summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md29
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yml56
-rw-r--r--.github/workflows/android_builds.yml6
-rw-r--r--.github/workflows/linux_builds.yml19
-rw-r--r--.github/workflows/windows_builds.yml4
-rw-r--r--.mailmap2
-rw-r--r--AUTHORS.md1
-rw-r--r--COPYRIGHT.txt21
-rw-r--r--DONORS.md164
-rw-r--r--README.md2
-rw-r--r--SConstruct65
-rw-r--r--core/SCsub20
-rw-r--r--core/config/engine.cpp14
-rw-r--r--core/config/engine.h5
-rw-r--r--core/config/project_settings.cpp19
-rw-r--r--core/core_bind.cpp297
-rw-r--r--core/core_bind.h61
-rw-r--r--core/core_constants.cpp6
-rw-r--r--core/crypto/aes_context.h6
-rw-r--r--core/crypto/crypto.h10
-rw-r--r--core/crypto/crypto_core.h2
-rw-r--r--core/crypto/hashing_context.h6
-rw-r--r--core/debugger/local_debugger.cpp4
-rw-r--r--core/debugger/remote_debugger_peer.cpp2
-rw-r--r--core/debugger/remote_debugger_peer.h4
-rw-r--r--core/input/input.cpp15
-rw-r--r--core/input/input.h3
-rw-r--r--core/input/input_event.cpp193
-rw-r--r--core/input/input_event.h43
-rw-r--r--core/input/input_map.cpp21
-rw-r--r--core/io/compression.cpp7
-rw-r--r--core/io/config_file.h8
-rw-r--r--core/io/dir_access.cpp (renamed from core/os/dir_access.cpp)14
-rw-r--r--core/io/dir_access.h (renamed from core/os/dir_access.h)10
-rw-r--r--core/io/dtls_server.cpp2
-rw-r--r--core/io/dtls_server.h4
-rw-r--r--core/io/file_access.cpp (renamed from core/os/file_access.cpp)35
-rw-r--r--core/io/file_access.h (renamed from core/os/file_access.h)24
-rw-r--r--core/io/file_access_compressed.cpp34
-rw-r--r--core/io/file_access_compressed.h30
-rw-r--r--core/io/file_access_encrypted.cpp47
-rw-r--r--core/io/file_access_encrypted.h18
-rw-r--r--core/io/file_access_memory.cpp29
-rw-r--r--core/io/file_access_memory.h18
-rw-r--r--core/io/file_access_network.cpp42
-rw-r--r--core/io/file_access_network.h40
-rw-r--r--core/io/file_access_pack.cpp42
-rw-r--r--core/io/file_access_pack.h32
-rw-r--r--core/io/file_access_zip.cpp69
-rw-r--r--core/io/file_access_zip.h11
-rw-r--r--core/io/http_client.cpp6
-rw-r--r--core/io/http_client.h6
-rw-r--r--core/io/image.cpp55
-rw-r--r--core/io/image.h9
-rw-r--r--core/io/image_loader.h2
-rw-r--r--core/io/ip.cpp109
-rw-r--r--core/io/ip.h14
-rw-r--r--core/io/ip_address.cpp24
-rw-r--r--core/io/ip_address.h12
-rw-r--r--core/io/json.cpp36
-rw-r--r--core/io/json.h10
-rw-r--r--core/io/logger.cpp9
-rw-r--r--core/io/logger.h2
-rw-r--r--core/io/marshalls.cpp40
-rw-r--r--core/io/marshalls.h6
-rw-r--r--core/io/multiplayer_api.cpp314
-rw-r--r--core/io/multiplayer_api.h51
-rw-r--r--core/io/net_socket.h19
-rw-r--r--core/io/packed_data_container.cpp11
-rw-r--r--core/io/packed_data_container.h4
-rw-r--r--core/io/packet_peer.h4
-rw-r--r--core/io/packet_peer_dtls.cpp2
-rw-r--r--core/io/packet_peer_udp.cpp35
-rw-r--r--core/io/packet_peer_udp.h23
-rw-r--r--core/io/pck_packer.cpp6
-rw-r--r--core/io/pck_packer.h6
-rw-r--r--core/io/resource.cpp9
-rw-r--r--core/io/resource.h8
-rw-r--r--core/io/resource_format_binary.cpp34
-rw-r--r--core/io/resource_format_binary.h2
-rw-r--r--core/io/resource_importer.h4
-rw-r--r--core/io/resource_loader.cpp55
-rw-r--r--core/io/resource_loader.h4
-rw-r--r--core/io/resource_saver.cpp20
-rw-r--r--core/io/resource_saver.h4
-rw-r--r--core/io/stream_peer.cpp8
-rw-r--r--core/io/stream_peer.h8
-rw-r--r--core/io/stream_peer_tcp.cpp51
-rw-r--r--core/io/stream_peer_tcp.h12
-rw-r--r--core/io/tcp_server.cpp36
-rw-r--r--core/io/tcp_server.h11
-rw-r--r--core/io/translation_loader_po.cpp2
-rw-r--r--core/io/translation_loader_po.h2
-rw-r--r--core/io/udp_server.cpp18
-rw-r--r--core/io/udp_server.h15
-rw-r--r--core/io/xml_parser.cpp103
-rw-r--r--core/io/xml_parser.h9
-rw-r--r--core/io/zip_io.cpp8
-rw-r--r--core/io/zip_io.h2
-rw-r--r--core/math/a_star.h10
-rw-r--r--core/math/aabb.cpp2
-rw-r--r--core/math/basis.cpp56
-rw-r--r--core/math/basis.h20
-rw-r--r--core/math/bvh.h695
-rw-r--r--core/math/bvh_abb.h276
-rw-r--r--core/math/bvh_cull.inc534
-rw-r--r--core/math/bvh_debug.inc68
-rw-r--r--core/math/bvh_integrity.inc42
-rw-r--r--core/math/bvh_logic.inc230
-rw-r--r--core/math/bvh_misc.inc55
-rw-r--r--core/math/bvh_pair.inc62
-rw-r--r--core/math/bvh_public.inc423
-rw-r--r--core/math/bvh_refit.inc141
-rw-r--r--core/math/bvh_split.inc294
-rw-r--r--core/math/bvh_structs.inc180
-rw-r--r--core/math/bvh_tree.h421
-rw-r--r--core/math/camera_matrix.cpp14
-rw-r--r--core/math/camera_matrix.h10
-rw-r--r--core/math/color.cpp20
-rw-r--r--core/math/color.h1
-rw-r--r--core/math/color_names.inc295
-rw-r--r--core/math/convex_hull.cpp2290
-rw-r--r--core/math/convex_hull.h112
-rw-r--r--core/math/delaunay_3d.h2
-rw-r--r--core/math/dynamic_bvh.cpp5
-rw-r--r--core/math/dynamic_bvh.h6
-rw-r--r--core/math/expression.cpp2
-rw-r--r--core/math/expression.h6
-rw-r--r--core/math/face3.cpp8
-rw-r--r--core/math/face3.h6
-rw-r--r--core/math/geometry_2d.cpp2
-rw-r--r--core/math/geometry_2d.h39
-rw-r--r--core/math/math_fieldwise.cpp8
-rw-r--r--core/math/math_funcs.h69
-rw-r--r--core/math/plane.cpp2
-rw-r--r--core/math/quaternion.cpp (renamed from core/math/quat.cpp)72
-rw-r--r--core/math/quaternion.h (renamed from core/math/quat.h)110
-rw-r--r--core/math/quick_hull.cpp2
-rw-r--r--core/math/random_number_generator.h6
-rw-r--r--core/math/random_pcg.cpp2
-rw-r--r--core/math/rect2.cpp8
-rw-r--r--core/math/rect2.h16
-rw-r--r--core/math/transform_2d.cpp11
-rw-r--r--core/math/transform_2d.h2
-rw-r--r--core/math/transform_3d.cpp (renamed from core/math/transform.cpp)90
-rw-r--r--core/math/transform_3d.h (renamed from core/math/transform.h)58
-rw-r--r--core/math/triangle_mesh.cpp2
-rw-r--r--core/math/triangle_mesh.h6
-rw-r--r--core/math/vector2.cpp26
-rw-r--r--core/math/vector2.h49
-rw-r--r--core/math/vector3.cpp24
-rw-r--r--core/math/vector3.h19
-rw-r--r--core/math/vector3i.cpp9
-rw-r--r--core/math/vector3i.h1
-rw-r--r--core/object/callable_method_pointer.h7
-rw-r--r--core/object/class_db.cpp62
-rw-r--r--core/object/class_db.h9
-rw-r--r--core/object/object.cpp61
-rw-r--r--core/object/object.h84
-rw-r--r--core/object/object_id.h2
-rw-r--r--core/object/ref_counted.cpp (renamed from core/object/reference.cpp)30
-rw-r--r--core/object/ref_counted.h (renamed from core/object/reference.h)30
-rw-r--r--core/object/script_language.cpp12
-rw-r--r--core/object/script_language.h54
-rw-r--r--core/object/undo_redo.cpp24
-rw-r--r--core/object/undo_redo.h4
-rw-r--r--core/os/keyboard.cpp6
-rw-r--r--core/os/keyboard.h2
-rw-r--r--core/os/main_loop.h2
-rw-r--r--core/os/memory.cpp1
-rw-r--r--core/os/os.cpp42
-rw-r--r--core/os/os.h34
-rw-r--r--core/os/pool_allocator.cpp3
-rw-r--r--core/os/time.cpp433
-rw-r--r--core/os/time.h109
-rw-r--r--core/register_core_types.cpp7
-rw-r--r--core/string/node_path.h2
-rw-r--r--core/string/optimized_translation.cpp1
-rw-r--r--core/string/translation.cpp2
-rw-r--r--core/string/translation_po.cpp22
-rw-r--r--core/string/ustring.cpp159
-rw-r--r--core/string/ustring.h5
-rw-r--r--core/templates/bin_sorted_array.h181
-rw-r--r--core/templates/command_queue_mt.cpp29
-rw-r--r--core/templates/command_queue_mt.h161
-rw-r--r--core/templates/hash_map.h6
-rw-r--r--core/templates/local_vector.h5
-rw-r--r--core/templates/oa_hash_map.h5
-rw-r--r--core/templates/paged_allocator.h8
-rw-r--r--core/templates/pooled_list.h (renamed from servers/physics_3d/broad_phase_3d_basic.h)124
-rw-r--r--core/templates/safe_refcount.h1
-rw-r--r--core/templates/vector.h12
-rw-r--r--core/variant/array.cpp78
-rw-r--r--core/variant/array.h4
-rw-r--r--core/variant/binder_common.h12
-rw-r--r--core/variant/callable.cpp31
-rw-r--r--core/variant/callable.h10
-rw-r--r--core/variant/method_ptrcall.h8
-rw-r--r--core/variant/type_info.h6
-rw-r--r--core/variant/typed_array.h8
-rw-r--r--core/variant/variant.cpp249
-rw-r--r--core/variant/variant.h24
-rw-r--r--core/variant/variant_call.cpp175
-rw-r--r--core/variant/variant_construct.cpp34
-rw-r--r--core/variant/variant_internal.h83
-rw-r--r--core/variant/variant_op.cpp90
-rw-r--r--core/variant/variant_parser.cpp31
-rw-r--r--core/variant/variant_parser.h2
-rw-r--r--core/variant/variant_setget.cpp52
-rw-r--r--core/variant/variant_utility.cpp7
-rw-r--r--doc/classes/@GlobalScope.xml43
-rw-r--r--doc/classes/AABB.xml2
-rw-r--r--doc/classes/AESContext.xml2
-rw-r--r--doc/classes/AStar.xml2
-rw-r--r--doc/classes/AStar2D.xml2
-rw-r--r--doc/classes/AcceptDialog.xml2
-rw-r--r--doc/classes/AnimatedSprite2D.xml4
-rw-r--r--doc/classes/AnimatedSprite3D.xml4
-rw-r--r--doc/classes/Animation.xml8
-rw-r--r--doc/classes/AnimationNode.xml118
-rw-r--r--doc/classes/AnimationNodeAnimation.xml2
-rw-r--r--doc/classes/AnimationNodeStateMachineTransition.xml2
-rw-r--r--doc/classes/AnimationPlayer.xml3
-rw-r--r--doc/classes/AnimationTrackEditPlugin.xml2
-rw-r--r--doc/classes/AnimationTree.xml6
-rw-r--r--doc/classes/Area2D.xml14
-rw-r--r--doc/classes/Area3D.xml14
-rw-r--r--doc/classes/Array.xml87
-rw-r--r--doc/classes/ArrayMesh.xml3
-rw-r--r--doc/classes/AudioEffectCompressor.xml2
-rw-r--r--doc/classes/AudioEffectInstance.xml2
-rw-r--r--doc/classes/AudioEffectPitchShift.xml25
-rw-r--r--doc/classes/AudioEffectSpectrumAnalyzer.xml28
-rw-r--r--doc/classes/AudioStreamGenerator.xml9
-rw-r--r--doc/classes/AudioStreamGeneratorPlayback.xml10
-rw-r--r--doc/classes/AudioStreamPlayback.xml2
-rw-r--r--doc/classes/AudioStreamPlayer.xml3
-rw-r--r--doc/classes/AudioStreamPlayer2D.xml6
-rw-r--r--doc/classes/AudioStreamPlayer3D.xml8
-rw-r--r--doc/classes/AudioStreamSample.xml6
-rw-r--r--doc/classes/BaseMaterial3D.xml15
-rw-r--r--doc/classes/Basis.xml12
-rw-r--r--doc/classes/BitMap.xml6
-rw-r--r--doc/classes/Bone2D.xml69
-rw-r--r--doc/classes/ButtonGroup.xml9
-rw-r--r--doc/classes/CPUParticles2D.xml2
-rw-r--r--doc/classes/Callable.xml16
-rw-r--r--doc/classes/Camera3D.xml13
-rw-r--r--doc/classes/CameraFeed.xml2
-rw-r--r--doc/classes/CharFXTransform.xml4
-rw-r--r--doc/classes/CharacterBody2D.xml132
-rw-r--r--doc/classes/CharacterBody3D.xml115
-rw-r--r--doc/classes/CodeEdit.xml397
-rw-r--r--doc/classes/CollisionObject2D.xml18
-rw-r--r--doc/classes/CollisionObject3D.xml23
-rw-r--r--doc/classes/Color.xml315
-rw-r--r--doc/classes/ConcavePolygonShape3D.xml2
-rw-r--r--doc/classes/ConfigFile.xml2
-rw-r--r--doc/classes/Control.xml265
-rw-r--r--doc/classes/Crypto.xml2
-rw-r--r--doc/classes/Curve.xml2
-rw-r--r--doc/classes/DTLSServer.xml2
-rw-r--r--doc/classes/Directory.xml10
-rw-r--r--doc/classes/DisplayServer.xml68
-rw-r--r--doc/classes/EditorDebuggerPlugin.xml2
-rw-r--r--doc/classes/EditorExportPlugin.xml2
-rw-r--r--doc/classes/EditorFeatureProfile.xml2
-rw-r--r--doc/classes/EditorImportPlugin.xml52
-rw-r--r--doc/classes/EditorInspectorPlugin.xml94
-rw-r--r--doc/classes/EditorInterface.xml6
-rw-r--r--doc/classes/EditorNode3DGizmo.xml138
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml162
-rw-r--r--doc/classes/EditorPaths.xml43
-rw-r--r--doc/classes/EditorPlugin.xml511
-rw-r--r--doc/classes/EditorProperty.xml20
-rw-r--r--doc/classes/EditorResourceConversionPlugin.xml2
-rw-r--r--doc/classes/EditorResourcePicker.xml81
-rw-r--r--doc/classes/EditorResourcePreview.xml6
-rw-r--r--doc/classes/EditorResourcePreviewGenerator.xml18
-rw-r--r--doc/classes/EditorSceneImporter.xml2
-rw-r--r--doc/classes/EditorScenePostImport.xml22
-rw-r--r--doc/classes/EditorScript.xml2
-rw-r--r--doc/classes/EditorScriptPicker.xml21
-rw-r--r--doc/classes/EditorSettings.xml9
-rw-r--r--doc/classes/EditorSpinSlider.xml2
-rw-r--r--doc/classes/EditorSyntaxHighlighter.xml2
-rw-r--r--doc/classes/EditorTranslationParserPlugin.xml16
-rw-r--r--doc/classes/EncodedObjectAsID.xml2
-rw-r--r--doc/classes/Engine.xml1
-rw-r--r--doc/classes/Environment.xml2
-rw-r--r--doc/classes/Expression.xml8
-rw-r--r--doc/classes/File.xml19
-rw-r--r--doc/classes/FileSystemDock.xml34
-rw-r--r--doc/classes/GPUParticles2D.xml16
-rw-r--r--doc/classes/GPUParticles3D.xml26
-rw-r--r--doc/classes/GeometryInstance3D.xml28
-rw-r--r--doc/classes/GraphEdit.xml12
-rw-r--r--doc/classes/GraphNode.xml83
-rw-r--r--doc/classes/HMACContext.xml2
-rw-r--r--doc/classes/HTTPClient.xml2
-rw-r--r--doc/classes/HashingContext.xml2
-rw-r--r--doc/classes/IP.xml22
-rw-r--r--doc/classes/Input.xml5
-rw-r--r--doc/classes/InputEventAction.xml2
-rw-r--r--doc/classes/InputEventMouseButton.xml2
-rw-r--r--doc/classes/InputEventWithModifiers.xml12
-rw-r--r--doc/classes/JSON.xml3
-rw-r--r--doc/classes/JSONParseResult.xml2
-rw-r--r--doc/classes/JSONParser.xml2
-rw-r--r--doc/classes/JavaClass.xml2
-rw-r--r--doc/classes/JavaScript.xml43
-rw-r--r--doc/classes/JavaScriptObject.xml42
-rw-r--r--doc/classes/KinematicBody2D.xml176
-rw-r--r--doc/classes/KinematicBody3D.xml188
-rw-r--r--doc/classes/KinematicCollision2D.xml6
-rw-r--r--doc/classes/KinematicCollision3D.xml6
-rw-r--r--doc/classes/LargeTexture.xml90
-rw-r--r--doc/classes/Light3D.xml2
-rw-r--r--doc/classes/LightmapGI.xml (renamed from doc/classes/BakedLightmap.xml)10
-rw-r--r--doc/classes/LightmapGIData.xml (renamed from doc/classes/BakedLightmapData.xml)2
-rw-r--r--doc/classes/Lightmapper.xml2
-rw-r--r--doc/classes/LineEdit.xml2
-rw-r--r--doc/classes/Listener3D.xml4
-rw-r--r--doc/classes/MeshDataTool.xml6
-rw-r--r--doc/classes/MeshInstance3D.xml7
-rw-r--r--doc/classes/MeshLibrary.xml8
-rw-r--r--doc/classes/MultiMesh.xml8
-rw-r--r--doc/classes/MultiplayerAPI.xml10
-rw-r--r--doc/classes/Mutex.xml2
-rw-r--r--doc/classes/NavigationAgent2D.xml6
-rw-r--r--doc/classes/NavigationAgent3D.xml6
-rw-r--r--doc/classes/NavigationServer3D.xml2
-rw-r--r--doc/classes/Node.xml95
-rw-r--r--doc/classes/Node2D.xml6
-rw-r--r--doc/classes/Node3D.xml23
-rw-r--r--doc/classes/Node3DGizmo.xml2
-rw-r--r--doc/classes/OS.xml88
-rw-r--r--doc/classes/Object.xml4
-rw-r--r--doc/classes/Occluder3D.xml19
-rw-r--r--doc/classes/OccluderInstance3D.xml37
-rw-r--r--doc/classes/PCKPacker.xml2
-rw-r--r--doc/classes/PackedByteArray.xml9
-rw-r--r--doc/classes/PackedColorArray.xml9
-rw-r--r--doc/classes/PackedDataContainerRef.xml4
-rw-r--r--doc/classes/PackedFloat32Array.xml9
-rw-r--r--doc/classes/PackedFloat64Array.xml9
-rw-r--r--doc/classes/PackedInt32Array.xml9
-rw-r--r--doc/classes/PackedInt64Array.xml9
-rw-r--r--doc/classes/PackedStringArray.xml9
-rw-r--r--doc/classes/PackedVector2Array.xml9
-rw-r--r--doc/classes/PackedVector3Array.xml11
-rw-r--r--doc/classes/PacketPeer.xml2
-rw-r--r--doc/classes/PacketPeerUDP.xml51
-rw-r--r--doc/classes/ParticlesMaterial.xml2
-rw-r--r--doc/classes/PhysicalBone2D.xml49
-rw-r--r--doc/classes/PhysicalBone3D.xml40
-rw-r--r--doc/classes/PhysicsBody2D.xml40
-rw-r--r--doc/classes/PhysicsBody3D.xml78
-rw-r--r--doc/classes/PhysicsDirectBodyState2D.xml2
-rw-r--r--doc/classes/PhysicsDirectBodyState3D.xml4
-rw-r--r--doc/classes/PhysicsServer2D.xml27
-rw-r--r--doc/classes/PhysicsServer3D.xml68
-rw-r--r--doc/classes/PhysicsShapeQueryParameters2D.xml2
-rw-r--r--doc/classes/PhysicsShapeQueryParameters3D.xml4
-rw-r--r--doc/classes/PhysicsShapeQueryResult2D.xml2
-rw-r--r--doc/classes/PhysicsShapeQueryResult3D.xml2
-rw-r--r--doc/classes/PhysicsTestMotionResult2D.xml2
-rw-r--r--doc/classes/PinJoint2D.xml2
-rw-r--r--doc/classes/PinJoint3D.xml2
-rw-r--r--doc/classes/PrimitiveMesh.xml2
-rw-r--r--doc/classes/ProjectSettings.xml108
-rw-r--r--doc/classes/Quaternion.xml (renamed from doc/classes/Quat.xml)90
-rw-r--r--doc/classes/RDAttachmentFormat.xml2
-rw-r--r--doc/classes/RDPipelineColorBlendState.xml2
-rw-r--r--doc/classes/RDPipelineColorBlendStateAttachment.xml2
-rw-r--r--doc/classes/RDPipelineDepthStencilState.xml2
-rw-r--r--doc/classes/RDPipelineMultisampleState.xml2
-rw-r--r--doc/classes/RDPipelineRasterizationState.xml2
-rw-r--r--doc/classes/RDSamplerState.xml2
-rw-r--r--doc/classes/RDShaderFile.xml4
-rw-r--r--doc/classes/RDShaderSource.xml2
-rw-r--r--doc/classes/RDTextureFormat.xml2
-rw-r--r--doc/classes/RDTextureView.xml2
-rw-r--r--doc/classes/RDUniform.xml2
-rw-r--r--doc/classes/RDVertexAttribute.xml2
-rw-r--r--doc/classes/RandomNumberGenerator.xml2
-rw-r--r--doc/classes/RefCounted.xml (renamed from doc/classes/Reference.xml)4
-rw-r--r--doc/classes/ReflectionProbe.xml2
-rw-r--r--doc/classes/RemoteTransform3D.xml4
-rw-r--r--doc/classes/RenderingServer.xml170
-rw-r--r--doc/classes/Resource.xml5
-rw-r--r--doc/classes/ResourceFormatLoader.xml14
-rw-r--r--doc/classes/ResourceFormatSaver.xml10
-rw-r--r--doc/classes/ResourceImporter.xml2
-rw-r--r--doc/classes/ResourceSaver.xml2
-rw-r--r--doc/classes/RibbonTrailMesh.xml31
-rw-r--r--doc/classes/RigidBody2D.xml34
-rw-r--r--doc/classes/RigidBody3D.xml59
-rw-r--r--doc/classes/SceneState.xml2
-rw-r--r--doc/classes/SceneTree.xml7
-rw-r--r--doc/classes/SceneTreeTimer.xml2
-rw-r--r--doc/classes/ScriptEditor.xml34
-rw-r--r--doc/classes/ScriptEditorBase.xml9
-rw-r--r--doc/classes/ScrollContainer.xml15
-rw-r--r--doc/classes/Semaphore.xml2
-rw-r--r--doc/classes/Shape3D.xml7
-rw-r--r--doc/classes/Skeleton2D.xml54
-rw-r--r--doc/classes/Skeleton3D.xml64
-rw-r--r--doc/classes/SkeletonIK3D.xml6
-rw-r--r--doc/classes/SkeletonModification2D.xml104
-rw-r--r--doc/classes/SkeletonModification2DCCDIK.xml170
-rw-r--r--doc/classes/SkeletonModification2DFABRIK.xml108
-rw-r--r--doc/classes/SkeletonModification2DJiggle.xml232
-rw-r--r--doc/classes/SkeletonModification2DLookAt.xml107
-rw-r--r--doc/classes/SkeletonModification2DPhysicalBones.xml68
-rw-r--r--doc/classes/SkeletonModification2DStackHolder.xml32
-rw-r--r--doc/classes/SkeletonModification2DTwoBoneIK.xml94
-rw-r--r--doc/classes/SkeletonModificationStack2D.xml108
-rw-r--r--doc/classes/Skin.xml6
-rw-r--r--doc/classes/SkinReference.xml2
-rw-r--r--doc/classes/Sprite2D.xml2
-rw-r--r--doc/classes/Sprite3D.xml7
-rw-r--r--doc/classes/StaticBody2D.xml15
-rw-r--r--doc/classes/StaticBody3D.xml15
-rw-r--r--doc/classes/StreamPeer.xml4
-rw-r--r--doc/classes/StreamPeerTCP.xml21
-rw-r--r--doc/classes/String.xml16
-rw-r--r--doc/classes/StyleBoxTexture.xml7
-rw-r--r--doc/classes/SubViewport.xml5
-rw-r--r--doc/classes/SurfaceTool.xml6
-rw-r--r--doc/classes/TCPServer.xml (renamed from doc/classes/TCP_Server.xml)9
-rw-r--r--doc/classes/Tabs.xml2
-rw-r--r--doc/classes/TextEdit.xml123
-rw-r--r--doc/classes/TextLine.xml2
-rw-r--r--doc/classes/TextParagraph.xml2
-rw-r--r--doc/classes/TextServer.xml2
-rw-r--r--doc/classes/Theme.xml204
-rw-r--r--doc/classes/Thread.xml2
-rw-r--r--doc/classes/TileData.xml245
-rw-r--r--doc/classes/TileMap.xml281
-rw-r--r--doc/classes/TileSet.xml708
-rw-r--r--doc/classes/TileSetAtlasSource.xml207
-rw-r--r--doc/classes/TileSetScenesCollectionSource.xml155
-rw-r--r--doc/classes/TileSetSource.xml13
-rw-r--r--doc/classes/Time.xml270
-rw-r--r--doc/classes/Transform2D.xml37
-rw-r--r--doc/classes/Transform3D.xml (renamed from doc/classes/Transform.xml)74
-rw-r--r--doc/classes/Tree.xml24
-rw-r--r--doc/classes/TreeItem.xml84
-rw-r--r--doc/classes/TriangleMesh.xml2
-rw-r--r--doc/classes/TubeTrailMesh.xml27
-rw-r--r--doc/classes/UDPServer.xml11
-rw-r--r--doc/classes/Variant.xml32
-rw-r--r--doc/classes/Vector2.xml21
-rw-r--r--doc/classes/Vector2i.xml11
-rw-r--r--doc/classes/Vector3.xml28
-rw-r--r--doc/classes/Vector3i.xml11
-rw-r--r--doc/classes/VelocityTracker3D.xml2
-rw-r--r--doc/classes/VideoPlayer.xml2
-rw-r--r--doc/classes/Viewport.xml38
-rw-r--r--doc/classes/VisibilityEnabler2D.xml64
-rw-r--r--doc/classes/VisibilityEnabler3D.xml35
-rw-r--r--doc/classes/VisibilityNotifier2D.xml17
-rw-r--r--doc/classes/VisibilityNotifier3D.xml16
-rw-r--r--doc/classes/VisualInstance3D.xml2
-rw-r--r--doc/classes/VisualShader.xml12
-rw-r--r--doc/classes/VisualShaderNode.xml16
-rw-r--r--doc/classes/VisualShaderNodeBillboard.xml38
-rw-r--r--doc/classes/VisualShaderNodeDeterminant.xml2
-rw-r--r--doc/classes/VisualShaderNodeParticleAccelerator.xml25
-rw-r--r--doc/classes/VisualShaderNodeParticleBoxEmitter.xml13
-rw-r--r--doc/classes/VisualShaderNodeParticleConeVelocity.xml13
-rw-r--r--doc/classes/VisualShaderNodeParticleEmit.xml27
-rw-r--r--doc/classes/VisualShaderNodeParticleEmitter.xml13
-rw-r--r--doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml17
-rw-r--r--doc/classes/VisualShaderNodeParticleOutput.xml13
-rw-r--r--doc/classes/VisualShaderNodeParticleRandomness.xml23
-rw-r--r--doc/classes/VisualShaderNodeParticleRingEmitter.xml13
-rw-r--r--doc/classes/VisualShaderNodeParticleSphereEmitter.xml13
-rw-r--r--doc/classes/VisualShaderNodeTransformCompose.xml2
-rw-r--r--doc/classes/VisualShaderNodeTransformConstant.xml8
-rw-r--r--doc/classes/VisualShaderNodeTransformDecompose.xml2
-rw-r--r--doc/classes/VisualShaderNodeTransformFunc.xml8
-rw-r--r--doc/classes/VisualShaderNodeTransformMult.xml2
-rw-r--r--doc/classes/VisualShaderNodeTransformUniform.xml4
-rw-r--r--doc/classes/VisualShaderNodeTransformVecMult.xml2
-rw-r--r--doc/classes/VisualShaderNodeUVFunc.xml28
-rw-r--r--doc/classes/VoxelGI.xml (renamed from doc/classes/GIProbe.xml)20
-rw-r--r--doc/classes/VoxelGIData.xml (renamed from doc/classes/GIProbeData.xml)6
-rw-r--r--doc/classes/WeakRef.xml4
-rw-r--r--doc/classes/Window.xml38
-rw-r--r--doc/classes/XMLParser.xml2
-rw-r--r--doc/classes/XRInterface.xml16
-rw-r--r--doc/classes/XRPositionalTracker.xml4
-rw-r--r--doc/classes/XRServer.xml8
-rw-r--r--doc/classes/YSort.xml21
-rw-r--r--doc/classes/float.xml6
-rw-r--r--doc/classes/int.xml4
-rw-r--r--doc/translations/ar.po26
-rw-r--r--doc/translations/ca.po26
-rw-r--r--doc/translations/classes.pot32
-rw-r--r--doc/translations/cs.po26
-rw-r--r--doc/translations/de.po26
-rw-r--r--doc/translations/es.po28
-rw-r--r--doc/translations/fa.po26
-rw-r--r--doc/translations/fi.po26
-rw-r--r--doc/translations/fr.po26
-rw-r--r--doc/translations/id.po26
-rw-r--r--doc/translations/it.po26
-rw-r--r--doc/translations/ja.po26
-rw-r--r--doc/translations/ko.po26
-rw-r--r--doc/translations/nl.po26
-rw-r--r--doc/translations/pl.po26
-rw-r--r--doc/translations/pt_BR.po26
-rw-r--r--doc/translations/ro.po26
-rw-r--r--doc/translations/ru.po26
-rw-r--r--doc/translations/sr_Cyrl.po26
-rw-r--r--doc/translations/th.po26
-rw-r--r--doc/translations/tr.po26
-rw-r--r--doc/translations/uk.po26
-rw-r--r--doc/translations/zh_Hans.po26
-rw-r--r--doc/translations/zh_Hant.po26
-rw-r--r--drivers/SCsub4
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp22
-rw-r--r--drivers/dummy/SCsub5
-rw-r--r--drivers/dummy/texture_loader_dummy.cpp109
-rw-r--r--drivers/dummy/texture_loader_dummy.h47
-rw-r--r--drivers/png/image_loader_png.cpp8
-rw-r--r--drivers/png/png_driver_common.cpp4
-rw-r--r--drivers/png/resource_saver_png.cpp2
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp56
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h2
-rw-r--r--drivers/unix/dir_access_unix.cpp63
-rw-r--r--drivers/unix/dir_access_unix.h8
-rw-r--r--drivers/unix/file_access_unix.cpp32
-rw-r--r--drivers/unix/file_access_unix.h12
-rw-r--r--drivers/unix/ip_unix.cpp42
-rw-r--r--drivers/unix/ip_unix.h8
-rw-r--r--drivers/unix/net_socket_posix.cpp101
-rw-r--r--drivers/unix/net_socket_posix.h27
-rw-r--r--drivers/unix/os_unix.cpp6
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp74
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h20
-rw-r--r--drivers/vulkan/vulkan_context.cpp172
-rw-r--r--drivers/vulkan/vulkan_context.h10
-rw-r--r--drivers/windows/dir_access_windows.cpp9
-rw-r--r--drivers/windows/dir_access_windows.h9
-rw-r--r--drivers/windows/file_access_windows.cpp33
-rw-r--r--drivers/windows/file_access_windows.h12
-rw-r--r--editor/action_map_editor.cpp108
-rw-r--r--editor/action_map_editor.h14
-rw-r--r--editor/animation_bezier_editor.cpp22
-rw-r--r--editor/animation_track_editor.cpp256
-rw-r--r--editor/animation_track_editor.h58
-rw-r--r--editor/animation_track_editor_plugins.cpp6
-rw-r--r--editor/array_property_edit.h4
-rw-r--r--editor/audio_stream_preview.h4
-rw-r--r--editor/code_editor.cpp136
-rw-r--r--editor/code_editor.h14
-rw-r--r--editor/connections_dialog.cpp28
-rw-r--r--editor/connections_dialog.h2
-rw-r--r--editor/create_dialog.cpp7
-rw-r--r--editor/debugger/editor_debugger_node.cpp2
-rw-r--r--editor/debugger/editor_debugger_server.cpp2
-rw-r--r--editor/debugger/editor_debugger_server.h4
-rw-r--r--editor/debugger/editor_profiler.cpp55
-rw-r--r--editor/debugger/script_editor_debugger.cpp12
-rw-r--r--editor/dependency_editor.cpp6
-rw-r--r--editor/dictionary_property_edit.h4
-rw-r--r--editor/doc_tools.cpp2
-rw-r--r--editor/editor_about.cpp31
-rw-r--r--editor/editor_about.h3
-rw-r--r--editor/editor_asset_installer.cpp12
-rw-r--r--editor/editor_audio_buses.cpp53
-rw-r--r--editor/editor_audio_buses.h8
-rw-r--r--editor/editor_autoload_settings.cpp21
-rw-r--r--editor/editor_autoload_settings.h2
-rw-r--r--editor/editor_builders.py2
-rw-r--r--editor/editor_data.cpp18
-rw-r--r--editor/editor_data.h4
-rw-r--r--editor/editor_dir_dialog.h2
-rw-r--r--editor/editor_export.cpp60
-rw-r--r--editor/editor_export.h14
-rw-r--r--editor/editor_feature_profile.cpp169
-rw-r--r--editor/editor_feature_profile.h18
-rw-r--r--editor/editor_file_dialog.cpp13
-rw-r--r--editor/editor_file_dialog.h6
-rw-r--r--editor/editor_file_system.cpp43
-rw-r--r--editor/editor_file_system.h4
-rw-r--r--editor/editor_folding.cpp2
-rw-r--r--editor/editor_fonts.cpp9
-rw-r--r--editor/editor_help.cpp13
-rw-r--r--editor/editor_help.h2
-rw-r--r--editor/editor_help_search.cpp2
-rw-r--r--editor/editor_help_search.h2
-rw-r--r--editor/editor_inspector.cpp123
-rw-r--r--editor/editor_inspector.h6
-rw-r--r--editor/editor_log.cpp316
-rw-r--r--editor/editor_log.h124
-rw-r--r--editor/editor_node.cpp299
-rw-r--r--editor/editor_node.h10
-rw-r--r--editor/editor_path.cpp100
-rw-r--r--editor/editor_path.h16
-rw-r--r--editor/editor_paths.cpp212
-rw-r--r--editor/editor_paths.h74
-rw-r--r--editor/editor_plugin.cpp179
-rw-r--r--editor/editor_plugin.h7
-rw-r--r--editor/editor_plugin_settings.cpp2
-rw-r--r--editor/editor_properties.cpp882
-rw-r--r--editor/editor_properties.h75
-rw-r--r--editor/editor_properties_array_dict.cpp16
-rw-r--r--editor/editor_properties_array_dict.h8
-rw-r--r--editor/editor_resource_picker.cpp864
-rw-r--r--editor/editor_resource_picker.h141
-rw-r--r--editor/editor_resource_preview.cpp38
-rw-r--r--editor/editor_resource_preview.h7
-rw-r--r--editor/editor_run.cpp45
-rw-r--r--editor/editor_run_script.h6
-rw-r--r--editor/editor_sectioned_inspector.cpp9
-rw-r--r--editor/editor_settings.cpp326
-rw-r--r--editor/editor_settings.h12
-rw-r--r--editor/editor_spin_slider.cpp14
-rw-r--r--editor/editor_spin_slider.h2
-rw-r--r--editor/editor_themes.cpp558
-rw-r--r--editor/editor_translation_parser.cpp16
-rw-r--r--editor/editor_translation_parser.h6
-rw-r--r--editor/editor_zoom_widget.cpp163
-rw-r--r--editor/editor_zoom_widget.h (renamed from platform/javascript/api/javascript_eval.h)35
-rw-r--r--editor/export_template_manager.cpp951
-rw-r--r--editor/export_template_manager.h89
-rw-r--r--editor/fileserver/editor_file_server.cpp5
-rw-r--r--editor/fileserver/editor_file_server.h2
-rw-r--r--editor/filesystem_dock.cpp95
-rw-r--r--editor/filesystem_dock.h3
-rw-r--r--editor/find_in_files.cpp22
-rw-r--r--editor/find_in_files.h4
-rw-r--r--editor/groups_editor.cpp12
-rw-r--r--editor/icons/2D.svg2
-rw-r--r--editor/icons/AABB.svg2
-rw-r--r--editor/icons/AddAtlasTile.svg1
-rw-r--r--editor/icons/AddAutotile.svg1
-rw-r--r--editor/icons/AddSingleTile.svg1
-rw-r--r--editor/icons/AddSplit.svg2
-rw-r--r--editor/icons/Anchor.svg2
-rw-r--r--editor/icons/AnimatedSprite2D.svg2
-rw-r--r--editor/icons/AnimatedSprite3D.svg2
-rw-r--r--editor/icons/AnimationPlayer.svg2
-rw-r--r--editor/icons/AnimationTree.svg2
-rw-r--r--editor/icons/Area2D.svg2
-rw-r--r--editor/icons/Area3D.svg2
-rw-r--r--editor/icons/ArrayMesh.svg2
-rw-r--r--editor/icons/AspectRatioContainer.svg2
-rw-r--r--editor/icons/AudioBusLayout.svg2
-rw-r--r--editor/icons/AudioStreamMP3.svg2
-rw-r--r--editor/icons/AudioStreamOGGVorbis.svg2
-rw-r--r--editor/icons/AudioStreamPlayer.svg2
-rw-r--r--editor/icons/AudioStreamPlayer2D.svg2
-rw-r--r--editor/icons/AudioStreamPlayer3D.svg2
-rw-r--r--editor/icons/AudioStreamSample.svg2
-rw-r--r--editor/icons/BackBufferCopy.svg2
-rw-r--r--editor/icons/Basis.svg2
-rw-r--r--editor/icons/BezierHandlesBalanced.svg2
-rw-r--r--editor/icons/BezierHandlesFree.svg2
-rw-r--r--editor/icons/BezierHandlesMirror.svg2
-rw-r--r--editor/icons/Bone2D.svg2
-rw-r--r--editor/icons/BoneAttachment3D.svg2
-rw-r--r--editor/icons/BoneTrack.svg2
-rw-r--r--editor/icons/BoxMesh.svg2
-rw-r--r--editor/icons/BusVuEmpty.svg2
-rw-r--r--editor/icons/BusVuFull.svg2
-rw-r--r--editor/icons/Button.svg2
-rw-r--r--editor/icons/CPUParticles3D.svg2
-rw-r--r--editor/icons/Camera2D.svg2
-rw-r--r--editor/icons/Camera3D.svg2
-rw-r--r--editor/icons/CameraEffects.svg2
-rw-r--r--editor/icons/CanvasItemMaterial.svg2
-rw-r--r--editor/icons/CanvasItemShader.svg2
-rw-r--r--editor/icons/CanvasItemShaderGraph.svg2
-rw-r--r--editor/icons/CanvasModulate.svg2
-rw-r--r--editor/icons/CapsuleMesh.svg2
-rw-r--r--editor/icons/CenterContainer.svg2
-rw-r--r--editor/icons/CharacterBody2D.svg (renamed from editor/icons/KinematicBody2D.svg)2
-rw-r--r--editor/icons/CharacterBody3D.svg (renamed from editor/icons/KinematicBody3D.svg)2
-rw-r--r--editor/icons/CheckBox.svg2
-rw-r--r--editor/icons/CheckButton.svg2
-rw-r--r--editor/icons/ClippedCamera3D.svg2
-rw-r--r--editor/icons/CodeEdit.svg2
-rw-r--r--editor/icons/CollapseTree.svg1
-rw-r--r--editor/icons/CollisionPolygon2D.svg2
-rw-r--r--editor/icons/CollisionPolygon3D.svg2
-rw-r--r--editor/icons/CollisionShape2D.svg2
-rw-r--r--editor/icons/CollisionShape3D.svg2
-rw-r--r--editor/icons/Color.svg2
-rw-r--r--editor/icons/ColorPicker.svg2
-rw-r--r--editor/icons/ColorPickerButton.svg2
-rw-r--r--editor/icons/ColorRect.svg2
-rw-r--r--editor/icons/CombineLines.svg1
-rw-r--r--editor/icons/ConeTwistJoint3D.svg2
-rw-r--r--editor/icons/Container.svg2
-rw-r--r--editor/icons/Control.svg2
-rw-r--r--editor/icons/ControlLayout.svg2
-rw-r--r--editor/icons/CreateNewSceneFrom.svg2
-rw-r--r--editor/icons/Cubemap.svg2
-rw-r--r--editor/icons/CubemapArray.svg2
-rw-r--r--editor/icons/CurveClose.svg2
-rw-r--r--editor/icons/CurveCreate.svg2
-rw-r--r--editor/icons/CurveCurve.svg2
-rw-r--r--editor/icons/CurveDelete.svg2
-rw-r--r--editor/icons/CurveEdit.svg2
-rw-r--r--editor/icons/CylinderMesh.svg2
-rw-r--r--editor/icons/DampedSpringJoint2D.svg2
-rw-r--r--editor/icons/DebugContinue.svg2
-rw-r--r--editor/icons/DebugNext.svg2
-rw-r--r--editor/icons/DebugStep.svg2
-rw-r--r--editor/icons/Decal.svg2
-rw-r--r--editor/icons/Dictionary.svg2
-rw-r--r--editor/icons/DirectionalLight3D.svg2
-rw-r--r--editor/icons/EditAddRemove.svg1
-rw-r--r--editor/icons/EditBezier.svg2
-rw-r--r--editor/icons/Editor3DHandle.svg2
-rw-r--r--editor/icons/EditorControlAnchor.svg2
-rw-r--r--editor/icons/EditorHandle.svg2
-rw-r--r--editor/icons/EditorHandleAdd.svg2
-rw-r--r--editor/icons/EditorHandleDisabled.svg1
-rw-r--r--editor/icons/EditorPivot.svg2
-rw-r--r--editor/icons/EditorPosition.svg2
-rw-r--r--editor/icons/Eraser.svg1
-rw-r--r--editor/icons/ExpandTree.svg1
-rw-r--r--editor/icons/FixedSpatialMaterial.svg2
-rw-r--r--editor/icons/FontData.svg2
-rw-r--r--editor/icons/FontSize.svg1
-rw-r--r--editor/icons/GPUParticles2D.svg2
-rw-r--r--editor/icons/GPUParticles3D.svg2
-rw-r--r--editor/icons/GPUParticlesAttractorBox.svg2
-rw-r--r--editor/icons/GPUParticlesAttractorSphere.svg2
-rw-r--r--editor/icons/GPUParticlesAttractorVectorField.svg2
-rw-r--r--editor/icons/GPUParticlesCollisionBox.svg2
-rw-r--r--editor/icons/GPUParticlesCollisionHeightField.svg2
-rw-r--r--editor/icons/GPUParticlesCollisionSDF.svg2
-rw-r--r--editor/icons/GPUParticlesCollisionSphere.svg2
-rw-r--r--editor/icons/Generic6DOFJoint3D.svg2
-rw-r--r--editor/icons/Gradient.svg2
-rw-r--r--editor/icons/GradientTexture.svg2
-rw-r--r--editor/icons/GraphEdit.svg2
-rw-r--r--editor/icons/GraphNode.svg2
-rw-r--r--editor/icons/Grid.svg2
-rw-r--r--editor/icons/GridContainer.svg2
-rw-r--r--editor/icons/GrooveJoint2D.svg2
-rw-r--r--editor/icons/GuiChecked.svg2
-rw-r--r--editor/icons/GuiRadioChecked.svg2
-rw-r--r--editor/icons/HBoxContainer.svg2
-rw-r--r--editor/icons/HScrollBar.svg2
-rw-r--r--editor/icons/HSeparator.svg2
-rw-r--r--editor/icons/HSlider.svg2
-rw-r--r--editor/icons/HSplitContainer.svg2
-rw-r--r--editor/icons/Heart.svg1
-rw-r--r--editor/icons/HingeJoint3D.svg2
-rw-r--r--editor/icons/ImmediateGeometry3D.svg2
-rw-r--r--editor/icons/InsertAfter.svg2
-rw-r--r--editor/icons/InsertBefore.svg2
-rw-r--r--editor/icons/InverseKinematics.svg2
-rw-r--r--editor/icons/ItemList.svg2
-rw-r--r--editor/icons/KeyAnimation.svg2
-rw-r--r--editor/icons/KeyAudio.svg2
-rw-r--r--editor/icons/KeyBezier.svg2
-rw-r--r--editor/icons/KeyBezierSelected.svg2
-rw-r--r--editor/icons/KeyCall.svg2
-rw-r--r--editor/icons/KeyNext.svg2
-rw-r--r--editor/icons/KeySelected.svg2
-rw-r--r--editor/icons/KeyXform.svg2
-rw-r--r--editor/icons/Label.svg2
-rw-r--r--editor/icons/LargeTexture.svg1
-rw-r--r--editor/icons/LightOccluder2D.svg2
-rw-r--r--editor/icons/LightmapGI.svg (renamed from editor/icons/BakedLightmap.svg)2
-rw-r--r--editor/icons/LightmapGIData.svg (renamed from editor/icons/BakedLightmapData.svg)0
-rw-r--r--editor/icons/LightmapProbe.svg2
-rw-r--r--editor/icons/Line2D.svg2
-rw-r--r--editor/icons/LineEdit.svg2
-rw-r--r--editor/icons/LinkButton.svg2
-rw-r--r--editor/icons/Listener3D.svg2
-rw-r--r--editor/icons/MarginContainer.svg2
-rw-r--r--editor/icons/MenuButton.svg2
-rw-r--r--editor/icons/Mesh.svg2
-rw-r--r--editor/icons/MeshInstance2D.svg2
-rw-r--r--editor/icons/MeshInstance3D.svg2
-rw-r--r--editor/icons/MeshLibrary.svg2
-rw-r--r--editor/icons/MiniObject.svg2
-rw-r--r--editor/icons/MovePoint.svg2
-rw-r--r--editor/icons/MultiMesh.svg2
-rw-r--r--editor/icons/MultiMeshInstance2D.svg2
-rw-r--r--editor/icons/MultiMeshInstance3D.svg2
-rw-r--r--editor/icons/Navigation2D.svg2
-rw-r--r--editor/icons/Navigation3D.svg2
-rw-r--r--editor/icons/NavigationMesh.svg2
-rw-r--r--editor/icons/NavigationRegion2D.svg2
-rw-r--r--editor/icons/NavigationRegion3D.svg2
-rw-r--r--editor/icons/New.svg2
-rw-r--r--editor/icons/NewRoot.svg2
-rw-r--r--editor/icons/NinePatchRect.svg2
-rw-r--r--editor/icons/Node2D.svg2
-rw-r--r--editor/icons/Node3D.svg2
-rw-r--r--editor/icons/NodePath.svg2
-rw-r--r--editor/icons/Occluder3D.svg1
-rw-r--r--editor/icons/OccluderInstance3D.svg1
-rw-r--r--editor/icons/OccluderPolygon2D.svg2
-rw-r--r--editor/icons/OmniLight3D.svg2
-rw-r--r--editor/icons/OptionButton.svg2
-rw-r--r--editor/icons/PackedColorArray.svg2
-rw-r--r--editor/icons/PackedFloat32Array.svg2
-rw-r--r--editor/icons/PackedFloat64Array.svg2
-rw-r--r--editor/icons/PackedInt32Array.svg2
-rw-r--r--editor/icons/PackedInt64Array.svg2
-rw-r--r--editor/icons/PackedStringArray.svg2
-rw-r--r--editor/icons/PackedVector2Array.svg2
-rw-r--r--editor/icons/PackedVector3Array.svg2
-rw-r--r--editor/icons/Panel.svg2
-rw-r--r--editor/icons/PanelContainer.svg2
-rw-r--r--editor/icons/PanoramaSkyMaterial.svg2
-rw-r--r--editor/icons/ParallaxLayer.svg2
-rw-r--r--editor/icons/ParticlesMaterial.svg2
-rw-r--r--editor/icons/Path2D.svg2
-rw-r--r--editor/icons/Path3D.svg2
-rw-r--r--editor/icons/PathFollow2D.svg2
-rw-r--r--editor/icons/PathFollow3D.svg2
-rw-r--r--editor/icons/PhysicalBone3D.svg2
-rw-r--r--editor/icons/PhysicalSkyMaterial.svg2
-rw-r--r--editor/icons/PinJoint2D.svg2
-rw-r--r--editor/icons/PinJoint3D.svg2
-rw-r--r--editor/icons/Plane.svg2
-rw-r--r--editor/icons/PlaneMesh.svg2
-rw-r--r--editor/icons/PointLight2D.svg2
-rw-r--r--editor/icons/PointMesh.svg2
-rw-r--r--editor/icons/Polygon2D.svg2
-rw-r--r--editor/icons/Portal.svg2
-rw-r--r--editor/icons/Position2D.svg2
-rw-r--r--editor/icons/Position3D.svg2
-rw-r--r--editor/icons/PrismMesh.svg2
-rw-r--r--editor/icons/ProceduralSkyMaterial.svg2
-rw-r--r--editor/icons/ProgressBar.svg2
-rw-r--r--editor/icons/ProximityGroup3D.svg2
-rw-r--r--editor/icons/Quad.svg2
-rw-r--r--editor/icons/QuadMesh.svg2
-rw-r--r--editor/icons/Quaternion.svg (renamed from editor/icons/Quat.svg)2
-rw-r--r--editor/icons/RID.svg2
-rw-r--r--editor/icons/RayCast2D.svg2
-rw-r--r--editor/icons/RayCast3D.svg2
-rw-r--r--editor/icons/Rayito.svg2
-rw-r--r--editor/icons/Rect2.svg2
-rw-r--r--editor/icons/Rect2i.svg2
-rw-r--r--editor/icons/RectangleAddRemove.svg1
-rw-r--r--editor/icons/ReferenceRect.svg2
-rw-r--r--editor/icons/ReflectionProbe.svg2
-rw-r--r--editor/icons/RemoteTransform2D.svg2
-rw-r--r--editor/icons/RemoteTransform3D.svg2
-rw-r--r--editor/icons/Reparent.svg2
-rw-r--r--editor/icons/ReparentToNewNode.svg2
-rw-r--r--editor/icons/RibbonTrailMesh.svg1
-rw-r--r--editor/icons/RichTextEffect.svg2
-rw-r--r--editor/icons/RichTextLabel.svg2
-rw-r--r--editor/icons/RigidBody2D.svg2
-rw-r--r--editor/icons/RigidBody3D.svg2
-rw-r--r--editor/icons/Room.svg2
-rw-r--r--editor/icons/RootMotionView.svg2
-rw-r--r--editor/icons/SampleLibrary.svg2
-rw-r--r--editor/icons/ScriptCreate.svg2
-rw-r--r--editor/icons/ScriptRemove.svg2
-rw-r--r--editor/icons/ScrollContainer.svg2
-rw-r--r--editor/icons/Shader.svg2
-rw-r--r--editor/icons/ShaderMaterial.svg2
-rw-r--r--editor/icons/Signal.svg2
-rw-r--r--editor/icons/Skeleton2D.svg2
-rw-r--r--editor/icons/Skeleton3D.svg2
-rw-r--r--editor/icons/SliderJoint3D.svg2
-rw-r--r--editor/icons/Slot.svg2
-rw-r--r--editor/icons/SoftBody3D.svg2
-rw-r--r--editor/icons/SphereMesh.svg2
-rw-r--r--editor/icons/SpinBox.svg2
-rw-r--r--editor/icons/SpotLight3D.svg2
-rw-r--r--editor/icons/SpringArm3D.svg2
-rw-r--r--editor/icons/Sprite2D.svg2
-rw-r--r--editor/icons/Sprite3D.svg2
-rw-r--r--editor/icons/StandardMaterial3D.svg2
-rw-r--r--editor/icons/StaticBody2D.svg2
-rw-r--r--editor/icons/StaticBody3D.svg2
-rw-r--r--editor/icons/String.svg2
-rw-r--r--editor/icons/StringName.svg2
-rw-r--r--editor/icons/StyleBoxEmpty.svg2
-rw-r--r--editor/icons/StyleBoxFlat.svg2
-rw-r--r--editor/icons/StyleBoxLine.svg2
-rw-r--r--editor/icons/StyleBoxTexture.svg2
-rw-r--r--editor/icons/SubViewportContainer.svg2
-rw-r--r--editor/icons/TabContainer.svg2
-rw-r--r--editor/icons/Tabs.svg2
-rw-r--r--editor/icons/TerrainMatchCorners.svg1
-rw-r--r--editor/icons/TerrainMatchCornersAndSides.svg1
-rw-r--r--editor/icons/TerrainMatchSides.svg1
-rw-r--r--editor/icons/TestCube.svg2
-rw-r--r--editor/icons/TextEdit.svg2
-rw-r--r--editor/icons/TextureButton.svg2
-rw-r--r--editor/icons/TextureProgressBar.svg2
-rw-r--r--editor/icons/TextureRect.svg2
-rw-r--r--editor/icons/Theme.svg2
-rw-r--r--editor/icons/ThemeDeselectAll.svg1
-rw-r--r--editor/icons/ThemeRemoveAllItems.svg1
-rw-r--r--editor/icons/ThemeRemoveCustomItems.svg1
-rw-r--r--editor/icons/ThemeSelectAll.svg1
-rw-r--r--editor/icons/ThemeSelectFull.svg1
-rw-r--r--editor/icons/TileMap.svg2
-rw-r--r--editor/icons/TouchScreenButton.svg2
-rw-r--r--editor/icons/TrackAddKey.svg2
-rw-r--r--editor/icons/TrackAddKeyHl.svg2
-rw-r--r--editor/icons/Transform2D.svg2
-rw-r--r--editor/icons/Transform3D.svg (renamed from editor/icons/Transform.svg)2
-rw-r--r--editor/icons/Tree.svg2
-rw-r--r--editor/icons/TubeTrailMesh.svg1
-rw-r--r--editor/icons/Tween.svg2
-rw-r--r--editor/icons/VBoxContainer.svg2
-rw-r--r--editor/icons/VScrollBar.svg2
-rw-r--r--editor/icons/VSeparator.svg2
-rw-r--r--editor/icons/VSlider.svg2
-rw-r--r--editor/icons/VSplitContainer.svg2
-rw-r--r--editor/icons/Variant.svg2
-rw-r--r--editor/icons/Vector2.svg2
-rw-r--r--editor/icons/Vector2i.svg2
-rw-r--r--editor/icons/Vector3.svg2
-rw-r--r--editor/icons/Vector3i.svg2
-rw-r--r--editor/icons/VehicleBody3D.svg2
-rw-r--r--editor/icons/VehicleWheel3D.svg2
-rw-r--r--editor/icons/VideoPlayer.svg2
-rw-r--r--editor/icons/VisibilityEnabler2D.svg2
-rw-r--r--editor/icons/VisibilityEnabler3D.svg2
-rw-r--r--editor/icons/VisibilityNotifier2D.svg2
-rw-r--r--editor/icons/VisibilityNotifier3D.svg2
-rw-r--r--editor/icons/VisualShader.svg2
-rw-r--r--editor/icons/VoxelGI.svg (renamed from editor/icons/GIProbe.svg)2
-rw-r--r--editor/icons/VoxelGIData.svg (renamed from editor/icons/GIProbeData.svg)0
-rw-r--r--editor/icons/WarningPattern.svg1
-rw-r--r--editor/icons/WorldEnvironment.svg2
-rw-r--r--editor/icons/X509Certificate.svg2
-rw-r--r--editor/icons/XRAnchor3D.svg2
-rw-r--r--editor/icons/XRCamera3D.svg2
-rw-r--r--editor/icons/XRController3D.svg2
-rw-r--r--editor/icons/XROrigin3D.svg2
-rw-r--r--editor/icons/YSort.svg2
-rw-r--r--editor/icons/bool.svg2
-rw-r--r--editor/icons/float.svg2
-rw-r--r--editor/icons/int.svg2
-rw-r--r--editor/import/collada.cpp51
-rw-r--r--editor/import/collada.h22
-rw-r--r--editor/import/editor_import_collada.cpp26
-rw-r--r--editor/import/editor_import_plugin.cpp72
-rw-r--r--editor/import/resource_importer_csv_translation.cpp2
-rw-r--r--editor/import/resource_importer_image.cpp4
-rw-r--r--editor/import/resource_importer_obj.cpp8
-rw-r--r--editor/import/resource_importer_scene.cpp179
-rw-r--r--editor/import/resource_importer_scene.h10
-rw-r--r--editor/import/resource_importer_shader_file.cpp2
-rw-r--r--editor/import/resource_importer_texture.cpp33
-rw-r--r--editor/import/resource_importer_texture.h2
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp2
-rw-r--r--editor/import/resource_importer_wav.cpp2
-rw-r--r--editor/import/scene_import_settings.cpp10
-rw-r--r--editor/import/scene_importer_mesh.cpp235
-rw-r--r--editor/import/scene_importer_mesh.h3
-rw-r--r--editor/inspector_dock.cpp107
-rw-r--r--editor/inspector_dock.h4
-rw-r--r--editor/localization_editor.cpp71
-rw-r--r--editor/localization_editor.h7
-rw-r--r--editor/multi_node_edit.h4
-rw-r--r--editor/node_3d_editor_gizmos.cpp376
-rw-r--r--editor/node_3d_editor_gizmos.h54
-rw-r--r--editor/plugin_config_dialog.cpp3
-rw-r--r--editor/plugins/SCsub2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp4
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp24
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp32
-rw-r--r--editor/plugins/animation_player_editor_plugin.h4
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp6
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp9
-rw-r--r--editor/plugins/asset_library_editor_plugin.h2
-rw-r--r--editor/plugins/audio_stream_editor_plugin.cpp17
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp857
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h39
-rw-r--r--editor/plugins/collision_polygon_3d_editor_plugin.cpp14
-rw-r--r--editor/plugins/curve_editor_plugin.cpp4
-rw-r--r--editor/plugins/editor_preview_plugins.cpp89
-rw-r--r--editor/plugins/font_editor_plugin.cpp2
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp6
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.cpp (renamed from editor/plugins/baked_lightmap_editor_plugin.cpp)42
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.h (renamed from editor/plugins/baked_lightmap_editor_plugin.h)16
-rw-r--r--editor/plugins/material_editor_plugin.cpp8
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp10
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp6
-rw-r--r--editor/plugins/multimesh_editor_plugin.cpp6
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp280
-rw-r--r--editor/plugins/node_3d_editor_plugin.h30
-rw-r--r--editor/plugins/occluder_instance_3d_editor_plugin.cpp117
-rw-r--r--editor/plugins/occluder_instance_3d_editor_plugin.h66
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp6
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp10
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp6
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp3
-rw-r--r--editor/plugins/script_editor_plugin.cpp163
-rw-r--r--editor/plugins/script_editor_plugin.h5
-rw-r--r--editor/plugins/script_text_editor.cpp123
-rw-r--r--editor/plugins/script_text_editor.h6
-rw-r--r--editor/plugins/shader_editor_plugin.cpp243
-rw-r--r--editor/plugins/shader_editor_plugin.h17
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp36
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h14
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp86
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h7
-rw-r--r--editor/plugins/text_editor.cpp71
-rw-r--r--editor/plugins/text_editor.h3
-rw-r--r--editor/plugins/texture_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp22
-rw-r--r--editor/plugins/theme_editor_plugin.cpp3803
-rw-r--r--editor/plugins/theme_editor_plugin.h367
-rw-r--r--editor/plugins/theme_editor_preview.cpp464
-rw-r--r--editor/plugins/theme_editor_preview.h118
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp2329
-rw-r--r--editor/plugins/tile_map_editor_plugin.h242
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp3680
-rw-r--r--editor/plugins/tile_set_editor_plugin.h298
-rw-r--r--editor/plugins/tiles/SCsub5
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp657
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h153
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp233
-rw-r--r--editor/plugins/tiles/tile_data_editors.h117
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp3570
-rw-r--r--editor/plugins/tiles/tile_map_editor.h343
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp1863
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h259
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp588
-rw-r--r--editor/plugins/tiles/tile_set_editor.h96
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp511
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.h139
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp277
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.h114
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp4
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp716
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h38
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp (renamed from editor/plugins/gi_probe_editor_plugin.cpp)74
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.h (renamed from editor/plugins/gi_probe_editor_plugin.h)24
-rw-r--r--editor/pot_generator.cpp2
-rw-r--r--editor/pot_generator.h2
-rw-r--r--editor/project_export.cpp24
-rw-r--r--editor/project_export.h2
-rw-r--r--editor/project_manager.cpp119
-rw-r--r--editor/project_manager.h2
-rw-r--r--editor/project_settings_editor.cpp264
-rw-r--r--editor/project_settings_editor.h20
-rw-r--r--editor/property_editor.cpp93
-rw-r--r--editor/property_editor.h4
-rw-r--r--editor/property_selector.cpp25
-rw-r--r--editor/quick_open.cpp4
-rw-r--r--editor/scene_tree_dock.cpp35
-rw-r--r--editor/scene_tree_dock.h3
-rw-r--r--editor/scene_tree_editor.cpp21
-rw-r--r--editor/scene_tree_editor.h4
-rw-r--r--editor/script_create_dialog.cpp16
-rw-r--r--editor/script_create_dialog.h2
-rw-r--r--editor/settings_config_dialog.cpp35
-rw-r--r--editor/shader_globals_editor.cpp4
-rw-r--r--editor/translations/af.po27
-rw-r--r--editor/translations/ar.po60
-rw-r--r--editor/translations/az.po12578
-rw-r--r--editor/translations/bg.po29
-rw-r--r--editor/translations/bn.po128
-rw-r--r--editor/translations/br.po27
-rw-r--r--editor/translations/ca.po105
-rw-r--r--editor/translations/cs.po41
-rw-r--r--editor/translations/da.po116
-rw-r--r--editor/translations/de.po105
-rw-r--r--editor/translations/editor.pot27
-rw-r--r--editor/translations/el.po124
-rw-r--r--editor/translations/eo.po1763
-rw-r--r--editor/translations/es.po53
-rw-r--r--editor/translations/es_AR.po45
-rw-r--r--editor/translations/et.po34
-rw-r--r--editor/translations/eu.po98
-rw-r--r--editor/translations/fa.po27
-rw-r--r--editor/translations/fi.po56
-rw-r--r--editor/translations/fil.po95
-rw-r--r--editor/translations/fr.po62
-rw-r--r--editor/translations/ga.po27
-rw-r--r--editor/translations/gl.po100
-rw-r--r--editor/translations/he.po65
-rw-r--r--editor/translations/hi.po171
-rw-r--r--editor/translations/hr.po27
-rw-r--r--editor/translations/hu.po28
-rw-r--r--editor/translations/id.po29
-rw-r--r--editor/translations/is.po27
-rw-r--r--editor/translations/it.po1124
-rw-r--r--editor/translations/ja.po45
-rw-r--r--editor/translations/ka.po27
-rw-r--r--editor/translations/km.po27
-rw-r--r--editor/translations/ko.po82
-rw-r--r--editor/translations/lt.po27
-rw-r--r--editor/translations/lv.po27
-rw-r--r--editor/translations/mi.po27
-rw-r--r--editor/translations/mk.po27
-rw-r--r--editor/translations/ml.po27
-rw-r--r--editor/translations/mr.po27
-rw-r--r--editor/translations/ms.po510
-rw-r--r--editor/translations/nb.po58
-rw-r--r--editor/translations/nl.po200
-rw-r--r--editor/translations/or.po27
-rw-r--r--editor/translations/pl.po51
-rw-r--r--editor/translations/pr.po76
-rw-r--r--editor/translations/pt.po65
-rw-r--r--editor/translations/pt_BR.po95
-rw-r--r--editor/translations/ro.po28
-rw-r--r--editor/translations/ru.po50
-rw-r--r--editor/translations/si.po27
-rw-r--r--editor/translations/sk.po28
-rw-r--r--editor/translations/sl.po27
-rw-r--r--editor/translations/sq.po28
-rw-r--r--editor/translations/sr_Cyrl.po27
-rw-r--r--editor/translations/sr_Latn.po27
-rw-r--r--editor/translations/sv.po120
-rw-r--r--editor/translations/ta.po27
-rw-r--r--editor/translations/te.po27
-rw-r--r--editor/translations/th.po212
-rw-r--r--editor/translations/tr.po65
-rw-r--r--editor/translations/tt.po12508
-rw-r--r--editor/translations/tzm.po27
-rw-r--r--editor/translations/uk.po55
-rw-r--r--editor/translations/ur_PK.po27
-rw-r--r--editor/translations/vi.po440
-rw-r--r--editor/translations/zh_CN.po68
-rw-r--r--editor/translations/zh_HK.po27
-rw-r--r--editor/translations/zh_TW.po41
-rw-r--r--icon_outlined.pngbin0 -> 9282 bytes
-rw-r--r--icon_outlined.svg159
-rw-r--r--logo_outlined.pngbin0 -> 17898 bytes
-rw-r--r--logo_outlined.svg185
-rw-r--r--main/main.cpp102
-rw-r--r--main/main.h1
-rw-r--r--methods.py13
-rw-r--r--misc/dist/html/fixed-size.html389
-rw-r--r--misc/dist/html/full-size.html1
-rw-r--r--misc/dist/html/offline-export.html42
-rw-r--r--misc/dist/html/service-worker.js19
-rw-r--r--misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj8
-rw-r--r--misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme10
-rw-r--r--misc/dist/linux/org.godotengine.Godot.xml6
-rw-r--r--misc/dist/osx/editor.entitlements12
-rw-r--r--misc/dist/osx/editor_mono.entitlements18
-rw-r--r--misc/dist/osx_template.app/Contents/Info.plist2
-rw-r--r--misc/dist/osx_tools.app/Contents/Info.plist2
-rwxr-xr-xmisc/hooks/canonicalize_filename.sh2
-rwxr-xr-xmisc/hooks/pre-commit-clang-format15
-rwxr-xr-xmisc/scripts/check_ci_log.py4
-rw-r--r--modules/SCsub2
-rw-r--r--modules/basis_universal/SCsub23
-rw-r--r--modules/basis_universal/register_types.cpp4
-rw-r--r--modules/basis_universal/texture_basisu.cpp2
-rw-r--r--modules/basis_universal/texture_basisu.h2
-rw-r--r--modules/bmp/image_loader_bmp.cpp28
-rw-r--r--modules/bullet/bullet_physics_server.cpp40
-rw-r--r--modules/bullet/bullet_physics_server.h34
-rw-r--r--modules/bullet/bullet_types_converter.cpp4
-rw-r--r--modules/bullet/bullet_types_converter.h6
-rw-r--r--modules/bullet/collision_object_bullet.cpp16
-rw-r--r--modules/bullet/collision_object_bullet.h16
-rw-r--r--modules/bullet/cone_twist_joint_bullet.cpp6
-rw-r--r--modules/bullet/cone_twist_joint_bullet.h2
-rw-r--r--modules/bullet/config.py1
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.cpp22
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.h10
-rw-r--r--modules/bullet/hinge_joint_bullet.cpp6
-rw-r--r--modules/bullet/hinge_joint_bullet.h2
-rw-r--r--modules/bullet/rigid_body_bullet.cpp34
-rw-r--r--modules/bullet/rigid_body_bullet.h9
-rw-r--r--modules/bullet/slider_joint_bullet.cpp30
-rw-r--r--modules/bullet/slider_joint_bullet.h14
-rw-r--r--modules/bullet/soft_body_bullet.cpp4
-rw-r--r--modules/bullet/soft_body_bullet.h4
-rw-r--r--modules/bullet/space_bullet.cpp14
-rw-r--r--modules/bullet/space_bullet.h12
-rw-r--r--modules/camera/camera_osx.mm24
-rw-r--r--modules/csg/config.py2
-rw-r--r--modules/csg/csg.cpp2
-rw-r--r--modules/csg/csg.h10
-rw-r--r--modules/csg/csg_gizmos.cpp40
-rw-r--r--modules/csg/csg_shape.cpp77
-rw-r--r--modules/csg/doc_classes/CSGMesh3D.xml3
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml2
-rw-r--r--modules/csg/icons/CSGBox3D.svg2
-rw-r--r--modules/csg/icons/CSGCapsule3D.svg2
-rw-r--r--modules/csg/icons/CSGCombiner3D.svg2
-rw-r--r--modules/csg/icons/CSGCylinder3D.svg2
-rw-r--r--modules/csg/icons/CSGMesh3D.svg2
-rw-r--r--modules/csg/icons/CSGPolygon3D.svg2
-rw-r--r--modules/csg/icons/CSGSphere3D.svg2
-rw-r--r--modules/csg/icons/CSGTorus3D.svg2
-rw-r--r--modules/dds/texture_loader_dds.cpp2
-rw-r--r--modules/enet/doc_classes/NetworkedMultiplayerENet.xml13
-rw-r--r--modules/enet/networked_multiplayer_enet.cpp88
-rw-r--r--modules/enet/networked_multiplayer_enet.h9
-rw-r--r--modules/fbx/README.md30
-rw-r--r--modules/fbx/SCsub3
-rw-r--r--modules/fbx/data/fbx_bone.h2
-rw-r--r--modules/fbx/data/fbx_material.h6
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp6
-rw-r--r--modules/fbx/data/fbx_mesh_data.h4
-rw-r--r--modules/fbx/data/fbx_node.h2
-rw-r--r--modules/fbx/data/fbx_skeleton.h4
-rw-r--r--modules/fbx/data/pivot_transform.cpp90
-rw-r--r--modules/fbx/data/pivot_transform.h30
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp67
-rw-r--r--modules/fbx/fbx_parser/FBXAnimation.cpp2
-rw-r--r--modules/fbx/fbx_parser/FBXDeformer.cpp2
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.cpp2
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.h24
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.cpp8
-rw-r--r--modules/fbx/fbx_parser/FBXMaterial.cpp2
-rw-r--r--modules/fbx/fbx_parser/FBXMeshGeometry.cpp8
-rw-r--r--modules/fbx/fbx_parser/FBXMeshGeometry.h6
-rw-r--r--modules/fbx/fbx_parser/FBXParser.cpp12
-rw-r--r--modules/fbx/fbx_parser/FBXParser.h6
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.cpp2
-rw-r--r--modules/fbx/fbx_parser/FBXUtil.cpp2
-rw-r--r--modules/fbx/tools/import_utils.cpp12
-rw-r--r--modules/fbx/tools/import_utils.h12
-rw-r--r--modules/fbx/tools/validation_tools.h2
-rw-r--r--modules/gdnative/doc_classes/GDNative.xml2
-rw-r--r--modules/gdnative/gdnative.cpp14
-rw-r--r--modules/gdnative/gdnative.h4
-rw-r--r--modules/gdnative/gdnative/quaternion.cpp (renamed from modules/gdnative/gdnative/quat.cpp)24
-rw-r--r--modules/gdnative/gdnative/transform_3d.cpp (renamed from modules/gdnative/gdnative/transform.cpp)16
-rw-r--r--modules/gdnative/gdnative/variant.cpp34
-rw-r--r--modules/gdnative/gdnative_api.json56
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp9
-rw-r--r--modules/gdnative/include/gdnative/callable.h1
-rw-r--r--modules/gdnative/include/gdnative/gdnative.h8
-rw-r--r--modules/gdnative/include/gdnative/quaternion.h (renamed from modules/gdnative/include/gdnative/transform.h)24
-rw-r--r--modules/gdnative/include/gdnative/signal.h1
-rw-r--r--modules/gdnative/include/gdnative/transform_3d.h (renamed from modules/gdnative/include/gdnative/quat.h)26
-rw-r--r--modules/gdnative/include/gdnative/variant.h16
-rw-r--r--modules/gdnative/include/pluginscript/godot_pluginscript.h10
-rw-r--r--modules/gdnative/include/xr/godot_xr.h31
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp43
-rw-r--r--modules/gdnative/nativescript/godot_nativescript.cpp24
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp292
-rw-r--r--modules/gdnative/nativescript/nativescript.h34
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.cpp38
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.h12
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp6
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.h1
-rw-r--r--modules/gdnative/pluginscript/pluginscript_loader.cpp2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp103
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.h15
-rw-r--r--modules/gdnative/pluginscript/register_types.cpp2
-rw-r--r--modules/gdnative/register_types.cpp2
-rw-r--r--modules/gdnative/tests/test_variant.h2
-rw-r--r--modules/gdnative/videodecoder/video_stream_gdnative.cpp32
-rw-r--r--modules/gdnative/videodecoder/video_stream_gdnative.h2
-rw-r--r--modules/gdnative/xr/xr_interface_gdnative.cpp71
-rw-r--r--modules/gdnative/xr/xr_interface_gdnative.h14
-rw-r--r--modules/gdnavigation/gd_navigation_server.cpp12
-rw-r--r--modules/gdnavigation/gd_navigation_server.h2
-rw-r--r--modules/gdnavigation/nav_map.cpp10
-rw-r--r--modules/gdnavigation/nav_region.cpp2
-rw-r--r--modules/gdnavigation/nav_region.h6
-rw-r--r--modules/gdnavigation/navigation_mesh_generator.cpp16
-rw-r--r--modules/gdnavigation/navigation_mesh_generator.h6
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml4
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp31
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h2
-rw-r--r--modules/gdscript/gdscript.cpp178
-rw-r--r--modules/gdscript/gdscript.h41
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp172
-rw-r--r--modules/gdscript/gdscript_analyzer.h4
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp193
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h17
-rw-r--r--modules/gdscript/gdscript_cache.cpp6
-rw-r--r--modules/gdscript/gdscript_cache.h4
-rw-r--r--modules/gdscript/gdscript_codegen.h3
-rw-r--r--modules/gdscript/gdscript_compiler.cpp186
-rw-r--r--modules/gdscript/gdscript_compiler.h2
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp53
-rw-r--r--modules/gdscript/gdscript_editor.cpp19
-rw-r--r--modules/gdscript/gdscript_function.cpp4
-rw-r--r--modules/gdscript/gdscript_function.h19
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp (renamed from platform/javascript/javascript_eval.cpp)90
-rw-r--r--modules/gdscript/gdscript_lambda_callable.h65
-rw-r--r--modules/gdscript/gdscript_parser.cpp274
-rw-r--r--modules/gdscript/gdscript_parser.h56
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp14
-rw-r--r--modules/gdscript/gdscript_tokenizer.h3
-rw-r--r--modules/gdscript/gdscript_vm.cpp154
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp88
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp3
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.h6
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp4
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp1
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h8
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp11
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h5
-rw-r--r--modules/gdscript/language_server/lsp.hpp118
-rw-r--r--modules/gdscript/register_types.cpp4
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp19
-rw-r--r--modules/gdscript/tests/gdscript_test_runner_suite.h21
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_argument.gd (renamed from modules/gdscript/tests/scripts/parser-errors/missing-argument.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_argument.out (renamed from modules/gdscript/tests/scripts/parser-errors/missing-argument.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd (renamed from modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.out (renamed from modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_colon.gd (renamed from modules/gdscript/tests/scripts/parser-errors/missing-colon.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_colon.out (renamed from modules/gdscript/tests/scripts/parser-errors/missing-colon.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd (renamed from modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.out (renamed from modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.gd (renamed from modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out (renamed from modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd (renamed from modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out (renamed from modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd (renamed from modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out (renamed from modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd (renamed from modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out (renamed from modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd (renamed from modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out (renamed from modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.gd (renamed from modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.out (renamed from modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/features/variable_declaration.gd (renamed from modules/gdscript/tests/scripts/parser-features/variable-declaration.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/features/variable_declaration.out (renamed from modules/gdscript/tests/scripts/parser-features/variable-declaration.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd (renamed from modules/gdscript/tests/scripts/parser-warnings/unused-variable.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unused_variable.out (renamed from modules/gdscript/tests/scripts/parser-warnings/unused-variable.out)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.gd5
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.out6
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp20
-rw-r--r--modules/glslang/register_types.cpp13
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml6
-rw-r--r--modules/gltf/editor_scene_importer_gltf.cpp2
-rw-r--r--modules/gltf/gltf_animation.h2
-rw-r--r--modules/gltf/gltf_document.cpp440
-rw-r--r--modules/gltf/gltf_document.h18
-rw-r--r--modules/gltf/gltf_node.cpp23
-rw-r--r--modules/gltf/gltf_node.h16
-rw-r--r--modules/gltf/gltf_skin.cpp2
-rw-r--r--modules/gltf/gltf_skin.h2
-rw-r--r--modules/gridmap/config.py2
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml4
-rw-r--r--modules/gridmap/grid_map.cpp33
-rw-r--r--modules/gridmap/grid_map.h6
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp56
-rw-r--r--modules/gridmap/grid_map_editor_plugin.h7
-rw-r--r--modules/gridmap/icons/GridMap.svg2
-rw-r--r--modules/jpg/image_loader_jpegd.cpp2
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp94
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h2
-rw-r--r--modules/lightmapper_rd/lm_common_inc.glsl7
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl21
-rw-r--r--modules/mbedtls/crypto_mbedtls.cpp12
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.cpp10
-rw-r--r--modules/mbedtls/ssl_context_mbedtls.h8
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.cpp4
-rw-r--r--modules/meshoptimizer/config.py2
-rw-r--r--modules/meshoptimizer/register_types.cpp1
-rw-r--r--modules/minimp3/audio_stream_mp3.cpp6
-rw-r--r--modules/minimp3/resource_importer_mp3.cpp4
-rw-r--r--modules/mobile_vr/config.py2
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp95
-rw-r--r--modules/mobile_vr/mobile_vr_interface.h14
-rw-r--r--modules/mono/class_db_api_json.cpp2
-rw-r--r--modules/mono/csharp_script.cpp289
-rw-r--r--modules/mono/csharp_script.h34
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs6
-rw-r--r--modules/mono/editor/bindings_generator.cpp57
-rw-r--r--modules/mono/editor/bindings_generator.h10
-rw-r--r--modules/mono/editor/godotsharp_export.cpp2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs84
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs27
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs586
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs)100
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs (renamed from modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs)96
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs49
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs23
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs41
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj4
-rw-r--r--modules/mono/glue/base_object_glue.cpp34
-rw-r--r--modules/mono/glue/glue_header.h2
-rw-r--r--modules/mono/godotsharp_dirs.cpp6
-rw-r--r--modules/mono/mono_gc_handle.h6
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp16
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp14
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp6
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp44
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h42
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp14
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h2
-rw-r--r--modules/mono/mono_gd/support/ios_support.mm8
-rw-r--r--modules/mono/signal_awaiter_utils.h2
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp2
-rw-r--r--modules/mono/utils/path_utils.cpp6
-rw-r--r--modules/mono/utils/string_utils.cpp6
-rw-r--r--modules/opensimplex/doc_classes/NoiseTexture.xml3
-rw-r--r--modules/opensimplex/doc_classes/OpenSimplexNoise.xml4
-rw-r--r--modules/opensimplex/noise_texture.cpp18
-rw-r--r--modules/opensimplex/noise_texture.h6
-rw-r--r--modules/opensimplex/open_simplex_noise.cpp6
-rw-r--r--modules/opensimplex/open_simplex_noise.h4
-rw-r--r--modules/pvr/image_compress_pvrtc.cpp4
-rw-r--r--modules/pvr/texture_loader_pvr.cpp2
-rw-r--r--modules/raycast/SCsub97
-rw-r--r--modules/raycast/config.py17
-rw-r--r--modules/raycast/godot_update_embree.py251
-rw-r--r--modules/raycast/lightmap_raycaster.cpp201
-rw-r--r--modules/raycast/lightmap_raycaster.h77
-rw-r--r--modules/raycast/raycast_occlusion_cull.cpp583
-rw-r--r--modules/raycast/raycast_occlusion_cull.h184
-rw-r--r--modules/raycast/register_types.cpp (renamed from core/os/copymem.h)33
-rw-r--r--modules/raycast/register_types.h (renamed from scene/2d/y_sort.h)21
-rw-r--r--modules/regex/doc_classes/RegEx.xml2
-rw-r--r--modules/regex/doc_classes/RegExMatch.xml2
-rw-r--r--modules/regex/regex.h10
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp6
-rw-r--r--modules/stb_vorbis/resource_importer_ogg_vorbis.cpp4
-rw-r--r--modules/svg/image_loader_svg.cpp2
-rw-r--r--modules/text_server_adv/SCsub4
-rw-r--r--modules/text_server_adv/dynamic_font_adv.cpp2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp32
-rw-r--r--modules/text_server_fb/dynamic_font_fb.cpp2
-rw-r--r--modules/text_server_fb/text_server_fb.cpp14
-rw-r--r--modules/tga/image_loader_tga.cpp26
-rw-r--r--modules/tga/image_loader_tga.h4
-rw-r--r--modules/theora/video_stream_theora.cpp20
-rw-r--r--modules/theora/video_stream_theora.h2
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp2
-rw-r--r--modules/tinyexr/image_saver_tinyexr.cpp2
-rw-r--r--modules/upnp/doc_classes/UPNP.xml2
-rw-r--r--modules/upnp/doc_classes/UPNPDevice.xml2
-rw-r--r--modules/upnp/upnp.h6
-rw-r--r--modules/upnp/upnp_device.h6
-rw-r--r--modules/vhacd/config.py2
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptClassConstant.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEmitSignal.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunctionCall.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunctionState.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptInputAction.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVar.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertyGet.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertySet.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptTypeCast.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptVariableGet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptVariableSet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptYieldSignal.xml4
-rw-r--r--modules/visual_script/visual_script.cpp110
-rw-r--r--modules/visual_script/visual_script.h32
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp5
-rw-r--r--modules/visual_script/visual_script_editor.cpp137
-rw-r--r--modules/visual_script/visual_script_editor.h4
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp16
-rw-r--r--modules/visual_script/visual_script_nodes.cpp4
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp10
-rw-r--r--modules/webm/libvpx/SCsub9
-rw-r--r--modules/webm/video_stream_webm.cpp8
-rw-r--r--modules/webp/image_loader_webp.cpp79
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnection.xml4
-rw-r--r--modules/webrtc/webrtc_multiplayer.h2
-rw-r--r--modules/webrtc/webrtc_peer_connection.h4
-rw-r--r--modules/websocket/emws_client.cpp4
-rw-r--r--modules/websocket/emws_client.h2
-rw-r--r--modules/websocket/emws_peer.cpp4
-rw-r--r--modules/websocket/emws_peer.h2
-rw-r--r--modules/websocket/emws_server.cpp4
-rw-r--r--modules/websocket/emws_server.h4
-rw-r--r--modules/websocket/packet_buffer.h5
-rw-r--r--modules/websocket/websocket_client.cpp32
-rw-r--r--modules/websocket/websocket_client.h2
-rw-r--r--modules/websocket/websocket_multiplayer_peer.cpp20
-rw-r--r--modules/websocket/websocket_peer.h2
-rw-r--r--modules/websocket/websocket_server.cpp6
-rw-r--r--modules/websocket/websocket_server.h10
-rw-r--r--modules/websocket/wsl_client.cpp6
-rw-r--r--modules/websocket/wsl_client.h2
-rw-r--r--modules/websocket/wsl_peer.cpp4
-rw-r--r--modules/websocket/wsl_peer.h2
-rw-r--r--modules/websocket/wsl_server.cpp4
-rw-r--r--modules/websocket/wsl_server.h6
-rw-r--r--modules/webxr/config.py2
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml2
-rw-r--r--modules/webxr/native/library_godot_webxr.js2
-rw-r--r--modules/webxr/webxr_interface_js.cpp35
-rw-r--r--modules/webxr/webxr_interface_js.h7
-rw-r--r--modules/xatlas_unwrap/register_types.cpp210
-rw-r--r--platform/android/SCsub1
-rw-r--r--platform/android/android_keys_utils.h4
-rw-r--r--platform/android/api/java_class_wrapper.h10
-rw-r--r--platform/android/audio_driver_jandroid.cpp185
-rw-r--r--platform/android/detect.py5
-rw-r--r--platform/android/dir_access_jandroid.cpp3
-rw-r--r--platform/android/dir_access_jandroid.h9
-rw-r--r--platform/android/display_server_android.cpp54
-rw-r--r--platform/android/display_server_android.h29
-rw-r--r--platform/android/export/export.cpp88
-rw-r--r--platform/android/export/gradle_export_util.h51
-rw-r--r--platform/android/file_access_android.cpp14
-rw-r--r--platform/android/file_access_android.h14
-rw-r--r--platform/android/java/app/AndroidManifest.xml9
-rw-r--r--platform/android/java/app/config.gradle2
-rw-r--r--platform/android/java/build.gradle6
-rw-r--r--platform/android/java/gradlew.bat4
-rw-r--r--platform/android/java/lib/res/values/strings.xml2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java23
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotIO.java93
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java24
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt6
-rw-r--r--platform/android/java_class_wrapper.cpp4
-rw-r--r--platform/android/java_godot_io_wrapper.cpp12
-rw-r--r--platform/android/java_godot_io_wrapper.h2
-rw-r--r--platform/android/java_godot_lib_jni.cpp8
-rw-r--r--platform/android/java_godot_lib_jni.h1
-rw-r--r--platform/android/java_godot_view_wrapper.cpp10
-rw-r--r--platform/android/java_godot_view_wrapper.h2
-rw-r--r--platform/android/net_socket_android.cpp4
-rw-r--r--platform/android/net_socket_android.h4
-rw-r--r--platform/android/os_android.cpp43
-rw-r--r--platform/android/os_android.h3
-rw-r--r--platform/android/plugin/godot_plugin_config.h6
-rw-r--r--platform/iphone/SCsub1
-rw-r--r--platform/iphone/display_server_iphone.h8
-rw-r--r--platform/iphone/display_server_iphone.mm71
-rw-r--r--platform/iphone/export/export.cpp68
-rw-r--r--platform/iphone/godot_app_delegate.m2
-rw-r--r--platform/iphone/godot_iphone.mm4
-rw-r--r--platform/iphone/godot_view.mm10
-rw-r--r--platform/iphone/ios.mm8
-rw-r--r--platform/iphone/keyboard_input_view.mm6
-rw-r--r--platform/iphone/native_video_view.h41
-rw-r--r--platform/iphone/native_video_view.m266
-rw-r--r--platform/iphone/os_iphone.mm12
-rw-r--r--platform/iphone/plugin/godot_plugin_config.h4
-rw-r--r--platform/iphone/view_controller.h5
-rw-r--r--platform/iphone/view_controller.mm24
-rw-r--r--platform/iphone/vulkan_context_iphone.mm4
-rw-r--r--platform/javascript/SCsub7
-rw-r--r--platform/javascript/api/api.cpp39
-rw-r--r--platform/javascript/api/javascript_singleton.h68
-rw-r--r--platform/javascript/api/javascript_tools_editor_plugin.cpp35
-rw-r--r--platform/javascript/detect.py9
-rw-r--r--platform/javascript/display_server_javascript.cpp36
-rw-r--r--platform/javascript/dom_keys.inc4
-rw-r--r--platform/javascript/emscripten_helpers.py24
-rw-r--r--platform/javascript/export/export.cpp670
-rw-r--r--platform/javascript/godot_js.h2
-rw-r--r--platform/javascript/http_client.h.inc3
-rw-r--r--platform/javascript/http_client_javascript.cpp2
-rw-r--r--platform/javascript/javascript_main.cpp5
-rw-r--r--platform/javascript/javascript_singleton.cpp346
-rw-r--r--platform/javascript/js/libs/library_godot_audio.js2
-rw-r--r--platform/javascript/js/libs/library_godot_display.js2
-rw-r--r--platform/javascript/js/libs/library_godot_editor_tools.js57
-rw-r--r--platform/javascript/js/libs/library_godot_eval.js86
-rw-r--r--platform/javascript/js/libs/library_godot_fetch.js8
-rw-r--r--platform/javascript/js/libs/library_godot_javascript_singleton.js333
-rw-r--r--platform/javascript/js/libs/library_godot_os.js17
-rw-r--r--platform/javascript/package-lock.json1017
-rw-r--r--platform/javascript/package.json8
-rw-r--r--platform/linuxbsd/SCsub22
-rw-r--r--platform/linuxbsd/detect.py37
-rw-r--r--platform/linuxbsd/display_server_x11.cpp37
-rw-r--r--platform/linuxbsd/export/export.cpp2
-rw-r--r--platform/linuxbsd/key_mapping_x11.cpp8
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp29
-rw-r--r--platform/osx/crash_handler_osx.mm10
-rw-r--r--platform/osx/dir_access_osx.h2
-rw-r--r--platform/osx/display_server_osx.mm69
-rw-r--r--platform/osx/export/export.cpp100
-rw-r--r--platform/osx/os_osx.mm42
-rw-r--r--platform/osx/vulkan_context_osx.mm4
-rw-r--r--platform/server/SCsub16
-rw-r--r--platform/server/detect.py296
-rw-r--r--platform/server/godot_server.cpp49
-rw-r--r--platform/server/logo.pngbin2016 -> 0 bytes
-rw-r--r--platform/server/os_server.cpp267
-rw-r--r--platform/server/os_server.h116
-rw-r--r--platform/server/platform_config.h49
-rw-r--r--platform/uwp/SCsub1
-rw-r--r--platform/uwp/app.cpp12
-rw-r--r--platform/uwp/export/export.cpp18
-rw-r--r--platform/uwp/os_uwp.cpp12
-rw-r--r--platform/windows/context_gl_windows.cpp2
-rw-r--r--platform/windows/display_server_windows.cpp131
-rw-r--r--platform/windows/export/export.cpp2
-rw-r--r--platform/windows/godot.natvis12
-rw-r--r--platform/windows/key_mapping_windows.cpp8
-rw-r--r--platform/windows/os_windows.cpp44
-rw-r--r--scene/2d/area_2d.cpp34
-rw-r--r--scene/2d/area_2d.h2
-rw-r--r--scene/2d/audio_stream_player_2d.cpp6
-rw-r--r--scene/2d/camera_2d.cpp9
-rw-r--r--scene/2d/collision_object_2d.cpp8
-rw-r--r--scene/2d/collision_object_2d.h3
-rw-r--r--scene/2d/collision_polygon_2d.cpp2
-rw-r--r--scene/2d/collision_shape_2d.cpp2
-rw-r--r--scene/2d/cpu_particles_2d.cpp4
-rw-r--r--scene/2d/cpu_particles_2d.h2
-rw-r--r--scene/2d/gpu_particles_2d.cpp209
-rw-r--r--scene/2d/gpu_particles_2d.h24
-rw-r--r--scene/2d/light_2d.cpp4
-rw-r--r--scene/2d/mesh_instance_2d.cpp3
-rw-r--r--scene/2d/multimesh_instance_2d.cpp3
-rw-r--r--scene/2d/navigation_agent_2d.cpp27
-rw-r--r--scene/2d/navigation_agent_2d.h1
-rw-r--r--scene/2d/node_2d.cpp15
-rw-r--r--scene/2d/node_2d.h4
-rw-r--r--scene/2d/physical_bone_2d.cpp303
-rw-r--r--scene/2d/physical_bone_2d.h88
-rw-r--r--scene/2d/physics_body_2d.cpp639
-rw-r--r--scene/2d/physics_body_2d.h132
-rw-r--r--scene/2d/polygon_2d.cpp48
-rw-r--r--scene/2d/polygon_2d.h3
-rw-r--r--scene/2d/position_2d.cpp39
-rw-r--r--scene/2d/ray_cast_2d.cpp2
-rw-r--r--scene/2d/skeleton_2d.cpp531
-rw-r--r--scene/2d/skeleton_2d.h53
-rw-r--r--scene/2d/sprite_2d.cpp16
-rw-r--r--scene/2d/sprite_2d.h4
-rw-r--r--scene/2d/tile_map.cpp2684
-rw-r--r--scene/2d/tile_map.h425
-rw-r--r--scene/2d/visibility_notifier_2d.cpp300
-rw-r--r--scene/2d/visibility_notifier_2d.h45
-rw-r--r--scene/2d/y_sort.cpp52
-rw-r--r--scene/3d/SCsub1
-rw-r--r--scene/3d/area_3d.cpp32
-rw-r--r--scene/3d/area_3d.h2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp9
-rw-r--r--scene/3d/audio_stream_player_3d.h2
-rw-r--r--scene/3d/camera_3d.cpp31
-rw-r--r--scene/3d/camera_3d.h5
-rw-r--r--scene/3d/collision_object_3d.cpp145
-rw-r--r--scene/3d/collision_object_3d.h21
-rw-r--r--scene/3d/collision_polygon_3d.cpp2
-rw-r--r--scene/3d/collision_shape_3d.cpp16
-rw-r--r--scene/3d/collision_shape_3d.h2
-rw-r--r--scene/3d/cpu_particles_3d.cpp12
-rw-r--r--scene/3d/cpu_particles_3d.h4
-rw-r--r--scene/3d/gpu_particles_3d.cpp178
-rw-r--r--scene/3d/gpu_particles_3d.h36
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp12
-rw-r--r--scene/3d/gpu_particles_collision_3d.h2
-rw-r--r--scene/3d/lightmap_gi.cpp (renamed from scene/3d/baked_lightmap.cpp)240
-rw-r--r--scene/3d/lightmap_gi.h (renamed from scene/3d/baked_lightmap.h)38
-rw-r--r--scene/3d/lightmapper.cpp9
-rw-r--r--scene/3d/lightmapper.h85
-rw-r--r--scene/3d/listener_3d.cpp2
-rw-r--r--scene/3d/listener_3d.h2
-rw-r--r--scene/3d/mesh_instance_3d.cpp40
-rw-r--r--scene/3d/mesh_instance_3d.h3
-rw-r--r--scene/3d/navigation_agent_3d.cpp26
-rw-r--r--scene/3d/navigation_agent_3d.h1
-rw-r--r--scene/3d/node_3d.cpp138
-rw-r--r--scene/3d/node_3d.h38
-rw-r--r--scene/3d/occluder_instance_3d.cpp335
-rw-r--r--scene/3d/occluder_instance_3d.h108
-rw-r--r--scene/3d/path_3d.cpp2
-rw-r--r--scene/3d/physics_body_3d.cpp783
-rw-r--r--scene/3d/physics_body_3d.h169
-rw-r--r--scene/3d/physics_joint_3d.cpp40
-rw-r--r--scene/3d/ray_cast_3d.cpp6
-rw-r--r--scene/3d/reflection_probe.cpp4
-rw-r--r--scene/3d/remote_transform_3d.cpp8
-rw-r--r--scene/3d/skeleton_3d.cpp166
-rw-r--r--scene/3d/skeleton_3d.h55
-rw-r--r--scene/3d/skeleton_ik_3d.cpp100
-rw-r--r--scene/3d/skeleton_ik_3d.h26
-rw-r--r--scene/3d/soft_body_3d.cpp14
-rw-r--r--scene/3d/spring_arm_3d.cpp2
-rw-r--r--scene/3d/sprite_3d.cpp16
-rw-r--r--scene/3d/sprite_3d.h4
-rw-r--r--scene/3d/vehicle_body_3d.cpp9
-rw-r--r--scene/3d/vehicle_body_3d.h4
-rw-r--r--scene/3d/velocity_tracker_3d.h4
-rw-r--r--scene/3d/visibility_notifier_3d.cpp229
-rw-r--r--scene/3d/visibility_notifier_3d.h53
-rw-r--r--scene/3d/visual_instance_3d.cpp89
-rw-r--r--scene/3d/visual_instance_3d.h34
-rw-r--r--scene/3d/voxel_gi.cpp (renamed from scene/3d/gi_probe.cpp)244
-rw-r--r--scene/3d/voxel_gi.h (renamed from scene/3d/gi_probe.h)42
-rw-r--r--scene/3d/voxelizer.cpp24
-rw-r--r--scene/3d/voxelizer.h18
-rw-r--r--scene/3d/xr_nodes.cpp23
-rw-r--r--scene/animation/animation_cache.cpp23
-rw-r--r--scene/animation/animation_cache.h8
-rw-r--r--scene/animation/animation_node_state_machine.cpp2
-rw-r--r--scene/animation/animation_player.cpp38
-rw-r--r--scene/animation/animation_player.h10
-rw-r--r--scene/animation/animation_tree.cpp83
-rw-r--r--scene/animation/animation_tree.h12
-rw-r--r--scene/animation/root_motion_view.cpp4
-rw-r--r--scene/animation/root_motion_view.h2
-rw-r--r--scene/animation/tween.cpp32
-rw-r--r--scene/debugger/scene_debugger.cpp2
-rw-r--r--scene/gui/aspect_ratio_container.cpp2
-rw-r--r--scene/gui/base_button.cpp13
-rw-r--r--scene/gui/button.cpp2
-rw-r--r--scene/gui/code_edit.cpp1694
-rw-r--r--scene/gui/code_edit.h191
-rw-r--r--scene/gui/color_picker.cpp132
-rw-r--r--scene/gui/color_picker.h16
-rw-r--r--scene/gui/control.cpp511
-rw-r--r--scene/gui/control.h51
-rw-r--r--scene/gui/dialogs.cpp6
-rw-r--r--scene/gui/dialogs.h4
-rw-r--r--scene/gui/file_dialog.cpp16
-rw-r--r--scene/gui/file_dialog.h6
-rw-r--r--scene/gui/gradient_edit.cpp10
-rw-r--r--scene/gui/graph_edit.cpp141
-rw-r--r--scene/gui/graph_edit.h28
-rw-r--r--scene/gui/graph_node.cpp78
-rw-r--r--scene/gui/graph_node.h12
-rw-r--r--scene/gui/grid_container.cpp2
-rw-r--r--scene/gui/item_list.cpp13
-rw-r--r--scene/gui/label.cpp3
-rw-r--r--scene/gui/line_edit.cpp40
-rw-r--r--scene/gui/line_edit.h2
-rw-r--r--scene/gui/link_button.cpp2
-rw-r--r--scene/gui/nine_patch_rect.cpp3
-rw-r--r--scene/gui/popup_menu.cpp8
-rw-r--r--scene/gui/rich_text_effect.h4
-rw-r--r--scene/gui/rich_text_label.cpp184
-rw-r--r--scene/gui/rich_text_label.h3
-rw-r--r--scene/gui/scroll_container.cpp161
-rw-r--r--scene/gui/scroll_container.h25
-rw-r--r--scene/gui/slider.cpp2
-rw-r--r--scene/gui/spin_box.cpp8
-rw-r--r--scene/gui/spin_box.h2
-rw-r--r--scene/gui/split_container.cpp2
-rw-r--r--scene/gui/tab_container.cpp1
-rw-r--r--scene/gui/tabs.cpp5
-rw-r--r--scene/gui/text_edit.cpp1189
-rw-r--r--scene/gui/text_edit.h82
-rw-r--r--scene/gui/texture_button.cpp3
-rw-r--r--scene/gui/tree.cpp639
-rw-r--r--scene/gui/tree.h117
-rw-r--r--scene/main/canvas_item.cpp12
-rw-r--r--scene/main/http_request.cpp59
-rw-r--r--scene/main/http_request.h2
-rw-r--r--scene/main/node.cpp291
-rw-r--r--scene/main/node.h49
-rw-r--r--scene/main/scene_tree.cpp11
-rw-r--r--scene/main/scene_tree.h4
-rw-r--r--scene/main/shader_globals_override.cpp2
-rw-r--r--scene/main/viewport.cpp137
-rw-r--r--scene/main/viewport.h34
-rw-r--r--scene/main/window.cpp140
-rw-r--r--scene/main/window.h31
-rw-r--r--scene/register_scene_types.cpp96
-rw-r--r--scene/resources/animation.cpp86
-rw-r--r--scene/resources/animation.h18
-rw-r--r--scene/resources/audio_stream_sample.cpp8
-rw-r--r--scene/resources/bit_map.cpp4
-rw-r--r--scene/resources/convex_polygon_shape_3d.cpp4
-rw-r--r--scene/resources/curve.cpp4
-rw-r--r--scene/resources/curve.h2
-rw-r--r--scene/resources/default_theme/SCsub12
-rw-r--r--scene/resources/default_theme/default_theme.cpp88
-rw-r--r--scene/resources/default_theme/default_theme_builders.py40
-rw-r--r--scene/resources/default_theme/ellipsis.pngbin0 -> 193 bytes
-rw-r--r--scene/resources/default_theme/font_hidpi.inc25463
-rw-r--r--scene/resources/default_theme/font_lodpi.inc13117
-rw-r--r--scene/resources/default_theme/theme_data.h4
-rw-r--r--scene/resources/material.cpp38
-rw-r--r--scene/resources/material.h11
-rw-r--r--scene/resources/mesh.cpp144
-rw-r--r--scene/resources/mesh.h7
-rw-r--r--scene/resources/mesh_data_tool.h4
-rw-r--r--scene/resources/mesh_library.cpp10
-rw-r--r--scene/resources/mesh_library.h8
-rw-r--r--scene/resources/multimesh.cpp8
-rw-r--r--scene/resources/multimesh.h4
-rw-r--r--scene/resources/navigation_mesh.cpp2
-rw-r--r--scene/resources/packed_scene.h4
-rw-r--r--scene/resources/particles_material.cpp6
-rw-r--r--scene/resources/physics_material.cpp4
-rw-r--r--scene/resources/primitive_meshes.cpp551
-rw-r--r--scene/resources/primitive_meshes.h94
-rw-r--r--scene/resources/resource_format_text.cpp19
-rw-r--r--scene/resources/resource_format_text.h2
-rw-r--r--scene/resources/shader.cpp8
-rw-r--r--scene/resources/shape_3d.cpp4
-rw-r--r--scene/resources/shape_3d.h2
-rw-r--r--scene/resources/skeleton_modification_2d.cpp253
-rw-r--r--scene/resources/skeleton_modification_2d.h85
-rw-r--r--scene/resources/skeleton_modification_2d_ccdik.cpp545
-rw-r--r--scene/resources/skeleton_modification_2d_ccdik.h116
-rw-r--r--scene/resources/skeleton_modification_2d_fabrik.cpp444
-rw-r--r--scene/resources/skeleton_modification_2d_fabrik.h108
-rw-r--r--scene/resources/skeleton_modification_2d_jiggle.cpp564
-rw-r--r--scene/resources/skeleton_modification_2d_jiggle.h139
-rw-r--r--scene/resources/skeleton_modification_2d_lookat.cpp407
-rw-r--r--scene/resources/skeleton_modification_2d_lookat.h100
-rw-r--r--scene/resources/skeleton_modification_2d_physicalbones.cpp297
-rw-r--r--scene/resources/skeleton_modification_2d_physicalbones.h82
-rw-r--r--scene/resources/skeleton_modification_2d_stackholder.cpp131
-rw-r--r--scene/resources/skeleton_modification_2d_stackholder.h64
-rw-r--r--scene/resources/skeleton_modification_2d_twoboneik.cpp481
-rw-r--r--scene/resources/skeleton_modification_2d_twoboneik.h107
-rw-r--r--scene/resources/skeleton_modification_stack_2d.cpp269
-rw-r--r--scene/resources/skeleton_modification_stack_2d.h99
-rw-r--r--scene/resources/skin.cpp8
-rw-r--r--scene/resources/skin.h12
-rw-r--r--scene/resources/sky_material.cpp2
-rw-r--r--scene/resources/style_box.cpp3
-rw-r--r--scene/resources/surface_tool.cpp33
-rw-r--r--scene/resources/surface_tool.h8
-rw-r--r--scene/resources/text_file.cpp6
-rw-r--r--scene/resources/text_line.cpp2
-rw-r--r--scene/resources/text_line.h4
-rw-r--r--scene/resources/text_paragraph.cpp2
-rw-r--r--scene/resources/text_paragraph.h4
-rw-r--r--scene/resources/texture.cpp209
-rw-r--r--scene/resources/texture.h70
-rw-r--r--scene/resources/theme.cpp730
-rw-r--r--scene/resources/theme.h131
-rw-r--r--scene/resources/tile_set.cpp5213
-rw-r--r--scene/resources/tile_set.h740
-rw-r--r--scene/resources/visual_shader.cpp575
-rw-r--r--scene/resources/visual_shader.h43
-rw-r--r--scene/resources/visual_shader_nodes.cpp345
-rw-r--r--scene/resources/visual_shader_nodes.h212
-rw-r--r--scene/resources/visual_shader_particle_nodes.cpp1025
-rw-r--r--scene/resources/visual_shader_particle_nodes.h285
-rw-r--r--scene/resources/world_2d.cpp289
-rw-r--r--scene/resources/world_2d.h14
-rw-r--r--scene/resources/world_3d.cpp213
-rw-r--r--scene/resources/world_3d.h14
-rw-r--r--scene/scene_string_names.cpp9
-rw-r--r--scene/scene_string_names.h9
-rw-r--r--servers/audio/audio_effect.h4
-rw-r--r--servers/audio/audio_stream.h4
-rw-r--r--servers/audio/effects/audio_effect_capture.h2
-rw-r--r--servers/audio/effects/audio_effect_distortion.cpp2
-rw-r--r--servers/audio/effects/audio_effect_pitch_shift.cpp4
-rw-r--r--servers/audio/effects/audio_effect_pitch_shift.h10
-rw-r--r--servers/audio/effects/audio_effect_record.h2
-rw-r--r--servers/audio/effects/audio_effect_spectrum_analyzer.cpp4
-rw-r--r--servers/audio/effects/audio_effect_spectrum_analyzer.h10
-rw-r--r--servers/audio/effects/reverb.cpp2
-rw-r--r--servers/audio_server.cpp6
-rw-r--r--servers/camera/camera_feed.h4
-rw-r--r--servers/camera_server.h2
-rw-r--r--servers/display_server.cpp45
-rw-r--r--servers/display_server.h14
-rw-r--r--servers/display_server_headless.h127
-rw-r--r--servers/navigation_server_2d.cpp6
-rw-r--r--servers/navigation_server_3d.h2
-rw-r--r--servers/physics_2d/area_pair_2d_sw.cpp102
-rw-r--r--servers/physics_2d/area_pair_2d_sw.h32
-rw-r--r--servers/physics_2d/body_2d_sw.cpp80
-rw-r--r--servers/physics_2d/body_2d_sw.h5
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp89
-rw-r--r--servers/physics_2d/body_pair_2d_sw.h24
-rw-r--r--servers/physics_2d/broad_phase_2d_basic.cpp174
-rw-r--r--servers/physics_2d/broad_phase_2d_bvh.cpp116
-rw-r--r--servers/physics_2d/broad_phase_2d_bvh.h (renamed from servers/physics_2d/broad_phase_2d_basic.h)58
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.cpp738
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.h194
-rw-r--r--servers/physics_2d/broad_phase_2d_sw.h2
-rw-r--r--servers/physics_2d/collision_object_2d_sw.cpp24
-rw-r--r--servers/physics_2d/collision_object_2d_sw.h4
-rw-r--r--servers/physics_2d/constraint_2d_sw.h1
-rw-r--r--servers/physics_2d/joints_2d_sw.cpp96
-rw-r--r--servers/physics_2d/joints_2d_sw.h31
-rw-r--r--servers/physics_2d/physics_server_2d_sw.cpp14
-rw-r--r--servers/physics_2d/physics_server_2d_sw.h8
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.cpp2
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.h3
-rw-r--r--servers/physics_2d/space_2d_sw.cpp4
-rw-r--r--servers/physics_2d/step_2d_sw.cpp157
-rw-r--r--servers/physics_2d/step_2d_sw.h15
-rw-r--r--servers/physics_3d/area_3d_sw.cpp2
-rw-r--r--servers/physics_3d/area_3d_sw.h2
-rw-r--r--servers/physics_3d/area_pair_3d_sw.cpp102
-rw-r--r--servers/physics_3d/area_pair_3d_sw.h16
-rw-r--r--servers/physics_3d/body_3d_sw.cpp115
-rw-r--r--servers/physics_3d/body_3d_sw.h17
-rw-r--r--servers/physics_3d/body_pair_3d_sw.cpp159
-rw-r--r--servers/physics_3d/body_pair_3d_sw.h40
-rw-r--r--servers/physics_3d/broad_phase_3d_basic.cpp212
-rw-r--r--servers/physics_3d/broad_phase_3d_bvh.cpp (renamed from servers/physics_3d/broad_phase_octree.cpp)74
-rw-r--r--servers/physics_3d/broad_phase_3d_bvh.h (renamed from servers/physics_3d/broad_phase_octree.h)22
-rw-r--r--servers/physics_3d/broad_phase_3d_sw.h2
-rw-r--r--servers/physics_3d/collision_object_3d_sw.cpp32
-rw-r--r--servers/physics_3d/collision_object_3d_sw.h24
-rw-r--r--servers/physics_3d/collision_solver_3d_sat.cpp56
-rw-r--r--servers/physics_3d/collision_solver_3d_sat.h2
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.cpp32
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.h14
-rw-r--r--servers/physics_3d/constraint_3d_sw.h7
-rw-r--r--servers/physics_3d/gjk_epa.cpp24
-rw-r--r--servers/physics_3d/gjk_epa.h4
-rw-r--r--servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp33
-rw-r--r--servers/physics_3d/joints/cone_twist_joint_3d_sw.h12
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp27
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.h37
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.cpp41
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.h12
-rw-r--r--servers/physics_3d/joints/jacobian_entry_3d_sw.h2
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.cpp13
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.h6
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.cpp47
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.h28
-rw-r--r--servers/physics_3d/joints_3d_sw.h9
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp62
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h35
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.cpp2
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.h37
-rw-r--r--servers/physics_3d/shape_3d_sw.cpp26
-rw-r--r--servers/physics_3d/shape_3d_sw.h26
-rw-r--r--servers/physics_3d/soft_body_3d_sw.cpp4
-rw-r--r--servers/physics_3d/soft_body_3d_sw.h9
-rw-r--r--servers/physics_3d/space_3d_sw.cpp67
-rw-r--r--servers/physics_3d/space_3d_sw.h12
-rw-r--r--servers/physics_3d/step_3d_sw.cpp227
-rw-r--r--servers/physics_3d/step_3d_sw.h16
-rw-r--r--servers/physics_server_2d.cpp18
-rw-r--r--servers/physics_server_2d.h50
-rw-r--r--servers/physics_server_3d.cpp25
-rw-r--r--servers/physics_server_3d.h88
-rw-r--r--servers/rendering/rasterizer_dummy.h (renamed from drivers/dummy/rasterizer_dummy.h)144
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp359
-rw-r--r--servers/rendering/renderer_canvas_cull.h26
-rw-r--r--servers/rendering/renderer_canvas_render.h8
-rw-r--r--servers/rendering/renderer_compositor.cpp9
-rw-r--r--servers/rendering/renderer_compositor.h32
-rw-r--r--servers/rendering/renderer_rd/SCsub1
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.cpp14
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.h12
-rw-r--r--servers/rendering/renderer_rd/effects_rd.cpp98
-rw-r--r--servers/rendering/renderer_rd/effects_rd.h33
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp579
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h62
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp67
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h4
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/SCsub5
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp2154
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h608
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp812
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h208
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp417
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h15
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp148
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h38
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp312
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.h127
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp490
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h178
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp71
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.h11
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp1082
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h246
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.cpp164
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp290
-rw-r--r--servers/rendering/renderer_rd/shader_rd.h23
-rw-r--r--servers/rendering/renderer_rd/shaders/blit.glsl95
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl102
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_sdf.glsl60
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl10
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl102
-rw-r--r--servers/rendering/renderer_rd/shaders/decal_data_inc.glsl18
-rw-r--r--servers/rendering/renderer_rd/shaders/gi.glsl76
-rw-r--r--servers/rendering/renderer_rd/shaders/light_data_inc.glsl87
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl321
-rw-r--r--servers/rendering/renderer_rd/shaders/particles_copy.glsl157
-rw-r--r--servers/rendering/renderer_rd/shaders/resolve.glsl22
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl58
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl1467
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl41
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl242
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl1022
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl1510
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl228
-rw-r--r--servers/rendering/renderer_rd/shaders/skeleton.glsl47
-rw-r--r--servers/rendering/renderer_rd/shaders/sky.glsl31
-rw-r--r--servers/rendering/renderer_rd/shaders/tonemap.glsl35
-rw-r--r--servers/rendering/renderer_rd/shaders/volumetric_fog.glsl33
-rw-r--r--servers/rendering/renderer_rd/shaders/voxel_gi.glsl (renamed from servers/rendering/renderer_rd/shaders/giprobe.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl (renamed from servers/rendering/renderer_rd/shaders/giprobe_debug.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl (renamed from servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl)0
-rw-r--r--servers/rendering/renderer_scene.h22
-rw-r--r--servers/rendering/renderer_scene_cull.cpp1185
-rw-r--r--servers/rendering/renderer_scene_cull.h180
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.cpp192
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.h201
-rw-r--r--servers/rendering/renderer_scene_render.cpp150
-rw-r--r--servers/rendering/renderer_scene_render.h52
-rw-r--r--servers/rendering/renderer_storage.h102
-rw-r--r--servers/rendering/renderer_viewport.cpp208
-rw-r--r--servers/rendering/renderer_viewport.h22
-rw-r--r--servers/rendering/rendering_device.cpp12
-rw-r--r--servers/rendering/rendering_device.h14
-rw-r--r--servers/rendering/rendering_device_binds.h48
-rw-r--r--servers/rendering/rendering_server_default.cpp6
-rw-r--r--servers/rendering/rendering_server_default.h102
-rw-r--r--servers/rendering/rendering_server_globals.cpp2
-rw-r--r--servers/rendering/rendering_server_globals.h2
-rw-r--r--servers/rendering/shader_language.cpp1409
-rw-r--r--servers/rendering/shader_language.h114
-rw-r--r--servers/rendering/shader_types.cpp33
-rw-r--r--servers/rendering/shader_warnings.cpp131
-rw-r--r--servers/rendering/shader_warnings.h (renamed from platform/android/audio_driver_jandroid.h)81
-rw-r--r--servers/rendering_server.cpp151
-rw-r--r--servers/rendering_server.h146
-rw-r--r--servers/text_server.cpp2
-rw-r--r--servers/text_server.h2
-rw-r--r--servers/xr/xr_interface.cpp3
-rw-r--r--servers/xr/xr_interface.h22
-rw-r--r--servers/xr/xr_positional_tracker.cpp4
-rw-r--r--servers/xr/xr_positional_tracker.h6
-rw-r--r--servers/xr_server.cpp16
-rw-r--r--servers/xr_server.h14
-rw-r--r--tests/test_aabb.h4
-rw-r--r--tests/test_class_db.h18
-rw-r--r--tests/test_color.h8
-rw-r--r--tests/test_command_queue.h60
-rw-r--r--tests/test_curve.h28
-rw-r--r--tests/test_expression.h24
-rw-r--r--tests/test_file_access.h2
-rw-r--r--tests/test_geometry_2d.h8
-rw-r--r--tests/test_image.h20
-rw-r--r--tests/test_json.h4
-rw-r--r--tests/test_macros.h4
-rw-r--r--tests/test_main.cpp36
-rw-r--r--tests/test_math.cpp16
-rw-r--r--tests/test_object.h35
-rw-r--r--tests/test_pck_packer.h8
-rw-r--r--tests/test_physics_2d.cpp7
-rw-r--r--tests/test_physics_3d.cpp47
-rw-r--r--tests/test_rect2.h16
-rw-r--r--tests/test_render.cpp14
-rw-r--r--tests/test_shader_lang.cpp2
-rw-r--r--tests/test_string.h28
-rw-r--r--tests/test_time.h145
-rw-r--r--tests/test_translation.h150
-rw-r--r--tests/test_validate_testing.h4
-rw-r--r--tests/test_vector.h496
-rw-r--r--thirdparty/README.md45
-rw-r--r--thirdparty/basis_universal/basisu_comp.cpp1206
-rw-r--r--thirdparty/basis_universal/basisu_etc.cpp1074
-rw-r--r--thirdparty/basis_universal/basisu_pvrtc1_4.cpp269
-rw-r--r--thirdparty/basis_universal/encoder/apg_bmp.c541
-rw-r--r--thirdparty/basis_universal/encoder/apg_bmp.h123
-rw-r--r--thirdparty/basis_universal/encoder/basisu_astc_decomp.cpp (renamed from thirdparty/basis_universal/basisu_astc_decomp.cpp)15
-rw-r--r--thirdparty/basis_universal/encoder/basisu_astc_decomp.h (renamed from thirdparty/basis_universal/basisu_astc_decomp.h)2
-rw-r--r--thirdparty/basis_universal/encoder/basisu_backend.cpp (renamed from thirdparty/basis_universal/basisu_backend.cpp)305
-rw-r--r--thirdparty/basis_universal/encoder/basisu_backend.h (renamed from thirdparty/basis_universal/basisu_backend.h)35
-rw-r--r--thirdparty/basis_universal/encoder/basisu_basis_file.cpp (renamed from thirdparty/basis_universal/basisu_basis_file.cpp)105
-rw-r--r--thirdparty/basis_universal/encoder/basisu_basis_file.h (renamed from thirdparty/basis_universal/basisu_basis_file.h)4
-rw-r--r--thirdparty/basis_universal/encoder/basisu_bc7enc.cpp1984
-rw-r--r--thirdparty/basis_universal/encoder/basisu_bc7enc.h131
-rw-r--r--thirdparty/basis_universal/encoder/basisu_comp.cpp2113
-rw-r--r--thirdparty/basis_universal/encoder/basisu_comp.h (renamed from thirdparty/basis_universal/basisu_comp.h)259
-rw-r--r--thirdparty/basis_universal/encoder/basisu_enc.cpp (renamed from thirdparty/basis_universal/basisu_enc.cpp)837
-rw-r--r--thirdparty/basis_universal/encoder/basisu_enc.h (renamed from thirdparty/basis_universal/basisu_enc.h)399
-rw-r--r--thirdparty/basis_universal/encoder/basisu_etc.cpp1593
-rw-r--r--thirdparty/basis_universal/encoder/basisu_etc.h (renamed from thirdparty/basis_universal/basisu_etc.h)158
-rw-r--r--thirdparty/basis_universal/encoder/basisu_frontend.cpp (renamed from thirdparty/basis_universal/basisu_frontend.cpp)897
-rw-r--r--thirdparty/basis_universal/encoder/basisu_frontend.h (renamed from thirdparty/basis_universal/basisu_frontend.h)46
-rw-r--r--thirdparty/basis_universal/encoder/basisu_global_selector_palette_helpers.cpp (renamed from thirdparty/basis_universal/basisu_global_selector_palette_helpers.cpp)0
-rw-r--r--thirdparty/basis_universal/encoder/basisu_global_selector_palette_helpers.h (renamed from thirdparty/basis_universal/basisu_global_selector_palette_helpers.h)6
-rw-r--r--thirdparty/basis_universal/encoder/basisu_gpu_texture.cpp (renamed from thirdparty/basis_universal/basisu_gpu_texture.cpp)625
-rw-r--r--thirdparty/basis_universal/encoder/basisu_gpu_texture.h (renamed from thirdparty/basis_universal/basisu_gpu_texture.h)24
-rw-r--r--thirdparty/basis_universal/encoder/basisu_kernels_declares.h25
-rw-r--r--thirdparty/basis_universal/encoder/basisu_kernels_imp.h584
-rw-r--r--thirdparty/basis_universal/encoder/basisu_kernels_sse.cpp161
-rw-r--r--thirdparty/basis_universal/encoder/basisu_miniz.h2514
-rw-r--r--thirdparty/basis_universal/encoder/basisu_pvrtc1_4.cpp564
-rw-r--r--thirdparty/basis_universal/encoder/basisu_pvrtc1_4.h (renamed from thirdparty/basis_universal/basisu_pvrtc1_4.h)100
-rw-r--r--thirdparty/basis_universal/encoder/basisu_resample_filters.cpp (renamed from thirdparty/basis_universal/basisu_resample_filters.cpp)24
-rw-r--r--thirdparty/basis_universal/encoder/basisu_resampler.cpp (renamed from thirdparty/basis_universal/basisu_resampler.cpp)0
-rw-r--r--thirdparty/basis_universal/encoder/basisu_resampler.h (renamed from thirdparty/basis_universal/basisu_resampler.h)2
-rw-r--r--thirdparty/basis_universal/encoder/basisu_resampler_filters.h (renamed from thirdparty/basis_universal/basisu_resampler_filters.h)2
-rw-r--r--thirdparty/basis_universal/encoder/basisu_ssim.cpp (renamed from thirdparty/basis_universal/basisu_ssim.cpp)0
-rw-r--r--thirdparty/basis_universal/encoder/basisu_ssim.h (renamed from thirdparty/basis_universal/basisu_ssim.h)0
-rw-r--r--thirdparty/basis_universal/encoder/basisu_uastc_enc.cpp4189
-rw-r--r--thirdparty/basis_universal/encoder/basisu_uastc_enc.h140
-rw-r--r--thirdparty/basis_universal/encoder/cppspmd_flow.h590
-rw-r--r--thirdparty/basis_universal/encoder/cppspmd_math.h725
-rw-r--r--thirdparty/basis_universal/encoder/cppspmd_math_declares.h89
-rw-r--r--thirdparty/basis_universal/encoder/cppspmd_sse.h2118
-rw-r--r--thirdparty/basis_universal/encoder/cppspmd_type_aliases.h47
-rw-r--r--thirdparty/basis_universal/encoder/jpgd.cpp3241
-rw-r--r--thirdparty/basis_universal/encoder/jpgd.h347
-rw-r--r--thirdparty/basis_universal/encoder/lodepng.cpp (renamed from thirdparty/basis_universal/lodepng.cpp)2
-rw-r--r--thirdparty/basis_universal/encoder/lodepng.h (renamed from thirdparty/basis_universal/lodepng.h)0
-rw-r--r--thirdparty/basis_universal/transcoder/basisu.h152
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_containers.h1908
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_containers_impl.h311
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_file_headers.h45
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_global_selector_cb.h2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_global_selector_palette.h8
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder.cpp9646
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder.h758
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_internal.h84
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_astc.inc2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_astc_0_255.inc2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_atc_55.inc2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_atc_56.inc2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m5_alpha.inc2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m5_color.inc2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m6.inc4383
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_dxt1_5.inc2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_dxt1_6.inc2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_pvrtc2_45.inc2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_tables_pvrtc2_alpha_33.inc2
-rw-r--r--thirdparty/basis_universal/transcoder/basisu_transcoder_uastc.h297
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp1
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp1
-rw-r--r--thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp1
-rw-r--r--thirdparty/embree/common/algorithms/parallel_any_of.h55
-rw-r--r--thirdparty/embree/common/algorithms/parallel_filter.h93
-rw-r--r--thirdparty/embree/common/algorithms/parallel_for.h186
-rw-r--r--thirdparty/embree/common/algorithms/parallel_for_for.h149
-rw-r--r--thirdparty/embree/common/algorithms/parallel_for_for_prefix_sum.h112
-rw-r--r--thirdparty/embree/common/algorithms/parallel_map.h85
-rw-r--r--thirdparty/embree/common/algorithms/parallel_partition.h283
-rw-r--r--thirdparty/embree/common/algorithms/parallel_prefix_sum.h85
-rw-r--r--thirdparty/embree/common/algorithms/parallel_reduce.h150
-rw-r--r--thirdparty/embree/common/algorithms/parallel_set.h52
-rw-r--r--thirdparty/embree/common/algorithms/parallel_sort.h454
-rw-r--r--thirdparty/embree/common/lexers/parsestream.h101
-rw-r--r--thirdparty/embree/common/lexers/stream.h215
-rw-r--r--thirdparty/embree/common/lexers/streamfilters.h39
-rw-r--r--thirdparty/embree/common/lexers/stringstream.cpp51
-rw-r--r--thirdparty/embree/common/lexers/stringstream.h29
-rw-r--r--thirdparty/embree/common/lexers/tokenstream.cpp181
-rw-r--r--thirdparty/embree/common/lexers/tokenstream.h164
-rw-r--r--thirdparty/embree/common/math/affinespace.h361
-rw-r--r--thirdparty/embree/common/math/bbox.h331
-rw-r--r--thirdparty/embree/common/math/col3.h47
-rw-r--r--thirdparty/embree/common/math/col4.h47
-rw-r--r--thirdparty/embree/common/math/color.h241
-rw-r--r--thirdparty/embree/common/math/constants.cpp27
-rw-r--r--thirdparty/embree/common/math/constants.h197
-rw-r--r--thirdparty/embree/common/math/interval.h161
-rw-r--r--thirdparty/embree/common/math/lbbox.h289
-rw-r--r--thirdparty/embree/common/math/linearspace2.h148
-rw-r--r--thirdparty/embree/common/math/linearspace3.h213
-rw-r--r--thirdparty/embree/common/math/math.h369
-rw-r--r--thirdparty/embree/common/math/obbox.h39
-rw-r--r--thirdparty/embree/common/math/quaternion.h254
-rw-r--r--thirdparty/embree/common/math/range.h137
-rw-r--r--thirdparty/embree/common/math/transcendental.h525
-rw-r--r--thirdparty/embree/common/math/vec2.h235
-rw-r--r--thirdparty/embree/common/math/vec2fa.h301
-rw-r--r--thirdparty/embree/common/math/vec3.h337
-rw-r--r--thirdparty/embree/common/math/vec3ba.h120
-rw-r--r--thirdparty/embree/common/math/vec3fa.h727
-rw-r--r--thirdparty/embree/common/math/vec3ia.h186
-rw-r--r--thirdparty/embree/common/math/vec4.h243
-rw-r--r--thirdparty/embree/common/simd/arm/emulation.h50
-rw-r--r--thirdparty/embree/common/simd/arm/sse2neon.h6996
-rw-r--r--thirdparty/embree/common/simd/avx.h34
-rw-r--r--thirdparty/embree/common/simd/avx512.h41
-rw-r--r--thirdparty/embree/common/simd/simd.h110
-rw-r--r--thirdparty/embree/common/simd/sse.cpp34
-rw-r--r--thirdparty/embree/common/simd/sse.h35
-rw-r--r--thirdparty/embree/common/simd/varying.h145
-rw-r--r--thirdparty/embree/common/simd/vboold4_avx.h169
-rw-r--r--thirdparty/embree/common/simd/vboold4_avx512.h156
-rw-r--r--thirdparty/embree/common/simd/vboold8_avx512.h151
-rw-r--r--thirdparty/embree/common/simd/vboolf16_avx512.h153
-rw-r--r--thirdparty/embree/common/simd/vboolf4_avx512.h159
-rw-r--r--thirdparty/embree/common/simd/vboolf4_sse2.h189
-rw-r--r--thirdparty/embree/common/simd/vboolf8_avx.h202
-rw-r--r--thirdparty/embree/common/simd/vboolf8_avx512.h159
-rw-r--r--thirdparty/embree/common/simd/vdouble4_avx.h321
-rw-r--r--thirdparty/embree/common/simd/vdouble8_avx512.h351
-rw-r--r--thirdparty/embree/common/simd/vfloat16_avx512.h615
-rw-r--r--thirdparty/embree/common/simd/vfloat4_sse2.h722
-rw-r--r--thirdparty/embree/common/simd/vfloat8_avx.h758
-rw-r--r--thirdparty/embree/common/simd/vint16_avx512.h472
-rw-r--r--thirdparty/embree/common/simd/vint4_sse2.h598
-rw-r--r--thirdparty/embree/common/simd/vint8_avx.h470
-rw-r--r--thirdparty/embree/common/simd/vint8_avx2.h518
-rw-r--r--thirdparty/embree/common/simd/vllong4_avx2.h352
-rw-r--r--thirdparty/embree/common/simd/vllong8_avx512.h358
-rw-r--r--thirdparty/embree/common/simd/vuint16_avx512.h424
-rw-r--r--thirdparty/embree/common/simd/vuint4_sse2.h426
-rw-r--r--thirdparty/embree/common/simd/vuint8_avx.h386
-rw-r--r--thirdparty/embree/common/simd/vuint8_avx2.h446
-rw-r--r--thirdparty/embree/common/sys/alloc.cpp327
-rw-r--r--thirdparty/embree/common/sys/alloc.h164
-rw-r--r--thirdparty/embree/common/sys/array.h222
-rw-r--r--thirdparty/embree/common/sys/atomic.h59
-rw-r--r--thirdparty/embree/common/sys/barrier.cpp289
-rw-r--r--thirdparty/embree/common/sys/barrier.h112
-rw-r--r--thirdparty/embree/common/sys/condition.cpp85
-rw-r--r--thirdparty/embree/common/sys/condition.h31
-rw-r--r--thirdparty/embree/common/sys/filename.cpp138
-rw-r--r--thirdparty/embree/common/sys/filename.h81
-rw-r--r--thirdparty/embree/common/sys/intrinsics.h525
-rw-r--r--thirdparty/embree/common/sys/library.cpp83
-rw-r--r--thirdparty/embree/common/sys/library.h21
-rw-r--r--thirdparty/embree/common/sys/mutex.cpp57
-rw-r--r--thirdparty/embree/common/sys/mutex.h98
-rw-r--r--thirdparty/embree/common/sys/platform.h392
-rw-r--r--thirdparty/embree/common/sys/ref.h122
-rw-r--r--thirdparty/embree/common/sys/regression.cpp30
-rw-r--r--thirdparty/embree/common/sys/regression.h25
-rw-r--r--thirdparty/embree/common/sys/string.cpp42
-rw-r--r--thirdparty/embree/common/sys/string.h37
-rw-r--r--thirdparty/embree/common/sys/sysinfo.cpp656
-rw-r--r--thirdparty/embree/common/sys/sysinfo.h178
-rw-r--r--thirdparty/embree/common/sys/thread.cpp474
-rw-r--r--thirdparty/embree/common/sys/thread.h49
-rw-r--r--thirdparty/embree/common/sys/vector.h242
-rw-r--r--thirdparty/embree/common/tasking/taskscheduler.h15
-rw-r--r--thirdparty/embree/common/tasking/taskschedulerinternal.cpp420
-rw-r--r--thirdparty/embree/common/tasking/taskschedulerinternal.h385
-rw-r--r--thirdparty/embree/common/tasking/taskschedulerppl.h46
-rw-r--r--thirdparty/embree/common/tasking/taskschedulertbb.h73
-rw-r--r--thirdparty/embree/include/embree3/rtcore.h14
-rw-r--r--thirdparty/embree/include/embree3/rtcore_buffer.h51
-rw-r--r--thirdparty/embree/include/embree3/rtcore_builder.h125
-rw-r--r--thirdparty/embree/include/embree3/rtcore_common.h328
-rw-r--r--thirdparty/embree/include/embree3/rtcore_config.h57
-rw-r--r--thirdparty/embree/include/embree3/rtcore_device.h87
-rw-r--r--thirdparty/embree/include/embree3/rtcore_geometry.h383
-rw-r--r--thirdparty/embree/include/embree3/rtcore_quaternion.h101
-rw-r--r--thirdparty/embree/include/embree3/rtcore_ray.h378
-rw-r--r--thirdparty/embree/include/embree3/rtcore_scene.h160
-rw-r--r--thirdparty/embree/kernels/builders/bvh_builder_hair.h411
-rw-r--r--thirdparty/embree/kernels/builders/bvh_builder_morton.h501
-rw-r--r--thirdparty/embree/kernels/builders/bvh_builder_msmblur.h692
-rw-r--r--thirdparty/embree/kernels/builders/bvh_builder_msmblur_hair.h526
-rw-r--r--thirdparty/embree/kernels/builders/bvh_builder_sah.h669
-rw-r--r--thirdparty/embree/kernels/builders/heuristic_binning.h496
-rw-r--r--thirdparty/embree/kernels/builders/heuristic_binning_array_aligned.h200
-rw-r--r--thirdparty/embree/kernels/builders/heuristic_binning_array_unaligned.h302
-rw-r--r--thirdparty/embree/kernels/builders/heuristic_openmerge_array.h443
-rw-r--r--thirdparty/embree/kernels/builders/heuristic_spatial.h414
-rw-r--r--thirdparty/embree/kernels/builders/heuristic_spatial_array.h546
-rw-r--r--thirdparty/embree/kernels/builders/heuristic_strand_array.h188
-rw-r--r--thirdparty/embree/kernels/builders/heuristic_timesplit_array.h237
-rw-r--r--thirdparty/embree/kernels/builders/priminfo.h362
-rw-r--r--thirdparty/embree/kernels/builders/primrefgen.cpp312
-rw-r--r--thirdparty/embree/kernels/builders/primrefgen.h34
-rw-r--r--thirdparty/embree/kernels/builders/primrefgen_presplit.h371
-rw-r--r--thirdparty/embree/kernels/builders/splitter.h191
-rw-r--r--thirdparty/embree/kernels/bvh/bvh.cpp190
-rw-r--r--thirdparty/embree/kernels/bvh/bvh.h235
-rw-r--r--thirdparty/embree/kernels/bvh/bvh4_factory.cpp1325
-rw-r--r--thirdparty/embree/kernels/bvh/bvh4_factory.h316
-rw-r--r--thirdparty/embree/kernels/bvh/bvh8_factory.cpp1165
-rw-r--r--thirdparty/embree/kernels/bvh/bvh8_factory.h280
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_builder.cpp60
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_builder.h115
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_builder_morton.cpp531
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_builder_sah.cpp543
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_builder_sah_mb.cpp705
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_builder_sah_spatial.cpp201
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_builder_twolevel.cpp369
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h263
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_builder_twolevel_internal.h267
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_collider.cpp375
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_collider.h72
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_factory.h21
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_intersector1.cpp321
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_intersector1.h34
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_intersector1_bvh4.cpp61
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.h58
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_intersector_stream.h270
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_intersector_stream_filters.h41
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_node_aabb.h213
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_node_aabb_mb.h247
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_node_aabb_mb4d.h107
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_node_base.h43
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_node_obb.h98
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_node_obb_mb.h90
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_node_qaabb.h265
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_node_ref.h242
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_refit.cpp247
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_refit.h95
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_rotate.cpp127
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_rotate.h37
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_statistics.cpp168
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_statistics.h285
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_traverser1.h466
-rw-r--r--thirdparty/embree/kernels/bvh/bvh_traverser_stream.h149
-rw-r--r--thirdparty/embree/kernels/bvh/node_intersector.h31
-rw-r--r--thirdparty/embree/kernels/bvh/node_intersector1.h1403
-rw-r--r--thirdparty/embree/kernels/bvh/node_intersector_frustum.h241
-rw-r--r--thirdparty/embree/kernels/bvh/node_intersector_packet.h805
-rw-r--r--thirdparty/embree/kernels/bvh/node_intersector_packet_stream.h189
-rw-r--r--thirdparty/embree/kernels/common/accel.h556
-rw-r--r--thirdparty/embree/kernels/common/accelinstance.h41
-rw-r--r--thirdparty/embree/kernels/common/acceln.cpp232
-rw-r--r--thirdparty/embree/kernels/common/acceln.h49
-rw-r--r--thirdparty/embree/kernels/common/accelset.cpp17
-rw-r--r--thirdparty/embree/kernels/common/accelset.h248
-rw-r--r--thirdparty/embree/kernels/common/alloc.cpp79
-rw-r--r--thirdparty/embree/kernels/common/alloc.h958
-rw-r--r--thirdparty/embree/kernels/common/buffer.h263
-rw-r--r--thirdparty/embree/kernels/common/builder.h60
-rw-r--r--thirdparty/embree/kernels/common/context.h131
-rw-r--r--thirdparty/embree/kernels/common/default.h268
-rw-r--r--thirdparty/embree/kernels/common/device.cpp556
-rw-r--r--thirdparty/embree/kernels/common/device.h85
-rw-r--r--thirdparty/embree/kernels/common/geometry.cpp259
-rw-r--r--thirdparty/embree/kernels/common/geometry.h582
-rw-r--r--thirdparty/embree/kernels/common/hit.h114
-rw-r--r--thirdparty/embree/kernels/common/instance_stack.h179
-rw-r--r--thirdparty/embree/kernels/common/isa.h246
-rw-r--r--thirdparty/embree/kernels/common/motion_derivative.h325
-rw-r--r--thirdparty/embree/kernels/common/point_query.h136
-rw-r--r--thirdparty/embree/kernels/common/primref.h138
-rw-r--r--thirdparty/embree/kernels/common/primref_mb.h262
-rw-r--r--thirdparty/embree/kernels/common/profile.h159
-rw-r--r--thirdparty/embree/kernels/common/ray.h1517
-rw-r--r--thirdparty/embree/kernels/common/rtcore.cpp1766
-rw-r--r--thirdparty/embree/kernels/common/rtcore.h142
-rw-r--r--thirdparty/embree/kernels/common/rtcore_builder.cpp442
-rw-r--r--thirdparty/embree/kernels/common/scene.cpp955
-rw-r--r--thirdparty/embree/kernels/common/scene.h390
-rw-r--r--thirdparty/embree/kernels/common/scene_curves.h688
-rw-r--r--thirdparty/embree/kernels/common/scene_grid_mesh.h294
-rw-r--r--thirdparty/embree/kernels/common/scene_instance.h272
-rw-r--r--thirdparty/embree/kernels/common/scene_line_segments.h345
-rw-r--r--thirdparty/embree/kernels/common/scene_points.h282
-rw-r--r--thirdparty/embree/kernels/common/scene_quad_mesh.h337
-rw-r--r--thirdparty/embree/kernels/common/scene_subdiv_mesh.h326
-rw-r--r--thirdparty/embree/kernels/common/scene_triangle_mesh.cpp194
-rw-r--r--thirdparty/embree/kernels/common/scene_triangle_mesh.h318
-rw-r--r--thirdparty/embree/kernels/common/scene_user_geometry.h77
-rw-r--r--thirdparty/embree/kernels/common/stack_item.h125
-rw-r--r--thirdparty/embree/kernels/common/stat.cpp128
-rw-r--r--thirdparty/embree/kernels/common/stat.h116
-rw-r--r--thirdparty/embree/kernels/common/state.cpp519
-rw-r--r--thirdparty/embree/kernels/common/state.h196
-rw-r--r--thirdparty/embree/kernels/common/vector.h76
-rw-r--r--thirdparty/embree/kernels/config.h76
-rw-r--r--thirdparty/embree/kernels/geometry/cone.h321
-rw-r--r--thirdparty/embree/kernels/geometry/coneline_intersector.h209
-rw-r--r--thirdparty/embree/kernels/geometry/conelinei_intersector.h141
-rw-r--r--thirdparty/embree/kernels/geometry/curveNi.h222
-rw-r--r--thirdparty/embree/kernels/geometry/curveNi_intersector.h569
-rw-r--r--thirdparty/embree/kernels/geometry/curveNi_mb.h278
-rw-r--r--thirdparty/embree/kernels/geometry/curveNi_mb_intersector.h516
-rw-r--r--thirdparty/embree/kernels/geometry/curveNv.h101
-rw-r--r--thirdparty/embree/kernels/geometry/curveNv_intersector.h181
-rw-r--r--thirdparty/embree/kernels/geometry/curve_intersector.h98
-rw-r--r--thirdparty/embree/kernels/geometry/curve_intersector_distance.h129
-rw-r--r--thirdparty/embree/kernels/geometry/curve_intersector_oriented.h417
-rw-r--r--thirdparty/embree/kernels/geometry/curve_intersector_precalculations.h49
-rw-r--r--thirdparty/embree/kernels/geometry/curve_intersector_ribbon.h216
-rw-r--r--thirdparty/embree/kernels/geometry/curve_intersector_sweep.h364
-rw-r--r--thirdparty/embree/kernels/geometry/curve_intersector_virtual.h671
-rw-r--r--thirdparty/embree/kernels/geometry/cylinder.h223
-rw-r--r--thirdparty/embree/kernels/geometry/disc_intersector.h216
-rw-r--r--thirdparty/embree/kernels/geometry/disci_intersector.h277
-rw-r--r--thirdparty/embree/kernels/geometry/filter.h204
-rw-r--r--thirdparty/embree/kernels/geometry/grid_intersector.h99
-rw-r--r--thirdparty/embree/kernels/geometry/grid_soa.h275
-rw-r--r--thirdparty/embree/kernels/geometry/grid_soa_intersector1.h207
-rw-r--r--thirdparty/embree/kernels/geometry/grid_soa_intersector_packet.h445
-rw-r--r--thirdparty/embree/kernels/geometry/instance.h78
-rw-r--r--thirdparty/embree/kernels/geometry/instance_intersector.h84
-rw-r--r--thirdparty/embree/kernels/geometry/intersector_epilog.h979
-rw-r--r--thirdparty/embree/kernels/geometry/intersector_iterators.h172
-rw-r--r--thirdparty/embree/kernels/geometry/line_intersector.h145
-rw-r--r--thirdparty/embree/kernels/geometry/linei.h705
-rw-r--r--thirdparty/embree/kernels/geometry/linei_intersector.h124
-rw-r--r--thirdparty/embree/kernels/geometry/object.h84
-rw-r--r--thirdparty/embree/kernels/geometry/object_intersector.h127
-rw-r--r--thirdparty/embree/kernels/geometry/plane.h57
-rw-r--r--thirdparty/embree/kernels/geometry/pointi.h412
-rw-r--r--thirdparty/embree/kernels/geometry/primitive.h49
-rw-r--r--thirdparty/embree/kernels/geometry/primitive4.cpp379
-rw-r--r--thirdparty/embree/kernels/geometry/quad_intersector.h76
-rw-r--r--thirdparty/embree/kernels/geometry/quad_intersector_moeller.h460
-rw-r--r--thirdparty/embree/kernels/geometry/quad_intersector_pluecker.h438
-rw-r--r--thirdparty/embree/kernels/geometry/quadi.h483
-rw-r--r--thirdparty/embree/kernels/geometry/quadi_intersector.h350
-rw-r--r--thirdparty/embree/kernels/geometry/quadv.h165
-rw-r--r--thirdparty/embree/kernels/geometry/quadv_intersector.h181
-rw-r--r--thirdparty/embree/kernels/geometry/roundline_intersector.h715
-rw-r--r--thirdparty/embree/kernels/geometry/roundlinei_intersector.h123
-rw-r--r--thirdparty/embree/kernels/geometry/sphere_intersector.h183
-rw-r--r--thirdparty/embree/kernels/geometry/spherei_intersector.h156
-rw-r--r--thirdparty/embree/kernels/geometry/subdivpatch1.h38
-rw-r--r--thirdparty/embree/kernels/geometry/subdivpatch1_intersector.h237
-rw-r--r--thirdparty/embree/kernels/geometry/subgrid.h517
-rw-r--r--thirdparty/embree/kernels/geometry/subgrid_intersector.h517
-rw-r--r--thirdparty/embree/kernels/geometry/subgrid_intersector_moeller.h382
-rw-r--r--thirdparty/embree/kernels/geometry/subgrid_intersector_pluecker.h367
-rw-r--r--thirdparty/embree/kernels/geometry/subgrid_mb_intersector.h236
-rw-r--r--thirdparty/embree/kernels/geometry/triangle.h162
-rw-r--r--thirdparty/embree/kernels/geometry/triangle_intersector.h96
-rw-r--r--thirdparty/embree/kernels/geometry/triangle_intersector_moeller.h525
-rw-r--r--thirdparty/embree/kernels/geometry/triangle_intersector_pluecker.h407
-rw-r--r--thirdparty/embree/kernels/geometry/triangle_intersector_woop.h418
-rw-r--r--thirdparty/embree/kernels/geometry/triangle_triangle_intersector.h132
-rw-r--r--thirdparty/embree/kernels/geometry/trianglei.h442
-rw-r--r--thirdparty/embree/kernels/geometry/trianglei_intersector.h336
-rw-r--r--thirdparty/embree/kernels/geometry/trianglev.h157
-rw-r--r--thirdparty/embree/kernels/geometry/trianglev_intersector.h206
-rw-r--r--thirdparty/embree/kernels/geometry/trianglev_mb.h201
-rw-r--r--thirdparty/embree/kernels/geometry/trianglev_mb_intersector.h211
-rw-r--r--thirdparty/embree/kernels/hash.h5
-rw-r--r--thirdparty/embree/kernels/subdiv/bezier_curve.h671
-rw-r--r--thirdparty/embree/kernels/subdiv/bezier_patch.h372
-rw-r--r--thirdparty/embree/kernels/subdiv/bilinear_patch.h191
-rw-r--r--thirdparty/embree/kernels/subdiv/bspline_curve.h320
-rw-r--r--thirdparty/embree/kernels/subdiv/bspline_patch.h449
-rw-r--r--thirdparty/embree/kernels/subdiv/catmullclark_coefficients.h85
-rw-r--r--thirdparty/embree/kernels/subdiv/catmullclark_patch.h562
-rw-r--r--thirdparty/embree/kernels/subdiv/catmullclark_ring.h826
-rw-r--r--thirdparty/embree/kernels/subdiv/catmullrom_curve.h297
-rw-r--r--thirdparty/embree/kernels/subdiv/feature_adaptive_eval.h226
-rw-r--r--thirdparty/embree/kernels/subdiv/feature_adaptive_eval_grid.h359
-rw-r--r--thirdparty/embree/kernels/subdiv/feature_adaptive_eval_simd.h186
-rw-r--r--thirdparty/embree/kernels/subdiv/gregory_patch.h893
-rw-r--r--thirdparty/embree/kernels/subdiv/gregory_patch_dense.h113
-rw-r--r--thirdparty/embree/kernels/subdiv/gridrange.h96
-rw-r--r--thirdparty/embree/kernels/subdiv/half_edge.h371
-rw-r--r--thirdparty/embree/kernels/subdiv/hermite_curve.h39
-rw-r--r--thirdparty/embree/kernels/subdiv/linear_bezier_patch.h403
-rw-r--r--thirdparty/embree/kernels/subdiv/patch.h371
-rw-r--r--thirdparty/embree/kernels/subdiv/patch_eval.h129
-rw-r--r--thirdparty/embree/kernels/subdiv/patch_eval_grid.h245
-rw-r--r--thirdparty/embree/kernels/subdiv/patch_eval_simd.h127
-rw-r--r--thirdparty/embree/kernels/subdiv/subdivpatch1base.h156
-rw-r--r--thirdparty/embree/kernels/subdiv/tessellation.h161
-rw-r--r--thirdparty/embree/kernels/subdiv/tessellation_cache.h325
-rw-r--r--thirdparty/embree/patches/godot-changes-android.patch103
-rw-r--r--thirdparty/embree/patches/godot-changes-misc.patch105
-rw-r--r--thirdparty/embree/patches/godot-changes-noexcept.patch630
-rw-r--r--thirdparty/embree/patches/godot-changes-ubsan.patch24
-rw-r--r--thirdparty/enet/godot.cpp110
-rw-r--r--thirdparty/fonts/OpenSans_SemiBold.ttfbin0 -> 100820 bytes
-rw-r--r--thirdparty/icu4c/APIChangeReport.md396
-rw-r--r--thirdparty/icu4c/common/bytestriebuilder.cpp26
-rw-r--r--thirdparty/icu4c/common/charstr.cpp34
-rw-r--r--thirdparty/icu4c/common/charstr.h3
-rw-r--r--thirdparty/icu4c/common/cmemory.h55
-rw-r--r--thirdparty/icu4c/common/dictbe.cpp32
-rw-r--r--thirdparty/icu4c/common/edits.cpp1
-rw-r--r--thirdparty/icu4c/common/filteredbrk.cpp93
-rw-r--r--thirdparty/icu4c/common/hash.h19
-rw-r--r--thirdparty/icu4c/common/localematcher.cpp12
-rw-r--r--thirdparty/icu4c/common/localeprioritylist.cpp11
-rw-r--r--thirdparty/icu4c/common/locdispnames.cpp2
-rw-r--r--thirdparty/icu4c/common/locid.cpp244
-rw-r--r--thirdparty/icu4c/common/loclikelysubtags.cpp3
-rw-r--r--thirdparty/icu4c/common/norm2allmodes.h82
-rw-r--r--thirdparty/icu4c/common/normalizer2impl.cpp152
-rw-r--r--thirdparty/icu4c/common/normalizer2impl.h11
-rw-r--r--thirdparty/icu4c/common/pluralmap.h2
-rw-r--r--thirdparty/icu4c/common/putil.cpp4
-rw-r--r--thirdparty/icu4c/common/putilimp.h2
-rw-r--r--thirdparty/icu4c/common/rbbi.cpp2
-rw-r--r--thirdparty/icu4c/common/rbbi_cache.cpp2
-rw-r--r--thirdparty/icu4c/common/rbbiscan.cpp6
-rw-r--r--thirdparty/icu4c/common/rbbitblb.cpp2
-rw-r--r--thirdparty/icu4c/common/resource.h6
-rw-r--r--thirdparty/icu4c/common/restrace.cpp3
-rw-r--r--thirdparty/icu4c/common/servnotf.h4
-rw-r--r--thirdparty/icu4c/common/ubrk.cpp12
-rw-r--r--thirdparty/icu4c/common/ucase.cpp2
-rw-r--r--thirdparty/icu4c/common/uchar.cpp38
-rw-r--r--thirdparty/icu4c/common/ucnv2022.cpp6
-rw-r--r--thirdparty/icu4c/common/ucnv_bld.cpp2
-rw-r--r--thirdparty/icu4c/common/ucnv_err.cpp2
-rw-r--r--thirdparty/icu4c/common/ucnv_lmb.cpp4
-rw-r--r--thirdparty/icu4c/common/ucnv_u7.cpp2
-rw-r--r--thirdparty/icu4c/common/ucnvisci.cpp6
-rw-r--r--thirdparty/icu4c/common/ucurr.cpp4
-rw-r--r--thirdparty/icu4c/common/uhash.cpp81
-rw-r--r--thirdparty/icu4c/common/uhash.h95
-rw-r--r--thirdparty/icu4c/common/uloc.cpp42
-rw-r--r--thirdparty/icu4c/common/uloc_keytype.cpp2
-rw-r--r--thirdparty/icu4c/common/uloc_tag.cpp41
-rw-r--r--thirdparty/icu4c/common/ulocimp.h3
-rw-r--r--thirdparty/icu4c/common/unicode/bytestream.h6
-rw-r--r--thirdparty/icu4c/common/unicode/bytestrie.h3
-rw-r--r--thirdparty/icu4c/common/unicode/bytestriebuilder.h5
-rw-r--r--thirdparty/icu4c/common/unicode/docmain.h8
-rw-r--r--thirdparty/icu4c/common/unicode/icuplug.h7
-rw-r--r--thirdparty/icu4c/common/unicode/localematcher.h16
-rw-r--r--thirdparty/icu4c/common/unicode/locid.h4
-rw-r--r--thirdparty/icu4c/common/unicode/normalizer2.h28
-rw-r--r--thirdparty/icu4c/common/unicode/platform.h2
-rw-r--r--thirdparty/icu4c/common/unicode/stringpiece.h26
-rw-r--r--thirdparty/icu4c/common/unicode/ubrk.h21
-rw-r--r--thirdparty/icu4c/common/unicode/ucnv.h4
-rw-r--r--thirdparty/icu4c/common/unicode/ucnvsel.h4
-rw-r--r--thirdparty/icu4c/common/unicode/unifilt.h4
-rw-r--r--thirdparty/icu4c/common/unicode/uniset.h66
-rw-r--r--thirdparty/icu4c/common/unicode/unistr.h8
-rw-r--r--thirdparty/icu4c/common/unicode/urename.h16
-rw-r--r--thirdparty/icu4c/common/unicode/uset.h95
-rw-r--r--thirdparty/icu4c/common/unicode/ushape.h2
-rw-r--r--thirdparty/icu4c/common/unicode/utrace.h17
-rw-r--r--thirdparty/icu4c/common/unicode/uvernum.h12
-rw-r--r--thirdparty/icu4c/common/uniset.cpp128
-rw-r--r--thirdparty/icu4c/common/uniset_props.cpp116
-rw-r--r--thirdparty/icu4c/common/unisetspan.cpp25
-rw-r--r--thirdparty/icu4c/common/uprops.h52
-rw-r--r--thirdparty/icu4c/common/uresbund.cpp23
-rw-r--r--thirdparty/icu4c/common/uresdata.cpp8
-rw-r--r--thirdparty/icu4c/common/uresimp.h4
-rw-r--r--thirdparty/icu4c/common/uset.cpp35
-rw-r--r--thirdparty/icu4c/common/usprep.cpp2
-rw-r--r--thirdparty/icu4c/common/ustr_wcs.cpp4
-rw-r--r--thirdparty/icu4c/common/utext.cpp6
-rw-r--r--thirdparty/icu4c/common/util.h6
-rw-r--r--thirdparty/icu4c/common/utracimp.h2
-rw-r--r--thirdparty/icu4c/common/uvector.cpp4
-rw-r--r--thirdparty/icu4c/common/wintz.cpp24
-rw-r--r--thirdparty/icu4c/icudt69l.dat (renamed from thirdparty/icu4c/icudt68l.dat)bin3846720 -> 3851952 bytes
-rw-r--r--thirdparty/meshoptimizer/meshoptimizer.h5
-rw-r--r--thirdparty/meshoptimizer/patches/attribute-aware-simplify.patch262
-rw-r--r--thirdparty/meshoptimizer/simplifier.cpp168
-rw-r--r--thirdparty/misc/patches/polypartition-godot-types.patch14
-rw-r--r--thirdparty/misc/polypartition.cpp10
-rw-r--r--thirdparty/misc/smolv.cpp2108
-rw-r--r--thirdparty/misc/smolv.h169
-rw-r--r--thirdparty/oidn/core/transfer_function.cpp107
-rw-r--r--thirdparty/oidn/patches/godot-changes-c58c5216.patch68
2544 files changed, 250926 insertions, 94832 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index bc56cba21b..0000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-name: Bug report
-about: Report a bug in Godot
-title: ''
-labels: ''
-assignees: ''
-
----
-<!-- Please search existing issues for potential duplicates before filing yours:
-https://github.com/godotengine/godot/issues?q=is%3Aissue
--->
-
-**Godot version:**
-<!-- Specify commit hash if using non-official build. -->
-
-
-**OS/device including version:**
-<!-- Specify GPU model, drivers, and the backend (GLES2, GLES3, Vulkan) if graphics-related. -->
-
-
-**Issue description:**
-<!-- What happened, and what was expected. -->
-
-
-**Steps to reproduce:**
-
-
-**Minimal reproduction project:**
-<!-- A small Godot project which reproduces the issue. Drag and drop a zip archive to upload it. -->
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000000..43ba5ef357
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,56 @@
+name: Bug report
+description: Report a bug in Godot
+body:
+
+- type: markdown
+ attributes:
+ value: |
+ - Read our [CONTRIBUTING.md guide](CONTRIBUTING.md#reporting-bugs) on reporting bugs.
+ - Write a descriptive issue title above.
+ - Search [open](https://github.com/godotengine/godot/issues) and [closed](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported.
+ - Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/stable/about/release_policy.html).
+
+- type: input
+ attributes:
+ label: Godot version
+ description: >
+ Specify the Git commit hash if using a development or non-official build.
+ If you use a custom build, please test if your issue is reproducible in official builds too.
+ placeholder: 3.3.stable, 4.0.dev (3041becc6)
+ validations:
+ required: true
+
+- type: input
+ attributes:
+ label: System information
+ description: |
+ Specify the OS version, and when relevant hardware information.
+ For graphics-related issues, specify the GPU model, driver version, and the rendering backend (GLES2, GLES3, Vulkan).
+ placeholder: Windows 10, GLES3, Intel HD Graphics 620 (27.20.100.9616)
+ validations:
+ required: true
+
+- type: textarea
+ attributes:
+ label: Issue description
+ description: |
+ Describe your issue briefly. What doesn't work, and how do you expect it to work instead?
+ You can include images or videos with drag and drop, and format code blocks or logs with <code>```</code> tags.
+ validations:
+ required: true
+
+- type: textarea
+ attributes:
+ label: Steps to reproduce
+ description: |
+ List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them.
+ If you include a minimal reproduction project below, you can detail how to use it here.
+ validations:
+ required: true
+
+- type: textarea
+ attributes:
+ label: Minimal reproduction project
+ description: |
+ A small Godot project which reproduces the issue. Highly recommended to speed up troubleshooting.
+ Drag and drop a ZIP archive to upload it.
diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml
index b24a36beef..63930aa9e2 100644
--- a/.github/workflows/android_builds.yml
+++ b/.github/workflows/android_builds.yml
@@ -6,7 +6,6 @@ env:
GODOT_BASE_BRANCH: master
SCONSFLAGS: platform=android verbose=yes warnings=extra werror=yes debug_symbols=no --jobs=2 module_text_server_fb_enabled=yes
SCONS_CACHE_LIMIT: 4096
- ANDROID_NDK_VERSION: 21.1.6352462
jobs:
android-template:
@@ -29,10 +28,6 @@ jobs:
with:
java-version: 8
- - name: Install Android NDK r21
- run: |
- sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install 'ndk;${{env.ANDROID_NDK_VERSION}}'
-
# Upload cache on completion and check it out now
- name: Load .scons_cache directory
id: android-template-cache
@@ -64,7 +59,6 @@ jobs:
- name: Compilation
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
- ANDROID_NDK_ROOT: /usr/local/lib/android/sdk/ndk/${{env.ANDROID_NDK_VERSION}}/
run: |
scons target=release tools=no android_arch=armv7
scons target=release tools=no android_arch=arm64v8
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index 7b144e6e43..b4bbaaacb1 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -70,6 +70,23 @@ jobs:
run: |
./bin/godot.linuxbsd.opt.tools.64 --test
+ # Download, unzip and setup SwiftShader library [d4550ab8d3f]
+ - name: Download SwiftShader
+ run: |
+ wget https://github.com/qarmin/gtk_library_store/releases/download/3.24.0/swiftshader.zip
+ unzip swiftshader.zip
+ rm swiftshader.zip
+ curr="$(pwd)/libvk_swiftshader.so"
+ sed -i "s|PATH_TO_CHANGE|$curr|" vk_swiftshader_icd.json
+
+ # Check class reference
+ - name: Check for class reference updates
+ run: |
+ echo "Running --doctool to see if this changes the public API without updating the documentation."
+ echo -e "If a diff is shown, it means that your code/doc changes are incomplete and you should update the class reference with --doctool.\n\n"
+ VK_ICD_FILENAMES=$(pwd)/vk_swiftshader_icd.json DRI_PRIME=0 xvfb-run bin/godot.linuxbsd.opt.tools.64 --doctool . 2>&1 > /dev/null || true
+ git diff --color --exit-code
+
- uses: actions/upload-artifact@v2
with:
name: ${{ github.job }}
@@ -127,7 +144,7 @@ jobs:
scons --version
# We should always be explicit with our flags usage here since it's gonna be sure to always set those flags
- # [Workaround] SwiftShader doesn't support tesselation, so we skip Godot check about it
+ # [Workaround] SwiftShader doesn't support tessellation, so we skip Godot check about it
- name: Compilation
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml
index b7cc127226..d1db449ab0 100644
--- a/.github/workflows/windows_builds.yml
+++ b/.github/workflows/windows_builds.yml
@@ -46,7 +46,7 @@ jobs:
- name: Configuring Python packages
run: |
python -c "import sys; print(sys.version)"
- python -m pip install scons pywin32
+ python -m pip install scons
python --version
scons --version
@@ -102,7 +102,7 @@ jobs:
- name: Configuring Python packages
run: |
python -c "import sys; print(sys.version)"
- python -m pip install scons pywin32
+ python -m pip install scons
python --version
scons --version
diff --git a/.mailmap b/.mailmap
index 3cb0a91356..dd1c35ed57 100644
--- a/.mailmap
+++ b/.mailmap
@@ -68,6 +68,7 @@ Kanabenki <lucien.menassol@gmail.com> <18357657+Kanabenki@users.noreply.github.c
Kelly Thomas <kelly.thomas@hotmail.com.au>
Kongfa Waroros <gongpha@hotmail.com>
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>
+kleonc <9283098+kleonc@users.noreply.github.com> <kleonc@users.noreply.github.com>
Leon Krause <lk@leonkrause.com> <eska@eska.me>
Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
Liz Haas <27thLiz@gmail.com>
@@ -94,6 +95,7 @@ Nathan Warden <nathan@nathanwarden.com> <nathanwardenlee@icloud.com>
Nils ANDRÉ-CHANG <nils@nilsand.re>
Nils ANDRÉ-CHANG <nils@nilsand.re> <nils.andre.chang@gmail.com>
Nuno Donato <nunodonato@gmail.com> <n.donato@estrelasustentavel.pt>
+Pawel Kowal <pkowal1982@gmail.com>
Pedro J. Estébanez <pedrojrulez@gmail.com> <RandomShaper@users.noreply.github.com>
Paul Batty <p_batty@hotmail.co.uk>
Paul Batty <p_batty@hotmail.co.uk> <Paulb23@users.noreply.github.com>
diff --git a/AUTHORS.md b/AUTHORS.md
index 7c5eb0c56b..0aacde20e8 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -109,6 +109,7 @@ name is available.
Julian Murgia (StraToN)
Justo Delgado (mrcdk)
Kelly Thomas (KellyThomas)
+ kleonc
Kongfa Waroros (gongpha)
Kostadin Damyanov (Max-Might)
K. S. Ernest (iFire) Lee (fire)
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 3bb9c916fd..b2a930a4bb 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -55,6 +55,14 @@ Comment: Godot Engine logo
Copyright: 2017, Andrea Calabró
License: CC-BY-4.0
+Files: ./core/math/convex_hull.cpp
+ ./core/math/convex_hull.h
+Comment: Bullet Continuous Collision Detection and Physics Library
+Copyright: 2011, Ole Kniemeyer, MAXON, www.maxon.net
+ 2007-2021, Juan Linietsky, Ariel Manzur.
+ 2014-2021, Godot Engine contributors.
+License: Expat and Zlib
+
Files: ./modules/fbx/fbx_parser/
Comment: Open Asset Import Library (FBX parser)
Copyright: 2006-2020, assimp team
@@ -131,6 +139,11 @@ Comment: doctest
Copyright: 2016-2020, Viktor Kirilov
License: Expat
+Files: ./thirdparty/embree/
+Comment: Embree
+Copyright: 2009-2021 Intel Corporation
+License: Apache-2.0
+
Files: ./thirdparty/enet/
Comment: ENet
Copyright: 2002-2020, Lee Salzman
@@ -198,7 +211,7 @@ License: HarfBuzz
Files: ./thirdparty/icu4c/
Comment: International Components for Unicode
-Copyright: 1991-2020, Unicode
+Copyright: 1991-2021, Unicode
License: Unicode
Files: ./thirdparty/jpeg-compressor/
@@ -347,6 +360,12 @@ Comment: SMAZ
Copyright: 2006-2009, Salvatore Sanfilippo
License: BSD-3-clause
+Files: ./thirdparty/misc/smolv.cpp
+ ./thirdparty/misc/smolv.h
+Comment: SMOL-V
+Copyright: 2016-2020, Aras Pranckevicius
+License: public-domain or Unlicense or Expat
+
Files: ./thirdparty/misc/stb_rect_pack.h
./thirdparty/misc/stb_vorbis.c
Comment: stb libraries
diff --git a/DONORS.md b/DONORS.md
index 77fa564a1b..6f359d4b6c 100644
--- a/DONORS.md
+++ b/DONORS.md
@@ -7,7 +7,7 @@ support of generous donors.
The ways to donate to the project, as well as details on how the funds are
used, are described on [Godot's website](https://godotengine.org/donate).
-The following is a list of the current monthly donors, to be have their
+The following is a list of the current monthly donors, who will have their
generous deed immortalized in the next stable release of Godot Engine.
## Platinum sponsors
@@ -23,16 +23,19 @@ generous deed immortalized in the next stable release of Godot Engine.
## Silver sponsors
ASIFA-Hollywood <https://www.asifa-hollywood.org>
- Moonwards <https://www.moonwards.com>
- Zenva Academy <https://academy.zenva.com>
+ LITSLINK <https://litslink.com>
## Bronze sponsors
+ Ben Nolan
Brandon Lamb
Garry Newman
Gordon MacPherson
Hunter Dickson
+ Kitcat490
Kyle Szklenski
+ Moonwards <https://www.moonwards.com>
+ TrampolineTales <http://trampolinetales.com>
## Mini sponsors
@@ -40,13 +43,14 @@ generous deed immortalized in the next stable release of Godot Engine.
Alejandro Saucedo
alex brown
Andrew Dunai
+ Angry Skull
anti666
- Ben Nolan
blurp
CD
Christian Baune
Christoffer Sundbom
Christopher Montesano
+ Daniel Edwards
Darrin Massena
David Mydlarz
Digital Grows
@@ -56,20 +60,23 @@ generous deed immortalized in the next stable release of Godot Engine.
Gamechuck
GameDev.net
Hein-Pieter van Braam
- Jacob McKenney
Jasper Brooks
Javary Co.
+ Jay Sistar
Jeffery Chiu
John G Gentzel
Jonah Stich
Justin Arnold
+ Justo Delgado Baudí
Kamil Brzezinski
Marcel Kräml
+ Marek Belski
Matthieu Huvé
Maxim Karsten
Mike King
Nathan Warden
Neal Gompa (Conan Kudo)
+ Ninja_5tyl3
Patrick Horn
Patrick Schmidt
Péter Magyar
@@ -86,8 +93,10 @@ generous deed immortalized in the next stable release of Godot Engine.
## Gold donors
Acheron
+ Adam Brown
albinaask
Alvaro A Baena R
+ Andres Hernandez
Asher Glick
Barugon
Carlo Cabanilla
@@ -97,12 +106,11 @@ generous deed immortalized in the next stable release of Godot Engine.
David Gehrig
David Snopek
Don B
+ Ealthy Studio
Ed Morley
Ellen Poe
Florian Rämisch
- Forge
Gamejunkey
- Hoojib
Jakub Grzesik
Javier Roman
Joan Fons
@@ -122,24 +130,26 @@ generous deed immortalized in the next stable release of Godot Engine.
m kaersten
Monster Vial
Officine Pixel S.n.c.
+ Petrus Prinsloo
Rene
Retro Village
Rob Messick
Roland Fredenhagen
Ronan Zeegers
- Sandro Jenny
Sarksus
Scott B
Sean
+ segfault-god
Sergey
Sofox
+ Stephen Molyneaux
Taylor Ritenour
Tom Langwaldt
Tricky Fat Cat
tukon
+ Vagabond Arcade
Vitaliy Sapronenko
William Wold
- xagonist
Xeno Coliseum
Zaven Muradyan
@@ -150,58 +160,69 @@ generous deed immortalized in the next stable release of Godot Engine.
Alexey Dyadchenko
Alex Khayrullin
alice gambrell
- Andreas Funke
Andrew Cunningham
Antanas Paskauskas
Antoni Batchelli
+ Arch Henderson III
Arisaka Mayuki
Arthur S. Muszynski
Ben Botwin
Brandon Hawkinson
Caleb Sizemore
- Can Eris
+ Cameron Connolly
Charlie Whitfield
Chase Taranto
Chelsea Hash
Chris Petrich
Chris Serino
Christian Leth Jeppesen
+ Container7
Craig Ostrin
Craig Smith
Cristopher
+ CzechBlueBear
D
dan didenko
+ Daniel Tebbutt
Darrian Little
Dennis Belfrage
Dev To be curious
+ Dietrich Schuetz
Digital Denizen
Dimitri Nüscheler
Donn Eddy
Easypete
Edgar Sun
+ Eric
Eric Brand
Eugenio Hugo Salgüero Jáñez
EXUREI
flesk
+ foxydevloper
+ Fransiska
F S
Gabrielius Vaiškūnas
Gary Hulst
gavlig
General Chicken
+ Geoffroy Warin
GGGames.org
Guilherme Felipe de C. G. da Silva
Harvey Fong
Heath Hayes
Horváth Péter
Hu Hund
+ Hunter Barabas
Jake Burga
James Couzens
+ Jan Sælid
Jared
Jared White
+ Jeppe Zapp
Jesús Chicharro
Joel Fivat
- Joel Höglund
Johnathan Kupferer
+ John Knight
Jose Malheiro
Jose Manuel Muñoz Perez
Joseph Crane
@@ -211,13 +232,14 @@ generous deed immortalized in the next stable release of Godot Engine.
Juan T Chen
Juan Velandia
Judd
+ Julián Absatz
Julian Todd
Juraj Móza
JUSTIN CARROLL
- Justo Delgado Baudí
Kelteseth
kickmaniac
kinfox
+ Kis Levente Lorand
Kos
Lachie
Lain Ballard
@@ -225,22 +247,21 @@ generous deed immortalized in the next stable release of Godot Engine.
leetNightshade
Leo Fidel R Liban
Liam Smyth
+ Luca Vazzano
Luc-Frédéric Langis
- Åukasz Nowak
MadScientistCarl
- Marcelo Dornbusch Lopes
Marcus Dobler
Marcus Richter
- Marek Belski
Mark Barrett
Martin Eigel
Martin Kotz
Martin Soucek
- Matt Eunson
+ matt
Matt Greene
Matthias Toepp
medecau
Michael
+ Michael Bordießer-Krauth
Michael Dürwald
Michael Policastro
MightyPossum
@@ -257,23 +278,26 @@ generous deed immortalized in the next stable release of Godot Engine.
Pavel Kotlyar
Pedro Silva
Pete Goodwin
+ Peter Richmond
Petr Malac
PhaineOfCatz
pl
Raymond Harris
- Raz A
+ Renato Fontes
Rene Tailleur
Rhodochrone
Ricardo Alcantara
+ Rob
Robert Larnach
+ Robert McDermott
Robert Willes
Rob McInroy
Rocknight Studios
Rodrigo Favarete
+ Romeo Disca
Ronnie Ashlock
Ronny Mühle
Ryan Scott
- Ryszard Sommefeldt
Samuel Judd
Sean Morgan
Sebastian Hutter
@@ -288,23 +312,26 @@ generous deed immortalized in the next stable release of Godot Engine.
Stephan Hennion
Steven Landow
Stoned Xander
+ Super Izzo
Sven F.
Thomas Bjarnelöf
Thomas Kurz
Tim Howard
Tobias Bocanegra
Todd Smith
+ Torbulous
+ toto bibi
+ Troy Kinsella
Turntsnaco
tweaklab
Valryia
Vincent Cloutier
Vlad Ceru Opran
VoidPointer
- voxelv
+ Winston
Wojciech Chojnacki
xzibiting
Yuancheng Zhang
- Zhou Tuizhi
Zie Weaver
Zoran Kukulj
@@ -312,8 +339,8 @@ generous deed immortalized in the next stable release of Godot Engine.
1D_Inc
Abraham Haskins
+ Actual_Dio
Adam
- Adam Brown
Adam Brunnmeier
Adam Carr
Adam Long
@@ -322,8 +349,8 @@ generous deed immortalized in the next stable release of Godot Engine.
Adam Smeltzer
Adam Szymański
Adisibio
+ Adrien de Pierres
Agar3s - Giovanny Beltrán
- Agustinus Arya
Ahmet Kalyoncu
Aidan O'Flannagain
Aki Mimoto
@@ -334,15 +361,19 @@ generous deed immortalized in the next stable release of Godot Engine.
AleMax
Alessandro Senese
Alexander Erlemann
+ Alexander Ravenheart
Alexander Ryndin
Alexander Walter (SilvanuZ)
Alexandre Beaudoin
+ Alex Chan
alex clavelle
+ alex raeside
Alex (Well Done Games)
Allan Davis
Allen Schade
+ Aloehart
+ Amanda
Anders Marstein Kruke
- Andreas Krampitz
Andre Stackhouse
andrew james morris
Andrew Mansuetti
@@ -350,22 +381,25 @@ generous deed immortalized in the next stable release of Godot Engine.
Ano Nim
Anthony Avina
Anton Bouwer
- aomimezura11
- AP Condomines
Arch Toasty
Arda Erol
Armin Preiml
Arseniy M
+ Arthur Brainville
Ashley Claymore
Astier Mickael
Aubrey Falconer
+ Audun Borgersen
+ aurelien condomines
AzulCrescent
Balázs Batári
Bartosz Bielecki
Benedikt
+ Benoit Jauvin-Girard
Ben Vercammen
Bernd Jänichen
Bernhard Werner
+ Bill Thibault
Bjarne Voigtländer
Black Block
blackjacksike
@@ -385,8 +419,8 @@ generous deed immortalized in the next stable release of Godot Engine.
Cameron Meyer
Carlos Cejudo
Carl van der Geest
- Carwyn Edwards
Cas Brugman
+ Casey
Cassidy James
Cédric Givord
Chad Steadman
@@ -404,13 +438,15 @@ generous deed immortalized in the next stable release of Godot Engine.
Clay Heaton
Cody Parker
Conall O
+ Conner Lane
+ Corchari
+ Craig Maloney
Craig Post
- CzechBlueBear
Daniel Cheney
Daniel Johnson
- DanielMaximiano
Daren Scot Wilson
Dave Walker
+ David Baker
David Bôle
David May
David Maziarka
@@ -447,6 +483,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Felix Bohmann
Flaredown
Forty Doubleu
+ Francisco Garcia Florez
Francois Holland
Frank
Game Endeavor
@@ -454,18 +491,18 @@ generous deed immortalized in the next stable release of Godot Engine.
Gary Thomas
George Marques
georgios katsanakis
- GFizz
Greg Lincoln
Greg Olson
Greyson Richey
Grid
+ Grominet
Guillaume Audirac
Guillaume Pham Ngoc
Guldoman
- Gustavo Loureiro dos Reis
Hal A
- helija
Heribert Hirth
+ Hoojib
+ Houdini Blueprints
Hunter Jones
Ian Williams
Iiari
@@ -473,7 +510,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Ivan Nikolaev
iveks
Jackson Harmer
- Jacob
+ Jacob D
Jaguar
Jaime Ruiz-Borau Vizárraga
Jake D
@@ -481,18 +518,25 @@ generous deed immortalized in the next stable release of Godot Engine.
Jako Danar
James
James A F Manley
+ James Gary
+ James Guardino
James Quincy
James Thomas
Jamie Massey
+ Janis Skuja
Jan Vetulani
JARKKO PARVIAINEN
Jason Bolton
+ Jason Malcolm-Herzmark
Jason Uechi
Jeff Hungerford
+ Jeffrey Berube
Jennifer Graves
Jesse Dubay
- Jhon Adams
+ Jim Engstrand
Joe Klemmer
+ Joel Höglund
+ John Bruce
John Gabriel
Jonah Branch
Jonas
@@ -500,10 +544,12 @@ generous deed immortalized in the next stable release of Godot Engine.
Jonas Rudlang
Jonas Yamazaki
Jonatan R
+ Jonathan Bieber
Jonathan G
Jon Bonazza
Jon Oakes
Jon Sully
+ Jordan West
Jordy Goodridge
Jorge Antunes
Jorge Araya Navarro
@@ -532,15 +578,19 @@ generous deed immortalized in the next stable release of Godot Engine.
Kenneth Lee
Kent Jofur
Ketafuki
+ Kevin van Rooijen
Kiri Jolly
Kjetil Haugland
Konstantin Goncharov
- Kridsada Thanabulpong
+ Krishna Nadoor
Kristian Nygaard Jensen
+ Kronarq
KsyTek Games
kycho
+ Kyle Burnett
Kyle Jacobs
Kyuppin
+ Lady Grach
Lasse le Dous
Laurent CHEA
Laurent Tréguier
@@ -569,17 +619,20 @@ generous deed immortalized in the next stable release of Godot Engine.
Matt Edwards
Matthew Booe
Matt Sylvia
+ Maverick C.
Max Fiedler
Maxime Blade
Maxwell
- Megasploot
+ Mecha Kaiju X
Melissa Mears
Merlyn Morgan-Graham
mewin
Michael
Michael Bruce-Lockhart
Michael Haney
+ Michael Morrison
Michał Skwarek
+ Michel Candries
MidoriBunn 'tis BS
Mikayla
Mike
@@ -588,9 +641,13 @@ generous deed immortalized in the next stable release of Godot Engine.
Mike Cunningham
Mitchell J. Wagner
MJacred
+ ModularMind
Molinghu
Molly Jameson
+ MoltenGears
+ Morwyn
MrAZIE
+ Mrjemandem
Nathan Fish
Nathaniel
nee
@@ -599,7 +656,9 @@ generous deed immortalized in the next stable release of Godot Engine.
Neil Wang
Nerdforge
Nerdyninja
- Nicholas
+ Nicholas La Roux
+ Nicholas Orlowski
+ Nick Eldrenkamp
Nick Macholl
Niclas Eriksen
Nicolas Goll-Perrier
@@ -612,27 +671,30 @@ generous deed immortalized in the next stable release of Godot Engine.
OKV
Oleg Reva
Oleksandr Kryvonos
+ Olle Soprani
Omar Delarosa
Oriol Muñoz Princep
Oscar Domingo
+ Pascal
Patrick Brock
Patrick Nafarrete
Paul Gieske
Paweł Kowal
PaweÅ‚ Åyczkowski
+ p_brighenti
Peter Höglund
- Peter Richmond
- Petrus Prinsloo
Philip Cohoe
Philip Ludington (MrPhil)
Pierre Caye
- Piotr Góral
+ pj
Point08
Preethi Vaidyanathan
pwab
+ Rackat
Rad Cat
Rafa Laguna
Raffaele Aramo
+ Rainer Amler
Rami Hanano
RAMupgrade
Remi Rampin
@@ -640,6 +702,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Reneator
Riccardo Marini
Richard Ivánek
+ Richard Néveri
Riley
Robert Farr (Larington)
Rob Ruana
@@ -652,15 +715,13 @@ generous deed immortalized in the next stable release of Godot Engine.
Ryan Groom
Sam Caulfield
Sam Edson
- Samuele Zolfanelli
- scapegoat57
- Scott D. Yelich
Scott Longley
Sean Lynch
Sebastian Michailidis
SeongWan Kim
Sergey
- Sergiy Onenko
+ SeungJong k
+ Shaidak
Shane
Shane Sicienski
Shane Spoor
@@ -669,35 +730,40 @@ generous deed immortalized in the next stable release of Godot Engine.
Simon Jonas Larsen
Simon Schoenenberger
Simon Wenner
+ sirn
Skalli
smbe19
smo1704
- soft circles
+ Solene Waked
Squirrel
Stéphane Roussel
Steve Cloete
summerblind
Sung soo Choi
Svenne Krap
+ SxP
tadashi endo
- tannhauser_gate
Tarch
Terry
+ the9thdude
Theodore Lindsey
TheVoiceInMyHead
thomas
Thomas Bechtold
Thomas Detoy
Thomas Horwath
+ Tianren Qin
+ Till1805
Tim Drumheller
Tim Erskine
Tim Gleason
Timothy B. MacDonald
+ Title Plinsut
TMoney
+ Toadile
Tobias Bradtke
Tom Coxon
Toni Duran
- Tony Zhao
Torgeir Lilleskog
Torsten Crass
toupeira
@@ -718,6 +784,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Vi Watch
Vladimir Savin
Vladislav Smirnov
+ Vojtěch
Vytenis Narušis
waka nya
Wayne Haak
@@ -729,10 +796,11 @@ generous deed immortalized in the next stable release of Godot Engine.
Wyatt Goodin
x1212
xenomat
+ Yan Shi
Yegor Smirnov
Zak Stephens
- Эльдар Будагов
蕭惟å…
+ éƒæ™¨ç…œ
## Bronze donors
diff --git a/README.md b/README.md
index 72a85492fd..8ddddf0e63 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
<p align="center">
<a href="https://godotengine.org">
- <img src="logo.svg" width="400" alt="Godot Engine logo">
+ <img src="logo_outlined.svg" width="400" alt="Godot Engine logo">
</a>
</p>
diff --git a/SConstruct b/SConstruct
index 2d9802f293..f8e3a68edd 100644
--- a/SConstruct
+++ b/SConstruct
@@ -123,6 +123,7 @@ opts.Add(BoolVariable("use_lto", "Use link-time optimization", 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))
+opts.Add(BoolVariable("vulkan", "Enable the vulkan video driver", True))
opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "")
opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True))
@@ -145,6 +146,7 @@ opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise e
# Thirdparty libraries
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_embree", "Use the built-in Embree library", 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))
@@ -408,14 +410,27 @@ if selected_platform in platform_list:
env.Prepend(CCFLAGS=["/std:c++17"])
# Enforce our minimal compiler version requirements
- cc_version = methods.get_compiler_version(env) or [-1, -1]
- cc_version_major = cc_version[0]
- cc_version_minor = cc_version[1]
+ cc_version = methods.get_compiler_version(env) or {
+ "major": None,
+ "minor": None,
+ "patch": None,
+ "metadata1": None,
+ "metadata2": None,
+ "date": None,
+ }
+ cc_version_major = int(cc_version["major"] or -1)
+ cc_version_minor = int(cc_version["minor"] or -1)
+ cc_version_metadata1 = cc_version["metadata1"] or ""
if methods.using_gcc(env):
+ if cc_version_major == -1:
+ print(
+ "Couldn't detect compiler version, skipping version checks. "
+ "Build may fail if the compiler doesn't support C++17 fully."
+ )
# 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:
+ elif 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 "
@@ -431,10 +446,23 @@ if selected_platform in platform_list:
"SCons command line."
)
Exit(255)
+ elif cc_version_metadata1 == "win32":
+ print(
+ "Detected mingw version is not using posix threads. Only posix "
+ "version of mingw is supported. "
+ 'Use "update-alternatives --config <platform>-w64-mingw32-[gcc|g++]" '
+ "to switch to posix threads."
+ )
+ Exit(255)
elif methods.using_clang(env):
+ if cc_version_major == -1:
+ print(
+ "Couldn't detect compiler version, skipping version checks. "
+ "Build may fail if the compiler doesn't support C++17 fully."
+ )
# Apple LLVM versions differ from upstream LLVM version \o/, compare
# in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
- if env["platform"] == "osx" or env["platform"] == "iphone":
+ elif env["platform"] == "osx" or env["platform"] == "iphone":
vanilla = methods.is_vanilla_clang(env)
if vanilla and cc_version_major < 6:
print(
@@ -638,20 +666,19 @@ if selected_platform in platform_list:
if not env["verbose"]:
methods.no_verbose(sys, env)
- if not env["platform"] == "server":
- GLSL_BUILDERS = {
- "RD_GLSL": env.Builder(
- action=env.Run(glsl_builders.build_rd_headers, 'Building RD_GLSL header: "$TARGET"'),
- suffix="glsl.gen.h",
- src_suffix=".glsl",
- ),
- "GLSL_HEADER": env.Builder(
- action=env.Run(glsl_builders.build_raw_headers, 'Building GLSL header: "$TARGET"'),
- suffix="glsl.gen.h",
- src_suffix=".glsl",
- ),
- }
- env.Append(BUILDERS=GLSL_BUILDERS)
+ GLSL_BUILDERS = {
+ "RD_GLSL": env.Builder(
+ action=env.Run(glsl_builders.build_rd_headers, 'Building RD_GLSL header: "$TARGET"'),
+ suffix="glsl.gen.h",
+ src_suffix=".glsl",
+ ),
+ "GLSL_HEADER": env.Builder(
+ action=env.Run(glsl_builders.build_raw_headers, 'Building GLSL header: "$TARGET"'),
+ suffix="glsl.gen.h",
+ src_suffix=".glsl",
+ ),
+ }
+ env.Append(BUILDERS=GLSL_BUILDERS)
scons_cache_path = os.environ.get("SCONS_CACHE")
if scons_cache_path != None:
diff --git a/core/SCsub b/core/SCsub
index 21829553a7..e3ba46be02 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -12,25 +12,28 @@ 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:
- e = os.environ["SCRIPT_AES256_ENCRYPTION_KEY"]
- txt = ""
+ key = os.environ["SCRIPT_AES256_ENCRYPTION_KEY"]
ec_valid = True
- if len(e) != 64:
+ if len(key) != 64:
ec_valid = False
else:
-
- for i in range(len(e) >> 1):
+ txt = ""
+ for i in range(len(key) >> 1):
if i > 0:
txt += ","
- txts = "0x" + e[i * 2 : i * 2 + 2]
+ txts = "0x" + key[i * 2 : i * 2 + 2]
try:
int(txts, 16)
except Exception:
ec_valid = False
txt += txts
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)
+ print("Error: Invalid AES256 encryption key, not 64 hexadecimal characters: '" + key + "'.")
+ print(
+ "Unset 'SCRIPT_AES256_ENCRYPTION_KEY' in your environment "
+ "or make sure that it contains exactly 64 hexadecimal characters."
+ )
+ Exit(255)
# 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:
@@ -56,6 +59,7 @@ thirdparty_misc_sources = [
"pcg.cpp",
"polypartition.cpp",
"clipper.cpp",
+ "smolv.cpp",
]
thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources)
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 2360d66438..99ec1aeb5b 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -31,6 +31,7 @@
#include "engine.h"
#include "core/authors.gen.h"
+#include "core/config/project_settings.h"
#include "core/donors.gen.h"
#include "core/license.gen.h"
#include "core/version.h"
@@ -210,6 +211,13 @@ void Engine::get_singletons(List<Singleton> *p_singletons) {
}
}
+void Engine::set_shader_cache_path(const String &p_path) {
+ shader_cache_path = p_path;
+}
+String Engine::get_shader_cache_path() const {
+ return shader_cache_path;
+}
+
Engine *Engine::singleton = nullptr;
Engine *Engine::get_singleton() {
@@ -224,9 +232,9 @@ Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr) :
name(p_name),
ptr(p_ptr) {
#ifdef DEBUG_ENABLED
- Reference *ref = Object::cast_to<Reference>(p_ptr);
- if (ref && !ref->is_referenced()) {
- WARN_PRINT("You must use Ref<> to ensure the lifetime of a Reference object intended to be used as a singleton.");
+ RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
+ if (rc && !rc->is_referenced()) {
+ WARN_PRINT("You must use Ref<> to ensure the lifetime of a RefCounted object intended to be used as a singleton.");
}
#endif
}
diff --git a/core/config/engine.h b/core/config/engine.h
index a9080e3dfd..276da1c7ea 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -72,6 +72,8 @@ private:
static Engine *singleton;
+ String shader_cache_path;
+
public:
static Engine *get_singleton();
@@ -121,6 +123,9 @@ public:
Dictionary get_license_info() const;
String get_license_text() const;
+ void set_shader_cache_path(const String &p_path);
+ String get_shader_cache_path() const;
+
bool is_abort_on_gpu_errors_enabled() const;
bool is_validation_layers_enabled() const;
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 25dd408dce..74ef05b797 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -33,11 +33,11 @@
#include "core/core_bind.h"
#include "core/core_string_names.h"
#include "core/input/input_map.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_network.h"
#include "core/io/file_access_pack.h"
#include "core/io/marshalls.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/variant/variant_parser.h"
@@ -62,7 +62,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
}
if (p_path.begins_with("res://") || p_path.begins_with("user://") ||
- (p_path.is_abs_path() && !p_path.begins_with(resource_path))) {
+ (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
return p_path.simplify_path();
}
@@ -711,8 +711,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
file->store_32(count + 1);
//store how many properties are saved, add one for custom featuers, which must always go first
String key = CoreStringNames::get_singleton()->_custom_features;
- file->store_32(key.length());
- file->store_string(key);
+ file->store_pascal_string(key);
int len;
err = encode_variant(p_custom_features, nullptr, len, false);
@@ -749,8 +748,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
value = get(key);
}
- file->store_32(key.length());
- file->store_string(key);
+ file->store_pascal_string(key);
int len;
err = encode_variant(value, nullptr, len, true);
@@ -1102,7 +1100,9 @@ ProjectSettings::ProjectSettings() {
if (Engine::get_singleton()->has_singleton("GodotSharp")) {
extensions.push_back("cs");
}
- extensions.push_back("shader");
+ extensions.push_back("gdshader");
+
+ GLOBAL_DEF("editor/run/main_run_args", "");
GLOBAL_DEF("editor/script/search_in_file_extensions", extensions);
custom_prop_info["editor/script/search_in_file_extensions"] = PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions");
@@ -1112,7 +1112,8 @@ ProjectSettings::ProjectSettings() {
_add_builtin_input_map();
- custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor");
+ // Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum.
+ custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::INT, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor");
custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
GLOBAL_DEF("physics/2d/run_on_thread", false);
GLOBAL_DEF("physics/3d/run_on_thread", false);
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 84d8d0d4d3..60759cd71c 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -42,28 +42,6 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
-/**
- * Time constants borrowed from loc_time.h
- */
-#define EPOCH_YR 1970 /* EPOCH = Jan 1 1970 00:00:00 */
-#define SECS_DAY (24L * 60L * 60L)
-#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
-#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
-#define SECOND_KEY "second"
-#define MINUTE_KEY "minute"
-#define HOUR_KEY "hour"
-#define DAY_KEY "day"
-#define MONTH_KEY "month"
-#define YEAR_KEY "year"
-#define WEEKDAY_KEY "weekday"
-#define DST_KEY "dst"
-
-/// Table of number of days in each month (for regular year and leap year)
-static const unsigned int MONTH_DAYS_TABLE[2][12] = {
- { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
- { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
-};
-
////// _ResourceLoader //////
_ResourceLoader *_ResourceLoader::singleton = nullptr;
@@ -322,198 +300,6 @@ uint64_t _OS::get_static_memory_peak_usage() const {
return OS::get_singleton()->get_static_memory_peak_usage();
}
-/**
- * Get current datetime with consideration for utc and
- * dst
- */
-Dictionary _OS::get_datetime(bool utc) const {
- Dictionary dated = get_date(utc);
- Dictionary timed = get_time(utc);
-
- List<Variant> keys;
- timed.get_key_list(&keys);
-
- for (int i = 0; i < keys.size(); i++) {
- dated[keys[i]] = timed[keys[i]];
- }
-
- return dated;
-}
-
-Dictionary _OS::get_date(bool utc) const {
- OS::Date date = OS::get_singleton()->get_date(utc);
- Dictionary dated;
- dated[YEAR_KEY] = date.year;
- dated[MONTH_KEY] = date.month;
- dated[DAY_KEY] = date.day;
- dated[WEEKDAY_KEY] = date.weekday;
- dated[DST_KEY] = date.dst;
- return dated;
-}
-
-Dictionary _OS::get_time(bool utc) const {
- OS::Time time = OS::get_singleton()->get_time(utc);
- Dictionary timed;
- timed[HOUR_KEY] = time.hour;
- timed[MINUTE_KEY] = time.min;
- timed[SECOND_KEY] = time.sec;
- return timed;
-}
-
-/**
- * Get an epoch time value from a dictionary of time values
- * @p datetime must be populated with the following keys:
- * day, hour, minute, month, second, year. (dst is ignored).
- *
- * You can pass the output from
- * get_datetime_from_unix_time directly into this function
- *
- * @param datetime dictionary of date and time values to convert
- *
- * @return epoch calculated
- */
-int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const {
- // if datetime is an empty Dictionary throws an error
- ERR_FAIL_COND_V_MSG(datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty");
-
- // Bunch of conversion constants
- static const unsigned int SECONDS_PER_MINUTE = 60;
- static const unsigned int MINUTES_PER_HOUR = 60;
- static const unsigned int HOURS_PER_DAY = 24;
- static const unsigned int SECONDS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE;
- static const unsigned int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
-
- // Get all time values from the dictionary, set to zero if it doesn't exist.
- // Risk incorrect calculation over throwing errors
- unsigned int second = ((datetime.has(SECOND_KEY)) ? static_cast<unsigned int>(datetime[SECOND_KEY]) : 0);
- unsigned int minute = ((datetime.has(MINUTE_KEY)) ? static_cast<unsigned int>(datetime[MINUTE_KEY]) : 0);
- unsigned int hour = ((datetime.has(HOUR_KEY)) ? static_cast<unsigned int>(datetime[HOUR_KEY]) : 0);
- unsigned int day = ((datetime.has(DAY_KEY)) ? static_cast<unsigned int>(datetime[DAY_KEY]) : 1);
- unsigned int month = ((datetime.has(MONTH_KEY)) ? static_cast<unsigned int>(datetime[MONTH_KEY]) : 1);
- unsigned int year = ((datetime.has(YEAR_KEY)) ? static_cast<unsigned int>(datetime[YEAR_KEY]) : 0);
-
- /// How many days come before each month (0-12)
- static const unsigned short int DAYS_PAST_THIS_YEAR_TABLE[2][13] = {
- /* Normal years. */
- { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
- /* Leap years. */
- { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
- };
-
- ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + ".");
-
- ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + ".");
-
- ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + ".");
-
- ERR_FAIL_COND_V_MSG(month > 12 || month == 0, 0, "Invalid month value of: " + itos(month) + ".");
-
- // Do this check after month is tested as valid
- ERR_FAIL_COND_V_MSG(day > MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1] || day == 0, 0, "Invalid day value of '" + itos(day) + "' which is larger than '" + itos(MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1]) + "' or 0.");
- // Calculate all the seconds from months past in this year
- uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month - 1] * SECONDS_PER_DAY;
-
- int64_t SECONDS_FROM_YEARS_PAST = 0;
- if (year >= EPOCH_YR) {
- for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) {
- SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * SECONDS_PER_DAY;
- }
- } else {
- for (unsigned int iyear = EPOCH_YR - 1; iyear >= year; iyear--) {
- SECONDS_FROM_YEARS_PAST -= YEARSIZE(iyear) * SECONDS_PER_DAY;
- }
- }
-
- int64_t epoch =
- second +
- minute * SECONDS_PER_MINUTE +
- hour * SECONDS_PER_HOUR +
- // Subtract 1 from day, since the current day isn't over yet
- // and we cannot count all 24 hours.
- (day - 1) * SECONDS_PER_DAY +
- SECONDS_FROM_MONTHS_PAST_THIS_YEAR +
- SECONDS_FROM_YEARS_PAST;
- return epoch;
-}
-
-/**
- * Get a dictionary of time values when given epoch time
- *
- * Dictionary Time values will be a union if values from #get_time
- * and #get_date dictionaries (with the exception of dst =
- * day light standard time, as it cannot be determined from epoch)
- *
- * @param unix_time_val epoch time to convert
- *
- * @return dictionary of date and time values
- */
-Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const {
- OS::Date date;
- OS::Time time;
-
- long dayclock, dayno;
- int year = EPOCH_YR;
-
- if (unix_time_val >= 0) {
- dayno = unix_time_val / SECS_DAY;
- dayclock = unix_time_val % SECS_DAY;
- /* day 0 was a thursday */
- date.weekday = static_cast<OS::Weekday>((dayno + 4) % 7);
- while (dayno >= YEARSIZE(year)) {
- dayno -= YEARSIZE(year);
- year++;
- }
- } else {
- dayno = (unix_time_val - SECS_DAY + 1) / SECS_DAY;
- dayclock = unix_time_val - dayno * SECS_DAY;
- date.weekday = static_cast<OS::Weekday>(((dayno % 7) + 11) % 7);
- do {
- year--;
- dayno += YEARSIZE(year);
- } while (dayno < 0);
- }
-
- time.sec = dayclock % 60;
- time.min = (dayclock % 3600) / 60;
- time.hour = dayclock / 3600;
- date.year = year;
-
- size_t imonth = 0;
-
- while ((unsigned long)dayno >= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]) {
- dayno -= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth];
- imonth++;
- }
-
- /// Add 1 to month to make sure months are indexed starting at 1
- date.month = static_cast<OS::Month>(imonth + 1);
-
- date.day = dayno + 1;
-
- Dictionary timed;
- timed[HOUR_KEY] = time.hour;
- timed[MINUTE_KEY] = time.min;
- timed[SECOND_KEY] = time.sec;
- timed[YEAR_KEY] = date.year;
- timed[MONTH_KEY] = date.month;
- timed[DAY_KEY] = date.day;
- timed[WEEKDAY_KEY] = date.weekday;
-
- return timed;
-}
-
-Dictionary _OS::get_time_zone_info() const {
- OS::TimeZoneInfo info = OS::get_singleton()->get_time_zone_info();
- Dictionary infod;
- infod["bias"] = info.bias;
- infod["name"] = info.name;
- return infod;
-}
-
-double _OS::get_unix_time() const {
- return OS::get_singleton()->get_unix_time();
-}
-
/** This method uses a signed argument for better error reporting as it's used from the scripting API. */
void _OS::delay_usec(int p_usec) const {
ERR_FAIL_COND_MSG(
@@ -530,14 +316,6 @@ void _OS::delay_msec(int p_msec) const {
OS::get_singleton()->delay_usec(int64_t(p_msec) * 1000);
}
-uint32_t _OS::get_ticks_msec() const {
- return OS::get_singleton()->get_ticks_msec();
-}
-
-uint64_t _OS::get_ticks_usec() const {
- return OS::get_singleton()->get_ticks_usec();
-}
-
bool _OS::can_use_threads() const {
return OS::get_singleton()->can_use_threads();
}
@@ -644,6 +422,10 @@ String _OS::get_user_data_dir() const {
return OS::get_singleton()->get_user_data_dir();
}
+String _OS::get_external_data_dir() const {
+ return OS::get_singleton()->get_external_data_dir();
+}
+
bool _OS::is_debug_build() const {
#ifdef DEBUG_ENABLED
return true;
@@ -713,18 +495,8 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_name"), &_OS::get_name);
ClassDB::bind_method(D_METHOD("get_cmdline_args"), &_OS::get_cmdline_args);
- ClassDB::bind_method(D_METHOD("get_datetime", "utc"), &_OS::get_datetime, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_date", "utc"), &_OS::get_date, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_time", "utc"), &_OS::get_time, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_time_zone_info"), &_OS::get_time_zone_info);
- ClassDB::bind_method(D_METHOD("get_unix_time"), &_OS::get_unix_time);
- ClassDB::bind_method(D_METHOD("get_datetime_from_unix_time", "unix_time_val"), &_OS::get_datetime_from_unix_time);
- ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime", "datetime"), &_OS::get_unix_time_from_datetime);
-
ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &_OS::delay_usec);
ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &_OS::delay_msec);
- ClassDB::bind_method(D_METHOD("get_ticks_msec"), &_OS::get_ticks_msec);
- ClassDB::bind_method(D_METHOD("get_ticks_usec"), &_OS::get_ticks_usec);
ClassDB::bind_method(D_METHOD("get_locale"), &_OS::get_locale);
ClassDB::bind_method(D_METHOD("get_model_name"), &_OS::get_model_name);
@@ -744,6 +516,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_static_memory_peak_usage"), &_OS::get_static_memory_peak_usage);
ClassDB::bind_method(D_METHOD("get_user_data_dir"), &_OS::get_user_data_dir);
+ ClassDB::bind_method(D_METHOD("get_external_data_dir"), &_OS::get_external_data_dir);
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);
@@ -1226,7 +999,7 @@ Error _File::open(const String &p_path, ModeFlags p_mode_flags) {
Error err;
f = FileAccess::open(p_path, p_mode_flags, &err);
if (f) {
- f->set_endian_swap(eswap);
+ f->set_big_endian(big_endian);
}
return err;
}
@@ -1259,6 +1032,7 @@ String _File::get_path_absolute() const {
void _File::seek(int64_t p_position) {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_COND_MSG(p_position < 0, "Seek position must be a positive integer.");
f->seek(p_position);
}
@@ -1267,14 +1041,14 @@ void _File::seek_end(int64_t p_position) {
f->seek_end(p_position);
}
-int64_t _File::get_position() const {
+uint64_t _File::get_position() const {
ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
return f->get_position();
}
-int64_t _File::get_len() const {
+uint64_t _File::get_length() const {
ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
- return f->get_len();
+ return f->get_length();
}
bool _File::eof_reached() const {
@@ -1317,7 +1091,7 @@ real_t _File::get_real() const {
return f->get_real();
}
-Vector<uint8_t> _File::get_buffer(int p_length) const {
+Vector<uint8_t> _File::get_buffer(int64_t p_length) const {
Vector<uint8_t> data;
ERR_FAIL_COND_V_MSG(!f, data, "File must be opened before use.");
@@ -1330,8 +1104,7 @@ Vector<uint8_t> _File::get_buffer(int p_length) const {
ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements.");
uint8_t *w = data.ptrw();
- int len = f->get_buffer(&w[0], p_length);
- ERR_FAIL_COND_V(len < 0, Vector<uint8_t>());
+ int64_t len = f->get_buffer(&w[0], p_length);
if (len < p_length) {
data.resize(len);
@@ -1344,7 +1117,7 @@ String _File::get_as_text() const {
ERR_FAIL_COND_V_MSG(!f, String(), "File must be opened before use.");
String text;
- size_t original_pos = f->get_position();
+ uint64_t original_pos = f->get_position();
f->seek(0);
String l = get_line();
@@ -1382,15 +1155,15 @@ Vector<String> _File::get_csv_line(const String &p_delim) const {
* These flags get reset to false (little endian) on each open
*/
-void _File::set_endian_swap(bool p_swap) {
- eswap = p_swap;
+void _File::set_big_endian(bool p_big_endian) {
+ big_endian = p_big_endian;
if (f) {
- f->set_endian_swap(p_swap);
+ f->set_big_endian(p_big_endian);
}
}
-bool _File::get_endian_swap() {
- return eswap;
+bool _File::is_big_endian() {
+ return big_endian;
}
Error _File::get_error() const {
@@ -1473,7 +1246,7 @@ void _File::store_csv_line(const Vector<String> &p_values, const String &p_delim
void _File::store_buffer(const Vector<uint8_t> &p_buffer) {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
- int len = p_buffer.size();
+ uint64_t len = p_buffer.size();
if (len == 0) {
return;
}
@@ -1537,7 +1310,7 @@ void _File::_bind_methods() {
ClassDB::bind_method(D_METHOD("seek", "position"), &_File::seek);
ClassDB::bind_method(D_METHOD("seek_end", "position"), &_File::seek_end, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_position"), &_File::get_position);
- ClassDB::bind_method(D_METHOD("get_len"), &_File::get_len);
+ ClassDB::bind_method(D_METHOD("get_length"), &_File::get_length);
ClassDB::bind_method(D_METHOD("eof_reached"), &_File::eof_reached);
ClassDB::bind_method(D_METHOD("get_8"), &_File::get_8);
ClassDB::bind_method(D_METHOD("get_16"), &_File::get_16);
@@ -1546,14 +1319,14 @@ void _File::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_float"), &_File::get_float);
ClassDB::bind_method(D_METHOD("get_double"), &_File::get_double);
ClassDB::bind_method(D_METHOD("get_real"), &_File::get_real);
- ClassDB::bind_method(D_METHOD("get_buffer", "len"), &_File::get_buffer);
+ ClassDB::bind_method(D_METHOD("get_buffer", "length"), &_File::get_buffer);
ClassDB::bind_method(D_METHOD("get_line"), &_File::get_line);
ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &_File::get_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("get_as_text"), &_File::get_as_text);
ClassDB::bind_method(D_METHOD("get_md5", "path"), &_File::get_md5);
ClassDB::bind_method(D_METHOD("get_sha256", "path"), &_File::get_sha256);
- ClassDB::bind_method(D_METHOD("get_endian_swap"), &_File::get_endian_swap);
- ClassDB::bind_method(D_METHOD("set_endian_swap", "enable"), &_File::set_endian_swap);
+ ClassDB::bind_method(D_METHOD("is_big_endian"), &_File::is_big_endian);
+ ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &_File::set_big_endian);
ClassDB::bind_method(D_METHOD("get_error"), &_File::get_error);
ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &_File::get_var, DEFVAL(false));
@@ -1576,7 +1349,7 @@ void _File::_bind_methods() {
ClassDB::bind_method(D_METHOD("file_exists", "path"), &_File::file_exists);
ClassDB::bind_method(D_METHOD("get_modified_time", "file"), &_File::get_modified_time);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "endian_swap"), "set_endian_swap", "get_endian_swap");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
BIND_ENUM_CONSTANT(READ);
BIND_ENUM_CONSTANT(WRITE);
@@ -1617,11 +1390,11 @@ bool _Directory::is_open() const {
return d && dir_open;
}
-Error _Directory::list_dir_begin(bool p_skip_navigational, bool p_skip_hidden) {
+Error _Directory::list_dir_begin(bool p_show_navigational, bool p_show_hidden) {
ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- _list_skip_navigational = p_skip_navigational;
- _list_skip_hidden = p_skip_hidden;
+ _list_skip_navigational = !p_show_navigational;
+ _list_skip_hidden = !p_show_hidden;
return d->list_dir_begin();
}
@@ -1721,9 +1494,9 @@ bool _Directory::dir_exists(String p_dir) {
return d->dir_exists(p_dir);
}
-int _Directory::get_space_left() {
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
- return d->get_space_left() / 1024 * 1024; //return value in megabytes, given binding is int
+uint64_t _Directory::get_space_left() {
+ ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use.");
+ return d->get_space_left() / 1024 * 1024; // Truncate to closest MiB.
}
Error _Directory::copy(String p_from, String p_to) {
@@ -1759,7 +1532,7 @@ Error _Directory::remove(String p_name) {
void _Directory::_bind_methods() {
ClassDB::bind_method(D_METHOD("open", "path"), &_Directory::open);
- ClassDB::bind_method(D_METHOD("list_dir_begin", "skip_navigational", "skip_hidden"), &_Directory::list_dir_begin, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("list_dir_begin", "show_navigational", "show_hidden"), &_Directory::list_dir_begin, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_next"), &_Directory::get_next);
ClassDB::bind_method(D_METHOD("current_is_dir"), &_Directory::current_is_dir);
ClassDB::bind_method(D_METHOD("list_dir_end"), &_Directory::list_dir_end);
@@ -2070,7 +1843,7 @@ Variant _ClassDB::instance(const StringName &p_class) const {
return Variant();
}
- Reference *r = Object::cast_to<Reference>(obj);
+ RefCounted *r = Object::cast_to<RefCounted>(obj);
if (r) {
return REF(r);
} else {
@@ -2416,12 +2189,12 @@ Variant JSONParseResult::get_result() const {
}
void _JSON::_bind_methods() {
- ClassDB::bind_method(D_METHOD("print", "value", "indent", "sort_keys"), &_JSON::print, DEFVAL(String()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("print", "value", "indent", "sort_keys", "full_precision"), &_JSON::print, DEFVAL(String()), DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("parse", "json"), &_JSON::parse);
}
-String _JSON::print(const Variant &p_value, const String &p_indent, bool p_sort_keys) {
- return JSON::print(p_value, p_indent, p_sort_keys);
+String _JSON::print(const Variant &p_value, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
+ return JSON::print(p_value, p_indent, p_sort_keys, p_full_precision);
}
Ref<JSONParseResult> _JSON::parse(const String &p_json) {
diff --git a/core/core_bind.h b/core/core_bind.h
index 3920116ca4..b161effe95 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -32,11 +32,11 @@
#define CORE_BIND_H
#include "core/io/compression.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
@@ -199,14 +199,6 @@ public:
void set_use_file_access_save_and_swap(bool p_enable);
- Dictionary get_date(bool utc) const;
- Dictionary get_time(bool utc) const;
- Dictionary get_datetime(bool utc) const;
- Dictionary get_datetime_from_unix_time(int64_t unix_time_val) const;
- int64_t get_unix_time_from_datetime(Dictionary datetime) const;
- Dictionary get_time_zone_info() const;
- double get_unix_time() const;
-
uint64_t get_static_memory_usage() const;
uint64_t get_static_memory_peak_usage() const;
@@ -237,6 +229,7 @@ public:
String get_system_dir(SystemDir p_dir) const;
String get_user_data_dir() const;
+ String get_external_data_dir() const;
Error set_thread_name(const String &p_name);
Thread::ID get_thread_caller_id() const;
@@ -352,11 +345,11 @@ public:
_Geometry3D() { singleton = this; }
};
-class _File : public Reference {
- GDCLASS(_File, Reference);
+class _File : public RefCounted {
+ GDCLASS(_File, RefCounted);
FileAccess *f = nullptr;
- bool eswap = false;
+ bool big_endian = false;
protected:
static void _bind_methods();
@@ -390,8 +383,8 @@ public:
void seek(int64_t p_position); // Seek to a given position.
void seek_end(int64_t p_position = 0); // Seek from the end of file.
- int64_t get_position() const; // Get position in the file.
- int64_t get_len() const; // Get size of the file.
+ uint64_t get_position() const; // Get position in the file.
+ uint64_t get_length() const; // Get size of the file.
bool eof_reached() const; // Reading passed EOF.
@@ -406,20 +399,20 @@ public:
Variant get_var(bool p_allow_objects = false) const;
- Vector<uint8_t> get_buffer(int p_length) const; // Get an array of bytes.
+ Vector<uint8_t> get_buffer(int64_t p_length) const; // Get an array of bytes.
String get_line() const;
Vector<String> get_csv_line(const String &p_delim = ",") const;
String get_as_text() const;
String get_md5(const String &p_path) const;
String get_sha256(const String &p_path) const;
- /* Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac).
+ /*
+ * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac).
* It's not about the current CPU type but file formats.
- * This flags get reset to false (little endian) on each open.
+ * This flag gets reset to `false` (little endian) on each open.
*/
-
- void set_endian_swap(bool p_swap);
- bool get_endian_swap();
+ void set_big_endian(bool p_big_endian);
+ bool is_big_endian();
Error get_error() const; // Get last error.
@@ -454,8 +447,8 @@ public:
VARIANT_ENUM_CAST(_File::ModeFlags);
VARIANT_ENUM_CAST(_File::CompressionMode);
-class _Directory : public Reference {
- GDCLASS(_Directory, Reference);
+class _Directory : public RefCounted {
+ GDCLASS(_Directory, RefCounted);
DirAccess *d;
bool dir_open = false;
@@ -467,7 +460,7 @@ public:
bool is_open() const;
- Error list_dir_begin(bool p_skip_navigational = false, bool p_skip_hidden = false); // This starts dir listing.
+ Error list_dir_begin(bool p_show_navigational = false, bool p_show_hidden = false); // This starts dir listing.
String get_next();
bool current_is_dir() const;
@@ -486,7 +479,7 @@ public:
bool file_exists(String p_file);
bool dir_exists(String p_dir);
- int get_space_left();
+ uint64_t get_space_left();
Error copy(String p_from, String p_to);
Error rename(String p_from, String p_to);
@@ -524,8 +517,8 @@ public:
~_Marshalls() { singleton = nullptr; }
};
-class _Mutex : public Reference {
- GDCLASS(_Mutex, Reference);
+class _Mutex : public RefCounted {
+ GDCLASS(_Mutex, RefCounted);
Mutex mutex;
static void _bind_methods();
@@ -536,8 +529,8 @@ public:
void unlock();
};
-class _Semaphore : public Reference {
- GDCLASS(_Semaphore, Reference);
+class _Semaphore : public RefCounted {
+ GDCLASS(_Semaphore, RefCounted);
Semaphore semaphore;
static void _bind_methods();
@@ -548,8 +541,8 @@ public:
void post();
};
-class _Thread : public Reference {
- GDCLASS(_Thread, Reference);
+class _Thread : public RefCounted {
+ GDCLASS(_Thread, RefCounted);
protected:
Variant ret;
@@ -665,8 +658,8 @@ public:
class _JSON;
-class JSONParseResult : public Reference {
- GDCLASS(JSONParseResult, Reference);
+class JSONParseResult : public RefCounted {
+ GDCLASS(JSONParseResult, RefCounted);
friend class _JSON;
@@ -705,7 +698,7 @@ protected:
public:
static _JSON *get_singleton() { return singleton; }
- String print(const Variant &p_value, const String &p_indent = "", bool p_sort_keys = false);
+ String print(const Variant &p_value, const String &p_indent = "", bool p_sort_keys = false, bool p_full_precision = false);
Ref<JSONParseResult> parse(const String &p_json);
_JSON() { singleton = this; }
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index f40928350a..7fc09fc3a6 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -161,7 +161,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(KEY_PAGEUP);
BIND_CORE_ENUM_CONSTANT(KEY_PAGEDOWN);
BIND_CORE_ENUM_CONSTANT(KEY_SHIFT);
- BIND_CORE_ENUM_CONSTANT(KEY_CONTROL);
+ BIND_CORE_ENUM_CONSTANT(KEY_CTRL);
BIND_CORE_ENUM_CONSTANT(KEY_META);
BIND_CORE_ENUM_CONSTANT(KEY_ALT);
BIND_CORE_ENUM_CONSTANT(KEY_CAPSLOCK);
@@ -580,10 +580,10 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3I", Variant::VECTOR3I);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM2D", Variant::TRANSFORM2D);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PLANE", Variant::PLANE);
- BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUAT", Variant::QUAT);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUATERNION", Variant::QUATERNION);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_AABB", Variant::AABB);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BASIS", Variant::BASIS);
- BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM", Variant::TRANSFORM);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM3D", Variant::TRANSFORM3D);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_COLOR", Variant::COLOR);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING_NAME", Variant::STRING_NAME);
BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NODE_PATH", Variant::NODE_PATH);
diff --git a/core/crypto/aes_context.h b/core/crypto/aes_context.h
index cc00b18fd2..2f8422f537 100644
--- a/core/crypto/aes_context.h
+++ b/core/crypto/aes_context.h
@@ -32,10 +32,10 @@
#define AES_CONTEXT_H
#include "core/crypto/crypto_core.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class AESContext : public Reference {
- GDCLASS(AESContext, Reference);
+class AESContext : public RefCounted {
+ GDCLASS(AESContext, RefCounted);
public:
enum Mode {
diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h
index 9438fcfea5..a2ccbba58a 100644
--- a/core/crypto/crypto.h
+++ b/core/crypto/crypto.h
@@ -35,7 +35,7 @@
#include "core/io/resource.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
class CryptoKey : public Resource {
GDCLASS(CryptoKey, Resource);
@@ -67,8 +67,8 @@ public:
virtual Error save(String p_path) = 0;
};
-class HMACContext : public Reference {
- GDCLASS(HMACContext, Reference);
+class HMACContext : public RefCounted {
+ GDCLASS(HMACContext, RefCounted);
protected:
static void _bind_methods();
@@ -84,8 +84,8 @@ public:
HMACContext() {}
};
-class Crypto : public Reference {
- GDCLASS(Crypto, Reference);
+class Crypto : public RefCounted {
+ GDCLASS(Crypto, RefCounted);
protected:
static void _bind_methods();
diff --git a/core/crypto/crypto_core.h b/core/crypto/crypto_core.h
index 27b380e838..7a2f4df589 100644
--- a/core/crypto/crypto_core.h
+++ b/core/crypto/crypto_core.h
@@ -31,7 +31,7 @@
#ifndef CRYPTO_CORE_H
#define CRYPTO_CORE_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
class CryptoCore {
public:
diff --git a/core/crypto/hashing_context.h b/core/crypto/hashing_context.h
index 892a48a4e8..31521a147c 100644
--- a/core/crypto/hashing_context.h
+++ b/core/crypto/hashing_context.h
@@ -31,10 +31,10 @@
#ifndef HASHING_CONTEXT_H
#define HASHING_CONTEXT_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class HashingContext : public Reference {
- GDCLASS(HashingContext, Reference);
+class HashingContext : public RefCounted {
+ GDCLASS(HashingContext, RefCounted);
public:
enum HashType {
diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp
index 1dd7e268a5..ab368471e4 100644
--- a/core/debugger/local_debugger.cpp
+++ b/core/debugger/local_debugger.cpp
@@ -183,7 +183,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
print_line("Error: Unknown option " + key);
} else {
// Allow explicit tab character
- String value = key_value.right(value_pos + 1).replace("\\t", "\t");
+ String value = key_value.substr(value_pos + 1).replace("\\t", "\t");
options[key] = value;
}
@@ -348,7 +348,7 @@ Pair<String, int> LocalDebugger::to_breakpoint(const String &p_line) {
}
breakpoint.first = script_debugger->breakpoint_find_source(breakpoint_part.left(last_colon).strip_edges());
- breakpoint.second = breakpoint_part.right(last_colon).strip_edges().to_int();
+ breakpoint.second = breakpoint_part.substr(last_colon).strip_edges().to_int();
return breakpoint;
}
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index 90b0975159..39113eda14 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -152,7 +152,7 @@ void RemoteDebuggerPeerTCP::_read_in() {
}
Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_port) {
- IP_Address ip;
+ IPAddress ip;
if (p_host.is_valid_ip_address()) {
ip = p_host;
} else {
diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h
index 652e2d9d20..8cba53a81c 100644
--- a/core/debugger/remote_debugger_peer.h
+++ b/core/debugger/remote_debugger_peer.h
@@ -32,12 +32,12 @@
#define REMOTE_DEBUGGER_PEER_H
#include "core/io/stream_peer_tcp.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/os/mutex.h"
#include "core/os/thread.h"
#include "core/string/ustring.h"
-class RemoteDebuggerPeer : public Reference {
+class RemoteDebuggerPeer : public RefCounted {
protected:
int max_queued_messages = 4096;
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 2304c05bf8..6e98b596d7 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -85,7 +85,7 @@ Input *Input::get_singleton() {
}
void Input::set_mouse_mode(MouseMode p_mode) {
- ERR_FAIL_INDEX((int)p_mode, 4);
+ ERR_FAIL_INDEX((int)p_mode, 5);
set_mouse_mode_func(p_mode);
}
@@ -138,6 +138,7 @@ void Input::_bind_methods() {
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
+ BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED_HIDDEN);
BIND_ENUM_CONSTANT(CURSOR_ARROW);
BIND_ENUM_CONSTANT(CURSOR_IBEAM);
@@ -1262,16 +1263,16 @@ void Input::parse_mapping(String p_mapping) {
} else if (output[0] == '-') {
output_range = NEGATIVE_HALF_AXIS;
}
- output = output.right(1);
+ output = output.substr(1);
}
JoyAxisRange input_range = FULL_AXIS;
if (input[0] == '+') {
input_range = POSITIVE_HALF_AXIS;
- input = input.right(1);
+ input = input.substr(1);
} else if (input[0] == '-') {
input_range = NEGATIVE_HALF_AXIS;
- input = input.right(1);
+ input = input.substr(1);
}
bool invert_axis = false;
if (input[input.length() - 1] == '~') {
@@ -1299,11 +1300,11 @@ void Input::parse_mapping(String p_mapping) {
switch (input[0]) {
case 'b':
binding.inputType = TYPE_BUTTON;
- binding.input.button = input.right(1).to_int();
+ binding.input.button = input.substr(1).to_int();
break;
case 'a':
binding.inputType = TYPE_AXIS;
- binding.input.axis.axis = input.right(1).to_int();
+ binding.input.axis.axis = input.substr(1).to_int();
binding.input.axis.range = input_range;
binding.input.axis.invert = invert_axis;
break;
@@ -1312,7 +1313,7 @@ void Input::parse_mapping(String p_mapping) {
String(entry[idx] + "\nInvalid hat input: " + input));
binding.inputType = TYPE_HAT;
binding.input.hat.hat = input.substr(1, 1).to_int();
- binding.input.hat.hat_mask = static_cast<HatMask>(input.right(3).to_int());
+ binding.input.hat.hat_mask = static_cast<HatMask>(input.substr(3).to_int());
break;
default:
ERR_CONTINUE_MSG(true, String(entry[idx] + "\nUnrecognised input string: " + input));
diff --git a/core/input/input.h b/core/input/input.h
index 99b45db325..ecb4981b13 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -46,7 +46,8 @@ public:
MOUSE_MODE_VISIBLE,
MOUSE_MODE_HIDDEN,
MOUSE_MODE_CAPTURED,
- MOUSE_MODE_CONFINED
+ MOUSE_MODE_CONFINED,
+ MOUSE_MODE_CONFINED_HIDDEN,
};
#undef CursorShape
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 99cc51b95e..9c1cf15342 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -147,66 +147,66 @@ bool InputEventWithModifiers::is_storing_command() const {
return store_command;
}
-void InputEventWithModifiers::set_shift(bool p_enabled) {
- shift = p_enabled;
+void InputEventWithModifiers::set_shift_pressed(bool p_enabled) {
+ shift_pressed = p_enabled;
}
-bool InputEventWithModifiers::get_shift() const {
- return shift;
+bool InputEventWithModifiers::is_shift_pressed() const {
+ return shift_pressed;
}
-void InputEventWithModifiers::set_alt(bool p_enabled) {
- alt = p_enabled;
+void InputEventWithModifiers::set_alt_pressed(bool p_enabled) {
+ alt_pressed = p_enabled;
}
-bool InputEventWithModifiers::get_alt() const {
- return alt;
+bool InputEventWithModifiers::is_alt_pressed() const {
+ return alt_pressed;
}
-void InputEventWithModifiers::set_control(bool p_enabled) {
- control = p_enabled;
+void InputEventWithModifiers::set_ctrl_pressed(bool p_enabled) {
+ ctrl_pressed = p_enabled;
}
-bool InputEventWithModifiers::get_control() const {
- return control;
+bool InputEventWithModifiers::is_ctrl_pressed() const {
+ return ctrl_pressed;
}
-void InputEventWithModifiers::set_metakey(bool p_enabled) {
- meta = p_enabled;
+void InputEventWithModifiers::set_meta_pressed(bool p_enabled) {
+ meta_pressed = p_enabled;
}
-bool InputEventWithModifiers::get_metakey() const {
- return meta;
+bool InputEventWithModifiers::is_meta_pressed() const {
+ return meta_pressed;
}
-void InputEventWithModifiers::set_command(bool p_enabled) {
- command = p_enabled;
+void InputEventWithModifiers::set_command_pressed(bool p_enabled) {
+ command_pressed = p_enabled;
}
-bool InputEventWithModifiers::get_command() const {
- return command;
+bool InputEventWithModifiers::is_command_pressed() const {
+ return command_pressed;
}
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());
+ set_alt_pressed(event->is_alt_pressed());
+ set_shift_pressed(event->is_shift_pressed());
+ set_ctrl_pressed(event->is_ctrl_pressed());
+ set_meta_pressed(event->is_meta_pressed());
}
String InputEventWithModifiers::as_text() const {
Vector<String> mod_names;
- if (get_control()) {
- mod_names.push_back(find_keycode_name(KEY_CONTROL));
+ if (is_ctrl_pressed()) {
+ mod_names.push_back(find_keycode_name(KEY_CTRL));
}
- if (get_shift()) {
+ if (is_shift_pressed()) {
mod_names.push_back(find_keycode_name(KEY_SHIFT));
}
- if (get_alt()) {
+ if (is_alt_pressed()) {
mod_names.push_back(find_keycode_name(KEY_ALT));
}
- if (get_metakey()) {
+ if (is_meta_pressed()) {
mod_names.push_back(find_keycode_name(KEY_META));
}
@@ -225,27 +225,27 @@ void InputEventWithModifiers::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_store_command", "enable"), &InputEventWithModifiers::set_store_command);
ClassDB::bind_method(D_METHOD("is_storing_command"), &InputEventWithModifiers::is_storing_command);
- 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_alt_pressed", "pressed"), &InputEventWithModifiers::set_alt_pressed);
+ ClassDB::bind_method(D_METHOD("is_alt_pressed"), &InputEventWithModifiers::is_alt_pressed);
- 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_shift_pressed", "pressed"), &InputEventWithModifiers::set_shift_pressed);
+ ClassDB::bind_method(D_METHOD("is_shift_pressed"), &InputEventWithModifiers::is_shift_pressed);
- 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_ctrl_pressed", "pressed"), &InputEventWithModifiers::set_ctrl_pressed);
+ ClassDB::bind_method(D_METHOD("is_ctrl_pressed"), &InputEventWithModifiers::is_ctrl_pressed);
- 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_meta_pressed", "pressed"), &InputEventWithModifiers::set_meta_pressed);
+ ClassDB::bind_method(D_METHOD("is_meta_pressed"), &InputEventWithModifiers::is_meta_pressed);
- ClassDB::bind_method(D_METHOD("set_command", "enable"), &InputEventWithModifiers::set_command);
- ClassDB::bind_method(D_METHOD("get_command"), &InputEventWithModifiers::get_command);
+ ClassDB::bind_method(D_METHOD("set_command_pressed", "pressed"), &InputEventWithModifiers::set_command_pressed);
+ ClassDB::bind_method(D_METHOD("is_command_pressed"), &InputEventWithModifiers::is_command_pressed);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "store_command"), "set_store_command", "is_storing_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");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alt_pressed"), "set_alt_pressed", "is_alt_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shift_pressed"), "set_shift_pressed", "is_shift_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ctrl_pressed"), "set_ctrl_pressed", "is_ctrl_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_pressed"), "set_meta_pressed", "is_meta_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command_pressed"), "set_command_pressed", "is_command_pressed");
}
void InputEventWithModifiers::_validate_property(PropertyInfo &property) const {
@@ -253,18 +253,18 @@ void InputEventWithModifiers::_validate_property(PropertyInfo &property) const {
// If we only want to Store "Command".
#ifdef APPLE_STYLE_KEYS
// Don't store "Meta" on Mac.
- if (property.name == "meta") {
+ if (property.name == "meta_pressed") {
property.usage ^= PROPERTY_USAGE_STORAGE;
}
#else
- // Don't store "Control".
- if (property.name == "control") {
+ // Don't store "Ctrl".
+ if (property.name == "ctrl_pressed") {
property.usage ^= PROPERTY_USAGE_STORAGE;
}
#endif
} else {
- // We don't want to store command, only control or meta (on mac).
- if (property.name == "command") {
+ // We don't want to store command, only ctrl or meta (on mac).
+ if (property.name == "command_pressed") {
property.usage ^= PROPERTY_USAGE_STORAGE;
}
}
@@ -314,16 +314,16 @@ bool InputEventKey::is_echo() const {
uint32_t InputEventKey::get_keycode_with_modifiers() const {
uint32_t sc = keycode;
- if (get_control()) {
+ if (is_ctrl_pressed()) {
sc |= KEY_MASK_CTRL;
}
- if (get_alt()) {
+ if (is_alt_pressed()) {
sc |= KEY_MASK_ALT;
}
- if (get_shift()) {
+ if (is_shift_pressed()) {
sc |= KEY_MASK_SHIFT;
}
- if (get_metakey()) {
+ if (is_meta_pressed()) {
sc |= KEY_MASK_META;
}
@@ -332,16 +332,16 @@ uint32_t InputEventKey::get_keycode_with_modifiers() const {
uint32_t InputEventKey::get_physical_keycode_with_modifiers() const {
uint32_t sc = physical_keycode;
- if (get_control()) {
+ if (is_ctrl_pressed()) {
sc |= KEY_MASK_CTRL;
}
- if (get_alt()) {
+ if (is_alt_pressed()) {
sc |= KEY_MASK_ALT;
}
- if (get_shift()) {
+ if (is_shift_pressed()) {
sc |= KEY_MASK_SHIFT;
}
- if (get_metakey()) {
+ if (is_meta_pressed()) {
sc |= KEY_MASK_META;
}
@@ -372,16 +372,16 @@ String InputEventKey::to_string() {
String kc = "";
String physical = "false";
if (keycode == 0) {
- kc = itos(physical_keycode) + " " + keycode_get_string(physical_keycode);
+ kc = itos(physical_keycode) + " (" + keycode_get_string(physical_keycode) + ")";
physical = "true";
} else {
- kc = itos(keycode) + " " + keycode_get_string(keycode);
+ kc = itos(keycode) + " (" + keycode_get_string(keycode) + ")";
}
String mods = InputEventWithModifiers::as_text();
- mods = mods == "" ? TTR("None") : mods;
+ mods = mods == "" ? TTR("none") : mods;
- return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", kc, mods, physical, p, e);
+ return vformat("InputEventKey: keycode=%s, mods=%s, physical=%s, pressed=%s, echo=%s", kc, mods, physical, p, e);
}
Ref<InputEventKey> InputEventKey::create_reference(uint32_t p_keycode) {
@@ -391,19 +391,19 @@ Ref<InputEventKey> InputEventKey::create_reference(uint32_t p_keycode) {
ie->set_unicode(p_keycode & KEY_CODE_MASK);
if (p_keycode & KEY_MASK_SHIFT) {
- ie->set_shift(true);
+ ie->set_shift_pressed(true);
}
if (p_keycode & KEY_MASK_ALT) {
- ie->set_alt(true);
+ ie->set_alt_pressed(true);
}
if (p_keycode & KEY_MASK_CTRL) {
- ie->set_control(true);
+ ie->set_ctrl_pressed(true);
}
if (p_keycode & KEY_MASK_CMD) {
- ie->set_command(true);
+ ie->set_command_pressed(true);
}
if (p_keycode & KEY_MASK_META) {
- ie->set_metakey(true);
+ ie->set_meta_pressed(true);
}
return ie;
@@ -545,12 +545,12 @@ bool InputEventMouseButton::is_pressed() const {
return pressed;
}
-void InputEventMouseButton::set_doubleclick(bool p_doubleclick) {
- doubleclick = p_doubleclick;
+void InputEventMouseButton::set_double_click(bool p_double_click) {
+ double_click = p_double_click;
}
-bool InputEventMouseButton::is_doubleclick() const {
- return doubleclick;
+bool InputEventMouseButton::is_double_click() const {
+ return double_click;
}
Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
@@ -569,7 +569,7 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co
mb->set_button_mask(get_button_mask());
mb->set_pressed(pressed);
- mb->set_doubleclick(doubleclick);
+ mb->set_double_click(double_click);
mb->set_factor(factor);
mb->set_button_index(button_index);
@@ -636,7 +636,7 @@ String InputEventMouseButton::as_text() const {
}
// Double Click
- if (doubleclick) {
+ if (double_click) {
full_string += " (" + RTR("Double Click") + ")";
}
@@ -645,7 +645,7 @@ String InputEventMouseButton::as_text() const {
String InputEventMouseButton::to_string() {
String p = is_pressed() ? "true" : "false";
- String d = doubleclick ? "true" : "false";
+ String d = double_click ? "true" : "false";
int idx = get_button_index();
String button_string = itos(idx);
@@ -667,11 +667,11 @@ String InputEventMouseButton::to_string() {
}
String mods = InputEventWithModifiers::as_text();
- mods = mods == "" ? TTR("None") : mods;
+ mods = mods == "" ? TTR("none") : mods;
// Work around the fact vformat can only take 5 substitutions but 6 need to be passed.
- String index_and_mods = vformat("button_index=%s mods=%s", button_index, mods);
- return vformat("InputEventMouseButton: %s pressed=%s position=(%s) button_mask=%s doubleclick=%s", index_and_mods, p, String(get_position()), itos(get_button_mask()), d);
+ String index_and_mods = vformat("button_index=%s, mods=%s", button_index, mods);
+ return vformat("InputEventMouseButton: %s, pressed=%s, position=(%s), button_mask=%d, double_click=%s", index_and_mods, p, String(get_position()), get_button_mask(), d);
}
void InputEventMouseButton::_bind_methods() {
@@ -684,13 +684,13 @@ void InputEventMouseButton::_bind_methods() {
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);
+ ClassDB::bind_method(D_METHOD("set_double_click", "double_click"), &InputEventMouseButton::set_double_click);
+ ClassDB::bind_method(D_METHOD("is_double_click"), &InputEventMouseButton::is_double_click);
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");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "double_click"), "set_double_click", "is_double_click");
}
///////////////////////////////////
@@ -780,7 +780,9 @@ String InputEventMouseMotion::to_string() {
break;
}
- return "InputEventMouseMotion : button_mask=" + button_mask_string + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + "), pressure=(" + rtos(get_pressure()) + "), tilt=(" + String(get_tilt()) + ")";
+ // Work around the fact vformat can only take 5 substitutions but 6 need to be passed.
+ String mask_and_position = vformat("button_mask=%s, position=(%s)", button_mask_string, String(get_position()));
+ return vformat("InputEventMouseMotion: %s, relative=(%s), speed=(%s), pressure=%.2f, tilt=(%s)", mask_and_position, String(get_relative()), String(get_speed()), get_pressure(), String(get_tilt()));
}
bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) {
@@ -801,19 +803,19 @@ bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) {
return false;
}
- if (get_shift() != motion->get_shift()) {
+ if (is_shift_pressed() != motion->is_shift_pressed()) {
return false;
}
- if (get_control() != motion->get_control()) {
+ if (is_ctrl_pressed() != motion->is_ctrl_pressed()) {
return false;
}
- if (get_alt() != motion->get_alt()) {
+ if (is_alt_pressed() != motion->is_alt_pressed()) {
return false;
}
- if (get_metakey() != motion->get_metakey()) {
+ if (is_meta_pressed() != motion->is_meta_pressed()) {
return false;
}
@@ -918,11 +920,11 @@ static const char *_joy_axis_descriptions[JOY_AXIS_MAX] = {
String InputEventJoypadMotion::as_text() const {
String desc = axis < JOY_AXIS_MAX ? RTR(_joy_axis_descriptions[axis]) : TTR("Unknown Joypad Axis");
- return vformat(TTR("Joypad Motion on Axis %s (%s) with Value %s"), itos(axis), desc, String(Variant(axis_value)));
+ return vformat(TTR("Joypad Motion on Axis %d (%s) with Value %.2f"), axis, desc, axis_value);
}
String InputEventJoypadMotion::to_string() {
- return "InputEventJoypadMotion : axis=" + itos(axis) + ", axis_value=" + String(Variant(axis_value));
+ return vformat("InputEventJoypadMotion: axis=%d, axis_value=%.2f", axis, axis_value);
}
void InputEventJoypadMotion::_bind_methods() {
@@ -1021,7 +1023,7 @@ static const char *_joy_button_descriptions[JOY_BUTTON_SDL_MAX] = {
String InputEventJoypadButton::as_text() const {
String text = "Joypad Button " + itos(button_index);
- if (button_index < JOY_BUTTON_SDL_MAX) {
+ if (button_index >= 0 && button_index < JOY_BUTTON_SDL_MAX) {
text += vformat(" (%s)", _joy_button_descriptions[button_index]);
}
@@ -1033,7 +1035,8 @@ String InputEventJoypadButton::as_text() const {
}
String InputEventJoypadButton::to_string() {
- return "InputEventJoypadButton : button_index=" + itos(button_index) + ", pressed=" + (pressed ? "true" : "false") + ", pressure=" + String(Variant(pressure));
+ String p = pressed ? "true" : "false";
+ return vformat("InputEventJoypadButton: button_index=%d, pressed=%s, pressure=%.2f", button_index, p, pressure);
}
Ref<InputEventJoypadButton> InputEventJoypadButton::create_reference(int p_btn_index) {
@@ -1104,7 +1107,8 @@ String InputEventScreenTouch::as_text() const {
}
String InputEventScreenTouch::to_string() {
- return "InputEventScreenTouch : index=" + itos(index) + ", pressed=" + (pressed ? "true" : "false") + ", position=(" + String(get_position()) + ")";
+ String p = pressed ? "true" : "false";
+ return vformat("InputEventScreenTouch: index=%d, pressed=%s, position=(%s)", index, p, String(get_position()));
}
void InputEventScreenTouch::_bind_methods() {
@@ -1177,7 +1181,7 @@ String InputEventScreenDrag::as_text() const {
}
String InputEventScreenDrag::to_string() {
- return "InputEventScreenDrag : index=" + itos(index) + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + ")";
+ return vformat("InputEventScreenDrag: index=%d, position=(%s), relative=(%s), speed=(%s)", index, String(get_position()), String(get_relative()), String(get_speed()));
}
void InputEventScreenDrag::_bind_methods() {
@@ -1264,7 +1268,8 @@ String InputEventAction::as_text() const {
}
String InputEventAction::to_string() {
- return "InputEventAction : action=" + action + ", pressed=(" + (pressed ? "true" : "false");
+ String p = pressed ? "true" : "false";
+ return vformat("InputEventAction: action=\"%s\", pressed=%s", action, p);
}
void InputEventAction::_bind_methods() {
@@ -1331,7 +1336,7 @@ String InputEventMagnifyGesture::as_text() const {
}
String InputEventMagnifyGesture::to_string() {
- return "InputEventMagnifyGesture : factor=" + rtos(get_factor()) + ", position=(" + String(get_position()) + ")";
+ return vformat("InputEventMagnifyGesture: factor=%.2f, position=(%s)", factor, String(get_position()));
}
void InputEventMagnifyGesture::_bind_methods() {
@@ -1371,7 +1376,7 @@ String InputEventPanGesture::as_text() const {
}
String InputEventPanGesture::to_string() {
- return "InputEventPanGesture : delta=(" + String(get_delta()) + "), position=(" + String(get_position()) + ")";
+ return vformat("InputEventPanGesture: delta=(%s), position=(%s)", String(get_delta()), String(get_position()));
}
void InputEventPanGesture::_bind_methods() {
@@ -1452,7 +1457,7 @@ String InputEventMIDI::as_text() const {
}
String InputEventMIDI::to_string() {
- return vformat("InputEvenMIDI: channel=%s message=%s pitch=%s velocity=%s pressure=%s", itos(channel), itos(message), itos(pitch), itos(velocity), itos(pressure));
+ return vformat("InputEventMIDI: channel=%d, message=%d, pitch=%d, velocity=%d, pressure=%d", channel, message, pitch, velocity, pressure);
}
void InputEventMIDI::_bind_methods() {
diff --git a/core/input/input_event.h b/core/input/input_event.h
index a1e7df5969..eed0d79326 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -33,7 +33,6 @@
#include "core/io/resource.h"
#include "core/math/transform_2d.h"
-#include "core/os/copymem.h"
#include "core/string/ustring.h"
#include "core/typedefs.h"
@@ -171,21 +170,21 @@ class InputEventWithModifiers : public InputEventFromWindow {
bool store_command = true;
- bool shift = false;
- bool alt = false;
+ bool shift_pressed = false;
+ bool alt_pressed = false;
#ifdef APPLE_STYLE_KEYS
union {
- bool command;
- bool meta = false; //< windows/mac key
+ bool command_pressed;
+ bool meta_pressed = false; //< windows/mac key
};
- bool control = false;
+ bool ctrl_pressed = false;
#else
union {
- bool command; //< windows/mac key
- bool control = false;
+ bool command_pressed; //< windows/mac key
+ bool ctrl_pressed = false;
};
- bool meta = false; //< windows/mac key
+ bool meta_pressed = false; //< windows/mac key
#endif
protected:
@@ -196,20 +195,20 @@ public:
void set_store_command(bool p_enabled);
bool is_storing_command() const;
- void set_shift(bool p_enabled);
- bool get_shift() const;
+ void set_shift_pressed(bool p_pressed);
+ bool is_shift_pressed() const;
- void set_alt(bool p_enabled);
- bool get_alt() const;
+ void set_alt_pressed(bool p_pressed);
+ bool is_alt_pressed() const;
- void set_control(bool p_enabled);
- bool get_control() const;
+ void set_ctrl_pressed(bool p_pressed);
+ bool is_ctrl_pressed() const;
- void set_metakey(bool p_enabled);
- bool get_metakey() const;
+ void set_meta_pressed(bool p_pressed);
+ bool is_meta_pressed() const;
- void set_command(bool p_enabled);
- bool get_command() const;
+ void set_command_pressed(bool p_pressed);
+ bool is_command_pressed() const;
void set_modifiers_from_event(const InputEventWithModifiers *event);
@@ -295,7 +294,7 @@ class InputEventMouseButton : public InputEventMouse {
float factor = 1;
int button_index = 0;
bool pressed = false; //otherwise released
- bool doubleclick = false; //last even less than doubleclick time
+ bool double_click = false; //last even less than double click time
protected:
static void _bind_methods();
@@ -310,8 +309,8 @@ public:
void set_pressed(bool p_pressed);
virtual bool is_pressed() const override;
- void set_doubleclick(bool p_doubleclick);
- bool is_doubleclick() const;
+ void set_double_click(bool p_double_click);
+ bool is_double_click() const;
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override;
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index aab4e6593c..c43fd64561 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -166,7 +166,7 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent
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), _suggest_actions(p_action));
if (_find_event(input_map[p_action], p_event, true)) {
- return; // Already addded.
+ return; // Already added.
}
input_map[p_action].inputs.push_back(p_event);
@@ -353,7 +353,9 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_text_scroll_down", TTRC("Scroll Down") },
{ "ui_text_scroll_down.OSX", TTRC("Scroll Down") },
{ "ui_text_select_all", TTRC("Select All") },
+ { "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") },
{ "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
+ { "ui_text_submit", TTRC("Text Submitted") },
{ "ui_graph_duplicate", TTRC("Duplicate Nodes") },
{ "ui_graph_delete", TTRC("Delete Nodes") },
{ "ui_filedialog_up_one_level", TTRC("Go Up One Level") },
@@ -473,9 +475,14 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_completion_query", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(KEY_TAB));
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER));
+ inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER));
default_builtin_cache.insert("ui_text_completion_accept", inputs);
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB));
+ default_builtin_cache.insert("ui_text_completion_replace", inputs);
+
// Newlines
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(KEY_ENTER));
@@ -505,6 +512,7 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
// Text Backspace and Delete
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE));
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE | KEY_MASK_SHIFT));
default_builtin_cache.insert("ui_text_backspace", inputs);
inputs = List<Ref<InputEvent>>();
@@ -650,6 +658,10 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_select_all", inputs);
inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_D | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_select_word_under_caret", inputs);
+
+ inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(KEY_INSERT));
default_builtin_cache.insert("ui_text_toggle_insert_mode", inputs);
@@ -657,6 +669,11 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(KEY_MENU));
default_builtin_cache.insert("ui_menu", inputs);
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER));
+ inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER));
+ default_builtin_cache.insert("ui_text_submit", inputs);
+
// ///// UI Graph Shortcuts /////
inputs = List<Ref<InputEvent>>();
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index 980234cbfc..6de626db99 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -32,7 +32,6 @@
#include "core/config/project_settings.h"
#include "core/io/zip_io.h"
-#include "core/os/copymem.h"
#include "thirdparty/misc/fastlz.h"
@@ -44,8 +43,8 @@ int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,
case MODE_FASTLZ: {
if (p_src_size < 16) {
uint8_t src[16];
- zeromem(&src[p_src_size], 16 - p_src_size);
- copymem(src, p_src, p_src_size);
+ memset(&src[p_src_size], 0, 16 - p_src_size);
+ memcpy(src, p_src, p_src_size);
return fastlz_compress(src, 16, p_dst);
} else {
return fastlz_compress(p_src, p_src_size, p_dst);
@@ -136,7 +135,7 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p
if (p_dst_max_size < 16) {
uint8_t dst[16];
ret_size = fastlz_decompress(p_src, p_src_size, dst, 16);
- copymem(p_dst, dst, p_dst_max_size);
+ memcpy(p_dst, dst, p_dst_max_size);
} else {
ret_size = fastlz_decompress(p_src, p_src_size, p_dst, p_dst_max_size);
}
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 1b28257c60..dbba43ace5 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -31,13 +31,13 @@
#ifndef CONFIG_FILE_H
#define CONFIG_FILE_H
-#include "core/object/reference.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
+#include "core/object/ref_counted.h"
#include "core/templates/ordered_hash_map.h"
#include "core/variant/variant_parser.h"
-class ConfigFile : public Reference {
- GDCLASS(ConfigFile, Reference);
+class ConfigFile : public RefCounted {
+ GDCLASS(ConfigFile, RefCounted);
OrderedHashMap<String, OrderedHashMap<String, Variant>> values;
diff --git a/core/os/dir_access.cpp b/core/io/dir_access.cpp
index b7c3a17ba9..dfba00067f 100644
--- a/core/os/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -31,7 +31,7 @@
#include "dir_access.h"
#include "core/config/project_settings.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/memory.h"
#include "core/os/os.h"
@@ -331,7 +331,7 @@ public:
}
};
-Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags) {
+Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links) {
List<String> dirs;
String curdir = get_current_dir();
@@ -339,7 +339,9 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag
String n = get_next();
while (n != String()) {
if (n != "." && n != "..") {
- if (current_is_dir()) {
+ if (p_copy_links && is_link(get_current_dir().plus_file(n))) {
+ create_link(read_link(get_current_dir().plus_file(n)), p_to + n);
+ } else if (current_is_dir()) {
dirs.push_back(n);
} else {
const String &rel_path = n;
@@ -371,7 +373,7 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag
Error err = change_dir(E->get());
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot change current directory to '" + E->get() + "'.");
- err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags);
+ err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags, p_copy_links);
if (err) {
change_dir("..");
ERR_FAIL_V_MSG(err, "Failed to copy recursively.");
@@ -383,7 +385,7 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag
return OK;
}
-Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags) {
+Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_copy_links) {
ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist.");
DirAccess *target_da = DirAccess::create_for_path(p_to);
@@ -402,7 +404,7 @@ Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags) {
}
DirChanger dir_changer(this, p_from);
- Error err = _copy_dir(target_da, p_to, p_chmod_flags);
+ Error err = _copy_dir(target_da, p_to, p_chmod_flags, p_copy_links);
memdelete(target_da);
return err;
diff --git a/core/os/dir_access.h b/core/io/dir_access.h
index 7f0bcd372d..16154a4850 100644
--- a/core/os/dir_access.h
+++ b/core/io/dir_access.h
@@ -50,7 +50,7 @@ private:
AccessType _access_type = ACCESS_FILESYSTEM;
static CreateFunc create_func[ACCESS_MAX]; ///< set this to instance a filesystem object
- Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags);
+ Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links);
protected:
String _get_root_path() const;
@@ -87,13 +87,17 @@ public:
virtual bool is_readable(String p_dir) { return true; };
virtual bool is_writable(String p_dir) { return true; };
static bool exists(String p_dir);
- virtual size_t get_space_left() = 0;
+ virtual uint64_t get_space_left() = 0;
- Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1);
+ Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1, bool p_copy_links = false);
virtual Error copy(String p_from, String p_to, int p_chmod_flags = -1);
virtual Error rename(String p_from, String p_to) = 0;
virtual Error remove(String p_name) = 0;
+ virtual bool is_link(String p_file) = 0;
+ virtual String read_link(String p_file) = 0;
+ virtual Error create_link(String p_source, String p_target) = 0;
+
// Meant for editor code when we want to quickly remove a file without custom
// handling (e.g. removing a cache file).
static void remove_file_or_error(String p_path) {
diff --git a/core/io/dtls_server.cpp b/core/io/dtls_server.cpp
index 288b2efe0e..655fb18535 100644
--- a/core/io/dtls_server.cpp
+++ b/core/io/dtls_server.cpp
@@ -31,7 +31,7 @@
#include "dtls_server.h"
#include "core/config/project_settings.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
DTLSServer *(*DTLSServer::_create)() = nullptr;
bool DTLSServer::available = false;
diff --git a/core/io/dtls_server.h b/core/io/dtls_server.h
index 92b6caf508..02a32533e1 100644
--- a/core/io/dtls_server.h
+++ b/core/io/dtls_server.h
@@ -34,8 +34,8 @@
#include "core/io/net_socket.h"
#include "core/io/packet_peer_dtls.h"
-class DTLSServer : public Reference {
- GDCLASS(DTLSServer, Reference);
+class DTLSServer : public RefCounted {
+ GDCLASS(DTLSServer, RefCounted);
protected:
static DTLSServer *(*_create)();
diff --git a/core/os/file_access.cpp b/core/io/file_access.cpp
index ad234c2d49..d21c0bd9a2 100644
--- a/core/os/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -164,7 +164,7 @@ uint16_t FileAccess::get_16() const {
a = get_8();
b = get_8();
- if (endian_swap) {
+ if (big_endian) {
SWAP(a, b);
}
@@ -182,7 +182,7 @@ uint32_t FileAccess::get_32() const {
a = get_16();
b = get_16();
- if (endian_swap) {
+ if (big_endian) {
SWAP(a, b);
}
@@ -200,7 +200,7 @@ uint64_t FileAccess::get_64() const {
a = get_32();
b = get_32();
- if (endian_swap) {
+ if (big_endian) {
SWAP(a, b);
}
@@ -367,10 +367,10 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
return strings;
}
-int FileAccess::get_buffer(uint8_t *p_dst, int p_length) const {
+uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(p_length < 0, -1);
- int i = 0;
+
+ uint64_t i = 0;
for (i = 0; i < p_length && !eof_reached(); i++) {
p_dst[i] = get_8();
}
@@ -380,11 +380,11 @@ int FileAccess::get_buffer(uint8_t *p_dst, int p_length) const {
String FileAccess::get_as_utf8_string() const {
Vector<uint8_t> sourcef;
- int len = get_len();
+ uint64_t len = get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
- int r = get_buffer(w, len);
+ uint64_t r = get_buffer(w, len);
ERR_FAIL_COND_V(r != len, String());
w[len] = 0;
@@ -401,7 +401,7 @@ void FileAccess::store_16(uint16_t p_dest) {
a = p_dest & 0xFF;
b = p_dest >> 8;
- if (endian_swap) {
+ if (big_endian) {
SWAP(a, b);
}
@@ -415,7 +415,7 @@ void FileAccess::store_32(uint32_t p_dest) {
a = p_dest & 0xFFFF;
b = p_dest >> 16;
- if (endian_swap) {
+ if (big_endian) {
SWAP(a, b);
}
@@ -429,7 +429,7 @@ void FileAccess::store_64(uint64_t p_dest) {
a = p_dest & 0xFFFFFFFF;
b = p_dest >> 32;
- if (endian_swap) {
+ if (big_endian) {
SWAP(a, b);
}
@@ -550,8 +550,9 @@ void FileAccess::store_csv_line(const Vector<String> &p_values, const String &p_
store_line(line);
}
-void FileAccess::store_buffer(const uint8_t *p_src, int p_length) {
- for (int i = 0; i < p_length; i++) {
+void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
+ ERR_FAIL_COND(!p_src && p_length > 0);
+ for (uint64_t i = 0; i < p_length; i++) {
store_8(p_src[i]);
}
}
@@ -565,7 +566,7 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_err
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Can't open file from path '" + String(p_path) + "'.");
}
Vector<uint8_t> data;
- data.resize(f->get_len());
+ data.resize(f->get_length());
f->get_buffer(data.ptrw(), data.size());
memdelete(f);
return data;
@@ -601,7 +602,7 @@ String FileAccess::get_md5(const String &p_file) {
unsigned char step[32768];
while (true) {
- int br = f->get_buffer(step, 32768);
+ uint64_t br = f->get_buffer(step, 32768);
if (br > 0) {
ctx.update(step, br);
}
@@ -629,7 +630,7 @@ String FileAccess::get_multiple_md5(const Vector<String> &p_file) {
unsigned char step[32768];
while (true) {
- int br = f->get_buffer(step, 32768);
+ uint64_t br = f->get_buffer(step, 32768);
if (br > 0) {
ctx.update(step, br);
}
@@ -658,7 +659,7 @@ String FileAccess::get_sha256(const String &p_file) {
unsigned char step[32768];
while (true) {
- int br = f->get_buffer(step, 32768);
+ uint64_t br = f->get_buffer(step, 32768);
if (br > 0) {
ctx.update(step, br);
}
diff --git a/core/os/file_access.h b/core/io/file_access.h
index 1c78204c1d..5804aa2c47 100644
--- a/core/os/file_access.h
+++ b/core/io/file_access.h
@@ -52,7 +52,7 @@ public:
typedef void (*FileCloseFailNotify)(const String &);
typedef FileAccess *(*CreateFunc)();
- bool endian_swap = false;
+ bool big_endian = false;
bool real_is_double = false;
virtual uint32_t _get_unix_permissions(const String &p_file) = 0;
@@ -93,10 +93,10 @@ public:
virtual String get_path() const { return ""; } /// returns the path for the current open file
virtual String get_path_absolute() const { return ""; } /// returns the absolute path for the current open file
- virtual void seek(size_t p_position) = 0; ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0) = 0; ///< seek from the end of file
- virtual size_t get_position() const = 0; ///< get position in the file
- virtual size_t get_len() const = 0; ///< get size of the file
+ virtual void seek(uint64_t p_position) = 0; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) = 0; ///< seek from the end of file with negative offset
+ virtual uint64_t get_position() const = 0; ///< get position in the file
+ virtual uint64_t get_length() const = 0; ///< get size of the file
virtual bool eof_reached() const = 0; ///< reading passed EOF
@@ -109,19 +109,19 @@ public:
virtual double get_double() const;
virtual real_t get_real() const;
- virtual int get_buffer(uint8_t *p_dst, int p_length) const; ///< get an array of bytes
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
virtual String get_line() const;
virtual String get_token() const;
virtual Vector<String> get_csv_line(const String &p_delim = ",") const;
virtual String get_as_utf8_string() const;
- /**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac)
+ /**
+ * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac)
* It's not about the current CPU type but file formats.
- * this flags get reset to false (little endian) on each open
+ * This flag gets reset to `false` (little endian) on each open.
*/
-
- virtual void set_endian_swap(bool p_swap) { endian_swap = p_swap; }
- inline bool get_endian_swap() const { return endian_swap; }
+ virtual void set_big_endian(bool p_big_endian) { big_endian = p_big_endian; }
+ inline bool is_big_endian() const { return big_endian; }
virtual Error get_error() const = 0; ///< get last error
@@ -142,7 +142,7 @@ public:
virtual void store_pascal_string(const String &p_string);
virtual String get_pascal_string();
- virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
virtual bool file_exists(const String &p_name) = 0; ///< return true if a file exists
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index b2440629e3..e54c947340 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -32,7 +32,7 @@
#include "core/string/print_string.h"
-void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_mode, int p_block_size) {
+void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_mode, uint32_t p_block_size) {
magic = p_magic.ascii().get_data();
if (magic.length() > 4) {
magic = magic.substr(0, 4);
@@ -67,10 +67,10 @@ Error FileAccessCompressed::open_after_magic(FileAccess *p_base) {
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();
- int bc = (read_total / block_size) + 1;
- int acc_ofs = f->get_position() + bc * 4;
- int max_bs = 0;
- for (int i = 0; i < bc; i++) {
+ uint32_t bc = (read_total / block_size) + 1;
+ uint64_t acc_ofs = f->get_position() + bc * 4;
+ uint32_t max_bs = 0;
+ for (uint32_t i = 0; i < bc; i++) {
ReadBlock rb;
rb.offset = acc_ofs;
rb.csize = f->get_32();
@@ -148,15 +148,15 @@ void FileAccessCompressed::close() {
f->store_32(cmode); //write compression mode 4
f->store_32(block_size); //write block size 4
f->store_32(write_max); //max amount of data written 4
- int bc = (write_max / block_size) + 1;
+ uint32_t bc = (write_max / block_size) + 1;
- for (int i = 0; i < bc; i++) {
+ for (uint32_t i = 0; i < bc; i++) {
f->store_32(0); //compressed sizes, will update later
}
Vector<int> block_sizes;
- for (int i = 0; i < bc; i++) {
- int bl = i == (bc - 1) ? write_max % block_size : block_size;
+ for (uint32_t i = 0; i < bc; i++) {
+ uint32_t bl = i == (bc - 1) ? write_max % block_size : block_size;
uint8_t *bp = &write_ptr[i * block_size];
Vector<uint8_t> cblock;
@@ -168,7 +168,7 @@ void FileAccessCompressed::close() {
}
f->seek(16); //ok write block sizes
- for (int i = 0; i < bc; i++) {
+ for (uint32_t i = 0; i < bc; i++) {
f->store_32(block_sizes[i]);
}
f->seek_end();
@@ -190,8 +190,9 @@ bool FileAccessCompressed::is_open() const {
return f != nullptr;
}
-void FileAccessCompressed::seek(size_t p_position) {
+void FileAccessCompressed::seek(uint64_t p_position) {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+
if (writing) {
ERR_FAIL_COND(p_position > write_max);
@@ -204,7 +205,7 @@ void FileAccessCompressed::seek(size_t p_position) {
} else {
at_end = false;
read_eof = false;
- int block_idx = p_position / block_size;
+ uint32_t block_idx = p_position / block_size;
if (block_idx != read_block) {
read_block = block_idx;
f->seek(read_blocks[read_block].offset);
@@ -227,7 +228,7 @@ void FileAccessCompressed::seek_end(int64_t p_position) {
}
}
-size_t FileAccessCompressed::get_position() const {
+uint64_t FileAccessCompressed::get_position() const {
ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
if (writing) {
return write_pos;
@@ -236,7 +237,7 @@ size_t FileAccessCompressed::get_position() const {
}
}
-size_t FileAccessCompressed::get_len() const {
+uint64_t FileAccessCompressed::get_length() const {
ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
if (writing) {
return write_max;
@@ -285,9 +286,8 @@ uint8_t FileAccessCompressed::get_8() const {
return ret;
}
-int FileAccessCompressed::get_buffer(uint8_t *p_dst, int p_length) const {
+uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use.");
ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode.");
@@ -296,7 +296,7 @@ int FileAccessCompressed::get_buffer(uint8_t *p_dst, int p_length) const {
return 0;
}
- for (int i = 0; i < p_length; i++) {
+ for (uint64_t i = 0; i < p_length; i++) {
p_dst[i] = read_ptr[read_pos];
read_pos++;
if (read_pos >= read_block_size) {
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index 118d05ea57..3389e020e3 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -32,39 +32,39 @@
#define FILE_ACCESS_COMPRESSED_H
#include "core/io/compression.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
class FileAccessCompressed : public FileAccess {
Compression::Mode cmode = Compression::MODE_ZSTD;
bool writing = false;
- uint32_t write_pos = 0;
+ uint64_t write_pos = 0;
uint8_t *write_ptr = nullptr;
uint32_t write_buffer_size = 0;
- uint32_t write_max = 0;
+ uint64_t write_max = 0;
uint32_t block_size = 0;
mutable bool read_eof = false;
mutable bool at_end = false;
struct ReadBlock {
- int csize;
- int offset;
+ uint32_t csize;
+ uint64_t offset;
};
mutable Vector<uint8_t> comp_buffer;
uint8_t *read_ptr = nullptr;
- mutable int read_block = 0;
- int read_block_count = 0;
- mutable int read_block_size = 0;
- mutable int read_pos = 0;
+ mutable uint32_t read_block = 0;
+ uint32_t read_block_count = 0;
+ mutable uint32_t read_block_size = 0;
+ mutable uint64_t read_pos = 0;
Vector<ReadBlock> read_blocks;
- uint32_t read_total = 0;
+ uint64_t read_total = 0;
String magic = "GCMP";
mutable Vector<uint8_t> buffer;
FileAccess *f = nullptr;
public:
- void configure(const String &p_magic, Compression::Mode p_mode = Compression::MODE_ZSTD, int p_block_size = 4096);
+ void configure(const String &p_magic, Compression::Mode p_mode = Compression::MODE_ZSTD, uint32_t p_block_size = 4096);
Error open_after_magic(FileAccess *p_base);
@@ -72,15 +72,15 @@ public:
virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
- virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek(uint64_t p_position); ///< seek to a given position
virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual size_t get_position() const; ///< get position in the file
- virtual size_t get_len() const; ///< get size of the file
+ virtual uint64_t get_position() const; ///< get position in the file
+ virtual uint64_t get_length() const; ///< get size of the file
virtual bool eof_reached() const; ///< reading passed EOF
virtual uint8_t get_8() const; ///< get a byte
- virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
virtual Error get_error() const; ///< get last error
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 8ace897f18..9e316291e8 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -31,7 +31,6 @@
#include "file_access_encrypted.h"
#include "core/crypto/crypto_core.h"
-#include "core/os/copymem.h"
#include "core/string/print_string.h"
#include "core/variant/variant.h"
@@ -70,14 +69,14 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8
}
base = p_base->get_position();
- ERR_FAIL_COND_V(p_base->get_len() < base + length, ERR_FILE_CORRUPT);
- uint32_t ds = length;
+ ERR_FAIL_COND_V(p_base->get_length() < base + length, ERR_FILE_CORRUPT);
+ uint64_t ds = length;
if (ds % 16) {
ds += 16 - (ds % 16);
}
data.resize(ds);
- uint32_t blen = p_base->get_buffer(data.ptrw(), ds);
+ uint64_t blen = p_base->get_buffer(data.ptrw(), ds);
ERR_FAIL_COND_V(blen != ds, ERR_FILE_CORRUPT);
{
@@ -142,7 +141,7 @@ void FileAccessEncrypted::release() {
void FileAccessEncrypted::_release() {
if (writing) {
Vector<uint8_t> compressed;
- size_t len = data.size();
+ uint64_t len = data.size();
if (len % 16) {
len += 16 - (len % 16);
}
@@ -151,7 +150,7 @@ void FileAccessEncrypted::_release() {
ERR_FAIL_COND(CryptoCore::md5(data.ptr(), data.size(), hash) != OK); // Bug?
compressed.resize(len);
- zeromem(compressed.ptrw(), len);
+ memset(compressed.ptrw(), 0, len);
for (int i = 0; i < data.size(); i++) {
compressed.write[i] = data[i];
}
@@ -199,9 +198,9 @@ String FileAccessEncrypted::get_path_absolute() const {
}
}
-void FileAccessEncrypted::seek(size_t p_position) {
- if (p_position > (size_t)data.size()) {
- p_position = data.size();
+void FileAccessEncrypted::seek(uint64_t p_position) {
+ if (p_position > get_length()) {
+ p_position = get_length();
}
pos = p_position;
@@ -209,14 +208,14 @@ void FileAccessEncrypted::seek(size_t p_position) {
}
void FileAccessEncrypted::seek_end(int64_t p_position) {
- seek(data.size() + p_position);
+ seek(get_length() + p_position);
}
-size_t FileAccessEncrypted::get_position() const {
+uint64_t FileAccessEncrypted::get_position() const {
return pos;
}
-size_t FileAccessEncrypted::get_len() const {
+uint64_t FileAccessEncrypted::get_length() const {
return data.size();
}
@@ -226,7 +225,7 @@ bool FileAccessEncrypted::eof_reached() const {
uint8_t FileAccessEncrypted::get_8() const {
ERR_FAIL_COND_V_MSG(writing, 0, "File has not been opened in read mode.");
- if (pos >= data.size()) {
+ if (pos >= get_length()) {
eofed = true;
return 0;
}
@@ -236,13 +235,12 @@ uint8_t FileAccessEncrypted::get_8() const {
return b;
}
-int FileAccessEncrypted::get_buffer(uint8_t *p_dst, int p_length) const {
+uint64_t FileAccessEncrypted::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode.");
- int to_copy = MIN(p_length, data.size() - pos);
- for (int i = 0; i < to_copy; i++) {
+ uint64_t to_copy = MIN(p_length, get_length() - pos);
+ for (uint64_t i = 0; i < to_copy; i++) {
p_dst[i] = data[pos++];
}
@@ -257,16 +255,17 @@ Error FileAccessEncrypted::get_error() const {
return eofed ? ERR_FILE_EOF : OK;
}
-void FileAccessEncrypted::store_buffer(const uint8_t *p_src, int p_length) {
+void FileAccessEncrypted::store_buffer(const uint8_t *p_src, uint64_t p_length) {
ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
+ ERR_FAIL_COND(!p_src && p_length > 0);
- if (pos < data.size()) {
- for (int i = 0; i < p_length; i++) {
+ if (pos < get_length()) {
+ for (uint64_t i = 0; i < p_length; i++) {
store_8(p_src[i]);
}
- } else if (pos == data.size()) {
+ } else if (pos == get_length()) {
data.resize(pos + p_length);
- for (int i = 0; i < p_length; i++) {
+ for (uint64_t i = 0; i < p_length; i++) {
data.write[pos + i] = p_src[i];
}
pos += p_length;
@@ -282,10 +281,10 @@ void FileAccessEncrypted::flush() {
void FileAccessEncrypted::store_8(uint8_t p_dest) {
ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
- if (pos < data.size()) {
+ if (pos < get_length()) {
data.write[pos] = p_dest;
pos++;
- } else if (pos == data.size()) {
+ } else if (pos == get_length()) {
data.push_back(p_dest);
pos++;
}
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 969052d04f..decffae696 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -31,7 +31,7 @@
#ifndef FILE_ACCESS_ENCRYPTED_H
#define FILE_ACCESS_ENCRYPTED_H
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#define ENCRYPTED_HEADER_MAGIC 0x43454447
@@ -47,10 +47,10 @@ private:
Vector<uint8_t> key;
bool writing = false;
FileAccess *file = nullptr;
- size_t base = 0;
- size_t length = 0;
+ uint64_t base = 0;
+ uint64_t length = 0;
Vector<uint8_t> data;
- mutable int pos = 0;
+ mutable uint64_t pos = 0;
mutable bool eofed = false;
bool use_magic = true;
@@ -68,21 +68,21 @@ public:
virtual String get_path() const; /// returns the path for the current open file
virtual String get_path_absolute() const; /// returns the absolute path for the current open file
- virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek(uint64_t p_position); ///< seek to a given position
virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual size_t get_position() const; ///< get position in the file
- virtual size_t get_len() const; ///< get size of the file
+ virtual uint64_t get_position() const; ///< get position in the file
+ virtual uint64_t get_length() const; ///< get size of the file
virtual bool eof_reached() const; ///< reading passed EOF
virtual uint8_t get_8() const; ///< get a byte
- virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
virtual Error get_error() const; ///< get last error
virtual void flush();
virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
virtual bool file_exists(const String &p_name); ///< return true if a file exists
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 58670d5246..627fd2bf9c 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -31,8 +31,7 @@
#include "file_access_memory.h"
#include "core/config/project_settings.h"
-#include "core/os/copymem.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "core/templates/map.h"
static Map<String, Vector<uint8_t>> *files = nullptr;
@@ -72,7 +71,7 @@ bool FileAccessMemory::file_exists(const String &p_name) {
return files && (files->find(name) != nullptr);
}
-Error FileAccessMemory::open_custom(const uint8_t *p_data, int p_len) {
+Error FileAccessMemory::open_custom(const uint8_t *p_data, uint64_t p_len) {
data = (uint8_t *)p_data;
length = p_len;
pos = 0;
@@ -103,7 +102,7 @@ bool FileAccessMemory::is_open() const {
return data != nullptr;
}
-void FileAccessMemory::seek(size_t p_position) {
+void FileAccessMemory::seek(uint64_t p_position) {
ERR_FAIL_COND(!data);
pos = p_position;
}
@@ -113,12 +112,12 @@ void FileAccessMemory::seek_end(int64_t p_position) {
pos = length + p_position;
}
-size_t FileAccessMemory::get_position() const {
+uint64_t FileAccessMemory::get_position() const {
ERR_FAIL_COND_V(!data, 0);
return pos;
}
-size_t FileAccessMemory::get_len() const {
+uint64_t FileAccessMemory::get_length() const {
ERR_FAIL_COND_V(!data, 0);
return length;
}
@@ -137,19 +136,18 @@ uint8_t FileAccessMemory::get_8() const {
return ret;
}
-int FileAccessMemory::get_buffer(uint8_t *p_dst, int p_length) const {
+uint64_t FileAccessMemory::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V(!data, -1);
- int left = length - pos;
- int read = MIN(p_length, left);
+ uint64_t left = length - pos;
+ uint64_t read = MIN(p_length, left);
if (read < p_length) {
WARN_PRINT("Reading less data than requested");
}
- copymem(p_dst, &data[pos], read);
+ memcpy(p_dst, &data[pos], read);
pos += p_length;
return read;
@@ -169,13 +167,14 @@ void FileAccessMemory::store_8(uint8_t p_byte) {
data[pos++] = p_byte;
}
-void FileAccessMemory::store_buffer(const uint8_t *p_src, int p_length) {
- int left = length - pos;
- int write = MIN(p_length, left);
+void FileAccessMemory::store_buffer(const uint8_t *p_src, uint64_t p_length) {
+ ERR_FAIL_COND(!p_src && p_length > 0);
+ uint64_t left = length - pos;
+ uint64_t write = MIN(p_length, left);
if (write < p_length) {
WARN_PRINT("Writing less data than requested");
}
- copymem(&data[pos], p_src, write);
+ memcpy(&data[pos], p_src, write);
pos += p_length;
}
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 0e3b0ad7b1..14135bd68c 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -31,12 +31,12 @@
#ifndef FILE_ACCESS_MEMORY_H
#define FILE_ACCESS_MEMORY_H
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
class FileAccessMemory : public FileAccess {
uint8_t *data = nullptr;
- int length = 0;
- mutable int pos = 0;
+ uint64_t length = 0;
+ mutable uint64_t pos = 0;
static FileAccess *create();
@@ -44,27 +44,27 @@ public:
static void register_file(String p_name, Vector<uint8_t> p_data);
static void cleanup();
- virtual Error open_custom(const uint8_t *p_data, int p_len); ///< open a file
+ virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
- virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek(uint64_t p_position); ///< seek to a given position
virtual void seek_end(int64_t p_position); ///< seek from the end of file
- virtual size_t get_position() const; ///< get position in the file
- virtual size_t get_len() const; ///< get size of the file
+ virtual uint64_t get_position() const; ///< get position in the file
+ virtual uint64_t get_length() const; ///< get size of the file
virtual bool eof_reached() const; ///< reading passed EOF
virtual uint8_t get_8() const; ///< get a byte
- virtual int get_buffer(uint8_t *p_dst, int p_length) const; ///< get an array of bytes
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
virtual Error get_error() const; ///< get last error
virtual void flush();
virtual void store_8(uint8_t p_byte); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
virtual bool file_exists(const String &p_name); ///< return true if a file exists
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 31b7d658d0..63a8f9c5b6 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -126,7 +126,7 @@ void FileAccessNetworkClient::_thread_func() {
if (status != OK) {
fa->_respond(0, Error(status));
} else {
- uint64_t len = get_64();
+ int64_t len = get_64();
fa->_respond(len, Error(status));
}
@@ -135,7 +135,7 @@ void FileAccessNetworkClient::_thread_func() {
} break;
case FileAccessNetwork::RESPONSE_DATA: {
int64_t offset = get_64();
- uint32_t len = get_32();
+ int32_t len = get_32();
Vector<uint8_t> block;
block.resize(len);
@@ -171,7 +171,7 @@ void FileAccessNetworkClient::_thread_func(void *s) {
}
Error FileAccessNetworkClient::connect(const String &p_host, int p_port, const String &p_password) {
- IP_Address ip;
+ IPAddress ip;
if (p_host.is_valid_ip_address()) {
ip = p_host;
@@ -219,13 +219,13 @@ FileAccessNetworkClient::~FileAccessNetworkClient() {
thread.wait_to_finish();
}
-void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block) {
- int page = p_offset / page_size;
+void FileAccessNetwork::_set_block(uint64_t p_offset, const Vector<uint8_t> &p_block) {
+ int32_t page = p_offset / page_size;
ERR_FAIL_INDEX(page, pages.size());
if (page < pages.size() - 1) {
ERR_FAIL_COND(p_block.size() != page_size);
} else {
- ERR_FAIL_COND((p_block.size() != (int)(total_size % page_size)));
+ ERR_FAIL_COND((uint64_t)p_block.size() != total_size % page_size);
}
{
@@ -240,7 +240,7 @@ void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block)
}
}
-void FileAccessNetwork::_respond(size_t p_len, Error p_status) {
+void FileAccessNetwork::_respond(uint64_t p_len, Error p_status) {
DEBUG_PRINT("GOT RESPONSE - len: " + itos(p_len) + " status: " + itos(p_status));
response = p_status;
if (response != OK) {
@@ -248,7 +248,7 @@ void FileAccessNetwork::_respond(size_t p_len, Error p_status) {
}
opened = true;
total_size = p_len;
- int pc = ((total_size - 1) / page_size) + 1;
+ int32_t pc = ((total_size - 1) / page_size) + 1;
pages.resize(pc);
}
@@ -307,8 +307,9 @@ bool FileAccessNetwork::is_open() const {
return opened;
}
-void FileAccessNetwork::seek(size_t p_position) {
+void FileAccessNetwork::seek(uint64_t p_position) {
ERR_FAIL_COND_MSG(!opened, "File must be opened before use.");
+
eof_flag = p_position > total_size;
if (p_position >= total_size) {
@@ -322,12 +323,12 @@ void FileAccessNetwork::seek_end(int64_t p_position) {
seek(total_size + p_position);
}
-size_t FileAccessNetwork::get_position() const {
+uint64_t FileAccessNetwork::get_position() const {
ERR_FAIL_COND_V_MSG(!opened, 0, "File must be opened before use.");
return pos;
}
-size_t FileAccessNetwork::get_len() const {
+uint64_t FileAccessNetwork::get_length() const {
ERR_FAIL_COND_V_MSG(!opened, 0, "File must be opened before use.");
return total_size;
}
@@ -343,7 +344,7 @@ uint8_t FileAccessNetwork::get_8() const {
return v;
}
-void FileAccessNetwork::_queue_page(int p_page) const {
+void FileAccessNetwork::_queue_page(int32_t p_page) const {
if (p_page >= pages.size()) {
return;
}
@@ -354,7 +355,7 @@ void FileAccessNetwork::_queue_page(int p_page) const {
FileAccessNetworkClient::BlockRequest br;
br.id = id;
- br.offset = size_t(p_page) * page_size;
+ br.offset = (uint64_t)p_page * page_size;
br.size = page_size;
nc->block_requests.push_back(br);
pages.write[p_page].queued = true;
@@ -365,11 +366,9 @@ void FileAccessNetwork::_queue_page(int p_page) const {
}
}
-int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const {
+uint64_t FileAccessNetwork::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(p_length < 0, -1);
- //bool eof=false;
if (pos + p_length > total_size) {
eof_flag = true;
}
@@ -377,18 +376,16 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const {
p_length = total_size - pos;
}
- //FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
-
uint8_t *buff = last_page_buff;
- for (int i = 0; i < p_length; i++) {
- int page = pos / page_size;
+ for (uint64_t i = 0; i < p_length; i++) {
+ int32_t page = pos / page_size;
if (page != last_page) {
buffer_mutex.lock();
if (pages[page].buffer.is_empty()) {
waiting_on_page = page;
- for (int j = 0; j < read_ahead; j++) {
+ for (int32_t j = 0; j < read_ahead; j++) {
_queue_page(page + j);
}
buffer_mutex.unlock();
@@ -396,10 +393,9 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const {
page_sem.wait();
DEBUG_PRINT("done");
} else {
- for (int j = 0; j < read_ahead; j++) {
+ for (int32_t j = 0; j < read_ahead; j++) {
_queue_page(page + j);
}
- //queue pages
buffer_mutex.unlock();
}
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index 1f5de3e5dd..1d9d761fbb 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -31,8 +31,8 @@
#ifndef FILE_ACCESS_NETWORK_H
#define FILE_ACCESS_NETWORK_H
+#include "core/io/file_access.h"
#include "core/io/stream_peer_tcp.h"
-#include "core/os/file_access.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
@@ -40,9 +40,9 @@ class FileAccessNetwork;
class FileAccessNetworkClient {
struct BlockRequest {
- int id;
+ int32_t id;
uint64_t offset;
- int size;
+ int32_t size;
};
List<BlockRequest> block_requests;
@@ -54,17 +54,17 @@ class FileAccessNetworkClient {
Mutex blockrequest_mutex;
Map<int, FileAccessNetwork *> accesses;
Ref<StreamPeerTCP> client;
- int last_id = 0;
- int lockcount = 0;
+ int32_t last_id = 0;
+ int32_t lockcount = 0;
Vector<uint8_t> block;
void _thread_func();
static void _thread_func(void *s);
- void put_32(int p_32);
+ void put_32(int32_t p_32);
void put_64(int64_t p_64);
- int get_32();
+ int32_t get_32();
int64_t get_64();
void lock_mutex();
void unlock_mutex();
@@ -86,15 +86,15 @@ class FileAccessNetwork : public FileAccess {
Semaphore page_sem;
Mutex buffer_mutex;
bool opened = false;
- size_t total_size;
- mutable size_t pos = 0;
- int id;
+ uint64_t total_size;
+ mutable uint64_t pos = 0;
+ int32_t id;
mutable bool eof_flag = false;
- mutable int last_page = -1;
+ mutable int32_t last_page = -1;
mutable uint8_t *last_page_buff = nullptr;
- int page_size;
- int read_ahead;
+ int32_t page_size;
+ int32_t read_ahead;
mutable int waiting_on_page = -1;
@@ -110,9 +110,9 @@ class FileAccessNetwork : public FileAccess {
uint64_t exists_modtime;
friend class FileAccessNetworkClient;
- void _queue_page(int p_page) const;
- void _respond(size_t p_len, Error p_status);
- void _set_block(int p_offset, const Vector<uint8_t> &p_block);
+ void _queue_page(int32_t p_page) const;
+ void _respond(uint64_t p_len, Error p_status);
+ void _set_block(uint64_t p_offset, const Vector<uint8_t> &p_block);
public:
enum Command {
@@ -134,15 +134,15 @@ public:
virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
- virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek(uint64_t p_position); ///< seek to a given position
virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual size_t get_position() const; ///< get position in the file
- virtual size_t get_len() const; ///< get size of the file
+ virtual uint64_t get_position() const; ///< get position in the file
+ virtual uint64_t get_length() const; ///< get size of the file
virtual bool eof_reached() const; ///< reading passed EOF
virtual uint8_t get_8() const; ///< get a byte
- virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
virtual Error get_error() const; ///< get last error
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index e24dc40166..7b43daf9c0 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -36,7 +36,7 @@
#include <stdio.h>
-Error PackedData::add_pack(const String &p_path, bool p_replace_files, size_t p_offset) {
+Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
for (int i = 0; i < sources.size(); i++) {
if (sources[i]->try_open_pack(p_path, p_replace_files, p_offset)) {
return OK;
@@ -46,17 +46,16 @@ Error PackedData::add_pack(const String &p_path, bool p_replace_files, size_t p_
return ERR_FILE_UNRECOGNIZED;
}
-void PackedData::add_path(const String &pkg_path, const String &path, uint64_t ofs, uint64_t size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted) {
- PathMD5 pmd5(path.md5_buffer());
- //printf("adding path %s, %lli, %lli\n", path.utf8().get_data(), pmd5.a, pmd5.b);
+void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted) {
+ PathMD5 pmd5(p_path.md5_buffer());
bool exists = files.has(pmd5);
PackedFile pf;
pf.encrypted = p_encrypted;
- pf.pack = pkg_path;
- pf.offset = ofs;
- pf.size = size;
+ pf.pack = p_pkg_path;
+ pf.offset = p_ofs;
+ pf.size = p_size;
for (int i = 0; i < 16; i++) {
pf.md5[i] = p_md5[i];
}
@@ -68,7 +67,7 @@ void PackedData::add_path(const String &pkg_path, const String &path, uint64_t o
if (!exists) {
//search for dir
- String p = path.replace_first("res://", "");
+ String p = p_path.replace_first("res://", "");
PackedDir *cd = root;
if (p.find("/") != -1) { //in a subdir
@@ -87,7 +86,7 @@ void PackedData::add_path(const String &pkg_path, const String &path, uint64_t o
}
}
}
- String filename = path.get_file();
+ String filename = p_path.get_file();
// Don't add as a file if the path points to a directory
if (!filename.is_empty()) {
cd->files.insert(filename);
@@ -126,7 +125,7 @@ PackedData::~PackedData() {
//////////////////////////////////////////////////////////////////
-bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset) {
+bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
return false;
@@ -261,7 +260,7 @@ bool FileAccessPack::is_open() const {
return f->is_open();
}
-void FileAccessPack::seek(size_t p_position) {
+void FileAccessPack::seek(uint64_t p_position) {
if (p_position > pf.size) {
eof = true;
} else {
@@ -276,11 +275,11 @@ void FileAccessPack::seek_end(int64_t p_position) {
seek(pf.size + p_position);
}
-size_t FileAccessPack::get_position() const {
+uint64_t FileAccessPack::get_position() const {
return pos;
}
-size_t FileAccessPack::get_len() const {
+uint64_t FileAccessPack::get_length() const {
return pf.size;
}
@@ -298,18 +297,17 @@ uint8_t FileAccessPack::get_8() const {
return f->get_8();
}
-int FileAccessPack::get_buffer(uint8_t *p_dst, int p_length) const {
+uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(p_length < 0, -1);
if (eof) {
return 0;
}
- uint64_t to_read = p_length;
+ int64_t to_read = p_length;
if (to_read + pos > pf.size) {
eof = true;
- to_read = int64_t(pf.size) - int64_t(pos);
+ to_read = (int64_t)pf.size - (int64_t)pos;
}
pos += p_length;
@@ -322,9 +320,9 @@ int FileAccessPack::get_buffer(uint8_t *p_dst, int p_length) const {
return to_read;
}
-void FileAccessPack::set_endian_swap(bool p_swap) {
- FileAccess::set_endian_swap(p_swap);
- f->set_endian_swap(p_swap);
+void FileAccessPack::set_big_endian(bool p_big_endian) {
+ FileAccess::set_big_endian(p_big_endian);
+ f->set_big_endian(p_big_endian);
}
Error FileAccessPack::get_error() const {
@@ -342,7 +340,7 @@ void FileAccessPack::store_8(uint8_t p_dest) {
ERR_FAIL();
}
-void FileAccessPack::store_buffer(const uint8_t *p_src, int p_length) {
+void FileAccessPack::store_buffer(const uint8_t *p_src, uint64_t p_length) {
ERR_FAIL();
}
@@ -549,7 +547,7 @@ Error DirAccessPack::remove(String p_name) {
return ERR_UNAVAILABLE;
}
-size_t DirAccessPack::get_space_left() {
+uint64_t DirAccessPack::get_space_left() {
return 0;
}
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 955108f455..2f0ee62723 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -31,8 +31,8 @@
#ifndef FILE_ACCESS_PACK_H
#define FILE_ACCESS_PACK_H
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/string/print_string.h"
#include "core/templates/list.h"
#include "core/templates/map.h"
@@ -112,13 +112,13 @@ private:
public:
void add_pack_source(PackSource *p_source);
- void add_path(const String &pkg_path, const String &path, uint64_t ofs, uint64_t size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false); // for PackSource
+ void add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false); // for PackSource
void set_disabled(bool p_disabled) { disabled = p_disabled; }
_FORCE_INLINE_ bool is_disabled() const { return disabled; }
static PackedData *get_singleton() { return singleton; }
- Error add_pack(const String &p_path, bool p_replace_files, size_t p_offset);
+ Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
_FORCE_INLINE_ FileAccess *try_open_path(const String &p_path);
_FORCE_INLINE_ bool has_path(const String &p_path);
@@ -132,21 +132,21 @@ public:
class PackSource {
public:
- virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset) = 0;
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) = 0;
virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file) = 0;
virtual ~PackSource() {}
};
class PackedSourcePCK : public PackSource {
public:
- virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset);
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file);
};
class FileAccessPack : public FileAccess {
PackedData::PackedFile pf;
- mutable size_t pos;
+ mutable uint64_t pos;
mutable bool eof;
uint64_t off;
@@ -160,25 +160,25 @@ public:
virtual void close();
virtual bool is_open() const;
- virtual void seek(size_t p_position);
+ virtual void seek(uint64_t p_position);
virtual void seek_end(int64_t p_position = 0);
- virtual size_t get_position() const;
- virtual size_t get_len() const;
+ virtual uint64_t get_position() const;
+ virtual uint64_t get_length() const;
virtual bool eof_reached() const;
virtual uint8_t get_8() const;
- virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
- virtual void set_endian_swap(bool p_swap);
+ virtual void set_big_endian(bool p_big_endian);
virtual Error get_error() const;
virtual void flush();
virtual void store_8(uint8_t p_dest);
- virtual void store_buffer(const uint8_t *p_src, int p_length);
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length);
virtual bool file_exists(const String &p_name);
@@ -243,7 +243,11 @@ public:
virtual Error rename(String p_from, String p_to);
virtual Error remove(String p_name);
- size_t get_space_left();
+ uint64_t get_space_left();
+
+ virtual bool is_link(String p_file) { return false; }
+ virtual String read_link(String p_file) { return p_file; }
+ virtual Error create_link(String p_source, String p_target) { return FAILED; }
virtual String get_filesystem_type() const;
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 586c988974..b5c882e9ce 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -32,8 +32,7 @@
#include "file_access_zip.h"
-#include "core/os/copymem.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
ZipArchive *ZipArchive::instance = nullptr;
@@ -44,14 +43,14 @@ static void *godot_open(void *data, const char *p_fname, int mode) {
return nullptr;
}
- FileAccess *f = (FileAccess *)data;
- f->open(p_fname, FileAccess::READ);
+ FileAccess *f = FileAccess::open(p_fname, FileAccess::READ);
+ ERR_FAIL_COND_V(!f, nullptr);
- return f->is_open() ? data : nullptr;
+ return f;
}
static uLong godot_read(void *data, void *fdata, void *buf, uLong size) {
- FileAccess *f = (FileAccess *)data;
+ FileAccess *f = (FileAccess *)fdata;
f->get_buffer((uint8_t *)buf, size);
return size;
}
@@ -61,20 +60,20 @@ static uLong godot_write(voidpf opaque, voidpf stream, const void *buf, uLong si
}
static long godot_tell(voidpf opaque, voidpf stream) {
- FileAccess *f = (FileAccess *)opaque;
+ FileAccess *f = (FileAccess *)stream;
return f->get_position();
}
static long godot_seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
- FileAccess *f = (FileAccess *)opaque;
+ FileAccess *f = (FileAccess *)stream;
- int pos = offset;
+ uint64_t pos = offset;
switch (origin) {
case ZLIB_FILEFUNC_SEEK_CUR:
pos = f->get_position() + offset;
break;
case ZLIB_FILEFUNC_SEEK_END:
- pos = f->get_len() + offset;
+ pos = f->get_length() + offset;
break;
default:
break;
@@ -85,13 +84,17 @@ static long godot_seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
}
static int godot_close(voidpf opaque, voidpf stream) {
- FileAccess *f = (FileAccess *)opaque;
- f->close();
+ FileAccess *f = (FileAccess *)stream;
+ if (f) {
+ f->close();
+ memdelete(f);
+ f = nullptr;
+ }
return 0;
}
static int godot_testerror(voidpf opaque, voidpf stream) {
- FileAccess *f = (FileAccess *)opaque;
+ FileAccess *f = (FileAccess *)stream;
return f->get_error() != OK ? 1 : 0;
}
@@ -106,23 +109,18 @@ static void godot_free(voidpf opaque, voidpf address) {
void ZipArchive::close_handle(unzFile p_file) const {
ERR_FAIL_COND_MSG(!p_file, "Cannot close a file if none is open.");
- FileAccess *f = (FileAccess *)unzGetOpaque(p_file);
unzCloseCurrentFile(p_file);
unzClose(p_file);
- memdelete(f);
}
unzFile ZipArchive::get_file_handle(String p_file) const {
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, nullptr, "Cannot open file '" + packages[file.package].filename + "'.");
-
zlib_filefunc_def io;
- zeromem(&io, sizeof(io));
+ memset(&io, 0, sizeof(io));
- io.opaque = f;
+ io.opaque = nullptr;
io.zopen_file = godot_open;
io.zread_file = godot_read;
io.zwrite_file = godot_write;
@@ -136,7 +134,7 @@ 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, nullptr);
+ ERR_FAIL_COND_V_MSG(!pkg, nullptr, "Cannot open file '" + packages[file.package].filename + "'.");
int unz_err = unzGoToFilePos(pkg, &file.file_pos);
if (unz_err != UNZ_OK || unzOpenCurrentFile(pkg) != UNZ_OK) {
unzClose(pkg);
@@ -146,8 +144,7 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
return pkg;
}
-bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset = 0) {
- //printf("opening zip pack %s, %i, %i\n", p_name.utf8().get_data(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
+bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset = 0) {
// load with offset feature only supported for PCK files
ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Invalid PCK data. Note that loading files with a non-zero offset isn't supported with ZIP archives.");
@@ -156,12 +153,9 @@ bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, size_
}
zlib_filefunc_def io;
+ memset(&io, 0, sizeof(io));
- FileAccess *fa = FileAccess::open(p_path, FileAccess::READ);
- if (!fa) {
- return false;
- }
- io.opaque = fa;
+ io.opaque = nullptr;
io.zopen_file = godot_open;
io.zread_file = godot_read;
io.zwrite_file = godot_write;
@@ -232,9 +226,7 @@ ZipArchive::ZipArchive() {
ZipArchive::~ZipArchive() {
for (int i = 0; i < packages.size(); i++) {
- FileAccess *f = (FileAccess *)unzGetOpaque(packages[i].zfile);
unzClose(packages[i].zfile);
- memdelete(f);
}
packages.clear();
@@ -270,22 +262,23 @@ bool FileAccessZip::is_open() const {
return zfile != nullptr;
}
-void FileAccessZip::seek(size_t p_position) {
+void FileAccessZip::seek(uint64_t p_position) {
ERR_FAIL_COND(!zfile);
+
unzSeekCurrentFile(zfile, p_position);
}
void FileAccessZip::seek_end(int64_t p_position) {
ERR_FAIL_COND(!zfile);
- unzSeekCurrentFile(zfile, get_len() + p_position);
+ unzSeekCurrentFile(zfile, get_length() + p_position);
}
-size_t FileAccessZip::get_position() const {
+uint64_t FileAccessZip::get_position() const {
ERR_FAIL_COND_V(!zfile, 0);
return unztell(zfile);
}
-size_t FileAccessZip::get_len() const {
+uint64_t FileAccessZip::get_length() const {
ERR_FAIL_COND_V(!zfile, 0);
return file_info.uncompressed_size;
}
@@ -302,17 +295,17 @@ uint8_t FileAccessZip::get_8() const {
return ret;
}
-int FileAccessZip::get_buffer(uint8_t *p_dst, int p_length) const {
+uint64_t FileAccessZip::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V(!zfile, -1);
+
at_eof = unzeof(zfile);
if (at_eof) {
return 0;
}
- int read = unzReadCurrentFile(zfile, p_dst, p_length);
+ int64_t read = unzReadCurrentFile(zfile, p_dst, p_length);
ERR_FAIL_COND_V(read < 0, read);
- if (read < p_length) {
+ if ((uint64_t)read < p_length) {
at_eof = true;
}
return read;
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index 8559f871ce..cca14ded62 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -67,7 +67,7 @@ public:
bool file_exists(String p_name) const;
- virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset);
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file);
static ZipArchive *get_singleton();
@@ -87,20 +87,21 @@ public:
virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
- virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek(uint64_t p_position); ///< seek to a given position
virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual size_t get_position() const; ///< get position in the file
- virtual size_t get_len() const; ///< get size of the file
+ virtual uint64_t get_position() const; ///< get position in the file
+ virtual uint64_t get_length() const; ///< get size of the file
virtual bool eof_reached() const; ///< reading passed EOF
virtual uint8_t get_8() const; ///< get a byte
- virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
virtual Error get_error() const; ///< get last error
virtual void flush();
virtual void store_8(uint8_t p_dest); ///< store a byte
+
virtual bool file_exists(const String &p_name); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) { return 0; } // todo
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 3863dce0f6..0cf870e7e7 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -77,7 +77,7 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl,
if (conn_host.is_valid_ip_address()) {
// Host contains valid IP
- Error err = tcp_connection->connect_to_host(IP_Address(conn_host), p_port);
+ Error err = tcp_connection->connect_to_host(IPAddress(conn_host), p_port);
if (err) {
status = STATUS_CANT_CONNECT;
return err;
@@ -328,7 +328,7 @@ Error HTTPClient::poll() {
return OK; // Still resolving
case IP::RESOLVER_STATUS_DONE: {
- IP_Address host = IP::get_singleton()->get_resolve_item_address(resolving);
+ IPAddress host = IP::get_singleton()->get_resolve_item_address(resolving);
Error err = tcp_connection->connect_to_host(host, conn_port);
IP::get_singleton()->erase_resolve_item(resolving);
resolving = IP::RESOLVER_INVALID_ID;
@@ -633,7 +633,7 @@ PackedByteArray HTTPClient::read_response_body_chunk() {
ret.resize(chunk.size() - 2);
uint8_t *w = ret.ptrw();
- copymem(w, chunk.ptr(), chunk.size() - 2);
+ memcpy(w, chunk.ptr(), chunk.size() - 2);
chunk.clear();
}
diff --git a/core/io/http_client.h b/core/io/http_client.h
index ec4b86b26f..f70999836f 100644
--- a/core/io/http_client.h
+++ b/core/io/http_client.h
@@ -34,10 +34,10 @@
#include "core/io/ip.h"
#include "core/io/stream_peer.h"
#include "core/io/stream_peer_tcp.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class HTTPClient : public Reference {
- GDCLASS(HTTPClient, Reference);
+class HTTPClient : public RefCounted {
+ GDCLASS(HTTPClient, RefCounted);
public:
enum ResponseCode {
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 873eb66f33..9cd0ea7b5d 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -34,7 +34,6 @@
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/math/math_funcs.h"
-#include "core/os/copymem.h"
#include "core/string/print_string.h"
#include "core/templates/hash_map.h"
@@ -1429,16 +1428,23 @@ void Image::flip_x() {
}
}
+/// Get mipmap size and offset.
int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps, int *r_mm_width, int *r_mm_height) {
+ // Data offset in mipmaps (including the original texture).
int size = 0;
+
int w = p_width;
int h = p_height;
+
+ // Current mipmap index in the loop below. p_mipmaps is the target mipmap index.
+ // In this function, mipmap 0 represents the first mipmap instead of the original texture.
int mm = 0;
int pixsize = get_format_pixel_size(p_format);
int pixshift = get_format_pixel_rshift(p_format);
int block = get_format_block_size(p_format);
- //technically, you can still compress up to 1 px no matter the format, so commenting this
+
+ // Technically, you can still compress up to 1 px no matter the format, so commenting this.
//int minw, minh;
//get_format_min_pixel_size(p_format, minw, minh);
int minw = 1, minh = 1;
@@ -1454,17 +1460,6 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &
size += s;
- if (r_mm_width) {
- *r_mm_width = bw;
- }
- if (r_mm_height) {
- *r_mm_height = bh;
- }
-
- if (p_mipmaps >= 0 && mm == p_mipmaps) {
- break;
- }
-
if (p_mipmaps >= 0) {
w = MAX(minw, w >> 1);
h = MAX(minh, h >> 1);
@@ -1475,6 +1470,21 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &
w = MAX(minw, w >> 1);
h = MAX(minh, h >> 1);
}
+
+ // Set mipmap size.
+ // It might be necessary to put this after the minimum mipmap size check because of the possible occurrence of "1 >> 1".
+ if (r_mm_width) {
+ *r_mm_width = bw >> 1;
+ }
+ if (r_mm_height) {
+ *r_mm_height = bh >> 1;
+ }
+
+ // Reach target mipmap.
+ if (p_mipmaps >= 0 && mm == p_mipmaps) {
+ break;
+ }
+
mm++;
}
@@ -1537,7 +1547,7 @@ void Image::shrink_x2() {
uint8_t *w = new_img.ptrw();
const uint8_t *r = data.ptr();
- copymem(w, &r[ofs], new_size);
+ memcpy(w, &r[ofs], new_size);
}
width = MAX(width / 2, 1);
@@ -1932,7 +1942,7 @@ Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, con
uint8_t* wr = imgdata.ptrw();
- copymem(wr.ptr(), ptr, size);
+ memcpy(wr.ptr(), ptr, size);
wr = uint8_t*();
Ref<Image> im;
im.instance();
@@ -1982,7 +1992,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
{
uint8_t *w = data.ptrw();
- zeromem(w, size);
+ memset(w, 0, size);
}
width = p_width;
@@ -2719,10 +2729,11 @@ 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) = 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::webp_lossy_packer)(const Ref<Image> &, float) = nullptr;
+Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr;
+Ref<Image> (*Image::webp_unpacker)(const Vector<uint8_t> &) = nullptr;
+Vector<uint8_t> (*Image::png_packer)(const Ref<Image> &) = nullptr;
+Ref<Image> (*Image::png_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;
@@ -3295,7 +3306,7 @@ Ref<Image> Image::get_image_from_mipmap(int p_mipamp) const {
{
uint8_t *wr = new_data.ptrw();
const uint8_t *rd = data.ptr();
- copymem(wr, rd + ofs, size);
+ memcpy(wr, rd + ofs, size);
}
Ref<Image> image;
@@ -3622,5 +3633,5 @@ Ref<Resource> Image::duplicate(bool p_subresources) const {
}
void Image::set_as_black() {
- zeromem(data.ptrw(), data.size());
+ memset(data.ptrw(), 0, data.size());
}
diff --git a/core/io/image.h b/core/io/image.h
index df8f9b35a1..060e54a308 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -148,10 +148,11 @@ public:
static void (*_image_decompress_etc1)(Image *);
static void (*_image_decompress_etc2)(Image *);
- static Vector<uint8_t> (*lossy_packer)(const Ref<Image> &p_image, float p_quality);
- static Ref<Image> (*lossy_unpacker)(const Vector<uint8_t> &p_buffer);
- static Vector<uint8_t> (*lossless_packer)(const Ref<Image> &p_image);
- static Ref<Image> (*lossless_unpacker)(const Vector<uint8_t> &p_buffer);
+ static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality);
+ static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image);
+ static Ref<Image> (*webp_unpacker)(const Vector<uint8_t> &p_buffer);
+ static Vector<uint8_t> (*png_packer)(const Ref<Image> &p_image);
+ static Ref<Image> (*png_unpacker)(const Vector<uint8_t> &p_buffer);
static Vector<uint8_t> (*basis_universal_packer)(const Ref<Image> &p_image, UsedChannels p_channels);
static Ref<Image> (*basis_universal_unpacker)(const Vector<uint8_t> &p_buffer);
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index a5d588e0b5..6d1b1e3646 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -31,9 +31,9 @@
#ifndef IMAGE_LOADER_H
#define IMAGE_LOADER_H
+#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
-#include "core/os/file_access.h"
#include "core/string/ustring.h"
#include "core/templates/list.h"
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index e1d9c19f10..001b1c4757 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -41,13 +41,15 @@ VARIANT_ENUM_CAST(IP::ResolverStatus);
struct _IP_ResolverPrivate {
struct QueueItem {
SafeNumeric<IP::ResolverStatus> status;
- IP_Address response;
+
+ List<IPAddress> response;
+
String hostname;
IP::Type type;
void clear() {
status.set(IP::RESOLVER_STATUS_NONE);
- response = IP_Address();
+ response.clear();
type = IP::TYPE_NONE;
hostname = "";
};
@@ -80,13 +82,9 @@ struct _IP_ResolverPrivate {
if (queue[i].status.get() != IP::RESOLVER_STATUS_WAITING) {
continue;
}
- queue[i].response = IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type);
- if (!queue[i].response.is_valid()) {
- queue[i].status.set(IP::RESOLVER_STATUS_ERROR);
- } else {
- queue[i].status.set(IP::RESOLVER_STATUS_DONE);
- }
+ IP::get_singleton()->_resolve_hostname(queue[i].response, queue[i].hostname, queue[i].type);
+ queue[i].status.set(queue[i].response.is_empty() ? IP::RESOLVER_STATUS_ERROR : IP::RESOLVER_STATUS_DONE);
}
}
@@ -101,25 +99,51 @@ struct _IP_ResolverPrivate {
}
}
- HashMap<String, IP_Address> cache;
+ HashMap<String, List<IPAddress>> cache;
static String get_cache_key(String p_hostname, IP::Type p_type) {
return itos(p_type) + p_hostname;
}
};
-IP_Address IP::resolve_hostname(const String &p_hostname, IP::Type p_type) {
+IPAddress IP::resolve_hostname(const String &p_hostname, IP::Type p_type) {
MutexLock lock(resolver->mutex);
+ List<IPAddress> res;
+
String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
- if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
- IP_Address res = resolver->cache[key];
- return res;
+ if (resolver->cache.has(key)) {
+ res = resolver->cache[key];
+ } else {
+ _resolve_hostname(res, p_hostname, p_type);
+ resolver->cache[key] = res;
}
- IP_Address res = _resolve_hostname(p_hostname, p_type);
- resolver->cache[key] = res;
- return res;
+ for (int i = 0; i < res.size(); ++i) {
+ if (res[i].is_valid()) {
+ return res[i];
+ }
+ }
+ return IPAddress();
+}
+
+Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) {
+ MutexLock lock(resolver->mutex);
+
+ String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
+ if (!resolver->cache.has(key)) {
+ _resolve_hostname(resolver->cache[key], p_hostname, p_type);
+ }
+
+ List<IPAddress> res = resolver->cache[key];
+
+ Array result;
+ for (int i = 0; i < res.size(); ++i) {
+ if (res[i].is_valid()) {
+ result.push_back(String(res[i]));
+ }
+ }
+ return result;
}
IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Type p_type) {
@@ -135,11 +159,11 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ
String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
resolver->queue[id].hostname = p_hostname;
resolver->queue[id].type = p_type;
- if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
+ if (resolver->cache.has(key)) {
resolver->queue[id].response = resolver->cache[key];
resolver->queue[id].status.set(IP::RESOLVER_STATUS_DONE);
} else {
- resolver->queue[id].response = IP_Address();
+ resolver->queue[id].response = List<IPAddress>();
resolver->queue[id].status.set(IP::RESOLVER_STATUS_WAITING);
if (resolver->thread.is_started()) {
resolver->sem.post();
@@ -158,24 +182,49 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
if (resolver->queue[p_id].status.get() == IP::RESOLVER_STATUS_NONE) {
ERR_PRINT("Condition status == IP::RESOLVER_STATUS_NONE");
- resolver->mutex.unlock();
return IP::RESOLVER_STATUS_NONE;
}
return resolver->queue[p_id].status.get();
}
-IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
- ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IP_Address());
+IPAddress IP::get_resolve_item_address(ResolverID p_id) const {
+ ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IPAddress());
MutexLock lock(resolver->mutex);
if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) {
ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
- resolver->mutex.unlock();
- return IP_Address();
+ return IPAddress();
+ }
+
+ List<IPAddress> res = resolver->queue[p_id].response;
+
+ for (int i = 0; i < res.size(); ++i) {
+ if (res[i].is_valid()) {
+ return res[i];
+ }
}
+ return IPAddress();
+}
+
+Array IP::get_resolve_item_addresses(ResolverID p_id) const {
+ ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, Array());
+ MutexLock lock(resolver->mutex);
- return resolver->queue[p_id].response;
+ if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) {
+ ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
+ return Array();
+ }
+
+ List<IPAddress> res = resolver->queue[p_id].response;
+
+ Array result;
+ for (int i = 0; i < res.size(); ++i) {
+ if (res[i].is_valid()) {
+ result.push_back(String(res[i]));
+ }
+ }
+ return result;
}
void IP::erase_resolve_item(ResolverID p_id) {
@@ -201,9 +250,9 @@ void IP::clear_cache(const String &p_hostname) {
Array IP::_get_local_addresses() const {
Array addresses;
- List<IP_Address> ip_addresses;
+ List<IPAddress> ip_addresses;
get_local_addresses(&ip_addresses);
- for (List<IP_Address>::Element *E = ip_addresses.front(); E; E = E->next()) {
+ for (List<IPAddress>::Element *E = ip_addresses.front(); E; E = E->next()) {
addresses.push_back(E->get());
}
@@ -222,7 +271,7 @@ Array IP::_get_local_interfaces() const {
rc["index"] = c.index;
Array ips;
- for (const List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
+ for (const List<IPAddress>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
ips.push_front(F->get());
}
rc["addresses"] = ips;
@@ -233,11 +282,11 @@ Array IP::_get_local_interfaces() const {
return results;
}
-void IP::get_local_addresses(List<IP_Address> *r_addresses) const {
+void IP::get_local_addresses(List<IPAddress> *r_addresses) const {
Map<String, Interface_Info> interfaces;
get_local_interfaces(&interfaces);
for (Map<String, Interface_Info>::Element *E = interfaces.front(); E; E = E->next()) {
- for (const List<IP_Address>::Element *F = E->get().ip_addresses.front(); F; F = F->next()) {
+ for (const List<IPAddress>::Element *F = E->get().ip_addresses.front(); F; F = F->next()) {
r_addresses->push_front(F->get());
}
}
@@ -245,9 +294,11 @@ void IP::get_local_addresses(List<IP_Address> *r_addresses) const {
void IP::_bind_methods() {
ClassDB::bind_method(D_METHOD("resolve_hostname", "host", "ip_type"), &IP::resolve_hostname, DEFVAL(IP::TYPE_ANY));
+ ClassDB::bind_method(D_METHOD("resolve_hostname_addresses", "host", "ip_type"), &IP::resolve_hostname_addresses, DEFVAL(IP::TYPE_ANY));
ClassDB::bind_method(D_METHOD("resolve_hostname_queue_item", "host", "ip_type"), &IP::resolve_hostname_queue_item, DEFVAL(IP::TYPE_ANY));
ClassDB::bind_method(D_METHOD("get_resolve_item_status", "id"), &IP::get_resolve_item_status);
ClassDB::bind_method(D_METHOD("get_resolve_item_address", "id"), &IP::get_resolve_item_address);
+ ClassDB::bind_method(D_METHOD("get_resolve_item_addresses", "id"), &IP::get_resolve_item_addresses);
ClassDB::bind_method(D_METHOD("erase_resolve_item", "id"), &IP::erase_resolve_item);
ClassDB::bind_method(D_METHOD("get_local_addresses"), &IP::_get_local_addresses);
ClassDB::bind_method(D_METHOD("get_local_interfaces"), &IP::_get_local_interfaces);
diff --git a/core/io/ip.h b/core/io/ip.h
index ae080b8e26..3c6040a1f0 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -69,7 +69,6 @@ protected:
static IP *singleton;
static void _bind_methods();
- virtual IP_Address _resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY) = 0;
Array _get_local_addresses() const;
Array _get_local_interfaces() const;
@@ -80,15 +79,20 @@ public:
String name;
String name_friendly;
String index;
- List<IP_Address> ip_addresses;
+ List<IPAddress> ip_addresses;
};
- IP_Address resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY);
+ IPAddress resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY);
+ Array resolve_hostname_addresses(const String &p_hostname, Type p_type = TYPE_ANY);
// async resolver hostname
ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY);
ResolverStatus get_resolve_item_status(ResolverID p_id) const;
- IP_Address get_resolve_item_address(ResolverID p_id) const;
- virtual void get_local_addresses(List<IP_Address> *r_addresses) const;
+ IPAddress get_resolve_item_address(ResolverID p_id) const;
+ virtual void get_local_addresses(List<IPAddress> *r_addresses) const;
+
+ virtual void _resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type = TYPE_ANY) const = 0;
+ Array get_resolve_item_addresses(ResolverID p_id) const;
+
virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const = 0;
void erase_resolve_item(ResolverID p_id);
diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp
index 5f98eb69e8..1c1ac8a88f 100644
--- a/core/io/ip_address.cpp
+++ b/core/io/ip_address.cpp
@@ -30,14 +30,14 @@
#include "ip_address.h"
/*
-IP_Address::operator Variant() const {
+IPAddress::operator Variant() const {
return operator String();
}*/
#include <stdio.h>
#include <string.h>
-IP_Address::operator String() const {
+IPAddress::operator String() const {
if (wildcard) {
return "*";
}
@@ -90,7 +90,7 @@ static void _parse_hex(const String &p_string, int p_start, uint8_t *p_dst) {
p_dst[1] = ret & 0xff;
}
-void IP_Address::_parse_ipv6(const String &p_string) {
+void IPAddress::_parse_ipv6(const String &p_string) {
static const int parts_total = 8;
int parts[parts_total] = { 0 };
int parts_count = 0;
@@ -146,7 +146,7 @@ void IP_Address::_parse_ipv6(const String &p_string) {
}
}
-void IP_Address::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret) {
+void IPAddress::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret) {
String ip;
if (p_start != 0) {
ip = p_string.substr(p_start, p_string.length() - p_start);
@@ -161,33 +161,33 @@ void IP_Address::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret
}
}
-void IP_Address::clear() {
+void IPAddress::clear() {
memset(&field8[0], 0, sizeof(field8));
valid = false;
wildcard = false;
}
-bool IP_Address::is_ipv4() const {
+bool IPAddress::is_ipv4() const {
return (field32[0] == 0 && field32[1] == 0 && field16[4] == 0 && field16[5] == 0xffff);
}
-const uint8_t *IP_Address::get_ipv4() const {
+const uint8_t *IPAddress::get_ipv4() const {
ERR_FAIL_COND_V_MSG(!is_ipv4(), &(field8[12]), "IPv4 requested, but current IP is IPv6."); // Not the correct IPv4 (it's an IPv6), but we don't want to return a null pointer risking an engine crash.
return &(field8[12]);
}
-void IP_Address::set_ipv4(const uint8_t *p_ip) {
+void IPAddress::set_ipv4(const uint8_t *p_ip) {
clear();
valid = true;
field16[5] = 0xffff;
field32[3] = *((const uint32_t *)p_ip);
}
-const uint8_t *IP_Address::get_ipv6() const {
+const uint8_t *IPAddress::get_ipv6() const {
return field8;
}
-void IP_Address::set_ipv6(const uint8_t *p_buf) {
+void IPAddress::set_ipv6(const uint8_t *p_buf) {
clear();
valid = true;
for (int i = 0; i < 16; i++) {
@@ -195,7 +195,7 @@ void IP_Address::set_ipv6(const uint8_t *p_buf) {
}
}
-IP_Address::IP_Address(const String &p_string) {
+IPAddress::IPAddress(const String &p_string) {
clear();
if (p_string == "*") {
@@ -225,7 +225,7 @@ _FORCE_INLINE_ static void _32_to_buf(uint8_t *p_dst, uint32_t p_n) {
p_dst[3] = (p_n >> 0) & 0xff;
}
-IP_Address::IP_Address(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d, bool is_v6) {
+IPAddress::IPAddress(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d, bool is_v6) {
clear();
valid = true;
if (!is_v6) {
diff --git a/core/io/ip_address.h b/core/io/ip_address.h
index 49bf83d72f..05da675704 100644
--- a/core/io/ip_address.h
+++ b/core/io/ip_address.h
@@ -33,7 +33,7 @@
#include "core/string/ustring.h"
-struct IP_Address {
+struct IPAddress {
private:
union {
uint8_t field8[16];
@@ -50,7 +50,7 @@ protected:
public:
//operator Variant() const;
- bool operator==(const IP_Address &p_ip) const {
+ bool operator==(const IPAddress &p_ip) const {
if (p_ip.valid != valid) {
return false;
}
@@ -65,7 +65,7 @@ public:
return true;
}
- bool operator!=(const IP_Address &p_ip) const {
+ bool operator!=(const IPAddress &p_ip) const {
if (p_ip.valid != valid) {
return true;
}
@@ -91,9 +91,9 @@ public:
void set_ipv6(const uint8_t *p_buf);
operator String() const;
- IP_Address(const String &p_string);
- IP_Address(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d, bool is_v6 = false);
- IP_Address() { clear(); }
+ IPAddress(const String &p_string);
+ IPAddress(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d, bool is_v6 = false);
+ IPAddress() { clear(); }
};
#endif // IP_ADDRESS_H
diff --git a/core/io/json.cpp b/core/io/json.cpp
index 394cf216e8..82ef2a6894 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -55,7 +55,7 @@ static String _make_indent(const String &p_indent, int p_size) {
return indent_text;
}
-String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys) {
+String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision) {
String colon = ":";
String end_statement = "";
@@ -71,8 +71,17 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_
return p_var.operator bool() ? "true" : "false";
case Variant::INT:
return itos(p_var);
- case Variant::FLOAT:
- return rtos(p_var);
+ case Variant::FLOAT: {
+ double num = p_var;
+ if (p_full_precision) {
+ // Store unreliable digits (17) instead of just reliable
+ // digits (14) so that the value can be decoded exactly.
+ return String::num(num, 17 - (int)floor(log10(num)));
+ } else {
+ // Store only reliable digits (14) by default.
+ return String::num(num, 14 - (int)floor(log10(num)));
+ }
+ }
case Variant::PACKED_INT32_ARRAY:
case Variant::PACKED_INT64_ARRAY:
case Variant::PACKED_FLOAT32_ARRAY:
@@ -82,20 +91,29 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_
String s = "[";
s += end_statement;
Array a = p_var;
+
+ ERR_FAIL_COND_V_MSG(p_markers.has(a.id()), "\"[...]\"", "Converting circular structure to JSON.");
+ p_markers.insert(a.id());
+
for (int i = 0; i < a.size(); i++) {
if (i > 0) {
s += ",";
s += end_statement;
}
- s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(a[i], p_indent, p_cur_indent + 1, p_sort_keys);
+ s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(a[i], p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
}
s += end_statement + _make_indent(p_indent, p_cur_indent) + "]";
+ p_markers.erase(a.id());
return s;
}
case Variant::DICTIONARY: {
String s = "{";
s += end_statement;
Dictionary d = p_var;
+
+ ERR_FAIL_COND_V_MSG(p_markers.has(d.id()), "\"{...}\"", "Converting circular structure to JSON.");
+ p_markers.insert(d.id());
+
List<Variant> keys;
d.get_key_list(&keys);
@@ -108,12 +126,13 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_
s += ",";
s += end_statement;
}
- s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys);
+ s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
s += colon;
- s += _print_var(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys);
+ s += _print_var(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys, p_markers);
}
s += end_statement + _make_indent(p_indent, p_cur_indent) + "}";
+ p_markers.erase(d.id());
return s;
}
default:
@@ -121,8 +140,9 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_
}
}
-String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_keys) {
- return _print_var(p_var, p_indent, 0, p_sort_keys);
+String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
+ Set<const void *> markers;
+ return _print_var(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision);
}
Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) {
diff --git a/core/io/json.h b/core/io/json.h
index 537477666e..5be8cc1e86 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -31,7 +31,7 @@
#ifndef JSON_H
#define JSON_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/variant/variant.h"
class JSON {
enum TokenType {
@@ -62,7 +62,7 @@ class JSON {
static const char *tk_name[TK_MAX];
- static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys);
+ static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision = false);
static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
@@ -70,12 +70,12 @@ class JSON {
static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
public:
- static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true);
+ static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false);
static Error parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line);
};
-class JSONParser : public Reference {
- GDCLASS(JSONParser, Reference);
+class JSONParser : public RefCounted {
+ GDCLASS(JSONParser, RefCounted);
Variant data;
String string;
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index 8a07459a1d..09539f716c 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -31,8 +31,9 @@
#include "logger.h"
#include "core/config/project_settings.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "core/os/os.h"
+#include "core/os/time.h"
#include "core/string/print_string.h"
#if defined(MINGW_ENABLED) || defined(_MSC_VER)
@@ -156,11 +157,7 @@ void RotatedFileLogger::rotate_file() {
if (FileAccess::exists(base_path)) {
if (max_files > 1) {
- char timestamp[21];
- OS::Date date = OS::get_singleton()->get_date();
- OS::Time time = OS::get_singleton()->get_time();
- sprintf(timestamp, "_%04d-%02d-%02d_%02d.%02d.%02d", date.year, date.month, date.day, time.hour, time.min, time.sec);
-
+ String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace(":", ".");
String backup_name = base_path.get_basename() + timestamp;
if (base_path.get_extension() != String()) {
backup_name += "." + base_path.get_extension();
diff --git a/core/io/logger.h b/core/io/logger.h
index a12945911c..ccf68562d6 100644
--- a/core/io/logger.h
+++ b/core/io/logger.h
@@ -31,7 +31,7 @@
#ifndef LOGGER_H
#define LOGGER_H
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/string/ustring.h"
#include "core/templates/vector.h"
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index 218a612da2..4c58c84c14 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -30,7 +30,7 @@
#include "marshalls.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/os/keyboard.h"
#include "core/string/print_string.h"
@@ -279,9 +279,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
}
} break;
- case Variant::QUAT: {
+ case Variant::QUATERNION: {
ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA);
- Quat val;
+ Quaternion val;
val.x = decode_float(&buf[0]);
val.y = decode_float(&buf[4]);
val.z = decode_float(&buf[8]);
@@ -325,9 +325,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
}
} break;
- case Variant::TRANSFORM: {
+ case Variant::TRANSFORM3D: {
ERR_FAIL_COND_V(len < 4 * 12, ERR_INVALID_DATA);
- Transform val;
+ Transform3D val;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
val.basis.elements[i][j] = decode_float(&buf[(i * 3 + j) * 4]);
@@ -489,8 +489,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
obj->set(str, value);
}
- if (Object::cast_to<Reference>(obj)) {
- REF ref = REF(Object::cast_to<Reference>(obj));
+ if (Object::cast_to<RefCounted>(obj)) {
+ REF ref = REF(Object::cast_to<RefCounted>(obj));
r_variant = ref;
} else {
r_variant = obj;
@@ -851,7 +851,7 @@ static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) {
if (buf) {
encode_uint32(utf8.length(), buf);
buf += 4;
- copymem(buf, utf8.get_data(), utf8.length());
+ memcpy(buf, utf8.get_data(), utf8.length());
buf += utf8.length();
}
@@ -889,7 +889,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 nullptr instead.
+ // Object is invalid, send a nullptr instead.
if (buf) {
encode_uint32(Variant::NIL, buf);
}
@@ -995,7 +995,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
if (buf) {
encode_uint32(utf8.length(), buf);
buf += 4;
- copymem(buf, utf8.get_data(), utf8.length());
+ memcpy(buf, utf8.get_data(), utf8.length());
buf += pad + utf8.length();
}
@@ -1079,7 +1079,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
Transform2D val = p_variant;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
- copymem(&buf[(i * 2 + j) * 4], &val.elements[i][j], sizeof(float));
+ memcpy(&buf[(i * 2 + j) * 4], &val.elements[i][j], sizeof(float));
}
}
}
@@ -1099,9 +1099,9 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len += 4 * 4;
} break;
- case Variant::QUAT: {
+ case Variant::QUATERNION: {
if (buf) {
- Quat q = p_variant;
+ Quaternion q = p_variant;
encode_float(q.x, &buf[0]);
encode_float(q.y, &buf[4]);
encode_float(q.z, &buf[8]);
@@ -1130,7 +1130,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
Basis val = p_variant;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- copymem(&buf[(i * 3 + j) * 4], &val.elements[i][j], sizeof(float));
+ memcpy(&buf[(i * 3 + j) * 4], &val.elements[i][j], sizeof(float));
}
}
}
@@ -1138,12 +1138,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len += 9 * 4;
} break;
- case Variant::TRANSFORM: {
+ case Variant::TRANSFORM3D: {
if (buf) {
- Transform val = p_variant;
+ Transform3D val = p_variant;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- copymem(&buf[(i * 3 + j) * 4], &val.basis.elements[i][j], sizeof(float));
+ memcpy(&buf[(i * 3 + j) * 4], &val.basis.elements[i][j], sizeof(float));
}
}
@@ -1258,7 +1258,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
if (buf) {
encode_uint32(utf8.length()+1,buf);
buf+=4;
- copymem(buf,utf8.get_data(),utf8.length()+1);
+ memcpy(buf,utf8.get_data(),utf8.length()+1);
}
r_len+=4+utf8.length()+1;
@@ -1314,7 +1314,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
encode_uint32(datalen, buf);
buf += 4;
const uint8_t *r = data.ptr();
- copymem(buf, &r[0], datalen * datasize);
+ memcpy(buf, &r[0], datalen * datasize);
buf += datalen * datasize;
}
@@ -1412,7 +1412,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
if (buf) {
encode_uint32(utf8.length() + 1, buf);
buf += 4;
- copymem(buf, utf8.get_data(), utf8.length() + 1);
+ memcpy(buf, utf8.get_data(), utf8.length() + 1);
buf += utf8.length() + 1;
}
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
index cc0e9ba301..7fac708f97 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -31,7 +31,7 @@
#ifndef MARSHALLS_H
#define MARSHALLS_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/typedefs.h"
#include "core/variant/variant.h"
@@ -165,8 +165,8 @@ static inline double decode_double(const uint8_t *p_arr) {
return md.d;
}
-class EncodedObjectAsID : public Reference {
- GDCLASS(EncodedObjectAsID, Reference);
+class EncodedObjectAsID : public RefCounted {
+ GDCLASS(EncodedObjectAsID, RefCounted);
ObjectID id;
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 94060cfe0b..78ec7ea21a 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -44,6 +44,56 @@
#include "core/os/os.h"
#endif
+String _get_rpc_md5(const Node *p_node) {
+ String rpc_list;
+ const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods();
+ for (int i = 0; i < node_config.size(); i++) {
+ rpc_list += String(node_config[i].name);
+ }
+ if (p_node->get_script_instance()) {
+ const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods();
+ for (int i = 0; i < script_config.size(); i++) {
+ rpc_list += String(script_config[i].name);
+ }
+ }
+ return rpc_list.md5_text();
+}
+
+const MultiplayerAPI::RPCConfig _get_rpc_config(const Node *p_node, const StringName &p_method, uint16_t &r_id) {
+ const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods();
+ for (int i = 0; i < node_config.size(); i++) {
+ if (node_config[i].name == p_method) {
+ r_id = ((uint16_t)i) & (1 << 15);
+ return node_config[i];
+ }
+ }
+ if (p_node->get_script_instance()) {
+ const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods();
+ for (int i = 0; i < script_config.size(); i++) {
+ if (script_config[i].name == p_method) {
+ r_id = (uint16_t)i;
+ return script_config[i];
+ }
+ }
+ }
+ return MultiplayerAPI::RPCConfig();
+}
+
+const MultiplayerAPI::RPCConfig _get_rpc_config_by_id(Node *p_node, uint16_t p_id) {
+ Vector<MultiplayerAPI::RPCConfig> config;
+ uint16_t id = p_id;
+ if (id & (1 << 15)) {
+ id = id & ~(1 << 15);
+ config = p_node->get_node_rpc_methods();
+ } else {
+ config = p_node->get_script_instance()->get_rpc_methods();
+ }
+ if (id < config.size()) {
+ return config[p_id];
+ }
+ return MultiplayerAPI::RPCConfig();
+}
+
_FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_master, bool &r_skip_rpc) {
switch (mode) {
case MultiplayerAPI::RPC_MODE_DISABLED: {
@@ -231,8 +281,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
_process_confirm_path(p_from, p_packet, p_packet_len);
} break;
- case NETWORK_COMMAND_REMOTE_CALL:
- case NETWORK_COMMAND_REMOTE_SET: {
+ case NETWORK_COMMAND_REMOTE_CALL: {
// Extract packet meta
int packet_min_size = 1;
int name_id_offset = 1;
@@ -302,13 +351,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
}
const int packet_len = get_packet_len(node_target, p_packet_len);
- if (packet_type == NETWORK_COMMAND_REMOTE_CALL) {
- _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size);
-
- } else {
- _process_rset(node, name_id, p_from, p_packet, packet_len, packet_min_size);
- }
-
+ _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size);
} break;
case NETWORK_COMMAND_RAW: {
@@ -362,16 +405,11 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id,
ERR_FAIL_COND_MSG(p_offset > p_packet_len, "Invalid packet received. Size too small.");
// Check that remote can call the RPC on this node.
- StringName name = p_node->get_node_rpc_method(p_rpc_method_id);
- RPCMode rpc_mode = p_node->get_node_rpc_mode_by_id(p_rpc_method_id);
- if (name == StringName() && p_node->get_script_instance()) {
- name = p_node->get_script_instance()->get_rpc_method(p_rpc_method_id);
- rpc_mode = p_node->get_script_instance()->get_rpc_mode_by_id(p_rpc_method_id);
- }
- ERR_FAIL_COND(name == StringName());
+ const RPCConfig config = _get_rpc_config_by_id(p_node, p_rpc_method_id);
+ ERR_FAIL_COND(config.name == StringName());
- bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
- ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
+ bool can_call = _can_call_mode(p_node, config.rpc_mode, p_from);
+ ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(config.name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)config.rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
int argc = 0;
bool byte_only = false;
@@ -424,47 +462,14 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id,
Callable::CallError ce;
- p_node->call(name, (const Variant **)argp.ptr(), argc, ce);
+ p_node->call(config.name, (const Variant **)argp.ptr(), argc, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- String error = Variant::get_call_error_text(p_node, name, (const Variant **)argp.ptr(), argc, ce);
+ String error = Variant::get_call_error_text(p_node, config.name, (const Variant **)argp.ptr(), argc, ce);
error = "RPC - " + error;
ERR_PRINT(error);
}
}
-void MultiplayerAPI::_process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) {
- ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
-
- // Check that remote can call the RSET on this node.
- StringName name = p_node->get_node_rset_property(p_rpc_property_id);
- RPCMode rset_mode = p_node->get_node_rset_mode_by_id(p_rpc_property_id);
- if (name == StringName() && p_node->get_script_instance()) {
- name = p_node->get_script_instance()->get_rset_property(p_rpc_property_id);
- rset_mode = p_node->get_script_instance()->get_rset_mode_by_id(p_rpc_property_id);
- }
- ERR_FAIL_COND(name == StringName());
-
- bool can_call = _can_call_mode(p_node, rset_mode, p_from);
- ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
-
-#ifdef DEBUG_ENABLED
- _profile_node_data("in_rset", p_node->get_instance_id());
-#endif
-
- Variant value;
- 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.");
-
- bool valid;
-
- p_node->set(name, value, &valid);
- if (!valid) {
- String error = "Error setting remote property '" + String(name) + "', not found in object of type " + p_node->get_class() + ".";
- ERR_PRINT(error);
- }
-}
-
void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small.");
int ofs = 1;
@@ -487,7 +492,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 == nullptr);
- const bool valid_rpc_checksum = node->get_rpc_md5() == methods_md5;
+ const bool valid_rpc_checksum = _get_rpc_md5(node) == 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);
}
@@ -569,7 +574,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC
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();
+ const String methods_md5 = _get_rpc_md5(p_node);
const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder.
Vector<uint8_t> packet;
@@ -752,7 +757,7 @@ Error MultiplayerAPI::_decode_and_decompress_variant(Variant &r_variant, const u
return OK;
}
-void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) {
+void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) {
ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree.");
ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree.");
@@ -797,7 +802,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
// - `NetworkNameIdCompression` in the next 1 bit.
// - `byte_only_or_no_args` in the next 1 bit.
// - So we still have the last bit free!
- uint8_t command_type = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
+ uint8_t command_type = NETWORK_COMMAND_REMOTE_CALL;
uint8_t node_id_compression = UINT8_MAX;
uint8_t name_id_compression = UINT8_MAX;
bool byte_only_or_no_args = false;
@@ -837,81 +842,42 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
ofs += 4;
}
- if (p_set) {
- // Take the rpc property ID
- uint16_t property_id = p_from->get_node_rset_property_id(p_name);
- if (property_id == UINT16_MAX && p_from->get_script_instance()) {
- property_id = p_from->get_script_instance()->get_rset_property_id(p_name);
- }
- ERR_FAIL_COND_MSG(property_id == UINT16_MAX, "Unable to take the `property_id` for the property:" + p_name + ". this can happen only if this property is not marked as `remote`.");
-
- if (property_id <= UINT8_MAX) {
- // The ID fits in 1 byte
- name_id_compression = NETWORK_NAME_ID_COMPRESSION_8;
- MAKE_ROOM(ofs + 1);
- packet_cache.write[ofs] = static_cast<uint8_t>(property_id);
- ofs += 1;
- } else {
- // The ID is larger, let's use 2 bytes
- name_id_compression = NETWORK_NAME_ID_COMPRESSION_16;
- MAKE_ROOM(ofs + 2);
- encode_uint16(property_id, &(packet_cache.write[ofs]));
- ofs += 2;
- }
-
- // Set argument.
- int len(0);
- 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);
- ofs += len;
-
+ // Encode method ID
+ if (p_rpc_id <= UINT8_MAX) {
+ // The ID fits in 1 byte
+ name_id_compression = NETWORK_NAME_ID_COMPRESSION_8;
+ MAKE_ROOM(ofs + 1);
+ packet_cache.write[ofs] = static_cast<uint8_t>(p_rpc_id);
+ ofs += 1;
} else {
- // Take the rpc method ID
- uint16_t method_id = p_from->get_node_rpc_method_id(p_name);
- 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,
- 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
- name_id_compression = NETWORK_NAME_ID_COMPRESSION_8;
- MAKE_ROOM(ofs + 1);
- packet_cache.write[ofs] = static_cast<uint8_t>(method_id);
- ofs += 1;
- } else {
- // The ID is larger, let's use 2 bytes
- name_id_compression = NETWORK_NAME_ID_COMPRESSION_16;
- MAKE_ROOM(ofs + 2);
- encode_uint16(method_id, &(packet_cache.write[ofs]));
- ofs += 2;
- }
+ // The ID is larger, let's use 2 bytes
+ name_id_compression = NETWORK_NAME_ID_COMPRESSION_16;
+ MAKE_ROOM(ofs + 2);
+ encode_uint16(p_rpc_id, &(packet_cache.write[ofs]));
+ ofs += 2;
+ }
- if (p_argcount == 0) {
- byte_only_or_no_args = true;
- } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) {
- byte_only_or_no_args = true;
- // Special optimization when only the byte vector is sent.
- const Vector<uint8_t> data = *p_arg[0];
- MAKE_ROOM(ofs + data.size());
- copymem(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size());
- ofs += data.size();
- } else {
- // Arguments
- MAKE_ROOM(ofs + 1);
- packet_cache.write[ofs] = p_argcount;
- ofs += 1;
- for (int i = 0; i < p_argcount; i++) {
- int len(0);
- 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);
- ofs += len;
- }
+ if (p_argcount == 0) {
+ byte_only_or_no_args = true;
+ } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) {
+ byte_only_or_no_args = true;
+ // Special optimization when only the byte vector is sent.
+ const Vector<uint8_t> data = *p_arg[0];
+ MAKE_ROOM(ofs + data.size());
+ memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size());
+ ofs += data.size();
+ } else {
+ // Arguments
+ MAKE_ROOM(ofs + 1);
+ packet_cache.write[ofs] = p_argcount;
+ ofs += 1;
+ for (int i = 0; i < p_argcount; i++) {
+ int len(0);
+ 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);
+ ofs += len;
}
}
@@ -927,7 +893,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
#endif
// Take chance and set transfer mode, since all send methods will use it.
- network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
+ network_peer->set_transfer_mode(p_config.transfer_mode);
if (has_all_peers) {
// They all have verified paths, so send fast.
@@ -1015,19 +981,15 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
bool call_local_native = false;
bool call_local_script = false;
bool is_master = p_node->is_network_master();
-
+ uint16_t rpc_id = UINT16_MAX;
+ const RPCConfig config = _get_rpc_config(p_node, p_method, rpc_id);
+ ERR_FAIL_COND_MSG(config.name == StringName(),
+ vformat("Unable to get the RPC configuration for the function \"%s\" at path: \"%s\". This happens when the method is not marked for RPCs.", p_method, p_node->get_path()));
if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) {
- // Check that send mode can use local call.
-
- RPCMode rpc_mode = p_node->get_node_rpc_mode(p_method);
- call_local_native = _should_call_local(rpc_mode, is_master, skip_rpc);
-
- if (call_local_native) {
- // Done below.
- } else if (p_node->get_script_instance()) {
- // Attempt with script.
- rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method);
- call_local_script = _should_call_local(rpc_mode, is_master, skip_rpc);
+ if (rpc_id & (1 << 15)) {
+ call_local_native = _should_call_local(config.rpc_mode, is_master, skip_rpc);
+ } else {
+ call_local_script = _should_call_local(config.rpc_mode, is_master, skip_rpc);
}
}
@@ -1036,7 +998,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
_profile_node_data("out_rpc", p_node->get_instance_id());
#endif
- _send_rpc(p_node, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount);
+ _send_rpc(p_node, p_peer_id, rpc_id, config, p_method, p_arg, p_argcount);
}
if (call_local_native) {
@@ -1071,70 +1033,6 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
ERR_FAIL_COND_MSG(skip_rpc && !(call_local_native || call_local_script), "RPC '" + p_method + "' on yourself is not allowed by selected mode.");
}
-void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) {
- ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to RSET while no network peer is active.");
- ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to RSET on a node which is not inside SceneTree.");
- ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to send an RSET via a network peer which is not connected.");
-
- int node_id = network_peer->get_unique_id();
- bool is_master = p_node->is_network_master();
- bool skip_rset = node_id == p_peer_id;
- bool set_local = false;
-
- if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) {
- // Check that send mode can use local call.
- RPCMode rpc_mode = p_node->get_node_rset_mode(p_property);
- set_local = _should_call_local(rpc_mode, is_master, skip_rset);
-
- if (set_local) {
- bool valid;
- int temp_id = rpc_sender_id;
-
- rpc_sender_id = get_network_unique_id();
- p_node->set(p_property, p_value, &valid);
- rpc_sender_id = temp_id;
-
- if (!valid) {
- String error = "rset() aborted in local set, property not found: - " + String(p_property) + ".";
- ERR_PRINT(error);
- return;
- }
- } else if (p_node->get_script_instance()) {
- // Attempt with script.
- rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property);
-
- set_local = _should_call_local(rpc_mode, is_master, skip_rset);
-
- if (set_local) {
- int temp_id = rpc_sender_id;
-
- rpc_sender_id = get_network_unique_id();
- bool valid = p_node->get_script_instance()->set(p_property, p_value);
- rpc_sender_id = temp_id;
-
- if (!valid) {
- String error = "rset() aborted in local script set, property not found: - " + String(p_property) + ".";
- ERR_PRINT(error);
- return;
- }
- }
- }
- }
-
- if (skip_rset) {
- ERR_FAIL_COND_MSG(!set_local, "RSET for '" + p_property + "' on yourself is not allowed by selected mode.");
- return;
- }
-
-#ifdef DEBUG_ENABLED
- _profile_node_data("out_rset", p_node->get_instance_id());
-#endif
-
- const Variant *vptr = &p_value;
-
- _send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1);
-}
-
Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) {
ERR_FAIL_COND_V_MSG(p_data.size() < 1, ERR_INVALID_DATA, "Trying to send an empty raw packet.");
ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), ERR_UNCONFIGURED, "Trying to send a raw packet while no network peer is active.");
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index 7f88b53a27..43804a20ec 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -32,10 +32,39 @@
#define MULTIPLAYER_API_H
#include "core/io/networked_multiplayer_peer.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class MultiplayerAPI : public Reference {
- GDCLASS(MultiplayerAPI, Reference);
+class MultiplayerAPI : public RefCounted {
+ GDCLASS(MultiplayerAPI, RefCounted);
+
+public:
+ enum RPCMode {
+ RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
+ RPC_MODE_REMOTE, // Using rpc() on it will call method in all remote peers
+ RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote
+ RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets
+ RPC_MODE_REMOTESYNC, // Using rpc() on it will call method in all remote peers and locally
+ RPC_MODE_MASTERSYNC, // Using rpc() on it will call method in the master peer and locally
+ RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method in all puppets peers and locally
+ };
+
+ struct RPCConfig {
+ StringName name;
+ RPCMode rpc_mode = RPC_MODE_DISABLED;
+ NetworkedMultiplayerPeer::TransferMode transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE;
+ int channel = 0;
+
+ bool operator==(RPCConfig const &p_other) const {
+ return name == p_other.name;
+ }
+ };
+
+ struct SortRPCConfig {
+ StringName::AlphCompare compare;
+ bool operator()(const RPCConfig &p_a, const RPCConfig &p_b) const {
+ return compare(p_a.name, p_b.name);
+ }
+ };
private:
//path sent caches
@@ -72,10 +101,9 @@ protected:
void _process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len);
Node *_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len);
void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
- void _process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
void _process_raw(int p_from, const uint8_t *p_packet, int p_packet_len);
- void _send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount);
+ void _send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount);
bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target);
Error _encode_and_compress_variant(const Variant &p_variant, uint8_t *p_buffer, int &r_len);
@@ -84,7 +112,6 @@ protected:
public:
enum NetworkCommands {
NETWORK_COMMAND_REMOTE_CALL = 0,
- NETWORK_COMMAND_REMOTE_SET,
NETWORK_COMMAND_SIMPLIFY_PATH,
NETWORK_COMMAND_CONFIRM_PATH,
NETWORK_COMMAND_RAW,
@@ -101,16 +128,6 @@ public:
NETWORK_NAME_ID_COMPRESSION_16,
};
- enum RPCMode {
- RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
- RPC_MODE_REMOTE, // Using rpc() on it will call method / set property in all remote peers
- RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote
- RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets
- RPC_MODE_REMOTESYNC, // Using rpc() on it will call method / set property in all remote peers and locally
- RPC_MODE_MASTERSYNC, // Using rpc() on it will call method / set property in the master peer and locally
- RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method / set property in all puppets peers and locally
- };
-
void poll();
void clear();
void set_root_node(Node *p_node);
@@ -121,8 +138,6 @@ public:
// Called by Node.rpc
void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount);
- // Called by Node.rset
- void rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value);
void _add_peer(int p_id);
void _del_peer(int p_id);
diff --git a/core/io/net_socket.h b/core/io/net_socket.h
index bc09477693..fd7d50c704 100644
--- a/core/io/net_socket.h
+++ b/core/io/net_socket.h
@@ -32,9 +32,9 @@
#define NET_SOCKET_H
#include "core/io/ip.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class NetSocket : public Reference {
+class NetSocket : public RefCounted {
protected:
static NetSocket *(*_create)();
@@ -55,26 +55,27 @@ public:
virtual Error open(Type p_type, IP::Type &ip_type) = 0;
virtual void close() = 0;
- virtual Error bind(IP_Address p_addr, uint16_t p_port) = 0;
+ virtual Error bind(IPAddress p_addr, uint16_t p_port) = 0;
virtual Error listen(int p_max_pending) = 0;
- virtual Error connect_to_host(IP_Address p_addr, uint16_t p_port) = 0;
+ virtual Error connect_to_host(IPAddress p_addr, uint16_t p_port) = 0;
virtual Error poll(PollType p_type, int timeout) const = 0;
virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read) = 0;
- virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port, bool p_peek = false) = 0;
+ virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false) = 0;
virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent) = 0;
- virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) = 0;
- virtual Ref<NetSocket> accept(IP_Address &r_ip, uint16_t &r_port) = 0;
+ virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) = 0;
+ virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port) = 0;
virtual bool is_open() const = 0;
virtual int get_available_bytes() const = 0;
+ virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const = 0;
virtual Error set_broadcasting_enabled(bool p_enabled) = 0; // Returns OK if the socket option has been set successfully.
virtual void set_blocking_enabled(bool p_enabled) = 0;
virtual void set_ipv6_only_enabled(bool p_enabled) = 0;
virtual void set_tcp_no_delay_enabled(bool p_enabled) = 0;
virtual void set_reuse_address_enabled(bool p_enabled) = 0;
- virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name) = 0;
- virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) = 0;
+ virtual Error join_multicast_group(const IPAddress &p_multi_address, String p_if_name) = 0;
+ virtual Error leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) = 0;
};
#endif // NET_SOCKET_H
diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp
index a0b97772e6..cf6a0b6027 100644
--- a/core/io/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -123,6 +123,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b
uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const {
const uint8_t *rd = data.ptr();
+ ERR_FAIL_COND_V(!rd, 0);
const uint8_t *r = &rd[p_ofs];
uint32_t type = decode_uint32(r);
@@ -149,6 +150,10 @@ int PackedDataContainer::_size(uint32_t p_ofs) const {
Variant PackedDataContainer::_key_at_ofs(uint32_t p_ofs, const Variant &p_key, bool &err) const {
const uint8_t *rd = data.ptr();
+ if (!rd) {
+ err = true;
+ ERR_FAIL_COND_V(!rd, Variant());
+ }
const uint8_t *r = &rd[p_ofs];
uint32_t type = decode_uint32(r);
@@ -222,10 +227,10 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd
case Variant::VECTOR3:
case Variant::TRANSFORM2D:
case Variant::PLANE:
- case Variant::QUAT:
+ case Variant::QUATERNION:
case Variant::AABB:
case Variant::BASIS:
- case Variant::TRANSFORM:
+ case Variant::TRANSFORM3D:
case Variant::PACKED_BYTE_ARRAY:
case Variant::PACKED_INT32_ARRAY:
case Variant::PACKED_INT64_ARRAY:
@@ -317,7 +322,7 @@ Error PackedDataContainer::pack(const Variant &p_data) {
datalen = tmpdata.size();
data.resize(tmpdata.size());
uint8_t *w = data.ptrw();
- copymem(w, tmpdata.ptr(), tmpdata.size());
+ memcpy(w, tmpdata.ptr(), tmpdata.size());
return OK;
}
diff --git a/core/io/packed_data_container.h b/core/io/packed_data_container.h
index 7791e21bb3..40772bb2bf 100644
--- a/core/io/packed_data_container.h
+++ b/core/io/packed_data_container.h
@@ -80,8 +80,8 @@ public:
PackedDataContainer() {}
};
-class PackedDataContainerRef : public Reference {
- GDCLASS(PackedDataContainerRef, Reference);
+class PackedDataContainerRef : public RefCounted {
+ GDCLASS(PackedDataContainerRef, RefCounted);
friend class PackedDataContainer;
uint32_t offset = 0;
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
index 9e03c44750..9a345af3d0 100644
--- a/core/io/packet_peer.h
+++ b/core/io/packet_peer.h
@@ -35,8 +35,8 @@
#include "core/object/class_db.h"
#include "core/templates/ring_buffer.h"
-class PacketPeer : public Reference {
- GDCLASS(PacketPeer, Reference);
+class PacketPeer : public RefCounted {
+ GDCLASS(PacketPeer, RefCounted);
Variant _bnd_get_var(bool p_allow_objects = false);
diff --git a/core/io/packet_peer_dtls.cpp b/core/io/packet_peer_dtls.cpp
index bac98e20e7..a6d220622b 100644
--- a/core/io/packet_peer_dtls.cpp
+++ b/core/io/packet_peer_dtls.cpp
@@ -30,7 +30,7 @@
#include "packet_peer_dtls.h"
#include "core/config/project_settings.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
PacketPeerDTLS *(*PacketPeerDTLS::_create)() = nullptr;
bool PacketPeerDTLS::available = false;
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
index 3f46f2706e..f951a5158c 100644
--- a/core/io/packet_peer_udp.cpp
+++ b/core/io/packet_peer_udp.cpp
@@ -45,7 +45,7 @@ void PacketPeerUDP::set_broadcast_enabled(bool p_enabled) {
}
}
-Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_if_name) {
+Error PacketPeerUDP::join_multicast_group(IPAddress p_multi_address, String p_if_name) {
ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_multi_address.is_valid(), ERR_INVALID_PARAMETER);
@@ -60,7 +60,7 @@ Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_i
return _sock->join_multicast_group(p_multi_address, p_if_name);
}
-Error PacketPeerUDP::leave_multicast_group(IP_Address p_multi_address, String p_if_name) {
+Error PacketPeerUDP::leave_multicast_group(IPAddress p_multi_address, String p_if_name) {
ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!_sock->is_open(), ERR_UNCONFIGURED);
@@ -72,7 +72,7 @@ String PacketPeerUDP::_get_packet_ip() const {
}
Error PacketPeerUDP::_set_dest_address(const String &p_address, int p_port) {
- IP_Address ip;
+ IPAddress ip;
if (p_address.is_valid_ip_address()) {
ip = p_address;
} else {
@@ -159,10 +159,11 @@ int PacketPeerUDP::get_max_packet_size() const {
return 512; // uhm maybe not
}
-Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_recv_buffer_size) {
+Error PacketPeerUDP::bind(int p_port, const IPAddress &p_bind_address, int p_recv_buffer_size) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
Error err;
IP::Type ip_type = IP::TYPE_ANY;
@@ -189,7 +190,7 @@ Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_
return OK;
}
-Error PacketPeerUDP::connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *p_server) {
+Error PacketPeerUDP::connect_shared_socket(Ref<NetSocket> p_sock, IPAddress p_ip, uint16_t p_port, UDPServer *p_server) {
udp_server = p_server;
connected = true;
_sock = p_sock;
@@ -206,10 +207,11 @@ void PacketPeerUDP::disconnect_shared_socket() {
close();
}
-Error PacketPeerUDP::connect_to_host(const IP_Address &p_host, int p_port) {
+Error PacketPeerUDP::connect_to_host(const IPAddress &p_host, int p_port) {
ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, ERR_INVALID_PARAMETER, "The remote port number must be between 1 and 65535 (inclusive).");
Error err;
@@ -274,7 +276,7 @@ Error PacketPeerUDP::_poll() {
Error err;
int read;
- IP_Address ip;
+ IPAddress ip;
uint16_t port;
while (true) {
@@ -304,7 +306,7 @@ Error PacketPeerUDP::_poll() {
return OK;
}
-Error PacketPeerUDP::store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size) {
+Error PacketPeerUDP::store_packet(IPAddress p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size) {
if (rb.space_left() < p_buf_size + 24) {
return ERR_OUT_OF_MEMORY;
}
@@ -316,11 +318,11 @@ Error PacketPeerUDP::store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_b
return OK;
}
-bool PacketPeerUDP::is_listening() const {
+bool PacketPeerUDP::is_bound() const {
return _sock.is_valid() && _sock->is_open();
}
-IP_Address PacketPeerUDP::get_packet_address() const {
+IPAddress PacketPeerUDP::get_packet_address() const {
return packet_ip;
}
@@ -328,21 +330,28 @@ int PacketPeerUDP::get_packet_port() const {
return packet_port;
}
-void PacketPeerUDP::set_dest_address(const IP_Address &p_address, int p_port) {
+int PacketPeerUDP::get_local_port() const {
+ uint16_t local_port;
+ _sock->get_socket_address(nullptr, &local_port);
+ return local_port;
+}
+
+void PacketPeerUDP::set_dest_address(const IPAddress &p_address, int p_port) {
ERR_FAIL_COND_MSG(connected, "Destination address cannot be set for connected sockets");
peer_addr = p_address;
peer_port = p_port;
}
void PacketPeerUDP::_bind_methods() {
- ClassDB::bind_method(D_METHOD("listen", "port", "bind_address", "recv_buf_size"), &PacketPeerUDP::listen, DEFVAL("*"), DEFVAL(65536));
+ ClassDB::bind_method(D_METHOD("bind", "port", "bind_address", "recv_buf_size"), &PacketPeerUDP::bind, DEFVAL("*"), DEFVAL(65536));
ClassDB::bind_method(D_METHOD("close"), &PacketPeerUDP::close);
ClassDB::bind_method(D_METHOD("wait"), &PacketPeerUDP::wait);
- ClassDB::bind_method(D_METHOD("is_listening"), &PacketPeerUDP::is_listening);
+ ClassDB::bind_method(D_METHOD("is_bound"), &PacketPeerUDP::is_bound);
ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port"), &PacketPeerUDP::connect_to_host);
ClassDB::bind_method(D_METHOD("is_connected_to_host"), &PacketPeerUDP::is_connected_to_host);
ClassDB::bind_method(D_METHOD("get_packet_ip"), &PacketPeerUDP::_get_packet_ip);
ClassDB::bind_method(D_METHOD("get_packet_port"), &PacketPeerUDP::get_packet_port);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &PacketPeerUDP::get_local_port);
ClassDB::bind_method(D_METHOD("set_dest_address", "host", "port"), &PacketPeerUDP::_set_dest_address);
ClassDB::bind_method(D_METHOD("set_broadcast_enabled", "enabled"), &PacketPeerUDP::set_broadcast_enabled);
ClassDB::bind_method(D_METHOD("join_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::join_multicast_group);
diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h
index 4bac6994fc..40d3c44e40 100644
--- a/core/io/packet_peer_udp.h
+++ b/core/io/packet_peer_udp.h
@@ -48,11 +48,11 @@ protected:
RingBuffer<uint8_t> rb;
uint8_t recv_buffer[PACKET_BUFFER_SIZE];
uint8_t packet_buffer[PACKET_BUFFER_SIZE];
- IP_Address packet_ip;
+ IPAddress packet_ip;
int packet_port = 0;
int queue_count = 0;
- IP_Address peer_addr;
+ IPAddress peer_addr;
int peer_port = 0;
bool connected = false;
bool blocking = true;
@@ -70,28 +70,29 @@ protected:
public:
void set_blocking_mode(bool p_enable);
- Error listen(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536);
+ Error bind(int p_port, const IPAddress &p_bind_address = IPAddress("*"), int p_recv_buffer_size = 65536);
void close();
Error wait();
- bool is_listening() const;
+ bool is_bound() const;
- Error connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *ref); // Used by UDPServer
+ Error connect_shared_socket(Ref<NetSocket> p_sock, IPAddress p_ip, uint16_t p_port, UDPServer *ref); // Used by UDPServer
void disconnect_shared_socket(); // Used by UDPServer
- Error store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size); // Used internally and by UDPServer
- Error connect_to_host(const IP_Address &p_host, int p_port);
+ Error store_packet(IPAddress p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size); // Used internally and by UDPServer
+ Error connect_to_host(const IPAddress &p_host, int p_port);
bool is_connected_to_host() const;
- IP_Address get_packet_address() const;
+ IPAddress get_packet_address() const;
int get_packet_port() const;
- void set_dest_address(const IP_Address &p_address, int p_port);
+ int get_local_port() const;
+ void set_dest_address(const IPAddress &p_address, int p_port);
Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
int get_available_packet_count() const override;
int get_max_packet_size() const override;
void set_broadcast_enabled(bool p_enabled);
- Error join_multicast_group(IP_Address p_multi_address, String p_if_name);
- Error leave_multicast_group(IP_Address p_multi_address, String p_if_name);
+ Error join_multicast_group(IPAddress p_multi_address, String p_if_name);
+ Error leave_multicast_group(IPAddress p_multi_address, String p_if_name);
PacketPeerUDP();
~PacketPeerUDP();
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp
index a0697ca18b..806a95398f 100644
--- a/core/io/pck_packer.cpp
+++ b/core/io/pck_packer.cpp
@@ -31,9 +31,9 @@
#include "pck_packer.h"
#include "core/crypto/crypto_core.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/file_access_pack.h" // PACK_HEADER_MAGIC, PACK_FORMAT_VERSION
-#include "core/os/file_access.h"
#include "core/version.h"
static int _get_pad(int p_alignment, int p_n) {
@@ -120,7 +120,7 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encr
pf.path = p_file;
pf.src_path = p_src;
pf.ofs = ofs;
- pf.size = f->get_len();
+ pf.size = f->get_length();
Vector<uint8_t> data = FileAccess::get_file_as_array(p_src);
{
@@ -236,7 +236,7 @@ Error PCKPacker::flush(bool p_verbose) {
}
while (to_write > 0) {
- int read = src->get_buffer(buf, MIN(to_write, buf_max));
+ uint64_t read = src->get_buffer(buf, MIN(to_write, buf_max));
ftmp->store_buffer(buf, read);
to_write -= read;
}
diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h
index dec8f8748d..3d2ce8f240 100644
--- a/core/io/pck_packer.h
+++ b/core/io/pck_packer.h
@@ -31,12 +31,12 @@
#ifndef PCK_PACKER_H
#define PCK_PACKER_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
class FileAccess;
-class PCKPacker : public Reference {
- GDCLASS(PCKPacker, Reference);
+class PCKPacker : public RefCounted {
+ GDCLASS(PCKPacker, RefCounted);
FileAccess *file = nullptr;
int alignment = 0;
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 8560e2abc7..b970e85c99 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -31,9 +31,9 @@
#include "resource.h"
#include "core/core_string_names.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/object/script_language.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "scene/main/node.h" //only so casting works
@@ -110,6 +110,12 @@ String Resource::get_name() const {
return name;
}
+void Resource::update_configuration_warning() {
+ if (_update_configuration_warning) {
+ _update_configuration_warning();
+ }
+}
+
bool Resource::editor_can_reload_from_file() {
return true; //by default yes
}
@@ -320,6 +326,7 @@ void Resource::setup_local_to_scene() {
}
Node *(*Resource::_get_local_scene_func)() = nullptr;
+void (*Resource::_update_configuration_warning)() = nullptr;
void Resource::set_as_translation_remapped(bool p_remapped) {
if (remapped_list.in_list() == p_remapped) {
diff --git a/core/io/resource.h b/core/io/resource.h
index ae18ac0c8a..028fed1c6e 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -32,7 +32,7 @@
#define RESOURCE_H
#include "core/object/class_db.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/templates/safe_refcount.h"
#include "core/templates/self_list.h"
@@ -43,8 +43,8 @@ public:
\
private:
-class Resource : public Reference {
- GDCLASS(Resource, Reference);
+class Resource : public RefCounted {
+ GDCLASS(Resource, RefCounted);
OBJ_CATEGORY("Resources");
public:
@@ -88,7 +88,9 @@ protected:
public:
static Node *(*_get_local_scene_func)(); //used by editor
+ static void (*_update_configuration_warning)(); //used by editor
+ void update_configuration_warning();
virtual bool editor_can_reload_from_file();
virtual void reset_state(); //for resources that use variable amount of properties, either via _validate_property or _get_property_list, this function needs to be implemented to correctly clear state
virtual Error copy_from(const Ref<Resource> &p_resource);
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index c4eb2a20bb..f83ba30514 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -31,10 +31,10 @@
#include "resource_format_binary.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
#include "core/io/file_access_compressed.h"
#include "core/io/image.h"
#include "core/io/marshalls.h"
-#include "core/os/dir_access.h"
#include "core/version.h"
//#define print_bl(m_what) print_line(m_what)
@@ -51,7 +51,7 @@ enum {
VARIANT_RECT2 = 11,
VARIANT_VECTOR3 = 12,
VARIANT_PLANE = 13,
- VARIANT_QUAT = 14,
+ VARIANT_QUATERNION = 14,
VARIANT_AABB = 15,
VARIANT_MATRIX3 = 16,
VARIANT_TRANSFORM = 17,
@@ -199,8 +199,8 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
v.d = f->get_real();
r_v = v;
} break;
- case VARIANT_QUAT: {
- Quat v;
+ case VARIANT_QUATERNION: {
+ Quaternion v;
v.x = f->get_real();
v.y = f->get_real();
v.z = f->get_real();
@@ -245,7 +245,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
} break;
case VARIANT_TRANSFORM: {
- Transform v;
+ Transform3D v;
v.basis.elements[0].x = f->get_real();
v.basis.elements[0].y = f->get_real();
v.basis.elements[0].z = f->get_real();
@@ -851,7 +851,7 @@ void ResourceLoaderBinary::open(FileAccess *p_f) {
bool big_endian = f->get_32();
bool use_real64 = f->get_32();
- f->set_endian_swap(big_endian != 0); //read big endian if saved as big endian
+ f->set_big_endian(big_endian != 0); //read big endian if saved as big endian
uint32_t ver_major = f->get_32();
uint32_t ver_minor = f->get_32();
@@ -948,7 +948,7 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) {
bool big_endian = f->get_32();
f->get_32(); // use_real64
- f->set_endian_swap(big_endian != 0); //read big endian if saved as big endian
+ f->set_big_endian(big_endian != 0); //read big endian if saved as big endian
uint32_t ver_major = f->get_32();
f->get_32(); // ver_minor
@@ -1097,13 +1097,13 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
bool big_endian = f->get_32();
bool use_real64 = f->get_32();
- f->set_endian_swap(big_endian != 0); //read big endian if saved as big endian
+ f->set_big_endian(big_endian != 0); //read big endian if saved as big endian
#ifdef BIG_ENDIAN_ENABLED
fw->store_32(!big_endian);
#else
fw->store_32(big_endian);
#endif
- fw->set_endian_swap(big_endian != 0);
+ fw->set_big_endian(big_endian != 0);
fw->store_32(use_real64); //use real64
uint32_t ver_major = f->get_32();
@@ -1157,8 +1157,8 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
save_ustring(fw, get_ustring(f)); //type
- size_t md_ofs = f->get_position();
- size_t importmd_ofs = f->get_64();
+ uint64_t md_ofs = f->get_position();
+ uint64_t importmd_ofs = f->get_64();
fw->store_64(0); //metadata offset
for (int i = 0; i < 14; i++) {
@@ -1371,9 +1371,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
f->store_real(val.d);
} break;
- case Variant::QUAT: {
- f->store_32(VARIANT_QUAT);
- Quat val = p_property;
+ case Variant::QUATERNION: {
+ f->store_32(VARIANT_QUATERNION);
+ Quaternion val = p_property;
f->store_real(val.x);
f->store_real(val.y);
f->store_real(val.z);
@@ -1416,9 +1416,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
f->store_real(val.elements[2].z);
} break;
- case Variant::TRANSFORM: {
+ case Variant::TRANSFORM3D: {
f->store_32(VARIANT_TRANSFORM);
- Transform val = p_property;
+ Transform3D val = p_property;
f->store_real(val.basis.elements[0].x);
f->store_real(val.basis.elements[0].y);
f->store_real(val.basis.elements[0].z);
@@ -1798,7 +1798,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
if (big_endian) {
f->store_32(1);
- f->set_endian_swap(true);
+ f->set_big_endian(true);
} else {
f->store_32(0);
}
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 3592bbdbc4..abc7403935 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -31,9 +31,9 @@
#ifndef RESOURCE_FORMAT_BINARY_H
#define RESOURCE_FORMAT_BINARY_H
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
class ResourceLoaderBinary {
bool translation_remapped = false;
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index a14d6ba52c..2ceeb176e5 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -93,8 +93,8 @@ public:
ResourceFormatImporter();
};
-class ResourceImporter : public Reference {
- GDCLASS(ResourceImporter, Reference);
+class ResourceImporter : public RefCounted {
+ GDCLASS(ResourceImporter, RefCounted);
public:
virtual String get_importer_name() const = 0;
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index dcf71bb4a9..1700766cbf 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -31,8 +31,8 @@
#include "resource_loader.h"
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/resource_importer.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
@@ -68,17 +68,17 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_
}
bool ResourceFormatLoader::handles_type(const String &p_type) const {
- if (get_script_instance() && get_script_instance()->has_method("handles_type")) {
+ if (get_script_instance() && get_script_instance()->has_method("_handles_type")) {
// I guess custom loaders for custom resources should use "Resource"
- return get_script_instance()->call("handles_type", p_type);
+ return get_script_instance()->call("_handles_type", p_type);
}
return false;
}
String ResourceFormatLoader::get_resource_type(const String &p_path) const {
- if (get_script_instance() && get_script_instance()->has_method("get_resource_type")) {
- return get_script_instance()->call("get_resource_type", p_path);
+ if (get_script_instance() && get_script_instance()->has_method("_get_resource_type")) {
+ return get_script_instance()->call("_get_resource_type", p_path);
}
return "";
@@ -101,8 +101,8 @@ bool ResourceFormatLoader::exists(const String &p_path) const {
}
void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) const {
- if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) {
- PackedStringArray exts = get_script_instance()->call("get_recognized_extensions");
+ if (get_script_instance() && get_script_instance()->has_method("_get_recognized_extensions")) {
+ PackedStringArray exts = get_script_instance()->call("_get_recognized_extensions");
{
const String *r = exts.ptr();
@@ -114,30 +114,29 @@ void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions)
}
RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- if (get_script_instance() && get_script_instance()->has_method("load")) {
- Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads, p_cache_mode);
+ // Check user-defined loader if there's any. Hard fail if it returns an error.
+ if (get_script_instance() && get_script_instance()->has_method("_load")) {
+ Variant res = get_script_instance()->call("_load", p_path, p_original_path, p_use_sub_threads, p_cache_mode);
- if (res.get_type() == Variant::INT) {
+ if (res.get_type() == Variant::INT) { // Error code, abort.
if (r_error) {
*r_error = (Error)res.operator int64_t();
}
-
- } else {
+ return RES();
+ } else { // Success, pass on result.
if (r_error) {
*r_error = OK;
}
return res;
}
-
- return res;
}
- ERR_FAIL_V_MSG(RES(), "Failed to load resource '" + p_path + "', ResourceFormatLoader::load was not implemented for this resource type.");
+ ERR_FAIL_V_MSG(RES(), "Failed to load resource '" + p_path + "'. ResourceFormatLoader::load was not implemented for this resource type.");
}
void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
- if (get_script_instance() && get_script_instance()->has_method("get_dependencies")) {
- PackedStringArray deps = get_script_instance()->call("get_dependencies", p_path, p_add_types);
+ if (get_script_instance() && get_script_instance()->has_method("_get_dependencies")) {
+ PackedStringArray deps = get_script_instance()->call("_get_dependencies", p_path, p_add_types);
{
const String *r = deps.ptr();
@@ -149,13 +148,13 @@ void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *
}
Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map<String, String> &p_map) {
- if (get_script_instance() && get_script_instance()->has_method("rename_dependencies")) {
+ if (get_script_instance() && get_script_instance()->has_method("_rename_dependencies")) {
Dictionary deps_dict;
for (Map<String, String>::Element *E = p_map.front(); E; E = E->next()) {
deps_dict[E->key()] = E->value();
}
- int64_t res = get_script_instance()->call("rename_dependencies", deps_dict);
+ int64_t res = get_script_instance()->call("_rename_dependencies", deps_dict);
return (Error)res;
}
@@ -164,16 +163,16 @@ Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map<
void ResourceFormatLoader::_bind_methods() {
{
- MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode"));
+ MethodInfo info = MethodInfo(Variant::NIL, "_load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode"));
info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- ClassDB::add_virtual_method(get_class_static(), info);
+ BIND_VMETHOD(info);
}
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_recognized_extensions"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles_type", PropertyInfo(Variant::STRING_NAME, "typename")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type", PropertyInfo(Variant::STRING, "path")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames")));
+ BIND_VMETHOD(MethodInfo(Variant::PACKED_STRING_ARRAY, "_get_recognized_extensions"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_handles_type", PropertyInfo(Variant::STRING_NAME, "typename")));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_resource_type", PropertyInfo(Variant::STRING, "path")));
+ BIND_VMETHOD(MethodInfo("_get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types")));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames")));
BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE);
BIND_ENUM_CONSTANT(CACHE_MODE_REUSE);
@@ -355,7 +354,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
ThreadLoadTask &load_task = thread_load_tasks[local_path];
- if (load_task.resource.is_null()) { //needs to be loaded in thread
+ if (load_task.resource.is_null()) { //needs to be loaded in thread
load_task.semaphore = memnew(Semaphore);
if (thread_loading_count < thread_load_max) {
@@ -868,7 +867,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
continue;
}
- String l = res_remaps[i].right(split + 1).strip_edges();
+ String l = res_remaps[i].substr(split + 1).strip_edges();
if (l == locale) { // Exact match.
new_path = res_remaps[i].left(split);
break;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 914d988caa..c656b9a69c 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -35,8 +35,8 @@
#include "core/os/semaphore.h"
#include "core/os/thread.h"
-class ResourceFormatLoader : public Reference {
- GDCLASS(ResourceFormatLoader, Reference);
+class ResourceFormatLoader : public RefCounted {
+ GDCLASS(ResourceFormatLoader, RefCounted);
public:
enum CacheMode {
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 7ebc7f34b3..389a4fdbbd 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -30,9 +30,9 @@
#include "resource_saver.h"
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/object/script_language.h"
-#include "core/os/file_access.h"
Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS];
@@ -41,24 +41,24 @@ bool ResourceSaver::timestamp_on_save = false;
ResourceSavedCallback ResourceSaver::save_callback = nullptr;
Error ResourceFormatSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
- if (get_script_instance() && get_script_instance()->has_method("save")) {
- return (Error)get_script_instance()->call("save", p_path, p_resource, p_flags).operator int64_t();
+ if (get_script_instance() && get_script_instance()->has_method("_save")) {
+ return (Error)get_script_instance()->call("_save", p_path, p_resource, p_flags).operator int64_t();
}
return ERR_METHOD_NOT_FOUND;
}
bool ResourceFormatSaver::recognize(const RES &p_resource) const {
- if (get_script_instance() && get_script_instance()->has_method("recognize")) {
- return get_script_instance()->call("recognize", p_resource);
+ if (get_script_instance() && get_script_instance()->has_method("_recognize")) {
+ return get_script_instance()->call("_recognize", p_resource);
}
return false;
}
void ResourceFormatSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
- if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) {
- PackedStringArray exts = get_script_instance()->call("get_recognized_extensions", p_resource);
+ if (get_script_instance() && get_script_instance()->has_method("_get_recognized_extensions")) {
+ PackedStringArray exts = get_script_instance()->call("_get_recognized_extensions", p_resource);
{
const String *r = exts.ptr();
@@ -74,11 +74,11 @@ void ResourceFormatSaver::_bind_methods() {
PropertyInfo arg0 = PropertyInfo(Variant::STRING, "path");
PropertyInfo arg1 = PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource");
PropertyInfo arg2 = PropertyInfo(Variant::INT, "flags");
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "save", arg0, arg1, arg2));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_save", arg0, arg1, arg2));
}
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_recognized_extensions", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "recognize", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
+ BIND_VMETHOD(MethodInfo(Variant::PACKED_STRING_ARRAY, "_get_recognized_extensions", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_recognize", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
}
Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 2c9e8f1aa3..07154aac4d 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -33,8 +33,8 @@
#include "core/io/resource.h"
-class ResourceFormatSaver : public Reference {
- GDCLASS(ResourceFormatSaver, Reference);
+class ResourceFormatSaver : public RefCounted {
+ GDCLASS(ResourceFormatSaver, RefCounted);
protected:
static void _bind_methods();
diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp
index 8407d55196..ee5e9eca0c 100644
--- a/core/io/stream_peer.cpp
+++ b/core/io/stream_peer.cpp
@@ -108,8 +108,8 @@ Array StreamPeer::_get_partial_data(int p_bytes) {
return ret;
}
-void StreamPeer::set_big_endian(bool p_enable) {
- big_endian = p_enable;
+void StreamPeer::set_big_endian(bool p_big_endian) {
+ big_endian = p_big_endian;
}
bool StreamPeer::is_big_endian_enabled() const {
@@ -433,7 +433,7 @@ Error StreamPeerBuffer::put_data(const uint8_t *p_data, int p_bytes) {
}
uint8_t *w = data.ptrw();
- copymem(&w[pointer], p_data, p_bytes);
+ memcpy(&w[pointer], p_data, p_bytes);
pointer += p_bytes;
return OK;
@@ -466,7 +466,7 @@ Error StreamPeerBuffer::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_
}
const uint8_t *r = data.ptr();
- copymem(p_buffer, r + pointer, r_received);
+ memcpy(p_buffer, r + pointer, r_received);
pointer += r_received;
// FIXME: return what? OK or ERR_*
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index dadedbd2dc..effc3850af 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -31,10 +31,10 @@
#ifndef STREAM_PEER_H
#define STREAM_PEER_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class StreamPeer : public Reference {
- GDCLASS(StreamPeer, Reference);
+class StreamPeer : public RefCounted {
+ GDCLASS(StreamPeer, RefCounted);
OBJ_CATEGORY("Networking");
protected:
@@ -58,7 +58,7 @@ public:
virtual int get_available_bytes() const = 0;
- void set_big_endian(bool p_enable);
+ void set_big_endian(bool p_big_endian);
bool is_big_endian_enabled() const;
void put_8(int8_t p_val);
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
index 760710a9eb..5b794274ca 100644
--- a/core/io/stream_peer_tcp.cpp
+++ b/core/io/stream_peer_tcp.cpp
@@ -56,7 +56,7 @@ Error StreamPeerTCP::_poll_connection() {
return ERR_CONNECTION_ERROR;
}
-void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint16_t p_port) {
+void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IPAddress p_host, uint16_t p_port) {
_sock = p_sock;
_sock->set_blocking_enabled(false);
@@ -67,21 +67,40 @@ void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint
peer_port = p_port;
}
-Error StreamPeerTCP::connect_to_host(const IP_Address &p_host, uint16_t p_port) {
+Error StreamPeerTCP::bind(int p_port, const IPAddress &p_host) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
- ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
- Error err;
IP::Type ip_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
+ if (p_host.is_wildcard()) {
+ ip_type = IP::TYPE_ANY;
+ }
+ Error err = _sock->open(NetSocket::TYPE_TCP, ip_type);
+ if (err != OK) {
+ return err;
+ }
+ _sock->set_blocking_enabled(false);
+ return _sock->bind(p_host, p_port);
+}
- err = _sock->open(NetSocket::TYPE_TCP, ip_type);
- ERR_FAIL_COND_V(err != OK, FAILED);
+Error StreamPeerTCP::connect_to_host(const IPAddress &p_host, int p_port) {
+ ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
+ ERR_FAIL_COND_V(status != STATUS_NONE, ERR_ALREADY_IN_USE);
+ ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, ERR_INVALID_PARAMETER, "The remote port number must be between 1 and 65535 (inclusive).");
- _sock->set_blocking_enabled(false);
+ if (!_sock->is_open()) {
+ IP::Type ip_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
+ Error err = _sock->open(NetSocket::TYPE_TCP, ip_type);
+ if (err != OK) {
+ return err;
+ }
+ _sock->set_blocking_enabled(false);
+ }
timeout = OS::get_singleton()->get_ticks_msec() + (((uint64_t)GLOBAL_GET("network/limits/tcp/connect_timeout_seconds")) * 1000);
- err = _sock->connect_to_host(p_host, p_port);
+ Error err = _sock->connect_to_host(p_host, p_port);
if (err == OK) {
status = STATUS_CONNECTED;
@@ -264,7 +283,7 @@ void StreamPeerTCP::disconnect_from_host() {
timeout = 0;
status = STATUS_NONE;
- peer_host = IP_Address();
+ peer_host = IPAddress();
peer_port = 0;
}
@@ -296,16 +315,22 @@ int StreamPeerTCP::get_available_bytes() const {
return _sock->get_available_bytes();
}
-IP_Address StreamPeerTCP::get_connected_host() const {
+IPAddress StreamPeerTCP::get_connected_host() const {
return peer_host;
}
-uint16_t StreamPeerTCP::get_connected_port() const {
+int StreamPeerTCP::get_connected_port() const {
return peer_port;
}
+int StreamPeerTCP::get_local_port() const {
+ uint16_t local_port;
+ _sock->get_socket_address(nullptr, &local_port);
+ return local_port;
+}
+
Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
- IP_Address ip;
+ IPAddress ip;
if (p_address.is_valid_ip_address()) {
ip = p_address;
} else {
@@ -319,11 +344,13 @@ Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
}
void StreamPeerTCP::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("bind", "port", "host"), &StreamPeerTCP::bind, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port"), &StreamPeerTCP::_connect);
ClassDB::bind_method(D_METHOD("is_connected_to_host"), &StreamPeerTCP::is_connected_to_host);
ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerTCP::get_status);
ClassDB::bind_method(D_METHOD("get_connected_host"), &StreamPeerTCP::get_connected_host);
ClassDB::bind_method(D_METHOD("get_connected_port"), &StreamPeerTCP::get_connected_port);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &StreamPeerTCP::get_local_port);
ClassDB::bind_method(D_METHOD("disconnect_from_host"), &StreamPeerTCP::disconnect_from_host);
ClassDB::bind_method(D_METHOD("set_no_delay", "enabled"), &StreamPeerTCP::set_no_delay);
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index 10b90908d4..a2a7f447d8 100644
--- a/core/io/stream_peer_tcp.h
+++ b/core/io/stream_peer_tcp.h
@@ -52,7 +52,7 @@ protected:
Ref<NetSocket> _sock;
uint64_t timeout = 0;
Status status = STATUS_NONE;
- IP_Address peer_host;
+ IPAddress peer_host;
uint16_t peer_port = 0;
Error _connect(const String &p_address, int p_port);
@@ -63,12 +63,14 @@ protected:
static void _bind_methods();
public:
- void accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint16_t p_port);
+ void accept_socket(Ref<NetSocket> p_sock, IPAddress p_host, uint16_t p_port);
- Error connect_to_host(const IP_Address &p_host, uint16_t p_port);
+ Error bind(int p_port, const IPAddress &p_host);
+ Error connect_to_host(const IPAddress &p_host, int p_port);
bool is_connected_to_host() const;
- IP_Address get_connected_host() const;
- uint16_t get_connected_port() const;
+ IPAddress get_connected_host() const;
+ int get_connected_port() const;
+ int get_local_port() const;
void disconnect_from_host();
int get_available_bytes() const override;
diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp
index 323d2bbd7f..b760a9ef80 100644
--- a/core/io/tcp_server.cpp
+++ b/core/io/tcp_server.cpp
@@ -30,18 +30,20 @@
#include "tcp_server.h"
-void TCP_Server::_bind_methods() {
- ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &TCP_Server::listen, DEFVAL("*"));
- ClassDB::bind_method(D_METHOD("is_connection_available"), &TCP_Server::is_connection_available);
- ClassDB::bind_method(D_METHOD("is_listening"), &TCP_Server::is_listening);
- ClassDB::bind_method(D_METHOD("take_connection"), &TCP_Server::take_connection);
- ClassDB::bind_method(D_METHOD("stop"), &TCP_Server::stop);
+void TCPServer::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &TCPServer::listen, DEFVAL("*"));
+ ClassDB::bind_method(D_METHOD("is_connection_available"), &TCPServer::is_connection_available);
+ ClassDB::bind_method(D_METHOD("is_listening"), &TCPServer::is_listening);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &TCPServer::get_local_port);
+ ClassDB::bind_method(D_METHOD("take_connection"), &TCPServer::take_connection);
+ ClassDB::bind_method(D_METHOD("stop"), &TCPServer::stop);
}
-Error TCP_Server::listen(uint16_t p_port, const IP_Address &p_bind_address) {
+Error TCPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
Error err;
IP::Type ip_type = IP::TYPE_ANY;
@@ -74,13 +76,19 @@ Error TCP_Server::listen(uint16_t p_port, const IP_Address &p_bind_address) {
return OK;
}
-bool TCP_Server::is_listening() const {
+int TCPServer::get_local_port() const {
+ uint16_t local_port;
+ _sock->get_socket_address(nullptr, &local_port);
+ return local_port;
+}
+
+bool TCPServer::is_listening() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false);
return _sock->is_open();
}
-bool TCP_Server::is_connection_available() const {
+bool TCPServer::is_connection_available() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false);
if (!_sock->is_open()) {
@@ -91,14 +99,14 @@ bool TCP_Server::is_connection_available() const {
return (err == OK);
}
-Ref<StreamPeerTCP> TCP_Server::take_connection() {
+Ref<StreamPeerTCP> TCPServer::take_connection() {
Ref<StreamPeerTCP> conn;
if (!is_connection_available()) {
return conn;
}
Ref<NetSocket> ns;
- IP_Address ip;
+ IPAddress ip;
uint16_t port = 0;
ns = _sock->accept(ip, port);
if (!ns.is_valid()) {
@@ -110,16 +118,16 @@ Ref<StreamPeerTCP> TCP_Server::take_connection() {
return conn;
}
-void TCP_Server::stop() {
+void TCPServer::stop() {
if (_sock.is_valid()) {
_sock->close();
}
}
-TCP_Server::TCP_Server() :
+TCPServer::TCPServer() :
_sock(Ref<NetSocket>(NetSocket::create())) {
}
-TCP_Server::~TCP_Server() {
+TCPServer::~TCPServer() {
stop();
}
diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h
index f06ddd2d99..10985a04d5 100644
--- a/core/io/tcp_server.h
+++ b/core/io/tcp_server.h
@@ -36,8 +36,8 @@
#include "core/io/stream_peer.h"
#include "core/io/stream_peer_tcp.h"
-class TCP_Server : public Reference {
- GDCLASS(TCP_Server, Reference);
+class TCPServer : public RefCounted {
+ GDCLASS(TCPServer, RefCounted);
protected:
enum {
@@ -48,15 +48,16 @@ protected:
static void _bind_methods();
public:
- Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
+ Error listen(uint16_t p_port, const IPAddress &p_bind_address = IPAddress("*"));
+ int get_local_port() const;
bool is_listening() const;
bool is_connection_available() const;
Ref<StreamPeerTCP> take_connection();
void stop(); // Stop listening
- TCP_Server();
- ~TCP_Server();
+ TCPServer();
+ ~TCPServer();
};
#endif // TCP_SERVER_H
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 9adf912224..83d575cee8 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -30,7 +30,7 @@
#include "translation_loader_po.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/string/translation.h"
#include "core/string/translation_po.h"
diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h
index 36d33fcac3..c52820e60d 100644
--- a/core/io/translation_loader_po.h
+++ b/core/io/translation_loader_po.h
@@ -31,8 +31,8 @@
#ifndef TRANSLATION_LOADER_PO_H
#define TRANSLATION_LOADER_PO_H
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
-#include "core/os/file_access.h"
#include "core/string/translation.h"
class TranslationLoaderPO : public ResourceFormatLoader {
diff --git a/core/io/udp_server.cpp b/core/io/udp_server.cpp
index f56fb431ef..6a1af0c2a9 100644
--- a/core/io/udp_server.cpp
+++ b/core/io/udp_server.cpp
@@ -34,6 +34,7 @@ void UDPServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &UDPServer::listen, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("poll"), &UDPServer::poll);
ClassDB::bind_method(D_METHOD("is_connection_available"), &UDPServer::is_connection_available);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &UDPServer::get_local_port);
ClassDB::bind_method(D_METHOD("is_listening"), &UDPServer::is_listening);
ClassDB::bind_method(D_METHOD("take_connection"), &UDPServer::take_connection);
ClassDB::bind_method(D_METHOD("stop"), &UDPServer::stop);
@@ -49,7 +50,7 @@ Error UDPServer::poll() {
}
Error err;
int read;
- IP_Address ip;
+ IPAddress ip;
uint16_t port;
while (true) {
err = _sock->recvfrom(recv_buffer, sizeof(recv_buffer), read, ip, port);
@@ -86,10 +87,11 @@ Error UDPServer::poll() {
return OK;
}
-Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) {
+Error UDPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
Error err;
IP::Type ip_type = IP::TYPE_ANY;
@@ -112,11 +114,15 @@ Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) {
stop();
return err;
}
- bind_address = p_bind_address;
- bind_port = p_port;
return OK;
}
+int UDPServer::get_local_port() const {
+ uint16_t local_port;
+ _sock->get_socket_address(nullptr, &local_port);
+ return local_port;
+}
+
bool UDPServer::is_listening() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false);
@@ -162,7 +168,7 @@ Ref<PacketPeerUDP> UDPServer::take_connection() {
return peer.peer;
}
-void UDPServer::remove_peer(IP_Address p_ip, int p_port) {
+void UDPServer::remove_peer(IPAddress p_ip, int p_port) {
Peer peer;
peer.ip = p_ip;
peer.port = p_port;
@@ -176,8 +182,6 @@ void UDPServer::stop() {
if (_sock.is_valid()) {
_sock->close();
}
- bind_port = 0;
- bind_address = IP_Address();
List<Peer>::Element *E = peers.front();
while (E) {
E->get().peer->disconnect_shared_socket();
diff --git a/core/io/udp_server.h b/core/io/udp_server.h
index bbd2f951c9..e49a559c51 100644
--- a/core/io/udp_server.h
+++ b/core/io/udp_server.h
@@ -34,8 +34,8 @@
#include "core/io/net_socket.h"
#include "core/io/packet_peer_udp.h"
-class UDPServer : public Reference {
- GDCLASS(UDPServer, Reference);
+class UDPServer : public RefCounted {
+ GDCLASS(UDPServer, RefCounted);
protected:
enum {
@@ -44,7 +44,7 @@ protected:
struct Peer {
PacketPeerUDP *peer;
- IP_Address ip;
+ IPAddress ip;
uint16_t port = 0;
bool operator==(const Peer &p_other) const {
@@ -53,21 +53,18 @@ protected:
};
uint8_t recv_buffer[PACKET_BUFFER_SIZE];
- int bind_port = 0;
- IP_Address bind_address;
-
List<Peer> peers;
List<Peer> pending;
int max_pending_connections = 16;
Ref<NetSocket> _sock;
-
static void _bind_methods();
public:
- void remove_peer(IP_Address p_ip, int p_port);
- Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
+ void remove_peer(IPAddress p_ip, int p_port);
+ Error listen(uint16_t p_port, const IPAddress &p_bind_address = IPAddress("*"));
Error poll();
+ int get_local_port() const;
bool is_listening() const;
bool is_connection_available() const;
void set_max_pending_connections(int p_max);
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index d5eb32513b..938d93a01b 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -75,7 +75,7 @@ void XMLParser::_parse_closing_xml_element() {
++P;
const char *pBeginClose = P;
- while (*P != '>') {
+ while (*P && *P != '>') {
++P;
}
@@ -83,7 +83,10 @@ void XMLParser::_parse_closing_xml_element() {
#ifdef DEBUG_XML
print_line("XML CLOSE: " + node_name);
#endif
- ++P;
+
+ if (*P) {
+ ++P;
+ }
}
void XMLParser::_ignore_definition() {
@@ -91,11 +94,14 @@ void XMLParser::_ignore_definition() {
char *F = P;
// move until end marked with '>' reached
- while (*P != '>') {
+ while (*P && *P != '>') {
++P;
}
node_name.parse_utf8(F, P - F);
- ++P;
+
+ if (*P) {
+ ++P;
+ }
}
bool XMLParser::_parse_cdata() {
@@ -113,6 +119,7 @@ bool XMLParser::_parse_cdata() {
}
if (!*P) {
+ node_name = "";
return true;
}
@@ -131,10 +138,9 @@ bool XMLParser::_parse_cdata() {
}
if (cDataEnd) {
- node_name = String::utf8(cDataBegin, (int)(cDataEnd - cDataBegin));
- } else {
- node_name = "";
+ cDataEnd = P;
}
+ node_name = String::utf8(cDataBegin, (int)(cDataEnd - cDataBegin));
#ifdef DEBUG_XML
print_line("XML CDATA: " + node_name);
#endif
@@ -146,24 +152,45 @@ void XMLParser::_parse_comment() {
node_type = NODE_COMMENT;
P += 1;
- char *pCommentBegin = P;
+ char *pEndOfInput = data + length;
+ char *pCommentBegin;
+ char *pCommentEnd;
- int count = 1;
-
- // move until end of comment reached
- while (count) {
- if (*P == '>') {
- --count;
- } else if (*P == '<') {
- ++count;
+ if (P + 1 < pEndOfInput && P[0] == '-' && P[1] == '-') {
+ // Comment, use '-->' as end.
+ pCommentBegin = P + 2;
+ for (pCommentEnd = pCommentBegin; pCommentEnd + 2 < pEndOfInput; pCommentEnd++) {
+ if (pCommentEnd[0] == '-' && pCommentEnd[1] == '-' && pCommentEnd[2] == '>') {
+ break;
+ }
+ }
+ if (pCommentEnd + 2 < pEndOfInput) {
+ P = pCommentEnd + 3;
+ } else {
+ P = pCommentEnd = pEndOfInput;
+ }
+ } else {
+ // Like document type definition, match angle brackets.
+ pCommentBegin = P;
+
+ int count = 1;
+ while (*P && count) {
+ if (*P == '>') {
+ --count;
+ } else if (*P == '<') {
+ ++count;
+ }
+ ++P;
}
- ++P;
+ if (count) {
+ pCommentEnd = P;
+ } else {
+ pCommentEnd = P - 1;
+ }
}
- P -= 3;
- node_name = String::utf8(pCommentBegin + 2, (int)(P - pCommentBegin - 2));
- P += 3;
+ node_name = String::utf8(pCommentBegin, (int)(pCommentEnd - pCommentBegin));
#ifdef DEBUG_XML
print_line("XML COMMENT: " + node_name);
#endif
@@ -178,14 +205,14 @@ void XMLParser::_parse_opening_xml_element() {
const char *startName = P;
// find end of element
- while (*P != '>' && !_is_white_space(*P)) {
+ while (*P && *P != '>' && !_is_white_space(*P)) {
++P;
}
const char *endName = P;
// find attributes
- while (*P != '>') {
+ while (*P && *P != '>') {
if (_is_white_space(*P)) {
++P;
} else {
@@ -195,10 +222,14 @@ void XMLParser::_parse_opening_xml_element() {
// read the attribute names
const char *attributeNameBegin = P;
- while (!_is_white_space(*P) && *P != '=') {
+ while (*P && !_is_white_space(*P) && *P != '=') {
++P;
}
+ if (!*P) {
+ break;
+ }
+
const char *attributeNameEnd = P;
++P;
@@ -209,7 +240,7 @@ void XMLParser::_parse_opening_xml_element() {
}
if (!*P) { // malformatted xml file
- return;
+ break;
}
const char attributeQuoteChar = *P;
@@ -221,12 +252,10 @@ void XMLParser::_parse_opening_xml_element() {
++P;
}
- if (!*P) { // malformatted xml file
- return;
- }
-
const char *attributeValueEnd = P;
- ++P;
+ if (*P) {
+ ++P;
+ }
Attribute attr;
attr.name = String::utf8(attributeNameBegin,
@@ -258,7 +287,9 @@ void XMLParser::_parse_opening_xml_element() {
print_line("XML OPEN: " + node_name);
#endif
- ++P;
+ if (*P) {
+ ++P;
+ }
}
void XMLParser::_parse_current_node() {
@@ -270,10 +301,6 @@ void XMLParser::_parse_current_node() {
++P;
}
- if (!*P) {
- return;
- }
-
if (P - start > 0) {
// we found some text, store it
if (_set_text(start, P)) {
@@ -281,6 +308,10 @@ void XMLParser::_parse_current_node() {
}
}
+ if (!*P) {
+ return;
+ }
+
++P;
// based on current token, parse and report next element
@@ -433,7 +464,7 @@ Error XMLParser::open_buffer(const Vector<uint8_t> &p_buffer) {
length = p_buffer.size();
data = memnew_arr(char, length + 1);
- copymem(data, p_buffer.ptr(), length);
+ memcpy(data, p_buffer.ptr(), length);
data[length] = 0;
P = data;
return OK;
@@ -445,7 +476,7 @@ Error XMLParser::open(const String &p_path) {
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'.");
- length = file->get_len();
+ length = file->get_length();
ERR_FAIL_COND_V(length < 1, ERR_FILE_CORRUPT);
if (data) {
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index 847edf958d..1113cce715 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -31,8 +31,8 @@
#ifndef XML_PARSER_H
#define XML_PARSER_H
-#include "core/object/reference.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
+#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
#include "core/templates/vector.h"
@@ -40,8 +40,8 @@
Based on irrXML (see their zlib license). Added mainly for compatibility with their Collada loader.
*/
-class XMLParser : public Reference {
- GDCLASS(XMLParser, Reference);
+class XMLParser : public RefCounted {
+ GDCLASS(XMLParser, RefCounted);
public:
//! Enumeration of all supported source text file formats
@@ -80,7 +80,6 @@ private:
Vector<Attribute> attributes;
- String _replace_special_characters(const String &origstr);
bool _set_text(char *start, char *end);
void _parse_closing_xml_element();
void _ignore_definition();
diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp
index 4b4a46e198..fb4c76aa7a 100644
--- a/core/io/zip_io.cpp
+++ b/core/io/zip_io.cpp
@@ -30,8 +30,6 @@
#include "zip_io.h"
-#include "core/os/copymem.h"
-
void *zipio_open(void *data, const char *p_fname, int mode) {
FileAccess *&f = *(FileAccess **)data;
@@ -70,13 +68,13 @@ long zipio_tell(voidpf opaque, voidpf stream) {
long zipio_seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
FileAccess *f = *(FileAccess **)opaque;
- int pos = offset;
+ uint64_t pos = offset;
switch (origin) {
case ZLIB_FILEFUNC_SEEK_CUR:
pos = f->get_position() + offset;
break;
case ZLIB_FILEFUNC_SEEK_END:
- pos = f->get_len() + offset;
+ pos = f->get_length() + offset;
break;
default:
break;
@@ -103,7 +101,7 @@ int zipio_testerror(voidpf opaque, voidpf stream) {
voidpf zipio_alloc(voidpf opaque, uInt items, uInt size) {
voidpf ptr = memalloc(items * size);
- zeromem(ptr, items * size);
+ memset(ptr, 0, items * size);
return ptr;
}
diff --git a/core/io/zip_io.h b/core/io/zip_io.h
index 52691c65e9..776473bfa1 100644
--- a/core/io/zip_io.h
+++ b/core/io/zip_io.h
@@ -31,7 +31,7 @@
#ifndef ZIP_IO_H
#define ZIP_IO_H
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
// Not directly used in this header, but assumed available in downstream users
// like platform/*/export/export.cpp. Could be fixed, but probably better to have
diff --git a/core/math/a_star.h b/core/math/a_star.h
index 4c61abd91c..44758cb046 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -31,7 +31,7 @@
#ifndef A_STAR_H
#define A_STAR_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/templates/oa_hash_map.h"
/**
@@ -40,8 +40,8 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
-class AStar : public Reference {
- GDCLASS(AStar, Reference);
+class AStar : public RefCounted {
+ GDCLASS(AStar, RefCounted);
friend class AStar2D;
struct Point {
@@ -157,8 +157,8 @@ public:
~AStar();
};
-class AStar2D : public Reference {
- GDCLASS(AStar2D, Reference);
+class AStar2D : public RefCounted {
+ GDCLASS(AStar2D, RefCounted);
AStar astar;
bool _solve(AStar::Point *begin_point, AStar::Point *end_point);
diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp
index 2c721997d8..33aa65f15d 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -392,5 +392,5 @@ Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) c
}
AABB::operator String() const {
- return String() + position + " - " + size;
+ return "[P: " + position.operator String() + ", S: " + size + "]";
}
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index cc2b7c6611..aa3831d4cf 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -31,7 +31,6 @@
#include "basis.h"
#include "core/math/math_funcs.h"
-#include "core/os/copymem.h"
#include "core/string/print_string.h"
#define cofac(row1, col1, row2, col2) \
@@ -110,7 +109,7 @@ bool Basis::is_diagonal() const {
}
bool Basis::is_rotation() const {
- return Math::is_equal_approx(determinant(), 1, UNIT_EPSILON) && is_orthogonal();
+ return Math::is_equal_approx(determinant(), 1, (real_t)UNIT_EPSILON) && is_orthogonal();
}
#ifdef MATH_CHECKS
@@ -346,12 +345,12 @@ void Basis::rotate(const Vector3 &p_euler) {
*this = rotated(p_euler);
}
-Basis Basis::rotated(const Quat &p_quat) const {
- return Basis(p_quat) * (*this);
+Basis Basis::rotated(const Quaternion &p_quaternion) const {
+ return Basis(p_quaternion) * (*this);
}
-void Basis::rotate(const Quat &p_quat) {
- *this = rotated(p_quat);
+void Basis::rotate(const Quaternion &p_quaternion) {
+ *this = rotated(p_quaternion);
}
Vector3 Basis::get_rotation_euler() const {
@@ -368,7 +367,7 @@ Vector3 Basis::get_rotation_euler() const {
return m.get_euler();
}
-Quat Basis::get_rotation_quat() const {
+Quaternion Basis::get_rotation_quaternion() const {
// Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S,
// and returns the Euler angles corresponding to the rotation part, complementing get_scale().
// See the comment in get_scale() for further information.
@@ -379,7 +378,7 @@ Quat Basis::get_rotation_quat() const {
m.scale(Vector3(-1, -1, -1));
}
- return m.get_quat();
+ return m.get_quaternion();
}
void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const {
@@ -757,23 +756,14 @@ bool Basis::operator!=(const Basis &p_matrix) const {
}
Basis::operator String() const {
- String mtx;
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- if (i != 0 || j != 0) {
- mtx += ", ";
- }
-
- mtx += rtos(elements[j][i]); //matrix is stored transposed for performance, so print it transposed
- }
- }
-
- return mtx;
+ return "[X: " + get_axis(0).operator String() +
+ ", Y: " + get_axis(1).operator String() +
+ ", Z: " + get_axis(2).operator String() + "]";
}
-Quat Basis::get_quat() const {
+Quaternion Basis::get_quaternion() const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_rotation(), Quat(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quat() or call orthonormalized() instead.");
+ ERR_FAIL_COND_V_MSG(!is_rotation(), Quaternion(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quaternion() or call orthonormalized() instead.");
#endif
/* Allow getting a quaternion from an unnormalized transform */
Basis m = *this;
@@ -804,7 +794,7 @@ Quat Basis::get_quat() const {
temp[k] = (m.elements[k][i] + m.elements[i][k]) * s;
}
- return Quat(temp[0], temp[1], temp[2], temp[3]);
+ return Quaternion(temp[0], temp[1], temp[2], temp[3]);
}
static const Basis _ortho_bases[24] = {
@@ -946,13 +936,13 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
r_angle = angle;
}
-void Basis::set_quat(const Quat &p_quat) {
- real_t d = p_quat.length_squared();
+void Basis::set_quaternion(const Quaternion &p_quaternion) {
+ real_t d = p_quaternion.length_squared();
real_t s = 2.0 / d;
- real_t xs = p_quat.x * s, ys = p_quat.y * s, zs = p_quat.z * s;
- real_t wx = p_quat.w * xs, wy = p_quat.w * ys, wz = p_quat.w * zs;
- real_t xx = p_quat.x * xs, xy = p_quat.x * ys, xz = p_quat.x * zs;
- real_t yy = p_quat.y * ys, yz = p_quat.y * zs, zz = p_quat.z * zs;
+ real_t xs = p_quaternion.x * s, ys = p_quaternion.y * s, zs = p_quaternion.z * s;
+ real_t wx = p_quaternion.w * xs, wy = p_quaternion.w * ys, wz = p_quaternion.w * zs;
+ real_t xx = p_quaternion.x * xs, xy = p_quaternion.x * ys, xz = p_quaternion.x * zs;
+ real_t yy = p_quaternion.y * ys, yz = p_quaternion.y * zs, zz = p_quaternion.z * zs;
set(1.0 - (yy + zz), xy - wz, xz + wy,
xy + wz, 1.0 - (xx + zz), yz - wx,
xz - wy, yz + wx, 1.0 - (xx + yy));
@@ -998,9 +988,9 @@ void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) {
rotate(p_euler);
}
-void Basis::set_quat_scale(const Quat &p_quat, const Vector3 &p_scale) {
+void Basis::set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale) {
set_diagonal(p_scale);
- rotate(p_quat);
+ rotate(p_quaternion);
}
void Basis::set_diagonal(const Vector3 &p_diag) {
@@ -1019,8 +1009,8 @@ void Basis::set_diagonal(const Vector3 &p_diag) {
Basis Basis::slerp(const Basis &p_to, const real_t &p_weight) const {
//consider scale
- Quat from(*this);
- Quat to(p_to);
+ Quaternion from(*this);
+ Quaternion to(p_to);
Basis b(from.slerp(to, p_weight));
b.elements[0] *= Math::lerp(elements[0].length(), p_to.elements[0].length(), p_weight);
diff --git a/core/math/basis.h b/core/math/basis.h
index 56f6227313..3736047dd3 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -31,7 +31,7 @@
#ifndef BASIS_H
#define BASIS_H
-#include "core/math/quat.h"
+#include "core/math/quaternion.h"
#include "core/math/vector3.h"
class Basis {
@@ -79,13 +79,13 @@ public:
void rotate(const Vector3 &p_euler);
Basis rotated(const Vector3 &p_euler) const;
- void rotate(const Quat &p_quat);
- Basis rotated(const Quat &p_quat) const;
+ void rotate(const Quaternion &p_quaternion);
+ Basis rotated(const Quaternion &p_quaternion) const;
Vector3 get_rotation_euler() const;
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
- Quat get_rotation_quat() const;
+ Quaternion get_rotation_quaternion() const;
Vector3 get_rotation() const { return get_rotation_euler(); };
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
@@ -108,8 +108,8 @@ public:
Vector3 get_euler_zyx() const;
void set_euler_zyx(const Vector3 &p_euler);
- Quat get_quat() const;
- void set_quat(const Quat &p_quat);
+ Quaternion get_quaternion() const;
+ void set_quaternion(const Quaternion &p_quaternion);
Vector3 get_euler() const { return get_euler_yxz(); }
void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }
@@ -132,7 +132,7 @@ public:
void set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale);
void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale);
- void set_quat_scale(const Quat &p_quat, const Vector3 &p_scale);
+ void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale);
// transposed dot products
_FORCE_INLINE_ real_t tdotx(const Vector3 &v) const {
@@ -240,10 +240,10 @@ public:
#endif
Basis diagonalize();
- operator Quat() const { return get_quat(); }
+ operator Quaternion() const { return get_quaternion(); }
- Basis(const Quat &p_quat) { set_quat(p_quat); };
- Basis(const Quat &p_quat, const Vector3 &p_scale) { set_quat_scale(p_quat, p_scale); }
+ Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); };
+ Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }
Basis(const Vector3 &p_euler) { set_euler(p_euler); }
Basis(const Vector3 &p_euler, const Vector3 &p_scale) { set_euler_scale(p_euler, p_scale); }
diff --git a/core/math/bvh.h b/core/math/bvh.h
new file mode 100644
index 0000000000..cefbc9b0db
--- /dev/null
+++ b/core/math/bvh.h
@@ -0,0 +1,695 @@
+/*************************************************************************/
+/* bvh.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BVH_H
+#define BVH_H
+
+// BVH
+// This class provides a wrapper around BVH tree, which contains most of the functionality
+// for a dynamic BVH with templated leaf size.
+// However BVH also adds facilities for pairing, to maintain compatibility with Godot 3.2.
+// Pairing is a collision pairing system, on top of the basic BVH.
+
+// Some notes on the use of BVH / Octree from Godot 3.2.
+// This is not well explained elsewhere.
+// The rendering tree mask and types that are sent to the BVH are NOT layer masks.
+// They are INSTANCE_TYPES (defined in visual_server.h), e.g. MESH, MULTIMESH, PARTICLES etc.
+// Thus the lights do no cull by layer mask in the BVH.
+
+// Layer masks are implemented in the renderers as a later step, and light_cull_mask appears to be
+// implemented in GLES3 but not GLES2. Layer masks are not yet implemented for directional lights.
+
+#include "bvh_tree.h"
+
+#define BVHTREE_CLASS BVH_Tree<T, 2, MAX_ITEMS, USE_PAIRS, Bounds, Point>
+
+template <class T, bool USE_PAIRS = false, int MAX_ITEMS = 32, class Bounds = AABB, class Point = Vector3>
+class BVH_Manager {
+public:
+ // note we are using uint32_t instead of BVHHandle, losing type safety, but this
+ // is for compatibility with octree
+ typedef void *(*PairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int);
+ typedef void (*UnpairCallback)(void *, uint32_t, T *, int, uint32_t, T *, int, void *);
+
+ // these 2 are crucial for fine tuning, and can be applied manually
+ // see the variable declarations for more info.
+ void params_set_node_expansion(real_t p_value) {
+ if (p_value >= 0.0) {
+ tree._node_expansion = p_value;
+ tree._auto_node_expansion = false;
+ } else {
+ tree._auto_node_expansion = true;
+ }
+ }
+
+ void params_set_pairing_expansion(real_t p_value) {
+ if (p_value >= 0.0) {
+ tree._pairing_expansion = p_value;
+ tree._auto_pairing_expansion = false;
+ } else {
+ tree._auto_pairing_expansion = true;
+ }
+ }
+
+ void set_pair_callback(PairCallback p_callback, void *p_userdata) {
+ pair_callback = p_callback;
+ pair_callback_userdata = p_userdata;
+ }
+ void set_unpair_callback(UnpairCallback p_callback, void *p_userdata) {
+ unpair_callback = p_callback;
+ unpair_callback_userdata = p_userdata;
+ }
+
+ BVHHandle create(T *p_userdata, bool p_active, const Bounds &p_aabb = Bounds(), int p_subindex = 0, bool p_pairable = false, uint32_t p_pairable_type = 0, uint32_t p_pairable_mask = 1) {
+ // not sure if absolutely necessary to flush collisions here. It will cost performance to, instead
+ // of waiting for update, so only uncomment this if there are bugs.
+ if (USE_PAIRS) {
+ //_check_for_collisions();
+ }
+
+#ifdef TOOLS_ENABLED
+ if (!USE_PAIRS) {
+ if (p_pairable) {
+ WARN_PRINT_ONCE("creating pairable item in BVH with USE_PAIRS set to false");
+ }
+ }
+#endif
+
+ BVHHandle h = tree.item_add(p_userdata, p_active, p_aabb, p_subindex, p_pairable, p_pairable_type, p_pairable_mask);
+
+ if (USE_PAIRS) {
+ // for safety initialize the expanded AABB
+ Bounds &expanded_aabb = tree._pairs[h.id()].expanded_aabb;
+ expanded_aabb = p_aabb;
+ expanded_aabb.grow_by(tree._pairing_expansion);
+
+ // force a collision check no matter the AABB
+ if (p_active) {
+ _add_changed_item(h, p_aabb, false);
+ _check_for_collisions(true);
+ }
+ }
+
+ return h;
+ }
+
+ ////////////////////////////////////////////////////
+ // wrapper versions that use uint32_t instead of handle
+ // for backward compatibility. Less type safe
+ void move(uint32_t p_handle, const Bounds &p_aabb) {
+ BVHHandle h;
+ h.set(p_handle);
+ move(h, p_aabb);
+ }
+
+ void erase(uint32_t p_handle) {
+ BVHHandle h;
+ h.set(p_handle);
+ erase(h);
+ }
+
+ void force_collision_check(uint32_t p_handle) {
+ BVHHandle h;
+ h.set(p_handle);
+ force_collision_check(h);
+ }
+
+ bool activate(uint32_t p_handle, const Bounds &p_aabb, bool p_delay_collision_check = false) {
+ BVHHandle h;
+ h.set(p_handle);
+ return activate(h, p_aabb, p_delay_collision_check);
+ }
+
+ bool deactivate(uint32_t p_handle) {
+ BVHHandle h;
+ h.set(p_handle);
+ return deactivate(h);
+ }
+
+ void set_pairable(uint32_t p_handle, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask, bool p_force_collision_check = true) {
+ BVHHandle h;
+ h.set(p_handle);
+ set_pairable(h, p_pairable, p_pairable_type, p_pairable_mask, p_force_collision_check);
+ }
+
+ bool is_pairable(uint32_t p_handle) const {
+ BVHHandle h;
+ h.set(p_handle);
+ return item_is_pairable(h);
+ }
+ int get_subindex(uint32_t p_handle) const {
+ BVHHandle h;
+ h.set(p_handle);
+ return item_get_subindex(h);
+ }
+
+ T *get(uint32_t p_handle) const {
+ BVHHandle h;
+ h.set(p_handle);
+ return item_get_userdata(h);
+ }
+
+ ////////////////////////////////////////////////////
+
+ void move(BVHHandle p_handle, const Bounds &p_aabb) {
+ if (tree.item_move(p_handle, p_aabb)) {
+ if (USE_PAIRS) {
+ _add_changed_item(p_handle, p_aabb);
+ }
+ }
+ }
+
+ void erase(BVHHandle p_handle) {
+ // call unpair and remove all references to the item
+ // before deleting from the tree
+ if (USE_PAIRS) {
+ _remove_changed_item(p_handle);
+ }
+
+ tree.item_remove(p_handle);
+
+ _check_for_collisions(true);
+ }
+
+ // use in conjunction with activate if you have deferred the collision check, and
+ // set pairable has never been called.
+ // (deferred collision checks are a workaround for visual server for historical reasons)
+ void force_collision_check(BVHHandle p_handle) {
+ if (USE_PAIRS) {
+ // the aabb should already be up to date in the BVH
+ Bounds aabb;
+ item_get_AABB(p_handle, aabb);
+
+ // add it as changed even if aabb not different
+ _add_changed_item(p_handle, aabb, false);
+
+ // force an immediate full collision check, much like calls to set_pairable
+ _check_for_collisions(true);
+ }
+ }
+
+ // these should be read as set_visible for render trees,
+ // but generically this makes items add or remove from the
+ // tree internally, to speed things up by ignoring inactive items
+ bool activate(BVHHandle p_handle, const Bounds &p_aabb, bool p_delay_collision_check = false) {
+ // sending the aabb here prevents the need for the BVH to maintain
+ // a redundant copy of the aabb.
+ // returns success
+ if (tree.item_activate(p_handle, p_aabb)) {
+ if (USE_PAIRS) {
+ // in the special case of the render tree, when setting visibility we are using the combination of
+ // activate then set_pairable. This would case 2 sets of collision checks. For efficiency here we allow
+ // deferring to have a single collision check at the set_pairable call.
+ // Watch for bugs! This may cause bugs if set_pairable is not called.
+ if (!p_delay_collision_check) {
+ _add_changed_item(p_handle, p_aabb, false);
+
+ // force an immediate collision check, much like calls to set_pairable
+ _check_for_collisions(true);
+ }
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ bool deactivate(BVHHandle p_handle) {
+ // returns success
+ if (tree.item_deactivate(p_handle)) {
+ // call unpair and remove all references to the item
+ // before deleting from the tree
+ if (USE_PAIRS) {
+ _remove_changed_item(p_handle);
+
+ // force check for collisions, much like an erase was called
+ _check_for_collisions(true);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ bool get_active(BVHHandle p_handle) const {
+ return tree.item_get_active(p_handle);
+ }
+
+ // call e.g. once per frame (this does a trickle optimize)
+ void update() {
+ tree.update();
+ _check_for_collisions();
+#ifdef BVH_INTEGRITY_CHECKS
+ tree.integrity_check_all();
+#endif
+ }
+
+ // this can be called more frequently than per frame if necessary
+ void update_collisions() {
+ _check_for_collisions();
+ }
+
+ // prefer calling this directly as type safe
+ void set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask, bool p_force_collision_check = true) {
+ // Returns true if the pairing state has changed.
+ bool state_changed = tree.item_set_pairable(p_handle, p_pairable, p_pairable_type, p_pairable_mask);
+
+ if (USE_PAIRS) {
+ // not sure if absolutely necessary to flush collisions here. It will cost performance to, instead
+ // of waiting for update, so only uncomment this if there are bugs.
+ //_check_for_collisions();
+
+ if ((p_force_collision_check || state_changed) && get_active(p_handle)) {
+ // when the pairable state changes, we need to force a collision check because newly pairable
+ // items may be in collision, and unpairable items might move out of collision.
+ // We cannot depend on waiting for the next update, because that may come much later.
+ Bounds aabb;
+ item_get_AABB(p_handle, aabb);
+
+ // passing false disables the optimization which prevents collision checks if
+ // the aabb hasn't changed
+ _add_changed_item(p_handle, aabb, false);
+
+ // force an immediate collision check (probably just for this one item)
+ // but it must be a FULL collision check, also checking pairable state and masks.
+ // This is because AABB intersecting objects may have changed pairable state / mask
+ // such that they should no longer be paired. E.g. lights.
+ _check_for_collisions(true);
+ } // only if active
+ }
+ }
+
+ // cull tests
+ int cull_aabb(const Bounds &p_aabb, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF) {
+ typename BVHTREE_CLASS::CullParams params;
+
+ params.result_count_overall = 0;
+ params.result_max = p_result_max;
+ params.result_array = p_result_array;
+ params.subindex_array = p_subindex_array;
+ params.mask = p_mask;
+ params.pairable_type = 0;
+ params.test_pairable_only = false;
+ params.abb.from(p_aabb);
+
+ tree.cull_aabb(params);
+
+ return params.result_count_overall;
+ }
+
+ int cull_segment(const Point &p_from, const Point &p_to, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF) {
+ typename BVHTREE_CLASS::CullParams params;
+
+ params.result_count_overall = 0;
+ params.result_max = p_result_max;
+ params.result_array = p_result_array;
+ params.subindex_array = p_subindex_array;
+ params.mask = p_mask;
+ params.pairable_type = 0;
+
+ params.segment.from = p_from;
+ params.segment.to = p_to;
+
+ tree.cull_segment(params);
+
+ return params.result_count_overall;
+ }
+
+ int cull_point(const Point &p_point, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF) {
+ typename BVHTREE_CLASS::CullParams params;
+
+ params.result_count_overall = 0;
+ params.result_max = p_result_max;
+ params.result_array = p_result_array;
+ params.subindex_array = p_subindex_array;
+ params.mask = p_mask;
+ params.pairable_type = 0;
+
+ params.point = p_point;
+
+ tree.cull_point(params);
+ return params.result_count_overall;
+ }
+
+ int cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, uint32_t p_mask = 0xFFFFFFFF) {
+ if (!p_convex.size()) {
+ return 0;
+ }
+
+ Vector<Vector3> convex_points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size());
+ if (convex_points.size() == 0) {
+ return 0;
+ }
+
+ typename BVHTREE_CLASS::CullParams params;
+ params.result_count_overall = 0;
+ params.result_max = p_result_max;
+ params.result_array = p_result_array;
+ params.subindex_array = nullptr;
+ params.mask = p_mask;
+ params.pairable_type = 0;
+
+ params.hull.planes = &p_convex[0];
+ params.hull.num_planes = p_convex.size();
+ params.hull.points = &convex_points[0];
+ params.hull.num_points = convex_points.size();
+
+ tree.cull_convex(params);
+
+ return params.result_count_overall;
+ }
+
+private:
+ // do this after moving etc.
+ void _check_for_collisions(bool p_full_check = false) {
+ if (!changed_items.size()) {
+ // noop
+ return;
+ }
+
+ Bounds bb;
+
+ typename BVHTREE_CLASS::CullParams params;
+
+ params.result_count_overall = 0;
+ params.result_max = INT_MAX;
+ params.result_array = nullptr;
+ params.subindex_array = nullptr;
+ params.mask = 0xFFFFFFFF;
+ params.pairable_type = 0;
+
+ for (unsigned int n = 0; n < changed_items.size(); n++) {
+ const BVHHandle &h = changed_items[n];
+
+ // use the expanded aabb for pairing
+ const Bounds &expanded_aabb = tree._pairs[h.id()].expanded_aabb;
+ BVHABB_CLASS abb;
+ abb.from(expanded_aabb);
+
+ // find all the existing paired aabbs that are no longer
+ // paired, and send callbacks
+ _find_leavers(h, abb, p_full_check);
+
+ uint32_t changed_item_ref_id = h.id();
+
+ // set up the test from this item.
+ // this includes whether to test the non pairable tree,
+ // and the item mask.
+ tree.item_fill_cullparams(h, params);
+
+ params.abb = abb;
+
+ params.result_count_overall = 0; // might not be needed
+ tree.cull_aabb(params, false);
+
+ for (unsigned int i = 0; i < tree._cull_hits.size(); i++) {
+ uint32_t ref_id = tree._cull_hits[i];
+
+ // don't collide against ourself
+ if (ref_id == changed_item_ref_id) {
+ continue;
+ }
+
+#ifdef BVH_CHECKS
+ // if neither are pairable, they should ignore each other
+ // THIS SHOULD NEVER HAPPEN .. now we only test the pairable tree
+ // if the changed item is not pairable
+ CRASH_COND(params.test_pairable_only && !tree._extra[ref_id].pairable);
+#endif
+
+ // checkmasks is already done in the cull routine.
+ BVHHandle h_collidee;
+ h_collidee.set_id(ref_id);
+
+ // find NEW enterers, and send callbacks for them only
+ _collide(h, h_collidee);
+ }
+ }
+ _reset();
+ }
+
+public:
+ void item_get_AABB(BVHHandle p_handle, Bounds &r_aabb) {
+ BVHABB_CLASS abb;
+ tree.item_get_ABB(p_handle, abb);
+ abb.to(r_aabb);
+ }
+
+private:
+ // supplemental funcs
+ bool item_is_pairable(BVHHandle p_handle) const { return _get_extra(p_handle).pairable; }
+ T *item_get_userdata(BVHHandle p_handle) const { return _get_extra(p_handle).userdata; }
+ int item_get_subindex(BVHHandle p_handle) const { return _get_extra(p_handle).subindex; }
+
+ void _unpair(BVHHandle p_from, BVHHandle p_to) {
+ tree._handle_sort(p_from, p_to);
+
+ typename BVHTREE_CLASS::ItemExtra &exa = tree._extra[p_from.id()];
+ typename BVHTREE_CLASS::ItemExtra &exb = tree._extra[p_to.id()];
+
+ // if the userdata is the same, no collisions should occur
+ if ((exa.userdata == exb.userdata) && exa.userdata) {
+ return;
+ }
+
+ typename BVHTREE_CLASS::ItemPairs &pairs_from = tree._pairs[p_from.id()];
+ typename BVHTREE_CLASS::ItemPairs &pairs_to = tree._pairs[p_to.id()];
+
+ void *ud_from = pairs_from.remove_pair_to(p_to);
+ pairs_to.remove_pair_to(p_from);
+
+ // callback
+ if (unpair_callback) {
+ unpair_callback(pair_callback_userdata, p_from, exa.userdata, exa.subindex, p_to, exb.userdata, exb.subindex, ud_from);
+ }
+ }
+
+ // returns true if unpair
+ bool _find_leavers_process_pair(typename BVHTREE_CLASS::ItemPairs &p_pairs_from, const BVHABB_CLASS &p_abb_from, BVHHandle p_from, BVHHandle p_to, bool p_full_check) {
+ BVHABB_CLASS abb_to;
+ tree.item_get_ABB(p_to, abb_to);
+
+ // do they overlap?
+ if (p_abb_from.intersects(abb_to)) {
+ // the full check for pairable / non pairable and mask changes is extra expense
+ // this need not be done in most cases (for speed) except in the case where set_pairable is called
+ // where the masks etc of the objects in question may have changed
+ if (!p_full_check) {
+ return false;
+ }
+ const typename BVHTREE_CLASS::ItemExtra &exa = _get_extra(p_from);
+ const typename BVHTREE_CLASS::ItemExtra &exb = _get_extra(p_to);
+
+ // one of the two must be pairable to still pair
+ // if neither are pairable, we always unpair
+ if (exa.pairable || exb.pairable) {
+ // the masks must still be compatible to pair
+ // i.e. if there is a hit between the two, then they should stay paired
+ if (tree._cull_pairing_mask_test_hit(exa.pairable_mask, exa.pairable_type, exb.pairable_mask, exb.pairable_type)) {
+ return false;
+ }
+ }
+ }
+
+ _unpair(p_from, p_to);
+ return true;
+ }
+
+ // find all the existing paired aabbs that are no longer
+ // paired, and send callbacks
+ void _find_leavers(BVHHandle p_handle, const BVHABB_CLASS &expanded_abb_from, bool p_full_check) {
+ typename BVHTREE_CLASS::ItemPairs &p_from = tree._pairs[p_handle.id()];
+
+ BVHABB_CLASS abb_from = expanded_abb_from;
+
+ // remove from pairing list for every partner
+ for (unsigned int n = 0; n < p_from.extended_pairs.size(); n++) {
+ BVHHandle h_to = p_from.extended_pairs[n].handle;
+ if (_find_leavers_process_pair(p_from, abb_from, p_handle, h_to, p_full_check)) {
+ // we need to keep the counter n up to date if we deleted a pair
+ // as the number of items in p_from.extended_pairs will have decreased by 1
+ // and we don't want to miss an item
+ n--;
+ }
+ }
+ }
+
+ // find NEW enterers, and send callbacks for them only
+ // handle a and b
+ void _collide(BVHHandle p_ha, BVHHandle p_hb) {
+ // only have to do this oneway, lower ID then higher ID
+ tree._handle_sort(p_ha, p_hb);
+
+ const typename BVHTREE_CLASS::ItemExtra &exa = _get_extra(p_ha);
+ const typename BVHTREE_CLASS::ItemExtra &exb = _get_extra(p_hb);
+
+ // if the userdata is the same, no collisions should occur
+ if ((exa.userdata == exb.userdata) && exa.userdata) {
+ return;
+ }
+
+ typename BVHTREE_CLASS::ItemPairs &p_from = tree._pairs[p_ha.id()];
+ typename BVHTREE_CLASS::ItemPairs &p_to = tree._pairs[p_hb.id()];
+
+ // does this pair exist already?
+ // or only check the one with lower number of pairs for greater speed
+ if (p_from.num_pairs <= p_to.num_pairs) {
+ if (p_from.contains_pair_to(p_hb)) {
+ return;
+ }
+ } else {
+ if (p_to.contains_pair_to(p_ha)) {
+ return;
+ }
+ }
+
+ // callback
+ void *callback_userdata = nullptr;
+
+ if (pair_callback) {
+ callback_userdata = pair_callback(pair_callback_userdata, p_ha, exa.userdata, exa.subindex, p_hb, exb.userdata, exb.subindex);
+ }
+
+ // new pair! .. only really need to store the userdata on the lower handle, but both have storage so...
+ p_from.add_pair_to(p_hb, callback_userdata);
+ p_to.add_pair_to(p_ha, callback_userdata);
+ }
+
+ // if we remove an item, we need to immediately remove the pairs, to prevent reading the pair after deletion
+ void _remove_pairs_containing(BVHHandle p_handle) {
+ typename BVHTREE_CLASS::ItemPairs &p_from = tree._pairs[p_handle.id()];
+
+ // remove from pairing list for every partner.
+ // can't easily use a for loop here, because removing changes the size of the list
+ while (p_from.extended_pairs.size()) {
+ BVHHandle h_to = p_from.extended_pairs[0].handle;
+ _unpair(p_handle, h_to);
+ }
+ }
+
+private:
+ const typename BVHTREE_CLASS::ItemExtra &_get_extra(BVHHandle p_handle) const {
+ return tree._extra[p_handle.id()];
+ }
+ const typename BVHTREE_CLASS::ItemRef &_get_ref(BVHHandle p_handle) const {
+ return tree._refs[p_handle.id()];
+ }
+
+ void _reset() {
+ changed_items.clear();
+ _tick++;
+ }
+
+ void _add_changed_item(BVHHandle p_handle, const Bounds &aabb, bool p_check_aabb = true) {
+ // Note that non pairable items can pair with pairable,
+ // so all types must be added to the list
+
+ // aabb check with expanded aabb. This greatly decreases processing
+ // at the cost of slightly less accurate pairing checks
+ // Note this pairing AABB is separate from the AABB in the actual tree
+ Bounds &expanded_aabb = tree._pairs[p_handle.id()].expanded_aabb;
+
+ // passing p_check_aabb false disables the optimization which prevents collision checks if
+ // the aabb hasn't changed. This is needed where set_pairable has been called, but the position
+ // has not changed.
+ if (p_check_aabb && expanded_aabb.encloses(aabb)) {
+ return;
+ }
+
+ // ALWAYS update the new expanded aabb, even if already changed once
+ // this tick, because it is vital that the AABB is kept up to date
+ expanded_aabb = aabb;
+ expanded_aabb.grow_by(tree._pairing_expansion);
+
+ // this code is to ensure that changed items only appear once on the updated list
+ // collision checking them multiple times is not needed, and repeats the same thing
+ uint32_t &last_updated_tick = tree._extra[p_handle.id()].last_updated_tick;
+
+ if (last_updated_tick == _tick) {
+ return; // already on changed list
+ }
+
+ // mark as on list
+ last_updated_tick = _tick;
+
+ // add to the list
+ changed_items.push_back(p_handle);
+ }
+
+ void _remove_changed_item(BVHHandle p_handle) {
+ // Care has to be taken here for items that are deleted. The ref ID
+ // could be reused on the same tick for new items. This is probably
+ // rare but should be taken into consideration
+
+ // callbacks
+ _remove_pairs_containing(p_handle);
+
+ // remove from changed items (not very efficient yet)
+ for (int n = 0; n < (int)changed_items.size(); n++) {
+ if (changed_items[n] == p_handle) {
+ changed_items.remove_unordered(n);
+
+ // because we are using an unordered remove,
+ // the last changed item will now be at spot 'n',
+ // and we need to redo it, so we prevent moving on to
+ // the next n at the next for iteration.
+ n--;
+ }
+ }
+
+ // reset the last updated tick (may not be necessary but just in case)
+ tree._extra[p_handle.id()].last_updated_tick = 0;
+ }
+
+ PairCallback pair_callback;
+ UnpairCallback unpair_callback;
+ void *pair_callback_userdata;
+ void *unpair_callback_userdata;
+
+ BVHTREE_CLASS tree;
+
+ // for collision pairing,
+ // maintain a list of all items moved etc on each frame / tick
+ LocalVector<BVHHandle, uint32_t, true> changed_items;
+ uint32_t _tick;
+
+public:
+ BVH_Manager() {
+ _tick = 1; // start from 1 so items with 0 indicate never updated
+ pair_callback = nullptr;
+ unpair_callback = nullptr;
+ pair_callback_userdata = nullptr;
+ unpair_callback_userdata = nullptr;
+ }
+};
+
+#undef BVHTREE_CLASS
+
+#endif // BVH_H
diff --git a/core/math/bvh_abb.h b/core/math/bvh_abb.h
new file mode 100644
index 0000000000..bd9a01a87e
--- /dev/null
+++ b/core/math/bvh_abb.h
@@ -0,0 +1,276 @@
+/*************************************************************************/
+/* bvh_abb.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BVH_ABB_H
+#define BVH_ABB_H
+
+// special optimized version of axis aligned bounding box
+template <class Bounds = AABB, class Point = Vector3>
+struct BVH_ABB {
+ struct ConvexHull {
+ // convex hulls (optional)
+ const Plane *planes;
+ int num_planes;
+ const Vector3 *points;
+ int num_points;
+ };
+
+ struct Segment {
+ Point from;
+ Point to;
+ };
+
+ enum IntersectResult {
+ IR_MISS = 0,
+ IR_PARTIAL,
+ IR_FULL,
+ };
+
+ // we store mins with a negative value in order to test them with SIMD
+ Point min;
+ Point neg_max;
+
+ bool operator==(const BVH_ABB &o) const { return (min == o.min) && (neg_max == o.neg_max); }
+ bool operator!=(const BVH_ABB &o) const { return (*this == o) == false; }
+
+ void set(const Point &_min, const Point &_max) {
+ min = _min;
+ neg_max = -_max;
+ }
+
+ // to and from standard AABB
+ void from(const Bounds &p_aabb) {
+ min = p_aabb.position;
+ neg_max = -(p_aabb.position + p_aabb.size);
+ }
+
+ void to(Bounds &r_aabb) const {
+ r_aabb.position = min;
+ r_aabb.size = calculate_size();
+ }
+
+ void merge(const BVH_ABB &p_o) {
+ for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ neg_max[axis] = MIN(neg_max[axis], p_o.neg_max[axis]);
+ min[axis] = MIN(min[axis], p_o.min[axis]);
+ }
+ }
+
+ Point calculate_size() const {
+ return -neg_max - min;
+ }
+
+ Point calculate_centre() const {
+ return Point((calculate_size() * 0.5) + min);
+ }
+
+ real_t get_proximity_to(const BVH_ABB &p_b) const {
+ const Point d = (min - neg_max) - (p_b.min - p_b.neg_max);
+ real_t proximity = 0.0;
+ for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ proximity += Math::abs(d[axis]);
+ }
+ return proximity;
+ }
+
+ int select_by_proximity(const BVH_ABB &p_a, const BVH_ABB &p_b) const {
+ return (get_proximity_to(p_a) < get_proximity_to(p_b) ? 0 : 1);
+ }
+
+ uint32_t find_cutting_planes(const BVH_ABB::ConvexHull &p_hull, uint32_t *p_plane_ids) const {
+ uint32_t count = 0;
+
+ for (int n = 0; n < p_hull.num_planes; n++) {
+ const Plane &p = p_hull.planes[n];
+ if (intersects_plane(p)) {
+ p_plane_ids[count++] = n;
+ }
+ }
+
+ return count;
+ }
+
+ bool intersects_plane(const Plane &p_p) const {
+ Vector3 size = calculate_size();
+ Vector3 half_extents = size * 0.5;
+ Vector3 ofs = min + half_extents;
+
+ // forward side of plane?
+ Vector3 point_offset(
+ (p_p.normal.x < 0) ? -half_extents.x : half_extents.x,
+ (p_p.normal.y < 0) ? -half_extents.y : half_extents.y,
+ (p_p.normal.z < 0) ? -half_extents.z : half_extents.z);
+ Vector3 point = point_offset + ofs;
+
+ if (!p_p.is_point_over(point)) {
+ return false;
+ }
+
+ point = -point_offset + ofs;
+ if (p_p.is_point_over(point)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool intersects_convex_optimized(const ConvexHull &p_hull, const uint32_t *p_plane_ids, uint32_t p_num_planes) const {
+ Vector3 size = calculate_size();
+ Vector3 half_extents = size * 0.5;
+ Vector3 ofs = min + half_extents;
+
+ for (unsigned int i = 0; i < p_num_planes; i++) {
+ const Plane &p = p_hull.planes[p_plane_ids[i]];
+ 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);
+ point += ofs;
+ if (p.is_point_over(point)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool intersects_convex_partial(const ConvexHull &p_hull) const {
+ Bounds bb;
+ to(bb);
+ return bb.intersects_convex_shape(p_hull.planes, p_hull.num_planes, p_hull.points, p_hull.num_points);
+ }
+
+ IntersectResult intersects_convex(const ConvexHull &p_hull) const {
+ if (intersects_convex_partial(p_hull)) {
+ // fully within? very important for tree checks
+ if (is_within_convex(p_hull)) {
+ return IR_FULL;
+ }
+
+ return IR_PARTIAL;
+ }
+
+ return IR_MISS;
+ }
+
+ bool is_within_convex(const ConvexHull &p_hull) const {
+ // use half extents routine
+ Bounds bb;
+ to(bb);
+ return bb.inside_convex_shape(p_hull.planes, p_hull.num_planes);
+ }
+
+ bool is_point_within_hull(const ConvexHull &p_hull, const Vector3 &p_pt) const {
+ for (int n = 0; n < p_hull.num_planes; n++) {
+ if (p_hull.planes[n].distance_to(p_pt) > 0.0f) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool intersects_segment(const Segment &p_s) const {
+ Bounds bb;
+ to(bb);
+ return bb.intersects_segment(p_s.from, p_s.to);
+ }
+
+ bool intersects_point(const Point &p_pt) const {
+ if (_any_lessthan(-p_pt, neg_max)) {
+ return false;
+ }
+ if (_any_lessthan(p_pt, min)) {
+ return false;
+ }
+ return true;
+ }
+
+ bool intersects(const BVH_ABB &p_o) const {
+ if (_any_morethan(p_o.min, -neg_max)) {
+ return false;
+ }
+ if (_any_morethan(min, -p_o.neg_max)) {
+ return false;
+ }
+ return true;
+ }
+
+ bool is_other_within(const BVH_ABB &p_o) const {
+ if (_any_lessthan(p_o.neg_max, neg_max)) {
+ return false;
+ }
+ if (_any_lessthan(p_o.min, min)) {
+ return false;
+ }
+ return true;
+ }
+
+ void grow(const Point &p_change) {
+ neg_max -= p_change;
+ min -= p_change;
+ }
+
+ void expand(real_t p_change) {
+ Point change;
+ change.set_all(p_change);
+ grow(change);
+ }
+
+ // Actually surface area metric.
+ float get_area() const {
+ Point d = calculate_size();
+ return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x);
+ }
+
+ void set_to_max_opposite_extents() {
+ neg_max.set_all(FLT_MAX);
+ min = neg_max;
+ }
+
+ bool _any_morethan(const Point &p_a, const Point &p_b) const {
+ for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ if (p_a[axis] > p_b[axis]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool _any_lessthan(const Point &p_a, const Point &p_b) const {
+ for (int axis = 0; axis < Point::AXIS_COUNT; ++axis) {
+ if (p_a[axis] < p_b[axis]) {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+#endif // BVH_ABB_H
diff --git a/core/math/bvh_cull.inc b/core/math/bvh_cull.inc
new file mode 100644
index 0000000000..cba8ea6cb3
--- /dev/null
+++ b/core/math/bvh_cull.inc
@@ -0,0 +1,534 @@
+public:
+// cull parameters is a convenient way of passing a bunch
+// of arguments through the culling functions without
+// writing loads of code. Not all members are used for some cull checks
+struct CullParams {
+ int result_count_overall; // both trees
+ int result_count; // this tree only
+ int result_max;
+ T **result_array;
+ int *subindex_array;
+
+ // nobody truly understands how masks are intended to work.
+ uint32_t mask;
+ uint32_t pairable_type;
+
+ // optional components for different tests
+ Vector3 point;
+ BVHABB_CLASS abb;
+ typename BVHABB_CLASS::ConvexHull hull;
+ typename BVHABB_CLASS::Segment segment;
+
+ // when collision testing, non pairable moving items
+ // only need to be tested against the pairable tree.
+ // collisions with other non pairable items are irrelevant.
+ bool test_pairable_only;
+};
+
+private:
+void _cull_translate_hits(CullParams &p) {
+ int num_hits = _cull_hits.size();
+ int left = p.result_max - p.result_count_overall;
+
+ if (num_hits > left) {
+ num_hits = left;
+ }
+
+ int out_n = p.result_count_overall;
+
+ for (int n = 0; n < num_hits; n++) {
+ uint32_t ref_id = _cull_hits[n];
+
+ const ItemExtra &ex = _extra[ref_id];
+ p.result_array[out_n] = ex.userdata;
+
+ if (p.subindex_array) {
+ p.subindex_array[out_n] = ex.subindex;
+ }
+
+ out_n++;
+ }
+
+ p.result_count = num_hits;
+ p.result_count_overall += num_hits;
+}
+
+public:
+int cull_convex(CullParams &r_params, bool p_translate_hits = true) {
+ _cull_hits.clear();
+ r_params.result_count = 0;
+
+ for (int n = 0; n < NUM_TREES; n++) {
+ if (_root_node_id[n] == BVHCommon::INVALID) {
+ continue;
+ }
+
+ _cull_convex_iterative(_root_node_id[n], r_params);
+ }
+
+ if (p_translate_hits) {
+ _cull_translate_hits(r_params);
+ }
+
+ return r_params.result_count;
+}
+
+int cull_segment(CullParams &r_params, bool p_translate_hits = true) {
+ _cull_hits.clear();
+ r_params.result_count = 0;
+
+ for (int n = 0; n < NUM_TREES; n++) {
+ if (_root_node_id[n] == BVHCommon::INVALID) {
+ continue;
+ }
+
+ _cull_segment_iterative(_root_node_id[n], r_params);
+ }
+
+ if (p_translate_hits) {
+ _cull_translate_hits(r_params);
+ }
+
+ return r_params.result_count;
+}
+
+int cull_point(CullParams &r_params, bool p_translate_hits = true) {
+ _cull_hits.clear();
+ r_params.result_count = 0;
+
+ for (int n = 0; n < NUM_TREES; n++) {
+ if (_root_node_id[n] == BVHCommon::INVALID) {
+ continue;
+ }
+
+ _cull_point_iterative(_root_node_id[n], r_params);
+ }
+
+ if (p_translate_hits) {
+ _cull_translate_hits(r_params);
+ }
+
+ return r_params.result_count;
+}
+
+int cull_aabb(CullParams &r_params, bool p_translate_hits = true) {
+ _cull_hits.clear();
+ r_params.result_count = 0;
+
+ for (int n = 0; n < NUM_TREES; n++) {
+ if (_root_node_id[n] == BVHCommon::INVALID) {
+ continue;
+ }
+
+ if ((n == 0) && r_params.test_pairable_only) {
+ continue;
+ }
+
+ _cull_aabb_iterative(_root_node_id[n], r_params);
+ }
+
+ if (p_translate_hits) {
+ _cull_translate_hits(r_params);
+ }
+
+ return r_params.result_count;
+}
+
+bool _cull_hits_full(const CullParams &p) {
+ // instead of checking every hit, we can do a lazy check for this condition.
+ // it isn't a problem if we write too much _cull_hits because they only the
+ // result_max amount will be translated and outputted. But we might as
+ // well stop our cull checks after the maximum has been reached.
+ return (int)_cull_hits.size() >= p.result_max;
+}
+
+// write this logic once for use in all routines
+// double check this as a possible source of bugs in future.
+bool _cull_pairing_mask_test_hit(uint32_t p_maskA, uint32_t p_typeA, uint32_t p_maskB, uint32_t p_typeB) const {
+ // double check this as a possible source of bugs in future.
+ bool A_match_B = p_maskA & p_typeB;
+
+ if (!A_match_B) {
+ bool B_match_A = p_maskB & p_typeA;
+ if (!B_match_A) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void _cull_hit(uint32_t p_ref_id, CullParams &p) {
+ // take into account masks etc
+ // this would be more efficient to do before plane checks,
+ // but done here for ease to get started
+ if (USE_PAIRS) {
+ const ItemExtra &ex = _extra[p_ref_id];
+
+ if (!_cull_pairing_mask_test_hit(p.mask, p.pairable_type, ex.pairable_mask, ex.pairable_type)) {
+ return;
+ }
+ }
+
+ _cull_hits.push_back(p_ref_id);
+}
+
+bool _cull_segment_iterative(uint32_t p_node_id, CullParams &r_params) {
+ // our function parameters to keep on a stack
+ struct CullSegParams {
+ uint32_t node_id;
+ };
+
+ // most of the iterative functionality is contained in this helper class
+ BVH_IterativeInfo<CullSegParams> ii;
+
+ // alloca must allocate the stack from this function, it cannot be allocated in the
+ // helper class
+ ii.stack = (CullSegParams *)alloca(ii.get_alloca_stacksize());
+
+ // seed the stack
+ ii.get_first()->node_id = p_node_id;
+
+ CullSegParams csp;
+
+ // while there are still more nodes on the stack
+ while (ii.pop(csp)) {
+ TNode &tnode = _nodes[csp.node_id];
+
+ if (tnode.is_leaf()) {
+ // lazy check for hits full up condition
+ if (_cull_hits_full(r_params)) {
+ return false;
+ }
+
+ TLeaf &leaf = _node_get_leaf(tnode);
+
+ // test children individually
+ for (int n = 0; n < leaf.num_items; n++) {
+ const BVHABB_CLASS &aabb = leaf.get_aabb(n);
+
+ if (aabb.intersects_segment(r_params.segment)) {
+ uint32_t child_id = leaf.get_item_ref_id(n);
+
+ // register hit
+ _cull_hit(child_id, r_params);
+ }
+ }
+ } else {
+ // test children individually
+ for (int n = 0; n < tnode.num_children; n++) {
+ uint32_t child_id = tnode.children[n];
+ const BVHABB_CLASS &child_abb = _nodes[child_id].aabb;
+
+ if (child_abb.intersects_segment(r_params.segment)) {
+ // add to the stack
+ CullSegParams *child = ii.request();
+ child->node_id = child_id;
+ }
+ }
+ }
+
+ } // while more nodes to pop
+
+ // true indicates results are not full
+ return true;
+}
+
+bool _cull_point_iterative(uint32_t p_node_id, CullParams &r_params) {
+ // our function parameters to keep on a stack
+ struct CullPointParams {
+ uint32_t node_id;
+ };
+
+ // most of the iterative functionality is contained in this helper class
+ BVH_IterativeInfo<CullPointParams> ii;
+
+ // alloca must allocate the stack from this function, it cannot be allocated in the
+ // helper class
+ ii.stack = (CullPointParams *)alloca(ii.get_alloca_stacksize());
+
+ // seed the stack
+ ii.get_first()->node_id = p_node_id;
+
+ CullPointParams cpp;
+
+ // while there are still more nodes on the stack
+ while (ii.pop(cpp)) {
+ TNode &tnode = _nodes[cpp.node_id];
+ // no hit with this node?
+ if (!tnode.aabb.intersects_point(r_params.point)) {
+ continue;
+ }
+
+ if (tnode.is_leaf()) {
+ // lazy check for hits full up condition
+ if (_cull_hits_full(r_params)) {
+ return false;
+ }
+
+ TLeaf &leaf = _node_get_leaf(tnode);
+
+ // test children individually
+ for (int n = 0; n < leaf.num_items; n++) {
+ if (leaf.get_aabb(n).intersects_point(r_params.point)) {
+ uint32_t child_id = leaf.get_item_ref_id(n);
+
+ // register hit
+ _cull_hit(child_id, r_params);
+ }
+ }
+ } else {
+ // test children individually
+ for (int n = 0; n < tnode.num_children; n++) {
+ uint32_t child_id = tnode.children[n];
+
+ // add to the stack
+ CullPointParams *child = ii.request();
+ child->node_id = child_id;
+ }
+ }
+
+ } // while more nodes to pop
+
+ // true indicates results are not full
+ return true;
+}
+
+bool _cull_aabb_iterative(uint32_t p_node_id, CullParams &r_params, bool p_fully_within = false) {
+ // our function parameters to keep on a stack
+ struct CullAABBParams {
+ uint32_t node_id;
+ bool fully_within;
+ };
+
+ // most of the iterative functionality is contained in this helper class
+ BVH_IterativeInfo<CullAABBParams> ii;
+
+ // alloca must allocate the stack from this function, it cannot be allocated in the
+ // helper class
+ ii.stack = (CullAABBParams *)alloca(ii.get_alloca_stacksize());
+
+ // seed the stack
+ ii.get_first()->node_id = p_node_id;
+ ii.get_first()->fully_within = p_fully_within;
+
+ CullAABBParams cap;
+
+ // while there are still more nodes on the stack
+ while (ii.pop(cap)) {
+ TNode &tnode = _nodes[cap.node_id];
+
+ if (tnode.is_leaf()) {
+ // lazy check for hits full up condition
+ if (_cull_hits_full(r_params)) {
+ return false;
+ }
+
+ TLeaf &leaf = _node_get_leaf(tnode);
+
+ // if fully within we can just add all items
+ // as long as they pass mask checks
+ if (cap.fully_within) {
+ for (int n = 0; n < leaf.num_items; n++) {
+ uint32_t child_id = leaf.get_item_ref_id(n);
+
+ // register hit
+ _cull_hit(child_id, r_params);
+ }
+ } else {
+ for (int n = 0; n < leaf.num_items; n++) {
+ const BVHABB_CLASS &aabb = leaf.get_aabb(n);
+
+ if (aabb.intersects(r_params.abb)) {
+ uint32_t child_id = leaf.get_item_ref_id(n);
+
+ // register hit
+ _cull_hit(child_id, r_params);
+ }
+ }
+ } // not fully within
+ } else {
+ if (!cap.fully_within) {
+ // test children individually
+ for (int n = 0; n < tnode.num_children; n++) {
+ uint32_t child_id = tnode.children[n];
+ const BVHABB_CLASS &child_abb = _nodes[child_id].aabb;
+
+ if (child_abb.intersects(r_params.abb)) {
+ // is the node totally within the aabb?
+ bool fully_within = r_params.abb.is_other_within(child_abb);
+
+ // add to the stack
+ CullAABBParams *child = ii.request();
+
+ // should always return valid child
+ child->node_id = child_id;
+ child->fully_within = fully_within;
+ }
+ }
+ } else {
+ for (int n = 0; n < tnode.num_children; n++) {
+ uint32_t child_id = tnode.children[n];
+
+ // add to the stack
+ CullAABBParams *child = ii.request();
+
+ // should always return valid child
+ child->node_id = child_id;
+ child->fully_within = true;
+ }
+ }
+ }
+
+ } // while more nodes to pop
+
+ // true indicates results are not full
+ return true;
+}
+
+// returns full up with results
+bool _cull_convex_iterative(uint32_t p_node_id, CullParams &r_params, bool p_fully_within = false) {
+ // our function parameters to keep on a stack
+ struct CullConvexParams {
+ uint32_t node_id;
+ bool fully_within;
+ };
+
+ // most of the iterative functionality is contained in this helper class
+ BVH_IterativeInfo<CullConvexParams> ii;
+
+ // alloca must allocate the stack from this function, it cannot be allocated in the
+ // helper class
+ ii.stack = (CullConvexParams *)alloca(ii.get_alloca_stacksize());
+
+ // seed the stack
+ ii.get_first()->node_id = p_node_id;
+ ii.get_first()->fully_within = p_fully_within;
+
+ // preallocate these as a once off to be reused
+ uint32_t max_planes = r_params.hull.num_planes;
+ uint32_t *plane_ids = (uint32_t *)alloca(sizeof(uint32_t) * max_planes);
+
+ CullConvexParams ccp;
+
+ // while there are still more nodes on the stack
+ while (ii.pop(ccp)) {
+ const TNode &tnode = _nodes[ccp.node_id];
+
+ if (!ccp.fully_within) {
+ typename BVHABB_CLASS::IntersectResult res = tnode.aabb.intersects_convex(r_params.hull);
+
+ switch (res) {
+ default: {
+ continue; // miss, just move on to the next node in the stack
+ } break;
+ case BVHABB_CLASS::IR_PARTIAL: {
+ } break;
+ case BVHABB_CLASS::IR_FULL: {
+ ccp.fully_within = true;
+ } break;
+ }
+
+ } // if not fully within already
+
+ if (tnode.is_leaf()) {
+ // lazy check for hits full up condition
+ if (_cull_hits_full(r_params)) {
+ return false;
+ }
+
+ const TLeaf &leaf = _node_get_leaf(tnode);
+
+ // if fully within, simply add all items to the result
+ // (taking into account masks)
+ if (ccp.fully_within) {
+ for (int n = 0; n < leaf.num_items; n++) {
+ uint32_t child_id = leaf.get_item_ref_id(n);
+
+ // register hit
+ _cull_hit(child_id, r_params);
+ }
+
+ } else {
+ // we can either use a naive check of all the planes against the AABB,
+ // or an optimized check, which finds in advance which of the planes can possibly
+ // cut the AABB, and only tests those. This can be much faster.
+#define BVH_CONVEX_CULL_OPTIMIZED
+#ifdef BVH_CONVEX_CULL_OPTIMIZED
+ // first find which planes cut the aabb
+ uint32_t num_planes = tnode.aabb.find_cutting_planes(r_params.hull, plane_ids);
+ BVH_ASSERT(num_planes <= max_planes);
+
+//#define BVH_CONVEX_CULL_OPTIMIZED_RIGOR_CHECK
+#ifdef BVH_CONVEX_CULL_OPTIMIZED_RIGOR_CHECK
+ // rigorous check
+ uint32_t results[MAX_ITEMS];
+ uint32_t num_results = 0;
+#endif
+
+ // test children individually
+ for (int n = 0; n < leaf.num_items; n++) {
+ //const Item &item = leaf.get_item(n);
+ const BVHABB_CLASS &aabb = leaf.get_aabb(n);
+
+ if (aabb.intersects_convex_optimized(r_params.hull, plane_ids, num_planes)) {
+ uint32_t child_id = leaf.get_item_ref_id(n);
+
+#ifdef BVH_CONVEX_CULL_OPTIMIZED_RIGOR_CHECK
+ results[num_results++] = child_id;
+#endif
+
+ // register hit
+ _cull_hit(child_id, r_params);
+ }
+ }
+
+#ifdef BVH_CONVEX_CULL_OPTIMIZED_RIGOR_CHECK
+ uint32_t test_count = 0;
+
+ for (int n = 0; n < leaf.num_items; n++) {
+ const BVHABB_CLASS &aabb = leaf.get_aabb(n);
+
+ if (aabb.intersects_convex_partial(r_params.hull)) {
+ uint32_t child_id = leaf.get_item_ref_id(n);
+
+ CRASH_COND(child_id != results[test_count++]);
+ CRASH_COND(test_count > num_results);
+ }
+ }
+#endif
+
+#else
+ // not BVH_CONVEX_CULL_OPTIMIZED
+ // test children individually
+ for (int n = 0; n < leaf.num_items; n++) {
+ const BVHABB_CLASS &aabb = leaf.get_aabb(n);
+
+ if (aabb.intersects_convex_partial(r_params.hull)) {
+ uint32_t child_id = leaf.get_item_ref_id(n);
+
+ // full up with results? exit early, no point in further testing
+ if (!_cull_hit(child_id, r_params))
+ return false;
+ }
+ }
+#endif // BVH_CONVEX_CULL_OPTIMIZED
+ } // if not fully within
+ } else {
+ for (int n = 0; n < tnode.num_children; n++) {
+ uint32_t child_id = tnode.children[n];
+
+ // add to the stack
+ CullConvexParams *child = ii.request();
+
+ // should always return valid child
+ child->node_id = child_id;
+ child->fully_within = ccp.fully_within;
+ }
+ }
+
+ } // while more nodes to pop
+
+ // true indicates results are not full
+ return true;
+}
diff --git a/core/math/bvh_debug.inc b/core/math/bvh_debug.inc
new file mode 100644
index 0000000000..a97304334c
--- /dev/null
+++ b/core/math/bvh_debug.inc
@@ -0,0 +1,68 @@
+public:
+#ifdef BVH_VERBOSE
+void _debug_recursive_print_tree(int p_tree_id) const {
+ if (_root_node_id[p_tree_id] != BVHCommon::INVALID)
+ _debug_recursive_print_tree_node(_root_node_id[p_tree_id]);
+}
+
+String _debug_aabb_to_string(const BVHABB_CLASS &aabb) const {
+ String sz = "(";
+ sz += itos(aabb.min.x);
+ sz += " ~ ";
+ sz += itos(-aabb.neg_max.x);
+ sz += ") (";
+
+ sz += itos(aabb.min.y);
+ sz += " ~ ";
+ sz += itos(-aabb.neg_max.y);
+ sz += ") (";
+
+ sz += itos(aabb.min.z);
+ sz += " ~ ";
+ sz += itos(-aabb.neg_max.z);
+ sz += ") ";
+
+ Vector3 size = aabb.calculate_size();
+ float vol = size.x * size.y * size.z;
+ sz += "vol " + itos(vol);
+
+ return sz;
+}
+
+void _debug_recursive_print_tree_node(uint32_t p_node_id, int depth = 0) const {
+ const TNode &tnode = _nodes[p_node_id];
+
+ String sz = "";
+ for (int n = 0; n < depth; n++) {
+ sz += "\t";
+ }
+ sz += itos(p_node_id);
+
+ if (tnode.is_leaf()) {
+ sz += " L";
+ sz += itos(tnode.height) + " ";
+ const TLeaf &leaf = _node_get_leaf(tnode);
+
+ sz += "[";
+ for (int n = 0; n < leaf.num_items; n++) {
+ if (n)
+ sz += ", ";
+ sz += "r";
+ sz += itos(leaf.get_item_ref_id(n));
+ }
+ sz += "] ";
+ } else {
+ sz += " N";
+ sz += itos(tnode.height) + " ";
+ }
+
+ sz += _debug_aabb_to_string(tnode.aabb);
+ print_line(sz);
+
+ if (!tnode.is_leaf()) {
+ for (int n = 0; n < tnode.num_children; n++) {
+ _debug_recursive_print_tree_node(tnode.children[n], depth + 1);
+ }
+ }
+}
+#endif
diff --git a/core/math/bvh_integrity.inc b/core/math/bvh_integrity.inc
new file mode 100644
index 0000000000..02e9d30097
--- /dev/null
+++ b/core/math/bvh_integrity.inc
@@ -0,0 +1,42 @@
+void _integrity_check_all() {
+#ifdef BVH_INTEGRITY_CHECKS
+ for (int n = 0; n < NUM_TREES; n++) {
+ uint32_t root = _root_node_id[n];
+ if (root != BVHCommon::INVALID) {
+ _integrity_check_down(root);
+ }
+ }
+#endif
+}
+
+void _integrity_check_up(uint32_t p_node_id) {
+ TNode &node = _nodes[p_node_id];
+
+ BVHABB_CLASS abb = node.aabb;
+ node_update_aabb(node);
+
+ BVHABB_CLASS abb2 = node.aabb;
+ abb2.expand(-_node_expansion);
+
+ CRASH_COND(!abb.is_other_within(abb2));
+}
+
+void _integrity_check_down(uint32_t p_node_id) {
+ const TNode &node = _nodes[p_node_id];
+
+ if (node.is_leaf()) {
+ _integrity_check_up(p_node_id);
+ } else {
+ CRASH_COND(node.num_children != 2);
+
+ for (int n = 0; n < node.num_children; n++) {
+ uint32_t child_id = node.children[n];
+
+ // check the children parent pointers are correct
+ TNode &child = _nodes[child_id];
+ CRASH_COND(child.parent_id != p_node_id);
+
+ _integrity_check_down(child_id);
+ }
+ }
+}
diff --git a/core/math/bvh_logic.inc b/core/math/bvh_logic.inc
new file mode 100644
index 0000000000..afab08f151
--- /dev/null
+++ b/core/math/bvh_logic.inc
@@ -0,0 +1,230 @@
+
+// for slow incremental optimization, we will periodically remove each
+// item from the tree and reinsert, to give it a chance to find a better position
+void _logic_item_remove_and_reinsert(uint32_t p_ref_id) {
+ // get the reference
+ ItemRef &ref = _refs[p_ref_id];
+
+ // no need to optimize inactive items
+ if (!ref.is_active()) {
+ return;
+ }
+
+ // special case of debug draw
+ if (ref.item_id == BVHCommon::INVALID) {
+ return;
+ }
+
+ BVH_ASSERT(ref.tnode_id != BVHCommon::INVALID);
+
+ // some overlay elaborate way to find out which tree the node is in!
+ BVHHandle temp_handle;
+ temp_handle.set_id(p_ref_id);
+ uint32_t tree_id = _handle_get_tree_id(temp_handle);
+
+ // remove and reinsert
+ BVHABB_CLASS abb;
+ node_remove_item(p_ref_id, tree_id, &abb);
+
+ // we must choose where to add to tree
+ ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb);
+ _node_add_item(ref.tnode_id, p_ref_id, abb);
+
+ refit_upward_and_balance(ref.tnode_id, tree_id);
+}
+
+// from randy gaul balance function
+BVHABB_CLASS _logic_abb_merge(const BVHABB_CLASS &a, const BVHABB_CLASS &b) {
+ BVHABB_CLASS c = a;
+ c.merge(b);
+ return c;
+}
+
+//--------------------------------------------------------------------------------------------------
+/**
+@file q3DynamicAABBTree.h
+@author Randy Gaul
+@date 10/10/2014
+ Copyright (c) 2014 Randy Gaul http://www.randygaul.net
+ 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.
+*/
+//--------------------------------------------------------------------------------------------------
+
+// This function is based on the 'Balance' function from Randy Gaul's qu3e
+// https://github.com/RandyGaul/qu3e
+// It is MODIFIED from qu3e version.
+// This is the only function used (and _logic_abb_merge helper function).
+int32_t _logic_balance(int32_t iA, uint32_t p_tree_id) {
+ // return iA; // uncomment this to bypass balance
+
+ TNode *A = &_nodes[iA];
+
+ if (A->is_leaf() || A->height == 1) {
+ return iA;
+ }
+
+ /* A
+ / \
+ B C
+ / \ / \
+ D E F G
+ */
+
+ CRASH_COND(A->num_children != 2);
+ int32_t iB = A->children[0];
+ int32_t iC = A->children[1];
+ TNode *B = &_nodes[iB];
+ TNode *C = &_nodes[iC];
+
+ int32_t balance = C->height - B->height;
+
+ // C is higher, promote C
+ if (balance > 1) {
+ int32_t iF = C->children[0];
+ int32_t iG = C->children[1];
+ TNode *F = &_nodes[iF];
+ TNode *G = &_nodes[iG];
+
+ // grandParent point to C
+ if (A->parent_id != BVHCommon::INVALID) {
+ if (_nodes[A->parent_id].children[0] == iA) {
+ _nodes[A->parent_id].children[0] = iC;
+
+ } else {
+ _nodes[A->parent_id].children[1] = iC;
+ }
+ } else {
+ // check this .. seems dodgy
+ change_root_node(iC, p_tree_id);
+ }
+
+ // Swap A and C
+ C->children[0] = iA;
+ C->parent_id = A->parent_id;
+ A->parent_id = iC;
+
+ // Finish rotation
+ if (F->height > G->height) {
+ C->children[1] = iF;
+ A->children[1] = iG;
+ G->parent_id = iA;
+ A->aabb = _logic_abb_merge(B->aabb, G->aabb);
+ C->aabb = _logic_abb_merge(A->aabb, F->aabb);
+
+ A->height = 1 + MAX(B->height, G->height);
+ C->height = 1 + MAX(A->height, F->height);
+ }
+
+ else {
+ C->children[1] = iG;
+ A->children[1] = iF;
+ F->parent_id = iA;
+ A->aabb = _logic_abb_merge(B->aabb, F->aabb);
+ C->aabb = _logic_abb_merge(A->aabb, G->aabb);
+
+ A->height = 1 + MAX(B->height, F->height);
+ C->height = 1 + MAX(A->height, G->height);
+ }
+
+ return iC;
+ }
+
+ // B is higher, promote B
+ else if (balance < -1) {
+ int32_t iD = B->children[0];
+ int32_t iE = B->children[1];
+ TNode *D = &_nodes[iD];
+ TNode *E = &_nodes[iE];
+
+ // grandParent point to B
+ if (A->parent_id != BVHCommon::INVALID) {
+ if (_nodes[A->parent_id].children[0] == iA) {
+ _nodes[A->parent_id].children[0] = iB;
+ } else {
+ _nodes[A->parent_id].children[1] = iB;
+ }
+ }
+
+ else {
+ // check this .. seems dodgy
+ change_root_node(iB, p_tree_id);
+ }
+
+ // Swap A and B
+ B->children[1] = iA;
+ B->parent_id = A->parent_id;
+ A->parent_id = iB;
+
+ // Finish rotation
+ if (D->height > E->height) {
+ B->children[0] = iD;
+ A->children[0] = iE;
+ E->parent_id = iA;
+ A->aabb = _logic_abb_merge(C->aabb, E->aabb);
+ B->aabb = _logic_abb_merge(A->aabb, D->aabb);
+
+ A->height = 1 + MAX(C->height, E->height);
+ B->height = 1 + MAX(A->height, D->height);
+ }
+
+ else {
+ B->children[0] = iE;
+ A->children[0] = iD;
+ D->parent_id = iA;
+ A->aabb = _logic_abb_merge(C->aabb, D->aabb);
+ B->aabb = _logic_abb_merge(A->aabb, E->aabb);
+
+ A->height = 1 + MAX(C->height, D->height);
+ B->height = 1 + MAX(A->height, E->height);
+ }
+
+ return iB;
+ }
+
+ return iA;
+}
+
+// either choose an existing node to add item to, or create a new node and return this
+uint32_t _logic_choose_item_add_node(uint32_t p_node_id, const BVHABB_CLASS &p_aabb) {
+ while (true) {
+ BVH_ASSERT(p_node_id != BVHCommon::INVALID);
+ TNode &tnode = _nodes[p_node_id];
+
+ if (tnode.is_leaf()) {
+ // if a leaf, and non full, use this to add to
+ if (!node_is_leaf_full(tnode)) {
+ return p_node_id;
+ }
+
+ // else split the leaf, and use one of the children to add to
+ return split_leaf(p_node_id, p_aabb);
+ }
+
+ // this should not happen???
+ // is still happening, need to debug and find circumstances. Is not that serious
+ // but would be nice to prevent. I think it only happens with the root node.
+ if (tnode.num_children == 1) {
+ WARN_PRINT_ONCE("BVH::recursive_choose_item_add_node, node with 1 child, recovering");
+ p_node_id = tnode.children[0];
+ } else {
+ BVH_ASSERT(tnode.num_children == 2);
+ TNode &childA = _nodes[tnode.children[0]];
+ TNode &childB = _nodes[tnode.children[1]];
+ int which = p_aabb.select_by_proximity(childA.aabb, childB.aabb);
+
+ p_node_id = tnode.children[which];
+ }
+ }
+}
diff --git a/core/math/bvh_misc.inc b/core/math/bvh_misc.inc
new file mode 100644
index 0000000000..71aa0e4fe0
--- /dev/null
+++ b/core/math/bvh_misc.inc
@@ -0,0 +1,55 @@
+
+int _handle_get_tree_id(BVHHandle p_handle) const {
+ if (USE_PAIRS) {
+ int tree = 0;
+ if (_extra[p_handle.id()].pairable) {
+ tree = 1;
+ }
+ return tree;
+ }
+ return 0;
+}
+
+public:
+void _handle_sort(BVHHandle &p_ha, BVHHandle &p_hb) const {
+ if (p_ha.id() > p_hb.id()) {
+ BVHHandle temp = p_hb;
+ p_hb = p_ha;
+ p_ha = temp;
+ }
+}
+
+private:
+void create_root_node(int p_tree) {
+ // if there is no root node, create one
+ if (_root_node_id[p_tree] == BVHCommon::INVALID) {
+ uint32_t root_node_id;
+ TNode *node = _nodes.request(root_node_id);
+ node->clear();
+ _root_node_id[p_tree] = root_node_id;
+
+ // make the root node a leaf
+ uint32_t leaf_id;
+ TLeaf *leaf = _leaves.request(leaf_id);
+ leaf->clear();
+ node->neg_leaf_id = -(int)leaf_id;
+ }
+}
+
+bool node_is_leaf_full(TNode &tnode) const {
+ const TLeaf &leaf = _node_get_leaf(tnode);
+ return leaf.is_full();
+}
+
+public:
+TLeaf &_node_get_leaf(TNode &tnode) {
+ BVH_ASSERT(tnode.is_leaf());
+ return _leaves[tnode.get_leaf_id()];
+}
+
+const TLeaf &_node_get_leaf(const TNode &tnode) const {
+ BVH_ASSERT(tnode.is_leaf());
+ return _leaves[tnode.get_leaf_id()];
+}
+
+private:
diff --git a/core/math/bvh_pair.inc b/core/math/bvh_pair.inc
new file mode 100644
index 0000000000..839db59a3a
--- /dev/null
+++ b/core/math/bvh_pair.inc
@@ -0,0 +1,62 @@
+public:
+// note .. maybe this can be attached to another node structure?
+// depends which works best for cache.
+struct ItemPairs {
+ struct Link {
+ void set(BVHHandle h, void *ud) {
+ handle = h;
+ userdata = ud;
+ }
+ BVHHandle handle;
+ void *userdata;
+ };
+
+ void clear() {
+ num_pairs = 0;
+ extended_pairs.reset();
+ expanded_aabb = Bounds();
+ }
+
+ Bounds expanded_aabb;
+
+ // maybe we can just use the number in the vector TODO
+ int32_t num_pairs;
+ LocalVector<Link> extended_pairs;
+
+ void add_pair_to(BVHHandle h, void *p_userdata) {
+ Link temp;
+ temp.set(h, p_userdata);
+
+ extended_pairs.push_back(temp);
+ num_pairs++;
+ }
+
+ uint32_t find_pair_to(BVHHandle h) const {
+ for (int n = 0; n < num_pairs; n++) {
+ if (extended_pairs[n].handle == h) {
+ return n;
+ }
+ }
+ return -1;
+ }
+
+ bool contains_pair_to(BVHHandle h) const {
+ return find_pair_to(h) != BVHCommon::INVALID;
+ }
+
+ // return success
+ void *remove_pair_to(BVHHandle h) {
+ void *userdata = nullptr;
+
+ for (int n = 0; n < num_pairs; n++) {
+ if (extended_pairs[n].handle == h) {
+ userdata = extended_pairs[n].userdata;
+ extended_pairs.remove_unordered(n);
+ num_pairs--;
+ break;
+ }
+ }
+
+ return userdata;
+ }
+};
diff --git a/core/math/bvh_public.inc b/core/math/bvh_public.inc
new file mode 100644
index 0000000000..2c1e406712
--- /dev/null
+++ b/core/math/bvh_public.inc
@@ -0,0 +1,423 @@
+public:
+BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p_subindex, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask, bool p_invisible = false) {
+#ifdef BVH_VERBOSE_TREE
+ VERBOSE_PRINT("\nitem_add BEFORE");
+ _debug_recursive_print_tree(0);
+ VERBOSE_PRINT("\n");
+#endif
+
+ BVHABB_CLASS abb;
+ abb.from(p_aabb);
+
+ // handle to be filled with the new item ref
+ BVHHandle handle;
+
+ // ref id easier to pass around than handle
+ uint32_t ref_id;
+
+ // this should never fail
+ ItemRef *ref = _refs.request(ref_id);
+
+ // the extra data should be parallel list to the references
+ uint32_t extra_id;
+ ItemExtra *extra = _extra.request(extra_id);
+ BVH_ASSERT(extra_id == ref_id);
+
+ // pairs info
+ if (USE_PAIRS) {
+ uint32_t pairs_id;
+ ItemPairs *pairs = _pairs.request(pairs_id);
+ pairs->clear();
+ BVH_ASSERT(pairs_id == ref_id);
+ }
+
+ extra->subindex = p_subindex;
+ extra->userdata = p_userdata;
+ extra->last_updated_tick = 0;
+
+ // add an active reference to the list for slow incremental optimize
+ // this list must be kept in sync with the references as they are added or removed.
+ extra->active_ref_id = _active_refs.size();
+ _active_refs.push_back(ref_id);
+
+ if (USE_PAIRS) {
+ extra->pairable_mask = p_pairable_mask;
+ extra->pairable_type = p_pairable_type;
+ extra->pairable = p_pairable;
+ } else {
+ // just for safety, in case this gets queried etc
+ extra->pairable = 0;
+ p_pairable = false;
+ }
+
+ // assign to handle to return
+ handle.set_id(ref_id);
+
+ uint32_t tree_id = 0;
+ if (p_pairable) {
+ tree_id = 1;
+ }
+
+ create_root_node(tree_id);
+
+ // we must choose where to add to tree
+ if (p_active) {
+ ref->tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb);
+
+ bool refit = _node_add_item(ref->tnode_id, ref_id, abb);
+
+ if (refit) {
+ // only need to refit from the parent
+ const TNode &add_node = _nodes[ref->tnode_id];
+ if (add_node.parent_id != BVHCommon::INVALID) {
+ refit_upward_and_balance(add_node.parent_id, tree_id);
+ }
+ }
+ } else {
+ ref->set_inactive();
+ }
+
+#ifdef BVH_VERBOSE
+ // memory use
+ int mem = _refs.estimate_memory_use();
+ mem += _nodes.estimate_memory_use();
+
+ String sz = _debug_aabb_to_string(abb);
+ VERBOSE_PRINT("\titem_add [" + itos(ref_id) + "] " + itos(_refs.size()) + " refs,\t" + itos(_nodes.size()) + " nodes " + sz);
+ VERBOSE_PRINT("mem use : " + itos(mem) + ", num nodes : " + itos(_nodes.size()));
+
+#endif
+
+ return handle;
+}
+
+void _debug_print_refs() {
+#ifdef BVH_VERBOSE_TREE
+ print_line("refs.....");
+ for (int n = 0; n < _refs.size(); n++) {
+ const ItemRef &ref = _refs[n];
+ print_line("tnode_id " + itos(ref.tnode_id) + ", item_id " + itos(ref.item_id));
+ }
+
+#endif
+}
+
+// returns false if noop
+bool item_move(BVHHandle p_handle, const Bounds &p_aabb) {
+ uint32_t ref_id = p_handle.id();
+
+ // get the reference
+ ItemRef &ref = _refs[ref_id];
+ if (!ref.is_active()) {
+ return false;
+ }
+
+ BVHABB_CLASS abb;
+ abb.from(p_aabb);
+
+ BVH_ASSERT(ref.tnode_id != BVHCommon::INVALID);
+ TNode &tnode = _nodes[ref.tnode_id];
+
+ // does it fit within the current aabb?
+ if (tnode.aabb.is_other_within(abb)) {
+ // do nothing .. fast path .. not moved enough to need refit
+
+ // however we WILL update the exact aabb in the leaf, as this will be needed
+ // for accurate collision detection
+ TLeaf &leaf = _node_get_leaf(tnode);
+
+ BVHABB_CLASS &leaf_abb = leaf.get_aabb(ref.item_id);
+
+ // no change?
+ if (leaf_abb == abb) {
+ return false;
+ }
+
+ leaf_abb = abb;
+ _integrity_check_all();
+
+ return true;
+ }
+
+ uint32_t tree_id = _handle_get_tree_id(p_handle);
+
+ // remove and reinsert
+ node_remove_item(ref_id, tree_id);
+
+ // we must choose where to add to tree
+ ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb);
+
+ // add to the tree
+ bool needs_refit = _node_add_item(ref.tnode_id, ref_id, abb);
+
+ // only need to refit from the PARENT
+ if (needs_refit) {
+ // only need to refit from the parent
+ const TNode &add_node = _nodes[ref.tnode_id];
+ if (add_node.parent_id != BVHCommon::INVALID) {
+ // not sure we need to rebalance all the time, this can be done less often
+ refit_upward(add_node.parent_id);
+ }
+ //refit_upward_and_balance(add_node.parent_id);
+ }
+
+ return true;
+}
+
+void item_remove(BVHHandle p_handle) {
+ uint32_t ref_id = p_handle.id();
+
+ uint32_t tree_id = _handle_get_tree_id(p_handle);
+
+ VERBOSE_PRINT("item_remove [" + itos(ref_id) + "] ");
+
+ ////////////////////////////////////////
+ // remove the active reference from the list for slow incremental optimize
+ // this list must be kept in sync with the references as they are added or removed.
+ uint32_t active_ref_id = _extra[ref_id].active_ref_id;
+ uint32_t ref_id_moved_back = _active_refs[_active_refs.size() - 1];
+
+ // swap back and decrement for fast unordered remove
+ _active_refs[active_ref_id] = ref_id_moved_back;
+ _active_refs.resize(_active_refs.size() - 1);
+
+ // keep the moved active reference up to date
+ _extra[ref_id_moved_back].active_ref_id = active_ref_id;
+ ////////////////////////////////////////
+
+ // remove the item from the node (only if active)
+ if (_refs[ref_id].is_active()) {
+ node_remove_item(ref_id, tree_id);
+ }
+
+ // remove the item reference
+ _refs.free(ref_id);
+ _extra.free(ref_id);
+ if (USE_PAIRS) {
+ _pairs.free(ref_id);
+ }
+
+ // don't think refit_all is necessary?
+ //refit_all(_tree_id);
+
+#ifdef BVH_VERBOSE_TREE
+ _debug_recursive_print_tree(tree_id);
+#endif
+}
+
+// returns success
+bool item_activate(BVHHandle p_handle, const Bounds &p_aabb) {
+ uint32_t ref_id = p_handle.id();
+ ItemRef &ref = _refs[ref_id];
+ if (ref.is_active()) {
+ // noop
+ return false;
+ }
+
+ // add to tree
+ BVHABB_CLASS abb;
+ abb.from(p_aabb);
+
+ uint32_t tree_id = _handle_get_tree_id(p_handle);
+
+ // we must choose where to add to tree
+ ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb);
+ _node_add_item(ref.tnode_id, ref_id, abb);
+
+ refit_upward_and_balance(ref.tnode_id, tree_id);
+
+ return true;
+}
+
+// returns success
+bool item_deactivate(BVHHandle p_handle) {
+ uint32_t ref_id = p_handle.id();
+ ItemRef &ref = _refs[ref_id];
+ if (!ref.is_active()) {
+ // noop
+ return false;
+ }
+
+ uint32_t tree_id = _handle_get_tree_id(p_handle);
+
+ // remove from tree
+ BVHABB_CLASS abb;
+ node_remove_item(ref_id, tree_id, &abb);
+
+ // mark as inactive
+ ref.set_inactive();
+ return true;
+}
+
+bool item_get_active(BVHHandle p_handle) const {
+ uint32_t ref_id = p_handle.id();
+ const ItemRef &ref = _refs[ref_id];
+ return ref.is_active();
+}
+
+// during collision testing, we want to set the mask and whether pairable for the item testing from
+void item_fill_cullparams(BVHHandle p_handle, CullParams &r_params) const {
+ uint32_t ref_id = p_handle.id();
+ const ItemExtra &extra = _extra[ref_id];
+
+ // testing from a non pairable item, we only want to test pairable items
+ r_params.test_pairable_only = extra.pairable == 0;
+
+ // we take into account the mask of the item testing from
+ r_params.mask = extra.pairable_mask;
+ r_params.pairable_type = extra.pairable_type;
+}
+
+bool item_is_pairable(const BVHHandle &p_handle) {
+ uint32_t ref_id = p_handle.id();
+ const ItemExtra &extra = _extra[ref_id];
+ return extra.pairable != 0;
+}
+
+void item_get_ABB(const BVHHandle &p_handle, BVHABB_CLASS &r_abb) {
+ // change tree?
+ uint32_t ref_id = p_handle.id();
+ const ItemRef &ref = _refs[ref_id];
+
+ TNode &tnode = _nodes[ref.tnode_id];
+ TLeaf &leaf = _node_get_leaf(tnode);
+
+ r_abb = leaf.get_aabb(ref.item_id);
+}
+
+bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pairable_type, uint32_t p_pairable_mask) {
+ // change tree?
+ uint32_t ref_id = p_handle.id();
+
+ ItemExtra &ex = _extra[ref_id];
+ ItemRef &ref = _refs[ref_id];
+
+ bool active = ref.is_active();
+ bool pairable_changed = (ex.pairable != 0) != p_pairable;
+ bool state_changed = pairable_changed || (ex.pairable_type != p_pairable_type) || (ex.pairable_mask != p_pairable_mask);
+
+ ex.pairable_type = p_pairable_type;
+ ex.pairable_mask = p_pairable_mask;
+
+ if (active && pairable_changed) {
+ // record abb
+ TNode &tnode = _nodes[ref.tnode_id];
+ TLeaf &leaf = _node_get_leaf(tnode);
+ BVHABB_CLASS abb = leaf.get_aabb(ref.item_id);
+
+ // make sure current tree is correct prior to changing
+ uint32_t tree_id = _handle_get_tree_id(p_handle);
+
+ // remove from old tree
+ node_remove_item(ref_id, tree_id);
+
+ // we must set the pairable AFTER getting the current tree
+ // because the pairable status determines which tree
+ ex.pairable = p_pairable;
+
+ // add to new tree
+ tree_id = _handle_get_tree_id(p_handle);
+ create_root_node(tree_id);
+
+ // we must choose where to add to tree
+ ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb);
+ bool needs_refit = _node_add_item(ref.tnode_id, ref_id, abb);
+
+ // only need to refit from the PARENT
+ if (needs_refit) {
+ // only need to refit from the parent
+ const TNode &add_node = _nodes[ref.tnode_id];
+ if (add_node.parent_id != BVHCommon::INVALID) {
+ refit_upward_and_balance(add_node.parent_id, tree_id);
+ }
+ }
+ } else {
+ // always keep this up to date
+ ex.pairable = p_pairable;
+ }
+
+ return state_changed;
+}
+
+void incremental_optimize() {
+ // first update all aabbs as one off step..
+ // this is cheaper than doing it on each move as each leaf may get touched multiple times
+ // in a frame.
+ for (int n = 0; n < NUM_TREES; n++) {
+ if (_root_node_id[n] != BVHCommon::INVALID) {
+ refit_branch(_root_node_id[n]);
+ }
+ }
+
+ // now do small section reinserting to get things moving
+ // gradually, and keep items in the right leaf
+ if (_current_active_ref >= _active_refs.size()) {
+ _current_active_ref = 0;
+ }
+
+ // special case
+ if (!_active_refs.size()) {
+ return;
+ }
+
+ uint32_t ref_id = _active_refs[_current_active_ref++];
+
+ _logic_item_remove_and_reinsert(ref_id);
+
+#ifdef BVH_VERBOSE
+ /*
+ // memory use
+ int mem_refs = _refs.estimate_memory_use();
+ int mem_nodes = _nodes.estimate_memory_use();
+ int mem_leaves = _leaves.estimate_memory_use();
+
+ String sz;
+ sz += "mem_refs : " + itos(mem_refs) + " ";
+ sz += "mem_nodes : " + itos(mem_nodes) + " ";
+ sz += "mem_leaves : " + itos(mem_leaves) + " ";
+ sz += ", num nodes : " + itos(_nodes.size());
+ print_line(sz);
+ */
+#endif
+}
+
+void update() {
+ incremental_optimize();
+
+ // keep the expansion values up to date with the world bound
+//#define BVH_ALLOW_AUTO_EXPANSION
+#ifdef BVH_ALLOW_AUTO_EXPANSION
+ if (_auto_node_expansion || _auto_pairing_expansion) {
+ BVHABB_CLASS world_bound;
+ world_bound.set_to_max_opposite_extents();
+
+ bool bound_valid = false;
+
+ for (int n = 0; n < NUM_TREES; n++) {
+ uint32_t node_id = _root_node_id[n];
+ if (node_id != BVHCommon::INVALID) {
+ world_bound.merge(_nodes[node_id].aabb);
+ bound_valid = true;
+ }
+ }
+
+ // if there are no nodes, do nothing, but if there are...
+ if (bound_valid) {
+ Bounds bb;
+ world_bound.to(bb);
+ real_t size = bb.get_longest_axis_size();
+
+ // automatic AI decision for best parameters.
+ // These can be overridden in project settings.
+
+ // these magic numbers are determined by experiment
+ if (_auto_node_expansion) {
+ _node_expansion = size * 0.025;
+ }
+ if (_auto_pairing_expansion) {
+ _pairing_expansion = size * 0.009;
+ }
+ }
+ }
+#endif
+}
diff --git a/core/math/bvh_refit.inc b/core/math/bvh_refit.inc
new file mode 100644
index 0000000000..717a3438c7
--- /dev/null
+++ b/core/math/bvh_refit.inc
@@ -0,0 +1,141 @@
+void _debug_node_verify_bound(uint32_t p_node_id) {
+ TNode &node = _nodes[p_node_id];
+ BVHABB_CLASS abb_before = node.aabb;
+
+ node_update_aabb(node);
+
+ BVHABB_CLASS abb_after = node.aabb;
+ CRASH_COND(abb_before != abb_after);
+}
+
+void node_update_aabb(TNode &tnode) {
+ tnode.aabb.set_to_max_opposite_extents();
+ tnode.height = 0;
+
+ if (!tnode.is_leaf()) {
+ for (int n = 0; n < tnode.num_children; n++) {
+ uint32_t child_node_id = tnode.children[n];
+
+ // merge with child aabb
+ const TNode &tchild = _nodes[child_node_id];
+ tnode.aabb.merge(tchild.aabb);
+
+ // do heights at the same time
+ if (tchild.height > tnode.height) {
+ tnode.height = tchild.height;
+ }
+ }
+
+ // the height of a non leaf is always 1 bigger than the biggest child
+ tnode.height++;
+
+#ifdef BVH_CHECKS
+ if (!tnode.num_children) {
+ // the 'blank' aabb will screw up parent aabbs
+ WARN_PRINT("BVH_Tree::TNode no children, AABB is undefined");
+ }
+#endif
+ } else {
+ // leaf
+ const TLeaf &leaf = _node_get_leaf(tnode);
+
+ for (int n = 0; n < leaf.num_items; n++) {
+ tnode.aabb.merge(leaf.get_aabb(n));
+ }
+
+ // now the leaf items are unexpanded, we expand only in the node AABB
+ tnode.aabb.expand(_node_expansion);
+#ifdef BVH_CHECKS
+ if (!leaf.num_items) {
+ // the 'blank' aabb will screw up parent aabbs
+ WARN_PRINT("BVH_Tree::TLeaf no items, AABB is undefined");
+ }
+#endif
+ }
+}
+
+void refit_all(int p_tree_id) {
+ refit_downward(_root_node_id[p_tree_id]);
+}
+
+void refit_upward(uint32_t p_node_id) {
+ while (p_node_id != BVHCommon::INVALID) {
+ TNode &tnode = _nodes[p_node_id];
+ node_update_aabb(tnode);
+ p_node_id = tnode.parent_id;
+ }
+}
+
+void refit_upward_and_balance(uint32_t p_node_id, uint32_t p_tree_id) {
+ while (p_node_id != BVHCommon::INVALID) {
+ uint32_t before = p_node_id;
+ p_node_id = _logic_balance(p_node_id, p_tree_id);
+
+ if (before != p_node_id) {
+ VERBOSE_PRINT("REBALANCED!");
+ }
+
+ TNode &tnode = _nodes[p_node_id];
+
+ // update overall aabb from the children
+ node_update_aabb(tnode);
+
+ p_node_id = tnode.parent_id;
+ }
+}
+
+void refit_downward(uint32_t p_node_id) {
+ TNode &tnode = _nodes[p_node_id];
+
+ // do children first
+ if (!tnode.is_leaf()) {
+ for (int n = 0; n < tnode.num_children; n++) {
+ refit_downward(tnode.children[n]);
+ }
+ }
+
+ node_update_aabb(tnode);
+}
+
+// go down to the leaves, then refit upward
+void refit_branch(uint32_t p_node_id) {
+ // our function parameters to keep on a stack
+ struct RefitParams {
+ uint32_t node_id;
+ };
+
+ // most of the iterative functionality is contained in this helper class
+ BVH_IterativeInfo<RefitParams> ii;
+
+ // alloca must allocate the stack from this function, it cannot be allocated in the
+ // helper class
+ ii.stack = (RefitParams *)alloca(ii.get_alloca_stacksize());
+
+ // seed the stack
+ ii.get_first()->node_id = p_node_id;
+
+ RefitParams rp;
+
+ // while there are still more nodes on the stack
+ while (ii.pop(rp)) {
+ TNode &tnode = _nodes[rp.node_id];
+
+ // do children first
+ if (!tnode.is_leaf()) {
+ for (int n = 0; n < tnode.num_children; n++) {
+ uint32_t child_id = tnode.children[n];
+
+ // add to the stack
+ RefitParams *child = ii.request();
+ child->node_id = child_id;
+ }
+ } else {
+ // leaf .. only refit upward if dirty
+ TLeaf &leaf = _node_get_leaf(tnode);
+ if (leaf.is_dirty()) {
+ leaf.set_dirty(false);
+ refit_upward(p_node_id);
+ }
+ }
+ } // while more nodes to pop
+}
diff --git a/core/math/bvh_split.inc b/core/math/bvh_split.inc
new file mode 100644
index 0000000000..3fcc4c7b10
--- /dev/null
+++ b/core/math/bvh_split.inc
@@ -0,0 +1,294 @@
+void _split_inform_references(uint32_t p_node_id) {
+ TNode &node = _nodes[p_node_id];
+ TLeaf &leaf = _node_get_leaf(node);
+
+ for (int n = 0; n < leaf.num_items; n++) {
+ uint32_t ref_id = leaf.get_item_ref_id(n);
+
+ ItemRef &ref = _refs[ref_id];
+ ref.tnode_id = p_node_id;
+ ref.item_id = n;
+ }
+}
+
+void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, uint16_t *group_b, const BVHABB_CLASS *temp_bounds, const BVHABB_CLASS full_bound) {
+ // special case for low leaf sizes .. should static compile out
+ if (MAX_ITEMS < 4) {
+ uint32_t ind = group_a[0];
+
+ // add to b
+ group_b[num_b++] = ind;
+
+ // remove from a
+ group_a[0] = group_a[num_a - 1];
+ num_a--;
+ return;
+ }
+
+ Point centre = full_bound.calculate_centre();
+ Point size = full_bound.calculate_size();
+
+ int order[3];
+
+ order[0] = size.min_axis();
+ order[2] = size.max_axis();
+ order[1] = 3 - (order[0] + order[2]);
+
+ // simplest case, split on the longest axis
+ int split_axis = order[0];
+ for (int a = 0; a < num_a; a++) {
+ uint32_t ind = group_a[a];
+
+ if (temp_bounds[ind].min.coord[split_axis] > centre.coord[split_axis]) {
+ // add to b
+ group_b[num_b++] = ind;
+
+ // remove from a
+ group_a[a] = group_a[num_a - 1];
+ num_a--;
+
+ // do this one again, as it has been replaced
+ a--;
+ }
+ }
+
+ // detect when split on longest axis failed
+ int min_threshold = MAX_ITEMS / 4;
+ int min_group_size[3];
+ min_group_size[0] = MIN(num_a, num_b);
+ if (min_group_size[0] < min_threshold) {
+ // slow but sure .. first move everything back into a
+ for (int b = 0; b < num_b; b++) {
+ group_a[num_a++] = group_b[b];
+ }
+ num_b = 0;
+
+ // now calculate the best split
+ for (int axis = 1; axis < 3; axis++) {
+ split_axis = order[axis];
+ int count = 0;
+
+ for (int a = 0; a < num_a; a++) {
+ uint32_t ind = group_a[a];
+
+ if (temp_bounds[ind].min.coord[split_axis] > centre.coord[split_axis]) {
+ count++;
+ }
+ }
+
+ min_group_size[axis] = MIN(count, num_a - count);
+ } // for axis
+
+ // best axis
+ int best_axis = 0;
+ int best_min = min_group_size[0];
+ for (int axis = 1; axis < 3; axis++) {
+ if (min_group_size[axis] > best_min) {
+ best_min = min_group_size[axis];
+ best_axis = axis;
+ }
+ }
+
+ // now finally do the split
+ if (best_min > 0) {
+ split_axis = order[best_axis];
+
+ for (int a = 0; a < num_a; a++) {
+ uint32_t ind = group_a[a];
+
+ if (temp_bounds[ind].min.coord[split_axis] > centre.coord[split_axis]) {
+ // add to b
+ group_b[num_b++] = ind;
+
+ // remove from a
+ group_a[a] = group_a[num_a - 1];
+ num_a--;
+
+ // do this one again, as it has been replaced
+ a--;
+ }
+ }
+ } // if there was a split!
+ } // if the longest axis wasn't a good split
+
+ // special case, none crossed threshold
+ if (!num_b) {
+ uint32_t ind = group_a[0];
+
+ // add to b
+ group_b[num_b++] = ind;
+
+ // remove from a
+ group_a[0] = group_a[num_a - 1];
+ num_a--;
+ }
+ // opposite problem! :)
+ if (!num_a) {
+ uint32_t ind = group_b[0];
+
+ // add to a
+ group_a[num_a++] = ind;
+
+ // remove from b
+ group_b[0] = group_b[num_b - 1];
+ num_b--;
+ }
+}
+
+void _split_leaf_sort_groups(int &num_a, int &num_b, uint16_t *group_a, uint16_t *group_b, const BVHABB_CLASS *temp_bounds) {
+ BVHABB_CLASS groupb_aabb;
+ groupb_aabb.set_to_max_opposite_extents();
+ for (int n = 0; n < num_b; n++) {
+ int which = group_b[n];
+ groupb_aabb.merge(temp_bounds[which]);
+ }
+ BVHABB_CLASS groupb_aabb_new;
+
+ BVHABB_CLASS rest_aabb;
+
+ float best_size = FLT_MAX;
+ int best_candidate = -1;
+
+ // find most likely from a to move into b
+ for (int check = 0; check < num_a; check++) {
+ rest_aabb.set_to_max_opposite_extents();
+ groupb_aabb_new = groupb_aabb;
+
+ // find aabb of all the rest
+ for (int rest = 0; rest < num_a; rest++) {
+ if (rest == check) {
+ continue;
+ }
+
+ int which = group_a[rest];
+ rest_aabb.merge(temp_bounds[which]);
+ }
+
+ groupb_aabb_new.merge(temp_bounds[group_a[check]]);
+
+ // now compare the sizes
+ float size = groupb_aabb_new.get_area() + rest_aabb.get_area();
+ if (size < best_size) {
+ best_size = size;
+ best_candidate = check;
+ }
+ }
+
+ // we should now have the best, move it from group a to group b
+ group_b[num_b++] = group_a[best_candidate];
+
+ // remove best candidate from group a
+ num_a--;
+ group_a[best_candidate] = group_a[num_a];
+}
+
+uint32_t split_leaf(uint32_t p_node_id, const BVHABB_CLASS &p_added_item_aabb) {
+ return split_leaf_complex(p_node_id, p_added_item_aabb);
+}
+
+// aabb is the new inserted node
+uint32_t split_leaf_complex(uint32_t p_node_id, const BVHABB_CLASS &p_added_item_aabb) {
+ VERBOSE_PRINT("split_leaf");
+
+ // note the tnode before and AFTER splitting may be a different address
+ // in memory because the vector could get relocated. So we need to reget
+ // the tnode after the split
+ BVH_ASSERT(_nodes[p_node_id].is_leaf());
+
+ // first create child leaf nodes
+ uint32_t *child_ids = (uint32_t *)alloca(sizeof(uint32_t) * MAX_CHILDREN);
+
+ for (int n = 0; n < MAX_CHILDREN; n++) {
+ // create node children
+ TNode *child_node = _nodes.request(child_ids[n]);
+
+ child_node->clear();
+
+ // back link to parent
+ child_node->parent_id = p_node_id;
+
+ // make each child a leaf node
+ node_make_leaf(child_ids[n]);
+ }
+
+ // don't get any leaves or nodes till AFTER the split
+ TNode &tnode = _nodes[p_node_id];
+ uint32_t orig_leaf_id = tnode.get_leaf_id();
+ const TLeaf &orig_leaf = _node_get_leaf(tnode);
+
+ // store the final child ids
+ for (int n = 0; n < MAX_CHILDREN; n++) {
+ tnode.children[n] = child_ids[n];
+ }
+
+ // mark as no longer a leaf node
+ tnode.num_children = MAX_CHILDREN;
+
+ // 2 groups, A and B, and assign children to each to split equally
+ int max_children = orig_leaf.num_items + 1; // plus 1 for the wildcard .. the item being added
+ //CRASH_COND(max_children > MAX_CHILDREN);
+
+ uint16_t *group_a = (uint16_t *)alloca(sizeof(uint16_t) * max_children);
+ uint16_t *group_b = (uint16_t *)alloca(sizeof(uint16_t) * max_children);
+
+ // we are copying the ABBs. This is ugly, but we need one extra for the inserted item...
+ BVHABB_CLASS *temp_bounds = (BVHABB_CLASS *)alloca(sizeof(BVHABB_CLASS) * max_children);
+
+ int num_a = max_children;
+ int num_b = 0;
+
+ // setup - start with all in group a
+ for (int n = 0; n < orig_leaf.num_items; n++) {
+ group_a[n] = n;
+ temp_bounds[n] = orig_leaf.get_aabb(n);
+ }
+ // wildcard
+ int wildcard = orig_leaf.num_items;
+
+ group_a[wildcard] = wildcard;
+ temp_bounds[wildcard] = p_added_item_aabb;
+
+ // we can choose here either an equal split, or just 1 in the new leaf
+ _split_leaf_sort_groups_simple(num_a, num_b, group_a, group_b, temp_bounds, tnode.aabb);
+
+ uint32_t wildcard_node = BVHCommon::INVALID;
+
+ // now there should be equal numbers in both groups
+ for (int n = 0; n < num_a; n++) {
+ int which = group_a[n];
+
+ if (which != wildcard) {
+ const BVHABB_CLASS &source_item_aabb = orig_leaf.get_aabb(which);
+ uint32_t source_item_ref_id = orig_leaf.get_item_ref_id(which);
+ //const Item &source_item = orig_leaf.get_item(which);
+ _node_add_item(tnode.children[0], source_item_ref_id, source_item_aabb);
+ } else {
+ wildcard_node = tnode.children[0];
+ }
+ }
+ for (int n = 0; n < num_b; n++) {
+ int which = group_b[n];
+
+ if (which != wildcard) {
+ const BVHABB_CLASS &source_item_aabb = orig_leaf.get_aabb(which);
+ uint32_t source_item_ref_id = orig_leaf.get_item_ref_id(which);
+ //const Item &source_item = orig_leaf.get_item(which);
+ _node_add_item(tnode.children[1], source_item_ref_id, source_item_aabb);
+ } else {
+ wildcard_node = tnode.children[1];
+ }
+ }
+
+ // now remove all items from the parent and replace with the child nodes
+ _leaves.free(orig_leaf_id);
+
+ // we should keep the references up to date!
+ for (int n = 0; n < MAX_CHILDREN; n++) {
+ _split_inform_references(tnode.children[n]);
+ }
+
+ refit_upward(p_node_id);
+
+ BVH_ASSERT(wildcard_node != BVHCommon::INVALID);
+ return wildcard_node;
+}
diff --git a/core/math/bvh_structs.inc b/core/math/bvh_structs.inc
new file mode 100644
index 0000000000..1d1e0e6468
--- /dev/null
+++ b/core/math/bvh_structs.inc
@@ -0,0 +1,180 @@
+
+public:
+struct ItemRef {
+ uint32_t tnode_id; // -1 is invalid
+ uint32_t item_id; // in the leaf
+
+ bool is_active() const { return tnode_id != BVHCommon::INACTIVE; }
+ void set_inactive() {
+ tnode_id = BVHCommon::INACTIVE;
+ item_id = BVHCommon::INACTIVE;
+ }
+};
+
+// extra info kept in separate parallel list to the references,
+// as this is less used as keeps cache better
+struct ItemExtra {
+ uint32_t last_updated_tick;
+ uint32_t pairable;
+ uint32_t pairable_mask;
+ uint32_t pairable_type;
+
+ int32_t subindex;
+
+ // the active reference is a separate list of which references
+ // are active so that we can slowly iterate through it over many frames for
+ // slow optimize.
+ uint32_t active_ref_id;
+
+ T *userdata;
+};
+
+// this is an item OR a child node depending on whether a leaf node
+struct Item {
+ BVHABB_CLASS aabb;
+ uint32_t item_ref_id;
+};
+
+// tree leaf
+struct TLeaf {
+ uint16_t num_items;
+
+private:
+ uint16_t dirty;
+ // separate data orientated lists for faster SIMD traversal
+ uint32_t item_ref_ids[MAX_ITEMS];
+ BVHABB_CLASS aabbs[MAX_ITEMS];
+
+public:
+ // accessors
+ BVHABB_CLASS &get_aabb(uint32_t p_id) { return aabbs[p_id]; }
+ const BVHABB_CLASS &get_aabb(uint32_t p_id) const { return aabbs[p_id]; }
+
+ uint32_t &get_item_ref_id(uint32_t p_id) { return item_ref_ids[p_id]; }
+ const uint32_t &get_item_ref_id(uint32_t p_id) const { return item_ref_ids[p_id]; }
+
+ bool is_dirty() const { return dirty; }
+ void set_dirty(bool p) { dirty = p; }
+
+ void clear() {
+ num_items = 0;
+ set_dirty(true);
+ }
+ bool is_full() const { return num_items >= MAX_ITEMS; }
+
+ void remove_item_unordered(uint32_t p_id) {
+ BVH_ASSERT(p_id < num_items);
+ num_items--;
+ aabbs[p_id] = aabbs[num_items];
+ item_ref_ids[p_id] = item_ref_ids[num_items];
+ }
+
+ uint32_t request_item() {
+ if (num_items < MAX_ITEMS) {
+ uint32_t id = num_items;
+ num_items++;
+ return id;
+ }
+ return -1;
+ }
+};
+
+// tree node
+struct TNode {
+ BVHABB_CLASS aabb;
+ // either number of children if positive
+ // or leaf id if negative (leaf id 0 is disallowed)
+ union {
+ int32_t num_children;
+ int32_t neg_leaf_id;
+ };
+ uint32_t parent_id; // or -1
+ uint16_t children[MAX_CHILDREN];
+
+ // height in the tree, where leaves are 0, and all above are 1+
+ // (or the highest where there is a tie off)
+ int32_t height;
+
+ bool is_leaf() const { return num_children < 0; }
+ void set_leaf_id(int id) { neg_leaf_id = -id; }
+ int get_leaf_id() const { return -neg_leaf_id; }
+
+ void clear() {
+ num_children = 0;
+ parent_id = BVHCommon::INVALID;
+ height = 0; // or -1 for testing
+
+ // for safety set to improbable value
+ aabb.set_to_max_opposite_extents();
+
+ // other members are not blanked for speed .. they may be uninitialized
+ }
+
+ bool is_full_of_children() const { return num_children >= MAX_CHILDREN; }
+
+ void remove_child_internal(uint32_t child_num) {
+ children[child_num] = children[num_children - 1];
+ num_children--;
+ }
+
+ int find_child(uint32_t p_child_node_id) {
+ BVH_ASSERT(!is_leaf());
+
+ for (int n = 0; n < num_children; n++) {
+ if (children[n] == p_child_node_id) {
+ return n;
+ }
+ }
+
+ // not found
+ return -1;
+ }
+};
+
+// instead of using linked list we maintain
+// item references (for quick lookup)
+PooledList<ItemRef, true> _refs;
+PooledList<ItemExtra, true> _extra;
+PooledList<ItemPairs> _pairs;
+
+// these 2 are not in sync .. nodes != leaves!
+PooledList<TNode, true> _nodes;
+PooledList<TLeaf, true> _leaves;
+
+// we can maintain an un-ordered list of which references are active,
+// in order to do a slow incremental optimize of the tree over each frame.
+// This will work best if dynamic objects and static objects are in a different tree.
+LocalVector<uint32_t, uint32_t, true> _active_refs;
+uint32_t _current_active_ref = 0;
+
+// instead of translating directly to the userdata output,
+// we keep an intermediate list of hits as reference IDs, which can be used
+// for pairing collision detection
+LocalVector<uint32_t, uint32_t, true> _cull_hits;
+
+// we now have multiple root nodes, allowing us to store
+// more than 1 tree. This can be more efficient, while sharing the same
+// common lists
+enum { NUM_TREES = 2,
+};
+
+// Tree 0 - Non pairable
+// Tree 1 - Pairable
+// This is more efficient because in physics we only need check non pairable against the pairable tree.
+uint32_t _root_node_id[NUM_TREES];
+
+// these values may need tweaking according to the project
+// the bound of the world, and the average velocities of the objects
+
+// node expansion is important in the rendering tree
+// larger values give less re-insertion as items move...
+// but on the other hand over estimates the bounding box of nodes.
+// we can either use auto mode, where the expansion is based on the root node size, or specify manually
+real_t _node_expansion = 0.5;
+bool _auto_node_expansion = true;
+
+// pairing expansion important for physics pairing
+// larger values gives more 'sticky' pairing, and is less likely to exhibit tunneling
+// we can either use auto mode, where the expansion is based on the root node size, or specify manually
+real_t _pairing_expansion = 0.1;
+bool _auto_pairing_expansion = true;
diff --git a/core/math/bvh_tree.h b/core/math/bvh_tree.h
new file mode 100644
index 0000000000..3169d31ec7
--- /dev/null
+++ b/core/math/bvh_tree.h
@@ -0,0 +1,421 @@
+/*************************************************************************/
+/* bvh_tree.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BVH_TREE_H
+#define BVH_TREE_H
+
+// BVH Tree
+// This is an implementation of a dynamic BVH with templated leaf size.
+// This differs from most dynamic BVH in that it can handle more than 1 object
+// in leaf nodes. This can make it far more efficient in certain circumstances.
+// It also means that the splitting logic etc have to be completely different
+// to a simpler tree.
+// Note that MAX_CHILDREN should be fixed at 2 for now.
+
+#include "core/math/aabb.h"
+#include "core/math/bvh_abb.h"
+#include "core/math/geometry_3d.h"
+#include "core/math/vector3.h"
+#include "core/string/print_string.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/pooled_list.h"
+#include <limits.h>
+
+#define BVHABB_CLASS BVH_ABB<Bounds, Point>
+
+// never do these checks in release
+#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
+//#define BVH_VERBOSE
+//#define BVH_VERBOSE_TREE
+
+//#define BVH_VERBOSE_FRAME
+//#define BVH_CHECKS
+//#define BVH_INTEGRITY_CHECKS
+#endif
+
+// debug only assert
+#ifdef BVH_CHECKS
+#define BVH_ASSERT(a) CRASH_COND((a) == false)
+#else
+#define BVH_ASSERT(a)
+#endif
+
+#ifdef BVH_VERBOSE
+#define VERBOSE_PRINT print_line
+#else
+#define VERBOSE_PRINT(a)
+#endif
+
+// really just a namespace
+struct BVHCommon {
+ // these could possibly also be the same constant,
+ // although this may be useful for debugging.
+ // or use zero for invalid and +1 based indices.
+ static const uint32_t INVALID = (0xffffffff);
+ static const uint32_t INACTIVE = (0xfffffffe);
+};
+
+// really a handle, can be anything
+// note that zero is a valid reference for the BVH .. this may involve using
+// a plus one based ID for clients that expect 0 to be invalid.
+struct BVHHandle {
+ // conversion operator
+ operator uint32_t() const { return _data; }
+ void set(uint32_t p_value) { _data = p_value; }
+
+ uint32_t _data;
+
+ void set_invalid() { _data = BVHCommon::INVALID; }
+ bool is_invalid() const { return _data == BVHCommon::INVALID; }
+ uint32_t id() const { return _data; }
+ void set_id(uint32_t p_id) { _data = p_id; }
+
+ bool operator==(const BVHHandle &p_h) const { return _data == p_h._data; }
+ bool operator!=(const BVHHandle &p_h) const { return (*this == p_h) == false; }
+};
+
+// helper class to make iterative versions of recursive functions
+template <class T>
+class BVH_IterativeInfo {
+public:
+ enum {
+ ALLOCA_STACK_SIZE = 128
+ };
+
+ int32_t depth = 1;
+ int32_t threshold = ALLOCA_STACK_SIZE - 2;
+ T *stack;
+ //only used in rare occasions when you run out of alloca memory
+ // because tree is too unbalanced.
+ LocalVector<T> aux_stack;
+ int32_t get_alloca_stacksize() const { return ALLOCA_STACK_SIZE * sizeof(T); }
+
+ T *get_first() const {
+ return &stack[0];
+ }
+
+ // pop the last member of the stack, or return false
+ bool pop(T &r_value) {
+ if (!depth) {
+ return false;
+ }
+
+ depth--;
+ r_value = stack[depth];
+ return true;
+ }
+
+ // request new addition to stack
+ T *request() {
+ if (depth > threshold) {
+ if (aux_stack.is_empty()) {
+ aux_stack.resize(ALLOCA_STACK_SIZE * 2);
+ memcpy(aux_stack.ptr(), stack, get_alloca_stacksize());
+ } else {
+ aux_stack.resize(aux_stack.size() * 2);
+ }
+ stack = aux_stack.ptr();
+ threshold = aux_stack.size() - 2;
+ }
+ return &stack[depth++];
+ }
+};
+
+template <class T, int MAX_CHILDREN, int MAX_ITEMS, bool USE_PAIRS = false, class Bounds = AABB, class Point = Vector3>
+class BVH_Tree {
+ friend class BVH;
+
+#include "bvh_pair.inc"
+#include "bvh_structs.inc"
+
+public:
+ BVH_Tree() {
+ for (int n = 0; n < NUM_TREES; n++) {
+ _root_node_id[n] = BVHCommon::INVALID;
+ }
+
+ // disallow zero leaf ids
+ // (as these ids are stored as negative numbers in the node)
+ uint32_t dummy_leaf_id;
+ _leaves.request(dummy_leaf_id);
+ }
+
+private:
+ bool node_add_child(uint32_t p_node_id, uint32_t p_child_node_id) {
+ TNode &tnode = _nodes[p_node_id];
+ if (tnode.is_full_of_children()) {
+ return false;
+ }
+
+ tnode.children[tnode.num_children] = p_child_node_id;
+ tnode.num_children += 1;
+
+ // back link in the child to the parent
+ TNode &tnode_child = _nodes[p_child_node_id];
+ tnode_child.parent_id = p_node_id;
+
+ return true;
+ }
+
+ void node_replace_child(uint32_t p_parent_id, uint32_t p_old_child_id, uint32_t p_new_child_id) {
+ TNode &parent = _nodes[p_parent_id];
+ BVH_ASSERT(!parent.is_leaf());
+
+ int child_num = parent.find_child(p_old_child_id);
+ BVH_ASSERT(child_num != BVHCommon::INVALID);
+ parent.children[child_num] = p_new_child_id;
+
+ TNode &new_child = _nodes[p_new_child_id];
+ new_child.parent_id = p_parent_id;
+ }
+
+ void node_remove_child(uint32_t p_parent_id, uint32_t p_child_id, uint32_t p_tree_id, bool p_prevent_sibling = false) {
+ TNode &parent = _nodes[p_parent_id];
+ BVH_ASSERT(!parent.is_leaf());
+
+ int child_num = parent.find_child(p_child_id);
+ BVH_ASSERT(child_num != BVHCommon::INVALID);
+
+ parent.remove_child_internal(child_num);
+
+ // no need to keep back references for children at the moment
+
+ uint32_t sibling_id; // always a node id, as tnode is never a leaf
+ bool sibling_present = false;
+
+ // if there are more children, or this is the root node, don't try and delete
+ if (parent.num_children > 1) {
+ return;
+ }
+
+ // if there is 1 sibling, it can be moved to be a child of the
+ if (parent.num_children == 1) {
+ // else there is now a redundant node with one child, which can be removed
+ sibling_id = parent.children[0];
+ sibling_present = true;
+ }
+
+ // now there may be no children in this node .. in which case it can be deleted
+ // remove node if empty
+ // remove link from parent
+ uint32_t grandparent_id = parent.parent_id;
+
+ // special case for root node
+ if (grandparent_id == BVHCommon::INVALID) {
+ if (sibling_present) {
+ // change the root node
+ change_root_node(sibling_id, p_tree_id);
+
+ // delete the old root node as no longer needed
+ _nodes.free(p_parent_id);
+ }
+
+ return;
+ }
+
+ if (sibling_present) {
+ node_replace_child(grandparent_id, p_parent_id, sibling_id);
+ } else {
+ node_remove_child(grandparent_id, p_parent_id, p_tree_id, true);
+ }
+
+ // put the node on the free list to recycle
+ _nodes.free(p_parent_id);
+ }
+
+ void change_root_node(uint32_t p_new_root_id, uint32_t p_tree_id) {
+ _root_node_id[p_tree_id] = p_new_root_id;
+ TNode &root = _nodes[p_new_root_id];
+
+ // mark no parent
+ root.parent_id = BVHCommon::INVALID;
+ }
+
+ void node_make_leaf(uint32_t p_node_id) {
+ uint32_t child_leaf_id;
+ TLeaf *child_leaf = _leaves.request(child_leaf_id);
+ child_leaf->clear();
+
+ // zero is reserved at startup, to prevent this id being used
+ // (as they are stored as negative values in the node, and zero is already taken)
+ BVH_ASSERT(child_leaf_id != 0);
+
+ TNode &node = _nodes[p_node_id];
+ node.neg_leaf_id = -(int)child_leaf_id;
+ }
+
+ void node_remove_item(uint32_t p_ref_id, uint32_t p_tree_id, BVHABB_CLASS *r_old_aabb = nullptr) {
+ // get the reference
+ ItemRef &ref = _refs[p_ref_id];
+ uint32_t owner_node_id = ref.tnode_id;
+
+ // debug draw special
+ // This may not be needed
+ if (owner_node_id == BVHCommon::INVALID) {
+ return;
+ }
+
+ TNode &tnode = _nodes[owner_node_id];
+ CRASH_COND(!tnode.is_leaf());
+
+ TLeaf &leaf = _node_get_leaf(tnode);
+
+ // if the aabb is not determining the corner size, then there is no need to refit!
+ // (optimization, as merging AABBs takes a lot of time)
+ const BVHABB_CLASS &old_aabb = leaf.get_aabb(ref.item_id);
+
+ // shrink a little to prevent using corner aabbs
+ // in order to miss the corners first we shrink by node_expansion
+ // (which is added to the overall bound of the leaf), then we also
+ // shrink by an epsilon, in order to miss out the very corner aabbs
+ // which are important in determining the bound. Any other aabb
+ // within this can be removed and not affect the overall bound.
+ BVHABB_CLASS node_bound = tnode.aabb;
+ node_bound.expand(-_node_expansion - 0.001f);
+ bool refit = true;
+
+ if (node_bound.is_other_within(old_aabb)) {
+ refit = false;
+ }
+
+ // record the old aabb if required (for incremental remove_and_reinsert)
+ if (r_old_aabb) {
+ *r_old_aabb = old_aabb;
+ }
+
+ leaf.remove_item_unordered(ref.item_id);
+
+ if (leaf.num_items) {
+ // the swapped item has to have its reference changed to, to point to the new item id
+ uint32_t swapped_ref_id = leaf.get_item_ref_id(ref.item_id);
+
+ ItemRef &swapped_ref = _refs[swapped_ref_id];
+
+ swapped_ref.item_id = ref.item_id;
+
+ // only have to refit if it is an edge item
+ // This is a VERY EXPENSIVE STEP
+ // we defer the refit updates until the update function is called once per frame
+ if (refit) {
+ leaf.set_dirty(true);
+ }
+ } else {
+ // remove node if empty
+ // remove link from parent
+ if (tnode.parent_id != BVHCommon::INVALID) {
+ // DANGER .. this can potentially end up with root node with 1 child ...
+ // we don't want this and must check for it
+
+ uint32_t parent_id = tnode.parent_id;
+
+ node_remove_child(parent_id, owner_node_id, p_tree_id);
+ refit_upward(parent_id);
+
+ // put the node on the free list to recycle
+ _nodes.free(owner_node_id);
+ }
+
+ // else if no parent, it is the root node. Do not delete
+ }
+
+ ref.tnode_id = BVHCommon::INVALID;
+ ref.item_id = BVHCommon::INVALID; // unset
+ }
+
+ // returns true if needs refit of PARENT tree only, the node itself AABB is calculated
+ // within this routine
+ bool _node_add_item(uint32_t p_node_id, uint32_t p_ref_id, const BVHABB_CLASS &p_aabb) {
+ ItemRef &ref = _refs[p_ref_id];
+ ref.tnode_id = p_node_id;
+
+ TNode &node = _nodes[p_node_id];
+ BVH_ASSERT(node.is_leaf());
+ TLeaf &leaf = _node_get_leaf(node);
+
+ // optimization - we only need to do a refit
+ // if the added item is changing the AABB of the node.
+ // in most cases it won't.
+ bool needs_refit = true;
+
+ // expand bound now
+ BVHABB_CLASS expanded = p_aabb;
+ expanded.expand(_node_expansion);
+
+ // the bound will only be valid if there is an item in there already
+ if (leaf.num_items) {
+ if (node.aabb.is_other_within(expanded)) {
+ // no change to node AABBs
+ needs_refit = false;
+ } else {
+ node.aabb.merge(expanded);
+ }
+ } else {
+ // bound of the node = the new aabb
+ node.aabb = expanded;
+ }
+
+ ref.item_id = leaf.request_item();
+ BVH_ASSERT(ref.item_id != BVHCommon::INVALID);
+
+ // set the aabb of the new item
+ leaf.get_aabb(ref.item_id) = p_aabb;
+
+ // back reference on the item back to the item reference
+ leaf.get_item_ref_id(ref.item_id) = p_ref_id;
+
+ return needs_refit;
+ }
+
+ uint32_t _node_create_another_child(uint32_t p_node_id, const BVHABB_CLASS &p_aabb) {
+ uint32_t child_node_id;
+ TNode *child_node = _nodes.request(child_node_id);
+ child_node->clear();
+
+ // may not be necessary
+ child_node->aabb = p_aabb;
+
+ node_add_child(p_node_id, child_node_id);
+
+ return child_node_id;
+ }
+
+#include "bvh_cull.inc"
+#include "bvh_debug.inc"
+#include "bvh_integrity.inc"
+#include "bvh_logic.inc"
+#include "bvh_misc.inc"
+#include "bvh_public.inc"
+#include "bvh_refit.inc"
+#include "bvh_split.inc"
+};
+
+#undef VERBOSE_PRINT
+
+#endif // BVH_TREE_H
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index 1066cf5e30..66c18f7b3c 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -315,8 +315,8 @@ Vector2 CameraMatrix::get_far_plane_half_extents() const {
return Vector2(res.x, res.y);
}
-bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const {
- Vector<Plane> planes = get_projection_planes(Transform());
+bool CameraMatrix::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const {
+ Vector<Plane> planes = get_projection_planes(Transform3D());
const Planes intersections[8][3] = {
{ PLANE_FAR, PLANE_LEFT, PLANE_TOP },
{ PLANE_FAR, PLANE_LEFT, PLANE_BOTTOM },
@@ -338,7 +338,7 @@ bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8point
return true;
}
-Vector<Plane> CameraMatrix::get_projection_planes(const Transform &p_transform) const {
+Vector<Plane> CameraMatrix::get_projection_planes(const Transform3D &p_transform) const {
/** Fast Plane Extraction from combined modelview/projection matrices.
* References:
* https://web.archive.org/web/20011221205252/http://www.markmorley.com/opengl/frustumculling.html
@@ -707,8 +707,8 @@ void CameraMatrix::scale_translate_to_fit(const AABB &p_aabb) {
matrix[3][3] = 1;
}
-CameraMatrix::operator Transform() const {
- Transform tr;
+CameraMatrix::operator Transform3D() const {
+ Transform3D tr;
const real_t *m = &matrix[0][0];
tr.basis.elements[0][0] = m[0];
@@ -730,8 +730,8 @@ CameraMatrix::operator Transform() const {
return tr;
}
-CameraMatrix::CameraMatrix(const Transform &p_transform) {
- const Transform &tr = p_transform;
+CameraMatrix::CameraMatrix(const Transform3D &p_transform) {
+ const Transform3D &tr = p_transform;
real_t *m = &matrix[0][0];
m[0] = tr.basis.elements[0][0];
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index 3f327d3bc4..786d46055a 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -32,7 +32,7 @@
#define CAMERA_MATRIX_H
#include "core/math/rect2.h"
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
struct CameraMatrix {
enum Planes {
@@ -71,9 +71,9 @@ struct CameraMatrix {
real_t get_fov() const;
bool is_orthogonal() const;
- Vector<Plane> get_projection_planes(const Transform &p_transform) const;
+ Vector<Plane> get_projection_planes(const Transform3D &p_transform) const;
- bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const;
+ bool get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const;
Vector2 get_viewport_half_extents() const;
Vector2 get_far_plane_half_extents() const;
@@ -90,7 +90,7 @@ struct CameraMatrix {
void scale_translate_to_fit(const AABB &p_aabb);
void make_scale(const Vector3 &p_scale);
int get_pixels_per_meter(int p_for_pixel_width) const;
- operator Transform() const;
+ operator Transform3D() const;
void flip_y();
@@ -112,7 +112,7 @@ struct CameraMatrix {
float get_lod_multiplier() const;
CameraMatrix();
- CameraMatrix(const Transform &p_transform);
+ CameraMatrix(const Transform3D &p_transform);
~CameraMatrix();
};
diff --git a/core/math/color.cpp b/core/math/color.cpp
index 8affb07e8c..dc86cacf8f 100644
--- a/core/math/color.cpp
+++ b/core/math/color.cpp
@@ -211,6 +211,14 @@ bool Color::is_equal_approx(const Color &p_color) const {
return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a);
}
+Color Color::clamp(const Color &p_min, const Color &p_max) const {
+ return Color(
+ CLAMP(r, p_min.r, p_max.r),
+ CLAMP(g, p_min.g, p_max.g),
+ CLAMP(b, p_min.b, p_max.b),
+ CLAMP(a, p_min.a, p_max.a));
+}
+
void Color::invert() {
r = 1.0 - r;
g = 1.0 - g;
@@ -360,7 +368,7 @@ Color Color::named(const String &p_name) {
ERR_FAIL_V_MSG(Color(), "Invalid color name: " + p_name + ".");
return Color();
}
- return get_named_color(idx);
+ return named_colors[idx].color;
}
Color Color::named(const String &p_name, const Color &p_default) {
@@ -368,7 +376,7 @@ Color Color::named(const String &p_name, const Color &p_default) {
if (idx == -1) {
return p_default;
}
- return get_named_color(idx);
+ return named_colors[idx].color;
}
int Color::find_named_color(const String &p_name) {
@@ -379,11 +387,11 @@ int Color::find_named_color(const String &p_name) {
name = name.replace("_", "");
name = name.replace("'", "");
name = name.replace(".", "");
- name = name.to_lower();
+ name = name.to_upper();
int idx = 0;
while (named_colors[idx].name != nullptr) {
- if (name == named_colors[idx].name) {
+ if (name == String(named_colors[idx].name).replace("_", "")) {
return idx;
}
idx++;
@@ -401,10 +409,12 @@ int Color::get_named_color_count() {
}
String Color::get_named_color_name(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), "");
return named_colors[p_idx].name;
}
Color Color::get_named_color(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), Color());
return named_colors[p_idx].color;
}
@@ -458,7 +468,7 @@ Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const {
}
Color::operator String() const {
- return rtos(r) + ", " + rtos(g) + ", " + rtos(b) + ", " + rtos(a);
+ return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")";
}
Color Color::operator+(const Color &p_color) const {
diff --git a/core/math/color.h b/core/math/color.h
index e404d80c8a..a95dbf4f60 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -89,6 +89,7 @@ struct Color {
bool is_equal_approx(const Color &p_color) const;
+ Color clamp(const Color &p_min = Color(0, 0, 0, 0), const Color &p_max = Color(1, 1, 1, 1)) const;
void invert();
Color inverted() const;
diff --git a/core/math/color_names.inc b/core/math/color_names.inc
index e5b935ea9c..2020bdbfca 100644
--- a/core/math/color_names.inc
+++ b/core/math/color_names.inc
@@ -9,152 +9,155 @@ struct NamedColor {
Color color;
};
+// NOTE: This data is duplicated in the file:
+// modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
+
static NamedColor named_colors[] = {
- { "aliceblue", Color(0.94, 0.97, 1.00) },
- { "antiquewhite", Color(0.98, 0.92, 0.84) },
- { "aqua", Color(0.00, 1.00, 1.00) },
- { "aquamarine", Color(0.50, 1.00, 0.83) },
- { "azure", Color(0.94, 1.00, 1.00) },
- { "beige", Color(0.96, 0.96, 0.86) },
- { "bisque", Color(1.00, 0.89, 0.77) },
- { "black", Color(0.00, 0.00, 0.00) },
- { "blanchedalmond", Color(1.00, 0.92, 0.80) },
- { "blue", Color(0.00, 0.00, 1.00) },
- { "blueviolet", Color(0.54, 0.17, 0.89) },
- { "brown", Color(0.65, 0.16, 0.16) },
- { "burlywood", Color(0.87, 0.72, 0.53) },
- { "cadetblue", Color(0.37, 0.62, 0.63) },
- { "chartreuse", Color(0.50, 1.00, 0.00) },
- { "chocolate", Color(0.82, 0.41, 0.12) },
- { "coral", Color(1.00, 0.50, 0.31) },
- { "cornflower", Color(0.39, 0.58, 0.93) },
- { "cornsilk", Color(1.00, 0.97, 0.86) },
- { "crimson", Color(0.86, 0.08, 0.24) },
- { "cyan", Color(0.00, 1.00, 1.00) },
- { "darkblue", Color(0.00, 0.00, 0.55) },
- { "darkcyan", Color(0.00, 0.55, 0.55) },
- { "darkgoldenrod", Color(0.72, 0.53, 0.04) },
- { "darkgray", Color(0.66, 0.66, 0.66) },
- { "darkgreen", Color(0.00, 0.39, 0.00) },
- { "darkkhaki", Color(0.74, 0.72, 0.42) },
- { "darkmagenta", Color(0.55, 0.00, 0.55) },
- { "darkolivegreen", Color(0.33, 0.42, 0.18) },
- { "darkorange", Color(1.00, 0.55, 0.00) },
- { "darkorchid", Color(0.60, 0.20, 0.80) },
- { "darkred", Color(0.55, 0.00, 0.00) },
- { "darksalmon", Color(0.91, 0.59, 0.48) },
- { "darkseagreen", Color(0.56, 0.74, 0.56) },
- { "darkslateblue", Color(0.28, 0.24, 0.55) },
- { "darkslategray", Color(0.18, 0.31, 0.31) },
- { "darkturquoise", Color(0.00, 0.81, 0.82) },
- { "darkviolet", Color(0.58, 0.00, 0.83) },
- { "deeppink", Color(1.00, 0.08, 0.58) },
- { "deepskyblue", Color(0.00, 0.75, 1.00) },
- { "dimgray", Color(0.41, 0.41, 0.41) },
- { "dodgerblue", Color(0.12, 0.56, 1.00) },
- { "firebrick", Color(0.70, 0.13, 0.13) },
- { "floralwhite", Color(1.00, 0.98, 0.94) },
- { "forestgreen", Color(0.13, 0.55, 0.13) },
- { "fuchsia", Color(1.00, 0.00, 1.00) },
- { "gainsboro", Color(0.86, 0.86, 0.86) },
- { "ghostwhite", Color(0.97, 0.97, 1.00) },
- { "gold", Color(1.00, 0.84, 0.00) },
- { "goldenrod", Color(0.85, 0.65, 0.13) },
- { "gray", Color(0.75, 0.75, 0.75) },
- { "green", Color(0.00, 1.00, 0.00) },
- { "greenyellow", Color(0.68, 1.00, 0.18) },
- { "honeydew", Color(0.94, 1.00, 0.94) },
- { "hotpink", Color(1.00, 0.41, 0.71) },
- { "indianred", Color(0.80, 0.36, 0.36) },
- { "indigo", Color(0.29, 0.00, 0.51) },
- { "ivory", Color(1.00, 1.00, 0.94) },
- { "khaki", Color(0.94, 0.90, 0.55) },
- { "lavender", Color(0.90, 0.90, 0.98) },
- { "lavenderblush", Color(1.00, 0.94, 0.96) },
- { "lawngreen", Color(0.49, 0.99, 0.00) },
- { "lemonchiffon", Color(1.00, 0.98, 0.80) },
- { "lightblue", Color(0.68, 0.85, 0.90) },
- { "lightcoral", Color(0.94, 0.50, 0.50) },
- { "lightcyan", Color(0.88, 1.00, 1.00) },
- { "lightgoldenrod", Color(0.98, 0.98, 0.82) },
- { "lightgray", Color(0.83, 0.83, 0.83) },
- { "lightgreen", Color(0.56, 0.93, 0.56) },
- { "lightpink", Color(1.00, 0.71, 0.76) },
- { "lightsalmon", Color(1.00, 0.63, 0.48) },
- { "lightseagreen", Color(0.13, 0.70, 0.67) },
- { "lightskyblue", Color(0.53, 0.81, 0.98) },
- { "lightslategray", Color(0.47, 0.53, 0.60) },
- { "lightsteelblue", Color(0.69, 0.77, 0.87) },
- { "lightyellow", Color(1.00, 1.00, 0.88) },
- { "lime", Color(0.00, 1.00, 0.00) },
- { "limegreen", Color(0.20, 0.80, 0.20) },
- { "linen", Color(0.98, 0.94, 0.90) },
- { "magenta", Color(1.00, 0.00, 1.00) },
- { "maroon", Color(0.69, 0.19, 0.38) },
- { "mediumaquamarine", Color(0.40, 0.80, 0.67) },
- { "mediumblue", Color(0.00, 0.00, 0.80) },
- { "mediumorchid", Color(0.73, 0.33, 0.83) },
- { "mediumpurple", Color(0.58, 0.44, 0.86) },
- { "mediumseagreen", Color(0.24, 0.70, 0.44) },
- { "mediumslateblue", Color(0.48, 0.41, 0.93) },
- { "mediumspringgreen", Color(0.00, 0.98, 0.60) },
- { "mediumturquoise", Color(0.28, 0.82, 0.80) },
- { "mediumvioletred", Color(0.78, 0.08, 0.52) },
- { "midnightblue", Color(0.10, 0.10, 0.44) },
- { "mintcream", Color(0.96, 1.00, 0.98) },
- { "mistyrose", Color(1.00, 0.89, 0.88) },
- { "moccasin", Color(1.00, 0.89, 0.71) },
- { "navajowhite", Color(1.00, 0.87, 0.68) },
- { "navyblue", Color(0.00, 0.00, 0.50) },
- { "oldlace", Color(0.99, 0.96, 0.90) },
- { "olive", Color(0.50, 0.50, 0.00) },
- { "olivedrab", Color(0.42, 0.56, 0.14) },
- { "orange", Color(1.00, 0.65, 0.00) },
- { "orangered", Color(1.00, 0.27, 0.00) },
- { "orchid", Color(0.85, 0.44, 0.84) },
- { "palegoldenrod", Color(0.93, 0.91, 0.67) },
- { "palegreen", Color(0.60, 0.98, 0.60) },
- { "paleturquoise", Color(0.69, 0.93, 0.93) },
- { "palevioletred", Color(0.86, 0.44, 0.58) },
- { "papayawhip", Color(1.00, 0.94, 0.84) },
- { "peachpuff", Color(1.00, 0.85, 0.73) },
- { "peru", Color(0.80, 0.52, 0.25) },
- { "pink", Color(1.00, 0.75, 0.80) },
- { "plum", Color(0.87, 0.63, 0.87) },
- { "powderblue", Color(0.69, 0.88, 0.90) },
- { "purple", Color(0.63, 0.13, 0.94) },
- { "rebeccapurple", Color(0.40, 0.20, 0.60) },
- { "red", Color(1.00, 0.00, 0.00) },
- { "rosybrown", Color(0.74, 0.56, 0.56) },
- { "royalblue", Color(0.25, 0.41, 0.88) },
- { "saddlebrown", Color(0.55, 0.27, 0.07) },
- { "salmon", Color(0.98, 0.50, 0.45) },
- { "sandybrown", Color(0.96, 0.64, 0.38) },
- { "seagreen", Color(0.18, 0.55, 0.34) },
- { "seashell", Color(1.00, 0.96, 0.93) },
- { "sienna", Color(0.63, 0.32, 0.18) },
- { "silver", Color(0.75, 0.75, 0.75) },
- { "skyblue", Color(0.53, 0.81, 0.92) },
- { "slateblue", Color(0.42, 0.35, 0.80) },
- { "slategray", Color(0.44, 0.50, 0.56) },
- { "snow", Color(1.00, 0.98, 0.98) },
- { "springgreen", Color(0.00, 1.00, 0.50) },
- { "steelblue", Color(0.27, 0.51, 0.71) },
- { "tan", Color(0.82, 0.71, 0.55) },
- { "teal", Color(0.00, 0.50, 0.50) },
- { "thistle", Color(0.85, 0.75, 0.85) },
- { "tomato", Color(1.00, 0.39, 0.28) },
- { "transparent", Color(1.00, 1.00, 1.00, 0.00) },
- { "turquoise", Color(0.25, 0.88, 0.82) },
- { "violet", Color(0.93, 0.51, 0.93) },
- { "webgray", Color(0.50, 0.50, 0.50) },
- { "webgreen", Color(0.00, 0.50, 0.00) },
- { "webmaroon", Color(0.50, 0.00, 0.00) },
- { "webpurple", Color(0.50, 0.00, 0.50) },
- { "wheat", Color(0.96, 0.87, 0.70) },
- { "white", Color(1.00, 1.00, 1.00) },
- { "whitesmoke", Color(0.96, 0.96, 0.96) },
- { "yellow", Color(1.00, 1.00, 0.00) },
- { "yellowgreen", Color(0.60, 0.80, 0.20) },
+ { "ALICE_BLUE", Color(0.94, 0.97, 1.00) },
+ { "ANTIQUE_WHITE", Color(0.98, 0.92, 0.84) },
+ { "AQUA", Color(0.00, 1.00, 1.00) },
+ { "AQUAMARINE", Color(0.50, 1.00, 0.83) },
+ { "AZURE", Color(0.94, 1.00, 1.00) },
+ { "BEIGE", Color(0.96, 0.96, 0.86) },
+ { "BISQUE", Color(1.00, 0.89, 0.77) },
+ { "BLACK", Color(0.00, 0.00, 0.00) },
+ { "BLANCHED_ALMOND", Color(1.00, 0.92, 0.80) },
+ { "BLUE", Color(0.00, 0.00, 1.00) },
+ { "BLUE_VIOLET", Color(0.54, 0.17, 0.89) },
+ { "BROWN", Color(0.65, 0.16, 0.16) },
+ { "BURLYWOOD", Color(0.87, 0.72, 0.53) },
+ { "CADET_BLUE", Color(0.37, 0.62, 0.63) },
+ { "CHARTREUSE", Color(0.50, 1.00, 0.00) },
+ { "CHOCOLATE", Color(0.82, 0.41, 0.12) },
+ { "CORAL", Color(1.00, 0.50, 0.31) },
+ { "CORNFLOWER_BLUE", Color(0.39, 0.58, 0.93) },
+ { "CORNSILK", Color(1.00, 0.97, 0.86) },
+ { "CRIMSON", Color(0.86, 0.08, 0.24) },
+ { "CYAN", Color(0.00, 1.00, 1.00) },
+ { "DARK_BLUE", Color(0.00, 0.00, 0.55) },
+ { "DARK_CYAN", Color(0.00, 0.55, 0.55) },
+ { "DARK_GOLDENROD", Color(0.72, 0.53, 0.04) },
+ { "DARK_GRAY", Color(0.66, 0.66, 0.66) },
+ { "DARK_GREEN", Color(0.00, 0.39, 0.00) },
+ { "DARK_KHAKI", Color(0.74, 0.72, 0.42) },
+ { "DARK_MAGENTA", Color(0.55, 0.00, 0.55) },
+ { "DARK_OLIVE_GREEN", Color(0.33, 0.42, 0.18) },
+ { "DARK_ORANGE", Color(1.00, 0.55, 0.00) },
+ { "DARK_ORCHID", Color(0.60, 0.20, 0.80) },
+ { "DARK_RED", Color(0.55, 0.00, 0.00) },
+ { "DARK_SALMON", Color(0.91, 0.59, 0.48) },
+ { "DARK_SEA_GREEN", Color(0.56, 0.74, 0.56) },
+ { "DARK_SLATE_BLUE", Color(0.28, 0.24, 0.55) },
+ { "DARK_SLATE_GRAY", Color(0.18, 0.31, 0.31) },
+ { "DARK_TURQUOISE", Color(0.00, 0.81, 0.82) },
+ { "DARK_VIOLET", Color(0.58, 0.00, 0.83) },
+ { "DEEP_PINK", Color(1.00, 0.08, 0.58) },
+ { "DEEP_SKY_BLUE", Color(0.00, 0.75, 1.00) },
+ { "DIM_GRAY", Color(0.41, 0.41, 0.41) },
+ { "DODGER_BLUE", Color(0.12, 0.56, 1.00) },
+ { "FIREBRICK", Color(0.70, 0.13, 0.13) },
+ { "FLORAL_WHITE", Color(1.00, 0.98, 0.94) },
+ { "FOREST_GREEN", Color(0.13, 0.55, 0.13) },
+ { "FUCHSIA", Color(1.00, 0.00, 1.00) },
+ { "GAINSBORO", Color(0.86, 0.86, 0.86) },
+ { "GHOST_WHITE", Color(0.97, 0.97, 1.00) },
+ { "GOLD", Color(1.00, 0.84, 0.00) },
+ { "GOLDENROD", Color(0.85, 0.65, 0.13) },
+ { "GRAY", Color(0.75, 0.75, 0.75) },
+ { "GREEN", Color(0.00, 1.00, 0.00) },
+ { "GREEN_YELLOW", Color(0.68, 1.00, 0.18) },
+ { "HONEYDEW", Color(0.94, 1.00, 0.94) },
+ { "HOT_PINK", Color(1.00, 0.41, 0.71) },
+ { "INDIAN_RED", Color(0.80, 0.36, 0.36) },
+ { "INDIGO", Color(0.29, 0.00, 0.51) },
+ { "IVORY", Color(1.00, 1.00, 0.94) },
+ { "KHAKI", Color(0.94, 0.90, 0.55) },
+ { "LAVENDER", Color(0.90, 0.90, 0.98) },
+ { "LAVENDER_BLUSH", Color(1.00, 0.94, 0.96) },
+ { "LAWN_GREEN", Color(0.49, 0.99, 0.00) },
+ { "LEMON_CHIFFON", Color(1.00, 0.98, 0.80) },
+ { "LIGHT_BLUE", Color(0.68, 0.85, 0.90) },
+ { "LIGHT_CORAL", Color(0.94, 0.50, 0.50) },
+ { "LIGHT_CYAN", Color(0.88, 1.00, 1.00) },
+ { "LIGHT_GOLDENROD", Color(0.98, 0.98, 0.82) },
+ { "LIGHT_GRAY", Color(0.83, 0.83, 0.83) },
+ { "LIGHT_GREEN", Color(0.56, 0.93, 0.56) },
+ { "LIGHT_PINK", Color(1.00, 0.71, 0.76) },
+ { "LIGHT_SALMON", Color(1.00, 0.63, 0.48) },
+ { "LIGHT_SEA_GREEN", Color(0.13, 0.70, 0.67) },
+ { "LIGHT_SKY_BLUE", Color(0.53, 0.81, 0.98) },
+ { "LIGHT_SLATE_GRAY", Color(0.47, 0.53, 0.60) },
+ { "LIGHT_STEEL_BLUE", Color(0.69, 0.77, 0.87) },
+ { "LIGHT_YELLOW", Color(1.00, 1.00, 0.88) },
+ { "LIME", Color(0.00, 1.00, 0.00) },
+ { "LIME_GREEN", Color(0.20, 0.80, 0.20) },
+ { "LINEN", Color(0.98, 0.94, 0.90) },
+ { "MAGENTA", Color(1.00, 0.00, 1.00) },
+ { "MAROON", Color(0.69, 0.19, 0.38) },
+ { "MEDIUM_AQUAMARINE", Color(0.40, 0.80, 0.67) },
+ { "MEDIUM_BLUE", Color(0.00, 0.00, 0.80) },
+ { "MEDIUM_ORCHID", Color(0.73, 0.33, 0.83) },
+ { "MEDIUM_PURPLE", Color(0.58, 0.44, 0.86) },
+ { "MEDIUM_SEA_GREEN", Color(0.24, 0.70, 0.44) },
+ { "MEDIUM_SLATE_BLUE", Color(0.48, 0.41, 0.93) },
+ { "MEDIUM_SPRING_GREEN", Color(0.00, 0.98, 0.60) },
+ { "MEDIUM_TURQUOISE", Color(0.28, 0.82, 0.80) },
+ { "MEDIUM_VIOLET_RED", Color(0.78, 0.08, 0.52) },
+ { "MIDNIGHT_BLUE", Color(0.10, 0.10, 0.44) },
+ { "MINT_CREAM", Color(0.96, 1.00, 0.98) },
+ { "MISTY_ROSE", Color(1.00, 0.89, 0.88) },
+ { "MOCCASIN", Color(1.00, 0.89, 0.71) },
+ { "NAVAJO_WHITE", Color(1.00, 0.87, 0.68) },
+ { "NAVY_BLUE", Color(0.00, 0.00, 0.50) },
+ { "OLD_LACE", Color(0.99, 0.96, 0.90) },
+ { "OLIVE", Color(0.50, 0.50, 0.00) },
+ { "OLIVE_DRAB", Color(0.42, 0.56, 0.14) },
+ { "ORANGE", Color(1.00, 0.65, 0.00) },
+ { "ORANGE_RED", Color(1.00, 0.27, 0.00) },
+ { "ORCHID", Color(0.85, 0.44, 0.84) },
+ { "PALE_GOLDENROD", Color(0.93, 0.91, 0.67) },
+ { "PALE_GREEN", Color(0.60, 0.98, 0.60) },
+ { "PALE_TURQUOISE", Color(0.69, 0.93, 0.93) },
+ { "PALE_VIOLET_RED", Color(0.86, 0.44, 0.58) },
+ { "PAPAYA_WHIP", Color(1.00, 0.94, 0.84) },
+ { "PEACH_PUFF", Color(1.00, 0.85, 0.73) },
+ { "PERU", Color(0.80, 0.52, 0.25) },
+ { "PINK", Color(1.00, 0.75, 0.80) },
+ { "PLUM", Color(0.87, 0.63, 0.87) },
+ { "POWDER_BLUE", Color(0.69, 0.88, 0.90) },
+ { "PURPLE", Color(0.63, 0.13, 0.94) },
+ { "REBECCA_PURPLE", Color(0.40, 0.20, 0.60) },
+ { "RED", Color(1.00, 0.00, 0.00) },
+ { "ROSY_BROWN", Color(0.74, 0.56, 0.56) },
+ { "ROYAL_BLUE", Color(0.25, 0.41, 0.88) },
+ { "SADDLE_BROWN", Color(0.55, 0.27, 0.07) },
+ { "SALMON", Color(0.98, 0.50, 0.45) },
+ { "SANDY_BROWN", Color(0.96, 0.64, 0.38) },
+ { "SEA_GREEN", Color(0.18, 0.55, 0.34) },
+ { "SEASHELL", Color(1.00, 0.96, 0.93) },
+ { "SIENNA", Color(0.63, 0.32, 0.18) },
+ { "SILVER", Color(0.75, 0.75, 0.75) },
+ { "SKY_BLUE", Color(0.53, 0.81, 0.92) },
+ { "SLATE_BLUE", Color(0.42, 0.35, 0.80) },
+ { "SLATE_GRAY", Color(0.44, 0.50, 0.56) },
+ { "SNOW", Color(1.00, 0.98, 0.98) },
+ { "SPRING_GREEN", Color(0.00, 1.00, 0.50) },
+ { "STEEL_BLUE", Color(0.27, 0.51, 0.71) },
+ { "TAN", Color(0.82, 0.71, 0.55) },
+ { "TEAL", Color(0.00, 0.50, 0.50) },
+ { "THISTLE", Color(0.85, 0.75, 0.85) },
+ { "TOMATO", Color(1.00, 0.39, 0.28) },
+ { "TRANSPARENT", Color(1.00, 1.00, 1.00, 0.00) },
+ { "TURQUOISE", Color(0.25, 0.88, 0.82) },
+ { "VIOLET", Color(0.93, 0.51, 0.93) },
+ { "WEB_GRAY", Color(0.50, 0.50, 0.50) },
+ { "WEB_GREEN", Color(0.00, 0.50, 0.00) },
+ { "WEB_MAROON", Color(0.50, 0.00, 0.00) },
+ { "WEB_PURPLE", Color(0.50, 0.00, 0.50) },
+ { "WHEAT", Color(0.96, 0.87, 0.70) },
+ { "WHITE", Color(1.00, 1.00, 1.00) },
+ { "WHITE_SMOKE", Color(0.96, 0.96, 0.96) },
+ { "YELLOW", Color(1.00, 1.00, 0.00) },
+ { "YELLOW_GREEN", Color(0.60, 0.80, 0.20) },
{ nullptr, Color() },
};
diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp
new file mode 100644
index 0000000000..682a7ea39e
--- /dev/null
+++ b/core/math/convex_hull.cpp
@@ -0,0 +1,2290 @@
+/*************************************************************************/
+/* convex_hull.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+ * Based on Godot's patched VHACD-version of Bullet's btConvexHullComputer.
+ * See /thirdparty/vhacd/btConvexHullComputer.cpp at 64403ddcab9f1dca2408f0a412a22d899708bbb1
+ * In turn, based on /src/LinearMath/btConvexHullComputer.cpp in <https://github.com/bulletphysics/bullet3>
+ * at 73b217fb07e7e3ce126caeb28ab3c9ddd0718467
+ *
+ * Changes:
+ * - int32_t is consistently used instead of int in some cases
+ * - integrated patch db0d6c92927f5a1358b887f2645c11f3014f0e8a from Bullet (CWE-190 integer overflow in btConvexHullComputer)
+ * - adapted to Godot's code style
+ * - replaced Bullet's types (e.g. vectors) with Godot's
+ * - replaced custom Pool implementation with PagedAllocator
+ */
+
+/*
+Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net
+
+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 "convex_hull.h"
+
+#include "core/error/error_macros.h"
+#include "core/math/aabb.h"
+#include "core/math/math_defs.h"
+#include "core/os/memory.h"
+#include "core/templates/paged_allocator.h"
+
+#include <string.h>
+
+//#define DEBUG_CONVEX_HULL
+//#define SHOW_ITERATIONS
+
+// -- GODOT start --
+// Assembly optimizations are not used at the moment.
+//#define USE_X86_64_ASM
+// -- GODOT end --
+
+#ifdef DEBUG_ENABLED
+#define CHULL_ASSERT(m_cond) \
+ do { \
+ if (unlikely(!(m_cond))) { \
+ ERR_PRINT("Assertion \"" _STR(m_cond) "\" failed."); \
+ } \
+ } while (0)
+#else
+#define CHULL_ASSERT(m_cond) \
+ do { \
+ } while (0)
+#endif
+
+#if defined(DEBUG_CONVEX_HULL) || defined(SHOW_ITERATIONS)
+#include <stdio.h>
+#endif
+
+// Convex hull implementation based on Preparata and Hong
+// Ole Kniemeyer, MAXON Computer GmbH
+class ConvexHullInternal {
+public:
+ class Point64 {
+ public:
+ int64_t x;
+ int64_t y;
+ int64_t z;
+
+ Point64(int64_t p_x, int64_t p_y, int64_t p_z) {
+ x = p_x;
+ y = p_y;
+ z = p_z;
+ }
+
+ bool is_zero() {
+ return (x == 0) && (y == 0) && (z == 0);
+ }
+
+ int64_t dot(const Point64 &b) const {
+ return x * b.x + y * b.y + z * b.z;
+ }
+ };
+
+ class Point32 {
+ public:
+ int32_t x = 0;
+ int32_t y = 0;
+ int32_t z = 0;
+ int32_t index = -1;
+
+ Point32() {
+ }
+
+ Point32(int32_t p_x, int32_t p_y, int32_t p_z) {
+ x = p_x;
+ y = p_y;
+ z = p_z;
+ }
+
+ bool operator==(const Point32 &b) const {
+ return (x == b.x) && (y == b.y) && (z == b.z);
+ }
+
+ bool operator!=(const Point32 &b) const {
+ return (x != b.x) || (y != b.y) || (z != b.z);
+ }
+
+ bool is_zero() {
+ return (x == 0) && (y == 0) && (z == 0);
+ }
+
+ Point64 cross(const Point32 &b) const {
+ return Point64((int64_t)y * b.z - (int64_t)z * b.y, (int64_t)z * b.x - (int64_t)x * b.z, (int64_t)x * b.y - (int64_t)y * b.x);
+ }
+
+ Point64 cross(const Point64 &b) const {
+ return Point64(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x);
+ }
+
+ int64_t dot(const Point32 &b) const {
+ return (int64_t)x * b.x + (int64_t)y * b.y + (int64_t)z * b.z;
+ }
+
+ int64_t dot(const Point64 &b) const {
+ return x * b.x + y * b.y + z * b.z;
+ }
+
+ Point32 operator+(const Point32 &b) const {
+ return Point32(x + b.x, y + b.y, z + b.z);
+ }
+
+ Point32 operator-(const Point32 &b) const {
+ return Point32(x - b.x, y - b.y, z - b.z);
+ }
+ };
+
+ class Int128 {
+ public:
+ uint64_t low = 0;
+ uint64_t high = 0;
+
+ Int128() {
+ }
+
+ Int128(uint64_t p_low, uint64_t p_high) {
+ low = p_low;
+ high = p_high;
+ }
+
+ Int128(uint64_t p_low) {
+ low = p_low;
+ high = 0;
+ }
+
+ Int128(int64_t p_value) {
+ low = p_value;
+ if (p_value >= 0) {
+ high = 0;
+ } else {
+ high = (uint64_t)-1LL;
+ }
+ }
+
+ static Int128 mul(int64_t a, int64_t b);
+
+ static Int128 mul(uint64_t a, uint64_t b);
+
+ Int128 operator-() const {
+ return Int128((uint64_t) - (int64_t)low, ~high + (low == 0));
+ }
+
+ Int128 operator+(const Int128 &b) const {
+#ifdef USE_X86_64_ASM
+ Int128 result;
+ __asm__("addq %[bl], %[rl]\n\t"
+ "adcq %[bh], %[rh]\n\t"
+ : [rl] "=r"(result.low), [rh] "=r"(result.high)
+ : "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high)
+ : "cc");
+ return result;
+#else
+ uint64_t lo = low + b.low;
+ return Int128(lo, high + b.high + (lo < low));
+#endif
+ }
+
+ Int128 operator-(const Int128 &b) const {
+#ifdef USE_X86_64_ASM
+ Int128 result;
+ __asm__("subq %[bl], %[rl]\n\t"
+ "sbbq %[bh], %[rh]\n\t"
+ : [rl] "=r"(result.low), [rh] "=r"(result.high)
+ : "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high)
+ : "cc");
+ return result;
+#else
+ return *this + -b;
+#endif
+ }
+
+ Int128 &operator+=(const Int128 &b) {
+#ifdef USE_X86_64_ASM
+ __asm__("addq %[bl], %[rl]\n\t"
+ "adcq %[bh], %[rh]\n\t"
+ : [rl] "=r"(low), [rh] "=r"(high)
+ : "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high)
+ : "cc");
+#else
+ uint64_t lo = low + b.low;
+ if (lo < low) {
+ ++high;
+ }
+ low = lo;
+ high += b.high;
+#endif
+ return *this;
+ }
+
+ Int128 &operator++() {
+ if (++low == 0) {
+ ++high;
+ }
+ return *this;
+ }
+
+ Int128 operator*(int64_t b) const;
+
+ real_t to_scalar() const {
+ return ((int64_t)high >= 0) ? real_t(high) * (real_t(0x100000000LL) * real_t(0x100000000LL)) + real_t(low) : -(-*this).to_scalar();
+ }
+
+ int32_t get_sign() const {
+ return ((int64_t)high < 0) ? -1 : (high || low) ? 1 :
+ 0;
+ }
+
+ bool operator<(const Int128 &b) const {
+ return (high < b.high) || ((high == b.high) && (low < b.low));
+ }
+
+ int32_t ucmp(const Int128 &b) const {
+ if (high < b.high) {
+ return -1;
+ }
+ if (high > b.high) {
+ return 1;
+ }
+ if (low < b.low) {
+ return -1;
+ }
+ if (low > b.low) {
+ return 1;
+ }
+ return 0;
+ }
+ };
+
+ class Rational64 {
+ private:
+ uint64_t numerator;
+ uint64_t denominator;
+ int32_t sign;
+
+ public:
+ Rational64(int64_t p_numerator, int64_t p_denominator) {
+ if (p_numerator > 0) {
+ sign = 1;
+ numerator = (uint64_t)p_numerator;
+ } else if (p_numerator < 0) {
+ sign = -1;
+ numerator = (uint64_t)-p_numerator;
+ } else {
+ sign = 0;
+ numerator = 0;
+ }
+ if (p_denominator > 0) {
+ denominator = (uint64_t)p_denominator;
+ } else if (p_denominator < 0) {
+ sign = -sign;
+ denominator = (uint64_t)-p_denominator;
+ } else {
+ denominator = 0;
+ }
+ }
+
+ bool is_negative_infinity() const {
+ return (sign < 0) && (denominator == 0);
+ }
+
+ bool is_nan() const {
+ return (sign == 0) && (denominator == 0);
+ }
+
+ int32_t compare(const Rational64 &b) const;
+
+ real_t to_scalar() const {
+ return sign * ((denominator == 0) ? FLT_MAX : (real_t)numerator / denominator);
+ }
+ };
+
+ class Rational128 {
+ private:
+ Int128 numerator;
+ Int128 denominator;
+ int32_t sign;
+ bool is_int_64;
+
+ public:
+ Rational128(int64_t p_value) {
+ if (p_value > 0) {
+ sign = 1;
+ this->numerator = p_value;
+ } else if (p_value < 0) {
+ sign = -1;
+ this->numerator = -p_value;
+ } else {
+ sign = 0;
+ this->numerator = (uint64_t)0;
+ }
+ this->denominator = (uint64_t)1;
+ is_int_64 = true;
+ }
+
+ Rational128(const Int128 &p_numerator, const Int128 &p_denominator) {
+ sign = p_numerator.get_sign();
+ if (sign >= 0) {
+ this->numerator = p_numerator;
+ } else {
+ this->numerator = -p_numerator;
+ }
+ int32_t dsign = p_denominator.get_sign();
+ if (dsign >= 0) {
+ this->denominator = p_denominator;
+ } else {
+ sign = -sign;
+ this->denominator = -p_denominator;
+ }
+ is_int_64 = false;
+ }
+
+ int32_t compare(const Rational128 &b) const;
+
+ int32_t compare(int64_t b) const;
+
+ real_t to_scalar() const {
+ return sign * ((denominator.get_sign() == 0) ? FLT_MAX : numerator.to_scalar() / denominator.to_scalar());
+ }
+ };
+
+ class PointR128 {
+ public:
+ Int128 x;
+ Int128 y;
+ Int128 z;
+ Int128 denominator;
+
+ PointR128() {
+ }
+
+ PointR128(Int128 p_x, Int128 p_y, Int128 p_z, Int128 p_denominator) {
+ x = p_x;
+ y = p_y;
+ z = p_z;
+ denominator = p_denominator;
+ }
+
+ real_t xvalue() const {
+ return x.to_scalar() / denominator.to_scalar();
+ }
+
+ real_t yvalue() const {
+ return y.to_scalar() / denominator.to_scalar();
+ }
+
+ real_t zvalue() const {
+ return z.to_scalar() / denominator.to_scalar();
+ }
+ };
+
+ class Edge;
+ class Face;
+
+ class Vertex {
+ public:
+ Vertex *next = nullptr;
+ Vertex *prev = nullptr;
+ Edge *edges = nullptr;
+ Face *first_nearby_face = nullptr;
+ Face *last_nearby_face = nullptr;
+ PointR128 point128;
+ Point32 point;
+ int32_t copy = -1;
+
+ Vertex() {
+ }
+
+#ifdef DEBUG_CONVEX_HULL
+ void print() {
+ printf("V%d (%d, %d, %d)", point.index, point.x, point.y, point.z);
+ }
+
+ void print_graph();
+#endif
+
+ Point32 operator-(const Vertex &b) const {
+ return point - b.point;
+ }
+
+ Rational128 dot(const Point64 &b) const {
+ return (point.index >= 0) ? Rational128(point.dot(b)) : Rational128(point128.x * b.x + point128.y * b.y + point128.z * b.z, point128.denominator);
+ }
+
+ real_t xvalue() const {
+ return (point.index >= 0) ? real_t(point.x) : point128.xvalue();
+ }
+
+ real_t yvalue() const {
+ return (point.index >= 0) ? real_t(point.y) : point128.yvalue();
+ }
+
+ real_t zvalue() const {
+ return (point.index >= 0) ? real_t(point.z) : point128.zvalue();
+ }
+
+ void receive_nearby_faces(Vertex *p_src) {
+ if (last_nearby_face) {
+ last_nearby_face->next_with_same_nearby_vertex = p_src->first_nearby_face;
+ } else {
+ first_nearby_face = p_src->first_nearby_face;
+ }
+ if (p_src->last_nearby_face) {
+ last_nearby_face = p_src->last_nearby_face;
+ }
+ for (Face *f = p_src->first_nearby_face; f; f = f->next_with_same_nearby_vertex) {
+ CHULL_ASSERT(f->nearby_vertex == p_src);
+ f->nearby_vertex = this;
+ }
+ p_src->first_nearby_face = nullptr;
+ p_src->last_nearby_face = nullptr;
+ }
+ };
+
+ class Edge {
+ public:
+ Edge *next = nullptr;
+ Edge *prev = nullptr;
+ Edge *reverse = nullptr;
+ Vertex *target = nullptr;
+ Face *face = nullptr;
+ int32_t copy = -1;
+
+ void link(Edge *n) {
+ CHULL_ASSERT(reverse->target == n->reverse->target);
+ next = n;
+ n->prev = this;
+ }
+
+#ifdef DEBUG_CONVEX_HULL
+ void print() {
+ printf("E%p : %d -> %d, n=%p p=%p (0 %d\t%d\t%d) -> (%d %d %d)", this, reverse->target->point.index, target->point.index, next, prev,
+ reverse->target->point.x, reverse->target->point.y, reverse->target->point.z, target->point.x, target->point.y, target->point.z);
+ }
+#endif
+ };
+
+ class Face {
+ public:
+ Face *next = nullptr;
+ Vertex *nearby_vertex = nullptr;
+ Face *next_with_same_nearby_vertex = nullptr;
+ Point32 origin;
+ Point32 dir0;
+ Point32 dir1;
+
+ Face() {
+ }
+
+ void init(Vertex *p_a, Vertex *p_b, Vertex *p_c) {
+ nearby_vertex = p_a;
+ origin = p_a->point;
+ dir0 = *p_b - *p_a;
+ dir1 = *p_c - *p_a;
+ if (p_a->last_nearby_face) {
+ p_a->last_nearby_face->next_with_same_nearby_vertex = this;
+ } else {
+ p_a->first_nearby_face = this;
+ }
+ p_a->last_nearby_face = this;
+ }
+
+ Point64 get_normal() {
+ return dir0.cross(dir1);
+ }
+ };
+
+ template <typename UWord, typename UHWord>
+ class DMul {
+ private:
+ static uint32_t high(uint64_t p_value) {
+ return (uint32_t)(p_value >> 32);
+ }
+
+ static uint32_t low(uint64_t p_value) {
+ return (uint32_t)p_value;
+ }
+
+ static uint64_t mul(uint32_t a, uint32_t b) {
+ return (uint64_t)a * (uint64_t)b;
+ }
+
+ static void shl_half(uint64_t &p_value) {
+ p_value <<= 32;
+ }
+
+ static uint64_t high(Int128 p_value) {
+ return p_value.high;
+ }
+
+ static uint64_t low(Int128 p_value) {
+ return p_value.low;
+ }
+
+ static Int128 mul(uint64_t a, uint64_t b) {
+ return Int128::mul(a, b);
+ }
+
+ static void shl_half(Int128 &p_value) {
+ p_value.high = p_value.low;
+ p_value.low = 0;
+ }
+
+ public:
+ static void mul(UWord p_a, UWord p_b, UWord &r_low, UWord &r_high) {
+ UWord p00 = mul(low(p_a), low(p_b));
+ UWord p01 = mul(low(p_a), high(p_b));
+ UWord p10 = mul(high(p_a), low(p_b));
+ UWord p11 = mul(high(p_a), high(p_b));
+ UWord p0110 = UWord(low(p01)) + UWord(low(p10));
+ p11 += high(p01);
+ p11 += high(p10);
+ p11 += high(p0110);
+ shl_half(p0110);
+ p00 += p0110;
+ if (p00 < p0110) {
+ ++p11;
+ }
+ r_low = p00;
+ r_high = p11;
+ }
+ };
+
+private:
+ class IntermediateHull {
+ public:
+ Vertex *min_xy = nullptr;
+ Vertex *max_xy = nullptr;
+ Vertex *min_yx = nullptr;
+ Vertex *max_yx = nullptr;
+
+ IntermediateHull() {
+ }
+
+ void print();
+ };
+
+ enum Orientation { NONE,
+ CLOCKWISE,
+ COUNTER_CLOCKWISE };
+
+ Vector3 scaling;
+ Vector3 center;
+ PagedAllocator<Vertex> vertex_pool;
+ PagedAllocator<Edge> edge_pool;
+ PagedAllocator<Face> face_pool;
+ LocalVector<Vertex *> original_vertices;
+ int32_t merge_stamp = 0;
+ int32_t min_axis = 0;
+ int32_t med_axis = 0;
+ int32_t max_axis = 0;
+ int32_t used_edge_pairs = 0;
+ int32_t max_used_edge_pairs = 0;
+
+ static Orientation get_orientation(const Edge *p_prev, const Edge *p_next, const Point32 &p_s, const Point32 &p_t);
+ Edge *find_max_angle(bool p_ccw, const Vertex *p_start, const Point32 &p_s, const Point64 &p_rxs, const Point64 &p_ssxrxs, Rational64 &p_min_cot);
+ void find_edge_for_coplanar_faces(Vertex *p_c0, Vertex *p_c1, Edge *&p_e0, Edge *&p_e1, Vertex *p_stop0, Vertex *p_stop1);
+
+ Edge *new_edge_pair(Vertex *p_from, Vertex *p_to);
+
+ void remove_edge_pair(Edge *p_edge) {
+ Edge *n = p_edge->next;
+ Edge *r = p_edge->reverse;
+
+ CHULL_ASSERT(p_edge->target && r->target);
+
+ if (n != p_edge) {
+ n->prev = p_edge->prev;
+ p_edge->prev->next = n;
+ r->target->edges = n;
+ } else {
+ r->target->edges = nullptr;
+ }
+
+ n = r->next;
+
+ if (n != r) {
+ n->prev = r->prev;
+ r->prev->next = n;
+ p_edge->target->edges = n;
+ } else {
+ p_edge->target->edges = nullptr;
+ }
+
+ edge_pool.free(p_edge);
+ edge_pool.free(r);
+ used_edge_pairs--;
+ }
+
+ void compute_internal(int32_t p_start, int32_t p_end, IntermediateHull &r_result);
+
+ bool merge_projection(IntermediateHull &p_h0, IntermediateHull &p_h1, Vertex *&r_c0, Vertex *&r_c1);
+
+ void merge(IntermediateHull &p_h0, IntermediateHull &p_h1);
+
+ Vector3 to_gd_vector(const Point32 &p_v);
+
+ Vector3 get_gd_normal(Face *p_face);
+
+ bool shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> p_stack);
+
+public:
+ ~ConvexHullInternal() {
+ vertex_pool.reset(true);
+ edge_pool.reset(true);
+ face_pool.reset(true);
+ }
+
+ Vertex *vertex_list;
+
+ void compute(const Vector3 *p_coords, int32_t p_count);
+
+ Vector3 get_coordinates(const Vertex *p_v);
+
+ real_t shrink(real_t amount, real_t p_clamp_amount);
+};
+
+ConvexHullInternal::Int128 ConvexHullInternal::Int128::operator*(int64_t b) const {
+ bool negative = (int64_t)high < 0;
+ Int128 a = negative ? -*this : *this;
+ if (b < 0) {
+ negative = !negative;
+ b = -b;
+ }
+ Int128 result = mul(a.low, (uint64_t)b);
+ result.high += a.high * (uint64_t)b;
+ return negative ? -result : result;
+}
+
+ConvexHullInternal::Int128 ConvexHullInternal::Int128::mul(int64_t a, int64_t b) {
+ Int128 result;
+
+#ifdef USE_X86_64_ASM
+ __asm__("imulq %[b]"
+ : "=a"(result.low), "=d"(result.high)
+ : "0"(a), [b] "r"(b)
+ : "cc");
+ return result;
+
+#else
+ bool negative = a < 0;
+ if (negative) {
+ a = -a;
+ }
+ if (b < 0) {
+ negative = !negative;
+ b = -b;
+ }
+ DMul<uint64_t, uint32_t>::mul((uint64_t)a, (uint64_t)b, result.low, result.high);
+ return negative ? -result : result;
+#endif
+}
+
+ConvexHullInternal::Int128 ConvexHullInternal::Int128::mul(uint64_t a, uint64_t b) {
+ Int128 result;
+
+#ifdef USE_X86_64_ASM
+ __asm__("mulq %[b]"
+ : "=a"(result.low), "=d"(result.high)
+ : "0"(a), [b] "r"(b)
+ : "cc");
+
+#else
+ DMul<uint64_t, uint32_t>::mul(a, b, result.low, result.high);
+#endif
+
+ return result;
+}
+
+int32_t ConvexHullInternal::Rational64::compare(const Rational64 &b) const {
+ if (sign != b.sign) {
+ return sign - b.sign;
+ } else if (sign == 0) {
+ return 0;
+ }
+
+ // return (numerator * b.denominator > b.numerator * denominator) ? sign : (numerator * b.denominator < b.numerator * denominator) ? -sign : 0;
+
+#ifdef USE_X86_64_ASM
+
+ int32_t result;
+ int64_t tmp;
+ int64_t dummy;
+ __asm__("mulq %[bn]\n\t"
+ "movq %%rax, %[tmp]\n\t"
+ "movq %%rdx, %%rbx\n\t"
+ "movq %[tn], %%rax\n\t"
+ "mulq %[bd]\n\t"
+ "subq %[tmp], %%rax\n\t"
+ "sbbq %%rbx, %%rdx\n\t" // rdx:rax contains 128-bit-difference "numerator*b.denominator - b.numerator*denominator"
+ "setnsb %%bh\n\t" // bh=1 if difference is non-negative, bh=0 otherwise
+ "orq %%rdx, %%rax\n\t"
+ "setnzb %%bl\n\t" // bl=1 if difference if non-zero, bl=0 if it is zero
+ "decb %%bh\n\t" // now bx=0x0000 if difference is zero, 0xff01 if it is negative, 0x0001 if it is positive (i.e., same sign as difference)
+ "shll $16, %%ebx\n\t" // ebx has same sign as difference
+ : "=&b"(result), [tmp] "=&r"(tmp), "=a"(dummy)
+ : "a"(denominator), [bn] "g"(b.numerator), [tn] "g"(numerator), [bd] "g"(b.denominator)
+ : "%rdx", "cc");
+ return result ? result ^ sign // if sign is +1, only bit 0 of result is inverted, which does not change the sign of result (and cannot result in zero)
+ // if sign is -1, all bits of result are inverted, which changes the sign of result (and again cannot result in zero)
+ :
+ 0;
+
+#else
+
+ return sign * Int128::mul(numerator, b.denominator).ucmp(Int128::mul(denominator, b.numerator));
+
+#endif
+}
+
+int32_t ConvexHullInternal::Rational128::compare(const Rational128 &b) const {
+ if (sign != b.sign) {
+ return sign - b.sign;
+ } else if (sign == 0) {
+ return 0;
+ }
+ if (is_int_64) {
+ return -b.compare(sign * (int64_t)numerator.low);
+ }
+
+ Int128 nbd_low, nbd_high, dbn_low, dbn_high;
+ DMul<Int128, uint64_t>::mul(numerator, b.denominator, nbd_low, nbd_high);
+ DMul<Int128, uint64_t>::mul(denominator, b.numerator, dbn_low, dbn_high);
+
+ int32_t cmp = nbd_high.ucmp(dbn_high);
+ if (cmp) {
+ return cmp * sign;
+ }
+ return nbd_low.ucmp(dbn_low) * sign;
+}
+
+int32_t ConvexHullInternal::Rational128::compare(int64_t b) const {
+ if (is_int_64) {
+ int64_t a = sign * (int64_t)numerator.low;
+ return (a > b) ? 1 : (a < b) ? -1 :
+ 0;
+ }
+ if (b > 0) {
+ if (sign <= 0) {
+ return -1;
+ }
+ } else if (b < 0) {
+ if (sign >= 0) {
+ return 1;
+ }
+ b = -b;
+ } else {
+ return sign;
+ }
+
+ return numerator.ucmp(denominator * b) * sign;
+}
+
+ConvexHullInternal::Edge *ConvexHullInternal::new_edge_pair(Vertex *p_from, Vertex *p_to) {
+ CHULL_ASSERT(p_from && p_to);
+ Edge *e = edge_pool.alloc();
+ Edge *r = edge_pool.alloc();
+ e->reverse = r;
+ r->reverse = e;
+ e->copy = merge_stamp;
+ r->copy = merge_stamp;
+ e->target = p_to;
+ r->target = p_from;
+ e->face = nullptr;
+ r->face = nullptr;
+ used_edge_pairs++;
+ if (used_edge_pairs > max_used_edge_pairs) {
+ max_used_edge_pairs = used_edge_pairs;
+ }
+ return e;
+}
+
+bool ConvexHullInternal::merge_projection(IntermediateHull &r_h0, IntermediateHull &r_h1, Vertex *&r_c0, Vertex *&r_c1) {
+ Vertex *v0 = r_h0.max_yx;
+ Vertex *v1 = r_h1.min_yx;
+ if ((v0->point.x == v1->point.x) && (v0->point.y == v1->point.y)) {
+ CHULL_ASSERT(v0->point.z < v1->point.z);
+ Vertex *v1p = v1->prev;
+ if (v1p == v1) {
+ r_c0 = v0;
+ if (v1->edges) {
+ CHULL_ASSERT(v1->edges->next == v1->edges);
+ v1 = v1->edges->target;
+ CHULL_ASSERT(v1->edges->next == v1->edges);
+ }
+ r_c1 = v1;
+ return false;
+ }
+ Vertex *v1n = v1->next;
+ v1p->next = v1n;
+ v1n->prev = v1p;
+ if (v1 == r_h1.min_xy) {
+ if ((v1n->point.x < v1p->point.x) || ((v1n->point.x == v1p->point.x) && (v1n->point.y < v1p->point.y))) {
+ r_h1.min_xy = v1n;
+ } else {
+ r_h1.min_xy = v1p;
+ }
+ }
+ if (v1 == r_h1.max_xy) {
+ if ((v1n->point.x > v1p->point.x) || ((v1n->point.x == v1p->point.x) && (v1n->point.y > v1p->point.y))) {
+ r_h1.max_xy = v1n;
+ } else {
+ r_h1.max_xy = v1p;
+ }
+ }
+ }
+
+ v0 = r_h0.max_xy;
+ v1 = r_h1.max_xy;
+ Vertex *v00 = nullptr;
+ Vertex *v10 = nullptr;
+ int32_t sign = 1;
+
+ for (int32_t side = 0; side <= 1; side++) {
+ int32_t dx = (v1->point.x - v0->point.x) * sign;
+ if (dx > 0) {
+ while (true) {
+ int32_t dy = v1->point.y - v0->point.y;
+
+ Vertex *w0 = side ? v0->next : v0->prev;
+ if (w0 != v0) {
+ int32_t dx0 = (w0->point.x - v0->point.x) * sign;
+ int32_t dy0 = w0->point.y - v0->point.y;
+ if ((dy0 <= 0) && ((dx0 == 0) || ((dx0 < 0) && (dy0 * dx <= dy * dx0)))) {
+ v0 = w0;
+ dx = (v1->point.x - v0->point.x) * sign;
+ continue;
+ }
+ }
+
+ Vertex *w1 = side ? v1->next : v1->prev;
+ if (w1 != v1) {
+ int32_t dx1 = (w1->point.x - v1->point.x) * sign;
+ int32_t dy1 = w1->point.y - v1->point.y;
+ int32_t dxn = (w1->point.x - v0->point.x) * sign;
+ if ((dxn > 0) && (dy1 < 0) && ((dx1 == 0) || ((dx1 < 0) && (dy1 * dx < dy * dx1)))) {
+ v1 = w1;
+ dx = dxn;
+ continue;
+ }
+ }
+
+ break;
+ }
+ } else if (dx < 0) {
+ while (true) {
+ int32_t dy = v1->point.y - v0->point.y;
+
+ Vertex *w1 = side ? v1->prev : v1->next;
+ if (w1 != v1) {
+ int32_t dx1 = (w1->point.x - v1->point.x) * sign;
+ int32_t dy1 = w1->point.y - v1->point.y;
+ if ((dy1 >= 0) && ((dx1 == 0) || ((dx1 < 0) && (dy1 * dx <= dy * dx1)))) {
+ v1 = w1;
+ dx = (v1->point.x - v0->point.x) * sign;
+ continue;
+ }
+ }
+
+ Vertex *w0 = side ? v0->prev : v0->next;
+ if (w0 != v0) {
+ int32_t dx0 = (w0->point.x - v0->point.x) * sign;
+ int32_t dy0 = w0->point.y - v0->point.y;
+ int32_t dxn = (v1->point.x - w0->point.x) * sign;
+ if ((dxn < 0) && (dy0 > 0) && ((dx0 == 0) || ((dx0 < 0) && (dy0 * dx < dy * dx0)))) {
+ v0 = w0;
+ dx = dxn;
+ continue;
+ }
+ }
+
+ break;
+ }
+ } else {
+ int32_t x = v0->point.x;
+ int32_t y0 = v0->point.y;
+ Vertex *w0 = v0;
+ Vertex *t;
+ while (((t = side ? w0->next : w0->prev) != v0) && (t->point.x == x) && (t->point.y <= y0)) {
+ w0 = t;
+ y0 = t->point.y;
+ }
+ v0 = w0;
+
+ int32_t y1 = v1->point.y;
+ Vertex *w1 = v1;
+ while (((t = side ? w1->prev : w1->next) != v1) && (t->point.x == x) && (t->point.y >= y1)) {
+ w1 = t;
+ y1 = t->point.y;
+ }
+ v1 = w1;
+ }
+
+ if (side == 0) {
+ v00 = v0;
+ v10 = v1;
+
+ v0 = r_h0.min_xy;
+ v1 = r_h1.min_xy;
+ sign = -1;
+ }
+ }
+
+ v0->prev = v1;
+ v1->next = v0;
+
+ v00->next = v10;
+ v10->prev = v00;
+
+ if (r_h1.min_xy->point.x < r_h0.min_xy->point.x) {
+ r_h0.min_xy = r_h1.min_xy;
+ }
+ if (r_h1.max_xy->point.x >= r_h0.max_xy->point.x) {
+ r_h0.max_xy = r_h1.max_xy;
+ }
+
+ r_h0.max_yx = r_h1.max_yx;
+
+ r_c0 = v00;
+ r_c1 = v10;
+
+ return true;
+}
+
+void ConvexHullInternal::compute_internal(int32_t p_start, int32_t p_end, IntermediateHull &r_result) {
+ int32_t n = p_end - p_start;
+ switch (n) {
+ case 0:
+ r_result.min_xy = nullptr;
+ r_result.max_xy = nullptr;
+ r_result.min_yx = nullptr;
+ r_result.max_yx = nullptr;
+ return;
+ case 2: {
+ Vertex *v = original_vertices[p_start];
+ Vertex *w = original_vertices[p_start + 1];
+ if (v->point != w->point) {
+ int32_t dx = v->point.x - w->point.x;
+ int32_t dy = v->point.y - w->point.y;
+
+ if ((dx == 0) && (dy == 0)) {
+ if (v->point.z > w->point.z) {
+ Vertex *t = w;
+ w = v;
+ v = t;
+ }
+ CHULL_ASSERT(v->point.z < w->point.z);
+ v->next = v;
+ v->prev = v;
+ r_result.min_xy = v;
+ r_result.max_xy = v;
+ r_result.min_yx = v;
+ r_result.max_yx = v;
+ } else {
+ v->next = w;
+ v->prev = w;
+ w->next = v;
+ w->prev = v;
+
+ if ((dx < 0) || ((dx == 0) && (dy < 0))) {
+ r_result.min_xy = v;
+ r_result.max_xy = w;
+ } else {
+ r_result.min_xy = w;
+ r_result.max_xy = v;
+ }
+
+ if ((dy < 0) || ((dy == 0) && (dx < 0))) {
+ r_result.min_yx = v;
+ r_result.max_yx = w;
+ } else {
+ r_result.min_yx = w;
+ r_result.max_yx = v;
+ }
+ }
+
+ Edge *e = new_edge_pair(v, w);
+ e->link(e);
+ v->edges = e;
+
+ e = e->reverse;
+ e->link(e);
+ w->edges = e;
+
+ return;
+ }
+ [[fallthrough]];
+ }
+ case 1: {
+ Vertex *v = original_vertices[p_start];
+ v->edges = nullptr;
+ v->next = v;
+ v->prev = v;
+
+ r_result.min_xy = v;
+ r_result.max_xy = v;
+ r_result.min_yx = v;
+ r_result.max_yx = v;
+
+ return;
+ }
+ }
+
+ int32_t split0 = p_start + n / 2;
+ Point32 p = original_vertices[split0 - 1]->point;
+ int32_t split1 = split0;
+ while ((split1 < p_end) && (original_vertices[split1]->point == p)) {
+ split1++;
+ }
+ compute_internal(p_start, split0, r_result);
+ IntermediateHull hull1;
+ compute_internal(split1, p_end, hull1);
+#ifdef DEBUG_CONVEX_HULL
+ printf("\n\nMerge\n");
+ r_result.print();
+ hull1.print();
+#endif
+ merge(r_result, hull1);
+#ifdef DEBUG_CONVEX_HULL
+ printf("\n Result\n");
+ r_result.print();
+#endif
+}
+
+#ifdef DEBUG_CONVEX_HULL
+void ConvexHullInternal::IntermediateHull::print() {
+ printf(" Hull\n");
+ for (Vertex *v = min_xy; v;) {
+ printf(" ");
+ v->print();
+ if (v == max_xy) {
+ printf(" max_xy");
+ }
+ if (v == min_yx) {
+ printf(" min_yx");
+ }
+ if (v == max_yx) {
+ printf(" max_yx");
+ }
+ if (v->next->prev != v) {
+ printf(" Inconsistency");
+ }
+ printf("\n");
+ v = v->next;
+ if (v == min_xy) {
+ break;
+ }
+ }
+ if (min_xy) {
+ min_xy->copy = (min_xy->copy == -1) ? -2 : -1;
+ min_xy->print_graph();
+ }
+}
+
+void ConvexHullInternal::Vertex::print_graph() {
+ print();
+ printf("\nEdges\n");
+ Edge *e = edges;
+ if (e) {
+ do {
+ e->print();
+ printf("\n");
+ e = e->next;
+ } while (e != edges);
+ do {
+ Vertex *v = e->target;
+ if (v->copy != copy) {
+ v->copy = copy;
+ v->print_graph();
+ }
+ e = e->next;
+ } while (e != edges);
+ }
+}
+#endif
+
+ConvexHullInternal::Orientation ConvexHullInternal::get_orientation(const Edge *p_prev, const Edge *p_next, const Point32 &p_s, const Point32 &p_t) {
+ CHULL_ASSERT(p_prev->reverse->target == p_next->reverse->target);
+ if (p_prev->next == p_next) {
+ if (p_prev->prev == p_next) {
+ Point64 n = p_t.cross(p_s);
+ Point64 m = (*p_prev->target - *p_next->reverse->target).cross(*p_next->target - *p_next->reverse->target);
+ CHULL_ASSERT(!m.is_zero());
+ int64_t dot = n.dot(m);
+ CHULL_ASSERT(dot != 0);
+ return (dot > 0) ? COUNTER_CLOCKWISE : CLOCKWISE;
+ }
+ return COUNTER_CLOCKWISE;
+ } else if (p_prev->prev == p_next) {
+ return CLOCKWISE;
+ } else {
+ return NONE;
+ }
+}
+
+ConvexHullInternal::Edge *ConvexHullInternal::find_max_angle(bool p_ccw, const Vertex *p_start, const Point32 &p_s, const Point64 &p_rxs, const Point64 &p_sxrxs, Rational64 &p_min_cot) {
+ Edge *min_edge = nullptr;
+
+#ifdef DEBUG_CONVEX_HULL
+ printf("find max edge for %d\n", p_start->point.index);
+#endif
+ Edge *e = p_start->edges;
+ if (e) {
+ do {
+ if (e->copy > merge_stamp) {
+ Point32 t = *e->target - *p_start;
+ Rational64 cot(t.dot(p_sxrxs), t.dot(p_rxs));
+#ifdef DEBUG_CONVEX_HULL
+ printf(" Angle is %f (%d) for ", Math::atan(cot.to_scalar()), (int32_t)cot.is_nan());
+ e->print();
+#endif
+ if (cot.is_nan()) {
+ CHULL_ASSERT(p_ccw ? (t.dot(p_s) < 0) : (t.dot(p_s) > 0));
+ } else {
+ int32_t cmp;
+ if (min_edge == nullptr) {
+ p_min_cot = cot;
+ min_edge = e;
+ } else if ((cmp = cot.compare(p_min_cot)) < 0) {
+ p_min_cot = cot;
+ min_edge = e;
+ } else if ((cmp == 0) && (p_ccw == (get_orientation(min_edge, e, p_s, t) == COUNTER_CLOCKWISE))) {
+ min_edge = e;
+ }
+ }
+#ifdef DEBUG_CONVEX_HULL
+ printf("\n");
+#endif
+ }
+ e = e->next;
+ } while (e != p_start->edges);
+ }
+ return min_edge;
+}
+
+void ConvexHullInternal::find_edge_for_coplanar_faces(Vertex *p_c0, Vertex *p_c1, Edge *&p_e0, Edge *&p_e1, Vertex *p_stop0, Vertex *p_stop1) {
+ Edge *start0 = p_e0;
+ Edge *start1 = p_e1;
+ Point32 et0 = start0 ? start0->target->point : p_c0->point;
+ Point32 et1 = start1 ? start1->target->point : p_c1->point;
+ Point32 s = p_c1->point - p_c0->point;
+ Point64 normal = ((start0 ? start0 : start1)->target->point - p_c0->point).cross(s);
+ int64_t dist = p_c0->point.dot(normal);
+ CHULL_ASSERT(!start1 || (start1->target->point.dot(normal) == dist));
+ Point64 perp = s.cross(normal);
+ CHULL_ASSERT(!perp.is_zero());
+
+#ifdef DEBUG_CONVEX_HULL
+ printf(" Advancing %d %d (%p %p, %d %d)\n", p_c0->point.index, p_c1->point.index, start0, start1, start0 ? start0->target->point.index : -1, start1 ? start1->target->point.index : -1);
+#endif
+
+ int64_t max_dot0 = et0.dot(perp);
+ if (p_e0) {
+ while (p_e0->target != p_stop0) {
+ Edge *e = p_e0->reverse->prev;
+ if (e->target->point.dot(normal) < dist) {
+ break;
+ }
+ CHULL_ASSERT(e->target->point.dot(normal) == dist);
+ if (e->copy == merge_stamp) {
+ break;
+ }
+ int64_t dot = e->target->point.dot(perp);
+ if (dot <= max_dot0) {
+ break;
+ }
+ max_dot0 = dot;
+ p_e0 = e;
+ et0 = e->target->point;
+ }
+ }
+
+ int64_t max_dot1 = et1.dot(perp);
+ if (p_e1) {
+ while (p_e1->target != p_stop1) {
+ Edge *e = p_e1->reverse->next;
+ if (e->target->point.dot(normal) < dist) {
+ break;
+ }
+ CHULL_ASSERT(e->target->point.dot(normal) == dist);
+ if (e->copy == merge_stamp) {
+ break;
+ }
+ int64_t dot = e->target->point.dot(perp);
+ if (dot <= max_dot1) {
+ break;
+ }
+ max_dot1 = dot;
+ p_e1 = e;
+ et1 = e->target->point;
+ }
+ }
+
+#ifdef DEBUG_CONVEX_HULL
+ printf(" Starting at %d %d\n", et0.index, et1.index);
+#endif
+
+ int64_t dx = max_dot1 - max_dot0;
+ if (dx > 0) {
+ while (true) {
+ int64_t dy = (et1 - et0).dot(s);
+
+ if (p_e0 && (p_e0->target != p_stop0)) {
+ Edge *f0 = p_e0->next->reverse;
+ if (f0->copy > merge_stamp) {
+ int64_t dx0 = (f0->target->point - et0).dot(perp);
+ int64_t dy0 = (f0->target->point - et0).dot(s);
+ if ((dx0 == 0) ? (dy0 < 0) : ((dx0 < 0) && (Rational64(dy0, dx0).compare(Rational64(dy, dx)) >= 0))) {
+ et0 = f0->target->point;
+ dx = (et1 - et0).dot(perp);
+ p_e0 = (p_e0 == start0) ? nullptr : f0;
+ continue;
+ }
+ }
+ }
+
+ if (p_e1 && (p_e1->target != p_stop1)) {
+ Edge *f1 = p_e1->reverse->next;
+ if (f1->copy > merge_stamp) {
+ Point32 d1 = f1->target->point - et1;
+ if (d1.dot(normal) == 0) {
+ int64_t dx1 = d1.dot(perp);
+ int64_t dy1 = d1.dot(s);
+ int64_t dxn = (f1->target->point - et0).dot(perp);
+ if ((dxn > 0) && ((dx1 == 0) ? (dy1 < 0) : ((dx1 < 0) && (Rational64(dy1, dx1).compare(Rational64(dy, dx)) > 0)))) {
+ p_e1 = f1;
+ et1 = p_e1->target->point;
+ dx = dxn;
+ continue;
+ }
+ } else {
+ CHULL_ASSERT((p_e1 == start1) && (d1.dot(normal) < 0));
+ }
+ }
+ }
+
+ break;
+ }
+ } else if (dx < 0) {
+ while (true) {
+ int64_t dy = (et1 - et0).dot(s);
+
+ if (p_e1 && (p_e1->target != p_stop1)) {
+ Edge *f1 = p_e1->prev->reverse;
+ if (f1->copy > merge_stamp) {
+ int64_t dx1 = (f1->target->point - et1).dot(perp);
+ int64_t dy1 = (f1->target->point - et1).dot(s);
+ if ((dx1 == 0) ? (dy1 > 0) : ((dx1 < 0) && (Rational64(dy1, dx1).compare(Rational64(dy, dx)) <= 0))) {
+ et1 = f1->target->point;
+ dx = (et1 - et0).dot(perp);
+ p_e1 = (p_e1 == start1) ? nullptr : f1;
+ continue;
+ }
+ }
+ }
+
+ if (p_e0 && (p_e0->target != p_stop0)) {
+ Edge *f0 = p_e0->reverse->prev;
+ if (f0->copy > merge_stamp) {
+ Point32 d0 = f0->target->point - et0;
+ if (d0.dot(normal) == 0) {
+ int64_t dx0 = d0.dot(perp);
+ int64_t dy0 = d0.dot(s);
+ int64_t dxn = (et1 - f0->target->point).dot(perp);
+ if ((dxn < 0) && ((dx0 == 0) ? (dy0 > 0) : ((dx0 < 0) && (Rational64(dy0, dx0).compare(Rational64(dy, dx)) < 0)))) {
+ p_e0 = f0;
+ et0 = p_e0->target->point;
+ dx = dxn;
+ continue;
+ }
+ } else {
+ CHULL_ASSERT((p_e0 == start0) && (d0.dot(normal) < 0));
+ }
+ }
+ }
+
+ break;
+ }
+ }
+#ifdef DEBUG_CONVEX_HULL
+ printf(" Advanced edges to %d %d\n", et0.index, et1.index);
+#endif
+}
+
+void ConvexHullInternal::merge(IntermediateHull &p_h0, IntermediateHull &p_h1) {
+ if (!p_h1.max_xy) {
+ return;
+ }
+ if (!p_h0.max_xy) {
+ p_h0 = p_h1;
+ return;
+ }
+
+ merge_stamp--;
+
+ Vertex *c0 = nullptr;
+ Edge *to_prev0 = nullptr;
+ Edge *first_new0 = nullptr;
+ Edge *pending_head0 = nullptr;
+ Edge *pending_tail0 = nullptr;
+ Vertex *c1 = nullptr;
+ Edge *to_prev1 = nullptr;
+ Edge *first_new1 = nullptr;
+ Edge *pending_head1 = nullptr;
+ Edge *pending_tail1 = nullptr;
+ Point32 prev_point;
+
+ if (merge_projection(p_h0, p_h1, c0, c1)) {
+ Point32 s = *c1 - *c0;
+ Point64 normal = Point32(0, 0, -1).cross(s);
+ Point64 t = s.cross(normal);
+ CHULL_ASSERT(!t.is_zero());
+
+ Edge *e = c0->edges;
+ Edge *start0 = nullptr;
+ if (e) {
+ do {
+ int64_t dot = (*e->target - *c0).dot(normal);
+ CHULL_ASSERT(dot <= 0);
+ if ((dot == 0) && ((*e->target - *c0).dot(t) > 0)) {
+ if (!start0 || (get_orientation(start0, e, s, Point32(0, 0, -1)) == CLOCKWISE)) {
+ start0 = e;
+ }
+ }
+ e = e->next;
+ } while (e != c0->edges);
+ }
+
+ e = c1->edges;
+ Edge *start1 = nullptr;
+ if (e) {
+ do {
+ int64_t dot = (*e->target - *c1).dot(normal);
+ CHULL_ASSERT(dot <= 0);
+ if ((dot == 0) && ((*e->target - *c1).dot(t) > 0)) {
+ if (!start1 || (get_orientation(start1, e, s, Point32(0, 0, -1)) == COUNTER_CLOCKWISE)) {
+ start1 = e;
+ }
+ }
+ e = e->next;
+ } while (e != c1->edges);
+ }
+
+ if (start0 || start1) {
+ find_edge_for_coplanar_faces(c0, c1, start0, start1, nullptr, nullptr);
+ if (start0) {
+ c0 = start0->target;
+ }
+ if (start1) {
+ c1 = start1->target;
+ }
+ }
+
+ prev_point = c1->point;
+ prev_point.z++;
+ } else {
+ prev_point = c1->point;
+ prev_point.x++;
+ }
+
+ Vertex *first0 = c0;
+ Vertex *first1 = c1;
+ bool first_run = true;
+
+ while (true) {
+ Point32 s = *c1 - *c0;
+ Point32 r = prev_point - c0->point;
+ Point64 rxs = r.cross(s);
+ Point64 sxrxs = s.cross(rxs);
+
+#ifdef DEBUG_CONVEX_HULL
+ printf("\n Checking %d %d\n", c0->point.index, c1->point.index);
+#endif
+ Rational64 min_cot0(0, 0);
+ Edge *min0 = find_max_angle(false, c0, s, rxs, sxrxs, min_cot0);
+ Rational64 min_cot1(0, 0);
+ Edge *min1 = find_max_angle(true, c1, s, rxs, sxrxs, min_cot1);
+ if (!min0 && !min1) {
+ Edge *e = new_edge_pair(c0, c1);
+ e->link(e);
+ c0->edges = e;
+
+ e = e->reverse;
+ e->link(e);
+ c1->edges = e;
+ return;
+ } else {
+ int32_t cmp = !min0 ? 1 : !min1 ? -1 :
+ min_cot0.compare(min_cot1);
+#ifdef DEBUG_CONVEX_HULL
+ printf(" -> Result %d\n", cmp);
+#endif
+ if (first_run || ((cmp >= 0) ? !min_cot1.is_negative_infinity() : !min_cot0.is_negative_infinity())) {
+ Edge *e = new_edge_pair(c0, c1);
+ if (pending_tail0) {
+ pending_tail0->prev = e;
+ } else {
+ pending_head0 = e;
+ }
+ e->next = pending_tail0;
+ pending_tail0 = e;
+
+ e = e->reverse;
+ if (pending_tail1) {
+ pending_tail1->next = e;
+ } else {
+ pending_head1 = e;
+ }
+ e->prev = pending_tail1;
+ pending_tail1 = e;
+ }
+
+ Edge *e0 = min0;
+ Edge *e1 = min1;
+
+#ifdef DEBUG_CONVEX_HULL
+ printf(" Found min edges to %d %d\n", e0 ? e0->target->point.index : -1, e1 ? e1->target->point.index : -1);
+#endif
+
+ if (cmp == 0) {
+ find_edge_for_coplanar_faces(c0, c1, e0, e1, nullptr, nullptr);
+ }
+
+ if ((cmp >= 0) && e1) {
+ if (to_prev1) {
+ for (Edge *e = to_prev1->next, *n = nullptr; e != min1; e = n) {
+ n = e->next;
+ remove_edge_pair(e);
+ }
+ }
+
+ if (pending_tail1) {
+ if (to_prev1) {
+ to_prev1->link(pending_head1);
+ } else {
+ min1->prev->link(pending_head1);
+ first_new1 = pending_head1;
+ }
+ pending_tail1->link(min1);
+ pending_head1 = nullptr;
+ pending_tail1 = nullptr;
+ } else if (!to_prev1) {
+ first_new1 = min1;
+ }
+
+ prev_point = c1->point;
+ c1 = e1->target;
+ to_prev1 = e1->reverse;
+ }
+
+ if ((cmp <= 0) && e0) {
+ if (to_prev0) {
+ for (Edge *e = to_prev0->prev, *n = nullptr; e != min0; e = n) {
+ n = e->prev;
+ remove_edge_pair(e);
+ }
+ }
+
+ if (pending_tail0) {
+ if (to_prev0) {
+ pending_head0->link(to_prev0);
+ } else {
+ pending_head0->link(min0->next);
+ first_new0 = pending_head0;
+ }
+ min0->link(pending_tail0);
+ pending_head0 = nullptr;
+ pending_tail0 = nullptr;
+ } else if (!to_prev0) {
+ first_new0 = min0;
+ }
+
+ prev_point = c0->point;
+ c0 = e0->target;
+ to_prev0 = e0->reverse;
+ }
+ }
+
+ if ((c0 == first0) && (c1 == first1)) {
+ if (to_prev0 == nullptr) {
+ pending_head0->link(pending_tail0);
+ c0->edges = pending_tail0;
+ } else {
+ for (Edge *e = to_prev0->prev, *n = nullptr; e != first_new0; e = n) {
+ n = e->prev;
+ remove_edge_pair(e);
+ }
+ if (pending_tail0) {
+ pending_head0->link(to_prev0);
+ first_new0->link(pending_tail0);
+ }
+ }
+
+ if (to_prev1 == nullptr) {
+ pending_tail1->link(pending_head1);
+ c1->edges = pending_tail1;
+ } else {
+ for (Edge *e = to_prev1->next, *n = nullptr; e != first_new1; e = n) {
+ n = e->next;
+ remove_edge_pair(e);
+ }
+ if (pending_tail1) {
+ to_prev1->link(pending_head1);
+ pending_tail1->link(first_new1);
+ }
+ }
+
+ return;
+ }
+
+ first_run = false;
+ }
+}
+
+struct PointComparator {
+ _FORCE_INLINE_ bool operator()(const ConvexHullInternal::Point32 &p, const ConvexHullInternal::Point32 &q) const {
+ return (p.y < q.y) || ((p.y == q.y) && ((p.x < q.x) || ((p.x == q.x) && (p.z < q.z))));
+ }
+};
+
+void ConvexHullInternal::compute(const Vector3 *p_coords, int32_t p_count) {
+ AABB aabb;
+ for (int32_t i = 0; i < p_count; i++) {
+ Vector3 p = p_coords[i];
+ if (i == 0) {
+ aabb.position = p;
+ } else {
+ aabb.expand_to(p);
+ }
+ }
+
+ Vector3 s = aabb.size;
+ max_axis = s.max_axis();
+ min_axis = s.min_axis();
+ if (min_axis == max_axis) {
+ min_axis = (max_axis + 1) % 3;
+ }
+ med_axis = 3 - max_axis - min_axis;
+
+ s /= real_t(10216);
+ if (((med_axis + 1) % 3) != max_axis) {
+ s *= -1;
+ }
+ scaling = s;
+
+ if (s[0] != 0) {
+ s[0] = real_t(1) / s[0];
+ }
+ if (s[1] != 0) {
+ s[1] = real_t(1) / s[1];
+ }
+ if (s[2] != 0) {
+ s[2] = real_t(1) / s[2];
+ }
+
+ center = aabb.position;
+
+ LocalVector<Point32> points;
+ points.resize(p_count);
+ for (int32_t i = 0; i < p_count; i++) {
+ Vector3 p = p_coords[i];
+ p = (p - center) * s;
+ points[i].x = (int32_t)p[med_axis];
+ points[i].y = (int32_t)p[max_axis];
+ points[i].z = (int32_t)p[min_axis];
+ points[i].index = i;
+ }
+
+ points.sort_custom<PointComparator>();
+
+ vertex_pool.reset(true);
+ original_vertices.resize(p_count);
+ for (int32_t i = 0; i < p_count; i++) {
+ Vertex *v = vertex_pool.alloc();
+ v->edges = nullptr;
+ v->point = points[i];
+ v->copy = -1;
+ original_vertices[i] = v;
+ }
+
+ points.clear();
+
+ edge_pool.reset(true);
+
+ used_edge_pairs = 0;
+ max_used_edge_pairs = 0;
+
+ merge_stamp = -3;
+
+ IntermediateHull hull;
+ compute_internal(0, p_count, hull);
+ vertex_list = hull.min_xy;
+#ifdef DEBUG_CONVEX_HULL
+ printf("max. edges %d (3v = %d)", max_used_edge_pairs, 3 * p_count);
+#endif
+}
+
+Vector3 ConvexHullInternal::to_gd_vector(const Point32 &p_v) {
+ Vector3 p;
+ p[med_axis] = real_t(p_v.x);
+ p[max_axis] = real_t(p_v.y);
+ p[min_axis] = real_t(p_v.z);
+ return p * scaling;
+}
+
+Vector3 ConvexHullInternal::get_gd_normal(Face *p_face) {
+ return to_gd_vector(p_face->dir0).cross(to_gd_vector(p_face->dir1)).normalized();
+}
+
+Vector3 ConvexHullInternal::get_coordinates(const Vertex *p_v) {
+ Vector3 p;
+ p[med_axis] = p_v->xvalue();
+ p[max_axis] = p_v->yvalue();
+ p[min_axis] = p_v->zvalue();
+ return p * scaling + center;
+}
+
+real_t ConvexHullInternal::shrink(real_t p_amount, real_t p_clamp_amount) {
+ if (!vertex_list) {
+ return 0;
+ }
+ int32_t stamp = --merge_stamp;
+ LocalVector<Vertex *> stack;
+ vertex_list->copy = stamp;
+ stack.push_back(vertex_list);
+ LocalVector<Face *> faces;
+
+ Point32 ref = vertex_list->point;
+ Int128 hull_center_x(0, 0);
+ Int128 hull_center_y(0, 0);
+ Int128 hull_center_z(0, 0);
+ Int128 volume(0, 0);
+
+ while (stack.size() > 0) {
+ Vertex *v = stack[stack.size() - 1];
+ stack.remove(stack.size() - 1);
+ Edge *e = v->edges;
+ if (e) {
+ do {
+ if (e->target->copy != stamp) {
+ e->target->copy = stamp;
+ stack.push_back(e->target);
+ }
+ if (e->copy != stamp) {
+ Face *face = face_pool.alloc();
+ face->init(e->target, e->reverse->prev->target, v);
+ faces.push_back(face);
+ Edge *f = e;
+
+ Vertex *a = nullptr;
+ Vertex *b = nullptr;
+ do {
+ if (a && b) {
+ int64_t vol = (v->point - ref).dot((a->point - ref).cross(b->point - ref));
+ CHULL_ASSERT(vol >= 0);
+ Point32 c = v->point + a->point + b->point + ref;
+ hull_center_x += vol * c.x;
+ hull_center_y += vol * c.y;
+ hull_center_z += vol * c.z;
+ volume += vol;
+ }
+
+ CHULL_ASSERT(f->copy != stamp);
+ f->copy = stamp;
+ f->face = face;
+
+ a = b;
+ b = f->target;
+
+ f = f->reverse->prev;
+ } while (f != e);
+ }
+ e = e->next;
+ } while (e != v->edges);
+ }
+ }
+
+ if (volume.get_sign() <= 0) {
+ return 0;
+ }
+
+ Vector3 hull_center;
+ hull_center[med_axis] = hull_center_x.to_scalar();
+ hull_center[max_axis] = hull_center_y.to_scalar();
+ hull_center[min_axis] = hull_center_z.to_scalar();
+ hull_center /= 4 * volume.to_scalar();
+ hull_center *= scaling;
+
+ int32_t face_count = faces.size();
+
+ if (p_clamp_amount > 0) {
+ real_t min_dist = FLT_MAX;
+ for (int32_t i = 0; i < face_count; i++) {
+ Vector3 normal = get_gd_normal(faces[i]);
+ real_t dist = normal.dot(to_gd_vector(faces[i]->origin) - hull_center);
+ if (dist < min_dist) {
+ min_dist = dist;
+ }
+ }
+
+ if (min_dist <= 0) {
+ return 0;
+ }
+
+ p_amount = MIN(p_amount, min_dist * p_clamp_amount);
+ }
+
+ uint32_t seed = 243703;
+ for (int32_t i = 0; i < face_count; i++, seed = 1664525 * seed + 1013904223) {
+ SWAP(faces[i], faces[seed % face_count]);
+ }
+
+ for (int32_t i = 0; i < face_count; i++) {
+ if (!shift_face(faces[i], p_amount, stack)) {
+ return -p_amount;
+ }
+ }
+
+ return p_amount;
+}
+
+bool ConvexHullInternal::shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> p_stack) {
+ Vector3 orig_shift = get_gd_normal(p_face) * -p_amount;
+ if (scaling[0] != 0) {
+ orig_shift[0] /= scaling[0];
+ }
+ if (scaling[1] != 0) {
+ orig_shift[1] /= scaling[1];
+ }
+ if (scaling[2] != 0) {
+ orig_shift[2] /= scaling[2];
+ }
+ Point32 shift((int32_t)orig_shift[med_axis], (int32_t)orig_shift[max_axis], (int32_t)orig_shift[min_axis]);
+ if (shift.is_zero()) {
+ return true;
+ }
+ Point64 normal = p_face->get_normal();
+#ifdef DEBUG_CONVEX_HULL
+ printf("\nShrinking p_face (%d %d %d) (%d %d %d) (%d %d %d) by (%d %d %d)\n",
+ p_face->origin.x, p_face->origin.y, p_face->origin.z, p_face->dir0.x, p_face->dir0.y, p_face->dir0.z, p_face->dir1.x, p_face->dir1.y, p_face->dir1.z, shift.x, shift.y, shift.z);
+#endif
+ int64_t orig_dot = p_face->origin.dot(normal);
+ Point32 shifted_origin = p_face->origin + shift;
+ int64_t shifted_dot = shifted_origin.dot(normal);
+ CHULL_ASSERT(shifted_dot <= orig_dot);
+ if (shifted_dot >= orig_dot) {
+ return false;
+ }
+
+ Edge *intersection = nullptr;
+
+ Edge *start_edge = p_face->nearby_vertex->edges;
+#ifdef DEBUG_CONVEX_HULL
+ printf("Start edge is ");
+ start_edge->print();
+ printf(", normal is (%lld %lld %lld), shifted dot is %lld\n", normal.x, normal.y, normal.z, shifted_dot);
+#endif
+ Rational128 opt_dot = p_face->nearby_vertex->dot(normal);
+ int32_t cmp = opt_dot.compare(shifted_dot);
+#ifdef SHOW_ITERATIONS
+ int32_t n = 0;
+#endif
+ if (cmp >= 0) {
+ Edge *e = start_edge;
+ do {
+#ifdef SHOW_ITERATIONS
+ n++;
+#endif
+ Rational128 dot = e->target->dot(normal);
+ CHULL_ASSERT(dot.compare(orig_dot) <= 0);
+#ifdef DEBUG_CONVEX_HULL
+ printf("Moving downwards, edge is ");
+ e->print();
+ printf(", dot is %f (%f %lld)\n", (float)dot.to_scalar(), (float)opt_dot.to_scalar(), shifted_dot);
+#endif
+ if (dot.compare(opt_dot) < 0) {
+ int32_t c = dot.compare(shifted_dot);
+ opt_dot = dot;
+ e = e->reverse;
+ start_edge = e;
+ if (c < 0) {
+ intersection = e;
+ break;
+ }
+ cmp = c;
+ }
+ e = e->prev;
+ } while (e != start_edge);
+
+ if (!intersection) {
+ return false;
+ }
+ } else {
+ Edge *e = start_edge;
+ do {
+#ifdef SHOW_ITERATIONS
+ n++;
+#endif
+ Rational128 dot = e->target->dot(normal);
+ CHULL_ASSERT(dot.compare(orig_dot) <= 0);
+#ifdef DEBUG_CONVEX_HULL
+ printf("Moving upwards, edge is ");
+ e->print();
+ printf(", dot is %f (%f %lld)\n", (float)dot.to_scalar(), (float)opt_dot.to_scalar(), shifted_dot);
+#endif
+ if (dot.compare(opt_dot) > 0) {
+ cmp = dot.compare(shifted_dot);
+ if (cmp >= 0) {
+ intersection = e;
+ break;
+ }
+ opt_dot = dot;
+ e = e->reverse;
+ start_edge = e;
+ }
+ e = e->prev;
+ } while (e != start_edge);
+
+ if (!intersection) {
+ return true;
+ }
+ }
+
+#ifdef SHOW_ITERATIONS
+ printf("Needed %d iterations to find initial intersection\n", n);
+#endif
+
+ if (cmp == 0) {
+ Edge *e = intersection->reverse->next;
+#ifdef SHOW_ITERATIONS
+ n = 0;
+#endif
+ while (e->target->dot(normal).compare(shifted_dot) <= 0) {
+#ifdef SHOW_ITERATIONS
+ n++;
+#endif
+ e = e->next;
+ if (e == intersection->reverse) {
+ return true;
+ }
+#ifdef DEBUG_CONVEX_HULL
+ printf("Checking for outwards edge, current edge is ");
+ e->print();
+ printf("\n");
+#endif
+ }
+#ifdef SHOW_ITERATIONS
+ printf("Needed %d iterations to check for complete containment\n", n);
+#endif
+ }
+
+ Edge *first_intersection = nullptr;
+ Edge *face_edge = nullptr;
+ Edge *first_face_edge = nullptr;
+
+#ifdef SHOW_ITERATIONS
+ int32_t m = 0;
+#endif
+ while (true) {
+#ifdef SHOW_ITERATIONS
+ m++;
+#endif
+#ifdef DEBUG_CONVEX_HULL
+ printf("Intersecting edge is ");
+ intersection->print();
+ printf("\n");
+#endif
+ if (cmp == 0) {
+ Edge *e = intersection->reverse->next;
+ start_edge = e;
+#ifdef SHOW_ITERATIONS
+ n = 0;
+#endif
+ while (true) {
+#ifdef SHOW_ITERATIONS
+ n++;
+#endif
+ if (e->target->dot(normal).compare(shifted_dot) >= 0) {
+ break;
+ }
+ intersection = e->reverse;
+ e = e->next;
+ if (e == start_edge) {
+ return true;
+ }
+ }
+#ifdef SHOW_ITERATIONS
+ printf("Needed %d iterations to advance intersection\n", n);
+#endif
+ }
+
+#ifdef DEBUG_CONVEX_HULL
+ printf("Advanced intersecting edge to ");
+ intersection->print();
+ printf(", cmp = %d\n", cmp);
+#endif
+
+ if (!first_intersection) {
+ first_intersection = intersection;
+ } else if (intersection == first_intersection) {
+ break;
+ }
+
+ int32_t prev_cmp = cmp;
+ Edge *prev_intersection = intersection;
+ Edge *prev_face_edge = face_edge;
+
+ Edge *e = intersection->reverse;
+#ifdef SHOW_ITERATIONS
+ n = 0;
+#endif
+ while (true) {
+#ifdef SHOW_ITERATIONS
+ n++;
+#endif
+ e = e->reverse->prev;
+ CHULL_ASSERT(e != intersection->reverse);
+ cmp = e->target->dot(normal).compare(shifted_dot);
+#ifdef DEBUG_CONVEX_HULL
+ printf("Testing edge ");
+ e->print();
+ printf(" -> cmp = %d\n", cmp);
+#endif
+ if (cmp >= 0) {
+ intersection = e;
+ break;
+ }
+ }
+#ifdef SHOW_ITERATIONS
+ printf("Needed %d iterations to find other intersection of p_face\n", n);
+#endif
+
+ if (cmp > 0) {
+ Vertex *removed = intersection->target;
+ e = intersection->reverse;
+ if (e->prev == e) {
+ removed->edges = nullptr;
+ } else {
+ removed->edges = e->prev;
+ e->prev->link(e->next);
+ e->link(e);
+ }
+#ifdef DEBUG_CONVEX_HULL
+ printf("1: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z);
+#endif
+
+ Point64 n0 = intersection->face->get_normal();
+ Point64 n1 = intersection->reverse->face->get_normal();
+ int64_t m00 = p_face->dir0.dot(n0);
+ int64_t m01 = p_face->dir1.dot(n0);
+ int64_t m10 = p_face->dir0.dot(n1);
+ int64_t m11 = p_face->dir1.dot(n1);
+ int64_t r0 = (intersection->face->origin - shifted_origin).dot(n0);
+ int64_t r1 = (intersection->reverse->face->origin - shifted_origin).dot(n1);
+ Int128 det = Int128::mul(m00, m11) - Int128::mul(m01, m10);
+ CHULL_ASSERT(det.get_sign() != 0);
+ Vertex *v = vertex_pool.alloc();
+ v->point.index = -1;
+ v->copy = -1;
+ v->point128 = PointR128(Int128::mul(p_face->dir0.x * r0, m11) - Int128::mul(p_face->dir0.x * r1, m01) + Int128::mul(p_face->dir1.x * r1, m00) - Int128::mul(p_face->dir1.x * r0, m10) + det * shifted_origin.x,
+ Int128::mul(p_face->dir0.y * r0, m11) - Int128::mul(p_face->dir0.y * r1, m01) + Int128::mul(p_face->dir1.y * r1, m00) - Int128::mul(p_face->dir1.y * r0, m10) + det * shifted_origin.y,
+ Int128::mul(p_face->dir0.z * r0, m11) - Int128::mul(p_face->dir0.z * r1, m01) + Int128::mul(p_face->dir1.z * r1, m00) - Int128::mul(p_face->dir1.z * r0, m10) + det * shifted_origin.z,
+ det);
+ v->point.x = (int32_t)v->point128.xvalue();
+ v->point.y = (int32_t)v->point128.yvalue();
+ v->point.z = (int32_t)v->point128.zvalue();
+ intersection->target = v;
+ v->edges = e;
+
+ p_stack.push_back(v);
+ p_stack.push_back(removed);
+ p_stack.push_back(nullptr);
+ }
+
+ if (cmp || prev_cmp || (prev_intersection->reverse->next->target != intersection->target)) {
+ face_edge = new_edge_pair(prev_intersection->target, intersection->target);
+ if (prev_cmp == 0) {
+ face_edge->link(prev_intersection->reverse->next);
+ }
+ if ((prev_cmp == 0) || prev_face_edge) {
+ prev_intersection->reverse->link(face_edge);
+ }
+ if (cmp == 0) {
+ intersection->reverse->prev->link(face_edge->reverse);
+ }
+ face_edge->reverse->link(intersection->reverse);
+ } else {
+ face_edge = prev_intersection->reverse->next;
+ }
+
+ if (prev_face_edge) {
+ if (prev_cmp > 0) {
+ face_edge->link(prev_face_edge->reverse);
+ } else if (face_edge != prev_face_edge->reverse) {
+ p_stack.push_back(prev_face_edge->target);
+ while (face_edge->next != prev_face_edge->reverse) {
+ Vertex *removed = face_edge->next->target;
+ remove_edge_pair(face_edge->next);
+ p_stack.push_back(removed);
+#ifdef DEBUG_CONVEX_HULL
+ printf("2: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z);
+#endif
+ }
+ p_stack.push_back(nullptr);
+ }
+ }
+ face_edge->face = p_face;
+ face_edge->reverse->face = intersection->face;
+
+ if (!first_face_edge) {
+ first_face_edge = face_edge;
+ }
+ }
+#ifdef SHOW_ITERATIONS
+ printf("Needed %d iterations to process all intersections\n", m);
+#endif
+
+ if (cmp > 0) {
+ first_face_edge->reverse->target = face_edge->target;
+ first_intersection->reverse->link(first_face_edge);
+ first_face_edge->link(face_edge->reverse);
+ } else if (first_face_edge != face_edge->reverse) {
+ p_stack.push_back(face_edge->target);
+ while (first_face_edge->next != face_edge->reverse) {
+ Vertex *removed = first_face_edge->next->target;
+ remove_edge_pair(first_face_edge->next);
+ p_stack.push_back(removed);
+#ifdef DEBUG_CONVEX_HULL
+ printf("3: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z);
+#endif
+ }
+ p_stack.push_back(nullptr);
+ }
+
+ CHULL_ASSERT(p_stack.size() > 0);
+ vertex_list = p_stack[0];
+
+#ifdef DEBUG_CONVEX_HULL
+ printf("Removing part\n");
+#endif
+#ifdef SHOW_ITERATIONS
+ n = 0;
+#endif
+ uint32_t pos = 0;
+ while (pos < p_stack.size()) {
+ uint32_t end = p_stack.size();
+ while (pos < end) {
+ Vertex *kept = p_stack[pos++];
+#ifdef DEBUG_CONVEX_HULL
+ kept->print();
+#endif
+ bool deeper = false;
+ Vertex *removed;
+ while ((removed = p_stack[pos++]) != nullptr) {
+#ifdef SHOW_ITERATIONS
+ n++;
+#endif
+ kept->receive_nearby_faces(removed);
+ while (removed->edges) {
+ if (!deeper) {
+ deeper = true;
+ p_stack.push_back(kept);
+ }
+ p_stack.push_back(removed->edges->target);
+ remove_edge_pair(removed->edges);
+ }
+ }
+ if (deeper) {
+ p_stack.push_back(nullptr);
+ }
+ }
+ }
+#ifdef SHOW_ITERATIONS
+ printf("Needed %d iterations to remove part\n", n);
+#endif
+
+ p_stack.resize(0);
+ p_face->origin = shifted_origin;
+
+ return true;
+}
+
+static int32_t get_vertex_copy(ConvexHullInternal::Vertex *p_vertex, LocalVector<ConvexHullInternal::Vertex *> &p_vertices) {
+ int32_t index = p_vertex->copy;
+ if (index < 0) {
+ index = p_vertices.size();
+ p_vertex->copy = index;
+ p_vertices.push_back(p_vertex);
+#ifdef DEBUG_CONVEX_HULL
+ printf("Vertex %d gets index *%d\n", p_vertex->point.index, index);
+#endif
+ }
+ return index;
+}
+
+real_t ConvexHullComputer::compute(const Vector3 *p_coords, int32_t p_count, real_t p_shrink, real_t p_shrink_clamp) {
+ if (p_count <= 0) {
+ vertices.clear();
+ edges.clear();
+ faces.clear();
+ return 0;
+ }
+
+ ConvexHullInternal hull;
+ hull.compute(p_coords, p_count);
+
+ real_t shift = 0;
+ if ((p_shrink > 0) && ((shift = hull.shrink(p_shrink, p_shrink_clamp)) < 0)) {
+ vertices.clear();
+ edges.clear();
+ faces.clear();
+ return shift;
+ }
+
+ vertices.resize(0);
+ edges.resize(0);
+ faces.resize(0);
+
+ LocalVector<ConvexHullInternal::Vertex *> old_vertices;
+ get_vertex_copy(hull.vertex_list, old_vertices);
+ int32_t copied = 0;
+ while (copied < (int32_t)old_vertices.size()) {
+ ConvexHullInternal::Vertex *v = old_vertices[copied];
+ vertices.push_back(hull.get_coordinates(v));
+ ConvexHullInternal::Edge *first_edge = v->edges;
+ if (first_edge) {
+ int32_t first_copy = -1;
+ int32_t prev_copy = -1;
+ ConvexHullInternal::Edge *e = first_edge;
+ do {
+ if (e->copy < 0) {
+ int32_t s = edges.size();
+ edges.push_back(Edge());
+ edges.push_back(Edge());
+ Edge *c = &edges[s];
+ Edge *r = &edges[s + 1];
+ e->copy = s;
+ e->reverse->copy = s + 1;
+ c->reverse = 1;
+ r->reverse = -1;
+ c->target_vertex = get_vertex_copy(e->target, old_vertices);
+ r->target_vertex = copied;
+#ifdef DEBUG_CONVEX_HULL
+ printf(" CREATE: Vertex *%d has edge to *%d\n", copied, c->get_target_vertex());
+#endif
+ }
+ if (prev_copy >= 0) {
+ edges[e->copy].next = prev_copy - e->copy;
+ } else {
+ first_copy = e->copy;
+ }
+ prev_copy = e->copy;
+ e = e->next;
+ } while (e != first_edge);
+ edges[first_copy].next = prev_copy - first_copy;
+ }
+ copied++;
+ }
+
+ for (int32_t i = 0; i < copied; i++) {
+ ConvexHullInternal::Vertex *v = old_vertices[i];
+ ConvexHullInternal::Edge *first_edge = v->edges;
+ if (first_edge) {
+ ConvexHullInternal::Edge *e = first_edge;
+ do {
+ if (e->copy >= 0) {
+#ifdef DEBUG_CONVEX_HULL
+ printf("Vertex *%d has edge to *%d\n", i, edges[e->copy].get_target_vertex());
+#endif
+ faces.push_back(e->copy);
+ ConvexHullInternal::Edge *f = e;
+ do {
+#ifdef DEBUG_CONVEX_HULL
+ printf(" Face *%d\n", edges[f->copy].get_target_vertex());
+#endif
+ f->copy = -1;
+ f = f->reverse->prev;
+ } while (f != e);
+ }
+ e = e->next;
+ } while (e != first_edge);
+ }
+ }
+
+ return shift;
+}
+
+Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_mesh) {
+ r_mesh = Geometry3D::MeshData(); // clear
+
+ if (p_points.size() == 0) {
+ return FAILED; // matches QuickHull
+ }
+
+ ConvexHullComputer ch;
+ ch.compute(p_points.ptr(), p_points.size(), -1.0, -1.0);
+
+ r_mesh.vertices = ch.vertices;
+
+ r_mesh.edges.resize(ch.edges.size());
+ for (uint32_t i = 0; i < ch.edges.size(); i++) {
+ r_mesh.edges.write[i].a = (&ch.edges[i])->get_source_vertex();
+ r_mesh.edges.write[i].b = (&ch.edges[i])->get_target_vertex();
+ }
+
+ r_mesh.faces.resize(ch.faces.size());
+ for (uint32_t i = 0; i < ch.faces.size(); i++) {
+ const Edge *e_start = &ch.edges[ch.faces[i]];
+ const Edge *e = e_start;
+ Geometry3D::MeshData::Face &face = r_mesh.faces.write[i];
+
+ do {
+ face.indices.push_back(e->get_target_vertex());
+
+ e = e->get_next_edge_of_face();
+ } while (e != e_start);
+
+ // compute normal
+ if (face.indices.size() >= 3) {
+ face.plane = Plane(r_mesh.vertices[face.indices[0]], r_mesh.vertices[face.indices[2]], r_mesh.vertices[face.indices[1]]);
+ } else {
+ WARN_PRINT("Too few vertices per face.");
+ }
+ }
+
+ return OK;
+}
diff --git a/core/math/convex_hull.h b/core/math/convex_hull.h
new file mode 100644
index 0000000000..ba7be9c5e8
--- /dev/null
+++ b/core/math/convex_hull.h
@@ -0,0 +1,112 @@
+/*************************************************************************/
+/* convex_hull.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net
+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.
+*/
+
+#ifndef CONVEX_HULL_H
+#define CONVEX_HULL_H
+
+#include "core/math/geometry_3d.h"
+#include "core/math/vector3.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/vector.h"
+
+/// Convex hull implementation based on Preparata and Hong
+/// See http://code.google.com/p/bullet/issues/detail?id=275
+/// Ole Kniemeyer, MAXON Computer GmbH
+class ConvexHullComputer {
+public:
+ class Edge {
+ private:
+ int32_t next = 0;
+ int32_t reverse = 0;
+ int32_t target_vertex = 0;
+
+ friend class ConvexHullComputer;
+
+ public:
+ int32_t get_source_vertex() const {
+ return (this + reverse)->target_vertex;
+ }
+
+ int32_t get_target_vertex() const {
+ return target_vertex;
+ }
+
+ const Edge *get_next_edge_of_vertex() const // clockwise list of all edges of a vertex
+ {
+ return this + next;
+ }
+
+ const Edge *get_next_edge_of_face() const // counter-clockwise list of all edges of a face
+ {
+ return (this + reverse)->get_next_edge_of_vertex();
+ }
+
+ const Edge *get_reverse_edge() const {
+ return this + reverse;
+ }
+ };
+
+ // Vertices of the output hull
+ Vector<Vector3> vertices;
+
+ // Edges of the output hull
+ LocalVector<Edge> edges;
+
+ // Faces of the convex hull. Each entry is an index into the "edges" array pointing to an edge of the face. Faces are planar n-gons
+ LocalVector<int32_t> faces;
+
+ /*
+ Compute convex hull of "count" vertices stored in "coords".
+ If "shrink" is positive, the convex hull is shrunken by that amount (each face is moved by "shrink" length units
+ towards the center along its normal).
+ If "shrinkClamp" is positive, "shrink" is clamped to not exceed "shrinkClamp * innerRadius", where "innerRadius"
+ is the minimum distance of a face to the center of the convex hull.
+ The returned value is the amount by which the hull has been shrunken. If it is negative, the amount was so large
+ that the resulting convex hull is empty.
+ The output convex hull can be found in the member variables "vertices", "edges", "faces".
+ */
+ real_t compute(const Vector3 *p_coords, int32_t p_count, real_t p_shrink, real_t p_shrink_clamp);
+
+ static Error convex_hull(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_mesh);
+};
+
+#endif // CONVEX_HULL_H
diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h
index 25cc1125db..6f7209556e 100644
--- a/core/math/delaunay_3d.h
+++ b/core/math/delaunay_3d.h
@@ -31,10 +31,10 @@
#ifndef DELAUNAY_3D_H
#define DELAUNAY_3D_H
+#include "core/io/file_access.h"
#include "core/math/aabb.h"
#include "core/math/camera_matrix.h"
#include "core/math/vector3.h"
-#include "core/os/file_access.h"
#include "core/string/print_string.h"
#include "core/templates/local_vector.h"
#include "core/templates/oa_hash_map.h"
diff --git a/core/math/dynamic_bvh.cpp b/core/math/dynamic_bvh.cpp
index 200095d8cb..8e596f0f9d 100644
--- a/core/math/dynamic_bvh.cpp
+++ b/core/math/dynamic_bvh.cpp
@@ -312,8 +312,11 @@ void DynamicBVH::optimize_incremental(int passes) {
if (passes < 0) {
passes = total_leaves;
}
- if (bvh_root && (passes > 0)) {
+ if (passes > 0) {
do {
+ if (!bvh_root) {
+ break;
+ }
Node *node = bvh_root;
unsigned bit = 0;
while (node->is_internal()) {
diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h
index 3fb22515a2..0b6286cd9d 100644
--- a/core/math/dynamic_bvh.h
+++ b/core/math/dynamic_bvh.h
@@ -343,7 +343,7 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {
if (depth > threshold) {
if (aux_stack.is_empty()) {
aux_stack.resize(ALLOCA_STACK_SIZE * 2);
- copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ memcpy(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
} else {
aux_stack.resize(aux_stack.size() * 2);
}
@@ -399,7 +399,7 @@ void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Ve
if (depth > threshold) {
if (aux_stack.is_empty()) {
aux_stack.resize(ALLOCA_STACK_SIZE * 2);
- copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ memcpy(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
} else {
aux_stack.resize(aux_stack.size() * 2);
}
@@ -456,7 +456,7 @@ void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResu
if (depth > threshold) {
if (aux_stack.is_empty()) {
aux_stack.resize(ALLOCA_STACK_SIZE * 2);
- copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ memcpy(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
} else {
aux_stack.resize(aux_stack.size() * 2);
}
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index f7ac44d321..0146c345f0 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -33,7 +33,7 @@
#include "core/io/marshalls.h"
#include "core/math/math_funcs.h"
#include "core/object/class_db.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/os/os.h"
#include "core/variant/variant_parser.h"
diff --git a/core/math/expression.h b/core/math/expression.h
index a6b288ed6e..aecf662d0a 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -31,10 +31,10 @@
#ifndef EXPRESSION_H
#define EXPRESSION_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class Expression : public Reference {
- GDCLASS(Expression, Reference);
+class Expression : public RefCounted {
+ GDCLASS(Expression, RefCounted);
private:
struct Input {
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index beb0a8e405..9af3f868d2 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -169,7 +169,7 @@ Vector3 Face3::get_median_point() const {
}
real_t Face3::get_area() const {
- return vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]).length();
+ return vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]).length() * 0.5;
}
ClockDirection Face3::get_clock_dir() const {
@@ -230,7 +230,7 @@ bool Face3::intersects_aabb(const AABB &p_aabb) const {
real_t minA, maxA, minB, maxB;
p_aabb.project_range_in_plane(Plane(axis, 0), minA, maxA);
- project_range(axis, Transform(), minB, maxB);
+ project_range(axis, Transform3D(), minB, maxB);
if (maxA < minB || maxB < minA) {
return false;
@@ -244,7 +244,7 @@ Face3::operator String() const {
return String() + vertex[0] + ", " + vertex[1] + ", " + vertex[2];
}
-void Face3::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+void Face3::project_range(const Vector3 &p_normal, const Transform3D &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);
@@ -259,7 +259,7 @@ void Face3::project_range(const Vector3 &p_normal, const Transform &p_transform,
}
}
-void Face3::get_support(const Vector3 &p_normal, const Transform &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const {
+void Face3::get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const {
#define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.98
#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.05
diff --git a/core/math/face3.h b/core/math/face3.h
index 2e86b0a904..5091b338ef 100644
--- a/core/math/face3.h
+++ b/core/math/face3.h
@@ -33,7 +33,7 @@
#include "core/math/aabb.h"
#include "core/math/plane.h"
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include "core/math/vector3.h"
class Face3 {
@@ -74,8 +74,8 @@ public:
ClockDirection get_clock_dir() const; ///< todo, test if this is returning the proper clockwisity
- void get_support(const Vector3 &p_normal, const Transform &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const;
- void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const;
+ void get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const;
+ void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
AABB get_aabb() const {
AABB aabb(vertex[0], Vector3());
diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp
index feb1fb2fb8..7b2630b4ff 100644
--- a/core/math/geometry_2d.cpp
+++ b/core/math/geometry_2d.cpp
@@ -358,7 +358,7 @@ Vector<Point2i> Geometry2D::pack_rects(const Vector<Size2i> &p_sizes, const Size
Vector<Vector3i> Geometry2D::partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size) {
Vector<stbrp_node> nodes;
nodes.resize(p_atlas_size.width);
- zeromem(nodes.ptrw(), sizeof(stbrp_node) * nodes.size());
+ memset(nodes.ptrw(), 0, sizeof(stbrp_node) * nodes.size());
stbrp_context context;
stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width);
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index 4b5aef352f..4958b5ac6a 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -395,6 +395,45 @@ public:
H.resize(k);
return H;
}
+
+ static Vector<Point2i> bresenham_line(const Point2i &p_start, const Point2i &p_end) {
+ Vector<Point2i> points;
+
+ Vector2i delta = (p_end - p_start).abs() * 2;
+ Vector2i step = (p_end - p_start).sign();
+ Vector2i current = p_start;
+
+ if (delta.x > delta.y) {
+ int err = delta.x / 2;
+
+ for (; current.x != p_end.x; current.x += step.x) {
+ points.push_back(current);
+
+ err -= delta.y;
+ if (err < 0) {
+ current.y += step.y;
+ err += delta.x;
+ }
+ }
+ } else {
+ int err = delta.y / 2;
+
+ for (; current.y != p_end.y; current.y += step.y) {
+ points.push_back(current);
+
+ err -= delta.x;
+ if (err < 0) {
+ current.x += step.x;
+ err += delta.y;
+ }
+ }
+ }
+
+ points.push_back(current);
+
+ return points;
+ }
+
static Vector<Vector<Vector2>> decompose_polygon_in_convex(Vector<Point2> polygon);
static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size);
diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp
index 0985a727f2..570c57e254 100644
--- a/core/math/math_fieldwise.cpp
+++ b/core/math/math_fieldwise.cpp
@@ -88,8 +88,8 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
- case Variant::QUAT: {
- SETUP_TYPE(Quat)
+ case Variant::QUATERNION: {
+ SETUP_TYPE(Quaternion)
/**/ TRY_TRANSFER_FIELD("x", x)
else TRY_TRANSFER_FIELD("y", y)
@@ -141,8 +141,8 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
- case Variant::TRANSFORM: {
- SETUP_TYPE(Transform)
+ case Variant::TRANSFORM3D: {
+ SETUP_TYPE(Transform3D)
/**/ TRY_TRANSFER_FIELD("xx", basis.elements[0][0])
else TRY_TRANSFER_FIELD("xy", basis.elements[0][1])
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 267f6a4fe2..3389407e72 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -103,6 +103,9 @@ public:
static _ALWAYS_INLINE_ double log(double p_x) { return ::log(p_x); }
static _ALWAYS_INLINE_ float log(float p_x) { return ::logf(p_x); }
+ static _ALWAYS_INLINE_ double log2(double p_x) { return ::log2(p_x); }
+ static _ALWAYS_INLINE_ float log2(float p_x) { return ::log2f(p_x); }
+
static _ALWAYS_INLINE_ double exp(double p_x) { return ::exp(p_x); }
static _ALWAYS_INLINE_ float exp(float p_x) { return ::expf(p_x); }
@@ -215,8 +218,8 @@ public:
return value;
}
- static _ALWAYS_INLINE_ int posmod(int p_x, int p_y) {
- int value = p_x % p_y;
+ static _ALWAYS_INLINE_ int64_t posmod(int64_t p_x, int64_t p_y) {
+ int64_t value = p_x % p_y;
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
value += p_y;
}
@@ -272,8 +275,8 @@ public:
static _ALWAYS_INLINE_ double db2linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
static _ALWAYS_INLINE_ float db2linear(float p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
- static _ALWAYS_INLINE_ double round(double p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); }
- static _ALWAYS_INLINE_ float round(float p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); }
+ static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); }
+ static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); }
static _ALWAYS_INLINE_ int64_t wrapi(int64_t value, int64_t min, int64_t max) {
int64_t range = max - min;
@@ -308,20 +311,46 @@ public:
static float random(float from, float to);
static int random(int from, int to);
- static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
+ static _ALWAYS_INLINE_ bool is_equal_approx(float a, float b) {
+ // Check for exact equality first, required to handle "infinity" values.
+ if (a == b) {
+ return true;
+ }
+ // Then check for approximate equality.
+ float tolerance = CMP_EPSILON * abs(a);
+ if (tolerance < CMP_EPSILON) {
+ tolerance = CMP_EPSILON;
+ }
+ return abs(a - b) < tolerance;
+ }
+
+ static _ALWAYS_INLINE_ bool is_equal_approx(float a, float b, float tolerance) {
+ // Check for exact equality first, required to handle "infinity" values.
+ if (a == b) {
+ return true;
+ }
+ // Then check for approximate equality.
+ return abs(a - b) < tolerance;
+ }
+
+ static _ALWAYS_INLINE_ bool is_zero_approx(float s) {
+ return abs(s) < CMP_EPSILON;
+ }
+
+ static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
- real_t tolerance = CMP_EPSILON * abs(a);
+ double tolerance = CMP_EPSILON * abs(a);
if (tolerance < CMP_EPSILON) {
tolerance = CMP_EPSILON;
}
return abs(a - b) < tolerance;
}
- static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t tolerance) {
+ static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b, double tolerance) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
@@ -330,7 +359,7 @@ public:
return abs(a - b) < tolerance;
}
- static _ALWAYS_INLINE_ bool is_zero_approx(real_t s) {
+ static _ALWAYS_INLINE_ bool is_zero_approx(double s) {
return abs(s) < CMP_EPSILON;
}
@@ -355,28 +384,10 @@ public:
return u.d;
}
- //this function should be as fast as possible and rounding mode should not matter
+ // This function should be as fast as possible and rounding mode should not matter.
static _ALWAYS_INLINE_ int fast_ftoi(float a) {
- static int b;
-
-#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0603) || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // windows 8 phone?
- b = (int)((a > 0.0) ? (a + 0.5) : (a - 0.5));
-
-#elif defined(_MSC_VER) && _MSC_VER < 1800
- __asm fld a __asm fistp b
- /*#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
- // use AT&T inline assembly style, document that
- // we use memory as output (=m) and input (m)
- __asm__ __volatile__ (
- "flds %1 \n\t"
- "fistpl %0 \n\t"
- : "=m" (b)
- : "m" (a));*/
-
-#else
- b = lrintf(a); //assuming everything but msvc 2012 or earlier has lrint
-#endif
- return b;
+ // Assuming every supported compiler has `lrint()`.
+ return lrintf(a);
}
static _ALWAYS_INLINE_ uint32_t halfbits_to_floatbits(uint16_t h) {
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index f1d3bbbd54..3c78b55b90 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -175,5 +175,5 @@ bool Plane::is_equal_approx(const Plane &p_plane) const {
}
Plane::operator String() const {
- return normal.operator String() + ", " + rtos(d);
+ return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]";
}
diff --git a/core/math/quat.cpp b/core/math/quaternion.cpp
index 6f13e04027..7037db7112 100644
--- a/core/math/quat.cpp
+++ b/core/math/quaternion.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* quat.cpp */
+/* quaternion.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "quat.h"
+#include "quaternion.h"
#include "core/math/basis.h"
#include "core/string/print_string.h"
@@ -37,7 +37,7 @@
// (ax,ay,az), where ax is the angle of rotation around x axis,
// and similar for other axes.
// This implementation uses XYZ convention (Z is the first rotation).
-Vector3 Quat::get_euler_xyz() const {
+Vector3 Quaternion::get_euler_xyz() const {
Basis m(*this);
return m.get_euler_xyz();
}
@@ -46,7 +46,7 @@ Vector3 Quat::get_euler_xyz() const {
// (ax,ay,az), where ax is the angle of rotation around x axis,
// and similar for other axes.
// This implementation uses YXZ convention (Z is the first rotation).
-Vector3 Quat::get_euler_yxz() const {
+Vector3 Quaternion::get_euler_yxz() const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized.");
#endif
@@ -54,7 +54,7 @@ Vector3 Quat::get_euler_yxz() const {
return m.get_euler_yxz();
}
-void Quat::operator*=(const Quat &p_q) {
+void Quaternion::operator*=(const Quaternion &p_q) {
real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y;
real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z;
real_t zz = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x;
@@ -64,45 +64,45 @@ void Quat::operator*=(const Quat &p_q) {
z = zz;
}
-Quat Quat::operator*(const Quat &p_q) const {
- Quat r = *this;
+Quaternion Quaternion::operator*(const Quaternion &p_q) const {
+ Quaternion r = *this;
r *= p_q;
return r;
}
-bool Quat::is_equal_approx(const Quat &p_quat) const {
- return Math::is_equal_approx(x, p_quat.x) && Math::is_equal_approx(y, p_quat.y) && Math::is_equal_approx(z, p_quat.z) && Math::is_equal_approx(w, p_quat.w);
+bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const {
+ return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w);
}
-real_t Quat::length() const {
+real_t Quaternion::length() const {
return Math::sqrt(length_squared());
}
-void Quat::normalize() {
+void Quaternion::normalize() {
*this /= length();
}
-Quat Quat::normalized() const {
+Quaternion Quaternion::normalized() const {
return *this / length();
}
-bool Quat::is_normalized() const {
- return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); //use less epsilon
+bool Quaternion::is_normalized() const {
+ return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); //use less epsilon
}
-Quat Quat::inverse() const {
+Quaternion Quaternion::inverse() const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The quaternion must be normalized.");
#endif
- return Quat(-x, -y, -z, w);
+ return Quaternion(-x, -y, -z, w);
}
-Quat Quat::slerp(const Quat &p_to, const real_t &p_weight) const {
+Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized.");
- ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quat(), "The end quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
#endif
- Quat to1;
+ Quaternion to1;
real_t omega, cosom, sinom, scale0, scale1;
// calc cosine
@@ -137,19 +137,19 @@ Quat Quat::slerp(const Quat &p_to, const real_t &p_weight) const {
scale1 = p_weight;
}
// calculate final values
- return Quat(
+ return Quaternion(
scale0 * x + scale1 * to1.x,
scale0 * y + scale1 * to1.y,
scale0 * z + scale1 * to1.z,
scale0 * w + scale1 * to1.w);
}
-Quat Quat::slerpni(const Quat &p_to, const real_t &p_weight) const {
+Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized.");
- ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quat(), "The end quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
#endif
- const Quat &from = *this;
+ const Quaternion &from = *this;
real_t dot = from.dot(p_to);
@@ -162,29 +162,29 @@ Quat Quat::slerpni(const Quat &p_to, const real_t &p_weight) const {
newFactor = Math::sin(p_weight * theta) * sinT,
invFactor = Math::sin((1.0 - p_weight) * theta) * sinT;
- return Quat(invFactor * from.x + newFactor * p_to.x,
+ return Quaternion(invFactor * from.x + newFactor * p_to.x,
invFactor * from.y + newFactor * p_to.y,
invFactor * from.z + newFactor * p_to.z,
invFactor * from.w + newFactor * p_to.w);
}
-Quat Quat::cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const {
+Quaternion Quaternion::cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized.");
- ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quat(), "The end quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
#endif
//the only way to do slerp :|
real_t t2 = (1.0 - p_weight) * p_weight * 2;
- Quat sp = this->slerp(p_b, p_weight);
- Quat sq = p_pre_a.slerpni(p_post_b, p_weight);
+ Quaternion sp = this->slerp(p_b, p_weight);
+ Quaternion sq = p_pre_a.slerpni(p_post_b, p_weight);
return sp.slerpni(sq, t2);
}
-Quat::operator String() const {
- return String::num(x) + ", " + String::num(y) + ", " + String::num(z) + ", " + String::num(w);
+Quaternion::operator String() const {
+ return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
}
-Quat::Quat(const Vector3 &p_axis, real_t p_angle) {
+Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
#ifdef MATH_CHECKS
ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized.");
#endif
@@ -209,7 +209,7 @@ Quat::Quat(const Vector3 &p_axis, real_t p_angle) {
// (ax, ay, az), where ax is the angle of rotation around x axis,
// and similar for other axes.
// This implementation uses YXZ convention (Z is the first rotation).
-Quat::Quat(const Vector3 &p_euler) {
+Quaternion::Quaternion(const Vector3 &p_euler) {
real_t half_a1 = p_euler.y * 0.5;
real_t half_a2 = p_euler.x * 0.5;
real_t half_a3 = p_euler.z * 0.5;
diff --git a/core/math/quat.h b/core/math/quaternion.h
index 9db914fe52..796214b79e 100644
--- a/core/math/quat.h
+++ b/core/math/quaternion.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* quat.h */
+/* quaternion.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,17 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-// Circular dependency between Vector3 and Basis :/
-#include "core/math/vector3.h"
-
#ifndef QUAT_H
#define QUAT_H
#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
+#include "core/math/vector3.h"
#include "core/string/ustring.h"
-class Quat {
+class Quaternion {
public:
union {
struct {
@@ -57,21 +55,21 @@ public:
return components[idx];
}
_FORCE_INLINE_ real_t length_squared() const;
- bool is_equal_approx(const Quat &p_quat) const;
+ bool is_equal_approx(const Quaternion &p_quaternion) const;
real_t length() const;
void normalize();
- Quat normalized() const;
+ Quaternion normalized() const;
bool is_normalized() const;
- Quat inverse() const;
- _FORCE_INLINE_ real_t dot(const Quat &p_q) const;
+ Quaternion inverse() const;
+ _FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
Vector3 get_euler_xyz() const;
Vector3 get_euler_yxz() const;
Vector3 get_euler() const { return get_euler_yxz(); };
- Quat slerp(const Quat &p_to, const real_t &p_weight) const;
- Quat slerpni(const Quat &p_to, const real_t &p_weight) const;
- Quat cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const;
+ Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
+ Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
+ Quaternion cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
_FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
r_angle = 2 * Math::acos(w);
@@ -81,11 +79,11 @@ public:
r_axis.z = z * r;
}
- void operator*=(const Quat &p_q);
- Quat operator*(const Quat &p_q) const;
+ void operator*=(const Quaternion &p_q);
+ Quaternion operator*(const Quaternion &p_q) const;
- Quat operator*(const Vector3 &v) const {
- return Quat(w * v.x + y * v.z - z * v.y,
+ Quaternion operator*(const Vector3 &v) const {
+ return Quaternion(w * v.x + y * v.z - z * v.y,
w * v.y + z * v.x - x * v.z,
w * v.z + x * v.y - y * v.x,
-x * v.x - y * v.y - z * v.z);
@@ -104,42 +102,42 @@ public:
return inverse().xform(v);
}
- _FORCE_INLINE_ void operator+=(const Quat &p_q);
- _FORCE_INLINE_ void operator-=(const Quat &p_q);
+ _FORCE_INLINE_ void operator+=(const Quaternion &p_q);
+ _FORCE_INLINE_ void operator-=(const Quaternion &p_q);
_FORCE_INLINE_ void operator*=(const real_t &s);
_FORCE_INLINE_ void operator/=(const real_t &s);
- _FORCE_INLINE_ Quat operator+(const Quat &q2) const;
- _FORCE_INLINE_ Quat operator-(const Quat &q2) const;
- _FORCE_INLINE_ Quat operator-() const;
- _FORCE_INLINE_ Quat operator*(const real_t &s) const;
- _FORCE_INLINE_ Quat operator/(const real_t &s) const;
+ _FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const;
+ _FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const;
+ _FORCE_INLINE_ Quaternion operator-() const;
+ _FORCE_INLINE_ Quaternion operator*(const real_t &s) const;
+ _FORCE_INLINE_ Quaternion operator/(const real_t &s) const;
- _FORCE_INLINE_ bool operator==(const Quat &p_quat) const;
- _FORCE_INLINE_ bool operator!=(const Quat &p_quat) const;
+ _FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const;
+ _FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const;
operator String() const;
- _FORCE_INLINE_ Quat() {}
+ _FORCE_INLINE_ Quaternion() {}
- _FORCE_INLINE_ Quat(real_t p_x, real_t p_y, real_t p_z, real_t p_w) :
+ _FORCE_INLINE_ Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) :
x(p_x),
y(p_y),
z(p_z),
w(p_w) {
}
- Quat(const Vector3 &p_axis, real_t p_angle);
+ Quaternion(const Vector3 &p_axis, real_t p_angle);
- Quat(const Vector3 &p_euler);
+ Quaternion(const Vector3 &p_euler);
- Quat(const Quat &p_q) :
+ Quaternion(const Quaternion &p_q) :
x(p_q.x),
y(p_q.y),
z(p_q.z),
w(p_q.w) {
}
- Quat &operator=(const Quat &p_q) {
+ Quaternion &operator=(const Quaternion &p_q) {
x = p_q.x;
y = p_q.y;
z = p_q.z;
@@ -147,7 +145,7 @@ public:
return *this;
}
- Quat(const Vector3 &v0, const Vector3 &v1) // shortest arc
+ Quaternion(const Vector3 &v0, const Vector3 &v1) // shortest arc
{
Vector3 c = v0.cross(v1);
real_t d = v0.dot(v1);
@@ -169,72 +167,72 @@ public:
}
};
-real_t Quat::dot(const Quat &p_q) const {
+real_t Quaternion::dot(const Quaternion &p_q) const {
return x * p_q.x + y * p_q.y + z * p_q.z + w * p_q.w;
}
-real_t Quat::length_squared() const {
+real_t Quaternion::length_squared() const {
return dot(*this);
}
-void Quat::operator+=(const Quat &p_q) {
+void Quaternion::operator+=(const Quaternion &p_q) {
x += p_q.x;
y += p_q.y;
z += p_q.z;
w += p_q.w;
}
-void Quat::operator-=(const Quat &p_q) {
+void Quaternion::operator-=(const Quaternion &p_q) {
x -= p_q.x;
y -= p_q.y;
z -= p_q.z;
w -= p_q.w;
}
-void Quat::operator*=(const real_t &s) {
+void Quaternion::operator*=(const real_t &s) {
x *= s;
y *= s;
z *= s;
w *= s;
}
-void Quat::operator/=(const real_t &s) {
+void Quaternion::operator/=(const real_t &s) {
*this *= 1.0 / s;
}
-Quat Quat::operator+(const Quat &q2) const {
- const Quat &q1 = *this;
- return Quat(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w);
+Quaternion Quaternion::operator+(const Quaternion &q2) const {
+ const Quaternion &q1 = *this;
+ return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w);
}
-Quat Quat::operator-(const Quat &q2) const {
- const Quat &q1 = *this;
- return Quat(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w);
+Quaternion Quaternion::operator-(const Quaternion &q2) const {
+ const Quaternion &q1 = *this;
+ return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w);
}
-Quat Quat::operator-() const {
- const Quat &q2 = *this;
- return Quat(-q2.x, -q2.y, -q2.z, -q2.w);
+Quaternion Quaternion::operator-() const {
+ const Quaternion &q2 = *this;
+ return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w);
}
-Quat Quat::operator*(const real_t &s) const {
- return Quat(x * s, y * s, z * s, w * s);
+Quaternion Quaternion::operator*(const real_t &s) const {
+ return Quaternion(x * s, y * s, z * s, w * s);
}
-Quat Quat::operator/(const real_t &s) const {
+Quaternion Quaternion::operator/(const real_t &s) const {
return *this * (1.0 / s);
}
-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;
+bool Quaternion::operator==(const Quaternion &p_quaternion) const {
+ return x == p_quaternion.x && y == p_quaternion.y && z == p_quaternion.z && w == p_quaternion.w;
}
-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;
+bool Quaternion::operator!=(const Quaternion &p_quaternion) const {
+ return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w;
}
-_FORCE_INLINE_ Quat operator*(const real_t &p_real, const Quat &p_quat) {
- return p_quat * p_real;
+_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) {
+ return p_quaternion * p_real;
}
#endif // QUAT_H
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index fe18cc3d41..0d77bfe933 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -112,7 +112,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_
}
}
- //fourth vertex is the one most further away from the plane
+ //fourth vertex is the one most further away from the plane
{
real_t maxd = 0;
diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h
index a396c2b7d7..06cd3999f3 100644
--- a/core/math/random_number_generator.h
+++ b/core/math/random_number_generator.h
@@ -32,10 +32,10 @@
#define RANDOM_NUMBER_GENERATOR_H
#include "core/math/random_pcg.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class RandomNumberGenerator : public Reference {
- GDCLASS(RandomNumberGenerator, Reference);
+class RandomNumberGenerator : public RefCounted {
+ GDCLASS(RandomNumberGenerator, RefCounted);
protected:
RandomPCG randbase;
diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp
index 9609620469..681c2a9717 100644
--- a/core/math/random_pcg.cpp
+++ b/core/math/random_pcg.cpp
@@ -39,7 +39,7 @@ RandomPCG::RandomPCG(uint64_t p_seed, uint64_t p_inc) :
}
void RandomPCG::randomize() {
- seed(OS::get_singleton()->get_ticks_usec() * pcg.state + PCG_DEFAULT_INC_64);
+ seed(((uint64_t)OS::get_singleton()->get_unix_time() + OS::get_singleton()->get_ticks_usec()) * pcg.state + PCG_DEFAULT_INC_64);
}
double RandomPCG::random(double p_from, double p_to) {
diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp
index 60c44999f7..f64bf560c8 100644
--- a/core/math/rect2.cpp
+++ b/core/math/rect2.cpp
@@ -263,3 +263,11 @@ next4:
return true;
}
+
+Rect2::operator String() const {
+ return "[P: " + position.operator String() + ", S: " + size + "]";
+}
+
+Rect2i::operator String() const {
+ return "[P: " + position.operator String() + ", S: " + size + "]";
+}
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 512499bdb2..ab0b489b4a 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -182,13 +182,17 @@ struct Rect2 {
inline Rect2 grow(real_t p_amount) const {
Rect2 g = *this;
- g.position.x -= p_amount;
- g.position.y -= p_amount;
- g.size.width += p_amount * 2;
- g.size.height += p_amount * 2;
+ g.grow_by(p_amount);
return g;
}
+ inline void grow_by(real_t p_amount) {
+ position.x -= p_amount;
+ position.y -= p_amount;
+ size.width += p_amount * 2;
+ size.height += p_amount * 2;
+ }
+
inline Rect2 grow_side(Side p_side, real_t p_amount) const {
Rect2 g = *this;
g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0,
@@ -316,7 +320,7 @@ struct Rect2 {
return position + size;
}
- operator String() const { return String(position) + ", " + String(size); }
+ operator String() const;
Rect2() {}
Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) :
@@ -494,7 +498,7 @@ struct Rect2i {
return position + size;
}
- operator String() const { return String(position) + ", " + String(size); }
+ operator String() const;
operator Rect2() const { return Rect2(position, size); }
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 4a521b96ae..0140f31b8a 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -158,6 +158,13 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
return elements[0].is_equal_approx(p_transform.elements[0]) && elements[1].is_equal_approx(p_transform.elements[1]) && elements[2].is_equal_approx(p_transform.elements[2]);
}
+Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
+ Transform2D return_trans = Transform2D(get_rotation(), get_origin());
+ Vector2 target_position = affine_inverse().xform(p_target);
+ return_trans.set_rotation(return_trans.get_rotation() + (target_position * get_scale()).angle());
+ return return_trans;
+}
+
bool Transform2D::operator==(const Transform2D &p_transform) const {
for (int i = 0; i < 3; i++) {
if (elements[i] != p_transform.elements[i]) {
@@ -270,5 +277,7 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t
}
Transform2D::operator String() const {
- return String(String() + elements[0] + ", " + elements[1] + ", " + elements[2]);
+ return "[X: " + elements[0].operator String() +
+ ", Y: " + elements[1].operator String() +
+ ", O: " + elements[2].operator String() + "]";
}
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index 327d0f244f..715f013701 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -100,6 +100,8 @@ struct Transform2D {
Transform2D orthonormalized() const;
bool is_equal_approx(const Transform2D &p_transform) const;
+ Transform2D looking_at(const Vector2 &p_target) const;
+
bool operator==(const Transform2D &p_transform) const;
bool operator!=(const Transform2D &p_transform) const;
diff --git a/core/math/transform.cpp b/core/math/transform_3d.cpp
index fab5d124fa..a34d998dde 100644
--- a/core/math/transform.cpp
+++ b/core/math/transform_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* transform.cpp */
+/* transform_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,55 +28,54 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "transform.h"
+#include "transform_3d.h"
#include "core/math/math_funcs.h"
-#include "core/os/copymem.h"
#include "core/string/print_string.h"
-void Transform::affine_invert() {
+void Transform3D::affine_invert() {
basis.invert();
origin = basis.xform(-origin);
}
-Transform Transform::affine_inverse() const {
- Transform ret = *this;
+Transform3D Transform3D::affine_inverse() const {
+ Transform3D ret = *this;
ret.affine_invert();
return ret;
}
-void Transform::invert() {
+void Transform3D::invert() {
basis.transpose();
origin = basis.xform(-origin);
}
-Transform Transform::inverse() const {
+Transform3D Transform3D::inverse() const {
// FIXME: this function assumes the basis is a rotation matrix, with no scaling.
- // Transform::affine_inverse can handle matrices with scaling, so GDScript should eventually use that.
- Transform ret = *this;
+ // Transform3D::affine_inverse can handle matrices with scaling, so GDScript should eventually use that.
+ Transform3D ret = *this;
ret.invert();
return ret;
}
-void Transform::rotate(const Vector3 &p_axis, real_t p_phi) {
+void Transform3D::rotate(const Vector3 &p_axis, real_t p_phi) {
*this = rotated(p_axis, p_phi);
}
-Transform Transform::rotated(const Vector3 &p_axis, real_t p_phi) const {
- return Transform(Basis(p_axis, p_phi), Vector3()) * (*this);
+Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_phi) const {
+ return Transform3D(Basis(p_axis, p_phi), Vector3()) * (*this);
}
-void Transform::rotate_basis(const Vector3 &p_axis, real_t p_phi) {
+void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_phi) {
basis.rotate(p_axis, p_phi);
}
-Transform Transform::looking_at(const Vector3 &p_target, const Vector3 &p_up) const {
- Transform t = *this;
+Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const {
+ Transform3D t = *this;
t.set_look_at(origin, p_target, p_up);
return t;
}
-void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) {
+void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) {
#ifdef MATH_CHECKS
ERR_FAIL_COND(p_eye == p_target);
ERR_FAIL_COND(p_up.length() == 0);
@@ -109,105 +108,108 @@ void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const
origin = p_eye;
}
-Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c) const {
+Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const {
/* not sure if very "efficient" but good enough? */
Vector3 src_scale = basis.get_scale();
- Quat src_rot = basis.get_rotation_quat();
+ Quaternion src_rot = basis.get_rotation_quaternion();
Vector3 src_loc = origin;
Vector3 dst_scale = p_transform.basis.get_scale();
- Quat dst_rot = p_transform.basis.get_rotation_quat();
+ Quaternion dst_rot = p_transform.basis.get_rotation_quaternion();
Vector3 dst_loc = p_transform.origin;
- Transform interp;
- interp.basis.set_quat_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c));
+ Transform3D interp;
+ interp.basis.set_quaternion_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c));
interp.origin = src_loc.lerp(dst_loc, p_c);
return interp;
}
-void Transform::scale(const Vector3 &p_scale) {
+void Transform3D::scale(const Vector3 &p_scale) {
basis.scale(p_scale);
origin *= p_scale;
}
-Transform Transform::scaled(const Vector3 &p_scale) const {
- Transform t = *this;
+Transform3D Transform3D::scaled(const Vector3 &p_scale) const {
+ Transform3D t = *this;
t.scale(p_scale);
return t;
}
-void Transform::scale_basis(const Vector3 &p_scale) {
+void Transform3D::scale_basis(const Vector3 &p_scale) {
basis.scale(p_scale);
}
-void Transform::translate(real_t p_tx, real_t p_ty, real_t p_tz) {
+void Transform3D::translate(real_t p_tx, real_t p_ty, real_t p_tz) {
translate(Vector3(p_tx, p_ty, p_tz));
}
-void Transform::translate(const Vector3 &p_translation) {
+void Transform3D::translate(const Vector3 &p_translation) {
for (int i = 0; i < 3; i++) {
origin[i] += basis[i].dot(p_translation);
}
}
-Transform Transform::translated(const Vector3 &p_translation) const {
- Transform t = *this;
+Transform3D Transform3D::translated(const Vector3 &p_translation) const {
+ Transform3D t = *this;
t.translate(p_translation);
return t;
}
-void Transform::orthonormalize() {
+void Transform3D::orthonormalize() {
basis.orthonormalize();
}
-Transform Transform::orthonormalized() const {
- Transform _copy = *this;
+Transform3D Transform3D::orthonormalized() const {
+ Transform3D _copy = *this;
_copy.orthonormalize();
return _copy;
}
-bool Transform::is_equal_approx(const Transform &p_transform) const {
+bool Transform3D::is_equal_approx(const Transform3D &p_transform) const {
return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin);
}
-bool Transform::operator==(const Transform &p_transform) const {
+bool Transform3D::operator==(const Transform3D &p_transform) const {
return (basis == p_transform.basis && origin == p_transform.origin);
}
-bool Transform::operator!=(const Transform &p_transform) const {
+bool Transform3D::operator!=(const Transform3D &p_transform) const {
return (basis != p_transform.basis || origin != p_transform.origin);
}
-void Transform::operator*=(const Transform &p_transform) {
+void Transform3D::operator*=(const Transform3D &p_transform) {
origin = xform(p_transform.origin);
basis *= p_transform.basis;
}
-Transform Transform::operator*(const Transform &p_transform) const {
- Transform t = *this;
+Transform3D Transform3D::operator*(const Transform3D &p_transform) const {
+ Transform3D t = *this;
t *= p_transform;
return t;
}
-Transform::operator String() const {
- return basis.operator String() + " - " + origin.operator String();
+Transform3D::operator String() const {
+ return "[X: " + basis.get_axis(0).operator String() +
+ ", Y: " + basis.get_axis(1).operator String() +
+ ", Z: " + basis.get_axis(2).operator String() +
+ ", O: " + origin.operator String() + "]";
}
-Transform::Transform(const Basis &p_basis, const Vector3 &p_origin) :
+Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) :
basis(p_basis),
origin(p_origin) {
}
-Transform::Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) :
+Transform3D::Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) :
origin(p_origin) {
basis.set_axis(0, p_x);
basis.set_axis(1, p_y);
basis.set_axis(2, p_z);
}
-Transform::Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) {
+Transform3D::Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) {
basis = Basis(xx, xy, xz, yx, yy, yz, zx, zy, zz);
origin = Vector3(ox, oy, oz);
}
diff --git a/core/math/transform.h b/core/math/transform_3d.h
index 1c05dbe554..078a2ca11a 100644
--- a/core/math/transform.h
+++ b/core/math/transform_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* transform.h */
+/* transform_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -35,31 +35,31 @@
#include "core/math/basis.h"
#include "core/math/plane.h"
-class Transform {
+class Transform3D {
public:
Basis basis;
Vector3 origin;
void invert();
- Transform inverse() const;
+ Transform3D inverse() const;
void affine_invert();
- Transform affine_inverse() const;
+ Transform3D affine_inverse() const;
- Transform rotated(const Vector3 &p_axis, real_t p_phi) const;
+ Transform3D rotated(const Vector3 &p_axis, real_t p_phi) const;
void rotate(const Vector3 &p_axis, real_t p_phi);
void rotate_basis(const Vector3 &p_axis, real_t p_phi);
void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
- Transform looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const;
+ Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const;
void scale(const Vector3 &p_scale);
- Transform scaled(const Vector3 &p_scale) const;
+ Transform3D scaled(const Vector3 &p_scale) const;
void scale_basis(const Vector3 &p_scale);
void translate(real_t p_tx, real_t p_ty, real_t p_tz);
void translate(const Vector3 &p_translation);
- Transform translated(const Vector3 &p_translation) const;
+ Transform3D translated(const Vector3 &p_translation) const;
const Basis &get_basis() const { return basis; }
void set_basis(const Basis &p_basis) { basis = p_basis; }
@@ -68,11 +68,11 @@ public:
void set_origin(const Vector3 &p_origin) { origin = p_origin; }
void orthonormalize();
- Transform orthonormalized() const;
- bool is_equal_approx(const Transform &p_transform) const;
+ Transform3D orthonormalized() const;
+ bool is_equal_approx(const Transform3D &p_transform) const;
- bool operator==(const Transform &p_transform) const;
- bool operator!=(const Transform &p_transform) const;
+ bool operator==(const Transform3D &p_transform) const;
+ bool operator!=(const Transform3D &p_transform) const;
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const;
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const;
@@ -86,14 +86,14 @@ public:
_FORCE_INLINE_ Vector<Vector3> xform(const Vector<Vector3> &p_array) const;
_FORCE_INLINE_ Vector<Vector3> xform_inv(const Vector<Vector3> &p_array) const;
- void operator*=(const Transform &p_transform);
- Transform operator*(const Transform &p_transform) const;
+ void operator*=(const Transform3D &p_transform);
+ Transform3D operator*(const Transform3D &p_transform) const;
- Transform interpolate_with(const Transform &p_transform, real_t p_c) const;
+ Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const;
- _FORCE_INLINE_ Transform inverse_xform(const Transform &t) const {
+ _FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const {
Vector3 v = t.origin - origin;
- return Transform(basis.transpose_xform(t.basis),
+ return Transform3D(basis.transpose_xform(t.basis),
basis.xform(v));
}
@@ -106,20 +106,20 @@ public:
operator String() const;
- Transform() {}
- Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3());
- Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin);
- Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz);
+ Transform3D() {}
+ Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3());
+ Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin);
+ Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz);
};
-_FORCE_INLINE_ Vector3 Transform::xform(const Vector3 &p_vector) const {
+_FORCE_INLINE_ Vector3 Transform3D::xform(const Vector3 &p_vector) const {
return Vector3(
basis[0].dot(p_vector) + origin.x,
basis[1].dot(p_vector) + origin.y,
basis[2].dot(p_vector) + origin.z);
}
-_FORCE_INLINE_ Vector3 Transform::xform_inv(const Vector3 &p_vector) const {
+_FORCE_INLINE_ Vector3 Transform3D::xform_inv(const Vector3 &p_vector) const {
Vector3 v = p_vector - origin;
return Vector3(
@@ -128,7 +128,7 @@ _FORCE_INLINE_ Vector3 Transform::xform_inv(const Vector3 &p_vector) const {
(basis.elements[0][2] * v.x) + (basis.elements[1][2] * v.y) + (basis.elements[2][2] * v.z));
}
-_FORCE_INLINE_ Plane Transform::xform(const Plane &p_plane) const {
+_FORCE_INLINE_ Plane Transform3D::xform(const Plane &p_plane) const {
Vector3 point = p_plane.normal * p_plane.d;
Vector3 point_dir = point + p_plane.normal;
point = xform(point);
@@ -141,7 +141,7 @@ _FORCE_INLINE_ Plane Transform::xform(const Plane &p_plane) const {
return Plane(normal, d);
}
-_FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const {
+_FORCE_INLINE_ Plane Transform3D::xform_inv(const Plane &p_plane) const {
Vector3 point = p_plane.normal * p_plane.d;
Vector3 point_dir = point + p_plane.normal;
point = xform_inv(point);
@@ -154,7 +154,7 @@ _FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const {
return Plane(normal, d);
}
-_FORCE_INLINE_ AABB Transform::xform(const AABB &p_aabb) const {
+_FORCE_INLINE_ AABB Transform3D::xform(const AABB &p_aabb) const {
/* http://dev.theomader.com/transform-bounding-boxes/ */
Vector3 min = p_aabb.position;
Vector3 max = p_aabb.position + p_aabb.size;
@@ -179,7 +179,7 @@ _FORCE_INLINE_ AABB Transform::xform(const AABB &p_aabb) const {
return r_aabb;
}
-_FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const {
+_FORCE_INLINE_ AABB Transform3D::xform_inv(const AABB &p_aabb) const {
/* define vertices */
Vector3 vertices[8] = {
Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z),
@@ -203,7 +203,7 @@ _FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const {
return ret;
}
-Vector<Vector3> Transform::xform(const Vector<Vector3> &p_array) const {
+Vector<Vector3> Transform3D::xform(const Vector<Vector3> &p_array) const {
Vector<Vector3> array;
array.resize(p_array.size());
@@ -216,7 +216,7 @@ Vector<Vector3> Transform::xform(const Vector<Vector3> &p_array) const {
return array;
}
-Vector<Vector3> Transform::xform_inv(const Vector<Vector3> &p_array) const {
+Vector<Vector3> Transform3D::xform_inv(const Vector<Vector3> &p_array) const {
Vector<Vector3> array;
array.resize(p_array.size());
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index 23c0c686a2..903d5951a8 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -600,7 +600,7 @@ bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count,
const Vector3 *vertexptr = vertices.ptr();
const BVH *bvhptr = bvh.ptr();
- Transform scale(Basis().scaled(p_scale));
+ Transform3D scale(Basis().scaled(p_scale));
int pos = bvh.size() - 1;
diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h
index 1d1dbc114b..463b0dd5c8 100644
--- a/core/math/triangle_mesh.h
+++ b/core/math/triangle_mesh.h
@@ -32,10 +32,10 @@
#define TRIANGLE_MESH_H
#include "core/math/face3.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class TriangleMesh : public Reference {
- GDCLASS(TriangleMesh, Reference);
+class TriangleMesh : public RefCounted {
+ GDCLASS(TriangleMesh, RefCounted);
struct Triangle {
Vector3 normal;
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index 5129ed336e..eb3301f5d0 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -59,7 +59,7 @@ Vector2 Vector2::normalized() const {
bool Vector2::is_normalized() const {
// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
- return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON);
+ return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON);
}
real_t Vector2::distance_to(const Vector2 &p_vector2) const {
@@ -122,14 +122,20 @@ Vector2 Vector2::project(const Vector2 &p_to) const {
return p_to * (dot(p_to) / p_to.length_squared());
}
+Vector2 Vector2::clamp(const Vector2 &p_min, const Vector2 &p_max) const {
+ return Vector2(
+ CLAMP(x, p_min.x, p_max.x),
+ CLAMP(y, p_min.y, p_max.y));
+}
+
Vector2 Vector2::snapped(const Vector2 &p_step) const {
return Vector2(
Math::snapped(x, p_step.x),
Math::snapped(y, p_step.y));
}
-Vector2 Vector2::clamped(real_t p_len) const {
- real_t l = length();
+Vector2 Vector2::limit_length(const real_t p_len) const {
+ const real_t l = length();
Vector2 v = *this;
if (l > 0 && p_len < l) {
v /= l;
@@ -187,8 +193,18 @@ bool Vector2::is_equal_approx(const Vector2 &p_v) const {
return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y);
}
+Vector2::operator String() const {
+ return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
+}
+
/* Vector2i */
+Vector2i Vector2i::clamp(const Vector2i &p_min, const Vector2i &p_max) const {
+ return Vector2i(
+ CLAMP(x, p_min.x, p_max.x),
+ CLAMP(y, p_min.y, p_max.y));
+}
+
Vector2i Vector2i::operator+(const Vector2i &p_v) const {
return Vector2i(x + p_v.x, y + p_v.y);
}
@@ -257,3 +273,7 @@ bool Vector2i::operator==(const Vector2i &p_vec2) const {
bool Vector2i::operator!=(const Vector2i &p_vec2) const {
return x != p_vec2.x || y != p_vec2.y;
}
+
+Vector2i::operator String() const {
+ return "(" + itos(x) + ", " + itos(y) + ")";
+}
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 81bc71d590..78deb473b4 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -37,18 +37,26 @@
struct Vector2i;
struct Vector2 {
+ static const int AXIS_COUNT = 2;
+
enum Axis {
AXIS_X,
AXIS_Y,
};
union {
- real_t x = 0;
- real_t width;
- };
- union {
- real_t y = 0;
- real_t height;
+ struct {
+ union {
+ real_t x;
+ real_t width;
+ };
+ union {
+ real_t y;
+ real_t height;
+ };
+ };
+
+ real_t coord[2] = { 0 };
};
_FORCE_INLINE_ real_t &operator[](int p_idx) {
@@ -58,12 +66,25 @@ struct Vector2 {
return p_idx ? y : x;
}
+ _FORCE_INLINE_ void set_all(real_t p_value) {
+ x = y = p_value;
+ }
+
+ _FORCE_INLINE_ int min_axis() const {
+ return x < y ? 0 : 1;
+ }
+
+ _FORCE_INLINE_ int max_axis() const {
+ return x < y ? 1 : 0;
+ }
+
void normalize();
Vector2 normalized() const;
bool is_normalized() const;
real_t length() const;
real_t length_squared() const;
+ Vector2 limit_length(const real_t p_len = 1.0) const;
Vector2 min(const Vector2 &p_vector2) const {
return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y));
@@ -87,8 +108,6 @@ struct Vector2 {
Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const;
- Vector2 clamped(real_t p_len) const;
-
_FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, real_t p_weight) const;
_FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, real_t p_weight) const;
Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const;
@@ -143,9 +162,10 @@ struct Vector2 {
Vector2 ceil() const;
Vector2 round() const;
Vector2 snapped(const Vector2 &p_by) const;
+ Vector2 clamp(const Vector2 &p_min, const Vector2 &p_max) const;
real_t aspect() const { return width / height; }
- operator String() const { return String::num(x) + ", " + String::num(y); }
+ operator String() const;
_FORCE_INLINE_ Vector2() {}
_FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) {
@@ -280,6 +300,14 @@ struct Vector2i {
return p_idx ? y : x;
}
+ Vector2i min(const Vector2i &p_vector2i) const {
+ return Vector2(MIN(x, p_vector2i.x), MIN(y, p_vector2i.y));
+ }
+
+ Vector2i max(const Vector2i &p_vector2i) const {
+ return Vector2(MAX(x, p_vector2i.x), MAX(y, p_vector2i.y));
+ }
+
Vector2i operator+(const Vector2i &p_v) const;
void operator+=(const Vector2i &p_v);
Vector2i operator-(const Vector2i &p_v) const;
@@ -310,8 +338,9 @@ struct Vector2i {
real_t aspect() const { return width / (real_t)height; }
Vector2i sign() const { return Vector2i(SGN(x), SGN(y)); }
Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); }
+ Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const;
- operator String() const { return String::num(x) + ", " + String::num(y); }
+ operator String() const;
operator Vector2() const { return Vector2(x, y); }
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index f0629d3db8..3d59064af6 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -52,12 +52,11 @@ real_t Vector3::get_axis(int p_axis) const {
return operator[](p_axis);
}
-int Vector3::min_axis() const {
- return x < y ? (x < z ? 0 : 2) : (y < z ? 1 : 2);
-}
-
-int Vector3::max_axis() const {
- return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0);
+Vector3 Vector3::clamp(const Vector3 &p_min, const Vector3 &p_max) const {
+ return Vector3(
+ CLAMP(x, p_min.x, p_max.x),
+ CLAMP(y, p_min.y, p_max.y),
+ CLAMP(z, p_min.z, p_max.z));
}
void Vector3::snap(Vector3 p_step) {
@@ -72,6 +71,17 @@ Vector3 Vector3::snapped(Vector3 p_step) const {
return v;
}
+Vector3 Vector3::limit_length(const real_t p_len) const {
+ const real_t l = length();
+ Vector3 v = *this;
+ if (l > 0 && p_len < l) {
+ v /= l;
+ v *= p_len;
+ }
+
+ return v;
+}
+
Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight) const {
Vector3 p0 = p_pre_a;
Vector3 p1 = *this;
@@ -116,5 +126,5 @@ bool Vector3::is_equal_approx(const Vector3 &p_v) const {
}
Vector3::operator String() const {
- return (rtos(x) + ", " + rtos(y) + ", " + rtos(z));
+ return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
}
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 377581bb45..d8d3cd3cc0 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -38,6 +38,8 @@
class Basis;
struct Vector3 {
+ static const int AXIS_COUNT = 3;
+
enum Axis {
AXIS_X,
AXIS_Y,
@@ -65,8 +67,17 @@ struct Vector3 {
void set_axis(int p_axis, real_t p_value);
real_t get_axis(int p_axis) const;
- int min_axis() const;
- int max_axis() const;
+ _FORCE_INLINE_ void set_all(real_t p_value) {
+ x = y = z = p_value;
+ }
+
+ _FORCE_INLINE_ int min_axis() const {
+ return x < y ? (x < z ? 0 : 2) : (y < z ? 1 : 2);
+ }
+
+ _FORCE_INLINE_ int max_axis() const {
+ return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0);
+ }
_FORCE_INLINE_ real_t length() const;
_FORCE_INLINE_ real_t length_squared() const;
@@ -75,6 +86,7 @@ struct Vector3 {
_FORCE_INLINE_ Vector3 normalized() const;
_FORCE_INLINE_ bool is_normalized() const;
_FORCE_INLINE_ Vector3 inverse() const;
+ Vector3 limit_length(const real_t p_len = 1.0) const;
_FORCE_INLINE_ void zero();
@@ -101,6 +113,7 @@ struct Vector3 {
_FORCE_INLINE_ Vector3 sign() const;
_FORCE_INLINE_ Vector3 ceil() const;
_FORCE_INLINE_ Vector3 round() const;
+ Vector3 clamp(const Vector3 &p_min, const Vector3 &p_max) const;
_FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const;
_FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const;
@@ -412,7 +425,7 @@ Vector3 Vector3::normalized() const {
bool Vector3::is_normalized() const {
// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
- return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON);
+ return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON);
}
Vector3 Vector3::inverse() const {
diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp
index 167fa3221d..2de1e4e331 100644
--- a/core/math/vector3i.cpp
+++ b/core/math/vector3i.cpp
@@ -48,6 +48,13 @@ int Vector3i::max_axis() const {
return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0);
}
+Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const {
+ return Vector3i(
+ CLAMP(x, p_min.x, p_max.x),
+ CLAMP(y, p_min.y, p_max.y),
+ CLAMP(z, p_min.z, p_max.z));
+}
+
Vector3i::operator String() const {
- return (itos(x) + ", " + itos(y) + ", " + itos(z));
+ return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")";
}
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index b0411fb62e..37c7c1c368 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -69,6 +69,7 @@ struct Vector3i {
_FORCE_INLINE_ Vector3i abs() const;
_FORCE_INLINE_ Vector3i sign() const;
+ Vector3i clamp(const Vector3i &p_min, const Vector3i &p_max) const;
/* Operators */
diff --git a/core/object/callable_method_pointer.h b/core/object/callable_method_pointer.h
index 115797a00c..8ba01be4e4 100644
--- a/core/object/callable_method_pointer.h
+++ b/core/object/callable_method_pointer.h
@@ -32,7 +32,6 @@
#define CALLABLE_METHOD_POINTER_H
#include "core/object/object.h"
-#include "core/os/copymem.h"
#include "core/templates/hashfuncs.h"
#include "core/templates/simple_type.h"
#include "core/variant/binder_common.h"
@@ -98,7 +97,7 @@ public:
}
CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) {
- zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes.
+ memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
#ifdef DEBUG_ENABLED
data.object_id = p_instance->get_instance_id();
@@ -153,7 +152,7 @@ public:
}
CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
- zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes.
+ memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
#ifdef DEBUG_ENABLED
data.object_id = p_instance->get_instance_id();
@@ -208,7 +207,7 @@ public:
}
CallableCustomMethodPointerRetC(T *p_instance, R (T::*p_method)(P...) const) {
- zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes.
+ memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
#ifdef DEBUG_ENABLED
data.object_id = p_instance->get_instance_id();
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index fb7eb42738..5bf874ccae 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -501,12 +501,27 @@ void ClassDB::add_compatibility_class(const StringName &p_class, const StringNam
compat_classes[p_class] = p_fallback;
}
+thread_local bool initializing_with_extension = false;
+thread_local ObjectNativeExtension *initializing_extension = nullptr;
+thread_local void *initializing_extension_instance = nullptr;
+
+void ClassDB::instance_get_native_extension_data(ObjectNativeExtension **r_extension, void **r_extension_instance) {
+ if (initializing_with_extension) {
+ *r_extension = initializing_extension;
+ *r_extension_instance = initializing_extension_instance;
+ initializing_with_extension = false;
+ } else {
+ *r_extension = nullptr;
+ *r_extension_instance = nullptr;
+ }
+}
+
Object *ClassDB::instance(const StringName &p_class) {
ClassInfo *ti;
{
OBJTYPE_RLOCK;
ti = classes.getptr(p_class);
- if (!ti || ti->disabled || !ti->creation_func) {
+ if (!ti || ti->disabled || !ti->creation_func || (ti->native_extension && !ti->native_extension->create_instance)) {
if (compat_classes.has(p_class)) {
ti = classes.getptr(compat_classes[p_class]);
}
@@ -521,6 +536,11 @@ Object *ClassDB::instance(const StringName &p_class) {
return nullptr;
}
#endif
+ if (ti->native_extension) {
+ initializing_with_extension = true;
+ initializing_extension = ti->native_extension;
+ initializing_extension_instance = ti->native_extension->create_instance(ti->native_extension->create_instance_userdata);
+ }
return ti->creation_func();
}
@@ -534,7 +554,7 @@ bool ClassDB::can_instance(const StringName &p_class) {
return false;
}
#endif
- return (!ti->disabled && ti->creation_func != nullptr);
+ return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance));
}
void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) {
@@ -1310,6 +1330,24 @@ bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inhe
return false;
}
+void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method) {
+ ClassInfo *type = classes.getptr(p_class);
+ if (!type) {
+ ERR_FAIL_MSG("Couldn't bind custom method '" + p_method->get_name() + "' for instance '" + p_class + "'.");
+ }
+
+ if (type->method_map.has(p_method->get_name())) {
+ // overloading not supported
+ ERR_FAIL_MSG("Method already bound '" + p_class + "::" + p_method->get_name() + "'.");
+ }
+
+#ifdef DEBUG_METHODS_ENABLED
+ type->method_order.push_back(p_method->get_name());
+#endif
+
+ type->method_map[p_method->get_name()] = p_method;
+}
+
#ifdef DEBUG_METHODS_ENABLED
MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) {
StringName mdname = method_name.name;
@@ -1545,6 +1583,26 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
return var;
}
+void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
+ GLOBAL_LOCK_FUNCTION;
+
+ ERR_FAIL_COND_MSG(classes.has(p_extension->class_name), "Class already registered: " + String(p_extension->class_name));
+ ERR_FAIL_COND_MSG(classes.has(p_extension->parent_class_name), "Parent class name for extension class not found: " + String(p_extension->parent_class_name));
+
+ ClassInfo *parent = classes.getptr(p_extension->parent_class_name);
+
+ ClassInfo c;
+ c.api = p_extension->editor_class ? API_EDITOR_EXTENSION : API_EXTENSION;
+ c.native_extension = p_extension;
+ c.name = p_extension->class_name;
+ c.creation_func = parent->creation_func;
+ c.inherits = parent->name;
+ c.class_ptr = parent->class_ptr;
+ c.inherits_ptr = parent;
+
+ classes[p_extension->class_name] = c;
+}
+
RWLock ClassDB::lock;
void ClassDB::cleanup_defaults() {
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 6fd5748dbb..4355c9b0ea 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -97,6 +97,8 @@ public:
enum APIType {
API_CORE,
API_EDITOR,
+ API_EXTENSION,
+ API_EDITOR_EXTENSION,
API_NONE
};
@@ -115,6 +117,8 @@ public:
ClassInfo *inherits_ptr = nullptr;
void *class_ptr = nullptr;
+ ObjectNativeExtension *native_extension = nullptr;
+
HashMap<StringName, MethodBind *> method_map;
HashMap<StringName, int> constant_map;
HashMap<StringName, List<StringName>> enum_map;
@@ -199,6 +203,8 @@ public:
//nothing
}
+ static void register_extension_class(ObjectNativeExtension *p_extension);
+
template <class T>
static Object *_create_ptr_func() {
return T::create();
@@ -226,6 +232,7 @@ public:
static bool is_parent_class(const StringName &p_class, const StringName &p_inherits);
static bool can_instance(const StringName &p_class);
static Object *instance(const StringName &p_class);
+ static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, void **r_extension_instance);
static APIType get_api_type(const StringName &p_class);
static uint64_t get_api_hash(APIType p_api);
@@ -334,6 +341,8 @@ public:
return bind;
}
+ static void bind_method_custom(const StringName &p_class, MethodBind *p_method);
+
static void add_signal(StringName p_class, const MethodInfo &p_signal);
static bool has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance = false);
static bool get_signal(StringName p_class, StringName p_signal, MethodInfo *r_signal);
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 413f917518..799e63a512 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -385,6 +385,15 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
}
}
+ if (_extension && _extension->set) {
+ if (_extension->set(_extension_instance, &p_name, &p_value)) {
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return;
+ }
+ }
+
//try built-in setgetter
{
if (ClassDB::set_property(this, p_name, p_value, r_valid)) {
@@ -451,6 +460,15 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
}
}
+ if (_extension && _extension->get) {
+ if (_extension->get(_extension_instance, &p_name, &ret)) {
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return ret;
+ }
+ }
+
//try built-in setgetter
{
if (ClassDB::get_property(const_cast<Object *>(this), p_name, ret)) {
@@ -596,6 +614,17 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
_get_property_listv(p_list, p_reversed);
+ if (_extension && _extension->get_property_list) {
+ uint32_t pcount;
+ const ObjectNativeExtension::PInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount);
+ for (uint32_t i = 0; i < pcount; i++) {
+ p_list->push_back(PropertyInfo(Variant::Type(pinfo[i].type), pinfo[i].class_name, PropertyHint(pinfo[i].hint), pinfo[i].hint_string, pinfo[i].usage, pinfo[i].class_name));
+ }
+ if (_extension->free_property_list) {
+ _extension->free_property_list(_extension_instance, pinfo);
+ }
+ }
+
if (!is_class("Script")) { // can still be set, but this is for user-friendliness
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
@@ -740,7 +769,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a
r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
return Variant();
}
- if (Object::cast_to<Reference>(this)) {
+ if (Object::cast_to<RefCounted>(this)) {
r_error.argument = 0;
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference.");
@@ -761,6 +790,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a
Variant ret;
OBJ_DEBUG_LOCK
+
if (script_instance) {
ret = script_instance->call(p_method, p_args, p_argcount, r_error);
//force jumptable
@@ -778,6 +808,8 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a
}
}
+ //extension does not need this, because all methods are registered in MethodBind
+
MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
if (method) {
@@ -795,6 +827,10 @@ void Object::notification(int p_notification, bool p_reversed) {
if (script_instance) {
script_instance->notification(p_notification);
}
+
+ if (_extension && _extension->notification) {
+ _extension->notification(_extension_instance, p_notification);
+ }
}
String Object::to_string() {
@@ -805,6 +841,9 @@ String Object::to_string() {
return ret;
}
}
+ if (_extension && _extension->to_string) {
+ return _extension->to_string(_extension_instance);
+ }
return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
}
@@ -1345,7 +1384,7 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
if (!s) {
bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal) ||
(!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal));
- ERR_FAIL_COND_MSG(signal_is_valid, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. signal: '" + p_signal + "', callable: '" + p_callable + "'.");
+ ERR_FAIL_COND_MSG(signal_is_valid, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'.");
}
ERR_FAIL_COND_MSG(!s, vformat("Disconnecting nonexistent signal '%s' in %s.", p_signal, to_string()));
@@ -1751,6 +1790,8 @@ void Object::_construct_object(bool p_reference) {
_instance_id = ObjectDB::add_instance(this);
memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS);
+ ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance);
+
#ifdef DEBUG_ENABLED
_lock_index.init(1);
#endif
@@ -1770,6 +1811,12 @@ Object::~Object() {
}
script_instance = nullptr;
+ if (_extension && _extension->free_instance) {
+ _extension->free_instance(_extension->create_instance_userdata, _extension_instance);
+ _extension = nullptr;
+ _extension_instance = nullptr;
+ }
+
const StringName *S = nullptr;
if (_emitting) {
@@ -1853,7 +1900,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) {
object_slots = (ObjectSlot *)memrealloc(object_slots, sizeof(ObjectSlot) * new_slot_max);
for (uint32_t i = slot_max; i < new_slot_max; i++) {
object_slots[i].object = nullptr;
- object_slots[i].is_reference = false;
+ object_slots[i].is_ref_counted = false;
object_slots[i].next_free = i;
object_slots[i].validator = 0;
}
@@ -1866,7 +1913,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) {
ERR_FAIL_COND_V(object_slots[slot].object != nullptr, ObjectID());
}
object_slots[slot].object = p_object;
- object_slots[slot].is_reference = p_object->is_reference();
+ object_slots[slot].is_ref_counted = p_object->is_ref_counted();
validator_counter = (validator_counter + 1) & OBJECTDB_VALIDATOR_MASK;
if (unlikely(validator_counter == 0)) {
validator_counter = 1;
@@ -1877,7 +1924,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) {
id <<= OBJECTDB_SLOT_MAX_COUNT_BITS;
id |= uint64_t(slot);
- if (p_object->is_reference()) {
+ if (p_object->is_ref_counted()) {
id |= OBJECTDB_REFERENCE_BIT;
}
@@ -1915,7 +1962,7 @@ void ObjectDB::remove_instance(Object *p_object) {
object_slots[slot_count].next_free = slot;
//invalidate, so checks against it fail
object_slots[slot].validator = 0;
- object_slots[slot].is_reference = false;
+ object_slots[slot].is_ref_counted = false;
object_slots[slot].object = nullptr;
spin_lock.unlock();
@@ -1950,7 +1997,7 @@ void ObjectDB::cleanup() {
extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error));
}
- uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[i].is_reference ? OBJECTDB_REFERENCE_BIT : 0);
+ uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[i].is_ref_counted ? OBJECTDB_REFERENCE_BIT : 0);
print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + extra_info);
count--;
diff --git a/core/object/object.h b/core/object/object.h
index 448a33d3bc..37b2e61dfe 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -238,6 +238,50 @@ struct MethodInfo {
////else
//return nullptr;
+// API used to extend in GDNative and other C compatible compiled languages
+class MethodBind;
+
+struct ObjectNativeExtension {
+ ObjectNativeExtension *parent = nullptr;
+ StringName parent_class_name;
+ StringName class_name;
+ bool editor_class = false;
+ bool (*set)(void *instance, const void *name, const void *value) = nullptr;
+ bool (*get)(void *instance, const void *name, void *ret_variant) = nullptr;
+ struct PInfo {
+ uint32_t type;
+ const char *name;
+ const char *class_name;
+ uint32_t hint;
+ const char *hint_string;
+ uint32_t usage;
+ };
+ const PInfo *(*get_property_list)(void *instance, uint32_t *count) = nullptr;
+ void (*free_property_list)(void *instance, const PInfo *) = nullptr;
+
+ //call is not used, as all methods registered in ClassDB
+
+ void (*notification)(void *instance, int32_t what) = nullptr;
+ const char *(*to_string)(void *instance) = nullptr;
+
+ void (*reference)(void *instance) = nullptr;
+ void (*unreference)(void *instance) = nullptr;
+
+ _FORCE_INLINE_ bool is_class(const String &p_class) const {
+ const ObjectNativeExtension *e = this;
+ while (e) {
+ if (p_class == e->class_name.operator String()) {
+ return true;
+ }
+ e = e->parent;
+ }
+ return false;
+ }
+ void *create_instance_userdata = nullptr;
+ void *(*create_instance)(void *create_instance_userdata) = nullptr;
+ void (*free_instance)(void *create_instance_userdata, void *instance) = 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.
*/
@@ -262,9 +306,15 @@ private:
\
public: \
virtual String get_class() const override { \
+ if (_get_extension()) { \
+ return _get_extension()->class_name.operator String(); \
+ } \
return String(#m_class); \
} \
virtual const StringName *_get_class_namev() const override { \
+ if (_get_extension()) { \
+ return &_get_extension()->class_name; \
+ } \
if (!_class_name) { \
_class_name = get_class_static(); \
} \
@@ -297,7 +347,12 @@ public:
static String inherits_static() { \
return String(#m_inherits); \
} \
- virtual bool is_class(const String &p_class) const override { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \
+ virtual bool is_class(const String &p_class) const override { \
+ if (_get_extension() && _get_extension()->is_class(p_class)) { \
+ return true; \
+ } \
+ return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); \
+ } \
virtual bool is_class_ptr(void *p_ptr) const override { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \
\
static void get_valid_parents_static(List<String> *p_parents) { \
@@ -440,6 +495,9 @@ private:
friend bool predelete_handler(Object *);
friend void postinitialize_handler(Object *);
+ ObjectNativeExtension *_extension = nullptr;
+ void *_extension_instance = nullptr;
+
struct SignalData {
struct Slot {
int reference_count = 0;
@@ -487,7 +545,7 @@ private:
_FORCE_INLINE_ void _construct_object(bool p_reference);
- friend class Reference;
+ friend class RefCounted;
bool type_is_reference = false;
SafeNumeric<uint32_t> instance_binding_count;
void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS];
@@ -495,6 +553,8 @@ private:
Object(bool p_reference);
protected:
+ _ALWAYS_INLINE_ const ObjectNativeExtension *_get_extension() const { return _extension; }
+ _ALWAYS_INLINE_ void *_get_extension_instance() const { return _extension_instance; }
virtual void _initialize_classv() { initialize_class(); }
virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; };
virtual bool _getv(const StringName &p_name, Variant &r_property) const { return false; };
@@ -610,13 +670,25 @@ public:
static String get_parent_class_static() { return String(); }
static String get_category_static() { return String(); }
- virtual String get_class() const { return "Object"; }
+ virtual String get_class() const {
+ if (_extension)
+ return _extension->class_name.operator String();
+ return "Object";
+ }
virtual String get_save_class() const { return get_class(); } //class stored when saving
- virtual bool is_class(const String &p_class) const { return (p_class == "Object"); }
+ virtual bool is_class(const String &p_class) const {
+ if (_extension && _extension->is_class(p_class)) {
+ return true;
+ }
+ return (p_class == "Object");
+ }
virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; }
_FORCE_INLINE_ const StringName &get_class_name() const {
+ if (_extension) {
+ return _extension->class_name;
+ }
if (!_class_ptr) {
return *_get_class_namev();
} else {
@@ -723,7 +795,7 @@ public:
void clear_internal_resource_paths();
- _ALWAYS_INLINE_ bool is_reference() const { return type_is_reference; }
+ _ALWAYS_INLINE_ bool is_ref_counted() const { return type_is_reference; }
Object();
virtual ~Object();
@@ -743,7 +815,7 @@ class ObjectDB {
struct ObjectSlot { //128 bits per slot
uint64_t validator : OBJECTDB_VALIDATOR_BITS;
uint64_t next_free : OBJECTDB_SLOT_MAX_COUNT_BITS;
- uint64_t is_reference : 1;
+ uint64_t is_ref_counted : 1;
Object *object;
};
diff --git a/core/object/object_id.h b/core/object/object_id.h
index 7f2496ad48..0666ec0855 100644
--- a/core/object/object_id.h
+++ b/core/object/object_id.h
@@ -42,7 +42,7 @@ class ObjectID {
uint64_t id = 0;
public:
- _ALWAYS_INLINE_ bool is_reference() const { return (id & (uint64_t(1) << 63)) != 0; }
+ _ALWAYS_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
_ALWAYS_INLINE_ bool is_valid() const { return id != 0; }
_ALWAYS_INLINE_ bool is_null() const { return id == 0; }
_ALWAYS_INLINE_ operator uint64_t() const { return id; }
diff --git a/core/object/reference.cpp b/core/object/ref_counted.cpp
index 22e4e8a336..9862624972 100644
--- a/core/object/reference.cpp
+++ b/core/object/ref_counted.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* reference.cpp */
+/* ref_counted.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "reference.h"
+#include "ref_counted.h"
#include "core/object/script_language.h"
-bool Reference::init_ref() {
+bool RefCounted::init_ref() {
if (reference()) {
if (!is_referenced() && refcount_init.unref()) {
unreference(); // first referencing is already 1, so compensate for the ref above
@@ -44,17 +44,17 @@ bool Reference::init_ref() {
}
}
-void Reference::_bind_methods() {
- ClassDB::bind_method(D_METHOD("init_ref"), &Reference::init_ref);
- ClassDB::bind_method(D_METHOD("reference"), &Reference::reference);
- ClassDB::bind_method(D_METHOD("unreference"), &Reference::unreference);
+void RefCounted::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("init_ref"), &RefCounted::init_ref);
+ ClassDB::bind_method(D_METHOD("reference"), &RefCounted::reference);
+ ClassDB::bind_method(D_METHOD("unreference"), &RefCounted::unreference);
}
-int Reference::reference_get_count() const {
+int RefCounted::reference_get_count() const {
return refcount.get();
}
-bool Reference::reference() {
+bool RefCounted::reference() {
uint32_t rc_val = refcount.refval();
bool success = rc_val != 0;
@@ -62,6 +62,9 @@ bool Reference::reference() {
if (get_script_instance()) {
get_script_instance()->refcount_incremented();
}
+ if (_get_extension() && _get_extension()->reference) {
+ _get_extension()->reference(_get_extension_instance());
+ }
if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
if (_script_instance_bindings[i]) {
@@ -74,7 +77,7 @@ bool Reference::reference() {
return success;
}
-bool Reference::unreference() {
+bool RefCounted::unreference() {
uint32_t rc_val = refcount.unrefval();
bool die = rc_val == 0;
@@ -83,6 +86,9 @@ bool Reference::unreference() {
bool script_ret = get_script_instance()->refcount_decremented();
die = die && script_ret;
}
+ if (_get_extension() && _get_extension()->unreference) {
+ _get_extension()->unreference(_get_extension_instance());
+ }
if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
if (_script_instance_bindings[i]) {
@@ -96,7 +102,7 @@ bool Reference::unreference() {
return die;
}
-Reference::Reference() :
+RefCounted::RefCounted() :
Object(true) {
refcount.init();
refcount_init.init();
@@ -111,7 +117,7 @@ Variant WeakRef::get_ref() const {
if (!obj) {
return Variant();
}
- Reference *r = cast_to<Reference>(obj);
+ RefCounted *r = cast_to<RefCounted>(obj);
if (r) {
return REF(r);
}
diff --git a/core/object/reference.h b/core/object/ref_counted.h
index d02cb12069..3dd7cc456b 100644
--- a/core/object/reference.h
+++ b/core/object/ref_counted.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* reference.h */
+/* ref_counted.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,14 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef REFERENCE_H
-#define REFERENCE_H
+#ifndef REF_COUNTED_H
+#define REF_COUNTED_H
#include "core/object/class_db.h"
#include "core/templates/safe_refcount.h"
-class Reference : public Object {
- GDCLASS(Reference, Object);
+class RefCounted : public Object {
+ GDCLASS(RefCounted, Object);
SafeRefCount refcount;
SafeRefCount refcount_init;
@@ -49,8 +49,8 @@ public:
bool unreference();
int reference_get_count() const;
- Reference();
- ~Reference() {}
+ RefCounted();
+ ~RefCounted() {}
};
template <class T>
@@ -78,7 +78,7 @@ class Ref {
}
}
- //virtual Reference * get_reference() const { return reference; }
+ //virtual RefCounted * get_reference() const { return reference; }
public:
_FORCE_INLINE_ bool operator==(const T *p_ptr) const {
return reference == p_ptr;
@@ -130,7 +130,7 @@ public:
template <class T_Other>
void operator=(const Ref<T_Other> &p_from) {
- Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
+ RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) {
unref();
return;
@@ -179,7 +179,7 @@ public:
template <class T_Other>
Ref(const Ref<T_Other> &p_from) {
- Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
+ RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) {
unref();
return;
@@ -234,10 +234,10 @@ public:
}
};
-typedef Ref<Reference> REF;
+typedef Ref<RefCounted> REF;
-class WeakRef : public Reference {
- GDCLASS(WeakRef, Reference);
+class WeakRef : public RefCounted {
+ GDCLASS(WeakRef, RefCounted);
ObjectID ref;
@@ -259,7 +259,7 @@ struct PtrToArg<Ref<T>> {
}
_FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) {
- *(Ref<Reference> *)p_ptr = p_val;
+ *(Ref<RefCounted> *)p_ptr = p_val;
}
};
@@ -294,4 +294,4 @@ struct GetTypeInfo<const Ref<T> &> {
#endif // DEBUG_METHODS_ENABLED
-#endif // REFERENCE_H
+#endif // REF_COUNTED_H
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 42fb0a0caf..196f7a1876 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -353,10 +353,10 @@ void ScriptLanguage::get_core_type_words(List<String> *p_core_type_words) const
p_core_type_words->push_back("Vector3i");
p_core_type_words->push_back("Transform2D");
p_core_type_words->push_back("Plane");
- p_core_type_words->push_back("Quat");
+ p_core_type_words->push_back("Quaternion");
p_core_type_words->push_back("AABB");
p_core_type_words->push_back("Basis");
- p_core_type_words->push_back("Transform");
+ p_core_type_words->push_back("Transform3D");
p_core_type_words->push_back("Color");
p_core_type_words->push_back("StringName");
p_core_type_words->push_back("NodePath");
@@ -585,14 +585,6 @@ Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_nam
return Variant();
}
-uint16_t PlaceHolderScriptInstance::get_rpc_method_id(const StringName &p_method) const {
- return UINT16_MAX;
-}
-
-uint16_t PlaceHolderScriptInstance::get_rset_property_id(const StringName &p_method) const {
- return UINT16_MAX;
-}
-
PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) :
owner(p_owner),
language(p_language),
diff --git a/core/object/script_language.h b/core/object/script_language.h
index f9898ccd0c..a22e91870e 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -41,21 +41,6 @@ class ScriptLanguage;
typedef void (*ScriptEditRequestFunction)(const String &p_path);
-struct ScriptNetData {
- StringName name;
- MultiplayerAPI::RPCMode mode;
- bool operator==(ScriptNetData const &p_other) const {
- return name == p_other.name;
- }
-};
-
-struct SortNetData {
- StringName::AlphCompare compare;
- bool operator()(const ScriptNetData &p_a, const ScriptNetData &p_b) const {
- return compare(p_a.name, p_b.name);
- }
-};
-
class ScriptServer {
enum {
MAX_LANGUAGES = 16
@@ -174,17 +159,7 @@ public:
virtual bool is_placeholder_fallback_enabled() const { return false; }
- virtual Vector<ScriptNetData> get_rpc_methods() const = 0;
- virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0;
- virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const = 0;
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const = 0;
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0;
-
- virtual Vector<ScriptNetData> get_rset_properties() const = 0;
- virtual uint16_t get_rset_property_id(const StringName &p_property) const = 0;
- virtual StringName get_rset_property(const uint16_t p_rset_property_id) const = 0;
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const = 0;
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0;
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0;
Script() {}
};
@@ -225,23 +200,15 @@ public:
virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid);
virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid);
- virtual Vector<ScriptNetData> get_rpc_methods() const = 0;
- virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0;
- virtual StringName get_rpc_method(uint16_t p_id) const = 0;
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const = 0;
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0;
-
- virtual Vector<ScriptNetData> get_rset_properties() const = 0;
- virtual uint16_t get_rset_property_id(const StringName &p_variable) const = 0;
- virtual StringName get_rset_property(uint16_t p_id) const = 0;
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const = 0;
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0;
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0;
virtual ScriptLanguage *get_language() = 0;
virtual ~ScriptInstance();
};
struct ScriptCodeCompletionOption {
+ /* Keep enum in Sync with: */
+ /* /scene/gui/code_edit.h - CodeEdit::CodeCompletionKind */
enum Kind {
KIND_CLASS,
KIND_FUNCTION,
@@ -303,6 +270,7 @@ public:
void get_core_type_words(List<String> *p_core_type_words) const;
virtual void get_reserved_words(List<String> *p_words) const = 0;
+ virtual bool is_control_flow_keyword(String p_string) const = 0;
virtual void get_comment_delimiters(List<String> *p_delimiters) const = 0;
virtual void get_string_delimiters(List<String> *p_delimiters) const = 0;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0;
@@ -444,17 +412,7 @@ public:
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;
- virtual StringName get_rpc_method(uint16_t p_id) const { return StringName(); }
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
-
- virtual Vector<ScriptNetData> get_rset_properties() const { return Vector<ScriptNetData>(); }
- virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
- virtual StringName get_rset_property(uint16_t p_id) const { return StringName(); }
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const { return MultiplayerAPI::RPC_MODE_DISABLED; }
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const { return Vector<MultiplayerAPI::RPCConfig>(); }
PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner);
~PlaceHolderScriptInstance();
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index e8735e335c..96c96c1efb 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -122,8 +122,8 @@ void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIA
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
do_op.object = p_object->get_instance_id();
- if (Object::cast_to<Reference>(p_object)) {
- do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
+ if (Object::cast_to<RefCounted>(p_object)) {
+ do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
}
do_op.type = Operation::TYPE_METHOD;
@@ -148,8 +148,8 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR
Operation undo_op;
undo_op.object = p_object->get_instance_id();
- if (Object::cast_to<Reference>(p_object)) {
- undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
+ if (Object::cast_to<RefCounted>(p_object)) {
+ undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
}
undo_op.type = Operation::TYPE_METHOD;
@@ -167,8 +167,8 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
do_op.object = p_object->get_instance_id();
- if (Object::cast_to<Reference>(p_object)) {
- do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
+ if (Object::cast_to<RefCounted>(p_object)) {
+ do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
}
do_op.type = Operation::TYPE_PROPERTY;
@@ -189,8 +189,8 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
Operation undo_op;
undo_op.object = p_object->get_instance_id();
- if (Object::cast_to<Reference>(p_object)) {
- undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
+ if (Object::cast_to<RefCounted>(p_object)) {
+ undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
}
undo_op.type = Operation::TYPE_PROPERTY;
@@ -205,8 +205,8 @@ void UndoRedo::add_do_reference(Object *p_object) {
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
do_op.object = p_object->get_instance_id();
- if (Object::cast_to<Reference>(p_object)) {
- do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
+ if (Object::cast_to<RefCounted>(p_object)) {
+ do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
}
do_op.type = Operation::TYPE_REFERENCE;
@@ -225,8 +225,8 @@ void UndoRedo::add_undo_reference(Object *p_object) {
Operation undo_op;
undo_op.object = p_object->get_instance_id();
- if (Object::cast_to<Reference>(p_object)) {
- undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
+ if (Object::cast_to<RefCounted>(p_object)) {
+ undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
}
undo_op.type = Operation::TYPE_REFERENCE;
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index a08ca7792f..8f009830e3 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -32,7 +32,7 @@
#define UNDO_REDO_H
#include "core/object/class_db.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
class UndoRedo : public Object {
GDCLASS(UndoRedo, Object);
@@ -61,7 +61,7 @@ private:
};
Type type;
- Ref<Reference> ref;
+ Ref<RefCounted> ref;
ObjectID object;
StringName name;
Variant args[VARIANT_ARG_MAX];
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index 4b2cafd8fe..4c5f0b5220 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -60,7 +60,7 @@ static const _KeyCodeText _keycodes[] = {
{KEY_PAGEUP ,"PageUp"},
{KEY_PAGEDOWN ,"PageDown"},
{KEY_SHIFT ,"Shift"},
- {KEY_CONTROL ,"Control"},
+ {KEY_CTRL ,"Ctrl"},
#ifdef OSX_ENABLED
{KEY_META ,"Command"},
#else
@@ -314,7 +314,7 @@ bool keycode_has_unicode(uint32_t p_keycode) {
case KEY_PAGEUP:
case KEY_PAGEDOWN:
case KEY_SHIFT:
- case KEY_CONTROL:
+ case KEY_CTRL:
case KEY_META:
case KEY_ALT:
case KEY_CAPSLOCK:
@@ -401,7 +401,7 @@ String keycode_get_string(uint32_t p_code) {
codestr += "+";
}
if (p_code & KEY_MASK_CTRL) {
- codestr += find_keycode_name(KEY_CONTROL);
+ codestr += find_keycode_name(KEY_CTRL);
codestr += "+";
}
if (p_code & KEY_MASK_META) {
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index f6fe5fc070..33f9213c4e 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -68,7 +68,7 @@ enum Key {
KEY_PAGEUP = SPKEY | 0x13,
KEY_PAGEDOWN = SPKEY | 0x14,
KEY_SHIFT = SPKEY | 0x15,
- KEY_CONTROL = SPKEY | 0x16,
+ KEY_CTRL = SPKEY | 0x16,
KEY_META = SPKEY | 0x17,
KEY_ALT = SPKEY | 0x18,
KEY_CAPSLOCK = SPKEY | 0x19,
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index 25a09fe98f..34e944709b 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -32,7 +32,7 @@
#define MAIN_LOOP_H
#include "core/input/input_event.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
class MainLoop : public Object {
diff --git a/core/os/memory.cpp b/core/os/memory.cpp
index 5910cb0e7b..a756c1d5dd 100644
--- a/core/os/memory.cpp
+++ b/core/os/memory.cpp
@@ -31,7 +31,6 @@
#include "memory.h"
#include "core/error/error_macros.h"
-#include "core/os/copymem.h"
#include "core/templates/safe_refcount.h"
#include <stdio.h>
diff --git a/core/os/os.cpp b/core/os/os.cpp
index ca1b798e11..535eee4797 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -32,8 +32,8 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/os/midi_driver.h"
#include "core/version_generated.gen.h"
#include "servers/audio_server.h"
@@ -47,37 +47,8 @@ OS *OS::get_singleton() {
return singleton;
}
-uint32_t OS::get_ticks_msec() const {
- return get_ticks_usec() / 1000;
-}
-
-String OS::get_iso_date_time(bool local) const {
- OS::Date date = get_date(local);
- OS::Time time = get_time(local);
-
- String timezone;
- if (!local) {
- TimeZoneInfo zone = get_time_zone_info();
- if (zone.bias >= 0) {
- timezone = "+";
- }
- timezone = timezone + itos(zone.bias / 60).pad_zeros(2) + itos(zone.bias % 60).pad_zeros(2);
- } else {
- timezone = "Z";
- }
-
- return itos(date.year).pad_zeros(2) +
- "-" +
- itos(date.month).pad_zeros(2) +
- "-" +
- itos(date.day).pad_zeros(2) +
- "T" +
- itos(time.hour).pad_zeros(2) +
- ":" +
- itos(time.min).pad_zeros(2) +
- ":" +
- itos(time.sec).pad_zeros(2) +
- timezone;
+uint64_t OS::get_ticks_msec() const {
+ return get_ticks_usec() / 1000ULL;
}
double OS::get_unix_time() const {
@@ -310,6 +281,11 @@ String OS::get_user_data_dir() const {
return ".";
}
+// Android OS path to app's external data storage
+String OS::get_external_data_dir() const {
+ return get_user_data_dir();
+};
+
// Absolute path to res://
String OS::get_resource_dir() const {
return ProjectSettings::get_singleton()->get_resource_path();
diff --git a/core/os/os.h b/core/os/os.h
index 7198607237..444f67431f 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -158,17 +158,17 @@ public:
virtual void yield();
- enum Weekday {
- DAY_SUNDAY,
- DAY_MONDAY,
- DAY_TUESDAY,
- DAY_WEDNESDAY,
- DAY_THURSDAY,
- DAY_FRIDAY,
- DAY_SATURDAY
+ enum Weekday : uint8_t {
+ WEEKDAY_SUNDAY,
+ WEEKDAY_MONDAY,
+ WEEKDAY_TUESDAY,
+ WEEKDAY_WEDNESDAY,
+ WEEKDAY_THURSDAY,
+ WEEKDAY_FRIDAY,
+ WEEKDAY_SATURDAY,
};
- enum Month {
+ enum Month : uint8_t {
/// Start at 1 to follow Windows SYSTEMTIME structure
/// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
MONTH_JANUARY = 1,
@@ -182,21 +182,21 @@ public:
MONTH_SEPTEMBER,
MONTH_OCTOBER,
MONTH_NOVEMBER,
- MONTH_DECEMBER
+ MONTH_DECEMBER,
};
struct Date {
- int year;
+ int64_t year;
Month month;
- int day;
+ uint8_t day;
Weekday weekday;
bool dst;
};
struct Time {
- int hour;
- int min;
- int sec;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
};
struct TimeZoneInfo {
@@ -207,14 +207,13 @@ public:
virtual Date get_date(bool local = false) const = 0;
virtual Time get_time(bool local = false) const = 0;
virtual TimeZoneInfo get_time_zone_info() const = 0;
- virtual String get_iso_date_time(bool local = false) const;
virtual double get_unix_time() const;
virtual void delay_usec(uint32_t p_usec) const = 0;
virtual void add_frame_delay(bool p_can_draw);
virtual uint64_t get_ticks_usec() const = 0;
- uint32_t get_ticks_msec() const;
+ uint64_t get_ticks_msec() const;
virtual bool is_userfs_persistent() const { return true; }
@@ -252,6 +251,7 @@ public:
virtual String get_bundle_resource_dir() const;
virtual String get_user_data_dir() const;
+ virtual String get_external_data_dir() const;
virtual String get_resource_dir() const;
enum SystemDir {
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index 9be3a62e2f..74e9c24e04 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -31,7 +31,6 @@
#include "pool_allocator.h"
#include "core/error/error_macros.h"
-#include "core/os/copymem.h"
#include "core/os/memory.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -42,7 +41,7 @@
do { \
void *_dst = &((unsigned char *)pool)[m_to_pos]; \
void *_src = &((unsigned char *)pool)[(m_entry).pos]; \
- movemem(_dst, _src, aligned((m_entry).len)); \
+ memmove(_dst, _src, aligned((m_entry).len)); \
(m_entry).pos = m_to_pos; \
} while (0);
diff --git a/core/os/time.cpp b/core/os/time.cpp
new file mode 100644
index 0000000000..a185029969
--- /dev/null
+++ b/core/os/time.cpp
@@ -0,0 +1,433 @@
+/*************************************************************************/
+/* time.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "time.h"
+
+#include "core/os/os.h"
+
+#define UNIX_EPOCH_YEAR_AD 1970 // 1970
+#define SECONDS_PER_DAY (24 * 60 * 60) // 86400
+#define IS_LEAP_YEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
+#define YEAR_SIZE(year) (IS_LEAP_YEAR(year) ? 366 : 365)
+
+#define YEAR_KEY "year"
+#define MONTH_KEY "month"
+#define DAY_KEY "day"
+#define WEEKDAY_KEY "weekday"
+#define HOUR_KEY "hour"
+#define MINUTE_KEY "minute"
+#define SECOND_KEY "second"
+#define DST_KEY "dst"
+
+// Table of number of days in each month (for regular year and leap year).
+static const uint8_t MONTH_DAYS_TABLE[2][12] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+VARIANT_ENUM_CAST(Time::Month);
+VARIANT_ENUM_CAST(Time::Weekday);
+
+#define UNIX_TIME_TO_HMS \
+ uint8_t hour, minute, second; \
+ { \
+ /* The time of the day (in seconds since start of day). */ \
+ uint32_t day_clock = Math::posmod(p_unix_time_val, SECONDS_PER_DAY); \
+ /* On x86 these 4 lines can be optimized to only 2 divisions. */ \
+ second = day_clock % 60; \
+ day_clock /= 60; \
+ minute = day_clock % 60; \
+ hour = day_clock / 60; \
+ }
+
+#define UNIX_TIME_TO_YMD \
+ int64_t year; \
+ Month month; \
+ uint8_t day; \
+ /* The day number since Unix epoch (0-index). Days before 1970 are negative. */ \
+ int64_t day_number = Math::floor(p_unix_time_val / (double)SECONDS_PER_DAY); \
+ { \
+ int64_t day_number_copy = day_number; \
+ year = UNIX_EPOCH_YEAR_AD; \
+ uint8_t month_zero_index = 0; \
+ while (day_number_copy >= YEAR_SIZE(year)) { \
+ day_number_copy -= YEAR_SIZE(year); \
+ year++; \
+ } \
+ while (day_number_copy < 0) { \
+ year--; \
+ day_number_copy += YEAR_SIZE(year); \
+ } \
+ /* After the above, day_number now represents the day of the year (0-index). */ \
+ while (day_number_copy >= MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month_zero_index]) { \
+ day_number_copy -= MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month_zero_index]; \
+ month_zero_index++; \
+ } \
+ /* After the above, day_number now represents the day of the month (0-index). */ \
+ month = (Month)(month_zero_index + 1); \
+ day = day_number_copy + 1; \
+ }
+
+#define VALIDATE_YMDHMS \
+ ERR_FAIL_COND_V_MSG(month == 0, 0, "Invalid month value of: " + itos(month) + ", months are 1-indexed and cannot be 0. See the Time.Month enum for valid values."); \
+ ERR_FAIL_COND_V_MSG(month > 12, 0, "Invalid month value of: " + itos(month) + ". See the Time.Month enum for valid values."); \
+ ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); \
+ ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); \
+ ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + " (leap seconds are not supported)."); \
+ /* Do this check after month is tested as valid. */ \
+ ERR_FAIL_COND_V_MSG(day == 0, 0, "Invalid day value of: " + itos(month) + ", days are 1-indexed and cannot be 0."); \
+ uint8_t days_in_this_month = MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month - 1]; \
+ ERR_FAIL_COND_V_MSG(day > days_in_this_month, 0, "Invalid day value of: " + itos(day) + " which is larger than the maximum for this month, " + itos(days_in_this_month) + ".");
+
+#define YMD_TO_DAY_NUMBER \
+ /* The day number since Unix epoch (0-index). Days before 1970 are negative. */ \
+ int64_t day_number = day - 1; \
+ /* Add the days in the months to day_number. */ \
+ for (int i = 0; i < month - 1; i++) { \
+ day_number += MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][i]; \
+ } \
+ /* Add the days in the years to day_number. */ \
+ if (year >= UNIX_EPOCH_YEAR_AD) { \
+ for (int64_t iyear = UNIX_EPOCH_YEAR_AD; iyear < year; iyear++) { \
+ day_number += YEAR_SIZE(iyear); \
+ } \
+ } else { \
+ for (int64_t iyear = UNIX_EPOCH_YEAR_AD - 1; iyear >= year; iyear--) { \
+ day_number -= YEAR_SIZE(iyear); \
+ } \
+ }
+
+#define PARSE_ISO8601_STRING \
+ int64_t year = UNIX_EPOCH_YEAR_AD; \
+ Month month = MONTH_JANUARY; \
+ uint8_t day = 1; \
+ uint8_t hour = 0; \
+ uint8_t minute = 0; \
+ uint8_t second = 0; \
+ { \
+ bool has_date = false, has_time = false; \
+ String date, time; \
+ if (p_datetime.find_char('T') > 0) { \
+ has_date = has_time = true; \
+ PackedStringArray array = p_datetime.split("T"); \
+ date = array[0]; \
+ time = array[1]; \
+ } else if (p_datetime.find_char(' ') > 0) { \
+ has_date = has_time = true; \
+ PackedStringArray array = p_datetime.split(" "); \
+ date = array[0]; \
+ time = array[1]; \
+ } else if (p_datetime.find_char('-', 1) > 0) { \
+ has_date = true; \
+ date = p_datetime; \
+ } else if (p_datetime.find_char(':') > 0) { \
+ has_time = true; \
+ time = p_datetime; \
+ } \
+ /* Set the variables from the contents of the string. */ \
+ if (has_date) { \
+ PackedInt32Array array = date.split_ints("-", false); \
+ year = array[0]; \
+ month = (Month)array[1]; \
+ day = array[2]; \
+ /* Handle negative years. */ \
+ if (p_datetime.find_char('-') == 0) { \
+ year *= -1; \
+ } \
+ } \
+ if (has_time) { \
+ PackedInt32Array array = time.split_ints(":", false); \
+ hour = array[0]; \
+ minute = array[1]; \
+ second = array[2]; \
+ } \
+ }
+
+#define EXTRACT_FROM_DICTIONARY \
+ /* Get all time values from the dictionary. If it doesn't exist, set the */ \
+ /* values to the default values for Unix epoch (1970-01-01 00:00:00). */ \
+ int64_t year = p_datetime.has(YEAR_KEY) ? int64_t(p_datetime[YEAR_KEY]) : UNIX_EPOCH_YEAR_AD; \
+ Month month = Month((p_datetime.has(MONTH_KEY)) ? uint8_t(p_datetime[MONTH_KEY]) : 1); \
+ uint8_t day = p_datetime.has(DAY_KEY) ? uint8_t(p_datetime[DAY_KEY]) : 1; \
+ uint8_t hour = p_datetime.has(HOUR_KEY) ? uint8_t(p_datetime[HOUR_KEY]) : 0; \
+ uint8_t minute = p_datetime.has(MINUTE_KEY) ? uint8_t(p_datetime[MINUTE_KEY]) : 0; \
+ uint8_t second = p_datetime.has(SECOND_KEY) ? uint8_t(p_datetime[SECOND_KEY]) : 0;
+
+Time *Time::singleton = nullptr;
+
+Time *Time::get_singleton() {
+ if (!singleton) {
+ memnew(Time);
+ }
+ return singleton;
+}
+
+Dictionary Time::get_datetime_dict_from_unix_time(int64_t p_unix_time_val) const {
+ UNIX_TIME_TO_HMS
+ UNIX_TIME_TO_YMD
+ Dictionary datetime;
+ datetime[YEAR_KEY] = year;
+ datetime[MONTH_KEY] = (uint8_t)month;
+ datetime[DAY_KEY] = day;
+ // Unix epoch was a Thursday (day 0 aka 1970-01-01).
+ datetime[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7);
+ datetime[HOUR_KEY] = hour;
+ datetime[MINUTE_KEY] = minute;
+ datetime[SECOND_KEY] = second;
+
+ return datetime;
+}
+
+Dictionary Time::get_date_dict_from_unix_time(int64_t p_unix_time_val) const {
+ UNIX_TIME_TO_YMD
+ Dictionary datetime;
+ datetime[YEAR_KEY] = year;
+ datetime[MONTH_KEY] = (uint8_t)month;
+ datetime[DAY_KEY] = day;
+ // Unix epoch was a Thursday (day 0 aka 1970-01-01).
+ datetime[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7);
+
+ return datetime;
+}
+
+Dictionary Time::get_time_dict_from_unix_time(int64_t p_unix_time_val) const {
+ UNIX_TIME_TO_HMS
+ Dictionary datetime;
+ datetime[HOUR_KEY] = hour;
+ datetime[MINUTE_KEY] = minute;
+ datetime[SECOND_KEY] = second;
+
+ return datetime;
+}
+
+String Time::get_datetime_string_from_unix_time(int64_t p_unix_time_val, bool p_use_space) const {
+ UNIX_TIME_TO_HMS
+ UNIX_TIME_TO_YMD
+ // vformat only supports up to 6 arguments, so we need to split this up into 2 parts.
+ String timestamp = vformat("%04d-%02d-%02d", year, (uint8_t)month, day);
+ if (p_use_space) {
+ timestamp = vformat("%s %02d:%02d:%02d", timestamp, hour, minute, second);
+ } else {
+ timestamp = vformat("%sT%02d:%02d:%02d", timestamp, hour, minute, second);
+ }
+
+ return timestamp;
+}
+
+String Time::get_date_string_from_unix_time(int64_t p_unix_time_val) const {
+ UNIX_TIME_TO_YMD
+ // Android is picky about the types passed to make Variant, so we need a cast.
+ return vformat("%04d-%02d-%02d", year, (uint8_t)month, day);
+}
+
+String Time::get_time_string_from_unix_time(int64_t p_unix_time_val) const {
+ UNIX_TIME_TO_HMS
+ return vformat("%02d:%02d:%02d", hour, minute, second);
+}
+
+Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday) const {
+ PARSE_ISO8601_STRING
+ Dictionary dict;
+ dict[YEAR_KEY] = year;
+ dict[MONTH_KEY] = (uint8_t)month;
+ dict[DAY_KEY] = day;
+ if (p_weekday) {
+ YMD_TO_DAY_NUMBER
+ // Unix epoch was a Thursday (day 0 aka 1970-01-01).
+ dict[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7);
+ }
+ dict[HOUR_KEY] = hour;
+ dict[MINUTE_KEY] = minute;
+ dict[SECOND_KEY] = second;
+
+ return dict;
+}
+
+String Time::get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space) const {
+ ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), "", "Invalid datetime Dictionary: Dictionary is empty.");
+ EXTRACT_FROM_DICTIONARY
+ // vformat only supports up to 6 arguments, so we need to split this up into 2 parts.
+ String timestamp = vformat("%04d-%02d-%02d", year, (uint8_t)month, day);
+ if (p_use_space) {
+ timestamp = vformat("%s %02d:%02d:%02d", timestamp, hour, minute, second);
+ } else {
+ timestamp = vformat("%sT%02d:%02d:%02d", timestamp, hour, minute, second);
+ }
+ return timestamp;
+}
+
+int64_t Time::get_unix_time_from_datetime_dict(Dictionary p_datetime) const {
+ ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty");
+ EXTRACT_FROM_DICTIONARY
+ VALIDATE_YMDHMS
+ YMD_TO_DAY_NUMBER
+ return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second;
+}
+
+int64_t Time::get_unix_time_from_datetime_string(String p_datetime) const {
+ PARSE_ISO8601_STRING
+ VALIDATE_YMDHMS
+ YMD_TO_DAY_NUMBER
+ return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second;
+}
+
+Dictionary Time::get_datetime_dict_from_system(bool p_utc) const {
+ OS::Date date = OS::get_singleton()->get_date(p_utc);
+ OS::Time time = OS::get_singleton()->get_time(p_utc);
+ Dictionary datetime;
+ datetime[YEAR_KEY] = date.year;
+ datetime[MONTH_KEY] = (uint8_t)date.month;
+ datetime[DAY_KEY] = date.day;
+ datetime[WEEKDAY_KEY] = (uint8_t)date.weekday;
+ datetime[DST_KEY] = date.dst;
+ datetime[HOUR_KEY] = time.hour;
+ datetime[MINUTE_KEY] = time.minute;
+ datetime[SECOND_KEY] = time.second;
+ return datetime;
+}
+
+Dictionary Time::get_date_dict_from_system(bool p_utc) const {
+ OS::Date date = OS::get_singleton()->get_date(p_utc);
+ Dictionary date_dictionary;
+ date_dictionary[YEAR_KEY] = date.year;
+ date_dictionary[MONTH_KEY] = (uint8_t)date.month;
+ date_dictionary[DAY_KEY] = date.day;
+ date_dictionary[WEEKDAY_KEY] = (uint8_t)date.weekday;
+ date_dictionary[DST_KEY] = date.dst;
+ return date_dictionary;
+}
+
+Dictionary Time::get_time_dict_from_system(bool p_utc) const {
+ OS::Time time = OS::get_singleton()->get_time(p_utc);
+ Dictionary time_dictionary;
+ time_dictionary[HOUR_KEY] = time.hour;
+ time_dictionary[MINUTE_KEY] = time.minute;
+ time_dictionary[SECOND_KEY] = time.second;
+ return time_dictionary;
+}
+
+String Time::get_datetime_string_from_system(bool p_utc, bool p_use_space) const {
+ OS::Date date = OS::get_singleton()->get_date(p_utc);
+ OS::Time time = OS::get_singleton()->get_time(p_utc);
+ // vformat only supports up to 6 arguments, so we need to split this up into 2 parts.
+ String timestamp = vformat("%04d-%02d-%02d", date.year, (uint8_t)date.month, date.day);
+ if (p_use_space) {
+ timestamp = vformat("%s %02d:%02d:%02d", timestamp, time.hour, time.minute, time.second);
+ } else {
+ timestamp = vformat("%sT%02d:%02d:%02d", timestamp, time.hour, time.minute, time.second);
+ }
+
+ return timestamp;
+}
+
+String Time::get_date_string_from_system(bool p_utc) const {
+ OS::Date date = OS::get_singleton()->get_date(p_utc);
+ // Android is picky about the types passed to make Variant, so we need a cast.
+ return vformat("%04d-%02d-%02d", date.year, (uint8_t)date.month, date.day);
+}
+
+String Time::get_time_string_from_system(bool p_utc) const {
+ OS::Time time = OS::get_singleton()->get_time(p_utc);
+ return vformat("%02d:%02d:%02d", time.hour, time.minute, time.second);
+}
+
+Dictionary Time::get_time_zone_from_system() const {
+ OS::TimeZoneInfo info = OS::get_singleton()->get_time_zone_info();
+ Dictionary timezone;
+ timezone["bias"] = info.bias;
+ timezone["name"] = info.name;
+ return timezone;
+}
+
+double Time::get_unix_time_from_system() const {
+ return OS::get_singleton()->get_unix_time();
+}
+
+uint64_t Time::get_ticks_msec() const {
+ return OS::get_singleton()->get_ticks_msec();
+}
+
+uint64_t Time::get_ticks_usec() const {
+ return OS::get_singleton()->get_ticks_usec();
+}
+
+void Time::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_datetime_dict_from_unix_time", "unix_time_val"), &Time::get_datetime_dict_from_unix_time);
+ ClassDB::bind_method(D_METHOD("get_date_dict_from_unix_time", "unix_time_val"), &Time::get_date_dict_from_unix_time);
+ ClassDB::bind_method(D_METHOD("get_time_dict_from_unix_time", "unix_time_val"), &Time::get_time_dict_from_unix_time);
+ ClassDB::bind_method(D_METHOD("get_datetime_string_from_unix_time", "unix_time_val", "use_space"), &Time::get_datetime_string_from_unix_time, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_date_string_from_unix_time", "unix_time_val"), &Time::get_date_string_from_unix_time);
+ ClassDB::bind_method(D_METHOD("get_time_string_from_unix_time", "unix_time_val"), &Time::get_time_string_from_unix_time);
+ ClassDB::bind_method(D_METHOD("get_datetime_dict_from_string", "datetime", "weekday"), &Time::get_datetime_dict_from_string);
+ ClassDB::bind_method(D_METHOD("get_datetime_string_from_dict", "datetime", "use_space"), &Time::get_datetime_string_from_dict);
+ ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_dict", "datetime"), &Time::get_unix_time_from_datetime_dict);
+ ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_string", "datetime"), &Time::get_unix_time_from_datetime_string);
+
+ ClassDB::bind_method(D_METHOD("get_datetime_dict_from_system", "utc"), &Time::get_datetime_dict_from_system, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_date_dict_from_system", "utc"), &Time::get_date_dict_from_system, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_time_dict_from_system", "utc"), &Time::get_time_dict_from_system, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_datetime_string_from_system", "utc", "use_space"), &Time::get_datetime_string_from_system, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_date_string_from_system", "utc"), &Time::get_date_string_from_system, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_time_string_from_system", "utc"), &Time::get_time_string_from_system, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_time_zone_from_system"), &Time::get_time_zone_from_system);
+ ClassDB::bind_method(D_METHOD("get_unix_time_from_system"), &Time::get_unix_time_from_system);
+ ClassDB::bind_method(D_METHOD("get_ticks_msec"), &Time::get_ticks_msec);
+ ClassDB::bind_method(D_METHOD("get_ticks_usec"), &Time::get_ticks_usec);
+
+ BIND_ENUM_CONSTANT(MONTH_JANUARY);
+ BIND_ENUM_CONSTANT(MONTH_FEBRUARY);
+ BIND_ENUM_CONSTANT(MONTH_MARCH);
+ BIND_ENUM_CONSTANT(MONTH_APRIL);
+ BIND_ENUM_CONSTANT(MONTH_MAY);
+ BIND_ENUM_CONSTANT(MONTH_JUNE);
+ BIND_ENUM_CONSTANT(MONTH_JULY);
+ BIND_ENUM_CONSTANT(MONTH_AUGUST);
+ BIND_ENUM_CONSTANT(MONTH_SEPTEMBER);
+ BIND_ENUM_CONSTANT(MONTH_OCTOBER);
+ BIND_ENUM_CONSTANT(MONTH_NOVEMBER);
+ BIND_ENUM_CONSTANT(MONTH_DECEMBER);
+
+ BIND_ENUM_CONSTANT(WEEKDAY_SUNDAY);
+ BIND_ENUM_CONSTANT(WEEKDAY_MONDAY);
+ BIND_ENUM_CONSTANT(WEEKDAY_TUESDAY);
+ BIND_ENUM_CONSTANT(WEEKDAY_WEDNESDAY);
+ BIND_ENUM_CONSTANT(WEEKDAY_THURSDAY);
+ BIND_ENUM_CONSTANT(WEEKDAY_FRIDAY);
+ BIND_ENUM_CONSTANT(WEEKDAY_SATURDAY);
+}
+
+Time::Time() {
+ ERR_FAIL_COND_MSG(singleton, "Singleton for Time already exists.");
+ singleton = this;
+}
+
+Time::~Time() {
+ singleton = nullptr;
+}
diff --git a/core/os/time.h b/core/os/time.h
new file mode 100644
index 0000000000..4325f93d56
--- /dev/null
+++ b/core/os/time.h
@@ -0,0 +1,109 @@
+/*************************************************************************/
+/* time.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TIME_H
+#define TIME_H
+
+#include "core/object/class_db.h"
+
+// This Time class conforms with as many of the ISO 8601 standards as possible.
+// * As per ISO 8601:2004 4.3.2.1, all dates follow the Proleptic Gregorian
+// calendar. As such, the day before 1582-10-15 is 1582-10-14, not 1582-10-04.
+// See: https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar
+// * As per ISO 8601:2004 3.4.2 and 4.1.2.4, the year before 1 AD (aka 1 BC)
+// is number "0", with the year before that (2 BC) being "-1", etc.
+// Conversion methods assume "the same timezone", and do not handle DST.
+// Leap seconds are not handled, they must be done manually if desired.
+// Suffixes such as "Z" are not handled, you need to strip them away manually.
+
+class Time : public Object {
+ GDCLASS(Time, Object);
+ static void _bind_methods();
+ static Time *singleton;
+
+public:
+ static Time *get_singleton();
+
+ enum Month : uint8_t {
+ /// Start at 1 to follow Windows SYSTEMTIME structure
+ /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
+ MONTH_JANUARY = 1,
+ MONTH_FEBRUARY,
+ MONTH_MARCH,
+ MONTH_APRIL,
+ MONTH_MAY,
+ MONTH_JUNE,
+ MONTH_JULY,
+ MONTH_AUGUST,
+ MONTH_SEPTEMBER,
+ MONTH_OCTOBER,
+ MONTH_NOVEMBER,
+ MONTH_DECEMBER,
+ };
+
+ enum Weekday : uint8_t {
+ WEEKDAY_SUNDAY,
+ WEEKDAY_MONDAY,
+ WEEKDAY_TUESDAY,
+ WEEKDAY_WEDNESDAY,
+ WEEKDAY_THURSDAY,
+ WEEKDAY_FRIDAY,
+ WEEKDAY_SATURDAY,
+ };
+
+ // Methods that convert times.
+ Dictionary get_datetime_dict_from_unix_time(int64_t p_unix_time_val) const;
+ Dictionary get_date_dict_from_unix_time(int64_t p_unix_time_val) const;
+ Dictionary get_time_dict_from_unix_time(int64_t p_unix_time_val) const;
+ String get_datetime_string_from_unix_time(int64_t p_unix_time_val, bool p_use_space = false) const;
+ String get_date_string_from_unix_time(int64_t p_unix_time_val) const;
+ String get_time_string_from_unix_time(int64_t p_unix_time_val) const;
+ Dictionary get_datetime_dict_from_string(String p_datetime, bool p_weekday = true) const;
+ String get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space = false) const;
+ int64_t get_unix_time_from_datetime_dict(Dictionary p_datetime) const;
+ int64_t get_unix_time_from_datetime_string(String p_datetime) const;
+
+ // Methods that get information from OS.
+ Dictionary get_datetime_dict_from_system(bool p_utc = false) const;
+ Dictionary get_date_dict_from_system(bool p_utc = false) const;
+ Dictionary get_time_dict_from_system(bool p_utc = false) const;
+ String get_datetime_string_from_system(bool p_utc = false, bool p_use_space = false) const;
+ String get_date_string_from_system(bool p_utc = false) const;
+ String get_time_string_from_system(bool p_utc = false) const;
+ Dictionary get_time_zone_from_system() const;
+ double get_unix_time_from_system() const;
+ uint64_t get_ticks_msec() const;
+ uint64_t get_ticks_usec() const;
+
+ Time();
+ virtual ~Time();
+};
+
+#endif // TIME_H
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index d6a5eff10d..f67d615418 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -68,6 +68,7 @@
#include "core/object/class_db.h"
#include "core/object/undo_redo.h"
#include "core/os/main_loop.h"
+#include "core/os/time.h"
#include "core/string/optimized_translation.h"
#include "core/string/translation.h"
@@ -131,7 +132,7 @@ void register_core_types() {
ClassDB::register_virtual_class<Script>();
- ClassDB::register_class<Reference>();
+ ClassDB::register_class<RefCounted>();
ClassDB::register_class<WeakRef>();
ClassDB::register_class<Resource>();
ClassDB::register_class<Image>();
@@ -156,7 +157,7 @@ void register_core_types() {
ClassDB::register_virtual_class<StreamPeer>();
ClassDB::register_class<StreamPeerBuffer>();
ClassDB::register_class<StreamPeerTCP>();
- ClassDB::register_class<TCP_Server>();
+ ClassDB::register_class<TCPServer>();
ClassDB::register_class<PacketPeerUDP>();
ClassDB::register_class<UDPServer>();
ClassDB::register_custom_instance_class<PacketPeerDTLS>();
@@ -258,6 +259,7 @@ void register_core_singletons() {
ClassDB::register_class<_JSON>();
ClassDB::register_class<Expression>();
ClassDB::register_class<_EngineDebugger>();
+ ClassDB::register_class<Time>();
Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton()));
@@ -274,6 +276,7 @@ void register_core_singletons() {
Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("JSON", _JSON::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _EngineDebugger::get_singleton()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton()));
}
void unregister_core_types() {
diff --git a/core/string/node_path.h b/core/string/node_path.h
index 26e15636d9..a277ab26fa 100644
--- a/core/string/node_path.h
+++ b/core/string/node_path.h
@@ -66,8 +66,6 @@ public:
void prepend_period();
- NodePath get_parent() const;
-
_FORCE_INLINE_ uint32_t hash() const {
if (!data) {
return 0;
diff --git a/core/string/optimized_translation.cpp b/core/string/optimized_translation.cpp
index 53d0a8924d..268562d971 100644
--- a/core/string/optimized_translation.cpp
+++ b/core/string/optimized_translation.cpp
@@ -46,6 +46,7 @@ void OptimizedTranslation::generate(const Ref<Translation> &p_from) {
// This method compresses a Translation instance.
// Right now, it doesn't handle context or plurals, so Translation subclasses using plurals or context (i.e TranslationPO) shouldn't be compressed.
#ifdef TOOLS_ENABLED
+ ERR_FAIL_COND(p_from.is_null());
List<StringName> keys;
p_from->get_message_list(&keys);
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index ade5f7b4d8..153f0190fd 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -835,7 +835,7 @@ Vector<String> Translation::_get_message_list() const {
void Translation::_set_messages(const Dictionary &p_messages) {
List<Variant> keys;
p_messages.get_key_list(&keys);
- for (auto E = keys.front(); E; E = E->next()) {
+ for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
translation_map[E->get()] = p_messages[E->get()];
}
}
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
index 2efadaa9b7..d6b84cabc9 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -30,7 +30,7 @@
#include "translation_po.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#ifdef DEBUG_TRANSLATION_PO
void TranslationPO::print_translation_map() {
@@ -47,14 +47,14 @@ void TranslationPO::print_translation_map() {
List<StringName> context_l;
translation_map.get_key_list(&context_l);
- for (auto E = context_l.front(); E; E = E->next()) {
+ for (List<StringName>::Element *E = context_l.front(); E; E = E->next()) {
StringName ctx = E->get();
file->store_line(" ===== Context: " + String::utf8(String(ctx).utf8()) + " ===== ");
const HashMap<StringName, Vector<StringName>> &inner_map = translation_map[ctx];
List<StringName> id_l;
inner_map.get_key_list(&id_l);
- for (auto E2 = id_l.front(); E2; E2 = E2->next()) {
+ for (List<StringName>::Element *E2 = id_l.front(); E2; E2 = E2->next()) {
StringName id = E2->get();
file->store_line("msgid: " + String::utf8(String(id).utf8()));
for (int i = 0; i < inner_map[id].size(); i++) {
@@ -74,7 +74,7 @@ Dictionary TranslationPO::_get_messages() const {
List<StringName> context_l;
translation_map.get_key_list(&context_l);
- for (auto E = context_l.front(); E; E = E->next()) {
+ for (List<StringName>::Element *E = context_l.front(); E; E = E->next()) {
StringName ctx = E->get();
const HashMap<StringName, Vector<StringName>> &id_str_map = translation_map[ctx];
@@ -82,7 +82,7 @@ Dictionary TranslationPO::_get_messages() const {
List<StringName> id_l;
id_str_map.get_key_list(&id_l);
// Save list of id and strs associated with a context in a temporary dictionary.
- for (auto E2 = id_l.front(); E2; E2 = E2->next()) {
+ for (List<StringName>::Element *E2 = id_l.front(); E2; E2 = E2->next()) {
StringName id = E2->get();
d2[id] = id_str_map[id];
}
@@ -98,14 +98,14 @@ void TranslationPO::_set_messages(const Dictionary &p_messages) {
List<Variant> context_l;
p_messages.get_key_list(&context_l);
- for (auto E = context_l.front(); E; E = E->next()) {
+ for (List<Variant>::Element *E = context_l.front(); E; E = E->next()) {
StringName ctx = E->get();
const Dictionary &id_str_map = p_messages[ctx];
HashMap<StringName, Vector<StringName>> temp_map;
List<Variant> id_l;
id_str_map.get_key_list(&id_l);
- for (auto E2 = id_l.front(); E2; E2 = E2->next()) {
+ for (List<Variant>::Element *E2 = id_l.front(); E2; E2 = E2->next()) {
StringName id = E2->get();
temp_map[id] = id_str_map[id];
}
@@ -121,7 +121,7 @@ Vector<String> TranslationPO::_get_message_list() const {
get_message_list(&msgs);
Vector<String> v;
- for (auto E = msgs.front(); E; E = E->next()) {
+ for (List<StringName>::Element *E = msgs.front(); E; E = E->next()) {
v.push_back(E->get());
}
@@ -281,7 +281,7 @@ void TranslationPO::get_message_list(List<StringName> *r_messages) const {
List<StringName> context_l;
translation_map.get_key_list(&context_l);
- for (auto E = context_l.front(); E; E = E->next()) {
+ for (List<StringName>::Element *E = context_l.front(); E; E = E->next()) {
if (String(E->get()) != "") {
continue;
}
@@ -289,7 +289,7 @@ void TranslationPO::get_message_list(List<StringName> *r_messages) const {
List<StringName> msgid_l;
translation_map[E->get()].get_key_list(&msgid_l);
- for (auto E2 = msgid_l.front(); E2; E2 = E2->next()) {
+ for (List<StringName>::Element *E2 = msgid_l.front(); E2; E2 = E2->next()) {
r_messages->push_back(E2->get());
}
}
@@ -300,7 +300,7 @@ int TranslationPO::get_message_count() const {
translation_map.get_key_list(&context_l);
int count = 0;
- for (auto E = context_l.front(); E; E = E->next()) {
+ for (List<StringName>::Element *E = context_l.front(); E; E = E->next()) {
count += translation_map[E->get()].size();
}
return count;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index cf0040353d..019754bc22 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -54,7 +54,7 @@
#define snprintf _snprintf_s
#endif
-#define MAX_DIGITS 6
+#define MAX_DECIMALS 32
#define UPPERCASE(m_c) (((m_c) >= 'a' && (m_c) <= 'z') ? ((m_c) - ('a' - 'A')) : (m_c))
#define LOWERCASE(m_c) (((m_c) >= 'A' && (m_c) <= 'Z') ? ((m_c) + ('a' - 'A')) : (m_c))
#define IS_DIGIT(m_d) ((m_d) >= '0' && (m_d) <= '9')
@@ -240,6 +240,71 @@ String String::word_wrap(int p_chars_per_line) const {
return ret;
}
+Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path) const {
+ // Splits the URL into scheme, host, port, path. Strip credentials when present.
+ String base = *this;
+ r_scheme = "";
+ r_host = "";
+ r_port = 0;
+ r_path = "";
+ int pos = base.find("://");
+ // Scheme
+ if (pos != -1) {
+ r_scheme = base.substr(0, pos + 3).to_lower();
+ base = base.substr(pos + 3, base.length() - pos - 3);
+ }
+ pos = base.find("/");
+ // Path
+ if (pos != -1) {
+ r_path = base.substr(pos, base.length() - pos);
+ base = base.substr(0, pos);
+ }
+ // Host
+ pos = base.find("@");
+ if (pos != -1) {
+ // Strip credentials
+ base = base.substr(pos + 1, base.length() - pos - 1);
+ }
+ if (base.begins_with("[")) {
+ // Literal IPv6
+ pos = base.rfind("]");
+ if (pos == -1) {
+ return ERR_INVALID_PARAMETER;
+ }
+ r_host = base.substr(1, pos - 1);
+ base = base.substr(pos + 1, base.length() - pos - 1);
+ } else {
+ // Anything else
+ if (base.get_slice_count(":") > 2) {
+ return ERR_INVALID_PARAMETER;
+ }
+ pos = base.rfind(":");
+ if (pos == -1) {
+ r_host = base;
+ base = "";
+ } else {
+ r_host = base.substr(0, pos);
+ base = base.substr(pos, base.length() - pos);
+ }
+ }
+ if (r_host.is_empty()) {
+ return ERR_INVALID_PARAMETER;
+ }
+ r_host = r_host.to_lower();
+ // Port
+ if (base.begins_with(":")) {
+ base = base.substr(1, base.length() - 1);
+ if (!base.is_valid_integer()) {
+ return ERR_INVALID_PARAMETER;
+ }
+ r_port = base.to_int();
+ if (r_port < 1 || r_port > 65535) {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+ return OK;
+}
+
void String::copy_from(const char *p_cstr) {
// copy Latin-1 encoded c-string directly
if (!p_cstr) {
@@ -874,7 +939,7 @@ const char32_t *String::get_data() const {
}
void String::erase(int p_pos, int p_chars) {
- *this = left(p_pos) + substr(p_pos + p_chars, length() - ((p_pos + p_chars)));
+ *this = left(MAX(p_pos, 0)) + substr(p_pos + p_chars, length() - ((p_pos + p_chars)));
}
String String::capitalize() const {
@@ -1314,8 +1379,11 @@ String String::num(double p_num, int p_decimals) {
}
#ifndef NO_USE_STDLIB
- if (p_decimals > 16) {
- p_decimals = 16;
+ if (p_decimals < 0) {
+ p_decimals = 14 - (int)floor(log10(p_num));
+ }
+ if (p_decimals > MAX_DECIMALS) {
+ p_decimals = MAX_DECIMALS;
}
char fmt[7];
@@ -1326,7 +1394,6 @@ String String::num(double p_num, int p_decimals) {
fmt[1] = 'l';
fmt[2] = 'f';
fmt[3] = 0;
-
} else if (p_decimals < 10) {
fmt[2] = '0' + p_decimals;
fmt[3] = 'l';
@@ -1393,8 +1460,9 @@ String String::num(double p_num, int p_decimals) {
double dec = p_num - (double)((int)p_num);
int digit = 0;
- if (p_decimals > MAX_DIGITS)
- p_decimals = MAX_DIGITS;
+ if (p_decimals > MAX_DECIMALS) {
+ p_decimals = MAX_DECIMALS;
+ }
int dec_int = 0;
int dec_max = 0;
@@ -1406,16 +1474,18 @@ String String::num(double p_num, int p_decimals) {
digit++;
if (p_decimals == -1) {
- if (digit == MAX_DIGITS) //no point in going to infinite
+ if (digit == MAX_DECIMALS) { //no point in going to infinite
break;
+ }
if (dec - (double)((int)dec) < 1e-6) {
break;
}
}
- if (digit == p_decimals)
+ if (digit == p_decimals) {
break;
+ }
}
dec *= 10;
int last = (int)dec % 10;
@@ -1524,7 +1594,7 @@ String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) {
return s;
}
-String String::num_real(double p_num) {
+String String::num_real(double p_num, bool p_trailing) {
if (Math::is_nan(p_num)) {
return "nan";
}
@@ -1551,7 +1621,15 @@ String String::num_real(double p_num) {
double dec = p_num - (double)((int)p_num);
int digit = 0;
- int decimals = MAX_DIGITS;
+
+#if REAL_T_IS_DOUBLE
+ int decimals = 14 - (int)floor(log10(p_num));
+#else
+ int decimals = 6 - (int)floor(log10(p_num));
+#endif
+ if (decimals > MAX_DECIMALS) {
+ decimals = MAX_DECIMALS;
+ }
int dec_int = 0;
int dec_max = 0;
@@ -1591,8 +1669,10 @@ String String::num_real(double p_num) {
dec_int /= 10;
}
sd = '.' + decimal;
- } else {
+ } else if (p_trailing) {
sd = ".0";
+ } else {
+ sd = "";
}
if (intn == 0) {
@@ -3317,14 +3397,14 @@ String String::format(const Variant &values, String placeholder) const {
if (value_arr.size() == 2) {
Variant v_key = value_arr[0];
String key = v_key;
- if (key.left(1) == "\"" && key.right(key.length() - 1) == "\"") {
+ if (key.left(1) == "\"" && key.right(1) == "\"") {
key = key.substr(1, key.length() - 2);
}
Variant v_val = value_arr[1];
String val = v_val;
- if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") {
+ if (val.left(1) == "\"" && val.right(1) == "\"") {
val = val.substr(1, val.length() - 2);
}
@@ -3336,7 +3416,7 @@ String String::format(const Variant &values, String placeholder) const {
Variant v_val = values_arr[i];
String val = v_val;
- if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") {
+ if (val.left(1) == "\"" && val.right(1) == "\"") {
val = val.substr(1, val.length() - 2);
}
@@ -3356,11 +3436,11 @@ String String::format(const Variant &values, String placeholder) const {
String key = E->get();
String val = d[E->get()];
- if (key.left(1) == "\"" && key.right(key.length() - 1) == "\"") {
+ if (key.left(1) == "\"" && key.right(1) == "\"") {
key = key.substr(1, key.length() - 2);
}
- if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") {
+ if (val.left(1) == "\"" && val.right(1) == "\"") {
val = val.substr(1, val.length() - 2);
}
@@ -3464,6 +3544,10 @@ String String::repeat(int p_count) const {
}
String String::left(int p_pos) const {
+ if (p_pos < 0) {
+ p_pos = length() + p_pos;
+ }
+
if (p_pos <= 0) {
return "";
}
@@ -3476,15 +3560,19 @@ String String::left(int p_pos) const {
}
String String::right(int p_pos) const {
- if (p_pos >= length()) {
- return "";
+ if (p_pos < 0) {
+ p_pos = length() + p_pos;
}
if (p_pos <= 0) {
+ return "";
+ }
+
+ if (p_pos >= length()) {
return *this;
}
- return substr(p_pos, (length() - p_pos));
+ return substr(length() - p_pos);
}
char32_t String::unicode_at(int p_idx) const {
@@ -3713,7 +3801,7 @@ String String::humanize_size(uint64_t p_size) {
return String::num(p_size / divisor).pad_decimals(digits) + " " + prefixes[prefix_idx];
}
-bool String::is_abs_path() const {
+bool String::is_absolute_path() const {
if (length() > 1) {
return (operator[](0) == '/' || operator[](0) == '\\' || find(":/") != -1 || find(":\\") != -1);
} else if ((length()) == 1) {
@@ -3784,27 +3872,28 @@ String String::uri_encode() const {
}
String String::uri_decode() const {
- String res;
- for (int i = 0; i < length(); ++i) {
- if (unicode_at(i) == '%' && i + 2 < length()) {
- char32_t ord1 = unicode_at(i + 1);
+ CharString src = utf8();
+ CharString res;
+ for (int i = 0; i < src.length(); ++i) {
+ if (src[i] == '%' && i + 2 < src.length()) {
+ char ord1 = src[i + 1];
if ((ord1 >= '0' && ord1 <= '9') || (ord1 >= 'A' && ord1 <= 'Z')) {
- char32_t ord2 = unicode_at(i + 2);
+ char ord2 = src[i + 2];
if ((ord2 >= '0' && ord2 <= '9') || (ord2 >= 'A' && ord2 <= 'Z')) {
char bytes[3] = { (char)ord1, (char)ord2, 0 };
res += (char)strtol(bytes, nullptr, 16);
i += 2;
}
} else {
- res += unicode_at(i);
+ res += src[i];
}
- } else if (unicode_at(i) == '+') {
+ } else if (src[i] == '+') {
res += ' ';
} else {
- res += unicode_at(i);
+ res += src[i];
}
}
- return String::utf8(res.ascii());
+ return String::utf8(res);
}
String String::c_unescape() const {
@@ -4322,7 +4411,7 @@ bool String::is_resource_file() const {
}
bool String::is_rel_path() const {
- return !is_abs_path();
+ return !is_absolute_path();
}
String String::get_base_dir() const {
@@ -4765,7 +4854,7 @@ Vector<uint8_t> String::to_ascii_buffer() const {
size_t len = charstr.length();
retval.resize(len);
uint8_t *w = retval.ptrw();
- copymem(w, charstr.ptr(), len);
+ memcpy(w, charstr.ptr(), len);
return retval;
}
@@ -4781,7 +4870,7 @@ Vector<uint8_t> String::to_utf8_buffer() const {
size_t len = charstr.length();
retval.resize(len);
uint8_t *w = retval.ptrw();
- copymem(w, charstr.ptr(), len);
+ memcpy(w, charstr.ptr(), len);
return retval;
}
@@ -4797,7 +4886,7 @@ Vector<uint8_t> String::to_utf16_buffer() const {
size_t len = charstr.length() * sizeof(char16_t);
retval.resize(len);
uint8_t *w = retval.ptrw();
- copymem(w, (const void *)charstr.ptr(), len);
+ memcpy(w, (const void *)charstr.ptr(), len);
return retval;
}
@@ -4812,7 +4901,7 @@ Vector<uint8_t> String::to_utf32_buffer() const {
size_t len = s->length() * sizeof(char32_t);
retval.resize(len);
uint8_t *w = retval.ptrw();
- copymem(w, (const void *)s->ptr(), len);
+ memcpy(w, (const void *)s->ptr(), len);
return retval;
}
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 1e362d7683..82cd3e1667 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -309,7 +309,7 @@ public:
String unquote() const;
static String num(double p_num, int p_decimals = -1);
static String num_scientific(double p_num);
- static String num_real(double p_num);
+ static String num_real(double p_num, bool p_trailing = true);
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false);
static String chr(char32_t p_char);
@@ -397,7 +397,7 @@ public:
_FORCE_INLINE_ bool is_empty() const { return length() == 0; }
// path functions
- bool is_abs_path() const;
+ bool is_absolute_path() const;
bool is_rel_path() const;
bool is_resource_file() const;
String path_to(const String &p_path) const;
@@ -416,6 +416,7 @@ public:
String c_unescape() const;
String json_escape() const;
String word_wrap(int p_chars_per_line) const;
+ Error parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path) const;
String property_name_encode() const;
diff --git a/core/templates/bin_sorted_array.h b/core/templates/bin_sorted_array.h
new file mode 100644
index 0000000000..be9d0b5475
--- /dev/null
+++ b/core/templates/bin_sorted_array.h
@@ -0,0 +1,181 @@
+/*************************************************************************/
+/* bin_sorted_array.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BIN_SORTED_ARRAY_H
+#define BIN_SORTED_ARRAY_H
+
+#include "core/templates/local_vector.h"
+#include "core/templates/paged_array.h"
+
+template <class T>
+class BinSortedArray {
+ PagedArray<T> array;
+ LocalVector<uint64_t> bin_limits;
+
+ // Implement if elements need to keep track of their own index in the array.
+ _FORCE_INLINE_ virtual void _update_idx(T &r_element, uint64_t p_idx) {}
+
+ _FORCE_INLINE_ void _swap(uint64_t p_a, uint64_t p_b) {
+ SWAP(array[p_a], array[p_b]);
+ _update_idx(array[p_a], p_a);
+ _update_idx(array[p_b], p_b);
+ }
+
+public:
+ uint64_t insert(T &p_element, uint64_t p_bin) {
+ array.push_back(p_element);
+ uint64_t new_idx = array.size() - 1;
+ _update_idx(p_element, new_idx);
+ bin_limits[0] = new_idx;
+ if (p_bin != 0) {
+ new_idx = move(new_idx, p_bin);
+ }
+ return new_idx;
+ }
+
+ uint64_t move(uint64_t p_idx, uint64_t p_bin) {
+ ERR_FAIL_COND_V(p_idx >= array.size(), -1);
+
+ uint64_t current_bin = bin_limits.size() - 1;
+ while (p_idx > bin_limits[current_bin]) {
+ current_bin--;
+ }
+
+ if (p_bin == current_bin) {
+ return p_idx;
+ }
+
+ uint64_t current_idx = p_idx;
+ if (p_bin > current_bin) {
+ while (p_bin > current_bin) {
+ uint64_t swap_idx = 0;
+
+ if (current_bin == bin_limits.size() - 1) {
+ bin_limits.push_back(0);
+ } else {
+ bin_limits[current_bin + 1]++;
+ swap_idx = bin_limits[current_bin + 1];
+ }
+
+ if (current_idx != swap_idx) {
+ _swap(current_idx, swap_idx);
+ current_idx = swap_idx;
+ }
+
+ current_bin++;
+ }
+ } else {
+ while (p_bin < current_bin) {
+ uint64_t swap_idx = bin_limits[current_bin];
+
+ if (current_idx != swap_idx) {
+ _swap(current_idx, swap_idx);
+ }
+
+ if (current_bin == bin_limits.size() - 1 && bin_limits[current_bin] == 0) {
+ bin_limits.resize(bin_limits.size() - 1);
+ } else {
+ bin_limits[current_bin]--;
+ }
+ current_idx = swap_idx;
+ current_bin--;
+ }
+ }
+
+ return current_idx;
+ }
+
+ void remove(uint64_t p_idx) {
+ ERR_FAIL_COND(p_idx >= array.size());
+ uint64_t new_idx = move(p_idx, 0);
+ uint64_t swap_idx = array.size() - 1;
+
+ if (new_idx != swap_idx) {
+ _swap(new_idx, swap_idx);
+ }
+
+ if (bin_limits[0] > 0) {
+ bin_limits[0]--;
+ }
+
+ array.pop_back();
+ }
+
+ void set_page_pool(PagedArrayPool<T> *p_page_pool) {
+ array.set_page_pool(p_page_pool);
+ }
+
+ _FORCE_INLINE_ const T &operator[](uint64_t p_index) const {
+ return array[p_index];
+ }
+
+ _FORCE_INLINE_ T &operator[](uint64_t p_index) {
+ return array[p_index];
+ }
+
+ int get_bin_count() {
+ if (array.size() == 0) {
+ return 0;
+ }
+ return bin_limits.size();
+ }
+
+ int get_bin_start(int p_bin) {
+ ERR_FAIL_COND_V(p_bin >= get_bin_count(), ~0U);
+ if ((unsigned int)p_bin == bin_limits.size() - 1) {
+ return 0;
+ }
+ return bin_limits[p_bin + 1] + 1;
+ }
+
+ int get_bin_size(int p_bin) {
+ ERR_FAIL_COND_V(p_bin >= get_bin_count(), 0);
+ if ((unsigned int)p_bin == bin_limits.size() - 1) {
+ return bin_limits[p_bin] + 1;
+ }
+ return bin_limits[p_bin] - bin_limits[p_bin + 1];
+ }
+
+ void reset() {
+ array.reset();
+ bin_limits.clear();
+ bin_limits.push_back(0);
+ }
+
+ BinSortedArray() {
+ bin_limits.push_back(0);
+ }
+
+ virtual ~BinSortedArray() {
+ reset();
+ }
+};
+
+#endif //BIN_SORTED_ARRAY_H
diff --git a/core/templates/command_queue_mt.cpp b/core/templates/command_queue_mt.cpp
index 238bf3975c..04a8095f0b 100644
--- a/core/templates/command_queue_mt.cpp
+++ b/core/templates/command_queue_mt.cpp
@@ -70,35 +70,7 @@ CommandQueueMT::SyncSemaphore *CommandQueueMT::_alloc_sync_sem() {
return &sync_sems[idx];
}
-bool CommandQueueMT::dealloc_one() {
-tryagain:
- if (dealloc_ptr == (write_ptr_and_epoch >> 1)) {
- // The queue is empty
- return false;
- }
-
- uint32_t size = *(uint32_t *)&command_mem[dealloc_ptr];
-
- if (size == 0) {
- // End of command buffer wrap down
- dealloc_ptr = 0;
- goto tryagain;
- }
-
- if (size & 1) {
- // Still used, nothing can be deallocated
- return false;
- }
-
- dealloc_ptr += (size >> 1) + 8;
- return true;
-}
-
CommandQueueMT::CommandQueueMT(bool p_sync) {
- command_mem_size = GLOBAL_DEF_RST("memory/limits/command_queue/multithreading_queue_size_kb", DEFAULT_COMMAND_MEM_SIZE_KB);
- ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/command_queue/multithreading_queue_size_kb", PropertyInfo(Variant::INT, "memory/limits/command_queue/multithreading_queue_size_kb", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"));
- command_mem_size *= 1024;
- command_mem = (uint8_t *)memalloc(command_mem_size);
if (p_sync) {
sync = memnew(Semaphore);
}
@@ -108,5 +80,4 @@ CommandQueueMT::~CommandQueueMT() {
if (sync) {
memdelete(sync);
}
- memfree(command_mem);
}
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index 0012cea72d..acc46da0d5 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -34,6 +34,8 @@
#include "core/os/memory.h"
#include "core/os/mutex.h"
#include "core/os/semaphore.h"
+#include "core/string/print_string.h"
+#include "core/templates/local_vector.h"
#include "core/templates/simple_type.h"
#include "core/typedefs.h"
@@ -334,11 +336,7 @@ class CommandQueueMT {
SYNC_SEMAPHORES = 8
};
- uint8_t *command_mem = nullptr;
- uint32_t read_ptr_and_epoch = 0;
- uint32_t write_ptr_and_epoch = 0;
- uint32_t dealloc_ptr = 0;
- uint32_t command_mem_size = 0;
+ LocalVector<uint8_t> command_mem;
SyncSemaphore sync_sems[SYNC_SEMAPHORES];
Mutex mutex;
Semaphore *sync = nullptr;
@@ -346,138 +344,47 @@ class CommandQueueMT {
template <class T>
T *allocate() {
// alloc size is size+T+safeguard
- uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1)) + 8;
-
- // Assert that the buffer is big enough to hold at least two messages.
- ERR_FAIL_COND_V(alloc_size * 2 + sizeof(uint32_t) > command_mem_size, nullptr);
-
- tryagain:
- uint32_t write_ptr = write_ptr_and_epoch >> 1;
-
- if (write_ptr < dealloc_ptr) {
- // behind dealloc_ptr, check that there is room
- if ((dealloc_ptr - write_ptr) <= alloc_size) {
- // There is no more room, try to deallocate something
- if (dealloc_one()) {
- goto tryagain;
- }
- return nullptr;
- }
- } else {
- // ahead of dealloc_ptr, check that there is room
-
- if ((command_mem_size - write_ptr) < alloc_size + sizeof(uint32_t)) {
- // no room at the end, wrap down;
-
- if (dealloc_ptr == 0) { // don't want write_ptr to become dealloc_ptr
-
- // There is no more room, try to deallocate something
- if (dealloc_one()) {
- goto tryagain;
- }
- return nullptr;
- }
-
- // if this happens, it's a bug
- 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];
- *p = 1;
- write_ptr_and_epoch = 0 | (1 & ~write_ptr_and_epoch); // Invert epoch.
- // See if we can get the thread to run and clear up some more space while we wait.
- // This is required if alloc_size * 2 + 4 > COMMAND_MEM_SIZE
- if (sync) {
- sync->post();
- }
- goto tryagain;
- }
- }
- // Allocate the size and the 'in use' bit.
- // First bit used to mark if command is still in use (1)
- // or if it has been destroyed and can be deallocated (0).
- uint32_t size = (sizeof(T) + 8 - 1) & ~(8 - 1);
- uint32_t *p = (uint32_t *)&command_mem[write_ptr];
- *p = (size << 1) | 1;
- write_ptr += 8;
- // allocate the command
- T *cmd = memnew_placement(&command_mem[write_ptr], T);
- write_ptr += size;
- write_ptr_and_epoch = (write_ptr << 1) | (write_ptr_and_epoch & 1);
+ uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1));
+ uint64_t size = command_mem.size();
+ command_mem.resize(size + alloc_size + 8);
+ *(uint64_t *)&command_mem[size] = alloc_size;
+ T *cmd = memnew_placement(&command_mem[size + 8], T);
return cmd;
}
template <class T>
T *allocate_and_lock() {
lock();
- T *ret;
-
- while ((ret = allocate<T>()) == nullptr) {
- unlock();
- // sleep a little until fetch happened and some room is made
- wait_for_flush();
- lock();
- }
-
+ T *ret = allocate<T>();
return ret;
}
- bool flush_one(bool p_lock = true) {
- if (p_lock) {
- lock();
- }
- tryagain:
-
- // tried to read an empty queue
- if (read_ptr_and_epoch == write_ptr_and_epoch) {
- if (p_lock) {
- unlock();
- }
- return false;
- }
-
- uint32_t read_ptr = read_ptr_and_epoch >> 1;
- uint32_t size_ptr = read_ptr;
- uint32_t size = *(uint32_t *)&command_mem[read_ptr] >> 1;
-
- if (size == 0) {
- *(uint32_t *)&command_mem[read_ptr] = 0; // clear in-use bit.
- //end of ringbuffer, wrap
- read_ptr_and_epoch = 0 | (1 & ~read_ptr_and_epoch); // Invert epoch.
- goto tryagain;
- }
-
- read_ptr += 8;
+ void _flush() {
+ lock();
- CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]);
+ uint64_t read_ptr = 0;
+ uint64_t limit = command_mem.size();
- read_ptr += size;
+ while (read_ptr < limit) {
+ uint64_t size = *(uint64_t *)&command_mem[read_ptr];
+ read_ptr += 8;
+ CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]);
- read_ptr_and_epoch = (read_ptr << 1) | (read_ptr_and_epoch & 1);
+ cmd->call(); //execute the function
+ cmd->post(); //release in case it needs sync/ret
+ cmd->~CommandBase(); //should be done, so erase the command
- if (p_lock) {
- unlock();
- }
- cmd->call();
- if (p_lock) {
- lock();
+ read_ptr += size;
}
- cmd->post();
- cmd->~CommandBase();
- *(uint32_t *)&command_mem[size_ptr] &= ~1;
-
- if (p_lock) {
- unlock();
- }
- return true;
+ command_mem.clear();
+ unlock();
}
void lock();
void unlock();
void wait_for_flush();
SyncSemaphore *_alloc_sync_sem();
- bool dealloc_one();
public:
/* NORMAL PUSH COMMANDS */
@@ -492,23 +399,19 @@ public:
DECL_PUSH_AND_SYNC(0)
SPACE_SEP_LIST(DECL_PUSH_AND_SYNC, 15)
- void wait_and_flush_one() {
- ERR_FAIL_COND(!sync);
- sync->wait();
- flush_one();
- }
-
_FORCE_INLINE_ void flush_if_pending() {
- if (unlikely(read_ptr_and_epoch != write_ptr_and_epoch)) {
- flush_all();
+ if (unlikely(command_mem.size() > 0)) {
+ _flush();
}
}
void flush_all() {
- //ERR_FAIL_COND(sync);
- lock();
- while (flush_one(false)) {
- }
- unlock();
+ _flush();
+ }
+
+ void wait_and_flush() {
+ ERR_FAIL_COND(!sync);
+ sync->wait();
+ _flush();
}
CommandQueueMT(bool p_sync);
diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h
index dc378aed69..1257b54449 100644
--- a/core/templates/hash_map.h
+++ b/core/templates/hash_map.h
@@ -291,7 +291,7 @@ public:
}
/**
- * Same as get, except it can return nullptr 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.
*/
@@ -324,7 +324,7 @@ public:
}
/**
- * Same as get, except it can return nullptr 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==()
*/
@@ -443,7 +443,7 @@ 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, nullptr 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:
diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h
index ffd17b7ee9..5f22e08eb8 100644
--- a/core/templates/local_vector.h
+++ b/core/templates/local_vector.h
@@ -32,7 +32,6 @@
#define LOCAL_VECTOR_H
#include "core/error/error_macros.h"
-#include "core/os/copymem.h"
#include "core/os/memory.h"
#include "core/templates/sort_array.h"
#include "core/templates/vector.h"
@@ -216,7 +215,7 @@ public:
Vector<T> ret;
ret.resize(size());
T *w = ret.ptrw();
- copymem(w, data, sizeof(T) * count);
+ memcpy(w, data, sizeof(T) * count);
return ret;
}
@@ -224,7 +223,7 @@ public:
Vector<uint8_t> ret;
ret.resize(count * sizeof(T));
uint8_t *w = ret.ptrw();
- copymem(w, data, sizeof(T) * count);
+ memcpy(w, data, sizeof(T) * count);
return ret;
}
diff --git a/core/templates/oa_hash_map.h b/core/templates/oa_hash_map.h
index 1d4176eb10..025cc30db4 100644
--- a/core/templates/oa_hash_map.h
+++ b/core/templates/oa_hash_map.h
@@ -32,7 +32,6 @@
#define OA_HASH_MAP_H
#include "core/math/math_funcs.h"
-#include "core/os/copymem.h"
#include "core/os/memory.h"
#include "core/templates/hashfuncs.h"
@@ -232,7 +231,7 @@ public:
/**
* returns true if the value was found, false otherwise.
*
- * if r_data is not nullptr 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 {
@@ -250,7 +249,7 @@ public:
/**
* returns true if the value was found, false otherwise.
*
- * if r_data is not nullptr 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 {
diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h
index 7002034710..481289309f 100644
--- a/core/templates/paged_allocator.h
+++ b/core/templates/paged_allocator.h
@@ -35,6 +35,8 @@
#include "core/os/spin_lock.h"
#include "core/typedefs.h"
+#include <type_traits>
+
template <class T, bool thread_safe = false>
class PagedAllocator {
T **page_pool = nullptr;
@@ -89,8 +91,10 @@ public:
allocs_available++;
}
- void reset() {
- ERR_FAIL_COND(allocs_available < pages_allocated * page_size);
+ void reset(bool p_allow_unfreed = false) {
+ if (!p_allow_unfreed || !std::is_trivially_destructible<T>::value) {
+ ERR_FAIL_COND(allocs_available < pages_allocated * page_size);
+ }
if (pages_allocated) {
for (uint32_t i = 0; i < pages_allocated; i++) {
memfree(page_pool[i]);
diff --git a/servers/physics_3d/broad_phase_3d_basic.h b/core/templates/pooled_list.h
index 54d34e005f..b4a6d2d1dd 100644
--- a/servers/physics_3d/broad_phase_3d_basic.h
+++ b/core/templates/pooled_list.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* broad_phase_3d_basic.h */
+/* pooled_list.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,78 +28,68 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BROAD_PHASE_BASIC_H
-#define BROAD_PHASE_BASIC_H
+#pragma once
-#include "broad_phase_3d_sw.h"
-#include "core/templates/map.h"
+// Simple template to provide a pool with O(1) allocate and free.
+// The freelist could alternatively be a linked list placed within the unused elements
+// to use less memory, however a separate freelist is probably more cache friendly.
-class BroadPhase3DBasic : public BroadPhase3DSW {
- struct Element {
- CollisionObject3DSW *owner;
- bool _static;
- AABB aabb;
- int subindex;
- };
+// NOTE : Take great care when using this with non POD types. The construction and destruction
+// is done in the LocalVector, NOT as part of the pool. So requesting a new item does not guarantee
+// a constructor is run, and free does not guarantee a destructor.
+// You should generally handle clearing
+// an item explicitly after a request, as it may contain 'leftovers'.
+// This is by design for fastest use in the BVH. If you want a more general pool
+// that does call constructors / destructors on request / free, this should probably be
+// a separate template.
- Map<ID, Element> element_map;
+#include "core/templates/local_vector.h"
- ID current;
+template <class T, bool force_trivial = false>
+class PooledList {
+ LocalVector<T, uint32_t, force_trivial> list;
+ LocalVector<uint32_t, uint32_t, true> freelist;
- 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;
+ // not all list members are necessarily used
+ int _used_size;
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();
+ PooledList() {
+ _used_size = 0;
+ }
+
+ int estimate_memory_use() const {
+ return (list.size() * sizeof(T)) + (freelist.size() * sizeof(uint32_t));
+ }
+
+ const T &operator[](uint32_t p_index) const {
+ return list[p_index];
+ }
+ T &operator[](uint32_t p_index) {
+ return list[p_index];
+ }
+
+ int size() const { return _used_size; }
+
+ T *request(uint32_t &r_id) {
+ _used_size++;
+
+ if (freelist.size()) {
+ // pop from freelist
+ int new_size = freelist.size() - 1;
+ r_id = freelist[new_size];
+ freelist.resize(new_size);
+ return &list[r_id];
+ }
- static BroadPhase3DSW *_create();
- BroadPhase3DBasic();
+ r_id = list.size();
+ list.resize(r_id + 1);
+ return &list[r_id];
+ }
+ void free(const uint32_t &p_id) {
+ // should not be on free list already
+ CRASH_COND(p_id >= list.size());
+ freelist.push_back(p_id);
+ _used_size--;
+ }
};
-
-#endif // BROAD_PHASE_BASIC_H
diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h
index 91a34ecd54..e9e5695f80 100644
--- a/core/templates/safe_refcount.h
+++ b/core/templates/safe_refcount.h
@@ -36,6 +36,7 @@
#if !defined(NO_THREADS)
#include <atomic>
+#include <type_traits>
// Design goals for these classes:
// - No automatic conversions or arithmetic operators,
diff --git a/core/templates/vector.h b/core/templates/vector.h
index a56a941dbc..dae8874a87 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -38,7 +38,6 @@
*/
#include "core/error/error_macros.h"
-#include "core/os/copymem.h"
#include "core/os/memory.h"
#include "core/templates/cowdata.h"
#include "core/templates/sort_array.h"
@@ -66,6 +65,7 @@ private:
public:
bool push_back(T p_elem);
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } //alias
+ void fill(T p_elem);
void remove(int p_index) { _cowdata.remove(p_index); }
void erase(const T &p_val) {
@@ -134,7 +134,7 @@ public:
Vector<uint8_t> to_byte_array() const {
Vector<uint8_t> ret;
ret.resize(size() * sizeof(T));
- copymem(ret.ptrw(), ptr(), sizeof(T) * size());
+ memcpy(ret.ptrw(), ptr(), sizeof(T) * size());
return ret;
}
@@ -223,4 +223,12 @@ bool Vector<T>::push_back(T p_elem) {
return false;
}
+template <class T>
+void Vector<T>::fill(T p_elem) {
+ T *p = ptrw();
+ for (int i = 0; i < size(); i++) {
+ p[i] = p_elem;
+ }
+}
+
#endif // VECTOR_H
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 2ad728ec5e..09cf785390 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -208,6 +208,11 @@ void Array::insert(int p_pos, const Variant &p_value) {
_p->array.insert(p_pos, p_value);
}
+void Array::fill(const Variant &p_value) {
+ ERR_FAIL_COND(!_p->typed.validate(p_value, "fill"));
+ _p->array.fill(p_value);
+}
+
void Array::erase(const Variant &p_value) {
ERR_FAIL_COND(!_p->typed.validate(p_value, "erase"));
_p->array.erase(p_value);
@@ -356,6 +361,79 @@ Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const { // l
return new_arr;
}
+Array Array::filter(const Callable &p_callable) const {
+ Array new_arr;
+ new_arr.resize(size());
+ int accepted_count = 0;
+
+ const Variant *argptrs[1];
+ for (int i = 0; i < size(); i++) {
+ argptrs[0] = &get(i);
+
+ Variant result;
+ Callable::CallError ce;
+ p_callable.call(argptrs, 1, result, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_FAIL_V_MSG(Array(), "Error calling method from 'filter': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));
+ }
+
+ if (result.operator bool()) {
+ new_arr[accepted_count] = get(i);
+ accepted_count++;
+ }
+ }
+
+ new_arr.resize(accepted_count);
+
+ return new_arr;
+}
+
+Array Array::map(const Callable &p_callable) const {
+ Array new_arr;
+ new_arr.resize(size());
+
+ const Variant *argptrs[1];
+ for (int i = 0; i < size(); i++) {
+ argptrs[0] = &get(i);
+
+ Variant result;
+ Callable::CallError ce;
+ p_callable.call(argptrs, 1, result, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_FAIL_V_MSG(Array(), "Error calling method from 'map': " + Variant::get_callable_error_text(p_callable, argptrs, 1, ce));
+ }
+
+ new_arr[i] = result;
+ }
+
+ return new_arr;
+}
+
+Variant Array::reduce(const Callable &p_callable, const Variant &p_accum) const {
+ int start = 0;
+ Variant ret = p_accum;
+ if (ret == Variant() && size() > 0) {
+ ret = front();
+ start = 1;
+ }
+
+ const Variant *argptrs[2];
+ for (int i = start; i < size(); i++) {
+ argptrs[0] = &ret;
+ argptrs[1] = &get(i);
+
+ Variant result;
+ Callable::CallError ce;
+ p_callable.call(argptrs, 2, result, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_FAIL_V_MSG(Variant(), "Error calling method from 'reduce': " + Variant::get_callable_error_text(p_callable, argptrs, 2, ce));
+ }
+ ret = result;
+ }
+
+ return ret;
+}
+
struct _ArrayVariantSort {
_FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {
bool valid = false;
diff --git a/core/variant/array.h b/core/variant/array.h
index 6b58ed12cb..540dcb1f4e 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -74,6 +74,7 @@ public:
void insert(int p_pos, const Variant &p_value);
void remove(int p_pos);
+ void fill(const Variant &p_value);
Variant front() const;
Variant back() const;
@@ -100,6 +101,9 @@ public:
Array duplicate(bool p_deep = false) const;
Array slice(int p_begin, int p_end, int p_step = 1, bool p_deep = false) const;
+ Array filter(const Callable &p_callable) const;
+ Array map(const Callable &p_callable) const;
+ Variant reduce(const Callable &p_callable, const Variant &p_accum) const;
bool operator<(const Array &p_array) const;
bool operator<=(const Array &p_array) const;
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index 86bbf43266..830e0a5cbd 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -122,6 +122,18 @@ struct VariantObjectClassChecker {
}
};
+template <typename T>
+class Ref;
+
+template <typename T>
+struct VariantObjectClassChecker<const Ref<T> &> {
+ static _FORCE_INLINE_ bool check(const Variant &p_variant) {
+ Object *obj = p_variant;
+ const Ref<T> node = p_variant;
+ return node.ptr() || !obj;
+ }
+};
+
template <>
struct VariantObjectClassChecker<Node *> {
static _FORCE_INLINE_ bool check(const Variant &p_variant) {
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index a1d9c5ed2f..34b3e3ea35 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -33,7 +33,7 @@
#include "callable_bind.h"
#include "core/object/message_queue.h"
#include "core/object/object.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
void Callable::call_deferred(const Variant **p_arguments, int p_argcount) const {
@@ -50,10 +50,33 @@ void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_retu
custom->call(p_arguments, p_argcount, r_return_value, r_call_error);
} else {
Object *obj = ObjectDB::get_instance(ObjectID(object));
+#ifdef DEBUG_ENABLED
+ if (!obj) {
+ r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ r_return_value = Variant();
+ return;
+ }
+#endif
r_return_value = obj->call(method, p_arguments, p_argcount, r_call_error);
}
}
+void Callable::rpc(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const {
+ if (is_null()) {
+ r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ } else if (!is_custom()) {
+ r_call_error.error = CallError::CALL_ERROR_INVALID_METHOD;
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ } else {
+ custom->rpc(p_id, p_arguments, p_argcount, r_call_error);
+ }
+}
+
Callable Callable::bind(const Variant **p_arguments, int p_argcount) const {
Vector<Variant> args;
args.resize(p_argcount);
@@ -283,6 +306,12 @@ Callable::~Callable() {
}
}
+void CallableCustom::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
+ r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+}
+
const Callable *CallableCustom::get_base_comparator() const {
return nullptr;
}
diff --git a/core/variant/callable.h b/core/variant/callable.h
index 090fd888e2..20d0804292 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -44,9 +44,9 @@ class CallableCustom;
// is required. It is designed for the standard case (object and method)
// but can be optimized or customized.
+// Enforce 16 bytes with `alignas` to avoid arch-specific alignment issues on x86 vs armv7.
class Callable {
- //needs to be max 16 bytes in 64 bits
- StringName method;
+ alignas(8) StringName method;
union {
uint64_t object = 0;
CallableCustom *custom;
@@ -70,6 +70,8 @@ public:
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const;
void call_deferred(const Variant **p_arguments, int p_argcount) const;
+ void rpc(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const;
+
_FORCE_INLINE_ bool is_null() const {
return method == StringName() && object == 0;
}
@@ -124,6 +126,7 @@ public:
virtual CompareLessFunc get_compare_less_func() const = 0;
virtual ObjectID get_object() const = 0; //must always be able to provide an object
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const = 0;
+ virtual void rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const;
virtual const Callable *get_base_comparator() const;
CallableCustom();
@@ -135,8 +138,9 @@ public:
// be put inside a Variant, but it is not
// used by the engine itself.
+// Enforce 16 bytes with `alignas` to avoid arch-specific alignment issues on x86 vs armv7.
class Signal {
- StringName name;
+ alignas(8) StringName name;
ObjectID object;
public:
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
index c294592b63..d4ec5e570c 100644
--- a/core/variant/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -122,10 +122,10 @@ MAKE_PTRARG_BY_REFERENCE(Vector3);
MAKE_PTRARG_BY_REFERENCE(Vector3i);
MAKE_PTRARG(Transform2D);
MAKE_PTRARG_BY_REFERENCE(Plane);
-MAKE_PTRARG(Quat);
+MAKE_PTRARG(Quaternion);
MAKE_PTRARG_BY_REFERENCE(AABB);
MAKE_PTRARG_BY_REFERENCE(Basis);
-MAKE_PTRARG_BY_REFERENCE(Transform);
+MAKE_PTRARG_BY_REFERENCE(Transform3D);
MAKE_PTRARG_BY_REFERENCE(Color);
MAKE_PTRARG(StringName);
MAKE_PTRARG(NodePath);
@@ -364,7 +364,7 @@ MAKE_VECARR(Plane);
} \
}
-// Special case for IP_Address.
+// Special case for IPAddress.
#define MAKE_STRINGCONV_BY_REFERENCE(m_type) \
template <> \
@@ -387,7 +387,7 @@ MAKE_VECARR(Plane);
} \
}
-MAKE_STRINGCONV_BY_REFERENCE(IP_Address);
+MAKE_STRINGCONV_BY_REFERENCE(IPAddress);
template <>
struct PtrToArg<Vector<Face3>> {
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index f61ff29b8f..76cb065d10 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -146,10 +146,10 @@ 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)
+MAKE_TYPE_INFO(Quaternion, Variant::QUATERNION)
MAKE_TYPE_INFO(AABB, Variant::AABB)
MAKE_TYPE_INFO(Basis, Variant::BASIS)
-MAKE_TYPE_INFO(Transform, Variant::TRANSFORM)
+MAKE_TYPE_INFO(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPE_INFO(Color, Variant::COLOR)
MAKE_TYPE_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPE_INFO(NodePath, Variant::NODE_PATH)
@@ -168,7 +168,7 @@ MAKE_TYPE_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPE_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPE_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
-MAKE_TYPE_INFO(IP_Address, Variant::STRING)
+MAKE_TYPE_INFO(IPAddress, Variant::STRING)
//objectID
template <>
diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h
index e0309aa3fe..900dcf7689 100644
--- a/core/variant/typed_array.h
+++ b/core/variant/typed_array.h
@@ -98,10 +98,10 @@ MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY(Plane, Variant::PLANE)
-MAKE_TYPED_ARRAY(Quat, Variant::QUAT)
+MAKE_TYPED_ARRAY(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY(AABB, Variant::AABB)
MAKE_TYPED_ARRAY(Basis, Variant::BASIS)
-MAKE_TYPED_ARRAY(Transform, Variant::TRANSFORM)
+MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY(Color, Variant::COLOR)
MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH)
@@ -196,10 +196,10 @@ MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE)
-MAKE_TYPED_ARRAY_INFO(Quat, Variant::QUAT)
+MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
-MAKE_TYPED_ARRAY_INFO(Transform, Variant::TRANSFORM)
+MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 015cee09a7..4e45862fd3 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -91,16 +91,16 @@ String Variant::get_type_name(Variant::Type p_type) {
case AABB: {
return "AABB";
} break;
- case QUAT: {
- return "Quat";
+ case QUATERNION: {
+ return "Quaternion";
} break;
case BASIS: {
return "Basis";
} break;
- case TRANSFORM: {
- return "Transform";
+ case TRANSFORM3D: {
+ return "Transform3D";
} break;
@@ -275,7 +275,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) {
} break;
case TRANSFORM2D: {
static const Type valid[] = {
- TRANSFORM,
+ TRANSFORM3D,
NIL
};
@@ -300,7 +300,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) {
} break;
- case QUAT: {
+ case QUATERNION: {
static const Type valid[] = {
BASIS,
NIL
@@ -311,7 +311,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) {
} break;
case BASIS: {
static const Type valid[] = {
- QUAT,
+ QUATERNION,
VECTOR3,
NIL
};
@@ -319,10 +319,10 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) {
valid_types = valid;
} break;
- case TRANSFORM: {
+ case TRANSFORM3D: {
static const Type valid[] = {
TRANSFORM2D,
- QUAT,
+ QUATERNION,
BASIS,
NIL
};
@@ -582,7 +582,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type
} break;
case TRANSFORM2D: {
static const Type valid[] = {
- TRANSFORM,
+ TRANSFORM3D,
NIL
};
@@ -607,7 +607,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type
} break;
- case QUAT: {
+ case QUATERNION: {
static const Type valid[] = {
BASIS,
NIL
@@ -618,7 +618,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type
} break;
case BASIS: {
static const Type valid[] = {
- QUAT,
+ QUATERNION,
VECTOR3,
NIL
};
@@ -626,10 +626,10 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type
valid_types = valid;
} break;
- case TRANSFORM: {
+ case TRANSFORM3D: {
static const Type valid[] = {
TRANSFORM2D,
- QUAT,
+ QUATERNION,
BASIS,
NIL
};
@@ -873,16 +873,16 @@ bool Variant::is_zero() const {
case AABB: {
return *_data._aabb == ::AABB();
} break;
- case QUAT: {
- return *reinterpret_cast<const Quat *>(_data._mem) == Quat();
+ case QUATERNION: {
+ return *reinterpret_cast<const Quaternion *>(_data._mem) == Quaternion();
} break;
case BASIS: {
return *_data._basis == Basis();
} break;
- case TRANSFORM: {
- return *_data._transform == Transform();
+ case TRANSFORM3D: {
+ return *_data._transform3d == Transform3D();
} break;
@@ -1092,16 +1092,16 @@ void Variant::reference(const Variant &p_variant) {
case AABB: {
_data._aabb = memnew(::AABB(*p_variant._data._aabb));
} break;
- case QUAT: {
- memnew_placement(_data._mem, Quat(*reinterpret_cast<const Quat *>(p_variant._data._mem)));
+ case QUATERNION: {
+ memnew_placement(_data._mem, Quaternion(*reinterpret_cast<const Quaternion *>(p_variant._data._mem)));
} break;
case BASIS: {
_data._basis = memnew(Basis(*p_variant._data._basis));
} break;
- case TRANSFORM: {
- _data._transform = memnew(Transform(*p_variant._data._transform));
+ case TRANSFORM3D: {
+ _data._transform3d = memnew(Transform3D(*p_variant._data._transform3d));
} break;
// misc types
@@ -1115,9 +1115,9 @@ void Variant::reference(const Variant &p_variant) {
case OBJECT: {
memnew_placement(_data._mem, ObjData);
- if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) {
- Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj);
- if (!reference->reference()) {
+ if (p_variant._get_obj().obj && p_variant._get_obj().id.is_ref_counted()) {
+ RefCounted *ref_counted = static_cast<RefCounted *>(p_variant._get_obj().obj);
+ if (!ref_counted->reference()) {
_get_obj().obj = nullptr;
_get_obj().id = ObjectID();
break;
@@ -1254,8 +1254,8 @@ void Variant::zero() {
case PLANE:
*reinterpret_cast<Plane *>(this->_data._mem) = Plane();
break;
- case QUAT:
- *reinterpret_cast<Quat *>(this->_data._mem) = Quat();
+ case QUATERNION:
+ *reinterpret_cast<Quaternion *>(this->_data._mem) = Quaternion();
break;
case COLOR:
*reinterpret_cast<Color *>(this->_data._mem) = Color();
@@ -1275,7 +1275,7 @@ void Variant::_clear_internal() {
// no point, they don't allocate memory
VECTOR3,
PLANE,
- QUAT,
+ QUATERNION,
COLOR,
VECTOR2,
RECT2
@@ -1289,8 +1289,8 @@ void Variant::_clear_internal() {
case BASIS: {
memdelete(_data._basis);
} break;
- case TRANSFORM: {
- memdelete(_data._transform);
+ case TRANSFORM3D: {
+ memdelete(_data._transform3d);
} break;
// misc types
@@ -1301,11 +1301,11 @@ void Variant::_clear_internal() {
reinterpret_cast<NodePath *>(_data._mem)->~NodePath();
} break;
case OBJECT: {
- if (_get_obj().id.is_reference()) {
+ if (_get_obj().id.is_ref_counted()) {
//we are safe that there is a reference here
- Reference *reference = static_cast<Reference *>(_get_obj().obj);
- if (reference->unreference()) {
- memdelete(reference);
+ RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj);
+ if (ref_counted->unreference()) {
+ memdelete(ref_counted);
}
}
_get_obj().obj = nullptr;
@@ -1636,60 +1636,35 @@ String Variant::stringify(List<const void *> &stack) const {
case STRING:
return *reinterpret_cast<const String *>(_data._mem);
case VECTOR2:
- return "(" + operator Vector2() + ")";
+ return operator Vector2();
case VECTOR2I:
- return "(" + operator Vector2i() + ")";
+ return operator Vector2i();
case RECT2:
- return "(" + operator Rect2() + ")";
+ return operator Rect2();
case RECT2I:
- return "(" + operator Rect2i() + ")";
- case TRANSFORM2D: {
- Transform2D mat32 = operator Transform2D();
- return "(" + Variant(mat32.elements[0]).operator String() + ", " + Variant(mat32.elements[1]).operator String() + ", " + Variant(mat32.elements[2]).operator String() + ")";
- } break;
+ return operator Rect2i();
+ case TRANSFORM2D:
+ return operator Transform2D();
case VECTOR3:
- return "(" + operator Vector3() + ")";
+ return operator Vector3();
case VECTOR3I:
- return "(" + operator Vector3i() + ")";
+ return operator Vector3i();
case PLANE:
return operator Plane();
- //case QUAT:
case AABB:
return operator ::AABB();
- case QUAT:
- return "(" + operator Quat() + ")";
- case BASIS: {
- Basis mat3 = operator Basis();
-
- String mtx("(");
- for (int i = 0; i < 3; i++) {
- if (i != 0) {
- mtx += ", ";
- }
-
- mtx += "(";
-
- for (int j = 0; j < 3; j++) {
- if (j != 0) {
- mtx += ", ";
- }
-
- mtx += Variant(mat3.elements[i][j]).operator String();
- }
-
- mtx += ")";
- }
-
- return mtx + ")";
- } break;
- case TRANSFORM:
- return operator Transform();
+ case QUATERNION:
+ return operator Quaternion();
+ case BASIS:
+ return operator Basis();
+ case TRANSFORM3D:
+ return operator Transform3D();
case STRING_NAME:
return operator StringName();
case NODE_PATH:
return operator NodePath();
case COLOR:
- return String::num(operator Color().r) + "," + String::num(operator Color().g) + "," + String::num(operator Color().b) + "," + String::num(operator Color().a);
+ return operator Color();
case DICTIONARY: {
const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem);
if (stack.find(d.id())) {
@@ -1723,6 +1698,7 @@ String Variant::stringify(List<const void *> &stack) const {
}
str += "}";
+ stack.erase(d.id());
return str;
} break;
case PACKED_VECTOR2_ARRAY: {
@@ -1826,12 +1802,13 @@ String Variant::stringify(List<const void *> &stack) const {
}
str += "]";
+ stack.erase(arr.id());
return str;
} break;
case OBJECT: {
if (_get_obj().obj) {
- if (!_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ if (!_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
return "[Freed Object]";
}
@@ -1956,39 +1933,39 @@ Variant::operator ::AABB() const {
Variant::operator Basis() const {
if (type == BASIS) {
return *_data._basis;
- } else if (type == QUAT) {
- return *reinterpret_cast<const Quat *>(_data._mem);
+ } else if (type == QUATERNION) {
+ return *reinterpret_cast<const Quaternion *>(_data._mem);
} else if (type == VECTOR3) {
return Basis(*reinterpret_cast<const Vector3 *>(_data._mem));
- } else if (type == TRANSFORM) { // unexposed in Variant::can_convert?
- return _data._transform->basis;
+ } else if (type == TRANSFORM3D) { // unexposed in Variant::can_convert?
+ return _data._transform3d->basis;
} else {
return Basis();
}
}
-Variant::operator Quat() const {
- if (type == QUAT) {
- return *reinterpret_cast<const Quat *>(_data._mem);
+Variant::operator Quaternion() const {
+ if (type == QUATERNION) {
+ return *reinterpret_cast<const Quaternion *>(_data._mem);
} else if (type == BASIS) {
return *_data._basis;
- } else if (type == TRANSFORM) {
- return _data._transform->basis;
+ } else if (type == TRANSFORM3D) {
+ return _data._transform3d->basis;
} else {
- return Quat();
+ return Quaternion();
}
}
-Variant::operator Transform() const {
- if (type == TRANSFORM) {
- return *_data._transform;
+Variant::operator Transform3D() const {
+ if (type == TRANSFORM3D) {
+ return *_data._transform3d;
} else if (type == BASIS) {
- return Transform(*_data._basis, Vector3());
- } else if (type == QUAT) {
- return Transform(Basis(*reinterpret_cast<const Quat *>(_data._mem)), Vector3());
+ return Transform3D(*_data._basis, Vector3());
+ } else if (type == QUATERNION) {
+ return Transform3D(Basis(*reinterpret_cast<const Quaternion *>(_data._mem)), Vector3());
} else if (type == TRANSFORM2D) {
const Transform2D &t = *_data._transform2d;
- Transform m;
+ Transform3D m;
m.basis.elements[0][0] = t.elements[0][0];
m.basis.elements[1][0] = t.elements[0][1];
m.basis.elements[0][1] = t.elements[1][0];
@@ -1997,15 +1974,15 @@ Variant::operator Transform() const {
m.origin[1] = t.elements[2][1];
return m;
} else {
- return Transform();
+ return Transform3D();
}
}
Variant::operator Transform2D() const {
if (type == TRANSFORM2D) {
return *_data._transform2d;
- } else if (type == TRANSFORM) {
- const Transform &t = *_data._transform;
+ } else if (type == TRANSFORM3D) {
+ const Transform3D &t = *_data._transform3d;
Transform2D m;
m.elements[0][0] = t.basis.elements[0][0];
m.elements[0][1] = t.basis.elements[1][0];
@@ -2346,15 +2323,15 @@ Variant::operator Orientation() const {
return (Orientation) operator int();
}
-Variant::operator IP_Address() const {
+Variant::operator IPAddress() const {
if (type == PACKED_FLOAT32_ARRAY || type == PACKED_INT32_ARRAY || type == PACKED_FLOAT64_ARRAY || type == PACKED_INT64_ARRAY || type == PACKED_BYTE_ARRAY) {
Vector<int> addr = operator Vector<int>();
if (addr.size() == 4) {
- return IP_Address(addr.get(0), addr.get(1), addr.get(2), addr.get(3));
+ return IPAddress(addr.get(0), addr.get(1), addr.get(2), addr.get(3));
}
}
- return IP_Address(operator String());
+ return IPAddress(operator String());
}
Variant::Variant(bool p_bool) {
@@ -2495,14 +2472,14 @@ Variant::Variant(const Basis &p_matrix) {
_data._basis = memnew(Basis(p_matrix));
}
-Variant::Variant(const Quat &p_quat) {
- type = QUAT;
- memnew_placement(_data._mem, Quat(p_quat));
+Variant::Variant(const Quaternion &p_quaternion) {
+ type = QUATERNION;
+ memnew_placement(_data._mem, Quaternion(p_quaternion));
}
-Variant::Variant(const Transform &p_transform) {
- type = TRANSFORM;
- _data._transform = memnew(Transform(p_transform));
+Variant::Variant(const Transform3D &p_transform) {
+ type = TRANSFORM3D;
+ _data._transform3d = memnew(Transform3D(p_transform));
}
Variant::Variant(const Transform2D &p_transform) {
@@ -2531,9 +2508,9 @@ Variant::Variant(const Object *p_object) {
memnew_placement(_data._mem, ObjData);
if (p_object) {
- if (p_object->is_reference()) {
- Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(p_object));
- if (!reference->init_ref()) {
+ if (p_object->is_ref_counted()) {
+ RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_object));
+ if (!ref_counted->init_ref()) {
_get_obj().obj = nullptr;
_get_obj().id = ObjectID();
return;
@@ -2739,14 +2716,14 @@ void Variant::operator=(const Variant &p_variant) {
case AABB: {
*_data._aabb = *(p_variant._data._aabb);
} break;
- case QUAT: {
- *reinterpret_cast<Quat *>(_data._mem) = *reinterpret_cast<const Quat *>(p_variant._data._mem);
+ case QUATERNION: {
+ *reinterpret_cast<Quaternion *>(_data._mem) = *reinterpret_cast<const Quaternion *>(p_variant._data._mem);
} break;
case BASIS: {
*_data._basis = *(p_variant._data._basis);
} break;
- case TRANSFORM: {
- *_data._transform = *(p_variant._data._transform);
+ case TRANSFORM3D: {
+ *_data._transform3d = *(p_variant._data._transform3d);
} break;
// misc types
@@ -2757,17 +2734,17 @@ void Variant::operator=(const Variant &p_variant) {
*reinterpret_cast<::RID *>(_data._mem) = *reinterpret_cast<const ::RID *>(p_variant._data._mem);
} break;
case OBJECT: {
- if (_get_obj().id.is_reference()) {
+ if (_get_obj().id.is_ref_counted()) {
//we are safe that there is a reference here
- Reference *reference = static_cast<Reference *>(_get_obj().obj);
- if (reference->unreference()) {
- memdelete(reference);
+ RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj);
+ if (ref_counted->unreference()) {
+ memdelete(ref_counted);
}
}
- if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) {
- Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj);
- if (!reference->reference()) {
+ if (p_variant._get_obj().obj && p_variant._get_obj().id.is_ref_counted()) {
+ RefCounted *ref_counted = static_cast<RefCounted *>(p_variant._get_obj().obj);
+ if (!ref_counted->reference()) {
_get_obj().obj = nullptr;
_get_obj().id = ObjectID();
break;
@@ -2831,7 +2808,7 @@ void Variant::operator=(const Variant &p_variant) {
}
}
-Variant::Variant(const IP_Address &p_address) {
+Variant::Variant(const IPAddress &p_address) {
type = STRING;
memnew_placement(_data._mem, String(p_address));
}
@@ -2916,11 +2893,11 @@ uint32_t Variant::hash() const {
return hash;
} break;
- case QUAT: {
- uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->x);
- hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->y, hash);
- hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->z, hash);
- return hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->w, hash);
+ case QUATERNION: {
+ uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->x);
+ hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->y, hash);
+ hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->z, hash);
+ return hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->w, hash);
} break;
case BASIS: {
@@ -2934,13 +2911,13 @@ uint32_t Variant::hash() const {
return hash;
} break;
- case TRANSFORM: {
+ case TRANSFORM3D: {
uint32_t hash = 5831;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- hash = hash_djb2_one_float(_data._transform->basis.elements[i][j], hash);
+ hash = hash_djb2_one_float(_data._transform3d->basis.elements[i][j], hash);
}
- hash = hash_djb2_one_float(_data._transform->origin[i], hash);
+ hash = hash_djb2_one_float(_data._transform3d->origin[i], hash);
}
return hash;
@@ -3127,7 +3104,7 @@ uint32_t Variant::hash() const {
(hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \
(hash_compare_scalar((p_lhs).z, (p_rhs).z))
-#define hash_compare_quat(p_lhs, p_rhs) \
+#define hash_compare_quaternion(p_lhs, p_rhs) \
(hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \
(hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \
(hash_compare_scalar((p_lhs).z, (p_rhs).z)) && \
@@ -3235,11 +3212,11 @@ bool Variant::hash_compare(const Variant &p_variant) const {
} break;
- case QUAT: {
- const Quat *l = reinterpret_cast<const Quat *>(_data._mem);
- const Quat *r = reinterpret_cast<const Quat *>(p_variant._data._mem);
+ case QUATERNION: {
+ const Quaternion *l = reinterpret_cast<const Quaternion *>(_data._mem);
+ const Quaternion *r = reinterpret_cast<const Quaternion *>(p_variant._data._mem);
- return hash_compare_quat(*l, *r);
+ return hash_compare_quaternion(*l, *r);
} break;
case BASIS: {
@@ -3255,9 +3232,9 @@ bool Variant::hash_compare(const Variant &p_variant) const {
return true;
} break;
- case TRANSFORM: {
- const Transform *l = _data._transform;
- const Transform *r = p_variant._data._transform;
+ case TRANSFORM3D: {
+ const Transform3D *l = _data._transform3d;
+ const Transform3D *r = p_variant._data._transform3d;
for (int i = 0; i < 3; i++) {
if (!(hash_compare_vector3(l->basis.elements[i], r->basis.elements[i]))) {
@@ -3324,7 +3301,7 @@ bool Variant::hash_compare(const Variant &p_variant) const {
}
bool Variant::is_ref() const {
- return type == OBJECT && _get_obj().id.is_reference();
+ return type == OBJECT && _get_obj().id.is_ref_counted();
}
Vector<Variant> varray() {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 0acafc64fa..75316da63f 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -37,9 +37,9 @@
#include "core/math/color.h"
#include "core/math/face3.h"
#include "core/math/plane.h"
-#include "core/math/quat.h"
-#include "core/math/transform.h"
+#include "core/math/quaternion.h"
#include "core/math/transform_2d.h"
+#include "core/math/transform_3d.h"
#include "core/math/vector3.h"
#include "core/math/vector3i.h"
#include "core/object/object_id.h"
@@ -88,10 +88,10 @@ public:
VECTOR3I,
TRANSFORM2D,
PLANE,
- QUAT,
+ QUATERNION,
AABB,
BASIS,
- TRANSFORM,
+ TRANSFORM3D,
// misc types
COLOR,
@@ -200,7 +200,7 @@ private:
Transform2D *_transform2d;
::AABB *_aabb;
Basis *_basis;
- Transform *_transform;
+ Transform3D *_transform3d;
PackedArrayRefBase *packed_array;
void *_ptr; //generic pointer
uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)];
@@ -225,7 +225,7 @@ private:
false, //VECTOR3I,
true, //TRANSFORM2D,
false, //PLANE,
- false, //QUAT,
+ false, //QUATERNION,
true, //AABB,
true, //BASIS,
true, //TRANSFORM,
@@ -320,10 +320,10 @@ public:
operator Vector3i() const;
operator Plane() const;
operator ::AABB() const;
- operator Quat() const;
+ operator Quaternion() const;
operator Basis() const;
- operator Transform() const;
operator Transform2D() const;
+ operator Transform3D() const;
operator Color() const;
operator NodePath() const;
@@ -359,7 +359,7 @@ public:
operator Side() const;
operator Orientation() const;
- operator IP_Address() const;
+ operator IPAddress() const;
Object *get_validated_object() const;
Object *get_validated_object_with_check(bool &r_previously_freed) const;
@@ -392,10 +392,10 @@ public:
Variant(const Vector3i &p_vector3i);
Variant(const Plane &p_plane);
Variant(const ::AABB &p_aabb);
- Variant(const Quat &p_quat);
+ Variant(const Quaternion &p_quat);
Variant(const Basis &p_matrix);
Variant(const Transform2D &p_transform);
- Variant(const Transform &p_transform);
+ Variant(const Transform3D &p_transform);
Variant(const Color &p_color);
Variant(const NodePath &p_node_path);
Variant(const ::RID &p_rid);
@@ -421,7 +421,7 @@ public:
Variant(const Vector<::RID> &p_array); // helper
Variant(const Vector<Vector2> &p_array); // helper
- Variant(const IP_Address &p_address);
+ Variant(const IPAddress &p_address);
// If this changes the table in variant_op must be updated
enum Operator {
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 7f83e27dfe..05ed35c760 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -493,6 +493,58 @@ static _FORCE_INLINE_ void vc_ptrcall(void (*method)(T *, P...), void *p_base, c
} \
};
+#define VARARG_CLASS1(m_class, m_method_name, m_method_ptr, m_arg_type) \
+ struct Method_##m_class##_##m_method_name { \
+ static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
+ m_method_ptr(base, p_args, p_argcount, r_ret, r_error); \
+ } \
+ static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
+ Callable::CallError ce; \
+ m_method_ptr(base, p_args, p_argcount, *r_ret, ce); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ LocalVector<Variant> vars; \
+ vars.resize(p_argcount); \
+ LocalVector<const Variant *> vars_ptrs; \
+ vars_ptrs.resize(p_argcount); \
+ for (int i = 0; i < p_argcount; i++) { \
+ vars[i] = PtrToArg<Variant>::convert(p_args[i]); \
+ vars_ptrs[i] = &vars[i]; \
+ } \
+ Variant base = PtrToArg<m_class>::convert(p_base); \
+ Variant ret; \
+ Callable::CallError ce; \
+ m_method_ptr(&base, (const Variant **)&vars_ptrs[0], p_argcount, ret, ce); \
+ } \
+ static int get_argument_count() { \
+ return 1; \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return m_arg_type; \
+ } \
+ static Variant::Type get_return_type() { \
+ return Variant::NIL; \
+ } \
+ static bool has_return_type() { \
+ return false; \
+ } \
+ static bool is_const() { \
+ return true; \
+ } \
+ static bool is_static() { \
+ return false; \
+ } \
+ static bool is_vararg() { \
+ return true; \
+ } \
+ static Variant::Type get_base_type() { \
+ return GetTypeInfo<m_class>::VARIANT_TYPE; \
+ } \
+ static StringName get_name() { \
+ return #m_method_name; \
+ } \
+ };
+
struct _VariantCall {
static String func_PackedByteArray_get_string_from_ascii(PackedByteArray *p_instance) {
String s;
@@ -500,7 +552,7 @@ struct _VariantCall {
const uint8_t *r = p_instance->ptr();
CharString cs;
cs.resize(p_instance->size() + 1);
- copymem(cs.ptrw(), r, p_instance->size());
+ memcpy(cs.ptrw(), r, p_instance->size());
cs[p_instance->size()] = 0;
s = cs.get_data();
@@ -559,6 +611,9 @@ struct _VariantCall {
if (buffer_size <= 0) {
ERR_FAIL_V_MSG(decompressed, "Decompression buffer size must be greater than zero.");
}
+ if (p_instance->size() == 0) {
+ ERR_FAIL_V_MSG(decompressed, "Compressed buffer size must be greater than zero.");
+ }
decompressed.resize(buffer_size);
int result = Compression::decompress(decompressed.ptrw(), buffer_size, p_instance->ptr(), p_instance->size(), mode);
@@ -792,6 +847,27 @@ struct _VariantCall {
callable->call_deferred(p_args, p_argcount);
}
+ static void func_Callable_rpc(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ callable->rpc(0, p_args, p_argcount, r_error);
+ }
+
+ static void func_Callable_rpc_id(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ if (p_argcount == 0) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ r_error.expected = 1;
+
+ } else if (p_args[0]->get_type() != Variant::INT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::INT;
+ } else {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ callable->rpc(*p_args[0], &p_args[1], p_argcount - 1, r_error);
+ }
+ }
+
static void func_Callable_bind(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
r_ret = callable->bind(p_args, p_argcount);
@@ -896,7 +972,7 @@ void Variant::call(const StringName &p_method, const Variant **p_args, int p_arg
return;
}
#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
return;
}
@@ -1219,6 +1295,10 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va
VARARG_CLASS(m_type, m_name, m_method, m_has_return, m_ret_type) \
register_builtin_method<Method_##m_type##_##m_name>(sarray(), Vector<Variant>());
+#define bind_custom1(m_type, m_name, m_method, m_arg_type, m_arg_name) \
+ VARARG_CLASS1(m_type, m_name, m_method, m_arg_type) \
+ register_builtin_method<Method_##m_type##_##m_name>(sarray(m_arg_name), Vector<Variant>());
+
static void _register_variant_builtin_methods() {
_VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX);
builtin_method_info = memnew_arr(BuiltinMethodMap, Variant::VARIANT_MAX);
@@ -1285,7 +1365,7 @@ static void _register_variant_builtin_methods() {
// FIXME: Static function, not sure how to bind
//bind_method(String, humanize_size, sarray("size"), varray());
- bind_method(String, is_abs_path, sarray(), varray());
+ bind_method(String, is_absolute_path, sarray(), varray());
bind_method(String, is_rel_path, sarray(), varray());
bind_method(String, get_base_dir, sarray(), varray());
bind_method(String, get_file, sarray(), varray());
@@ -1339,6 +1419,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, distance_squared_to, sarray("to"), varray());
bind_method(Vector2, length, sarray(), varray());
bind_method(Vector2, length_squared, sarray(), varray());
+ bind_method(Vector2, limit_length, sarray("length"), varray(1.0));
bind_method(Vector2, normalized, sarray(), varray());
bind_method(Vector2, is_normalized, sarray(), varray());
bind_method(Vector2, is_equal_approx, sarray("to"), varray());
@@ -1362,14 +1443,15 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, cross, sarray("with"), varray());
bind_method(Vector2, abs, sarray(), varray());
bind_method(Vector2, sign, sarray(), varray());
+ bind_method(Vector2, clamp, sarray("min", "max"), varray());
bind_method(Vector2, snapped, sarray("step"), varray());
- bind_method(Vector2, clamped, sarray("length"), varray());
/* Vector2i */
bind_method(Vector2i, aspect, sarray(), varray());
bind_method(Vector2i, sign, sarray(), varray());
bind_method(Vector2i, abs, sarray(), varray());
+ bind_method(Vector2i, clamp, sarray("min", "max"), varray());
/* Rect2 */
@@ -1413,10 +1495,12 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, distance_squared_to, sarray("b"), varray());
bind_method(Vector3, length, sarray(), varray());
bind_method(Vector3, length_squared, sarray(), varray());
+ bind_method(Vector3, limit_length, sarray("length"), varray(1.0));
bind_method(Vector3, normalized, sarray(), varray());
bind_method(Vector3, is_normalized, sarray(), varray());
bind_method(Vector3, is_equal_approx, sarray("to"), varray());
bind_method(Vector3, inverse, sarray(), varray());
+ bind_method(Vector3, clamp, sarray("min", "max"), varray());
bind_method(Vector3, snapped, sarray("step"), varray());
bind_method(Vector3, rotated, sarray("by_axis", "phi"), varray());
bind_method(Vector3, lerp, sarray("to", "weight"), varray());
@@ -1445,6 +1529,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3i, max_axis, sarray(), varray());
bind_method(Vector3i, sign, sarray(), varray());
bind_method(Vector3i, abs, sarray(), varray());
+ bind_method(Vector3i, clamp, sarray("min", "max"), varray());
/* Plane */
@@ -1459,19 +1544,19 @@ static void _register_variant_builtin_methods() {
bind_methodv(Plane, intersects_ray, &Plane::intersects_ray_bind, sarray("from", "dir"), varray());
bind_methodv(Plane, intersects_segment, &Plane::intersects_segment_bind, sarray("from", "to"), varray());
- /* Quat */
+ /* Quaternion */
- bind_method(Quat, length, sarray(), varray());
- bind_method(Quat, length_squared, sarray(), varray());
- bind_method(Quat, normalized, sarray(), varray());
- bind_method(Quat, is_normalized, sarray(), varray());
- bind_method(Quat, is_equal_approx, sarray("to"), varray());
- bind_method(Quat, inverse, sarray(), varray());
- bind_method(Quat, dot, sarray("with"), varray());
- bind_method(Quat, slerp, sarray("to", "weight"), varray());
- bind_method(Quat, slerpni, sarray("to", "weight"), varray());
- bind_method(Quat, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray());
- bind_method(Quat, get_euler, sarray(), varray());
+ bind_method(Quaternion, length, sarray(), varray());
+ bind_method(Quaternion, length_squared, sarray(), varray());
+ bind_method(Quaternion, normalized, sarray(), varray());
+ bind_method(Quaternion, is_normalized, sarray(), varray());
+ bind_method(Quaternion, is_equal_approx, sarray("to"), varray());
+ bind_method(Quaternion, inverse, sarray(), varray());
+ bind_method(Quaternion, dot, sarray("with"), varray());
+ bind_method(Quaternion, slerp, sarray("to", "weight"), varray());
+ bind_method(Quaternion, slerpni, sarray("to", "weight"), varray());
+ bind_method(Quaternion, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray());
+ bind_method(Quaternion, get_euler, sarray(), varray());
/* Color */
@@ -1482,6 +1567,7 @@ static void _register_variant_builtin_methods() {
bind_method(Color, to_abgr64, sarray(), varray());
bind_method(Color, to_rgba64, sarray(), varray());
+ bind_method(Color, clamp, sarray("min", "max"), varray(Color(0, 0, 0, 0), Color(1, 1, 1, 1)));
bind_method(Color, inverted, sarray(), varray());
bind_method(Color, lerp, sarray("to", "weight"), varray());
bind_method(Color, lightened, sarray("amount"), varray());
@@ -1532,6 +1618,8 @@ static void _register_variant_builtin_methods() {
bind_custom(Callable, call, _VariantCall::func_Callable_call, true, Variant);
bind_custom(Callable, call_deferred, _VariantCall::func_Callable_call_deferred, false, Variant);
+ bind_custom(Callable, rpc, _VariantCall::func_Callable_rpc, false, Variant);
+ bind_custom1(Callable, rpc_id, _VariantCall::func_Callable_rpc_id, Variant::INT, "peer_id");
bind_custom(Callable, bind, _VariantCall::func_Callable_bind, true, Callable);
/* Signal */
@@ -1563,6 +1651,8 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform2D, is_equal_approx, sarray("xform"), varray());
+ bind_method(Transform2D, set_rotation, sarray("rotation"), varray());
+ bind_method(Transform2D, looking_at, sarray("target"), varray(Transform2D()));
/* Basis */
@@ -1580,7 +1670,7 @@ static void _register_variant_builtin_methods() {
bind_method(Basis, get_orthogonal_index, sarray(), varray());
bind_method(Basis, slerp, sarray("to", "weight"), varray());
bind_method(Basis, is_equal_approx, sarray("b"), varray());
- bind_method(Basis, get_rotation_quat, sarray(), varray());
+ bind_method(Basis, get_rotation_quaternion, sarray(), varray());
/* AABB */
@@ -1608,17 +1698,17 @@ static void _register_variant_builtin_methods() {
bind_methodv(AABB, intersects_segment, &AABB::intersects_segment_bind, sarray("from", "to"), varray());
bind_methodv(AABB, intersects_ray, &AABB::intersects_ray_bind, sarray("from", "dir"), varray());
- /* Transform */
+ /* Transform3D */
- bind_method(Transform, inverse, sarray(), varray());
- bind_method(Transform, affine_inverse, sarray(), varray());
- bind_method(Transform, orthonormalized, sarray(), varray());
- bind_method(Transform, rotated, sarray("axis", "phi"), varray());
- bind_method(Transform, scaled, sarray("scale"), varray());
- bind_method(Transform, translated, sarray("offset"), varray());
- bind_method(Transform, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
- bind_method(Transform, interpolate_with, sarray("xform", "weight"), varray());
- bind_method(Transform, is_equal_approx, sarray("xform"), varray());
+ bind_method(Transform3D, inverse, sarray(), varray());
+ bind_method(Transform3D, affine_inverse, sarray(), varray());
+ bind_method(Transform3D, orthonormalized, sarray(), varray());
+ bind_method(Transform3D, rotated, sarray("axis", "phi"), varray());
+ bind_method(Transform3D, scaled, sarray("scale"), varray());
+ bind_method(Transform3D, translated, sarray("offset"), varray());
+ bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
+ bind_method(Transform3D, interpolate_with, sarray("xform", "weight"), varray());
+ bind_method(Transform3D, is_equal_approx, sarray("xform"), varray());
/* Dictionary */
@@ -1647,6 +1737,7 @@ static void _register_variant_builtin_methods() {
bind_method(Array, resize, sarray("size"), varray());
bind_method(Array, insert, sarray("position", "value"), varray());
bind_method(Array, remove, sarray("position"), varray());
+ bind_method(Array, fill, sarray("value"), varray());
bind_method(Array, erase, sarray("value"), varray());
bind_method(Array, front, sarray(), varray());
bind_method(Array, back, sarray(), varray());
@@ -1665,6 +1756,9 @@ static void _register_variant_builtin_methods() {
bind_method(Array, reverse, sarray(), varray());
bind_method(Array, duplicate, sarray("deep"), varray(false));
bind_method(Array, slice, sarray("begin", "end", "step", "deep"), varray(1, false));
+ bind_method(Array, filter, sarray("method"), varray());
+ bind_method(Array, map, sarray("method"), varray());
+ bind_method(Array, reduce, sarray("method", "accum"), varray(Variant()));
bind_method(Array, max, sarray(), varray());
bind_method(Array, min, sarray(), varray());
@@ -1677,6 +1771,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedByteArray, append_array, sarray("array"), varray());
bind_method(PackedByteArray, remove, sarray("index"), varray());
bind_method(PackedByteArray, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedByteArray, fill, sarray("value"), varray());
bind_method(PackedByteArray, resize, sarray("new_size"), varray());
bind_method(PackedByteArray, has, sarray("value"), varray());
bind_method(PackedByteArray, reverse, sarray(), varray());
@@ -1731,6 +1826,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt32Array, append_array, sarray("array"), varray());
bind_method(PackedInt32Array, remove, sarray("index"), varray());
bind_method(PackedInt32Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedInt32Array, fill, sarray("value"), varray());
bind_method(PackedInt32Array, resize, sarray("new_size"), varray());
bind_method(PackedInt32Array, has, sarray("value"), varray());
bind_method(PackedInt32Array, reverse, sarray(), varray());
@@ -1749,6 +1845,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt64Array, append_array, sarray("array"), varray());
bind_method(PackedInt64Array, remove, sarray("index"), varray());
bind_method(PackedInt64Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedInt64Array, fill, sarray("value"), varray());
bind_method(PackedInt64Array, resize, sarray("new_size"), varray());
bind_method(PackedInt64Array, has, sarray("value"), varray());
bind_method(PackedInt64Array, reverse, sarray(), varray());
@@ -1767,6 +1864,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat32Array, append_array, sarray("array"), varray());
bind_method(PackedFloat32Array, remove, sarray("index"), varray());
bind_method(PackedFloat32Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedFloat32Array, fill, sarray("value"), varray());
bind_method(PackedFloat32Array, resize, sarray("new_size"), varray());
bind_method(PackedFloat32Array, has, sarray("value"), varray());
bind_method(PackedFloat32Array, reverse, sarray(), varray());
@@ -1785,6 +1883,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat64Array, append_array, sarray("array"), varray());
bind_method(PackedFloat64Array, remove, sarray("index"), varray());
bind_method(PackedFloat64Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedFloat64Array, fill, sarray("value"), varray());
bind_method(PackedFloat64Array, resize, sarray("new_size"), varray());
bind_method(PackedFloat64Array, has, sarray("value"), varray());
bind_method(PackedFloat64Array, reverse, sarray(), varray());
@@ -1803,6 +1902,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedStringArray, append_array, sarray("array"), varray());
bind_method(PackedStringArray, remove, sarray("index"), varray());
bind_method(PackedStringArray, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedStringArray, fill, sarray("value"), varray());
bind_method(PackedStringArray, resize, sarray("new_size"), varray());
bind_method(PackedStringArray, has, sarray("value"), varray());
bind_method(PackedStringArray, reverse, sarray(), varray());
@@ -1821,6 +1921,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector2Array, append_array, sarray("array"), varray());
bind_method(PackedVector2Array, remove, sarray("index"), varray());
bind_method(PackedVector2Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedVector2Array, fill, sarray("value"), varray());
bind_method(PackedVector2Array, resize, sarray("new_size"), varray());
bind_method(PackedVector2Array, has, sarray("value"), varray());
bind_method(PackedVector2Array, reverse, sarray(), varray());
@@ -1839,6 +1940,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector3Array, append_array, sarray("array"), varray());
bind_method(PackedVector3Array, remove, sarray("index"), varray());
bind_method(PackedVector3Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedVector3Array, fill, sarray("value"), varray());
bind_method(PackedVector3Array, resize, sarray("new_size"), varray());
bind_method(PackedVector3Array, has, sarray("value"), varray());
bind_method(PackedVector3Array, reverse, sarray(), varray());
@@ -1857,6 +1959,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedColorArray, append_array, sarray("array"), varray());
bind_method(PackedColorArray, remove, sarray("index"), varray());
bind_method(PackedColorArray, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedColorArray, fill, sarray("value"), varray());
bind_method(PackedColorArray, resize, sarray("new_size"), varray());
bind_method(PackedColorArray, has, sarray("value"), varray());
bind_method(PackedColorArray, reverse, sarray(), varray());
@@ -1924,14 +2027,14 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0));
_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0));
- Transform identity_transform = Transform();
- Transform flip_x_transform = Transform(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
- Transform flip_y_transform = Transform(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
- Transform flip_z_transform = Transform(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
- _VariantCall::add_variant_constant(Variant::TRANSFORM, "IDENTITY", identity_transform);
- _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_X", flip_x_transform);
- _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Y", flip_y_transform);
- _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", flip_z_transform);
+ Transform3D identity_transform = Transform3D();
+ Transform3D flip_x_transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
+ Transform3D flip_y_transform = Transform3D(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
+ Transform3D flip_z_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "IDENTITY", identity_transform);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_X", flip_x_transform);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_Y", flip_y_transform);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_Z", flip_z_transform);
Basis identity_basis = Basis();
Basis flip_x_basis = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1);
@@ -1946,7 +2049,7 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XZ", Plane(Vector3(0, 1, 0), 0));
_VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XY", Plane(Vector3(0, 0, 1), 0));
- _VariantCall::add_variant_constant(Variant::QUAT, "IDENTITY", Quat(0, 0, 0, 1));
+ _VariantCall::add_variant_constant(Variant::QUATERNION, "IDENTITY", Quaternion(0, 0, 0, 1));
}
void Variant::_register_variant_methods() {
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index f0c9e52b46..9e3ab5897b 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -62,10 +62,10 @@ MAKE_PTRCONSTRUCT(Vector3);
MAKE_PTRCONSTRUCT(Vector3i);
MAKE_PTRCONSTRUCT(Transform2D);
MAKE_PTRCONSTRUCT(Plane);
-MAKE_PTRCONSTRUCT(Quat);
+MAKE_PTRCONSTRUCT(Quaternion);
MAKE_PTRCONSTRUCT(AABB);
MAKE_PTRCONSTRUCT(Basis);
-MAKE_PTRCONSTRUCT(Transform);
+MAKE_PTRCONSTRUCT(Transform3D);
MAKE_PTRCONSTRUCT(Color);
MAKE_PTRCONSTRUCT(StringName);
MAKE_PTRCONSTRUCT(NodePath);
@@ -659,13 +659,13 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructor<Plane, Vector3, Vector3, Vector3>>(sarray("point1", "point2", "point3"));
add_constructor<VariantConstructor<Plane, double, double, double, double>>(sarray("a", "b", "c", "d"));
- add_constructor<VariantConstructNoArgs<Quat>>(sarray());
- add_constructor<VariantConstructor<Quat, Quat>>(sarray("from"));
- add_constructor<VariantConstructor<Quat, Basis>>(sarray("from"));
- add_constructor<VariantConstructor<Quat, Vector3>>(sarray("euler"));
- add_constructor<VariantConstructor<Quat, Vector3, double>>(sarray("axis", "angle"));
- add_constructor<VariantConstructor<Quat, Vector3, Vector3>>(sarray("arc_from", "arc_to"));
- add_constructor<VariantConstructor<Quat, double, double, double, double>>(sarray("x", "y", "z", "w"));
+ add_constructor<VariantConstructNoArgs<Quaternion>>(sarray());
+ add_constructor<VariantConstructor<Quaternion, Quaternion>>(sarray("from"));
+ add_constructor<VariantConstructor<Quaternion, Basis>>(sarray("from"));
+ add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler"));
+ add_constructor<VariantConstructor<Quaternion, Vector3, double>>(sarray("axis", "angle"));
+ add_constructor<VariantConstructor<Quaternion, Vector3, Vector3>>(sarray("arc_from", "arc_to"));
+ add_constructor<VariantConstructor<Quaternion, double, double, double, double>>(sarray("x", "y", "z", "w"));
add_constructor<VariantConstructNoArgs<::AABB>>(sarray());
add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from"));
@@ -673,15 +673,15 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructNoArgs<Basis>>(sarray());
add_constructor<VariantConstructor<Basis, Basis>>(sarray("from"));
- add_constructor<VariantConstructor<Basis, Quat>>(sarray("from"));
+ add_constructor<VariantConstructor<Basis, Quaternion>>(sarray("from"));
add_constructor<VariantConstructor<Basis, Vector3>>(sarray("euler"));
add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "phi"));
add_constructor<VariantConstructor<Basis, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis"));
- add_constructor<VariantConstructNoArgs<Transform>>(sarray());
- add_constructor<VariantConstructor<Transform, Transform>>(sarray("from"));
- add_constructor<VariantConstructor<Transform, Basis, Vector3>>(sarray("basis", "origin"));
- add_constructor<VariantConstructor<Transform, Vector3, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis", "origin"));
+ add_constructor<VariantConstructNoArgs<Transform3D>>(sarray());
+ add_constructor<VariantConstructor<Transform3D, Transform3D>>(sarray("from"));
+ add_constructor<VariantConstructor<Transform3D, Basis, Vector3>>(sarray("basis", "origin"));
+ add_constructor<VariantConstructor<Transform3D, Vector3, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis", "origin"));
add_constructor<VariantConstructNoArgs<Color>>(sarray());
add_constructor<VariantConstructor<Color, Color>>(sarray("from"));
@@ -836,9 +836,9 @@ String Variant::get_constructor_argument_name(Variant::Type p_type, int p_constr
void VariantInternal::object_assign(Variant *v, const Object *o) {
if (o) {
- if (o->is_reference()) {
- Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(o));
- if (!reference->init_ref()) {
+ if (o->is_ref_counted()) {
+ RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(o));
+ if (!ref_counted->init_ref()) {
v->_get_obj().obj = nullptr;
v->_get_obj().id = ObjectID();
return;
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 7d33d85cd6..78e1ad06ae 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -43,17 +43,20 @@ public:
v->type = p_type;
switch (p_type) {
- case Variant::AABB:
- init_aabb(v);
+ case Variant::STRING:
+ init_string(v);
break;
case Variant::TRANSFORM2D:
init_transform2d(v);
break;
- case Variant::TRANSFORM:
- init_transform(v);
+ case Variant::AABB:
+ init_aabb(v);
break;
- case Variant::STRING:
- init_string(v);
+ case Variant::BASIS:
+ init_basis(v);
+ break;
+ case Variant::TRANSFORM3D:
+ init_transform(v);
break;
case Variant::STRING_NAME:
init_string_name(v);
@@ -135,14 +138,14 @@ public:
_FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return v->_data._transform2d; }
_FORCE_INLINE_ static Plane *get_plane(Variant *v) { return reinterpret_cast<Plane *>(v->_data._mem); }
_FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return reinterpret_cast<const Plane *>(v->_data._mem); }
- _FORCE_INLINE_ static Quat *get_quat(Variant *v) { return reinterpret_cast<Quat *>(v->_data._mem); }
- _FORCE_INLINE_ static const Quat *get_quat(const Variant *v) { return reinterpret_cast<const Quat *>(v->_data._mem); }
+ _FORCE_INLINE_ static Quaternion *get_quaternion(Variant *v) { return reinterpret_cast<Quaternion *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Quaternion *get_quaternion(const Variant *v) { return reinterpret_cast<const Quaternion *>(v->_data._mem); }
_FORCE_INLINE_ static ::AABB *get_aabb(Variant *v) { return v->_data._aabb; }
_FORCE_INLINE_ static const ::AABB *get_aabb(const Variant *v) { return v->_data._aabb; }
_FORCE_INLINE_ static Basis *get_basis(Variant *v) { return v->_data._basis; }
_FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return v->_data._basis; }
- _FORCE_INLINE_ static Transform *get_transform(Variant *v) { return v->_data._transform; }
- _FORCE_INLINE_ static const Transform *get_transform(const Variant *v) { return v->_data._transform; }
+ _FORCE_INLINE_ static Transform3D *get_transform(Variant *v) { return v->_data._transform3d; }
+ _FORCE_INLINE_ static const Transform3D *get_transform(const Variant *v) { return v->_data._transform3d; }
// Misc types.
_FORCE_INLINE_ static Color *get_color(Variant *v) { return reinterpret_cast<Color *>(v->_data._mem); }
@@ -192,6 +195,10 @@ public:
v->type = GetTypeInfo<T>::VARIANT_TYPE;
}
+ // Should be in the same order as Variant::Type for consistency.
+ // Those primitive and vector types don't need an `init_` method:
+ // Nil, bool, float, Vector2/i, Rect2/i, Vector3/i, Plane, Quat, Color, RID.
+ // Object is a special case, handled via `object_assign_null`.
_FORCE_INLINE_ static void init_string(Variant *v) {
memnew_placement(v->_data._mem, String);
v->type = Variant::STRING;
@@ -210,8 +217,8 @@ public:
v->type = Variant::BASIS;
}
_FORCE_INLINE_ static void init_transform(Variant *v) {
- v->_data._transform = memnew(Transform);
- v->type = Variant::TRANSFORM;
+ v->_data._transform3d = memnew(Transform3D);
+ v->type = Variant::TRANSFORM3D;
}
_FORCE_INLINE_ static void init_string_name(Variant *v) {
memnew_placement(v->_data._mem, StringName);
@@ -278,7 +285,7 @@ public:
v->clear();
}
- static void object_assign(Variant *v, const Object *o); // Needs Reference, so it's implemented elsewhere.
+ static void object_assign(Variant *v, const Object *o); // Needs RefCounted, so it's implemented elsewhere.
_FORCE_INLINE_ static void object_assign(Variant *v, const Variant *o) {
object_assign(v, o->_get_obj().obj);
@@ -313,12 +320,12 @@ public:
return get_rect2(v);
case Variant::RECT2I:
return get_rect2i(v);
- case Variant::TRANSFORM:
+ case Variant::TRANSFORM3D:
return get_transform(v);
case Variant::TRANSFORM2D:
return get_transform2d(v);
- case Variant::QUAT:
- return get_quat(v);
+ case Variant::QUATERNION:
+ return get_quaternion(v);
case Variant::PLANE:
return get_plane(v);
case Variant::BASIS:
@@ -391,12 +398,12 @@ public:
return get_rect2(v);
case Variant::RECT2I:
return get_rect2i(v);
- case Variant::TRANSFORM:
+ case Variant::TRANSFORM3D:
return get_transform(v);
case Variant::TRANSFORM2D:
return get_transform2d(v);
- case Variant::QUAT:
- return get_quat(v);
+ case Variant::QUATERNION:
+ return get_quaternion(v);
case Variant::PLANE:
return get_plane(v);
case Variant::BASIS:
@@ -583,9 +590,9 @@ struct VariantGetInternalPtr<Transform2D> {
};
template <>
-struct VariantGetInternalPtr<Transform> {
- static Transform *get_ptr(Variant *v) { return VariantInternal::get_transform(v); }
- static const Transform *get_ptr(const Variant *v) { return VariantInternal::get_transform(v); }
+struct VariantGetInternalPtr<Transform3D> {
+ static Transform3D *get_ptr(Variant *v) { return VariantInternal::get_transform(v); }
+ static const Transform3D *get_ptr(const Variant *v) { return VariantInternal::get_transform(v); }
};
template <>
@@ -595,9 +602,9 @@ struct VariantGetInternalPtr<Plane> {
};
template <>
-struct VariantGetInternalPtr<Quat> {
- static Quat *get_ptr(Variant *v) { return VariantInternal::get_quat(v); }
- static const Quat *get_ptr(const Variant *v) { return VariantInternal::get_quat(v); }
+struct VariantGetInternalPtr<Quaternion> {
+ static Quaternion *get_ptr(Variant *v) { return VariantInternal::get_quaternion(v); }
+ static const Quaternion *get_ptr(const Variant *v) { return VariantInternal::get_quaternion(v); }
};
template <>
@@ -812,9 +819,9 @@ struct VariantInternalAccessor<Transform2D> {
};
template <>
-struct VariantInternalAccessor<Transform> {
- static _FORCE_INLINE_ const Transform &get(const Variant *v) { return *VariantInternal::get_transform(v); }
- static _FORCE_INLINE_ void set(Variant *v, const Transform &p_value) { *VariantInternal::get_transform(v) = p_value; }
+struct VariantInternalAccessor<Transform3D> {
+ static _FORCE_INLINE_ const Transform3D &get(const Variant *v) { return *VariantInternal::get_transform(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Transform3D &p_value) { *VariantInternal::get_transform(v) = p_value; }
};
template <>
@@ -824,9 +831,9 @@ struct VariantInternalAccessor<Plane> {
};
template <>
-struct VariantInternalAccessor<Quat> {
- static _FORCE_INLINE_ const Quat &get(const Variant *v) { return *VariantInternal::get_quat(v); }
- static _FORCE_INLINE_ void set(Variant *v, const Quat &p_value) { *VariantInternal::get_quat(v) = p_value; }
+struct VariantInternalAccessor<Quaternion> {
+ static _FORCE_INLINE_ const Quaternion &get(const Variant *v) { return *VariantInternal::get_quaternion(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Quaternion &p_value) { *VariantInternal::get_quaternion(v) = p_value; }
};
template <>
@@ -1060,8 +1067,8 @@ struct VariantInitializer<Plane> {
};
template <>
-struct VariantInitializer<Quat> {
- static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Quat>(v); }
+struct VariantInitializer<Quaternion> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Quaternion>(v); }
};
template <>
@@ -1075,7 +1082,7 @@ struct VariantInitializer<Basis> {
};
template <>
-struct VariantInitializer<Transform> {
+struct VariantInitializer<Transform3D> {
static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_transform(v); }
};
@@ -1234,8 +1241,8 @@ struct VariantZeroAssigner<Plane> {
};
template <>
-struct VariantZeroAssigner<Quat> {
- static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_quat(v) = Quat(); }
+struct VariantZeroAssigner<Quaternion> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_quaternion(v) = Quaternion(); }
};
template <>
@@ -1249,8 +1256,8 @@ struct VariantZeroAssigner<Basis> {
};
template <>
-struct VariantZeroAssigner<Transform> {
- static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform(v) = Transform(); }
+struct VariantZeroAssigner<Transform3D> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform(v) = Transform3D(); }
};
template <>
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index e0a3cf4215..10d0a83014 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -257,6 +257,14 @@ public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+
+#if defined(DEBUG_ENABLED)
+ if (b < 0 || a < 0) {
+ *r_ret = "Invalid operands for bit shifting. Only positive operands are supported.";
+ r_valid = false;
+ return;
+ }
+#endif
*r_ret = a << b;
r_valid = true;
}
@@ -276,6 +284,14 @@ public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+
+#if defined(DEBUG_ENABLED)
+ if (b < 0 || a < 0) {
+ *r_ret = "Invalid operands for bit shifting. Only positive operands are supported.";
+ r_valid = false;
+ return;
+ }
+#endif
*r_ret = a >> b;
r_valid = true;
}
@@ -1365,10 +1381,10 @@ void register_op(Variant::Operator p_op, Variant::Type p_type_a, Variant::Type p
}
void Variant::_register_variant_operators() {
- zeromem(operator_return_type_table, sizeof(operator_return_type_table));
- zeromem(operator_evaluator_table, sizeof(operator_evaluator_table));
- zeromem(validated_operator_evaluator_table, sizeof(validated_operator_evaluator_table));
- zeromem(ptr_operator_evaluator_table, sizeof(ptr_operator_evaluator_table));
+ memset(operator_return_type_table, 0, sizeof(operator_return_type_table));
+ memset(operator_evaluator_table, 0, sizeof(operator_evaluator_table));
+ memset(validated_operator_evaluator_table, 0, sizeof(validated_operator_evaluator_table));
+ memset(ptr_operator_evaluator_table, 0, sizeof(ptr_operator_evaluator_table));
register_op<OperatorEvaluatorAdd<int64_t, int64_t, int64_t>>(Variant::OP_ADD, Variant::INT, Variant::INT);
register_op<OperatorEvaluatorAdd<double, int64_t, double>>(Variant::OP_ADD, Variant::INT, Variant::FLOAT);
@@ -1379,7 +1395,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAdd<Vector2i, Vector2i, Vector2i>>(Variant::OP_ADD, Variant::VECTOR2I, Variant::VECTOR2I);
register_op<OperatorEvaluatorAdd<Vector3, Vector3, Vector3>>(Variant::OP_ADD, Variant::VECTOR3, Variant::VECTOR3);
register_op<OperatorEvaluatorAdd<Vector3i, Vector3i, Vector3i>>(Variant::OP_ADD, Variant::VECTOR3I, Variant::VECTOR3I);
- register_op<OperatorEvaluatorAdd<Quat, Quat, Quat>>(Variant::OP_ADD, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorAdd<Quaternion, Quaternion, Quaternion>>(Variant::OP_ADD, Variant::QUATERNION, Variant::QUATERNION);
register_op<OperatorEvaluatorAdd<Color, Color, Color>>(Variant::OP_ADD, Variant::COLOR, Variant::COLOR);
register_op<OperatorEvaluatorAddArray>(Variant::OP_ADD, Variant::ARRAY, Variant::ARRAY);
register_op<OperatorEvaluatorAppendArray<uint8_t>>(Variant::OP_ADD, Variant::PACKED_BYTE_ARRAY, Variant::PACKED_BYTE_ARRAY);
@@ -1400,7 +1416,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorSub<Vector2i, Vector2i, Vector2i>>(Variant::OP_SUBTRACT, Variant::VECTOR2I, Variant::VECTOR2I);
register_op<OperatorEvaluatorSub<Vector3, Vector3, Vector3>>(Variant::OP_SUBTRACT, Variant::VECTOR3, Variant::VECTOR3);
register_op<OperatorEvaluatorSub<Vector3i, Vector3i, Vector3i>>(Variant::OP_SUBTRACT, Variant::VECTOR3I, Variant::VECTOR3I);
- register_op<OperatorEvaluatorSub<Quat, Quat, Quat>>(Variant::OP_SUBTRACT, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorSub<Quaternion, Quaternion, Quaternion>>(Variant::OP_SUBTRACT, Variant::QUATERNION, Variant::QUATERNION);
register_op<OperatorEvaluatorSub<Color, Color, Color>>(Variant::OP_SUBTRACT, Variant::COLOR, Variant::COLOR);
register_op<OperatorEvaluatorMul<int64_t, int64_t, int64_t>>(Variant::OP_MULTIPLY, Variant::INT, Variant::INT);
@@ -1433,9 +1449,9 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorMul<Vector3i, Vector3i, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::INT);
register_op<OperatorEvaluatorMul<Vector3i, Vector3i, double>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::FLOAT);
- register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT);
- register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT);
- register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorMul<Quaternion, Quaternion, Quaternion>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::QUATERNION);
+ register_op<OperatorEvaluatorMul<Quaternion, Quaternion, int64_t>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::INT);
+ register_op<OperatorEvaluatorMul<Quaternion, Quaternion, double>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::FLOAT);
register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR);
register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT);
@@ -1449,25 +1465,25 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorXForm<Vector<Vector2>, Transform2D, Vector<Vector2>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::PACKED_VECTOR2_ARRAY);
register_op<OperatorEvaluatorXFormInv<Vector<Vector2>, Vector<Vector2>, Transform2D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR2_ARRAY, Variant::TRANSFORM2D);
- register_op<OperatorEvaluatorMul<Transform, Transform, Transform>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::TRANSFORM);
- register_op<OperatorEvaluatorXForm<Vector3, Transform, Vector3>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::VECTOR3);
- register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM);
- register_op<OperatorEvaluatorXForm<::AABB, Transform, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::AABB);
- register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM);
- register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::PACKED_VECTOR3_ARRAY);
- register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorMul<Transform3D, Transform3D, Transform3D>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorXForm<Vector3, Transform3D, Vector3>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::VECTOR3);
+ register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform3D>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorXForm<::AABB, Transform3D, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::AABB);
+ register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform3D>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform3D, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform3D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM3D);
register_op<OperatorEvaluatorMul<Basis, Basis, Basis>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::BASIS);
register_op<OperatorEvaluatorXForm<Vector3, Basis, Vector3>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::VECTOR3);
register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Basis>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::BASIS);
- register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT);
- register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT);
- register_op<OperatorEvaluatorMul<Quat, int64_t, Quat>>(Variant::OP_MULTIPLY, Variant::INT, Variant::QUAT);
- register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT);
- register_op<OperatorEvaluatorMul<Quat, double, Quat>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::QUAT);
- register_op<OperatorEvaluatorXForm<Vector3, Quat, Vector3>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::VECTOR3);
- register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Quat>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::QUAT);
+ register_op<OperatorEvaluatorMul<Quaternion, Quaternion, Quaternion>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::QUATERNION);
+ register_op<OperatorEvaluatorMul<Quaternion, Quaternion, int64_t>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::INT);
+ register_op<OperatorEvaluatorMul<Quaternion, int64_t, Quaternion>>(Variant::OP_MULTIPLY, Variant::INT, Variant::QUATERNION);
+ register_op<OperatorEvaluatorMul<Quaternion, Quaternion, double>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::FLOAT);
+ register_op<OperatorEvaluatorMul<Quaternion, double, Quaternion>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::QUATERNION);
+ register_op<OperatorEvaluatorXForm<Vector3, Quaternion, Vector3>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::VECTOR3);
+ register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Quaternion>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::QUATERNION);
register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR);
register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT);
@@ -1500,8 +1516,8 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, double>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::FLOAT);
register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::INT);
- register_op<OperatorEvaluatorDiv<Quat, Quat, double>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::FLOAT);
- register_op<OperatorEvaluatorDiv<Quat, Quat, int64_t>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::INT);
+ register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, double>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, int64_t>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::INT);
register_op<OperatorEvaluatorDiv<Color, Color, Color>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::COLOR);
register_op<OperatorEvaluatorDiv<Color, Color, double>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::FLOAT);
@@ -1528,10 +1544,10 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorStringModT<Vector3i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3I);
register_op<OperatorEvaluatorStringModT<Transform2D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM2D);
register_op<OperatorEvaluatorStringModT<Plane>>(Variant::OP_MODULE, Variant::STRING, Variant::PLANE);
- register_op<OperatorEvaluatorStringModT<Quat>>(Variant::OP_MODULE, Variant::STRING, Variant::QUAT);
+ register_op<OperatorEvaluatorStringModT<Quaternion>>(Variant::OP_MODULE, Variant::STRING, Variant::QUATERNION);
register_op<OperatorEvaluatorStringModT<::AABB>>(Variant::OP_MODULE, Variant::STRING, Variant::AABB);
register_op<OperatorEvaluatorStringModT<Basis>>(Variant::OP_MODULE, Variant::STRING, Variant::BASIS);
- register_op<OperatorEvaluatorStringModT<Transform>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorStringModT<Transform3D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM3D);
register_op<OperatorEvaluatorStringModT<Color>>(Variant::OP_MODULE, Variant::STRING, Variant::COLOR);
register_op<OperatorEvaluatorStringModT<StringName>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING_NAME);
@@ -1558,7 +1574,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorNeg<Vector2i, Vector2i>>(Variant::OP_NEGATE, Variant::VECTOR2I, Variant::NIL);
register_op<OperatorEvaluatorNeg<Vector3, Vector3>>(Variant::OP_NEGATE, Variant::VECTOR3, Variant::NIL);
register_op<OperatorEvaluatorNeg<Vector3i, Vector3i>>(Variant::OP_NEGATE, Variant::VECTOR3I, Variant::NIL);
- register_op<OperatorEvaluatorNeg<Quat, Quat>>(Variant::OP_NEGATE, Variant::QUAT, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Quaternion, Quaternion>>(Variant::OP_NEGATE, Variant::QUATERNION, Variant::NIL);
register_op<OperatorEvaluatorNeg<Plane, Plane>>(Variant::OP_NEGATE, Variant::PLANE, Variant::NIL);
register_op<OperatorEvaluatorNeg<Color, Color>>(Variant::OP_NEGATE, Variant::COLOR, Variant::NIL);
@@ -1568,7 +1584,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorPos<Vector2i, Vector2i>>(Variant::OP_POSITIVE, Variant::VECTOR2I, Variant::NIL);
register_op<OperatorEvaluatorPos<Vector3, Vector3>>(Variant::OP_POSITIVE, Variant::VECTOR3, Variant::NIL);
register_op<OperatorEvaluatorPos<Vector3i, Vector3i>>(Variant::OP_POSITIVE, Variant::VECTOR3I, Variant::NIL);
- register_op<OperatorEvaluatorPos<Quat, Quat>>(Variant::OP_POSITIVE, Variant::QUAT, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Quaternion, Quaternion>>(Variant::OP_POSITIVE, Variant::QUATERNION, Variant::NIL);
register_op<OperatorEvaluatorPos<Plane, Plane>>(Variant::OP_POSITIVE, Variant::PLANE, Variant::NIL);
register_op<OperatorEvaluatorPos<Color, Color>>(Variant::OP_POSITIVE, Variant::COLOR, Variant::NIL);
@@ -1596,10 +1612,10 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorEqual<Vector3i, Vector3i>>(Variant::OP_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I);
register_op<OperatorEvaluatorEqual<Transform2D, Transform2D>>(Variant::OP_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D);
register_op<OperatorEvaluatorEqual<Plane, Plane>>(Variant::OP_EQUAL, Variant::PLANE, Variant::PLANE);
- register_op<OperatorEvaluatorEqual<Quat, Quat>>(Variant::OP_EQUAL, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorEqual<Quaternion, Quaternion>>(Variant::OP_EQUAL, Variant::QUATERNION, Variant::QUATERNION);
register_op<OperatorEvaluatorEqual<::AABB, ::AABB>>(Variant::OP_EQUAL, Variant::AABB, Variant::AABB);
register_op<OperatorEvaluatorEqual<Basis, Basis>>(Variant::OP_EQUAL, Variant::BASIS, Variant::BASIS);
- register_op<OperatorEvaluatorEqual<Transform, Transform>>(Variant::OP_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorEqual<Transform3D, Transform3D>>(Variant::OP_EQUAL, Variant::TRANSFORM3D, Variant::TRANSFORM3D);
register_op<OperatorEvaluatorEqual<Color, Color>>(Variant::OP_EQUAL, Variant::COLOR, Variant::COLOR);
register_op<OperatorEvaluatorEqual<StringName, String>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING);
@@ -1642,10 +1658,10 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorNotEqual<Vector3i, Vector3i>>(Variant::OP_NOT_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I);
register_op<OperatorEvaluatorNotEqual<Transform2D, Transform2D>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D);
register_op<OperatorEvaluatorNotEqual<Plane, Plane>>(Variant::OP_NOT_EQUAL, Variant::PLANE, Variant::PLANE);
- register_op<OperatorEvaluatorNotEqual<Quat, Quat>>(Variant::OP_NOT_EQUAL, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorNotEqual<Quaternion, Quaternion>>(Variant::OP_NOT_EQUAL, Variant::QUATERNION, Variant::QUATERNION);
register_op<OperatorEvaluatorNotEqual<::AABB, ::AABB>>(Variant::OP_NOT_EQUAL, Variant::AABB, Variant::AABB);
register_op<OperatorEvaluatorNotEqual<Basis, Basis>>(Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::BASIS);
- register_op<OperatorEvaluatorNotEqual<Transform, Transform>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorNotEqual<Transform3D, Transform3D>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM3D, Variant::TRANSFORM3D);
register_op<OperatorEvaluatorNotEqual<Color, Color>>(Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::COLOR);
register_op<OperatorEvaluatorNotEqual<StringName, String>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING);
@@ -1833,10 +1849,10 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorInDictionaryHas<Vector3i>>(Variant::OP_IN, Variant::VECTOR3I, Variant::DICTIONARY);
register_op<OperatorEvaluatorInDictionaryHas<Transform2D>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::DICTIONARY);
register_op<OperatorEvaluatorInDictionaryHas<Plane>>(Variant::OP_IN, Variant::PLANE, Variant::DICTIONARY);
- register_op<OperatorEvaluatorInDictionaryHas<Quat>>(Variant::OP_IN, Variant::QUAT, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Quaternion>>(Variant::OP_IN, Variant::QUATERNION, Variant::DICTIONARY);
register_op<OperatorEvaluatorInDictionaryHas<::AABB>>(Variant::OP_IN, Variant::AABB, Variant::DICTIONARY);
register_op<OperatorEvaluatorInDictionaryHas<Basis>>(Variant::OP_IN, Variant::BASIS, Variant::DICTIONARY);
- register_op<OperatorEvaluatorInDictionaryHas<Transform>>(Variant::OP_IN, Variant::TRANSFORM, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Transform3D>>(Variant::OP_IN, Variant::TRANSFORM3D, Variant::DICTIONARY);
register_op<OperatorEvaluatorInDictionaryHas<Color>>(Variant::OP_IN, Variant::COLOR, Variant::DICTIONARY);
register_op<OperatorEvaluatorInDictionaryHas<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::DICTIONARY);
@@ -1870,10 +1886,10 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorInArrayFind<Vector3i, Array>>(Variant::OP_IN, Variant::VECTOR3I, Variant::ARRAY);
register_op<OperatorEvaluatorInArrayFind<Transform2D, Array>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::ARRAY);
register_op<OperatorEvaluatorInArrayFind<Plane, Array>>(Variant::OP_IN, Variant::PLANE, Variant::ARRAY);
- register_op<OperatorEvaluatorInArrayFind<Quat, Array>>(Variant::OP_IN, Variant::QUAT, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Quaternion, Array>>(Variant::OP_IN, Variant::QUATERNION, Variant::ARRAY);
register_op<OperatorEvaluatorInArrayFind<::AABB, Array>>(Variant::OP_IN, Variant::AABB, Variant::ARRAY);
register_op<OperatorEvaluatorInArrayFind<Basis, Array>>(Variant::OP_IN, Variant::BASIS, Variant::ARRAY);
- register_op<OperatorEvaluatorInArrayFind<Transform, Array>>(Variant::OP_IN, Variant::TRANSFORM, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Transform3D, Array>>(Variant::OP_IN, Variant::TRANSFORM3D, Variant::ARRAY);
register_op<OperatorEvaluatorInArrayFind<Color, Array>>(Variant::OP_IN, Variant::COLOR, Variant::ARRAY);
register_op<OperatorEvaluatorInArrayFind<StringName, Array>>(Variant::OP_IN, Variant::STRING_NAME, Variant::ARRAY);
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index edaeddbf27..751cb64c62 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -190,10 +190,13 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
r_token.type = TK_COLOR;
return OK;
}
- case '@': {
+#ifndef DISABLE_DEPRECATED
+ case '@': // Compatibility with 3.x StringNames.
+#endif
+ case '&': { // StringName.
cchar = p_stream->get_char();
if (cchar != '"') {
- r_err_str = "Expected '\"' after '@'";
+ r_err_str = "Expected '\"' after '&'";
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
@@ -614,7 +617,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
}
value = Plane(args[0], args[1], args[2], args[3]);
- } else if (id == "Quat") {
+ } else if (id == "Quaternion" || id == "Quat") { // "Quat" kept for compatibility
Vector<real_t> args;
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
@@ -626,7 +629,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
return ERR_PARSE_ERROR;
}
- value = Quat(args[0], args[1], args[2], args[3]);
+ value = Quaternion(args[0], args[1], args[2], args[3]);
} else if (id == "AABB" || id == "Rect3") {
Vector<real_t> args;
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
@@ -653,7 +656,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
}
value = Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
- } else if (id == "Transform") {
+ } else if (id == "Transform3D" || id == "Transform") { // "Transform" kept for compatibility with Godot <4.
Vector<real_t> args;
Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
@@ -665,7 +668,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
return ERR_PARSE_ERROR;
}
- value = Transform(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11]));
+ value = Transform3D(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11]));
} else if (id == "Color") {
Vector<float> args;
Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
@@ -742,7 +745,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
return ERR_PARSE_ERROR;
}
- REF ref = REF(Object::cast_to<Reference>(obj));
+ REF ref = REF(Object::cast_to<RefCounted>(obj));
get_token(p_stream, token, line, r_err_str);
if (token.type != TK_COMMA) {
@@ -1454,9 +1457,9 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
p_store_string_func(p_store_string_ud, "AABB( " + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.position.z) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ", " + rtosfix(aabb.size.z) + " )");
} break;
- case Variant::QUAT: {
- Quat quat = p_variant;
- p_store_string_func(p_store_string_ud, "Quat( " + rtosfix(quat.x) + ", " + rtosfix(quat.y) + ", " + rtosfix(quat.z) + ", " + rtosfix(quat.w) + " )");
+ case Variant::QUATERNION: {
+ Quaternion quaternion = p_variant;
+ p_store_string_func(p_store_string_ud, "Quaternion( " + rtosfix(quaternion.x) + ", " + rtosfix(quaternion.y) + ", " + rtosfix(quaternion.z) + ", " + rtosfix(quaternion.w) + " )");
} break;
case Variant::TRANSFORM2D: {
@@ -1489,9 +1492,9 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
p_store_string_func(p_store_string_ud, s + " )");
} break;
- case Variant::TRANSFORM: {
- String s = "Transform( ";
- Transform t = p_variant;
+ case Variant::TRANSFORM3D: {
+ String s = "Transform3D( ";
+ Transform3D t = p_variant;
Basis &m3 = t.basis;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
@@ -1516,7 +1519,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
case Variant::STRING_NAME: {
String str = p_variant;
- str = "@\"" + str.c_escape() + "\"";
+ str = "&\"" + str.c_escape() + "\"";
p_store_string_func(p_store_string_ud, str);
} break;
diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h
index 5703f0200c..05fc29b5e0 100644
--- a/core/variant/variant_parser.h
+++ b/core/variant/variant_parser.h
@@ -31,8 +31,8 @@
#ifndef VARIANT_PARSER_H
#define VARIANT_PARSER_H
+#include "core/io/file_access.h"
#include "core/io/resource.h"
-#include "core/os/file_access.h"
#include "core/variant/variant.h"
class VariantParser {
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index 9ab8602782..ae2795f2fd 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -279,17 +279,17 @@ SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, z, normal.z)
SETGET_STRUCT(Plane, Vector3, normal)
SETGET_NUMBER_STRUCT(Plane, double, d)
-SETGET_NUMBER_STRUCT(Quat, double, x)
-SETGET_NUMBER_STRUCT(Quat, double, y)
-SETGET_NUMBER_STRUCT(Quat, double, z)
-SETGET_NUMBER_STRUCT(Quat, double, w)
+SETGET_NUMBER_STRUCT(Quaternion, double, x)
+SETGET_NUMBER_STRUCT(Quaternion, double, y)
+SETGET_NUMBER_STRUCT(Quaternion, double, z)
+SETGET_NUMBER_STRUCT(Quaternion, double, w)
SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_axis, get_axis, 0)
SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_axis, get_axis, 1)
SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_axis, get_axis, 2)
-SETGET_STRUCT(Transform, Basis, basis)
-SETGET_STRUCT(Transform, Vector3, origin)
+SETGET_STRUCT(Transform3D, Basis, basis)
+SETGET_STRUCT(Transform3D, Vector3, origin)
SETGET_NUMBER_STRUCT(Color, double, r)
SETGET_NUMBER_STRUCT(Color, double, g)
@@ -374,17 +374,17 @@ void register_named_setters_getters() {
REGISTER_MEMBER(Plane, d);
REGISTER_MEMBER(Plane, normal);
- REGISTER_MEMBER(Quat, x);
- REGISTER_MEMBER(Quat, y);
- REGISTER_MEMBER(Quat, z);
- REGISTER_MEMBER(Quat, w);
+ REGISTER_MEMBER(Quaternion, x);
+ REGISTER_MEMBER(Quaternion, y);
+ REGISTER_MEMBER(Quaternion, z);
+ REGISTER_MEMBER(Quaternion, w);
REGISTER_MEMBER(Basis, x);
REGISTER_MEMBER(Basis, y);
REGISTER_MEMBER(Basis, z);
- REGISTER_MEMBER(Transform, basis);
- REGISTER_MEMBER(Transform, origin);
+ REGISTER_MEMBER(Transform3D, basis);
+ REGISTER_MEMBER(Transform3D, origin);
REGISTER_MEMBER(Color, r);
REGISTER_MEMBER(Color, g);
@@ -975,7 +975,7 @@ INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2, double, real_t, 2)
INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2i, int64_t, int32_t, 2)
INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3, double, real_t, 3)
INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3i, int64_t, int32_t, 3)
-INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quat, double, real_t, 4)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quaternion, double, real_t, 4)
INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Color, double, float, 4)
INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .elements, 3)
@@ -1037,7 +1037,7 @@ void register_indexed_setters_getters() {
REGISTER_INDEXED_MEMBER(Vector2i);
REGISTER_INDEXED_MEMBER(Vector3);
REGISTER_INDEXED_MEMBER(Vector3i);
- REGISTER_INDEXED_MEMBER(Quat);
+ REGISTER_INDEXED_MEMBER(Quaternion);
REGISTER_INDEXED_MEMBER(Color);
REGISTER_INDEXED_MEMBER(Transform2D);
REGISTER_INDEXED_MEMBER(Basis);
@@ -1453,7 +1453,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const {
#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
valid = false;
return false;
}
@@ -1680,7 +1680,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const {
#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
valid = false;
return false;
}
@@ -1865,7 +1865,7 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
return Variant();
}
#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
r_valid = false;
return Variant();
}
@@ -2135,10 +2135,10 @@ void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst)
r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c);
}
return;
- case QUAT: {
- Quat empty_rot;
- const Quat *qa = reinterpret_cast<const Quat *>(a._data._mem);
- const Quat *qb = reinterpret_cast<const Quat *>(b._data._mem);
+ case QUATERNION: {
+ Quaternion empty_rot;
+ const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem);
+ const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem);
r_dst = *qa * empty_rot.slerp(*qb, c);
}
return;
@@ -2295,8 +2295,8 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &
r_dst = a;
}
return;
- case QUAT: {
- r_dst = reinterpret_cast<const Quat *>(a._data._mem)->slerp(*reinterpret_cast<const Quat *>(b._data._mem), c);
+ case QUATERNION: {
+ r_dst = reinterpret_cast<const Quaternion *>(a._data._mem)->slerp(*reinterpret_cast<const Quaternion *>(b._data._mem), c);
}
return;
case AABB: {
@@ -2304,11 +2304,11 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &
}
return;
case BASIS: {
- r_dst = Transform(*a._data._basis).interpolate_with(Transform(*b._data._basis), c).basis;
+ r_dst = Transform3D(*a._data._basis).interpolate_with(Transform3D(*b._data._basis), c).basis;
}
return;
- case TRANSFORM: {
- r_dst = a._data._transform->interpolate_with(*b._data._transform, c);
+ case TRANSFORM3D: {
+ r_dst = a._data._transform3d->interpolate_with(*b._data._transform3d, c);
}
return;
case COLOR: {
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index f154ab1ed6..5d1efb4166 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -32,7 +32,7 @@
#include "core/core_string_names.h"
#include "core/io/marshalls.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/os/os.h"
#include "core/templates/oa_hash_map.h"
#include "core/variant/binder_common.h"
@@ -93,6 +93,10 @@ struct VariantUtilityFunctions {
return Math::fposmod(b, r);
}
+ static inline int64_t posmod(int64_t b, int64_t r) {
+ return Math::posmod(b, r);
+ }
+
static inline double floor(double x) {
return Math::floor(x);
}
@@ -1154,6 +1158,7 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(sqrt, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(fmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(fposmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(posmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(floor, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(ceil, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(round, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 25f8f22d44..552fc41318 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -652,6 +652,31 @@
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).
</description>
</method>
+ <method name="posmod">
+ <return type="int">
+ </return>
+ <argument index="0" name="x" type="int">
+ </argument>
+ <argument index="1" name="y" type="int">
+ </argument>
+ <description>
+ Returns the integer modulus of [code]x/y[/code] that wraps equally in positive and negative.
+ [codeblock]
+ for i in range(-3, 4):
+ print("%2d %2d %2d" % [i, i % 3, posmod(i, 3)])
+ [/codeblock]
+ Produces:
+ [codeblock]
+ -3 0 0
+ -2 -2 1
+ -1 -1 2
+ 0 0 0
+ 1 1 1
+ 2 2 2
+ 3 0 0
+ [/codeblock]
+ </description>
+ </method>
<method name="pow">
<return type="float">
</return>
@@ -804,10 +829,7 @@
<method name="randomize">
<description>
Randomizes the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time.
- [codeblock]
- func _ready():
- randomize()
- [/codeblock]
+ [b]Note:[/b] This method is called automatically when the project is run. If you need to fix the seed to have reproducible results, use [method seed] to initialize the random number generator.
</description>
</method>
<method name="range_lerp">
@@ -1239,6 +1261,9 @@
<member name="TextServerManager" type="TextServerManager" setter="" getter="">
The [TextServerManager] singleton.
</member>
+ <member name="Time" type="Time" setter="" getter="">
+ The [Time] singleton.
+ </member>
<member name="TranslationServer" type="TranslationServer" setter="" getter="">
The [TranslationServer] singleton.
</member>
@@ -1371,7 +1396,7 @@
<constant name="KEY_SHIFT" value="16777237" enum="Key">
Shift key.
</constant>
- <constant name="KEY_CONTROL" value="16777238" enum="Key">
+ <constant name="KEY_CTRL" value="16777238" enum="Key">
Control key.
</constant>
<constant name="KEY_META" value="16777239" enum="Key">
@@ -2574,8 +2599,8 @@
<constant name="TYPE_PLANE" value="12" enum="Variant.Type">
Variable is of type [Plane].
</constant>
- <constant name="TYPE_QUAT" value="13" enum="Variant.Type">
- Variable is of type [Quat].
+ <constant name="TYPE_QUATERNION" value="13" enum="Variant.Type">
+ Variable is of type [Quaternion].
</constant>
<constant name="TYPE_AABB" value="14" enum="Variant.Type">
Variable is of type [AABB].
@@ -2583,8 +2608,8 @@
<constant name="TYPE_BASIS" value="15" enum="Variant.Type">
Variable is of type [Basis].
</constant>
- <constant name="TYPE_TRANSFORM" value="16" enum="Variant.Type">
- Variable is of type [Transform].
+ <constant name="TYPE_TRANSFORM3D" value="16" enum="Variant.Type">
+ Variable is of type [Transform3D].
</constant>
<constant name="TYPE_COLOR" value="17" enum="Variant.Type">
Variable is of type [Color].
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index a28bde9946..af34a948f5 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -242,7 +242,7 @@
<method name="operator *" qualifiers="operator">
<return type="AABB">
</return>
- <argument index="0" name="right" type="Transform">
+ <argument index="0" name="right" type="Transform3D">
</argument>
<description>
</description>
diff --git a/doc/classes/AESContext.xml b/doc/classes/AESContext.xml
index f577bab992..9dde25028e 100644
--- a/doc/classes/AESContext.xml
+++ b/doc/classes/AESContext.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AESContext" inherits="Reference" version="4.0">
+<class name="AESContext" inherits="RefCounted" version="4.0">
<brief_description>
Interface to low level AES encryption features.
</brief_description>
diff --git a/doc/classes/AStar.xml b/doc/classes/AStar.xml
index fce2b90197..cc7f7072b9 100644
--- a/doc/classes/AStar.xml
+++ b/doc/classes/AStar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AStar" inherits="Reference" version="4.0">
+<class name="AStar" inherits="RefCounted" version="4.0">
<brief_description>
An implementation of A* to find the shortest paths among connected points in space.
</brief_description>
diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml
index 3efd2f604c..9edc300169 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AStar2D" inherits="Reference" version="4.0">
+<class name="AStar2D" inherits="RefCounted" version="4.0">
<brief_description>
AStar class representation that uses 2D vectors as edges.
</brief_description>
diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml
index f4cf246713..f644606040 100644
--- a/doc/classes/AcceptDialog.xml
+++ b/doc/classes/AcceptDialog.xml
@@ -49,7 +49,7 @@
<method name="register_text_enter">
<return type="void">
</return>
- <argument index="0" name="line_edit" type="Node">
+ <argument index="0" name="line_edit" type="Control">
</argument>
<description>
Registers a [LineEdit] in the dialog. When the enter key is pressed, the dialog will be accepted.
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index 969e9cc85b..d18419f163 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -22,7 +22,7 @@
<method name="play">
<return type="void">
</return>
- <argument index="0" name="anim" type="StringName" default="@&quot;&quot;">
+ <argument index="0" name="anim" type="StringName" default="&amp;&quot;&quot;">
</argument>
<argument index="1" name="backwards" type="bool" default="false">
</argument>
@@ -39,7 +39,7 @@
</method>
</methods>
<members>
- <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="@&quot;default&quot;">
+ <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="&amp;&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">
diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml
index 02ccab4e05..39ab317b79 100644
--- a/doc/classes/AnimatedSprite3D.xml
+++ b/doc/classes/AnimatedSprite3D.xml
@@ -20,7 +20,7 @@
<method name="play">
<return type="void">
</return>
- <argument index="0" name="anim" type="StringName" default="@&quot;&quot;">
+ <argument index="0" name="anim" type="StringName" default="&amp;&quot;&quot;">
</argument>
<description>
Plays the animation named [code]anim[/code]. If no [code]anim[/code] is provided, the current animation is played.
@@ -35,7 +35,7 @@
</method>
</methods>
<members>
- <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="@&quot;default&quot;">
+ <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="&amp;&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="frame" type="int" setter="set_frame" getter="get_frame" default="0">
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index 7ceb21d22e..02203a3725 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -640,7 +640,7 @@
</argument>
<argument index="2" name="location" type="Vector3">
</argument>
- <argument index="3" name="rotation" type="Quat">
+ <argument index="3" name="rotation" type="Quaternion">
</argument>
<argument index="4" name="scale" type="Vector3">
</argument>
@@ -656,7 +656,7 @@
<argument index="1" name="time_sec" type="float">
</argument>
<description>
- 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]).
+ Returns the interpolated value of a transform track at a given time (in seconds). An array consisting of 3 elements: position ([Vector3]), rotation ([Quaternion]) and scale ([Vector3]).
</description>
</method>
<method name="value_track_get_key_indices" qualifiers="const">
@@ -727,8 +727,8 @@
<constant name="TYPE_VALUE" value="0" enum="TrackType">
Value tracks set values in node properties, but only those which can be Interpolated.
</constant>
- <constant name="TYPE_TRANSFORM" value="1" enum="TrackType">
- Transform tracks are used to change node local transforms or skeleton pose bones. Transitions are interpolated.
+ <constant name="TYPE_TRANSFORM3D" value="1" enum="TrackType">
+ Transform3D tracks are used to change node local transforms or skeleton pose bones of 3D nodes. Transitions are interpolated.
</constant>
<constant name="TYPE_METHOD" value="2" enum="TrackType">
Method tracks call functions with given arguments per key.
diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml
index 8204b456d9..fddd8989ab 100644
--- a/doc/classes/AnimationNode.xml
+++ b/doc/classes/AnimationNode.xml
@@ -11,6 +11,65 @@
<link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
+ <method name="_get_caption" qualifiers="virtual">
+ <return type="String">
+ </return>
+ <description>
+ Gets the text caption for this node (used by some editors).
+ </description>
+ </method>
+ <method name="_get_child_by_name" qualifiers="virtual">
+ <return type="Object">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <description>
+ Gets a child node by index (used by editors inheriting from [AnimationRootNode]).
+ </description>
+ </method>
+ <method name="_get_child_nodes" qualifiers="virtual">
+ <return type="Dictionary">
+ </return>
+ <description>
+ Gets all children nodes in order as a [code]name: node[/code] dictionary. Only useful when inheriting [AnimationRootNode].
+ </description>
+ </method>
+ <method name="_get_parameter_default_value" qualifiers="virtual">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ 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.
+ </description>
+ </method>
+ <method name="_get_parameter_list" qualifiers="virtual">
+ <return type="Array">
+ </return>
+ <description>
+ 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].
+ </description>
+ </method>
+ <method name="_has_filter" qualifiers="virtual">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] whether you want the blend tree editor to display filter editing on this node.
+ </description>
+ </method>
+ <method name="_process" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="time" type="float">
+ </argument>
+ <argument index="1" name="seek" type="bool">
+ </argument>
+ <description>
+ 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.
+ 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.
+ This function should return the time left for the current animation to finish (if unsure, pass the value from the main blend being called).
+ </description>
+ </method>
<method name="add_input">
<return type="void">
</return>
@@ -77,29 +136,6 @@
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.
</description>
</method>
- <method name="get_caption" qualifiers="virtual">
- <return type="String">
- </return>
- <description>
- Gets the text caption for this node (used by some editors).
- </description>
- </method>
- <method name="get_child_by_name" qualifiers="virtual">
- <return type="Object">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Gets a child node by index (used by editors inheriting from [AnimationRootNode]).
- </description>
- </method>
- <method name="get_child_nodes" qualifiers="virtual">
- <return type="Dictionary">
- </return>
- <description>
- Gets all children nodes in order as a [code]name: node[/code] dictionary. Only useful when inheriting [AnimationRootNode].
- </description>
- </method>
<method name="get_input_count" qualifiers="const">
<return type="int">
</return>
@@ -125,29 +161,6 @@
Gets the value of a parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees.
</description>
</method>
- <method name="get_parameter_default_value" qualifiers="virtual">
- <return type="Variant">
- </return>
- <argument index="0" name="name" type="StringName">
- </argument>
- <description>
- 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.
- </description>
- </method>
- <method name="get_parameter_list" qualifiers="virtual">
- <return type="Array">
- </return>
- <description>
- 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].
- </description>
- </method>
- <method name="has_filter" qualifiers="virtual">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] whether you want the blend tree editor to display filter editing on this node.
- </description>
- </method>
<method name="is_path_filtered" qualifiers="const">
<return type="bool">
</return>
@@ -157,19 +170,6 @@
Returns [code]true[/code] whether a given path is filtered.
</description>
</method>
- <method name="process" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="time" type="float">
- </argument>
- <argument index="1" name="seek" type="bool">
- </argument>
- <description>
- 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.
- 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.
- This function should return the time left for the current animation to finish (if unsure, pass the value from the main blend being called).
- </description>
- </method>
<method name="remove_input">
<return type="void">
</return>
diff --git a/doc/classes/AnimationNodeAnimation.xml b/doc/classes/AnimationNodeAnimation.xml
index 3f0843c112..75dae6a48e 100644
--- a/doc/classes/AnimationNodeAnimation.xml
+++ b/doc/classes/AnimationNodeAnimation.xml
@@ -14,7 +14,7 @@
<methods>
</methods>
<members>
- <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="@&quot;&quot;">
+ <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="&amp;&quot;&quot;">
Animation to use as an output. It is one of the animations provided by [member AnimationTree.anim_player].
</member>
</members>
diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml
index 2f0ebd7de6..7f07afecee 100644
--- a/doc/classes/AnimationNodeStateMachineTransition.xml
+++ b/doc/classes/AnimationNodeStateMachineTransition.xml
@@ -10,7 +10,7 @@
<methods>
</methods>
<members>
- <member name="advance_condition" type="StringName" setter="set_advance_condition" getter="get_advance_condition" default="@&quot;&quot;">
+ <member name="advance_condition" type="StringName" setter="set_advance_condition" getter="get_advance_condition" default="&amp;&quot;&quot;">
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]:
[codeblocks]
[gdscript]
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index 7696f36009..8a94eee54c 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -275,7 +275,8 @@
<argument index="1" name="new_name" type="StringName">
</argument>
<description>
- If the currently being played animation changes, this signal will notify of such change.
+ Emitted when a queued animation plays after the previous animation was finished. See [method queue].
+ [b]Note:[/b] The signal is not emitted when the animation is changed via [method play] or from [AnimationTree].
</description>
</signal>
<signal name="animation_finished">
diff --git a/doc/classes/AnimationTrackEditPlugin.xml b/doc/classes/AnimationTrackEditPlugin.xml
index 8490d48718..7b96808581 100644
--- a/doc/classes/AnimationTrackEditPlugin.xml
+++ b/doc/classes/AnimationTrackEditPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimationTrackEditPlugin" inherits="Reference" version="4.0">
+<class name="AnimationTrackEditPlugin" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index 2517941133..af7d8d73e8 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -21,10 +21,10 @@
</description>
</method>
<method name="get_root_motion_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<description>
- Retrieve the motion of the [member root_motion_track] as a [Transform] that can be used elsewhere. If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_TRANSFORM], returns an identity transformation.
+ Retrieve the motion of the [member root_motion_track] as a [Transform3D] that can be used elsewhere. If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_TRANSFORM3D], returns an identity transformation.
</description>
</method>
<method name="rename_parameter">
@@ -50,7 +50,7 @@
</member>
<member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath(&quot;&quot;)">
The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code].
- If the track has type [constant Animation.TYPE_TRANSFORM], the transformation will be cancelled visually, and the animation will appear to stay in place.
+ If the track has type [constant Animation.TYPE_TRANSFORM3D], the transformation will be cancelled visually, and the animation will appear to stay in place.
</member>
<member name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root">
The root animation node of this [AnimationTree]. See [AnimationNode].
diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml
index a1e522d146..96333988f8 100644
--- a/doc/classes/Area2D.xml
+++ b/doc/classes/Area2D.xml
@@ -54,14 +54,14 @@
The rate at which objects stop spinning in this area. Represents the angular velocity lost per second.
See [member ProjectSettings.physics/2d/default_angular_damp] for more details about damping.
</member>
- <member name="audio_bus_name" type="StringName" setter="set_audio_bus_name" getter="get_audio_bus_name" default="@&quot;Master&quot;">
+ <member name="audio_bus_name" type="StringName" setter="set_audio_bus_name" getter="get_audio_bus_name" default="&amp;&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="gravity" type="float" setter="set_gravity" getter="get_gravity" default="98.0">
- The area's gravity intensity (ranges from -1024 to 1024). This value multiplies the gravity vector. This is useful to alter the force of gravity without altering its direction.
+ <member name="gravity" type="float" setter="set_gravity" getter="get_gravity" default="980.0">
+ The area's gravity intensity (in pixels per second squared). 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.
@@ -107,7 +107,7 @@
</description>
</signal>
<signal name="area_shape_entered">
- <argument index="0" name="area_id" type="int">
+ <argument index="0" name="area_rid" type="RID">
</argument>
<argument index="1" name="area" type="Area2D">
</argument>
@@ -124,7 +124,7 @@
</description>
</signal>
<signal name="area_shape_exited">
- <argument index="0" name="area_id" type="int">
+ <argument index="0" name="area_rid" type="RID">
</argument>
<argument index="1" name="area" type="Area2D">
</argument>
@@ -157,7 +157,7 @@
</description>
</signal>
<signal name="body_shape_entered">
- <argument index="0" name="body_id" type="int">
+ <argument index="0" name="body_rid" type="RID">
</argument>
<argument index="1" name="body" type="Node2D">
</argument>
@@ -174,7 +174,7 @@
</description>
</signal>
<signal name="body_shape_exited">
- <argument index="0" name="body_id" type="int">
+ <argument index="0" name="body_rid" type="RID">
</argument>
<argument index="1" name="body" type="Node2D">
</argument>
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index e69a89a836..a2724f3f23 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -52,14 +52,14 @@
The rate at which objects stop spinning in this area. Represents the angular velocity lost per second.
See [member ProjectSettings.physics/3d/default_angular_damp] for more details about damping.
</member>
- <member name="audio_bus_name" type="StringName" setter="set_audio_bus_name" getter="get_audio_bus_name" default="@&quot;Master&quot;">
+ <member name="audio_bus_name" type="StringName" setter="set_audio_bus_name" getter="get_audio_bus_name" default="&amp;&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="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.
+ The area's gravity intensity (in meters per second squared). 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.
@@ -89,7 +89,7 @@
<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;">
+ <member name="reverb_bus_name" type="StringName" setter="set_reverb_bus" getter="get_reverb_bus" default="&amp;&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">
@@ -117,7 +117,7 @@
</description>
</signal>
<signal name="area_shape_entered">
- <argument index="0" name="area_id" type="int">
+ <argument index="0" name="area_rid" type="RID">
</argument>
<argument index="1" name="area" type="Area3D">
</argument>
@@ -134,7 +134,7 @@
</description>
</signal>
<signal name="area_shape_exited">
- <argument index="0" name="area_id" type="int">
+ <argument index="0" name="area_rid" type="RID">
</argument>
<argument index="1" name="area" type="Area3D">
</argument>
@@ -167,7 +167,7 @@
</description>
</signal>
<signal name="body_shape_entered">
- <argument index="0" name="body_id" type="int">
+ <argument index="0" name="body_rid" type="RID">
</argument>
<argument index="1" name="body" type="Node3D">
</argument>
@@ -184,7 +184,7 @@
</description>
</signal>
<signal name="body_shape_exited">
- <argument index="0" name="body_id" type="int">
+ <argument index="0" name="body_rid" type="RID">
</argument>
<argument index="1" name="body" type="Node3D">
</argument>
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index 54bbe7a94b..543ec096c7 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -33,8 +33,8 @@
[/gdscript]
[csharp]
// Array concatenation is not possible with C# arrays, but is with Godot.Collections.Array.
- var array1 = new Godot.Collections.Array("One", 2);
- var array2 = new Godot.Collections.Array(3, "Four");
+ var array1 = new Godot.Collections.Array{"One", 2};
+ var array2 = new Godot.Collections.Array{3, "Four"};
GD.Print(array1 + array2); // Prints [One, 2, 3, Four]
[/csharp]
[/codeblocks]
@@ -237,6 +237,45 @@
[b]Note:[/b] On large arrays, this method will be slower if the removed element is close to the beginning of the array (index 0). This is because all elements placed after the removed element have to be reindexed.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="Variant">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements:
+ [codeblocks]
+ [gdscript]
+ var array = []
+ array.resize(10)
+ array.fill(0) # Initialize the 10 elements to 0.
+ [/gdscript]
+ [csharp]
+ var array = new Godot.Collections.Array{};
+ array.Resize(10);
+ array.Fill(0); // Initialize the 10 elements to 0.
+ [/csharp]
+ [/codeblocks]
+ </description>
+ </method>
+ <method name="filter" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="method" type="Callable">
+ </argument>
+ <description>
+ Calls the provided [Callable] on each element in the array and returns a new array with the elements for which the method returned [code]true[/code].
+ The callable's method should take one [Variant] parameter (the current array element) and return a boolean value.
+ [codeblock]
+ func _ready():
+ print([1, 2, 3].filter(remove_1)) # Prints [2, 3].
+ print([1, 2, 3].filter(func(number): return number != 1)) # Same as above, but using lambda function.
+
+ func remove_1(number):
+ return number != 1
+ [/codeblock]
+ </description>
+ </method>
<method name="find" qualifiers="const">
<return type="int">
</return>
@@ -294,14 +333,14 @@
[gdscript]
# Will evaluate to `true`.
if 2 in [2, 4, 6, 8]:
- print("Containes!")
+ print("Contains!")
[/gdscript]
[csharp]
// As there is no "in" keyword in C#, you have to use Contains
var array = new Godot.Collections.Array{2, 4, 6, 8};
if (array.Contains(2))
{
- GD.Print("Containes!");
+ GD.Print("Contains!");
}
[/csharp]
[/codeblocks]
@@ -335,6 +374,24 @@
Returns [code]true[/code] if the array is empty.
</description>
</method>
+ <method name="map" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="method" type="Callable">
+ </argument>
+ <description>
+ Calls the provided [Callable] for each element in the array and returns a new array filled with values returned by the method.
+ The callable's method should take one [Variant] parameter (the current array element) and can return any [Variant].
+ [codeblock]
+ func _ready():
+ print([1, 2, 3].map(negate)) # Prints [-1, -2, -3].
+ print([1, 2, 3].map(func(number): return -number)) # Same as above, but using lambda function.
+
+ func negate(number):
+ return -number
+ [/codeblock]
+ </description>
+ </method>
<method name="max" qualifiers="const">
<return type="Variant">
</return>
@@ -447,6 +504,26 @@
[b]Note:[/b] On large arrays, this method is much slower than [method push_back] as it will reindex all the array's elements every time it's called. The larger the array, the slower [method push_front] will be.
</description>
</method>
+ <method name="reduce" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="method" type="Callable">
+ </argument>
+ <argument index="1" name="accum" type="Variant" default="null">
+ </argument>
+ <description>
+ Calls the provided [Callable] for each element in array and accumulates the result in [code]accum[/code].
+ The callable's method takes two arguments: the current value of [code]accum[/code] and the current array element. If [code]accum[/code] is [code]null[/code] (default value), the iteration will start from the second element, with the first one used as initial value of [code]accum[/code].
+ [codeblock]
+ func _ready():
+ print([1, 2, 3].reduce(sum, 10)) # Prints 16.
+ print([1, 2, 3].reduce(func(accum, number): return accum + number, 10)) # Same as above, but using lambda function.
+
+ func sum(accum, number):
+ return accum + number
+ [/codeblock]
+ </description>
+ </method>
<method name="remove">
<return type="void">
</return>
@@ -538,7 +615,7 @@
<argument index="0" name="func" type="Callable">
</argument>
<description>
- Sorts the array using a custom 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].
+ Sorts the array using a custom 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]. For two elements [code]a[/code] and [code]b[/code], if the given method returns [code]true[/code], element [code]b[/code] will be after element [code]a[/code] in the array.
[b]Note:[/b] you cannot randomize the return value as the heapsort algorithm expects a deterministic result. Doing so will result in unexpected behavior.
[codeblocks]
[gdscript]
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index 7c1c4656f8..f8cbc942e6 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -77,7 +77,6 @@
Creates a new surface.
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.
The [code]arrays[/code] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
- 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.
</description>
</method>
<method name="clear_blend_shapes">
@@ -113,7 +112,7 @@
<method name="lightmap_unwrap">
<return type="int" enum="Error">
</return>
- <argument index="0" name="transform" type="Transform">
+ <argument index="0" name="transform" type="Transform3D">
</argument>
<argument index="1" name="texel_size" type="float">
</argument>
diff --git a/doc/classes/AudioEffectCompressor.xml b/doc/classes/AudioEffectCompressor.xml
index 3117978d8a..4e924bcb65 100644
--- a/doc/classes/AudioEffectCompressor.xml
+++ b/doc/classes/AudioEffectCompressor.xml
@@ -32,7 +32,7 @@
<member name="release_ms" type="float" setter="set_release_ms" getter="get_release_ms" default="250.0">
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.
</member>
- <member name="sidechain" type="StringName" setter="set_sidechain" getter="get_sidechain" default="@&quot;&quot;">
+ <member name="sidechain" type="StringName" setter="set_sidechain" getter="get_sidechain" default="&amp;&quot;&quot;">
Reduce the sound level using another audio bus for threshold detection.
</member>
<member name="threshold" type="float" setter="set_threshold" getter="get_threshold" default="0.0">
diff --git a/doc/classes/AudioEffectInstance.xml b/doc/classes/AudioEffectInstance.xml
index dc76880a36..9ab6028901 100644
--- a/doc/classes/AudioEffectInstance.xml
+++ b/doc/classes/AudioEffectInstance.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioEffectInstance" inherits="Reference" version="4.0">
+<class name="AudioEffectInstance" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/AudioEffectPitchShift.xml b/doc/classes/AudioEffectPitchShift.xml
index afe364de63..9c28a01650 100644
--- a/doc/classes/AudioEffectPitchShift.xml
+++ b/doc/classes/AudioEffectPitchShift.xml
@@ -12,27 +12,34 @@
<methods>
</methods>
<members>
- <member name="fft_size" type="int" setter="set_fft_size" getter="get_fft_size" enum="AudioEffectPitchShift.FFT_Size" default="3">
+ <member name="fft_size" type="int" setter="set_fft_size" getter="get_fft_size" enum="AudioEffectPitchShift.FFTSize" default="3">
+ The size of the [url=https://en.wikipedia.org/wiki/Fast_Fourier_transform]Fast Fourier transform[/url] buffer. Higher values smooth out the effect over time, but have greater latency. The effects of this higher latency are especially noticeable on sounds that have sudden amplitude changes.
</member>
<member name="oversampling" type="int" setter="set_oversampling" getter="get_oversampling" default="4">
+ The oversampling factor to use. Higher values result in better quality, but are more demanding on the CPU and may cause audio cracking if the CPU can't keep up.
</member>
<member name="pitch_scale" type="float" setter="set_pitch_scale" getter="get_pitch_scale" default="1.0">
- Pitch value. Can range from 0 (-1 octave) to 16 (+16 octaves).
+ The pitch scale to use. [code]1.0[/code] is the default pitch and plays sounds unaltered. [member pitch_scale] can range from [code]0.0[/code] (infinitely low pitch, inaudible) to [code]16[/code] (16 times higher than the initial pitch).
</member>
</members>
<constants>
- <constant name="FFT_SIZE_256" value="0" enum="FFT_Size">
+ <constant name="FFT_SIZE_256" value="0" enum="FFTSize">
+ Use a buffer of 256 samples for the Fast Fourier transform. Lowest latency, but least stable over time.
</constant>
- <constant name="FFT_SIZE_512" value="1" enum="FFT_Size">
+ <constant name="FFT_SIZE_512" value="1" enum="FFTSize">
+ Use a buffer of 512 samples for the Fast Fourier transform. Low latency, but less stable over time.
</constant>
- <constant name="FFT_SIZE_1024" value="2" enum="FFT_Size">
+ <constant name="FFT_SIZE_1024" value="2" enum="FFTSize">
+ Use a buffer of 1024 samples for the Fast Fourier transform. This is a compromise between latency and stability over time.
</constant>
- <constant name="FFT_SIZE_2048" value="3" enum="FFT_Size">
+ <constant name="FFT_SIZE_2048" value="3" enum="FFTSize">
+ Use a buffer of 2048 samples for the Fast Fourier transform. High latency, but stable over time.
</constant>
- <constant name="FFT_SIZE_4096" value="4" enum="FFT_Size">
+ <constant name="FFT_SIZE_4096" value="4" enum="FFTSize">
+ Use a buffer of 4096 samples for the Fast Fourier transform. Highest latency, but most stable over time.
</constant>
- <constant name="FFT_SIZE_MAX" value="5" enum="FFT_Size">
- Represents the size of the [enum FFT_Size] enum.
+ <constant name="FFT_SIZE_MAX" value="5" enum="FFTSize">
+ Represents the size of the [enum FFTSize] enum.
</constant>
</constants>
</class>
diff --git a/doc/classes/AudioEffectSpectrumAnalyzer.xml b/doc/classes/AudioEffectSpectrumAnalyzer.xml
index 4c08b18f1d..10d29ff8ab 100644
--- a/doc/classes/AudioEffectSpectrumAnalyzer.xml
+++ b/doc/classes/AudioEffectSpectrumAnalyzer.xml
@@ -1,34 +1,46 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioEffectSpectrumAnalyzer" inherits="AudioEffect" version="4.0">
<brief_description>
+ Audio effect that can be used for real-time audio visualizations.
</brief_description>
<description>
+ This audio effect does not affect sound output, but can be used for real-time audio visualizations.
+ See also [AudioStreamGenerator] for procedurally generating sounds.
</description>
<tutorials>
+ <link title="https://godotengine.org/asset-library/asset/528">Audio Spectrum Demo</link>
+ <link title="https://godotengine.org/article/godot-32-will-get-new-audio-features">Godot 3.2 will get new audio features</link>
</tutorials>
<methods>
</methods>
<members>
<member name="buffer_length" type="float" setter="set_buffer_length" getter="get_buffer_length" default="2.0">
+ The length of the buffer to keep (in seconds). Higher values keep data around for longer, but require more memory.
</member>
- <member name="fft_size" type="int" setter="set_fft_size" getter="get_fft_size" enum="AudioEffectSpectrumAnalyzer.FFT_Size" default="2">
+ <member name="fft_size" type="int" setter="set_fft_size" getter="get_fft_size" enum="AudioEffectSpectrumAnalyzer.FFTSize" default="2">
+ The size of the [url=https://en.wikipedia.org/wiki/Fast_Fourier_transform]Fast Fourier transform[/url] buffer. Higher values smooth out the spectrum analysis over time, but have greater latency. The effects of this higher latency are especially noticeable with sudden amplitude changes.
</member>
<member name="tap_back_pos" type="float" setter="set_tap_back_pos" getter="get_tap_back_pos" default="0.01">
</member>
</members>
<constants>
- <constant name="FFT_SIZE_256" value="0" enum="FFT_Size">
+ <constant name="FFT_SIZE_256" value="0" enum="FFTSize">
+ Use a buffer of 256 samples for the Fast Fourier transform. Lowest latency, but least stable over time.
</constant>
- <constant name="FFT_SIZE_512" value="1" enum="FFT_Size">
+ <constant name="FFT_SIZE_512" value="1" enum="FFTSize">
+ Use a buffer of 512 samples for the Fast Fourier transform. Low latency, but less stable over time.
</constant>
- <constant name="FFT_SIZE_1024" value="2" enum="FFT_Size">
+ <constant name="FFT_SIZE_1024" value="2" enum="FFTSize">
+ Use a buffer of 1024 samples for the Fast Fourier transform. This is a compromise between latency and stability over time.
</constant>
- <constant name="FFT_SIZE_2048" value="3" enum="FFT_Size">
+ <constant name="FFT_SIZE_2048" value="3" enum="FFTSize">
+ Use a buffer of 2048 samples for the Fast Fourier transform. High latency, but stable over time.
</constant>
- <constant name="FFT_SIZE_4096" value="4" enum="FFT_Size">
+ <constant name="FFT_SIZE_4096" value="4" enum="FFTSize">
+ Use a buffer of 4096 samples for the Fast Fourier transform. Highest latency, but most stable over time.
</constant>
- <constant name="FFT_SIZE_MAX" value="5" enum="FFT_Size">
- Represents the size of the [enum FFT_Size] enum.
+ <constant name="FFT_SIZE_MAX" value="5" enum="FFTSize">
+ Represents the size of the [enum FFTSize] enum.
</constant>
</constants>
</class>
diff --git a/doc/classes/AudioStreamGenerator.xml b/doc/classes/AudioStreamGenerator.xml
index a273beb5af..8464bc8a85 100644
--- a/doc/classes/AudioStreamGenerator.xml
+++ b/doc/classes/AudioStreamGenerator.xml
@@ -1,18 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioStreamGenerator" inherits="AudioStream" version="4.0">
<brief_description>
+ Audio stream that generates sounds procedurally.
</brief_description>
<description>
+ This audio stream does not play back sounds, but expects a script to generate audio data for it instead. See also [AudioStreamGeneratorPlayback].
+ See also [AudioEffectSpectrumAnalyzer] for performing real-time audio spectrum analysis.
+ [b]Note:[/b] Due to performance constraints, this class is best used from C# or from a compiled language via GDNative. If you still want to use this class from GDScript, consider using a lower [member mix_rate] such as 11,025 Hz or 22,050 Hz.
</description>
<tutorials>
<link title="Audio Generator Demo">https://godotengine.org/asset-library/asset/526</link>
+ <link title="https://godotengine.org/article/godot-32-will-get-new-audio-features">Godot 3.2 will get new audio features</link>
</tutorials>
<methods>
</methods>
<members>
<member name="buffer_length" type="float" setter="set_buffer_length" getter="get_buffer_length" default="0.5">
+ The length of the buffer to generate (in seconds). Lower values result in less latency, but require the script to generate audio data faster, resulting in increased CPU usage and more risk for audio cracking if the CPU can't keep up.
</member>
<member name="mix_rate" type="float" setter="set_mix_rate" getter="get_mix_rate" default="44100.0">
+ The sample rate to use (in Hz). Higher values are more demanding for the CPU to generate, but result in better quality.
+ In games, common sample rates in use are [code]11025[/code], [code]16000[/code], [code]22050[/code], [code]32000[/code], [code]44100[/code], and [code]48000[/code].
+ According to the [url=https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem]Nyquist-Shannon sampling theorem[/url], there is no quality difference to human hearing when going past 40,000 Hz (since most humans can only hear up to ~20,000 Hz, often less). If you are generating lower-pitched sounds such as voices, lower sample rates such as [code]32000[/code] or [code]22050[/code] may be usable with no loss in quality.
</member>
</members>
<constants>
diff --git a/doc/classes/AudioStreamGeneratorPlayback.xml b/doc/classes/AudioStreamGeneratorPlayback.xml
index cd8e8735b6..503f72a048 100644
--- a/doc/classes/AudioStreamGeneratorPlayback.xml
+++ b/doc/classes/AudioStreamGeneratorPlayback.xml
@@ -1,11 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioStreamGeneratorPlayback" inherits="AudioStreamPlaybackResampled" version="4.0">
<brief_description>
+ Plays back audio generated using [AudioStreamGenerator].
</brief_description>
<description>
+ This class is meant to be used with [AudioStreamGenerator] to play back the generated audio in real-time.
</description>
<tutorials>
- <link title="Audio generator demo project">https://github.com/godotengine/godot-demo-projects/tree/master/audio/generator</link>
+ <link title="Audio Generator Demo">https://godotengine.org/asset-library/asset/526</link>
+ <link title="https://godotengine.org/article/godot-32-will-get-new-audio-features">Godot 3.2 will get new audio features</link>
</tutorials>
<methods>
<method name="can_push_buffer" qualifiers="const">
@@ -14,18 +17,21 @@
<argument index="0" name="amount" type="int">
</argument>
<description>
+ Returns [code]true[/code] if a buffer of the size [code]amount[/code] can be pushed to the audio sample data buffer without overflowing it, [code]false[/code] otherwise.
</description>
</method>
<method name="clear_buffer">
<return type="void">
</return>
<description>
+ Clears the audio sample data buffer.
</description>
</method>
<method name="get_frames_available" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the number of audio data frames left to play. If this returned number reaches [code]0[/code], the audio will stop playing until frames are added again. Therefore, make sure your script can always generate and push new audio frames fast enough to avoid audio cracking.
</description>
</method>
<method name="get_skips" qualifiers="const">
@@ -40,6 +46,7 @@
<argument index="0" name="frames" type="PackedVector2Array">
</argument>
<description>
+ Pushes several audio data frames to the buffer. This is usually more efficient than [method push_frame] in C# and compiled languages via GDNative, but [method push_buffer] may be [i]less[/i] efficient in GDScript.
</description>
</method>
<method name="push_frame">
@@ -48,6 +55,7 @@
<argument index="0" name="frame" type="Vector2">
</argument>
<description>
+ Pushes a single audio data frame to the buffer. This is usually less efficient than [method push_buffer] in C# and compiled languages via GDNative, but [method push_frame] may be [i]more[/i] efficient in GDScript.
</description>
</method>
</methods>
diff --git a/doc/classes/AudioStreamPlayback.xml b/doc/classes/AudioStreamPlayback.xml
index da75ff206c..cb01aa75e8 100644
--- a/doc/classes/AudioStreamPlayback.xml
+++ b/doc/classes/AudioStreamPlayback.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamPlayback" inherits="Reference" version="4.0">
+<class name="AudioStreamPlayback" inherits="RefCounted" version="4.0">
<brief_description>
Meta class for playing back audio.
</brief_description>
diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml
index 55190c5f9f..7c7f7e0cea 100644
--- a/doc/classes/AudioStreamPlayer.xml
+++ b/doc/classes/AudioStreamPlayer.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Plays an audio stream non-positionally.
+ To play audio positionally, use [AudioStreamPlayer2D] or [AudioStreamPlayer3D] instead of [AudioStreamPlayer].
</description>
<tutorials>
<link title="Audio streams">https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
@@ -59,7 +60,7 @@
<member name="autoplay" type="bool" setter="set_autoplay" getter="is_autoplay_enabled" default="false">
If [code]true[/code], audio plays when added to scene tree.
</member>
- <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="@&quot;Master&quot;">
+ <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&amp;&quot;Master&quot;">
Bus on which this audio is playing.
</member>
<member name="mix_target" type="int" setter="set_mix_target" getter="get_mix_target" enum="AudioStreamPlayer.MixTarget" default="0">
diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml
index d8b9385736..b1e18ab550 100644
--- a/doc/classes/AudioStreamPlayer2D.xml
+++ b/doc/classes/AudioStreamPlayer2D.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioStreamPlayer2D" inherits="Node2D" version="4.0">
<brief_description>
- Plays audio in 2D.
+ Plays positional sound in 2D space.
</brief_description>
<description>
Plays audio that dampens with distance from screen center.
+ See also [AudioStreamPlayer] to play a sound non-positionally.
+ [b]Note:[/b] Hiding an [AudioStreamPlayer2D] node does not disable its audio output. To temporarily disable an [AudioStreamPlayer2D]'s audio output, set [member volume_db] to a very low value like [code]-100[/code] (which isn't audible to human hearing).
</description>
<tutorials>
<link title="Audio streams">https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
@@ -60,7 +62,7 @@
<member name="autoplay" type="bool" setter="set_autoplay" getter="is_autoplay_enabled" default="false">
If [code]true[/code], audio plays when added to scene tree.
</member>
- <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="@&quot;Master&quot;">
+ <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&amp;&quot;Master&quot;">
Bus on which this audio is playing.
</member>
<member name="max_distance" type="float" setter="set_max_distance" getter="get_max_distance" default="2000.0">
diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml
index 7a8c4b2cc7..3bd20b4b9b 100644
--- a/doc/classes/AudioStreamPlayer3D.xml
+++ b/doc/classes/AudioStreamPlayer3D.xml
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioStreamPlayer3D" inherits="Node3D" version="4.0">
<brief_description>
- Plays 3D sound in 3D space.
+ Plays positional sound in 3D space.
</brief_description>
<description>
Plays a sound effect with directed sound effects, dampens with distance if needed, generates effect of hearable position in space. For greater realism, a low-pass filter is automatically applied to distant sounds. This can be disabled by setting [member attenuation_filter_cutoff_hz] to [code]20500[/code].
By default, audio is heard from the camera position. This can be changed by adding a [Listener3D] node to the scene and enabling it by calling [method Listener3D.make_current] on it.
+ See also [AudioStreamPlayer] to play a sound non-positionally.
+ [b]Note:[/b] Hiding an [AudioStreamPlayer3D] node does not disable its audio output. To temporarily disable an [AudioStreamPlayer3D]'s audio output, set [member unit_db] to a very low value like [code]-100[/code] (which isn't audible to human hearing).
</description>
<tutorials>
<link title="Audio streams">https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
@@ -67,7 +69,7 @@
<member name="autoplay" type="bool" setter="set_autoplay" getter="is_autoplay_enabled" default="false">
If [code]true[/code], audio plays when the AudioStreamPlayer3D node is added to scene tree.
</member>
- <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="@&quot;Master&quot;">
+ <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&amp;&quot;Master&quot;">
The bus on which this audio is playing.
</member>
<member name="doppler_tracking" type="int" setter="set_doppler_tracking" getter="get_doppler_tracking" enum="AudioStreamPlayer3D.DopplerTracking" default="0">
@@ -106,7 +108,7 @@
<member name="unit_db" type="float" setter="set_unit_db" getter="get_unit_db" default="0.0">
The base sound level unaffected by dampening, in decibels.
</member>
- <member name="unit_size" type="float" setter="set_unit_size" getter="get_unit_size" default="1.0">
+ <member name="unit_size" type="float" setter="set_unit_size" getter="get_unit_size" default="10.0">
The factor for the attenuation effect. Higher values make the sound audible over a larger distance.
</member>
</members>
diff --git a/doc/classes/AudioStreamSample.xml b/doc/classes/AudioStreamSample.xml
index c12e1bd05c..d07b1ac66d 100644
--- a/doc/classes/AudioStreamSample.xml
+++ b/doc/classes/AudioStreamSample.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
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.
- This class can also be used to store dynamically-generated PCM audio data.
+ This class can also be used to store dynamically-generated PCM audio data. See also [AudioStreamGenerator] for procedural audio generation.
</description>
<tutorials>
</tutorials>
@@ -39,7 +39,9 @@
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.
+ The sample rate for mixing this audio. Higher values require more storage space, but result in better quality.
+ In games, common sample rates in use are [code]11025[/code], [code]16000[/code], [code]22050[/code], [code]32000[/code], [code]44100[/code], and [code]48000[/code].
+ According to the [url=https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem]Nyquist-Shannon sampling theorem[/url], there is no quality difference to human hearing when going past 40,000 Hz (since most humans can only hear up to ~20,000 Hz, often less). If you are using lower-pitched sounds such as voices, lower sample rates such as [code]32000[/code] or [code]22050[/code] may be usable with no loss in quality.
</member>
<member name="stereo" type="bool" setter="set_stereo" getter="is_stereo" default="false">
If [code]true[/code], audio is stereo.
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index c87398ac8f..49edb4c691 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -142,6 +142,7 @@
</member>
<member name="clearcoat_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], clearcoat rendering is enabled. Adds a secondary transparent pass to the lighting calculation resulting in an added specular blob. This makes materials appear as if they have a clear layer on them that can be either glossy or rough.
+ [b]Note:[/b] Clearcoat rendering is not visible if the material's [member shading_mode] is [constant SHADING_MODE_UNSHADED].
</member>
<member name="clearcoat_gloss" type="float" setter="set_clearcoat_gloss" getter="get_clearcoat_gloss" default="0.5">
Sets the roughness of the clearcoat pass. A higher value results in a smoother clearcoat while a lower value results in a rougher clearcoat.
@@ -198,7 +199,7 @@
The emitted light's color. See [member emission_enabled].
</member>
<member name="emission_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
- If [code]true[/code], the body emits light. Emitting light makes the object appear brighter. The object can also cast light on other objects if a [GIProbe] is used and this object is used in baked lighting.
+ 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 [VoxelGI] is used and this object is used in baked lighting.
</member>
<member name="emission_energy" type="float" setter="set_emission_energy" getter="get_emission_energy" default="1.0">
The emitted light's strength. See [member emission_enabled].
@@ -304,6 +305,7 @@
</member>
<member name="rim_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], rim effect is enabled. Rim lighting increases the brightness at glancing angles on an object.
+ [b]Note:[/b] Rim lighting is not visible if the material's [member shading_mode] is [constant SHADING_MODE_UNSHADED].
</member>
<member name="rim_texture" type="Texture2D" setter="set_texture" getter="get_texture">
Texture used to set the strength of the rim lighting effect per-pixel. Multiplied by [member rim].
@@ -362,6 +364,8 @@
<member name="transparency" type="int" setter="set_transparency" getter="get_transparency" enum="BaseMaterial3D.Transparency" default="0">
If [code]true[/code], transparency is enabled on the body. See also [member blend_mode].
</member>
+ <member name="use_particle_trails" type="bool" setter="set_flag" getter="get_flag" default="false">
+ </member>
<member name="use_point_size" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], render point size can be changed.
[b]Note:[/b] this is only effective for objects whose geometry is point-based rather than triangle-based. See also [member point_size].
@@ -653,7 +657,9 @@
<constant name="FLAG_SUBSURFACE_MODE_SKIN" value="18" enum="Flags">
Enables the skin mode for subsurface scattering which is used to improve the look of subsurface scattering when used for human skin.
</constant>
- <constant name="FLAG_MAX" value="19" enum="Flags">
+ <constant name="FLAG_PARTICLE_TRAILS_MODE" value="19" enum="Flags">
+ </constant>
+ <constant name="FLAG_MAX" value="20" enum="Flags">
Represents the size of the [enum Flags] enum.
</constant>
<constant name="DIFFUSE_BURLEY" value="0" enum="DiffuseMode">
@@ -665,10 +671,7 @@
<constant name="DIFFUSE_LAMBERT_WRAP" value="2" enum="DiffuseMode">
Extends Lambert to cover more than 90 degrees when roughness increases.
</constant>
- <constant name="DIFFUSE_OREN_NAYAR" value="3" enum="DiffuseMode">
- Attempts to use roughness to emulate microsurfacing.
- </constant>
- <constant name="DIFFUSE_TOON" value="4" enum="DiffuseMode">
+ <constant name="DIFFUSE_TOON" value="3" enum="DiffuseMode">
Uses a hard cut for lighting, with smoothing affected by roughness.
</constant>
<constant name="SPECULAR_SCHLICK_GGX" value="0" enum="SpecularMode">
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index 55ae58ee3a..14fca04672 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -4,7 +4,7 @@
3×3 matrix datatype.
</brief_description>
<description>
- 3×3 matrix used for 3D rotation and scale. Almost always used as an orthogonal basis for a Transform.
+ 3×3 matrix used for 3D rotation and scale. Almost always used as an orthogonal basis for a [Transform3D].
Contains 3 vector fields X, Y and Z as its columns, which are typically interpreted as the local basis vectors of a transformation. For such use, it is composed of a scaling and a rotation matrix, in that order (M = R.S).
Can also be accessed as array of 3D vectors. These vectors are normally orthogonal to each other, but are not necessarily normalized (due to scaling).
For more information, read the "Matrices and transforms" documentation article.
@@ -53,13 +53,13 @@
</argument>
<description>
Constructs a pure rotation basis matrix from the given Euler angles (in the YXZ convention: when *composing*, first Y, then X, and Z last), given in the vector format as (X angle, Y angle, Z angle).
- Consider using the [Quat] constructor instead, which uses a quaternion instead of Euler angles.
+ Consider using the [Quaternion] constructor instead, which uses a quaternion instead of Euler angles.
</description>
</method>
<method name="Basis" qualifiers="constructor">
<return type="Basis">
</return>
- <argument index="0" name="from" type="Quat">
+ <argument index="0" name="from" type="Quaternion">
</argument>
<description>
Constructs a pure rotation basis matrix from the given quaternion.
@@ -91,7 +91,7 @@
</return>
<description>
Returns the basis's rotation in the form of Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last). The returned vector contains the rotation angles in the format (X angle, Y angle, Z angle).
- Consider using the [method get_rotation_quat] method instead, which returns a [Quat] quaternion instead of Euler angles.
+ Consider using the [method get_rotation_quaternion] method instead, which returns a [Quaternion] quaternion instead of Euler angles.
</description>
</method>
<method name="get_orthogonal_index" qualifiers="const">
@@ -101,8 +101,8 @@
This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1, 0, or 1, and returns the index of the point best representing the orientation of the object. It is mainly used by the [GridMap] editor. For further details, refer to the Godot source code.
</description>
</method>
- <method name="get_rotation_quat" qualifiers="const">
- <return type="Quat">
+ <method name="get_rotation_quaternion" qualifiers="const">
+ <return type="Quaternion">
</return>
<description>
Returns the basis's rotation in the form of a quaternion. See [method get_euler] if you need Euler angles, but keep in mind quaternions should generally be preferred to Euler angles.
diff --git a/doc/classes/BitMap.xml b/doc/classes/BitMap.xml
index 27ead07e6f..83e598d2ba 100644
--- a/doc/classes/BitMap.xml
+++ b/doc/classes/BitMap.xml
@@ -71,6 +71,12 @@
<argument index="1" name="epsilon" type="float" default="2.0">
</argument>
<description>
+ Creates an [Array] of polygons covering a rectangular portion of the bitmap. It uses a marching squares algorithm, followed by Ramer-Douglas-Peucker (RDP) reduction of the number of vertices. Each polygon is described as a [PackedVector2Array] of its vertices.
+ To get polygons covering the whole bitmap, pass:
+ [codeblock]
+ Rect2(Vector2(), get_size())
+ [/codeblock]
+ [code]epsilon[/code] is passed to RDP to control how accurately the polygons cover the bitmap: a lower [code]epsilon[/code] corresponds to more points in the polygons.
</description>
</method>
<method name="set_bit">
diff --git a/doc/classes/Bone2D.xml b/doc/classes/Bone2D.xml
index 910d488dfd..93744ddad7 100644
--- a/doc/classes/Bone2D.xml
+++ b/doc/classes/Bone2D.xml
@@ -19,6 +19,28 @@
Stores the node's current transforms in [member rest].
</description>
</method>
+ <method name="get_autocalculate_length_and_angle" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether this [code]Bone2D[/code] node is going to autocalculate its length and bone angle using its first [code]Bone2D[/code] child node, if one exists. If there are no [code]Bone2D[/code] children, then it cannot autocalculate these values and will print a warning.
+ </description>
+ </method>
+ <method name="get_bone_angle" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the angle of the bone in the [code]Bone2D[/code] node.
+ [b]Note:[/b] This is different from the [code]Bone2D[/code]'s rotation. The bone angle is the rotation of the bone shown by the [code]Bone2D[/code] gizmo, and because [code]Bone2D[/code] bones are based on positions, this can vary from the actual rotation of the [code]Bone2D[/code] node.
+ </description>
+ </method>
+ <method name="get_default_length" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Deprecated. Please use [code]get_length[/code] instead.
+ </description>
+ </method>
<method name="get_index_in_skeleton" qualifiers="const">
<return type="int">
</return>
@@ -26,6 +48,13 @@
Returns the node's index as part of the entire skeleton. See [Skeleton2D].
</description>
</method>
+ <method name="get_length" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the length of the bone in the [code]Bone2D[/code] node.
+ </description>
+ </method>
<method name="get_skeleton_rest" qualifiers="const">
<return type="Transform2D">
</return>
@@ -33,11 +62,45 @@
Returns the node's [member rest] [code]Transform2D[/code] if it doesn't have a parent, or its rest pose relative to its parent.
</description>
</method>
+ <method name="set_autocalculate_length_and_angle">
+ <return type="void">
+ </return>
+ <argument index="0" name="auto_calculate" type="bool">
+ </argument>
+ <description>
+ When set to [code]true[/code], the [code]Bone2D[/code] node will attempt to automatically calculate the bone angle and length using the first child [code]Bone2D[/code] node, if one exists. If none exist, the [code]Bone2D[/code] cannot automatically calculate these values and will print a warning.
+ </description>
+ </method>
+ <method name="set_bone_angle">
+ <return type="void">
+ </return>
+ <argument index="0" name="angle" type="float">
+ </argument>
+ <description>
+ Sets the bone angle for the [code]Bone2D[/code] node. This is typically set to the rotation from the [code]Bone2D[/code] node to a child [code]Bone2D[/code] node.
+ [b]Note:[/b] This is different from the [code]Bone2D[/code]'s rotation. The bone angle is the rotation of the bone shown by the [code]Bone2D[/code] gizmo, and because [code]Bone2D[/code] bones are based on positions, this can vary from the actual rotation of the [code]Bone2D[/code] node.
+ </description>
+ </method>
+ <method name="set_default_length">
+ <return type="void">
+ </return>
+ <argument index="0" name="default_length" type="float">
+ </argument>
+ <description>
+ Deprecated. Please use [code]set_length[/code] instead.
+ </description>
+ </method>
+ <method name="set_length">
+ <return type="void">
+ </return>
+ <argument index="0" name="length" type="float">
+ </argument>
+ <description>
+ Sets the length of the bone in the [code]Bone2D[/code] node.
+ </description>
+ </method>
</methods>
<members>
- <member name="default_length" type="float" setter="set_default_length" getter="get_default_length" default="16.0">
- Length of the bone's representation drawn in the editor's viewport in pixels.
- </member>
<member name="rest" type="Transform2D" setter="set_rest" getter="get_rest" default="Transform2D( 0, 0, 0, 0, 0, 0 )">
Rest transform of the bone. You can reset the node's transforms to this value using [method apply_rest].
</member>
diff --git a/doc/classes/ButtonGroup.xml b/doc/classes/ButtonGroup.xml
index 5aa2d699a8..0b31352611 100644
--- a/doc/classes/ButtonGroup.xml
+++ b/doc/classes/ButtonGroup.xml
@@ -28,6 +28,15 @@
<members>
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" override="true" default="true" />
</members>
+ <signals>
+ <signal name="pressed">
+ <argument index="0" name="button" type="Object">
+ </argument>
+ <description>
+ Emitted when one of the buttons of the group is pressed.
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index aa9f99a31e..9e70978db8 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -199,7 +199,7 @@
<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="Vector2" setter="set_gravity" getter="get_gravity" default="Vector2( 0, 98 )">
+ <member name="gravity" type="Vector2" setter="set_gravity" getter="get_gravity" default="Vector2( 0, 980 )">
Gravity applied to every particle.
</member>
<member name="hue_variation" type="float" setter="set_param" getter="get_param" default="0.0">
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index 0cfbd0270c..cbab1a8f50 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -151,6 +151,22 @@
Returns [code]true[/code] if both [Callable]s invoke the same custom target.
</description>
</method>
+ <method name="rpc" qualifiers="vararg const">
+ <return type="void">
+ </return>
+ <description>
+ Perform an RPC (Remote Procedure Call). This is used for multiplayer and is normally not available unless the function being called has been marked as [i]RPC[/i]. Calling it on unsupported functions will result in an error.
+ </description>
+ </method>
+ <method name="rpc_id" qualifiers="vararg const">
+ <return type="void">
+ </return>
+ <argument index="0" name="peer_id" type="int">
+ </argument>
+ <description>
+ Perform an RPC (Remote Procedure Call) on a specific peer ID (see multiplayer documentation for reference). This is used for multiplayer and is normally not available unless the function being called has been marked as [i]RPC[/i]. Calling it on unsupported functions will result in an error.
+ </description>
+ </method>
<method name="unbind" qualifiers="const">
<return type="Callable">
</return>
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
index 9f1d6d8e31..016eb05308 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -27,7 +27,7 @@
</description>
</method>
<method name="get_camera_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<description>
Gets the camera transform. Subclassed cameras such as [ClippedCamera3D] may provide different transforms than the [Node] transform.
@@ -55,10 +55,19 @@
<argument index="0" name="world_point" type="Vector3">
</argument>
<description>
- Returns [code]true[/code] if the given position is behind the camera.
+ Returns [code]true[/code] if the given position is behind the camera (the blue part of the linked diagram). [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/camera3d_position_frustum.png]See this diagram[/url] for an overview of position query methods.
[b]Note:[/b] A position which returns [code]false[/code] may still be outside the camera's field of view.
</description>
</method>
+ <method name="is_position_in_frustum" 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 inside the camera's frustum (the green part of the linked diagram). [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/camera3d_position_frustum.png]See this diagram[/url] for an overview of position query methods.
+ </description>
+ </method>
<method name="make_current">
<return type="void">
</return>
diff --git a/doc/classes/CameraFeed.xml b/doc/classes/CameraFeed.xml
index 4fc124592f..fc7dcd3772 100644
--- a/doc/classes/CameraFeed.xml
+++ b/doc/classes/CameraFeed.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CameraFeed" inherits="Reference" version="4.0">
+<class name="CameraFeed" inherits="RefCounted" version="4.0">
<brief_description>
A camera feed gives you access to a single physical camera attached to your device.
</brief_description>
diff --git a/doc/classes/CharFXTransform.xml b/doc/classes/CharFXTransform.xml
index 850098f741..7a6a18f532 100644
--- a/doc/classes/CharFXTransform.xml
+++ b/doc/classes/CharFXTransform.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CharFXTransform" inherits="Reference" version="4.0">
+<class name="CharFXTransform" inherits="RefCounted" version="4.0">
<brief_description>
Controls how an individual character will be displayed in a [RichTextEffect].
</brief_description>
@@ -37,7 +37,7 @@
The position offset the character will be drawn with (in pixels).
</member>
<member name="outline" type="bool" setter="set_outline" getter="is_outline" default="false">
- If [code]ture[/code], FX transform is called for outline drawing. Setting this property won't affect drawing.
+ If [code]true[/code], FX transform is called for outline drawing. Setting this property won't affect drawing.
</member>
<member name="range" type="Vector2i" setter="set_range" getter="get_range" default="Vector2i( 0, 0 )">
Absolute character range in the string, corresponding to the glyph. Setting this property won't affect drawing.
diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml
new file mode 100644
index 0000000000..0e6ca073a7
--- /dev/null
+++ b/doc/classes/CharacterBody2D.xml
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CharacterBody2D" inherits="PhysicsBody2D" version="4.0">
+ <brief_description>
+ Character body 2D node.
+ </brief_description>
+ <description>
+ Character 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 rigid body, these are the same as a static body. However, they have two main uses:
+ [b]Kinematic characters:[/b] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody3D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics.
+ [b]Kinematic motion:[/b] Character bodies can also be used for kinematic motion (same functionality as [member StaticBody3D.kinematic_motion] when enabled), which allows them to be moved by code and push other bodies on their path.
+ </description>
+ <tutorials>
+ <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
+ <link title="Using KinematicBody2D">https://docs.godotengine.org/en/latest/tutorials/physics/using_kinematic_body_2d.html</link>
+ <link title="2D Kinematic Character Demo">https://godotengine.org/asset-library/asset/113</link>
+ <link title="2D Platformer Demo">https://godotengine.org/asset-library/asset/120</link>
+ </tutorials>
+ <methods>
+ <method name="get_floor_normal" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
+ </description>
+ </method>
+ <method name="get_floor_velocity" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
+ </description>
+ </method>
+ <method name="get_slide_collision">
+ <return type="KinematicCollision2D">
+ </return>
+ <argument index="0" name="slide_idx" type="int">
+ </argument>
+ <description>
+ Returns a [KinematicCollision2D], which contains information about a collision that occurred during the last call to [method move_and_slide]. 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).
+ [b]Example usage:[/b]
+ [codeblocks]
+ [gdscript]
+ for i in get_slide_count():
+ var collision = get_slide_collision(i)
+ print("Collided with: ", collision.collider.name)
+ [/gdscript]
+ [csharp]
+ for (int i = 0; i &lt; GetSlideCount(); i++)
+ {
+ KinematicCollision2D collision = GetSlideCollision(i);
+ GD.Print("Collided with: ", (collision.Collider as Node).Name);
+ }
+ [/csharp]
+ [/codeblocks]
+ </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 collided with the ceiling on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code].
+ </description>
+ </method>
+ <method name="is_on_floor" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the body collided with the floor on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code].
+ </description>
+ </method>
+ <method name="is_on_wall" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the body collided with a wall on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code].
+ </description>
+ </method>
+ <method name="move_and_slide">
+ <return type="void">
+ </return>
+ <description>
+ Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidBody2D], it will also be affected by the motion of the other body. You can use this to make moving and 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.
+ Modifies [member linear_velocity] if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision].
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08">
+ Extra margin used for collision recovery when calling [method move_and_slide].
+ If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
+ A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
+ A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
+ </member>
+ <member name="floor_max_angle" type="float" setter="set_floor_max_angle" getter="get_floor_max_angle" default="0.785398">
+ Maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. The default value equals 45 degrees.
+ </member>
+ <member name="floor_max_angle_degrees" type="float" setter="set_floor_max_angle_degrees" getter="get_floor_max_angle_degrees" default="45.0">
+ Maximum angle (in degrees) where a slope is still considered a floor (or a ceiling), rather than a wall, when calling [method move_and_slide].
+ </member>
+ <member name="infinite_inertia" type="bool" setter="set_infinite_inertia_enabled" getter="is_infinite_inertia_enabled" default="true">
+ If [code]true[/code], the body will be able to push [RigidBody2D] nodes when calling [method move_and_slide], but it also won't detect any collisions with them. If [code]false[/code], it will interact with [RigidBody2D] nodes like with [StaticBody2D].
+ </member>
+ <member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector2( 0, 0 )">
+ Current velocity vector in pixels per second, used and modified during calls to [method move_and_slide].
+ </member>
+ <member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="4">
+ Maximum number of times the body can change direction before it stops when calling [method move_and_slide].
+ </member>
+ <member name="motion/sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false">
+ If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method move_and_slide] or [method PhysicsBody2D.move_and_collide] functions.
+ </member>
+ <member name="snap" type="Vector2" setter="set_snap" getter="get_snap" default="Vector2( 0, 0 )">
+ When set to a value different from [code]Vector2(0, 0)[/code], the body is kept attached to slopes when calling [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]Vector2(0, 0)[/code].
+ </member>
+ <member name="stop_on_slope" type="bool" setter="set_stop_on_slope_enabled" getter="is_stop_on_slope_enabled" default="false">
+ If [code]true[/code], the body will not slide on slopes when you include gravity in [code]linear_velocity[/code] when calling [method move_and_slide] and the body is standing still.
+ </member>
+ <member name="up_direction" type="Vector2" setter="set_up_direction" getter="get_up_direction" default="Vector2( 0, -1 )">
+ Direction vector used to determine what is a wall and what is a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. Defaults to [code]Vector2.UP[/code]. If set to [code]Vector2(0, 0)[/code], everything is considered a wall. This is useful for topdown games.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml
new file mode 100644
index 0000000000..790edfcad1
--- /dev/null
+++ b/doc/classes/CharacterBody3D.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CharacterBody3D" inherits="PhysicsBody3D" version="4.0">
+ <brief_description>
+ Character body 3D node.
+ </brief_description>
+ <description>
+ Character 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 rigid body, these are the same as a static body. However, they have two main uses:
+ [b]Kinematic characters:[/b] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody3D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics.
+ [b]Kinematic motion:[/b] Character bodies can also be used for kinematic motion (same functionality as [member StaticBody3D.kinematic_motion] when enabled), which allows them to be moved by code and push other bodies on their path.
+ </description>
+ <tutorials>
+ <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
+ <link title="3D Kinematic Character Demo">https://godotengine.org/asset-library/asset/126</link>
+ <link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link>
+ <link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/676</link>
+ <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
+ </tutorials>
+ <methods>
+ <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] 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] 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 call to [method move_and_slide]. 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 collided with the ceiling on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code].
+ </description>
+ </method>
+ <method name="is_on_floor" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the body collided with the floor on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code].
+ </description>
+ </method>
+ <method name="is_on_wall" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the body collided with a wall on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code].
+ </description>
+ </method>
+ <method name="move_and_slide">
+ <return type="void">
+ </return>
+ <description>
+ Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidBody3D], it will also be affected by the motion of the other body. You can use this to make moving and 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.
+ Modifies [member linear_velocity] if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision].
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001">
+ Extra margin used for collision recovery when calling [method move_and_slide].
+ If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
+ A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
+ A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
+ </member>
+ <member name="floor_max_angle" type="float" setter="set_floor_max_angle" getter="get_floor_max_angle" default="0.785398">
+ Maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. The default value equals 45 degrees.
+ </member>
+ <member name="floor_max_angle_degrees" type="float" setter="set_floor_max_angle_degrees" getter="get_floor_max_angle_degrees" default="45.0">
+ Maximum angle (in degrees) where a slope is still considered a floor (or a ceiling), rather than a wall, when calling [method move_and_slide].
+ </member>
+ <member name="infinite_inertia" type="bool" setter="set_infinite_inertia_enabled" getter="is_infinite_inertia_enabled" default="true">
+ If [code]true[/code], the body will be able to push [RigidBody3D] nodes when calling [method move_and_slide], but it also won't detect any collisions with them. If [code]false[/code], it will interact with [RigidBody3D] nodes like with [StaticBody3D].
+ </member>
+ <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3( 0, 0, 0 )">
+ Current velocity vector (typically meters per second), used and modified during calls to [method move_and_slide].
+ </member>
+ <member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="4">
+ Maximum number of times the body can change direction before it stops when calling [method move_and_slide].
+ </member>
+ <member name="snap" type="Vector3" setter="set_snap" getter="get_snap" default="Vector3( 0, 0, 0 )">
+ When set to a value different from [code]Vector3(0, 0, 0)[/code], the body is kept attached to slopes when calling [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]Vector3(0, 0, 0)[/code].
+ </member>
+ <member name="stop_on_slope" type="bool" setter="set_stop_on_slope_enabled" getter="is_stop_on_slope_enabled" default="false">
+ If [code]true[/code], the body will not slide on slopes when you include gravity in [code]linear_velocity[/code] when calling [method move_and_slide] and the body is standing still.
+ </member>
+ <member name="up_direction" type="Vector3" setter="set_up_direction" getter="get_up_direction" default="Vector3( 0, 1, 0 )">
+ Direction vector used to determine what is a wall and what is a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. Defaults to [code]Vector3.UP[/code]. If set to [code]Vector3(0, 0, 0)[/code], everything is considered a wall. This is useful for topdown games.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index 81795abcdd..1250350971 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -8,6 +8,100 @@
<tutorials>
</tutorials>
<methods>
+ <method name="_confirm_code_completion" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="replace" type="bool">
+ </argument>
+ <description>
+ Override this method to define how the selected entry should be inserted. If [code]replace[/code] is true, any existing text should be replaced.
+ </description>
+ </method>
+ <method name="_filter_code_completion_candidates" qualifiers="virtual">
+ <return type="Array">
+ </return>
+ <argument index="0" name="candidates" type="Array">
+ </argument>
+ <description>
+ Override this method to define what items in [code]candidates[/code] should be displayed.
+ Both [code]candidates[/code] and the return is a [Array] of [Dictionary], see [method get_code_completion_option] for [Dictionary] content.
+ </description>
+ </method>
+ <method name="_request_code_completion" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="force" type="bool">
+ </argument>
+ <description>
+ Override this method to define what happens when the user requests code completion. If [code]force[/code] is true, any checks should be bypassed.
+ </description>
+ </method>
+ <method name="add_code_completion_option">
+ <return type="void">
+ </return>
+ <argument index="0" name="type" type="int" enum="CodeEdit.CodeCompletionKind">
+ </argument>
+ <argument index="1" name="display_text" type="String">
+ </argument>
+ <argument index="2" name="insert_text" type="String">
+ </argument>
+ <argument index="3" name="text_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ </argument>
+ <argument index="4" name="icon" type="Resource" default="null">
+ </argument>
+ <argument index="5" name="value" type="Variant" default="0">
+ </argument>
+ <description>
+ Submits an item to the queue of potential candidates for the autocomplete menu. Call [method update_code_completion_options] to update the list.
+ [b]Note[/b]: This list will replace all current candidates.
+ </description>
+ </method>
+ <method name="add_comment_delimiter">
+ <return type="void">
+ </return>
+ <argument index="0" name="start_key" type="String">
+ </argument>
+ <argument index="1" name="end_key" type="String">
+ </argument>
+ <argument index="2" name="line_only" type="bool" default="false">
+ </argument>
+ <description>
+ Adds a comment delimiter.
+ Both the start and end keys must be symbols. Only the start key has to be unique.
+ Line only denotes if the region should continue until the end of the line or carry over on to the next line. If the end key is blank this is automatically set to [code]true[/code].
+ </description>
+ </method>
+ <method name="add_string_delimiter">
+ <return type="void">
+ </return>
+ <argument index="0" name="start_key" type="String">
+ </argument>
+ <argument index="1" name="end_key" type="String">
+ </argument>
+ <argument index="2" name="line_only" type="bool" default="false">
+ </argument>
+ <description>
+ Adds a string delimiter.
+ Both the start and end keys must be symbols. Only the start key has to be unique.
+ Line only denotes if the region should continue until the end of the line or carry over on to the next line. If the end key is blank this is automatically set to [code]true[/code].
+ </description>
+ </method>
+ <method name="can_fold_line" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="line" type="int">
+ </argument>
+ <description>
+ Returns if the given line is foldable, that is, it has indented lines right below it or a comment / string block.
+ </description>
+ </method>
+ <method name="cancel_code_completion">
+ <return type="void">
+ </return>
+ <description>
+ Cancels the autocomplete menu.
+ </description>
+ </method>
<method name="clear_bookmarked_lines">
<return type="void">
</return>
@@ -20,12 +114,51 @@
<description>
</description>
</method>
+ <method name="clear_comment_delimiters">
+ <return type="void">
+ </return>
+ <description>
+ Removes all comment delimiters.
+ </description>
+ </method>
<method name="clear_executing_lines">
<return type="void">
</return>
<description>
</description>
</method>
+ <method name="clear_string_delimiters">
+ <return type="void">
+ </return>
+ <description>
+ Removes all string delimiters.
+ </description>
+ </method>
+ <method name="confirm_code_completion">
+ <return type="void">
+ </return>
+ <argument index="0" name="replace" type="bool" default="false">
+ </argument>
+ <description>
+ Inserts the selected entry into the text. If [code]replace[/code] is true, any existing text is replaced rather then merged.
+ </description>
+ </method>
+ <method name="fold_all_lines">
+ <return type="void">
+ </return>
+ <description>
+ Folds all lines that are possible to be folded (see [method can_fold_line]).
+ </description>
+ </method>
+ <method name="fold_line">
+ <return type="void">
+ </return>
+ <argument index="0" name="line" type="int">
+ </argument>
+ <description>
+ Folds the given line, if possible (see [method can_fold_line]).
+ </description>
+ </method>
<method name="get_bookmarked_lines" qualifiers="const">
<return type="Array">
</return>
@@ -38,12 +171,135 @@
<description>
</description>
</method>
+ <method name="get_code_completion_option" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ Gets the completion option at [code]index[/code]. The return [Dictionary] has the following key-values:
+ [code]kind[/code]: [enum CodeCompletionKind]
+ [code]display_text[/code]: Text that is shown on the autocomplete menu.
+ [code]insert_text[/code]: Text that is to be inserted when this item is selected.
+ [code]font_color[/code]: Color of the text on the autocomplete menu.
+ [code]icon[/code]: Icon to draw on the autocomplete menu.
+ [code]default_value[/code]: Value of the symbol.
+ </description>
+ </method>
+ <method name="get_code_completion_options" qualifiers="const">
+ <return type="Dictionary[]">
+ </return>
+ <description>
+ Gets all completion options, see [method get_code_completion_option] for return content.
+ </description>
+ </method>
+ <method name="get_code_completion_selected_index" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Gets the index of the current selected completion option.
+ </description>
+ </method>
+ <method name="get_delimiter_end_key" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="delimiter_index" type="int">
+ </argument>
+ <description>
+ Gets the end key for a string or comment region index.
+ </description>
+ </method>
+ <method name="get_delimiter_end_position" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="line" type="int">
+ </argument>
+ <argument index="1" name="column" type="int">
+ </argument>
+ <description>
+ If [code]line[/code] [code]column[/code] is in a string or comment, returns the end position of the region. If not or no end could be found, both [Vector2] values will be [code]-1[/code].
+ </description>
+ </method>
+ <method name="get_delimiter_start_key" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="delimiter_index" type="int">
+ </argument>
+ <description>
+ Gets the start key for a string or comment region index.
+ </description>
+ </method>
+ <method name="get_delimiter_start_position" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="line" type="int">
+ </argument>
+ <argument index="1" name="column" type="int">
+ </argument>
+ <description>
+ If [code]line[/code] [code]column[/code] is in a string or comment, returns the start position of the region. If not or no start could be found, both [Vector2] values will be [code]-1[/code].
+ </description>
+ </method>
<method name="get_executing_lines" qualifiers="const">
<return type="Array">
</return>
<description>
</description>
</method>
+ <method name="get_folded_lines" qualifiers="const">
+ <return type="int[]">
+ </return>
+ <description>
+ Return all lines that are current folded.
+ </description>
+ </method>
+ <method name="get_text_for_code_completion" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ Returns the full text with char [code]0xFFFF[/code] at the caret location.
+ </description>
+ </method>
+ <method name="has_comment_delimiter" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="start_key" type="String">
+ </argument>
+ <description>
+ Returns [code]true[/code] if comment [code]start_key[/code] exists.
+ </description>
+ </method>
+ <method name="has_string_delimiter" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="start_key" type="String">
+ </argument>
+ <description>
+ Returns [code]true[/code] if string [code]start_key[/code] exists.
+ </description>
+ </method>
+ <method name="is_in_comment" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="line" type="int">
+ </argument>
+ <argument index="1" name="column" type="int" default="-1">
+ </argument>
+ <description>
+ Return delimiter index if [code]line[/code] [code]column[/code] is in a comment. If [code]column[/code] is not provided, will return delimiter index if the entire [code]line[/code] is a comment. Otherwise [code]-1[/code].
+ </description>
+ </method>
+ <method name="is_in_string" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="line" type="int">
+ </argument>
+ <argument index="1" name="column" type="int" default="-1">
+ </argument>
+ <description>
+ Return the delimiter index if [code]line[/code] [code]column[/code] is in a string. If [code]column[/code] is not provided, will return the delimiter index if the entire [code]line[/code] is a string. Otherwise [code]-1[/code].
+ </description>
+ </method>
<method name="is_line_bookmarked" qualifiers="const">
<return type="bool">
</return>
@@ -68,6 +324,69 @@
<description>
</description>
</method>
+ <method name="is_line_folded" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="line" type="int">
+ </argument>
+ <description>
+ Returns whether the line at the specified index is folded or not.
+ </description>
+ </method>
+ <method name="remove_comment_delimiter">
+ <return type="void">
+ </return>
+ <argument index="0" name="start_key" type="String">
+ </argument>
+ <description>
+ Removes the comment delimiter with [code]start_key[/code].
+ </description>
+ </method>
+ <method name="remove_string_delimiter">
+ <return type="void">
+ </return>
+ <argument index="0" name="start_key" type="String">
+ </argument>
+ <description>
+ Removes the string delimiter with [code]start_key[/code].
+ </description>
+ </method>
+ <method name="request_code_completion">
+ <return type="void">
+ </return>
+ <argument index="0" name="force" type="bool" default="false">
+ </argument>
+ <description>
+ Emits [signal request_code_completion], if [code]force[/code] is true will bypass all checks. Otherwise will check that the caret is in a word or in front of a prefix. Will ignore the request if all current options are of type file path, node path or signal.
+ </description>
+ </method>
+ <method name="set_code_completion_selected_index">
+ <return type="void">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ Sets the current selected completion option.
+ </description>
+ </method>
+ <method name="set_code_hint">
+ <return type="void">
+ </return>
+ <argument index="0" name="code_hint" type="String">
+ </argument>
+ <description>
+ Sets the code hint text. Pass an empty string to clear.
+ </description>
+ </method>
+ <method name="set_code_hint_draw_below">
+ <return type="void">
+ </return>
+ <argument index="0" name="draw_below" type="bool">
+ </argument>
+ <description>
+ Sets if the code hint should draw below the text.
+ </description>
+ </method>
<method name="set_line_as_bookmarked">
<return type="void">
</return>
@@ -98,8 +417,54 @@
<description>
</description>
</method>
+ <method name="toggle_foldable_line">
+ <return type="void">
+ </return>
+ <argument index="0" name="line" type="int">
+ </argument>
+ <description>
+ Toggle the folding of the code block at the given line.
+ </description>
+ </method>
+ <method name="unfold_all_lines">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="unfold_line">
+ <return type="void">
+ </return>
+ <argument index="0" name="line" type="int">
+ </argument>
+ <description>
+ Unfolds all lines that were previously folded.
+ </description>
+ </method>
+ <method name="update_code_completion_options">
+ <return type="void">
+ </return>
+ <argument index="0" name="force" type="bool">
+ </argument>
+ <description>
+ Submits all completion options added with [method add_code_completion_option]. Will try to force the autoccomplete menu to popup, if [code]force[/code] is [code]true[/code].
+ [b]Note[/b]: This will replace all current candidates.
+ </description>
+ </method>
</methods>
<members>
+ <member name="code_completion_enabled" type="bool" setter="set_code_completion_enabled" getter="is_code_completion_enabled" default="false">
+ Sets whether code completion is allowed.
+ </member>
+ <member name="code_completion_prefixes" type="String[]" setter="set_code_completion_prefixes" getter="get_code_comletion_prefixes" default="[ ]">
+ Sets prefixes that will trigger code completion.
+ </member>
+ <member name="delimiter_comments" type="String[]" setter="set_comment_delimiters" getter="get_comment_delimiters" default="[ ]">
+ Sets the comment delimiters. All existing comment delimiters will be removed.
+ </member>
+ <member name="delimiter_strings" type="String[]" setter="set_string_delimiters" getter="get_string_delimiters" default="[ ]">
+ Sets the string delimiters. All existing string delimiters will be removed.
+ </member>
<member name="draw_bookmarks" type="bool" setter="set_draw_bookmarks_gutter" getter="is_drawing_bookmarks_gutter" default="false">
</member>
<member name="draw_breakpoints_gutter" type="bool" setter="set_draw_breakpoints_gutter" getter="is_drawing_breakpoints_gutter" default="false">
@@ -111,6 +476,9 @@
<member name="draw_line_numbers" type="bool" setter="set_draw_line_numbers" getter="is_draw_line_numbers_enabled" default="false">
</member>
<member name="layout_direction" type="int" setter="set_layout_direction" getter="get_layout_direction" override="true" enum="Control.LayoutDirection" default="2" />
+ <member name="line_folding" type="bool" setter="set_line_folding_enabled" getter="is_line_folding_enabled" default="true">
+ Sets whether line folding is allowed.
+ </member>
<member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" override="true" default="[ ]" />
<member name="text_direction" type="int" setter="set_text_direction" getter="get_text_direction" override="true" enum="Control.TextDirection" default="1" />
<member name="zero_pad_line_numbers" type="bool" setter="set_line_numbers_zero_padded" getter="is_line_numbers_zero_padded" default="false">
@@ -123,8 +491,33 @@
<description>
</description>
</signal>
+ <signal name="request_code_completion">
+ <description>
+ Emitted when the user requests code completion.
+ </description>
+ </signal>
</signals>
<constants>
+ <constant name="KIND_CLASS" value="0" enum="CodeCompletionKind">
+ </constant>
+ <constant name="KIND_FUNCTION" value="1" enum="CodeCompletionKind">
+ </constant>
+ <constant name="KIND_SIGNAL" value="2" enum="CodeCompletionKind">
+ </constant>
+ <constant name="KIND_VARIABLE" value="3" enum="CodeCompletionKind">
+ </constant>
+ <constant name="KIND_MEMBER" value="4" enum="CodeCompletionKind">
+ </constant>
+ <constant name="KIND_ENUM" value="5" enum="CodeCompletionKind">
+ </constant>
+ <constant name="KIND_CONSTANT" value="6" enum="CodeCompletionKind">
+ </constant>
+ <constant name="KIND_NODE_PATH" value="7" enum="CodeCompletionKind">
+ </constant>
+ <constant name="KIND_FILE_PATH" value="8" enum="CodeCompletionKind">
+ </constant>
+ <constant name="KIND_PLAIN_TEXT" value="9" enum="CodeCompletionKind">
+ </constant>
</constants>
<theme_items>
<theme_item name="background_color" type="Color" default="Color( 0, 0, 0, 0 )">
@@ -175,6 +568,8 @@
</theme_item>
<theme_item name="folded" type="Texture2D">
</theme_item>
+ <theme_item name="folded_eol_icon" type="Texture2D">
+ </theme_item>
<theme_item name="font" type="Font">
</theme_item>
<theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )">
@@ -193,8 +588,6 @@
</theme_item>
<theme_item name="line_spacing" type="int" default="4">
</theme_item>
- <theme_item name="mark_color" type="Color" default="Color( 1, 0.4, 0.4, 0.4 )">
- </theme_item>
<theme_item name="normal" type="StyleBox">
</theme_item>
<theme_item name="outline_size" type="int" default="0">
diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index e18970d84f..7c4c75bf0f 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -99,15 +99,6 @@
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="set_collision_layer_bit">
<return type="void">
</return>
@@ -132,6 +123,15 @@
If [code]value[/value] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_mask].
</description>
</method>
+ <method name="shape_find_owner" qualifiers="const">
+ <return type="int">
+ </return>
+ <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>
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index 4523a63c4c..4ab37f5c7b 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -16,14 +16,14 @@
</argument>
<argument index="1" name="event" type="InputEvent">
</argument>
- <argument index="2" name="click_position" type="Vector3">
+ <argument index="2" name="position" type="Vector3">
</argument>
- <argument index="3" name="click_normal" type="Vector3">
+ <argument index="3" name="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.
+ Receives unhandled [InputEvent]s. [code]position[/code] is the location in world space of the mouse pointer on the surface of the shape with index [code]shape_idx[/code] and [code]normal[/code] is the normal vector of the surface at that point. Connect to the [signal input_event] signal to easily pick up these events.
</description>
</method>
<method name="create_shape_owner">
@@ -179,12 +179,12 @@
</description>
</method>
<method name="shape_owner_get_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="owner_id" type="int">
</argument>
<description>
- Returns the shape owner's [Transform].
+ Returns the shape owner's [Transform3D].
</description>
</method>
<method name="shape_owner_remove_shape">
@@ -214,10 +214,10 @@
</return>
<argument index="0" name="owner_id" type="int">
</argument>
- <argument index="1" name="transform" type="Transform">
+ <argument index="1" name="transform" type="Transform3D">
</argument>
<description>
- Sets the [Transform] of the given shape owner.
+ Sets the [Transform3D] of the given shape owner.
</description>
</method>
</methods>
@@ -230,9 +230,6 @@
The physics layers this CollisionObject3D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
[b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
- <member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" default="true">
- If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one [code]collision_layer[/code] bit to be set.
- </member>
<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>
@@ -246,14 +243,14 @@
</argument>
<argument index="1" name="event" type="InputEvent">
</argument>
- <argument index="2" name="click_position" type="Vector3">
+ <argument index="2" name="position" type="Vector3">
</argument>
- <argument index="3" name="click_normal" type="Vector3">
+ <argument index="3" name="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.
+ Emitted when the object receives an unhandled [InputEvent]. [code]position[/code] is the location in world space of the mouse pointer on the surface of the shape with index [code]shape_idx[/code] and [code]normal[/code] is the normal vector of the surface at that point.
</description>
</signal>
<signal name="mouse_entered">
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index c33d007735..ddff92e6fc 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -136,6 +136,17 @@
[/codeblocks]
</description>
</method>
+ <method name="clamp" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="min" type="Color" default="Color( 0, 0, 0, 0 )">
+ </argument>
+ <argument index="1" name="max" type="Color" default="Color( 1, 1, 1, 1 )">
+ </argument>
+ <description>
+ Returns a new color with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
+ </description>
+ </method>
<method name="darkened" qualifiers="const">
<return type="Color">
</return>
@@ -269,7 +280,7 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the linear interpolation with another color. The interpolation factor [code]t[/code] is between 0 and 1.
+ Returns the linear interpolation with another color. The interpolation factor [code]weight[/code] is between 0 and 1.
[codeblocks]
[gdscript]
var c1 = Color(1.0, 0.0, 0.0)
@@ -564,442 +575,442 @@
</member>
</members>
<constants>
- <constant name="aliceblue" value="Color( 0.94, 0.97, 1, 1 )">
+ <constant name="ALICE_BLUE" value="Color( 0.94, 0.97, 1, 1 )">
Alice blue color.
</constant>
- <constant name="antiquewhite" value="Color( 0.98, 0.92, 0.84, 1 )">
+ <constant name="ANTIQUE_WHITE" value="Color( 0.98, 0.92, 0.84, 1 )">
Antique white color.
</constant>
- <constant name="aqua" value="Color( 0, 1, 1, 1 )">
+ <constant name="AQUA" value="Color( 0, 1, 1, 1 )">
Aqua color.
</constant>
- <constant name="aquamarine" value="Color( 0.5, 1, 0.83, 1 )">
+ <constant name="AQUAMARINE" value="Color( 0.5, 1, 0.83, 1 )">
Aquamarine color.
</constant>
- <constant name="azure" value="Color( 0.94, 1, 1, 1 )">
+ <constant name="AZURE" value="Color( 0.94, 1, 1, 1 )">
Azure color.
</constant>
- <constant name="beige" value="Color( 0.96, 0.96, 0.86, 1 )">
+ <constant name="BEIGE" value="Color( 0.96, 0.96, 0.86, 1 )">
Beige color.
</constant>
- <constant name="bisque" value="Color( 1, 0.89, 0.77, 1 )">
+ <constant name="BISQUE" value="Color( 1, 0.89, 0.77, 1 )">
Bisque color.
</constant>
- <constant name="black" value="Color( 0, 0, 0, 1 )">
+ <constant name="BLACK" value="Color( 0, 0, 0, 1 )">
Black color.
</constant>
- <constant name="blanchedalmond" value="Color( 1, 0.92, 0.8, 1 )">
- Blanche almond color.
+ <constant name="BLANCHED_ALMOND" value="Color( 1, 0.92, 0.8, 1 )">
+ Blanched almond color.
</constant>
- <constant name="blue" value="Color( 0, 0, 1, 1 )">
+ <constant name="BLUE" value="Color( 0, 0, 1, 1 )">
Blue color.
</constant>
- <constant name="blueviolet" value="Color( 0.54, 0.17, 0.89, 1 )">
+ <constant name="BLUE_VIOLET" value="Color( 0.54, 0.17, 0.89, 1 )">
Blue violet color.
</constant>
- <constant name="brown" value="Color( 0.65, 0.16, 0.16, 1 )">
+ <constant name="BROWN" value="Color( 0.65, 0.16, 0.16, 1 )">
Brown color.
</constant>
- <constant name="burlywood" value="Color( 0.87, 0.72, 0.53, 1 )">
- Burly wood color.
+ <constant name="BURLYWOOD" value="Color( 0.87, 0.72, 0.53, 1 )">
+ Burlywood color.
</constant>
- <constant name="cadetblue" value="Color( 0.37, 0.62, 0.63, 1 )">
+ <constant name="CADET_BLUE" value="Color( 0.37, 0.62, 0.63, 1 )">
Cadet blue color.
</constant>
- <constant name="chartreuse" value="Color( 0.5, 1, 0, 1 )">
+ <constant name="CHARTREUSE" value="Color( 0.5, 1, 0, 1 )">
Chartreuse color.
</constant>
- <constant name="chocolate" value="Color( 0.82, 0.41, 0.12, 1 )">
+ <constant name="CHOCOLATE" value="Color( 0.82, 0.41, 0.12, 1 )">
Chocolate color.
</constant>
- <constant name="coral" value="Color( 1, 0.5, 0.31, 1 )">
+ <constant name="CORAL" value="Color( 1, 0.5, 0.31, 1 )">
Coral color.
</constant>
- <constant name="cornflower" value="Color( 0.39, 0.58, 0.93, 1 )">
- Cornflower color.
+ <constant name="CORNFLOWER_BLUE" value="Color( 0.39, 0.58, 0.93, 1 )">
+ Cornflower blue color.
</constant>
- <constant name="cornsilk" value="Color( 1, 0.97, 0.86, 1 )">
- Corn silk color.
+ <constant name="CORNSILK" value="Color( 1, 0.97, 0.86, 1 )">
+ Cornsilk color.
</constant>
- <constant name="crimson" value="Color( 0.86, 0.08, 0.24, 1 )">
+ <constant name="CRIMSON" value="Color( 0.86, 0.08, 0.24, 1 )">
Crimson color.
</constant>
- <constant name="cyan" value="Color( 0, 1, 1, 1 )">
+ <constant name="CYAN" value="Color( 0, 1, 1, 1 )">
Cyan color.
</constant>
- <constant name="darkblue" value="Color( 0, 0, 0.55, 1 )">
+ <constant name="DARK_BLUE" value="Color( 0, 0, 0.55, 1 )">
Dark blue color.
</constant>
- <constant name="darkcyan" value="Color( 0, 0.55, 0.55, 1 )">
+ <constant name="DARK_CYAN" value="Color( 0, 0.55, 0.55, 1 )">
Dark cyan color.
</constant>
- <constant name="darkgoldenrod" value="Color( 0.72, 0.53, 0.04, 1 )">
+ <constant name="DARK_GOLDENROD" value="Color( 0.72, 0.53, 0.04, 1 )">
Dark goldenrod color.
</constant>
- <constant name="darkgray" value="Color( 0.66, 0.66, 0.66, 1 )">
+ <constant name="DARK_GRAY" value="Color( 0.66, 0.66, 0.66, 1 )">
Dark gray color.
</constant>
- <constant name="darkgreen" value="Color( 0, 0.39, 0, 1 )">
+ <constant name="DARK_GREEN" value="Color( 0, 0.39, 0, 1 )">
Dark green color.
</constant>
- <constant name="darkkhaki" value="Color( 0.74, 0.72, 0.42, 1 )">
+ <constant name="DARK_KHAKI" value="Color( 0.74, 0.72, 0.42, 1 )">
Dark khaki color.
</constant>
- <constant name="darkmagenta" value="Color( 0.55, 0, 0.55, 1 )">
+ <constant name="DARK_MAGENTA" value="Color( 0.55, 0, 0.55, 1 )">
Dark magenta color.
</constant>
- <constant name="darkolivegreen" value="Color( 0.33, 0.42, 0.18, 1 )">
+ <constant name="DARK_OLIVE_GREEN" value="Color( 0.33, 0.42, 0.18, 1 )">
Dark olive green color.
</constant>
- <constant name="darkorange" value="Color( 1, 0.55, 0, 1 )">
+ <constant name="DARK_ORANGE" value="Color( 1, 0.55, 0, 1 )">
Dark orange color.
</constant>
- <constant name="darkorchid" value="Color( 0.6, 0.2, 0.8, 1 )">
+ <constant name="DARK_ORCHID" value="Color( 0.6, 0.2, 0.8, 1 )">
Dark orchid color.
</constant>
- <constant name="darkred" value="Color( 0.55, 0, 0, 1 )">
+ <constant name="DARK_RED" value="Color( 0.55, 0, 0, 1 )">
Dark red color.
</constant>
- <constant name="darksalmon" value="Color( 0.91, 0.59, 0.48, 1 )">
+ <constant name="DARK_SALMON" value="Color( 0.91, 0.59, 0.48, 1 )">
Dark salmon color.
</constant>
- <constant name="darkseagreen" value="Color( 0.56, 0.74, 0.56, 1 )">
+ <constant name="DARK_SEA_GREEN" value="Color( 0.56, 0.74, 0.56, 1 )">
Dark sea green color.
</constant>
- <constant name="darkslateblue" value="Color( 0.28, 0.24, 0.55, 1 )">
+ <constant name="DARK_SLATE_BLUE" value="Color( 0.28, 0.24, 0.55, 1 )">
Dark slate blue color.
</constant>
- <constant name="darkslategray" value="Color( 0.18, 0.31, 0.31, 1 )">
+ <constant name="DARK_SLATE_GRAY" value="Color( 0.18, 0.31, 0.31, 1 )">
Dark slate gray color.
</constant>
- <constant name="darkturquoise" value="Color( 0, 0.81, 0.82, 1 )">
+ <constant name="DARK_TURQUOISE" value="Color( 0, 0.81, 0.82, 1 )">
Dark turquoise color.
</constant>
- <constant name="darkviolet" value="Color( 0.58, 0, 0.83, 1 )">
+ <constant name="DARK_VIOLET" value="Color( 0.58, 0, 0.83, 1 )">
Dark violet color.
</constant>
- <constant name="deeppink" value="Color( 1, 0.08, 0.58, 1 )">
+ <constant name="DEEP_PINK" value="Color( 1, 0.08, 0.58, 1 )">
Deep pink color.
</constant>
- <constant name="deepskyblue" value="Color( 0, 0.75, 1, 1 )">
+ <constant name="DEEP_SKY_BLUE" value="Color( 0, 0.75, 1, 1 )">
Deep sky blue color.
</constant>
- <constant name="dimgray" value="Color( 0.41, 0.41, 0.41, 1 )">
+ <constant name="DIM_GRAY" value="Color( 0.41, 0.41, 0.41, 1 )">
Dim gray color.
</constant>
- <constant name="dodgerblue" value="Color( 0.12, 0.56, 1, 1 )">
+ <constant name="DODGER_BLUE" value="Color( 0.12, 0.56, 1, 1 )">
Dodger blue color.
</constant>
- <constant name="firebrick" value="Color( 0.7, 0.13, 0.13, 1 )">
+ <constant name="FIREBRICK" value="Color( 0.7, 0.13, 0.13, 1 )">
Firebrick color.
</constant>
- <constant name="floralwhite" value="Color( 1, 0.98, 0.94, 1 )">
+ <constant name="FLORAL_WHITE" value="Color( 1, 0.98, 0.94, 1 )">
Floral white color.
</constant>
- <constant name="forestgreen" value="Color( 0.13, 0.55, 0.13, 1 )">
+ <constant name="FOREST_GREEN" value="Color( 0.13, 0.55, 0.13, 1 )">
Forest green color.
</constant>
- <constant name="fuchsia" value="Color( 1, 0, 1, 1 )">
+ <constant name="FUCHSIA" value="Color( 1, 0, 1, 1 )">
Fuchsia color.
</constant>
- <constant name="gainsboro" value="Color( 0.86, 0.86, 0.86, 1 )">
+ <constant name="GAINSBORO" value="Color( 0.86, 0.86, 0.86, 1 )">
Gainsboro color.
</constant>
- <constant name="ghostwhite" value="Color( 0.97, 0.97, 1, 1 )">
+ <constant name="GHOST_WHITE" value="Color( 0.97, 0.97, 1, 1 )">
Ghost white color.
</constant>
- <constant name="gold" value="Color( 1, 0.84, 0, 1 )">
+ <constant name="GOLD" value="Color( 1, 0.84, 0, 1 )">
Gold color.
</constant>
- <constant name="goldenrod" value="Color( 0.85, 0.65, 0.13, 1 )">
+ <constant name="GOLDENROD" value="Color( 0.85, 0.65, 0.13, 1 )">
Goldenrod color.
</constant>
- <constant name="gray" value="Color( 0.75, 0.75, 0.75, 1 )">
+ <constant name="GRAY" value="Color( 0.75, 0.75, 0.75, 1 )">
Gray color.
</constant>
- <constant name="green" value="Color( 0, 1, 0, 1 )">
+ <constant name="GREEN" value="Color( 0, 1, 0, 1 )">
Green color.
</constant>
- <constant name="greenyellow" value="Color( 0.68, 1, 0.18, 1 )">
+ <constant name="GREEN_YELLOW" value="Color( 0.68, 1, 0.18, 1 )">
Green yellow color.
</constant>
- <constant name="honeydew" value="Color( 0.94, 1, 0.94, 1 )">
+ <constant name="HONEYDEW" value="Color( 0.94, 1, 0.94, 1 )">
Honeydew color.
</constant>
- <constant name="hotpink" value="Color( 1, 0.41, 0.71, 1 )">
+ <constant name="HOT_PINK" value="Color( 1, 0.41, 0.71, 1 )">
Hot pink color.
</constant>
- <constant name="indianred" value="Color( 0.8, 0.36, 0.36, 1 )">
+ <constant name="INDIAN_RED" value="Color( 0.8, 0.36, 0.36, 1 )">
Indian red color.
</constant>
- <constant name="indigo" value="Color( 0.29, 0, 0.51, 1 )">
+ <constant name="INDIGO" value="Color( 0.29, 0, 0.51, 1 )">
Indigo color.
</constant>
- <constant name="ivory" value="Color( 1, 1, 0.94, 1 )">
+ <constant name="IVORY" value="Color( 1, 1, 0.94, 1 )">
Ivory color.
</constant>
- <constant name="khaki" value="Color( 0.94, 0.9, 0.55, 1 )">
+ <constant name="KHAKI" value="Color( 0.94, 0.9, 0.55, 1 )">
Khaki color.
</constant>
- <constant name="lavender" value="Color( 0.9, 0.9, 0.98, 1 )">
+ <constant name="LAVENDER" value="Color( 0.9, 0.9, 0.98, 1 )">
Lavender color.
</constant>
- <constant name="lavenderblush" value="Color( 1, 0.94, 0.96, 1 )">
+ <constant name="LAVENDER_BLUSH" value="Color( 1, 0.94, 0.96, 1 )">
Lavender blush color.
</constant>
- <constant name="lawngreen" value="Color( 0.49, 0.99, 0, 1 )">
+ <constant name="LAWN_GREEN" value="Color( 0.49, 0.99, 0, 1 )">
Lawn green color.
</constant>
- <constant name="lemonchiffon" value="Color( 1, 0.98, 0.8, 1 )">
+ <constant name="LEMON_CHIFFON" value="Color( 1, 0.98, 0.8, 1 )">
Lemon chiffon color.
</constant>
- <constant name="lightblue" value="Color( 0.68, 0.85, 0.9, 1 )">
+ <constant name="LIGHT_BLUE" value="Color( 0.68, 0.85, 0.9, 1 )">
Light blue color.
</constant>
- <constant name="lightcoral" value="Color( 0.94, 0.5, 0.5, 1 )">
+ <constant name="LIGHT_CORAL" value="Color( 0.94, 0.5, 0.5, 1 )">
Light coral color.
</constant>
- <constant name="lightcyan" value="Color( 0.88, 1, 1, 1 )">
+ <constant name="LIGHT_CYAN" value="Color( 0.88, 1, 1, 1 )">
Light cyan color.
</constant>
- <constant name="lightgoldenrod" value="Color( 0.98, 0.98, 0.82, 1 )">
+ <constant name="LIGHT_GOLDENROD" value="Color( 0.98, 0.98, 0.82, 1 )">
Light goldenrod color.
</constant>
- <constant name="lightgray" value="Color( 0.83, 0.83, 0.83, 1 )">
+ <constant name="LIGHT_GRAY" value="Color( 0.83, 0.83, 0.83, 1 )">
Light gray color.
</constant>
- <constant name="lightgreen" value="Color( 0.56, 0.93, 0.56, 1 )">
+ <constant name="LIGHT_GREEN" value="Color( 0.56, 0.93, 0.56, 1 )">
Light green color.
</constant>
- <constant name="lightpink" value="Color( 1, 0.71, 0.76, 1 )">
+ <constant name="LIGHT_PINK" value="Color( 1, 0.71, 0.76, 1 )">
Light pink color.
</constant>
- <constant name="lightsalmon" value="Color( 1, 0.63, 0.48, 1 )">
+ <constant name="LIGHT_SALMON" value="Color( 1, 0.63, 0.48, 1 )">
Light salmon color.
</constant>
- <constant name="lightseagreen" value="Color( 0.13, 0.7, 0.67, 1 )">
+ <constant name="LIGHT_SEA_GREEN" value="Color( 0.13, 0.7, 0.67, 1 )">
Light sea green color.
</constant>
- <constant name="lightskyblue" value="Color( 0.53, 0.81, 0.98, 1 )">
+ <constant name="LIGHT_SKY_BLUE" value="Color( 0.53, 0.81, 0.98, 1 )">
Light sky blue color.
</constant>
- <constant name="lightslategray" value="Color( 0.47, 0.53, 0.6, 1 )">
+ <constant name="LIGHT_SLATE_GRAY" value="Color( 0.47, 0.53, 0.6, 1 )">
Light slate gray color.
</constant>
- <constant name="lightsteelblue" value="Color( 0.69, 0.77, 0.87, 1 )">
+ <constant name="LIGHT_STEEL_BLUE" value="Color( 0.69, 0.77, 0.87, 1 )">
Light steel blue color.
</constant>
- <constant name="lightyellow" value="Color( 1, 1, 0.88, 1 )">
+ <constant name="LIGHT_YELLOW" value="Color( 1, 1, 0.88, 1 )">
Light yellow color.
</constant>
- <constant name="lime" value="Color( 0, 1, 0, 1 )">
+ <constant name="LIME" value="Color( 0, 1, 0, 1 )">
Lime color.
</constant>
- <constant name="limegreen" value="Color( 0.2, 0.8, 0.2, 1 )">
+ <constant name="LIME_GREEN" value="Color( 0.2, 0.8, 0.2, 1 )">
Lime green color.
</constant>
- <constant name="linen" value="Color( 0.98, 0.94, 0.9, 1 )">
+ <constant name="LINEN" value="Color( 0.98, 0.94, 0.9, 1 )">
Linen color.
</constant>
- <constant name="magenta" value="Color( 1, 0, 1, 1 )">
+ <constant name="MAGENTA" value="Color( 1, 0, 1, 1 )">
Magenta color.
</constant>
- <constant name="maroon" value="Color( 0.69, 0.19, 0.38, 1 )">
+ <constant name="MAROON" value="Color( 0.69, 0.19, 0.38, 1 )">
Maroon color.
</constant>
- <constant name="mediumaquamarine" value="Color( 0.4, 0.8, 0.67, 1 )">
+ <constant name="MEDIUM_AQUAMARINE" value="Color( 0.4, 0.8, 0.67, 1 )">
Medium aquamarine color.
</constant>
- <constant name="mediumblue" value="Color( 0, 0, 0.8, 1 )">
+ <constant name="MEDIUM_BLUE" value="Color( 0, 0, 0.8, 1 )">
Medium blue color.
</constant>
- <constant name="mediumorchid" value="Color( 0.73, 0.33, 0.83, 1 )">
+ <constant name="MEDIUM_ORCHID" value="Color( 0.73, 0.33, 0.83, 1 )">
Medium orchid color.
</constant>
- <constant name="mediumpurple" value="Color( 0.58, 0.44, 0.86, 1 )">
+ <constant name="MEDIUM_PURPLE" value="Color( 0.58, 0.44, 0.86, 1 )">
Medium purple color.
</constant>
- <constant name="mediumseagreen" value="Color( 0.24, 0.7, 0.44, 1 )">
+ <constant name="MEDIUM_SEA_GREEN" value="Color( 0.24, 0.7, 0.44, 1 )">
Medium sea green color.
</constant>
- <constant name="mediumslateblue" value="Color( 0.48, 0.41, 0.93, 1 )">
+ <constant name="MEDIUM_SLATE_BLUE" value="Color( 0.48, 0.41, 0.93, 1 )">
Medium slate blue color.
</constant>
- <constant name="mediumspringgreen" value="Color( 0, 0.98, 0.6, 1 )">
+ <constant name="MEDIUM_SPRING_GREEN" value="Color( 0, 0.98, 0.6, 1 )">
Medium spring green color.
</constant>
- <constant name="mediumturquoise" value="Color( 0.28, 0.82, 0.8, 1 )">
+ <constant name="MEDIUM_TURQUOISE" value="Color( 0.28, 0.82, 0.8, 1 )">
Medium turquoise color.
</constant>
- <constant name="mediumvioletred" value="Color( 0.78, 0.08, 0.52, 1 )">
+ <constant name="MEDIUM_VIOLET_RED" value="Color( 0.78, 0.08, 0.52, 1 )">
Medium violet red color.
</constant>
- <constant name="midnightblue" value="Color( 0.1, 0.1, 0.44, 1 )">
+ <constant name="MIDNIGHT_BLUE" value="Color( 0.1, 0.1, 0.44, 1 )">
Midnight blue color.
</constant>
- <constant name="mintcream" value="Color( 0.96, 1, 0.98, 1 )">
+ <constant name="MINT_CREAM" value="Color( 0.96, 1, 0.98, 1 )">
Mint cream color.
</constant>
- <constant name="mistyrose" value="Color( 1, 0.89, 0.88, 1 )">
+ <constant name="MISTY_ROSE" value="Color( 1, 0.89, 0.88, 1 )">
Misty rose color.
</constant>
- <constant name="moccasin" value="Color( 1, 0.89, 0.71, 1 )">
+ <constant name="MOCCASIN" value="Color( 1, 0.89, 0.71, 1 )">
Moccasin color.
</constant>
- <constant name="navajowhite" value="Color( 1, 0.87, 0.68, 1 )">
+ <constant name="NAVAJO_WHITE" value="Color( 1, 0.87, 0.68, 1 )">
Navajo white color.
</constant>
- <constant name="navyblue" value="Color( 0, 0, 0.5, 1 )">
+ <constant name="NAVY_BLUE" value="Color( 0, 0, 0.5, 1 )">
Navy blue color.
</constant>
- <constant name="oldlace" value="Color( 0.99, 0.96, 0.9, 1 )">
+ <constant name="OLD_LACE" value="Color( 0.99, 0.96, 0.9, 1 )">
Old lace color.
</constant>
- <constant name="olive" value="Color( 0.5, 0.5, 0, 1 )">
+ <constant name="OLIVE" value="Color( 0.5, 0.5, 0, 1 )">
Olive color.
</constant>
- <constant name="olivedrab" value="Color( 0.42, 0.56, 0.14, 1 )">
+ <constant name="OLIVE_DRAB" value="Color( 0.42, 0.56, 0.14, 1 )">
Olive drab color.
</constant>
- <constant name="orange" value="Color( 1, 0.65, 0, 1 )">
+ <constant name="ORANGE" value="Color( 1, 0.65, 0, 1 )">
Orange color.
</constant>
- <constant name="orangered" value="Color( 1, 0.27, 0, 1 )">
+ <constant name="ORANGE_RED" value="Color( 1, 0.27, 0, 1 )">
Orange red color.
</constant>
- <constant name="orchid" value="Color( 0.85, 0.44, 0.84, 1 )">
+ <constant name="ORCHID" value="Color( 0.85, 0.44, 0.84, 1 )">
Orchid color.
</constant>
- <constant name="palegoldenrod" value="Color( 0.93, 0.91, 0.67, 1 )">
+ <constant name="PALE_GOLDENROD" value="Color( 0.93, 0.91, 0.67, 1 )">
Pale goldenrod color.
</constant>
- <constant name="palegreen" value="Color( 0.6, 0.98, 0.6, 1 )">
+ <constant name="PALE_GREEN" value="Color( 0.6, 0.98, 0.6, 1 )">
Pale green color.
</constant>
- <constant name="paleturquoise" value="Color( 0.69, 0.93, 0.93, 1 )">
+ <constant name="PALE_TURQUOISE" value="Color( 0.69, 0.93, 0.93, 1 )">
Pale turquoise color.
</constant>
- <constant name="palevioletred" value="Color( 0.86, 0.44, 0.58, 1 )">
+ <constant name="PALE_VIOLET_RED" value="Color( 0.86, 0.44, 0.58, 1 )">
Pale violet red color.
</constant>
- <constant name="papayawhip" value="Color( 1, 0.94, 0.84, 1 )">
+ <constant name="PAPAYA_WHIP" value="Color( 1, 0.94, 0.84, 1 )">
Papaya whip color.
</constant>
- <constant name="peachpuff" value="Color( 1, 0.85, 0.73, 1 )">
+ <constant name="PEACH_PUFF" value="Color( 1, 0.85, 0.73, 1 )">
Peach puff color.
</constant>
- <constant name="peru" value="Color( 0.8, 0.52, 0.25, 1 )">
+ <constant name="PERU" value="Color( 0.8, 0.52, 0.25, 1 )">
Peru color.
</constant>
- <constant name="pink" value="Color( 1, 0.75, 0.8, 1 )">
+ <constant name="PINK" value="Color( 1, 0.75, 0.8, 1 )">
Pink color.
</constant>
- <constant name="plum" value="Color( 0.87, 0.63, 0.87, 1 )">
+ <constant name="PLUM" value="Color( 0.87, 0.63, 0.87, 1 )">
Plum color.
</constant>
- <constant name="powderblue" value="Color( 0.69, 0.88, 0.9, 1 )">
+ <constant name="POWDER_BLUE" value="Color( 0.69, 0.88, 0.9, 1 )">
Powder blue color.
</constant>
- <constant name="purple" value="Color( 0.63, 0.13, 0.94, 1 )">
+ <constant name="PURPLE" value="Color( 0.63, 0.13, 0.94, 1 )">
Purple color.
</constant>
- <constant name="rebeccapurple" value="Color( 0.4, 0.2, 0.6, 1 )">
+ <constant name="REBECCA_PURPLE" value="Color( 0.4, 0.2, 0.6, 1 )">
Rebecca purple color.
</constant>
- <constant name="red" value="Color( 1, 0, 0, 1 )">
+ <constant name="RED" value="Color( 1, 0, 0, 1 )">
Red color.
</constant>
- <constant name="rosybrown" value="Color( 0.74, 0.56, 0.56, 1 )">
+ <constant name="ROSY_BROWN" value="Color( 0.74, 0.56, 0.56, 1 )">
Rosy brown color.
</constant>
- <constant name="royalblue" value="Color( 0.25, 0.41, 0.88, 1 )">
+ <constant name="ROYAL_BLUE" value="Color( 0.25, 0.41, 0.88, 1 )">
Royal blue color.
</constant>
- <constant name="saddlebrown" value="Color( 0.55, 0.27, 0.07, 1 )">
+ <constant name="SADDLE_BROWN" value="Color( 0.55, 0.27, 0.07, 1 )">
Saddle brown color.
</constant>
- <constant name="salmon" value="Color( 0.98, 0.5, 0.45, 1 )">
+ <constant name="SALMON" value="Color( 0.98, 0.5, 0.45, 1 )">
Salmon color.
</constant>
- <constant name="sandybrown" value="Color( 0.96, 0.64, 0.38, 1 )">
+ <constant name="SANDY_BROWN" value="Color( 0.96, 0.64, 0.38, 1 )">
Sandy brown color.
</constant>
- <constant name="seagreen" value="Color( 0.18, 0.55, 0.34, 1 )">
+ <constant name="SEA_GREEN" value="Color( 0.18, 0.55, 0.34, 1 )">
Sea green color.
</constant>
- <constant name="seashell" value="Color( 1, 0.96, 0.93, 1 )">
+ <constant name="SEASHELL" value="Color( 1, 0.96, 0.93, 1 )">
Seashell color.
</constant>
- <constant name="sienna" value="Color( 0.63, 0.32, 0.18, 1 )">
+ <constant name="SIENNA" value="Color( 0.63, 0.32, 0.18, 1 )">
Sienna color.
</constant>
- <constant name="silver" value="Color( 0.75, 0.75, 0.75, 1 )">
+ <constant name="SILVER" value="Color( 0.75, 0.75, 0.75, 1 )">
Silver color.
</constant>
- <constant name="skyblue" value="Color( 0.53, 0.81, 0.92, 1 )">
+ <constant name="SKY_BLUE" value="Color( 0.53, 0.81, 0.92, 1 )">
Sky blue color.
</constant>
- <constant name="slateblue" value="Color( 0.42, 0.35, 0.8, 1 )">
+ <constant name="SLATE_BLUE" value="Color( 0.42, 0.35, 0.8, 1 )">
Slate blue color.
</constant>
- <constant name="slategray" value="Color( 0.44, 0.5, 0.56, 1 )">
+ <constant name="SLATE_GRAY" value="Color( 0.44, 0.5, 0.56, 1 )">
Slate gray color.
</constant>
- <constant name="snow" value="Color( 1, 0.98, 0.98, 1 )">
+ <constant name="SNOW" value="Color( 1, 0.98, 0.98, 1 )">
Snow color.
</constant>
- <constant name="springgreen" value="Color( 0, 1, 0.5, 1 )">
+ <constant name="SPRING_GREEN" value="Color( 0, 1, 0.5, 1 )">
Spring green color.
</constant>
- <constant name="steelblue" value="Color( 0.27, 0.51, 0.71, 1 )">
+ <constant name="STEEL_BLUE" value="Color( 0.27, 0.51, 0.71, 1 )">
Steel blue color.
</constant>
- <constant name="tan" value="Color( 0.82, 0.71, 0.55, 1 )">
+ <constant name="TAN" value="Color( 0.82, 0.71, 0.55, 1 )">
Tan color.
</constant>
- <constant name="teal" value="Color( 0, 0.5, 0.5, 1 )">
+ <constant name="TEAL" value="Color( 0, 0.5, 0.5, 1 )">
Teal color.
</constant>
- <constant name="thistle" value="Color( 0.85, 0.75, 0.85, 1 )">
+ <constant name="THISTLE" value="Color( 0.85, 0.75, 0.85, 1 )">
Thistle color.
</constant>
- <constant name="tomato" value="Color( 1, 0.39, 0.28, 1 )">
+ <constant name="TOMATO" value="Color( 1, 0.39, 0.28, 1 )">
Tomato color.
</constant>
- <constant name="transparent" value="Color( 1, 1, 1, 0 )">
- Transparent color (white with no alpha).
+ <constant name="TRANSPARENT" value="Color( 1, 1, 1, 0 )">
+ Transparent color (white with zero alpha).
</constant>
- <constant name="turquoise" value="Color( 0.25, 0.88, 0.82, 1 )">
+ <constant name="TURQUOISE" value="Color( 0.25, 0.88, 0.82, 1 )">
Turquoise color.
</constant>
- <constant name="violet" value="Color( 0.93, 0.51, 0.93, 1 )">
+ <constant name="VIOLET" value="Color( 0.93, 0.51, 0.93, 1 )">
Violet color.
</constant>
- <constant name="webgray" value="Color( 0.5, 0.5, 0.5, 1 )">
+ <constant name="WEB_GRAY" value="Color( 0.5, 0.5, 0.5, 1 )">
Web gray color.
</constant>
- <constant name="webgreen" value="Color( 0, 0.5, 0, 1 )">
+ <constant name="WEB_GREEN" value="Color( 0, 0.5, 0, 1 )">
Web green color.
</constant>
- <constant name="webmaroon" value="Color( 0.5, 0, 0, 1 )">
+ <constant name="WEB_MAROON" value="Color( 0.5, 0, 0, 1 )">
Web maroon color.
</constant>
- <constant name="webpurple" value="Color( 0.5, 0, 0.5, 1 )">
+ <constant name="WEB_PURPLE" value="Color( 0.5, 0, 0.5, 1 )">
Web purple color.
</constant>
- <constant name="wheat" value="Color( 0.96, 0.87, 0.7, 1 )">
+ <constant name="WHEAT" value="Color( 0.96, 0.87, 0.7, 1 )">
Wheat color.
</constant>
- <constant name="white" value="Color( 1, 1, 1, 1 )">
+ <constant name="WHITE" value="Color( 1, 1, 1, 1 )">
White color.
</constant>
- <constant name="whitesmoke" value="Color( 0.96, 0.96, 0.96, 1 )">
+ <constant name="WHITE_SMOKE" value="Color( 0.96, 0.96, 0.96, 1 )">
White smoke color.
</constant>
- <constant name="yellow" value="Color( 1, 1, 0, 1 )">
+ <constant name="YELLOW" value="Color( 1, 1, 0, 1 )">
Yellow color.
</constant>
- <constant name="yellowgreen" value="Color( 0.6, 0.8, 0.2, 1 )">
+ <constant name="YELLOW_GREEN" value="Color( 0.6, 0.8, 0.2, 1 )">
Yellow green color.
</constant>
</constants>
diff --git a/doc/classes/ConcavePolygonShape3D.xml b/doc/classes/ConcavePolygonShape3D.xml
index a9687abedc..b510905d1f 100644
--- a/doc/classes/ConcavePolygonShape3D.xml
+++ b/doc/classes/ConcavePolygonShape3D.xml
@@ -5,7 +5,7 @@
</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.
+ Note: when used for collision, [ConcavePolygonShape3D] is intended to work with static [PhysicsBody3D] nodes like [StaticBody3D] and will not work with [CharacterBody3D] or [RigidBody3D] with a mode other than Static.
</description>
<tutorials>
<link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link>
diff --git a/doc/classes/ConfigFile.xml b/doc/classes/ConfigFile.xml
index 38948a2d6e..8b903d8dbc 100644
--- a/doc/classes/ConfigFile.xml
+++ b/doc/classes/ConfigFile.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConfigFile" inherits="Reference" version="4.0">
+<class name="ConfigFile" inherits="RefCounted" version="4.0">
<brief_description>
Helper class to handle INI-style files.
</brief_description>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index c0f918a01f..33969cf4c3 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -22,6 +22,34 @@
<link title="All GUI Demos">https://github.com/godotengine/godot-demo-projects/tree/master/gui</link>
</tutorials>
<methods>
+ <method name="_can_drop_data" qualifiers="virtual">
+ <return type="bool">
+ </return>
+ <argument index="0" name="position" type="Vector2">
+ </argument>
+ <argument index="1" name="data" type="Variant">
+ </argument>
+ <description>
+ 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.
+ This method should only be used to test the data. Process the data in [method _drop_data].
+ [codeblocks]
+ [gdscript]
+ func _can_drop_data(position, data):
+ # Check position if it is relevant to you
+ # Otherwise, just check data
+ return typeof(data) == TYPE_DICTIONARY and data.has("expected")
+ [/gdscript]
+ [csharp]
+ public override bool CanDropData(Vector2 position, object data)
+ {
+ // Check position if it is relevant to you
+ // Otherwise, just check data
+ return data is Godot.Collections.Dictionary &amp;&amp; (data as Godot.Collections.Dictionary).Contains("expected");
+ }
+ [/csharp]
+ [/codeblocks]
+ </description>
+ </method>
<method name="_clips_input" qualifiers="virtual">
<return type="bool">
</return>
@@ -30,6 +58,61 @@
If not overridden, defaults to [code]false[/code].
</description>
</method>
+ <method name="_drop_data" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector2">
+ </argument>
+ <argument index="1" name="data" type="Variant">
+ </argument>
+ <description>
+ 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.
+ [codeblocks]
+ [gdscript]
+ func _can_drop_data(position, data):
+ return typeof(data) == TYPE_DICTIONARY and data.has("color")
+ func _drop_data(position, data):
+ var color = data["color"]
+ [/gdscript]
+ [csharp]
+ public override bool CanDropData(Vector2 position, object data)
+ {
+ return data is Godot.Collections.Dictionary &amp;&amp; (data as Godot.Collections.Dictionary).Contains("color");
+ }
+ public override void DropData(Vector2 position, object data)
+ {
+ Color color = (Color)(data as Godot.Collections.Dictionary)["color"];
+ }
+ [/csharp]
+ [/codeblocks]
+ </description>
+ </method>
+ <method name="_get_drag_data" qualifiers="virtual">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="position" type="Vector2">
+ </argument>
+ <description>
+ 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].
+ 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.
+ [codeblocks]
+ [gdscript]
+ func _get_drag_data(position):
+ var mydata = make_data() # This is your custom method generating the drag data.
+ set_drag_preview(make_preview(mydata)) # This is your custom method generating the preview of the drag data.
+ return mydata
+ [/gdscript]
+ [csharp]
+ public override object GetDragData(Vector2 position)
+ {
+ object mydata = MakeData(); // This is your custom method generating the drag data.
+ SetDragPreview(MakePreview(mydata)); // This is your custom method generating the preview of the drag data.
+ return mydata;
+ }
+ [/csharp]
+ [/codeblocks]
+ </description>
+ </method>
<method name="_get_minimum_size" qualifiers="virtual">
<return type="Vector2">
</return>
@@ -68,13 +151,24 @@
[/csharp]
[/codeblocks]
The event won't trigger if:
- * clicking outside the control (see [method has_point]);
+ * clicking outside the control (see [method _has_point]);
* control has [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE];
* control is obstructed by another [Control] on top of it, which doesn't have [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE];
* control's parent has [member mouse_filter] set to [constant MOUSE_FILTER_STOP] or has accepted the event;
* it happens outside parent's rectangle and the parent has either [member rect_clip_content] or [method _clips_input] enabled.
</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="_make_custom_tooltip" qualifiers="virtual">
<return type="Control">
</return>
@@ -249,63 +343,6 @@
[/codeblocks]
</description>
</method>
- <method name="can_drop_data" qualifiers="virtual">
- <return type="bool">
- </return>
- <argument index="0" name="position" type="Vector2">
- </argument>
- <argument index="1" name="data" type="Variant">
- </argument>
- <description>
- 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.
- This method should only be used to test the data. Process the data in [method drop_data].
- [codeblocks]
- [gdscript]
- func can_drop_data(position, data):
- # Check position if it is relevant to you
- # Otherwise, just check data
- return typeof(data) == TYPE_DICTIONARY and data.has("expected")
- [/gdscript]
- [csharp]
- public override bool CanDropData(Vector2 position, object data)
- {
- // Check position if it is relevant to you
- // Otherwise, just check data
- return data is Godot.Collections.Dictionary &amp;&amp; (data as Godot.Collections.Dictionary).Contains("expected");
- }
- [/csharp]
- [/codeblocks]
- </description>
- </method>
- <method name="drop_data" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector2">
- </argument>
- <argument index="1" name="data" type="Variant">
- </argument>
- <description>
- 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.
- [codeblocks]
- [gdscript]
- func can_drop_data(position, data):
- return typeof(data) == TYPE_DICTIONARY and data.has("color")
- func drop_data(position, data):
- var color = data["color"]
- [/gdscript]
- [csharp]
- public override bool CanDropData(Vector2 position, object data)
- {
- return data is Godot.Collections.Dictionary &amp;&amp; (data as Godot.Collections.Dictionary).Contains("color");
- }
- public override void DropData(Vector2 position, object data)
- {
- Color color = (Color)(data as Godot.Collections.Dictionary)["color"];
- }
- [/csharp]
- [/codeblocks]
- </description>
- </method>
<method name="find_next_valid_focus" qualifiers="const">
<return type="Control">
</return>
@@ -328,8 +365,8 @@
<argument index="1" name="preview" type="Control">
</argument>
<description>
- 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.
- The methods [method can_drop_data] and [method drop_data] must be implemented on controls that want to receive drop data.
+ 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.
+ The methods [method _can_drop_data] and [method _drop_data] must be implemented on controls that want to receive drop data.
</description>
</method>
<method name="get_anchor" qualifiers="const">
@@ -364,32 +401,6 @@
Returns the mouse cursor shape the control displays on mouse hover. See [enum CursorShape].
</description>
</method>
- <method name="get_drag_data" qualifiers="virtual">
- <return type="Variant">
- </return>
- <argument index="0" name="position" type="Vector2">
- </argument>
- <description>
- 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].
- 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.
- [codeblocks]
- [gdscript]
- func get_drag_data(position):
- var mydata = make_data() # This is your custom method generating the drag data.
- set_drag_preview(make_preview(mydata)) # This is your custom method generating the preview of the drag data.
- return mydata
- [/gdscript]
- [csharp]
- public override object GetDragData(Vector2 position)
- {
- object mydata = MakeData(); // This is your custom method generating the drag data.
- SetDragPreview(MakePreview(mydata)); // This is your custom method generating the preview of the drag data.
- return mydata;
- }
- [/csharp]
- [/codeblocks]
- </description>
- </method>
<method name="get_end" qualifiers="const">
<return type="Vector2">
</return>
@@ -462,10 +473,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_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]node_type[/code].
+ Returns a color from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code].
[codeblocks]
[gdscript]
func _ready():
@@ -485,10 +496,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_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]node_type[/code].
+ Returns a constant from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code].
</description>
</method>
<method name="get_theme_font" qualifiers="const">
@@ -496,10 +507,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_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]node_type[/code].
+ Returns a font from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code].
</description>
</method>
<method name="get_theme_font_size" qualifiers="const">
@@ -507,10 +518,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns a font size from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code].
+ Returns a font size from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code].
</description>
</method>
<method name="get_theme_icon" qualifiers="const">
@@ -518,10 +529,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_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]node_type[/code].
+ Returns an icon from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code].
</description>
</method>
<method name="get_theme_stylebox" qualifiers="const">
@@ -529,10 +540,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns a [StyleBox] from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]node_type[/code].
+ Returns a [StyleBox] from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code].
</description>
</method>
<method name="get_tooltip" qualifiers="const">
@@ -577,26 +588,15 @@
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">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns [code]true[/code] if [Color] with given [code]name[/code] and associated with [Control] of given [code]node_type[/code] exists in assigned [Theme].
+ Returns [code]true[/code] if [Color] with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code] exists in assigned [Theme].
</description>
</method>
<method name="has_theme_color_override" qualifiers="const">
@@ -613,10 +613,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns [code]true[/code] if constant with given [code]name[/code] and associated with [Control] of given [code]node_type[/code] exists in assigned [Theme].
+ Returns [code]true[/code] if constant with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code] exists in assigned [Theme].
</description>
</method>
<method name="has_theme_constant_override" qualifiers="const">
@@ -633,10 +633,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns [code]true[/code] if font with given [code]name[/code] and associated with [Control] of given [code]node_type[/code] exists in assigned [Theme].
+ Returns [code]true[/code] if font with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code] exists in assigned [Theme].
</description>
</method>
<method name="has_theme_font_override" qualifiers="const">
@@ -653,10 +653,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns [code]true[/code] if font size with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme].
+ Returns [code]true[/code] if font size with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code] exists in assigned [Theme].
</description>
</method>
<method name="has_theme_font_size_override" qualifiers="const">
@@ -673,10 +673,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns [code]true[/code] if icon with given [code]name[/code] and associated with [Control] of given [code]node_type[/code] exists in assigned [Theme].
+ Returns [code]true[/code] if icon with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code] exists in assigned [Theme].
</description>
</method>
<method name="has_theme_icon_override" qualifiers="const">
@@ -693,10 +693,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns [code]true[/code] if [StyleBox] with given [code]name[/code] and associated with [Control] of given [code]node_type[/code] exists in assigned [Theme].
+ Returns [code]true[/code] if [StyleBox] with given [code]name[/code] and associated with [Control] of given [code]theme_type[/code] exists in assigned [Theme].
</description>
</method>
<method name="has_theme_stylebox_override" qualifiers="const">
@@ -856,7 +856,7 @@
</argument>
<description>
Forwards the handling of this control's drag and drop to [code]target[/code] control.
- 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:
+ 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:
1. The function name must be suffixed with [b]_fw[/b]
2. The function must take an extra argument that is the control doing the forwarding
[codeblocks]
@@ -871,13 +871,13 @@
# TargetControl.gd
extends Control
- func can_drop_data_fw(position, data, from_control):
+ func _can_drop_data_fw(position, data, from_control):
return true
- func drop_data_fw(position, data, from_control):
+ func _drop_data_fw(position, data, from_control):
my_handle_data(data) # Your handler method.
- func get_drag_data_fw(position, from_control):
+ func _get_drag_data_fw(position, from_control):
set_drag_preview(my_preview)
return my_data()
[/gdscript]
@@ -922,12 +922,12 @@
<argument index="0" name="control" type="Control">
</argument>
<description>
- Shows the given control at the mouse pointer. A good time to call this method is in [method get_drag_data]. The control must not be in the scene tree. You should not free the control, and you should not keep a reference to the control beyond the duration of the drag. It will be deleted automatically after the drag has ended.
+ Shows the given control at the mouse pointer. A good time to call this method is in [method _get_drag_data]. The control must not be in the scene tree. You should not free the control, and you should not keep a reference to the control beyond the duration of the drag. It will be deleted automatically after the drag has ended.
[codeblocks]
[gdscript]
export (Color, RGBA) var color = Color(1, 0, 0, 1)
- func get_drag_data(position):
+ func _get_drag_data(position):
# Use a control that is not in the tree
var cpb = ColorPickerButton.new()
cpb.color = color
@@ -1055,7 +1055,7 @@
Anchors the right edge of the node to the origin, the center or the end of its parent control. It changes how the right offset updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience.
</member>
<member name="anchor_top" type="float" setter="_set_anchor" getter="get_anchor" default="0.0">
- Anchors the top edge of the node to the origin, the center or the end of its parent control. It changes how the top offset updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience.
+ Anchors the top edge of the node to the origin, the center or the end of its parent control. It changes how the top offset updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience.
</member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode" default="0">
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.
@@ -1067,7 +1067,7 @@
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.
</member>
<member name="focus_neighbor_right" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath(&quot;&quot;)">
- 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.
+ 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.
</member>
<member name="focus_neighbor_top" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath(&quot;&quot;)">
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.
@@ -1173,7 +1173,12 @@
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.
</member>
<member name="theme" type="Theme" setter="set_theme" getter="get_theme">
- Changing this property replaces the current [Theme] resource this node and all its [Control] children use.
+ The [Theme] resource this node and all its [Control] children use. If a child node has its own [Theme] resource set, theme items are merged with child's definitions having higher priority.
+ </member>
+ <member name="theme_custom_type" type="StringName" setter="set_theme_custom_type" getter="get_theme_custom_type" default="&amp;&quot;&quot;">
+ The type name used by this [Control] to look up its own theme items. By default, the class name of the node is used (e.g. [code]Button[/code] for the [Button] control), as well as the class names of all parent classes (in order of inheritance). Setting this property gives the highest priority to the type of the specified name, then falls back on the class names.
+ [b]Note:[/b] To look up [Control]'s own items use various [code]get_theme_*[/code] methods without specifying [code]theme_type[/code].
+ [b]Note:[/b] Theme items are looked for in the tree order, from branch to root, where each [Control] node is checked for its [member theme] property. The earliest match against any type/class name is returned. The project-level Theme and the default Theme are checked last.
</member>
</members>
<signals>
diff --git a/doc/classes/Crypto.xml b/doc/classes/Crypto.xml
index 1f6cb40cde..deda6116f4 100644
--- a/doc/classes/Crypto.xml
+++ b/doc/classes/Crypto.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Crypto" inherits="Reference" version="4.0">
+<class name="Crypto" inherits="RefCounted" version="4.0">
<brief_description>
Access to advanced cryptographic functionalities.
</brief_description>
diff --git a/doc/classes/Curve.xml b/doc/classes/Curve.xml
index 26872e1f8e..e47c420a3b 100644
--- a/doc/classes/Curve.xml
+++ b/doc/classes/Curve.xml
@@ -108,7 +108,7 @@
Returns the Y value for the point that would exist at the X position [code]offset[/code] along the curve.
</description>
</method>
- <method name="interpolate_baked">
+ <method name="interpolate_baked" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="offset" type="float">
diff --git a/doc/classes/DTLSServer.xml b/doc/classes/DTLSServer.xml
index 91a04b1f28..28d68d309f 100644
--- a/doc/classes/DTLSServer.xml
+++ b/doc/classes/DTLSServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="DTLSServer" inherits="Reference" version="4.0">
+<class name="DTLSServer" inherits="RefCounted" version="4.0">
<brief_description>
Helper class to implement a DTLS server.
</brief_description>
diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml
index a9d7960501..dae8d83f0c 100644
--- a/doc/classes/Directory.xml
+++ b/doc/classes/Directory.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Directory" inherits="Reference" version="4.0">
+<class name="Directory" inherits="RefCounted" version="4.0">
<brief_description>
Type used to handle the filesystem.
</brief_description>
@@ -154,14 +154,14 @@
<method name="list_dir_begin">
<return type="int" enum="Error">
</return>
- <argument index="0" name="skip_navigational" type="bool" default="false">
+ <argument index="0" name="show_navigational" type="bool" default="false">
</argument>
- <argument index="1" name="skip_hidden" type="bool" default="false">
+ <argument index="1" name="show_hidden" type="bool" default="false">
</argument>
<description>
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].
- If [code]skip_navigational[/code] is [code]true[/code], [code].[/code] and [code]..[/code] are filtered out.
- If [code]skip_hidden[/code] is [code]true[/code], hidden files are filtered out.
+ If [code]show_navigational[/code] is [code]true[/code], [code].[/code] and [code]..[/code] are included too.
+ If [code]show_hidden[/code] is [code]true[/code], hidden files are included too.
</description>
</method>
<method name="list_dir_end">
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 91e90d051d..6c1cd37beb 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -469,46 +469,6 @@
<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="screen" 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>
@@ -1065,33 +1025,39 @@
</constant>
<constant name="FEATURE_CUSTOM_CURSOR_SHAPE" value="8" enum="Feature">
</constant>
- <constant name="FEATURE_NATIVE_VIDEO" value="9" enum="Feature">
+ <constant name="FEATURE_NATIVE_DIALOG" value="9" enum="Feature">
</constant>
- <constant name="FEATURE_NATIVE_DIALOG" value="10" enum="Feature">
+ <constant name="FEATURE_CONSOLE_WINDOW" value="10" enum="Feature">
</constant>
- <constant name="FEATURE_CONSOLE_WINDOW" value="11" enum="Feature">
+ <constant name="FEATURE_IME" value="11" enum="Feature">
</constant>
- <constant name="FEATURE_IME" value="12" enum="Feature">
+ <constant name="FEATURE_WINDOW_TRANSPARENCY" value="12" enum="Feature">
</constant>
- <constant name="FEATURE_WINDOW_TRANSPARENCY" value="13" enum="Feature">
+ <constant name="FEATURE_HIDPI" value="13" enum="Feature">
</constant>
- <constant name="FEATURE_HIDPI" value="14" enum="Feature">
+ <constant name="FEATURE_ICON" value="14" enum="Feature">
</constant>
- <constant name="FEATURE_ICON" value="15" enum="Feature">
+ <constant name="FEATURE_NATIVE_ICON" value="15" enum="Feature">
</constant>
- <constant name="FEATURE_NATIVE_ICON" value="16" enum="Feature">
+ <constant name="FEATURE_ORIENTATION" value="16" enum="Feature">
</constant>
- <constant name="FEATURE_ORIENTATION" value="17" enum="Feature">
- </constant>
- <constant name="FEATURE_SWAP_BUFFERS" value="18" enum="Feature">
+ <constant name="FEATURE_SWAP_BUFFERS" value="17" enum="Feature">
</constant>
<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 its position locked at the center of the screen.
+ [b]Note:[/b] If you want to process the mouse's movement in this mode, you need to use [member InputEventMouseMotion.relative].
</constant>
<constant name="MOUSE_MODE_CONFINED" value="3" enum="MouseMode">
+ Confines the mouse cursor to the game window, and make it visible.
+ </constant>
+ <constant name="MOUSE_MODE_CONFINED_HIDDEN" value="4" enum="MouseMode">
+ Confines the mouse cursor to the game window, and make it hidden.
</constant>
<constant name="SCREEN_OF_MAIN_WINDOW" value="-1">
</constant>
diff --git a/doc/classes/EditorDebuggerPlugin.xml b/doc/classes/EditorDebuggerPlugin.xml
index b97933e582..9484d33252 100644
--- a/doc/classes/EditorDebuggerPlugin.xml
+++ b/doc/classes/EditorDebuggerPlugin.xml
@@ -38,7 +38,7 @@
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if there is an instance of the game running with the attached debugger otherwise [code]false[/code].
+ Returns [code]true[/code] if there is an instance of the game running with the attached debugger otherwise [code]false[/code].
</description>
</method>
<method name="register_message_capture">
diff --git a/doc/classes/EditorExportPlugin.xml b/doc/classes/EditorExportPlugin.xml
index b29734de1c..d9e3003fbb 100644
--- a/doc/classes/EditorExportPlugin.xml
+++ b/doc/classes/EditorExportPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorExportPlugin" inherits="Reference" version="4.0">
+<class name="EditorExportPlugin" inherits="RefCounted" version="4.0">
<brief_description>
A script that is executed when exporting the project.
</brief_description>
diff --git a/doc/classes/EditorFeatureProfile.xml b/doc/classes/EditorFeatureProfile.xml
index e05a685dd7..0cd839f370 100644
--- a/doc/classes/EditorFeatureProfile.xml
+++ b/doc/classes/EditorFeatureProfile.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorFeatureProfile" inherits="Reference" version="4.0">
+<class name="EditorFeatureProfile" inherits="RefCounted" version="4.0">
<brief_description>
An editor feature profile which can be used to disable specific features.
</brief_description>
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index aa64ab4043..a532e9bc2b 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -5,45 +5,45 @@
</brief_description>
<description>
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].
- 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].godot/imported[/code] directory.
+ 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].godot/imported[/code] directory.
Below is an example EditorImportPlugin that imports a [Mesh] from a file with the extension ".special" or ".spec":
[codeblocks]
[gdscript]
tool
extends EditorImportPlugin
- func get_importer_name():
+ func _get_importer_name():
return "my.special.plugin"
- func get_visible_name():
+ func _get_visible_name():
return "Special Mesh"
- func get_recognized_extensions():
+ func _get_recognized_extensions():
return ["special", "spec"]
- func get_save_extension():
+ func _get_save_extension():
return "mesh"
- func get_resource_type():
+ func _get_resource_type():
return "Mesh"
- func get_preset_count():
+ func _get_preset_count():
return 1
- func get_preset_name(i):
+ func _get_preset_name(i):
return "Default"
- func get_import_options(i):
+ func _get_import_options(i):
return [{"name": "my_option", "default_value": false}]
- func import(source_file, save_path, options, platform_variants, gen_files):
+ func _import(source_file, save_path, options, platform_variants, gen_files):
var file = File.new()
if file.open(source_file, File.READ) != OK:
return FAILED
var mesh = ArrayMesh.new()
# Fill the Mesh with data read in "file", left as an exercise to the reader.
- var filename = save_path + "." + get_save_extension()
+ var filename = save_path + "." + _get_save_extension()
return ResourceSaver.save(filename, mesh)
[/gdscript]
[csharp]
@@ -92,7 +92,7 @@
return new Godot.Collections.Array{new Godot.Collections.Dictionary{{"name", "myOption"}, {"defaultValue", false}}};
}
- public override int Import(String sourceFile, String savePath, Godot.Collections.Dictionary options, Godot.Collections.Array platformVariants, Godot.Collections.Array genFiles)
+ public override int Import(String sourceFile, String savePath, Godot.Collections.Dictionary options, Godot.Collections.Array platformVariants, Godot.Collections.Array genFiles)
{
var file = new File();
if (file.Open(sourceFile, File.ModeFlags.Read) != Error.Ok)
@@ -113,7 +113,7 @@
<link title="Import plugins">https://docs.godotengine.org/en/latest/tutorials/plugins/editor/import_plugins.html</link>
</tutorials>
<methods>
- <method name="get_import_options" qualifiers="virtual">
+ <method name="_get_import_options" qualifiers="virtual">
<return type="Array">
</return>
<argument index="0" name="preset" type="int">
@@ -122,21 +122,21 @@
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).
</description>
</method>
- <method name="get_import_order" qualifiers="virtual">
+ <method name="_get_import_order" qualifiers="virtual">
<return type="int">
</return>
<description>
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.
</description>
</method>
- <method name="get_importer_name" qualifiers="virtual">
+ <method name="_get_importer_name" qualifiers="virtual">
<return type="String">
</return>
<description>
Gets the unique name of the importer.
</description>
</method>
- <method name="get_option_visibility" qualifiers="virtual">
+ <method name="_get_option_visibility" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="option" type="String">
@@ -147,7 +147,7 @@
This method can be overridden to hide specific import options if conditions are met. This is mainly useful for hiding options that depend on others if one of them is disabled. For example:
[codeblocks]
[gdscript]
- func get_option_visibility(option, options):
+ func _get_option_visibility(option, options):
# Only show the lossy quality setting if the compression mode is set to "Lossy".
if option == "compress/lossy_quality" and options.has("compress/mode"):
return int(options["compress/mode"]) == COMPRESS_LOSSY # This is a constant that you set
@@ -170,14 +170,14 @@
Return [code]true[/code] to make all options always visible.
</description>
</method>
- <method name="get_preset_count" qualifiers="virtual">
+ <method name="_get_preset_count" qualifiers="virtual">
<return type="int">
</return>
<description>
- 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.
+ 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.
</description>
</method>
- <method name="get_preset_name" qualifiers="virtual">
+ <method name="_get_preset_name" qualifiers="virtual">
<return type="String">
</return>
<argument index="0" name="preset" type="int">
@@ -186,42 +186,42 @@
Gets the name of the options preset at this index.
</description>
</method>
- <method name="get_priority" qualifiers="virtual">
+ <method name="_get_priority" qualifiers="virtual">
<return type="float">
</return>
<description>
Gets the priority of this plugin for the recognized extension. Higher priority plugins will be preferred. The default priority is [code]1.0[/code].
</description>
</method>
- <method name="get_recognized_extensions" qualifiers="virtual">
+ <method name="_get_recognized_extensions" qualifiers="virtual">
<return type="Array">
</return>
<description>
Gets the list of file extensions to associate with this loader (case-insensitive). e.g. [code]["obj"][/code].
</description>
</method>
- <method name="get_resource_type" qualifiers="virtual">
+ <method name="_get_resource_type" qualifiers="virtual">
<return type="String">
</return>
<description>
Gets the Godot resource type associated with this loader. e.g. [code]"Mesh"[/code] or [code]"Animation"[/code].
</description>
</method>
- <method name="get_save_extension" qualifiers="virtual">
+ <method name="_get_save_extension" qualifiers="virtual">
<return type="String">
</return>
<description>
Gets the extension used to save this resource in the [code].godot/imported[/code] directory.
</description>
</method>
- <method name="get_visible_name" qualifiers="virtual">
+ <method name="_get_visible_name" qualifiers="virtual">
<return type="String">
</return>
<description>
Gets the name to display in the import window. You should choose this name as a continuation to "Import as", e.g. "Import as Special Mesh".
</description>
</method>
- <method name="import" qualifiers="virtual">
+ <method name="_import" qualifiers="virtual">
<return type="int">
</return>
<argument index="0" name="source_file" type="String">
diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml
index 8204dc931e..c992d0fbb4 100644
--- a/doc/classes/EditorInspectorPlugin.xml
+++ b/doc/classes/EditorInspectorPlugin.xml
@@ -1,106 +1,100 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorInspectorPlugin" inherits="Reference" version="4.0">
+<class name="EditorInspectorPlugin" inherits="RefCounted" version="4.0">
<brief_description>
Plugin for adding custom property editors on inspector.
</brief_description>
<description>
These plugins allow adding custom property editors to [EditorInspector].
Plugins are registered via [method EditorPlugin.add_inspector_plugin].
- When an object is edited, the [method can_handle] function is called and must return [code]true[/code] if the object type is supported.
- If supported, the function [method parse_begin] will be called, allowing to place custom controls at the beginning of the class.
- Subsequently, the [method parse_category] and [method parse_property] are called for every category and property. They offer the ability to add custom controls to the inspector too.
- Finally, [method parse_end] will be called.
+ When an object is edited, the [method _can_handle] function is called and must return [code]true[/code] if the object type is supported.
+ If supported, the function [method _parse_begin] will be called, allowing to place custom controls at the beginning of the class.
+ Subsequently, the [method _parse_category] and [method _parse_property] are called for every category and property. They offer the ability to add custom controls to the inspector too.
+ Finally, [method _parse_end] will be called.
On each of these calls, the "add" functions can be called.
</description>
<tutorials>
</tutorials>
<methods>
- <method name="add_custom_control">
- <return type="void">
+ <method name="_can_handle" qualifiers="virtual">
+ <return type="bool">
</return>
- <argument index="0" name="control" type="Control">
+ <argument index="0" name="object" type="Object">
</argument>
<description>
- Adds a custom control, not necessarily a property editor.
+ Returns [code]true[/code] if this object can be handled by this plugin.
</description>
</method>
- <method name="add_property_editor">
+ <method name="_parse_begin" qualifiers="virtual">
<return type="void">
</return>
- <argument index="0" name="property" type="String">
- </argument>
- <argument index="1" name="editor" type="Control">
- </argument>
<description>
- Adds a property editor, this must inherit [EditorProperty].
+ Called to allow adding controls at the beginning of the list.
</description>
</method>
- <method name="add_property_editor_for_multiple_properties">
+ <method name="_parse_category" qualifiers="virtual">
<return type="void">
</return>
- <argument index="0" name="label" type="String">
- </argument>
- <argument index="1" name="properties" type="PackedStringArray">
- </argument>
- <argument index="2" name="editor" type="Control">
+ <argument index="0" name="category" type="String">
</argument>
<description>
- Adds an editor that allows modifying multiple properties, this must inherit [EditorProperty].
+ Called to allow adding controls at the beginning of the category.
</description>
</method>
- <method name="can_handle" qualifiers="virtual">
- <return type="bool">
+ <method name="_parse_end" qualifiers="virtual">
+ <return type="void">
</return>
- <argument index="0" name="object" type="Object">
- </argument>
<description>
- Returns [code]true[/code] if this object can be handled by this plugin.
+ Called to allow adding controls at the end of the list.
</description>
</method>
- <method name="parse_begin" qualifiers="virtual">
- <return type="void">
+ <method name="_parse_property" qualifiers="virtual">
+ <return type="bool">
</return>
- <argument index="0" name="object" type="Object">
+ <argument index="0" name="type" type="int">
+ </argument>
+ <argument index="1" name="path" type="String">
+ </argument>
+ <argument index="2" name="hint" type="int">
+ </argument>
+ <argument index="3" name="hint_text" type="String">
+ </argument>
+ <argument index="4" name="usage" type="int">
</argument>
<description>
- Called to allow adding controls at the beginning of the list.
+ 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.
</description>
</method>
- <method name="parse_category" qualifiers="virtual">
+ <method name="add_custom_control">
<return type="void">
</return>
- <argument index="0" name="object" type="Object">
- </argument>
- <argument index="1" name="category" type="String">
+ <argument index="0" name="control" type="Control">
</argument>
<description>
- Called to allow adding controls at the beginning of the category.
+ Adds a custom control, not necessarily a property editor.
</description>
</method>
- <method name="parse_end" qualifiers="virtual">
+ <method name="add_property_editor">
<return type="void">
</return>
+ <argument index="0" name="property" type="String">
+ </argument>
+ <argument index="1" name="editor" type="Control">
+ </argument>
<description>
- Called to allow adding controls at the end of the list.
+ Adds a property editor, this must inherit [EditorProperty].
</description>
</method>
- <method name="parse_property" qualifiers="virtual">
- <return type="bool">
+ <method name="add_property_editor_for_multiple_properties">
+ <return type="void">
</return>
- <argument index="0" name="object" type="Object">
- </argument>
- <argument index="1" name="type" type="int">
- </argument>
- <argument index="2" name="path" type="String">
- </argument>
- <argument index="3" name="hint" type="int">
+ <argument index="0" name="label" type="String">
</argument>
- <argument index="4" name="hint_text" type="String">
+ <argument index="1" name="properties" type="PackedStringArray">
</argument>
- <argument index="5" name="usage" type="int">
+ <argument index="2" name="editor" type="Control">
</argument>
<description>
- 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.
+ Adds an editor that allows modifying multiple properties, this must inherit [EditorProperty].
</description>
</method>
</methods>
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index a5328ce382..3f324bf1a0 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -57,6 +57,12 @@
[b]Note:[/b] This returns the main editor control containing the whole editor, not the 2D or 3D viewports specifically.
</description>
</method>
+ <method name="get_editor_paths">
+ <return type="EditorPaths">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_editor_scale" qualifiers="const">
<return type="float">
</return>
diff --git a/doc/classes/EditorNode3DGizmo.xml b/doc/classes/EditorNode3DGizmo.xml
index 45541b9263..dcc6d6ef12 100644
--- a/doc/classes/EditorNode3DGizmo.xml
+++ b/doc/classes/EditorNode3DGizmo.xml
@@ -9,13 +9,76 @@
<tutorials>
</tutorials>
<methods>
+ <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="_is_handle_highlighted" qualifiers="virtual">
+ <return type="bool">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ Returns [code]true[/code] if the handle at index [code]index[/code] is highlighted by being hovered with the mouse.
+ </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="add_collision_segments">
<return type="void">
</return>
<argument index="0" name="segments" type="PackedVector3Array">
</argument>
<description>
- Adds the specified [code]segments[/code] to the gizmo's collision shape for picking. Call this function during [method redraw].
+ Adds the specified [code]segments[/code] to the gizmo's collision shape for picking. Call this function during [method _redraw].
</description>
</method>
<method name="add_collision_triangles">
@@ -24,7 +87,7 @@
<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].
+ 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">
@@ -40,7 +103,7 @@
</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].
+ 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">
@@ -55,7 +118,7 @@
<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].
+ 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">
@@ -70,7 +133,7 @@
<argument index="3" name="material" type="Material" default="null">
</argument>
<description>
- Adds a mesh to the gizmo with the specified [code]billboard[/code] state, [code]skeleton[/code] and [code]material[/code]. If [code]billboard[/code] is [code]true[/code], the mesh will rotate to always face the camera. Call this function during [method redraw].
+ Adds a mesh to the gizmo with the specified [code]billboard[/code] state, [code]skeleton[/code] and [code]material[/code]. If [code]billboard[/code] is [code]true[/code], the mesh will rotate to always face the camera. Call this function during [method _redraw].
</description>
</method>
<method name="add_unscaled_billboard">
@@ -83,7 +146,7 @@
<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].
+ Adds an unscaled billboard for visualization. Call this function during [method _redraw].
</description>
</method>
<method name="clear">
@@ -93,39 +156,6 @@
Removes everything in the gizmo including meshes, collisions and handles.
</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>
@@ -140,36 +170,6 @@
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>
- Returns [code]true[/code] if the handle at index [code]index[/code] is highlighted by being hovered with the mouse.
- </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>
diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml
index 34657a1c08..5551326533 100644
--- a/doc/classes/EditorNode3DGizmoPlugin.xml
+++ b/doc/classes/EditorNode3DGizmoPlugin.xml
@@ -10,25 +10,14 @@
<link title="Spatial gizmo plugins">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">
+ <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">
+ <method name="_commit_handle" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="gizmo" type="EditorNode3DGizmo">
@@ -43,69 +32,23 @@
Override this method to commit gizmo handles. Called for this plugin's active gizmos.
</description>
</method>
- <method name="create_gizmo" qualifiers="virtual">
+ <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>
- <argument index="2" name="texture" type="Texture2D" default="null">
- </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.
- You can optionally provide a texture to use instead of the default icon.
- </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.
+ 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="get_gizmo_name" qualifiers="virtual">
+ <method name="_get_gizmo_name" qualifiers="virtual">
<return type="String">
</return>
<description>
Override this method to provide the name that will appear in the gizmo visibility menu.
</description>
</method>
- <method name="get_handle_name" qualifiers="virtual">
+ <method name="_get_handle_name" qualifiers="virtual">
<return type="String">
</return>
<argument index="0" name="gizmo" type="EditorNode3DGizmo">
@@ -116,7 +59,7 @@
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">
+ <method name="_get_handle_value" qualifiers="virtual">
<return type="Variant">
</return>
<argument index="0" name="gizmo" type="EditorNode3DGizmo">
@@ -127,18 +70,7 @@
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" default="null">
- </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_priority" qualifiers="virtual">
+ <method name="_get_priority" qualifiers="virtual">
<return type="int">
</return>
<description>
@@ -146,7 +78,7 @@
All built-in editor gizmos return a priority of [code]-1[/code]. If not overridden, this method will return [code]0[/code], which means custom gizmos will automatically override built-in gizmos.
</description>
</method>
- <method name="has_gizmo" qualifiers="virtual">
+ <method name="_has_gizmo" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="spatial" type="Node3D">
@@ -155,7 +87,7 @@
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">
+ <method name="_is_handle_highlighted" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="gizmo" type="EditorNode3DGizmo">
@@ -166,14 +98,14 @@
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">
+ <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 selectable even when the gizmo is hidden.
</description>
</method>
- <method name="redraw" qualifiers="virtual">
+ <method name="_redraw" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="gizmo" type="EditorNode3DGizmo">
@@ -182,7 +114,7 @@
Callback to redraw the provided gizmo. Called for this plugin's active gizmos.
</description>
</method>
- <method name="set_handle" qualifiers="virtual">
+ <method name="_set_handle" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="gizmo" type="EditorNode3DGizmo">
@@ -197,6 +129,74 @@
Update the value of a handle after it has been updated. Called for this plugin's active gizmos.
</description>
</method>
+ <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="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>
+ <argument index="2" name="texture" type="Texture2D" default="null">
+ </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.
+ You can optionally provide a texture to use instead of the default icon.
+ </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_material">
+ <return type="StandardMaterial3D">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="gizmo" type="EditorNode3DGizmo" default="null">
+ </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>
</methods>
<constants>
</constants>
diff --git a/doc/classes/EditorPaths.xml b/doc/classes/EditorPaths.xml
new file mode 100644
index 0000000000..d0d785dbb8
--- /dev/null
+++ b/doc/classes/EditorPaths.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorPaths" inherits="Object" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_cache_dir" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_config_dir" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_data_dir" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_self_contained_file" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_self_contained" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 61f1761249..0c0439e9d3 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -10,154 +10,7 @@
<link title="Editor plugins tutorial index">https://docs.godotengine.org/en/latest/tutorials/plugins/editor/index.html</link>
</tutorials>
<methods>
- <method name="add_autoload_singleton">
- <return type="void">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="path" type="String">
- </argument>
- <description>
- Adds a script at [code]path[/code] to the Autoload list as [code]name[/code].
- </description>
- </method>
- <method name="add_control_to_bottom_panel">
- <return type="Button">
- </return>
- <argument index="0" name="control" type="Control">
- </argument>
- <argument index="1" name="title" type="String">
- </argument>
- <description>
- 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].
- </description>
- </method>
- <method name="add_control_to_container">
- <return type="void">
- </return>
- <argument index="0" name="container" type="int" enum="EditorPlugin.CustomControlContainer">
- </argument>
- <argument index="1" name="control" type="Control">
- </argument>
- <description>
- Adds a custom control to a container (see [enum CustomControlContainer]). There are many locations where custom controls can be added in the editor UI.
- Please remember that you have to manage the visibility of your custom controls yourself (and likely hide it after adding it).
- 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].
- </description>
- </method>
- <method name="add_control_to_dock">
- <return type="void">
- </return>
- <argument index="0" name="slot" type="int" enum="EditorPlugin.DockSlot">
- </argument>
- <argument index="1" name="control" type="Control">
- </argument>
- <description>
- Adds the control to a specific dock slot (see [enum DockSlot] for options).
- If the dock is repositioned and as long as the plugin is active, the editor will save the dock position on further sessions.
- 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].
- </description>
- </method>
- <method name="add_custom_type">
- <return type="void">
- </return>
- <argument index="0" name="type" type="String">
- </argument>
- <argument index="1" name="base" type="String">
- </argument>
- <argument index="2" name="script" type="Script">
- </argument>
- <argument index="3" name="icon" type="Texture2D">
- </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. "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>
- </method>
- <method name="add_debugger_plugin">
- <return type="void">
- </return>
- <argument index="0" name="script" type="Script">
- </argument>
- <description>
- Adds a [Script] as debugger plugin to the Debugger. The script must extend [EditorDebuggerPlugin].
- </description>
- </method>
- <method name="add_export_plugin">
- <return type="void">
- </return>
- <argument index="0" name="plugin" type="EditorExportPlugin">
- </argument>
- <description>
- Registers a new export plugin. Export plugins are used when the project is being exported. See [EditorExportPlugin] for more information.
- </description>
- </method>
- <method name="add_import_plugin">
- <return type="void">
- </return>
- <argument index="0" name="importer" type="EditorImportPlugin">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_inspector_plugin">
- <return type="void">
- </return>
- <argument index="0" name="plugin" type="EditorInspectorPlugin">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_scene_import_plugin">
- <return type="void">
- </return>
- <argument index="0" name="scene_importer" type="EditorSceneImporter">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_spatial_gizmo_plugin">
- <return type="void">
- </return>
- <argument index="0" name="plugin" type="EditorNode3DGizmoPlugin">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_tool_menu_item">
- <return type="void">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="callable" type="Callable">
- </argument>
- <description>
- Adds a custom menu item to [b]Project &gt; Tools[/b] named [code]name[/code]. When clicked, the provided [code]callable[/code] will be called.
- </description>
- </method>
- <method name="add_tool_submenu_item">
- <return type="void">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="submenu" type="Object">
- </argument>
- <description>
- Adds a custom submenu under [b]Project &gt; Tools &gt;[/b] [code]name[/code]. [code]submenu[/code] should be an object of class [PopupMenu]. Use [code]remove_tool_menu_item(name)[/code] on plugin clean up to remove the menu.
- </description>
- </method>
- <method name="add_translation_parser_plugin">
- <return type="void">
- </return>
- <argument index="0" name="parser" type="EditorTranslationParserPlugin">
- </argument>
- <description>
- Registers a custom translation parser plugin for extracting translatable strings from custom files.
- </description>
- </method>
- <method name="apply_changes" qualifiers="virtual">
+ <method name="_apply_changes" qualifiers="virtual">
<return type="void">
</return>
<description>
@@ -165,29 +18,29 @@
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.
</description>
</method>
- <method name="build" qualifiers="virtual">
+ <method name="_build" qualifiers="virtual">
<return type="bool">
</return>
<description>
This method is called when the editor is about to run the project. The plugin can then perform required operations before the project runs.
- This method must return a boolean. If this method returns [code]false[/code], the project will not run. The run is aborted immediately, so this also prevents all other plugins' [method build] methods from running.
+ This method must return a boolean. If this method returns [code]false[/code], the project will not run. The run is aborted immediately, so this also prevents all other plugins' [method _build] methods from running.
</description>
</method>
- <method name="clear" qualifiers="virtual">
+ <method name="_clear" qualifiers="virtual">
<return type="void">
</return>
<description>
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.
</description>
</method>
- <method name="disable_plugin" qualifiers="virtual">
+ <method name="_disable_plugin" qualifiers="virtual">
<return type="void">
</return>
<description>
Called by the engine when the user disables the [EditorPlugin] in the Plugin tab of the project settings window.
</description>
</method>
- <method name="edit" qualifiers="virtual">
+ <method name="_edit" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="object" type="Object">
@@ -196,14 +49,14 @@
This function is used for plugins that edit specific object types (nodes or resources). It requests the editor to edit the given object.
</description>
</method>
- <method name="enable_plugin" qualifiers="virtual">
+ <method name="_enable_plugin" qualifiers="virtual">
<return type="void">
</return>
<description>
Called by the engine when the user enables the [EditorPlugin] in the Plugin tab of the project settings window.
</description>
</method>
- <method name="forward_canvas_draw_over_viewport" qualifiers="virtual">
+ <method name="_forward_canvas_draw_over_viewport" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="overlay" type="Control">
@@ -212,11 +65,11 @@
Called by the engine when the 2D editor's viewport is updated. Use the [code]overlay[/code] [Control] for drawing. You can update the viewport manually by calling [method update_overlays].
[codeblocks]
[gdscript]
- func forward_canvas_draw_over_viewport(overlay):
+ func _forward_canvas_draw_over_viewport(overlay):
# Draw a circle at cursor position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.white)
- func forward_canvas_gui_input(event):
+ func _forward_canvas_gui_input(event):
if event is InputEventMouseMotion:
# Redraw viewport when cursor is moved.
update_overlays()
@@ -243,27 +96,27 @@
[/codeblocks]
</description>
</method>
- <method name="forward_canvas_force_draw_over_viewport" qualifiers="virtual">
+ <method name="_forward_canvas_force_draw_over_viewport" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="overlay" type="Control">
</argument>
<description>
- This method is the same as [method forward_canvas_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else.
+ This method is the same as [method _forward_canvas_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else.
You need to enable calling of this method by using [method set_force_draw_over_forwarding_enabled].
</description>
</method>
- <method name="forward_canvas_gui_input" qualifiers="virtual">
+ <method name="_forward_canvas_gui_input" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="event" type="InputEvent">
</argument>
<description>
- 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:
+ 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:
[codeblocks]
[gdscript]
# Prevents the InputEvent to reach other Editor classes
- func forward_canvas_gui_input(event):
+ func _forward_canvas_gui_input(event):
return true
[/gdscript]
[csharp]
@@ -278,7 +131,7 @@
[codeblocks]
[gdscript]
# Consumes InputEventMouseMotion and forwards other InputEvent types.
- func forward_canvas_gui_input(event):
+ func _forward_canvas_gui_input(event):
return event is InputEventMouseMotion
[/gdscript]
[csharp]
@@ -291,7 +144,7 @@
[/codeblocks]
</description>
</method>
- <method name="forward_spatial_draw_over_viewport" qualifiers="virtual">
+ <method name="_forward_spatial_draw_over_viewport" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="overlay" type="Control">
@@ -300,11 +153,11 @@
Called by the engine when the 3D editor's viewport is updated. Use the [code]overlay[/code] [Control] for drawing. You can update the viewport manually by calling [method update_overlays].
[codeblocks]
[gdscript]
- func forward_spatial_draw_over_viewport(overlay):
+ func _forward_spatial_draw_over_viewport(overlay):
# Draw a circle at cursor position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64)
- func forward_spatial_gui_input(camera, event):
+ func _forward_spatial_gui_input(camera, event):
if event is InputEventMouseMotion:
# Redraw viewport when cursor is moved.
update_overlays()
@@ -331,17 +184,17 @@
[/codeblocks]
</description>
</method>
- <method name="forward_spatial_force_draw_over_viewport" qualifiers="virtual">
+ <method name="_forward_spatial_force_draw_over_viewport" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="overlay" type="Control">
</argument>
<description>
- This method is the same as [method forward_spatial_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else.
+ This method is the same as [method _forward_spatial_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else.
You need to enable calling of this method by using [method set_force_draw_over_forwarding_enabled].
</description>
</method>
- <method name="forward_spatial_gui_input" qualifiers="virtual">
+ <method name="_forward_spatial_gui_input" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="camera" type="Camera3D">
@@ -349,11 +202,11 @@
<argument index="1" name="event" type="InputEvent">
</argument>
<description>
- 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:
+ 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:
[codeblocks]
[gdscript]
# Prevents the InputEvent to reach other Editor classes.
- func forward_spatial_gui_input(camera, event):
+ func _forward_spatial_gui_input(camera, event):
return true
[/gdscript]
[csharp]
@@ -368,7 +221,7 @@
[codeblocks]
[gdscript]
# Consumes InputEventMouseMotion and forwards other InputEvent types.
- func forward_spatial_gui_input(camera, event):
+ func _forward_spatial_gui_input(camera, event):
return event is InputEventMouseMotion
[/gdscript]
[csharp]
@@ -381,21 +234,14 @@
[/codeblocks]
</description>
</method>
- <method name="get_breakpoints" qualifiers="virtual">
+ <method name="_get_breakpoints" qualifiers="virtual">
<return type="PackedStringArray">
</return>
<description>
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].
</description>
</method>
- <method name="get_editor_interface">
- <return type="EditorInterface">
- </return>
- <description>
- Returns the [EditorInterface] object that gives you control over Godot editor's window and its functionalities.
- </description>
- </method>
- <method name="get_plugin_icon" qualifiers="virtual">
+ <method name="_get_plugin_icon" qualifiers="virtual">
<return type="Texture2D">
</return>
<description>
@@ -404,7 +250,7 @@
Ideally, the plugin icon should be white with a transparent background and 16x16 pixels in size.
[codeblocks]
[gdscript]
- func get_plugin_icon():
+ func _get_plugin_icon():
# You can use a custom icon:
return preload("res://addons/my_plugin/my_plugin_icon.svg")
# Or use a built-in icon:
@@ -422,7 +268,7 @@
[/codeblocks]
</description>
</method>
- <method name="get_plugin_name" qualifiers="virtual">
+ <method name="_get_plugin_name" qualifiers="virtual">
<return type="String">
</return>
<description>
@@ -430,75 +276,285 @@
For main screen plugins, this appears at the top of the screen, to the right of the "2D", "3D", "Script", and "AssetLib" buttons.
</description>
</method>
- <method name="get_script_create_dialog">
- <return type="ScriptCreateDialog">
+ <method name="_get_state" qualifiers="virtual">
+ <return type="Dictionary">
</return>
<description>
- Gets the Editor's dialogue used for making scripts.
- [b]Note:[/b] Users can configure it before use.
+ 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).
</description>
</method>
- <method name="get_state" qualifiers="virtual">
- <return type="Dictionary">
+ <method name="_get_window_layout" qualifiers="virtual">
+ <return type="void">
</return>
+ <argument index="0" name="layout" type="ConfigFile">
+ </argument>
<description>
- 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).
+ 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).
</description>
</method>
- <method name="get_undo_redo">
- <return type="UndoRedo">
+ <method name="_handles" qualifiers="virtual">
+ <return type="bool">
</return>
+ <argument index="0" name="object" type="Object">
+ </argument>
<description>
- 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.
+ 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.
+ </description>
+ </method>
+ <method name="_has_main_screen" qualifiers="virtual">
+ <return type="bool">
+ </return>
+ <description>
+ 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]).
+ </description>
+ </method>
+ <method name="_make_visible" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="visible" type="bool">
+ </argument>
+ <description>
+ This function will be called when the editor is requested to become visible. It is used for plugins that edit a specific object type.
+ Remember that you have to manage the visibility of all your editor controls manually.
+ </description>
+ </method>
+ <method name="_save_external_data" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <description>
+ 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.
+ </description>
+ </method>
+ <method name="_set_state" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="state" type="Dictionary">
+ </argument>
+ <description>
+ Restore the state saved by [method _get_state].
</description>
</method>
- <method name="get_window_layout" qualifiers="virtual">
+ <method name="_set_window_layout" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="layout" type="ConfigFile">
</argument>
<description>
- 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).
+ Restore the plugin GUI layout saved by [method _get_window_layout].
</description>
</method>
- <method name="handles" qualifiers="virtual">
- <return type="bool">
+ <method name="add_autoload_singleton">
+ <return type="void">
</return>
- <argument index="0" name="object" type="Object">
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="path" type="String">
</argument>
<description>
- Implement this function if your plugin edits a specific type of object (Resource or Node). If you return [code]true[/code], then you will get the functions [method edit] and [method make_visible] called when the editor requests them. If you have declared the methods [method forward_canvas_gui_input] and [method forward_spatial_gui_input] these will be called too.
+ Adds a script at [code]path[/code] to the Autoload list as [code]name[/code].
</description>
</method>
- <method name="has_main_screen" qualifiers="virtual">
- <return type="bool">
+ <method name="add_control_to_bottom_panel">
+ <return type="Button">
</return>
+ <argument index="0" name="control" type="Control">
+ </argument>
+ <argument index="1" name="title" type="String">
+ </argument>
<description>
- 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]).
+ 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].
</description>
</method>
- <method name="hide_bottom_panel">
+ <method name="add_control_to_container">
<return type="void">
</return>
+ <argument index="0" name="container" type="int" enum="EditorPlugin.CustomControlContainer">
+ </argument>
+ <argument index="1" name="control" type="Control">
+ </argument>
<description>
+ Adds a custom control to a container (see [enum CustomControlContainer]). There are many locations where custom controls can be added in the editor UI.
+ Please remember that you have to manage the visibility of your custom controls yourself (and likely hide it after adding it).
+ 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].
</description>
</method>
- <method name="make_bottom_panel_item_visible">
+ <method name="add_control_to_dock">
<return type="void">
</return>
- <argument index="0" name="item" type="Control">
+ <argument index="0" name="slot" type="int" enum="EditorPlugin.DockSlot">
+ </argument>
+ <argument index="1" name="control" type="Control">
</argument>
<description>
+ Adds the control to a specific dock slot (see [enum DockSlot] for options).
+ If the dock is repositioned and as long as the plugin is active, the editor will save the dock position on further sessions.
+ 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].
</description>
</method>
- <method name="make_visible" qualifiers="virtual">
+ <method name="add_custom_type">
<return type="void">
</return>
- <argument index="0" name="visible" type="bool">
+ <argument index="0" name="type" type="String">
+ </argument>
+ <argument index="1" name="base" type="String">
+ </argument>
+ <argument index="2" name="script" type="Script">
+ </argument>
+ <argument index="3" name="icon" type="Texture2D">
+ </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. "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>
+ </method>
+ <method name="add_debugger_plugin">
+ <return type="void">
+ </return>
+ <argument index="0" name="script" type="Script">
+ </argument>
+ <description>
+ Adds a [Script] as debugger plugin to the Debugger. The script must extend [EditorDebuggerPlugin].
+ </description>
+ </method>
+ <method name="add_export_plugin">
+ <return type="void">
+ </return>
+ <argument index="0" name="plugin" type="EditorExportPlugin">
+ </argument>
+ <description>
+ Registers a new [EditorExportPlugin]. Export plugins are used to perform tasks when the project is being exported.
+ See [method add_inspector_plugin] for an example of how to register a plugin.
+ </description>
+ </method>
+ <method name="add_import_plugin">
+ <return type="void">
+ </return>
+ <argument index="0" name="importer" type="EditorImportPlugin">
+ </argument>
+ <description>
+ Registers a new [EditorImportPlugin]. Import plugins are used to import custom and unsupported assets as a custom [Resource] type.
+ [b]Note:[/b] If you want to import custom 3D asset formats use [method add_scene_import_plugin] instead.
+ See [method add_inspector_plugin] for an example of how to register a plugin.
+ </description>
+ </method>
+ <method name="add_inspector_plugin">
+ <return type="void">
+ </return>
+ <argument index="0" name="plugin" type="EditorInspectorPlugin">
+ </argument>
+ <description>
+ Registers a new [EditorInspectorPlugin]. Inspector plugins are used to extend [EditorInspector] and provide custom configuration tools for your object's properties.
+ [b]Note:[/b] Always use [method remove_inspector_plugin] to remove the registered [EditorInspectorPlugin] when your [EditorPlugin] is disabled to prevent leaks and an unexpected behavior.
+ [codeblocks]
+ [gdscript]
+ const MyInspectorPlugin = preload("res://addons/your_addon/path/to/your/script.gd")
+ var inspector_plugin = MyInspectorPlugin.new()
+
+ func _enter_tree():
+ add_inspector_plugin(inspector_plugin)
+
+ func _exit_tree():
+ remove_inspector_plugin(inspector_plugin)
+ [/gdscript]
+ [/codeblocks]
+ </description>
+ </method>
+ <method name="add_scene_import_plugin">
+ <return type="void">
+ </return>
+ <argument index="0" name="scene_importer" type="EditorSceneImporter">
+ </argument>
+ <description>
+ Registers a new [EditorSceneImporter]. Scene importers are used to import custom 3D asset formats as scenes.
+ </description>
+ </method>
+ <method name="add_spatial_gizmo_plugin">
+ <return type="void">
+ </return>
+ <argument index="0" name="plugin" type="EditorNode3DGizmoPlugin">
+ </argument>
+ <description>
+ Registers a new [EditorNode3DGizmoPlugin]. Gizmo plugins are used to add custom gizmos to the 3D preview viewport for a [Node3D].
+ See [method add_inspector_plugin] for an example of how to register a plugin.
+ </description>
+ </method>
+ <method name="add_tool_menu_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="callable" type="Callable">
+ </argument>
+ <description>
+ Adds a custom menu item to [b]Project &gt; Tools[/b] named [code]name[/code]. When clicked, the provided [code]callable[/code] will be called.
+ </description>
+ </method>
+ <method name="add_tool_submenu_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="submenu" type="Object">
+ </argument>
+ <description>
+ Adds a custom submenu under [b]Project &gt; Tools &gt;[/b] [code]name[/code]. [code]submenu[/code] should be an object of class [PopupMenu]. Use [code]remove_tool_menu_item(name)[/code] on plugin clean up to remove the menu.
+ </description>
+ </method>
+ <method name="add_translation_parser_plugin">
+ <return type="void">
+ </return>
+ <argument index="0" name="parser" type="EditorTranslationParserPlugin">
+ </argument>
+ <description>
+ Registers a custom translation parser plugin for extracting translatable strings from custom files.
+ </description>
+ </method>
+ <method name="add_undo_redo_inspector_hook_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="callable" type="Callable">
+ </argument>
+ <description>
+ Hooks a callback into the undo/redo action creation when a property is modified in the inspector. This allows, for example, to save other properties that may be lost when a given property is modified.
+ The callback should have 4 arguments: [Object] [code]undo_redo[/code], [Object] [code]modified_object[/code], [String] [code]property[/code] and [Variant] [code]new_value[/code]. They are, respectively, the [UndoRedo] object used by the inspector, the currently modified object, the name of the modified property and the new value the property is about to take.
+ </description>
+ </method>
+ <method name="get_editor_interface">
+ <return type="EditorInterface">
+ </return>
+ <description>
+ Returns the [EditorInterface] object that gives you control over Godot editor's window and its functionalities.
+ </description>
+ </method>
+ <method name="get_script_create_dialog">
+ <return type="ScriptCreateDialog">
+ </return>
+ <description>
+ Gets the Editor's dialogue used for making scripts.
+ [b]Note:[/b] Users can configure it before use.
+ </description>
+ </method>
+ <method name="get_undo_redo">
+ <return type="UndoRedo">
+ </return>
+ <description>
+ 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.
+ </description>
+ </method>
+ <method name="hide_bottom_panel">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="make_bottom_panel_item_visible">
+ <return type="void">
+ </return>
+ <argument index="0" name="item" type="Control">
</argument>
<description>
- This function will be called when the editor is requested to become visible. It is used for plugins that edit a specific object type.
- Remember that you have to manage the visibility of all your editor controls manually.
</description>
</method>
<method name="queue_save_layout">
@@ -570,6 +626,7 @@
<argument index="0" name="plugin" type="EditorExportPlugin">
</argument>
<description>
+ Removes an export plugin registered by [method add_export_plugin].
</description>
</method>
<method name="remove_import_plugin">
@@ -578,6 +635,7 @@
<argument index="0" name="importer" type="EditorImportPlugin">
</argument>
<description>
+ Removes an import plugin registered by [method add_import_plugin].
</description>
</method>
<method name="remove_inspector_plugin">
@@ -586,6 +644,7 @@
<argument index="0" name="plugin" type="EditorInspectorPlugin">
</argument>
<description>
+ Removes an inspector plugin registered by [method add_import_plugin]
</description>
</method>
<method name="remove_scene_import_plugin">
@@ -594,6 +653,7 @@
<argument index="0" name="scene_importer" type="EditorSceneImporter">
</argument>
<description>
+ Removes a scene importer registered by [method add_scene_import_plugin].
</description>
</method>
<method name="remove_spatial_gizmo_plugin">
@@ -602,6 +662,7 @@
<argument index="0" name="plugin" type="EditorNode3DGizmoPlugin">
</argument>
<description>
+ Removes a gizmo plugin registered by [method add_spatial_gizmo_plugin].
</description>
</method>
<method name="remove_tool_menu_item">
@@ -619,53 +680,37 @@
<argument index="0" name="parser" type="EditorTranslationParserPlugin">
</argument>
<description>
- Removes a registered custom translation parser plugin.
+ Removes a custom translation parser plugin registered by [method add_translation_parser_plugin].
</description>
</method>
- <method name="save_external_data" qualifiers="virtual">
+ <method name="remove_undo_redo_inspector_hook_callback">
<return type="void">
</return>
+ <argument index="0" name="callable" type="Callable">
+ </argument>
<description>
- 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.
+ Removes a callback previsously added by [method add_undo_redo_inspector_hook_callback].
</description>
</method>
<method name="set_force_draw_over_forwarding_enabled">
<return type="void">
</return>
<description>
- Enables calling of [method forward_canvas_force_draw_over_viewport] for the 2D editor and [method forward_spatial_force_draw_over_viewport] for the 3D editor when their viewports are updated. You need to call this method only once and it will work permanently for this plugin.
+ Enables calling of [method _forward_canvas_force_draw_over_viewport] for the 2D editor and [method _forward_spatial_force_draw_over_viewport] for the 3D editor when their viewports are updated. You need to call this method only once and it will work permanently for this plugin.
</description>
</method>
<method name="set_input_event_forwarding_always_enabled">
<return type="void">
</return>
<description>
- 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.
- </description>
- </method>
- <method name="set_state" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="state" type="Dictionary">
- </argument>
- <description>
- Restore the state saved by [method get_state].
- </description>
- </method>
- <method name="set_window_layout" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="layout" type="ConfigFile">
- </argument>
- <description>
- Restore the plugin GUI layout saved by [method get_window_layout].
+ 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.
</description>
</method>
<method name="update_overlays" qualifiers="const">
<return type="int">
</return>
<description>
- Updates the overlays of the 2D and 3D editor viewport. Causes methods [method forward_canvas_draw_over_viewport], [method forward_canvas_force_draw_over_viewport], [method forward_spatial_draw_over_viewport] and [method forward_spatial_force_draw_over_viewport] to be called.
+ Updates the overlays of the 2D and 3D editor viewport. Causes methods [method _forward_canvas_draw_over_viewport], [method _forward_canvas_force_draw_over_viewport], [method _forward_spatial_draw_over_viewport] and [method _forward_spatial_force_draw_over_viewport] to be called.
</description>
</method>
</methods>
diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml
index f568263ff8..549d2c1628 100644
--- a/doc/classes/EditorProperty.xml
+++ b/doc/classes/EditorProperty.xml
@@ -9,6 +9,13 @@
<tutorials>
</tutorials>
<methods>
+ <method name="_update_property" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <description>
+ When this virtual function is called, you must update your editor.
+ </description>
+ </method>
<method name="add_focusable">
<return type="void">
</return>
@@ -25,7 +32,7 @@
</argument>
<argument index="1" name="value" type="Variant">
</argument>
- <argument index="2" name="field" type="StringName" default="@&quot;&quot;">
+ <argument index="2" name="field" type="StringName" default="&amp;&quot;&quot;">
</argument>
<argument index="3" name="changing" type="bool" default="false">
</argument>
@@ -44,7 +51,7 @@
<return type="StringName">
</return>
<description>
- Gets the edited property. If your editor is for a single property (added via [method EditorInspectorPlugin.parse_property]), then this will return the property.
+ Gets the edited property. If your editor is for a single property (added via [method EditorInspectorPlugin._parse_property]), then this will return the property.
</description>
</method>
<method name="get_tooltip_text" qualifiers="const">
@@ -63,13 +70,6 @@
Adds controls with this function if you want them on the bottom (below the label).
</description>
</method>
- <method name="update_property" qualifiers="virtual">
- <return type="void">
- </return>
- <description>
- When this virtual function is called, you must update your editor.
- </description>
- </method>
</methods>
<members>
<member name="checkable" type="bool" setter="set_checkable" getter="is_checkable" default="false">
@@ -101,7 +101,7 @@
<argument index="1" name="value" type="Array">
</argument>
<description>
- Emit it if you want multiple properties modified at the same time. Do not use if added via [method EditorInspectorPlugin.parse_property].
+ Emit it if you want multiple properties modified at the same time. Do not use if added via [method EditorInspectorPlugin._parse_property].
</description>
</signal>
<signal name="object_id_selected">
diff --git a/doc/classes/EditorResourceConversionPlugin.xml b/doc/classes/EditorResourceConversionPlugin.xml
index 1976eb802c..1d7e98c99d 100644
--- a/doc/classes/EditorResourceConversionPlugin.xml
+++ b/doc/classes/EditorResourceConversionPlugin.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorResourceConversionPlugin" inherits="Reference" version="4.0">
+<class name="EditorResourceConversionPlugin" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/EditorResourcePicker.xml b/doc/classes/EditorResourcePicker.xml
new file mode 100644
index 0000000000..0029955819
--- /dev/null
+++ b/doc/classes/EditorResourcePicker.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorResourcePicker" inherits="HBoxContainer" version="4.0">
+ <brief_description>
+ Godot editor's control for selecting [Resource] type properties.
+ </brief_description>
+ <description>
+ This [Control] node is used in the editor's Inspector dock to allow editing of [Resource] type properties. It provides options for creating, loading, saving and converting resources. Can be used with [EditorInspectorPlugin] to recreate the same behavior.
+ [b]Note:[/b] This [Control] does not include any editor for the resource, as editing is controlled by the Inspector dock itself or sub-Inspectors.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_handle_menu_selected" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ This virtual method can be implemented to handle context menu items not handled by default. See [method _set_create_options].
+ </description>
+ </method>
+ <method name="_set_create_options" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_node" type="Object">
+ </argument>
+ <description>
+ This virtual method is called when updating the context menu of [EditorResourcePicker]. Implement this method to override the "New ..." items with your own options. [code]menu_node[/code] is a reference to the [PopupMenu] node.
+ [b]Note:[/b] Implement [method _handle_menu_selected] to handle these custom items.
+ </description>
+ </method>
+ <method name="get_allowed_types" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <description>
+ Returns a list of all allowed types and subtypes corresponding to the [member base_type]. If the [member base_type] is empty, an empty list is returned.
+ </description>
+ </method>
+ <method name="set_toggle_pressed">
+ <return type="void">
+ </return>
+ <argument index="0" name="pressed" type="bool">
+ </argument>
+ <description>
+ Sets the toggle mode state for the main button. Works only if [member toggle_mode] is set to [code]true[/code].
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="base_type" type="String" setter="set_base_type" getter="get_base_type" default="&quot;&quot;">
+ The base type of allowed resource types. Can be a comma-separated list of several options.
+ </member>
+ <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true">
+ If [code]true[/code], the value can be selected and edited.
+ </member>
+ <member name="edited_resource" type="Resource" setter="set_edited_resource" getter="get_edited_resource">
+ The edited resource value.
+ </member>
+ <member name="toggle_mode" type="bool" setter="set_toggle_mode" getter="is_toggle_mode" default="false">
+ If [code]true[/code], the main button with the resource preview works in the toggle mode. Use [method set_toggle_pressed] to manually set the state.
+ </member>
+ </members>
+ <signals>
+ <signal name="resource_changed">
+ <argument index="0" name="resource" type="Resource">
+ </argument>
+ <description>
+ Emitted when the value of the edited resource was changed.
+ </description>
+ </signal>
+ <signal name="resource_selected">
+ <argument index="0" name="resource" type="Resource">
+ </argument>
+ <description>
+ Emitted when the resource value was set and user clicked to edit it.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/EditorResourcePreview.xml b/doc/classes/EditorResourcePreview.xml
index 0c1d969518..3239a75ada 100644
--- a/doc/classes/EditorResourcePreview.xml
+++ b/doc/classes/EditorResourcePreview.xml
@@ -40,7 +40,8 @@
<argument index="3" name="userdata" type="Variant">
</argument>
<description>
- 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.
+ Queue the [code]resource[/code] being edited for preview. Once the preview is ready, the [code]receiver[/code]'s [code]receiver_func[/code] will be called. The [code]receiver_func[/code] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Variant] userdata. [code]userdata[/code] can be anything, and will be returned when [code]receiver_func[/code] is called.
+ [b]Note[/b]: If it was not possible to create the preview the [code]receiver_func[/code] will still be called, but the preview will be null.
</description>
</method>
<method name="queue_resource_preview">
@@ -55,7 +56,8 @@
<argument index="3" name="userdata" type="Variant">
</argument>
<description>
- 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.
+ Queue a resource file located at [code]path[/code] for preview. Once the preview is ready, the [code]receiver[/code]'s [code]receiver_func[/code] will be called. The [code]receiver_func[/code] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Variant] userdata. [code]userdata[/code] can be anything, and will be returned when [code]receiver_func[/code] is called.
+ [b]Note[/b]: If it was not possible to create the preview the [code]receiver_func[/code] will still be called, but the preview will be null.
</description>
</method>
<method name="remove_preview_generator">
diff --git a/doc/classes/EditorResourcePreviewGenerator.xml b/doc/classes/EditorResourcePreviewGenerator.xml
index e935bf19fc..3594474e36 100644
--- a/doc/classes/EditorResourcePreviewGenerator.xml
+++ b/doc/classes/EditorResourcePreviewGenerator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorResourcePreviewGenerator" inherits="Reference" version="4.0">
+<class name="EditorResourcePreviewGenerator" inherits="RefCounted" version="4.0">
<brief_description>
Custom generator of previews.
</brief_description>
@@ -9,15 +9,15 @@
<tutorials>
</tutorials>
<methods>
- <method name="can_generate_small_preview" qualifiers="virtual">
+ <method name="_can_generate_small_preview" qualifiers="virtual">
<return type="bool">
</return>
<description>
- If this function returns [code]true[/code], the generator will call [method generate] or [method generate_from_path] for small previews as well.
+ If this function returns [code]true[/code], the generator will call [method _generate] or [method _generate_from_path] for small previews as well.
By default, it returns [code]false[/code].
</description>
</method>
- <method name="generate" qualifiers="virtual">
+ <method name="_generate" qualifiers="virtual">
<return type="Texture2D">
</return>
<argument index="0" name="from" type="Resource">
@@ -30,7 +30,7 @@
Care must be taken because this function is always called from a thread (not the main thread).
</description>
</method>
- <method name="generate_from_path" qualifiers="virtual">
+ <method name="_generate_from_path" qualifiers="virtual">
<return type="Texture2D">
</return>
<argument index="0" name="path" type="String">
@@ -38,20 +38,20 @@
<argument index="1" name="size" type="Vector2">
</argument>
<description>
- Generate a preview directly from a path with the specified size. Implementing this is optional, as default code will load and call [method generate].
+ Generate a preview directly from a path with the specified size. Implementing this is optional, as default code will load and call [method _generate].
Returning an empty texture is an OK way to fail and let another generator take care.
Care must be taken because this function is always called from a thread (not the main thread).
</description>
</method>
- <method name="generate_small_preview_automatically" qualifiers="virtual">
+ <method name="_generate_small_preview_automatically" qualifiers="virtual">
<return type="bool">
</return>
<description>
- 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].
+ 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].
By default, it returns [code]false[/code].
</description>
</method>
- <method name="handles" qualifiers="virtual">
+ <method name="_handles" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="type" type="String">
diff --git a/doc/classes/EditorSceneImporter.xml b/doc/classes/EditorSceneImporter.xml
index aa55a1653d..8df3091057 100644
--- a/doc/classes/EditorSceneImporter.xml
+++ b/doc/classes/EditorSceneImporter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneImporter" inherits="Reference" version="4.0">
+<class name="EditorSceneImporter" inherits="RefCounted" version="4.0">
<brief_description>
Imports scenes from third-parties' 3D files.
</brief_description>
diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml
index d1cdc4e43e..d2b5e84ff7 100644
--- a/doc/classes/EditorScenePostImport.xml
+++ b/doc/classes/EditorScenePostImport.xml
@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorScenePostImport" inherits="Reference" version="4.0">
+<class name="EditorScenePostImport" inherits="RefCounted" version="4.0">
<brief_description>
Post-processes scenes after import.
</brief_description>
<description>
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.
- The [method post_import] callback receives the imported scene's root node and returns the modified version of the scene. Usage example:
+ The [method _post_import] callback receives the imported scene's root node and returns the modified version of the scene. Usage example:
[codeblocks]
[gdscript]
tool # Needed so it runs in editor.
extends EditorScenePostImport
# This sample changes all node names.
# Called right after the scene is imported and gets the root node.
- func post_import(scene):
+ func _post_import(scene):
# Change all node names to "modified_[oldnodename]"
iterate(scene)
return scene # Remember to return the imported scene
@@ -55,14 +55,7 @@
<link title="Importing 3D scenes: Custom script">https://docs.godotengine.org/en/latest/getting_started/workflow/assets/importing_scenes.html#custom-script</link>
</tutorials>
<methods>
- <method name="get_source_file" qualifiers="const">
- <return type="String">
- </return>
- <description>
- Returns the source file path which got imported (e.g. [code]res://scene.dae[/code]).
- </description>
- </method>
- <method name="post_import" qualifiers="virtual">
+ <method name="_post_import" qualifiers="virtual">
<return type="Object">
</return>
<argument index="0" name="scene" type="Object">
@@ -71,6 +64,13 @@
Called after the scene was imported. This method must return the modified version of the scene.
</description>
</method>
+ <method name="get_source_file" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ Returns the source file path which got imported (e.g. [code]res://scene.dae[/code]).
+ </description>
+ </method>
</methods>
<constants>
</constants>
diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml
index 60ccf451b8..a91ea0eb14 100644
--- a/doc/classes/EditorScript.xml
+++ b/doc/classes/EditorScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorScript" inherits="Reference" version="4.0">
+<class name="EditorScript" inherits="RefCounted" version="4.0">
<brief_description>
Base script that can be used to add extension functions to the editor.
</brief_description>
diff --git a/doc/classes/EditorScriptPicker.xml b/doc/classes/EditorScriptPicker.xml
new file mode 100644
index 0000000000..8334676d92
--- /dev/null
+++ b/doc/classes/EditorScriptPicker.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorScriptPicker" inherits="EditorResourcePicker" version="4.0">
+ <brief_description>
+ Godot editor's control for selecting the [code]script[/code] property of a [Node].
+ </brief_description>
+ <description>
+ Similar to [EditorResourcePicker] this [Control] node is used in the editor's Inspector dock, but only to edit the [code]script[/code] property of a [Node]. Default options for creating new resources of all possible subtypes are replaced with dedicated buttons that open the "Attach Node Script" dialog. Can be used with [EditorInspectorPlugin] to recreate the same behavior.
+ [b]Note:[/b] You must set the [member script_owner] for the custom context menu items to work.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="script_owner" type="Node" setter="set_script_owner" getter="get_script_owner">
+ The owner [Node] of the script property that holds the edited resource.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 016d0128eb..e732223516 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -124,15 +124,6 @@
Returns the value of the setting specified by [code]name[/code]. This is equivalent to using [method Object.get] on the EditorSettings instance.
</description>
</method>
- <method name="get_settings_dir" qualifiers="const">
- <return type="String">
- </return>
- <description>
- Gets the global settings path for the engine. Inside this path, you can find some standard paths such as:
- [code]settings/tmp[/code] - Used for temporary storage of files
- [code]settings/templates[/code] - Where export templates are located
- </description>
- </method>
<method name="has_setting" qualifiers="const">
<return type="bool">
</return>
diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml
index 381f4fae04..935335943f 100644
--- a/doc/classes/EditorSpinSlider.xml
+++ b/doc/classes/EditorSpinSlider.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorSpinSlider" inherits="Range" version="4.0">
<brief_description>
+ Godot editor's control for editing numeric values.
</brief_description>
<description>
+ This [Control] node is used in the editor's Inspector dock to allow editing of numeric values. Can be used with [EditorInspectorPlugin] to recreate the same behavior.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/EditorSyntaxHighlighter.xml b/doc/classes/EditorSyntaxHighlighter.xml
index b80e81928f..d81b25345f 100644
--- a/doc/classes/EditorSyntaxHighlighter.xml
+++ b/doc/classes/EditorSyntaxHighlighter.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Base syntax highlighter resource all editor syntax highlighters extend from, it is used in the [ScriptEditor].
- Add a syntax highlighter to an individual script by calling [method ScriptEditorBase.add_syntax_highlighter]. To apply to all scripts on open, call [method ScriptEditor.register_syntax_highlighter]
+ Add a syntax highlighter to an individual script by calling [method ScriptEditorBase._add_syntax_highlighter]. To apply to all scripts on open, call [method ScriptEditor.register_syntax_highlighter]
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/EditorTranslationParserPlugin.xml b/doc/classes/EditorTranslationParserPlugin.xml
index c97459d9dc..a9f4e90e72 100644
--- a/doc/classes/EditorTranslationParserPlugin.xml
+++ b/doc/classes/EditorTranslationParserPlugin.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorTranslationParserPlugin" inherits="Reference" version="4.0">
+<class name="EditorTranslationParserPlugin" inherits="RefCounted" version="4.0">
<brief_description>
Plugin for adding custom parsers to extract strings that are to be translated from custom files (.csv, .json etc.).
</brief_description>
<description>
- Plugins are registered via [method EditorPlugin.add_translation_parser_plugin] method. To define the parsing and string extraction logic, override the [method parse_file] method in script.
+ Plugins are registered via [method EditorPlugin.add_translation_parser_plugin] method. To define the parsing and string extraction logic, override the [method _parse_file] method in script.
Add the extracted strings to argument [code]msgids[/code] or [code]msgids_context_plural[/code] if context or plural is used.
When adding to [code]msgids_context_plural[/code], you must add the data using the format [code]["A", "B", "C"][/code], where [code]A[/code] represents the extracted string, [code]B[/code] represents the context, and [code]C[/code] represents the plural version of the extracted string. If you want to add only context but not plural, put [code]""[/code] for the plural slot. The idea is the same if you only want to add plural but not context. See the code below for concrete examples.
The extracted strings will be written into a POT file selected by user under "POT Generation" in "Localization" tab in "Project Settings" menu.
@@ -14,7 +14,7 @@
tool
extends EditorTranslationParserPlugin
- func parse_file(path, msgids, msgids_context_plural):
+ func _parse_file(path, msgids, msgids_context_plural):
var file = File.new()
file.open(path, File.READ)
var text = file.get_as_text()
@@ -23,7 +23,7 @@
msgids.append(s)
#print("Extracted string: " + s)
- func get_recognized_extensions():
+ func _get_recognized_extensions():
return ["csv"]
[/gdscript]
[csharp]
@@ -76,12 +76,12 @@
For example:
[codeblocks]
[gdscript]
- func parse_file(path, msgids, msgids_context_plural):
+ func _parse_file(path, msgids, msgids_context_plural):
var res = ResourceLoader.load(path, "Script")
var text = res.source_code
# Parsing logic.
- func get_recognized_extensions():
+ func _get_recognized_extensions():
return ["gd"]
[/gdscript]
[csharp]
@@ -102,14 +102,14 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_recognized_extensions" qualifiers="virtual">
+ <method name="_get_recognized_extensions" qualifiers="virtual">
<return type="Array">
</return>
<description>
Gets the list of file extensions to associate with this parser, e.g. [code]["csv"][/code].
</description>
</method>
- <method name="parse_file" qualifiers="virtual">
+ <method name="_parse_file" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="path" type="String">
diff --git a/doc/classes/EncodedObjectAsID.xml b/doc/classes/EncodedObjectAsID.xml
index 1e4fde453b..e3e36590a3 100644
--- a/doc/classes/EncodedObjectAsID.xml
+++ b/doc/classes/EncodedObjectAsID.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EncodedObjectAsID" inherits="Reference" version="4.0">
+<class name="EncodedObjectAsID" inherits="RefCounted" version="4.0">
<brief_description>
Holds a reference to an [Object]'s instance ID.
</brief_description>
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index 1147b52102..ab480c50ab 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -171,6 +171,7 @@
</member>
<member name="physics_jitter_fix" type="float" setter="set_physics_jitter_fix" getter="get_physics_jitter_fix" default="0.5">
Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows smoothing out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended.
+ [b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics_jitter_fix] to [code]0[/code].
</member>
<member name="target_fps" type="int" setter="set_target_fps" getter="get_target_fps" default="0">
The desired frames per second. If the hardware cannot keep up, this setting may not be respected. A value of 0 means no limit.
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 6909fac2b7..878535a08d 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -206,7 +206,7 @@
The depth tolerance for screen-space reflections.
</member>
<member name="ss_reflections_enabled" type="bool" setter="set_ssr_enabled" getter="is_ssr_enabled" default="false">
- 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.
+ If [code]true[/code], screen-space reflections are enabled. Screen-space reflections are more accurate than reflections from [VoxelGI]s or [ReflectionProbe]s, but are slower and can't reflect surfaces occluded by others.
</member>
<member name="ss_reflections_fade_in" type="float" setter="set_ssr_fade_in" getter="get_ssr_fade_in" default="0.15">
The fade-in distance for screen-space reflections. Affects the area from the reflected material to the screen-space reflection).
diff --git a/doc/classes/Expression.xml b/doc/classes/Expression.xml
index d777c6fd9d..0781d2ffa2 100644
--- a/doc/classes/Expression.xml
+++ b/doc/classes/Expression.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Expression" inherits="Reference" version="4.0">
+<class name="Expression" inherits="RefCounted" version="4.0">
<brief_description>
A class that stores an expression you can execute.
</brief_description>
@@ -12,9 +12,9 @@
var expression = Expression.new()
func _ready():
- $LineEdit.connect("text_entered", self, "_on_text_entered")
+ $LineEdit.connect("text_submitted", self, "_on_text_submitted")
- func _on_text_entered(command):
+ func _on_text_submitted(command):
var error = expression.parse(command)
if error != OK:
print(expression.get_error_text())
@@ -28,7 +28,7 @@
public override void _Ready()
{
- GetNode("LineEdit").Connect("text_entered", this, nameof(OnTextEntered));
+ GetNode("LineEdit").Connect("text_submitted", this, nameof(OnTextEntered));
}
private void OnTextEntered(string command)
diff --git a/doc/classes/File.xml b/doc/classes/File.xml
index e0781e807f..7feaaa2040 100644
--- a/doc/classes/File.xml
+++ b/doc/classes/File.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="File" inherits="Reference" version="4.0">
+<class name="File" inherits="RefCounted" version="4.0">
<brief_description>
Type to handle file reading and writing operations.
</brief_description>
@@ -61,7 +61,7 @@
</return>
<description>
Returns [code]true[/code] if the file cursor has read past the end of the file.
- [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.
+ [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_length] and [method get_position] to implement a custom logic.
</description>
</method>
<method name="file_exists" qualifiers="const">
@@ -121,10 +121,10 @@
<method name="get_buffer" qualifiers="const">
<return type="PackedByteArray">
</return>
- <argument index="0" name="len" type="int">
+ <argument index="0" name="length" type="int">
</argument>
<description>
- Returns next [code]len[/code] bytes of the file as a [PackedByteArray].
+ Returns next [code]length[/code] bytes of the file as a [PackedByteArray].
</description>
</method>
<method name="get_csv_line" qualifiers="const">
@@ -158,7 +158,7 @@
Returns the next 32 bits from the file as a floating-point number.
</description>
</method>
- <method name="get_len" qualifiers="const">
+ <method name="get_length" qualifiers="const">
<return type="int">
</return>
<description>
@@ -188,7 +188,7 @@
<argument index="0" name="file" type="String">
</argument>
<description>
- 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].
+ 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 another format using the [Time] singleton.
</description>
</method>
<method name="get_pascal_string">
@@ -275,6 +275,7 @@
</argument>
<description>
Opens a compressed file for reading or writing.
+ [b]Note:[/b] [method open_compressed] can only read files that were saved by Godot, not third-party compression formats. See [url=https://github.com/godotengine/godot/issues/28999]GitHub issue #28999[/url] for a workaround.
</description>
</method>
<method name="open_encrypted">
@@ -489,10 +490,10 @@
</method>
</methods>
<members>
- <member name="endian_swap" type="bool" setter="set_endian_swap" getter="get_endian_swap" default="false">
+ <member name="big_endian" type="bool" setter="set_big_endian" getter="is_big_endian" default="false">
If [code]true[/code], the file is read with big-endian [url=https://en.wikipedia.org/wiki/Endianness]endianness[/url]. If [code]false[/code], the file is read with little-endian endianness. If in doubt, leave this to [code]false[/code] as most files are written with little-endian endianness.
- [b]Note:[/b] [member endian_swap] is only about the file format, not the CPU type. The CPU endianness doesn't affect the default endianness for files written.
- [b]Note:[/b] This is always reset to [code]false[/code] whenever you open the file. Therefore, you must set [member endian_swap] [i]after[/i] opening the file, not before.
+ [b]Note:[/b] [member big_endian] is only about the file format, not the CPU type. The CPU endianness doesn't affect the default endianness for files written.
+ [b]Note:[/b] This is always reset to [code]false[/code] whenever you open the file. Therefore, you must set [member big_endian] [i]after[/i] opening the file, not before.
</member>
</members>
<constants>
diff --git a/doc/classes/FileSystemDock.xml b/doc/classes/FileSystemDock.xml
index c553f90e37..15f92e90e3 100644
--- a/doc/classes/FileSystemDock.xml
+++ b/doc/classes/FileSystemDock.xml
@@ -7,40 +7,6 @@
<tutorials>
</tutorials>
<methods>
- <method name="can_drop_data_fw" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="position" type="Vector2">
- </argument>
- <argument index="1" name="data" type="Variant">
- </argument>
- <argument index="2" name="from" type="Control">
- </argument>
- <description>
- </description>
- </method>
- <method name="drop_data_fw">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector2">
- </argument>
- <argument index="1" name="data" type="Variant">
- </argument>
- <argument index="2" name="from" type="Control">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_drag_data_fw">
- <return type="Variant">
- </return>
- <argument index="0" name="position" type="Vector2">
- </argument>
- <argument index="1" name="from" type="Control">
- </argument>
- <description>
- </description>
- </method>
<method name="navigate_to_path">
<return type="void">
</return>
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index ebe4e3b00d..ebd6d2b92c 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -31,7 +31,9 @@
<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">
+ <member name="collision_base_size" type="float" setter="set_collision_base_size" getter="get_collision_base_size" default="1.0">
+ </member>
+ <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="GPUParticles2D.DrawOrder" default="1">
Particle draw order. Uses [enum DrawOrder] values.
</member>
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
@@ -40,7 +42,7 @@
<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">
+ <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="30">
The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
</member>
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
@@ -70,6 +72,14 @@
<member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
Particle texture. If [code]null[/code], particles will be squares.
</member>
+ <member name="trail_enabled" type="bool" setter="set_trail_enabled" getter="is_trail_enabled" default="false">
+ </member>
+ <member name="trail_length_secs" type="float" setter="set_trail_length" getter="get_trail_length" default="0.3">
+ </member>
+ <member name="trail_section_subdivisions" type="int" setter="set_trail_section_subdivisions" getter="get_trail_section_subdivisions" default="4">
+ </member>
+ <member name="trail_sections" type="int" setter="set_trail_sections" getter="get_trail_sections" default="8">
+ </member>
<member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect" default="Rect2( -100, -100, 200, 200 )">
The [Rect2] that determines the node's region which needs to be visible on screen for the particle system to be active.
Grow the rect if particles suddenly appear/disappear when the node enters/exits the screen. The [Rect2] can be grown via code or with the [b]Particles → Generate Visibility Rect[/b] editor tool.
@@ -82,5 +92,7 @@
<constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
Particles are drawn in order of remaining lifetime.
</constant>
+ <constant name="DRAW_ORDER_REVERSE_LIFETIME" value="2" enum="DrawOrder">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index aea106af50..47bdd9d745 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -22,7 +22,7 @@
<method name="emit_particle">
<return type="void">
</return>
- <argument index="0" name="xform" type="Transform">
+ <argument index="0" name="xform" type="Transform3D">
</argument>
<argument index="1" name="velocity" type="Vector3">
</argument>
@@ -87,18 +87,22 @@
<member name="draw_passes" type="int" setter="set_draw_passes" getter="get_draw_passes" default="1">
The number of draw passes when rendering particles.
</member>
+ <member name="draw_skin" type="Skin" setter="set_skin" getter="get_skin">
+ </member>
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
If [code]true[/code], particles are being emitted.
</member>
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
Time ratio between each emission. If [code]0[/code], particles are emitted continuously. If [code]1[/code], all particles are emitted simultaneously.
</member>
- <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
+ <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="30">
The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
</member>
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
</member>
+ <member name="interpolate" type="bool" setter="set_interpolate" getter="get_interpolate" default="true">
+ </member>
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
Amount of time each particle will exist.
</member>
@@ -122,6 +126,12 @@
</member>
<member name="sub_emitter" type="NodePath" setter="set_sub_emitter" getter="get_sub_emitter" default="NodePath(&quot;&quot;)">
</member>
+ <member name="trail_enabled" type="bool" setter="set_trail_enabled" getter="is_trail_enabled" default="false">
+ </member>
+ <member name="trail_length_secs" type="float" setter="set_trail_length" getter="get_trail_length" default="0.3">
+ </member>
+ <member name="transform_align" type="int" setter="set_transform_align" getter="get_transform_align" enum="GPUParticles3D.TransformAlign" default="0">
+ </member>
<member name="visibility_aabb" type="AABB" setter="set_visibility_aabb" getter="get_visibility_aabb" default="AABB( -4, -4, -4, 8, 8, 8 )">
The [AABB] that determines the node's region which needs to be visible on screen for the particle system to be active.
Grow the box if particles suddenly appear/disappear when the node enters/exits the screen. The [AABB] can be grown via code or with the [b]Particles → Generate AABB[/b] editor tool.
@@ -134,7 +144,9 @@
<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">
+ <constant name="DRAW_ORDER_REVERSE_LIFETIME" value="2" enum="DrawOrder">
+ </constant>
+ <constant name="DRAW_ORDER_VIEW_DEPTH" value="3" enum="DrawOrder">
Particles are drawn in order of depth.
</constant>
<constant name="EMIT_FLAG_POSITION" value="1" enum="EmitFlags">
@@ -150,5 +162,13 @@
<constant name="MAX_DRAW_PASSES" value="4">
Maximum number of draw passes supported.
</constant>
+ <constant name="TRANSFORM_ALIGN_DISABLED" value="0" enum="TransformAlign">
+ </constant>
+ <constant name="TRANSFORM_ALIGN_Z_BILLBOARD" value="1" enum="TransformAlign">
+ </constant>
+ <constant name="TRANSFORM_ALIGN_Y_TO_VELOCITY" value="2" enum="TransformAlign">
+ </constant>
+ <constant name="TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY" value="3" enum="TransformAlign">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
index 631a30abab..667ca2dacf 100644
--- a/doc/classes/GeometryInstance3D.xml
+++ b/doc/classes/GeometryInstance3D.xml
@@ -48,27 +48,25 @@
</member>
<member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" enum="GeometryInstance3D.GIMode" default="0">
</member>
+ <member name="ignore_occlusion_culling" type="bool" setter="set_ignore_occlusion_culling" getter="is_ignoring_occlusion_culling" default="false">
+ </member>
<member name="lod_bias" type="float" setter="set_lod_bias" getter="get_lod_bias" default="1.0">
</member>
- <member name="lod_max_distance" type="float" setter="set_lod_max_distance" getter="get_lod_max_distance" default="0.0">
- The GeometryInstance3D's max LOD distance.
- [b]Note:[/b] This property currently has no effect.
+ <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="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 name="visibility_range_begin" type="float" setter="set_visibility_range_begin" getter="get_visibility_range_begin" default="0.0">
+ Starting distance from which the GeometryInstance3D will be visible, taking [member visibility_range_begin_margin] into account as well. The default value of 0 is used to disable the range check.
</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 name="visibility_range_begin_margin" type="float" setter="set_visibility_range_begin_margin" getter="get_visibility_range_begin_margin" default="0.0">
+ Margin for the [member visibility_range_begin] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_begin] threshold by this amount.
</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 name="visibility_range_end" type="float" setter="set_visibility_range_end" getter="get_visibility_range_end" default="0.0">
+ Distance from which the GeometryInstance3D will be hidden, taking [member visibility_range_end_margin] into account as well. The default value of 0 is used to disable the range check..
</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 name="visibility_range_end_margin" type="float" setter="set_visibility_range_end_margin" getter="get_visibility_range_end_margin" default="0.0">
+ Margin for the [member visibility_range_end] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_end] threshold by this amount.
</member>
</members>
<constants>
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index b4536c0589..16fc1ca17a 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -197,6 +197,9 @@
<member name="scroll_offset" type="Vector2" setter="set_scroll_ofs" getter="get_scroll_ofs" default="Vector2( 0, 0 )">
The scroll offset.
</member>
+ <member name="show_zoom_label" type="bool" setter="set_show_zoom_label" getter="is_showing_zoom_label" default="false">
+ If [code]true[/code], makes a label with the current zoom level visible. The zoom value is displayed in percents.
+ </member>
<member name="snap_distance" type="int" setter="set_snap" getter="get_snap" default="20">
The snapping distance in pixels.
</member>
@@ -206,6 +209,15 @@
<member name="zoom" type="float" setter="set_zoom" getter="get_zoom" default="1.0">
The current zoom value.
</member>
+ <member name="zoom_max" type="float" setter="set_zoom_max" getter="get_zoom_max" default="2.0736">
+ The upper zoom limit.
+ </member>
+ <member name="zoom_min" type="float" setter="set_zoom_min" getter="get_zoom_min" default="0.232568">
+ The lower zoom limit.
+ </member>
+ <member name="zoom_step" type="float" setter="set_zoom_step" getter="get_zoom_step" default="1.2">
+ The step of each zoom level.
+ </member>
</members>
<signals>
<signal name="begin_node_move">
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index aae3126c0f..82ba45f11a 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -40,7 +40,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- Returns the color of the input connection [code]idx[/code].
+ Returns the [Color] of the input connection [code]idx[/code].
</description>
</method>
<method name="get_connection_input_count">
@@ -74,7 +74,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- Returns the color of the output connection [code]idx[/code].
+ Returns the [Color] of the output connection [code]idx[/code].
</description>
</method>
<method name="get_connection_output_count">
@@ -117,7 +117,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- Returns the color set to [code]idx[/code] left (input) slot.
+ Returns the left (input) [Color] of the slot [code]idx[/code].
</description>
</method>
<method name="get_slot_color_right" qualifiers="const">
@@ -126,7 +126,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- Returns the color set to [code]idx[/code] right (output) slot.
+ Returns the right (output) [Color] of the slot [code]idx[/code].
</description>
</method>
<method name="get_slot_type_left" qualifiers="const">
@@ -135,7 +135,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- Returns the (integer) type of left (input) [code]idx[/code] slot.
+ Returns the left (input) type of the slot [code]idx[/code].
</description>
</method>
<method name="get_slot_type_right" qualifiers="const">
@@ -144,7 +144,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- Returns the (integer) type of right (output) [code]idx[/code] slot.
+ Returns the right (output) type of the slot [code]idx[/code].
</description>
</method>
<method name="is_slot_enabled_left" qualifiers="const">
@@ -153,7 +153,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- Returns [code]true[/code] if left (input) slot [code]idx[/code] is enabled, [code]false[/code] otherwise.
+ Returns [code]true[/code] if left (input) side of the slot [code]idx[/code] is enabled.
</description>
</method>
<method name="is_slot_enabled_right" qualifiers="const">
@@ -162,7 +162,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
- Returns [code]true[/code] if right (output) slot [code]idx[/code] is enabled, [code]false[/code] otherwise.
+ Returns [code]true[/code] if right (output) side of the slot [code]idx[/code] is enabled.
</description>
</method>
<method name="set_opentype_feature">
@@ -204,6 +204,73 @@
[code]color_left[/code]/[code]right[/code] is the tint of the port's icon on this side.
[code]custom_left[/code]/[code]right[/code] is a custom texture for this side's port.
[b]Note:[/b] This method only sets properties of the slot. To create the slot, add a [Control]-derived child to the GraphNode.
+ Individual properties can be set using one of the [code]set_slot_*[/code] methods. You must enable at least one side of the slot to do so.
+ </description>
+ </method>
+ <method name="set_slot_color_left">
+ <return type="void">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="color_left" type="Color">
+ </argument>
+ <description>
+ Sets the [Color] of the left (input) side of the slot [code]idx[/code] to [code]color_left[/code].
+ </description>
+ </method>
+ <method name="set_slot_color_right">
+ <return type="void">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="color_right" type="Color">
+ </argument>
+ <description>
+ Sets the [Color] of the right (output) side of the slot [code]idx[/code] to [code]color_right[/code].
+ </description>
+ </method>
+ <method name="set_slot_enabled_left">
+ <return type="void">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="enable_left" type="bool">
+ </argument>
+ <description>
+ Toggles the left (input) side of the slot [code]idx[/code]. If [code]enable_left[/code] is [code]true[/code], a port will appear on the left side and the slot will be able to be connected from this side.
+ </description>
+ </method>
+ <method name="set_slot_enabled_right">
+ <return type="void">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="enable_right" type="bool">
+ </argument>
+ <description>
+ Toggles the right (output) side of the slot [code]idx[/code]. If [code]enable_right[/code] is [code]true[/code], a port will appear on the right side and the slot will be able to be connected from this side.
+ </description>
+ </method>
+ <method name="set_slot_type_left">
+ <return type="void">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="type_left" type="int">
+ </argument>
+ <description>
+ Sets the left (input) type of the slot [code]idx[/code] to [code]type_left[/code].
+ </description>
+ </method>
+ <method name="set_slot_type_right">
+ <return type="void">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="type_right" type="int">
+ </argument>
+ <description>
+ Sets the right (output) type of the slot [code]idx[/code] to [code]type_right[/code].
</description>
</method>
</methods>
diff --git a/doc/classes/HMACContext.xml b/doc/classes/HMACContext.xml
index 00d528ef8f..9fa96e5ddf 100644
--- a/doc/classes/HMACContext.xml
+++ b/doc/classes/HMACContext.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HMACContext" inherits="Reference" version="4.0">
+<class name="HMACContext" inherits="RefCounted" version="4.0">
<brief_description>
Used to create an HMAC for a message using a key.
</brief_description>
diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml
index ddfcdf7724..a549994a69 100644
--- a/doc/classes/HTTPClient.xml
+++ b/doc/classes/HTTPClient.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HTTPClient" inherits="Reference" version="4.0">
+<class name="HTTPClient" inherits="RefCounted" version="4.0">
<brief_description>
Low-level hyper-text transfer protocol client.
</brief_description>
diff --git a/doc/classes/HashingContext.xml b/doc/classes/HashingContext.xml
index e020293d76..1c7b7ca937 100644
--- a/doc/classes/HashingContext.xml
+++ b/doc/classes/HashingContext.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HashingContext" inherits="Reference" version="4.0">
+<class name="HashingContext" inherits="RefCounted" version="4.0">
<brief_description>
Context to compute cryptographic hashes over multiple iterations.
</brief_description>
diff --git a/doc/classes/IP.xml b/doc/classes/IP.xml
index 849f036bbd..b3ce1abaeb 100644
--- a/doc/classes/IP.xml
+++ b/doc/classes/IP.xml
@@ -4,7 +4,7 @@
Internet protocol (IP) support functions such as DNS resolution.
</brief_description>
<description>
- 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.
+ IP contains support functions for the Internet Protocol (IP). TCP/IP support is in different classes (see [StreamPeerTCP] and [TCPServer]). IP provides DNS hostname resolution support, both blocking and threaded.
</description>
<tutorials>
</tutorials>
@@ -59,6 +59,15 @@
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]).
</description>
</method>
+ <method name="get_resolve_item_addresses" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ Returns resolved addresses, or an empty array if an error happened or resolution didn't happen yet (see [method get_resolve_item_status]).
+ </description>
+ </method>
<method name="get_resolve_item_status" qualifiers="const">
<return type="int" enum="IP.ResolverStatus">
</return>
@@ -79,6 +88,17 @@
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].
</description>
</method>
+ <method name="resolve_hostname_addresses">
+ <return type="Array">
+ </return>
+ <argument index="0" name="host" type="String">
+ </argument>
+ <argument index="1" name="ip_type" type="int" enum="IP.Type" default="3">
+ </argument>
+ <description>
+ Resolves a given hostname in a blocking way. Addresses are returned as an [Array] of IPv4 or IPv6 addresses depending on [code]ip_type[/code].
+ </description>
+ </method>
<method name="resolve_hostname_queue_item">
<return type="int">
</return>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index d7408cd0ff..ebfd32c5fb 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -449,7 +449,10 @@
[b]Note:[/b] If you want to process the mouse's movement in this mode, you need to use [member InputEventMouseMotion.relative].
</constant>
<constant name="MOUSE_MODE_CONFINED" value="3" enum="MouseMode">
- Makes the mouse cursor visible but confines it to the game window.
+ Confines the mouse cursor to the game window, and make it visible.
+ </constant>
+ <constant name="MOUSE_MODE_CONFINED_HIDDEN" value="4" enum="MouseMode">
+ Confines the mouse cursor to the game window, and make it hidden.
</constant>
<constant name="CURSOR_ARROW" value="0" enum="CursorShape">
Arrow cursor. Standard, default pointing cursor.
diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml
index ed290fc7e2..42326f344f 100644
--- a/doc/classes/InputEventAction.xml
+++ b/doc/classes/InputEventAction.xml
@@ -14,7 +14,7 @@
<methods>
</methods>
<members>
- <member name="action" type="StringName" setter="set_action" getter="get_action" default="@&quot;&quot;">
+ <member name="action" type="StringName" setter="set_action" getter="get_action" default="&amp;&quot;&quot;">
The action's name. Actions are accessed via this [String].
</member>
<member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false">
diff --git a/doc/classes/InputEventMouseButton.xml b/doc/classes/InputEventMouseButton.xml
index d7e92f8bca..be71b42567 100644
--- a/doc/classes/InputEventMouseButton.xml
+++ b/doc/classes/InputEventMouseButton.xml
@@ -15,7 +15,7 @@
<member name="button_index" type="int" setter="set_button_index" getter="get_button_index" default="0">
The mouse button identifier, one of the [enum MouseButton] button or button wheel constants.
</member>
- <member name="doubleclick" type="bool" setter="set_doubleclick" getter="is_doubleclick" default="false">
+ <member name="double_click" type="bool" setter="set_double_click" getter="is_double_click" default="false">
If [code]true[/code], the mouse button's state is a double-click.
</member>
<member name="factor" type="float" setter="set_factor" getter="get_factor" default="1.0">
diff --git a/doc/classes/InputEventWithModifiers.xml b/doc/classes/InputEventWithModifiers.xml
index dd782209e5..3beea7f9a0 100644
--- a/doc/classes/InputEventWithModifiers.xml
+++ b/doc/classes/InputEventWithModifiers.xml
@@ -12,23 +12,23 @@
<methods>
</methods>
<members>
- <member name="alt" type="bool" setter="set_alt" getter="get_alt" default="false">
+ <member name="alt_pressed" type="bool" setter="set_alt_pressed" getter="is_alt_pressed" default="false">
State of the [kbd]Alt[/kbd] modifier.
</member>
- <member name="command" type="bool" setter="set_command" getter="get_command" default="false">
+ <member name="command_pressed" type="bool" setter="set_command_pressed" getter="is_command_pressed" default="false">
State of the [kbd]Cmd[/kbd] modifier.
</member>
- <member name="control" type="bool" setter="set_control" getter="get_control" default="false">
+ <member name="ctrl_pressed" type="bool" setter="set_ctrl_pressed" getter="is_ctrl_pressed" default="false">
State of the [kbd]Ctrl[/kbd] modifier.
</member>
- <member name="meta" type="bool" setter="set_metakey" getter="get_metakey" default="false">
+ <member name="meta_pressed" type="bool" setter="set_meta_pressed" getter="is_meta_pressed" default="false">
State of the [kbd]Meta[/kbd] modifier.
</member>
- <member name="shift" type="bool" setter="set_shift" getter="get_shift" default="false">
+ <member name="shift_pressed" type="bool" setter="set_shift_pressed" getter="is_shift_pressed" default="false">
State of the [kbd]Shift[/kbd] modifier.
</member>
<member name="store_command" type="bool" setter="set_store_command" getter="is_storing_command" default="true">
- If [code]true[/code], pressing [kbd]Cmd[/kbd] on macOS or [kbd]Ctrl[/kbd] on all other platforms will both be serialized as [member command]. If [code]false[/code], those same keys will be serialized as [member meta] on macOS and [member control] on all other platforms.
+ If [code]true[/code], pressing [kbd]Cmd[/kbd] on macOS or [kbd]Ctrl[/kbd] on all other platforms will both be serialized as [member command_pressed]. If [code]false[/code], those same keys will be serialized as [member meta_pressed] on macOS and [member ctrl_pressed] on all other platforms.
This aids with cross-platform compatibility when developing e.g. on Windows for macOS, or vice-versa.
</member>
</members>
diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml
index a9fb50c262..7baff7aa39 100644
--- a/doc/classes/JSON.xml
+++ b/doc/classes/JSON.xml
@@ -27,9 +27,12 @@
</argument>
<argument index="2" name="sort_keys" type="bool" default="false">
</argument>
+ <argument index="3" name="full_precision" type="bool" default="false">
+ </argument>
<description>
Converts a [Variant] var to JSON text and returns the result. Useful for serializing data to store or send over the network.
[b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a Variant to JSON text will convert all numerical values to [float] types.
+ [b]Note:[/b] If [code]full_precision[/code] is true, when printing floats, the unreliable digits are printed in addition to the reliable digits to guarantee exact decoding.
Use [code]indent[/code] parameter to pretty print the output.
[b]Example output:[/b]
[codeblock]
diff --git a/doc/classes/JSONParseResult.xml b/doc/classes/JSONParseResult.xml
index bc94f74b07..7311343b68 100644
--- a/doc/classes/JSONParseResult.xml
+++ b/doc/classes/JSONParseResult.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="JSONParseResult" inherits="Reference" version="4.0">
+<class name="JSONParseResult" inherits="RefCounted" version="4.0">
<brief_description>
Data class wrapper for decoded JSON.
</brief_description>
diff --git a/doc/classes/JSONParser.xml b/doc/classes/JSONParser.xml
index 31ba295418..991629f255 100644
--- a/doc/classes/JSONParser.xml
+++ b/doc/classes/JSONParser.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="JSONParser" inherits="Reference" version="4.0">
+<class name="JSONParser" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/JavaClass.xml b/doc/classes/JavaClass.xml
index 69b7a9b718..0b6a44fe14 100644
--- a/doc/classes/JavaClass.xml
+++ b/doc/classes/JavaClass.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="JavaClass" inherits="Reference" version="4.0">
+<class name="JavaClass" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/JavaScript.xml b/doc/classes/JavaScript.xml
index c707a72ee8..c87e637ff5 100644
--- a/doc/classes/JavaScript.xml
+++ b/doc/classes/JavaScript.xml
@@ -11,6 +11,40 @@
<link title="Exporting for the Web: Calling JavaScript from script">https://docs.godotengine.org/en/latest/getting_started/workflow/export/exporting_for_web.html#calling-javascript-from-script</link>
</tutorials>
<methods>
+ <method name="create_callback">
+ <return type="JavaScriptObject">
+ </return>
+ <argument index="0" name="callable" type="Callable">
+ </argument>
+ <description>
+ Creates a reference to a [Callable] that can be used as a callback by JavaScript. The reference must be kept until the callback happens, or it won't be called at all. See [JavaScriptObject] for usage.
+ </description>
+ </method>
+ <method name="create_object" qualifiers="vararg">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="object" type="String">
+ </argument>
+ <description>
+ Creates a new JavaScript object using the [code]new[/code] constructor. The [code]object[/code] must a valid property of the JavaScript [code]window[/code]. See [JavaScriptObject] for usage.
+ </description>
+ </method>
+ <method name="download_buffer">
+ <return type="void">
+ </return>
+ <argument index="0" name="buffer" type="PackedByteArray">
+ </argument>
+ <argument index="1" name="name" type="String">
+ </argument>
+ <argument index="2" name="mime" type="String" default="&quot;application/octet-stream&quot;">
+ </argument>
+ <description>
+ Prompts the user to download a file containing the specified [code]buffer[/code]. The file will have the given [code]name[/code] and [code]mime[/code] type.
+ [b]Note:[/b] The browser may override the [url=https://en.wikipedia.org/wiki/Media_type]MIME type[/url] provided based on the file [code]name[/code]'s extension.
+ [b]Note:[/b] Browsers might block the download if [method download_buffer] is not being called from a user interaction (e.g. button click).
+ [b]Note:[/b] Browsers might ask the user for permission or block the download if multiple download requests are made in a quick succession.
+ </description>
+ </method>
<method name="eval">
<return type="Variant">
</return>
@@ -23,6 +57,15 @@
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.
</description>
</method>
+ <method name="get_interface">
+ <return type="JavaScriptObject">
+ </return>
+ <argument index="0" name="interface" type="String">
+ </argument>
+ <description>
+ Returns an interface to a JavaScript object that can be used by scripts. The [code]interface[/code] must be a valid property of the JavaScript [code]window[/code]. The callback must accept a single [Array] argument, which will contain the JavaScript [code]arguments[/code]. See [JavaScriptObject] for usage.
+ </description>
+ </method>
</methods>
<constants>
</constants>
diff --git a/doc/classes/JavaScriptObject.xml b/doc/classes/JavaScriptObject.xml
new file mode 100644
index 0000000000..087fe163b4
--- /dev/null
+++ b/doc/classes/JavaScriptObject.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="JavaScriptObject" inherits="RefCounted" version="4.0">
+ <brief_description>
+ A wrapper class for native JavaScript objects.
+ </brief_description>
+ <description>
+ JavaScriptObject is used to interact with JavaScript objects retrieved or created via [method JavaScript.get_interface], [method JavaScript.create_object], or [method JavaScript.create_callback].
+ Example:
+ [codeblock]
+ extends Node
+
+ var _my_js_callback = JavaScript.create_callback(self, "myCallback") # This reference must be kept
+ var console = JavaScript.get_interface("console")
+
+ func _init():
+ var buf = JavaScript.create_object("ArrayBuffer", 10) # new ArrayBuffer(10)
+ print(buf) # prints [JavaScriptObject:OBJECT_ID]
+ var uint8arr = JavaScript.create_object("Uint8Array", buf) # new Uint8Array(buf)
+ uint8arr[1] = 255
+ prints(uint8arr[1], uint8arr.byteLength) # prints 255 10
+ console.log(uint8arr) # prints in browser console "Uint8Array(10) [ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0 ]"
+
+ # Equivalent of JavaScript: Array.from(uint8arr).forEach(myCallback)
+ JavaScript.get_interface("Array").from(uint8arr).forEach(_my_js_callback)
+
+ func myCallback(args):
+ # Will be called with the parameters passed to the "forEach" callback
+ # [0, 0, [JavaScriptObject:1173]]
+ # [255, 1, [JavaScriptObject:1173]]
+ # ...
+ # [0, 9, [JavaScriptObject:1180]]
+ print(args)
+ [/codeblock]
+ Note: Only available in the "HTML5" platform.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml
deleted file mode 100644
index fdd4db6115..0000000000
--- a/doc/classes/KinematicBody2D.xml
+++ /dev/null
@@ -1,176 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="KinematicBody2D" inherits="PhysicsBody2D" version="4.0">
- <brief_description>
- Kinematic body 2D 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] 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 don't require advanced physics.
- </description>
- <tutorials>
- <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
- <link title="Using KinematicBody2D">https://docs.godotengine.org/en/latest/tutorials/physics/using_kinematic_body_2d.html</link>
- <link title="2D Kinematic Character Demo">https://godotengine.org/asset-library/asset/113</link>
- <link title="2D Platformer Demo">https://godotengine.org/asset-library/asset/120</link>
- </tutorials>
- <methods>
- <method name="get_floor_normal" qualifiers="const">
- <return type="Vector2">
- </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="Vector2">
- </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="KinematicCollision2D">
- </return>
- <argument index="0" name="slide_idx" type="int">
- </argument>
- <description>
- Returns a [KinematicCollision2D], which contains information about a collision that occurred during the last call to [method move_and_slide] or [method move_and_slide_with_snap]. 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).
- [b]Example usage:[/b]
- [codeblocks]
- [gdscript]
- for i in get_slide_count():
- var collision = get_slide_collision(i)
- print("Collided with: ", collision.collider.name)
- [/gdscript]
- [csharp]
- for (int i = 0; i &lt; GetSlideCount(); i++)
- {
- KinematicCollision2D collision = GetSlideCollision(i);
- GD.Print("Collided with: ", (collision.Collider as Node).Name);
- }
- [/csharp]
- [/codeblocks]
- </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] or [method move_and_slide_with_snap].
- </description>
- </method>
- <method name="is_on_ceiling" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the body collided with the ceiling on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code].
- </description>
- </method>
- <method name="is_on_floor" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the body collided with the floor on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code].
- </description>
- </method>
- <method name="is_on_wall" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the body collided with a wall on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code].
- </description>
- </method>
- <method name="move_and_collide">
- <return type="KinematicCollision2D">
- </return>
- <argument index="0" name="rel_vec" type="Vector2">
- </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 [KinematicCollision2D], 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="Vector2">
- </return>
- <argument index="0" name="linear_velocity" type="Vector2">
- </argument>
- <argument index="1" name="up_direction" type="Vector2" default="Vector2( 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 [KinematicBody2D] or [RigidBody2D], it will also be affected by the motion of the other body. You can use this to make moving and 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 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.
- [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.
- 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.
- 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 [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].
- 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="Vector2">
- </return>
- <argument index="0" name="linear_velocity" type="Vector2">
- </argument>
- <argument index="1" name="snap" type="Vector2">
- </argument>
- <argument index="2" name="up_direction" type="Vector2" default="Vector2( 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)[/code] or by using [method move_and_slide] instead.
- </description>
- </method>
- <method name="test_move">
- <return type="bool">
- </return>
- <argument index="0" name="from" type="Transform2D">
- </argument>
- <argument index="1" name="rel_vec" type="Vector2">
- </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 [Transform2D], 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.08">
- Extra margin used for collision recovery in motion functions (see [method move_and_collide], [method move_and_slide], [method move_and_slide_with_snap]).
- If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
- A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
- A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of kinematic bodies.
- </member>
- <member name="motion/sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false">
- If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method move_and_slide] or [method move_and_collide] functions.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/KinematicBody3D.xml b/doc/classes/KinematicBody3D.xml
deleted file mode 100644
index efd3f58f88..0000000000
--- a/doc/classes/KinematicBody3D.xml
+++ /dev/null
@@ -1,188 +0,0 @@
-<?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 don't require advanced physics.
- </description>
- <tutorials>
- <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
- <link title="3D Kinematic Character Demo">https://godotengine.org/asset-library/asset/126</link>
- <link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link>
- <link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/676</link>
- <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</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 axis_lock_motion_x], [member axis_lock_motion_y] and [member axis_lock_motion_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 call to [method move_and_slide] or [method move_and_slide_with_snap]. 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] or [method move_and_slide_with_snap].
- </description>
- </method>
- <method name="is_on_ceiling" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the body collided with the ceiling on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code].
- </description>
- </method>
- <method name="is_on_floor" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the body collided with the floor on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code].
- </description>
- </method>
- <method name="is_on_wall" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the body collided with a wall on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code].
- </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 and 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 when you include gravity in [code]linear_velocity[/code] and the body is standing still.
- 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 axis_lock_motion_x], [member axis_lock_motion_y] and [member axis_lock_motion_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="axis_lock_motion_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's X axis movement.
- </member>
- <member name="axis_lock_motion_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's Y axis movement.
- </member>
- <member name="axis_lock_motion_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's Z axis movement.
- </member>
- <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001">
- Extra margin used for collision recovery in motion functions (see [method move_and_collide], [method move_and_slide], [method move_and_slide_with_snap]).
- If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
- A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
- A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of kinematic bodies.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/KinematicCollision2D.xml b/doc/classes/KinematicCollision2D.xml
index ec6e16e25a..5480d7d55f 100644
--- a/doc/classes/KinematicCollision2D.xml
+++ b/doc/classes/KinematicCollision2D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="KinematicCollision2D" inherits="Reference" version="4.0">
+<class name="KinematicCollision2D" inherits="RefCounted" version="4.0">
<brief_description>
- Collision data for [KinematicBody2D] collisions.
+ Collision data for [method PhysicsBody2D.move_and_collide] collisions.
</brief_description>
<description>
- 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.
+ Contains collision data for [method PhysicsBody2D.move_and_collide] collisions. When a [PhysicsBody2D] is moved using [method PhysicsBody2D.move_and_collide], it stops if it detects a collision with another body. If a collision is detected, a [KinematicCollision2D] 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>
diff --git a/doc/classes/KinematicCollision3D.xml b/doc/classes/KinematicCollision3D.xml
index f3248a9ca1..329efab474 100644
--- a/doc/classes/KinematicCollision3D.xml
+++ b/doc/classes/KinematicCollision3D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="KinematicCollision3D" inherits="Reference" version="4.0">
+<class name="KinematicCollision3D" inherits="RefCounted" version="4.0">
<brief_description>
- Collision data for [KinematicBody3D] collisions.
+ Collision data for [method PhysicsBody3D.move_and_collide] 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.
+ Contains collision data for [method PhysicsBody3D.move_and_collide] collisions. When a [PhysicsBody3D] is moved using [method PhysicsBody3D.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>
diff --git a/doc/classes/LargeTexture.xml b/doc/classes/LargeTexture.xml
deleted file mode 100644
index a1d172e4b1..0000000000
--- a/doc/classes/LargeTexture.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="LargeTexture" inherits="Texture2D" version="4.0">
- <brief_description>
- A [Texture2D] capable of storing many smaller textures with offsets.
- </brief_description>
- <description>
- A [Texture2D] capable of storing many smaller textures with offsets.
- You can dynamically add pieces ([Texture2D]s) to this [LargeTexture] using different offsets.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_piece">
- <return type="int">
- </return>
- <argument index="0" name="ofs" type="Vector2">
- </argument>
- <argument index="1" name="texture" type="Texture2D">
- </argument>
- <description>
- Adds [code]texture[/code] to this [LargeTexture], starting on offset [code]ofs[/code].
- </description>
- </method>
- <method name="clear">
- <return type="void">
- </return>
- <description>
- Clears the [LargeTexture].
- </description>
- </method>
- <method name="get_piece_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of pieces currently in this [LargeTexture].
- </description>
- </method>
- <method name="get_piece_offset" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the offset of the piece with the index [code]idx[/code].
- </description>
- </method>
- <method name="get_piece_texture" qualifiers="const">
- <return type="Texture2D">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the [Texture2D] of the piece with the index [code]idx[/code].
- </description>
- </method>
- <method name="set_piece_offset">
- <return type="void">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="ofs" type="Vector2">
- </argument>
- <description>
- Sets the offset of the piece with the index [code]idx[/code] to [code]ofs[/code].
- </description>
- </method>
- <method name="set_piece_texture">
- <return type="void">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="texture" type="Texture2D">
- </argument>
- <description>
- Sets the [Texture2D] of the piece with index [code]idx[/code] to [code]texture[/code].
- </description>
- </method>
- <method name="set_size">
- <return type="void">
- </return>
- <argument index="0" name="size" type="Vector2">
- </argument>
- <description>
- Sets the size of this [LargeTexture].
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
index 6bae612c9f..42b9ed8ab4 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -52,7 +52,7 @@
The light's strength multiplier (this is not a physical unit). For [OmniLight3D] and [SpotLight3D], changing this value will only change the light color's intensity, not the light's radius.
</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].
+ Secondary multiplier used with indirect light (light bounces). Used with [VoxelGI].
</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.
diff --git a/doc/classes/BakedLightmap.xml b/doc/classes/LightmapGI.xml
index 6fd08fc4e4..d7722a83b0 100644
--- a/doc/classes/BakedLightmap.xml
+++ b/doc/classes/LightmapGI.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BakedLightmap" inherits="VisualInstance3D" version="4.0">
+<class name="LightmapGI" inherits="VisualInstance3D" version="4.0">
<brief_description>
</brief_description>
<description>
@@ -21,17 +21,17 @@
</member>
<member name="environment_custom_sky" type="Sky" setter="set_environment_custom_sky" getter="get_environment_custom_sky">
</member>
- <member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="BakedLightmap.EnvironmentMode" default="0">
+ <member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="LightmapGI.EnvironmentMode" default="0">
</member>
- <member name="generate_probes_subdiv" type="int" setter="set_generate_probes" getter="get_generate_probes" enum="BakedLightmap.GenerateProbes" default="0">
+ <member name="generate_probes_subdiv" type="int" setter="set_generate_probes" getter="get_generate_probes" enum="LightmapGI.GenerateProbes" default="0">
</member>
<member name="interior" type="bool" setter="set_interior" getter="is_interior" default="false">
</member>
- <member name="light_data" type="BakedLightmapData" setter="set_light_data" getter="get_light_data">
+ <member name="light_data" type="LightmapGIData" setter="set_light_data" getter="get_light_data">
</member>
<member name="max_texture_size" type="int" setter="set_max_texture_size" getter="get_max_texture_size" default="16384">
</member>
- <member name="quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="BakedLightmap.BakeQuality" default="1">
+ <member name="quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="LightmapGI.BakeQuality" default="1">
</member>
<member name="use_denoiser" type="bool" setter="set_use_denoiser" getter="is_using_denoiser" default="true">
</member>
diff --git a/doc/classes/BakedLightmapData.xml b/doc/classes/LightmapGIData.xml
index 904555c48e..3a37c6dcb7 100644
--- a/doc/classes/BakedLightmapData.xml
+++ b/doc/classes/LightmapGIData.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BakedLightmapData" inherits="Resource" version="4.0">
+<class name="LightmapGIData" inherits="Resource" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/Lightmapper.xml b/doc/classes/Lightmapper.xml
index e80194858a..79fae42d68 100644
--- a/doc/classes/Lightmapper.xml
+++ b/doc/classes/Lightmapper.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Lightmapper" inherits="Reference" version="4.0">
+<class name="Lightmapper" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index 7adf19632e..e11ae7969a 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -248,7 +248,7 @@
Emitted when the text changes.
</description>
</signal>
- <signal name="text_entered">
+ <signal name="text_submitted">
<argument index="0" name="new_text" type="String">
</argument>
<description>
diff --git a/doc/classes/Listener3D.xml b/doc/classes/Listener3D.xml
index 998ea757ff..b2fcbe534d 100644
--- a/doc/classes/Listener3D.xml
+++ b/doc/classes/Listener3D.xml
@@ -18,10 +18,10 @@
</description>
</method>
<method name="get_listener_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<description>
- Returns the listener's global orthonormalized [Transform].
+ Returns the listener's global orthonormalized [Transform3D].
</description>
</method>
<method name="is_current" qualifiers="const">
diff --git a/doc/classes/MeshDataTool.xml b/doc/classes/MeshDataTool.xml
index db7a3187f0..da02511dc0 100644
--- a/doc/classes/MeshDataTool.xml
+++ b/doc/classes/MeshDataTool.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MeshDataTool" inherits="Reference" version="4.0">
+<class name="MeshDataTool" inherits="RefCounted" version="4.0">
<brief_description>
Helper tool to access and edit [Mesh] data.
</brief_description>
@@ -15,7 +15,7 @@
mdt.create_from_surface(mesh, 0)
for i in range(mdt.get_vertex_count()):
var vertex = mdt.get_vertex(i)
- # In this example we extend the mesh by one unit, which results in seperated faces as it is flat shaded.
+ # In this example we extend the mesh by one unit, which results in separated faces as it is flat shaded.
vertex += mdt.get_vertex_normal(i)
# Save your change.
mdt.set_vertex(i, vertex)
@@ -33,7 +33,7 @@
for (var i = 0; i &lt; mdt.GetVertexCount(); i++)
{
Vector3 vertex = mdt.GetVertex(i);
- // In this example we extend the mesh by one unit, which results in seperated faces as it is flat shaded.
+ // In this example we extend the mesh by one unit, which results in separated faces as it is flat shaded.
vertex += mdt.GetVertexNormal(i);
// Save your change.
mdt.SetVertex(i, vertex);
diff --git a/doc/classes/MeshInstance3D.xml b/doc/classes/MeshInstance3D.xml
index e1a6cf44a7..b5ab296bd0 100644
--- a/doc/classes/MeshInstance3D.xml
+++ b/doc/classes/MeshInstance3D.xml
@@ -27,6 +27,13 @@
This helper creates a [MeshInstance3D] child node with gizmos at every vertex calculated from the mesh geometry. It's mainly used for testing.
</description>
</method>
+ <method name="create_multiple_convex_collisions">
+ <return type="void">
+ </return>
+ <description>
+ This helper creates a [StaticBody3D] child node with multiple [ConvexPolygonShape3D] collision shapes calculated from the mesh geometry via convex decomposition. It's mainly used for testing.
+ </description>
+ </method>
<method name="create_trimesh_collision">
<return type="void">
</return>
diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml
index ad8bd6991d..b33bcc89e3 100644
--- a/doc/classes/MeshLibrary.xml
+++ b/doc/classes/MeshLibrary.xml
@@ -72,7 +72,7 @@
</description>
</method>
<method name="get_item_navmesh_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="id" type="int">
</argument>
@@ -96,7 +96,7 @@
</argument>
<description>
Returns an item's collision shapes.
- The array consists of each [Shape3D] followed by its [Transform].
+ The array consists of each [Shape3D] followed by its [Transform3D].
</description>
</method>
<method name="get_last_unused_item_id" qualifiers="const">
@@ -154,7 +154,7 @@
</return>
<argument index="0" name="id" type="int">
</argument>
- <argument index="1" name="navmesh" type="Transform">
+ <argument index="1" name="navmesh" type="Transform3D">
</argument>
<description>
Sets the transform to apply to the item's navigation mesh.
@@ -180,7 +180,7 @@
</argument>
<description>
Sets an item's collision shapes.
- 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].
+ The array should consist of [Shape3D] objects, each followed by a [Transform3D] that will be applied to it. For shapes that should not have a transform, use [constant Transform3D.IDENTITY].
</description>
</method>
</methods>
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index 2adebdb306..02628f4960 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -40,12 +40,12 @@
</description>
</method>
<method name="get_instance_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="instance" type="int">
</argument>
<description>
- Returns the [Transform] of a specific instance.
+ Returns the [Transform3D] of a specific instance.
</description>
</method>
<method name="get_instance_transform_2d" qualifiers="const">
@@ -86,10 +86,10 @@
</return>
<argument index="0" name="instance" type="int">
</argument>
- <argument index="1" name="transform" type="Transform">
+ <argument index="1" name="transform" type="Transform3D">
</argument>
<description>
- Sets the [Transform] for a specific instance.
+ Sets the [Transform3D] for a specific instance.
</description>
</method>
<method name="set_instance_transform_2d">
diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml
index c168695d61..5de5703d95 100644
--- a/doc/classes/MultiplayerAPI.xml
+++ b/doc/classes/MultiplayerAPI.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiplayerAPI" inherits="Reference" version="4.0">
+<class name="MultiplayerAPI" inherits="RefCounted" version="4.0">
<brief_description>
High-level multiplayer API.
</brief_description>
@@ -135,16 +135,16 @@
</signals>
<constants>
<constant name="RPC_MODE_DISABLED" value="0" enum="RPCMode">
- 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.
+ Used with [method Node.rpc_config] to disable a method or property for all RPC calls, making it unavailable. Default for all methods.
</constant>
<constant name="RPC_MODE_REMOTE" value="1" enum="RPCMode">
- 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.
+ Used with [method Node.rpc_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.
</constant>
<constant name="RPC_MODE_MASTER" value="2" enum="RPCMode">
- 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].
+ Used with [method Node.rpc_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].
</constant>
<constant name="RPC_MODE_PUPPET" value="3" enum="RPCMode">
- 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].
+ Used with [method Node.rpc_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].
</constant>
<constant name="RPC_MODE_REMOTESYNC" value="4" enum="RPCMode">
Behave like [constant RPC_MODE_REMOTE] but also make the call or property change locally. Analogous to the [code]remotesync[/code] keyword.
diff --git a/doc/classes/Mutex.xml b/doc/classes/Mutex.xml
index f5f6308401..dfda614f8e 100644
--- a/doc/classes/Mutex.xml
+++ b/doc/classes/Mutex.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Mutex" inherits="Reference" version="4.0">
+<class name="Mutex" inherits="RefCounted" version="4.0">
<brief_description>
A synchronization mutex (mutual exclusion).
</brief_description>
diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml
index 1060e2de41..de81ae4d91 100644
--- a/doc/classes/NavigationAgent2D.xml
+++ b/doc/classes/NavigationAgent2D.xml
@@ -44,6 +44,12 @@
Returns a [Vector2] in global coordinates, that can be moved to, making sure that there are no static objects in the way. If the agent does not have a navigation path, it will return the position of the agent's parent.
</description>
</method>
+ <method name="get_rid" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_target_location" qualifiers="const">
<return type="Vector2">
</return>
diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml
index 00e9db0a33..8942a37774 100644
--- a/doc/classes/NavigationAgent3D.xml
+++ b/doc/classes/NavigationAgent3D.xml
@@ -44,6 +44,12 @@
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_rid" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_target_location" qualifiers="const">
<return type="Vector3">
</return>
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index b098a7fc20..ef9efcb99c 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -413,7 +413,7 @@
</return>
<argument index="0" name="region" type="RID">
</argument>
- <argument index="1" name="transform" type="Transform">
+ <argument index="1" name="transform" type="Transform3D">
</argument>
<description>
Sets the global transformation for the region.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 523f3a0c17..1300351e47 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -649,7 +649,7 @@
<argument index="0" name="method" type="StringName">
</argument>
<description>
- 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].
+ 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. Returns an empty [Variant].
[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].
</description>
</method>
@@ -658,33 +658,17 @@
</return>
<argument index="0" name="method" type="StringName">
</argument>
- <argument index="1" name="mode" type="int" enum="MultiplayerAPI.RPCMode">
+ <argument index="1" name="rpc_mode" type="int" enum="MultiplayerAPI.RPCMode">
</argument>
- <description>
- 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.
- </description>
- </method>
- <method name="rpc_id" qualifiers="vararg">
- <return type="Variant">
- </return>
- <argument index="0" name="peer_id" type="int">
+ <argument index="2" name="transfer_mode" type="int" enum="NetworkedMultiplayerPeer.TransferMode" default="2">
</argument>
- <argument index="1" name="method" type="StringName">
- </argument>
- <description>
- Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). Returns an empty [Variant].
- </description>
- </method>
- <method name="rpc_unreliable" qualifiers="vararg">
- <return type="Variant">
- </return>
- <argument index="0" name="method" type="StringName">
+ <argument index="3" name="channel" type="int" default="0">
</argument>
<description>
- Sends a [method rpc] using an unreliable protocol. Returns an empty [Variant].
+ Changes the RPC mode for the given [code]method[/code] to the given [code]rpc_mode[/code], optionally specifying the [code]transfer_mode[/code] and [code]channel[/code] (on supported peers). See [enum MultiplayerAPI.RPCMode] and [enum NetworkedMultiplayerPeer.TransferMode]. 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).
</description>
</method>
- <method name="rpc_unreliable_id" qualifiers="vararg">
+ <method name="rpc_id" qualifiers="vararg">
<return type="Variant">
</return>
<argument index="0" name="peer_id" type="int">
@@ -692,66 +676,7 @@
<argument index="1" name="method" type="StringName">
</argument>
<description>
- 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].
- </description>
- </method>
- <method name="rset">
- <return type="void">
- </return>
- <argument index="0" name="property" type="StringName">
- </argument>
- <argument index="1" name="value" type="Variant">
- </argument>
- <description>
- 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.
- </description>
- </method>
- <method name="rset_config">
- <return type="int">
- </return>
- <argument index="0" name="property" type="StringName">
- </argument>
- <argument index="1" name="mode" type="int" enum="MultiplayerAPI.RPCMode">
- </argument>
- <description>
- 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.
- </description>
- </method>
- <method name="rset_id">
- <return type="void">
- </return>
- <argument index="0" name="peer_id" type="int">
- </argument>
- <argument index="1" name="property" type="StringName">
- </argument>
- <argument index="2" name="value" type="Variant">
- </argument>
- <description>
- Remotely changes the property's value on a specific peer identified by [code]peer_id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]).
- </description>
- </method>
- <method name="rset_unreliable">
- <return type="void">
- </return>
- <argument index="0" name="property" type="StringName">
- </argument>
- <argument index="1" name="value" type="Variant">
- </argument>
- <description>
- Remotely changes the property's value on other peers (and locally) using an unreliable protocol.
- </description>
- </method>
- <method name="rset_unreliable_id">
- <return type="void">
- </return>
- <argument index="0" name="peer_id" type="int">
- </argument>
- <argument index="1" name="property" type="StringName">
- </argument>
- <argument index="2" name="value" type="Variant">
- </argument>
- <description>
- 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]).
+ Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). Returns an empty [Variant].
</description>
</method>
<method name="set_display_folded">
@@ -969,6 +894,12 @@
<constant name="NOTIFICATION_POST_ENTER_TREE" value="27">
Notification received when the node is ready, just before [constant NOTIFICATION_READY] is received. Unlike the latter, it's sent every time the node enters tree, instead of only once.
</constant>
+ <constant name="NOTIFICATION_EDITOR_PRE_SAVE" value="9001">
+ Notification received right before the scene with the node is saved in the editor. This notification is only sent in the Godot editor and will not occur in exported projects.
+ </constant>
+ <constant name="NOTIFICATION_EDITOR_POST_SAVE" value="9002">
+ Notification received right after the scene with the node is saved in the editor. This notification is only sent in the Godot editor and will not occur in exported projects.
+ </constant>
<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.
diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml
index eed0ec8d7e..8ca945418c 100644
--- a/doc/classes/Node2D.xml
+++ b/doc/classes/Node2D.xml
@@ -150,11 +150,15 @@
<member name="transform" type="Transform2D" setter="set_transform" getter="get_transform">
Local [Transform2D].
</member>
+ <member name="y_sort_enabled" type="bool" setter="set_y_sort_enabled" getter="is_y_sort_enabled" default="false">
+ If [code]true[/code], child nodes with the lowest Y position are drawn before those with a higher Y position. If [code]false[/code], Y-sorting is disabled. Y-sorting only affects children that inherit from [CanvasItem].
+ You can nest nodes with Y-sorting. Child Y-sorted nodes are sorted in the same space as the parent Y-sort. This feature allows you to organize a scene better or divide it into multiple ones without changing your scene tree.
+ </member>
<member name="z_as_relative" type="bool" setter="set_z_as_relative" getter="is_z_relative" default="true">
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.
</member>
<member name="z_index" type="int" setter="set_z_index" getter="get_z_index" default="0">
- Z index. Controls the order in which the nodes render. A node with a higher Z index will display in front of others.
+ Z index. Controls the order in which the nodes render. A node with a higher Z index will display in front of others. Must be between [constant RenderingServer.CANVAS_ITEM_Z_MIN] and [constant RenderingServer.CANVAS_ITEM_Z_MAX] (inclusive).
</member>
</members>
<constants>
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
index 5c29c0d48f..1c161803db 100644
--- a/doc/classes/Node3D.xml
+++ b/doc/classes/Node3D.xml
@@ -4,7 +4,7 @@
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.
+ Most basic 3D game object, with a 3D [Transform3D] 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.
[b]Note:[/b] Unless otherwise specified, all methods that have angle parameters must have angles specified as [i]radians[/i]. To convert degrees to radians, use [method @GlobalScope.deg2rad].
</description>
@@ -20,7 +20,7 @@
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">
+ <method name="get_parent_node_3d" qualifiers="const">
<return type="Node3D">
</return>
<description>
@@ -128,7 +128,7 @@
<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].
+ Resets this node's transformations (like scale, skew and taper) preserving its rotation and translation by performing Gram-Schmidt orthonormalization on this node's [Transform3D].
</description>
</method>
<method name="rotate">
@@ -202,7 +202,7 @@
<return type="void">
</return>
<description>
- Reset all transformations for this node (sets its [Transform] to the identity matrix).
+ Reset all transformations for this node (sets its [Transform3D] to the identity matrix).
</description>
</method>
<method name="set_ignore_transform_notification">
@@ -288,8 +288,11 @@
<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 name="global_transform" type="Transform3D" setter="set_global_transform" getter="get_global_transform">
+ World3D space (global) [Transform3D] of this node.
+ </member>
+ <member name="position" type="Vector3" setter="set_position" getter="get_position" default="Vector3( 0, 0, 0 )">
+ Local position or translation of this node relative to the parent. This is equivalent to [code]transform.origin[/code].
</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).
@@ -304,11 +307,11 @@
<member name="top_level" type="bool" setter="set_as_top_level" getter="is_set_as_top_level" default="false">
If [code]true[/code], the node will not inherit its transformations from its parent. Node transformations are only in global space.
</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 name="transform" type="Transform3D" setter="set_transform" getter="get_transform" default="Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ Local space [Transform3D] 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 name="visibility_parent" type="NodePath" setter="set_visibility_parent" getter="get_visibility_parent" default="NodePath(&quot;&quot;)">
+ Defines the visibility range parent for this node and its subtree. The visibility parent must be a GeometryInstance3D. Any visual instance will only be visible if the visibility parent (and all of its visibility ancestors) is hidden by being closer to the camera than its own [member GeometryInstance3D.visibility_range_begin]. Nodes hidden via the [member Node3D.visible] property are essentially removed from the visibility dependency tree, so dependant instances will not take the hidden node or its ancestors into account.
</member>
<member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true">
If [code]true[/code], this node is drawn. The node is only visible if all of its antecedents are visible as well (in other words, [method is_visible_in_tree] must return [code]true[/code]).
diff --git a/doc/classes/Node3DGizmo.xml b/doc/classes/Node3DGizmo.xml
index 55080614fc..c561047332 100644
--- a/doc/classes/Node3DGizmo.xml
+++ b/doc/classes/Node3DGizmo.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Node3DGizmo" inherits="Reference" version="4.0">
+<class name="Node3DGizmo" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 8c90108aef..bfcd5b1beb 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -143,7 +143,7 @@
Returns the command-line arguments passed to the engine.
Command-line arguments can be written in any form, including both [code]--key value[/code] and [code]--key=value[/code] forms so they can be properly parsed, as long as custom command-line arguments do not conflict with engine arguments.
You can also incorporate environment variables using the [method get_environment] method.
- You can set [code]editor/main_run_args[/code] in the Project Settings to define command-line arguments to be passed by the editor when running the project.
+ You can set [member ProjectSettings.editor/run/main_run_args] to define command-line arguments to be passed by the editor when running the project.
Here's a minimal example on how to parse command-line arguments into a dictionary using the [code]--key=value[/code] form for arguments:
[codeblocks]
[gdscript]
@@ -176,34 +176,6 @@
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
- <method name="get_date" qualifiers="const">
- <return type="Dictionary">
- </return>
- <argument index="0" name="utc" type="bool" default="false">
- </argument>
- <description>
- 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).
- </description>
- </method>
- <method name="get_datetime" qualifiers="const">
- <return type="Dictionary">
- </return>
- <argument index="0" name="utc" type="bool" default="false">
- </argument>
- <description>
- 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].
- </description>
- </method>
- <method name="get_datetime_from_unix_time" qualifiers="const">
- <return type="Dictionary">
- </return>
- <argument index="0" name="unix_time_val" type="int">
- </argument>
- <description>
- Gets a dictionary of time values corresponding to the given UNIX epoch time (in seconds).
- 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.
- </description>
- </method>
<method name="get_environment" qualifiers="const">
<return type="String">
</return>
@@ -221,6 +193,13 @@
Returns the path to the current engine executable.
</description>
</method>
+ <method name="get_external_data_dir" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ On Android, returns the absolute directory path where user data can be written to external storage if available. On all other platforms, this will return the same location as [method get_user_data_dir].
+ </description>
+ </method>
<method name="get_granted_permissions" qualifiers="const">
<return type="PackedStringArray">
</return>
@@ -313,64 +292,15 @@
[b]Note:[/b] Thread IDs are not deterministic and may be reused across application restarts.
</description>
</method>
- <method name="get_ticks_msec" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the amount of time passed in milliseconds since the engine started.
- </description>
- </method>
- <method name="get_ticks_usec" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the amount of time passed in microseconds since the engine started.
- </description>
- </method>
- <method name="get_time" qualifiers="const">
- <return type="Dictionary">
- </return>
- <argument index="0" name="utc" type="bool" default="false">
- </argument>
- <description>
- Returns current time as a dictionary of keys: hour, minute, second.
- </description>
- </method>
- <method name="get_time_zone_info" qualifiers="const">
- <return type="Dictionary">
- </return>
- <description>
- Returns the current time zone as a dictionary with the keys: bias and name.
- </description>
- </method>
<method name="get_unique_id" qualifiers="const">
<return type="String">
</return>
<description>
Returns a string that is unique to the device.
+ [b]Note:[/b] This string may change without notice if the user reinstalls/upgrades their operating system or changes their hardware. This means it should generally not be used to encrypt persistent data as the data saved prior to an unexpected ID change would become inaccessible. The returned string may also be falsified using external programs, so do not rely on the string returned by [method get_unique_id] for security purposes.
[b]Note:[/b] Returns an empty string on HTML5 and UWP, as this method isn't implemented on those platforms yet.
</description>
</method>
- <method name="get_unix_time" qualifiers="const">
- <return type="float">
- </return>
- <description>
- Returns the current UNIX epoch timestamp in seconds.
- [b]Important:[/b] This is the system clock that the user can manully set. [b]Never use[/b] this method for precise time calculation since its results are also subject to automatic adjustments by the operating system. [b]Always use[/b] [method get_ticks_usec] or [method get_ticks_msec] for precise time calculation instead, since they are guaranteed to be monotonic (i.e. never decrease).
- </description>
- </method>
- <method name="get_unix_time_from_datetime" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="datetime" type="Dictionary">
- </argument>
- <description>
- Gets an epoch time value from a dictionary of time values.
- [code]datetime[/code] must be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], [code]second[/code].
- If the dictionary is empty [code]0[/code] is returned.
- You can pass the output from [method get_datetime_from_unix_time] directly into this function. Daylight Savings Time ([code]dst[/code]), if present, is ignored.
- </description>
- </method>
<method name="get_user_data_dir" qualifiers="const">
<return type="String">
</return>
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 7da9c1ac38..f5dcd6bcdc 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -7,7 +7,7 @@
Every class which is not a built-in type inherits from this class.
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.
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++.
- 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.
+ Some classes that extend Object add memory management. This is the case of [RefCounted], which counts references and deletes itself automatically when no longer referenced. [Node], another fundamental type, deletes all its children when freed from memory.
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.
Property membership can be tested directly in GDScript using [code]in[/code]:
[codeblocks]
@@ -26,7 +26,7 @@
[/codeblocks]
The [code]in[/code] operator will evaluate to [code]true[/code] as long as the key exists, even if the value is [code]null[/code].
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].
- [b]Note:[/b] Unlike references to a [Reference], references to an Object stored in a variable can become invalid without warning. Therefore, it's recommended to use [Reference] for data classes instead of [Object].
+ [b]Note:[/b] Unlike references to a [RefCounted], references to an Object stored in a variable can become invalid without warning. Therefore, it's recommended to use [RefCounted] for data classes instead of [Object].
</description>
<tutorials>
<link title="When and how to avoid using nodes for everything">https://docs.godotengine.org/en/latest/getting_started/workflow/best_practices/node_alternatives.html</link>
diff --git a/doc/classes/Occluder3D.xml b/doc/classes/Occluder3D.xml
new file mode 100644
index 0000000000..fc676c2b49
--- /dev/null
+++ b/doc/classes/Occluder3D.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Occluder3D" inherits="Resource" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="indices" type="PackedInt32Array" setter="set_indices" getter="get_indices" default="PackedInt32Array( )">
+ </member>
+ <member name="vertices" type="PackedVector3Array" setter="set_vertices" getter="get_vertices" default="PackedVector3Array( )">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/OccluderInstance3D.xml b/doc/classes/OccluderInstance3D.xml
new file mode 100644
index 0000000000..76b784d21d
--- /dev/null
+++ b/doc/classes/OccluderInstance3D.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="OccluderInstance3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_bake_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="layer" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_bake_mask_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer" type="int">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="bake_mask" type="int" setter="set_bake_mask" getter="get_bake_mask" default="4294967295">
+ </member>
+ <member name="occluder" type="Occluder3D" setter="set_occluder" getter="get_occluder">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PCKPacker.xml b/doc/classes/PCKPacker.xml
index e3c78e08f1..40e8683c93 100644
--- a/doc/classes/PCKPacker.xml
+++ b/doc/classes/PCKPacker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PCKPacker" inherits="Reference" version="4.0">
+<class name="PCKPacker" inherits="RefCounted" version="4.0">
<brief_description>
Creates packages that can be loaded into a running project.
</brief_description>
diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml
index 24178c3ff6..0652cf0aa1 100644
--- a/doc/classes/PackedByteArray.xml
+++ b/doc/classes/PackedByteArray.xml
@@ -322,6 +322,15 @@
<description>
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="int">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="get_string_from_ascii" qualifiers="const">
<return type="String">
</return>
diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml
index 38240b3154..19cfcd7c87 100644
--- a/doc/classes/PackedColorArray.xml
+++ b/doc/classes/PackedColorArray.xml
@@ -59,6 +59,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="Color">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
diff --git a/doc/classes/PackedDataContainerRef.xml b/doc/classes/PackedDataContainerRef.xml
index f0f59675de..bfd5a6f1c1 100644
--- a/doc/classes/PackedDataContainerRef.xml
+++ b/doc/classes/PackedDataContainerRef.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedDataContainerRef" inherits="Reference" version="4.0">
+<class name="PackedDataContainerRef" inherits="RefCounted" version="4.0">
<brief_description>
- Reference version of [PackedDataContainer].
+ Reference-counted version of [PackedDataContainer].
</brief_description>
<description>
</description>
diff --git a/doc/classes/PackedFloat32Array.xml b/doc/classes/PackedFloat32Array.xml
index 5e0008852c..ab97c9a695 100644
--- a/doc/classes/PackedFloat32Array.xml
+++ b/doc/classes/PackedFloat32Array.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="float">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml
index fb7817cb41..ad20801b01 100644
--- a/doc/classes/PackedFloat64Array.xml
+++ b/doc/classes/PackedFloat64Array.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="float">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
diff --git a/doc/classes/PackedInt32Array.xml b/doc/classes/PackedInt32Array.xml
index 4ee428dfbc..ff4729082e 100644
--- a/doc/classes/PackedInt32Array.xml
+++ b/doc/classes/PackedInt32Array.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="int">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml
index 51948fcbc8..195b12b129 100644
--- a/doc/classes/PackedInt64Array.xml
+++ b/doc/classes/PackedInt64Array.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="int">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml
index 9748301dae..22458832da 100644
--- a/doc/classes/PackedStringArray.xml
+++ b/doc/classes/PackedStringArray.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="String">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml
index 1b3201b072..6c8791f988 100644
--- a/doc/classes/PackedVector2Array.xml
+++ b/doc/classes/PackedVector2Array.xml
@@ -60,6 +60,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="Vector2">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml
index 25d854016a..00ded39082 100644
--- a/doc/classes/PackedVector3Array.xml
+++ b/doc/classes/PackedVector3Array.xml
@@ -59,6 +59,15 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="fill">
+ <return type="void">
+ </return>
+ <argument index="0" name="value" type="Vector3">
+ </argument>
+ <description>
+ Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
+ </description>
+ </method>
<method name="has">
<return type="bool">
</return>
@@ -97,7 +106,7 @@
<method name="operator *" qualifiers="operator">
<return type="PackedVector3Array">
</return>
- <argument index="0" name="right" type="Transform">
+ <argument index="0" name="right" type="Transform3D">
</argument>
<description>
</description>
diff --git a/doc/classes/PacketPeer.xml b/doc/classes/PacketPeer.xml
index e3e2f63e14..0a758c2cd6 100644
--- a/doc/classes/PacketPeer.xml
+++ b/doc/classes/PacketPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PacketPeer" inherits="Reference" version="4.0">
+<class name="PacketPeer" inherits="RefCounted" version="4.0">
<brief_description>
Abstraction and base class for packet-based protocols.
</brief_description>
diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml
index d7cf6cc8c6..5d059ad3df 100644
--- a/doc/classes/PacketPeerUDP.xml
+++ b/doc/classes/PacketPeerUDP.xml
@@ -9,11 +9,27 @@
<tutorials>
</tutorials>
<methods>
+ <method name="bind">
+ <return type="int" enum="Error">
+ </return>
+ <argument index="0" name="port" type="int">
+ </argument>
+ <argument index="1" name="bind_address" type="String" default="&quot;*&quot;">
+ </argument>
+ <argument index="2" name="recv_buf_size" type="int" default="65536">
+ </argument>
+ <description>
+ Binds this [PacketPeerUDP] to the specified [code]port[/code] and [code]address[/code] with a buffer size [code]recv_buf_size[/code], allowing it to receive incoming packets.
+ If [code]address[/code] is set to [code]"*"[/code] (default), the peer will be bound on all available addresses (both IPv4 and IPv6).
+ If [code]address[/code] is set to [code]"0.0.0.0"[/code] (for IPv4) or [code]"::"[/code] (for IPv6), the peer will be bound to all available addresses matching that IP type.
+ If [code]address[/code] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the peer will only be bound to the interface with that addresses (or fail if no interface with the given address exists).
+ </description>
+ </method>
<method name="close">
<return type="void">
</return>
<description>
- Closes the UDP socket the [PacketPeerUDP] is currently listening on.
+ Closes the [PacketPeerUDP]'s underlying UDP socket.
</description>
</method>
<method name="connect_to_host">
@@ -28,6 +44,13 @@
[b]Note:[/b] Connecting to the remote peer does not help to protect from malicious attacks like IP spoofing, etc. Think about using an encryption technique like SSL or DTLS if you feel like your application is transferring sensitive information.
</description>
</method>
+ <method name="get_local_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the local port to which this peer is bound.
+ </description>
+ </method>
<method name="get_packet_ip" qualifiers="const">
<return type="String">
</return>
@@ -42,18 +65,18 @@
Returns the port of the remote peer that sent the last packet(that was received with [method PacketPeer.get_packet] or [method PacketPeer.get_var]).
</description>
</method>
- <method name="is_connected_to_host" qualifiers="const">
+ <method name="is_bound" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if the UDP socket is open and has been connected to a remote address. See [method connect_to_host].
+ Returns whether this [PacketPeerUDP] is bound to an address and can receive packets.
</description>
</method>
- <method name="is_listening" qualifiers="const">
+ <method name="is_connected_to_host" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns whether this [PacketPeerUDP] is listening.
+ Returns [code]true[/code] if the UDP socket is open and has been connected to a remote address. See [method connect_to_host].
</description>
</method>
<method name="join_multicast_group">
@@ -80,22 +103,6 @@
Removes the interface identified by [code]interface_name[/code] from the multicast group specified by [code]multicast_address[/code].
</description>
</method>
- <method name="listen">
- <return type="int" enum="Error">
- </return>
- <argument index="0" name="port" type="int">
- </argument>
- <argument index="1" name="bind_address" type="String" default="&quot;*&quot;">
- </argument>
- <argument index="2" name="recv_buf_size" type="int" default="65536">
- </argument>
- <description>
- Makes this [PacketPeerUDP] listen on the [code]port[/code] binding to [code]bind_address[/code] with a buffer size [code]recv_buf_size[/code].
- If [code]bind_address[/code] is set to [code]"*"[/code] (default), the peer will listen on all available addresses (both IPv4 and IPv6).
- If [code]bind_address[/code] is set to [code]"0.0.0.0"[/code] (for IPv4) or [code]"::"[/code] (for IPv6), the peer will listen on all available addresses matching that IP type.
- If [code]bind_address[/code] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the peer will only listen on the interface with that addresses (or fail if no interface with the given address exists).
- </description>
- </method>
<method name="set_broadcast_enabled">
<return type="void">
</return>
@@ -122,7 +129,7 @@
<return type="int" enum="Error">
</return>
<description>
- Waits for a packet to arrive on the listening port. See [method listen].
+ Waits for a packet to arrive on the bound address. See [method bind].
[b]Note:[/b] [method wait] can't be interrupted once it has been called. This can be worked around by allowing the other party to send a specific "death pill" packet like this:
[codeblocks]
[gdscript]
diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml
index 6d7f99a55b..3c364b621a 100644
--- a/doc/classes/ParticlesMaterial.xml
+++ b/doc/classes/ParticlesMaterial.xml
@@ -135,7 +135,7 @@
</member>
<member name="collision_bounce" type="float" setter="set_collision_bounce" getter="get_collision_bounce" default="0.0">
</member>
- <member name="collision_enabled" type="bool" setter="set_collision_enabled" getter="is_collision_enabled" default="true">
+ <member name="collision_enabled" type="bool" setter="set_collision_enabled" getter="is_collision_enabled" default="false">
</member>
<member name="collision_friction" type="float" setter="set_collision_friction" getter="get_collision_friction" default="0.0">
</member>
diff --git a/doc/classes/PhysicalBone2D.xml b/doc/classes/PhysicalBone2D.xml
new file mode 100644
index 0000000000..cea75bad52
--- /dev/null
+++ b/doc/classes/PhysicalBone2D.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicalBone2D" inherits="RigidBody2D" version="4.0">
+ <brief_description>
+ A 2D node that can be used for physically aware bones in 2D.
+ </brief_description>
+ <description>
+ The [code]PhysicalBone2D[/code] node is a [RigidBody2D]-based node that can be used to make [Bone2D] nodes in a [Skeleton2D] react to physics. This node is very similar to the [PhysicalBone3D] node, just for 2D instead of 3D.
+ [b]Note:[/b] To have the Bone2D nodes visually follow the [code]PhysicalBone2D[/code] node, use a [SkeletonModification2DPhysicalBones] modification on the [Skeleton2D] node with the [Bone2D] nodes.
+ [b]Note:[/b] The PhysicalBone2D node does not automatically create a [Joint2D] node to keep [code]PhysicalBone2D[/code] nodes together. You will need to create these manually. For most cases, you want to use a [PinJoint2D] node. The [code]PhysicalBone2D[/code] node can automatically configure the [Joint2D] node once it's been created as a child node.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_joint" qualifiers="const">
+ <return type="Joint2D">
+ </return>
+ <description>
+ Returns the first [Joint2D] child node, if one exists. This is mainly a helper function to make it easier to get the [Joint2D] that the [code]PhysicalBone2D[/code] is autoconfiguring.
+ </description>
+ </method>
+ <method name="is_simulating_physics" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns a boolean that indicates whether the [code]PhysicalBone2D[/code] node is running and simulating using the Godot 2D physics engine. When [code]true[/code], the PhysicalBone2D node is using physics.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="auto_configure_joint" type="bool" setter="set_auto_configure_joint" getter="get_auto_configure_joint" default="true">
+ If [code]true[/code], the [code]PhysicalBone2D[/code] node will automatically configure the first [Joint2D] child node. The automatic configuration is limited to setting up the node properties and positioning the [Joint2D].
+ </member>
+ <member name="bone2d_index" type="int" setter="set_bone2d_index" getter="get_bone2d_index" default="-1">
+ The index of the [Bone2D] node that this [code]PhysicalBone2D[/code] node is supposed to be simulating.
+ </member>
+ <member name="bone2d_nodepath" type="NodePath" setter="set_bone2d_nodepath" getter="get_bone2d_nodepath" default="NodePath(&quot;&quot;)">
+ The [NodePath] to the [Bone2D] node that this [code]PhysicalBone2D[/code] node is supposed to be simulating.
+ </member>
+ <member name="follow_bone_when_simulating" type="bool" setter="set_follow_bone_when_simulating" getter="get_follow_bone_when_simulating" default="false">
+ If [code]true[/code], the [code]PhysicalBone2D[/code] will keep the transform of the bone it is bound to when simulating physics.
+ </member>
+ <member name="simulate_physics" type="bool" setter="set_simulate_physics" getter="get_simulate_physics" default="false">
+ If [code]true[/code], the [code]PhysicalBone2D[/code] will start simulating using physics. If [code]false[/code], the [code]PhysicalBone2D[/code] will follow the transform of the [Bone2D] node.
+ [b]Note:[/b] To have the Bone2D nodes visually follow the [code]PhysicalBone2D[/code] node, use a [SkeletonModification2DPhysicalBones] modification on the [Skeleton2D] node with the [Bone2D] nodes.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml
index 38d9f722b1..5d15590a3f 100644
--- a/doc/classes/PhysicalBone3D.xml
+++ b/doc/classes/PhysicalBone3D.xml
@@ -25,14 +25,6 @@
<description>
</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>
- </description>
- </method>
<method name="get_bone_id" qualifiers="const">
<return type="int">
</return>
@@ -51,40 +43,12 @@
<description>
</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>
- </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 )">
+ <member name="body_offset" type="Transform3D" setter="set_body_offset" getter="get_body_offset" default="Transform3D( 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">
@@ -99,7 +63,7 @@
<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 )">
+ <member name="joint_offset" type="Transform3D" setter="set_joint_offset" getter="get_joint_offset" default="Transform3D( 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">
diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml
index e43d3bb762..654b0fb668 100644
--- a/doc/classes/PhysicsBody2D.xml
+++ b/doc/classes/PhysicsBody2D.xml
@@ -26,6 +26,25 @@
Returns an array of nodes that were added as collision exceptions for this body.
</description>
</method>
+ <method name="move_and_collide">
+ <return type="KinematicCollision2D">
+ </return>
+ <argument index="0" name="rel_vec" type="Vector2">
+ </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>
+ <argument index="4" name="safe_margin" type="float" default="0.08">
+ </argument>
+ <description>
+ 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.
+ If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
+ [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details).
+ </description>
+ </method>
<method name="remove_collision_exception_with">
<return type="void">
</return>
@@ -35,6 +54,27 @@
Removes a body from the list of bodies that this body can't collide with.
</description>
</method>
+ <method name="test_move">
+ <return type="bool">
+ </return>
+ <argument index="0" name="from" type="Transform2D">
+ </argument>
+ <argument index="1" name="rel_vec" type="Vector2">
+ </argument>
+ <argument index="2" name="infinite_inertia" type="bool" default="true">
+ </argument>
+ <argument index="3" name="exclude_raycast_shapes" type="bool" default="true">
+ </argument>
+ <argument index="4" name="collision" type="KinematicCollision2D" default="null">
+ </argument>
+ <argument index="5" name="safe_margin" type="float" default="0.08">
+ </argument>
+ <description>
+ 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.
+ [code]collision[/code] is an optional object of type [KinematicCollision2D], which contains additional information about the collision (should there be one).
+ [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details).
+ </description>
+ </method>
</methods>
<members>
<member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" override="true" default="false" />
diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml
index 2ad1e513c2..1ec38000be 100644
--- a/doc/classes/PhysicsBody3D.xml
+++ b/doc/classes/PhysicsBody3D.xml
@@ -19,6 +19,15 @@
Adds a body to the list of bodies that this body can't collide with.
</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 [code]axis[/code] is locked.
+ </description>
+ </method>
<method name="get_collision_exceptions">
<return type="PhysicsBody3D[]">
</return>
@@ -26,6 +35,25 @@
Returns an array of nodes that were added as collision exceptions for this body.
</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>
+ <argument index="4" name="safe_margin" type="float" default="0.001">
+ </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.
+ [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details).
+ </description>
+ </method>
<method name="remove_collision_exception_with">
<return type="void">
</return>
@@ -35,8 +63,58 @@
Removes a body from the list of bodies that this body can't collide with.
</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 linear or rotational [code]axis[/code] depending on the value of [code]lock[/code].
+ </description>
+ </method>
+ <method name="test_move">
+ <return type="bool">
+ </return>
+ <argument index="0" name="from" type="Transform3D">
+ </argument>
+ <argument index="1" name="rel_vec" type="Vector3">
+ </argument>
+ <argument index="2" name="infinite_inertia" type="bool" default="true">
+ </argument>
+ <argument index="3" name="exclude_raycast_shapes" type="bool" default="true">
+ </argument>
+ <argument index="4" name="collision" type="KinematicCollision3D" default="null">
+ </argument>
+ <argument index="5" name="safe_margin" type="float" default="0.001">
+ </argument>
+ <description>
+ Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
+ [code]collision[/code] is an optional object of type [KinematicCollision3D], which contains additional information about the collision (should there be one).
+ [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details).
+ </description>
+ </method>
</methods>
<members>
+ <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 linear 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 linear 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 linear movement in the Z axis.
+ </member>
</members>
<constants>
</constants>
diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml
index dfc0ab909a..66ff16a3ce 100644
--- a/doc/classes/PhysicsDirectBodyState2D.xml
+++ b/doc/classes/PhysicsDirectBodyState2D.xml
@@ -4,7 +4,7 @@
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].
+ 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 dynamic bodies, and is intended for changing the direct state of that body. See [method RigidBody2D._integrate_forces].
</description>
<tutorials>
<link title="Ray-casting">https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml
index eea681e696..7cb3a56338 100644
--- a/doc/classes/PhysicsDirectBodyState3D.xml
+++ b/doc/classes/PhysicsDirectBodyState3D.xml
@@ -4,7 +4,7 @@
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].
+ 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 dynamic bodies, and is intended for changing the direct state of that body. See [method RigidBody3D._integrate_forces].
</description>
<tutorials>
</tutorials>
@@ -214,7 +214,7 @@
<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">
+ <member name="transform" type="Transform3D" setter="set_transform" getter="get_transform">
The body's transformation matrix.
</member>
</members>
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 701a430538..4c2abcb087 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -659,11 +659,9 @@
</return>
<argument index="0" name="body" type="RID">
</argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
+ <argument index="1" name="callable" type="Callable">
</argument>
- <argument index="3" name="userdata" type="Variant" default="null">
+ <argument index="2" name="userdata" type="Variant" default="null">
</argument>
<description>
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
@@ -1020,6 +1018,15 @@
Activates or deactivates the 2D physics engine.
</description>
</method>
+ <method name="set_collision_iterations">
+ <return type="void">
+ </return>
+ <argument index="0" name="iterations" type="int">
+ </argument>
+ <description>
+ Sets the amount of iterations for calculating velocities of colliding bodies. The greater the amount, the more accurate the collisions, but with a performance loss.
+ </description>
+ </method>
<method name="shape_get_data" qualifiers="const">
<return type="Variant">
</return>
@@ -1200,16 +1207,16 @@
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 for static bodies. In this mode, a body can be only moved by user code.
</constant>
<constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode">
- Constant for kinematic bodies.
+ Constant for kinematic bodies. In this mode, a body can be only moved by user code and collides with other bodies along its path.
</constant>
- <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode">
- Constant for rigid bodies.
+ <constant name="BODY_MODE_DYNAMIC" value="2" enum="BodyMode">
+ Constant for dynamic bodies. In this mode, a body can be pushed by other bodies and has forces applied.
</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 name="BODY_MODE_DYNAMIC_LOCKED" value="3" enum="BodyMode">
+ Constant for locked dynamic bodies. In this mode, a body is dynamic but can not rotate, and only its linear velocity is affected by external forces.
</constant>
<constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter">
Constant to set/get a body's bounce factor.
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index c61347ba0b..2972d5155c 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -16,7 +16,7 @@
</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 index="2" name="transform" type="Transform3D" default="Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
</argument>
<argument index="3" name="disabled" type="bool" default="false">
</argument>
@@ -92,7 +92,7 @@
</description>
</method>
<method name="area_get_shape_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="area" type="RID">
</argument>
@@ -121,7 +121,7 @@
</description>
</method>
<method name="area_get_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="area" type="RID">
</argument>
@@ -258,7 +258,7 @@
</argument>
<argument index="1" name="shape_idx" type="int">
</argument>
- <argument index="2" name="transform" type="Transform">
+ <argument index="2" name="transform" type="Transform3D">
</argument>
<description>
Sets the transform matrix for an area shape.
@@ -291,7 +291,7 @@
</return>
<argument index="0" name="area" type="RID">
</argument>
- <argument index="1" name="transform" type="Transform">
+ <argument index="1" name="transform" type="Transform3D">
</argument>
<description>
Sets the transform matrix for an area.
@@ -337,7 +337,7 @@
</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 index="2" name="transform" type="Transform3D" default="Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
</argument>
<argument index="3" name="disabled" type="bool" default="false">
</argument>
@@ -443,14 +443,6 @@
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>
@@ -510,7 +502,7 @@
</description>
</method>
<method name="body_get_shape_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="body" type="RID">
</argument>
@@ -653,26 +645,14 @@
</return>
<argument index="0" name="body" type="RID">
</argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
+ <argument index="1" name="callable" type="Callable">
</argument>
- <argument index="3" name="userdata" type="Variant" default="null">
+ <argument index="2" name="userdata" type="Variant" default="null">
</argument>
<description>
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
</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>
@@ -762,7 +742,7 @@
</argument>
<argument index="1" name="shape_idx" type="int">
</argument>
- <argument index="2" name="transform" type="Transform">
+ <argument index="2" name="transform" type="Transform3D">
</argument>
<description>
Sets the transform matrix for a body shape.
@@ -1019,11 +999,11 @@
</argument>
<argument index="1" name="body_A" type="RID">
</argument>
- <argument index="2" name="local_ref_A" type="Transform">
+ <argument index="2" name="local_ref_A" type="Transform3D">
</argument>
<argument index="3" name="body_B" type="RID">
</argument>
- <argument index="4" name="local_ref_B" type="Transform">
+ <argument index="4" name="local_ref_B" type="Transform3D">
</argument>
<description>
</description>
@@ -1035,11 +1015,11 @@
</argument>
<argument index="1" name="body_A" type="RID">
</argument>
- <argument index="2" name="local_ref_A" type="Transform">
+ <argument index="2" name="local_ref_A" type="Transform3D">
</argument>
<argument index="3" name="body_B" type="RID">
</argument>
- <argument index="4" name="local_ref_B" type="Transform">
+ <argument index="4" name="local_ref_B" type="Transform3D">
</argument>
<description>
</description>
@@ -1051,11 +1031,11 @@
</argument>
<argument index="1" name="body_A" type="RID">
</argument>
- <argument index="2" name="hinge_A" type="Transform">
+ <argument index="2" name="hinge_A" type="Transform3D">
</argument>
<argument index="3" name="body_B" type="RID">
</argument>
- <argument index="4" name="hinge_B" type="Transform">
+ <argument index="4" name="hinge_B" type="Transform3D">
</argument>
<description>
</description>
@@ -1083,11 +1063,11 @@
</argument>
<argument index="1" name="body_A" type="RID">
</argument>
- <argument index="2" name="local_ref_A" type="Transform">
+ <argument index="2" name="local_ref_A" type="Transform3D">
</argument>
<argument index="3" name="body_B" type="RID">
</argument>
- <argument index="4" name="local_ref_B" type="Transform">
+ <argument index="4" name="local_ref_B" type="Transform3D">
</argument>
<description>
</description>
@@ -1597,16 +1577,16 @@
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 for static bodies. In this mode, a body can be only moved by user code.
</constant>
<constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode">
- Constant for kinematic bodies.
+ Constant for kinematic bodies. In this mode, a body can be only moved by user code and collides with other bodies along its path.
</constant>
- <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode">
- Constant for rigid bodies.
+ <constant name="BODY_MODE_DYNAMIC" value="2" enum="BodyMode">
+ Constant for dynamic bodies. In this mode, a body can be pushed by other bodies and has forces applied.
</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 name="BODY_MODE_DYNAMIC_LOCKED" value="3" enum="BodyMode">
+ Constant for locked dynamic bodies. In this mode, a body is dynamic but can not rotate, and only its linear velocity is affected by external forces.
</constant>
<constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter">
Constant to set/get a body's bounce factor.
diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml
index 4d7fc61517..92bd9b136a 100644
--- a/doc/classes/PhysicsShapeQueryParameters2D.xml
+++ b/doc/classes/PhysicsShapeQueryParameters2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsShapeQueryParameters2D" inherits="Reference" version="4.0">
+<class name="PhysicsShapeQueryParameters2D" inherits="RefCounted" version="4.0">
<brief_description>
Parameters to be sent to a 2D shape physics query.
</brief_description>
diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml
index 4b43ea66fc..087c52a650 100644
--- a/doc/classes/PhysicsShapeQueryParameters3D.xml
+++ b/doc/classes/PhysicsShapeQueryParameters3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsShapeQueryParameters3D" inherits="Reference" version="4.0">
+<class name="PhysicsShapeQueryParameters3D" inherits="RefCounted" version="4.0">
<brief_description>
Parameters to be sent to a 3D shape physics query.
</brief_description>
@@ -60,7 +60,7 @@
[/csharp]
[/codeblocks]
</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 )">
+ <member name="transform" type="Transform3D" setter="set_transform" getter="get_transform" default="Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
The queried shape's transform matrix.
</member>
</members>
diff --git a/doc/classes/PhysicsShapeQueryResult2D.xml b/doc/classes/PhysicsShapeQueryResult2D.xml
index 227683cc33..07b7bc90e2 100644
--- a/doc/classes/PhysicsShapeQueryResult2D.xml
+++ b/doc/classes/PhysicsShapeQueryResult2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsShapeQueryResult2D" inherits="Reference" version="4.0">
+<class name="PhysicsShapeQueryResult2D" inherits="RefCounted" version="4.0">
<brief_description>
Result of a 2D shape query in [PhysicsServer2D].
</brief_description>
diff --git a/doc/classes/PhysicsShapeQueryResult3D.xml b/doc/classes/PhysicsShapeQueryResult3D.xml
index 4555c4e242..d0ca227a68 100644
--- a/doc/classes/PhysicsShapeQueryResult3D.xml
+++ b/doc/classes/PhysicsShapeQueryResult3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsShapeQueryResult3D" inherits="Reference" version="4.0">
+<class name="PhysicsShapeQueryResult3D" inherits="RefCounted" version="4.0">
<brief_description>
Result of a 3D shape query in [PhysicsServer3D].
</brief_description>
diff --git a/doc/classes/PhysicsTestMotionResult2D.xml b/doc/classes/PhysicsTestMotionResult2D.xml
index 301cff2885..2744aa17a1 100644
--- a/doc/classes/PhysicsTestMotionResult2D.xml
+++ b/doc/classes/PhysicsTestMotionResult2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsTestMotionResult2D" inherits="Reference" version="4.0">
+<class name="PhysicsTestMotionResult2D" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/PinJoint2D.xml b/doc/classes/PinJoint2D.xml
index 42155a7f25..ed45149cdf 100644
--- a/doc/classes/PinJoint2D.xml
+++ b/doc/classes/PinJoint2D.xml
@@ -4,7 +4,7 @@
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 (dynamic or static) together.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PinJoint3D.xml b/doc/classes/PinJoint3D.xml
index 267ea38873..37a85e497f 100644
--- a/doc/classes/PinJoint3D.xml
+++ b/doc/classes/PinJoint3D.xml
@@ -4,7 +4,7 @@
Pin joint for 3D PhysicsBodies.
</brief_description>
<description>
- Pin joint for 3D rigid bodies. It pins 2 bodies (rigid or static) together. See also [Generic6DOFJoint3D].
+ Pin joint for 3D rigid bodies. It pins 2 bodies (dynamic or static) together. See also [Generic6DOFJoint3D].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml
index 8b73bcb9c1..3892633654 100644
--- a/doc/classes/PrimitiveMesh.xml
+++ b/doc/classes/PrimitiveMesh.xml
@@ -31,7 +31,7 @@
</methods>
<members>
<member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB( 0, 0, 0, 0, 0, 0 )">
- Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unexpected culling when using a shader to offset vertices.
+ Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unexpected culling when using a shader to offset vertices.
</member>
<member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces" default="false">
If set, the order of the vertices in each triangle are reversed resulting in the backside of the mesh being drawn.
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index c8fd0d667b..35656d170b 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -6,6 +6,7 @@
<description>
Contains global variables accessible from everywhere. Use [method get_setting], [method set_setting] or [method has_setting] to access them. Variables stored in [code]project.godot[/code] are also loaded into ProjectSettings, making this object very useful for reading custom game configuration options.
When naming a Project Settings property, use the full path to the setting including the category. For example, [code]"application/config/name"[/code] for the project name. Category and property names can be viewed in the Project Settings dialog.
+ [b]Feature tags:[/b] Project settings can be overridden for specific platforms and configurations (debug, release, ...) using [url=https://docs.godotengine.org/en/latest/tutorials/export/feature_tags.html]feature tags[/url].
[b]Overriding:[/b] Any project setting can be overridden by creating a file named [code]override.cfg[/code] in the project's root directory. This can also be used in exported projects by placing this file in the same directory as the project binary. Overriding will still take the base project settings' [url=https://docs.godotengine.org/en/latest/tutorials/export/feature_tags.html]feature tags[/url] in account. Therefore, make sure to [i]also[/i] override the setting with the desired feature tags if you want them to override base project settings on all platforms and configurations.
</description>
<tutorials>
@@ -308,7 +309,7 @@
If [code]true[/code], microphone input will be allowed. This requires appropriate permissions to be set when exporting to Android or iOS.
</member>
<member name="audio/driver/mix_rate" type="int" setter="" getter="" default="44100">
- Mixing rate used for audio. In general, it's better to not touch this and leave it to the host operating system.
+ The mixing rate used for audio (in Hz). In general, it's better to not touch this and leave it to the host operating system.
</member>
<member name="audio/driver/output_latency" type="int" setter="" getter="" default="15">
Output latency in milliseconds for audio. Lower values will result in lower audio latency at the cost of increased CPU usage. Low values may result in audible cracking on slower hardware.
@@ -493,8 +494,9 @@
<member name="display/window/energy_saving/keep_screen_on" type="bool" setter="" getter="" default="true">
If [code]true[/code], keeps the screen on (even in case of inactivity), so the screensaver does not take over. Works on desktop and mobile platforms.
</member>
- <member name="display/window/handheld/orientation" type="String" setter="" getter="" default="&quot;landscape&quot;">
- Default orientation on mobile devices.
+ <member name="display/window/handheld/orientation" type="int" setter="" getter="" default="0">
+ The default screen orientation to use on mobile devices. See [enum DisplayServer.ScreenOrientation] for possible values.
+ [b]Note:[/b] When set to a portrait orientation, this project setting does not flip the project resolution's width and height automatically. Instead, you have to set [member display/window/size/width] and [member display/window/size/height] accordingly.
</member>
<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.
@@ -541,7 +543,15 @@
<member name="editor/node_naming/name_num_separator" type="int" setter="" getter="" default="0">
What to use to separate node name from number. This is mostly an editor setting.
</member>
- <member name="editor/script/search_in_file_extensions" type="PackedStringArray" setter="" getter="" default="PackedStringArray( &quot;gd&quot;, &quot;shader&quot; )">
+ <member name="editor/run/main_run_args" type="String" setter="" getter="" default="&quot;&quot;">
+ The command-line arguments to append to Godot's own command line when running the project. This doesn't affect the editor itself.
+ It is possible to make another executable run Godot by using the [code]%command%[/code] placeholder. The placeholder will be replaced with Godot's own command line. Program-specific arguments should be placed [i]before[/i] the placeholder, whereas Godot-specific arguments should be placed [i]after[/i] the placeholder.
+ For example, this can be used to force the project to run on the dedicated GPU in a NVIDIA Optimus system on Linux:
+ [codeblock]
+ prime-run %command%
+ [/codeblock]
+ </member>
+ <member name="editor/script/search_in_file_extensions" type="PackedStringArray" setter="" getter="" default="PackedStringArray( &quot;gd&quot;, &quot;gdshader&quot; )">
Text-based file extensions to include in the script editor's "Find in Files" feature. You can add e.g. [code]tscn[/code] if you wish to also parse your scene files, especially if you use built-in scripts which are serialized in the scene files.
</member>
<member name="editor/script/templates_search_path" type="String" setter="" getter="" default="&quot;res://script_templates&quot;">
@@ -693,6 +703,8 @@
</member>
<member name="input/ui_text_completion_query" type="Dictionary" setter="" getter="">
</member>
+ <member name="input/ui_text_completion_replace" type="Dictionary" setter="" getter="">
+ </member>
<member name="input/ui_text_dedent" type="Dictionary" setter="" getter="">
</member>
<member name="input/ui_text_delete" type="Dictionary" setter="" getter="">
@@ -723,6 +735,12 @@
</member>
<member name="input/ui_text_select_all" type="Dictionary" setter="" getter="">
</member>
+ <member name="input/ui_text_select_word_under_caret" type="Dictionary" setter="" getter="">
+ If no selection is currently active, selects the word currently under the caret in text fields. If a selection is currently active, deselects the current selection.
+ [b]Note:[/b] Currently, this is only implemented in [TextEdit], not [LineEdit].
+ </member>
+ <member name="input/ui_text_submit" type="Dictionary" setter="" getter="">
+ </member>
<member name="input/ui_text_toggle_insert_mode" type="Dictionary" setter="" getter="">
</member>
<member name="input/ui_undo" type="Dictionary" setter="" getter="">
@@ -749,6 +767,11 @@
<member name="internationalization/locale/fallback" type="String" setter="" getter="" default="&quot;en&quot;">
The locale to fall back to if a translation isn't available in a given language. If left empty, [code]en[/code] (English) will be used.
</member>
+ <member name="internationalization/locale/include_text_server_data" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], text server break iteration rule sets, dictionaries and other optional data are included in the exported project.
+ [b]Note:[/b] "ICU / HarfBuzz / Graphite" text server data includes dictionaries for Burmese, Chinese, Japanese, Khmer, Lao and Thai as well as Unicode Standard Annex #29 and Unicode Standard Annex #14 word and line breaking rules. Data is about 4 MB large.
+ [b]Note:[/b] "Fallback" text server does not use additional data.
+ </member>
<member name="internationalization/locale/test" type="String" setter="" getter="" default="&quot;&quot;">
If non-empty, this locale will be used when running the project from the editor.
</member>
@@ -1118,8 +1141,6 @@
<member name="layer_names/3d_render/layer_9" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 3D render layer 9. If left empty, the layer will display as "Layer 9".
</member>
- <member name="memory/limits/command_queue/multithreading_queue_size_kb" type="int" setter="" getter="" default="256">
- </member>
<member name="memory/limits/message_queue/max_size_kb" type="int" setter="" getter="" default="4096">
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.
</member>
@@ -1183,27 +1204,21 @@
The CA certificates bundle to use for SSL connections. If this is set to a non-empty value, this will [i]override[/i] Godot's default [url=https://github.com/godotengine/godot/blob/master/thirdparty/certs/ca-certificates.crt]Mozilla certificate bundle[/url]. If left empty, the default certificate bundle will be used.
If in doubt, leave this setting empty.
</member>
- <member name="physics/2d/bp_hash_table_size" type="int" setter="" getter="" default="4096">
- Size of the hash table used for the broad-phase 2D hash grid algorithm.
- </member>
- <member name="physics/2d/cell_size" type="int" setter="" getter="" default="128">
- Cell size used for the broad-phase 2D hash grid algorithm (in pixels).
- </member>
<member name="physics/2d/default_angular_damp" type="float" setter="" getter="" default="1.0">
The default angular damp in 2D.
[b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_fps], [code]60[/code] by default) will bring the object to a stop in one iteration.
</member>
- <member name="physics/2d/default_gravity" type="int" setter="" getter="" default="98">
- The default gravity strength in 2D.
+ <member name="physics/2d/default_gravity" type="float" setter="" getter="" default="980.0">
+ The default gravity strength in 2D (in pixels per second squared).
[b]Note:[/b] This property is only read when the project starts. To change the default gravity at runtime, use the following code sample:
[codeblocks]
[gdscript]
- # Set the default gravity strength to 98.
- PhysicsServer2D.area_set_param(get_viewport().find_world_2d().space, PhysicsServer2D.AREA_PARAM_GRAVITY, 98)
+ # Set the default gravity strength to 980.
+ PhysicsServer2D.area_set_param(get_viewport().find_world_2d().space, PhysicsServer2D.AREA_PARAM_GRAVITY, 980)
[/gdscript]
[csharp]
- // Set the default gravity strength to 98.
- PhysicsServer2D.AreaSetParam(GetViewport().FindWorld2d().Space, PhysicsServer2D.AreaParameter.Gravity, 98);
+ // Set the default gravity strength to 980.
+ PhysicsServer2D.AreaSetParam(GetViewport().FindWorld2d().Space, PhysicsServer2D.AreaParameter.Gravity, 980);
[/csharp]
[/codeblocks]
</member>
@@ -1225,9 +1240,6 @@
The default linear damp in 2D.
[b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_fps], [code]60[/code] by default) will bring the object to a stop in one iteration.
</member>
- <member name="physics/2d/large_object_surface_threshold_in_cells" type="int" setter="" getter="" default="512">
- Threshold defining the surface size that constitutes a large object with regard to cells in the broad-phase 2D hash grid algorithm.
- </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 "GodotPhysics2D" are the same, as there is currently no alternative 2D physics server implemented.
@@ -1249,7 +1261,7 @@
[b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_fps], [code]60[/code] by default) will bring the object to a stop in one iteration.
</member>
<member name="physics/3d/default_gravity" type="float" setter="" getter="" default="9.8">
- The default gravity strength in 3D.
+ The default gravity strength in 3D (in meters per second squared).
[b]Note:[/b] This property is only read when the project starts. To change the default gravity at runtime, use the following code sample:
[codeblocks]
[gdscript]
@@ -1301,7 +1313,8 @@
[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.
</member>
<member name="physics/common/physics_jitter_fix" type="float" setter="" getter="" default="0.5">
- Fix to improve physics jitter, specially on monitors where refresh rate is different than the physics FPS.
+ Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows smoothing out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended.
+ [b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics/common/physics_jitter_fix] to [code]0[/code].
[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/2d/sdf/oversize" type="int" setter="" getter="" default="1">
@@ -1350,10 +1363,6 @@
[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/driver/rd_renderer/use_low_end_renderer" type="bool" setter="" getter="" default="false">
- </member>
- <member name="rendering/driver/rd_renderer/use_low_end_renderer.mobile" type="bool" setter="" getter="" default="true">
- </member>
<member name="rendering/driver/threads/thread_model" type="int" setter="" getter="" default="1">
Thread model for rendering. Rendering on a thread can vastly improve performance, but synchronizing to the main thread can cause a bit more jitter.
</member>
@@ -1413,18 +1422,16 @@
</member>
<member name="rendering/global_illumination/gi/use_half_resolution" type="bool" setter="" getter="" default="false">
</member>
- <member name="rendering/global_illumination/gi_probes/anisotropic" type="bool" setter="" getter="" default="false">
- If [code]true[/code], take additional samples when rendering objects affected by a [GIProbe] to reduce artifacts from only sampling in one direction.
- </member>
- <member name="rendering/global_illumination/gi_probes/quality" type="int" setter="" getter="" default="1">
- Sets the number of cone samples taken when rendering objects affected by [GIProbe]s.
- </member>
<member name="rendering/global_illumination/sdfgi/frames_to_converge" type="int" setter="" getter="" default="4">
</member>
<member name="rendering/global_illumination/sdfgi/frames_to_update_lights" type="int" setter="" getter="" default="2">
</member>
<member name="rendering/global_illumination/sdfgi/probe_ray_count" type="int" setter="" getter="" default="1">
</member>
+ <member name="rendering/global_illumination/voxel_gi/anisotropic" type="bool" setter="" getter="" default="false">
+ </member>
+ <member name="rendering/global_illumination/voxel_gi/quality" type="int" setter="" getter="" default="1">
+ </member>
<member name="rendering/lightmapping/bake_performance/max_rays_per_pass" type="int" setter="" getter="" default="32">
</member>
<member name="rendering/lightmapping/bake_performance/max_rays_per_probe_pass" type="int" setter="" getter="" default="64">
@@ -1463,6 +1470,12 @@
</member>
<member name="rendering/mesh_lod/lod_change/threshold_pixels" type="float" setter="" getter="" default="1.0">
</member>
+ <member name="rendering/occlusion_culling/bvh_build_quality" type="int" setter="" getter="" default="2">
+ </member>
+ <member name="rendering/occlusion_culling/occlusion_rays_per_thread" type="int" setter="" getter="" default="512">
+ </member>
+ <member name="rendering/occlusion_culling/use_occlusion_culling" type="bool" setter="" getter="" default="false">
+ </member>
<member name="rendering/reflections/reflection_atlas/reflection_count" type="int" setter="" getter="" default="64">
Number of cubemaps to store in the reflection atlas. The number of [ReflectionProbe]s in a scene will be limited by this amount. A higher number requires more VRAM.
</member>
@@ -1490,6 +1503,16 @@
<member name="rendering/reflections/sky_reflections/texture_array_reflections.mobile" type="bool" setter="" getter="" default="false">
Lower-end override for [member rendering/reflections/sky_reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support.
</member>
+ <member name="rendering/shader_compiler/shader_cache/compress" type="bool" setter="" getter="" default="true">
+ </member>
+ <member name="rendering/shader_compiler/shader_cache/enabled" type="bool" setter="" getter="" default="true">
+ </member>
+ <member name="rendering/shader_compiler/shader_cache/strip_debug" type="bool" setter="" getter="" default="false">
+ </member>
+ <member name="rendering/shader_compiler/shader_cache/strip_debug.release" type="bool" setter="" getter="" default="true">
+ </member>
+ <member name="rendering/shader_compiler/shader_cache/use_zstd_compression" type="bool" setter="" getter="" default="true">
+ </member>
<member name="rendering/shading/overrides/force_blinn_over_ggx" type="bool" setter="" getter="" default="false">
If [code]true[/code], uses faster but lower-quality Blinn model to generate blurred reflections instead of the GGX model.
</member>
@@ -1554,31 +1577,46 @@
<member name="rendering/textures/default_filters/use_nearest_mipmap_filter" type="bool" setter="" getter="" default="false">
If [code]true[/code], uses nearest-neighbor mipmap filtering when using mipmaps (also called "bilinear filtering"), which will result in visible seams appearing between mipmap stages. This may increase performance in mobile as less memory bandwidth is used. If [code]false[/code], linear mipmap filtering (also called "trilinear filtering") is used.
</member>
+ <member name="rendering/textures/lossless_compression/force_png" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], the texture importer will import lossless textures using the PNG format. Otherwise, it will default to using WebP.
+ </member>
+ <member name="rendering/textures/lossless_compression/webp_compression_level" type="int" setter="" getter="" default="2">
+ The default compression level for lossless WebP. Higher levels result in smaller files at the cost of compression speed. Decompression speed is mostly unaffected by the compression level. Supported values are 0 to 9. Note that compression levels above 6 are very slow and offer very little savings.
+ </member>
<member name="rendering/textures/vram_compression/import_bptc" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the BPTC algorithm. This texture compression algorithm is only supported on desktop platforms, and only when using the Vulkan renderer.
+ [b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor.
</member>
<member name="rendering/textures/vram_compression/import_etc" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the Ericsson Texture Compression algorithm. This algorithm doesn't support alpha channels in textures.
+ [b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor.
</member>
<member name="rendering/textures/vram_compression/import_etc2" type="bool" setter="" getter="" default="true">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the Ericsson Texture Compression 2 algorithm. This texture compression algorithm is only supported when using the Vulkan renderer.
+ [b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor.
</member>
<member name="rendering/textures/vram_compression/import_pvrtc" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the PowerVR Texture Compression algorithm. This texture compression algorithm is only supported on iOS.
+ [b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor.
</member>
<member name="rendering/textures/vram_compression/import_s3tc" type="bool" setter="" getter="" default="true">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the S3 Texture Compression algorithm. This algorithm is only supported on desktop platforms and consoles.
+ [b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor.
</member>
<member name="rendering/vulkan/descriptor_pools/max_descriptors_per_pool" type="int" setter="" getter="" default="64">
</member>
+ <member name="rendering/vulkan/rendering/back_end" type="int" setter="" getter="" default="0">
+ </member>
+ <member name="rendering/vulkan/rendering/back_end.mobile" type="int" setter="" getter="" default="1">
+ </member>
<member name="rendering/vulkan/staging_buffer/block_size_kb" type="int" setter="" getter="" default="256">
</member>
<member name="rendering/vulkan/staging_buffer/max_size_mb" type="int" setter="" getter="" default="128">
</member>
<member name="rendering/vulkan/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64">
</member>
- <member name="world/2d/cell_size" type="int" setter="" getter="" default="100">
- Cell size used for the 2D hash grid that [VisibilityNotifier2D] uses (in pixels).
+ <member name="rendering/xr/enabled" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], XR support is enabled in Godot, this ensures required shaders are compiled.
</member>
</members>
<constants>
diff --git a/doc/classes/Quat.xml b/doc/classes/Quaternion.xml
index 1c0a3e37c0..678fb0d44d 100644
--- a/doc/classes/Quat.xml
+++ b/doc/classes/Quaternion.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Quat" version="4.0">
+<class name="Quaternion" version="4.0">
<brief_description>
Quaternion.
</brief_description>
<description>
A unit quaternion used for representing 3D rotations. Quaternions need to be normalized to be used for rotation.
- It is similar to Basis, which implements matrix representation of rotations, and can be parametrized using both an axis-angle pair or Euler angles. Basis stores rotation, scale, and shearing, while Quat only stores rotation.
+ It is similar to Basis, which implements matrix representation of rotations, and can be parametrized using both an axis-angle pair or Euler angles. Basis stores rotation, scale, and shearing, while Quaternion only stores rotation.
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.
</description>
<tutorials>
@@ -13,24 +13,24 @@
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
</tutorials>
<methods>
- <method name="Quat" qualifiers="constructor">
- <return type="Quat">
+ <method name="Quaternion" qualifiers="constructor">
+ <return type="Quaternion">
</return>
<description>
Constructs a default-initialized quaternion with all components set to [code]0[/code].
</description>
</method>
- <method name="Quat" qualifiers="constructor">
- <return type="Quat">
+ <method name="Quaternion" qualifiers="constructor">
+ <return type="Quaternion">
</return>
- <argument index="0" name="from" type="Quat">
+ <argument index="0" name="from" type="Quaternion">
</argument>
<description>
- Constructs a [Quat] as a copy of the given [Quat].
+ Constructs a [Quaternion] as a copy of the given [Quaternion].
</description>
</method>
- <method name="Quat" qualifiers="constructor">
- <return type="Quat">
+ <method name="Quaternion" qualifiers="constructor">
+ <return type="Quaternion">
</return>
<argument index="0" name="arc_from" type="Vector3">
</argument>
@@ -39,8 +39,8 @@
<description>
</description>
</method>
- <method name="Quat" qualifiers="constructor">
- <return type="Quat">
+ <method name="Quaternion" qualifiers="constructor">
+ <return type="Quaternion">
</return>
<argument index="0" name="axis" type="Vector3">
</argument>
@@ -50,8 +50,8 @@
Constructs a quaternion that will rotate around the given axis by the specified angle. The axis must be a normalized vector.
</description>
</method>
- <method name="Quat" qualifiers="constructor">
- <return type="Quat">
+ <method name="Quaternion" qualifiers="constructor">
+ <return type="Quaternion">
</return>
<argument index="0" name="euler" type="Vector3">
</argument>
@@ -59,8 +59,8 @@
Constructs a quaternion that will perform a rotation specified by Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last), given in the vector format as (X angle, Y angle, Z angle).
</description>
</method>
- <method name="Quat" qualifiers="constructor">
- <return type="Quat">
+ <method name="Quaternion" qualifiers="constructor">
+ <return type="Quaternion">
</return>
<argument index="0" name="from" type="Basis">
</argument>
@@ -68,8 +68,8 @@
Constructs a quaternion from the given [Basis].
</description>
</method>
- <method name="Quat" qualifiers="constructor">
- <return type="Quat">
+ <method name="Quaternion" qualifiers="constructor">
+ <return type="Quaternion">
</return>
<argument index="0" name="x" type="float">
</argument>
@@ -84,13 +84,13 @@
</description>
</method>
<method name="cubic_slerp" qualifiers="const">
- <return type="Quat">
+ <return type="Quaternion">
</return>
- <argument index="0" name="b" type="Quat">
+ <argument index="0" name="b" type="Quaternion">
</argument>
- <argument index="1" name="pre_a" type="Quat">
+ <argument index="1" name="pre_a" type="Quaternion">
</argument>
- <argument index="2" name="post_b" type="Quat">
+ <argument index="2" name="post_b" type="Quaternion">
</argument>
<argument index="3" name="weight" type="float">
</argument>
@@ -101,7 +101,7 @@
<method name="dot" qualifiers="const">
<return type="float">
</return>
- <argument index="0" name="with" type="Quat">
+ <argument index="0" name="with" type="Quaternion">
</argument>
<description>
Returns the dot product of two quaternions.
@@ -115,7 +115,7 @@
</description>
</method>
<method name="inverse" qualifiers="const">
- <return type="Quat">
+ <return type="Quaternion">
</return>
<description>
Returns the inverse of the quaternion.
@@ -124,7 +124,7 @@
<method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="to" type="Quat">
+ <argument index="0" name="to" type="Quaternion">
</argument>
<description>
Returns [code]true[/code] if this quaternion and [code]quat[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
@@ -152,7 +152,7 @@
</description>
</method>
<method name="normalized" qualifiers="const">
- <return type="Quat">
+ <return type="Quaternion">
</return>
<description>
Returns a copy of the quaternion, normalized to unit length.
@@ -161,15 +161,15 @@
<method name="operator !=" qualifiers="operator">
<return type="bool">
</return>
- <argument index="0" name="right" type="Quat">
+ <argument index="0" name="right" type="Quaternion">
</argument>
<description>
</description>
</method>
<method name="operator *" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
- <argument index="0" name="right" type="Quat">
+ <argument index="0" name="right" type="Quaternion">
</argument>
<description>
</description>
@@ -183,7 +183,7 @@
</description>
</method>
<method name="operator *" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
<argument index="0" name="right" type="float">
</argument>
@@ -191,7 +191,7 @@
</description>
</method>
<method name="operator *" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
<argument index="0" name="right" type="int">
</argument>
@@ -199,35 +199,35 @@
</description>
</method>
<method name="operator +" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
<description>
</description>
</method>
<method name="operator +" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
- <argument index="0" name="right" type="Quat">
+ <argument index="0" name="right" type="Quaternion">
</argument>
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
<description>
</description>
</method>
<method name="operator -" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
- <argument index="0" name="right" type="Quat">
+ <argument index="0" name="right" type="Quaternion">
</argument>
<description>
</description>
</method>
<method name="operator /" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
<argument index="0" name="right" type="float">
</argument>
@@ -235,7 +235,7 @@
</description>
</method>
<method name="operator /" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
<argument index="0" name="right" type="int">
</argument>
@@ -245,7 +245,7 @@
<method name="operator ==" qualifiers="operator">
<return type="bool">
</return>
- <argument index="0" name="right" type="Quat">
+ <argument index="0" name="right" type="Quaternion">
</argument>
<description>
</description>
@@ -259,9 +259,9 @@
</description>
</method>
<method name="slerp" qualifiers="const">
- <return type="Quat">
+ <return type="Quaternion">
</return>
- <argument index="0" name="to" type="Quat">
+ <argument index="0" name="to" type="Quaternion">
</argument>
<argument index="1" name="weight" type="float">
</argument>
@@ -271,9 +271,9 @@
</description>
</method>
<method name="slerpni" qualifiers="const">
- <return type="Quat">
+ <return type="Quaternion">
</return>
- <argument index="0" name="to" type="Quat">
+ <argument index="0" name="to" type="Quaternion">
</argument>
<argument index="1" name="weight" type="float">
</argument>
@@ -301,7 +301,7 @@
</member>
</members>
<constants>
- <constant name="IDENTITY" value="Quat( 0, 0, 0, 1 )">
+ <constant name="IDENTITY" value="Quaternion( 0, 0, 0, 1 )">
The identity quaternion, representing no rotation. Equivalent to an identity [Basis] matrix. If a vector is transformed by an identity quaternion, it will not change.
</constant>
</constants>
diff --git a/doc/classes/RDAttachmentFormat.xml b/doc/classes/RDAttachmentFormat.xml
index 4ee7b9b28e..b73377bf77 100644
--- a/doc/classes/RDAttachmentFormat.xml
+++ b/doc/classes/RDAttachmentFormat.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDAttachmentFormat" inherits="Reference" version="4.0">
+<class name="RDAttachmentFormat" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDPipelineColorBlendState.xml b/doc/classes/RDPipelineColorBlendState.xml
index adc6f1f6a3..1424a0d653 100644
--- a/doc/classes/RDPipelineColorBlendState.xml
+++ b/doc/classes/RDPipelineColorBlendState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineColorBlendState" inherits="Reference" version="4.0">
+<class name="RDPipelineColorBlendState" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDPipelineColorBlendStateAttachment.xml b/doc/classes/RDPipelineColorBlendStateAttachment.xml
index 7f118b5f0b..a6a1900cb5 100644
--- a/doc/classes/RDPipelineColorBlendStateAttachment.xml
+++ b/doc/classes/RDPipelineColorBlendStateAttachment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineColorBlendStateAttachment" inherits="Reference" version="4.0">
+<class name="RDPipelineColorBlendStateAttachment" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDPipelineDepthStencilState.xml b/doc/classes/RDPipelineDepthStencilState.xml
index 562ff52819..76e0506bca 100644
--- a/doc/classes/RDPipelineDepthStencilState.xml
+++ b/doc/classes/RDPipelineDepthStencilState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineDepthStencilState" inherits="Reference" version="4.0">
+<class name="RDPipelineDepthStencilState" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDPipelineMultisampleState.xml b/doc/classes/RDPipelineMultisampleState.xml
index 4658c7d9ba..8c90f02301 100644
--- a/doc/classes/RDPipelineMultisampleState.xml
+++ b/doc/classes/RDPipelineMultisampleState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineMultisampleState" inherits="Reference" version="4.0">
+<class name="RDPipelineMultisampleState" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDPipelineRasterizationState.xml b/doc/classes/RDPipelineRasterizationState.xml
index 5064dd6deb..3f8c50cf42 100644
--- a/doc/classes/RDPipelineRasterizationState.xml
+++ b/doc/classes/RDPipelineRasterizationState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDPipelineRasterizationState" inherits="Reference" version="4.0">
+<class name="RDPipelineRasterizationState" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDSamplerState.xml b/doc/classes/RDSamplerState.xml
index ab31960b7c..9a9d55948c 100644
--- a/doc/classes/RDSamplerState.xml
+++ b/doc/classes/RDSamplerState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDSamplerState" inherits="Reference" version="4.0">
+<class name="RDSamplerState" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDShaderFile.xml b/doc/classes/RDShaderFile.xml
index 14e70d53ea..346a97a1c0 100644
--- a/doc/classes/RDShaderFile.xml
+++ b/doc/classes/RDShaderFile.xml
@@ -10,7 +10,7 @@
<method name="get_bytecode" qualifiers="const">
<return type="RDShaderBytecode">
</return>
- <argument index="0" name="version" type="StringName" default="@&quot;&quot;">
+ <argument index="0" name="version" type="StringName" default="&amp;&quot;&quot;">
</argument>
<description>
</description>
@@ -26,7 +26,7 @@
</return>
<argument index="0" name="bytecode" type="RDShaderBytecode">
</argument>
- <argument index="1" name="version" type="StringName" default="@&quot;&quot;">
+ <argument index="1" name="version" type="StringName" default="&amp;&quot;&quot;">
</argument>
<description>
</description>
diff --git a/doc/classes/RDShaderSource.xml b/doc/classes/RDShaderSource.xml
index c1cfd34bb7..68fc43d8ef 100644
--- a/doc/classes/RDShaderSource.xml
+++ b/doc/classes/RDShaderSource.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDShaderSource" inherits="Reference" version="4.0">
+<class name="RDShaderSource" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDTextureFormat.xml b/doc/classes/RDTextureFormat.xml
index e41ddff368..ccfa6d1b95 100644
--- a/doc/classes/RDTextureFormat.xml
+++ b/doc/classes/RDTextureFormat.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDTextureFormat" inherits="Reference" version="4.0">
+<class name="RDTextureFormat" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDTextureView.xml b/doc/classes/RDTextureView.xml
index 73b2a7ae4a..db140ae775 100644
--- a/doc/classes/RDTextureView.xml
+++ b/doc/classes/RDTextureView.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDTextureView" inherits="Reference" version="4.0">
+<class name="RDTextureView" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDUniform.xml b/doc/classes/RDUniform.xml
index bc8a21e985..666935d663 100644
--- a/doc/classes/RDUniform.xml
+++ b/doc/classes/RDUniform.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDUniform" inherits="Reference" version="4.0">
+<class name="RDUniform" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RDVertexAttribute.xml b/doc/classes/RDVertexAttribute.xml
index 56fe40b51d..3499918cc8 100644
--- a/doc/classes/RDVertexAttribute.xml
+++ b/doc/classes/RDVertexAttribute.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RDVertexAttribute" inherits="Reference" version="4.0">
+<class name="RDVertexAttribute" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/RandomNumberGenerator.xml b/doc/classes/RandomNumberGenerator.xml
index 6312cd18aa..6fcb79b5fe 100644
--- a/doc/classes/RandomNumberGenerator.xml
+++ b/doc/classes/RandomNumberGenerator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RandomNumberGenerator" inherits="Reference" version="4.0">
+<class name="RandomNumberGenerator" inherits="RefCounted" version="4.0">
<brief_description>
A class for generating pseudo-random numbers.
</brief_description>
diff --git a/doc/classes/Reference.xml b/doc/classes/RefCounted.xml
index 724d2db924..cf96514203 100644
--- a/doc/classes/Reference.xml
+++ b/doc/classes/RefCounted.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Reference" inherits="Object" version="4.0">
+<class name="RefCounted" inherits="Object" version="4.0">
<brief_description>
Base class for reference-counted objects.
</brief_description>
<description>
Base class for any object that keeps a reference count. [Resource] and many other helper objects inherit this class.
Unlike other [Object] types, 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].
- 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.
+ In the vast majority of use cases, instantiating and using [RefCounted]-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.
[b]Note:[/b] In C#, references will not be freed instantly after they are no longer in use. Instead, garbage collection will run periodically and will free references that are no longer in use. This means that unused references will linger on for a while before being removed.
</description>
<tutorials>
diff --git a/doc/classes/ReflectionProbe.xml b/doc/classes/ReflectionProbe.xml
index cd08778c89..13df17cd22 100644
--- a/doc/classes/ReflectionProbe.xml
+++ b/doc/classes/ReflectionProbe.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Captures its surroundings as a cubemap, and stores versions of it with increasing levels of blur to simulate different material roughnesses.
- 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.
+ The [ReflectionProbe] is used to create high-quality reflections at the cost of performance. It can be combined with [VoxelGI]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.
</description>
<tutorials>
<link title="Reflection probes">https://docs.godotengine.org/en/latest/tutorials/3d/reflection_probes.html</link>
diff --git a/doc/classes/RemoteTransform3D.xml b/doc/classes/RemoteTransform3D.xml
index bd3da2aea9..453177496f 100644
--- a/doc/classes/RemoteTransform3D.xml
+++ b/doc/classes/RemoteTransform3D.xml
@@ -1,10 +1,10 @@
<?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.
+ RemoteTransform3D pushes its own [Transform3D] 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.
+ RemoteTransform3D pushes its own [Transform3D] 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>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index d6eaa1b88b..300108ff77 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -130,10 +130,10 @@
</return>
<argument index="0" name="camera" type="RID">
</argument>
- <argument index="1" name="transform" type="Transform">
+ <argument index="1" name="transform" type="Transform3D">
</argument>
<description>
- Sets [Transform] of camera.
+ Sets [Transform3D] of camera.
</description>
</method>
<method name="camera_set_use_vertical_aspect">
@@ -1175,17 +1175,6 @@
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>
@@ -1197,45 +1186,45 @@
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">
+ <method name="instance_geometry_set_flag">
<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 index="1" name="flag" type="int" enum="RenderingServer.InstanceFlags">
</argument>
- <argument index="4" name="max_margin" type="float">
+ <argument index="2" name="enabled" type="bool">
</argument>
<description>
- Not implemented in Godot 3.x.
+ Sets the flag for a given [enum InstanceFlags]. See [enum InstanceFlags] for more details.
</description>
</method>
- <method name="instance_geometry_set_flag">
+ <method name="instance_geometry_set_material_override">
<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 index="1" name="material" type="RID">
</argument>
<description>
- Sets the flag for a given [enum InstanceFlags]. See [enum InstanceFlags] for more details.
+ 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_geometry_set_material_override">
+ <method name="instance_geometry_set_visibility_range">
<return type="void">
</return>
<argument index="0" name="instance" type="RID">
</argument>
- <argument index="1" name="material" type="RID">
+ <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>
- Sets a material that will override the material for all surfaces on the mesh associated with this instance. Equivalent to [member GeometryInstance3D.material_override].
+ Sets the visibility range values for the given geometry instance. Equivalent to [member GeometryInstance3D.visibility_range_begin] and related properties.
</description>
</method>
<method name="instance_set_base">
@@ -1335,12 +1324,23 @@
</return>
<argument index="0" name="instance" type="RID">
</argument>
- <argument index="1" name="transform" type="Transform">
+ <argument index="1" name="transform" type="Transform3D">
</argument>
<description>
Sets the world space transform of the instance. Equivalent to [member Node3D.transform].
</description>
</method>
+ <method name="instance_set_visibility_parent">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="parent" type="RID">
+ </argument>
+ <description>
+ Sets the visibility parent for the given instance. Equivalent to [member Node3D.visibility_parent].
+ </description>
+ </method>
<method name="instance_set_visible">
<return type="void">
</return>
@@ -1894,14 +1894,14 @@
</description>
</method>
<method name="multimesh_instance_get_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</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.
+ Returns the [Transform3D] of the specified instance.
</description>
</method>
<method name="multimesh_instance_get_transform_2d" qualifiers="const">
@@ -1948,10 +1948,10 @@
</argument>
<argument index="1" name="index" type="int">
</argument>
- <argument index="2" name="transform" type="Transform">
+ <argument index="2" name="transform" type="Transform3D">
</argument>
<description>
- Sets the [Transform] for this instance. Equivalent to [method MultiMesh.set_instance_transform].
+ Sets the [Transform3D] for this instance. Equivalent to [method MultiMesh.set_instance_transform].
</description>
</method>
<method name="multimesh_instance_set_transform_2d">
@@ -1999,6 +1999,24 @@
Sets the number of instances visible at a given time. If -1, all instances that have been allocated are drawn. Equivalent to [member MultiMesh.visible_instance_count].
</description>
</method>
+ <method name="occluder_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="occluder_set_mesh">
+ <return type="void">
+ </return>
+ <argument index="0" name="arg0" type="RID">
+ </argument>
+ <argument index="1" name="arg1" type="PackedVector3Array">
+ </argument>
+ <argument index="2" name="arg2" type="PackedInt32Array">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="omni_light_create">
<return type="RID">
</return>
@@ -2124,10 +2142,10 @@
</return>
<argument index="0" name="particles" type="RID">
</argument>
- <argument index="1" name="transform" type="Transform">
+ <argument index="1" name="transform" type="Transform3D">
</argument>
<description>
- Sets the [Transform] that will be used by the particles when they first emit.
+ Sets the [Transform3D] that will be used by the particles when they first emit.
</description>
</method>
<method name="particles_set_emitting">
@@ -2412,6 +2430,16 @@
The scenario is the 3D world that all the visual instances exist in.
</description>
</method>
+ <method name="scenario_set_camera_effects">
+ <return type="void">
+ </return>
+ <argument index="0" name="scenario" type="RID">
+ </argument>
+ <argument index="1" name="effects" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="scenario_set_debug">
<return type="void">
</return>
@@ -2562,14 +2590,14 @@
</description>
</method>
<method name="skeleton_bone_get_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</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.
+ Returns the [Transform3D] set for a specific bone of this skeleton.
</description>
</method>
<method name="skeleton_bone_get_transform_2d" qualifiers="const">
@@ -2590,10 +2618,10 @@
</argument>
<argument index="1" name="bone" type="int">
</argument>
- <argument index="2" name="transform" type="Transform">
+ <argument index="2" name="transform" type="Transform3D">
</argument>
<description>
- Sets the [Transform] for a specific bone of this skeleton.
+ Sets the [Transform3D] for a specific bone of this skeleton.
</description>
</method>
<method name="skeleton_bone_set_transform_2d">
@@ -2897,6 +2925,22 @@
Sets the anti-aliasing mode. See [enum ViewportMSAA] for options.
</description>
</method>
+ <method name="viewport_set_occlusion_culling_build_quality">
+ <return type="void">
+ </return>
+ <argument index="0" name="quality" type="int" enum="RenderingServer.ViewportOcclusionCullingBuildQuality">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="viewport_set_occlusion_rays_per_thread">
+ <return type="void">
+ </return>
+ <argument index="0" name="rays_per_thread" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="viewport_set_parent_viewport">
<return type="void">
</return>
@@ -3002,6 +3046,16 @@
<description>
</description>
</method>
+ <method name="viewport_set_use_occlusion_culling">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="viewport_set_use_xr">
<return type="void">
</return>
@@ -3213,7 +3267,7 @@
Use [Transform2D] to store MultiMesh transform.
</constant>
<constant name="MULTIMESH_TRANSFORM_3D" value="1" enum="MultimeshTransformFormat">
- Use [Transform] to store MultiMesh transform.
+ Use [Transform3D] to store MultiMesh transform.
</constant>
<constant name="LIGHT_DIRECTIONAL" value="0" enum="LightType">
Is a directional (sun) light.
@@ -3334,7 +3388,7 @@
<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">
+ <constant name="PARTICLES_DRAW_ORDER_VIEW_DEPTH" value="3" enum="ParticlesDrawOrder">
Sort particles based on their distance to the camera.
</constant>
<constant name="VIEWPORT_UPDATE_DISABLED" value="0" enum="ViewportUpdateMode">
@@ -3423,14 +3477,14 @@
<constant name="VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="ViewportDebugDraw">
Normal buffer is drawn instead of regular scene so you can see the per-pixel normals that will be used by post-processing effects.
</constant>
- <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO" value="6" enum="ViewportDebugDraw">
- Objects are displayed with only the albedo value from [GIProbe]s.
+ <constant name="VIEWPORT_DEBUG_DRAW_VOXEL_GI_ALBEDO" value="6" enum="ViewportDebugDraw">
+ Objects are displayed with only the albedo value from [VoxelGI]s.
</constant>
- <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING" value="7" enum="ViewportDebugDraw">
- Objects are displayed with only the lighting value from [GIProbe]s.
+ <constant name="VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING" value="7" enum="ViewportDebugDraw">
+ Objects are displayed with only the lighting value from [VoxelGI]s.
</constant>
- <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION" value="8" enum="ViewportDebugDraw">
- Objects are displayed with only the emission color from [GIProbe]s.
+ <constant name="VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION" value="8" enum="ViewportDebugDraw">
+ Objects are displayed with only the emission color from [VoxelGI]s.
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS" value="9" enum="ViewportDebugDraw">
Draws the shadow atlas that stores shadows from [OmniLight3D]s and [SpotLight3D]s in the upper left quadrant of the [Viewport].
@@ -3454,6 +3508,8 @@
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_GI_BUFFER" value="17" enum="ViewportDebugDraw">
</constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_OCCLUDERS" value="23" enum="ViewportDebugDraw">
+ </constant>
<constant name="SKY_MODE_QUALITY" value="1" enum="SkyMode">
Uses high quality importance sampling to process the radiance map. In general, this results in much higher quality than [constant Sky.PROCESS_MODE_REALTIME] but takes much longer to generate. This should not be used if you plan on changing the sky at runtime. If you are finding that the reflection is not blurry enough and is showing sparkles or fireflies, try increasing [member ProjectSettings.rendering/reflections/sky_reflections/ggx_samples].
</constant>
@@ -3606,6 +3662,12 @@
<constant name="SCENARIO_DEBUG_SHADELESS" value="3" enum="ScenarioDebugMode">
Draw all objects without shading. Equivalent to setting all objects shaders to [code]unshaded[/code].
</constant>
+ <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW" value="0" enum="ViewportOcclusionCullingBuildQuality">
+ </constant>
+ <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM" value="1" enum="ViewportOcclusionCullingBuildQuality">
+ </constant>
+ <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH" value="2" enum="ViewportOcclusionCullingBuildQuality">
+ </constant>
<constant name="INSTANCE_NONE" value="0" enum="InstanceType">
The instance does not have a type.
</constant>
@@ -3632,13 +3694,15 @@
<constant name="INSTANCE_DECAL" value="8" enum="InstanceType">
The instance is a decal.
</constant>
- <constant name="INSTANCE_GI_PROBE" value="9" enum="InstanceType">
- The instance is a GI probe.
+ <constant name="INSTANCE_VOXEL_GI" value="9" enum="InstanceType">
+ The instance is a VoxelGI.
</constant>
<constant name="INSTANCE_LIGHTMAP" value="10" enum="InstanceType">
The instance is a lightmap.
</constant>
- <constant name="INSTANCE_MAX" value="11" enum="InstanceType">
+ <constant name="INSTANCE_OCCLUDER" value="11" enum="InstanceType">
+ </constant>
+ <constant name="INSTANCE_MAX" value="13" enum="InstanceType">
Represents the size of the [enum InstanceType] enum.
</constant>
<constant name="INSTANCE_GEOMETRY_MASK" value="30" enum="InstanceType">
@@ -3653,7 +3717,9 @@
<constant name="INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE" value="2" enum="InstanceFlags">
When set, manually requests to draw geometry on next frame.
</constant>
- <constant name="INSTANCE_FLAG_MAX" value="3" enum="InstanceFlags">
+ <constant name="INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING" value="3" enum="InstanceFlags">
+ </constant>
+ <constant name="INSTANCE_FLAG_MAX" value="4" enum="InstanceFlags">
Represents the size of the [enum InstanceFlags] enum.
</constant>
<constant name="SHADOW_CASTING_SETTING_OFF" value="0" enum="ShadowCastingSetting">
diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml
index 2548f8d911..6edb3b1a11 100644
--- a/doc/classes/Resource.xml
+++ b/doc/classes/Resource.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Resource" inherits="Reference" version="4.0">
+<class name="Resource" inherits="RefCounted" version="4.0">
<brief_description>
Base class for all resources.
</brief_description>
<description>
- Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Since they inherit from [Reference], resources 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.
+ Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Since they inherit from [RefCounted], resources 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.
[b]Note:[/b] In C#, resources will not be freed instantly after they are no longer in use. Instead, garbage collection will run periodically and will free resources that are no longer in use. This means that unused resources will linger on for a while before being removed.
</description>
<tutorials>
@@ -27,6 +27,7 @@
<description>
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 which will copy the subresources.
[b]Note:[/b] If [code]subresources[/code] is [code]true[/code], this method will only perform a shallow copy. Nested resources within subresources will not be duplicated and will still be shared.
+ [b]Note:[/b] When duplicating a resource, only [code]export[/code]ed properties are copied. Other properties will be set to their default value in the new resource.
</description>
</method>
<method name="emit_changed">
diff --git a/doc/classes/ResourceFormatLoader.xml b/doc/classes/ResourceFormatLoader.xml
index 9943f644cf..6abe5c813b 100644
--- a/doc/classes/ResourceFormatLoader.xml
+++ b/doc/classes/ResourceFormatLoader.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceFormatLoader" inherits="Reference" version="4.0">
+<class name="ResourceFormatLoader" inherits="RefCounted" version="4.0">
<brief_description>
Loads a specific resource type from a file.
</brief_description>
@@ -11,7 +11,7 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_dependencies" qualifiers="virtual">
+ <method name="_get_dependencies" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="path" type="String">
@@ -23,14 +23,14 @@
[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.
</description>
</method>
- <method name="get_recognized_extensions" qualifiers="virtual">
+ <method name="_get_recognized_extensions" qualifiers="virtual">
<return type="PackedStringArray">
</return>
<description>
Gets the list of extensions for files this loader is able to read.
</description>
</method>
- <method name="get_resource_type" qualifiers="virtual">
+ <method name="_get_resource_type" qualifiers="virtual">
<return type="String">
</return>
<argument index="0" name="path" type="String">
@@ -40,7 +40,7 @@
[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.
</description>
</method>
- <method name="handles_type" qualifiers="virtual">
+ <method name="_handles_type" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="typename" type="StringName">
@@ -50,7 +50,7 @@
[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.
</description>
</method>
- <method name="load" qualifiers="virtual">
+ <method name="_load" qualifiers="virtual">
<return type="Variant">
</return>
<argument index="0" name="path" type="String">
@@ -66,7 +66,7 @@
The [code]cache_mode[/code] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details.
</description>
</method>
- <method name="rename_dependencies" qualifiers="virtual">
+ <method name="_rename_dependencies" qualifiers="virtual">
<return type="int">
</return>
<argument index="0" name="path" type="String">
diff --git a/doc/classes/ResourceFormatSaver.xml b/doc/classes/ResourceFormatSaver.xml
index 69f8b43898..df71e05d02 100644
--- a/doc/classes/ResourceFormatSaver.xml
+++ b/doc/classes/ResourceFormatSaver.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceFormatSaver" inherits="Reference" version="4.0">
+<class name="ResourceFormatSaver" inherits="RefCounted" version="4.0">
<brief_description>
Saves a specific resource type to a file.
</brief_description>
@@ -10,16 +10,16 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_recognized_extensions" qualifiers="virtual">
+ <method name="_get_recognized_extensions" qualifiers="virtual">
<return type="PackedStringArray">
</return>
<argument index="0" name="resource" type="Resource">
</argument>
<description>
- Returns the list of extensions available for saving the resource object, provided it is recognized (see [method recognize]).
+ Returns the list of extensions available for saving the resource object, provided it is recognized (see [method _recognize]).
</description>
</method>
- <method name="recognize" qualifiers="virtual">
+ <method name="_recognize" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="resource" type="Resource">
@@ -28,7 +28,7 @@
Returns whether the given resource object can be saved by this saver.
</description>
</method>
- <method name="save" qualifiers="virtual">
+ <method name="_save" qualifiers="virtual">
<return type="int">
</return>
<argument index="0" name="path" type="String">
diff --git a/doc/classes/ResourceImporter.xml b/doc/classes/ResourceImporter.xml
index 0475d2c94d..59900b1b73 100644
--- a/doc/classes/ResourceImporter.xml
+++ b/doc/classes/ResourceImporter.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceImporter" inherits="Reference" version="4.0">
+<class name="ResourceImporter" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml
index ecde5754f9..437b0ce730 100644
--- a/doc/classes/ResourceSaver.xml
+++ b/doc/classes/ResourceSaver.xml
@@ -49,7 +49,7 @@
Do not save editor-specific metadata (identified by their [code]__editor[/code] prefix).
</constant>
<constant name="FLAG_SAVE_BIG_ENDIAN" value="16" enum="SaverFlags">
- Save as big endian (see [member File.endian_swap]).
+ Save as big endian (see [member File.big_endian]).
</constant>
<constant name="FLAG_COMPRESS" value="32" enum="SaverFlags">
Compress the resource on save using [constant File.COMPRESSION_ZSTD]. Only available for binary resource types.
diff --git a/doc/classes/RibbonTrailMesh.xml b/doc/classes/RibbonTrailMesh.xml
new file mode 100644
index 0000000000..771f2e444b
--- /dev/null
+++ b/doc/classes/RibbonTrailMesh.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RibbonTrailMesh" inherits="PrimitiveMesh" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="curve" type="Curve" setter="set_curve" getter="get_curve">
+ </member>
+ <member name="section_length" type="float" setter="set_section_length" getter="get_section_length" default="0.2">
+ </member>
+ <member name="section_segments" type="int" setter="set_section_segments" getter="get_section_segments" default="3">
+ </member>
+ <member name="sections" type="int" setter="set_sections" getter="get_sections" default="5">
+ </member>
+ <member name="shape" type="int" setter="set_shape" getter="get_shape" enum="RibbonTrailMesh.Shape" default="1">
+ </member>
+ <member name="size" type="float" setter="set_size" getter="get_size" default="1.0">
+ </member>
+ </members>
+ <constants>
+ <constant name="SHAPE_FLAT" value="0" enum="Shape">
+ </constant>
+ <constant name="SHAPE_CROSS" value="1" enum="Shape">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml
index ed375a8b1e..237317daf1 100644
--- a/doc/classes/RigidBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
This node implements simulated 2D physics. You do not control a RigidBody2D directly. Instead, you apply forces to it (gravity, impulses, etc.) and the physics simulation calculates the resulting movement based on its mass, friction, and other physical properties.
- A RigidBody2D has 4 behavior [member mode]s: Rigid, Static, Character, and Kinematic.
+ A RigidBody2D has 4 behavior [member mode]s: Dynamic, Static, DynamicLocked, and Kinematic.
[b]Note:[/b] You should not change a RigidBody2D's [code]position[/code] or [code]linear_velocity[/code] every frame or even very often. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state.
Please also keep in mind that physics bodies manage their own transform which overwrites the ones you set. So any direct or indirect transformation (including scaling of the node or its parent) will be visible in the editor only, and immediately reset at runtime.
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].
@@ -100,21 +100,6 @@
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.
</description>
</method>
- <method name="test_motion">
- <return type="bool">
- </return>
- <argument index="0" name="motion" type="Vector2">
- </argument>
- <argument index="1" name="infinite_inertia" type="bool" default="true">
- </argument>
- <argument index="2" name="margin" type="float" default="0.08">
- </argument>
- <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 [PhysicsTestMotionResult2D], which contains additional information about the collision (should there be one).
- </description>
- </method>
</methods>
<members>
<member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="-1.0">
@@ -132,7 +117,6 @@
</member>
<member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true">
If [code]true[/code], the body can enter sleep mode when there is no movement. See [member sleeping].
- [b]Note:[/b] A RigidBody2D will never enter sleep mode automatically if its [member mode] is [constant MODE_CHARACTER]. It can still be put to sleep manually by setting its [member sleeping] property to [code]true[/code].
</member>
<member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false">
If [code]true[/code], the body will emit signals when it collides with another RigidBody2D. See also [member contacts_reported].
@@ -193,7 +177,7 @@
</description>
</signal>
<signal name="body_shape_entered">
- <argument index="0" name="body_id" type="int">
+ <argument index="0" name="body_rid" type="RID">
</argument>
<argument index="1" name="body" type="Node">
</argument>
@@ -210,7 +194,7 @@
</description>
</signal>
<signal name="body_shape_exited">
- <argument index="0" name="body_id" type="int">
+ <argument index="0" name="body_rid" type="RID">
</argument>
<argument index="1" name="body" type="Node">
</argument>
@@ -234,17 +218,17 @@
</signal>
</signals>
<constants>
- <constant name="MODE_RIGID" value="0" enum="Mode">
- 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.
+ <constant name="MODE_DYNAMIC" value="0" enum="Mode">
+ Dynamic body mode. This is the default mode 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 [StaticBody2D] and does not move.
+ Static body mode. The body behaves like a [StaticBody2D], and must be moved by code.
</constant>
- <constant name="MODE_CHARACTER" value="2" enum="Mode">
- Character mode. Similar to [constant MODE_RIGID], but the body can not rotate.
+ <constant name="MODE_DYNAMIC_LOCKED" value="2" enum="Mode">
+ Locked dynamic body mode. Similar to [constant MODE_DYNAMIC], but the body can not rotate.
</constant>
<constant name="MODE_KINEMATIC" value="3" enum="Mode">
- Kinematic mode. The body behaves like a [KinematicBody2D], and must be moved by code.
+ Kinematic body mode. The body behaves like a [StaticBody2D] with [member StaticBody2D.kinematic_motion] enabled, and must be moved by user code.
</constant>
<constant name="CCD_MODE_DISABLED" value="0" enum="CCDMode">
Continuous collision detection disabled. This is the fastest way to detect body collisions, but can miss small, fast-moving objects.
diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml
index 1c6c8852a9..e3349169ff 100644
--- a/doc/classes/RigidBody3D.xml
+++ b/doc/classes/RigidBody3D.xml
@@ -5,7 +5,7 @@
</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.
+ A RigidBody3D has 4 behavior [member mode]s: Dynamic, Static, DynamicLocked, 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].
With Bullet physics (the default), the center of mass is the RigidBody3D center. With GodotPhysics, the center of mass is the average of the [CollisionShape3D] centers.
@@ -86,15 +86,6 @@
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>
@@ -103,24 +94,13 @@
[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="get_inverse_inertia_tensor">
+ <method name="get_inverse_inertia_tensor" qualifiers="const">
<return type="Basis">
</return>
<description>
Returns the inverse inertia tensor basis. This is used to calculate the angular acceleration resulting from a torque applied to the [RigidBody3D].
</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>
@@ -139,27 +119,8 @@
<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 can enter sleep mode when there is no movement. See [member sleeping].
- [b]Note:[/b] A RigidBody3D will never enter sleep mode automatically if its [member mode] is [constant MODE_CHARACTER]. It can still be put to sleep manually by setting its [member sleeping] property to [code]true[/code].
</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. See also [member contacts_reported].
@@ -217,7 +178,7 @@
</description>
</signal>
<signal name="body_shape_entered">
- <argument index="0" name="body_id" type="int">
+ <argument index="0" name="body_rid" type="RID">
</argument>
<argument index="1" name="body" type="Node">
</argument>
@@ -235,7 +196,7 @@
</description>
</signal>
<signal name="body_shape_exited">
- <argument index="0" name="body_id" type="int">
+ <argument index="0" name="body_rid" type="RID">
</argument>
<argument index="1" name="body" type="Node">
</argument>
@@ -260,17 +221,17 @@
</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 name="MODE_DYNAMIC" value="0" enum="Mode">
+ Dynamic body mode. This is the default mode 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.
+ Static body 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 name="MODE_DYNAMIC_LOCKED" value="2" enum="Mode">
+ Locked dynamic body mode. Similar to [constant MODE_DYNAMIC], but the body 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.
+ Kinematic body mode. The body behaves like a [StaticBody3D] with [member StaticBody3D.kinematic_motion] enabled, and can only move by user code.
</constant>
</constants>
</class>
diff --git a/doc/classes/SceneState.xml b/doc/classes/SceneState.xml
index abc429d5fe..f9e0ef76b9 100644
--- a/doc/classes/SceneState.xml
+++ b/doc/classes/SceneState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SceneState" inherits="Reference" version="4.0">
+<class name="SceneState" inherits="RefCounted" version="4.0">
<brief_description>
A script interface to a scene file's data.
</brief_description>
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index 9366d7dd44..7a15153fc2 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -21,7 +21,8 @@
<argument index="1" name="method" type="StringName">
</argument>
<description>
- Calls [code]method[/code] on each member of the given group.
+ Calls [code]method[/code] on each member of the given group. You can pass arguments to [code]method[/code] by specifying them at the end of the method call.
+ [b]Note:[/b] [method call_group] will always call methods with an one-frame delay, in a way similar to [method Object.call_deferred]. To call methods immediately, use [method call_group_flags] with the [constant GROUP_CALL_REALTIME] flag.
</description>
</method>
<method name="call_group_flags" qualifiers="vararg">
@@ -34,7 +35,8 @@
<argument index="2" name="method" type="StringName">
</argument>
<description>
- Calls [code]method[/code] on each member of the given group, respecting the given [enum GroupCallFlags].
+ Calls [code]method[/code] on each member of the given group, respecting the given [enum GroupCallFlags]. You can pass arguments to [code]method[/code] by specifying them at the end of the method call.
+ [b]Note:[/b] Group call flags are used to control the method calling behavior. If the [constant GROUP_CALL_REALTIME] flag is present in the [code]flags[/code] argument, methods will be called immediately. If this flag isn't present in [code]flags[/code], methods will be called with a one-frame delay in a way similar to [method call_group].
</description>
</method>
<method name="change_scene">
@@ -205,6 +207,7 @@
Quits the application at the end of the current iteration. Argument [code]exit_code[/code] can optionally be given (defaulting to 0) to customize the exit status code.
By convention, an exit code of [code]0[/code] indicates success whereas a non-zero exit code indicates an error.
For portability reasons, the exit code should be set between 0 and 125 (inclusive).
+ [b]Note:[/b] On iOS this method doesn't work. Instead, as recommended by the iOS Human Interface Guidelines, the user is expected to close apps via the Home button.
</description>
</method>
<method name="reload_current_scene">
diff --git a/doc/classes/SceneTreeTimer.xml b/doc/classes/SceneTreeTimer.xml
index b223bf6821..4eef754345 100644
--- a/doc/classes/SceneTreeTimer.xml
+++ b/doc/classes/SceneTreeTimer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SceneTreeTimer" inherits="Reference" version="4.0">
+<class name="SceneTreeTimer" inherits="RefCounted" version="4.0">
<brief_description>
One-shot timer.
</brief_description>
diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml
index 28620bd29b..31dbf7453f 100644
--- a/doc/classes/ScriptEditor.xml
+++ b/doc/classes/ScriptEditor.xml
@@ -9,30 +9,6 @@
<tutorials>
</tutorials>
<methods>
- <method name="can_drop_data_fw" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="point" type="Vector2">
- </argument>
- <argument index="1" name="data" type="Variant">
- </argument>
- <argument index="2" name="from" type="Control">
- </argument>
- <description>
- </description>
- </method>
- <method name="drop_data_fw">
- <return type="void">
- </return>
- <argument index="0" name="point" type="Vector2">
- </argument>
- <argument index="1" name="data" type="Variant">
- </argument>
- <argument index="2" name="from" type="Control">
- </argument>
- <description>
- </description>
- </method>
<method name="get_current_editor" qualifiers="const">
<return type="ScriptEditorBase">
</return>
@@ -47,16 +23,6 @@
Returns a [Script] that is currently active in editor.
</description>
</method>
- <method name="get_drag_data_fw">
- <return type="Variant">
- </return>
- <argument index="0" name="point" type="Vector2">
- </argument>
- <argument index="1" name="from" type="Control">
- </argument>
- <description>
- </description>
- </method>
<method name="get_open_script_editors" qualifiers="const">
<return type="Array">
</return>
diff --git a/doc/classes/ScriptEditorBase.xml b/doc/classes/ScriptEditorBase.xml
index ee498de302..a135062bd8 100644
--- a/doc/classes/ScriptEditorBase.xml
+++ b/doc/classes/ScriptEditorBase.xml
@@ -9,7 +9,7 @@
<tutorials>
</tutorials>
<methods>
- <method name="add_syntax_highlighter" qualifiers="virtual">
+ <method name="_add_syntax_highlighter" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="highlighter" type="Object">
@@ -18,6 +18,13 @@
Adds a [EditorSyntaxHighlighter] to the open script.
</description>
</method>
+ <method name="get_base_editor" qualifiers="const">
+ <return type="Control">
+ </return>
+ <description>
+ Returns the underlying [Control] used for editing scripts. This can be either [CodeEdit] (for text scripts) or [GraphEdit] (for visual scripts).
+ </description>
+ </method>
</methods>
<signals>
<signal name="edited_script_changed">
diff --git a/doc/classes/ScrollContainer.xml b/doc/classes/ScrollContainer.xml
index 9c5634f43a..60f3106b4b 100644
--- a/doc/classes/ScrollContainer.xml
+++ b/doc/classes/ScrollContainer.xml
@@ -11,6 +11,15 @@
<tutorials>
</tutorials>
<methods>
+ <method name="ensure_control_visible">
+ <return type="void">
+ </return>
+ <argument index="0" name="control" type="Control">
+ </argument>
+ <description>
+ Ensures the given [code]control[/code] is visible (must be a direct or indirect child of the ScrollContainer). Used by [member follow_focus].
+ </description>
+ </method>
<method name="get_h_scrollbar">
<return type="HScrollBar">
</return>
@@ -39,12 +48,18 @@
<member name="scroll_horizontal_enabled" type="bool" setter="set_enable_h_scroll" getter="is_h_scroll_enabled" default="true">
If [code]true[/code], enables horizontal scrolling.
</member>
+ <member name="scroll_horizontal_visible" type="bool" setter="set_h_scroll_visible" getter="is_h_scroll_visible" default="true">
+ If [code]false[/code], hides the horizontal scrollbar.
+ </member>
<member name="scroll_vertical" type="int" setter="set_v_scroll" getter="get_v_scroll" default="0">
The current vertical scroll value.
</member>
<member name="scroll_vertical_enabled" type="bool" setter="set_enable_v_scroll" getter="is_v_scroll_enabled" default="true">
If [code]true[/code], enables vertical scrolling.
</member>
+ <member name="scroll_vertical_visible" type="bool" setter="set_v_scroll_visible" getter="is_v_scroll_visible" default="true">
+ If [code]false[/code], hides the vertical scrollbar.
+ </member>
</members>
<signals>
<signal name="scroll_ended">
diff --git a/doc/classes/Semaphore.xml b/doc/classes/Semaphore.xml
index f311e1c72f..e8b405e52a 100644
--- a/doc/classes/Semaphore.xml
+++ b/doc/classes/Semaphore.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Semaphore" inherits="Reference" version="4.0">
+<class name="Semaphore" inherits="RefCounted" version="4.0">
<brief_description>
A synchronization semaphore.
</brief_description>
diff --git a/doc/classes/Shape3D.xml b/doc/classes/Shape3D.xml
index f8b749aebf..b5f70132d7 100644
--- a/doc/classes/Shape3D.xml
+++ b/doc/classes/Shape3D.xml
@@ -10,6 +10,13 @@
<link title="Physics introduction">https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<methods>
+ <method name="get_debug_mesh">
+ <return type="ArrayMesh">
+ </return>
+ <description>
+ Returns the [ArrayMesh] used to draw the debug collision for this [Shape3D].
+ </description>
+ </method>
</methods>
<members>
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04">
diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml
index 0ddbac9ba4..6665a4a9f6 100644
--- a/doc/classes/Skeleton2D.xml
+++ b/doc/classes/Skeleton2D.xml
@@ -10,6 +10,17 @@
<link title="2D skeletons">https://docs.godotengine.org/en/latest/tutorials/animation/2d_skeletons.html</link>
</tutorials>
<methods>
+ <method name="execute_modifications">
+ <return type="void">
+ </return>
+ <argument index="0" name="delta" type="float">
+ </argument>
+ <argument index="1" name="execution_mode" type="int">
+ </argument>
+ <description>
+ Executes all the modifications on the [SkeletonModificationStack2D], if the Skeleton3D has one assigned.
+ </description>
+ </method>
<method name="get_bone">
<return type="Bone2D">
</return>
@@ -26,6 +37,22 @@
Returns the number of [Bone2D] nodes in the node hierarchy parented by Skeleton2D.
</description>
</method>
+ <method name="get_bone_local_pose_override">
+ <return type="Transform2D">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Returns the local pose override transform for [code]bone_idx[/code].
+ </description>
+ </method>
+ <method name="get_modification_stack" qualifiers="const">
+ <return type="SkeletonModificationStack2D">
+ </return>
+ <description>
+ Returns the [SkeletonModificationStack2D] attached to this skeleton, if one exists.
+ </description>
+ </method>
<method name="get_skeleton" qualifiers="const">
<return type="RID">
</return>
@@ -33,10 +60,37 @@
Returns the [RID] of a Skeleton2D instance.
</description>
</method>
+ <method name="set_bone_local_pose_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="override_pose" type="Transform2D">
+ </argument>
+ <argument index="2" name="strength" type="float">
+ </argument>
+ <argument index="3" name="persistent" type="bool">
+ </argument>
+ <description>
+ Sets the local pose transform, [code]pose[/code], for the bone at [code]bone_idx[/code].
+ [code]amount[/code] is the interpolation strengh that will be used when applying the pose, and [code]persistent[/code] determines if the applied pose will remain.
+ [b]Note:[/b] The pose transform needs to be a local transform relative to the [Bone2D] node at [code]bone_idx[/code]!
+ </description>
+ </method>
+ <method name="set_modification_stack">
+ <return type="void">
+ </return>
+ <argument index="0" name="modification_stack" type="SkeletonModificationStack2D">
+ </argument>
+ <description>
+ Sets the [SkeletonModificationStack2D] attached to this skeleton.
+ </description>
+ </method>
</methods>
<signals>
<signal name="bone_setup_changed">
<description>
+ Emitted when the [Bone2D] setup attached to this skeletons changes. This is primarily used internally within the skeleton.
</description>
</signal>
</signals>
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index c6dd6fb142..d8b35ad272 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -22,21 +22,10 @@
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="bone_transform_to_world_transform">
- <return type="Transform">
+ <return type="Transform3D">
</return>
- <argument index="0" name="bone_transform" type="Transform">
+ <argument index="0" name="bone_transform" type="Transform3D">
</argument>
<description>
Takes the given bone pose/transform and converts it to a world transform, relative to the [Skeleton3D] node.
@@ -74,7 +63,7 @@
</description>
</method>
<method name="get_bone_custom_pose" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="bone_idx" type="int">
</argument>
@@ -83,7 +72,7 @@
</description>
</method>
<method name="get_bone_global_pose" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="bone_idx" type="int">
</argument>
@@ -91,6 +80,15 @@
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_global_pose_no_override" qualifiers="const">
+ <return type="Transform3D">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Returns the overall transform of the specified bone, with respect to the skeleton, but without any global pose overrides. 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>
@@ -111,7 +109,7 @@
</description>
</method>
<method name="get_bone_pose" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="bone_idx" type="int">
</argument>
@@ -126,7 +124,7 @@
</description>
</method>
<method name="get_bone_rest" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="bone_idx" type="int">
</argument>
@@ -134,15 +132,6 @@
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>
@@ -210,7 +199,7 @@
</return>
<argument index="0" name="bone_idx" type="int">
</argument>
- <argument index="1" name="custom_pose" type="Transform">
+ <argument index="1" name="custom_pose" type="Transform3D">
</argument>
<description>
Sets the custom pose transform, [code]custom_pose[/code], for the bone at [code]bone_idx[/code]. This pose is an addition to the bone rest pose.
@@ -233,7 +222,7 @@
</return>
<argument index="0" name="bone_idx" type="int">
</argument>
- <argument index="1" name="pose" type="Transform">
+ <argument index="1" name="pose" type="Transform3D">
</argument>
<argument index="2" name="amount" type="float">
</argument>
@@ -272,7 +261,7 @@
</return>
<argument index="0" name="bone_idx" type="int">
</argument>
- <argument index="1" name="pose" type="Transform">
+ <argument index="1" name="pose" type="Transform3D">
</argument>
<description>
Sets the pose transform for bone [code]bone_idx[/code].
@@ -284,23 +273,12 @@
</return>
<argument index="0" name="bone_idx" type="int">
</argument>
- <argument index="1" name="rest" type="Transform">
+ <argument index="1" name="rest" type="Transform3D">
</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>
@@ -311,9 +289,9 @@
</description>
</method>
<method name="world_transform_to_bone_transform">
- <return type="Transform">
+ <return type="Transform3D">
</return>
- <argument index="0" name="world_transform" type="Transform">
+ <argument index="0" name="world_transform" type="Transform3D">
</argument>
<description>
Takes the given world transform, relative to the [Skeleton3D], and converts it to a bone pose/transform.
diff --git a/doc/classes/SkeletonIK3D.xml b/doc/classes/SkeletonIK3D.xml
index 5193109447..dccc45d0ec 100644
--- a/doc/classes/SkeletonIK3D.xml
+++ b/doc/classes/SkeletonIK3D.xml
@@ -46,13 +46,13 @@
</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 name="root_bone" type="StringName" setter="set_root_bone" getter="get_root_bone" default="&amp;&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 name="target" type="Transform3D" setter="set_target_transform" getter="get_target_transform" default="Transform3D( 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 name="tip_bone" type="StringName" setter="set_tip_bone" getter="get_tip_bone" default="&amp;&quot;&quot;">
</member>
<member name="use_magnet" type="bool" setter="set_use_magnet" getter="is_using_magnet" default="false">
</member>
diff --git a/doc/classes/SkeletonModification2D.xml b/doc/classes/SkeletonModification2D.xml
new file mode 100644
index 0000000000..8596dac76e
--- /dev/null
+++ b/doc/classes/SkeletonModification2D.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SkeletonModification2D" inherits="Resource" version="4.0">
+ <brief_description>
+ A resource that operates on [Bone2D] nodes in a [Skeleton2D].
+ </brief_description>
+ <description>
+ This resource provides an interface that can be expanded so code that operates on [Bone2D] nodes in a [Skeleton2D] can be mixed and matched together to create complex interactions.
+ This is used to provide Godot with a flexible and powerful Inverse Kinematics solution that can be adapted for many different uses.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_draw_editor_gizmo" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <description>
+ Used for drawing [b]editor-only[/b] modification gizmos. This function will only be called in the Godot editor and can be overriden to draw custom gizmos.
+ [b]Note:[/b] You will need to use the Skeleton2D from [method SkeletonModificationStack2D.get_skeleton] and it's draw functions, as the [SkeletonModification2D] resource cannot draw on its own.
+ </description>
+ </method>
+ <method name="_execute" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="delta" type="float">
+ </argument>
+ <description>
+ Executes the given modification. This is where the modification performs whatever function it is designed to do.
+ </description>
+ </method>
+ <method name="_setup_modification" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="modification_stack" type="SkeletonModificationStack2D">
+ </argument>
+ <description>
+ Called when the modification is setup. This is where the modification performs initialization.
+ </description>
+ </method>
+ <method name="clamp_angle">
+ <return type="float">
+ </return>
+ <argument index="0" name="angle" type="float">
+ </argument>
+ <argument index="1" name="min" type="float">
+ </argument>
+ <argument index="2" name="max" type="float">
+ </argument>
+ <argument index="3" name="invert" type="bool">
+ </argument>
+ <description>
+ Takes a angle and clamps it so it is within the passed-in [code]min[/code] and [code]max[/code] range. [code]invert[/code] will inversely clamp the angle, clamping it to the range outside of the given bounds.
+ </description>
+ </method>
+ <method name="get_editor_draw_gizmo" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether this modification will call [method _draw_editor_gizmo] in the Godot editor to draw modification-specific gizmos.
+ </description>
+ </method>
+ <method name="get_is_setup" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether this modification has been successfully setup or not.
+ </description>
+ </method>
+ <method name="get_modification_stack">
+ <return type="SkeletonModificationStack2D">
+ </return>
+ <description>
+ Returns the [SkeletonModificationStack2D] that this modification is bound to. Through the modification stack, you can access the Skeleton3D the modification is operating on.
+ </description>
+ </method>
+ <method name="set_editor_draw_gizmo">
+ <return type="void">
+ </return>
+ <argument index="0" name="draw_gizmo" type="bool">
+ </argument>
+ <description>
+ Sets whether this modification will call [method _draw_editor_gizmo] in the Godot editor to draw modification-specific gizmos.
+ </description>
+ </method>
+ <method name="set_is_setup">
+ <return type="void">
+ </return>
+ <argument index="0" name="is_setup" type="bool">
+ </argument>
+ <description>
+ Manually allows you to set the setup state of the modification. This function should only rarely be used, as the [SkeletonModificationStack2D] the modification is bound to should handle setting the modification up.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="enabled" type="bool" setter="set_enabled" getter="get_enabled" default="true">
+ If [code]true[/code], the modification's [method _execute] function will be called by the [SkeletonModificationStack2D].
+ </member>
+ <member name="execution_mode" type="int" setter="set_execution_mode" getter="get_execution_mode" default="0">
+ The execution mode for the modification. This tells the modification stack when to execute the modification. Some modifications have settings that are only availible in certain execution modes.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SkeletonModification2DCCDIK.xml b/doc/classes/SkeletonModification2DCCDIK.xml
new file mode 100644
index 0000000000..014d366a42
--- /dev/null
+++ b/doc/classes/SkeletonModification2DCCDIK.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SkeletonModification2DCCDIK" inherits="SkeletonModification2D" version="4.0">
+ <brief_description>
+ A modification that uses CCDIK to manipulate a series of bones to reach a target in 2D.
+ </brief_description>
+ <description>
+ This [SkeletonModification2D] uses an algorithm called [b]C[/b]yclic [b]C[/b]oordinate [b]D[/b]escent [b]I[/b]nverse [b]K[/b]inematics, or CCDIK, to maniuplate a chain of bones in a [Skeleton2D] so it reaches a defined target.
+ CCDIK works by rotating a set of bones, typically called a "bone chain", on a single axis. Each bone is rotated to face the target from the tip (by default), which over a chain of bones allow it to rotate properly to reach the target. Because the bones only rotate on a single axis, CCDIK [i]can[/i] look more robotic than other IK solvers.
+ [b]Note:[/b] The CCDIK modifier has [code]ccdik_joints[/code], which are the data objects that hold the data for each joint in the CCDIK chain. This is different from a bone! CCDIK joints hold the data needed for each bone in the bone chain used by CCDIK.
+ CCDIK also fully supports angle constraints, allowing for more control over how a solution is met.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_ccdik_joint_bone2d_node" qualifiers="const">
+ <return type="NodePath">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the [Bone2D] node assigned to the CCDIK joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_ccdik_joint_bone_index" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the index of the [Bone2D] node assigned to the CCDIK joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_ccdik_joint_constraint_angle_invert" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns whether the CCDIK joint at [code]joint_idx[/code] uses an inverted joint constraint. See [method set_ccdik_joint_constraint_angle_invert] for details.
+ </description>
+ </method>
+ <method name="get_ccdik_joint_constraint_angle_max" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the maximum angle constraint for the joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_ccdik_joint_constraint_angle_min" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the minimum angle constraint for the joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_ccdik_joint_enable_constraint" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns whether angle constraints on the CCDIK joint at [code]joint_idx[/code] are enabled.
+ </description>
+ </method>
+ <method name="get_ccdik_joint_rotate_from_joint" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns whether the joint at [code]joint_idx[/code] is set to rotate from the joint, [code]true[/code], or to rotate from the tip, [code]false[/code]. The default is to rotate from the tip.
+ </description>
+ </method>
+ <method name="set_ccdik_joint_bone2d_node">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="bone2d_nodepath" type="NodePath">
+ </argument>
+ <description>
+ Sets the [Bone2D] node assigned to the CCDIK joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_ccdik_joint_bone_index">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Sets the bone index, [code]bone_index[/code], of the CCDIK joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone2d_node[/code] of the CCDIK joint based on data provided by the linked skeleton.
+ </description>
+ </method>
+ <method name="set_ccdik_joint_constraint_angle_invert">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="invert" type="bool">
+ </argument>
+ <description>
+ Sets whether the CCDIK joint at [code]joint_idx[/code] uses an inverted joint constraint.
+ An inverted joint constraint only constraints the CCDIK joint to the angles [i]outside of[/i] the inputted minimum and maximum angles. For this reason, it is referred to as an inverted joint constraint, as it constraints the joint to the outside of the inputted values.
+ </description>
+ </method>
+ <method name="set_ccdik_joint_constraint_angle_max">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="angle_max" type="float">
+ </argument>
+ <description>
+ Sets the maximum angle constraint for the joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_ccdik_joint_constraint_angle_min">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="angle_min" type="float">
+ </argument>
+ <description>
+ Sets the minimum angle constraint for the joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_ccdik_joint_enable_constraint">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="enable_constraint" type="bool">
+ </argument>
+ <description>
+ Determines whether angle constraints on the CCDIK joint at [code]joint_idx[/code] are enabled. When [code]true[/code], constraints will be enabled and taken into account when solving.
+ </description>
+ </method>
+ <method name="set_ccdik_joint_rotate_from_joint">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="rotate_from_joint" type="bool">
+ </argument>
+ <description>
+ Sets whether the joint at [code]joint_idx[/code] is set to rotate from the joint, [code]true[/code], or to rotate from the tip, [code]false[/code].
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="ccdik_data_chain_length" type="int" setter="set_ccdik_data_chain_length" getter="get_ccdik_data_chain_length" default="0">
+ The amount of CCDIK joints in the CCDIK modification.
+ </member>
+ <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
+ The NodePath to the node that is the target for the CCDIK modification. This node is what the CCDIK chain will attempt to rotate the bone chain to.
+ </member>
+ <member name="tip_nodepath" type="NodePath" setter="set_tip_node" getter="get_tip_node" default="NodePath(&quot;&quot;)">
+ The end position of the CCDIK chain. Typically, this should be a child of a [Bone2D] node attached to the final [Bone2D] in the CCDIK chain.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SkeletonModification2DFABRIK.xml b/doc/classes/SkeletonModification2DFABRIK.xml
new file mode 100644
index 0000000000..62ab34b06f
--- /dev/null
+++ b/doc/classes/SkeletonModification2DFABRIK.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SkeletonModification2DFABRIK" inherits="SkeletonModification2D" version="4.0">
+ <brief_description>
+ A modification that uses FABRIK to manipulate a series of [Bone2D] nodes to reach a target.
+ </brief_description>
+ <description>
+ This [SkeletonModification2D] uses an algorithm called [b]F[/b]orward [b]A[/b]nd [b]B[/b]ackward [b]R[/b]eaching [b]I[/b]nverse [b]K[/b]inematics, or FABRIK, to rotate a bone chain so that it reaches a target.
+ FABRIK works by knowing the positions and lengths of a series of bones, typically called a "bone chain". It first starts by running a forward pass, which places the final bone at the target's position. Then all other bones are moved towards the tip bone, so they stay at the defined bone length away. Then a backwards pass is performed, where the root/first bone in the FABRIK chain is placed back at the origin. then all other bones are moved so they stay at the defined bone length away. This positions the bone chain so that it reaches the target when possible, but all of the bones stay the correct length away from each other.
+ Because of how FABRIK works, it often gives more natural results than those seen in [SkeletonModification2DCCDIK]. FABRIK also supports angle constraints, which are fully taken into account when solving.
+ [b]Note:[/b] The FABRIK modifier has [code]fabrik_joints[/code], which are the data objects that hold the data for each joint in the FABRIK chain. This is different from [Bone2D] nodes! FABRIK joints hold the data needed for each [Bone2D] in the bone chain used by FABRIK.
+ To help control how the FABRIK joints move, a magnet vector can be passed, which can nudge the bones in a certain direction prior to solving, giving a level of control over the final result.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_fabrik_joint_bone2d_node" qualifiers="const">
+ <return type="NodePath">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the [Bone2D] node assigned to the FABRIK joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_fabrik_joint_bone_index" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the index of the [Bone2D] node assigned to the FABRIK joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_fabrik_joint_magnet_position" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the magnet position vector for the joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_fabrik_joint_use_target_rotation" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns whether the joint is using the target's rotation rather than allowing FABRIK to rotate the joint. This option only applies to the tip/final joint in the chain.
+ </description>
+ </method>
+ <method name="set_fabrik_joint_bone2d_node">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="bone2d_nodepath" type="NodePath">
+ </argument>
+ <description>
+ Sets the [Bone2D] node assigned to the FABRIK joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_fabrik_joint_bone_index">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Sets the bone index, [code]bone_index[/code], of the FABRIK joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone2d_node[/code] of the FABRIK joint based on data provided by the linked skeleton.
+ </description>
+ </method>
+ <method name="set_fabrik_joint_magnet_position">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="magnet_position" type="Vector2">
+ </argument>
+ <description>
+ Sets the magnet position vector for the joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_fabrik_joint_use_target_rotation">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="use_target_rotation" type="bool">
+ </argument>
+ <description>
+ Sets whether the joint at [code]joint_idx[/code] will use the target node's rotation rather than letting FABRIK rotate the node.
+ [b]Note:[/b] This option only works for the tip/final joint in the chain. For all other nodes, this option will be ignored.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="fabrik_data_chain_length" type="int" setter="set_fabrik_data_chain_length" getter="get_fabrik_data_chain_length" default="0">
+ The amount of FABRIK joints in the FABRIK modification.
+ </member>
+ <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
+ The NodePath to the node that is the target for the FABRIK modification. This node is what the FABRIK chain will attempt to rotate the bone chain to.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SkeletonModification2DJiggle.xml b/doc/classes/SkeletonModification2DJiggle.xml
new file mode 100644
index 0000000000..7f8cf2d4d9
--- /dev/null
+++ b/doc/classes/SkeletonModification2DJiggle.xml
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SkeletonModification2DJiggle" inherits="SkeletonModification2D" version="4.0">
+ <brief_description>
+ A modification that jiggles [Bone2D] nodes as they move towards a target.
+ </brief_description>
+ <description>
+ This modification moves a series of bones, typically called a bone chain, towards a target. What makes this modification special is that it calculates the velocity and acceleration for each bone in the bone chain, and runs a very light physics-like calculation using the inputted values. This allows the bones to overshoot the target and "jiggle" around. It can be configured to act more like a spring, or sway around like cloth might.
+ This modification is useful for adding additional motion to things like hair, the edges of clothing, and more. It has several settings to that allow control over how the joint moves when the target moves.
+ [b]Note:[/b] The Jiggle modifier has [code]jiggle_joints[/code], which are the data objects that hold the data for each joint in the Jiggle chain. This is different from than [Bone2D] nodes! Jiggle joints hold the data needed for each [Bone2D] in the bone chain used by the Jiggle modification.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_collision_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the collision mask used by the Jiggle modifier when collisions are enabled.
+ </description>
+ </method>
+ <method name="get_jiggle_joint_bone2d_node" qualifiers="const">
+ <return type="NodePath">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the [Bone2D] node assigned to the Jiggle joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_jiggle_joint_bone_index" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the index of the [Bone2D] node assigned to the Jiggle joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_jiggle_joint_damping" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the amount of damping of the Jiggle joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_jiggle_joint_gravity" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns a [Vector2] representing the amount of gravity the Jiggle joint at [code]joint_idx[/code] is influenced by.
+ </description>
+ </method>
+ <method name="get_jiggle_joint_mass" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the amount of mass of the jiggle joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_jiggle_joint_override" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns a boolean that indiciates whether the joint at [code]joint_idx[/code] is overriding the default Jiggle joint data defined in the modification.
+ </description>
+ </method>
+ <method name="get_jiggle_joint_stiffness" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the stiffness of the Jiggle joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="get_jiggle_joint_use_gravity" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns a boolean that indiciates whether the joint at [code]joint_idx[/code] is using gravity or not.
+ </description>
+ </method>
+ <method name="get_use_colliders" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether the jiggle modifier is taking physics colliders into account when solving.
+ </description>
+ </method>
+ <method name="set_collision_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="collision_mask" type="int">
+ </argument>
+ <description>
+ Sets the collision mask that the Jiggle modifier will use when reacting to colliders, if the Jiggle modifier is set to take colliders into account.
+ </description>
+ </method>
+ <method name="set_jiggle_joint_bone2d_node">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="bone2d_node" type="NodePath">
+ </argument>
+ <description>
+ Sets the [Bone2D] node assigned to the Jiggle joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_jiggle_joint_bone_index">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Sets the bone index, [code]bone_index[/code], of the Jiggle joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone2d_node[/code] of the Jiggle joint based on data provided by the linked skeleton.
+ </description>
+ </method>
+ <method name="set_jiggle_joint_damping">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="damping" type="float">
+ </argument>
+ <description>
+ Sets the amount of dampening of the Jiggle joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_jiggle_joint_gravity">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="gravity" type="Vector2">
+ </argument>
+ <description>
+ Sets the gravity vector of the Jiggle joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_jiggle_joint_mass">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="mass" type="float">
+ </argument>
+ <description>
+ Sets the of mass of the Jiggle joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_jiggle_joint_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="override" type="bool">
+ </argument>
+ <description>
+ Sets whether the Jiggle joint at [code]joint_idx[/code] should override the default Jiggle joint settings. Setting this to [code]true[/code] will make the joint use its own settings rather than the default ones attached to the modification.
+ </description>
+ </method>
+ <method name="set_jiggle_joint_stiffness">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="stiffness" type="float">
+ </argument>
+ <description>
+ Sets the of stiffness of the Jiggle joint at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_jiggle_joint_use_gravity">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="use_gravity" type="bool">
+ </argument>
+ <description>
+ Sets whether the Jiggle joint at [code]joint_idx[/code] should use gravity.
+ </description>
+ </method>
+ <method name="set_use_colliders">
+ <return type="void">
+ </return>
+ <argument index="0" name="use_colliders" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], the Jiggle modifier will take colliders into account, keeping them from entering into these collision objects.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="damping" type="float" setter="set_damping" getter="get_damping" default="0.75">
+ The default amount of dampening applied to the Jiggle joints, if they are not overriden. Higher values lead to more of the calculated velocity being applied.
+ </member>
+ <member name="gravity" type="Vector2" setter="set_gravity" getter="get_gravity" default="Vector2( 0, 6 )">
+ The default amount of gravity applied to the Jiggle joints, if they are not overriden.
+ </member>
+ <member name="jiggle_data_chain_length" type="int" setter="set_jiggle_data_chain_length" getter="get_jiggle_data_chain_length" default="0">
+ The amount of Jiggle joints in the Jiggle modification.
+ </member>
+ <member name="mass" type="float" setter="set_mass" getter="get_mass" default="0.75">
+ The default amount of mass assigned to the Jiggle joints, if they are not overriden. Higher values lead to faster movements and more overshooting.
+ </member>
+ <member name="stiffness" type="float" setter="set_stiffness" getter="get_stiffness" default="3.0">
+ The default amount of stiffness assigned to the Jiggle joints, if they are not overriden. Higher values act more like springs, quickly moving into the correct position.
+ </member>
+ <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
+ The NodePath to the node that is the target for the Jiggle modification. This node is what the Jiggle chain will attempt to rotate the bone chain to.
+ </member>
+ <member name="use_gravity" type="bool" setter="set_use_gravity" getter="get_use_gravity" default="false">
+ Whether the gravity vector, [member gravity], should be applied to the Jiggle joints, assuming they are not overriding the default settings.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SkeletonModification2DLookAt.xml b/doc/classes/SkeletonModification2DLookAt.xml
new file mode 100644
index 0000000000..b0fa0e5a01
--- /dev/null
+++ b/doc/classes/SkeletonModification2DLookAt.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SkeletonModification2DLookAt" inherits="SkeletonModification2D" version="4.0">
+ <brief_description>
+ A modification that rotates a [Bone2D] node to look at a target.
+ </brief_description>
+ <description>
+ This [SkeletonModification2D] rotates a bone to look a target. This is extremely helpful for moving character's head to look at the player, rotating a turret to look at a target, or any other case where you want to make a bone rotate towards something quickly and easily.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_additional_rotation" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the amount of additional rotation that is applied after the LookAt modification executes.
+ </description>
+ </method>
+ <method name="get_constraint_angle_invert" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether the constraints to this modification are inverted or not.
+ </description>
+ </method>
+ <method name="get_constraint_angle_max" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the constraint's maximum allowed angle.
+ </description>
+ </method>
+ <method name="get_constraint_angle_min" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the constraint's minimum allowed angle.
+ </description>
+ </method>
+ <method name="get_enable_constraint" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the LookAt modification is using constraints.
+ </description>
+ </method>
+ <method name="set_additional_rotation">
+ <return type="void">
+ </return>
+ <argument index="0" name="rotation" type="float">
+ </argument>
+ <description>
+ Sets the amount of additional rotation that is to be applied after executing the modification. This allows for offsetting the results by the inputted rotation amount.
+ </description>
+ </method>
+ <method name="set_constraint_angle_invert">
+ <return type="void">
+ </return>
+ <argument index="0" name="invert" type="bool">
+ </argument>
+ <description>
+ When [code]true[/code], the modification will use an inverted joint constraint.
+ An inverted joint constraint only constraints the [Bone2D] to the angles [i]outside of[/i] the inputted minimum and maximum angles. For this reason, it is referred to as an inverted joint constraint, as it constraints the joint to the outside of the inputted values.
+ </description>
+ </method>
+ <method name="set_constraint_angle_max">
+ <return type="void">
+ </return>
+ <argument index="0" name="angle_max" type="float">
+ </argument>
+ <description>
+ Sets the constraint's maximum allowed angle.
+ </description>
+ </method>
+ <method name="set_constraint_angle_min">
+ <return type="void">
+ </return>
+ <argument index="0" name="angle_min" type="float">
+ </argument>
+ <description>
+ Sets the constraint's minimum allowed angle.
+ </description>
+ </method>
+ <method name="set_enable_constraint">
+ <return type="void">
+ </return>
+ <argument index="0" name="enable_constraint" type="bool">
+ </argument>
+ <description>
+ Sets whether this modification will use constraints or not. When [code]true[/code], constraints will be applied when solving the LookAt modification.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="bone2d_node" type="NodePath" setter="set_bone2d_node" getter="get_bone2d_node" default="NodePath(&quot;&quot;)">
+ The [Bone2D] node that the modification will operate on.
+ </member>
+ <member name="bone_index" type="int" setter="set_bone_index" getter="get_bone_index" default="-1">
+ The index of the [Bone2D] node that the modification will oeprate on.
+ </member>
+ <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
+ The NodePath to the node that is the target for the LookAt modification. This node is what the modification will rotate the [Bone2D] to.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SkeletonModification2DPhysicalBones.xml b/doc/classes/SkeletonModification2DPhysicalBones.xml
new file mode 100644
index 0000000000..d8aaf09a8e
--- /dev/null
+++ b/doc/classes/SkeletonModification2DPhysicalBones.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SkeletonModification2DPhysicalBones" inherits="SkeletonModification2D" version="4.0">
+ <brief_description>
+ A modification that applies the transforms of [PhysicalBone2D] nodes to [Bone2D] nodes.
+ </brief_description>
+ <description>
+ This modification takes the transforms of [PhysicalBone2D] nodes and applies them to [Bone2D] nodes. This allows the [Bone2D] nodes to react to physics thanks to the linked [PhysicalBone2D] nodes.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="fetch_physical_bones">
+ <return type="void">
+ </return>
+ <description>
+ Empties the list of [PhysicalBone2D] nodes and populates it will all [PhysicalBone2D] nodes that are children of the [Skeleton2D].
+ </description>
+ </method>
+ <method name="get_physical_bone_node" qualifiers="const">
+ <return type="NodePath">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <description>
+ Returns the [PhysicalBone2D] node at [code]joint_idx[/code].
+ </description>
+ </method>
+ <method name="set_physical_bone_node">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint_idx" type="int">
+ </argument>
+ <argument index="1" name="physicalbone2d_node" type="NodePath">
+ </argument>
+ <description>
+ Sets the [PhysicalBone2D] node at [code]joint_idx[/code].
+ [b]Note:[/b] This is just the index used for this modification, not the bone index used in the [Skeleton2D].
+ </description>
+ </method>
+ <method name="start_simulation">
+ <return type="void">
+ </return>
+ <argument index="0" name="bones" type="StringName[]" default="[ ]">
+ </argument>
+ <description>
+ Tell the [PhysicalBone2D] nodes to start simulating and interacting with the physics world.
+ Optionally, an array of bone names can be passed to this function, and that will cause only [PhysicalBone2D] nodes with those names to start simulating.
+ </description>
+ </method>
+ <method name="stop_simulation">
+ <return type="void">
+ </return>
+ <argument index="0" name="bones" type="StringName[]" default="[ ]">
+ </argument>
+ <description>
+ Tell the [PhysicalBone2D] nodes to stop simulating and interacting with the physics world.
+ Optionally, an array of bone names can be passed to this function, and that will cause only [PhysicalBone2D] nodes with those names to stop simulating.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="physical_bone_chain_length" type="int" setter="set_physical_bone_chain_length" getter="get_physical_bone_chain_length" default="0">
+ The amount of [PhysicalBone2D] nodes linked in this modification.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SkeletonModification2DStackHolder.xml b/doc/classes/SkeletonModification2DStackHolder.xml
new file mode 100644
index 0000000000..313cf81482
--- /dev/null
+++ b/doc/classes/SkeletonModification2DStackHolder.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SkeletonModification2DStackHolder" inherits="SkeletonModification2D" version="4.0">
+ <brief_description>
+ A modification that holds and executes a [SkeletonModificationStack2D].
+ </brief_description>
+ <description>
+ This [SkeletonModification2D] holds a reference to a [SkeletonModificationStack2D], allowing you to use multiple modification stacks on a single [Skeleton2D].
+ [b]Note:[/b] The modifications in the held [SkeletonModificationStack2D] will only be executed if their execution mode matches the execution mode of the SkeletonModification2DStackHolder.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_held_modification_stack" qualifiers="const">
+ <return type="SkeletonModificationStack2D">
+ </return>
+ <description>
+ Returns the [SkeletonModificationStack2D] that this modification is holding.
+ </description>
+ </method>
+ <method name="set_held_modification_stack">
+ <return type="void">
+ </return>
+ <argument index="0" name="held_modification_stack" type="SkeletonModificationStack2D">
+ </argument>
+ <description>
+ Sets the [SkeletonModificationStack2D] that this modification is holding. This modification stack will then be executed when this modification is executed.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SkeletonModification2DTwoBoneIK.xml b/doc/classes/SkeletonModification2DTwoBoneIK.xml
new file mode 100644
index 0000000000..554515556b
--- /dev/null
+++ b/doc/classes/SkeletonModification2DTwoBoneIK.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SkeletonModification2DTwoBoneIK" inherits="SkeletonModification2D" version="4.0">
+ <brief_description>
+ A modification that rotates two bones using the law of cosigns to reach the target.
+ </brief_description>
+ <description>
+ This [SkeletonModification2D] uses an algorithm typically called TwoBoneIK. This algorithm works by leveraging the law of cosigns and the lengths of the bones to figure out what rotation the bones currently have, and what rotation they need to make a complete triangle, where the first bone, the second bone, and the target form the three verticies of the triangle. Because the algorithm works by making a triangle, it can only opperate on two bones.
+ TwoBoneIK is great for arms, legs, and really any joints that can be represented by just two bones that bend to reach a target. This solver is more lightweight than [SkeletonModification2DFABRIK], but gives similar, natural looking results.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_joint_one_bone2d_node" qualifiers="const">
+ <return type="NodePath">
+ </return>
+ <description>
+ Returns the [Bone2D] node that is being used as the first bone in the TwoBoneIK modification.
+ </description>
+ </method>
+ <method name="get_joint_one_bone_idx" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the index of the [Bone2D] node that is being used as the first bone in the TwoBoneIK modification.
+ </description>
+ </method>
+ <method name="get_joint_two_bone2d_node" qualifiers="const">
+ <return type="NodePath">
+ </return>
+ <description>
+ Returns the [Bone2D] node that is being used as the second bone in the TwoBoneIK modification.
+ </description>
+ </method>
+ <method name="get_joint_two_bone_idx" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the index of the [Bone2D] node that is being used as the second bone in the TwoBoneIK modification.
+ </description>
+ </method>
+ <method name="set_joint_one_bone2d_node">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone2d_node" type="NodePath">
+ </argument>
+ <description>
+ Sets the [Bone2D] node that is being used as the first bone in the TwoBoneIK modification.
+ </description>
+ </method>
+ <method name="set_joint_one_bone_idx">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Sets the index of the [Bone2D] node that is being used as the first bone in the TwoBoneIK modification.
+ </description>
+ </method>
+ <method name="set_joint_two_bone2d_node">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone2d_node" type="NodePath">
+ </argument>
+ <description>
+ Sets the [Bone2D] node that is being used as the second bone in the TwoBoneIK modification.
+ </description>
+ </method>
+ <method name="set_joint_two_bone_idx">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Sets the index of the [Bone2D] node that is being used as the second bone in the TwoBoneIK modification.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="flip_bend_direction" type="bool" setter="set_flip_bend_direction" getter="get_flip_bend_direction" default="false">
+ If [code]true[/code], the bones in the modification will blend outward as opposed to inwards when contracting. If [code]false[/code], the bones will bend inwards when contracting.
+ </member>
+ <member name="target_maximum_distance" type="float" setter="set_target_maximum_distance" getter="get_target_maximum_distance" default="0.0">
+ The maximum distance the target can be at. If the target is farther than this distance, the modification will solve as if it's at this maximum distance. When set to [code]0[/code], the modification will solve without distance constraints.
+ </member>
+ <member name="target_minimum_distance" type="float" setter="set_target_minimum_distance" getter="get_target_minimum_distance" default="0.0">
+ The minimum distance the target can be at. If the target is closer than this distance, the modification will solve as if it's at this minimum distance. When set to [code]0[/code], the modification will solve without distance constraints.
+ </member>
+ <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
+ The NodePath to the node that is the target for the TwoBoneIK modification. This node is what the modification will use when bending the [Bone2D] nodes.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SkeletonModificationStack2D.xml b/doc/classes/SkeletonModificationStack2D.xml
new file mode 100644
index 0000000000..35b899fe08
--- /dev/null
+++ b/doc/classes/SkeletonModificationStack2D.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SkeletonModificationStack2D" inherits="Resource" version="4.0">
+ <brief_description>
+ A resource that holds a stack of [SkeletonModification2D]s.
+ </brief_description>
+ <description>
+ This resource is used by the Skeleton and holds a stack of [SkeletonModification2D]s.
+ This controls the order of the modifications and how they are applied. Modification order is especially important for full-body IK setups, as you need to execute the modifications in the correct order to get the desired results. For example, you want to execute a modification on the spine [i]before[/i] the arms on a humanoid skeleton.
+ This resource also controls how strongly all of the modifications are applied to the [Skeleton2D].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_modification">
+ <return type="void">
+ </return>
+ <argument index="0" name="modification" type="SkeletonModification2D">
+ </argument>
+ <description>
+ Adds the passed-in [SkeletonModification2D] to the stack.
+ </description>
+ </method>
+ <method name="delete_modification">
+ <return type="void">
+ </return>
+ <argument index="0" name="mod_idx" type="int">
+ </argument>
+ <description>
+ Deletes the [SkeletonModification2D] at the index position [code]mod_idx[/code], if it exists.
+ </description>
+ </method>
+ <method name="enable_all_modifications">
+ <return type="void">
+ </return>
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ Enables all [SkeletonModification2D]s in the stack.
+ </description>
+ </method>
+ <method name="execute">
+ <return type="void">
+ </return>
+ <argument index="0" name="delta" type="float">
+ </argument>
+ <argument index="1" name="execution_mode" type="int">
+ </argument>
+ <description>
+ Executes all of the [SkeletonModification2D]s in the stack that use the same execution mode as the passed-in [code]execution_mode[/code], starting from index [code]0[/code] to [member modification_count].
+ [b]Note:[/b] The order of the modifications can matter depending on the modifications. For example, modifications on a spine should operate before modifications on the arms in order to get proper results.
+ </description>
+ </method>
+ <method name="get_is_setup" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns a boolean that indiciates whether the modification stack is setup and can execute.
+ </description>
+ </method>
+ <method name="get_modification" qualifiers="const">
+ <return type="SkeletonModification2D">
+ </return>
+ <argument index="0" name="mod_idx" type="int">
+ </argument>
+ <description>
+ Returns the [SkeletonModification2D] at the passed-in index, [code]mod_idx[/code].
+ </description>
+ </method>
+ <method name="get_skeleton" qualifiers="const">
+ <return type="Skeleton2D">
+ </return>
+ <description>
+ Returns the [Skeleton2D] node that the SkeletonModificationStack2D is bound to.
+ </description>
+ </method>
+ <method name="set_modification">
+ <return type="void">
+ </return>
+ <argument index="0" name="mod_idx" type="int">
+ </argument>
+ <argument index="1" name="modification" type="SkeletonModification2D">
+ </argument>
+ <description>
+ Sets the modification at [code]mod_idx[/code] to the passed-in modification, [code]modification[/code].
+ </description>
+ </method>
+ <method name="setup">
+ <return type="void">
+ </return>
+ <description>
+ Sets up the modification stack so it can execute. This function should be called by [Skeleton2D] and shouldn't be manually called unless you know what you are doing.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="enabled" type="bool" setter="set_enabled" getter="get_enabled" default="false">
+ If [code]true[/code], the modification's in the stack will be called. This is handled automatically through the [Skeleton2D] node.
+ </member>
+ <member name="modification_count" type="int" setter="set_modification_count" getter="get_modification_count" default="0">
+ The number of modifications in the stack.
+ </member>
+ <member name="strength" type="float" setter="set_strength" getter="get_strength" default="1.0">
+ The interpolation strength of the modifications in stack. A value of [code]0[/code] will make it where the modifications are not applied, a strength of [code]0.5[/code] will be half applied, and a strength of [code]1[/code] will allow the modifications to be fully applied and override the [Skeleton2D] [Bone2D] poses.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Skin.xml b/doc/classes/Skin.xml
index e22feb42f0..f409b6c80c 100644
--- a/doc/classes/Skin.xml
+++ b/doc/classes/Skin.xml
@@ -12,7 +12,7 @@
</return>
<argument index="0" name="bone" type="int">
</argument>
- <argument index="1" name="pose" type="Transform">
+ <argument index="1" name="pose" type="Transform3D">
</argument>
<description>
</description>
@@ -46,7 +46,7 @@
</description>
</method>
<method name="get_bind_pose" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="bind_index" type="int">
</argument>
@@ -86,7 +86,7 @@
</return>
<argument index="0" name="bind_index" type="int">
</argument>
- <argument index="1" name="pose" type="Transform">
+ <argument index="1" name="pose" type="Transform3D">
</argument>
<description>
</description>
diff --git a/doc/classes/SkinReference.xml b/doc/classes/SkinReference.xml
index 8fc163f88d..3f8bc3be82 100644
--- a/doc/classes/SkinReference.xml
+++ b/doc/classes/SkinReference.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkinReference" inherits="Reference" version="4.0">
+<class name="SkinReference" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml
index 617ad3a371..c320adb1be 100644
--- a/doc/classes/Sprite2D.xml
+++ b/doc/classes/Sprite2D.xml
@@ -64,7 +64,7 @@
<member name="frame" type="int" setter="set_frame" getter="get_frame" default="0">
Current frame to display from sprite sheet. [member hframes] or [member vframes] must be greater than 1.
</member>
- <member name="frame_coords" type="Vector2" setter="set_frame_coords" getter="get_frame_coords" default="Vector2( 0, 0 )">
+ <member name="frame_coords" type="Vector2i" setter="set_frame_coords" getter="get_frame_coords" default="Vector2i( 0, 0 )">
Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member hframes] or [member vframes] must be greater than 1.
</member>
<member name="hframes" type="int" setter="set_hframes" getter="get_hframes" default="1">
diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml
index 658fd1a4f2..8c4b9e7d10 100644
--- a/doc/classes/Sprite3D.xml
+++ b/doc/classes/Sprite3D.xml
@@ -14,7 +14,7 @@
<member name="frame" type="int" setter="set_frame" getter="get_frame" default="0">
Current frame to display from sprite sheet. [member hframes] or [member vframes] must be greater than 1.
</member>
- <member name="frame_coords" type="Vector2" setter="set_frame_coords" getter="get_frame_coords" default="Vector2( 0, 0 )">
+ <member name="frame_coords" type="Vector2i" setter="set_frame_coords" getter="get_frame_coords" default="Vector2i( 0, 0 )">
Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member hframes] or [member vframes] must be greater than 1.
</member>
<member name="hframes" type="int" setter="set_hframes" getter="get_hframes" default="1">
@@ -39,6 +39,11 @@
Emitted when the [member frame] changes.
</description>
</signal>
+ <signal name="texture_changed">
+ <description>
+ Emitted when the [member texture] changes.
+ </description>
+ </signal>
</signals>
<constants>
</constants>
diff --git a/doc/classes/StaticBody2D.xml b/doc/classes/StaticBody2D.xml
index 2a5c1ea6f4..298339d5fc 100644
--- a/doc/classes/StaticBody2D.xml
+++ b/doc/classes/StaticBody2D.xml
@@ -4,8 +4,11 @@
Static body for 2D physics.
</brief_description>
<description>
- 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.
- 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).
+ Static body for 2D physics. A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody2D], they don't consume any CPU resources as long as they don't move.
+ They however have extra functionalities to move and affect other bodies:
+ [b]Constant velocity:[/b] [member constant_linear_velocity] and [member constant_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).
+ [b]Transform change:[/b] Static bodies can be also moved by code. Unless [member kinematic_motion] is enabled, they are just teleported in this case and don't affect other bodies on their path.
+ [b]Kinematic motion:[/b] Static bodies can have [member kinematic_motion] enabled to make them kinematic bodies that can be moved by code and push other bodies on their path.
</description>
<tutorials>
</tutorials>
@@ -13,10 +16,14 @@
</methods>
<members>
<member name="constant_angular_velocity" type="float" setter="set_constant_angular_velocity" getter="get_constant_angular_velocity" default="0.0">
- The body's constant angular velocity. This does not rotate the body, but affects colliding bodies, as if it were rotating.
+ The body's constant angular velocity. This does not rotate the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were rotating.
</member>
<member name="constant_linear_velocity" type="Vector2" setter="set_constant_linear_velocity" getter="get_constant_linear_velocity" default="Vector2( 0, 0 )">
- The body's constant linear velocity. This does not move the body, but affects colliding bodies, as if it were moving.
+ The body's constant linear velocity. This does not move the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were moving.
+ </member>
+ <member name="kinematic_motion" type="bool" setter="set_kinematic_motion_enabled" getter="is_kinematic_motion_enabled" default="false">
+ If [code]true[/code], the body will act the same as a [RigidBody2D] in [constant RigidBody2D.MODE_KINEMATIC] mode.
+ When the body is moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to [code]physics[/code]), 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).
</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.
diff --git a/doc/classes/StaticBody3D.xml b/doc/classes/StaticBody3D.xml
index 63a15cbe1d..5ffbb71522 100644
--- a/doc/classes/StaticBody3D.xml
+++ b/doc/classes/StaticBody3D.xml
@@ -4,8 +4,11 @@
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).
+ Static body for 3D physics. A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody3D], they don't consume any CPU resources as long as they don't move.
+ They however have extra functionalities to move and affect other bodies:
+ [b]Constant velocity:[/b] [member constant_linear_velocity] and [member constant_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).
+ [b]Transform change:[/b] Static bodies can be also moved by code. Unless [member kinematic_motion] is enabled, they are just teleported in this case and don't affect other bodies on their path.
+ [b]Kinematic motion:[/b] Static bodies can have [member kinematic_motion] enabled to make them kinematic bodies that can be moved by code and push other bodies on their path.
</description>
<tutorials>
<link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link>
@@ -16,10 +19,14 @@
</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.
+ The body's constant angular velocity. This does not rotate the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were rotating.
</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.
+ The body's constant linear velocity. This does not move the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were moving.
+ </member>
+ <member name="kinematic_motion" type="bool" setter="set_kinematic_motion_enabled" getter="is_kinematic_motion_enabled" default="false">
+ If [code]true[/code], the body will act the same as a [RigidBody3D] in [constant RigidBody3D.MODE_KINEMATIC] mode.
+ When the body is moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to [code]physics[/code]), 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).
</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.
diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml
index a1b858acf6..5367a572f1 100644
--- a/doc/classes/StreamPeer.xml
+++ b/doc/classes/StreamPeer.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StreamPeer" inherits="Reference" version="4.0">
+<class name="StreamPeer" inherits="RefCounted" version="4.0">
<brief_description>
Abstraction and base class for stream-based protocols.
</brief_description>
<description>
- 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.
+ StreamPeer is an abstraction and base class for stream-based protocols (such as TCP). It provides an API for sending and receiving data through streams as raw data or strings.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/StreamPeerTCP.xml b/doc/classes/StreamPeerTCP.xml
index b6d91715ee..7b7c1d7426 100644
--- a/doc/classes/StreamPeerTCP.xml
+++ b/doc/classes/StreamPeerTCP.xml
@@ -9,6 +9,18 @@
<tutorials>
</tutorials>
<methods>
+ <method name="bind">
+ <return type="int" enum="Error">
+ </return>
+ <argument index="0" name="port" type="int">
+ </argument>
+ <argument index="1" name="host" type="String" default="&quot;*&quot;">
+ </argument>
+ <description>
+ Opens the TCP socket, and binds it to the specified local address.
+ This method is generally not needed, and only used to force the subsequent call to [method connect_to_host] to use the specified [code]host[/code] and [code]port[/code] as source address. This can be desired in some NAT punchthrough techniques, or when forcing the source network interface.
+ </description>
+ </method>
<method name="connect_to_host">
<return type="int" enum="Error">
</return>
@@ -17,7 +29,7 @@
<argument index="1" name="port" type="int">
</argument>
<description>
- Connects to the specified [code]host:port[/code] pair. A hostname will be resolved if valid. Returns [constant OK] on success or [constant FAILED] on failure.
+ Connects to the specified [code]host:port[/code] pair. A hostname will be resolved if valid. Returns [constant OK] on success.
</description>
</method>
<method name="disconnect_from_host">
@@ -41,6 +53,13 @@
Returns the port of this peer.
</description>
</method>
+ <method name="get_local_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the local port to which this peer is bound.
+ </description>
+ </method>
<method name="get_status">
<return type="int" enum="StreamPeerTCP.Status">
</return>
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 416438e648..d0c5f0ea86 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -275,7 +275,7 @@
Returns a copy of the string with the substring [code]what[/code] inserted at the given position.
</description>
</method>
- <method name="is_abs_path" qualifiers="const">
+ <method name="is_absolute_path" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -397,7 +397,12 @@
<argument index="0" name="position" type="int">
</argument>
<description>
- Returns a number of characters from the left of the string.
+ Returns a number of characters from the left of the string. If negative [code]position[/code] is used, the characters are counted downwards from [String]'s length.
+ Examples:
+ [codeblock]
+ print("sample text".left(3)) #prints "sam"
+ print("sample text".left(-3)) #prints "sample t"
+ [/codeblock]
</description>
</method>
<method name="length" qualifiers="const">
@@ -669,7 +674,12 @@
<argument index="0" name="position" type="int">
</argument>
<description>
- Returns the right side of the string from a given position.
+ Returns a number of characters from the right of the string. If negative [code]position[/code] is used, the characters are counted downwards from [String]'s length.
+ Examples:
+ [codeblock]
+ print("sample text".right(3)) #prints "ext"
+ print("sample text".right(-3)) #prints "ple text"
+ [/codeblock]
</description>
</method>
<method name="rpad" qualifiers="const">
diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml
index 895d0c357d..f4a1f1f01d 100644
--- a/doc/classes/StyleBoxTexture.xml
+++ b/doc/classes/StyleBoxTexture.xml
@@ -127,13 +127,6 @@
The texture to use when drawing this style box.
</member>
</members>
- <signals>
- <signal name="texture_changed">
- <description>
- Emitted when the stylebox's texture is changed.
- </description>
- </signal>
- </signals>
<constants>
<constant name="AXIS_STRETCH_MODE_STRETCH" value="0" enum="AxisStretchMode">
Stretch the stylebox's texture. This results in visible distortion unless the texture size matches the stylebox's size perfectly.
diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml
index 376082f417..f54f22d6fa 100644
--- a/doc/classes/SubViewport.xml
+++ b/doc/classes/SubViewport.xml
@@ -25,7 +25,7 @@
<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 )">
+ <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i( 512, 512 )">
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 )">
@@ -34,9 +34,6 @@
<member name="size_2d_override_stretch" type="bool" setter="set_size_2d_override_stretch" getter="is_size_2d_override_stretch_enabled" default="false">
If [code]true[/code], the 2D size override affects stretch as well.
</member>
- <member name="xr" type="bool" setter="set_use_xr" getter="is_using_xr" default="false">
- If [code]true[/code], the sub-viewport will be used in AR/VR process.
- </member>
</members>
<constants>
<constant name="CLEAR_MODE_ALWAYS" value="0" enum="ClearMode">
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index 1195e4aa2b..56b47f4a24 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SurfaceTool" inherits="Reference" version="4.0">
+<class name="SurfaceTool" inherits="RefCounted" version="4.0">
<brief_description>
Helper tool to create geometry.
</brief_description>
@@ -76,10 +76,10 @@
</argument>
<argument index="1" name="surface" type="int">
</argument>
- <argument index="2" name="transform" type="Transform">
+ <argument index="2" name="transform" type="Transform3D">
</argument>
<description>
- Append vertices from a given [Mesh] surface onto the current vertex array with specified [Transform].
+ Append vertices from a given [Mesh] surface onto the current vertex array with specified [Transform3D].
</description>
</method>
<method name="begin">
diff --git a/doc/classes/TCP_Server.xml b/doc/classes/TCPServer.xml
index 72e9ca923d..7160055c6d 100644
--- a/doc/classes/TCP_Server.xml
+++ b/doc/classes/TCPServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TCP_Server" inherits="Reference" version="4.0">
+<class name="TCPServer" inherits="RefCounted" version="4.0">
<brief_description>
A TCP server.
</brief_description>
@@ -9,6 +9,13 @@
<tutorials>
</tutorials>
<methods>
+ <method name="get_local_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the local port this server is listening to.
+ </description>
+ </method>
<method name="is_connection_available" qualifiers="const">
<return type="bool">
</return>
diff --git a/doc/classes/Tabs.xml b/doc/classes/Tabs.xml
index 79fa8896e3..d784585e20 100644
--- a/doc/classes/Tabs.xml
+++ b/doc/classes/Tabs.xml
@@ -389,8 +389,6 @@
<theme_item name="outline_size" type="int" default="0">
The size of the tab text outline.
</theme_item>
- <theme_item name="panel" type="StyleBox">
- </theme_item>
<theme_item name="tab_disabled" type="StyleBox">
The style of disabled tabs.
</theme_item>
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 088bcd1c3c..2d6a052fe3 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
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.
+ [b]Note:[/b] When holding down [kbd]Alt[/kbd], the vertical scroll wheel will scroll 5 times as fast as it would normally do. This also works in the Godot script editor.
</description>
<tutorials>
</tutorials>
@@ -17,15 +18,6 @@
<description>
</description>
</method>
- <method name="can_fold" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="line" type="int">
- </argument>
- <description>
- Returns if the given line is foldable, that is, it has indented lines right below it.
- </description>
- </method>
<method name="center_viewport_to_cursor">
<return type="void">
</return>
@@ -94,7 +86,7 @@
<description>
Moves the cursor at the specified [code]line[/code] index.
If [code]adjust_viewport[/code] is set to [code]true[/code], the viewport will center at the cursor position after the move occurs.
- 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].
+ If [code]can_be_hidden[/code] is set to [code]true[/code], the specified [code]line[/code] can be hidden.
</description>
</method>
<method name="cut">
@@ -111,20 +103,11 @@
Deselects the current selection.
</description>
</method>
- <method name="fold_all_lines">
- <return type="void">
- </return>
- <description>
- Folds all lines that are possible to be folded (see [method can_fold]).
- </description>
- </method>
- <method name="fold_line">
- <return type="void">
+ <method name="get_caret_draw_pos" qualifiers="const">
+ <return type="Vector2">
</return>
- <argument index="0" name="line" type="int">
- </argument>
<description>
- Folds the given line, if possible (see [method can_fold]).
+ Gets the caret pixel draw poistion.
</description>
</method>
<method name="get_gutter_count" qualifiers="const">
@@ -166,6 +149,15 @@
Returns the text of a specific line.
</description>
</method>
+ <method name="get_line_background_color">
+ <return type="Color">
+ </return>
+ <argument index="0" name="line" type="int">
+ </argument>
+ <description>
+ Returns the current background color of the line. [code]Color(0, 0, 0, 0)[/code] is returned if no color is set.
+ </description>
+ </method>
<method name="get_line_count" qualifiers="const">
<return type="int">
</return>
@@ -282,6 +274,13 @@
Returns the selection end line.
</description>
</method>
+ <method name="get_visible_line_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of visible lines, including wrapped text.
+ </description>
+ </method>
<method name="get_word_under_cursor" qualifiers="const">
<return type="String">
</return>
@@ -298,13 +297,11 @@
Insert the specified text at the cursor position.
</description>
</method>
- <method name="is_folded" qualifiers="const">
+ <method name="is_caret_visible" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="line" type="int">
- </argument>
<description>
- Returns whether the line at the specified index is folded or not.
+ Returns [code]true[/code] if the caret is visible on the screen.
</description>
</method>
<method name="is_gutter_clickable" qualifiers="const">
@@ -341,15 +338,6 @@
<description>
</description>
</method>
- <method name="is_line_hidden" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="line" type="int">
- </argument>
- <description>
- Returns whether the line at the specified index is hidden or not.
- </description>
- </method>
<method name="is_selection_active" qualifiers="const">
<return type="bool">
</return>
@@ -529,15 +517,15 @@
Sets the text for a specific line.
</description>
</method>
- <method name="set_line_as_hidden">
+ <method name="set_line_background_color">
<return type="void">
</return>
<argument index="0" name="line" type="int">
</argument>
- <argument index="1" name="enable" type="bool">
+ <argument index="1" name="color" type="Color">
</argument>
<description>
- If [code]true[/code], hides the line of the specified index.
+ Sets the current background color of the line. Set to [code]Color(0, 0, 0, 0)[/code] for no color.
</description>
</method>
<method name="set_line_gutter_clickable">
@@ -623,15 +611,6 @@
<description>
</description>
</method>
- <method name="toggle_fold_line">
- <return type="void">
- </return>
- <argument index="0" name="line" type="int">
- </argument>
- <description>
- Toggle the folding of the code block at the given line.
- </description>
- </method>
<method name="undo">
<return type="void">
</return>
@@ -639,22 +618,6 @@
Perform undo operation.
</description>
</method>
- <method name="unfold_line">
- <return type="void">
- </return>
- <argument index="0" name="line" type="int">
- </argument>
- <description>
- Unfolds the given line, if folded.
- </description>
- </method>
- <method name="unhide_all_lines">
- <return type="void">
- </return>
- <description>
- Unhide all lines that were previously set to hidden by [method set_line_as_hidden].
- </description>
- </method>
</methods>
<members>
<member name="caret_blink" type="bool" setter="cursor_set_blink_enabled" getter="cursor_get_blink_enabled" default="false">
@@ -688,9 +651,6 @@
If [code]true[/code], the "tab" character will have a visible representation.
</member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" override="true" enum="Control.FocusMode" default="2" />
- <member name="hiding_enabled" type="bool" setter="set_hiding_enabled" getter="is_hiding_enabled" default="false">
- If [code]true[/code], all lines that have been set to hidden by [method set_line_as_hidden], will not be visible.
- </member>
<member name="highlight_all_occurrences" type="bool" setter="set_highlight_all_occurrences" getter="is_highlight_all_occurrences_enabled" default="false">
If [code]true[/code], all occurrences of the selected text will be highlighted.
</member>
@@ -714,10 +674,10 @@
If [code]true[/code], read-only mode is enabled. Existing text cannot be modified and new text cannot be added.
</member>
<member name="scroll_horizontal" type="int" setter="set_h_scroll" getter="get_h_scroll" default="0">
- If there is a horizontal scrollbar this determines the current horizontal scroll value in pixels.
+ If there is a horizontal scrollbar, this determines the current horizontal scroll value in pixels.
</member>
<member name="scroll_vertical" type="float" setter="set_v_scroll" getter="get_v_scroll" default="0.0">
- If there is a vertical scrollbar this determines the current vertical scroll value in line numbers, starting at 0 for the top line.
+ If there is a vertical scrollbar, this determines the current vertical scroll value in line numbers, starting at 0 for the top line.
</member>
<member name="selecting_enabled" type="bool" setter="set_selecting_enabled" getter="is_selecting_enabled" default="true">
If [code]true[/code], text can be selected.
@@ -784,10 +744,6 @@
<description>
</description>
</signal>
- <signal name="request_completion">
- <description>
- </description>
- </signal>
<signal name="symbol_lookup">
<argument index="0" name="symbol" type="String">
</argument>
@@ -934,26 +890,6 @@
</theme_item>
<theme_item name="caret_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )">
</theme_item>
- <theme_item name="code_folding_color" type="Color" default="Color( 0.8, 0.8, 0.8, 0.8 )">
- </theme_item>
- <theme_item name="completion" type="StyleBox">
- </theme_item>
- <theme_item name="completion_background_color" type="Color" default="Color( 0.17, 0.16, 0.2, 1 )">
- </theme_item>
- <theme_item name="completion_existing_color" type="Color" default="Color( 0.87, 0.87, 0.87, 0.13 )">
- </theme_item>
- <theme_item name="completion_font_color" type="Color" default="Color( 0.67, 0.67, 0.67, 1 )">
- </theme_item>
- <theme_item name="completion_lines" type="int" default="7">
- </theme_item>
- <theme_item name="completion_max_width" type="int" default="50">
- </theme_item>
- <theme_item name="completion_scroll_color" type="Color" default="Color( 1, 1, 1, 1 )">
- </theme_item>
- <theme_item name="completion_scroll_width" type="int" default="3">
- </theme_item>
- <theme_item name="completion_selected_color" type="Color" default="Color( 0.26, 0.26, 0.27, 1 )">
- </theme_item>
<theme_item name="current_line_color" type="Color" default="Color( 0.25, 0.25, 0.26, 0.8 )">
Sets the [Color] of the breakpoints. [member breakpoint_gutter] has to be enabled.
</theme_item>
@@ -979,9 +915,6 @@
<theme_item name="line_spacing" type="int" default="4">
Sets the spacing between the lines.
</theme_item>
- <theme_item name="mark_color" type="Color" default="Color( 1, 0.4, 0.4, 0.4 )">
- Sets the [Color] of marked text.
- </theme_item>
<theme_item name="normal" type="StyleBox">
Sets the [StyleBox] of this [TextEdit].
</theme_item>
diff --git a/doc/classes/TextLine.xml b/doc/classes/TextLine.xml
index c21da09edb..ddbae0e977 100644
--- a/doc/classes/TextLine.xml
+++ b/doc/classes/TextLine.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextLine" inherits="Reference" version="4.0">
+<class name="TextLine" inherits="RefCounted" version="4.0">
<brief_description>
Holds a line of text.
</brief_description>
diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml
index 8df53b8423..e9afe47ee8 100644
--- a/doc/classes/TextParagraph.xml
+++ b/doc/classes/TextParagraph.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextParagraph" inherits="Reference" version="4.0">
+<class name="TextParagraph" inherits="RefCounted" version="4.0">
<brief_description>
Holds a paragraph of text.
</brief_description>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index fe63e434c9..9a96d8699c 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -976,7 +976,7 @@
</argument>
<description>
Returns [code]true[/code] if text buffer is configured to display hexadecimal codes in place of invalid characters.
- Note: If set to [code]false[/code], nothing is displayed in place of invalid characters.
+ Note: If set to [code]false[/code], nothing is displayed in place of invalid characters.
</description>
</method>
<method name="shaped_text_get_range" qualifiers="const">
diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml
index 3173dddb42..7448697df3 100644
--- a/doc/classes/Theme.xml
+++ b/doc/classes/Theme.xml
@@ -23,10 +23,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Clears the [Color] at [code]name[/code] if the theme has [code]node_type[/code].
+ Clears the [Color] at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="clear_constant">
@@ -34,10 +34,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Clears the constant at [code]name[/code] if the theme has [code]node_type[/code].
+ Clears the constant at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="clear_font">
@@ -45,10 +45,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Clears the [Font] at [code]name[/code] if the theme has [code]node_type[/code].
+ Clears the [Font] at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="clear_font_size">
@@ -56,10 +56,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Clears the font size [code]name[/code] if the theme has [code]node_type[/code].
+ Clears the font size [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="clear_icon">
@@ -67,10 +67,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Clears the icon at [code]name[/code] if the theme has [code]node_type[/code].
+ Clears the icon at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="clear_stylebox">
@@ -78,10 +78,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Clears [StyleBox] at [code]name[/code] if the theme has [code]node_type[/code].
+ Clears [StyleBox] at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="clear_theme_item">
@@ -91,10 +91,10 @@
</argument>
<argument index="1" name="name" type="StringName">
</argument>
- <argument index="2" name="node_type" type="StringName">
+ <argument index="2" name="theme_type" type="StringName">
</argument>
<description>
- Clears the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]node_type[/code].
+ Clears the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="copy_default_theme">
@@ -118,19 +118,19 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns the [Color] at [code]name[/code] if the theme has [code]node_type[/code].
+ Returns the [Color] at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="get_color_list" qualifiers="const">
<return type="PackedStringArray">
</return>
- <argument index="0" name="node_type" type="String">
+ <argument index="0" name="theme_type" type="String">
</argument>
<description>
- 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]node_type[/code].
+ 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]theme_type[/code].
</description>
</method>
<method name="get_color_type_list" qualifiers="const">
@@ -145,19 +145,19 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns the constant at [code]name[/code] if the theme has [code]node_type[/code].
+ Returns the constant at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="get_constant_list" qualifiers="const">
<return type="PackedStringArray">
</return>
- <argument index="0" name="node_type" type="String">
+ <argument index="0" name="theme_type" type="String">
</argument>
<description>
- Returns all the constants as a [PackedStringArray] filled with each constant's name, for use in [method get_constant], if the theme has [code]node_type[/code].
+ Returns all the constants as a [PackedStringArray] filled with each constant's name, for use in [method get_constant], if the theme has [code]theme_type[/code].
</description>
</method>
<method name="get_constant_type_list" qualifiers="const">
@@ -172,19 +172,19 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns the [Font] at [code]name[/code] if the theme has [code]node_type[/code].
+ Returns the [Font] at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="get_font_list" qualifiers="const">
<return type="PackedStringArray">
</return>
- <argument index="0" name="node_type" type="String">
+ <argument index="0" name="theme_type" type="String">
</argument>
<description>
- 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]node_type[/code].
+ 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]theme_type[/code].
</description>
</method>
<method name="get_font_size" qualifiers="const">
@@ -192,19 +192,19 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns the font size at [code]name[/code] if the theme has [code]node_type[/code].
+ Returns the font size at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="get_font_size_list" qualifiers="const">
<return type="PackedStringArray">
</return>
- <argument index="0" name="node_type" type="String">
+ <argument index="0" name="theme_type" type="String">
</argument>
<description>
- Returns all the font sizes as a [PackedStringArray] filled with each font size name, for use in [method get_font_size], if the theme has [code]node_type[/code].
+ Returns all the font sizes as a [PackedStringArray] filled with each font size name, for use in [method get_font_size], if the theme has [code]theme_type[/code].
</description>
</method>
<method name="get_font_size_type_list" qualifiers="const">
@@ -226,19 +226,19 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns the icon [Texture2D] at [code]name[/code] if the theme has [code]node_type[/code].
+ Returns the icon [Texture2D] at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="get_icon_list" qualifiers="const">
<return type="PackedStringArray">
</return>
- <argument index="0" name="node_type" type="String">
+ <argument index="0" name="theme_type" type="String">
</argument>
<description>
- Returns all the icons as a [PackedStringArray] filled with each [Texture2D]'s name, for use in [method get_icon], if the theme has [code]node_type[/code].
+ Returns all the icons as a [PackedStringArray] filled with each [Texture2D]'s name, for use in [method get_icon], if the theme has [code]theme_type[/code].
</description>
</method>
<method name="get_icon_type_list" qualifiers="const">
@@ -253,21 +253,21 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns the [StyleBox] at [code]name[/code] if the theme has [code]node_type[/code].
- Valid [code]name[/code]s may be found using [method get_stylebox_list]. Valid [code]node_type[/code]s may be found using [method get_stylebox_type_list].
+ Returns the [StyleBox] at [code]name[/code] if the theme has [code]theme_type[/code].
+ Valid [code]name[/code]s may be found using [method get_stylebox_list]. Valid [code]theme_type[/code]s may be found using [method get_stylebox_type_list].
</description>
</method>
<method name="get_stylebox_list" qualifiers="const">
<return type="PackedStringArray">
</return>
- <argument index="0" name="node_type" type="String">
+ <argument index="0" name="theme_type" type="String">
</argument>
<description>
- Returns all the [StyleBox]s as a [PackedStringArray] filled with each [StyleBox]'s name, for use in [method get_stylebox], if the theme has [code]node_type[/code].
- Valid [code]node_type[/code]s may be found using [method get_stylebox_type_list].
+ 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]theme_type[/code].
+ Valid [code]theme_type[/code]s may be found using [method get_stylebox_type_list].
</description>
</method>
<method name="get_stylebox_type_list" qualifiers="const">
@@ -284,11 +284,11 @@
</argument>
<argument index="1" name="name" type="StringName">
</argument>
- <argument index="2" name="node_type" type="StringName">
+ <argument index="2" name="theme_type" type="StringName">
</argument>
<description>
- Returns the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]node_type[/code].
- Valid [code]name[/code]s may be found using [method get_theme_item_list] or a data type specific method. Valid [code]node_type[/code]s may be found using [method get_theme_item_type_list] or a data type specific method.
+ Returns the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]theme_type[/code].
+ Valid [code]name[/code]s may be found using [method get_theme_item_list] or a data type specific method. Valid [code]theme_type[/code]s may be found using [method get_theme_item_type_list] or a data type specific method.
</description>
</method>
<method name="get_theme_item_list" qualifiers="const">
@@ -296,11 +296,11 @@
</return>
<argument index="0" name="data_type" type="int" enum="Theme.DataType">
</argument>
- <argument index="1" name="node_type" type="String">
+ <argument index="1" name="theme_type" type="String">
</argument>
<description>
- Returns all the theme items of [code]data_type[/code] as a [PackedStringArray] filled with each theme items's name, for use in [method get_theme_item] or a data type specific method, if the theme has [code]node_type[/code].
- Valid [code]node_type[/code]s may be found using [method get_theme_item_type_list] or a data type specific method.
+ Returns all the theme items of [code]data_type[/code] as a [PackedStringArray] filled with each theme items's name, for use in [method get_theme_item] or a data type specific method, if the theme has [code]theme_type[/code].
+ Valid [code]theme_type[/code]s may be found using [method get_theme_item_type_list] or a data type specific method.
</description>
</method>
<method name="get_theme_item_type_list" qualifiers="const">
@@ -324,11 +324,11 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns [code]true[/code] if [Color] with [code]name[/code] is in [code]node_type[/code].
- Returns [code]false[/code] if the theme does not have [code]node_type[/code].
+ Returns [code]true[/code] if [Color] with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
</description>
</method>
<method name="has_constant" qualifiers="const">
@@ -336,11 +336,11 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns [code]true[/code] if constant with [code]name[/code] is in [code]node_type[/code].
- Returns [code]false[/code] if the theme does not have [code]node_type[/code].
+ Returns [code]true[/code] if constant with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
</description>
</method>
<method name="has_font" qualifiers="const">
@@ -348,11 +348,11 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns [code]true[/code] if [Font] with [code]name[/code] is in [code]node_type[/code].
- Returns [code]false[/code] if the theme does not have [code]node_type[/code].
+ Returns [code]true[/code] if [Font] with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
</description>
</method>
<method name="has_font_size" qualifiers="const">
@@ -360,11 +360,11 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns [code]true[/code] if font size with [code]name[/code] is in [code]node_type[/code].
- Returns [code]false[/code] if the theme does not have [code]node_type[/code].
+ Returns [code]true[/code] if font size with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
</description>
</method>
<method name="has_icon" qualifiers="const">
@@ -372,11 +372,11 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns [code]true[/code] if icon [Texture2D] with [code]name[/code] is in [code]node_type[/code].
- Returns [code]false[/code] if the theme does not have [code]node_type[/code].
+ Returns [code]true[/code] if icon [Texture2D] with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
</description>
</method>
<method name="has_stylebox" qualifiers="const">
@@ -384,11 +384,11 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<description>
- Returns [code]true[/code] if [StyleBox] with [code]name[/code] is in [code]node_type[/code].
- Returns [code]false[/code] if the theme does not have [code]node_type[/code].
+ Returns [code]true[/code] if [StyleBox] with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
</description>
</method>
<method name="has_theme_item" qualifiers="const">
@@ -398,11 +398,11 @@
</argument>
<argument index="1" name="name" type="StringName">
</argument>
- <argument index="2" name="node_type" type="StringName">
+ <argument index="2" name="theme_type" type="StringName">
</argument>
<description>
- Returns [code]true[/code] if a theme item of [code]data_type[/code] with [code]name[/code] is in [code]node_type[/code].
- Returns [code]false[/code] if the theme does not have [code]node_type[/code].
+ Returns [code]true[/code] if a theme item of [code]data_type[/code] with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
</description>
</method>
<method name="rename_color">
@@ -412,10 +412,10 @@
</argument>
<argument index="1" name="name" type="StringName">
</argument>
- <argument index="2" name="node_type" type="StringName">
+ <argument index="2" name="theme_type" type="StringName">
</argument>
<description>
- Renames the [Color] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ Renames the [Color] at [code]old_name[/code] to [code]name[/code] if the theme has [code]theme_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
</method>
<method name="rename_constant">
@@ -425,10 +425,10 @@
</argument>
<argument index="1" name="name" type="StringName">
</argument>
- <argument index="2" name="node_type" type="StringName">
+ <argument index="2" name="theme_type" type="StringName">
</argument>
<description>
- Renames the constant at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ Renames the constant at [code]old_name[/code] to [code]name[/code] if the theme has [code]theme_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
</method>
<method name="rename_font">
@@ -438,10 +438,10 @@
</argument>
<argument index="1" name="name" type="StringName">
</argument>
- <argument index="2" name="node_type" type="StringName">
+ <argument index="2" name="theme_type" type="StringName">
</argument>
<description>
- Renames the [Font] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ Renames the [Font] at [code]old_name[/code] to [code]name[/code] if the theme has [code]theme_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
</method>
<method name="rename_font_size">
@@ -451,10 +451,10 @@
</argument>
<argument index="1" name="name" type="StringName">
</argument>
- <argument index="2" name="node_type" type="StringName">
+ <argument index="2" name="theme_type" type="StringName">
</argument>
<description>
- Renames the font size [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ Renames the font size [code]old_name[/code] to [code]name[/code] if the theme has [code]theme_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
</method>
<method name="rename_icon">
@@ -464,10 +464,10 @@
</argument>
<argument index="1" name="name" type="StringName">
</argument>
- <argument index="2" name="node_type" type="StringName">
+ <argument index="2" name="theme_type" type="StringName">
</argument>
<description>
- Renames the icon at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ Renames the icon at [code]old_name[/code] to [code]name[/code] if the theme has [code]theme_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
</method>
<method name="rename_stylebox">
@@ -477,10 +477,10 @@
</argument>
<argument index="1" name="name" type="StringName">
</argument>
- <argument index="2" name="node_type" type="StringName">
+ <argument index="2" name="theme_type" type="StringName">
</argument>
<description>
- Renames [StyleBox] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ Renames [StyleBox] at [code]old_name[/code] to [code]name[/code] if the theme has [code]theme_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
</method>
<method name="rename_theme_item">
@@ -492,10 +492,10 @@
</argument>
<argument index="2" name="name" type="StringName">
</argument>
- <argument index="3" name="node_type" type="StringName">
+ <argument index="3" name="theme_type" type="StringName">
</argument>
<description>
- Renames the theme item of [code]data_type[/code] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ Renames the theme item of [code]data_type[/code] at [code]old_name[/code] to [code]name[/code] if the theme has [code]theme_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
</method>
<method name="set_color">
@@ -503,13 +503,13 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<argument index="2" name="color" type="Color">
</argument>
<description>
- Sets the theme's [Color] to [code]color[/code] at [code]name[/code] in [code]node_type[/code].
- Creates [code]node_type[/code] if the theme does not have it.
+ Sets the theme's [Color] to [code]color[/code] at [code]name[/code] in [code]theme_type[/code].
+ Creates [code]theme_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_constant">
@@ -517,13 +517,13 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<argument index="2" name="constant" type="int">
</argument>
<description>
- Sets the theme's constant to [code]constant[/code] at [code]name[/code] in [code]node_type[/code].
- Creates [code]node_type[/code] if the theme does not have it.
+ Sets the theme's constant to [code]constant[/code] at [code]name[/code] in [code]theme_type[/code].
+ Creates [code]theme_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_font">
@@ -531,13 +531,13 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<argument index="2" name="font" type="Font">
</argument>
<description>
- Sets the theme's [Font] to [code]font[/code] at [code]name[/code] in [code]node_type[/code].
- Creates [code]node_type[/code] if the theme does not have it.
+ Sets the theme's [Font] to [code]font[/code] at [code]name[/code] in [code]theme_type[/code].
+ Creates [code]theme_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_font_size">
@@ -545,13 +545,13 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<argument index="2" name="font_size" type="int">
</argument>
<description>
- Sets the theme's font size to [code]font_size[/code] at [code]name[/code] in [code]node_type[/code].
- Creates [code]node_type[/code] if the theme does not have it.
+ Sets the theme's font size to [code]font_size[/code] at [code]name[/code] in [code]theme_type[/code].
+ Creates [code]theme_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_icon">
@@ -559,13 +559,13 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<argument index="2" name="texture" type="Texture2D">
</argument>
<description>
- Sets the theme's icon [Texture2D] to [code]texture[/code] at [code]name[/code] in [code]node_type[/code].
- Creates [code]node_type[/code] if the theme does not have it.
+ Sets the theme's icon [Texture2D] to [code]texture[/code] at [code]name[/code] in [code]theme_type[/code].
+ Creates [code]theme_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_stylebox">
@@ -573,13 +573,13 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="node_type" type="StringName">
+ <argument index="1" name="theme_type" type="StringName">
</argument>
<argument index="2" name="texture" type="StyleBox">
</argument>
<description>
- Sets theme's [StyleBox] to [code]stylebox[/code] at [code]name[/code] in [code]node_type[/code].
- Creates [code]node_type[/code] if the theme does not have it.
+ Sets theme's [StyleBox] to [code]stylebox[/code] at [code]name[/code] in [code]theme_type[/code].
+ Creates [code]theme_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_theme_item">
@@ -589,14 +589,14 @@
</argument>
<argument index="1" name="name" type="StringName">
</argument>
- <argument index="2" name="node_type" type="StringName">
+ <argument index="2" name="theme_type" type="StringName">
</argument>
<argument index="3" name="value" type="Variant">
</argument>
<description>
- Sets the theme item of [code]data_type[/code] to [code]value[/code] at [code]name[/code] in [code]node_type[/code].
+ Sets the theme item of [code]data_type[/code] to [code]value[/code] at [code]name[/code] in [code]theme_type[/code].
Does nothing if the [code]value[/code] type does not match [code]data_type[/code].
- Creates [code]node_type[/code] if the theme does not have it.
+ Creates [code]theme_type[/code] if the theme does not have it.
</description>
</method>
</methods>
diff --git a/doc/classes/Thread.xml b/doc/classes/Thread.xml
index 88f46e3937..5ac9416b72 100644
--- a/doc/classes/Thread.xml
+++ b/doc/classes/Thread.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Thread" inherits="Reference" version="4.0">
+<class name="Thread" inherits="RefCounted" version="4.0">
<brief_description>
A unit of execution in a process.
</brief_description>
diff --git a/doc/classes/TileData.xml b/doc/classes/TileData.xml
new file mode 100644
index 0000000000..efcbdf2e95
--- /dev/null
+++ b/doc/classes/TileData.xml
@@ -0,0 +1,245 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TileData" inherits="Object" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_collision_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_shape_one_way_margin" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="shape_index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_shape_shape" qualifiers="const">
+ <return type="Shape2D">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="shape_index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_shapes_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_custom_data" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="layer_name" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_custom_data_by_layer_id" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_navigation_polygon" qualifiers="const">
+ <return type="NavigationPolygon">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_occluder" qualifiers="const">
+ <return type="OccluderPolygon2D">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_peering_bit_terrain" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_collision_shape_one_way" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="shape_index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_collision_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="shape_index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_collision_shape_one_way">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="shape_index" type="int">
+ </argument>
+ <argument index="2" name="one_way" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_collision_shape_one_way_margin">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="shape_index" type="int">
+ </argument>
+ <argument index="2" name="one_way_margin" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_collision_shape_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="shape_index" type="int">
+ </argument>
+ <argument index="2" name="shape" type="Shape2D">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_collision_shapes_count">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="shapes_count" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_custom_data">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer_name" type="String">
+ </argument>
+ <argument index="1" name="value" type="Variant">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_custom_data_by_layer_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="value" type="Variant">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_navigation_polygon">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="navigation_polygon" type="NavigationPolygon">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_occluder">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer_id" type="int">
+ </argument>
+ <argument index="1" name="occluder_polygon" type="OccluderPolygon2D">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_peering_bit_terrain">
+ <return type="void">
+ </return>
+ <argument index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor">
+ </argument>
+ <argument index="1" name="terrain" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="tile_get_material" qualifiers="const">
+ <return type="ShaderMaterial">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="tile_set_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="material" type="ShaderMaterial">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="flip_h" type="bool" setter="set_flip_h" getter="get_flip_h" default="false">
+ </member>
+ <member name="flip_v" type="bool" setter="set_flip_v" getter="get_flip_v" default="false">
+ </member>
+ <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color( 1, 1, 1, 1 )">
+ </member>
+ <member name="probability" type="float" setter="set_probability" getter="get_probability" default="1.0">
+ </member>
+ <member name="terrain_set" type="int" setter="set_terrain_set" getter="get_terrain_set" default="-1">
+ </member>
+ <member name="texture_offset" type="Vector2i" setter="set_texture_offset" getter="get_texture_offset" default="Vector2i( 0, 0 )">
+ </member>
+ <member name="transpose" type="bool" setter="set_transpose" getter="get_transpose" default="false">
+ </member>
+ <member name="y_sort_origin" type="int" setter="set_y_sort_origin" getter="get_y_sort_origin" default="0">
+ </member>
+ <member name="z_index" type="int" setter="set_z_index" getter="get_z_index" default="0">
+ </member>
+ </members>
+ <signals>
+ <signal name="changed">
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 205b342ba8..93d5dd8037 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -31,53 +31,46 @@
Clears cells that do not exist in the tileset.
</description>
</method>
- <method name="get_cell" qualifiers="const">
+ <method name="get_cell_alternative_tile" qualifiers="const">
<return type="int">
</return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
+ <argument index="0" name="coords" type="Vector2i">
</argument>
<description>
- Returns the tile index of the given cell. If no tile exists in the cell, returns [constant INVALID_CELL].
</description>
</method>
- <method name="get_cell_autotile_coord" qualifiers="const">
- <return type="Vector2">
+ <method name="get_cell_atlas_coords" qualifiers="const">
+ <return type="Vector2i">
</return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
+ <argument index="0" name="coords" type="Vector2i">
</argument>
<description>
- 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">
+ <method name="get_cell_source_id" qualifiers="const">
<return type="int">
</return>
- <argument index="0" name="position" type="Vector2">
+ <argument index="0" name="coords" type="Vector2i">
</argument>
<description>
- Returns the tile index of the cell given by a Vector2. If no tile exists in the cell, returns [constant INVALID_CELL].
</description>
</method>
- <method name="get_collision_layer_bit" qualifiers="const">
- <return type="bool">
+ <method name="get_neighbor_cell" qualifiers="const">
+ <return type="Vector2i">
</return>
- <argument index="0" name="bit" type="int">
+ <argument index="0" name="coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="neighbor" type="int" enum="TileSet.CellNeighbor">
</argument>
<description>
- Returns [code]true[/code] if the given collision layer bit is set.
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
+ <method name="get_surrounding_tiles">
+ <return type="Vector2i[]">
</return>
- <argument index="0" name="bit" type="int">
+ <argument index="0" name="coords" type="Vector2i">
</argument>
<description>
- Returns [code]true[/code] if the given collision mask bit is set.
</description>
</method>
<method name="get_used_cells" qualifiers="const">
@@ -87,15 +80,6 @@
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]).
</description>
</method>
- <method name="get_used_cells_by_index" qualifiers="const">
- <return type="Vector2i[]">
- </return>
- <argument index="0" name="index" type="int">
- </argument>
- <description>
- Returns an array of all cells with the given tile [code]index[/code].
- </description>
- </method>
<method name="get_used_rect">
<return type="Rect2">
</return>
@@ -103,155 +87,28 @@
Returns a rectangle enclosing the used (non-empty) tiles of the map.
</description>
</method>
- <method name="is_cell_transposed" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <description>
- Returns [code]true[/code] if the given cell is transposed, i.e. the X and Y axes are swapped.
- </description>
- </method>
- <method name="is_cell_x_flipped" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <description>
- Returns [code]true[/code] if the given cell is flipped in the X axis.
- </description>
- </method>
- <method name="is_cell_y_flipped" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <description>
- Returns [code]true[/code] if the given cell is flipped in the Y axis.
- </description>
- </method>
<method name="map_to_world" qualifiers="const">
<return type="Vector2">
</return>
- <argument index="0" name="map_position" type="Vector2">
- </argument>
- <argument index="1" name="ignore_half_ofs" type="bool" default="false">
+ <argument index="0" name="map_position" type="Vector2i">
</argument>
<description>
Returns the local position corresponding to the given tilemap (grid-based) coordinates.
- Optionally, the tilemap's half offset can be ignored.
</description>
</method>
<method name="set_cell">
<return type="void">
</return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="tile" type="int">
- </argument>
- <argument index="3" name="flip_x" type="bool" default="false">
- </argument>
- <argument index="4" name="flip_y" type="bool" default="false">
- </argument>
- <argument index="5" name="transpose" type="bool" default="false">
- </argument>
- <argument index="6" name="autotile_coord" type="Vector2" default="Vector2( 0, 0 )">
- </argument>
- <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. 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:
- [codeblocks]
- [gdscript]
- func set_cell(x, y, tile, flip_x=false, flip_y=false, transpose=false, autotile_coord=Vector2()):
- # Write your custom logic here.
- # To call the default method:
- .set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)
- [/gdscript]
- [csharp]
- public void SetCell(int x, int y, int tile, bool flipX = false, bool flipY = false, bool transpose = false, Vector2 autotileCoord = new Vector2())
- {
- // Write your custom logic here.
- // To call the default method:
- base.SetCell(x, y, tile, flipX, flipY, transpose, autotileCoord);
- }
- [/csharp]
- [/codeblocks]
- </description>
- </method>
- <method name="set_cellv">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector2">
+ <argument index="0" name="coords" type="Vector2i">
</argument>
- <argument index="1" name="tile" type="int">
+ <argument index="1" name="source_id" type="int" default="-1">
</argument>
- <argument index="2" name="flip_x" type="bool" default="false">
+ <argument index="2" name="atlas_coords" type="Vector2i" default="Vector2i( -1, -1 )">
</argument>
- <argument index="3" name="flip_y" type="bool" default="false">
- </argument>
- <argument index="4" name="transpose" type="bool" default="false">
+ <argument index="3" name="alternative_tile" type="int" default="-1">
</argument>
<description>
- Sets the tile index for the given cell.
- An index of [code]-1[/code] clears the cell.
- Optionally, the tile can also be flipped or transposed.
- [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].
- </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 the given collision layer bit.
- </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 given collision mask bit.
- </description>
- </method>
- <method name="update_bitmask_area">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector2">
- </argument>
- <description>
- Applies autotiling rules to the cell (and its adjacent cells) referenced by its grid-based X and Y coordinates.
- </description>
- </method>
- <method name="update_bitmask_region">
- <return type="void">
- </return>
- <argument index="0" name="start" type="Vector2" default="Vector2( 0, 0 )">
- </argument>
- <argument index="1" name="end" type="Vector2" default="Vector2( 0, 0 )">
- </argument>
- <description>
- Applies autotiling rules to the cells in the given region (specified by grid-based X and Y coordinates).
- Calling with invalid (or missing) parameters applies autotiling rules for the entire tilemap.
+ Sets the tile index for the cell given by a Vector2i.
</description>
</method>
<method name="update_dirty_quadrants">
@@ -262,7 +119,7 @@
</description>
</method>
<method name="world_to_map" qualifiers="const">
- <return type="Vector2">
+ <return type="Vector2i">
</return>
<argument index="0" name="world_position" type="Vector2">
</argument>
@@ -272,110 +129,30 @@
</method>
</methods>
<members>
- <member name="bake_navigation" type="bool" setter="set_bake_navigation" getter="is_baking_navigation" default="false">
- If [code]true[/code], this TileMap bakes a navigation region.
- </member>
- <member name="cell_clip_uv" type="bool" setter="set_clip_uv" getter="get_clip_uv" default="false">
- If [code]true[/code], the cell's UVs will be clipped.
- </member>
- <member name="cell_custom_transform" type="Transform2D" setter="set_custom_transform" getter="get_custom_transform" default="Transform2D( 64, 0, 0, 64, 0, 0 )">
- The custom [Transform2D] to be applied to the TileMap's cells.
- </member>
- <member name="cell_half_offset" type="int" setter="set_half_offset" getter="get_half_offset" enum="TileMap.HalfOffset" default="2">
- Amount to offset alternating tiles. See [enum HalfOffset] for possible values.
- </member>
<member name="cell_quadrant_size" type="int" setter="set_quadrant_size" getter="get_quadrant_size" default="16">
The TileMap's quadrant size. Optimizes drawing by batching, using chunks of this size.
</member>
- <member name="cell_size" type="Vector2" setter="set_cell_size" getter="get_cell_size" default="Vector2( 64, 64 )">
- The TileMap's cell size.
- </member>
- <member name="cell_tile_origin" type="int" setter="set_tile_origin" getter="get_tile_origin" enum="TileMap.TileOrigin" default="0">
- Position for tile origin. See [enum TileOrigin] for possible values.
- </member>
- <member name="cell_y_sort" type="bool" setter="set_y_sort_enabled" getter="is_y_sort_enabled" default="false">
- If [code]true[/code], the TileMap's direct children will be drawn in order of their Y coordinate.
- </member>
- <member name="centered_textures" type="bool" setter="set_centered_textures" getter="is_centered_textures_enabled" default="false">
- 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.
- If [code]false[/code], the texture position start in the top-left corner unless [member compatibility_mode] is enabled.
- </member>
- <member name="collision_bounce" type="float" setter="set_collision_bounce" getter="get_collision_bounce" default="0.0">
- Bounce value for static body collisions (see [code]collision_use_kinematic[/code]).
- </member>
- <member name="collision_friction" type="float" setter="set_collision_friction" getter="get_collision_friction" default="1.0">
- Friction value for static body collisions (see [code]collision_use_kinematic[/code]).
- </member>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The collision layer(s) for all colliders in the TileMap. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The collision mask(s) for all colliders in the TileMap. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
- <member name="collision_use_kinematic" type="bool" setter="set_collision_use_kinematic" getter="get_collision_use_kinematic" default="false">
- If [code]true[/code], TileMap collisions will be handled as a kinematic body. If [code]false[/code], collisions will be handled as static body.
- </member>
- <member name="collision_use_parent" type="bool" setter="set_collision_use_parent" getter="get_collision_use_parent" default="false">
- 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].
+ <member name="show_collision" type="int" setter="set_collision_visibility_mode" getter="get_collision_visibility_mode" enum="TileMap.VisibilityMode" default="0">
</member>
- <member name="compatibility_mode" type="bool" setter="set_compatibility_mode" getter="is_compatibility_mode_enabled" default="false">
- 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.
- 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.
- 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.
- </member>
- <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="TileMap.Mode" default="0">
- The TileMap orientation mode. See [enum Mode] for possible values.
- </member>
- <member name="occluder_light_mask" type="int" setter="set_occluder_light_mask" getter="get_occluder_light_mask" default="1">
- 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).
+ <member name="show_navigation" type="int" setter="set_navigation_visibility_mode" getter="get_navigation_visibility_mode" enum="TileMap.VisibilityMode" default="0">
</member>
<member name="tile_set" type="TileSet" setter="set_tileset" getter="get_tileset">
The assigned [TileSet].
</member>
</members>
<signals>
- <signal name="settings_changed">
+ <signal name="changed">
<description>
- Emitted when a tilemap setting has changed.
+ Emitted when the [TileSet] of this TileMap changes.
</description>
</signal>
</signals>
<constants>
- <constant name="INVALID_CELL" value="-1">
- Returned when a cell doesn't exist.
- </constant>
- <constant name="MODE_SQUARE" value="0" enum="Mode">
- Orthogonal orientation mode.
- </constant>
- <constant name="MODE_ISOMETRIC" value="1" enum="Mode">
- Isometric orientation mode.
- </constant>
- <constant name="MODE_CUSTOM" value="2" enum="Mode">
- Custom orientation mode.
- </constant>
- <constant name="HALF_OFFSET_X" value="0" enum="HalfOffset">
- Half offset on the X coordinate.
- </constant>
- <constant name="HALF_OFFSET_Y" value="1" enum="HalfOffset">
- Half offset on the Y coordinate.
- </constant>
- <constant name="HALF_OFFSET_DISABLED" value="2" enum="HalfOffset">
- Half offset disabled.
- </constant>
- <constant name="HALF_OFFSET_NEGATIVE_X" value="3" enum="HalfOffset">
- Half offset on the X coordinate (negative).
- </constant>
- <constant name="HALF_OFFSET_NEGATIVE_Y" value="4" enum="HalfOffset">
- Half offset on the Y coordinate (negative).
- </constant>
- <constant name="TILE_ORIGIN_TOP_LEFT" value="0" enum="TileOrigin">
- Tile origin at its top-left corner.
+ <constant name="VISIBILITY_MODE_DEFAULT" value="0" enum="VisibilityMode">
</constant>
- <constant name="TILE_ORIGIN_CENTER" value="1" enum="TileOrigin">
- Tile origin at its center.
+ <constant name="VISIBILITY_MODE_FORCE_HIDE" value="2" enum="VisibilityMode">
</constant>
- <constant name="TILE_ORIGIN_BOTTOM_LEFT" value="2" enum="TileOrigin">
- Tile origin at its bottom-left corner.
+ <constant name="VISIBILITY_MODE_FORCE_SHOW" value="1" enum="VisibilityMode">
</constant>
</constants>
</class>
diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml
index adc5880c71..2015b1f1cd 100644
--- a/doc/classes/TileSet.xml
+++ b/doc/classes/TileSet.xml
@@ -17,752 +17,350 @@
<link title="2D Kinematic Character Demo">https://godotengine.org/asset-library/asset/113</link>
</tutorials>
<methods>
- <method name="_forward_atlas_subtile_selection" qualifiers="virtual">
- <return type="Vector2">
- </return>
- <argument index="0" name="atlastile_id" type="int">
- </argument>
- <argument index="1" name="tilemap" type="Object">
- </argument>
- <argument index="2" name="tile_location" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="_forward_subtile_selection" qualifiers="virtual">
- <return type="Vector2">
- </return>
- <argument index="0" name="autotile_id" type="int">
- </argument>
- <argument index="1" name="bitmask" type="int">
- </argument>
- <argument index="2" name="tilemap" type="Object">
- </argument>
- <argument index="3" name="tile_location" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="_is_tile_bound" qualifiers="virtual">
- <return type="bool">
- </return>
- <argument index="0" name="drawn_id" type="int">
- </argument>
- <argument index="1" name="neighbor_id" type="int">
- </argument>
- <description>
- Determines when the auto-tiler should consider two different auto-tile IDs to be bound together.
- [b]Note:[/b] [code]neighbor_id[/code] will be [code]-1[/code] ([constant TileMap.INVALID_CELL]) when checking a tile against an empty neighbor tile.
- </description>
- </method>
- <method name="autotile_clear_bitmask_map">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Clears all bitmask information of the autotile.
- </description>
- </method>
- <method name="autotile_get_bitmask">
+ <method name="add_source">
<return type="int">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="coord" type="Vector2">
+ <argument index="0" name="atlas_source_id_override" type="TileSetSource">
</argument>
- <description>
- Returns the bitmask of the subtile from an autotile given its coordinates.
- 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).
- </description>
- </method>
- <method name="autotile_get_bitmask_mode" qualifiers="const">
- <return type="int" enum="TileSet.BitmaskMode">
- </return>
- <argument index="0" name="id" type="int">
+ <argument index="1" name="arg1" type="int" default="-1">
</argument>
<description>
- Returns the [enum BitmaskMode] of the autotile.
</description>
</method>
- <method name="autotile_get_icon_coordinate" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns the subtile that's being used as an icon in an atlas/autotile given its coordinates.
- 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.
- </description>
- </method>
- <method name="autotile_get_light_occluder" qualifiers="const">
- <return type="OccluderPolygon2D">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="coord" type="Vector2">
- </argument>
- <description>
- Returns the light occluder of the subtile from an atlas/autotile given its coordinates.
- </description>
- </method>
- <method name="autotile_get_navigation_polygon" qualifiers="const">
- <return type="NavigationPolygon">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="coord" type="Vector2">
- </argument>
- <description>
- Returns the navigation polygon of the subtile from an atlas/autotile given its coordinates.
- </description>
- </method>
- <method name="autotile_get_size" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns the size of the subtiles in an atlas/autotile.
- </description>
- </method>
- <method name="autotile_get_spacing" qualifiers="const">
+ <method name="get_navigation_layer_layers" qualifiers="const">
<return type="int">
</return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="layer_index" type="int">
</argument>
<description>
- Returns the spacing between subtiles of the atlas/autotile.
</description>
</method>
- <method name="autotile_get_subtile_priority">
+ <method name="get_next_source_id" qualifiers="const">
<return type="int">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="coord" type="Vector2">
- </argument>
<description>
- Returns the priority of the subtile from an autotile given its coordinates.
- 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.
</description>
</method>
- <method name="autotile_get_z_index">
+ <method name="get_occlusion_layer_light_mask" qualifiers="const">
<return type="int">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="coord" type="Vector2">
+ <argument index="0" name="arg0" type="int">
</argument>
<description>
- Returns the drawing index of the subtile from an atlas/autotile given its coordinates.
</description>
</method>
- <method name="autotile_set_bitmask">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="bitmask" type="Vector2">
- </argument>
- <argument index="2" name="flag" type="int">
- </argument>
- <description>
- Sets the bitmask of the subtile from an autotile given its coordinates.
- 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).
- </description>
- </method>
- <method name="autotile_set_bitmask_mode">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="mode" type="int" enum="TileSet.BitmaskMode">
- </argument>
- <description>
- Sets the [enum BitmaskMode] of the autotile.
- </description>
- </method>
- <method name="autotile_set_icon_coordinate">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="coord" type="Vector2">
- </argument>
- <description>
- Sets the subtile that will be used as an icon in an atlas/autotile given its coordinates.
- 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.
- </description>
- </method>
- <method name="autotile_set_light_occluder">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="light_occluder" type="OccluderPolygon2D">
- </argument>
- <argument index="2" name="coord" type="Vector2">
- </argument>
- <description>
- Sets the light occluder of the subtile from an atlas/autotile given its coordinates.
- </description>
- </method>
- <method name="autotile_set_navigation_polygon">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="navigation_polygon" type="NavigationPolygon">
- </argument>
- <argument index="2" name="coord" type="Vector2">
- </argument>
- <description>
- Sets the navigation polygon of the subtile from an atlas/autotile given its coordinates.
- </description>
- </method>
- <method name="autotile_set_size">
- <return type="void">
+ <method name="get_occlusion_layer_sdf_collision" qualifiers="const">
+ <return type="bool">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="size" type="Vector2">
+ <argument index="0" name="arg0" type="int">
</argument>
<description>
- Sets the size of the subtiles in an atlas/autotile.
</description>
</method>
- <method name="autotile_set_spacing">
- <return type="void">
+ <method name="get_physics_layer_collision_layer" qualifiers="const">
+ <return type="int">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="spacing" type="int">
+ <argument index="0" name="layer_index" type="int">
</argument>
<description>
- Sets the spacing between subtiles of the atlas/autotile.
</description>
</method>
- <method name="autotile_set_subtile_priority">
- <return type="void">
+ <method name="get_physics_layer_collision_mask" qualifiers="const">
+ <return type="int">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="coord" type="Vector2">
- </argument>
- <argument index="2" name="priority" type="int">
+ <argument index="0" name="layer_index" type="int">
</argument>
<description>
- Sets the priority of the subtile from an autotile given its coordinates.
- 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.
</description>
</method>
- <method name="autotile_set_z_index">
- <return type="void">
+ <method name="get_physics_layer_physics_material" qualifiers="const">
+ <return type="PhysicsMaterial">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="coord" type="Vector2">
- </argument>
- <argument index="2" name="z_index" type="int">
+ <argument index="0" name="layer_index" type="int">
</argument>
<description>
- Sets the drawing index of the subtile from an atlas/autotile given its coordinates.
</description>
</method>
- <method name="clear">
- <return type="void">
+ <method name="get_source" qualifiers="const">
+ <return type="TileSetSource">
</return>
- <description>
- Clears all tiles.
- </description>
- </method>
- <method name="create_tile">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="index" type="int">
</argument>
<description>
- Creates a new tile with the given ID.
</description>
</method>
- <method name="find_tile_by_name" qualifiers="const">
+ <method name="get_source_count" qualifiers="const">
<return type="int">
</return>
- <argument index="0" name="name" type="String">
- </argument>
<description>
- Returns the first tile matching the given name.
</description>
</method>
- <method name="get_last_unused_tile_id" qualifiers="const">
+ <method name="get_source_id" qualifiers="const">
<return type="int">
</return>
- <description>
- Returns the ID following the last currently used ID, useful when creating a new tile.
- </description>
- </method>
- <method name="get_tiles_ids" qualifiers="const">
- <return type="Array">
- </return>
- <description>
- Returns an array of all currently used tile IDs.
- </description>
- </method>
- <method name="remove_tile">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="index" type="int">
</argument>
<description>
- Removes the given tile ID.
</description>
</method>
- <method name="tile_add_shape">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape" type="Shape2D">
- </argument>
- <argument index="2" name="shape_transform" type="Transform2D">
- </argument>
- <argument index="3" name="one_way" type="bool" default="false">
- </argument>
- <argument index="4" name="autotile_coord" type="Vector2" default="Vector2( 0, 0 )">
- </argument>
- <description>
- Adds a shape to the tile.
- </description>
- </method>
- <method name="tile_get_light_occluder" qualifiers="const">
- <return type="OccluderPolygon2D">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns the tile's light occluder.
- </description>
- </method>
- <method name="tile_get_material" qualifiers="const">
- <return type="ShaderMaterial">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns the tile's material.
- </description>
- </method>
- <method name="tile_get_modulate" qualifiers="const">
+ <method name="get_terrain_color" qualifiers="const">
<return type="Color">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns the tile's modulation color.
- </description>
- </method>
- <method name="tile_get_name" qualifiers="const">
- <return type="String">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns the tile's name.
- </description>
- </method>
- <method name="tile_get_navigation_polygon" qualifiers="const">
- <return type="NavigationPolygon">
- </return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="terrain_set" type="int">
</argument>
- <description>
- Returns the navigation polygon of the tile.
- </description>
- </method>
- <method name="tile_get_navigation_polygon_offset" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="id" type="int">
+ <argument index="1" name="terrain_index" type="int">
</argument>
<description>
- Returns the offset of the tile's navigation polygon.
</description>
</method>
- <method name="tile_get_occluder_offset" qualifiers="const">
- <return type="Vector2">
+ <method name="get_terrain_name" qualifiers="const">
+ <return type="String">
</return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="terrain_set" type="int">
</argument>
- <description>
- Returns the offset of the tile's light occluder.
- </description>
- </method>
- <method name="tile_get_region" qualifiers="const">
- <return type="Rect2">
- </return>
- <argument index="0" name="id" type="int">
+ <argument index="1" name="terrain_index" type="int">
</argument>
<description>
- Returns the tile sub-region in the texture.
</description>
</method>
- <method name="tile_get_shape" qualifiers="const">
- <return type="Shape2D">
+ <method name="get_terrain_set_mode" qualifiers="const">
+ <return type="int" enum="TileSet.TerrainMode">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
+ <argument index="0" name="terrain_set" type="int">
</argument>
<description>
- Returns a tile's given shape.
</description>
</method>
- <method name="tile_get_shape_count" qualifiers="const">
+ <method name="get_terrains_count" qualifiers="const">
<return type="int">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns the number of shapes assigned to a tile.
- </description>
- </method>
- <method name="tile_get_shape_offset" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
+ <argument index="0" name="terrain_set" type="int">
</argument>
<description>
- Returns the offset of a tile's shape.
</description>
</method>
- <method name="tile_get_shape_one_way" qualifiers="const">
+ <method name="has_source" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
- </argument>
- <description>
- Returns the one-way collision value of a tile's shape.
- </description>
- </method>
- <method name="tile_get_shape_one_way_margin" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_get_shape_transform" qualifiers="const">
- <return type="Transform2D">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
- </argument>
- <description>
- Returns the [Transform2D] of a tile's shape.
- </description>
- </method>
- <method name="tile_get_shapes" qualifiers="const">
- <return type="Array">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns an array of dictionaries describing the tile's shapes.
- [b]Dictionary structure in the array returned by this method:[/b]
- [codeblock]
- {
- "autotile_coord": Vector2,
- "one_way": bool,
- "one_way_margin": int,
- "shape": CollisionShape2D,
- "shape_transform": Transform2D,
- }
- [/codeblock]
- </description>
- </method>
- <method name="tile_get_texture" qualifiers="const">
- <return type="Texture2D">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns the tile's texture.
- </description>
- </method>
- <method name="tile_get_texture_offset" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns the texture offset of the tile.
- </description>
- </method>
- <method name="tile_get_tile_mode" qualifiers="const">
- <return type="int" enum="TileSet.TileMode">
- </return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="index" type="int">
</argument>
<description>
- Returns the tile's [enum TileMode].
</description>
</method>
- <method name="tile_get_z_index" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns the tile's Z index (drawing layer).
- </description>
- </method>
- <method name="tile_set_light_occluder">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="light_occluder" type="OccluderPolygon2D">
- </argument>
- <description>
- Sets a light occluder for the tile.
- </description>
- </method>
- <method name="tile_set_material">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="material" type="ShaderMaterial">
- </argument>
- <description>
- Sets the tile's material.
- </description>
- </method>
- <method name="tile_set_modulate">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Sets the tile's modulation color.
- </description>
- </method>
- <method name="tile_set_name">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="name" type="String">
- </argument>
- <description>
- Sets the tile's name.
- </description>
- </method>
- <method name="tile_set_navigation_polygon">
+ <method name="remove_source">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="navigation_polygon" type="NavigationPolygon">
+ <argument index="0" name="source_id" type="int">
</argument>
<description>
- Sets the tile's navigation polygon.
</description>
</method>
- <method name="tile_set_navigation_polygon_offset">
+ <method name="set_navigation_layer_layers">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="layer_index" type="int">
</argument>
- <argument index="1" name="navigation_polygon_offset" type="Vector2">
+ <argument index="1" name="layers" type="int">
</argument>
<description>
- Sets an offset for the tile's navigation polygon.
</description>
</method>
- <method name="tile_set_occluder_offset">
+ <method name="set_occlusion_layer_light_mask">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="layer_index" type="int">
</argument>
- <argument index="1" name="occluder_offset" type="Vector2">
+ <argument index="1" name="light_mask" type="int">
</argument>
<description>
- Sets an offset for the tile's light occluder.
</description>
</method>
- <method name="tile_set_region">
+ <method name="set_occlusion_layer_sdf_collision">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="layer_index" type="int">
</argument>
- <argument index="1" name="region" type="Rect2">
+ <argument index="1" name="sdf_collision" type="int">
</argument>
<description>
- Sets the tile's sub-region in the texture. This is common in texture atlases.
</description>
</method>
- <method name="tile_set_shape">
+ <method name="set_physics_layer_collision_layer">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
+ <argument index="0" name="layer_index" type="int">
</argument>
- <argument index="2" name="shape" type="Shape2D">
+ <argument index="1" name="layer" type="int">
</argument>
<description>
- Sets a shape for the tile, enabling collision.
</description>
</method>
- <method name="tile_set_shape_offset">
+ <method name="set_physics_layer_collision_mask">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
+ <argument index="0" name="layer_index" type="int">
</argument>
- <argument index="2" name="shape_offset" type="Vector2">
+ <argument index="1" name="mask" type="int">
</argument>
<description>
- Sets the offset of a tile's shape.
</description>
</method>
- <method name="tile_set_shape_one_way">
+ <method name="set_physics_layer_physics_material">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="layer_index" type="int">
</argument>
- <argument index="1" name="shape_id" type="int">
- </argument>
- <argument index="2" name="one_way" type="bool">
+ <argument index="1" name="physics_material" type="PhysicsMaterial">
</argument>
<description>
- Enables one-way collision on a tile's shape.
</description>
</method>
- <method name="tile_set_shape_one_way_margin">
+ <method name="set_source_id">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
+ <argument index="0" name="source_id" type="int">
</argument>
- <argument index="2" name="one_way" type="float">
+ <argument index="1" name="arg1" type="int">
</argument>
<description>
</description>
</method>
- <method name="tile_set_shape_transform">
+ <method name="set_terrain_color">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="terrain_set" type="int">
</argument>
- <argument index="1" name="shape_id" type="int">
+ <argument index="1" name="terrain_index" type="int">
</argument>
- <argument index="2" name="shape_transform" type="Transform2D">
+ <argument index="2" name="color" type="Color">
</argument>
<description>
- Sets a [Transform2D] on a tile's shape.
</description>
</method>
- <method name="tile_set_shapes">
+ <method name="set_terrain_name">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="terrain_set" type="int">
</argument>
- <argument index="1" name="shapes" type="Array">
- </argument>
- <description>
- Sets an array of shapes for the tile, enabling collision.
- </description>
- </method>
- <method name="tile_set_texture">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="texture" type="Texture2D">
- </argument>
- <description>
- Sets the tile's texture.
- </description>
- </method>
- <method name="tile_set_texture_offset">
- <return type="void">
- </return>
- <argument index="0" name="id" type="int">
+ <argument index="1" name="terrain_index" type="int">
</argument>
- <argument index="1" name="texture_offset" type="Vector2">
+ <argument index="2" name="name" type="String">
</argument>
<description>
- Sets the tile's texture offset.
</description>
</method>
- <method name="tile_set_tile_mode">
+ <method name="set_terrain_set_mode">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="terrain_set" type="int">
</argument>
- <argument index="1" name="tilemode" type="int" enum="TileSet.TileMode">
+ <argument index="1" name="mode" type="int" enum="TileSet.TerrainMode">
</argument>
<description>
- Sets the tile's [enum TileMode].
</description>
</method>
- <method name="tile_set_z_index">
+ <method name="set_terrains_count">
<return type="void">
</return>
- <argument index="0" name="id" type="int">
+ <argument index="0" name="terrain_set" type="int">
</argument>
- <argument index="1" name="z_index" type="int">
+ <argument index="1" name="terrains_count" type="int">
</argument>
<description>
- Sets the tile's drawing index.
</description>
</method>
</methods>
+ <members>
+ <member name="custom_data_layers_count" type="int" setter="set_custom_data_layers_count" getter="get_custom_data_layers_count" default="0">
+ </member>
+ <member name="navigation_layers_count" type="int" setter="set_navigation_layers_count" getter="get_navigation_layers_count" default="0">
+ </member>
+ <member name="occlusion_layers_count" type="int" setter="set_occlusion_layers_count" getter="get_occlusion_layers_count" default="0">
+ </member>
+ <member name="physics_layers_count" type="int" setter="set_physics_layers_count" getter="get_physics_layers_count" default="0">
+ </member>
+ <member name="terrains_sets_count" type="int" setter="set_terrain_sets_count" getter="get_terrain_sets_count" default="0">
+ </member>
+ <member name="tile_layout" type="int" setter="set_tile_layout" getter="get_tile_layout" enum="TileSet.TileLayout" default="0">
+ </member>
+ <member name="tile_offset_axis" type="int" setter="set_tile_offset_axis" getter="get_tile_offset_axis" enum="TileSet.TileOffsetAxis" default="0">
+ </member>
+ <member name="tile_shape" type="int" setter="set_tile_shape" getter="get_tile_shape" enum="TileSet.TileShape" default="0">
+ </member>
+ <member name="tile_size" type="Vector2i" setter="set_tile_size" getter="get_tile_size" default="Vector2i( 16, 16 )">
+ </member>
+ <member name="tile_skew" type="Vector2" setter="set_tile_skew" getter="get_tile_skew" default="Vector2( 0, 0 )">
+ </member>
+ <member name="uv_clipping" type="bool" setter="set_uv_clipping" getter="is_uv_clipping" default="false">
+ </member>
+ <member name="y_sorting" type="bool" setter="set_y_sorting" getter="is_y_sorting" default="false">
+ </member>
+ </members>
<constants>
- <constant name="BITMASK_2X2" value="0" enum="BitmaskMode">
+ <constant name="TILE_SHAPE_SQUARE" value="0" enum="TileShape">
+ Orthogonal orientation mode.
+ </constant>
+ <constant name="TILE_SHAPE_ISOMETRIC" value="1" enum="TileShape">
+ Isometric orientation mode.
+ </constant>
+ <constant name="TILE_SHAPE_HALF_OFFSET_SQUARE" value="2" enum="TileShape">
+ </constant>
+ <constant name="TILE_SHAPE_HEXAGON" value="3" enum="TileShape">
+ Hexagon orientation mode.
+ </constant>
+ <constant name="TILE_LAYOUT_STACKED" value="0" enum="TileLayout">
+ </constant>
+ <constant name="TILE_LAYOUT_STACKED_OFFSET" value="1" enum="TileLayout">
+ </constant>
+ <constant name="TILE_LAYOUT_STAIRS_RIGHT" value="2" enum="TileLayout">
+ </constant>
+ <constant name="TILE_LAYOUT_STAIRS_DOWN" value="3" enum="TileLayout">
+ </constant>
+ <constant name="TILE_LAYOUT_DIAMOND_RIGHT" value="4" enum="TileLayout">
+ </constant>
+ <constant name="TILE_LAYOUT_DIAMOND_DOWN" value="5" enum="TileLayout">
+ </constant>
+ <constant name="TILE_OFFSET_AXIS_HORIZONTAL" value="0" enum="TileOffsetAxis">
+ </constant>
+ <constant name="TILE_OFFSET_AXIS_VERTICAL" value="1" enum="TileOffsetAxis">
+ </constant>
+ <constant name="TileSet::CELL_NEIGHBOR_RIGHT_SIDE" value="0" enum="CellNeighbor">
+ </constant>
+ <constant name="TileSet::CELL_NEIGHBOR_RIGHT_CORNER" value="1" enum="CellNeighbor">
+ </constant>
+ <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE" value="2" enum="CellNeighbor">
+ </constant>
+ <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER" value="3" enum="CellNeighbor">
+ </constant>
+ <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_SIDE" value="4" enum="CellNeighbor">
</constant>
- <constant name="BITMASK_3X3_MINIMAL" value="1" enum="BitmaskMode">
+ <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_CORNER" value="5" enum="CellNeighbor">
</constant>
- <constant name="BITMASK_3X3" value="2" enum="BitmaskMode">
+ <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE" value="6" enum="CellNeighbor">
</constant>
- <constant name="BIND_TOPLEFT" value="1" enum="AutotileBindings">
+ <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER" value="7" enum="CellNeighbor">
</constant>
- <constant name="BIND_TOP" value="2" enum="AutotileBindings">
+ <constant name="TileSet::CELL_NEIGHBOR_LEFT_SIDE" value="8" enum="CellNeighbor">
</constant>
- <constant name="BIND_TOPRIGHT" value="4" enum="AutotileBindings">
+ <constant name="TileSet::CELL_NEIGHBOR_LEFT_CORNER" value="9" enum="CellNeighbor">
</constant>
- <constant name="BIND_LEFT" value="8" enum="AutotileBindings">
+ <constant name="TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE" value="10" enum="CellNeighbor">
</constant>
- <constant name="BIND_CENTER" value="16" enum="AutotileBindings">
+ <constant name="TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER" value="11" enum="CellNeighbor">
</constant>
- <constant name="BIND_RIGHT" value="32" enum="AutotileBindings">
+ <constant name="TileSet::CELL_NEIGHBOR_TOP_SIDE" value="12" enum="CellNeighbor">
</constant>
- <constant name="BIND_BOTTOMLEFT" value="64" enum="AutotileBindings">
+ <constant name="TileSet::CELL_NEIGHBOR_TOP_CORNER" value="13" enum="CellNeighbor">
</constant>
- <constant name="BIND_BOTTOM" value="128" enum="AutotileBindings">
+ <constant name="TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE" value="14" enum="CellNeighbor">
</constant>
- <constant name="BIND_BOTTOMRIGHT" value="256" enum="AutotileBindings">
+ <constant name="TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER" value="15" enum="CellNeighbor">
</constant>
- <constant name="SINGLE_TILE" value="0" enum="TileMode">
+ <constant name="TERRAIN_MODE_MATCH_CORNERS_AND_SIDES" value="0" enum="TerrainMode">
</constant>
- <constant name="AUTO_TILE" value="1" enum="TileMode">
+ <constant name="TERRAIN_MODE_MATCH_CORNERS" value="1" enum="TerrainMode">
</constant>
- <constant name="ATLAS_TILE" value="2" enum="TileMode">
+ <constant name="TERRAIN_MODE_MATCH_SIDES" value="2" enum="TerrainMode">
</constant>
</constants>
</class>
diff --git a/doc/classes/TileSetAtlasSource.xml b/doc/classes/TileSetAtlasSource.xml
new file mode 100644
index 0000000000..a7a304ca27
--- /dev/null
+++ b/doc/classes/TileSetAtlasSource.xml
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TileSetAtlasSource" inherits="TileSetSource" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="can_move_tile_in_atlas" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="new_atlas_coords" type="Vector2i" default="Vector2i( -1, -1 )">
+ </argument>
+ <argument index="2" name="new_size" type="Vector2i" default="Vector2i( -1, -1 )">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear_tiles_outside_texture">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="create_alternative_tile">
+ <return type="int">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="alternative_id_override" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="create_tile">
+ <return type="void">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="size" type="Vector2i" default="Vector2i( 1, 1 )">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_alternative_tile_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_alternative_tiles_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_atlas_grid_size" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_next_alternative_tile_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_tile_at_coords" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_tile_data" qualifiers="const">
+ <return type="Object">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_tile_id" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_tile_size_in_atlas" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_tile_texture_region" qualifiers="const">
+ <return type="Rect2i">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_tiles_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="has_alternative_tile" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="alternative_tile" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_tile" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_tiles_outside_texture">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="move_tile_in_atlas">
+ <return type="void">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="new_atlas_coords" type="Vector2i" default="Vector2i( -1, -1 )">
+ </argument>
+ <argument index="2" name="new_size" type="Vector2i" default="Vector2i( -1, -1 )">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_alternative_tile">
+ <return type="void">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="alternative_tile" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_tile">
+ <return type="void">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_alternative_tile_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="alternative_tile" type="int">
+ </argument>
+ <argument index="2" name="new_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="margins" type="Vector2i" setter="set_margins" getter="get_margins" default="Vector2i( 0, 0 )">
+ </member>
+ <member name="separation" type="Vector2i" setter="set_separation" getter="get_separation" default="Vector2i( 0, 0 )">
+ </member>
+ <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ </member>
+ <member name="tile_size" type="Vector2i" setter="set_texture_region_size" getter="get_texture_region_size" default="Vector2i( 16, 16 )">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/TileSetScenesCollectionSource.xml b/doc/classes/TileSetScenesCollectionSource.xml
new file mode 100644
index 0000000000..1a00eb51c0
--- /dev/null
+++ b/doc/classes/TileSetScenesCollectionSource.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TileSetScenesCollectionSource" inherits="TileSetSource" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="create_scene_tile">
+ <return type="int">
+ </return>
+ <argument index="0" name="packed_scene" type="PackedScene">
+ </argument>
+ <argument index="1" name="id_override" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_alternative_tile_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_alternative_tiles_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_next_scene_tile_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_scene_tile_display_placeholder" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_scene_tile_id">
+ <return type="int">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_scene_tile_scene" qualifiers="const">
+ <return type="PackedScene">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_scene_tiles_count">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_tile_id" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_tiles_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="has_alternative_tile" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <argument index="1" name="alternative_tile" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_scene_tile_id">
+ <return type="bool">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_tile" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="atlas_coords" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_scene_tile">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_scene_tile_display_placeholder">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="display_placeholder" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_scene_tile_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="new_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_scene_tile_scene">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="packed_scene" type="PackedScene">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/TileSetSource.xml b/doc/classes/TileSetSource.xml
new file mode 100644
index 0000000000..6a3029bb3f
--- /dev/null
+++ b/doc/classes/TileSetSource.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TileSetSource" inherits="Resource" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Time.xml b/doc/classes/Time.xml
new file mode 100644
index 0000000000..0c7c090e97
--- /dev/null
+++ b/doc/classes/Time.xml
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Time" inherits="Object" version="4.0">
+ <brief_description>
+ Time singleton for working with time.
+ </brief_description>
+ <description>
+ The Time singleton allows converting time between various formats and also getting time information from the system.
+ This class conforms with as many of the ISO 8601 standards as possible. All dates follow the Proleptic Gregorian calendar. As such, the day before [code]1582-10-15[/code] is [code]1582-10-14[/code], not [code]1582-10-04[/code]. The year before 1 AD (aka 1 BC) is number [code]0[/code], with the year before that (2 BC) being [code]-1[/code], etc.
+ Conversion methods assume "the same timezone", and do not handle timezone conversions or DST automatically. Leap seconds are also not handled, they must be done manually if desired. Suffixes such as "Z" are not handled, you need to strip them away manually.
+ [b]Important:[/b] The [code]_from_system[/code] methods use the system clock that the user can manually set. [b]Never use[/b] this method for precise time calculation since its results are subject to automatic adjustments by the user or the operating system. [b]Always use[/b] [method get_ticks_usec] or [method get_ticks_msec] for precise time calculation instead, since they are guaranteed to be monotonic (i.e. never decrease).
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_date_dict_from_system" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="utc" type="bool" default="false">
+ </argument>
+ <description>
+ Returns the current date as a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], and [code]dst[/code] (Daylight Savings Time).
+ The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC.
+ </description>
+ </method>
+ <method name="get_date_dict_from_unix_time" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="unix_time_val" type="int">
+ </argument>
+ <description>
+ Converts the given Unix timestamp to a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], and [code]weekday[/code].
+ </description>
+ </method>
+ <method name="get_date_string_from_system" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="utc" type="bool" default="false">
+ </argument>
+ <description>
+ Returns the current date as an ISO 8601 date string (YYYY-MM-DD).
+ The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC.
+ </description>
+ </method>
+ <method name="get_date_string_from_unix_time" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="unix_time_val" type="int">
+ </argument>
+ <description>
+ Converts the given Unix timestamp to an ISO 8601 date string (YYYY-MM-DD).
+ </description>
+ </method>
+ <method name="get_datetime_dict_from_string" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="datetime" type="String">
+ </argument>
+ <argument index="1" name="weekday" type="bool">
+ </argument>
+ <description>
+ Converts the given ISO 8601 date and time string (YYYY-MM-DDTHH:MM:SS) to a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code].
+ If [code]weekday[/code] is false, then the [code]weekday[/code] entry is excluded (the calculation is relatively expensive).
+ </description>
+ </method>
+ <method name="get_datetime_dict_from_system" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="utc" type="bool" default="false">
+ </argument>
+ <description>
+ Returns the current date as a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code].
+ </description>
+ </method>
+ <method name="get_datetime_dict_from_unix_time" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="unix_time_val" type="int">
+ </argument>
+ <description>
+ Converts the given Unix timestamp to a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], and [code]weekday[/code].
+ The returned Dictionary's values will be the same as the [method get_datetime_dict_from_system] if the Unix timestamp is the current time, with the exception of Daylight Savings Time as it cannot be determined from the epoch.
+ </description>
+ </method>
+ <method name="get_datetime_string_from_dict" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="datetime" type="Dictionary">
+ </argument>
+ <argument index="1" name="use_space" type="bool">
+ </argument>
+ <description>
+ Converts the given dictionary of keys to an ISO 8601 date and time string (YYYY-MM-DDTHH:MM:SS).
+ The given dictionary can be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code]. Any other entries (including [code]dst[/code]) are ignored.
+ If the dictionary is empty, [code]0[/code] is returned. If some keys are omitted, they default to the equivalent values for the Unix epoch timestamp 0 (1970-01-01 at 00:00:00).
+ If [code]use_space[/code] is true, use a space instead of the letter T in the middle.
+ </description>
+ </method>
+ <method name="get_datetime_string_from_system" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="utc" type="bool" default="false">
+ </argument>
+ <argument index="1" name="use_space" type="bool" default="false">
+ </argument>
+ <description>
+ Returns the current date and time 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], and [code]second[/code].
+ The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC.
+ If [code]use_space[/code] is true, use a space instead of the letter T in the middle.
+ </description>
+ </method>
+ <method name="get_datetime_string_from_unix_time" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="unix_time_val" type="int">
+ </argument>
+ <argument index="1" name="use_space" type="bool" default="false">
+ </argument>
+ <description>
+ Converts the given Unix timestamp to an ISO 8601 date and time string (YYYY-MM-DDTHH:MM:SS).
+ If [code]use_space[/code] is true, use a space instead of the letter T in the middle.
+ </description>
+ </method>
+ <method name="get_ticks_msec" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the amount of time passed in milliseconds since the engine started.
+ </description>
+ </method>
+ <method name="get_ticks_usec" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the amount of time passed in microseconds since the engine started.
+ </description>
+ </method>
+ <method name="get_time_dict_from_system" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="utc" type="bool" default="false">
+ </argument>
+ <description>
+ Returns the current time as a dictionary of keys: [code]hour[/code], [code]minute[/code], and [code]second[/code].
+ The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC.
+ </description>
+ </method>
+ <method name="get_time_dict_from_unix_time" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="unix_time_val" type="int">
+ </argument>
+ <description>
+ Converts the given time to a dictionary of keys: [code]hour[/code], [code]minute[/code], and [code]second[/code].
+ </description>
+ </method>
+ <method name="get_time_string_from_system" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="utc" type="bool" default="false">
+ </argument>
+ <description>
+ Returns the current time as an ISO 8601 time string (HH:MM:SS).
+ The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC.
+ </description>
+ </method>
+ <method name="get_time_string_from_unix_time" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="unix_time_val" type="int">
+ </argument>
+ <description>
+ Converts the given Unix timestamp to an ISO 8601 time string (HH:MM:SS).
+ </description>
+ </method>
+ <method name="get_time_zone_from_system" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <description>
+ Returns the current time zone as a dictionary of keys: [code]bias[/code] and [code]name[/code]. The [code]bias[/code] value is the offset from UTC in minutes, since not all time zones are multiples of an hour from UTC.
+ </description>
+ </method>
+ <method name="get_unix_time_from_datetime_dict" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="datetime" type="Dictionary">
+ </argument>
+ <description>
+ Converts a dictionary of time values to a Unix timestamp.
+ The given dictionary can be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code]. Any other entries (including [code]dst[/code]) are ignored.
+ If the dictionary is empty, [code]0[/code] is returned. If some keys are omitted, they default to the equivalent values for the Unix epoch timestamp 0 (1970-01-01 at 00:00:00).
+ You can pass the output from [method get_datetime_dict_from_unix_time] directly into this function and get the same as what was put in.
+ </description>
+ </method>
+ <method name="get_unix_time_from_datetime_string" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="datetime" type="String">
+ </argument>
+ <description>
+ Converts the given ISO 8601 date and/or time string to a Unix timestamp. The string can contain a date only, a time only, or both.
+ </description>
+ </method>
+ <method name="get_unix_time_from_system" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the current Unix timestamp in seconds based on the system time.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="MONTH_JANUARY" value="1" enum="Month">
+ The month of January, represented numerically as [code]01[/code].
+ </constant>
+ <constant name="MONTH_FEBRUARY" value="2" enum="Month">
+ The month of February, represented numerically as [code]02[/code].
+ </constant>
+ <constant name="MONTH_MARCH" value="3" enum="Month">
+ The month of March, represented numerically as [code]03[/code].
+ </constant>
+ <constant name="MONTH_APRIL" value="4" enum="Month">
+ The month of April, represented numerically as [code]04[/code].
+ </constant>
+ <constant name="MONTH_MAY" value="5" enum="Month">
+ The month of May, represented numerically as [code]05[/code].
+ </constant>
+ <constant name="MONTH_JUNE" value="6" enum="Month">
+ The month of June, represented numerically as [code]06[/code].
+ </constant>
+ <constant name="MONTH_JULY" value="7" enum="Month">
+ The month of July, represented numerically as [code]07[/code].
+ </constant>
+ <constant name="MONTH_AUGUST" value="8" enum="Month">
+ The month of August, represented numerically as [code]08[/code].
+ </constant>
+ <constant name="MONTH_SEPTEMBER" value="9" enum="Month">
+ The month of September, represented numerically as [code]09[/code].
+ </constant>
+ <constant name="MONTH_OCTOBER" value="10" enum="Month">
+ The month of October, represented numerically as [code]10[/code].
+ </constant>
+ <constant name="MONTH_NOVEMBER" value="11" enum="Month">
+ The month of November, represented numerically as [code]11[/code].
+ </constant>
+ <constant name="MONTH_DECEMBER" value="12" enum="Month">
+ The month of December, represented numerically as [code]12[/code].
+ </constant>
+ <constant name="WEEKDAY_SUNDAY" value="0" enum="Weekday">
+ The day of the week Sunday, represented numerically as [code]0[/code].
+ </constant>
+ <constant name="WEEKDAY_MONDAY" value="1" enum="Weekday">
+ The day of the week Monday, represented numerically as [code]1[/code].
+ </constant>
+ <constant name="WEEKDAY_TUESDAY" value="2" enum="Weekday">
+ The day of the week Tuesday, represented numerically as [code]2[/code].
+ </constant>
+ <constant name="WEEKDAY_WEDNESDAY" value="3" enum="Weekday">
+ The day of the week Wednesday, represented numerically as [code]3[/code].
+ </constant>
+ <constant name="WEEKDAY_THURSDAY" value="4" enum="Weekday">
+ The day of the week Thursday, represented numerically as [code]4[/code].
+ </constant>
+ <constant name="WEEKDAY_FRIDAY" value="5" enum="Weekday">
+ The day of the week Friday, represented numerically as [code]5[/code].
+ </constant>
+ <constant name="WEEKDAY_SATURDAY" value="6" enum="Weekday">
+ The day of the week Saturday, represented numerically as [code]6[/code].
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index 6ae7fbcf79..0dbf95376a 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -18,7 +18,7 @@
<return type="Transform2D">
</return>
<description>
- Constructs a default-initialized [Transform] set to [constant IDENTITY].
+ Constructs a default-initialized [Transform2D] set to [constant IDENTITY].
</description>
</method>
<method name="Transform2D" qualifiers="constructor">
@@ -129,6 +129,16 @@
Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
+ <method name="looking_at" qualifiers="const">
+ <return type="Transform2D">
+ </return>
+ <argument index="0" name="target" type="Vector2" default="Transform2D( 1, 0, 0, 1, 0, 0 )">
+ </argument>
+ <description>
+ Returns a copy of the transform rotated such that it's rotation on the X-axis points towards the [code]target[/code] position.
+ Operations take place in global space.
+ </description>
+ </method>
<method name="operator !=" qualifiers="operator">
<return type="bool">
</return>
@@ -138,33 +148,33 @@
</description>
</method>
<method name="operator *" qualifiers="operator">
- <return type="Vector2">
+ <return type="PackedVector2Array">
</return>
- <argument index="0" name="right" type="Vector2">
+ <argument index="0" name="right" type="PackedVector2Array">
</argument>
<description>
</description>
</method>
<method name="operator *" qualifiers="operator">
- <return type="Rect2">
+ <return type="Transform2D">
</return>
- <argument index="0" name="right" type="Rect2">
+ <argument index="0" name="right" type="Transform2D">
</argument>
<description>
</description>
</method>
<method name="operator *" qualifiers="operator">
- <return type="Transform2D">
+ <return type="Rect2">
</return>
- <argument index="0" name="right" type="Transform2D">
+ <argument index="0" name="right" type="Rect2">
</argument>
<description>
</description>
</method>
<method name="operator *" qualifiers="operator">
- <return type="PackedVector2Array">
+ <return type="Vector2">
</return>
- <argument index="0" name="right" type="PackedVector2Array">
+ <argument index="0" name="right" type="Vector2">
</argument>
<description>
</description>
@@ -210,6 +220,15 @@
Scales the transform by the given scale factor, using matrix multiplication.
</description>
</method>
+ <method name="set_rotation">
+ <return type="void">
+ </return>
+ <argument index="0" name="rotation" type="float">
+ </argument>
+ <description>
+ Sets the transform's rotation (in radians).
+ </description>
+ </method>
<method name="translated" qualifiers="const">
<return type="Transform2D">
</return>
diff --git a/doc/classes/Transform.xml b/doc/classes/Transform3D.xml
index 9d8721e2de..0d49255523 100644
--- a/doc/classes/Transform.xml
+++ b/doc/classes/Transform3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Transform" version="4.0">
+<class name="Transform3D" version="4.0">
<brief_description>
3D transformation (3×4 matrix).
</brief_description>
@@ -16,35 +16,35 @@
<link title="2.5D Demo">https://godotengine.org/asset-library/asset/583</link>
</tutorials>
<methods>
- <method name="Transform" qualifiers="constructor">
- <return type="Transform">
+ <method name="Transform3D" qualifiers="constructor">
+ <return type="Transform3D">
</return>
<description>
- Constructs a default-initialized [Transform] set to [constant IDENTITY].
+ Constructs a default-initialized [Transform3D] set to [constant IDENTITY].
</description>
</method>
- <method name="Transform" qualifiers="constructor">
- <return type="Transform">
+ <method name="Transform3D" qualifiers="constructor">
+ <return type="Transform3D">
</return>
- <argument index="0" name="from" type="Transform">
+ <argument index="0" name="from" type="Transform3D">
</argument>
<description>
- Constructs a [Transform] as a copy of the given [Transform].
+ Constructs a [Transform3D] as a copy of the given [Transform3D].
</description>
</method>
- <method name="Transform" qualifiers="constructor">
- <return type="Transform">
+ <method name="Transform3D" qualifiers="constructor">
+ <return type="Transform3D">
</return>
<argument index="0" name="basis" type="Basis">
</argument>
<argument index="1" name="origin" type="Vector3">
</argument>
<description>
- Constructs a Transform from a [Basis] and [Vector3].
+ Constructs a Transform3D from a [Basis] and [Vector3].
</description>
</method>
- <method name="Transform" qualifiers="constructor">
- <return type="Transform">
+ <method name="Transform3D" qualifiers="constructor">
+ <return type="Transform3D">
</return>
<argument index="0" name="x_axis" type="Vector3">
</argument>
@@ -55,29 +55,29 @@
<argument index="3" name="origin" type="Vector3">
</argument>
<description>
- Constructs a Transform from four [Vector3] values (matrix columns). Each axis corresponds to local basis vectors (some of which may be scaled).
+ Constructs a Transform3D from four [Vector3] values (matrix columns). Each axis corresponds to local basis vectors (some of which may be scaled).
</description>
</method>
<method name="affine_inverse" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.
</description>
</method>
<method name="interpolate_with" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
- <argument index="0" name="xform" type="Transform">
+ <argument index="0" name="xform" type="Transform3D">
</argument>
<argument index="1" name="weight" type="float">
</argument>
<description>
- Interpolates the transform to other Transform by weight amount (on the range of 0.0 to 1.0).
+ Interpolates the transform to other Transform3D by weight amount (on the range of 0.0 to 1.0).
</description>
</method>
<method name="inverse" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use affine_inverse for transforms with scaling).
@@ -86,14 +86,14 @@
<method name="is_equal_approx" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="xform" type="Transform">
+ <argument index="0" name="xform" type="Transform3D">
</argument>
<description>
Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
<method name="looking_at" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="target" type="Vector3">
</argument>
@@ -108,7 +108,7 @@
<method name="operator !=" qualifiers="operator">
<return type="bool">
</return>
- <argument index="0" name="right" type="Transform">
+ <argument index="0" name="right" type="Transform3D">
</argument>
<description>
</description>
@@ -122,9 +122,9 @@
</description>
</method>
<method name="operator *" qualifiers="operator">
- <return type="Transform">
+ <return type="Transform3D">
</return>
- <argument index="0" name="right" type="Transform">
+ <argument index="0" name="right" type="Transform3D">
</argument>
<description>
</description>
@@ -148,20 +148,20 @@
<method name="operator ==" qualifiers="operator">
<return type="bool">
</return>
- <argument index="0" name="right" type="Transform">
+ <argument index="0" name="right" type="Transform3D">
</argument>
<description>
</description>
</method>
<method name="orthonormalized" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<description>
Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors.
</description>
</method>
<method name="rotated" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="axis" type="Vector3">
</argument>
@@ -172,7 +172,7 @@
</description>
</method>
<method name="scaled" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="scale" type="Vector3">
</argument>
@@ -181,7 +181,7 @@
</description>
</method>
<method name="translated" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="offset" type="Vector3">
</argument>
@@ -200,17 +200,17 @@
</member>
</members>
<constants>
- <constant name="IDENTITY" value="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
- [Transform] with no translation, rotation or scaling applied. When applied to other data structures, [constant IDENTITY] performs no transformation.
+ <constant name="IDENTITY" value="Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ [Transform3D] with no translation, rotation or scaling applied. When applied to other data structures, [constant IDENTITY] performs no transformation.
</constant>
- <constant name="FLIP_X" value="Transform( -1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
- [Transform] with mirroring applied perpendicular to the YZ plane.
+ <constant name="FLIP_X" value="Transform3D( -1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ [Transform3D] with mirroring applied perpendicular to the YZ plane.
</constant>
- <constant name="FLIP_Y" value="Transform( 1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0 )">
- [Transform] with mirroring applied perpendicular to the XZ plane.
+ <constant name="FLIP_Y" value="Transform3D( 1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0 )">
+ [Transform3D] with mirroring applied perpendicular to the XZ plane.
</constant>
- <constant name="FLIP_Z" value="Transform( 1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0 )">
- [Transform] with mirroring applied perpendicular to the XY plane.
+ <constant name="FLIP_Z" value="Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0 )">
+ [Transform3D] with mirroring applied perpendicular to the XY plane.
</constant>
</constants>
</class>
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index a09f1bf470..fe83bf9c2d 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -30,7 +30,7 @@
}
[/csharp]
[/codeblocks]
- To iterate over all the [TreeItem] objects in a [Tree] object, use [method TreeItem.get_next] and [method TreeItem.get_children] after getting the root through [method get_root]. You can use [method Object.free] on a [TreeItem] to remove it from the [Tree].
+ To iterate over all the [TreeItem] objects in a [Tree] object, use [method TreeItem.get_next] and [method TreeItem.get_first_child] after getting the root through [method get_root]. You can use [method Object.free] on a [TreeItem] to remove it from the [Tree].
</description>
<tutorials>
</tutorials>
@@ -361,7 +361,7 @@
The number of columns.
</member>
<member name="drop_mode_flags" type="int" setter="set_drop_mode_flags" getter="get_drop_mode_flags" default="0">
- 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.
+ 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.
This controls the drop sections, i.e. the decision and drawing of possible drop locations based on the mouse position.
</member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" override="true" enum="Control.FocusMode" default="2" />
@@ -533,6 +533,12 @@
<theme_item name="checked" type="Texture2D">
The check icon to display when the [constant TreeItem.CELL_MODE_CHECK] mode cell is checked.
</theme_item>
+ <theme_item name="children_hl_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )">
+ The [Color] of the relationship lines between the selected [TreeItem] and its children.
+ </theme_item>
+ <theme_item name="children_hl_line_width" type="int" default="1">
+ The width of the relationship lines between the selected [TreeItem] and its children.
+ </theme_item>
<theme_item name="cursor" type="StyleBox">
[StyleBox] used for the cursor, when the [Tree] is being focused.
</theme_item>
@@ -587,8 +593,20 @@
<theme_item name="outline_size" type="int" default="0">
The size of the text outline.
</theme_item>
+ <theme_item name="parent_hl_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )">
+ The [Color] of the relationship lines between the selected [TreeItem] and its parents.
+ </theme_item>
+ <theme_item name="parent_hl_line_margin" type="int" default="0">
+ The space between the parent relationship lines for the selected [TreeItem] and the relationship lines to its siblings that are not selected.
+ </theme_item>
+ <theme_item name="parent_hl_line_width" type="int" default="1">
+ The width of the relationship lines between the selected [TreeItem] and its parents.
+ </theme_item>
<theme_item name="relationship_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )">
- [Color] of the relationship lines.
+ The default [Color] of the relationship lines.
+ </theme_item>
+ <theme_item name="relationship_line_width" type="int" default="1">
+ The default width of the relationship lines.
</theme_item>
<theme_item name="scroll_border" type="int" default="4">
The maximum distance between the mouse cursor and the control's border to trigger border scrolling when dragging.
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index add23c2ce6..0256d83fea 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -63,6 +63,16 @@
Removes all OpenType features.
</description>
</method>
+ <method name="create_child">
+ <return type="TreeItem">
+ </return>
+ <argument index="0" name="idx" type="int" default="-1">
+ </argument>
+ <description>
+ Creates an item and adds it as a child.
+ The new item will be inserted as position [code]idx[/code] (the default value [code]-1[/code] means the last position), or it will be the last child if [code]idx[/code] is higher than the child count.
+ </description>
+ </method>
<method name="deselect">
<return type="void">
</return>
@@ -123,11 +133,28 @@
Returns the column's cell mode.
</description>
</method>
- <method name="get_children">
+ <method name="get_child">
<return type="TreeItem">
</return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns a child item by its index (see [method get_child_count]). This method is often used for iterating all children of an item.
+ Negative indices access the children from the last one.
+ </description>
+ </method>
+ <method name="get_child_count">
+ <return type="int">
+ </return>
<description>
- Returns the TreeItem's first child item or a null object if there is none.
+ Returns the number of child items.
+ </description>
+ </method>
+ <method name="get_children">
+ <return type="Array">
+ </return>
+ <description>
+ Returns an array of references to the item's children.
</description>
</method>
<method name="get_custom_bg_color" qualifiers="const">
@@ -148,6 +175,14 @@
Returns the custom color of column [code]column[/code].
</description>
</method>
+ <method name="get_custom_font" qualifiers="const">
+ <return type="Font">
+ </return>
+ <argument index="0" name="column" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="get_expand_right" qualifiers="const">
<return type="bool">
</return>
@@ -157,6 +192,13 @@
Returns [code]true[/code] if [code]expand_right[/code] is set.
</description>
</method>
+ <method name="get_first_child">
+ <return type="TreeItem">
+ </return>
+ <description>
+ Returns the TreeItem's first child.
+ </description>
+ </method>
<method name="get_icon" qualifiers="const">
<return type="Texture2D">
</return>
@@ -193,6 +235,13 @@
Returns the icon [Texture2D] region as [Rect2].
</description>
</method>
+ <method name="get_index">
+ <return type="int">
+ </return>
+ <description>
+ Returns the node's order in the tree. For example, if called on the first child item the position is [code]0[/code].
+ </description>
+ </method>
<method name="get_language" qualifiers="const">
<return type="String">
</return>
@@ -342,6 +391,13 @@
Returns the given column's tooltip.
</description>
</method>
+ <method name="get_tree">
+ <return type="Tree">
+ </return>
+ <description>
+ Returns the [Tree] that owns this TreeItem.
+ </description>
+ </method>
<method name="is_button_disabled" qualifiers="const">
<return type="bool">
</return>
@@ -397,18 +453,24 @@
Returns [code]true[/code] if column [code]column[/code] is selected.
</description>
</method>
- <method name="move_to_bottom">
+ <method name="move_after">
<return type="void">
</return>
+ <argument index="0" name="item" type="Object">
+ </argument>
<description>
- Moves this TreeItem to the bottom in the [Tree] hierarchy.
+ Moves this TreeItem right after the given [code]item[/code].
+ [b]Note:[/b] You can't move to the root or move the root.
</description>
</method>
- <method name="move_to_top">
+ <method name="move_before">
<return type="void">
</return>
+ <argument index="0" name="item" type="Object">
+ </argument>
<description>
- Moves this TreeItem to the top in the [Tree] hierarchy.
+ Moves this TreeItem right before the given [code]item[/code].
+ [b]Note:[/b] You can't move to the root or move the root.
</description>
</method>
<method name="remove_child">
@@ -525,6 +587,16 @@
The [code]callback[/code] should accept two arguments: the [TreeItem] that is drawn and its position and size as a [Rect2].
</description>
</method>
+ <method name="set_custom_font">
+ <return type="void">
+ </return>
+ <argument index="0" name="column" type="int">
+ </argument>
+ <argument index="1" name="font" type="Font">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_editable">
<return type="void">
</return>
diff --git a/doc/classes/TriangleMesh.xml b/doc/classes/TriangleMesh.xml
index 39bee0c2b3..cfdb6fe33e 100644
--- a/doc/classes/TriangleMesh.xml
+++ b/doc/classes/TriangleMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TriangleMesh" inherits="Reference" version="4.0">
+<class name="TriangleMesh" inherits="RefCounted" version="4.0">
<brief_description>
Internal mesh type.
</brief_description>
diff --git a/doc/classes/TubeTrailMesh.xml b/doc/classes/TubeTrailMesh.xml
new file mode 100644
index 0000000000..2782791a62
--- /dev/null
+++ b/doc/classes/TubeTrailMesh.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TubeTrailMesh" inherits="PrimitiveMesh" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="curve" type="Curve" setter="set_curve" getter="get_curve">
+ </member>
+ <member name="radial_steps" type="int" setter="set_radial_steps" getter="get_radial_steps" default="8">
+ </member>
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ </member>
+ <member name="section_length" type="float" setter="set_section_length" getter="get_section_length" default="0.2">
+ </member>
+ <member name="section_rings" type="int" setter="set_section_rings" getter="get_section_rings" default="3">
+ </member>
+ <member name="sections" type="int" setter="set_sections" getter="get_sections" default="5">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/UDPServer.xml b/doc/classes/UDPServer.xml
index 0fc00f67f8..5e2906450c 100644
--- a/doc/classes/UDPServer.xml
+++ b/doc/classes/UDPServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="UDPServer" inherits="Reference" version="4.0">
+<class name="UDPServer" inherits="RefCounted" version="4.0">
<brief_description>
Helper class to implement a UDP server.
</brief_description>
@@ -123,6 +123,13 @@
<tutorials>
</tutorials>
<methods>
+ <method name="get_local_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the local port this server is listening to.
+ </description>
+ </method>
<method name="is_connection_available" qualifiers="const">
<return type="bool">
</return>
@@ -145,7 +152,7 @@
<argument index="1" name="bind_address" type="String" default="&quot;*&quot;">
</argument>
<description>
- Starts the server by opening a UDP socket listening on the given port. You can optionally specify a [code]bind_address[/code] to only listen for packets sent to that address. See also [method PacketPeerUDP.listen].
+ Starts the server by opening a UDP socket listening on the given port. You can optionally specify a [code]bind_address[/code] to only listen for packets sent to that address. See also [method PacketPeerUDP.bind].
</description>
</method>
<method name="poll">
diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml
index 775bd58bcf..240c1c909f 100644
--- a/doc/classes/Variant.xml
+++ b/doc/classes/Variant.xml
@@ -5,20 +5,30 @@
</brief_description>
<description>
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.
- [codeblock]
+ [codeblocks]
+ [gdscript]
var foo = 2 # foo is dynamically an integer
foo = "Now foo is a string!"
- foo = Reference.new() # foo is an Object
+ foo = RefCounted.new() # foo is an Object
var bar: int = 2 # bar is a statically typed integer.
# bar = "Uh oh! I can't make static variables become a different type!"
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ // ... but C# is statically typed. Once a variable has a type it cannot be changed. However you can use the var keyword in methods to let the compiler decide the type automatically.
+ var foo = 2; // Foo is a 32-bit integer (int). Be cautious, integers in GDScript are 64-bit and the direct C# equivalent is "long".
+ // foo = "foo was and will always be an integer. It cannot be turned into a string!";
+ var boo = "Boo is a string!";
+ var ref = new Reference(); // var is especially useful when used together with a constructor.
+ [/csharp]
+ [/codeblocks]
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.
- 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.
- 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.
- 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.
- 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.
The global [method @GlobalScope.typeof] function returns the enumerated value of the Variant type stored in the current variable (see [enum Variant.Type]).
- [codeblock]
+ [codeblocks]
+ [gdscript]
var foo = 2
match typeof(foo):
TYPE_NIL:
@@ -32,7 +42,19 @@
# Note also that there is not yet any way to get a script's `class_name` string easily.
# To fetch that value, you need to dig deeply into a hidden ProjectSettings setting: an Array of Dictionaries called "_global_script_classes".
# Open your project.godot file to see it up close.
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ int foo = 2;
+ if (foo == null)
+ {
+ GD.Print("foo is null");
+ }
+ if (foo is int)
+ {
+ GD.Print("foo is an integer");
+ }
+ [/csharp]
+ [/codeblocks]
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.
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.
A Variant:
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index b979425b85..1390a5e45b 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -110,13 +110,15 @@
Returns the vector with all components rounded up (towards positive infinity).
</description>
</method>
- <method name="clamped" qualifiers="const">
+ <method name="clamp" qualifiers="const">
<return type="Vector2">
</return>
- <argument index="0" name="length" type="float">
+ <argument index="0" name="min" type="Vector2">
+ </argument>
+ <argument index="1" name="max" type="Vector2">
</argument>
<description>
- Returns the vector with a maximum length by limiting its length to [code]length[/code].
+ Returns a new vector with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
</description>
</method>
<method name="cross" qualifiers="const">
@@ -229,7 +231,16 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of the linear interpolation between this vector and [code]to[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ </description>
+ </method>
+ <method name="limit_length" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="length" type="float" default="1.0">
+ </argument>
+ <description>
+ Returns the vector with a maximum length by limiting its length to [code]length[/code].
</description>
</method>
<method name="move_toward" qualifiers="const">
@@ -464,7 +475,7 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the result of spherical linear interpolation between this vector and [code]b[/code], by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of spherical linear interpolation between this vector and [code]to[/code], by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
[b]Note:[/b] Both vectors must be normalized.
</description>
</method>
diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml
index b38b968ba3..6efb52b712 100644
--- a/doc/classes/Vector2i.xml
+++ b/doc/classes/Vector2i.xml
@@ -64,6 +64,17 @@
Returns the ratio of [member x] to [member y].
</description>
</method>
+ <method name="clamp" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="min" type="Vector2i">
+ </argument>
+ <argument index="1" name="max" type="Vector2i">
+ </argument>
+ <description>
+ Returns a new vector with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
+ </description>
+ </method>
<method name="operator !=" qualifiers="operator">
<return type="bool">
</return>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index bd568e01ec..b6effd441b 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -87,6 +87,17 @@
Returns a new vector with all components rounded up (towards positive infinity).
</description>
</method>
+ <method name="clamp" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="min" type="Vector3">
+ </argument>
+ <argument index="1" name="max" type="Vector3">
+ </argument>
+ <description>
+ Returns a new vector with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
+ </description>
+ </method>
<method name="cross" qualifiers="const">
<return type="Vector3">
</return>
@@ -204,7 +215,16 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of the linear interpolation between this vector and [code]to[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ </description>
+ </method>
+ <method name="limit_length" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="length" type="float" default="1.0">
+ </argument>
+ <description>
+ Returns the vector with a maximum length by limiting its length to [code]length[/code].
</description>
</method>
<method name="max_axis" qualifiers="const">
@@ -266,7 +286,7 @@
<method name="operator *" qualifiers="operator">
<return type="Vector3">
</return>
- <argument index="0" name="right" type="Quat">
+ <argument index="0" name="right" type="Quaternion">
</argument>
<description>
</description>
@@ -274,7 +294,7 @@
<method name="operator *" qualifiers="operator">
<return type="Vector3">
</return>
- <argument index="0" name="right" type="Transform">
+ <argument index="0" name="right" type="Transform3D">
</argument>
<description>
</description>
@@ -484,7 +504,7 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the result of spherical linear interpolation between this vector and [code]b[/code], by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of spherical linear interpolation between this vector and [code]to[/code], by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
[b]Note:[/b] Both vectors must be normalized.
</description>
</method>
diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml
index ea5945f5b7..6e8a34b692 100644
--- a/doc/classes/Vector3i.xml
+++ b/doc/classes/Vector3i.xml
@@ -58,6 +58,17 @@
<description>
</description>
</method>
+ <method name="clamp" qualifiers="const">
+ <return type="Vector3i">
+ </return>
+ <argument index="0" name="min" type="Vector3i">
+ </argument>
+ <argument index="1" name="max" type="Vector3i">
+ </argument>
+ <description>
+ Returns a new vector with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
+ </description>
+ </method>
<method name="max_axis" qualifiers="const">
<return type="int">
</return>
diff --git a/doc/classes/VelocityTracker3D.xml b/doc/classes/VelocityTracker3D.xml
index 98f7533c76..2d5e3a4d30 100644
--- a/doc/classes/VelocityTracker3D.xml
+++ b/doc/classes/VelocityTracker3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VelocityTracker3D" inherits="Reference" version="4.0">
+<class name="VelocityTracker3D" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/VideoPlayer.xml b/doc/classes/VideoPlayer.xml
index d905ce4054..12558ebbbc 100644
--- a/doc/classes/VideoPlayer.xml
+++ b/doc/classes/VideoPlayer.xml
@@ -60,7 +60,7 @@
<member name="buffering_msec" type="int" setter="set_buffering_msec" getter="get_buffering_msec" default="500">
Amount of time in milliseconds to store in buffer while playing.
</member>
- <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="@&quot;Master&quot;">
+ <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&amp;&quot;Master&quot;">
Audio bus to use for sound playback.
</member>
<member name="expand" type="bool" setter="set_expand" getter="has_expand" default="true">
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 471d21374d..292be34a0d 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -81,10 +81,16 @@
<description>
Returns the viewport's texture.
[b]Note:[/b] Due to the way OpenGL works, the resulting [ViewportTexture] is flipped vertically. You can use [method Image.flip_y] on the result of [method Texture2D.get_image] to flip it back, for example:
- [codeblock]
+ [codeblocks]
+ [gdscript]
var img = get_viewport().get_texture().get_image()
img.flip_y()
- [/codeblock]
+ [/gdscript]
+ [csharp]
+ Image img = GetViewport().GetTexture().GetImage();
+ img.FlipY();
+ [/csharp]
+ [/codeblocks]
</description>
</method>
<method name="get_viewport_rid" qualifiers="const">
@@ -105,7 +111,7 @@
<return type="Variant">
</return>
<description>
- Returns the drag data from the GUI, that was previously returned by [method Control.get_drag_data].
+ Returns the drag data from the GUI, that was previously returned by [method Control._get_drag_data].
</description>
</method>
<method name="gui_is_dragging" qualifiers="const">
@@ -173,13 +179,6 @@
<description>
</description>
</method>
- <method name="update_worlds">
- <return type="void">
- </return>
- <description>
- Forces update of the 2D and 3D worlds.
- </description>
- </method>
<method name="warp_mouse">
<return type="void">
</return>
@@ -267,6 +266,11 @@
</member>
<member name="use_debanding" type="bool" setter="set_use_debanding" getter="is_using_debanding" default="false">
</member>
+ <member name="use_occlusion_culling" type="bool" setter="set_use_occlusion_culling" getter="is_using_occlusion_culling" default="false">
+ </member>
+ <member name="use_xr" type="bool" setter="set_use_xr" getter="is_using_xr" default="false">
+ If [code]true[/code], the viewport will use the primary XR interface to render XR output. When applicable this can result in a stereoscopic image and the resulting render being output to a headset.
+ </member>
<member name="world_2d" type="World2D" setter="set_world_2d" getter="get_world_2d">
The custom [World2D] which can be used as 2D environment source.
</member>
@@ -377,14 +381,14 @@
</constant>
<constant name="DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="DebugDraw">
</constant>
- <constant name="DEBUG_DRAW_GI_PROBE_ALBEDO" value="6" enum="DebugDraw">
- Objects are displayed with only the albedo value from [GIProbe]s.
+ <constant name="DEBUG_DRAW_VOXEL_GI_ALBEDO" value="6" enum="DebugDraw">
+ Objects are displayed with only the albedo value from [VoxelGI]s.
</constant>
- <constant name="DEBUG_DRAW_GI_PROBE_LIGHTING" value="7" enum="DebugDraw">
- Objects are displayed with only the lighting value from [GIProbe]s.
+ <constant name="DEBUG_DRAW_VOXEL_GI_LIGHTING" value="7" enum="DebugDraw">
+ Objects are displayed with only the lighting value from [VoxelGI]s.
</constant>
- <constant name="DEBUG_DRAW_GI_PROBE_EMISSION" value="8" enum="DebugDraw">
- Objects are displayed with only the emission color from [GIProbe]s.
+ <constant name="DEBUG_DRAW_VOXEL_GI_EMISSION" value="8" enum="DebugDraw">
+ Objects are displayed with only the emission color from [VoxelGI]s.
</constant>
<constant name="DEBUG_DRAW_SHADOW_ATLAS" value="9" enum="DebugDraw">
Draws the shadow atlas that stores shadows from [OmniLight3D]s and [SpotLight3D]s in the upper left quadrant of the [Viewport].
@@ -419,6 +423,8 @@
</constant>
<constant name="DEBUG_DRAW_CLUSTER_REFLECTION_PROBES" value="22" enum="DebugDraw">
</constant>
+ <constant name="DEBUG_DRAW_OCCLUDERS" value="23" enum="DebugDraw">
+ </constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST" value="0" enum="DefaultCanvasItemTextureFilter">
The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
</constant>
diff --git a/doc/classes/VisibilityEnabler2D.xml b/doc/classes/VisibilityEnabler2D.xml
index 02fe7a7cd0..8eb16ba075 100644
--- a/doc/classes/VisibilityEnabler2D.xml
+++ b/doc/classes/VisibilityEnabler2D.xml
@@ -1,79 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisibilityEnabler2D" inherits="VisibilityNotifier2D" version="4.0">
<brief_description>
- Enables certain nodes only when approximately visible.
</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.
- If you just want to receive notifications, use [VisibilityNotifier2D] instead.
- [b]Note:[/b] For performance reasons, VisibilityEnabler2D uses an approximate heuristic with precision determined by [member ProjectSettings.world/2d/cell_size]. If you need precise visibility checking, use another method such as adding an [Area2D] node as a child of a [Camera2D] node.
- [b]Note:[/b] VisibilityEnabler2D 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="VisibilityEnabler2D.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="VisibilityEnabler2D.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], [RigidBody2D] nodes will be paused.
+ <member name="enable_mode" type="int" setter="set_enable_mode" getter="get_enable_mode" enum="VisibilityEnabler2D.EnableMode" default="0">
</member>
- <member name="pause_animated_sprites" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
- 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], [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.
- </member>
- <member name="process_parent" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="false">
- If [code]true[/code], the parent's [method Node._process] will be stopped.
+ <member name="enable_node_path" type="NodePath" setter="set_enable_node_path" getter="get_enable_node_path" default="NodePath(&quot;..&quot;)">
</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 [RigidBody2D] nodes.
- </constant>
- <constant name="ENABLER_PAUSE_PARTICLES" value="2" enum="Enabler">
- 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.
- </constant>
- <constant name="ENABLER_PARENT_PHYSICS_PROCESS" value="4" enum="Enabler">
- This enabler will stop the parent's _physics_process function.
+ <constant name="ENABLE_MODE_INHERIT" value="0" enum="EnableMode">
</constant>
- <constant name="ENABLER_PAUSE_ANIMATED_SPRITES" value="5" enum="Enabler">
- This enabler will stop [AnimatedSprite2D] nodes animations.
+ <constant name="ENABLE_MODE_ALWAYS" value="1" enum="EnableMode">
</constant>
- <constant name="ENABLER_MAX" value="6" enum="Enabler">
- Represents the size of the [enum Enabler] enum.
+ <constant name="ENABLE_MODE_WHEN_PAUSED" value="2" enum="EnableMode">
</constant>
</constants>
</class>
diff --git a/doc/classes/VisibilityEnabler3D.xml b/doc/classes/VisibilityEnabler3D.xml
index d78ebb55f2..4614859a44 100644
--- a/doc/classes/VisibilityEnabler3D.xml
+++ b/doc/classes/VisibilityEnabler3D.xml
@@ -12,44 +12,19 @@
<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 name="enable_mode" type="int" setter="set_enable_mode" getter="get_enable_mode" enum="VisibilityEnabler3D.EnableMode" default="0">
</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 name="enable_node_path" type="NodePath" setter="set_enable_node_path" getter="get_enable_node_path" default="NodePath(&quot;..&quot;)">
</member>
</members>
<constants>
- <constant name="ENABLER_PAUSE_ANIMATIONS" value="0" enum="Enabler">
- This enabler will pause [AnimationPlayer] nodes.
+ <constant name="ENABLE_MODE_INHERIT" value="0" enum="EnableMode">
</constant>
- <constant name="ENABLER_FREEZE_BODIES" value="1" enum="Enabler">
- This enabler will freeze [RigidBody3D] nodes.
+ <constant name="ENABLE_MODE_ALWAYS" value="1" enum="EnableMode">
</constant>
- <constant name="ENABLER_MAX" value="2" enum="Enabler">
- Represents the size of the [enum Enabler] enum.
+ <constant name="ENABLE_MODE_WHEN_PAUSED" value="2" enum="EnableMode">
</constant>
</constants>
</class>
diff --git a/doc/classes/VisibilityNotifier2D.xml b/doc/classes/VisibilityNotifier2D.xml
index 761438b77e..78983e74ee 100644
--- a/doc/classes/VisibilityNotifier2D.xml
+++ b/doc/classes/VisibilityNotifier2D.xml
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisibilityNotifier2D" inherits="Node2D" version="4.0">
<brief_description>
- Detects approximately when the node is visible on screen.
+ Detects when the node extents are visible on screen.
</brief_description>
<description>
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.
If you want nodes to be disabled automatically when they exit the screen, use [VisibilityEnabler2D] instead.
- [b]Note:[/b] For performance reasons, VisibilityNotifier2D uses an approximate heuristic with precision determined by [member ProjectSettings.world/2d/cell_size]. If you need precise visibility checking, use another method such as adding an [Area2D] node as a child of a [Camera2D] node.
</description>
<tutorials>
<link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link>
@@ -37,20 +36,6 @@
Emitted when the VisibilityNotifier2D exits the screen.
</description>
</signal>
- <signal name="viewport_entered">
- <argument index="0" name="viewport" type="Viewport">
- </argument>
- <description>
- Emitted when the VisibilityNotifier2D enters a [Viewport]'s view.
- </description>
- </signal>
- <signal name="viewport_exited">
- <argument index="0" name="viewport" type="Viewport">
- </argument>
- <description>
- Emitted when the VisibilityNotifier2D exits a [Viewport]'s view.
- </description>
- </signal>
</signals>
<constants>
</constants>
diff --git a/doc/classes/VisibilityNotifier3D.xml b/doc/classes/VisibilityNotifier3D.xml
index e5d3116612..bd6c03ea20 100644
--- a/doc/classes/VisibilityNotifier3D.xml
+++ b/doc/classes/VisibilityNotifier3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisibilityNotifier3D" inherits="Node3D" version="4.0">
+<class name="VisibilityNotifier3D" inherits="VisualInstance3D" version="4.0">
<brief_description>
Detects approximately when the node is visible on screen.
</brief_description>
@@ -26,20 +26,6 @@
</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.
diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml
index 01d569d9c8..2a12254b71 100644
--- a/doc/classes/VisualInstance3D.xml
+++ b/doc/classes/VisualInstance3D.xml
@@ -44,7 +44,7 @@
</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]. See also [method get_aabb].
+ Transformed in this case means the [AABB] plus the position, rotation, and scale of the [Node3D]'s [Transform3D]. See also [method get_aabb].
</description>
</method>
<method name="set_base">
diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml
index ff00a848b9..775ac88eff 100644
--- a/doc/classes/VisualShader.xml
+++ b/doc/classes/VisualShader.xml
@@ -222,15 +222,19 @@
<constant name="TYPE_LIGHT" value="2" enum="Type">
A shader for light calculations.
</constant>
- <constant name="TYPE_EMIT" value="3" enum="Type">
+ <constant name="TYPE_START" value="3" enum="Type">
</constant>
<constant name="TYPE_PROCESS" value="4" enum="Type">
</constant>
- <constant name="TYPE_END" value="5" enum="Type">
+ <constant name="TYPE_COLLIDE" value="5" enum="Type">
</constant>
- <constant name="TYPE_SKY" value="6" enum="Type">
+ <constant name="TYPE_START_CUSTOM" value="6" enum="Type">
</constant>
- <constant name="TYPE_MAX" value="7" enum="Type">
+ <constant name="TYPE_PROCESS_CUSTOM" value="7" enum="Type">
+ </constant>
+ <constant name="TYPE_SKY" value="8" enum="Type">
+ </constant>
+ <constant name="TYPE_MAX" value="9" enum="Type">
Represents the size of the [enum Type] enum.
</constant>
<constant name="NODE_ID_INVALID" value="-1">
diff --git a/doc/classes/VisualShaderNode.xml b/doc/classes/VisualShaderNode.xml
index 6327ab534f..9a74f2322e 100644
--- a/doc/classes/VisualShaderNode.xml
+++ b/doc/classes/VisualShaderNode.xml
@@ -9,6 +9,13 @@
<link title="VisualShaders">https://docs.godotengine.org/en/latest/tutorials/shading/visual_shaders.html</link>
</tutorials>
<methods>
+ <method name="clear_default_input_values">
+ <return type="void">
+ </return>
+ <description>
+ Clears the default input ports value.
+ </description>
+ </method>
<method name="get_default_input_values" qualifiers="const">
<return type="Array">
</return>
@@ -25,6 +32,15 @@
Returns the default value of the input [code]port[/code].
</description>
</method>
+ <method name="remove_input_port_default_value">
+ <return type="void">
+ </return>
+ <argument index="0" name="port" type="int">
+ </argument>
+ <description>
+ Removes the default value of the input [code]port[/code].
+ </description>
+ </method>
<method name="set_default_input_values">
<return type="void">
</return>
diff --git a/doc/classes/VisualShaderNodeBillboard.xml b/doc/classes/VisualShaderNodeBillboard.xml
new file mode 100644
index 0000000000..53bcfa7b5c
--- /dev/null
+++ b/doc/classes/VisualShaderNodeBillboard.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeBillboard" inherits="VisualShaderNode" version="4.0">
+ <brief_description>
+ A node that controls how the object faces the camera to be used within the visual shader graph.
+ </brief_description>
+ <description>
+ The output port of this node needs to be connected to [code]Model View Matrix[/code] port of [VisualShaderNodeOutput].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="billboard_type" type="int" setter="set_billboard_type" getter="get_billboard_type" enum="VisualShaderNodeBillboard.BillboardType" default="1">
+ Controls how the object faces the camera. See [enum BillboardType].
+ </member>
+ <member name="keep_scale" type="bool" setter="set_keep_scale_enabled" getter="is_keep_scale_enabled" default="false">
+ If [code]true[/code], the shader will keep the scale set for the mesh. Otherwise, the scale is lost when billboarding.
+ </member>
+ </members>
+ <constants>
+ <constant name="BILLBOARD_TYPE_DISABLED" value="0" enum="BillboardType">
+ Billboarding is disabled and the node does nothing.
+ </constant>
+ <constant name="BILLBOARD_TYPE_ENABLED" value="1" enum="BillboardType">
+ A standard billboarding algorithm is enabled.
+ </constant>
+ <constant name="BILLBOARD_TYPE_FIXED_Y" value="2" enum="BillboardType">
+ A billboarding algorithm to rotate around Y-axis is enabled.
+ </constant>
+ <constant name="BILLBOARD_TYPE_PARTICLES" value="3" enum="BillboardType">
+ A billboarding algorithm designed to use on particles is enabled.
+ </constant>
+ <constant name="BILLBOARD_TYPE_MAX" value="4" enum="BillboardType">
+ Represents the size of the [enum BillboardType] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeDeterminant.xml b/doc/classes/VisualShaderNodeDeterminant.xml
index 6b042f6172..06b05addfa 100644
--- a/doc/classes/VisualShaderNodeDeterminant.xml
+++ b/doc/classes/VisualShaderNodeDeterminant.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeDeterminant" inherits="VisualShaderNode" version="4.0">
<brief_description>
- Calculates the determinant of a [Transform] within the visual shader graph.
+ Calculates the determinant of a [Transform3D] within the visual shader graph.
</brief_description>
<description>
Translates to [code]determinant(x)[/code] in the shader language.
diff --git a/doc/classes/VisualShaderNodeParticleAccelerator.xml b/doc/classes/VisualShaderNodeParticleAccelerator.xml
new file mode 100644
index 0000000000..82aae1df63
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParticleAccelerator.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParticleAccelerator" inherits="VisualShaderNodeOutput" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="VisualShaderNodeParticleAccelerator.Mode" default="0">
+ </member>
+ </members>
+ <constants>
+ <constant name="MODE_LINEAR" value="0" enum="Mode">
+ </constant>
+ <constant name="MODE_RADIAL" value="1" enum="Mode">
+ </constant>
+ <constant name="MODE_TANGENTIAL" value="2" enum="Mode">
+ </constant>
+ <constant name="MODE_MAX" value="3" enum="Mode">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeParticleBoxEmitter.xml b/doc/classes/VisualShaderNodeParticleBoxEmitter.xml
new file mode 100644
index 0000000000..af33b285d2
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParticleBoxEmitter.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParticleBoxEmitter" inherits="VisualShaderNodeParticleEmitter" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeParticleConeVelocity.xml b/doc/classes/VisualShaderNodeParticleConeVelocity.xml
new file mode 100644
index 0000000000..7a40c2a7d0
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParticleConeVelocity.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParticleConeVelocity" inherits="VisualShaderNode" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeParticleEmit.xml b/doc/classes/VisualShaderNodeParticleEmit.xml
new file mode 100644
index 0000000000..120b12d643
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParticleEmit.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParticleEmit" inherits="VisualShaderNode" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="flags" type="int" setter="set_flags" getter="get_flags" enum="VisualShaderNodeParticleEmit.EmitFlags" default="31">
+ </member>
+ </members>
+ <constants>
+ <constant name="EMIT_FLAG_POSITION" value="1" enum="EmitFlags">
+ </constant>
+ <constant name="EMIT_FLAG_ROT_SCALE" value="2" enum="EmitFlags">
+ </constant>
+ <constant name="EMIT_FLAG_VELOCITY" value="4" enum="EmitFlags">
+ </constant>
+ <constant name="EMIT_FLAG_COLOR" value="8" enum="EmitFlags">
+ </constant>
+ <constant name="EMIT_FLAG_CUSTOM" value="16" enum="EmitFlags">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeParticleEmitter.xml b/doc/classes/VisualShaderNodeParticleEmitter.xml
new file mode 100644
index 0000000000..3a25fc1c7f
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParticleEmitter.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParticleEmitter" inherits="VisualShaderNode" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml b/doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml
new file mode 100644
index 0000000000..89a53699c9
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParticleMultiplyByAxisAngle" inherits="VisualShaderNode" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="degrees_mode" type="bool" setter="set_degrees_mode" getter="is_degrees_mode" default="true">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeParticleOutput.xml b/doc/classes/VisualShaderNodeParticleOutput.xml
new file mode 100644
index 0000000000..c8fc66f2ff
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParticleOutput.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParticleOutput" inherits="VisualShaderNodeOutput" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeParticleRandomness.xml b/doc/classes/VisualShaderNodeParticleRandomness.xml
new file mode 100644
index 0000000000..f19723a663
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParticleRandomness.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParticleRandomness" inherits="VisualShaderNode" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="op_type" type="int" setter="set_op_type" getter="get_op_type" enum="VisualShaderNodeParticleRandomness.OpType" default="0">
+ </member>
+ </members>
+ <constants>
+ <constant name="OP_TYPE_SCALAR" value="0" enum="OpType">
+ </constant>
+ <constant name="OP_TYPE_VECTOR" value="1" enum="OpType">
+ </constant>
+ <constant name="OP_TYPE_MAX" value="2" enum="OpType">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeParticleRingEmitter.xml b/doc/classes/VisualShaderNodeParticleRingEmitter.xml
new file mode 100644
index 0000000000..ee3fbe7faf
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParticleRingEmitter.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParticleRingEmitter" inherits="VisualShaderNodeParticleEmitter" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeParticleSphereEmitter.xml b/doc/classes/VisualShaderNodeParticleSphereEmitter.xml
new file mode 100644
index 0000000000..d43ac518cf
--- /dev/null
+++ b/doc/classes/VisualShaderNodeParticleSphereEmitter.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeParticleSphereEmitter" inherits="VisualShaderNodeParticleEmitter" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualShaderNodeTransformCompose.xml b/doc/classes/VisualShaderNodeTransformCompose.xml
index 41762b0099..b82ce9bdd8 100644
--- a/doc/classes/VisualShaderNodeTransformCompose.xml
+++ b/doc/classes/VisualShaderNodeTransformCompose.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTransformCompose" inherits="VisualShaderNode" version="4.0">
<brief_description>
- Composes a [Transform] from four [Vector3]s within the visual shader graph.
+ Composes a [Transform3D] from four [Vector3]s within the visual shader graph.
</brief_description>
<description>
Creates a 4x4 transform matrix using four vectors of type [code]vec3[/code]. Each vector is one row in the matrix and the last column is a [code]vec4(0, 0, 0, 1)[/code].
diff --git a/doc/classes/VisualShaderNodeTransformConstant.xml b/doc/classes/VisualShaderNodeTransformConstant.xml
index b8f054e914..550ed829c9 100644
--- a/doc/classes/VisualShaderNodeTransformConstant.xml
+++ b/doc/classes/VisualShaderNodeTransformConstant.xml
@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTransformConstant" inherits="VisualShaderNodeConstant" version="4.0">
<brief_description>
- A [Transform] constant for use within the visual shader graph.
+ A [Transform3D] constant for use within the visual shader graph.
</brief_description>
<description>
- A constant [Transform], which can be used as an input node.
+ A constant [Transform3D], which can be used as an input node.
</description>
<tutorials>
</tutorials>
<methods>
</methods>
<members>
- <member name="constant" type="Transform" setter="set_constant" getter="get_constant" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
- A [Transform] constant which represents the state of this node.
+ <member name="constant" type="Transform3D" setter="set_constant" getter="get_constant" default="Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ A [Transform3D] constant which represents the state of this node.
</member>
</members>
<constants>
diff --git a/doc/classes/VisualShaderNodeTransformDecompose.xml b/doc/classes/VisualShaderNodeTransformDecompose.xml
index c8d893db00..b815efc67a 100644
--- a/doc/classes/VisualShaderNodeTransformDecompose.xml
+++ b/doc/classes/VisualShaderNodeTransformDecompose.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTransformDecompose" inherits="VisualShaderNode" version="4.0">
<brief_description>
- Decomposes a [Transform] into four [Vector3]s within the visual shader graph.
+ Decomposes a [Transform3D] into four [Vector3]s within the visual shader graph.
</brief_description>
<description>
Takes a 4x4 transform matrix and decomposes it into four [code]vec3[/code] values, one from each row of the matrix.
diff --git a/doc/classes/VisualShaderNodeTransformFunc.xml b/doc/classes/VisualShaderNodeTransformFunc.xml
index d0b5c5129d..41a58e1458 100644
--- a/doc/classes/VisualShaderNodeTransformFunc.xml
+++ b/doc/classes/VisualShaderNodeTransformFunc.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTransformFunc" inherits="VisualShaderNode" version="4.0">
<brief_description>
- Computes a [Transform] function within the visual shader graph.
+ Computes a [Transform3D] function within the visual shader graph.
</brief_description>
<description>
- Computes an inverse or transpose function on the provided [Transform].
+ Computes an inverse or transpose function on the provided [Transform3D].
</description>
<tutorials>
</tutorials>
@@ -17,10 +17,10 @@
</members>
<constants>
<constant name="FUNC_INVERSE" value="0" enum="Function">
- Perform the inverse operation on the [Transform] matrix.
+ Perform the inverse operation on the [Transform3D] matrix.
</constant>
<constant name="FUNC_TRANSPOSE" value="1" enum="Function">
- Perform the transpose operation on the [Transform] matrix.
+ Perform the transpose operation on the [Transform3D] matrix.
</constant>
</constants>
</class>
diff --git a/doc/classes/VisualShaderNodeTransformMult.xml b/doc/classes/VisualShaderNodeTransformMult.xml
index 02b6e0cd1c..f26f60a1f3 100644
--- a/doc/classes/VisualShaderNodeTransformMult.xml
+++ b/doc/classes/VisualShaderNodeTransformMult.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTransformMult" inherits="VisualShaderNode" version="4.0">
<brief_description>
- Multiplies [Transform] by [Transform] within the visual shader graph.
+ Multiplies [Transform3D] by [Transform3D] within the visual shader graph.
</brief_description>
<description>
A multiplication operation on two transforms (4x4 matrices), with support for different multiplication operators.
diff --git a/doc/classes/VisualShaderNodeTransformUniform.xml b/doc/classes/VisualShaderNodeTransformUniform.xml
index ff6246618d..1f1cc4b630 100644
--- a/doc/classes/VisualShaderNodeTransformUniform.xml
+++ b/doc/classes/VisualShaderNodeTransformUniform.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTransformUniform" inherits="VisualShaderNodeUniform" version="4.0">
<brief_description>
- A [Transform] uniform for use within the visual shader graph.
+ A [Transform3D] uniform for use within the visual shader graph.
</brief_description>
<description>
Translated to [code]uniform mat4[/code] in the shader language.
@@ -11,7 +11,7 @@
<methods>
</methods>
<members>
- <member name="default_value" type="Transform" setter="set_default_value" getter="get_default_value" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ <member name="default_value" type="Transform3D" setter="set_default_value" getter="get_default_value" default="Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
A default value to be assigned within the shader.
</member>
<member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false">
diff --git a/doc/classes/VisualShaderNodeTransformVecMult.xml b/doc/classes/VisualShaderNodeTransformVecMult.xml
index 3d5f87f727..2c9c115d9c 100644
--- a/doc/classes/VisualShaderNodeTransformVecMult.xml
+++ b/doc/classes/VisualShaderNodeTransformVecMult.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTransformVecMult" inherits="VisualShaderNode" version="4.0">
<brief_description>
- Multiplies a [Transform] and a [Vector3] within the visual shader graph.
+ Multiplies a [Transform3D] and a [Vector3] within the visual shader graph.
</brief_description>
<description>
A multiplication operation on a transform (4x4 matrix) and a vector, with support for different multiplication operators.
diff --git a/doc/classes/VisualShaderNodeUVFunc.xml b/doc/classes/VisualShaderNodeUVFunc.xml
new file mode 100644
index 0000000000..042644feb0
--- /dev/null
+++ b/doc/classes/VisualShaderNodeUVFunc.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeUVFunc" inherits="VisualShaderNode" version="4.0">
+ <brief_description>
+ Contains functions to modify texture coordinates ([code]uv[/code]) to be used within the visual shader graph.
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="function" type="int" setter="set_function" getter="get_function" enum="VisualShaderNodeUVFunc.Function" default="0">
+ A function to be applied to the texture coordinates. See [enum Function] for options.
+ </member>
+ </members>
+ <constants>
+ <constant name="FUNC_PANNING" value="0" enum="Function">
+ Translates [code]uv[/code] by using [code]scale[/code] and [code]offset[/code] values using the following formula: [code]uv = uv + offset * scale[/code]. [code]uv[/code] port is connected to [code]UV[/code] built-in by default.
+ </constant>
+ <constant name="FUNC_SCALING" value="1" enum="Function">
+ Scales [code]uv[/uv] by using [code]scale[/code] and [code]pivot[/code] values using the following formula: [code]uv = (uv - pivot) * scale + pivot[/code]. [code]uv[/code] port is connected to [code]UV[/code] built-in by default.
+ </constant>
+ <constant name="FUNC_MAX" value="2" enum="Function">
+ Represents the size of the [enum Function] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/GIProbe.xml b/doc/classes/VoxelGI.xml
index 4f56d1ad3e..fa5035349e 100644
--- a/doc/classes/GIProbe.xml
+++ b/doc/classes/VoxelGI.xml
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GIProbe" inherits="VisualInstance3D" version="4.0">
+<class name="VoxelGI" inherits="VisualInstance3D" version="4.0">
<brief_description>
Real-time global illumination (GI) probe.
</brief_description>
<description>
- [GIProbe]s are used to provide high-quality real-time indirect light to scenes. They precompute the effect of objects that emit light and the effect of static geometry to simulate the behavior of complex light in real-time. [GIProbe]s need to be baked before using, however, once baked, dynamic objects will receive light from them. Further, lights can be fully dynamic or baked.
- Having [GIProbe]s in a scene can be expensive, the quality of the probe can be turned down in exchange for better performance in the [ProjectSettings] using [member ProjectSettings.rendering/global_illumination/gi_probes/quality].
+ [VoxelGI]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. [VoxelGI]s need to be baked before using, however, once baked, dynamic objects will receive light from them. Further, lights can be fully dynamic or baked.
+ Having [VoxelGI]s in a scene can be expensive, the quality of the probe can be turned down in exchange for better performance in the [ProjectSettings] using [member ProjectSettings.rendering/global_illumination/voxel_gi/quality].
[b]Note:[/b] Meshes should have sufficiently thick walls to avoid light leaks (avoid one-sided walls). For interior levels, enclose your level geometry in a sufficiently large box and bridge the loops to close the mesh.
</description>
<tutorials>
- <link title="GI probes">https://docs.godotengine.org/en/latest/tutorials/3d/gi_probes.html</link>
+ <link title="GI probes">https://docs.godotengine.org/en/latest/tutorials/3d/voxel_gi.html</link>
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
</tutorials>
<methods>
@@ -21,7 +21,7 @@
<argument index="1" name="create_visual_debug" type="bool" default="false">
</argument>
<description>
- Bakes the effect from all [GeometryInstance3D]s marked with [constant GeometryInstance3D.GI_MODE_BAKED] and [Light3D]s marked with either [constant Light3D.BAKE_DYNAMIC] or [constant Light3D.BAKE_STATIC]. 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 [constant GeometryInstance3D.GI_MODE_BAKED] and [Light3D]s marked with either [constant Light3D.BAKE_DYNAMIC] or [constant Light3D.BAKE_STATIC]. 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 [VoxelGI]'s data and debug any issues that may be occurring.
</description>
</method>
<method name="debug_bake">
@@ -33,14 +33,14 @@
</method>
</methods>
<members>
- <member name="data" type="GIProbeData" setter="set_probe_data" getter="get_probe_data">
- The [GIProbeData] resource that holds the data for this [GIProbe].
+ <member name="data" type="VoxelGIData" setter="set_probe_data" getter="get_probe_data">
+ The [VoxelGIData] resource that holds the data for this [VoxelGI].
</member>
<member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 10, 10, 10 )">
- 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.
+ The size of the area covered by the [VoxelGI]. 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.
</member>
- <member name="subdiv" type="int" setter="set_subdiv" getter="get_subdiv" enum="GIProbe.Subdiv" default="1">
- 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.
+ <member name="subdiv" type="int" setter="set_subdiv" getter="get_subdiv" enum="VoxelGI.Subdiv" default="1">
+ Number of times to subdivide the grid that the [VoxelGI] operates on. A higher number results in finer detail and thus higher visual quality, while lower numbers result in better performance.
</member>
</members>
<constants>
diff --git a/doc/classes/GIProbeData.xml b/doc/classes/VoxelGIData.xml
index 693df8f819..88a0411e2b 100644
--- a/doc/classes/GIProbeData.xml
+++ b/doc/classes/VoxelGIData.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GIProbeData" inherits="Resource" version="4.0">
+<class name="VoxelGIData" inherits="Resource" version="4.0">
<brief_description>
</brief_description>
<description>
@@ -11,7 +11,7 @@
<method name="allocate">
<return type="void">
</return>
- <argument index="0" name="to_cell_xform" type="Transform">
+ <argument index="0" name="to_cell_xform" type="Transform3D">
</argument>
<argument index="1" name="aabb" type="AABB">
</argument>
@@ -59,7 +59,7 @@
</description>
</method>
<method name="get_to_cell_xform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<description>
</description>
diff --git a/doc/classes/WeakRef.xml b/doc/classes/WeakRef.xml
index 4140df5828..6c9a7de67f 100644
--- a/doc/classes/WeakRef.xml
+++ b/doc/classes/WeakRef.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WeakRef" inherits="Reference" version="4.0">
+<class name="WeakRef" inherits="RefCounted" version="4.0">
<brief_description>
Holds an [Object], but does not contribute to the reference count if the object is a reference.
</brief_description>
<description>
- A weakref can hold a [Reference], without contributing to the reference counter. A weakref can be created from an [Object] using [method @GlobalScope.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.
+ A weakref can hold a [RefCounted], without contributing to the reference counter. A weakref can be created from an [Object] using [method @GlobalScope.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.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index b99a251a11..9c320747d1 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -45,7 +45,7 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
</description>
@@ -55,7 +55,7 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
</description>
@@ -65,10 +65,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns the [Font] at [code]name[/code] if the theme has [code]type[/code].
+ Returns the [Font] at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="get_theme_font_size" qualifiers="const">
@@ -76,10 +76,10 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns the font size at [code]name[/code] if the theme has [code]type[/code].
+ Returns the font size at [code]name[/code] if the theme has [code]theme_type[/code].
</description>
</method>
<method name="get_theme_icon" qualifiers="const">
@@ -87,7 +87,7 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
</description>
@@ -97,7 +97,7 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
</description>
@@ -119,7 +119,7 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
</description>
@@ -129,7 +129,7 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
</description>
@@ -139,11 +139,11 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns [code]true[/code] if [Font] with [code]name[/code] is in [code]type[/code].
- Returns [code]false[/code] if the theme does not have [code]type[/code].
+ Returns [code]true[/code] if [Font] with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
</description>
</method>
<method name="has_theme_font_size" qualifiers="const">
@@ -151,11 +151,11 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
- Returns [code]true[/code] if font size with [code]name[/code] is in [code]type[/code].
- Returns [code]false[/code] if the theme does not have [code]type[/code].
+ Returns [code]true[/code] if font size with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
</description>
</method>
<method name="has_theme_icon" qualifiers="const">
@@ -163,7 +163,7 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
</description>
@@ -173,7 +173,7 @@
</return>
<argument index="0" name="name" type="StringName">
</argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;">
</argument>
<description>
</description>
@@ -340,6 +340,8 @@
</member>
<member name="theme" type="Theme" setter="set_theme" getter="get_theme">
</member>
+ <member name="theme_custom_type" type="StringName" setter="set_theme_custom_type" getter="get_theme_custom_type" default="&amp;&quot;&quot;">
+ </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">
diff --git a/doc/classes/XMLParser.xml b/doc/classes/XMLParser.xml
index 2849ea62ab..ab5c58c51c 100644
--- a/doc/classes/XMLParser.xml
+++ b/doc/classes/XMLParser.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XMLParser" inherits="Reference" version="4.0">
+<class name="XMLParser" inherits="RefCounted" version="4.0">
<brief_description>
Low-level class for creating parsers for [url=https://en.wikipedia.org/wiki/XML]XML[/url] files.
</brief_description>
diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml
index 034cb51be3..fec98007c3 100644
--- a/doc/classes/XRInterface.xml
+++ b/doc/classes/XRInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRInterface" inherits="Reference" version="4.0">
+<class name="XRInterface" inherits="RefCounted" version="4.0">
<brief_description>
Base class for an AR/VR interface implementation.
</brief_description>
@@ -46,6 +46,13 @@
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="get_view_count">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of views that need to be rendered for this device. 1 for Monoscopic, 2 for Stereoscopic.
+ </description>
+ </method>
<method name="initialize">
<return type="bool">
</return>
@@ -57,13 +64,6 @@
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>
diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml
index 5274d952fd..cd8cb71cd9 100644
--- a/doc/classes/XRPositionalTracker.xml
+++ b/doc/classes/XRPositionalTracker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRPositionalTracker" inherits="Reference" version="4.0">
+<class name="XRPositionalTracker" inherits="RefCounted" version="4.0">
<brief_description>
A tracked object.
</brief_description>
@@ -69,7 +69,7 @@
</description>
</method>
<method name="get_transform" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<argument index="0" name="adjust_by_reference_frame" type="bool">
</argument>
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index d0edf91fed..149e177700 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -63,7 +63,7 @@
</description>
</method>
<method name="get_hmd_transform">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<description>
Returns the primary interface's transformation.
@@ -96,7 +96,7 @@
<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].
+ 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 Time.get_ticks_usec].
</description>
</method>
<method name="get_last_frame_usec">
@@ -110,11 +110,11 @@
<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].
+ Returns the absolute timestamp (in μs) of the last [XRServer] process callback. The value comes from an internal call to [method Time.get_ticks_usec].
</description>
</method>
<method name="get_reference_frame" qualifiers="const">
- <return type="Transform">
+ <return type="Transform3D">
</return>
<description>
Returns the reference frame transform. Mostly used internally and exposed for GDNative build interfaces.
diff --git a/doc/classes/YSort.xml b/doc/classes/YSort.xml
deleted file mode 100644
index 4ef6a4b4ec..0000000000
--- a/doc/classes/YSort.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="YSort" inherits="Node2D" version="4.0">
- <brief_description>
- Sort all child nodes based on their Y positions.
- </brief_description>
- <description>
- 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.
- 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.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="sort_enabled" type="bool" setter="set_sort_enabled" getter="is_sort_enabled" default="true">
- If [code]true[/code], child nodes are sorted, otherwise sorting is disabled.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/float.xml b/doc/classes/float.xml
index 11f6d91b05..f75c130039 100644
--- a/doc/classes/float.xml
+++ b/doc/classes/float.xml
@@ -113,12 +113,12 @@
</description>
</method>
<method name="operator *" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
- <argument index="0" name="right" type="Quat">
+ <argument index="0" name="right" type="Quaternion">
</argument>
<description>
- Multiplies each component of the [Quat] by the given [float].
+ Multiplies each component of the [Quaternion] by the given [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
diff --git a/doc/classes/int.xml b/doc/classes/int.xml
index 119cdf8eeb..b0ad963998 100644
--- a/doc/classes/int.xml
+++ b/doc/classes/int.xml
@@ -183,9 +183,9 @@
</description>
</method>
<method name="operator *" qualifiers="operator">
- <return type="Quat">
+ <return type="Quaternion">
</return>
- <argument index="0" name="right" type="Quat">
+ <argument index="0" name="right" type="Quaternion">
</argument>
<description>
Multiplies each component of the quaternion by the given integer.
diff --git a/doc/translations/ar.po b/doc/translations/ar.po
index b4ae664714..77a3d39f27 100644
--- a/doc/translations/ar.po
+++ b/doc/translations/ar.po
@@ -33036,7 +33036,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33055,12 +33055,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34557,7 +34557,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41765,30 +41765,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41796,7 +41796,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54060,7 +54060,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59139,7 +59139,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/ca.po b/doc/translations/ca.po
index 6485111b20..8ea801181d 100644
--- a/doc/translations/ca.po
+++ b/doc/translations/ca.po
@@ -33067,7 +33067,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33086,12 +33086,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34588,7 +34588,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41796,30 +41796,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41827,7 +41827,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54091,7 +54091,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59170,7 +59170,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/classes.pot b/doc/translations/classes.pot
index d14b0d9b1f..f138276364 100644
--- a/doc/translations/classes.pot
+++ b/doc/translations/classes.pot
@@ -20685,9 +20685,9 @@ msgid ""
"onready var expression = Expression.new()\n"
"\n"
"func _ready():\n"
-" $LineEdit.connect(\"text_entered\", self, \"_on_text_entered\")\n"
+" $LineEdit.connect(\"text_submitted\", self, \"_on_text_submitted\")\n"
"\n"
-"func _on_text_entered(command):\n"
+"func _on_text_submitted(command):\n"
" var error = expression.parse(command, [])\n"
" if error != OK:\n"
" print(expression.get_error_text())\n"
@@ -33037,7 +33037,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33056,12 +33056,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -33187,7 +33187,7 @@ msgid ""
"Examples:\n"
"[codeblock]\n"
"connect(\"pressed\", self, \"_on_Button_pressed\") # BaseButton signal\n"
-"connect(\"text_entered\", self, \"_on_LineEdit_text_entered\") # LineEdit "
+"connect(\"text_submitted\", self, \"_on_LineEdit_text_submitted\") # LineEdit "
"signal\n"
"connect(\"hit\", self, \"_on_Player_hit\", [ weapon_type, damage ]) # User-"
"defined signal\n"
@@ -34558,7 +34558,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41766,30 +41766,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41797,7 +41797,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54061,7 +54061,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59140,7 +59140,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/cs.po b/doc/translations/cs.po
index 7b958a5049..a267656497 100644
--- a/doc/translations/cs.po
+++ b/doc/translations/cs.po
@@ -33536,7 +33536,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33555,12 +33555,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -35058,7 +35058,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -42266,30 +42266,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -42297,7 +42297,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54562,7 +54562,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59645,7 +59645,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/de.po b/doc/translations/de.po
index 2e3e219ba6..181d64d525 100644
--- a/doc/translations/de.po
+++ b/doc/translations/de.po
@@ -33453,7 +33453,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33472,12 +33472,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
#, fuzzy
msgid ""
@@ -34984,7 +34984,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -42226,30 +42226,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -42257,7 +42257,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54558,7 +54558,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59796,7 +59796,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/es.po b/doc/translations/es.po
index 3078c1bf90..7df36316b7 100644
--- a/doc/translations/es.po
+++ b/doc/translations/es.po
@@ -44834,7 +44834,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -44853,9 +44853,9 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
"Toda clase que no es un tipo integrado hereda de esta clase.\n"
"Puedes construir Objetos desde lenguajes de scripting, usando [code]Object."
@@ -44866,7 +44866,7 @@ msgstr ""
"llama al método [method free] desde tu script o elimina la instancia desde C+"
"+.\n"
"Algunas clases que extienden a Object añaden gestión de memoria. Este es el "
-"caso de [Reference], que cuenta las referencias y se borra a sí misma "
+"caso de [RefCounted], que cuenta las referencias y se borra a sí misma "
"automáticamente cuando deja de estar referenciada. [Node], otro tipo "
"fundamental, borra todos sus hijos cuando se libera de la memoria.\n"
"Los objetos exportan propiedades, que son principalmente útiles para el "
@@ -44887,7 +44887,7 @@ msgstr ""
"sencilla de notificar al objeto sobre diferentes eventos, de modo que todos "
"ellos pueden ser manejados juntos. Véase [method _notification]."
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
#, fuzzy
msgid ""
@@ -46525,7 +46525,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -53779,30 +53779,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -53810,7 +53810,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -66189,7 +66189,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -71348,7 +71348,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/fa.po b/doc/translations/fa.po
index 733d3bb969..e440146dd3 100644
--- a/doc/translations/fa.po
+++ b/doc/translations/fa.po
@@ -33042,7 +33042,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33061,12 +33061,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34563,7 +34563,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41771,30 +41771,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41802,7 +41802,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54066,7 +54066,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59145,7 +59145,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/fi.po b/doc/translations/fi.po
index 0a40863a52..92ec4f29dd 100644
--- a/doc/translations/fi.po
+++ b/doc/translations/fi.po
@@ -33055,7 +33055,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33074,12 +33074,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34576,7 +34576,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41784,30 +41784,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41815,7 +41815,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54080,7 +54080,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59168,7 +59168,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/fr.po b/doc/translations/fr.po
index f3e26ebc61..7717474c0f 100644
--- a/doc/translations/fr.po
+++ b/doc/translations/fr.po
@@ -33403,7 +33403,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33422,12 +33422,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34927,7 +34927,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -42142,30 +42142,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -42173,7 +42173,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54519,7 +54519,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59618,7 +59618,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/id.po b/doc/translations/id.po
index 1bce3d6b50..edfd392f4f 100644
--- a/doc/translations/id.po
+++ b/doc/translations/id.po
@@ -33068,7 +33068,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33087,12 +33087,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34589,7 +34589,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41797,30 +41797,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41828,7 +41828,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54092,7 +54092,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59171,7 +59171,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/it.po b/doc/translations/it.po
index 18e162476c..353eae4116 100644
--- a/doc/translations/it.po
+++ b/doc/translations/it.po
@@ -33334,7 +33334,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33353,12 +33353,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34856,7 +34856,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -42067,30 +42067,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -42098,7 +42098,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54365,7 +54365,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59459,7 +59459,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/ja.po b/doc/translations/ja.po
index ede80a35ef..1424b24153 100644
--- a/doc/translations/ja.po
+++ b/doc/translations/ja.po
@@ -34306,7 +34306,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -34325,12 +34325,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
#, fuzzy
msgid ""
@@ -35830,7 +35830,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -43046,30 +43046,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -43077,7 +43077,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -55349,7 +55349,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -60446,7 +60446,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/ko.po b/doc/translations/ko.po
index e71cd06ba7..8e8aef2eaf 100644
--- a/doc/translations/ko.po
+++ b/doc/translations/ko.po
@@ -33044,7 +33044,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33063,12 +33063,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34565,7 +34565,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41773,30 +41773,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41804,7 +41804,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54068,7 +54068,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59149,7 +59149,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/nl.po b/doc/translations/nl.po
index 032ff95bdb..096e59f497 100644
--- a/doc/translations/nl.po
+++ b/doc/translations/nl.po
@@ -33070,7 +33070,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33089,12 +33089,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34591,7 +34591,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41799,30 +41799,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41830,7 +41830,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54094,7 +54094,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59173,7 +59173,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/pl.po b/doc/translations/pl.po
index b0c94b55be..5ef41b155a 100644
--- a/doc/translations/pl.po
+++ b/doc/translations/pl.po
@@ -33089,7 +33089,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33108,12 +33108,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34610,7 +34610,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41818,30 +41818,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41849,7 +41849,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54117,7 +54117,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59203,7 +59203,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/pt_BR.po b/doc/translations/pt_BR.po
index a508d38859..ef62950d51 100644
--- a/doc/translations/pt_BR.po
+++ b/doc/translations/pt_BR.po
@@ -33083,7 +33083,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33102,12 +33102,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34604,7 +34604,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41812,30 +41812,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41843,7 +41843,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54108,7 +54108,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59194,7 +59194,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/ro.po b/doc/translations/ro.po
index 96c0161312..5f018aa497 100644
--- a/doc/translations/ro.po
+++ b/doc/translations/ro.po
@@ -33044,7 +33044,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33063,12 +33063,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34565,7 +34565,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41773,30 +41773,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41804,7 +41804,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54068,7 +54068,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59147,7 +59147,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/ru.po b/doc/translations/ru.po
index 1108967bc9..0d227beff7 100644
--- a/doc/translations/ru.po
+++ b/doc/translations/ru.po
@@ -33581,7 +33581,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33600,12 +33600,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -35104,7 +35104,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -42362,30 +42362,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -42393,7 +42393,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54666,7 +54666,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59891,7 +59891,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/sr_Cyrl.po b/doc/translations/sr_Cyrl.po
index d7d2911b97..d53711d996 100644
--- a/doc/translations/sr_Cyrl.po
+++ b/doc/translations/sr_Cyrl.po
@@ -33054,7 +33054,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33073,12 +33073,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34575,7 +34575,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41783,30 +41783,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41814,7 +41814,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54078,7 +54078,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59157,7 +59157,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/th.po b/doc/translations/th.po
index 5031ecfb0e..7686e22f19 100644
--- a/doc/translations/th.po
+++ b/doc/translations/th.po
@@ -33060,7 +33060,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33079,12 +33079,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34581,7 +34581,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41789,30 +41789,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41820,7 +41820,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54084,7 +54084,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59163,7 +59163,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/tr.po b/doc/translations/tr.po
index a317f4ee83..df9897f1d6 100644
--- a/doc/translations/tr.po
+++ b/doc/translations/tr.po
@@ -33036,7 +33036,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33055,12 +33055,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34557,7 +34557,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41765,30 +41765,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41796,7 +41796,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54060,7 +54060,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59139,7 +59139,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/uk.po b/doc/translations/uk.po
index 8ca75e8b19..d1296da87a 100644
--- a/doc/translations/uk.po
+++ b/doc/translations/uk.po
@@ -33122,7 +33122,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33141,12 +33141,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34643,7 +34643,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41851,30 +41851,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41882,7 +41882,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54147,7 +54147,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59237,7 +59237,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/zh_Hans.po b/doc/translations/zh_Hans.po
index aee852699c..edfb11dec1 100644
--- a/doc/translations/zh_Hans.po
+++ b/doc/translations/zh_Hans.po
@@ -33272,7 +33272,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33291,12 +33291,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34794,7 +34794,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -42002,30 +42002,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -42033,7 +42033,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54298,7 +54298,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59381,7 +59381,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/doc/translations/zh_Hant.po b/doc/translations/zh_Hant.po
index 242c8cc086..3afec7ead8 100644
--- a/doc/translations/zh_Hant.po
+++ b/doc/translations/zh_Hant.po
@@ -33073,7 +33073,7 @@ msgid ""
"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 "
+"[RefCounted], 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, "
@@ -33092,12 +33092,12 @@ msgid ""
"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].\n"
-"[b]Note:[/b] Unlike references to a [Reference], references to an Object "
+"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object "
"stored in a variable can become invalid without warning. Therefore, it's "
-"recommended to use [Reference] for data classes instead of [Object]."
+"recommended to use [RefCounted] for data classes instead of [Object]."
msgstr ""
-#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12
+#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12
#: doc/classes/Resource.xml:11
msgid ""
"https://docs.godotengine.org/en/latest/getting_started/workflow/"
@@ -34594,7 +34594,7 @@ msgid "Changes the [Color] at the given index."
msgstr ""
#: doc/classes/PackedDataContainerRef.xml:4
-msgid "Reference version of [PackedDataContainer]."
+msgid "RefCounted version of [PackedDataContainer]."
msgstr ""
#: doc/classes/PackedFloat32Array.xml:4
@@ -41802,30 +41802,30 @@ msgid ""
"the half extents."
msgstr ""
-#: doc/classes/Reference.xml:4
+#: doc/classes/RefCounted.xml:4
msgid "Base class for reference-counted objects."
msgstr ""
-#: doc/classes/Reference.xml:7
+#: doc/classes/RefCounted.xml:7
msgid ""
"Base class for any object that keeps a reference count. [Resource] and many "
"other helper objects inherit this class.\n"
"Unlike [Object]s, 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]-"
+"In the vast majority of use cases, instantiating and using [RefCounted]-"
"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:19
+#: doc/classes/RefCounted.xml:19
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:27
+#: doc/classes/RefCounted.xml:27
msgid ""
"Increments the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -41833,7 +41833,7 @@ msgid ""
"code] otherwise."
msgstr ""
-#: doc/classes/Reference.xml:35
+#: doc/classes/RefCounted.xml:35
msgid ""
"Decrements the internal reference counter. Use this only if you really know "
"what you are doing.\n"
@@ -54098,7 +54098,7 @@ msgid ""
"[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"
+"foo = RefCounted.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"
@@ -59181,7 +59181,7 @@ msgstr ""
#: doc/classes/WeakRef.xml:7
msgid ""
-"A weakref can hold a [Reference], without contributing to the reference "
+"A weakref can hold a [RefCounted], 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 "
diff --git a/drivers/SCsub b/drivers/SCsub
index e2ac9ee01e..a7b21b855f 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -23,10 +23,8 @@ SConscript("coremidi/SCsub")
SConscript("winmidi/SCsub")
# Graphics drivers
-if env["platform"] != "server" and env["platform"] != "javascript":
+if env["vulkan"]:
SConscript("vulkan/SCsub")
-else:
- SConscript("dummy/SCsub")
# Core dependencies
SConscript("png/SCsub")
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index f40036d628..4139727422 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -70,7 +70,7 @@ OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID
Error AudioDriverCoreAudio::init() {
AudioComponentDescription desc;
- zeromem(&desc, sizeof(desc));
+ memset(&desc, 0, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
#ifdef OSX_ENABLED
desc.componentSubType = kAudioUnitSubType_HALOutput;
@@ -97,7 +97,7 @@ Error AudioDriverCoreAudio::init() {
AudioStreamBasicDescription strdesc;
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
UInt32 size = sizeof(strdesc);
result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &strdesc, &size);
ERR_FAIL_COND_V(result != noErr, FAILED);
@@ -118,7 +118,7 @@ Error AudioDriverCoreAudio::init() {
mix_rate = GLOBAL_GET("audio/driver/mix_rate");
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
strdesc.mChannelsPerFrame = channels;
@@ -148,7 +148,7 @@ Error AudioDriverCoreAudio::init() {
print_verbose("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
callback.inputProc = &AudioDriverCoreAudio::output_callback;
callback.inputProcRefCon = this;
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
@@ -173,7 +173,7 @@ OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
if (!ad->active || !ad->try_lock()) {
for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
AudioBuffer *abuf = &ioData->mBuffers[i];
- zeromem(abuf->mData, abuf->mDataByteSize);
+ memset(abuf->mData, 0, abuf->mDataByteSize);
};
return 0;
};
@@ -293,7 +293,7 @@ void AudioDriverCoreAudio::finish() {
lock();
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
if (result != noErr) {
ERR_PRINT("AudioUnitSetProperty failed");
@@ -337,7 +337,7 @@ void AudioDriverCoreAudio::finish() {
Error AudioDriverCoreAudio::capture_init() {
AudioComponentDescription desc;
- zeromem(&desc, sizeof(desc));
+ memset(&desc, 0, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
#ifdef OSX_ENABLED
desc.componentSubType = kAudioUnitSubType_HALOutput;
@@ -383,7 +383,7 @@ Error AudioDriverCoreAudio::capture_init() {
#endif
AudioStreamBasicDescription strdesc;
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
size = sizeof(strdesc);
result = AudioUnitGetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size);
ERR_FAIL_COND_V(result != noErr, FAILED);
@@ -405,7 +405,7 @@ Error AudioDriverCoreAudio::capture_init() {
mix_rate = GLOBAL_GET("audio/driver/mix_rate");
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
strdesc.mChannelsPerFrame = capture_channels;
@@ -419,7 +419,7 @@ Error AudioDriverCoreAudio::capture_init() {
ERR_FAIL_COND_V(result != noErr, FAILED);
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
callback.inputProc = &AudioDriverCoreAudio::input_callback;
callback.inputProcRefCon = this;
result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callback, sizeof(callback));
@@ -436,7 +436,7 @@ void AudioDriverCoreAudio::capture_finish() {
lock();
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
OSStatus result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
if (result != noErr) {
ERR_PRINT("AudioUnitSetProperty failed");
diff --git a/drivers/dummy/SCsub b/drivers/dummy/SCsub
deleted file mode 100644
index 91e1140b75..0000000000
--- a/drivers/dummy/SCsub
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-
-env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/dummy/texture_loader_dummy.cpp b/drivers/dummy/texture_loader_dummy.cpp
deleted file mode 100644
index f148e42845..0000000000
--- a/drivers/dummy/texture_loader_dummy.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*************************************************************************/
-/* texture_loader_dummy.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "texture_loader_dummy.h"
-
-#include "core/os/file_access.h"
-#include "core/string/print_string.h"
-
-#include <string.h>
-
-RES ResourceFormatDummyTexture::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- unsigned int width = 8;
- unsigned int height = 8;
-
- //We just use some format
- Image::Format fmt = Image::FORMAT_RGB8;
- int rowsize = 3 * width;
-
- Vector<uint8_t> dstbuff;
-
- dstbuff.resize(rowsize * height);
-
- uint8_t **row_p = memnew_arr(uint8_t *, height);
-
- for (unsigned int i = 0; i < height; i++) {
- row_p[i] = 0; //No colors any more, I want them to turn black
- }
-
- memdelete_arr(row_p);
-
- Ref<Image> img = memnew(Image(width, height, 0, fmt, dstbuff));
-
- Ref<ImageTexture> texture = memnew(ImageTexture);
- texture->create_from_image(img);
-
- if (r_error)
- *r_error = OK;
-
- return texture;
-}
-
-void ResourceFormatDummyTexture::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("bmp");
- p_extensions->push_back("dds");
- p_extensions->push_back("exr");
- p_extensions->push_back("jpeg");
- p_extensions->push_back("jpg");
- p_extensions->push_back("hdr");
- p_extensions->push_back("pkm");
- p_extensions->push_back("png");
- p_extensions->push_back("pvr");
- p_extensions->push_back("svg");
- p_extensions->push_back("svgz");
- p_extensions->push_back("tga");
- p_extensions->push_back("webp");
-}
-
-bool ResourceFormatDummyTexture::handles_type(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "Texture2D");
-}
-
-String ResourceFormatDummyTexture::get_resource_type(const String &p_path) const {
- String extension = p_path.get_extension().to_lower();
- if (
- extension == "bmp" ||
- extension == "dds" ||
- extension == "exr" ||
- extension == "jpeg" ||
- extension == "jpg" ||
- extension == "hdr" ||
- extension == "pkm" ||
- extension == "png" ||
- extension == "pvr" ||
- extension == "svg" ||
- extension == "svgz" ||
- extension == "tga" ||
- extension == "webp") {
- return "ImageTexture";
- }
-
- return "";
-}
diff --git a/drivers/dummy/texture_loader_dummy.h b/drivers/dummy/texture_loader_dummy.h
deleted file mode 100644
index 00e6b9cc53..0000000000
--- a/drivers/dummy/texture_loader_dummy.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*************************************************************************/
-/* texture_loader_dummy.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef TEXTURE_LOADER_DUMMY_H
-#define TEXTURE_LOADER_DUMMY_H
-
-#include "core/io/resource_loader.h"
-#include "scene/resources/texture.h"
-
-class ResourceFormatDummyTexture : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-
- virtual ~ResourceFormatDummyTexture() {}
-};
-
-#endif // TEXTURE_LOADER_DUMMY_H
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 854c6706e6..8cc76b01e1 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -37,7 +37,7 @@
#include <string.h>
Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
- const size_t buffer_size = f->get_len();
+ const uint64_t buffer_size = f->get_length();
Vector<uint8_t> file_buffer;
Error err = file_buffer.resize(buffer_size);
if (err) {
@@ -88,7 +88,7 @@ Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) {
{
// must be closed before call to image_to_png
uint8_t *writer = out_buffer.ptrw();
- copymem(writer, "PNG ", 4);
+ memcpy(writer, "PNG ", 4);
}
Error err = PNGDriverCommon::image_to_png(p_image, out_buffer);
@@ -101,6 +101,6 @@ Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) {
ImageLoaderPNG::ImageLoaderPNG() {
Image::_png_mem_loader_func = load_mem_png;
- Image::lossless_unpacker = lossless_unpack_png;
- Image::lossless_packer = lossless_pack_png;
+ Image::png_unpacker = lossless_unpack_png;
+ Image::png_packer = lossless_pack_png;
}
diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp
index 9e848a2253..412e17c6b7 100644
--- a/drivers/png/png_driver_common.cpp
+++ b/drivers/png/png_driver_common.cpp
@@ -60,7 +60,7 @@ static bool check_error(const png_image &image) {
Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear, Ref<Image> p_image) {
png_image png_img;
- zeromem(&png_img, sizeof(png_img));
+ memset(&png_img, 0, sizeof(png_img));
png_img.version = PNG_IMAGE_VERSION;
// fetch image properties
@@ -134,7 +134,7 @@ Error image_to_png(const Ref<Image> &p_image, Vector<uint8_t> &p_buffer) {
ERR_FAIL_COND_V(source_image->is_compressed(), FAILED);
png_image png_img;
- zeromem(&png_img, sizeof(png_img));
+ memset(&png_img, 0, sizeof(png_img));
png_img.version = PNG_IMAGE_VERSION;
png_img.width = source_image->get_width();
png_img.height = source_image->get_height();
diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp
index b737a287d1..2971880985 100644
--- a/drivers/png/resource_saver_png.cpp
+++ b/drivers/png/resource_saver_png.cpp
@@ -30,8 +30,8 @@
#include "resource_saver_png.h"
+#include "core/io/file_access.h"
#include "core/io/image.h"
-#include "core/os/file_access.h"
#include "drivers/png/png_driver_common.h"
#include "scene/resources/texture.h"
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 5e87bc019b..5e2431d44e 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -35,18 +35,28 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
+#ifdef ALSAMIDI_ENABLED
+#include "drivers/alsa/asound-so_wrap.h"
+#endif
+
void AudioDriverPulseAudio::pa_state_cb(pa_context *c, void *userdata) {
AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
switch (pa_context_get_state(c)) {
case PA_CONTEXT_TERMINATED:
+ print_verbose("PulseAudio: context terminated");
+ ad->pa_ready = -1;
+ break;
case PA_CONTEXT_FAILED:
+ print_verbose("PulseAudio: context failed");
ad->pa_ready = -1;
break;
case PA_CONTEXT_READY:
+ print_verbose("PulseAudio: context ready");
ad->pa_ready = 1;
break;
default:
+ print_verbose("PulseAudio: context other");
// TODO: Check if we want to handle some of the other
// PA context states like PA_CONTEXT_UNCONNECTED.
break;
@@ -61,6 +71,13 @@ void AudioDriverPulseAudio::pa_sink_info_cb(pa_context *c, const pa_sink_info *l
return;
}
+ // If eol is set to a negative number there's an error.
+ if (eol < 0) {
+ ERR_PRINT("PulseAudio: sink info error: " + String(pa_strerror(pa_context_errno(c))));
+ ad->pa_status--;
+ return;
+ }
+
ad->pa_map = l->channel_map;
ad->pa_status++;
}
@@ -73,6 +90,13 @@ void AudioDriverPulseAudio::pa_source_info_cb(pa_context *c, const pa_source_inf
return;
}
+ // If eol is set to a negative number there's an error.
+ if (eol < 0) {
+ ERR_PRINT("PulseAudio: sink info error: " + String(pa_strerror(pa_context_errno(c))));
+ ad->pa_status--;
+ return;
+ }
+
ad->pa_rec_map = l->channel_map;
ad->pa_status++;
}
@@ -86,7 +110,7 @@ void AudioDriverPulseAudio::pa_server_info_cb(pa_context *c, const pa_server_inf
ad->pa_status++;
}
-void AudioDriverPulseAudio::detect_channels(bool capture) {
+Error AudioDriverPulseAudio::detect_channels(bool capture) {
pa_channel_map_init_stereo(capture ? &pa_rec_map : &pa_map);
String device = capture ? capture_device_name : device_name;
@@ -104,7 +128,8 @@ void AudioDriverPulseAudio::detect_channels(bool capture) {
pa_operation_unref(pa_op);
} else {
- ERR_PRINT("pa_context_get_server_info error");
+ ERR_PRINT("pa_context_get_server_info error: " + String(pa_strerror(pa_context_errno(pa_ctx))));
+ return FAILED;
}
}
@@ -114,6 +139,7 @@ void AudioDriverPulseAudio::detect_channels(bool capture) {
} else {
strcpy(dev, device.utf8().get_data());
}
+ print_verbose("PulseAudio: Detecting channels for device: " + String(dev));
// Now using the device name get the amount of channels
pa_status = 0;
@@ -133,6 +159,10 @@ void AudioDriverPulseAudio::detect_channels(bool capture) {
}
pa_operation_unref(pa_op);
+
+ if (pa_status == -1) {
+ return FAILED;
+ }
} else {
if (capture) {
ERR_PRINT("pa_context_get_source_info_by_name error");
@@ -140,6 +170,8 @@ void AudioDriverPulseAudio::detect_channels(bool capture) {
ERR_PRINT("pa_context_get_sink_info_by_name error");
}
}
+
+ return OK;
}
Error AudioDriverPulseAudio::init_device() {
@@ -156,7 +188,13 @@ Error AudioDriverPulseAudio::init_device() {
// Note: If using an even amount of channels (2, 4, etc) channels and pa_map.channels will be equal,
// if not then pa_map.channels will have the real amount of channels PulseAudio is using and channels
// will have the amount of channels Godot is using (in this case it's pa_map.channels + 1)
- detect_channels();
+ Error err = detect_channels();
+ if (err != OK) {
+ // This most likely means there are no sinks.
+ ERR_PRINT("PulseAudio: init device failed to detect number of channels");
+ return err;
+ }
+
switch (pa_map.channels) {
case 1: // Mono
case 3: // Surround 2.1
@@ -238,6 +276,10 @@ Error AudioDriverPulseAudio::init() {
#else
int dylibloader_verbose = 0;
#endif
+#ifdef ALSAMIDI_ENABLED
+ // If using PulseAudio with ALSA MIDI, we need to initialize ALSA as well
+ initialize_asound(dylibloader_verbose);
+#endif
if (initialize_pulse(dylibloader_verbose)) {
return ERR_CANT_OPEN;
}
@@ -294,10 +336,8 @@ Error AudioDriverPulseAudio::init() {
return ERR_CANT_OPEN;
}
- Error err = init_device();
- if (err == OK) {
- thread.start(AudioDriverPulseAudio::thread_func, this);
- }
+ init_device();
+ thread.start(AudioDriverPulseAudio::thread_func, this);
return OK;
}
@@ -441,7 +481,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
pa_operation_unref(pa_op);
} else {
- ERR_PRINT("pa_context_get_server_info error");
+ ERR_PRINT("pa_context_get_server_info error: " + String(pa_strerror(pa_context_errno(ad->pa_ctx))));
}
if (old_default_device != ad->default_device) {
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index fa9b573d94..1358561c02 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -89,7 +89,7 @@ class AudioDriverPulseAudio : public AudioDriver {
Error capture_init_device();
void capture_finish_device();
- void detect_channels(bool capture = false);
+ Error detect_channels(bool capture = false);
static void thread_func(void *p_udata);
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index 34ef6f3ce6..a2c9bae852 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -226,8 +226,9 @@ static void _get_drives(List<String> *list) {
while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) {
if (mnt.mnt_dir != nullptr && _filter_drive(&mnt)) {
// Avoid duplicates
- if (!list->find(mnt.mnt_dir)) {
- list->push_back(mnt.mnt_dir);
+ String name = String::utf8(mnt.mnt_dir);
+ if (!list->find(name)) {
+ list->push_back(name);
}
}
}
@@ -240,8 +241,9 @@ static void _get_drives(List<String> *list) {
const char *home = getenv("HOME");
if (home) {
// Only add if it's not a duplicate
- if (!list->find(home)) {
- list->push_back(home);
+ String home_name = String::utf8(home);
+ if (!list->find(home_name)) {
+ list->push_back(home_name);
}
// Check $HOME/.config/gtk-3.0/bookmarks
@@ -254,7 +256,7 @@ static void _get_drives(List<String> *list) {
// Parse only file:// links
if (strncmp(string, "file://", 7) == 0) {
// Strip any unwanted edges on the strings and push_back if it's not a duplicate
- String fpath = String(string + 7).strip_edges().split_spaces()[0].uri_decode();
+ String fpath = String::utf8(string + 7).strip_edges().split_spaces()[0].uri_decode();
if (!list->find(fpath)) {
list->push_back(fpath);
}
@@ -404,14 +406,61 @@ Error DirAccessUnix::remove(String p_path) {
}
}
-size_t DirAccessUnix::get_space_left() {
+bool DirAccessUnix::is_link(String p_file) {
+ if (p_file.is_rel_path()) {
+ p_file = get_current_dir().plus_file(p_file);
+ }
+
+ p_file = fix_path(p_file);
+
+ struct stat flags;
+ if ((lstat(p_file.utf8().get_data(), &flags) != 0)) {
+ return FAILED;
+ }
+
+ return S_ISLNK(flags.st_mode);
+}
+
+String DirAccessUnix::read_link(String p_file) {
+ if (p_file.is_rel_path()) {
+ p_file = get_current_dir().plus_file(p_file);
+ }
+
+ p_file = fix_path(p_file);
+
+ char buf[256];
+ memset(buf, 0, 256);
+ ssize_t len = readlink(p_file.utf8().get_data(), buf, sizeof(buf));
+ String link;
+ if (len > 0) {
+ link.parse_utf8(buf, len);
+ }
+ return link;
+}
+
+Error DirAccessUnix::create_link(String p_source, String p_target) {
+ if (p_target.is_rel_path()) {
+ p_target = get_current_dir().plus_file(p_target);
+ }
+
+ p_source = fix_path(p_source);
+ p_target = fix_path(p_target);
+
+ if (symlink(p_source.utf8().get_data(), p_target.utf8().get_data()) == 0) {
+ return OK;
+ } else {
+ return FAILED;
+ }
+}
+
+uint64_t DirAccessUnix::get_space_left() {
#ifndef NO_STATVFS
struct statvfs vfs;
if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) {
return 0;
};
- return vfs.f_bfree * vfs.f_bsize;
+ return (uint64_t)vfs.f_bavail * (uint64_t)vfs.f_frsize;
#else
// FIXME: Implement this.
return 0;
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index 54f4a5c312..8b19308967 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.h
@@ -33,7 +33,7 @@
#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include <dirent.h>
#include <sys/stat.h>
@@ -79,7 +79,11 @@ public:
virtual Error rename(String p_path, String p_new_path);
virtual Error remove(String p_path);
- virtual size_t get_space_left();
+ virtual bool is_link(String p_file);
+ virtual String read_link(String p_file);
+ virtual Error create_link(String p_source, String p_target);
+
+ virtual uint64_t get_space_left();
virtual String get_filesystem_type() const;
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 4c08380dd0..6ea55219bb 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -184,11 +184,11 @@ String FileAccessUnix::get_path_absolute() const {
return path;
}
-void FileAccessUnix::seek(size_t p_position) {
+void FileAccessUnix::seek(uint64_t p_position) {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
last_error = OK;
- if (fseek(f, p_position, SEEK_SET)) {
+ if (fseeko(f, p_position, SEEK_SET)) {
check_errors();
}
}
@@ -196,15 +196,15 @@ void FileAccessUnix::seek(size_t p_position) {
void FileAccessUnix::seek_end(int64_t p_position) {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
- if (fseek(f, p_position, SEEK_END)) {
+ if (fseeko(f, p_position, SEEK_END)) {
check_errors();
}
}
-size_t FileAccessUnix::get_position() const {
+uint64_t FileAccessUnix::get_position() const {
ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
- long pos = ftell(f);
+ int64_t pos = ftello(f);
if (pos < 0) {
check_errors();
ERR_FAIL_V(0);
@@ -212,15 +212,15 @@ size_t FileAccessUnix::get_position() const {
return pos;
}
-size_t FileAccessUnix::get_len() const {
+uint64_t FileAccessUnix::get_length() const {
ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
- long pos = ftell(f);
+ int64_t pos = ftello(f);
ERR_FAIL_COND_V(pos < 0, 0);
- ERR_FAIL_COND_V(fseek(f, 0, SEEK_END), 0);
- long size = ftell(f);
+ ERR_FAIL_COND_V(fseeko(f, 0, SEEK_END), 0);
+ int64_t size = ftello(f);
ERR_FAIL_COND_V(size < 0, 0);
- ERR_FAIL_COND_V(fseek(f, pos, SEEK_SET), 0);
+ ERR_FAIL_COND_V(fseeko(f, pos, SEEK_SET), 0);
return size;
}
@@ -239,11 +239,11 @@ uint8_t FileAccessUnix::get_8() const {
return b;
}
-int FileAccessUnix::get_buffer(uint8_t *p_dst, int p_length) const {
+uint64_t FileAccessUnix::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use.");
- int read = fread(p_dst, 1, p_length, f);
+
+ uint64_t read = fread(p_dst, 1, p_length, f);
check_errors();
return read;
};
@@ -262,10 +262,10 @@ void FileAccessUnix::store_8(uint8_t p_dest) {
ERR_FAIL_COND(fwrite(&p_dest, 1, 1, f) != 1);
}
-void FileAccessUnix::store_buffer(const uint8_t *p_src, int p_length) {
+void FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
- ERR_FAIL_COND(!p_src);
- ERR_FAIL_COND((int)fwrite(p_src, 1, p_length, f) != p_length);
+ ERR_FAIL_COND(!p_src && p_length > 0);
+ ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length);
}
bool FileAccessUnix::file_exists(const String &p_path) {
diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h
index 998fad7909..8b27c308e1 100644
--- a/drivers/unix/file_access_unix.h
+++ b/drivers/unix/file_access_unix.h
@@ -31,7 +31,7 @@
#ifndef FILE_ACCESS_UNIX_H
#define FILE_ACCESS_UNIX_H
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/memory.h"
#include <stdio.h>
@@ -61,21 +61,21 @@ public:
virtual String get_path() const; /// returns the path for the current open file
virtual String get_path_absolute() const; /// returns the absolute path for the current open file
- virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek(uint64_t p_position); ///< seek to a given position
virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual size_t get_position() const; ///< get position in the file
- virtual size_t get_len() const; ///< get size of the file
+ virtual uint64_t get_position() const; ///< get position in the file
+ virtual uint64_t get_length() const; ///< get size of the file
virtual bool eof_reached() const; ///< reading passed EOF
virtual uint8_t get_8() const; ///< get a byte
- virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
virtual Error get_error() const; ///< get last error
virtual void flush();
virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
virtual bool file_exists(const String &p_path); ///< return true if a file exists
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp
index 8ec1de4386..e8f8ae4717 100644
--- a/drivers/unix/ip_unix.cpp
+++ b/drivers/unix/ip_unix.cpp
@@ -75,8 +75,8 @@
#include <net/if.h> // Order is important on OpenBSD, leave as last
#endif
-static IP_Address _sockaddr2ip(struct sockaddr *p_addr) {
- IP_Address ip;
+static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
+ IPAddress ip;
if (p_addr->sa_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *)p_addr;
@@ -89,7 +89,7 @@ static IP_Address _sockaddr2ip(struct sockaddr *p_addr) {
return ip;
};
-IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
+void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type) const {
struct addrinfo hints;
struct addrinfo *result = nullptr;
@@ -108,7 +108,7 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
int s = getaddrinfo(p_hostname.utf8().get_data(), nullptr, &hints, &result);
if (s != 0) {
ERR_PRINT("getaddrinfo failed! Cannot resolve hostname.");
- return IP_Address();
+ return;
};
if (result == nullptr || result->ai_addr == nullptr) {
@@ -116,21 +116,31 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
if (result) {
freeaddrinfo(result);
}
- return IP_Address();
+ return;
};
- IP_Address ip = _sockaddr2ip(result->ai_addr);
+ struct addrinfo *next = result;
- freeaddrinfo(result);
+ do {
+ if (next->ai_addr == NULL) {
+ next = next->ai_next;
+ continue;
+ }
+ IPAddress ip = _sockaddr2ip(next->ai_addr);
+ if (!r_addresses.find(ip)) {
+ r_addresses.push_back(ip);
+ }
+ next = next->ai_next;
+ } while (next);
- return ip;
+ freeaddrinfo(result);
}
#if defined(WINDOWS_ENABLED)
#if defined(UWP_ENABLED)
-void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
using namespace Windows::Networking;
using namespace Windows::Networking::Connectivity;
@@ -156,14 +166,14 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
Interface_Info &info = E->get();
- IP_Address ip = IP_Address(hostname->CanonicalName->Data());
+ IPAddress ip = IPAddress(hostname->CanonicalName->Data());
info.ip_addresses.push_front(ip);
}
}
#else
-void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
ULONG buf_size = 1024;
IP_ADAPTER_ADDRESSES *addrs;
@@ -211,7 +221,7 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
#else // UNIX
-void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
struct ifaddrs *ifAddrStruct = nullptr;
struct ifaddrs *ifa = nullptr;
int family;
@@ -249,15 +259,15 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
}
#endif
-void IP_Unix::make_default() {
+void IPUnix::make_default() {
_create = _create_unix;
}
-IP *IP_Unix::_create_unix() {
- return memnew(IP_Unix);
+IP *IPUnix::_create_unix() {
+ return memnew(IPUnix);
}
-IP_Unix::IP_Unix() {
+IPUnix::IPUnix() {
}
#endif
diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h
index ca2ee17f4e..0d64648b39 100644
--- a/drivers/unix/ip_unix.h
+++ b/drivers/unix/ip_unix.h
@@ -35,10 +35,10 @@
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
-class IP_Unix : public IP {
- GDCLASS(IP_Unix, IP);
+class IPUnix : public IP {
+ GDCLASS(IPUnix, IP);
- virtual IP_Address _resolve_hostname(const String &p_hostname, IP::Type p_type) override;
+ virtual void _resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type = TYPE_ANY) const override;
static IP *_create_unix();
@@ -46,7 +46,7 @@ public:
virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const override;
static void make_default();
- IP_Unix();
+ IPUnix();
};
#endif
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index 19753943c8..efeaf32ff7 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -95,7 +95,7 @@
#endif
-size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) {
+size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
memset(p_addr, 0, sizeof(struct sockaddr_storage));
if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket
@@ -106,7 +106,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(p_port);
if (p_ip.is_valid()) {
- copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16);
+ memcpy(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16);
} else {
addr6->sin6_addr = in6addr_any;
}
@@ -121,7 +121,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
addr4->sin_port = htons(p_port); // short, network byte order
if (p_ip.is_valid()) {
- copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
+ memcpy(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
} else {
addr4->sin_addr.s_addr = INADDR_ANY;
}
@@ -130,18 +130,23 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
}
}
-void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port) {
+void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) {
if (p_addr->ss_family == AF_INET) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
- r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
-
- r_port = ntohs(addr4->sin_port);
-
+ if (r_ip) {
+ r_ip->set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
+ }
+ if (r_port) {
+ *r_port = ntohs(addr4->sin_port);
+ }
} else if (p_addr->ss_family == AF_INET6) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
- r_ip.set_ipv6(addr6->sin6_addr.s6_addr);
-
- r_port = ntohs(addr6->sin6_port);
+ if (r_ip) {
+ r_ip->set_ipv6(addr6->sin6_addr.s6_addr);
+ }
+ if (r_port) {
+ *r_port = ntohs(addr6->sin6_port);
+ }
};
}
@@ -186,13 +191,21 @@ NetSocketPosix::~NetSocketPosix() {
NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
#if defined(WINDOWS_ENABLED)
int err = WSAGetLastError();
-
- if (err == WSAEISCONN)
+ if (err == WSAEISCONN) {
return ERR_NET_IS_CONNECTED;
- if (err == WSAEINPROGRESS || err == WSAEALREADY)
+ }
+ if (err == WSAEINPROGRESS || err == WSAEALREADY) {
return ERR_NET_IN_PROGRESS;
- if (err == WSAEWOULDBLOCK)
+ }
+ if (err == WSAEWOULDBLOCK) {
return ERR_NET_WOULD_BLOCK;
+ }
+ if (err == WSAEADDRINUSE || err == WSAEADDRNOTAVAIL) {
+ return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
+ }
+ if (err == WSAEACCES) {
+ return ERR_NET_UNAUTHORIZED;
+ }
print_verbose("Socket error: " + itos(err));
return ERR_NET_OTHER;
#else
@@ -205,6 +218,12 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return ERR_NET_WOULD_BLOCK;
}
+ if (errno == EADDRINUSE || errno == EINVAL || errno == EADDRNOTAVAIL) {
+ return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
+ }
+ if (errno == EACCES) {
+ return ERR_NET_UNAUTHORIZED;
+ }
print_verbose("Socket error: " + itos(errno));
return ERR_NET_OTHER;
#endif
@@ -214,7 +233,7 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
#pragma GCC diagnostic pop
#endif
-bool NetSocketPosix::_can_use_ip(const IP_Address &p_ip, const bool p_for_bind) const {
+bool NetSocketPosix::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const {
if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) {
return false;
} else if (!p_for_bind && !p_ip.is_valid()) {
@@ -225,7 +244,7 @@ bool NetSocketPosix::_can_use_ip(const IP_Address &p_ip, const bool p_for_bind)
return !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type);
}
-_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add) {
+_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER);
@@ -235,7 +254,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St
int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int ret = -1;
- IP_Address if_ip;
+ IPAddress if_ip;
uint32_t if_v6id = 0;
Map<String, IP::Interface_Info> if_info;
IP::get_singleton()->get_local_interfaces(&if_info);
@@ -250,7 +269,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St
break; // IPv6 uses index.
}
- for (List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
+ for (List<IPAddress>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
if (!F->get().is_ipv4()) {
continue; // Wrong IP type
}
@@ -264,13 +283,13 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St
ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER);
struct ip_mreq greq;
int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
- copymem(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
- copymem(&greq.imr_interface, if_ip.get_ipv4(), 4);
+ memcpy(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
+ memcpy(&greq.imr_interface, if_ip.get_ipv4(), 4);
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
} else {
struct ipv6_mreq greq;
int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
- copymem(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
+ memcpy(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
greq.ipv6mr_interface = if_v6id;
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
}
@@ -376,7 +395,7 @@ void NetSocketPosix::close() {
_is_stream = false;
}
-Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) {
+Error NetSocketPosix::bind(IPAddress p_addr, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_addr, true), ERR_INVALID_PARAMETER);
@@ -384,8 +403,8 @@ Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) {
size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type);
if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
- _get_socket_error();
- print_verbose("Failed to bind socket.");
+ NetError err = _get_socket_error();
+ print_verbose("Failed to bind socket. Error: " + itos(err));
close();
return ERR_UNAVAILABLE;
}
@@ -406,7 +425,7 @@ Error NetSocketPosix::listen(int p_max_pending) {
return OK;
}
-Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) {
+Error NetSocketPosix::connect_to_host(IPAddress p_host, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_host, false), ERR_INVALID_PARAMETER);
@@ -446,8 +465,8 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
FD_ZERO(&wr);
FD_ZERO(&ex);
FD_SET(_sock, &ex);
- struct timeval timeout = { p_timeout, 0 };
- // For blocking operation, pass nullptr timeout pointer to select.
+ struct timeval timeout = { p_timeout / 1000, (p_timeout % 1000) * 1000 };
+ // For blocking operation, pass nullptr timeout pointer to select.
struct timeval *tp = nullptr;
if (p_timeout >= 0) {
// If timeout is non-negative, we want to specify the timeout instead.
@@ -540,7 +559,7 @@ Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
return OK;
}
-Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port, bool p_peek) {
+Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
struct sockaddr_storage from;
@@ -597,7 +616,7 @@ Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
return OK;
}
-Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
+Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
struct sockaddr_storage addr;
@@ -716,7 +735,21 @@ int NetSocketPosix::get_available_bytes() const {
return len;
}
-Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
+Error NetSocketPosix::get_socket_address(IPAddress *r_ip, uint16_t *r_port) const {
+ ERR_FAIL_COND_V(!is_open(), FAILED);
+
+ struct sockaddr_storage saddr;
+ socklen_t len = sizeof(saddr);
+ if (getsockname(_sock, (struct sockaddr *)&saddr, &len) != 0) {
+ _get_socket_error();
+ print_verbose("Error when reading local socket address.");
+ return FAILED;
+ }
+ _set_ip_port(&saddr, r_ip, r_port);
+ return OK;
+}
+
+Ref<NetSocket> NetSocketPosix::accept(IPAddress &r_ip, uint16_t &r_port) {
Ref<NetSocket> out;
ERR_FAIL_COND_V(!is_open(), out);
@@ -729,7 +762,7 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
return out;
}
- _set_ip_port(&their_addr, r_ip, r_port);
+ _set_ip_port(&their_addr, &r_ip, &r_port);
NetSocketPosix *ns = memnew(NetSocketPosix);
ns->_set_socket(fd, _ip_type, _is_stream);
@@ -737,11 +770,11 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
return Ref<NetSocket>(ns);
}
-Error NetSocketPosix::join_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+Error NetSocketPosix::join_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
return _change_multicast_group(p_multi_address, p_if_name, true);
}
-Error NetSocketPosix::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+Error NetSocketPosix::leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
return _change_multicast_group(p_multi_address, p_if_name, false);
}
#endif
diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h
index cc6af661c8..38c8170a52 100644
--- a/drivers/unix/net_socket_posix.h
+++ b/drivers/unix/net_socket_posix.h
@@ -54,39 +54,42 @@ private:
ERR_NET_WOULD_BLOCK,
ERR_NET_IS_CONNECTED,
ERR_NET_IN_PROGRESS,
- ERR_NET_OTHER
+ ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE,
+ ERR_NET_UNAUTHORIZED,
+ ERR_NET_OTHER,
};
NetError _get_socket_error() const;
void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream);
- _FORCE_INLINE_ Error _change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add);
+ _FORCE_INLINE_ Error _change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add);
_FORCE_INLINE_ void _set_close_exec_enabled(bool p_enabled);
protected:
static NetSocket *_create_func();
- bool _can_use_ip(const IP_Address &p_ip, const bool p_for_bind) const;
+ bool _can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const;
public:
static void make_default();
static void cleanup();
- static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port);
- static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type);
+ static void _set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port);
+ static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type);
virtual Error open(Type p_sock_type, IP::Type &ip_type);
virtual void close();
- virtual Error bind(IP_Address p_addr, uint16_t p_port);
+ virtual Error bind(IPAddress p_addr, uint16_t p_port);
virtual Error listen(int p_max_pending);
- virtual Error connect_to_host(IP_Address p_host, uint16_t p_port);
+ virtual Error connect_to_host(IPAddress p_host, uint16_t p_port);
virtual Error poll(PollType p_type, int timeout) const;
virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read);
- virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port, bool p_peek = false);
+ virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false);
virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent);
- virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port);
- virtual Ref<NetSocket> accept(IP_Address &r_ip, uint16_t &r_port);
+ virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port);
+ virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port);
virtual bool is_open() const;
virtual int get_available_bytes() const;
+ virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const;
virtual Error set_broadcasting_enabled(bool p_enabled);
virtual void set_blocking_enabled(bool p_enabled);
@@ -94,8 +97,8 @@ public:
virtual void set_tcp_no_delay_enabled(bool p_enabled);
virtual void set_reuse_address_enabled(bool p_enabled);
virtual void set_reuse_port_enabled(bool p_enabled);
- virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name);
- virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name);
+ virtual Error join_multicast_group(const IPAddress &p_multi_address, String p_if_name);
+ virtual Error leave_multicast_group(const IPAddress &p_multi_address, String p_if_name);
NetSocketPosix();
~NetSocketPosix();
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index b9bd773c2e..a5c61bbea5 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -129,7 +129,7 @@ void OS_Unix::initialize_core() {
#ifndef NO_NETWORK
NetSocketPosix::make_default();
- IP_Unix::make_default();
+ IPUnix::make_default();
#endif
_setup_clock();
@@ -195,8 +195,8 @@ OS::Time OS_Unix::get_time(bool utc) const {
}
Time ret;
ret.hour = lt.tm_hour;
- ret.min = lt.tm_min;
- ret.sec = lt.tm_sec;
+ ret.minute = lt.tm_min;
+ ret.second = lt.tm_sec;
get_time_zone_info();
return ret;
}
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 09e2b4546a..c69b516f37 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -31,7 +31,7 @@
#include "rendering_device_vulkan.h"
#include "core/config/project_settings.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/os.h"
#include "core/templates/hashfuncs.h"
#include "drivers/vulkan/vulkan_context.h"
@@ -1600,7 +1600,7 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c
}
//copy to staging buffer
- copymem(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount);
+ memcpy(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount);
//unmap
vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation);
@@ -2558,7 +2558,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * line_width;
- copymem(wptr, rptr, line_width);
+ memcpy(wptr, rptr, line_width);
}
} else {
@@ -2566,7 +2566,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
for (uint32_t y = 0; y < height; y++) {
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * pixel_size * width;
- copymem(wptr, rptr, (uint64_t)pixel_size * width);
+ memcpy(wptr, rptr, (uint64_t)pixel_size * width);
}
}
}
@@ -2699,7 +2699,7 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
{
buffer_data.resize(buffer_size);
uint8_t *w = buffer_data.ptrw();
- copymem(w, buffer_mem, buffer_size);
+ memcpy(w, buffer_mem, buffer_size);
}
vmaUnmapMemory(allocator, tmp_buffer.allocation);
@@ -3244,7 +3244,7 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f
/**** ATTACHMENT ****/
/********************/
-VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, int *r_color_attachment_count) {
+VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, int *r_color_attachment_count, uint32_t p_view_count) {
Vector<VkAttachmentDescription> attachments;
Vector<VkAttachmentReference> color_references;
Vector<VkAttachmentReference> depth_stencil_references;
@@ -3280,7 +3280,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
// For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write
// Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs.
- // the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that
+ // the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that
// stage
switch (is_depth_stencil ? p_initial_depth_action : p_initial_color_action) {
case INITIAL_ACTION_CLEAR_REGION:
@@ -3469,6 +3469,31 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
render_pass_create_info.dependencyCount = 0;
render_pass_create_info.pDependencies = nullptr;
+ const uint32_t view_mask = (1 << p_view_count) - 1;
+ const uint32_t correlation_mask = (1 << p_view_count) - 1;
+ VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info;
+
+ if (p_view_count > 1) {
+ const VulkanContext::MultiviewCapabilities capabilities = context->get_multiview_capabilities();
+
+ // For now this only works with multiview!
+ ERR_FAIL_COND_V_MSG(!capabilities.is_supported, VK_NULL_HANDLE, "Multiview not supported");
+
+ // Make sure we limit this to the number of views we support.
+ ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, VK_NULL_HANDLE, "Hardware does not support requested number of views for Multiview render pass");
+
+ render_pass_multiview_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
+ render_pass_multiview_create_info.pNext = nullptr;
+ render_pass_multiview_create_info.subpassCount = 1;
+ render_pass_multiview_create_info.pViewMasks = &view_mask;
+ render_pass_multiview_create_info.dependencyCount = 0;
+ render_pass_multiview_create_info.pViewOffsets = nullptr;
+ render_pass_multiview_create_info.correlationMaskCount = 1;
+ render_pass_multiview_create_info.pCorrelationMasks = &correlation_mask;
+
+ render_pass_create_info.pNext = &render_pass_multiview_create_info;
+ }
+
VkRenderPass 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) + ".");
@@ -3479,11 +3504,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
return render_pass;
}
-RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector<AttachmentFormat> &p_format) {
+RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count) {
_THREAD_SAFE_METHOD_
FramebufferFormatKey key;
key.attachments = p_format;
+ key.view_count = p_view_count;
const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
if (E) {
@@ -3492,7 +3518,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
}
int color_references;
- VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, &color_references); //actions don't matter for this use case
+ VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, &color_references, p_view_count); //actions don't matter for this use case
if (render_pass == VK_NULL_HANDLE) { //was likely invalid
return INVALID_ID;
@@ -3505,6 +3531,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
fb_format.color_attachments = color_references;
fb_format.render_pass = render_pass;
fb_format.samples = p_format[0].samples;
+ fb_format.view_count = p_view_count;
framebuffer_formats[id] = fb_format;
return id;
}
@@ -3580,11 +3607,12 @@ RID RenderingDeviceVulkan::framebuffer_create_empty(const Size2i &p_size, Textur
framebuffer.format_id = framebuffer_format_create_empty(p_samples);
ERR_FAIL_COND_V(p_format_check != INVALID_FORMAT_ID && framebuffer.format_id != p_format_check, RID());
framebuffer.size = p_size;
+ framebuffer.view_count = 1;
return framebuffer_owner.make_rid(framebuffer);
}
-RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check) {
+RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) {
_THREAD_SAFE_METHOD_
Vector<AttachmentFormat> attachments;
@@ -3594,6 +3622,8 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
Texture *texture = texture_owner.getornull(p_texture_attachments[i]);
ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture.");
+ ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");
+
if (i == 0) {
size.width = texture->width;
size.height = texture->height;
@@ -3609,7 +3639,7 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
attachments.push_back(af);
}
- FramebufferFormatID format_id = framebuffer_format_create(attachments);
+ FramebufferFormatID format_id = framebuffer_format_create(attachments, p_view_count);
if (format_id == INVALID_ID) {
return RID();
}
@@ -3621,6 +3651,7 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
framebuffer.format_id = format_id;
framebuffer.texture_ids = p_texture_attachments;
framebuffer.size = size;
+ framebuffer.view_count = p_view_count;
RID id = framebuffer_owner.make_rid(framebuffer);
@@ -5359,7 +5390,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
{
buffer_data.resize(buffer->size);
uint8_t *w = buffer_data.ptrw();
- copymem(w, buffer_mem, buffer->size);
+ memcpy(w, buffer_mem, buffer->size);
}
vmaUnmapMemory(allocator, tmp_buffer.allocation);
@@ -5904,12 +5935,13 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
vk.final_color_action = p_final_color_action;
vk.initial_depth_action = p_initial_depth_action;
vk.final_depth_action = p_final_depth_action;
+ vk.view_count = p_framebuffer->view_count;
if (!p_framebuffer->framebuffers.has(vk)) {
//need to create this version
Framebuffer::Version version;
- version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action);
+ version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, nullptr, p_framebuffer->view_count);
VkFramebufferCreateInfo framebuffer_create_info;
framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
@@ -7844,6 +7876,10 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
device_capabilities.subgroup_size = subgroup_capabilities.size;
device_capabilities.subgroup_in_shaders = subgroup_capabilities.supported_stages_flags_rd();
device_capabilities.subgroup_operations = subgroup_capabilities.supported_operations_flags_rd();
+
+ // get info about further features
+ VulkanContext::MultiviewCapabilities multiview_capabilies = p_context->get_multiview_capabilities();
+ device_capabilities.supports_multiview = multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
}
context = p_context;
@@ -7986,7 +8022,11 @@ void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) {
List<RID> owned;
p_owner.get_owned_list(&owned);
if (owned.size()) {
- WARN_PRINT(itos(owned.size()) + " RIDs of type '" + p_type + "' were leaked.");
+ if (owned.size() == 1) {
+ WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type));
+ } else {
+ WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));
+ }
for (List<RID>::Element *E = owned.front(); E; E = E->next()) {
free(E->get());
}
@@ -8199,7 +8239,11 @@ void RenderingDeviceVulkan::finalize() {
List<RID> owned;
texture_owner.get_owned_list(&owned);
if (owned.size()) {
- WARN_PRINT(itos(owned.size()) + " RIDs of type 'Texture' were leaked.");
+ if (owned.size() == 1) {
+ WARN_PRINT("1 RID of type \"Texture\" was leaked.");
+ } else {
+ WARN_PRINT(vformat("%d RIDs of type \"Texture\" were leaked.", owned.size()));
+ }
//free shared first
for (List<RID>::Element *E = owned.front(); E;) {
List<RID>::Element *N = E->next();
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index a2527d5c33..f4fe9cf956 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -234,7 +234,12 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct FramebufferFormatKey {
Vector<AttachmentFormat> attachments;
+ uint32_t view_count = 1;
bool operator<(const FramebufferFormatKey &p_key) const {
+ if (view_count != p_key.view_count) {
+ return view_count < p_key.view_count;
+ }
+
int as = attachments.size();
int bs = p_key.attachments.size();
if (as != bs) {
@@ -261,7 +266,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 = nullptr);
+ 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, uint32_t p_view_count = 1);
// This is a cache and it's never freed, it ensures
// IDs for a given format are always unique.
@@ -271,6 +276,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkRenderPass render_pass = VK_NULL_HANDLE; //here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec)
int color_attachments = 0; //used for pipeline validation
TextureSamples samples;
+ uint32_t view_count = 1; // number of views
};
Map<FramebufferFormatID, FramebufferFormat> framebuffer_formats;
@@ -282,11 +288,16 @@ class RenderingDeviceVulkan : public RenderingDevice {
FinalAction final_color_action;
InitialAction initial_depth_action;
FinalAction final_depth_action;
+ uint32_t view_count;
bool operator<(const VersionKey &p_key) const {
if (initial_color_action == p_key.initial_color_action) {
if (final_color_action == p_key.final_color_action) {
if (initial_depth_action == p_key.initial_depth_action) {
- return final_depth_action < p_key.final_depth_action;
+ if (final_depth_action == p_key.final_depth_action) {
+ return view_count < p_key.view_count;
+ } else {
+ return final_depth_action < p_key.final_depth_action;
+ }
} else {
return initial_depth_action < p_key.initial_depth_action;
}
@@ -309,6 +320,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
Map<VersionKey, Version> framebuffers;
Size2 size;
+ uint32_t view_count;
};
RID_Owner<Framebuffer, true> framebuffer_owner;
@@ -938,11 +950,11 @@ public:
/**** FRAMEBUFFER ****/
/*********************/
- virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format);
+ virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1);
virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1);
virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format);
- virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID);
+ virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID);
virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer);
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index e759e53288..6ed43b5d31 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -337,6 +337,9 @@ Error VulkanContext::_initialize_extensions() {
extension_names[enabled_extension_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
enabled_debug_utils = true;
}
+ if (!strcmp(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, instance_extensions[i].extensionName)) {
+ extension_names[enabled_extension_count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
+ }
if (enabled_extension_count >= MAX_EXTENSIONS) {
free(instance_extensions);
ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");
@@ -352,8 +355,6 @@ Error VulkanContext::_initialize_extensions() {
return OK;
}
-typedef void(VKAPI_PTR *_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice, VkPhysicalDeviceProperties2 *);
-
uint32_t VulkanContext::SubgroupCapabilities::supported_stages_flags_rd() const {
uint32_t flags = 0;
@@ -496,20 +497,73 @@ String VulkanContext::SubgroupCapabilities::supported_operations_desc() const {
}
Error VulkanContext::_check_capabilities() {
- // check subgroups
+ // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_multiview.html
// https://www.khronos.org/blog/vulkan-subgroup-tutorial
+
// for Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android.
- _vkGetPhysicalDeviceProperties2 func = (_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2");
- if (func != nullptr) {
+
+ // so we check if the functions are accessible by getting their function pointers and skipping if not
+ // (note that the desktop loader does a better job here but the android loader doesn't)
+
+ // assume not supported until proven otherwise
+ multiview_capabilities.is_supported = false;
+ multiview_capabilities.geometry_shader_is_supported = false;
+ multiview_capabilities.tessellation_shader_is_supported = false;
+ multiview_capabilities.max_view_count = 0;
+ multiview_capabilities.max_instance_count = 0;
+ subgroup_capabilities.size = 0;
+ subgroup_capabilities.supportedStages = 0;
+ subgroup_capabilities.supportedOperations = 0;
+ subgroup_capabilities.quadOperationsInAllStages = false;
+
+ // check for extended features
+ PFN_vkGetPhysicalDeviceFeatures2 device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2");
+ if (device_features_func == nullptr) {
+ // In Vulkan 1.0 might be accessible under its original extension name
+ device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR");
+ }
+ if (device_features_func != nullptr) {
+ // check our extended features
+ VkPhysicalDeviceMultiviewFeatures multiview_features;
+ multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
+ multiview_features.pNext = NULL;
+
+ VkPhysicalDeviceFeatures2 device_features;
+ device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ device_features.pNext = &multiview_features;
+
+ device_features_func(gpu, &device_features);
+ multiview_capabilities.is_supported = multiview_features.multiview;
+ multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader;
+ multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader;
+ }
+
+ // check extended properties
+ PFN_vkGetPhysicalDeviceProperties2 device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2");
+ if (device_properties_func == nullptr) {
+ // In Vulkan 1.0 might be accessible under its original extension name
+ device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR");
+ }
+ if (device_properties_func != nullptr) {
+ VkPhysicalDeviceMultiviewProperties multiviewProperties;
VkPhysicalDeviceSubgroupProperties subgroupProperties;
+ VkPhysicalDeviceProperties2 physicalDeviceProperties;
+
subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
subgroupProperties.pNext = nullptr;
- VkPhysicalDeviceProperties2 physicalDeviceProperties;
physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
- physicalDeviceProperties.pNext = &subgroupProperties;
- func(gpu, &physicalDeviceProperties);
+ if (multiview_capabilities.is_supported) {
+ multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
+ multiviewProperties.pNext = &subgroupProperties;
+
+ physicalDeviceProperties.pNext = &multiviewProperties;
+ } else {
+ physicalDeviceProperties.pNext = &subgroupProperties;
+ }
+
+ device_properties_func(gpu, &physicalDeviceProperties);
subgroup_capabilities.size = subgroupProperties.subgroupSize;
subgroup_capabilities.supportedStages = subgroupProperties.supportedStages;
@@ -519,18 +573,30 @@ Error VulkanContext::_check_capabilities() {
// - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT
subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;
- // only output this when debugging?
- print_line("- Vulkan subgroup size " + itos(subgroup_capabilities.size));
- print_line("- Vulkan subgroup stages " + subgroup_capabilities.supported_stages_desc());
- print_line("- Vulkan subgroup supported ops " + subgroup_capabilities.supported_operations_desc());
+ if (multiview_capabilities.is_supported) {
+ multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount;
+ multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex;
+
+#ifdef DEBUG_ENABLED
+ print_line("- Vulkan multiview supported:");
+ print_line(" max view count: " + itos(multiview_capabilities.max_view_count));
+ print_line(" max instances: " + itos(multiview_capabilities.max_instance_count));
+ } else {
+ print_line("- Vulkan multiview not supported");
+#endif
+ }
+
+#ifdef DEBUG_ENABLED
+ print_line("- Vulkan subgroup:");
+ print_line(" size: " + itos(subgroup_capabilities.size));
+ print_line(" stages: " + subgroup_capabilities.supported_stages_desc());
+ print_line(" supported ops: " + subgroup_capabilities.supported_operations_desc());
if (subgroup_capabilities.quadOperationsInAllStages) {
- print_line("- Vulkan subgroup quad operations in all stages");
+ print_line(" quad operations in all stages");
}
} else {
- subgroup_capabilities.size = 0;
- subgroup_capabilities.supportedStages = 0;
- subgroup_capabilities.supportedOperations = 0;
- subgroup_capabilities.quadOperationsInAllStages = false;
+ print_line("- Couldn't call vkGetPhysicalDeviceProperties2");
+#endif
}
return OK;
@@ -634,8 +700,25 @@ Error VulkanContext::_create_physical_device() {
free(physical_devices);
ERR_FAIL_V(ERR_CANT_CREATE);
}
- /* for now, just grab the first physical device */
+
+ // TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances.
+ // The device should really be a preference, but for now choosing a discrete GPU over the
+ // integrated one is better than the default.
+
+ // Default to first device
uint32_t device_index = 0;
+
+ for (uint32_t i = 0; i < gpu_count; ++i) {
+ VkPhysicalDeviceProperties props;
+ vkGetPhysicalDeviceProperties(physical_devices[i], &props);
+
+ if (props.deviceType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
+ // Prefer discrete GPU.
+ device_index = i;
+ break;
+ }
+ }
+
gpu = physical_devices[device_index];
free(physical_devices);
@@ -695,6 +778,10 @@ Error VulkanContext::_create_physical_device() {
swapchainExtFound = 1;
extension_names[enabled_extension_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
}
+ if (!strcmp(VK_KHR_MULTIVIEW_EXTENSION_NAME, device_extensions[i].extensionName)) {
+ // if multiview is supported, enable it
+ extension_names[enabled_extension_count++] = VK_KHR_MULTIVIEW_EXTENSION_NAME;
+ }
if (enabled_extension_count >= MAX_EXTENSIONS) {
free(device_extensions);
ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");
@@ -816,7 +903,7 @@ Error VulkanContext::_create_physical_device() {
}
}
- /* Call with NULL data to get count */
+ /* Call with nullptr data to get count */
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr);
ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE);
@@ -887,6 +974,39 @@ Error VulkanContext::_create_device() {
queues[1].flags = 0;
sdevice.queueCreateInfoCount = 2;
}
+
+#ifdef VK_VERSION_1_2
+ VkPhysicalDeviceVulkan11Features vulkan11features;
+
+ vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
+ vulkan11features.pNext = nullptr;
+ // !BAS! Need to figure out which ones of these we want enabled...
+ vulkan11features.storageBuffer16BitAccess = 0;
+ vulkan11features.uniformAndStorageBuffer16BitAccess = 0;
+ vulkan11features.storagePushConstant16 = 0;
+ vulkan11features.storageInputOutput16 = 0;
+ vulkan11features.multiview = multiview_capabilities.is_supported;
+ vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
+ vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
+ vulkan11features.variablePointersStorageBuffer = 0;
+ vulkan11features.variablePointers = 0;
+ vulkan11features.protectedMemory = 0;
+ vulkan11features.samplerYcbcrConversion = 0;
+ vulkan11features.shaderDrawParameters = 0;
+
+ sdevice.pNext = &vulkan11features;
+#elif VK_VERSION_1_1
+ VkPhysicalDeviceMultiviewFeatures multiview_features;
+
+ multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
+ multiview_features.pNext = nullptr;
+ multiview_features.multiview = multiview_capabilities.is_supported;
+ multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
+ multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
+
+ sdevice.pNext = &multiview_features;
+#endif
+
err = vkCreateDevice(gpu, &sdevice, nullptr, &device);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
@@ -1596,13 +1716,13 @@ Error VulkanContext::prepare_buffers() {
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
// swapchain is out of date (e.g. the window was resized) and
// must be recreated:
- print_line("early out of data");
+ print_verbose("Vulkan: Early out of date swapchain, recreating.");
//resize_notify();
_update_swap_chain(w);
} else if (err == VK_SUBOPTIMAL_KHR) {
- print_line("early suboptimal");
// swapchain is not as optimal as it could be, but the platform's
// presentation engine will still present the image correctly.
+ print_verbose("Vulkan: Early suboptimal swapchain.");
break;
} else {
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
@@ -1810,12 +1930,12 @@ Error VulkanContext::swap_buffers() {
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
// swapchain is out of date (e.g. the window was resized) and
// must be recreated:
- print_line("out of date");
+ print_verbose("Vulkan: Swapchain is out of date, recreating.");
resize_notify();
} else if (err == VK_SUBOPTIMAL_KHR) {
// swapchain is not as optimal as it could be, but the platform's
// presentation engine will still present the image correctly.
- print_line("suboptimal");
+ print_verbose("Vulkan: Swapchain is suboptimal.");
} else {
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
@@ -1911,13 +2031,13 @@ void VulkanContext::local_device_push_command_buffers(RID p_local_device, const
VkResult err = vkQueueSubmit(ld->queue, 1, &submit_info, VK_NULL_HANDLE);
if (err == VK_ERROR_OUT_OF_HOST_MEMORY) {
- print_line("out of host memory");
+ print_line("Vulkan: Out of host memory!");
}
if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
- print_line("out of device memory");
+ print_line("Vulkan: Out of device memory!");
}
if (err == VK_ERROR_DEVICE_LOST) {
- print_line("device lost");
+ print_line("Vulkan: Device lost!");
}
ERR_FAIL_COND(err);
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 88e4f26bb1..738ead4f96 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -54,6 +54,14 @@ public:
String supported_operations_desc() const;
};
+ struct MultiviewCapabilities {
+ bool is_supported;
+ bool geometry_shader_is_supported;
+ bool tessellation_shader_is_supported;
+ uint32_t max_view_count;
+ uint32_t max_instance_count;
+ };
+
private:
enum {
MAX_EXTENSIONS = 128,
@@ -75,6 +83,7 @@ private:
uint32_t vulkan_major = 1;
uint32_t vulkan_minor = 0;
SubgroupCapabilities subgroup_capabilities;
+ MultiviewCapabilities multiview_capabilities;
String device_vendor;
String device_name;
@@ -227,6 +236,7 @@ public:
uint32_t get_vulkan_major() const { return vulkan_major; };
uint32_t get_vulkan_minor() const { return vulkan_minor; };
SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; };
+ MultiviewCapabilities get_multiview_capabilities() const { return multiview_capabilities; };
VkDevice get_device();
VkPhysicalDevice get_physical_device();
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp
index 2c9f28717d..325bae5b56 100644
--- a/drivers/windows/dir_access_windows.cpp
+++ b/drivers/windows/dir_access_windows.cpp
@@ -198,7 +198,7 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) {
if (_get_root_string() == "") {
int p = current_dir.find(":");
if (p != -1) {
- return current_dir.right(p + 1);
+ return current_dir.substr(p + 1);
}
}
return current_dir;
@@ -208,7 +208,7 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) {
bool DirAccessWindows::file_exists(String p_file) {
GLOBAL_LOCK_FUNCTION
- if (!p_file.is_abs_path()) {
+ if (!p_file.is_absolute_path()) {
p_file = get_current_dir().plus_file(p_file);
}
@@ -325,14 +325,15 @@ FileType DirAccessWindows::get_file_type(const String& p_file) const {
}
*/
-size_t DirAccessWindows::get_space_left() {
+
+uint64_t DirAccessWindows::get_space_left() {
uint64_t bytes = 0;
if (!GetDiskFreeSpaceEx(nullptr, (PULARGE_INTEGER)&bytes, nullptr, nullptr)) {
return 0;
}
//this is either 0 or a value in bytes.
- return (size_t)bytes;
+ return bytes;
}
String DirAccessWindows::get_filesystem_type() const {
diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h
index 7f10023470..1ba4e70e42 100644
--- a/drivers/windows/dir_access_windows.h
+++ b/drivers/windows/dir_access_windows.h
@@ -33,7 +33,7 @@
#ifdef WINDOWS_ENABLED
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
/**
@author Juan Linietsky <reduz@gmail.com>
@@ -78,8 +78,11 @@ public:
virtual Error rename(String p_path, String p_new_path);
virtual Error remove(String p_path);
- //virtual FileType get_file_type() const;
- size_t get_space_left();
+ virtual bool is_link(String p_file) { return false; };
+ virtual String read_link(String p_file) { return p_file; };
+ virtual Error create_link(String p_source, String p_target) { return FAILED; };
+
+ uint64_t get_space_left();
virtual String get_filesystem_type() const;
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index b1b3fc9092..d6deda7b5d 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -193,10 +193,11 @@ bool FileAccessWindows::is_open() const {
return (f != nullptr);
}
-void FileAccessWindows::seek(size_t p_position) {
+void FileAccessWindows::seek(uint64_t p_position) {
ERR_FAIL_COND(!f);
+
last_error = OK;
- if (fseek(f, p_position, SEEK_SET)) {
+ if (_fseeki64(f, p_position, SEEK_SET)) {
check_errors();
}
prev_op = 0;
@@ -204,28 +205,27 @@ void FileAccessWindows::seek(size_t p_position) {
void FileAccessWindows::seek_end(int64_t p_position) {
ERR_FAIL_COND(!f);
- if (fseek(f, p_position, SEEK_END)) {
+ if (_fseeki64(f, p_position, SEEK_END)) {
check_errors();
}
prev_op = 0;
}
-size_t FileAccessWindows::get_position() const {
- size_t aux_position = 0;
- aux_position = ftell(f);
- if (!aux_position) {
+uint64_t FileAccessWindows::get_position() const {
+ int64_t aux_position = _ftelli64(f);
+ if (aux_position < 0) {
check_errors();
}
return aux_position;
}
-size_t FileAccessWindows::get_len() const {
+uint64_t FileAccessWindows::get_length() const {
ERR_FAIL_COND_V(!f, 0);
- size_t pos = get_position();
- fseek(f, 0, SEEK_END);
- int size = get_position();
- fseek(f, pos, SEEK_SET);
+ uint64_t pos = get_position();
+ _fseeki64(f, 0, SEEK_END);
+ uint64_t size = get_position();
+ _fseeki64(f, pos, SEEK_SET);
return size;
}
@@ -252,17 +252,17 @@ uint8_t FileAccessWindows::get_8() const {
return b;
}
-int FileAccessWindows::get_buffer(uint8_t *p_dst, int p_length) const {
+uint64_t FileAccessWindows::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(p_length < 0, -1);
ERR_FAIL_COND_V(!f, -1);
+
if (flags == READ_WRITE || flags == WRITE_READ) {
if (prev_op == WRITE) {
fflush(f);
}
prev_op = READ;
}
- int read = fread(p_dst, 1, p_length, f);
+ uint64_t read = fread(p_dst, 1, p_length, f);
check_errors();
return read;
};
@@ -292,8 +292,9 @@ void FileAccessWindows::store_8(uint8_t p_dest) {
fwrite(&p_dest, 1, 1, f);
}
-void FileAccessWindows::store_buffer(const uint8_t *p_src, int p_length) {
+void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) {
ERR_FAIL_COND(!f);
+ ERR_FAIL_COND(!p_src && p_length > 0);
if (flags == READ_WRITE || flags == WRITE_READ) {
if (prev_op == READ) {
if (last_error != ERR_FILE_EOF) {
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index 507e0b2c20..7280fc3237 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -33,7 +33,7 @@
#ifdef WINDOWS_ENABLED
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/memory.h"
#include <stdio.h>
@@ -56,21 +56,21 @@ public:
virtual String get_path() const; /// returns the path for the current open file
virtual String get_path_absolute() const; /// returns the absolute path for the current open file
- virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek(uint64_t p_position); ///< seek to a given position
virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual size_t get_position() const; ///< get position in the file
- virtual size_t get_len() const; ///< get size of the file
+ virtual uint64_t get_position() const; ///< get position in the file
+ virtual uint64_t get_length() const; ///< get size of the file
virtual bool eof_reached() const; ///< reading passed EOF
virtual uint8_t get_8() const; ///< get a byte
- virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
virtual Error get_error() const; ///< get last error
virtual void flush();
virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
virtual bool file_exists(const String &p_name); ///< return true if a file exists
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 9949fd8199..b0b79ca069 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -63,7 +63,7 @@ static const char *_joy_axis_descriptions[JOY_AXIS_MAX * 2] = {
String InputEventConfigurationDialog::get_event_text(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_V_MSG(p_event.is_null(), String(), "Provided event is not a valid instance of InputEvent");
- // Joypad motion events will display slighlty differently than what the event->as_text() provides. See #43660.
+ // Joypad motion events will display slightly differently than what the event->as_text() provides. See #43660.
Ref<InputEventJoypadMotion> jpmotion = p_event;
if (jpmotion.is_valid()) {
String desc = TTR("Unknown Joypad Axis");
@@ -97,11 +97,11 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event) {
if (mod.is_valid()) {
show_mods = true;
- mod_checkboxes[MOD_ALT]->set_pressed(mod->get_alt());
- mod_checkboxes[MOD_SHIFT]->set_pressed(mod->get_shift());
- mod_checkboxes[MOD_COMMAND]->set_pressed(mod->get_command());
- mod_checkboxes[MOD_CONTROL]->set_pressed(mod->get_control());
- mod_checkboxes[MOD_META]->set_pressed(mod->get_metakey());
+ mod_checkboxes[MOD_ALT]->set_pressed(mod->is_alt_pressed());
+ mod_checkboxes[MOD_SHIFT]->set_pressed(mod->is_shift_pressed());
+ mod_checkboxes[MOD_COMMAND]->set_pressed(mod->is_command_pressed());
+ mod_checkboxes[MOD_CTRL]->set_pressed(mod->is_ctrl_pressed());
+ mod_checkboxes[MOD_META]->set_pressed(mod->is_meta_pressed());
store_command_checkbox->set_pressed(mod->is_storing_command());
}
@@ -122,9 +122,9 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event) {
// Update selected item in input list for keys, joybuttons and joyaxis only (since the mouse cannot be "listened" for).
if (k.is_valid() || joyb.is_valid() || joym.is_valid()) {
- TreeItem *category = input_list_tree->get_root()->get_children();
+ TreeItem *category = input_list_tree->get_root()->get_first_child();
while (category) {
- TreeItem *input_item = category->get_children();
+ TreeItem *input_item = category->get_first_child();
// has_type this should be always true, unless the tree structure has been misconfigured.
bool has_type = input_item->get_parent()->has_meta("__type");
@@ -384,15 +384,15 @@ void InputEventConfigurationDialog::_mod_toggled(bool p_checked, int p_index) {
}
if (p_index == 0) {
- ie->set_alt(p_checked);
+ ie->set_alt_pressed(p_checked);
} else if (p_index == 1) {
- ie->set_shift(p_checked);
+ ie->set_shift_pressed(p_checked);
} else if (p_index == 2) {
- ie->set_command(p_checked);
+ ie->set_command_pressed(p_checked);
} else if (p_index == 3) {
- ie->set_control(p_checked);
+ ie->set_ctrl_pressed(p_checked);
} else if (p_index == 4) {
- ie->set_metakey(p_checked);
+ ie->set_meta_pressed(p_checked);
}
_set_event(ie);
@@ -413,7 +413,7 @@ void InputEventConfigurationDialog::_store_command_toggled(bool p_checked) {
mod_checkboxes[MOD_COMMAND]->show();
mod_checkboxes[MOD_COMMAND]->set_text("Meta (Command)");
#else
- mod_checkboxes[MOD_CONTROL]->hide();
+ mod_checkboxes[MOD_CTRL]->hide();
mod_checkboxes[MOD_COMMAND]->show();
mod_checkboxes[MOD_COMMAND]->set_text("Control (Command)");
@@ -421,7 +421,7 @@ void InputEventConfigurationDialog::_store_command_toggled(bool p_checked) {
} else {
// If not, hide Command, show Control and Meta.
mod_checkboxes[MOD_COMMAND]->hide();
- mod_checkboxes[MOD_CONTROL]->show();
+ mod_checkboxes[MOD_CTRL]->show();
mod_checkboxes[MOD_META]->show();
}
}
@@ -469,11 +469,11 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
}
// Maintain modifier state from checkboxes
- k->set_alt(mod_checkboxes[MOD_ALT]->is_pressed());
- k->set_shift(mod_checkboxes[MOD_SHIFT]->is_pressed());
- k->set_command(mod_checkboxes[MOD_COMMAND]->is_pressed());
- k->set_control(mod_checkboxes[MOD_CONTROL]->is_pressed());
- k->set_metakey(mod_checkboxes[MOD_META]->is_pressed());
+ k->set_alt_pressed(mod_checkboxes[MOD_ALT]->is_pressed());
+ k->set_shift_pressed(mod_checkboxes[MOD_SHIFT]->is_pressed());
+ k->set_command_pressed(mod_checkboxes[MOD_COMMAND]->is_pressed());
+ k->set_ctrl_pressed(mod_checkboxes[MOD_CTRL]->is_pressed());
+ k->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
k->set_store_command(store_command_checkbox->is_pressed());
_set_event(k);
@@ -484,11 +484,11 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
mb.instance();
mb->set_button_index(idx);
// Maintain modifier state from checkboxes
- mb->set_alt(mod_checkboxes[MOD_ALT]->is_pressed());
- mb->set_shift(mod_checkboxes[MOD_SHIFT]->is_pressed());
- mb->set_command(mod_checkboxes[MOD_COMMAND]->is_pressed());
- mb->set_control(mod_checkboxes[MOD_CONTROL]->is_pressed());
- mb->set_metakey(mod_checkboxes[MOD_META]->is_pressed());
+ mb->set_alt_pressed(mod_checkboxes[MOD_ALT]->is_pressed());
+ mb->set_shift_pressed(mod_checkboxes[MOD_SHIFT]->is_pressed());
+ mb->set_command_pressed(mod_checkboxes[MOD_COMMAND]->is_pressed());
+ mb->set_ctrl_pressed(mod_checkboxes[MOD_CTRL]->is_pressed());
+ mb->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
mb->set_store_command(store_command_checkbox->is_pressed());
_set_event(mb);
@@ -730,12 +730,8 @@ void ActionMapEditor::_add_action_pressed() {
}
void ActionMapEditor::_add_action(const String &p_name) {
- if (!allow_editing_actions) {
- return;
- }
-
if (p_name == "" || !_is_action_name_valid(p_name)) {
- show_message(TTR("Invalid action name. it cannot be.is_empty()() nor contain '/', ':', '=', '\\' or '\"'"));
+ show_message(TTR("Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or '\"'"));
return;
}
@@ -744,10 +740,6 @@ void ActionMapEditor::_add_action(const String &p_name) {
}
void ActionMapEditor::_action_edited() {
- if (!allow_editing_actions) {
- return;
- }
-
TreeItem *ti = action_tree->get_edited();
if (!ti) {
return;
@@ -764,7 +756,7 @@ void ActionMapEditor::_action_edited() {
if (new_name == "" || !_is_action_name_valid(new_name)) {
ti->set_text(0, old_name);
- show_message(TTR("Invalid action name. it cannot be.is_empty()() nor contain '/', ':', '=', '\\' or '\"'"));
+ show_message(TTR("Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or '\"'"));
return;
}
@@ -812,10 +804,6 @@ void ActionMapEditor::_tree_button_pressed(Object *p_item, int p_column, int p_i
} break;
case ActionMapEditor::BUTTON_REMOVE_ACTION: {
- if (!allow_editing_actions) {
- break;
- }
-
// Send removed action name
String name = item->get_meta("__name");
emit_signal("action_removed", name);
@@ -848,11 +836,11 @@ void ActionMapEditor::_tree_item_activated() {
_tree_button_pressed(item, 2, BUTTON_EDIT_EVENT);
}
-void ActionMapEditor::set_show_uneditable(bool p_show) {
- show_uneditable = p_show;
- show_uneditable_actions_checkbox->set_pressed(p_show);
+void ActionMapEditor::set_show_builtin_actions(bool p_show) {
+ show_builtin_actions = p_show;
+ show_builtin_actions_checkbutton->set_pressed(p_show);
- // Prevent unnecessary updates of action list when cache is.is_empty()().
+ // Prevent unnecessary updates of action list when cache is empty.
if (!actions_cache.is_empty()) {
update_action_list();
}
@@ -981,9 +969,9 @@ void ActionMapEditor::_notification(int p_what) {
}
void ActionMapEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &ActionMapEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &ActionMapEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &ActionMapEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ActionMapEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ActionMapEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ActionMapEditor::drop_data_fw);
ADD_SIGNAL(MethodInfo("action_added", PropertyInfo(Variant::STRING, "name")));
ADD_SIGNAL(MethodInfo("action_edited", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::DICTIONARY, "new_action")));
@@ -1022,7 +1010,7 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info
continue;
}
- if (!action_info.editable && !show_uneditable) {
+ if (!action_info.editable && !show_builtin_actions) {
continue;
}
@@ -1080,15 +1068,6 @@ void ActionMapEditor::show_message(const String &p_message) {
message->popup_centered(Size2(300, 100) * EDSCALE);
}
-void ActionMapEditor::set_allow_editing_actions(bool p_allow) {
- allow_editing_actions = p_allow;
- add_hbox->set_visible(p_allow);
-}
-
-void ActionMapEditor::set_toggle_editable_label(const String &p_label) {
- show_uneditable_actions_checkbox->set_text(p_label);
-}
-
void ActionMapEditor::use_external_search_box(LineEdit *p_searchbox) {
memdelete(action_list_search);
action_list_search = p_searchbox;
@@ -1096,8 +1075,7 @@ void ActionMapEditor::use_external_search_box(LineEdit *p_searchbox) {
}
ActionMapEditor::ActionMapEditor() {
- allow_editing_actions = true;
- show_uneditable = true;
+ show_builtin_actions = false;
// Main Vbox Container
VBoxContainer *main_vbox = memnew(VBoxContainer);
@@ -1114,11 +1092,11 @@ ActionMapEditor::ActionMapEditor() {
action_list_search->connect("text_changed", callable_mp(this, &ActionMapEditor::_search_term_updated));
top_hbox->add_child(action_list_search);
- show_uneditable_actions_checkbox = memnew(CheckBox);
- show_uneditable_actions_checkbox->set_pressed(false);
- show_uneditable_actions_checkbox->set_text(TTR("Show Uneditable Actions"));
- show_uneditable_actions_checkbox->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_uneditable));
- top_hbox->add_child(show_uneditable_actions_checkbox);
+ show_builtin_actions_checkbutton = memnew(CheckButton);
+ show_builtin_actions_checkbutton->set_pressed(false);
+ show_builtin_actions_checkbutton->set_text(TTR("Show Built-in Actions"));
+ show_builtin_actions_checkbutton->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_builtin_actions));
+ top_hbox->add_child(show_builtin_actions_checkbutton);
// Adding Action line edit + button
add_hbox = memnew(HBoxContainer);
@@ -1128,11 +1106,11 @@ ActionMapEditor::ActionMapEditor() {
add_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_edit->set_placeholder(TTR("Add New Action"));
add_edit->set_clear_button_enabled(true);
- add_edit->connect("text_entered", callable_mp(this, &ActionMapEditor::_add_action));
+ add_edit->connect("text_submitted", callable_mp(this, &ActionMapEditor::_add_action));
add_hbox->add_child(add_edit);
Button *add_button = memnew(Button);
- add_button->set_text("Add");
+ add_button->set_text(TTR("Add"));
add_button->connect("pressed", callable_mp(this, &ActionMapEditor::_add_action_pressed));
add_hbox->add_child(add_button);
diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h
index f1f7bffef4..aff3e6e957 100644
--- a/editor/action_map_editor.h
+++ b/editor/action_map_editor.h
@@ -78,11 +78,11 @@ private:
MOD_ALT,
MOD_SHIFT,
MOD_COMMAND,
- MOD_CONTROL,
+ MOD_CTRL,
MOD_META,
MOD_MAX
};
- String mods[MOD_MAX] = { "Alt", "Shift", "Command", "Control", "Meta" };
+ String mods[MOD_MAX] = { "Alt", "Shift", "Command", "Ctrl", "Metakey" };
CheckBox *mod_checkboxes[MOD_MAX];
CheckBox *store_command_checkbox;
@@ -156,11 +156,10 @@ private:
// Filtering and Adding actions
- bool show_uneditable;
- CheckBox *show_uneditable_actions_checkbox;
+ bool show_builtin_actions;
+ CheckButton *show_builtin_actions_checkbutton;
LineEdit *action_list_search;
- bool allow_editing_actions;
HBoxContainer *add_hbox;
LineEdit *add_edit;
@@ -190,10 +189,7 @@ public:
void update_action_list(const Vector<ActionInfo> &p_action_infos = Vector<ActionInfo>());
void show_message(const String &p_message);
- void set_show_uneditable(bool p_show);
- void set_allow_editing_actions(bool p_allow);
-
- void set_toggle_editable_label(const String &p_label);
+ void set_show_builtin_actions(bool p_show);
void use_external_search_box(LineEdit *p_searchbox);
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index ab8ae71904..63ffab6727 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -619,7 +619,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
float v_zoom_orig = v_zoom;
- if (mb->get_command()) {
+ if (mb->is_command_pressed()) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
} else {
if (v_zoom < 100000) {
@@ -632,7 +632,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
float v_zoom_orig = v_zoom;
- if (mb->get_command()) {
+ if (mb->is_command_pressed()) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
} else {
if (v_zoom > 0.000001) {
@@ -691,9 +691,9 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
//first check point
//command makes it ignore the main point, so control point editors can be force-edited
//path 2D editing in the 3D and 2D editors works the same way
- if (!mb->get_command()) {
+ if (!mb->is_command_pressed()) {
if (edit_points[i].point_rect.has_point(mb->get_position())) {
- if (mb->get_shift()) {
+ if (mb->is_shift_pressed()) {
//add to selection
if (selection.has(i)) {
selection.erase(i);
@@ -743,7 +743,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
//insert new point
- if (mb->get_command() && mb->get_position().x >= timeline->get_name_limit() && mb->get_position().x < get_size().width - timeline->get_buttons_width()) {
+ if (mb->is_command_pressed() && mb->get_position().x >= timeline->get_name_limit() && mb->get_position().x < get_size().width - timeline->get_buttons_width()) {
Array new_point;
new_point.resize(5);
@@ -762,7 +762,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Add Bezier Point"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, time, new_point);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, time);
undo_redo->commit_action();
//then attempt to move
@@ -857,7 +857,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
continue; //already in selection, don't save
}
- undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_position", track, newtime);
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, newtime);
AnimMoveRestore amr;
amr.key = animation->track_get_key_value(track, idx);
@@ -888,7 +888,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
if (newpos<0)
continue; //no remove what no inserted
*/
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, newpos);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, newpos);
}
// 5-(undo) reinsert keys
@@ -961,7 +961,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
if (box_selecting_attempt && mm.is_valid()) {
if (!box_selecting) {
box_selecting = true;
- box_selecting_add = mm->get_shift();
+ box_selecting_add = mm->is_shift_pressed();
}
box_selection_to = mm->get_position();
@@ -1038,7 +1038,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
undo_redo->create_action(TTR("Add Bezier Point"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, time, new_point);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, time);
undo_redo->commit_action();
} break;
@@ -1074,7 +1074,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
int existing_idx = animation->track_find_key(track, dst_time, true);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, dst_time, animation->track_get_key_value(track, E->get()), animation->track_get_key_transition(track, E->get()));
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, dst_time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, dst_time);
Pair<int, float> p;
p.first = track;
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 9db2f0a287..28453eb41d 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -134,7 +134,7 @@ public:
undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans);
undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, new_time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time);
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans);
undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs);
@@ -165,7 +165,7 @@ public:
}
switch (animation->track_get_type(track)) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
Dictionary d_old = animation->track_get_key_value(track, key);
Dictionary d_new = d_old.duplicate();
d_new[p_name] = p_value;
@@ -412,7 +412,7 @@ public:
}
switch (animation->track_get_type(track)) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
Dictionary d = animation->track_get_key_value(track, key);
ERR_FAIL_COND_V(!d.has(name), false);
r_ret = d[p_name];
@@ -523,9 +523,9 @@ public:
}
switch (animation->track_get_type(track)) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
p_list->push_back(PropertyInfo(Variant::VECTOR3, "location"));
- p_list->push_back(PropertyInfo(Variant::QUAT, "rotation"));
+ p_list->push_back(PropertyInfo(Variant::QUATERNION, "rotation"));
p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
} break;
@@ -758,7 +758,7 @@ public:
undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans);
undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, new_time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time);
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans);
undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs);
@@ -781,7 +781,7 @@ public:
}
switch (animation->track_get_type(track)) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
Dictionary d_old = animation->track_get_key_value(track, key);
Dictionary d_new = d_old.duplicate();
d_new[p_name] = p_value;
@@ -1012,7 +1012,7 @@ public:
}
switch (animation->track_get_type(track)) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
Dictionary d = animation->track_get_key_value(track, key);
ERR_FAIL_COND_V(!d.has(name), false);
r_ret = d[p_name];
@@ -1162,9 +1162,9 @@ public:
if (same_track_type) {
switch (animation->track_get_type(first_track)) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
p_list->push_back(PropertyInfo(Variant::VECTOR3, "location"));
- p_list->push_back(PropertyInfo(Variant::QUAT, "rotation"));
+ p_list->push_back(PropertyInfo(Variant::QUATERNION, "rotation"));
p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
} break;
case Animation::TYPE_VALUE: {
@@ -1586,6 +1586,10 @@ void AnimationTimelineEdit::set_zoom(Range *p_zoom) {
zoom->connect("value_changed", callable_mp(this, &AnimationTimelineEdit::_zoom_changed));
}
+void AnimationTimelineEdit::set_track_edit(AnimationTrackEdit *p_track_edit) {
+ track_edit = p_track_edit;
+}
+
void AnimationTimelineEdit::set_play_position(float p_pos) {
play_position_pos = p_pos;
play_position->update();
@@ -1643,7 +1647,31 @@ void AnimationTimelineEdit::_play_position_draw() {
void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- Ref<InputEventMouseButton> mb = p_event;
+ const Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ get_zoom()->set_value(get_zoom()->get_value() * 1.05);
+ accept_event();
+ }
+
+ if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ get_zoom()->set_value(get_zoom()->get_value() / 1.05);
+ accept_event();
+ }
+
+ if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ if (track_edit) {
+ track_edit->get_editor()->goto_prev_step(true);
+ }
+ accept_event();
+ }
+
+ if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ if (track_edit) {
+ track_edit->get_editor()->goto_next_step(true);
+ }
+ accept_event();
+ }
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && hsize_rect.has_point(mb->get_position())) {
dragging_hsize = true;
@@ -1659,7 +1687,7 @@ void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
int x = mb->get_position().x - get_name_limit();
float ofs = x / get_zoom_scale() + get_value();
- emit_signal("timeline_changed", ofs, false);
+ emit_signal("timeline_changed", ofs, false, Input::get_singleton()->is_key_pressed(KEY_ALT));
dragging_timeline = true;
}
if (!dragging_timeline && mb->get_button_index() == MOUSE_BUTTON_MIDDLE) {
@@ -1698,7 +1726,7 @@ void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
if (dragging_timeline) {
int x = mm->get_position().x - get_name_limit();
float ofs = x / get_zoom_scale() + get_value();
- emit_signal("timeline_changed", ofs, false);
+ emit_signal("timeline_changed", ofs, false, Input::get_singleton()->is_key_pressed(KEY_ALT));
}
if (panning_timeline) {
int x = mm->get_position().x - get_name_limit();
@@ -1742,6 +1770,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
editing = false;
name_limit = 150 * EDSCALE;
zoom = nullptr;
+ track_edit = nullptr;
play_position_pos = 0;
play_position = memnew(Control);
@@ -2007,7 +2036,7 @@ void AnimationTrackEdit::_notification(int p_what) {
interp_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
interp_mode_rect.size = icon->get_size();
- if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) {
+ if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) {
draw_texture(icon, interp_mode_rect.position);
}
//make it easier to click
@@ -2017,7 +2046,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + hsep;
interp_mode_rect.size.x += hsep;
- if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) {
+ if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
interp_mode_rect.size.x += down_icon->get_width();
} else {
@@ -2040,7 +2069,7 @@ void AnimationTrackEdit::_notification(int p_what) {
loop_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
loop_mode_rect.size = icon->get_size();
- if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) {
+ if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) {
draw_texture(icon, loop_mode_rect.position);
}
@@ -2050,7 +2079,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + hsep;
loop_mode_rect.size.x += hsep;
- if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) {
+ if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
loop_mode_rect.size.x += down_icon->get_width();
} else {
@@ -2308,6 +2337,7 @@ void AnimationTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) {
void AnimationTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) {
timeline = p_timeline;
+ timeline->set_track_edit(this);
timeline->connect("zoom_changed", callable_mp(this, &AnimationTrackEdit::_zoom_changed));
timeline->connect("name_limit_changed", callable_mp(this, &AnimationTrackEdit::_zoom_changed));
}
@@ -2350,7 +2380,7 @@ void AnimationTrackEdit::_zoom_changed() {
play_position->update();
}
-void AnimationTrackEdit::_path_entered(const String &p_text) {
+void AnimationTrackEdit::_path_submitted(const String &p_text) {
undo_redo->create_action(TTR("Change Track Path"));
undo_redo->add_do_method(animation.ptr(), "track_set_path", track, p_text);
undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
@@ -2441,7 +2471,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
if (key_idx != -1) {
String text = TTR("Time (s): ") + rtos(animation->track_get_key_time(track, key_idx)) + "\n";
switch (animation->track_get_type(track)) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
Dictionary d = animation->track_get_key_value(track, key_idx);
if (d.has("location")) {
text += "Pos: " + String(d["location"]) + "\n";
@@ -2662,7 +2692,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
if (key_idx != -1) {
- if (mb->get_command() || mb->get_shift()) {
+ if (mb->is_command_pressed() || mb->is_shift_pressed()) {
if (editor->is_key_selected(track, key_idx)) {
emit_signal("deselect_key", key_idx);
} else {
@@ -2725,7 +2755,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
path = memnew(LineEdit);
path_popup->add_child(path);
path->set_anchors_and_offsets_preset(PRESET_WIDE);
- path->connect("text_entered", callable_mp(this, &AnimationTrackEdit::_path_entered));
+ path->connect("text_submitted", callable_mp(this, &AnimationTrackEdit::_path_submitted));
}
path->set_text(animation->track_get_path(track));
@@ -3254,8 +3284,8 @@ void AnimationTrackEditor::_name_limit_changed() {
}
}
-void AnimationTrackEditor::_timeline_changed(float p_new_pos, bool p_drag) {
- emit_signal("timeline_changed", p_new_pos, p_drag);
+void AnimationTrackEditor::_timeline_changed(float p_new_pos, bool p_drag, bool p_timeline_only) {
+ emit_signal("timeline_changed", p_new_pos, p_drag, p_timeline_only);
}
void AnimationTrackEditor::_track_remove_request(int p_track) {
@@ -3310,7 +3340,7 @@ static bool track_type_is_resettable(Animation::TrackType p_type) {
[[fallthrough]];
case Animation::TYPE_BEZIER:
[[fallthrough]];
- case Animation::TYPE_TRANSFORM:
+ case Animation::TYPE_TRANSFORM3D:
return true;
default:
return false;
@@ -3376,7 +3406,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
case Variant::FLOAT:
case Variant::VECTOR2:
case Variant::VECTOR3:
- case Variant::QUAT:
+ case Variant::QUATERNION:
case Variant::PLANE:
case Variant::COLOR: {
// Valid.
@@ -3459,7 +3489,7 @@ void AnimationTrackEditor::_insert_delay(bool p_create_reset, bool p_create_bezi
insert_queue = false;
}
-void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Transform &p_xform) {
+void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform) {
if (!keying) {
return;
}
@@ -3479,7 +3509,7 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_
int track_idx = -1;
for (int i = 0; i < animation->get_track_count(); i++) {
- if (animation->track_get_type(i) != Animation::TYPE_TRANSFORM) {
+ if (animation->track_get_type(i) != Animation::TYPE_TRANSFORM3D) {
continue;
}
if (animation->track_get_path(i) != np) {
@@ -3496,7 +3526,7 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_
id.path = np;
id.track_idx = track_idx;
id.value = p_xform;
- id.type = Animation::TYPE_TRANSFORM;
+ id.type = Animation::TYPE_TRANSFORM3D;
id.query = "node '" + p_node->get_name() + "'";
id.advance = false;
@@ -3845,7 +3875,7 @@ static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool
subindices.push_back(":y");
subindices.push_back(":z");
} break;
- case Variant::QUAT: {
+ case Variant::QUATERNION: {
subindices.push_back(":x");
subindices.push_back(":y");
subindices.push_back(":z");
@@ -3911,11 +3941,11 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
h.type == Variant::RECT2 ||
h.type == Variant::VECTOR3 ||
h.type == Variant::AABB ||
- h.type == Variant::QUAT ||
+ h.type == Variant::QUATERNION ||
h.type == Variant::COLOR ||
h.type == Variant::PLANE ||
h.type == Variant::TRANSFORM2D ||
- h.type == Variant::TRANSFORM) {
+ h.type == Variant::TRANSFORM3D) {
update_mode = Animation::UPDATE_CONTINUOUS;
}
@@ -3945,12 +3975,12 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
value = p_id.value;
} break;
- case Animation::TYPE_TRANSFORM: {
- Transform tr = p_id.value;
+ case Animation::TYPE_TRANSFORM3D: {
+ Transform3D tr = p_id.value;
Dictionary d;
d["location"] = tr.origin;
d["scale"] = tr.basis.get_scale();
- d["rotation"] = Quat(tr.basis);
+ d["rotation"] = Quaternion(tr.basis);
value = d;
} break;
case Animation::TYPE_BEZIER: {
@@ -3979,7 +4009,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
p_next_tracks.normal++;
} else {
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_id.track_idx, time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_id.track_idx, time);
int existing = animation->track_find_key(p_id.track_idx, time, true);
if (existing != -1) {
Variant v = animation->track_get_key_value(p_id.track_idx, existing);
@@ -4028,7 +4058,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() ^ Input::get_singleton()->is_key_pressed(KEY_CTRL);
}
void AnimationTrackEditor::_update_tracks() {
@@ -4368,8 +4398,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("Node3D")) {
- EditorNode::get_singleton()->show_warning(TTR("Transform tracks only apply to 3D-based nodes."));
+ if (adding_track_type == Animation::TYPE_TRANSFORM3D && !node->is_class("Node3D")) {
+ EditorNode::get_singleton()->show_warning(TTR("Transform3D tracks only apply to 3D-based nodes."));
return;
}
@@ -4379,7 +4409,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
prop_selector->set_type_filter(Vector<Variant::Type>());
prop_selector->select_property_from_instance(node);
} break;
- case Animation::TYPE_TRANSFORM:
+ case Animation::TYPE_TRANSFORM3D:
case Animation::TYPE_METHOD: {
undo_redo->create_action(TTR("Add Track"));
undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
@@ -4394,7 +4424,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
filter.push_back(Variant::FLOAT);
filter.push_back(Variant::VECTOR2);
filter.push_back(Variant::VECTOR3);
- filter.push_back(Variant::QUAT);
+ filter.push_back(Variant::QUATERNION);
filter.push_back(Variant::PLANE);
filter.push_back(Variant::COLOR);
@@ -4464,11 +4494,11 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) {
h.type == Variant::RECT2 ||
h.type == Variant::VECTOR3 ||
h.type == Variant::AABB ||
- h.type == Variant::QUAT ||
+ h.type == Variant::QUATERNION ||
h.type == Variant::COLOR ||
h.type == Variant::PLANE ||
h.type == Variant::TRANSFORM2D ||
- h.type == Variant::TRANSFORM) {
+ h.type == Variant::TRANSFORM3D) {
update_mode = Animation::UPDATE_CONTINUOUS;
}
@@ -4548,7 +4578,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
}
switch (animation->track_get_type(p_track)) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
if (!root->has_node(animation->track_get_path(p_track))) {
EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a key."));
return;
@@ -4560,15 +4590,15 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
return;
}
- Transform xf = base->get_transform();
+ Transform3D xf = base->get_transform();
Vector3 loc = xf.get_origin();
Vector3 scale = xf.basis.get_scale_local();
- Quat rot = xf.basis;
+ Quaternion rot = xf.basis;
undo_redo->create_action(TTR("Add Transform Track Key"));
undo_redo->add_do_method(animation.ptr(), "transform_track_insert_key", p_track, p_ofs, loc, rot, scale);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
@@ -4580,7 +4610,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
undo_redo->create_action(TTR("Add Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, value);
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
@@ -4611,7 +4641,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
undo_redo->create_action(TTR("Add Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, arr);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
@@ -4623,7 +4653,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
undo_redo->create_action(TTR("Add Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, ak);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
case Animation::TYPE_ANIMATION: {
@@ -4631,7 +4661,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
undo_redo->create_action(TTR("Add Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, anim);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
}
@@ -4669,7 +4699,7 @@ void AnimationTrackEditor::_add_method_key(const String &p_method) {
undo_redo->create_action(TTR("Add Method Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", insert_key_from_track_call_track, insert_key_from_track_call_ofs, d);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", insert_key_from_track_call_track, insert_key_from_track_call_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", insert_key_from_track_call_track, insert_key_from_track_call_ofs);
undo_redo->commit_action();
return;
@@ -4879,7 +4909,7 @@ void AnimationTrackEditor::_move_selection_commit() {
continue; //already in selection, don't save
}
- undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newtime);
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newtime);
_AnimMoveRestore amr;
amr.key = animation->track_get_key_value(E->key().track, idx);
@@ -4899,7 +4929,7 @@ void AnimationTrackEditor::_move_selection_commit() {
// 4 - (undo) remove inserted keys
for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newpos = snap_time(E->get().pos + motion);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newpos);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos);
}
// 5 - (undo) reinsert keys
@@ -4959,16 +4989,26 @@ void AnimationTrackEditor::_box_selection_draw() {
void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
scroll->accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
scroll->accept_event();
}
+ if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ goto_prev_step(true);
+ scroll->accept_event();
+ }
+
+ if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ goto_next_step(true);
+ scroll->accept_event();
+ }
+
if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
box_selecting = true;
@@ -4980,7 +5020,7 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
for (int i = 0; i < track_edits.size(); i++) {
Rect2 local_rect = box_select_rect;
local_rect.position -= track_edits[i]->get_global_position();
- track_edits[i]->append_to_selection(local_rect, mb->get_command());
+ track_edits[i]->append_to_selection(local_rect, mb->is_command_pressed());
}
if (_get_track_selected() == -1 && track_edits.size() > 0) { //minimal hack to make shortcuts work
@@ -5010,7 +5050,7 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
}
if (!box_selection->is_visible_in_tree()) {
- if (!mm->get_command() && !mm->get_shift()) {
+ if (!mm->is_command_pressed() && !mm->is_shift_pressed()) {
_clear_selection();
}
box_selection->show();
@@ -5096,7 +5136,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
int existing_idx = animation->track_find_key(dst_track, dst_time, true);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", dst_track, dst_time, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", dst_track, dst_time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", dst_track, dst_time);
Pair<int, float> p;
p.first = dst_track;
@@ -5143,6 +5183,56 @@ void AnimationTrackEditor::_edit_menu_about_to_popup() {
edit->get_popup()->set_item_disabled(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), !player->can_apply_reset());
}
+void AnimationTrackEditor::goto_prev_step(bool p_from_mouse_event) {
+ if (animation.is_null()) {
+ return;
+ }
+ float step = animation->get_step();
+ if (step == 0) {
+ step = 1;
+ }
+ if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ // Use more precise snapping when holding Shift.
+ // This is used when scrobbling the timeline using Alt + Mouse wheel.
+ step *= 0.25;
+ }
+
+ float pos = timeline->get_play_position();
+ pos = Math::snapped(pos - step, step);
+ if (pos < 0) {
+ pos = 0;
+ }
+ set_anim_pos(pos);
+ emit_signal("timeline_changed", pos, true);
+}
+
+void AnimationTrackEditor::goto_next_step(bool p_from_mouse_event) {
+ if (animation.is_null()) {
+ return;
+ }
+ float step = animation->get_step();
+ if (step == 0) {
+ step = 1;
+ }
+ if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ // Use more precise snapping when holding Shift.
+ // This is used when scrobbling the timeline using Alt + Mouse wheel.
+ // Do not use precise snapping when using the menu action or keyboard shortcut,
+ // as the default keyboard shortcut requires pressing Shift.
+ step *= 0.25;
+ }
+
+ float pos = timeline->get_play_position();
+
+ pos = Math::snapped(pos + step, step);
+ if (pos > animation->get_length()) {
+ pos = animation->get_length();
+ }
+ set_anim_pos(pos);
+
+ emit_signal("timeline_changed", pos, true);
+}
+
void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
last_menu_track_opt = p_option;
switch (p_option) {
@@ -5182,7 +5272,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
switch (animation->track_get_type(i)) {
- case Animation::TYPE_TRANSFORM:
+ case Animation::TYPE_TRANSFORM3D:
text += " (Transform)";
break;
case Animation::TYPE_METHOD:
@@ -5216,7 +5306,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
track_clipboard.clear();
TreeItem *root = track_copy_select->get_root();
if (root) {
- TreeItem *it = root->get_children();
+ TreeItem *it = root->get_first_child();
while (it) {
Dictionary md = it->get_metadata(0);
int idx = md["track_idx"];
@@ -5344,7 +5434,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
continue; //already in selection, don't save
}
- undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newtime);
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newtime);
_AnimMoveRestore amr;
amr.key = animation->track_get_key_value(E->key().track, idx);
@@ -5365,7 +5455,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
// 4-(undo) remove inserted keys
for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newpos = _NEW_POS(E->get().pos);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newpos);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos);
}
// 5-(undo) reinsert keys
@@ -5428,42 +5518,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
} break;
case EDIT_GOTO_NEXT_STEP: {
- if (animation.is_null()) {
- break;
- }
- float step = animation->get_step();
- if (step == 0) {
- step = 1;
- }
-
- float pos = timeline->get_play_position();
-
- pos = Math::snapped(pos + step, step);
- if (pos > animation->get_length()) {
- pos = animation->get_length();
- }
- set_anim_pos(pos);
-
- emit_signal("timeline_changed", pos, true);
-
+ goto_next_step(false);
} break;
case EDIT_GOTO_PREV_STEP: {
- if (animation.is_null()) {
- break;
- }
- float step = animation->get_step();
- if (step == 0) {
- step = 1;
- }
-
- float pos = timeline->get_play_position();
- pos = Math::snapped(pos - step, step);
- if (pos < 0) {
- pos = 0;
- }
- set_anim_pos(pos);
- emit_signal("timeline_changed", pos, true);
-
+ goto_prev_step(false);
} break;
case EDIT_APPLY_RESET: {
AnimationPlayerEditor::singleton->get_player()->apply_reset(true);
@@ -5602,7 +5660,7 @@ void AnimationTrackEditor::_show_imported_anim_warning() {
}
void AnimationTrackEditor::_select_all_tracks_for_copy() {
- TreeItem *track = track_copy_select->get_root()->get_children();
+ TreeItem *track = track_copy_select->get_root()->get_first_child();
if (!track) {
return;
}
@@ -5616,7 +5674,7 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() {
track = track->get_next();
}
- track = track_copy_select->get_root()->get_children();
+ track = track_copy_select->get_root()->get_first_child();
while (track) {
track->set_checked(0, !all_selected);
track = track->get_next();
@@ -5681,7 +5739,7 @@ void AnimationTrackEditor::_pick_track_select_recursive(TreeItem *p_item, const
p_select_candidates.push_back(node);
}
- TreeItem *c = p_item->get_children();
+ TreeItem *c = p_item->get_first_child();
while (c) {
_pick_track_select_recursive(c, p_filter, p_select_candidates);
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index c25865effb..6d977e5a3f 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -49,10 +49,13 @@
class AnimationPlayer;
+class AnimationTrackEdit;
+
class AnimationTimelineEdit : public Range {
GDCLASS(AnimationTimelineEdit, Range);
Ref<Animation> animation;
+ AnimationTrackEdit *track_edit;
int name_limit;
Range *zoom;
Range *h_scroll;
@@ -101,6 +104,7 @@ public:
virtual Size2 get_minimum_size() const override;
void set_animation(const Ref<Animation> &p_animation);
+ void set_track_edit(AnimationTrackEdit *p_track_edit);
void set_zoom(Range *p_zoom);
Range *get_zoom() const { return zoom; }
void set_undo_redo(UndoRedo *p_undo_redo);
@@ -173,7 +177,7 @@ class AnimationTrackEdit : public Control {
void _menu_selected(int p_index);
- void _path_entered(const String &p_text);
+ void _path_submitted(const String &p_text);
void _play_position_draw();
bool _is_value_key_valid(const Variant &p_key_value, Variant::Type &r_valid_type) const;
@@ -236,8 +240,8 @@ public:
AnimationTrackEdit();
};
-class AnimationTrackEditPlugin : public Reference {
- GDCLASS(AnimationTrackEditPlugin, Reference);
+class AnimationTrackEditPlugin : public RefCounted {
+ GDCLASS(AnimationTrackEditPlugin, RefCounted);
public:
virtual AnimationTrackEdit *create_value_track_edit(Object *p_object, Variant::Type p_type, const String &p_property, PropertyHint p_hint, const String &p_hint_string, int p_usage);
@@ -275,25 +279,6 @@ public:
class AnimationTrackEditor : public VBoxContainer {
GDCLASS(AnimationTrackEditor, VBoxContainer);
- enum {
- EDIT_COPY_TRACKS,
- EDIT_COPY_TRACKS_CONFIRM,
- EDIT_PASTE_TRACKS,
- EDIT_SCALE_SELECTION,
- EDIT_SCALE_FROM_CURSOR,
- EDIT_SCALE_CONFIRM,
- EDIT_DUPLICATE_SELECTION,
- EDIT_DUPLICATE_TRANSPOSED,
- EDIT_DELETE_SELECTION,
- EDIT_GOTO_NEXT_STEP,
- EDIT_GOTO_PREV_STEP,
- EDIT_APPLY_RESET,
- EDIT_OPTIMIZE_ANIMATION,
- EDIT_OPTIMIZE_ANIMATION_CONFIRM,
- EDIT_CLEAN_UP_ANIMATION,
- EDIT_CLEAN_UP_ANIMATION_CONFIRM
- };
-
Ref<Animation> animation;
Node *root;
@@ -328,7 +313,7 @@ class AnimationTrackEditor : public VBoxContainer {
void _update_tracks();
void _name_limit_changed();
- void _timeline_changed(float p_new_pos, bool p_drag);
+ void _timeline_changed(float p_new_pos, bool p_drag, bool p_timeline_only = false);
void _track_remove_request(int p_track);
void _track_grab_focus(int p_track);
@@ -508,6 +493,25 @@ protected:
void _notification(int p_what);
public:
+ enum {
+ EDIT_COPY_TRACKS,
+ EDIT_COPY_TRACKS_CONFIRM,
+ EDIT_PASTE_TRACKS,
+ EDIT_SCALE_SELECTION,
+ EDIT_SCALE_FROM_CURSOR,
+ EDIT_SCALE_CONFIRM,
+ EDIT_DUPLICATE_SELECTION,
+ EDIT_DUPLICATE_TRANSPOSED,
+ EDIT_DELETE_SELECTION,
+ EDIT_GOTO_NEXT_STEP,
+ EDIT_GOTO_PREV_STEP,
+ EDIT_APPLY_RESET,
+ EDIT_OPTIMIZE_ANIMATION,
+ EDIT_OPTIMIZE_ANIMATION_CONFIRM,
+ EDIT_CLEAN_UP_ANIMATION,
+ EDIT_CLEAN_UP_ANIMATION_CONFIRM
+ };
+
void add_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
void remove_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
@@ -526,7 +530,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(Node3D *p_node, const String &p_sub, const Transform &p_xform);
+ void insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform);
void show_select_node_warning(bool p_show);
@@ -538,6 +542,12 @@ public:
float snap_time(float p_value, bool p_relative = false);
bool is_grouping_tracks();
+ /** If `p_from_mouse_event` is `true`, handle Shift key presses for precise snapping. */
+ void goto_prev_step(bool p_from_mouse_event);
+
+ /** If `p_from_mouse_event` is `true`, handle Shift key presses for precise snapping. */
+ void goto_next_step(bool p_from_mouse_event);
+
MenuButton *get_edit_menu();
AnimationTrackEditor();
~AnimationTrackEditor();
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index 506a327ffc..54c1e89d1e 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -1024,7 +1024,7 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant
get_undo_redo()->create_action(TTR("Add Audio Track Clip"));
get_undo_redo()->add_do_method(get_animation().ptr(), "audio_track_insert_key", get_track(), ofs, stream);
- get_undo_redo()->add_undo_method(get_animation().ptr(), "track_remove_key_at_position", get_track(), ofs);
+ get_undo_redo()->add_undo_method(get_animation().ptr(), "track_remove_key_at_time", get_track(), ofs);
get_undo_redo()->commit_action();
update();
@@ -1091,7 +1091,7 @@ void AnimationTrackEditTypeAudio::_gui_input(const Ref<InputEvent> &p_event) {
if (len_resizing && mm.is_valid()) {
len_resizing_rel += mm->get_relative().x;
- len_resizing_start = mm->get_shift();
+ len_resizing_start = mm->is_shift_pressed();
update();
accept_event();
return;
@@ -1100,7 +1100,7 @@ void AnimationTrackEditTypeAudio::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && get_default_cursor_shape() == CURSOR_HSIZE) {
len_resizing = true;
- len_resizing_start = mb->get_shift();
+ len_resizing_start = mb->is_shift_pressed();
len_resizing_from_px = mb->get_position().x;
len_resizing_rel = 0;
update();
diff --git a/editor/array_property_edit.h b/editor/array_property_edit.h
index fa3dcbe038..d7e11936a3 100644
--- a/editor/array_property_edit.h
+++ b/editor/array_property_edit.h
@@ -33,8 +33,8 @@
#include "scene/main/node.h"
-class ArrayPropertyEdit : public Reference {
- GDCLASS(ArrayPropertyEdit, Reference);
+class ArrayPropertyEdit : public RefCounted {
+ GDCLASS(ArrayPropertyEdit, RefCounted);
int page;
ObjectID obj;
diff --git a/editor/audio_stream_preview.h b/editor/audio_stream_preview.h
index accc7275c0..61567598ed 100644
--- a/editor/audio_stream_preview.h
+++ b/editor/audio_stream_preview.h
@@ -36,8 +36,8 @@
#include "scene/main/node.h"
#include "servers/audio/audio_stream.h"
-class AudioStreamPreview : public Reference {
- GDCLASS(AudioStreamPreview, Reference);
+class AudioStreamPreview : public RefCounted {
+ GDCLASS(AudioStreamPreview, RefCounted);
friend class AudioStream;
Vector<uint8_t> preview;
float length;
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 1c62c3d3e1..807a45eb32 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -302,7 +302,7 @@ void FindReplaceBar::_replace_all() {
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_editor->call_deferred("connect", "text_changed", Callable(this, "_editor_text_changed"));
+ text_editor->call_deferred("connect", "text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed));
results_count = -1;
}
@@ -539,7 +539,7 @@ void FindReplaceBar::_search_text_changed(const String &p_text) {
search_current();
}
-void FindReplaceBar::_search_text_entered(const String &p_text) {
+void FindReplaceBar::_search_text_submitted(const String &p_text) {
if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
search_prev();
} else {
@@ -547,7 +547,7 @@ void FindReplaceBar::_search_text_entered(const String &p_text) {
}
}
-void FindReplaceBar::_replace_text_entered(const String &p_text) {
+void FindReplaceBar::_replace_text_submitted(const String &p_text) {
if (selection_only->is_pressed() && text_editor->is_selection_active()) {
_replace_all();
_hide_bar();
@@ -583,15 +583,29 @@ void FindReplaceBar::set_error(const String &p_label) {
emit_signal("error", p_label);
}
-void FindReplaceBar::set_text_edit(CodeEdit *p_text_edit) {
+void FindReplaceBar::set_text_edit(CodeTextEditor *p_text_editor) {
+ if (p_text_editor == base_text_editor) {
+ return;
+ }
+
+ if (base_text_editor) {
+ base_text_editor->remove_find_replace_bar();
+ base_text_editor = nullptr;
+ text_editor->disconnect("text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed));
+ text_editor = nullptr;
+ }
+
results_count = -1;
- text_editor = p_text_edit;
+ base_text_editor = p_text_editor;
+ text_editor = base_text_editor->get_text_editor();
text_editor->connect("text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed));
+
+ _update_results_count();
+ _update_matches_label();
}
void FindReplaceBar::_bind_methods() {
ClassDB::bind_method("_unhandled_input", &FindReplaceBar::_unhandled_input);
-
ClassDB::bind_method("_search_current", &FindReplaceBar::search_current);
ADD_SIGNAL(MethodInfo("search"));
@@ -629,7 +643,7 @@ FindReplaceBar::FindReplaceBar() {
vbc_lineedit->add_child(search_text);
search_text->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
search_text->connect("text_changed", callable_mp(this, &FindReplaceBar::_search_text_changed));
- search_text->connect("text_entered", callable_mp(this, &FindReplaceBar::_search_text_entered));
+ search_text->connect("text_submitted", callable_mp(this, &FindReplaceBar::_search_text_submitted));
matches_label = memnew(Label);
hbc_button_search->add_child(matches_label);
@@ -663,7 +677,7 @@ FindReplaceBar::FindReplaceBar() {
replace_text = memnew(LineEdit);
vbc_lineedit->add_child(replace_text);
replace_text->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- replace_text->connect("text_entered", callable_mp(this, &FindReplaceBar::_replace_text_entered));
+ replace_text->connect("text_submitted", callable_mp(this, &FindReplaceBar::_replace_text_submitted));
replace = memnew(Button);
hbc_button_replace->add_child(replace);
@@ -726,7 +740,7 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_command()) {
+ if (mb->is_pressed() && mb->is_command_pressed()) {
if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
_zoom_in();
} else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
@@ -816,12 +830,12 @@ void CodeTextEditor::_code_complete_timer_timeout() {
if (!is_visible_in_tree()) {
return;
}
- text_editor->query_code_comple();
+ text_editor->request_code_completion();
}
void CodeTextEditor::_complete_request() {
List<ScriptCodeCompletionOption> entries;
- String ctext = text_editor->get_text_for_completion();
+ String ctext = text_editor->get_text_for_code_completion();
_code_complete_script(ctext, &entries);
bool forced = false;
if (code_complete_func) {
@@ -832,16 +846,17 @@ void CodeTextEditor::_complete_request() {
}
for (List<ScriptCodeCompletionOption>::Element *E = entries.front(); E; E = E->next()) {
- ScriptCodeCompletionOption *e = &E->get();
- e->icon = _get_completion_icon(*e);
- e->font_color = completion_font_color;
- if (e->insert_text.begins_with("\"") || e->insert_text.begins_with("\'")) {
- e->font_color = completion_string_color;
- } else if (e->insert_text.begins_with("#") || e->insert_text.begins_with("//")) {
- e->font_color = completion_comment_color;
+ ScriptCodeCompletionOption &e = E->get();
+
+ Color font_color = completion_font_color;
+ if (e.insert_text.begins_with("\"") || e.insert_text.begins_with("\'")) {
+ font_color = completion_string_color;
+ } else if (e.insert_text.begins_with("#") || e.insert_text.begins_with("//")) {
+ font_color = completion_comment_color;
}
+ text_editor->add_code_completion_option((CodeEdit::CodeCompletionKind)e.kind, e.display, e.insert_text, font_color, _get_completion_icon(e), e.default_value);
}
- text_editor->code_complete(entries, forced);
+ text_editor->update_code_completion_options(forced);
}
Ref<Texture2D> CodeTextEditor::_get_completion_icon(const ScriptCodeCompletionOption &p_option) {
@@ -925,7 +940,7 @@ void CodeTextEditor::update_editor_settings() {
text_editor->set_draw_line_numbers(EditorSettings::get_singleton()->get("text_editor/appearance/show_line_numbers"));
text_editor->set_line_numbers_zero_padded(EditorSettings::get_singleton()->get("text_editor/appearance/line_numbers_zero_padded"));
text_editor->set_draw_bookmarks_gutter(EditorSettings::get_singleton()->get("text_editor/appearance/show_bookmark_gutter"));
- text_editor->set_hiding_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding"));
+ text_editor->set_line_folding_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding"));
text_editor->set_draw_fold_gutter(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding"));
text_editor->set_wrap_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/word_wrap"));
text_editor->set_show_line_length_guidelines(EditorSettings::get_singleton()->get("text_editor/appearance/show_line_length_guidelines"));
@@ -938,6 +953,25 @@ void CodeTextEditor::update_editor_settings() {
text_editor->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete"));
}
+void CodeTextEditor::set_find_replace_bar(FindReplaceBar *p_bar) {
+ if (find_replace_bar) {
+ return;
+ }
+
+ find_replace_bar = p_bar;
+ find_replace_bar->set_text_edit(this);
+ find_replace_bar->connect("error", callable_mp(error, &Label::set_text));
+}
+
+void CodeTextEditor::remove_find_replace_bar() {
+ if (!find_replace_bar) {
+ return;
+ }
+
+ find_replace_bar->disconnect("error", callable_mp(error, &Label::set_text));
+ find_replace_bar = nullptr;
+}
+
void CodeTextEditor::trim_trailing_whitespace() {
bool trimed_whitespace = false;
for (int i = 0; i < text_editor->get_line_count(); i++) {
@@ -1012,7 +1046,7 @@ void CodeTextEditor::convert_indent_to_spaces() {
if (cursor_line == i && cursor_column > j) {
cursor_column += indent_size - 1;
}
- line = line.left(j) + indent + line.right(j + 1);
+ line = line.left(j) + indent + line.substr(j + 1);
}
j++;
}
@@ -1056,7 +1090,7 @@ void CodeTextEditor::convert_indent_to_tabs() {
if (cursor_line == i && cursor_column > j) {
cursor_column -= indent_size;
}
- line = line.left(j - indent_size) + "\t" + line.right(j + 1);
+ line = line.left(j - indent_size) + "\t" + line.substr(j + 1);
j = 0;
space_count = -1;
}
@@ -1114,7 +1148,7 @@ void CodeTextEditor::convert_case(CaseStyle p_case) {
new_line = text_editor->get_line(i).left(begin_col) + new_line;
}
if (i == end) {
- new_line = new_line + text_editor->get_line(i).right(end_col);
+ new_line = new_line + text_editor->get_line(i).substr(end_col);
}
text_editor->set_line(i, new_line);
}
@@ -1468,12 +1502,41 @@ void CodeTextEditor::set_error_pos(int p_line, int p_column) {
void CodeTextEditor::goto_error() {
if (error->get_text() != "") {
+ text_editor->unfold_line(error_line);
text_editor->cursor_set_line(error_line);
text_editor->cursor_set_column(error_column);
text_editor->center_viewport_to_cursor();
}
}
+void CodeTextEditor::_update_text_editor_theme() {
+ text_editor->add_theme_color_override("background_color", EDITOR_GET("text_editor/highlighting/background_color"));
+ text_editor->add_theme_color_override("completion_background_color", EDITOR_GET("text_editor/highlighting/completion_background_color"));
+ text_editor->add_theme_color_override("completion_selected_color", EDITOR_GET("text_editor/highlighting/completion_selected_color"));
+ text_editor->add_theme_color_override("completion_existing_color", EDITOR_GET("text_editor/highlighting/completion_existing_color"));
+ text_editor->add_theme_color_override("completion_scroll_color", EDITOR_GET("text_editor/highlighting/completion_scroll_color"));
+ text_editor->add_theme_color_override("completion_font_color", EDITOR_GET("text_editor/highlighting/completion_font_color"));
+ text_editor->add_theme_color_override("font_color", EDITOR_GET("text_editor/highlighting/text_color"));
+ text_editor->add_theme_color_override("line_number_color", EDITOR_GET("text_editor/highlighting/line_number_color"));
+ text_editor->add_theme_color_override("caret_color", EDITOR_GET("text_editor/highlighting/caret_color"));
+ text_editor->add_theme_color_override("caret_background_color", EDITOR_GET("text_editor/highlighting/caret_background_color"));
+ text_editor->add_theme_color_override("font_selected_color", EDITOR_GET("text_editor/highlighting/text_selected_color"));
+ text_editor->add_theme_color_override("selection_color", EDITOR_GET("text_editor/highlighting/selection_color"));
+ text_editor->add_theme_color_override("brace_mismatch_color", EDITOR_GET("text_editor/highlighting/brace_mismatch_color"));
+ text_editor->add_theme_color_override("current_line_color", EDITOR_GET("text_editor/highlighting/current_line_color"));
+ text_editor->add_theme_color_override("line_length_guideline_color", EDITOR_GET("text_editor/highlighting/line_length_guideline_color"));
+ text_editor->add_theme_color_override("word_highlighted_color", EDITOR_GET("text_editor/highlighting/word_highlighted_color"));
+ text_editor->add_theme_color_override("bookmark_color", EDITOR_GET("text_editor/highlighting/bookmark_color"));
+ text_editor->add_theme_color_override("breakpoint_color", EDITOR_GET("text_editor/highlighting/breakpoint_color"));
+ text_editor->add_theme_color_override("executing_line_color", EDITOR_GET("text_editor/highlighting/executing_line_color"));
+ text_editor->add_theme_color_override("code_folding_color", EDITOR_GET("text_editor/highlighting/code_folding_color"));
+ text_editor->add_theme_color_override("search_result_color", EDITOR_GET("text_editor/highlighting/search_result_color"));
+ text_editor->add_theme_color_override("search_result_border_color", EDITOR_GET("text_editor/highlighting/search_result_border_color"));
+ text_editor->add_theme_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6));
+ emit_signal("load_theme_settings");
+ _load_theme_settings();
+}
+
void CodeTextEditor::_update_font() {
text_editor->add_theme_font_override("font", get_theme_font("source", "EditorFonts"));
text_editor->add_theme_font_size_override("font_size", get_theme_font_size("source_size", "EditorFonts"));
@@ -1497,6 +1560,7 @@ void CodeTextEditor::_update_font() {
}
void CodeTextEditor::_on_settings_change() {
+ _update_text_editor_theme();
_update_font();
font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size");
@@ -1534,9 +1598,7 @@ void CodeTextEditor::_on_settings_change() {
EDITOR_GET("text_editor/completion/code_complete_delay"));
// Call hint settings.
- text_editor->set_callhint_settings(
- EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line"),
- EDITOR_GET("text_editor/completion/callhint_tooltip_offset"));
+ text_editor->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line"));
idle->set_wait_time(EDITOR_GET("text_editor/completion/idle_parse_delay"));
}
@@ -1583,14 +1645,11 @@ void CodeTextEditor::_error_pressed(const Ref<InputEvent> &p_event) {
void CodeTextEditor::_notification(int p_what) {
switch (p_what) {
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- _load_theme_settings();
- emit_signal("load_theme_settings");
- } break;
case NOTIFICATION_THEME_CHANGED: {
if (toggle_scripts_button->is_visible()) {
update_toggle_scripts_button();
}
+ _update_text_editor_theme();
_update_font();
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -1735,14 +1794,6 @@ CodeTextEditor::CodeTextEditor() {
} break;
}
- // Added second so it opens at the bottom, so it won't shift the entire text editor when opening.
- find_replace_bar = memnew(FindReplaceBar);
- add_child(find_replace_bar);
- find_replace_bar->set_h_size_flags(SIZE_EXPAND_FILL);
- find_replace_bar->hide();
-
- find_replace_bar->set_text_edit(text_editor);
-
text_editor->set_draw_line_numbers(true);
text_editor->set_brace_matching(true);
text_editor->set_auto_indent(true);
@@ -1783,7 +1834,6 @@ CodeTextEditor::CodeTextEditor() {
error->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
error->set_mouse_filter(MOUSE_FILTER_STOP);
error->connect("gui_input", callable_mp(this, &CodeTextEditor::_error_pressed));
- find_replace_bar->connect("error", callable_mp(error, &Label::set_text));
// Warnings
warning_button = memnew(Button);
@@ -1821,15 +1871,17 @@ CodeTextEditor::CodeTextEditor() {
text_editor->connect("gui_input", callable_mp(this, &CodeTextEditor::_text_editor_gui_input));
text_editor->connect("cursor_changed", callable_mp(this, &CodeTextEditor::_line_col_changed));
text_editor->connect("text_changed", callable_mp(this, &CodeTextEditor::_text_changed));
- text_editor->connect("request_completion", callable_mp(this, &CodeTextEditor::_complete_request));
- Vector<String> cs;
+ text_editor->connect("request_code_completion", callable_mp(this, &CodeTextEditor::_complete_request));
+ TypedArray<String> cs;
cs.push_back(".");
cs.push_back(",");
cs.push_back("(");
cs.push_back("=");
cs.push_back("$");
cs.push_back("@");
- text_editor->set_completion(true, cs);
+ cs.push_back("\"");
+ cs.push_back("\'");
+ text_editor->set_code_completion_prefixes(cs);
idle->connect("timeout", callable_mp(this, &CodeTextEditor::_text_changed_idle_timeout));
code_complete_timer->connect("timeout", callable_mp(this, &CodeTextEditor::_code_complete_timer_timeout));
diff --git a/editor/code_editor.h b/editor/code_editor.h
index e201da446e..f368305e85 100644
--- a/editor/code_editor.h
+++ b/editor/code_editor.h
@@ -57,6 +57,8 @@ public:
GotoLineDialog();
};
+class CodeTextEditor;
+
class FindReplaceBar : public HBoxContainer {
GDCLASS(FindReplaceBar, HBoxContainer);
@@ -77,6 +79,7 @@ class FindReplaceBar : public HBoxContainer {
HBoxContainer *hbc_button_replace;
HBoxContainer *hbc_option_replace;
+ CodeTextEditor *base_text_editor = nullptr;
CodeEdit *text_editor;
int result_line;
@@ -96,8 +99,8 @@ class FindReplaceBar : public HBoxContainer {
void _editor_text_changed();
void _search_options_changed(bool p_pressed);
void _search_text_changed(const String &p_text);
- void _search_text_entered(const String &p_text);
- void _replace_text_entered(const String &p_text);
+ void _search_text_submitted(const String &p_text);
+ void _replace_text_submitted(const String &p_text);
void _update_size();
protected:
@@ -120,7 +123,7 @@ public:
bool is_selection_only() const;
void set_error(const String &p_label);
- void set_text_edit(CodeEdit *p_text_edit);
+ void set_text_edit(CodeTextEditor *p_text_editor);
void popup_search(bool p_show_only = false);
void popup_replace();
@@ -138,7 +141,7 @@ class CodeTextEditor : public VBoxContainer {
GDCLASS(CodeTextEditor, VBoxContainer);
CodeEdit *text_editor;
- FindReplaceBar *find_replace_bar;
+ FindReplaceBar *find_replace_bar = nullptr;
HBoxContainer *status_bar;
Button *toggle_scripts_button;
@@ -161,6 +164,7 @@ class CodeTextEditor : public VBoxContainer {
void _on_settings_change();
+ void _update_text_editor_theme();
void _update_font();
void _complete_request();
Ref<Texture2D> _get_completion_icon(const ScriptCodeCompletionOption &p_option);
@@ -242,6 +246,8 @@ public:
void update_line_and_column() { _line_col_changed(); }
CodeEdit *get_text_editor() { return text_editor; }
FindReplaceBar *get_find_replace_bar() { return find_replace_bar; }
+ void set_find_replace_bar(FindReplaceBar *p_bar);
+ void remove_find_replace_bar();
virtual void apply_code() {}
void goto_error();
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 0c1fb6fe4d..de6407da73 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -66,8 +66,8 @@ public:
bool _set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
- if (name.begins_with("bind/")) {
- int which = name.get_slice("/", 1).to_int() - 1;
+ if (name.begins_with("bind/argument_")) {
+ int which = name.get_slice("_", 1).to_int() - 1;
ERR_FAIL_INDEX_V(which, params.size(), false);
params.write[which] = p_value;
} else {
@@ -80,8 +80,8 @@ public:
bool _get(const StringName &p_name, Variant &r_ret) const {
String name = p_name;
- if (name.begins_with("bind/")) {
- int which = name.get_slice("/", 1).to_int() - 1;
+ if (name.begins_with("bind/argument_")) {
+ int which = name.get_slice("_", 1).to_int() - 1;
ERR_FAIL_INDEX_V(which, params.size(), false);
r_ret = params[which];
} else {
@@ -93,7 +93,7 @@ public:
void _get_property_list(List<PropertyInfo> *p_list) const {
for (int i = 0; i < params.size(); i++) {
- p_list->push_back(PropertyInfo(params[i].get_type(), "bind/" + itos(i + 1)));
+ p_list->push_back(PropertyInfo(params[i].get_type(), "bind/argument_" + itos(i + 1)));
}
}
@@ -146,7 +146,7 @@ void ConnectDialog::_item_activated() {
_ok_pressed(); // From AcceptDialog.
}
-void ConnectDialog::_text_entered(const String &p_text) {
+void ConnectDialog::_text_submitted(const String &p_text) {
_ok_pressed(); // From AcceptDialog.
}
@@ -203,8 +203,8 @@ void ConnectDialog::_add_bind() {
case Variant::PLANE:
value = Plane();
break;
- case Variant::QUAT:
- value = Quat();
+ case Variant::QUATERNION:
+ value = Quaternion();
break;
case Variant::AABB:
value = AABB();
@@ -212,8 +212,8 @@ void ConnectDialog::_add_bind() {
case Variant::BASIS:
value = Basis();
break;
- case Variant::TRANSFORM:
- value = Transform();
+ case Variant::TRANSFORM3D:
+ value = Transform3D();
break;
case Variant::COLOR:
value = Color();
@@ -443,10 +443,10 @@ ConnectDialog::ConnectDialog() {
type_list->add_item("Rect2", Variant::RECT2);
type_list->add_item("Vector3", Variant::VECTOR3);
type_list->add_item("Plane", Variant::PLANE);
- type_list->add_item("Quat", Variant::QUAT);
+ type_list->add_item("Quaternion", Variant::QUATERNION);
type_list->add_item("AABB", Variant::AABB);
type_list->add_item("Basis", Variant::BASIS);
- type_list->add_item("Transform", Variant::TRANSFORM);
+ type_list->add_item("Transform3D", Variant::TRANSFORM3D);
type_list->add_item("Color", Variant::COLOR);
type_list->select(0);
@@ -471,7 +471,7 @@ ConnectDialog::ConnectDialog() {
dst_method = memnew(LineEdit);
dst_method->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- dst_method->connect("text_entered", callable_mp(this, &ConnectDialog::_text_entered));
+ dst_method->connect("text_submitted", callable_mp(this, &ConnectDialog::_text_submitted));
dstm_hb->add_child(dst_method);
advanced = memnew(CheckButton);
@@ -655,7 +655,7 @@ void ConnectionsDock::_disconnect_all() {
return;
}
- TreeItem *child = item->get_children();
+ TreeItem *child = item->get_first_child();
String signalName = item->get_metadata(0).operator Dictionary()["name"];
undo_redo->create_action(vformat(TTR("Disconnect all from signal: '%s'"), signalName));
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index 18feba0a61..b9911c1cc5 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -105,7 +105,7 @@ private:
void ok_pressed() override;
void _cancel_pressed();
void _item_activated();
- void _text_entered(const String &_text);
+ void _text_submitted(const String &_text);
void _tree_node_selected();
void _add_bind();
void _remove_bind();
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 711072f4b2..968b24893c 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -643,9 +643,9 @@ void CreateDialog::_load_favorites_and_history() {
void CreateDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_save_and_update_favorite_list"), &CreateDialog::_save_and_update_favorite_list);
- ClassDB::bind_method("get_drag_data_fw", &CreateDialog::get_drag_data_fw);
- ClassDB::bind_method("can_drop_data_fw", &CreateDialog::can_drop_data_fw);
- ClassDB::bind_method("drop_data_fw", &CreateDialog::drop_data_fw);
+ ClassDB::bind_method("_get_drag_data_fw", &CreateDialog::get_drag_data_fw);
+ ClassDB::bind_method("_can_drop_data_fw", &CreateDialog::can_drop_data_fw);
+ ClassDB::bind_method("_drop_data_fw", &CreateDialog::drop_data_fw);
ADD_SIGNAL(MethodInfo("create"));
ADD_SIGNAL(MethodInfo("favorites_updated"));
@@ -708,7 +708,6 @@ CreateDialog::CreateDialog() {
search_hb->add_child(search_box);
favorite = memnew(Button);
- favorite->set_flat(true);
favorite->set_toggle_mode(true);
favorite->set_tooltip(TTR("(Un)favorite selected item."));
favorite->connect("pressed", callable_mp(this, &CreateDialog::_favorite_toggled));
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 3ef9548727..ded0ee3aa7 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -209,7 +209,7 @@ void EditorDebuggerNode::stop() {
// Also close all debugging sessions.
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
if (dbg->is_session_active()) {
- dbg->stop();
+ dbg->_stop_and_notify();
}
});
_break_state_changed();
diff --git a/editor/debugger/editor_debugger_server.cpp b/editor/debugger/editor_debugger_server.cpp
index 4add891bcb..662f247062 100644
--- a/editor/debugger/editor_debugger_server.cpp
+++ b/editor/debugger/editor_debugger_server.cpp
@@ -40,7 +40,7 @@
class EditorDebuggerServerTCP : public EditorDebuggerServer {
private:
- Ref<TCP_Server> server;
+ Ref<TCPServer> server;
public:
static EditorDebuggerServer *create(const String &p_protocol);
diff --git a/editor/debugger/editor_debugger_server.h b/editor/debugger/editor_debugger_server.h
index 6458421e7a..6216d0df3d 100644
--- a/editor/debugger/editor_debugger_server.h
+++ b/editor/debugger/editor_debugger_server.h
@@ -32,9 +32,9 @@
#define EDITOR_DEBUGGER_CONNECTION_H
#include "core/debugger/remote_debugger_peer.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class EditorDebuggerServer : public Reference {
+class EditorDebuggerServer : public RefCounted {
public:
typedef EditorDebuggerServer *(*CreateServerFunc)(const String &p_uri);
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 6befee090b..d60e2783ec 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -508,23 +508,35 @@ Vector<Vector<String>> EditorProfiler::get_data_as_csv() const {
return res;
}
- // signatures
- Vector<String> signatures;
- const Vector<EditorProfiler::Metric::Category> &categories = frame_metrics[0].categories;
-
- for (int j = 0; j < categories.size(); j++) {
- const EditorProfiler::Metric::Category &c = categories[j];
- signatures.push_back(c.signature);
-
- for (int k = 0; k < c.items.size(); k++) {
- signatures.push_back(c.items[k].signature);
+ // Different metrics may contain different number of categories.
+ Set<StringName> possible_signatures;
+ for (int i = 0; i < frame_metrics.size(); i++) {
+ const Metric &m = frame_metrics[i];
+ if (!m.valid) {
+ continue;
+ }
+ for (Map<StringName, Metric::Category *>::Element *E = m.category_ptrs.front(); E; E = E->next()) {
+ possible_signatures.insert(E->key());
+ }
+ for (Map<StringName, Metric::Category::Item *>::Element *E = m.item_ptrs.front(); E; E = E->next()) {
+ possible_signatures.insert(E->key());
}
}
+
+ // Generate CSV header and cache indices.
+ Map<StringName, int> sig_map;
+ Vector<String> signatures;
+ signatures.resize(possible_signatures.size());
+ int sig_index = 0;
+ for (const Set<StringName>::Element *E = possible_signatures.front(); E; E = E->next()) {
+ signatures.write[sig_index] = E->get();
+ sig_map[E->get()] = sig_index;
+ sig_index++;
+ }
res.push_back(signatures);
// values
Vector<String> values;
- values.resize(signatures.size());
int index = last_metric;
@@ -535,20 +547,23 @@ Vector<Vector<String>> EditorProfiler::get_data_as_csv() const {
index = 0;
}
- if (!frame_metrics[index].valid) {
+ const Metric &m = frame_metrics[index];
+
+ if (!m.valid) {
continue;
}
- int it = 0;
- const Vector<EditorProfiler::Metric::Category> &frame_cat = frame_metrics[index].categories;
- for (int j = 0; j < frame_cat.size(); j++) {
- const EditorProfiler::Metric::Category &c = frame_cat[j];
- values.write[it++] = String::num_real(c.total_time);
+ // Don't keep old values since there may be empty cells.
+ values.clear();
+ values.resize(possible_signatures.size());
- for (int k = 0; k < c.items.size(); k++) {
- values.write[it++] = String::num_real(c.items[k].total);
- }
+ for (Map<StringName, Metric::Category *>::Element *E = m.category_ptrs.front(); E; E = E->next()) {
+ values.write[sig_map[E->key()]] = String::num_real(E->value()->total_time);
+ }
+ for (Map<StringName, Metric::Category::Item *>::Element *E = m.item_ptrs.front(); E; E = E->next()) {
+ values.write[sig_map[E->key()]] = String::num_real(E->value()->total);
}
+
res.push_back(values);
}
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 1d95161e6c..7493cc2a8d 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -220,7 +220,7 @@ void ScriptEditorDebugger::_file_selected(const String &p_file) {
file->store_csv_line(headers);
if (vmem_tree->get_root()) {
- TreeItem *ti = vmem_tree->get_root()->get_children();
+ TreeItem *ti = vmem_tree->get_root()->get_first_child();
while (ti) {
Vector<String> values;
values.resize(vmem_tree->get_columns());
@@ -1319,7 +1319,7 @@ bool ScriptEditorDebugger::is_skip_breakpoints() {
void ScriptEditorDebugger::_error_activated() {
TreeItem *selected = error_tree->get_selected();
- TreeItem *ci = selected->get_children();
+ TreeItem *ci = selected->get_first_child();
if (ci) {
selected->set_collapsed(!selected->is_collapsed());
}
@@ -1341,7 +1341,7 @@ void ScriptEditorDebugger::_expand_errors_list() {
return;
}
- TreeItem *item = root->get_children();
+ TreeItem *item = root->get_first_child();
while (item) {
item->set_collapsed(false);
item = item->get_next();
@@ -1354,7 +1354,7 @@ void ScriptEditorDebugger::_collapse_errors_list() {
return;
}
- TreeItem *item = root->get_children();
+ TreeItem *item = root->get_first_child();
while (item) {
item->set_collapsed(true);
item = item->get_next();
@@ -1403,7 +1403,7 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
int rpad_len = text.length();
text = type + text + ti->get_text(1) + "\n";
- TreeItem *ci = ti->get_children();
+ TreeItem *ci = ti->get_first_child();
while (ci) {
text += " " + ci->get_text(0).rpad(rpad_len) + ci->get_text(1) + "\n";
ci = ci->get_next();
@@ -1419,7 +1419,7 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
}
// We only need the first child here (C++ source stack trace).
- TreeItem *ci = ti->get_children();
+ TreeItem *ci = ti->get_first_child();
// Parse back the `file:line @ method()` string.
const Vector<String> file_line_number = ci->get_text(1).split("@")[0].strip_edges().split(":");
ERR_FAIL_COND_MSG(file_line_number.size() < 2, "Incorrect C++ source stack trace file:line format (please report).");
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 57d44ca56c..7534b419fe 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -30,8 +30,8 @@
#include "dependency_editor.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
-#include "core/os/file_access.h"
#include "editor_node.h"
#include "editor_scale.h"
#include "scene/gui/margin_container.h"
@@ -725,8 +725,8 @@ void OrphanResourcesDialog::_find_to_delete(TreeItem *p_item, List<String> &path
paths.push_back(p_item->get_metadata(0));
}
- if (p_item->get_children()) {
- _find_to_delete(p_item->get_children(), paths);
+ if (p_item->get_first_child()) {
+ _find_to_delete(p_item->get_first_child(), paths);
}
p_item = p_item->get_next();
diff --git a/editor/dictionary_property_edit.h b/editor/dictionary_property_edit.h
index e0fd945491..d1401c5e5f 100644
--- a/editor/dictionary_property_edit.h
+++ b/editor/dictionary_property_edit.h
@@ -33,8 +33,8 @@
#include "scene/main/node.h"
-class DictionaryPropertyEdit : public Reference {
- GDCLASS(DictionaryPropertyEdit, Reference);
+class DictionaryPropertyEdit : public RefCounted {
+ GDCLASS(DictionaryPropertyEdit, RefCounted);
ObjectID obj;
StringName property;
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index e29c9593c3..d3df4d91a6 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -34,9 +34,9 @@
#include "core/config/project_settings.h"
#include "core/core_constants.h"
#include "core/io/compression.h"
+#include "core/io/dir_access.h"
#include "core/io/marshalls.h"
#include "core/object/script_language.h"
-#include "core/os/dir_access.h"
#include "core/version.h"
#include "scene/resources/theme.h"
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index d962658484..b8504ad02a 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -37,6 +37,9 @@
#include "core/version.h"
#include "core/version_hash.gen.h"
+// The metadata key used to store and retrieve the version text to copy to the clipboard.
+static const String META_TEXT_TO_COPY = "text_to_copy";
+
void EditorAbout::_theme_changed() {
const Ref<Font> font = get_theme_font("source", "EditorFonts");
const int font_size = get_theme_font_size("source_size", "EditorFonts");
@@ -63,7 +66,12 @@ void EditorAbout::_license_tree_selected() {
_tpl_text->set_text(selected->get_metadata(0));
}
+void EditorAbout::_version_button_pressed() {
+ DisplayServer::get_singleton()->clipboard_set(version_btn->get_meta(META_TEXT_TO_COPY));
+}
+
void EditorAbout::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_version_button_pressed"), &EditorAbout::_version_button_pressed);
}
TextureRect *EditorAbout::get_logo() const {
@@ -124,17 +132,32 @@ EditorAbout::EditorAbout() {
_logo = memnew(TextureRect);
hbc->add_child(_logo);
+ VBoxContainer *version_info_vbc = memnew(VBoxContainer);
+
+ // Add a dummy control node for spacing.
+ Control *v_spacer = memnew(Control);
+ version_info_vbc->add_child(v_spacer);
+
+ version_btn = memnew(LinkButton);
String hash = String(VERSION_HASH);
if (hash.length() != 0) {
- hash = "." + hash.left(9);
+ hash = " " + vformat("[%s]", hash.left(9));
}
+ version_btn->set_text(VERSION_FULL_NAME + hash);
+ // Set the text to copy in metadata as it slightly differs from the button's text.
+ version_btn->set_meta(META_TEXT_TO_COPY, "v" VERSION_FULL_BUILD + hash);
+ version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
+ version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->connect("pressed", callable_mp(this, &EditorAbout::_version_button_pressed));
+ version_info_vbc->add_child(version_btn);
Label *about_text = memnew(Label);
about_text->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
- about_text->set_text(VERSION_FULL_NAME + hash +
- String::utf8("\n\xc2\xa9 2007-2021 Juan Linietsky, Ariel Manzur.\n\xc2\xa9 2014-2021 ") +
+ about_text->set_text(String::utf8("\xc2\xa9 2007-2021 Juan Linietsky, Ariel Manzur.\n\xc2\xa9 2014-2021 ") +
TTR("Godot Engine contributors") + "\n");
- hbc->add_child(about_text);
+ version_info_vbc->add_child(about_text);
+
+ hbc->add_child(version_info_vbc);
TabContainer *tc = memnew(TabContainer);
tc->set_custom_minimum_size(Size2(950, 400) * EDSCALE);
diff --git a/editor/editor_about.h b/editor/editor_about.h
index 2823220a8a..b76a2ada34 100644
--- a/editor/editor_about.h
+++ b/editor/editor_about.h
@@ -34,6 +34,7 @@
#include "scene/gui/control.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/item_list.h"
+#include "scene/gui/link_button.h"
#include "scene/gui/rich_text_label.h"
#include "scene/gui/scroll_container.h"
#include "scene/gui/separator.h"
@@ -53,8 +54,10 @@ class EditorAbout : public AcceptDialog {
private:
void _license_tree_selected();
+ void _version_button_pressed();
ScrollContainer *_populate_list(const String &p_name, const List<String> &p_sections, const char *const *const p_src[], const int p_flag_single_column = 0);
+ LinkButton *version_btn;
Tree *_tpl_tree;
RichTextLabel *_license_text;
RichTextLabel *_tpl_text;
diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp
index 2d29076476..38f417a8ce 100644
--- a/editor/editor_asset_installer.cpp
+++ b/editor/editor_asset_installer.cpp
@@ -30,9 +30,9 @@
#include "editor_asset_installer.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/zip_io.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "editor_node.h"
#include "progress_dialog.h"
@@ -45,8 +45,8 @@ void EditorAssetInstaller::_update_subitems(TreeItem *p_item, bool p_check, bool
p_item->set_checked(0, false);
}
- if (p_item->get_children()) {
- _update_subitems(p_item->get_children(), p_check);
+ if (p_item->get_first_child()) {
+ _update_subitems(p_item->get_first_child(), p_check);
}
if (!p_first && p_item->get_next()) {
@@ -60,7 +60,7 @@ void EditorAssetInstaller::_uncheck_parent(TreeItem *p_item) {
}
bool any_checked = false;
- TreeItem *item = p_item->get_children();
+ TreeItem *item = p_item->get_first_child();
while (item) {
if (item->is_checked(0)) {
any_checked = true;
@@ -137,7 +137,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
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["gdshader"] = tree->get_theme_icon("Shader", "EditorIcons");
extension_guess["gd"] = tree->get_theme_icon("GDScript", "EditorIcons");
extension_guess["vs"] = tree->get_theme_icon("VisualScript", "EditorIcons");
}
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index e7934bed0a..e08334c00e 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -173,6 +173,9 @@ void EditorAudioBus::_notification(int p_what) {
bypass->set_icon(get_theme_icon("AudioBusBypass", "EditorIcons"));
bus_options->set_icon(get_theme_icon("GuiTabMenuHl", "EditorIcons"));
+
+ audio_value_preview_box->add_theme_color_override("font_color", get_theme_color("font_color", "TooltipLabel"));
+ audio_value_preview_box->add_theme_style_override("panel", get_theme_stylebox("panel", "TooltipPanel"));
} break;
case NOTIFICATION_MOUSE_EXIT:
case NOTIFICATION_DRAG_END: {
@@ -312,7 +315,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 (Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
// Snap the value when holding Ctrl for easier editing.
// To do so, it needs to be converted back to normalized volume (as the slider uses that unit).
slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db)));
@@ -372,22 +375,31 @@ 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 (Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
// Display the correct (snapped) value when holding Ctrl
db = Math::round(_normalized_volume_to_scaled_db(slider_value));
} else {
db = _normalized_volume_to_scaled_db(slider_value);
}
- String text = vformat("%10.1f dB", db);
+ String text;
+ if (Math::is_zero_approx(Math::snapped(db, 0.1))) {
+ // Prevent displaying `-0.0 dB` and show ` 0.0 dB` instead.
+ // The leading space makes the text visually line up with its positive/negative counterparts.
+ text = " 0.0 dB";
+ } else {
+ // Show an explicit `+` sign if positive.
+ text = vformat("%+.1f dB", db);
+ }
+ // Also set the preview text as a standard Control tooltip.
+ // This way, it can be seen when the slider is merely hovered (instead of dragged).
slider->set_tooltip(text);
audio_value_preview_label->set_text(text);
- Vector2 slider_size = slider->get_size();
- Vector2 slider_position = slider->get_global_position();
- float left_padding = 5.0f;
- float vert_padding = 10.0f;
- Vector2 box_position = Vector2(slider_size.x + left_padding, (slider_size.y - vert_padding) * (1.0f - slider->get_value()) - vert_padding);
+ const Vector2 slider_size = slider->get_size();
+ const Vector2 slider_position = slider->get_global_position();
+ const float vert_padding = 10.0f;
+ const Vector2 box_position = Vector2(slider_size.x, (slider_size.y - vert_padding) * (1.0f - slider->get_value()) - vert_padding);
audio_value_preview_box->set_position(slider_position + box_position);
audio_value_preview_box->set_size(audio_value_preview_label->get_size());
if (slider->has_focus() && !audio_value_preview_box->is_visible()) {
@@ -745,9 +757,9 @@ void EditorAudioBus::_bind_methods() {
ClassDB::bind_method("update_bus", &EditorAudioBus::update_bus);
ClassDB::bind_method("update_send", &EditorAudioBus::update_send);
ClassDB::bind_method("_gui_input", &EditorAudioBus::_gui_input);
- ClassDB::bind_method("get_drag_data_fw", &EditorAudioBus::get_drag_data_fw);
- ClassDB::bind_method("can_drop_data_fw", &EditorAudioBus::can_drop_data_fw);
- ClassDB::bind_method("drop_data_fw", &EditorAudioBus::drop_data_fw);
+ ClassDB::bind_method("_get_drag_data_fw", &EditorAudioBus::get_drag_data_fw);
+ ClassDB::bind_method("_can_drop_data_fw", &EditorAudioBus::can_drop_data_fw);
+ ClassDB::bind_method("_drop_data_fw", &EditorAudioBus::drop_data_fw);
ADD_SIGNAL(MethodInfo("duplicate_request"));
ADD_SIGNAL(MethodInfo("delete_request"));
@@ -770,7 +782,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
set_v_size_flags(SIZE_EXPAND_FILL);
track_name = memnew(LineEdit);
- track_name->connect("text_entered", callable_mp(this, &EditorAudioBus::_name_changed));
+ track_name->connect("text_submitted", callable_mp(this, &EditorAudioBus::_name_changed));
track_name->connect("focus_exited", callable_mp(this, &EditorAudioBus::_name_focus_exit));
vb->add_child(track_name);
@@ -830,14 +842,13 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
audio_value_preview_label->set_v_size_flags(SIZE_EXPAND_FILL);
audio_value_preview_label->set_h_size_flags(SIZE_EXPAND_FILL);
audio_value_preview_label->set_mouse_filter(MOUSE_FILTER_PASS);
+ audio_value_preview_box->add_theme_color_override("font_color", get_theme_color("font_color", "TooltipLabel"));
audioprev_hbc->add_child(audio_value_preview_label);
slider->add_child(audio_value_preview_box);
audio_value_preview_box->set_as_top_level(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_theme_style_override("panel", panel_style);
+ audio_value_preview_box->add_theme_style_override("panel", get_theme_stylebox("panel", "TooltipPanel"));
audio_value_preview_box->set_mouse_filter(MOUSE_FILTER_PASS);
audio_value_preview_box->hide();
@@ -925,7 +936,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
bus_options->set_shortcut_context(this);
bus_options->set_h_size_flags(SIZE_SHRINK_END);
bus_options->set_anchor(SIDE_RIGHT, 0.0);
- bus_options->set_tooltip(TTR("Bus options"));
+ bus_options->set_tooltip(TTR("Bus Options"));
hbc->add_child(bus_options);
bus_popup = bus_options->get_popup();
@@ -1400,7 +1411,7 @@ void EditorAudioMeterNotches::_bind_methods() {
void EditorAudioMeterNotches::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- notch_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(0, 0, 0);
+ notch_color = get_theme_color("font_color", "Editor");
} break;
case NOTIFICATION_DRAW: {
_draw_audio_notches();
@@ -1416,13 +1427,13 @@ void EditorAudioMeterNotches::_draw_audio_notches() {
for (int i = 0; i < notches.size(); i++) {
AudioNotch n = notches[i];
draw_line(Vector2(0, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),
- Vector2(line_length, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),
+ Vector2(line_length * EDSCALE, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding),
notch_color,
- 1);
+ Math::round(EDSCALE));
if (n.render_db_value) {
draw_string(font,
- Vector2(line_length + label_space,
+ Vector2((line_length + label_space) * EDSCALE,
(1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + (font_height / 4) + top_padding),
String::num(Math::abs(n.db_value)) + "dB",
HALIGN_LEFT, -1, font_size,
@@ -1432,5 +1443,5 @@ void EditorAudioMeterNotches::_draw_audio_notches() {
}
EditorAudioMeterNotches::EditorAudioMeterNotches() {
- notch_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(0, 0, 0);
+ notch_color = get_theme_color("font_color", "Editor");
}
diff --git a/editor/editor_audio_buses.h b/editor/editor_audio_buses.h
index 8dfc2137ef..0fbda8ece9 100644
--- a/editor/editor_audio_buses.h
+++ b/editor/editor_audio_buses.h
@@ -243,10 +243,10 @@ private:
List<AudioNotch> notches;
public:
- float line_length = 5.0f;
- float label_space = 2.0f;
- float btm_padding = 9.0f;
- float top_padding = 5.0f;
+ const float line_length = 5.0f;
+ const float label_space = 2.0f;
+ const float btm_padding = 9.0f;
+ const float top_padding = 5.0f;
Color notch_color;
void add_notch(float p_normalized_offset, float p_db_value, bool p_render_value = false);
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index d46df05f6e..304c2fe532 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -327,7 +327,7 @@ void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) {
add_autoload->set_disabled(false);
}
-void EditorAutoloadSettings::_autoload_text_entered(const String p_name) {
+void EditorAutoloadSettings::_autoload_text_submitted(const String p_name) {
if (autoload_add_path->get_text() != "" && _autoload_name_is_valid(p_name, nullptr)) {
_autoload_add();
}
@@ -749,9 +749,9 @@ void EditorAutoloadSettings::autoload_remove(const String &p_name) {
void EditorAutoloadSettings::_bind_methods() {
ClassDB::bind_method("_autoload_open", &EditorAutoloadSettings::_autoload_open);
- ClassDB::bind_method("get_drag_data_fw", &EditorAutoloadSettings::get_drag_data_fw);
- ClassDB::bind_method("can_drop_data_fw", &EditorAutoloadSettings::can_drop_data_fw);
- ClassDB::bind_method("drop_data_fw", &EditorAutoloadSettings::drop_data_fw);
+ ClassDB::bind_method("_get_drag_data_fw", &EditorAutoloadSettings::get_drag_data_fw);
+ ClassDB::bind_method("_can_drop_data_fw", &EditorAutoloadSettings::can_drop_data_fw);
+ ClassDB::bind_method("_drop_data_fw", &EditorAutoloadSettings::drop_data_fw);
ClassDB::bind_method("update_autoload", &EditorAutoloadSettings::update_autoload);
ClassDB::bind_method("autoload_add", &EditorAutoloadSettings::autoload_add);
@@ -859,7 +859,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
autoload_add_name = memnew(LineEdit);
autoload_add_name->set_h_size_flags(SIZE_EXPAND_FILL);
- autoload_add_name->connect("text_entered", callable_mp(this, &EditorAutoloadSettings::_autoload_text_entered));
+ autoload_add_name->connect("text_submitted", callable_mp(this, &EditorAutoloadSettings::_autoload_text_submitted));
autoload_add_name->connect("text_changed", callable_mp(this, &EditorAutoloadSettings::_autoload_text_changed));
hbc->add_child(autoload_add_name);
@@ -882,15 +882,16 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
tree->set_column_title(0, TTR("Name"));
tree->set_column_expand(0, true);
- tree->set_column_min_width(0, 100);
+ tree->set_column_min_width(0, 100 * EDSCALE);
tree->set_column_title(1, TTR("Path"));
tree->set_column_expand(1, true);
- tree->set_column_min_width(1, 100);
+ tree->set_column_min_width(1, 100 * EDSCALE);
- tree->set_column_title(2, TTR("Singleton"));
+ tree->set_column_title(2, TTR("Global Variable"));
tree->set_column_expand(2, false);
- tree->set_column_min_width(2, 80 * EDSCALE);
+ // Reserve enough space for translations of "Global Variable" which may be longer.
+ tree->set_column_min_width(2, 150 * EDSCALE);
tree->set_column_expand(3, false);
tree->set_column_min_width(3, 120 * EDSCALE);
@@ -915,7 +916,7 @@ 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);
+ autoload_add_path->emit_signal("text_submitted", p_text);
}
void EditorAutoloadSettings::_browse_autoload_add_path() {
diff --git a/editor/editor_autoload_settings.h b/editor/editor_autoload_settings.h
index 762457463c..b709728856 100644
--- a/editor/editor_autoload_settings.h
+++ b/editor/editor_autoload_settings.h
@@ -81,7 +81,7 @@ class EditorAutoloadSettings : public VBoxContainer {
void _autoload_button_pressed(Object *p_item, int p_column, int p_button);
void _autoload_activated();
void _autoload_path_text_changed(const String p_path);
- void _autoload_text_entered(const String p_name);
+ void _autoload_text_submitted(const String p_name);
void _autoload_text_changed(const String p_name);
void _autoload_open(const String &fpath);
void _autoload_file_callback(const String &p_path);
diff --git a/editor/editor_builders.py b/editor/editor_builders.py
index 86c5c87a68..ff0daa86ff 100644
--- a/editor/editor_builders.py
+++ b/editor/editor_builders.py
@@ -53,7 +53,7 @@ def make_fonts_header(target, source, env):
g.write("#ifndef _EDITOR_FONTS_H\n")
g.write("#define _EDITOR_FONTS_H\n")
- # saving uncompressed, since freetype will reference from memory pointer
+ # Saving uncompressed, since FreeType will reference from memory pointer.
for i in range(len(source)):
with open(source[i], "rb") as f:
buf = f.read()
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index fa4703d425..56c6a416af 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -31,9 +31,9 @@
#include "editor_data.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "editor_node.h"
#include "editor_settings.h"
#include "scene/resources/packed_scene.h"
@@ -83,7 +83,7 @@ void EditorHistory::cleanup_history() {
void EditorHistory::_add_object(ObjectID p_object, const String &p_property, int p_level_change, bool p_inspector_only) {
Object *obj = ObjectDB::get_instance(p_object);
ERR_FAIL_COND(!obj);
- Reference *r = Object::cast_to<Reference>(obj);
+ RefCounted *r = Object::cast_to<RefCounted>(obj);
Obj o;
if (r) {
o.ref = REF(r);
@@ -426,6 +426,18 @@ UndoRedo &EditorData::get_undo_redo() {
return undo_redo;
}
+void EditorData::add_undo_redo_inspector_hook_callback(Callable p_callable) {
+ undo_redo_callbacks.push_back(p_callable);
+}
+
+void EditorData::remove_undo_redo_inspector_hook_callback(Callable p_callable) {
+ undo_redo_callbacks.erase(p_callable);
+}
+
+const Vector<Callable> EditorData::get_undo_redo_inspector_hook_callback() {
+ return undo_redo_callbacks;
+}
+
void EditorData::remove_editor_plugin(EditorPlugin *p_plugin) {
p_plugin->undo_redo = nullptr;
editor_plugins.erase(p_plugin);
diff --git a/editor/editor_data.h b/editor/editor_data.h
index dbe729d9d9..df6ba9d0c9 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -132,6 +132,7 @@ private:
List<PropertyData> clipboard;
UndoRedo undo_redo;
+ Vector<Callable> undo_redo_callbacks;
void _cleanup_history();
@@ -166,6 +167,9 @@ public:
EditorPlugin *get_editor_plugin(int p_idx);
UndoRedo &get_undo_redo();
+ void add_undo_redo_inspector_hook_callback(Callable p_callable); // Callbacks should have 4 args: (Object* undo_redo, Object *modified_object, String property, Variant new_value)
+ void remove_undo_redo_inspector_hook_callback(Callable p_callable);
+ const Vector<Callable> get_undo_redo_inspector_hook_callback();
void save_editor_global_states();
void restore_editor_global_states();
diff --git a/editor/editor_dir_dialog.h b/editor/editor_dir_dialog.h
index 05451b7bda..ef473b0779 100644
--- a/editor/editor_dir_dialog.h
+++ b/editor/editor_dir_dialog.h
@@ -31,7 +31,7 @@
#ifndef EDITOR_DIR_DIALOG_H
#define EDITOR_DIR_DIALOG_H
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "editor/editor_file_system.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index a5ebfbfb8a..7c5a06107d 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -33,14 +33,14 @@
#include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h"
#include "core/io/config_file.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/file_access_pack.h" // PACK_HEADER_MAGIC, PACK_FORMAT_VERSION
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/io/zip_io.h"
#include "core/object/script_language.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/version.h"
#include "editor/editor_file_system.h"
#include "editor/plugins/script_editor_plugin.h"
@@ -151,7 +151,7 @@ void EditorExportPreset::set_export_path(const String &p_path) {
export_path = p_path;
/* NOTE(SonerSound): if there is a need to implement a PropertyHint that specifically indicates a relative path,
* this should be removed. */
- if (export_path.is_abs_path()) {
+ if (export_path.is_absolute_path()) {
String res_path = OS::get_singleton()->get_resource_dir();
export_path = res_path.path_to_file(export_path);
}
@@ -1051,20 +1051,34 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
}
- // Store text server data if exists.
+ // Store text server data if it is supported.
if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- String ts_data = "res://" + TS->get_support_data_filename();
- if (FileAccess::exists(ts_data)) {
- Vector<uint8_t> array = FileAccess::get_file_as_array(ts_data);
- err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
- if (err != OK) {
- return err;
+ bool use_data = ProjectSettings::get_singleton()->get("internationalization/locale/include_text_server_data");
+ if (use_data) {
+ // Try using user provided data file.
+ String ts_data = "res://" + TS->get_support_data_filename();
+ if (FileAccess::exists(ts_data)) {
+ Vector<uint8_t> array = FileAccess::get_file_as_array(ts_data);
+ err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
+ } else {
+ // Use default text server data.
+ String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_icu_data");
+ TS->save_support_data(icu_data_file);
+ Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file);
+ err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ DirAccess::remove_file_or_error(icu_data_file);
+ if (err != OK) {
+ return err;
+ }
}
}
}
String config_file = "project.binary";
- String engine_cfb = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp" + config_file);
+ String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp" + config_file);
ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list);
Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb);
DirAccess::remove_file_or_error(engine_cfb);
@@ -1086,9 +1100,9 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
// Create the temporary export directory if it doesn't exist.
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- da->make_dir_recursive(EditorSettings::get_singleton()->get_cache_dir());
+ da->make_dir_recursive(EditorPaths::get_singleton()->get_cache_dir());
- String tmppath = EditorSettings::get_singleton()->get_cache_dir().plus_file("packtmp");
+ String tmppath = EditorPaths::get_singleton()->get_cache_dir().plus_file("packtmp");
FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(!ftmp, ERR_CANT_CREATE, "Cannot create file '" + tmppath + "'.");
@@ -1208,12 +1222,12 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
}
for (int i = 0; i < pd.file_ofs.size(); i++) {
- int string_len = pd.file_ofs[i].path_utf8.length();
- int pad = _get_pad(4, string_len);
+ uint32_t string_len = pd.file_ofs[i].path_utf8.length();
+ uint32_t pad = _get_pad(4, string_len);
fhead->store_32(string_len + pad);
fhead->store_buffer((const uint8_t *)pd.file_ofs[i].path_utf8.get_data(), string_len);
- for (int j = 0; j < pad; j++) {
+ for (uint32_t j = 0; j < pad; j++) {
fhead->store_8(0);
}
@@ -1255,8 +1269,8 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
uint8_t buf[bufsize];
while (true) {
- int got = ftmp->get_buffer(buf, bufsize);
- if (got <= 0) {
+ uint64_t got = ftmp->get_buffer(buf, bufsize);
+ if (got == 0) {
break;
}
f->store_buffer(buf, got);
@@ -1266,13 +1280,13 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
if (p_embed) {
// Ensure embedded data ends at a 64-bit multiple
- int64_t embed_end = f->get_position() - embed_pos + 12;
- int pad = embed_end % 8;
- for (int i = 0; i < pad; i++) {
+ uint64_t embed_end = f->get_position() - embed_pos + 12;
+ uint64_t pad = embed_end % 8;
+ for (uint64_t i = 0; i < pad; i++) {
f->store_8(0);
}
- int64_t pck_size = f->get_position() - pck_start_pos;
+ uint64_t pck_size = f->get_position() - pck_start_pos;
f->store_64(pck_size);
f->store_32(PACK_HEADER_MAGIC);
@@ -1970,7 +1984,7 @@ void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, con
if (!convert) {
return;
}
- String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpfile.res");
+ String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpfile.res");
Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path);
if (err != OK) {
DirAccess::remove_file_or_error(tmp_path);
diff --git a/editor/editor_export.h b/editor/editor_export.h
index c96c8fdbce..c9401df9c2 100644
--- a/editor/editor_export.h
+++ b/editor/editor_export.h
@@ -31,8 +31,8 @@
#ifndef EDITOR_EXPORT_H
#define EDITOR_EXPORT_H
+#include "core/io/dir_access.h"
#include "core/io/resource.h"
-#include "core/os/dir_access.h"
#include "scene/main/node.h"
#include "scene/main/timer.h"
#include "scene/resources/texture.h"
@@ -42,8 +42,8 @@ class EditorExportPlatform;
class EditorFileSystemDirectory;
struct EditorProgress;
-class EditorExportPreset : public Reference {
- GDCLASS(EditorExportPreset, Reference);
+class EditorExportPreset : public RefCounted {
+ GDCLASS(EditorExportPreset, RefCounted);
public:
enum ExportFilter {
@@ -161,8 +161,8 @@ struct SharedObject {
SharedObject() {}
};
-class EditorExportPlatform : public Reference {
- GDCLASS(EditorExportPlatform, Reference);
+class EditorExportPlatform : public RefCounted {
+ GDCLASS(EditorExportPlatform, RefCounted);
public:
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
@@ -284,8 +284,8 @@ public:
EditorExportPlatform();
};
-class EditorExportPlugin : public Reference {
- GDCLASS(EditorExportPlugin, Reference);
+class EditorExportPlugin : public RefCounted {
+ GDCLASS(EditorExportPlugin, RefCounted);
friend class EditorExportPlatform;
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index bd00d86ec8..51c6b473ad 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -30,8 +30,8 @@
#include "editor_feature_profile.h"
+#include "core/io/dir_access.h"
#include "core/io/json.h"
-#include "core/os/dir_access.h"
#include "editor/editor_settings.h"
#include "editor_node.h"
#include "editor_scale.h"
@@ -46,6 +46,16 @@ const char *EditorFeatureProfile::feature_names[FEATURE_MAX] = {
TTRC("Import Dock"),
};
+const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = {
+ TTRC("Allows to view and edit 3D scenes."),
+ TTRC("Allows to edit scripts using the integrated script editor."),
+ TTRC("Provides built-in access to the Asset Library."),
+ TTRC("Allows editing the node hierarchy in the Scene dock."),
+ TTRC("Allows to work with signals and groups of the node selected in the Scene dock."),
+ TTRC("Allows to browse the local file system via a dedicated dock."),
+ TTRC("Allows to configure import settings for individual assets. Requires the FileSystem dock to function."),
+};
+
const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = {
"3d",
"script",
@@ -118,6 +128,18 @@ bool EditorFeatureProfile::has_class_properties_disabled(const StringName &p_cla
return disabled_properties.has(p_class);
}
+void EditorFeatureProfile::set_item_collapsed(const StringName &p_class, bool p_collapsed) {
+ if (p_collapsed) {
+ collapsed_classes.insert(p_class);
+ } else {
+ collapsed_classes.erase(p_class);
+ }
+}
+
+bool EditorFeatureProfile::is_item_collapsed(const StringName &p_class) const {
+ return collapsed_classes.has(p_class);
+}
+
void EditorFeatureProfile::set_disable_feature(Feature p_feature, bool p_disable) {
ERR_FAIL_INDEX(p_feature, FEATURE_MAX);
features_disabled[p_feature] = p_disable;
@@ -133,6 +155,11 @@ String EditorFeatureProfile::get_feature_name(Feature p_feature) {
return feature_names[p_feature];
}
+String EditorFeatureProfile::get_feature_description(Feature p_feature) {
+ ERR_FAIL_INDEX_V(p_feature, FEATURE_MAX, String());
+ return feature_descriptions[p_feature];
+}
+
Error EditorFeatureProfile::save_to_file(const String &p_path) {
Dictionary json;
json["type"] = "feature_profile";
@@ -406,7 +433,7 @@ void EditorFeatureProfileManager::_profile_action(int p_action) {
export_profile->set_current_file(_get_selected_profile() + ".profile");
} break;
case PROFILE_NEW: {
- new_profile_dialog->popup_centered();
+ new_profile_dialog->popup_centered(Size2(240, 60) * EDSCALE);
new_profile_name->clear();
new_profile_name->grab_focus();
} break;
@@ -414,8 +441,8 @@ void EditorFeatureProfileManager::_profile_action(int p_action) {
String selected = _get_selected_profile();
ERR_FAIL_COND(selected == String());
- erase_profile_dialog->set_text(vformat(TTR("Erase profile '%s'? (no undo)"), selected));
- erase_profile_dialog->popup_centered();
+ erase_profile_dialog->set_text(vformat(TTR("Remove currently selected profile, '%s'? Cannot be undone."), selected));
+ erase_profile_dialog->popup_centered(Size2(240, 60) * EDSCALE);
} break;
}
}
@@ -484,6 +511,9 @@ void EditorFeatureProfileManager::_fill_classes_from(TreeItem *p_parent, const S
class_item->set_selectable(0, true);
class_item->set_metadata(0, p_class);
+ bool collapsed = edited->is_item_collapsed(p_class);
+ class_item->set_collapsed(collapsed);
+
if (p_class == p_selected) {
class_item->select(0);
}
@@ -520,12 +550,28 @@ void EditorFeatureProfileManager::_class_list_item_selected() {
}
Variant md = item->get_metadata(0);
- if (md.get_type() != Variant::STRING && md.get_type() != Variant::STRING_NAME) {
+ if (md.get_type() == Variant::STRING || md.get_type() == Variant::STRING_NAME) {
+ String class_name = md;
+ String class_description;
+
+ DocTools *dd = EditorHelp::get_doc_data();
+ Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(class_name);
+ if (E) {
+ class_description = DTR(E->get().brief_description);
+ }
+
+ description_bit->set_text(class_description);
+ } else if (md.get_type() == Variant::INT) {
+ int feature_id = md;
+ String feature_description = EditorFeatureProfile::get_feature_description(EditorFeatureProfile::Feature(feature_id));
+
+ description_bit->set_text(feature_description);
+ return;
+ } else {
return;
}
String class_name = md;
-
if (edited->is_class_disabled(class_name)) {
return;
}
@@ -545,27 +591,28 @@ void EditorFeatureProfileManager::_class_list_item_selected() {
option->set_metadata(0, CLASS_OPTION_DISABLE_EDITOR);
}
- TreeItem *properties = property_list->create_item(root);
- properties->set_text(0, TTR("Enabled Properties:"));
-
List<PropertyInfo> props;
-
ClassDB::get_property_list(class_name, &props, true);
- for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
- String name = E->get().name;
- if (!(E->get().usage & PROPERTY_USAGE_EDITOR)) {
- continue;
+ if (props.size() > 0) {
+ TreeItem *properties = property_list->create_item(root);
+ properties->set_text(0, TTR("Class Properties:"));
+
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ String name = E->get().name;
+ if (!(E->get().usage & PROPERTY_USAGE_EDITOR)) {
+ continue;
+ }
+ TreeItem *property = property_list->create_item(properties);
+ property->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ property->set_editable(0, true);
+ property->set_selectable(0, true);
+ property->set_checked(0, !edited->is_class_property_disabled(class_name, name));
+ property->set_text(0, name.capitalize());
+ property->set_metadata(0, name);
+ String icon_type = Variant::get_type_name(E->get().type);
+ property->set_icon(0, EditorNode::get_singleton()->get_class_icon(icon_type));
}
- TreeItem *property = property_list->create_item(properties);
- property->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
- property->set_editable(0, true);
- property->set_selectable(0, true);
- property->set_checked(0, !edited->is_class_property_disabled(class_name, name));
- property->set_text(0, name.capitalize());
- property->set_metadata(0, name);
- String icon_type = Variant::get_type_name(E->get().type);
- property->set_icon(0, EditorNode::get_singleton()->get_class_icon(icon_type));
}
updating_features = false;
@@ -596,6 +643,26 @@ void EditorFeatureProfileManager::_class_list_item_edited() {
}
}
+void EditorFeatureProfileManager::_class_list_item_collapsed(Object *p_item) {
+ if (updating_features) {
+ return;
+ }
+
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ if (!item) {
+ return;
+ }
+
+ Variant md = item->get_metadata(0);
+ if (md.get_type() != Variant::STRING && md.get_type() != Variant::STRING_NAME) {
+ return;
+ }
+
+ String class_name = md;
+ bool collapsed = item->is_collapsed();
+ edited->set_item_collapsed(class_name, collapsed);
+}
+
void EditorFeatureProfileManager::_property_item_edited() {
if (updating_features) {
return;
@@ -675,7 +742,7 @@ void EditorFeatureProfileManager::_update_selected_profile() {
TreeItem *features = class_list->create_item(root);
TreeItem *last_feature;
- features->set_text(0, TTR("Enabled Features:"));
+ features->set_text(0, TTR("Main Features") + ":");
for (int i = 0; i < EditorFeatureProfile::FEATURE_MAX; i++) {
TreeItem *feature;
if (i == EditorFeatureProfile::FEATURE_IMPORT_DOCK) {
@@ -699,7 +766,7 @@ void EditorFeatureProfileManager::_update_selected_profile() {
}
TreeItem *classes = class_list->create_item(root);
- classes->set_text(0, TTR("Enabled Classes:"));
+ classes->set_text(0, TTR("Nodes and Classes") + ":");
_fill_classes_from(classes, "Node", class_selected);
_fill_classes_from(classes, "Resource", class_selected);
@@ -797,47 +864,51 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
current_profile_name->set_text(TTR("(none)"));
current_profile_name->set_editable(false);
current_profile_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- profile_actions[PROFILE_CLEAR] = memnew(Button(TTR("Unset")));
+ profile_actions[PROFILE_CLEAR] = memnew(Button(TTR("Reset to Default")));
name_hbc->add_child(profile_actions[PROFILE_CLEAR]);
profile_actions[PROFILE_CLEAR]->set_disabled(true);
profile_actions[PROFILE_CLEAR]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_CLEAR));
main_vbc->add_margin_child(TTR("Current Profile:"), name_hbc);
+ main_vbc->add_child(memnew(HSeparator));
+
HBoxContainer *profiles_hbc = memnew(HBoxContainer);
profile_list = memnew(OptionButton);
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));
- profile_actions[PROFILE_SET] = memnew(Button(TTR("Make Current")));
- profiles_hbc->add_child(profile_actions[PROFILE_SET]);
- profile_actions[PROFILE_SET]->set_disabled(true);
- profile_actions[PROFILE_SET]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_SET));
+ profile_actions[PROFILE_NEW] = memnew(Button(TTR("Create Profile")));
+ profiles_hbc->add_child(profile_actions[PROFILE_NEW]);
+ profile_actions[PROFILE_NEW]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_NEW));
- profile_actions[PROFILE_ERASE] = memnew(Button(TTR("Remove")));
+ profile_actions[PROFILE_ERASE] = memnew(Button(TTR("Remove Profile")));
profiles_hbc->add_child(profile_actions[PROFILE_ERASE]);
profile_actions[PROFILE_ERASE]->set_disabled(true);
profile_actions[PROFILE_ERASE]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_ERASE));
- profiles_hbc->add_child(memnew(VSeparator));
+ main_vbc->add_margin_child(TTR("Available Profiles:"), profiles_hbc);
- profile_actions[PROFILE_NEW] = memnew(Button(TTR("New")));
- profiles_hbc->add_child(profile_actions[PROFILE_NEW]);
- profile_actions[PROFILE_NEW]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_NEW));
+ HBoxContainer *current_profile_hbc = memnew(HBoxContainer);
- profiles_hbc->add_child(memnew(VSeparator));
+ profile_actions[PROFILE_SET] = memnew(Button(TTR("Make Current")));
+ current_profile_hbc->add_child(profile_actions[PROFILE_SET]);
+ profile_actions[PROFILE_SET]->set_disabled(true);
+ profile_actions[PROFILE_SET]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_SET));
+
+ current_profile_hbc->add_child(memnew(VSeparator));
profile_actions[PROFILE_IMPORT] = memnew(Button(TTR("Import")));
- profiles_hbc->add_child(profile_actions[PROFILE_IMPORT]);
+ current_profile_hbc->add_child(profile_actions[PROFILE_IMPORT]);
profile_actions[PROFILE_IMPORT]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_IMPORT));
profile_actions[PROFILE_EXPORT] = memnew(Button(TTR("Export")));
- profiles_hbc->add_child(profile_actions[PROFILE_EXPORT]);
+ current_profile_hbc->add_child(profile_actions[PROFILE_EXPORT]);
profile_actions[PROFILE_EXPORT]->set_disabled(true);
profile_actions[PROFILE_EXPORT]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_EXPORT));
- main_vbc->add_margin_child(TTR("Available Profiles:"), profiles_hbc);
+ main_vbc->add_child(current_profile_hbc);
h_split = memnew(HSplitContainer);
h_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -848,11 +919,12 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
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);
+ class_list_vbc->add_margin_child(TTR("Configure Selected Profile") + ":", class_list, true);
class_list->set_hide_root(true);
class_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
class_list->connect("cell_selected", callable_mp(this, &EditorFeatureProfileManager::_class_list_item_selected));
class_list->connect("item_edited", callable_mp(this, &EditorFeatureProfileManager::_class_list_item_edited), varray(), CONNECT_DEFERRED);
+ class_list->connect("item_collapsed", callable_mp(this, &EditorFeatureProfileManager::_class_list_item_collapsed));
// It will be displayed once the user creates or chooses a profile.
class_list_vbc->hide();
@@ -860,8 +932,12 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
h_split->add_child(property_list_vbc);
property_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ description_bit = memnew(EditorHelpBit);
+ property_list_vbc->add_margin_child(TTR("Description") + ":", description_bit, false);
+ description_bit->set_custom_minimum_size(Size2(0, 80) * EDSCALE);
+
property_list = memnew(Tree);
- property_list_vbc->add_margin_child(TTR("Class Options:"), property_list, true);
+ property_list_vbc->add_margin_child(TTR("Extra Options") + ":", property_list, true);
property_list->set_hide_root(true);
property_list->set_hide_folding(true);
property_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
@@ -879,9 +955,14 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
h_split->add_child(no_profile_selected_help);
new_profile_dialog = memnew(ConfirmationDialog);
- new_profile_dialog->set_title(TTR("New profile name:"));
+ new_profile_dialog->set_title(TTR("Create Profile"));
+ VBoxContainer *new_profile_vb = memnew(VBoxContainer);
+ new_profile_dialog->add_child(new_profile_vb);
+ Label *new_profile_label = memnew(Label);
+ new_profile_label->set_text(TTR("New profile name") + ":");
+ new_profile_vb->add_child(new_profile_label);
new_profile_name = memnew(LineEdit);
- new_profile_dialog->add_child(new_profile_name);
+ new_profile_vb->add_child(new_profile_name);
new_profile_name->set_custom_minimum_size(Size2(300 * EDSCALE, 1));
add_child(new_profile_dialog);
new_profile_dialog->connect("confirmed", callable_mp(this, &EditorFeatureProfileManager::_create_new_profile));
@@ -890,7 +971,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
erase_profile_dialog = memnew(ConfirmationDialog);
add_child(erase_profile_dialog);
- erase_profile_dialog->set_title(TTR("Erase Profile"));
+ erase_profile_dialog->set_title(TTR("Remove Profile"));
erase_profile_dialog->connect("confirmed", callable_mp(this, &EditorFeatureProfileManager::_erase_selected_profile));
import_profiles = memnew(EditorFileDialog);
diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h
index 01e6a6a142..d31498bfc6 100644
--- a/editor/editor_feature_profile.h
+++ b/editor/editor_feature_profile.h
@@ -31,17 +31,18 @@
#ifndef EDITOR_FEATURE_PROFILE_H
#define EDITOR_FEATURE_PROFILE_H
-#include "core/object/reference.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
+#include "core/object/ref_counted.h"
#include "editor/editor_file_dialog.h"
+#include "editor_help.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/option_button.h"
#include "scene/gui/separator.h"
#include "scene/gui/split_container.h"
#include "scene/gui/tree.h"
-class EditorFeatureProfile : public Reference {
- GDCLASS(EditorFeatureProfile, Reference);
+class EditorFeatureProfile : public RefCounted {
+ GDCLASS(EditorFeatureProfile, RefCounted);
public:
enum Feature {
@@ -60,8 +61,11 @@ private:
Set<StringName> disabled_editors;
Map<StringName, Set<StringName>> disabled_properties;
+ Set<StringName> collapsed_classes;
+
bool features_disabled[FEATURE_MAX];
static const char *feature_names[FEATURE_MAX];
+ static const char *feature_descriptions[FEATURE_MAX];
static const char *feature_identifiers[FEATURE_MAX];
String _get_feature_name(Feature p_feature) { return get_feature_name(p_feature); }
@@ -80,6 +84,9 @@ public:
bool is_class_property_disabled(const StringName &p_class, const StringName &p_property) const;
bool has_class_properties_disabled(const StringName &p_class) const;
+ void set_item_collapsed(const StringName &p_class, bool p_collapsed);
+ bool is_item_collapsed(const StringName &p_class) const;
+
void set_disable_feature(Feature p_feature, bool p_disable);
bool is_feature_disabled(Feature p_feature) const;
@@ -87,6 +94,7 @@ public:
Error load_from_file(const String &p_path);
static String get_feature_name(Feature p_feature);
+ static String get_feature_description(Feature p_feature);
EditorFeatureProfile();
};
@@ -124,6 +132,7 @@ class EditorFeatureProfileManager : public AcceptDialog {
Tree *class_list;
VBoxContainer *property_list_vbc;
Tree *property_list;
+ EditorHelpBit *description_bit;
Label *no_profile_selected_help;
EditorFileDialog *import_profiles;
@@ -151,6 +160,7 @@ class EditorFeatureProfileManager : public AcceptDialog {
void _class_list_item_selected();
void _class_list_item_edited();
+ void _class_list_item_collapsed(Object *p_item);
void _property_item_edited();
void _save_and_update();
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 75815fa750..f3cee7576d 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -30,7 +30,7 @@
#include "editor_file_dialog.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -230,14 +230,14 @@ void EditorFileDialog::update_dir() {
}
}
-void EditorFileDialog::_dir_entered(String p_dir) {
+void EditorFileDialog::_dir_submitted(String p_dir) {
dir_access->change_dir(p_dir);
invalidate();
update_dir();
_push_history();
}
-void EditorFileDialog::_file_entered(const String &p_file) {
+void EditorFileDialog::_file_submitted(const String &p_file) {
_action_pressed();
}
@@ -294,6 +294,9 @@ void EditorFileDialog::_post_popup() {
if (res && name == "res://") {
name = "/";
} else {
+ if (name.ends_with("/")) {
+ name = name.substr(0, name.length() - 1);
+ }
name = name.get_file() + "/";
}
bool exists = dir_access->dir_exists(recentd[i]);
@@ -1673,8 +1676,8 @@ EditorFileDialog::EditorFileDialog() {
item_list->connect("multi_selected", callable_mp(this, &EditorFileDialog::_multi_selected), varray(), CONNECT_DEFERRED);
item_list->connect("item_activated", callable_mp(this, &EditorFileDialog::_item_dc_selected), varray());
item_list->connect("nothing_selected", callable_mp(this, &EditorFileDialog::_items_clear_selection));
- dir->connect("text_entered", callable_mp(this, &EditorFileDialog::_dir_entered));
- file->connect("text_entered", callable_mp(this, &EditorFileDialog::_file_entered));
+ dir->connect("text_submitted", callable_mp(this, &EditorFileDialog::_dir_submitted));
+ file->connect("text_submitted", callable_mp(this, &EditorFileDialog::_file_submitted));
filter->connect("item_selected", callable_mp(this, &EditorFileDialog::_filter_selected));
confirm_save = memnew(ConfirmationDialog);
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index 5a5e3a8807..d789956a3e 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -31,7 +31,7 @@
#ifndef EDITORFILEDIALOG_H
#define EDITORFILEDIALOG_H
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "scene/gui/box_container.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/item_list.h"
@@ -167,8 +167,8 @@ private:
void _item_menu_id_pressed(int p_option);
void _select_drive(int p_idx);
- void _dir_entered(String p_dir);
- void _file_entered(const String &p_file);
+ void _dir_submitted(String p_dir);
+ void _file_submitted(const String &p_file);
void _action_pressed();
void _save_confirm_pressed();
void _cancel_pressed();
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 59d3b09678..c61b097ccd 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -31,10 +31,10 @@
#include "editor_file_system.h"
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/resource_importer.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/variant/variant_parser.h"
#include "editor_node.h"
@@ -68,6 +68,11 @@ int EditorFileSystemDirectory::find_dir_index(const String &p_dir) const {
return -1;
}
+void EditorFileSystemDirectory::force_update() {
+ // We set modified_time to 0 to force `EditorFileSystem::_scan_fs_changes` to search changes in the directory
+ modified_time = 0;
+}
+
int EditorFileSystemDirectory::get_subdir_count() const {
return subdirs.size();
}
@@ -501,7 +506,7 @@ bool EditorFileSystem::_update_scan_actions() {
case ItemAction::ACTION_DIR_ADD: {
int idx = 0;
for (int i = 0; i < ia.dir->subdirs.size(); i++) {
- if (ia.new_dir->name < ia.dir->subdirs[i]->name) {
+ if (ia.new_dir->name.naturalnocasecmp_to(ia.dir->subdirs[i]->name) < 0) {
break;
}
idx++;
@@ -523,7 +528,7 @@ bool EditorFileSystem::_update_scan_actions() {
case ItemAction::ACTION_FILE_ADD: {
int idx = 0;
for (int i = 0; i < ia.dir->files.size(); i++) {
- if (ia.new_file->file < ia.dir->files[i]->file) {
+ if (ia.new_file->file.naturalnocasecmp_to(ia.dir->files[i]->file) < 0) {
break;
}
idx++;
@@ -708,7 +713,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
int idx2 = 0;
for (int i = 0; i < p_dir->subdirs.size(); i++) {
- if (efd->name < p_dir->subdirs[i]->name) {
+ if (efd->name.naturalnocasecmp_to(p_dir->subdirs[i]->name) < 0) {
break;
}
idx2++;
@@ -854,9 +859,11 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
//then scan files and directories and check what's different
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+
+ Error ret = da->change_dir(cd);
+ ERR_FAIL_COND_MSG(ret != OK, "Cannot change to '" + cd + "' folder.");
- da->change_dir(cd);
da->list_dir_begin();
while (true) {
String f = da->get_next();
@@ -944,7 +951,6 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
}
da->list_dir_end();
- memdelete(da);
}
for (int i = 0; i < p_dir->files.size(); i++) {
@@ -1239,7 +1245,7 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector
int idx2 = 0;
for (int j = 0; j < fs->get_subdir_count(); j++) {
- if (efsd->name < fs->get_subdir(j)->get_name()) {
+ if (efsd->name.naturalnocasecmp_to(fs->get_subdir(j)->get_name()) < 0) {
break;
}
idx2++;
@@ -1475,7 +1481,7 @@ void EditorFileSystem::update_file(const String &p_file) {
String file_name = p_file.get_file();
for (int i = 0; i < fs->files.size(); i++) {
- if (file_name < fs->files[i]->file) {
+ if (p_file.naturalnocasecmp_to(fs->files[i]->file) < 0) {
break;
}
idx++;
@@ -1928,19 +1934,6 @@ void EditorFileSystem::_reimport_thread(uint32_t p_index, ImportThreadData *p_im
}
void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
- {
- // Ensure that ProjectSettings::IMPORTED_FILES_PATH exists.
- DirAccess *da = DirAccess::open("res://");
- if (da->change_dir(ProjectSettings::IMPORTED_FILES_PATH) != OK) {
- Error err = da->make_dir_recursive(ProjectSettings::IMPORTED_FILES_PATH);
- if (err || da->change_dir(ProjectSettings::IMPORTED_FILES_PATH) != OK) {
- memdelete(da);
- ERR_FAIL_MSG("Failed to create '" + ProjectSettings::IMPORTED_FILES_PATH + "' folder.");
- }
- }
- memdelete(da);
- }
-
importing = true;
EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size());
@@ -2171,13 +2164,9 @@ EditorFileSystem::EditorFileSystem() {
scanning_changes = false;
scanning_changes_done = false;
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- if (da->change_dir(ProjectSettings::IMPORTED_FILES_PATH) != OK) {
- da->make_dir(ProjectSettings::IMPORTED_FILES_PATH);
- }
// This should probably also work on Unix and use the string it returns for FAT32 or exFAT
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT");
- memdelete(da);
scan_total = 0;
update_script_classes_queued.clear();
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 9c9076106c..04879bad6d 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -31,7 +31,7 @@
#ifndef EDITOR_FILE_SYSTEM_H
#define EDITOR_FILE_SYSTEM_H
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "core/os/thread.h"
#include "core/os/thread_safe.h"
#include "core/templates/safe_refcount.h"
@@ -102,6 +102,8 @@ public:
int find_file_index(const String &p_file) const;
int find_dir_index(const String &p_dir) const;
+ void force_update();
+
EditorFileSystemDirectory();
~EditorFileSystemDirectory();
};
diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp
index 97a2c67c26..4030aecbf5 100644
--- a/editor/editor_folding.cpp
+++ b/editor/editor_folding.cpp
@@ -30,7 +30,7 @@
#include "editor_folding.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "editor_inspector.h"
#include "editor_settings.h"
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index 96869ae6fd..2f5451fba3 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -31,7 +31,7 @@
#include "editor_fonts.h"
#include "builtin_fonts.gen.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "editor_scale.h"
#include "editor_settings.h"
#include "scene/resources/default_theme/default_theme.h"
@@ -313,9 +313,14 @@ void editor_register_fonts(Ref<Theme> p_theme) {
p_theme->set_font("bold", "EditorFonts", df_bold);
// Title font
- p_theme->set_font_size("title_size", "EditorFonts", default_font_size + 2 * EDSCALE);
+ p_theme->set_font_size("title_size", "EditorFonts", default_font_size + 1 * EDSCALE);
p_theme->set_font("title", "EditorFonts", df_bold);
+ p_theme->set_font_size("main_button_font_size", "EditorFonts", default_font_size + 1 * EDSCALE);
+ p_theme->set_font("main_button_font", "EditorFonts", df_bold);
+
+ p_theme->set_font("font", "Label", df_bold);
+
// Documentation fonts
MAKE_SOURCE_FONT(df_code);
p_theme->set_font_size("doc_size", "EditorFonts", int(EDITOR_GET("text_editor/help/help_font_size")) * EDSCALE);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 6039f64b7c..7365e8fd7d 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -475,7 +475,7 @@ void EditorHelp::_update_doc() {
String linktxt = (cd.tutorials[i].title.is_empty()) ? link : DTR(cd.tutorials[i].title);
const int seppos = linktxt.find("//");
if (seppos != -1) {
- linktxt = link.right(seppos + 2);
+ linktxt = link.substr(seppos + 2);
}
class_desc->push_color(symbol_color);
@@ -1593,7 +1593,7 @@ void EditorHelp::_notification(int p_what) {
_update_doc();
} break;
case NOTIFICATION_THEME_CHANGED: {
- if (is_visible_in_tree()) {
+ if (is_inside_tree()) {
_class_desc_resized();
}
} break;
@@ -1761,7 +1761,7 @@ FindBar::FindBar() {
search_text->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
search_text->set_h_size_flags(SIZE_EXPAND_FILL);
search_text->connect("text_changed", callable_mp(this, &FindBar::_search_text_changed));
- search_text->connect("text_entered", callable_mp(this, &FindBar::_search_text_entered));
+ search_text->connect("text_submitted", callable_mp(this, &FindBar::_search_text_submitted));
matches_label = memnew(Label);
add_child(matches_label);
@@ -1849,9 +1849,6 @@ bool FindBar::_search(bool p_search_previous) {
bool keep = prev_search == stext;
bool ret = rich_text_label->search(stext, keep, p_search_previous);
- if (!ret) {
- ret = rich_text_label->search(stext, false, p_search_previous);
- }
prev_search = stext;
@@ -1878,7 +1875,7 @@ void FindBar::_update_results_count() {
int from_pos = 0;
while (true) {
- int pos = full_text.find(searched, from_pos);
+ int pos = full_text.findn(searched, from_pos);
if (pos == -1) {
break;
}
@@ -1935,7 +1932,7 @@ void FindBar::_search_text_changed(const String &p_text) {
search_next();
}
-void FindBar::_search_text_entered(const String &p_text) {
+void FindBar::_search_text_submitted(const String &p_text) {
if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
search_prev();
} else {
diff --git a/editor/editor_help.h b/editor/editor_help.h
index 65e20f060c..69bb72c52d 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -61,7 +61,7 @@ class FindBar : public HBoxContainer {
void _hide_bar();
void _search_text_changed(const String &p_text);
- void _search_text_entered(const String &p_text);
+ void _search_text_submitted(const String &p_text);
void _update_results_count();
void _update_matches_label();
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 23226ffa9b..b93ffa9321 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -334,7 +334,7 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
for (int i = 0; i < class_doc.methods.size(); i++) {
String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.methods[i].name : class_doc.methods[i].name.to_lower();
if (method_name.find(term) > -1 ||
- (term.begins_with(".") && method_name.begins_with(term.right(1))) ||
+ (term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
(term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
(term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
match.methods.push_back(const_cast<DocData::MethodDoc *>(&class_doc.methods[i]));
diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h
index 350a02315f..75da2d5aba 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -83,7 +83,7 @@ public:
EditorHelpSearch();
};
-class EditorHelpSearch::Runner : public Reference {
+class EditorHelpSearch::Runner : public RefCounted {
enum Phase {
PHASE_MATCH_CLASSES_INIT,
PHASE_MATCH_CLASSES,
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 738b2f9f82..69709315ff 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -380,7 +380,7 @@ StringName EditorProperty::get_edited_property() {
void EditorProperty::update_property() {
if (get_script_instance()) {
- get_script_instance()->call("update_property");
+ get_script_instance()->call("_update_property");
}
}
@@ -741,7 +741,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
if (use_keying_next()) {
if (property == "frame_coords" && (object->is_class("Sprite2D") || object->is_class("Sprite3D"))) {
- Vector2 new_coords = object->get(property);
+ Vector2i new_coords = object->get(property);
new_coords.x++;
if (new_coords.x >= object->get("hframes").operator int64_t()) {
new_coords.x = 0;
@@ -753,7 +753,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
call_deferred("emit_changed", property, object->get(property).operator int64_t() + 1, "", false);
}
- call_deferred("update_property");
+ call_deferred("_update_property");
}
}
if (delete_rect.has_point(mpos)) {
@@ -965,9 +965,7 @@ void EditorProperty::_bind_methods() {
ADD_SIGNAL(MethodInfo("object_id_selected", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx")));
- MethodInfo vm;
- vm.name = "update_property";
- BIND_VMETHOD(vm);
+ BIND_VMETHOD(MethodInfo("_update_property"));
}
EditorProperty::EditorProperty() {
@@ -1023,20 +1021,20 @@ void EditorInspectorPlugin::add_property_editor_for_multiple_properties(const St
bool EditorInspectorPlugin::can_handle(Object *p_object) {
if (get_script_instance()) {
- return get_script_instance()->call("can_handle", p_object);
+ return get_script_instance()->call("_can_handle", p_object);
}
return false;
}
void EditorInspectorPlugin::parse_begin(Object *p_object) {
if (get_script_instance()) {
- get_script_instance()->call("parse_begin", p_object);
+ get_script_instance()->call("_parse_begin", p_object);
}
}
void EditorInspectorPlugin::parse_category(Object *p_object, const String &p_parse_category) {
if (get_script_instance()) {
- get_script_instance()->call("parse_category", p_object, p_parse_category);
+ get_script_instance()->call("_parse_category", p_object, p_parse_category);
}
}
@@ -1050,14 +1048,14 @@ bool EditorInspectorPlugin::parse_property(Object *p_object, Variant::Type p_typ
};
Callable::CallError err;
- return get_script_instance()->call("parse_property", (const Variant **)&argptr, 6, err);
+ return get_script_instance()->call("_parse_property", (const Variant **)&argptr, 6, err);
}
return false;
}
void EditorInspectorPlugin::parse_end() {
if (get_script_instance()) {
- get_script_instance()->call("parse_end");
+ get_script_instance()->call("_parse_end");
}
}
@@ -1066,30 +1064,11 @@ void EditorInspectorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_property_editor", "property", "editor"), &EditorInspectorPlugin::add_property_editor);
ClassDB::bind_method(D_METHOD("add_property_editor_for_multiple_properties", "label", "properties", "editor"), &EditorInspectorPlugin::add_property_editor_for_multiple_properties);
- MethodInfo vm;
- vm.name = "can_handle";
- vm.return_val.type = Variant::BOOL;
- vm.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
- BIND_VMETHOD(vm);
- vm.name = "parse_begin";
- vm.return_val.type = Variant::NIL;
- BIND_VMETHOD(vm);
- vm.name = "parse_category";
- vm.arguments.push_back(PropertyInfo(Variant::STRING, "category"));
- BIND_VMETHOD(vm);
- vm.arguments.pop_back();
- vm.name = "parse_property";
- vm.return_val.type = Variant::BOOL;
- vm.arguments.push_back(PropertyInfo(Variant::INT, "type"));
- vm.arguments.push_back(PropertyInfo(Variant::STRING, "path"));
- vm.arguments.push_back(PropertyInfo(Variant::INT, "hint"));
- vm.arguments.push_back(PropertyInfo(Variant::STRING, "hint_text"));
- vm.arguments.push_back(PropertyInfo(Variant::INT, "usage"));
- BIND_VMETHOD(vm);
- vm.arguments.clear();
- vm.name = "parse_end";
- vm.return_val.type = Variant::NIL;
- BIND_VMETHOD(vm);
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_can_handle", PropertyInfo(Variant::OBJECT, "object")));
+ BIND_VMETHOD(MethodInfo(Variant::NIL, "_parse_begin"));
+ BIND_VMETHOD(MethodInfo(Variant::NIL, "_parse_category", PropertyInfo(Variant::STRING, "category")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_parse_property", PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "hint"), PropertyInfo(Variant::STRING, "hint_text"), PropertyInfo(Variant::INT, "usage")));
+ BIND_VMETHOD(MethodInfo(Variant::NIL, "_parse_end"));
}
////////////////////////////////////////////////
@@ -1097,9 +1076,12 @@ void EditorInspectorPlugin::_bind_methods() {
void EditorInspectorCategory::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
- draw_rect(Rect2(Vector2(), get_size()), bg_color);
- Ref<Font> font = get_theme_font("font", "Tree");
- int font_size = get_theme_font_size("font_size", "Tree");
+ Ref<StyleBox> sb = get_theme_stylebox("prop_category_style", "Editor");
+
+ draw_style_box(sb, Rect2(Vector2(), get_size()));
+
+ Ref<Font> font = get_theme_font("bold", "EditorFonts");
+ int font_size = get_theme_font_size("bold_size", "EditorFonts");
int hs = get_theme_constant("hseparation", "Tree");
@@ -1181,8 +1163,9 @@ void EditorInspectorSection::_test_unfold() {
void EditorInspectorSection::_notification(int p_what) {
if (p_what == NOTIFICATION_SORT_CHILDREN) {
- Ref<Font> font = get_theme_font("font", "Tree");
- int font_size = get_theme_font_size("font_size", "Tree");
+ Ref<Font> font = get_theme_font("bold", "EditorFonts");
+ int font_size = get_theme_font_size("bold_size", "EditorFonts");
+
Ref<Texture2D> arrow;
if (foldable) {
@@ -1233,15 +1216,19 @@ void EditorInspectorSection::_notification(int p_what) {
bool rtl = is_layout_rtl();
if (foldable) {
- if (rtl) {
- arrow = get_theme_icon("arrow_collapsed_mirrored", "Tree");
+ if (object->editor_is_section_unfolded(section)) {
+ arrow = get_theme_icon("arrow", "Tree");
} else {
- arrow = get_theme_icon("arrow_collapsed", "Tree");
+ if (is_layout_rtl()) {
+ arrow = get_theme_icon("arrow_collapsed_mirrored", "Tree");
+ } else {
+ arrow = get_theme_icon("arrow_collapsed", "Tree");
+ }
}
}
- Ref<Font> font = get_theme_font("font", "Tree");
- int font_size = get_theme_font_size("font_size", "Tree");
+ Ref<Font> font = get_theme_font("bold", "EditorFonts");
+ int font_size = get_theme_font_size("bold_size", "EditorFonts");
int h = font->get_height(font_size);
if (arrow.is_valid()) {
@@ -1249,12 +1236,15 @@ void EditorInspectorSection::_notification(int p_what) {
}
h += get_theme_constant("vseparation", "Tree");
- draw_rect(Rect2(Vector2(), Vector2(get_size().width, h)), bg_color);
+ Color c = bg_color;
+ c.a *= 0.4;
+ draw_rect(Rect2(Vector2(), Vector2(get_size().width, h)), c);
- const int arrow_margin = 3;
- Color color = get_theme_color("font_color", "Tree");
- float text_width = get_size().width - Math::round((16 + arrow_margin) * EDSCALE);
- draw_string(font, Point2(rtl ? 0 : Math::round((16 + arrow_margin) * EDSCALE), font->get_ascent(font_size) + (h - font->get_height(font_size)) / 2).floor(), label, rtl ? HALIGN_RIGHT : HALIGN_LEFT, text_width, font_size, color);
+ const int arrow_margin = 2;
+ const int arrow_width = arrow.is_valid() ? arrow->get_width() : 0;
+ Color color = get_theme_color("font_color");
+ float text_width = get_size().width - Math::round(arrow_width + arrow_margin * EDSCALE);
+ draw_string(font, Point2(rtl ? 0 : Math::round(arrow_width + arrow_margin * EDSCALE), font->get_ascent(font_size) + (h - font->get_height(font_size)) / 2).floor(), label, rtl ? HALIGN_RIGHT : HALIGN_LEFT, text_width, font_size, color);
if (arrow.is_valid()) {
if (rtl) {
@@ -1279,7 +1269,7 @@ void EditorInspectorSection::_notification(int p_what) {
Control *editor_property = Object::cast_to<Control>(vbox->get_child(child_idx));
// Test can_drop_data and can_drop_data_fw, since can_drop_data only works if set up with forwarding or if script attached.
- if (editor_property && (editor_property->can_drop_data(Point2(), dd) || editor_property->call("can_drop_data_fw", Point2(), dd, this))) {
+ if (editor_property && (editor_property->can_drop_data(Point2(), dd) || editor_property->call("_can_drop_data_fw", Point2(), dd, this))) {
children_can_drop = true;
break;
}
@@ -1626,7 +1616,7 @@ void EditorInspector::update_tree() {
bool draw_red = false;
- {
+ if (is_inside_tree()) {
Node *nod = Object::cast_to<Node>(object);
Node *es = EditorNode::get_singleton()->get_edited_scene();
if (nod && es != nod && nod->get_owner() != es) {
@@ -1737,7 +1727,6 @@ void EditorInspector::update_tree() {
}
category->label = type;
- category->bg_color = get_theme_color("prop_category", "Editor");
if (use_doc_hints) {
StringName type2 = p.name;
if (!class_descr_cache.has(type2)) {
@@ -1809,12 +1798,12 @@ void EditorInspector::update_tree() {
basename = group + "/" + basename;
}
- String name = (basename.find("/") != -1) ? basename.right(basename.rfind("/") + 1) : basename;
+ String name = (basename.find("/") != -1) ? basename.substr(basename.rfind("/") + 1) : basename;
if (capitalize_paths) {
int dot = name.find(".");
if (dot != -1) {
- String ov = name.right(dot);
+ String ov = name.substr(dot);
name = name.substr(0, dot);
name = name.capitalize();
name += ov;
@@ -1824,7 +1813,13 @@ void EditorInspector::update_tree() {
}
}
- String path = basename.left(basename.rfind("/"));
+ String path;
+ {
+ int idx = basename.rfind("/");
+ if (idx > -1) {
+ path = basename.left(idx);
+ }
+ }
if (use_filter && filter != "") {
String cat = path;
@@ -2266,6 +2261,22 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
undo_redo->add_do_property(object, p_name, p_value);
undo_redo->add_undo_property(object, p_name, object->get(p_name));
+ Variant v_undo_redo = (Object *)undo_redo;
+ Variant v_object = object;
+ Variant v_name = p_name;
+ for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback().size(); i++) {
+ const Callable &callback = EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback()[i];
+
+ const Variant *p_arguments[] = { &v_undo_redo, &v_object, &v_name, &p_value };
+ Variant return_value;
+ Callable::CallError call_error;
+
+ callback.call(p_arguments, 4, return_value, call_error);
+ if (call_error.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT("Invalid UndoRedo callback.");
+ }
+ }
+
if (p_refresh_all) {
undo_redo->add_do_method(this, "_edit_request_change", object, "");
undo_redo->add_undo_method(this, "_edit_request_change", object, "");
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 18250780be..e4bcab3e3f 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -175,8 +175,8 @@ public:
EditorProperty();
};
-class EditorInspectorPlugin : public Reference {
- GDCLASS(EditorInspectorPlugin, Reference);
+class EditorInspectorPlugin : public RefCounted {
+ GDCLASS(EditorInspectorPlugin, RefCounted);
friend class EditorInspector;
struct AddedEditor {
@@ -208,7 +208,7 @@ class EditorInspectorCategory : public Control {
friend class EditorInspector;
Ref<Texture2D> icon;
String label;
- Color bg_color;
+
mutable String tooltip_text;
protected:
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 7b94016fb6..35d8021394 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -63,6 +63,20 @@ void EditorLog::_notification(int p_what) {
log->add_theme_font_override("normal_font", get_theme_font("output_source", "EditorFonts"));
log->add_theme_font_size_override("normal_font_size", get_theme_font_size("output_source_size", "EditorFonts"));
log->add_theme_color_override("selection_color", get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.4));
+ log->add_theme_font_override("bold_font", get_theme_font("bold", "EditorFonts"));
+
+ type_filter_map[MSG_TYPE_STD]->toggle_button->set_icon(get_theme_icon("Popup", "EditorIcons"));
+ type_filter_map[MSG_TYPE_ERROR]->toggle_button->set_icon(get_theme_icon("StatusError", "EditorIcons"));
+ type_filter_map[MSG_TYPE_WARNING]->toggle_button->set_icon(get_theme_icon("StatusWarning", "EditorIcons"));
+ type_filter_map[MSG_TYPE_EDITOR]->toggle_button->set_icon(get_theme_icon("Edit", "EditorIcons"));
+
+ clear_button->set_icon(get_theme_icon("Clear", "EditorIcons"));
+ copy_button->set_icon(get_theme_icon("ActionCopy", "EditorIcons"));
+ collapse_button->set_icon(get_theme_icon("CombineLines", "EditorIcons"));
+ show_search_button->set_icon(get_theme_icon("Search", "EditorIcons"));
+
+ _load_state();
+
} else if (p_what == NOTIFICATION_THEME_CHANGED) {
Ref<Font> df_output_code = get_theme_font("output_source", "EditorFonts");
if (df_output_code.is_valid()) {
@@ -75,8 +89,62 @@ void EditorLog::_notification(int p_what) {
}
}
+void EditorLog::_set_collapse(bool p_collapse) {
+ collapse = p_collapse;
+ _start_state_save_timer();
+ _rebuild_log();
+}
+
+void EditorLog::_start_state_save_timer() {
+ if (!is_loading_state) {
+ save_state_timer->start();
+ }
+}
+
+void EditorLog::_save_state() {
+ Ref<ConfigFile> config;
+ config.instance();
+ // Load and amend existing config if it exists.
+ config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+
+ const String section = "editor_log";
+ for (Map<MessageType, LogFilter *>::Element *E = type_filter_map.front(); E; E = E->next()) {
+ config->set_value(section, "log_filter_" + itos(E->key()), E->get()->is_active());
+ }
+
+ config->set_value(section, "collapse", collapse);
+ config->set_value(section, "show_search", search_box->is_visible());
+
+ config->save(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+}
+
+void EditorLog::_load_state() {
+ is_loading_state = true;
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+
+ if (err == OK) {
+ const String section = "editor_log";
+ for (Map<MessageType, LogFilter *>::Element *E = type_filter_map.front(); E; E = E->next()) {
+ E->get()->set_active(config->get_value(section, "log_filter_" + itos(E->key()), false));
+ }
+
+ collapse = config->get_value(section, "collapse", false);
+ collapse_button->set_pressed(collapse);
+ bool show_search = config->get_value(section, "show_search", true);
+ search_box->set_visible(show_search);
+ show_search_button->set_pressed(show_search);
+ }
+
+ is_loading_state = false;
+}
+
void EditorLog::_clear_request() {
log->clear();
+ messages.clear();
+ _reset_message_counts();
tool_button->set_icon(Ref<Texture2D>());
}
@@ -96,13 +164,82 @@ void EditorLog::clear() {
_clear_request();
}
-void EditorLog::copy() {
- _copy_request();
+void EditorLog::_process_message(const String &p_msg, MessageType p_type) {
+ if (messages.size() > 0 && messages[messages.size() - 1].text == p_msg) {
+ // If previous message is the same as the new one, increase previous count rather than adding another
+ // instance to the messages list.
+ LogMessage &previous = messages.write[messages.size() - 1];
+ previous.count++;
+
+ _add_log_line(previous, collapse);
+ } else {
+ // Different message to the previous one received.
+ LogMessage message(p_msg, p_type);
+ _add_log_line(message);
+ messages.push_back(message);
+ }
+
+ type_filter_map[p_type]->set_message_count(type_filter_map[p_type]->get_message_count() + 1);
}
void EditorLog::add_message(const String &p_msg, MessageType p_type) {
- bool restore = p_type != MSG_TYPE_STD;
- switch (p_type) {
+ // Make text split by new lines their own message.
+ // See #41321 for reasoning. At time of writing, multiple print()'s in running projects
+ // get grouped together and sent to the editor log as one message. This can mess with the
+ // search functionality (see the comments on the PR above for more details). This behaviour
+ // also matches that of other IDE's.
+ Vector<String> lines = p_msg.split("\n", false);
+
+ for (int i = 0; i < lines.size(); i++) {
+ _process_message(lines[i], p_type);
+ }
+}
+
+void EditorLog::set_tool_button(Button *p_tool_button) {
+ tool_button = p_tool_button;
+}
+
+void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) {
+ EditorLog *self = (EditorLog *)p_self;
+ self->add_message(p_name, EditorLog::MSG_TYPE_EDITOR);
+}
+
+void EditorLog::_rebuild_log() {
+ log->clear();
+
+ for (int msg_idx = 0; msg_idx < messages.size(); msg_idx++) {
+ LogMessage msg = messages[msg_idx];
+
+ if (collapse) {
+ // If collapsing, only log one instance of the message.
+ _add_log_line(msg);
+ } else {
+ // If not collapsing, log each instance on a line.
+ for (int i = 0; i < msg.count; i++) {
+ _add_log_line(msg);
+ }
+ }
+ }
+}
+
+void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
+ // Only add the message to the log if it passes the filters.
+ bool filter_active = type_filter_map[p_message.type]->is_active();
+ String search_text = search_box->get_text();
+ bool search_match = search_text == String() || p_message.text.findn(search_text) > -1;
+
+ if (!filter_active || !search_match) {
+ return;
+ }
+
+ if (p_replace_previous) {
+ // Remove last line if replacing, as it will be replace by the next added line.
+ // Why "- 2"? RichTextLabel is weird. When you add a line with add_newline(), it also adds an element to the list of lines which is null/blank,
+ // but it still counts as a line. So if you remove the last line (count - 1) you are actually removing nothing...
+ log->remove_line(log->get_paragraph_count() - 2);
+ }
+
+ switch (p_message.type) {
case MSG_TYPE_STD: {
} break;
case MSG_TYPE_ERROR: {
@@ -125,21 +262,46 @@ void EditorLog::add_message(const String &p_msg, MessageType p_type) {
} break;
}
- log->add_text(p_msg);
- log->add_newline();
+ // If collapsing, add the count of this message in bold at the start of the line.
+ if (collapse && p_message.count > 1) {
+ log->push_bold();
+ log->add_text(vformat("(%s) ", itos(p_message.count)));
+ log->pop();
+ }
+
+ log->add_text(p_message.text);
- if (restore) {
+ // Need to use pop() to exit out of the RichTextLabels current "push" stack.
+ // We only "push" in the above switch when message type != STD, so only pop when that is the case.
+ if (p_message.type != MSG_TYPE_STD) {
log->pop();
}
+
+ log->add_newline();
}
-void EditorLog::set_tool_button(Button *p_tool_button) {
- tool_button = p_tool_button;
+void EditorLog::_set_filter_active(bool p_active, MessageType p_message_type) {
+ type_filter_map[p_message_type]->set_active(p_active);
+ _start_state_save_timer();
+ _rebuild_log();
}
-void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) {
- EditorLog *self = (EditorLog *)p_self;
- self->add_message(p_name, EditorLog::MSG_TYPE_EDITOR);
+void EditorLog::_set_search_visible(bool p_visible) {
+ search_box->set_visible(p_visible);
+ if (p_visible) {
+ search_box->grab_focus();
+ }
+ _start_state_save_timer();
+}
+
+void EditorLog::_search_changed(const String &p_text) {
+ _rebuild_log();
+}
+
+void EditorLog::_reset_message_counts() {
+ for (Map<MessageType, LogFilter *>::Element *E = type_filter_map.front(); E; E = E->next()) {
+ E->value()->set_message_count(0);
+ }
}
void EditorLog::_bind_methods() {
@@ -148,37 +310,114 @@ void EditorLog::_bind_methods() {
}
EditorLog::EditorLog() {
- VBoxContainer *vb = this;
-
- HBoxContainer *hb = memnew(HBoxContainer);
- vb->add_child(hb);
- title = memnew(Label);
- title->set_text(TTR("Output:"));
- title->set_h_size_flags(SIZE_EXPAND_FILL);
- hb->add_child(title);
-
- copybutton = memnew(Button);
- hb->add_child(copybutton);
- copybutton->set_text(TTR("Copy"));
- copybutton->set_shortcut(ED_SHORTCUT("editor/copy_output", TTR("Copy Selection"), KEY_MASK_CMD | KEY_C));
- copybutton->set_shortcut_context(this);
- copybutton->connect("pressed", callable_mp(this, &EditorLog::_copy_request));
-
- clearbutton = memnew(Button);
- hb->add_child(clearbutton);
- clearbutton->set_text(TTR("Clear"));
- clearbutton->set_shortcut(ED_SHORTCUT("editor/clear_output", TTR("Clear Output"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_K));
- clearbutton->set_shortcut_context(this);
- clearbutton->connect("pressed", callable_mp(this, &EditorLog::_clear_request));
+ save_state_timer = memnew(Timer);
+ save_state_timer->set_wait_time(2);
+ save_state_timer->set_one_shot(true);
+ save_state_timer->connect("timeout", callable_mp(this, &EditorLog::_save_state));
+ add_child(save_state_timer);
+
+ HBoxContainer *hb = this;
+
+ VBoxContainer *vb_left = memnew(VBoxContainer);
+ vb_left->set_custom_minimum_size(Size2(0, 180) * EDSCALE);
+ vb_left->set_v_size_flags(SIZE_EXPAND_FILL);
+ vb_left->set_h_size_flags(SIZE_EXPAND_FILL);
+ hb->add_child(vb_left);
+ // Log - Rich Text Label.
log = memnew(RichTextLabel);
log->set_scroll_follow(true);
log->set_selection_enabled(true);
log->set_focus_mode(FOCUS_CLICK);
- log->set_custom_minimum_size(Size2(0, 180) * EDSCALE);
log->set_v_size_flags(SIZE_EXPAND_FILL);
log->set_h_size_flags(SIZE_EXPAND_FILL);
- vb->add_child(log);
+ vb_left->add_child(log);
+
+ // Search box
+ search_box = memnew(LineEdit);
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ search_box->set_placeholder(TTR("Filter messages"));
+ search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
+ search_box->set_visible(true);
+ search_box->connect("text_changed", callable_mp(this, &EditorLog::_search_changed));
+ vb_left->add_child(search_box);
+
+ VBoxContainer *vb_right = memnew(VBoxContainer);
+ hb->add_child(vb_right);
+
+ // Tools grid
+ HBoxContainer *hb_tools = memnew(HBoxContainer);
+ hb_tools->set_h_size_flags(SIZE_SHRINK_CENTER);
+ vb_right->add_child(hb_tools);
+
+ // Clear.
+ clear_button = memnew(Button);
+ clear_button->set_flat(true);
+ clear_button->set_focus_mode(FOCUS_NONE);
+ clear_button->set_shortcut(ED_SHORTCUT("editor/clear_output", TTR("Clear Output"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_K));
+ clear_button->set_shortcut_context(this);
+ clear_button->connect("pressed", callable_mp(this, &EditorLog::_clear_request));
+ hb_tools->add_child(clear_button);
+
+ // Copy.
+ copy_button = memnew(Button);
+ copy_button->set_flat(true);
+ copy_button->set_focus_mode(FOCUS_NONE);
+ copy_button->set_shortcut(ED_SHORTCUT("editor/copy_output", TTR("Copy Selection"), KEY_MASK_CMD | KEY_C));
+ copy_button->set_shortcut_context(this);
+ copy_button->connect("pressed", callable_mp(this, &EditorLog::_copy_request));
+ hb_tools->add_child(copy_button);
+
+ // A second hbox to make a 2x2 grid of buttons.
+ HBoxContainer *hb_tools2 = memnew(HBoxContainer);
+ hb_tools2->set_h_size_flags(SIZE_SHRINK_CENTER);
+ vb_right->add_child(hb_tools2);
+
+ // Collapse.
+ collapse_button = memnew(Button);
+ collapse_button->set_flat(true);
+ collapse_button->set_focus_mode(FOCUS_NONE);
+ collapse_button->set_tooltip(TTR("Collapse duplicate messages into one log entry. Shows number of occurrences."));
+ collapse_button->set_toggle_mode(true);
+ collapse_button->set_pressed(false);
+ collapse_button->connect("toggled", callable_mp(this, &EditorLog::_set_collapse));
+ hb_tools2->add_child(collapse_button);
+
+ // Show Search.
+ show_search_button = memnew(Button);
+ show_search_button->set_flat(true);
+ show_search_button->set_focus_mode(FOCUS_NONE);
+ show_search_button->set_toggle_mode(true);
+ show_search_button->set_pressed(true);
+ show_search_button->set_shortcut(ED_SHORTCUT("editor/open_search", TTR("Open the search box."), KEY_MASK_CMD | KEY_F));
+ show_search_button->set_shortcut_context(this);
+ show_search_button->connect("toggled", callable_mp(this, &EditorLog::_set_search_visible));
+ hb_tools2->add_child(show_search_button);
+
+ // Message Type Filters.
+ vb_right->add_child(memnew(HSeparator));
+
+ LogFilter *std_filter = memnew(LogFilter(MSG_TYPE_STD));
+ std_filter->initialize_button("Toggle visibility of standard output messages.", callable_mp(this, &EditorLog::_set_filter_active));
+ vb_right->add_child(std_filter->toggle_button);
+ type_filter_map.insert(MSG_TYPE_STD, std_filter);
+
+ LogFilter *error_filter = memnew(LogFilter(MSG_TYPE_ERROR));
+ error_filter->initialize_button("Toggle visibility of errors.", callable_mp(this, &EditorLog::_set_filter_active));
+ vb_right->add_child(error_filter->toggle_button);
+ type_filter_map.insert(MSG_TYPE_ERROR, error_filter);
+
+ LogFilter *warning_filter = memnew(LogFilter(MSG_TYPE_WARNING));
+ warning_filter->initialize_button("Toggle visibility of warnings.", callable_mp(this, &EditorLog::_set_filter_active));
+ vb_right->add_child(warning_filter->toggle_button);
+ type_filter_map.insert(MSG_TYPE_WARNING, warning_filter);
+
+ LogFilter *editor_filter = memnew(LogFilter(MSG_TYPE_EDITOR));
+ editor_filter->initialize_button("Toggle visibility of editor messages.", callable_mp(this, &EditorLog::_set_filter_active));
+ vb_right->add_child(editor_filter->toggle_button);
+ type_filter_map.insert(MSG_TYPE_EDITOR, editor_filter);
+
add_message(VERSION_FULL_NAME " (c) 2007-2021 Juan Linietsky, Ariel Manzur & Godot Contributors.");
eh.errfunc = _error_handler;
@@ -187,8 +426,6 @@ EditorLog::EditorLog() {
current = Thread::get_caller_id();
- add_theme_constant_override("separation", get_theme_constant("separation", "VBoxContainer"));
-
EditorNode::get_undo_redo()->set_commit_notify_callback(_undo_redo_cbk, this);
}
@@ -197,4 +434,7 @@ void EditorLog::deinit() {
}
EditorLog::~EditorLog() {
+ for (Map<MessageType, LogFilter *>::Element *E = type_filter_map.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
}
diff --git a/editor/editor_log.h b/editor/editor_log.h
index 79dfb3ffaa..3b6476634a 100644
--- a/editor/editor_log.h
+++ b/editor/editor_log.h
@@ -36,21 +36,106 @@
#include "scene/gui/button.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/rich_text_label.h"
#include "scene/gui/texture_button.h"
#include "scene/gui/texture_rect.h"
-class EditorLog : public VBoxContainer {
- GDCLASS(EditorLog, VBoxContainer);
+class EditorLog : public HBoxContainer {
+ GDCLASS(EditorLog, HBoxContainer);
+
+public:
+ enum MessageType {
+ MSG_TYPE_STD,
+ MSG_TYPE_ERROR,
+ MSG_TYPE_WARNING,
+ MSG_TYPE_EDITOR,
+ };
+
+private:
+ struct LogMessage {
+ String text;
+ MessageType type;
+ int count = 1;
+
+ LogMessage() {}
+
+ LogMessage(const String p_text, MessageType p_type) :
+ text(p_text),
+ type(p_type) {
+ }
+ };
+
+ // Encapsulates all data and functionality regarding filters.
+ struct LogFilter {
+ private:
+ // Force usage of set method since it has functionality built-in.
+ int message_count = 0;
+ bool active = true;
+
+ public:
+ MessageType type;
+ Button *toggle_button = nullptr;
+
+ void initialize_button(const String &p_tooltip, Callable p_toggled_callback) {
+ toggle_button = memnew(Button);
+ toggle_button->set_toggle_mode(true);
+ toggle_button->set_pressed(true);
+ toggle_button->set_text(itos(message_count));
+ toggle_button->set_tooltip(TTR(p_tooltip));
+ // Don't tint the icon even when in "pressed" state.
+ toggle_button->add_theme_color_override("icon_color_pressed", Color(1, 1, 1, 1));
+ toggle_button->set_focus_mode(FOCUS_NONE);
+ // When toggled call the callback and pass the MessageType this button is for.
+ toggle_button->connect("toggled", p_toggled_callback, varray(type));
+ }
+
+ int get_message_count() {
+ return message_count;
+ }
+
+ void set_message_count(int p_count) {
+ message_count = p_count;
+ toggle_button->set_text(itos(message_count));
+ }
+
+ bool is_active() {
+ return active;
+ }
+
+ void set_active(bool p_active) {
+ toggle_button->set_pressed(p_active);
+ active = p_active;
+ }
+
+ LogFilter(MessageType p_type) :
+ type(p_type) {
+ }
+ };
+
+ Vector<LogMessage> messages;
+ // Maps MessageTypes to LogFilters for convenient access and storage (don't need 1 member per filter).
+ Map<MessageType, LogFilter *> type_filter_map;
- Button *clearbutton;
- Button *copybutton;
- Label *title;
RichTextLabel *log;
- HBoxContainer *title_hb;
+
+ Button *clear_button;
+ Button *copy_button;
+
+ Button *collapse_button;
+ bool collapse = false;
+
+ Button *show_search_button;
+ LineEdit *search_box;
+
+ // Reference to the "Output" button on the toolbar so we can update it's icon when
+ // Warnings or Errors are encounetered.
Button *tool_button;
+ bool is_loading_state = false; // Used to disable saving requests while loading (some signals from buttons will try trigger a save, which happens during loading).
+ Timer *save_state_timer;
+
static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, ErrorHandlerType p_type);
ErrorHandlerList eh;
@@ -62,26 +147,37 @@ class EditorLog : public VBoxContainer {
void _copy_request();
static void _undo_redo_cbk(void *p_self, const String &p_name);
+ void _rebuild_log();
+ void _add_log_line(LogMessage &p_message, bool p_replace_previous = false);
+
+ void _set_filter_active(bool p_active, MessageType p_message_type);
+ void _set_search_visible(bool p_visible);
+ void _search_changed(const String &p_text);
+
+ void _process_message(const String &p_msg, MessageType p_type);
+ void _reset_message_counts();
+
+ void _set_collapse(bool p_collapse);
+
+ void _start_state_save_timer();
+ void _save_state();
+ void _load_state();
+
protected:
static void _bind_methods();
void _notification(int p_what);
public:
- enum MessageType {
- MSG_TYPE_STD,
- MSG_TYPE_ERROR,
- MSG_TYPE_WARNING,
- MSG_TYPE_EDITOR
- };
-
void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD);
void set_tool_button(Button *p_tool_button);
void deinit();
void clear();
- void copy();
+
EditorLog();
~EditorLog();
};
+VARIANT_ENUM_CAST(EditorLog::MessageType);
+
#endif // EDITOR_LOG_H
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 055baeb81e..b6264af9eb 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -34,23 +34,26 @@
#include "core/core_bind.h"
#include "core/input/input.h"
#include "core/io/config_file.h"
+#include "core/io/file_access.h"
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/io/stream_peer_ssl.h"
#include "core/object/class_db.h"
#include "core/object/message_queue.h"
-#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
+#include "core/os/time.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
#include "core/version.h"
+#include "core/version_hash.gen.h"
#include "main/main.h"
#include "scene/gui/center_container.h"
#include "scene/gui/control.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/file_dialog.h"
+#include "scene/gui/link_button.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "scene/gui/panel_container.h"
@@ -78,8 +81,10 @@
#include "editor/editor_inspector.h"
#include "editor/editor_layouts_dialog.h"
#include "editor/editor_log.h"
+#include "editor/editor_paths.h"
#include "editor/editor_plugin.h"
#include "editor/editor_properties.h"
+#include "editor/editor_resource_picker.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_run_native.h"
#include "editor/editor_run_script.h"
@@ -115,7 +120,6 @@
#include "editor/plugins/animation_tree_editor_plugin.h"
#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_3d_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/plugins/collision_polygon_2d_editor_plugin.h"
@@ -128,13 +132,13 @@
#include "editor/plugins/editor_debugger_plugin.h"
#include "editor/plugins/editor_preview_plugins.h"
#include "editor/plugins/font_editor_plugin.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/gpu_particles_collision_sdf_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/lightmap_gi_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"
@@ -143,6 +147,7 @@
#include "editor/plugins/multimesh_editor_plugin.h"
#include "editor/plugins/navigation_polygon_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
+#include "editor/plugins/occluder_instance_3d_editor_plugin.h"
#include "editor/plugins/ot_features_plugin.h"
#include "editor/plugins/packed_scene_translation_parser_plugin.h"
#include "editor/plugins/path_2d_editor_plugin.h"
@@ -167,10 +172,10 @@
#include "editor/plugins/texture_layered_editor_plugin.h"
#include "editor/plugins/texture_region_editor_plugin.h"
#include "editor/plugins/theme_editor_plugin.h"
-#include "editor/plugins/tile_map_editor_plugin.h"
-#include "editor/plugins/tile_set_editor_plugin.h"
+#include "editor/plugins/tiles/tiles_editor_plugin.h"
#include "editor/plugins/version_control_editor_plugin.h"
#include "editor/plugins/visual_shader_editor_plugin.h"
+#include "editor/plugins/voxel_gi_editor_plugin.h"
#include "editor/progress_dialog.h"
#include "editor/project_export.h"
#include "editor/project_settings_editor.h"
@@ -183,6 +188,9 @@
EditorNode *EditorNode::singleton = nullptr;
+// The metadata key used to store and retrieve the version text to copy to the clipboard.
+static const String META_TEXT_TO_COPY = "text_to_copy";
+
void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames) {
// Keep track of a list of "index sets," i.e. sets of indices
// within disambiguated_scene_names which contain the same name.
@@ -477,8 +485,8 @@ void EditorNode::_update_from_settings() {
RS::get_singleton()->environment_set_sdfgi_frames_to_converge(frames_to_converge);
RS::EnvironmentSDFGIRayCount ray_count = RS::EnvironmentSDFGIRayCount(int(GLOBAL_GET("rendering/global_illumination/sdfgi/probe_ray_count")));
RS::get_singleton()->environment_set_sdfgi_ray_count(ray_count);
- RS::GIProbeQuality gi_probe_quality = RS::GIProbeQuality(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")));
- RS::get_singleton()->gi_probe_set_quality(gi_probe_quality);
+ RS::VoxelGIQuality voxel_gi_quality = RS::VoxelGIQuality(int(GLOBAL_GET("rendering/global_illumination/voxel_gi/quality")));
+ RS::get_singleton()->voxel_gi_set_quality(voxel_gi_quality);
RS::get_singleton()->environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/environment/volumetric_fog/volume_size"), GLOBAL_GET("rendering/environment/volumetric_fog/volume_depth"));
RS::get_singleton()->environment_set_volumetric_fog_filter_active(bool(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter")));
RS::get_singleton()->canvas_set_shadow_texture_size(GLOBAL_GET("rendering/2d/shadow_atlas/size"));
@@ -623,7 +631,7 @@ void EditorNode::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
scene_tabs->set_tab_close_display_policy((bool(EDITOR_GET("interface/scene_tabs/always_show_close_button")) ? Tabs::CLOSE_BUTTON_SHOW_ALWAYS : Tabs::CLOSE_BUTTON_SHOW_ACTIVE_ONLY));
- theme = create_editor_theme(theme_base->get_theme());
+ theme = create_custom_theme(theme_base->get_theme());
theme_base->set_theme(theme);
gui_base->set_theme(theme);
@@ -694,11 +702,16 @@ void EditorNode::_notification(int p_what) {
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"));
+ p->set_item_icon(p->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), gui_base->get_theme_icon("Heart", "EditorIcons"));
+
+ for (int i = 0; i < main_editor_buttons.size(); i++) {
+ main_editor_buttons.write[i]->add_theme_font_override("font", gui_base->get_theme_font("main_button_font", "EditorFonts"));
+ main_editor_buttons.write[i]->add_theme_font_size_override("font_size", gui_base->get_theme_font_size("main_button_font_size", "EditorFonts"));
+ }
_update_update_spinner();
} break;
@@ -733,6 +746,18 @@ void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_nam
push_item(script.operator->());
}
+void EditorNode::_remove_plugin_from_enabled(const String &p_name) {
+ ProjectSettings *ps = ProjectSettings::get_singleton();
+ PackedStringArray enabled_plugins = ps->get("editor_plugins/enabled");
+ for (int i = 0; i < enabled_plugins.size(); ++i) {
+ if (enabled_plugins.get(i) == p_name) {
+ enabled_plugins.remove(i);
+ break;
+ }
+ }
+ ps->set("editor_plugins/enabled", enabled_plugins);
+}
+
void EditorNode::_resources_changed(const Vector<String> &p_resources) {
List<Ref<Resource>> changed;
@@ -746,7 +771,7 @@ void EditorNode::_resources_changed(const Vector<String> &p_resources) {
if (!res->editor_can_reload_from_file()) {
continue;
}
- if (!res->get_path().is_resource_file() && !res->get_path().is_abs_path()) {
+ if (!res->get_path().is_resource_file() && !res->get_path().is_absolute_path()) {
continue;
}
if (!FileAccess::exists(res->get_path())) {
@@ -988,6 +1013,10 @@ void EditorNode::_reload_project_settings() {
void EditorNode::_vp_resized() {
}
+void EditorNode::_version_button_pressed() {
+ DisplayServer::get_singleton()->clipboard_set(version_btn->get_meta(META_TEXT_TO_COPY));
+}
+
void EditorNode::_node_renamed() {
if (get_inspector()) {
get_inspector()->update_tree();
@@ -1398,8 +1427,9 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
} else {
// The 3D editor may be disabled as a feature, but scenes can still be opened.
// This check prevents the preview from regenerating in case those scenes are then saved.
+ // The preview will be generated if no feature profile is set (as the 3D editor is enabled by default).
Ref<EditorFeatureProfile> profile = feature_profile_manager->get_current_profile();
- if (profile.is_valid() && !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)) {
+ if (!profile.is_valid() || !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)) {
img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_image();
}
}
@@ -1434,7 +1464,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
img->convert(Image::FORMAT_RGB8);
//save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5
- String temp_path = EditorSettings::get_singleton()->get_cache_dir();
+ String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text();
cache_base = temp_path.plus_file("resthumb-" + cache_base);
@@ -1558,6 +1588,8 @@ void EditorNode::_save_scene(String p_file, int idx) {
return;
}
+ scene->propagate_notification(NOTIFICATION_EDITOR_PRE_SAVE);
+
editor_data.apply_changes_in_editors();
List<Ref<AnimatedValuesBackup>> anim_backups;
_reset_animation_players(scene, &anim_backups);
@@ -1629,6 +1661,8 @@ void EditorNode::_save_scene(String p_file, int idx) {
} else {
_dialog_display_save_error(p_file, err);
}
+
+ scene->propagate_notification(NOTIFICATION_EDITOR_POST_SAVE);
}
void EditorNode::save_all_scenes() {
@@ -1793,28 +1827,6 @@ void EditorNode::_dialog_action(String p_file) {
}
} break;
- case FILE_EXPORT_TILESET: {
- Ref<TileSet> tileset;
- if (FileAccess::exists(p_file) && file_export_lib_merge->is_pressed()) {
- tileset = ResourceLoader::load(p_file, "TileSet");
-
- if (tileset.is_null()) {
- show_accept(TTR("Can't load TileSet for merging!"), TTR("OK"));
- return;
- }
-
- } else {
- tileset = Ref<TileSet>(memnew(TileSet));
- }
-
- TileSetEditor::update_library_file(editor_data.get_edited_scene_root(), tileset, true);
-
- Error err = ResourceSaver::save(p_file, tileset);
- if (err) {
- show_accept(TTR("Error saving TileSet!"), TTR("OK"));
- return;
- }
- } break;
case RESOURCE_SAVE:
case RESOURCE_SAVE_AS: {
@@ -2150,9 +2162,14 @@ void EditorNode::_edit_current() {
if (!inspector_only) {
EditorPlugin *main_plugin = editor_data.get_editor(current_obj);
- for (int i = 0; i < editor_table.size(); i++) {
- if (editor_table[i] == main_plugin && !main_editor_buttons[i]->is_visible()) {
- main_plugin = nullptr; //if button is not visible, then no plugin active
+ int plugin_index = 0;
+ for (; plugin_index < editor_table.size(); plugin_index++) {
+ if (editor_table[plugin_index] == main_plugin) {
+ if (!main_editor_buttons[plugin_index]->is_visible()) {
+ main_plugin = nullptr; //if button is not visible, then no plugin active
+ }
+
+ break;
}
}
@@ -2166,26 +2183,8 @@ void EditorNode::_edit_current() {
else if (main_plugin != editor_plugin_screen && (!ScriptEditor::get_singleton() || !ScriptEditor::get_singleton()->is_visible_in_tree() || ScriptEditor::get_singleton()->can_take_away_focus())) {
// update screen main_plugin
-
- if (!changing_scene) {
- if (editor_plugin_screen) {
- editor_plugin_screen->make_visible(false);
- }
- editor_plugin_screen = main_plugin;
- editor_plugin_screen->edit(current_obj);
-
- editor_plugin_screen->make_visible(true);
-
- int plugin_count = editor_data.get_editor_plugin_count();
- for (int i = 0; i < plugin_count; i++) {
- editor_data.get_editor_plugin(i)->notify_main_screen_changed(editor_plugin_screen->get_name());
- }
-
- for (int i = 0; i < editor_table.size(); i++) {
- main_editor_buttons[i]->set_pressed(editor_table[i] == main_plugin);
- }
- }
-
+ _editor_select(plugin_index);
+ main_plugin->edit(current_obj);
} else {
editor_plugin_screen->edit(current_obj);
}
@@ -2459,15 +2458,24 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
Node *scene = editor_data.get_edited_scene_root(scene_idx);
if (!scene) {
- int saved = _save_external_resources();
- String err_text;
+ if (p_option == FILE_SAVE_SCENE) {
+ // Pressing Ctrl + S saves the current script if a scene is currently open, but it won't if the scene has no root node.
+ // Work around this by explicitly saving the script in this case (similar to pressing Ctrl + Alt + S).
+ ScriptEditor::get_singleton()->save_current_script();
+ }
+
+ const int saved = _save_external_resources();
if (saved > 0) {
- err_text = vformat(TTR("Saved %s modified resource(s)."), itos(saved));
- } else {
- err_text = TTR("A root node is required to save the scene.");
+ show_accept(
+ vformat(TTR("The current scene has no root node, but %d modified external resource(s) were saved anyway."), saved),
+ TTR("OK"));
+ } else if (p_option == FILE_SAVE_AS_SCENE) {
+ // Don't show this dialog when pressing Ctrl + S to avoid interfering with script saving.
+ show_accept(
+ TTR("A root node is required to save the scene. You can add a root node using the Scene tree dock."),
+ TTR("OK"));
}
- show_accept(err_text, TTR("OK"));
break;
}
@@ -2529,25 +2537,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
file_export_lib->set_title(TTR("Export Mesh Library"));
} break;
- case FILE_EXPORT_TILESET: {
- //Make sure that the scene has a root before trying to convert to tileset
- if (!editor_data.get_edited_scene_root()) {
- show_accept(TTR("This operation can't be done without a root node."), TTR("OK"));
- break;
- }
-
- List<String> extensions;
- Ref<TileSet> ml(memnew(TileSet));
- ResourceSaver::get_recognized_extensions(ml, &extensions);
- file_export_lib->clear_filters();
- for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
- file_export_lib->add_filter("*." + E->get());
- }
-
- file_export_lib->popup_file_dialog();
- file_export_lib->set_title(TTR("Export Tile Set"));
-
- } break;
case FILE_EXTERNAL_OPEN_SCENE: {
if (unsaved_cache && !p_confirmed) {
@@ -2704,6 +2693,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_EXPLORE_ANDROID_BUILD_TEMPLATES: {
OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().plus_file("android"));
} break;
+ case RUN_RELOAD_CURRENT_PROJECT: {
+ restart_editor();
+ } break;
case FILE_QUIT:
case RUN_PROJECT_MANAGER: {
if (!p_confirmed) {
@@ -2754,10 +2746,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
settings_config_dialog->popup_edit_settings();
} break;
case SETTINGS_EDITOR_DATA_FOLDER: {
- OS::get_singleton()->shell_open(String("file://") + EditorSettings::get_singleton()->get_data_dir());
+ OS::get_singleton()->shell_open(String("file://") + EditorPaths::get_singleton()->get_data_dir());
} break;
case SETTINGS_EDITOR_CONFIG_FOLDER: {
- OS::get_singleton()->shell_open(String("file://") + EditorSettings::get_singleton()->get_settings_dir());
+ OS::get_singleton()->shell_open(String("file://") + EditorPaths::get_singleton()->get_config_dir());
} break;
case SETTINGS_MANAGE_EXPORT_TEMPLATES: {
export_template_manager->popup_manager();
@@ -2816,6 +2808,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case HELP_ABOUT: {
about->popup_centered(Size2(780, 500) * EDSCALE);
} break;
+ case HELP_SUPPORT_GODOT_DEVELOPMENT: {
+ OS::get_singleton()->shell_open("https://godotengine.org/donate");
+ } break;
case SET_VIDEO_DRIVER_SAVE_AND_RESTART: {
ProjectSettings::get_singleton()->set("rendering/driver/driver_name", video_driver_request);
@@ -2832,7 +2827,7 @@ void EditorNode::_request_screenshot() {
}
void EditorNode::_screenshot(bool p_use_utc) {
- String name = "editor_screenshot_" + OS::get_singleton()->get_iso_date_time(p_use_utc).replace(":", "") + ".png";
+ String name = "editor_screenshot_" + Time::get_singleton()->get_datetime_string_from_system(p_use_utc).replace(":", "") + ".png";
NodePath path = String("user://") + name;
_save_screenshot(path);
if (EditorSettings::get_singleton()->get("interface/editor/automatically_open_screenshots")) {
@@ -2898,7 +2893,7 @@ void EditorNode::_exit_editor() {
_save_docks();
// Dim the editor window while it's quitting to make it clearer that it's busy
- dim_editor(true, true);
+ dim_editor(true);
get_tree()->quit();
}
@@ -3064,6 +3059,9 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
tb->set_icon(singleton->gui_base->get_theme_icon(p_editor->get_name(), "EditorIcons"));
}
+ tb->add_theme_font_override("font", singleton->gui_base->get_theme_font("main_button_font", "EditorFonts"));
+ tb->add_theme_font_size_override("font_size", singleton->gui_base->get_theme_font_size("main_button_font_size", "EditorFonts"));
+
tb->set_name(p_editor->get_name());
singleton->main_editor_buttons.push_back(tb);
singleton->main_editor_button_vb->add_child(tb);
@@ -3100,10 +3098,11 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan
if (p_config_changed) {
p_editor->disable_plugin();
}
- singleton->editor_plugins_over->get_plugins_list().erase(p_editor);
+ singleton->editor_plugins_over->remove_plugin(p_editor);
+ singleton->editor_plugins_force_over->remove_plugin(p_editor);
+ singleton->editor_plugins_force_input_forwarding->remove_plugin(p_editor);
singleton->remove_child(p_editor);
singleton->editor_data.remove_editor_plugin(p_editor);
- singleton->get_editor_plugins_force_input_forwarding()->remove_plugin(p_editor);
}
void EditorNode::_update_addon_config() {
@@ -3142,16 +3141,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
Ref<ConfigFile> cf;
cf.instance();
if (!DirAccess::exists(p_addon.get_base_dir())) {
- ProjectSettings *ps = ProjectSettings::get_singleton();
- PackedStringArray enabled_plugins = ps->get("editor_plugins/enabled");
- for (int i = 0; i < enabled_plugins.size(); ++i) {
- if (enabled_plugins.get(i) == p_addon) {
- enabled_plugins.remove(i);
- break;
- }
- }
- ps->set("editor_plugins/enabled", enabled_plugins);
- ps->save();
+ _remove_plugin_from_enabled(p_addon);
WARN_PRINT("Addon '" + p_addon + "' failed to load. No directory found. Removing from enabled plugins.");
return;
}
@@ -3181,7 +3171,8 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
// Errors in the script cause the base_type to be an empty string.
if (String(script->get_instance_base_type()) == "") {
- show_warning(vformat(TTR("Unable to load addon script from path: '%s' There seems to be an error in the code, please check the syntax."), script_path));
+ show_warning(vformat(TTR("Unable to load addon script from path: '%s'. This might be due to a code error in that script.\nDisabling the addon at '%s' to prevent further errors."), script_path, p_addon));
+ _remove_plugin_from_enabled(p_addon);
return;
}
@@ -3744,6 +3735,7 @@ void EditorNode::register_editor_types() {
ResourceLoader::set_timestamp_on_load(true);
ResourceSaver::set_timestamp_on_save(true);
+ ClassDB::register_class<EditorPaths>();
ClassDB::register_class<EditorPlugin>();
ClassDB::register_class<EditorTranslationParserPlugin>();
ClassDB::register_class<EditorImportPlugin>();
@@ -3772,6 +3764,8 @@ void EditorNode::register_editor_types() {
ClassDB::register_class<ScriptCreateDialog>();
ClassDB::register_class<EditorFeatureProfile>();
ClassDB::register_class<EditorSpinSlider>();
+ ClassDB::register_class<EditorResourcePicker>();
+ ClassDB::register_class<EditorScriptPicker>();
ClassDB::register_class<EditorSceneImporterMesh>();
ClassDB::register_class<EditorSceneImporterMeshNode3D>();
@@ -3785,6 +3779,9 @@ void EditorNode::register_editor_types() {
void EditorNode::unregister_editor_types() {
_init_callbacks.clear();
+ if (EditorPaths::get_singleton()) {
+ EditorPaths::free();
+ }
}
void EditorNode::stop_child_process(OS::ProcessID p_pid) {
@@ -4351,6 +4348,8 @@ void EditorNode::_save_docks() {
}
Ref<ConfigFile> config;
config.instance();
+ // Load and amend existing config if it exists.
+ config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
_save_docks_to_config(config, "docks");
_save_open_scenes_to_config(config, "EditorNode");
@@ -4854,7 +4853,7 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
_scene_tab_closed(scene_tabs->get_hovered_tab());
}
} else {
- if ((mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_doubleclick()) || (mb->get_button_index() == MOUSE_BUTTON_MIDDLE && mb->is_pressed())) {
+ if ((mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_double_click()) || (mb->get_button_index() == MOUSE_BUTTON_MIDDLE && mb->is_pressed())) {
_menu_option_confirm(FILE_NEW_SCENE, true);
}
}
@@ -5301,7 +5300,7 @@ void EditorNode::_file_access_close_error_notify(const String &p_str) {
void EditorNode::reload_scene(const String &p_path) {
/*
- * No longer necesary since scenes now reset and reload their internal resource if needed.
+ * No longer necessary since scenes now reset and reload their internal resource if needed.
//first of all, reload internal textures, materials, meshes, etc. as they might have changed on disk
List<Ref<Resource>> cached;
@@ -5405,15 +5404,9 @@ void EditorNode::_open_imported() {
load_scene(open_import_request, true, false, true, true);
}
-void EditorNode::dim_editor(bool p_dimming, bool p_force_dim) {
- // Dimming can be forced regardless of the editor setting, which is useful when quitting the editor.
- if ((p_force_dim || EditorSettings::get_singleton()->get("interface/editor/dim_editor_on_dialog_popup")) && p_dimming) {
- dimmed = true;
- gui_base->set_modulate(Color(0.5, 0.5, 0.5));
- } else {
- dimmed = false;
- gui_base->set_modulate(Color(1, 1, 1));
- }
+void EditorNode::dim_editor(bool p_dimming) {
+ dimmed = p_dimming;
+ gui_base->set_modulate(p_dimming ? Color(0.5, 0.5, 0.5) : Color(1, 1, 1));
}
bool EditorNode::is_editor_dimmed() const {
@@ -5558,6 +5551,8 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("_screenshot", &EditorNode::_screenshot);
ClassDB::bind_method("_save_screenshot", &EditorNode::_save_screenshot);
+ ClassDB::bind_method("_version_button_pressed", &EditorNode::_version_button_pressed);
+
ADD_SIGNAL(MethodInfo("play_pressed"));
ADD_SIGNAL(MethodInfo("pause_pressed"));
ADD_SIGNAL(MethodInfo("stop_pressed"));
@@ -5694,34 +5689,10 @@ EditorNode::EditorNode() {
int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
switch (display_scale) {
- case 0: {
+ case 0:
// Try applying a suitable display scale automatically.
- // The code below is adapted in `editor/editor_settings.cpp` and `editor/project_manager.cpp`.
- // Make sure to update those when modifying the code below.
-#ifdef OSX_ENABLED
- editor_set_scale(DisplayServer::get_singleton()->screen_get_max_scale());
-#else
- const int screen = DisplayServer::get_singleton()->window_get_current_screen();
- float scale;
- if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) {
- // hiDPI display.
- scale = 2.0;
- } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) {
- // Likely a hiDPI display, but we aren't certain due to the returned DPI.
- // Use an intermediate scale to handle this situation.
- scale = 1.5;
- } else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) {
- // Small loDPI display. Use a smaller display scale so that editor elements fit more easily.
- // Icons won't look great, but this is better than having editor elements overflow from its window.
- scale = 0.75;
- } else {
- scale = 1.0;
- }
-
- editor_set_scale(scale);
-#endif
- } break;
-
+ editor_set_scale(EditorSettings::get_singleton()->get_auto_display_scale());
+ break;
case 1:
editor_set_scale(0.75);
break;
@@ -5864,8 +5835,6 @@ EditorNode::EditorNode() {
register_exporters();
- GLOBAL_DEF("editor/run/main_run_args", "");
-
ClassDB::set_class_enabled("RootMotionView", true);
//defs here, use EDITOR_GET in logic
@@ -5889,7 +5858,7 @@ EditorNode::EditorNode() {
EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false);
EDITOR_DEF("interface/inspector/horizontal_vector_types_editing", true);
EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true);
- EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "Script,MeshLibrary,TileSet");
+ EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "Script,MeshLibrary");
EDITOR_DEF("interface/inspector/default_color_picker_mode", 0);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW", PROPERTY_USAGE_DEFAULT));
EDITOR_DEF("interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_VHS_CIRCLE);
@@ -6218,8 +6187,8 @@ EditorNode::EditorNode() {
p = file_menu->get_popup();
- 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/new_scene", TTR("New Scene"), KEY_MASK_CMD + KEY_N), FILE_NEW_SCENE);
+ p->add_shortcut(ED_SHORTCUT("editor/new_inherited_scene", TTR("New Inherited Scene..."), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_N), FILE_NEW_INHERITED_SCENE);
p->add_shortcut(ED_SHORTCUT("editor/open_scene", TTR("Open Scene..."), KEY_MASK_CMD + KEY_O), FILE_OPEN_SCENE);
p->add_shortcut(ED_SHORTCUT("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_T), FILE_OPEN_PREV);
p->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT);
@@ -6241,7 +6210,6 @@ EditorNode::EditorNode() {
p->add_child(pm_export);
p->add_submenu_item(TTR("Convert To..."), "Export");
pm_export->add_shortcut(ED_SHORTCUT("editor/convert_to_MeshLibrary", TTR("MeshLibrary...")), FILE_EXPORT_MESH_LIBRARY);
- pm_export->add_shortcut(ED_SHORTCUT("editor/convert_to_TileSet", TTR("TileSet...")), FILE_EXPORT_TILESET);
pm_export->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
p->add_separator();
@@ -6299,6 +6267,7 @@ EditorNode::EditorNode() {
tool_menu->add_item(TTR("Orphan Resource Explorer..."), TOOLS_ORPHAN_RESOURCES);
p->add_separator();
+ p->add_item(TTR("Reload Current Project"), RUN_RELOAD_CURRENT_PROJECT);
#ifdef OSX_ENABLED
p->add_shortcut(ED_SHORTCUT("editor/quit_to_project_list", TTR("Quit to Project List"), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q), RUN_PROJECT_MANAGER, true);
#else
@@ -6388,13 +6357,14 @@ EditorNode::EditorNode() {
p->add_icon_shortcut(gui_base->get_theme_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_F1), HELP_SEARCH);
#endif
p->add_separator();
- p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/online_docs", TTR("Online Docs")), HELP_DOCS);
- p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/q&a", TTR("Q&A")), HELP_QA);
+ p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/online_docs", TTR("Online Documentation")), HELP_DOCS);
+ p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/q&a", TTR("Questions & Answers")), 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_theme_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 Godot")), HELP_ABOUT);
+ p->add_icon_shortcut(gui_base->get_theme_icon("Heart", "EditorIcons"), ED_SHORTCUT("editor/support_development", TTR("Support Godot Development")), HELP_SUPPORT_GODOT_DEVELOPMENT);
HBoxContainer *play_hb = memnew(HBoxContainer);
menu_hb->add_child(play_hb);
@@ -6478,7 +6448,6 @@ EditorNode::EditorNode() {
// Toggle for video driver
video_driver = memnew(OptionButton);
- 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_theme_font_override("font", gui_base->get_theme_font("bold", "EditorFonts"));
@@ -6616,11 +6585,31 @@ EditorNode::EditorNode() {
bottom_panel_hb_editors->set_h_size_flags(Control::SIZE_EXPAND_FILL);
bottom_panel_hb->add_child(bottom_panel_hb_editors);
- version_label = memnew(Label);
- version_label->set_text(VERSION_FULL_CONFIG);
+ VBoxContainer *version_info_vbc = memnew(VBoxContainer);
+ bottom_panel_hb->add_child(version_info_vbc);
+
+ // Add a dummy control node for vertical spacing.
+ Control *v_spacer = memnew(Control);
+ version_info_vbc->add_child(v_spacer);
+
+ version_btn = memnew(LinkButton);
+ version_btn->set_text(VERSION_FULL_CONFIG);
+ String hash = String(VERSION_HASH);
+ if (hash.length() != 0) {
+ hash = " " + vformat("[%s]", hash.left(9));
+ }
+ // Set the text to copy in metadata as it slightly differs from the button's text.
+ version_btn->set_meta(META_TEXT_TO_COPY, "v" VERSION_FULL_BUILD + hash);
// Fade out the version label to be less prominent, but still readable
- version_label->set_self_modulate(Color(1, 1, 1, 0.6));
- bottom_panel_hb->add_child(version_label);
+ version_btn->set_self_modulate(Color(1, 1, 1, 0.65));
+ version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
+ version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->connect("pressed", callable_mp(this, &EditorNode::_version_button_pressed));
+ version_info_vbc->add_child(version_btn);
+
+ // Add a dummy control node for horizontal spacing.
+ Control *h_spacer = memnew(Control);
+ bottom_panel_hb->add_child(h_spacer);
bottom_panel_raise = memnew(Button);
bottom_panel_raise->set_flat(true);
@@ -6794,12 +6783,12 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(ItemListEditorPlugin(this)));
add_editor_plugin(memnew(Polygon3DEditorPlugin(this)));
add_editor_plugin(memnew(CollisionPolygon2DEditorPlugin(this)));
- add_editor_plugin(memnew(TileSetEditorPlugin(this)));
- add_editor_plugin(memnew(TileMapEditorPlugin(this)));
+ add_editor_plugin(memnew(TilesEditorPlugin(this)));
add_editor_plugin(memnew(SpriteFramesEditorPlugin(this)));
add_editor_plugin(memnew(TextureRegionEditorPlugin(this)));
- add_editor_plugin(memnew(GIProbeEditorPlugin(this)));
- add_editor_plugin(memnew(BakedLightmapEditorPlugin(this)));
+ add_editor_plugin(memnew(VoxelGIEditorPlugin(this)));
+ add_editor_plugin(memnew(LightmapGIEditorPlugin(this)));
+ add_editor_plugin(memnew(OccluderInstance3DEditorPlugin(this)));
add_editor_plugin(memnew(Path2DEditorPlugin(this)));
add_editor_plugin(memnew(Path3DEditorPlugin(this)));
add_editor_plugin(memnew(Line2DEditorPlugin(this)));
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 7e16936f5d..037ed263c5 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -40,6 +40,7 @@
#include "editor/inspector_dock.h"
#include "editor/property_editor.h"
#include "editor/scene_tree_dock.h"
+#include "scene/gui/link_button.h"
typedef void (*EditorNodeInitCallback)();
typedef void (*EditorPluginInitializeCallback)();
@@ -134,7 +135,6 @@ private:
FILE_EXPORT_MESH_LIBRARY,
FILE_INSTALL_ANDROID_SOURCE,
FILE_EXPLORE_ANDROID_BUILD_TEMPLATES,
- FILE_EXPORT_TILESET,
FILE_SAVE_OPTIMIZED,
FILE_OPEN_RECENT,
FILE_OPEN_OLD_SCENE,
@@ -164,6 +164,7 @@ private:
RUN_PLAY_CUSTOM_SCENE,
RUN_SETTINGS,
RUN_PROJECT_DATA_FOLDER,
+ RUN_RELOAD_CURRENT_PROJECT,
RUN_PROJECT_MANAGER,
RUN_VCS_SETTINGS,
RUN_VCS_SHUT_DOWN,
@@ -196,6 +197,7 @@ private:
HELP_SEND_DOCS_FEEDBACK,
HELP_COMMUNITY,
HELP_ABOUT,
+ HELP_SUPPORT_GODOT_DEVELOPMENT,
SET_VIDEO_DRIVER_SAVE_AND_RESTART,
@@ -424,7 +426,7 @@ private:
HBoxContainer *bottom_panel_hb;
HBoxContainer *bottom_panel_hb_editors;
VBoxContainer *bottom_panel_vb;
- Label *version_label;
+ LinkButton *version_btn;
Button *bottom_panel_raise;
Tree *disk_changed_list;
@@ -460,6 +462,7 @@ private:
void _update_file_menu_closed();
void _on_plugin_ready(Object *p_script, const String &p_activate_name);
+ void _remove_plugin_from_enabled(const String &p_name);
void _fs_changed();
void _resources_reimported(const Vector<String> &p_resources);
@@ -477,6 +480,7 @@ private:
void _close_messages();
void _show_messages();
void _vp_resized();
+ void _version_button_pressed();
int _save_external_resources();
@@ -852,7 +856,7 @@ public:
void notify_settings_changed();
- void dim_editor(bool p_dimming, bool p_force_dim = false);
+ void dim_editor(bool p_dimming);
bool is_editor_dimmed() const;
void edit_current() { _edit_current(); };
diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp
index d1c52b4310..63281ae1aa 100644
--- a/editor/editor_path.cpp
+++ b/editor/editor_path.cpp
@@ -59,15 +59,40 @@ void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) {
Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj);
- int index = get_popup()->get_item_count();
- get_popup()->add_icon_item(icon, E->get().name.capitalize(), objects.size());
- get_popup()->set_item_h_offset(index, p_depth * 10 * EDSCALE);
+ String proper_name = "";
+ Vector<String> name_parts = E->get().name.split("/");
+
+ for (int i = 0; i < name_parts.size(); i++) {
+ if (i > 0) {
+ proper_name += " > ";
+ }
+ proper_name += name_parts[i].capitalize();
+ }
+
+ int index = sub_objects_menu->get_item_count();
+ sub_objects_menu->add_icon_item(icon, proper_name, objects.size());
+ sub_objects_menu->set_item_h_offset(index, p_depth * 10 * EDSCALE);
objects.push_back(obj->get_instance_id());
_add_children_to_popup(obj, p_depth + 1);
}
}
+void EditorPath::_show_popup() {
+ sub_objects_menu->clear();
+
+ Size2 size = get_size();
+ Point2 gp = get_screen_position();
+ gp.y += size.y;
+
+ sub_objects_menu->set_position(gp);
+ sub_objects_menu->set_size(Size2(size.width, 1));
+ sub_objects_menu->set_parent_rect(Rect2(Point2(gp - sub_objects_menu->get_position()), size));
+
+ sub_objects_menu->take_mouse_focus();
+ sub_objects_menu->popup();
+}
+
void EditorPath::_about_to_show() {
Object *obj = ObjectDB::get_instance(history->get_path_object(history->get_path_size() - 1));
if (!obj) {
@@ -75,13 +100,11 @@ void EditorPath::_about_to_show() {
}
objects.clear();
- get_popup()->clear();
- get_popup()->set_size(Size2(get_size().width, 1));
_add_children_to_popup(obj);
- if (get_popup()->get_item_count() == 0) {
- get_popup()->add_item(TTR("No sub-resources found."));
- get_popup()->set_item_disabled(0, true);
+ if (sub_objects_menu->get_item_count() == 0) {
+ sub_objects_menu->add_item(TTR("No sub-resources found."));
+ sub_objects_menu->set_item_disabled(0, true);
}
}
@@ -94,7 +117,7 @@ void EditorPath::update_path() {
Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj);
if (icon.is_valid()) {
- set_icon(icon);
+ current_object_icon->set_texture(icon);
}
if (i == history->get_path_size() - 1) {
@@ -120,12 +143,26 @@ void EditorPath::update_path() {
name = obj->get_class();
}
- set_text(" " + name); // An extra space so the text is not too close of the icon.
+ current_object_label->set_text(" " + name); // An extra space so the text is not too close of the icon.
set_tooltip(obj->get_class());
}
}
}
+void EditorPath::clear_path() {
+ set_disabled(true);
+ set_tooltip("");
+
+ current_object_label->set_text("");
+ current_object_icon->set_texture(nullptr);
+ sub_objects_icon->set_visible(false);
+}
+
+void EditorPath::enable_path() {
+ set_disabled(false);
+ sub_objects_icon->set_visible(true);
+}
+
void EditorPath::_id_pressed(int p_idx) {
ERR_FAIL_INDEX(p_idx, objects.size());
@@ -139,8 +176,16 @@ void EditorPath::_id_pressed(int p_idx) {
void EditorPath::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
update_path();
+
+ sub_objects_icon->set_texture(get_theme_icon("select_arrow", "Tree"));
+ current_object_label->add_theme_font_override("font", get_theme_font("main", "EditorFonts"));
+ } break;
+
+ case NOTIFICATION_READY: {
+ connect("pressed", callable_mp(this, &EditorPath::_show_popup));
} break;
}
}
@@ -150,8 +195,35 @@ void EditorPath::_bind_methods() {
EditorPath::EditorPath(EditorHistory *p_history) {
history = p_history;
- set_clip_text(true);
- set_text_align(ALIGN_LEFT);
- get_popup()->connect("about_to_popup", callable_mp(this, &EditorPath::_about_to_show));
- get_popup()->connect("id_pressed", callable_mp(this, &EditorPath::_id_pressed));
+
+ MarginContainer *main_mc = memnew(MarginContainer);
+ main_mc->set_anchors_and_offsets_preset(PRESET_WIDE);
+ main_mc->add_theme_constant_override("margin_left", 4 * EDSCALE);
+ main_mc->add_theme_constant_override("margin_right", 6 * EDSCALE);
+ add_child(main_mc);
+
+ HBoxContainer *main_hb = memnew(HBoxContainer);
+ main_mc->add_child(main_hb);
+
+ current_object_icon = memnew(TextureRect);
+ current_object_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
+ main_hb->add_child(current_object_icon);
+
+ current_object_label = memnew(Label);
+ current_object_label->set_clip_text(true);
+ current_object_label->set_align(Label::ALIGN_LEFT);
+ current_object_label->set_h_size_flags(SIZE_EXPAND_FILL);
+ main_hb->add_child(current_object_label);
+
+ sub_objects_icon = memnew(TextureRect);
+ sub_objects_icon->set_visible(false);
+ sub_objects_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
+ main_hb->add_child(sub_objects_icon);
+
+ sub_objects_menu = memnew(PopupMenu);
+ add_child(sub_objects_menu);
+ sub_objects_menu->connect("about_to_popup", callable_mp(this, &EditorPath::_about_to_show));
+ sub_objects_menu->connect("id_pressed", callable_mp(this, &EditorPath::_id_pressed));
+
+ set_tooltip(TTR("Open a list of sub-resources."));
}
diff --git a/editor/editor_path.h b/editor/editor_path.h
index d1090947f9..cabfa931d6 100644
--- a/editor/editor_path.h
+++ b/editor/editor_path.h
@@ -32,16 +32,24 @@
#define EDITOR_PATH_H
#include "editor_data.h"
-#include "scene/gui/menu_button.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/popup_menu.h"
-class EditorPath : public MenuButton {
- GDCLASS(EditorPath, MenuButton);
+class EditorPath : public Button {
+ GDCLASS(EditorPath, Button);
EditorHistory *history;
+ TextureRect *current_object_icon;
+ Label *current_object_label;
+ TextureRect *sub_objects_icon;
+ PopupMenu *sub_objects_menu;
+
Vector<ObjectID> objects;
EditorPath();
+ void _show_popup();
void _id_pressed(int p_idx);
void _about_to_show();
void _add_children_to_popup(Object *p_obj, int p_depth = 0);
@@ -52,6 +60,8 @@ protected:
public:
void update_path();
+ void clear_path();
+ void enable_path();
EditorPath(EditorHistory *p_history);
};
diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp
new file mode 100644
index 0000000000..c9817190dd
--- /dev/null
+++ b/editor/editor_paths.cpp
@@ -0,0 +1,212 @@
+/*************************************************************************/
+/* editor_paths.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_paths.h"
+
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/os/os.h"
+#include "main/main.h" // For `is_project_manager`.
+
+EditorPaths *EditorPaths::singleton = nullptr;
+
+bool EditorPaths::are_paths_valid() const {
+ return paths_valid;
+}
+
+String EditorPaths::get_data_dir() const {
+ return data_dir;
+}
+
+String EditorPaths::get_config_dir() const {
+ return config_dir;
+}
+
+String EditorPaths::get_cache_dir() const {
+ return cache_dir;
+}
+
+String EditorPaths::get_project_data_dir() const {
+ return project_data_dir;
+}
+
+bool EditorPaths::is_self_contained() const {
+ return self_contained;
+}
+
+String EditorPaths::get_self_contained_file() const {
+ return self_contained_file;
+}
+
+void EditorPaths::create() {
+ ERR_FAIL_COND(singleton != nullptr);
+ memnew(EditorPaths());
+}
+
+void EditorPaths::free() {
+ ERR_FAIL_COND(singleton == nullptr);
+ memdelete(singleton);
+}
+
+void EditorPaths::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_data_dir"), &EditorPaths::get_data_dir);
+ ClassDB::bind_method(D_METHOD("get_config_dir"), &EditorPaths::get_config_dir);
+ ClassDB::bind_method(D_METHOD("get_cache_dir"), &EditorPaths::get_cache_dir);
+ ClassDB::bind_method(D_METHOD("is_self_contained"), &EditorPaths::is_self_contained);
+ ClassDB::bind_method(D_METHOD("get_self_contained_file"), &EditorPaths::get_self_contained_file);
+}
+
+EditorPaths::EditorPaths() {
+ singleton = this;
+
+ // Self-contained mode if a `._sc_` or `_sc_` file is present in executable dir.
+ String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();
+ {
+ DirAccessRef d = DirAccess::create_for_path(exe_path);
+
+ if (d->file_exists(exe_path + "/._sc_")) {
+ self_contained = true;
+ self_contained_file = exe_path + "/._sc_";
+ } else if (d->file_exists(exe_path + "/_sc_")) {
+ self_contained = true;
+ self_contained_file = exe_path + "/_sc_";
+ }
+ }
+
+ String data_path;
+ String config_path;
+ String cache_path;
+
+ if (self_contained) {
+ // editor is self contained, all in same folder
+ data_path = exe_path;
+ data_dir = data_path.plus_file("editor_data");
+ config_path = exe_path;
+ config_dir = data_dir;
+ cache_path = exe_path;
+ cache_dir = data_dir.plus_file("cache");
+ } else {
+ // Typically XDG_DATA_HOME or %APPDATA%.
+ data_path = OS::get_singleton()->get_data_path();
+ data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+ // Can be different from data_path e.g. on Linux or macOS.
+ config_path = OS::get_singleton()->get_config_path();
+ config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+ // Can be different from above paths, otherwise a subfolder of data_dir.
+ cache_path = OS::get_singleton()->get_cache_path();
+ if (cache_path == data_path) {
+ cache_dir = data_dir.plus_file("cache");
+ } else {
+ cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+ }
+ }
+
+ paths_valid = (data_path != "" && config_path != "" && cache_path != "");
+ ERR_FAIL_COND_MSG(!paths_valid, "Editor data, config, or cache paths are invalid.");
+
+ // Validate or create each dir and its relevant subdirectories.
+
+ DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ // Data dir.
+ {
+ if (dir->change_dir(data_dir) != OK) {
+ dir->make_dir_recursive(data_dir);
+ if (dir->change_dir(data_dir) != OK) {
+ ERR_PRINT("Could not create editor data directory: " + data_dir);
+ paths_valid = false;
+ }
+ }
+
+ if (!dir->dir_exists("templates")) {
+ dir->make_dir("templates");
+ }
+ }
+
+ // Config dir.
+ {
+ if (dir->change_dir(config_dir) != OK) {
+ dir->make_dir_recursive(config_dir);
+ if (dir->change_dir(config_dir) != OK) {
+ ERR_PRINT("Could not create editor config directory: " + config_dir);
+ paths_valid = false;
+ }
+ }
+
+ if (!dir->dir_exists("text_editor_themes")) {
+ dir->make_dir("text_editor_themes");
+ }
+ if (!dir->dir_exists("script_templates")) {
+ dir->make_dir("script_templates");
+ }
+ if (!dir->dir_exists("feature_profiles")) {
+ dir->make_dir("feature_profiles");
+ }
+ }
+
+ // Cache dir.
+ {
+ if (dir->change_dir(cache_dir) != OK) {
+ dir->make_dir_recursive(cache_dir);
+ if (dir->change_dir(cache_dir) != OK) {
+ ERR_PRINT("Could not create editor cache directory: " + cache_dir);
+ paths_valid = false;
+ }
+ }
+ }
+
+ // Validate or create project-specific editor data dir (`res://.godot`),
+ // including shader cache subdir.
+
+ if (Main::is_project_manager() || Main::is_cmdline_tool()) {
+ // Nothing to create, use shared editor data dir for shader cache.
+ Engine::get_singleton()->set_shader_cache_path(data_dir);
+ } else {
+ DirAccessRef dir_res = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (dir_res->change_dir(project_data_dir) != OK) {
+ dir_res->make_dir_recursive(project_data_dir);
+ if (dir_res->change_dir(project_data_dir) != OK) {
+ ERR_PRINT("Could not create project data directory (" + project_data_dir + ") in: " + dir_res->get_current_dir());
+ paths_valid = false;
+ }
+ }
+ Engine::get_singleton()->set_shader_cache_path(project_data_dir);
+
+ // Editor metadata dir.
+ if (!dir_res->dir_exists("editor")) {
+ dir_res->make_dir("editor");
+ }
+ // Imported assets dir.
+ if (!dir_res->dir_exists(ProjectSettings::IMPORTED_FILES_PATH)) {
+ dir_res->make_dir(ProjectSettings::IMPORTED_FILES_PATH);
+ }
+ }
+}
diff --git a/editor/editor_paths.h b/editor/editor_paths.h
new file mode 100644
index 0000000000..2c156b7c96
--- /dev/null
+++ b/editor/editor_paths.h
@@ -0,0 +1,74 @@
+/*************************************************************************/
+/* editor_paths.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_PATHS_H
+#define EDITOR_PATHS_H
+
+#include "core/object/class_db.h"
+#include "core/string/ustring.h"
+
+class EditorPaths : public Object {
+ GDCLASS(EditorPaths, Object)
+
+ bool paths_valid = false; // If any of the paths can't be created, this is false.
+ String data_dir; // Editor data (templates, shader cache, etc.).
+ String config_dir; // Editor config (settings, profiles, themes, etc.).
+ String cache_dir; // Editor cache (thumbnails, tmp generated files).
+ String project_data_dir = "res://.godot"; // Project-specific data (metadata, shader cache, etc.).
+ bool self_contained = false; // Self-contained means everything goes to `editor_data` dir.
+ String self_contained_file; // Self-contained file with configuration.
+
+ static EditorPaths *singleton;
+
+protected:
+ static void _bind_methods();
+
+public:
+ bool are_paths_valid() const;
+
+ String get_data_dir() const;
+ String get_config_dir() const;
+ String get_cache_dir() const;
+ String get_project_data_dir() const;
+
+ bool is_self_contained() const;
+ String get_self_contained_file() const;
+
+ static EditorPaths *get_singleton() {
+ return singleton;
+ }
+
+ static void create();
+ static void free();
+
+ EditorPaths();
+};
+
+#endif // EDITOR_PATHS_H
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index eabcbacd9a..63de06d5e2 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_export.h"
#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
#include "editor/editor_settings.h"
#include "editor/filesystem_dock.h"
#include "editor/project_settings_editor.h"
@@ -59,7 +60,7 @@ 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<Transform3D> *p_transforms, int p_preview_size) {
int size = p_preview_size;
RID scenario = RS::get_singleton()->scenario_create();
@@ -93,7 +94,7 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh
continue;
}
- Transform mesh_xform;
+ Transform3D mesh_xform;
if (p_transforms != nullptr) {
mesh_xform = (*p_transforms)[i];
}
@@ -104,7 +105,7 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh
AABB aabb = mesh->get_aabb();
Vector3 ofs = aabb.position + aabb.size * 0.5;
aabb.position -= ofs;
- Transform xform;
+ Transform3D xform;
xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI / 6);
xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI / 6) * xform.basis;
AABB rot_aabb = xform.xform(aabb);
@@ -118,11 +119,11 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh
xform.invert();
xform = mesh_xform * xform;
- RS::get_singleton()->camera_set_transform(camera, xform * Transform(Basis(), Vector3(0, 0, 3)));
+ RS::get_singleton()->camera_set_transform(camera, xform * Transform3D(Basis(), Vector3(0, 0, 3)));
RS::get_singleton()->camera_set_orthogonal(camera, m * 2, 0.01, 1000.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)));
+ RS::get_singleton()->instance_set_transform(light_instance, xform * Transform3D().looking_at(Vector3(-2, -1, -1), Vector3(0, 1, 0)));
+ RS::get_singleton()->instance_set_transform(light_instance2, xform * Transform3D().looking_at(Vector3(+1, -1, -2), Vector3(0, 1, 0)));
ep.step(TTR("Thumbnail..."), i);
Main::iteration();
@@ -257,6 +258,9 @@ EditorSelection *EditorInterface::get_selection() {
Ref<EditorSettings> EditorInterface::get_editor_settings() {
return EditorSettings::get_singleton();
}
+EditorPaths *EditorInterface::get_editor_paths() {
+ return EditorPaths::get_singleton();
+}
EditorResourcePreview *EditorInterface::get_resource_previewer() {
return EditorResourcePreview::get_singleton();
@@ -335,6 +339,7 @@ void EditorInterface::_bind_methods() {
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("get_editor_paths"), &EditorInterface::get_editor_paths);
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);
@@ -548,21 +553,21 @@ void EditorPlugin::notify_resource_saved(const Ref<Resource> &p_resource) {
}
bool EditorPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
- if (get_script_instance() && get_script_instance()->has_method("forward_canvas_gui_input")) {
- return get_script_instance()->call("forward_canvas_gui_input", p_event);
+ if (get_script_instance() && get_script_instance()->has_method("_forward_canvas_gui_input")) {
+ return get_script_instance()->call("_forward_canvas_gui_input", p_event);
}
return false;
}
void EditorPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) {
- if (get_script_instance() && get_script_instance()->has_method("forward_canvas_draw_over_viewport")) {
- get_script_instance()->call("forward_canvas_draw_over_viewport", p_overlay);
+ if (get_script_instance() && get_script_instance()->has_method("_forward_canvas_draw_over_viewport")) {
+ get_script_instance()->call("_forward_canvas_draw_over_viewport", p_overlay);
}
}
void EditorPlugin::forward_canvas_force_draw_over_viewport(Control *p_overlay) {
- if (get_script_instance() && get_script_instance()->has_method("forward_canvas_force_draw_over_viewport")) {
- get_script_instance()->call("forward_canvas_force_draw_over_viewport", p_overlay);
+ if (get_script_instance() && get_script_instance()->has_method("_forward_canvas_force_draw_over_viewport")) {
+ get_script_instance()->call("_forward_canvas_force_draw_over_viewport", p_overlay);
}
}
@@ -586,110 +591,110 @@ int EditorPlugin::update_overlays() const {
}
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);
+ 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);
}
return false;
}
void EditorPlugin::forward_spatial_draw_over_viewport(Control *p_overlay) {
- if (get_script_instance() && get_script_instance()->has_method("forward_spatial_draw_over_viewport")) {
- get_script_instance()->call("forward_spatial_draw_over_viewport", p_overlay);
+ if (get_script_instance() && get_script_instance()->has_method("_forward_spatial_draw_over_viewport")) {
+ get_script_instance()->call("_forward_spatial_draw_over_viewport", p_overlay);
}
}
void EditorPlugin::forward_spatial_force_draw_over_viewport(Control *p_overlay) {
- if (get_script_instance() && get_script_instance()->has_method("forward_spatial_force_draw_over_viewport")) {
- get_script_instance()->call("forward_spatial_force_draw_over_viewport", p_overlay);
+ if (get_script_instance() && get_script_instance()->has_method("_forward_spatial_force_draw_over_viewport")) {
+ get_script_instance()->call("_forward_spatial_force_draw_over_viewport", p_overlay);
}
}
String EditorPlugin::get_name() const {
- if (get_script_instance() && get_script_instance()->has_method("get_plugin_name")) {
- return get_script_instance()->call("get_plugin_name");
+ if (get_script_instance() && get_script_instance()->has_method("_get_plugin_name")) {
+ return get_script_instance()->call("_get_plugin_name");
}
return String();
}
const Ref<Texture2D> EditorPlugin::get_icon() const {
- if (get_script_instance() && get_script_instance()->has_method("get_plugin_icon")) {
- return get_script_instance()->call("get_plugin_icon");
+ if (get_script_instance() && get_script_instance()->has_method("_get_plugin_icon")) {
+ return get_script_instance()->call("_get_plugin_icon");
}
return Ref<Texture2D>();
}
bool EditorPlugin::has_main_screen() const {
- if (get_script_instance() && get_script_instance()->has_method("has_main_screen")) {
- return get_script_instance()->call("has_main_screen");
+ if (get_script_instance() && get_script_instance()->has_method("_has_main_screen")) {
+ return get_script_instance()->call("_has_main_screen");
}
return false;
}
void EditorPlugin::make_visible(bool p_visible) {
- if (get_script_instance() && get_script_instance()->has_method("make_visible")) {
- get_script_instance()->call("make_visible", p_visible);
+ if (get_script_instance() && get_script_instance()->has_method("_make_visible")) {
+ get_script_instance()->call("_make_visible", p_visible);
}
}
void EditorPlugin::edit(Object *p_object) {
- if (get_script_instance() && get_script_instance()->has_method("edit")) {
+ if (get_script_instance() && get_script_instance()->has_method("_edit")) {
if (p_object->is_class("Resource")) {
- get_script_instance()->call("edit", Ref<Resource>(Object::cast_to<Resource>(p_object)));
+ get_script_instance()->call("_edit", Ref<Resource>(Object::cast_to<Resource>(p_object)));
} else {
- get_script_instance()->call("edit", p_object);
+ get_script_instance()->call("_edit", p_object);
}
}
}
bool EditorPlugin::handles(Object *p_object) const {
- if (get_script_instance() && get_script_instance()->has_method("handles")) {
- return get_script_instance()->call("handles", p_object);
+ if (get_script_instance() && get_script_instance()->has_method("_handles")) {
+ return get_script_instance()->call("_handles", p_object);
}
return false;
}
Dictionary EditorPlugin::get_state() const {
- if (get_script_instance() && get_script_instance()->has_method("get_state")) {
- return get_script_instance()->call("get_state");
+ if (get_script_instance() && get_script_instance()->has_method("_get_state")) {
+ return get_script_instance()->call("_get_state");
}
return Dictionary();
}
void EditorPlugin::set_state(const Dictionary &p_state) {
- if (get_script_instance() && get_script_instance()->has_method("set_state")) {
- get_script_instance()->call("set_state", p_state);
+ if (get_script_instance() && get_script_instance()->has_method("_set_state")) {
+ get_script_instance()->call("_set_state", p_state);
}
}
void EditorPlugin::clear() {
- if (get_script_instance() && get_script_instance()->has_method("clear")) {
- get_script_instance()->call("clear");
+ if (get_script_instance() && get_script_instance()->has_method("_clear")) {
+ get_script_instance()->call("_clear");
}
}
// if editor references external resources/scenes, save them
void EditorPlugin::save_external_data() {
- if (get_script_instance() && get_script_instance()->has_method("save_external_data")) {
- get_script_instance()->call("save_external_data");
+ if (get_script_instance() && get_script_instance()->has_method("_save_external_data")) {
+ get_script_instance()->call("_save_external_data");
}
}
// if changes are pending in editor, apply them
void EditorPlugin::apply_changes() {
- if (get_script_instance() && get_script_instance()->has_method("apply_changes")) {
- get_script_instance()->call("apply_changes");
+ if (get_script_instance() && get_script_instance()->has_method("_apply_changes")) {
+ get_script_instance()->call("_apply_changes");
}
}
void EditorPlugin::get_breakpoints(List<String> *p_breakpoints) {
- if (get_script_instance() && get_script_instance()->has_method("get_breakpoints")) {
- PackedStringArray arr = get_script_instance()->call("get_breakpoints");
+ if (get_script_instance() && get_script_instance()->has_method("_get_breakpoints")) {
+ PackedStringArray arr = get_script_instance()->call("_get_breakpoints");
for (int i = 0; i < arr.size(); i++) {
p_breakpoints->push_back(arr[i]);
}
@@ -703,53 +708,73 @@ bool EditorPlugin::get_remove_list(List<Node *> *p_list) {
void EditorPlugin::restore_global_state() {}
void EditorPlugin::save_global_state() {}
+void EditorPlugin::add_undo_redo_inspector_hook_callback(Callable p_callable) {
+ EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(p_callable);
+}
+
+void EditorPlugin::remove_undo_redo_inspector_hook_callback(Callable p_callable) {
+ EditorNode::get_singleton()->get_editor_data().remove_undo_redo_inspector_hook_callback(p_callable);
+}
+
void EditorPlugin::add_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser) {
+ ERR_FAIL_COND(!p_parser.is_valid());
EditorTranslationParser::get_singleton()->add_parser(p_parser, EditorTranslationParser::CUSTOM);
}
void EditorPlugin::remove_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser) {
+ ERR_FAIL_COND(!p_parser.is_valid());
EditorTranslationParser::get_singleton()->remove_parser(p_parser, EditorTranslationParser::CUSTOM);
}
void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer) {
+ ERR_FAIL_COND(!p_importer.is_valid());
ResourceFormatImporter::get_singleton()->add_importer(p_importer);
EditorFileSystem::get_singleton()->call_deferred("scan");
}
void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) {
+ ERR_FAIL_COND(!p_importer.is_valid());
ResourceFormatImporter::get_singleton()->remove_importer(p_importer);
EditorFileSystem::get_singleton()->call_deferred("scan");
}
void EditorPlugin::add_export_plugin(const Ref<EditorExportPlugin> &p_exporter) {
+ ERR_FAIL_COND(!p_exporter.is_valid());
EditorExport::get_singleton()->add_export_plugin(p_exporter);
}
void EditorPlugin::remove_export_plugin(const Ref<EditorExportPlugin> &p_exporter) {
+ ERR_FAIL_COND(!p_exporter.is_valid());
EditorExport::get_singleton()->remove_export_plugin(p_exporter);
}
void EditorPlugin::add_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) {
+ ERR_FAIL_COND(!p_gizmo_plugin.is_valid());
Node3DEditor::get_singleton()->add_gizmo_plugin(p_gizmo_plugin);
}
void EditorPlugin::remove_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) {
+ ERR_FAIL_COND(!p_gizmo_plugin.is_valid());
Node3DEditor::get_singleton()->remove_gizmo_plugin(p_gizmo_plugin);
}
void EditorPlugin::add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) {
+ ERR_FAIL_COND(!p_plugin.is_valid());
EditorInspector::add_inspector_plugin(p_plugin);
}
void EditorPlugin::remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) {
+ ERR_FAIL_COND(!p_plugin.is_valid());
EditorInspector::remove_inspector_plugin(p_plugin);
}
void EditorPlugin::add_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) {
+ ERR_FAIL_COND(!p_importer.is_valid());
ResourceImporterScene::get_singleton()->add_importer(p_importer);
}
void EditorPlugin::remove_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) {
+ ERR_FAIL_COND(!p_importer.is_valid());
ResourceImporterScene::get_singleton()->remove_importer(p_importer);
}
@@ -766,8 +791,8 @@ int find(const PackedStringArray &a, const String &v) {
void EditorPlugin::enable_plugin() {
// Called when the plugin gets enabled in project settings, after it's added to the tree.
// You can implement it to register autoloads.
- if (get_script_instance() && get_script_instance()->has_method("enable_plugin")) {
- get_script_instance()->call("enable_plugin");
+ if (get_script_instance() && get_script_instance()->has_method("_enable_plugin")) {
+ get_script_instance()->call("_enable_plugin");
}
}
@@ -775,26 +800,26 @@ void EditorPlugin::disable_plugin() {
// Last function called when the plugin gets disabled in project settings.
// Implement it to cleanup things from the project, such as unregister autoloads.
- if (get_script_instance() && get_script_instance()->has_method("disable_plugin")) {
- get_script_instance()->call("disable_plugin");
+ if (get_script_instance() && get_script_instance()->has_method("_disable_plugin")) {
+ get_script_instance()->call("_disable_plugin");
}
}
void EditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
- if (get_script_instance() && get_script_instance()->has_method("set_window_layout")) {
- get_script_instance()->call("set_window_layout", p_layout);
+ if (get_script_instance() && get_script_instance()->has_method("_set_window_layout")) {
+ get_script_instance()->call("_set_window_layout", p_layout);
}
}
void EditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) {
- if (get_script_instance() && get_script_instance()->has_method("get_window_layout")) {
- get_script_instance()->call("get_window_layout", p_layout);
+ if (get_script_instance() && get_script_instance()->has_method("_get_window_layout")) {
+ get_script_instance()->call("_get_window_layout", p_layout);
}
}
bool EditorPlugin::build() {
- if (get_script_instance() && get_script_instance()->has_method("build")) {
- return get_script_instance()->call("build");
+ if (get_script_instance() && get_script_instance()->has_method("_build")) {
+ return get_script_instance()->call("_build");
}
return true;
@@ -862,6 +887,8 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("hide_bottom_panel"), &EditorPlugin::hide_bottom_panel);
ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::_get_undo_redo);
+ ClassDB::bind_method(D_METHOD("add_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::add_undo_redo_inspector_hook_callback);
+ ClassDB::bind_method(D_METHOD("remove_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::remove_undo_redo_inspector_hook_callback);
ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout);
ClassDB::bind_method(D_METHOD("add_translation_parser_plugin", "parser"), &EditorPlugin::add_translation_parser_plugin);
ClassDB::bind_method(D_METHOD("remove_translation_parser_plugin", "parser"), &EditorPlugin::remove_translation_parser_plugin);
@@ -883,29 +910,29 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_debugger_plugin", "script"), &EditorPlugin::add_debugger_plugin);
ClassDB::bind_method(D_METHOD("remove_debugger_plugin", "script"), &EditorPlugin::remove_debugger_plugin);
- ClassDB::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, "Camera3D"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_spatial_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_spatial_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
- 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"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("make_visible", PropertyInfo(Variant::BOOL, "visible")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("edit", PropertyInfo(Variant::OBJECT, "object")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles", PropertyInfo(Variant::OBJECT, "object")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::DICTIONARY, "get_state"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("set_state", PropertyInfo(Variant::DICTIONARY, "state")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("clear"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("save_external_data"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("apply_changes"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_breakpoints"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("set_window_layout", PropertyInfo(Variant::OBJECT, "layout", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_window_layout", PropertyInfo(Variant::OBJECT, "layout", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "build"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("enable_plugin"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo("disable_plugin"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_forward_canvas_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
+ BIND_VMETHOD(MethodInfo("_forward_canvas_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
+ BIND_VMETHOD(MethodInfo("_forward_canvas_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
+ BIND_VMETHOD(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")));
+ BIND_VMETHOD(MethodInfo("_forward_spatial_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
+ BIND_VMETHOD(MethodInfo("_forward_spatial_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_plugin_name"));
+ BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "_get_plugin_icon"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_has_main_screen"));
+ BIND_VMETHOD(MethodInfo("_make_visible", PropertyInfo(Variant::BOOL, "visible")));
+ BIND_VMETHOD(MethodInfo("_edit", PropertyInfo(Variant::OBJECT, "object")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_handles", PropertyInfo(Variant::OBJECT, "object")));
+ BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "_get_state"));
+ BIND_VMETHOD(MethodInfo("_set_state", PropertyInfo(Variant::DICTIONARY, "state")));
+ BIND_VMETHOD(MethodInfo("_clear"));
+ BIND_VMETHOD(MethodInfo("_save_external_data"));
+ BIND_VMETHOD(MethodInfo("_apply_changes"));
+ BIND_VMETHOD(MethodInfo(Variant::PACKED_STRING_ARRAY, "_get_breakpoints"));
+ BIND_VMETHOD(MethodInfo("_set_window_layout", PropertyInfo(Variant::OBJECT, "layout", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile")));
+ BIND_VMETHOD(MethodInfo("_get_window_layout", PropertyInfo(Variant::OBJECT, "layout", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_build"));
+ BIND_VMETHOD(MethodInfo("_enable_plugin"));
+ BIND_VMETHOD(MethodInfo("_disable_plugin"));
ADD_SIGNAL(MethodInfo("scene_changed", PropertyInfo(Variant::OBJECT, "scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("scene_closed", PropertyInfo(Variant::STRING, "filepath")));
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 67b163eabf..2e1dd0a0c1 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -54,6 +54,7 @@ class EditorNode3DGizmoPlugin;
class EditorResourcePreview;
class EditorFileSystem;
class EditorToolAddons;
+class EditorPaths;
class FileSystemDock;
class ScriptEditor;
@@ -95,6 +96,7 @@ public:
EditorSelection *get_selection();
//EditorImportExport *get_import_export();
Ref<EditorSettings> get_editor_settings();
+ EditorPaths *get_editor_paths();
EditorResourcePreview *get_resource_previewer();
EditorFileSystem *get_resource_file_system();
@@ -111,7 +113,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<Transform3D> *p_transforms, int p_preview_size);
void set_main_screen_editor(const String &p_name);
void set_distraction_free_mode(bool p_enter);
@@ -225,6 +227,9 @@ public:
EditorInterface *get_editor_interface();
ScriptCreateDialog *get_script_create_dialog();
+ void add_undo_redo_inspector_hook_callback(Callable p_callable);
+ void remove_undo_redo_inspector_hook_callback(Callable p_callable);
+
int update_overlays() const;
void queue_save_layout();
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index e5b62513ff..1db24bb908 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -32,7 +32,7 @@
#include "core/config/project_settings.h"
#include "core/io/config_file.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/main_loop.h"
#include "editor_node.h"
#include "editor_scale.h"
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 4ea993af5b..3feeaec070 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -38,7 +38,7 @@
#include "scene/main/window.h"
#include "scene/resources/font.h"
-///////////////////// NULL /////////////////////////
+///////////////////// Nil /////////////////////////
void EditorPropertyNil::update_property() {
}
@@ -51,7 +51,7 @@ EditorPropertyNil::EditorPropertyNil() {
///////////////////// TEXT /////////////////////////
-void EditorPropertyText::_text_entered(const String &p_string) {
+void EditorPropertyText::_text_submitted(const String &p_string) {
if (updating) {
return;
}
@@ -100,7 +100,7 @@ EditorPropertyText::EditorPropertyText() {
add_child(text);
add_focusable(text);
text->connect("text_changed", callable_mp(this, &EditorPropertyText::_text_changed));
- text->connect("text_entered", callable_mp(this, &EditorPropertyText::_text_entered));
+ text->connect("text_submitted", callable_mp(this, &EditorPropertyText::_text_submitted));
string_name = false;
updating = false;
@@ -297,7 +297,7 @@ EditorPropertyPath::EditorPropertyPath() {
path = memnew(LineEdit);
path->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE);
path_hb->add_child(path);
- path->connect("text_entered", callable_mp(this, &EditorPropertyPath::_path_selected));
+ path->connect("text_submitted", callable_mp(this, &EditorPropertyPath::_path_selected));
path->connect("focus_exited", callable_mp(this, &EditorPropertyPath::_path_focus_exited));
path->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -929,7 +929,7 @@ EditorPropertyFloat::EditorPropertyFloat() {
void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
const Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid()) {
- if (mb->is_doubleclick() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_double_click() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_setup_spin();
}
@@ -951,7 +951,7 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
const Ref<InputEventMouseMotion> mm = p_ev;
- if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ if (dragging && mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
float rel = mm->get_relative().x;
if (rel == 0) {
return;
@@ -994,9 +994,8 @@ void EditorPropertyEasing::_draw_easing() {
Size2 s = easing_draw->get_size();
- const int points = 48;
+ const int point_count = 48;
- float prev = 1.0;
const float exp = get_edited_object()->get(get_edited_property());
const Ref<Font> f = get_theme_font("font", "Label");
@@ -1009,24 +1008,20 @@ void EditorPropertyEasing::_draw_easing() {
line_color = get_theme_color("font_color", "Label") * Color(1, 1, 1, 0.9);
}
- Vector<Point2> lines;
- for (int i = 1; i <= points; i++) {
- float ifl = i / float(points);
- float iflp = (i - 1) / float(points);
+ Vector<Point2> points;
+ for (int i = 0; i <= point_count; i++) {
+ float ifl = i / float(point_count);
const float h = 1.0 - Math::ease(ifl, exp);
if (flip) {
ifl = 1.0 - ifl;
- iflp = 1.0 - iflp;
}
- lines.push_back(Point2(ifl * s.width, h * s.height));
- lines.push_back(Point2(iflp * s.width, prev * s.height));
- prev = h;
+ points.push_back(Point2(ifl * s.width, h * s.height));
}
- easing_draw->draw_multiline(lines, line_color, 1.0);
+ easing_draw->draw_polyline(points, line_color, 1.0, true);
// Draw more decimals for small numbers since higher precision is usually required for fine adjustments.
int decimals;
if (Math::abs(exp) < 0.1 - CMP_EPSILON) {
@@ -1761,14 +1756,14 @@ EditorPropertyPlane::EditorPropertyPlane(bool p_force_wide) {
setting = false;
}
-///////////////////// QUAT /////////////////////////
+///////////////////// QUATERNION /////////////////////////
-void EditorPropertyQuat::_value_changed(double val, const String &p_name) {
+void EditorPropertyQuaternion::_value_changed(double val, const String &p_name) {
if (setting) {
return;
}
- Quat p;
+ Quaternion p;
p.x = spin[0]->get_value();
p.y = spin[1]->get_value();
p.z = spin[2]->get_value();
@@ -1776,8 +1771,8 @@ void EditorPropertyQuat::_value_changed(double val, const String &p_name) {
emit_changed(get_edited_property(), p, p_name);
}
-void EditorPropertyQuat::update_property() {
- Quat val = get_edited_object()->get(get_edited_property());
+void EditorPropertyQuaternion::update_property() {
+ Quaternion val = get_edited_object()->get(get_edited_property());
setting = true;
spin[0]->set_value(val.x);
spin[1]->set_value(val.y);
@@ -1786,7 +1781,7 @@ void EditorPropertyQuat::update_property() {
setting = false;
}
-void EditorPropertyQuat::_notification(int p_what) {
+void EditorPropertyQuaternion::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 3; i++) {
@@ -1797,10 +1792,10 @@ void EditorPropertyQuat::_notification(int p_what) {
}
}
-void EditorPropertyQuat::_bind_methods() {
+void EditorPropertyQuaternion::_bind_methods() {
}
-void EditorPropertyQuat::setup(double p_min, double p_max, double p_step, bool p_no_slider) {
+void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_no_slider) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
@@ -1811,7 +1806,7 @@ void EditorPropertyQuat::setup(double p_min, double p_max, double p_step, bool p
}
}
-EditorPropertyQuat::EditorPropertyQuat() {
+EditorPropertyQuaternion::EditorPropertyQuaternion() {
bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector_types_editing");
BoxContainer *bc;
@@ -1832,7 +1827,7 @@ EditorPropertyQuat::EditorPropertyQuat() {
spin[i]->set_label(desc[i]);
bc->add_child(spin[i]);
add_focusable(spin[i]);
- spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyQuat::_value_changed), varray(desc[i]));
+ spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyQuaternion::_value_changed), varray(desc[i]));
if (horizontal) {
spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
}
@@ -2078,12 +2073,12 @@ EditorPropertyBasis::EditorPropertyBasis() {
///////////////////// TRANSFORM /////////////////////////
-void EditorPropertyTransform::_value_changed(double val, const String &p_name) {
+void EditorPropertyTransform3D::_value_changed(double val, const String &p_name) {
if (setting) {
return;
}
- Transform p;
+ Transform3D p;
p.basis[0][0] = spin[0]->get_value();
p.basis[1][0] = spin[1]->get_value();
p.basis[2][0] = spin[2]->get_value();
@@ -2100,11 +2095,11 @@ void EditorPropertyTransform::_value_changed(double val, const String &p_name) {
emit_changed(get_edited_property(), p, p_name);
}
-void EditorPropertyTransform::update_property() {
+void EditorPropertyTransform3D::update_property() {
update_using_transform(get_edited_object()->get(get_edited_property()));
}
-void EditorPropertyTransform::update_using_transform(Transform p_transform) {
+void EditorPropertyTransform3D::update_using_transform(Transform3D p_transform) {
setting = true;
spin[0]->set_value(p_transform.basis[0][0]);
spin[1]->set_value(p_transform.basis[1][0]);
@@ -2121,7 +2116,7 @@ void EditorPropertyTransform::update_using_transform(Transform p_transform) {
setting = false;
}
-void EditorPropertyTransform::_notification(int p_what) {
+void EditorPropertyTransform3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 12; i++) {
@@ -2132,10 +2127,10 @@ void EditorPropertyTransform::_notification(int p_what) {
}
}
-void EditorPropertyTransform::_bind_methods() {
+void EditorPropertyTransform3D::_bind_methods() {
}
-void EditorPropertyTransform::setup(double p_min, double p_max, double p_step, bool p_no_slider) {
+void EditorPropertyTransform3D::setup(double p_min, double p_max, double p_step, bool p_no_slider) {
for (int i = 0; i < 12; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
@@ -2146,7 +2141,7 @@ void EditorPropertyTransform::setup(double p_min, double p_max, double p_step, b
}
}
-EditorPropertyTransform::EditorPropertyTransform() {
+EditorPropertyTransform3D::EditorPropertyTransform3D() {
GridContainer *g = memnew(GridContainer);
g->set_columns(3);
add_child(g);
@@ -2159,7 +2154,7 @@ EditorPropertyTransform::EditorPropertyTransform() {
g->add_child(spin[i]);
spin[i]->set_h_size_flags(SIZE_EXPAND_FILL);
add_focusable(spin[i]);
- spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyTransform::_value_changed), varray(desc[i]));
+ spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyTransform3D::_value_changed), varray(desc[i]));
}
set_bottom_editor(g);
setting = false;
@@ -2261,7 +2256,7 @@ void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
base_node = get_edited_object()->call("get_root_path");
}
- if (!base_node && Object::cast_to<Reference>(get_edited_object())) {
+ if (!base_node && Object::cast_to<RefCounted>(get_edited_object())) {
Node *to_node = get_node(p_path);
ERR_FAIL_COND(!to_node);
path = get_tree()->get_edited_scene_root()->get_path_to(to_node);
@@ -2384,426 +2379,64 @@ EditorPropertyRID::EditorPropertyRID() {
////////////// RESOURCE //////////////////////
-void EditorPropertyResource::_file_selected(const String &p_path) {
- RES res = ResourceLoader::load(p_path);
-
- ERR_FAIL_COND_MSG(res.is_null(), "Cannot load resource from path '" + p_path + "'.");
-
- List<PropertyInfo> prop_list;
- get_edited_object()->get_property_list(&prop_list);
- String property_types;
-
- for (List<PropertyInfo>::Element *E = prop_list.front(); E; E = E->next()) {
- if (E->get().name == get_edited_property() && (E->get().hint & PROPERTY_HINT_RESOURCE_TYPE)) {
- property_types = E->get().hint_string;
- }
- }
- if (!property_types.is_empty()) {
- bool any_type_matches = false;
- const Vector<String> split_property_types = property_types.split(",");
- for (int i = 0; i < split_property_types.size(); ++i) {
- if (res->is_class(split_property_types[i])) {
- any_type_matches = true;
- break;
- }
- }
-
- if (!any_type_matches) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("The selected resource (%s) does not match any type expected for this property (%s)."), res->get_class(), property_types));
- }
+void EditorPropertyResource::_resource_selected(const RES &p_resource) {
+ if (use_sub_inspector) {
+ bool unfold = !get_edited_object()->editor_is_section_unfolded(get_edited_property());
+ get_edited_object()->editor_set_section_unfold(get_edited_property(), unfold);
+ update_property();
+ } else {
+ emit_signal("resource_selected", get_edited_property(), p_resource);
}
-
- emit_changed(get_edited_property(), res);
- update_property();
}
-void EditorPropertyResource::_menu_option(int p_which) {
- //scene_tree->popup_scenetree_dialog();
- switch (p_which) {
- case OBJ_MENU_LOAD: {
- if (!file) {
- file = memnew(EditorFileDialog);
- file->connect("file_selected", callable_mp(this, &EditorPropertyResource::_file_selected));
- add_child(file);
- }
- file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
- String type = base_type;
-
- List<String> extensions;
- for (int i = 0; i < type.get_slice_count(","); i++) {
- ResourceLoader::get_recognized_extensions_for_type(type.get_slice(",", i), &extensions);
- }
-
- Set<String> valid_extensions;
- for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
- valid_extensions.insert(E->get());
- }
-
- file->clear_filters();
- for (Set<String>::Element *E = valid_extensions.front(); E; E = E->next()) {
- file->add_filter("*." + E->get() + " ; " + E->get().to_upper());
- }
-
- file->popup_file_dialog();
- } break;
-
- case OBJ_MENU_EDIT: {
- RES res = get_edited_object()->get(get_edited_property());
+void EditorPropertyResource::_resource_changed(const RES &p_resource) {
+ // Make visual script the correct type.
+ Ref<Script> s = p_resource;
+ if (get_edited_object() && s.is_valid()) {
+ s->call("set_instance_base_type", get_edited_object()->get_class());
+ }
- if (!res.is_null()) {
- emit_signal("resource_selected", get_edited_property(), res);
- }
- } break;
- case OBJ_MENU_CLEAR: {
+ // Prevent the creation of invalid ViewportTextures when possible.
+ Ref<ViewportTexture> vpt = p_resource;
+ if (vpt.is_valid()) {
+ Resource *r = Object::cast_to<Resource>(get_edited_object());
+ if (r && r->get_path().is_resource_file()) {
+ EditorNode::get_singleton()->show_warning(TTR("Can't create a ViewportTexture on resources saved as a file.\nResource needs to belong to a scene."));
emit_changed(get_edited_property(), RES());
update_property();
-
- } break;
-
- case OBJ_MENU_MAKE_UNIQUE: {
- RES res_orig = get_edited_object()->get(get_edited_property());
- if (res_orig.is_null()) {
- return;
- }
-
- List<PropertyInfo> property_list;
- res_orig->get_property_list(&property_list);
- List<Pair<String, Variant>> propvalues;
-
- for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
- Pair<String, Variant> p;
- PropertyInfo &pi = E->get();
- if (pi.usage & PROPERTY_USAGE_STORAGE) {
- p.first = pi.name;
- p.second = res_orig->get(pi.name);
- }
-
- propvalues.push_back(p);
- }
-
- String orig_type = res_orig->get_class();
-
- Object *inst = ClassDB::instance(orig_type);
-
- Ref<Resource> res = Ref<Resource>(Object::cast_to<Resource>(inst));
-
- ERR_FAIL_COND(res.is_null());
-
- 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);
- }
-
- emit_changed(get_edited_property(), res);
- update_property();
-
- } break;
-
- case OBJ_MENU_SAVE: {
- RES res = get_edited_object()->get(get_edited_property());
- if (res.is_null()) {
- return;
- }
- EditorNode::get_singleton()->save_resource(res);
- } break;
-
- case OBJ_MENU_COPY: {
- RES res = get_edited_object()->get(get_edited_property());
-
- EditorSettings::get_singleton()->set_resource_clipboard(res);
-
- } break;
- case OBJ_MENU_PASTE: {
- RES res = EditorSettings::get_singleton()->get_resource_clipboard();
- emit_changed(get_edited_property(), res);
- update_property();
-
- } break;
- case OBJ_MENU_NEW_SCRIPT: {
- if (Object::cast_to<Node>(get_edited_object())) {
- EditorNode::get_singleton()->get_scene_tree_dock()->open_script_dialog(Object::cast_to<Node>(get_edited_object()), false);
- }
-
- } break;
- case OBJ_MENU_EXTEND_SCRIPT: {
- if (Object::cast_to<Node>(get_edited_object())) {
- EditorNode::get_singleton()->get_scene_tree_dock()->open_script_dialog(Object::cast_to<Node>(get_edited_object()), true);
- }
-
- } break;
- case OBJ_MENU_SHOW_IN_FILE_SYSTEM: {
- RES res = get_edited_object()->get(get_edited_property());
-
- FileSystemDock *file_system_dock = EditorNode::get_singleton()->get_filesystem_dock();
- 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_index());
- } break;
- default: {
- RES res = get_edited_object()->get(get_edited_property());
-
- if (p_which >= CONVERT_BASE_ID) {
- int to_type = p_which - CONVERT_BASE_ID;
-
- Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(res);
-
- ERR_FAIL_INDEX(to_type, conversions.size());
-
- Ref<Resource> new_res = conversions[to_type]->convert(res);
-
- emit_changed(get_edited_property(), new_res);
- update_property();
- break;
- }
- ERR_FAIL_COND(inheritors_array.is_empty());
-
- String intype = inheritors_array[p_which - TYPE_BASE_ID];
-
- if (intype == "ViewportTexture") {
- Resource *r = Object::cast_to<Resource>(get_edited_object());
- if (r && r->get_path().is_resource_file()) {
- EditorNode::get_singleton()->show_warning(TTR("Can't create a ViewportTexture on resources saved as a file.\nResource needs to belong to a scene."));
- return;
- }
-
- if (r && !r->is_local_to_scene()) {
- EditorNode::get_singleton()->show_warning(TTR("Can't create a ViewportTexture on this resource because it's not set as local to scene.\nPlease switch on the 'local to scene' property on it (and all resources containing it up to a node)."));
- return;
- }
-
- if (!scene_tree) {
- scene_tree = memnew(SceneTreeDialog);
- Vector<StringName> valid_types;
- valid_types.push_back("Viewport");
- scene_tree->get_scene_tree()->set_valid_types(valid_types);
- scene_tree->get_scene_tree()->set_show_enabled_subscene(true);
- add_child(scene_tree);
- scene_tree->connect("selected", callable_mp(this, &EditorPropertyResource::_viewport_selected));
- scene_tree->set_title(TTR("Pick a Viewport"));
- }
- scene_tree->popup_scenetree_dialog();
-
- return;
- }
-
- Variant obj;
-
- if (ScriptServer::is_global_class(intype)) {
- obj = ClassDB::instance(ScriptServer::get_global_class_native_base(intype));
- if (obj) {
- Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(intype));
- if (script.is_valid()) {
- ((Object *)obj)->set_script(script);
- }
- }
- } else {
- obj = ClassDB::instance(intype);
- }
-
- if (!obj) {
- obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
- }
-
- Resource *resp = Object::cast_to<Resource>(obj);
- ERR_BREAK(!resp);
- if (get_edited_object() && base_type != String() && base_type == "Script") {
- //make visual script the right type
- resp->call("set_instance_base_type", get_edited_object()->get_class());
- }
-
- res = RES(resp);
- emit_changed(get_edited_property(), res);
- update_property();
-
- } break;
- }
-}
-
-void EditorPropertyResource::_resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj) {
- RES p = get_edited_object()->get(get_edited_property());
- if (p.is_valid() && p->get_instance_id() == p_obj) {
- String type = p->get_class_name();
-
- if (ClassDB::is_parent_class(type, "Script")) {
- assign->set_text(p->get_path().get_file());
return;
}
- if (p_preview.is_valid()) {
- preview->set_offset(SIDE_LEFT, assign->get_icon()->get_width() + assign->get_theme_stylebox("normal")->get_default_margin(SIDE_LEFT) + get_theme_constant("hseparation", "Button"));
- if (type == "GradientTexture") {
- preview->set_stretch_mode(TextureRect::STRETCH_SCALE);
- assign->set_custom_minimum_size(Size2(1, 1));
- } else {
- preview->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
- assign->set_custom_minimum_size(Size2(1, thumbnail_size));
- }
- preview->set_texture(p_preview);
- assign->set_text("");
- }
- }
-}
-
-void EditorPropertyResource::_update_menu_items() {
- //////////////////// UPDATE MENU //////////////////////////
- RES res = get_edited_object()->get(get_edited_property());
-
- menu->clear();
-
- if (get_edited_property() == "script" && base_type == "Script" && Object::cast_to<Node>(get_edited_object())) {
- 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;
-
- Vector<EditorData::CustomType> custom_resources;
-
- if (EditorNode::get_editor_data().get_custom_types().has("Resource")) {
- custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"];
- }
-
- for (int i = 0; i < base_type.get_slice_count(","); i++) {
- String base = base_type.get_slice(",", i);
-
- Set<String> valid_inheritors;
- valid_inheritors.insert(base);
- List<StringName> inheritors;
- ClassDB::get_inheriters_from_class(base.strip_edges(), &inheritors);
-
- for (int j = 0; j < custom_resources.size(); j++) {
- inheritors.push_back(custom_resources[j].name);
- }
-
- List<StringName>::Element *E = inheritors.front();
- while (E) {
- valid_inheritors.insert(E->get());
- E = E->next();
- }
-
- List<StringName> global_classes;
- ScriptServer::get_global_class_list(&global_classes);
- E = global_classes.front();
- while (E) {
- if (EditorNode::get_editor_data().script_class_is_parent(E->get(), base_type)) {
- valid_inheritors.insert(E->get());
- }
- E = E->next();
- }
-
- for (Set<String>::Element *F = valid_inheritors.front(); F; F = F->next()) {
- const String &t = F->get();
-
- bool is_custom_resource = false;
- Ref<Texture2D> icon;
- if (!custom_resources.is_empty()) {
- for (int j = 0; j < custom_resources.size(); j++) {
- if (custom_resources[j].name == t) {
- is_custom_resource = true;
- if (custom_resources[j].icon.is_valid()) {
- icon = custom_resources[j].icon;
- }
- break;
- }
- }
- }
-
- if (!is_custom_resource && !(ScriptServer::is_global_class(t) || ClassDB::can_instance(t))) {
- continue;
- }
-
- inheritors_array.push_back(t);
-
- if (!icon.is_valid()) {
- 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);
-
- idx++;
- }
- }
-
- if (menu->get_item_count()) {
- menu->add_separator();
- }
- }
-
- menu->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Load"), OBJ_MENU_LOAD);
-
- if (!res.is_null()) {
- 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();
- menu->add_item(TTR("Show in FileSystem"), OBJ_MENU_SHOW_IN_FILE_SYSTEM);
- }
- }
-
- RES cb = EditorSettings::get_singleton()->get_resource_clipboard();
- bool paste_valid = false;
- if (cb.is_valid()) {
- if (base_type == "") {
- paste_valid = true;
- } else {
- for (int i = 0; i < base_type.get_slice_count(","); i++) {
- if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) {
- paste_valid = true;
- break;
- }
- }
+ if (r && !r->is_local_to_scene()) {
+ EditorNode::get_singleton()->show_warning(TTR("Can't create a ViewportTexture on this resource because it's not set as local to scene.\nPlease switch on the 'local to scene' property on it (and all resources containing it up to a node)."));
+ emit_changed(get_edited_property(), RES());
+ update_property();
+ return;
}
}
- if (!res.is_null() || paste_valid) {
- menu->add_separator();
+ emit_changed(get_edited_property(), p_resource);
+ update_property();
- if (!res.is_null()) {
- menu->add_item(TTR("Copy"), OBJ_MENU_COPY);
- }
+ // Automatically suggest setting up the path for a ViewportTexture.
+ if (vpt.is_valid() && vpt->get_viewport_path_in_scene().is_empty()) {
+ if (!scene_tree) {
+ scene_tree = memnew(SceneTreeDialog);
+ scene_tree->set_title(TTR("Pick a Viewport"));
- if (paste_valid) {
- menu->add_item(TTR("Paste"), OBJ_MENU_PASTE);
- }
- }
+ Vector<StringName> valid_types;
+ valid_types.push_back("Viewport");
+ scene_tree->get_scene_tree()->set_valid_types(valid_types);
+ scene_tree->get_scene_tree()->set_show_enabled_subscene(true);
- if (!res.is_null()) {
- Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(res);
- if (conversions.size()) {
- menu->add_separator();
+ add_child(scene_tree);
+ scene_tree->connect("selected", callable_mp(this, &EditorPropertyResource::_viewport_selected));
}
- for (int i = 0; i < conversions.size(); i++) {
- String what = conversions[i]->converts_to();
- Ref<Texture2D> icon;
- if (has_theme_icon(what, "EditorIcons")) {
- icon = get_theme_icon(what, "EditorIcons");
- } else {
- icon = get_theme_icon(what, "Resource");
- }
- menu->add_icon_item(icon, vformat(TTR("Convert To %s"), what), CONVERT_BASE_ID + i);
- }
+ scene_tree->popup_scenetree_dialog();
}
}
-void EditorPropertyResource::_update_menu() {
- _update_menu_items();
-
- Rect2 gt = edit->get_screen_rect();
- menu->set_as_minsize();
- int ms = menu->get_contents_minimum_size().width;
- Vector2 popup_pos = gt.position + gt.size - Vector2(ms, 0);
- menu->set_position(popup_pos);
- menu->popup();
-}
-
void EditorPropertyResource::_sub_inspector_property_keyed(const String &p_property, const Variant &p_value, bool) {
emit_signal("property_keyed_with_value", String(get_edited_property()) + ":" + p_property, p_value, false);
}
@@ -2816,24 +2449,11 @@ void EditorPropertyResource::_sub_inspector_object_id_selected(int p_id) {
emit_signal("object_id_selected", get_edited_property(), p_id);
}
-void EditorPropertyResource::_button_input(const Ref<InputEvent> &p_event) {
- Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- _update_menu_items();
- Vector2 pos = get_screen_position() + mb->get_position();
- //pos = assign->get_global_transform().xform(pos);
- menu->set_as_minsize();
- menu->set_position(pos);
- menu->popup();
- }
- }
-}
-
void EditorPropertyResource::_open_editor_pressed() {
RES res = get_edited_object()->get(get_edited_property());
if (res.is_valid()) {
- EditorNode::get_singleton()->call_deferred("edit_item_resource", res); //may clear the editor so do it deferred
+ // May clear the editor so do it deferred.
+ EditorNode::get_singleton()->call_deferred("edit_item_resource", res);
}
}
@@ -2843,28 +2463,28 @@ void EditorPropertyResource::_fold_other_editors(Object *p_self) {
}
RES res = get_edited_object()->get(get_edited_property());
-
if (!res.is_valid()) {
return;
}
+
bool use_editor = false;
for (int i = 0; i < EditorNode::get_editor_data().get_editor_plugin_count(); i++) {
EditorPlugin *ep = EditorNode::get_editor_data().get_editor_plugin(i);
if (ep->handles(res.ptr())) {
use_editor = true;
+ break;
}
}
-
if (!use_editor) {
return;
}
- bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
opened_editor = false;
+ bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
if (unfolded) {
- //refold
- assign->set_pressed(false);
+ // Refold.
+ resource_picker->set_toggle_pressed(false);
get_edited_object()->editor_set_section_unfold(get_edited_property(), false);
update_property();
}
@@ -2876,6 +2496,7 @@ void EditorPropertyResource::_update_property_bg() {
}
updating_theme = true;
+
if (sub_inspector != nullptr) {
int count_subinspectors = 0;
Node *n = get_parent();
@@ -2905,12 +2526,60 @@ void EditorPropertyResource::_update_property_bg() {
updating_theme = false;
update();
}
+
+void EditorPropertyResource::_viewport_selected(const NodePath &p_path) {
+ Node *to_node = get_node(p_path);
+ if (!Object::cast_to<Viewport>(to_node)) {
+ EditorNode::get_singleton()->show_warning(TTR("Selected node is not a Viewport!"));
+ return;
+ }
+
+ Ref<ViewportTexture> vt;
+ vt.instance();
+ vt->set_viewport_path_in_scene(get_tree()->get_edited_scene_root()->get_path_to(to_node));
+ vt->setup_local_to_scene();
+
+ emit_changed(get_edited_property(), vt);
+ update_property();
+}
+
+void EditorPropertyResource::setup(Object *p_object, const String &p_path, const String &p_base_type) {
+ if (resource_picker) {
+ resource_picker->disconnect("resource_selected", callable_mp(this, &EditorPropertyResource::_resource_selected));
+ resource_picker->disconnect("resource_changed", callable_mp(this, &EditorPropertyResource::_resource_changed));
+ memdelete(resource_picker);
+ }
+
+ if (p_path == "script" && p_base_type == "Script" && Object::cast_to<Node>(p_object)) {
+ EditorScriptPicker *script_picker = memnew(EditorScriptPicker);
+ script_picker->set_script_owner(Object::cast_to<Node>(p_object));
+ resource_picker = script_picker;
+ } else {
+ resource_picker = memnew(EditorResourcePicker);
+ }
+
+ resource_picker->set_base_type(p_base_type);
+ resource_picker->set_editable(true);
+ resource_picker->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_child(resource_picker);
+
+ resource_picker->connect("resource_selected", callable_mp(this, &EditorPropertyResource::_resource_selected));
+ resource_picker->connect("resource_changed", callable_mp(this, &EditorPropertyResource::_resource_changed));
+
+ for (int i = 0; i < resource_picker->get_child_count(); i++) {
+ Button *b = Object::cast_to<Button>(resource_picker->get_child(i));
+ if (b) {
+ add_focusable(b);
+ }
+ }
+}
+
void EditorPropertyResource::update_property() {
RES res = get_edited_object()->get(get_edited_property());
if (use_sub_inspector) {
- if (res.is_valid() != assign->is_toggle_mode()) {
- assign->set_toggle_mode(res.is_valid());
+ if (res.is_valid() != resource_picker->is_toggle_mode()) {
+ resource_picker->set_toggle_mode(res.is_valid());
}
if (res.is_valid() && get_edited_object()->editor_is_section_unfolded(get_edited_property())) {
@@ -2935,7 +2604,7 @@ void EditorPropertyResource::update_property() {
set_bottom_editor(sub_inspector_vbox);
sub_inspector_vbox->add_child(sub_inspector);
- assign->set_pressed(true);
+ resource_picker->set_toggle_pressed(true);
bool use_editor = false;
for (int i = 0; i < EditorNode::get_editor_data().get_editor_plugin_count(); i++) {
@@ -2946,7 +2615,7 @@ void EditorPropertyResource::update_property() {
}
if (use_editor) {
- //open editor directly and hide other open of these
+ // Open editor directly and hide other such editors which are currently open.
_open_editor_pressed();
if (is_inside_tree()) {
get_tree()->call_deferred("call_group", "_editor_resource_properties", "_fold_other_editors", this);
@@ -2967,102 +2636,18 @@ void EditorPropertyResource::update_property() {
memdelete(sub_inspector_vbox);
sub_inspector = nullptr;
sub_inspector_vbox = nullptr;
+
if (opened_editor) {
EditorNode::get_singleton()->hide_top_editors();
opened_editor = false;
}
+
_update_property_bg();
}
}
}
- preview->set_texture(Ref<Texture2D>());
- if (res == RES()) {
- assign->set_icon(Ref<Texture2D>());
- assign->set_text(TTR("[empty]"));
- assign->set_custom_minimum_size(Size2(1, 1));
- } else {
- assign->set_icon(EditorNode::get_singleton()->get_object_icon(res.operator->(), "Object"));
-
- if (res->get_name() != String()) {
- assign->set_text(res->get_name());
- } else if (res->get_path().is_resource_file()) {
- assign->set_text(res->get_path().get_file());
- assign->set_tooltip(res->get_path());
- } else {
- assign->set_text(res->get_class());
- }
-
- if (res->get_path().is_resource_file()) {
- assign->set_tooltip(res->get_path());
- }
-
- //preview will override the above, so called at the end
- EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_resource_preview", res->get_instance_id());
- }
-}
-
-void EditorPropertyResource::_resource_selected() {
- RES res = get_edited_object()->get(get_edited_property());
-
- if (res.is_null()) {
- edit->set_pressed(true);
- _update_menu();
- return;
- }
-
- if (use_sub_inspector) {
- bool unfold = !get_edited_object()->editor_is_section_unfolded(get_edited_property());
- get_edited_object()->editor_set_section_unfold(get_edited_property(), unfold);
- update_property();
- } else {
- emit_signal("resource_selected", get_edited_property(), res);
- }
-}
-
-void EditorPropertyResource::setup(const String &p_base_type) {
- base_type = p_base_type;
-}
-
-void EditorPropertyResource::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- if (updating_theme) {
- return;
- }
- Ref<Texture2D> t = get_theme_icon("select_arrow", "Tree");
- edit->set_icon(t);
- _update_property_bg();
- }
-
- if (p_what == NOTIFICATION_DRAG_BEGIN) {
- if (_is_drop_valid(get_viewport()->gui_get_drag_data())) {
- dropping = true;
- assign->update();
- }
- }
-
- if (p_what == NOTIFICATION_DRAG_END) {
- if (dropping) {
- dropping = false;
- assign->update();
- }
- }
-}
-
-void EditorPropertyResource::_viewport_selected(const NodePath &p_path) {
- Node *to_node = get_node(p_path);
- if (!Object::cast_to<Viewport>(to_node)) {
- EditorNode::get_singleton()->show_warning(TTR("Selected node is not a Viewport!"));
- return;
- }
-
- Ref<ViewportTexture> vt;
- vt.instance();
- vt->set_viewport_path_in_scene(get_tree()->get_edited_scene_root()->get_path_to(to_node));
- vt->setup_local_to_scene();
-
- emit_changed(get_edited_property(), vt);
- update_property();
+ resource_picker->set_edited_resource(res);
}
void EditorPropertyResource::collapse_all_folding() {
@@ -3077,202 +2662,29 @@ void EditorPropertyResource::expand_all_folding() {
}
}
-void EditorPropertyResource::_button_draw() {
- if (dropping) {
- Color color = get_theme_color("accent_color", "Editor");
- assign->draw_rect(Rect2(Point2(), assign->get_size()), color, false);
- }
-}
-
-Variant EditorPropertyResource::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
- RES res = get_edited_object()->get(get_edited_property());
- if (res.is_valid()) {
- return EditorNode::get_singleton()->drag_resource(res, p_from);
- }
-
- return Variant();
-}
-
-bool EditorPropertyResource::_is_drop_valid(const Dictionary &p_drag_data) const {
- Vector<String> allowed_types = base_type.split(",");
- int size = allowed_types.size();
- for (int i = 0; i < size; i++) {
- String at = allowed_types[i].strip_edges();
- if (at == "StandardMaterial3D") {
- allowed_types.append("Texture2D");
- } else if (at == "ShaderMaterial") {
- allowed_types.append("Shader");
- } else if (at == "Font") {
- allowed_types.append("FontData");
- }
- }
-
- Dictionary drag_data = p_drag_data;
-
- Ref<Resource> res;
- if (drag_data.has("type") && String(drag_data["type"]) == "script_list_element") {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(drag_data["script_list_element"]);
- res = se->get_edited_resource();
- } else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
- res = drag_data["resource"];
- }
-
- if (res.is_valid()) {
- for (int i = 0; i < allowed_types.size(); i++) {
- String at = allowed_types[i].strip_edges();
- if (ClassDB::is_parent_class(res->get_class(), at)) {
- return true;
- }
- }
- }
-
- if (drag_data.has("type") && String(drag_data["type"]) == "files") {
- Vector<String> files = drag_data["files"];
-
- if (files.size() == 1) {
- String file = files[0];
- String ftype = EditorFileSystem::get_singleton()->get_file_type(file);
-
- if (ftype != "") {
- for (int i = 0; i < allowed_types.size(); i++) {
- String at = allowed_types[i].strip_edges();
- if (ClassDB::is_parent_class(ftype, at)) {
- return true;
- }
- }
- }
- }
- }
-
- return false;
-}
-
-bool EditorPropertyResource::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
- return _is_drop_valid(p_data);
+void EditorPropertyResource::set_use_sub_inspector(bool p_enable) {
+ use_sub_inspector = p_enable;
}
-void EditorPropertyResource::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
- ERR_FAIL_COND(!_is_drop_valid(p_data));
-
- Dictionary drag_data = p_data;
-
- Ref<Resource> res;
- if (drag_data.has("type") && String(drag_data["type"]) == "script_list_element") {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(drag_data["script_list_element"]);
- res = se->get_edited_resource();
- } else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
- res = drag_data["resource"];
- }
-
- if (!res.is_valid() && drag_data.has("type") && String(drag_data["type"]) == "files") {
- Vector<String> files = drag_data["files"];
-
- if (files.size() == 1) {
- String file = files[0];
- res = ResourceLoader::load(file);
- }
- }
-
- if (res.is_valid()) {
- bool need_convert = true;
-
- Vector<String> allowed_types = base_type.split(",");
- for (int i = 0; i < allowed_types.size(); i++) {
- String at = allowed_types[i].strip_edges();
- if (ClassDB::is_parent_class(res->get_class(), at)) {
- need_convert = false;
- break;
- }
- }
-
- if (need_convert) {
- for (int i = 0; i < allowed_types.size(); i++) {
- String at = allowed_types[i].strip_edges();
- if (at == "StandardMaterial3D" && ClassDB::is_parent_class(res->get_class(), "Texture2D")) {
- Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
- mat->set_texture(StandardMaterial3D::TextureParam::TEXTURE_ALBEDO, res);
- res = mat;
- break;
- }
-
- if (at == "ShaderMaterial" && ClassDB::is_parent_class(res->get_class(), "Shader")) {
- Ref<ShaderMaterial> mat = memnew(ShaderMaterial);
- mat->set_shader(res);
- res = mat;
- break;
- }
-
- if (at == "Font" && ClassDB::is_parent_class(res->get_class(), "FontData")) {
- Ref<Font> font = memnew(Font);
- font->add_data(res);
- res = font;
- break;
- }
+void EditorPropertyResource::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ if (!updating_theme) {
+ _update_property_bg();
}
- }
-
- emit_changed(get_edited_property(), res);
- update_property();
- return;
+ } break;
}
}
-void EditorPropertyResource::set_use_sub_inspector(bool p_enable) {
- use_sub_inspector = p_enable;
-}
-
void EditorPropertyResource::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_resource_preview"), &EditorPropertyResource::_resource_preview);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &EditorPropertyResource::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &EditorPropertyResource::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &EditorPropertyResource::drop_data_fw);
ClassDB::bind_method(D_METHOD("_open_editor_pressed"), &EditorPropertyResource::_open_editor_pressed);
ClassDB::bind_method(D_METHOD("_fold_other_editors"), &EditorPropertyResource::_fold_other_editors);
}
EditorPropertyResource::EditorPropertyResource() {
- opened_editor = false;
- sub_inspector = nullptr;
- sub_inspector_vbox = nullptr;
use_sub_inspector = bool(EDITOR_GET("interface/inspector/open_resources_in_current_inspector"));
- HBoxContainer *hbc = memnew(HBoxContainer);
- add_child(hbc);
- assign = memnew(Button);
- assign->set_flat(true);
- assign->set_h_size_flags(SIZE_EXPAND_FILL);
- assign->set_clip_text(true);
- assign->connect("pressed", callable_mp(this, &EditorPropertyResource::_resource_selected));
- assign->set_drag_forwarding(this);
- assign->connect("draw", callable_mp(this, &EditorPropertyResource::_button_draw));
- hbc->add_child(assign);
- add_focusable(assign);
-
- preview = memnew(TextureRect);
- preview->set_expand(true);
- preview->set_anchors_and_offsets_preset(PRESET_WIDE);
- preview->set_offset(SIDE_TOP, 1);
- preview->set_offset(SIDE_BOTTOM, -1);
- preview->set_offset(SIDE_RIGHT, -1);
- assign->add_child(preview);
- assign->connect("gui_input", callable_mp(this, &EditorPropertyResource::_button_input));
-
- menu = memnew(PopupMenu);
- add_child(menu);
- edit = memnew(Button);
- edit->set_flat(true);
- edit->set_toggle_mode(true);
- menu->connect("id_pressed", callable_mp(this, &EditorPropertyResource::_menu_option));
- menu->connect("popup_hide", callable_mp((BaseButton *)edit, &BaseButton::set_pressed), varray(false));
- edit->connect("pressed", callable_mp(this, &EditorPropertyResource::_update_menu));
- hbc->add_child(edit);
- edit->connect("gui_input", callable_mp(this, &EditorPropertyResource::_button_input));
- add_focusable(edit);
-
- file = nullptr;
- scene_tree = nullptr;
- dropping = false;
-
add_to_group("_editor_resource_properties");
}
@@ -3639,8 +3051,8 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
editor->setup(min, max, step, hide_slider);
add_property_editor(p_path, editor);
} break;
- case Variant::QUAT: {
- EditorPropertyQuat *editor = memnew(EditorPropertyQuat);
+ case Variant::QUATERNION: {
+ EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion);
double min = -65535, max = 65535, step = default_float_step;
bool hide_slider = true;
@@ -3690,8 +3102,8 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
editor->setup(min, max, step, hide_slider);
add_property_editor(p_path, editor);
} break;
- case Variant::TRANSFORM: {
- EditorPropertyTransform *editor = memnew(EditorPropertyTransform);
+ case Variant::TRANSFORM3D: {
+ EditorPropertyTransform3D *editor = memnew(EditorPropertyTransform3D);
double min = -65535, max = 65535, step = default_float_step;
bool hide_slider = true;
@@ -3749,7 +3161,7 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
} break;
case Variant::OBJECT: {
EditorPropertyResource *editor = memnew(EditorPropertyResource);
- editor->setup(p_hint == PROPERTY_HINT_RESOURCE_TYPE ? p_hint_text : "Resource");
+ editor->setup(p_object, p_path, p_hint == PROPERTY_HINT_RESOURCE_TYPE ? p_hint_text : "Resource");
if (p_hint == PROPERTY_HINT_RESOURCE_TYPE) {
String open_in_new = EDITOR_GET("interface/inspector/resources_to_open_in_new_inspector");
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index 07a1e72319..dcde7dda3d 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -33,6 +33,7 @@
#include "editor/create_dialog.h"
#include "editor/editor_inspector.h"
+#include "editor/editor_resource_picker.h"
#include "editor/editor_spin_slider.h"
#include "editor/property_selector.h"
#include "editor/scene_tree_editor.h"
@@ -55,7 +56,7 @@ class EditorPropertyText : public EditorProperty {
bool updating;
bool string_name;
void _text_changed(const String &p_string);
- void _text_entered(const String &p_string);
+ void _text_submitted(const String &p_string);
protected:
static void _bind_methods();
@@ -464,8 +465,8 @@ public:
EditorPropertyPlane(bool p_force_wide = false);
};
-class EditorPropertyQuat : public EditorProperty {
- GDCLASS(EditorPropertyQuat, EditorProperty);
+class EditorPropertyQuaternion : public EditorProperty {
+ GDCLASS(EditorPropertyQuaternion, EditorProperty);
EditorSpinSlider *spin[4];
bool setting;
void _value_changed(double p_val, const String &p_name);
@@ -477,7 +478,7 @@ protected:
public:
virtual void update_property() override;
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
- EditorPropertyQuat();
+ EditorPropertyQuaternion();
};
class EditorPropertyAABB : public EditorProperty {
@@ -528,8 +529,8 @@ public:
EditorPropertyBasis();
};
-class EditorPropertyTransform : public EditorProperty {
- GDCLASS(EditorPropertyTransform, EditorProperty);
+class EditorPropertyTransform3D : public EditorProperty {
+ GDCLASS(EditorPropertyTransform3D, EditorProperty);
EditorSpinSlider *spin[12];
bool setting;
void _value_changed(double p_val, const String &p_name);
@@ -540,9 +541,9 @@ protected:
public:
virtual void update_property() override;
- virtual void update_using_transform(Transform p_transform);
+ virtual void update_using_transform(Transform3D p_transform);
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
- EditorPropertyTransform();
+ EditorPropertyTransform3D();
};
class EditorPropertyColor : public EditorProperty {
@@ -599,64 +600,26 @@ public:
class EditorPropertyResource : public EditorProperty {
GDCLASS(EditorPropertyResource, EditorProperty);
- enum MenuOption {
- OBJ_MENU_LOAD = 0,
- OBJ_MENU_EDIT = 1,
- OBJ_MENU_CLEAR = 2,
- OBJ_MENU_MAKE_UNIQUE = 3,
- OBJ_MENU_SAVE = 4,
- OBJ_MENU_COPY = 5,
- OBJ_MENU_PASTE = 6,
- OBJ_MENU_NEW_SCRIPT = 7,
- OBJ_MENU_EXTEND_SCRIPT = 8,
- OBJ_MENU_SHOW_IN_FILE_SYSTEM = 9,
- TYPE_BASE_ID = 100,
- CONVERT_BASE_ID = 1000
+ EditorResourcePicker *resource_picker = nullptr;
+ SceneTreeDialog *scene_tree = nullptr;
- };
-
- Button *assign;
- TextureRect *preview;
- Button *edit;
- PopupMenu *menu;
- EditorFileDialog *file;
- Vector<String> inheritors_array;
- EditorInspector *sub_inspector;
- VBoxContainer *sub_inspector_vbox;
-
- bool use_sub_inspector;
- bool dropping;
- String base_type;
+ bool use_sub_inspector = false;
+ EditorInspector *sub_inspector = nullptr;
+ VBoxContainer *sub_inspector_vbox = nullptr;
+ bool updating_theme = false;
+ bool opened_editor = false;
- SceneTreeDialog *scene_tree;
+ void _resource_selected(const RES &p_resource);
+ void _resource_changed(const RES &p_resource);
- void _file_selected(const String &p_path);
- void _menu_option(int p_which);
- void _resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj);
- void _resource_selected();
void _viewport_selected(const NodePath &p_path);
- void _update_menu_items();
-
- void _update_menu();
-
void _sub_inspector_property_keyed(const String &p_property, const Variant &p_value, bool);
void _sub_inspector_resource_selected(const RES &p_resource, const String &p_property);
void _sub_inspector_object_id_selected(int p_id);
- void _button_draw();
- Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
- bool _is_drop_valid(const Dictionary &p_drag_data) const;
- bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
- void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
-
- void _button_input(const Ref<InputEvent> &p_event);
void _open_editor_pressed();
void _fold_other_editors(Object *p_self);
-
- bool opened_editor;
-
- bool updating_theme = false;
void _update_property_bg();
protected:
@@ -665,7 +628,7 @@ protected:
public:
virtual void update_property() override;
- void setup(const String &p_base_type);
+ void setup(Object *p_object, const String &p_path, const String &p_base_type);
void collapse_all_folding() override;
void expand_all_folding() override;
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index de688f2709..66fabcd940 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -567,15 +567,14 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint
}
void EditorPropertyArray::_bind_methods() {
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &EditorPropertyArray::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &EditorPropertyArray::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorPropertyArray::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorPropertyArray::drop_data_fw);
}
EditorPropertyArray::EditorPropertyArray() {
object.instance();
page_len = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
edit = memnew(Button);
- edit->set_flat(true);
edit->set_h_size_flags(SIZE_EXPAND_FILL);
edit->set_clip_text(true);
edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_edit_pressed));
@@ -851,8 +850,8 @@ void EditorPropertyDictionary::update_property() {
prop = editor;
} break;
- case Variant::QUAT: {
- EditorPropertyQuat *editor = memnew(EditorPropertyQuat);
+ case Variant::QUATERNION: {
+ EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion);
editor->setup(-100000, 100000, 0.001, true);
prop = editor;
@@ -869,8 +868,8 @@ void EditorPropertyDictionary::update_property() {
prop = editor;
} break;
- case Variant::TRANSFORM: {
- EditorPropertyTransform *editor = memnew(EditorPropertyTransform);
+ case Variant::TRANSFORM3D: {
+ EditorPropertyTransform3D *editor = memnew(EditorPropertyTransform3D);
editor->setup(-100000, 100000, 0.001, true);
prop = editor;
@@ -903,7 +902,7 @@ void EditorPropertyDictionary::update_property() {
} else {
EditorPropertyResource *editor = memnew(EditorPropertyResource);
- editor->setup("Resource");
+ editor->setup(object.ptr(), prop_name, "Resource");
prop = editor;
}
@@ -1070,7 +1069,6 @@ EditorPropertyDictionary::EditorPropertyDictionary() {
object.instance();
page_len = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
edit = memnew(Button);
- edit->set_flat(true);
edit->set_h_size_flags(SIZE_EXPAND_FILL);
edit->set_clip_text(true);
edit->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_edit_pressed));
diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h
index fa5adc788d..aa2d8744b1 100644
--- a/editor/editor_properties_array_dict.h
+++ b/editor/editor_properties_array_dict.h
@@ -36,8 +36,8 @@
#include "editor/filesystem_dock.h"
#include "scene/gui/button.h"
-class EditorPropertyArrayObject : public Reference {
- GDCLASS(EditorPropertyArrayObject, Reference);
+class EditorPropertyArrayObject : public RefCounted {
+ GDCLASS(EditorPropertyArrayObject, RefCounted);
Variant array;
@@ -52,8 +52,8 @@ public:
EditorPropertyArrayObject();
};
-class EditorPropertyDictionaryObject : public Reference {
- GDCLASS(EditorPropertyDictionaryObject, Reference);
+class EditorPropertyDictionaryObject : public RefCounted {
+ GDCLASS(EditorPropertyDictionaryObject, RefCounted);
Variant new_item_key;
Variant new_item_value;
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
new file mode 100644
index 0000000000..1ea8c71f85
--- /dev/null
+++ b/editor/editor_resource_picker.cpp
@@ -0,0 +1,864 @@
+/*************************************************************************/
+/* editor_resource_picker.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_resource_picker.h"
+
+#include "editor/editor_resource_preview.h"
+#include "editor_node.h"
+#include "editor_scale.h"
+#include "editor_settings.h"
+#include "filesystem_dock.h"
+
+void EditorResourcePicker::_update_resource() {
+ preview_rect->set_texture(Ref<Texture2D>());
+ assign_button->set_custom_minimum_size(Size2(1, 1));
+
+ if (edited_resource == RES()) {
+ assign_button->set_icon(Ref<Texture2D>());
+ assign_button->set_text(TTR("[empty]"));
+ } else {
+ assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object"));
+
+ if (edited_resource->get_name() != String()) {
+ assign_button->set_text(edited_resource->get_name());
+ } else if (edited_resource->get_path().is_resource_file()) {
+ assign_button->set_text(edited_resource->get_path().get_file());
+ assign_button->set_tooltip(edited_resource->get_path());
+ } else {
+ assign_button->set_text(edited_resource->get_class());
+ }
+
+ if (edited_resource->get_path().is_resource_file()) {
+ assign_button->set_tooltip(edited_resource->get_path());
+ }
+
+ // Preview will override the above, so called at the end.
+ EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id());
+ }
+}
+
+void EditorResourcePicker::_update_resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj) {
+ if (!edited_resource.is_valid() || edited_resource->get_instance_id() != p_obj) {
+ return;
+ }
+
+ String type = edited_resource->get_class_name();
+ if (ClassDB::is_parent_class(type, "Script")) {
+ assign_button->set_text(edited_resource->get_path().get_file());
+ return;
+ }
+
+ if (p_preview.is_valid()) {
+ preview_rect->set_offset(SIDE_LEFT, assign_button->get_icon()->get_width() + assign_button->get_theme_stylebox("normal")->get_default_margin(SIDE_LEFT) + get_theme_constant("hseparation", "Button"));
+
+ if (type == "GradientTexture") {
+ preview_rect->set_stretch_mode(TextureRect::STRETCH_SCALE);
+ assign_button->set_custom_minimum_size(Size2(1, 1));
+ } else {
+ preview_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
+ int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ thumbnail_size *= EDSCALE;
+ assign_button->set_custom_minimum_size(Size2(1, thumbnail_size));
+ }
+
+ preview_rect->set_texture(p_preview);
+ assign_button->set_text("");
+ }
+}
+
+void EditorResourcePicker::_resource_selected() {
+ if (edited_resource.is_null()) {
+ edit_button->set_pressed(true);
+ _update_menu();
+ return;
+ }
+
+ emit_signal("resource_selected", edited_resource);
+}
+
+void EditorResourcePicker::_file_selected(const String &p_path) {
+ RES loaded_resource = ResourceLoader::load(p_path);
+ ERR_FAIL_COND_MSG(loaded_resource.is_null(), "Cannot load resource from path '" + p_path + "'.");
+
+ if (base_type != "") {
+ bool any_type_matches = false;
+
+ for (int i = 0; i < base_type.get_slice_count(","); i++) {
+ String base = base_type.get_slice(",", i);
+ if (loaded_resource->is_class(base)) {
+ any_type_matches = true;
+ break;
+ }
+ }
+
+ if (!any_type_matches) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("The selected resource (%s) does not match any type expected for this property (%s)."), loaded_resource->get_class(), base_type));
+ return;
+ }
+ }
+
+ edited_resource = loaded_resource;
+ emit_signal("resource_changed", edited_resource);
+ _update_resource();
+}
+
+void EditorResourcePicker::_update_menu() {
+ _update_menu_items();
+
+ Rect2 gt = edit_button->get_screen_rect();
+ edit_menu->set_as_minsize();
+ int ms = edit_menu->get_contents_minimum_size().width;
+ Vector2 popup_pos = gt.position + gt.size - Vector2(ms, 0);
+ edit_menu->set_position(popup_pos);
+ edit_menu->popup();
+}
+
+void EditorResourcePicker::_update_menu_items() {
+ edit_menu->clear();
+
+ // Add options for creating specific subtypes of the base resource type.
+ set_create_options(edit_menu);
+
+ // Add an option to load a resource from a file.
+ edit_menu->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Load"), OBJ_MENU_LOAD);
+
+ // Add options for changing existing value of the resource.
+ if (edited_resource.is_valid()) {
+ edit_menu->add_icon_item(get_theme_icon("Edit", "EditorIcons"), TTR("Edit"), OBJ_MENU_EDIT);
+ edit_menu->add_icon_item(get_theme_icon("Clear", "EditorIcons"), TTR("Clear"), OBJ_MENU_CLEAR);
+ edit_menu->add_icon_item(get_theme_icon("Duplicate", "EditorIcons"), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
+ edit_menu->add_icon_item(get_theme_icon("Save", "EditorIcons"), TTR("Save"), OBJ_MENU_SAVE);
+
+ if (edited_resource->get_path().is_resource_file()) {
+ edit_menu->add_separator();
+ edit_menu->add_item(TTR("Show in FileSystem"), OBJ_MENU_SHOW_IN_FILE_SYSTEM);
+ }
+ }
+
+ // Add options to copy/paste resource.
+ RES cb = EditorSettings::get_singleton()->get_resource_clipboard();
+ bool paste_valid = false;
+ if (cb.is_valid()) {
+ if (base_type == "") {
+ paste_valid = true;
+ } else {
+ for (int i = 0; i < base_type.get_slice_count(","); i++) {
+ if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) {
+ paste_valid = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (edited_resource.is_valid() || paste_valid) {
+ edit_menu->add_separator();
+
+ if (edited_resource.is_valid()) {
+ edit_menu->add_item(TTR("Copy"), OBJ_MENU_COPY);
+ }
+
+ if (paste_valid) {
+ edit_menu->add_item(TTR("Paste"), OBJ_MENU_PASTE);
+ }
+ }
+
+ // Add options to convert existing resource to another type of resource.
+ if (edited_resource.is_valid()) {
+ Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(edited_resource);
+ if (conversions.size()) {
+ edit_menu->add_separator();
+ }
+ for (int i = 0; i < conversions.size(); i++) {
+ String what = conversions[i]->converts_to();
+ Ref<Texture2D> icon;
+ if (has_theme_icon(what, "EditorIcons")) {
+ icon = get_theme_icon(what, "EditorIcons");
+ } else {
+ icon = get_theme_icon(what, "Resource");
+ }
+
+ edit_menu->add_icon_item(icon, vformat(TTR("Convert To %s"), what), CONVERT_BASE_ID + i);
+ }
+ }
+}
+
+void EditorResourcePicker::_edit_menu_cbk(int p_which) {
+ switch (p_which) {
+ case OBJ_MENU_LOAD: {
+ List<String> extensions;
+ for (int i = 0; i < base_type.get_slice_count(","); i++) {
+ String base = base_type.get_slice(",", i);
+ ResourceLoader::get_recognized_extensions_for_type(base, &extensions);
+ }
+
+ Set<String> valid_extensions;
+ for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
+ valid_extensions.insert(E->get());
+ }
+
+ if (!file_dialog) {
+ file_dialog = memnew(EditorFileDialog);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
+ add_child(file_dialog);
+ file_dialog->connect("file_selected", callable_mp(this, &EditorResourcePicker::_file_selected));
+ }
+
+ file_dialog->clear_filters();
+ for (Set<String>::Element *E = valid_extensions.front(); E; E = E->next()) {
+ file_dialog->add_filter("*." + E->get() + " ; " + E->get().to_upper());
+ }
+
+ file_dialog->popup_file_dialog();
+ } break;
+
+ case OBJ_MENU_EDIT: {
+ if (edited_resource.is_valid()) {
+ emit_signal("resource_selected", edited_resource);
+ }
+ } break;
+
+ case OBJ_MENU_CLEAR: {
+ edited_resource = RES();
+ emit_signal("resource_changed", edited_resource);
+ _update_resource();
+ } break;
+
+ case OBJ_MENU_MAKE_UNIQUE: {
+ if (edited_resource.is_null()) {
+ return;
+ }
+
+ List<PropertyInfo> property_list;
+ edited_resource->get_property_list(&property_list);
+ List<Pair<String, Variant>> propvalues;
+ for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
+ Pair<String, Variant> p;
+ PropertyInfo &pi = E->get();
+ if (pi.usage & PROPERTY_USAGE_STORAGE) {
+ p.first = pi.name;
+ p.second = edited_resource->get(pi.name);
+ }
+
+ propvalues.push_back(p);
+ }
+
+ String orig_type = edited_resource->get_class();
+ Object *inst = ClassDB::instance(orig_type);
+ Ref<Resource> unique_resource = Ref<Resource>(Object::cast_to<Resource>(inst));
+ ERR_FAIL_COND(unique_resource.is_null());
+
+ for (List<Pair<String, Variant>>::Element *E = propvalues.front(); E; E = E->next()) {
+ Pair<String, Variant> &p = E->get();
+ unique_resource->set(p.first, p.second);
+ }
+
+ edited_resource = unique_resource;
+ emit_signal("resource_changed", edited_resource);
+ _update_resource();
+ } break;
+
+ case OBJ_MENU_SAVE: {
+ if (edited_resource.is_null()) {
+ return;
+ }
+ EditorNode::get_singleton()->save_resource(edited_resource);
+ } break;
+
+ case OBJ_MENU_COPY: {
+ EditorSettings::get_singleton()->set_resource_clipboard(edited_resource);
+ } break;
+
+ case OBJ_MENU_PASTE: {
+ edited_resource = EditorSettings::get_singleton()->get_resource_clipboard();
+ emit_signal("resource_changed", edited_resource);
+ _update_resource();
+ } break;
+
+ case OBJ_MENU_SHOW_IN_FILE_SYSTEM: {
+ FileSystemDock *file_system_dock = EditorNode::get_singleton()->get_filesystem_dock();
+ file_system_dock->navigate_to_path(edited_resource->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_index());
+ } break;
+
+ default: {
+ // Allow subclasses to handle their own options first, only then fallback on the default branch logic.
+ if (handle_menu_selected(p_which)) {
+ break;
+ }
+
+ if (p_which >= CONVERT_BASE_ID) {
+ int to_type = p_which - CONVERT_BASE_ID;
+ Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(edited_resource);
+ ERR_FAIL_INDEX(to_type, conversions.size());
+
+ edited_resource = conversions[to_type]->convert(edited_resource);
+ emit_signal("resource_changed", edited_resource);
+ _update_resource();
+ break;
+ }
+
+ ERR_FAIL_COND(inheritors_array.is_empty());
+
+ String intype = inheritors_array[p_which - TYPE_BASE_ID];
+ Variant obj;
+
+ if (ScriptServer::is_global_class(intype)) {
+ obj = ClassDB::instance(ScriptServer::get_global_class_native_base(intype));
+ if (obj) {
+ Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(intype));
+ if (script.is_valid()) {
+ ((Object *)obj)->set_script(script);
+ }
+ }
+ } else {
+ obj = ClassDB::instance(intype);
+ }
+
+ if (!obj) {
+ obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
+ }
+
+ Resource *resp = Object::cast_to<Resource>(obj);
+ ERR_BREAK(!resp);
+
+ edited_resource = RES(resp);
+ emit_signal("resource_changed", edited_resource);
+ _update_resource();
+ } break;
+ }
+}
+
+void EditorResourcePicker::set_create_options(Object *p_menu_node) {
+ // If a subclass implements this method, use it to replace all create items.
+ if (get_script_instance() && get_script_instance()->has_method("_set_create_options")) {
+ get_script_instance()->call("_set_create_options", p_menu_node);
+ return;
+ }
+
+ // By default provide generic "New ..." options.
+ if (base_type != "") {
+ int idx = 0;
+
+ Set<String> allowed_types;
+ _get_allowed_types(false, &allowed_types);
+
+ Vector<EditorData::CustomType> custom_resources;
+ if (EditorNode::get_editor_data().get_custom_types().has("Resource")) {
+ custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"];
+ }
+
+ for (Set<String>::Element *E = allowed_types.front(); E; E = E->next()) {
+ const String &t = E->get();
+
+ bool is_custom_resource = false;
+ Ref<Texture2D> icon;
+ if (!custom_resources.is_empty()) {
+ for (int j = 0; j < custom_resources.size(); j++) {
+ if (custom_resources[j].name == t) {
+ is_custom_resource = true;
+ if (custom_resources[j].icon.is_valid()) {
+ icon = custom_resources[j].icon;
+ }
+ break;
+ }
+ }
+ }
+
+ if (!is_custom_resource && !(ScriptServer::is_global_class(t) || ClassDB::can_instance(t))) {
+ continue;
+ }
+
+ inheritors_array.push_back(t);
+
+ if (!icon.is_valid()) {
+ icon = get_theme_icon(has_theme_icon(t, "EditorIcons") ? t : "Object", "EditorIcons");
+ }
+
+ int id = TYPE_BASE_ID + idx;
+ edit_menu->add_icon_item(icon, vformat(TTR("New %s"), t), id);
+
+ idx++;
+ }
+
+ if (edit_menu->get_item_count()) {
+ edit_menu->add_separator();
+ }
+ }
+}
+
+bool EditorResourcePicker::handle_menu_selected(int p_which) {
+ if (get_script_instance() && get_script_instance()->has_method("_handle_menu_selected")) {
+ return get_script_instance()->call("_handle_menu_selected", p_which);
+ }
+
+ return false;
+}
+
+void EditorResourcePicker::_button_draw() {
+ if (dropping) {
+ Color color = get_theme_color("accent_color", "Editor");
+ assign_button->draw_rect(Rect2(Point2(), assign_button->get_size()), color, false);
+ }
+}
+
+void EditorResourcePicker::_button_input(const Ref<InputEvent> &p_event) {
+ if (!editable) {
+ return;
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid()) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ _update_menu_items();
+
+ Vector2 pos = get_screen_position() + mb->get_position();
+ edit_menu->set_as_minsize();
+ edit_menu->set_position(pos);
+ edit_menu->popup();
+ }
+ }
+}
+
+void EditorResourcePicker::_get_allowed_types(bool p_with_convert, Set<String> *p_vector) const {
+ Vector<String> allowed_types = base_type.split(",");
+ int size = allowed_types.size();
+
+ List<StringName> global_classes;
+ ScriptServer::get_global_class_list(&global_classes);
+
+ for (int i = 0; i < size; i++) {
+ String base = allowed_types[i].strip_edges();
+ p_vector->insert(base);
+
+ List<StringName> inheriters;
+
+ ClassDB::get_inheriters_from_class(base, &inheriters);
+ for (List<StringName>::Element *E = inheriters.front(); E; E = E->next()) {
+ p_vector->insert(E->get());
+ }
+
+ for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) {
+ if (EditorNode::get_editor_data().script_class_is_parent(E->get(), base)) {
+ p_vector->insert(E->get());
+ }
+ }
+
+ if (p_with_convert) {
+ if (base == "StandardMaterial3D") {
+ p_vector->insert("Texture2D");
+ } else if (base == "ShaderMaterial") {
+ p_vector->insert("Shader");
+ } else if (base == "Font") {
+ p_vector->insert("FontData");
+ }
+ }
+ }
+
+ if (EditorNode::get_editor_data().get_custom_types().has("Resource")) {
+ Vector<EditorData::CustomType> custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"];
+
+ for (int i = 0; i < custom_resources.size(); i++) {
+ p_vector->insert(custom_resources[i].name);
+ }
+ }
+}
+
+bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const {
+ if (base_type.is_empty()) {
+ return true;
+ }
+
+ Dictionary drag_data = p_drag_data;
+
+ Ref<Resource> res;
+ if (drag_data.has("type") && String(drag_data["type"]) == "script_list_element") {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(drag_data["script_list_element"]);
+ res = se->get_edited_resource();
+ } else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
+ res = drag_data["resource"];
+ }
+
+ Set<String> allowed_types;
+ _get_allowed_types(true, &allowed_types);
+
+ if (res.is_valid() && _is_type_valid(res->get_class(), allowed_types)) {
+ return true;
+ }
+
+ if (res.is_valid() && res->get_script()) {
+ StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res->get_script());
+ if (_is_type_valid(custom_class, allowed_types)) {
+ return true;
+ }
+ }
+
+ if (drag_data.has("type") && String(drag_data["type"]) == "files") {
+ Vector<String> files = drag_data["files"];
+
+ if (files.size() == 1) {
+ String file = files[0];
+
+ String file_type = EditorFileSystem::get_singleton()->get_file_type(file);
+ if (file_type != "" && _is_type_valid(file_type, allowed_types)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool EditorResourcePicker::_is_type_valid(const String p_type_name, Set<String> p_allowed_types) const {
+ for (Set<String>::Element *E = p_allowed_types.front(); E; E = E->next()) {
+ String at = E->get().strip_edges();
+ if (p_type_name == at || ClassDB::is_parent_class(p_type_name, at) || EditorNode::get_editor_data().script_class_is_parent(p_type_name, at)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Variant EditorResourcePicker::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ if (edited_resource.is_valid()) {
+ return EditorNode::get_singleton()->drag_resource(edited_resource, p_from);
+ }
+
+ return Variant();
+}
+
+bool EditorResourcePicker::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ return editable && _is_drop_valid(p_data);
+}
+
+void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ ERR_FAIL_COND(!_is_drop_valid(p_data));
+
+ Dictionary drag_data = p_data;
+
+ Ref<Resource> dropped_resource;
+ if (drag_data.has("type") && String(drag_data["type"]) == "script_list_element") {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(drag_data["script_list_element"]);
+ dropped_resource = se->get_edited_resource();
+ } else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
+ dropped_resource = drag_data["resource"];
+ }
+
+ if (!dropped_resource.is_valid() && drag_data.has("type") && String(drag_data["type"]) == "files") {
+ Vector<String> files = drag_data["files"];
+
+ if (files.size() == 1) {
+ String file = files[0];
+ dropped_resource = ResourceLoader::load(file);
+ }
+ }
+
+ if (dropped_resource.is_valid()) {
+ Set<String> allowed_types;
+ _get_allowed_types(false, &allowed_types);
+
+ // If the accepted dropped resource is from the extended list, it requires conversion.
+ if (!_is_type_valid(dropped_resource->get_class(), allowed_types)) {
+ for (Set<String>::Element *E = allowed_types.front(); E; E = E->next()) {
+ String at = E->get().strip_edges();
+
+ if (at == "StandardMaterial3D" && ClassDB::is_parent_class(dropped_resource->get_class(), "Texture2D")) {
+ Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
+ mat->set_texture(StandardMaterial3D::TextureParam::TEXTURE_ALBEDO, dropped_resource);
+ dropped_resource = mat;
+ break;
+ }
+
+ if (at == "ShaderMaterial" && ClassDB::is_parent_class(dropped_resource->get_class(), "Shader")) {
+ Ref<ShaderMaterial> mat = memnew(ShaderMaterial);
+ mat->set_shader(dropped_resource);
+ dropped_resource = mat;
+ break;
+ }
+
+ if (at == "Font" && ClassDB::is_parent_class(dropped_resource->get_class(), "FontData")) {
+ Ref<Font> font = memnew(Font);
+ font->add_data(dropped_resource);
+ dropped_resource = font;
+ break;
+ }
+ }
+ }
+
+ edited_resource = dropped_resource;
+ emit_signal("resource_changed", edited_resource);
+ _update_resource();
+ }
+}
+
+void EditorResourcePicker::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_resource_preview"), &EditorResourcePicker::_update_resource_preview);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "position", "from"), &EditorResourcePicker::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::drop_data_fw);
+
+ ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &EditorResourcePicker::set_base_type);
+ ClassDB::bind_method(D_METHOD("get_base_type"), &EditorResourcePicker::get_base_type);
+ ClassDB::bind_method(D_METHOD("get_allowed_types"), &EditorResourcePicker::get_allowed_types);
+ ClassDB::bind_method(D_METHOD("set_edited_resource", "resource"), &EditorResourcePicker::set_edited_resource);
+ ClassDB::bind_method(D_METHOD("get_edited_resource"), &EditorResourcePicker::get_edited_resource);
+ ClassDB::bind_method(D_METHOD("set_toggle_mode", "enable"), &EditorResourcePicker::set_toggle_mode);
+ ClassDB::bind_method(D_METHOD("is_toggle_mode"), &EditorResourcePicker::is_toggle_mode);
+ ClassDB::bind_method(D_METHOD("set_toggle_pressed", "pressed"), &EditorResourcePicker::set_toggle_pressed);
+ ClassDB::bind_method(D_METHOD("set_editable", "enable"), &EditorResourcePicker::set_editable);
+ ClassDB::bind_method(D_METHOD("is_editable"), &EditorResourcePicker::is_editable);
+
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_set_create_options", PropertyInfo(Variant::OBJECT, "menu_node")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_handle_menu_selected", PropertyInfo(Variant::INT, "id")));
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type"), "set_base_type", "get_base_type");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource", 0), "set_edited_resource", "get_edited_resource");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toggle_mode"), "set_toggle_mode", "is_toggle_mode");
+
+ ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
+ ADD_SIGNAL(MethodInfo("resource_changed", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
+}
+
+void EditorResourcePicker::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ _update_resource();
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ edit_button->set_icon(get_theme_icon("select_arrow", "Tree"));
+ } break;
+
+ case NOTIFICATION_DRAW: {
+ draw_style_box(get_theme_stylebox("bg", "Tree"), Rect2(Point2(), get_size()));
+ } break;
+
+ case NOTIFICATION_DRAG_BEGIN: {
+ if (editable && _is_drop_valid(get_viewport()->gui_get_drag_data())) {
+ dropping = true;
+ assign_button->update();
+ }
+ } break;
+
+ case NOTIFICATION_DRAG_END: {
+ if (dropping) {
+ dropping = false;
+ assign_button->update();
+ }
+ } break;
+ }
+}
+
+void EditorResourcePicker::set_base_type(const String &p_base_type) {
+ base_type = p_base_type;
+
+ // There is a possibility that the new base type is conflicting with the existing value.
+ // Keep the value, but warn the user that there is a potential mistake.
+ if (!base_type.is_empty() && edited_resource.is_valid()) {
+ Set<String> allowed_types;
+ _get_allowed_types(true, &allowed_types);
+
+ StringName custom_class;
+ bool is_custom = false;
+ if (edited_resource->get_script()) {
+ custom_class = EditorNode::get_singleton()->get_object_custom_type_name(edited_resource->get_script());
+ is_custom = _is_type_valid(custom_class, allowed_types);
+ }
+
+ if (!is_custom && !_is_type_valid(edited_resource->get_class(), allowed_types)) {
+ String class_str = (custom_class == StringName() ? edited_resource->get_class() : vformat("%s (%s)", custom_class, edited_resource->get_class()));
+ WARN_PRINT(vformat("Value mismatch between the new base type of this EditorResourcePicker, '%s', and the type of the value it already has, '%s'.", base_type, class_str));
+ }
+ }
+}
+
+String EditorResourcePicker::get_base_type() const {
+ return base_type;
+}
+
+Vector<String> EditorResourcePicker::get_allowed_types() const {
+ Set<String> allowed_types;
+ _get_allowed_types(false, &allowed_types);
+
+ Vector<String> types;
+ types.resize(allowed_types.size());
+
+ int i = 0;
+ String *w = types.ptrw();
+ for (Set<String>::Element *E = allowed_types.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+
+ return types;
+}
+
+void EditorResourcePicker::set_edited_resource(RES p_resource) {
+ if (!p_resource.is_valid()) {
+ edited_resource = RES();
+ _update_resource();
+ return;
+ }
+
+ if (!base_type.is_empty()) {
+ Set<String> allowed_types;
+ _get_allowed_types(true, &allowed_types);
+
+ StringName custom_class;
+ bool is_custom = false;
+ if (p_resource->get_script()) {
+ custom_class = EditorNode::get_singleton()->get_object_custom_type_name(p_resource->get_script());
+ is_custom = _is_type_valid(custom_class, allowed_types);
+ }
+
+ if (!is_custom && !_is_type_valid(p_resource->get_class(), allowed_types)) {
+ String class_str = (custom_class == StringName() ? p_resource->get_class() : vformat("%s (%s)", custom_class, p_resource->get_class()));
+ ERR_FAIL_MSG(vformat("Failed to set a resource of the type '%s' because this EditorResourcePicker only accepts '%s' and its derivatives.", class_str, base_type));
+ }
+ }
+
+ edited_resource = p_resource;
+ _update_resource();
+}
+
+RES EditorResourcePicker::get_edited_resource() {
+ return edited_resource;
+}
+
+void EditorResourcePicker::set_toggle_mode(bool p_enable) {
+ assign_button->set_toggle_mode(p_enable);
+}
+
+bool EditorResourcePicker::is_toggle_mode() const {
+ return assign_button->is_toggle_mode();
+}
+
+void EditorResourcePicker::set_toggle_pressed(bool p_pressed) {
+ if (!is_toggle_mode()) {
+ return;
+ }
+
+ assign_button->set_pressed(p_pressed);
+}
+
+void EditorResourcePicker::set_editable(bool p_editable) {
+ editable = p_editable;
+ assign_button->set_disabled(!editable);
+ edit_button->set_visible(editable);
+}
+
+bool EditorResourcePicker::is_editable() const {
+ return editable;
+}
+
+EditorResourcePicker::EditorResourcePicker() {
+ assign_button = memnew(Button);
+ assign_button->set_flat(true);
+ assign_button->set_h_size_flags(SIZE_EXPAND_FILL);
+ assign_button->set_clip_text(true);
+ assign_button->set_drag_forwarding(this);
+ add_child(assign_button);
+ assign_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_resource_selected));
+ assign_button->connect("draw", callable_mp(this, &EditorResourcePicker::_button_draw));
+ assign_button->connect("gui_input", callable_mp(this, &EditorResourcePicker::_button_input));
+
+ preview_rect = memnew(TextureRect);
+ preview_rect->set_expand(true);
+ preview_rect->set_anchors_and_offsets_preset(PRESET_WIDE);
+ preview_rect->set_offset(SIDE_TOP, 1);
+ preview_rect->set_offset(SIDE_BOTTOM, -1);
+ preview_rect->set_offset(SIDE_RIGHT, -1);
+ assign_button->add_child(preview_rect);
+
+ edit_button = memnew(Button);
+ edit_button->set_flat(true);
+ edit_button->set_toggle_mode(true);
+ edit_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_update_menu));
+ add_child(edit_button);
+ edit_button->connect("gui_input", callable_mp(this, &EditorResourcePicker::_button_input));
+ edit_menu = memnew(PopupMenu);
+ add_child(edit_menu);
+ edit_menu->connect("id_pressed", callable_mp(this, &EditorResourcePicker::_edit_menu_cbk));
+ edit_menu->connect("popup_hide", callable_mp((BaseButton *)edit_button, &BaseButton::set_pressed), varray(false));
+}
+
+void EditorScriptPicker::set_create_options(Object *p_menu_node) {
+ PopupMenu *menu_node = Object::cast_to<PopupMenu>(p_menu_node);
+ if (!menu_node) {
+ return;
+ }
+
+ menu_node->add_icon_item(get_theme_icon("ScriptCreate", "EditorIcons"), TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
+ menu_node->add_icon_item(get_theme_icon("ScriptExtend", "EditorIcons"), TTR("Extend Script"), OBJ_MENU_EXTEND_SCRIPT);
+ menu_node->add_separator();
+}
+
+bool EditorScriptPicker::handle_menu_selected(int p_which) {
+ switch (p_which) {
+ case OBJ_MENU_NEW_SCRIPT: {
+ if (script_owner) {
+ EditorNode::get_singleton()->get_scene_tree_dock()->open_script_dialog(script_owner, false);
+ }
+ return true;
+ }
+
+ case OBJ_MENU_EXTEND_SCRIPT: {
+ if (script_owner) {
+ EditorNode::get_singleton()->get_scene_tree_dock()->open_script_dialog(script_owner, true);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void EditorScriptPicker::set_script_owner(Node *p_owner) {
+ script_owner = p_owner;
+}
+
+Node *EditorScriptPicker::get_script_owner() const {
+ return script_owner;
+}
+
+void EditorScriptPicker::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_script_owner", "owner_node"), &EditorScriptPicker::set_script_owner);
+ ClassDB::bind_method(D_METHOD("get_script_owner"), &EditorScriptPicker::get_script_owner);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "script_owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_script_owner", "get_script_owner");
+}
+
+EditorScriptPicker::EditorScriptPicker() {
+}
diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h
new file mode 100644
index 0000000000..9a4b945bc7
--- /dev/null
+++ b/editor/editor_resource_picker.h
@@ -0,0 +1,141 @@
+/*************************************************************************/
+/* editor_resource_picker.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_RESOURCE_PICKER_H
+#define EDITOR_RESOURCE_PICKER_H
+
+#include "editor_file_dialog.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/popup_menu.h"
+#include "scene/gui/texture_rect.h"
+
+class EditorResourcePicker : public HBoxContainer {
+ GDCLASS(EditorResourcePicker, HBoxContainer);
+
+ String base_type;
+ RES edited_resource;
+
+ bool editable = true;
+ bool dropping = false;
+
+ Vector<String> inheritors_array;
+
+ Button *assign_button;
+ TextureRect *preview_rect;
+ Button *edit_button;
+ EditorFileDialog *file_dialog = nullptr;
+
+ enum MenuOption {
+ OBJ_MENU_LOAD,
+ OBJ_MENU_EDIT,
+ OBJ_MENU_CLEAR,
+ OBJ_MENU_MAKE_UNIQUE,
+ OBJ_MENU_SAVE,
+ OBJ_MENU_COPY,
+ OBJ_MENU_PASTE,
+ OBJ_MENU_SHOW_IN_FILE_SYSTEM,
+
+ TYPE_BASE_ID = 100,
+ CONVERT_BASE_ID = 1000,
+ };
+
+ PopupMenu *edit_menu;
+
+ void _update_resource();
+ void _update_resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj);
+
+ void _resource_selected();
+ void _file_selected(const String &p_path);
+
+ void _update_menu();
+ void _update_menu_items();
+ void _edit_menu_cbk(int p_which);
+
+ void _button_draw();
+ void _button_input(const Ref<InputEvent> &p_event);
+
+ void _get_allowed_types(bool p_with_convert, Set<String> *p_vector) const;
+ bool _is_drop_valid(const Dictionary &p_drag_data) const;
+ bool _is_type_valid(const String p_type_name, Set<String> p_allowed_types) const;
+
+ Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
+ bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ void set_base_type(const String &p_base_type);
+ String get_base_type() const;
+ Vector<String> get_allowed_types() const;
+
+ void set_edited_resource(RES p_resource);
+ RES get_edited_resource();
+
+ void set_toggle_mode(bool p_enable);
+ bool is_toggle_mode() const;
+ void set_toggle_pressed(bool p_pressed);
+
+ void set_editable(bool p_editable);
+ bool is_editable() const;
+
+ virtual void set_create_options(Object *p_menu_node);
+ virtual bool handle_menu_selected(int p_which);
+
+ EditorResourcePicker();
+};
+
+class EditorScriptPicker : public EditorResourcePicker {
+ GDCLASS(EditorScriptPicker, EditorResourcePicker);
+
+ enum ExtraMenuOption {
+ OBJ_MENU_NEW_SCRIPT = 10,
+ OBJ_MENU_EXTEND_SCRIPT = 11
+ };
+
+ Node *script_owner = nullptr;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual void set_create_options(Object *p_menu_node) override;
+ virtual bool handle_menu_selected(int p_which) override;
+
+ void set_script_owner(Node *p_owner);
+ Node *get_script_owner() const;
+
+ EditorScriptPicker();
+};
+
+#endif // EDITOR_RESOURCE_PICKER_H
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 138830cdc6..0f1b70936a 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -31,31 +31,31 @@
#include "editor_resource_preview.h"
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/object/message_queue.h"
-#include "core/os/file_access.h"
#include "editor_node.h"
#include "editor_scale.h"
#include "editor_settings.h"
bool EditorResourcePreviewGenerator::handles(const String &p_type) const {
- if (get_script_instance() && get_script_instance()->has_method("handles")) {
- return get_script_instance()->call("handles", p_type);
+ if (get_script_instance() && get_script_instance()->has_method("_handles")) {
+ return get_script_instance()->call("_handles", p_type);
}
- ERR_FAIL_V_MSG(false, "EditorResourcePreviewGenerator::handles needs to be overridden.");
+ ERR_FAIL_V_MSG(false, "EditorResourcePreviewGenerator::_handles needs to be overridden.");
}
Ref<Texture2D> EditorResourcePreviewGenerator::generate(const RES &p_from, const Size2 &p_size) const {
- if (get_script_instance() && get_script_instance()->has_method("generate")) {
- return get_script_instance()->call("generate", p_from, p_size);
+ if (get_script_instance() && get_script_instance()->has_method("_generate")) {
+ return get_script_instance()->call("_generate", p_from, p_size);
}
- ERR_FAIL_V_MSG(Ref<Texture2D>(), "EditorResourcePreviewGenerator::generate needs to be overridden.");
+ ERR_FAIL_V_MSG(Ref<Texture2D>(), "EditorResourcePreviewGenerator::_generate needs to be overridden.");
}
Ref<Texture2D> EditorResourcePreviewGenerator::generate_from_path(const String &p_path, const Size2 &p_size) const {
- if (get_script_instance() && get_script_instance()->has_method("generate_from_path")) {
- return get_script_instance()->call("generate_from_path", p_path, p_size);
+ if (get_script_instance() && get_script_instance()->has_method("_generate_from_path")) {
+ return get_script_instance()->call("_generate_from_path", p_path, p_size);
}
RES res = ResourceLoader::load(p_path);
@@ -66,27 +66,27 @@ Ref<Texture2D> EditorResourcePreviewGenerator::generate_from_path(const String &
}
bool EditorResourcePreviewGenerator::generate_small_preview_automatically() const {
- if (get_script_instance() && get_script_instance()->has_method("generate_small_preview_automatically")) {
- return get_script_instance()->call("generate_small_preview_automatically");
+ if (get_script_instance() && get_script_instance()->has_method("_generate_small_preview_automatically")) {
+ return get_script_instance()->call("_generate_small_preview_automatically");
}
return false;
}
bool EditorResourcePreviewGenerator::can_generate_small_preview() const {
- if (get_script_instance() && get_script_instance()->has_method("can_generate_small_preview")) {
- return get_script_instance()->call("can_generate_small_preview");
+ if (get_script_instance() && get_script_instance()->has_method("_can_generate_small_preview")) {
+ return get_script_instance()->call("_can_generate_small_preview");
}
return false;
}
void EditorResourcePreviewGenerator::_bind_methods() {
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles", PropertyInfo(Variant::STRING, "type")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture2D), "generate", PropertyInfo(Variant::OBJECT, "from", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::VECTOR2, "size")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture2D), "generate_from_path", PropertyInfo(Variant::STRING, "path", PROPERTY_HINT_FILE), PropertyInfo(Variant::VECTOR2, "size")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "generate_small_preview_automatically"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "can_generate_small_preview"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_handles", PropertyInfo(Variant::STRING, "type")));
+ BIND_VMETHOD(MethodInfo(CLASS_INFO(Texture2D), "_generate", PropertyInfo(Variant::OBJECT, "from", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::VECTOR2, "size")));
+ BIND_VMETHOD(MethodInfo(CLASS_INFO(Texture2D), "_generate_from_path", PropertyInfo(Variant::STRING, "path", PROPERTY_HINT_FILE), PropertyInfo(Variant::VECTOR2, "size")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_generate_small_preview_automatically"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_can_generate_small_preview"));
}
EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() {
@@ -241,7 +241,7 @@ void EditorResourcePreview::_thread() {
_preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
} else {
- String temp_path = EditorSettings::get_singleton()->get_cache_dir();
+ String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
cache_base = temp_path.plus_file("resthumb-" + cache_base);
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index c4e796dcf1..67f83220d0 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -37,8 +37,8 @@
#include "scene/main/node.h"
#include "scene/resources/texture.h"
-class EditorResourcePreviewGenerator : public Reference {
- GDCLASS(EditorResourcePreviewGenerator, Reference);
+class EditorResourcePreviewGenerator : public RefCounted {
+ GDCLASS(EditorResourcePreviewGenerator, RefCounted);
protected:
static void _bind_methods();
@@ -101,7 +101,8 @@ protected:
public:
static EditorResourcePreview *get_singleton();
- //callback function is callback(String p_path,Ref<Texture2D> preview,Variant udata) preview null if could not load
+ // p_receiver_func callback has signature (String p_path, Ref<Texture2D> p_preview, Ref<Texture2D> p_preview_small, Variant p_userdata)
+ // p_preview will be null if there was an error
void queue_resource_preview(const String &p_path, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata);
void queue_edited_resource_preview(const Ref<Resource> &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata);
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index e46f4eb65a..5e6d2ab69c 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -183,15 +183,50 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
args.push_back(p_scene);
}
+ String exec = OS::get_singleton()->get_executable_path();
+
if (p_custom_args != "") {
- Vector<String> cargs = p_custom_args.split(" ", false);
- for (int i = 0; i < cargs.size(); i++) {
- args.push_back(cargs[i].replace(" ", "%20"));
+ // Allow the user to specify a command to run, similar to Steam's launch options.
+ // In this case, Godot will no longer be run directly; it's up to the underlying command
+ // to run it. For instance, this can be used on Linux to force a running project
+ // to use Optimus using `prime-run` or similar.
+ // Example: `prime-run %command% --time-scale 0.5`
+ const int placeholder_pos = p_custom_args.find("%command%");
+
+ Vector<String> custom_args;
+
+ if (placeholder_pos != -1) {
+ // Prepend executable-specific custom arguments.
+ // If nothing is placed before `%command%`, behave as if no placeholder was specified.
+ Vector<String> exec_args = p_custom_args.substr(0, placeholder_pos).split(" ", false);
+ if (exec_args.size() >= 1) {
+ exec = exec_args[0];
+ exec_args.remove(0);
+
+ // Append the Godot executable name before we append executable arguments
+ // (since the order is reversed when using `push_front()`).
+ args.push_front(OS::get_singleton()->get_executable_path());
+ }
+
+ for (int i = exec_args.size() - 1; i >= 0; i--) {
+ // Iterate backwards as we're pushing items in the reverse order.
+ args.push_front(exec_args[i].replace(" ", "%20"));
+ }
+
+ // Append Godot-specific custom arguments.
+ custom_args = p_custom_args.substr(placeholder_pos + String("%command%").size()).split(" ", false);
+ for (int i = 0; i < custom_args.size(); i++) {
+ args.push_back(custom_args[i].replace(" ", "%20"));
+ }
+ } else {
+ // Append Godot-specific custom arguments.
+ custom_args = p_custom_args.split(" ", false);
+ for (int i = 0; i < custom_args.size(); i++) {
+ args.push_back(custom_args[i].replace(" ", "%20"));
+ }
}
}
- String exec = OS::get_singleton()->get_executable_path();
-
printf("Running: %s", exec.utf8().get_data());
for (List<String>::Element *E = args.front(); E; E = E->next()) {
printf(" %s", E->get().utf8().get_data());
diff --git a/editor/editor_run_script.h b/editor/editor_run_script.h
index 83987ecba1..c8412c3c92 100644
--- a/editor/editor_run_script.h
+++ b/editor/editor_run_script.h
@@ -31,11 +31,11 @@
#ifndef EDITOR_RUN_SCRIPT_H
#define EDITOR_RUN_SCRIPT_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "editor_plugin.h"
class EditorNode;
-class EditorScript : public Reference {
- GDCLASS(EditorScript, Reference);
+class EditorScript : public RefCounted {
+ GDCLASS(EditorScript, RefCounted);
EditorNode *editor;
diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp
index f81c87be9e..6bfb17f9c2 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -135,7 +135,7 @@ void SectionedInspector::_section_selected() {
}
selected_category = sections->get_selected()->get_metadata(0);
- filter->set_section(selected_category, sections->get_selected()->get_children() == nullptr);
+ filter->set_section(selected_category, sections->get_selected()->get_first_child() == nullptr);
inspector->set_property_prefix(selected_category + "/");
}
@@ -187,8 +187,8 @@ void SectionedInspector::edit(Object *p_object) {
TreeItem *first_item = sections->get_root();
if (first_item) {
- while (first_item->get_children()) {
- first_item = first_item->get_children();
+ while (first_item->get_first_child()) {
+ first_item = first_item->get_first_child();
}
first_item->select(0);
@@ -250,7 +250,8 @@ void SectionedInspector::update_category_list() {
for (int i = 0; i < sc; i++) {
TreeItem *parent = section_map[metasection];
- parent->set_custom_bg_color(0, get_theme_color("prop_subsection", "Editor"));
+ //parent->set_custom_bg_color(0, get_theme_color("prop_subsection", "Editor"));
+ parent->set_custom_font(0, get_theme_font("bold", "EditorFonts"));
if (i > 0) {
metasection += "/" + sectionarr[i];
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 4ddae7c062..df269606ad 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -35,13 +35,13 @@
#include "core/io/certs_compressed.gen.h"
#include "core/io/compression.h"
#include "core/io/config_file.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_memory.h"
#include "core/io/ip.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/io/translation_loader_po.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/version.h"
@@ -373,28 +373,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Editor
_initial_set("interface/editor/display_scale", 0);
// Display what the Auto display scale setting effectively corresponds to.
- // The code below is adapted in `editor/editor_node.cpp` and `editor/project_manager.cpp`.
- // Make sure to update those when modifying the code below.
-#ifdef OSX_ENABLED
- float scale = DisplayServer::get_singleton()->screen_get_max_scale();
-#else
- const int screen = DisplayServer::get_singleton()->window_get_current_screen();
- float scale;
- if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) {
- // hiDPI display.
- scale = 2.0;
- } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) {
- // Likely a hiDPI display, but we aren't certain due to the returned DPI.
- // Use an intermediate scale to handle this situation.
- scale = 1.5;
- } else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) {
- // Small loDPI display. Use a smaller display scale so that editor elements fit more easily.
- // Icons won't look great, but this is better than having editor elements overflow from its window.
- scale = 0.75;
- } else {
- scale = 1.0;
- }
-#endif
+ float scale = get_auto_display_scale();
hints["interface/editor/display_scale"] = PropertyInfo(Variant::INT, "interface/editor/display_scale", PROPERTY_HINT_ENUM, vformat("Auto (%d%%),75%%,100%%,125%%,150%%,175%%,200%%,Custom", Math::round(scale * 100)), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/custom_display_scale", 1.0f);
hints["interface/editor/custom_display_scale"] = PropertyInfo(Variant::FLOAT, "interface/editor/custom_display_scale", PROPERTY_HINT_RANGE, "0.5,3,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
@@ -419,7 +398,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["interface/editor/main_font_bold"] = PropertyInfo(Variant::STRING, "interface/editor/main_font_bold", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/editor/code_font", "");
hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT);
- _initial_set("interface/editor/dim_editor_on_dialog_popup", true);
_initial_set("interface/editor/low_processor_mode_sleep_usec", 6900); // ~144 FPS
hints["interface/editor/low_processor_mode_sleep_usec"] = PropertyInfo(Variant::FLOAT, "interface/editor/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/unfocused_low_processor_mode_sleep_usec", 50000); // 20 FPS
@@ -437,27 +415,27 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Theme
_initial_set("interface/theme/preset", "Default");
- hints["interface/theme/preset"] = PropertyInfo(Variant::STRING, "interface/theme/preset", PROPERTY_HINT_ENUM, "Default,Alien,Arc,Godot 2,Grey,Light,Solarized (Dark),Solarized (Light),Custom", PROPERTY_USAGE_DEFAULT);
+ hints["interface/theme/preset"] = PropertyInfo(Variant::STRING, "interface/theme/preset", PROPERTY_HINT_ENUM, "Default,Breeze Dark,Godot 2,Grey,Light,Solarized (Dark),Solarized (Light),Custom", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/icon_and_font_color", 0);
hints["interface/theme/icon_and_font_color"] = PropertyInfo(Variant::INT, "interface/theme/icon_and_font_color", PROPERTY_HINT_ENUM, "Auto,Dark,Light", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/base_color", Color(0.2, 0.23, 0.31));
hints["interface/theme/base_color"] = PropertyInfo(Variant::COLOR, "interface/theme/base_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/accent_color", Color(0.41, 0.61, 0.91));
hints["interface/theme/accent_color"] = PropertyInfo(Variant::COLOR, "interface/theme/accent_color", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT);
- _initial_set("interface/theme/contrast", 0.25);
- hints["interface/theme/contrast"] = PropertyInfo(Variant::FLOAT, "interface/theme/contrast", PROPERTY_HINT_RANGE, "0.01, 1, 0.01");
+ _initial_set("interface/theme/contrast", 0.3);
+ hints["interface/theme/contrast"] = PropertyInfo(Variant::FLOAT, "interface/theme/contrast", PROPERTY_HINT_RANGE, "-1, 1, 0.01");
_initial_set("interface/theme/icon_saturation", 1.0);
hints["interface/theme/icon_saturation"] = PropertyInfo(Variant::FLOAT, "interface/theme/icon_saturation", PROPERTY_HINT_RANGE, "0,2,0.01", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/relationship_line_opacity", 0.1);
hints["interface/theme/relationship_line_opacity"] = PropertyInfo(Variant::FLOAT, "interface/theme/relationship_line_opacity", PROPERTY_HINT_RANGE, "0.00, 1, 0.01");
- _initial_set("interface/theme/highlight_tabs", false);
- _initial_set("interface/theme/border_size", 1);
- _initial_set("interface/theme/use_graph_node_headers", false);
+ _initial_set("interface/theme/border_size", 0);
hints["interface/theme/border_size"] = PropertyInfo(Variant::INT, "interface/theme/border_size", PROPERTY_HINT_RANGE, "0,2,1", PROPERTY_USAGE_DEFAULT);
+ _initial_set("interface/theme/corner_radius", 3);
+ hints["interface/theme/corner_radius"] = PropertyInfo(Variant::INT, "interface/theme/corner_radius", PROPERTY_HINT_RANGE, "0,6,1", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/additional_spacing", 0);
hints["interface/theme/additional_spacing"] = PropertyInfo(Variant::FLOAT, "interface/theme/additional_spacing", PROPERTY_HINT_RANGE, "0,5,0.1", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/custom_theme", "");
- hints["interface/theme/custom_theme"] = PropertyInfo(Variant::STRING, "interface/theme/custom_theme", PROPERTY_HINT_GLOBAL_FILE, "*.res,*.tres,*.theme", PROPERTY_USAGE_DEFAULT);
+ hints["interface/theme/custom_theme"] = PropertyInfo(Variant::STRING, "interface/theme/custom_theme", PROPERTY_HINT_GLOBAL_FILE, "*.res,*.tres,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
// Scene tabs
_initial_set("interface/scene_tabs/show_thumbnail_on_hover", true);
@@ -503,12 +481,12 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
/* Text editor */
// Theme
- _initial_set("text_editor/theme/color_theme", "Adaptive");
- hints["text_editor/theme/color_theme"] = PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, "Adaptive,Default,Custom");
+ _initial_set("text_editor/theme/color_theme", "Default");
+ hints["text_editor/theme/color_theme"] = PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, "Default,Godot 2,Custom");
_initial_set("text_editor/theme/line_spacing", 6);
hints["text_editor/theme/line_spacing"] = PropertyInfo(Variant::INT, "text_editor/theme/line_spacing", PROPERTY_HINT_RANGE, "0,50,1");
- _load_default_text_editor_theme();
+ _load_godot2_text_editor_theme();
// Highlighting
_initial_set("text_editor/highlighting/highlight_all_occurrences", true);
@@ -572,7 +550,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/completion/code_complete_delay", 0.3);
hints["text_editor/completion/code_complete_delay"] = PropertyInfo(Variant::FLOAT, "text_editor/completion/code_complete_delay", PROPERTY_HINT_RANGE, "0.01, 5, 0.01");
_initial_set("text_editor/completion/put_callhint_tooltip_below_current_line", true);
- _initial_set("text_editor/completion/callhint_tooltip_offset", Vector2());
_initial_set("text_editor/completion/complete_file_paths", true);
_initial_set("text_editor/completion/add_type_hints", false);
_initial_set("text_editor/completion/use_single_quotes", false);
@@ -691,11 +668,11 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/2d/guides_color", Color(0.6, 0.0, 0.8));
_initial_set("editors/2d/smart_snapping_line_color", Color(0.9, 0.1, 0.1));
_initial_set("editors/2d/bone_width", 5);
- _initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.9));
- _initial_set("editors/2d/bone_color2", Color(0.6, 0.6, 0.6, 0.9));
- _initial_set("editors/2d/bone_selected_color", Color(0.9, 0.45, 0.45, 0.9));
- _initial_set("editors/2d/bone_ik_color", Color(0.9, 0.9, 0.45, 0.9));
- _initial_set("editors/2d/bone_outline_color", Color(0.35, 0.35, 0.35));
+ _initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.7));
+ _initial_set("editors/2d/bone_color2", Color(0.6, 0.6, 0.6, 0.7));
+ _initial_set("editors/2d/bone_selected_color", Color(0.9, 0.45, 0.45, 0.7));
+ _initial_set("editors/2d/bone_ik_color", Color(0.9, 0.9, 0.45, 0.7));
+ _initial_set("editors/2d/bone_outline_color", Color(0.35, 0.35, 0.35, 0.5));
_initial_set("editors/2d/bone_outline_size", 2);
_initial_set("editors/2d/viewport_border_color", Color(0.4, 0.4, 1.0, 0.4));
_initial_set("editors/2d/constrain_editor_view", true);
@@ -704,6 +681,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/2d/scroll_to_pan", false);
_initial_set("editors/2d/pan_speed", 20);
+ // Tiles editor
+ _initial_set("editors/tiles_editor/display_grid", true);
+ _initial_set("editors/tiles_editor/grid_color", Color(1.0, 0.5, 0.2, 0.5));
+
// Polygon editor
_initial_set("editors/poly_editor/point_grab_radius", 8);
_initial_set("editors/poly_editor/show_previous_outline", true);
@@ -766,8 +747,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
for (int i = 0; i < list.size(); i++) {
String name = list[i].replace("/", "::");
set("projects/" + name, list[i]);
- };
- };
+ }
+ }
if (p_extra_config->has_section("presets")) {
List<String> keys;
@@ -777,22 +758,22 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
String key = E->get();
Variant val = p_extra_config->get_value("presets", key);
set(key, val);
- };
- };
- };
+ }
+ }
+ }
}
-void EditorSettings::_load_default_text_editor_theme() {
- bool dark_theme = is_dark_theme();
-
+void EditorSettings::_load_godot2_text_editor_theme() {
+ // Godot 2 is only a dark theme; it doesn't have a light theme counterpart.
_initial_set("text_editor/highlighting/symbol_color", Color(0.73, 0.87, 1.0));
_initial_set("text_editor/highlighting/keyword_color", Color(1.0, 1.0, 0.7));
+ _initial_set("text_editor/highlighting/control_flow_keyword_color", Color(1.0, 0.85, 0.7));
_initial_set("text_editor/highlighting/base_type_color", Color(0.64, 1.0, 0.83));
_initial_set("text_editor/highlighting/engine_type_color", Color(0.51, 0.83, 1.0));
_initial_set("text_editor/highlighting/user_type_color", Color(0.42, 0.67, 0.93));
_initial_set("text_editor/highlighting/comment_color", Color(0.4, 0.4, 0.4));
_initial_set("text_editor/highlighting/string_color", Color(0.94, 0.43, 0.75));
- _initial_set("text_editor/highlighting/background_color", dark_theme ? Color(0.0, 0.0, 0.0, 0.23) : Color(0.2, 0.23, 0.31));
+ _initial_set("text_editor/highlighting/background_color", Color(0.13, 0.12, 0.15));
_initial_set("text_editor/highlighting/completion_background_color", Color(0.17, 0.16, 0.2));
_initial_set("text_editor/highlighting/completion_selected_color", Color(0.26, 0.26, 0.27));
_initial_set("text_editor/highlighting/completion_existing_color", Color(0.13, 0.87, 0.87, 0.87));
@@ -842,7 +823,7 @@ bool EditorSettings::_save_text_editor_theme(String p_file) {
}
bool EditorSettings::_is_default_text_editor_theme(String p_theme_name) {
- return p_theme_name == "default" || p_theme_name == "adaptive" || p_theme_name == "custom";
+ return p_theme_name == "default" || p_theme_name == "godot 2" || p_theme_name == "custom";
}
static Dictionary _get_builtin_script_templates() {
@@ -869,9 +850,8 @@ static void _create_script_templates(const String &p_path) {
Dictionary templates = _get_builtin_script_templates();
List<Variant> keys;
templates.get_key_list(&keys);
- FileAccess *file = FileAccess::create(FileAccess::ACCESS_FILESYSTEM);
-
- DirAccess *dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ FileAccessRef file = FileAccess::create(FileAccess::ACCESS_FILESYSTEM);
+ DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
dir->change_dir(p_path);
for (int i = 0; i < keys.size(); i++) {
if (!dir->file_exists(keys[i])) {
@@ -881,9 +861,6 @@ static void _create_script_templates(const String &p_path) {
file->close();
}
}
-
- memdelete(dir);
- memdelete(file);
}
// PUBLIC METHODS
@@ -893,163 +870,53 @@ EditorSettings *EditorSettings::get_singleton() {
}
void EditorSettings::create() {
+ // IMPORTANT: create() *must* create a valid EditorSettings singleton,
+ // as the rest of the engine code will assume it. As such, it should never
+ // return (incl. via ERR_FAIL) without initializing the singleton member.
+
if (singleton.ptr()) {
- return; //pointless
+ ERR_PRINT("Can't recreate EditorSettings as it already exists.");
+ return;
}
- DirAccess *dir = nullptr;
-
- String data_path;
- String data_dir;
- String config_path;
- String config_dir;
- String cache_path;
- String cache_dir;
+ ClassDB::register_class<EditorSettings>(); // Otherwise it can't be unserialized.
+ String config_file_path;
Ref<ConfigFile> extra_config = memnew(ConfigFile);
- String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();
- DirAccess *d = DirAccess::create_for_path(exe_path);
- bool self_contained = false;
-
- if (d->file_exists(exe_path + "/._sc_")) {
- self_contained = true;
- Error err = extra_config->load(exe_path + "/._sc_");
- if (err != OK) {
- ERR_PRINT("Can't load config from path '" + exe_path + "/._sc_'.");
- }
- } else if (d->file_exists(exe_path + "/_sc_")) {
- self_contained = true;
- Error err = extra_config->load(exe_path + "/_sc_");
- if (err != OK) {
- ERR_PRINT("Can't load config from path '" + exe_path + "/_sc_'.");
- }
+ if (!EditorPaths::get_singleton()) {
+ ERR_PRINT("Bug (please report): EditorPaths haven't been initialized, EditorSettings cannot be created properly.");
+ goto fail;
}
- memdelete(d);
- if (self_contained) {
- // editor is self contained, all in same folder
- data_path = exe_path;
- data_dir = data_path.plus_file("editor_data");
- config_path = exe_path;
- config_dir = data_dir;
- cache_path = exe_path;
- cache_dir = data_dir.plus_file("cache");
- } else {
- // Typically XDG_DATA_HOME or %APPDATA%
- data_path = OS::get_singleton()->get_data_path();
- data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name());
- // Can be different from data_path e.g. on Linux or macOS
- config_path = OS::get_singleton()->get_config_path();
- config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name());
- // Can be different from above paths, otherwise a subfolder of data_dir
- cache_path = OS::get_singleton()->get_cache_path();
- if (cache_path == data_path) {
- cache_dir = data_dir.plus_file("cache");
- } else {
- cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+ if (EditorPaths::get_singleton()->is_self_contained()) {
+ Error err = extra_config->load(EditorPaths::get_singleton()->get_self_contained_file());
+ if (err != OK) {
+ ERR_PRINT("Can't load extra config from path: " + EditorPaths::get_singleton()->get_self_contained_file());
}
}
- ClassDB::register_class<EditorSettings>(); //otherwise it can't be unserialized
-
- String config_file_path;
-
- if (data_path != "" && config_path != "" && cache_path != "") {
- // Validate/create data dir and subdirectories
-
- dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- if (dir->change_dir(data_dir) != OK) {
- dir->make_dir_recursive(data_dir);
- if (dir->change_dir(data_dir) != OK) {
- ERR_PRINT("Cannot create data directory!");
- memdelete(dir);
- goto fail;
- }
- }
-
- if (dir->change_dir("templates") != OK) {
- dir->make_dir("templates");
- } else {
- dir->change_dir("..");
- }
-
- // Validate/create cache dir
-
- if (dir->change_dir(cache_dir) != OK) {
- dir->make_dir_recursive(cache_dir);
- if (dir->change_dir(cache_dir) != OK) {
- ERR_PRINT("Cannot create cache directory!");
- memdelete(dir);
- goto fail;
- }
- }
-
- // Validate/create config dir and subdirectories
-
- if (dir->change_dir(config_dir) != OK) {
- dir->make_dir_recursive(config_dir);
- if (dir->change_dir(config_dir) != OK) {
- ERR_PRINT("Cannot create config directory!");
- memdelete(dir);
- goto fail;
- }
- }
-
- if (dir->change_dir("text_editor_themes") != OK) {
- dir->make_dir("text_editor_themes");
- } else {
- dir->change_dir("..");
- }
+ if (EditorPaths::get_singleton()->are_paths_valid()) {
+ _create_script_templates(EditorPaths::get_singleton()->get_config_dir().plus_file("script_templates"));
- if (dir->change_dir("script_templates") != OK) {
- dir->make_dir("script_templates");
- } else {
- dir->change_dir("..");
- }
-
- if (dir->change_dir("feature_profiles") != OK) {
- dir->make_dir("feature_profiles");
- } else {
- dir->change_dir("..");
- }
-
- _create_script_templates(dir->get_current_dir().plus_file("script_templates"));
-
- {
- // Validate/create project-specific editor settings dir.
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- if (da->change_dir(EditorSettings::PROJECT_EDITOR_SETTINGS_PATH) != OK) {
- Error err = da->make_dir_recursive(EditorSettings::PROJECT_EDITOR_SETTINGS_PATH);
- if (err || da->change_dir(EditorSettings::PROJECT_EDITOR_SETTINGS_PATH) != OK) {
- ERR_FAIL_MSG("Failed to create '" + EditorSettings::PROJECT_EDITOR_SETTINGS_PATH + "' folder.");
- }
- }
- }
-
- // Validate editor config file
+ // Validate editor config file.
+ DirAccessRef dir = DirAccess::open(EditorPaths::get_singleton()->get_config_dir());
String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres";
- config_file_path = config_dir.plus_file(config_file_name);
+ config_file_path = EditorPaths::get_singleton()->get_config_dir().plus_file(config_file_name);
if (!dir->file_exists(config_file_name)) {
- memdelete(dir);
goto fail;
}
- memdelete(dir);
-
singleton = ResourceLoader::load(config_file_path, "EditorSettings");
if (singleton.is_null()) {
- WARN_PRINT("Could not open config file.");
+ ERR_PRINT("Could not load editor settings from path: " + config_file_path);
goto fail;
}
singleton->save_changed_setting = true;
singleton->config_file_path = config_file_path;
- singleton->settings_dir = config_dir;
- singleton->data_dir = data_dir;
- singleton->cache_dir = cache_dir;
print_verbose("EditorSettings: Load OK!");
@@ -1062,22 +929,20 @@ void EditorSettings::create() {
}
fail:
-
// patch init projects
+ String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();
+
if (extra_config->has_section("init_projects")) {
Vector<String> list = extra_config->get_value("init_projects", "list");
for (int i = 0; i < list.size(); i++) {
list.write[i] = exe_path.plus_file(list[i]);
- };
+ }
extra_config->set_value("init_projects", "list", list);
- };
+ }
singleton = Ref<EditorSettings>(memnew(EditorSettings));
singleton->save_changed_setting = true;
singleton->config_file_path = config_file_path;
- singleton->settings_dir = config_dir;
- singleton->data_dir = data_dir;
- singleton->cache_dir = cache_dir;
singleton->_load_defaults(extra_config);
singleton->setup_language();
singleton->setup_network();
@@ -1138,14 +1003,14 @@ void EditorSettings::setup_language() {
}
void EditorSettings::setup_network() {
- List<IP_Address> local_ip;
+ List<IPAddress> local_ip;
IP::get_singleton()->get_local_addresses(&local_ip);
String hint;
String current = has_setting("network/debug/remote_host") ? get("network/debug/remote_host") : "";
String selected = "127.0.0.1";
// Check that current remote_host is a valid interface address and populate hints.
- for (List<IP_Address>::Element *E = local_ip.front(); E; E = E->next()) {
+ for (List<IPAddress>::Element *E = local_ip.front(); E; E = E->next()) {
String ip = E->get();
// link-local IPv6 addresses don't work, skipping them
@@ -1305,46 +1170,31 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) {
hints[p_hint.name] = p_hint;
}
-// Data directories
-
-String EditorSettings::get_data_dir() const {
- return data_dir;
-}
+// Editor data and config directories
+// EditorPaths::create() is responsible for the creation of these directories.
String EditorSettings::get_templates_dir() const {
- return get_data_dir().plus_file("templates");
-}
-
-// Config directories
-
-String EditorSettings::get_settings_dir() const {
- return settings_dir;
+ return EditorPaths::get_singleton()->get_data_dir().plus_file("templates");
}
String EditorSettings::get_project_settings_dir() const {
- return EditorSettings::PROJECT_EDITOR_SETTINGS_PATH;
+ return EditorPaths::get_singleton()->get_project_data_dir().plus_file("editor");
}
String EditorSettings::get_text_editor_themes_dir() const {
- return get_settings_dir().plus_file("text_editor_themes");
+ return EditorPaths::get_singleton()->get_config_dir().plus_file("text_editor_themes");
}
String EditorSettings::get_script_templates_dir() const {
- return get_settings_dir().plus_file("script_templates");
+ return EditorPaths::get_singleton()->get_config_dir().plus_file("script_templates");
}
String EditorSettings::get_project_script_templates_dir() const {
return ProjectSettings::get_singleton()->get("editor/script/templates_search_path");
}
-// Cache directory
-
-String EditorSettings::get_cache_dir() const {
- return cache_dir;
-}
-
String EditorSettings::get_feature_profiles_dir() const {
- return get_settings_dir().plus_file("feature_profiles");
+ return EditorPaths::get_singleton()->get_config_dir().plus_file("feature_profiles");
}
// Metadata
@@ -1431,7 +1281,7 @@ bool EditorSettings::is_dark_theme() {
}
void EditorSettings::list_text_editor_themes() {
- String themes = "Adaptive,Default,Custom";
+ String themes = "Default,Godot 2,Custom";
DirAccess *d = DirAccess::open(get_text_editor_themes_dir());
if (d) {
@@ -1459,8 +1309,8 @@ void EditorSettings::load_text_editor_theme() {
String p_file = get("text_editor/theme/color_theme");
if (_is_default_text_editor_theme(p_file.get_file().to_lower())) {
- if (p_file == "Default") {
- _load_default_text_editor_theme();
+ if (p_file == "Godot 2") {
+ _load_godot2_text_editor_theme();
}
return; // sorry for "Settings changed" console spam
}
@@ -1571,7 +1421,30 @@ Vector<String> EditorSettings::get_script_templates(const String &p_extension, c
}
String EditorSettings::get_editor_layouts_config() const {
- return get_settings_dir().plus_file("editor_layouts.cfg");
+ return EditorPaths::get_singleton()->get_config_dir().plus_file("editor_layouts.cfg");
+}
+
+float EditorSettings::get_auto_display_scale() const {
+#ifdef OSX_ENABLED
+ return DisplayServer::get_singleton()->screen_get_max_scale();
+#else
+ const int screen = DisplayServer::get_singleton()->window_get_current_screen();
+ // Use the smallest dimension to use a correct display scale on portait displays.
+ const int smallest_dimension = MIN(DisplayServer::get_singleton()->screen_get_size(screen).x, DisplayServer::get_singleton()->screen_get_size(screen).y);
+ if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && smallest_dimension >= 1400) {
+ // hiDPI display.
+ return 2.0;
+ } else if (smallest_dimension >= 1700) {
+ // Likely a hiDPI display, but we aren't certain due to the returned DPI.
+ // Use an intermediate scale to handle this situation.
+ return 1.5;
+ } else if (smallest_dimension <= 800) {
+ // Small loDPI display. Use a smaller display scale so that editor elements fit more easily.
+ // Icons won't look great, but this is better than having editor elements overflow from its window.
+ return 0.75;
+ }
+ return 1.0;
+#endif
}
// Shortcuts
@@ -1655,10 +1528,10 @@ Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, uint32_t p
ie->set_unicode(p_keycode & KEY_CODE_MASK);
ie->set_keycode(p_keycode & KEY_CODE_MASK);
- ie->set_shift(bool(p_keycode & KEY_MASK_SHIFT));
- ie->set_alt(bool(p_keycode & KEY_MASK_ALT));
- ie->set_control(bool(p_keycode & KEY_MASK_CTRL));
- ie->set_metakey(bool(p_keycode & KEY_MASK_META));
+ ie->set_shift_pressed(bool(p_keycode & KEY_MASK_SHIFT));
+ ie->set_alt_pressed(bool(p_keycode & KEY_MASK_ALT));
+ ie->set_ctrl_pressed(bool(p_keycode & KEY_MASK_CTRL));
+ ie->set_meta_pressed(bool(p_keycode & KEY_MASK_META));
}
if (!EditorSettings::get_singleton()) {
@@ -1773,7 +1646,6 @@ void EditorSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorSettings::property_get_revert);
ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind);
- ClassDB::bind_method(D_METHOD("get_settings_dir"), &EditorSettings::get_settings_dir);
ClassDB::bind_method(D_METHOD("get_project_settings_dir"), &EditorSettings::get_project_settings_dir);
ClassDB::bind_method(D_METHOD("set_project_metadata", "section", "key", "data"), &EditorSettings::set_project_metadata);
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index e5f8527faf..3a28c18b27 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -36,6 +36,7 @@
#include "core/object/class_db.h"
#include "core/os/thread_safe.h"
#include "core/string/translation.h"
+#include "editor/editor_paths.h"
#include "scene/gui/shortcut.h"
class EditorPlugin;
@@ -46,7 +47,6 @@ class EditorSettings : public Resource {
_THREAD_SAFE_CLASS_
public:
- inline static const String PROJECT_EDITOR_SETTINGS_PATH = "res://.godot/editor";
struct Plugin {
EditorPlugin *instance = nullptr;
String path;
@@ -87,12 +87,7 @@ private:
mutable Map<String, Ref<Shortcut>> shortcuts;
Map<String, List<Ref<InputEvent>>> builtin_action_overrides;
- String resource_path;
- String settings_dir;
- String data_dir;
- String cache_dir;
String config_file_path;
- String project_config_dir;
Vector<String> favorites;
Vector<String> recent_dirs;
@@ -108,7 +103,7 @@ private:
void _add_property_info_bind(const Dictionary &p_info);
void _load_defaults(Ref<ConfigFile> p_extra_config = Ref<ConfigFile>());
- void _load_default_text_editor_theme();
+ void _load_godot2_text_editor_theme();
bool _save_text_editor_theme(String p_file);
bool _is_default_text_editor_theme(String p_theme_name);
@@ -153,12 +148,10 @@ public:
String get_data_dir() const;
String get_templates_dir() const;
- String get_settings_dir() const;
String get_project_settings_dir() const;
String get_text_editor_themes_dir() const;
String get_script_templates_dir() const;
String get_project_script_templates_dir() const;
- String get_cache_dir() const;
String get_feature_profiles_dir() const;
void set_project_metadata(const String &p_section, const String &p_key, Variant p_data);
@@ -181,6 +174,7 @@ public:
Vector<String> get_script_templates(const String &p_extension, const String &p_custom_path = String());
String get_editor_layouts_config() const;
+ float get_auto_display_scale() const;
void add_shortcut(const String &p_name, Ref<Shortcut> &p_shortcut);
bool is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const;
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 8577ccb9db..4f0d75ecce 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -70,7 +70,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 = get_global_mouse_position();
}
} else {
if (grabbing_spinner_attempt) {
@@ -97,7 +97,7 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid()) {
if (grabbing_spinner_attempt) {
double diff_x = mm->get_relative().x;
- if (mm->get_shift() && grabbing_spinner) {
+ if (mm->is_shift_pressed() && grabbing_spinner) {
diff_x *= 0.1;
}
grabbing_spinner_dist_cache += diff_x;
@@ -116,7 +116,7 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
pre_grab_value = get_max();
}
- if (mm->get_control()) {
+ if (mm->is_ctrl_pressed()) {
// If control was just pressed, don't make the value do a huge jump in magnitude.
if (grabbing_spinner_dist_cache != 0) {
pre_grab_value += grabbing_spinner_dist_cache * get_step();
@@ -283,6 +283,8 @@ void EditorSpinSlider::_notification(int p_what) {
Rect2 grabber_rect = Rect2(ofs + gofs, svofs + 1, grabber_w, 2 * EDSCALE);
draw_rect(grabber_rect, c);
+ grabbing_spinner_mouse_pos = get_global_position() + grabber_rect.position + grabber_rect.size * 0.5;
+
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) {
@@ -384,8 +386,8 @@ void EditorSpinSlider::_evaluate_input_text() {
set_value(v);
}
-//text_entered signal
-void EditorSpinSlider::_value_input_entered(const String &p_text) {
+//text_submitted signal
+void EditorSpinSlider::_value_input_submitted(const String &p_text) {
value_input_just_closed = true;
value_input_popup->hide();
}
@@ -508,7 +510,7 @@ EditorSpinSlider::EditorSpinSlider() {
value_input_popup->set_wrap_controls(true);
value_input->set_anchors_and_offsets_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("text_submitted", callable_mp(this, &EditorSpinSlider::_value_input_submitted));
value_input->connect("focus_exited", callable_mp(this, &EditorSpinSlider::_value_focus_exited));
value_input_just_closed = false;
hide_slider = false;
diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h
index 248a13f7b6..50d04c9583 100644
--- a/editor/editor_spin_slider.h
+++ b/editor/editor_spin_slider.h
@@ -68,7 +68,7 @@ class EditorSpinSlider : public Range {
void _grabber_gui_input(const Ref<InputEvent> &p_event);
void _value_input_closed();
- void _value_input_entered(const String &);
+ void _value_input_submitted(const String &);
void _value_focus_exited();
bool hide_slider;
bool flat;
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 7cc9ebd63e..fa543b7455 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -65,9 +65,12 @@ static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_
return style;
}
-static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
+static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, int p_corner_width = 0) {
Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
style->set_bg_color(p_color);
+ // Adjust level of detail based on the corners' effective sizes.
+ style->set_corner_detail(Math::ceil(1.5 * p_corner_width * EDSCALE));
+ style->set_corner_radius_all(p_corner_width);
style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE);
style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE);
style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE);
@@ -141,70 +144,70 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
Set<StringName> exceptions;
if (!p_dark_theme) {
- // convert color: FROM TO
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e0e0e0", "#5a5a5a"); // common icon color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffffff", "#414141"); // white
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b4b4b4", "#363636"); // script darker color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f9f9f9", "#606060"); // scrollbar grabber highlight color
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#cea4f1", "#a85de9"); // animation
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fc9c9c", "#cd3838"); // spatial
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a5b7f3", "#3d64dd"); // 2d
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#708cea", "#1a3eac"); // 2d dark
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a5efac", "#2fa139"); // control
-
- // rainbow
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff7070", "#ff2929"); // red
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffeb70", "#ffe337"); // yellow
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#9dff70", "#74ff34"); // green
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#70ffb9", "#2cff98"); // aqua
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#70deff", "#22ccff"); // blue
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#9f70ff", "#702aff"); // purple
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff70ac", "#ff2781"); // pink
-
- // audio gradient
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff8484", "#ff4040"); // red
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e1dc7a", "#d6cf4b"); // yellow
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#84ffb1", "#00f010"); // green
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffd684", "#fea900"); // mesh (orange)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#40a2ff", "#68b6ff"); // shape (blue)
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff8484", "#ff3333"); // remove (red)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#84ffb1", "#00db50"); // add (green)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#84c2ff", "#5caeff"); // selection (blue)
+ // Convert color: FROM TO
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e0e0e0", "#5a5a5a"); // Common icon color
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffffff", "#414141"); // White
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b4b4b4", "#363636"); // Script darker color
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f9f9f9", "#606060"); // Scrollbar grabber highlight color
+
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c38ef1", "#a85de9"); // Animation
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fc7f7f", "#cd3838"); // Spatial
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8da5f3", "#3d64dd"); // 2D
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4b70ea", "#1a3eac"); // 2D Dark
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8eef97", "#2fa139"); // Control
+
+ // Rainbow
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff4545", "#ff2929"); // Red
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffe345", "#ffe337"); // Yellow
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#80ff45", "#74ff34"); // Green
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#45ffa2", "#2cff98"); // Aqua
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#45d7ff", "#22ccff"); // Blue
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8045ff", "#702aff"); // Purple
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff4596", "#ff2781"); // Pink
+
+ // Audio gradient
+ // Red is defined further below.
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e1da5b", "#d6cf4b"); // Yellow
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5fff97", "#00f010"); // Green
+
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffca5f", "#fea900"); // Mesh resource (orange)
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#0787ff", "#68b6ff"); // Shape resource (blue)
+
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff5f5f", "#ff3333"); // Red audio gradient + remove (red)
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5fff97", "#00db50"); // Add (green)
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5fb2ff", "#5caeff"); // Selection (blue)
// Animation editor tracks
- // The property track icon color is set by the common icon color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ea9568", "#bd5e2c"); // 3D Transform track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#66f376", "#16a827"); // Call Method track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5792f6", "#236be6"); // Bezier Curve track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eae668", "#9f9722"); // Audio Playback track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b76ef0", "#9853ce"); // Animation Playback track
+ // The property track icon color is set by the common icon color.
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ea7940", "#bd5e2c"); // 3D Transform track
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#3cf34e", "#16a827"); // Call Method track
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#2877f6", "#236be6"); // Bezier Curve track
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eae440", "#9f9722"); // Audio Playback track
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a448f0", "#9853ce"); // Animation Playback track
// TileSet editor icons
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fce844", "#aa8d24"); // New Single Tile
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4490fc", "#0350bd"); // New Autotile
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c9cfd4", "#828f9b"); // New Atlas
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#69ecbd", "#25e3a0"); // VS variant
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8da6f0", "#6d8eeb"); // VS bool
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#7dc6ef", "#4fb2e9"); // VS int
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#61daf4", "#27ccf0"); // VS float
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#6ba7ec", "#4690e7"); // VS string
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#bd91f1", "#ad76ee"); // VS vector2
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f191a5", "#ee758e"); // VS rect
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e286f0", "#dc6aed"); // VS vector3
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c4ec69", "#96ce1a"); // VS transform2D
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f77070", "#f77070"); // VS plane
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ec69a3", "#ec69a3"); // VS quat
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ee7991", "#ee7991"); // VS aabb
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e3ec69", "#b2bb19"); // VS basis
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f6a86e", "#f49047"); // VS transform
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#6993ec", "#6993ec"); // VS path
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#69ec9a", "#2ce573"); // VS rid
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#79f3e8", "#12d5c3"); // VS object
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#77edb1", "#57e99f"); // VS dict
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fce00e", "#aa8d24"); // New Single Tile
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#0e71fc", "#0350bd"); // New Autotile
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c6ced4", "#828f9b"); // New Atlas
+
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#41ecad", "#25e3a0"); // VisualScript variant
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#6f91f0", "#6d8eeb"); // VisualScript bool
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5abbef", "#4fb2e9"); // VisualScript int
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#35d4f4", "#27ccf0"); // VisualScript float
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4593ec", "#4690e7"); // VisualScript String
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ac73f1", "#ad76ee"); // VisualScript Vector2
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f1738f", "#ee758e"); // VisualScript Rect2
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#de66f0", "#dc6aed"); // VisualScript Vector3
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b9ec41", "#96ce1a"); // VisualScript Transform2D
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f74949", "#f77070"); // VisualScript Plane
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ec418e", "#ec69a3"); // VisualScript Quat
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ee5677", "#ee7991"); // VisualScript AABB
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e1ec41", "#b2bb19"); // VisualScript Basis
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f68f45", "#f49047"); // VisualScript Transform
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#417aec", "#6993ec"); // VisualScript NodePath
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#41ec80", "#2ce573"); // VisualScript RID
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#55f3e3", "#12d5c3"); // VisualScript Object
+ ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#54ed9e", "#57e99f"); // VisualScript Dictionary
exceptions.insert("EditorPivot");
exceptions.insert("EditorHandle");
@@ -213,6 +216,8 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
exceptions.insert("Sky");
exceptions.insert("EditorControlAnchor");
exceptions.insert("DefaultProjectIcon");
+ exceptions.insert("GuiChecked");
+ exceptions.insert("GuiRadioChecked");
exceptions.insert("GuiCloseCustomizable");
exceptions.insert("GuiGraphNodePort");
exceptions.insert("GuiResizer");
@@ -286,9 +291,9 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<Theme> theme = Ref<Theme>(memnew(Theme));
- const float default_contrast = 0.25;
+ const float default_contrast = 0.3;
- //Theme settings
+ // Theme settings
Color accent_color = EDITOR_GET("interface/theme/accent_color");
Color base_color = EDITOR_GET("interface/theme/base_color");
float contrast = EDITOR_GET("interface/theme/contrast");
@@ -297,56 +302,49 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
String preset = EDITOR_GET("interface/theme/preset");
- bool highlight_tabs = EDITOR_GET("interface/theme/highlight_tabs");
int border_size = EDITOR_GET("interface/theme/border_size");
-
- bool use_gn_headers = EDITOR_GET("interface/theme/use_graph_node_headers");
+ int corner_radius = EDITOR_GET("interface/theme/corner_radius");
Color preset_accent_color;
Color preset_base_color;
float preset_contrast = 0;
- // Please, use alphabet order if you've added new theme here(After "Default" and "Custom")
+ // Please use alphabetical order if you're adding a new theme here
+ // (after "Custom")
- if (preset == "Default") {
- preset_accent_color = Color(0.41, 0.61, 0.91);
- preset_base_color = Color(0.2, 0.23, 0.31);
- preset_contrast = default_contrast;
- } else if (preset == "Custom") {
+ if (preset == "Custom") {
accent_color = EDITOR_GET("interface/theme/accent_color");
base_color = EDITOR_GET("interface/theme/base_color");
contrast = EDITOR_GET("interface/theme/contrast");
- } else if (preset == "Alien") {
- preset_accent_color = Color(0.11, 1.0, 0.6);
- preset_base_color = Color(0.18, 0.22, 0.25);
- preset_contrast = 0.25;
- } else if (preset == "Arc") {
- preset_accent_color = Color(0.32, 0.58, 0.89);
- preset_base_color = Color(0.22, 0.24, 0.29);
- preset_contrast = 0.25;
+ } else if (preset == "Breeze Dark") {
+ preset_accent_color = Color(0.26, 0.76, 1.00);
+ preset_base_color = Color(0.24, 0.26, 0.28);
+ preset_contrast = default_contrast;
} else if (preset == "Godot 2") {
preset_accent_color = Color(0.53, 0.67, 0.89);
preset_base_color = Color(0.24, 0.23, 0.27);
- preset_contrast = 0.25;
+ preset_contrast = default_contrast;
} else if (preset == "Grey") {
- preset_accent_color = Color(0.72, 0.89, 1.0);
+ preset_accent_color = Color(0.72, 0.89, 1.00);
preset_base_color = Color(0.24, 0.24, 0.24);
- preset_contrast = 0.2;
+ preset_contrast = default_contrast;
} else if (preset == "Light") {
- preset_accent_color = Color(0.13, 0.44, 1.0);
- preset_base_color = Color(1, 1, 1);
- preset_contrast = 0.08;
+ preset_accent_color = Color(0.18, 0.50, 1.00);
+ preset_base_color = Color(0.9, 0.9, 0.9);
+ // A negative contrast rate looks better for light themes, since it better follows the natural order of UI "elevation".
+ preset_contrast = -0.08;
} else if (preset == "Solarized (Dark)") {
preset_accent_color = Color(0.15, 0.55, 0.82);
- preset_base_color = Color(0.03, 0.21, 0.26);
- preset_contrast = 0.23;
+ preset_base_color = Color(0.04, 0.23, 0.27);
+ preset_contrast = default_contrast;
} else if (preset == "Solarized (Light)") {
preset_accent_color = Color(0.15, 0.55, 0.82);
- preset_base_color = Color(0.99, 0.96, 0.89);
- preset_contrast = 0.06;
+ preset_base_color = Color(0.89, 0.86, 0.79);
+ // A negative contrast rate looks better for light themes, since it better follows the natural order of UI "elevation".
+ preset_contrast = -0.08;
} else { // Default
- preset_accent_color = Color(0.41, 0.61, 0.91);
- preset_base_color = Color(0.2, 0.23, 0.31);
+ preset_accent_color = Color(0.44, 0.73, 0.98);
+ preset_base_color = Color(0.21, 0.24, 0.29);
preset_contrast = default_contrast;
}
@@ -358,12 +356,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
EditorSettings::get_singleton()->set_initial_value("interface/theme/base_color", base_color);
EditorSettings::get_singleton()->set_initial_value("interface/theme/contrast", contrast);
}
+
EditorSettings::get_singleton()->set_manually("interface/theme/preset", preset);
EditorSettings::get_singleton()->set_manually("interface/theme/accent_color", accent_color);
EditorSettings::get_singleton()->set_manually("interface/theme/base_color", base_color);
EditorSettings::get_singleton()->set_manually("interface/theme/contrast", contrast);
- //Colors
+ // Colors
bool dark_theme = EditorSettings::get_singleton()->is_dark_theme();
const Color dark_color_1 = base_color.lerp(Color(0, 0, 0, 1), contrast);
@@ -372,14 +371,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color background_color = dark_color_2;
- // white (dark theme) or black (light theme), will be used to generate the rest of the colors
+ // White (dark theme) or black (light theme), will be used to generate the rest of the colors
const Color mono_color = dark_theme ? Color(1, 1, 1) : Color(0, 0, 0);
const Color contrast_color_1 = base_color.lerp(mono_color, MAX(contrast, default_contrast));
const Color contrast_color_2 = base_color.lerp(mono_color, MAX(contrast * 1.5, default_contrast * 1.5));
const Color font_color = mono_color.lerp(base_color, 0.25);
- const Color font_hover_color = mono_color.lerp(base_color, 0.15);
+ const Color font_hover_color = mono_color.lerp(base_color, 0.125);
const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.3);
const Color selection_color = accent_color * Color(1, 1, 1, 0.4);
const Color disabled_color = mono_color.inverted().lerp(base_color, 0.7);
@@ -393,8 +392,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
icon_pressed_color.a = 1.0;
const Color separator_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.1);
-
- const Color highlight_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.2);
+ const Color highlight_color = Color(accent_color.r, accent_color.g, accent_color.b, 0.275);
float prev_icon_saturation = theme->has_color("icon_saturation", "Editor") ? theme->get_color("icon_saturation", "Editor").r : 1.0;
@@ -447,35 +445,35 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("thumb_size", "Editor", thumb_size);
theme->set_constant("dark_theme", "Editor", dark_theme);
- //Register icons + font
+ // Register icons + font
- // the resolution and the icon color (dark_theme bool) has not changed, so we do not regenerate the icons
+ // The resolution and the icon color (dark_theme bool) has not changed, so we do not regenerate the icons.
if (p_theme != nullptr && fabs(p_theme->get_constant("scale", "Editor") - EDSCALE) < 0.00001 && (bool)p_theme->get_constant("dark_theme", "Editor") == dark_theme && prev_icon_saturation == icon_saturation) {
- // register already generated icons
+ // Register already generated icons.
for (int i = 0; i < editor_icons_count; i++) {
theme->set_icon(editor_icons_names[i], "EditorIcons", p_theme->get_icon(editor_icons_names[i], "EditorIcons"));
}
} else {
editor_register_and_generate_icons(theme, dark_theme, thumb_size, false, icon_saturation);
}
- // thumbnail size has changed, so we regenerate the medium sizes
+ // Thumbnail size has changed, so we regenerate the medium sizes
if (p_theme != nullptr && fabs((double)p_theme->get_constant("thumb_size", "Editor") - thumb_size) > 0.00001) {
editor_register_and_generate_icons(p_theme, dark_theme, thumb_size, true);
}
editor_register_fonts(theme);
- // Highlighted tabs and border width
- Color tab_color = highlight_tabs ? base_color.lerp(font_color, contrast) : base_color;
// Ensure borders are visible when using an editor scale below 100%.
- const int border_width = CLAMP(border_size, 0, 3) * MAX(1, EDSCALE);
-
+ const int border_width = CLAMP(border_size, 0, 2) * MAX(1, EDSCALE);
+ const int corner_width = CLAMP(corner_radius, 0, 6);
const int default_margin_size = 4;
- const int margin_size_extra = default_margin_size + CLAMP(border_size, 0, 3);
+ const int margin_size_extra = default_margin_size + CLAMP(border_size, 0, 2);
- // styleboxes
- // this is the most commonly used stylebox, variations should be made as duplicate of this
- Ref<StyleBoxFlat> style_default = make_flat_stylebox(base_color, default_margin_size, default_margin_size, default_margin_size, default_margin_size);
+ // Styleboxes
+ // This is the most commonly used stylebox, variations should be made as duplicate of this
+ Ref<StyleBoxFlat> style_default = make_flat_stylebox(base_color, default_margin_size, default_margin_size, default_margin_size, default_margin_size, corner_width);
+ // Work around issue about antialiased edges being blurrier (GH-35279).
+ style_default->set_anti_aliased(false);
style_default->set_border_width_all(border_width);
style_default->set_border_color(base_color);
style_default->set_draw_center(true);
@@ -483,11 +481,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Button and widgets
const float extra_spacing = EDITOR_GET("interface/theme/additional_spacing");
+ const Vector2 widget_default_margin = Vector2(extra_spacing + 6, extra_spacing + default_margin_size + 1) * EDSCALE;
+
Ref<StyleBoxFlat> style_widget = style_default->duplicate();
- style_widget->set_default_margin(SIDE_LEFT, (extra_spacing + 6) * EDSCALE);
- style_widget->set_default_margin(SIDE_TOP, (extra_spacing + default_margin_size) * EDSCALE);
- style_widget->set_default_margin(SIDE_RIGHT, (extra_spacing + 6) * EDSCALE);
- style_widget->set_default_margin(SIDE_BOTTOM, (extra_spacing + default_margin_size) * EDSCALE);
+ style_widget->set_default_margin(SIDE_LEFT, widget_default_margin.x);
+ style_widget->set_default_margin(SIDE_TOP, widget_default_margin.y);
+ style_widget->set_default_margin(SIDE_RIGHT, widget_default_margin.x);
+ style_widget->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
style_widget->set_bg_color(dark_color_1);
style_widget->set_border_color(dark_color_2);
@@ -496,69 +496,84 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_widget_disabled->set_bg_color(disabled_bg_color);
Ref<StyleBoxFlat> style_widget_focus = style_widget->duplicate();
+ style_widget_focus->set_draw_center(false);
+ style_widget_focus->set_border_width_all(Math::round(2 * MAX(1, EDSCALE)));
style_widget_focus->set_border_color(accent_color);
Ref<StyleBoxFlat> style_widget_pressed = style_widget->duplicate();
- style_widget_pressed->set_border_color(accent_color);
+ style_widget_pressed->set_bg_color(dark_color_1.darkened(0.125));
Ref<StyleBoxFlat> style_widget_hover = style_widget->duplicate();
- style_widget_hover->set_border_color(contrast_color_1);
+ style_widget_hover->set_bg_color(mono_color * Color(1, 1, 1, 0.11));
+ style_widget_hover->set_border_color(mono_color * Color(1, 1, 1, 0.05));
- // style for windows, popups, etc..
+ // Style for windows, popups, etc..
Ref<StyleBoxFlat> style_popup = style_default->duplicate();
- const int popup_margin_size = default_margin_size * EDSCALE * 2;
+ const int popup_margin_size = default_margin_size * EDSCALE * 3;
style_popup->set_default_margin(SIDE_LEFT, popup_margin_size);
style_popup->set_default_margin(SIDE_TOP, popup_margin_size);
style_popup->set_default_margin(SIDE_RIGHT, popup_margin_size);
style_popup->set_default_margin(SIDE_BOTTOM, popup_margin_size);
style_popup->set_border_color(contrast_color_1);
- style_popup->set_border_width_all(MAX(EDSCALE, border_width));
const Color shadow_color = Color(0, 0, 0, dark_theme ? 0.3 : 0.1);
style_popup->set_shadow_color(shadow_color);
style_popup->set_shadow_size(4 * EDSCALE);
Ref<StyleBoxLine> style_popup_separator(memnew(StyleBoxLine));
style_popup_separator->set_color(separator_color);
- style_popup_separator->set_grow_begin(popup_margin_size - MAX(EDSCALE, border_width));
- style_popup_separator->set_grow_end(popup_margin_size - MAX(EDSCALE, border_width));
- style_popup_separator->set_thickness(MAX(EDSCALE, border_width));
+ style_popup_separator->set_grow_begin(popup_margin_size - MAX(Math::round(EDSCALE), border_width));
+ style_popup_separator->set_grow_end(popup_margin_size - MAX(Math::round(EDSCALE), border_width));
+ style_popup_separator->set_thickness(MAX(Math::round(EDSCALE), border_width));
Ref<StyleBoxLine> style_popup_labeled_separator_left(memnew(StyleBoxLine));
- style_popup_labeled_separator_left->set_grow_begin(popup_margin_size - MAX(EDSCALE, border_width));
+ style_popup_labeled_separator_left->set_grow_begin(popup_margin_size - MAX(Math::round(EDSCALE), border_width));
style_popup_labeled_separator_left->set_color(separator_color);
- style_popup_labeled_separator_left->set_thickness(MAX(EDSCALE, border_width));
+ style_popup_labeled_separator_left->set_thickness(MAX(Math::round(EDSCALE), border_width));
Ref<StyleBoxLine> style_popup_labeled_separator_right(memnew(StyleBoxLine));
- style_popup_labeled_separator_right->set_grow_end(popup_margin_size - MAX(EDSCALE, border_width));
+ style_popup_labeled_separator_right->set_grow_end(popup_margin_size - MAX(Math::round(EDSCALE), border_width));
style_popup_labeled_separator_right->set_color(separator_color);
- style_popup_labeled_separator_right->set_thickness(MAX(EDSCALE, border_width));
+ style_popup_labeled_separator_right->set_thickness(MAX(Math::round(EDSCALE), border_width));
Ref<StyleBoxEmpty> style_empty = make_empty_stylebox(default_margin_size, default_margin_size, default_margin_size, default_margin_size);
// Tabs
- const int tab_default_margin_side = 10 * EDSCALE + extra_spacing * EDSCALE;
- const int tab_default_margin_vertical = 5 * EDSCALE + extra_spacing * EDSCALE;
-
Ref<StyleBoxFlat> style_tab_selected = style_widget->duplicate();
- style_tab_selected->set_border_width_all(border_width);
- style_tab_selected->set_border_width(SIDE_BOTTOM, 0);
- style_tab_selected->set_border_color(dark_color_3);
- style_tab_selected->set_expand_margin_size(SIDE_BOTTOM, border_width);
- style_tab_selected->set_default_margin(SIDE_LEFT, tab_default_margin_side);
- style_tab_selected->set_default_margin(SIDE_RIGHT, tab_default_margin_side);
- style_tab_selected->set_default_margin(SIDE_BOTTOM, tab_default_margin_vertical);
- style_tab_selected->set_default_margin(SIDE_TOP, tab_default_margin_vertical);
- style_tab_selected->set_bg_color(tab_color);
+ // Add a highlight line at the top of the selected tab.
+ style_tab_selected->set_border_width_all(0);
+ style_tab_selected->set_border_width(SIDE_TOP, Math::round(2 * EDSCALE));
+ // Make the highlight line prominent, but not too prominent as to not be distracting.
+ style_tab_selected->set_border_color(dark_color_2.lerp(accent_color, 0.75));
+ // Don't round the top corners to avoid creating a small blank space between the tabs and the main panel.
+ // This also makes the top highlight look better.
+ style_tab_selected->set_corner_radius_all(0);
+
+ // Prevent visible artifacts and cover the top-left rounded corner of the panel below the tab if selected
+ // We can't prevent them with both rounded corners and non-zero border width, though
+ style_tab_selected->set_expand_margin_size(SIDE_BOTTOM, corner_width > 0 ? corner_width : border_width);
+
+ style_tab_selected->set_default_margin(SIDE_LEFT, widget_default_margin.x + 2 * EDSCALE);
+ style_tab_selected->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 2 * EDSCALE);
+ style_tab_selected->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
+ style_tab_selected->set_default_margin(SIDE_TOP, widget_default_margin.y);
+ style_tab_selected->set_bg_color(base_color);
Ref<StyleBoxFlat> style_tab_unselected = style_tab_selected->duplicate();
style_tab_unselected->set_bg_color(dark_color_1);
- style_tab_unselected->set_border_color(dark_color_2);
+ style_tab_unselected->set_expand_margin_size(SIDE_BOTTOM, 0);
+ // Add some spacing between unselected tabs to make them easier to distinguish from each other
+ style_tab_unselected->set_border_color(Color(0, 0, 0, 0));
+ style_tab_unselected->set_border_width(SIDE_LEFT, Math::round(1 * EDSCALE));
+ style_tab_unselected->set_border_width(SIDE_RIGHT, Math::round(1 * EDSCALE));
+ style_tab_unselected->set_default_margin(SIDE_LEFT, widget_default_margin.x + 2 * EDSCALE);
+ style_tab_unselected->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 2 * EDSCALE);
Ref<StyleBoxFlat> style_tab_disabled = style_tab_selected->duplicate();
style_tab_disabled->set_bg_color(disabled_bg_color);
- style_tab_disabled->set_border_color(disabled_color);
+ style_tab_disabled->set_expand_margin_size(SIDE_BOTTOM, 0);
+ style_tab_disabled->set_border_color(disabled_bg_color);
// Editor background
Color background_color_opaque = background_color;
@@ -566,10 +581,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("Background", "EditorStyles", make_flat_stylebox(background_color_opaque, default_margin_size, default_margin_size, default_margin_size, default_margin_size));
// Focus
- Ref<StyleBoxFlat> style_focus = style_default->duplicate();
- style_focus->set_draw_center(false);
- style_focus->set_border_color(contrast_color_2);
- theme->set_stylebox("Focus", "EditorStyles", style_focus);
+ theme->set_stylebox("Focus", "EditorStyles", style_widget_focus);
// Menu
Ref<StyleBoxFlat> style_menu = style_widget->duplicate();
@@ -585,33 +597,16 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Play button group
theme->set_stylebox("PlayButtonPanel", "EditorStyles", style_empty);
- //MenuButton
- Ref<StyleBoxFlat> style_menu_hover_border = style_widget->duplicate();
- style_menu_hover_border->set_draw_center(false);
- style_menu_hover_border->set_border_width_all(0);
- style_menu_hover_border->set_border_width(SIDE_BOTTOM, border_width);
- style_menu_hover_border->set_border_color(accent_color);
-
- Ref<StyleBoxFlat> style_menu_hover_bg = style_widget->duplicate();
- style_menu_hover_bg->set_border_width_all(0);
- style_menu_hover_bg->set_bg_color(dark_color_1);
-
theme->set_stylebox("normal", "MenuButton", style_menu);
- theme->set_stylebox("hover", "MenuButton", style_menu);
+ theme->set_stylebox("hover", "MenuButton", style_widget_hover);
theme->set_stylebox("pressed", "MenuButton", style_menu);
theme->set_stylebox("focus", "MenuButton", style_menu);
theme->set_stylebox("disabled", "MenuButton", style_menu);
- theme->set_stylebox("normal", "PopupMenu", style_menu);
- theme->set_stylebox("hover", "PopupMenu", style_menu_hover_bg);
- theme->set_stylebox("pressed", "PopupMenu", style_menu);
- theme->set_stylebox("focus", "PopupMenu", style_menu);
- theme->set_stylebox("disabled", "PopupMenu", style_menu);
-
theme->set_color("font_color", "MenuButton", font_color);
theme->set_color("font_hover_color", "MenuButton", font_hover_color);
- theme->set_stylebox("MenuHover", "EditorStyles", style_menu_hover_border);
+ theme->set_stylebox("MenuHover", "EditorStyles", style_widget_hover);
// Buttons
theme->set_stylebox("normal", "Button", style_widget);
@@ -646,7 +641,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_disabled_color", "OptionButton", font_disabled_color);
theme->set_color("icon_hover_color", "OptionButton", icon_hover_color);
theme->set_icon("arrow", "OptionButton", theme->get_icon("GuiOptionArrow", "EditorIcons"));
- theme->set_constant("arrow_margin", "OptionButton", default_margin_size * EDSCALE);
+ theme->set_constant("arrow_margin", "OptionButton", widget_default_margin.x - 2 * EDSCALE);
theme->set_constant("modulate_arrow", "OptionButton", true);
theme->set_constant("hseparation", "OptionButton", 4 * EDSCALE);
@@ -672,7 +667,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_disabled_color", "CheckButton", font_disabled_color);
theme->set_color("icon_hover_color", "CheckButton", icon_hover_color);
- theme->set_constant("hseparation", "CheckButton", 4 * EDSCALE);
+ theme->set_constant("hseparation", "CheckButton", 8 * EDSCALE);
theme->set_constant("check_vadjust", "CheckButton", 0 * EDSCALE);
// Checkbox
@@ -697,7 +692,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_disabled_color", "CheckBox", font_disabled_color);
theme->set_color("icon_hover_color", "CheckBox", icon_hover_color);
- theme->set_constant("hseparation", "CheckBox", 4 * EDSCALE);
+ theme->set_constant("hseparation", "CheckBox", 8 * EDSCALE);
theme->set_constant("check_vadjust", "CheckBox", 0 * EDSCALE);
// PopupDialog
@@ -713,8 +708,16 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_popup_menu->set_default_margin(SIDE_TOP, popup_menu_margin_size);
style_popup_menu->set_default_margin(SIDE_RIGHT, 1 * EDSCALE);
style_popup_menu->set_default_margin(SIDE_BOTTOM, popup_menu_margin_size);
-
+ // Always display a border for PopupMenus so they can be distinguished from their background.
+ style_popup_menu->set_border_width_all(1 * EDSCALE);
+ style_popup_menu->set_border_color(dark_color_2);
theme->set_stylebox("panel", "PopupMenu", style_popup_menu);
+
+ Ref<StyleBoxFlat> style_menu_hover = style_widget_hover->duplicate();
+ // Don't use rounded corners for hover highlights since the StyleBox touches the PopupMenu's edges.
+ style_menu_hover->set_corner_radius_all(0);
+ theme->set_stylebox("hover", "PopupMenu", style_menu_hover);
+
theme->set_stylebox("separator", "PopupMenu", style_popup_separator);
theme->set_stylebox("labeled_separator_left", "PopupMenu", style_popup_labeled_separator_left);
theme->set_stylebox("labeled_separator_right", "PopupMenu", style_popup_labeled_separator_right);
@@ -783,23 +786,25 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_property_bg->set_bg_color(highlight_color);
style_property_bg->set_border_width_all(0);
- theme->set_constant("font_offset", "EditorProperty", 1 * EDSCALE);
+ theme->set_constant("font_offset", "EditorProperty", 8 * EDSCALE);
theme->set_stylebox("bg_selected", "EditorProperty", style_property_bg);
theme->set_stylebox("bg", "EditorProperty", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty)));
theme->set_constant("vseparation", "EditorProperty", (extra_spacing + default_margin_size) * EDSCALE);
theme->set_color("error_color", "EditorProperty", error_color);
theme->set_color("property_color", "EditorProperty", property_color);
- theme->set_constant("inspector_margin", "Editor", 8 * EDSCALE);
+ Color inspector_section_color = font_color.lerp(Color(0.5, 0.5, 0.5), 0.35);
+ theme->set_color("font_color", "EditorInspectorSection", inspector_section_color);
+
+ theme->set_constant("inspector_margin", "Editor", 12 * EDSCALE);
// Tree & ItemList background
Ref<StyleBoxFlat> style_tree_bg = style_default->duplicate();
- style_tree_bg->set_bg_color(dark_color_1);
+ // Make Trees easier to distinguish from other controls by using a darker background color.
+ style_tree_bg->set_bg_color(dark_color_1.lerp(dark_color_2, 0.5));
style_tree_bg->set_border_color(dark_color_3);
theme->set_stylebox("bg", "Tree", style_tree_bg);
- const Color guide_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.05);
- Color relationship_line_color = Color(mono_color.r, mono_color.g, mono_color.b, relationship_line_opacity);
// Tree
theme->set_icon("checked", "Tree", theme->get_icon("GuiChecked", "EditorIcons"));
theme->set_icon("unchecked", "Tree", theme->get_icon("GuiUnchecked", "EditorIcons"));
@@ -808,7 +813,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("arrow_collapsed_mirrored", "Tree", theme->get_icon("GuiTreeArrowLeft", "EditorIcons"));
theme->set_icon("updown", "Tree", theme->get_icon("GuiTreeUpdown", "EditorIcons"));
theme->set_icon("select_arrow", "Tree", theme->get_icon("GuiDropdown", "EditorIcons"));
- theme->set_stylebox("bg_focus", "Tree", style_focus);
+ theme->set_stylebox("bg_focus", "Tree", style_widget_focus);
theme->set_stylebox("custom_button", "Tree", make_empty_stylebox());
theme->set_stylebox("custom_button_pressed", "Tree", make_empty_stylebox());
theme->set_stylebox("custom_button_hover", "Tree", style_widget);
@@ -816,20 +821,35 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "Tree", font_color);
theme->set_color("font_selected_color", "Tree", mono_color);
theme->set_color("title_button_color", "Tree", font_color);
- theme->set_color("guide_color", "Tree", guide_color);
- theme->set_color("relationship_line_color", "Tree", relationship_line_color);
theme->set_color("drop_position_color", "Tree", accent_color);
- theme->set_constant("vseparation", "Tree", (extra_spacing + default_margin_size) * EDSCALE);
- theme->set_constant("hseparation", "Tree", (extra_spacing + default_margin_size) * EDSCALE);
+ theme->set_constant("vseparation", "Tree", widget_default_margin.y - EDSCALE);
+ theme->set_constant("hseparation", "Tree", 6 * EDSCALE);
+ theme->set_constant("guide_width", "Tree", border_width);
theme->set_constant("item_margin", "Tree", 3 * default_margin_size * EDSCALE);
theme->set_constant("button_margin", "Tree", default_margin_size * EDSCALE);
- theme->set_constant("draw_relationship_lines", "Tree", relationship_line_opacity >= 0.01);
- theme->set_constant("draw_guides", "Tree", relationship_line_opacity < 0.01);
theme->set_constant("scroll_border", "Tree", 40 * EDSCALE);
theme->set_constant("scroll_speed", "Tree", 12);
+ const Color guide_color = mono_color * Color(1, 1, 1, 0.05);
+ Color relationship_line_color = mono_color * Color(1, 1, 1, relationship_line_opacity);
+
+ theme->set_constant("draw_guides", "Tree", relationship_line_opacity < 0.01);
+ theme->set_color("guide_color", "Tree", guide_color);
+
+ int relationship_line_width = 1;
+ Color parent_line_color = mono_color * Color(1, 1, 1, CLAMP(relationship_line_opacity + 0.45, 0.0, 1.0));
+ Color children_line_color = mono_color * Color(1, 1, 1, CLAMP(relationship_line_opacity + 0.25, 0.0, 1.0));
+ theme->set_constant("draw_relationship_lines", "Tree", relationship_line_opacity >= 0.01);
+ theme->set_constant("relationship_line_width", "Tree", relationship_line_width);
+ theme->set_constant("parent_hl_line_width", "Tree", relationship_line_width * 2);
+ theme->set_constant("children_hl_line_width", "Tree", relationship_line_width);
+ theme->set_constant("parent_hl_line_margin", "Tree", relationship_line_width * 3);
+ theme->set_color("relationship_line_color", "Tree", relationship_line_color);
+ theme->set_color("parent_hl_line_color", "Tree", parent_line_color);
+ theme->set_color("children_hl_line_color", "Tree", children_line_color);
+
Ref<StyleBoxFlat> style_tree_btn = style_default->duplicate();
- style_tree_btn->set_bg_color(contrast_color_1);
+ style_tree_btn->set_bg_color(highlight_color);
style_tree_btn->set_border_width_all(0);
theme->set_stylebox("button_pressed", "Tree", style_tree_btn);
@@ -868,6 +888,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("prop_subsection", "Editor", prop_subsection_color);
theme->set_color("drop_position_color", "Tree", accent_color);
+ Ref<StyleBoxFlat> category_bg = style_default->duplicate();
+ // Make Trees easier to distinguish from other controls by using a darker background color.
+ category_bg->set_bg_color(prop_category_color);
+ category_bg->set_border_color(prop_category_color);
+ theme->set_stylebox("prop_category_style", "Editor", category_bg);
+
// ItemList
Ref<StyleBoxFlat> style_itemlist_bg = style_default->duplicate();
style_itemlist_bg->set_bg_color(dark_color_1);
@@ -882,14 +908,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("cursor_unfocused", "ItemList", style_itemlist_cursor);
theme->set_stylebox("selected_focus", "ItemList", style_tree_focus);
theme->set_stylebox("selected", "ItemList", style_tree_selected);
- theme->set_stylebox("bg_focus", "ItemList", style_focus);
+ theme->set_stylebox("bg_focus", "ItemList", style_widget_focus);
theme->set_stylebox("bg", "ItemList", style_itemlist_bg);
theme->set_color("font_color", "ItemList", font_color);
theme->set_color("font_selected_color", "ItemList", mono_color);
theme->set_color("guide_color", "ItemList", guide_color);
- theme->set_constant("vseparation", "ItemList", 3 * EDSCALE);
- theme->set_constant("hseparation", "ItemList", 3 * EDSCALE);
- theme->set_constant("icon_margin", "ItemList", default_margin_size * EDSCALE);
+ theme->set_constant("vseparation", "ItemList", widget_default_margin.y - EDSCALE);
+ theme->set_constant("hseparation", "ItemList", 6 * EDSCALE);
+ theme->set_constant("icon_margin", "ItemList", 6 * EDSCALE);
theme->set_constant("line_separation", "ItemList", 3 * EDSCALE);
// Tabs & TabContainer
@@ -925,23 +951,43 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_content_panel->set_border_color(dark_color_3);
style_content_panel->set_border_width_all(border_width);
// compensate the border
- style_content_panel->set_default_margin(SIDE_TOP, margin_size_extra * EDSCALE);
+ style_content_panel->set_default_margin(SIDE_TOP, (2 + margin_size_extra) * EDSCALE);
style_content_panel->set_default_margin(SIDE_RIGHT, margin_size_extra * EDSCALE);
style_content_panel->set_default_margin(SIDE_BOTTOM, margin_size_extra * EDSCALE);
style_content_panel->set_default_margin(SIDE_LEFT, margin_size_extra * EDSCALE);
+ // Display border to visually split the body of the container from its possible backgrounds.
+ style_content_panel->set_border_width(Side::SIDE_TOP, Math::round(2 * EDSCALE));
+ style_content_panel->set_border_color(dark_color_2);
+ theme->set_stylebox("panel", "TabContainer", style_content_panel);
+
+ // These styleboxes can be used on tabs against the base color background (e.g. nested tabs).
+ Ref<StyleBoxFlat> style_tab_selected_odd = style_tab_selected->duplicate();
+ style_tab_selected_odd->set_bg_color(disabled_bg_color);
+ theme->set_stylebox("tab_selected_odd", "TabContainer", style_tab_selected_odd);
- // this is the stylebox used in 3d and 2d viewports (no borders)
+ Ref<StyleBoxFlat> style_content_panel_odd = style_content_panel->duplicate();
+ style_content_panel_odd->set_bg_color(disabled_bg_color);
+ theme->set_stylebox("panel_odd", "TabContainer", style_content_panel_odd);
+
+ // This stylebox is used in 3d and 2d viewports (no borders).
Ref<StyleBoxFlat> style_content_panel_vp = style_content_panel->duplicate();
style_content_panel_vp->set_default_margin(SIDE_LEFT, border_width * 2);
style_content_panel_vp->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE);
style_content_panel_vp->set_default_margin(SIDE_RIGHT, border_width * 2);
style_content_panel_vp->set_default_margin(SIDE_BOTTOM, border_width * 2);
- theme->set_stylebox("panel", "TabContainer", style_content_panel);
theme->set_stylebox("Content", "EditorStyles", style_content_panel_vp);
+ // This stylebox is used by preview tabs in the Theme Editor.
+ Ref<StyleBoxFlat> style_theme_preview_tab = style_tab_selected_odd->duplicate();
+ style_theme_preview_tab->set_expand_margin_size(SIDE_BOTTOM, 5 * EDSCALE);
+ theme->set_stylebox("ThemeEditorPreviewFG", "EditorStyles", style_theme_preview_tab);
+ Ref<StyleBoxFlat> style_theme_preview_bg_tab = style_tab_unselected->duplicate();
+ style_theme_preview_bg_tab->set_expand_margin_size(SIDE_BOTTOM, 2 * EDSCALE);
+ theme->set_stylebox("ThemeEditorPreviewBG", "EditorStyles", style_theme_preview_bg_tab);
+
// Separators
- theme->set_stylebox("separator", "HSeparator", make_line_stylebox(separator_color, border_width));
- theme->set_stylebox("separator", "VSeparator", make_line_stylebox(separator_color, border_width, 0, 0, true));
+ theme->set_stylebox("separator", "HSeparator", make_line_stylebox(separator_color, MAX(Math::round(EDSCALE), border_width)));
+ theme->set_stylebox("separator", "VSeparator", make_line_stylebox(separator_color, MAX(Math::round(EDSCALE), border_width), 0, 0, true));
// Debugger
@@ -956,9 +1002,23 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("BottomPanelDebuggerOverride", "EditorStyles", style_panel_invisible_top);
// LineEdit
- theme->set_stylebox("normal", "LineEdit", style_widget);
+
+ Ref<StyleBoxFlat> style_line_edit = style_widget->duplicate();
+ // Add a bottom line to make LineEdits more visible, especially in sectioned inspectors
+ // such as the Project Settings.
+ style_line_edit->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE));
+ style_line_edit->set_border_color(dark_color_2);
+ // Don't round the bottom corner to make the line look sharper.
+ style_tab_selected->set_corner_radius(CORNER_BOTTOM_LEFT, 0);
+ style_tab_selected->set_corner_radius(CORNER_BOTTOM_RIGHT, 0);
+
+ Ref<StyleBoxFlat> style_line_edit_disabled = style_line_edit->duplicate();
+ style_line_edit_disabled->set_border_color(disabled_color);
+ style_line_edit_disabled->set_bg_color(disabled_bg_color);
+
+ theme->set_stylebox("normal", "LineEdit", style_line_edit);
theme->set_stylebox("focus", "LineEdit", style_widget_focus);
- theme->set_stylebox("read_only", "LineEdit", style_widget_disabled);
+ theme->set_stylebox("read_only", "LineEdit", style_line_edit_disabled);
theme->set_icon("clear", "LineEdit", theme->get_icon("GuiClose", "EditorIcons"));
theme->set_color("read_only", "LineEdit", font_disabled_color);
theme->set_color("font_color", "LineEdit", font_color);
@@ -969,9 +1029,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("clear_button_color_pressed", "LineEdit", accent_color);
// TextEdit
- theme->set_stylebox("normal", "TextEdit", style_widget);
- theme->set_stylebox("focus", "TextEdit", style_widget_hover);
- theme->set_stylebox("read_only", "TextEdit", style_widget_disabled);
+ theme->set_stylebox("normal", "TextEdit", style_line_edit);
+ theme->set_stylebox("focus", "TextEdit", style_widget_focus);
+ theme->set_stylebox("read_only", "TextEdit", style_line_edit_disabled);
theme->set_constant("side_margin", "TabContainer", 0);
theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons"));
theme->set_icon("space", "TextEdit", theme->get_icon("GuiSpace", "EditorIcons"));
@@ -1014,14 +1074,22 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("hseparation", "GridContainer", default_margin_size * EDSCALE);
theme->set_constant("vseparation", "GridContainer", default_margin_size * EDSCALE);
- // WindowDialog
+ // Window
+
+ // Prevent corner artifacts between window title and body.
+ Ref<StyleBoxFlat> style_window_title = style_default->duplicate();
+ style_window_title->set_corner_radius(CORNER_TOP_LEFT, 0);
+ style_window_title->set_corner_radius(CORNER_TOP_RIGHT, 0);
+ // Prevent visible line between window title and body.
+ style_window_title->set_expand_margin_size(SIDE_BOTTOM, 2 * EDSCALE);
+ theme->set_stylebox("panel", "Window", style_window_title);
+
Ref<StyleBoxFlat> style_window = style_popup->duplicate();
- style_window->set_border_color(tab_color);
+ style_window->set_border_color(base_color);
style_window->set_border_width(SIDE_TOP, 24 * EDSCALE);
style_window->set_expand_margin_size(SIDE_TOP, 24 * EDSCALE);
-
- 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"));
@@ -1032,10 +1100,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_font("title_font", "Window", theme->get_font("title", "EditorFonts"));
theme->set_font_size("title_font_size", "Window", theme->get_font_size("title_size", "EditorFonts"));
- // complex window, for now only Editor settings and Project settings
+ // Complex window (currently only Editor Settings and Project Settings)
Ref<StyleBoxFlat> style_complex_window = style_window->duplicate();
style_complex_window->set_bg_color(dark_color_2);
- style_complex_window->set_border_color(highlight_tabs ? tab_color : dark_color_2);
+ style_complex_window->set_border_color(dark_color_2);
theme->set_stylebox("panel", "EditorSettingsDialog", style_complex_window);
theme->set_stylebox("panel", "ProjectSettingsEditor", style_complex_window);
theme->set_stylebox("panel", "EditorAbout", style_complex_window);
@@ -1069,18 +1137,18 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// HSlider
theme->set_icon("grabber_highlight", "HSlider", theme->get_icon("GuiSliderGrabberHl", "EditorIcons"));
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("slider", "HSlider", make_flat_stylebox(dark_color_3, 0, default_margin_size / 2, 0, default_margin_size / 2, corner_width));
+ theme->set_stylebox("grabber_area", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2, corner_width));
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("slider", "VSlider", make_flat_stylebox(dark_color_3, default_margin_size / 2, 0, default_margin_size / 2, 0, corner_width));
+ theme->set_stylebox("grabber_area", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0, corner_width));
theme->set_stylebox("grabber_area_highlight", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0));
- //RichTextLabel
+ // RichTextLabel
theme->set_color("default_color", "RichTextLabel", font_color);
theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * EDSCALE);
@@ -1092,7 +1160,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("headline_color", "EditorHelp", mono_color);
// Panel
- theme->set_stylebox("panel", "Panel", make_flat_stylebox(dark_color_1, 6, 4, 6, 4));
+ theme->set_stylebox("panel", "Panel", make_flat_stylebox(dark_color_1, 6, 4, 6, 4, corner_width));
theme->set_stylebox("panel_fg", "Panel", style_default);
// Label
@@ -1113,16 +1181,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// TooltipPanel
Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate();
- float v = MAX(border_size * EDSCALE, 1.0);
- style_tooltip->set_default_margin(SIDE_LEFT, v);
- style_tooltip->set_default_margin(SIDE_TOP, v);
- style_tooltip->set_default_margin(SIDE_RIGHT, v);
- style_tooltip->set_default_margin(SIDE_BOTTOM, v);
- style_tooltip->set_bg_color(Color(mono_color.r, mono_color.g, mono_color.b, 0.9));
- style_tooltip->set_border_width_all(border_width);
- style_tooltip->set_border_color(mono_color);
- theme->set_color("font_color", "TooltipLabel", font_color.inverted());
- theme->set_color("font_shadow_color", "TooltipLabel", mono_color.inverted() * Color(1, 1, 1, 0.1));
+ style_tooltip->set_shadow_size(0);
+ style_tooltip->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE);
+ style_tooltip->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE * 0.5);
+ style_tooltip->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE);
+ style_tooltip->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE * 0.5);
+ style_tooltip->set_bg_color(mono_color.inverted() * Color(1, 1, 1, 0.8));
+ style_tooltip->set_border_width_all(0);
+ theme->set_color("font_color", "TooltipLabel", font_hover_color);
+ theme->set_color("font_color_shadow", "TooltipLabel", Color(0, 0, 0, 0));
theme->set_stylebox("panel", "TooltipPanel", style_tooltip);
// PopupPanel
@@ -1189,23 +1256,20 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("resizer_color", "GraphEditMinimap", minimap_resizer_color);
// GraphNode
- const float mv = dark_theme ? 0.0 : 1.0;
- const float mv2 = 1.0 - mv;
const int gn_margin_side = 28;
- Ref<StyleBoxFlat> graphsb = make_flat_stylebox(Color(mv, mv, mv, 0.7), gn_margin_side, 24, gn_margin_side, 5);
+
+ Ref<StyleBoxFlat> graphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), gn_margin_side, 24, gn_margin_side, 5, corner_width);
graphsb->set_border_width_all(border_width);
- graphsb->set_border_color(Color(mv2, mv2, mv2, 0.9));
- Ref<StyleBoxFlat> graphsbselected = make_flat_stylebox(Color(mv, mv, mv, 0.9), gn_margin_side, 24, gn_margin_side, 5);
- graphsbselected->set_border_width_all(border_width);
+ graphsb->set_border_color(dark_color_3);
+ Ref<StyleBoxFlat> graphsbselected = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.9), gn_margin_side, 24, gn_margin_side, 5, corner_width);
+ graphsbselected->set_border_width_all(2 * EDSCALE + border_width);
graphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
- graphsbselected->set_shadow_size(8 * EDSCALE);
- graphsbselected->set_shadow_color(shadow_color);
- Ref<StyleBoxFlat> graphsbcomment = make_flat_stylebox(Color(mv, mv, mv, 0.3), gn_margin_side, 24, gn_margin_side, 5);
+ Ref<StyleBoxFlat> graphsbcomment = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.3), gn_margin_side, 24, gn_margin_side, 5, corner_width);
graphsbcomment->set_border_width_all(border_width);
- graphsbcomment->set_border_color(Color(mv2, mv2, mv2, 0.9));
- Ref<StyleBoxFlat> graphsbcommentselected = make_flat_stylebox(Color(mv, mv, mv, 0.4), gn_margin_side, 24, gn_margin_side, 5);
+ graphsbcomment->set_border_color(dark_color_3);
+ Ref<StyleBoxFlat> graphsbcommentselected = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.4), gn_margin_side, 24, gn_margin_side, 5, corner_width);
graphsbcommentselected->set_border_width_all(border_width);
- graphsbcommentselected->set_border_color(Color(mv2, mv2, mv2, 0.9));
+ graphsbcommentselected->set_border_color(dark_color_3);
Ref<StyleBoxFlat> graphsbbreakpoint = graphsbselected->duplicate();
graphsbbreakpoint->set_draw_center(false);
graphsbbreakpoint->set_border_color(warning_color);
@@ -1214,21 +1278,19 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
graphsbposition->set_draw_center(false);
graphsbposition->set_border_color(error_color);
graphsbposition->set_shadow_color(error_color * Color(1.0, 1.0, 1.0, 0.2));
- Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(Color(mv, mv, mv, 0.7), gn_margin_side, 24, gn_margin_side, 5);
+ Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), gn_margin_side, 24, gn_margin_side, 5, corner_width);
smgraphsb->set_border_width_all(border_width);
- smgraphsb->set_border_color(Color(mv2, mv2, mv2, 0.9));
- Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(Color(mv, mv, mv, 0.9), gn_margin_side, 24, gn_margin_side, 5);
- smgraphsbselected->set_border_width_all(border_width);
+ smgraphsb->set_border_color(dark_color_3);
+ Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.9), gn_margin_side, 24, gn_margin_side, 5, corner_width);
+ smgraphsbselected->set_border_width_all(2 * EDSCALE + border_width);
smgraphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
smgraphsbselected->set_shadow_size(8 * EDSCALE);
smgraphsbselected->set_shadow_color(shadow_color);
- if (use_gn_headers) {
- graphsb->set_border_width(SIDE_TOP, 24 * EDSCALE);
- graphsbselected->set_border_width(SIDE_TOP, 24 * EDSCALE);
- graphsbcomment->set_border_width(SIDE_TOP, 24 * EDSCALE);
- graphsbcommentselected->set_border_width(SIDE_TOP, 24 * EDSCALE);
- }
+ graphsb->set_border_width(SIDE_TOP, 24 * EDSCALE);
+ graphsbselected->set_border_width(SIDE_TOP, 24 * EDSCALE);
+ graphsbcomment->set_border_width(SIDE_TOP, 24 * EDSCALE);
+ graphsbcommentselected->set_border_width(SIDE_TOP, 24 * EDSCALE);
theme->set_stylebox("frame", "GraphNode", graphsb);
theme->set_stylebox("selectedframe", "GraphNode", graphsbselected);
@@ -1239,7 +1301,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("state_machine_frame", "GraphNode", smgraphsb);
theme->set_stylebox("state_machine_selectedframe", "GraphNode", smgraphsbselected);
- Color default_node_color = Color(mv2, mv2, mv2);
+ Color default_node_color = dark_color_1.inverted();
theme->set_color("title_color", "GraphNode", default_node_color);
default_node_color.a = 0.7;
theme->set_color("close_color", "GraphNode", default_node_color);
@@ -1257,7 +1319,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("port", "GraphNode", theme->get_icon("GuiGraphNodePort", "EditorIcons"));
// GridContainer
- theme->set_constant("vseparation", "GridContainer", (extra_spacing + default_margin_size) * EDSCALE);
+ theme->set_constant("vseparation", "GridContainer", Math::round(widget_default_margin.y - 2 * EDSCALE));
// FileDialog
theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons"));
@@ -1292,6 +1354,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_info_3d_viewport->set_border_width_all(0);
theme->set_stylebox("Information3dViewport", "EditorStyles", style_info_3d_viewport);
+ // Theme editor.
+ theme->set_color("preview_picker_overlay_color", "ThemeEditor", Color(0.1, 0.1, 0.1, 0.25));
+ Color theme_preview_picker_bg_color = accent_color;
+ theme_preview_picker_bg_color.a = 0.2;
+ Ref<StyleBoxFlat> theme_preview_picker_sb = make_flat_stylebox(theme_preview_picker_bg_color, 0, 0, 0, 0);
+ theme_preview_picker_sb->set_border_color(accent_color);
+ theme_preview_picker_sb->set_border_width_all(1.0 * EDSCALE);
+ theme->set_stylebox("preview_picker_overlay", "ThemeEditor", theme_preview_picker_sb);
+
// adaptive script theme constants
// for comments and elements with lower relevance
const Color dim_color = Color(font_color.r, font_color.g, font_color.b, 0.5);
@@ -1306,13 +1377,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color symbol_color = Color(0.34, 0.57, 1.0).lerp(mono_color, dark_theme ? 0.5 : 0.3);
const Color keyword_color = Color(1.0, 0.44, 0.52);
+ const Color control_flow_keyword_color = dark_theme ? Color(1.0, 0.55, 0.8) : Color(0.8, 0.4, 0.6);
const Color basetype_color = dark_theme ? Color(0.26, 1.0, 0.76) : Color(0.0, 0.76, 0.38);
const Color type_color = basetype_color.lerp(mono_color, dark_theme ? 0.4 : 0.3);
const Color usertype_color = basetype_color.lerp(mono_color, dark_theme ? 0.7 : 0.5);
const Color comment_color = dim_color;
const Color string_color = (dark_theme ? Color(1.0, 0.85, 0.26) : Color(1.0, 0.82, 0.09)).lerp(mono_color, dark_theme ? 0.5 : 0.3);
- const Color te_background_color = dark_theme ? background_color : base_color;
+ // Use the brightest background color on a light theme (which generally uses a negative contrast rate).
+ const Color te_background_color = dark_theme ? background_color : dark_color_3;
const Color completion_background_color = dark_theme ? base_color : background_color;
const Color completion_selected_color = alpha1;
const Color completion_existing_color = alpha2;
@@ -1341,9 +1414,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
EditorSettings *setting = EditorSettings::get_singleton();
String text_editor_color_theme = setting->get("text_editor/theme/color_theme");
- if (text_editor_color_theme == "Adaptive") {
+ if (text_editor_color_theme == "Default") {
setting->set_initial_value("text_editor/highlighting/symbol_color", symbol_color, true);
setting->set_initial_value("text_editor/highlighting/keyword_color", keyword_color, true);
+ setting->set_initial_value("text_editor/highlighting/control_flow_keyword_color", control_flow_keyword_color, true);
setting->set_initial_value("text_editor/highlighting/base_type_color", basetype_color, true);
setting->set_initial_value("text_editor/highlighting/engine_type_color", type_color, true);
setting->set_initial_value("text_editor/highlighting/user_type_color", usertype_color, true);
@@ -1376,7 +1450,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
setting->set_initial_value("text_editor/highlighting/code_folding_color", code_folding_color, true);
setting->set_initial_value("text_editor/highlighting/search_result_color", search_result_color, true);
setting->set_initial_value("text_editor/highlighting/search_result_border_color", search_result_border_color, true);
- } else if (text_editor_color_theme == "Default") {
+ } else if (text_editor_color_theme == "Godot 2") {
setting->load_text_editor_theme();
}
diff --git a/editor/editor_translation_parser.cpp b/editor/editor_translation_parser.cpp
index fd36372dde..27d428e682 100644
--- a/editor/editor_translation_parser.cpp
+++ b/editor/editor_translation_parser.cpp
@@ -31,8 +31,8 @@
#include "editor_translation_parser.h"
#include "core/error/error_macros.h"
+#include "core/io/file_access.h"
#include "core/object/script_language.h"
-#include "core/os/file_access.h"
#include "core/templates/set.h"
EditorTranslationParser *EditorTranslationParser::singleton = nullptr;
@@ -42,10 +42,10 @@ Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<Str
return ERR_UNAVAILABLE;
}
- if (get_script_instance()->has_method("parse_file")) {
+ if (get_script_instance()->has_method("_parse_file")) {
Array ids;
Array ids_ctx_plural;
- get_script_instance()->call("parse_file", p_path, ids, ids_ctx_plural);
+ get_script_instance()->call("_parse_file", p_path, ids, ids_ctx_plural);
// Add user's extracted translatable messages.
for (int i = 0; i < ids.size(); i++) {
@@ -75,8 +75,8 @@ void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_ex
return;
}
- if (get_script_instance()->has_method("get_recognized_extensions")) {
- Array extensions = get_script_instance()->call("get_recognized_extensions");
+ if (get_script_instance()->has_method("_get_recognized_extensions")) {
+ Array extensions = get_script_instance()->call("_get_recognized_extensions");
for (int i = 0; i < extensions.size(); i++) {
r_extensions->push_back(extensions[i]);
}
@@ -86,8 +86,8 @@ void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_ex
}
void EditorTranslationParserPlugin::_bind_methods() {
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::NIL, "parse_file", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::ARRAY, "msgids"), PropertyInfo(Variant::ARRAY, "msgids_context_plural")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "get_recognized_extensions"));
+ BIND_VMETHOD(MethodInfo(Variant::NIL, "_parse_file", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::ARRAY, "msgids"), PropertyInfo(Variant::ARRAY, "msgids_context_plural")));
+ BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_recognized_extensions"));
}
/////////////////////////
@@ -105,7 +105,7 @@ void EditorTranslationParser::get_recognized_extensions(List<String> *r_extensio
for (int i = 0; i < temp.size(); i++) {
extensions.insert(temp[i]);
}
- for (auto E = extensions.front(); E; E = E->next()) {
+ for (Set<String>::Element *E = extensions.front(); E; E = E->next()) {
r_extensions->push_back(E->get());
}
}
diff --git a/editor/editor_translation_parser.h b/editor/editor_translation_parser.h
index 4f8f3537f2..7013bbb8c4 100644
--- a/editor/editor_translation_parser.h
+++ b/editor/editor_translation_parser.h
@@ -32,10 +32,10 @@
#define EDITOR_TRANSLATION_PARSER_H
#include "core/error/error_list.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class EditorTranslationParserPlugin : public Reference {
- GDCLASS(EditorTranslationParserPlugin, Reference);
+class EditorTranslationParserPlugin : public RefCounted {
+ GDCLASS(EditorTranslationParserPlugin, RefCounted);
protected:
static void _bind_methods();
diff --git a/editor/editor_zoom_widget.cpp b/editor/editor_zoom_widget.cpp
new file mode 100644
index 0000000000..f9be829493
--- /dev/null
+++ b/editor/editor_zoom_widget.cpp
@@ -0,0 +1,163 @@
+/*************************************************************************/
+/* editor_zoom_widget.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_zoom_widget.h"
+
+#include "core/os/keyboard.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+
+void EditorZoomWidget::_update_zoom_label() {
+ String zoom_text;
+ // The zoom level displayed is relative to the editor scale
+ // (like in most image editors). Its lower bound is clamped to 1 as some people
+ // lower the editor scale to increase the available real estate,
+ // even if their display doesn't have a particularly low DPI.
+ if (zoom >= 10) {
+ // Don't show a decimal when the zoom level is higher than 1000 %.
+ zoom_text = TS->format_number(rtos(Math::round((zoom / MAX(1, EDSCALE)) * 100))) + " " + TS->percent_sign();
+ } else {
+ zoom_text = TS->format_number(rtos(Math::snapped((zoom / MAX(1, EDSCALE)) * 100, 0.1))) + " " + TS->percent_sign();
+ }
+
+ zoom_reset->set_text(zoom_text);
+}
+
+void EditorZoomWidget::_button_zoom_minus() {
+ set_zoom_by_increments(-6);
+ emit_signal("zoom_changed", zoom);
+}
+
+void EditorZoomWidget::_button_zoom_reset() {
+ set_zoom(1.0);
+ emit_signal("zoom_changed", zoom);
+}
+
+void EditorZoomWidget::_button_zoom_plus() {
+ set_zoom_by_increments(6);
+ emit_signal("zoom_changed", zoom);
+}
+
+float EditorZoomWidget::get_zoom() {
+ return zoom;
+}
+
+void EditorZoomWidget::set_zoom(float p_zoom) {
+ if (p_zoom > 0 && p_zoom != zoom) {
+ zoom = p_zoom;
+ _update_zoom_label();
+ }
+}
+
+void EditorZoomWidget::set_zoom_by_increments(int p_increment_count) {
+ // Base increment factor defined as the twelveth root of two.
+ // This allow a smooth geometric evolution of the zoom, with the advantage of
+ // visiting all integer power of two scale factors.
+ // note: this is analogous to the 'semitones' interval in the music world
+ // In order to avoid numerical imprecisions, we compute and edit a zoom index
+ // with the following relation: zoom = 2 ^ (index / 12)
+
+ if (zoom < CMP_EPSILON || p_increment_count == 0) {
+ return;
+ }
+
+ // Remove Editor scale from the index computation
+ float zoom_noscale = zoom / MAX(1, EDSCALE);
+
+ // zoom = 2**(index/12) => log2(zoom) = index/12
+ float closest_zoom_index = Math::round(Math::log(zoom_noscale) * 12.f / Math::log(2.f));
+
+ float new_zoom_index = closest_zoom_index + p_increment_count;
+ float new_zoom = Math::pow(2.f, new_zoom_index / 12.f);
+
+ // Restore Editor scale transformation
+ new_zoom *= MAX(1, EDSCALE);
+
+ set_zoom(new_zoom);
+}
+
+void EditorZoomWidget::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ zoom_minus->set_icon(get_theme_icon("ZoomLess", "EditorIcons"));
+ zoom_plus->set_icon(get_theme_icon("ZoomMore", "EditorIcons"));
+ break;
+ default:
+ break;
+ }
+}
+
+void EditorZoomWidget::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &EditorZoomWidget::set_zoom);
+ ClassDB::bind_method(D_METHOD("get_zoom"), &EditorZoomWidget::get_zoom);
+ ClassDB::bind_method(D_METHOD("set_zoom_by_increments", "increment"), &EditorZoomWidget::set_zoom_by_increments);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom"), "set_zoom", "get_zoom");
+
+ ADD_SIGNAL(MethodInfo("zoom_changed", PropertyInfo(Variant::FLOAT, "zoom")));
+}
+
+EditorZoomWidget::EditorZoomWidget() {
+ // Zoom buttons
+ zoom_minus = memnew(Button);
+ zoom_minus->set_flat(true);
+ add_child(zoom_minus);
+ zoom_minus->connect("pressed", callable_mp(this, &EditorZoomWidget::_button_zoom_minus));
+ zoom_minus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", TTR("Zoom Out"), KEY_MASK_CMD | KEY_MINUS));
+ zoom_minus->set_shortcut_context(this);
+ zoom_minus->set_focus_mode(FOCUS_NONE);
+
+ zoom_reset = memnew(Button);
+ zoom_reset->set_flat(true);
+ add_child(zoom_reset);
+ zoom_reset->add_theme_constant_override("outline_size", 1);
+ zoom_reset->add_theme_color_override("font_outline_color", Color(0, 0, 0));
+ zoom_reset->add_theme_color_override("font_color", Color(1, 1, 1));
+ zoom_reset->connect("pressed", callable_mp(this, &EditorZoomWidget::_button_zoom_reset));
+ zoom_reset->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_reset", TTR("Zoom Reset"), KEY_MASK_CMD | KEY_0));
+ zoom_reset->set_shortcut_context(this);
+ zoom_reset->set_focus_mode(FOCUS_NONE);
+ zoom_reset->set_text_align(Button::TextAlign::ALIGN_CENTER);
+ // Prevent the button's size from changing when the text size changes
+ zoom_reset->set_custom_minimum_size(Size2(75 * EDSCALE, 0));
+
+ zoom_plus = memnew(Button);
+ zoom_plus->set_flat(true);
+ add_child(zoom_plus);
+ zoom_plus->connect("pressed", callable_mp(this, &EditorZoomWidget::_button_zoom_plus));
+ zoom_plus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", TTR("Zoom In"), KEY_MASK_CMD | KEY_EQUAL)); // Usually direct access key for PLUS
+ zoom_plus->set_shortcut_context(this);
+ zoom_plus->set_focus_mode(FOCUS_NONE);
+
+ _update_zoom_label();
+
+ add_theme_constant_override("separation", Math::round(-8 * EDSCALE));
+}
diff --git a/platform/javascript/api/javascript_eval.h b/editor/editor_zoom_widget.h
index 24f7648ed9..4e95018e52 100644
--- a/platform/javascript/api/javascript_eval.h
+++ b/editor/editor_zoom_widget.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* javascript_eval.h */
+/* editor_zoom_widget.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,26 +28,35 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_EVAL_H
-#define JAVASCRIPT_EVAL_H
+#ifndef EDITOR_ZOOM_WIDGET_H
+#define EDITOR_ZOOM_WIDGET_H
-#include "core/object/class_db.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
-class JavaScript : public Object {
-private:
- GDCLASS(JavaScript, Object);
+class EditorZoomWidget : public HBoxContainer {
+ GDCLASS(EditorZoomWidget, HBoxContainer);
- static JavaScript *singleton;
+ Button *zoom_minus;
+ Button *zoom_reset;
+ Button *zoom_plus;
+
+ float zoom = 1.0;
+ void _update_zoom_label();
+ void _button_zoom_minus();
+ void _button_zoom_reset();
+ void _button_zoom_plus();
protected:
+ void _notification(int p_what);
static void _bind_methods();
public:
- Variant eval(const String &p_code, bool p_use_global_exec_context = false);
+ EditorZoomWidget();
- static JavaScript *get_singleton();
- JavaScript();
- ~JavaScript();
+ float get_zoom();
+ void set_zoom(float p_zoom);
+ void set_zoom_by_increments(int p_increment_count);
};
-#endif // JAVASCRIPT_EVAL_H
+#endif // EDITOR_ZOOM_WIDGET_H
diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp
index 781d21c370..76c6fcc3d3 100644
--- a/editor/export_template_manager.cpp
+++ b/editor/export_template_manager.cpp
@@ -31,9 +31,9 @@
#include "export_template_manager.h"
#include "core/input/input.h"
+#include "core/io/dir_access.h"
#include "core/io/json.h"
#include "core/io/zip_io.h"
-#include "core/os/dir_access.h"
#include "core/os/keyboard.h"
#include "core/version.h"
#include "editor_node.h"
@@ -41,140 +41,336 @@
#include "progress_dialog.h"
#include "scene/gui/link_button.h"
-void ExportTemplateManager::_update_template_list() {
- while (current_hb->get_child_count()) {
- memdelete(current_hb->get_child(0));
- }
-
- while (installed_vb->get_child_count()) {
- memdelete(installed_vb->get_child(0));
- }
+void ExportTemplateManager::_update_template_status() {
+ // Fetch installed templates from the file system.
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ const String &templates_dir = EditorSettings::get_singleton()->get_templates_dir();
- DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- Error err = d->change_dir(EditorSettings::get_singleton()->get_templates_dir());
+ Error err = da->change_dir(templates_dir);
+ ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir + "'.");
Set<String> templates;
- d->list_dir_begin();
+ da->list_dir_begin();
if (err == OK) {
- String c = d->get_next();
+ String c = da->get_next();
while (c != String()) {
- if (d->current_is_dir() && !c.begins_with(".")) {
+ if (da->current_is_dir() && !c.begins_with(".")) {
templates.insert(c);
}
- c = d->get_next();
+ c = da->get_next();
}
}
- d->list_dir_end();
-
- memdelete(d);
+ da->list_dir_end();
+ memdelete(da);
+ // Update the state of the current version.
String current_version = VERSION_FULL_CONFIG;
- // Downloadable export templates are only available for stable and official alpha/beta/RC builds
- // (which always have a number following their status, e.g. "alpha1").
- // Therefore, don't display download-related features when using a development version
- // (whose builds aren't numbered).
- const bool downloads_available =
- String(VERSION_STATUS) != String("dev") &&
- String(VERSION_STATUS) != String("alpha") &&
- String(VERSION_STATUS) != String("beta") &&
- String(VERSION_STATUS) != String("rc");
-
- Label *current = memnew(Label);
- current->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- current_hb->add_child(current);
+ current_value->set_text(current_version);
if (templates.has(current_version)) {
- 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) {
- Button *redownload = memnew(Button);
- redownload->set_text(TTR("Redownload"));
- current_hb->add_child(redownload);
- redownload->connect("pressed", callable_mp(this, &ExportTemplateManager::_download_template), varray(current_version));
- }
+ current_missing_label->hide();
+ current_installed_label->show();
+
+ current_installed_hb->show();
+ current_version_exists = true;
+ } else {
+ current_installed_label->hide();
+ current_missing_label->show();
- Button *uninstall = memnew(Button);
- uninstall->set_text(TTR("Uninstall"));
- current_hb->add_child(uninstall);
- current->set_text(current_version + " " + TTR("(Installed)"));
- uninstall->connect("pressed", callable_mp(this, &ExportTemplateManager::_uninstall_template), varray(current_version));
+ current_installed_hb->hide();
+ current_version_exists = false;
+ }
+ if (is_downloading_templates) {
+ install_options_vb->hide();
+ download_progress_hb->show();
} else {
- current->add_theme_color_override("font_color", current->get_theme_color("error_color", "Editor"));
- Button *redownload = memnew(Button);
- redownload->set_text(TTR("Download"));
+ download_progress_hb->hide();
+ install_options_vb->show();
- if (!downloads_available) {
- redownload->set_disabled(true);
- redownload->set_tooltip(TTR("Official export templates aren't available for development builds."));
+ if (templates.has(current_version)) {
+ current_installed_path->set_text(templates_dir.plus_file(current_version));
}
-
- redownload->connect("pressed", callable_mp(this, &ExportTemplateManager::_download_template), varray(current_version));
- current_hb->add_child(redownload);
- current->set_text(current_version + " " + TTR("(Missing)"));
}
+ // Update the list of other installed versions.
+ installed_table->clear();
+ TreeItem *installed_root = installed_table->create_item();
+
for (Set<String>::Element *E = templates.back(); E; E = E->prev()) {
- HBoxContainer *hbc = memnew(HBoxContainer);
- Label *version = memnew(Label);
- version->set_modulate(current->get_theme_color("disabled_font_color", "Editor"));
- String text = E->get();
- if (text == current_version) {
- text += " " + TTR("(Current)");
+ String version_string = E->get();
+ if (version_string == current_version) {
+ continue;
}
- version->set_text(text);
- version->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- hbc->add_child(version);
- Button *uninstall = memnew(Button);
+ TreeItem *ti = installed_table->create_item(installed_root);
+ ti->set_text(0, version_string);
+
+ ti->add_button(0, get_theme_icon("Folder", "EditorIcons"), OPEN_TEMPLATE_FOLDER, false, TTR("Open the folder containing these templates."));
+ ti->add_button(0, get_theme_icon("Remove", "EditorIcons"), UNINSTALL_TEMPLATE, false, TTR("Uninstall these templates."));
+ }
+}
+
+void ExportTemplateManager::_download_current() {
+ if (is_downloading_templates) {
+ return;
+ }
+ is_downloading_templates = true;
+
+ install_options_vb->hide();
+ download_progress_hb->show();
- uninstall->set_text(TTR("Uninstall"));
- hbc->add_child(uninstall);
- uninstall->connect("pressed", callable_mp(this, &ExportTemplateManager::_uninstall_template), varray(E->get()));
+ if (mirrors_available) {
+ String mirror_url = _get_selected_mirror();
+ if (mirror_url.is_empty()) {
+ _set_current_progress_status(TTR("There are no mirrors available."), true);
+ return;
+ }
- installed_vb->add_child(hbc);
+ _download_template(mirror_url, true);
+ } else if (!mirrors_available && !is_refreshing_mirrors) {
+ _set_current_progress_status(TTR("Retrieving the mirror list..."));
+ _refresh_mirrors();
}
}
-void ExportTemplateManager::_download_template(const String &p_version) {
- while (template_list->get_child_count()) {
- memdelete(template_list->get_child(0));
- }
- 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);
- request_mirror->request("https://godotengine.org/mirrorlist/" + p_version + ".json");
- template_list_state->show();
- template_download_progress->show();
+void ExportTemplateManager::_download_template(const String &p_url, bool p_skip_check) {
+ if (!p_skip_check && is_downloading_templates) {
+ return;
+ }
+ is_downloading_templates = true;
+
+ install_options_vb->hide();
+ download_progress_hb->show();
+ _set_current_progress_status(TTR("Starting the download..."));
+
+ download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz"));
+ download_templates->set_use_threads(true);
+
+ Error err = download_templates->request(p_url);
+ if (err != OK) {
+ _set_current_progress_status(TTR("Error requesting URL:") + " " + p_url, true);
+ return;
+ }
+
+ set_process(true);
+ _set_current_progress_status(TTR("Connecting to the mirror..."));
}
-void ExportTemplateManager::_uninstall_template(const String &p_version) {
- remove_confirm->set_text(vformat(TTR("Remove template version '%s'?"), p_version));
- remove_confirm->popup_centered();
- to_remove = p_version;
+void ExportTemplateManager::_download_template_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) {
+ switch (p_status) {
+ case HTTPRequest::RESULT_CANT_RESOLVE: {
+ _set_current_progress_status(TTR("Can't resolve the requested address."), true);
+ } break;
+ case HTTPRequest::RESULT_BODY_SIZE_LIMIT_EXCEEDED:
+ case HTTPRequest::RESULT_CONNECTION_ERROR:
+ case HTTPRequest::RESULT_CHUNKED_BODY_SIZE_MISMATCH:
+ case HTTPRequest::RESULT_SSL_HANDSHAKE_ERROR:
+ case HTTPRequest::RESULT_CANT_CONNECT: {
+ _set_current_progress_status(TTR("Can't connect to the mirror."), true);
+ } break;
+ case HTTPRequest::RESULT_NO_RESPONSE: {
+ _set_current_progress_status(TTR("No response from the mirror."), true);
+ } break;
+ case HTTPRequest::RESULT_REQUEST_FAILED: {
+ _set_current_progress_status(TTR("Request failed."), true);
+ } break;
+ case HTTPRequest::RESULT_REDIRECT_LIMIT_REACHED: {
+ _set_current_progress_status(TTR("Request ended up in a redirect loop."), true);
+ } break;
+ default: {
+ if (p_code != 200) {
+ _set_current_progress_status(TTR("Request failed:") + " " + itos(p_code), true);
+ } else {
+ _set_current_progress_status(TTR("Download complete; extracting templates..."));
+ String path = download_templates->get_download_file();
+
+ is_downloading_templates = false;
+ bool ret = _install_file_selected(path, true);
+ if (ret) {
+ // Clean up downloaded file.
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Error err = da->remove(path);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Cannot remove temporary file:") + "\n" + path + "\n");
+ }
+ } else {
+ EditorNode::get_singleton()->add_io_error(vformat(TTR("Templates installation failed.\nThe problematic templates archives can be found at '%s'."), path));
+ }
+ }
+ } break;
+ }
+
+ set_process(false);
}
-void ExportTemplateManager::_uninstall_template_confirm() {
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- const String &templates_dir = EditorSettings::get_singleton()->get_templates_dir();
- Error err = da->change_dir(templates_dir);
- ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir + "'.");
- err = da->change_dir(to_remove);
- ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.plus_file(to_remove) + "'.");
+void ExportTemplateManager::_cancel_template_download() {
+ if (!is_downloading_templates) {
+ return;
+ }
- err = da->erase_contents_recursive();
- ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.plus_file(to_remove) + "'.");
+ download_templates->cancel_request();
+ download_progress_hb->hide();
+ install_options_vb->show();
+ is_downloading_templates = false;
+}
- da->change_dir("..");
- err = da->remove(to_remove);
- ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.plus_file(to_remove) + "'.");
+void ExportTemplateManager::_refresh_mirrors() {
+ if (is_refreshing_mirrors) {
+ return;
+ }
+ is_refreshing_mirrors = true;
+
+ String current_version = VERSION_FULL_CONFIG;
+ const String mirrors_metadata_url = "https://godotengine.org/mirrorlist/" + current_version + ".json";
+ request_mirrors->request(mirrors_metadata_url);
+}
+
+void ExportTemplateManager::_refresh_mirrors_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) {
+ if (p_status != HTTPRequest::RESULT_SUCCESS || p_code != 200) {
+ EditorNode::get_singleton()->show_warning(TTR("Error getting the list of mirrors."));
+ is_refreshing_mirrors = false;
+ if (is_downloading_templates) {
+ _cancel_template_download();
+ }
+ return;
+ }
+
+ String response_json;
+ {
+ const uint8_t *r = p_data.ptr();
+ response_json.parse_utf8((const char *)r, p_data.size());
+ }
+
+ Variant response;
+ String errs;
+ int errline;
+ Error err = JSON::parse(response_json, response, errs, errline);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Error parsing JSON with the list of mirrors. Please report this issue!"));
+ is_refreshing_mirrors = false;
+ if (is_downloading_templates) {
+ _cancel_template_download();
+ }
+ return;
+ }
+
+ mirrors_list->clear();
+ mirrors_list->add_item(TTR("Best available mirror"), 0);
+
+ mirrors_available = false;
+
+ Dictionary data = response;
+ if (data.has("mirrors")) {
+ Array mirrors = data["mirrors"];
+
+ for (int i = 0; i < mirrors.size(); i++) {
+ Dictionary m = mirrors[i];
+ ERR_CONTINUE(!m.has("url") || !m.has("name"));
+
+ mirrors_list->add_item(m["name"]);
+ mirrors_list->set_item_metadata(i + 1, m["url"]);
+
+ mirrors_available = true;
+ }
+ }
+ if (!mirrors_available) {
+ EditorNode::get_singleton()->show_warning(TTR("No download links found for this version. Direct download is only available for official releases."));
+ if (is_downloading_templates) {
+ _cancel_template_download();
+ }
+ }
+
+ is_refreshing_mirrors = false;
+
+ if (is_downloading_templates) {
+ String mirror_url = _get_selected_mirror();
+ if (mirror_url.is_empty()) {
+ _set_current_progress_status(TTR("There are no mirrors available."), true);
+ return;
+ }
+
+ _download_template(mirror_url, true);
+ }
+}
+
+bool ExportTemplateManager::_humanize_http_status(HTTPRequest *p_request, String *r_status, int *r_downloaded_bytes, int *r_total_bytes) {
+ *r_status = "";
+ *r_downloaded_bytes = -1;
+ *r_total_bytes = -1;
+ bool success = true;
+
+ switch (p_request->get_http_client_status()) {
+ case HTTPClient::STATUS_DISCONNECTED:
+ *r_status = TTR("Disconnected");
+ success = false;
+ break;
+ case HTTPClient::STATUS_RESOLVING:
+ *r_status = TTR("Resolving");
+ break;
+ case HTTPClient::STATUS_CANT_RESOLVE:
+ *r_status = TTR("Can't Resolve");
+ success = false;
+ break;
+ case HTTPClient::STATUS_CONNECTING:
+ *r_status = TTR("Connecting...");
+ break;
+ case HTTPClient::STATUS_CANT_CONNECT:
+ *r_status = TTR("Can't Connect");
+ success = false;
+ break;
+ case HTTPClient::STATUS_CONNECTED:
+ *r_status = TTR("Connected");
+ break;
+ case HTTPClient::STATUS_REQUESTING:
+ *r_status = TTR("Requesting...");
+ break;
+ case HTTPClient::STATUS_BODY:
+ *r_status = TTR("Downloading");
+ *r_downloaded_bytes = p_request->get_downloaded_bytes();
+ *r_total_bytes = p_request->get_body_size();
+
+ if (p_request->get_body_size() > 0) {
+ *r_status += " " + String::humanize_size(p_request->get_downloaded_bytes()) + "/" + String::humanize_size(p_request->get_body_size());
+ } else {
+ *r_status += " " + String::humanize_size(p_request->get_downloaded_bytes());
+ }
+ break;
+ case HTTPClient::STATUS_CONNECTION_ERROR:
+ *r_status = TTR("Connection Error");
+ success = false;
+ break;
+ case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR:
+ *r_status = TTR("SSL Handshake Error");
+ success = false;
+ break;
+ }
+
+ return success;
+}
+
+void ExportTemplateManager::_set_current_progress_status(const String &p_status, bool p_error) {
+ download_progress_bar->hide();
+ download_progress_label->set_text(p_status);
+
+ if (p_error) {
+ download_progress_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
+ } else {
+ download_progress_label->add_theme_color_override("font_color", get_theme_color("font_color", "Label"));
+ }
+}
- _update_template_list();
+void ExportTemplateManager::_set_current_progress_value(float p_value, const String &p_status) {
+ download_progress_bar->show();
+ download_progress_bar->set_value(p_value);
+ download_progress_label->set_text(p_status);
}
-bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_progress) {
+void ExportTemplateManager::_install_file() {
+ install_file_dialog->popup_file_dialog();
+}
+
+bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_skip_progress) {
// 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 = nullptr;
@@ -182,12 +378,13 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
unzFile pkg = unzOpen2(p_file.utf8().get_data(), &io);
if (!pkg) {
- EditorNode::get_singleton()->show_warning(TTR("Can't open export templates zip."));
+ EditorNode::get_singleton()->show_warning(TTR("Can't open the export templates file."));
return false;
}
int ret = unzGoToFirstFile(pkg);
- int fc = 0; //count them and find version
+ // Count them and find version.
+ int fc = 0;
String version;
String contents_dir;
@@ -197,12 +394,11 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
String file = fname;
-
if (file.ends_with("version.txt")) {
Vector<uint8_t> data;
data.resize(info.uncompressed_size);
- //read
+ // Read.
unzOpenCurrentFile(pkg);
ret = unzReadCurrentFile(pkg, data.ptrw(), data.size());
unzCloseCurrentFile(pkg);
@@ -214,7 +410,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
// Version number should be of the form major.minor[.patch].status[.module_config]
// so it can in theory have 3 or more slices.
if (data_str.get_slice_count(".") < 3) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Invalid version.txt format inside templates: %s."), data_str));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Invalid version.txt format inside the export templates file: %s."), data_str));
unzClose(pkg);
return false;
}
@@ -231,32 +427,29 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
}
if (version == String()) {
- EditorNode::get_singleton()->show_warning(TTR("No version.txt found inside templates."));
+ EditorNode::get_singleton()->show_warning(TTR("No version.txt found inside the export templates file."));
unzClose(pkg);
return false;
}
- String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version);
-
DirAccessRef d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version);
Error err = d->make_dir_recursive(template_path);
if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Error creating path for templates:") + "\n" + template_path);
+ EditorNode::get_singleton()->show_warning(TTR("Error creating path for extracting templates:") + "\n" + template_path);
unzClose(pkg);
return false;
}
- ret = unzGoToFirstFile(pkg);
-
EditorProgress *p = nullptr;
- if (p_use_progress) {
+ if (!p_skip_progress) {
p = memnew(EditorProgress("ltask", TTR("Extracting Export Templates"), fc));
}
fc = 0;
-
+ ret = unzGoToFirstFile(pkg);
while (ret == UNZ_OK) {
- //get filename
+ // Get filename.
unz_file_info info;
char fname[16384];
unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
@@ -273,7 +466,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
Vector<uint8_t> data;
data.resize(info.uncompressed_size);
- //read
+ // Read
unzOpenCurrentFile(pkg);
unzReadCurrentFile(pkg, data.ptrw(), data.size());
unzCloseCurrentFile(pkg);
@@ -321,216 +514,116 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
if (p) {
memdelete(p);
}
-
unzClose(pkg);
- _update_template_list();
+ _update_template_status();
return true;
}
-void ExportTemplateManager::popup_manager() {
- _update_template_list();
- popup_centered(Size2(400, 400) * EDSCALE);
-}
-
-void ExportTemplateManager::ok_pressed() {
- template_open->popup_file_dialog();
+void ExportTemplateManager::_uninstall_template(const String &p_version) {
+ uninstall_confirm->set_text(vformat(TTR("Remove templates for the version '%s'?"), p_version));
+ uninstall_confirm->popup_centered();
+ uninstall_version = p_version;
}
-void ExportTemplateManager::_http_download_mirror_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) {
- if (p_status != HTTPRequest::RESULT_SUCCESS || p_code != 200) {
- EditorNode::get_singleton()->show_warning(TTR("Error getting the list of mirrors."));
- return;
- }
+void ExportTemplateManager::_uninstall_template_confirmed() {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ const String &templates_dir = EditorSettings::get_singleton()->get_templates_dir();
- String mirror_str;
- {
- const uint8_t *r = p_data.ptr();
- mirror_str.parse_utf8((const char *)r, p_data.size());
- }
+ Error err = da->change_dir(templates_dir);
+ ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir + "'.");
+ err = da->change_dir(uninstall_version);
+ ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.plus_file(uninstall_version) + "'.");
- template_list_state->hide();
- template_download_progress->hide();
+ err = da->erase_contents_recursive();
+ ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.plus_file(uninstall_version) + "'.");
- Variant r;
- String errs;
- int errline;
- Error err = JSON::parse(mirror_str, r, errs, errline);
- if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Error parsing JSON of mirror list. Please report this issue!"));
- return;
- }
+ da->change_dir("..");
+ err = da->remove(uninstall_version);
+ ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.plus_file(uninstall_version) + "'.");
- bool mirrors_found = false;
+ _update_template_status();
+}
- Dictionary d = r;
- if (d.has("mirrors")) {
- Array mirrors = d["mirrors"];
- for (int i = 0; i < mirrors.size(); i++) {
- Dictionary m = mirrors[i];
- ERR_CONTINUE(!m.has("url") || !m.has("name"));
- LinkButton *lb = memnew(LinkButton);
- lb->set_text(m["name"]);
- lb->connect("pressed", callable_mp(this, &ExportTemplateManager::_begin_template_download), varray(m["url"]));
- template_list->add_child(lb);
- mirrors_found = true;
- }
+String ExportTemplateManager::_get_selected_mirror() const {
+ if (mirrors_list->get_item_count() == 1) {
+ return "";
}
- if (!mirrors_found) {
- EditorNode::get_singleton()->show_warning(TTR("No download links found for this version. Direct download is only available for official releases."));
- return;
+ int selected = mirrors_list->get_selected_id();
+ if (selected == 0) {
+ // This is a special "best available" value; so pick the first available mirror from the rest of the list.
+ selected = 1;
}
+
+ return mirrors_list->get_item_metadata(selected);
}
-void ExportTemplateManager::_http_download_templates_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) {
- switch (p_status) {
- case HTTPRequest::RESULT_CANT_RESOLVE: {
- template_list_state->set_text(TTR("Can't resolve."));
- } break;
- case HTTPRequest::RESULT_BODY_SIZE_LIMIT_EXCEEDED:
- case HTTPRequest::RESULT_CONNECTION_ERROR:
- case HTTPRequest::RESULT_CHUNKED_BODY_SIZE_MISMATCH:
- case HTTPRequest::RESULT_SSL_HANDSHAKE_ERROR:
- case HTTPRequest::RESULT_CANT_CONNECT: {
- template_list_state->set_text(TTR("Can't connect."));
- } break;
- case HTTPRequest::RESULT_NO_RESPONSE: {
- template_list_state->set_text(TTR("No response."));
- } break;
- case HTTPRequest::RESULT_REQUEST_FAILED: {
- template_list_state->set_text(TTR("Request Failed."));
- } break;
- case HTTPRequest::RESULT_REDIRECT_LIMIT_REACHED: {
- template_list_state->set_text(TTR("Redirect Loop."));
+void ExportTemplateManager::_mirror_options_button_cbk(int p_id) {
+ switch (p_id) {
+ case VISIT_WEB_MIRROR: {
+ String mirror_url = _get_selected_mirror();
+ if (mirror_url.is_empty()) {
+ EditorNode::get_singleton()->show_warning(TTR("There are no mirrors available."));
+ return;
+ }
+
+ OS::get_singleton()->shell_open(mirror_url);
} break;
- default: {
- if (p_code != 200) {
- template_list_state->set_text(TTR("Failed:") + " " + itos(p_code));
- } else {
- String path = download_templates->get_download_file();
- template_list_state->set_text(TTR("Download Complete."));
- template_downloader->hide();
- bool ret = _install_from_file(path, false);
- if (ret) {
- // Clean up downloaded file.
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- Error err = da->remove(path);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Cannot remove temporary file:") + "\n" + path + "\n");
- }
- } else {
- EditorNode::get_singleton()->add_io_error(vformat(TTR("Templates installation failed.\nThe problematic templates archives can be found at '%s'."), path));
- }
+
+ case COPY_MIRROR_URL: {
+ String mirror_url = _get_selected_mirror();
+ if (mirror_url.is_empty()) {
+ EditorNode::get_singleton()->show_warning(TTR("There are no mirrors available."));
+ return;
}
+
+ DisplayServer::get_singleton()->clipboard_set(mirror_url);
} break;
}
-
- set_process(false);
}
-void ExportTemplateManager::_begin_template_download(const String &p_url) {
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
- OS::get_singleton()->shell_open(p_url);
+void ExportTemplateManager::_installed_table_button_cbk(Object *p_item, int p_column, int p_id) {
+ TreeItem *ti = Object::cast_to<TreeItem>(p_item);
+ if (!ti) {
return;
}
- for (int i = 0; i < template_list->get_child_count(); i++) {
- BaseButton *b = Object::cast_to<BaseButton>(template_list->get_child(0));
- if (b) {
- b->set_disabled(true);
- }
- }
-
- download_data.clear();
- download_templates->set_download_file(EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz"));
- download_templates->set_use_threads(true);
+ switch (p_id) {
+ case OPEN_TEMPLATE_FOLDER: {
+ String version_string = ti->get_text(0);
+ _open_template_folder(version_string);
+ } break;
- Error err = download_templates->request(p_url);
- if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Error requesting URL:") + " " + p_url);
- return;
+ case UNINSTALL_TEMPLATE: {
+ String version_string = ti->get_text(0);
+ _uninstall_template(version_string);
+ } break;
}
+}
- set_process(true);
-
- template_list_state->show();
- template_download_progress->set_max(100);
- template_download_progress->set_value(0);
- template_download_progress->show();
- template_list_state->set_text(TTR("Connecting to Mirror..."));
+void ExportTemplateManager::_open_template_folder(const String &p_version) {
+ const String &templates_dir = EditorSettings::get_singleton()->get_templates_dir();
+ OS::get_singleton()->shell_open("file://" + templates_dir.plus_file(p_version));
}
-void ExportTemplateManager::_window_template_downloader_closed() {
- download_templates->cancel_request();
+void ExportTemplateManager::popup_manager() {
+ _update_template_status();
+ _refresh_mirrors();
+ popup_centered(Size2(720, 280) * EDSCALE);
}
-void ExportTemplateManager::_notification(int p_what) {
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (!is_visible()) {
- set_process(false);
- }
+void ExportTemplateManager::ok_pressed() {
+ if (!is_downloading_templates) {
+ hide();
+ return;
}
- if (p_what == NOTIFICATION_PROCESS) {
- update_countdown -= get_process_delta_time();
- if (update_countdown > 0) {
- return;
- }
- update_countdown = 0.5;
- String status;
- bool errored = false;
-
- switch (download_templates->get_http_client_status()) {
- case HTTPClient::STATUS_DISCONNECTED:
- status = TTR("Disconnected");
- errored = true;
- break;
- case HTTPClient::STATUS_RESOLVING:
- status = TTR("Resolving");
- break;
- case HTTPClient::STATUS_CANT_RESOLVE:
- status = TTR("Can't Resolve");
- errored = true;
- break;
- case HTTPClient::STATUS_CONNECTING:
- status = TTR("Connecting...");
- break;
- case HTTPClient::STATUS_CANT_CONNECT:
- status = TTR("Can't Connect");
- errored = true;
- break;
- case HTTPClient::STATUS_CONNECTED:
- status = TTR("Connected");
- break;
- case HTTPClient::STATUS_REQUESTING:
- status = TTR("Requesting...");
- break;
- case HTTPClient::STATUS_BODY:
- status = TTR("Downloading");
- if (download_templates->get_body_size() > 0) {
- status += " " + String::humanize_size(download_templates->get_downloaded_bytes()) + "/" + String::humanize_size(download_templates->get_body_size());
- template_download_progress->set_max(download_templates->get_body_size());
- template_download_progress->set_value(download_templates->get_downloaded_bytes());
- } else {
- status += " " + String::humanize_size(download_templates->get_downloaded_bytes());
- }
- break;
- case HTTPClient::STATUS_CONNECTION_ERROR:
- status = TTR("Connection Error");
- errored = true;
- break;
- case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR:
- status = TTR("SSL Handshake Error");
- errored = true;
- break;
- }
+ hide_dialog_accept->popup_centered();
+}
- template_list_state->set_text(status);
- if (errored) {
- set_process(false);
- }
- }
+void ExportTemplateManager::_hide_dialog() {
+ hide();
}
bool ExportTemplateManager::can_install_android_template() {
@@ -642,72 +735,246 @@ Error ExportTemplateManager::install_android_template() {
return OK;
}
-void ExportTemplateManager::_bind_methods() {
-}
+void ExportTemplateManager::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ current_value->add_theme_font_override("font", get_theme_font("main", "EditorFonts"));
+ current_missing_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
+ current_installed_label->add_theme_color_override("font_color", get_theme_color("disabled_font_color", "Editor"));
+
+ mirror_options_button->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons"));
+ } break;
-ExportTemplateManager::ExportTemplateManager() {
- VBoxContainer *main_vb = memnew(VBoxContainer);
- add_child(main_vb);
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible()) {
+ set_process(false);
+ } else if (is_visible() && is_downloading_templates) {
+ set_process(true);
+ }
+ } break;
- current_hb = memnew(HBoxContainer);
- main_vb->add_margin_child(TTR("Current Version:"), current_hb, false);
+ case NOTIFICATION_PROCESS: {
+ update_countdown -= get_process_delta_time();
+ if (update_countdown > 0) {
+ return;
+ }
+ update_countdown = 0.5;
- installed_scroll = memnew(ScrollContainer);
- main_vb->add_margin_child(TTR("Installed Versions:"), installed_scroll, true);
+ String status;
+ int downloaded_bytes;
+ int total_bytes;
+ bool success = _humanize_http_status(download_templates, &status, &downloaded_bytes, &total_bytes);
- installed_vb = memnew(VBoxContainer);
- 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(Control::SIZE_EXPAND_FILL);
+ if (downloaded_bytes >= 0) {
+ if (total_bytes > 0) {
+ _set_current_progress_value(float(downloaded_bytes) / total_bytes, status);
+ } else {
+ _set_current_progress_value(0, status);
+ }
+ } else {
+ _set_current_progress_status(status);
+ }
- get_cancel_button()->set_text(TTR("Close"));
- get_ok_button()->set_text(TTR("Install From File"));
+ if (!success) {
+ set_process(false);
+ }
+ } break;
- remove_confirm = memnew(ConfirmationDialog);
- remove_confirm->set_title(TTR("Remove Template"));
- add_child(remove_confirm);
- remove_confirm->connect("confirmed", callable_mp(this, &ExportTemplateManager::_uninstall_template_confirm));
+ case NOTIFICATION_WM_CLOSE_REQUEST: {
+ // This won't stop the window from closing, but will show the alert if the download is active.
+ ok_pressed();
+ } break;
+ }
+}
- template_open = memnew(FileDialog);
- 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_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);
+void ExportTemplateManager::_bind_methods() {
+}
+ExportTemplateManager::ExportTemplateManager() {
set_title(TTR("Export Template Manager"));
set_hide_on_ok(false);
+ get_ok_button()->set_text(TTR("Close"));
+
+ // Downloadable export templates are only available for stable and official alpha/beta/RC builds
+ // (which always have a number following their status, e.g. "alpha1").
+ // Therefore, don't display download-related features when using a development version
+ // (whose builds aren't numbered).
+ downloads_available =
+ String(VERSION_STATUS) != String("dev") &&
+ String(VERSION_STATUS) != String("alpha") &&
+ String(VERSION_STATUS) != String("beta") &&
+ String(VERSION_STATUS) != String("rc");
+
+ VBoxContainer *main_vb = memnew(VBoxContainer);
+ add_child(main_vb);
+
+ // Current version controls.
+ HBoxContainer *current_hb = memnew(HBoxContainer);
+ main_vb->add_child(current_hb);
+
+ Label *current_label = memnew(Label);
+ current_label->set_text(TTR("Current Version:"));
+ current_hb->add_child(current_label);
+
+ current_value = memnew(Label);
+ current_hb->add_child(current_value);
+
+ // Current version statuses.
+ // Status: Current version is missing.
+ current_missing_label = memnew(Label);
+ current_missing_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ current_missing_label->set_align(Label::ALIGN_RIGHT);
+ current_missing_label->set_text(TTR("Export templates are missing. Download them or install from a file."));
+ current_hb->add_child(current_missing_label);
+
+ // Status: Current version is installed.
+ current_installed_label = memnew(Label);
+ current_installed_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ current_installed_label->set_align(Label::ALIGN_RIGHT);
+ current_installed_label->set_text(TTR("Export templates are installed and ready to be used."));
+ current_hb->add_child(current_installed_label);
+ current_installed_label->hide();
+
+ // Currently installed template.
+ current_installed_hb = memnew(HBoxContainer);
+ main_vb->add_child(current_installed_hb);
+
+ current_installed_path = memnew(LineEdit);
+ current_installed_path->set_editable(false);
+ current_installed_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ current_installed_hb->add_child(current_installed_path);
+
+ current_open_button = memnew(Button);
+ current_open_button->set_text(TTR("Open Folder"));
+ current_open_button->set_tooltip(TTR("Open the folder containing installed templates for the current version."));
+ current_installed_hb->add_child(current_open_button);
+ current_open_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_open_template_folder), varray(VERSION_FULL_CONFIG));
+
+ current_uninstall_button = memnew(Button);
+ current_uninstall_button->set_text(TTR("Uninstall"));
+ current_uninstall_button->set_tooltip(TTR("Uninstall templates for the current version."));
+ current_installed_hb->add_child(current_uninstall_button);
+ current_uninstall_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_uninstall_template), varray(VERSION_FULL_CONFIG));
+
+ main_vb->add_child(memnew(HSeparator));
+
+ // Download and install section.
+ HBoxContainer *install_templates_hb = memnew(HBoxContainer);
+ main_vb->add_child(install_templates_hb);
+
+ // Download and install buttons are available.
+ install_options_vb = memnew(VBoxContainer);
+ install_options_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ install_templates_hb->add_child(install_options_vb);
+
+ HBoxContainer *download_install_hb = memnew(HBoxContainer);
+ install_options_vb->add_child(download_install_hb);
+
+ Label *mirrors_label = memnew(Label);
+ mirrors_label->set_text(TTR("Download from:"));
+ download_install_hb->add_child(mirrors_label);
+
+ mirrors_list = memnew(OptionButton);
+ mirrors_list->set_custom_minimum_size(Size2(280, 0) * EDSCALE);
+ download_install_hb->add_child(mirrors_list);
+ mirrors_list->add_item(TTR("Best available mirror"), 0);
+
+ request_mirrors = memnew(HTTPRequest);
+ mirrors_list->add_child(request_mirrors);
+ request_mirrors->connect("request_completed", callable_mp(this, &ExportTemplateManager::_refresh_mirrors_completed));
+
+ mirror_options_button = memnew(MenuButton);
+ mirror_options_button->get_popup()->add_item("Open in Web Browser", VISIT_WEB_MIRROR);
+ mirror_options_button->get_popup()->add_item("Copy Mirror URL", COPY_MIRROR_URL);
+ download_install_hb->add_child(mirror_options_button);
+ mirror_options_button->get_popup()->connect("id_pressed", callable_mp(this, &ExportTemplateManager::_mirror_options_button_cbk));
+
+ download_install_hb->add_spacer();
+
+ Button *download_current_button = memnew(Button);
+ download_current_button->set_text(TTR("Download and Install"));
+ download_current_button->set_tooltip(TTR("Download and install templates for the current version from the best possible mirror."));
+ download_install_hb->add_child(download_current_button);
+ download_current_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_download_current));
+
+ // Update downloads buttons to prevent unsupported downloads.
+ if (!downloads_available) {
+ download_current_button->set_disabled(true);
+ download_current_button->set_tooltip(TTR("Official export templates aren't available for development builds."));
+ }
- request_mirror = memnew(HTTPRequest);
- add_child(request_mirror);
- request_mirror->connect("request_completed", callable_mp(this, &ExportTemplateManager::_http_download_mirror_completed));
+ HBoxContainer *install_file_hb = memnew(HBoxContainer);
+ install_file_hb->set_alignment(BoxContainer::ALIGN_END);
+ install_options_vb->add_child(install_file_hb);
+
+ install_file_button = memnew(Button);
+ install_file_button->set_text(TTR("Install from File"));
+ install_file_button->set_tooltip(TTR("Install templates from a local file."));
+ install_file_hb->add_child(install_file_button);
+ install_file_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_install_file));
+
+ // Templates are being downloaded; buttons unavailable.
+ download_progress_hb = memnew(HBoxContainer);
+ download_progress_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ install_templates_hb->add_child(download_progress_hb);
+ download_progress_hb->hide();
+
+ download_progress_bar = memnew(ProgressBar);
+ download_progress_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ download_progress_bar->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
+ download_progress_bar->set_min(0);
+ download_progress_bar->set_max(1);
+ download_progress_bar->set_value(0);
+ download_progress_bar->set_step(0.01);
+ download_progress_hb->add_child(download_progress_bar);
+
+ download_progress_label = memnew(Label);
+ download_progress_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ download_progress_hb->add_child(download_progress_label);
+
+ Button *download_cancel_button = memnew(Button);
+ download_cancel_button->set_text(TTR("Cancel"));
+ download_cancel_button->set_tooltip(TTR("Cancel the download of the templates."));
+ download_progress_hb->add_child(download_cancel_button);
+ download_cancel_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_cancel_template_download));
download_templates = memnew(HTTPRequest);
- add_child(download_templates);
- download_templates->connect("request_completed", callable_mp(this, &ExportTemplateManager::_http_download_templates_completed));
-
- template_downloader = memnew(AcceptDialog);
- template_downloader->set_title(TTR("Download Templates"));
- template_downloader->get_ok_button()->set_text(TTR("Close"));
- template_downloader->set_exclusive(true);
- add_child(template_downloader);
- template_downloader->connect("cancelled", callable_mp(this, &ExportTemplateManager::_window_template_downloader_closed));
-
- VBoxContainer *vbc = memnew(VBoxContainer);
- template_downloader->add_child(vbc);
- ScrollContainer *sc = memnew(ScrollContainer);
- sc->set_custom_minimum_size(Size2(400, 200) * EDSCALE);
- vbc->add_margin_child(TTR("Select mirror from list: (Shift+Click: Open in Browser)"), sc);
- template_list = memnew(VBoxContainer);
- sc->add_child(template_list);
- sc->set_enable_v_scroll(true);
- sc->set_enable_h_scroll(false);
- template_list_state = memnew(Label);
- vbc->add_child(template_list_state);
- template_download_progress = memnew(ProgressBar);
- vbc->add_child(template_download_progress);
-
- update_countdown = 0;
+ install_templates_hb->add_child(download_templates);
+ download_templates->connect("request_completed", callable_mp(this, &ExportTemplateManager::_download_template_completed));
+
+ main_vb->add_child(memnew(HSeparator));
+
+ // Other installed templates table.
+ HBoxContainer *installed_versions_hb = memnew(HBoxContainer);
+ main_vb->add_child(installed_versions_hb);
+ Label *installed_label = memnew(Label);
+ installed_label->set_text(TTR("Other Installed Versions:"));
+ installed_versions_hb->add_child(installed_label);
+
+ installed_table = memnew(Tree);
+ installed_table->set_hide_root(true);
+ installed_table->set_custom_minimum_size(Size2(0, 100) * EDSCALE);
+ installed_table->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ main_vb->add_child(installed_table);
+ installed_table->connect("button_pressed", callable_mp(this, &ExportTemplateManager::_installed_table_button_cbk));
+
+ // Dialogs.
+ uninstall_confirm = memnew(ConfirmationDialog);
+ uninstall_confirm->set_title(TTR("Uninstall Template"));
+ add_child(uninstall_confirm);
+ uninstall_confirm->connect("confirmed", callable_mp(this, &ExportTemplateManager::_uninstall_template_confirmed));
+
+ install_file_dialog = memnew(FileDialog);
+ install_file_dialog->set_title(TTR("Select Template File"));
+ install_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ install_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
+ install_file_dialog->add_filter("*.tpz ; " + TTR("Godot Export Templates"));
+ install_file_dialog->connect("file_selected", callable_mp(this, &ExportTemplateManager::_install_file_selected), varray(false));
+ add_child(install_file_dialog);
+
+ hide_dialog_accept = memnew(AcceptDialog);
+ hide_dialog_accept->set_text(TTR("The templates will continue to download.\nYou may experience a short editor freeze when they finish."));
+ add_child(hide_dialog_accept);
+ hide_dialog_accept->connect("confirmed", callable_mp(this, &ExportTemplateManager::_hide_dialog));
}
diff --git a/editor/export_template_manager.h b/editor/export_template_manager.h
index 3de74e17d8..f145c6c0f5 100644
--- a/editor/export_template_manager.h
+++ b/editor/export_template_manager.h
@@ -34,50 +34,87 @@
#include "editor/editor_settings.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/file_dialog.h"
+#include "scene/gui/menu_button.h"
#include "scene/gui/progress_bar.h"
#include "scene/gui/scroll_container.h"
#include "scene/main/http_request.h"
class ExportTemplateVersion;
-class ExportTemplateManager : public ConfirmationDialog {
- GDCLASS(ExportTemplateManager, ConfirmationDialog);
+class ExportTemplateManager : public AcceptDialog {
+ GDCLASS(ExportTemplateManager, AcceptDialog);
+
+ bool current_version_exists = false;
+ bool downloads_available = true;
+ bool mirrors_available = false;
+ bool is_refreshing_mirrors = false;
+ bool is_downloading_templates = false;
+ float update_countdown = 0;
+
+ Label *current_value;
+ Label *current_missing_label;
+ Label *current_installed_label;
+
+ HBoxContainer *current_installed_hb;
+ LineEdit *current_installed_path;
+ Button *current_open_button;
+ Button *current_uninstall_button;
+
+ VBoxContainer *install_options_vb;
+ OptionButton *mirrors_list;
+
+ enum MirrorAction {
+ VISIT_WEB_MIRROR,
+ COPY_MIRROR_URL,
+ };
+
+ MenuButton *mirror_options_button;
+ HBoxContainer *download_progress_hb;
+ ProgressBar *download_progress_bar;
+ Label *download_progress_label;
+ HTTPRequest *download_templates;
+ Button *install_file_button;
+ HTTPRequest *request_mirrors;
- AcceptDialog *template_downloader;
- VBoxContainer *template_list;
- Label *template_list_state;
- ProgressBar *template_download_progress;
+ enum TemplatesAction {
+ OPEN_TEMPLATE_FOLDER,
+ UNINSTALL_TEMPLATE,
+ };
- ScrollContainer *installed_scroll;
- VBoxContainer *installed_vb;
- HBoxContainer *current_hb;
- FileDialog *template_open;
+ Tree *installed_table;
- ConfirmationDialog *remove_confirm;
- String to_remove;
+ ConfirmationDialog *uninstall_confirm;
+ String uninstall_version;
+ FileDialog *install_file_dialog;
+ AcceptDialog *hide_dialog_accept;
- HTTPRequest *request_mirror;
- HTTPRequest *download_templates;
+ void _update_template_status();
- Vector<uint8_t> download_data;
+ void _download_current();
+ void _download_template(const String &p_url, bool p_skip_check = false);
+ void _download_template_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
+ void _cancel_template_download();
+ void _refresh_mirrors();
+ void _refresh_mirrors_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
- float update_countdown;
+ bool _humanize_http_status(HTTPRequest *p_request, String *r_status, int *r_downloaded_bytes, int *r_total_bytes);
+ void _set_current_progress_status(const String &p_status, bool p_error = false);
+ void _set_current_progress_value(float p_value, const String &p_status);
- void _update_template_list();
+ void _install_file();
+ bool _install_file_selected(const String &p_file, bool p_skip_progress = false);
- void _download_template(const String &p_version);
void _uninstall_template(const String &p_version);
- void _uninstall_template_confirm();
+ void _uninstall_template_confirmed();
- virtual void ok_pressed() override;
- bool _install_from_file(const String &p_file, bool p_use_progress = true);
+ String _get_selected_mirror() const;
+ void _mirror_options_button_cbk(int p_id);
+ void _installed_table_button_cbk(Object *p_item, int p_column, int p_id);
- void _http_download_mirror_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
- void _http_download_templates_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
+ void _open_template_folder(const String &p_version);
- void _begin_template_download(const String &p_url);
-
- void _window_template_downloader_closed();
+ virtual void ok_pressed() override;
+ void _hide_dialog();
protected:
void _notification(int p_what);
diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp
index d80003a12a..654915e3e5 100644
--- a/editor/fileserver/editor_file_server.cpp
+++ b/editor/fileserver/editor_file_server.cpp
@@ -200,7 +200,7 @@ void EditorFileServer::_subthread_start(void *s) {
cd->connection->put_data(buf4, 4);
encode_uint32(OK, buf4);
cd->connection->put_data(buf4, 4);
- encode_uint64(fa->get_len(), buf4);
+ encode_uint64(fa->get_length(), buf4);
cd->connection->put_data(buf4, 8);
cd->files[id] = fa;
@@ -230,8 +230,7 @@ void EditorFileServer::_subthread_start(void *s) {
cd->files[id]->seek(offset);
Vector<uint8_t> buf;
buf.resize(blocklen);
- int read = cd->files[id]->get_buffer(buf.ptrw(), blocklen);
- ERR_CONTINUE(read < 0);
+ uint32_t read = cd->files[id]->get_buffer(buf.ptrw(), blocklen);
print_verbose("GET BLOCK - offset: " + itos(offset) + ", blocklen: " + itos(blocklen));
diff --git a/editor/fileserver/editor_file_server.h b/editor/fileserver/editor_file_server.h
index 8ffd4f9692..d0405e0bb7 100644
--- a/editor/fileserver/editor_file_server.h
+++ b/editor/fileserver/editor_file_server.h
@@ -54,7 +54,7 @@ class EditorFileServer : public Object {
bool quit = false;
};
- Ref<TCP_Server> server;
+ Ref<TCPServer> server;
Set<Thread *> to_wait;
static void _close_client(ClientData *cd);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 899070f036..fe1fa9f9d6 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -31,9 +31,9 @@
#include "filesystem_dock.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/templates/list.h"
@@ -180,12 +180,12 @@ Vector<String> FileSystemDock::_compute_uncollapsed_paths() {
Vector<String> uncollapsed_paths;
TreeItem *root = tree->get_root();
if (root) {
- TreeItem *favorites_item = root->get_children();
+ TreeItem *favorites_item = root->get_first_child();
if (!favorites_item->is_collapsed()) {
uncollapsed_paths.push_back(favorites_item->get_metadata(0));
}
- TreeItem *resTree = root->get_children()->get_next();
+ TreeItem *resTree = root->get_first_child()->get_next();
if (resTree) {
Vector<TreeItem *> needs_check;
needs_check.push_back(resTree);
@@ -193,7 +193,7 @@ Vector<String> FileSystemDock::_compute_uncollapsed_paths() {
while (needs_check.size()) {
if (!needs_check[0]->is_collapsed()) {
uncollapsed_paths.push_back(needs_check[0]->get_metadata(0));
- TreeItem *child = needs_check[0]->get_children();
+ TreeItem *child = needs_check[0]->get_first_child();
while (child) {
needs_check.push_back(child);
child = child->get_next();
@@ -365,7 +365,7 @@ void FileSystemDock::_notification(int p_what) {
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));
- current_path->connect("text_entered", callable_mp(this, &FileSystemDock::_navigate_to_path), make_binds(false));
+ current_path->connect("text_submitted", callable_mp(this, &FileSystemDock::_navigate_to_path), make_binds(false));
always_show_folders = bool(EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders"));
@@ -464,7 +464,7 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s
return;
}
- TreeItem *favorites_item = tree->get_root()->get_children();
+ TreeItem *favorites_item = tree->get_root()->get_first_child();
if (selected->get_parent() == favorites_item && !String(selected->get_metadata(0)).ends_with("/")) {
// Go to the favorites if we click in the favorites and the path has changed.
path = "Favorites";
@@ -860,7 +860,6 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
file_list.push_back(fi);
}
}
- file_list.sort();
}
// Sort the file list if needed.
@@ -1465,6 +1464,10 @@ void FileSystemDock::_folder_removed(String p_folder) {
}
current_path->set_text(path);
+ EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_filesystem_path(path);
+ if (efd) {
+ efd->force_update();
+ }
}
void FileSystemDock::_rename_operation_confirm() {
@@ -1640,7 +1643,7 @@ Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion) {
// Build a list of selected items with the active one at the first position.
Vector<String> selected_strings;
- TreeItem *favorites_item = tree->get_root()->get_children();
+ TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *active_selected = tree->get_selected();
if (active_selected && active_selected != favorites_item) {
selected_strings.push_back(active_selected->get_metadata(0));
@@ -1696,7 +1699,7 @@ void FileSystemDock::_tree_rmb_option(int p_option) {
while (needs_check.size()) {
needs_check[0]->set_collapsed(is_collapsed);
- TreeItem *child = needs_check[0]->get_children();
+ TreeItem *child = needs_check[0]->get_first_child();
while (child) {
needs_check.push_back(child);
child = child->get_next();
@@ -1982,6 +1985,20 @@ void FileSystemDock::_resource_created() {
editor->save_resource_as(RES(r), fpath);
}
+void FileSystemDock::_focus_current_search_box() {
+ LineEdit *current_search_box = nullptr;
+ if (display_mode == DISPLAY_MODE_TREE_ONLY) {
+ current_search_box = tree_search_box;
+ } else if (display_mode == DISPLAY_MODE_SPLIT) {
+ current_search_box = file_list_search_box;
+ }
+
+ if (current_search_box) {
+ current_search_box->grab_focus();
+ current_search_box->select_all();
+ }
+}
+
void FileSystemDock::_search_changed(const String &p_text, const Control *p_from) {
if (searched_string.length() == 0) {
// Register the uncollapsed paths before they change.
@@ -2044,13 +2061,13 @@ Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from)
// Check if the first selected is in favorite.
TreeItem *selected = tree->get_next_selected(tree->get_root());
while (selected) {
- TreeItem *favorites_item = tree->get_root()->get_children();
+ TreeItem *favorites_item = tree->get_root()->get_first_child();
if (selected == favorites_item) {
// The "Favorites" item is not draggable.
return Variant();
}
- bool is_favorite = selected->get_parent() != nullptr && tree->get_root()->get_children() == selected->get_parent();
+ bool is_favorite = selected->get_parent() != nullptr && tree->get_root()->get_first_child() == selected->get_parent();
all_favorites &= is_favorite;
all_not_favorites &= !is_favorite;
selected = tree->get_next_selected(selected);
@@ -2096,7 +2113,7 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da
}
int drop_section = tree->get_drop_section_at_position(p_point);
- TreeItem *favorites_item = tree->get_root()->get_children();
+ TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *resources_item = favorites_item->get_next();
@@ -2172,7 +2189,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
int drop_position;
Vector<String> files = drag_data["files"];
- TreeItem *favorites_item = tree->get_root()->get_children();
+ TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *resources_item = favorites_item->get_next();
if (ti == favorites_item) {
@@ -2246,7 +2263,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
}
}
if (!to_move.is_empty()) {
- if (Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
for (int i = 0; i < to_move.size(); i++) {
String new_path;
String new_path_base;
@@ -2310,10 +2327,10 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori
int section = tree->get_drop_section_at_position(p_point);
if (ti) {
// Check the favorites first.
- if (ti == tree->get_root()->get_children() && section >= 0) {
+ if (ti == tree->get_root()->get_first_child() && section >= 0) {
target_favorites = true;
return;
- } else if (ti->get_parent() == tree->get_root()->get_children()) {
+ } else if (ti->get_parent() == tree->get_root()->get_first_child()) {
target_favorites = true;
return;
} else {
@@ -2329,7 +2346,7 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori
return;
}
} else {
- if (ti->get_parent() != tree->get_root()->get_children()) {
+ if (ti->get_parent() != tree->get_root()->get_first_child()) {
// Not in the favorite section.
if (fpath != "res://") {
// We drop between two files
@@ -2572,6 +2589,8 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
_tree_rmb_option(FILE_REMOVE);
} else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) {
_tree_rmb_option(FILE_RENAME);
+ } else if (ED_IS_SHORTCUT("editor/open_search", p_event)) {
+ _focus_current_search_box();
} else {
return;
}
@@ -2591,6 +2610,8 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
_file_list_rmb_option(FILE_REMOVE);
} else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) {
_file_list_rmb_option(FILE_RENAME);
+ } else if (ED_IS_SHORTCUT("editor/open_search", p_event)) {
+ _focus_current_search_box();
} else {
return;
}
@@ -2713,12 +2734,12 @@ MenuButton *FileSystemDock::_create_file_menu_button() {
PopupMenu *p = button->get_popup();
p->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_sort_popup));
- p->add_radio_check_item("Sort by Name (Ascending)", FILE_SORT_NAME);
- p->add_radio_check_item("Sort by Name (Descending)", FILE_SORT_NAME_REVERSE);
- p->add_radio_check_item("Sort by Type (Ascending)", FILE_SORT_TYPE);
- p->add_radio_check_item("Sort by Type (Descending)", FILE_SORT_TYPE_REVERSE);
- p->add_radio_check_item("Sort by Last Modified", FILE_SORT_MODIFIED_TIME);
- p->add_radio_check_item("Sort by First Modified", FILE_SORT_MODIFIED_TIME_REVERSE);
+ p->add_radio_check_item(TTR("Sort by Name (Ascending)"), FILE_SORT_NAME);
+ p->add_radio_check_item(TTR("Sort by Name (Descending)"), FILE_SORT_NAME_REVERSE);
+ p->add_radio_check_item(TTR("Sort by Type (Ascending)"), FILE_SORT_TYPE);
+ p->add_radio_check_item(TTR("Sort by Type (Descending)"), FILE_SORT_TYPE_REVERSE);
+ p->add_radio_check_item(TTR("Sort by Last Modified"), FILE_SORT_MODIFIED_TIME);
+ p->add_radio_check_item(TTR("Sort by First Modified"), FILE_SORT_MODIFIED_TIME_REVERSE);
p->set_item_checked(file_sort, true);
return button;
}
@@ -2730,9 +2751,9 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_tree_thumbnail_done"), &FileSystemDock::_tree_thumbnail_done);
ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw", "position", "from"), &FileSystemDock::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw", "position", "data", "from"), &FileSystemDock::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw", "position", "data", "from"), &FileSystemDock::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "position", "from"), &FileSystemDock::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &FileSystemDock::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &FileSystemDock::drop_data_fw);
ClassDB::bind_method(D_METHOD("navigate_to_path", "path"), &FileSystemDock::navigate_to_path);
ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock);
@@ -2756,22 +2777,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
// `KEY_MASK_CMD | KEY_C` conflicts with other editor shortcuts.
ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_C);
ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KEY_MASK_CMD | KEY_D);
-
-#if defined(WINDOWS_ENABLED)
- // TRANSLATORS: This string is only used on Windows, as it refers to the system trash
- // as "Recycle Bin" instead of "Trash". Make sure to use the translation of "Recycle Bin"
- // recommended by Microsoft for the target language.
- ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Recycle Bin"), KEY_DELETE);
-#elif defined(OSX_ENABLED)
- // TRANSLATORS: This string is only used on macOS, as it refers to the system trash
- // as "Bin" instead of "Trash". Make sure to use the translation of "Bin"
- // recommended by Apple for the target language.
- ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Bin"), KEY_DELETE);
-#else
- // TRANSLATORS: This string is only used on platforms other than Windows and macOS.
- ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Trash"), KEY_DELETE);
-#endif
-
+ ED_SHORTCUT("filesystem_dock/delete", TTR("Delete"), KEY_DELETE);
ED_SHORTCUT("filesystem_dock/rename", TTR("Rename..."), KEY_F2);
VBoxContainer *top_vbc = memnew(VBoxContainer);
@@ -2802,7 +2808,6 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
toolbar_hbc->add_child(current_path);
button_reload = memnew(Button);
- button_reload->set_flat(true);
button_reload->connect("pressed", callable_mp(this, &FileSystemDock::_rescan));
button_reload->set_focus_mode(FOCUS_NONE);
button_reload->set_tooltip(TTR("Re-Scan Filesystem"));
@@ -2810,11 +2815,11 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
toolbar_hbc->add_child(button_reload);
button_toggle_display_mode = memnew(Button);
- button_toggle_display_mode->set_flat(true);
button_toggle_display_mode->set_toggle_mode(true);
button_toggle_display_mode->connect("toggled", callable_mp(this, &FileSystemDock::_toggle_split_mode));
button_toggle_display_mode->set_focus_mode(FOCUS_NONE);
button_toggle_display_mode->set_tooltip(TTR("Toggle Split Mode"));
+ button_toggle_display_mode->set_flat(true);
toolbar_hbc->add_child(button_toggle_display_mode);
toolbar2_hbc = memnew(HBoxContainer);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 39dc4784b8..12c567fb69 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -43,7 +43,7 @@
#include "scene/gui/tree.h"
#include "scene/main/timer.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "core/os/thread.h"
#include "create_dialog.h"
@@ -253,6 +253,7 @@ private:
void _toggle_split_mode(bool p_active);
+ void _focus_current_search_box();
void _search_changed(const String &p_text, const Control *p_from);
MenuButton *_create_file_menu_button();
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 47079a92b7..c29b5d5906 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -30,7 +30,7 @@
#include "find_in_files.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "core/os/os.h"
#include "editor_node.h"
#include "editor_scale.h"
@@ -311,7 +311,7 @@ FindInFilesDialog::FindInFilesDialog() {
_search_text_line_edit = memnew(LineEdit);
_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));
+ _search_text_line_edit->connect("text_submitted", callable_mp(this, &FindInFilesDialog::_on_search_text_submitted));
gc->add_child(_search_text_line_edit);
_replace_label = memnew(Label);
@@ -321,7 +321,7 @@ FindInFilesDialog::FindInFilesDialog() {
_replace_text_line_edit = memnew(LineEdit);
_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->connect("text_submitted", callable_mp(this, &FindInFilesDialog::_on_replace_text_submitted));
_replace_text_line_edit->hide();
gc->add_child(_replace_text_line_edit);
@@ -503,7 +503,7 @@ void FindInFilesDialog::_on_search_text_modified(String text) {
_replace_button->set_disabled(get_search_text().is_empty());
}
-void FindInFilesDialog::_on_search_text_entered(String text) {
+void FindInFilesDialog::_on_search_text_submitted(String text) {
// This allows to trigger a global search without leaving the keyboard
if (!_find_button->is_disabled()) {
if (_mode == SEARCH_MODE) {
@@ -518,7 +518,7 @@ void FindInFilesDialog::_on_search_text_entered(String text) {
}
}
-void FindInFilesDialog::_on_replace_text_entered(String text) {
+void FindInFilesDialog::_on_replace_text_submitted(String text) {
// This allows to trigger a global search without leaving the keyboard
if (!_replace_button->is_disabled()) {
if (_mode == REPLACE_MODE) {
@@ -530,7 +530,7 @@ void FindInFilesDialog::_on_replace_text_entered(String text) {
void FindInFilesDialog::_on_folder_selected(String path) {
int i = path.find("://");
if (i != -1) {
- path = path.right(i + 3);
+ path = path.substr(i + 3);
}
_folder_line_edit->set_text(path);
}
@@ -763,8 +763,10 @@ void FindInFilesPanel::draw_result_text(Object *item_obj, Rect2 rect) {
match_rect.position.y += 1 * EDSCALE;
match_rect.size.y -= 2 * EDSCALE;
- _results_display->draw_rect(match_rect, Color(0, 0, 0, 0.5));
- // Text is drawn by Tree already
+ // Use the inverted accent color to help match rectangles stand out even on the currently selected line.
+ _results_display->draw_rect(match_rect, get_theme_color("accent_color", "Editor").inverted() * Color(1, 1, 1, 0.5));
+
+ // Text is drawn by Tree already.
}
void FindInFilesPanel::_on_item_edited() {
@@ -838,7 +840,7 @@ void FindInFilesPanel::_on_replace_all_clicked() {
String fpath = file_item->get_metadata(0);
Vector<Result> locations;
- for (TreeItem *item = file_item->get_children(); item; item = item->get_next()) {
+ for (TreeItem *item = file_item->get_first_child(); item; item = item->get_next()) {
if (!item->is_checked(0)) {
continue;
}
@@ -932,7 +934,7 @@ void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result>
continue;
}
- line = line.left(repl_begin) + new_text + line.right(repl_end);
+ line = line.left(repl_begin) + new_text + line.substr(repl_end);
// keep an offset in case there are successive replaces in the same line
offset += new_text.length() - (repl_end - repl_begin);
}
diff --git a/editor/find_in_files.h b/editor/find_in_files.h
index b9d60a8d4f..488f14a922 100644
--- a/editor/find_in_files.h
+++ b/editor/find_in_files.h
@@ -128,8 +128,8 @@ private:
void _on_folder_button_pressed();
void _on_folder_selected(String path);
void _on_search_text_modified(String text);
- void _on_search_text_entered(String text);
- void _on_replace_text_entered(String text);
+ void _on_search_text_submitted(String text);
+ void _on_replace_text_submitted(String text);
FindInFilesMode _mode;
LineEdit *_search_text_line_edit;
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index f2a110ca03..1b11ec4451 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -52,7 +52,7 @@ void GroupDialog::_group_selected() {
selected_group = groups->get_selected()->get_text(0);
_load_nodes(scene_tree->get_edited_scene_root());
- group_empty->set_visible(!remove_node_root->get_children());
+ group_empty->set_visible(!remove_node_root->get_first_child());
}
void GroupDialog::_load_nodes(Node *p_current) {
@@ -217,7 +217,7 @@ void GroupDialog::_group_renamed() {
}
const String name = renamed_group->get_text(0).strip_edges();
- for (TreeItem *E = groups_root->get_children(); E; E = E->get_next()) {
+ for (TreeItem *E = groups_root->get_first_child(); E; E = E->get_next()) {
if (E != renamed_group && E->get_text(0) == name) {
renamed_group->set_text(0, selected_group);
error->set_text(TTR("Group name already exists."));
@@ -274,7 +274,7 @@ void GroupDialog::_rename_group_item(const String &p_old_name, const String &p_n
selected_group = p_new_name;
- for (TreeItem *E = groups_root->get_children(); E; E = E->get_next()) {
+ for (TreeItem *E = groups_root->get_first_child(); E; E = E->get_next()) {
if (E->get_text(0) == p_old_name) {
E->set_text(0, p_new_name);
return;
@@ -351,7 +351,7 @@ void GroupDialog::_delete_group_item(const String &p_name) {
selected_group = "";
}
- for (TreeItem *E = groups_root->get_children(); E; E = E->get_next()) {
+ for (TreeItem *E = groups_root->get_first_child(); E; E = E->get_next()) {
if (E->get_text(0) == p_name) {
groups_root->remove_child(E);
return;
@@ -446,7 +446,7 @@ GroupDialog::GroupDialog() {
add_group_text = memnew(LineEdit);
chbc->add_child(add_group_text);
add_group_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- add_group_text->connect("text_entered", callable_mp(this, &GroupDialog::_add_group_pressed));
+ add_group_text->connect("text_submitted", callable_mp(this, &GroupDialog::_add_group_pressed));
Button *add_group_button = memnew(Button);
add_group_button->set_text(TTR("Add"));
@@ -689,7 +689,7 @@ GroupsEditor::GroupsEditor() {
group_name = memnew(LineEdit);
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));
+ group_name->connect("text_submitted", callable_mp(this, &GroupsEditor::_add_group));
add = memnew(Button);
add->set_text(TTR("Add"));
diff --git a/editor/icons/2D.svg b/editor/icons/2D.svg
index afb9f4b45f..fdd2e473e3 100644
--- a/editor/icons/2D.svg
+++ b/editor/icons/2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.9844 1.002a1.0001 1.0001 0 0 0 -.69141.29102l-2 2a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l.29297-.29297v8.5859h8.5859l-.29297.29297a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l2-2a1.0001 1.0001 0 0 0 0-1.4141l-2-2a1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l.29297.29297h-6.5859v-6.5859l.29297.29297a1 1 0 0 0 1.4141 0 1 1 0 0 0 0-1.4141l-2-2a1.0001 1.0001 0 0 0 -.72266-.29102z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.984375 15a1 1 0 0 1 -.6914062-.291316l-2-2a1 1 0 0 1 0-1.414062 1 1 0 0 1 1.4140624 0l.2929688.292968v-8.5859371h8.585938l-.292969-.292969a1 1 0 0 1 0-1.414062 1 1 0 0 1 1.414062 0l2 2a1 1 0 0 1 0 1.414062l-2 2.0000002a1 1 0 0 1 -.720703.2910157 1 1 0 0 1 -.693359-.2910157 1 1 0 0 1 0-1.4140622l.292969-.292969h-6.585938v6.5859371l.2929688-.292968a1 1 0 0 1 1.4140624 0 1 1 0 0 1 0 1.414062l-2 2a1 1 0 0 1 -.7226562.291316z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/AABB.svg b/editor/icons/AABB.svg
index 03ec25caf2..7db093cc0d 100644
--- a/editor/icons/AABB.svg
+++ b/editor/icons/AABB.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1a3 3 0 0 0 -3 3 3 3 0 0 0 .77734 2.0117 3 3 0 0 0 -2.7773 2.9883 3 3 0 0 0 3 3h2v-5h2v-6h-2zm6 0v5.1738a3 3 0 0 0 -1-.17383v-2h-2v8h2a3 3 0 0 0 3-3 3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2h-2zm-6 2v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm8 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm-10 3v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm7 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#ee7991"/><path d="m8 4v8h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm-5 2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-6zm0 2v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm7 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#fff" fill-opacity=".23529"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1a3 3 0 0 0 -3 3 3 3 0 0 0 .77734 2.0117 3 3 0 0 0 -2.7773 2.9883 3 3 0 0 0 3 3h2v-5h2v-6h-2zm6 0v5.1738a3 3 0 0 0 -1-.17383v-2h-2v8h2a3 3 0 0 0 3-3 3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2h-2zm-6 2v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm8 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm-10 3v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm7 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#ee5677"/><path d="m8 4v8h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm-5 2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-6zm0 2v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm7 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#fff" fill-opacity=".23529"/></svg>
diff --git a/editor/icons/AddAtlasTile.svg b/editor/icons/AddAtlasTile.svg
deleted file mode 100644
index a6d94005a8..0000000000
--- a/editor/icons/AddAtlasTile.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 1v6h-6v2h6v6h2v-6h6v-2h-6v-6z" fill="#c9cfd4"/></svg>
diff --git a/editor/icons/AddAutotile.svg b/editor/icons/AddAutotile.svg
deleted file mode 100644
index 52664b3eb6..0000000000
--- a/editor/icons/AddAutotile.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 1v6h-6v2h6v6h2v-6h6v-2h-6v-6z" fill="#4490fc"/></svg>
diff --git a/editor/icons/AddSingleTile.svg b/editor/icons/AddSingleTile.svg
deleted file mode 100644
index 64bf1c99c0..0000000000
--- a/editor/icons/AddSingleTile.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 1v6h-6v2h6v6h2v-6h6v-2h-6v-6z" fill="#fce844"/></svg>
diff --git a/editor/icons/AddSplit.svg b/editor/icons/AddSplit.svg
index 5c034d8d12..e46949182c 100644
--- a/editor/icons/AddSplit.svg
+++ b/editor/icons/AddSplit.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 13 10-10" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#84ffb1"/><circle cx="4" cy="12" fill="none" r="2"/><path d="m13 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-10 10a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 13 10-10" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#5fff97"/><circle cx="4" cy="12" fill="none" r="2"/><path d="m13 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-10 10a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Anchor.svg b/editor/icons/Anchor.svg
index cb40970ba3..37bad8bec6 100644
--- a/editor/icons/Anchor.svg
+++ b/editor/icons/Anchor.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a3 3 0 0 0 -3 3 3 3 0 0 0 2 2.8262v.17383h-2v2h2v3.8984a5 5 0 0 1 -3.8281-3.6035l-1.9336.51758a7 7 0 0 0 6.7617 5.1875 7 7 0 0 0 6.7617-5.1875l-1.9375-.51953a5 5 0 0 1 -3.8242 3.6035v-3.8965h2v-2h-2v-.17578a3 3 0 0 0 2-2.8242 3 3 0 0 0 -3-3zm0 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a3 3 0 0 0 -3 3 3 3 0 0 0 2 2.8262v.17383h-2v2h2v3.8984a5 5 0 0 1 -3.8281-3.6035l-1.9336.51758a7 7 0 0 0 6.7617 5.1875 7 7 0 0 0 6.7617-5.1875l-1.9375-.51953a5 5 0 0 1 -3.8242 3.6035v-3.8965h2v-2h-2v-.17578a3 3 0 0 0 2-2.8242 3 3 0 0 0 -3-3zm0 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#8eef97"/></svg>
diff --git a/editor/icons/AnimatedSprite2D.svg b/editor/icons/AnimatedSprite2D.svg
index 0c9d2933ee..b22aeadeb6 100644
--- a/editor/icons/AnimatedSprite2D.svg
+++ b/editor/icons/AnimatedSprite2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#a5b7f3"><path d="m7 0c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v6c1.108 0 2-.89199 2-2v-6c0-1.108-.89199-2-2-2z" fill-opacity=".39216"/><path d="m5 2c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2z" fill-opacity=".58824"/><path d="m3 4c-1.108 0-2 .89199-2 2v7c0 1.108.89199 2 2 2h7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2zm0 4c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm7 0c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm-6 4h5a2.5 2 0 0 1 -1.25 1.7324 2.5 2 0 0 1 -2.5 0 2.5 2 0 0 1 -1.25-1.7324z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#8da5f3"><path d="m7 0c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v6c1.108 0 2-.89199 2-2v-6c0-1.108-.89199-2-2-2z" fill-opacity=".39216"/><path d="m5 2c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2z" fill-opacity=".58824"/><path d="m3 4c-1.108 0-2 .89199-2 2v7c0 1.108.89199 2 2 2h7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2zm0 4c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm7 0c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm-6 4h5a2.5 2 0 0 1 -1.25 1.7324 2.5 2 0 0 1 -2.5 0 2.5 2 0 0 1 -1.25-1.7324z"/></g></svg>
diff --git a/editor/icons/AnimatedSprite3D.svg b/editor/icons/AnimatedSprite3D.svg
index b25ebae683..99520a3bc2 100644
--- a/editor/icons/AnimatedSprite3D.svg
+++ b/editor/icons/AnimatedSprite3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc9c9c"><path d="m7 0c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v6c1.108 0 2-.89199 2-2v-6c0-1.108-.89199-2-2-2z" fill-opacity=".39216"/><path d="m5 2c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2z" fill-opacity=".58824"/><path d="m3 4c-1.108 0-2 .89199-2 2v7c0 1.108.89199 2 2 2h7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2zm0 4c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm7 0c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm-6 4h5a2.5 2 0 0 1 -1.25 1.7324 2.5 2 0 0 1 -2.5 0 2.5 2 0 0 1 -1.25-1.7324z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><path d="m7 0c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v6c1.108 0 2-.89199 2-2v-6c0-1.108-.89199-2-2-2z" fill-opacity=".39216"/><path d="m5 2c-1.108 0-2 .89199-2 2h7c1.108 0 2 .89199 2 2v7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2z" fill-opacity=".58824"/><path d="m3 4c-1.108 0-2 .89199-2 2v7c0 1.108.89199 2 2 2h7c1.108 0 2-.89199 2-2v-7c0-1.108-.89199-2-2-2zm0 4c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm7 0c.554 0 1 .446 1 1v1c0 .554-.446 1-1 1s-1-.446-1-1v-1c0-.554.446-1 1-1zm-6 4h5a2.5 2 0 0 1 -1.25 1.7324 2.5 2 0 0 1 -2.5 0 2.5 2 0 0 1 -1.25-1.7324z"/></g></svg>
diff --git a/editor/icons/AnimationPlayer.svg b/editor/icons/AnimationPlayer.svg
index 52b6b02c15..68a2c82dd0 100644
--- a/editor/icons/AnimationPlayer.svg
+++ b/editor/icons/AnimationPlayer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1037.4v14h1.1667v-2h1.8333v2h8v-2h2v2h1v-14h-1v2h-2v-2h-8v2h-1.8333v-2zm1.1667 4h1.8333v2h-1.8333zm9.8333 0h2v2h-2zm-9.8333 4h1.8333v2h-1.8333zm9.8333 0h2v2h-2z" fill="#cea4f1" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1037.4v14h1.1667v-2h1.8333v2h8v-2h2v2h1v-14h-1v2h-2v-2h-8v2h-1.8333v-2zm1.1667 4h1.8333v2h-1.8333zm9.8333 0h2v2h-2zm-9.8333 4h1.8333v2h-1.8333zm9.8333 0h2v2h-2z" fill="#c38ef1" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/AnimationTree.svg b/editor/icons/AnimationTree.svg
index d6484097c9..04c4d60402 100644
--- a/editor/icons/AnimationTree.svg
+++ b/editor/icons/AnimationTree.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h1.166v-2h1.834v2h8v-2h2v2h1v-14h-1v2h-2v-2h-8v2h-1.834v-2zm4 3h2v1 1h1 3v2h-2v1 1h1 1v2h-1-2a1.0001 1.0001 0 0 1 -1-1v-1-2h-1a1.0001 1.0001 0 0 1 -1-1v-1-1zm-2.834 1h1.834v2h-1.834zm9.834 0h2v2h-2zm-9.834 4h1.834v2h-1.834zm9.834 0h2v2h-2z" fill="#cea4f1"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h1.166v-2h1.834v2h8v-2h2v2h1v-14h-1v2h-2v-2h-8v2h-1.834v-2zm4 3h2v1 1h1 3v2h-2v1 1h1 1v2h-1-2a1.0001 1.0001 0 0 1 -1-1v-1-2h-1a1.0001 1.0001 0 0 1 -1-1v-1-1zm-2.834 1h1.834v2h-1.834zm9.834 0h2v2h-2zm-9.834 4h1.834v2h-1.834zm9.834 0h2v2h-2z" fill="#c38ef1"/></svg>
diff --git a/editor/icons/Area2D.svg b/editor/icons/Area2D.svg
index 005f70ed48..2150a582d2 100644
--- a/editor/icons/Area2D.svg
+++ b/editor/icons/Area2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 2h2v-2h2v-2zm10 0v2h2v2h2v-4zm-7 3v2 4 2h8v-2-6zm2 2h4v4h-4zm-5 5v2 2h2 2v-2h-2v-2zm12 0v2h-2v2h4v-2-2z" fill="#a5b7f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 2h2v-2h2v-2zm10 0v2h2v2h2v-4zm-7 3v2 4 2h8v-2-6zm2 2h4v4h-4zm-5 5v2 2h2 2v-2h-2v-2zm12 0v2h-2v2h4v-2-2z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/Area3D.svg b/editor/icons/Area3D.svg
index 4be8a2cced..88b6a42b23 100644
--- a/editor/icons/Area3D.svg
+++ b/editor/icons/Area3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 2h2v-2h2v-2zm10 0v2h2v2h2v-4zm-7 3v2 4 2h8v-2-6zm2 2h4v4h-4zm-5 5v2 2h2 2v-2h-2v-2zm12 0v2h-2v2h4v-2-2z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 2h2v-2h2v-2zm10 0v2h2v2h2v-4zm-7 3v2 4 2h8v-2-6zm2 2h4v4h-4zm-5 5v2 2h2 2v-2h-2v-2zm12 0v2h-2v2h4v-2-2z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/ArrayMesh.svg b/editor/icons/ArrayMesh.svg
index 3a33a966aa..2494a519fb 100644
--- a/editor/icons/ArrayMesh.svg
+++ b/editor/icons/ArrayMesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm10 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-2 7v3h-3v2h3v3h2v-3h3v-2h-3v-3zm-8 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm10 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-2 7v3h-3v2h3v3h2v-3h3v-2h-3v-3zm-8 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/AspectRatioContainer.svg b/editor/icons/AspectRatioContainer.svg
index a7aef8e028..d28bcc7193 100644
--- a/editor/icons/AspectRatioContainer.svg
+++ b/editor/icons/AspectRatioContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1c-1.1046 0-2 .89543-2 2h2zm2 0v2h2v-2zm4 0v2h2c0-1.1046-.89543-2-2-2zm-8 4v2h2v-2zm8 0v2h2v-2zm-8 4v2h2v-2zm8 0v2h2v-2zm-8 4c0 1.1046.89543 2 2 2v-2zm4 0v2h2v-2zm4 0v2c1.1046 0 2-.89543 2-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1c-1.1046 0-2 .89543-2 2h2zm2 0v2h2v-2zm4 0v2h2c0-1.1046-.89543-2-2-2zm-8 4v2h2v-2zm8 0v2h2v-2zm-8 4v2h2v-2zm8 0v2h2v-2zm-8 4c0 1.1046.89543 2 2 2v-2zm4 0v2h2v-2zm4 0v2c1.1046 0 2-.89543 2-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/AudioBusLayout.svg b/editor/icons/AudioBusLayout.svg
index 3b1f3e7a0d..9928f369e7 100644
--- a/editor/icons/AudioBusLayout.svg
+++ b/editor/icons/AudioBusLayout.svg
@@ -1 +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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1dc7a"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m3 1c-1.108 0-2 .89199-2 2v10c0 1.108.89199 2 2 2h2c1.108 0 2-.89199 2-2v-10c0-1.108-.89199-2-2-2zm8 0c-1.108 0-2 .89199-2 2v10c0 1.108.89199 2 2 2h2c1.108 0 2-.89199 2-2v-10c0-1.108-.89199-2-2-2zm-8 1h2c.55401 0 1 .44599 1 1v10c0 .55401-.44599 1-1 1h-2c-.55401 0-1-.44599-1-1v-10c0-.55401.44599-1 1-1z" fill="url(#a)"/></svg>
+<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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m3 1c-1.108 0-2 .89199-2 2v10c0 1.108.89199 2 2 2h2c1.108 0 2-.89199 2-2v-10c0-1.108-.89199-2-2-2zm8 0c-1.108 0-2 .89199-2 2v10c0 1.108.89199 2 2 2h2c1.108 0 2-.89199 2-2v-10c0-1.108-.89199-2-2-2zm-8 1h2c.55401 0 1 .44599 1 1v10c0 .55401-.44599 1-1 1h-2c-.55401 0-1-.44599-1-1v-10c0-.55401.44599-1 1-1z" fill="url(#a)"/></svg>
diff --git a/editor/icons/AudioStreamMP3.svg b/editor/icons/AudioStreamMP3.svg
index 900d5873fe..dc034c90de 100644
--- a/editor/icons/AudioStreamMP3.svg
+++ b/editor/icons/AudioStreamMP3.svg
@@ -1 +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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1dc7a"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m11.971 1.002c-.08326.00207-.16593.014541-.24609.037109l-7 2c-.42881.12287-.7244.51487-.72461.96094v5.5508c-.16454-.033679-.33205-.050692-.5-.050781-1.3807 0-2.5 1.1193-2.5 2.5-.00000475 1.3807 1.1193 2.5 2.5 2.5 1.3456-.0013 2.4488-1.0674 2.4961-2.4121.0025906-.029226.003894-.058551.0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5c-.000916-.56314-.4664-1.0145-1.0293-.99805zm-1.4707 6.998c-.277 0-.5.223-.5.5v5c0 .277.223.5.5.5s.5-.223.5-.5v-5c0-.277-.223-.5-.5-.5zm2 1c-.277 0-.5.223-.5.5v3c0 .277.223.5.5.5s.5-.223.5-.5v-3c0-.277-.223-.5-.5-.5zm-4 1c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5zm6 0c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5z" fill="url(#a)"/></svg>
+<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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m11.971 1.002c-.08326.00207-.16593.014541-.24609.037109l-7 2c-.42881.12287-.7244.51487-.72461.96094v5.5508c-.16454-.033679-.33205-.050692-.5-.050781-1.3807 0-2.5 1.1193-2.5 2.5-.00000475 1.3807 1.1193 2.5 2.5 2.5 1.3456-.0013 2.4488-1.0674 2.4961-2.4121.0025906-.029226.003894-.058551.0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5c-.000916-.56314-.4664-1.0145-1.0293-.99805zm-1.4707 6.998c-.277 0-.5.223-.5.5v5c0 .277.223.5.5.5s.5-.223.5-.5v-5c0-.277-.223-.5-.5-.5zm2 1c-.277 0-.5.223-.5.5v3c0 .277.223.5.5.5s.5-.223.5-.5v-3c0-.277-.223-.5-.5-.5zm-4 1c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5zm6 0c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5z" fill="url(#a)"/></svg>
diff --git a/editor/icons/AudioStreamOGGVorbis.svg b/editor/icons/AudioStreamOGGVorbis.svg
index 900d5873fe..dc034c90de 100644
--- a/editor/icons/AudioStreamOGGVorbis.svg
+++ b/editor/icons/AudioStreamOGGVorbis.svg
@@ -1 +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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1dc7a"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m11.971 1.002c-.08326.00207-.16593.014541-.24609.037109l-7 2c-.42881.12287-.7244.51487-.72461.96094v5.5508c-.16454-.033679-.33205-.050692-.5-.050781-1.3807 0-2.5 1.1193-2.5 2.5-.00000475 1.3807 1.1193 2.5 2.5 2.5 1.3456-.0013 2.4488-1.0674 2.4961-2.4121.0025906-.029226.003894-.058551.0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5c-.000916-.56314-.4664-1.0145-1.0293-.99805zm-1.4707 6.998c-.277 0-.5.223-.5.5v5c0 .277.223.5.5.5s.5-.223.5-.5v-5c0-.277-.223-.5-.5-.5zm2 1c-.277 0-.5.223-.5.5v3c0 .277.223.5.5.5s.5-.223.5-.5v-3c0-.277-.223-.5-.5-.5zm-4 1c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5zm6 0c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5z" fill="url(#a)"/></svg>
+<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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m11.971 1.002c-.08326.00207-.16593.014541-.24609.037109l-7 2c-.42881.12287-.7244.51487-.72461.96094v5.5508c-.16454-.033679-.33205-.050692-.5-.050781-1.3807 0-2.5 1.1193-2.5 2.5-.00000475 1.3807 1.1193 2.5 2.5 2.5 1.3456-.0013 2.4488-1.0674 2.4961-2.4121.0025906-.029226.003894-.058551.0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5c-.000916-.56314-.4664-1.0145-1.0293-.99805zm-1.4707 6.998c-.277 0-.5.223-.5.5v5c0 .277.223.5.5.5s.5-.223.5-.5v-5c0-.277-.223-.5-.5-.5zm2 1c-.277 0-.5.223-.5.5v3c0 .277.223.5.5.5s.5-.223.5-.5v-3c0-.277-.223-.5-.5-.5zm-4 1c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5zm6 0c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5z" fill="url(#a)"/></svg>
diff --git a/editor/icons/AudioStreamPlayer.svg b/editor/icons/AudioStreamPlayer.svg
index 48aa7c2904..6d074c0744 100644
--- a/editor/icons/AudioStreamPlayer.svg
+++ b/editor/icons/AudioStreamPlayer.svg
@@ -1 +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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1dc7a"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><g transform="translate(0 -1036.4)"><path d="m10.023 1044.4c-.56139-.013-1.0235.4264-1.0234.9724v5.0542c.0006911.7482.83361 1.2154 1.5.8414l4-2.5262c.66694-.3743.66694-1.3104 0-1.6847l-4-2.5261c-.14505-.082-.30893-.1269-.47656-.131z" fill="#e0e0e0"/><path d="m11.971 1.002a1.0001 1.0001 0 0 0 -.24609.037109l-7 2a1.0001 1.0001 0 0 0 -.72461.96094v5.5508a2.5 2.5 0 0 0 -.5-.050781 2.5 2.5 0 0 0 -2.5 2.5 2.5 2.5 0 0 0 2.5 2.5 2.5 2.5 0 0 0 2.4961-2.4121 1.0001 1.0001 0 0 0 .0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5a1.0001 1.0001 0 0 0 -1.0293-.99805z" fill="url(#a)" transform="translate(0 1036.4)"/></g></svg>
+<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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><g transform="translate(0 -1036.4)"><path d="m10.023 1044.4c-.56139-.013-1.0235.4264-1.0234.9724v5.0542c.0006911.7482.83361 1.2154 1.5.8414l4-2.5262c.66694-.3743.66694-1.3104 0-1.6847l-4-2.5261c-.14505-.082-.30893-.1269-.47656-.131z" fill="#e0e0e0"/><path d="m11.971 1.002a1.0001 1.0001 0 0 0 -.24609.037109l-7 2a1.0001 1.0001 0 0 0 -.72461.96094v5.5508a2.5 2.5 0 0 0 -.5-.050781 2.5 2.5 0 0 0 -2.5 2.5 2.5 2.5 0 0 0 2.5 2.5 2.5 2.5 0 0 0 2.4961-2.4121 1.0001 1.0001 0 0 0 .0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5a1.0001 1.0001 0 0 0 -1.0293-.99805z" fill="url(#a)" transform="translate(0 1036.4)"/></g></svg>
diff --git a/editor/icons/AudioStreamPlayer2D.svg b/editor/icons/AudioStreamPlayer2D.svg
index 21cf751c92..0bf091de29 100644
--- a/editor/icons/AudioStreamPlayer2D.svg
+++ b/editor/icons/AudioStreamPlayer2D.svg
@@ -1 +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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1dc7a"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><g transform="translate(0 -1036.4)"><path d="m10.023 1044.4c-.56139-.013-1.0235.4264-1.0234.9724v5.0542c.0006911.7482.83361 1.2154 1.5.8414l4-2.5262c.66694-.3743.66694-1.3104 0-1.6847l-4-2.5261c-.14505-.082-.30893-.1269-.47656-.131z" fill="#a5b7f3"/><path d="m11.971 1.002a1.0001 1.0001 0 0 0 -.24609.037109l-7 2a1.0001 1.0001 0 0 0 -.72461.96094v5.5508a2.5 2.5 0 0 0 -.5-.050781 2.5 2.5 0 0 0 -2.5 2.5 2.5 2.5 0 0 0 2.5 2.5 2.5 2.5 0 0 0 2.4961-2.4121 1.0001 1.0001 0 0 0 .0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5a1.0001 1.0001 0 0 0 -1.0293-.99805z" fill="url(#a)" transform="translate(0 1036.4)"/></g></svg>
+<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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><g transform="translate(0 -1036.4)"><path d="m10.023 1044.4c-.56139-.013-1.0235.4264-1.0234.9724v5.0542c.0006911.7482.83361 1.2154 1.5.8414l4-2.5262c.66694-.3743.66694-1.3104 0-1.6847l-4-2.5261c-.14505-.082-.30893-.1269-.47656-.131z" fill="#8da5f3"/><path d="m11.971 1.002a1.0001 1.0001 0 0 0 -.24609.037109l-7 2a1.0001 1.0001 0 0 0 -.72461.96094v5.5508a2.5 2.5 0 0 0 -.5-.050781 2.5 2.5 0 0 0 -2.5 2.5 2.5 2.5 0 0 0 2.5 2.5 2.5 2.5 0 0 0 2.4961-2.4121 1.0001 1.0001 0 0 0 .0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5a1.0001 1.0001 0 0 0 -1.0293-.99805z" fill="url(#a)" transform="translate(0 1036.4)"/></g></svg>
diff --git a/editor/icons/AudioStreamPlayer3D.svg b/editor/icons/AudioStreamPlayer3D.svg
index d1e39e62f3..ebe3128a21 100644
--- a/editor/icons/AudioStreamPlayer3D.svg
+++ b/editor/icons/AudioStreamPlayer3D.svg
@@ -1 +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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1dc7a"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><g transform="translate(0 -1036.4)"><path d="m10.023 1044.4c-.56139-.013-1.0235.4264-1.0234.9724v5.0542c.0006911.7482.83361 1.2154 1.5.8414l4-2.5262c.66694-.3743.66694-1.3104 0-1.6847l-4-2.5261c-.14505-.082-.30893-.1269-.47656-.131z" fill="#fc9c9c"/><path d="m11.971 1.002a1.0001 1.0001 0 0 0 -.24609.037109l-7 2a1.0001 1.0001 0 0 0 -.72461.96094v5.5508a2.5 2.5 0 0 0 -.5-.050781 2.5 2.5 0 0 0 -2.5 2.5 2.5 2.5 0 0 0 2.5 2.5 2.5 2.5 0 0 0 2.4961-2.4121 1.0001 1.0001 0 0 0 .0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5a1.0001 1.0001 0 0 0 -1.0293-.99805z" fill="url(#a)" transform="translate(0 1036.4)"/></g></svg>
+<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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><g transform="translate(0 -1036.4)"><path d="m10.023 1044.4c-.56139-.013-1.0235.4264-1.0234.9724v5.0542c.0006911.7482.83361 1.2154 1.5.8414l4-2.5262c.66694-.3743.66694-1.3104 0-1.6847l-4-2.5261c-.14505-.082-.30893-.1269-.47656-.131z" fill="#fc7f7f"/><path d="m11.971 1.002a1.0001 1.0001 0 0 0 -.24609.037109l-7 2a1.0001 1.0001 0 0 0 -.72461.96094v5.5508a2.5 2.5 0 0 0 -.5-.050781 2.5 2.5 0 0 0 -2.5 2.5 2.5 2.5 0 0 0 2.5 2.5 2.5 2.5 0 0 0 2.4961-2.4121 1.0001 1.0001 0 0 0 .0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5a1.0001 1.0001 0 0 0 -1.0293-.99805z" fill="url(#a)" transform="translate(0 1036.4)"/></g></svg>
diff --git a/editor/icons/AudioStreamSample.svg b/editor/icons/AudioStreamSample.svg
index 900d5873fe..dc034c90de 100644
--- a/editor/icons/AudioStreamSample.svg
+++ b/editor/icons/AudioStreamSample.svg
@@ -1 +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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1dc7a"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m11.971 1.002c-.08326.00207-.16593.014541-.24609.037109l-7 2c-.42881.12287-.7244.51487-.72461.96094v5.5508c-.16454-.033679-.33205-.050692-.5-.050781-1.3807 0-2.5 1.1193-2.5 2.5-.00000475 1.3807 1.1193 2.5 2.5 2.5 1.3456-.0013 2.4488-1.0674 2.4961-2.4121.0025906-.029226.003894-.058551.0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5c-.000916-.56314-.4664-1.0145-1.0293-.99805zm-1.4707 6.998c-.277 0-.5.223-.5.5v5c0 .277.223.5.5.5s.5-.223.5-.5v-5c0-.277-.223-.5-.5-.5zm2 1c-.277 0-.5.223-.5.5v3c0 .277.223.5.5.5s.5-.223.5-.5v-3c0-.277-.223-.5-.5-.5zm-4 1c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5zm6 0c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5z" fill="url(#a)"/></svg>
+<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="1" y2="15"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m11.971 1.002c-.08326.00207-.16593.014541-.24609.037109l-7 2c-.42881.12287-.7244.51487-.72461.96094v5.5508c-.16454-.033679-.33205-.050692-.5-.050781-1.3807 0-2.5 1.1193-2.5 2.5-.00000475 1.3807 1.1193 2.5 2.5 2.5 1.3456-.0013 2.4488-1.0674 2.4961-2.4121.0025906-.029226.003894-.058551.0039062-.087891v-7.2441l5-1.4277v3.1719l2-1v-3.5c-.000916-.56314-.4664-1.0145-1.0293-.99805zm-1.4707 6.998c-.277 0-.5.223-.5.5v5c0 .277.223.5.5.5s.5-.223.5-.5v-5c0-.277-.223-.5-.5-.5zm2 1c-.277 0-.5.223-.5.5v3c0 .277.223.5.5.5s.5-.223.5-.5v-3c0-.277-.223-.5-.5-.5zm-4 1c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5zm6 0c-.277 0-.5.223-.5.5v1c0 .277.223.5.5.5s.5-.223.5-.5v-1c0-.277-.223-.5-.5-.5z" fill="url(#a)"/></svg>
diff --git a/editor/icons/BackBufferCopy.svg b/editor/icons/BackBufferCopy.svg
index 9bd40395c0..c85a35a410 100644
--- a/editor/icons/BackBufferCopy.svg
+++ b/editor/icons/BackBufferCopy.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v11h5v-2h-3v-7h6v-2zm6 3v11h8v-11zm2 2h4v7h-4z" fill="#a5b7f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v11h5v-2h-3v-7h6v-2zm6 3v11h8v-11zm2 2h4v7h-4z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/Basis.svg b/editor/icons/Basis.svg
index 5ff892888a..e425cf3bcd 100644
--- a/editor/icons/Basis.svg
+++ b/editor/icons/Basis.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v8h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm10 0v2h2v-2zm-3 2a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2zm7 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v-2h-2v4h4a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2zm-12 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#e3ec69"/><path d="m10 2v2h2v-2zm0 4v4h2v-4z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v8h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm10 0v2h2v-2zm-3 2a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2zm7 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v-2h-2v4h4a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2zm-12 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#e1ec41"/><path d="m10 2v2h2v-2zm0 4v4h2v-4z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/BezierHandlesBalanced.svg b/editor/icons/BezierHandlesBalanced.svg
index e4b8ae12e3..911029e431 100644
--- a/editor/icons/BezierHandlesBalanced.svg
+++ b/editor/icons/BezierHandlesBalanced.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#84c2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m7.4559186 5.1473018-4.7355323 1.5541798" fill="none" stroke="#84c2ff" stroke-width=".618"/><path d="m10.790357 4.2063094-2.5009748.9433136" fill="none" stroke="#84c2ff" stroke-width=".614897"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m1.7157324 5.8754878a1.2675855 1.1997888 0 0 0 -1.26757806 1.1992188 1.2675855 1.1997888 0 0 0 1.26757806 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765616-.8007812.84677333.80148375 0 0 1 .84765616-.8007812z"/><path d="m11.909414 2.4642073a1.2836218 1.231838 0 0 0 -1.283614 1.2312528 1.2836218 1.231838 0 0 0 1.283614 1.2312527 1.2836218 1.231838 0 0 0 1.283614-1.2312527 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.822172.85748593.82289328 0 0 1 -.858379-.822172.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m7.4559186 5.1473018-4.7355323 1.5541798" fill="none" stroke="#5fb2ff" stroke-width=".618"/><path d="m10.790357 4.2063094-2.5009748.9433136" fill="none" stroke="#5fb2ff" stroke-width=".614897"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m1.7157324 5.8754878a1.2675855 1.1997888 0 0 0 -1.26757806 1.1992188 1.2675855 1.1997888 0 0 0 1.26757806 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765616-.8007812.84677333.80148375 0 0 1 .84765616-.8007812z"/><path d="m11.909414 2.4642073a1.2836218 1.231838 0 0 0 -1.283614 1.2312528 1.2836218 1.231838 0 0 0 1.283614 1.2312527 1.2836218 1.231838 0 0 0 1.283614-1.2312527 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.822172.85748593.82289328 0 0 1 -.858379-.822172.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg>
diff --git a/editor/icons/BezierHandlesFree.svg b/editor/icons/BezierHandlesFree.svg
index 88f8146871..6e91288c79 100644
--- a/editor/icons/BezierHandlesFree.svg
+++ b/editor/icons/BezierHandlesFree.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#84c2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m7.6850253 4.7560401-3.776127.6607599" fill="none" stroke="#84c2ff" stroke-width=".805138"/><path d="m11.695505 2.3941651-2.999121 2.2935078" fill="none" stroke="#84c2ff" stroke-width=".730798"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m2.4961199 4.3976698a1.1997888 1.2675855 80.074672 0 0 -1.0419038 1.3997559 1.1997888 1.2675855 80.074672 0 0 1.4553094.9627848 1.1997888 1.2675855 80.074672 0 0 1.0419037-1.3997558 1.1997888 1.2675855 80.074672 0 0 -1.4553093-.9627849zm.074974.4171488a.80148375.84677333 80.074672 0 1 .9729986.6426896.80148375.84677333 80.074672 0 1 -.6969432.934902.80148375.84677333 80.074672 0 1 -.9729958-.6426902.80148375.84677333 80.074672 0 1 .6969432-.934902z"/><path d="m11.838896.64428913a1.231838 1.2836218 52.593897 0 0 -.271701 1.75779027 1.231838 1.2836218 52.593897 0 0 1.767576.1983008 1.231838 1.2836218 52.593897 0 0 .271701-1.75779027 1.231838 1.2836218 52.593897 0 0 -1.767576-.1983008zm.265925.3444462a.82289328.85748593 52.593897 0 1 1.181294.13165847.82289328.85748593 52.593897 0 1 -.182417 1.1745241.82289328.85748593 52.593897 0 1 -1.181291-.1316609.82289328.85748593 52.593897 0 1 .182417-1.17452347z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m7.6850253 4.7560401-3.776127.6607599" fill="none" stroke="#5fb2ff" stroke-width=".805138"/><path d="m11.695505 2.3941651-2.999121 2.2935078" fill="none" stroke="#5fb2ff" stroke-width=".730798"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m2.4961199 4.3976698a1.1997888 1.2675855 80.074672 0 0 -1.0419038 1.3997559 1.1997888 1.2675855 80.074672 0 0 1.4553094.9627848 1.1997888 1.2675855 80.074672 0 0 1.0419037-1.3997558 1.1997888 1.2675855 80.074672 0 0 -1.4553093-.9627849zm.074974.4171488a.80148375.84677333 80.074672 0 1 .9729986.6426896.80148375.84677333 80.074672 0 1 -.6969432.934902.80148375.84677333 80.074672 0 1 -.9729958-.6426902.80148375.84677333 80.074672 0 1 .6969432-.934902z"/><path d="m11.838896.64428913a1.231838 1.2836218 52.593897 0 0 -.271701 1.75779027 1.231838 1.2836218 52.593897 0 0 1.767576.1983008 1.231838 1.2836218 52.593897 0 0 .271701-1.75779027 1.231838 1.2836218 52.593897 0 0 -1.767576-.1983008zm.265925.3444462a.82289328.85748593 52.593897 0 1 1.181294.13165847.82289328.85748593 52.593897 0 1 -.182417 1.1745241.82289328.85748593 52.593897 0 1 -1.181291-.1316609.82289328.85748593 52.593897 0 1 .182417-1.17452347z"/></g></svg>
diff --git a/editor/icons/BezierHandlesMirror.svg b/editor/icons/BezierHandlesMirror.svg
index 3a4b75ee96..9180e31921 100644
--- a/editor/icons/BezierHandlesMirror.svg
+++ b/editor/icons/BezierHandlesMirror.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#84c2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m8.2033896 4.6779662h-3.8335021" fill="none" stroke="#84c2ff" stroke-width=".805138"/><path d="m11.931789 4.6440679h-3.7283994" fill="none" stroke="#84c2ff" stroke-width=".716709"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m3.1539157 3.4305762a1.2675855 1.1997888 0 0 0 -1.2675781 1.1992188 1.2675855 1.1997888 0 0 0 1.2675781 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.8476562-.8007812.84677333.80148375 0 0 1 .8476562-.8007812z"/><path d="m13.093969 3.3750567a1.2675855 1.1997888 0 0 0 -1.267578 1.1992188 1.2675855 1.1997888 0 0 0 1.267578 1.1992187 1.2675855 1.1997888 0 0 0 1.267578-1.1992187 1.2675855 1.1997888 0 0 0 -1.267578-1.1992188zm.002.4238282a.84677333.80148375 0 0 1 .847659.8007812.84677333.80148375 0 0 1 -.847656.8007812.84677333.80148375 0 0 1 -.847656-.8007812.84677333.80148375 0 0 1 .847656-.8007812z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m8.2033896 4.6779662h-3.8335021" fill="none" stroke="#5fb2ff" stroke-width=".805138"/><path d="m11.931789 4.6440679h-3.7283994" fill="none" stroke="#5fb2ff" stroke-width=".716709"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m3.1539157 3.4305762a1.2675855 1.1997888 0 0 0 -1.2675781 1.1992188 1.2675855 1.1997888 0 0 0 1.2675781 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.8476562-.8007812.84677333.80148375 0 0 1 .8476562-.8007812z"/><path d="m13.093969 3.3750567a1.2675855 1.1997888 0 0 0 -1.267578 1.1992188 1.2675855 1.1997888 0 0 0 1.267578 1.1992187 1.2675855 1.1997888 0 0 0 1.267578-1.1992187 1.2675855 1.1997888 0 0 0 -1.267578-1.1992188zm.002.4238282a.84677333.80148375 0 0 1 .847659.8007812.84677333.80148375 0 0 1 -.847656.8007812.84677333.80148375 0 0 1 -.847656-.8007812.84677333.80148375 0 0 1 .847656-.8007812z"/></g></svg>
diff --git a/editor/icons/Bone2D.svg b/editor/icons/Bone2D.svg
index 2298022d6a..efbe9ca5b0 100644
--- a/editor/icons/Bone2D.svg
+++ b/editor/icons/Bone2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.478 1037.4a2.4664 2.4663 0 0 0 -1.7804.7205 2.4664 2.4663 0 0 0 -.31408 3.1041l-3.559 3.5608a2.4664 2.4663 0 0 0 -3.1023.3121 2.4664 2.4663 0 0 0 0 3.4876 2.4664 2.4663 0 0 0 1.397.6955 2.4664 2.4663 0 0 0 .69561 1.397 2.4664 2.4663 0 0 0 3.4877 0 2.4664 2.4663 0 0 0 .31408-3.1041l3.5609-3.5608a2.4664 2.4663 0 0 0 3.1004-.3102 2.4664 2.4663 0 0 0 0-3.4875 2.4664 2.4663 0 0 0 -1.397-.6974 2.4664 2.4663 0 0 0 -.69561-1.3971 2.4664 2.4663 0 0 0 -1.7072-.7205z" fill="#a5b7f3" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.478 1037.4a2.4664 2.4663 0 0 0 -1.7804.7205 2.4664 2.4663 0 0 0 -.31408 3.1041l-3.559 3.5608a2.4664 2.4663 0 0 0 -3.1023.3121 2.4664 2.4663 0 0 0 0 3.4876 2.4664 2.4663 0 0 0 1.397.6955 2.4664 2.4663 0 0 0 .69561 1.397 2.4664 2.4663 0 0 0 3.4877 0 2.4664 2.4663 0 0 0 .31408-3.1041l3.5609-3.5608a2.4664 2.4663 0 0 0 3.1004-.3102 2.4664 2.4663 0 0 0 0-3.4875 2.4664 2.4663 0 0 0 -1.397-.6974 2.4664 2.4663 0 0 0 -.69561-1.3971 2.4664 2.4663 0 0 0 -1.7072-.7205z" fill="#8da5f3" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/BoneAttachment3D.svg b/editor/icons/BoneAttachment3D.svg
index 2f2a9cdae5..be15631b5e 100644
--- a/editor/icons/BoneAttachment3D.svg
+++ b/editor/icons/BoneAttachment3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.478 1037.4a2.4664 2.4663 0 0 0 -1.7804.7205 2.4664 2.4663 0 0 0 -.31408 3.1041l-3.559 3.5608a2.4664 2.4663 0 0 0 -3.1023.3121 2.4664 2.4663 0 0 0 0 3.4876 2.4664 2.4663 0 0 0 1.397.6955 2.4664 2.4663 0 0 0 .69561 1.397 2.4664 2.4663 0 0 0 3.4877 0 2.4664 2.4663 0 0 0 .31408-3.1041l3.5609-3.5608a2.4664 2.4663 0 0 0 3.1004-.3102 2.4664 2.4663 0 0 0 0-3.4875 2.4664 2.4663 0 0 0 -1.397-.6974 2.4664 2.4663 0 0 0 -.69561-1.3971 2.4664 2.4663 0 0 0 -1.7072-.7205z" fill="#fc9c9c" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.478 1037.4a2.4664 2.4663 0 0 0 -1.7804.7205 2.4664 2.4663 0 0 0 -.31408 3.1041l-3.559 3.5608a2.4664 2.4663 0 0 0 -3.1023.3121 2.4664 2.4663 0 0 0 0 3.4876 2.4664 2.4663 0 0 0 1.397.6955 2.4664 2.4663 0 0 0 .69561 1.397 2.4664 2.4663 0 0 0 3.4877 0 2.4664 2.4663 0 0 0 .31408-3.1041l3.5609-3.5608a2.4664 2.4663 0 0 0 3.1004-.3102 2.4664 2.4663 0 0 0 0-3.4875 2.4664 2.4663 0 0 0 -1.397-.6974 2.4664 2.4663 0 0 0 -.69561-1.3971 2.4664 2.4663 0 0 0 -1.7072-.7205z" fill="#fc7f7f" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/BoneTrack.svg b/editor/icons/BoneTrack.svg
index 34fb76e696..69a32f3595 100644
--- a/editor/icons/BoneTrack.svg
+++ b/editor/icons/BoneTrack.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.478 1037.4a2.4664 2.4663 0 0 0 -1.7804.7205 2.4664 2.4663 0 0 0 -.31408 3.1041l-3.559 3.5608a2.4664 2.4663 0 0 0 -3.1023.3121 2.4664 2.4663 0 0 0 0 3.4876 2.4664 2.4663 0 0 0 1.397.6955 2.4664 2.4663 0 0 0 .69561 1.397 2.4664 2.4663 0 0 0 3.4877 0 2.4664 2.4663 0 0 0 .31408-3.1041l3.5609-3.5608a2.4664 2.4663 0 0 0 3.1004-.3102 2.4664 2.4663 0 0 0 0-3.4875 2.4664 2.4663 0 0 0 -1.397-.6974 2.4664 2.4663 0 0 0 -.69561-1.3971 2.4664 2.4663 0 0 0 -1.7072-.7205z" fill="#cea4f1" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.478 1037.4a2.4664 2.4663 0 0 0 -1.7804.7205 2.4664 2.4663 0 0 0 -.31408 3.1041l-3.559 3.5608a2.4664 2.4663 0 0 0 -3.1023.3121 2.4664 2.4663 0 0 0 0 3.4876 2.4664 2.4663 0 0 0 1.397.6955 2.4664 2.4663 0 0 0 .69561 1.397 2.4664 2.4663 0 0 0 3.4877 0 2.4664 2.4663 0 0 0 .31408-3.1041l3.5609-3.5608a2.4664 2.4663 0 0 0 3.1004-.3102 2.4664 2.4663 0 0 0 0-3.4875 2.4664 2.4663 0 0 0 -1.397-.6974 2.4664 2.4663 0 0 0 -.69561-1.3971 2.4664 2.4663 0 0 0 -1.7072-.7205z" fill="#c38ef1" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/BoxMesh.svg b/editor/icons/BoxMesh.svg
index d540858248..6809b989cc 100644
--- a/editor/icons/BoxMesh.svg
+++ b/editor/icons/BoxMesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 .88867-7 3.5v7.2227l7 3.5 7-3.5v-7.2227zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002zm10 0v3.9395l-4 2.002v-3.9414z" fill="#ffd684" stroke-width="1.0667" transform="scale(.9375)"/></svg>
+<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 .88867-7 3.5v7.2227l7 3.5 7-3.5v-7.2227zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002zm10 0v3.9395l-4 2.002v-3.9414z" fill="#ffca5f" stroke-width="1.0667" transform="scale(.9375)"/></svg>
diff --git a/editor/icons/BusVuEmpty.svg b/editor/icons/BusVuEmpty.svg
index 32a27e26b5..cc72e7cd36 100644
--- a/editor/icons/BusVuEmpty.svg
+++ b/editor/icons/BusVuEmpty.svg
@@ -1 +1 @@
-<svg height="128" viewBox="0 0 16 128" 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="926.36" y2="1050.36"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1dc7a"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><g transform="translate(0 -924.36)"><path d="m3 926.36c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 5c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1z" fill="url(#a)"/><path d="m3 2c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 5c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1z" fill-opacity=".19608" transform="translate(0 924.36)"/></g></svg>
+<svg height="128" viewBox="0 0 16 128" 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="926.36" y2="1050.36"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><g transform="translate(0 -924.36)"><path d="m3 926.36c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 5c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1z" fill="url(#a)"/><path d="m3 2c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 5c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1z" fill-opacity=".19608" transform="translate(0 924.36)"/></g></svg>
diff --git a/editor/icons/BusVuFull.svg b/editor/icons/BusVuFull.svg
index acfa742d18..34396c3c18 100644
--- a/editor/icons/BusVuFull.svg
+++ b/editor/icons/BusVuFull.svg
@@ -1 +1 @@
-<svg height="128" viewBox="0 0 16 128" 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="2" y2="126"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1dc7a"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m3 2c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 5c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1z" fill="url(#a)"/></svg>
+<svg height="128" viewBox="0 0 16 128" 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="2" y2="126"><stop offset="0" stop-color="#ff7a7a"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#66ff9e"/></linearGradient><path d="m3 2c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 5c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1zm0 3c-.554 0-1 .446-1 1s.446 1 1 1h10c.554 0 1-.446 1-1s-.446-1-1-1z" fill="url(#a)"/></svg>
diff --git a/editor/icons/Button.svg b/editor/icons/Button.svg
index 6046038289..a856b29a02 100644
--- a/editor/icons/Button.svg
+++ b/editor/icons/Button.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v3.1328l-1.4453-.96484-1.1094 1.6641 3 2a1.0001 1.0001 0 0 0 1.1094 0l3-2-1.1094-1.6641-1.4453.96484v-3.1328zm-1.5 8c-.831 0-1.5.669-1.5 1.5v1.5h-2v2h12v-2h-2v-1.5c0-.831-.669-1.5-1.5-1.5z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v3.1328l-1.4453-.96484-1.1094 1.6641 3 2a1.0001 1.0001 0 0 0 1.1094 0l3-2-1.1094-1.6641-1.4453.96484v-3.1328zm-1.5 8c-.831 0-1.5.669-1.5 1.5v1.5h-2v2h12v-2h-2v-1.5c0-.831-.669-1.5-1.5-1.5z" fill="#8eef97"/></svg>
diff --git a/editor/icons/CPUParticles3D.svg b/editor/icons/CPUParticles3D.svg
index 072703cfa9..d7ced5fc6b 100644
--- a/editor/icons/CPUParticles3D.svg
+++ b/editor/icons/CPUParticles3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4.5587261.60940813c-.4226244 0-.7617187.3410473-.7617187.76367177v.5078126c0 .1028478.020058.199689.056641.2890624h-1.1933597c-.4226245 0-.7617188.3390944-.7617188.7617188v.921875c-.040428-.00657-.0767989-.0234375-.1191406-.0234375h-.5078125c-.42262448 0-.76367188.3410475-.76367188.7636719v.3730468c0 .4226245.3410474.7617188.76367188.7617188h.5078125c.042396 0 .078663-.016851.1191406-.023437v4.4531248c-.040428-.0066-.076799-.02344-.1191406-.02344h-.5078125c-.42262448 0-.76367188.341047-.76367188.763672v.373047c0 .422625.3410474.761718.76367188.761718h.5078125c.042396 0 .078663-.01685.1191406-.02344v1.125c0 .422624.3390944.763672.7617188.763672h1.1367187v.457031c0 .422624.3390943.763672.7617187.763672h.3730469c.4226244 0 .7636719-.341048.7636719-.763672v-.457031h4.4062501v.457031c0 .422624.339094.763672.761719.763672h.373047c.422624 0 .763671-.341048.763671-.763672v-.457031h1.269532c.422625 0 .763672-.341048.763672-.763672v-1.111328c.01774.0012.03272.0098.05078.0098h.507812c.422624 0 .763672-.339093.763672-.761718v-.373047c0-.422624-.341048-.763672-.763672-.763672h-.507812c-.01803 0-.03307.0085-.05078.0098v-4.4258454c.01774.00122.03272.00977.05078.00977h.507812c.422624 0 .763672-.3390943.763672-.7617188v-.3730512c0-.4226244-.341048-.7636719-.763672-.7636719h-.507812c-.01803 0-.03307.00855-.05078.00977v-.9082075c0-.4226244-.341047-.7617187-.763672-.7617188h-1.328125c.03658-.089375.05859-.1862118.05859-.2890624v-.5078126c0-.42262437-.341047-.76367177-.763671-.76367177h-.373047c-.422625 0-.761719.3410474-.761719.76367177v.5078126c0 .1028478.02006.1996891.05664.2890624h-4.5214809c.036585-.0893749.0585938-.1862118.0585938-.2890624v-.5078126c0-.42262437-.3410475-.76367177-.7636719-.76367177zm3.2382813 2.35742177a3.279661 3.6440678 0 0 1 3.2128906 2.9394532 2.1864407 2.1864407 0 0 1 1.888672 2.1621094 2.1864407 2.1864407 0 0 1 -2.1875 2.1855475h-5.8300782a2.1864407 2.1864407 0 0 1 -2.1855469-2.1855475 2.1864407 2.1864407 0 0 1 1.8847656-2.1640626 3.279661 3.6440678 0 0 1 3.2167969-2.9375zm-2.9160156 8.0156251a.72881355.72881355 0 0 1 .7285156.728516.72881355.72881355 0 0 1 -.7285156.730469.72881355.72881355 0 0 1 -.7285157-.730469.72881355.72881355 0 0 1 .7285157-.728516zm5.8300782 0a.72881355.72881355 0 0 1 .730469.728516.72881355.72881355 0 0 1 -.730469.730469.72881355.72881355 0 0 1 -.7285157-.730469.72881355.72881355 0 0 1 .7285157-.728516zm-2.9140626.728516a.72881355.72881355 0 0 1 .7285156.730469.72881355.72881355 0 0 1 -.7285156.728515.72881355.72881355 0 0 1 -.7285156-.728515.72881355.72881355 0 0 1 .7285156-.730469z" fill="#fc9c9c" fill-opacity=".996078"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4.5587261.60940813c-.4226244 0-.7617187.3410473-.7617187.76367177v.5078126c0 .1028478.020058.199689.056641.2890624h-1.1933597c-.4226245 0-.7617188.3390944-.7617188.7617188v.921875c-.040428-.00657-.0767989-.0234375-.1191406-.0234375h-.5078125c-.42262448 0-.76367188.3410475-.76367188.7636719v.3730468c0 .4226245.3410474.7617188.76367188.7617188h.5078125c.042396 0 .078663-.016851.1191406-.023437v4.4531248c-.040428-.0066-.076799-.02344-.1191406-.02344h-.5078125c-.42262448 0-.76367188.341047-.76367188.763672v.373047c0 .422625.3410474.761718.76367188.761718h.5078125c.042396 0 .078663-.01685.1191406-.02344v1.125c0 .422624.3390944.763672.7617188.763672h1.1367187v.457031c0 .422624.3390943.763672.7617187.763672h.3730469c.4226244 0 .7636719-.341048.7636719-.763672v-.457031h4.4062501v.457031c0 .422624.339094.763672.761719.763672h.373047c.422624 0 .763671-.341048.763671-.763672v-.457031h1.269532c.422625 0 .763672-.341048.763672-.763672v-1.111328c.01774.0012.03272.0098.05078.0098h.507812c.422624 0 .763672-.339093.763672-.761718v-.373047c0-.422624-.341048-.763672-.763672-.763672h-.507812c-.01803 0-.03307.0085-.05078.0098v-4.4258454c.01774.00122.03272.00977.05078.00977h.507812c.422624 0 .763672-.3390943.763672-.7617188v-.3730512c0-.4226244-.341048-.7636719-.763672-.7636719h-.507812c-.01803 0-.03307.00855-.05078.00977v-.9082075c0-.4226244-.341047-.7617187-.763672-.7617188h-1.328125c.03658-.089375.05859-.1862118.05859-.2890624v-.5078126c0-.42262437-.341047-.76367177-.763671-.76367177h-.373047c-.422625 0-.761719.3410474-.761719.76367177v.5078126c0 .1028478.02006.1996891.05664.2890624h-4.5214809c.036585-.0893749.0585938-.1862118.0585938-.2890624v-.5078126c0-.42262437-.3410475-.76367177-.7636719-.76367177zm3.2382813 2.35742177a3.279661 3.6440678 0 0 1 3.2128906 2.9394532 2.1864407 2.1864407 0 0 1 1.888672 2.1621094 2.1864407 2.1864407 0 0 1 -2.1875 2.1855475h-5.8300782a2.1864407 2.1864407 0 0 1 -2.1855469-2.1855475 2.1864407 2.1864407 0 0 1 1.8847656-2.1640626 3.279661 3.6440678 0 0 1 3.2167969-2.9375zm-2.9160156 8.0156251a.72881355.72881355 0 0 1 .7285156.728516.72881355.72881355 0 0 1 -.7285156.730469.72881355.72881355 0 0 1 -.7285157-.730469.72881355.72881355 0 0 1 .7285157-.728516zm5.8300782 0a.72881355.72881355 0 0 1 .730469.728516.72881355.72881355 0 0 1 -.730469.730469.72881355.72881355 0 0 1 -.7285157-.730469.72881355.72881355 0 0 1 .7285157-.728516zm-2.9140626.728516a.72881355.72881355 0 0 1 .7285156.730469.72881355.72881355 0 0 1 -.7285156.728515.72881355.72881355 0 0 1 -.7285156-.728515.72881355.72881355 0 0 1 .7285156-.730469z" fill="#fc7f7f" fill-opacity=".996078"/></svg>
diff --git a/editor/icons/Camera2D.svg b/editor/icons/Camera2D.svg
index b6aa869be3..6b0f8e603f 100644
--- a/editor/icons/Camera2D.svg
+++ b/editor/icons/Camera2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1038.4a3 3 0 0 0 -2.9883 2.7774 3 3 0 0 0 -2.0117-.7774 3 3 0 0 0 -3 3 3 3 0 0 0 2 2.8243v2.1757c0 .554.44599 1 1 1h6c.55401 0 1-.446 1-1v-1l3 2v-6l-3 2v-1.7695a3 3 0 0 0 1-2.2305 3 3 0 0 0 -3-3z" fill="#a5b7f3" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1038.4a3 3 0 0 0 -2.9883 2.7774 3 3 0 0 0 -2.0117-.7774 3 3 0 0 0 -3 3 3 3 0 0 0 2 2.8243v2.1757c0 .554.44599 1 1 1h6c.55401 0 1-.446 1-1v-1l3 2v-6l-3 2v-1.7695a3 3 0 0 0 1-2.2305 3 3 0 0 0 -3-3z" fill="#8da5f3" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/Camera3D.svg b/editor/icons/Camera3D.svg
index f6e99cb56e..a8dee93de2 100644
--- a/editor/icons/Camera3D.svg
+++ b/editor/icons/Camera3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1038.4a3 3 0 0 0 -2.9883 2.7774 3 3 0 0 0 -2.0117-.7774 3 3 0 0 0 -3 3 3 3 0 0 0 2 2.8243v2.1757c0 .554.44599 1 1 1h6c.55401 0 1-.446 1-1v-1l3 2v-6l-3 2v-1.7695a3 3 0 0 0 1-2.2305 3 3 0 0 0 -3-3z" fill="#fc9c9c" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1038.4a3 3 0 0 0 -2.9883 2.7774 3 3 0 0 0 -2.0117-.7774 3 3 0 0 0 -3 3 3 3 0 0 0 2 2.8243v2.1757c0 .554.44599 1 1 1h6c.55401 0 1-.446 1-1v-1l3 2v-6l-3 2v-1.7695a3 3 0 0 0 1-2.2305 3 3 0 0 0 -3-3z" fill="#fc7f7f" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/CameraEffects.svg b/editor/icons/CameraEffects.svg
index de1d55e1a9..1ee7e15c87 100644
--- a/editor/icons/CameraEffects.svg
+++ b/editor/icons/CameraEffects.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5.9492188 2a3 3 0 0 0 -2.9492188 3 3 3 0 0 0 1 2.2304688v1.7695312l-3-2v6l3-2v1c0 .554.44599 1 1 1h3c.0076117-.045309.0115938-.096059.0214844-.134766.0773621-.302758.1860981-.478282.2832031-.625.1397097-.211089.2814954-.338835.4257813-.480468-.1445165-.141692-.2879205-.269839-.4277344-.480469-.0971224-.146315-.2052562-.321748-.2832032-.623047-.0777157-.300405-.1044198-.8152648.1640626-1.2910156.2700589-.4775976.7340166-.7239536 1.0371093-.8105469.3037241-.0867737.5108695-.0808838.6875-.0703125.2608449.0156115.4500479.0763383.6503909.1328125.049596-.1859081.086921-.3641449.195312-.5800781.078477-.1563394.174637-.3364783.396485-.5527344.221847-.2162561.652628-.4930277 1.195312-.4980469a1.6124973 1.6124973 0 0 1 .033203 0c.542861.0056205.97185.2837448 1.19336.5.146452.1429781.230167.265896.298828.3808594a3 3 0 0 0 .128906-.8671875 3 3 0 0 0 -3-3 3 3 0 0 0 -2.0117188.7773438 3 3 0 0 0 -2.9882812-2.7773438 3 3 0 0 0 -.0507812 0z" fill="#e0e0e0"/><path d="m12.36062 8.59795a.53334 3.2001 0 0 0 -.50976 2.2754 3.2001.53334 30 0 0 -2.2656-.71484 3.2001.53334 30 0 0 1.75 1.6016.53334 3.2001 60 0 0 -1.7461 1.5996.53334 3.2001 60 0 0 2.2578-.71094.53334 3.2001 0 0 0 .51367 2.3496.53334 3.2001 0 0 0 .51367-2.3516 3.2001.53334 30 0 0 2.2539.71094 3.2001.53334 30 0 0 -1.7441-1.5977.53334 3.2001 60 0 0 1.748-1.5996.53334 3.2001 60 0 0 -2.2617.71484.53334 3.2001 0 0 0 -.50977-2.2773z" fill="#cea4f1" stroke-width="1.0667"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5.9492188 2a3 3 0 0 0 -2.9492188 3 3 3 0 0 0 1 2.2304688v1.7695312l-3-2v6l3-2v1c0 .554.44599 1 1 1h3c.0076117-.045309.0115938-.096059.0214844-.134766.0773621-.302758.1860981-.478282.2832031-.625.1397097-.211089.2814954-.338835.4257813-.480468-.1445165-.141692-.2879205-.269839-.4277344-.480469-.0971224-.146315-.2052562-.321748-.2832032-.623047-.0777157-.300405-.1044198-.8152648.1640626-1.2910156.2700589-.4775976.7340166-.7239536 1.0371093-.8105469.3037241-.0867737.5108695-.0808838.6875-.0703125.2608449.0156115.4500479.0763383.6503909.1328125.049596-.1859081.086921-.3641449.195312-.5800781.078477-.1563394.174637-.3364783.396485-.5527344.221847-.2162561.652628-.4930277 1.195312-.4980469a1.6124973 1.6124973 0 0 1 .033203 0c.542861.0056205.97185.2837448 1.19336.5.146452.1429781.230167.265896.298828.3808594a3 3 0 0 0 .128906-.8671875 3 3 0 0 0 -3-3 3 3 0 0 0 -2.0117188.7773438 3 3 0 0 0 -2.9882812-2.7773438 3 3 0 0 0 -.0507812 0z" fill="#e0e0e0"/><path d="m12.36062 8.59795a.53334 3.2001 0 0 0 -.50976 2.2754 3.2001.53334 30 0 0 -2.2656-.71484 3.2001.53334 30 0 0 1.75 1.6016.53334 3.2001 60 0 0 -1.7461 1.5996.53334 3.2001 60 0 0 2.2578-.71094.53334 3.2001 0 0 0 .51367 2.3496.53334 3.2001 0 0 0 .51367-2.3516 3.2001.53334 30 0 0 2.2539.71094 3.2001.53334 30 0 0 -1.7441-1.5977.53334 3.2001 60 0 0 1.748-1.5996.53334 3.2001 60 0 0 -2.2617.71484.53334 3.2001 0 0 0 -.50977-2.2773z" fill="#c38ef1" stroke-width="1.0667"/></svg>
diff --git a/editor/icons/CanvasItemMaterial.svg b/editor/icons/CanvasItemMaterial.svg
index 241184f8b9..9a7a89431c 100644
--- a/editor/icons/CanvasItemMaterial.svg
+++ b/editor/icons/CanvasItemMaterial.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.1035 3a7 7 0 0 0 -1.418 2h12.631a7 7 0 0 0 -1.4277-2h-9.7852z" fill="#ffeb70"/><path d="m1.6855 5a7 7 0 0 0 -.60547 2h13.842a7 7 0 0 0 -.60547-2h-12.631z" fill="#9dff70"/><path d="m1.0801 7a7 7 0 0 0 -.080078 1 7 7 0 0 0 .078125 1h13.842a7 7 0 0 0 .080078-1 7 7 0 0 0 -.078125-1z" fill="#70ffb9"/><path d="m1.0781 9a7 7 0 0 0 .60547 2h12.631a7 7 0 0 0 .60547-2h-13.842z" fill="#70deff"/><path d="m3.1113 13a7 7 0 0 0 4.8887 2 7 7 0 0 0 4.8965-2z" fill="#ff70ac"/><path d="m1.6836 11a7 7 0 0 0 1.4277 2h9.7852a7 7 0 0 0 1.418-2h-12.631z" fill="#9f70ff"/><path d="m8 1a7 7 0 0 0 -4.8965 2h9.7852a7 7 0 0 0 -4.8887-2z" fill="#ff7070"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.1035 3a7 7 0 0 0 -1.418 2h12.631a7 7 0 0 0 -1.4277-2h-9.7852z" fill="#ffe345"/><path d="m1.6855 5a7 7 0 0 0 -.60547 2h13.842a7 7 0 0 0 -.60547-2h-12.631z" fill="#80ff45"/><path d="m1.0801 7a7 7 0 0 0 -.080078 1 7 7 0 0 0 .078125 1h13.842a7 7 0 0 0 .080078-1 7 7 0 0 0 -.078125-1z" fill="#45ffa2"/><path d="m1.0781 9a7 7 0 0 0 .60547 2h12.631a7 7 0 0 0 .60547-2h-13.842z" fill="#45d7ff"/><path d="m3.1113 13a7 7 0 0 0 4.8887 2 7 7 0 0 0 4.8965-2z" fill="#ff4596"/><path d="m1.6836 11a7 7 0 0 0 1.4277 2h9.7852a7 7 0 0 0 1.418-2h-12.631z" fill="#8045ff"/><path d="m8 1a7 7 0 0 0 -4.8965 2h9.7852a7 7 0 0 0 -4.8887-2z" fill="#ff4545"/></svg>
diff --git a/editor/icons/CanvasItemShader.svg b/editor/icons/CanvasItemShader.svg
index b8b1588843..9aeb2f0fdc 100644
--- a/editor/icons/CanvasItemShader.svg
+++ b/editor/icons/CanvasItemShader.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13.303 1c-.4344 0-.86973.16881-1.2012.50586l-1.4688 1.4941h4.3418c.082839-.52789-.072596-1.0872-.47266-1.4941-.33144-.33705-.76482-.50586-1.1992-.50586z" fill="#ff7070"/><path d="m10.633 3-1.9668 2h4.8008l1.0352-1.0527c.2628-.2673.41824-.60049.47266-.94727h-4.3418z" fill="#ffeb70"/><path d="m8.666 5-1.9648 2h4.7988l1.9668-2z" fill="#9dff70"/><path d="m6.7012 7-1.4004 1.4238.56641.57617h3.668l1.9648-2h-4.7988z" fill="#70ffb9"/><path d="m5.8672 9 1.834 1.8652 1.834-1.8652zm-1.752.57812c-.48501-.048725-.90521.12503-1.1953.45508-.21472.24426-.35243.57797-.39844.9668h3.5625c-.10223-.1935-.22224-.37965-.38281-.54297-.55011-.55955-1.1009-.83018-1.5859-.87891z" fill="#70deff"/><path d="m1.3242 13c.18414.24071.43707.53374.83789.94141.88382.899 2.6552.67038 3.5391-.22852.20747-.21103.36064-.45476.4707-.71289h-4.8477z" fill="#ff70ac"/><path d="m2.5215 11c-.0105.088737-.021484.17696-.021484.27148 0 1.3947-2.2782.28739-1.1758 1.7285h4.8477c.27363-.64173.24047-1.3785-.087891-2h-3.5625z" fill="#9f70ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13.303 1c-.4344 0-.86973.16881-1.2012.50586l-1.4688 1.4941h4.3418c.082839-.52789-.072596-1.0872-.47266-1.4941-.33144-.33705-.76482-.50586-1.1992-.50586z" fill="#ff4545"/><path d="m10.633 3-1.9668 2h4.8008l1.0352-1.0527c.2628-.2673.41824-.60049.47266-.94727h-4.3418z" fill="#ffe345"/><path d="m8.666 5-1.9648 2h4.7988l1.9668-2z" fill="#80ff45"/><path d="m6.7012 7-1.4004 1.4238.56641.57617h3.668l1.9648-2h-4.7988z" fill="#45ffa2"/><path d="m5.8672 9 1.834 1.8652 1.834-1.8652zm-1.752.57812c-.48501-.048725-.90521.12503-1.1953.45508-.21472.24426-.35243.57797-.39844.9668h3.5625c-.10223-.1935-.22224-.37965-.38281-.54297-.55011-.55955-1.1009-.83018-1.5859-.87891z" fill="#45d7ff"/><path d="m1.3242 13c.18414.24071.43707.53374.83789.94141.88382.899 2.6552.67038 3.5391-.22852.20747-.21103.36064-.45476.4707-.71289h-4.8477z" fill="#ff4596"/><path d="m2.5215 11c-.0105.088737-.021484.17696-.021484.27148 0 1.3947-2.2782.28739-1.1758 1.7285h4.8477c.27363-.64173.24047-1.3785-.087891-2h-3.5625z" fill="#8045ff"/></svg>
diff --git a/editor/icons/CanvasItemShaderGraph.svg b/editor/icons/CanvasItemShaderGraph.svg
index 838ca45178..70db53a4ba 100644
--- a/editor/icons/CanvasItemShaderGraph.svg
+++ b/editor/icons/CanvasItemShaderGraph.svg
@@ -1 +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"><clipPath id="a"><path d="m8.0625 1025.9a3.375 3 0 0 0 -3.375 3 3.375 3 0 0 0 1.6875 2.5957v9.8115a3.375 3 0 0 0 -1.6875 2.5928 3.375 3 0 0 0 3.375 3 3.375 3 0 0 0 3.375-3 3.375 3 0 0 0 -1.6875-2.5957v-8.7832l11.931 10.605a3.375 3 0 0 0 -.11865.7735 3.375 3 0 0 0 3.375 3 3.375 3 0 0 0 3.375-3 3.375 3 0 0 0 -3.375-3 3.375 3 0 0 0 -.87341.1025l-11.928-10.602h9.8844a3.375 3 0 0 0 2.9169 1.5 3.375 3 0 0 0 3.375-3 3.375 3 0 0 0 -3.375-3 3.375 3 0 0 0 -2.9202 1.5h-11.038a3.375 3 0 0 0 -2.9169-1.5z"/></clipPath><g transform="translate(0 -1036.4)"><g clip-path="url(#a)" transform="matrix(.59259 0 0 .66667 -1.7778 353.45)"><path d="m3 1025.9h27v3h-27z" fill="#ff7070"/><path d="m3 1028.9h27v3h-27z" fill="#ffeb70"/><path d="m3 1031.9h27v3h-27z" fill="#9dff70"/><path d="m3 1034.9h27v3h-27z" fill="#70ffb9"/><path d="m3 1037.9h27v3h-27z" fill="#70deff"/><path d="m3 1043.9h27v3h-27z" fill="#ff70ac"/><path d="m3 1040.9h27v3h-27z" fill="#9f70ff"/></g><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/></g></svg>
+<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"><clipPath id="a"><path d="m8.0625 1025.9a3.375 3 0 0 0 -3.375 3 3.375 3 0 0 0 1.6875 2.5957v9.8115a3.375 3 0 0 0 -1.6875 2.5928 3.375 3 0 0 0 3.375 3 3.375 3 0 0 0 3.375-3 3.375 3 0 0 0 -1.6875-2.5957v-8.7832l11.931 10.605a3.375 3 0 0 0 -.11865.7735 3.375 3 0 0 0 3.375 3 3.375 3 0 0 0 3.375-3 3.375 3 0 0 0 -3.375-3 3.375 3 0 0 0 -.87341.1025l-11.928-10.602h9.8844a3.375 3 0 0 0 2.9169 1.5 3.375 3 0 0 0 3.375-3 3.375 3 0 0 0 -3.375-3 3.375 3 0 0 0 -2.9202 1.5h-11.038a3.375 3 0 0 0 -2.9169-1.5z"/></clipPath><g transform="translate(0 -1036.4)"><g clip-path="url(#a)" transform="matrix(.59259 0 0 .66667 -1.7778 353.45)"><path d="m3 1025.9h27v3h-27z" fill="#ff4545"/><path d="m3 1028.9h27v3h-27z" fill="#ffe345"/><path d="m3 1031.9h27v3h-27z" fill="#80ff45"/><path d="m3 1034.9h27v3h-27z" fill="#45ffa2"/><path d="m3 1037.9h27v3h-27z" fill="#45d7ff"/><path d="m3 1043.9h27v3h-27z" fill="#ff4596"/><path d="m3 1040.9h27v3h-27z" fill="#8045ff"/></g><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/></g></svg>
diff --git a/editor/icons/CanvasModulate.svg b/editor/icons/CanvasModulate.svg
index 6096beb732..a96fb75643 100644
--- a/editor/icons/CanvasModulate.svg
+++ b/editor/icons/CanvasModulate.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m1 1037.4v14h14v-14zm2 2h10v10h-10z" fill="#a5b7f3"/><g fill-rule="evenodd"><path d="m12 1048.4h-5l5-5z" fill="#70bfff"/><path d="m4 1040.4h5l-5 5z" fill="#ff7070"/><path d="m4 1048.4v-3l5-5h3v3l-5 5z" fill="#7aff70"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m1 1037.4v14h14v-14zm2 2h10v10h-10z" fill="#8da5f3"/><g fill-rule="evenodd"><path d="m12 1048.4h-5l5-5z" fill="#70bfff"/><path d="m4 1040.4h5l-5 5z" fill="#ff4545"/><path d="m4 1048.4v-3l5-5h3v3l-5 5z" fill="#7aff70"/></g></g></svg>
diff --git a/editor/icons/CapsuleMesh.svg b/editor/icons/CapsuleMesh.svg
index f7424310aa..0bc7814bea 100644
--- a/editor/icons/CapsuleMesh.svg
+++ b/editor/icons/CapsuleMesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.7527 0-5 2.2419-5 4.9903v4.0175c0 2.7484 2.2473 4.9922 5 4.9922s5-2.2438 5-4.9922v-4.0175c0-2.7484-2.2473-4.9903-5-4.9903zm-1.0059 2.1264v4.8576c-.66556-.1047-1.2973-.372-1.9941-.6618v-1.3222c0-1.3474.79838-2.4648 1.9941-2.8736zm2.0118 0c1.1957.4088 1.9941 1.5262 1.9941 2.8736v1.3451c-.68406.3054-1.3142.5732-1.9941.6663zm-4.0059 6.334c.67836.2231 1.3126.447 1.9941.5264v2.8848c-1.1957-.4092-1.9941-1.5242-1.9941-2.8716zm6 .03v.5094c0 1.3474-.79838 2.4619-1.9941 2.8711v-2.8711c.68606-.068 1.3207-.2828 1.9941-.5094z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.7527 0-5 2.2419-5 4.9903v4.0175c0 2.7484 2.2473 4.9922 5 4.9922s5-2.2438 5-4.9922v-4.0175c0-2.7484-2.2473-4.9903-5-4.9903zm-1.0059 2.1264v4.8576c-.66556-.1047-1.2973-.372-1.9941-.6618v-1.3222c0-1.3474.79838-2.4648 1.9941-2.8736zm2.0118 0c1.1957.4088 1.9941 1.5262 1.9941 2.8736v1.3451c-.68406.3054-1.3142.5732-1.9941.6663zm-4.0059 6.334c.67836.2231 1.3126.447 1.9941.5264v2.8848c-1.1957-.4092-1.9941-1.5242-1.9941-2.8716zm6 .03v.5094c0 1.3474-.79838 2.4619-1.9941 2.8711v-2.8711c.68606-.068 1.3207-.2828 1.9941-.5094z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/CenterContainer.svg b/editor/icons/CenterContainer.svg
index af1958c2d8..990f63b6c2 100644
--- a/editor/icons/CenterContainer.svg
+++ b/editor/icons/CenterContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm3 1 2 2 2-2zm-2 2v4l2-2zm8 0-2 2 2 2zm-4 4-2 2h4z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm3 1 2 2 2-2zm-2 2v4l2-2zm8 0-2 2 2 2zm-4 4-2 2h4z" fill="#8eef97"/></svg>
diff --git a/editor/icons/KinematicBody2D.svg b/editor/icons/CharacterBody2D.svg
index 70faad6a49..b71fda9650 100644
--- a/editor/icons/KinematicBody2D.svg
+++ b/editor/icons/CharacterBody2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6.4921 1c-.55401 0-1 .446-1 1v3c0 .554.44599 1 1 1h1v.9902a1.0001 1.0001 0 0 0 -.31641.062l-2.0508.6836-.68359-2.0508a1.0001 1.0001 0 0 0 -.99023-.6972 1.0001 1.0001 0 0 0 -.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656.6328l1.6836-.5605v.6113c0 .041.018715.076.023437.1152l-4.5781 3.0528a1.0001 1.0001 0 1 0 1.1094 1.664l5.0566-3.3711 1.4941 2.9864a1.0001 1.0001 0 0 0 1.2109.5019l3-1a1.0001 1.0001 0 1 0 -.63281-1.8965l-2.1777.7246-.97461-1.9511c.2759-.1777.46875-.4723.46875-.8262v-1h1.3828l.72266 1.4473a1.0001 1.0001 0 1 0 1.7891-.8946l-1-2a1.0001 1.0001 0 0 0 -.89453-.5527h-3v-1h1c.55401 0 1-.446 1-1v-3c0-.554-.44599-1-1-1zm0 2h1v2h-1z" fill="#a5b7f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6.4921 1c-.55401 0-1 .446-1 1v3c0 .554.44599 1 1 1h1v.9902a1.0001 1.0001 0 0 0 -.31641.062l-2.0508.6836-.68359-2.0508a1.0001 1.0001 0 0 0 -.99023-.6972 1.0001 1.0001 0 0 0 -.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656.6328l1.6836-.5605v.6113c0 .041.018715.076.023437.1152l-4.5781 3.0528a1.0001 1.0001 0 1 0 1.1094 1.664l5.0566-3.3711 1.4941 2.9864a1.0001 1.0001 0 0 0 1.2109.5019l3-1a1.0001 1.0001 0 1 0 -.63281-1.8965l-2.1777.7246-.97461-1.9511c.2759-.1777.46875-.4723.46875-.8262v-1h1.3828l.72266 1.4473a1.0001 1.0001 0 1 0 1.7891-.8946l-1-2a1.0001 1.0001 0 0 0 -.89453-.5527h-3v-1h1c.55401 0 1-.446 1-1v-3c0-.554-.44599-1-1-1zm0 2h1v2h-1z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/KinematicBody3D.svg b/editor/icons/CharacterBody3D.svg
index 06e9275ec1..d0def4f14a 100644
--- a/editor/icons/KinematicBody3D.svg
+++ b/editor/icons/CharacterBody3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1c-.55401 0-1 .44599-1 1v3c0 .55401.44599 1 1 1h1v.99023a1.0001 1.0001 0 0 0 -.31641.0625l-2.0508.68359-.68359-2.0508a1.0001 1.0001 0 0 0 -.99023-.69727 1.0001 1.0001 0 0 0 -.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656.63281l1.6836-.56055v.61133c0 .04088.018715.07566.023437.11523l-4.5781 3.0527a1.0001 1.0001 0 1 0 1.1094 1.6641l5.0566-3.3711 1.4941 2.9863a1.0001 1.0001 0 0 0 1.2109.50195l3-1a1.0001 1.0001 0 1 0 -.63281-1.8965l-2.1777.72461-.97461-1.9512c.2759-.17764.46875-.47227.46875-.82617v-1h1.3828l.72266 1.4473a1.0001 1.0001 0 1 0 1.7891-.89453l-1-2a1.0001 1.0001 0 0 0 -.89453-.55273h-3v-1h1c.55401 0 1-.44599 1-1v-3c0-.55401-.44599-1-1-1zm0 2h1v2h-1z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1c-.55401 0-1 .44599-1 1v3c0 .55401.44599 1 1 1h1v.99023a1.0001 1.0001 0 0 0 -.31641.0625l-2.0508.68359-.68359-2.0508a1.0001 1.0001 0 0 0 -.99023-.69727 1.0001 1.0001 0 0 0 -.9082 1.3281l1 3a1.0001 1.0001 0 0 0 1.2656.63281l1.6836-.56055v.61133c0 .04088.018715.07566.023437.11523l-4.5781 3.0527a1.0001 1.0001 0 1 0 1.1094 1.6641l5.0566-3.3711 1.4941 2.9863a1.0001 1.0001 0 0 0 1.2109.50195l3-1a1.0001 1.0001 0 1 0 -.63281-1.8965l-2.1777.72461-.97461-1.9512c.2759-.17764.46875-.47227.46875-.82617v-1h1.3828l.72266 1.4473a1.0001 1.0001 0 1 0 1.7891-.89453l-1-2a1.0001 1.0001 0 0 0 -.89453-.55273h-3v-1h1c.55401 0 1-.44599 1-1v-3c0-.55401-.44599-1-1-1zm0 2h1v2h-1z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/CheckBox.svg b/editor/icons/CheckBox.svg
index 8707dfce0c..32eaf2d212 100644
--- a/editor/icons/CheckBox.svg
+++ b/editor/icons/CheckBox.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-1.1046 0-2 .89543-2 2v9c0 1.1046.89543 2 2 2h9c1.1046 0 2-.89543 2-2v-4.9277l-2 2v2.9277h-9v-9h6.5859l2-2zm9.3633 2.0508-4.9492 4.9492-1.4141-1.4141-1.4141 1.4141 2.8281 2.8281 6.3633-6.3633z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-1.1046 0-2 .89543-2 2v9c0 1.1046.89543 2 2 2h9c1.1046 0 2-.89543 2-2v-4.9277l-2 2v2.9277h-9v-9h6.5859l2-2zm9.3633 2.0508-4.9492 4.9492-1.4141-1.4141-1.4141 1.4141 2.8281 2.8281 6.3633-6.3633z" fill="#8eef97"/></svg>
diff --git a/editor/icons/CheckButton.svg b/editor/icons/CheckButton.svg
index 4b8106ecc0..91367e2a2a 100644
--- a/editor/icons/CheckButton.svg
+++ b/editor/icons/CheckButton.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 4a4 4 0 0 0 -4 4 4 4 0 0 0 4 4h6a4 4 0 0 0 4-4 4 4 0 0 0 -4-4zm0 2h2.541a4 4 0 0 0 -.54102 2 4 4 0 0 0 .54102 2h-2.541a2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 4a4 4 0 0 0 -4 4 4 4 0 0 0 4 4h6a4 4 0 0 0 4-4 4 4 0 0 0 -4-4zm0 2h2.541a4 4 0 0 0 -.54102 2 4 4 0 0 0 .54102 2h-2.541a2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/ClippedCamera3D.svg b/editor/icons/ClippedCamera3D.svg
index a66f7844a9..44d656e8ba 100644
--- a/editor/icons/ClippedCamera3D.svg
+++ b/editor/icons/ClippedCamera3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6.5 12v4h3v-1h-2v-3zm-1 0h-2c-.5 0-1 .5-1 1v2c-.01829.53653.5 1 1 1h2v-1h-2v-2h2zm4-12c-1.5691.0017903-2.8718 1.2125-2.9883 2.7773-.55103-.49952-1.268-.77655-2.0117-.77734-1.6569 0-3 1.3431-3 3 .00179 1.2698.80282 2.4009 2 2.8242v2.1758c0 .554.44599 1 1 1h6c.55401 0 1-.446 1-1v-1l3 2v-6l-3 2v-1.7695c.63486-.56783.99842-1.3788 1-2.2305 0-1.6569-1.3431-3-3-3zm1 12v4h1v-1h1c.55228 0 1-.44772 1-1v-1c0-.55228-.44775-.99374-1-1h-1zm1 1h1v1h-1z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6.5 12v4h3v-1h-2v-3zm-1 0h-2c-.5 0-1 .5-1 1v2c-.01829.53653.5 1 1 1h2v-1h-2v-2h2zm4-12c-1.5691.0017903-2.8718 1.2125-2.9883 2.7773-.55103-.49952-1.268-.77655-2.0117-.77734-1.6569 0-3 1.3431-3 3 .00179 1.2698.80282 2.4009 2 2.8242v2.1758c0 .554.44599 1 1 1h6c.55401 0 1-.446 1-1v-1l3 2v-6l-3 2v-1.7695c.63486-.56783.99842-1.3788 1-2.2305 0-1.6569-1.3431-3-3-3zm1 12v4h1v-1h1c.55228 0 1-.44772 1-1v-1c0-.55228-.44775-.99374-1-1h-1zm1 1h1v1h-1z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/CodeEdit.svg b/editor/icons/CodeEdit.svg
index 0750b072e7..7f08340ffb 100644
--- a/editor/icons/CodeEdit.svg
+++ b/editor/icons/CodeEdit.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m29 1042.4h1v1h-1z" fill="#fefeff"/><path d="m3 1c-1.1046 0-2 .8954-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm2 1-1 1 1 1-1 1 1 1 2-2zm2 3v1h2v-1z" fill="#a5efac" transform="translate(0 1036.4)"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m29 1042.4h1v1h-1z" fill="#fefeff"/><path d="m3 1c-1.1046 0-2 .8954-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm2 1-1 1 1 1-1 1 1 1 2-2zm2 3v1h2v-1z" fill="#8eef97" transform="translate(0 1036.4)"/></g></svg>
diff --git a/editor/icons/CollapseTree.svg b/editor/icons/CollapseTree.svg
new file mode 100644
index 0000000000..ece9071e03
--- /dev/null
+++ b/editor/icons/CollapseTree.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-rule="nonzero"><path d="m8 9.669-3.536 2.583h2.536v2.537h2v-2.537h2.536z"/><path d="m8 6.355-3.536-2.583h2.536v-2.537h2v2.537h2.536z"/><path d="m.704 7.085h14.591v1.831h-14.591z"/></g></svg>
diff --git a/editor/icons/CollisionPolygon2D.svg b/editor/icons/CollisionPolygon2D.svg
index 524efd1e65..a882943847 100644
--- a/editor/icons/CollisionPolygon2D.svg
+++ b/editor/icons/CollisionPolygon2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1050.4h-12v-12h12l-6 6z" fill="none" stroke="#a5b7f3" stroke-linejoin="round" stroke-opacity=".98824" stroke-width="2" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1050.4h-12v-12h12l-6 6z" fill="none" stroke="#8da5f3" stroke-linejoin="round" stroke-opacity=".98824" stroke-width="2" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/CollisionPolygon3D.svg b/editor/icons/CollisionPolygon3D.svg
index 9b8b13c514..57531fa9f4 100644
--- a/editor/icons/CollisionPolygon3D.svg
+++ b/editor/icons/CollisionPolygon3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1050.4h-12v-12h12l-6 6z" fill="none" stroke="#fc9c9c" stroke-linejoin="round" stroke-opacity=".99608" stroke-width="2" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1050.4h-12v-12h12l-6 6z" fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-opacity=".99608" stroke-width="2" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/CollisionShape2D.svg b/editor/icons/CollisionShape2D.svg
index d366ddb630..0acad74379 100644
--- a/editor/icons/CollisionShape2D.svg
+++ b/editor/icons/CollisionShape2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1050.4h-12v-12h12z" fill="none" stroke="#a5b7f3" stroke-linejoin="round" stroke-opacity=".98824" stroke-width="2" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1050.4h-12v-12h12z" fill="none" stroke="#8da5f3" stroke-linejoin="round" stroke-opacity=".98824" stroke-width="2" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/CollisionShape3D.svg b/editor/icons/CollisionShape3D.svg
index cf5925ce79..7a8bbf8050 100644
--- a/editor/icons/CollisionShape3D.svg
+++ b/editor/icons/CollisionShape3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1050.4-6-3v-6l6-3 6 3v6z" fill="none" stroke="#fc9c9c" stroke-linejoin="round" stroke-opacity=".99608" stroke-width="2" transform="translate(0 -1036.399988)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1050.4-6-3v-6l6-3 6 3v6z" fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-opacity=".99608" stroke-width="2" transform="translate(0 -1036.399988)"/></svg>
diff --git a/editor/icons/Color.svg b/editor/icons/Color.svg
index 91bc0d1d2d..5c6fca1876 100644
--- a/editor/icons/Color.svg
+++ b/editor/icons/Color.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2z" fill="#ff8484"/><path d="m14 4a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2z" fill="#84c2ff"/><path d="m6 2v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-5z" fill="#84ffb1"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2z" fill="#ff5f5f"/><path d="m14 4a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2z" fill="#5fb2ff"/><path d="m6 2v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-5z" fill="#5fff97"/></svg>
diff --git a/editor/icons/ColorPicker.svg b/editor/icons/ColorPicker.svg
index c4f48cd347..ce1f4fef96 100644
--- a/editor/icons/ColorPicker.svg
+++ b/editor/icons/ColorPicker.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-1.108 0-2 .892-2 2v2h-1v2h1v5a2 2 0 0 0 1 1.7285v1.2715h2v-1.2695a2 2 0 0 0 1-1.7305v-5h1v-2h-1v-2c0-1.108-.892-2-2-2zm-1 6h2v5a1 1 0 0 1 -1 1 1 1 0 0 1 -1-1z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-1.108 0-2 .892-2 2v2h-1v2h1v5a2 2 0 0 0 1 1.7285v1.2715h2v-1.2695a2 2 0 0 0 1-1.7305v-5h1v-2h-1v-2c0-1.108-.892-2-2-2zm-1 6h2v5a1 1 0 0 1 -1 1 1 1 0 0 1 -1-1z" fill="#8eef97"/></svg>
diff --git a/editor/icons/ColorPickerButton.svg b/editor/icons/ColorPickerButton.svg
index fa2a615428..ced130b1ce 100644
--- a/editor/icons/ColorPickerButton.svg
+++ b/editor/icons/ColorPickerButton.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 1c-1.108 0-2 .892-2 2v2h-1v2h1v5a2 2 0 0 0 1 1.7285v1.2715h2v-1.2695a2 2 0 0 0 1-1.7305v-5h1v-2h-1v-2c0-1.108-.892-2-2-2zm-9 1v3.1328l-1.4453-.96484-1.1094 1.6641 3 2c.3359.2239.77347.2239 1.1094 0l3-2-1.1094-1.6641-1.4453.96484v-3.1328zm8 5h2v5a1 1 0 0 1 -1 1 1 1 0 0 1 -1-1zm-8.5 3c-.831 0-1.5.669-1.5 1.5v.5 1h-1v2h8v-2h-1v-1-.5c0-.831-.669-1.5-1.5-1.5z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 1c-1.108 0-2 .892-2 2v2h-1v2h1v5a2 2 0 0 0 1 1.7285v1.2715h2v-1.2695a2 2 0 0 0 1-1.7305v-5h1v-2h-1v-2c0-1.108-.892-2-2-2zm-9 1v3.1328l-1.4453-.96484-1.1094 1.6641 3 2c.3359.2239.77347.2239 1.1094 0l3-2-1.1094-1.6641-1.4453.96484v-3.1328zm8 5h2v5a1 1 0 0 1 -1 1 1 1 0 0 1 -1-1zm-8.5 3c-.831 0-1.5.669-1.5 1.5v.5 1h-1v2h8v-2h-1v-1-.5c0-.831-.669-1.5-1.5-1.5z" fill="#8eef97"/></svg>
diff --git a/editor/icons/ColorRect.svg b/editor/icons/ColorRect.svg
index 306401191a..f08b17ed1f 100644
--- a/editor/icons/ColorRect.svg
+++ b/editor/icons/ColorRect.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m1 1v14h14v-14zm2 2h10v10h-10z" fill="#a5efac" transform="translate(0 1036.4)"/><g fill-rule="evenodd"><path d="m12 1048.4h-4.8l4.8-4.8z" fill="#70bfff"/><path d="m4 1040.4h4.8l-4.8 4.8z" fill="#ff7070"/><path d="m4 1048.4v-3.2l4.8-4.8h3.2v3.2l-4.8 4.8z" fill="#7aff70"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m1 1v14h14v-14zm2 2h10v10h-10z" fill="#8eef97" transform="translate(0 1036.4)"/><g fill-rule="evenodd"><path d="m12 1048.4h-4.8l4.8-4.8z" fill="#70bfff"/><path d="m4 1040.4h4.8l-4.8 4.8z" fill="#ff4545"/><path d="m4 1048.4v-3.2l4.8-4.8h3.2v3.2l-4.8 4.8z" fill="#7aff70"/></g></g></svg>
diff --git a/editor/icons/CombineLines.svg b/editor/icons/CombineLines.svg
new file mode 100644
index 0000000000..124814ae88
--- /dev/null
+++ b/editor/icons/CombineLines.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M1 2v2h14V2zm7 5v2h7V7zm0 5v2h7v-2zM4.976 14V9h2l-1.5-2-1.5-2-1.5 2-1.5 2h2v5z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/ConeTwistJoint3D.svg b/editor/icons/ConeTwistJoint3D.svg
index 9eff38d0dc..300cc7ecc1 100644
--- a/editor/icons/ConeTwistJoint3D.svg
+++ b/editor/icons/ConeTwistJoint3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9824 1a1.0001 1.0001 0 0 0 -.81445.44531l-4.7012 7.0527c-.80117.58197-1.3801 1.3563-1.4492 2.3145a1.0001 1.0001 0 0 0 -.017578.1875c0 .21449.033976.41628.082031.61328.0071983.028314.015306.055972.023438.083985.053631.19149.1274.37452.2207.54883.19678.36764.47105.69651.80273.98633.007988.007025.013442.016473.021484.023437.016953.014679.03747.026532.054688.041016.10299.086112.21259.16531.32422.24414.23883.16992.49083.33075.76953.4707.0025295.00127.0052799.002638.0078125.003906.001313.000658.0025928.001296.0039063.001953.0085785.00429.018732.007456.027344.011719.26499.13103.55174.24596.84961.35156.10487.037634.21202.071147.32031.10547.072945.022902.1402.050715.21484.072266.16777.04843.34161.086385.51367.12695.093562.021905.18185.048745.27734.068359.010733.002205.022447.003684.033203.00586.34623.071177.69974.12196 1.0566.16211.057889.006228.11544.01213.17383.017578.81052.079498 1.6348.079498 2.4453 0 .058387-.005448.11594-.01135.17383-.017578.3569-.040146.71041-.090932 1.0566-.16211.010948-.002251.022269-.003578.033203-.00586.095491-.019614.18378-.046454.27734-.068359.17206-.040568.3459-.078523.51367-.12695.074642-.021551.1419-.049364.21484-.072266.10829-.034322.21544-.067835.32031-.10547.29787-.1056.58462-.22053.84961-.35156.009951-.00492.021348-.008715.03125-.013672.002626-.001315.005189-.002588.007813-.003906.2787-.13995.5307-.30078.76953-.4707.11163-.07883.22123-.15803.32422-.24414.017218-.014484.037734-.026337.054687-.041016.008042-.006964.013497-.016412.021485-.023437.33169-.28982.60596-.61869.80273-.98633.093299-.17431.16707-.35733.2207-.54883.008132-.028013.016239-.055671.023438-.083985.048055-.197.082031-.39879.082031-.61328a1.0001 1.0001 0 0 0 -.017578-.18164 1.0001 1.0001 0 0 0 -.001953-.017578c-.073081-.95265-.64941-1.7232-1.4473-2.3027l-4.7012-7.0527a1.0001 1.0001 0 0 0 -.84961-.44531zm-.98242 4.3027v1.7461c-.43911.033461-.86366.087835-1.2734.16406l1.2734-1.9102zm2 0 1.2734 1.9102c-.40978-.076228-.83432-.1306-1.2734-.16406v-1.7461zm-2 3.748v1.9492a1.0001 1.0001 0 1 0 2 0v-1.9492c1.1126.10487 2.0951.37277 2.7949.72266.12146.060728.20622.12218.30664.18359l.80078 1.2012c-.032965.14677-.089654.30658-.30469.51758-.051464.049149-.10034.098137-.16406.14844-.045193.035312-.091373.070148-.14258.10547-.11245.07827-.24511.15838-.39062.23633-.075428.040204-.1553.078371-.23828.11719-.16195.075482-.33452.14662-.52148.21289-.070588.025324-.14454.048409-.21875.072265-.23425.074473-.48077.14392-.74414.20117-.021343.004579-.041038.011189-.0625.015625-.2559.05368-.53101.090517-.80859.125-.856.10229-1.7573.10229-2.6133 0-.27759-.034483-.5527-.07132-.80859-.125-.021462-.004436-.041156-.011046-.0625-.015625-.26337-.057254-.50989-.1267-.74414-.20117-.074211-.023856-.14816-.046941-.21875-.072265-.18697-.066266-.35954-.13741-.52148-.21289-.082979-.038816-.16285-.076983-.23828-.11719-.14552-.077951-.27818-.15806-.39062-.23633-.051205-.035321-.097386-.070157-.14258-.10547-.06372-.050301-.1126-.099289-.16406-.14844-.21503-.21099-.27173-.37081-.30469-.51758l.80078-1.2012c.10043-.061415.18518-.12287.30664-.18359.69978-.34989 1.6823-.61778 2.7949-.72266z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9824 1a1.0001 1.0001 0 0 0 -.81445.44531l-4.7012 7.0527c-.80117.58197-1.3801 1.3563-1.4492 2.3145a1.0001 1.0001 0 0 0 -.017578.1875c0 .21449.033976.41628.082031.61328.0071983.028314.015306.055972.023438.083985.053631.19149.1274.37452.2207.54883.19678.36764.47105.69651.80273.98633.007988.007025.013442.016473.021484.023437.016953.014679.03747.026532.054688.041016.10299.086112.21259.16531.32422.24414.23883.16992.49083.33075.76953.4707.0025295.00127.0052799.002638.0078125.003906.001313.000658.0025928.001296.0039063.001953.0085785.00429.018732.007456.027344.011719.26499.13103.55174.24596.84961.35156.10487.037634.21202.071147.32031.10547.072945.022902.1402.050715.21484.072266.16777.04843.34161.086385.51367.12695.093562.021905.18185.048745.27734.068359.010733.002205.022447.003684.033203.00586.34623.071177.69974.12196 1.0566.16211.057889.006228.11544.01213.17383.017578.81052.079498 1.6348.079498 2.4453 0 .058387-.005448.11594-.01135.17383-.017578.3569-.040146.71041-.090932 1.0566-.16211.010948-.002251.022269-.003578.033203-.00586.095491-.019614.18378-.046454.27734-.068359.17206-.040568.3459-.078523.51367-.12695.074642-.021551.1419-.049364.21484-.072266.10829-.034322.21544-.067835.32031-.10547.29787-.1056.58462-.22053.84961-.35156.009951-.00492.021348-.008715.03125-.013672.002626-.001315.005189-.002588.007813-.003906.2787-.13995.5307-.30078.76953-.4707.11163-.07883.22123-.15803.32422-.24414.017218-.014484.037734-.026337.054687-.041016.008042-.006964.013497-.016412.021485-.023437.33169-.28982.60596-.61869.80273-.98633.093299-.17431.16707-.35733.2207-.54883.008132-.028013.016239-.055671.023438-.083985.048055-.197.082031-.39879.082031-.61328a1.0001 1.0001 0 0 0 -.017578-.18164 1.0001 1.0001 0 0 0 -.001953-.017578c-.073081-.95265-.64941-1.7232-1.4473-2.3027l-4.7012-7.0527a1.0001 1.0001 0 0 0 -.84961-.44531zm-.98242 4.3027v1.7461c-.43911.033461-.86366.087835-1.2734.16406l1.2734-1.9102zm2 0 1.2734 1.9102c-.40978-.076228-.83432-.1306-1.2734-.16406v-1.7461zm-2 3.748v1.9492a1.0001 1.0001 0 1 0 2 0v-1.9492c1.1126.10487 2.0951.37277 2.7949.72266.12146.060728.20622.12218.30664.18359l.80078 1.2012c-.032965.14677-.089654.30658-.30469.51758-.051464.049149-.10034.098137-.16406.14844-.045193.035312-.091373.070148-.14258.10547-.11245.07827-.24511.15838-.39062.23633-.075428.040204-.1553.078371-.23828.11719-.16195.075482-.33452.14662-.52148.21289-.070588.025324-.14454.048409-.21875.072265-.23425.074473-.48077.14392-.74414.20117-.021343.004579-.041038.011189-.0625.015625-.2559.05368-.53101.090517-.80859.125-.856.10229-1.7573.10229-2.6133 0-.27759-.034483-.5527-.07132-.80859-.125-.021462-.004436-.041156-.011046-.0625-.015625-.26337-.057254-.50989-.1267-.74414-.20117-.074211-.023856-.14816-.046941-.21875-.072265-.18697-.066266-.35954-.13741-.52148-.21289-.082979-.038816-.16285-.076983-.23828-.11719-.14552-.077951-.27818-.15806-.39062-.23633-.051205-.035321-.097386-.070157-.14258-.10547-.06372-.050301-.1126-.099289-.16406-.14844-.21503-.21099-.27173-.37081-.30469-.51758l.80078-1.2012c.10043-.061415.18518-.12287.30664-.18359.69978-.34989 1.6823-.61778 2.7949-.72266z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/Container.svg b/editor/icons/Container.svg
index a7be880268..efe1966ad4 100644
--- a/editor/icons/Container.svg
+++ b/editor/icons/Container.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 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4c0 1.1046.89543 2 2 2v-2zm4 0v2h2v-2zm4 0v2h2v-2zm4 0v2c1.1046 0 2-.89543 2-2z" fill="#a5efac"/></svg>
+<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 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4c0 1.1046.89543 2 2 2v-2zm4 0v2h2v-2zm4 0v2h2v-2zm4 0v2c1.1046 0 2-.89543 2-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/Control.svg b/editor/icons/Control.svg
index 0ec9c4c6fe..3f3530de61 100644
--- a/editor/icons/Control.svg
+++ b/editor/icons/Control.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4z" fill="#8eef97"/></svg>
diff --git a/editor/icons/ControlLayout.svg b/editor/icons/ControlLayout.svg
index c4aa64113d..11dd2554be 100644
--- a/editor/icons/ControlLayout.svg
+++ b/editor/icons/ControlLayout.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h14v-14zm2 2h3v3h-3zm5 0h5v3h-5zm-5 5h3v5h-3zm5 0h5v5h-5z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h14v-14zm2 2h3v3h-3zm5 0h5v3h-5zm-5 5h3v5h-3zm5 0h5v5h-5z" fill="#8eef97"/></svg>
diff --git a/editor/icons/CreateNewSceneFrom.svg b/editor/icons/CreateNewSceneFrom.svg
index 094a0aae39..3ec6140515 100644
--- a/editor/icons/CreateNewSceneFrom.svg
+++ b/editor/icons/CreateNewSceneFrom.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m14.564 2-2.2441.32812.81836 1.9004 1.7148-.25-.28906-1.9785zm-4.2227.61523-1.9785.28906.81836 1.9023 1.9785-.28906zm-3.959.57812-1.9785.28906.81836 1.9023 1.9785-.28906zm-3.957.57812-1.7148.25.28906 1.9785 2.2441-.32812-.81836-1.9004zm-1.4258 3.2285v6c0 1.1046.89543 2 2 2h7v-1h-2v-4h2v-2h4v2h1v-3z" fill="#e0e0e0" transform="translate(0 1036.4)"/><circle cx="-14" cy="1047.4" fill="#e0e0e0" r="0"/><path d="m13 1049.4h2v-2h-2v-2h-2v2h-2v2h2v2h2z" fill="#84ffb1" fill-rule="evenodd"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m14.564 2-2.2441.32812.81836 1.9004 1.7148-.25-.28906-1.9785zm-4.2227.61523-1.9785.28906.81836 1.9023 1.9785-.28906zm-3.959.57812-1.9785.28906.81836 1.9023 1.9785-.28906zm-3.957.57812-1.7148.25.28906 1.9785 2.2441-.32812-.81836-1.9004zm-1.4258 3.2285v6c0 1.1046.89543 2 2 2h7v-1h-2v-4h2v-2h4v2h1v-3z" fill="#e0e0e0" transform="translate(0 1036.4)"/><circle cx="-14" cy="1047.4" fill="#e0e0e0" r="0"/><path d="m13 1049.4h2v-2h-2v-2h-2v2h-2v2h2v2h2z" fill="#5fff97" fill-rule="evenodd"/></g></svg>
diff --git a/editor/icons/Cubemap.svg b/editor/icons/Cubemap.svg
index b3ec2bd3e7..81965f7a09 100644
--- a/editor/icons/Cubemap.svg
+++ b/editor/icons/Cubemap.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 6v4h4v-4zm8 0v4h4v-4z" fill="#84ffb1"/><path d="m4 6v4h4v-4zm8 0v4h4v-4z" fill="#ff8484"/><path d="m4 2v4h4v-4zm0 8v4h4v-4z" fill="#84c2ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 6v4h4v-4zm8 0v4h4v-4z" fill="#5fff97"/><path d="m4 6v4h4v-4zm8 0v4h4v-4z" fill="#ff5f5f"/><path d="m4 2v4h4v-4zm0 8v4h4v-4z" fill="#5fb2ff"/></svg>
diff --git a/editor/icons/CubemapArray.svg b/editor/icons/CubemapArray.svg
index c9d722dc52..847fc7f70a 100644
--- a/editor/icons/CubemapArray.svg
+++ b/editor/icons/CubemapArray.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 6v4h2v-4zm6 0v4h4v-4z" fill="#84ffb1"/><path d="m4 6v4h4v-4zm8 0v4h2v-4z" fill="#ff8484"/><path d="m4 2v4h4v-4zm0 8v4h4v-4z" fill="#84c2ff"/><path d="m-.00000002 2v12h4.00000002v-2h-2v-8h2v-2h-2zm12.00000002 0v2h2.000001v8h-2.000001v2h4.000001v-12h-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 6v4h2v-4zm6 0v4h4v-4z" fill="#5fff97"/><path d="m4 6v4h4v-4zm8 0v4h2v-4z" fill="#ff5f5f"/><path d="m4 2v4h4v-4zm0 8v4h4v-4z" fill="#5fb2ff"/><path d="m-.00000002 2v12h4.00000002v-2h-2v-8h2v-2h-2zm12.00000002 0v2h2.000001v8h-2.000001v2h4.000001v-12h-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/CurveClose.svg b/editor/icons/CurveClose.svg
index 26e30cdb1c..5cb8ab890e 100644
--- a/editor/icons/CurveClose.svg
+++ b/editor/icons/CurveClose.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 1049.4c-2-9-1-10 8-8" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><g transform="translate(0 1036.4)"><path d="m5 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm8 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-8 8a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#f5f5f5"/><path d="m10 6v2h2v-2zm0 2h-2v2h2zm-2 2h-2v2h2z" fill="#84c2ff"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 1049.4c-2-9-1-10 8-8" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><g transform="translate(0 1036.4)"><path d="m5 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm8 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-8 8a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#f5f5f5"/><path d="m10 6v2h2v-2zm0 2h-2v2h2zm-2 2h-2v2h2z" fill="#5fb2ff"/></g></g></svg>
diff --git a/editor/icons/CurveCreate.svg b/editor/icons/CurveCreate.svg
index 962abd0b3f..1e80817a34 100644
--- a/editor/icons/CurveCreate.svg
+++ b/editor/icons/CurveCreate.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 1049.4c-2-9-1-10 8-8" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><g transform="translate(0 1036.4)"><path d="m5 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm6 5v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#84ffb1"/><path d="m13 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-8 8a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#f5f5f5"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 1049.4c-2-9-1-10 8-8" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><g transform="translate(0 1036.4)"><path d="m5 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm6 5v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#5fff97"/><path d="m13 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-8 8a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#f5f5f5"/></g></g></svg>
diff --git a/editor/icons/CurveCurve.svg b/editor/icons/CurveCurve.svg
index 35770543af..e43e7ccd8a 100644
--- a/editor/icons/CurveCurve.svg
+++ b/editor/icons/CurveCurve.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 1049.4c-2-9-1-10 8-8" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><g transform="translate(0 1036.4)"><path d="m8.4688.4707-2.6875 2.6875h-.0019531a2 2 0 0 0 -.7793-.1582 2 2 0 0 0 -2 2 2 2 0 0 0 .16016.7793l-2.6914 2.6914 1.0625 1.0605 2.6895-2.6895a2 2 0 0 0 .7793.1582 2 2 0 0 0 2-2 2 2 0 0 0 -.16016-.77734l2.6914-2.6914-1.0625-1.0605z" fill="#84c2ff"/><path d="m13 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-8 8a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#f5f5f5"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 1049.4c-2-9-1-10 8-8" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><g transform="translate(0 1036.4)"><path d="m8.4688.4707-2.6875 2.6875h-.0019531a2 2 0 0 0 -.7793-.1582 2 2 0 0 0 -2 2 2 2 0 0 0 .16016.7793l-2.6914 2.6914 1.0625 1.0605 2.6895-2.6895a2 2 0 0 0 .7793.1582 2 2 0 0 0 2-2 2 2 0 0 0 -.16016-.77734l2.6914-2.6914-1.0625-1.0605z" fill="#5fb2ff"/><path d="m13 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-8 8a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#f5f5f5"/></g></g></svg>
diff --git a/editor/icons/CurveDelete.svg b/editor/icons/CurveDelete.svg
index 5bce6d0c1c..cf15d75bc1 100644
--- a/editor/icons/CurveDelete.svg
+++ b/editor/icons/CurveDelete.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 1049.4c-2-9-1-10 8-8" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><path d="m5 1039.4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm4.8789 5.4648-1.4141 1.4141 2.1211 2.1211-2.1211 2.1211 1.4141 1.4141 2.1211-2.1211 2.1211 2.1211 1.4141-1.4141-2.1211-2.1211 2.1211-2.1211-1.4141-1.4141-2.1211 2.1211z" fill="#ff8484"/><path d="m13 1039.4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-8 8a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#f5f5f5"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 1049.4c-2-9-1-10 8-8" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><path d="m5 1039.4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm4.8789 5.4648-1.4141 1.4141 2.1211 2.1211-2.1211 2.1211 1.4141 1.4141 2.1211-2.1211 2.1211 2.1211 1.4141-1.4141-2.1211-2.1211 2.1211-2.1211-1.4141-1.4141-2.1211 2.1211z" fill="#ff5f5f"/><path d="m13 1039.4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-8 8a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#f5f5f5"/></g></svg>
diff --git a/editor/icons/CurveEdit.svg b/editor/icons/CurveEdit.svg
index 84b56fbccb..57e365f3cd 100644
--- a/editor/icons/CurveEdit.svg
+++ b/editor/icons/CurveEdit.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 1049.4c-2-9-1-10 8-8" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><g transform="translate(0 1036.4)"><path d="m5 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm3 5 3.291 8 .94726-2.8203 1.8828 1.8828.94336-.94141-1.8848-1.8828 2.8203-.94726-8-3.291z" fill="#84c2ff"/><path d="m13 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-8 8a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#f5f5f5"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 1049.4c-2-9-1-10 8-8" fill="none" stroke="#f5f5f5" stroke-opacity=".39216" stroke-width="2"/><g transform="translate(0 1036.4)"><path d="m5 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm3 5 3.291 8 .94726-2.8203 1.8828 1.8828.94336-.94141-1.8848-1.8828 2.8203-.94726-8-3.291z" fill="#5fb2ff"/><path d="m13 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-8 8a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z" fill="#f5f5f5"/></g></g></svg>
diff --git a/editor/icons/CylinderMesh.svg b/editor/icons/CylinderMesh.svg
index 85483aeeca..f6315c253c 100644
--- a/editor/icons/CylinderMesh.svg
+++ b/editor/icons/CylinderMesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.5.9375c-1.6377 0-3.12.2123-4.2737.5969-.57682.1923-1.0754.4237-1.4905.7508-.41505.3271-.79834.8259-.79834 1.4648v7.5c0 .6389.38329 1.1396.79834 1.4667s.91366.5585 1.4905.7507c1.1536.3846 2.6359.5951 4.2737.5951s3.12-.2105 4.2737-.5951c.57682-.1922 1.0754-.4236 1.4905-.7507.41505-.3271.79834-.8278.79834-1.4667v-7.5c0-.6389-.38329-1.1377-.79834-1.4648s-.91366-.5585-1.4905-.7508c-1.1536-.3846-2.6359-.5969-4.2737-.5969zm0 1.875c1.4689 0 2.8.2076 3.6823.5017.4347.1449.7513.3163.9082.4376-.15705.1212-.47387.2911-.9082.4358-.88221.2941-2.2134.4999-3.6823.4999s-2.8-.2058-3.6823-.4999c-.43433-.1447-.75115-.3146-.9082-.4358.15691-.1213.47351-.2927.9082-.4376.88221-.2941 2.2134-.5017 3.6823-.5017zm-4.6875 2.9883c.13762.055.26578.1173.41382.1666 1.1536.3846 2.6359.5951 4.2737.5951s3.12-.2105 4.2737-.5951c.14804-.049.2762-.1112.41382-.1666v5.4492c-.15705.1212-.57092.2929-1.0052.4376-.88221.2941-2.2134.4999-3.6823.4999s-2.8-.2058-3.6823-.4999c-.43433-.1447-.8482-.3164-1.0052-.4376z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.5.9375c-1.6377 0-3.12.2123-4.2737.5969-.57682.1923-1.0754.4237-1.4905.7508-.41505.3271-.79834.8259-.79834 1.4648v7.5c0 .6389.38329 1.1396.79834 1.4667s.91366.5585 1.4905.7507c1.1536.3846 2.6359.5951 4.2737.5951s3.12-.2105 4.2737-.5951c.57682-.1922 1.0754-.4236 1.4905-.7507.41505-.3271.79834-.8278.79834-1.4667v-7.5c0-.6389-.38329-1.1377-.79834-1.4648s-.91366-.5585-1.4905-.7508c-1.1536-.3846-2.6359-.5969-4.2737-.5969zm0 1.875c1.4689 0 2.8.2076 3.6823.5017.4347.1449.7513.3163.9082.4376-.15705.1212-.47387.2911-.9082.4358-.88221.2941-2.2134.4999-3.6823.4999s-2.8-.2058-3.6823-.4999c-.43433-.1447-.75115-.3146-.9082-.4358.15691-.1213.47351-.2927.9082-.4376.88221-.2941 2.2134-.5017 3.6823-.5017zm-4.6875 2.9883c.13762.055.26578.1173.41382.1666 1.1536.3846 2.6359.5951 4.2737.5951s3.12-.2105 4.2737-.5951c.14804-.049.2762-.1112.41382-.1666v5.4492c-.15705.1212-.57092.2929-1.0052.4376-.88221.2941-2.2134.4999-3.6823.4999s-2.8-.2058-3.6823-.4999c-.43433-.1447-.8482-.3164-1.0052-.4376z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/DampedSpringJoint2D.svg b/editor/icons/DampedSpringJoint2D.svg
index 02a7033106..99e1a1f1e1 100644
--- a/editor/icons/DampedSpringJoint2D.svg
+++ b/editor/icons/DampedSpringJoint2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".98824"><path d="m4 3v2l8 3v-2zm0 5v2l8 3v-2z" fill="#708cea"/><path d="m4 3v2l8-2v-2zm0 5v2l8-2v-2zm0 5v2l8-2v-2z" fill="#a5b7f3"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".98824"><path d="m4 3v2l8 3v-2zm0 5v2l8 3v-2z" fill="#4b70ea"/><path d="m4 3v2l8-2v-2zm0 5v2l8-2v-2zm0 5v2l8-2v-2z" fill="#8da5f3"/></g></svg>
diff --git a/editor/icons/DebugContinue.svg b/editor/icons/DebugContinue.svg
index cf9e0724c2..8625626ab2 100644
--- a/editor/icons/DebugContinue.svg
+++ b/editor/icons/DebugContinue.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m10 4v3h-5v2h5v3l2.5-2 2.5-2-2.5-2z" fill="#ff8484" transform="translate(0 1036.4)"/><circle cx="4" cy="1044.4" fill="#e0e0e0" r="3"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m10 4v3h-5v2h5v3l2.5-2 2.5-2-2.5-2z" fill="#ff5f5f" transform="translate(0 1036.4)"/><circle cx="4" cy="1044.4" fill="#e0e0e0" r="3"/></g></svg>
diff --git a/editor/icons/DebugNext.svg b/editor/icons/DebugNext.svg
index d510aff828..50532d6e77 100644
--- a/editor/icons/DebugNext.svg
+++ b/editor/icons/DebugNext.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1v10h-2l1.5 2 1.5 2 1.5-2 1.5-2h-2v-10z" fill="#ff8484"/><path d="m7 1v2h8v-2zm2 4v2h6v-2zm0 4v2h6v-2zm-2 4v2h8v-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1v10h-2l1.5 2 1.5 2 1.5-2 1.5-2h-2v-10z" fill="#ff5f5f"/><path d="m7 1v2h8v-2zm2 4v2h6v-2zm0 4v2h6v-2zm-2 4v2h8v-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/DebugStep.svg b/editor/icons/DebugStep.svg
index b26e9b7b25..f8d57ef693 100644
--- a/editor/icons/DebugStep.svg
+++ b/editor/icons/DebugStep.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v8 2h2 1v2l2-1.5 2-1.5-2-1.5-2-1.5v2h-1v-8z" fill="#ff8484"/><path d="m7 1v2h8v-2zm2 4v2h6v-2zm0 4v2h6v-2zm-2 4v2h8v-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v8 2h2 1v2l2-1.5 2-1.5-2-1.5-2-1.5v2h-1v-8z" fill="#ff5f5f"/><path d="m7 1v2h8v-2zm2 4v2h6v-2zm0 4v2h6v-2zm-2 4v2h8v-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Decal.svg b/editor/icons/Decal.svg
index 2a61ceb0a0..8c33f44360 100644
--- a/editor/icons/Decal.svg
+++ b/editor/icons/Decal.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2c-3.3137085 0-6 2.6862915-6 6 0 2.220299 1.2092804 4.153789 3.0019531 5.191406l8.9082029-6.1894529c-.476307-2.8374399-2.937354-5.0019531-5.910156-5.0019531z" fill="#fc9c9c"/><path d="m5.001954 13.191406 8.908202-6.1894529c-.882819-.510985-1.904638-.808594-2.998046-.808594-3.3137079 0-6 2.686292-6 5.9999999 0 .340906.03522.672663.08984.998047z" fill="#ff5d5d"/><path d="m13.910156 7.0019531-8.908202 6.1894529c.882819.510985 1.904638.808594 2.998046.808594 3.313708 0 6-2.686292 6-5.9999999 0-.340906-.03522-.672663-.08984-.998047z" fill="#fc9c9c" fill-opacity=".392157"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2c-3.3137085 0-6 2.6862915-6 6 0 2.220299 1.2092804 4.153789 3.0019531 5.191406l8.9082029-6.1894529c-.476307-2.8374399-2.937354-5.0019531-5.910156-5.0019531z" fill="#fc7f7f"/><path d="m5.001954 13.191406 8.908202-6.1894529c-.882819-.510985-1.904638-.808594-2.998046-.808594-3.3137079 0-6 2.686292-6 5.9999999 0 .340906.03522.672663.08984.998047z" fill="#ff5d5d"/><path d="m13.910156 7.0019531-8.908202 6.1894529c.882819.510985 1.904638.808594 2.998046.808594 3.313708 0 6-2.686292 6-5.9999999 0-.340906-.03522-.672663-.08984-.998047z" fill="#fc7f7f" fill-opacity=".392157"/></svg>
diff --git a/editor/icons/Dictionary.svg b/editor/icons/Dictionary.svg
index c835398836..0284e847d9 100644
--- a/editor/icons/Dictionary.svg
+++ b/editor/icons/Dictionary.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2v2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-8zm3 0v2h2v-2zm7 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2zm-2 2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2zm-3 3v-1h-2v4h2zm-5-1v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#77edb1"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2v2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-8zm3 0v2h2v-2zm7 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2zm-2 2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2zm-3 3v-1h-2v4h2zm-5-1v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#54ed9e"/></svg>
diff --git a/editor/icons/DirectionalLight3D.svg b/editor/icons/DirectionalLight3D.svg
index ff033636be..ef25fd473a 100644
--- a/editor/icons/DirectionalLight3D.svg
+++ b/editor/icons/DirectionalLight3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v3h2v-3zm-2.5352 2.0508-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm7.0703 0-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm-3.5352 1.9492c-1.6569 0-3 1.3432-3 3s1.3431 3 3 3 3-1.3432 3-3-1.3431-3-3-3zm-7 2v2h3v-2zm11 0v2h3v-2zm-7.5352 3.1211-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm7.0703 0-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm-4.5352 1.8789v3h2v-3z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v3h2v-3zm-2.5352 2.0508-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm7.0703 0-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm-3.5352 1.9492c-1.6569 0-3 1.3432-3 3s1.3431 3 3 3 3-1.3432 3-3-1.3431-3-3-3zm-7 2v2h3v-2zm11 0v2h3v-2zm-7.5352 3.1211-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm7.0703 0-1.4141 1.4141 1.4141 1.4141 1.4141-1.4141zm-4.5352 1.8789v3h2v-3z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/EditAddRemove.svg b/editor/icons/EditAddRemove.svg
new file mode 100644
index 0000000000..307557cbfc
--- /dev/null
+++ b/editor/icons/EditAddRemove.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.5105509 1c-.554 0-1 .446-1 1v2h4v-2c0-.554-.446-1-1-1zm5.4894491 12.5v1.5h6v-1.5zm-6.4894491-8.5v7l2 3 2-3v-7zm1 1h1v5h-1zm7.7394491 0v2.25h-2.25v1.5h2.25v2.25h1.5v-2.25h2.25v-1.5h-2.25v-2.25z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/EditBezier.svg b/editor/icons/EditBezier.svg
index 3feff790dc..82667d0bed 100644
--- a/editor/icons/EditBezier.svg
+++ b/editor/icons/EditBezier.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m1.4758015 1050.3064c11.6492855.7191 3.1098343-11.4976 12.2331255-11.3475" fill="none" stroke="#84c2ff" stroke-miterlimit="4.9" stroke-width="2.2"/><g fill="#e0e0e0"><circle cx="13.470984" cy="1038.7133" r="1.823002"/><circle cx="2.444912" cy="1050.1708" r="1.823002"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m1.4758015 1050.3064c11.6492855.7191 3.1098343-11.4976 12.2331255-11.3475" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="2.2"/><g fill="#e0e0e0"><circle cx="13.470984" cy="1038.7133" r="1.823002"/><circle cx="2.444912" cy="1050.1708" r="1.823002"/></g></g></svg>
diff --git a/editor/icons/Editor3DHandle.svg b/editor/icons/Editor3DHandle.svg
index f63234f410..00e0d865af 100644
--- a/editor/icons/Editor3DHandle.svg
+++ b/editor/icons/Editor3DHandle.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill-opacity=".29412" r="8"/><circle cx="8" cy="8" fill="#fff" r="7"/><circle cx="8" cy="8" fill="#ff8484" r="5"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill-opacity=".29412" r="8"/><circle cx="8" cy="8" fill="#fff" r="7"/><circle cx="8" cy="8" fill="#ff5f5f" r="5"/></svg>
diff --git a/editor/icons/EditorControlAnchor.svg b/editor/icons/EditorControlAnchor.svg
index 4574f5d7be..3383ea121f 100644
--- a/editor/icons/EditorControlAnchor.svg
+++ b/editor/icons/EditorControlAnchor.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 0a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 1.0566-.11914l9.9434 6.1191-6.1172-9.9395a5 5 0 0 0 .11719-1.0605 5 5 0 0 0 -5-5z" fill-opacity=".39216" transform="translate(0 1036.4)"/><path d="m5 1a4 4 0 0 0 -4 4 4 4 0 0 0 4 4 4 4 0 0 0 1.1406-.16992l9.8594 7.1699-7.168-9.8555a4 4 0 0 0 .16797-1.1445 4 4 0 0 0 -4-4z" fill="#a5efac" fill-rule="evenodd" transform="translate(0 1036.4)"/><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/><circle cx="5" cy="1041.4" fill="#a5efac" r="0"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m5 0a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 1.0566-.11914l9.9434 6.1191-6.1172-9.9395a5 5 0 0 0 .11719-1.0605 5 5 0 0 0 -5-5z" fill-opacity=".39216" transform="translate(0 1036.4)"/><path d="m5 1a4 4 0 0 0 -4 4 4 4 0 0 0 4 4 4 4 0 0 0 1.1406-.16992l9.8594 7.1699-7.168-9.8555a4 4 0 0 0 .16797-1.1445 4 4 0 0 0 -4-4z" fill="#8eef97" fill-rule="evenodd" transform="translate(0 1036.4)"/><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/><circle cx="5" cy="1041.4" fill="#8eef97" r="0"/></g></svg>
diff --git a/editor/icons/EditorHandle.svg b/editor/icons/EditorHandle.svg
index a56e64bde3..8f78189798 100644
--- a/editor/icons/EditorHandle.svg
+++ b/editor/icons/EditorHandle.svg
@@ -1 +1 @@
-<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><circle cx="5" cy="5" fill-opacity=".29412" r="5"/><circle cx="5" cy="5" fill="#fff" r="4"/><circle cx="5" cy="5" fill="#ff8484" r="3"/></svg>
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><circle cx="5" cy="5" fill-opacity=".29412" r="5"/><circle cx="5" cy="5" fill="#fff" r="4"/><circle cx="5" cy="5" fill="#ff5f5f" r="3"/></svg>
diff --git a/editor/icons/EditorHandleAdd.svg b/editor/icons/EditorHandleAdd.svg
index 82d3730d3c..aca6b61df1 100644
--- a/editor/icons/EditorHandleAdd.svg
+++ b/editor/icons/EditorHandleAdd.svg
@@ -1 +1 @@
-<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><circle cx="5" cy="5" fill-opacity=".29412" r="5"/><circle cx="5" cy="5" fill="#474747" r="4"/><path d="m4 2v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#84ffb1"/></svg>
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><circle cx="5" cy="5" fill-opacity=".29412" r="5"/><circle cx="5" cy="5" fill="#474747" r="4"/><path d="m4 2v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#5fff97"/></svg>
diff --git a/editor/icons/EditorHandleDisabled.svg b/editor/icons/EditorHandleDisabled.svg
new file mode 100644
index 0000000000..483a25a571
--- /dev/null
+++ b/editor/icons/EditorHandleDisabled.svg
@@ -0,0 +1 @@
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m5 0c-2.7614237 0-5 2.2385763-5 5s2.2385763 5 5 5 5-2.2385763 5-5-2.2385763-5-5-5zm-.0421327 2.2165215c.014044-.0001063.0280887-.0001063.0421327 0 1.5372727 0 2.7834785 1.2462058 2.7834785 2.7834785s-1.2462058 2.7834785-2.7834785 2.7834785-2.7834785-1.2462058-2.7834785-2.7834785c-.0001743-1.5209681 1.2205519-2.760456 2.7413458-2.7834785z" fill="#fff" fill-opacity=".294118"/></svg>
diff --git a/editor/icons/EditorPivot.svg b/editor/icons/EditorPivot.svg
index ecb5dd95b7..cd7f5779c5 100644
--- a/editor/icons/EditorPivot.svg
+++ b/editor/icons/EditorPivot.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 0v6h-6v4h6v6h4v-6h6v-4h-6v-6zm1 7h2v2h-2z" fill="#fff" fill-opacity=".70588"/><path d="m7 1v5h2v-5zm-6 6v2h5v-2zm9 0v2h5v-2zm-3 3v5h2v-5z" fill="#ff8484"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 0v6h-6v4h6v6h4v-6h6v-4h-6v-6zm1 7h2v2h-2z" fill="#fff" fill-opacity=".70588"/><path d="m7 1v5h2v-5zm-6 6v2h5v-2zm9 0v2h5v-2zm-3 3v5h2v-5z" fill="#ff5f5f"/></svg>
diff --git a/editor/icons/EditorPosition.svg b/editor/icons/EditorPosition.svg
index 09f09feffc..10d0f5629d 100644
--- a/editor/icons/EditorPosition.svg
+++ b/editor/icons/EditorPosition.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 0v4.4199a4.2662 4.0576 0 0 0 -1.709 1.5801h-4.291v4h4.2949a4.2662 4.0576 0 0 0 1.7051 1.582v4.418h4v-4.4199a4.2662 4.0576 0 0 0 1.709-1.5801h4.291v-4h-4.2949a4.2662 4.0576 0 0 0 -1.7051-1.582v-4.418z" fill="#fff" fill-opacity=".70588"/><path d="m7 1v3.0605a4.2662 4.0576 0 0 1 1-.11914 4.2662 4.0576 0 0 1 1 .11914v-3.0605zm1 4.0801a2.9201 2.9201 0 0 0 -2.9199 2.9199 2.9201 2.9201 0 0 0 2.9199 2.9199 2.9201 2.9201 0 0 0 2.9199-2.9199 2.9201 2.9201 0 0 0 -2.9199-2.9199zm-7 1.9199v2h2.8691a4.2662 4.0576 0 0 1 -.13477-1 4.2662 4.0576 0 0 1 .13672-1h-2.8711zm11.131 0a4.2662 4.0576 0 0 1 .13477 1 4.2662 4.0576 0 0 1 -.13672 1h2.8711v-2h-2.8691zm-5.1309 4.9395v3.0605h2v-3.0605a4.2662 4.0576 0 0 1 -1 .11914 4.2662 4.0576 0 0 1 -1-.11914z" fill="#ff8484"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 0v4.4199a4.2662 4.0576 0 0 0 -1.709 1.5801h-4.291v4h4.2949a4.2662 4.0576 0 0 0 1.7051 1.582v4.418h4v-4.4199a4.2662 4.0576 0 0 0 1.709-1.5801h4.291v-4h-4.2949a4.2662 4.0576 0 0 0 -1.7051-1.582v-4.418z" fill="#fff" fill-opacity=".70588"/><path d="m7 1v3.0605a4.2662 4.0576 0 0 1 1-.11914 4.2662 4.0576 0 0 1 1 .11914v-3.0605zm1 4.0801a2.9201 2.9201 0 0 0 -2.9199 2.9199 2.9201 2.9201 0 0 0 2.9199 2.9199 2.9201 2.9201 0 0 0 2.9199-2.9199 2.9201 2.9201 0 0 0 -2.9199-2.9199zm-7 1.9199v2h2.8691a4.2662 4.0576 0 0 1 -.13477-1 4.2662 4.0576 0 0 1 .13672-1h-2.8711zm11.131 0a4.2662 4.0576 0 0 1 .13477 1 4.2662 4.0576 0 0 1 -.13672 1h2.8711v-2h-2.8691zm-5.1309 4.9395v3.0605h2v-3.0605a4.2662 4.0576 0 0 1 -1 .11914 4.2662 4.0576 0 0 1 -1-.11914z" fill="#ff5f5f"/></svg>
diff --git a/editor/icons/Eraser.svg b/editor/icons/Eraser.svg
new file mode 100644
index 0000000000..4995fa863c
--- /dev/null
+++ b/editor/icons/Eraser.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.228155 1.5447161-9.60250173 9.6107429 1.41421353 1.414213 1.6134635 1.885612.00693-.0069 4.2288056.000024 7.4852811-7.4852817zm-4.4456043 7.2823178 2.3136653 2.5858141-1.0357479 1.035746h-2.5853592l-1.0209853-1.293133z" fill="#e0e0e0" fill-opacity=".996078" stroke-width="1.02405"/></svg>
diff --git a/editor/icons/ExpandTree.svg b/editor/icons/ExpandTree.svg
new file mode 100644
index 0000000000..abdc1f9458
--- /dev/null
+++ b/editor/icons/ExpandTree.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-rule="nonzero"><path d="m8 16-3.536-2.597h2.536v-2.523h2v2.523h2.536z"/><path d="m8 0-3.536 2.583h2.536v2.537h2v-2.537h2.536z"/><path d="m.704 7.085h14.591v1.831h-14.591z"/></g></svg>
diff --git a/editor/icons/FixedSpatialMaterial.svg b/editor/icons/FixedSpatialMaterial.svg
index 6701208560..322465a0c7 100644
--- a/editor/icons/FixedSpatialMaterial.svg
+++ b/editor/icons/FixedSpatialMaterial.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -4.8887 2h2.8887 6.8965a7 7 0 0 0 -4.8965-2z" fill="#ff7070"/><path d="m3.1113 3a7 7 0 0 0 -1.4277 2h2.3164a2 2 0 0 1 2-2zm2.8887 0a2 2 0 0 1 2 2h6.3145a7 7 0 0 0 -1.418-2z" fill="#ffeb70"/><path d="m1.6836 5a7 7 0 0 0 -.60547 2h4.9219a2 2 0 0 1 -2-2h-2.3164zm4.3164 2h8.9199a7 7 0 0 0 -.60547-2h-6.3145a2 2 0 0 1 -2 2z" fill="#9dff70"/><path d="m1.0781 7a7 7 0 0 0 -.078125 1 7 7 0 0 0 .080078 1h13.842a7 7 0 0 0 .078125-1 7 7 0 0 0 -.080078-1h-8.9199-4.9219z" fill="#70ffb9"/><path d="m1.0801 9a7 7 0 0 0 .60547 2h12.631a7 7 0 0 0 .60547-2h-13.842z" fill="#70deff"/><path d="m3.1035 13a7 7 0 0 0 4.8965 2 7 7 0 0 0 4.8887-2z" fill="#ff70ac"/><path d="m1.6855 11a7 7 0 0 0 1.418 2h9.7852a7 7 0 0 0 1.4277-2h-12.631z" fill="#9f70ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -4.8887 2h2.8887 6.8965a7 7 0 0 0 -4.8965-2z" fill="#ff4545"/><path d="m3.1113 3a7 7 0 0 0 -1.4277 2h2.3164a2 2 0 0 1 2-2zm2.8887 0a2 2 0 0 1 2 2h6.3145a7 7 0 0 0 -1.418-2z" fill="#ffe345"/><path d="m1.6836 5a7 7 0 0 0 -.60547 2h4.9219a2 2 0 0 1 -2-2h-2.3164zm4.3164 2h8.9199a7 7 0 0 0 -.60547-2h-6.3145a2 2 0 0 1 -2 2z" fill="#80ff45"/><path d="m1.0781 7a7 7 0 0 0 -.078125 1 7 7 0 0 0 .080078 1h13.842a7 7 0 0 0 .078125-1 7 7 0 0 0 -.080078-1h-8.9199-4.9219z" fill="#45ffa2"/><path d="m1.0801 9a7 7 0 0 0 .60547 2h12.631a7 7 0 0 0 .60547-2h-13.842z" fill="#45d7ff"/><path d="m3.1035 13a7 7 0 0 0 4.8965 2 7 7 0 0 0 4.8887-2z" fill="#ff4596"/><path d="m1.6855 11a7 7 0 0 0 1.418 2h9.7852a7 7 0 0 0 1.4277-2h-12.631z" fill="#8045ff"/></svg>
diff --git a/editor/icons/FontData.svg b/editor/icons/FontData.svg
index 7ee88582a5..4cb6412081 100644
--- a/editor/icons/FontData.svg
+++ b/editor/icons/FontData.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 1h1a1 1 0 0 1 1-1h2v6a1 1 0 0 1 -1 1v1h1 2 1v-1a1 1 0 0 1 -1-1v-6h2a1 1 0 0 1 1 1h1v-1-2h-4-2zm0 5v2h2v-2zm0 3v2h2v-2zm0 3v2h2v-2zm3 0v2h2v-2z" fill="#e0e0e0"/><path d="m4 5v2 1h1a1 1 0 0 1 1-1h2v6a1 1 0 0 1 -1 1v1h1 2 1v-1a1 1 0 0 1 -1-1v-6h2a1 1 0 0 1 1 1h1v-1-2h-4-2z" fill="#ff8484"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 1h1a1 1 0 0 1 1-1h2v6a1 1 0 0 1 -1 1v1h1 2 1v-1a1 1 0 0 1 -1-1v-6h2a1 1 0 0 1 1 1h1v-1-2h-4-2zm0 5v2h2v-2zm0 3v2h2v-2zm0 3v2h2v-2zm3 0v2h2v-2z" fill="#e0e0e0"/><path d="m4 5v2 1h1a1 1 0 0 1 1-1h2v6a1 1 0 0 1 -1 1v1h1 2 1v-1a1 1 0 0 1 -1-1v-6h2a1 1 0 0 1 1 1h1v-1-2h-4-2z" fill="#ff5f5f"/></svg>
diff --git a/editor/icons/FontSize.svg b/editor/icons/FontSize.svg
new file mode 100644
index 0000000000..3e148009ce
--- /dev/null
+++ b/editor/icons/FontSize.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-rule="nonzero"><path d="m1.047 7.127h6.025v1.2h-6.025z"/><path d="m3.452 7.127h1.214v6.508h-1.214z"/><path d="m2.238 13.171h3.643v.465h-3.643z"/><path d="m1.477 7.127v2.4h-.43v-2.4z"/><path d="m7.071 7.127v2.4h-.43v-2.4z"/><path d="m1.477 8.327v1.2c0-.658.389-1.2.861-1.2z"/><path d="m5.78 8.327c.473 0 .861.542.861 1.2v-1.2z"/><path d="m2.238 13.171c.666 0 1.214-.42 1.214-.93v.93z"/><path d="m5.88 13.171c-.666 0-1.214-.42-1.214-.93v.93z"/><path d="m4.563 2.873h10.773v1.539h-10.773z"/><path d="m9.18 2.873h1.539v10.773h-1.539z"/><path d="m7.641 12.877h4.617v.769h-4.617z"/><path d="m5.332 2.873v3.078h-.769v-3.078z"/><path d="m15.336 2.873v3.078h-.77v-3.078z"/><path d="m5.332 4.412v1.539c0-.844.695-1.539 1.539-1.539z"/><path d="m13.027 4.412c.844 0 1.539.695 1.539 1.539v-1.539z"/><path d="m7.641 12.877c.844 0 1.539-.695 1.539-1.539v1.539z"/><path d="m12.258 12.877c-.845 0-1.539-.695-1.539-1.539v1.539z"/></g></svg>
diff --git a/editor/icons/GPUParticles2D.svg b/editor/icons/GPUParticles2D.svg
index b291bcda95..a693e554b2 100644
--- a/editor/icons/GPUParticles2D.svg
+++ b/editor/icons/GPUParticles2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a4.5 5 0 0 0 -4.4141 4.0312 3 3 0 0 0 -2.5859 2.9688 3 3 0 0 0 3 3h8a3 3 0 0 0 3-3 3 3 0 0 0 -2.5898-2.9668 4.5 5 0 0 0 -4.4102-4.0332zm-4 11a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm8 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-4 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#a5b7f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a4.5 5 0 0 0 -4.4141 4.0312 3 3 0 0 0 -2.5859 2.9688 3 3 0 0 0 3 3h8a3 3 0 0 0 3-3 3 3 0 0 0 -2.5898-2.9668 4.5 5 0 0 0 -4.4102-4.0332zm-4 11a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm8 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-4 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/GPUParticles3D.svg b/editor/icons/GPUParticles3D.svg
index 25377f9f5f..bbc90ec35f 100644
--- a/editor/icons/GPUParticles3D.svg
+++ b/editor/icons/GPUParticles3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a4.5 5 0 0 0 -4.4141 4.0312 3 3 0 0 0 -2.5859 2.9688 3 3 0 0 0 3 3h8a3 3 0 0 0 3-3 3 3 0 0 0 -2.5898-2.9668 4.5 5 0 0 0 -4.4102-4.0332zm-4 11a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm8 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-4 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a4.5 5 0 0 0 -4.4141 4.0312 3 3 0 0 0 -2.5859 2.9688 3 3 0 0 0 3 3h8a3 3 0 0 0 3-3 3 3 0 0 0 -2.5898-2.9668 4.5 5 0 0 0 -4.4102-4.0332zm-4 11a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm8 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-4 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/GPUParticlesAttractorBox.svg b/editor/icons/GPUParticlesAttractorBox.svg
index 3c27b2d3cb..7a2ee7a6b9 100644
--- a/editor/icons/GPUParticlesAttractorBox.svg
+++ b/editor/icons/GPUParticlesAttractorBox.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#fc9c9c" fill-opacity=".996078" r="1"/><g fill="none" stroke="#fc9c9c" stroke-opacity=".996078"><ellipse cx="8" cy="-8" rx="2.339226" ry="4.949748" transform="rotate(90)"/><ellipse cx="8" cy="8" rx="2.339226" ry="4.949748"/><path d="m1.498906 1.498906h13.002189v13.002188h-13.002189z" stroke-width=".997813"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#fc7f7f" fill-opacity=".996078" r="1"/><g fill="none" stroke="#fc7f7f" stroke-opacity=".996078"><ellipse cx="8" cy="-8" rx="2.339226" ry="4.949748" transform="rotate(90)"/><ellipse cx="8" cy="8" rx="2.339226" ry="4.949748"/><path d="m1.498906 1.498906h13.002189v13.002188h-13.002189z" stroke-width=".997813"/></g></svg>
diff --git a/editor/icons/GPUParticlesAttractorSphere.svg b/editor/icons/GPUParticlesAttractorSphere.svg
index 5473a23854..2215331a18 100644
--- a/editor/icons/GPUParticlesAttractorSphere.svg
+++ b/editor/icons/GPUParticlesAttractorSphere.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="-8" cy="-7.999999" fill="none" rx="6.499003" ry="6.499001" stroke="#fc9c9c" stroke-opacity=".996078" stroke-width="1.002" transform="scale(-1)"/><circle cx="8" cy="8" fill="#fc9c9c" fill-opacity=".996078" r="1"/><g fill="none" stroke="#fc9c9c" stroke-opacity=".996078"><ellipse cx="11.313708" rx="2.339226" ry="4.949748" transform="matrix(.70710678 .70710678 -.70710678 .70710678 0 0)"/><ellipse cy="11.313708" rx="2.339226" ry="4.949748" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 0)"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="-8" cy="-7.999999" fill="none" rx="6.499003" ry="6.499001" stroke="#fc7f7f" stroke-opacity=".996078" stroke-width="1.002" transform="scale(-1)"/><circle cx="8" cy="8" fill="#fc7f7f" fill-opacity=".996078" r="1"/><g fill="none" stroke="#fc7f7f" stroke-opacity=".996078"><ellipse cx="11.313708" rx="2.339226" ry="4.949748" transform="matrix(.70710678 .70710678 -.70710678 .70710678 0 0)"/><ellipse cy="11.313708" rx="2.339226" ry="4.949748" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 0)"/></g></svg>
diff --git a/editor/icons/GPUParticlesAttractorVectorField.svg b/editor/icons/GPUParticlesAttractorVectorField.svg
index 93a29789e3..87b2b21804 100644
--- a/editor/icons/GPUParticlesAttractorVectorField.svg
+++ b/editor/icons/GPUParticlesAttractorVectorField.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="6.663637" cy="9.245457" fill="#fc9c9c" fill-opacity=".996078" rx="1.030661" ry=".998146"/><ellipse cx="-6.672815" cy="-9.387111" fill="none" rx="2.408711" ry="5.096776" stroke="#fc9c9c" stroke-opacity=".996078" stroke-width="1.0297" transform="matrix(-.99999945 .00104887 .00104887 -.99999945 0 0)"/><ellipse cx="9.387111" cy="-6.672815" fill="none" rx="2.408711" ry="5.096776" stroke="#fc9c9c" stroke-opacity=".996078" stroke-width="1.0297" transform="matrix(-.00104887 .99999945 -.99999945 .00104887 0 0)"/><g fill="#fc9c9c" fill-opacity=".996078"><path d="m11.8 15 2.4-2.4.8.8v-2.4h-2.4l.8.8-2.4 2.4z"/><path d="m11 6 3-3 1 1v-3h-3l1 1-3 3z"/><path d="m1.8 5 2.4-2.4.8.8v-2.4h-2.4l.8.8-2.4 2.4z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="6.663637" cy="9.245457" fill="#fc7f7f" fill-opacity=".996078" rx="1.030661" ry=".998146"/><ellipse cx="-6.672815" cy="-9.387111" fill="none" rx="2.408711" ry="5.096776" stroke="#fc7f7f" stroke-opacity=".996078" stroke-width="1.0297" transform="matrix(-.99999945 .00104887 .00104887 -.99999945 0 0)"/><ellipse cx="9.387111" cy="-6.672815" fill="none" rx="2.408711" ry="5.096776" stroke="#fc7f7f" stroke-opacity=".996078" stroke-width="1.0297" transform="matrix(-.00104887 .99999945 -.99999945 .00104887 0 0)"/><g fill="#fc7f7f" fill-opacity=".996078"><path d="m11.8 15 2.4-2.4.8.8v-2.4h-2.4l.8.8-2.4 2.4z"/><path d="m11 6 3-3 1 1v-3h-3l1 1-3 3z"/><path d="m1.8 5 2.4-2.4.8.8v-2.4h-2.4l.8.8-2.4 2.4z"/></g></svg>
diff --git a/editor/icons/GPUParticlesCollisionBox.svg b/editor/icons/GPUParticlesCollisionBox.svg
index f7296b34c3..4f7325d086 100644
--- a/editor/icons/GPUParticlesCollisionBox.svg
+++ b/editor/icons/GPUParticlesCollisionBox.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc9c9c" fill-opacity=".996078"><path d="m7.5 2.8124998-5.5883107 2.7941554v5.7660988l5.5883107 2.794155 5.588311-2.794155v-5.7660988zm0 1.6886278 3.145021 1.5732692-3.145021 1.5717523-3.1450214-1.5717523zm-3.9916505 2.8362274 3.1933204 1.5966602v3.1465378l-3.1933204-1.598256zm7.9833015 0v3.145021l-3.1933209 1.598257v-3.146538z" stroke-width=".851579"/><circle cx="1.875" cy="3.75" r=".9375"/><circle cx="13.124999" cy="3.75" r=".9375"/><circle cx="9.374999" cy="1.875" r=".9375"/><circle cx="5.625" cy="1.875" r=".9375"/></g></svg>
+<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f" fill-opacity=".996078"><path d="m7.5 2.8124998-5.5883107 2.7941554v5.7660988l5.5883107 2.794155 5.588311-2.794155v-5.7660988zm0 1.6886278 3.145021 1.5732692-3.145021 1.5717523-3.1450214-1.5717523zm-3.9916505 2.8362274 3.1933204 1.5966602v3.1465378l-3.1933204-1.598256zm7.9833015 0v3.145021l-3.1933209 1.598257v-3.146538z" stroke-width=".851579"/><circle cx="1.875" cy="3.75" r=".9375"/><circle cx="13.124999" cy="3.75" r=".9375"/><circle cx="9.374999" cy="1.875" r=".9375"/><circle cx="5.625" cy="1.875" r=".9375"/></g></svg>
diff --git a/editor/icons/GPUParticlesCollisionHeightField.svg b/editor/icons/GPUParticlesCollisionHeightField.svg
index b483f299e9..8bdc98a84b 100644
--- a/editor/icons/GPUParticlesCollisionHeightField.svg
+++ b/editor/icons/GPUParticlesCollisionHeightField.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc9c9c"><path d="m1 10c1-1 3-2 3-4s2-4 4-4 4 2 4 4 2 3 3 4l-7 5z"/><circle cx="2" cy="6" r="1"/><circle cx="14" cy="6" r="1"/><circle cx="12" cy="2" r="1"/><circle cx="4" cy="2" r="1"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><path d="m1 10c1-1 3-2 3-4s2-4 4-4 4 2 4 4 2 3 3 4l-7 5z"/><circle cx="2" cy="6" r="1"/><circle cx="14" cy="6" r="1"/><circle cx="12" cy="2" r="1"/><circle cx="4" cy="2" r="1"/></g></svg>
diff --git a/editor/icons/GPUParticlesCollisionSDF.svg b/editor/icons/GPUParticlesCollisionSDF.svg
index 6279990f3a..00eca8295d 100644
--- a/editor/icons/GPUParticlesCollisionSDF.svg
+++ b/editor/icons/GPUParticlesCollisionSDF.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 14h-12v-9s3 4 5.9999999 3.9999999c3.0000001-.0000001 6.0000001-3.9999999 6.0000001-3.9999999z" fill="none" stroke="#fc9c9c" stroke-linejoin="round" stroke-opacity=".996078" stroke-width="2"/><g fill="#fc9c9c" fill-opacity=".996078"><circle cx="2" cy="2" r="1"/><circle cx="14" cy="2" r="1"/><circle cx="10" cy="5" r="1"/><circle cx="6" cy="5" r="1"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 14h-12v-9s3 4 5.9999999 3.9999999c3.0000001-.0000001 6.0000001-3.9999999 6.0000001-3.9999999z" fill="none" stroke="#fc7f7f" stroke-linejoin="round" stroke-opacity=".996078" stroke-width="2"/><g fill="#fc7f7f" fill-opacity=".996078"><circle cx="2" cy="2" r="1"/><circle cx="14" cy="2" r="1"/><circle cx="10" cy="5" r="1"/><circle cx="6" cy="5" r="1"/></g></svg>
diff --git a/editor/icons/GPUParticlesCollisionSphere.svg b/editor/icons/GPUParticlesCollisionSphere.svg
index fc7715445c..cd188ddacc 100644
--- a/editor/icons/GPUParticlesCollisionSphere.svg
+++ b/editor/icons/GPUParticlesCollisionSphere.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc9c9c" fill-opacity=".996078"><path d="m8 3.0532484c-3.2888554 0-5.9733758 2.6845204-5.9733758 5.9733758 0 3.2889408 2.6845204 5.9733758 5.9733758 5.9733758 3.288855 0 5.973376-2.684435 5.973376-5.9733758 0-3.2888554-2.684521-5.9733758-5.973376-5.9733758zm-.8533394 1.79005v4.1567016c-1.1034532-.0608789-2.2238878-.2544573-3.3650586-.5900074.256693-1.7901354 1.6087154-3.2141029 3.3650586-3.5667027zm1.7066788 0c1.7535276.3520281 3.1035956 1.77213 3.3633516 3.55834-1.113266.3129793-2.2321649.5142138-3.3633516.5866709zm3.2300606 5.3599956c-.434043 1.51792-1.663927 2.690664-3.2300606 3.005035v-2.518376c1.0915918-.0617 2.1691036-.227875 3.2300606-.486668zm-8.161765.015c1.0865571.272147 2.162106.428504 3.2250256.480003v2.510013c-1.5608431-.313338-2.7870065-1.479605-3.2250256-2.990016z" stroke-width=".853339"/><circle cx="2" cy="5" r="1"/><circle cx="14" cy="5" r="1"/><circle cx="10" cy="2" r="1"/><circle cx="6" cy="2" r="1"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f" fill-opacity=".996078"><path d="m8 3.0532484c-3.2888554 0-5.9733758 2.6845204-5.9733758 5.9733758 0 3.2889408 2.6845204 5.9733758 5.9733758 5.9733758 3.288855 0 5.973376-2.684435 5.973376-5.9733758 0-3.2888554-2.684521-5.9733758-5.973376-5.9733758zm-.8533394 1.79005v4.1567016c-1.1034532-.0608789-2.2238878-.2544573-3.3650586-.5900074.256693-1.7901354 1.6087154-3.2141029 3.3650586-3.5667027zm1.7066788 0c1.7535276.3520281 3.1035956 1.77213 3.3633516 3.55834-1.113266.3129793-2.2321649.5142138-3.3633516.5866709zm3.2300606 5.3599956c-.434043 1.51792-1.663927 2.690664-3.2300606 3.005035v-2.518376c1.0915918-.0617 2.1691036-.227875 3.2300606-.486668zm-8.161765.015c1.0865571.272147 2.162106.428504 3.2250256.480003v2.510013c-1.5608431-.313338-2.7870065-1.479605-3.2250256-2.990016z" stroke-width=".853339"/><circle cx="2" cy="5" r="1"/><circle cx="14" cy="5" r="1"/><circle cx="10" cy="2" r="1"/><circle cx="6" cy="2" r="1"/></g></svg>
diff --git a/editor/icons/Generic6DOFJoint3D.svg b/editor/icons/Generic6DOFJoint3D.svg
index 63df5fc507..07918748e5 100644
--- a/editor/icons/Generic6DOFJoint3D.svg
+++ b/editor/icons/Generic6DOFJoint3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a1 1 0 0 0 -1 1v4.8828l-3.5527-1.7773a1 1 0 0 0 -.48438-.10352 1 1 0 0 0 -.85742.55078 1 1 0 0 0 .44727 1.3418l3.2109 1.6055-3.2109 1.6055a1 1 0 0 0 -.44727 1.3418 1 1 0 0 0 1.3418.44726l3.5527-1.7773v3.8828a1 1 0 0 0 1 1 1 1 0 0 0 1-1v-3.8828l3.5527 1.7773a1 1 0 0 0 1.3418-.44726 1 1 0 0 0 -.44726-1.3418l-3.2109-1.6055 3.2109-1.6055a1 1 0 0 0 .44726-1.3418 1 1 0 0 0 -.88672-.55273 1 1 0 0 0 -.45508.10547l-3.5527 1.7773v-4.8828a1 1 0 0 0 -1-1z" fill="#fc9c9c" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a1 1 0 0 0 -1 1v4.8828l-3.5527-1.7773a1 1 0 0 0 -.48438-.10352 1 1 0 0 0 -.85742.55078 1 1 0 0 0 .44727 1.3418l3.2109 1.6055-3.2109 1.6055a1 1 0 0 0 -.44727 1.3418 1 1 0 0 0 1.3418.44726l3.5527-1.7773v3.8828a1 1 0 0 0 1 1 1 1 0 0 0 1-1v-3.8828l3.5527 1.7773a1 1 0 0 0 1.3418-.44726 1 1 0 0 0 -.44726-1.3418l-3.2109-1.6055 3.2109-1.6055a1 1 0 0 0 .44726-1.3418 1 1 0 0 0 -.88672-.55273 1 1 0 0 0 -.45508.10547l-3.5527 1.7773v-4.8828a1 1 0 0 0 -1-1z" fill="#fc7f7f" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/Gradient.svg b/editor/icons/Gradient.svg
index 47dde294fc..99d3a871a6 100644
--- a/editor/icons/Gradient.svg
+++ b/editor/icons/Gradient.svg
@@ -1 +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="10" x2="10" y1="1" y2="15"><stop offset="0" stop-color="#e0e0e0"/><stop offset="1" stop-color="#e0e0e0" stop-opacity="0"/></linearGradient><path d="m2 1c-.55228 0-1 .44772-1 1v12c0 .55228.44772 1 1 1h12c.55228 0 1-.44772 1-1v-12c0-.55228-.44772-1-1-1z" fill="url(#a)"/></svg>
+<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 .8954299-2 1.9999999v10.0000001c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10.0000001c0-1.1046-.89543-1.9999999-2-1.9999999zm0 1.9999999h10v10.0000001h-10z"/><path d="m7.5 5.500001h1v1h-1z" stroke-width=".787342"/><path d="m3.5 3.5v9h3v-1h1v-1h-1v-1h1v-1h-1v-1h1v-1h-1v-1h1v-1h-1v-1z" stroke-width="4.09116"/><g stroke-width=".787342"><path d="m7.5 3.5h1v1h-1z"/><path d="m7.5 9.500001h1v1h-1z"/><path d="m7.5 7.500001h1v1h-1z"/><path d="m7.5 11.5h1v1h-1z"/><path d="m8.5 4.500001h1v1h-1z"/><path d="m8.5 6.500001h1v1h-1z"/><path d="m8.5 8.500002h1v1h-1z"/><path d="m8.5 10.500002h1v1h-1z"/></g></g></svg>
diff --git a/editor/icons/GradientTexture.svg b/editor/icons/GradientTexture.svg
index ec4c4546e1..fa03e69805 100644
--- a/editor/icons/GradientTexture.svg
+++ b/editor/icons/GradientTexture.svg
@@ -1 +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="10" x2="10" y1="1" y2="15"><stop offset="0" stop-color="#e0e0e0"/><stop offset="1" stop-color="#e0e0e0" stop-opacity="0"/></linearGradient><g transform="translate(0 -1036.4)"><path d="m2 1a1 1 0 0 0 -1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-12a1 1 0 0 0 -1-1zm1 2h10v8h-10z" fill="url(#a)" transform="translate(0 1036.4)"/><g fill="#e0e0e0"><path d="m6 1043.4h2v1h-2z"/><path d="m6 1044.4h2v2h-2z"/><path d="m4 1045.4h2v1h-2z"/><path d="m8 1044.4h2v2h-2z"/><path d="m10 1044.4h2v2h-2z"/><path d="m8 1042.4h3v2h-3z"/><path d="m9 1041.4h1v1h-1z"/><path d="m5 1044.4h1v1h-1z"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m12.5 10.5v-7h-3v1h-1v1h1v1h-1v1h1v1h-1v1h1v1zm-4-1h-1v1h1zm-1 0v-1h-1v1zm0-1h1v-1h-1zm0-1v-1h-1v1zm0-1h1v-1h-1zm0-1v-1h-1v1zm0-1h1v-1h-1z" stroke-width=".787342"/><path d="m2 1c-.552285 0-1 .4477153-1 1v12.000001c0 .552285.447715 1 1 1h11.999999c.552285 0 1-.447715 1-1v-12.000001c0-.5522847-.447715-1-1-1zm1 2.0000001h9.999999v8.0000009h-9.999999z" fill-opacity=".99608"/></g></svg>
diff --git a/editor/icons/GraphEdit.svg b/editor/icons/GraphEdit.svg
index b879259ffc..fbe7422f98 100644
--- a/editor/icons/GraphEdit.svg
+++ b/editor/icons/GraphEdit.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -1-1.7305v-5.8555l4.793 4.793 1.4141-1.4141-4.793-4.793h5.8574a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm10.656 6.9297-.70703.70703 1.4141 1.4141.70703-.70703zm-1.4141 1.4141-3.8887 3.8887-.35352 1.7676 1.7676-.35352 3.8887-3.8887-1.4141-1.4141z" fill="#a5efac" transform="translate(0 1036.4)"/><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -1-1.7305v-5.8555l4.793 4.793 1.4141-1.4141-4.793-4.793h5.8574a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm10.656 6.9297-.70703.70703 1.4141 1.4141.70703-.70703zm-1.4141 1.4141-3.8887 3.8887-.35352 1.7676 1.7676-.35352 3.8887-3.8887-1.4141-1.4141z" fill="#8eef97" transform="translate(0 1036.4)"/><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/></g></svg>
diff --git a/editor/icons/GraphNode.svg b/editor/icons/GraphNode.svg
index bcd7bfc1c1..061a81d951 100644
--- a/editor/icons/GraphNode.svg
+++ b/editor/icons/GraphNode.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -1-1.7305v-5.8555l4.0859 4.0859 1.4141-1.4141-4.0859-4.0859h5.8574a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm9.5 9a2.5 2.5 0 0 0 -2.5 2.5 2.5 2.5 0 0 0 2.5 2.5 2.5 2.5 0 0 0 2.5-2.5 2.5 2.5 0 0 0 -2.5-2.5z" fill="#a5efac" transform="translate(0 1036.4)"/><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -1-1.7305v-5.8555l4.0859 4.0859 1.4141-1.4141-4.0859-4.0859h5.8574a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm9.5 9a2.5 2.5 0 0 0 -2.5 2.5 2.5 2.5 0 0 0 2.5 2.5 2.5 2.5 0 0 0 2.5-2.5 2.5 2.5 0 0 0 -2.5-2.5z" fill="#8eef97" transform="translate(0 1036.4)"/><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/></g></svg>
diff --git a/editor/icons/Grid.svg b/editor/icons/Grid.svg
index 8353ad7d19..3b63bfb051 100644
--- a/editor/icons/Grid.svg
+++ b/editor/icons/Grid.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 10 2h2 12v-2-12h-12zm2 2h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm-8 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm-8 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2z" fill="#a5b7f3" fill-opacity=".98824"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h14v-14zm1.9999999 2h2v2h-2zm4 0h2v2h-2zm4.0000001 0h2v2h-2zm-8.0000001 4.0000004h2v2h-2zm4 0h2v2h-2zm4.0000001 0h2v2h-2zm-8.0000001 3.9999996h2v2h-2zm4 0h2v2h-2zm4.0000001 0h2v2h-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/GridContainer.svg b/editor/icons/GridContainer.svg
index fb6207d94b..94a312bc36 100644
--- a/editor/icons/GridContainer.svg
+++ b/editor/icons/GridContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm-8 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm-8 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm-8 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm-8 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/GrooveJoint2D.svg b/editor/icons/GrooveJoint2D.svg
index 41cf64ad66..0f7b84096c 100644
--- a/editor/icons/GrooveJoint2D.svg
+++ b/editor/icons/GrooveJoint2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 1037.4h-5v6h-5v2h5v6h5zm-7 0h-7v14h7v-4h-5v-6h5z" fill="#a5b7f3" fill-opacity=".98824" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 1037.4h-5v6h-5v2h5v6h5zm-7 0h-7v14h7v-4h-5v-6h5z" fill="#8da5f3" fill-opacity=".98824" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/GuiChecked.svg b/editor/icons/GuiChecked.svg
index 9bdf5dcb19..31b2995939 100644
--- a/editor/icons/GuiChecked.svg
+++ b/editor/icons/GuiChecked.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m3.3333333 1c-1.2887 0-2.3333333 1.0446683-2.3333333 2.3333333v9.3333337c0 1.2887 1.0446683 2.333333 2.3333333 2.333333h9.3333337c1.2887 0 2.333333-1.044668 2.333333-2.333333v-9.3333337c0-1.2887-1.044668-2.3333333-2.333333-2.3333333z" fill-opacity=".188235" stroke-width="1.166667"/><path d="m11.500773 3.7343508-5.6117507 5.6117502-1.7045017-1.6814543-1.4992276 1.4992276 3.2037293 3.1806817 7.1109777-7.1109775z" stroke-width="1.060227"/></g></svg>
+<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.3333333 1c-1.2887 0-2.3333333 1.0446683-2.3333333 2.3333333v9.3333337c0 1.2887 1.0446683 2.333333 2.3333333 2.333333h9.3333337c1.2887 0 2.333333-1.044668 2.333333-2.333333v-9.3333337c0-1.2887-1.044668-2.3333333-2.333333-2.3333333z" fill="#699ce8" stroke-width="1.16667"/><path d="m11.500773 3.7343508-5.6117507 5.6117502-1.7045017-1.6814543-1.4992276 1.4992276 3.2037293 3.1806817 7.1109777-7.1109775z" fill="#fff" stroke-width="1.06023"/></svg>
diff --git a/editor/icons/GuiRadioChecked.svg b/editor/icons/GuiRadioChecked.svg
index 771337116d..65ef086c9a 100644
--- a/editor/icons/GuiRadioChecked.svg
+++ b/editor/icons/GuiRadioChecked.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m15 8a7 7 0 0 1 -7 7 7 7 0 0 1 -7-7 7 7 0 0 1 7-7 7 7 0 0 1 7 7" fill-opacity=".188235" stroke-width="2.333333"/><path d="m12 8a4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4 4 4 0 0 1 4 4" stroke-width="1.333333"/></g></svg>
+<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8a7 7 0 0 1 -7 7 7 7 0 0 1 -7-7 7 7 0 0 1 7-7 7 7 0 0 1 7 7" fill="#699ce8" stroke-width="2.33333"/><path d="m12 8a4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4 4 4 0 0 1 4 4" fill="#fff" stroke-width="1.33333"/></svg>
diff --git a/editor/icons/HBoxContainer.svg b/editor/icons/HBoxContainer.svg
index 791fca0ebc..8fbeef525c 100644
--- a/editor/icons/HBoxContainer.svg
+++ b/editor/icons/HBoxContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h2v10h-2zm4 0h2v10h-2zm4 0h2v10h-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h2v10h-2zm4 0h2v10h-2zm4 0h2v10h-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/HScrollBar.svg b/editor/icons/HScrollBar.svg
index 5828ccb388..3b42eb94c9 100644
--- a/editor/icons/HScrollBar.svg
+++ b/editor/icons/HScrollBar.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 1041.4c0-1.108-.892-2-2-2h-10c-1.108 0-2 .892-2 2v6c0 1.108.892 2 2 2h10c1.108 0 2-.892 2-2zm-1 2.9883a1.0001 1.0001 0 0 1 -.168.5664l-2 3a1.0001 1.0001 0 1 1 -1.664-1.1094l1.6289-2.4453-1.6289-2.4453a1.0001 1.0001 0 1 1 1.664-1.1094l2 3a1.0001 1.0001 0 0 1 .168.543zm-7.9922-2.9981a1.0001 1.0001 0 0 1 -.1758.5645l-1.6308 2.4453 1.6308 2.4453a1.0001 1.0001 0 1 1 -1.664 1.1094l-2-3a1.0001 1.0001 0 0 1 0-1.1094l2-3a1.0001 1.0001 0 0 1 1.8398.5449z" fill="#a5efac" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 1041.4c0-1.108-.892-2-2-2h-10c-1.108 0-2 .892-2 2v6c0 1.108.892 2 2 2h10c1.108 0 2-.892 2-2zm-1 2.9883a1.0001 1.0001 0 0 1 -.168.5664l-2 3a1.0001 1.0001 0 1 1 -1.664-1.1094l1.6289-2.4453-1.6289-2.4453a1.0001 1.0001 0 1 1 1.664-1.1094l2 3a1.0001 1.0001 0 0 1 .168.543zm-7.9922-2.9981a1.0001 1.0001 0 0 1 -.1758.5645l-1.6308 2.4453 1.6308 2.4453a1.0001 1.0001 0 1 1 -1.664 1.1094l-2-3a1.0001 1.0001 0 0 1 0-1.1094l2-3a1.0001 1.0001 0 0 1 1.8398.5449z" fill="#8eef97" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/HSeparator.svg b/editor/icons/HSeparator.svg
index d786767be8..c47b126778 100644
--- a/editor/icons/HSeparator.svg
+++ b/editor/icons/HSeparator.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 2v3h6v-3zm-4 5v2h14v-2zm4 4v3h6v-3z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 2v3h6v-3zm-4 5v2h14v-2zm4 4v3h6v-3z" fill="#8eef97"/></svg>
diff --git a/editor/icons/HSlider.svg b/editor/icons/HSlider.svg
index 0ab453bbce..c876afa843 100644
--- a/editor/icons/HSlider.svg
+++ b/editor/icons/HSlider.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 3c-.55228 0-1 .44772-1 1v2c0 .55228.44772 1 1 1s1-.44772 1-1v-2c0-.55228-.44772-1-1-1zm12 0c-.55228 0-1 .44772-1 1v2c0 .55228.44772 1 1 1s1-.44772 1-1v-2c0-.55228-.44772-1-1-1zm-6 1c-.55228 0-1 .44772-1 1s.44772 1 1 1 1-.44772 1-1-.44772-1-1-1zm5 5c-1.1046 0-2 .89543-2 2 0 1.1046.89543 2 2 2 1.0099-.000337 1.8611-.75351 1.9844-1.7559.04003-.16104.03936-.32952-.002-.49024-.12404-1.0008-.97388-1.7527-1.9824-1.7539zm-11 1c-1.3523-.019125-1.3523 2.0191 0 2h7.1309c-.085635-.32648-.1296-.66248-.13086-1 .00189-.3376.046518-.67361.13281-1z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 3c-.55228 0-1 .44772-1 1v2c0 .55228.44772 1 1 1s1-.44772 1-1v-2c0-.55228-.44772-1-1-1zm12 0c-.55228 0-1 .44772-1 1v2c0 .55228.44772 1 1 1s1-.44772 1-1v-2c0-.55228-.44772-1-1-1zm-6 1c-.55228 0-1 .44772-1 1s.44772 1 1 1 1-.44772 1-1-.44772-1-1-1zm5 5c-1.1046 0-2 .89543-2 2 0 1.1046.89543 2 2 2 1.0099-.000337 1.8611-.75351 1.9844-1.7559.04003-.16104.03936-.32952-.002-.49024-.12404-1.0008-.97388-1.7527-1.9824-1.7539zm-11 1c-1.3523-.019125-1.3523 2.0191 0 2h7.1309c-.085635-.32648-.1296-.66248-.13086-1 .00189-.3376.046518-.67361.13281-1z" fill="#8eef97"/></svg>
diff --git a/editor/icons/HSplitContainer.svg b/editor/icons/HSplitContainer.svg
index 796e331ef5..4cf32d00ff 100644
--- a/editor/icons/HSplitContainer.svg
+++ b/editor/icons/HSplitContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h4v3l-2 2 2 2v3h-4zm6 0h4v10h-4v-3l2-2-2-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h4v3l-2 2 2 2v3h-4zm6 0h4v10h-4v-3l2-2-2-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/Heart.svg b/editor/icons/Heart.svg
new file mode 100644
index 0000000000..4f46908760
--- /dev/null
+++ b/editor/icons/Heart.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 14c-.1249999 0-.25-.046875-.34375-.140625l-4.875-4.703125c-.0625-.054687-1.7812496-1.6249999-1.7812496-3.5 0-2.2890626 1.3984372-3.6562499 3.7343748-3.6562499 1.3671873 0 2.6484373 1.390625 3.2656248 1.9999999.6171875-.6093749 1.8984375-1.9999999 3.265625-1.9999999 2.335938 0 3.734375 1.3671873 3.734375 3.6562499 0 1.8750001-1.71875 3.4453125-1.789062 3.5156251l-4.867188 4.6874999c-.09375.09375-.2187499.140625-.34375.140625z" fill="#ff7070"/></svg>
diff --git a/editor/icons/HingeJoint3D.svg b/editor/icons/HingeJoint3D.svg
index ca97169d82..a37377905d 100644
--- a/editor/icons/HingeJoint3D.svg
+++ b/editor/icons/HingeJoint3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.2832 1.3281a1.0001 1.0001 0 0 0 -.88086.51172l-3.6895 6.3906c.40599-.13877.83411-.23047 1.2871-.23047.37043 0 .72206.067873 1.0625.16211l3.0723-5.3223a1.0001 1.0001 0 0 0 -.85156-1.5117zm-3.2832 7.6719a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h10a1 1 0 0 0 1-1 1 1 0 0 0 -1-1h-7.1738a3 3 0 0 0 .17383-1 3 3 0 0 0 -3-3zm0 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.2832 1.3281a1.0001 1.0001 0 0 0 -.88086.51172l-3.6895 6.3906c.40599-.13877.83411-.23047 1.2871-.23047.37043 0 .72206.067873 1.0625.16211l3.0723-5.3223a1.0001 1.0001 0 0 0 -.85156-1.5117zm-3.2832 7.6719a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h10a1 1 0 0 0 1-1 1 1 0 0 0 -1-1h-7.1738a3 3 0 0 0 .17383-1 3 3 0 0 0 -3-3zm0 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/ImmediateGeometry3D.svg b/editor/icons/ImmediateGeometry3D.svg
index 876d752ced..ec5a392a68 100644
--- a/editor/icons/ImmediateGeometry3D.svg
+++ b/editor/icons/ImmediateGeometry3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.9208 1046.4c-.26373.3-.4204.7296-.4204 1.2383 0 1.6277-3.1381-.1781-.33757 2.6703.88382.899 2.6544.6701 3.5382-.2288.88384-.899.88382-2.3565 0-3.2554-1.1002-1.1191-2.2001-1.0845-2.7803-.4244zm2.3802-1.6103 2.4005 2.4416 6.8014-6.9177c.66286-.6742.66286-1.7673 0-2.4415-.66288-.6741-1.7376-.6741-2.4005 0z" fill="#fc9c9c" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2.9208 1046.4c-.26373.3-.4204.7296-.4204 1.2383 0 1.6277-3.1381-.1781-.33757 2.6703.88382.899 2.6544.6701 3.5382-.2288.88384-.899.88382-2.3565 0-3.2554-1.1002-1.1191-2.2001-1.0845-2.7803-.4244zm2.3802-1.6103 2.4005 2.4416 6.8014-6.9177c.66286-.6742.66286-1.7673 0-2.4415-.66288-.6741-1.7376-.6741-2.4005 0z" fill="#fc7f7f" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/InsertAfter.svg b/editor/icons/InsertAfter.svg
index b75df837bd..d7fc9c67c0 100644
--- a/editor/icons/InsertAfter.svg
+++ b/editor/icons/InsertAfter.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="12" fill="none" r="2"/><path d="m11.99.99023a1.0001 1.0001 0 0 0 -.69726 1.7168l.29297.29297h-2.5859v2h2.5859l-.29297.29297a1.0001 1.0001 0 1 0 1.4141 1.4141l2-2a1.0001 1.0001 0 0 0 0-1.4141l-2-2a1.0001 1.0001 0 0 0 -.7168-.30273zm-8.9902.0097656c-1.108 0-2 .892-2 2v2c0 1.108.892 2 2 2h2c1.108 0 2-.892 2-2v-2c0-1.108-.892-2-2-2z" fill="#e0e0e0"/><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#84ffb1"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="12" fill="none" r="2"/><path d="m11.99.99023a1.0001 1.0001 0 0 0 -.69726 1.7168l.29297.29297h-2.5859v2h2.5859l-.29297.29297a1.0001 1.0001 0 1 0 1.4141 1.4141l2-2a1.0001 1.0001 0 0 0 0-1.4141l-2-2a1.0001 1.0001 0 0 0 -.7168-.30273zm-8.9902.0097656c-1.108 0-2 .892-2 2v2c0 1.108.892 2 2 2h2c1.108 0 2-.892 2-2v-2c0-1.108-.892-2-2-2z" fill="#e0e0e0"/><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#5fff97"/></svg>
diff --git a/editor/icons/InsertBefore.svg b/editor/icons/InsertBefore.svg
index 44c876fc76..ee62b28380 100644
--- a/editor/icons/InsertBefore.svg
+++ b/editor/icons/InsertBefore.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="12" fill="none" r="2"/><path d="m4.0096.99023a1.0001 1.0001 0 0 1 .69726 1.7168l-.29297.29297h2.5859v2h-2.5859l.29297.29297a1.0001 1.0001 0 1 1 -1.4141 1.4141l-2-2a1.0001 1.0001 0 0 1 0-1.4141l2-2a1.0001 1.0001 0 0 1 .7168-.30273zm8.9902.0097656c1.108 0 2 .892 2 2v2c0 1.108-.892 2-2 2h-2c-1.108 0-2-.892-2-2v-2c0-1.108.892-2 2-2z" fill="#e0e0e0"/><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#84ffb1"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="12" fill="none" r="2"/><path d="m4.0096.99023a1.0001 1.0001 0 0 1 .69726 1.7168l-.29297.29297h2.5859v2h-2.5859l.29297.29297a1.0001 1.0001 0 1 1 -1.4141 1.4141l-2-2a1.0001 1.0001 0 0 1 0-1.4141l2-2a1.0001 1.0001 0 0 1 .7168-.30273zm8.9902.0097656c1.108 0 2 .892 2 2v2c0 1.108-.892 2-2 2h-2c-1.108 0-2-.892-2-2v-2c0-1.108.892-2 2-2z" fill="#e0e0e0"/><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#5fff97"/></svg>
diff --git a/editor/icons/InverseKinematics.svg b/editor/icons/InverseKinematics.svg
index e4a076fbbd..4c6dbd4546 100644
--- a/editor/icons/InverseKinematics.svg
+++ b/editor/icons/InverseKinematics.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v10.27h2v-10.271a2 2 0 0 0 .73047-.72852h4.541a2 2 0 0 0 .72852.73047v3.2695h-2v2l-1 2 3 2v-4h2v4l3-2-1-2v-2h-2v-3.2715a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-4.541a2 2 0 0 0 -1.7285-1z" fill="#fc9c9c" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v10.27h2v-10.271a2 2 0 0 0 .73047-.72852h4.541a2 2 0 0 0 .72852.73047v3.2695h-2v2l-1 2 3 2v-4h2v4l3-2-1-2v-2h-2v-3.2715a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-4.541a2 2 0 0 0 -1.7285-1z" fill="#fc7f7f" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/ItemList.svg b/editor/icons/ItemList.svg
index fb98a706a9..efa753fdb6 100644
--- a/editor/icons/ItemList.svg
+++ b/editor/icons/ItemList.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm1 1v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-6 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-6 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm1 1v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-6 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-6 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/KeyAnimation.svg b/editor/icons/KeyAnimation.svg
index 5afd5bdb70..24a1e84da2 100644
--- a/editor/icons/KeyAnimation.svg
+++ b/editor/icons/KeyAnimation.svg
@@ -1 +1 @@
-<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#b76ef0" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#a448f0" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
diff --git a/editor/icons/KeyAudio.svg b/editor/icons/KeyAudio.svg
index e1a93529a6..18caa7afe2 100644
--- a/editor/icons/KeyAudio.svg
+++ b/editor/icons/KeyAudio.svg
@@ -1 +1 @@
-<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#eae668" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#eae440" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
diff --git a/editor/icons/KeyBezier.svg b/editor/icons/KeyBezier.svg
index cd41f953b1..7bbdd8dbab 100644
--- a/editor/icons/KeyBezier.svg
+++ b/editor/icons/KeyBezier.svg
@@ -1 +1 @@
-<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#5792f6" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#2877f6" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
diff --git a/editor/icons/KeyBezierSelected.svg b/editor/icons/KeyBezierSelected.svg
index e8536e97b4..741f9bea60 100644
--- a/editor/icons/KeyBezierSelected.svg
+++ b/editor/icons/KeyBezierSelected.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg"><rect fill="#84c2ff" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1044.4)" width="6.1027" x="-741.53" y="741.08"/></svg>
+<svg height="8" viewBox="0 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg"><rect fill="#5fb2ff" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1044.4)" width="6.1027" x="-741.53" y="741.08"/></svg>
diff --git a/editor/icons/KeyCall.svg b/editor/icons/KeyCall.svg
index dd47272d4f..5ffbceeb09 100644
--- a/editor/icons/KeyCall.svg
+++ b/editor/icons/KeyCall.svg
@@ -1 +1 @@
-<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#66f376" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#3cf34e" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
diff --git a/editor/icons/KeyNext.svg b/editor/icons/KeyNext.svg
index a2b616072b..83a8329494 100644
--- a/editor/icons/KeyNext.svg
+++ b/editor/icons/KeyNext.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#84ffb1"/><path d="m11 1a4 4 0 0 0 -3.8691 3h-6.1309v2h1v2h3v-2h2.1328a4 4 0 0 0 2.8672 2.8691v-.86914h3.6387a4 4 0 0 0 1.3613-3 4 4 0 0 0 -4-4zm0 2a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#5fff97"/><path d="m11 1a4 4 0 0 0 -3.8691 3h-6.1309v2h1v2h3v-2h2.1328a4 4 0 0 0 2.8672 2.8691v-.86914h3.6387a4 4 0 0 0 1.3613-3 4 4 0 0 0 -4-4zm0 2a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/KeySelected.svg b/editor/icons/KeySelected.svg
index 32f900bdd6..aff66b9a27 100644
--- a/editor/icons/KeySelected.svg
+++ b/editor/icons/KeySelected.svg
@@ -1 +1 @@
-<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#84c2ff" height="6.1027" ry=".76286" transform="matrix(.87871827 -.87871827 .87871827 .87871827 .03288 -1297.7965)" width="6.1027" x="-741.53003" y="741.08002"/><rect fill="#003e7a" height="3.434683" ry=".429348" stroke-width=".562814" transform="matrix(.89137101 -.86588067 .89137101 .86588067 -.038545 -1297.8361)" width="3.434683" x="-751.20953" y="753.42743"/></svg>
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#5fb2ff" height="6.1027" ry=".76286" transform="matrix(.87871827 -.87871827 .87871827 .87871827 .03288 -1297.7965)" width="6.1027" x="-741.53003" y="741.08002"/><rect fill="#003e7a" height="3.434683" ry=".429348" stroke-width=".562814" transform="matrix(.89137101 -.86588067 .89137101 .86588067 -.038545 -1297.8361)" width="3.434683" x="-751.20953" y="753.42743"/></svg>
diff --git a/editor/icons/KeyXform.svg b/editor/icons/KeyXform.svg
index 12f27d32a9..59c14cd820 100644
--- a/editor/icons/KeyXform.svg
+++ b/editor/icons/KeyXform.svg
@@ -1 +1 @@
-<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#ea9568" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
+<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#ea7940" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>
diff --git a/editor/icons/Label.svg b/editor/icons/Label.svg
index bfb1c903f3..f7a6fb3a9e 100644
--- a/editor/icons/Label.svg
+++ b/editor/icons/Label.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 3a1.0001 1.0001 0 0 0 -.70703.29297l-4 4a1.0001 1.0001 0 0 0 0 1.4141l4 4a1.0001 1.0001 0 0 0 .70703.29297h8a1.0001 1.0001 0 0 0 1-1v-8a1.0001 1.0001 0 0 0 -1-1h-8zm-1 4a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#a5efac" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 3a1.0001 1.0001 0 0 0 -.70703.29297l-4 4a1.0001 1.0001 0 0 0 0 1.4141l4 4a1.0001 1.0001 0 0 0 .70703.29297h8a1.0001 1.0001 0 0 0 1-1v-8a1.0001 1.0001 0 0 0 -1-1h-8zm-1 4a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#8eef97" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/LargeTexture.svg b/editor/icons/LargeTexture.svg
deleted file mode 100644
index 137a761e1d..0000000000
--- a/editor/icons/LargeTexture.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v1 2h1v-2h2v-1zm11 0v1h2v2h1v-3zm-3 5v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-1-1h-1v-1zm-8 6v2 1h3v-1h-2v-2zm13 0v2h-2v1h3v-1-2z" fill="#e0e0e0" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/LightOccluder2D.svg b/editor/icons/LightOccluder2D.svg
index 8c5bb89218..ff2c4d4561 100644
--- a/editor/icons/LightOccluder2D.svg
+++ b/editor/icons/LightOccluder2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1037.4c-2.7614 0-5 2.2386-5 5 .00253 1.9858 1.18 3.7819 3 4.5762v2.4238h4v-2.4199c1.8213-.7949 2.999-2.5929 3-4.5801 0-2.7614-2.2386-5-5-5zm0 2v6c-1.6569 0-3-1.3431-3-3s1.3431-3 3-3zm-1 11v1h2v-1z" fill="#a5b7f3" fill-opacity=".98824" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1037.4c-2.7614 0-5 2.2386-5 5 .00253 1.9858 1.18 3.7819 3 4.5762v2.4238h4v-2.4199c1.8213-.7949 2.999-2.5929 3-4.5801 0-2.7614-2.2386-5-5-5zm0 2v6c-1.6569 0-3-1.3431-3-3s1.3431-3 3-3zm-1 11v1h2v-1z" fill="#8da5f3" fill-opacity=".98824" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/BakedLightmap.svg b/editor/icons/LightmapGI.svg
index ea9efa55ba..78f0a64a7b 100644
--- a/editor/icons/BakedLightmap.svg
+++ b/editor/icons/LightmapGI.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1v2h12v-2zm-1 3v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-9zm2 1h1v1h-1zm3 0h1v1h-1zm3 0h1v1h-1zm3 0h1v1h-1zm-9 2h10v6h-10zm3 1v1h4v-1z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1v2h12v-2zm-1 3v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-9zm2 1h1v1h-1zm3 0h1v1h-1zm3 0h1v1h-1zm3 0h1v1h-1zm-9 2h10v6h-10zm3 1v1h4v-1z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/BakedLightmapData.svg b/editor/icons/LightmapGIData.svg
index f5dcfb618b..f5dcfb618b 100644
--- a/editor/icons/BakedLightmapData.svg
+++ b/editor/icons/LightmapGIData.svg
diff --git a/editor/icons/LightmapProbe.svg b/editor/icons/LightmapProbe.svg
index bc790d50c1..07f2b41a7c 100644
--- a/editor/icons/LightmapProbe.svg
+++ b/editor/icons/LightmapProbe.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 9h3v-2h-3zm2.050781 2.535156 1.414063 1.414063 1.414062-1.414063-1.414062-1.414062zm0-7.070312 1.414063 1.414062 1.414062-1.414062-1.414062-1.414063zm1.949219 3.535156c0 1.6569 1.3432 3 3 3s3-1.3431 3-3-1.3432-3-3-3-3 1.3431-3 3zm3 7c3.865993 0 7-3.134007 7-7s-3.134007-7-7-7v2.333984c2.577329 0 4.666016 2.088687 4.666016 4.666016s-2.088687 4.666016-4.666016 4.666016z" fill="#fc9c9c" fill-opacity=".996078" stroke-width="1.16667"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 9h3v-2h-3zm2.050781 2.535156 1.414063 1.414063 1.414062-1.414063-1.414062-1.414062zm0-7.070312 1.414063 1.414062 1.414062-1.414062-1.414062-1.414063zm1.949219 3.535156c0 1.6569 1.3432 3 3 3s3-1.3431 3-3-1.3432-3-3-3-3 1.3431-3 3zm3 7c3.865993 0 7-3.134007 7-7s-3.134007-7-7-7v2.333984c2.577329 0 4.666016 2.088687 4.666016 4.666016s-2.088687 4.666016-4.666016 4.666016z" fill="#fc7f7f" fill-opacity=".996078" stroke-width="1.16667"/></svg>
diff --git a/editor/icons/Line2D.svg b/editor/icons/Line2D.svg
index a0f9d1e33c..e9e70af5c7 100644
--- a/editor/icons/Line2D.svg
+++ b/editor/icons/Line2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1045.4 3 4 3-10 3 6 3-2" fill="none" stroke="#a5b7f3" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1045.4 3 4 3-10 3 6 3-2" fill="none" stroke="#8da5f3" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/LineEdit.svg b/editor/icons/LineEdit.svg
index 54e3190259..168836a432 100644
--- a/editor/icons/LineEdit.svg
+++ b/editor/icons/LineEdit.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 4v5h2v-5zm-1 7c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2h-2-10z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 4v5h2v-5zm-1 7c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2h-2-10z" fill="#8eef97"/></svg>
diff --git a/editor/icons/LinkButton.svg b/editor/icons/LinkButton.svg
index 3a99d241c3..a3d29e82e8 100644
--- a/editor/icons/LinkButton.svg
+++ b/editor/icons/LinkButton.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 3a5 5 0 0 0 -4.3301 2.5 5 5 0 0 0 0 5 5 5 0 0 0 4.3301 2.5h1v-2h-1a3 3 0 0 1 -3-3 3 3 0 0 1 3-3h1v-2zm3 0v2h1a3 3 0 0 1 3 3 3 3 0 0 1 -3 3h-1v2h1a5 5 0 0 0 4.3301-2.5 5 5 0 0 0 0-5 5 5 0 0 0 -4.3301-2.5zm-3 4a.99998.99998 0 0 0 -1 1 .99998.99998 0 0 0 1 1h4a.99998.99998 0 0 0 1-1 .99998.99998 0 0 0 -1-1z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 3a5 5 0 0 0 -4.3301 2.5 5 5 0 0 0 0 5 5 5 0 0 0 4.3301 2.5h1v-2h-1a3 3 0 0 1 -3-3 3 3 0 0 1 3-3h1v-2zm3 0v2h1a3 3 0 0 1 3 3 3 3 0 0 1 -3 3h-1v2h1a5 5 0 0 0 4.3301-2.5 5 5 0 0 0 0-5 5 5 0 0 0 -4.3301-2.5zm-3 4a.99998.99998 0 0 0 -1 1 .99998.99998 0 0 0 1 1h4a.99998.99998 0 0 0 1-1 .99998.99998 0 0 0 -1-1z" fill="#8eef97"/></svg>
diff --git a/editor/icons/Listener3D.svg b/editor/icons/Listener3D.svg
index 7afbdccd43..c068474d17 100644
--- a/editor/icons/Listener3D.svg
+++ b/editor/icons/Listener3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a5 5 0 0 0 -5 5h2a3 3 0 0 1 3-3 3 3 0 0 1 3 3c0 1.75-.54175 2.3583-1.1406 2.8574-.29944.2495-.62954.44071-.97656.69141-.17351.1253-.35729.26529-.53711.49219-.17982.227-.3457.58398-.3457.95898 0 1.2778-.31632 1.5742-.63867 1.7676-.32236.1934-.86133.23242-1.3613.23242h-1v2h1c.5 0 1.461.038922 2.3887-.51758.87316-.5239 1.4826-1.6633 1.5566-3.2266.011365-.0098.027247-.024684.10938-.083984.21547-.1556.63537-.40194 1.0859-.77734.90112-.751 1.8594-2.1445 1.8594-4.3945a5 5 0 0 0 -5-5zm7.9277 1-1.7383 1.0039a6 6 0 0 1 .81055 2.9961 6 6 0 0 1 -.80859 2.998l1.7363 1.002a8 8 0 0 0 0-8z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a5 5 0 0 0 -5 5h2a3 3 0 0 1 3-3 3 3 0 0 1 3 3c0 1.75-.54175 2.3583-1.1406 2.8574-.29944.2495-.62954.44071-.97656.69141-.17351.1253-.35729.26529-.53711.49219-.17982.227-.3457.58398-.3457.95898 0 1.2778-.31632 1.5742-.63867 1.7676-.32236.1934-.86133.23242-1.3613.23242h-1v2h1c.5 0 1.461.038922 2.3887-.51758.87316-.5239 1.4826-1.6633 1.5566-3.2266.011365-.0098.027247-.024684.10938-.083984.21547-.1556.63537-.40194 1.0859-.77734.90112-.751 1.8594-2.1445 1.8594-4.3945a5 5 0 0 0 -5-5zm7.9277 1-1.7383 1.0039a6 6 0 0 1 .81055 2.9961 6 6 0 0 1 -.80859 2.998l1.7363 1.002a8 8 0 0 0 0-8z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/MarginContainer.svg b/editor/icons/MarginContainer.svg
index 82e72c0da9..6c6f1271d1 100644
--- a/editor/icons/MarginContainer.svg
+++ b/editor/icons/MarginContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#a5efac" transform="translate(0 -1036.4)"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10z" transform="translate(0 1036.4)"/><path d="m4 1042.4v4l2-2z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#8eef97" transform="translate(0 -1036.4)"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10z" transform="translate(0 1036.4)"/><path d="m4 1042.4v4l2-2z"/></g></svg>
diff --git a/editor/icons/MenuButton.svg b/editor/icons/MenuButton.svg
index ca129baced..cb1d9e8382 100644
--- a/editor/icons/MenuButton.svg
+++ b/editor/icons/MenuButton.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h14v-4zm5 1h4l-2 2zm-4 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>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h14v-4zm5 1h4l-2 2zm-4 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="#8eef97"/></svg>
diff --git a/editor/icons/Mesh.svg b/editor/icons/Mesh.svg
index c02d5d0613..a1743e4c58 100644
--- a/editor/icons/Mesh.svg
+++ b/editor/icons/Mesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h6.541a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.0312-1.75h.03125v-6.5215a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm2.4141 3h5.8574a2 2 0 0 0 .72852.73047v5.8555l-6.5859-6.5859zm-1.4141 1.4141 6.5859 6.5859h-5.8574a2 2 0 0 0 -.72852-.73047v-5.8555z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h6.541a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.0312-1.75h.03125v-6.5215a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm2.4141 3h5.8574a2 2 0 0 0 .72852.73047v5.8555l-6.5859-6.5859zm-1.4141 1.4141 6.5859 6.5859h-5.8574a2 2 0 0 0 -.72852-.73047v-5.8555z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/MeshInstance2D.svg b/editor/icons/MeshInstance2D.svg
index b8df0768d2..8f6de06252 100644
--- a/editor/icons/MeshInstance2D.svg
+++ b/editor/icons/MeshInstance2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h6.541a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.0312-1.75h.03125v-6.5215a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm2.4141 3h5.8574a2 2 0 0 0 .72852.73047v5.8555l-6.5859-6.5859zm-1.4141 1.4141 6.5859 6.5859h-5.8574a2 2 0 0 0 -.72852-.73047v-5.8555z" fill="#a5b7f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h6.541a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.0312-1.75h.03125v-6.5215a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm2.4141 3h5.8574a2 2 0 0 0 .72852.73047v5.8555l-6.5859-6.5859zm-1.4141 1.4141 6.5859 6.5859h-5.8574a2 2 0 0 0 -.72852-.73047v-5.8555z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/MeshInstance3D.svg b/editor/icons/MeshInstance3D.svg
index aa0cf7740b..a9258505f8 100644
--- a/editor/icons/MeshInstance3D.svg
+++ b/editor/icons/MeshInstance3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h6.541a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.0312-1.75h.03125v-6.5215a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm2.4141 3h5.8574a2 2 0 0 0 .72852.73047v5.8555l-6.5859-6.5859zm-1.4141 1.4141 6.5859 6.5859h-5.8574a2 2 0 0 0 -.72852-.73047v-5.8555z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h6.541a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.0312-1.75h.03125v-6.5215a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm2.4141 3h5.8574a2 2 0 0 0 .72852.73047v5.8555l-6.5859-6.5859zm-1.4141 1.4141 6.5859 6.5859h-5.8574a2 2 0 0 0 -.72852-.73047v-5.8555z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/MeshLibrary.svg b/editor/icons/MeshLibrary.svg
index 6e824af177..5d64acd97e 100644
--- a/editor/icons/MeshLibrary.svg
+++ b/editor/icons/MeshLibrary.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h2.2695v-2h-2.2715a2 2 0 0 0 -.72852-.73047v-5.8555l3 3v-.41406a2.0002 2.0002 0 0 1 .80859-1.6055l-2.3945-2.3945h5.8574a2 2 0 0 0 .72852.73047v1.2695a2.0002 2.0002 0 0 1 .99805.27148 2.0002 2.0002 0 0 1 1.002-.27148v-1.2715a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm6 7v1 5 1h5c.55228 0 1-.4477 1-1v-5c0-.5523-.44772-1-1-1v4l-1-1-1 1v-4z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h2.2695v-2h-2.2715a2 2 0 0 0 -.72852-.73047v-5.8555l3 3v-.41406a2.0002 2.0002 0 0 1 .80859-1.6055l-2.3945-2.3945h5.8574a2 2 0 0 0 .72852.73047v1.2695a2.0002 2.0002 0 0 1 .99805.27148 2.0002 2.0002 0 0 1 1.002-.27148v-1.2715a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm6 7v1 5 1h5c.55228 0 1-.4477 1-1v-5c0-.5523-.44772-1-1-1v4l-1-1-1 1v-4z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/MiniObject.svg b/editor/icons/MiniObject.svg
index b4a336923d..7fe3b773d6 100644
--- a/editor/icons/MiniObject.svg
+++ b/editor/icons/MiniObject.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 2v8h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm0 5a3 3 0 0 0 -3-3 3 3 0 0 0 -3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3zm7-3v5a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3-3v-5zm-10 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm5 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#79f3e8"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 2v8h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm0 5a3 3 0 0 0 -3-3 3 3 0 0 0 -3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3zm7-3v5a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3-3v-5zm-10 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm5 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#55f3e3"/></svg>
diff --git a/editor/icons/MovePoint.svg b/editor/icons/MovePoint.svg
index 03b15e47b5..a5d728e6dd 100644
--- a/editor/icons/MovePoint.svg
+++ b/editor/icons/MovePoint.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 1.2129-.10742l-2.5996-6.3203a1.5002 1.5002 0 0 1 1.3711-2.0703v-.0019531a1.5002 1.5002 0 0 1 .58594.11133l6.3184 2.5996a7 7 0 0 0 .11133-1.2109 7 7 0 0 0 -7-7zm2.7559 9.7559.52344 1.2734a1.5002 1.5002 0 0 1 .48047-.26953 1.5002 1.5002 0 0 1 .26953-.47852l-1.2734-.52539z" fill="#fff" transform="translate(0 1036.4)"/><path d="m8 3a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 .42578-.021484l-1.8125-4.4063a1.5002 1.5002 0 0 1 1.3711-2.0703v-.0019531a1.5002 1.5002 0 0 1 .58594.11133l4.4082 1.8125a5 5 0 0 0 .021484-.42383 5 5 0 0 0 -5-5zm2.7559 7.7559.44336 1.0801a5 5 0 0 0 .63867-.63281l-1.082-.44727z" fill="#ff8484" transform="translate(0 1036.4)"/><path d="m16 1047.7-8-3.291 3.291 8 .9471-2.8201 1.8836 1.8835.9418-.9418-1.8836-1.8835z" fill="#e0e0e0"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 1.2129-.10742l-2.5996-6.3203a1.5002 1.5002 0 0 1 1.3711-2.0703v-.0019531a1.5002 1.5002 0 0 1 .58594.11133l6.3184 2.5996a7 7 0 0 0 .11133-1.2109 7 7 0 0 0 -7-7zm2.7559 9.7559.52344 1.2734a1.5002 1.5002 0 0 1 .48047-.26953 1.5002 1.5002 0 0 1 .26953-.47852l-1.2734-.52539z" fill="#fff" transform="translate(0 1036.4)"/><path d="m8 3a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 .42578-.021484l-1.8125-4.4063a1.5002 1.5002 0 0 1 1.3711-2.0703v-.0019531a1.5002 1.5002 0 0 1 .58594.11133l4.4082 1.8125a5 5 0 0 0 .021484-.42383 5 5 0 0 0 -5-5zm2.7559 7.7559.44336 1.0801a5 5 0 0 0 .63867-.63281l-1.082-.44727z" fill="#ff5f5f" transform="translate(0 1036.4)"/><path d="m16 1047.7-8-3.291 3.291 8 .9471-2.8201 1.8836 1.8835.9418-.9418-1.8836-1.8835z" fill="#e0e0e0"/></g></svg>
diff --git a/editor/icons/MultiMesh.svg b/editor/icons/MultiMesh.svg
index 6ee638db4c..5b4900841f 100644
--- a/editor/icons/MultiMesh.svg
+++ b/editor/icons/MultiMesh.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 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h1.2695v-2h-1.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l3.5859 3.5859h1.4141v-1.4141l-3.5859-3.5859h5.8574c.17532.30158.42647.55205.72852.72656v1.2734h2v-1.2695c.61831-.35698.99944-1.0165 1-1.7305 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1zm8 7v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#ffd684"/></svg>
+<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 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h1.2695v-2h-1.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l3.5859 3.5859h1.4141v-1.4141l-3.5859-3.5859h5.8574c.17532.30158.42647.55205.72852.72656v1.2734h2v-1.2695c.61831-.35698.99944-1.0165 1-1.7305 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1zm8 7v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/MultiMeshInstance2D.svg b/editor/icons/MultiMeshInstance2D.svg
index 07c72aeed1..253a43bf55 100644
--- a/editor/icons/MultiMeshInstance2D.svg
+++ b/editor/icons/MultiMeshInstance2D.svg
@@ -1 +1 @@
-<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m-1-1h582v402h-582z" fill="none"/><path d="m3 1c-1.1046 0-2 .89543-2 2 .00056.71397.38169 1.3735 1 1.7305v6.541c-.61771.35664-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.00056 1.3735-.38169 1.7305-1h1.2695v-2h-1.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l3.5859 3.5859h1.4141v-1.4141l-3.5859-3.5859h5.8574c.17532.30158.42647.55205.72852.72656v1.2734h2v-1.2695c.61831-.35698.99944-1.0165 1-1.7305 0-1.1046-.89543-2-2-2-.71397.00056-1.3735.38169-1.7305 1h-6.541c-.35664-.61771-1.0152-.99874-1.7285-1zm8 7v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#a5b7f3" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
+<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m-1-1h582v402h-582z" fill="none"/><path d="m3 1c-1.1046 0-2 .89543-2 2 .00056.71397.38169 1.3735 1 1.7305v6.541c-.61771.35664-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.00056 1.3735-.38169 1.7305-1h1.2695v-2h-1.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l3.5859 3.5859h1.4141v-1.4141l-3.5859-3.5859h5.8574c.17532.30158.42647.55205.72852.72656v1.2734h2v-1.2695c.61831-.35698.99944-1.0165 1-1.7305 0-1.1046-.89543-2-2-2-.71397.00056-1.3735.38169-1.7305 1h-6.541c-.35664-.61771-1.0152-.99874-1.7285-1zm8 7v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#8da5f3" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
diff --git a/editor/icons/MultiMeshInstance3D.svg b/editor/icons/MultiMeshInstance3D.svg
index 61d728c4be..3ccd2c9cbe 100644
--- a/editor/icons/MultiMeshInstance3D.svg
+++ b/editor/icons/MultiMeshInstance3D.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 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h1.2695v-2h-1.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l3.5859 3.5859h1.4141v-1.4141l-3.5859-3.5859h5.8574c.17532.30158.42647.55205.72852.72656v1.2734h2v-1.2695c.61831-.35698.99944-1.0165 1-1.7305 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1zm8 7v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<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 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h1.2695v-2h-1.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l3.5859 3.5859h1.4141v-1.4141l-3.5859-3.5859h5.8574c.17532.30158.42647.55205.72852.72656v1.2734h2v-1.2695c.61831-.35698.99944-1.0165 1-1.7305 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1zm8 7v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/Navigation2D.svg b/editor/icons/Navigation2D.svg
index 6725400e92..aa3e258eae 100644
--- a/editor/icons/Navigation2D.svg
+++ b/editor/icons/Navigation2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1050.4 5-2 5 2-5-12z" fill="#a5b7f3" fill-opacity=".98824" fill-rule="evenodd" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1050.4 5-2 5 2-5-12z" fill="#8da5f3" fill-opacity=".98824" fill-rule="evenodd" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/Navigation3D.svg b/editor/icons/Navigation3D.svg
index 74c8e204a3..646500d9ed 100644
--- a/editor/icons/Navigation3D.svg
+++ b/editor/icons/Navigation3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1050.4 5-2 5 2-5-12z" fill="#fc9c9c" fill-opacity=".99608" fill-rule="evenodd" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1050.4 5-2 5 2-5-12z" fill="#fc7f7f" fill-opacity=".99608" fill-rule="evenodd" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/NavigationMesh.svg b/editor/icons/NavigationMesh.svg
index 45bc51ac31..c5f16596a6 100644
--- a/editor/icons/NavigationMesh.svg
+++ b/editor/icons/NavigationMesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h2.5078l.75-2h-3.2598a2 2 0 0 0 -.72852-.73047v-5.8555l4.6973 4.6973.77148-2.0566-4.0547-4.0547h5.8574a2 2 0 0 0 .72852.73047v.27148a2.0002 2.0002 0 0 1 .023438 0 2.0002 2.0002 0 0 1 1.8496 1.2969l.12695.33789v-1.9082a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm9 6-3 8 3-2 3 2z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v6.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h2.5078l.75-2h-3.2598a2 2 0 0 0 -.72852-.73047v-5.8555l4.6973 4.6973.77148-2.0566-4.0547-4.0547h5.8574a2 2 0 0 0 .72852.73047v.27148a2.0002 2.0002 0 0 1 .023438 0 2.0002 2.0002 0 0 1 1.8496 1.2969l.12695.33789v-1.9082a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -1.7285-1zm9 6-3 8 3-2 3 2z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/NavigationRegion2D.svg b/editor/icons/NavigationRegion2D.svg
index 3ec0938417..8efd836075 100644
--- a/editor/icons/NavigationRegion2D.svg
+++ b/editor/icons/NavigationRegion2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.1339223.0000569-.2535666.0306675-.3652344.0742188-.022275.0088111-.0410424.0209185-.0625.03125-.0889622.0424668-.1681009.0954994-.2382812.1601562-.0215322.0195204-.0427394.0372854-.0625.0585938-.0741112.0810923-.13722.1698052-.1816406.2695312-.0034324.0076504-.0084746.0137334-.0117188.0214844l-.0019531.0019531c-.0452252.1091882-.0629923.2268973-.0683594.3457031-.0005086.0130821-.0078112.023903-.0078125.0371094v12c.0000552.552262.4477381.999945 1 1h4.8847656a2.1184381 2.1184381 0 0 1 .1328125-.744141l2.9999999-7.9999996a2.1184381 2.1184381 0 0 1 2.007813-1.3730469 2.1184381 2.1184381 0 0 1 1.957031 1.3730469l1.017578 2.7128906v-6.96875c-.000001-.0132064-.007305-.0240273-.007812-.0371094-.005369-.1188058-.023135-.2365149-.06836-.3457031l-.001953-.0019531c-.003155-.0075626-.008384-.0139987-.011719-.0214844-.044421-.099726-.107529-.188439-.18164-.2695312-.019761-.0213083-.040968-.0390734-.0625-.0585938-.070181-.0646568-.149319-.1176895-.238282-.1601562-.021457-.0103315-.040225-.022439-.0625-.03125-.111667-.0435511-.231312-.0741619-.365234-.0742188zm10 6-3 8 3-2 3 2z" fill="#a5b7f3" fill-opacity=".98824" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.1339223.0000569-.2535666.0306675-.3652344.0742188-.022275.0088111-.0410424.0209185-.0625.03125-.0889622.0424668-.1681009.0954994-.2382812.1601562-.0215322.0195204-.0427394.0372854-.0625.0585938-.0741112.0810923-.13722.1698052-.1816406.2695312-.0034324.0076504-.0084746.0137334-.0117188.0214844l-.0019531.0019531c-.0452252.1091882-.0629923.2268973-.0683594.3457031-.0005086.0130821-.0078112.023903-.0078125.0371094v12c.0000552.552262.4477381.999945 1 1h4.8847656a2.1184381 2.1184381 0 0 1 .1328125-.744141l2.9999999-7.9999996a2.1184381 2.1184381 0 0 1 2.007813-1.3730469 2.1184381 2.1184381 0 0 1 1.957031 1.3730469l1.017578 2.7128906v-6.96875c-.000001-.0132064-.007305-.0240273-.007812-.0371094-.005369-.1188058-.023135-.2365149-.06836-.3457031l-.001953-.0019531c-.003155-.0075626-.008384-.0139987-.011719-.0214844-.044421-.099726-.107529-.188439-.18164-.2695312-.019761-.0213083-.040968-.0390734-.0625-.0585938-.070181-.0646568-.149319-.1176895-.238282-.1601562-.021457-.0103315-.040225-.022439-.0625-.03125-.111667-.0435511-.231312-.0741619-.365234-.0742188zm10 6-3 8 3-2 3 2z" fill="#8da5f3" fill-opacity=".98824" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/NavigationRegion3D.svg b/editor/icons/NavigationRegion3D.svg
index 7a899dbc80..39b6d0ca13 100644
--- a/editor/icons/NavigationRegion3D.svg
+++ b/editor/icons/NavigationRegion3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.1339223.0000569-.2535666.030668-.3652344.074219-.022275.00881-.041042.020919-.0625.03125-.088962.042467-.1681009.095499-.2382812.1601562-.021532.01952-.042739.037285-.0625.058594-.074111.081092-.13722.1698052-.1816406.2695312-.00343.00765-.00847.013733-.011719.021484l-.00195.00195c-.0452281.1091913-.0629952.2269004-.0683623.3457062-.0005086.0130821-.0078112.023903-.0078125.0371094v12c.0000552.552262.4477381.999945 1 1h4.8847656a2.1184381 2.1184381 0 0 1 .1328125-.744141l2.9999999-7.9999996a2.1184381 2.1184381 0 0 1 2.007813-1.3730469 2.1184381 2.1184381 0 0 1 1.957031 1.3730469l1.017578 2.7128906v-6.96875c-.000001-.013206-.0073-.024027-.0078-.037109-.0054-.1188058-.02313-.2365149-.06836-.3457031l-.002-.00195c-.0032-.00756-.0084-.013999-.01172-.021484-.04442-.099726-.107529-.188439-.18164-.2695312-.01976-.021308-.04097-.039073-.0625-.058594-.07018-.064657-.149319-.1176895-.238282-.1601562-.02146-.010331-.04022-.022439-.0625-.03125-.111631-.0435548-.231276-.0741656-.365198-.0742225zm10 6-3 8 3-2 3 2z" fill="#fc9c9c" fill-opacity=".996078" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.1339223.0000569-.2535666.030668-.3652344.074219-.022275.00881-.041042.020919-.0625.03125-.088962.042467-.1681009.095499-.2382812.1601562-.021532.01952-.042739.037285-.0625.058594-.074111.081092-.13722.1698052-.1816406.2695312-.00343.00765-.00847.013733-.011719.021484l-.00195.00195c-.0452281.1091913-.0629952.2269004-.0683623.3457062-.0005086.0130821-.0078112.023903-.0078125.0371094v12c.0000552.552262.4477381.999945 1 1h4.8847656a2.1184381 2.1184381 0 0 1 .1328125-.744141l2.9999999-7.9999996a2.1184381 2.1184381 0 0 1 2.007813-1.3730469 2.1184381 2.1184381 0 0 1 1.957031 1.3730469l1.017578 2.7128906v-6.96875c-.000001-.013206-.0073-.024027-.0078-.037109-.0054-.1188058-.02313-.2365149-.06836-.3457031l-.002-.00195c-.0032-.00756-.0084-.013999-.01172-.021484-.04442-.099726-.107529-.188439-.18164-.2695312-.01976-.021308-.04097-.039073-.0625-.058594-.07018-.064657-.149319-.1176895-.238282-.1601562-.02146-.010331-.04022-.022439-.0625-.03125-.111631-.0435548-.231276-.0741656-.365198-.0742225zm10 6-3 8 3-2 3 2z" fill="#fc7f7f" fill-opacity=".996078" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/New.svg b/editor/icons/New.svg
index efc897cb4f..1667f46075 100644
--- a/editor/icons/New.svg
+++ b/editor/icons/New.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.400017)"><path d="m2 1v14h8v-1h-2v-4h2v-2h4v-2h-5v-5zm8 0v4h4z" fill="#e0e0e0" transform="translate(0 1036.4)"/><path d="m11 1045.4v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#84ffb1"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.400017)"><path d="m2 1v14h8v-1h-2v-4h2v-2h4v-2h-5v-5zm8 0v4h4z" fill="#e0e0e0" transform="translate(0 1036.4)"/><path d="m11 1045.4v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#5fff97"/></g></svg>
diff --git a/editor/icons/NewRoot.svg b/editor/icons/NewRoot.svg
index 061ff6043a..df3d590d01 100644
--- a/editor/icons/NewRoot.svg
+++ b/editor/icons/NewRoot.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 4.7813475v2.0494746c-.6177049.3566305-.998733 1.0152377-1 1.7285 0 1.1045694.8954305 1.9999999 2 1.9999999.7139771-.000554 1.3735116-.381678 1.7305-.9999995h1.3545593c.3566306.6177035 1.0152377.9987325 1.7285.9999995 1.1045696 0 1.9999996-.8954305 1.9999996-1.9999999 0-1.1045695-.89543-2-1.9999996-2-.7139771.0005537-1.3735116.3816774-1.7305 1h-1.3545593c-.1747809-.3030102-.4259781-.5548798-.72852-.73047v-2.0494746c-.5384713.0290292-1.2982621.0368063-1.99998.00197z" fill="#e0e0e0"/><path d="m6.8474576 9.6288045v1.2020165c-.617705.35663-.998733 1.015237-1 1.7285 0 1.104569.89543 2 2 2 .713977-.000554 1.373512-.381678 1.7305-1h1.2867634c.35663.617704 1.015237.998733 1.7285 1 1.104569 0 1.999999-.895431 1.999999-2 0-1.10457-.89543-2-1.999999-2-.713977.000553-1.373512.381677-1.7305 1h-1.2867634c-.174781-.303011-.425978-.55488-.72852-.73047v-1.2020165s-1.264363.03681-1.99998.002z" fill="#e0e0e0"/><path d="m2.7966098 1.3559322c-1.104569 0-2.00000003.8954305-2.00000003 2 .000554.7139771.38167803 1.3735116 1.00000003 1.7305.757716.266212.949133.2840609 1.99998-.00197.617705-.3566306.998733-1.0152377 1-1.7285 0-1.1045695-.89543-2-2-2z" fill="#84ffb1"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 4.7813475v2.0494746c-.6177049.3566305-.998733 1.0152377-1 1.7285 0 1.1045694.8954305 1.9999999 2 1.9999999.7139771-.000554 1.3735116-.381678 1.7305-.9999995h1.3545593c.3566306.6177035 1.0152377.9987325 1.7285.9999995 1.1045696 0 1.9999996-.8954305 1.9999996-1.9999999 0-1.1045695-.89543-2-1.9999996-2-.7139771.0005537-1.3735116.3816774-1.7305 1h-1.3545593c-.1747809-.3030102-.4259781-.5548798-.72852-.73047v-2.0494746c-.5384713.0290292-1.2982621.0368063-1.99998.00197z" fill="#e0e0e0"/><path d="m6.8474576 9.6288045v1.2020165c-.617705.35663-.998733 1.015237-1 1.7285 0 1.104569.89543 2 2 2 .713977-.000554 1.373512-.381678 1.7305-1h1.2867634c.35663.617704 1.015237.998733 1.7285 1 1.104569 0 1.999999-.895431 1.999999-2 0-1.10457-.89543-2-1.999999-2-.713977.000553-1.373512.381677-1.7305 1h-1.2867634c-.174781-.303011-.425978-.55488-.72852-.73047v-1.2020165s-1.264363.03681-1.99998.002z" fill="#e0e0e0"/><path d="m2.7966098 1.3559322c-1.104569 0-2.00000003.8954305-2.00000003 2 .000554.7139771.38167803 1.3735116 1.00000003 1.7305.757716.266212.949133.2840609 1.99998-.00197.617705-.3566306.998733-1.0152377 1-1.7285 0-1.1045695-.89543-2-2-2z" fill="#5fff97"/></svg>
diff --git a/editor/icons/NinePatchRect.svg b/editor/icons/NinePatchRect.svg
index d857b71a46..56ed224f98 100644
--- a/editor/icons/NinePatchRect.svg
+++ b/editor/icons/NinePatchRect.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#a5efac" transform="translate(0 -1036.4)"><path d="m1 1037.4h2v14h-2z"/><path d="m1 1049.4h14v2h-14z"/><path d="m1 1037.4h14v2h-14z"/><path d="m13 1037.4h2v14h-2z"/><path d="m1 1041.4h14v.99998h-14z"/><path d="m1 1046.4h14v.99998h-14z"/><g transform="rotate(90)"><path d="m1037.4-6h14v.99998h-14z"/><path d="m1037.4-11h14v.99998h-14z"/></g></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#8eef97" transform="translate(0 -1036.4)"><path d="m1 1037.4h2v14h-2z"/><path d="m1 1049.4h14v2h-14z"/><path d="m1 1037.4h14v2h-14z"/><path d="m13 1037.4h2v14h-2z"/><path d="m1 1041.4h14v.99998h-14z"/><path d="m1 1046.4h14v.99998h-14z"/><g transform="rotate(90)"><path d="m1037.4-6h14v.99998h-14z"/><path d="m1037.4-11h14v.99998h-14z"/></g></g></svg>
diff --git a/editor/icons/Node2D.svg b/editor/icons/Node2D.svg
index 7f27e0695f..a47399df92 100644
--- a/editor/icons/Node2D.svg
+++ b/editor/icons/Node2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4z" fill="#a5b7f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/Node3D.svg b/editor/icons/Node3D.svg
index 56f6ed5542..c8a3163e51 100644
--- a/editor/icons/Node3D.svg
+++ b/editor/icons/Node3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/NodePath.svg b/editor/icons/NodePath.svg
index 3ecb830bec..14c753a136 100644
--- a/editor/icons/NodePath.svg
+++ b/editor/icons/NodePath.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v8h2v-2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2zm5 0v8h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3v-2zm-9 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#6993ec"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v8h2v-2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2zm5 0v8h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3v-2zm-9 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#417aec"/></svg>
diff --git a/editor/icons/Occluder3D.svg b/editor/icons/Occluder3D.svg
new file mode 100644
index 0000000000..850e2651af
--- /dev/null
+++ b/editor/icons/Occluder3D.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.90625 1a7 7 0 0 0 -1.2988281.1386719 4.5 4.5 0 0 1 3.3925781 4.3613281 4.5 4.5 0 0 1 -4.5 4.5 4.5 4.5 0 0 1 -4.359375-3.3886719 7 7 0 0 0 -.140625 1.3886719 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7 7 7 0 0 0 -.09375 0z" fill="#ffca5f" stroke-width=".365215"/></svg>
diff --git a/editor/icons/OccluderInstance3D.svg b/editor/icons/OccluderInstance3D.svg
new file mode 100644
index 0000000000..cc7ccc410f
--- /dev/null
+++ b/editor/icons/OccluderInstance3D.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.90625 1a7 7 0 0 0 -1.2988281.1386719 4.5 4.5 0 0 1 3.3925781 4.3613281 4.5 4.5 0 0 1 -4.5 4.5 4.5 4.5 0 0 1 -4.359375-3.3886719 7 7 0 0 0 -.140625 1.3886719 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7 7 7 0 0 0 -.09375 0z" fill="#fc7f7f" fill-opacity=".996078" stroke-width=".365215"/></svg>
diff --git a/editor/icons/OccluderPolygon2D.svg b/editor/icons/OccluderPolygon2D.svg
index cdceb16441..ae5d2f4a1d 100644
--- a/editor/icons/OccluderPolygon2D.svg
+++ b/editor/icons/OccluderPolygon2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd" transform="translate(0 -1036.4)"><path d="m1 1045.4 6 6h8v-8l-6-6h-8z" fill="#3552b1"/><path d="m1 1037.4h8l-3 4 3 4h-8z" fill="#a5b7f3" fill-opacity=".98824"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd" transform="translate(0 -1036.4)"><path d="m1 1045.4 6 6h8v-8l-6-6h-8z" fill="#3552b1"/><path d="m1 1037.4h8l-3 4 3 4h-8z" fill="#8da5f3" fill-opacity=".98824"/></g></svg>
diff --git a/editor/icons/OmniLight3D.svg b/editor/icons/OmniLight3D.svg
index 06b3786ebe..391e9104a1 100644
--- a/editor/icons/OmniLight3D.svg
+++ b/editor/icons/OmniLight3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a5 5 0 0 0 -5 5 5 5 0 0 0 3 4.5762v2.4238h4v-2.4199a5 5 0 0 0 3-4.5801 5 5 0 0 0 -5-5zm0 2a3 3 0 0 1 3 3 3 3 0 0 1 -3 3 3 3 0 0 1 -3-3 3 3 0 0 1 3-3zm-1 11v1h2v-1z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a5 5 0 0 0 -5 5 5 5 0 0 0 3 4.5762v2.4238h4v-2.4199a5 5 0 0 0 3-4.5801 5 5 0 0 0 -5-5zm0 2a3 3 0 0 1 3 3 3 3 0 0 1 -3 3 3 3 0 0 1 -3-3 3 3 0 0 1 3-3zm-1 11v1h2v-1z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/OptionButton.svg b/editor/icons/OptionButton.svg
index 50e6fae218..0a07470618 100644
--- a/editor/icons/OptionButton.svg
+++ b/editor/icons/OptionButton.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m3 3c-1.1046 0-2 .89543-2 2v6c0 1.1046.89543 2 2 2h5 1 1 2 1c1.1046 0 2-.89543 2-2v-6c0-1.1046-.89543-2-2-2h-1-2-1-1zm8 2.9863a1.0001 1.0001 0 0 1 .7168 1.7207l-3 3a1.0001 1.0001 0 0 1 -1.4141 0l-3-3a1.0001 1.0001 0 0 1 .69727-1.7168 1.0001 1.0001 0 0 1 .7168.30273l2.293 2.293 2.293-2.293a1.0001 1.0001 0 0 1 .69727-.30664z" fill="#a5efac" transform="translate(0 1036.4)"/><path d="m4 1042.4h4v4h-4z" fill="none"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m3 3c-1.1046 0-2 .89543-2 2v6c0 1.1046.89543 2 2 2h5 1 1 2 1c1.1046 0 2-.89543 2-2v-6c0-1.1046-.89543-2-2-2h-1-2-1-1zm8 2.9863a1.0001 1.0001 0 0 1 .7168 1.7207l-3 3a1.0001 1.0001 0 0 1 -1.4141 0l-3-3a1.0001 1.0001 0 0 1 .69727-1.7168 1.0001 1.0001 0 0 1 .7168.30273l2.293 2.293 2.293-2.293a1.0001 1.0001 0 0 1 .69727-.30664z" fill="#8eef97" transform="translate(0 1036.4)"/><path d="m4 1042.4h4v4h-4z" fill="none"/></g></svg>
diff --git a/editor/icons/PackedColorArray.svg b/editor/icons/PackedColorArray.svg
index 206819ffb6..588002f188 100644
--- a/editor/icons/PackedColorArray.svg
+++ b/editor/icons/PackedColorArray.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m6 3.5a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2z" fill="#ff7070"/><path d="m13 3.5a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1z" fill="#70bfff"/><path d="m7 1.5v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5z" fill="#7aff70"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m6 3.5a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2z" fill="#ff4545"/><path d="m13 3.5a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1z" fill="#70bfff"/><path d="m7 1.5v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5z" fill="#7aff70"/></svg>
diff --git a/editor/icons/PackedFloat32Array.svg b/editor/icons/PackedFloat32Array.svg
index 503b0e7b6f..ccfbb748b7 100644
--- a/editor/icons/PackedFloat32Array.svg
+++ b/editor/icons/PackedFloat32Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m6 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1-1zm1 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5zm3 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2z" fill="#61daf4"/><path d="m7 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m6 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1-1zm1 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5zm3 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2z" fill="#35d4f4"/><path d="m7 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/PackedFloat64Array.svg b/editor/icons/PackedFloat64Array.svg
index 503b0e7b6f..ccfbb748b7 100644
--- a/editor/icons/PackedFloat64Array.svg
+++ b/editor/icons/PackedFloat64Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m6 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1-1zm1 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5zm3 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2z" fill="#61daf4"/><path d="m7 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m6 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1-1zm1 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5zm3 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2z" fill="#35d4f4"/><path d="m7 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/PackedInt32Array.svg b/editor/icons/PackedInt32Array.svg
index a1dc417c11..973e4b9ab2 100644
--- a/editor/icons/PackedInt32Array.svg
+++ b/editor/icons/PackedInt32Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m3 2v2h2v-2zm2 2v2h-2v4h4v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm5 3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2h-2z" fill="#7dc6ef"/><path d="m5 4v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m3 2v2h2v-2zm2 2v2h-2v4h4v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm5 3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2h-2z" fill="#5abbef"/><path d="m5 4v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/PackedInt64Array.svg b/editor/icons/PackedInt64Array.svg
index a1dc417c11..973e4b9ab2 100644
--- a/editor/icons/PackedInt64Array.svg
+++ b/editor/icons/PackedInt64Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m3 2v2h2v-2zm2 2v2h-2v4h4v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm5 3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2h-2z" fill="#7dc6ef"/><path d="m5 4v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m3 2v2h2v-2zm2 2v2h-2v4h4v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm5 3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2h-2z" fill="#5abbef"/><path d="m5 4v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/PackedStringArray.svg b/editor/icons/PackedStringArray.svg
index e9285e2192..5273d6bc56 100644
--- a/editor/icons/PackedStringArray.svg
+++ b/editor/icons/PackedStringArray.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m7 2a3 3 0 0 0 -3 3v2a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3-3v-2a1 1 0 0 1 1-1h1v3a3 3 0 0 0 3 3h2v-3a1 1 0 0 1 1-1v-2a3 3 0 0 0 -3 3v1a1 1 0 0 1 -1-1v-1h1v-2h-1v-2h-2z" fill="#6ba7ec"/><path d="m8 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m7 2a3 3 0 0 0 -3 3v2a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3-3v-2a1 1 0 0 1 1-1h1v3a3 3 0 0 0 3 3h2v-3a1 1 0 0 1 1-1v-2a3 3 0 0 0 -3 3v1a1 1 0 0 1 -1-1v-1h1v-2h-1v-2h-2z" fill="#4593ec"/><path d="m8 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/PackedVector2Array.svg b/editor/icons/PackedVector2Array.svg
index a5c8921045..f7e23b800f 100644
--- a/editor/icons/PackedVector2Array.svg
+++ b/editor/icons/PackedVector2Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m9 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.0019531v2h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5zm-6 1v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4z" fill="#bd91f1"/><path d="m9 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.00195v2.0001h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5001z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m9 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.0019531v2h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5zm-6 1v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4z" fill="#ac73f1"/><path d="m9 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.00195v2.0001h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5001z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/PackedVector3Array.svg b/editor/icons/PackedVector3Array.svg
index e1de83908d..e78be63df2 100644
--- a/editor/icons/PackedVector3Array.svg
+++ b/editor/icons/PackedVector3Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m8 1v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.44772 1-1 1h-1v2h1c1.0716-.0001501 2.0618-.57193 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34772-.36523-.50195.13856-.15301.26095-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.003906v-2zm0 2h-2v3c-.0000096.55228-.44772.99999-1 1v-4h-2v6h2c1.6569 0 3-1.3431 3-3z" fill="#e286f0"/><path d="m8 1v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.44772 1-1 1h-1v2h1c1.0716-.0001501 2.0618-.57193 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34772-.36523-.50195.13856-.15301.26095-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.003906v-2z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m8 1v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.44772 1-1 1h-1v2h1c1.0716-.0001501 2.0618-.57193 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34772-.36523-.50195.13856-.15301.26095-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.003906v-2zm0 2h-2v3c-.0000096.55228-.44772.99999-1 1v-4h-2v6h2c1.6569 0 3-1.3431 3-3z" fill="#de66f0"/><path d="m8 1v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.44772 1-1 1h-1v2h1c1.0716-.0001501 2.0618-.57193 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34772-.36523-.50195.13856-.15301.26095-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.003906v-2z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/Panel.svg b/editor/icons/Panel.svg
index f82822c5a1..7a36a35048 100644
--- a/editor/icons/Panel.svg
+++ b/editor/icons/Panel.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-2z" fill="#a5efac"/></svg>
+<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-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/PanelContainer.svg b/editor/icons/PanelContainer.svg
index 017941ba36..2f783d6e49 100644
--- a/editor/icons/PanelContainer.svg
+++ b/editor/icons/PanelContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10z" fill="#8eef97"/></svg>
diff --git a/editor/icons/PanoramaSkyMaterial.svg b/editor/icons/PanoramaSkyMaterial.svg
index 33ffc20351..eddcbfd871 100644
--- a/editor/icons/PanoramaSkyMaterial.svg
+++ b/editor/icons/PanoramaSkyMaterial.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 5v2h8 1c0-.554.446-1 1-1h2c.554 0 1 .446 1 1h1v-2z" fill="#9dff70"/><path d="m1 3v2h14v-2h-1.589844c-2.86436 1.357608-6.9481434 1.30996-10.347656 0z" fill="#ffeb70"/><path d="m1 2v1h2.0625c-.7241713-.2790504-1.419865-.6077805-2.0625-1zm14 0c-.465784.3952185-1.005424.7230054-1.589844 1h1.589844z" fill="#ff7070"/><path d="m1 7v2h2 1 5c-.554 0-1-.446-1-1s.446-1 1-1zm13 0c0 .554-.446 1-1 1h-1c0 .554-.446 1-1 1h4v-2z" fill="#70ffb9"/><path d="m1 9v2h2c-.554 0-1-.446-1-1s.446-1 1-1zm3 0c.554 0 1 .446 1 1s-.446 1-1 1h11v-2h-4-2z" fill="#70deff"/><path d="m1 13v-2h14v2h-1.589844c-2.86436-1.357608-6.9481434-1.30996-10.347656 0z" fill="#9f70ff"/><path d="m1 14v-1h2.0625c-.7241713.27905-1.419865.60778-2.0625 1zm14 0c-.465784-.395219-1.005424-.723005-1.589844-1h1.589844z" fill="#ff70ac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 5v2h8 1c0-.554.446-1 1-1h2c.554 0 1 .446 1 1h1v-2z" fill="#80ff45"/><path d="m1 3v2h14v-2h-1.589844c-2.86436 1.357608-6.9481434 1.30996-10.347656 0z" fill="#ffe345"/><path d="m1 2v1h2.0625c-.7241713-.2790504-1.419865-.6077805-2.0625-1zm14 0c-.465784.3952185-1.005424.7230054-1.589844 1h1.589844z" fill="#ff4545"/><path d="m1 7v2h2 1 5c-.554 0-1-.446-1-1s.446-1 1-1zm13 0c0 .554-.446 1-1 1h-1c0 .554-.446 1-1 1h4v-2z" fill="#45ffa2"/><path d="m1 9v2h2c-.554 0-1-.446-1-1s.446-1 1-1zm3 0c.554 0 1 .446 1 1s-.446 1-1 1h11v-2h-4-2z" fill="#45d7ff"/><path d="m1 13v-2h14v2h-1.589844c-2.86436-1.357608-6.9481434-1.30996-10.347656 0z" fill="#8045ff"/><path d="m1 14v-1h2.0625c-.7241713.27905-1.419865.60778-2.0625 1zm14 0c-.465784-.395219-1.005424-.723005-1.589844-1h1.589844z" fill="#ff4596"/></svg>
diff --git a/editor/icons/ParallaxLayer.svg b/editor/icons/ParallaxLayer.svg
index 64bf68f604..0768e941ad 100644
--- a/editor/icons/ParallaxLayer.svg
+++ b/editor/icons/ParallaxLayer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 1h10c.55228.0000096.99999.44772 1 1v10c-.00001.55228-.44772.99999-1 1h-10c-.55228-.00001-.99999-.44772-1-1v-10c.0000096-.55228.44772-.99999 1-1zm4 3-3 3 3 3zm2 0v6l3-3z" fill="#a5b7f3" fill-opacity=".98824" fill-rule="evenodd" transform="translate(0 1036.4)"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><ellipse cx="3" cy="1039.4" fill="#6e6e6e"/><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 1h10c.55228.0000096.99999.44772 1 1v10c-.00001.55228-.44772.99999-1 1h-10c-.55228-.00001-.99999-.44772-1-1v-10c.0000096-.55228.44772-.99999 1-1zm4 3-3 3 3 3zm2 0v6l3-3z" fill="#8da5f3" fill-opacity=".98824" fill-rule="evenodd" transform="translate(0 1036.4)"/></g></svg>
diff --git a/editor/icons/ParticlesMaterial.svg b/editor/icons/ParticlesMaterial.svg
index f9a25530ef..33598980a5 100644
--- a/editor/icons/ParticlesMaterial.svg
+++ b/editor/icons/ParticlesMaterial.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a4.5 5 0 0 0 -3.5938 2h7.1816a4.5 5 0 0 0 -3.5879-2z" fill="#ff7070"/><path d="m4.4062 3a4.5 5 0 0 0 -.81445 2h8.8105a4.5 5 0 0 0 -.81445-2z" fill="#ffeb70"/><path d="m3.5918 5a4.5 5 0 0 0 -.0058594.03125 3 3 0 0 0 -2.4121 1.9688h13.65a3 3 0 0 0 -2.4141-1.9668 4.5 5 0 0 0 -.007812-.033203h-8.8105z" fill="#9dff70"/><path d="m1.1738 7a3 3 0 0 0 -.17383 1 3 3 0 0 0 .17578 1h13.65a3 3 0 0 0 .17383-1 3 3 0 0 0 -.17578-1z" fill="#70ffb9"/><path d="m1.1758 9a3 3 0 0 0 2.8242 2h8a3 3 0 0 0 2.8262-2h-13.65z" fill="#70deff"/><path d="m3 13a1 1 0 0 0 1 1 1 1 0 0 0 1-1zm5 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm3 0a1 1 0 0 0 1 1 1 1 0 0 0 1-1z" fill="#ff70ac"/><path d="m4 12a1 1 0 0 0 -1 1h2a1 1 0 0 0 -1-1zm8 0a1 1 0 0 0 -1 1h2a1 1 0 0 0 -1-1z" fill="#9f70ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a4.5 5 0 0 0 -3.5938 2h7.1816a4.5 5 0 0 0 -3.5879-2z" fill="#ff4545"/><path d="m4.4062 3a4.5 5 0 0 0 -.81445 2h8.8105a4.5 5 0 0 0 -.81445-2z" fill="#ffe345"/><path d="m3.5918 5a4.5 5 0 0 0 -.0058594.03125 3 3 0 0 0 -2.4121 1.9688h13.65a3 3 0 0 0 -2.4141-1.9668 4.5 5 0 0 0 -.007812-.033203h-8.8105z" fill="#80ff45"/><path d="m1.1738 7a3 3 0 0 0 -.17383 1 3 3 0 0 0 .17578 1h13.65a3 3 0 0 0 .17383-1 3 3 0 0 0 -.17578-1z" fill="#45ffa2"/><path d="m1.1758 9a3 3 0 0 0 2.8242 2h8a3 3 0 0 0 2.8262-2h-13.65z" fill="#45d7ff"/><path d="m3 13a1 1 0 0 0 1 1 1 1 0 0 0 1-1zm5 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm3 0a1 1 0 0 0 1 1 1 1 0 0 0 1-1z" fill="#ff4596"/><path d="m4 12a1 1 0 0 0 -1 1h2a1 1 0 0 0 -1-1zm8 0a1 1 0 0 0 -1 1h2a1 1 0 0 0 -1-1z" fill="#8045ff"/></svg>
diff --git a/editor/icons/Path2D.svg b/editor/icons/Path2D.svg
index 5633dcf923..494ca344be 100644
--- a/editor/icons/Path2D.svg
+++ b/editor/icons/Path2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 1a2 2 0 0 0 -2 2 2 2 0 0 0 .84961 1.6328c-.19239.88508-.55317 1.3394-.98633 1.6426-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c.8927-.62488 1.5321-1.6538 1.8184-3.0977a2 2 0 0 0 1.1699-1.8164 2 2 0 0 0 -2-2z" fill="#a5b7f3" fill-opacity=".98824"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 1a2 2 0 0 0 -2 2 2 2 0 0 0 .84961 1.6328c-.19239.88508-.55317 1.3394-.98633 1.6426-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c.8927-.62488 1.5321-1.6538 1.8184-3.0977a2 2 0 0 0 1.1699-1.8164 2 2 0 0 0 -2-2z" fill="#8da5f3" fill-opacity=".98824"/></svg>
diff --git a/editor/icons/Path3D.svg b/editor/icons/Path3D.svg
index 913fe8abf6..076ce9acd2 100644
--- a/editor/icons/Path3D.svg
+++ b/editor/icons/Path3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 1a2 2 0 0 0 -2 2 2 2 0 0 0 .84961 1.6328c-.19239.88508-.55317 1.3394-.98633 1.6426-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c.8927-.62488 1.5321-1.6538 1.8184-3.0977a2 2 0 0 0 1.1699-1.8164 2 2 0 0 0 -2-2z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 1a2 2 0 0 0 -2 2 2 2 0 0 0 .84961 1.6328c-.19239.88508-.55317 1.3394-.98633 1.6426-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c.8927-.62488 1.5321-1.6538 1.8184-3.0977a2 2 0 0 0 1.1699-1.8164 2 2 0 0 0 -2-2z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/PathFollow2D.svg b/editor/icons/PathFollow2D.svg
index ac0f17240e..a1fb97cf34 100644
--- a/editor/icons/PathFollow2D.svg
+++ b/editor/icons/PathFollow2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 0-3 4h1.9473c-.1385 1.3203-.5583 1.9074-1.084 2.2754-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c1.0528-.73697 1.7552-2.032 1.9375-3.9141h2.0508l-3-4z" fill="#a5b7f3" fill-opacity=".98824"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 0-3 4h1.9473c-.1385 1.3203-.5583 1.9074-1.084 2.2754-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c1.0528-.73697 1.7552-2.032 1.9375-3.9141h2.0508l-3-4z" fill="#8da5f3" fill-opacity=".98824"/></svg>
diff --git a/editor/icons/PathFollow3D.svg b/editor/icons/PathFollow3D.svg
index c9bd7009dc..f9bb38939e 100644
--- a/editor/icons/PathFollow3D.svg
+++ b/editor/icons/PathFollow3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 0-3 4h1.9473c-.1385 1.3203-.5583 1.9074-1.084 2.2754-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c1.0528-.73697 1.7552-2.032 1.9375-3.9141h2.0508l-3-4z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 0-3 4h1.9473c-.1385 1.3203-.5583 1.9074-1.084 2.2754-.64426.451-1.7129.60547-2.9629.73047s-2.6814.22053-3.9121 1.082c-.89278.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.84961-1.6328c.19235-.88496.55306-1.3373.98633-1.6406.64426-.451 1.7129-.60547 2.9629-.73047s2.6814-.22053 3.9121-1.082c1.0528-.73697 1.7552-2.032 1.9375-3.9141h2.0508l-3-4z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/PhysicalBone3D.svg b/editor/icons/PhysicalBone3D.svg
index 55df1f1e19..29f0611b9e 100644
--- a/editor/icons/PhysicalBone3D.svg
+++ b/editor/icons/PhysicalBone3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc9c9c" transform="translate(-2.5625 -18.4375)"><path d="m13.107422 19.382812a2.4664 2.4663 0 0 0 -1.78125.720704 2.4664 2.4663 0 0 0 -.185547.21289l1.332031 2.433594-1.605469.603516-3.414062 3.414062a2.4664 2.4663 0 0 0 -3.1015625.3125 2.4664 2.4663 0 0 0 0 3.488281 2.4664 2.4663 0 0 0 1.3964844.695313 2.4664 2.4663 0 0 0 .6953125 1.396484 2.4664 2.4663 0 0 0 3.4882812 0 2.4664 2.4663 0 0 0 .3144534-3.103515l3.560547-3.560547a2.4664 2.4663 0 0 0 3.099609-.310547 2.4664 2.4663 0 0 0 0-3.488281 2.4664 2.4663 0 0 0 -1.396484-.697266 2.4664 2.4663 0 0 0 -.695313-1.396484 2.4664 2.4663 0 0 0 -1.707031-.720704z"/><path d="m3.7211033 21.208326.9608286 4.82644 1.3962404-.524494z"/><path d="m6.4843278 19.465234.9608285 4.82644 1.3962404-.524494z"/><path d="m9.6964655 19.33678.7108285 3.51394 1.39624-.524494z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f" transform="translate(-2.5625 -18.4375)"><path d="m13.107422 19.382812a2.4664 2.4663 0 0 0 -1.78125.720704 2.4664 2.4663 0 0 0 -.185547.21289l1.332031 2.433594-1.605469.603516-3.414062 3.414062a2.4664 2.4663 0 0 0 -3.1015625.3125 2.4664 2.4663 0 0 0 0 3.488281 2.4664 2.4663 0 0 0 1.3964844.695313 2.4664 2.4663 0 0 0 .6953125 1.396484 2.4664 2.4663 0 0 0 3.4882812 0 2.4664 2.4663 0 0 0 .3144534-3.103515l3.560547-3.560547a2.4664 2.4663 0 0 0 3.099609-.310547 2.4664 2.4663 0 0 0 0-3.488281 2.4664 2.4663 0 0 0 -1.396484-.697266 2.4664 2.4663 0 0 0 -.695313-1.396484 2.4664 2.4663 0 0 0 -1.707031-.720704z"/><path d="m3.7211033 21.208326.9608286 4.82644 1.3962404-.524494z"/><path d="m6.4843278 19.465234.9608285 4.82644 1.3962404-.524494z"/><path d="m9.6964655 19.33678.7108285 3.51394 1.39624-.524494z"/></g></svg>
diff --git a/editor/icons/PhysicalSkyMaterial.svg b/editor/icons/PhysicalSkyMaterial.svg
index 68bf2785a4..a32b451c53 100644
--- a/editor/icons/PhysicalSkyMaterial.svg
+++ b/editor/icons/PhysicalSkyMaterial.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 5v2h8 1c0-.554.446-1 1-1h2c.554 0 1 .446 1 1h1v-2z" fill="#9dff70"/><path d="m1 7v2h2 1 5c-.554 0-1-.446-1-1s.446-1 1-1zm13 0c0 .554-.446 1-1 1h-1c0 .554-.446 1-1 1h4v-2z" fill="#70ffb9"/><path d="m1 9v2h2c-.554 0-1-.446-1-1s.446-1 1-1zm3 0c.554 0 1 .446 1 1s-.446 1-1 1h11v-2h-4-2z" fill="#70deff"/><path d="m1 3v2h14v-2z" fill="#ffeb70"/><path d="m1 11v2h14v-2z" fill="#9f70ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 5v2h8 1c0-.554.446-1 1-1h2c.554 0 1 .446 1 1h1v-2z" fill="#80ff45"/><path d="m1 7v2h2 1 5c-.554 0-1-.446-1-1s.446-1 1-1zm13 0c0 .554-.446 1-1 1h-1c0 .554-.446 1-1 1h4v-2z" fill="#45ffa2"/><path d="m1 9v2h2c-.554 0-1-.446-1-1s.446-1 1-1zm3 0c.554 0 1 .446 1 1s-.446 1-1 1h11v-2h-4-2z" fill="#45d7ff"/><path d="m1 3v2h14v-2z" fill="#ffe345"/><path d="m1 11v2h14v-2z" fill="#8045ff"/></svg>
diff --git a/editor/icons/PinJoint2D.svg b/editor/icons/PinJoint2D.svg
index 4e701df7fb..fc7329e4f3 100644
--- a/editor/icons/PinJoint2D.svg
+++ b/editor/icons/PinJoint2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1.2715-.70703.70703v1.4141l-2.1211 2.123 4.2422 4.2422 2.1211-2.1211h1.4141l.70703-.70703-5.6562-5.6582zm-3.5352 4.9512-3.5352.70703 7.0703 7.0703.70703-3.5352-4.2422-4.2422zm-1.4141 4.2422-1.4141 1.4141-.70703 2.1211 2.1211-.70703 1.4141-1.4141-1.4141-1.4141z" fill="#a5b7f3" fill-opacity=".98824" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1.2715-.70703.70703v1.4141l-2.1211 2.123 4.2422 4.2422 2.1211-2.1211h1.4141l.70703-.70703-5.6562-5.6582zm-3.5352 4.9512-3.5352.70703 7.0703 7.0703.70703-3.5352-4.2422-4.2422zm-1.4141 4.2422-1.4141 1.4141-.70703 2.1211 2.1211-.70703 1.4141-1.4141-1.4141-1.4141z" fill="#8da5f3" fill-opacity=".98824" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/PinJoint3D.svg b/editor/icons/PinJoint3D.svg
index 12f388b2f7..8cba452163 100644
--- a/editor/icons/PinJoint3D.svg
+++ b/editor/icons/PinJoint3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1.2715-.70703.70703v1.4141l-2.1211 2.123 4.2422 4.2422 2.1211-2.1211h1.4141l.70703-.70703-5.6562-5.6582zm-3.5352 4.9512-3.5352.70703 7.0703 7.0703.70703-3.5352-4.2422-4.2422zm-1.4141 4.2422-1.4141 1.4141-.70703 2.1211 2.1211-.70703 1.4141-1.4141-1.4141-1.4141z" fill="#fc9c9c" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 1.2715-.70703.70703v1.4141l-2.1211 2.123 4.2422 4.2422 2.1211-2.1211h1.4141l.70703-.70703-5.6562-5.6582zm-3.5352 4.9512-3.5352.70703 7.0703 7.0703.70703-3.5352-4.2422-4.2422zm-1.4141 4.2422-1.4141 1.4141-.70703 2.1211 2.1211-.70703 1.4141-1.4141-1.4141-1.4141z" fill="#fc7f7f" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/Plane.svg b/editor/icons/Plane.svg
index edaa86e772..5857ac56f7 100644
--- a/editor/icons/Plane.svg
+++ b/editor/icons/Plane.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 2v8h2v-2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3zm6 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5zm-4 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm8 0v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3z" fill="#f77070"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 2v8h2v-2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3zm6 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5zm-4 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm8 0v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3z" fill="#f74949"/></svg>
diff --git a/editor/icons/PlaneMesh.svg b/editor/icons/PlaneMesh.svg
index 3514c1e3e3..54b33616ba 100644
--- a/editor/icons/PlaneMesh.svg
+++ b/editor/icons/PlaneMesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 4-7 4 7 4 7-4zm0 2 3.5 2-3.5 2-3.5-2z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 4-7 4 7 4 7-4zm0 2 3.5 2-3.5 2-3.5-2z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/PointLight2D.svg b/editor/icons/PointLight2D.svg
index d660b82c34..1a3222c79e 100644
--- a/editor/icons/PointLight2D.svg
+++ b/editor/icons/PointLight2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a5 5 0 0 0 -5 5 5 5 0 0 0 3 4.5762v2.4238h4v-2.4199a5 5 0 0 0 3-4.5801 5 5 0 0 0 -5-5zm0 2a3 3 0 0 1 3 3 3 3 0 0 1 -3 3 3 3 0 0 1 -3-3 3 3 0 0 1 3-3zm-1 11v1h2v-1z" fill="#a5b7f3" fill-opacity=".98824"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a5 5 0 0 0 -5 5 5 5 0 0 0 3 4.5762v2.4238h4v-2.4199a5 5 0 0 0 3-4.5801 5 5 0 0 0 -5-5zm0 2a3 3 0 0 1 3 3 3 3 0 0 1 -3 3 3 3 0 0 1 -3-3 3 3 0 0 1 3-3zm-1 11v1h2v-1z" fill="#8da5f3" fill-opacity=".98824"/></svg>
diff --git a/editor/icons/PointMesh.svg b/editor/icons/PointMesh.svg
index 184200c528..ec04989e02 100644
--- a/editor/icons/PointMesh.svg
+++ b/editor/icons/PointMesh.svg
@@ -1 +1 @@
-<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ffd684"><ellipse cx="3.7237" cy="3.0268" rx="2.0114" ry="1.9956"/><ellipse cx="11.717" cy="6.1734" rx="2.0114" ry="1.9956"/><ellipse cx="6.5219" cy="12.477" rx="2.0114" ry="1.9956"/></g></svg>
+<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ffca5f"><ellipse cx="3.7237" cy="3.0268" rx="2.0114" ry="1.9956"/><ellipse cx="11.717" cy="6.1734" rx="2.0114" ry="1.9956"/><ellipse cx="6.5219" cy="12.477" rx="2.0114" ry="1.9956"/></g></svg>
diff --git a/editor/icons/Polygon2D.svg b/editor/icons/Polygon2D.svg
index b74ba3e342..9d7ad5d1cf 100644
--- a/editor/icons/Polygon2D.svg
+++ b/editor/icons/Polygon2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1050.4h-12v-12h12l-6 6z" fill="#a5b7f3" stroke="#a5b7f3" stroke-linejoin="round" stroke-width="2" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1050.4h-12v-12h12l-6 6z" fill="#8da5f3" stroke="#8da5f3" stroke-linejoin="round" stroke-width="2" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/Portal.svg b/editor/icons/Portal.svg
index e52e0473a6..9365c450da 100644
--- a/editor/icons/Portal.svg
+++ b/editor/icons/Portal.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a5 7 0 0 0 -5 7 5 7 0 0 0 5 7 5 7 0 0 0 5-7 5 7 0 0 0 -5-7zm0 2a3 5 0 0 1 3 5 3 5 0 0 1 -3 5 3 5 0 0 1 -3-5 3 5 0 0 1 3-5z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a5 7 0 0 0 -5 7 5 7 0 0 0 5 7 5 7 0 0 0 5-7 5 7 0 0 0 -5-7zm0 2a3 5 0 0 1 3 5 3 5 0 0 1 -3 5 3 5 0 0 1 -3-5 3 5 0 0 1 3-5z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/Position2D.svg b/editor/icons/Position2D.svg
index d5e7ff9621..191f0b2a03 100644
--- a/editor/icons/Position2D.svg
+++ b/editor/icons/Position2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v4h2v-4zm-6 6v2h4v-2zm10 0v2h4v-2zm-4 4v4h2v-4z" fill="#a5b7f3" fill-opacity=".98824"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v4h2v-4zm-6 6v2h4v-2zm10 0v2h4v-2zm-4 4v4h2v-4z" fill="#8da5f3" fill-opacity=".98824"/></svg>
diff --git a/editor/icons/Position3D.svg b/editor/icons/Position3D.svg
index da7dfb010a..894b195589 100644
--- a/editor/icons/Position3D.svg
+++ b/editor/icons/Position3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v4h2v-4zm-6 6v2h4v-2zm10 0v2h4v-2zm-4 4v4h2v-4z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v4h2v-4zm-6 6v2h4v-2zm10 0v2h4v-2zm-4 4v4h2v-4z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/PrismMesh.svg b/editor/icons/PrismMesh.svg
index bc5f4fb0b1..cca52bb7b0 100644
--- a/editor/icons/PrismMesh.svg
+++ b/editor/icons/PrismMesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9824 1.002a1.0001 1.0001 0 0 0 -.81445.44336l-5.9727 8.9609-.027344.03906a1 1 0 0 0 -.0625.10742 1 1 0 0 0 .44727 1.3418l6 3a1.0001 1.0001 0 0 0 .89453 0l6-3a1 1 0 0 0 .44726-1.3418 1 1 0 0 0 -.0625-.10742l-6-9a1.0001 1.0001 0 0 0 -.84961-.44336zm-.98242 4.3008v7.0801l-3.5391-1.7715zm2 0 3.5391 5.3086-3.5391 1.7715z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9824 1.002a1.0001 1.0001 0 0 0 -.81445.44336l-5.9727 8.9609-.027344.03906a1 1 0 0 0 -.0625.10742 1 1 0 0 0 .44727 1.3418l6 3a1.0001 1.0001 0 0 0 .89453 0l6-3a1 1 0 0 0 .44726-1.3418 1 1 0 0 0 -.0625-.10742l-6-9a1.0001 1.0001 0 0 0 -.84961-.44336zm-.98242 4.3008v7.0801l-3.5391-1.7715zm2 0 3.5391 5.3086-3.5391 1.7715z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/ProceduralSkyMaterial.svg b/editor/icons/ProceduralSkyMaterial.svg
index 9aa362d8da..ceaf56dbce 100644
--- a/editor/icons/ProceduralSkyMaterial.svg
+++ b/editor/icons/ProceduralSkyMaterial.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.0761719 11a7 7 0 0 0 .609375 2h12.6308591a7 7 0 0 0 .609375-2h-9.925781c0 .554-.446 1-1 1h-1c-.554 0-1-.446-1-1z" fill="#9f70ff"/><path d="m1.0722656 9a7 7 0 0 0 -.0722656 1 7 7 0 0 0 .0761719 1h.9238281c0-.554.446-1 1-1h1c.554 0 1 .446 1 1h9.925781a7 7 0 0 0 .074219-1 7 7 0 0 0 -.072266-1h-2.927734-1c0 .554-.446 1-1 1h-2c-.554 0-1-.446-1-1z" fill="#70deff"/><path d="m1.6757812 7a7 7 0 0 0 -.6035156 2h5.9277344c0-.554.446-1 1-1h1c0-.554.446-1 1-1zm10.3242188 0c.554 0 1 .446 1 1s-.446 1-1 1h2.927734a7 7 0 0 0 -.603515-2z" fill="#70ffb9"/><path d="m3.1035156 5a7 7 0 0 0 -1.4277344 2h12.6484378a7 7 0 0 0 -1.425781-2z" fill="#9dff70"/><path d="m8 3a7 7 0 0 0 -4.8964844 2h9.7949224a7 7 0 0 0 -4.898438-2z" fill="#ffeb70"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.0761719 11a7 7 0 0 0 .609375 2h12.6308591a7 7 0 0 0 .609375-2h-9.925781c0 .554-.446 1-1 1h-1c-.554 0-1-.446-1-1z" fill="#8045ff"/><path d="m1.0722656 9a7 7 0 0 0 -.0722656 1 7 7 0 0 0 .0761719 1h.9238281c0-.554.446-1 1-1h1c.554 0 1 .446 1 1h9.925781a7 7 0 0 0 .074219-1 7 7 0 0 0 -.072266-1h-2.927734-1c0 .554-.446 1-1 1h-2c-.554 0-1-.446-1-1z" fill="#45d7ff"/><path d="m1.6757812 7a7 7 0 0 0 -.6035156 2h5.9277344c0-.554.446-1 1-1h1c0-.554.446-1 1-1zm10.3242188 0c.554 0 1 .446 1 1s-.446 1-1 1h2.927734a7 7 0 0 0 -.603515-2z" fill="#45ffa2"/><path d="m3.1035156 5a7 7 0 0 0 -1.4277344 2h12.6484378a7 7 0 0 0 -1.425781-2z" fill="#80ff45"/><path d="m8 3a7 7 0 0 0 -4.8964844 2h9.7949224a7 7 0 0 0 -4.898438-2z" fill="#ffe345"/></svg>
diff --git a/editor/icons/ProgressBar.svg b/editor/icons/ProgressBar.svg
index 2200cb8ea7..5c49563f23 100644
--- a/editor/icons/ProgressBar.svg
+++ b/editor/icons/ProgressBar.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 3c-1.1046 0-2 .89543-2 2v6c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-6c0-1.1046-.89543-2-2-2zm0 2h10v6h-10zm1 1v4h1v-4zm2 0v4h1v-4zm2 0v4h1v-4z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 3c-1.1046 0-2 .89543-2 2v6c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-6c0-1.1046-.89543-2-2-2zm0 2h10v6h-10zm1 1v4h1v-4zm2 0v4h1v-4zm2 0v4h1v-4z" fill="#8eef97"/></svg>
diff --git a/editor/icons/ProximityGroup3D.svg b/editor/icons/ProximityGroup3D.svg
index 703abc6486..5cbf8add7b 100644
--- a/editor/icons/ProximityGroup3D.svg
+++ b/editor/icons/ProximityGroup3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h14v-14zm2 2h10v10h-10zm7.5 1c-.82843.0000048-1.5.67157-1.5 1.5.0000048.82843.67157 1.5 1.5 1.5.82842-.0000048 1.5-.67157 1.5-1.5-.000005-.82843-.67158-1.5-1.5-1.5zm-5 5c-.82843-.0000048-1.5.67157-1.5 1.5-.0000048.82843.67157 1.5 1.5 1.5.82843.000005 1.5-.67157 1.5-1.5.0000048-.82843-.67157-1.5-1.5-1.5zm5 0c-.82843.0000048-1.5.67157-1.5 1.5.0000048.82842.67157 1.5 1.5 1.5.82842-.000005 1.5-.67158 1.5-1.5-.000005-.82843-.67158-1.5-1.5-1.5z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h14v-14zm2 2h10v10h-10zm7.5 1c-.82843.0000048-1.5.67157-1.5 1.5.0000048.82843.67157 1.5 1.5 1.5.82842-.0000048 1.5-.67157 1.5-1.5-.000005-.82843-.67158-1.5-1.5-1.5zm-5 5c-.82843-.0000048-1.5.67157-1.5 1.5-.0000048.82843.67157 1.5 1.5 1.5.82843.000005 1.5-.67157 1.5-1.5.0000048-.82843-.67157-1.5-1.5-1.5zm5 0c-.82843.0000048-1.5.67157-1.5 1.5.0000048.82842.67157 1.5 1.5 1.5.82842-.000005 1.5-.67158 1.5-1.5-.000005-.82843-.67158-1.5-1.5-1.5z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/Quad.svg b/editor/icons/Quad.svg
index cf07be1d2f..70ef6b7227 100644
--- a/editor/icons/Quad.svg
+++ b/editor/icons/Quad.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 10 2h2 12v-2-12h-12zm3.4141 2h8.5859v8.5859zm-1.4141 1.4141 8.5859 8.5859h-8.5859z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 10 2h2 12v-2-12h-12zm3.4141 2h8.5859v8.5859zm-1.4141 1.4141 8.5859 8.5859h-8.5859z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/QuadMesh.svg b/editor/icons/QuadMesh.svg
index bee0b2853f..86cc1bc233 100644
--- a/editor/icons/QuadMesh.svg
+++ b/editor/icons/QuadMesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 1v14h-14v-14zm-2 2h-8.5859l8.5859 8.5859zm-10 1.4141v8.5859h8.5859z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 1v14h-14v-14zm-2 2h-8.5859l8.5859 8.5859zm-10 1.4141v8.5859h8.5859z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/Quat.svg b/editor/icons/Quaternion.svg
index 66020e5243..cf29160ff4 100644
--- a/editor/icons/Quat.svg
+++ b/editor/icons/Quaternion.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 3a3 3 0 0 0 -3 3 3 3 0 0 0 3 3v2h2v-2.7695a3 3 0 0 0 2 .76953h2v-6h-2v4a1 1 0 0 1 -1-1v-3h-2zm0 2v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#ec69a3"/><path d="m4 3v3a3 3 0 0 0 3 3h2v-6h-2v4a1 1 0 0 1 -1-1v-3z" fill="#fff" fill-opacity=".39216"/><path d="m13 1v2h-2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2zm-2 4v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#ec69a3"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 3a3 3 0 0 0 -3 3 3 3 0 0 0 3 3v2h2v-2.7695a3 3 0 0 0 2 .76953h2v-6h-2v4a1 1 0 0 1 -1-1v-3h-2zm0 2v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#ec418e"/><path d="m4 3v3a3 3 0 0 0 3 3h2v-6h-2v4a1 1 0 0 1 -1-1v-3z" fill="#fff" fill-opacity=".39216"/><path d="m13 1v2h-2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2zm-2 4v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#ec418e"/></svg>
diff --git a/editor/icons/RID.svg b/editor/icons/RID.svg
index 9198e421b1..40764867ba 100644
--- a/editor/icons/RID.svg
+++ b/editor/icons/RID.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 2v2h2v-2zm7 0v2h-1a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1 2v-8zm-10 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2zm3 2v4h2v-4zm6 0h1v2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#69ec9a"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 2v2h2v-2zm7 0v2h-1a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1 2v-8zm-10 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2zm3 2v4h2v-4zm6 0h1v2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#41ec80"/></svg>
diff --git a/editor/icons/RayCast2D.svg b/editor/icons/RayCast2D.svg
index 645da1e2da..07c8d45239 100644
--- a/editor/icons/RayCast2D.svg
+++ b/editor/icons/RayCast2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v9h-3l4 5 4-5h-3v-9z" fill="#a5b7f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v9h-3l4 5 4-5h-3v-9z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/RayCast3D.svg b/editor/icons/RayCast3D.svg
index 4500551463..9670e63022 100644
--- a/editor/icons/RayCast3D.svg
+++ b/editor/icons/RayCast3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v9h-3l4 5 4-5h-3v-9z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v9h-3l4 5 4-5h-3v-9z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/Rayito.svg b/editor/icons/Rayito.svg
index 1db71c2231..1d4f9ca458 100644
--- a/editor/icons/Rayito.svg
+++ b/editor/icons/Rayito.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 1-1 7h2.875l-.875 7 9-8h-3.8574l.85742-6h-7z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 1-1 7h2.875l-.875 7 9-8h-3.8574l.85742-6h-7z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/Rect2.svg b/editor/icons/Rect2.svg
index 18dbdf3a12..5b069bd3c1 100644
--- a/editor/icons/Rect2.svg
+++ b/editor/icons/Rect2.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 2v2h-1a3 3 0 0 0 -2.5 1.3457 3 3 0 0 0 -2.5-1.3457 3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1h3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v1a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2zm-10 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2z" fill="#f191a5"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 2v2h-1a3 3 0 0 0 -2.5 1.3457 3 3 0 0 0 -2.5-1.3457 3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1h3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v1a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2zm-10 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2z" fill="#f1738f"/></svg>
diff --git a/editor/icons/Rect2i.svg b/editor/icons/Rect2i.svg
index 142ad88515..76f4fededf 100644
--- a/editor/icons/Rect2i.svg
+++ b/editor/icons/Rect2i.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 2v2h-1c-1.7267 0-3 1.3359-3 3 0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228 0-1-.44772-1-1s.44772-1 1-1h1v1c0 1.6569 1.3431 3 3 3v-2c-.55228 0-.93526-.45152-1-1v-1h1v-2h-1v-2zm-5 2c-1.6569 0-2.9547 1.3438-3 3v3h2v-3c0-.55228.44772-1 1-1h1v-2z" fill="#f191a5"/><path d="m13 2v2h2v-2zm0 4v4h2v-4z" fill="#7dc6ef"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 2v2h-1c-1.7267 0-3 1.3359-3 3 0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228 0-1-.44772-1-1s.44772-1 1-1h1v1c0 1.6569 1.3431 3 3 3v-2c-.55228 0-.93526-.45152-1-1v-1h1v-2h-1v-2zm-5 2c-1.6569 0-2.9547 1.3438-3 3v3h2v-3c0-.55228.44772-1 1-1h1v-2z" fill="#f1738f"/><path d="m13 2v2h2v-2zm0 4v4h2v-4z" fill="#5abbef"/></svg>
diff --git a/editor/icons/RectangleAddRemove.svg b/editor/icons/RectangleAddRemove.svg
new file mode 100644
index 0000000000..87e2155a0d
--- /dev/null
+++ b/editor/icons/RectangleAddRemove.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 2c-.5522619.0000552-.9999448.4477381-1 1v10c.0000552.552262.4477381.999945 1 1h6v-2h-5v-8h10v1h2v-2c-.000055-.5522619-.447738-.9999448-1-1zm9.25 4v2.25h-2.25v1.5h2.25v2.25h1.5v-2.25h2.25v-1.5h-2.25v-2.25zm-2.25 7.5v1.5h6v-1.5z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/ReferenceRect.svg b/editor/icons/ReferenceRect.svg
index 449ca250e3..4ba50b2af2 100644
--- a/editor/icons/ReferenceRect.svg
+++ b/editor/icons/ReferenceRect.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h2v-2zm3 0v2h8v-2zm9 0v2h2v-2zm-12 3v8h2v-8zm12 0v8h2v-8zm-12 9v2h2v-2zm3 0v2h8v-2zm9 0v2h2v-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h2v-2zm3 0v2h8v-2zm9 0v2h2v-2zm-12 3v8h2v-8zm12 0v8h2v-8zm-12 9v2h2v-2zm3 0v2h8v-2zm9 0v2h2v-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/ReflectionProbe.svg b/editor/icons/ReflectionProbe.svg
index ff9263d798..a88a3524be 100644
--- a/editor/icons/ReflectionProbe.svg
+++ b/editor/icons/ReflectionProbe.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10 2a1.0001 1.0001 0 1 0 0 2h1.5859l-4.5195 4.5195-4.2988-5.1582-1.5352 1.2793 5 6a1.0001 1.0001 0 0 0 1.4746.064453l5.293-5.293v1.5879a1.0001 1.0001 0 1 0 2 0v-4a1.0001 1.0001 0 0 0 -1-1h-4zm-9 7v5a1.0001 1.0001 0 0 0 1 1h12a1.0001 1.0001 0 0 0 1-1v-4h-2v3h-10v-4z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10 2a1.0001 1.0001 0 1 0 0 2h1.5859l-4.5195 4.5195-4.2988-5.1582-1.5352 1.2793 5 6a1.0001 1.0001 0 0 0 1.4746.064453l5.293-5.293v1.5879a1.0001 1.0001 0 1 0 2 0v-4a1.0001 1.0001 0 0 0 -1-1h-4zm-9 7v5a1.0001 1.0001 0 0 0 1 1h12a1.0001 1.0001 0 0 0 1-1v-4h-2v3h-10v-4z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/RemoteTransform2D.svg b/editor/icons/RemoteTransform2D.svg
index 81a3946d9f..9d03db5c3b 100644
--- a/editor/icons/RemoteTransform2D.svg
+++ b/editor/icons/RemoteTransform2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.8565 0-5.4995 1.5262-6.9277 4a1 1 0 0 0 .36523 1.3672 1 1 0 0 0 1.3672-.36719c1.0726-1.8578 3.0501-3 5.1953-3s4.1227 1.1422 5.1953 3a1 1 0 0 0 1.3672.36719 1 1 0 0 0 .36523-1.3672c-1.4283-2.4738-4.0712-4-6.9277-4zm0 4c-1.8056 0-3.396 1.2207-3.8633 2.9648a1 1 0 0 0 .70703 1.2246 1 1 0 0 0 1.2246-.70703c.23553-.8791 1.0216-1.4824 1.9316-1.4824s1.6961.60332 1.9316 1.4824a1 1 0 0 0 1.2246.70703 1 1 0 0 0 .70703-1.2246c-.46732-1.7441-2.0577-2.9648-3.8633-2.9648zm0 4c-.554 0-1 .446-1 1v1h-3a4 4 0 0 0 2 3.4648 4 4 0 0 0 4 0 4 4 0 0 0 2-3.4648h-3v-1c0-.554-.446-1-1-1z" fill="#a5b7f3" fill-opacity=".98824"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.8565 0-5.4995 1.5262-6.9277 4a1 1 0 0 0 .36523 1.3672 1 1 0 0 0 1.3672-.36719c1.0726-1.8578 3.0501-3 5.1953-3s4.1227 1.1422 5.1953 3a1 1 0 0 0 1.3672.36719 1 1 0 0 0 .36523-1.3672c-1.4283-2.4738-4.0712-4-6.9277-4zm0 4c-1.8056 0-3.396 1.2207-3.8633 2.9648a1 1 0 0 0 .70703 1.2246 1 1 0 0 0 1.2246-.70703c.23553-.8791 1.0216-1.4824 1.9316-1.4824s1.6961.60332 1.9316 1.4824a1 1 0 0 0 1.2246.70703 1 1 0 0 0 .70703-1.2246c-.46732-1.7441-2.0577-2.9648-3.8633-2.9648zm0 4c-.554 0-1 .446-1 1v1h-3a4 4 0 0 0 2 3.4648 4 4 0 0 0 4 0 4 4 0 0 0 2-3.4648h-3v-1c0-.554-.446-1-1-1z" fill="#8da5f3" fill-opacity=".98824"/></svg>
diff --git a/editor/icons/RemoteTransform3D.svg b/editor/icons/RemoteTransform3D.svg
index d55e4e4224..96cd31a2df 100644
--- a/editor/icons/RemoteTransform3D.svg
+++ b/editor/icons/RemoteTransform3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.8565 0-5.4995 1.5262-6.9277 4a1 1 0 0 0 .36523 1.3672 1 1 0 0 0 1.3672-.36719c1.0726-1.8578 3.0501-3 5.1953-3s4.1227 1.1422 5.1953 3a1 1 0 0 0 1.3672.36719 1 1 0 0 0 .36523-1.3672c-1.4283-2.4738-4.0712-4-6.9277-4zm0 4c-1.8056 0-3.396 1.2207-3.8633 2.9648a1 1 0 0 0 .70703 1.2246 1 1 0 0 0 1.2246-.70703c.23553-.8791 1.0216-1.4824 1.9316-1.4824s1.6961.60332 1.9316 1.4824a1 1 0 0 0 1.2246.70703 1 1 0 0 0 .70703-1.2246c-.46732-1.7441-2.0577-2.9648-3.8633-2.9648zm0 4c-.554 0-1 .446-1 1v1h-3a4 4 0 0 0 2 3.4648 4 4 0 0 0 4 0 4 4 0 0 0 2-3.4648h-3v-1c0-.554-.446-1-1-1z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.8565 0-5.4995 1.5262-6.9277 4a1 1 0 0 0 .36523 1.3672 1 1 0 0 0 1.3672-.36719c1.0726-1.8578 3.0501-3 5.1953-3s4.1227 1.1422 5.1953 3a1 1 0 0 0 1.3672.36719 1 1 0 0 0 .36523-1.3672c-1.4283-2.4738-4.0712-4-6.9277-4zm0 4c-1.8056 0-3.396 1.2207-3.8633 2.9648a1 1 0 0 0 .70703 1.2246 1 1 0 0 0 1.2246-.70703c.23553-.8791 1.0216-1.4824 1.9316-1.4824s1.6961.60332 1.9316 1.4824a1 1 0 0 0 1.2246.70703 1 1 0 0 0 .70703-1.2246c-.46732-1.7441-2.0577-2.9648-3.8633-2.9648zm0 4c-.554 0-1 .446-1 1v1h-3a4 4 0 0 0 2 3.4648 4 4 0 0 0 4 0 4 4 0 0 0 2-3.4648h-3v-1c0-.554-.446-1-1-1z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/Reparent.svg b/editor/icons/Reparent.svg
index 04efb08b99..e95eb742db 100644
--- a/editor/icons/Reparent.svg
+++ b/editor/icons/Reparent.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v5.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h6.541a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -.72852-.73047v-5.541a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2z" fill="#e0e0e0"/><path d="m9 1-4 3 4 3v-2a3 3 0 0 1 3 3v2h2v-2a5 5 0 0 0 -5-5z" fill="#84ffb1"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7305v5.541a2 2 0 0 0 -1 1.7285 2 2 0 0 0 2 2 2 2 0 0 0 1.7305-1h6.541a2 2 0 0 0 1.7285 1 2 2 0 0 0 2-2 2 2 0 0 0 -2-2 2 2 0 0 0 -1.7305 1h-6.541a2 2 0 0 0 -.72852-.73047v-5.541a2 2 0 0 0 1-1.7285 2 2 0 0 0 -2-2z" fill="#e0e0e0"/><path d="m9 1-4 3 4 3v-2a3 3 0 0 1 3 3v2h2v-2a5 5 0 0 0 -5-5z" fill="#5fff97"/></svg>
diff --git a/editor/icons/ReparentToNewNode.svg b/editor/icons/ReparentToNewNode.svg
index cca610d2b1..f28a04a19e 100644
--- a/editor/icons/ReparentToNewNode.svg
+++ b/editor/icons/ReparentToNewNode.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m1.4915254 13c0 1.104569.8954305 2 2 2 .7139771-.000554 1.3735116-.381677 1.7305-1h6.0494746c.356631.617705 1.015238.998733 1.7285 1 1.104569 0 2-.895431 2-2s-.895431-2-2-2c-.713977.000554-1.373512.381677-1.7305 1h-6.0494746c-.1747809-.30301-.8483719-1-1.7285-1-.9027301 0-2 .891221-2 2z" fill="#e0e0e0" transform="translate(0 1036.4)"/><path d="m10.421845 1038.2814-2.7947264 2.096 2.7947264 2.0961v-1.3974c2.716918 0 2.180792 1.4469 2.180792 3.9265v1.3974h1.397363v-1.3974c0-3.863.13086-5.3239-3.578155-5.3239z" fill="#84ffb1" stroke-width=".698682"/><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#84ffb1" transform="translate(-8.5 1028.4)"/><path d="m4.5 1047.7968v-3.1171h-2.0000005v3.1171z" fill="#e0e0e0" stroke-width=".717839"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m1.4915254 13c0 1.104569.8954305 2 2 2 .7139771-.000554 1.3735116-.381677 1.7305-1h6.0494746c.356631.617705 1.015238.998733 1.7285 1 1.104569 0 2-.895431 2-2s-.895431-2-2-2c-.713977.000554-1.373512.381677-1.7305 1h-6.0494746c-.1747809-.30301-.8483719-1-1.7285-1-.9027301 0-2 .891221-2 2z" fill="#e0e0e0" transform="translate(0 1036.4)"/><path d="m10.421845 1038.2814-2.7947264 2.096 2.7947264 2.0961v-1.3974c2.716918 0 2.180792 1.4469 2.180792 3.9265v1.3974h1.397363v-1.3974c0-3.863.13086-5.3239-3.578155-5.3239z" fill="#5fff97" stroke-width=".698682"/><path d="m11 9v2h-2v2h2v2h2v-2h2v-2h-2v-2z" fill="#5fff97" transform="translate(-8.5 1028.4)"/><path d="m4.5 1047.7968v-3.1171h-2.0000005v3.1171z" fill="#e0e0e0" stroke-width=".717839"/></g></svg>
diff --git a/editor/icons/RibbonTrailMesh.svg b/editor/icons/RibbonTrailMesh.svg
new file mode 100644
index 0000000000..3f6cf0bfef
--- /dev/null
+++ b/editor/icons/RibbonTrailMesh.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ffca5f" stroke-width=".25" transform="rotate(90)"><path d="m6.5625-14.062499h1.875v13.124999h-1.875z"/><path d="m.9375-11.249999h1.875v7.499999h-1.875z"/><path d="m12.187499-11.249999h1.875v7.5h-1.875z"/></g></svg>
diff --git a/editor/icons/RichTextEffect.svg b/editor/icons/RichTextEffect.svg
index f1d3f168ff..3745219934 100644
--- a/editor/icons/RichTextEffect.svg
+++ b/editor/icons/RichTextEffect.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h7v-2zm9 0v2h5v-2zm-9 4v2h11v-2zm0 4v2h4v-2zm6 0v2h1c-.044949-.094701-.088906-.20229-.125-.3418-.077717-.30039-.10439-.81722.16406-1.293.081489-.1441.18202-.26127.28906-.36523zm-6 4v2h8.2812c-.066517-.011548-.1231-.014758-.20117-.037109-.30195-.08645-.76491-.33245-1.0352-.80664-.23366-.4121-.24101-.84933-.18945-1.1562z" fill="#e0e0e0"/><path d="m12.216 8.598a.53334 3.2001 0 0 0 -.50976 2.2754 3.2001.53334 30 0 0 -2.2656-.71484 3.2001.53334 30 0 0 1.75 1.6016.53334 3.2001 60 0 0 -1.7461 1.5996.53334 3.2001 60 0 0 2.2578-.71094.53334 3.2001 0 0 0 .51367 2.3496.53334 3.2001 0 0 0 .51367-2.3516 3.2001.53334 30 0 0 2.2539.71094 3.2001.53334 30 0 0 -1.7441-1.5977.53334 3.2001 60 0 0 1.748-1.5996.53334 3.2001 60 0 0 -2.2617.71484.53334 3.2001 0 0 0 -.50977-2.2773z" fill="#cea4f1" stroke-width="1.0667"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h7v-2zm9 0v2h5v-2zm-9 4v2h11v-2zm0 4v2h4v-2zm6 0v2h1c-.044949-.094701-.088906-.20229-.125-.3418-.077717-.30039-.10439-.81722.16406-1.293.081489-.1441.18202-.26127.28906-.36523zm-6 4v2h8.2812c-.066517-.011548-.1231-.014758-.20117-.037109-.30195-.08645-.76491-.33245-1.0352-.80664-.23366-.4121-.24101-.84933-.18945-1.1562z" fill="#e0e0e0"/><path d="m12.216 8.598a.53334 3.2001 0 0 0 -.50976 2.2754 3.2001.53334 30 0 0 -2.2656-.71484 3.2001.53334 30 0 0 1.75 1.6016.53334 3.2001 60 0 0 -1.7461 1.5996.53334 3.2001 60 0 0 2.2578-.71094.53334 3.2001 0 0 0 .51367 2.3496.53334 3.2001 0 0 0 .51367-2.3516 3.2001.53334 30 0 0 2.2539.71094 3.2001.53334 30 0 0 -1.7441-1.5977.53334 3.2001 60 0 0 1.748-1.5996.53334 3.2001 60 0 0 -2.2617.71484.53334 3.2001 0 0 0 -.50977-2.2773z" fill="#c38ef1" stroke-width="1.0667"/></svg>
diff --git a/editor/icons/RichTextLabel.svg b/editor/icons/RichTextLabel.svg
index 7283d3dd62..14c1af3ea3 100644
--- a/editor/icons/RichTextLabel.svg
+++ b/editor/icons/RichTextLabel.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h8v-2zm12 0-3 3h2v8h-2l3 3 3-3h-2v-8h2zm-12 4v2h2v-2zm4 0v2h4v-2zm-4 4v2h8v-2zm0 4v2h4v-2zm6 0v2h2v-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h8v-2zm12 0-3 3h2v8h-2l3 3 3-3h-2v-8h2zm-12 4v2h2v-2zm4 0v2h4v-2zm-4 4v2h8v-2zm0 4v2h4v-2zm6 0v2h2v-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/RigidBody2D.svg b/editor/icons/RigidBody2D.svg
index 9dc626b94e..5d08e991ae 100644
--- a/editor/icons/RigidBody2D.svg
+++ b/editor/icons/RigidBody2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 1.2227 3.9531 7 7 0 0 0 .30273.4082c.000785-.00256.0011667-.005252.0019532-.007812a7 7 0 0 0 5.4727 2.6465 7 7 0 0 0 3.2422-.80273c.001375.000393.002531.00156.003906.001953a7 7 0 0 0 .035156-.021485 7 7 0 0 0 .42578-.25 7 7 0 0 0 .16992-.10352 7 7 0 0 0 .36914-.26953 7 7 0 0 0 .20508-.15625 7 7 0 0 0 .3418-.30859 7 7 0 0 0 .16406-.1543 7 7 0 0 0 .33008-.36133 7 7 0 0 0 .14062-.16016 7 7 0 0 0 .27734-.37305 7 7 0 0 0 .13867-.19531 7 7 0 0 0 .21875-.36133 7 7 0 0 0 .14258-.25 7 7 0 0 0 .15625-.33398 7 7 0 0 0 .13867-.31055 7 7 0 0 0 .10742-.30859 7 7 0 0 0 .11914-.35352 7 7 0 0 0 .087891-.36914 7 7 0 0 0 .066406-.29297 7 7 0 0 0 .056641-.40039 7 7 0 0 0 .037109-.3125 7 7 0 0 0 .025391-.55273 7 7 0 0 0 -4.3926-6.4922 7 7 0 0 0 -.001953 0 7 7 0 0 0 -.66016-.22852 7 7 0 0 0 -.0058594-.0019531 7 7 0 0 0 -.55078-.13086 7 7 0 0 0 -.14062-.03125 7 7 0 0 0 -.55078-.072266 7 7 0 0 0 -.14258-.017578 7 7 0 0 0 -.55469-.025391zm1.9512 1.334a6 6 0 0 1 4.0488 5.666h-7a2 2 0 0 0 -.94922-1.6992c1.3464-2.0289 2.6038-3.2631 3.9004-3.9668zm-6.8281 2.1797c.14632.65093.35776 1.2833.68359 1.8848a2 2 0 0 0 -.80664 1.6016h-1a6 6 0 0 1 1.123-3.4863zm1.877 1.4863a2 2 0 0 0 -.10938.0039062 2 2 0 0 1 .10938-.0039062zm-.18945.011719a2 2 0 0 0 -.12109.013672 2 2 0 0 1 .12109-.013672zm-.44141.09375a2 2 0 0 0 -.056641.019531 2 2 0 0 1 .056641-.019531zm-1.3594 2.0605a2 2 0 0 0 .013672.11914 2 2 0 0 1 -.013672-.11914zm.027344.20898a2 2 0 0 0 .017578.080078 2 2 0 0 1 -.017578-.080078zm.73438 1.1992a2 2 0 0 0 1.2285.42578 2 2 0 0 0 1.0508-.30078c1.345 2.0268 2.6013 3.2645 3.8965 3.9688a6 6 0 0 1 -1.9473.33203 6 6 0 0 1 -5.0547-2.7695c.23771-.5785.50336-1.1403.82617-1.6563z" fill="#a5b7f3" fill-opacity=".98824"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 1.2227 3.9531 7 7 0 0 0 .30273.4082c.000785-.00256.0011667-.005252.0019532-.007812a7 7 0 0 0 5.4727 2.6465 7 7 0 0 0 3.2422-.80273c.001375.000393.002531.00156.003906.001953a7 7 0 0 0 .035156-.021485 7 7 0 0 0 .42578-.25 7 7 0 0 0 .16992-.10352 7 7 0 0 0 .36914-.26953 7 7 0 0 0 .20508-.15625 7 7 0 0 0 .3418-.30859 7 7 0 0 0 .16406-.1543 7 7 0 0 0 .33008-.36133 7 7 0 0 0 .14062-.16016 7 7 0 0 0 .27734-.37305 7 7 0 0 0 .13867-.19531 7 7 0 0 0 .21875-.36133 7 7 0 0 0 .14258-.25 7 7 0 0 0 .15625-.33398 7 7 0 0 0 .13867-.31055 7 7 0 0 0 .10742-.30859 7 7 0 0 0 .11914-.35352 7 7 0 0 0 .087891-.36914 7 7 0 0 0 .066406-.29297 7 7 0 0 0 .056641-.40039 7 7 0 0 0 .037109-.3125 7 7 0 0 0 .025391-.55273 7 7 0 0 0 -4.3926-6.4922 7 7 0 0 0 -.001953 0 7 7 0 0 0 -.66016-.22852 7 7 0 0 0 -.0058594-.0019531 7 7 0 0 0 -.55078-.13086 7 7 0 0 0 -.14062-.03125 7 7 0 0 0 -.55078-.072266 7 7 0 0 0 -.14258-.017578 7 7 0 0 0 -.55469-.025391zm1.9512 1.334a6 6 0 0 1 4.0488 5.666h-7a2 2 0 0 0 -.94922-1.6992c1.3464-2.0289 2.6038-3.2631 3.9004-3.9668zm-6.8281 2.1797c.14632.65093.35776 1.2833.68359 1.8848a2 2 0 0 0 -.80664 1.6016h-1a6 6 0 0 1 1.123-3.4863zm1.877 1.4863a2 2 0 0 0 -.10938.0039062 2 2 0 0 1 .10938-.0039062zm-.18945.011719a2 2 0 0 0 -.12109.013672 2 2 0 0 1 .12109-.013672zm-.44141.09375a2 2 0 0 0 -.056641.019531 2 2 0 0 1 .056641-.019531zm-1.3594 2.0605a2 2 0 0 0 .013672.11914 2 2 0 0 1 -.013672-.11914zm.027344.20898a2 2 0 0 0 .017578.080078 2 2 0 0 1 -.017578-.080078zm.73438 1.1992a2 2 0 0 0 1.2285.42578 2 2 0 0 0 1.0508-.30078c1.345 2.0268 2.6013 3.2645 3.8965 3.9688a6 6 0 0 1 -1.9473.33203 6 6 0 0 1 -5.0547-2.7695c.23771-.5785.50336-1.1403.82617-1.6563z" fill="#8da5f3" fill-opacity=".98824"/></svg>
diff --git a/editor/icons/RigidBody3D.svg b/editor/icons/RigidBody3D.svg
index 476bf3966a..7f5db4ce88 100644
--- a/editor/icons/RigidBody3D.svg
+++ b/editor/icons/RigidBody3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 .035156.69922 7 7 0 0 0 .27734 1.3691 7 7 0 0 0 .91016 1.8848 7 7 0 0 0 .30273.4082c.000785-.00256.0011667-.005252.0019532-.007812a7 7 0 0 0 5.4727 2.6465 7 7 0 0 0 3.2422-.80273c.001374.000393.002531.00156.003906.001953a7 7 0 0 0 .035156-.021485 7 7 0 0 0 .42578-.25 7 7 0 0 0 .16992-.10352 7 7 0 0 0 .36914-.26953 7 7 0 0 0 .20508-.15625 7 7 0 0 0 .3418-.30859 7 7 0 0 0 .16406-.1543 7 7 0 0 0 .33008-.36133 7 7 0 0 0 .14062-.16016 7 7 0 0 0 .27734-.37305 7 7 0 0 0 .13867-.19531 7 7 0 0 0 .21875-.36133 7 7 0 0 0 .14258-.25 7 7 0 0 0 .15625-.33398 7 7 0 0 0 .13867-.31055 7 7 0 0 0 .10742-.30859 7 7 0 0 0 .11914-.35352 7 7 0 0 0 .087891-.36914 7 7 0 0 0 .066406-.29297 7 7 0 0 0 .056641-.40039 7 7 0 0 0 .037109-.3125 7 7 0 0 0 .025391-.55273 7 7 0 0 0 -4.3848-6.4883 7 7 0 0 0 -.007812-.0039063 7 7 0 0 0 -.001953 0 7 7 0 0 0 -.61523-.21289 7 7 0 0 0 -.044922-.015625 7 7 0 0 0 -.0058594-.0019531 7 7 0 0 0 -.55078-.13086 7 7 0 0 0 -.14062-.03125 7 7 0 0 0 -.55078-.072266 7 7 0 0 0 -.14258-.017578 7 7 0 0 0 -.55469-.025391zm1.9512 1.334a6 6 0 0 1 4.0488 5.666h-7a2 2 0 0 0 -.94922-1.6992c1.3464-2.0289 2.6038-3.2631 3.9004-3.9668zm-6.8281 2.1797c.14632.65093.35776 1.2833.68359 1.8848a2 2 0 0 0 -.80664 1.6016h-1a6 6 0 0 1 1.123-3.4863zm1.877 1.4863a2 2 0 0 0 -.10938.0039062 2 2 0 0 1 .10938-.0039062zm-.18945.011719a2 2 0 0 0 -.12109.013672 2 2 0 0 1 .12109-.013672zm-.44141.09375a2 2 0 0 0 -.056641.019531 2 2 0 0 1 .056641-.019531zm-1.3594 2.0605a2 2 0 0 0 .013672.11914 2 2 0 0 1 -.013672-.11914zm.027344.20898a2 2 0 0 0 .017578.080078 2 2 0 0 1 -.017578-.080078zm.73438 1.1992a2 2 0 0 0 1.2285.42578 2 2 0 0 0 1.0508-.30078c1.345 2.0268 2.6013 3.2645 3.8965 3.9688a6 6 0 0 1 -1.9473.33203 6 6 0 0 1 -5.0547-2.7695c.23771-.5785.50336-1.1403.82617-1.6563z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 .035156.69922 7 7 0 0 0 .27734 1.3691 7 7 0 0 0 .91016 1.8848 7 7 0 0 0 .30273.4082c.000785-.00256.0011667-.005252.0019532-.007812a7 7 0 0 0 5.4727 2.6465 7 7 0 0 0 3.2422-.80273c.001374.000393.002531.00156.003906.001953a7 7 0 0 0 .035156-.021485 7 7 0 0 0 .42578-.25 7 7 0 0 0 .16992-.10352 7 7 0 0 0 .36914-.26953 7 7 0 0 0 .20508-.15625 7 7 0 0 0 .3418-.30859 7 7 0 0 0 .16406-.1543 7 7 0 0 0 .33008-.36133 7 7 0 0 0 .14062-.16016 7 7 0 0 0 .27734-.37305 7 7 0 0 0 .13867-.19531 7 7 0 0 0 .21875-.36133 7 7 0 0 0 .14258-.25 7 7 0 0 0 .15625-.33398 7 7 0 0 0 .13867-.31055 7 7 0 0 0 .10742-.30859 7 7 0 0 0 .11914-.35352 7 7 0 0 0 .087891-.36914 7 7 0 0 0 .066406-.29297 7 7 0 0 0 .056641-.40039 7 7 0 0 0 .037109-.3125 7 7 0 0 0 .025391-.55273 7 7 0 0 0 -4.3848-6.4883 7 7 0 0 0 -.007812-.0039063 7 7 0 0 0 -.001953 0 7 7 0 0 0 -.61523-.21289 7 7 0 0 0 -.044922-.015625 7 7 0 0 0 -.0058594-.0019531 7 7 0 0 0 -.55078-.13086 7 7 0 0 0 -.14062-.03125 7 7 0 0 0 -.55078-.072266 7 7 0 0 0 -.14258-.017578 7 7 0 0 0 -.55469-.025391zm1.9512 1.334a6 6 0 0 1 4.0488 5.666h-7a2 2 0 0 0 -.94922-1.6992c1.3464-2.0289 2.6038-3.2631 3.9004-3.9668zm-6.8281 2.1797c.14632.65093.35776 1.2833.68359 1.8848a2 2 0 0 0 -.80664 1.6016h-1a6 6 0 0 1 1.123-3.4863zm1.877 1.4863a2 2 0 0 0 -.10938.0039062 2 2 0 0 1 .10938-.0039062zm-.18945.011719a2 2 0 0 0 -.12109.013672 2 2 0 0 1 .12109-.013672zm-.44141.09375a2 2 0 0 0 -.056641.019531 2 2 0 0 1 .056641-.019531zm-1.3594 2.0605a2 2 0 0 0 .013672.11914 2 2 0 0 1 -.013672-.11914zm.027344.20898a2 2 0 0 0 .017578.080078 2 2 0 0 1 -.017578-.080078zm.73438 1.1992a2 2 0 0 0 1.2285.42578 2 2 0 0 0 1.0508-.30078c1.345 2.0268 2.6013 3.2645 3.8965 3.9688a6 6 0 0 1 -1.9473.33203 6 6 0 0 1 -5.0547-2.7695c.23771-.5785.50336-1.1403.82617-1.6563z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/Room.svg b/editor/icons/Room.svg
index 6491d0409c..2bc165e736 100644
--- a/editor/icons/Room.svg
+++ b/editor/icons/Room.svg
@@ -1 +1 @@
-<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-6 3a1.0001 1.0001 0 0 0 -.55273.89453v6a1.0001 1.0001 0 0 0 .55273.89453l6 3a1.0001 1.0001 0 0 0 .89453 0l6-3a1.0001 1.0001 0 0 0 .55273-.89453v-6a1.0001 1.0001 0 0 0 -.55273-.89453l-6-3a1.0001 1.0001 0 0 0 -.48438-.10352zm1.0371 2.6172 4 2v3.7637l-4-2zm-1 5.5 3.7637 1.8809-3.7637 1.8828-3.7637-1.8828z" fill="#fc9c9c" fill-opacity=".99608" fill-rule="evenodd"/></svg>
+<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-6 3a1.0001 1.0001 0 0 0 -.55273.89453v6a1.0001 1.0001 0 0 0 .55273.89453l6 3a1.0001 1.0001 0 0 0 .89453 0l6-3a1.0001 1.0001 0 0 0 .55273-.89453v-6a1.0001 1.0001 0 0 0 -.55273-.89453l-6-3a1.0001 1.0001 0 0 0 -.48438-.10352zm1.0371 2.6172 4 2v3.7637l-4-2zm-1 5.5 3.7637 1.8809-3.7637 1.8828-3.7637-1.8828z" fill="#fc7f7f" fill-opacity=".99608" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/RootMotionView.svg b/editor/icons/RootMotionView.svg
index f2d23e5b9f..051b95543c 100644
--- a/editor/icons/RootMotionView.svg
+++ b/editor/icons/RootMotionView.svg
@@ -1 +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"><radialGradient id="a" cx="8" cy="8" gradientTransform="matrix(.85714281 -.00000007 .00000004 .85714284 1.142858 1.142858)" gradientUnits="userSpaceOnUse" r="7"><stop offset="0" stop-color="#fc9c9c"/><stop offset=".83333331" stop-color="#fc9c9c" stop-opacity=".701961"/><stop offset="1" stop-color="#fc9c9c" stop-opacity="0"/></radialGradient><path d="m5 2v3h-3v2h3v2h-3v2h3v3h2v-3h2v3h2v-3h3v-2h-3v-2h3v-2h-3v-3h-2v3h-2v-3zm2 5h2v2h-2z" fill="url(#a)"/></svg>
+<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"><radialGradient id="a" cx="8" cy="8" gradientTransform="matrix(.85714281 -.00000007 .00000004 .85714284 1.142858 1.142858)" gradientUnits="userSpaceOnUse" r="7"><stop offset="0" stop-color="#fc7f7f"/><stop offset=".83333331" stop-color="#fc7f7f" stop-opacity=".701961"/><stop offset="1" stop-color="#fc7f7f" stop-opacity="0"/></radialGradient><path d="m5 2v3h-3v2h3v2h-3v2h3v3h2v-3h2v3h2v-3h3v-2h-3v-2h3v-2h-3v-3h-2v3h-2v-3zm2 5h2v2h-2z" fill="url(#a)"/></svg>
diff --git a/editor/icons/SampleLibrary.svg b/editor/icons/SampleLibrary.svg
index 962f7b9413..a5f86d7f3c 100644
--- a/editor/icons/SampleLibrary.svg
+++ b/editor/icons/SampleLibrary.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.0215 1.002a1.0001 1.0001 0 0 0 -1 .875l-.58984 4.7227-.52344-1.0469a1.0001 1.0001 0 0 0 -.89453-.55273h-2a1.0001 1.0001 0 1 0 0 2h1.3828l1.7227 3.4473a1.0001 1.0001 0 0 0 1.8867-.32227l.58984-4.7227.52344 1.0449a1.0001 1.0001 0 0 0 .89453.55273h3a1.0001 1.0001 0 1 0 0-2h-2.3809l-1.7246-3.4473a1.0001 1.0001 0 0 0 -.88672-.55078zm1.9785 6.998v1 5 1h5c.55228 0 1-.44772 1-1v-5c0-.55228-.44772-1-1-1v4l-1-1-1 1v-4z" fill="#ff8484"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.0215 1.002a1.0001 1.0001 0 0 0 -1 .875l-.58984 4.7227-.52344-1.0469a1.0001 1.0001 0 0 0 -.89453-.55273h-2a1.0001 1.0001 0 1 0 0 2h1.3828l1.7227 3.4473a1.0001 1.0001 0 0 0 1.8867-.32227l.58984-4.7227.52344 1.0449a1.0001 1.0001 0 0 0 .89453.55273h3a1.0001 1.0001 0 1 0 0-2h-2.3809l-1.7246-3.4473a1.0001 1.0001 0 0 0 -.88672-.55078zm1.9785 6.998v1 5 1h5c.55228 0 1-.44772 1-1v-5c0-.55228-.44772-1-1-1v4l-1-1-1 1v-4z" fill="#ff5f5f"/></svg>
diff --git a/editor/icons/ScriptCreate.svg b/editor/icons/ScriptCreate.svg
index 91e95eb8c7..564dcddc2e 100644
--- a/editor/icons/ScriptCreate.svg
+++ b/editor/icons/ScriptCreate.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" 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.13477v1h5 1v-1h-1v-4h2v-2h2v-3h3v-2c0-1.1046-.89543-2-2-2z" fill="#e0e0e0" transform="translate(0 1036.4)"/><path d="m6 1c-1.1046 0-2 .89543-2 2v7h-2-1v1 2c0 1.1046.89543 2 2 2s2-.89543 2-2v-10c0-.55228.44772-1 1-1s1 .44772 1 1v1 1 1h1 4v-1h-4v-1-1c0-1.1046-.89543-2-2-2zm-4 10h2v2c0 .55228-.44772 1-1 1s-1-.44772-1-1z" fill="#b4b4b4" transform="translate(0 1036.4)"/><circle cx="3" cy="1048.4" fill="#e0e0e0"/><path d="m13 1049.4h2v-2h-2v-2h-2v2h-2v2h2v2h2z" fill="#84ffb1" fill-rule="evenodd"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" 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.13477v1h5 1v-1h-1v-4h2v-2h2v-3h3v-2c0-1.1046-.89543-2-2-2z" fill="#e0e0e0" transform="translate(0 1036.4)"/><path d="m6 1c-1.1046 0-2 .89543-2 2v7h-2-1v1 2c0 1.1046.89543 2 2 2s2-.89543 2-2v-10c0-.55228.44772-1 1-1s1 .44772 1 1v1 1 1h1 4v-1h-4v-1-1c0-1.1046-.89543-2-2-2zm-4 10h2v2c0 .55228-.44772 1-1 1s-1-.44772-1-1z" fill="#b4b4b4" transform="translate(0 1036.4)"/><circle cx="3" cy="1048.4" fill="#e0e0e0"/><path d="m13 1049.4h2v-2h-2v-2h-2v2h-2v2h2v2h2z" fill="#5fff97" fill-rule="evenodd"/></g></svg>
diff --git a/editor/icons/ScriptRemove.svg b/editor/icons/ScriptRemove.svg
index b455583a6c..9af184c946 100644
--- a/editor/icons/ScriptRemove.svg
+++ b/editor/icons/ScriptRemove.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" 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.13477v1h5.6348l-1.584-1.584 1.4141-1.4141-1.4141-1.416 3.5352-3.5352 1.4141 1.4141v-.46484-3h3v-2c0-1.1046-.89543-2-2-2h-7z" fill="#e0e0e0" transform="translate(0 1036.4)"/><path d="m6 1c-1.1046 0-2 .89543-2 2v7h-2-1v1 2c0 1.1046.89543 2 2 2s2-.89543 2-2v-10c0-.55228.44772-1 1-1s1 .44772 1 1v1 1 1h1 4v-1h-4v-1-1c0-1.1046-.89543-2-2-2zm-4 10h2v2c0 .55228-.44772 1-1 1s-1-.44772-1-1z" fill="#b4b4b4" transform="translate(0 1036.4)"/><circle cx="3" cy="1048.4" fill="#e0e0e0"/><path d="m13.414 1048.4 1.4142-1.4142-1.4142-1.4142-1.4142 1.4142-1.4142-1.4142-1.4142 1.4142 1.4142 1.4142-1.4142 1.4142 1.4142 1.4142 1.4142-1.4142 1.4142 1.4142 1.4142-1.4142z" fill="#ff8484" fill-rule="evenodd"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" 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.13477v1h5.6348l-1.584-1.584 1.4141-1.4141-1.4141-1.416 3.5352-3.5352 1.4141 1.4141v-.46484-3h3v-2c0-1.1046-.89543-2-2-2h-7z" fill="#e0e0e0" transform="translate(0 1036.4)"/><path d="m6 1c-1.1046 0-2 .89543-2 2v7h-2-1v1 2c0 1.1046.89543 2 2 2s2-.89543 2-2v-10c0-.55228.44772-1 1-1s1 .44772 1 1v1 1 1h1 4v-1h-4v-1-1c0-1.1046-.89543-2-2-2zm-4 10h2v2c0 .55228-.44772 1-1 1s-1-.44772-1-1z" fill="#b4b4b4" transform="translate(0 1036.4)"/><circle cx="3" cy="1048.4" fill="#e0e0e0"/><path d="m13.414 1048.4 1.4142-1.4142-1.4142-1.4142-1.4142 1.4142-1.4142-1.4142-1.4142 1.4142 1.4142 1.4142-1.4142 1.4142 1.4142 1.4142 1.4142-1.4142 1.4142 1.4142 1.4142-1.4142z" fill="#ff5f5f" fill-rule="evenodd"/></g></svg>
diff --git a/editor/icons/ScrollContainer.svg b/editor/icons/ScrollContainer.svg
index 600590684d..de631a525e 100644
--- a/editor/icons/ScrollContainer.svg
+++ b/editor/icons/ScrollContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm5 1-2 2h4zm2 2v4l2-2zm0 4h-4l2 2zm-4 0v-4l-2 2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm5 1-2 2h4zm2 2v4l2-2zm0 4h-4l2 2zm-4 0v-4l-2 2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/Shader.svg b/editor/icons/Shader.svg
index 33479326d4..5a7e51191f 100644
--- a/editor/icons/Shader.svg
+++ b/editor/icons/Shader.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v12c.0000552.5523.44774.9999 1 1h12c.55226-.0001.99994-.4477 1-1v-8l-5-5zm1 2h6v3c0 .554.44599 1 1 1h3v6h-10z" fill="#e0e0e0"/><path d="m10 11h2v1h-2z" fill="#9f70ff"/><path d="m4 6h2v1h-2z" fill="#ffeb70"/><path d="m8 8h4v1h-4z" fill="#9dff70"/><path d="m7 6h1v1h-1z" fill="#70deff"/><path d="m4 11h5v1h-5z" fill="#ff70ac"/><path d="m4 4h3v1h-3z" fill="#ff7070"/><path d="m4 8h3v1h-3z" fill="#70ffb9"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v12c.0000552.5523.44774.9999 1 1h12c.55226-.0001.99994-.4477 1-1v-8l-5-5zm1 2h6v3c0 .554.44599 1 1 1h3v6h-10z" fill="#e0e0e0"/><path d="m10 11h2v1h-2z" fill="#8045ff"/><path d="m4 6h2v1h-2z" fill="#ffe345"/><path d="m8 8h4v1h-4z" fill="#80ff45"/><path d="m7 6h1v1h-1z" fill="#45d7ff"/><path d="m4 11h5v1h-5z" fill="#ff4596"/><path d="m4 4h3v1h-3z" fill="#ff4545"/><path d="m4 8h3v1h-3z" fill="#45ffa2"/></svg>
diff --git a/editor/icons/ShaderMaterial.svg b/editor/icons/ShaderMaterial.svg
index ff92f0c376..80a1d0a24d 100644
--- a/editor/icons/ShaderMaterial.svg
+++ b/editor/icons/ShaderMaterial.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v1h2 6 3l-2-2z" fill="#ff7070"/><path d="m1 3v2h2v-2zm8 0v2h5l-2-2z" fill="#ffeb70"/><path d="m1 5v2h2v-2zm8 0v1c0 .554.44599 1 1 1h3 2v-1l-1-1z" fill="#9dff70"/><path d="m1 7v2h2v-2zm12 0v2h2v-2z" fill="#70ffb9"/><path d="m1 9v2h2v-2zm12 0v2h2v-2z" fill="#70deff"/><path d="m1 13v1c.0000552.5523.44774.9999 1 1h12c.55226-.0001.99994-.4477 1-1v-1h-2-10z" fill="#ff70ac"/><path d="m1 11v2h2v-2zm12 0v2h2v-2z" fill="#9f70ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v1h2 6 3l-2-2z" fill="#ff4545"/><path d="m1 3v2h2v-2zm8 0v2h5l-2-2z" fill="#ffe345"/><path d="m1 5v2h2v-2zm8 0v1c0 .554.44599 1 1 1h3 2v-1l-1-1z" fill="#80ff45"/><path d="m1 7v2h2v-2zm12 0v2h2v-2z" fill="#45ffa2"/><path d="m1 9v2h2v-2zm12 0v2h2v-2z" fill="#45d7ff"/><path d="m1 13v1c.0000552.5523.44774.9999 1 1h12c.55226-.0001.99994-.4477 1-1v-1h-2-10z" fill="#ff4596"/><path d="m1 11v2h2v-2zm12 0v2h2v-2z" fill="#8045ff"/></svg>
diff --git a/editor/icons/Signal.svg b/editor/icons/Signal.svg
index 91599ffd65..ad5b5e5b06 100644
--- a/editor/icons/Signal.svg
+++ b/editor/icons/Signal.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 3v10h2 4v-2h-4v-6h4v-2h-4zm9 1v3h-5v2h5v3l2.5-2 2.5-2-2.5-2z" fill="#ff8484"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 3v10h2 4v-2h-4v-6h4v-2h-4zm9 1v3h-5v2h5v3l2.5-2 2.5-2-2.5-2z" fill="#ff5f5f"/></svg>
diff --git a/editor/icons/Skeleton2D.svg b/editor/icons/Skeleton2D.svg
index b34a2a9dca..fc2555fb8a 100644
--- a/editor/icons/Skeleton2D.svg
+++ b/editor/icons/Skeleton2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 2a4 4 0 0 0 -4 4 4 4 0 0 0 2 3.4531v3.5469a2 2 0 0 0 1 1.7324 2 2 0 0 0 1 .26562v.001953h4v-.001953a2 2 0 0 0 1-.26562 2 2 0 0 0 1-1.7324v-3.5469a4 4 0 0 0 2-3.4531 4 4 0 0 0 -4-4zm-1 3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-4 2h2v1h-2zm-2 2h1v1h1v-1h1 1v1h1v-1h1v.86719 3.1328h-1v-1h-1v1h-1-1v-1h-1v1h-1v-3.1309-.86914z" fill="#a5b7f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 2a4 4 0 0 0 -4 4 4 4 0 0 0 2 3.4531v3.5469a2 2 0 0 0 1 1.7324 2 2 0 0 0 1 .26562v.001953h4v-.001953a2 2 0 0 0 1-.26562 2 2 0 0 0 1-1.7324v-3.5469a4 4 0 0 0 2-3.4531 4 4 0 0 0 -4-4zm-1 3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-4 2h2v1h-2zm-2 2h1v1h1v-1h1 1v1h1v-1h1v.86719 3.1328h-1v-1h-1v1h-1-1v-1h-1v1h-1v-3.1309-.86914z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/Skeleton3D.svg b/editor/icons/Skeleton3D.svg
index e0780dedd6..f1a1db86a9 100644
--- a/editor/icons/Skeleton3D.svg
+++ b/editor/icons/Skeleton3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 2a4 4 0 0 0 -4 4 4 4 0 0 0 2 3.4531v3.5469a2 2 0 0 0 1 1.7324 2 2 0 0 0 1 .26562v.001953h4v-.001953a2 2 0 0 0 1-.26562 2 2 0 0 0 1-1.7324v-3.5469a4 4 0 0 0 2-3.4531 4 4 0 0 0 -4-4zm-1 3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-4 2h2v1h-2zm-2 2h1v1h1v-1h1 1v1h1v-1h1v.86719 3.1328h-1v-1h-1v1h-1-1v-1h-1v1h-1v-3.1309-.86914z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 2a4 4 0 0 0 -4 4 4 4 0 0 0 2 3.4531v3.5469a2 2 0 0 0 1 1.7324 2 2 0 0 0 1 .26562v.001953h4v-.001953a2 2 0 0 0 1-.26562 2 2 0 0 0 1-1.7324v-3.5469a4 4 0 0 0 2-3.4531 4 4 0 0 0 -4-4zm-1 3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-4 2h2v1h-2zm-2 2h1v1h1v-1h1 1v1h1v-1h1v.86719 3.1328h-1v-1h-1v1h-1-1v-1h-1v1h-1v-3.1309-.86914z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/SliderJoint3D.svg b/editor/icons/SliderJoint3D.svg
index 57d22dff6a..20b265b766 100644
--- a/editor/icons/SliderJoint3D.svg
+++ b/editor/icons/SliderJoint3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1c-.55228 0-1 .44772-1 1s.44772 1 1 1h3l-7 7v3l12-12zm10 2-12 12h8c.55228 0 1-.44772 1-1s-.44772-1-1-1h-3l7-7z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1c-.55228 0-1 .44772-1 1s.44772 1 1 1h3l-7 7v3l12-12zm10 2-12 12h8c.55228 0 1-.44772 1-1s-.44772-1-1-1h-3l7-7z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/Slot.svg b/editor/icons/Slot.svg
index ec35be6b51..93c125a801 100644
--- a/editor/icons/Slot.svg
+++ b/editor/icons/Slot.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 3v2h4v6h-4v2h4 2v-10h-2zm-3 1v3h-5v2h5v3l2.5-2 2.5-2-2.5-2z" fill="#84ffb1"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 3v2h4v6h-4v2h4 2v-10h-2zm-3 1v3h-5v2h5v3l2.5-2 2.5-2-2.5-2z" fill="#5fff97"/></svg>
diff --git a/editor/icons/SoftBody3D.svg b/editor/icons/SoftBody3D.svg
index e46691d6a2..7bc9a22c22 100644
--- a/editor/icons/SoftBody3D.svg
+++ b/editor/icons/SoftBody3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1s-3 5 0 7-1 7-1 7h13s3-6 0-8 1-6 1-6zm2 2h7s-2 3 1 5 0 5 0 5h-7s2-4-1-6 0-4 0-4z" fill="#fc9c9c" fill-opacity=".996078"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1s-3 5 0 7-1 7-1 7h13s3-6 0-8 1-6 1-6zm2 2h7s-2 3 1 5 0 5 0 5h-7s2-4-1-6 0-4 0-4z" fill="#fc7f7f" fill-opacity=".996078"/></svg>
diff --git a/editor/icons/SphereMesh.svg b/editor/icons/SphereMesh.svg
index 66cc8e3cc4..be2dd44a34 100644
--- a/editor/icons/SphereMesh.svg
+++ b/editor/icons/SphereMesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7s7-3.1458 7-7c0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-.071342-2.6061-.29819-3.9434-.69141.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549.41253 3.637 2.0767 3.9414 4.1699-1.3046.36677-2.6158.60259-3.9414.6875zm3.7852 6.2812c-.50864 1.7788-1.9499 3.1531-3.7852 3.5215v-2.9512c1.2792-.072301 2.5419-.26704 3.7852-.57031zm-9.5645.017578c1.2733.31892 2.5337.50215 3.7793.5625v2.9414c-1.8291-.36719-3.266-1.7339-3.7793-3.5039z" fill="#ffd684"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7s7-3.1458 7-7c0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-.071342-2.6061-.29819-3.9434-.69141.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549.41253 3.637 2.0767 3.9414 4.1699-1.3046.36677-2.6158.60259-3.9414.6875zm3.7852 6.2812c-.50864 1.7788-1.9499 3.1531-3.7852 3.5215v-2.9512c1.2792-.072301 2.5419-.26704 3.7852-.57031zm-9.5645.017578c1.2733.31892 2.5337.50215 3.7793.5625v2.9414c-1.8291-.36719-3.266-1.7339-3.7793-3.5039z" fill="#ffca5f"/></svg>
diff --git a/editor/icons/SpinBox.svg b/editor/icons/SpinBox.svg
index a8dc55d8db..1206ada6bd 100644
--- a/editor/icons/SpinBox.svg
+++ b/editor/icons/SpinBox.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 3c-1.1046 0-2 .89543-2 2v6c0 1.1046.89543 2 2 2h7v-2-6-2zm10 1-2 3h4zm-10 1h5v6h-5zm8 4 2 3 2-3z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 3c-1.1046 0-2 .89543-2 2v6c0 1.1046.89543 2 2 2h7v-2-6-2zm10 1-2 3h4zm-10 1h5v6h-5zm8 4 2 3 2-3z" fill="#8eef97"/></svg>
diff --git a/editor/icons/SpotLight3D.svg b/editor/icons/SpotLight3D.svg
index a1dea938a3..73b738efcf 100644
--- a/editor/icons/SpotLight3D.svg
+++ b/editor/icons/SpotLight3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a1 1 0 0 0 -1 1v3.6934c-1.7861.86608-3 2.4605-3 4.3066h4a2 2 0 0 0 2 2 2 2 0 0 0 2-2h4c0-1.8462-1.2139-3.4406-3-4.3066v-3.6934a1 1 0 0 0 -1-1zm-1.0977 9.6348-1.7324 1 1 1.7305 1.7324-1zm6.1953 0-1 1.7305 1.7324 1 1-1.7305zm-4.0977 2.3652v2h2v-2z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1a1 1 0 0 0 -1 1v3.6934c-1.7861.86608-3 2.4605-3 4.3066h4a2 2 0 0 0 2 2 2 2 0 0 0 2-2h4c0-1.8462-1.2139-3.4406-3-4.3066v-3.6934a1 1 0 0 0 -1-1zm-1.0977 9.6348-1.7324 1 1 1.7305 1.7324-1zm6.1953 0-1 1.7305 1.7324 1 1-1.7305zm-4.0977 2.3652v2h2v-2z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/SpringArm3D.svg b/editor/icons/SpringArm3D.svg
index 707e408dd9..e2c607c7bd 100644
--- a/editor/icons/SpringArm3D.svg
+++ b/editor/icons/SpringArm3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#fc9c9c" stroke-width="2"><path d="m8 14 6-6"/><path d="m2 2 7 7"/><path d="m10 9h-6"/><path d="m9 9v-5"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#fc7f7f" stroke-width="2"><path d="m8 14 6-6"/><path d="m2 2 7 7"/><path d="m10 9h-6"/><path d="m9 9v-5"/></g></svg>
diff --git a/editor/icons/Sprite2D.svg b/editor/icons/Sprite2D.svg
index faae0e444f..0d3ec05a30 100644
--- a/editor/icons/Sprite2D.svg
+++ b/editor/icons/Sprite2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1c-2.216 0-4 1.784-4 4v6c0 2.216 1.784 4 4 4h6c2.216 0 4-1.784 4-4v-6c0-2.216-1.784-4-4-4zm-1 5c.554 0 1 .446 1 1v2c0 .554-.446 1-1 1s-1-.446-1-1v-2c0-.554.446-1 1-1zm8 0c.554 0 1 .446 1 1v2c0 .554-.446 1-1 1s-1-.446-1-1v-2c0-.554.446-1 1-1zm-1.8887 5.1074a1.0001 1.0001 0 0 1 .7168 1.7207c-.74987.74987-1.7676 1.1719-2.8281 1.1719s-2.0783-.422-2.8281-1.1719a1.0001 1.0001 0 0 1 .69727-1.7168 1.0001 1.0001 0 0 1 .7168.30273c.37534.37535.88325.58594 1.4141.58594s1.0387-.21059 1.4141-.58594a1.0001 1.0001 0 0 1 .69727-.30664z" fill="#a5b7f3"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1c-2.216 0-4 1.784-4 4v6c0 2.216 1.784 4 4 4h6c2.216 0 4-1.784 4-4v-6c0-2.216-1.784-4-4-4zm-1 5c.554 0 1 .446 1 1v2c0 .554-.446 1-1 1s-1-.446-1-1v-2c0-.554.446-1 1-1zm8 0c.554 0 1 .446 1 1v2c0 .554-.446 1-1 1s-1-.446-1-1v-2c0-.554.446-1 1-1zm-1.8887 5.1074a1.0001 1.0001 0 0 1 .7168 1.7207c-.74987.74987-1.7676 1.1719-2.8281 1.1719s-2.0783-.422-2.8281-1.1719a1.0001 1.0001 0 0 1 .69727-1.7168 1.0001 1.0001 0 0 1 .7168.30273c.37534.37535.88325.58594 1.4141.58594s1.0387-.21059 1.4141-.58594a1.0001 1.0001 0 0 1 .69727-.30664z" fill="#8da5f3"/></svg>
diff --git a/editor/icons/Sprite3D.svg b/editor/icons/Sprite3D.svg
index 4ccd8f9c48..b002249ed7 100644
--- a/editor/icons/Sprite3D.svg
+++ b/editor/icons/Sprite3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1c-2.216 0-4 1.784-4 4v6c0 2.216 1.784 4 4 4h6c2.216 0 4-1.784 4-4v-6c0-2.216-1.784-4-4-4zm-1 5c.554 0 1 .446 1 1v2c0 .554-.446 1-1 1s-1-.446-1-1v-2c0-.554.446-1 1-1zm8 0c.554 0 1 .446 1 1v2c0 .554-.446 1-1 1s-1-.446-1-1v-2c0-.554.446-1 1-1zm-1.8887 5.1074a1.0001 1.0001 0 0 1 .7168 1.7207c-.74987.74987-1.7676 1.1719-2.8281 1.1719s-2.0783-.422-2.8281-1.1719a1.0001 1.0001 0 0 1 .69727-1.7168 1.0001 1.0001 0 0 1 .7168.30273c.37534.37535.88325.58594 1.4141.58594s1.0387-.21059 1.4141-.58594a1.0001 1.0001 0 0 1 .69727-.30664z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1c-2.216 0-4 1.784-4 4v6c0 2.216 1.784 4 4 4h6c2.216 0 4-1.784 4-4v-6c0-2.216-1.784-4-4-4zm-1 5c.554 0 1 .446 1 1v2c0 .554-.446 1-1 1s-1-.446-1-1v-2c0-.554.446-1 1-1zm8 0c.554 0 1 .446 1 1v2c0 .554-.446 1-1 1s-1-.446-1-1v-2c0-.554.446-1 1-1zm-1.8887 5.1074a1.0001 1.0001 0 0 1 .7168 1.7207c-.74987.74987-1.7676 1.1719-2.8281 1.1719s-2.0783-.422-2.8281-1.1719a1.0001 1.0001 0 0 1 .69727-1.7168 1.0001 1.0001 0 0 1 .7168.30273c.37534.37535.88325.58594 1.4141.58594s1.0387-.21059 1.4141-.58594a1.0001 1.0001 0 0 1 .69727-.30664z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/StandardMaterial3D.svg b/editor/icons/StandardMaterial3D.svg
index 7c52665a89..717ba5d239 100644
--- a/editor/icons/StandardMaterial3D.svg
+++ b/editor/icons/StandardMaterial3D.svg
@@ -1 +1 @@
-<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>
+<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="#ff4545"/><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="#ffe345"/><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="#80ff45"/><path d="m1 7v2h2v-2zm2.7617 0 3.2383 1.6191v.38086h2v-.38086l3.2383-1.6191zm9.2383 0v2h2v-2z" fill="#45ffa2"/><path d="m1 9v2h3.2344l-1.2344-.61719v-1.3828h-2zm6 0v2h2v-2zm6 0v1.3828l-1.2344.61719h3.2344v-2h-2z" fill="#45d7ff"/><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="#ff4596"/><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="#8045ff"/></svg>
diff --git a/editor/icons/StaticBody2D.svg b/editor/icons/StaticBody2D.svg
index 66940ad415..ba61605522 100644
--- a/editor/icons/StaticBody2D.svg
+++ b/editor/icons/StaticBody2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m29 1042.4h1v1h-1z" fill="#fefeff"/><path d="m3 1a2 2 0 0 0 -1.4141.58594 2 2 0 0 0 -.58594 1.4141v10a2 2 0 0 0 .58594 1.4141 2 2 0 0 0 1.4141.58594h10a2 2 0 0 0 2-2v-10a2 2 0 0 0 -2-2h-10zm0 1h10a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-10a1 1 0 0 1 -1-1v-10a1 1 0 0 1 1-1zm0 1v2h2v-2zm8 0v2h2v-2zm-8 8v2h2v-2zm8 0v2h2v-2z" fill="#a5b7f3" fill-opacity=".98824" transform="translate(0 1036.4)"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m29 1042.4h1v1h-1z" fill="#fefeff"/><path d="m3 1a2 2 0 0 0 -1.4141.58594 2 2 0 0 0 -.58594 1.4141v10a2 2 0 0 0 .58594 1.4141 2 2 0 0 0 1.4141.58594h10a2 2 0 0 0 2-2v-10a2 2 0 0 0 -2-2h-10zm0 1h10a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-10a1 1 0 0 1 -1-1v-10a1 1 0 0 1 1-1zm0 1v2h2v-2zm8 0v2h2v-2zm-8 8v2h2v-2zm8 0v2h2v-2z" fill="#8da5f3" fill-opacity=".98824" transform="translate(0 1036.4)"/></g></svg>
diff --git a/editor/icons/StaticBody3D.svg b/editor/icons/StaticBody3D.svg
index a4a641f28c..55b061571f 100644
--- a/editor/icons/StaticBody3D.svg
+++ b/editor/icons/StaticBody3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -1.4141.58594 2 2 0 0 0 -.58594 1.4141v10a2 2 0 0 0 .58594 1.4141 2 2 0 0 0 1.4141.58594h10a2 2 0 0 0 2-2v-10a2 2 0 0 0 -2-2h-10zm0 1h10a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-10a1 1 0 0 1 -1-1v-10a1 1 0 0 1 1-1zm0 1v2h2v-2zm8 0v2h2v-2zm-8 8v2h2v-2zm8 0v2h2v-2z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -1.4141.58594 2 2 0 0 0 -.58594 1.4141v10a2 2 0 0 0 .58594 1.4141 2 2 0 0 0 1.4141.58594h10a2 2 0 0 0 2-2v-10a2 2 0 0 0 -2-2h-10zm0 1h10a1 1 0 0 1 1 1v10a1 1 0 0 1 -1 1h-10a1 1 0 0 1 -1-1v-10a1 1 0 0 1 1-1zm0 1v2h2v-2zm8 0v2h2v-2zm-8 8v2h2v-2zm8 0v2h2v-2z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/String.svg b/editor/icons/String.svg
index 5b7ade8b1e..abcb92d4b2 100644
--- a/editor/icons/String.svg
+++ b/editor/icons/String.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 2a3 3 0 0 0 -3 3v2a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3-3v-2a1 1 0 0 1 1-1h1v-2zm2 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2zm8 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2z" fill="#6ba7ec"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 2a3 3 0 0 0 -3 3v2a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3-3v-2a1 1 0 0 1 1-1h1v-2zm2 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2zm8 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2z" fill="#4593ec"/></svg>
diff --git a/editor/icons/StringName.svg b/editor/icons/StringName.svg
index 8f2ef13a37..3b67f2accd 100644
--- a/editor/icons/StringName.svg
+++ b/editor/icons/StringName.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 2c-1.6569 0-3 1.3431-3 3v2c0 .55228-.44772 1-1 1h-1v2h1c1.6569 0 3-1.3431 3-3v-2c0-.55228.44772-1 1-1h1v3c0 1.6569 1.3431 3 3 3h3v-4h1c.55228 0 1 .44772 1 1v3h2v-3c0-1.6569-1.3431-3-3-3h-5v-2zm3 4h2v2h-1c-.55228 0-1-.44772-1-1z" fill="#6ba7ec"/><path d="m10 4v6h2v-4h1c.55228 0 1 .44772 1 1v3h2v-3c0-1.6569-1.3431-3-3-3h-1z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 2c-1.6569 0-3 1.3431-3 3v2c0 .55228-.44772 1-1 1h-1v2h1c1.6569 0 3-1.3431 3-3v-2c0-.55228.44772-1 1-1h1v3c0 1.6569 1.3431 3 3 3h3v-4h1c.55228 0 1 .44772 1 1v3h2v-3c0-1.6569-1.3431-3-3-3h-5v-2zm3 4h2v2h-1c-.55228 0-1-.44772-1-1z" fill="#4593ec"/><path d="m10 4v6h2v-4h1c.55228 0 1 .44772 1 1v3h2v-3c0-1.6569-1.3431-3-3-3h-1z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/StyleBoxEmpty.svg b/editor/icons/StyleBoxEmpty.svg
index e1a2bc6888..3c4546dff5 100644
--- a/editor/icons/StyleBoxEmpty.svg
+++ b/editor/icons/StyleBoxEmpty.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v1h2v-2zm3 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2v-1c-.000055-.5523-.44774-.9999-1-1z" fill="#ff7070"/><path d="m1 5v2h2v-2zm12 0v.23242c.31584.1783.57817.43795.75977.75195.19142.33153.43699.67036.69922 1.0156h.54102v-2h-2z" fill="#9dff70"/><path d="m12 7c-.43047.7456-.94451 1.3867-1.4355 2h2.8711c-.49104-.6133-1.0051-1.2544-1.4355-2zm2.459 0c.17438.2296.352.46082.54102.69922v-.69922z" fill="#70ffb9"/><path d="m1 9v2h2v-2zm9.5645 0c-.55248.69003-1.0583 1.3421-1.334 2h5.5391c-.2757-.65786-.78151-1.31-1.334-2z" fill="#70deff"/><path d="m1 13v1c.0000552.5523.44774.9999 1 1h1v-2zm4 0v2h2v-2zm4.1836 0c.41312 1.1628 1.5119 2 2.8164 2s2.4033-.83718 2.8164-2z" fill="#ff70ac"/><path d="m9.2305 11c-.13656.32585-.23047.65576-.23047 1 0 .35235.07201.68593.18359 1h5.6328c.11158-.31407.18359-.64765.18359-1 0-.34424-.093909-.67415-.23047-1h-5.5391z" fill="#9f70ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v1h2v-2zm3 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2v-1c-.000055-.5523-.44774-.9999-1-1z" fill="#ff4545"/><path d="m1 5v2h2v-2zm12 0v.23242c.31584.1783.57817.43795.75977.75195.19142.33153.43699.67036.69922 1.0156h.54102v-2h-2z" fill="#80ff45"/><path d="m12 7c-.43047.7456-.94451 1.3867-1.4355 2h2.8711c-.49104-.6133-1.0051-1.2544-1.4355-2zm2.459 0c.17438.2296.352.46082.54102.69922v-.69922z" fill="#45ffa2"/><path d="m1 9v2h2v-2zm9.5645 0c-.55248.69003-1.0583 1.3421-1.334 2h5.5391c-.2757-.65786-.78151-1.31-1.334-2z" fill="#45d7ff"/><path d="m1 13v1c.0000552.5523.44774.9999 1 1h1v-2zm4 0v2h2v-2zm4.1836 0c.41312 1.1628 1.5119 2 2.8164 2s2.4033-.83718 2.8164-2z" fill="#ff4596"/><path d="m9.2305 11c-.13656.32585-.23047.65576-.23047 1 0 .35235.07201.68593.18359 1h5.6328c.11158-.31407.18359-.64765.18359-1 0-.34424-.093909-.67415-.23047-1h-5.5391z" fill="#8045ff"/></svg>
diff --git a/editor/icons/StyleBoxFlat.svg b/editor/icons/StyleBoxFlat.svg
index b24c453f6b..5bf01f5e66 100644
--- a/editor/icons/StyleBoxFlat.svg
+++ b/editor/icons/StyleBoxFlat.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v1h14v-1c-.000055-.5523-.44774-.9999-1-1z" fill="#ff7070"/><path d="m1 3v2h14v-2z" fill="#ffeb70"/><path d="m1 5v2h8.582c.25686-.33847.49465-.66934.68555-1 .33885-.5859.95103-.96109 1.627-.99609.7512-.04 1.4613.34489 1.8379.99609.18899.32737.42831.66049.68555 1h.58203v-2h-14z" fill="#9dff70"/><path d="m1 7v2h7.0547c.14116-.20345.28508-.40233.42383-.58398.38601-.5053.76348-.96794 1.1035-1.416h-8.582zm11 0c-.43047.7456-.94451 1.3867-1.4355 2h2.8711c-.49104-.6133-1.0051-1.2544-1.4355-2zm2.418 0c.18626.24583.37928.49419.58203.75v-.75z" fill="#70ffb9"/><path d="m1 9v2h6.1172c.17955-.78395.54577-1.4354.9375-2zm9.5645 0c-.55248.69003-1.0583 1.3421-1.334 2h5.5391c-.2757-.65786-.78151-1.31-1.334-2z" fill="#70deff"/><path d="m1 13v1c.0000552.5523.44774.9999 1 1h6.0371c-.44511-.58388-.76161-1.2639-.91992-2h-6.1172zm8.1836 0c.41312 1.1628 1.5119 2 2.8164 2s2.4033-.83718 2.8164-2z" fill="#ff70ac"/><path d="m1 11v2h6.1172c-.06966-.3239-.11719-.65596-.11719-1 0-.35655.045474-.68688.11719-1zm8.2305 0c-.13656.32585-.23047.65576-.23047 1 0 .35235.07201.68593.18359 1h5.6328c.11158-.31407.18359-.64765.18359-1 0-.34424-.093909-.67415-.23047-1h-5.5391z" fill="#9f70ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.55226.0001-.99994.4477-1 1v1h14v-1c-.000055-.5523-.44774-.9999-1-1z" fill="#ff4545"/><path d="m1 3v2h14v-2z" fill="#ffe345"/><path d="m1 5v2h8.582c.25686-.33847.49465-.66934.68555-1 .33885-.5859.95103-.96109 1.627-.99609.7512-.04 1.4613.34489 1.8379.99609.18899.32737.42831.66049.68555 1h.58203v-2h-14z" fill="#80ff45"/><path d="m1 7v2h7.0547c.14116-.20345.28508-.40233.42383-.58398.38601-.5053.76348-.96794 1.1035-1.416h-8.582zm11 0c-.43047.7456-.94451 1.3867-1.4355 2h2.8711c-.49104-.6133-1.0051-1.2544-1.4355-2zm2.418 0c.18626.24583.37928.49419.58203.75v-.75z" fill="#45ffa2"/><path d="m1 9v2h6.1172c.17955-.78395.54577-1.4354.9375-2zm9.5645 0c-.55248.69003-1.0583 1.3421-1.334 2h5.5391c-.2757-.65786-.78151-1.31-1.334-2z" fill="#45d7ff"/><path d="m1 13v1c.0000552.5523.44774.9999 1 1h6.0371c-.44511-.58388-.76161-1.2639-.91992-2h-6.1172zm8.1836 0c.41312 1.1628 1.5119 2 2.8164 2s2.4033-.83718 2.8164-2z" fill="#ff4596"/><path d="m1 11v2h6.1172c-.06966-.3239-.11719-.65596-.11719-1 0-.35655.045474-.68688.11719-1zm8.2305 0c-.13656.32585-.23047.65576-.23047 1 0 .35235.07201.68593.18359 1h5.6328c.11158-.31407.18359-.64765.18359-1 0-.34424-.093909-.67415-.23047-1h-5.5391z" fill="#8045ff"/></svg>
diff --git a/editor/icons/StyleBoxLine.svg b/editor/icons/StyleBoxLine.svg
index e92f33b7b0..995f56f726 100644
--- a/editor/icons/StyleBoxLine.svg
+++ b/editor/icons/StyleBoxLine.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13.303 1c-.4344 0-.86973.16881-1.2012.50586l-1.4688 1.4941h4.3418c.082839-.52789-.072596-1.0872-.47266-1.4941-.33144-.33705-.76482-.50586-1.1992-.50586z" fill="#ff7070"/><path d="m10.633 3-1.9668 2h4.8008l1.0352-1.0527c.2628-.2673.41824-.60049.47266-.94727h-4.3418z" fill="#ffeb70"/><path d="m8.666 5-1.9648 2h2.8809c.25686-.33847.49465-.66934.68555-1 .33885-.5859.95098-.96109 1.627-.99609.44399-.023642.86385.115 1.2188.35547l.35352-.35938h-4.8008z" fill="#9dff70"/><path d="m1.2617 13c-.08284.52789.072596 1.0872.47266 1.4941.33144.33705.76484.50586 1.1992.50586.4344 0 .8697-.16881 1.2012-.50586l1.4688-1.4941h-4.3418zm7.9219 0c.41312 1.1628 1.5119 2 2.8164 2s2.4033-.83718 2.8164-2z" fill="#ff70ac"/><path d="m2.7695 11-1.0352 1.0527c-.2628.2673-.41824.60049-.47266.94727h4.3418l1.4238-1.4473c.020288-.18998.04923-.37542.089844-.55273h-4.3477zm6.4609 0c-.13656.32585-.23047.65576-.23047 1 0 .35235.072014.68593.18359 1h5.6328c.11158-.31407.18359-.64765.18359-1 0-.34424-.093909-.67415-.23047-1h-5.5391z" fill="#9f70ff"/><path d="m4.7363 9-1.9668 2h4.3477c.17955-.78395.54577-1.4354.9375-2zm5.8281 0c-.55248.69003-1.0583 1.3421-1.334 2h5.5391c-.2757-.65786-.78149-1.31-1.334-2z" fill="#70deff"/><path d="m6.7012 7-1.9648 2h3.3184c.14116-.20345.28508-.40233.42383-.58398.38601-.5053.7635-.96796 1.1035-1.416h-2.8809zm5.2988 0c-.43047.7456-.94456 1.3867-1.4355 2h2.8711c-.49104-.6133-1.0051-1.2544-1.4355-2z" fill="#70ffb9"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13.303 1c-.4344 0-.86973.16881-1.2012.50586l-1.4688 1.4941h4.3418c.082839-.52789-.072596-1.0872-.47266-1.4941-.33144-.33705-.76482-.50586-1.1992-.50586z" fill="#ff4545"/><path d="m10.633 3-1.9668 2h4.8008l1.0352-1.0527c.2628-.2673.41824-.60049.47266-.94727h-4.3418z" fill="#ffe345"/><path d="m8.666 5-1.9648 2h2.8809c.25686-.33847.49465-.66934.68555-1 .33885-.5859.95098-.96109 1.627-.99609.44399-.023642.86385.115 1.2188.35547l.35352-.35938h-4.8008z" fill="#80ff45"/><path d="m1.2617 13c-.08284.52789.072596 1.0872.47266 1.4941.33144.33705.76484.50586 1.1992.50586.4344 0 .8697-.16881 1.2012-.50586l1.4688-1.4941h-4.3418zm7.9219 0c.41312 1.1628 1.5119 2 2.8164 2s2.4033-.83718 2.8164-2z" fill="#ff4596"/><path d="m2.7695 11-1.0352 1.0527c-.2628.2673-.41824.60049-.47266.94727h4.3418l1.4238-1.4473c.020288-.18998.04923-.37542.089844-.55273h-4.3477zm6.4609 0c-.13656.32585-.23047.65576-.23047 1 0 .35235.072014.68593.18359 1h5.6328c.11158-.31407.18359-.64765.18359-1 0-.34424-.093909-.67415-.23047-1h-5.5391z" fill="#8045ff"/><path d="m4.7363 9-1.9668 2h4.3477c.17955-.78395.54577-1.4354.9375-2zm5.8281 0c-.55248.69003-1.0583 1.3421-1.334 2h5.5391c-.2757-.65786-.78149-1.31-1.334-2z" fill="#45d7ff"/><path d="m6.7012 7-1.9648 2h3.3184c.14116-.20345.28508-.40233.42383-.58398.38601-.5053.7635-.96796 1.1035-1.416h-2.8809zm5.2988 0c-.43047.7456-.94456 1.3867-1.4355 2h2.8711c-.49104-.6133-1.0051-1.2544-1.4355-2z" fill="#45ffa2"/></svg>
diff --git a/editor/icons/StyleBoxTexture.svg b/editor/icons/StyleBoxTexture.svg
index 89bbc41ef8..a356d11885 100644
--- a/editor/icons/StyleBoxTexture.svg
+++ b/editor/icons/StyleBoxTexture.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1.0001 1.0001 0 0 0 -1 1v1h2 10 2v-1a1.0001 1.0001 0 0 0 -1-1z" fill="#ff7070"/><path d="m1 3v2h2v-2zm12 0v2h2v-2zm-4 1v1h1v-1z" fill="#ffeb70"/><path d="m1 5v2h2v-2zm7 0v1h-2v1h3.543c.26215-.34438.50373-.68039.69727-1.0156a2.0315 2.0315 0 0 1 .75977-.75195v-.23242h-1-1-1zm5 0v.23242a2.0315 2.0315 0 0 1 .75977.75195c.19142.33153.43699.67033.69922 1.0156h.54102v-2h-2z" fill="#9dff70"/><path d="m1 7v2h2v-2zm4 0v1h-1v1h4.0156c.14585-.2113.29419-.41592.4375-.60352.38121-.49904.75394-.95521 1.0898-1.3965h-3.543-1zm7 0c-.43047.7456-.94451 1.3867-1.4355 2h2.8711c-.49104-.6133-1.0051-1.2544-1.4355-2zm2.459 0c.17438.22962.352.46082.54102.69922v-.69922z" fill="#70ffb9"/><path d="m1 9v2h2v-2zm9.5645 0c-.55248.69003-1.0583 1.3421-1.334 2h5.5391c-.2757-.65786-.78151-1.31-1.334-2z" fill="#70deff"/><path d="m1 13v1a1.0001 1.0001 0 0 0 1 1h5.998c-.4429-.5864-.77294-1.2592-.92578-2h-4.0723-2zm8.1836 0c.41312 1.1628 1.5119 2 2.8164 2s2.4033-.83718 2.8164-2z" fill="#ff70ac"/><path d="m1 11v2h2v-2zm8.2305 0c-.13656.32585-.23047.65576-.23047 1 0 .35235.07201.68593.18359 1h5.6328c.11158-.31407.18359-.64765.18359-1 0-.34424-.093909-.67415-.23047-1h-5.5391z" fill="#9f70ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1.0001 1.0001 0 0 0 -1 1v1h2 10 2v-1a1.0001 1.0001 0 0 0 -1-1z" fill="#ff4545"/><path d="m1 3v2h2v-2zm12 0v2h2v-2zm-4 1v1h1v-1z" fill="#ffe345"/><path d="m1 5v2h2v-2zm7 0v1h-2v1h3.543c.26215-.34438.50373-.68039.69727-1.0156a2.0315 2.0315 0 0 1 .75977-.75195v-.23242h-1-1-1zm5 0v.23242a2.0315 2.0315 0 0 1 .75977.75195c.19142.33153.43699.67033.69922 1.0156h.54102v-2h-2z" fill="#80ff45"/><path d="m1 7v2h2v-2zm4 0v1h-1v1h4.0156c.14585-.2113.29419-.41592.4375-.60352.38121-.49904.75394-.95521 1.0898-1.3965h-3.543-1zm7 0c-.43047.7456-.94451 1.3867-1.4355 2h2.8711c-.49104-.6133-1.0051-1.2544-1.4355-2zm2.459 0c.17438.22962.352.46082.54102.69922v-.69922z" fill="#45ffa2"/><path d="m1 9v2h2v-2zm9.5645 0c-.55248.69003-1.0583 1.3421-1.334 2h5.5391c-.2757-.65786-.78151-1.31-1.334-2z" fill="#45d7ff"/><path d="m1 13v1a1.0001 1.0001 0 0 0 1 1h5.998c-.4429-.5864-.77294-1.2592-.92578-2h-4.0723-2zm8.1836 0c.41312 1.1628 1.5119 2 2.8164 2s2.4033-.83718 2.8164-2z" fill="#ff4596"/><path d="m1 11v2h2v-2zm8.2305 0c-.13656.32585-.23047.65576-.23047 1 0 .35235.07201.68593.18359 1h5.6328c.11158-.31407.18359-.64765.18359-1 0-.34424-.093909-.67415-.23047-1h-5.5391z" fill="#8045ff"/></svg>
diff --git a/editor/icons/SubViewportContainer.svg b/editor/icons/SubViewportContainer.svg
index baf80e5086..e4584c3b9a 100644
--- a/editor/icons/SubViewportContainer.svg
+++ b/editor/icons/SubViewportContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm3 1c-.5304.0001-1.0391.21084-1.4141.58594-.37509.375-.58586.88366-.58594 1.4141v4c.00008.5304.21085 1.0391.58594 1.4141.37501.3751.88366.58584 1.4141.58594h4c1.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="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm3 1c-.5304.0001-1.0391.21084-1.4141.58594-.37509.375-.58586.88366-.58594 1.4141v4c.00008.5304.21085 1.0391.58594 1.4141.37501.3751.88366.58584 1.4141.58594h4c1.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="#8eef97"/></svg>
diff --git a/editor/icons/TabContainer.svg b/editor/icons/TabContainer.svg
index aeb5507279..92ca60911a 100644
--- a/editor/icons/TabContainer.svg
+++ b/editor/icons/TabContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h5v2 2h5v6h-10zm7 0h3v2h-3z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h5v2 2h5v6h-10zm7 0h3v2h-3z" fill="#8eef97"/></svg>
diff --git a/editor/icons/Tabs.svg b/editor/icons/Tabs.svg
index 4fd4a5cd80..e20a1a0131 100644
--- a/editor/icons/Tabs.svg
+++ b/editor/icons/Tabs.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 4c-1.108 0-1.8178.9071-2 2l-1 6h-1v2h4 6 4v-2h-2l-1-6c-.18216-1.0929-.89199-2-2-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 4c-1.108 0-1.8178.9071-2 2l-1 6h-1v2h4 6 4v-2h-2l-1-6c-.18216-1.0929-.89199-2-2-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/TerrainMatchCorners.svg b/editor/icons/TerrainMatchCorners.svg
new file mode 100644
index 0000000000..b9dfcf67d2
--- /dev/null
+++ b/editor/icons/TerrainMatchCorners.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-width="70.7093"><path d="m15 1h-6v3h3v3h3z" fill="#ffa62a"/><path d="m1 1h6v3h-2.9999996l-.0000004 3h-3.0000004z" fill="#1aab1a"/><path d="m1 15h5.9999999v-3h-3v-3h-2.9999999z" fill="#ffa62a"/><path d="m15.000001 15h-6v-3h2.999999l.000001-2.9999997h3z" fill="#1aab1a"/></g></svg>
diff --git a/editor/icons/TerrainMatchCornersAndSides.svg b/editor/icons/TerrainMatchCornersAndSides.svg
new file mode 100644
index 0000000000..81153005bd
--- /dev/null
+++ b/editor/icons/TerrainMatchCornersAndSides.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 1h4v3h-1l-1 1-1-1h-1z" fill="#ffa62a" stroke-width="70.7093"/><path d="m1 15h4v-3h-1v-1h-3z" fill="#1aab1a" stroke-width="70.7093"/><path d="m6 15h4v-3h-1l-1-1-1 1h-1z" fill="#ffa62a" stroke-width="99.998"/><g stroke-width="70.7093"><path d="m1 10v-4h3v1l1 1-1 1v1z" fill="#ffa62a"/><path d="m15 10v-4h-3v1l-1 1 1 1v1z" fill="#ffa62a"/><g fill="#1aab1a"><path d="m15 15h-4v-3h1v-1h3z"/><path d="m15 1h-4v3h1v1h3z"/><path d="m1 1h4.0000004v3h-1v1h-3.0000004z"/></g></g></svg>
diff --git a/editor/icons/TerrainMatchSides.svg b/editor/icons/TerrainMatchSides.svg
new file mode 100644
index 0000000000..1e2ec75ea7
--- /dev/null
+++ b/editor/icons/TerrainMatchSides.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-width="70.7093"><path d="m1 14v-12l3 3v2l1 1-1 1v2z" fill="#1aab1a"/><path d="m15 14v-12l-3 2.7057075v2l-1 1.0000001 1 1v1.9999994z" fill="#1aab1a"/><g fill="#ffa62a"><path d="m2 15h12l-3-3h-2l-1-1-1 1h-2z"/><path d="m14 1h-12l2.9999992 3h1.9999998l1.000001.9999999 1-.9999999h1.999999z"/></g></g></svg>
diff --git a/editor/icons/TestCube.svg b/editor/icons/TestCube.svg
index bdfb3c893b..9995f5b5f4 100644
--- a/editor/icons/TestCube.svg
+++ b/editor/icons/TestCube.svg
@@ -1 +1 @@
-<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-6 3a1.0001 1.0001 0 0 0 -.55273.89453v6a1.0001 1.0001 0 0 0 .55273.89453l6 3a1.0001 1.0001 0 0 0 .89453 0l6-3a1.0001 1.0001 0 0 0 .55273-.89453v-6a1.0001 1.0001 0 0 0 -.55273-.89453l-6-3a1.0001 1.0001 0 0 0 -.48438-.10352zm.037109 2.1172 3.7637 1.8809-3.7637 1.8828-3.7637-1.8828zm-5 3.5 4 2v3.7637l-4-2zm10 0v3.7637l-4 2v-3.7637z" fill="#fc9c9c" fill-opacity=".99608" fill-rule="evenodd" transform="translate(0 .000012)"/></svg>
+<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-6 3a1.0001 1.0001 0 0 0 -.55273.89453v6a1.0001 1.0001 0 0 0 .55273.89453l6 3a1.0001 1.0001 0 0 0 .89453 0l6-3a1.0001 1.0001 0 0 0 .55273-.89453v-6a1.0001 1.0001 0 0 0 -.55273-.89453l-6-3a1.0001 1.0001 0 0 0 -.48438-.10352zm.037109 2.1172 3.7637 1.8809-3.7637 1.8828-3.7637-1.8828zm-5 3.5 4 2v3.7637l-4-2zm10 0v3.7637l-4 2v-3.7637z" fill="#fc7f7f" fill-opacity=".99608" fill-rule="evenodd" transform="translate(0 .000012)"/></svg>
diff --git a/editor/icons/TextEdit.svg b/editor/icons/TextEdit.svg
index 366cf6596d..67a5145373 100644
--- a/editor/icons/TextEdit.svg
+++ b/editor/icons/TextEdit.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m29 1042.4h1v1h-1z" fill="#fefeff"/><path d="m3 1c-1.1046 0-2 .8954-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm1 1v4h1v-4z" fill="#a5efac" transform="translate(0 1036.4)"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m29 1042.4h1v1h-1z" fill="#fefeff"/><path d="m3 1c-1.1046 0-2 .8954-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v10h-10zm1 1v4h1v-4z" fill="#8eef97" transform="translate(0 1036.4)"/></g></svg>
diff --git a/editor/icons/TextureButton.svg b/editor/icons/TextureButton.svg
index 497386945e..8d3d1c52ce 100644
--- a/editor/icons/TextureButton.svg
+++ b/editor/icons/TextureButton.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1v2h6v10h-4v2h6v-14zm-5 1v3.1328l-1.4453-.96484-1.1094 1.6641 3 2c.3359.2239.77347.2239 1.1094 0l3-2-1.1094-1.6641-1.4453.96484v-3.1328zm7 4v1h-1v1h-1v1h1v2h2 2v-2h-1v-2h-1v-1zm-7.5 4c-.831 0-1.5.669-1.5 1.5v.5 1h-1v2h8v-2h-1v-1-.5c0-.831-.669-1.5-1.5-1.5z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1v2h6v10h-4v2h6v-14zm-5 1v3.1328l-1.4453-.96484-1.1094 1.6641 3 2c.3359.2239.77347.2239 1.1094 0l3-2-1.1094-1.6641-1.4453.96484v-3.1328zm7 4v1h-1v1h-1v1h1v2h2 2v-2h-1v-2h-1v-1zm-7.5 4c-.831 0-1.5.669-1.5 1.5v.5 1h-1v2h8v-2h-1v-1-.5c0-.831-.669-1.5-1.5-1.5z" fill="#8eef97"/></svg>
diff --git a/editor/icons/TextureProgressBar.svg b/editor/icons/TextureProgressBar.svg
index 30d76e33b8..a72f0e5754 100644
--- a/editor/icons/TextureProgressBar.svg
+++ b/editor/icons/TextureProgressBar.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#a5efac" transform="translate(0 -1036.4)"><path d="m3 3c-1.1046 0-2 .89543-2 2v6c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-6c0-1.1046-.89543-2-2-2zm0 2h10v6h-10z" transform="translate(0 1036.4)"/><path d="m4 1042.4h1v2h-1z"/><path d="m6 1043.4h1v3h-1z"/><path d="m8 1042.4h1v4h-1z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#8eef97" transform="translate(0 -1036.4)"><path d="m3 3c-1.1046 0-2 .89543-2 2v6c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-6c0-1.1046-.89543-2-2-2zm0 2h10v6h-10z" transform="translate(0 1036.4)"/><path d="m4 1042.4h1v2h-1z"/><path d="m6 1043.4h1v3h-1z"/><path d="m8 1042.4h1v4h-1z"/></g></svg>
diff --git a/editor/icons/TextureRect.svg b/editor/icons/TextureRect.svg
index 605afbb7ca..5f55c06bce 100644
--- a/editor/icons/TextureRect.svg
+++ b/editor/icons/TextureRect.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h14v-14zm2 2h10v10h-10zm6 3v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-2h-1v-1z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h14v-14zm2 2h10v10h-10zm6 3v1h-1v1h-2v1h-1v1h-1v1h2 2 2 2v-2h-1v-2h-1v-1z" fill="#8eef97"/></svg>
diff --git a/editor/icons/Theme.svg b/editor/icons/Theme.svg
index 00e1716dad..401d884022 100644
--- a/editor/icons/Theme.svg
+++ b/editor/icons/Theme.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-width="0"><path d="m6.7246 3c-.52985.78935-.96267 1.4021-1.3945 2h5.3398c-.43187-.59786-.86468-1.2107-1.3945-2z" fill="#ffeb70"/><path d="m5.3301 5c-.52617.72841-1.0198 1.4208-1.375 2h8.0898c-.35516-.57924-.84883-1.2716-1.375-2z" fill="#9dff70"/><path d="m3.9551 7c-.41451.67603-.71534 1.3082-.85547 2h9.8008c-.14013-.69181-.44096-1.324-.85547-2h-8.0898z" fill="#70ffb9"/><path d="m3.0996 9c-.063989.3159-.099609.64498-.099609 1 0 .34242.034776.67693.10156 1h9.7969c.066786-.32307.10156-.65758.10156-1 0-.35502-.03562-.6841-.099609-1h-9.8008z" fill="#70deff"/><path d="m3.1016 11c.15381.74405.48967 1.4159.93555 2h7.9258c.44588-.5841.78173-1.2559.93555-2h-9.7969z" fill="#9f70ff"/><path d="m4.0371 13c.9218 1.2076 2.3612 2 3.9629 2s3.0411-.79243 3.9629-2z" fill="#ff70ac"/><path d="m8 1c-.45196.75327-.87224 1.3994-1.2754 2h2.5508c-.40315-.6006-.82343-1.2467-1.2754-2z" fill="#ff7070"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-width="0"><path d="m6.7246 3c-.52985.78935-.96267 1.4021-1.3945 2h5.3398c-.43187-.59786-.86468-1.2107-1.3945-2z" fill="#ffe345"/><path d="m5.3301 5c-.52617.72841-1.0198 1.4208-1.375 2h8.0898c-.35516-.57924-.84883-1.2716-1.375-2z" fill="#80ff45"/><path d="m3.9551 7c-.41451.67603-.71534 1.3082-.85547 2h9.8008c-.14013-.69181-.44096-1.324-.85547-2h-8.0898z" fill="#45ffa2"/><path d="m3.0996 9c-.063989.3159-.099609.64498-.099609 1 0 .34242.034776.67693.10156 1h9.7969c.066786-.32307.10156-.65758.10156-1 0-.35502-.03562-.6841-.099609-1h-9.8008z" fill="#45d7ff"/><path d="m3.1016 11c.15381.74405.48967 1.4159.93555 2h7.9258c.44588-.5841.78173-1.2559.93555-2h-9.7969z" fill="#8045ff"/><path d="m4.0371 13c.9218 1.2076 2.3612 2 3.9629 2s3.0411-.79243 3.9629-2z" fill="#ff4596"/><path d="m8 1c-.45196.75327-.87224 1.3994-1.2754 2h2.5508c-.40315-.6006-.82343-1.2467-1.2754-2z" fill="#ff4545"/></g></svg>
diff --git a/editor/icons/ThemeDeselectAll.svg b/editor/icons/ThemeDeselectAll.svg
new file mode 100644
index 0000000000..d43ca85163
--- /dev/null
+++ b/editor/icons/ThemeDeselectAll.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m5.952 6.976h8.063v2.005h-8.063z" fill-rule="nonzero"/><path d="m.989 5.995h4.011v4.01h-4.011zm.968.968h2.075v2.074h-2.075z"/><path d="m5.952 1.956h8.063v2.005h-8.063z" fill-rule="nonzero"/><path d="m.989.974h4.011v4.011h-4.011zm.968.968h2.075v2.075h-2.075z"/><path d="m5.952 11.996h8.063v2.005h-8.063z" fill-rule="nonzero"/><path d="m.989 11.015h4.011v4.011h-4.011zm.968.968h2.075v2.075h-2.075z"/></g></svg>
diff --git a/editor/icons/ThemeRemoveAllItems.svg b/editor/icons/ThemeRemoveAllItems.svg
new file mode 100644
index 0000000000..c04254ea8d
--- /dev/null
+++ b/editor/icons/ThemeRemoveAllItems.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1.745c-.595 0-1.084.489-1.084 1.084v3.699l-3.851-1.927c-.163-.08-.343-.119-.525-.112-.395.015-.752.244-.929.597-.076.151-.115.317-.115.485 0 .41.233.786.599.97l3.481 1.74-3.481 1.74c-.366.184-.599.56-.599.97 0 .168.039.334.115.485.183.367.559.599.969.599.168 0 .334-.039.485-.114l3.851-1.927v3.111c0 .594.489 1.084 1.084 1.084s1.084-.49 1.084-1.084v-3.111l3.851 1.927c.151.075.317.114.485.114.41 0 .786-.232.969-.599.076-.151.115-.317.115-.485 0-.41-.233-.786-.599-.97l-3.481-1.74 3.481-1.74c.366-.184.599-.56.599-.97 0-.168-.039-.334-.115-.485-.182-.364-.554-.596-.961-.599-.171-.001-.34.038-.493.114l-3.851 1.927v-3.699c0-.595-.489-1.084-1.084-1.084z" fill="#8eef97"/><g fill-rule="nonzero"><path d="m8 1.745v1.783h-1.084v-.699c0-.595.489-1.084 1.084-1.084z" fill="#ff4545"/><path d="m1.528 5.312h2.957l-1.42-.711c-.163-.08-.343-.119-.525-.112-.395.015-.752.244-.929.597-.036.072-.064.148-.083.226zm5.388-1.784h1.084v1.784h-1.084z" fill="#ffe345"/><path d="m6.916 5.312h1.084v1.783h-4.796l-1.109-.554c-.366-.184-.599-.56-.599-.97 0-.088.011-.175.032-.259h2.957l2.431 1.216z" fill="#80ff45"/><path d="m3.204 7.095h4.796v1.783h-3.619l1.195-.597z" fill="#45ffa2"/><path d="m4.381 8.878h3.619v1.784h-1.084v-.628l-1.255.628h-4.114c.088-.274.283-.508.548-.641z" fill="#45d7ff"/><path d="m6.916 12.445h1.084v1.784c-.595-.001-1.084-.49-1.084-1.084z" fill="#ff4596"/><path d="m6.916 10.662h1.084v1.783h-1.084zm-1.255 0h-4.114c-.033.105-.051.216-.051.329 0 .168.039.334.115.485.183.367.559.599.969.599.168 0 .334-.039.485-.114z" fill="#8045ff"/></g></svg>
diff --git a/editor/icons/ThemeRemoveCustomItems.svg b/editor/icons/ThemeRemoveCustomItems.svg
new file mode 100644
index 0000000000..5ecde9ff55
--- /dev/null
+++ b/editor/icons/ThemeRemoveCustomItems.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><path d="m11.299 3c.772.513 1.42 1.199 1.888 2h-2.553c-.706-.621-1.629-1-2.634-1s-1.928.379-2.634 1h-2.553c.468-.801 1.116-1.487 1.888-2z" fill="#ffe345"/><path d="m5.366 5c-.593.522-1.033 1.216-1.238 2h-2.043c.122-.717.373-1.392.728-2zm7.821 0c.355.608.606 1.283.728 2h-2.043c-.205-.784-.645-1.478-1.238-2z" fill="#80ff45"/><path d="m13.915 7c.056.326.085.66.085 1s-.029.674-.085 1h-2.043c.083-.32.128-.655.128-1s-.045-.68-.128-1zm-9.787 0c-.083.32-.128.655-.128 1s.045.68.128 1h-2.043c-.056-.326-.085-.66-.085-1s.029-.674.085-1z" fill="#45ffa2"/><path d="m4.128 9c.205.784.645 1.478 1.238 2h-2.553c-.355-.608-.606-1.283-.728-2zm9.787 0c-.122.717-.373 1.392-.728 2h-2.553c.593-.522 1.033-1.216 1.238-2z" fill="#45d7ff"/><path d="m11.299 13h-6.598c.949.631 2.084 1 3.299 1s2.35-.369 3.299-1z" fill="#ff4596"/><path d="m13.187 11c-.468.801-1.116 1.487-1.888 2h-6.598c-.772-.513-1.42-1.199-1.888-2h2.553c.706.621 1.629 1 2.634 1s1.928-.379 2.634-1z" fill="#8045ff"/><path d="m4.701 3h6.598c-.949-.631-2.084-1-3.299-1s-2.35.369-3.299 1z" fill="#ff4545"/></g></svg>
diff --git a/editor/icons/ThemeSelectAll.svg b/editor/icons/ThemeSelectAll.svg
new file mode 100644
index 0000000000..59d9fb3387
--- /dev/null
+++ b/editor/icons/ThemeSelectAll.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m5.952 6.976h8.049v2.005h-8.049z" fill="#e0e0e0" fill-rule="nonzero"/><path d="m.989 5.995h4.011v4.011h-4.011z" fill="#fff" fill-rule="nonzero"/><path d="m.989 5.995h4.011v4.01h-4.011zm.968.968h2.075v2.074h-2.075z" fill="#e0e0e0"/><path d="m5.952 1.956h8.049v2.005h-8.049z" fill="#e0e0e0" fill-rule="nonzero"/><path d="m.989.974h4.011v4.011h-4.011z" fill="#fff" fill-rule="nonzero"/><path d="m.989.974h4.011v4.011h-4.011zm.968.968h2.075v2.075h-2.075z" fill="#e0e0e0"/><path d="m5.952 11.996h8.049v2.005h-8.049z" fill="#e0e0e0" fill-rule="nonzero"/><path d="m.989 11.015h4.011v4.011h-4.011z" fill="#fff" fill-rule="nonzero"/><path d="m.989 11.015h4.011v4.011h-4.011zm.968.968h2.075v2.075h-2.075z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/ThemeSelectFull.svg b/editor/icons/ThemeSelectFull.svg
new file mode 100644
index 0000000000..0fabb9961a
--- /dev/null
+++ b/editor/icons/ThemeSelectFull.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m11 6.976h3.015v2.005h-3.015z" fill="#e0e0e0" fill-rule="nonzero"/><path d="m.989 5.995h4.011v4.011h-4.011z" fill="#fff" fill-rule="nonzero"/><path d="m.989 5.995h4.011v4.01h-4.011zm.968.968h2.075v2.074h-2.075z" fill="#e0e0e0"/><path d="m11 1.956h3.015v2.005h-3.015z" fill="#e0e0e0" fill-rule="nonzero"/><path d="m.989.974h4.011v4.011h-4.011z" fill="#fff" fill-rule="nonzero"/><path d="m.989.974h4.011v4.011h-4.011zm.968.968h2.075v2.075h-2.075z" fill="#e0e0e0"/><path d="m11 11.996h3.015v2.005h-3.015z" fill="#e0e0e0" fill-rule="nonzero"/><path d="m.989 11.015h4.011v4.011h-4.011z" fill="#fff" fill-rule="nonzero"/><path d="m.989 11.015h4.011v4.011h-4.011zm.968.968h2.075v2.075h-2.075z" fill="#e0e0e0"/><path d="m5.995 5.995h4.011v4.011h-4.011z" fill="#fff" fill-rule="nonzero"/><path d="m5.995 5.995h4.01v4.01h-4.01zm.968.968h2.074v2.074h-2.074z" fill="#e0e0e0"/><path d="m5.995.974h4.011v4.011h-4.011z" fill="#fff" fill-rule="nonzero"/><path d="m5.995.974h4.01v4.011h-4.01zm.968.968h2.074v2.075h-2.074z" fill="#e0e0e0"/><path d="m5.995 11.015h4.011v4.011h-4.011z" fill="#fff" fill-rule="nonzero"/><path d="m5.995 11.015h4.01v4.011h-4.01zm.968.968h2.074v2.075h-2.074z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/TileMap.svg b/editor/icons/TileMap.svg
index d1904338a8..291d02b858 100644
--- a/editor/icons/TileMap.svg
+++ b/editor/icons/TileMap.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-12 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-12 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-12 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-12 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2z" fill="#a5b7f3" fill-opacity=".98824"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-12 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-12 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-12 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm-12 3v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2z" fill="#8da5f3" fill-opacity=".98824"/></svg>
diff --git a/editor/icons/TouchScreenButton.svg b/editor/icons/TouchScreenButton.svg
index aec0951d59..7e3e232867 100644
--- a/editor/icons/TouchScreenButton.svg
+++ b/editor/icons/TouchScreenButton.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a1 1 0 0 0 -1 1v2a1 1 0 0 0 1 1h2v-1h-1-1v-2h8v2h-2v1h2a1 1 0 0 0 1-1v-2a1 1 0 0 0 -1-1zm4 2a1 1 0 0 0 -1 1v7 .033203l-2.4746-1.8086c-.52015-.3803-1.1948-.4556-1.6504 0-.45566.4556-.45561 1.1948 0 1.6504l4.125 4.125h6c1.1046 0 2-.8954 2-2v-5h-6v-4a1 1 0 0 0 -1-1z" fill="#a5b7f3" fill-opacity=".98824"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a1 1 0 0 0 -1 1v2a1 1 0 0 0 1 1h2v-1h-1-1v-2h8v2h-2v1h2a1 1 0 0 0 1-1v-2a1 1 0 0 0 -1-1zm4 2a1 1 0 0 0 -1 1v7 .033203l-2.4746-1.8086c-.52015-.3803-1.1948-.4556-1.6504 0-.45566.4556-.45561 1.1948 0 1.6504l4.125 4.125h6c1.1046 0 2-.8954 2-2v-5h-6v-4a1 1 0 0 0 -1-1z" fill="#8da5f3" fill-opacity=".98824"/></svg>
diff --git a/editor/icons/TrackAddKey.svg b/editor/icons/TrackAddKey.svg
index 5d2b4ebaf9..82eff5d2bf 100644
--- a/editor/icons/TrackAddKey.svg
+++ b/editor/icons/TrackAddKey.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg"><path d="m3 0v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#84ffb1"/></svg>
+<svg height="8" viewBox="0 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg"><path d="m3 0v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#5fff97"/></svg>
diff --git a/editor/icons/TrackAddKeyHl.svg b/editor/icons/TrackAddKeyHl.svg
index 0a0cdea48c..03fb90f1e9 100644
--- a/editor/icons/TrackAddKeyHl.svg
+++ b/editor/icons/TrackAddKeyHl.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg"><path d="m3 0v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#84ffb1"/><path d="m3 0v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#fff" fill-opacity=".42424"/></svg>
+<svg height="8" viewBox="0 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg"><path d="m3 0v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#5fff97"/><path d="m3 0v3h-3v2h3v3h2v-3h3v-2h-3v-3z" fill="#fff" fill-opacity=".42424"/></svg>
diff --git a/editor/icons/Transform2D.svg b/editor/icons/Transform2D.svg
index a0b5430298..75be0b73e1 100644
--- a/editor/icons/Transform2D.svg
+++ b/editor/icons/Transform2D.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v2h2v6h2v-6h2v-2zm7 0v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.0019531v2h7a4 4 0 0 0 3.4648-2 4 4 0 0 0 0-4 4 4 0 0 0 -3.4648-2h-2v6h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5zm5 2a2 2 0 0 1 1.7324 1 2 2 0 0 1 0 2 2 2 0 0 1 -1.7324 1z" fill="#c4ec69"/><path d="m7 2v2c.55228 0 1 .44772 1 1s-.44772 1-1 1c-.71466-.0001326-1.3751.38108-1.7324 1-.17472.30426-.26633.64914-.26562 1h-.0019531v2h5v-2h-3c1.0716-.00015 2.0618-.57193 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.53582-.92807-1.526-1.4998-2.5977-1.5z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v2h2v6h2v-6h2v-2zm7 0v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.0019531v2h7a4 4 0 0 0 3.4648-2 4 4 0 0 0 0-4 4 4 0 0 0 -3.4648-2h-2v6h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5zm5 2a2 2 0 0 1 1.7324 1 2 2 0 0 1 0 2 2 2 0 0 1 -1.7324 1z" fill="#b9ec41"/><path d="m7 2v2c.55228 0 1 .44772 1 1s-.44772 1-1 1c-.71466-.0001326-1.3751.38108-1.7324 1-.17472.30426-.26633.64914-.26562 1h-.0019531v2h5v-2h-3c1.0716-.00015 2.0618-.57193 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.53582-.92807-1.526-1.4998-2.5977-1.5z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/Transform.svg b/editor/icons/Transform3D.svg
index 4d9bb829cd..a940120702 100644
--- a/editor/icons/Transform.svg
+++ b/editor/icons/Transform3D.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2 2 4-2 4h2l.9082-2.1816 1.0918 2.1816h2l-2-4 2-4h-2l-.9082 2.1816-1.0918-2.1816zm6 8h2v-2h1v-2h-1v-1c.0000096-.55228.44772-.99999 1-1h1v-2h-1c-1.6569 0-3 1.3431-3 3zm4-6v6h2v-2l1 1 1-1v2h2v-6h-2l-1 2-1-2z" fill="#f6a86e"/><path d="m9 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1-1h1v-2z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2 2 4-2 4h2l.9082-2.1816 1.0918 2.1816h2l-2-4 2-4h-2l-.9082 2.1816-1.0918-2.1816zm6 8h2v-2h1v-2h-1v-1c.0000096-.55228.44772-.99999 1-1h1v-2h-1c-1.6569 0-3 1.3431-3 3zm4-6v6h2v-2l1 1 1-1v2h2v-6h-2l-1 2-1-2z" fill="#f68f45"/><path d="m9 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1-1h1v-2z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/Tree.svg b/editor/icons/Tree.svg
index 9476f40db3..a6c8ace55f 100644
--- a/editor/icons/Tree.svg
+++ b/editor/icons/Tree.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v13c.0000552.55226.44774.99994 1 1h13v-2h-12v-6h2v3c.0000552.55226.44774.99994 1 1h9v-2h-8v-2h8v-2h-12v-2h12v-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v13c.0000552.55226.44774.99994 1 1h13v-2h-12v-6h2v3c.0000552.55226.44774.99994 1 1h9v-2h-8v-2h8v-2h-12v-2h12v-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/TubeTrailMesh.svg b/editor/icons/TubeTrailMesh.svg
new file mode 100644
index 0000000000..3ca524226f
--- /dev/null
+++ b/editor/icons/TubeTrailMesh.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ffca5f"><path d="m14.0625 7.5c0-1.6377-.2123-3.12-.5969-4.2737-.1923-.57682-.4237-1.0754-.7508-1.4905-.3271-.41505-.8259-.79834-1.4648-.79834h-7.5c-.6389 0-1.1396.38329-1.4667.79834s-.5585.91366-.7507 1.4905c-.3846 1.1536-.5951 2.6359-.5951 4.2737s.2105 3.12.5951 4.2737c.1922.57682.4236 1.0754.7507 1.4905.3271.41505.8278.79834 1.4667.79834h7.5c.6389 0 1.1377-.38329 1.4648-.79834s.5585-.91366.7508-1.4905c.3846-1.1536.5969-2.6359.5969-4.2737zm-2.8125-4.6875002c.4358 1.0052002 0 0 .4358 1.0052002.2941.88221.5017 2.2134.5017 3.6823s-.2076 2.8-.5017 3.6823c-.1449.4347 0 0-.4358 1.005199l-7.5.000041c-.1212-.15705-.2929-.57092-.4376-1.0052-.2941-.88221-.4999-2.2134-.4999-3.6823s.2058-2.8.4999-3.6823c.1447-.43433.3164-.8482.4376-1.0052"/><path d="m6.5625-11.25h1.875v7.5h-1.875z" stroke-width=".25" transform="rotate(90)"/></g></svg>
diff --git a/editor/icons/Tween.svg b/editor/icons/Tween.svg
index d5cfbbcd88..388aaaf66a 100644
--- a/editor/icons/Tween.svg
+++ b/editor/icons/Tween.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v2h6v6h2v-8zm-1 4 1.793 1.793-4.793 4.793v-4.5859h-2v8h8v-2h-4.5859l4.793-4.793 1.793 1.793v-5h-5z" fill="#cea4f1" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v2h6v6h2v-8zm-1 4 1.793 1.793-4.793 4.793v-4.5859h-2v8h8v-2h-4.5859l4.793-4.793 1.793 1.793v-5h-5z" fill="#c38ef1" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/VBoxContainer.svg b/editor/icons/VBoxContainer.svg
index 9a68df4f6a..c515d61d83 100644
--- a/editor/icons/VBoxContainer.svg
+++ b/editor/icons/VBoxContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 1039.4c0-1.1046-.89543-2-2-2h-10c-1.1046 0-2 .8954-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2zm-2 0v2h-10v-2zm0 4v2h-10v-2zm0 4v2h-10v-2z" fill="#a5efac" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 1039.4c0-1.1046-.89543-2-2-2h-10c-1.1046 0-2 .8954-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2zm-2 0v2h-10v-2zm0 4v2h-10v-2zm0 4v2h-10v-2z" fill="#8eef97" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/VScrollBar.svg b/editor/icons/VScrollBar.svg
index e0fc575860..65f068f8da 100644
--- a/editor/icons/VScrollBar.svg
+++ b/editor/icons/VScrollBar.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1c-1.108 0-2 .89199-2 2v10c0 1.108.89199 2 2 2h6c1.108 0 2-.89199 2-2v-10c0-1.108-.89199-2-2-2zm2.9883 1a1.0001 1.0001 0 0 1 .56641.16797l3 2a1.0001 1.0001 0 1 1 -1.1094 1.6641l-2.4453-1.6289-2.4453 1.6289a1.0001 1.0001 0 1 1 -1.1094-1.6641l3-2a1.0001 1.0001 0 0 1 .54297-.16797zm-2.998 7.9922a1.0001 1.0001 0 0 1 .56445.17578l2.4453 1.6309 2.4453-1.6309a1.0001 1.0001 0 1 1 1.1094 1.6641l-3 2a1.0001 1.0001 0 0 1 -1.1094 0l-3-2a1.0001 1.0001 0 0 1 .54492-1.8398z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1c-1.108 0-2 .89199-2 2v10c0 1.108.89199 2 2 2h6c1.108 0 2-.89199 2-2v-10c0-1.108-.89199-2-2-2zm2.9883 1a1.0001 1.0001 0 0 1 .56641.16797l3 2a1.0001 1.0001 0 1 1 -1.1094 1.6641l-2.4453-1.6289-2.4453 1.6289a1.0001 1.0001 0 1 1 -1.1094-1.6641l3-2a1.0001 1.0001 0 0 1 .54297-.16797zm-2.998 7.9922a1.0001 1.0001 0 0 1 .56445.17578l2.4453 1.6309 2.4453-1.6309a1.0001 1.0001 0 1 1 1.1094 1.6641l-3 2a1.0001 1.0001 0 0 1 -1.1094 0l-3-2a1.0001 1.0001 0 0 1 .54492-1.8398z" fill="#8eef97"/></svg>
diff --git a/editor/icons/VSeparator.svg b/editor/icons/VSeparator.svg
index 11038b7542..1fd31d89d1 100644
--- a/editor/icons/VSeparator.svg
+++ b/editor/icons/VSeparator.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1047.4h3v-6h-3zm5 4h2v-14h-2zm4-4h3v-6h-3z" fill="#a5efac" transform="translate(0 -1036.4)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1047.4h3v-6h-3zm5 4h2v-14h-2zm4-4h3v-6h-3z" fill="#8eef97" transform="translate(0 -1036.4)"/></svg>
diff --git a/editor/icons/VSlider.svg b/editor/icons/VSlider.svg
index 0ecb1e9aa3..16fafe1162 100644
--- a/editor/icons/VSlider.svg
+++ b/editor/icons/VSlider.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm5 0c-.55228 0-1 .44772-1 1s.44772 1 1 1h2c.55228 0 1-.44772 1-1s-.44772-1-1-1zm-4 5.8672c-.32639.086294-.6624.13092-1 .13281-.33752-.0012549-.67352-.045224-1-.13086v5 1.1309 1c-.019125 1.3523 2.0191 1.3523 2 0v-1-1.1328-5zm5 .13281c-.55228 0-1 .44772-1 1s.44772 1 1 1 1-.44772 1-1-.44772-1-1-1zm-1 6c-.55228 0-1 .44772-1 1s.44772 1 1 1h2c.55228 0 1-.44772 1-1s-.44772-1-1-1z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm5 0c-.55228 0-1 .44772-1 1s.44772 1 1 1h2c.55228 0 1-.44772 1-1s-.44772-1-1-1zm-4 5.8672c-.32639.086294-.6624.13092-1 .13281-.33752-.0012549-.67352-.045224-1-.13086v5 1.1309 1c-.019125 1.3523 2.0191 1.3523 2 0v-1-1.1328-5zm5 .13281c-.55228 0-1 .44772-1 1s.44772 1 1 1 1-.44772 1-1-.44772-1-1-1zm-1 6c-.55228 0-1 .44772-1 1s.44772 1 1 1h2c.55228 0 1-.44772 1-1s-.44772-1-1-1z" fill="#8eef97"/></svg>
diff --git a/editor/icons/VSplitContainer.svg b/editor/icons/VSplitContainer.svg
index 21d45bd5e7..785b1b1880 100644
--- a/editor/icons/VSplitContainer.svg
+++ b/editor/icons/VSplitContainer.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v4h-3l-2-2-2 2h-3zm0 6h3l2 2 2-2h3v4h-10z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm0 2h10v4h-3l-2-2-2 2h-3zm0 6h3l2 2 2-2h3v4h-10z" fill="#8eef97"/></svg>
diff --git a/editor/icons/Variant.svg b/editor/icons/Variant.svg
index 71ebd060ae..dff2c67ebc 100644
--- a/editor/icons/Variant.svg
+++ b/editor/icons/Variant.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-6zm3 0v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm5 3a3 3 0 0 0 3 3v2h2v-8h-2v4a1 1 0 0 1 -1-1v-3h-2zm-8-1v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#69ecbd"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-6zm3 0v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm5 3a3 3 0 0 0 3 3v2h2v-8h-2v4a1 1 0 0 1 -1-1v-3h-2zm-8-1v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#41ecad"/></svg>
diff --git a/editor/icons/Vector2.svg b/editor/icons/Vector2.svg
index 43a93df83f..2bab922ca9 100644
--- a/editor/icons/Vector2.svg
+++ b/editor/icons/Vector2.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.001953v2h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5zm-11 2v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm5 3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2h-1a3 3 0 0 0 -3 3z" fill="#bd91f1"/><path d="m12 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.001953v2h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.001953v2h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5zm-11 2v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm5 3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2h-1a3 3 0 0 0 -3 3z" fill="#ac73f1"/><path d="m12 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.001953v2h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/Vector2i.svg b/editor/icons/Vector2i.svg
index 39803fd6a4..f2923542e8 100644
--- a/editor/icons/Vector2i.svg
+++ b/editor/icons/Vector2i.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2v2h1c.55228 0 1 .44772 1 1s-.44772 1-1 1c-.71466-.0001248-1.3751.38109-1.7324 1-.17472.30426-.26633.64914-.26562 1h-.002v2h5v-2h-3c1.0717-.0001344 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.53578-.92809-1.526-1.4999-2.5977-1.5zm-7 2v6h2c1.6569 0 3-1.3431 3-3v-3h-2v3c0 .55228-.44772 1-1 1v-4z" fill="#bd91f1"/><path d="m8 2v2h1c.55228 0 1 .44772 1 1s-.44772 1-1 1c-.71466-.0001248-1.3751.38109-1.7324 1-.17472.30426-.26633.64914-.26562 1h-.001953v2h5v-2h-3c1.0717-.0001344 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.53583-.92809-1.526-1.4999-2.5977-1.5z" fill="#fff" fill-opacity=".39216"/><path d="m13 2v2h2v-2zm0 4v4h2v-4z" fill="#7dc6ef"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2v2h1c.55228 0 1 .44772 1 1s-.44772 1-1 1c-.71466-.0001248-1.3751.38109-1.7324 1-.17472.30426-.26633.64914-.26562 1h-.002v2h5v-2h-3c1.0717-.0001344 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.53578-.92809-1.526-1.4999-2.5977-1.5zm-7 2v6h2c1.6569 0 3-1.3431 3-3v-3h-2v3c0 .55228-.44772 1-1 1v-4z" fill="#ac73f1"/><path d="m8 2v2h1c.55228 0 1 .44772 1 1s-.44772 1-1 1c-.71466-.0001248-1.3751.38109-1.7324 1-.17472.30426-.26633.64914-.26562 1h-.001953v2h5v-2h-3c1.0717-.0001344 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.53583-.92809-1.526-1.4999-2.5977-1.5z" fill="#fff" fill-opacity=".39216"/><path d="m13 2v2h2v-2zm0 4v4h2v-4z" fill="#5abbef"/></svg>
diff --git a/editor/icons/Vector3.svg b/editor/icons/Vector3.svg
index 2606f6e22b..85cac571cf 100644
--- a/editor/icons/Vector3.svg
+++ b/editor/icons/Vector3.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 2v2h2a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -.36523-.50195 3 3 0 0 0 .36523-.49805 3 3 0 0 0 .39844-1.5h.003906v-2zm-11 2v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm5 3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2h-1a3 3 0 0 0 -3 3z" fill="#e286f0"/><path d="m12 2v2h2a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -.36523-.50195 3 3 0 0 0 .36523-.49805 3 3 0 0 0 .39844-1.5h.003906v-2z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 2v2h2a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -.36523-.50195 3 3 0 0 0 .36523-.49805 3 3 0 0 0 .39844-1.5h.003906v-2zm-11 2v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm5 3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2h-1a3 3 0 0 0 -3 3z" fill="#de66f0"/><path d="m12 2v2h2a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -.36523-.50195 3 3 0 0 0 .36523-.49805 3 3 0 0 0 .39844-1.5h.003906v-2z" fill="#fff" fill-opacity=".39216"/></svg>
diff --git a/editor/icons/Vector3i.svg b/editor/icons/Vector3i.svg
index 09651193a5..26e9c1b3ef 100644
--- a/editor/icons/Vector3i.svg
+++ b/editor/icons/Vector3i.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.45296.92408-1 1h-1v2h1c1.0717-.000134 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34771-.36523-.50195.13855-.15301.26094-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.0039v-2zm-7 2v6h2c1.6569 0 3-1.3431 3-3v-3h-2v3c0 .55228-.44772 1-1 1v-4z" fill="#e286f0"/><path d="m8 2v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.44948.95585-1 1h-1v2h1c1.0717-.000134 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34771-.36523-.50195.13855-.15301.26094-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.0039v-2z" fill="#fff" fill-opacity=".39216"/><path d="m13 2v2h2v-2zm0 4v4h2v-4z" fill="#7dc6ef"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.45296.92408-1 1h-1v2h1c1.0717-.000134 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34771-.36523-.50195.13855-.15301.26094-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.0039v-2zm-7 2v6h2c1.6569 0 3-1.3431 3-3v-3h-2v3c0 .55228-.44772 1-1 1v-4z" fill="#de66f0"/><path d="m8 2v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.44948.95585-1 1h-1v2h1c1.0717-.000134 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34771-.36523-.50195.13855-.15301.26094-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.0039v-2z" fill="#fff" fill-opacity=".39216"/><path d="m13 2v2h2v-2zm0 4v4h2v-4z" fill="#5abbef"/></svg>
diff --git a/editor/icons/VehicleBody3D.svg b/editor/icons/VehicleBody3D.svg
index 0cfbad371c..00e4696a17 100644
--- a/editor/icons/VehicleBody3D.svg
+++ b/editor/icons/VehicleBody3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 3a1 1 0 0 0 -1 1l-1 3h-2v4h1.0508c.23167-1.1411 1.2398-2 2.4492-2s2.2175.85893 2.4492 2h2.1016c.23167-1.1411 1.2398-2 2.4492-2s2.2175.85893 2.4492 2h1.0508v-4h-4v-4zm1 1h4v3h-4zm-1.5 6a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5zm7 0a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 3a1 1 0 0 0 -1 1l-1 3h-2v4h1.0508c.23167-1.1411 1.2398-2 2.4492-2s2.2175.85893 2.4492 2h2.1016c.23167-1.1411 1.2398-2 2.4492-2s2.2175.85893 2.4492 2h1.0508v-4h-4v-4zm1 1h4v3h-4zm-1.5 6a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5zm7 0a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/VehicleWheel3D.svg b/editor/icons/VehicleWheel3D.svg
index 0391eac4cf..4c825d6e34 100644
--- a/editor/icons/VehicleWheel3D.svg
+++ b/editor/icons/VehicleWheel3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm0 2a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5zm0 1a4 4 0 0 0 -4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0 -4-4zm0 1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-2 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-2 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm0 2a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5zm0 1a4 4 0 0 0 -4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0 -4-4zm0 1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-2 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm-2 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/VideoPlayer.svg b/editor/icons/VideoPlayer.svg
index c5433e0131..092a26b955 100644
--- a/editor/icons/VideoPlayer.svg
+++ b/editor/icons/VideoPlayer.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.0907 0-2 .9093-2 2v10c0 1.0907.90929 2 2 2h10c1.0907 0 2-.9093 2-2v-10c0-1.0907-.90929-2-2-2zm0 2h10v8h-10zm3 2v4l4-2z" fill="#a5efac"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.0907 0-2 .9093-2 2v10c0 1.0907.90929 2 2 2h10c1.0907 0 2-.9093 2-2v-10c0-1.0907-.90929-2-2-2zm0 2h10v8h-10zm3 2v4l4-2z" fill="#8eef97"/></svg>
diff --git a/editor/icons/VisibilityEnabler2D.svg b/editor/icons/VisibilityEnabler2D.svg
index e603936d83..989675f44f 100644
--- a/editor/icons/VisibilityEnabler2D.svg
+++ b/editor/icons/VisibilityEnabler2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v3h1v-2h2v-1zm11 0v1h2v2h1v-3zm-4 1c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0-.55273c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-7 6v3h3v-1h-2v-2zm13 0v2h-2v1h3v-3z" fill="#a5b7f3" fill-opacity=".98824" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v3h1v-2h2v-1zm11 0v1h2v2h1v-3zm-4 1c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0-.55273c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-7 6v3h3v-1h-2v-2zm13 0v2h-2v1h3v-3z" fill="#8da5f3" fill-opacity=".98824" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/VisibilityEnabler3D.svg b/editor/icons/VisibilityEnabler3D.svg
index 07ba8b88df..6923bcb46b 100644
--- a/editor/icons/VisibilityEnabler3D.svg
+++ b/editor/icons/VisibilityEnabler3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v3h1v-2h2v-1zm11 0v1h2v2h1v-3zm-4 1c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0-.55273c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-7 6v3h3v-1h-2v-2zm13 0v2h-2v1h3v-3z" fill="#fc9c9c" fill-opacity=".99608" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v3h1v-2h2v-1zm11 0v1h2v2h1v-3zm-4 1c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246s5.8365-1.7892 6.9609-5.7246a1.0001 1.0001 0 0 0 0-.55273c-1.1003-3.7876-4.4066-5.7227-6.9609-5.7227zm0 2a4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4zm0 2a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm-7 6v3h3v-1h-2v-2zm13 0v2h-2v1h3v-3z" fill="#fc7f7f" fill-opacity=".99608" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/VisibilityNotifier2D.svg b/editor/icons/VisibilityNotifier2D.svg
index 8eaf8334ac..13df19be56 100644
--- a/editor/icons/VisibilityNotifier2D.svg
+++ b/editor/icons/VisibilityNotifier2D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 1v6h2v-6zm-4 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246 1.4907 0 3.2717-.65207 4.7109-2h-.71094-2v-.54102a4 4 0 0 1 -2 .54102 4 4 0 0 1 -4-4 4 4 0 0 1 4-4 4 4 0 0 1 2 .54102v-2.1816c-.68312-.23834-1.3644-.35938-2-.35938zm0 4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm4 2v2h2v-2z" fill="#a5b7f3" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 1v6h2v-6zm-4 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246 1.4907 0 3.2717-.65207 4.7109-2h-.71094-2v-.54102a4 4 0 0 1 -2 .54102 4 4 0 0 1 -4-4 4 4 0 0 1 4-4 4 4 0 0 1 2 .54102v-2.1816c-.68312-.23834-1.3644-.35938-2-.35938zm0 4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm4 2v2h2v-2z" fill="#8da5f3" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/VisibilityNotifier3D.svg b/editor/icons/VisibilityNotifier3D.svg
index afb433c9ed..2fdf784701 100644
--- a/editor/icons/VisibilityNotifier3D.svg
+++ b/editor/icons/VisibilityNotifier3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 1v6h2v-6zm-4 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246 1.4907 0 3.2717-.65207 4.7109-2h-.71094-2v-.54102a4 4 0 0 1 -2 .54102 4 4 0 0 1 -4-4 4 4 0 0 1 4-4 4 4 0 0 1 2 .54102v-2.1816c-.68312-.23834-1.3644-.35938-2-.35938zm0 4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm4 2v2h2v-2z" fill="#fc9c9c" fill-opacity=".99608" fill-rule="evenodd"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 1v6h2v-6zm-4 2c-2.5567 0-5.7907 1.9477-6.9551 5.7051a1.0001 1.0001 0 0 0 -.0058594.57031c1.1244 3.9354 4.4609 5.7246 6.9609 5.7246 1.4907 0 3.2717-.65207 4.7109-2h-.71094-2v-.54102a4 4 0 0 1 -2 .54102 4 4 0 0 1 -4-4 4 4 0 0 1 4-4 4 4 0 0 1 2 .54102v-2.1816c-.68312-.23834-1.3644-.35938-2-.35938zm0 4a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm4 2v2h2v-2z" fill="#fc7f7f" fill-opacity=".99608" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/VisualShader.svg b/editor/icons/VisualShader.svg
index 7006066592..92b4737cbe 100644
--- a/editor/icons/VisualShader.svg
+++ b/editor/icons/VisualShader.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m2.8642 9.9954v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4z"/><path d="m10.864 9.9954a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z"/><path d="m2 1c-.55226.0001-.99994.4477-1 1v7h2v-6h6v3c0 .554.44599 1 1 1h3v2h2v-3l-5-5z"/></g><path d="m4 6h2v1h-2z" fill="#ffeb70"/><path d="m8 8h4v1h-4z" fill="#9dff70"/><path d="m7 6h1v1h-1z" fill="#70deff"/><path d="m4 4h3v1h-3z" fill="#ff7070"/><path d="m4 8h3v1h-3z" fill="#70ffb9"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m2.8642 9.9954v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4z"/><path d="m10.864 9.9954a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z"/><path d="m2 1c-.55226.0001-.99994.4477-1 1v7h2v-6h6v3c0 .554.44599 1 1 1h3v2h2v-3l-5-5z"/></g><path d="m4 6h2v1h-2z" fill="#ffe345"/><path d="m8 8h4v1h-4z" fill="#80ff45"/><path d="m7 6h1v1h-1z" fill="#45d7ff"/><path d="m4 4h3v1h-3z" fill="#ff4545"/><path d="m4 8h3v1h-3z" fill="#45ffa2"/></svg>
diff --git a/editor/icons/GIProbe.svg b/editor/icons/VoxelGI.svg
index b66c937317..f5e1025260 100644
--- a/editor/icons/GIProbe.svg
+++ b/editor/icons/VoxelGI.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1.0001 1.0001 0 0 0 -1 1v12a1.0001 1.0001 0 0 0 1 1h4v-2h-3v-10h9v-2zm9 3a4 4 0 0 0 -4 4 4 4 0 0 0 2 3.459v.54102c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1v-.54102a4 4 0 0 0 2-3.459 4 4 0 0 0 -4-4zm0 2a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2zm-1 8v1h2v-1z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1a1.0001 1.0001 0 0 0 -1 1v12a1.0001 1.0001 0 0 0 1 1h4v-2h-3v-10h9v-2zm9 3a4 4 0 0 0 -4 4 4 4 0 0 0 2 3.459v.54102c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1v-.54102a4 4 0 0 0 2-3.459 4 4 0 0 0 -4-4zm0 2a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2zm-1 8v1h2v-1z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/editor/icons/GIProbeData.svg b/editor/icons/VoxelGIData.svg
index 5975115f4c..5975115f4c 100644
--- a/editor/icons/GIProbeData.svg
+++ b/editor/icons/VoxelGIData.svg
diff --git a/editor/icons/WarningPattern.svg b/editor/icons/WarningPattern.svg
new file mode 100644
index 0000000000..8ef2c14041
--- /dev/null
+++ b/editor/icons/WarningPattern.svg
@@ -0,0 +1 @@
+<svg height="64" viewBox="0 0 64 64" width="64" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v8l8-8zm16 0-16 16v8l24-24zm16 0-32 32v8l40-40zm16 0-48 48v8l56-56zm16 0-64 64h8l56-56zm0 16-48 48h8l40-40zm0 16-32 32h8s24-23 24-24zm0 16-16 16h8l8-8z" fill="#fff"/></svg>
diff --git a/editor/icons/WorldEnvironment.svg b/editor/icons/WorldEnvironment.svg
index 314639a576..d26ec52034 100644
--- a/editor/icons/WorldEnvironment.svg
+++ b/editor/icons/WorldEnvironment.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm-1.7305 2.3125c-.83125 1.5372-1.2685 3.1037-1.2695 4.6816-.64057-.11251-1.3005-.27158-1.9766-.47266a5 5 0 0 1 3.2461-4.209zm3.4629.0039062a5 5 0 0 1 3.2383 4.1875c-.65187.17448-1.3077.32867-1.9727.44922-.00845-1.5627-.44294-3.1141-1.2656-4.6367zm-1.7324.0078126c1.0126 1.593 1.5 3.1425 1.5 4.6758 0 .054042-.0066161.10803-.0078125.16211-.96392.096801-1.9566.1103-2.9844.027344-.0016335-.063192-.0078125-.12632-.0078125-.18945 0-1.5333.48744-3.0828 1.5-4.6758zm4.8789 5.7578a5 5 0 0 1 -3.1484 3.6055c.57106-1.0564.95277-2.1268 1.1367-3.2051.68204-.10905 1.3556-.23789 2.0117-.40039zm-9.7461.033203c.68377.18153 1.3555.33345 2.0098.43164.18781 1.0551.56647 2.1026 1.125 3.1367a5 5 0 0 1 -3.1348-3.5684zm6.168.55469c-.22615.98866-.65424 1.9884-1.3008 3.0059-.63811-1.0042-1.0645-1.9908-1.293-2.9668.89027.054126 1.7517.029377 2.5938-.039062z" fill="#fc9c9c" fill-opacity=".99608"/><path d="m8 1v2.3242c1.0126 1.593 1.5 3.1425 1.5 4.6758 0 .054042-.0066161.10803-.0078125.16211-.4894.049148-.98713.077552-1.4922.082031v1.4922c.43915-.0075968.87287-.031628 1.3008-.066406-.22615.98866-.65424 1.9884-1.3008 3.0059v2.3242a7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm1.7324 2.3164a5 5 0 0 1 3.2383 4.1875c-.65187.17448-1.3077.32867-1.9727.44922-.00845-1.5627-.44294-3.1141-1.2656-4.6367zm3.1465 5.7656a5 5 0 0 1 -3.1484 3.6055c.57106-1.0564.95277-2.1268 1.1367-3.2051.68204-.10905 1.3556-.23789 2.0117-.40039z" fill="#a5b7f3"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm-1.7305 2.3125c-.83125 1.5372-1.2685 3.1037-1.2695 4.6816-.64057-.11251-1.3005-.27158-1.9766-.47266a5 5 0 0 1 3.2461-4.209zm3.4629.0039062a5 5 0 0 1 3.2383 4.1875c-.65187.17448-1.3077.32867-1.9727.44922-.00845-1.5627-.44294-3.1141-1.2656-4.6367zm-1.7324.0078126c1.0126 1.593 1.5 3.1425 1.5 4.6758 0 .054042-.0066161.10803-.0078125.16211-.96392.096801-1.9566.1103-2.9844.027344-.0016335-.063192-.0078125-.12632-.0078125-.18945 0-1.5333.48744-3.0828 1.5-4.6758zm4.8789 5.7578a5 5 0 0 1 -3.1484 3.6055c.57106-1.0564.95277-2.1268 1.1367-3.2051.68204-.10905 1.3556-.23789 2.0117-.40039zm-9.7461.033203c.68377.18153 1.3555.33345 2.0098.43164.18781 1.0551.56647 2.1026 1.125 3.1367a5 5 0 0 1 -3.1348-3.5684zm6.168.55469c-.22615.98866-.65424 1.9884-1.3008 3.0059-.63811-1.0042-1.0645-1.9908-1.293-2.9668.89027.054126 1.7517.029377 2.5938-.039062z" fill="#fc7f7f" fill-opacity=".99608"/><path d="m8 1v2.3242c1.0126 1.593 1.5 3.1425 1.5 4.6758 0 .054042-.0066161.10803-.0078125.16211-.4894.049148-.98713.077552-1.4922.082031v1.4922c.43915-.0075968.87287-.031628 1.3008-.066406-.22615.98866-.65424 1.9884-1.3008 3.0059v2.3242a7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm1.7324 2.3164a5 5 0 0 1 3.2383 4.1875c-.65187.17448-1.3077.32867-1.9727.44922-.00845-1.5627-.44294-3.1141-1.2656-4.6367zm3.1465 5.7656a5 5 0 0 1 -3.1484 3.6055c.57106-1.0564.95277-2.1268 1.1367-3.2051.68204-.10905 1.3556-.23789 2.0117-.40039z" fill="#8da5f3"/></g></svg>
diff --git a/editor/icons/X509Certificate.svg b/editor/icons/X509Certificate.svg
index b56268f281..718b0ee6a1 100644
--- a/editor/icons/X509Certificate.svg
+++ b/editor/icons/X509Certificate.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 4.233 4.233" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.967.263-3.704.001v2.646h1.427a.993.993 0 0 1 -.022-.096.993.993 0 0 1 -.012-.099.993.993 0 0 1 -.002-.07.993.993 0 0 1 .005-.1.993.993 0 0 1 .014-.097.993.993 0 0 1 .025-.096.993.993 0 0 1 .034-.093.993.993 0 0 1 .043-.09.993.993 0 0 1 .052-.085.993.993 0 0 1 .06-.079.993.993 0 0 1 .068-.072.993.993 0 0 1 .074-.066.993.993 0 0 1 .08-.057.993.993 0 0 1 .087-.05.993.993 0 0 1 .09-.04.993.993 0 0 1 .095-.031.993.993 0 0 1 .096-.022.993.993 0 0 1 .099-.012.993.993 0 0 1 .07-.003.993.993 0 0 1 .099.006.993.993 0 0 1 .098.014.993.993 0 0 1 .096.025.993.993 0 0 1 .094.034.993.993 0 0 1 .089.043.993.993 0 0 1 .084.052.993.993 0 0 1 .08.06.993.993 0 0 1 .072.068.993.993 0 0 1 .065.074.993.993 0 0 1 .058.08.993.993 0 0 1 .05.087.993.993 0 0 1 .04.09.993.993 0 0 1 .031.095.993.993 0 0 1 .022.096.993.993 0 0 1 .012.099.993.993 0 0 1 .002.07.993.993 0 0 1 -.004.1.993.993 0 0 1 -.015.097.993.993 0 0 1 -.017.068h.365z" fill="#e0e0e0"/><g fill="#ff8484"><path d="m2.116 3.175v.793l.53-.253.529.253v-.793z"/><circle cx="2.646" cy="2.645" r=".794"/></g></svg>
+<svg height="16" viewBox="0 0 4.233 4.233" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.967.263-3.704.001v2.646h1.427a.993.993 0 0 1 -.022-.096.993.993 0 0 1 -.012-.099.993.993 0 0 1 -.002-.07.993.993 0 0 1 .005-.1.993.993 0 0 1 .014-.097.993.993 0 0 1 .025-.096.993.993 0 0 1 .034-.093.993.993 0 0 1 .043-.09.993.993 0 0 1 .052-.085.993.993 0 0 1 .06-.079.993.993 0 0 1 .068-.072.993.993 0 0 1 .074-.066.993.993 0 0 1 .08-.057.993.993 0 0 1 .087-.05.993.993 0 0 1 .09-.04.993.993 0 0 1 .095-.031.993.993 0 0 1 .096-.022.993.993 0 0 1 .099-.012.993.993 0 0 1 .07-.003.993.993 0 0 1 .099.006.993.993 0 0 1 .098.014.993.993 0 0 1 .096.025.993.993 0 0 1 .094.034.993.993 0 0 1 .089.043.993.993 0 0 1 .084.052.993.993 0 0 1 .08.06.993.993 0 0 1 .072.068.993.993 0 0 1 .065.074.993.993 0 0 1 .058.08.993.993 0 0 1 .05.087.993.993 0 0 1 .04.09.993.993 0 0 1 .031.095.993.993 0 0 1 .022.096.993.993 0 0 1 .012.099.993.993 0 0 1 .002.07.993.993 0 0 1 -.004.1.993.993 0 0 1 -.015.097.993.993 0 0 1 -.017.068h.365z" fill="#e0e0e0"/><g fill="#ff5f5f"><path d="m2.116 3.175v.793l.53-.253.529.253v-.793z"/><circle cx="2.646" cy="2.645" r=".794"/></g></svg>
diff --git a/editor/icons/XRAnchor3D.svg b/editor/icons/XRAnchor3D.svg
index 0f6282a085..2d8e543f85 100644
--- a/editor/icons/XRAnchor3D.svg
+++ b/editor/icons/XRAnchor3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v2h-2v2h2v3.2656l-2.5527-1.2773c-.15005-.075253-.31662-.11152-.48438-.10547-.36536.013648-.69415.2256-.85742.55273-.24709.49403-.046823 1.0948.44727 1.3418l4.4473 2.2227 4.4473-2.2227c.49409-.24697.69435-.84777.44726-1.3418-.24697-.49409-.84777-.69435-1.3418-.44727l-2.5527 1.2773v-3.2656h2v-2h-2v-2zm-3 11v1c0 .55228.44772 1 1 1-.55228 0-1 .44772-1 1v1h1v-1h1v1h1v-1c0-.55228-.44772-1-1-1 .55228 0 1-.44772 1-1v-1h-1v1h-1v-1zm5 0v4h1v-1h1v1h1v-1c-.000834-.17579-.047991-.34825-.13672-.5.088728-.15175.13588-.32421.13672-.5v-1c0-.55228-.44772-1-1-1h-1zm1 1h1v1h-1z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v2h-2v2h2v3.2656l-2.5527-1.2773c-.15005-.075253-.31662-.11152-.48438-.10547-.36536.013648-.69415.2256-.85742.55273-.24709.49403-.046823 1.0948.44727 1.3418l4.4473 2.2227 4.4473-2.2227c.49409-.24697.69435-.84777.44726-1.3418-.24697-.49409-.84777-.69435-1.3418-.44727l-2.5527 1.2773v-3.2656h2v-2h-2v-2zm-3 11v1c0 .55228.44772 1 1 1-.55228 0-1 .44772-1 1v1h1v-1h1v1h1v-1c0-.55228-.44772-1-1-1 .55228 0 1-.44772 1-1v-1h-1v1h-1v-1zm5 0v4h1v-1h1v1h1v-1c-.000834-.17579-.047991-.34825-.13672-.5.088728-.15175.13588-.32421.13672-.5v-1c0-.55228-.44772-1-1-1h-1zm1 1h1v1h-1z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/XRCamera3D.svg b/editor/icons/XRCamera3D.svg
index 9f9072fc1e..b4657c9f2c 100644
--- a/editor/icons/XRCamera3D.svg
+++ b/editor/icons/XRCamera3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9.5 0a3 3 0 0 0 -2.9883 2.7773 3 3 0 0 0 -2.0117-.77734 3 3 0 0 0 -3 3 3 3 0 0 0 2 2.8242v2.1758c0 .554.44599 1 1 1h6c.55401 0 1-.446 1-1v-1l3 2v-6l-3 2v-1.7695a3 3 0 0 0 1-2.2305 3 3 0 0 0 -3-3zm-5.5 12v1c0 .55228.44772 1 1 1-.55228 0-1 .44772-1 1v1h1v-1h1v1h1v-1c0-.55228-.44772-1-1-1 .55228 0 1-.44772 1-1v-1h-1v1h-1v-1zm5 0v1 3h1v-1h1v1h1v-1c-.000834-.17579-.047991-.34825-.13672-.5.088728-.15175.13588-.32421.13672-.5v-1c0-.55228-.44772-1-1-1h-1zm1 1h1v1h-1z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9.5 0a3 3 0 0 0 -2.9883 2.7773 3 3 0 0 0 -2.0117-.77734 3 3 0 0 0 -3 3 3 3 0 0 0 2 2.8242v2.1758c0 .554.44599 1 1 1h6c.55401 0 1-.446 1-1v-1l3 2v-6l-3 2v-1.7695a3 3 0 0 0 1-2.2305 3 3 0 0 0 -3-3zm-5.5 12v1c0 .55228.44772 1 1 1-.55228 0-1 .44772-1 1v1h1v-1h1v1h1v-1c0-.55228-.44772-1-1-1 .55228 0 1-.44772 1-1v-1h-1v1h-1v-1zm5 0v1 3h1v-1h1v1h1v-1c-.000834-.17579-.047991-.34825-.13672-.5.088728-.15175.13588-.32421.13672-.5v-1c0-.55228-.44772-1-1-1h-1zm1 1h1v1h-1z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/XRController3D.svg b/editor/icons/XRController3D.svg
index 9296b11c8e..cfde6691df 100644
--- a/editor/icons/XRController3D.svg
+++ b/editor/icons/XRController3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.554 0-1 .446-1 1v6c0 .554.446 1 1 1h12c.554 0 1-.446 1-1v-6c0-.554-.446-1-1-1zm2 1h2v2h2v2h-2v2h-2v-2h-2v-2h2zm9 1c.55228 0 1 .44772 1 1s-.44772 1-1 1-1-.44772-1-1 .44772-1 1-1zm-2 2c.55228 0 1 .44772 1 1s-.44772 1-1 1-1-.44772-1-1 .44772-1 1-1zm-7 7v1c0 .55228.44772 1 1 1-.55228 0-1 .44772-1 1v1h1v-1h1v1h1v-1c0-.55228-.44772-1-1-1 .55228 0 1-.44772 1-1v-1h-1v1h-1v-1zm5 0v1 3h1v-1h1v1h1v-1c-.000834-.17579-.047991-.34825-.13672-.5.088728-.15175.13588-.32421.13672-.5v-1c0-.55228-.44772-1-1-1h-1zm1 1h1v1h-1z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1c-.554 0-1 .446-1 1v6c0 .554.446 1 1 1h12c.554 0 1-.446 1-1v-6c0-.554-.446-1-1-1zm2 1h2v2h2v2h-2v2h-2v-2h-2v-2h2zm9 1c.55228 0 1 .44772 1 1s-.44772 1-1 1-1-.44772-1-1 .44772-1 1-1zm-2 2c.55228 0 1 .44772 1 1s-.44772 1-1 1-1-.44772-1-1 .44772-1 1-1zm-7 7v1c0 .55228.44772 1 1 1-.55228 0-1 .44772-1 1v1h1v-1h1v1h1v-1c0-.55228-.44772-1-1-1 .55228 0 1-.44772 1-1v-1h-1v1h-1v-1zm5 0v1 3h1v-1h1v1h1v-1c-.000834-.17579-.047991-.34825-.13672-.5.088728-.15175.13588-.32421.13672-.5v-1c0-.55228-.44772-1-1-1h-1zm1 1h1v1h-1z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/XROrigin3D.svg b/editor/icons/XROrigin3D.svg
index dda24e7530..03d6e67500 100644
--- a/editor/icons/XROrigin3D.svg
+++ b/editor/icons/XROrigin3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v3h2v-3zm-4 4v2h3v-2zm5 0c-.55228 0-1 .44772-1 1s.44772 1 1 1 1-.44772 1-1-.44772-1-1-1zm2 0v2h3v-2zm-3 3v3h2v-3zm-3 4v1c0 .55228.44772 1 1 1-.55228 0-1 .44772-1 1v1h1v-1h1v1h1v-1c0-.55228-.44772-1-1-1 .55228 0 1-.44772 1-1v-1h-1v1h-1v-1zm5 0v1 3h1v-1h1v1h1v-1c-.000834-.17579-.047991-.34825-.13672-.5.088728-.15175.13588-.32421.13672-.5v-1c0-.55228-.44772-1-1-1h-1zm1 1h1v1h-1z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v3h2v-3zm-4 4v2h3v-2zm5 0c-.55228 0-1 .44772-1 1s.44772 1 1 1 1-.44772 1-1-.44772-1-1-1zm2 0v2h3v-2zm-3 3v3h2v-3zm-3 4v1c0 .55228.44772 1 1 1-.55228 0-1 .44772-1 1v1h1v-1h1v1h1v-1c0-.55228-.44772-1-1-1 .55228 0 1-.44772 1-1v-1h-1v1h-1v-1zm5 0v1 3h1v-1h1v1h1v-1c-.000834-.17579-.047991-.34825-.13672-.5.088728-.15175.13588-.32421.13672-.5v-1c0-.55228-.44772-1-1-1h-1zm1 1h1v1h-1z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/YSort.svg b/editor/icons/YSort.svg
index 40367bd2b2..31e5d9a67e 100644
--- a/editor/icons/YSort.svg
+++ b/editor/icons/YSort.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 1-3 3h2v8h-2l3 3 3-3h-2v-8h2zm5 1v2h6v-2zm0 5v2h4v-2zm0 5v2h2v-2z" fill="#a5b7f3" fill-opacity=".98824"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 1-3 3h2v8h-2l3 3 3-3h-2v-8h2zm5 1v2h6v-2zm0 5v2h4v-2zm0 5v2h2v-2z" fill="#8da5f3" fill-opacity=".98824"/></svg>
diff --git a/editor/icons/bool.svg b/editor/icons/bool.svg
index e6e32001ef..674cbc9e6c 100644
--- a/editor/icons/bool.svg
+++ b/editor/icons/bool.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v8h2a3 3 0 0 0 2.5-1.3457 3 3 0 0 0 2.5 1.3457 3 3 0 0 0 2-.76758 3 3 0 0 0 2 .76758 3 3 0 0 0 2.5-1.3457 3 3 0 0 0 2.5 1.3457v-2a1 1 0 0 1 -1-1v-5h-2v2.7695a3 3 0 0 0 -2-.76953 3 3 0 0 0 -2 .76758 3 3 0 0 0 -2-.76758 3 3 0 0 0 -2.5 1.3457 3 3 0 0 0 -2.5-1.3457v-2zm2 4a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm5 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#8da6f0"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v8h2a3 3 0 0 0 2.5-1.3457 3 3 0 0 0 2.5 1.3457 3 3 0 0 0 2-.76758 3 3 0 0 0 2 .76758 3 3 0 0 0 2.5-1.3457 3 3 0 0 0 2.5 1.3457v-2a1 1 0 0 1 -1-1v-5h-2v2.7695a3 3 0 0 0 -2-.76953 3 3 0 0 0 -2 .76758 3 3 0 0 0 -2-.76758 3 3 0 0 0 -2.5 1.3457 3 3 0 0 0 -2.5-1.3457v-2zm2 4a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm5 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#6f91f0"/></svg>
diff --git a/editor/icons/float.svg b/editor/icons/float.svg
index 1e931ad930..b941332e6c 100644
--- a/editor/icons/float.svg
+++ b/editor/icons/float.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2a3 3 0 0 0 -3 3v5h2v-2h2v-2h-2v-1a1 1 0 0 1 1-1h1v-2zm3 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-5zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2z" fill="#61daf4"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2a3 3 0 0 0 -3 3v5h2v-2h2v-2h-2v-1a1 1 0 0 1 1-1h1v-2zm3 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-5zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2z" fill="#35d4f4"/></svg>
diff --git a/editor/icons/int.svg b/editor/icons/int.svg
index f8c88300f7..b943822c23 100644
--- a/editor/icons/int.svg
+++ b/editor/icons/int.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 2v2h2v-2zm11 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2zm-8 2v6h2v-4h1a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3h-1zm-3 2v4h2v-4z" fill="#7dc6ef"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 2v2h2v-2zm11 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2zm-8 2v6h2v-4h1a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3h-1zm-3 2v4h2v-4z" fill="#5abbef"/></svg>
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index e38034dd8c..aa9700716d 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -50,8 +50,8 @@ String Collada::Effect::get_texture_path(const String &p_source, Collada &state)
return state.state.image_map[image].path;
}
-Transform Collada::get_root_transform() const {
- Transform unit_scale_transform;
+Transform3D Collada::get_root_transform() const {
+ Transform3D unit_scale_transform;
#ifndef COLLADA_IMPORT_SCALE_SCENE
unit_scale_transform.scale(Vector3(state.unit_scale, state.unit_scale, state.unit_scale));
#endif
@@ -74,8 +74,8 @@ static String _uri_to_id(const String &p_uri) {
/** HELPER FUNCTIONS **/
-Transform Collada::fix_transform(const Transform &p_transform) {
- Transform tr = p_transform;
+Transform3D Collada::fix_transform(const Transform3D &p_transform) {
+ Transform3D tr = p_transform;
#ifndef NO_UP_AXIS_SWAP
@@ -102,8 +102,8 @@ Transform Collada::fix_transform(const Transform &p_transform) {
//return state.matrix_fix * p_transform;
}
-static Transform _read_transform_from_array(const Vector<float> &array, int ofs = 0) {
- Transform tr;
+static Transform3D _read_transform_from_array(const Vector<float> &array, int ofs = 0) {
+ Transform3D 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];
@@ -122,11 +122,11 @@ static Transform _read_transform_from_array(const Vector<float> &array, int ofs
/* STRUCTURES */
-Transform Collada::Node::compute_transform(Collada &state) const {
- Transform xform;
+Transform3D Collada::Node::compute_transform(Collada &state) const {
+ Transform3D xform;
for (int i = 0; i < xform_list.size(); i++) {
- Transform xform_step;
+ Transform3D xform_step;
const XForm &xf = xform_list[i];
switch (xf.op) {
case XForm::OP_ROTATE: {
@@ -165,11 +165,11 @@ Transform Collada::Node::compute_transform(Collada &state) const {
return xform;
}
-Transform Collada::Node::get_transform() const {
+Transform3D Collada::Node::get_transform() const {
return default_transform;
}
-Transform Collada::Node::get_global_transform() const {
+Transform3D Collada::Node::get_global_transform() const {
if (parent) {
return parent->get_global_transform() * default_transform;
} else {
@@ -201,14 +201,14 @@ Vector<float> Collada::AnimationTrack::get_value_at_time(float p_time) const {
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);
+ Transform3D src = _read_transform_from_array(keys[i - 1].data);
+ Transform3D dst = _read_transform_from_array(keys[i].data);
- Transform interp = c < 0.001 ? src : src.interpolate_with(dst, c);
+ Transform3D interp = c < 0.001 ? src : src.interpolate_with(dst, c);
Vector<float> ret;
ret.resize(16);
- Transform tr;
+ Transform3D 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];
@@ -410,10 +410,9 @@ Vector<String> Collada::_read_string_array(XMLParser &parser) {
return array;
}
-Transform Collada::_read_transform(XMLParser &parser) {
- if (parser.is_empty()) {
- return Transform();
- }
+Transform3D Collada::_read_transform(XMLParser &parser) {
+ if (parser.is_empty())
+ return Transform3D();
Vector<String> array;
while (parser.read() == OK) {
@@ -429,7 +428,7 @@ Transform Collada::_read_transform(XMLParser &parser) {
}
}
- ERR_FAIL_COND_V(array.size() != 16, Transform());
+ ERR_FAIL_COND_V(array.size() != 16, Transform3D());
Vector<float> farr;
farr.resize(16);
for (int i = 0; i < 16; i++) {
@@ -1197,7 +1196,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
/* STORE REST MATRICES */
- Vector<Transform> rests;
+ Vector<Transform3D> rests;
ERR_FAIL_COND(!skindata.joints.sources.has("JOINT"));
ERR_FAIL_COND(!skindata.joints.sources.has("INV_BIND_MATRIX"));
@@ -1214,7 +1213,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
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
+ Transform3D 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;
@@ -2096,7 +2095,7 @@ void Collada::_merge_skeletons2(VisualScene *p_vscene) {
NodeSkeleton *skeleton = nullptr;
- for (Map<String, Transform>::Element *F = cd.bone_rest_map.front(); F; F = F->next()) {
+ for (Map<String, Transform3D>::Element *F = cd.bone_rest_map.front(); F; F = F->next()) {
String name;
if (!state.sid_to_node_map.has(F->key())) {
@@ -2240,11 +2239,11 @@ bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, L
//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();
+ Transform3D 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()) {
+ for (Map<String, Transform3D>::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
}
@@ -2252,7 +2251,7 @@ bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, L
//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->default_transform=Transform3D(); //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
diff --git a/editor/import/collada.h b/editor/import/collada.h
index 2c3f0a3006..5e38637504 100644
--- a/editor/import/collada.h
+++ b/editor/import/collada.h
@@ -182,7 +182,7 @@ public:
String base;
bool use_idrefs = false;
- Transform bind_shape;
+ Transform3D bind_shape;
struct Source {
Vector<String> sarray; //maybe for names
@@ -210,7 +210,7 @@ public:
int count = 0;
} weights;
- Map<String, Transform> bone_rest_map;
+ Map<String, Transform3D> bone_rest_map;
SkinControllerData() {}
};
@@ -342,15 +342,15 @@ public:
String empty_draw_type;
bool noname = false;
Vector<XForm> xform_list;
- Transform default_transform;
- Transform post_transform;
+ Transform3D default_transform;
+ Transform3D post_transform;
Vector<Node *> children;
Node *parent = nullptr;
- Transform compute_transform(Collada &state) const;
- Transform get_global_transform() const;
- Transform get_transform() const;
+ Transform3D compute_transform(Collada &state) const;
+ Transform3D get_global_transform() const;
+ Transform3D get_transform() const;
bool ignore_anim = false;
@@ -497,7 +497,7 @@ public:
Map<String, String> sid_to_node_map;
//Map<String,NodeJoint*> bone_map;
- Map<String, Transform> bone_rest_map;
+ Map<String, Transform3D> bone_rest_map;
String local_path;
String root_visual_scene;
@@ -517,9 +517,9 @@ public:
Collada();
- Transform fix_transform(const Transform &p_transform);
+ Transform3D fix_transform(const Transform3D &p_transform);
- Transform get_root_transform() const;
+ Transform3D get_root_transform() const;
int get_uv_channel(String p_name);
@@ -557,7 +557,7 @@ private: // private stuff
Variant _parse_param(XMLParser &parser);
Vector<float> _read_float_array(XMLParser &parser);
Vector<String> _read_string_array(XMLParser &parser);
- Transform _read_transform(XMLParser &parser);
+ Transform3D _read_transform(XMLParser &parser);
String _read_empty_draw_type(XMLParser &parser);
void _joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner);
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index d3183e5a8d..dc1bd38a99 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -87,7 +87,7 @@ struct ColladaImport {
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<EditorSceneImporterMesh> &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<EditorSceneImporterMesh>> p_morph_meshes = Vector<Ref<EditorSceneImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false);
+ Error _create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes = Vector<Ref<EditorSceneImporterMesh>>(), 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);
@@ -300,7 +300,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) {
nm.node = node;
node_map[p_node->id] = nm;
node_name_map[node->get_name()] = p_node->id;
- Transform xf = p_node->default_transform;
+ Transform3D xf = p_node->default_transform;
xf = collada.fix_transform(xf) * p_node->post_transform;
node->set_transform(xf);
@@ -457,7 +457,7 @@ Error ColladaImport::_create_material(const String &p_target) {
return OK;
}
-Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &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<EditorSceneImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
+Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
bool local_xform_mirror = p_local_xform.basis.determinant() < 0;
if (p_morph_data) {
@@ -811,7 +811,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImpor
if (has_weights) {
//if skeleton, localize
- Transform local_xform = p_local_xform;
+ Transform3D local_xform = p_local_xform;
for (int i = 0; i < vertex_array.size(); i++) {
vertex_array.write[i].vertex = local_xform.xform(vertex_array[i].vertex);
vertex_array.write[i].normal = local_xform.basis.xform(vertex_array[i].normal).normalized();
@@ -1037,7 +1037,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
Collada::SkinControllerData *skin = nullptr;
Collada::MorphControllerData *morph = nullptr;
String meshid;
- Transform apply_xform;
+ Transform3D apply_xform;
Vector<int> bone_remap;
Vector<Ref<EditorSceneImporterMesh>> morphs;
@@ -1073,9 +1073,9 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
if (apply_mesh_xform_to_vertices) {
apply_xform = collada.fix_transform(p_node->default_transform);
- node->set_transform(Transform());
+ node->set_transform(Transform3D());
} else {
- apply_xform = Transform();
+ apply_xform = Transform3D();
}
ERR_FAIL_COND_V(!skin->weights.sources.has("JOINT"), ERR_INVALID_DATA);
@@ -1461,7 +1461,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
continue;
}
- animation->add_track(Animation::TYPE_TRANSFORM);
+ animation->add_track(Animation::TYPE_TRANSFORM3D);
int track = animation->get_track_count() - 1;
animation->track_set_path(track, path);
animation->track_set_imported(track, true); //helps merging later
@@ -1530,7 +1530,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
}
}
- Transform xform = cn->compute_transform(collada);
+ Transform3D xform = cn->compute_transform(collada);
xform = collada.fix_transform(xform) * cn->post_transform;
if (nm.bone >= 0) {
@@ -1545,7 +1545,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
Vector3 s = xform.basis.get_scale();
bool singular_matrix = Math::is_equal_approx(s.x, 0.0f) || Math::is_equal_approx(s.y, 0.0f) || Math::is_equal_approx(s.z, 0.0f);
- Quat q = singular_matrix ? Quat() : xform.basis.get_rotation_quat();
+ Quaternion q = singular_matrix ? Quaternion() : xform.basis.get_rotation_quaternion();
Vector3 l = xform.origin;
animation->transform_track_insert_key(track, snapshots[i], l, q, s);
@@ -1584,19 +1584,19 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
continue;
}
- animation->add_track(Animation::TYPE_TRANSFORM);
+ animation->add_track(Animation::TYPE_TRANSFORM3D);
int track = animation->get_track_count() - 1;
animation->track_set_path(track, path);
animation->track_set_imported(track, true); //helps merging later
- Transform xform = cn->compute_transform(collada);
+ Transform3D xform = cn->compute_transform(collada);
xform = collada.fix_transform(xform) * cn->post_transform;
xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform;
Vector3 s = xform.basis.get_scale();
bool singular_matrix = Math::is_equal_approx(s.x, 0.0f) || Math::is_equal_approx(s.y, 0.0f) || Math::is_equal_approx(s.z, 0.0f);
- Quat q = singular_matrix ? Quat() : xform.basis.get_rotation_quat();
+ Quaternion q = singular_matrix ? Quaternion() : xform.basis.get_rotation_quaternion();
Vector3 l = xform.origin;
animation->transform_track_insert_key(track, 0, l, q, s);
diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp
index 44aff874eb..8660289c40 100644
--- a/editor/import/editor_import_plugin.cpp
+++ b/editor/import/editor_import_plugin.cpp
@@ -35,63 +35,63 @@ EditorImportPlugin::EditorImportPlugin() {
}
String EditorImportPlugin::get_importer_name() const {
- ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_importer_name")), "");
- return get_script_instance()->call("get_importer_name");
+ ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_importer_name")), "");
+ return get_script_instance()->call("_get_importer_name");
}
String EditorImportPlugin::get_visible_name() const {
- ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_visible_name")), "");
- return get_script_instance()->call("get_visible_name");
+ ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_visible_name")), "");
+ return get_script_instance()->call("_get_visible_name");
}
void EditorImportPlugin::get_recognized_extensions(List<String> *p_extensions) const {
- ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")));
- Array extensions = get_script_instance()->call("get_recognized_extensions");
+ ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("_get_recognized_extensions")));
+ Array extensions = get_script_instance()->call("_get_recognized_extensions");
for (int i = 0; i < extensions.size(); i++) {
p_extensions->push_back(extensions[i]);
}
}
String EditorImportPlugin::get_preset_name(int p_idx) const {
- ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_preset_name")), "");
- return get_script_instance()->call("get_preset_name", p_idx);
+ ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_preset_name")), "");
+ return get_script_instance()->call("_get_preset_name", p_idx);
}
int EditorImportPlugin::get_preset_count() const {
- ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_preset_count")), 0);
- return get_script_instance()->call("get_preset_count");
+ ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_preset_count")), 0);
+ return get_script_instance()->call("_get_preset_count");
}
String EditorImportPlugin::get_save_extension() const {
- ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_save_extension")), "");
- return get_script_instance()->call("get_save_extension");
+ ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_save_extension")), "");
+ return get_script_instance()->call("_get_save_extension");
}
String EditorImportPlugin::get_resource_type() const {
- ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_resource_type")), "");
- return get_script_instance()->call("get_resource_type");
+ ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_resource_type")), "");
+ return get_script_instance()->call("_get_resource_type");
}
float EditorImportPlugin::get_priority() const {
- if (!(get_script_instance() && get_script_instance()->has_method("get_priority"))) {
+ if (!(get_script_instance() && get_script_instance()->has_method("_get_priority"))) {
return ResourceImporter::get_priority();
}
- return get_script_instance()->call("get_priority");
+ return get_script_instance()->call("_get_priority");
}
int EditorImportPlugin::get_import_order() const {
- if (!(get_script_instance() && get_script_instance()->has_method("get_import_order"))) {
+ if (!(get_script_instance() && get_script_instance()->has_method("_get_import_order"))) {
return ResourceImporter::get_import_order();
}
- return get_script_instance()->call("get_import_order");
+ return get_script_instance()->call("_get_import_order");
}
void EditorImportPlugin::get_import_options(List<ResourceImporter::ImportOption> *r_options, int p_preset) const {
- ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("get_import_options")));
+ ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("_get_import_options")));
Array needed;
needed.push_back("name");
needed.push_back("default_value");
- Array options = get_script_instance()->call("get_import_options", p_preset);
+ Array options = get_script_instance()->call("_get_import_options", p_preset);
for (int i = 0; i < options.size(); i++) {
Dictionary d = options[i];
ERR_FAIL_COND(!d.has_all(needed));
@@ -119,18 +119,18 @@ void EditorImportPlugin::get_import_options(List<ResourceImporter::ImportOption>
}
bool EditorImportPlugin::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
- ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_option_visibility")), true);
+ ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_option_visibility")), true);
Dictionary d;
Map<StringName, Variant>::Element *E = p_options.front();
while (E) {
d[E->key()] = E->get();
E = E->next();
}
- return get_script_instance()->call("get_option_visibility", p_option, d);
+ return get_script_instance()->call("_get_option_visibility", p_option, d);
}
Error EditorImportPlugin::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) {
- ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("import")), ERR_UNAVAILABLE);
+ ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_import")), ERR_UNAVAILABLE);
Dictionary options;
Array platform_variants, gen_files;
@@ -139,7 +139,7 @@ Error EditorImportPlugin::import(const String &p_source_file, const String &p_sa
options[E->key()] = E->get();
E = E->next();
}
- Error err = (Error)get_script_instance()->call("import", p_source_file, p_save_path, options, platform_variants, gen_files).operator int64_t();
+ Error err = (Error)get_script_instance()->call("_import", p_source_file, p_save_path, options, platform_variants, gen_files).operator int64_t();
for (int i = 0; i < platform_variants.size(); i++) {
r_platform_variants->push_back(platform_variants[i]);
@@ -151,16 +151,16 @@ Error EditorImportPlugin::import(const String &p_source_file, const String &p_sa
}
void EditorImportPlugin::_bind_methods() {
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_importer_name"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_visible_name"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "get_preset_count"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_preset_name", PropertyInfo(Variant::INT, "preset")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "get_recognized_extensions"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "get_import_options", PropertyInfo(Variant::INT, "preset")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_save_extension"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::FLOAT, "get_priority"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "get_import_order"));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "get_option_visibility", PropertyInfo(Variant::STRING, "option"), PropertyInfo(Variant::DICTIONARY, "options")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "import", PropertyInfo(Variant::STRING, "source_file"), PropertyInfo(Variant::STRING, "save_path"), PropertyInfo(Variant::DICTIONARY, "options"), PropertyInfo(Variant::ARRAY, "platform_variants"), PropertyInfo(Variant::ARRAY, "gen_files")));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_importer_name"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_visible_name"));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_get_preset_count"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_preset_name", PropertyInfo(Variant::INT, "preset")));
+ BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_recognized_extensions"));
+ BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_import_options", PropertyInfo(Variant::INT, "preset")));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_save_extension"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_resource_type"));
+ BIND_VMETHOD(MethodInfo(Variant::FLOAT, "_get_priority"));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_get_import_order"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_get_option_visibility", PropertyInfo(Variant::STRING, "option"), PropertyInfo(Variant::DICTIONARY, "options")));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_import", PropertyInfo(Variant::STRING, "source_file"), PropertyInfo(Variant::STRING, "save_path"), PropertyInfo(Variant::DICTIONARY, "options"), PropertyInfo(Variant::ARRAY, "platform_variants"), PropertyInfo(Variant::ARRAY, "gen_files")));
}
diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp
index 4a4d9d8f06..c9e446a1a2 100644
--- a/editor/import/resource_importer_csv_translation.cpp
+++ b/editor/import/resource_importer_csv_translation.cpp
@@ -30,8 +30,8 @@
#include "resource_importer_csv_translation.h"
+#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
#include "core/string/optimized_translation.h"
#include "core/string/translation.h"
diff --git a/editor/import/resource_importer_image.cpp b/editor/import/resource_importer_image.cpp
index 26c6a8462b..2dea359188 100644
--- a/editor/import/resource_importer_image.cpp
+++ b/editor/import/resource_importer_image.cpp
@@ -30,9 +30,9 @@
#include "resource_importer_image.h"
+#include "core/io/file_access.h"
#include "core/io/image_loader.h"
#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
#include "scene/resources/texture.h"
String ResourceImporterImage::get_importer_name() const {
@@ -75,7 +75,7 @@ Error ResourceImporterImage::import(const String &p_source_file, const String &p
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file from path '" + p_source_file + "'.");
- size_t len = f->get_len();
+ uint64_t len = f->get_length();
Vector<uint8_t> data;
data.resize(len);
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index dd62c72d8a..3aa17ee581 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -30,8 +30,8 @@
#include "resource_importer_obj.h"
+#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
#include "editor/import/scene_importer_mesh.h"
#include "editor/import/scene_importer_mesh_node_3d.h"
#include "scene/3d/mesh_instance_3d.h"
@@ -126,7 +126,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Stand
String p = l.replace("map_Kd", "").replace("\\", "/").strip_edges();
String path;
- if (p.is_abs_path()) {
+ if (p.is_absolute_path()) {
path = p;
} else {
path = base_path.plus_file(p);
@@ -146,7 +146,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Stand
String p = l.replace("map_Ks", "").replace("\\", "/").strip_edges();
String path;
- if (p.is_abs_path()) {
+ if (p.is_absolute_path()) {
path = p;
} else {
path = base_path.plus_file(p);
@@ -166,7 +166,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Stand
String p = l.replace("map_Ns", "").replace("\\", "/").strip_edges();
String path;
- if (p.is_abs_path()) {
+ if (p.is_absolute_path()) {
path = p;
} else {
path = base_path.plus_file(p);
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 4bb56beaeb..08aa2fecbb 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -120,13 +120,13 @@ void EditorSceneImporter::_bind_methods() {
/////////////////////////////////
void EditorScenePostImport::_bind_methods() {
- BIND_VMETHOD(MethodInfo(Variant::OBJECT, "post_import", PropertyInfo(Variant::OBJECT, "scene")));
+ BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_post_import", PropertyInfo(Variant::OBJECT, "scene")));
ClassDB::bind_method(D_METHOD("get_source_file"), &EditorScenePostImport::get_source_file);
}
Node *EditorScenePostImport::post_import(Node *p_scene) {
if (get_script_instance()) {
- return get_script_instance()->call("post_import", p_scene);
+ return get_script_instance()->call("_post_import", p_scene);
}
return p_scene;
@@ -433,7 +433,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform());
p_node = rigid_body;
- mi->set_transform(Transform());
+ mi->set_transform(Transform3D());
rigid_body->add_child(mi);
mi->set_owner(rigid_body->get_owner());
@@ -632,7 +632,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform());
p_node = rigid_body;
- mi->set_transform(Transform());
+ mi->set_transform(Transform3D());
rigid_body->add_child(mi);
mi->set_owner(rigid_body->get_owner());
base = rigid_body;
@@ -856,8 +856,8 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
new_anim->track_set_path(dtrack, default_anim->track_get_path(j));
if (kt > (from + 0.01) && k > 0) {
- if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) {
- Quat q;
+ if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) {
+ Quaternion q;
Vector3 p;
Vector3 s;
default_anim->transform_track_interpolate(j, from, &p, &q, &s);
@@ -870,8 +870,8 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
}
}
- if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) {
- Quat q;
+ if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) {
+ Quaternion q;
Vector3 p;
Vector3 s;
default_anim->transform_track_get_key(j, k, &p, &q, &s);
@@ -884,8 +884,8 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
}
if (dtrack != -1 && kt >= to) {
- if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) {
- Quat q;
+ if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) {
+ Quaternion q;
Vector3 p;
Vector3 s;
default_anim->transform_track_interpolate(j, to, &p, &q, &s);
@@ -902,8 +902,8 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
new_anim->add_track(default_anim->track_get_type(j));
dtrack = new_anim->get_track_count() - 1;
new_anim->track_set_path(dtrack, default_anim->track_get_path(j));
- if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) {
- Quat q;
+ if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) {
+ Quaternion q;
Vector3 p;
Vector3 s;
default_anim->transform_track_interpolate(j, from, &p, &q, &s);
@@ -1136,7 +1136,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
return importer->import_animation(p_path, p_flags, p_bake_fps);
}
-void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache) {
+void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches) {
EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
if (src_mesh_node) {
//is mesh
@@ -1209,14 +1209,35 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
}
if (bake_lightmaps) {
- Transform xf;
+ Transform3D xf;
Node3D *n = src_mesh_node;
while (n) {
xf = n->get_transform() * xf;
- n = n->get_parent_spatial();
+ n = n->get_parent_node_3d();
}
- //use xf as transform for mesh, and bake it
+ Vector<uint8_t> lightmap_cache;
+ src_mesh_node->get_mesh()->lightmap_unwrap_cached(xf, p_lightmap_texel_size, p_src_lightmap_cache, lightmap_cache);
+
+ if (!lightmap_cache.is_empty()) {
+ if (r_lightmap_caches.is_empty()) {
+ r_lightmap_caches.push_back(lightmap_cache);
+ } else {
+ String new_md5 = String::md5(lightmap_cache.ptr()); // MD5 is stored at the beginning of the cache data
+
+ for (int i = 0; i < r_lightmap_caches.size(); i++) {
+ String md5 = String::md5(r_lightmap_caches[i].ptr());
+ if (new_md5 < md5) {
+ r_lightmap_caches.insert(i, lightmap_cache);
+ break;
+ }
+
+ if (new_md5 == md5) {
+ break;
+ }
+ }
+ }
+ }
}
if (save_to_file != String()) {
@@ -1265,7 +1286,7 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
}
for (int i = 0; i < p_node->get_child_count(); i++) {
- _generate_meshes(p_node->get_child(i), p_mesh_data, p_generate_lods, p_create_shadow_meshes, p_light_bake_mode, p_lightmap_texel_size, p_src_lightmap_cache, r_dst_lightmap_cache);
+ _generate_meshes(p_node->get_child(i), p_mesh_data, p_generate_lods, p_create_shadow_meshes, p_light_bake_mode, p_lightmap_texel_size, p_src_lightmap_cache, r_lightmap_caches);
}
}
@@ -1433,7 +1454,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
float lightmap_texel_size = MAX(0.001, texel_size);
Vector<uint8_t> src_lightmap_cache;
- Vector<uint8_t> dst_lightmap_cache;
+ Vector<Vector<uint8_t>> mesh_lightmap_caches;
{
src_lightmap_cache = FileAccess::get_file_as_array(p_source_file + ".unwrap_cache", &err);
@@ -1446,124 +1467,20 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
if (subresources.has("meshes")) {
mesh_data = subresources["meshes"];
}
- _generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, dst_lightmap_cache);
+ _generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, mesh_lightmap_caches);
- if (dst_lightmap_cache.size()) {
+ if (mesh_lightmap_caches.size()) {
FileAccessRef f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE);
if (f) {
- f->store_buffer(dst_lightmap_cache.ptr(), dst_lightmap_cache.size());
- }
- }
- err = OK;
-
-#if 0
- if (light_bake_mode == 2 /* || generate LOD */) {
- Map<Ref<ArrayMesh>, Transform> meshes;
- _find_meshes(scene, meshes);
-
- String file_id = src_path.get_file();
- String cache_file_path = base_path.plus_file(file_id + ".unwrap_cache");
-
- Vector<unsigned char> cache_data;
-
- if (FileAccess::exists(cache_file_path)) {
- Error err2;
- FileAccess *file = FileAccess::open(cache_file_path, FileAccess::READ, &err2);
-
- if (err2) {
- if (file) {
- memdelete(file);
- }
- } else {
- int cache_size = file->get_len();
- cache_data.resize(cache_size);
- file->get_buffer(cache_data.ptrw(), cache_size);
+ f->store_32(mesh_lightmap_caches.size());
+ for (int i = 0; i < mesh_lightmap_caches.size(); i++) {
+ String md5 = String::md5(mesh_lightmap_caches[i].ptr());
+ f->store_buffer(mesh_lightmap_caches[i].ptr(), mesh_lightmap_caches[i].size());
}
- }
-
- Map<String, unsigned int> used_unwraps;
-
- EditorProgress progress2("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size());
- int step = 0;
- for (Map<Ref<ArrayMesh>, Transform>::Element *E = meshes.front(); E; E = E->next()) {
- Ref<ArrayMesh> mesh = E->key();
- String name = mesh->get_name();
- if (name == "") { //should not happen but..
- name = "Mesh " + itos(step);
- }
-
- progress2.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step);
-
- int *ret_cache_data = (int *)cache_data.ptrw();
- unsigned int ret_cache_size = cache_data.size();
- bool ret_used_cache = true; // Tell the unwrapper to use the cache
- Error err2 = mesh->lightmap_unwrap_cached(ret_cache_data, ret_cache_size, ret_used_cache, E->get(), texel_size);
-
- if (err2 != OK) {
- EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry.");
- } else {
-` String hash = String::md5((unsigned char *)ret_cache_data);
- used_unwraps.insert(hash, ret_cache_size);
-
- if (!ret_used_cache) {
- // Cache was not used, add the generated entry to the current cache
- if (cache_data.is_empty()) {
- cache_data.resize(4 + ret_cache_size);
- int *data = (int *)cache_data.ptrw();
- data[0] = 1;
- memcpy(&data[1], ret_cache_data, ret_cache_size);
- } else {
- int current_size = cache_data.size();
- cache_data.resize(cache_data.size() + ret_cache_size);
- unsigned char *ptrw = cache_data.ptrw();
- memcpy(&ptrw[current_size], ret_cache_data, ret_cache_size);
- int *data = (int *)ptrw;
- data[0] += 1;
- }
- }
- }
- step++;
- }
-
- Error err2;
- FileAccess *file = FileAccess::open(cache_file_path, FileAccess::WRITE, &err2);
-
- if (err2) {
- if (file) {
- memdelete(file);
- }
- } else {
- // Store number of entries
- file->store_32(used_unwraps.size());
-
- // Store cache entries
- const int *cache = (int *)cache_data.ptr();
- unsigned int r_idx = 1;
- for (int i = 0; i < cache[0]; ++i) {
- unsigned char *entry_start = (unsigned char *)&cache[r_idx];
- String entry_hash = String::md5(entry_start);
- if (used_unwraps.has(entry_hash)) {
- unsigned int entry_size = used_unwraps[entry_hash];
- file->store_buffer(entry_start, entry_size);
- }
-
- r_idx += 4; // hash
- r_idx += 2; // size hint
-
- int vertex_count = cache[r_idx];
- r_idx += 1; // vertex count
- r_idx += vertex_count; // vertex
- r_idx += vertex_count * 2; // uvs
-
- int index_count = cache[r_idx];
- r_idx += 1; // index count
- r_idx += index_count; // indices
- }
-
- file->close();
+ f->close();
}
}
-#endif
+ err = OK;
progress.step(TTR("Running Custom Script..."), 2);
@@ -1591,7 +1508,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
if (!scene) {
EditorNode::add_io_error(
TTR("Error running post-import script:") + " " + post_import_script_path + "\n" +
- TTR("Did you return a Node-derived object in the `post_import()` method?"));
+ TTR("Did you return a Node-derived object in the `_post_import()` method?"));
return err;
}
}
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 00039f2ac6..c6e5836a23 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -42,8 +42,8 @@ class Material;
class AnimationPlayer;
class EditorSceneImporterMesh;
-class EditorSceneImporter : public Reference {
- GDCLASS(EditorSceneImporter, Reference);
+class EditorSceneImporter : public RefCounted {
+ GDCLASS(EditorSceneImporter, RefCounted);
protected:
static void _bind_methods();
@@ -69,8 +69,8 @@ public:
EditorSceneImporter() {}
};
-class EditorScenePostImport : public Reference {
- GDCLASS(EditorScenePostImport, Reference);
+class EditorScenePostImport : public RefCounted {
+ GDCLASS(EditorScenePostImport, RefCounted);
String source_file;
@@ -119,7 +119,7 @@ class ResourceImporterScene : public ResourceImporter {
};
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
- void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache);
+ void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches);
void _add_shapes(Node *p_node, const List<Ref<Shape3D>> &p_shapes);
public:
diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp
index f4d20a6296..70119bfd1c 100644
--- a/editor/import/resource_importer_shader_file.cpp
+++ b/editor/import/resource_importer_shader_file.cpp
@@ -30,9 +30,9 @@
#include "resource_importer_shader_file.h"
+#include "core/io/file_access.h"
#include "core/io/marshalls.h"
#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
#include "editor/editor_node.h"
#include "editor/plugins/shader_file_editor_plugin.h"
#include "servers/rendering/rendering_device_binds.h"
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index de8031af35..72df65a787 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -208,7 +208,7 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "roughness/src_normal", PROPERTY_HINT_FILE, "*.bmp,*.dds,*.exr,*.jpeg,*.jpg,*.hdr,*.png,*.svg,*.svgz,*.tga,*.webp"), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/fix_alpha_border"), p_preset != PRESET_3D));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/invert_color"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/normal_map_invert_y"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/HDR_as_SRGB"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "detect_3d/compress_to", PROPERTY_HINT_ENUM, "Disabled,VRAM Compressed,Basis Universal"), (p_preset == PRESET_DETECT) ? 1 : 0));
@@ -218,14 +218,21 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,
void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality) {
switch (p_compress_mode) {
case COMPRESS_LOSSLESS: {
- f->store_32(StreamTexture2D::DATA_FORMAT_LOSSLESS);
+ bool lossless_force_png = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/force_png");
+ bool use_webp = !lossless_force_png && p_image->get_width() <= 16383 && p_image->get_height() <= 16383; // WebP has a size limit
+ f->store_32(use_webp ? StreamTexture2D::DATA_FORMAT_WEBP : StreamTexture2D::DATA_FORMAT_PNG);
f->store_16(p_image->get_width());
f->store_16(p_image->get_height());
f->store_32(p_image->get_mipmap_count());
f->store_32(p_image->get_format());
for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
- Vector<uint8_t> data = Image::lossless_packer(p_image->get_image_from_mipmap(i));
+ Vector<uint8_t> data;
+ if (use_webp) {
+ data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i));
+ } else {
+ data = Image::png_packer(p_image->get_image_from_mipmap(i));
+ }
int data_len = data.size();
f->store_32(data_len);
@@ -235,14 +242,14 @@ void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image
} break;
case COMPRESS_LOSSY: {
- f->store_32(StreamTexture2D::DATA_FORMAT_LOSSY);
+ f->store_32(StreamTexture2D::DATA_FORMAT_WEBP);
f->store_16(p_image->get_width());
f->store_16(p_image->get_height());
f->store_32(p_image->get_mipmap_count());
f->store_32(p_image->get_format());
for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
- Vector<uint8_t> data = Image::lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
+ Vector<uint8_t> data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
int data_len = data.size();
f->store_32(data_len);
@@ -301,6 +308,7 @@ void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image
void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_roughness, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel) {
FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE);
+ ERR_FAIL_NULL(f);
f->store_8('G');
f->store_8('S');
f->store_8('T');
@@ -388,7 +396,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
uint32_t mipmap_limit = int(mipmaps ? int(p_options["mipmaps/limit"]) : int(-1));
bool fix_alpha_border = p_options["process/fix_alpha_border"];
bool premult_alpha = p_options["process/premult_alpha"];
- bool invert_color = p_options["process/invert_color"];
+ bool normal_map_invert_y = p_options["process/normal_map_invert_y"];
bool stream = p_options["compress/streamed"];
int size_limit = p_options["process/size_limit"];
bool hdr_as_srgb = p_options["process/HDR_as_SRGB"];
@@ -444,13 +452,18 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
image->premultiply_alpha();
}
- if (invert_color) {
- int height = image->get_height();
- int width = image->get_width();
+ if (normal_map_invert_y) {
+ // Inverting the green channel can be used to flip a normal map's direction.
+ // There's no standard when it comes to normal map Y direction, so this is
+ // sometimes needed when using a normal map exported from another program.
+ // See <http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates>.
+ const int height = image->get_height();
+ const int width = image->get_width();
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
- image->set_pixel(i, j, image->get_pixel(i, j).inverted());
+ const Color color = image->get_pixel(i, j);
+ image->set_pixel(i, j, Color(color.r, 1 - color.g, color.b));
}
}
}
diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h
index 0d551a965c..41220009cd 100644
--- a/editor/import/resource_importer_texture.h
+++ b/editor/import/resource_importer_texture.h
@@ -31,9 +31,9 @@
#ifndef RESOURCEIMPORTTEXTURE_H
#define RESOURCEIMPORTTEXTURE_H
+#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_importer.h"
-#include "core/os/file_access.h"
#include "scene/resources/texture.h"
#include "servers/rendering_server.h"
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index 4c3ae59951..d5d1a14be3 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -31,10 +31,10 @@
#include "resource_importer_texture_atlas.h"
#include "atlas_import_failed.xpm"
+#include "core/io/file_access.h"
#include "core/io/image_loader.h"
#include "core/io/resource_saver.h"
#include "core/math/geometry_2d.h"
-#include "core/os/file_access.h"
#include "editor/editor_atlas_packer.h"
#include "scene/resources/mesh.h"
#include "scene/resources/texture.h"
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index bcc55b330b..e615212569 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -30,9 +30,9 @@
#include "resource_importer_wav.h"
+#include "core/io/file_access.h"
#include "core/io/marshalls.h"
#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
#include "scene/resources/audio_stream_sample.h"
const float TRIM_DB_LIMIT = -50;
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
index 48340ac242..600f3fe2f0 100644
--- a/editor/import/scene_import_settings.cpp
+++ b/editor/import/scene_import_settings.cpp
@@ -317,7 +317,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
if (mesh_node && mesh_node->get_mesh().is_valid()) {
_fill_mesh(scene_tree, mesh_node->get_mesh(), item);
- Transform accum_xform;
+ Transform3D accum_xform;
Node3D *base = mesh_node;
while (base) {
accum_xform = base->get_transform() * accum_xform;
@@ -339,7 +339,7 @@ void SceneImportSettings::_update_scene() {
material_tree->clear();
mesh_tree->clear();
- //hiden roots
+ //hidden roots
material_tree->create_item();
mesh_tree->create_item();
@@ -379,7 +379,7 @@ void SceneImportSettings::_update_camera() {
camera->set_orthogonal(camera_size * zoom, 0.0001, camera_size * 2);
- Transform xf;
+ Transform3D xf;
xf.basis = Basis(Vector3(0, 1, 0), rot_y) * Basis(Vector3(1, 0, 0), rot_x);
xf.origin = center;
xf.translate(0, 0, camera_size);
@@ -493,7 +493,7 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
Ref<Mesh> base_mesh = mi->get_mesh();
if (base_mesh.is_valid()) {
AABB aabb = base_mesh->get_aabb();
- Transform aabb_xf;
+ Transform3D aabb_xf;
aabb_xf.basis.scale(aabb.size);
aabb_xf.origin = aabb.position;
@@ -1099,7 +1099,7 @@ SceneImportSettings::SceneImportSettings() {
camera->make_current();
light = memnew(DirectionalLight3D);
- light->set_transform(Transform().looking_at(Vector3(-1, -2, -0.6), Vector3(0, 1, 0)));
+ light->set_transform(Transform3D().looking_at(Vector3(-1, -2, -0.6), Vector3(0, 1, 0)));
base_viewport->add_child(light);
light->set_shadow(true);
diff --git a/editor/import/scene_importer_mesh.cpp b/editor/import/scene_importer_mesh.cpp
index 28fdd4ddbd..bf17ea7bca 100644
--- a/editor/import/scene_importer_mesh.cpp
+++ b/editor/import/scene_importer_mesh.cpp
@@ -30,6 +30,7 @@
#include "scene_importer_mesh.h"
+#include "core/math/math_defs.h"
#include "scene/resources/surface_tool.h"
void EditorSceneImporterMesh::add_blend_shape(const String &p_name) {
@@ -141,6 +142,18 @@ void EditorSceneImporterMesh::set_surface_material(int p_surface, const Ref<Mate
surfaces.write[p_surface].material = p_material;
}
+Basis EditorSceneImporterMesh::compute_rotation_matrix_from_ortho_6d(Vector3 p_x_raw, Vector3 p_y_raw) {
+ Vector3 x = p_x_raw.normalized();
+ Vector3 z = x.cross(p_y_raw);
+ z = z.normalized();
+ Vector3 y = z.cross(x);
+ Basis basis;
+ basis.set_axis(Vector3::AXIS_X, x);
+ basis.set_axis(Vector3::AXIS_Y, y);
+ basis.set_axis(Vector3::AXIS_Z, z);
+ return basis;
+}
+
void EditorSceneImporterMesh::generate_lods() {
if (!SurfaceTool::simplify_func) {
return;
@@ -151,6 +164,9 @@ void EditorSceneImporterMesh::generate_lods() {
if (!SurfaceTool::simplify_sloppy_func) {
return;
}
+ if (!SurfaceTool::simplify_with_attrib_func) {
+ return;
+ }
for (int i = 0; i < surfaces.size(); i++) {
if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) {
@@ -163,59 +179,62 @@ void EditorSceneImporterMesh::generate_lods() {
if (indices.size() == 0) {
continue; //no lods if no indices
}
+ Vector<Vector3> normals = surfaces[i].arrays[RS::ARRAY_NORMAL];
uint32_t vertex_count = vertices.size();
const Vector3 *vertices_ptr = vertices.ptr();
-
- int min_indices = 10;
- int index_target = indices.size() / 2;
- print_line("Total indices: " + itos(indices.size()));
- float mesh_scale = SurfaceTool::simplify_scale_func((const float *)vertices_ptr, vertex_count, sizeof(Vector3));
- const float target_error = 1e-3f;
- float abs_target_error = target_error / mesh_scale;
+ Vector<float> attributes;
+ Vector<float> normal_weights;
+ int32_t attribute_count = 6;
+ if (normals.size()) {
+ attributes.resize(normals.size() * attribute_count);
+ for (int32_t normal_i = 0; normal_i < normals.size(); normal_i++) {
+ Basis basis;
+ basis.set_euler(normals[normal_i]);
+ Vector3 basis_x = basis.get_axis(0);
+ Vector3 basis_y = basis.get_axis(1);
+ basis = compute_rotation_matrix_from_ortho_6d(basis_x, basis_y);
+ basis_x = basis.get_axis(0);
+ basis_y = basis.get_axis(1);
+ attributes.write[normal_i * attribute_count + 0] = basis_x.x;
+ attributes.write[normal_i * attribute_count + 1] = basis_x.y;
+ attributes.write[normal_i * attribute_count + 2] = basis_x.z;
+ attributes.write[normal_i * attribute_count + 3] = basis_y.x;
+ attributes.write[normal_i * attribute_count + 4] = basis_y.y;
+ attributes.write[normal_i * attribute_count + 5] = basis_y.z;
+ }
+ normal_weights.resize(vertex_count);
+ for (int32_t weight_i = 0; weight_i < normal_weights.size(); weight_i++) {
+ normal_weights.write[weight_i] = 1.0;
+ }
+ } else {
+ attribute_count = 0;
+ }
+ const int min_indices = 10;
+ const float error_tolerance = 1.44224'95703; // Cube root of 3
+ const float threshold = 1.0 / error_tolerance;
+ int index_target = indices.size() * threshold;
+ float max_mesh_error_percentage = 1e0f;
+ float mesh_error = 0.0f;
while (index_target > min_indices) {
- float error;
Vector<int> new_indices;
new_indices.resize(indices.size());
- size_t new_len = SurfaceTool::simplify_func((unsigned int *)new_indices.ptrw(), (const unsigned int *)indices.ptr(), indices.size(), (const float *)vertices_ptr, vertex_count, sizeof(Vector3), index_target, abs_target_error, &error);
- if ((int)new_len > (index_target * 120 / 100)) {
- // Attribute discontinuities break normals.
- bool is_sloppy = false;
- if (is_sloppy) {
- abs_target_error = target_error / mesh_scale;
- index_target = new_len;
- while (index_target > min_indices) {
- Vector<int> sloppy_new_indices;
- sloppy_new_indices.resize(indices.size());
- new_len = SurfaceTool::simplify_sloppy_func((unsigned int *)sloppy_new_indices.ptrw(), (const unsigned int *)indices.ptr(), indices.size(), (const float *)vertices_ptr, vertex_count, sizeof(Vector3), index_target, abs_target_error, &error);
- if ((int)new_len > (index_target * 120 / 100)) {
- break; // 20 percent tolerance
- }
- sloppy_new_indices.resize(new_len);
- Surface::LOD lod;
- lod.distance = error * mesh_scale;
- abs_target_error = lod.distance;
- if (Math::is_equal_approx(abs_target_error, 0.0f)) {
- return;
- }
- lod.indices = sloppy_new_indices;
- print_line("Lod " + itos(surfaces.write[i].lods.size()) + " shoot for " + itos(index_target / 3) + " triangles, got " + itos(new_len / 3) + " triangles. Distance " + rtos(lod.distance) + ". Use simplify sloppy.");
- surfaces.write[i].lods.push_back(lod);
- index_target /= 2;
- }
- }
- break; // 20 percent tolerance
+ size_t new_len = SurfaceTool::simplify_with_attrib_func((unsigned int *)new_indices.ptrw(), (const unsigned int *)indices.ptr(), indices.size(), (const float *)vertices_ptr, vertex_count, sizeof(Vector3), index_target, max_mesh_error_percentage, &mesh_error, (float *)attributes.ptrw(), normal_weights.ptrw(), attribute_count);
+ if ((int)new_len > (index_target * error_tolerance)) {
+ break;
}
- new_indices.resize(new_len);
Surface::LOD lod;
- lod.distance = error * mesh_scale;
- abs_target_error = lod.distance;
- if (Math::is_equal_approx(abs_target_error, 0.0f)) {
- return;
+ lod.distance = mesh_error;
+ if (Math::is_equal_approx(mesh_error, 0.0f)) {
+ break;
+ }
+ if (new_len <= 0) {
+ break;
}
+ new_indices.resize(new_len);
lod.indices = new_indices;
- print_line("Lod " + itos(surfaces.write[i].lods.size()) + " shoot for " + itos(index_target / 3) + " triangles, got " + itos(new_len / 3) + " triangles. Distance " + rtos(lod.distance));
+ print_line("Lod " + itos(surfaces.write[i].lods.size()) + " begin with " + itos(indices.size() / 3) + " triangles and shoot for " + itos(index_target / 3) + " triangles. Got " + itos(new_len / 3) + " triangles. Lod screen ratio " + rtos(lod.distance));
surfaces.write[i].lods.push_back(lod);
- index_target /= 2;
+ index_target *= threshold;
}
}
}
@@ -583,7 +602,7 @@ Ref<NavigationMesh> EditorSceneImporterMesh::create_navigation_mesh() {
return nm;
}
-extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache);
+extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, 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);
struct EditorSceneImporterMeshLightmapSurface {
Ref<Material> material;
@@ -593,22 +612,24 @@ struct EditorSceneImporterMeshLightmapSurface {
String name;
};
-Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size) {
+Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache) {
ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
- Vector<float> vertices;
- Vector<float> normals;
- Vector<int> indices;
- Vector<float> uv;
- Vector<Pair<int, int>> uv_indices;
+ LocalVector<float> vertices;
+ LocalVector<float> normals;
+ LocalVector<int> indices;
+ LocalVector<float> uv;
+ LocalVector<Pair<int, int>> uv_indices;
Vector<EditorSceneImporterMeshLightmapSurface> lightmap_surfaces;
// Keep only the scale
- Transform transform = p_base_transform;
- transform.origin = Vector3();
- transform.looking_at(Vector3(1, 0, 0), Vector3(0, 1, 0));
+ Basis basis = p_base_transform.get_basis();
+ Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length());
+
+ Transform3D transform;
+ transform.scale(scale);
Basis normal_basis = transform.basis.inverse().transposed();
@@ -623,15 +644,10 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices, &s.format);
- Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX];
+ PackedVector3Array rvertices = arrays[Mesh::ARRAY_VERTEX];
int vc = rvertices.size();
- const Vector3 *r = rvertices.ptr();
-
- Vector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL];
- ERR_FAIL_COND_V_MSG(rnormals.size() == 0, ERR_UNAVAILABLE, "Normals are required for lightmap unwrap.");
-
- const Vector3 *rn = rnormals.ptr();
+ PackedVector3Array rnormals = arrays[Mesh::ARRAY_NORMAL];
int vertex_ofs = vertices.size() / 3;
@@ -640,24 +656,29 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
uv_indices.resize(vertex_ofs + vc);
for (int j = 0; j < vc; j++) {
- Vector3 v = transform.xform(r[j]);
- Vector3 n = normal_basis.xform(rn[j]).normalized();
-
- vertices.write[(j + vertex_ofs) * 3 + 0] = v.x;
- vertices.write[(j + vertex_ofs) * 3 + 1] = v.y;
- vertices.write[(j + vertex_ofs) * 3 + 2] = v.z;
- normals.write[(j + vertex_ofs) * 3 + 0] = n.x;
- normals.write[(j + vertex_ofs) * 3 + 1] = n.y;
- normals.write[(j + vertex_ofs) * 3 + 2] = n.z;
- uv_indices.write[j + vertex_ofs] = Pair<int, int>(i, j);
+ Vector3 v = transform.xform(rvertices[j]);
+ Vector3 n = normal_basis.xform(rnormals[j]).normalized();
+
+ vertices[(j + vertex_ofs) * 3 + 0] = v.x;
+ vertices[(j + vertex_ofs) * 3 + 1] = v.y;
+ vertices[(j + vertex_ofs) * 3 + 2] = v.z;
+ normals[(j + vertex_ofs) * 3 + 0] = n.x;
+ normals[(j + vertex_ofs) * 3 + 1] = n.y;
+ normals[(j + vertex_ofs) * 3 + 2] = n.z;
+ uv_indices[j + vertex_ofs] = Pair<int, int>(i, j);
}
- Vector<int> rindices = arrays[Mesh::ARRAY_INDEX];
+ PackedInt32Array rindices = arrays[Mesh::ARRAY_INDEX];
int ic = rindices.size();
+ float eps = 1.19209290e-7F; // Taken from xatlas.h
if (ic == 0) {
for (int j = 0; j < vc / 3; j++) {
- if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) {
+ Vector3 p0 = transform.xform(rvertices[j * 3 + 0]);
+ Vector3 p1 = transform.xform(rvertices[j * 3 + 1]);
+ Vector3 p2 = transform.xform(rvertices[j * 3 + 2]);
+
+ if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue;
}
@@ -667,15 +688,18 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
}
} else {
- const int *ri = rindices.ptr();
-
for (int j = 0; j < ic / 3; j++) {
- if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) {
+ Vector3 p0 = transform.xform(rvertices[rindices[j * 3 + 0]]);
+ Vector3 p1 = transform.xform(rvertices[rindices[j * 3 + 1]]);
+ Vector3 p2 = transform.xform(rvertices[rindices[j * 3 + 2]]);
+
+ if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue;
}
- indices.push_back(vertex_ofs + ri[j * 3 + 0]);
- indices.push_back(vertex_ofs + ri[j * 3 + 1]);
- indices.push_back(vertex_ofs + ri[j * 3 + 2]);
+
+ indices.push_back(vertex_ofs + rindices[j * 3 + 0]);
+ indices.push_back(vertex_ofs + rindices[j * 3 + 1]);
+ indices.push_back(vertex_ofs + rindices[j * 3 + 2]);
}
}
@@ -684,6 +708,9 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
//unwrap
+ bool use_cache = true; // Used to request cache generation and to know if cache was used
+ uint8_t *gen_cache;
+ int gen_cache_size;
float *gen_uvs;
int *gen_vertices;
int *gen_indices;
@@ -692,7 +719,7 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
int size_x;
int size_y;
- bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y, r_cache_data, r_cache_size, r_used_cache);
+ bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), p_src_cache.ptr(), &use_cache, &gen_cache, &gen_cache_size, &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y);
if (!ok) {
return ERR_CANT_CREATE;
@@ -702,7 +729,7 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
clear();
//create surfacetools for each surface..
- Vector<Ref<SurfaceTool>> surfaces_tools;
+ LocalVector<Ref<SurfaceTool>> surfaces_tools;
for (int i = 0; i < lightmap_surfaces.size(); i++) {
Ref<SurfaceTool> st;
@@ -714,11 +741,12 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
}
print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
+
//go through all indices
for (int i = 0; i < gen_index_count; i += 3) {
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_indices.size(), ERR_BUG);
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_indices.size(), ERR_BUG);
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], (int)uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], (int)uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], (int)uv_indices.size(), ERR_BUG);
ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG);
@@ -728,49 +756,54 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_COLOR) {
- surfaces_tools.write[surface]->set_color(v.color);
+ surfaces_tools[surface]->set_color(v.color);
}
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TEX_UV) {
- surfaces_tools.write[surface]->set_uv(v.uv);
+ surfaces_tools[surface]->set_uv(v.uv);
}
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_NORMAL) {
- surfaces_tools.write[surface]->set_normal(v.normal);
+ surfaces_tools[surface]->set_normal(v.normal);
}
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TANGENT) {
Plane t;
t.normal = v.tangent;
t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
- surfaces_tools.write[surface]->set_tangent(t);
+ surfaces_tools[surface]->set_tangent(t);
}
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_BONES) {
- surfaces_tools.write[surface]->set_bones(v.bones);
+ surfaces_tools[surface]->set_bones(v.bones);
}
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_WEIGHTS) {
- surfaces_tools.write[surface]->set_weights(v.weights);
+ surfaces_tools[surface]->set_weights(v.weights);
}
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
- surfaces_tools.write[surface]->set_uv2(uv2);
+ surfaces_tools[surface]->set_uv2(uv2);
- surfaces_tools.write[surface]->add_vertex(v.vertex);
+ surfaces_tools[surface]->add_vertex(v.vertex);
}
}
//generate surfaces
-
- for (int i = 0; i < surfaces_tools.size(); i++) {
- surfaces_tools.write[i]->index();
- Array arrays = surfaces_tools.write[i]->commit_to_arrays();
- add_surface(surfaces_tools.write[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools.write[i]->get_material(), surfaces_tools.write[i]->get_meta("name"));
+ for (unsigned int i = 0; i < surfaces_tools.size(); i++) {
+ surfaces_tools[i]->index();
+ Array arrays = surfaces_tools[i]->commit_to_arrays();
+ add_surface(surfaces_tools[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools[i]->get_material(), surfaces_tools[i]->get_meta("name"));
}
set_lightmap_size_hint(Size2(size_x, size_y));
- if (!r_used_cache) {
- //free stuff
- ::free(gen_vertices);
- ::free(gen_indices);
- ::free(gen_uvs);
+ if (gen_cache_size > 0) {
+ r_dst_cache.resize(gen_cache_size);
+ memcpy(r_dst_cache.ptrw(), gen_cache, gen_cache_size);
+ memfree(gen_cache);
+ }
+
+ if (!use_cache) {
+ // Cache was not used, free the buffers
+ memfree(gen_vertices);
+ memfree(gen_indices);
+ memfree(gen_uvs);
}
return OK;
diff --git a/editor/import/scene_importer_mesh.h b/editor/import/scene_importer_mesh.h
index 3326fab55d..2488de7ed0 100644
--- a/editor/import/scene_importer_mesh.h
+++ b/editor/import/scene_importer_mesh.h
@@ -67,6 +67,7 @@ class EditorSceneImporterMesh : public Resource {
Ref<EditorSceneImporterMesh> shadow_mesh;
Size2i lightmap_size_hint;
+ Basis compute_rotation_matrix_from_ortho_6d(Vector3 p_x_raw, Vector3 y_raw);
protected:
void _set_data(const Dictionary &p_data);
@@ -105,7 +106,7 @@ public:
Vector<Ref<Shape3D>> convex_decompose() const;
Ref<Shape3D> create_trimesh_shape() const;
Ref<NavigationMesh> create_navigation_mesh();
- Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size);
+ Error lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache);
void set_lightmap_size_hint(const Size2i &p_size);
Size2i get_lightmap_size_hint() const;
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index fbcd76a95f..e8c01d0e0c 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -42,6 +42,14 @@ void InspectorDock::_menu_option(int p_option) {
case COLLAPSE_ALL: {
_menu_collapseall();
} break;
+
+ case RESOURCE_SAVE: {
+ _save_resource(false);
+ } break;
+ case RESOURCE_SAVE_AS: {
+ _save_resource(true);
+ } break;
+
case RESOURCE_MAKE_BUILT_IN: {
_unref_resource();
} break;
@@ -52,13 +60,6 @@ void InspectorDock::_menu_option(int p_option) {
_paste_resource();
} break;
- case RESOURCE_SAVE: {
- _save_resource(false);
- } break;
- case RESOURCE_SAVE_AS: {
- _save_resource(true);
- } break;
-
case OBJECT_REQUEST_HELP: {
if (current) {
editor->set_visible_editor(EditorNode::EDITOR_SCRIPT);
@@ -313,7 +314,7 @@ void InspectorDock::_property_keyed(const String &p_keyed, const Variant &p_valu
AnimationPlayerEditor::singleton->get_track_editor()->insert_value_key(p_keyed, p_value, p_advance);
}
-void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Transform &p_key) {
+void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Transform3D &p_key) {
Node3D *s = Object::cast_to<Node3D>(sp);
if (!s) {
return;
@@ -335,9 +336,16 @@ void InspectorDock::_notification(int p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
set_theme(editor->get_gui_base()->get_theme());
+
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"));
+ resource_extra_button->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons"));
+
+ PopupMenu *resource_extra_popup = resource_extra_button->get_popup();
+ resource_extra_popup->set_item_icon(resource_extra_popup->get_item_index(RESOURCE_EDIT_CLIPBOARD), get_theme_icon("ActionPaste", "EditorIcons"));
+ resource_extra_popup->set_item_icon(resource_extra_popup->get_item_index(RESOURCE_COPY), get_theme_icon("ActionCopy", "EditorIcons"));
+
if (is_layout_rtl()) {
backward_button->set_icon(get_theme_icon("Forward", "EditorIcons"));
forward_button->set_icon(get_theme_icon("Back", "EditorIcons"));
@@ -345,6 +353,7 @@ void InspectorDock::_notification(int p_what) {
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"));
@@ -403,12 +412,7 @@ void InspectorDock::update(Object *p_object) {
object_menu->set_disabled(true);
warning->hide();
search->set_editable(false);
-
- editor_path->set_disabled(true);
- editor_path->set_text("");
- editor_path->set_tooltip("");
- editor_path->set_icon(nullptr);
-
+ editor_path->clear_path();
return;
}
@@ -417,35 +421,28 @@ void InspectorDock::update(Object *p_object) {
object_menu->set_disabled(false);
search->set_editable(true);
- editor_path->set_disabled(false);
+ editor_path->enable_path();
+
resource_save_button->set_disabled(!is_resource);
+ open_docs_button->set_visible(is_resource || is_node);
+
+ PopupMenu *resource_extra_popup = resource_extra_button->get_popup();
+ resource_extra_popup->set_item_disabled(resource_extra_popup->get_item_index(RESOURCE_COPY), !is_resource);
+ resource_extra_popup->set_item_disabled(resource_extra_popup->get_item_index(RESOURCE_MAKE_BUILT_IN), !is_resource);
PopupMenu *p = object_menu->get_popup();
p->clear();
- p->add_shortcut(ED_SHORTCUT("property_editor/expand_all", TTR("Expand All Properties")), EXPAND_ALL);
- p->add_shortcut(ED_SHORTCUT("property_editor/collapse_all", TTR("Collapse All Properties")), COLLAPSE_ALL);
- p->add_separator();
- if (is_resource) {
- p->add_item(TTR("Save"), RESOURCE_SAVE);
- p->add_item(TTR("Save As..."), RESOURCE_SAVE_AS);
- p->add_separator();
- }
- p->add_shortcut(ED_SHORTCUT("property_editor/copy_params", TTR("Copy Params")), OBJECT_COPY_PARAMS);
- p->add_shortcut(ED_SHORTCUT("property_editor/paste_params", TTR("Paste Params")), OBJECT_PASTE_PARAMS);
+ p->add_icon_shortcut(get_theme_icon("GuiTreeArrowDown", "EditorIcons"), ED_SHORTCUT("property_editor/expand_all", TTR("Expand All")), EXPAND_ALL);
+ p->add_icon_shortcut(get_theme_icon("GuiTreeArrowRight", "EditorIcons"), ED_SHORTCUT("property_editor/collapse_all", TTR("Collapse All")), COLLAPSE_ALL);
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("property_editor/paste_resource", TTR("Edit Resource Clipboard")), RESOURCE_EDIT_CLIPBOARD);
- if (is_resource) {
- p->add_shortcut(ED_SHORTCUT("property_editor/copy_resource", TTR("Copy Resource")), RESOURCE_COPY);
- p->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Built-In")), RESOURCE_MAKE_BUILT_IN);
- }
+ p->add_shortcut(ED_SHORTCUT("property_editor/copy_params", TTR("Copy Properties")), OBJECT_COPY_PARAMS);
+ p->add_shortcut(ED_SHORTCUT("property_editor/paste_params", TTR("Paste Properties")), OBJECT_PASTE_PARAMS);
if (is_resource || is_node) {
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_theme_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("property_editor/open_help", TTR("Open in Help")), OBJECT_REQUEST_HELP);
}
List<MethodInfo> methods;
@@ -525,6 +522,17 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
resource_save_button->set_focus_mode(Control::FOCUS_NONE);
resource_save_button->set_disabled(true);
+ resource_extra_button = memnew(MenuButton);
+ resource_extra_button->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons"));
+ general_options_hb->add_child(resource_extra_button);
+ resource_extra_button->get_popup()->add_icon_shortcut(get_theme_icon("ActionPaste", "EditorIcons"), ED_SHORTCUT("property_editor/paste_resource", TTR("Edit Resource from Clipboard")), RESOURCE_EDIT_CLIPBOARD);
+ resource_extra_button->get_popup()->add_icon_shortcut(get_theme_icon("ActionCopy", "EditorIcons"), ED_SHORTCUT("property_editor/copy_resource", TTR("Copy Resource")), RESOURCE_COPY);
+ resource_extra_button->get_popup()->set_item_disabled(1, true);
+ resource_extra_button->get_popup()->add_separator();
+ resource_extra_button->get_popup()->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Resource Built-In")), RESOURCE_MAKE_BUILT_IN);
+ resource_extra_button->get_popup()->set_item_disabled(3, true);
+ resource_extra_button->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option));
+
general_options_hb->add_spacer();
backward_button = memnew(Button);
@@ -535,7 +543,6 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
} else {
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);
backward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_back));
@@ -548,7 +555,6 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
} else {
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);
forward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_forward));
@@ -560,31 +566,42 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
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);
- add_child(node_info_hb);
-
+ HBoxContainer *subresource_hb = memnew(HBoxContainer);
+ add_child(subresource_hb);
editor_path = memnew(EditorPath(editor->get_editor_history()));
editor_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- node_info_hb->add_child(editor_path);
+ subresource_hb->add_child(editor_path);
- object_menu = memnew(MenuButton);
- object_menu->set_shortcut_context(this);
- 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));
+ open_docs_button = memnew(Button);
+ open_docs_button->set_flat(true);
+ open_docs_button->set_visible(false);
+ open_docs_button->set_tooltip(TTR("Open documentation for this object."));
+ open_docs_button->set_icon(get_theme_icon("HelpSearch", "EditorIcons"));
+ open_docs_button->set_shortcut(ED_SHORTCUT("property_editor/open_help", TTR("Open Documentation")));
+ subresource_hb->add_child(open_docs_button);
+ open_docs_button->connect("pressed", callable_mp(this, &InspectorDock::_menu_option), varray(OBJECT_REQUEST_HELP));
new_resource_dialog = memnew(CreateDialog);
editor->get_gui_base()->add_child(new_resource_dialog);
new_resource_dialog->set_base_type("Resource");
new_resource_dialog->connect("create", callable_mp(this, &InspectorDock::_resource_created));
+ HBoxContainer *property_tools_hb = memnew(HBoxContainer);
+ add_child(property_tools_hb);
+
search = memnew(LineEdit);
search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
search->set_placeholder(TTR("Filter properties"));
search->set_right_icon(get_theme_icon("Search", "EditorIcons"));
search->set_clear_button_enabled(true);
- add_child(search);
+ property_tools_hb->add_child(search);
+
+ object_menu = memnew(MenuButton);
+ object_menu->set_shortcut_context(this);
+ object_menu->set_icon(get_theme_icon("Tools", "EditorIcons"));
+ property_tools_hb->add_child(object_menu);
+ object_menu->set_tooltip(TTR("Manage object properties."));
+ object_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option));
warning = memnew(Button);
add_child(warning);
diff --git a/editor/inspector_dock.h b/editor/inspector_dock.h
index 6a3f8c679c..d50785d95c 100644
--- a/editor/inspector_dock.h
+++ b/editor/inspector_dock.h
@@ -81,9 +81,11 @@ class InspectorDock : public VBoxContainer {
Button *resource_new_button;
Button *resource_load_button;
MenuButton *resource_save_button;
+ MenuButton *resource_extra_button;
MenuButton *history_menu;
LineEdit *search;
+ Button *open_docs_button;
MenuButton *object_menu;
EditorPath *editor_path;
@@ -112,7 +114,7 @@ class InspectorDock : public VBoxContainer {
void _prepare_history();
void _property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance);
- void _transform_keyed(Object *sp, const String &p_sub, const Transform &p_key);
+ void _transform_keyed(Object *sp, const String &p_sub, const Transform3D &p_key);
protected:
static void _bind_methods();
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index 0e68af06f0..161f1dde0d 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -37,24 +37,6 @@
#include "scene/gui/control.h"
void LocalizationEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_TEXT_SERVER_CHANGED) {
- ts_name->set_text(TTR("Text server: ") + TS->get_name());
-
- FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- if (file_check->file_exists("res://" + TS->get_support_data_filename())) {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Installed"));
- ts_install->set_disabled(true);
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not installed"));
- ts_install->set_disabled(false);
- }
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not supported"));
- ts_install->set_disabled(false);
- }
- ts_data_info->set_text(TTR("Info: ") + TS->get_support_data_info());
- }
if (p_what == NOTIFICATION_ENTER_TREE) {
translation_list->connect("button_pressed", callable_mp(this, &LocalizationEditor::_translation_delete));
translation_pot_list->connect("button_pressed", callable_mp(this, &LocalizationEditor::_pot_delete));
@@ -649,26 +631,6 @@ void LocalizationEditor::update_translations() {
updating_translations = false;
}
-void LocalizationEditor::_install_ts_data() {
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- TS->save_support_data("res://" + TS->get_support_data_filename());
- }
-
- FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- if (file_check->file_exists("res://" + TS->get_support_data_filename())) {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Installed"));
- ts_install->set_disabled(true);
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not installed"));
- ts_install->set_disabled(false);
- }
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not supported"));
- ts_install->set_disabled(false);
- }
-}
-
void LocalizationEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_translations"), &LocalizationEditor::update_translations);
@@ -838,37 +800,4 @@ LocalizationEditor::LocalizationEditor() {
pot_file_open_dialog->connect("files_selected", callable_mp(this, &LocalizationEditor::_pot_add));
add_child(pot_file_open_dialog);
}
-
- {
- VBoxContainer *tvb = memnew(VBoxContainer);
- tvb->set_name(TTR("Text Server Data"));
- translations->add_child(tvb);
-
- ts_name = memnew(Label(TTR("Text server: ") + TS->get_name()));
- tvb->add_child(ts_name);
-
- ts_data_status = memnew(Label(TTR("Support data: ")));
- tvb->add_child(ts_data_status);
-
- ts_data_info = memnew(Label(TTR("Info: ") + TS->get_support_data_info()));
- tvb->add_child(ts_data_info);
-
- ts_install = memnew(Button(TTR("Install support data...")));
- ts_install->connect("pressed", callable_mp(this, &LocalizationEditor::_install_ts_data));
- tvb->add_child(ts_install);
-
- FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- if (file_check->file_exists("res://" + TS->get_support_data_filename())) {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Installed"));
- ts_install->set_disabled(true);
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not installed"));
- ts_install->set_disabled(false);
- }
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not supported"));
- ts_install->set_disabled(false);
- }
- }
}
diff --git a/editor/localization_editor.h b/editor/localization_editor.h
index 6e0d7ce61f..23cea06fbe 100644
--- a/editor/localization_editor.h
+++ b/editor/localization_editor.h
@@ -58,11 +58,6 @@ class LocalizationEditor : public VBoxContainer {
Vector<TreeItem *> translation_filter_treeitems;
Vector<int> translation_locales_idxs_remap;
- Label *ts_name;
- Label *ts_data_status;
- Label *ts_data_info;
- Button *ts_install;
-
Tree *translation_pot_list;
EditorFileDialog *pot_file_open_dialog;
EditorFileDialog *pot_generate_dialog;
@@ -94,8 +89,6 @@ class LocalizationEditor : public VBoxContainer {
void _pot_generate(const String &p_file);
void _update_pot_file_extensions();
- void _install_ts_data();
-
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/multi_node_edit.h b/editor/multi_node_edit.h
index 0544eb2d50..2efecb9f65 100644
--- a/editor/multi_node_edit.h
+++ b/editor/multi_node_edit.h
@@ -33,8 +33,8 @@
#include "scene/main/node.h"
-class MultiNodeEdit : public Reference {
- GDCLASS(MultiNodeEdit, Reference);
+class MultiNodeEdit : public RefCounted {
+ GDCLASS(MultiNodeEdit, RefCounted);
List<NodePath> nodes;
struct PLData {
diff --git a/editor/node_3d_editor_gizmos.cpp b/editor/node_3d_editor_gizmos.cpp
index 7dcabafece..5c69a1e975 100644
--- a/editor/node_3d_editor_gizmos.cpp
+++ b/editor/node_3d_editor_gizmos.cpp
@@ -30,23 +30,23 @@
#include "node_3d_editor_gizmos.h"
+#include "core/math/convex_hull.h"
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.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/gpu_particles_collision_3d.h"
#include "scene/3d/light_3d.h"
+#include "scene/3d/lightmap_gi.h"
#include "scene/3d/lightmap_probe.h"
#include "scene/3d/listener_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/navigation_region_3d.h"
+#include "scene/3d/occluder_instance_3d.h"
#include "scene/3d/physics_joint_3d.h"
#include "scene/3d/position_3d.h"
#include "scene/3d/ray_cast_3d.h"
@@ -56,6 +56,7 @@
#include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body_3d.h"
#include "scene/3d/visibility_notifier_3d.h"
+#include "scene/3d/voxel_gi.h"
#include "scene/resources/box_shape_3d.h"
#include "scene/resources/capsule_shape_3d.h"
#include "scene/resources/concave_polygon_shape_3d.h"
@@ -103,8 +104,8 @@ void EditorNode3DGizmo::clear() {
}
void EditorNode3DGizmo::redraw() {
- if (get_script_instance() && get_script_instance()->has_method("redraw")) {
- get_script_instance()->call("redraw");
+ if (get_script_instance() && get_script_instance()->has_method("_redraw")) {
+ get_script_instance()->call("_redraw");
return;
}
@@ -113,8 +114,8 @@ void EditorNode3DGizmo::redraw() {
}
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);
+ 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, "");
@@ -122,8 +123,8 @@ String EditorNode3DGizmo::get_handle_name(int p_idx) const {
}
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);
+ 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);
@@ -131,8 +132,8 @@ bool EditorNode3DGizmo::is_handle_highlighted(int p_idx) const {
}
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);
+ 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());
@@ -140,8 +141,8 @@ Variant EditorNode3DGizmo::get_handle_value(int 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);
+ if (get_script_instance() && get_script_instance()->has_method("_set_handle")) {
+ get_script_instance()->call("_set_handle", p_idx, p_camera, p_point);
return;
}
@@ -150,8 +151,8 @@ void EditorNode3DGizmo::set_handle(int p_idx, Camera3D *p_camera, const Point2 &
}
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);
+ if (get_script_instance() && get_script_instance()->has_method("_commit_handle")) {
+ get_script_instance()->call("_commit_handle", p_idx, p_restore, p_cancel);
return;
}
@@ -176,6 +177,7 @@ void EditorNode3DGizmo::Instance::create_instance(Node3D *p_base, bool p_hidden)
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, RS::SHADOW_CASTING_SETTING_OFF);
int layer = p_hidden ? 0 : 1 << Node3DEditorViewport::GIZMO_EDIT_LAYER;
RS::get_singleton()->instance_set_layer_mask(instance, layer); //gizmos are 26
+ RS::get_singleton()->instance_geometry_set_flag(instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
}
void EditorNode3DGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard, const Ref<SkinReference> &p_skin_reference, const Ref<Material> &p_material) {
@@ -453,7 +455,7 @@ bool EditorNode3DGizmo::intersect_frustum(const Camera3D *p_camera, const Vector
int vc = collision_segments.size();
const Vector3 *vptr = collision_segments.ptr();
- Transform t = spatial_node->get_global_transform();
+ Transform3D t = spatial_node->get_global_transform();
bool any_out = false;
for (int j = 0; j < fc; j++) {
@@ -475,12 +477,12 @@ bool EditorNode3DGizmo::intersect_frustum(const Camera3D *p_camera, const Vector
}
if (collision_mesh.is_valid()) {
- Transform t = spatial_node->get_global_transform();
+ Transform3D t = spatial_node->get_global_transform();
Vector3 mesh_scale = t.get_basis().get_scale();
t.orthonormalize();
- Transform it = t.affine_inverse();
+ Transform3D it = t.affine_inverse();
Vector<Plane> transformed_frustum;
@@ -506,7 +508,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
}
if (r_gizmo_handle && !hidden) {
- Transform t = spatial_node->get_global_transform();
+ Transform3D 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));
}
@@ -558,7 +560,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
}
if (selectable_icon_size > 0.0f) {
- Transform t = spatial_node->get_global_transform();
+ Transform3D 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);
@@ -574,7 +576,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
Point2 center = p_camera->unproject_position(t.origin);
- Transform orig_camera_transform = p_camera->get_camera_transform();
+ Transform3D 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) {
@@ -607,7 +609,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
int vc = collision_segments.size();
const Vector3 *vptr = collision_segments.ptr();
- Transform t = spatial_node->get_global_transform();
+ Transform3D 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));
}
@@ -655,13 +657,13 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
}
if (collision_mesh.is_valid()) {
- Transform gt = spatial_node->get_global_transform();
+ Transform3D 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();
+ Transform3D 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;
@@ -737,16 +739,16 @@ void EditorNode3DGizmo::_bind_methods() {
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")));
+ 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"));
+ 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"));
+ 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);
}
@@ -824,7 +826,7 @@ Variant Light3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_i
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) {
+static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform3D &p_arc_xform) {
//bleh, discrete is simpler
static const int arc_test_points = 64;
float min_d = 1e20;
@@ -853,8 +855,8 @@ static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vec
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();
+ Transform3D gt = light->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -1082,8 +1084,8 @@ Variant AudioStreamPlayer3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gi
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();
+ Transform3D gt = player->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -1228,8 +1230,8 @@ Variant Camera3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_
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();
+ Transform3D gt = camera->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -1237,7 +1239,7 @@ void Camera3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Came
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();
+ Transform3D 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 {
@@ -1416,7 +1418,7 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
lines.push_back(cam_pos);
}
- Transform local = camera->get_global_transform().affine_inverse();
+ Transform3D local = camera->get_global_transform().affine_inverse();
for (int i = 0; i < lines.size(); i++) {
lines.write[i] = local.xform(lines[i]);
}
@@ -1464,6 +1466,44 @@ void MeshInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
/////
+
+OccluderInstance3DGizmoPlugin::OccluderInstance3DGizmoPlugin() {
+ create_material("line_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/occluder", Color(0.8, 0.5, 1)));
+}
+
+bool OccluderInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<OccluderInstance3D>(p_spatial) != nullptr;
+}
+
+String OccluderInstance3DGizmoPlugin::get_gizmo_name() const {
+ return "OccluderInstance3D";
+}
+
+int OccluderInstance3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void OccluderInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ OccluderInstance3D *occluder_instance = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Ref<Occluder3D> o = occluder_instance->get_occluder();
+
+ if (!o.is_valid()) {
+ return;
+ }
+
+ Vector<Vector3> lines = o->get_debug_lines();
+ if (!lines.is_empty()) {
+ Ref<Material> material = get_material("line_material", p_gizmo);
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+ }
+}
+
+/////
+
Sprite3DGizmoPlugin::Sprite3DGizmoPlugin() {
}
@@ -1501,19 +1541,46 @@ Position3DGizmoPlugin::Position3DGizmoPlugin() {
cursor_points = Vector<Vector3>();
Vector<Color> cursor_colors;
- float cs = 0.25;
+ const float cs = 0.25;
+ // Add more points to create a "hard stop" in the color gradient.
cursor_points.push_back(Vector3(+cs, 0, 0));
+ cursor_points.push_back(Vector3());
+ cursor_points.push_back(Vector3());
cursor_points.push_back(Vector3(-cs, 0, 0));
+
cursor_points.push_back(Vector3(0, +cs, 0));
+ cursor_points.push_back(Vector3());
+ cursor_points.push_back(Vector3());
cursor_points.push_back(Vector3(0, -cs, 0));
+
cursor_points.push_back(Vector3(0, 0, +cs));
+ cursor_points.push_back(Vector3());
+ cursor_points.push_back(Vector3());
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"));
+
+ // Use the axis color which is brighter for the positive axis.
+ // Use a darkened axis color for the negative axis.
+ // This makes it possible to see in which direction the Position3D node is rotated
+ // (which can be important depending on how it's used).
+ const Color color_x = EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_x_color", "Editor");
+ cursor_colors.push_back(color_x);
+ cursor_colors.push_back(color_x);
+ // FIXME: Use less strong darkening factor once GH-48573 is fixed.
+ // The current darkening factor compensates for lines being too bright in the 3D editor.
+ cursor_colors.push_back(color_x.lerp(Color(0, 0, 0), 0.75));
+ cursor_colors.push_back(color_x.lerp(Color(0, 0, 0), 0.75));
+
+ const Color color_y = EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_y_color", "Editor");
+ cursor_colors.push_back(color_y);
+ cursor_colors.push_back(color_y);
+ cursor_colors.push_back(color_y.lerp(Color(0, 0, 0), 0.75));
+ cursor_colors.push_back(color_y.lerp(Color(0, 0, 0), 0.75));
+
+ const Color color_z = EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_z_color", "Editor");
+ cursor_colors.push_back(color_z);
+ cursor_colors.push_back(color_z);
+ cursor_colors.push_back(color_z.lerp(Color(0, 0, 0), 0.75));
+ cursor_colors.push_back(color_z.lerp(Color(0, 0, 0), 0.75));
Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
@@ -1577,7 +1644,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
surface_tool->begin(Mesh::PRIMITIVE_LINES);
surface_tool->set_material(material);
- Vector<Transform> grests;
+ Vector<Transform3D> grests;
grests.resize(skel->get_bone_count());
Vector<int> bones;
@@ -1691,59 +1758,10 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
surface_tool->set_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();
@@ -2156,9 +2174,9 @@ Variant VisibilityNotifier3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_g
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();
+ Transform3D gt = notifier->get_global_transform();
- Transform gi = gt.affine_inverse();
+ Transform3D gi = gt.affine_inverse();
bool move = p_idx >= 3;
p_idx = p_idx % 3;
@@ -2348,8 +2366,8 @@ Variant GPUParticles3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo,
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();
+ Transform3D gt = particles->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
bool move = p_idx >= 3;
p_idx = p_idx % 3;
@@ -2515,8 +2533,8 @@ Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *
void GPUParticlesCollision3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
Node3D *sn = p_gizmo->get_spatial_node();
- Transform gt = sn->get_global_transform();
- Transform gi = gt.affine_inverse();
+ Transform3D gt = sn->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -2774,9 +2792,9 @@ Variant ReflectionProbeGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo,
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();
+ Transform3D gt = probe->get_global_transform();
- Transform gi = gt.affine_inverse();
+ Transform3D gi = gt.affine_inverse();
if (p_idx < 3) {
Vector3 extents = probe->get_extents();
@@ -2953,9 +2971,9 @@ Variant DecalGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx
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();
+ Transform3D gt = decal->get_global_transform();
- Transform gi = gt.affine_inverse();
+ Transform3D gi = gt.affine_inverse();
Vector3 extents = decal->get_extents();
@@ -3046,35 +3064,35 @@ void DecalGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
///////////////////////////////
-GIProbeGizmoPlugin::GIProbeGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6));
+VoxelGIGizmoPlugin::VoxelGIGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/voxel_gi", Color(0.5, 1, 0.6));
- create_material("gi_probe_material", gizmo_color);
+ create_material("voxel_gi_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);
+ create_material("voxel_gi_internal_material", gizmo_color);
gizmo_color.a = 0.05;
- create_material("gi_probe_solid_material", gizmo_color);
+ create_material("voxel_gi_solid_material", gizmo_color);
- create_icon_material("gi_probe_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoGIProbe", "EditorIcons"));
+ create_icon_material("voxel_gi_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoVoxelGI", "EditorIcons"));
create_handle_material("handles");
}
-bool GIProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- return Object::cast_to<GIProbe>(p_spatial) != nullptr;
+bool VoxelGIGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<VoxelGI>(p_spatial) != nullptr;
}
-String GIProbeGizmoPlugin::get_gizmo_name() const {
- return "GIProbe";
+String VoxelGIGizmoPlugin::get_gizmo_name() const {
+ return "VoxelGI";
}
-int GIProbeGizmoPlugin::get_priority() const {
+int VoxelGIGizmoPlugin::get_priority() const {
return -1;
}
-String GIProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
switch (p_idx) {
case 0:
return "Extents X";
@@ -3087,16 +3105,16 @@ String GIProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int
return "";
}
-Variant GIProbeGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
- GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
+Variant VoxelGIGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+ VoxelGI *probe = Object::cast_to<VoxelGI>(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());
+void VoxelGIGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+ VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node());
- Transform gt = probe->get_global_transform();
- Transform gi = gt.affine_inverse();
+ Transform3D gt = probe->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
Vector3 extents = probe->get_extents();
@@ -3123,8 +3141,8 @@ void GIProbeGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camer
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());
+void VoxelGIGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+ VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node());
Vector3 restore = p_restore;
@@ -3140,19 +3158,19 @@ void GIProbeGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, co
ur->commit_action();
}
-void GIProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
+void VoxelGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ VoxelGI *probe = Object::cast_to<VoxelGI>(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);
+ Ref<Material> material = get_material("voxel_gi_material", p_gizmo);
+ Ref<Material> icon = get_material("voxel_gi_icon", p_gizmo);
+ Ref<Material> material_internal = get_material("voxel_gi_internal_material", p_gizmo);
p_gizmo->clear();
Vector<Vector3> lines;
Vector3 extents = probe->get_extents();
- static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 };
+ static const int subdivs[VoxelGI::SUBDIV_MAX] = { 64, 128, 256, 512 };
AABB aabb = AABB(-extents, extents * 2);
int subdiv = subdivs[probe->get_subdiv()];
@@ -3216,7 +3234,7 @@ void GIProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
if (p_gizmo->is_selected()) {
- Ref<Material> solid_material = get_material("gi_probe_solid_material", p_gizmo);
+ Ref<Material> solid_material = get_material("voxel_gi_solid_material", p_gizmo);
p_gizmo->add_solid_box(solid_material, aabb.get_size());
}
@@ -3226,7 +3244,7 @@ void GIProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
////
-BakedLightmapGizmoPlugin::BakedLightmapGizmoPlugin() {
+LightmapGIGizmoPlugin::LightmapGIGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/lightmap_lines", Color(0.5, 0.6, 1));
gizmo_color.a = 0.1;
@@ -3240,39 +3258,39 @@ BakedLightmapGizmoPlugin::BakedLightmapGizmoPlugin() {
add_material("lightmap_probe_material", mat);
- create_icon_material("baked_indirect_light_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoBakedLightmap", "EditorIcons"));
+ create_icon_material("baked_indirect_light_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoLightmapGI", "EditorIcons"));
}
-String BakedLightmapGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+String LightmapGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
return "";
}
-Variant BakedLightmapGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+Variant LightmapGIGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
return Variant();
}
-void BakedLightmapGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+void LightmapGIGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
}
-void BakedLightmapGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+void LightmapGIGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
}
-bool BakedLightmapGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- return Object::cast_to<BakedLightmap>(p_spatial) != nullptr;
+bool LightmapGIGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<LightmapGI>(p_spatial) != nullptr;
}
-String BakedLightmapGizmoPlugin::get_gizmo_name() const {
- return "BakedLightmap";
+String LightmapGIGizmoPlugin::get_gizmo_name() const {
+ return "LightmapGI";
}
-int BakedLightmapGizmoPlugin::get_priority() const {
+int LightmapGIGizmoPlugin::get_priority() const {
return -1;
}
-void BakedLightmapGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+void LightmapGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<Material> icon = get_material("baked_indirect_light_icon", p_gizmo);
- BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
- Ref<BakedLightmapData> data = baker->get_light_data();
+ LightmapGI *baker = Object::cast_to<LightmapGI>(p_gizmo->get_spatial_node());
+ Ref<LightmapGIData> data = baker->get_light_data();
p_gizmo->add_unscaled_billboard(icon, 0.05);
@@ -3543,7 +3561,7 @@ void CollisionObject3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
co->get_shape_owners(&owners);
for (List<uint32_t>::Element *E = owners.front(); E; E = E->next()) {
uint32_t owner_id = E->get();
- Transform xform = co->shape_owner_get_transform(owner_id);
+ Transform3D xform = co->shape_owner_get_transform(owner_id);
Object *owner = co->shape_owner_get_owner(owner_id);
// Exclude CollisionShape3D and CollisionPolygon3D as they have their gizmo.
if (!Object::cast_to<CollisionShape3D>(owner) && !Object::cast_to<CollisionPolygon3D>(owner)) {
@@ -3661,8 +3679,8 @@ void CollisionShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_i
return;
}
- Transform gt = cs->get_global_transform();
- Transform gi = gt.affine_inverse();
+ Transform3D gt = cs->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -4121,7 +4139,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (points.size() > 3) {
Vector<Vector3> varr = Variant(points);
Geometry3D::MeshData md;
- Error err = QuickHull::build(varr, md);
+ Error err = ConvexHullComputer::convex_hull(varr, md);
if (err == OK) {
Vector<Vector3> points2;
points2.resize(md.edges.size() * 2);
@@ -4329,7 +4347,7 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
#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) {
+Basis JointGizmosDrawer::look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) {
const Vector3 &p_eye(p_joint_transform.origin);
const Vector3 &p_target(p_body_transform.origin);
@@ -4354,7 +4372,7 @@ Basis JointGizmosDrawer::look_body(const Transform &p_joint_transform, const Tra
return base;
}
-Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform) {
+Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform3D &joint_transform, const Transform3D &body_transform) {
switch (p_axis) {
case Vector3::AXIS_X:
return look_body_toward_x(joint_transform, body_transform);
@@ -4367,7 +4385,7 @@ Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform
}
}
-Basis JointGizmosDrawer::look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform) {
+Basis JointGizmosDrawer::look_body_toward_x(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) {
const Vector3 &p_eye(p_joint_transform.origin);
const Vector3 &p_target(p_body_transform.origin);
@@ -4398,7 +4416,7 @@ Basis JointGizmosDrawer::look_body_toward_x(const Transform &p_joint_transform,
return base;
}
-Basis JointGizmosDrawer::look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform) {
+Basis JointGizmosDrawer::look_body_toward_y(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) {
const Vector3 &p_eye(p_joint_transform.origin);
const Vector3 &p_target(p_body_transform.origin);
@@ -4429,7 +4447,7 @@ Basis JointGizmosDrawer::look_body_toward_y(const Transform &p_joint_transform,
return base;
}
-Basis JointGizmosDrawer::look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform) {
+Basis JointGizmosDrawer::look_body_toward_z(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) {
const Vector3 &p_eye(p_joint_transform.origin);
const Vector3 &p_target(p_body_transform.origin);
@@ -4460,7 +4478,7 @@ Basis JointGizmosDrawer::look_body_toward_z(const Transform &p_joint_transform,
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) {
+void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform3D &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);
@@ -4522,7 +4540,7 @@ void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const
}
}
-void JointGizmosDrawer::draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points) {
+void JointGizmosDrawer::draw_cone(const Transform3D &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);
@@ -4626,7 +4644,7 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector<Vector3> body_b_points;
if (Object::cast_to<PinJoint3D>(joint)) {
- CreatePinJointGizmo(Transform(), points);
+ CreatePinJointGizmo(Transform3D(), points);
p_gizmo->add_collision_segments(points);
p_gizmo->add_lines(points, common_material);
}
@@ -4634,10 +4652,10 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
HingeJoint3D *hinge = Object::cast_to<HingeJoint3D>(joint);
if (hinge) {
CreateHingeJointGizmo(
- Transform(),
+ Transform3D(),
hinge->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform3D(),
+ node_body_b ? node_body_b->get_global_transform() : Transform3D(),
hinge->get_param(HingeJoint3D::PARAM_LIMIT_LOWER),
hinge->get_param(HingeJoint3D::PARAM_LIMIT_UPPER),
hinge->get_flag(HingeJoint3D::FLAG_USE_LIMIT),
@@ -4657,10 +4675,10 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
SliderJoint3D *slider = Object::cast_to<SliderJoint3D>(joint);
if (slider) {
CreateSliderJointGizmo(
- Transform(),
+ Transform3D(),
slider->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform3D(),
+ node_body_b ? node_body_b->get_global_transform() : Transform3D(),
slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_LOWER),
slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_UPPER),
slider->get_param(SliderJoint3D::PARAM_LINEAR_LIMIT_LOWER),
@@ -4681,10 +4699,10 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
ConeTwistJoint3D *cone = Object::cast_to<ConeTwistJoint3D>(joint);
if (cone) {
CreateConeTwistJointGizmo(
- Transform(),
+ Transform3D(),
cone->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform3D(),
+ node_body_b ? node_body_b->get_global_transform() : Transform3D(),
cone->get_param(ConeTwistJoint3D::PARAM_SWING_SPAN),
cone->get_param(ConeTwistJoint3D::PARAM_TWIST_SPAN),
node_body_a ? &body_a_points : nullptr,
@@ -4700,10 +4718,10 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Generic6DOFJoint3D *gen = Object::cast_to<Generic6DOFJoint3D>(joint);
if (gen) {
CreateGeneric6DOFJointGizmo(
- Transform(),
+ Transform3D(),
gen->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform3D(),
+ node_body_b ? node_body_b->get_global_transform() : Transform3D(),
gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT),
gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT),
@@ -4740,7 +4758,7 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
-void Joint3DGizmoPlugin::CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) {
+void Joint3DGizmoPlugin::CreatePinJointGizmo(const Transform3D &p_offset, Vector<Vector3> &r_cursor_points) {
float cs = 0.25;
r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin);
@@ -4751,7 +4769,7 @@ void Joint3DGizmoPlugin::CreatePinJointGizmo(const Transform &p_offset, Vector<V
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) {
+void Joint3DGizmoPlugin::CreateHingeJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &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);
@@ -4781,7 +4799,7 @@ void Joint3DGizmoPlugin::CreateHingeJointGizmo(const Transform &p_offset, const
}
}
-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) {
+void Joint3DGizmoPlugin::CreateSliderJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &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;
@@ -4840,7 +4858,7 @@ void Joint3DGizmoPlugin::CreateSliderJointGizmo(const Transform &p_offset, const
}
}
-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) {
+void Joint3DGizmoPlugin::CreateConeTwistJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &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,
@@ -4861,10 +4879,10 @@ void Joint3DGizmoPlugin::CreateConeTwistJointGizmo(const Transform &p_offset, co
}
void Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo(
- const Transform &p_offset,
- const Transform &p_trs_joint,
- const Transform &p_trs_body_a,
- const Transform &p_trs_body_b,
+ const Transform3D &p_offset,
+ const Transform3D &p_trs_joint,
+ const Transform3D &p_trs_body_a,
+ const Transform3D &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,
diff --git a/editor/node_3d_editor_gizmos.h b/editor/node_3d_editor_gizmos.h
index 6f98d3a08c..8a0e10241a 100644
--- a/editor/node_3d_editor_gizmos.h
+++ b/editor/node_3d_editor_gizmos.h
@@ -100,6 +100,18 @@ public:
MeshInstance3DGizmoPlugin();
};
+class OccluderInstance3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(OccluderInstance3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial) override;
+ String get_gizmo_name() const override;
+ int get_priority() const override;
+ void redraw(EditorNode3DGizmo *p_gizmo) override;
+
+ OccluderInstance3DGizmoPlugin();
+};
+
class Sprite3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Sprite3DGizmoPlugin, EditorNode3DGizmoPlugin);
@@ -304,8 +316,8 @@ public:
DecalGizmoPlugin();
};
-class GIProbeGizmoPlugin : public EditorNode3DGizmoPlugin {
- GDCLASS(GIProbeGizmoPlugin, EditorNode3DGizmoPlugin);
+class VoxelGIGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(VoxelGIGizmoPlugin, EditorNode3DGizmoPlugin);
public:
bool has_gizmo(Node3D *p_spatial) override;
@@ -318,11 +330,11 @@ public:
void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) override;
void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false) override;
- GIProbeGizmoPlugin();
+ VoxelGIGizmoPlugin();
};
-class BakedLightmapGizmoPlugin : public EditorNode3DGizmoPlugin {
- GDCLASS(BakedLightmapGizmoPlugin, EditorNode3DGizmoPlugin);
+class LightmapGIGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(LightmapGIGizmoPlugin, EditorNode3DGizmoPlugin);
public:
bool has_gizmo(Node3D *p_spatial) override;
@@ -335,7 +347,7 @@ public:
void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) override;
void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false) override;
- BakedLightmapGizmoPlugin();
+ LightmapGIGizmoPlugin();
};
class LightmapProbeGizmoPlugin : public EditorNode3DGizmoPlugin {
@@ -416,17 +428,17 @@ public:
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);
+ static Basis look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform);
+ static Basis look_body_toward(Vector3::Axis p_axis, const Transform3D &joint_transform, const Transform3D &body_transform);
+ static Basis look_body_toward_x(const Transform3D &p_joint_transform, const Transform3D &p_body_transform);
+ static Basis look_body_toward_y(const Transform3D &p_joint_transform, const Transform3D &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);
+ static Basis look_body_toward_z(const Transform3D &p_joint_transform, const Transform3D &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);
+ static void draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform3D &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 Transform3D &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points);
};
class Joint3DGizmoPlugin : public EditorNode3DGizmoPlugin {
@@ -443,15 +455,15 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- 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 CreatePinJointGizmo(const Transform3D &p_offset, Vector<Vector3> &r_cursor_points);
+ static void CreateHingeJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &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 Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &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 Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &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,
+ const Transform3D &p_offset,
+ const Transform3D &p_trs_joint,
+ const Transform3D &p_trs_body_a,
+ const Transform3D &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,
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index f496811e0a..f55d77d782 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -30,7 +30,7 @@
#include "plugin_config_dialog.h"
#include "core/io/config_file.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_scale.h"
@@ -214,6 +214,7 @@ PluginConfigDialog::PluginConfigDialog() {
desc_edit = memnew(TextEdit);
desc_edit->set_custom_minimum_size(Size2(400, 80) * EDSCALE);
+ desc_edit->set_wrap_enabled(true);
grid->add_child(desc_edit);
Label *author_lb = memnew(Label);
diff --git a/editor/plugins/SCsub b/editor/plugins/SCsub
index 359d04e5df..10a65b427e 100644
--- a/editor/plugins/SCsub
+++ b/editor/plugins/SCsub
@@ -3,3 +3,5 @@
Import("env")
env.add_source_files(env.editor_sources, "*.cpp")
+
+SConscript("tiles/SCsub")
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 80d0a7db60..e6f7ec1fbf 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -266,7 +266,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
- if (mb->get_control() || mb->get_shift() || mb->get_alt()) {
+ if (mb->is_ctrl_pressed() || mb->is_shift_pressed() || mb->is_alt_pressed()) {
return false;
}
@@ -399,7 +399,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)));
//Move the point in a single axis. Should only work when editing a polygon and while holding shift.
- if (mode == MODE_EDIT && mm->get_shift()) {
+ if (mode == MODE_EDIT && mm->is_shift_pressed()) {
Vector2 old_point = pre_move_edit.get(selected_point.vertex);
if (ABS(cpoint.x - old_point.x) > ABS(cpoint.y - old_point.y)) {
cpoint.y = old_point.y;
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 48fb507bb1..867c701733 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -139,7 +139,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
name->set_expand_to_text_length_enabled(true);
node->add_child(name);
node->set_slot(0, false, 0, Color(), true, 0, get_theme_color("font_color", "Label"));
- name->connect("text_entered", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed), varray(agnode), CONNECT_DEFERRED);
+ name->connect("text_submitted", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed), varray(agnode), CONNECT_DEFERRED);
name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out), varray(name, agnode), CONNECT_DEFERRED);
base = 1;
node->set_show_close_button(true);
@@ -231,18 +231,16 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
mb->get_popup()->connect("index_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_anim_selected), varray(options, E->get()), CONNECT_DEFERRED);
}
- if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
- 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_theme_color_override("title_color", c);
- c.a = 0.7;
- node->add_theme_color_override("close_color", c);
- node->add_theme_color_override("resizer_color", c);
- }
+ 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_theme_color_override("title_color", c);
+ c.a = 0.7;
+ node->add_theme_color_override("close_color", c);
+ node->add_theme_color_override("resizer_color", c);
}
List<AnimationNodeBlendTree::NodeConnection> connections;
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 612a8f30a4..4a3f3212fa 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -994,7 +994,7 @@ void AnimationPlayerEditor::_animation_duplicate() {
}
}
-void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set) {
+void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool p_timeline_only) {
if (updating || !player || player->is_playing()) {
return;
};
@@ -1015,18 +1015,18 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set) {
pos = Math::snapped(pos, _get_editor_step());
}
- if (player->is_valid() && !p_set) {
- float cpos = player->get_current_animation_position();
+ if (!p_timeline_only) {
+ if (player->is_valid() && !p_set) {
+ float cpos = player->get_current_animation_position();
- player->seek_delta(pos, pos - cpos);
- } else {
- player->stop(true);
- player->seek(pos, true);
+ player->seek_delta(pos, pos - cpos);
+ } else {
+ player->stop(true);
+ player->seek(pos, true);
+ }
}
track_editor->set_anim_pos(pos);
-
- updating = true;
};
void AnimationPlayerEditor::_animation_player_changed(Object *p_pl) {
@@ -1048,7 +1048,7 @@ void AnimationPlayerEditor::_animation_key_editor_anim_len_changed(float p_len)
frame->set_max(p_len);
}
-void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) {
+void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag, bool p_timeline_only) {
timeline_position = p_pos;
if (!is_visible_in_tree()) {
@@ -1070,7 +1070,7 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag)
updating = true;
frame->set_value(Math::snapped(p_pos, _get_editor_step()));
updating = false;
- _seek_value_changed(p_pos, !p_drag);
+ _seek_value_changed(p_pos, !p_drag, p_timeline_only);
}
void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
@@ -1222,10 +1222,10 @@ void AnimationPlayerEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND(p_ev.is_null());
Ref<InputEventKey> k = p_ev;
- if (is_visible_in_tree() && k.is_valid() && k->is_pressed() && !k->is_echo() && !k->get_alt() && !k->get_control() && !k->get_metakey()) {
+ if (is_visible_in_tree() && k.is_valid() && k->is_pressed() && !k->is_echo() && !k->is_alt_pressed() && !k->is_ctrl_pressed() && !k->is_meta_pressed()) {
switch (k->get_keycode()) {
case KEY_A: {
- if (!k->get_shift()) {
+ if (!k->is_shift_pressed()) {
_play_bw_from_pressed();
} else {
_play_bw_pressed();
@@ -1237,7 +1237,7 @@ void AnimationPlayerEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
accept_event();
} break;
case KEY_D: {
- if (!k->get_shift()) {
+ if (!k->is_shift_pressed()) {
_play_from_pressed();
} else {
_play_pressed();
@@ -1693,8 +1693,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
animation->connect("item_selected", callable_mp(this, &AnimationPlayerEditor::_animation_selected));
file->connect("file_selected", callable_mp(this, &AnimationPlayerEditor::_dialog_action));
- frame->connect("value_changed", callable_mp(this, &AnimationPlayerEditor::_seek_value_changed), make_binds(true));
- scale->connect("text_entered", callable_mp(this, &AnimationPlayerEditor::_scale_changed));
+ frame->connect("value_changed", callable_mp(this, &AnimationPlayerEditor::_seek_value_changed), make_binds(true, false));
+ scale->connect("text_submitted", callable_mp(this, &AnimationPlayerEditor::_scale_changed));
renaming = false;
last_active = false;
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 2f6bf55e4c..5c2348f86b 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -187,7 +187,7 @@ class AnimationPlayerEditor : public VBoxContainer {
void _scale_changed(const String &p_scale);
void _dialog_action(String p_file);
void _seek_frame_changed(const String &p_frame);
- void _seek_value_changed(float p_value, bool p_set = false);
+ void _seek_value_changed(float p_value, bool p_set = false, bool p_timeline_only = false);
void _blend_editor_next_changed(const int p_idx);
void _list_changed();
@@ -197,7 +197,7 @@ class AnimationPlayerEditor : public VBoxContainer {
void _animation_player_changed(Object *p_pl);
- void _animation_key_editor_seek(float p_pos, bool p_drag);
+ void _animation_key_editor_seek(float p_pos, bool p_drag, bool p_timeline_only = false);
void _animation_key_editor_anim_len_changed(float p_len);
void _unhandled_key_input(const Ref<InputEvent> &p_ev);
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index a9709bbb16..fe5a0cab4d 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -124,7 +124,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// select node or push a field inside
- if (mb.is_valid() && !mb->get_shift() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_shift_pressed() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
selected_transition_from = StringName();
selected_transition_to = StringName();
selected_node = StringName();
@@ -237,7 +237,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
//connect nodes
- if (mb.is_valid() && ((tool_select->is_pressed() && mb->get_shift()) || tool_connect->is_pressed()) && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
+ if (mb.is_valid() && ((tool_select->is_pressed() && mb->is_shift_pressed()) || tool_connect->is_pressed()) && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected
connecting = true;
@@ -1329,7 +1329,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
name_edit = memnew(LineEdit);
name_edit_popup->add_child(name_edit);
name_edit->set_anchors_and_offsets_preset(PRESET_WIDE);
- name_edit->connect("text_entered", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited));
+ name_edit->connect("text_submitted", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited));
name_edit->connect("focus_exited", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited_focus_out));
open_file = memnew(EditorFileDialog);
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index fd47d9964e..93bb170128 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -240,7 +240,6 @@ void EditorAssetLibraryItemDescription::add_preview(int p_id, bool p_video, cons
preview.video_link = p_url;
preview.is_video = p_video;
preview.button = memnew(Button);
- preview.button->set_flat(true);
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));
@@ -465,7 +464,7 @@ void EditorAssetLibraryItemDownload::_make_request() {
retry->hide();
download->cancel_request();
- download->set_download_file(EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip");
+ download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip");
Error err = download->request(host);
if (err != OK) {
@@ -703,7 +702,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
PackedByteArray image_data = p_data;
if (use_cache) {
- String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
+ String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
FileAccess *file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ);
@@ -782,7 +781,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) {
for (int i = 0; i < headers.size(); i++) {
if (headers[i].findn("ETag:") == 0) { // Save etag
- String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
+ String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges();
FileAccess *file;
@@ -830,7 +829,7 @@ void EditorAssetLibrary::_update_image_queue() {
List<int> to_delete;
for (Map<int, ImageQueue>::Element *E = image_queue.front(); E; E = E->next()) {
if (!E->get().active && current_images < max_images) {
- String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + E->get().image_url.md5_text());
+ String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + E->get().image_url.md5_text());
Vector<String> headers;
if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) {
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 11eae9e041..c6ca1ecd4f 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -282,7 +282,7 @@ class EditorAssetLibrary : public PanelContainer {
void _search(int p_page = 0);
void _rerun_search(int p_ignore);
void _search_text_changed(const String &p_text = "");
- void _search_text_entered(const String &p_text = "");
+ void _search_text_submitted(const String &p_text = "");
void _api_request(const String &p_request, RequestType p_request_type, const String &p_arguments = "");
void _http_request_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
void _http_download_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp
index 3553450672..3b54b30b54 100644
--- a/editor/plugins/audio_stream_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
+#include "core/os/keyboard.h"
#include "editor/audio_stream_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -144,23 +145,26 @@ 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_theme_color("accent_color", "Editor"), 1);
+ const Color color = get_theme_color("accent_color", "Editor");
+ _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), color, Math::round(2 * EDSCALE));
+ _indicator->draw_texture(
+ get_theme_icon("TimelineIndicator", "EditorIcons"),
+ Point2(ofs_x - get_theme_icon("TimelineIndicator", "EditorIcons")->get_width() * 0.5, 0),
+ color);
_current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /");
}
void AudioStreamEditor::_on_input_indicator(Ref<InputEvent> p_event) {
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid()) {
+ const Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
_seek_to(mb->get_position().x);
}
_dragging = mb->is_pressed();
}
- Ref<InputEventMouseMotion> mm = p_event;
-
+ const Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
if (_dragging) {
_seek_to(mm->get_position().x);
@@ -228,6 +232,7 @@ AudioStreamEditor::AudioStreamEditor() {
hbox->add_child(_play_button);
_play_button->set_focus_mode(Control::FOCUS_NONE);
_play_button->connect("pressed", callable_mp(this, &AudioStreamEditor::_play));
+ _play_button->set_shortcut(ED_SHORTCUT("inspector/audio_preview_play_pause", TTR("Audio Preview Play/Pause"), KEY_SPACE));
_stop_button = memnew(Button);
_stop_button->set_flat(true);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index fc3e15aa52..5d248176c1 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -332,7 +332,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 ^ Input::get_singleton()->is_key_pressed(KEY_CTRL);
// Smart snap using the canvas position
Vector2 output = p_target;
@@ -460,7 +460,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) ^ Input::get_singleton()->is_key_pressed(KEY_CTRL)) && snap_rotation_step != 0) {
if (snap_relative) {
return Math::snapped(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset + (p_start - (int)(p_start / snap_rotation_step) * snap_rotation_step);
} else {
@@ -481,11 +481,11 @@ void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
}
if (k.is_valid()) {
- if (k->get_keycode() == KEY_CONTROL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT) {
+ if (k->get_keycode() == KEY_CTRL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT) {
viewport->update();
}
- if (k->is_pressed() && !k->get_control() && !k->is_echo()) {
+ if (k->is_pressed() && !k->is_ctrl_pressed() && !k->is_echo()) {
if ((grid_snap_active || show_grid) && multiply_grid_step_shortcut.is_valid() && multiply_grid_step_shortcut->is_shortcut(p_ev)) {
// Multiply the grid size
grid_step_multiplier = MIN(grid_step_multiplier + 1, 12);
@@ -666,93 +666,6 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel
}
}
-void CanvasItemEditor::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items) {
- Point2 screen_pos = transform.xform(p_pos);
-
- for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
- Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from));
-
- Vector<Vector2> bone_shape;
- if (!_get_bone_shape(&bone_shape, nullptr, E)) {
- continue;
- }
-
- // Check if the point is inside the Polygon2D
- if (Geometry2D::is_point_in_polygon(screen_pos, bone_shape)) {
- // Check if the item is already in the list
- bool duplicate = false;
- for (int i = 0; i < r_items.size(); i++) {
- if (r_items[i].item == from_node) {
- duplicate = true;
- break;
- }
- }
- if (duplicate) {
- continue;
- }
-
- // Else, add it
- _SelectResult res;
- res.item = from_node;
- res.z_index = from_node ? from_node->get_z_index() : 0;
- res.has_z = from_node;
- r_items.push_back(res);
- }
- }
-}
-
-bool CanvasItemEditor::_get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> *outline_shape, Map<BoneKey, BoneList>::Element *bone) {
- int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width");
- int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size");
-
- Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().from));
- Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().to));
-
- if (!from_node) {
- return false;
- }
- if (!from_node->is_inside_tree()) {
- return false; //may have been removed
- }
-
- if (!to_node && bone->get().length == 0) {
- return false;
- }
-
- Vector2 from = transform.xform(from_node->get_global_position());
- Vector2 to;
-
- if (to_node) {
- to = transform.xform(to_node->get_global_position());
- } else {
- to = transform.xform(from_node->get_global_transform().xform(Vector2(bone->get().length, 0)));
- }
-
- Vector2 rel = to - from;
- Vector2 relt = rel.orthogonal().normalized() * bone_width;
- Vector2 reln = rel.normalized();
- Vector2 reltn = relt.normalized();
-
- if (shape) {
- shape->clear();
- shape->push_back(from);
- shape->push_back(from + rel * 0.2 + relt);
- shape->push_back(to);
- shape->push_back(from + rel * 0.2 - relt);
- }
-
- if (outline_shape) {
- outline_shape->clear();
- outline_shape->push_back(from + (-reln - reltn) * bone_outline_width);
- outline_shape->push_back(from + (-reln + reltn) * bone_outline_width);
- outline_shape->push_back(from + rel * 0.2 + relt + reltn * bone_outline_width);
- outline_shape->push_back(to + (reln + reltn) * bone_outline_width);
- outline_shape->push_back(to + (reln - reltn) * bone_outline_width);
- outline_shape->push_back(from + rel * 0.2 - relt - reltn * bone_outline_width);
- }
- return true;
-}
-
void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
if (!p_node) {
return;
@@ -886,50 +799,6 @@ Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2
return output;
}
-void CanvasItemEditor::_save_canvas_item_ik_chain(const CanvasItem *p_canvas_item, List<float> *p_bones_length, List<Dictionary> *p_bones_state) {
- if (p_bones_length) {
- *p_bones_length = List<float>();
- }
- if (p_bones_state) {
- *p_bones_state = List<Dictionary>();
- }
-
- const Node2D *bone = Object::cast_to<Node2D>(p_canvas_item);
- if (bone && bone->has_meta("_edit_bone_")) {
- // Check if we have an IK chain
- List<const Node2D *> bone_ik_list;
- bool ik_found = false;
- bone = Object::cast_to<Node2D>(bone->get_parent());
- while (bone) {
- bone_ik_list.push_back(bone);
- if (bone->has_meta("_edit_ik_")) {
- ik_found = true;
- break;
- } else if (!bone->has_meta("_edit_bone_")) {
- break;
- }
- bone = Object::cast_to<Node2D>(bone->get_parent());
- }
-
- //Save the bone state and length if we have an IK chain
- if (ik_found) {
- bone = Object::cast_to<Node2D>(p_canvas_item);
- Transform2D bone_xform = bone->get_global_transform();
- for (List<const Node2D *>::Element *bone_E = bone_ik_list.front(); bone_E; bone_E = bone_E->next()) {
- bone_xform = bone_xform * bone->get_transform().affine_inverse();
- const Node2D *parent_bone = bone_E->get();
- if (p_bones_length) {
- p_bones_length->push_back(parent_bone->get_global_transform().get_origin().distance_to(bone->get_global_position()));
- }
- if (p_bones_state) {
- p_bones_state->push_back(parent_bone->_edit_get_state());
- }
- bone = parent_bone;
- }
- }
- }
-}
-
void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) {
for (List<CanvasItem *>::Element *E = p_canvas_items.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
@@ -942,31 +811,15 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items
} else {
se->pre_drag_rect = Rect2();
}
-
- // If we have a bone, save the state of all nodes in the IK chain
- _save_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_length), &(se->pre_drag_bones_undo_state));
}
}
}
-void CanvasItemEditor::_restore_canvas_item_ik_chain(CanvasItem *p_canvas_item, const List<Dictionary> *p_bones_state) {
- CanvasItem *canvas_item = p_canvas_item;
- for (const List<Dictionary>::Element *E = p_bones_state->front(); E; E = E->next()) {
- canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent());
- canvas_item->_edit_set_state(E->get());
- }
-}
-
void CanvasItemEditor::_restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones) {
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
- if (se) {
- canvas_item->_edit_set_state(se->undo_state);
- if (restore_bones) {
- _restore_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_undo_state));
- }
- }
+ canvas_item->_edit_set_state(se->undo_state);
}
}
@@ -1269,12 +1122,12 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bool p_already_accepted) {
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid() && !p_already_accepted) {
- const bool pan_on_scroll = bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan")) && !b->get_control();
+ const bool pan_on_scroll = bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan")) && !b->is_ctrl_pressed();
if (pan_on_scroll) {
// Perform horizontal scrolling first so we can check for Shift being held.
if (b->is_pressed() &&
- (b->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT || (b->get_shift() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP))) {
+ (b->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT || (b->is_shift_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP))) {
// Pan left
view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
update_viewport();
@@ -1282,7 +1135,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
}
if (b->is_pressed() &&
- (b->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT || (b->get_shift() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN))) {
+ (b->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT || (b->is_shift_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN))) {
// Pan right
view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
update_viewport();
@@ -1296,11 +1149,11 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
update_viewport();
} else {
- float new_zoom = _get_next_zoom_value(-1);
+ zoom_widget->set_zoom_by_increments(-1);
if (b->get_factor() != 1.f) {
- new_zoom = zoom * ((new_zoom / zoom - 1.f) * b->get_factor() + 1.f);
+ zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * b->get_factor() + 1.f));
}
- _zoom_on_position(new_zoom, b->get_position());
+ _zoom_on_position(zoom_widget->get_zoom(), b->get_position());
}
return true;
}
@@ -1311,11 +1164,11 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
update_viewport();
} else {
- float new_zoom = _get_next_zoom_value(1);
+ zoom_widget->set_zoom_by_increments(1);
if (b->get_factor() != 1.f) {
- new_zoom = zoom * ((new_zoom / zoom - 1.f) * b->get_factor() + 1.f);
+ zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * b->get_factor() + 1.f));
}
- _zoom_on_position(new_zoom, b->get_position());
+ _zoom_on_position(zoom_widget->get_zoom(), b->get_position());
}
return true;
}
@@ -1389,14 +1242,15 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid() && !p_already_accepted) {
// If control key pressed, then zoom instead of pan
- if (pan_gesture->get_control()) {
+ if (pan_gesture->is_ctrl_pressed()) {
const float factor = pan_gesture->get_delta().y;
- float new_zoom = _get_next_zoom_value(-1);
+ zoom_widget->set_zoom_by_increments(1);
if (factor != 1.f) {
- new_zoom = zoom * ((new_zoom / zoom - 1.f) * factor + 1.f);
+ zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * factor + 1.f));
}
- _zoom_on_position(new_zoom, pan_gesture->get_position());
+ _zoom_on_position(zoom_widget->get_zoom(), pan_gesture->get_position());
+
return true;
}
@@ -1496,76 +1350,6 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
return false;
}
-void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) {
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(leaf_node);
- if (se) {
- int nb_bones = se->pre_drag_bones_undo_state.size();
- if (nb_bones > 0) {
- // Build the node list
- Point2 leaf_pos = target_position;
-
- List<Node2D *> joints_list;
- List<Point2> joints_pos;
- Node2D *joint = leaf_node;
- Transform2D joint_transform = leaf_node->get_global_transform_with_canvas();
- for (int i = 0; i < nb_bones + 1; i++) {
- joints_list.push_back(joint);
- joints_pos.push_back(joint_transform.get_origin());
- joint_transform = joint_transform * joint->get_transform().affine_inverse();
- joint = Object::cast_to<Node2D>(joint->get_parent());
- }
- Point2 root_pos = joints_list.back()->get()->get_global_transform_with_canvas().get_origin();
-
- // Restraints the node to a maximum distance is necessary
- float total_len = 0;
- for (List<float>::Element *E = se->pre_drag_bones_length.front(); E; E = E->next()) {
- total_len += E->get();
- }
- if ((root_pos.distance_to(leaf_pos)) > total_len) {
- Vector2 rel = leaf_pos - root_pos;
- rel = rel.normalized() * total_len;
- leaf_pos = root_pos + rel;
- }
- joints_pos[0] = leaf_pos;
-
- // Run the solver
- int solver_iterations = 64;
- float solver_k = 0.3;
-
- // Build the position list
- for (int i = 0; i < solver_iterations; i++) {
- // Handle the leaf joint
- int node_id = 0;
- for (List<float>::Element *E = se->pre_drag_bones_length.front(); E; E = E->next()) {
- Vector2 direction = (joints_pos[node_id + 1] - joints_pos[node_id]).normalized();
- int len = E->get();
- if (E == se->pre_drag_bones_length.front()) {
- joints_pos[1] = joints_pos[1].lerp(joints_pos[0] + len * direction, solver_k);
- } else if (E == se->pre_drag_bones_length.back()) {
- joints_pos[node_id] = joints_pos[node_id].lerp(joints_pos[node_id + 1] - len * direction, solver_k);
- } else {
- Vector2 center = (joints_pos[node_id + 1] + joints_pos[node_id]) / 2.0;
- joints_pos[node_id] = joints_pos[node_id].lerp(center - (direction * len) / 2.0, solver_k);
- joints_pos[node_id + 1] = joints_pos[node_id + 1].lerp(center + (direction * len) / 2.0, solver_k);
- }
- node_id++;
- }
- }
-
- // Set the position
- for (int node_id = joints_list.size() - 1; node_id > 0; node_id--) {
- Point2 current = (joints_list[node_id - 1]->get_global_position() - joints_list[node_id]->get_global_position()).normalized();
- Point2 target = (joints_pos[node_id - 1] - joints_list[node_id]->get_global_position()).normalized();
- float rot = current.angle_to(target);
- if (joints_list[node_id]->get_global_transform().basis_determinant() < 0) {
- rot = -rot;
- }
- joints_list[node_id]->rotate(rot);
- }
- }
- }
-}
-
bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> b = p_event;
Ref<InputEventMouseMotion> m = p_event;
@@ -1573,7 +1357,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
// Start rotation
if (drag_type == DRAG_NONE) {
if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
- if ((b->get_command() && !b->get_alt() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
+ if ((b->is_command_pressed() && !b->is_alt_pressed() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
// Remove not movable nodes
@@ -1654,7 +1438,7 @@ bool CanvasItemEditor::_gui_input_open_scene_on_double_click(const Ref<InputEven
Ref<InputEventMouseButton> b = p_event;
// Open a sub-scene on double-click
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && b->is_doubleclick() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && b->is_double_click() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -1739,7 +1523,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
Vector2 new_anchor = xform.xform(snap_point(previous_anchor + (drag_to - drag_from), SNAP_GRID | SNAP_OTHER_NODES, SNAP_NODE_PARENT | SNAP_NODE_SIDES | SNAP_NODE_CENTER, control));
new_anchor = _position_to_anchor(control, new_anchor).snapped(Vector2(0.001, 0.001));
- bool use_single_axis = m->get_shift();
+ bool use_single_axis = m->is_shift_pressed();
Vector2 drag_vector = xform.xform(drag_to) - xform.xform(drag_from);
bool use_y = Math::abs(drag_vector.y) > Math::abs(drag_vector.x);
@@ -1887,8 +1671,8 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
//Reset state
canvas_item->_edit_set_state(se->undo_state);
- bool uniform = m->get_shift();
- bool symmetric = m->get_alt();
+ bool uniform = m->is_shift_pressed();
+ bool symmetric = m->is_alt_pressed();
Rect2 local_rect = canvas_item->_edit_get_rect();
float aspect = local_rect.get_size().y / local_rect.get_size().x;
@@ -2027,7 +1811,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
// Drag resize handles
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && ((b->get_alt() && b->get_control()) || tool == TOOL_SCALE)) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_ctrl_pressed()) || tool == TOOL_SCALE)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -2073,8 +1857,8 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
Transform2D unscaled_transform = (transform * parent_xform * canvas_item->_edit_get_transform()).orthonormalized();
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 uniform = m->is_shift_pressed();
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
Point2 drag_from_local = simple_xform.xform(drag_from);
Point2 drag_to_local = simple_xform.xform(drag_to);
@@ -2166,7 +1950,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_NONE) {
//Start moving the nodes
if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
- if ((b->get_alt() && !b->get_control()) || tool == TOOL_MOVE) {
+ if ((b->is_alt_pressed() && !b->is_ctrl_pressed()) || tool == TOOL_MOVE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
drag_selection.clear();
@@ -2207,14 +1991,6 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_MOVE || drag_type == DRAG_MOVE_X || drag_type == DRAG_MOVE_Y) {
// Move the nodes
if (m.is_valid()) {
- // Save the ik chain for reapplying before IK solve
- 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(), nullptr, &bones_ik_states);
- all_bones_ik_states.push_back(bones_ik_states);
- }
-
_restore_canvas_item_state(drag_selection, true);
drag_to = transform.affine_inverse().xform(m->get_position());
@@ -2234,7 +2010,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
new_pos.x = previous_pos.x;
}
- bool single_axis = m->get_shift();
+ bool single_axis = m->is_shift_pressed();
if (single_axis) {
if (ABS(new_pos.x - previous_pos.x) > ABS(new_pos.y - previous_pos.y)) {
new_pos.y = previous_pos.y;
@@ -2243,25 +2019,12 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
}
- bool force_no_IK = m->get_alt();
int index = 0;
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
- if (se) {
- Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
-
- Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
- if (node2d && se->pre_drag_bones_undo_state.size() > 0 && !force_no_IK) {
- real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
- _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
- real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
- node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
- _solve_IK(node2d, new_pos);
- } else {
- canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
- }
- }
+ Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
+
+ canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
index++;
}
return true;
@@ -2324,18 +2087,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;
- for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
- List<Dictionary> bones_ik_states;
- _save_canvas_item_ik_chain(E->get(), nullptr, &bones_ik_states);
- all_bones_ik_states.push_back(bones_ik_states);
- }
-
_restore_canvas_item_state(drag_selection, true);
- bool move_local_base = k->get_alt();
- bool move_local_base_rotated = k->get_control() || k->get_metakey();
+ bool move_local_base = k->is_alt_pressed();
+ bool move_local_base_rotated = k->is_ctrl_pressed() || k->is_meta_pressed();
Vector2 dir;
if (k->get_keycode() == KEY_UP) {
@@ -2347,12 +2102,12 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
} else if (k->get_keycode() == KEY_RIGHT) {
dir += Vector2(1, 0);
}
- if (k->get_shift()) {
+ if (k->is_shift_pressed()) {
dir *= grid_step * Math::pow(2.0, grid_step_multiplier);
}
drag_to += dir;
- if (k->get_shift()) {
+ if (k->is_shift_pressed()) {
drag_to = drag_to.snapped(grid_step * Math::pow(2.0, grid_step_multiplier));
}
@@ -2383,21 +2138,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
int index = 0;
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
- if (se) {
- Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
-
- Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
- if (node2d && se->pre_drag_bones_undo_state.size() > 0) {
- real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
- _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
- real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
- node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
- _solve_IK(node2d, new_pos);
- } else {
- canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
- }
- }
+ Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
+
+ canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
index++;
}
}
@@ -2441,18 +2184,18 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_NONE) {
if (b.is_valid() &&
- ((b->get_button_index() == MOUSE_BUTTON_RIGHT && b->get_alt() && tool == TOOL_SELECT) ||
+ ((b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_alt_pressed() && tool == TOOL_SELECT) ||
(b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_LIST_SELECT))) {
// Popup the selection menu list
Point2 click = transform.affine_inverse().xform(b->get_position());
- _get_canvas_items_at_pos(click, selection_results, b->get_alt() && tool != TOOL_LIST_SELECT);
+ _get_canvas_items_at_pos(click, selection_results, b->is_alt_pressed() && tool != TOOL_LIST_SELECT);
if (selection_results.size() == 1) {
CanvasItem *item = selection_results[0].item;
selection_results.clear();
- _select_click_on_item(item, click, b->get_shift());
+ _select_click_on_item(item, click, b->is_shift_pressed());
return true;
} else if (!selection_results.is_empty()) {
@@ -2496,14 +2239,14 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
selection_menu->set_item_tooltip(i, String(item->get_name()) + "\nType: " + item->get_class() + "\nPath: " + node_path);
}
- selection_menu_additive_selection = b->get_shift();
+ selection_menu_additive_selection = b->is_shift_pressed();
selection_menu->set_position(get_screen_transform().xform(b->get_position()));
selection_menu->popup();
return true;
}
}
- if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->get_control()) {
+ if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_ctrl_pressed()) {
add_node_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
add_node_menu->set_size(Vector2(1, 1));
add_node_menu->popup();
@@ -2523,23 +2266,17 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
// Find the item to select
CanvasItem *canvas_item = nullptr;
- // Retrieve the bones
Vector<_SelectResult> selection = Vector<_SelectResult>();
- _get_bones_at_pos(click, selection);
+ // Retrieve the canvas items
+ selection = Vector<_SelectResult>();
+ _get_canvas_items_at_pos(click, selection);
if (!selection.is_empty()) {
canvas_item = selection[0].item;
- } else {
- // Retrieve the canvas items
- selection = Vector<_SelectResult>();
- _get_canvas_items_at_pos(click, selection);
- if (!selection.is_empty()) {
- canvas_item = selection[0].item;
- }
}
if (!canvas_item) {
// Start a box selection
- if (!b->get_shift()) {
+ if (!b->is_shift_pressed()) {
// Clear the selection if not additive
editor_selection->clear();
viewport->update();
@@ -2551,26 +2288,42 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
box_selecting_to = drag_from;
return true;
} else {
- bool still_selected = _select_click_on_item(canvas_item, click, b->get_shift());
+ bool still_selected = _select_click_on_item(canvas_item, click, b->is_shift_pressed());
// Start dragging
if (still_selected) {
// Drag the node(s) if requested
- List<CanvasItem *> selection2 = _get_edited_canvas_items();
+ drag_start_origin = click;
+ drag_type = DRAG_QUEUED;
+ }
+ // Select the item
+ return true;
+ }
+ }
+ }
- drag_selection.clear();
- for (int i = 0; i < selection2.size(); i++) {
- if (_is_node_movable(selection2[i], true)) {
- drag_selection.push_back(selection2[i]);
- }
- }
+ if (drag_type == DRAG_QUEUED) {
+ if (b.is_valid() && !b->is_pressed()) {
+ drag_type = DRAG_NONE;
+ return true;
+ }
+ if (m.is_valid()) {
+ Point2 click = transform.affine_inverse().xform(m->get_position());
+ bool movement_threshold_passed = drag_start_origin.distance_to(click) > 10 * EDSCALE;
+ if (m.is_valid() && movement_threshold_passed) {
+ List<CanvasItem *> selection2 = _get_edited_canvas_items();
- if (selection2.size() > 0) {
- drag_type = DRAG_MOVE;
- drag_from = click;
- _save_canvas_item_state(drag_selection);
+ drag_selection.clear();
+ for (int i = 0; i < selection2.size(); i++) {
+ if (_is_node_movable(selection2[i], true)) {
+ drag_selection.push_back(selection2[i]);
}
}
- // Select the item
+
+ if (selection2.size() > 0) {
+ drag_type = DRAG_MOVE;
+ drag_from = click;
+ _save_canvas_item_state(drag_selection);
+ }
return true;
}
}
@@ -3573,7 +3326,7 @@ void CanvasItemEditor::_draw_selection() {
}
// Draw the move handles
- bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
if (tool == TOOL_MOVE && show_transformation_gizmos) {
if (_is_node_movable(canvas_item)) {
@@ -3733,65 +3486,6 @@ void CanvasItemEditor::_draw_axis() {
}
}
-void CanvasItemEditor::_draw_bones() {
- RID ci = viewport->get_canvas_item();
-
- if (skeleton_show_bones) {
- Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1");
- Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2");
- Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
- Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color");
- Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color");
-
- for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
- Vector<Vector2> bone_shape;
- Vector<Vector2> bone_shape_outline;
- if (!_get_bone_shape(&bone_shape, &bone_shape_outline, E)) {
- continue;
- }
-
- Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from));
- if (!from_node->is_visible_in_tree()) {
- continue;
- }
-
- Vector<Color> colors;
- if (from_node->has_meta("_edit_ik_")) {
- colors.push_back(bone_ik_color);
- colors.push_back(bone_ik_color);
- colors.push_back(bone_ik_color);
- colors.push_back(bone_ik_color);
- } else {
- colors.push_back(bone_color1);
- colors.push_back(bone_color2);
- colors.push_back(bone_color1);
- colors.push_back(bone_color2);
- }
-
- Vector<Color> outline_colors;
-
- if (editor_selection->is_selected(from_node)) {
- outline_colors.push_back(bone_selected_color);
- outline_colors.push_back(bone_selected_color);
- outline_colors.push_back(bone_selected_color);
- outline_colors.push_back(bone_selected_color);
- outline_colors.push_back(bone_selected_color);
- outline_colors.push_back(bone_selected_color);
- } else {
- outline_colors.push_back(bone_outline_color);
- outline_colors.push_back(bone_outline_color);
- outline_colors.push_back(bone_outline_color);
- outline_colors.push_back(bone_outline_color);
- outline_colors.push_back(bone_outline_color);
- outline_colors.push_back(bone_outline_color);
- }
-
- 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());
- }
- }
-}
-
void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
ERR_FAIL_COND(!p_node);
@@ -3907,72 +3601,6 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p
}
}
-bool CanvasItemEditor::_build_bones_list(Node *p_node) {
- ERR_FAIL_COND_V(!p_node, false);
-
- bool has_child_bones = false;
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
- if (_build_bones_list(p_node->get_child(i))) {
- has_child_bones = true;
- }
- }
-
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
- Node *scene = editor->get_edited_scene();
- if (!canvas_item || !canvas_item->is_visible() || (canvas_item != scene && canvas_item->get_owner() != scene && canvas_item != scene->get_deepest_editable_node(canvas_item))) {
- return false;
- }
-
- Node *parent = canvas_item->get_parent();
-
- if (Object::cast_to<Bone2D>(canvas_item)) {
- if (Object::cast_to<Bone2D>(parent)) {
- // Add as bone->parent relationship
- BoneKey bk;
- bk.from = parent->get_instance_id();
- bk.to = canvas_item->get_instance_id();
- if (!bone_list.has(bk)) {
- BoneList b;
- b.length = 0;
- bone_list[bk] = b;
- }
-
- bone_list[bk].last_pass = bone_last_frame;
- }
-
- if (!has_child_bones) {
- // Add a last bone if the Bone2D has no Bone2D child
- BoneKey bk;
- bk.from = canvas_item->get_instance_id();
- bk.to = ObjectID();
- if (!bone_list.has(bk)) {
- BoneList b;
- b.length = 0;
- bone_list[bk] = b;
- }
- bone_list[bk].last_pass = bone_last_frame;
- }
-
- return true;
- }
-
- if (canvas_item->has_meta("_edit_bone_")) {
- // Add a "custom bone"
- BoneKey bk;
- bk.from = parent->get_instance_id();
- bk.to = canvas_item->get_instance_id();
- if (!bone_list.has(bk)) {
- BoneList b;
- b.length = 0;
- bone_list[bk] = b;
- }
- bone_list[bk].last_pass = bone_last_frame;
- }
-
- return false;
-}
-
void CanvasItemEditor::_draw_viewport() {
// Update the transform
transform = Transform2D();
@@ -4032,7 +3660,6 @@ void CanvasItemEditor::_draw_viewport() {
force_over_plugin_list->forward_canvas_force_draw_over_viewport(viewport);
}
- _draw_bones();
if (show_rulers) {
_draw_rulers();
}
@@ -4158,8 +3785,8 @@ void CanvasItemEditor::_notification(int p_what) {
}
Bone2D *bone = Object::cast_to<Bone2D>(b);
- if (bone && bone->get_default_length() != E->get().length) {
- E->get().length = bone->get_default_length();
+ if (bone && bone->get_length() != E->get().length) {
+ E->get().length = bone->get_length();
viewport->update();
}
}
@@ -4174,18 +3801,11 @@ void CanvasItemEditor::_notification(int p_what) {
AnimationPlayerEditor::singleton->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
_keying_changed();
- get_tree()->connect("node_added", callable_mp(this, &CanvasItemEditor::_tree_changed), varray());
- get_tree()->connect("node_removed", callable_mp(this, &CanvasItemEditor::_tree_changed), varray());
} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
select_sb->set_texture(get_theme_icon("EditorRect2D", "EditorIcons"));
}
- if (p_what == NOTIFICATION_EXIT_TREE) {
- get_tree()->disconnect("node_added", callable_mp(this, &CanvasItemEditor::_tree_changed));
- get_tree()->disconnect("node_removed", callable_mp(this, &CanvasItemEditor::_tree_changed));
- }
-
if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
select_button->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
list_select_button->set_icon(get_theme_icon("ListSelect", "EditorIcons"));
@@ -4219,9 +3839,6 @@ void CanvasItemEditor::_notification(int p_what) {
key_auto_insert_button->add_theme_color_override("icon_pressed_color", key_auto_color.lerp(Color(1, 0, 0), 0.55));
animation_menu->set_icon(get_theme_icon("GuiTabMenuHl", "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();
@@ -4323,46 +3940,6 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
}
}
-void CanvasItemEditor::_queue_update_bone_list() {
- if (bone_list_dirty) {
- return;
- }
-
- call_deferred("_update_bone_list");
- bone_list_dirty = true;
-}
-
-void CanvasItemEditor::_update_bone_list() {
- bone_last_frame++;
-
- if (editor->get_edited_scene()) {
- _build_bones_list(editor->get_edited_scene());
- }
-
- List<Map<BoneKey, BoneList>::Element *> bone_to_erase;
- for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) {
- if (E->get().last_pass != bone_last_frame) {
- bone_to_erase.push_back(E);
- continue;
- }
-
- Node *node = Object::cast_to<Node>(ObjectDB::get_instance(E->key().from));
- if (!node || !node->is_inside_tree() || (node != get_tree()->get_edited_scene_root() && !get_tree()->get_edited_scene_root()->is_a_parent_of(node))) {
- bone_to_erase.push_back(E);
- continue;
- }
- }
- while (bone_to_erase.size()) {
- bone_list.erase(bone_to_erase.front()->get());
- bone_to_erase.pop_front();
- }
- bone_list_dirty = false;
-}
-
-void CanvasItemEditor::_tree_changed(Node *) {
- _queue_update_bone_list();
-}
-
void CanvasItemEditor::_update_scrollbars() {
updating_scroll = true;
@@ -4378,11 +3955,9 @@ void CanvasItemEditor::_update_scrollbars() {
Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height));
- _queue_update_bone_list();
-
// Calculate scrollable area.
Rect2 canvas_item_rect = Rect2(Point2(), screen_rect);
- if (editor->get_edited_scene()) {
+ if (editor->is_inside_tree() && editor->get_edited_scene()) {
Rect2 content_rect = _get_encompassing_rect(editor->get_edited_scene());
canvas_item_rect.expand_to(content_rect.position);
canvas_item_rect.expand_to(content_rect.position + content_rect.size);
@@ -4579,33 +4154,6 @@ void CanvasItemEditor::_set_anchors_preset(Control::LayoutPreset p_preset) {
undo_redo->commit_action();
}
-float CanvasItemEditor::_get_next_zoom_value(int p_increment_count) const {
- // Base increment factor defined as the twelveth root of two.
- // This allow a smooth geometric evolution of the zoom, with the advantage of
- // visiting all integer power of two scale factors.
- // note: this is analogous to the 'semitones' interval in the music world
- // In order to avoid numerical imprecisions, we compute and edit a zoom index
- // with the following relation: zoom = 2 ^ (index / 12)
-
- if (zoom < CMP_EPSILON || p_increment_count == 0) {
- return 1.f;
- }
-
- // Remove Editor scale from the index computation
- float zoom_noscale = zoom / MAX(1, EDSCALE);
-
- // zoom = 2**(index/12) => log2(zoom) = index/12
- float closest_zoom_index = Math::round(Math::log(zoom_noscale) * 12.f / Math::log(2.f));
-
- float new_zoom_index = closest_zoom_index + p_increment_count;
- float new_zoom = Math::pow(2.f, new_zoom_index / 12.f);
-
- // Restore Editor scale transformation
- new_zoom *= MAX(1, EDSCALE);
-
- return new_zoom;
-}
-
void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM);
@@ -4630,36 +4178,12 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
view_offset = view_offset_int + (view_offset_frac * closest_zoom_factor).round() / closest_zoom_factor;
}
- _update_zoom_label();
+ zoom_widget->set_zoom(zoom);
update_viewport();
}
-void CanvasItemEditor::_update_zoom_label() {
- String zoom_text;
- // The zoom level displayed is relative to the editor scale
- // (like in most image editors). Its lower bound is clamped to 1 as some people
- // lower the editor scale to increase the available real estate,
- // even if their display doesn't have a particularly low DPI.
- if (zoom >= 10) {
- // Don't show a decimal when the zoom level is higher than 1000 %.
- zoom_text = TS->format_number(rtos(Math::round((zoom / MAX(1, EDSCALE)) * 100))) + " " + TS->percent_sign();
- } else {
- zoom_text = TS->format_number(rtos(Math::snapped((zoom / MAX(1, EDSCALE)) * 100, 0.1))) + " " + TS->percent_sign();
- }
-
- zoom_reset->set_text(zoom_text);
-}
-
-void CanvasItemEditor::_button_zoom_minus() {
- _zoom_on_position(_get_next_zoom_value(-6), viewport_scrollable->get_size() / 2.0);
-}
-
-void CanvasItemEditor::_button_zoom_reset() {
- _zoom_on_position(1.0 * MAX(1, EDSCALE), viewport_scrollable->get_size() / 2.0);
-}
-
-void CanvasItemEditor::_button_zoom_plus() {
- _zoom_on_position(_get_next_zoom_value(6), viewport_scrollable->get_size() / 2.0);
+void CanvasItemEditor::_update_zoom(float p_zoom) {
+ _zoom_on_position(p_zoom, viewport_scrollable->get_size() / 2.0);
}
void CanvasItemEditor::_button_toggle_smart_snap(bool p_status) {
@@ -4890,10 +4414,19 @@ void CanvasItemEditor::_popup_callback(int p_op) {
snap_dialog->popup_centered(Size2(220, 160) * EDSCALE);
} break;
case SKELETON_SHOW_BONES: {
- skeleton_show_bones = !skeleton_show_bones;
- int idx = skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES);
- skeleton_menu->get_popup()->set_item_checked(idx, skeleton_show_bones);
- viewport->update();
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ // Add children nodes so they are processed
+ for (int child = 0; child < E->get()->get_child_count(); child++) {
+ selection.push_back(E->get()->get_child(child));
+ }
+
+ Bone2D *bone_2d = Object::cast_to<Bone2D>(E->get());
+ if (!bone_2d || !bone_2d->is_inside_tree()) {
+ continue;
+ }
+ bone_2d->_editor_set_show_bone_gizmo(!bone_2d->_editor_get_show_bone_gizmo());
+ }
} break;
case SHOW_HELPERS: {
show_helpers = !show_helpers;
@@ -5242,107 +4775,45 @@ void CanvasItemEditor::_popup_callback(int p_op) {
} break;
case SKELETON_MAKE_BONES: {
Map<Node *, Object *> &selection = editor_selection->get_selection();
+ Node *editor_root = EditorNode::get_singleton()->get_edited_scene()->get_tree()->get_edited_scene_root();
- undo_redo->create_action(TTR("Create Custom Bone(s) from Node(s)"));
+ undo_redo->create_action(TTR("Create Custom Bone2D(s) from Node(s)"));
for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
Node2D *n2d = Object::cast_to<Node2D>(E->key());
- if (!n2d) {
- continue;
- }
- if (!n2d->is_visible_in_tree()) {
- continue;
- }
- if (!n2d->get_parent_item()) {
- continue;
- }
- if (n2d->has_meta("_edit_bone_") && n2d->get_meta("_edit_bone_")) {
- continue;
- }
-
- undo_redo->add_do_method(n2d, "set_meta", "_edit_bone_", true);
- undo_redo->add_undo_method(n2d, "remove_meta", "_edit_bone_");
- }
- undo_redo->add_do_method(this, "_queue_update_bone_list");
- undo_redo->add_undo_method(this, "_queue_update_bone_list");
- undo_redo->add_do_method(viewport, "update");
- undo_redo->add_undo_method(viewport, "update");
- undo_redo->commit_action();
- } break;
- case SKELETON_CLEAR_BONES: {
- Map<Node *, Object *> &selection = editor_selection->get_selection();
+ Bone2D *new_bone = memnew(Bone2D);
+ String new_bone_name = n2d->get_name();
+ new_bone_name += "Bone2D";
+ new_bone->set_name(new_bone_name);
+ new_bone->set_transform(n2d->get_transform());
- undo_redo->create_action(TTR("Clear Bones"));
- for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
- Node2D *n2d = Object::cast_to<Node2D>(E->key());
- if (!n2d) {
- continue;
- }
- if (!n2d->is_visible_in_tree()) {
+ Node *n2d_parent = n2d->get_parent();
+ if (!n2d_parent) {
continue;
}
- if (!n2d->has_meta("_edit_bone_")) {
- continue;
- }
-
- undo_redo->add_do_method(n2d, "remove_meta", "_edit_bone_");
- undo_redo->add_undo_method(n2d, "set_meta", "_edit_bone_", n2d->get_meta("_edit_bone_"));
- }
- undo_redo->add_do_method(this, "_queue_update_bone_list");
- undo_redo->add_undo_method(this, "_queue_update_bone_list");
- undo_redo->add_do_method(viewport, "update");
- undo_redo->add_undo_method(viewport, "update");
- undo_redo->commit_action();
- } break;
- case SKELETON_SET_IK_CHAIN: {
- List<Node *> selection = editor_selection->get_selected_node_list();
+ undo_redo->add_do_method(n2d_parent, "add_child", new_bone);
+ undo_redo->add_do_method(n2d_parent, "remove_child", n2d);
+ undo_redo->add_do_method(new_bone, "add_child", n2d);
+ undo_redo->add_do_method(n2d, "set_transform", Transform2D());
+ undo_redo->add_do_method(this, "_set_owner_for_node_and_children", new_bone, editor_root);
- undo_redo->create_action(TTR("Make IK Chain"));
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
- if (!canvas_item || !canvas_item->is_visible_in_tree()) {
- continue;
- }
- if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
- continue;
- }
- if (canvas_item->has_meta("_edit_ik_") && canvas_item->get_meta("_edit_ik_")) {
- continue;
- }
-
- undo_redo->add_do_method(canvas_item, "set_meta", "_edit_ik_", true);
- undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_ik_");
+ undo_redo->add_undo_method(new_bone, "remove_child", n2d);
+ undo_redo->add_undo_method(n2d_parent, "add_child", n2d);
+ undo_redo->add_undo_method(n2d, "set_transform", new_bone->get_transform());
+ undo_redo->add_undo_method(new_bone, "queue_free");
+ undo_redo->add_undo_method(this, "_set_owner_for_node_and_children", n2d, editor_root);
}
- undo_redo->add_do_method(viewport, "update");
- undo_redo->add_undo_method(viewport, "update");
undo_redo->commit_action();
} break;
- case SKELETON_CLEAR_IK_CHAIN: {
- Map<Node *, Object *> &selection = editor_selection->get_selection();
-
- undo_redo->create_action(TTR("Clear IK Chain"));
- for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
- CanvasItem *n2d = Object::cast_to<CanvasItem>(E->key());
- if (!n2d) {
- continue;
- }
- if (!n2d->is_visible_in_tree()) {
- continue;
- }
- if (!n2d->has_meta("_edit_ik_")) {
- continue;
- }
-
- undo_redo->add_do_method(n2d, "remove_meta", "_edit_ik_");
- undo_redo->add_undo_method(n2d, "set_meta", "_edit_ik_", n2d->get_meta("_edit_ik_"));
- }
- undo_redo->add_do_method(viewport, "update");
- undo_redo->add_undo_method(viewport, "update");
- undo_redo->commit_action();
+ }
+}
- } break;
+void CanvasItemEditor::_set_owner_for_node_and_children(Node *p_node, Node *p_owner) {
+ p_node->set_owner(p_owner);
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _set_owner_for_node_and_children(p_node->get_child(i), p_owner);
}
}
@@ -5401,7 +4872,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
zoom = scale_x < scale_y ? scale_x : scale_y;
zoom *= 0.90;
viewport->update();
- _update_zoom_label();
+ zoom_widget->set_zoom(zoom);
call_deferred("_popup_callback", VIEW_CENTER_TO_SELECTION);
}
}
@@ -5411,11 +4882,11 @@ void CanvasItemEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button);
ClassDB::bind_method("_get_editor_data", &CanvasItemEditor::_get_editor_data);
ClassDB::bind_method("_unhandled_key_input", &CanvasItemEditor::_unhandled_key_input);
- ClassDB::bind_method("_queue_update_bone_list", &CanvasItemEditor::_update_bone_list);
- ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list);
- ClassDB::bind_method("_reset_create_position", &CanvasItemEditor::_reset_create_position);
ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);
ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport);
+ ClassDB::bind_method(D_METHOD("_zoom_on_position"), &CanvasItemEditor::_zoom_on_position);
+
+ ClassDB::bind_method("_set_owner_for_node_and_children", &CanvasItemEditor::_set_owner_for_node_and_children);
ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
ADD_SIGNAL(MethodInfo("item_group_status_changed"));
@@ -5446,14 +4917,13 @@ Dictionary CanvasItemEditor::get_state() const {
state["show_rulers"] = show_rulers;
state["show_guides"] = show_guides;
state["show_helpers"] = show_helpers;
- state["show_zoom_control"] = zoom_hb->is_visible();
+ state["show_zoom_control"] = zoom_widget->is_visible();
state["show_edit_locks"] = show_edit_locks;
state["show_transformation_gizmos"] = show_transformation_gizmos;
state["snap_rotation"] = snap_rotation;
state["snap_scale"] = snap_scale;
state["snap_relative"] = snap_relative;
state["snap_pixel"] = snap_pixel;
- state["skeleton_show_bones"] = skeleton_show_bones;
return state;
}
@@ -5464,7 +4934,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
// Compensate the editor scale, so that the editor scale can be changed
// and the zoom level will still be the same (relative to the editor scale).
zoom = float(p_state["zoom"]) * MAX(1, EDSCALE);
- _update_zoom_label();
+ zoom_widget->set_zoom(zoom);
}
if (state.has("ofs")) {
@@ -5594,7 +5064,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
if (state.has("show_zoom_control")) {
// This one is not user-controllable, but instrumentable
- zoom_hb->set_visible(state["show_zoom_control"]);
+ zoom_widget->set_visible(state["show_zoom_control"]);
}
if (state.has("snap_rotation")) {
@@ -5621,12 +5091,6 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
snap_config_menu->get_popup()->set_item_checked(idx, snap_pixel);
}
- if (state.has("skeleton_show_bones")) {
- skeleton_show_bones = state["skeleton_show_bones"];
- int idx = skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES);
- skeleton_menu->get_popup()->set_item_checked(idx, skeleton_show_bones);
- }
-
if (update_scrollbars) {
_update_scrollbars();
}
@@ -5709,8 +5173,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
selected_from_canvas = false;
anchors_mode = false;
- skeleton_show_bones = true;
-
drag_type = DRAG_NONE;
drag_from = Vector2();
drag_to = Vector2();
@@ -5726,7 +5188,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
bone_last_frame = 0;
- bone_list_dirty = false;
tool = TOOL_SELECT;
undo_redo = p_editor->get_undo_redo();
editor = p_editor;
@@ -5770,11 +5231,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
controls_vb = memnew(VBoxContainer);
controls_vb->set_begin(Point2(5, 5));
- zoom_hb = memnew(HBoxContainer);
- // Bring the zoom percentage closer to the zoom buttons
- zoom_hb->add_theme_constant_override("separation", Math::round(-8 * EDSCALE));
- controls_vb->add_child(zoom_hb);
-
viewport = memnew(CanvasItemEditorViewport(p_editor, this));
viewport_scrollable->add_child(viewport);
viewport->set_mouse_filter(MOUSE_FILTER_PASS);
@@ -5821,38 +5277,20 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
viewport->add_child(controls_vb);
- zoom_minus = memnew(Button);
- zoom_minus->set_flat(true);
- zoom_hb->add_child(zoom_minus);
- zoom_minus->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_zoom_minus));
- zoom_minus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", TTR("Zoom Out"), KEY_MASK_CMD | KEY_MINUS));
- zoom_minus->set_shortcut_context(this);
- zoom_minus->set_focus_mode(FOCUS_NONE);
-
- zoom_reset = memnew(Button);
- zoom_reset->set_flat(true);
- zoom_hb->add_child(zoom_reset);
- zoom_reset->add_theme_constant_override("outline_size", 1);
- zoom_reset->add_theme_color_override("font_outline_color", Color(0, 0, 0));
- zoom_reset->add_theme_color_override("font_color", Color(1, 1, 1));
- zoom_reset->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_zoom_reset));
- zoom_reset->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_reset", TTR("Zoom Reset"), KEY_MASK_CMD | KEY_0));
- zoom_reset->set_shortcut_context(this);
- zoom_reset->set_focus_mode(FOCUS_NONE);
- zoom_reset->set_text_align(Button::TextAlign::ALIGN_CENTER);
- // Prevent the button's size from changing when the text size changes
- zoom_reset->set_custom_minimum_size(Size2(75 * EDSCALE, 0));
-
- zoom_plus = memnew(Button);
- zoom_plus->set_flat(true);
- zoom_hb->add_child(zoom_plus);
- zoom_plus->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_zoom_plus));
- zoom_plus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", TTR("Zoom In"), KEY_MASK_CMD | KEY_EQUAL)); // Usually direct access key for PLUS
- zoom_plus->set_shortcut_context(this);
- zoom_plus->set_focus_mode(FOCUS_NONE);
+ zoom_widget = memnew(EditorZoomWidget);
+ controls_vb->add_child(zoom_widget);
+ zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);
+ zoom_widget->connect("zoom_changed", callable_mp(this, &CanvasItemEditor::_update_zoom));
updating_scroll = false;
+ // Add some margin to the left for better aesthetics.
+ // This prevents the first button's hover/pressed effect from "touching" the panel's border,
+ // which looks ugly.
+ Control *margin_left = memnew(Control);
+ hb->add_child(margin_left);
+ margin_left->set_custom_minimum_size(Size2(2, 0) * EDSCALE);
+
select_button = memnew(Button);
select_button->set_flat(true);
hb->add_child(select_button);
@@ -6014,13 +5452,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p = skeleton_menu->get_popup();
p->set_hide_on_checkable_item_selection(false);
- p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_show_bones", TTR("Show Bones")), SKELETON_SHOW_BONES);
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_set_ik_chain", TTR("Make IK Chain")), SKELETON_SET_IK_CHAIN);
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_ik_chain", TTR("Clear IK Chain")), SKELETON_CLEAR_IK_CHAIN);
+ p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_show_bones", TTR("Show Bones")), SKELETON_SHOW_BONES);
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Custom Bone(s) from Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B), SKELETON_MAKE_BONES);
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Custom Bones")), SKELETON_CLEAR_BONES);
+ p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Bone2D Node(s) from Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B), SKELETON_MAKE_BONES);
p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback));
hb->add_child(memnew(VSeparator));
@@ -6089,7 +5523,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_loc_button = memnew(Button);
key_loc_button->set_toggle_mode(true);
- key_loc_button->set_flat(true);
key_loc_button->set_pressed(true);
key_loc_button->set_focus_mode(FOCUS_NONE);
key_loc_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_POS));
@@ -6098,7 +5531,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_rot_button = memnew(Button);
key_rot_button->set_toggle_mode(true);
- key_rot_button->set_flat(true);
key_rot_button->set_pressed(true);
key_rot_button->set_focus_mode(FOCUS_NONE);
key_rot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_ROT));
@@ -6107,14 +5539,12 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_scale_button = memnew(Button);
key_scale_button->set_toggle_mode(true);
- key_scale_button->set_flat(true);
key_scale_button->set_focus_mode(FOCUS_NONE);
key_scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_SCALE));
key_scale_button->set_tooltip(TTR("Scale mask for inserting keys."));
animation_hb->add_child(key_scale_button);
key_insert_button = memnew(Button);
- key_insert_button->set_flat(true);
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_KEY));
key_insert_button->set_tooltip(TTR("Insert keys (based on mask)."));
@@ -6518,8 +5948,7 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
type == "CurveTexture" ||
type == "GradientTexture" ||
type == "StreamTexture2D" ||
- type == "AtlasTexture" ||
- type == "LargeTexture") {
+ type == "AtlasTexture") {
Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res));
if (!texture.is_valid()) {
continue;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 62a9b1e162..7b64d0cb5d 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -33,6 +33,7 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
+#include "editor/editor_zoom_widget.h"
#include "scene/gui/box_container.h"
#include "scene/gui/check_box.h"
#include "scene/gui/label.h"
@@ -186,10 +187,7 @@ private:
VIEW_FRAME_TO_SELECTION,
PREVIEW_CANVAS_SCALE,
SKELETON_MAKE_BONES,
- SKELETON_CLEAR_BONES,
- SKELETON_SHOW_BONES,
- SKELETON_SET_IK_CHAIN,
- SKELETON_CLEAR_IK_CHAIN
+ SKELETON_SHOW_BONES
};
enum DragType {
@@ -208,6 +206,7 @@ private:
DRAG_ANCHOR_BOTTOM_RIGHT,
DRAG_ANCHOR_BOTTOM_LEFT,
DRAG_ANCHOR_ALL,
+ DRAG_QUEUED,
DRAG_MOVE,
DRAG_MOVE_X,
DRAG_MOVE_Y,
@@ -222,7 +221,6 @@ private:
DRAG_KEY_MOVE
};
- EditorSelection *editor_selection;
bool selection_menu_additive_selection;
Tool tool;
@@ -233,10 +231,6 @@ private:
VScrollBar *v_scroll;
HBoxContainer *hb;
- Button *zoom_minus;
- Button *zoom_reset;
- Button *zoom_plus;
-
Map<Control *, Timer *> popup_temporarily_timers;
Label *warning_child_of_container;
@@ -280,7 +274,6 @@ private:
bool snap_scale;
bool snap_relative;
bool snap_pixel;
- bool skeleton_show_bones;
bool key_pos;
bool key_rot;
bool key_scale;
@@ -387,6 +380,7 @@ private:
Control *top_ruler;
Control *left_ruler;
+ Point2 drag_start_origin;
DragType drag_type;
Point2 drag_from;
Point2 drag_to;
@@ -415,7 +409,6 @@ private:
bool _is_node_movable(const Node *p_node, bool p_popup_warning = false);
void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, bool p_allow_locked = false);
- void _get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items);
void _find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append);
@@ -426,9 +419,7 @@ private:
void _add_canvas_item(CanvasItem *p_canvas_item);
- void _save_canvas_item_ik_chain(const CanvasItem *p_canvas_item, List<float> *p_bones_length, List<Dictionary> *p_bones_state);
void _save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones = false);
- void _restore_canvas_item_ik_chain(CanvasItem *p_canvas_item, const List<Dictionary> *p_bones_state);
void _restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones = false);
void _commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones = false);
@@ -448,8 +439,6 @@ private:
void _reset_create_position();
UndoRedo *undo_redo;
- bool _build_bones_list(Node *p_node);
- bool _get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> *outline_shape, Map<BoneKey, BoneList>::Element *bone);
List<CanvasItem *> _get_edited_canvas_items(bool retreive_locked = false, bool remove_canvas_item_if_parent_in_selection = true);
Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list);
@@ -479,7 +468,6 @@ private:
void _draw_control_helpers(Control *control);
void _draw_selection();
void _draw_axis();
- void _draw_bones();
void _draw_invisible_nodes_positions(Node *p_node, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
void _draw_locks_and_groups(Node *p_node, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
void _draw_hover();
@@ -506,8 +494,6 @@ private:
void _focus_selection(int p_op);
- void _solve_IK(Node2D *leaf_node, Point2 target_position);
-
SnapTarget snap_target[2];
Transform2D snap_transform;
void _snap_if_closer_float(
@@ -536,13 +522,9 @@ private:
void _button_toggle_anchor_mode(bool p_status);
VBoxContainer *controls_vb;
- HBoxContainer *zoom_hb;
- float _get_next_zoom_value(int p_increment_count) const;
+ EditorZoomWidget *zoom_widget;
+ void _update_zoom(float p_zoom);
void _zoom_on_position(float p_zoom, Point2 p_position = Point2());
- void _update_zoom_label();
- void _button_zoom_minus();
- void _button_zoom_reset();
- void _button_zoom_plus();
void _button_toggle_smart_snap(bool p_status);
void _button_toggle_grid_snap(bool p_status);
void _button_override_camera(bool p_pressed);
@@ -553,14 +535,11 @@ private:
HSplitContainer *palette_split;
VSplitContainer *bottom_split;
- bool bone_list_dirty;
- void _queue_update_bone_list();
- void _update_bone_list();
- void _tree_changed(Node *);
-
void _popup_warning_temporarily(Control *p_control, const float p_duration);
void _popup_warning_depop(Control *p_control);
+ void _set_owner_for_node_and_children(Node *p_node, Node *p_owner);
+
friend class CanvasItemEditorPlugin;
protected:
@@ -648,6 +627,8 @@ public:
bool is_anchors_mode_enabled() { return anchors_mode; };
+ EditorSelection *editor_selection;
+
CanvasItemEditor(EditorNode *p_editor);
};
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.cpp b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
index b50a497ccf..a0df7e289e 100644
--- a/editor/plugins/collision_polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
@@ -32,8 +32,8 @@
#include "canvas_item_editor_plugin.h"
#include "core/input/input.h"
+#include "core/io/file_access.h"
#include "core/math/geometry_2d.h"
-#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "editor/editor_settings.h"
#include "node_3d_editor_plugin.h"
@@ -108,8 +108,8 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
return false;
}
- Transform gt = node->get_global_transform();
- Transform gi = gt.affine_inverse();
+ Transform3D gt = node->get_global_transform();
+ Transform3D 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);
@@ -175,7 +175,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
case MODE_EDIT: {
if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
- if (mb->get_control()) {
+ if (mb->is_ctrl_pressed()) {
if (poly.size() < 3) {
undo_redo->create_action(TTR("Edit Poly"));
undo_redo->add_undo_method(node, "set_polygon", poly);
@@ -317,7 +317,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
Vector2 cpoint(spoint.x, spoint.y);
- if (snap_ignore && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (snap_ignore && !Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
snap_ignore = false;
}
@@ -516,7 +516,7 @@ CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) {
mode = MODE_EDIT;
wip_active = false;
imgeom = memnew(ImmediateGeometry3D);
- imgeom->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001)));
+ imgeom->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001)));
line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
@@ -539,7 +539,7 @@ CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) {
imgeom->add_child(pointsm);
m.instance();
pointsm->set_mesh(m);
- pointsm->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001)));
+ pointsm->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001)));
snap_ignore = false;
}
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index db999f50ab..7a38fd2bd5 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -168,8 +168,8 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) {
// Snap to "round" coordinates when holding Ctrl.
// Be more precise when holding Shift as well.
float snap_threshold;
- if (mm.get_control()) {
- snap_threshold = mm.get_shift() ? 0.025 : 0.1;
+ if (mm.is_ctrl_pressed()) {
+ snap_threshold = mm.is_shift_pressed() ? 0.025 : 0.1;
} else {
snap_threshold = 0.0;
}
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index d3e5854786..235ccb18cb 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -81,7 +81,6 @@ bool EditorTexturePreviewPlugin::generate_small_preview_automatically() const {
Ref<Texture2D> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
Ref<Image> img;
Ref<AtlasTexture> atex = p_from;
- Ref<LargeTexture> ltex = p_from;
if (atex.is_valid()) {
Ref<Texture2D> tex = atex->get_atlas();
if (!tex.is_valid()) {
@@ -94,8 +93,6 @@ Ref<Texture2D> EditorTexturePreviewPlugin::generate(const RES &p_from, const Siz
}
img = atlas->get_rect(atex->get_region());
- } else if (ltex.is_valid()) {
- img = ltex->to_image();
} else {
Ref<Texture2D> tex = p_from;
if (tex.is_valid()) {
@@ -268,7 +265,7 @@ Ref<Texture2D> EditorPackedScenePreviewPlugin::generate(const RES &p_from, const
}
Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const {
- String temp_path = EditorSettings::get_singleton()->get_cache_dir();
+ String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text();
cache_base = temp_path.plus_file("resthumb-" + cache_base);
@@ -362,12 +359,12 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
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_transform(camera, Transform3D(Basis(), Vector3(0, 0, 3)));
RS::get_singleton()->camera_set_perspective(camera, 45, 0.1, 10);
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)));
+ RS::get_singleton()->instance_set_transform(light_instance, Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
light2 = RS::get_singleton()->directional_light_create();
RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
@@ -375,7 +372,7 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
light_instance2 = RS::get_singleton()->instance_create2(light2, scenario);
- RS::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, Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
sphere = RS::get_singleton()->mesh_create();
sphere_instance = RS::get_singleton()->instance_create2(sphere, scenario);
@@ -490,10 +487,15 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
List<String> kwors;
scr->get_language()->get_reserved_words(&kwors);
+ Set<String> control_flow_keywords;
Set<String> keywords;
for (List<String>::Element *E = kwors.front(); E; E = E->next()) {
- keywords.insert(E->get());
+ if (scr->get_language()->is_control_flow_keyword(E->get())) {
+ control_flow_keywords.insert(E->get());
+ } else {
+ keywords.insert(E->get());
+ }
}
int line = 0;
@@ -505,8 +507,10 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
Color bg_color = EditorSettings::get_singleton()->get("text_editor/highlighting/background_color");
Color keyword_color = EditorSettings::get_singleton()->get("text_editor/highlighting/keyword_color");
+ Color control_flow_keyword_color = EditorSettings::get_singleton()->get("text_editor/highlighting/control_flow_keyword_color");
Color text_color = EditorSettings::get_singleton()->get("text_editor/highlighting/text_color");
Color symbol_color = EditorSettings::get_singleton()->get("text_editor/highlighting/symbol_color");
+ Color comment_color = EditorSettings::get_singleton()->get("text_editor/highlighting/comment_color");
if (bg_color.a == 0) {
bg_color = Color(0, 0, 0, 0);
@@ -525,36 +529,50 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
col = x0;
bool prev_is_text = false;
+ bool in_control_flow_keyword = false;
bool in_keyword = false;
+ bool in_comment = false;
for (int i = 0; i < code.length(); i++) {
char32_t c = code[i];
if (c > 32) {
if (col < thumbnail_size) {
Color color = text_color;
- if (c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t')) {
- //make symbol a little visible
- color = symbol_color;
- in_keyword = false;
- } else if (!prev_is_text && _is_text_char(c)) {
- int pos = i;
+ if (c == '#') {
+ in_comment = true;
+ }
- while (_is_text_char(code[pos])) {
- pos++;
- }
- String word = code.substr(i, pos - i);
- if (keywords.has(word)) {
- in_keyword = true;
+ if (in_comment) {
+ color = comment_color;
+ } else {
+ if (c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t')) {
+ //make symbol a little visible
+ color = symbol_color;
+ in_control_flow_keyword = false;
+ in_keyword = false;
+ } else if (!prev_is_text && _is_text_char(c)) {
+ int pos = i;
+
+ while (_is_text_char(code[pos])) {
+ pos++;
+ }
+ String word = code.substr(i, pos - i);
+ if (control_flow_keywords.has(word)) {
+ in_control_flow_keyword = true;
+ } else if (keywords.has(word)) {
+ in_keyword = true;
+ }
+
+ } else if (!_is_text_char(c)) {
+ in_keyword = false;
}
- } else if (!_is_text_char(c)) {
- in_keyword = false;
- }
-
- if (in_keyword) {
- color = keyword_color;
+ if (in_control_flow_keyword) {
+ color = control_flow_keyword_color;
+ } else if (in_keyword) {
+ color = keyword_color;
+ }
}
-
Color ul = color;
ul.a *= 0.5;
img->set_pixel(col, y0 + line * 2, bg_color.blend(ul));
@@ -562,11 +580,15 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
prev_is_text = _is_text_char(c);
}
+ col++;
} else {
prev_is_text = false;
+ in_control_flow_keyword = false;
in_keyword = false;
if (c == '\n') {
+ in_comment = false;
+
col = x0;
line++;
if (line >= available_height / 2) {
@@ -574,9 +596,10 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
}
} else if (c == '\t') {
col += 3;
+ } else {
+ col++;
}
}
- col++;
}
post_process_preview(img);
@@ -697,7 +720,7 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2
AABB aabb = mesh->get_aabb();
Vector3 ofs = aabb.position + aabb.size * 0.5;
aabb.position -= ofs;
- Transform xform;
+ Transform3D xform;
xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI * 0.125);
xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI * 0.125) * xform.basis;
AABB rot_aabb = xform.xform(aabb);
@@ -757,20 +780,20 @@ EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() {
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_transform(camera, Transform3D(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 = 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)));
+ RS::get_singleton()->instance_set_transform(light_instance, Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
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);
- RS::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, Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
//sphere = RS::get_singleton()->mesh_create();
mesh_instance = RS::get_singleton()->instance_create();
@@ -809,7 +832,7 @@ struct FSample {
};
static FSample _samples[] = {
- { "hani", U"漢語" },
+ { "hani", U"漢字" },
{ "armn", U"Ô±Õ¢" },
{ "copt", U"Αα" },
{ "cyrl", U"Ðб" },
diff --git a/editor/plugins/font_editor_plugin.cpp b/editor/plugins/font_editor_plugin.cpp
index fa58eb5480..8de7dc2447 100644
--- a/editor/plugins/font_editor_plugin.cpp
+++ b/editor/plugins/font_editor_plugin.cpp
@@ -56,7 +56,7 @@ struct FSample {
};
static FSample _samples[] = {
- { "hani", U"漢語" },
+ { "hani", U"漢字" },
{ "armn", U"Ô±Õ¢" },
{ "copt", U"Αα" },
{ "cyrl", U"Ðб" },
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index 433a5ae51c..17c7397729 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -177,7 +177,7 @@ void GPUParticles3DEditorBase::_node_selected(const NodePath &p_path) {
return;
}
- Transform geom_xform = base_node->get_global_transform().affine_inverse() * vi->get_global_transform();
+ Transform3D geom_xform = base_node->get_global_transform().affine_inverse() * vi->get_global_transform();
int gc = geometry.size();
Face3 *w = geometry.ptrw();
@@ -346,7 +346,7 @@ void GPUParticles3DEditor::_generate_emission_points() {
{
uint8_t *iw = point_img.ptrw();
- zeromem(iw, w * h * 3 * sizeof(float));
+ memset(iw, 0, w * h * 3 * sizeof(float));
const Vector3 *r = points.ptr();
float *wf = (float *)iw;
for (int i = 0; i < point_count; i++) {
@@ -374,7 +374,7 @@ void GPUParticles3DEditor::_generate_emission_points() {
{
uint8_t *iw = point_img2.ptrw();
- zeromem(iw, w * h * 3 * sizeof(float));
+ memset(iw, 0, w * h * 3 * sizeof(float));
const Vector3 *r = normals.ptr();
float *wf = (float *)iw;
for (int i = 0; i < point_count; i++) {
diff --git a/editor/plugins/baked_lightmap_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp
index 470b61bf40..484fdabfe1 100644
--- a/editor/plugins/baked_lightmap_editor_plugin.cpp
+++ b/editor/plugins/lightmap_gi_editor_plugin.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* baked_lightmap_editor_plugin.cpp */
+/* lightmap_gi_editor_plugin.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "baked_lightmap_editor_plugin.h"
+#include "lightmap_gi_editor_plugin.h"
-void BakedLightmapEditorPlugin::_bake_select_file(const String &p_file) {
+void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
if (lightmap) {
- BakedLightmap::BakeError err;
+ LightmapGI::BakeError err;
if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) {
err = lightmap->bake(lightmap, p_file, bake_func_step);
} else {
@@ -42,7 +42,7 @@ void BakedLightmapEditorPlugin::_bake_select_file(const String &p_file) {
bake_func_end();
switch (err) {
- case BakedLightmap::BAKE_ERROR_NO_SAVE_PATH: {
+ case LightmapGI::BAKE_ERROR_NO_SAVE_PATH: {
String scene_path = lightmap->get_filename();
if (scene_path == String()) {
scene_path = lightmap->get_owner()->get_filename();
@@ -57,10 +57,10 @@ void BakedLightmapEditorPlugin::_bake_select_file(const String &p_file) {
file_dialog->popup_file_dialog();
} break;
- case BakedLightmap::BAKE_ERROR_NO_MESHES:
+ case LightmapGI::BAKE_ERROR_NO_MESHES:
EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake Light' flag is on."));
break;
- case BakedLightmap::BAKE_ERROR_CANT_CREATE_IMAGE:
+ case LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE:
EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable."));
break;
default: {
@@ -69,12 +69,12 @@ void BakedLightmapEditorPlugin::_bake_select_file(const String &p_file) {
}
}
-void BakedLightmapEditorPlugin::_bake() {
+void LightmapGIEditorPlugin::_bake() {
_bake_select_file("");
}
-void BakedLightmapEditorPlugin::edit(Object *p_object) {
- BakedLightmap *s = Object::cast_to<BakedLightmap>(p_object);
+void LightmapGIEditorPlugin::edit(Object *p_object) {
+ LightmapGI *s = Object::cast_to<LightmapGI>(p_object);
if (!s) {
return;
}
@@ -82,11 +82,11 @@ void BakedLightmapEditorPlugin::edit(Object *p_object) {
lightmap = s;
}
-bool BakedLightmapEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("BakedLightmap");
+bool LightmapGIEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("LightmapGI");
}
-void BakedLightmapEditorPlugin::make_visible(bool p_visible) {
+void LightmapGIEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
bake->show();
} else {
@@ -94,9 +94,9 @@ void BakedLightmapEditorPlugin::make_visible(bool p_visible) {
}
}
-EditorProgress *BakedLightmapEditorPlugin::tmp_progress = nullptr;
+EditorProgress *LightmapGIEditorPlugin::tmp_progress = nullptr;
-bool BakedLightmapEditorPlugin::bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh) {
+bool LightmapGIEditorPlugin::bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh) {
if (!tmp_progress) {
tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), 1000, false));
ERR_FAIL_COND_V(tmp_progress == nullptr, false);
@@ -104,18 +104,18 @@ bool BakedLightmapEditorPlugin::bake_func_step(float p_progress, const String &p
return tmp_progress->step(p_description, p_progress * 1000, p_refresh);
}
-void BakedLightmapEditorPlugin::bake_func_end() {
+void LightmapGIEditorPlugin::bake_func_end() {
if (tmp_progress != nullptr) {
memdelete(tmp_progress);
tmp_progress = nullptr;
}
}
-void BakedLightmapEditorPlugin::_bind_methods() {
- ClassDB::bind_method("_bake", &BakedLightmapEditorPlugin::_bake);
+void LightmapGIEditorPlugin::_bind_methods() {
+ ClassDB::bind_method("_bake", &LightmapGIEditorPlugin::_bake);
}
-BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) {
+LightmapGIEditorPlugin::LightmapGIEditorPlugin(EditorNode *p_node) {
editor = p_node;
bake = memnew(Button);
bake->set_flat(true);
@@ -130,9 +130,9 @@ BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) {
file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->add_filter("*.lmbake ; LightMap Bake");
file_dialog->set_title(TTR("Select lightmap bake file:"));
- file_dialog->connect("file_selected", callable_mp(this, &BakedLightmapEditorPlugin::_bake_select_file));
+ file_dialog->connect("file_selected", callable_mp(this, &LightmapGIEditorPlugin::_bake_select_file));
bake->add_child(file_dialog);
}
-BakedLightmapEditorPlugin::~BakedLightmapEditorPlugin() {
+LightmapGIEditorPlugin::~LightmapGIEditorPlugin() {
}
diff --git a/editor/plugins/baked_lightmap_editor_plugin.h b/editor/plugins/lightmap_gi_editor_plugin.h
index d291c377d9..12d080d6be 100644
--- a/editor/plugins/baked_lightmap_editor_plugin.h
+++ b/editor/plugins/lightmap_gi_editor_plugin.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* baked_lightmap_editor_plugin.h */
+/* lightmap_gi_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -33,13 +33,13 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-#include "scene/3d/baked_lightmap.h"
+#include "scene/3d/lightmap_gi.h"
#include "scene/resources/material.h"
-class BakedLightmapEditorPlugin : public EditorPlugin {
- GDCLASS(BakedLightmapEditorPlugin, EditorPlugin);
+class LightmapGIEditorPlugin : public EditorPlugin {
+ GDCLASS(LightmapGIEditorPlugin, EditorPlugin);
- BakedLightmap *lightmap;
+ LightmapGI *lightmap;
Button *bake;
EditorNode *editor;
@@ -56,14 +56,14 @@ protected:
static void _bind_methods();
public:
- virtual String get_name() const override { return "BakedLightmap"; }
+ virtual String get_name() const override { return "LightmapGI"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- BakedLightmapEditorPlugin(EditorNode *p_node);
- ~BakedLightmapEditorPlugin();
+ LightmapGIEditorPlugin(EditorNode *p_node);
+ ~LightmapGIEditorPlugin();
};
#endif
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index ad99ad7808..81f0ecacf2 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -119,17 +119,17 @@ MaterialEditor::MaterialEditor() {
viewport->set_msaa(Viewport::MSAA_4X);
camera = memnew(Camera3D);
- camera->set_transform(Transform(Basis(), Vector3(0, 0, 3)));
+ camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 3)));
camera->set_perspective(45, 0.1, 10);
camera->make_current();
viewport->add_child(camera);
light1 = memnew(DirectionalLight3D);
- light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
+ light1->set_transform(Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
viewport->add_child(light1);
light2 = memnew(DirectionalLight3D);
- light2->set_transform(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
+ light2->set_transform(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
light2->set_color(Color(0.7, 0.7, 0.7));
viewport->add_child(light2);
@@ -139,7 +139,7 @@ MaterialEditor::MaterialEditor() {
box_instance = memnew(MeshInstance3D);
viewport->add_child(box_instance);
- Transform box_xform;
+ Transform3D box_xform;
box_xform.basis.rotate(Vector3(1, 0, 0), Math::deg2rad(25.0));
box_xform.basis = box_xform.basis * Basis().rotated(Vector3(0, 1, 0), Math::deg2rad(-25.0));
box_xform.basis.scale(Vector3(0.8, 0.8, 0.8));
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index 9d29c31522..8d488dce20 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -65,7 +65,7 @@ void MeshEditor::_notification(int p_what) {
}
void MeshEditor::_update_rotation() {
- Transform t;
+ Transform3D t;
t.basis.rotate(Vector3(0, 1, 0), -rot_y);
t.basis.rotate(Vector3(1, 0, 0), -rot_x);
rotation->set_transform(t);
@@ -85,7 +85,7 @@ void MeshEditor::edit(Ref<Mesh> p_mesh) {
if (m != 0) {
m = 1.0 / m;
m *= 0.5;
- Transform xform;
+ Transform3D xform;
xform.basis.scale(Vector3(m, m, m));
xform.origin = -xform.basis.xform(ofs); //-ofs*m;
//xform.origin.z -= aabb.get_longest_axis_size() * 2;
@@ -117,16 +117,16 @@ MeshEditor::MeshEditor() {
viewport->set_msaa(Viewport::MSAA_2X);
set_stretch(true);
camera = memnew(Camera3D);
- camera->set_transform(Transform(Basis(), Vector3(0, 0, 1.1)));
+ camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1)));
camera->set_perspective(45, 0.1, 10);
viewport->add_child(camera);
light1 = memnew(DirectionalLight3D);
- light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
+ light1->set_transform(Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
viewport->add_child(light1);
light2 = memnew(DirectionalLight3D);
- light2->set_transform(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
+ light2->set_transform(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
light2->set_color(Color(0.7, 0.7, 0.7));
viewport->add_child(light2);
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index 6f1f243444..e64992759d 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -127,7 +127,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
continue;
}
- //Transform shape_transform = sb->shape_owner_get_transform(E->get());
+ //Transform3D shape_transform = sb->shape_owner_get_transform(E->get());
//shape_transform.set_origin(shape_transform.get_origin() - phys_offset);
@@ -147,7 +147,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
p_library->set_item_shapes(id, collisions);
Ref<NavigationMesh> navmesh;
- Transform navmesh_transform;
+ Transform3D navmesh_transform;
for (int j = 0; j < mi->get_child_count(); j++) {
Node *child2 = mi->get_child(j);
if (!Object::cast_to<NavigationRegion3D>(child2)) {
@@ -170,7 +170,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
if (true) {
Vector<Ref<Mesh>> meshes;
- Vector<Transform> transforms;
+ Vector<Transform3D> transforms;
Vector<int> ids = p_library->get_item_list();
for (int i = 0; i < ids.size(); i++) {
if (mesh_instances.find(ids[i])) {
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index 19c6dcf402..48b885930f 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -111,7 +111,7 @@ void MultiMeshEditor::_populate() {
return;
}
- Transform geom_xform = node->get_global_transform().affine_inverse() * ss_instance->get_global_transform();
+ Transform3D geom_xform = node->get_global_transform().affine_inverse() * ss_instance->get_global_transform();
Vector<Face3> geometry = ss_instance->get_faces(VisualInstance3D::FACES_SOLID);
@@ -167,7 +167,7 @@ void MultiMeshEditor::_populate() {
float _scale = populate_scale->get_value();
int axis = populate_axis->get_selected();
- Transform axis_xform;
+ Transform3D axis_xform;
if (axis == Vector3::AXIS_Z) {
axis_xform.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
}
@@ -191,7 +191,7 @@ void MultiMeshEditor::_populate() {
Vector3 normal = face.get_plane().normal;
Vector3 op_axis = (face.vertex[0] - face.vertex[1]).normalized();
- Transform xform;
+ Transform3D xform;
xform.set_look_at(pos, pos + op_axis, normal);
xform = xform * axis_xform;
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 13c7814dac..60cc0a0a2a 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -85,10 +85,10 @@ void ViewportRotationControl::_notification(int p_what) {
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_REAR);
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_menu_options.push_back(Node3DEditorViewport::VIEW_FRONT);
axis_colors.clear();
axis_colors.push_back(get_theme_color("axis_x_color", "Editor"));
@@ -309,7 +309,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
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);
+ manipulated |= Input::get_singleton()->is_key_pressed(KEY_CTRL);
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);
@@ -344,7 +344,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
equal = false;
}
- if (!equal || p_interp_delta == 0 || is_freelook_active() || is_orthogonal != orthogonal) {
+ if (!equal || p_interp_delta == 0 || is_orthogonal != orthogonal) {
camera->set_global_transform(to_camera_transform(camera_cursor));
if (orthogonal) {
@@ -361,8 +361,8 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) {
}
}
-Transform Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) const {
- Transform camera_transform;
+Transform3D Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) const {
+ Transform3D 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);
@@ -410,7 +410,7 @@ float Node3DEditorViewport::get_fov() const {
return CLAMP(spatial_editor->get_fov(), MIN_FOV, MAX_FOV);
}
-Transform Node3DEditorViewport::_get_camera_transform() const {
+Transform3D Node3DEditorViewport::_get_camera_transform() const {
return camera->get_global_transform();
}
@@ -631,7 +631,7 @@ Vector3 Node3DEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) {
}
Vector2 screen_he = cm.get_viewport_half_extents();
- Transform camera_transform;
+ Transform3D 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);
@@ -794,22 +794,22 @@ static int _get_key_modifier_setting(const String &p_property) {
case 3:
return KEY_META;
case 4:
- return KEY_CONTROL;
+ return KEY_CTRL;
}
return 0;
}
static int _get_key_modifier(Ref<InputEventWithModifiers> e) {
- if (e->get_shift()) {
+ if (e->is_shift_pressed()) {
return KEY_SHIFT;
}
- if (e->get_alt()) {
+ if (e->is_alt_pressed()) {
return KEY_ALT;
}
- if (e->get_control()) {
- return KEY_CONTROL;
+ if (e->is_ctrl_pressed()) {
+ return KEY_CTRL;
}
- if (e->get_metakey()) {
+ if (e->is_meta_pressed()) {
return KEY_META;
}
return 0;
@@ -829,7 +829,7 @@ bool Node3DEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_high
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();
+ Transform3D 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) {
@@ -1024,7 +1024,7 @@ bool Node3DEditorViewport ::_is_node_locked(const Node *p_node) {
}
void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
- _find_items_at_pos(b->get_position(), clicked_includes_current, selection_results, b->get_shift());
+ _find_items_at_pos(b->get_position(), clicked_includes_current, selection_results, b->is_shift_pressed());
Node *scene = editor->get_edited_scene();
@@ -1037,7 +1037,7 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
}
}
- clicked_wants_append = b->get_shift();
+ clicked_wants_append = b->is_shift_pressed();
if (selection_results.size() == 1) {
clicked = selection_results[0].item->get_instance_id();
@@ -1149,7 +1149,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
if (_edit.mode == TRANSFORM_NONE && b->is_pressed()) {
- if (b->get_alt()) {
+ if (b->is_alt_pressed()) {
if (nav_scheme == NAVIGATION_MAYA) {
break;
}
@@ -1234,7 +1234,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
case MOUSE_BUTTON_LEFT: {
if (b->is_pressed()) {
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
- if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b->get_alt()) {
+ if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b->is_alt_pressed()) {
break;
}
@@ -1244,6 +1244,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
_edit.mouse_pos = b->get_position();
+ _edit.original_mouse_pos = b->get_position();
_edit.snap = spatial_editor->is_snap_enabled();
_edit.mode = TRANSFORM_NONE;
@@ -1262,7 +1263,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
int handle = -1;
Vector3 point;
Vector3 normal;
- bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, b->get_shift());
+ bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, b->is_shift_pressed());
if (inters && handle != -1) {
_edit.gizmo = seg;
_edit.gizmo_handle = handle;
@@ -1279,7 +1280,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
clicked = ObjectID();
clicked_includes_current = false;
- if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->get_command()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
+ if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->is_command_pressed()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
/* HANDLE ROTATION */
if (get_selected_count() == 0) {
break; //bye
@@ -1314,11 +1315,11 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
int gizmo_handle = -1;
- clicked = _select_ray(b->get_position(), b->get_shift(), clicked_includes_current, &gizmo_handle, b->get_shift());
+ clicked = _select_ray(b->get_position(), b->is_shift_pressed(), clicked_includes_current, &gizmo_handle, b->is_shift_pressed());
//clicking is always deferred to either move or release
- clicked_wants_append = b->get_shift();
+ clicked_wants_append = b->is_shift_pressed();
if (clicked.is_null()) {
if (!clicked_wants_append) {
@@ -1441,16 +1442,17 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
set_message(n + ": " + String(v));
} else if (m->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
- if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
+ if (nav_scheme == NAVIGATION_MAYA && m->is_alt_pressed()) {
nav_mode = NAVIGATION_ORBIT;
- } else if (nav_scheme == NAVIGATION_MODO && m->get_alt() && m->get_shift()) {
+ } else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed() && m->is_shift_pressed()) {
nav_mode = NAVIGATION_PAN;
- } else if (nav_scheme == NAVIGATION_MODO && m->get_alt() && m->get_control()) {
+ } else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed() && m->is_ctrl_pressed()) {
nav_mode = NAVIGATION_ZOOM;
- } else if (nav_scheme == NAVIGATION_MODO && m->get_alt()) {
+ } else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed()) {
nav_mode = NAVIGATION_ORBIT;
} else {
- if (clicked.is_valid()) {
+ bool movement_threshold_passed = _edit.original_mouse_pos.distance_to(_edit.mouse_pos) > 10 * EDSCALE;
+ if (clicked.is_valid() && movement_threshold_passed) {
if (!clicked_includes_current) {
_select_clicked(clicked_wants_append, true);
// Processing was deferred.
@@ -1579,10 +1581,10 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
continue;
}
- Transform original = se->original;
- Transform original_local = se->original_local;
- Transform base = Transform(Basis(), _edit.center);
- Transform t;
+ Transform3D original = se->original;
+ Transform3D original_local = se->original_local;
+ Transform3D base = Transform3D(Basis(), _edit.center);
+ Transform3D t;
Vector3 local_scale;
if (local_coords) {
@@ -1608,7 +1610,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
motion.snap(Vector3(snap, snap, snap));
}
- Transform r;
+ Transform3D r;
r.basis.scale(motion + Vector3(1, 1, 1));
t = base * (r * (base.inverse() * original));
@@ -1701,8 +1703,8 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
continue;
}
- Transform original = se->original;
- Transform t;
+ Transform3D original = se->original;
+ Transform3D t;
if (local_coords) {
if (_edit.snap || spatial_editor->is_snap_enabled()) {
@@ -1797,10 +1799,10 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
continue;
}
- Transform t;
+ Transform3D t;
if (local_coords) {
- Transform original_local = se->original_local;
+ Transform3D original_local = se->original_local;
Basis rot = Basis(axis, angle);
t.basis = original_local.get_basis().orthonormalized() * rot;
@@ -1811,9 +1813,9 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
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);
+ Transform3D original = se->original;
+ Transform3D r;
+ Transform3D base = Transform3D(Basis(), _edit.center);
r.basis.rotate(plane.normal, angle);
t = base * r * base.inverse() * original;
@@ -1831,7 +1833,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
} else if ((m->get_button_mask() & MOUSE_BUTTON_MASK_RIGHT) || freelook_active) {
- if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
+ if (nav_scheme == NAVIGATION_MAYA && m->is_alt_pressed()) {
nav_mode = NAVIGATION_ZOOM;
} else if (freelook_active) {
nav_mode = NAVIGATION_LOOK;
@@ -1924,7 +1926,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
} else if (nav_scheme == NAVIGATION_MAYA) {
- if (pan_gesture->get_alt()) {
+ if (pan_gesture->is_alt_pressed()) {
nav_mode = NAVIGATION_PAN;
}
}
@@ -2053,11 +2055,11 @@ void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const
real_t pan_speed = 1 / 150.0;
int pan_speed_modifier = 10;
- if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift()) {
+ if (nav_scheme == NAVIGATION_MAYA && p_event->is_shift_pressed()) {
pan_speed *= pan_speed_modifier;
}
- Transform camera_transform;
+ Transform3D camera_transform;
camera_transform.translate(cursor.pos);
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
@@ -2078,7 +2080,7 @@ void Node3DEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const
real_t zoom_speed = 1 / 80.0;
int zoom_speed_modifier = 10;
- if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift()) {
+ if (nav_scheme == NAVIGATION_MAYA && p_event->is_shift_pressed()) {
zoom_speed *= zoom_speed_modifier;
}
@@ -2145,7 +2147,7 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const
const 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".
- const Transform prev_camera_transform = to_camera_transform(cursor);
+ const Transform3D prev_camera_transform = to_camera_transform(cursor);
if (invert_y_axis) {
cursor.x_rot -= p_relative.y * radians_per_pixel;
@@ -2158,7 +2160,7 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const
cursor.y_rot += p_relative.x * radians_per_pixel;
// Look is like the opposite of Orbit: the focus point rotates around the camera
- Transform camera_transform = to_camera_transform(cursor);
+ Transform3D 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;
@@ -2368,6 +2370,9 @@ void Node3DEditorViewport::_project_settings_changed() {
viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
const bool use_debanding = GLOBAL_GET("rendering/anti_aliasing/quality/use_debanding");
viewport->set_use_debanding(use_debanding);
+
+ const bool use_occlusion_culling = GLOBAL_GET("rendering/occlusion_culling/use_occlusion_culling");
+ viewport->set_use_occlusion_culling(use_occlusion_culling);
}
void Node3DEditorViewport::_notification(int p_what) {
@@ -2441,7 +2446,7 @@ void Node3DEditorViewport::_notification(int p_what) {
continue;
}
- Transform t = sp->get_global_gizmo_transform();
+ Transform3D t = sp->get_global_gizmo_transform();
VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(sp);
AABB new_aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp);
@@ -2497,9 +2502,9 @@ void Node3DEditorViewport::_notification(int p_what) {
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 += "X: " + rtos(current_camera->get_position().x).pad_decimals(1) + "\n";
+ text += "Y: " + rtos(current_camera->get_position().y).pad_decimals(1) + "\n";
+ text += "Z: " + rtos(current_camera->get_position().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";
@@ -2875,7 +2880,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
break;
}
- Transform camera_transform = camera->get_global_transform();
+ Transform3D camera_transform = camera->get_global_transform();
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -2892,7 +2897,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
continue;
}
- Transform xform;
+ Transform3D xform;
if (orthogonal) {
xform = sp->get_global_transform();
xform.basis.set_euler(camera_transform.basis.get_euler());
@@ -2912,7 +2917,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
break;
}
- Transform camera_transform = camera->get_global_transform();
+ Transform3D camera_transform = camera->get_global_transform();
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -3057,9 +3062,9 @@ void Node3DEditorViewport::_menu_option(int p_option) {
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_VOXEL_GI_ALBEDO:
+ case VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING:
+ case VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION:
case VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE:
case VIEW_DISPLAY_DEBUG_SSAO:
case VIEW_DISPLAY_DEBUG_PSSM_SPLITS:
@@ -3071,7 +3076,8 @@ void Node3DEditorViewport::_menu_option(int p_option) {
case VIEW_DISPLAY_DEBUG_CLUSTER_OMNI_LIGHTS:
case VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS:
case VIEW_DISPLAY_DEBUG_CLUSTER_DECALS:
- case VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES: {
+ case VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES:
+ case VIEW_DISPLAY_DEBUG_OCCLUDERS: {
static const int display_options[] = {
VIEW_DISPLAY_NORMAL,
VIEW_DISPLAY_WIREFRAME,
@@ -3082,9 +3088,9 @@ void Node3DEditorViewport::_menu_option(int p_option) {
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_VOXEL_GI_ALBEDO,
+ VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING,
+ VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION,
VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
VIEW_DISPLAY_DEBUG_SSAO,
VIEW_DISPLAY_DEBUG_GI_BUFFER,
@@ -3097,6 +3103,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS,
VIEW_DISPLAY_DEBUG_CLUSTER_DECALS,
VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES,
+ VIEW_DISPLAY_DEBUG_OCCLUDERS,
VIEW_MAX
};
static const Viewport::DebugDraw debug_draw_modes[] = {
@@ -3109,9 +3116,9 @@ void Node3DEditorViewport::_menu_option(int p_option) {
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_VOXEL_GI_ALBEDO,
+ Viewport::DEBUG_DRAW_VOXEL_GI_LIGHTING,
+ Viewport::DEBUG_DRAW_VOXEL_GI_EMISSION,
Viewport::DEBUG_DRAW_SCENE_LUMINANCE,
Viewport::DEBUG_DRAW_SSAO,
Viewport::DEBUG_DRAW_GI_BUFFER,
@@ -3124,6 +3131,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
Viewport::DEBUG_DRAW_CLUSTER_SPOT_LIGHTS,
Viewport::DEBUG_DRAW_CLUSTER_DECALS,
Viewport::DEBUG_DRAW_CLUSTER_REFLECTION_PROBES,
+ Viewport::DEBUG_DRAW_OCCLUDERS,
};
int idx = 0;
@@ -3173,6 +3181,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(move_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(move_gizmo_instance[i], layer);
+ RS::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
move_plane_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(move_plane_gizmo_instance[i], spatial_editor->get_move_plane_gizmo(i)->get_rid());
@@ -3180,6 +3189,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_plane_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(move_plane_gizmo_instance[i], layer);
+ RS::get_singleton()->instance_geometry_set_flag(move_plane_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
rotate_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid());
@@ -3187,6 +3197,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer);
+ RS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
scale_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(scale_gizmo_instance[i], spatial_editor->get_scale_gizmo(i)->get_rid());
@@ -3194,6 +3205,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer);
+ RS::get_singleton()->instance_geometry_set_flag(scale_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
scale_plane_gizmo_instance[i] = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(scale_plane_gizmo_instance[i], spatial_editor->get_scale_plane_gizmo(i)->get_rid());
@@ -3201,6 +3213,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer);
+ RS::get_singleton()->instance_geometry_set_flag(scale_plane_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
}
// Rotation white outline
@@ -3210,6 +3223,7 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false);
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[3], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[3], layer);
+ RS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[3], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
}
void Node3DEditorViewport::_finish_gizmo_instances() {
@@ -3303,9 +3317,9 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
return;
}
- Transform xform = spatial_editor->get_gizmo_transform();
+ Transform3D xform = spatial_editor->get_gizmo_transform();
- Transform camera_xform = camera->get_transform();
+ Transform3D camera_xform = camera->get_transform();
if (xform.origin.distance_squared_to(camera_xform.origin) < 0.01) {
for (int i = 0; i < 3; i++) {
@@ -3539,8 +3553,8 @@ Dictionary Node3DEditorViewport::get_state() const {
void Node3DEditorViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &Node3DEditorViewport::update_transform_gizmo_view); // Used by call_deferred.
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Node3DEditorViewport::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &Node3DEditorViewport::drop_data_fw);
+ 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")));
@@ -3788,7 +3802,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
Node3D *node3d = Object::cast_to<Node3D>(instanced_scene);
if (node3d) {
- Transform global_transform;
+ Transform3D global_transform;
Node3D *parent_node3d = Object::cast_to<Node3D>(parent);
if (parent_node3d) {
global_transform = parent_node3d->get_global_gizmo_transform();
@@ -3888,7 +3902,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
}
if (can_instance) {
- Transform global_transform = Transform(Basis(), _get_instance_position(p_point));
+ Transform3D global_transform = Transform3D(Basis(), _get_instance_position(p_point));
preview_node->set_global_transform(global_transform);
}
@@ -4024,9 +4038,9 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
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_radio_check_item(TTR("VoxelGI Lighting"), VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING);
+ display_submenu->add_radio_check_item(TTR("VoxelGI Albedo"), VIEW_DISPLAY_DEBUG_VOXEL_GI_ALBEDO);
+ display_submenu->add_radio_check_item(TTR("VoxelGI Emission"), VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION);
display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("SDFGI Cascades"), VIEW_DISPLAY_DEBUG_SDFGI);
display_submenu->add_radio_check_item(TTR("SDFGI Probes"), VIEW_DISPLAY_DEBUG_SDFGI_PROBES);
@@ -4043,6 +4057,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
display_submenu->add_radio_check_item(TTR("Spot Light Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS);
display_submenu->add_radio_check_item(TTR("Decal Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_DECALS);
display_submenu->add_radio_check_item(TTR("Reflection Probe Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES);
+ display_submenu->add_radio_check_item(TTR("Occlusion Culling Buffer"), VIEW_DISPLAY_DEBUG_OCCLUDERS);
display_submenu->set_name("display_advanced");
view_menu->get_popup()->add_submenu_item(TTR("Display Advanced..."), "display_advanced", VIEW_DISPLAY_ADVANCED);
@@ -4561,7 +4576,7 @@ void Node3DEditor::update_transform_gizmo() {
continue;
}
- Transform xf = se->sp->get_global_gizmo_transform();
+ Transform3D xf = se->sp->get_global_gizmo_transform();
if (first) {
center.position = xf.origin;
@@ -4625,6 +4640,7 @@ Object *Node3DEditor::_get_editor_data(Object *p_what) {
si->sbox_instance,
RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(si->sbox_instance, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
+ RS::get_singleton()->instance_geometry_set_flag(si->sbox_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
si->sbox_instance_xray = RenderingServer::get_singleton()->instance_create2(
selection_box_xray->get_rid(),
sp->get_world_3d()->get_scenario());
@@ -4632,6 +4648,7 @@ Object *Node3DEditor::_get_editor_data(Object *p_what) {
si->sbox_instance_xray,
RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(si->sbox_instance_xray, 1 << Node3DEditorViewport::MISC_TOOL_LAYER);
+ RS::get_singleton()->instance_geometry_set_flag(si->sbox_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
return si;
}
@@ -4940,7 +4957,7 @@ void Node3DEditor::_snap_update() {
}
void Node3DEditor::_xform_dialog_action() {
- Transform t;
+ Transform3D t;
//translation
Vector3 scale;
Vector3 rotate;
@@ -4973,7 +4990,7 @@ void Node3DEditor::_xform_dialog_action() {
bool post = xform_type->get_selected() > 0;
- Transform tr = sp->get_global_gizmo_transform();
+ Transform3D tr = sp->get_global_gizmo_transform();
if (post) {
tr = tr * t;
} else {
@@ -5041,11 +5058,11 @@ void Node3DEditor::_update_camera_override_button(bool p_game_running) {
if (p_game_running) {
button->set_disabled(false);
- button->set_tooltip(TTR("Game Camera Override\nNo game instance running."));
+ button->set_tooltip(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
} else {
button->set_disabled(true);
button->set_pressed(false);
- button->set_tooltip(TTR("Game Camera Override\nOverrides game camera with editor viewport camera."));
+ button->set_tooltip(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
}
}
@@ -5403,6 +5420,7 @@ void Node3DEditor::_init_indicators() {
origin_instance = RenderingServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
+ RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, RS::SHADOW_CASTING_SETTING_OFF);
}
@@ -5818,7 +5836,7 @@ void Node3DEditor::_init_grid() {
return;
}
Camera3D *camera = get_editor_viewport(0)->camera;
- Vector3 camera_position = camera->get_translation();
+ Vector3 camera_position = camera->get_position();
if (camera_position == Vector3()) {
return; // Camera3D is invalid, don't draw the grid.
}
@@ -5964,6 +5982,7 @@ void Node3DEditor::_init_grid() {
RenderingServer::get_singleton()->instance_set_visible(grid_instance[c], grid_visible[a]);
RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[c], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(grid_instance[c], 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
+ RS::get_singleton()->instance_geometry_set_flag(grid_instance[c], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
}
}
@@ -6163,7 +6182,7 @@ void Node3DEditor::snap_selected_nodes_to_floor() {
if (ss->intersect_ray(from, to, result, excluded)) {
Vector3 position_offset = d["position_offset"];
- Transform new_transform = sp->get_global_transform();
+ Transform3D new_transform = sp->get_global_transform();
new_transform.origin.y = result.position.y;
new_transform.origin = new_transform.origin - position_offset;
@@ -6187,7 +6206,7 @@ void Node3DEditor::_unhandled_key_input(Ref<InputEvent> p_event) {
return;
}
- snap_key_enabled = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ snap_key_enabled = Input::get_singleton()->is_key_pressed(KEY_CTRL);
}
void Node3DEditor::_sun_environ_settings_pressed() {
@@ -6465,6 +6484,7 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<Light3DGizmoPlugin>(memnew(Light3DGizmoPlugin)));
add_gizmo_plugin(Ref<AudioStreamPlayer3DGizmoPlugin>(memnew(AudioStreamPlayer3DGizmoPlugin)));
add_gizmo_plugin(Ref<MeshInstance3DGizmoPlugin>(memnew(MeshInstance3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<OccluderInstance3DGizmoPlugin>(memnew(OccluderInstance3DGizmoPlugin)));
add_gizmo_plugin(Ref<SoftBody3DGizmoPlugin>(memnew(SoftBody3DGizmoPlugin)));
add_gizmo_plugin(Ref<Sprite3DGizmoPlugin>(memnew(Sprite3DGizmoPlugin)));
add_gizmo_plugin(Ref<Skeleton3DGizmoPlugin>(memnew(Skeleton3DGizmoPlugin)));
@@ -6478,8 +6498,8 @@ void Node3DEditor::_register_all_gizmos() {
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<BakedLightmapGizmoPlugin>(memnew(BakedLightmapGizmoPlugin)));
+ add_gizmo_plugin(Ref<VoxelGIGizmoPlugin>(memnew(VoxelGIGizmoPlugin)));
+ add_gizmo_plugin(Ref<LightmapGIGizmoPlugin>(memnew(LightmapGIGizmoPlugin)));
add_gizmo_plugin(Ref<LightmapProbeGizmoPlugin>(memnew(LightmapProbeGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionObject3DGizmoPlugin>(memnew(CollisionObject3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionShape3DGizmoPlugin>(memnew(CollisionShape3DGizmoPlugin)));
@@ -6538,7 +6558,7 @@ void Node3DEditor::_preview_settings_changed() {
}
{ // preview sun
- Transform t;
+ Transform3D t;
t.basis = sun_rotation;
preview_sun->set_transform(t);
sun_direction->update();
@@ -6674,6 +6694,13 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
button_binds.resize(1);
String sct;
+ // Add some margin to the left for better aesthetics.
+ // This prevents the first button's hover/pressed effect from "touching" the panel's border,
+ // which looks ugly.
+ Control *margin_left = memnew(Control);
+ hbc_menu->add_child(margin_left);
+ margin_left->set_custom_minimum_size(Size2(2, 0) * EDSCALE);
+
tool_button[TOOL_MODE_SELECT] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_MODE_SELECT]);
tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true);
@@ -7218,10 +7245,6 @@ 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);
@@ -7264,14 +7287,6 @@ float Node3DEditor::get_scale_snap() const {
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()) {
@@ -7340,6 +7355,7 @@ void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color
material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
+ material->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
if (p_use_vertex_color) {
material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
@@ -7449,15 +7465,15 @@ Ref<StandardMaterial3D> EditorNode3DGizmoPlugin::get_material(const String &p_na
}
String EditorNode3DGizmoPlugin::get_gizmo_name() const {
- if (get_script_instance() && get_script_instance()->has_method("get_gizmo_name")) {
- return get_script_instance()->call("get_gizmo_name");
+ if (get_script_instance() && get_script_instance()->has_method("_get_gizmo_name")) {
+ return get_script_instance()->call("_get_gizmo_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");
+ if (get_script_instance() && get_script_instance()->has_method("_get_priority")) {
+ return get_script_instance()->call("_get_priority");
}
return 0;
}
@@ -7484,8 +7500,8 @@ Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::get_gizmo(Node3D *p_spatial) {
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")));
+ 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)));
@@ -7494,38 +7510,38 @@ void EditorNode3DGizmoPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorNode3DGizmoPlugin::get_material, DEFVAL(Ref<EditorNode3DGizmo>()));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "get_gizmo_name"));
- BIND_VMETHOD(MethodInfo(Variant::INT, "get_priority"));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_be_hidden"));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_selectable_when_hidden"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_gizmo_name"));
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_get_priority"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_can_be_hidden"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_selectable_when_hidden"));
- BIND_VMETHOD(MethodInfo("redraw", GIZMO_REF));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", GIZMO_REF, PropertyInfo(Variant::INT, "index")));
+ 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"));
+ 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"));
+ 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")));
+ 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);
+ 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);
+ if (get_script_instance() && get_script_instance()->has_method("_create_gizmo")) {
+ return get_script_instance()->call("_create_gizmo", p_spatial);
}
Ref<EditorNode3DGizmo> ref;
@@ -7536,55 +7552,55 @@ Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::create_gizmo(Node3D *p_spatial)
}
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");
+ 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");
+ 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")) {
+ if (get_script_instance() && get_script_instance()->has_method("_redraw")) {
Ref<EditorNode3DGizmo> ref(p_gizmo);
- get_script_instance()->call("redraw", ref);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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;
}
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 70329f90c7..20a0c501df 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -206,9 +206,9 @@ class Node3DEditorViewport : public Control {
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_VOXEL_GI_ALBEDO,
+ VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING,
+ VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION,
VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
VIEW_DISPLAY_DEBUG_SSAO,
VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
@@ -221,6 +221,7 @@ class Node3DEditorViewport : public Control {
VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS,
VIEW_DISPLAY_DEBUG_CLUSTER_DECALS,
VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES,
+ VIEW_DISPLAY_DEBUG_OCCLUDERS,
VIEW_LOCK_ROTATION,
VIEW_CINEMATIC_PREVIEW,
@@ -321,7 +322,7 @@ private:
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;
+ Transform3D _get_camera_transform() const;
int get_selected_count() const;
Vector3 _get_camera_position() const;
@@ -379,13 +380,14 @@ private:
struct EditData {
TransformMode mode;
TransformPlane plane;
- Transform original;
+ Transform3D original;
Vector3 click_ray;
Vector3 click_ray_pos;
Vector3 center;
Vector3 orig_gizmo_pos;
int edited_gizmo = 0;
Point2 mouse_pos;
+ Point2 original_mouse_pos;
bool snap = false;
Ref<EditorNode3DGizmo> gizmo;
int gizmo_handle = 0;
@@ -431,7 +433,7 @@ private:
//
void _update_camera(float p_interp_delta);
- Transform to_camera_transform(const Cursor &p_cursor) const;
+ Transform3D to_camera_transform(const Cursor &p_cursor) const;
void _draw();
void _surface_mouse_enter();
@@ -504,9 +506,9 @@ class Node3DEditorSelectedItem : public Object {
public:
AABB aabb;
- Transform original; // original location when moving
- Transform original_local;
- Transform last_xform; // last transform
+ Transform3D original; // original location when moving
+ Transform3D original_local;
+ Transform3D last_xform; // last transform
bool last_xform_dirty;
Node3D *sp;
RID sbox_instance;
@@ -640,7 +642,7 @@ private:
struct Gizmo {
bool visible = false;
float scale = 0;
- Transform transform;
+ Transform3D transform;
} gizmo;
enum MenuOption {
@@ -815,7 +817,6 @@ protected:
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;
@@ -823,7 +824,7 @@ public:
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; }
+ Transform3D get_gizmo_transform() const { return gizmo.transform; }
bool is_gizmo_visible() const { return gizmo.visible; }
ToolMode get_tool_mode() const { return tool_mode; }
@@ -888,12 +889,7 @@ class Node3DEditorPlugin : public 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 override { return "3D"; }
bool has_main_screen() const override { return true; }
diff --git a/editor/plugins/occluder_instance_3d_editor_plugin.cpp b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..0821f140b3
--- /dev/null
+++ b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
@@ -0,0 +1,117 @@
+/*************************************************************************/
+/* occluder_instance_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "occluder_instance_3d_editor_plugin.h"
+
+void OccluderInstance3DEditorPlugin::_bake_select_file(const String &p_file) {
+ if (occluder_instance) {
+ OccluderInstance3D::BakeError err;
+ if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == occluder_instance) {
+ err = occluder_instance->bake(occluder_instance, p_file);
+ } else {
+ err = occluder_instance->bake(occluder_instance->get_parent(), p_file);
+ }
+
+ switch (err) {
+ case OccluderInstance3D::BAKE_ERROR_NO_SAVE_PATH: {
+ String scene_path = occluder_instance->get_filename();
+ if (scene_path == String()) {
+ scene_path = occluder_instance->get_owner()->get_filename();
+ }
+ if (scene_path == String()) {
+ EditorNode::get_singleton()->show_warning(TTR("Can't determine a save path for the occluder.\nSave your scene and try again."));
+ break;
+ }
+ scene_path = scene_path.get_basename() + ".occ";
+
+ file_dialog->set_current_path(scene_path);
+ file_dialog->popup_file_dialog();
+
+ } break;
+ case OccluderInstance3D::BAKE_ERROR_NO_MESHES: {
+ EditorNode::get_singleton()->show_warning(TTR("No meshes to bake."));
+ break;
+ }
+ default: {
+ }
+ }
+ }
+}
+
+void OccluderInstance3DEditorPlugin::_bake() {
+ _bake_select_file("");
+}
+
+void OccluderInstance3DEditorPlugin::edit(Object *p_object) {
+ OccluderInstance3D *s = Object::cast_to<OccluderInstance3D>(p_object);
+ if (!s) {
+ return;
+ }
+
+ occluder_instance = s;
+}
+
+bool OccluderInstance3DEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("OccluderInstance3D");
+}
+
+void OccluderInstance3DEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ bake->show();
+ } else {
+ bake->hide();
+ }
+}
+
+void OccluderInstance3DEditorPlugin::_bind_methods() {
+ ClassDB::bind_method("_bake", &OccluderInstance3DEditorPlugin::_bake);
+}
+
+OccluderInstance3DEditorPlugin::OccluderInstance3DEditorPlugin(EditorNode *p_node) {
+ editor = p_node;
+ bake = memnew(Button);
+ bake->set_flat(true);
+ bake->set_icon(editor->get_gui_base()->get_theme_icon("Bake", "EditorIcons"));
+ bake->set_text(TTR("Bake Occluders"));
+ bake->hide();
+ bake->connect("pressed", Callable(this, "_bake"));
+ add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake);
+ occluder_instance = nullptr;
+
+ file_dialog = memnew(EditorFileDialog);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
+ file_dialog->add_filter("*.occ ; Occluder3D");
+ file_dialog->set_title(TTR("Select occluder bake file:"));
+ file_dialog->connect("file_selected", callable_mp(this, &OccluderInstance3DEditorPlugin::_bake_select_file));
+ bake->add_child(file_dialog);
+}
+
+OccluderInstance3DEditorPlugin::~OccluderInstance3DEditorPlugin() {
+}
diff --git a/editor/plugins/occluder_instance_3d_editor_plugin.h b/editor/plugins/occluder_instance_3d_editor_plugin.h
new file mode 100644
index 0000000000..161b17811c
--- /dev/null
+++ b/editor/plugins/occluder_instance_3d_editor_plugin.h
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* occluder_instance_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OCCLUDER_INSTANCE_3D_EDITOR_PLUGIN_H
+#define OCCLUDER_INSTANCE_3D_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/3d/occluder_instance_3d.h"
+#include "scene/resources/material.h"
+
+class OccluderInstance3DEditorPlugin : public EditorPlugin {
+ GDCLASS(OccluderInstance3DEditorPlugin, EditorPlugin);
+
+ OccluderInstance3D *occluder_instance;
+
+ Button *bake;
+ EditorNode *editor;
+
+ EditorFileDialog *file_dialog;
+
+ void _bake_select_file(const String &p_file);
+ void _bake();
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_name() const override { return "OccluderInstance3D"; }
+ bool has_main_screen() const override { return false; }
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
+ virtual void make_visible(bool p_visible) override;
+
+ OccluderInstance3DEditorPlugin(EditorNode *p_node);
+ ~OccluderInstance3DEditorPlugin();
+};
+
+#endif
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 84b4516452..838e67b5e7 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -31,7 +31,7 @@
#include "path_2d_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -89,7 +89,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
// Check for point movement start (for point + in/out controls).
if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (mode == MODE_EDIT && !mb->get_shift() && dist_to_p < grab_threshold) {
+ if (mode == MODE_EDIT && !mb->is_shift_pressed() && dist_to_p < grab_threshold) {
// Points can only be moved in edit mode.
action = ACTION_MOVING_POINT;
@@ -149,7 +149,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point creation.
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && ((mb->get_command() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && ((mb->is_command_pressed() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
Ref<Curve2D> curve = node->get_curve();
undo_redo->create_action(TTR("Add Point to Curve"));
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 47bd1114d2..b0eb13c3c6 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -94,8 +94,8 @@ void Path3DGizmo::set_handle(int p_idx, Camera3D *p_camera, const Point2 &p_poin
return;
}
- Transform gt = path->get_global_transform();
- Transform gi = gt.affine_inverse();
+ Transform3D gt = path->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -302,8 +302,8 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
if (c.is_null()) {
return false;
}
- Transform gt = path->get_global_transform();
- Transform it = gt.affine_inverse();
+ Transform3D gt = path->get_global_transform();
+ Transform3D it = gt.affine_inverse();
static const int click_dist = 10; //should make global
@@ -316,7 +316,7 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
set_handle_clicked(false);
}
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->get_control()))) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->is_ctrl_pressed()))) {
//click into curve, break it down
Vector<Vector3> v3a = c->tessellate();
int idx = 0;
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 470d897dcc..8a14db0cfd 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -32,8 +32,8 @@
#include "canvas_item_editor_plugin.h"
#include "core/input/input.h"
+#include "core/io/file_access.h"
#include "core/math/geometry_2d.h"
-#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -613,11 +613,11 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
if (uv_move_current == UV_MODE_EDIT_POINT) {
- if (mb->get_shift() && mb->get_command()) {
+ if (mb->is_shift_pressed() && mb->is_command_pressed()) {
uv_move_current = UV_MODE_SCALE;
- } else if (mb->get_shift()) {
+ } else if (mb->is_shift_pressed()) {
uv_move_current = UV_MODE_MOVE;
- } else if (mb->get_command()) {
+ } else if (mb->is_command_pressed()) {
uv_move_current = UV_MODE_ROTATE;
}
}
@@ -1144,7 +1144,7 @@ void Polygon2DEditor::_uv_draw() {
if (!found_child) {
//draw normally
Transform2D bone_xform = node->get_global_transform().affine_inverse() * (skeleton->get_global_transform() * bone->get_skeleton_rest());
- Transform2D endpoint_xform = bone_xform * Transform2D(0, Vector2(bone->get_default_length(), 0));
+ Transform2D endpoint_xform = bone_xform * Transform2D(0, Vector2(bone->get_length(), 0));
Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5);
uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), Color(0, 0, 0), Math::round((current ? 5 : 4) * EDSCALE));
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index b4b8e82124..b8b2c6d343 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -339,9 +339,9 @@ void ResourcePreloaderEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_library"), &ResourcePreloaderEditor::_update_library);
ClassDB::bind_method(D_METHOD("_remove_resource", "to_remove"), &ResourcePreloaderEditor::_remove_resource);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &ResourcePreloaderEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &ResourcePreloaderEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &ResourcePreloaderEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ResourcePreloaderEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ResourcePreloaderEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ResourcePreloaderEditor::drop_data_fw);
}
ResourcePreloaderEditor::ResourcePreloaderEditor() {
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index 50f4d8493f..1e6237ced1 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -205,7 +205,6 @@ void EditorPropertyRootMotion::update_property() {
assign->set_flat(false);
return;
}
- assign->set_flat(true);
Node *base_node = nullptr;
if (base_hint != NodePath()) {
@@ -247,14 +246,12 @@ EditorPropertyRootMotion::EditorPropertyRootMotion() {
HBoxContainer *hbc = memnew(HBoxContainer);
add_child(hbc);
assign = memnew(Button);
- assign->set_flat(true);
assign->set_h_size_flags(SIZE_EXPAND_FILL);
assign->set_clip_text(true);
assign->connect("pressed", callable_mp(this, &EditorPropertyRootMotion::_node_assign));
hbc->add_child(assign);
clear = memnew(Button);
- clear->set_flat(true);
clear->connect("pressed", callable_mp(this, &EditorPropertyRootMotion::_node_clear));
hbc->add_child(clear);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 58e6717a3d..0410ab3a45 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -32,8 +32,8 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
-#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "editor/debugger/editor_debugger_node.h"
@@ -140,10 +140,15 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Reserved words. */
const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ const Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
List<String> keywords;
script->get_language()->get_reserved_words(&keywords);
for (List<String>::Element *E = keywords.front(); E; E = E->next()) {
- highlighter->add_keyword_color(E->get(), keyword_color);
+ if (script->get_language()->is_control_flow_keyword(E->get())) {
+ highlighter->add_keyword_color(E->get(), control_flow_keyword_color);
+ } else {
+ highlighter->add_keyword_color(E->get(), keyword_color);
+ }
}
/* Member types. */
@@ -213,6 +218,8 @@ Ref<EditorSyntaxHighlighter> EditorPlainTextSyntaxHighlighter::_create() const {
/*** SCRIPT EDITOR ****/
void ScriptEditorBase::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_base_editor"), &ScriptEditorBase::get_base_editor);
+
ADD_SIGNAL(MethodInfo("name_changed"));
ADD_SIGNAL(MethodInfo("edited_script_changed"));
ADD_SIGNAL(MethodInfo("request_help", PropertyInfo(Variant::STRING, "topic")));
@@ -223,7 +230,7 @@ void ScriptEditorBase::_bind_methods() {
ADD_SIGNAL(MethodInfo("search_in_files_requested", PropertyInfo(Variant::STRING, "text")));
ADD_SIGNAL(MethodInfo("replace_in_files_requested", PropertyInfo(Variant::STRING, "text")));
- BIND_VMETHOD(MethodInfo("add_syntax_highlighter", PropertyInfo(Variant::OBJECT, "highlighter")));
+ BIND_VMETHOD(MethodInfo("_add_syntax_highlighter", PropertyInfo(Variant::OBJECT, "highlighter")));
}
static bool _is_built_in_script(Script *p_script) {
@@ -332,13 +339,13 @@ void ScriptEditorQuickOpen::_update_search() {
if ((search_box->get_text() == "" || file.findn(search_box->get_text()) != -1)) {
TreeItem *ti = search_options->create_item(root);
ti->set_text(0, file);
- if (root->get_children() == ti) {
+ if (root->get_first_child() == ti) {
ti->select(0);
}
}
}
- get_ok_button()->set_disabled(root->get_children() == nullptr);
+ get_ok_button()->set_disabled(root->get_first_child() == nullptr);
}
void ScriptEditorQuickOpen::_confirmed() {
@@ -698,7 +705,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
// Do not try to save internal scripts, but prompt to save in-memory
// scripts which are not saved to disk yet (have empty path).
if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) {
- _menu_option(FILE_SAVE);
+ save_current_script();
}
}
if (script.is_valid()) {
@@ -1224,55 +1231,7 @@ void ScriptEditor::_menu_option(int p_option) {
if (current) {
switch (p_option) {
case FILE_SAVE: {
- if (_test_script_times_on_disk()) {
- return;
- }
-
- if (trim_trailing_whitespace_on_save) {
- current->trim_trailing_whitespace();
- }
-
- current->insert_final_newline();
-
- if (convert_indent_on_save) {
- if (use_space_indentation) {
- current->convert_indent_to_spaces();
- } else {
- current->convert_indent_to_tabs();
- }
- }
-
- RES resource = current->get_edited_resource();
- Ref<TextFile> text_file = resource;
- Ref<Script> script = resource;
-
- if (text_file != nullptr) {
- current->apply_code();
- _save_text_file(text_file, text_file->get_path());
- break;
- }
-
- if (script != nullptr) {
- const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
- for (int j = 0; j < documentations.size(); j++) {
- const DocData::ClassDoc &doc = documentations.get(j);
- if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
- EditorHelp::get_doc_data()->remove_doc(doc.name);
- }
- }
- }
-
- editor->save_resource(resource);
-
- if (script != nullptr) {
- const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
- for (int j = 0; j < documentations.size(); j++) {
- const DocData::ClassDoc &doc = documentations.get(j);
- EditorHelp::get_doc_data()->add_doc(doc);
- update_doc(doc.name);
- }
- }
-
+ save_current_script();
} break;
case FILE_SAVE_AS: {
if (trim_trailing_whitespace_on_save) {
@@ -1544,6 +1503,11 @@ void ScriptEditor::_notification(int p_what) {
filename->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("normal", "LineEdit"));
recent_scripts->set_as_minsize();
+
+ if (is_inside_tree()) {
+ _update_script_colors();
+ _update_script_names();
+ }
} break;
case NOTIFICATION_READY: {
@@ -1676,10 +1640,13 @@ void ScriptEditor::ensure_select_current() {
ScriptEditorBase *se = _get_current_editor();
if (se) {
se->enable_editor();
+ se->set_find_replace_bar(find_replace_bar);
if (!grab_focus_block && is_visible_in_tree()) {
se->ensure_focus();
}
+ } else {
+ find_replace_bar->hide();
}
}
@@ -1718,7 +1685,7 @@ struct _ScriptEditorItemData {
if (sort_key == id.sort_key) {
return index < id.index;
} else {
- return sort_key < id.sort_key;
+ return sort_key.naturalnocasecmp_to(id.sort_key) < 0;
}
} else {
return category < id.category;
@@ -1827,7 +1794,6 @@ void ScriptEditor::_update_help_overview() {
void ScriptEditor::_update_script_colors() {
bool script_temperature_enabled = EditorSettings::get_singleton()->get("text_editor/script_list/script_temperature_enabled");
- 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_theme_color("accent_color", "Editor");
@@ -1842,11 +1808,7 @@ void ScriptEditor::_update_script_colors() {
script_list->set_item_custom_bg_color(i, Color(0, 0, 0, 0));
- bool current = tab_container->get_current_tab() == c;
- if (current && highlight_current) {
- script_list->set_item_custom_bg_color(i, EditorSettings::get_singleton()->get("text_editor/script_list/current_script_background_color"));
-
- } else if (script_temperature_enabled) {
+ if (script_temperature_enabled) {
if (!n->has_meta("__editor_pass")) {
continue;
}
@@ -2325,6 +2287,58 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
return true;
}
+void ScriptEditor::save_current_script() {
+ ScriptEditorBase *current = _get_current_editor();
+ if (!current || _test_script_times_on_disk()) {
+ return;
+ }
+
+ if (trim_trailing_whitespace_on_save) {
+ current->trim_trailing_whitespace();
+ }
+
+ current->insert_final_newline();
+
+ if (convert_indent_on_save) {
+ if (use_space_indentation) {
+ current->convert_indent_to_spaces();
+ } else {
+ current->convert_indent_to_tabs();
+ }
+ }
+
+ RES resource = current->get_edited_resource();
+ Ref<TextFile> text_file = resource;
+ Ref<Script> script = resource;
+
+ if (text_file != nullptr) {
+ current->apply_code();
+ _save_text_file(text_file, text_file->get_path());
+ return;
+ }
+
+ if (script != nullptr) {
+ const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
+ for (int j = 0; j < documentations.size(); j++) {
+ const DocData::ClassDoc &doc = documentations.get(j);
+ if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
+ EditorHelp::get_doc_data()->remove_doc(doc.name);
+ }
+ }
+ }
+
+ editor->save_resource(resource);
+
+ if (script != nullptr) {
+ const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
+ for (int j = 0; j < documentations.size(); j++) {
+ const DocData::ClassDoc &doc = documentations.get(j);
+ EditorHelp::get_doc_data()->add_doc(doc);
+ update_doc(doc.name);
+ }
+ }
+}
+
void ScriptEditor::save_all_scripts() {
for (int i = 0; i < tab_container->get_child_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
@@ -2439,6 +2453,11 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const
script_list->select(script_list->find_metadata(i));
+ // Save the current script so the changes can be picked up by an external editor.
+ if (!_is_built_in_script(script.ptr())) { // But only if it's not built-in script.
+ save_current_script();
+ }
+
break;
}
}
@@ -3174,7 +3193,7 @@ void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_numb
if (ResourceLoader::exists(fpath)) {
RES res = ResourceLoader::load(fpath);
- if (fpath.get_extension() == "shader") {
+ if (fpath.get_extension() == "gdshader") {
ShaderEditorPlugin *shader_editor = Object::cast_to<ShaderEditorPlugin>(EditorNode::get_singleton()->get_editor_data().get_editor("Shader"));
shader_editor->edit(res.ptr());
shader_editor->make_visible(true);
@@ -3257,9 +3276,9 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("register_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::register_syntax_highlighter);
ClassDB::bind_method(D_METHOD("unregister_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::unregister_syntax_highlighter);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw", "point", "from"), &ScriptEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw", "point", "data", "from"), &ScriptEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ScriptEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ScriptEditor::drop_data_fw);
ClassDB::bind_method(D_METHOD("goto_line", "line_number"), &ScriptEditor::_goto_script_line2);
ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script);
@@ -3363,11 +3382,19 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
help_overview->set_custom_minimum_size(Size2(0, 60) * EDSCALE); //need to give a bit of limit to avoid it from disappearing
help_overview->set_v_size_flags(SIZE_EXPAND_FILL);
+ VBoxContainer *code_editor_container = memnew(VBoxContainer);
+ script_split->add_child(code_editor_container);
+
tab_container = memnew(TabContainer);
tab_container->set_tabs_visible(false);
tab_container->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
- script_split->add_child(tab_container);
+ code_editor_container->add_child(tab_container);
tab_container->set_h_size_flags(SIZE_EXPAND_FILL);
+ tab_container->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ find_replace_bar = memnew(FindReplaceBar);
+ code_editor_container->add_child(find_replace_bar);
+ find_replace_bar->hide();
ED_SHORTCUT("script_editor/window_sort", TTR("Sort"));
ED_SHORTCUT("script_editor/window_move_up", TTR("Move Up"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_UP);
@@ -3672,9 +3699,7 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
EDITOR_DEF("text_editor/external/use_external_editor", false);
EDITOR_DEF("text_editor/external/exec_path", "");
EDITOR_DEF("text_editor/script_list/script_temperature_enabled", true);
- EDITOR_DEF("text_editor/script_list/highlight_current_script", true);
EDITOR_DEF("text_editor/script_list/script_temperature_history_size", 15);
- EDITOR_DEF("text_editor/script_list/current_script_background_color", Color(1, 1, 1, 0.3));
EDITOR_DEF("text_editor/script_list/group_help_pages", true);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "text_editor/script_list/sort_scripts_by", PROPERTY_HINT_ENUM, "Name,Path,None"));
EDITOR_DEF("text_editor/script_list/sort_scripts_by", 0);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index b2172e7f10..1d379059d4 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -162,6 +162,9 @@ public:
virtual void set_tooltip_request_func(String p_method, Object *p_obj) = 0;
virtual Control *get_edit_menu() = 0;
virtual void clear_edit_menu() = 0;
+ virtual void set_find_replace_bar(FindReplaceBar *p_bar) = 0;
+
+ virtual Control *get_base_editor() const = 0;
virtual void validate() = 0;
@@ -268,6 +271,7 @@ class ScriptEditor : public PanelContainer {
ConfirmationDialog *erase_tab_confirm;
ScriptCreateDialog *script_create_dialog;
Button *scripts_visible;
+ FindReplaceBar *find_replace_bar;
String current_theme;
@@ -463,6 +467,7 @@ public:
void get_breakpoints(List<String> *p_breakpoints);
+ void save_current_script();
void save_all_scripts();
void set_window_layout(Ref<ConfigFile> p_layout);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index c982207224..3ec20ae68e 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -170,66 +170,25 @@ void ScriptTextEditor::_load_theme_settings() {
CodeEdit *text_edit = code_editor->get_text_editor();
text_edit->clear_keywords();
+ Color updated_marked_line_color = EDITOR_GET("text_editor/highlighting/mark_color");
Color updated_safe_line_number_color = EDITOR_GET("text_editor/highlighting/safe_line_number_color");
- if (updated_safe_line_number_color != safe_line_number_color) {
+
+ bool safe_line_number_color_updated = updated_safe_line_number_color != safe_line_number_color;
+ bool marked_line_color_updated = updated_marked_line_color != marked_line_color;
+ if (safe_line_number_color_updated || marked_line_color_updated) {
safe_line_number_color = updated_safe_line_number_color;
for (int i = 0; i < text_edit->get_line_count(); i++) {
- if (text_edit->get_line_gutter_item_color(i, line_number_gutter) != default_line_number_color) {
+ if (marked_line_color_updated && text_edit->get_line_background_color(i) == marked_line_color) {
+ text_edit->set_line_background_color(i, updated_marked_line_color);
+ }
+
+ if (safe_line_number_color_updated && text_edit->get_line_gutter_item_color(i, line_number_gutter) != default_line_number_color) {
text_edit->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color);
}
}
+ marked_line_color = updated_marked_line_color;
}
- Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
- Color completion_background_color = EDITOR_GET("text_editor/highlighting/completion_background_color");
- Color completion_selected_color = EDITOR_GET("text_editor/highlighting/completion_selected_color");
- Color completion_existing_color = EDITOR_GET("text_editor/highlighting/completion_existing_color");
- Color completion_scroll_color = EDITOR_GET("text_editor/highlighting/completion_scroll_color");
- Color completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color");
- Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
- Color line_number_color = EDITOR_GET("text_editor/highlighting/line_number_color");
- Color caret_color = EDITOR_GET("text_editor/highlighting/caret_color");
- Color caret_background_color = EDITOR_GET("text_editor/highlighting/caret_background_color");
- Color text_selected_color = EDITOR_GET("text_editor/highlighting/text_selected_color");
- Color selection_color = EDITOR_GET("text_editor/highlighting/selection_color");
- Color brace_mismatch_color = EDITOR_GET("text_editor/highlighting/brace_mismatch_color");
- Color current_line_color = EDITOR_GET("text_editor/highlighting/current_line_color");
- Color line_length_guideline_color = EDITOR_GET("text_editor/highlighting/line_length_guideline_color");
- Color word_highlighted_color = EDITOR_GET("text_editor/highlighting/word_highlighted_color");
- Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color");
- Color bookmark_color = EDITOR_GET("text_editor/highlighting/bookmark_color");
- Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color");
- Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color");
- Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color");
- Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color");
- Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color");
-
- 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_selected_color", 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("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_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6));
-
theme_loaded = true;
if (!script.is_null()) {
_set_theme_for_script();
@@ -244,6 +203,26 @@ void ScriptTextEditor::_set_theme_for_script() {
CodeEdit *text_edit = code_editor->get_text_editor();
text_edit->get_syntax_highlighter()->update_cache();
+ List<String> strings;
+ script->get_language()->get_string_delimiters(&strings);
+ text_edit->clear_string_delimiters();
+ for (List<String>::Element *E = strings.front(); E; E = E->next()) {
+ String string = E->get();
+ String beg = string.get_slice(" ", 0);
+ String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String();
+ text_edit->add_string_delimiter(beg, end, end == "");
+ }
+
+ List<String> comments;
+ script->get_language()->get_comment_delimiters(&comments);
+ text_edit->clear_comment_delimiters();
+ for (List<String>::Element *E = comments.front(); E; E = E->next()) {
+ String comment = E->get();
+ String beg = comment.get_slice(" ", 0);
+ String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
+ text_edit->add_comment_delimiter(beg, end, end == "");
+ }
+
/* add keywords for auto completion */
// singleton autoloads (as types, just as engine singletons are)
Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
@@ -292,7 +271,7 @@ void ScriptTextEditor::_show_warnings_panel(bool p_show) {
void ScriptTextEditor::_warning_clicked(Variant p_line) {
if (p_line.get_type() == Variant::INT) {
- code_editor->get_text_editor()->cursor_set_line(p_line.operator int64_t());
+ goto_line_centered(p_line.operator int64_t());
} else if (p_line.get_type() == Variant::DICTIONARY) {
Dictionary meta = p_line.operator Dictionary();
code_editor->get_text_editor()->insert_at("# warning-ignore:" + meta["code"].operator String(), meta["line"].operator int64_t() - 1);
@@ -546,7 +525,7 @@ void ScriptTextEditor::_validate_script() {
bool highlight_safe = EDITOR_DEF("text_editor/highlighting/highlight_type_safe_lines", true);
bool last_is_safe = false;
for (int i = 0; i < te->get_line_count(); i++) {
- te->set_line_as_marked(i, line == i);
+ te->set_line_background_color(i, (line == i) ? marked_line_color : Color(0, 0, 0, 0));
if (highlight_safe) {
if (safe_lines.has(i + 1)) {
te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color);
@@ -1082,7 +1061,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
code_editor->clone_lines_down();
} break;
case EDIT_TOGGLE_FOLD_LINE: {
- tx->toggle_fold_line(tx->cursor_get_line());
+ tx->toggle_foldable_line(tx->cursor_get_line());
tx->update();
} break;
case EDIT_FOLD_ALL_LINES: {
@@ -1097,7 +1076,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
_edit_option_toggle_inline_comment();
} break;
case EDIT_COMPLETE: {
- tx->query_code_comple();
+ tx->request_code_completion(true);
} break;
case EDIT_AUTO_INDENT: {
String text = tx->get_text();
@@ -1364,9 +1343,9 @@ void ScriptTextEditor::_notification(int p_what) {
void ScriptTextEditor::_bind_methods() {
ClassDB::bind_method("_update_connected_methods", &ScriptTextEditor::_update_connected_methods);
- ClassDB::bind_method("get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw);
- ClassDB::bind_method("can_drop_data_fw", &ScriptTextEditor::can_drop_data_fw);
- ClassDB::bind_method("drop_data_fw", &ScriptTextEditor::drop_data_fw);
+ ClassDB::bind_method("_get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw);
+ ClassDB::bind_method("_can_drop_data_fw", &ScriptTextEditor::can_drop_data_fw);
+ ClassDB::bind_method("_drop_data_fw", &ScriptTextEditor::drop_data_fw);
ClassDB::bind_method(D_METHOD("add_syntax_highlighter", "highlighter"), &ScriptTextEditor::add_syntax_highlighter);
}
@@ -1379,6 +1358,10 @@ void ScriptTextEditor::clear_edit_menu() {
memdelete(edit_hb);
}
+void ScriptTextEditor::set_find_replace_bar(FindReplaceBar *p_bar) {
+ code_editor->set_find_replace_bar(p_bar);
+}
+
void ScriptTextEditor::reload(bool p_soft) {
CodeEdit *te = code_editor->get_text_editor();
Ref<Script> scr = script;
@@ -1402,6 +1385,10 @@ void ScriptTextEditor::set_tooltip_request_func(String p_method, Object *p_obj)
void ScriptTextEditor::set_debugger_active(bool p_active) {
}
+Control *ScriptTextEditor::get_base_editor() const {
+ return code_editor->get_text_editor();
+}
+
Variant ScriptTextEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
return Variant();
}
@@ -1466,11 +1453,17 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
Array files = d["files"];
String text_to_drop;
+ bool preload = Input::get_singleton()->is_key_pressed(KEY_CTRL);
for (int i = 0; i < files.size(); i++) {
if (i > 0) {
- text_to_drop += ",";
+ text_to_drop += ", ";
+ }
+
+ if (preload) {
+ text_to_drop += "preload(\"" + String(files[i]).c_escape() + "\")";
+ } else {
+ text_to_drop += "\"" + String(files[i]).c_escape() + "\"";
}
- text_to_drop += "\"" + String(files[i]).c_escape() + "\"";
}
te->cursor_set_line(row);
@@ -1556,7 +1549,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
}
bool has_color = (word_at_pos == "Color");
- bool foldable = tx->can_fold(row) || tx->is_folded(row);
+ bool foldable = tx->can_fold_line(row) || tx->is_line_folded(row);
bool open_docs = false;
bool goto_definition = false;
@@ -1835,9 +1828,7 @@ ScriptTextEditor::ScriptTextEditor() {
update_settings();
- code_editor->get_text_editor()->set_callhint_settings(
- EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"),
- EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset"));
+ code_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"));
code_editor->get_text_editor()->set_select_identifiers_on_hover(true);
code_editor->get_text_editor()->set_context_menu_enabled(false);
@@ -1933,7 +1924,7 @@ void ScriptTextEditor::register_editor() {
#ifdef OSX_ENABLED
ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_C);
#else
- ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD | KEY_D);
+ ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_D);
#endif
ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_E);
ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_T);
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 17abfcf4cc..7bb961bf19 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -89,6 +89,8 @@ class ScriptTextEditor : public ScriptEditorBase {
Color default_line_number_color = Color(1, 1, 1);
Color safe_line_number_color = Color(1, 1, 1);
+ Color marked_line_color = Color(1, 1, 1);
+
PopupPanel *color_panel = nullptr;
ColorPicker *color_picker = nullptr;
Vector2 color_position;
@@ -231,8 +233,12 @@ public:
Control *get_edit_menu() override;
virtual void clear_edit_menu() override;
+ virtual void set_find_replace_bar(FindReplaceBar *p_bar) override;
+
static void register_editor();
+ virtual Control *get_base_editor() const override;
+
virtual void validate() override;
ScriptTextEditor();
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index ed3b746678..e4a5a3796e 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -37,12 +37,18 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/project_settings_editor.h"
#include "editor/property_editor.h"
#include "servers/display_server.h"
#include "servers/rendering/shader_types.h"
/*** SHADER SCRIPT EDITOR ****/
+static bool saved_warnings_enabled = false;
+static bool saved_treat_warning_as_errors = false;
+static Map<ShaderWarning::Code, bool> saved_warnings;
+static uint32_t saved_warning_flags = 0U;
+
Ref<Shader> ShaderTextEditor::get_edited_shader() const {
return shader;
}
@@ -57,6 +63,8 @@ void ShaderTextEditor::set_edited_shader(const Ref<Shader> &p_shader) {
get_text_editor()->set_text(p_shader->get_code());
get_text_editor()->clear_undo_history();
+ get_text_editor()->call_deferred("set_h_scroll", 0);
+ get_text_editor()->call_deferred("set_v_scroll", 0);
_validate_script();
_line_col_changed();
@@ -82,54 +90,21 @@ void ShaderTextEditor::reload_text() {
update_line_and_column();
}
+void ShaderTextEditor::set_warnings_panel(RichTextLabel *p_warnings_panel) {
+ warnings_panel = p_warnings_panel;
+}
+
void ShaderTextEditor::_load_theme_settings() {
- Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
- Color completion_background_color = EDITOR_GET("text_editor/highlighting/completion_background_color");
- Color completion_selected_color = EDITOR_GET("text_editor/highlighting/completion_selected_color");
- Color completion_existing_color = EDITOR_GET("text_editor/highlighting/completion_existing_color");
- Color completion_scroll_color = EDITOR_GET("text_editor/highlighting/completion_scroll_color");
- Color completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color");
- Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
- Color line_number_color = EDITOR_GET("text_editor/highlighting/line_number_color");
- Color caret_color = EDITOR_GET("text_editor/highlighting/caret_color");
- Color caret_background_color = EDITOR_GET("text_editor/highlighting/caret_background_color");
- Color text_selected_color = EDITOR_GET("text_editor/highlighting/text_selected_color");
- Color selection_color = EDITOR_GET("text_editor/highlighting/selection_color");
- Color brace_mismatch_color = EDITOR_GET("text_editor/highlighting/brace_mismatch_color");
- Color current_line_color = EDITOR_GET("text_editor/highlighting/current_line_color");
- Color line_length_guideline_color = EDITOR_GET("text_editor/highlighting/line_length_guideline_color");
- Color word_highlighted_color = EDITOR_GET("text_editor/highlighting/word_highlighted_color");
- Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color");
- Color bookmark_color = EDITOR_GET("text_editor/highlighting/bookmark_color");
- Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color");
- Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color");
- Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color");
- Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color");
- Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color");
-
- get_text_editor()->add_theme_color_override("background_color", background_color);
- get_text_editor()->add_theme_color_override("completion_background_color", completion_background_color);
- get_text_editor()->add_theme_color_override("completion_selected_color", completion_selected_color);
- get_text_editor()->add_theme_color_override("completion_existing_color", completion_existing_color);
- get_text_editor()->add_theme_color_override("completion_scroll_color", completion_scroll_color);
- get_text_editor()->add_theme_color_override("completion_font_color", completion_font_color);
- get_text_editor()->add_theme_color_override("font_color", text_color);
- get_text_editor()->add_theme_color_override("line_number_color", line_number_color);
- get_text_editor()->add_theme_color_override("caret_color", caret_color);
- get_text_editor()->add_theme_color_override("caret_background_color", caret_background_color);
- get_text_editor()->add_theme_color_override("font_selected_color", text_selected_color);
- get_text_editor()->add_theme_color_override("selection_color", selection_color);
- get_text_editor()->add_theme_color_override("brace_mismatch_color", brace_mismatch_color);
- get_text_editor()->add_theme_color_override("current_line_color", current_line_color);
- get_text_editor()->add_theme_color_override("line_length_guideline_color", line_length_guideline_color);
- get_text_editor()->add_theme_color_override("word_highlighted_color", word_highlighted_color);
- get_text_editor()->add_theme_color_override("mark_color", mark_color);
- get_text_editor()->add_theme_color_override("bookmark_color", bookmark_color);
- get_text_editor()->add_theme_color_override("breakpoint_color", breakpoint_color);
- get_text_editor()->add_theme_color_override("executing_line_color", executing_line_color);
- get_text_editor()->add_theme_color_override("code_folding_color", code_folding_color);
- get_text_editor()->add_theme_color_override("search_result_color", search_result_color);
- get_text_editor()->add_theme_color_override("search_result_border_color", search_result_border_color);
+ CodeEdit *text_editor = get_text_editor();
+ Color updated_marked_line_color = EDITOR_GET("text_editor/highlighting/mark_color");
+ if (updated_marked_line_color != marked_line_color) {
+ for (int i = 0; i < text_editor->get_line_count(); i++) {
+ if (text_editor->get_line_background_color(i) == marked_line_color) {
+ text_editor->set_line_background_color(i, updated_marked_line_color);
+ }
+ }
+ marked_line_color = updated_marked_line_color;
+ }
syntax_highlighter->set_number_color(EDITOR_GET("text_editor/highlighting/number_color"));
syntax_highlighter->set_symbol_color(EDITOR_GET("text_editor/highlighting/symbol_color"));
@@ -141,9 +116,14 @@ void ShaderTextEditor::_load_theme_settings() {
List<String> keywords;
ShaderLanguage::get_keyword_list(&keywords);
const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ const Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
for (List<String>::Element *E = keywords.front(); E; E = E->next()) {
- syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ if (ShaderLanguage::is_control_flow_keyword(E->get())) {
+ syntax_highlighter->add_keyword_color(E->get(), control_flow_keyword_color);
+ } else {
+ syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ }
}
// Colorize built-ins like `COLOR` differently to make them easier
@@ -173,6 +153,16 @@ void ShaderTextEditor::_load_theme_settings() {
syntax_highlighter->clear_color_regions();
syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
syntax_highlighter->add_color_region("//", "", comment_color, true);
+
+ text_editor->clear_comment_delimiters();
+ text_editor->add_comment_delimiter("/*", "*/", false);
+ text_editor->add_comment_delimiter("//", "", true);
+
+ if (warnings_panel) {
+ // Warnings panel
+ warnings_panel->add_theme_font_override("normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts"));
+ warnings_panel->add_theme_font_size_override("normal_font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size("main_size", "EditorFonts"));
+ }
}
void ShaderTextEditor::_check_shader_mode() {
@@ -219,6 +209,9 @@ void ShaderTextEditor::_validate_script() {
ShaderLanguage sl;
+ sl.enable_warning_checking(saved_warnings_enabled);
+ sl.set_warning_flags(saved_warning_flags);
+
Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
if (err != OK) {
@@ -226,20 +219,70 @@ void ShaderTextEditor::_validate_script() {
set_error(error_text);
set_error_pos(sl.get_error_line() - 1, 0);
for (int i = 0; i < get_text_editor()->get_line_count(); i++) {
- get_text_editor()->set_line_as_marked(i, false);
+ get_text_editor()->set_line_background_color(i, Color(0, 0, 0, 0));
}
- get_text_editor()->set_line_as_marked(sl.get_error_line() - 1, true);
-
+ get_text_editor()->set_line_background_color(sl.get_error_line() - 1, marked_line_color);
} else {
for (int i = 0; i < get_text_editor()->get_line_count(); i++) {
- get_text_editor()->set_line_as_marked(i, false);
+ get_text_editor()->set_line_background_color(i, Color(0, 0, 0, 0));
}
set_error("");
}
+ if (warnings.size() > 0 || err != OK) {
+ warnings_panel->clear();
+ }
+ warnings.clear();
+ for (List<ShaderWarning>::Element *E = sl.get_warnings_ptr(); E; E = E->next()) {
+ warnings.push_back(E->get());
+ }
+ if (warnings.size() > 0 && err == OK) {
+ warnings.sort_custom<WarningsComparator>();
+ _update_warning_panel();
+ } else {
+ set_warning_nb(0);
+ }
emit_signal("script_changed");
}
+void ShaderTextEditor::_update_warning_panel() {
+ int warning_count = 0;
+
+ warnings_panel->push_table(2);
+ for (int i = 0; i < warnings.size(); i++) {
+ ShaderWarning &w = warnings[i];
+
+ if (warning_count == 0) {
+ if (saved_treat_warning_as_errors) {
+ String error_text = "error(" + itos(w.get_line()) + "): " + w.get_message() + " " + TTR("Warnings should be fixed to prevent errors.");
+ set_error_pos(w.get_line() - 1, 0);
+ set_error(error_text);
+ get_text_editor()->set_line_background_color(w.get_line() - 1, marked_line_color);
+ }
+ }
+
+ warning_count++;
+
+ // First cell.
+ warnings_panel->push_cell();
+ warnings_panel->push_meta(w.get_line() - 1);
+ warnings_panel->push_color(warnings_panel->get_theme_color("warning_color", "Editor"));
+ warnings_panel->add_text(TTR("Line") + " " + itos(w.get_line()));
+ warnings_panel->add_text(" (" + w.get_name() + "):");
+ warnings_panel->pop(); // Color.
+ warnings_panel->pop(); // Meta goto.
+ warnings_panel->pop(); // Cell.
+
+ // Second cell.
+ warnings_panel->push_cell();
+ warnings_panel->add_text(w.get_message());
+ warnings_panel->pop(); // Cell.
+ }
+ warnings_panel->pop(); // Table.
+
+ set_warning_nb(warning_count);
+}
+
void ShaderTextEditor::_bind_methods() {
}
@@ -309,7 +352,7 @@ void ShaderEditor::_menu_option(int p_option) {
} break;
case EDIT_COMPLETE: {
- shader_editor->get_text_editor()->query_code_comple();
+ shader_editor->get_text_editor()->request_code_completion();
} break;
case SEARCH_FIND: {
shader_editor->get_find_replace_bar()->popup_search();
@@ -353,10 +396,6 @@ void ShaderEditor::_notification(int p_what) {
}
}
-void ShaderEditor::_params_changed() {
- shader_editor->_validate_script();
-}
-
void ShaderEditor::_editor_settings_changed() {
shader_editor->update_editor_settings();
@@ -365,8 +404,19 @@ void ShaderEditor::_editor_settings_changed() {
shader_editor->get_text_editor()->set_draw_executing_lines_gutter(false);
}
+void ShaderEditor::_show_warnings_panel(bool p_show) {
+ warnings_panel->set_visible(p_show);
+}
+
+void ShaderEditor::_warning_clicked(Variant p_line) {
+ if (p_line.get_type() == Variant::INT) {
+ shader_editor->get_text_editor()->cursor_set_line(p_line.operator int64_t());
+ }
+}
+
void ShaderEditor::_bind_methods() {
- ClassDB::bind_method("_params_changed", &ShaderEditor::_params_changed);
+ ClassDB::bind_method("_show_warnings_panel", &ShaderEditor::_show_warnings_panel);
+ ClassDB::bind_method("_warning_clicked", &ShaderEditor::_warning_clicked);
}
void ShaderEditor::ensure_select_current() {
@@ -384,6 +434,47 @@ void ShaderEditor::goto_line_selection(int p_line, int p_begin, int p_end) {
shader_editor->goto_line_selection(p_line, p_begin, p_end);
}
+void ShaderEditor::_project_settings_changed() {
+ _update_warnings(true);
+}
+
+void ShaderEditor::_update_warnings(bool p_validate) {
+ bool changed = false;
+
+ bool warnings_enabled = GLOBAL_GET("debug/shader_language/warnings/enable").booleanize();
+ if (warnings_enabled != saved_warnings_enabled) {
+ saved_warnings_enabled = warnings_enabled;
+ changed = true;
+ }
+
+ bool treat_warning_as_errors = GLOBAL_GET("debug/shader_language/warnings/treat_warnings_as_errors").booleanize();
+ if (treat_warning_as_errors != saved_treat_warning_as_errors) {
+ saved_treat_warning_as_errors = treat_warning_as_errors;
+ changed = true;
+ }
+
+ bool update_flags = false;
+
+ for (int i = 0; i < ShaderWarning::WARNING_MAX; i++) {
+ ShaderWarning::Code code = (ShaderWarning::Code)i;
+ bool value = GLOBAL_GET("debug/shader_language/warnings/" + ShaderWarning::get_name_from_code(code).to_lower());
+
+ if (saved_warnings[code] != value) {
+ saved_warnings[code] = value;
+ update_flags = true;
+ changed = true;
+ }
+ }
+
+ if (update_flags) {
+ saved_warning_flags = (uint32_t)ShaderWarning::get_flags_from_codemap(saved_warnings);
+ }
+
+ if (p_validate && changed && shader_editor && shader_editor->get_edited_shader().is_valid()) {
+ shader_editor->validate_script();
+ }
+}
+
void ShaderEditor::_check_for_external_edit() {
if (shader.is_null() || !shader.is_valid()) {
return;
@@ -555,17 +646,24 @@ void ShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) {
}
ShaderEditor::ShaderEditor(EditorNode *p_node) {
+ GLOBAL_DEF("debug/shader_language/warnings/enable", true);
+ GLOBAL_DEF("debug/shader_language/warnings/treat_warnings_as_errors", false);
+ for (int i = 0; i < (int)ShaderWarning::WARNING_MAX; i++) {
+ GLOBAL_DEF("debug/shader_language/warnings/" + ShaderWarning::get_name_from_code((ShaderWarning::Code)i).to_lower(), true);
+ }
+ _update_warnings(false);
+
shader_editor = memnew(ShaderTextEditor);
shader_editor->set_v_size_flags(SIZE_EXPAND_FILL);
shader_editor->add_theme_constant_override("separation", 0);
shader_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ shader_editor->connect("show_warnings_panel", callable_mp(this, &ShaderEditor::_show_warnings_panel));
shader_editor->connect("script_changed", callable_mp(this, &ShaderEditor::apply_shaders));
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &ShaderEditor::_editor_settings_changed));
+ ProjectSettingsEditor::get_singleton()->connect("confirmed", callable_mp(this, &ShaderEditor::_project_settings_changed));
- shader_editor->get_text_editor()->set_callhint_settings(
- EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"),
- EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset"));
+ shader_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"));
shader_editor->get_text_editor()->set_select_identifiers_on_hover(true);
shader_editor->get_text_editor()->set_context_menu_enabled(false);
@@ -646,7 +744,28 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
hbc->add_child(goto_menu);
hbc->add_child(help_menu);
hbc->add_theme_style_override("panel", p_node->get_gui_base()->get_theme_stylebox("ScriptEditorPanel", "EditorStyles"));
- main_container->add_child(shader_editor);
+
+ VSplitContainer *editor_box = memnew(VSplitContainer);
+ main_container->add_child(editor_box);
+ editor_box->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ editor_box->set_v_size_flags(SIZE_EXPAND_FILL);
+ editor_box->add_child(shader_editor);
+
+ FindReplaceBar *bar = memnew(FindReplaceBar);
+ main_container->add_child(bar);
+ bar->hide();
+ shader_editor->set_find_replace_bar(bar);
+
+ warnings_panel = memnew(RichTextLabel);
+ warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE));
+ warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL);
+ warnings_panel->set_meta_underline(true);
+ warnings_panel->set_selection_enabled(true);
+ warnings_panel->set_focus_mode(FOCUS_CLICK);
+ warnings_panel->hide();
+ warnings_panel->connect("meta_clicked", callable_mp(this, &ShaderEditor::_warning_clicked));
+ editor_box->add_child(warnings_panel);
+ shader_editor->set_warnings_panel(warnings_panel);
goto_line_dialog = memnew(GotoLineDialog);
add_child(goto_line_dialog);
diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h
index 731c0a5b7e..d7da73f2ae 100644
--- a/editor/plugins/shader_editor_plugin.h
+++ b/editor/plugins/shader_editor_plugin.h
@@ -35,6 +35,7 @@
#include "editor/editor_plugin.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel_container.h"
+#include "scene/gui/rich_text_label.h"
#include "scene/gui/tab_container.h"
#include "scene/gui/text_edit.h"
#include "scene/main/timer.h"
@@ -44,10 +45,19 @@
class ShaderTextEditor : public CodeTextEditor {
GDCLASS(ShaderTextEditor, CodeTextEditor);
+ Color marked_line_color = Color(1, 1, 1);
+
+ struct WarningsComparator {
+ _ALWAYS_INLINE_ bool operator()(const ShaderWarning &p_a, const ShaderWarning &p_b) const { return (p_a.get_line() < p_b.get_line()); }
+ };
+
Ref<CodeHighlighter> syntax_highlighter;
+ RichTextLabel *warnings_panel = nullptr;
Ref<Shader> shader;
+ List<ShaderWarning> warnings;
void _check_shader_mode();
+ void _update_warning_panel();
protected:
static void _bind_methods();
@@ -59,6 +69,7 @@ public:
virtual void _validate_script() override;
void reload_text();
+ void set_warnings_panel(RichTextLabel *p_warnings_panel);
Ref<Shader> get_edited_shader() const;
void set_edited_shader(const Ref<Shader> &p_shader);
@@ -100,6 +111,7 @@ class ShaderEditor : public PanelContainer {
PopupMenu *bookmarks_menu;
MenuButton *help_menu;
PopupMenu *context_menu;
+ RichTextLabel *warnings_panel = nullptr;
uint64_t idle;
GotoLineDialog *goto_line_dialog;
@@ -109,13 +121,16 @@ class ShaderEditor : public PanelContainer {
ShaderTextEditor *shader_editor;
void _menu_option(int p_option);
- void _params_changed();
mutable Ref<Shader> shader;
void _editor_settings_changed();
+ void _project_settings_changed();
void _check_for_external_edit();
void _reload_shader_from_disk();
+ void _show_warnings_panel(bool p_show);
+ void _warning_clicked(Variant p_line);
+ void _update_warnings(bool p_validate);
protected:
void _notification(int p_what);
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 404ef62eca..a97584ebce 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -95,7 +95,7 @@ void BoneTransformEditor::create_editors() {
section->get_vbox()->add_child(transform_section);
// Transform/Matrix property
- transform_property = memnew(EditorPropertyTransform());
+ transform_property = memnew(EditorPropertyTransform3D());
transform_property->setup(-10000, 10000, 0.001f, true);
transform_property->set_label("Transform");
transform_property->set_use_folding(true);
@@ -171,7 +171,7 @@ void BoneTransformEditor::_value_changed(const double p_value) {
return;
}
- Transform tform = compute_transform_from_vector3s();
+ Transform3D tform = compute_transform_from_vector3s();
_change_transform(tform);
}
@@ -179,30 +179,30 @@ void BoneTransformEditor::_value_changed_vector3(const String p_property_name, c
if (updating) {
return;
}
- Transform tform = compute_transform_from_vector3s();
+ Transform3D tform = compute_transform_from_vector3s();
_change_transform(tform);
}
-Transform BoneTransformEditor::compute_transform_from_vector3s() const {
+Transform3D BoneTransformEditor::compute_transform_from_vector3s() const {
// Convert rotation from degrees to radians.
Vector3 prop_rotation = rotation_property->get_vector();
prop_rotation.x = Math::deg2rad(prop_rotation.x);
prop_rotation.y = Math::deg2rad(prop_rotation.y);
prop_rotation.z = Math::deg2rad(prop_rotation.z);
- return Transform(
+ return Transform3D(
Basis(prop_rotation, scale_property->get_vector()),
translation_property->get_vector());
}
-void BoneTransformEditor::_value_changed_transform(const String p_property_name, const Transform p_transform, const StringName p_edited_property_name, const bool p_boolean) {
+void BoneTransformEditor::_value_changed_transform(const String p_property_name, const Transform3D p_transform, const StringName p_edited_property_name, const bool p_boolean) {
if (updating) {
return;
}
_change_transform(p_transform);
}
-void BoneTransformEditor::_change_transform(Transform p_new_transform) {
+void BoneTransformEditor::_change_transform(Transform3D p_new_transform) {
if (property.get_slicec('/', 0) == "bones" && property.get_slicec('/', 2) == "custom_pose") {
undo_redo->create_action(TTR("Set Custom Bone Pose Transform"), UndoRedo::MERGE_ENDS);
undo_redo->add_undo_method(skeleton, "set_bone_custom_pose", property.get_slicec('/', 1).to_int(), skeleton->get_bone_custom_pose(property.get_slicec('/', 1).to_int()));
@@ -235,7 +235,7 @@ void BoneTransformEditor::_update_properties() {
updating = true;
- Transform tform = skeleton->get(property);
+ Transform3D tform = skeleton->get(property);
_update_transform_properties(tform);
}
@@ -250,11 +250,11 @@ void BoneTransformEditor::_update_custom_pose_properties() {
updating = true;
- Transform tform = skeleton->get_bone_custom_pose(property.to_int());
+ Transform3D tform = skeleton->get_bone_custom_pose(property.to_int());
_update_transform_properties(tform);
}
-void BoneTransformEditor::_update_transform_properties(Transform tform) {
+void BoneTransformEditor::_update_transform_properties(Transform3D tform) {
Basis rotation_basis = tform.get_basis();
Vector3 rotation_radians = rotation_basis.get_rotation_euler();
Vector3 rotation_degrees = Vector3(Math::rad2deg(rotation_radians.x), Math::rad2deg(rotation_radians.y), Math::rad2deg(rotation_radians.z));
@@ -306,7 +306,7 @@ void BoneTransformEditor::_key_button_pressed() {
}
// Need to normalize the basis before you key it
- Transform tform = compute_transform_from_vector3s();
+ Transform3D tform = compute_transform_from_vector3s();
tform.orthonormalize();
AnimationPlayerEditor::singleton->get_track_editor()->insert_transform_key(skeleton, name, tform);
}
@@ -380,7 +380,7 @@ void Skeleton3DEditor::create_physical_skeleton() {
}
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 Transform3D 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);
@@ -392,15 +392,15 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
CollisionShape3D *bone_shape = memnew(CollisionShape3D);
bone_shape->set_shape(bone_shape_capsule);
- Transform capsule_transform;
+ Transform3D capsule_transform;
capsule_transform.basis = Basis(Vector3(1, 0, 0), Vector3(0, 0, 1), Vector3(0, -1, 0));
bone_shape->set_transform(capsule_transform);
- Transform body_transform;
+ Transform3D body_transform;
body_transform.set_look_at(Vector3(0, 0, 0), child_rest.origin);
body_transform.origin = body_transform.basis.xform(Vector3(0, 0, -half_height));
- Transform joint_transform;
+ Transform3D joint_transform;
joint_transform.origin = Vector3(0, 0, half_height);
PhysicalBone3D *physical_bone = memnew(PhysicalBone3D);
@@ -666,9 +666,9 @@ void Skeleton3DEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_properties"), &Skeleton3DEditor::_update_properties);
ClassDB::bind_method(D_METHOD("_on_click_option"), &Skeleton3DEditor::_on_click_option);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &Skeleton3DEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Skeleton3DEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &Skeleton3DEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &Skeleton3DEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &Skeleton3DEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &Skeleton3DEditor::drop_data_fw);
ClassDB::bind_method(D_METHOD("move_skeleton_bone"), &Skeleton3DEditor::move_skeleton_bone);
}
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
index 14c213f7b2..9de52c6fa8 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -41,7 +41,7 @@ class PhysicalBone3D;
class Skeleton3DEditorPlugin;
class Button;
class CheckBox;
-class EditorPropertyTransform;
+class EditorPropertyTransform3D;
class EditorPropertyVector3;
class BoneTransformEditor : public VBoxContainer {
@@ -53,7 +53,7 @@ class BoneTransformEditor : public VBoxContainer {
EditorPropertyVector3 *rotation_property = nullptr;
EditorPropertyVector3 *scale_property = nullptr;
EditorInspectorSection *transform_section = nullptr;
- EditorPropertyTransform *transform_property = nullptr;
+ EditorPropertyTransform3D *transform_property = nullptr;
Rect2 background_rects[5];
@@ -78,11 +78,11 @@ class BoneTransformEditor : public VBoxContainer {
// Called when the one of the EditorPropertyVector3 are updated.
void _value_changed_vector3(const String p_property_name, const Vector3 p_vector, const StringName p_edited_property_name, const bool p_boolean);
// Called when the transform_property is updated.
- void _value_changed_transform(const String p_property_name, const Transform p_transform, const StringName p_edited_property_name, const bool p_boolean);
+ void _value_changed_transform(const String p_property_name, const Transform3D p_transform, const StringName p_edited_property_name, const bool p_boolean);
// Changes the transform to the given transform and updates the UI accordingly.
- void _change_transform(Transform p_new_transform);
+ void _change_transform(Transform3D p_new_transform);
// Creates a Transform using the EditorPropertyVector3 properties.
- Transform compute_transform_from_vector3s() const;
+ Transform3D compute_transform_from_vector3s() const;
void update_enabled_checkbox();
@@ -98,7 +98,7 @@ public:
void _update_properties();
void _update_custom_pose_properties();
- void _update_transform_properties(Transform p_transform);
+ void _update_transform_properties(Transform3D p_transform);
// Can/cannot modify the spinner values for the Transform
void set_read_only(const bool p_read_only);
@@ -127,7 +127,7 @@ class Skeleton3DEditor : public VBoxContainer {
struct BoneInfo {
PhysicalBone3D *physical_bone = nullptr;
- Transform relative_rest; // Relative to skeleton node
+ Transform3D relative_rest; // Relative to skeleton node
};
EditorNode *editor;
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index bd6dac7490..a5a3d624ec 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -115,7 +115,7 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
int idx = h * y + x;
- if (mb->get_shift() && last_frame_selected >= 0) {
+ if (mb->is_shift_pressed() && last_frame_selected >= 0) {
//select multiple
int from = idx;
int to = last_frame_selected;
@@ -124,7 +124,7 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
}
for (int i = from; i <= to; i++) {
- if (mb->get_control()) {
+ if (mb->is_ctrl_pressed()) {
frames_selected.erase(i);
} else {
frames_selected.insert(i);
@@ -150,11 +150,11 @@ void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) {
// Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
// to allow performing this action anywhere, even if the cursor isn't
// hovering the texture in the workspace.
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->is_ctrl_pressed()) {
_sheet_zoom_in();
// Don't scroll up after zooming in.
accept_event();
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->is_ctrl_pressed()) {
_sheet_zoom_out();
// Don't scroll down after zooming out.
accept_event();
@@ -220,7 +220,7 @@ void SpriteFramesEditor::_sheet_zoom_out() {
void SpriteFramesEditor::_sheet_zoom_reset() {
// Default the zoom to match the editor scale, but don't dezoom on editor scales below 100% to prevent pixel art from looking bad.
- sheet_zoom = MAX(1.0, EDSCALE);
+ sheet_zoom = MAX(1.0f, EDSCALE);
Size2 texture_size = split_sheet_preview->get_texture()->get_size();
split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom);
}
@@ -252,10 +252,10 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
EditorNode::get_singleton()->show_warning(TTR("Unable to load images"));
ERR_FAIL_COND(!texture.is_valid());
}
- bool new_texture = texture != split_sheet_preview->get_texture();
frames_selected.clear();
last_frame_selected = -1;
+ bool new_texture = texture != split_sheet_preview->get_texture();
split_sheet_preview->set_texture(texture);
if (new_texture) {
//different texture, reset to 4x4
@@ -280,17 +280,17 @@ void SpriteFramesEditor::_notification(int p_what) {
move_down->set_icon(get_theme_icon("MoveRight", "EditorIcons"));
_delete->set_icon(get_theme_icon("Remove", "EditorIcons"));
zoom_out->set_icon(get_theme_icon("ZoomLess", "EditorIcons"));
- zoom_1->set_icon(get_theme_icon("ZoomReset", "EditorIcons"));
+ zoom_reset->set_icon(get_theme_icon("ZoomReset", "EditorIcons"));
zoom_in->set_icon(get_theme_icon("ZoomMore", "EditorIcons"));
new_anim->set_icon(get_theme_icon("New", "EditorIcons"));
remove_anim->set_icon(get_theme_icon("Remove", "EditorIcons"));
split_sheet_zoom_out->set_icon(get_theme_icon("ZoomLess", "EditorIcons"));
- split_sheet_zoom_1->set_icon(get_theme_icon("ZoomReset", "EditorIcons"));
+ split_sheet_zoom_reset->set_icon(get_theme_icon("ZoomReset", "EditorIcons"));
split_sheet_zoom_in->set_icon(get_theme_icon("ZoomMore", "EditorIcons"));
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
- splite_sheet_scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
+ split_sheet_scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
} break;
case NOTIFICATION_READY: {
add_theme_constant_override("autohide", 1); // Fixes the dragger always showing up.
@@ -513,7 +513,7 @@ void SpriteFramesEditor::_animation_select() {
if (frames->has_animation(edited_anim)) {
double value = anim_speed->get_line_edit()->get_text().to_float();
- if (!Math::is_equal_approx(value, frames->get_animation_speed(edited_anim))) {
+ if (!Math::is_equal_approx(value, (double)frames->get_animation_speed(edited_anim))) {
_animation_fps_changed(value);
}
}
@@ -694,11 +694,11 @@ void SpriteFramesEditor::_tree_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->is_ctrl_pressed()) {
_zoom_in();
// Don't scroll up after zooming in.
accept_event();
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->is_ctrl_pressed()) {
_zoom_out();
// Don't scroll down after zooming out.
accept_event();
@@ -733,7 +733,7 @@ void SpriteFramesEditor::_zoom_out() {
}
void SpriteFramesEditor::_zoom_reset() {
- thumbnail_zoom = MAX(1.0, EDSCALE);
+ thumbnail_zoom = MAX(1.0f, EDSCALE);
tree->set_fixed_column_width(thumbnail_default_size * 3 / 2);
tree->set_fixed_icon_size(Size2(thumbnail_default_size, thumbnail_default_size));
}
@@ -954,7 +954,7 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
if (String(d["type"]) == "files") {
Vector<String> files = d["files"];
- if (Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
_prepare_sprite_sheet(files[0]);
} else {
_file_load_request(files, at_pos);
@@ -964,9 +964,9 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
void SpriteFramesEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_library", "skipsel"), &SpriteFramesEditor::_update_library, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpriteFramesEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &SpriteFramesEditor::drop_data_fw);
}
SpriteFramesEditor::SpriteFramesEditor() {
@@ -1086,11 +1086,13 @@ SpriteFramesEditor::SpriteFramesEditor() {
zoom_out->set_flat(true);
zoom_out->set_tooltip(TTR("Zoom Out"));
hbc->add_child(zoom_out);
- zoom_1 = memnew(Button);
- zoom_1->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_reset));
- zoom_1->set_flat(true);
- zoom_1->set_tooltip(TTR("Zoom Reset"));
- hbc->add_child(zoom_1);
+
+ zoom_reset = memnew(Button);
+ zoom_reset->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_reset));
+ zoom_reset->set_flat(true);
+ zoom_reset->set_tooltip(TTR("Zoom Reset"));
+ hbc->add_child(zoom_reset);
+
zoom_in = memnew(Button);
zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_in));
zoom_in->set_flat(true);
@@ -1183,16 +1185,16 @@ SpriteFramesEditor::SpriteFramesEditor() {
split_sheet_preview->connect("draw", callable_mp(this, &SpriteFramesEditor::_sheet_preview_draw));
split_sheet_preview->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_sheet_preview_input));
- splite_sheet_scroll = memnew(ScrollContainer);
- splite_sheet_scroll->set_enable_h_scroll(true);
- splite_sheet_scroll->set_enable_v_scroll(true);
- splite_sheet_scroll->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_sheet_scroll_input));
- split_sheet_panel->add_child(splite_sheet_scroll);
+ split_sheet_scroll = memnew(ScrollContainer);
+ split_sheet_scroll->set_enable_h_scroll(true);
+ split_sheet_scroll->set_enable_v_scroll(true);
+ split_sheet_scroll->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_sheet_scroll_input));
+ split_sheet_panel->add_child(split_sheet_scroll);
CenterContainer *cc = memnew(CenterContainer);
cc->add_child(split_sheet_preview);
cc->set_h_size_flags(SIZE_EXPAND_FILL);
cc->set_v_size_flags(SIZE_EXPAND_FILL);
- splite_sheet_scroll->add_child(cc);
+ split_sheet_scroll->add_child(cc);
MarginContainer *split_sheet_zoom_margin = memnew(MarginContainer);
split_sheet_panel->add_child(split_sheet_zoom_margin);
@@ -1209,12 +1211,14 @@ SpriteFramesEditor::SpriteFramesEditor() {
split_sheet_zoom_out->set_tooltip(TTR("Zoom Out"));
split_sheet_zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_out));
split_sheet_zoom_hb->add_child(split_sheet_zoom_out);
- split_sheet_zoom_1 = memnew(Button);
- split_sheet_zoom_1->set_flat(true);
- split_sheet_zoom_1->set_focus_mode(FOCUS_NONE);
- split_sheet_zoom_1->set_tooltip(TTR("Zoom Reset"));
- split_sheet_zoom_1->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_reset));
- split_sheet_zoom_hb->add_child(split_sheet_zoom_1);
+
+ split_sheet_zoom_reset = memnew(Button);
+ split_sheet_zoom_reset->set_flat(true);
+ split_sheet_zoom_reset->set_focus_mode(FOCUS_NONE);
+ split_sheet_zoom_reset->set_tooltip(TTR("Zoom Reset"));
+ split_sheet_zoom_reset->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_reset));
+ split_sheet_zoom_hb->add_child(split_sheet_zoom_reset);
+
split_sheet_zoom_in = memnew(Button);
split_sheet_zoom_in->set_flat(true);
split_sheet_zoom_in->set_focus_mode(FOCUS_NONE);
@@ -1230,14 +1234,14 @@ SpriteFramesEditor::SpriteFramesEditor() {
// Config scale.
scale_ratio = 1.2f;
- thumbnail_default_size = 96 * MAX(1.0, EDSCALE);
- thumbnail_zoom = MAX(1.0, EDSCALE);
- max_thumbnail_zoom = 8.0f * MAX(1.0, EDSCALE);
- min_thumbnail_zoom = 0.1f * MAX(1.0, EDSCALE);
+ thumbnail_default_size = 96 * MAX(1, EDSCALE);
+ thumbnail_zoom = MAX(1.0f, EDSCALE);
+ max_thumbnail_zoom = 8.0f * MAX(1.0f, EDSCALE);
+ min_thumbnail_zoom = 0.1f * MAX(1.0f, EDSCALE);
// Default the zoom to match the editor scale, but don't dezoom on editor scales below 100% to prevent pixel art from looking bad.
- sheet_zoom = MAX(1.0, EDSCALE);
- max_sheet_zoom = 16.0f * MAX(1.0, EDSCALE);
- min_sheet_zoom = 0.01f * MAX(1.0, EDSCALE);
+ sheet_zoom = MAX(1.0f, EDSCALE);
+ max_sheet_zoom = 16.0f * MAX(1.0f, EDSCALE);
+ min_sheet_zoom = 0.01f * MAX(1.0f, EDSCALE);
_zoom_reset();
}
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index bbc26ca726..77cdbb4af6 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -54,13 +54,12 @@ class SpriteFramesEditor : public HSplitContainer {
Button *move_up;
Button *move_down;
Button *zoom_out;
- Button *zoom_1;
+ Button *zoom_reset;
Button *zoom_in;
ItemList *tree;
bool loading_scene;
int sel;
- HSplitContainer *split;
Button *new_anim;
Button *remove_anim;
@@ -79,12 +78,12 @@ class SpriteFramesEditor : public HSplitContainer {
ConfirmationDialog *delete_dialog;
ConfirmationDialog *split_sheet_dialog;
- ScrollContainer *splite_sheet_scroll;
+ ScrollContainer *split_sheet_scroll;
TextureRect *split_sheet_preview;
SpinBox *split_sheet_h;
SpinBox *split_sheet_v;
Button *split_sheet_zoom_out;
- Button *split_sheet_zoom_1;
+ Button *split_sheet_zoom_reset;
Button *split_sheet_zoom_in;
EditorFileDialog *file_split_sheet;
Set<int> frames_selected;
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 2b8bfe067d..621f843e6f 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -59,58 +59,7 @@ void TextEditor::_change_syntax_highlighter(int p_idx) {
}
void TextEditor::_load_theme_settings() {
- CodeEdit *text_edit = code_editor->get_text_editor();
- text_edit->get_syntax_highlighter()->update_cache();
-
- Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
- Color completion_background_color = EDITOR_GET("text_editor/highlighting/completion_background_color");
- Color completion_selected_color = EDITOR_GET("text_editor/highlighting/completion_selected_color");
- Color completion_existing_color = EDITOR_GET("text_editor/highlighting/completion_existing_color");
- Color completion_scroll_color = EDITOR_GET("text_editor/highlighting/completion_scroll_color");
- Color completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color");
- Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
- Color line_number_color = EDITOR_GET("text_editor/highlighting/line_number_color");
- Color caret_color = EDITOR_GET("text_editor/highlighting/caret_color");
- Color caret_background_color = EDITOR_GET("text_editor/highlighting/caret_background_color");
- Color text_selected_color = EDITOR_GET("text_editor/highlighting/text_selected_color");
- Color selection_color = EDITOR_GET("text_editor/highlighting/selection_color");
- Color brace_mismatch_color = EDITOR_GET("text_editor/highlighting/brace_mismatch_color");
- Color current_line_color = EDITOR_GET("text_editor/highlighting/current_line_color");
- Color line_length_guideline_color = EDITOR_GET("text_editor/highlighting/line_length_guideline_color");
- Color word_highlighted_color = EDITOR_GET("text_editor/highlighting/word_highlighted_color");
- Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color");
- Color bookmark_color = EDITOR_GET("text_editor/highlighting/bookmark_color");
- Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color");
- Color executing_line_color = EDITOR_GET("text_editor/highlighting/executing_line_color");
- Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color");
- Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color");
- Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color");
-
- 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_selected_color", 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("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_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6));
+ code_editor->get_text_editor()->get_syntax_highlighter()->update_cache();
}
String TextEditor::get_name() {
@@ -171,6 +120,10 @@ void TextEditor::add_callback(const String &p_function, PackedStringArray p_args
void TextEditor::set_debugger_active(bool p_active) {
}
+Control *TextEditor::get_base_editor() const {
+ return code_editor->get_text_editor();
+}
+
Array TextEditor::get_breakpoints() {
return Array();
}
@@ -328,6 +281,10 @@ void TextEditor::clear_edit_menu() {
memdelete(edit_hb);
}
+void TextEditor::set_find_replace_bar(FindReplaceBar *p_bar) {
+ code_editor->set_find_replace_bar(p_bar);
+}
+
void TextEditor::_edit_option(int p_op) {
CodeEdit *tx = code_editor->get_text_editor();
@@ -375,7 +332,7 @@ void TextEditor::_edit_option(int p_op) {
code_editor->clone_lines_down();
} break;
case EDIT_TOGGLE_FOLD_LINE: {
- tx->toggle_fold_line(tx->cursor_get_line());
+ tx->toggle_foldable_line(tx->cursor_get_line());
tx->update();
} break;
case EDIT_FOLD_ALL_LINES: {
@@ -475,8 +432,8 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col);
tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret"));
- bool can_fold = tx->can_fold(row);
- bool is_folded = tx->is_folded(row);
+ bool can_fold = tx->can_fold_line(row);
+ bool is_folded = tx->is_line_folded(row);
if (tx->is_right_click_moving_caret()) {
if (tx->is_selection_active()) {
@@ -506,7 +463,7 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
if (k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_MENU) {
CodeEdit *tx = code_editor->get_text_editor();
int line = tx->cursor_get_line();
- _make_context_menu(tx->is_selection_active(), tx->can_fold(line), tx->is_folded(line), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->_get_cursor_pixel_pos()));
+ _make_context_menu(tx->is_selection_active(), tx->can_fold_line(line), tx->is_line_folded(line), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->_get_cursor_pixel_pos()));
context_menu->grab_focus();
}
}
@@ -585,7 +542,7 @@ TextEditor::TextEditor() {
edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option));
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("un_redo"), EDIT_REDO);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY);
diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h
index c066d51b18..4e667dc676 100644
--- a/editor/plugins/text_editor.h
+++ b/editor/plugins/text_editor.h
@@ -139,9 +139,12 @@ public:
virtual Control *get_edit_menu() override;
virtual void clear_edit_menu() override;
+ virtual void set_find_replace_bar(FindReplaceBar *p_bar) override;
virtual void validate() override;
+ virtual Control *get_base_editor() const override;
+
static void register_editor();
TextEditor();
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index 253f8878d2..ecf7370834 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -143,7 +143,7 @@ TextureEditor::~TextureEditor() {
//
bool EditorInspectorPluginTexture::can_handle(Object *p_object) {
- return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<StreamTexture2D>(p_object) != nullptr || Object::cast_to<LargeTexture>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr;
+ return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<StreamTexture2D>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr;
}
void EditorInspectorPluginTexture::parse_begin(Object *p_object) {
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 7b927ad98b..d0ba68138b 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -331,7 +331,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 (Input::get_singleton()->is_key_pressed(KEY_CTRL) && !(Input::get_singleton()->is_key_pressed(KEY_SHIFT | KEY_ALT))) {
Rect2 r;
if (node_sprite) {
r = node_sprite->get_region_rect();
@@ -863,13 +863,13 @@ Sprite2D *TextureRegionEditor::get_sprite() {
void TextureRegionEditor::edit(Object *p_obj) {
if (node_sprite) {
- node_sprite->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
+ node_sprite->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (node_sprite_3d) {
- node_sprite_3d->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
+ node_sprite_3d->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (node_ninepatch) {
- node_ninepatch->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
+ node_ninepatch->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (obj_styleBox.is_valid()) {
obj_styleBox->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
@@ -881,13 +881,22 @@ void TextureRegionEditor::edit(Object *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);
+
+ bool is_resource = false;
if (Object::cast_to<StyleBoxTexture>(p_obj)) {
obj_styleBox = Ref<StyleBoxTexture>(Object::cast_to<StyleBoxTexture>(p_obj));
+ is_resource = true;
}
if (Object::cast_to<AtlasTexture>(p_obj)) {
atlas_tex = Ref<AtlasTexture>(Object::cast_to<AtlasTexture>(p_obj));
+ is_resource = true;
+ }
+
+ if (is_resource) {
+ p_obj->connect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
+ } else {
+ p_obj->connect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
- p_obj->connect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
_edit_region();
} else {
node_sprite = nullptr;
@@ -937,7 +946,6 @@ void TextureRegionEditor::_edit_region() {
if (cache_map.has(texture->get_rid())) {
autoslice_cache = cache_map[texture->get_rid()];
autoslice_is_dirty = false;
- return;
} else {
if (is_visible() && snap_mode == SNAP_AUTOSLICE) {
_update_autoslice();
@@ -1034,7 +1042,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
hb_grid->add_child(sb_step_y);
hb_grid->add_child(memnew(VSeparator));
- hb_grid->add_child(memnew(Label(TTR("Sep.:"))));
+ hb_grid->add_child(memnew(Label(TTR("Separation:"))));
sb_sep_x = memnew(SpinBox);
sb_sep_x->set_min(0);
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index dfa8c04145..6607bf6cad 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -30,911 +30,3220 @@
#include "theme_editor_plugin.h"
-#include "core/os/file_access.h"
-#include "core/version.h"
+#include "core/os/keyboard.h"
+#include "editor/editor_resource_picker.h"
#include "editor/editor_scale.h"
-#include "scene/gui/progress_bar.h"
+#include "editor/progress_dialog.h"
-void ThemeEditor::edit(const Ref<Theme> &p_theme) {
- theme = p_theme;
- main_panel->set_theme(p_theme);
- main_container->set_theme(p_theme);
+void ThemeItemImportTree::_update_items_tree() {
+ import_items_tree->clear();
+ TreeItem *root = import_items_tree->create_item();
+
+ if (base_theme.is_null()) {
+ return;
+ }
+
+ String filter_text = import_items_filter->get_text();
+
+ List<StringName> types;
+ List<StringName> names;
+ List<StringName> filtered_names;
+ base_theme->get_type_list(&types);
+ types.sort_custom<StringName::AlphCompare>();
+
+ int color_amount = 0;
+ int constant_amount = 0;
+ int font_amount = 0;
+ int font_size_amount = 0;
+ int icon_amount = 0;
+ int stylebox_amount = 0;
+
+ tree_color_items.clear();
+ tree_constant_items.clear();
+ tree_font_items.clear();
+ tree_font_size_items.clear();
+ tree_icon_items.clear();
+ tree_stylebox_items.clear();
+
+ for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
+ String type_name = (String)E->get();
+
+ TreeItem *type_node = import_items_tree->create_item(root);
+ type_node->set_meta("_can_be_imported", false);
+ type_node->set_collapsed(true);
+ type_node->set_text(0, type_name);
+ type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);
+ type_node->set_checked(IMPORT_ITEM, false);
+ type_node->set_editable(IMPORT_ITEM, true);
+ type_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);
+ type_node->set_checked(IMPORT_ITEM_DATA, false);
+ type_node->set_editable(IMPORT_ITEM_DATA, true);
+
+ bool is_matching_filter = (filter_text.is_empty() || type_name.findn(filter_text) > -1);
+ bool has_filtered_items = false;
+ bool any_checked = false;
+ bool any_checked_with_data = false;
+
+ for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {
+ Theme::DataType dt = (Theme::DataType)i;
+
+ names.clear();
+ filtered_names.clear();
+ base_theme->get_theme_item_list(dt, E->get(), &names);
+
+ bool data_type_has_filtered_items = false;
+
+ for (List<StringName>::Element *F = names.front(); F; F = F->next()) {
+ String item_name = (String)F->get();
+ bool is_item_matching_filter = (item_name.findn(filter_text) > -1);
+ if (!filter_text.is_empty() && !is_matching_filter && !is_item_matching_filter) {
+ continue;
+ }
+
+ // Only mark this if actual items match the filter and not just the type group.
+ if (!filter_text.is_empty() && is_item_matching_filter) {
+ has_filtered_items = true;
+ data_type_has_filtered_items = true;
+ }
+ filtered_names.push_back(F->get());
+ }
+
+ if (filtered_names.size() == 0) {
+ continue;
+ }
+
+ TreeItem *data_type_node = import_items_tree->create_item(type_node);
+ data_type_node->set_meta("_can_be_imported", false);
+ data_type_node->set_metadata(0, i);
+ data_type_node->set_collapsed(!data_type_has_filtered_items);
+ data_type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);
+ data_type_node->set_checked(IMPORT_ITEM, false);
+ data_type_node->set_editable(IMPORT_ITEM, true);
+ data_type_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);
+ data_type_node->set_checked(IMPORT_ITEM_DATA, false);
+ data_type_node->set_editable(IMPORT_ITEM_DATA, true);
+
+ List<TreeItem *> *item_list;
+
+ switch (dt) {
+ case Theme::DATA_TYPE_COLOR:
+ data_type_node->set_icon(0, get_theme_icon("Color", "EditorIcons"));
+ data_type_node->set_text(0, TTR("Colors"));
+
+ item_list = &tree_color_items;
+ color_amount += filtered_names.size();
+ break;
+
+ case Theme::DATA_TYPE_CONSTANT:
+ data_type_node->set_icon(0, get_theme_icon("MemberConstant", "EditorIcons"));
+ data_type_node->set_text(0, TTR("Constants"));
+
+ item_list = &tree_constant_items;
+ constant_amount += filtered_names.size();
+ break;
+
+ case Theme::DATA_TYPE_FONT:
+ data_type_node->set_icon(0, get_theme_icon("Font", "EditorIcons"));
+ data_type_node->set_text(0, TTR("Fonts"));
+
+ item_list = &tree_font_items;
+ font_amount += filtered_names.size();
+ break;
+
+ case Theme::DATA_TYPE_FONT_SIZE:
+ data_type_node->set_icon(0, get_theme_icon("FontSize", "EditorIcons"));
+ data_type_node->set_text(0, TTR("Font Sizes"));
+
+ item_list = &tree_font_size_items;
+ font_size_amount += filtered_names.size();
+ break;
+
+ case Theme::DATA_TYPE_ICON:
+ data_type_node->set_icon(0, get_theme_icon("ImageTexture", "EditorIcons"));
+ data_type_node->set_text(0, TTR("Icons"));
+
+ item_list = &tree_icon_items;
+ icon_amount += filtered_names.size();
+ break;
+
+ case Theme::DATA_TYPE_STYLEBOX:
+ data_type_node->set_icon(0, get_theme_icon("StyleBoxFlat", "EditorIcons"));
+ data_type_node->set_text(0, TTR("Styleboxes"));
+
+ item_list = &tree_stylebox_items;
+ stylebox_amount += filtered_names.size();
+ break;
+
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ bool data_type_any_checked = false;
+ bool data_type_any_checked_with_data = false;
+
+ filtered_names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *F = filtered_names.front(); F; F = F->next()) {
+ TreeItem *item_node = import_items_tree->create_item(data_type_node);
+ item_node->set_meta("_can_be_imported", true);
+ item_node->set_text(0, F->get());
+ item_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);
+ item_node->set_checked(IMPORT_ITEM, false);
+ item_node->set_editable(IMPORT_ITEM, true);
+ item_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);
+ item_node->set_checked(IMPORT_ITEM_DATA, false);
+ item_node->set_editable(IMPORT_ITEM_DATA, true);
+
+ _restore_selected_item(item_node);
+ if (item_node->is_checked(IMPORT_ITEM)) {
+ data_type_any_checked = true;
+ any_checked = true;
+ }
+ if (item_node->is_checked(IMPORT_ITEM_DATA)) {
+ data_type_any_checked_with_data = true;
+ any_checked_with_data = true;
+ }
+
+ item_list->push_back(item_node);
+ }
+
+ data_type_node->set_checked(IMPORT_ITEM, data_type_any_checked);
+ data_type_node->set_checked(IMPORT_ITEM_DATA, data_type_any_checked && data_type_any_checked_with_data);
+ }
+
+ // Remove the item if it doesn't match the filter in any way.
+ if (!is_matching_filter && !has_filtered_items) {
+ root->remove_child(type_node);
+ memdelete(type_node);
+ continue;
+ }
+
+ // Show one level inside of a type group if there are matches in items.
+ if (!filter_text.is_empty() && has_filtered_items) {
+ type_node->set_collapsed(false);
+ }
+
+ type_node->set_checked(IMPORT_ITEM, any_checked);
+ type_node->set_checked(IMPORT_ITEM_DATA, any_checked && any_checked_with_data);
+ }
+
+ if (color_amount > 0) {
+ Array arr;
+ arr.push_back(color_amount);
+ select_colors_label->set_text(TTRN("One color", "{num} colors", color_amount).format(arr, "{num}"));
+ select_all_colors_button->set_visible(true);
+ select_full_colors_button->set_visible(true);
+ deselect_all_colors_button->set_visible(true);
+ } else {
+ select_colors_label->set_text(TTR("No colors found."));
+ select_all_colors_button->set_visible(false);
+ select_full_colors_button->set_visible(false);
+ deselect_all_colors_button->set_visible(false);
+ }
+
+ if (constant_amount > 0) {
+ Array arr;
+ arr.push_back(constant_amount);
+ select_constants_label->set_text(TTRN("One constant", "{num} constants", constant_amount).format(arr, "{num}"));
+ select_all_constants_button->set_visible(true);
+ select_full_constants_button->set_visible(true);
+ deselect_all_constants_button->set_visible(true);
+ } else {
+ select_constants_label->set_text(TTR("No constants found."));
+ select_all_constants_button->set_visible(false);
+ select_full_constants_button->set_visible(false);
+ deselect_all_constants_button->set_visible(false);
+ }
+
+ if (font_amount > 0) {
+ Array arr;
+ arr.push_back(font_amount);
+ select_fonts_label->set_text(TTRN("One font", "{num} fonts", font_amount).format(arr, "{num}"));
+ select_all_fonts_button->set_visible(true);
+ select_full_fonts_button->set_visible(true);
+ deselect_all_fonts_button->set_visible(true);
+ } else {
+ select_fonts_label->set_text(TTR("No fonts found."));
+ select_all_fonts_button->set_visible(false);
+ select_full_fonts_button->set_visible(false);
+ deselect_all_fonts_button->set_visible(false);
+ }
+
+ if (font_size_amount > 0) {
+ Array arr;
+ arr.push_back(font_size_amount);
+ select_font_sizes_label->set_text(TTRN("One font size", "{num} font sizes", font_size_amount).format(arr, "{num}"));
+ select_all_font_sizes_button->set_visible(true);
+ select_full_font_sizes_button->set_visible(true);
+ deselect_all_font_sizes_button->set_visible(true);
+ } else {
+ select_font_sizes_label->set_text(TTR("No font sizes found."));
+ select_all_font_sizes_button->set_visible(false);
+ select_full_font_sizes_button->set_visible(false);
+ deselect_all_font_sizes_button->set_visible(false);
+ }
+
+ if (icon_amount > 0) {
+ Array arr;
+ arr.push_back(icon_amount);
+ select_icons_label->set_text(TTRN("One icon", "{num} icons", icon_amount).format(arr, "{num}"));
+ select_all_icons_button->set_visible(true);
+ select_full_icons_button->set_visible(true);
+ deselect_all_icons_button->set_visible(true);
+ select_icons_warning_hb->set_visible(true);
+ } else {
+ select_icons_label->set_text(TTR("No icons found."));
+ select_all_icons_button->set_visible(false);
+ select_full_icons_button->set_visible(false);
+ deselect_all_icons_button->set_visible(false);
+ select_icons_warning_hb->set_visible(false);
+ }
+
+ if (stylebox_amount > 0) {
+ Array arr;
+ arr.push_back(stylebox_amount);
+ select_styleboxes_label->set_text(TTRN("One stylebox", "{num} styleboxes", stylebox_amount).format(arr, "{num}"));
+ select_all_styleboxes_button->set_visible(true);
+ select_full_styleboxes_button->set_visible(true);
+ deselect_all_styleboxes_button->set_visible(true);
+ } else {
+ select_styleboxes_label->set_text(TTR("No styleboxes found."));
+ select_all_styleboxes_button->set_visible(false);
+ select_full_styleboxes_button->set_visible(false);
+ deselect_all_styleboxes_button->set_visible(false);
+ }
+}
+
+void ThemeItemImportTree::_toggle_type_items(bool p_collapse) {
+ TreeItem *root = import_items_tree->get_root();
+ if (!root) {
+ return;
+ }
+
+ TreeItem *type_node = root->get_first_child();
+ while (type_node) {
+ type_node->set_collapsed(p_collapse);
+ type_node = type_node->get_next();
+ }
+}
+
+void ThemeItemImportTree::_filter_text_changed(const String &p_value) {
+ _update_items_tree();
+}
+
+void ThemeItemImportTree::_store_selected_item(TreeItem *p_tree_item) {
+ if (!p_tree_item->get_meta("_can_be_imported")) {
+ return;
+ }
+
+ TreeItem *data_type_node = p_tree_item->get_parent();
+ if (!data_type_node || data_type_node == import_items_tree->get_root()) {
+ return;
+ }
+
+ TreeItem *type_node = data_type_node->get_parent();
+ if (!type_node || type_node == import_items_tree->get_root()) {
+ return;
+ }
+
+ ThemeItem ti;
+ ti.item_name = p_tree_item->get_text(0);
+ ti.data_type = (Theme::DataType)(int)data_type_node->get_metadata(0);
+ ti.type_name = type_node->get_text(0);
+
+ bool import = p_tree_item->is_checked(IMPORT_ITEM);
+ bool with_data = p_tree_item->is_checked(IMPORT_ITEM_DATA);
+
+ if (import && with_data) {
+ selected_items[ti] = SELECT_IMPORT_FULL;
+ } else if (import) {
+ selected_items[ti] = SELECT_IMPORT_DEFINITION;
+ } else {
+ selected_items.erase(ti);
+ }
+
+ _update_total_selected(ti.data_type);
+}
+
+void ThemeItemImportTree::_restore_selected_item(TreeItem *p_tree_item) {
+ if (!p_tree_item->get_meta("_can_be_imported")) {
+ return;
+ }
+
+ TreeItem *data_type_node = p_tree_item->get_parent();
+ if (!data_type_node || data_type_node == import_items_tree->get_root()) {
+ return;
+ }
+
+ TreeItem *type_node = data_type_node->get_parent();
+ if (!type_node || type_node == import_items_tree->get_root()) {
+ return;
+ }
+
+ ThemeItem ti;
+ ti.item_name = p_tree_item->get_text(0);
+ ti.data_type = (Theme::DataType)(int)data_type_node->get_metadata(0);
+ ti.type_name = type_node->get_text(0);
+
+ if (!selected_items.has(ti)) {
+ p_tree_item->set_checked(IMPORT_ITEM, false);
+ p_tree_item->set_checked(IMPORT_ITEM_DATA, false);
+ return;
+ }
+
+ if (selected_items[ti] == SELECT_IMPORT_FULL) {
+ p_tree_item->set_checked(IMPORT_ITEM, true);
+ p_tree_item->set_checked(IMPORT_ITEM_DATA, true);
+ } else if (selected_items[ti] == SELECT_IMPORT_DEFINITION) {
+ p_tree_item->set_checked(IMPORT_ITEM, true);
+ p_tree_item->set_checked(IMPORT_ITEM_DATA, false);
+ }
+}
+
+void ThemeItemImportTree::_update_total_selected(Theme::DataType p_data_type) {
+ ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
+
+ Label *total_selected_items_label;
+ switch (p_data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ total_selected_items_label = total_selected_colors_label;
+ break;
+
+ case Theme::DATA_TYPE_CONSTANT:
+ total_selected_items_label = total_selected_constants_label;
+ break;
+
+ case Theme::DATA_TYPE_FONT:
+ total_selected_items_label = total_selected_fonts_label;
+ break;
+
+ case Theme::DATA_TYPE_FONT_SIZE:
+ total_selected_items_label = total_selected_font_sizes_label;
+ break;
+
+ case Theme::DATA_TYPE_ICON:
+ total_selected_items_label = total_selected_icons_label;
+ break;
+
+ case Theme::DATA_TYPE_STYLEBOX:
+ total_selected_items_label = total_selected_styleboxes_label;
+ break;
+
+ case Theme::DATA_TYPE_MAX:
+ return; // Can't happen, but silences warning.
+ }
+
+ if (!total_selected_items_label) {
+ return;
+ }
+
+ int count = 0;
+ for (Map<ThemeItem, ItemCheckedState>::Element *E = selected_items.front(); E; E = E->next()) {
+ ThemeItem ti = E->key();
+ if (ti.data_type == p_data_type) {
+ count++;
+ }
+ }
+
+ if (count == 0) {
+ total_selected_items_label->hide();
+ } else {
+ Array arr;
+ arr.push_back(count);
+ total_selected_items_label->set_text(TTRN("{num} currently selected", "{num} currently selected", count).format(arr, "{num}"));
+ total_selected_items_label->show();
+ }
+}
+
+void ThemeItemImportTree::_tree_item_edited() {
+ if (updating_tree) {
+ return;
+ }
+
+ TreeItem *edited_item = import_items_tree->get_edited();
+ if (!edited_item) {
+ return;
+ }
+
+ updating_tree = true;
+
+ int edited_column = import_items_tree->get_edited_column();
+ bool is_checked = edited_item->is_checked(edited_column);
+ if (is_checked) {
+ if (edited_column == IMPORT_ITEM_DATA) {
+ edited_item->set_checked(IMPORT_ITEM, true);
+ }
+
+ _select_all_subitems(edited_item, (edited_column == IMPORT_ITEM_DATA));
+ } else {
+ if (edited_column == IMPORT_ITEM) {
+ edited_item->set_checked(IMPORT_ITEM_DATA, false);
+ }
+
+ _deselect_all_subitems(edited_item, (edited_column == IMPORT_ITEM));
+ }
+
+ _update_parent_items(edited_item);
+ _store_selected_item(edited_item);
+
+ updating_tree = false;
+}
+
+void ThemeItemImportTree::_select_all_subitems(TreeItem *p_root_item, bool p_select_with_data) {
+ TreeItem *child_item = p_root_item->get_first_child();
+ while (child_item) {
+ child_item->set_checked(IMPORT_ITEM, true);
+ if (p_select_with_data) {
+ child_item->set_checked(IMPORT_ITEM_DATA, true);
+ }
+ _store_selected_item(child_item);
+
+ _select_all_subitems(child_item, p_select_with_data);
+ child_item = child_item->get_next();
+ }
}
-void ThemeEditor::_propagate_redraw(Control *p_at) {
- p_at->notification(NOTIFICATION_THEME_CHANGED);
- p_at->minimum_size_changed();
- p_at->update();
- for (int i = 0; i < p_at->get_child_count(); i++) {
- Control *a = Object::cast_to<Control>(p_at->get_child(i));
- if (a) {
- _propagate_redraw(a);
+void ThemeItemImportTree::_deselect_all_subitems(TreeItem *p_root_item, bool p_deselect_completely) {
+ TreeItem *child_item = p_root_item->get_first_child();
+ while (child_item) {
+ child_item->set_checked(IMPORT_ITEM_DATA, false);
+ if (p_deselect_completely) {
+ child_item->set_checked(IMPORT_ITEM, false);
}
+ _store_selected_item(child_item);
+
+ _deselect_all_subitems(child_item, p_deselect_completely);
+ child_item = child_item->get_next();
}
}
-void ThemeEditor::_refresh_interval() {
- _propagate_redraw(main_panel);
- _propagate_redraw(main_container);
+void ThemeItemImportTree::_update_parent_items(TreeItem *p_root_item) {
+ TreeItem *parent_item = p_root_item->get_parent();
+ if (!parent_item) {
+ return;
+ }
+
+ bool any_checked = false;
+ bool any_checked_with_data = false;
+
+ TreeItem *child_item = parent_item->get_first_child();
+ while (child_item) {
+ if (child_item->is_checked(IMPORT_ITEM)) {
+ any_checked = true;
+ }
+ if (child_item->is_checked(IMPORT_ITEM_DATA)) {
+ any_checked_with_data = true;
+ }
+
+ child_item = child_item->get_next();
+ }
+
+ parent_item->set_checked(IMPORT_ITEM, any_checked);
+ parent_item->set_checked(IMPORT_ITEM_DATA, any_checked && any_checked_with_data);
+ _update_parent_items(parent_item);
}
-void ThemeEditor::_type_menu_cbk(int p_option) {
- type_edit->set_text(type_menu->get_popup()->get_item_text(p_option));
+void ThemeItemImportTree::_select_all_items_pressed() {
+ if (updating_tree) {
+ return;
+ }
+
+ updating_tree = true;
+
+ TreeItem *root = import_items_tree->get_root();
+ _select_all_subitems(root, false);
+
+ updating_tree = false;
}
-void ThemeEditor::_name_menu_about_to_show() {
- String fromtype = type_edit->get_text();
- List<StringName> names;
+void ThemeItemImportTree::_select_full_items_pressed() {
+ if (updating_tree) {
+ return;
+ }
+
+ updating_tree = true;
+
+ TreeItem *root = import_items_tree->get_root();
+ _select_all_subitems(root, true);
+
+ updating_tree = false;
+}
+
+void ThemeItemImportTree::_deselect_all_items_pressed() {
+ if (updating_tree) {
+ return;
+ }
+
+ updating_tree = true;
+
+ TreeItem *root = import_items_tree->get_root();
+ _deselect_all_subitems(root, true);
+
+ updating_tree = false;
+}
+
+void ThemeItemImportTree::_select_all_data_type_pressed(int p_data_type) {
+ ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
+
+ if (updating_tree) {
+ return;
+ }
+
+ Theme::DataType data_type = (Theme::DataType)p_data_type;
+ List<TreeItem *> *item_list;
+
+ switch (data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ item_list = &tree_color_items;
+ break;
+
+ case Theme::DATA_TYPE_CONSTANT:
+ item_list = &tree_constant_items;
+ break;
+
+ case Theme::DATA_TYPE_FONT:
+ item_list = &tree_font_items;
+ break;
+
+ case Theme::DATA_TYPE_FONT_SIZE:
+ item_list = &tree_font_size_items;
+ break;
+
+ case Theme::DATA_TYPE_ICON:
+ item_list = &tree_icon_items;
+ break;
+
+ case Theme::DATA_TYPE_STYLEBOX:
+ item_list = &tree_stylebox_items;
+ break;
- if (popup_mode == POPUP_ADD) {
- switch (type_select->get_selected()) {
- case 0:
- Theme::get_default()->get_icon_list(fromtype, &names);
+ case Theme::DATA_TYPE_MAX:
+ return; // Can't happen, but silences warning.
+ }
+
+ updating_tree = true;
+
+ for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {
+ TreeItem *child_item = E->get();
+ if (!child_item) {
+ continue;
+ }
+
+ child_item->set_checked(IMPORT_ITEM, true);
+ _update_parent_items(child_item);
+ _store_selected_item(child_item);
+ }
+
+ updating_tree = false;
+}
+
+void ThemeItemImportTree::_select_full_data_type_pressed(int p_data_type) {
+ ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
+
+ if (updating_tree) {
+ return;
+ }
+
+ Theme::DataType data_type = (Theme::DataType)p_data_type;
+ List<TreeItem *> *item_list;
+
+ switch (data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ item_list = &tree_color_items;
+ break;
+
+ case Theme::DATA_TYPE_CONSTANT:
+ item_list = &tree_constant_items;
+ break;
+
+ case Theme::DATA_TYPE_FONT:
+ item_list = &tree_font_items;
+ break;
+
+ case Theme::DATA_TYPE_FONT_SIZE:
+ item_list = &tree_font_size_items;
+ break;
+
+ case Theme::DATA_TYPE_ICON:
+ item_list = &tree_icon_items;
+ break;
+
+ case Theme::DATA_TYPE_STYLEBOX:
+ item_list = &tree_stylebox_items;
+ break;
+
+ case Theme::DATA_TYPE_MAX:
+ return; // Can't happen, but silences warning.
+ }
+
+ updating_tree = true;
+
+ for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {
+ TreeItem *child_item = E->get();
+ if (!child_item) {
+ continue;
+ }
+
+ child_item->set_checked(IMPORT_ITEM, true);
+ child_item->set_checked(IMPORT_ITEM_DATA, true);
+ _update_parent_items(child_item);
+ _store_selected_item(child_item);
+ }
+
+ updating_tree = false;
+}
+
+void ThemeItemImportTree::_deselect_all_data_type_pressed(int p_data_type) {
+ ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
+
+ if (updating_tree) {
+ return;
+ }
+
+ Theme::DataType data_type = (Theme::DataType)p_data_type;
+ List<TreeItem *> *item_list;
+
+ switch (data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ item_list = &tree_color_items;
+ break;
+
+ case Theme::DATA_TYPE_CONSTANT:
+ item_list = &tree_constant_items;
+ break;
+
+ case Theme::DATA_TYPE_FONT:
+ item_list = &tree_font_items;
+ break;
+
+ case Theme::DATA_TYPE_FONT_SIZE:
+ item_list = &tree_font_size_items;
+ break;
+
+ case Theme::DATA_TYPE_ICON:
+ item_list = &tree_icon_items;
+ break;
+
+ case Theme::DATA_TYPE_STYLEBOX:
+ item_list = &tree_stylebox_items;
+ break;
+
+ case Theme::DATA_TYPE_MAX:
+ return; // Can't happen, but silences warning.
+ }
+
+ updating_tree = true;
+
+ for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {
+ TreeItem *child_item = E->get();
+ if (!child_item) {
+ continue;
+ }
+
+ child_item->set_checked(IMPORT_ITEM, false);
+ child_item->set_checked(IMPORT_ITEM_DATA, false);
+ _update_parent_items(child_item);
+ _store_selected_item(child_item);
+ }
+
+ updating_tree = false;
+}
+
+void ThemeItemImportTree::_import_selected() {
+ if (selected_items.size() == 0) {
+ EditorNode::get_singleton()->show_accept(TTR("Nothing was selected for the import."), TTR("OK"));
+ return;
+ }
+
+ // Prevent changes from immediatelly being reported while the operation is still ongoing.
+ edited_theme->_freeze_change_propagation();
+ ProgressDialog::get_singleton()->add_task("import_theme_items", TTR("Importing Theme Items"), selected_items.size() + 2);
+
+ int idx = 0;
+ for (Map<ThemeItem, ItemCheckedState>::Element *E = selected_items.front(); E; E = E->next()) {
+ // Arbitrary number of items to skip from reporting.
+ // Reduces the number of UI updates that this causes when copying large themes.
+ if (idx % 10 == 0) {
+ Array arr;
+ arr.push_back(idx + 1);
+ arr.push_back(selected_items.size());
+ ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Importing items {n}/{n}").format(arr, "{n}"), idx);
+ }
+
+ ItemCheckedState cs = E->get();
+ ThemeItem ti = E->key();
+
+ if (cs == SELECT_IMPORT_DEFINITION || cs == SELECT_IMPORT_FULL) {
+ Variant item_value = Variant();
+
+ if (cs == SELECT_IMPORT_FULL) {
+ item_value = base_theme->get_theme_item(ti.data_type, ti.item_name, ti.type_name);
+ } else {
+ switch (ti.data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ item_value = Color();
+ break;
+
+ case Theme::DATA_TYPE_CONSTANT:
+ item_value = 0;
+ break;
+
+ case Theme::DATA_TYPE_FONT:
+ item_value = Ref<Font>();
+ break;
+
+ case Theme::DATA_TYPE_FONT_SIZE:
+ item_value = -1;
+ break;
+
+ case Theme::DATA_TYPE_ICON:
+ item_value = Ref<Texture2D>();
+ break;
+
+ case Theme::DATA_TYPE_STYLEBOX:
+ item_value = Ref<StyleBox>();
+ break;
+
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+ }
+
+ edited_theme->set_theme_item(ti.data_type, ti.item_name, ti.type_name, item_value);
+ }
+
+ idx++;
+ }
+
+ // Allow changes to be reported now that the operation is finished.
+ ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Updating the editor"), idx++);
+ edited_theme->_unfreeze_and_propagate_changes();
+ // Make sure the task is not ended before the editor freezes to update the Inspector.
+ ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Finalizing"), idx++);
+
+ ProgressDialog::get_singleton()->end_task("import_theme_items");
+ emit_signal("items_imported");
+}
+
+void ThemeItemImportTree::set_edited_theme(const Ref<Theme> &p_theme) {
+ edited_theme = p_theme;
+}
+
+void ThemeItemImportTree::set_base_theme(const Ref<Theme> &p_theme) {
+ base_theme = p_theme;
+}
+
+void ThemeItemImportTree::reset_item_tree() {
+ import_items_filter->clear();
+ selected_items.clear();
+
+ total_selected_colors_label->hide();
+ total_selected_constants_label->hide();
+ total_selected_fonts_label->hide();
+ total_selected_font_sizes_label->hide();
+ total_selected_icons_label->hide();
+ total_selected_styleboxes_label->hide();
+
+ _update_items_tree();
+}
+
+bool ThemeItemImportTree::has_selected_items() const {
+ return (selected_items.size() > 0);
+}
+
+void ThemeItemImportTree::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ select_icons_warning_icon->set_texture(get_theme_icon("StatusWarning", "EditorIcons"));
+ select_icons_warning->add_theme_color_override("font_color", get_theme_color("disabled_font_color", "Editor"));
+
+ // Bottom panel buttons.
+ import_collapse_types_button->set_icon(get_theme_icon("CollapseTree", "EditorIcons"));
+ import_expand_types_button->set_icon(get_theme_icon("ExpandTree", "EditorIcons"));
+
+ import_select_all_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons"));
+ import_select_full_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons"));
+ import_deselect_all_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons"));
+
+ // Side panel buttons.
+ select_colors_icon->set_texture(get_theme_icon("Color", "EditorIcons"));
+ deselect_all_colors_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons"));
+ select_all_colors_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons"));
+ select_full_colors_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons"));
+
+ select_constants_icon->set_texture(get_theme_icon("MemberConstant", "EditorIcons"));
+ deselect_all_constants_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons"));
+ select_all_constants_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons"));
+ select_full_constants_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons"));
+
+ select_fonts_icon->set_texture(get_theme_icon("Font", "EditorIcons"));
+ deselect_all_fonts_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons"));
+ select_all_fonts_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons"));
+ select_full_fonts_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons"));
+
+ select_font_sizes_icon->set_texture(get_theme_icon("FontSize", "EditorIcons"));
+ deselect_all_font_sizes_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons"));
+ select_all_font_sizes_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons"));
+ select_full_font_sizes_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons"));
+
+ select_icons_icon->set_texture(get_theme_icon("ImageTexture", "EditorIcons"));
+ deselect_all_icons_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons"));
+ select_all_icons_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons"));
+ select_full_icons_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons"));
+
+ select_styleboxes_icon->set_texture(get_theme_icon("StyleBoxFlat", "EditorIcons"));
+ deselect_all_styleboxes_button->set_icon(get_theme_icon("ThemeDeselectAll", "EditorIcons"));
+ select_all_styleboxes_button->set_icon(get_theme_icon("ThemeSelectAll", "EditorIcons"));
+ select_full_styleboxes_button->set_icon(get_theme_icon("ThemeSelectFull", "EditorIcons"));
+ } break;
+ }
+}
+
+void ThemeItemImportTree::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("items_imported"));
+}
+
+ThemeItemImportTree::ThemeItemImportTree() {
+ HBoxContainer *import_items_filter_hb = memnew(HBoxContainer);
+ add_child(import_items_filter_hb);
+ Label *import_items_filter_label = memnew(Label);
+ import_items_filter_label->set_text(TTR("Filter:"));
+ import_items_filter_hb->add_child(import_items_filter_label);
+ import_items_filter = memnew(LineEdit);
+ import_items_filter->set_clear_button_enabled(true);
+ import_items_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ import_items_filter_hb->add_child(import_items_filter);
+ import_items_filter->connect("text_changed", callable_mp(this, &ThemeItemImportTree::_filter_text_changed));
+
+ HBoxContainer *import_main_hb = memnew(HBoxContainer);
+ import_main_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ add_child(import_main_hb);
+
+ import_items_tree = memnew(Tree);
+ import_items_tree->set_hide_root(true);
+ import_items_tree->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ import_main_hb->add_child(import_items_tree);
+ import_items_tree->connect("item_edited", callable_mp(this, &ThemeItemImportTree::_tree_item_edited));
+
+ import_items_tree->set_columns(3);
+ import_items_tree->set_column_titles_visible(true);
+ import_items_tree->set_column_title(IMPORT_ITEM, TTR("Import"));
+ import_items_tree->set_column_title(IMPORT_ITEM_DATA, TTR("With Data"));
+ import_items_tree->set_column_expand(0, true);
+ import_items_tree->set_column_expand(IMPORT_ITEM, false);
+ import_items_tree->set_column_expand(IMPORT_ITEM_DATA, false);
+ import_items_tree->set_column_min_width(0, 160 * EDSCALE);
+ import_items_tree->set_column_min_width(IMPORT_ITEM, 80 * EDSCALE);
+ import_items_tree->set_column_min_width(IMPORT_ITEM_DATA, 80 * EDSCALE);
+
+ ScrollContainer *import_bulk_sc = memnew(ScrollContainer);
+ import_bulk_sc->set_custom_minimum_size(Size2(260.0, 0.0) * EDSCALE);
+ import_bulk_sc->set_enable_h_scroll(false);
+ import_main_hb->add_child(import_bulk_sc);
+ VBoxContainer *import_bulk_vb = memnew(VBoxContainer);
+ import_bulk_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ import_bulk_sc->add_child(import_bulk_vb);
+
+ Label *import_bulk_label = memnew(Label);
+ import_bulk_label->set_text(TTR("Select by data type:"));
+ import_bulk_vb->add_child(import_bulk_label);
+
+ select_colors_icon = memnew(TextureRect);
+ select_colors_label = memnew(Label);
+ deselect_all_colors_button = memnew(Button);
+ select_all_colors_button = memnew(Button);
+ select_full_colors_button = memnew(Button);
+ total_selected_colors_label = memnew(Label);
+
+ select_constants_icon = memnew(TextureRect);
+ select_constants_label = memnew(Label);
+ deselect_all_constants_button = memnew(Button);
+ select_all_constants_button = memnew(Button);
+ select_full_constants_button = memnew(Button);
+ total_selected_constants_label = memnew(Label);
+
+ select_fonts_icon = memnew(TextureRect);
+ select_fonts_label = memnew(Label);
+ deselect_all_fonts_button = memnew(Button);
+ select_all_fonts_button = memnew(Button);
+ select_full_fonts_button = memnew(Button);
+ total_selected_fonts_label = memnew(Label);
+
+ select_font_sizes_icon = memnew(TextureRect);
+ select_font_sizes_label = memnew(Label);
+ deselect_all_font_sizes_button = memnew(Button);
+ select_all_font_sizes_button = memnew(Button);
+ select_full_font_sizes_button = memnew(Button);
+ total_selected_font_sizes_label = memnew(Label);
+
+ select_icons_icon = memnew(TextureRect);
+ select_icons_label = memnew(Label);
+ deselect_all_icons_button = memnew(Button);
+ select_all_icons_button = memnew(Button);
+ select_full_icons_button = memnew(Button);
+ total_selected_icons_label = memnew(Label);
+
+ select_styleboxes_icon = memnew(TextureRect);
+ select_styleboxes_label = memnew(Label);
+ deselect_all_styleboxes_button = memnew(Button);
+ select_all_styleboxes_button = memnew(Button);
+ select_full_styleboxes_button = memnew(Button);
+ total_selected_styleboxes_label = memnew(Label);
+
+ for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {
+ Theme::DataType dt = (Theme::DataType)i;
+
+ TextureRect *select_items_icon;
+ Label *select_items_label;
+ Button *deselect_all_items_button;
+ Button *select_all_items_button;
+ Button *select_full_items_button;
+ Label *total_selected_items_label;
+
+ String items_title = "";
+ String select_all_items_tooltip = "";
+ String select_full_items_tooltip = "";
+ String deselect_all_items_tooltip = "";
+
+ switch (dt) {
+ case Theme::DATA_TYPE_COLOR:
+ select_items_icon = select_colors_icon;
+ select_items_label = select_colors_label;
+ deselect_all_items_button = deselect_all_colors_button;
+ select_all_items_button = select_all_colors_button;
+ select_full_items_button = select_full_colors_button;
+ total_selected_items_label = total_selected_colors_label;
+
+ items_title = TTR("Colors");
+ select_all_items_tooltip = TTR("Select all visible color items.");
+ select_full_items_tooltip = TTR("Select all visible color items and their data.");
+ deselect_all_items_tooltip = TTR("Deselect all visible color items.");
break;
- case 1:
- Theme::get_default()->get_stylebox_list(fromtype, &names);
+
+ case Theme::DATA_TYPE_CONSTANT:
+ select_items_icon = select_constants_icon;
+ select_items_label = select_constants_label;
+ deselect_all_items_button = deselect_all_constants_button;
+ select_all_items_button = select_all_constants_button;
+ select_full_items_button = select_full_constants_button;
+ total_selected_items_label = total_selected_constants_label;
+
+ items_title = TTR("Constants");
+ select_all_items_tooltip = TTR("Select all visible constant items.");
+ select_full_items_tooltip = TTR("Select all visible constant items and their data.");
+ deselect_all_items_tooltip = TTR("Deselect all visible constant items.");
break;
- case 2:
- Theme::get_default()->get_font_list(fromtype, &names);
+
+ case Theme::DATA_TYPE_FONT:
+ select_items_icon = select_fonts_icon;
+ select_items_label = select_fonts_label;
+ deselect_all_items_button = deselect_all_fonts_button;
+ select_all_items_button = select_all_fonts_button;
+ select_full_items_button = select_full_fonts_button;
+ total_selected_items_label = total_selected_fonts_label;
+
+ items_title = TTR("Fonts");
+ select_all_items_tooltip = TTR("Select all visible font items.");
+ select_full_items_tooltip = TTR("Select all visible font items and their data.");
+ deselect_all_items_tooltip = TTR("Deselect all visible font items.");
break;
- case 3:
- Theme::get_default()->get_font_size_list(fromtype, &names);
+
+ case Theme::DATA_TYPE_FONT_SIZE:
+ select_items_icon = select_font_sizes_icon;
+ select_items_label = select_font_sizes_label;
+ deselect_all_items_button = deselect_all_font_sizes_button;
+ select_all_items_button = select_all_font_sizes_button;
+ select_full_items_button = select_full_font_sizes_button;
+ total_selected_items_label = total_selected_font_sizes_label;
+
+ items_title = TTR("Font sizes");
+ select_all_items_tooltip = TTR("Select all visible font size items.");
+ select_full_items_tooltip = TTR("Select all visible font size items and their data.");
+ deselect_all_items_tooltip = TTR("Deselect all visible font size items.");
break;
- case 4:
- Theme::get_default()->get_color_list(fromtype, &names);
+
+ case Theme::DATA_TYPE_ICON:
+ select_items_icon = select_icons_icon;
+ select_items_label = select_icons_label;
+ deselect_all_items_button = deselect_all_icons_button;
+ select_all_items_button = select_all_icons_button;
+ select_full_items_button = select_full_icons_button;
+ total_selected_items_label = total_selected_icons_label;
+
+ items_title = TTR("Icons");
+ select_all_items_tooltip = TTR("Select all visible icon items.");
+ select_full_items_tooltip = TTR("Select all visible icon items and their data.");
+ deselect_all_items_tooltip = TTR("Deselect all visible icon items.");
break;
- case 5:
- Theme::get_default()->get_constant_list(fromtype, &names);
+
+ case Theme::DATA_TYPE_STYLEBOX:
+ select_items_icon = select_styleboxes_icon;
+ select_items_label = select_styleboxes_label;
+ deselect_all_items_button = deselect_all_styleboxes_button;
+ select_all_items_button = select_all_styleboxes_button;
+ select_full_items_button = select_full_styleboxes_button;
+ total_selected_items_label = total_selected_styleboxes_label;
+
+ items_title = TTR("Styleboxes");
+ select_all_items_tooltip = TTR("Select all visible stylebox items.");
+ select_full_items_tooltip = TTR("Select all visible stylebox items and their data.");
+ deselect_all_items_tooltip = TTR("Deselect all visible stylebox items.");
break;
+
+ case Theme::DATA_TYPE_MAX:
+ continue; // Can't happen, but silences warning.
+ }
+
+ if (i > 0) {
+ import_bulk_vb->add_child(memnew(HSeparator));
+ }
+
+ HBoxContainer *all_set = memnew(HBoxContainer);
+ import_bulk_vb->add_child(all_set);
+
+ HBoxContainer *label_set = memnew(HBoxContainer);
+ label_set->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ all_set->add_child(label_set);
+ select_items_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
+ label_set->add_child(select_items_icon);
+ select_items_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ select_items_label->set_clip_text(true);
+ select_items_label->set_text(items_title);
+ label_set->add_child(select_items_label);
+
+ HBoxContainer *button_set = memnew(HBoxContainer);
+ button_set->set_alignment(BoxContainer::ALIGN_END);
+ all_set->add_child(button_set);
+ select_all_items_button->set_flat(true);
+ select_all_items_button->set_tooltip(select_all_items_tooltip);
+ button_set->add_child(select_all_items_button);
+ select_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_all_data_type_pressed), varray(i));
+ select_full_items_button->set_flat(true);
+ select_full_items_button->set_tooltip(select_full_items_tooltip);
+ button_set->add_child(select_full_items_button);
+ select_full_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_full_data_type_pressed), varray(i));
+ deselect_all_items_button->set_flat(true);
+ deselect_all_items_button->set_tooltip(deselect_all_items_tooltip);
+ button_set->add_child(deselect_all_items_button);
+ deselect_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_data_type_pressed), varray(i));
+
+ total_selected_items_label->set_align(Label::ALIGN_RIGHT);
+ total_selected_items_label->hide();
+ import_bulk_vb->add_child(total_selected_items_label);
+
+ if (dt == Theme::DATA_TYPE_ICON) {
+ select_icons_warning_hb = memnew(HBoxContainer);
+ import_bulk_vb->add_child(select_icons_warning_hb);
+
+ select_icons_warning_icon = memnew(TextureRect);
+ select_icons_warning_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
+ select_icons_warning_hb->add_child(select_icons_warning_icon);
+
+ select_icons_warning = memnew(Label);
+ select_icons_warning->set_text(TTR("Caution: Adding icon data may considerably increase the size of your Theme resource."));
+ select_icons_warning->set_autowrap(true);
+ select_icons_warning->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ select_icons_warning_hb->add_child(select_icons_warning);
+ }
+ }
+
+ add_child(memnew(HSeparator));
+
+ HBoxContainer *import_buttons = memnew(HBoxContainer);
+ add_child(import_buttons);
+
+ import_collapse_types_button = memnew(Button);
+ import_collapse_types_button->set_flat(true);
+ import_collapse_types_button->set_tooltip(TTR("Collapse types."));
+ import_buttons->add_child(import_collapse_types_button);
+ import_collapse_types_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_toggle_type_items), varray(true));
+ import_expand_types_button = memnew(Button);
+ import_expand_types_button->set_flat(true);
+ import_expand_types_button->set_tooltip(TTR("Expand types."));
+ import_buttons->add_child(import_expand_types_button);
+ import_expand_types_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_toggle_type_items), varray(false));
+
+ import_buttons->add_child(memnew(VSeparator));
+
+ import_select_all_button = memnew(Button);
+ import_select_all_button->set_flat(true);
+ import_select_all_button->set_text(TTR("Select All"));
+ import_select_all_button->set_tooltip(TTR("Select all Theme items."));
+ import_buttons->add_child(import_select_all_button);
+ import_select_all_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_all_items_pressed));
+ import_select_full_button = memnew(Button);
+ import_select_full_button->set_flat(true);
+ import_select_full_button->set_text(TTR("Select With Data"));
+ import_select_full_button->set_tooltip(TTR("Select all Theme items with item data."));
+ import_buttons->add_child(import_select_full_button);
+ import_select_full_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_full_items_pressed));
+ import_deselect_all_button = memnew(Button);
+ import_deselect_all_button->set_flat(true);
+ import_deselect_all_button->set_text(TTR("Deselect All"));
+ import_deselect_all_button->set_tooltip(TTR("Deselect all Theme items."));
+ import_buttons->add_child(import_deselect_all_button);
+ import_deselect_all_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_items_pressed));
+
+ import_buttons->add_spacer();
+
+ Button *import_add_selected_button = memnew(Button);
+ import_add_selected_button->set_text(TTR("Import Selected"));
+ import_buttons->add_child(import_add_selected_button);
+ import_add_selected_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_import_selected));
+}
+
+void ThemeItemEditorDialog::ok_pressed() {
+ if (import_default_theme_items->has_selected_items() || import_editor_theme_items->has_selected_items() || import_other_theme_items->has_selected_items()) {
+ confirm_closing_dialog->set_text(TTR("Import Items tab has some items selected. Selection will be lost upon closing this window.\nClose anyway?"));
+ confirm_closing_dialog->popup_centered(Size2i(380, 120) * EDSCALE);
+ return;
+ }
+
+ hide();
+}
+
+void ThemeItemEditorDialog::_close_dialog() {
+ hide();
+}
+
+void ThemeItemEditorDialog::_dialog_about_to_show() {
+ ERR_FAIL_COND_MSG(edited_theme.is_null(), "Invalid state of the Theme Editor; the Theme resource is missing.");
+
+ _update_edit_types();
+
+ import_default_theme_items->set_edited_theme(edited_theme);
+ import_default_theme_items->set_base_theme(Theme::get_default());
+ import_default_theme_items->reset_item_tree();
+
+ import_editor_theme_items->set_edited_theme(edited_theme);
+ import_editor_theme_items->set_base_theme(EditorNode::get_singleton()->get_theme_base()->get_theme());
+ import_editor_theme_items->reset_item_tree();
+
+ import_other_theme_items->set_edited_theme(edited_theme);
+ import_other_theme_items->reset_item_tree();
+}
+
+void ThemeItemEditorDialog::_update_edit_types() {
+ Ref<Theme> base_theme = Theme::get_default();
+
+ List<StringName> theme_types;
+ edited_theme->get_type_list(&theme_types);
+ theme_types.sort_custom<StringName::AlphCompare>();
+
+ bool item_reselected = false;
+ edit_type_list->clear();
+ int e_idx = 0;
+ for (List<StringName>::Element *E = theme_types.front(); E; E = E->next()) {
+ Ref<Texture2D> item_icon;
+ if (E->get() == "") {
+ item_icon = get_theme_icon("NodeDisabled", "EditorIcons");
+ } else {
+ item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled");
+ }
+ edit_type_list->add_item(E->get(), item_icon);
+
+ if (E->get() == edited_item_type) {
+ edit_type_list->select(e_idx);
+ item_reselected = true;
+ }
+ e_idx++;
+ }
+ if (!item_reselected) {
+ edited_item_type = "";
+
+ if (edit_type_list->get_item_count() > 0) {
+ edit_type_list->select(0);
+ }
+ }
+
+ List<StringName> default_types;
+ base_theme->get_type_list(&default_types);
+ default_types.sort_custom<StringName::AlphCompare>();
+
+ String selected_type = "";
+ Vector<int> selected_ids = edit_type_list->get_selected_items();
+ if (selected_ids.size() > 0) {
+ selected_type = edit_type_list->get_item_text(selected_ids[0]);
+
+ edit_items_add_color->set_disabled(false);
+ edit_items_add_constant->set_disabled(false);
+ edit_items_add_font->set_disabled(false);
+ edit_items_add_font_size->set_disabled(false);
+ edit_items_add_icon->set_disabled(false);
+ edit_items_add_stylebox->set_disabled(false);
+
+ edit_items_remove_class->set_disabled(false);
+ edit_items_remove_custom->set_disabled(false);
+ edit_items_remove_all->set_disabled(false);
+ } else {
+ edit_items_add_color->set_disabled(true);
+ edit_items_add_constant->set_disabled(true);
+ edit_items_add_font->set_disabled(true);
+ edit_items_add_font_size->set_disabled(true);
+ edit_items_add_icon->set_disabled(true);
+ edit_items_add_stylebox->set_disabled(true);
+
+ edit_items_remove_class->set_disabled(true);
+ edit_items_remove_custom->set_disabled(true);
+ edit_items_remove_all->set_disabled(true);
+ }
+ _update_edit_item_tree(selected_type);
+}
+
+void ThemeItemEditorDialog::_edited_type_selected(int p_item_idx) {
+ String selected_type = edit_type_list->get_item_text(p_item_idx);
+ _update_edit_item_tree(selected_type);
+}
+
+void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) {
+ edited_item_type = p_item_type;
+
+ edit_items_tree->clear();
+ TreeItem *root = edit_items_tree->create_item();
+
+ List<StringName> names;
+
+ { // Colors.
+ names.clear();
+ edited_theme->get_color_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *color_root = edit_items_tree->create_item(root);
+ color_root->set_metadata(0, Theme::DATA_TYPE_COLOR);
+ color_root->set_icon(0, get_theme_icon("Color", "EditorIcons"));
+ color_root->set_text(0, TTR("Colors"));
+ color_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Color Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(color_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ { // Constants.
+ names.clear();
+ edited_theme->get_constant_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *constant_root = edit_items_tree->create_item(root);
+ constant_root->set_metadata(0, Theme::DATA_TYPE_CONSTANT);
+ constant_root->set_icon(0, get_theme_icon("MemberConstant", "EditorIcons"));
+ constant_root->set_text(0, TTR("Constants"));
+ constant_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Constant Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(constant_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
}
- } else if (popup_mode == POPUP_REMOVE) {
- theme->get_icon_list(fromtype, &names);
- theme->get_stylebox_list(fromtype, &names);
- theme->get_font_list(fromtype, &names);
- theme->get_font_size_list(fromtype, &names);
- theme->get_color_list(fromtype, &names);
- theme->get_constant_list(fromtype, &names);
}
- name_menu->get_popup()->clear();
- name_menu->get_popup()->set_size(Size2());
+ { // Fonts.
+ names.clear();
+ edited_theme->get_font_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *font_root = edit_items_tree->create_item(root);
+ font_root->set_metadata(0, Theme::DATA_TYPE_FONT);
+ font_root->set_icon(0, get_theme_icon("Font", "EditorIcons"));
+ font_root->set_text(0, TTR("Fonts"));
+ font_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(font_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ { // Font sizes.
+ names.clear();
+ edited_theme->get_font_size_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *font_size_root = edit_items_tree->create_item(root);
+ font_size_root->set_metadata(0, Theme::DATA_TYPE_FONT_SIZE);
+ font_size_root->set_icon(0, get_theme_icon("FontSize", "EditorIcons"));
+ font_size_root->set_text(0, TTR("Font Sizes"));
+ font_size_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Size Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(font_size_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ { // Icons.
+ names.clear();
+ edited_theme->get_icon_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *icon_root = edit_items_tree->create_item(root);
+ icon_root->set_metadata(0, Theme::DATA_TYPE_ICON);
+ icon_root->set_icon(0, get_theme_icon("ImageTexture", "EditorIcons"));
+ icon_root->set_text(0, TTR("Icons"));
+ icon_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Icon Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(icon_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ { // Styleboxes.
+ names.clear();
+ edited_theme->get_stylebox_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *stylebox_root = edit_items_tree->create_item(root);
+ stylebox_root->set_metadata(0, Theme::DATA_TYPE_STYLEBOX);
+ stylebox_root->set_icon(0, get_theme_icon("StyleBoxFlat", "EditorIcons"));
+ stylebox_root->set_text(0, TTR("Styleboxes"));
+ stylebox_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All StyleBox Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(stylebox_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+}
+
+void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_column, int p_id) {
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ if (!item) {
+ return;
+ }
+
+ switch (p_id) {
+ case ITEMS_TREE_RENAME_ITEM: {
+ String item_name = item->get_text(0);
+ int data_type = item->get_parent()->get_metadata(0);
+ _open_rename_theme_item_dialog((Theme::DataType)data_type, item_name);
+ } break;
+ case ITEMS_TREE_REMOVE_ITEM: {
+ String item_name = item->get_text(0);
+ int data_type = item->get_parent()->get_metadata(0);
+ edited_theme->clear_theme_item((Theme::DataType)data_type, item_name, edited_item_type);
+ } break;
+ case ITEMS_TREE_REMOVE_DATA_TYPE: {
+ int data_type = item->get_metadata(0);
+ _remove_data_type_items((Theme::DataType)data_type, edited_item_type);
+ } break;
+ }
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_add_theme_type() {
+ edited_theme->add_icon_type(edit_add_type_value->get_text());
+ edited_theme->add_stylebox_type(edit_add_type_value->get_text());
+ edited_theme->add_font_type(edit_add_type_value->get_text());
+ edited_theme->add_font_size_type(edit_add_type_value->get_text());
+ edited_theme->add_color_type(edit_add_type_value->get_text());
+ edited_theme->add_constant_type(edit_add_type_value->get_text());
+ _update_edit_types();
+
+ // Force emit a change so that other parts of the editor can update.
+ edited_theme->emit_changed();
+}
+
+void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) {
+ switch (p_data_type) {
+ case Theme::DATA_TYPE_ICON:
+ edited_theme->set_icon(p_item_name, p_item_type, Ref<Texture2D>());
+ break;
+ case Theme::DATA_TYPE_STYLEBOX:
+ edited_theme->set_stylebox(p_item_name, p_item_type, Ref<StyleBox>());
+ break;
+ case Theme::DATA_TYPE_FONT:
+ edited_theme->set_font(p_item_name, p_item_type, Ref<Font>());
+ break;
+ case Theme::DATA_TYPE_FONT_SIZE:
+ edited_theme->set_font_size(p_item_name, p_item_type, -1);
+ break;
+ case Theme::DATA_TYPE_COLOR:
+ edited_theme->set_color(p_item_name, p_item_type, Color());
+ break;
+ case Theme::DATA_TYPE_CONSTANT:
+ edited_theme->set_constant(p_item_name, p_item_type, 0);
+ break;
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, String p_item_type) {
+ List<StringName> names;
+
+ // Prevent changes from immediatelly being reported while the operation is still ongoing.
+ edited_theme->_freeze_change_propagation();
+
+ edited_theme->get_theme_item_list(p_data_type, p_item_type, &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- name_menu->get_popup()->add_item(E->get());
+ edited_theme->clear_theme_item(p_data_type, E->get(), p_item_type);
}
+
+ // Allow changes to be reported now that the operation is finished.
+ edited_theme->_unfreeze_and_propagate_changes();
+}
+
+void ThemeItemEditorDialog::_remove_class_items() {
+ List<StringName> names;
+
+ // Prevent changes from immediatelly being reported while the operation is still ongoing.
+ edited_theme->_freeze_change_propagation();
+
+ for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
+ Theme::DataType data_type = (Theme::DataType)dt;
+
+ names.clear();
+ Theme::get_default()->get_theme_item_list(data_type, edited_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (edited_theme->has_theme_item_nocheck(data_type, E->get(), edited_item_type)) {
+ edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
+ }
+ }
+ }
+
+ // Allow changes to be reported now that the operation is finished.
+ edited_theme->_unfreeze_and_propagate_changes();
+
+ _update_edit_item_tree(edited_item_type);
}
-void ThemeEditor::_name_menu_cbk(int p_option) {
- name_edit->set_text(name_menu->get_popup()->get_item_text(p_option));
+void ThemeItemEditorDialog::_remove_custom_items() {
+ List<StringName> names;
+
+ // Prevent changes from immediatelly being reported while the operation is still ongoing.
+ edited_theme->_freeze_change_propagation();
+
+ for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
+ Theme::DataType data_type = (Theme::DataType)dt;
+
+ names.clear();
+ edited_theme->get_theme_item_list(data_type, edited_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (!Theme::get_default()->has_theme_item_nocheck(data_type, E->get(), edited_item_type)) {
+ edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
+ }
+ }
+ }
+
+ // Allow changes to be reported now that the operation is finished.
+ edited_theme->_unfreeze_and_propagate_changes();
+
+ _update_edit_item_tree(edited_item_type);
}
-struct _TECategory {
- template <class T>
- struct RefItem {
- Ref<T> item;
- StringName name;
- bool operator<(const RefItem<T> &p) const { return item->get_instance_id() < p.item->get_instance_id(); }
- };
+void ThemeItemEditorDialog::_remove_all_items() {
+ List<StringName> names;
- template <class T>
- struct Item {
- T item;
- String name;
- bool operator<(const Item<T> &p) const { return name < p.name; }
- };
-
- Set<RefItem<StyleBox>> stylebox_items;
- Set<RefItem<Font>> font_items;
- Set<Item<int>> font_size_items;
- Set<RefItem<Texture2D>> icon_items;
-
- Set<Item<Color>> color_items;
- Set<Item<int>> constant_items;
-};
-
-void ThemeEditor::_save_template_cbk(String fname) {
- String filename = file_dialog->get_current_path();
-
- Map<String, _TECategory> categories;
-
- // Fill types.
- List<StringName> type_list;
- Theme::get_default()->get_type_list(&type_list);
- for (List<StringName>::Element *E = type_list.front(); E; E = E->next()) {
- categories.insert(E->get(), _TECategory());
- }
-
- // Fill default theme.
- for (Map<String, _TECategory>::Element *E = categories.front(); E; E = E->next()) {
- _TECategory &tc = E->get();
-
- List<StringName> stylebox_list;
- Theme::get_default()->get_stylebox_list(E->key(), &stylebox_list);
- for (List<StringName>::Element *F = stylebox_list.front(); F; F = F->next()) {
- _TECategory::RefItem<StyleBox> it;
- it.name = F->get();
- it.item = Theme::get_default()->get_stylebox(F->get(), E->key());
- tc.stylebox_items.insert(it);
- }
-
- List<StringName> font_list;
- Theme::get_default()->get_font_list(E->key(), &font_list);
- for (List<StringName>::Element *F = font_list.front(); F; F = F->next()) {
- _TECategory::RefItem<Font> it;
- it.name = F->get();
- it.item = Theme::get_default()->get_font(F->get(), E->key());
- tc.font_items.insert(it);
- }
-
- List<StringName> font_size_list;
- Theme::get_default()->get_font_size_list(E->key(), &font_list);
- for (List<StringName>::Element *F = font_size_list.front(); F; F = F->next()) {
- _TECategory::Item<int> it;
- it.name = F->get();
- it.item = Theme::get_default()->get_font_size(F->get(), E->key());
- tc.font_size_items.insert(it);
- }
-
- List<StringName> icon_list;
- Theme::get_default()->get_icon_list(E->key(), &icon_list);
- for (List<StringName>::Element *F = icon_list.front(); F; F = F->next()) {
- _TECategory::RefItem<Texture2D> it;
- it.name = F->get();
- it.item = Theme::get_default()->get_icon(F->get(), E->key());
- tc.icon_items.insert(it);
- }
-
- List<StringName> color_list;
- Theme::get_default()->get_color_list(E->key(), &color_list);
- for (List<StringName>::Element *F = color_list.front(); F; F = F->next()) {
- _TECategory::Item<Color> it;
- it.name = F->get();
- it.item = Theme::get_default()->get_color(F->get(), E->key());
- tc.color_items.insert(it);
- }
-
- List<StringName> constant_list;
- Theme::get_default()->get_constant_list(E->key(), &constant_list);
- for (List<StringName>::Element *F = constant_list.front(); F; F = F->next()) {
- _TECategory::Item<int> it;
- it.name = F->get();
- it.item = Theme::get_default()->get_constant(F->get(), E->key());
- tc.constant_items.insert(it);
- }
- }
-
- FileAccess *file = FileAccess::open(filename, FileAccess::WRITE);
-
- ERR_FAIL_COND_MSG(!file, "Can't save theme to file '" + filename + "'.");
-
- file->store_line("; ******************* ");
- file->store_line("; Template Theme File ");
- file->store_line("; ******************* ");
- file->store_line("; ");
- file->store_line("; Theme Syntax: ");
- file->store_line("; ------------- ");
- file->store_line("; ");
- file->store_line("; Must be placed in section [theme]");
- file->store_line("; ");
- file->store_line("; Type.item = [value] ");
- file->store_line("; ");
- file->store_line("; [value] examples:");
- file->store_line("; ");
- file->store_line("; Type.item = 6 ; numeric constant. ");
- file->store_line("; Type.item = #FF00FF ; HTML color (magenta).");
- file->store_line("; Type.item = #FF00FF55 ; HTML color (magenta with alpha 0x55).");
- file->store_line("; Type.item = icon(image.png) ; icon in a png file (relative to theme file).");
- file->store_line("; Type.item = font(font.xres) ; font in a resource (relative to theme file).");
- file->store_line("; Type.item = sbox(stylebox.xres) ; stylebox in a resource (relative to theme file).");
- file->store_line("; Type.item = sboxf(2,#FF00FF) ; flat stylebox with margin 2.");
- file->store_line("; Type.item = sboxf(2,#FF00FF,#FFFFFF) ; flat stylebox with margin 2 and border.");
- file->store_line("; Type.item = sboxf(2,#FF00FF,#FFFFFF,#000000) ; flat stylebox with margin 2, light & dark borders.");
- file->store_line("; Type.item = sboxt(base.png,2,2,2,2) ; textured stylebox with 3x3 stretch and stretch margins.");
- file->store_line("; -Additionally, 4 extra integers can be added to sboxf and sboxt to specify custom padding of contents:");
- file->store_line("; Type.item = sboxt(base.png,2,2,2,2,5,4,2,4) ;");
- file->store_line("; -Order for all is always left, top, right, bottom.");
- file->store_line("; ");
- file->store_line("; Special values:");
- file->store_line("; Type.item = default ; use the value in the default theme (must exist there).");
- file->store_line("; Type.item = @somebutton_color ; reference to a library value previously defined.");
- file->store_line("; ");
- file->store_line("; Library Syntax: ");
- file->store_line("; --------------- ");
- file->store_line("; ");
- file->store_line("; Must be placed in section [library], but usage is optional.");
- file->store_line("; ");
- file->store_line("; item = [value] ; same as Theme, but assign to library.");
- file->store_line("; ");
- file->store_line("; examples:");
- file->store_line("; ");
- file->store_line("; [library]");
- file->store_line("; ");
- file->store_line("; default_button_color = #FF00FF");
- file->store_line("; ");
- file->store_line("; [theme]");
- file->store_line("; ");
- file->store_line("; Button.color = @default_button_color ; used reference.");
- file->store_line("; ");
- file->store_line("; ******************* ");
- file->store_line("; ");
- file->store_line("; Template Generated Using: " + String(VERSION_FULL_BUILD));
- file->store_line("; ");
- file->store_line("; ");
- file->store_line("");
- file->store_line("[library]");
- file->store_line("");
- file->store_line("; place library stuff here");
- file->store_line("");
- file->store_line("[theme]");
- file->store_line("");
- file->store_line("");
+ // Prevent changes from immediatelly being reported while the operation is still ongoing.
+ edited_theme->_freeze_change_propagation();
- // Write default theme.
- for (Map<String, _TECategory>::Element *E = categories.front(); E; E = E->next()) {
- _TECategory &tc = E->get();
+ for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
+ Theme::DataType data_type = (Theme::DataType)dt;
- String underline = "; ";
- for (int i = 0; i < E->key().length(); i++) {
- underline += "*";
+ names.clear();
+ edited_theme->get_theme_item_list(data_type, edited_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
}
+ }
+
+ // Allow changes to be reported now that the operation is finished.
+ edited_theme->_unfreeze_and_propagate_changes();
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_open_add_theme_item_dialog(int p_data_type) {
+ ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
+
+ item_popup_mode = CREATE_THEME_ITEM;
+ edit_item_data_type = (Theme::DataType)p_data_type;
+
+ switch (edit_item_data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ edit_theme_item_dialog->set_title(TTR("Add Color Item"));
+ break;
+ case Theme::DATA_TYPE_CONSTANT:
+ edit_theme_item_dialog->set_title(TTR("Add Constant Item"));
+ break;
+ case Theme::DATA_TYPE_FONT:
+ edit_theme_item_dialog->set_title(TTR("Add Font Item"));
+ break;
+ case Theme::DATA_TYPE_FONT_SIZE:
+ edit_theme_item_dialog->set_title(TTR("Add Font Size Item"));
+ break;
+ case Theme::DATA_TYPE_ICON:
+ edit_theme_item_dialog->set_title(TTR("Add Icon Item"));
+ break;
+ case Theme::DATA_TYPE_STYLEBOX:
+ edit_theme_item_dialog->set_title(TTR("Add Stylebox Item"));
+ break;
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ edit_theme_item_old_vb->hide();
+ theme_item_name->clear();
+ edit_theme_item_dialog->popup_centered(Size2(380, 110) * EDSCALE);
+ theme_item_name->grab_focus();
+}
+
+void ThemeItemEditorDialog::_open_rename_theme_item_dialog(Theme::DataType p_data_type, String p_item_name) {
+ ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
+
+ item_popup_mode = RENAME_THEME_ITEM;
+ edit_item_data_type = p_data_type;
+ edit_item_old_name = p_item_name;
+
+ switch (edit_item_data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ edit_theme_item_dialog->set_title(TTR("Rename Color Item"));
+ break;
+ case Theme::DATA_TYPE_CONSTANT:
+ edit_theme_item_dialog->set_title(TTR("Rename Constant Item"));
+ break;
+ case Theme::DATA_TYPE_FONT:
+ edit_theme_item_dialog->set_title(TTR("Rename Font Item"));
+ break;
+ case Theme::DATA_TYPE_FONT_SIZE:
+ edit_theme_item_dialog->set_title(TTR("Rename Font Size Item"));
+ break;
+ case Theme::DATA_TYPE_ICON:
+ edit_theme_item_dialog->set_title(TTR("Rename Icon Item"));
+ break;
+ case Theme::DATA_TYPE_STYLEBOX:
+ edit_theme_item_dialog->set_title(TTR("Rename Stylebox Item"));
+ break;
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ edit_theme_item_old_vb->show();
+ theme_item_old_name->set_text(p_item_name);
+ theme_item_name->set_text(p_item_name);
+ edit_theme_item_dialog->popup_centered(Size2(380, 140) * EDSCALE);
+ theme_item_name->grab_focus();
+}
+
+void ThemeItemEditorDialog::_confirm_edit_theme_item() {
+ if (item_popup_mode == CREATE_THEME_ITEM) {
+ _add_theme_item(edit_item_data_type, theme_item_name->get_text(), edited_item_type);
+ } else if (item_popup_mode == RENAME_THEME_ITEM) {
+ edited_theme->rename_theme_item(edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type);
+ }
- file->store_line("");
- file->store_line(underline);
- file->store_line("; " + E->key());
- file->store_line(underline);
+ item_popup_mode = ITEM_POPUP_MODE_MAX;
+ edit_item_data_type = Theme::DATA_TYPE_MAX;
+ edit_item_old_name = "";
- if (tc.stylebox_items.size()) {
- file->store_line("\n; StyleBox Items:\n");
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_edit_theme_item_gui_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEventKey> k = p_event;
+
+ if (k.is_valid()) {
+ if (!k->is_pressed()) {
+ return;
}
- for (Set<_TECategory::RefItem<StyleBox>>::Element *F = tc.stylebox_items.front(); F; F = F->next()) {
- file->store_line(E->key() + "." + F->get().name + " = default");
+ switch (k->get_keycode()) {
+ case KEY_KP_ENTER:
+ case KEY_ENTER: {
+ _confirm_edit_theme_item();
+ edit_theme_item_dialog->hide();
+ edit_theme_item_dialog->set_input_as_handled();
+ } break;
+ case KEY_ESCAPE: {
+ edit_theme_item_dialog->hide();
+ edit_theme_item_dialog->set_input_as_handled();
+ } break;
+ }
+ }
+}
+
+void ThemeItemEditorDialog::_open_select_another_theme() {
+ import_another_theme_dialog->popup_file_dialog();
+}
+
+void ThemeItemEditorDialog::_select_another_theme_cbk(const String &p_path) {
+ Ref<Theme> loaded_theme = ResourceLoader::load(p_path);
+ if (loaded_theme.is_null()) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid file, not a Theme resource."));
+ return;
+ }
+ if (loaded_theme == edited_theme) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid file, same as the edited Theme resource."));
+ return;
+ }
+
+ import_another_theme_value->set_text(p_path);
+ import_other_theme_items->set_base_theme(loaded_theme);
+ import_other_theme_items->reset_item_tree();
+}
+
+void ThemeItemEditorDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ connect("about_to_popup", callable_mp(this, &ThemeItemEditorDialog::_dialog_about_to_show));
+ [[fallthrough]];
}
+ case NOTIFICATION_THEME_CHANGED: {
+ edit_items_add_color->set_icon(get_theme_icon("Color", "EditorIcons"));
+ edit_items_add_constant->set_icon(get_theme_icon("MemberConstant", "EditorIcons"));
+ edit_items_add_font->set_icon(get_theme_icon("Font", "EditorIcons"));
+ edit_items_add_font_size->set_icon(get_theme_icon("FontSize", "EditorIcons"));
+ edit_items_add_icon->set_icon(get_theme_icon("ImageTexture", "EditorIcons"));
+ edit_items_add_stylebox->set_icon(get_theme_icon("StyleBoxFlat", "EditorIcons"));
+
+ edit_items_remove_class->set_icon(get_theme_icon("Control", "EditorIcons"));
+ edit_items_remove_custom->set_icon(get_theme_icon("ThemeRemoveCustomItems", "EditorIcons"));
+ edit_items_remove_all->set_icon(get_theme_icon("ThemeRemoveAllItems", "EditorIcons"));
+
+ import_another_theme_button->set_icon(get_theme_icon("Folder", "EditorIcons"));
+
+ tc->add_theme_style_override("tab_selected", get_theme_stylebox("tab_selected_odd", "TabContainer"));
+ tc->add_theme_style_override("panel", get_theme_stylebox("panel_odd", "TabContainer"));
+ } break;
+ }
+}
- if (tc.font_items.size()) {
- file->store_line("\n; Font Items:\n");
+void ThemeItemEditorDialog::set_edited_theme(const Ref<Theme> &p_theme) {
+ edited_theme = p_theme;
+}
+
+ThemeItemEditorDialog::ThemeItemEditorDialog() {
+ set_title(TTR("Manage Theme Items"));
+ get_ok_button()->set_text(TTR("Close"));
+ set_hide_on_ok(false); // Closing may require a confirmation in some cases.
+
+ tc = memnew(TabContainer);
+ tc->set_tab_align(TabContainer::TabAlign::ALIGN_LEFT);
+ add_child(tc);
+
+ // Edit Items tab.
+ HSplitContainer *edit_dialog_hs = memnew(HSplitContainer);
+ tc->add_child(edit_dialog_hs);
+ tc->set_tab_title(0, TTR("Edit Items"));
+
+ VBoxContainer *edit_dialog_side_vb = memnew(VBoxContainer);
+ edit_dialog_side_vb->set_custom_minimum_size(Size2(200.0, 0.0) * EDSCALE);
+ edit_dialog_hs->add_child(edit_dialog_side_vb);
+
+ Label *edit_type_label = memnew(Label);
+ edit_type_label->set_text(TTR("Types:"));
+ edit_dialog_side_vb->add_child(edit_type_label);
+
+ edit_type_list = memnew(ItemList);
+ edit_type_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_dialog_side_vb->add_child(edit_type_list);
+ edit_type_list->connect("item_selected", callable_mp(this, &ThemeItemEditorDialog::_edited_type_selected));
+
+ Label *edit_add_type_label = memnew(Label);
+ edit_add_type_label->set_text(TTR("Add Type:"));
+ edit_dialog_side_vb->add_child(edit_add_type_label);
+
+ HBoxContainer *edit_add_type_hb = memnew(HBoxContainer);
+ edit_dialog_side_vb->add_child(edit_add_type_hb);
+ edit_add_type_value = memnew(LineEdit);
+ edit_add_type_value->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_add_type_hb->add_child(edit_add_type_value);
+ Button *edit_add_type_button = memnew(Button);
+ edit_add_type_button->set_text(TTR("Add"));
+ edit_add_type_hb->add_child(edit_add_type_button);
+ edit_add_type_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_add_theme_type));
+
+ VBoxContainer *edit_items_vb = memnew(VBoxContainer);
+ edit_items_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_dialog_hs->add_child(edit_items_vb);
+
+ HBoxContainer *edit_items_toolbar = memnew(HBoxContainer);
+ edit_items_vb->add_child(edit_items_toolbar);
+
+ Label *edit_items_toolbar_add_label = memnew(Label);
+ edit_items_toolbar_add_label->set_text(TTR("Add Item:"));
+ edit_items_toolbar->add_child(edit_items_toolbar_add_label);
+
+ edit_items_add_color = memnew(Button);
+ edit_items_add_color->set_tooltip(TTR("Add Color Item"));
+ edit_items_add_color->set_flat(true);
+ edit_items_add_color->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_color);
+ edit_items_add_color->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_COLOR));
+
+ edit_items_add_constant = memnew(Button);
+ edit_items_add_constant->set_tooltip(TTR("Add Constant Item"));
+ edit_items_add_constant->set_flat(true);
+ edit_items_add_constant->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_constant);
+ edit_items_add_constant->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_CONSTANT));
+
+ edit_items_add_font = memnew(Button);
+ edit_items_add_font->set_tooltip(TTR("Add Font Item"));
+ edit_items_add_font->set_flat(true);
+ edit_items_add_font->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_font);
+ edit_items_add_font->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_FONT));
+
+ edit_items_add_font_size = memnew(Button);
+ edit_items_add_font_size->set_tooltip(TTR("Add Font Size Item"));
+ edit_items_add_font_size->set_flat(true);
+ edit_items_add_font_size->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_font_size);
+ edit_items_add_font_size->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_FONT_SIZE));
+
+ edit_items_add_icon = memnew(Button);
+ edit_items_add_icon->set_tooltip(TTR("Add Icon Item"));
+ edit_items_add_icon->set_flat(true);
+ edit_items_add_icon->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_icon);
+ edit_items_add_icon->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_ICON));
+
+ edit_items_add_stylebox = memnew(Button);
+ edit_items_add_stylebox->set_tooltip(TTR("Add StyleBox Item"));
+ edit_items_add_stylebox->set_flat(true);
+ edit_items_add_stylebox->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_stylebox);
+ edit_items_add_stylebox->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_STYLEBOX));
+
+ edit_items_toolbar->add_child(memnew(VSeparator));
+
+ Label *edit_items_toolbar_remove_label = memnew(Label);
+ edit_items_toolbar_remove_label->set_text(TTR("Remove Items:"));
+ edit_items_toolbar->add_child(edit_items_toolbar_remove_label);
+
+ edit_items_remove_class = memnew(Button);
+ edit_items_remove_class->set_tooltip(TTR("Remove Class Items"));
+ edit_items_remove_class->set_flat(true);
+ edit_items_remove_class->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_remove_class);
+ edit_items_remove_class->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_class_items));
+
+ edit_items_remove_custom = memnew(Button);
+ edit_items_remove_custom->set_tooltip(TTR("Remove Custom Items"));
+ edit_items_remove_custom->set_flat(true);
+ edit_items_remove_custom->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_remove_custom);
+ edit_items_remove_custom->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_custom_items));
+
+ edit_items_remove_all = memnew(Button);
+ edit_items_remove_all->set_tooltip(TTR("Remove All Items"));
+ edit_items_remove_all->set_flat(true);
+ edit_items_remove_all->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_remove_all);
+ edit_items_remove_all->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_all_items));
+
+ edit_items_tree = memnew(Tree);
+ edit_items_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_items_tree->set_hide_root(true);
+ edit_items_tree->set_columns(1);
+ edit_items_vb->add_child(edit_items_tree);
+ edit_items_tree->connect("button_pressed", callable_mp(this, &ThemeItemEditorDialog::_item_tree_button_pressed));
+
+ edit_theme_item_dialog = memnew(ConfirmationDialog);
+ edit_theme_item_dialog->set_title(TTR("Add Theme Item"));
+ add_child(edit_theme_item_dialog);
+ VBoxContainer *edit_theme_item_vb = memnew(VBoxContainer);
+ edit_theme_item_dialog->add_child(edit_theme_item_vb);
+
+ edit_theme_item_old_vb = memnew(VBoxContainer);
+ edit_theme_item_vb->add_child(edit_theme_item_old_vb);
+ Label *edit_theme_item_old = memnew(Label);
+ edit_theme_item_old->set_text(TTR("Old Name:"));
+ edit_theme_item_old_vb->add_child(edit_theme_item_old);
+ theme_item_old_name = memnew(Label);
+ edit_theme_item_old_vb->add_child(theme_item_old_name);
+
+ Label *edit_theme_item_label = memnew(Label);
+ edit_theme_item_label->set_text(TTR("Name:"));
+ edit_theme_item_vb->add_child(edit_theme_item_label);
+ theme_item_name = memnew(LineEdit);
+ edit_theme_item_vb->add_child(theme_item_name);
+ theme_item_name->connect("gui_input", callable_mp(this, &ThemeItemEditorDialog::_edit_theme_item_gui_input));
+ edit_theme_item_dialog->connect("confirmed", callable_mp(this, &ThemeItemEditorDialog::_confirm_edit_theme_item));
+
+ // Import Items tab.
+ TabContainer *import_tc = memnew(TabContainer);
+ tc->add_child(import_tc);
+ tc->set_tab_title(1, TTR("Import Items"));
+
+ import_default_theme_items = memnew(ThemeItemImportTree);
+ import_tc->add_child(import_default_theme_items);
+ import_tc->set_tab_title(0, TTR("Default Theme"));
+ import_default_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types));
+
+ import_editor_theme_items = memnew(ThemeItemImportTree);
+ import_tc->add_child(import_editor_theme_items);
+ import_tc->set_tab_title(1, TTR("Editor Theme"));
+ import_editor_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types));
+
+ VBoxContainer *import_another_theme_vb = memnew(VBoxContainer);
+
+ HBoxContainer *import_another_file_hb = memnew(HBoxContainer);
+ import_another_theme_vb->add_child(import_another_file_hb);
+ import_another_theme_value = memnew(LineEdit);
+ import_another_theme_value->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ import_another_theme_value->set_editable(false);
+ import_another_file_hb->add_child(import_another_theme_value);
+ import_another_theme_button = memnew(Button);
+ import_another_file_hb->add_child(import_another_theme_button);
+ import_another_theme_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_select_another_theme));
+
+ import_another_theme_dialog = memnew(EditorFileDialog);
+ import_another_theme_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
+ import_another_theme_dialog->set_title(TTR("Select Another Theme Resource:"));
+ List<String> ext;
+ ResourceLoader::get_recognized_extensions_for_type("Theme", &ext);
+ for (List<String>::Element *E = ext.front(); E; E = E->next()) {
+ import_another_theme_dialog->add_filter("*." + E->get() + "; Theme Resource");
+ }
+ import_another_file_hb->add_child(import_another_theme_dialog);
+ import_another_theme_dialog->connect("file_selected", callable_mp(this, &ThemeItemEditorDialog::_select_another_theme_cbk));
+
+ import_other_theme_items = memnew(ThemeItemImportTree);
+ import_other_theme_items->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ import_another_theme_vb->add_child(import_other_theme_items);
+
+ import_tc->add_child(import_another_theme_vb);
+ import_tc->set_tab_title(2, TTR("Another Theme"));
+ import_other_theme_items->connect("items_imported", callable_mp(this, &ThemeItemEditorDialog::_update_edit_types));
+
+ confirm_closing_dialog = memnew(ConfirmationDialog);
+ confirm_closing_dialog->set_autowrap(true);
+ add_child(confirm_closing_dialog);
+ confirm_closing_dialog->connect("confirmed", callable_mp(this, &ThemeItemEditorDialog::_close_dialog));
+}
+
+VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) {
+ VBoxContainer *items_tab = memnew(VBoxContainer);
+ items_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE);
+ data_type_tabs->add_child(items_tab);
+ data_type_tabs->set_tab_title(data_type_tabs->get_tab_count() - 1, "");
+
+ ScrollContainer *items_sc = memnew(ScrollContainer);
+ items_sc->set_v_size_flags(SIZE_EXPAND_FILL);
+ items_sc->set_enable_h_scroll(false);
+ items_tab->add_child(items_sc);
+ VBoxContainer *items_list = memnew(VBoxContainer);
+ items_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ items_sc->add_child(items_list);
+
+ HBoxContainer *item_add_hb = memnew(HBoxContainer);
+ items_tab->add_child(item_add_hb);
+ LineEdit *item_add_edit = memnew(LineEdit);
+ item_add_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_add_hb->add_child(item_add_edit);
+ item_add_edit->connect("text_entered", callable_mp(this, &ThemeTypeEditor::_item_add_lineedit_cbk), varray(p_data_type, item_add_edit));
+ Button *item_add_button = memnew(Button);
+ item_add_button->set_text(TTR("Add"));
+ item_add_hb->add_child(item_add_button);
+ item_add_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_add_cbk), varray(p_data_type, item_add_edit));
+
+ return items_list;
+}
+
+void ThemeTypeEditor::_update_type_list() {
+ ERR_FAIL_COND(edited_theme.is_null());
+
+ if (updating) {
+ return;
+ }
+ updating = true;
+
+ Control *focused = get_focus_owner();
+ if (focused) {
+ if (focusables.has(focused)) {
+ // If focus is currently on one of the internal property editors, don't update.
+ updating = false;
+ return;
}
- for (Set<_TECategory::RefItem<Font>>::Element *F = tc.font_items.front(); F; F = F->next()) {
- file->store_line(E->key() + "." + F->get().name + " = default");
+ Node *focus_parent = focused->get_parent();
+ while (focus_parent) {
+ Control *c = Object::cast_to<Control>(focus_parent);
+ if (c && focusables.has(c)) {
+ // If focus is currently on one of the internal property editors, don't update.
+ updating = false;
+ return;
+ }
+
+ focus_parent = focus_parent->get_parent();
}
+ }
+
+ List<StringName> theme_types;
+ edited_theme->get_type_list(&theme_types);
+ theme_types.sort_custom<StringName::AlphCompare>();
+
+ theme_type_list->clear();
- if (tc.font_size_items.size()) {
- file->store_line("\n; Font Size Items:\n");
+ if (theme_types.size() > 0) {
+ theme_type_list->set_disabled(false);
+
+ bool item_reselected = false;
+ int e_idx = 0;
+ for (List<StringName>::Element *E = theme_types.front(); E; E = E->next()) {
+ Ref<Texture2D> item_icon;
+ if (E->get() == "") {
+ item_icon = get_theme_icon("NodeDisabled", "EditorIcons");
+ } else {
+ item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled");
+ }
+ theme_type_list->add_icon_item(item_icon, E->get());
+
+ if (E->get() == edited_type) {
+ theme_type_list->select(e_idx);
+ item_reselected = true;
+ }
+ e_idx++;
}
- for (Set<_TECategory::Item<int>>::Element *F = tc.font_size_items.front(); F; F = F->next()) {
- file->store_line(E->key() + "." + F->get().name + " = default");
- }
-
- 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()) {
- file->store_line(E->key() + "." + F->get().name + " = default");
+ if (!item_reselected) {
+ theme_type_list->select(0);
+ _list_type_selected(0);
+ } else {
+ _update_type_items();
}
+ } else {
+ theme_type_list->set_disabled(true);
+ theme_type_list->add_item(TTR("None"));
- if (tc.color_items.size()) {
- file->store_line("\n; Color Items:\n");
+ edited_type = "";
+ _update_type_items();
+ }
+
+ updating = false;
+}
+
+void ThemeTypeEditor::_update_type_list_debounced() {
+ update_debounce_timer->start();
+}
+
+void ThemeTypeEditor::_update_add_type_options(const String &p_filter) {
+ add_type_options->clear();
+
+ List<StringName> names;
+ Theme::get_default()->get_type_list(&names);
+ names.sort_custom<StringName::AlphCompare>();
+
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (!p_filter.is_subsequence_ofi(String(E->get()))) {
+ continue;
}
- for (Set<_TECategory::Item<Color>>::Element *F = tc.color_items.front(); F; F = F->next()) {
- file->store_line(E->key() + "." + F->get().name + " = default");
+ Ref<Texture2D> item_icon;
+ if (E->get() == "") {
+ item_icon = get_theme_icon("NodeDisabled", "EditorIcons");
+ } else {
+ item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled");
}
- if (tc.constant_items.size()) {
- file->store_line("\n; Constant Items:\n");
+ add_type_options->add_item(E->get(), item_icon);
+ }
+}
+
+OrderedHashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default) {
+ OrderedHashMap<StringName, bool> items;
+ List<StringName> names;
+
+ if (include_default) {
+ names.clear();
+ (Theme::get_default().operator->()->*get_list_func)(p_type_name, &names);
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ items[E->get()] = false;
}
+ }
- for (Set<_TECategory::Item<int>>::Element *F = tc.constant_items.front(); F; F = F->next()) {
- file->store_line(E->key() + "." + F->get().name + " = default");
+ {
+ names.clear();
+ (edited_theme.operator->()->*get_list_func)(p_type_name, &names);
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ items[E->get()] = true;
}
}
- file->close();
- memdelete(file);
+ List<StringName> keys;
+ for (OrderedHashMap<StringName, bool>::Element E = items.front(); E; E = E.next()) {
+ keys.push_back(E.key());
+ }
+ keys.sort_custom<StringName::AlphCompare>();
+
+ OrderedHashMap<StringName, bool> ordered_items;
+ for (List<StringName>::Element *E = keys.front(); E; E = E->next()) {
+ ordered_items[E->get()] = items[E->get()];
+ }
+
+ return ordered_items;
}
-void ThemeEditor::_dialog_cbk() {
- switch (popup_mode) {
- case POPUP_ADD: {
- switch (type_select->get_selected()) {
- case 0:
- theme->set_icon(name_edit->get_text(), type_edit->get_text(), Ref<Texture2D>());
- break;
- case 1:
- theme->set_stylebox(name_edit->get_text(), type_edit->get_text(), Ref<StyleBox>());
- break;
- case 2:
- theme->set_font(name_edit->get_text(), type_edit->get_text(), Ref<Font>());
- break;
- case 3:
- theme->set_font_size(name_edit->get_text(), type_edit->get_text(), -1);
- break;
- case 4:
- theme->set_color(name_edit->get_text(), type_edit->get_text(), Color());
- break;
- case 5:
- theme->set_constant(name_edit->get_text(), type_edit->get_text(), 0);
- break;
+HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_type, String p_item_name, bool p_editable) {
+ HBoxContainer *item_control = memnew(HBoxContainer);
+
+ HBoxContainer *item_name_container = memnew(HBoxContainer);
+ item_name_container->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_name_container->set_stretch_ratio(2.0);
+ item_control->add_child(item_name_container);
+
+ Label *item_name = memnew(Label);
+ item_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_name->set_clip_text(true);
+ item_name->set_text(p_item_name);
+ item_name->set_tooltip(p_item_name);
+ item_name_container->add_child(item_name);
+
+ if (p_editable) {
+ LineEdit *item_name_edit = memnew(LineEdit);
+ item_name_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_name_edit->set_text(p_item_name);
+ item_name_container->add_child(item_name_edit);
+ item_name_edit->connect("text_entered", callable_mp(this, &ThemeTypeEditor::_item_rename_entered), varray(p_data_type, p_item_name, item_name_container));
+ item_name_edit->hide();
+
+ Button *item_rename_button = memnew(Button);
+ item_rename_button->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ item_rename_button->set_tooltip(TTR("Rename Item"));
+ item_rename_button->set_flat(true);
+ item_name_container->add_child(item_rename_button);
+ item_rename_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_cbk), varray(p_data_type, p_item_name, item_name_container));
+
+ Button *item_remove_button = memnew(Button);
+ item_remove_button->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ item_remove_button->set_tooltip(TTR("Remove Item"));
+ item_remove_button->set_flat(true);
+ item_name_container->add_child(item_remove_button);
+ item_remove_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_remove_cbk), varray(p_data_type, p_item_name));
+
+ Button *item_rename_confirm_button = memnew(Button);
+ item_rename_confirm_button->set_icon(get_theme_icon("ImportCheck", "EditorIcons"));
+ item_rename_confirm_button->set_tooltip(TTR("Confirm Item Rename"));
+ item_rename_confirm_button->set_flat(true);
+ item_name_container->add_child(item_rename_confirm_button);
+ item_rename_confirm_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_confirmed), varray(p_data_type, p_item_name, item_name_container));
+ item_rename_confirm_button->hide();
+
+ Button *item_rename_cancel_button = memnew(Button);
+ item_rename_cancel_button->set_icon(get_theme_icon("ImportFail", "EditorIcons"));
+ item_rename_cancel_button->set_tooltip(TTR("Cancel Item Rename"));
+ item_rename_cancel_button->set_flat(true);
+ item_name_container->add_child(item_rename_cancel_button);
+ item_rename_cancel_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_canceled), varray(p_data_type, p_item_name, item_name_container));
+ item_rename_cancel_button->hide();
+ } else {
+ item_name->add_theme_color_override("font_color", get_theme_color("disabled_font_color", "Editor"));
+
+ Button *item_override_button = memnew(Button);
+ item_override_button->set_icon(get_theme_icon("Add", "EditorIcons"));
+ item_override_button->set_tooltip(TTR("Override Item"));
+ item_override_button->set_flat(true);
+ item_name_container->add_child(item_override_button);
+ item_override_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_override_cbk), varray(p_data_type, p_item_name));
+ }
+
+ return item_control;
+}
+
+void ThemeTypeEditor::_add_focusable(Control *p_control) {
+ focusables.append(p_control);
+}
+
+void ThemeTypeEditor::_update_type_items() {
+ bool show_default = show_default_items_button->is_pressed();
+ List<StringName> names;
+
+ focusables.clear();
+
+ // Colors.
+ {
+ for (int i = color_items_list->get_child_count() - 1; i >= 0; i--) {
+ Node *node = color_items_list->get_child(i);
+ node->queue_delete();
+ color_items_list->remove_child(node);
+ }
+
+ OrderedHashMap<StringName, bool> color_items = _get_type_items(edited_type, &Theme::get_color_list, show_default);
+ for (OrderedHashMap<StringName, bool>::Element E = color_items.front(); E; E = E.next()) {
+ HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_COLOR, E.key(), E.get());
+ ColorPickerButton *item_editor = memnew(ColorPickerButton);
+ item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_control->add_child(item_editor);
+
+ if (E.get()) {
+ item_editor->set_pick_color(edited_theme->get_color(E.key(), edited_type));
+ item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed), varray(E.key()));
+ } else {
+ item_editor->set_pick_color(Theme::get_default()->get_color(E.key(), edited_type));
+ item_editor->set_disabled(true);
}
- } break;
- case POPUP_CLASS_ADD: {
- StringName fromtype = type_edit->get_text();
- List<StringName> names;
-
- {
- names.clear();
- Theme::get_default()->get_icon_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_icon(E->get(), fromtype, Ref<Texture2D>());
- }
+ _add_focusable(item_editor);
+ color_items_list->add_child(item_control);
+ }
+ }
+
+ // Constants.
+ {
+ for (int i = constant_items_list->get_child_count() - 1; i >= 0; i--) {
+ Node *node = constant_items_list->get_child(i);
+ node->queue_delete();
+ constant_items_list->remove_child(node);
+ }
+
+ OrderedHashMap<StringName, bool> constant_items = _get_type_items(edited_type, &Theme::get_constant_list, show_default);
+ for (OrderedHashMap<StringName, bool>::Element E = constant_items.front(); E; E = E.next()) {
+ HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_CONSTANT, E.key(), E.get());
+ SpinBox *item_editor = memnew(SpinBox);
+ item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_editor->set_min(-100000);
+ item_editor->set_max(100000);
+ item_editor->set_step(1);
+ item_editor->set_allow_lesser(true);
+ item_editor->set_allow_greater(true);
+ item_control->add_child(item_editor);
+
+ if (E.get()) {
+ item_editor->set_value(edited_theme->get_constant(E.key(), edited_type));
+ item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_constant_item_changed), varray(E.key()));
+ } else {
+ item_editor->set_value(Theme::get_default()->get_constant(E.key(), edited_type));
+ item_editor->set_editable(false);
}
- {
- names.clear();
- Theme::get_default()->get_stylebox_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_stylebox(E->get(), fromtype, Ref<StyleBox>());
+
+ _add_focusable(item_editor);
+ constant_items_list->add_child(item_control);
+ }
+ }
+
+ // Fonts.
+ {
+ for (int i = font_items_list->get_child_count() - 1; i >= 0; i--) {
+ Node *node = font_items_list->get_child(i);
+ node->queue_delete();
+ font_items_list->remove_child(node);
+ }
+
+ OrderedHashMap<StringName, bool> font_items = _get_type_items(edited_type, &Theme::get_font_list, show_default);
+ for (OrderedHashMap<StringName, bool>::Element E = font_items.front(); E; E = E.next()) {
+ HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT, E.key(), E.get());
+ EditorResourcePicker *item_editor = memnew(EditorResourcePicker);
+ item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_editor->set_base_type("Font");
+ item_control->add_child(item_editor);
+
+ if (E.get()) {
+ if (edited_theme->has_font(E.key(), edited_type)) {
+ item_editor->set_edited_resource(edited_theme->get_font(E.key(), edited_type));
+ } else {
+ item_editor->set_edited_resource(RES());
}
- }
- {
- names.clear();
- Theme::get_default()->get_font_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_font(E->get(), fromtype, Ref<Font>());
+ item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item), varray(item_control));
+ item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed), varray(E.key()));
+ } else {
+ if (Theme::get_default()->has_font(E.key(), edited_type)) {
+ item_editor->set_edited_resource(Theme::get_default()->get_font(E.key(), edited_type));
+ } else {
+ item_editor->set_edited_resource(RES());
}
+ item_editor->set_editable(false);
}
- {
- names.clear();
- Theme::get_default()->get_font_size_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_font_size(E->get(), fromtype, Theme::get_default()->get_font_size(E->get(), fromtype));
- }
+
+ _add_focusable(item_editor);
+ font_items_list->add_child(item_control);
+ }
+ }
+
+ // Fonts sizes.
+ {
+ for (int i = font_size_items_list->get_child_count() - 1; i >= 0; i--) {
+ Node *node = font_size_items_list->get_child(i);
+ node->queue_delete();
+ font_size_items_list->remove_child(node);
+ }
+
+ OrderedHashMap<StringName, bool> font_size_items = _get_type_items(edited_type, &Theme::get_font_size_list, show_default);
+ for (OrderedHashMap<StringName, bool>::Element E = font_size_items.front(); E; E = E.next()) {
+ HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT_SIZE, E.key(), E.get());
+ SpinBox *item_editor = memnew(SpinBox);
+ item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_editor->set_min(-100000);
+ item_editor->set_max(100000);
+ item_editor->set_step(1);
+ item_editor->set_allow_lesser(true);
+ item_editor->set_allow_greater(true);
+ item_control->add_child(item_editor);
+
+ if (E.get()) {
+ item_editor->set_value(edited_theme->get_font_size(E.key(), edited_type));
+ item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_font_size_item_changed), varray(E.key()));
+ } else {
+ item_editor->set_value(Theme::get_default()->get_font_size(E.key(), edited_type));
+ item_editor->set_editable(false);
}
- {
- names.clear();
- Theme::get_default()->get_color_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_color(E->get(), fromtype, Theme::get_default()->get_color(E->get(), fromtype));
+
+ _add_focusable(item_editor);
+ font_size_items_list->add_child(item_control);
+ }
+ }
+
+ // Icons.
+ {
+ for (int i = icon_items_list->get_child_count() - 1; i >= 0; i--) {
+ Node *node = icon_items_list->get_child(i);
+ node->queue_delete();
+ icon_items_list->remove_child(node);
+ }
+
+ OrderedHashMap<StringName, bool> icon_items = _get_type_items(edited_type, &Theme::get_icon_list, show_default);
+ for (OrderedHashMap<StringName, bool>::Element E = icon_items.front(); E; E = E.next()) {
+ HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_ICON, E.key(), E.get());
+ EditorResourcePicker *item_editor = memnew(EditorResourcePicker);
+ item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_editor->set_base_type("Texture2D");
+ item_control->add_child(item_editor);
+
+ if (E.get()) {
+ if (edited_theme->has_icon(E.key(), edited_type)) {
+ item_editor->set_edited_resource(edited_theme->get_icon(E.key(), edited_type));
+ } else {
+ item_editor->set_edited_resource(RES());
}
- }
- {
- names.clear();
- Theme::get_default()->get_constant_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_constant(E->get(), fromtype, Theme::get_default()->get_constant(E->get(), fromtype));
+ item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item), varray(item_control));
+ item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed), varray(E.key()));
+ } else {
+ if (Theme::get_default()->has_icon(E.key(), edited_type)) {
+ item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key(), edited_type));
+ } else {
+ item_editor->set_edited_resource(RES());
}
+ item_editor->set_editable(false);
}
- } break;
- case POPUP_REMOVE: {
- switch (type_select->get_selected()) {
- case 0:
- theme->clear_icon(name_edit->get_text(), type_edit->get_text());
- break;
- case 1:
- theme->clear_stylebox(name_edit->get_text(), type_edit->get_text());
- break;
- case 2:
- theme->clear_font(name_edit->get_text(), type_edit->get_text());
- break;
- case 3:
- theme->clear_font_size(name_edit->get_text(), type_edit->get_text());
- break;
- case 4:
- theme->clear_color(name_edit->get_text(), type_edit->get_text());
- break;
- case 5:
- theme->clear_constant(name_edit->get_text(), type_edit->get_text());
- break;
+
+ _add_focusable(item_editor);
+ icon_items_list->add_child(item_control);
+ }
+ }
+
+ // Styleboxes.
+ {
+ for (int i = stylebox_items_list->get_child_count() - 1; i >= 0; i--) {
+ Node *node = stylebox_items_list->get_child(i);
+ node->queue_delete();
+ stylebox_items_list->remove_child(node);
+ }
+
+ if (leading_stylebox.pinned) {
+ HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, leading_stylebox.item_name, true);
+ EditorResourcePicker *item_editor = memnew(EditorResourcePicker);
+ item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_editor->set_stretch_ratio(1.5);
+ item_editor->set_base_type("StyleBox");
+
+ Button *pin_leader_button = memnew(Button);
+ pin_leader_button->set_flat(true);
+ pin_leader_button->set_toggle_mode(true);
+ pin_leader_button->set_pressed(true);
+ pin_leader_button->set_icon(get_theme_icon("Pin", "EditorIcons"));
+ pin_leader_button->set_tooltip(TTR("Unpin this StyleBox as a main style."));
+ item_control->add_child(pin_leader_button);
+ pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_unpin_leading_stylebox));
+
+ item_control->add_child(item_editor);
+
+ if (leading_stylebox.stylebox.is_valid()) {
+ item_editor->set_edited_resource(leading_stylebox.stylebox);
+ } else {
+ item_editor->set_edited_resource(RES());
}
+ item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item), varray(item_control));
+ item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed), varray(leading_stylebox.item_name));
- } break;
- case POPUP_CLASS_REMOVE: {
- StringName fromtype = type_edit->get_text();
- List<StringName> names;
-
- {
- names.clear();
- Theme::get_default()->get_icon_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_icon(E->get(), fromtype);
- }
+ stylebox_items_list->add_child(item_control);
+ stylebox_items_list->add_child(memnew(HSeparator));
+ }
+
+ OrderedHashMap<StringName, bool> stylebox_items = _get_type_items(edited_type, &Theme::get_stylebox_list, show_default);
+ for (OrderedHashMap<StringName, bool>::Element E = stylebox_items.front(); E; E = E.next()) {
+ if (leading_stylebox.pinned && leading_stylebox.item_name == E.key()) {
+ continue;
}
- {
- names.clear();
- Theme::get_default()->get_stylebox_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_stylebox(E->get(), fromtype);
+
+ HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, E.key(), E.get());
+ EditorResourcePicker *item_editor = memnew(EditorResourcePicker);
+ item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ item_editor->set_stretch_ratio(1.5);
+ item_editor->set_base_type("StyleBox");
+
+ if (E.get()) {
+ Ref<StyleBox> stylebox_value;
+ if (edited_theme->has_stylebox(E.key(), edited_type)) {
+ stylebox_value = edited_theme->get_stylebox(E.key(), edited_type);
+ item_editor->set_edited_resource(stylebox_value);
+ } else {
+ item_editor->set_edited_resource(RES());
}
- }
- {
- names.clear();
- Theme::get_default()->get_font_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_font(E->get(), fromtype);
+ item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item), varray(item_control));
+ item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed), varray(E.key()));
+
+ Button *pin_leader_button = memnew(Button);
+ pin_leader_button->set_flat(true);
+ pin_leader_button->set_toggle_mode(true);
+ pin_leader_button->set_icon(get_theme_icon("Pin", "EditorIcons"));
+ pin_leader_button->set_tooltip(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type."));
+ item_control->add_child(pin_leader_button);
+ pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_pin_leading_stylebox), varray(stylebox_value, E.key()));
+ } else {
+ if (Theme::get_default()->has_stylebox(E.key(), edited_type)) {
+ item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key(), edited_type));
+ } else {
+ item_editor->set_edited_resource(RES());
}
+ item_editor->set_editable(false);
}
- {
- names.clear();
- Theme::get_default()->get_font_size_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_font_size(E->get(), fromtype);
- }
+
+ item_control->add_child(item_editor);
+ _add_focusable(item_editor);
+ stylebox_items_list->add_child(item_control);
+ }
+ }
+}
+
+void ThemeTypeEditor::_list_type_selected(int p_index) {
+ edited_type = theme_type_list->get_item_text(p_index);
+ _update_type_items();
+}
+
+void ThemeTypeEditor::_add_type_button_cbk() {
+ add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);
+ add_type_filter->grab_focus();
+}
+
+void ThemeTypeEditor::_add_type_filter_cbk(const String &p_value) {
+ _update_add_type_options(p_value);
+}
+
+void ThemeTypeEditor::_add_type_options_cbk(int p_index) {
+ add_type_filter->set_text(add_type_options->get_item_text(p_index));
+}
+
+void ThemeTypeEditor::_add_type_dialog_confirmed() {
+ select_type(add_type_filter->get_text().strip_edges());
+}
+
+void ThemeTypeEditor::_add_type_dialog_entered(const String &p_value) {
+ select_type(p_value.strip_edges());
+ add_type_dialog->hide();
+}
+
+void ThemeTypeEditor::_add_type_dialog_activated(int p_index) {
+ select_type(add_type_options->get_item_text(p_index));
+ add_type_dialog->hide();
+}
+
+void ThemeTypeEditor::_add_default_type_items() {
+ List<StringName> names;
+
+ updating = true;
+ // Prevent changes from immediatelly being reported while the operation is still ongoing.
+ edited_theme->_freeze_change_propagation();
+
+ {
+ names.clear();
+ Theme::get_default()->get_icon_list(edited_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (!edited_theme->has_icon(E->get(), edited_type)) {
+ edited_theme->set_icon(E->get(), edited_type, Ref<Texture2D>());
}
- {
- names.clear();
- Theme::get_default()->get_color_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_color(E->get(), fromtype);
- }
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_stylebox_list(edited_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (!edited_theme->has_stylebox(E->get(), edited_type)) {
+ edited_theme->set_stylebox(E->get(), edited_type, Ref<StyleBox>());
}
- {
- names.clear();
- Theme::get_default()->get_constant_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_constant(E->get(), fromtype);
- }
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_font_list(edited_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (!edited_theme->has_font(E->get(), edited_type)) {
+ edited_theme->set_font(E->get(), edited_type, Ref<Font>());
+ }
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_font_size_list(edited_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (!edited_theme->has_font_size(E->get(), edited_type)) {
+ edited_theme->set_font_size(E->get(), edited_type, Theme::get_default()->get_font_size(E->get(), edited_type));
}
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_color_list(edited_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (!edited_theme->has_color(E->get(), edited_type)) {
+ edited_theme->set_color(E->get(), edited_type, Theme::get_default()->get_color(E->get(), edited_type));
+ }
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_constant_list(edited_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (!edited_theme->has_constant(E->get(), edited_type)) {
+ edited_theme->set_constant(E->get(), edited_type, Theme::get_default()->get_constant(E->get(), edited_type));
+ }
+ }
+ }
+
+ // Allow changes to be reported now that the operation is finished.
+ edited_theme->_unfreeze_and_propagate_changes();
+ updating = false;
+
+ _update_type_items();
+}
+
+void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) {
+ LineEdit *le = Object::cast_to<LineEdit>(p_control);
+ if (le->get_text().strip_edges().is_empty()) {
+ return;
+ }
+ String item_name = le->get_text().strip_edges();
+ switch (p_data_type) {
+ case Theme::DATA_TYPE_COLOR: {
+ edited_theme->set_color(item_name, edited_type, Color());
+ } break;
+ case Theme::DATA_TYPE_CONSTANT: {
+ edited_theme->set_constant(item_name, edited_type, 0);
+ } break;
+ case Theme::DATA_TYPE_FONT: {
+ edited_theme->set_font(item_name, edited_type, Ref<Font>());
+ } break;
+ case Theme::DATA_TYPE_FONT_SIZE: {
+ edited_theme->set_font_size(item_name, edited_type, -1);
+ } break;
+ case Theme::DATA_TYPE_ICON: {
+ edited_theme->set_icon(item_name, edited_type, Ref<Texture2D>());
+ } break;
+ case Theme::DATA_TYPE_STYLEBOX: {
+ edited_theme->set_stylebox(item_name, edited_type, Ref<StyleBox>());
} break;
}
+
+ le->set_text("");
}
-void ThemeEditor::_theme_menu_cbk(int p_option) {
- if (p_option == POPUP_CREATE_EMPTY || p_option == POPUP_CREATE_EDITOR_EMPTY || p_option == POPUP_IMPORT_EDITOR_THEME) {
- bool import = (p_option == POPUP_IMPORT_EDITOR_THEME);
+void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Control *p_control) {
+ _item_add_cbk(p_data_type, p_control);
+}
- Ref<Theme> base_theme;
+void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
+ switch (p_data_type) {
+ case Theme::DATA_TYPE_COLOR: {
+ edited_theme->set_color(p_item_name, edited_type, Theme::get_default()->get_color(p_item_name, edited_type));
+ } break;
+ case Theme::DATA_TYPE_CONSTANT: {
+ edited_theme->set_constant(p_item_name, edited_type, Theme::get_default()->get_constant(p_item_name, edited_type));
+ } break;
+ case Theme::DATA_TYPE_FONT: {
+ edited_theme->set_font(p_item_name, edited_type, Ref<Font>());
+ } break;
+ case Theme::DATA_TYPE_FONT_SIZE: {
+ edited_theme->set_font_size(p_item_name, edited_type, Theme::get_default()->get_font_size(p_item_name, edited_type));
+ } break;
+ case Theme::DATA_TYPE_ICON: {
+ edited_theme->set_icon(p_item_name, edited_type, Ref<Texture2D>());
+ } break;
+ case Theme::DATA_TYPE_STYLEBOX: {
+ edited_theme->set_stylebox(p_item_name, edited_type, Ref<StyleBox>());
+ } break;
+ }
+}
- if (p_option == POPUP_CREATE_EMPTY) {
- base_theme = Theme::get_default();
- } else {
- base_theme = EditorNode::get_singleton()->get_theme_base()->get_theme();
- }
+void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) {
+ switch (p_data_type) {
+ case Theme::DATA_TYPE_COLOR: {
+ edited_theme->clear_color(p_item_name, edited_type);
+ } break;
+ case Theme::DATA_TYPE_CONSTANT: {
+ edited_theme->clear_constant(p_item_name, edited_type);
+ } break;
+ case Theme::DATA_TYPE_FONT: {
+ edited_theme->clear_font(p_item_name, edited_type);
+ } break;
+ case Theme::DATA_TYPE_FONT_SIZE: {
+ edited_theme->clear_font_size(p_item_name, edited_type);
+ } break;
+ case Theme::DATA_TYPE_ICON: {
+ edited_theme->clear_icon(p_item_name, edited_type);
+ } break;
+ case Theme::DATA_TYPE_STYLEBOX: {
+ edited_theme->clear_stylebox(p_item_name, edited_type);
+ } break;
+ }
+}
- {
- List<StringName> types;
- base_theme->get_type_list(&types);
+void ThemeTypeEditor::_item_rename_cbk(int p_data_type, String p_item_name, Control *p_control) {
+ // Label
+ Object::cast_to<Label>(p_control->get_child(0))->hide();
+ // Label buttons
+ Object::cast_to<Button>(p_control->get_child(2))->hide();
+ Object::cast_to<Button>(p_control->get_child(3))->hide();
+
+ // LineEdit
+ Object::cast_to<LineEdit>(p_control->get_child(1))->set_text(p_item_name);
+ Object::cast_to<LineEdit>(p_control->get_child(1))->show();
+ // LineEdit buttons
+ Object::cast_to<Button>(p_control->get_child(4))->show();
+ Object::cast_to<Button>(p_control->get_child(5))->show();
+}
- for (List<StringName>::Element *T = types.front(); T; T = T->next()) {
- StringName type = T->get();
+void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name, Control *p_control) {
+ LineEdit *le = Object::cast_to<LineEdit>(p_control->get_child(1));
+ if (le->get_text().strip_edges().is_empty()) {
+ return;
+ }
- List<StringName> icons;
- base_theme->get_icon_list(type, &icons);
+ String new_name = le->get_text().strip_edges();
+ if (new_name == p_item_name) {
+ _item_rename_canceled(p_data_type, p_item_name, p_control);
+ return;
+ }
- for (List<StringName>::Element *E = icons.front(); E; E = E->next()) {
- theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref<Texture2D>());
- }
+ switch (p_data_type) {
+ case Theme::DATA_TYPE_COLOR: {
+ edited_theme->rename_color(p_item_name, new_name, edited_type);
+ } break;
+ case Theme::DATA_TYPE_CONSTANT: {
+ edited_theme->rename_constant(p_item_name, new_name, edited_type);
+ } break;
+ case Theme::DATA_TYPE_FONT: {
+ edited_theme->rename_font(p_item_name, new_name, edited_type);
+ } break;
+ case Theme::DATA_TYPE_FONT_SIZE: {
+ edited_theme->rename_font_size(p_item_name, new_name, edited_type);
+ } break;
+ case Theme::DATA_TYPE_ICON: {
+ edited_theme->rename_icon(p_item_name, new_name, edited_type);
+ } break;
+ case Theme::DATA_TYPE_STYLEBOX: {
+ edited_theme->rename_stylebox(p_item_name, new_name, edited_type);
+ } break;
+ }
+}
- List<StringName> styleboxs;
- base_theme->get_stylebox_list(type, &styleboxs);
+void ThemeTypeEditor::_item_rename_entered(String p_value, int p_data_type, String p_item_name, Control *p_control) {
+ _item_rename_confirmed(p_data_type, p_item_name, p_control);
+}
- for (List<StringName>::Element *E = styleboxs.front(); E; E = E->next()) {
- theme->set_stylebox(E->get(), type, import ? base_theme->get_stylebox(E->get(), type) : Ref<StyleBox>());
- }
+void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name, Control *p_control) {
+ // LineEdit
+ Object::cast_to<LineEdit>(p_control->get_child(1))->hide();
+ // LineEdit buttons
+ Object::cast_to<Button>(p_control->get_child(4))->hide();
+ Object::cast_to<Button>(p_control->get_child(5))->hide();
+
+ // Label
+ Object::cast_to<Label>(p_control->get_child(0))->show();
+ // Label buttons
+ Object::cast_to<Button>(p_control->get_child(2))->show();
+ Object::cast_to<Button>(p_control->get_child(3))->show();
+}
- List<StringName> fonts;
- base_theme->get_font_list(type, &fonts);
+void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {
+ edited_theme->set_color(p_item_name, edited_type, p_value);
+}
- for (List<StringName>::Element *E = fonts.front(); E; E = E->next()) {
- theme->set_font(E->get(), type, Ref<Font>());
- }
+void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) {
+ edited_theme->set_constant(p_item_name, edited_type, int(p_value));
+}
- List<StringName> font_sizes;
- base_theme->get_font_size_list(type, &font_sizes);
+void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) {
+ edited_theme->set_font_size(p_item_name, edited_type, int(p_value));
+}
- for (List<StringName>::Element *E = font_sizes.front(); E; E = E->next()) {
- theme->set_font_size(E->get(), type, base_theme->get_font_size(E->get(), type));
- }
+void ThemeTypeEditor::_edit_resource_item(RES p_resource, Control *p_editor) {
+ EditorNode::get_singleton()->edit_resource(p_resource);
+}
- List<StringName> colors;
- base_theme->get_color_list(type, &colors);
+void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) {
+ edited_theme->set_font(p_item_name, edited_type, p_value);
+}
- for (List<StringName>::Element *E = colors.front(); E; E = E->next()) {
- theme->set_color(E->get(), type, import ? base_theme->get_color(E->get(), type) : Color());
- }
+void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) {
+ edited_theme->set_icon(p_item_name, edited_type, p_value);
+}
- List<StringName> constants;
- base_theme->get_constant_list(type, &constants);
+void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) {
+ edited_theme->set_stylebox(p_item_name, edited_type, p_value);
- for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
- theme->set_constant(E->get(), type, base_theme->get_constant(E->get(), type));
- }
- }
+ if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {
+ if (leading_stylebox.stylebox.is_valid()) {
+ leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ }
+
+ leading_stylebox.stylebox = p_value;
+ leading_stylebox.ref_stylebox = (p_value.is_valid() ? p_value->duplicate() : RES());
+ if (p_value.is_valid()) {
+ leading_stylebox.stylebox->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
+ }
+}
+
+void ThemeTypeEditor::_pin_leading_stylebox(Ref<StyleBox> p_stylebox, String p_item_name) {
+ if (leading_stylebox.stylebox.is_valid()) {
+ leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ }
+
+ LeadingStylebox leader;
+ leader.pinned = true;
+ leader.item_name = p_item_name;
+ leader.stylebox = p_stylebox;
+ leader.ref_stylebox = (p_stylebox.is_valid() ? p_stylebox->duplicate() : RES());
+
+ leading_stylebox = leader;
+ if (leading_stylebox.stylebox.is_valid()) {
+ leading_stylebox.stylebox->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ }
+
+ _update_type_items();
+}
+
+void ThemeTypeEditor::_unpin_leading_stylebox() {
+ if (leading_stylebox.stylebox.is_valid()) {
+ leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ }
+
+ LeadingStylebox leader;
+ leader.pinned = false;
+ leading_stylebox = leader;
+
+ _update_type_items();
+}
+
+void ThemeTypeEditor::_update_stylebox_from_leading() {
+ if (!leading_stylebox.pinned || leading_stylebox.stylebox.is_null()) {
return;
}
- Ref<Theme> base_theme;
+ // Prevent changes from immediatelly being reported while the operation is still ongoing.
+ edited_theme->_freeze_change_propagation();
- name_select_label->show();
- name_hbc->show();
- type_select_label->show();
- type_select->show();
+ List<StringName> names;
+ edited_theme->get_stylebox_list(edited_type, &names);
+ List<Ref<StyleBox>> styleboxes;
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (E->get() == leading_stylebox.item_name) {
+ continue;
+ }
- if (p_option == POPUP_ADD) { // Add.
+ Ref<StyleBox> sb = edited_theme->get_stylebox(E->get(), edited_type);
+ if (sb->get_class() == leading_stylebox.stylebox->get_class()) {
+ styleboxes.push_back(sb);
+ }
+ }
- add_del_dialog->set_title(TTR("Add Item"));
- add_del_dialog->get_ok_button()->set_text(TTR("Add"));
- add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE);
+ List<PropertyInfo> props;
+ leading_stylebox.stylebox->get_property_list(&props);
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
- base_theme = Theme::get_default();
+ Variant value = leading_stylebox.stylebox->get(E->get().name);
+ Variant ref_value = leading_stylebox.ref_stylebox->get(E->get().name);
+ if (value == ref_value) {
+ continue;
+ }
- } else if (p_option == POPUP_CLASS_ADD) { // Add.
+ for (List<Ref<StyleBox>>::Element *F = styleboxes.front(); F; F = F->next()) {
+ Ref<StyleBox> sb = F->get();
+ sb->set(E->get().name, value);
+ }
+ }
- add_del_dialog->set_title(TTR("Add All Items"));
- add_del_dialog->get_ok_button()->set_text(TTR("Add All"));
- add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE);
+ leading_stylebox.ref_stylebox = leading_stylebox.stylebox->duplicate();
- base_theme = Theme::get_default();
+ // Allow changes to be reported now that the operation is finished.
+ edited_theme->_unfreeze_and_propagate_changes();
+}
- name_select_label->hide();
- name_hbc->hide();
- type_select_label->hide();
- type_select->hide();
+void ThemeTypeEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ add_type_button->set_icon(get_theme_icon("Add", "EditorIcons"));
- } else if (p_option == POPUP_REMOVE) {
- add_del_dialog->set_title(TTR("Remove Item"));
- add_del_dialog->get_ok_button()->set_text(TTR("Remove"));
- add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE);
+ data_type_tabs->set_tab_icon(0, get_theme_icon("Color", "EditorIcons"));
+ data_type_tabs->set_tab_icon(1, get_theme_icon("MemberConstant", "EditorIcons"));
+ data_type_tabs->set_tab_icon(2, get_theme_icon("Font", "EditorIcons"));
+ data_type_tabs->set_tab_icon(3, get_theme_icon("FontSize", "EditorIcons"));
+ data_type_tabs->set_tab_icon(4, get_theme_icon("ImageTexture", "EditorIcons"));
+ data_type_tabs->set_tab_icon(5, get_theme_icon("StyleBoxFlat", "EditorIcons"));
- base_theme = theme;
+ data_type_tabs->add_theme_style_override("tab_selected", get_theme_stylebox("tab_selected_odd", "TabContainer"));
+ data_type_tabs->add_theme_style_override("panel", get_theme_stylebox("panel_odd", "TabContainer"));
- } else if (p_option == POPUP_CLASS_REMOVE) {
- add_del_dialog->set_title(TTR("Remove All Items"));
- add_del_dialog->get_ok_button()->set_text(TTR("Remove All"));
- add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE);
+ _update_add_type_options();
+ } break;
+ }
+}
+
+void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) {
+ if (edited_theme.is_valid()) {
+ edited_theme->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
+ }
- base_theme = Theme::get_default();
+ edited_theme = p_theme;
+ edited_theme->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
+ _update_type_list();
+}
+
+void ThemeTypeEditor::select_type(String p_type_name) {
+ edited_type = p_type_name;
+ bool type_exists = false;
- name_select_label->hide();
- name_hbc->hide();
- type_select_label->hide();
- type_select->hide();
+ for (int i = 0; i < theme_type_list->get_item_count(); i++) {
+ String type_name = theme_type_list->get_item_text(i);
+ if (type_name == edited_type) {
+ theme_type_list->select(i);
+ type_exists = true;
+ break;
+ }
}
- popup_mode = p_option;
- ERR_FAIL_COND(theme.is_null());
+ if (type_exists) {
+ _update_type_items();
+ } else {
+ edited_theme->add_icon_type(edited_type);
+ edited_theme->add_stylebox_type(edited_type);
+ edited_theme->add_font_type(edited_type);
+ edited_theme->add_font_size_type(edited_type);
+ edited_theme->add_color_type(edited_type);
+ edited_theme->add_constant_type(edited_type);
+
+ _update_type_list();
+ }
+}
- List<StringName> types;
- base_theme->get_type_list(&types);
+ThemeTypeEditor::ThemeTypeEditor() {
+ VBoxContainer *main_vb = memnew(VBoxContainer);
+ add_child(main_vb);
+
+ HBoxContainer *type_list_hb = memnew(HBoxContainer);
+ main_vb->add_child(type_list_hb);
+
+ Label *type_list_label = memnew(Label);
+ type_list_label->set_text(TTR("Type:"));
+ type_list_hb->add_child(type_list_label);
+
+ theme_type_list = memnew(OptionButton);
+ theme_type_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ type_list_hb->add_child(theme_type_list);
+ theme_type_list->connect("item_selected", callable_mp(this, &ThemeTypeEditor::_list_type_selected));
+
+ add_type_button = memnew(Button);
+ add_type_button->set_tooltip(TTR("Add Type"));
+ type_list_hb->add_child(add_type_button);
+ add_type_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_type_button_cbk));
+
+ add_type_dialog = memnew(ConfirmationDialog);
+ add_type_dialog->set_title(TTR("Add Item Type"));
+ type_list_hb->add_child(add_type_dialog);
+ add_type_dialog->connect("confirmed", callable_mp(this, &ThemeTypeEditor::_add_type_dialog_confirmed));
+
+ VBoxContainer *add_type_vb = memnew(VBoxContainer);
+ add_type_dialog->add_child(add_type_vb);
+
+ Label *add_type_filter_label = memnew(Label);
+ add_type_filter_label->set_text(TTR("Name:"));
+ add_type_vb->add_child(add_type_filter_label);
+ add_type_filter = memnew(LineEdit);
+ add_type_vb->add_child(add_type_filter);
+ add_type_filter->connect("text_changed", callable_mp(this, &ThemeTypeEditor::_add_type_filter_cbk));
+ add_type_filter->connect("text_entered", callable_mp(this, &ThemeTypeEditor::_add_type_dialog_entered));
+ Label *add_type_options_label = memnew(Label);
+ add_type_options_label->set_text(TTR("Node Types:"));
+ add_type_vb->add_child(add_type_options_label);
+ add_type_options = memnew(ItemList);
+ add_type_options->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_type_vb->add_child(add_type_options);
+ add_type_options->connect("item_selected", callable_mp(this, &ThemeTypeEditor::_add_type_options_cbk));
+ add_type_options->connect("item_activated", callable_mp(this, &ThemeTypeEditor::_add_type_dialog_activated));
+
+ HBoxContainer *type_controls = memnew(HBoxContainer);
+ main_vb->add_child(type_controls);
+
+ show_default_items_button = memnew(CheckButton);
+ show_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);
+ show_default_items_button->set_text(TTR("Show Default"));
+ show_default_items_button->set_tooltip(TTR("Show default type items alongside items that have been overridden."));
+ show_default_items_button->set_pressed(true);
+ type_controls->add_child(show_default_items_button);
+ show_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_update_type_items));
+
+ Button *add_default_items_button = memnew(Button);
+ add_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_default_items_button->set_text(TTR("Override All"));
+ add_default_items_button->set_tooltip(TTR("Override all default type items."));
+ type_controls->add_child(add_default_items_button);
+ add_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_default_type_items));
+
+ data_type_tabs = memnew(TabContainer);
+ main_vb->add_child(data_type_tabs);
+ data_type_tabs->set_v_size_flags(SIZE_EXPAND_FILL);
+ data_type_tabs->set_use_hidden_tabs_for_min_size(true);
+
+ color_items_list = _create_item_list(Theme::DATA_TYPE_COLOR);
+ constant_items_list = _create_item_list(Theme::DATA_TYPE_CONSTANT);
+ font_items_list = _create_item_list(Theme::DATA_TYPE_FONT);
+ font_size_items_list = _create_item_list(Theme::DATA_TYPE_FONT_SIZE);
+ icon_items_list = _create_item_list(Theme::DATA_TYPE_ICON);
+ stylebox_items_list = _create_item_list(Theme::DATA_TYPE_STYLEBOX);
+
+ update_debounce_timer = memnew(Timer);
+ update_debounce_timer->set_one_shot(true);
+ update_debounce_timer->set_wait_time(0.5);
+ update_debounce_timer->connect("timeout", callable_mp(this, &ThemeTypeEditor::_update_type_list));
+ add_child(update_debounce_timer);
+}
- type_menu->get_popup()->clear();
+void ThemeEditor::edit(const Ref<Theme> &p_theme) {
+ if (theme == p_theme) {
+ return;
+ }
- if (p_option == 0 || p_option == 1) { // Add.
+ theme = p_theme;
+ theme_type_editor->set_edited_theme(p_theme);
+ theme_edit_dialog->set_edited_theme(p_theme);
- List<StringName> new_types;
- theme->get_type_list(&new_types);
- for (List<StringName>::Element *F = new_types.front(); F; F = F->next()) {
- bool found = false;
- for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
- if (E->get() == F->get()) {
- found = true;
- break;
- }
- }
+ for (int i = 0; i < preview_tabs_content->get_child_count(); i++) {
+ ThemeEditorPreview *preview_tab = Object::cast_to<ThemeEditorPreview>(preview_tabs_content->get_child(i));
+ if (!preview_tab) {
+ continue;
+ }
- if (!found) {
- types.push_back(F->get());
- }
+ preview_tab->set_preview_theme(p_theme);
+ }
+
+ theme_name->set_text(TTR("Theme") + ": " + theme->get_path().get_file());
+}
+
+Ref<Theme> ThemeEditor::get_edited_theme() {
+ return theme;
+}
+
+void ThemeEditor::_theme_save_button_cbk(bool p_save_as) {
+ ERR_FAIL_COND_MSG(theme.is_null(), "Invalid state of the Theme Editor; the Theme resource is missing.");
+
+ if (p_save_as) {
+ EditorNode::get_singleton()->save_resource_as(theme);
+ } else {
+ EditorNode::get_singleton()->save_resource(theme);
+ }
+}
+
+void ThemeEditor::_theme_edit_button_cbk() {
+ theme_edit_dialog->popup_centered(Size2(850, 760) * EDSCALE);
+}
+
+void ThemeEditor::_add_preview_button_cbk() {
+ preview_scene_dialog->popup_file_dialog();
+}
+
+void ThemeEditor::_preview_scene_dialog_cbk(const String &p_path) {
+ SceneThemeEditorPreview *preview_tab = memnew(SceneThemeEditorPreview);
+ if (!preview_tab->set_preview_scene(p_path)) {
+ return;
+ }
+
+ _add_preview_tab(preview_tab, p_path.get_file(), get_theme_icon("PackedScene", "EditorIcons"));
+ preview_tab->connect("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid), varray(preview_tab));
+ preview_tab->connect("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab), varray(preview_tab));
+}
+
+void ThemeEditor::_add_preview_tab(ThemeEditorPreview *p_preview_tab, const String &p_preview_name, const Ref<Texture2D> &p_icon) {
+ p_preview_tab->set_preview_theme(theme);
+
+ preview_tabs->add_tab(p_preview_name, p_icon);
+ preview_tabs_content->add_child(p_preview_tab);
+ preview_tabs->set_tab_right_button(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("close", "Tabs"));
+ p_preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));
+
+ preview_tabs->set_current_tab(preview_tabs->get_tab_count() - 1);
+}
+
+void ThemeEditor::_change_preview_tab(int p_tab) {
+ ERR_FAIL_INDEX_MSG(p_tab, preview_tabs_content->get_child_count(), "Attempting to open a preview tab that doesn't exist.");
+
+ for (int i = 0; i < preview_tabs_content->get_child_count(); i++) {
+ Control *c = Object::cast_to<Control>(preview_tabs_content->get_child(i));
+ if (!c) {
+ continue;
}
+
+ c->set_visible(i == p_tab);
}
+}
- types.sort_custom<StringName::AlphCompare>();
- for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
- type_menu->get_popup()->add_item(E->get());
+void ThemeEditor::_remove_preview_tab(int p_tab) {
+ ERR_FAIL_INDEX_MSG(p_tab, preview_tabs_content->get_child_count(), "Attempting to remove a preview tab that doesn't exist.");
+
+ ThemeEditorPreview *preview_tab = Object::cast_to<ThemeEditorPreview>(preview_tabs_content->get_child(p_tab));
+ ERR_FAIL_COND_MSG(Object::cast_to<DefaultThemeEditorPreview>(preview_tab), "Attemptying to remove the default preview tab.");
+
+ if (preview_tab) {
+ preview_tab->disconnect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));
+ if (preview_tab->is_connected("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid))) {
+ preview_tab->disconnect("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid));
+ }
+ if (preview_tab->is_connected("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab))) {
+ preview_tab->disconnect("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab));
+ }
+
+ preview_tabs_content->remove_child(preview_tab);
+ preview_tabs->remove_tab(p_tab);
+ _change_preview_tab(preview_tabs->get_current_tab());
+ }
+}
+
+void ThemeEditor::_remove_preview_tab_invalid(Node *p_tab_control) {
+ int tab_index = p_tab_control->get_index();
+ _remove_preview_tab(tab_index);
+}
+
+void ThemeEditor::_update_preview_tab(Node *p_tab_control) {
+ if (!Object::cast_to<SceneThemeEditorPreview>(p_tab_control)) {
+ return;
}
+
+ int tab_index = p_tab_control->get_index();
+ SceneThemeEditorPreview *scene_preview = Object::cast_to<SceneThemeEditorPreview>(p_tab_control);
+ preview_tabs->set_tab_title(tab_index, scene_preview->get_preview_scene_path().get_file());
+}
+
+void ThemeEditor::_preview_control_picked(String p_class_name) {
+ theme_type_editor->select_type(p_class_name);
}
void ThemeEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_PROCESS: {
- time_left -= get_process_delta_time();
- if (time_left < 0) {
- time_left = 1.5;
- _refresh_interval();
- }
- } break;
+ case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- theme_menu->set_icon(get_theme_icon("Theme", "EditorIcons"));
+ preview_tabs->add_theme_style_override("tab_selected", get_theme_stylebox("ThemeEditorPreviewFG", "EditorStyles"));
+ preview_tabs->add_theme_style_override("tab_unselected", get_theme_stylebox("ThemeEditorPreviewBG", "EditorStyles"));
+ preview_tabs_content->add_theme_style_override("panel", get_theme_stylebox("panel_odd", "TabContainer"));
+
+ add_preview_button->set_icon(get_theme_icon("Add", "EditorIcons"));
} break;
}
}
-void ThemeEditor::_bind_methods() {
-}
-
ThemeEditor::ThemeEditor() {
- time_left = 0;
-
HBoxContainer *top_menu = memnew(HBoxContainer);
add_child(top_menu);
- top_menu->add_child(memnew(Label(TTR("Preview:"))));
+ theme_name = memnew(Label);
+ theme_name->set_text(TTR("Theme") + ": ");
+ top_menu->add_child(theme_name);
+
top_menu->add_spacer(false);
- theme_menu = memnew(MenuButton);
- theme_menu->set_text(TTR("Edit Theme"));
- theme_menu->set_tooltip(TTR("Theme editing menu."));
- theme_menu->get_popup()->add_item(TTR("Add Item"), POPUP_ADD);
- theme_menu->get_popup()->add_item(TTR("Add Class Items"), POPUP_CLASS_ADD);
- theme_menu->get_popup()->add_item(TTR("Remove Item"), POPUP_REMOVE);
- theme_menu->get_popup()->add_item(TTR("Remove Class Items"), POPUP_CLASS_REMOVE);
- theme_menu->get_popup()->add_separator();
- theme_menu->get_popup()->add_item(TTR("Create Empty Template"), POPUP_CREATE_EMPTY);
- theme_menu->get_popup()->add_item(TTR("Create Empty Editor Template"), POPUP_CREATE_EDITOR_EMPTY);
- theme_menu->get_popup()->add_item(TTR("Create From Current Editor Theme"), POPUP_IMPORT_EDITOR_THEME);
- top_menu->add_child(theme_menu);
- theme_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_theme_menu_cbk));
-
- ScrollContainer *scroll = memnew(ScrollContainer);
- add_child(scroll);
- scroll->set_enable_v_scroll(true);
- scroll->set_enable_h_scroll(true);
- scroll->set_v_size_flags(SIZE_EXPAND_FILL);
-
- MarginContainer *root_container = memnew(MarginContainer);
- scroll->add_child(root_container);
- root_container->set_theme(Theme::get_default());
- root_container->set_clip_contents(true);
- root_container->set_custom_minimum_size(Size2(700, 0) * EDSCALE);
- root_container->set_v_size_flags(SIZE_EXPAND_FILL);
- root_container->set_h_size_flags(SIZE_EXPAND_FILL);
-
- //// Preview Controls ////
-
- main_panel = memnew(Panel);
- root_container->add_child(main_panel);
-
- main_container = memnew(MarginContainer);
- root_container->add_child(main_container);
- 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);
-
- VBoxContainer *first_vb = memnew(VBoxContainer);
- main_hb->add_child(first_vb);
- first_vb->set_h_size_flags(SIZE_EXPAND_FILL);
- first_vb->add_theme_constant_override("separation", 10 * EDSCALE);
-
- first_vb->add_child(memnew(Label("Label")));
-
- first_vb->add_child(memnew(Button("Button")));
- Button *bt = memnew(Button);
- bt->set_text(TTR("Toggle Button"));
- bt->set_toggle_mode(true);
- bt->set_pressed(true);
- first_vb->add_child(bt);
- bt = memnew(Button);
- bt->set_text(TTR("Disabled Button"));
- bt->set_disabled(true);
- first_vb->add_child(bt);
- Button *tb = memnew(Button);
- tb->set_flat(true);
- tb->set_text("Button");
- first_vb->add_child(tb);
-
- CheckButton *cb = memnew(CheckButton);
- cb->set_text("CheckButton");
- first_vb->add_child(cb);
- CheckBox *cbx = memnew(CheckBox);
- cbx->set_text("CheckBox");
- first_vb->add_child(cbx);
-
- MenuButton *test_menu_button = memnew(MenuButton);
- test_menu_button->set_text("MenuButton");
- test_menu_button->get_popup()->add_item(TTR("Item"));
- test_menu_button->get_popup()->add_item(TTR("Disabled Item"));
- test_menu_button->get_popup()->set_item_disabled(1, true);
- test_menu_button->get_popup()->add_separator();
- test_menu_button->get_popup()->add_check_item(TTR("Check Item"));
- test_menu_button->get_popup()->add_check_item(TTR("Checked Item"));
- test_menu_button->get_popup()->set_item_checked(4, true);
- test_menu_button->get_popup()->add_separator();
- test_menu_button->get_popup()->add_radio_check_item(TTR("Radio Item"));
- test_menu_button->get_popup()->add_radio_check_item(TTR("Checked Radio Item"));
- test_menu_button->get_popup()->set_item_checked(7, true);
- test_menu_button->get_popup()->add_separator(TTR("Named Sep."));
-
- PopupMenu *test_submenu = memnew(PopupMenu);
- test_menu_button->get_popup()->add_child(test_submenu);
- test_submenu->set_name("submenu");
- test_menu_button->get_popup()->add_submenu_item(TTR("Submenu"), "submenu");
- test_submenu->add_item(TTR("Subitem 1"));
- test_submenu->add_item(TTR("Subitem 2"));
- first_vb->add_child(test_menu_button);
-
- OptionButton *test_option_button = memnew(OptionButton);
- test_option_button->add_item("OptionButton");
- test_option_button->add_separator();
- test_option_button->add_item(TTR("Has"));
- test_option_button->add_item(TTR("Many"));
- test_option_button->add_item(TTR("Options"));
- first_vb->add_child(test_option_button);
- first_vb->add_child(memnew(ColorPickerButton));
-
- VBoxContainer *second_vb = memnew(VBoxContainer);
- second_vb->set_h_size_flags(SIZE_EXPAND_FILL);
- main_hb->add_child(second_vb);
- second_vb->add_theme_constant_override("separation", 10 * EDSCALE);
- LineEdit *le = memnew(LineEdit);
- le->set_text("LineEdit");
- second_vb->add_child(le);
- le = memnew(LineEdit);
- le->set_text(TTR("Disabled LineEdit"));
- le->set_editable(false);
- second_vb->add_child(le);
- TextEdit *te = memnew(TextEdit);
- te->set_text("TextEdit");
- te->set_custom_minimum_size(Size2(0, 100) * EDSCALE);
- second_vb->add_child(te);
- second_vb->add_child(memnew(SpinBox));
-
- HBoxContainer *vhb = memnew(HBoxContainer);
- second_vb->add_child(vhb);
- vhb->set_custom_minimum_size(Size2(0, 100) * EDSCALE);
- vhb->add_child(memnew(VSlider));
- VScrollBar *vsb = memnew(VScrollBar);
- vsb->set_page(25);
- vhb->add_child(vsb);
- vhb->add_child(memnew(VSeparator));
- VBoxContainer *hvb = memnew(VBoxContainer);
- vhb->add_child(hvb);
- hvb->set_alignment(ALIGN_CENTER);
- hvb->set_h_size_flags(SIZE_EXPAND_FILL);
- hvb->add_child(memnew(HSlider));
- HScrollBar *hsb = memnew(HScrollBar);
- hsb->set_page(25);
- hvb->add_child(hsb);
- HSlider *hs = memnew(HSlider);
- hs->set_editable(false);
- hvb->add_child(hs);
- hvb->add_child(memnew(HSeparator));
- ProgressBar *pb = memnew(ProgressBar);
- pb->set_value(50);
- hvb->add_child(pb);
-
- VBoxContainer *third_vb = memnew(VBoxContainer);
- third_vb->set_h_size_flags(SIZE_EXPAND_FILL);
- third_vb->add_theme_constant_override("separation", 10 * EDSCALE);
- main_hb->add_child(third_vb);
-
- TabContainer *tc = memnew(TabContainer);
- third_vb->add_child(tc);
- tc->set_custom_minimum_size(Size2(0, 135) * EDSCALE);
- Control *tcc = memnew(Control);
- tcc->set_name(TTR("Tab 1"));
- tc->add_child(tcc);
- tcc = memnew(Control);
- tcc->set_name(TTR("Tab 2"));
- tc->add_child(tcc);
- tcc = memnew(Control);
- tcc->set_name(TTR("Tab 3"));
- tc->add_child(tcc);
- tc->set_tab_disabled(2, true);
-
- Tree *test_tree = memnew(Tree);
- third_vb->add_child(test_tree);
- test_tree->set_custom_minimum_size(Size2(0, 175) * EDSCALE);
- test_tree->add_theme_constant_override("draw_relationship_lines", 1);
-
- TreeItem *item = test_tree->create_item();
- item->set_text(0, "Tree");
- item = test_tree->create_item(test_tree->get_root());
- item->set_text(0, "Item");
- item = test_tree->create_item(test_tree->get_root());
- item->set_editable(0, true);
- item->set_text(0, TTR("Editable Item"));
- TreeItem *sub_tree = test_tree->create_item(test_tree->get_root());
- sub_tree->set_text(0, TTR("Subtree"));
- item = test_tree->create_item(sub_tree);
- item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
- item->set_editable(0, true);
- item->set_text(0, "Check Item");
- item = test_tree->create_item(sub_tree);
- item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
- item->set_editable(0, true);
- item->set_range_config(0, 0, 20, 0.1);
- item->set_range(0, 2);
- item = test_tree->create_item(sub_tree);
- item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
- item->set_editable(0, true);
- item->set_text(0, TTR("Has,Many,Options"));
- item->set_range(0, 2);
-
- main_hb->add_theme_constant_override("separation", 20 * EDSCALE);
-
- ////////
-
- add_del_dialog = memnew(ConfirmationDialog);
- add_del_dialog->hide();
- add_child(add_del_dialog);
-
- VBoxContainer *dialog_vbc = memnew(VBoxContainer);
- add_del_dialog->add_child(dialog_vbc);
-
- Label *l = memnew(Label);
- l->set_text(TTR("Type:"));
- dialog_vbc->add_child(l);
-
- type_hbc = memnew(HBoxContainer);
- dialog_vbc->add_child(type_hbc);
-
- type_edit = memnew(LineEdit);
- type_edit->set_h_size_flags(SIZE_EXPAND_FILL);
- type_hbc->add_child(type_edit);
- type_menu = memnew(MenuButton);
- type_menu->set_flat(false);
- type_menu->set_text("...");
- type_hbc->add_child(type_menu);
-
- type_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_type_menu_cbk));
-
- l = memnew(Label);
- l->set_text(TTR("Name:"));
- dialog_vbc->add_child(l);
- name_select_label = l;
-
- name_hbc = memnew(HBoxContainer);
- dialog_vbc->add_child(name_hbc);
-
- name_edit = memnew(LineEdit);
- name_edit->set_h_size_flags(SIZE_EXPAND_FILL);
- name_hbc->add_child(name_edit);
- name_menu = memnew(MenuButton);
- type_menu->set_flat(false);
- name_menu->set_text("...");
- name_hbc->add_child(name_menu);
-
- name_menu->get_popup()->connect("about_to_popup", callable_mp(this, &ThemeEditor::_name_menu_about_to_show));
- name_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_name_menu_cbk));
-
- type_select_label = memnew(Label);
- type_select_label->set_text(TTR("Data Type:"));
- dialog_vbc->add_child(type_select_label);
-
- type_select = memnew(OptionButton);
- type_select->add_item(TTR("Icon"));
- type_select->add_item(TTR("Style"));
- type_select->add_item(TTR("Font"));
- type_select->add_item(TTR("Font Size"));
- type_select->add_item(TTR("Color"));
- type_select->add_item(TTR("Constant"));
-
- dialog_vbc->add_child(type_select);
-
- add_del_dialog->get_ok_button()->connect("pressed", callable_mp(this, &ThemeEditor::_dialog_cbk));
-
- file_dialog = memnew(EditorFileDialog);
- file_dialog->add_filter("*.theme ; " + TTR("Theme File"));
- add_child(file_dialog);
- file_dialog->connect("file_selected", callable_mp(this, &ThemeEditor::_save_template_cbk));
+ Button *theme_save_button = memnew(Button);
+ theme_save_button->set_text(TTR("Save"));
+ theme_save_button->set_flat(true);
+ theme_save_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_save_button_cbk), varray(false));
+ top_menu->add_child(theme_save_button);
+
+ Button *theme_save_as_button = memnew(Button);
+ theme_save_as_button->set_text(TTR("Save As..."));
+ theme_save_as_button->set_flat(true);
+ theme_save_as_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_save_button_cbk), varray(true));
+ top_menu->add_child(theme_save_as_button);
+
+ top_menu->add_child(memnew(VSeparator));
+
+ Button *theme_edit_button = memnew(Button);
+ theme_edit_button->set_text(TTR("Manage Items..."));
+ theme_edit_button->set_tooltip(TTR("Add, remove, organize and import Theme items."));
+ theme_edit_button->set_flat(true);
+ theme_edit_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_edit_button_cbk));
+ top_menu->add_child(theme_edit_button);
+
+ theme_edit_dialog = memnew(ThemeItemEditorDialog);
+ theme_edit_dialog->hide();
+ top_menu->add_child(theme_edit_dialog);
+
+ HSplitContainer *main_hs = memnew(HSplitContainer);
+ main_hs->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(main_hs);
+
+ VBoxContainer *preview_tabs_vb = memnew(VBoxContainer);
+ preview_tabs_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ preview_tabs_vb->set_custom_minimum_size(Size2(520, 0) * EDSCALE);
+ preview_tabs_vb->add_theme_constant_override("separation", 2 * EDSCALE);
+ main_hs->add_child(preview_tabs_vb);
+ HBoxContainer *preview_tabbar_hb = memnew(HBoxContainer);
+ preview_tabs_vb->add_child(preview_tabbar_hb);
+ preview_tabs_content = memnew(PanelContainer);
+ preview_tabs_content->set_v_size_flags(SIZE_EXPAND_FILL);
+ preview_tabs_content->set_draw_behind_parent(true);
+ preview_tabs_vb->add_child(preview_tabs_content);
+
+ preview_tabs = memnew(Tabs);
+ preview_tabs->set_tab_align(Tabs::ALIGN_LEFT);
+ preview_tabs->set_h_size_flags(SIZE_EXPAND_FILL);
+ preview_tabbar_hb->add_child(preview_tabs);
+ preview_tabs->connect("tab_changed", callable_mp(this, &ThemeEditor::_change_preview_tab));
+ preview_tabs->connect("right_button_pressed", callable_mp(this, &ThemeEditor::_remove_preview_tab));
+
+ HBoxContainer *add_preview_button_hb = memnew(HBoxContainer);
+ preview_tabbar_hb->add_child(add_preview_button_hb);
+ add_preview_button = memnew(Button);
+ add_preview_button->set_text(TTR("Add Preview"));
+ add_preview_button_hb->add_child(add_preview_button);
+ add_preview_button->connect("pressed", callable_mp(this, &ThemeEditor::_add_preview_button_cbk));
+
+ DefaultThemeEditorPreview *default_preview_tab = memnew(DefaultThemeEditorPreview);
+ preview_tabs_content->add_child(default_preview_tab);
+ default_preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));
+ preview_tabs->add_tab(TTR("Default Preview"));
+
+ preview_scene_dialog = memnew(EditorFileDialog);
+ preview_scene_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
+ preview_scene_dialog->set_title(TTR("Select UI Scene:"));
+ List<String> ext;
+ ResourceLoader::get_recognized_extensions_for_type("PackedScene", &ext);
+ for (List<String>::Element *E = ext.front(); E; E = E->next()) {
+ preview_scene_dialog->add_filter("*." + E->get() + "; Scene");
+ }
+ main_hs->add_child(preview_scene_dialog);
+ preview_scene_dialog->connect("file_selected", callable_mp(this, &ThemeEditor::_preview_scene_dialog_cbk));
+
+ theme_type_editor = memnew(ThemeTypeEditor);
+ main_hs->add_child(theme_type_editor);
+ theme_type_editor->set_custom_minimum_size(Size2(360, 0) * EDSCALE);
}
void ThemeEditorPlugin::edit(Object *p_node) {
if (Object::cast_to<Theme>(p_node)) {
theme_editor->edit(Object::cast_to<Theme>(p_node));
+ } else if (Object::cast_to<Font>(p_node) || Object::cast_to<StyleBox>(p_node) || Object::cast_to<Texture2D>(p_node)) {
+ // Do nothing, keep editing the existing theme.
} else {
theme_editor->edit(Ref<Theme>());
}
}
bool ThemeEditorPlugin::handles(Object *p_node) const {
- return p_node->is_class("Theme");
+ if (Object::cast_to<Theme>(p_node)) {
+ return true;
+ }
+
+ Ref<Theme> edited_theme = theme_editor->get_edited_theme();
+ if (edited_theme.is_null()) {
+ return false;
+ }
+
+ // If we are editing a theme already and this particular resource happens to belong to it,
+ // then we just keep editing it, despite not being able to directly handle it.
+ // This only goes one layer deep, but if required this can be extended to support, say, FontData inside of Font.
+ bool belongs_to_theme = false;
+
+ if (Object::cast_to<Font>(p_node)) {
+ Ref<Font> font_item = Object::cast_to<Font>(p_node);
+ List<StringName> types;
+ List<StringName> names;
+
+ edited_theme->get_font_type_list(&types);
+ for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
+ names.clear();
+ edited_theme->get_font_list(E->get(), &names);
+
+ for (List<StringName>::Element *F = names.front(); F; F = F->next()) {
+ if (font_item == edited_theme->get_font(F->get(), E->get())) {
+ belongs_to_theme = true;
+ break;
+ }
+ }
+ }
+ } else if (Object::cast_to<StyleBox>(p_node)) {
+ Ref<StyleBox> stylebox_item = Object::cast_to<StyleBox>(p_node);
+ List<StringName> types;
+ List<StringName> names;
+
+ edited_theme->get_stylebox_type_list(&types);
+ for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
+ names.clear();
+ edited_theme->get_stylebox_list(E->get(), &names);
+
+ for (List<StringName>::Element *F = names.front(); F; F = F->next()) {
+ if (stylebox_item == edited_theme->get_stylebox(F->get(), E->get())) {
+ belongs_to_theme = true;
+ break;
+ }
+ }
+ }
+ } else if (Object::cast_to<Texture2D>(p_node)) {
+ Ref<Texture2D> icon_item = Object::cast_to<Texture2D>(p_node);
+ List<StringName> types;
+ List<StringName> names;
+
+ edited_theme->get_icon_type_list(&types);
+ for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
+ names.clear();
+ edited_theme->get_icon_list(E->get(), &names);
+
+ for (List<StringName>::Element *F = names.front(); F; F = F->next()) {
+ if (icon_item == edited_theme->get_icon(F->get(), E->get())) {
+ belongs_to_theme = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return belongs_to_theme;
}
void ThemeEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- theme_editor->set_process(true);
button->show();
editor->make_bottom_panel_item_visible(theme_editor);
} else {
- theme_editor->set_process(false);
if (theme_editor->is_visible_in_tree()) {
editor->hide_bottom_panel();
}
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index ab199f8e51..77baf46395 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -31,68 +31,355 @@
#ifndef THEME_EDITOR_PLUGIN_H
#define THEME_EDITOR_PLUGIN_H
-#include "scene/gui/check_box.h"
-#include "scene/gui/file_dialog.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/option_button.h"
#include "scene/gui/scroll_container.h"
+#include "scene/gui/tabs.h"
#include "scene/gui/texture_rect.h"
#include "scene/resources/theme.h"
+#include "theme_editor_preview.h"
#include "editor/editor_node.h"
+class ThemeItemImportTree : public VBoxContainer {
+ GDCLASS(ThemeItemImportTree, VBoxContainer);
+
+ Ref<Theme> edited_theme;
+ Ref<Theme> base_theme;
+
+ struct ThemeItem {
+ String type_name;
+ Theme::DataType data_type;
+ String item_name;
+
+ bool operator<(const ThemeItem &p_item) const {
+ if (type_name == p_item.type_name && data_type == p_item.data_type) {
+ return item_name < p_item.item_name;
+ }
+ if (type_name == p_item.type_name) {
+ return data_type < p_item.data_type;
+ }
+ return type_name < p_item.type_name;
+ }
+ };
+
+ enum ItemCheckedState {
+ SELECT_IMPORT_DEFINITION,
+ SELECT_IMPORT_FULL,
+ };
+
+ Map<ThemeItem, ItemCheckedState> selected_items;
+
+ LineEdit *import_items_filter;
+
+ Tree *import_items_tree;
+ List<TreeItem *> tree_color_items;
+ List<TreeItem *> tree_constant_items;
+ List<TreeItem *> tree_font_items;
+ List<TreeItem *> tree_font_size_items;
+ List<TreeItem *> tree_icon_items;
+ List<TreeItem *> tree_stylebox_items;
+
+ bool updating_tree = false;
+
+ enum ItemActionFlag {
+ IMPORT_ITEM = 1,
+ IMPORT_ITEM_DATA = 2,
+ };
+
+ TextureRect *select_colors_icon;
+ Label *select_colors_label;
+ Button *select_all_colors_button;
+ Button *select_full_colors_button;
+ Button *deselect_all_colors_button;
+ Label *total_selected_colors_label;
+
+ TextureRect *select_constants_icon;
+ Label *select_constants_label;
+ Button *select_all_constants_button;
+ Button *select_full_constants_button;
+ Button *deselect_all_constants_button;
+ Label *total_selected_constants_label;
+
+ TextureRect *select_fonts_icon;
+ Label *select_fonts_label;
+ Button *select_all_fonts_button;
+ Button *select_full_fonts_button;
+ Button *deselect_all_fonts_button;
+ Label *total_selected_fonts_label;
+
+ TextureRect *select_font_sizes_icon;
+ Label *select_font_sizes_label;
+ Button *select_all_font_sizes_button;
+ Button *select_full_font_sizes_button;
+ Button *deselect_all_font_sizes_button;
+ Label *total_selected_font_sizes_label;
+
+ TextureRect *select_icons_icon;
+ Label *select_icons_label;
+ Button *select_all_icons_button;
+ Button *select_full_icons_button;
+ Button *deselect_all_icons_button;
+ Label *total_selected_icons_label;
+
+ TextureRect *select_styleboxes_icon;
+ Label *select_styleboxes_label;
+ Button *select_all_styleboxes_button;
+ Button *select_full_styleboxes_button;
+ Button *deselect_all_styleboxes_button;
+ Label *total_selected_styleboxes_label;
+
+ HBoxContainer *select_icons_warning_hb;
+ TextureRect *select_icons_warning_icon;
+ Label *select_icons_warning;
+
+ Button *import_collapse_types_button;
+ Button *import_expand_types_button;
+ Button *import_select_all_button;
+ Button *import_select_full_button;
+ Button *import_deselect_all_button;
+
+ void _update_items_tree();
+ void _toggle_type_items(bool p_collapse);
+ void _filter_text_changed(const String &p_value);
+
+ void _store_selected_item(TreeItem *p_tree_item);
+ void _restore_selected_item(TreeItem *p_tree_item);
+ void _update_total_selected(Theme::DataType p_data_type);
+
+ void _tree_item_edited();
+ void _select_all_subitems(TreeItem *p_root_item, bool p_select_with_data);
+ void _deselect_all_subitems(TreeItem *p_root_item, bool p_deselect_completely);
+ void _update_parent_items(TreeItem *p_root_item);
+
+ void _select_all_items_pressed();
+ void _select_full_items_pressed();
+ void _deselect_all_items_pressed();
+
+ void _select_all_data_type_pressed(int p_data_type);
+ void _select_full_data_type_pressed(int p_data_type);
+ void _deselect_all_data_type_pressed(int p_data_type);
+
+ void _import_selected();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_edited_theme(const Ref<Theme> &p_theme);
+ void set_base_theme(const Ref<Theme> &p_theme);
+ void reset_item_tree();
+
+ bool has_selected_items() const;
+
+ ThemeItemImportTree();
+};
+
+class ThemeItemEditorDialog : public AcceptDialog {
+ GDCLASS(ThemeItemEditorDialog, AcceptDialog);
+
+ Ref<Theme> edited_theme;
+
+ TabContainer *tc;
+
+ ItemList *edit_type_list;
+ LineEdit *edit_add_type_value;
+ String edited_item_type;
+
+ Button *edit_items_add_color;
+ Button *edit_items_add_constant;
+ Button *edit_items_add_font;
+ Button *edit_items_add_font_size;
+ Button *edit_items_add_icon;
+ Button *edit_items_add_stylebox;
+ Button *edit_items_remove_class;
+ Button *edit_items_remove_custom;
+ Button *edit_items_remove_all;
+ Tree *edit_items_tree;
+
+ enum ItemsTreeAction {
+ ITEMS_TREE_RENAME_ITEM,
+ ITEMS_TREE_REMOVE_ITEM,
+ ITEMS_TREE_REMOVE_DATA_TYPE,
+ };
+
+ ConfirmationDialog *edit_theme_item_dialog;
+ VBoxContainer *edit_theme_item_old_vb;
+ Label *theme_item_old_name;
+ LineEdit *theme_item_name;
+
+ enum ItemPopupMode {
+ CREATE_THEME_ITEM,
+ RENAME_THEME_ITEM,
+ ITEM_POPUP_MODE_MAX
+ };
+
+ ItemPopupMode item_popup_mode = ITEM_POPUP_MODE_MAX;
+ String edit_item_old_name;
+ Theme::DataType edit_item_data_type = Theme::DATA_TYPE_MAX;
+
+ ThemeItemImportTree *import_default_theme_items;
+ ThemeItemImportTree *import_editor_theme_items;
+ ThemeItemImportTree *import_other_theme_items;
+
+ LineEdit *import_another_theme_value;
+ Button *import_another_theme_button;
+ EditorFileDialog *import_another_theme_dialog;
+
+ ConfirmationDialog *confirm_closing_dialog;
+
+ void ok_pressed() override;
+ void _close_dialog();
+
+ void _dialog_about_to_show();
+ void _update_edit_types();
+ void _edited_type_selected(int p_item_idx);
+
+ void _update_edit_item_tree(String p_item_type);
+ void _item_tree_button_pressed(Object *p_item, int p_column, int p_id);
+
+ void _add_theme_type();
+ void _add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type);
+ void _remove_data_type_items(Theme::DataType p_data_type, String p_item_type);
+ void _remove_class_items();
+ void _remove_custom_items();
+ void _remove_all_items();
+
+ void _open_add_theme_item_dialog(int p_data_type);
+ void _open_rename_theme_item_dialog(Theme::DataType p_data_type, String p_item_name);
+ void _confirm_edit_theme_item();
+ void _edit_theme_item_gui_input(const Ref<InputEvent> &p_event);
+
+ void _open_select_another_theme();
+ void _select_another_theme_cbk(const String &p_path);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ void set_edited_theme(const Ref<Theme> &p_theme);
+
+ ThemeItemEditorDialog();
+};
+
+class ThemeTypeEditor : public MarginContainer {
+ GDCLASS(ThemeTypeEditor, MarginContainer);
+
+ Ref<Theme> edited_theme;
+ String edited_type;
+ bool updating = false;
+
+ struct LeadingStylebox {
+ bool pinned = false;
+ StringName item_name;
+ Ref<StyleBox> stylebox;
+ Ref<StyleBox> ref_stylebox;
+ };
+
+ LeadingStylebox leading_stylebox;
+
+ OptionButton *theme_type_list;
+ Button *add_type_button;
+ ConfirmationDialog *add_type_dialog;
+ LineEdit *add_type_filter;
+ ItemList *add_type_options;
+
+ CheckButton *show_default_items_button;
+
+ TabContainer *data_type_tabs;
+ VBoxContainer *color_items_list;
+ VBoxContainer *constant_items_list;
+ VBoxContainer *font_items_list;
+ VBoxContainer *font_size_items_list;
+ VBoxContainer *icon_items_list;
+ VBoxContainer *stylebox_items_list;
+
+ Vector<Control *> focusables;
+ Timer *update_debounce_timer;
+
+ VBoxContainer *_create_item_list(Theme::DataType p_data_type);
+ void _update_type_list();
+ void _update_type_list_debounced();
+ void _update_add_type_options(const String &p_filter = "");
+ OrderedHashMap<StringName, bool> _get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default);
+ HBoxContainer *_create_property_control(Theme::DataType p_data_type, String p_item_name, bool p_editable);
+ void _add_focusable(Control *p_control);
+ void _update_type_items();
+
+ void _list_type_selected(int p_index);
+ void _select_type(String p_type_name);
+ void _add_type_button_cbk();
+ void _add_type_filter_cbk(const String &p_value);
+ void _add_type_options_cbk(int p_index);
+ void _add_type_dialog_confirmed();
+ void _add_type_dialog_entered(const String &p_value);
+ void _add_type_dialog_activated(int p_index);
+ void _add_default_type_items();
+
+ void _item_add_cbk(int p_data_type, Control *p_control);
+ void _item_add_lineedit_cbk(String p_value, int p_data_type, Control *p_control);
+ void _item_override_cbk(int p_data_type, String p_item_name);
+ void _item_remove_cbk(int p_data_type, String p_item_name);
+ void _item_rename_cbk(int p_data_type, String p_item_name, Control *p_control);
+ void _item_rename_confirmed(int p_data_type, String p_item_name, Control *p_control);
+ void _item_rename_entered(String p_value, int p_data_type, String p_item_name, Control *p_control);
+ void _item_rename_canceled(int p_data_type, String p_item_name, Control *p_control);
+
+ void _color_item_changed(Color p_value, String p_item_name);
+ void _constant_item_changed(float p_value, String p_item_name);
+ void _font_size_item_changed(float p_value, String p_item_name);
+ void _edit_resource_item(RES p_resource, Control *p_editor);
+ void _font_item_changed(Ref<Font> p_value, String p_item_name);
+ void _icon_item_changed(Ref<Texture2D> p_value, String p_item_name);
+ void _stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name);
+ void _pin_leading_stylebox(Ref<StyleBox> p_stylebox, String p_item_name);
+ void _unpin_leading_stylebox();
+ void _update_stylebox_from_leading();
+
+protected:
+ void _notification(int p_what);
+
+public:
+ void set_edited_theme(const Ref<Theme> &p_theme);
+ void select_type(String p_type_name);
+
+ ThemeTypeEditor();
+};
+
class ThemeEditor : public VBoxContainer {
GDCLASS(ThemeEditor, VBoxContainer);
- Panel *main_panel;
- MarginContainer *main_container;
Ref<Theme> theme;
- EditorFileDialog *file_dialog;
-
- double time_left;
-
- MenuButton *theme_menu;
- ConfirmationDialog *add_del_dialog;
- HBoxContainer *type_hbc;
- MenuButton *type_menu;
- LineEdit *type_edit;
- HBoxContainer *name_hbc;
- MenuButton *name_menu;
- LineEdit *name_edit;
- OptionButton *type_select;
- Label *type_select_label;
- Label *name_select_label;
-
- enum PopupMode {
- POPUP_ADD,
- POPUP_CLASS_ADD,
- POPUP_REMOVE,
- POPUP_CLASS_REMOVE,
- POPUP_CREATE_EMPTY,
- POPUP_CREATE_EDITOR_EMPTY,
- POPUP_IMPORT_EDITOR_THEME
- };
+ Tabs *preview_tabs;
+ PanelContainer *preview_tabs_content;
+ Button *add_preview_button;
+ EditorFileDialog *preview_scene_dialog;
- int popup_mode;
+ ThemeTypeEditor *theme_type_editor;
- Tree *test_tree;
+ Label *theme_name;
+ ThemeItemEditorDialog *theme_edit_dialog;
- void _save_template_cbk(String fname);
- void _dialog_cbk();
- void _type_menu_cbk(int p_option);
- void _name_menu_about_to_show();
- void _name_menu_cbk(int p_option);
- void _theme_menu_cbk(int p_option);
- void _propagate_redraw(Control *p_at);
- void _refresh_interval();
+ void _theme_save_button_cbk(bool p_save_as);
+ void _theme_edit_button_cbk();
+
+ void _add_preview_button_cbk();
+ void _preview_scene_dialog_cbk(const String &p_path);
+ void _add_preview_tab(ThemeEditorPreview *p_preview_tab, const String &p_preview_name, const Ref<Texture2D> &p_icon);
+ void _change_preview_tab(int p_tab);
+ void _remove_preview_tab(int p_tab);
+ void _remove_preview_tab_invalid(Node *p_tab_control);
+ void _update_preview_tab(Node *p_tab_control);
+ void _preview_control_picked(String p_class_name);
protected:
void _notification(int p_what);
- static void _bind_methods();
public:
void edit(const Ref<Theme> &p_theme);
+ Ref<Theme> get_edited_theme();
ThemeEditor();
};
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
new file mode 100644
index 0000000000..cb7b5949d1
--- /dev/null
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -0,0 +1,464 @@
+/*************************************************************************/
+/* theme_editor_preview.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "theme_editor_preview.h"
+
+#include "core/input/input.h"
+#include "core/math/math_funcs.h"
+#include "scene/resources/packed_scene.h"
+
+#include "editor/editor_scale.h"
+
+void ThemeEditorPreview::set_preview_theme(const Ref<Theme> &p_theme) {
+ preview_content->set_theme(p_theme);
+}
+
+void ThemeEditorPreview::add_preview_overlay(Control *p_overlay) {
+ preview_overlay->add_child(p_overlay);
+ p_overlay->hide();
+}
+
+void ThemeEditorPreview::_propagate_redraw(Control *p_at) {
+ p_at->notification(NOTIFICATION_THEME_CHANGED);
+ p_at->minimum_size_changed();
+ p_at->update();
+ for (int i = 0; i < p_at->get_child_count(); i++) {
+ Control *a = Object::cast_to<Control>(p_at->get_child(i));
+ if (a) {
+ _propagate_redraw(a);
+ }
+ }
+}
+
+void ThemeEditorPreview::_refresh_interval() {
+ // In case the project settings have changed.
+ preview_bg->set_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
+
+ _propagate_redraw(preview_bg);
+ _propagate_redraw(preview_content);
+}
+
+void ThemeEditorPreview::_preview_visibility_changed() {
+ set_process(is_visible());
+}
+
+void ThemeEditorPreview::_picker_button_cbk() {
+ picker_overlay->set_visible(picker_button->is_pressed());
+}
+
+Control *ThemeEditorPreview::_find_hovered_control(Control *p_parent, Vector2 p_mouse_position) {
+ Control *found = nullptr;
+
+ for (int i = 0; i < p_parent->get_child_count(); i++) {
+ Control *cc = Object::cast_to<Control>(p_parent->get_child(i));
+ if (!cc || !cc->is_visible()) {
+ continue;
+ }
+
+ Rect2 crect = cc->get_rect();
+ if (crect.has_point(p_mouse_position)) {
+ // Check if there is a child control under mouse.
+ if (cc->get_child_count() > 0) {
+ found = _find_hovered_control(cc, p_mouse_position - cc->get_position());
+ }
+
+ // If there are no applicable children, use the control itself.
+ if (!found) {
+ found = cc;
+ }
+ break;
+ }
+ }
+
+ return found;
+}
+
+void ThemeEditorPreview::_draw_picker_overlay() {
+ if (!picker_button->is_pressed()) {
+ return;
+ }
+
+ picker_overlay->draw_rect(Rect2(Vector2(0.0, 0.0), picker_overlay->get_size()), get_theme_color("preview_picker_overlay_color", "ThemeEditor"));
+ if (hovered_control) {
+ Rect2 highlight_rect = hovered_control->get_global_rect();
+ highlight_rect.position = picker_overlay->get_global_transform().affine_inverse().xform(highlight_rect.position);
+
+ picker_overlay->draw_style_box(get_theme_stylebox("preview_picker_overlay", "ThemeEditor"), highlight_rect);
+ }
+}
+
+void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_event) {
+ if (!picker_button->is_pressed()) {
+ return;
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (hovered_control) {
+ StringName theme_type = hovered_control->get_theme_custom_type();
+ if (theme_type == StringName()) {
+ theme_type = hovered_control->get_class_name();
+ }
+
+ emit_signal("control_picked", theme_type);
+ picker_button->set_pressed(false);
+ picker_overlay->set_visible(false);
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+
+ if (mm.is_valid()) {
+ Vector2 mp = preview_content->get_local_mouse_position();
+ hovered_control = _find_hovered_control(preview_content, mp);
+ picker_overlay->update();
+ }
+}
+
+void ThemeEditorPreview::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (is_visible_in_tree()) {
+ set_process(true);
+ }
+
+ connect("visibility_changed", callable_mp(this, &ThemeEditorPreview::_preview_visibility_changed));
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons"));
+ } break;
+ case NOTIFICATION_PROCESS: {
+ time_left -= get_process_delta_time();
+ if (time_left < 0) {
+ time_left = 1.5;
+ _refresh_interval();
+ }
+ } break;
+ }
+}
+
+void ThemeEditorPreview::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("control_picked", PropertyInfo(Variant::STRING, "class_name")));
+}
+
+ThemeEditorPreview::ThemeEditorPreview() {
+ preview_toolbar = memnew(HBoxContainer);
+ add_child(preview_toolbar);
+
+ picker_button = memnew(Button);
+ preview_toolbar->add_child(picker_button);
+ picker_button->set_flat(true);
+ picker_button->set_toggle_mode(true);
+ picker_button->set_tooltip(TTR("Toggle the control picker, allowing to visually select control types for edit."));
+ picker_button->connect("pressed", callable_mp(this, &ThemeEditorPreview::_picker_button_cbk));
+
+ MarginContainer *preview_body = memnew(MarginContainer);
+ preview_body->set_custom_minimum_size(Size2(480, 0) * EDSCALE);
+ preview_body->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(preview_body);
+
+ ScrollContainer *preview_container = memnew(ScrollContainer);
+ preview_container->set_enable_v_scroll(true);
+ preview_container->set_enable_h_scroll(true);
+ preview_body->add_child(preview_container);
+
+ MarginContainer *preview_root = memnew(MarginContainer);
+ preview_container->add_child(preview_root);
+ preview_root->set_theme(Theme::get_default());
+ preview_root->set_clip_contents(true);
+ preview_root->set_custom_minimum_size(Size2(450, 0) * EDSCALE);
+ preview_root->set_v_size_flags(SIZE_EXPAND_FILL);
+ preview_root->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ preview_bg = memnew(ColorRect);
+ preview_bg->set_anchors_and_offsets_preset(PRESET_WIDE);
+ preview_bg->set_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
+ preview_root->add_child(preview_bg);
+
+ preview_content = memnew(MarginContainer);
+ preview_root->add_child(preview_content);
+ preview_content->add_theme_constant_override("margin_right", 4 * EDSCALE);
+ preview_content->add_theme_constant_override("margin_top", 4 * EDSCALE);
+ preview_content->add_theme_constant_override("margin_left", 4 * EDSCALE);
+ preview_content->add_theme_constant_override("margin_bottom", 4 * EDSCALE);
+
+ preview_overlay = memnew(MarginContainer);
+ preview_overlay->set_mouse_filter(MOUSE_FILTER_IGNORE);
+ preview_body->add_child(preview_overlay);
+
+ picker_overlay = memnew(Control);
+ add_preview_overlay(picker_overlay);
+ picker_overlay->connect("draw", callable_mp(this, &ThemeEditorPreview::_draw_picker_overlay));
+ picker_overlay->connect("gui_input", callable_mp(this, &ThemeEditorPreview::_gui_input_picker_overlay));
+}
+
+DefaultThemeEditorPreview::DefaultThemeEditorPreview() {
+ Panel *main_panel = memnew(Panel);
+ preview_content->add_child(main_panel);
+
+ MarginContainer *main_mc = memnew(MarginContainer);
+ main_mc->add_theme_constant_override("margin_right", 4 * EDSCALE);
+ main_mc->add_theme_constant_override("margin_top", 4 * EDSCALE);
+ main_mc->add_theme_constant_override("margin_left", 4 * EDSCALE);
+ main_mc->add_theme_constant_override("margin_bottom", 4 * EDSCALE);
+ preview_content->add_child(main_mc);
+
+ HBoxContainer *main_hb = memnew(HBoxContainer);
+ main_mc->add_child(main_hb);
+ main_hb->add_theme_constant_override("separation", 20 * EDSCALE);
+
+ VBoxContainer *first_vb = memnew(VBoxContainer);
+ main_hb->add_child(first_vb);
+ first_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ first_vb->add_theme_constant_override("separation", 10 * EDSCALE);
+
+ first_vb->add_child(memnew(Label("Label")));
+
+ first_vb->add_child(memnew(Button("Button")));
+ Button *bt = memnew(Button);
+ bt->set_text(TTR("Toggle Button"));
+ bt->set_toggle_mode(true);
+ bt->set_pressed(true);
+ first_vb->add_child(bt);
+ bt = memnew(Button);
+ bt->set_text(TTR("Disabled Button"));
+ bt->set_disabled(true);
+ first_vb->add_child(bt);
+ Button *tb = memnew(Button);
+ tb->set_flat(true);
+ tb->set_text("Button");
+ first_vb->add_child(tb);
+
+ CheckButton *cb = memnew(CheckButton);
+ cb->set_text("CheckButton");
+ first_vb->add_child(cb);
+ CheckBox *cbx = memnew(CheckBox);
+ cbx->set_text("CheckBox");
+ first_vb->add_child(cbx);
+
+ MenuButton *test_menu_button = memnew(MenuButton);
+ test_menu_button->set_text("MenuButton");
+ test_menu_button->get_popup()->add_item(TTR("Item"));
+ test_menu_button->get_popup()->add_item(TTR("Disabled Item"));
+ test_menu_button->get_popup()->set_item_disabled(1, true);
+ test_menu_button->get_popup()->add_separator();
+ test_menu_button->get_popup()->add_check_item(TTR("Check Item"));
+ test_menu_button->get_popup()->add_check_item(TTR("Checked Item"));
+ test_menu_button->get_popup()->set_item_checked(4, true);
+ test_menu_button->get_popup()->add_separator();
+ test_menu_button->get_popup()->add_radio_check_item(TTR("Radio Item"));
+ test_menu_button->get_popup()->add_radio_check_item(TTR("Checked Radio Item"));
+ test_menu_button->get_popup()->set_item_checked(7, true);
+ test_menu_button->get_popup()->add_separator(TTR("Named Separator"));
+
+ PopupMenu *test_submenu = memnew(PopupMenu);
+ test_menu_button->get_popup()->add_child(test_submenu);
+ test_submenu->set_name("submenu");
+ test_menu_button->get_popup()->add_submenu_item(TTR("Submenu"), "submenu");
+ test_submenu->add_item(TTR("Subitem 1"));
+ test_submenu->add_item(TTR("Subitem 2"));
+ first_vb->add_child(test_menu_button);
+
+ OptionButton *test_option_button = memnew(OptionButton);
+ test_option_button->add_item("OptionButton");
+ test_option_button->add_separator();
+ test_option_button->add_item(TTR("Has"));
+ test_option_button->add_item(TTR("Many"));
+ test_option_button->add_item(TTR("Options"));
+ first_vb->add_child(test_option_button);
+ first_vb->add_child(memnew(ColorPickerButton));
+
+ VBoxContainer *second_vb = memnew(VBoxContainer);
+ second_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ main_hb->add_child(second_vb);
+ second_vb->add_theme_constant_override("separation", 10 * EDSCALE);
+ LineEdit *le = memnew(LineEdit);
+ le->set_text("LineEdit");
+ second_vb->add_child(le);
+ le = memnew(LineEdit);
+ le->set_text(TTR("Disabled LineEdit"));
+ le->set_editable(false);
+ second_vb->add_child(le);
+ TextEdit *te = memnew(TextEdit);
+ te->set_text("TextEdit");
+ te->set_custom_minimum_size(Size2(0, 100) * EDSCALE);
+ second_vb->add_child(te);
+ second_vb->add_child(memnew(SpinBox));
+
+ HBoxContainer *vhb = memnew(HBoxContainer);
+ second_vb->add_child(vhb);
+ vhb->set_custom_minimum_size(Size2(0, 100) * EDSCALE);
+ vhb->add_child(memnew(VSlider));
+ VScrollBar *vsb = memnew(VScrollBar);
+ vsb->set_page(25);
+ vhb->add_child(vsb);
+ vhb->add_child(memnew(VSeparator));
+ VBoxContainer *hvb = memnew(VBoxContainer);
+ vhb->add_child(hvb);
+ hvb->set_alignment(BoxContainer::ALIGN_CENTER);
+ hvb->set_h_size_flags(SIZE_EXPAND_FILL);
+ hvb->add_child(memnew(HSlider));
+ HScrollBar *hsb = memnew(HScrollBar);
+ hsb->set_page(25);
+ hvb->add_child(hsb);
+ HSlider *hs = memnew(HSlider);
+ hs->set_editable(false);
+ hvb->add_child(hs);
+ hvb->add_child(memnew(HSeparator));
+ ProgressBar *pb = memnew(ProgressBar);
+ pb->set_value(50);
+ hvb->add_child(pb);
+
+ VBoxContainer *third_vb = memnew(VBoxContainer);
+ third_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ third_vb->add_theme_constant_override("separation", 10 * EDSCALE);
+ main_hb->add_child(third_vb);
+
+ TabContainer *tc = memnew(TabContainer);
+ third_vb->add_child(tc);
+ tc->set_custom_minimum_size(Size2(0, 135) * EDSCALE);
+ Control *tcc = memnew(Control);
+ tcc->set_name(TTR("Tab 1"));
+ tc->add_child(tcc);
+ tcc = memnew(Control);
+ tcc->set_name(TTR("Tab 2"));
+ tc->add_child(tcc);
+ tcc = memnew(Control);
+ tcc->set_name(TTR("Tab 3"));
+ tc->add_child(tcc);
+ tc->set_tab_disabled(2, true);
+
+ Tree *test_tree = memnew(Tree);
+ third_vb->add_child(test_tree);
+ test_tree->set_custom_minimum_size(Size2(0, 175) * EDSCALE);
+
+ TreeItem *item = test_tree->create_item();
+ item->set_text(0, "Tree");
+ item = test_tree->create_item(test_tree->get_root());
+ item->set_text(0, "Item");
+ item = test_tree->create_item(test_tree->get_root());
+ item->set_editable(0, true);
+ item->set_text(0, TTR("Editable Item"));
+ TreeItem *sub_tree = test_tree->create_item(test_tree->get_root());
+ sub_tree->set_text(0, TTR("Subtree"));
+ item = test_tree->create_item(sub_tree);
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_editable(0, true);
+ item->set_text(0, "Check Item");
+ item = test_tree->create_item(sub_tree);
+ item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
+ item->set_editable(0, true);
+ item->set_range_config(0, 0, 20, 0.1);
+ item->set_range(0, 2);
+ item = test_tree->create_item(sub_tree);
+ item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
+ item->set_editable(0, true);
+ item->set_text(0, TTR("Has,Many,Options"));
+ item->set_range(0, 2);
+}
+
+void SceneThemeEditorPreview::_reload_scene() {
+ if (loaded_scene.is_null()) {
+ return;
+ }
+
+ if (loaded_scene->get_path().is_empty() || !ResourceLoader::exists(loaded_scene->get_path())) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid path, the PackedScene resource was probably moved or removed."));
+ emit_signal("scene_invalidated");
+ return;
+ }
+
+ for (int i = preview_content->get_child_count() - 1; i >= 0; i--) {
+ Node *node = preview_content->get_child(i);
+ node->queue_delete();
+ preview_content->remove_child(node);
+ }
+
+ Node *instance = loaded_scene->instance();
+ if (!instance || !Object::cast_to<Control>(instance)) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid PackedScene resource, must have a Control node at its root."));
+ emit_signal("scene_invalidated");
+ return;
+ }
+
+ preview_content->add_child(instance);
+ emit_signal("scene_reloaded");
+}
+
+void SceneThemeEditorPreview::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ reload_scene_button->set_icon(get_theme_icon("Reload", "EditorIcons"));
+ } break;
+ }
+}
+
+void SceneThemeEditorPreview::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("scene_invalidated"));
+ ADD_SIGNAL(MethodInfo("scene_reloaded"));
+}
+
+bool SceneThemeEditorPreview::set_preview_scene(const String &p_path) {
+ loaded_scene = ResourceLoader::load(p_path);
+ if (loaded_scene.is_null()) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid file, not a PackedScene resource."));
+ return false;
+ }
+
+ Node *instance = loaded_scene->instance();
+ if (!instance || !Object::cast_to<Control>(instance)) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid PackedScene resource, must have a Control node at its root."));
+ return false;
+ }
+
+ preview_content->add_child(instance);
+ return true;
+}
+
+String SceneThemeEditorPreview::get_preview_scene_path() const {
+ if (loaded_scene.is_null()) {
+ return "";
+ }
+
+ return loaded_scene->get_path();
+}
+
+SceneThemeEditorPreview::SceneThemeEditorPreview() {
+ preview_toolbar->add_child(memnew(VSeparator));
+
+ reload_scene_button = memnew(Button);
+ reload_scene_button->set_flat(true);
+ reload_scene_button->set_tooltip(TTR("Reload the scene to reflect its most actual state."));
+ preview_toolbar->add_child(reload_scene_button);
+ reload_scene_button->connect("pressed", callable_mp(this, &SceneThemeEditorPreview::_reload_scene));
+}
diff --git a/editor/plugins/theme_editor_preview.h b/editor/plugins/theme_editor_preview.h
new file mode 100644
index 0000000000..efb7e424d4
--- /dev/null
+++ b/editor/plugins/theme_editor_preview.h
@@ -0,0 +1,118 @@
+/*************************************************************************/
+/* theme_editor_preview.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef THEME_EDITOR_PREVIEW_H
+#define THEME_EDITOR_PREVIEW_H
+
+#include "scene/gui/box_container.h"
+#include "scene/gui/check_box.h"
+#include "scene/gui/check_button.h"
+#include "scene/gui/color_picker.h"
+#include "scene/gui/color_rect.h"
+#include "scene/gui/label.h"
+#include "scene/gui/margin_container.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/panel.h"
+#include "scene/gui/progress_bar.h"
+#include "scene/gui/scroll_container.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/spin_box.h"
+#include "scene/gui/tab_container.h"
+#include "scene/gui/text_edit.h"
+#include "scene/gui/tree.h"
+#include "scene/resources/theme.h"
+
+#include "editor/editor_node.h"
+
+class ThemeEditorPreview : public VBoxContainer {
+ GDCLASS(ThemeEditorPreview, VBoxContainer);
+
+ ColorRect *preview_bg;
+ MarginContainer *preview_overlay;
+ Control *picker_overlay;
+ Control *hovered_control = nullptr;
+
+ double time_left = 0;
+
+ void _propagate_redraw(Control *p_at);
+ void _refresh_interval();
+ void _preview_visibility_changed();
+
+ void _picker_button_cbk();
+ Control *_find_hovered_control(Control *p_parent, Vector2 p_mouse_position);
+
+ void _draw_picker_overlay();
+ void _gui_input_picker_overlay(const Ref<InputEvent> &p_event);
+
+protected:
+ HBoxContainer *preview_toolbar;
+ MarginContainer *preview_content;
+ Button *picker_button;
+
+ void add_preview_overlay(Control *p_overlay);
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_preview_theme(const Ref<Theme> &p_theme);
+
+ ThemeEditorPreview();
+};
+
+class DefaultThemeEditorPreview : public ThemeEditorPreview {
+ GDCLASS(DefaultThemeEditorPreview, ThemeEditorPreview);
+
+public:
+ DefaultThemeEditorPreview();
+};
+
+class SceneThemeEditorPreview : public ThemeEditorPreview {
+ GDCLASS(SceneThemeEditorPreview, ThemeEditorPreview);
+
+ Ref<PackedScene> loaded_scene;
+
+ Button *reload_scene_button;
+
+ void _reload_scene();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ bool set_preview_scene(const String &p_path);
+ String get_preview_scene_path() const;
+
+ SceneThemeEditorPreview();
+};
+
+#endif // THEME_EDITOR_PREVIEW_H
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
deleted file mode 100644
index bd721244ea..0000000000
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ /dev/null
@@ -1,2329 +0,0 @@
-/*************************************************************************/
-/* tile_map_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "tile_map_editor_plugin.h"
-
-#include "canvas_item_editor_plugin.h"
-#include "core/input/input.h"
-#include "core/math/math_funcs.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) {
- Callable callable_tileset_settings_changed = callable_mp(this, &TileMapEditor::_tileset_settings_changed);
-
- if (node->is_connected("settings_changed", callable_tileset_settings_changed)) {
- // Fixes #44824, which describes a situation where you can reselect a TileMap node without first de-selecting it when switching scenes.
- node->disconnect("settings_changed", callable_tileset_settings_changed);
- }
- node = nullptr;
- }
-}
-
-void TileMapEditor::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_PROCESS: {
- if (bucket_queue.size()) {
- CanvasItemEditor::get_singleton()->update_viewport();
- }
-
- } break;
-
- case NOTIFICATION_ENTER_TREE: {
- get_tree()->connect("node_removed", callable_mp(this, &TileMapEditor::_node_removed));
- [[fallthrough]];
- }
-
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- if (is_visible_in_tree()) {
- _update_palette();
- }
-
- paint_button->set_icon(get_theme_icon("Edit", "EditorIcons"));
- line_button->set_icon(get_theme_icon("CurveLinear", "EditorIcons"));
- rectangle_button->set_icon(get_theme_icon("Rectangle", "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_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_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_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;
-
- case NOTIFICATION_APPLICATION_FOCUS_OUT: {
- if (tool == TOOL_PAINTING) {
- Vector<int> ids = get_selected_tiles();
-
- if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
- _set_cell(over_tile, ids, flip_h, flip_v, transpose);
- _finish_undo();
-
- paint_undo.clear();
- }
-
- tool = TOOL_NONE;
- _update_button_tool();
- }
-
- // set flag to ignore over_tile on refocus
- refocus_over_tile = true;
- } break;
- }
-}
-
-void TileMapEditor::_update_button_tool() {
- Button *tb[6] = { paint_button, line_button, rectangle_button, bucket_fill_button, picker_button, select_button };
-
- // Unpress all buttons
- for (int i = 0; i < 6; i++) {
- tb[i]->set_pressed(false);
- }
-
- // Press the good button
- switch (tool) {
- case TOOL_NONE:
- case TOOL_PAINTING: {
- paint_button->set_pressed(true);
- } break;
- case TOOL_LINE_PAINT: {
- line_button->set_pressed(true);
- } break;
- case TOOL_RECTANGLE_PAINT: {
- rectangle_button->set_pressed(true);
- } break;
- case TOOL_BUCKET: {
- bucket_fill_button->set_pressed(true);
- } break;
- case TOOL_PICKING: {
- picker_button->set_pressed(true);
- } break;
- case TOOL_SELECTING: {
- select_button->set_pressed(true);
- } break;
- default:
- break;
- }
-
- if (tool != TOOL_PICKING) {
- last_tool = tool;
- }
-}
-
-void TileMapEditor::_button_tool_select(int p_tool) {
- tool = (Tool)p_tool;
- _update_button_tool();
- switch (tool) {
- case TOOL_SELECTING: {
- selection_active = false;
- } break;
- default:
- break;
- }
- CanvasItemEditor::get_singleton()->update_viewport();
-}
-
-void TileMapEditor::_menu_option(int p_option) {
- switch (p_option) {
- case OPTION_COPY: {
- _update_copydata();
-
- if (selection_active) {
- tool = TOOL_PASTING;
-
- CanvasItemEditor::get_singleton()->update_viewport();
- }
- } break;
- case OPTION_ERASE_SELECTION: {
- if (!selection_active) {
- return;
- }
-
- _start_undo(TTR("Erase Selection"));
- _erase_selection();
- _finish_undo();
-
- selection_active = false;
- copydata.clear();
-
- CanvasItemEditor::get_singleton()->update_viewport();
- } break;
- case OPTION_FIX_INVALID: {
- undo_redo->create_action(TTR("Fix Invalid Tiles"));
- undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data"));
- node->fix_invalid_tiles();
- undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data"));
- undo_redo->commit_action();
-
- } break;
- case OPTION_CUT: {
- if (selection_active) {
- _update_copydata();
-
- _start_undo(TTR("Cut Selection"));
- _erase_selection();
- _finish_undo();
-
- selection_active = false;
-
- tool = TOOL_PASTING;
-
- CanvasItemEditor::get_singleton()->update_viewport();
- }
- } break;
- }
- _update_button_tool();
-}
-
-void TileMapEditor::_palette_selected(int index) {
- _update_palette();
-}
-
-void TileMapEditor::_palette_multi_selected(int index, bool selected) {
- _update_palette();
-}
-
-void TileMapEditor::_palette_input(const Ref<InputEvent> &p_event) {
- const Ref<InputEventMouseButton> mb = p_event;
-
- // Zoom in/out using Ctrl + mouse wheel.
- if (mb.is_valid() && mb->is_pressed() && mb->get_command()) {
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
- size_slider->set_value(size_slider->get_value() + 0.2);
- }
-
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
- size_slider->set_value(size_slider->get_value() - 0.2);
- }
- }
-}
-
-void TileMapEditor::_canvas_mouse_enter() {
- mouse_over = true;
- CanvasItemEditor::get_singleton()->update_viewport();
-}
-
-void TileMapEditor::_canvas_mouse_exit() {
- mouse_over = false;
- CanvasItemEditor::get_singleton()->update_viewport();
-}
-
-Vector<int> TileMapEditor::get_selected_tiles() const {
- Vector<int> items = palette->get_selected_items();
-
- if (items.size() == 0) {
- items.push_back(TileMap::INVALID_CELL);
- return items;
- }
-
- for (int i = items.size() - 1; i >= 0; i--) {
- items.write[i] = palette->get_item_metadata(items[i]);
- }
- return items;
-}
-
-void TileMapEditor::set_selected_tiles(Vector<int> p_tiles) {
- palette->deselect_all();
-
- for (int i = p_tiles.size() - 1; i >= 0; i--) {
- int idx = palette->find_metadata(p_tiles[i]);
-
- if (idx >= 0) {
- palette->select(idx, false);
- }
- }
-
- palette->ensure_current_is_visible();
-}
-
-Dictionary TileMapEditor::_create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord) {
- Dictionary cell;
-
- cell["id"] = tile;
- cell["flip_h"] = flip_x;
- cell["flip_y"] = flip_y;
- cell["transpose"] = transpose;
- cell["auto_coord"] = autotile_coord;
-
- return cell;
-}
-
-void TileMapEditor::_create_set_cell_undo_redo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new) {
- Dictionary cell_old = _create_cell_dictionary(p_cell_old.idx, p_cell_old.xf, p_cell_old.yf, p_cell_old.tr, p_cell_old.ac);
- Dictionary cell_new = _create_cell_dictionary(p_cell_new.idx, p_cell_new.xf, p_cell_new.yf, p_cell_new.tr, p_cell_new.ac);
-
- undo_redo->add_undo_method(node, "_set_celld", p_vec, cell_old);
- undo_redo->add_do_method(node, "_set_celld", p_vec, cell_new);
-}
-
-void TileMapEditor::_start_undo(const String &p_action) {
- undo_data.clear();
- undo_redo->create_action(p_action);
-}
-
-void TileMapEditor::_finish_undo() {
- if (undo_data.size()) {
- for (Map<Point2i, CellOp>::Element *E = undo_data.front(); E; E = E->next()) {
- _create_set_cell_undo_redo(E->key(), E->get(), _get_op_from_cell(E->key()));
- }
-
- undo_data.clear();
- }
-
- undo_redo->commit_action();
-}
-
-void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord) {
- ERR_FAIL_COND(!node);
-
- if (p_values.size() == 0) {
- return;
- }
-
- int p_value = p_values[Math::rand() % p_values.size()];
- int prev_val = node->get_cell(p_pos.x, p_pos.y);
-
- bool prev_flip_h = node->is_cell_x_flipped(p_pos.x, p_pos.y);
- bool prev_flip_v = node->is_cell_y_flipped(p_pos.x, p_pos.y);
- bool prev_transpose = node->is_cell_transposed(p_pos.x, p_pos.y);
- Vector2 prev_position = node->get_cell_autotile_coord(p_pos.x, p_pos.y);
-
- Vector2 position;
- int current = manual_palette->get_current();
- if (current != -1) {
- if (tool != TOOL_PASTING) {
- position = manual_palette->get_item_metadata(current);
- } else {
- position = p_autotile_coord;
- }
- } else {
- // If there is no manual tile selected, that either means that
- // autotiling is enabled, or the given tile is not autotiling. Either
- // way, the coordinate of the tile does not matter, so assigning it to
- // the coordinate of the existing tile works fine.
- position = prev_position;
- }
-
- if (p_value == prev_val && p_flip_h == prev_flip_h && p_flip_v == prev_flip_v && p_transpose == prev_transpose && prev_position == position) {
- return; // Check that it's actually different.
- }
-
- for (int y = p_pos.y - 1; y <= p_pos.y + 1; y++) {
- for (int x = p_pos.x - 1; x <= p_pos.x + 1; x++) {
- Point2i p = Point2i(x, y);
- if (!undo_data.has(p)) {
- undo_data[p] = _get_op_from_cell(p);
- }
- }
- }
-
- node->_set_celld(p_pos, _create_cell_dictionary(p_value, p_flip_h, p_flip_v, p_transpose, p_autotile_coord));
-
- if (tool == TOOL_PASTING) {
- return;
- }
-
- if (manual_autotile || (p_value != -1 && node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE)) {
- if (current != -1) {
- node->set_cell_autotile_coord(p_pos.x, p_pos.y, position);
- } else if (node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE && priority_atlastile) {
- // BIND_CENTER is used to indicate that bitmask should not update for this tile cell.
- node->get_tileset()->autotile_set_bitmask(p_value, Vector2(p_pos.x, p_pos.y), TileSet::BIND_CENTER);
- node->update_cell_bitmask(p_pos.x, p_pos.y);
- }
- } else {
- node->update_bitmask_area(Point2(p_pos));
- }
-}
-
-void TileMapEditor::_manual_toggled(bool p_enabled) {
- manual_autotile = p_enabled;
- _update_palette();
-}
-
-void TileMapEditor::_priority_toggled(bool p_enabled) {
- priority_atlastile = p_enabled;
- _update_palette();
-}
-
-void TileMapEditor::_text_entered(const String &p_text) {
- canvas_item_editor_viewport->grab_focus();
-}
-
-void TileMapEditor::_text_changed(const String &p_text) {
- _update_palette();
-}
-
-void TileMapEditor::_sbox_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
-
- if (k.is_valid() && (k->get_keycode() == KEY_UP ||
- k->get_keycode() == KEY_DOWN ||
- k->get_keycode() == KEY_PAGEUP ||
- k->get_keycode() == KEY_PAGEDOWN)) {
- palette->call("_gui_input", k);
- search_box->accept_event();
- }
-}
-
-// Implementation detail of TileMapEditor::_update_palette();
-// In modern C++ this could have been inside its body.
-namespace {
-struct _PaletteEntry {
- int id = 0;
- String name;
-
- bool operator<(const _PaletteEntry &p_rhs) const {
- // Natural no case comparison will compare strings based on CharType
- // order (except digits) and on numbers that start on the same position.
- return name.naturalnocasecmp_to(p_rhs.name) < 0;
- }
-};
-} // namespace
-
-void TileMapEditor::_update_palette() {
- if (!node) {
- return;
- }
-
- // Update the clear button.
- clear_transform_button->set_disabled(!flip_h && !flip_v && !transpose);
-
- // Update the palette.
- Vector<int> selected = get_selected_tiles();
- int selected_single = palette->get_current();
- int selected_manual = manual_palette->get_current();
- palette->clear();
- manual_palette->clear();
- manual_palette->hide();
-
- Ref<TileSet> tileset = node->get_tileset();
- if (tileset.is_null()) {
- search_box->set_text("");
- search_box->set_editable(false);
- info_message->show();
- return;
- }
-
- search_box->set_editable(true);
- info_message->hide();
-
- List<int> tiles;
- tileset->get_tile_list(&tiles);
- if (tiles.is_empty()) {
- return;
- }
-
- float min_size = EDITOR_DEF("editors/tile_map/preview_size", 64);
- min_size *= EDSCALE;
- int hseparation = EDITOR_DEF("editors/tile_map/palette_item_hseparation", 8);
- bool show_tile_names = bool(EDITOR_DEF("editors/tile_map/show_tile_names", true));
- 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_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));
- palette->set_same_column_width(true);
- manual_palette->set_fixed_icon_size(Size2(min_size, min_size));
- manual_palette->set_same_column_width(true);
-
- String filter = search_box->get_text().strip_edges();
-
- Vector<_PaletteEntry> entries;
-
- for (List<int>::Element *E = tiles.front(); E; E = E->next()) {
- String name = tileset->tile_get_name(E->get());
-
- if (name != "") {
- if (show_tile_ids) {
- if (sort_by_name) {
- name = name + " - " + itos(E->get());
- } else {
- name = itos(E->get()) + " - " + name;
- }
- }
- } else {
- name = "#" + itos(E->get());
- }
-
- if (filter != "" && !filter.is_subsequence_ofi(name)) {
- continue;
- }
-
- const _PaletteEntry entry = { E->get(), name };
- entries.push_back(entry);
- }
-
- if (sort_by_name) {
- entries.sort();
- }
-
- for (int i = 0; i < entries.size(); i++) {
- if (show_tile_names) {
- palette->add_item(entries[i].name);
- } else {
- palette->add_item(String());
- }
-
- Ref<Texture2D> tex = tileset->tile_get_texture(entries[i].id);
-
- if (tex.is_valid()) {
- Rect2 region = tileset->tile_get_region(entries[i].id);
-
- if (tileset->tile_get_tile_mode(entries[i].id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(entries[i].id) == TileSet::ATLAS_TILE) {
- int spacing = tileset->autotile_get_spacing(entries[i].id);
- region.size = tileset->autotile_get_size(entries[i].id);
- region.position += (region.size + Vector2(spacing, spacing)) * tileset->autotile_get_icon_coordinate(entries[i].id);
- }
-
- // Transpose and flip.
- palette->set_item_icon_transposed(palette->get_item_count() - 1, transpose);
- if (flip_h) {
- region.size.x = -region.size.x;
- }
- if (flip_v) {
- region.size.y = -region.size.y;
- }
-
- // Set region.
- if (region.size != Size2()) {
- palette->set_item_icon_region(palette->get_item_count() - 1, region);
- }
-
- // Set icon.
- palette->set_item_icon(palette->get_item_count() - 1, tex);
-
- // Modulation.
- Color color = tileset->tile_get_modulate(entries[i].id);
- palette->set_item_icon_modulate(palette->get_item_count() - 1, color);
- }
-
- palette->set_item_metadata(palette->get_item_count() - 1, entries[i].id);
- }
-
- int sel_tile = selected.get(0);
- if (selected.get(0) != TileMap::INVALID_CELL) {
- set_selected_tiles(selected);
- sel_tile = selected.get(Math::rand() % selected.size());
- } else if (palette->get_item_count() > 0) {
- palette->select(0);
- sel_tile = palette->get_selected_items().get(0);
- }
-
- if (sel_tile != TileMap::INVALID_CELL && ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || (!priority_atlastile && tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE))) {
- const Map<Vector2, uint32_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile);
-
- Vector<Vector2> entries2;
- for (const Map<Vector2, uint32_t>::Element *E = tiles2.front(); E; E = E->next()) {
- entries2.push_back(E->key());
- }
- // Sort tiles in row-major order.
- struct SwapComparator {
- _FORCE_INLINE_ bool operator()(const Vector2 &v_l, const Vector2 &v_r) const {
- return v_l.y != v_r.y ? v_l.y < v_r.y : v_l.x < v_r.x;
- }
- };
- entries2.sort_custom<SwapComparator>();
-
- Ref<Texture2D> tex = tileset->tile_get_texture(sel_tile);
-
- for (int i = 0; i < entries2.size(); i++) {
- manual_palette->add_item(String());
-
- if (tex.is_valid()) {
- Rect2 region = tileset->tile_get_region(sel_tile);
- int spacing = tileset->autotile_get_spacing(sel_tile);
- region.size = tileset->autotile_get_size(sel_tile); // !!
- region.position += (region.size + Vector2(spacing, spacing)) * entries2[i];
-
- if (!region.has_no_area()) {
- manual_palette->set_item_icon_region(manual_palette->get_item_count() - 1, region);
- }
-
- manual_palette->set_item_icon(manual_palette->get_item_count() - 1, tex);
- }
-
- manual_palette->set_item_metadata(manual_palette->get_item_count() - 1, entries2[i]);
- }
- }
-
- if (manual_palette->get_item_count() > 0) {
- // Only show the manual palette if at least tile exists in it.
- if (selected_manual == -1 || selected_single != palette->get_current()) {
- selected_manual = 0;
- }
- if (selected_manual < manual_palette->get_item_count()) {
- manual_palette->set_current(selected_manual);
- }
- manual_palette->show();
- }
-
- if (sel_tile != TileMap::INVALID_CELL && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) {
- manual_button->show();
- priority_button->hide();
- } else {
- manual_button->hide();
- priority_button->show();
- }
-}
-
-void TileMapEditor::_pick_tile(const Point2 &p_pos) {
- int id = node->get_cell(p_pos.x, p_pos.y);
-
- if (id == TileMap::INVALID_CELL) {
- return;
- }
-
- if (search_box->get_text() != "") {
- search_box->set_text("");
- _update_palette();
- }
-
- flip_h = node->is_cell_x_flipped(p_pos.x, p_pos.y);
- flip_v = node->is_cell_y_flipped(p_pos.x, p_pos.y);
- transpose = node->is_cell_transposed(p_pos.x, p_pos.y);
- autotile_coord = node->get_cell_autotile_coord(p_pos.x, p_pos.y);
-
- Vector<int> selected;
- selected.push_back(id);
- set_selected_tiles(selected);
- _update_palette();
-
- if ((manual_autotile && node->get_tileset()->tile_get_tile_mode(id) == TileSet::AUTO_TILE) || (!priority_atlastile && node->get_tileset()->tile_get_tile_mode(id) == TileSet::ATLAS_TILE)) {
- manual_palette->select(manual_palette->find_metadata((Point2)autotile_coord));
- }
-
- CanvasItemEditor::get_singleton()->update_viewport();
-}
-
-Vector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool erase, bool preview) {
- int prev_id = node->get_cell(p_start.x, p_start.y);
- Vector<int> ids;
- ids.push_back(TileMap::INVALID_CELL);
- if (!erase) {
- ids = get_selected_tiles();
-
- if (ids.size() == 0 || ids[0] == TileMap::INVALID_CELL) {
- return Vector<Vector2>();
- }
- } else if (prev_id == TileMap::INVALID_CELL) {
- return Vector<Vector2>();
- }
-
- // Check if the tile variation is the same
- Vector2 prev_position = node->get_cell_autotile_coord(p_start.x, p_start.y);
- if (ids.size() == 1 && ids[0] == prev_id) {
- int current = manual_palette->get_current();
- Vector2 position = manual_palette->get_item_metadata(current);
- if (prev_position == position) {
- // Same ID and variation, nothing to change
- return Vector<Vector2>();
- }
- }
-
- Rect2i r = node->get_used_rect();
-
- int area = r.get_area();
- if (preview) {
- // Test if we can re-use the result from preview bucket fill
- bool invalidate_cache = false;
- // Area changed
- if (r != bucket_cache_rect) {
- _clear_bucket_cache();
- }
- // Cache grid is not initialized
- if (bucket_cache_visited == nullptr) {
- bucket_cache_visited = new bool[area];
- invalidate_cache = true;
- }
- // Tile ID changed or position wasn't visited by the previous fill
- const int loc = (p_start.x - r.position.x) + (p_start.y - r.position.y) * r.get_size().x;
- const bool in_range = 0 <= loc && loc < area;
- if (prev_id != bucket_cache_tile || (in_range && !bucket_cache_visited[loc])) {
- invalidate_cache = true;
- }
- if (invalidate_cache) {
- for (int i = 0; i < area; ++i) {
- bucket_cache_visited[i] = false;
- }
- bucket_cache = Vector<Vector2>();
- bucket_cache_tile = prev_id;
- bucket_cache_rect = r;
- bucket_queue.clear();
- }
- }
-
- Vector<Vector2> points;
- Vector<Vector2> non_preview_cache;
- int count = 0;
- int limit = 0;
-
- if (preview) {
- limit = 1024;
- } else {
- bucket_queue.clear();
- }
-
- bucket_queue.push_back(p_start);
-
- while (bucket_queue.size()) {
- Point2i n = bucket_queue.front()->get();
- bucket_queue.pop_front();
-
- if (!r.has_point(n)) {
- continue;
- }
-
- if (node->get_cell(n.x, n.y) == prev_id) {
- if (preview) {
- int loc = (n.x - r.position.x) + (n.y - r.position.y) * r.get_size().x;
- if (bucket_cache_visited[loc]) {
- continue;
- }
- bucket_cache_visited[loc] = true;
- bucket_cache.push_back(n);
- } else {
- if (non_preview_cache.find(n) >= 0) {
- continue;
- }
- points.push_back(n);
- non_preview_cache.push_back(n);
- }
-
- bucket_queue.push_back(Point2i(n.x, n.y + 1));
- bucket_queue.push_back(Point2i(n.x, n.y - 1));
- bucket_queue.push_back(Point2i(n.x + 1, n.y));
- bucket_queue.push_back(Point2i(n.x - 1, n.y));
- count++;
- }
-
- if (limit > 0 && count >= limit) {
- break;
- }
- }
-
- return preview ? bucket_cache : points;
-}
-
-void TileMapEditor::_fill_points(const Vector<Vector2> &p_points, const Dictionary &p_op) {
- int len = p_points.size();
- const Vector2 *pr = p_points.ptr();
-
- Vector<int> ids = p_op["id"];
- bool xf = p_op["flip_h"];
- bool yf = p_op["flip_v"];
- bool tr = p_op["transpose"];
-
- for (int i = 0; i < len; i++) {
- _set_cell(pr[i], ids, xf, yf, tr);
- node->make_bitmask_area_dirty(pr[i]);
- }
- if (!manual_autotile) {
- node->update_dirty_bitmask();
- }
-}
-
-void TileMapEditor::_erase_points(const Vector<Vector2> &p_points) {
- int len = p_points.size();
- const Vector2 *pr = p_points.ptr();
-
- for (int i = 0; i < len; i++) {
- _set_cell(pr[i], invalid_cell);
- }
-}
-
-void TileMapEditor::_select(const Point2i &p_from, const Point2i &p_to) {
- Point2i begin = p_from;
- Point2i end = p_to;
-
- if (begin.x > end.x) {
- SWAP(begin.x, end.x);
- }
- if (begin.y > end.y) {
- SWAP(begin.y, end.y);
- }
-
- rectangle.position = begin;
- rectangle.size = end - begin;
-
- CanvasItemEditor::get_singleton()->update_viewport();
-}
-
-void TileMapEditor::_erase_selection() {
- if (!selection_active) {
- return;
- }
-
- for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
- for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- _set_cell(Point2i(j, i), invalid_cell, false, false, false);
- }
- }
-}
-
-void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord, const Transform2D &p_xform) {
- Ref<Texture2D> t = node->get_tileset()->tile_get_texture(p_cell);
-
- if (t.is_null()) {
- return;
- }
-
- Vector2 tile_ofs = node->get_tileset()->tile_get_texture_offset(p_cell);
-
- Rect2 r = node->get_tileset()->tile_get_region(p_cell);
- if (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::AUTO_TILE || node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE) {
- Vector2 offset;
- if (tool != TOOL_PASTING) {
- int selected = manual_palette->get_current();
- if ((manual_autotile || (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE && !priority_atlastile)) && selected != -1) {
- offset = manual_palette->get_item_metadata(selected);
- } else {
- offset = node->get_tileset()->autotile_get_icon_coordinate(p_cell);
- }
- } else {
- offset = p_autotile_coord;
- }
-
- int spacing = node->get_tileset()->autotile_get_spacing(p_cell);
- r.size = node->get_tileset()->autotile_get_size(p_cell);
- r.position += (r.size + Vector2(spacing, spacing)) * offset;
- }
- Size2 cell_size = node->get_cell_size();
- bool centered_texture = node->is_centered_textures_enabled();
- bool compatibility_mode_enabled = node->is_compatibility_mode_enabled();
- Rect2 rect = Rect2();
- rect.position = node->map_to_world(p_point) + node->get_cell_draw_offset();
-
- if (r.has_no_area()) {
- rect.size = t->get_size();
- } else {
- rect.size = r.size;
- }
-
- if (compatibility_mode_enabled && !centered_texture) {
- if (rect.size.y > rect.size.x) {
- if ((p_flip_h && (p_flip_v || p_transpose)) || (p_flip_v && !p_transpose)) {
- tile_ofs.y += rect.size.y - rect.size.x;
- }
- } else if (rect.size.y < rect.size.x) {
- if ((p_flip_v && (p_flip_h || p_transpose)) || (p_flip_h && !p_transpose)) {
- tile_ofs.x += rect.size.x - rect.size.y;
- }
- }
- }
-
- if (p_transpose) {
- SWAP(tile_ofs.x, tile_ofs.y);
- if (centered_texture) {
- rect.position.x += cell_size.x / 2 - rect.size.y / 2;
- rect.position.y += cell_size.y / 2 - rect.size.x / 2;
- }
- } else if (centered_texture) {
- rect.position += cell_size / 2 - rect.size / 2;
- }
-
- if (p_flip_h) {
- rect.size.x *= -1.0;
- tile_ofs.x *= -1.0;
- }
-
- if (p_flip_v) {
- rect.size.y *= -1.0;
- tile_ofs.y *= -1.0;
- }
-
- if (compatibility_mode_enabled && !centered_texture) {
- if (node->get_tile_origin() == TileMap::TILE_ORIGIN_TOP_LEFT) {
- rect.position += tile_ofs;
- } else if (node->get_tile_origin() == TileMap::TILE_ORIGIN_BOTTOM_LEFT) {
- rect.position += tile_ofs;
-
- if (p_transpose) {
- if (p_flip_h) {
- rect.position.x -= cell_size.x;
- } else {
- rect.position.x += cell_size.x;
- }
- } else {
- if (p_flip_v) {
- rect.position.y -= cell_size.y;
- } else {
- rect.position.y += cell_size.y;
- }
- }
-
- } else if (node->get_tile_origin() == TileMap::TILE_ORIGIN_CENTER) {
- rect.position += tile_ofs;
-
- if (p_flip_h) {
- rect.position.x -= cell_size.x / 2;
- } else {
- rect.position.x += cell_size.x / 2;
- }
-
- if (p_flip_v) {
- rect.position.y -= cell_size.y / 2;
- } else {
- rect.position.y += cell_size.y / 2;
- }
- }
- } else {
- rect.position += tile_ofs;
- }
-
- Color modulate = node->get_tileset()->tile_get_modulate(p_cell);
- modulate.a = 0.5;
-
- Transform2D old_transform = p_viewport->get_viewport_transform();
- p_viewport->draw_set_transform_matrix(p_xform); // Take into account TileMap transformation when displaying cell
- if (r.has_no_area()) {
- p_viewport->draw_texture_rect(t, rect, false, modulate, p_transpose);
- } else {
- p_viewport->draw_texture_rect_region(t, rect, r, modulate, p_transpose);
- }
- p_viewport->draw_set_transform_matrix(old_transform);
-}
-
-void TileMapEditor::_draw_fill_preview(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord, const Transform2D &p_xform) {
- Vector<Vector2> points = _bucket_fill(p_point, false, true);
- const Vector2 *pr = points.ptr();
- int len = points.size();
-
- for (int i = 0; i < len; ++i) {
- _draw_cell(p_viewport, p_cell, pr[i], p_flip_h, p_flip_v, p_transpose, p_autotile_coord, p_xform);
- }
-}
-
-void TileMapEditor::_clear_bucket_cache() {
- if (bucket_cache_visited) {
- delete[] bucket_cache_visited;
- bucket_cache_visited = nullptr;
- }
-}
-
-void TileMapEditor::_update_copydata() {
- copydata.clear();
-
- if (!selection_active) {
- return;
- }
-
- for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
- for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- TileData tcd;
-
- tcd.cell = node->get_cell(j, i);
- if (tcd.cell != TileMap::INVALID_CELL) {
- tcd.pos = Point2i(j, i);
- tcd.flip_h = node->is_cell_x_flipped(j, i);
- tcd.flip_v = node->is_cell_y_flipped(j, i);
- tcd.transpose = node->is_cell_transposed(j, i);
- tcd.autotile_coord = node->get_cell_autotile_coord(j, i);
-
- copydata.push_back(tcd);
- }
- }
- }
-}
-
-static inline Vector<Point2i> line(int x0, int x1, int y0, int y1) {
- Vector<Point2i> points;
-
- float dx = ABS(x1 - x0);
- float dy = ABS(y1 - y0);
-
- int x = x0;
- int y = y0;
-
- int sx = x0 > x1 ? -1 : 1;
- int sy = y0 > y1 ? -1 : 1;
-
- if (dx > dy) {
- float err = dx / 2;
-
- for (; x != x1; x += sx) {
- points.push_back(Vector2(x, y));
-
- err -= dy;
- if (err < 0) {
- y += sy;
- err += dx;
- }
- }
- } else {
- float err = dy / 2;
-
- for (; y != y1; y += sy) {
- points.push_back(Vector2(x, y));
-
- err -= dx;
- if (err < 0) {
- x += sx;
- err += dy;
- }
- }
- }
-
- points.push_back(Vector2(x, y));
-
- return points;
-}
-
-bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
- if (!node || !node->get_tileset().is_valid() || !node->is_visible_in_tree() || CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) {
- return false;
- }
-
- Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
- Transform2D xform_inv = xform.affine_inverse();
-
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (mb->is_pressed()) {
- if (Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
- return false; // Drag.
- }
-
- if (tool == TOOL_NONE) {
- tool = TOOL_PAINTING;
- _update_button_tool();
-
- if (mb->get_command()) {
- tool = TOOL_PICKING;
- _pick_tile(over_tile);
- _update_button_tool();
-
- return true;
- }
- }
-
- if (tool == TOOL_LINE_PAINT || tool == TOOL_RECTANGLE_PAINT) {
- selection_active = false;
- rectangle_begin = over_tile;
-
- mouse_down = true;
- } else if (tool == TOOL_PAINTING) {
- Vector<int> ids = get_selected_tiles();
-
- if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
- tool = TOOL_PAINTING;
-
- _start_undo(TTR("Paint TileMap"));
- }
- } else if (tool == TOOL_PICKING) {
- _pick_tile(over_tile);
- } else if (tool == TOOL_SELECTING) {
- selection_active = true;
- rectangle_begin = over_tile;
- }
-
- _update_button_tool();
- return true;
-
- } else {
- // Mousebutton was released.
- if (tool != TOOL_NONE) {
- if (tool == TOOL_PAINTING) {
- Vector<int> ids = get_selected_tiles();
-
- if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
- _set_cell(over_tile, ids, flip_h, flip_v, transpose);
- _finish_undo();
-
- paint_undo.clear();
- }
- } else if (tool == TOOL_LINE_PAINT) {
- if (!mouse_down) {
- return true;
- }
-
- Vector<int> ids = get_selected_tiles();
-
- if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
- _start_undo(TTR("Line Draw"));
- for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
- _set_cell(E->key(), ids, flip_h, flip_v, transpose);
- }
- _finish_undo();
-
- paint_undo.clear();
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- mouse_down = false;
- return true;
- }
-
- mouse_down = false;
- } else if (tool == TOOL_RECTANGLE_PAINT) {
- if (!mouse_down) {
- return true;
- }
-
- Vector<int> ids = get_selected_tiles();
-
- if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
- _start_undo(TTR("Rectangle Paint"));
- for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
- for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- _set_cell(Point2i(j, i), ids, flip_h, flip_v, transpose);
- }
- }
- _finish_undo();
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- mouse_down = false;
- return true;
- }
-
- mouse_down = false;
- } else if (tool == TOOL_PASTING) {
- Point2 ofs = over_tile - rectangle.position;
- Vector<int> ids;
-
- _start_undo(TTR("Paste"));
- ids.push_back(0);
- for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) {
- ids.write[0] = E->get().cell;
- _set_cell(E->get().pos + ofs, ids, E->get().flip_h, E->get().flip_v, E->get().transpose, E->get().autotile_coord);
- }
- _finish_undo();
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- return true; // We want to keep the Pasting tool.
- } else if (tool == TOOL_SELECTING) {
- CanvasItemEditor::get_singleton()->update_viewport();
-
- } else if (tool == TOOL_BUCKET) {
- Vector<Vector2> points = _bucket_fill(over_tile);
-
- if (points.size() == 0) {
- return false;
- }
-
- _start_undo(TTR("Bucket Fill"));
-
- Dictionary op;
- op["id"] = get_selected_tiles();
- op["flip_h"] = flip_h;
- op["flip_v"] = flip_v;
- op["transpose"] = transpose;
-
- _fill_points(points, op);
-
- _finish_undo();
-
- // So the fill preview is cleared right after the click.
- CanvasItemEditor::get_singleton()->update_viewport();
-
- // We want to keep the bucket-tool active.
- return true;
- }
-
- tool = TOOL_NONE;
- _update_button_tool();
-
- return true;
- }
- }
- } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- if (mb->is_pressed()) {
- if (tool == TOOL_SELECTING || selection_active) {
- tool = TOOL_NONE;
- selection_active = false;
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
-
- if (tool == TOOL_PASTING) {
- tool = TOOL_NONE;
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
-
- if (tool == TOOL_LINE_PAINT) {
- tool = TOOL_LINE_ERASE;
- mouse_down = true;
- rectangle_begin = over_tile;
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
-
- if (tool == TOOL_RECTANGLE_PAINT) {
- tool = TOOL_RECTANGLE_ERASE;
- mouse_down = true;
- rectangle_begin = over_tile;
- copydata.clear();
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
-
- if (tool == TOOL_NONE) {
- paint_undo.clear();
-
- Point2 local = node->world_to_map(xform_inv.xform(mb->get_position()));
-
- _start_undo(TTR("Erase TileMap"));
- tool = TOOL_ERASING;
- _set_cell(local, invalid_cell);
-
- _update_button_tool();
- return true;
- }
-
- } else {
- if (tool == TOOL_LINE_ERASE) {
- if (!mouse_down) {
- return true;
- }
-
- tool = TOOL_LINE_PAINT;
- _update_button_tool();
-
- Vector<int> ids = get_selected_tiles();
-
- if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
- _start_undo(TTR("Line Erase"));
- for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
- _set_cell(E->key(), invalid_cell, flip_h, flip_v, transpose);
- }
- _finish_undo();
- paint_undo.clear();
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- mouse_down = false;
- return true;
- }
-
- mouse_down = false;
- } else if (tool == TOOL_RECTANGLE_ERASE) {
- if (!mouse_down) {
- return true;
- }
-
- tool = TOOL_RECTANGLE_PAINT;
- _update_button_tool();
-
- Vector<int> ids = get_selected_tiles();
-
- if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
- _start_undo(TTR("Rectangle Erase"));
- for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
- for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- _set_cell(Point2i(j, i), invalid_cell, flip_h, flip_v, transpose);
- }
- }
- _finish_undo();
- paint_undo.clear();
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- mouse_down = false;
- return true;
- }
-
- mouse_down = false;
- tool = TOOL_RECTANGLE_PAINT;
- }
-
- if (tool == TOOL_ERASING) {
- tool = TOOL_NONE;
- _update_button_tool();
-
- return true;
- } else if (tool == TOOL_BUCKET) {
- Vector<int> ids;
- ids.push_back(node->get_cell(over_tile.x, over_tile.y));
- Dictionary pop;
- pop["id"] = ids;
- pop["flip_h"] = node->is_cell_x_flipped(over_tile.x, over_tile.y);
- pop["flip_v"] = node->is_cell_y_flipped(over_tile.x, over_tile.y);
- pop["transpose"] = node->is_cell_transposed(over_tile.x, over_tile.y);
-
- Vector<Vector2> points = _bucket_fill(over_tile, true);
-
- if (points.size() == 0) {
- return false;
- }
-
- undo_redo->create_action(TTR("Bucket Fill"));
-
- undo_redo->add_do_method(this, "_erase_points", points);
- undo_redo->add_undo_method(this, "_fill_points", points, pop);
-
- undo_redo->commit_action();
- }
- }
- }
- }
-
- Ref<InputEventMouseMotion> mm = p_event;
-
- if (mm.is_valid()) {
- Point2i new_over_tile = node->world_to_map(xform_inv.xform(mm->get_position()));
- Point2i old_over_tile = over_tile;
-
- if (new_over_tile != over_tile) {
- over_tile = new_over_tile;
- CanvasItemEditor::get_singleton()->update_viewport();
- }
-
- if (refocus_over_tile) {
- // editor lost focus; forget last tile position
- old_over_tile = new_over_tile;
- refocus_over_tile = false;
- }
-
- int tile_under = node->get_cell(over_tile.x, over_tile.y);
- String tile_name = "none";
-
- if (node->get_tileset()->has_tile(tile_under)) {
- tile_name = node->get_tileset()->tile_get_name(tile_under);
- }
- tile_info->show();
- tile_info->set_text(String::num(over_tile.x) + ", " + String::num(over_tile.y) + " [" + tile_name + "]");
-
- if (tool == TOOL_PAINTING) {
- // Paint using bresenham line to prevent holes in painting if the user moves fast.
-
- Vector<Point2i> points = line(old_over_tile.x, over_tile.x, old_over_tile.y, over_tile.y);
- Vector<int> ids = get_selected_tiles();
-
- for (int i = 0; i < points.size(); ++i) {
- Point2i pos = points[i];
-
- if (!paint_undo.has(pos)) {
- paint_undo[pos] = _get_op_from_cell(pos);
- }
-
- _set_cell(pos, ids, flip_h, flip_v, transpose);
- }
-
- return true;
- }
-
- if (tool == TOOL_ERASING) {
- // Erase using bresenham line to prevent holes in painting if the user moves fast.
-
- Vector<Point2i> points = line(old_over_tile.x, over_tile.x, old_over_tile.y, over_tile.y);
-
- for (int i = 0; i < points.size(); ++i) {
- Point2i pos = points[i];
-
- _set_cell(pos, invalid_cell);
- }
-
- return true;
- }
-
- if (tool == TOOL_SELECTING) {
- _select(rectangle_begin, over_tile);
-
- return true;
- }
-
- if (tool == TOOL_LINE_PAINT || tool == TOOL_LINE_ERASE) {
- Vector<int> ids = get_selected_tiles();
- Vector<int> tmp_cell;
- bool erasing = (tool == TOOL_LINE_ERASE);
-
- if (!mouse_down) {
- return true;
- }
-
- tmp_cell.push_back(0);
- if (erasing && paint_undo.size()) {
- for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
- tmp_cell.write[0] = E->get().idx;
- _set_cell(E->key(), tmp_cell, E->get().xf, E->get().yf, E->get().tr);
- }
- }
-
- paint_undo.clear();
-
- if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
- Vector<Point2i> points = line(rectangle_begin.x, over_tile.x, rectangle_begin.y, over_tile.y);
-
- for (int i = 0; i < points.size(); i++) {
- paint_undo[points[i]] = _get_op_from_cell(points[i]);
-
- if (erasing) {
- _set_cell(points[i], invalid_cell);
- }
- }
-
- CanvasItemEditor::get_singleton()->update_viewport();
- }
-
- return true;
- }
- if (tool == TOOL_RECTANGLE_PAINT || tool == TOOL_RECTANGLE_ERASE) {
- Vector<int> tmp_cell;
- tmp_cell.push_back(0);
-
- Point2i end_tile = over_tile;
-
- if (!mouse_down) {
- return true;
- }
-
- if (mm->get_shift()) {
- int size = fmax(ABS(end_tile.x - rectangle_begin.x), ABS(end_tile.y - rectangle_begin.y));
- int xDirection = MAX(MIN(end_tile.x - rectangle_begin.x, 1), -1);
- int yDirection = MAX(MIN(end_tile.y - rectangle_begin.y, 1), -1);
- end_tile = rectangle_begin + Point2i(xDirection * size, yDirection * size);
- }
-
- _select(rectangle_begin, end_tile);
-
- if (tool == TOOL_RECTANGLE_ERASE) {
- if (paint_undo.size()) {
- for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
- tmp_cell.write[0] = E->get().idx;
- _set_cell(E->key(), tmp_cell, E->get().xf, E->get().yf, E->get().tr);
- }
- }
-
- paint_undo.clear();
-
- for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
- for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- Point2i tile = Point2i(j, i);
- paint_undo[tile] = _get_op_from_cell(tile);
-
- _set_cell(tile, invalid_cell);
- }
- }
- }
-
- return true;
- }
- if (tool == TOOL_PICKING && Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) {
- _pick_tile(over_tile);
-
- return true;
- }
- }
-
- Ref<InputEventKey> k = p_event;
-
- if (k.is_valid() && k->is_pressed()) {
- if (last_tool == TOOL_NONE && tool == TOOL_PICKING && k->get_keycode() == KEY_SHIFT && k->get_command()) {
- // trying to draw a rectangle with the painting tool, so change to the correct tool
- tool = last_tool;
-
- CanvasItemEditor::get_singleton()->update_viewport();
- _update_button_tool();
- }
-
- if (k->get_keycode() == KEY_ESCAPE) {
- if (tool == TOOL_PASTING) {
- copydata.clear();
- } else if (tool == TOOL_SELECTING || selection_active) {
- selection_active = false;
- }
-
- tool = TOOL_NONE;
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
-
- if (!mouse_over) {
- // Editor shortcuts should not fire if mouse not in viewport.
- return false;
- }
-
- if (ED_IS_SHORTCUT("tile_map_editor/paint_tile", p_event)) {
- // NOTE: We do not set tool = TOOL_PAINTING as this begins painting
- // immediately without pressing the left mouse button first.
- tool = TOOL_NONE;
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/line_fill", p_event)) {
- tool = TOOL_LINE_PAINT;
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/rectangle_fill", p_event)) {
- tool = TOOL_RECTANGLE_PAINT;
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/bucket_fill", p_event)) {
- tool = TOOL_BUCKET;
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/erase_selection", p_event)) {
- _menu_option(OPTION_ERASE_SELECTION);
-
- _update_button_tool();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/select", p_event)) {
- tool = TOOL_SELECTING;
- selection_active = false;
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/copy_selection", p_event)) {
- _update_copydata();
-
- if (selection_active) {
- tool = TOOL_PASTING;
-
- CanvasItemEditor::get_singleton()->update_viewport();
-
- _update_button_tool();
- return true;
- }
- }
- if (ED_IS_SHORTCUT("tile_map_editor/cut_selection", p_event)) {
- if (selection_active) {
- _update_copydata();
-
- _start_undo(TTR("Cut Selection"));
- _erase_selection();
- _finish_undo();
-
- selection_active = false;
-
- tool = TOOL_PASTING;
-
- CanvasItemEditor::get_singleton()->update_viewport();
- _update_button_tool();
- return true;
- }
- }
- if (ED_IS_SHORTCUT("tile_map_editor/find_tile", p_event)) {
- search_box->select_all();
- search_box->grab_focus();
-
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/rotate_left", p_event)) {
- _rotate(-1);
- CanvasItemEditor::get_singleton()->update_viewport();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/rotate_right", p_event)) {
- _rotate(1);
- CanvasItemEditor::get_singleton()->update_viewport();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/flip_horizontal", p_event)) {
- _flip_horizontal();
- CanvasItemEditor::get_singleton()->update_viewport();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/flip_vertical", p_event)) {
- _flip_vertical();
- CanvasItemEditor::get_singleton()->update_viewport();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/clear_transform", p_event)) {
- _clear_transform();
- CanvasItemEditor::get_singleton()->update_viewport();
- return true;
- }
- if (ED_IS_SHORTCUT("tile_map_editor/transpose", p_event)) {
- transpose = !transpose;
- _update_palette();
- CanvasItemEditor::get_singleton()->update_viewport();
- return true;
- }
- } else if (k.is_valid()) { // Release event.
-
- if (tool == TOOL_NONE) {
- if (k->get_keycode() == KEY_SHIFT && k->get_command()) {
- tool = TOOL_PICKING;
- _update_button_tool();
- }
- } else if (tool == TOOL_PICKING) {
-#ifdef APPLE_STYLE_KEYS
- if (k->get_keycode() == KEY_META) {
-#else
- if (k->get_keycode() == KEY_CONTROL) {
-#endif
- // Go back to that last tool if KEY_CONTROL was released.
- tool = last_tool;
-
- CanvasItemEditor::get_singleton()->update_viewport();
- _update_button_tool();
- }
- }
- }
- return false;
-}
-
-void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
- if (!node || CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) {
- return;
- }
-
- Transform2D cell_xf = node->get_cell_transform();
- Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
- Transform2D xform_inv = xform.affine_inverse();
-
- Size2 screen_size = p_overlay->get_size();
- {
- Rect2 aabb;
- aabb.position = node->world_to_map(xform_inv.xform(Vector2()));
- aabb.expand_to(node->world_to_map(xform_inv.xform(Vector2(0, screen_size.height))));
- aabb.expand_to(node->world_to_map(xform_inv.xform(Vector2(screen_size.width, 0))));
- aabb.expand_to(node->world_to_map(xform_inv.xform(screen_size)));
- Rect2i si = aabb.grow(1.0);
-
- if (node->get_half_offset() != TileMap::HALF_OFFSET_X && node->get_half_offset() != TileMap::HALF_OFFSET_NEGATIVE_X) {
- int max_lines = 2000; //avoid crash if size too small
-
- for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) {
- Vector2 from = xform.xform(node->map_to_world(Vector2(i, si.position.y)));
- Vector2 to = xform.xform(node->map_to_world(Vector2(i, si.position.y + si.size.y + 1)));
-
- Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2);
- p_overlay->draw_line(from, to, col, 1);
- if (max_lines-- == 0) {
- break;
- }
- }
- } else {
- int max_lines = 10000; //avoid crash if size too small
-
- for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) {
- for (int j = (si.position.y) - 1; j <= (si.position.y + si.size.y); j++) {
- Vector2 ofs;
- if (ABS(j) & 1) {
- ofs = cell_xf[0] * (node->get_half_offset() == TileMap::HALF_OFFSET_X ? 0.5 : -0.5);
- }
-
- Vector2 from = xform.xform(node->map_to_world(Vector2(i, j), true) + ofs);
- Vector2 to = xform.xform(node->map_to_world(Vector2(i, j + 1), true) + ofs);
-
- Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2);
- p_overlay->draw_line(from, to, col, 1);
-
- if (--max_lines == 0) {
- break;
- }
- }
- if (max_lines == 0) {
- break;
- }
- }
- }
-
- int max_lines = 10000; //avoid crash if size too small
-
- if (node->get_half_offset() != TileMap::HALF_OFFSET_Y && node->get_half_offset() != TileMap::HALF_OFFSET_NEGATIVE_Y) {
- for (int i = (si.position.y) - 1; i <= (si.position.y + si.size.y); i++) {
- Vector2 from = xform.xform(node->map_to_world(Vector2(si.position.x, i)));
- Vector2 to = xform.xform(node->map_to_world(Vector2(si.position.x + si.size.x + 1, i)));
-
- Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2);
- p_overlay->draw_line(from, to, col, 1);
-
- if (max_lines-- == 0) {
- break;
- }
- }
- } else {
- for (int i = (si.position.y) - 1; i <= (si.position.y + si.size.y); i++) {
- for (int j = (si.position.x) - 1; j <= (si.position.x + si.size.x); j++) {
- Vector2 ofs;
- if (ABS(j) & 1) {
- ofs = cell_xf[1] * (node->get_half_offset() == TileMap::HALF_OFFSET_Y ? 0.5 : -0.5);
- }
-
- Vector2 from = xform.xform(node->map_to_world(Vector2(j, i), true) + ofs);
- Vector2 to = xform.xform(node->map_to_world(Vector2(j + 1, i), true) + ofs);
-
- Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2);
- p_overlay->draw_line(from, to, col, 1);
-
- if (--max_lines == 0) {
- break;
- }
- }
- if (max_lines == 0) {
- break;
- }
- }
- }
- }
-
- if (selection_active) {
- Vector<Vector2> points;
- points.push_back(xform.xform(node->map_to_world((rectangle.position))));
- points.push_back(xform.xform(node->map_to_world((rectangle.position + Point2(rectangle.size.x + 1, 0)))));
- points.push_back(xform.xform(node->map_to_world((rectangle.position + Point2(rectangle.size.x + 1, rectangle.size.y + 1)))));
- points.push_back(xform.xform(node->map_to_world((rectangle.position + Point2(0, rectangle.size.y + 1)))));
-
- p_overlay->draw_colored_polygon(points, Color(0.2, 0.8, 1, 0.4));
- }
-
- if (mouse_over && node->get_tileset().is_valid()) {
- Vector2 endpoints[4] = {
- node->map_to_world(over_tile, true),
- node->map_to_world((over_tile + Point2(1, 0)), true),
- node->map_to_world((over_tile + Point2(1, 1)), true),
- node->map_to_world((over_tile + Point2(0, 1)), true)
- };
-
- for (int i = 0; i < 4; i++) {
- if (node->get_half_offset() == TileMap::HALF_OFFSET_X && ABS(over_tile.y) & 1) {
- endpoints[i] += cell_xf[0] * 0.5;
- }
- if (node->get_half_offset() == TileMap::HALF_OFFSET_NEGATIVE_X && ABS(over_tile.y) & 1) {
- endpoints[i] += cell_xf[0] * -0.5;
- }
- if (node->get_half_offset() == TileMap::HALF_OFFSET_Y && ABS(over_tile.x) & 1) {
- endpoints[i] += cell_xf[1] * 0.5;
- }
- if (node->get_half_offset() == TileMap::HALF_OFFSET_NEGATIVE_Y && ABS(over_tile.x) & 1) {
- endpoints[i] += cell_xf[1] * -0.5;
- }
- endpoints[i] = xform.xform(endpoints[i]);
- }
- Color col;
- if (node->get_cell(over_tile.x, over_tile.y) != TileMap::INVALID_CELL) {
- col = Color(0.2, 0.8, 1.0, 0.8);
- } else {
- col = Color(1.0, 0.4, 0.2, 0.8);
- }
-
- for (int i = 0; i < 4; i++) {
- p_overlay->draw_line(endpoints[i], endpoints[(i + 1) % 4], col, 2);
- }
-
- bool bucket_preview = EditorSettings::get_singleton()->get("editors/tile_map/bucket_fill_preview");
- if (tool == TOOL_SELECTING || tool == TOOL_PICKING || !bucket_preview) {
- return;
- }
-
- if (tool == TOOL_LINE_PAINT) {
- if (!mouse_down) {
- return;
- }
-
- if (paint_undo.is_empty()) {
- return;
- }
-
- Vector<int> ids = get_selected_tiles();
-
- if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL) {
- return;
- }
-
- for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
- _draw_cell(p_overlay, ids[0], E->key(), flip_h, flip_v, transpose, autotile_coord, xform);
- }
-
- } else if (tool == TOOL_RECTANGLE_PAINT) {
- if (!mouse_down) {
- return;
- }
-
- Vector<int> ids = get_selected_tiles();
-
- if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL) {
- return;
- }
-
- for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
- for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
- _draw_cell(p_overlay, ids[0], Point2i(j, i), flip_h, flip_v, transpose, autotile_coord, xform);
- }
- }
- } else if (tool == TOOL_PASTING) {
- if (copydata.is_empty()) {
- return;
- }
-
- Ref<TileSet> ts = node->get_tileset();
-
- if (ts.is_null()) {
- return;
- }
-
- Point2 ofs = over_tile - rectangle.position;
-
- for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) {
- if (!ts->has_tile(E->get().cell)) {
- continue;
- }
-
- TileData tcd = E->get();
-
- _draw_cell(p_overlay, tcd.cell, tcd.pos + ofs, tcd.flip_h, tcd.flip_v, tcd.transpose, tcd.autotile_coord, xform);
- }
-
- Rect2i duplicate = rectangle;
- duplicate.position = over_tile;
-
- Vector<Vector2> points;
- points.push_back(xform.xform(node->map_to_world(duplicate.position)));
- points.push_back(xform.xform(node->map_to_world((duplicate.position + Point2(duplicate.size.x + 1, 0)))));
- points.push_back(xform.xform(node->map_to_world((duplicate.position + Point2(duplicate.size.x + 1, duplicate.size.y + 1)))));
- points.push_back(xform.xform(node->map_to_world((duplicate.position + Point2(0, duplicate.size.y + 1)))));
-
- p_overlay->draw_colored_polygon(points, Color(0.2, 1.0, 0.8, 0.2));
-
- } else if (tool == TOOL_BUCKET) {
- Vector<int> tiles = get_selected_tiles();
- _draw_fill_preview(p_overlay, tiles[0], over_tile, flip_h, flip_v, transpose, autotile_coord, xform);
-
- } else {
- Vector<int> st = get_selected_tiles();
-
- if (st.size() == 1 && st[0] == TileMap::INVALID_CELL) {
- return;
- }
-
- _draw_cell(p_overlay, st[0], over_tile, flip_h, flip_v, transpose, autotile_coord, xform);
- }
- }
-}
-
-void TileMapEditor::edit(Node *p_tile_map) {
- search_box->set_text("");
-
- if (!canvas_item_editor_viewport) {
- canvas_item_editor_viewport = CanvasItemEditor::get_singleton()->get_viewport_control();
- }
-
- if (node) {
- Callable callable_tileset_settings_changed = callable_mp(this, &TileMapEditor::_tileset_settings_changed);
-
- if (node->is_connected("settings_changed", callable_tileset_settings_changed)) {
- node->disconnect("settings_changed", callable_tileset_settings_changed);
- }
- }
- if (p_tile_map) {
- node = Object::cast_to<TileMap>(p_tile_map);
- if (!canvas_item_editor_viewport->is_connected("mouse_entered", callable_mp(this, &TileMapEditor::_canvas_mouse_enter))) {
- canvas_item_editor_viewport->connect("mouse_entered", callable_mp(this, &TileMapEditor::_canvas_mouse_enter));
- }
- if (!canvas_item_editor_viewport->is_connected("mouse_exited", callable_mp(this, &TileMapEditor::_canvas_mouse_exit))) {
- canvas_item_editor_viewport->connect("mouse_exited", callable_mp(this, &TileMapEditor::_canvas_mouse_exit));
- }
-
- _update_palette();
-
- } else {
- 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));
- }
- if (canvas_item_editor_viewport->is_connected("mouse_exited", callable_mp(this, &TileMapEditor::_canvas_mouse_exit))) {
- canvas_item_editor_viewport->disconnect("mouse_exited", callable_mp(this, &TileMapEditor::_canvas_mouse_exit));
- }
-
- _update_palette();
- }
-
- if (node) {
- Callable callable_tileset_settings_changed = callable_mp(this, &TileMapEditor::_tileset_settings_changed);
-
- if (!node->is_connected("settings_changed", callable_tileset_settings_changed)) {
- node->connect("settings_changed", callable_tileset_settings_changed);
- }
- }
-
- _clear_bucket_cache();
-}
-
-void TileMapEditor::_tileset_settings_changed() {
- _update_palette();
- CanvasItemEditor::get_singleton()->update_viewport();
-}
-
-void TileMapEditor::_icon_size_changed(float p_value) {
- if (node) {
- palette->set_icon_scale(p_value);
- manual_palette->set_icon_scale(p_value);
- _update_palette();
- }
-}
-
-void TileMapEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_fill_points"), &TileMapEditor::_fill_points);
- ClassDB::bind_method(D_METHOD("_erase_points"), &TileMapEditor::_erase_points);
-}
-
-TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i &p_pos) {
- CellOp op;
- op.idx = node->get_cell(p_pos.x, p_pos.y);
- if (op.idx != TileMap::INVALID_CELL) {
- if (node->is_cell_x_flipped(p_pos.x, p_pos.y)) {
- op.xf = true;
- }
- if (node->is_cell_y_flipped(p_pos.x, p_pos.y)) {
- op.yf = true;
- }
- if (node->is_cell_transposed(p_pos.x, p_pos.y)) {
- op.tr = true;
- }
- op.ac = node->get_cell_autotile_coord(p_pos.x, p_pos.y);
- }
- return op;
-}
-
-void TileMapEditor::_rotate(int steps) {
- const bool normal_rotation_matrix[][3] = {
- { false, false, false },
- { true, true, false },
- { false, true, true },
- { true, false, true }
- };
-
- const bool mirrored_rotation_matrix[][3] = {
- { false, true, false },
- { true, true, true },
- { false, false, true },
- { true, false, false }
- };
-
- if (transpose ^ flip_h ^ flip_v) {
- // Odd number of flags activated = mirrored rotation
- for (int i = 0; i < 4; i++) {
- if (transpose == mirrored_rotation_matrix[i][0] &&
- flip_h == mirrored_rotation_matrix[i][1] &&
- flip_v == mirrored_rotation_matrix[i][2]) {
- int new_id = Math::wrapi(i + steps, 0, 4);
- transpose = mirrored_rotation_matrix[new_id][0];
- flip_h = mirrored_rotation_matrix[new_id][1];
- flip_v = mirrored_rotation_matrix[new_id][2];
- break;
- }
- }
- } else {
- // Even number of flags activated = normal rotation
- for (int i = 0; i < 4; i++) {
- if (transpose == normal_rotation_matrix[i][0] &&
- flip_h == normal_rotation_matrix[i][1] &&
- flip_v == normal_rotation_matrix[i][2]) {
- int new_id = Math::wrapi(i + steps, 0, 4);
- transpose = normal_rotation_matrix[new_id][0];
- flip_h = normal_rotation_matrix[new_id][1];
- flip_v = normal_rotation_matrix[new_id][2];
- break;
- }
- }
- }
-
- _update_palette();
-}
-
-void TileMapEditor::_flip_horizontal() {
- flip_h = !flip_h;
- _update_palette();
-}
-
-void TileMapEditor::_flip_vertical() {
- flip_v = !flip_v;
- _update_palette();
-}
-
-void TileMapEditor::_clear_transform() {
- transpose = false;
- flip_h = false;
- flip_v = false;
- _update_palette();
-}
-
-TileMapEditor::TileMapEditor(EditorNode *p_editor) {
- node = nullptr;
- manual_autotile = false;
- priority_atlastile = false;
- manual_position = Vector2(0, 0);
- canvas_item_editor_viewport = nullptr;
- editor = p_editor;
- undo_redo = EditorNode::get_undo_redo();
-
- tool = TOOL_NONE;
- selection_active = false;
- mouse_over = false;
- mouse_down = false;
-
- flip_h = false;
- flip_v = false;
- transpose = false;
-
- bucket_cache_tile = -1;
- bucket_cache_visited = nullptr;
-
- invalid_cell.resize(1);
- invalid_cell.write[0] = TileMap::INVALID_CELL;
-
- ED_SHORTCUT("tile_map_editor/erase_selection", TTR("Erase Selection"), KEY_DELETE);
- ED_SHORTCUT("tile_map_editor/find_tile", TTR("Find Tile"), KEY_MASK_CMD + KEY_F);
- ED_SHORTCUT("tile_map_editor/transpose", TTR("Transpose"), KEY_T);
-
- HBoxContainer *tool_hb = memnew(HBoxContainer);
- add_child(tool_hb);
-
- manual_button = memnew(CheckBox);
- manual_button->set_text(TTR("Disable Autotile"));
- manual_button->connect("toggled", callable_mp(this, &TileMapEditor::_manual_toggled));
- add_child(manual_button);
-
- priority_button = memnew(CheckBox);
- priority_button->set_text(TTR("Enable Priority"));
- priority_button->connect("toggled", callable_mp(this, &TileMapEditor::_priority_toggled));
- add_child(priority_button);
-
- search_box = memnew(LineEdit);
- search_box->set_placeholder(TTR("Filter tiles"));
- search_box->set_h_size_flags(SIZE_EXPAND_FILL);
- search_box->connect("text_entered", callable_mp(this, &TileMapEditor::_text_entered));
- search_box->connect("text_changed", callable_mp(this, &TileMapEditor::_text_changed));
- search_box->connect("gui_input", callable_mp(this, &TileMapEditor::_sbox_input));
- add_child(search_box);
-
- size_slider = memnew(HSlider);
- size_slider->set_h_size_flags(SIZE_EXPAND_FILL);
- size_slider->set_min(0.1f);
- size_slider->set_max(4.0f);
- size_slider->set_step(0.1f);
- size_slider->set_value(1.0f);
- size_slider->connect("value_changed", callable_mp(this, &TileMapEditor::_icon_size_changed));
- add_child(size_slider);
-
- int mw = EDITOR_DEF("editors/tile_map/palette_min_width", 80);
-
- VSplitContainer *palette_container = memnew(VSplitContainer);
- palette_container->set_v_size_flags(SIZE_EXPAND_FILL);
- palette_container->set_custom_minimum_size(Size2(mw, 0));
- add_child(palette_container);
-
- // Add tile palette.
- palette = memnew(ItemList);
- palette->set_h_size_flags(SIZE_EXPAND_FILL);
- palette->set_v_size_flags(SIZE_EXPAND_FILL);
- palette->set_max_columns(0);
- palette->set_icon_mode(ItemList::ICON_MODE_TOP);
- palette->set_max_text_lines(2);
- palette->set_select_mode(ItemList::SELECT_MULTI);
- 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->connect("gui_input", callable_mp(this, &TileMapEditor::_palette_input));
- palette_container->add_child(palette);
-
- // Add message for when no texture is selected.
- info_message = memnew(Label);
- info_message->set_text(TTR("Give a TileSet resource to this TileMap to use its tiles."));
- info_message->set_valign(Label::VALIGN_CENTER);
- info_message->set_align(Label::ALIGN_CENTER);
- info_message->set_autowrap(true);
- info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- info_message->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
- palette->add_child(info_message);
-
- // Add autotile override palette.
- manual_palette = memnew(ItemList);
- manual_palette->set_h_size_flags(SIZE_EXPAND_FILL);
- manual_palette->set_v_size_flags(SIZE_EXPAND_FILL);
- manual_palette->set_max_columns(0);
- manual_palette->set_icon_mode(ItemList::ICON_MODE_TOP);
- manual_palette->set_max_text_lines(2);
- manual_palette->hide();
- palette_container->add_child(manual_palette);
-
- // Add menu items.
- toolbar = memnew(HBoxContainer);
- toolbar->hide();
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(toolbar);
-
- toolbar->add_child(memnew(VSeparator));
-
- // Tools.
- paint_button = memnew(Button);
- paint_button->set_flat(true);
- paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P));
- paint_button->set_shortcut_context(this);
- paint_button->set_tooltip(TTR("RMB: Erase"));
- paint_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_NONE));
- paint_button->set_toggle_mode(true);
- toolbar->add_child(paint_button);
-
- line_button = memnew(Button);
- line_button->set_flat(true);
- line_button->set_shortcut(ED_SHORTCUT("tile_map_editor/line_fill", TTR("Line Fill"), KEY_L));
- line_button->set_shortcut_context(this);
- line_button->set_tooltip(TTR("RMB: Erase"));
- line_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_LINE_PAINT));
- line_button->set_toggle_mode(true);
- toolbar->add_child(line_button);
-
- rectangle_button = memnew(Button);
- rectangle_button->set_flat(true);
- rectangle_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rectangle_fill", TTR("Rectangle Fill"), KEY_O));
- rectangle_button->set_shortcut_context(this);
- rectangle_button->set_tooltip(TTR("Shift+LMB: Keep 1:1 proporsions\nRMB: Erase"));
- rectangle_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_RECTANGLE_PAINT));
- rectangle_button->set_toggle_mode(true);
- toolbar->add_child(rectangle_button);
-
- bucket_fill_button = memnew(Button);
- bucket_fill_button->set_flat(true);
- bucket_fill_button->set_shortcut(ED_SHORTCUT("tile_map_editor/bucket_fill", TTR("Bucket Fill"), KEY_B));
- bucket_fill_button->set_shortcut_context(this);
- bucket_fill_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_BUCKET));
- bucket_fill_button->set_toggle_mode(true);
- toolbar->add_child(bucket_fill_button);
-
- picker_button = memnew(Button);
- picker_button->set_flat(true);
- picker_button->set_shortcut(ED_SHORTCUT("tile_map_editor/pick_tile", TTR("Pick Tile"), KEY_I));
- picker_button->set_shortcut_context(this);
- picker_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_PICKING));
- picker_button->set_toggle_mode(true);
- toolbar->add_child(picker_button);
-
- select_button = memnew(Button);
- select_button->set_flat(true);
- select_button->set_shortcut(ED_SHORTCUT("tile_map_editor/select", TTR("Select"), KEY_M));
- select_button->set_shortcut_context(this);
- select_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_SELECTING));
- select_button->set_toggle_mode(true);
- toolbar->add_child(select_button);
-
- _update_button_tool();
-
- // Container to the right of the toolbar.
- toolbar_right = memnew(HBoxContainer);
- toolbar_right->hide();
- toolbar_right->set_h_size_flags(SIZE_EXPAND_FILL);
- toolbar_right->set_alignment(BoxContainer::ALIGN_END);
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(toolbar_right);
-
- // Tile position.
- 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_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts"));
- tile_info->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size("main_size", "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);
-
- // Menu.
- options = memnew(MenuButton);
- options->set_shortcut_context(this);
- options->set_text("TileMap");
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("TileMap", "EditorIcons"));
- toolbar_right->add_child(options);
-
- PopupMenu *p = options->get_popup();
- p->add_shortcut(ED_SHORTCUT("tile_map_editor/cut_selection", TTR("Cut Selection"), KEY_MASK_CMD + KEY_X), OPTION_CUT);
- p->add_shortcut(ED_SHORTCUT("tile_map_editor/copy_selection", TTR("Copy Selection"), KEY_MASK_CMD + KEY_C), OPTION_COPY);
- p->add_shortcut(ED_GET_SHORTCUT("tile_map_editor/erase_selection"), OPTION_ERASE_SELECTION);
- p->add_separator();
- p->add_item(TTR("Fix Invalid Tiles"), OPTION_FIX_INVALID);
- p->connect("id_pressed", callable_mp(this, &TileMapEditor::_menu_option));
-
- rotate_left_button = memnew(Button);
- rotate_left_button->set_flat(true);
- rotate_left_button->set_tooltip(TTR("Rotate Left"));
- rotate_left_button->set_focus_mode(FOCUS_NONE);
- rotate_left_button->connect("pressed", callable_mp(this, &TileMapEditor::_rotate), varray(-1));
- rotate_left_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rotate_left", TTR("Rotate Left"), KEY_A));
- rotate_left_button->set_shortcut_context(this);
- tool_hb->add_child(rotate_left_button);
-
- rotate_right_button = memnew(Button);
- rotate_right_button->set_flat(true);
- rotate_right_button->set_tooltip(TTR("Rotate Right"));
- rotate_right_button->set_focus_mode(FOCUS_NONE);
- rotate_right_button->connect("pressed", callable_mp(this, &TileMapEditor::_rotate), varray(1));
- rotate_right_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rotate_right", TTR("Rotate Right"), KEY_S));
- rotate_right_button->set_shortcut_context(this);
- tool_hb->add_child(rotate_right_button);
-
- flip_horizontal_button = memnew(Button);
- flip_horizontal_button->set_flat(true);
- flip_horizontal_button->set_tooltip(TTR("Flip Horizontally"));
- flip_horizontal_button->set_focus_mode(FOCUS_NONE);
- flip_horizontal_button->connect("pressed", callable_mp(this, &TileMapEditor::_flip_horizontal));
- flip_horizontal_button->set_shortcut(ED_SHORTCUT("tile_map_editor/flip_horizontal", TTR("Flip Horizontally"), KEY_X));
- flip_horizontal_button->set_shortcut_context(this);
- tool_hb->add_child(flip_horizontal_button);
-
- flip_vertical_button = memnew(Button);
- flip_vertical_button->set_flat(true);
- flip_vertical_button->set_tooltip(TTR("Flip Vertically"));
- flip_vertical_button->set_focus_mode(FOCUS_NONE);
- flip_vertical_button->connect("pressed", callable_mp(this, &TileMapEditor::_flip_vertical));
- flip_vertical_button->set_shortcut(ED_SHORTCUT("tile_map_editor/flip_vertical", TTR("Flip Vertically"), KEY_Z));
- flip_vertical_button->set_shortcut_context(this);
- tool_hb->add_child(flip_vertical_button);
-
- clear_transform_button = memnew(Button);
- clear_transform_button->set_flat(true);
- clear_transform_button->set_tooltip(TTR("Clear Transform"));
- clear_transform_button->set_focus_mode(FOCUS_NONE);
- clear_transform_button->connect("pressed", callable_mp(this, &TileMapEditor::_clear_transform));
- clear_transform_button->set_shortcut(ED_SHORTCUT("tile_map_editor/clear_transform", TTR("Clear Transform"), KEY_W));
- clear_transform_button->set_shortcut_context(this);
- tool_hb->add_child(clear_transform_button);
-
- clear_transform_button->set_disabled(true);
-}
-
-TileMapEditor::~TileMapEditor() {
- _clear_bucket_cache();
- copydata.clear();
-}
-
-///////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////
-
-void TileMapEditorPlugin::_notification(int p_what) {
- if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
- switch ((int)EditorSettings::get_singleton()->get("editors/tile_map/editor_side")) {
- case 0: { // Left.
- CanvasItemEditor::get_singleton()->get_palette_split()->move_child(tile_map_editor, 0);
- } break;
- case 1: { // Right.
- CanvasItemEditor::get_singleton()->get_palette_split()->move_child(tile_map_editor, 1);
- } break;
- }
- }
-}
-
-void TileMapEditorPlugin::edit(Object *p_object) {
- tile_map_editor->edit(Object::cast_to<Node>(p_object));
-}
-
-bool TileMapEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("TileMap");
-}
-
-void TileMapEditorPlugin::make_visible(bool p_visible) {
- if (p_visible) {
- tile_map_editor->show();
- tile_map_editor->get_toolbar()->show();
- tile_map_editor->get_toolbar_right()->show();
- // `tile_info` isn't shown here, as it's displayed after a tile has been hovered.
- // Otherwise, a translucent black rectangle would be visible as there would be an
- // empty Label in the CanvasItemEditor's info overlay.
-
- // Change to TOOL_SELECT when TileMap node is selected, to prevent accidental movement.
- CanvasItemEditor::get_singleton()->set_current_tool(CanvasItemEditor::TOOL_SELECT);
- } else {
- tile_map_editor->hide();
- tile_map_editor->get_toolbar()->hide();
- tile_map_editor->get_toolbar_right()->hide();
- tile_map_editor->get_tile_info()->hide();
- tile_map_editor->edit(nullptr);
- }
-}
-
-TileMapEditorPlugin::TileMapEditorPlugin(EditorNode *p_node) {
- EDITOR_DEF("editors/tile_map/preview_size", 64);
- EDITOR_DEF("editors/tile_map/palette_item_hseparation", 8);
- EDITOR_DEF("editors/tile_map/show_tile_names", true);
- EDITOR_DEF("editors/tile_map/show_tile_ids", false);
- EDITOR_DEF("editors/tile_map/sort_tiles_by_name", true);
- EDITOR_DEF("editors/tile_map/bucket_fill_preview", true);
- EDITOR_DEF("editors/tile_map/editor_side", 1);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/tile_map/editor_side", PROPERTY_HINT_ENUM, "Left,Right"));
-
- tile_map_editor = memnew(TileMapEditor(p_node));
- switch ((int)EditorSettings::get_singleton()->get("editors/tile_map/editor_side")) {
- case 0: { // Left.
- add_control_to_container(CONTAINER_CANVAS_EDITOR_SIDE_LEFT, tile_map_editor);
- } break;
- case 1: { // Right.
- add_control_to_container(CONTAINER_CANVAS_EDITOR_SIDE_RIGHT, tile_map_editor);
- } break;
- }
- tile_map_editor->hide();
-}
-
-TileMapEditorPlugin::~TileMapEditorPlugin() {
-}
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
deleted file mode 100644
index 421a3b3f68..0000000000
--- a/editor/plugins/tile_map_editor_plugin.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/*************************************************************************/
-/* tile_map_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef TILE_MAP_EDITOR_PLUGIN_H
-#define TILE_MAP_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-#include "scene/2d/tile_map.h"
-#include "scene/gui/check_box.h"
-#include "scene/gui/label.h"
-#include "scene/gui/line_edit.h"
-#include "scene/gui/menu_button.h"
-
-class TileMapEditor : public VBoxContainer {
- GDCLASS(TileMapEditor, VBoxContainer);
-
- enum Tool {
- TOOL_NONE,
- TOOL_PAINTING,
- TOOL_ERASING,
- TOOL_RECTANGLE_PAINT,
- TOOL_RECTANGLE_ERASE,
- TOOL_LINE_PAINT,
- TOOL_LINE_ERASE,
- TOOL_SELECTING,
- TOOL_BUCKET,
- TOOL_PICKING,
- TOOL_PASTING
- };
-
- enum Options {
- OPTION_COPY,
- OPTION_ERASE_SELECTION,
- OPTION_FIX_INVALID,
- OPTION_CUT
- };
-
- TileMap *node;
- bool manual_autotile;
- bool priority_atlastile;
- Vector2 manual_position;
-
- EditorNode *editor;
- UndoRedo *undo_redo;
- Control *canvas_item_editor_viewport;
-
- LineEdit *search_box;
- HSlider *size_slider;
- ItemList *palette;
- ItemList *manual_palette;
-
- Label *info_message;
-
- HBoxContainer *toolbar;
- HBoxContainer *toolbar_right;
-
- Label *tile_info;
- MenuButton *options;
-
- Button *paint_button;
- Button *line_button;
- Button *rectangle_button;
- Button *bucket_fill_button;
- Button *picker_button;
- Button *select_button;
-
- Button *flip_horizontal_button;
- Button *flip_vertical_button;
- Button *rotate_left_button;
- Button *rotate_right_button;
- Button *clear_transform_button;
-
- CheckBox *manual_button;
- CheckBox *priority_button;
-
- Tool tool;
- Tool last_tool;
-
- bool selection_active;
- bool mouse_over;
- bool mouse_down;
-
- bool flip_h;
- bool flip_v;
- bool transpose;
- Point2i autotile_coord;
-
- Point2i rectangle_begin;
- Rect2i rectangle;
-
- Point2i over_tile;
- bool refocus_over_tile = false;
-
- bool *bucket_cache_visited;
- Rect2i bucket_cache_rect;
- int bucket_cache_tile;
- Vector<Vector2> bucket_cache;
- List<Point2i> bucket_queue;
-
- struct CellOp {
- int idx = TileMap::INVALID_CELL;
- bool xf = false;
- bool yf = false;
- bool tr = false;
- Vector2 ac;
- };
-
- Map<Point2i, CellOp> paint_undo;
-
- struct TileData {
- Point2i pos;
- int cell = TileMap::INVALID_CELL;
- bool flip_h = false;
- bool flip_v = false;
- bool transpose = false;
- Point2i autotile_coord;
- };
-
- List<TileData> copydata;
-
- Map<Point2i, CellOp> undo_data;
- Vector<int> invalid_cell;
-
- void _pick_tile(const Point2 &p_pos);
-
- Vector<Vector2> _bucket_fill(const Point2i &p_start, bool erase = false, bool preview = false);
-
- void _fill_points(const Vector<Vector2> &p_points, const Dictionary &p_op);
- void _erase_points(const Vector<Vector2> &p_points);
-
- void _select(const Point2i &p_from, const Point2i &p_to);
- void _erase_selection();
-
- void _draw_cell(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord, const Transform2D &p_xform);
- void _draw_fill_preview(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord, const Transform2D &p_xform);
- void _clear_bucket_cache();
-
- void _update_copydata();
-
- Vector<int> get_selected_tiles() const;
- void set_selected_tiles(Vector<int> p_tile);
-
- void _manual_toggled(bool p_enabled);
- void _priority_toggled(bool p_enabled);
- void _text_entered(const String &p_text);
- void _text_changed(const String &p_text);
- void _sbox_input(const Ref<InputEvent> &p_ie);
- void _update_palette();
- void _update_button_tool();
- void _button_tool_select(int p_tool);
- void _menu_option(int p_option);
- void _palette_selected(int index);
- void _palette_multi_selected(int index, bool selected);
- void _palette_input(const Ref<InputEvent> &p_event);
-
- Dictionary _create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord);
- void _start_undo(const String &p_action);
- void _finish_undo();
- void _create_set_cell_undo_redo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new);
- void _set_cell(const Point2i &p_pos, Vector<int> p_values, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, const Point2i &p_autotile_coord = Point2());
-
- void _canvas_mouse_enter();
- void _canvas_mouse_exit();
- void _tileset_settings_changed();
- void _icon_size_changed(float p_value);
-
- void _clear_transform();
- void _flip_horizontal();
- void _flip_vertical();
- void _rotate(int steps);
-
-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);
-
-public:
- HBoxContainer *get_toolbar() const { return toolbar; }
- HBoxContainer *get_toolbar_right() const { return toolbar_right; }
- Label *get_tile_info() const { return tile_info; }
-
- bool forward_gui_input(const Ref<InputEvent> &p_event);
- void forward_canvas_draw_over_viewport(Control *p_overlay);
-
- void edit(Node *p_tile_map);
-
- TileMapEditor(EditorNode *p_editor);
- ~TileMapEditor();
-};
-
-class TileMapEditorPlugin : public EditorPlugin {
- GDCLASS(TileMapEditorPlugin, EditorPlugin);
-
- TileMapEditor *tile_map_editor;
-
-protected:
- void _notification(int p_what);
-
-public:
- virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return tile_map_editor->forward_gui_input(p_event); }
- virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { tile_map_editor->forward_canvas_draw_over_viewport(p_overlay); }
-
- virtual String get_name() const override { return "TileMap"; }
- bool has_main_screen() const override { return false; }
- virtual void edit(Object *p_object) override;
- virtual bool handles(Object *p_object) const override;
- virtual void make_visible(bool p_visible) override;
-
- TileMapEditorPlugin(EditorNode *p_node);
- ~TileMapEditorPlugin();
-};
-
-#endif // TILE_MAP_EDITOR_PLUGIN_H
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
deleted file mode 100644
index feaf609557..0000000000
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ /dev/null
@@ -1,3680 +0,0 @@
-/*************************************************************************/
-/* tile_set_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "tile_set_editor_plugin.h"
-
-#include "core/input/input.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_2d.h"
-
-void TileSetEditor::edit(const Ref<TileSet> &p_tileset) {
- tileset = p_tileset;
-
- texture_list->clear();
- texture_map.clear();
- update_texture_list();
-}
-
-void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) {
- for (int i = 0; i < p_node->get_child_count(); i++) {
- Node *child = p_node->get_child(i);
-
- if (!Object::cast_to<Sprite2D>(child)) {
- if (child->get_child_count() > 0) {
- _import_node(child, p_library);
- }
-
- continue;
- }
-
- Sprite2D *mi = Object::cast_to<Sprite2D>(child);
- Ref<Texture2D> texture = mi->get_texture();
- Ref<ShaderMaterial> material = mi->get_material();
-
- if (texture.is_null()) {
- continue;
- }
-
- int id = p_library->find_tile_by_name(mi->get_name());
- if (id < 0) {
- id = p_library->get_last_unused_tile_id();
- p_library->create_tile(id);
- p_library->tile_set_name(id, mi->get_name());
- }
-
- p_library->tile_set_texture(id, texture);
- p_library->tile_set_material(id, material);
-
- p_library->tile_set_modulate(id, mi->get_modulate());
-
- Vector2 phys_offset;
- Size2 s;
-
- if (mi->is_region_enabled()) {
- s = mi->get_region_rect().size;
- p_library->tile_set_region(id, mi->get_region_rect());
- } else {
- const int frame = mi->get_frame();
- const int hframes = mi->get_hframes();
- s = texture->get_size() / Size2(hframes, mi->get_vframes());
- p_library->tile_set_region(id, Rect2(Vector2(frame % hframes, frame / hframes) * s, s));
- }
-
- if (mi->is_centered()) {
- phys_offset += -s / 2;
- }
-
- Vector<TileSet::ShapeData> collisions;
- Ref<NavigationPolygon> nav_poly;
- Ref<OccluderPolygon2D> occluder;
- bool found_collisions = false;
-
- for (int j = 0; j < mi->get_child_count(); j++) {
- Node *child2 = mi->get_child(j);
-
- if (Object::cast_to<NavigationRegion2D>(child2)) {
- nav_poly = Object::cast_to<NavigationRegion2D>(child2)->get_navigation_polygon();
- }
-
- if (Object::cast_to<LightOccluder2D>(child2)) {
- occluder = Object::cast_to<LightOccluder2D>(child2)->get_occluder_polygon();
- }
-
- if (!Object::cast_to<StaticBody2D>(child2)) {
- continue;
- }
-
- found_collisions = true;
-
- StaticBody2D *sb = Object::cast_to<StaticBody2D>(child2);
-
- List<uint32_t> shapes;
- sb->get_shape_owners(&shapes);
-
- for (List<uint32_t>::Element *E = shapes.front(); E; E = E->next()) {
- if (sb->is_shape_owner_disabled(E->get())) {
- continue;
- }
-
- Transform2D shape_transform = sb->get_transform() * sb->shape_owner_get_transform(E->get());
- bool one_way = sb->is_shape_owner_one_way_collision_enabled(E->get());
-
- shape_transform[2] -= phys_offset;
-
- for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) {
- Ref<Shape2D> shape = sb->shape_owner_get_shape(E->get(), k);
- TileSet::ShapeData shape_data;
- shape_data.shape = shape;
- shape_data.shape_transform = shape_transform;
- shape_data.one_way_collision = one_way;
- collisions.push_back(shape_data);
- }
- }
- }
-
- if (found_collisions) {
- p_library->tile_set_shapes(id, collisions);
- }
-
- p_library->tile_set_texture_offset(id, mi->get_offset());
- p_library->tile_set_navigation_polygon(id, nav_poly);
- p_library->tile_set_light_occluder(id, occluder);
- p_library->tile_set_occluder_offset(id, -phys_offset);
- p_library->tile_set_navigation_polygon_offset(id, -phys_offset);
- p_library->tile_set_z_index(id, mi->get_z_index());
- }
-}
-
-void TileSetEditor::_import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge) {
- if (!p_merge) {
- p_library->clear();
- }
-
- _import_node(p_scene, p_library);
-}
-
-void TileSetEditor::_undo_redo_import_scene(Node *p_scene, bool p_merge) {
- _import_scene(p_scene, tileset, p_merge);
-}
-
-Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bool p_merge) {
- _import_scene(p_base_scene, ml, p_merge);
- return OK;
-}
-
-Variant TileSetEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
- return false;
-}
-
-bool TileSetEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
- Dictionary d = p_data;
-
- if (!d.has("type")) {
- return false;
- }
-
- if (d.has("from") && (Object *)(d["from"]) == texture_list) {
- return false;
- }
-
- if (String(d["type"]) == "resource" && d.has("resource")) {
- RES r = d["resource"];
-
- Ref<Texture2D> texture = r;
-
- if (texture.is_valid()) {
- return true;
- }
- }
-
- if (String(d["type"]) == "files") {
- Vector<String> files = d["files"];
-
- if (files.size() == 0) {
- return false;
- }
-
- for (int i = 0; i < files.size(); i++) {
- String file = files[i];
- String ftype = EditorFileSystem::get_singleton()->get_file_type(file);
-
- if (!ClassDB::is_parent_class(ftype, "Texture")) {
- return false;
- }
- }
-
- return true;
- }
- return false;
-}
-
-void TileSetEditor::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;
- }
-
- Dictionary d = p_data;
-
- if (!d.has("type")) {
- return;
- }
-
- if (String(d["type"]) == "resource" && d.has("resource")) {
- RES r = d["resource"];
-
- Ref<Texture2D> texture = r;
-
- if (texture.is_valid()) {
- add_texture(texture);
- }
-
- if (texture_list->get_item_count() > 0) {
- update_texture_list_icon();
- texture_list->select(texture_list->get_item_count() - 1);
- _on_texture_list_selected(texture_list->get_item_count() - 1);
- }
- }
-
- if (String(d["type"]) == "files") {
- Vector<String> files = d["files"];
-
- _on_textures_added(files);
- }
-}
-
-void TileSetEditor::_bind_methods() {
- ClassDB::bind_method("_undo_redo_import_scene", &TileSetEditor::_undo_redo_import_scene);
- ClassDB::bind_method("_on_workspace_process", &TileSetEditor::_on_workspace_process); // Still used by some connect_compat.
- ClassDB::bind_method("_set_snap_step", &TileSetEditor::_set_snap_step);
- ClassDB::bind_method("_set_snap_off", &TileSetEditor::_set_snap_off);
- ClassDB::bind_method("_set_snap_sep", &TileSetEditor::_set_snap_sep);
- ClassDB::bind_method("_validate_current_tile_id", &TileSetEditor::_validate_current_tile_id);
- ClassDB::bind_method("_select_edited_shape_coord", &TileSetEditor::_select_edited_shape_coord);
- ClassDB::bind_method("_sort_tiles", &TileSetEditor::_sort_tiles);
-
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &TileSetEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &TileSetEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &TileSetEditor::drop_data_fw);
-
- ClassDB::bind_method("edit", &TileSetEditor::edit);
- ClassDB::bind_method("add_texture", &TileSetEditor::add_texture);
- ClassDB::bind_method("remove_texture", &TileSetEditor::remove_texture);
- ClassDB::bind_method("update_texture_list_icon", &TileSetEditor::update_texture_list_icon);
- ClassDB::bind_method("update_workspace_minsize", &TileSetEditor::update_workspace_minsize);
-}
-
-void TileSetEditor::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_READY: {
- add_theme_constant_override("autohide", 1); // Fixes the dragger always showing up.
- } break;
- case NOTIFICATION_TRANSLATION_CHANGED:
- case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
- case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED: {
- 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"));
- if (is_layout_rtl()) {
- tools[SELECT_PREVIOUS]->set_icon(get_theme_icon("ArrowLeft", "EditorIcons"));
- tools[SELECT_NEXT]->set_icon(get_theme_icon("ArrowRight", "EditorIcons"));
- } else {
- tools[SELECT_PREVIOUS]->set_icon(get_theme_icon("ArrowRight", "EditorIcons"));
- tools[SELECT_NEXT]->set_icon(get_theme_icon("ArrowLeft", "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_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_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
- } break;
- }
-}
-
-TileSetEditor::TileSetEditor(EditorNode *p_editor) {
- editor = p_editor;
- undo_redo = EditorNode::get_undo_redo();
- current_tile = -1;
-
- VBoxContainer *left_container = memnew(VBoxContainer);
- add_child(left_container);
-
- texture_list = memnew(ItemList);
- left_container->add_child(texture_list);
- texture_list->set_v_size_flags(SIZE_EXPAND_FILL);
- texture_list->set_custom_minimum_size(Size2(200, 0));
- texture_list->connect("item_selected", callable_mp(this, &TileSetEditor::_on_texture_list_selected));
- texture_list->set_drag_forwarding(this);
-
- HBoxContainer *tileset_toolbar_container = memnew(HBoxContainer);
- left_container->add_child(tileset_toolbar_container);
-
- tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE] = memnew(Button);
- tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_flat(true);
- tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_button_pressed), varray(TOOL_TILESET_ADD_TEXTURE));
- tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]);
- tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_tooltip(TTR("Add Texture(s) to TileSet."));
-
- tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE] = memnew(Button);
- tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_flat(true);
- tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_button_pressed), varray(TOOL_TILESET_REMOVE_TEXTURE));
- tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]);
- tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_tooltip(TTR("Remove selected Texture from TileSet."));
-
- Control *toolbar_separator = memnew(Control);
- toolbar_separator->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- tileset_toolbar_container->add_child(toolbar_separator);
-
- tileset_toolbar_tools = memnew(MenuButton);
- tileset_toolbar_tools->set_text(TTR("Tools"));
- tileset_toolbar_tools->get_popup()->add_item(TTR("Create from Scene"), TOOL_TILESET_CREATE_SCENE);
- tileset_toolbar_tools->get_popup()->add_item(TTR("Merge from Scene"), TOOL_TILESET_MERGE_SCENE);
-
- tileset_toolbar_tools->get_popup()->connect("id_pressed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_button_pressed));
- tileset_toolbar_container->add_child(tileset_toolbar_tools);
-
- //---------------
- VBoxContainer *right_container = memnew(VBoxContainer);
- right_container->set_v_size_flags(SIZE_EXPAND_FILL);
- add_child(right_container);
-
- dragging_point = -1;
- creating_shape = false;
- snap_step = Vector2(32, 32);
- snap_offset = WORKSPACE_MARGIN;
-
- set_custom_minimum_size(Size2(0, 150));
-
- VBoxContainer *main_vb = memnew(VBoxContainer);
- right_container->add_child(main_vb);
- main_vb->set_v_size_flags(SIZE_EXPAND_FILL);
-
- HBoxContainer *tool_hb = memnew(HBoxContainer);
- Ref<ButtonGroup> g(memnew(ButtonGroup));
-
- String workspace_label[WORKSPACE_MODE_MAX] = {
- TTR("Edit"),
- TTR("New Single Tile"),
- TTR("New Autotile"),
- TTR("New Atlas")
- };
- for (int i = 0; i < (int)WORKSPACE_MODE_MAX; i++) {
- tool_workspacemode[i] = memnew(Button);
- tool_workspacemode[i]->set_text(workspace_label[i]);
- tool_workspacemode[i]->set_toggle_mode(true);
- tool_workspacemode[i]->set_button_group(g);
- tool_workspacemode[i]->connect("pressed", callable_mp(this, &TileSetEditor::_on_workspace_mode_changed), varray(i));
- tool_hb->add_child(tool_workspacemode[i]);
- }
-
- Control *spacer = memnew(Control);
- spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- tool_hb->add_child(spacer);
- tool_hb->move_child(spacer, WORKSPACE_CREATE_SINGLE);
-
- tools[SELECT_NEXT] = memnew(Button);
- tool_hb->add_child(tools[SELECT_NEXT]);
- tool_hb->move_child(tools[SELECT_NEXT], WORKSPACE_CREATE_SINGLE);
- tools[SELECT_NEXT]->set_flat(true);
- tools[SELECT_NEXT]->set_shortcut(ED_SHORTCUT("tileset_editor/next_shape", TTR("Next Coordinate"), KEY_PAGEDOWN));
- tools[SELECT_NEXT]->set_shortcut_context(this);
- tools[SELECT_NEXT]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SELECT_NEXT));
- tools[SELECT_NEXT]->set_tooltip(TTR("Select the next shape, subtile, or Tile."));
- tools[SELECT_PREVIOUS] = memnew(Button);
- tool_hb->add_child(tools[SELECT_PREVIOUS]);
- tool_hb->move_child(tools[SELECT_PREVIOUS], WORKSPACE_CREATE_SINGLE);
- tools[SELECT_PREVIOUS]->set_flat(true);
- tools[SELECT_PREVIOUS]->set_shortcut(ED_SHORTCUT("tileset_editor/previous_shape", TTR("Previous Coordinate"), KEY_PAGEUP));
- tools[SELECT_PREVIOUS]->set_shortcut_context(this);
- tools[SELECT_PREVIOUS]->set_tooltip(TTR("Select the previous shape, subtile, or Tile."));
- tools[SELECT_PREVIOUS]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SELECT_PREVIOUS));
-
- VSeparator *separator_shape_selection = memnew(VSeparator);
- tool_hb->add_child(separator_shape_selection);
- tool_hb->move_child(separator_shape_selection, WORKSPACE_CREATE_SINGLE);
-
- tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true);
- workspace_mode = WORKSPACE_EDIT;
-
- main_vb->add_child(tool_hb);
- main_vb->add_child(memnew(HSeparator));
-
- tool_hb = memnew(HBoxContainer);
-
- g = Ref<ButtonGroup>(memnew(ButtonGroup));
- String label[EDITMODE_MAX] = {
- TTR("Region"),
- TTR("Collision"),
- TTR("Occlusion"),
- TTR("Navigation"),
- TTR("Bitmask"),
- TTR("Priority"),
- TTR("Icon"),
- TTR("Z Index")
- };
- for (int i = 0; i < (int)EDITMODE_MAX; i++) {
- tool_editmode[i] = memnew(Button);
- tool_editmode[i]->set_text(label[i]);
- tool_editmode[i]->set_toggle_mode(true);
- tool_editmode[i]->set_button_group(g);
- tool_editmode[i]->connect("pressed", callable_mp(this, &TileSetEditor::_on_edit_mode_changed), varray(i));
- tool_hb->add_child(tool_editmode[i]);
- }
- tool_editmode[EDITMODE_COLLISION]->set_pressed(true);
- edit_mode = EDITMODE_COLLISION;
-
- tool_editmode[EDITMODE_REGION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_region", TTR("Region Mode"), KEY_1));
- tool_editmode[EDITMODE_COLLISION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_collision", TTR("Collision Mode"), KEY_2));
- tool_editmode[EDITMODE_OCCLUSION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_occlusion", TTR("Occlusion Mode"), KEY_3));
- tool_editmode[EDITMODE_NAVIGATION]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_navigation", TTR("Navigation Mode"), KEY_4));
- tool_editmode[EDITMODE_BITMASK]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_bitmask", TTR("Bitmask Mode"), KEY_5));
- tool_editmode[EDITMODE_PRIORITY]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_priority", TTR("Priority Mode"), KEY_6));
- tool_editmode[EDITMODE_ICON]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_icon", TTR("Icon Mode"), KEY_7));
- tool_editmode[EDITMODE_Z_INDEX]->set_shortcut(ED_SHORTCUT("tileset_editor/editmode_z_index", TTR("Z Index Mode"), KEY_8));
-
- tool_editmode[EDITMODE_REGION]->set_shortcut_context(this);
- tool_editmode[EDITMODE_REGION]->set_shortcut_context(this);
- tool_editmode[EDITMODE_COLLISION]->set_shortcut_context(this);
- tool_editmode[EDITMODE_OCCLUSION]->set_shortcut_context(this);
- tool_editmode[EDITMODE_NAVIGATION]->set_shortcut_context(this);
- tool_editmode[EDITMODE_BITMASK]->set_shortcut_context(this);
- tool_editmode[EDITMODE_PRIORITY]->set_shortcut_context(this);
- tool_editmode[EDITMODE_ICON]->set_shortcut_context(this);
- tool_editmode[EDITMODE_Z_INDEX]->set_shortcut_context(this);
-
- main_vb->add_child(tool_hb);
- separator_editmode = memnew(HSeparator);
- main_vb->add_child(separator_editmode);
-
- toolbar = memnew(HBoxContainer);
- Ref<ButtonGroup> tg(memnew(ButtonGroup));
-
- tools[TOOL_SELECT] = memnew(Button);
- toolbar->add_child(tools[TOOL_SELECT]);
- tools[TOOL_SELECT]->set_flat(true);
- tools[TOOL_SELECT]->set_toggle_mode(true);
- tools[TOOL_SELECT]->set_button_group(tg);
- tools[TOOL_SELECT]->set_pressed(true);
- tools[TOOL_SELECT]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(TOOL_SELECT));
-
- separator_bitmask = memnew(VSeparator);
- toolbar->add_child(separator_bitmask);
- tools[BITMASK_COPY] = memnew(Button);
- tools[BITMASK_COPY]->set_flat(true);
- tools[BITMASK_COPY]->set_tooltip(TTR("Copy bitmask."));
- tools[BITMASK_COPY]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_COPY));
- toolbar->add_child(tools[BITMASK_COPY]);
- tools[BITMASK_PASTE] = memnew(Button);
- tools[BITMASK_PASTE]->set_flat(true);
- tools[BITMASK_PASTE]->set_tooltip(TTR("Paste bitmask."));
- tools[BITMASK_PASTE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_PASTE));
- toolbar->add_child(tools[BITMASK_PASTE]);
- tools[BITMASK_CLEAR] = memnew(Button);
- tools[BITMASK_CLEAR]->set_flat(true);
- tools[BITMASK_CLEAR]->set_tooltip(TTR("Erase bitmask."));
- tools[BITMASK_CLEAR]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_CLEAR));
- toolbar->add_child(tools[BITMASK_CLEAR]);
-
- tools[SHAPE_NEW_RECTANGLE] = memnew(Button);
- toolbar->add_child(tools[SHAPE_NEW_RECTANGLE]);
- tools[SHAPE_NEW_RECTANGLE]->set_flat(true);
- tools[SHAPE_NEW_RECTANGLE]->set_toggle_mode(true);
- tools[SHAPE_NEW_RECTANGLE]->set_button_group(tg);
- tools[SHAPE_NEW_RECTANGLE]->set_tooltip(TTR("Create a new rectangle."));
- tools[SHAPE_NEW_RECTANGLE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_NEW_RECTANGLE));
- tools[SHAPE_NEW_RECTANGLE]->set_shortcut(ED_SHORTCUT("tileset_editor/shape_new_rectangle", TTR("New Rectangle"), KEY_MASK_SHIFT | KEY_R));
-
- tools[SHAPE_NEW_POLYGON] = memnew(Button);
- toolbar->add_child(tools[SHAPE_NEW_POLYGON]);
- tools[SHAPE_NEW_POLYGON]->set_flat(true);
- tools[SHAPE_NEW_POLYGON]->set_toggle_mode(true);
- tools[SHAPE_NEW_POLYGON]->set_button_group(tg);
- tools[SHAPE_NEW_POLYGON]->set_tooltip(TTR("Create a new polygon."));
- tools[SHAPE_NEW_POLYGON]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_NEW_POLYGON));
- tools[SHAPE_NEW_POLYGON]->set_shortcut(ED_SHORTCUT("tileset_editor/shape_new_polygon", TTR("New Polygon"), KEY_MASK_SHIFT | KEY_P));
-
- separator_shape_toggle = memnew(VSeparator);
- toolbar->add_child(separator_shape_toggle);
- tools[SHAPE_TOGGLE_TYPE] = memnew(Button);
- tools[SHAPE_TOGGLE_TYPE]->set_flat(true);
- tools[SHAPE_TOGGLE_TYPE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_TOGGLE_TYPE));
- toolbar->add_child(tools[SHAPE_TOGGLE_TYPE]);
-
- separator_delete = memnew(VSeparator);
- toolbar->add_child(separator_delete);
- tools[SHAPE_DELETE] = memnew(Button);
- tools[SHAPE_DELETE]->set_flat(true);
- tools[SHAPE_DELETE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_DELETE));
- tools[SHAPE_DELETE]->set_shortcut(ED_SHORTCUT("tileset_editor/shape_delete", TTR("Delete Selected Shape"), KEY_MASK_SHIFT | KEY_BACKSPACE));
- toolbar->add_child(tools[SHAPE_DELETE]);
-
- spin_priority = memnew(SpinBox);
- spin_priority->set_min(1);
- spin_priority->set_max(255);
- spin_priority->set_step(1);
- spin_priority->set_custom_minimum_size(Size2(100, 0));
- spin_priority->connect("value_changed", callable_mp(this, &TileSetEditor::_on_priority_changed));
- spin_priority->hide();
- toolbar->add_child(spin_priority);
-
- spin_z_index = memnew(SpinBox);
- 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));
- spin_z_index->hide();
- toolbar->add_child(spin_z_index);
-
- separator_grid = memnew(VSeparator);
- toolbar->add_child(separator_grid);
- tools[SHAPE_KEEP_INSIDE_TILE] = memnew(Button);
- tools[SHAPE_KEEP_INSIDE_TILE]->set_flat(true);
- tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true);
- tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true);
- tools[SHAPE_KEEP_INSIDE_TILE]->set_tooltip(TTR("Keep polygon inside region Rect."));
- toolbar->add_child(tools[SHAPE_KEEP_INSIDE_TILE]);
- tools[TOOL_GRID_SNAP] = memnew(Button);
- tools[TOOL_GRID_SNAP]->set_flat(true);
- tools[TOOL_GRID_SNAP]->set_toggle_mode(true);
- tools[TOOL_GRID_SNAP]->set_tooltip(TTR("Enable snap and show grid (configurable via the Inspector)."));
- tools[TOOL_GRID_SNAP]->connect("toggled", callable_mp(this, &TileSetEditor::_on_grid_snap_toggled));
- toolbar->add_child(tools[TOOL_GRID_SNAP]);
-
- Control *separator = memnew(Control);
- separator->set_h_size_flags(SIZE_EXPAND_FILL);
- toolbar->add_child(separator);
-
- tools[ZOOM_OUT] = memnew(Button);
- tools[ZOOM_OUT]->set_flat(true);
- tools[ZOOM_OUT]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_out));
- toolbar->add_child(tools[ZOOM_OUT]);
- tools[ZOOM_OUT]->set_tooltip(TTR("Zoom Out"));
- tools[ZOOM_1] = memnew(Button);
- tools[ZOOM_1]->set_flat(true);
- tools[ZOOM_1]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_reset));
- toolbar->add_child(tools[ZOOM_1]);
- tools[ZOOM_1]->set_tooltip(TTR("Zoom Reset"));
- tools[ZOOM_IN] = memnew(Button);
- tools[ZOOM_IN]->set_flat(true);
- tools[ZOOM_IN]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_in));
- toolbar->add_child(tools[ZOOM_IN]);
- tools[ZOOM_IN]->set_tooltip(TTR("Zoom In"));
-
- tools[VISIBLE_INFO] = memnew(Button);
- tools[VISIBLE_INFO]->set_flat(true);
- tools[VISIBLE_INFO]->set_toggle_mode(true);
- tools[VISIBLE_INFO]->set_tooltip(TTR("Display Tile Names (Hold Alt Key)"));
- toolbar->add_child(tools[VISIBLE_INFO]);
-
- main_vb->add_child(toolbar);
-
- scroll = memnew(ScrollContainer);
- main_vb->add_child(scroll);
- scroll->set_v_size_flags(SIZE_EXPAND_FILL);
- scroll->connect("gui_input", callable_mp(this, &TileSetEditor::_on_scroll_container_input));
- scroll->set_clip_contents(true);
-
- empty_message = memnew(Label);
- empty_message->set_text(TTR("Add or select a texture on the left panel to edit the tiles bound to it."));
- empty_message->set_valign(Label::VALIGN_CENTER);
- empty_message->set_align(Label::ALIGN_CENTER);
- empty_message->set_autowrap(true);
- empty_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- empty_message->set_v_size_flags(SIZE_EXPAND_FILL);
- main_vb->add_child(empty_message);
-
- workspace_container = memnew(Control);
- scroll->add_child(workspace_container);
-
- workspace_overlay = memnew(Control);
- workspace_overlay->connect("draw", callable_mp(this, &TileSetEditor::_on_workspace_overlay_draw));
- workspace_container->add_child(workspace_overlay);
-
- workspace = memnew(Control);
- workspace->set_focus_mode(FOCUS_ALL);
- workspace->connect("draw", callable_mp(this, &TileSetEditor::_on_workspace_draw));
- workspace->connect("gui_input", callable_mp(this, &TileSetEditor::_on_workspace_input));
- workspace->set_draw_behind_parent(true);
- workspace_overlay->add_child(workspace);
-
- preview = memnew(Sprite2D);
- workspace->add_child(preview);
- preview->set_centered(false);
- preview->set_draw_behind_parent(true);
- preview->set_position(WORKSPACE_MARGIN);
-
- //---------------
- cd = memnew(ConfirmationDialog);
- add_child(cd);
- cd->connect("confirmed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_confirm));
-
- //---------------
- err_dialog = memnew(AcceptDialog);
- add_child(err_dialog);
-
- //---------------
- texture_dialog = memnew(EditorFileDialog);
- texture_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES);
- texture_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES);
- texture_dialog->clear_filters();
- List<String> extensions;
-
- ResourceLoader::get_recognized_extensions_for_type("Texture2D", &extensions);
- for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
- texture_dialog->add_filter("*." + E->get() + " ; " + E->get().to_upper());
- }
- add_child(texture_dialog);
- texture_dialog->connect("files_selected", callable_mp(this, &TileSetEditor::_on_textures_added));
-
- //---------------
- helper = memnew(TilesetEditorContext(this));
- tile_names_visible = false;
-
- // Config scale.
- max_scale = 16.0f;
- min_scale = 0.01f;
- scale_ratio = 1.2f;
-}
-
-TileSetEditor::~TileSetEditor() {
- if (helper) {
- memdelete(helper);
- }
-}
-
-void TileSetEditor::_on_tileset_toolbar_button_pressed(int p_index) {
- option = p_index;
- switch (option) {
- case TOOL_TILESET_ADD_TEXTURE: {
- texture_dialog->popup_file_dialog();
- } break;
- case TOOL_TILESET_REMOVE_TEXTURE: {
- if (get_current_texture().is_valid()) {
- cd->set_text(TTR("Remove selected texture? This will remove all tiles which use it."));
- cd->popup_centered(Size2(300, 60));
- } else {
- err_dialog->set_text(TTR("You haven't selected a texture to remove."));
- err_dialog->popup_centered(Size2(300, 60));
- }
- } break;
- case TOOL_TILESET_CREATE_SCENE: {
- cd->set_text(TTR("Create from scene? This will overwrite all current tiles."));
- cd->popup_centered(Size2(300, 60));
- } break;
- case TOOL_TILESET_MERGE_SCENE: {
- cd->set_text(TTR("Merge from scene?"));
- cd->popup_centered(Size2(300, 60));
- } break;
- }
-}
-
-void TileSetEditor::_on_tileset_toolbar_confirm() {
- switch (option) {
- case TOOL_TILESET_REMOVE_TEXTURE: {
- RID current_rid = get_current_texture()->get_rid();
- List<int> ids;
- tileset->get_tile_list(&ids);
-
- undo_redo->create_action(TTR("Remove Texture"));
- for (List<int>::Element *E = ids.front(); E; E = E->next()) {
- if (tileset->tile_get_texture(E->get())->get_rid() == current_rid) {
- undo_redo->add_do_method(tileset.ptr(), "remove_tile", E->get());
- _undo_tile_removal(E->get());
- }
- }
- undo_redo->add_do_method(this, "remove_texture", get_current_texture());
- undo_redo->add_undo_method(this, "add_texture", get_current_texture());
- undo_redo->add_undo_method(this, "update_texture_list_icon");
- undo_redo->commit_action();
- } break;
- case TOOL_TILESET_MERGE_SCENE:
- case TOOL_TILESET_CREATE_SCENE: {
- EditorNode *en = editor;
- Node *scene = en->get_edited_scene();
- if (!scene) {
- break;
- }
-
- List<int> ids;
- tileset->get_tile_list(&ids);
-
- undo_redo->create_action(option == TOOL_TILESET_MERGE_SCENE ? TTR("Merge Tileset from Scene") : TTR("Create Tileset from Scene"));
- undo_redo->add_do_method(this, "_undo_redo_import_scene", scene, option == TOOL_TILESET_MERGE_SCENE);
- undo_redo->add_undo_method(tileset.ptr(), "clear");
- for (List<int>::Element *E = ids.front(); E; E = E->next()) {
- _undo_tile_removal(E->get());
- }
- undo_redo->add_do_method(this, "edit", tileset);
- undo_redo->add_undo_method(this, "edit", tileset);
- undo_redo->commit_action();
- } break;
- }
-}
-
-void TileSetEditor::_on_texture_list_selected(int p_index) {
- if (get_current_texture().is_valid()) {
- current_item_index = p_index;
- preview->set_texture(get_current_texture());
- update_workspace_tile_mode();
- update_workspace_minsize();
- } else {
- current_item_index = -1;
- preview->set_texture(nullptr);
- workspace->set_custom_minimum_size(Size2i());
- update_workspace_tile_mode();
- }
-
- set_current_tile(-1);
- workspace->update();
-}
-
-void TileSetEditor::_on_textures_added(const PackedStringArray &p_paths) {
- int invalid_count = 0;
- for (int i = 0; i < p_paths.size(); i++) {
- Ref<Texture2D> t = Ref<Texture2D>(ResourceLoader::load(p_paths[i]));
-
- ERR_CONTINUE_MSG(!t.is_valid(), "'" + p_paths[i] + "' is not a valid texture.");
-
- if (texture_map.has(t->get_rid())) {
- invalid_count++;
- } else {
- add_texture(t);
- }
- }
-
- if (texture_list->get_item_count() > 0) {
- update_texture_list_icon();
- texture_list->select(texture_list->get_item_count() - 1);
- _on_texture_list_selected(texture_list->get_item_count() - 1);
- }
-
- if (invalid_count > 0) {
- err_dialog->set_text(vformat(TTR("%s file(s) were not added because was already on the list."), String::num(invalid_count, 0)));
- err_dialog->popup_centered(Size2(300, 60));
- }
-}
-
-void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
- draw_handles = false;
- creating_shape = false;
- edit_mode = (EditMode)p_edit_mode;
- switch (edit_mode) {
- case EDITMODE_REGION: {
- tools[TOOL_SELECT]->show();
-
- separator_bitmask->hide();
- tools[BITMASK_COPY]->hide();
- tools[BITMASK_PASTE]->hide();
- tools[BITMASK_CLEAR]->hide();
- tools[SHAPE_NEW_POLYGON]->hide();
- tools[SHAPE_NEW_RECTANGLE]->hide();
-
- if (workspace_mode == WORKSPACE_EDIT) {
- separator_delete->show();
- tools[SHAPE_DELETE]->show();
- } else {
- separator_delete->hide();
- tools[SHAPE_DELETE]->hide();
- }
-
- separator_grid->show();
- tools[SHAPE_KEEP_INSIDE_TILE]->hide();
- tools[TOOL_GRID_SNAP]->show();
-
- tools[TOOL_SELECT]->set_pressed(true);
- tools[TOOL_SELECT]->set_tooltip(TTR("Drag handles to edit Rect.\nClick on another Tile to edit it."));
- tools[SHAPE_DELETE]->set_tooltip(TTR("Delete selected Rect."));
- spin_priority->hide();
- spin_z_index->hide();
- } break;
- case EDITMODE_COLLISION:
- case EDITMODE_OCCLUSION:
- case EDITMODE_NAVIGATION: {
- tools[TOOL_SELECT]->show();
-
- separator_bitmask->hide();
- tools[BITMASK_COPY]->hide();
- tools[BITMASK_PASTE]->hide();
- tools[BITMASK_CLEAR]->hide();
- tools[SHAPE_NEW_POLYGON]->show();
- tools[SHAPE_NEW_RECTANGLE]->show();
-
- separator_delete->show();
- tools[SHAPE_DELETE]->show();
-
- separator_grid->show();
- tools[SHAPE_KEEP_INSIDE_TILE]->show();
- tools[TOOL_GRID_SNAP]->show();
-
- tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile.\nClick on another Tile to edit it."));
- tools[SHAPE_DELETE]->set_tooltip(TTR("Delete polygon."));
- spin_priority->hide();
- spin_z_index->hide();
-
- _select_edited_shape_coord();
- } break;
- case EDITMODE_BITMASK: {
- tools[TOOL_SELECT]->show();
-
- separator_bitmask->show();
- tools[BITMASK_COPY]->show();
- tools[BITMASK_PASTE]->show();
- tools[BITMASK_CLEAR]->show();
- tools[SHAPE_NEW_POLYGON]->hide();
- tools[SHAPE_NEW_RECTANGLE]->hide();
-
- separator_delete->hide();
- tools[SHAPE_DELETE]->hide();
-
- tools[SHAPE_KEEP_INSIDE_TILE]->hide();
-
- tools[TOOL_SELECT]->set_pressed(true);
- tools[TOOL_SELECT]->set_tooltip(TTR("LMB: Set bit on.\nRMB: Set bit off.\nShift+LMB: Set wildcard bit.\nClick on another Tile to edit it."));
- spin_priority->hide();
- } break;
- case EDITMODE_Z_INDEX:
- case EDITMODE_PRIORITY:
- case EDITMODE_ICON: {
- tools[TOOL_SELECT]->show();
-
- separator_bitmask->hide();
- tools[BITMASK_COPY]->hide();
- tools[BITMASK_PASTE]->hide();
- tools[BITMASK_CLEAR]->hide();
- tools[SHAPE_NEW_POLYGON]->hide();
- tools[SHAPE_NEW_RECTANGLE]->hide();
-
- separator_delete->hide();
- tools[SHAPE_DELETE]->hide();
-
- separator_grid->show();
- tools[SHAPE_KEEP_INSIDE_TILE]->hide();
- tools[TOOL_GRID_SNAP]->show();
-
- if (edit_mode == EDITMODE_ICON) {
- tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.\nClick on another Tile to edit it."));
- spin_priority->hide();
- spin_z_index->hide();
- } else if (edit_mode == EDITMODE_PRIORITY) {
- tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change its priority.\nClick on another Tile to edit it."));
- spin_priority->show();
- spin_z_index->hide();
- } else {
- tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change its z index.\nClick on another Tile to edit it."));
- spin_priority->hide();
- spin_z_index->show();
- }
- } break;
- default: {
- }
- }
- _update_toggle_shape_button();
- workspace->update();
-}
-
-void TileSetEditor::_on_workspace_mode_changed(int p_workspace_mode) {
- workspace_mode = (WorkspaceMode)p_workspace_mode;
- if (p_workspace_mode == WORKSPACE_EDIT) {
- update_workspace_tile_mode();
- } else {
- for (int i = 0; i < EDITMODE_MAX; i++) {
- tool_editmode[i]->hide();
- }
- tool_editmode[EDITMODE_REGION]->show();
- tool_editmode[EDITMODE_REGION]->set_pressed(true);
- _on_edit_mode_changed(EDITMODE_REGION);
- separator_editmode->show();
- }
-}
-
-void TileSetEditor::_on_workspace_draw() {
- if (tileset.is_null() || !get_current_texture().is_valid()) {
- return;
- }
-
- const Color COLOR_AUTOTILE = Color(0.3, 0.6, 1);
- const Color COLOR_SINGLE = Color(1, 1, 0.3);
- const Color COLOR_ATLAS = Color(0.8, 0.8, 0.8);
- const Color COLOR_SUBDIVISION = Color(0.3, 0.7, 0.6);
-
- draw_handles = false;
-
- draw_highlight_current_tile();
-
- draw_grid_snap();
- if (get_current_tile() >= 0) {
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 size = tileset->autotile_get_size(get_current_tile());
- Rect2i region = tileset->tile_get_region(get_current_tile());
-
- switch (edit_mode) {
- case EDITMODE_ICON: {
- Vector2 coord = tileset->autotile_get_icon_coordinate(get_current_tile());
- draw_highlight_subtile(coord);
- } break;
- case EDITMODE_BITMASK: {
- Color c(1, 0, 0, 0.5);
- Color ci(0.3, 0.6, 1, 0.5);
- for (int x = 0; x < region.size.x / (spacing + size.x); x++) {
- for (int y = 0; y < region.size.y / (spacing + size.y); y++) {
- Vector2 coord(x, y);
- Point2 anchor(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
- anchor += WORKSPACE_MARGIN;
- anchor += region.position;
- uint32_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
- if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
- if (mask & TileSet::BIND_IGNORE_TOPLEFT) {
- workspace->draw_rect(Rect2(anchor, size / 4), ci);
- workspace->draw_rect(Rect2(anchor + size / 4, size / 4), ci);
- } else if (mask & TileSet::BIND_TOPLEFT) {
- workspace->draw_rect(Rect2(anchor, size / 2), c);
- }
- if (mask & TileSet::BIND_IGNORE_TOPRIGHT) {
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, 0), size / 4), ci);
- workspace->draw_rect(Rect2(anchor + Vector2(size.x * 3 / 4, size.y / 4), size / 4), ci);
- } else if (mask & TileSet::BIND_TOPRIGHT) {
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, 0), size / 2), c);
- }
- if (mask & TileSet::BIND_IGNORE_BOTTOMLEFT) {
- workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 2), size / 4), ci);
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 4, size.y * 3 / 4), size / 4), ci);
- } else if (mask & TileSet::BIND_BOTTOMLEFT) {
- workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 2), size / 2), c);
- }
- if (mask & TileSet::BIND_IGNORE_BOTTOMRIGHT) {
- workspace->draw_rect(Rect2(anchor + size / 2, size / 4), ci);
- workspace->draw_rect(Rect2(anchor + size * 3 / 4, size / 4), ci);
- } else if (mask & TileSet::BIND_BOTTOMRIGHT) {
- workspace->draw_rect(Rect2(anchor + size / 2, size / 2), c);
- }
- } else {
- if (mask & TileSet::BIND_IGNORE_TOPLEFT) {
- workspace->draw_rect(Rect2(anchor, size / 6), ci);
- workspace->draw_rect(Rect2(anchor + size / 6, size / 6), ci);
- } else if (mask & TileSet::BIND_TOPLEFT) {
- workspace->draw_rect(Rect2(anchor, size / 3), c);
- }
- if (mask & TileSet::BIND_IGNORE_TOP) {
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, 0), size / 6), ci);
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, size.y / 6), size / 6), ci);
- } else if (mask & TileSet::BIND_TOP) {
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, 0), size / 3), c);
- }
- if (mask & TileSet::BIND_IGNORE_TOPRIGHT) {
- workspace->draw_rect(Rect2(anchor + Vector2(size.x * 4 / 6, 0), size / 6), ci);
- workspace->draw_rect(Rect2(anchor + Vector2(size.x * 5 / 6, size.y / 6), size / 6), ci);
- } else if (mask & TileSet::BIND_TOPRIGHT) {
- workspace->draw_rect(Rect2(anchor + Vector2((size.x / 3) * 2, 0), size / 3), c);
- }
- if (mask & TileSet::BIND_IGNORE_LEFT) {
- workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 3), size / 6), ci);
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 6, size.y / 2), size / 6), ci);
- } else if (mask & TileSet::BIND_LEFT) {
- workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 3), size / 3), c);
- }
- if (mask & TileSet::BIND_IGNORE_CENTER) {
- workspace->draw_rect(Rect2(anchor + size / 3, size / 6), ci);
- workspace->draw_rect(Rect2(anchor + size / 2, size / 6), ci);
- } else if (mask & TileSet::BIND_CENTER) {
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, size.y / 3), size / 3), c);
- }
- if (mask & TileSet::BIND_IGNORE_RIGHT) {
- workspace->draw_rect(Rect2(anchor + Vector2(size.x * 4 / 6, size.y / 3), size / 6), ci);
- workspace->draw_rect(Rect2(anchor + Vector2(size.x * 5 / 6, size.y / 2), size / 6), ci);
- } else if (mask & TileSet::BIND_RIGHT) {
- workspace->draw_rect(Rect2(anchor + Vector2((size.x / 3) * 2, size.y / 3), size / 3), c);
- }
- if (mask & TileSet::BIND_IGNORE_BOTTOMLEFT) {
- workspace->draw_rect(Rect2(anchor + Vector2(0, size.y * 4 / 6), size / 6), ci);
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 6, size.y * 5 / 6), size / 6), ci);
- } else if (mask & TileSet::BIND_BOTTOMLEFT) {
- workspace->draw_rect(Rect2(anchor + Vector2(0, (size.y / 3) * 2), size / 3), c);
- }
- if (mask & TileSet::BIND_IGNORE_BOTTOM) {
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, size.y * 4 / 6), size / 6), ci);
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, size.y * 5 / 6), size / 6), ci);
- } else if (mask & TileSet::BIND_BOTTOM) {
- workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, (size.y / 3) * 2), size / 3), c);
- }
- if (mask & TileSet::BIND_IGNORE_BOTTOMRIGHT) {
- workspace->draw_rect(Rect2(anchor + size * 4 / 6, size / 6), ci);
- workspace->draw_rect(Rect2(anchor + size * 5 / 6, size / 6), ci);
- } else if (mask & TileSet::BIND_BOTTOMRIGHT) {
- workspace->draw_rect(Rect2(anchor + (size / 3) * 2, size / 3), c);
- }
- }
- }
- }
- } break;
- case EDITMODE_COLLISION:
- case EDITMODE_OCCLUSION:
- case EDITMODE_NAVIGATION: {
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
- draw_highlight_subtile(edited_shape_coord);
- }
- draw_polygon_shapes();
- draw_grid_snap();
- } break;
- case EDITMODE_PRIORITY: {
- spin_priority->set_value(tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord));
- uint32_t mask = tileset->autotile_get_bitmask(get_current_tile(), edited_shape_coord);
- Vector<Vector2> queue_others;
- int total = 0;
- for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
- if (E->value() == mask) {
- total += tileset->autotile_get_subtile_priority(get_current_tile(), E->key());
- if (E->key() != edited_shape_coord) {
- queue_others.push_back(E->key());
- }
- }
- }
- spin_priority->set_suffix(" / " + String::num(total, 0));
- draw_highlight_subtile(edited_shape_coord, queue_others);
- } break;
- case EDITMODE_Z_INDEX: {
- spin_z_index->set_value(tileset->autotile_get_z_index(get_current_tile(), edited_shape_coord));
- draw_highlight_subtile(edited_shape_coord);
- } break;
- default: {
- }
- }
- }
-
- RID current_texture_rid = get_current_texture()->get_rid();
- List<int> *tiles = new List<int>();
- tileset->get_tile_list(tiles);
- for (List<int>::Element *E = tiles->front(); E; E = E->next()) {
- int t_id = E->get();
- if (tileset->tile_get_texture(t_id)->get_rid() == current_texture_rid && (t_id != get_current_tile() || edit_mode != EDITMODE_REGION || workspace_mode != WORKSPACE_EDIT)) {
- Rect2i region = tileset->tile_get_region(t_id);
- region.position += WORKSPACE_MARGIN;
- Color c;
- if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) {
- c = COLOR_SINGLE;
- } else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) {
- c = COLOR_AUTOTILE;
- } else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) {
- c = COLOR_ATLAS;
- }
- draw_tile_subdivision(t_id, COLOR_SUBDIVISION);
- workspace->draw_rect(region, c, false);
- }
- }
- delete tiles;
-
- if (edit_mode == EDITMODE_REGION) {
- if (workspace_mode != WORKSPACE_EDIT) {
- Rect2i region = edited_region;
- Color c;
- if (workspace_mode == WORKSPACE_CREATE_SINGLE) {
- c = COLOR_SINGLE;
- } else if (workspace_mode == WORKSPACE_CREATE_AUTOTILE) {
- c = COLOR_AUTOTILE;
- } else if (workspace_mode == WORKSPACE_CREATE_ATLAS) {
- c = COLOR_ATLAS;
- }
- workspace->draw_rect(region, c, false);
- draw_edited_region_subdivision();
- } else {
- int t_id = get_current_tile();
- if (t_id < 0) {
- return;
- }
-
- Rect2i region;
- if (draw_edited_region) {
- region = edited_region;
- } else {
- region = tileset->tile_get_region(t_id);
- region.position += WORKSPACE_MARGIN;
- }
-
- if (draw_edited_region) {
- draw_edited_region_subdivision();
- } else {
- draw_tile_subdivision(t_id, COLOR_SUBDIVISION);
- }
-
- Color c;
- if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) {
- c = COLOR_SINGLE;
- } else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) {
- c = COLOR_AUTOTILE;
- } else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) {
- c = COLOR_ATLAS;
- }
- workspace->draw_rect(region, c, false);
- }
- }
-
- workspace_overlay->update();
-}
-
-void TileSetEditor::_on_workspace_process() {
- if (Input::get_singleton()->is_key_pressed(KEY_ALT) || tools[VISIBLE_INFO]->is_pressed()) {
- if (!tile_names_visible) {
- tile_names_visible = true;
- workspace_overlay->update();
- }
- } else if (tile_names_visible) {
- tile_names_visible = false;
- workspace_overlay->update();
- }
-}
-
-void TileSetEditor::_on_workspace_overlay_draw() {
- if (!tileset.is_valid() || !get_current_texture().is_valid()) {
- return;
- }
-
- const Color COLOR_AUTOTILE = Color(0.266373, 0.565288, 0.988281);
- const Color COLOR_SINGLE = Color(0.988281, 0.909323, 0.266373);
- const Color COLOR_ATLAS = Color(0.78653, 0.812835, 0.832031);
-
- if (tile_names_visible) {
- RID current_texture_rid = get_current_texture()->get_rid();
- List<int> *tiles = new List<int>();
- tileset->get_tile_list(tiles);
- for (List<int>::Element *E = tiles->front(); E; E = E->next()) {
- int t_id = E->get();
- if (tileset->tile_get_texture(t_id)->get_rid() != current_texture_rid) {
- continue;
- }
-
- Rect2 region = tileset->tile_get_region(t_id);
- region.position += WORKSPACE_MARGIN;
- region.position *= workspace->get_scale().x;
- Color c;
- if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) {
- c = COLOR_SINGLE;
- } else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) {
- c = COLOR_AUTOTILE;
- } 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_theme_font("font", "Label");
- int font_size = get_theme_font_size("font_size", "Label");
- region.set_size(font->get_string_size(tile_id_name, font_size));
- workspace_overlay->draw_rect(region, c);
- region.position.y += region.size.y - 2;
- c = Color(0.1, 0.1, 0.1);
- workspace_overlay->draw_string(font, region.position, tile_id_name, HALIGN_LEFT, -1, font_size, c);
- }
- delete tiles;
- }
-
- int t_id = get_current_tile();
- if (t_id < 0) {
- return;
- }
-
- 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);
- }
- }
-}
-
-int TileSetEditor::get_grabbed_point(const Vector2 &p_mouse_pos, real_t p_grab_threshold) {
- Transform2D xform = workspace->get_transform();
-
- int grabbed_point = -1;
- real_t min_distance = 1e10;
-
- for (int i = 0; i < current_shape.size(); i++) {
- const real_t distance = xform.xform(current_shape[i]).distance_to(xform.xform(p_mouse_pos));
- if (distance < p_grab_threshold && distance < min_distance) {
- min_distance = distance;
- grabbed_point = i;
- }
- }
-
- return grabbed_point;
-}
-
-bool TileSetEditor::is_within_grabbing_distance_of_first_point(const Vector2 &p_pos, real_t p_grab_threshold) {
- Transform2D xform = workspace->get_transform();
-
- const real_t distance = xform.xform(current_shape[0]).distance_to(xform.xform(p_pos));
-
- return distance < p_grab_threshold;
-}
-
-void TileSetEditor::_on_scroll_container_input(const Ref<InputEvent> &p_event) {
- const Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid()) {
- // Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
- // to allow performing this action anywhere, even if the cursor isn't
- // hovering the texture in the workspace.
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
- print_line("zooming in");
- _zoom_in();
- // Don't scroll up after zooming in.
- accept_event();
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
- print_line("zooming out");
- _zoom_out();
- // Don't scroll down after zooming out.
- accept_event();
- }
- }
-}
-
-void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
- if (tileset.is_null() || !get_current_texture().is_valid()) {
- return;
- }
-
- static bool dragging;
- static bool erasing;
- static bool alternative;
- draw_edited_region = false;
-
- Rect2 current_tile_region = Rect2();
- if (get_current_tile() >= 0) {
- current_tile_region = tileset->tile_get_region(get_current_tile());
- }
- current_tile_region.position += WORKSPACE_MARGIN;
-
- const Ref<InputEventMouseButton> mb = p_ie;
- const Ref<InputEventMouseMotion> mm = p_ie;
-
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !creating_shape) {
- if (!current_tile_region.has_point(mb->get_position())) {
- List<int> *tiles = new List<int>();
- tileset->get_tile_list(tiles);
- for (List<int>::Element *E = tiles->front(); E; E = E->next()) {
- int t_id = E->get();
- if (get_current_texture()->get_rid() == tileset->tile_get_texture(t_id)->get_rid()) {
- Rect2 r = tileset->tile_get_region(t_id);
- r.position += WORKSPACE_MARGIN;
- if (r.has_point(mb->get_position())) {
- set_current_tile(t_id);
- workspace->update();
- workspace_overlay->update();
- delete tiles;
- return;
- }
- }
- }
- delete tiles;
- }
- }
- }
- // Drag Middle Mouse
- if (mm.is_valid()) {
- if (mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
- Vector2 dragged(mm->get_relative().x, mm->get_relative().y);
- scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x);
- scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x);
- }
- }
-
- if (edit_mode == EDITMODE_REGION) {
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (get_current_tile() >= 0 || workspace_mode != WORKSPACE_EDIT) {
- dragging = true;
- region_from = mb->get_position();
- edited_region = Rect2(region_from, Size2());
- workspace->update();
- workspace_overlay->update();
- return;
- }
- } else if (dragging && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- dragging = false;
- edited_region = Rect2();
- workspace->update();
- workspace_overlay->update();
- return;
- } else if (dragging && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- dragging = false;
- update_edited_region(mb->get_position());
- edited_region.position -= WORKSPACE_MARGIN;
- if (!edited_region.has_no_area()) {
- if (get_current_tile() >= 0 && workspace_mode == WORKSPACE_EDIT) {
- undo_redo->create_action(TTR("Set Tile Region"));
- undo_redo->add_do_method(tileset.ptr(), "tile_set_region", get_current_tile(), edited_region);
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_region", get_current_tile(), tileset->tile_get_region(get_current_tile()));
-
- Size2 tile_workspace_size = edited_region.position + edited_region.size + WORKSPACE_MARGIN * 2;
- Size2 workspace_minsize = workspace->get_custom_minimum_size();
- // If the new region is bigger, just directly change the workspace size to avoid checking all other tiles.
- if (tile_workspace_size.x > workspace_minsize.x || tile_workspace_size.y > workspace_minsize.y) {
- Size2 max_workspace_size = Size2(MAX(tile_workspace_size.x, workspace_minsize.x), MAX(tile_workspace_size.y, workspace_minsize.y));
- undo_redo->add_do_method(workspace, "set_custom_minimum_size", max_workspace_size);
- undo_redo->add_undo_method(workspace, "set_custom_minimum_size", workspace_minsize);
- undo_redo->add_do_method(workspace_container, "set_custom_minimum_size", max_workspace_size);
- undo_redo->add_undo_method(workspace_container, "set_custom_minimum_size", workspace_minsize);
- undo_redo->add_do_method(workspace_overlay, "set_custom_minimum_size", max_workspace_size);
- undo_redo->add_undo_method(workspace_overlay, "set_custom_minimum_size", workspace_minsize);
- } else if (workspace_minsize.x > get_current_texture()->get_size().x + WORKSPACE_MARGIN.x * 2 || workspace_minsize.y > get_current_texture()->get_size().y + WORKSPACE_MARGIN.y * 2) {
- undo_redo->add_do_method(this, "update_workspace_minsize");
- undo_redo->add_undo_method(this, "update_workspace_minsize");
- }
-
- edited_region = Rect2();
-
- undo_redo->add_do_method(workspace, "update");
- undo_redo->add_undo_method(workspace, "update");
- undo_redo->add_do_method(workspace_overlay, "update");
- undo_redo->add_undo_method(workspace_overlay, "update");
- undo_redo->commit_action();
- } else {
- int t_id = tileset->get_last_unused_tile_id();
- undo_redo->create_action(TTR("Create Tile"));
- undo_redo->add_do_method(tileset.ptr(), "create_tile", t_id);
- undo_redo->add_undo_method(tileset.ptr(), "remove_tile", t_id);
- undo_redo->add_undo_method(this, "_validate_current_tile_id");
- undo_redo->add_do_method(tileset.ptr(), "tile_set_texture", t_id, get_current_texture());
- undo_redo->add_do_method(tileset.ptr(), "tile_set_region", t_id, edited_region);
- undo_redo->add_do_method(tileset.ptr(), "tile_set_name", t_id, get_current_texture()->get_path().get_file() + " " + String::num(t_id, 0));
- if (workspace_mode != WORKSPACE_CREATE_SINGLE) {
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_size", t_id, snap_step);
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_spacing", t_id, snap_separation.x);
- undo_redo->add_do_method(tileset.ptr(), "tile_set_tile_mode", t_id, workspace_mode == WORKSPACE_CREATE_AUTOTILE ? TileSet::AUTO_TILE : TileSet::ATLAS_TILE);
- }
-
- tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true);
- tool_editmode[EDITMODE_COLLISION]->set_pressed(true);
- edit_mode = EDITMODE_COLLISION;
-
- Size2 tile_workspace_size = edited_region.position + edited_region.size + WORKSPACE_MARGIN * 2;
- Size2 workspace_minsize = workspace->get_custom_minimum_size();
- if (tile_workspace_size.x > workspace_minsize.x || tile_workspace_size.y > workspace_minsize.y) {
- Size2 new_workspace_minsize = Size2(MAX(tile_workspace_size.x, workspace_minsize.x), MAX(tile_workspace_size.y, workspace_minsize.y));
- undo_redo->add_do_method(workspace, "set_custom_minimum_size", new_workspace_minsize);
- undo_redo->add_undo_method(workspace, "set_custom_minimum_size", workspace_minsize);
- undo_redo->add_do_method(workspace_container, "set_custom_minimum_size", new_workspace_minsize);
- undo_redo->add_undo_method(workspace_container, "set_custom_minimum_size", workspace_minsize);
- undo_redo->add_do_method(workspace_overlay, "set_custom_minimum_size", new_workspace_minsize);
- undo_redo->add_undo_method(workspace_overlay, "set_custom_minimum_size", workspace_minsize);
- }
-
- edited_region = Rect2();
-
- undo_redo->add_do_method(workspace, "update");
- undo_redo->add_undo_method(workspace, "update");
- undo_redo->add_do_method(workspace_overlay, "update");
- undo_redo->add_undo_method(workspace_overlay, "update");
- undo_redo->commit_action();
-
- set_current_tile(t_id);
- _on_workspace_mode_changed(WORKSPACE_EDIT);
- }
- } else {
- edited_region = Rect2();
- workspace->update();
- workspace_overlay->update();
- }
- return;
- }
- } else if (mm.is_valid()) {
- if (dragging) {
- update_edited_region(mm->get_position());
- draw_edited_region = true;
- workspace->update();
- workspace_overlay->update();
- return;
- }
- }
- }
-
- if (workspace_mode == WORKSPACE_EDIT) {
- if (get_current_tile() >= 0) {
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 size = tileset->autotile_get_size(get_current_tile());
- switch (edit_mode) {
- case EDITMODE_ICON: {
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && current_tile_region.has_point(mb->get_position())) {
- Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
- undo_redo->create_action(TTR("Set Tile Icon"));
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_icon_coordinate", get_current_tile(), coord);
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_icon_coordinate", get_current_tile(), tileset->autotile_get_icon_coordinate(get_current_tile()));
- undo_redo->add_do_method(workspace, "update");
- undo_redo->add_undo_method(workspace, "update");
- undo_redo->commit_action();
- }
- }
- } break;
- case EDITMODE_BITMASK: {
- if (mb.is_valid()) {
- if (mb->is_pressed()) {
- if (dragging) {
- return;
- }
- if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT || mb->get_button_index() == MOUSE_BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) {
- dragging = true;
- erasing = (mb->get_button_index() == MOUSE_BUTTON_RIGHT);
- alternative = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
- Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
- Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
- pos = mb->get_position() - (pos + current_tile_region.position);
- uint32_t bit = 0;
- if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
- if (pos.x < size.x / 2) {
- if (pos.y < size.y / 2) {
- bit = TileSet::BIND_TOPLEFT;
- } else {
- bit = TileSet::BIND_BOTTOMLEFT;
- }
- } else {
- if (pos.y < size.y / 2) {
- bit = TileSet::BIND_TOPRIGHT;
- } else {
- bit = TileSet::BIND_BOTTOMRIGHT;
- }
- }
- } else {
- if (pos.x < size.x / 3) {
- if (pos.y < size.y / 3) {
- bit = TileSet::BIND_TOPLEFT;
- } else if (pos.y > (size.y / 3) * 2) {
- bit = TileSet::BIND_BOTTOMLEFT;
- } else {
- bit = TileSet::BIND_LEFT;
- }
- } else if (pos.x > (size.x / 3) * 2) {
- if (pos.y < size.y / 3) {
- bit = TileSet::BIND_TOPRIGHT;
- } else if (pos.y > (size.y / 3) * 2) {
- bit = TileSet::BIND_BOTTOMRIGHT;
- } else {
- bit = TileSet::BIND_RIGHT;
- }
- } else {
- if (pos.y < size.y / 3) {
- bit = TileSet::BIND_TOP;
- } else if (pos.y > (size.y / 3) * 2) {
- bit = TileSet::BIND_BOTTOM;
- } else {
- bit = TileSet::BIND_CENTER;
- }
- }
- }
-
- uint32_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
- uint32_t new_mask = old_mask;
- if (alternative) {
- new_mask &= ~bit;
- new_mask |= (bit << 16);
- } else if (erasing) {
- new_mask &= ~bit;
- new_mask &= ~(bit << 16);
- } else {
- new_mask |= bit;
- new_mask &= ~(bit << 16);
- }
-
- if (old_mask != new_mask) {
- undo_redo->create_action(TTR("Edit Tile Bitmask"));
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, new_mask);
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, old_mask);
- undo_redo->add_do_method(workspace, "update");
- undo_redo->add_undo_method(workspace, "update");
- undo_redo->commit_action();
- }
- }
- } else {
- if ((erasing && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (!erasing && mb->get_button_index() == MOUSE_BUTTON_LEFT)) {
- dragging = false;
- erasing = false;
- alternative = false;
- }
- }
- }
- if (mm.is_valid()) {
- if (dragging && current_tile_region.has_point(mm->get_position())) {
- Vector2 coord((int)((mm->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mm->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
- Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
- pos = mm->get_position() - (pos + current_tile_region.position);
- uint32_t bit = 0;
- if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
- if (pos.x < size.x / 2) {
- if (pos.y < size.y / 2) {
- bit = TileSet::BIND_TOPLEFT;
- } else {
- bit = TileSet::BIND_BOTTOMLEFT;
- }
- } else {
- if (pos.y < size.y / 2) {
- bit = TileSet::BIND_TOPRIGHT;
- } else {
- bit = TileSet::BIND_BOTTOMRIGHT;
- }
- }
- } else {
- if (pos.x < size.x / 3) {
- if (pos.y < size.y / 3) {
- bit = TileSet::BIND_TOPLEFT;
- } else if (pos.y > (size.y / 3) * 2) {
- bit = TileSet::BIND_BOTTOMLEFT;
- } else {
- bit = TileSet::BIND_LEFT;
- }
- } else if (pos.x > (size.x / 3) * 2) {
- if (pos.y < size.y / 3) {
- bit = TileSet::BIND_TOPRIGHT;
- } else if (pos.y > (size.y / 3) * 2) {
- bit = TileSet::BIND_BOTTOMRIGHT;
- } else {
- bit = TileSet::BIND_RIGHT;
- }
- } else {
- if (pos.y < size.y / 3) {
- bit = TileSet::BIND_TOP;
- } else if (pos.y > (size.y / 3) * 2) {
- bit = TileSet::BIND_BOTTOM;
- } else {
- bit = TileSet::BIND_CENTER;
- }
- }
- }
-
- uint32_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
- uint32_t new_mask = old_mask;
- if (alternative) {
- new_mask &= ~bit;
- new_mask |= (bit << 16);
- } else if (erasing) {
- new_mask &= ~bit;
- new_mask &= ~(bit << 16);
- } else {
- new_mask |= bit;
- new_mask &= ~(bit << 16);
- }
- if (old_mask != new_mask) {
- undo_redo->create_action(TTR("Edit Tile Bitmask"));
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, new_mask);
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, old_mask);
- undo_redo->add_do_method(workspace, "update");
- undo_redo->add_undo_method(workspace, "update");
- undo_redo->commit_action();
- }
- }
- }
- } break;
- case EDITMODE_COLLISION:
- case EDITMODE_OCCLUSION:
- case EDITMODE_NAVIGATION:
- case EDITMODE_PRIORITY:
- case EDITMODE_Z_INDEX: {
- Vector2 shape_anchor = Vector2(0, 0);
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
- shape_anchor = edited_shape_coord;
- shape_anchor.x *= (size.x + spacing);
- shape_anchor.y *= (size.y + spacing);
- }
-
- const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
- shape_anchor += current_tile_region.position;
- if (tools[TOOL_SELECT]->is_pressed()) {
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (edit_mode != EDITMODE_PRIORITY && current_shape.size() > 0) {
- int grabbed_point = get_grabbed_point(mb->get_position(), grab_threshold);
-
- if (grabbed_point >= 0) {
- dragging_point = grabbed_point;
- workspace->update();
- return;
- }
- }
- if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) && current_tile_region.has_point(mb->get_position())) {
- Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
- if (edited_shape_coord != coord) {
- edited_shape_coord = coord;
- _select_edited_shape_coord();
- }
- }
- workspace->update();
- } else if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (edit_mode == EDITMODE_COLLISION) {
- if (dragging_point >= 0) {
- dragging_point = -1;
-
- Vector<Vector2> points;
-
- for (int i = 0; i < current_shape.size(); i++) {
- Vector2 p = current_shape[i];
- if (tools[TOOL_GRID_SNAP]->is_pressed() || tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) {
- p = snap_point(p);
- }
- points.push_back(p - shape_anchor);
- }
-
- undo_redo->create_action(TTR("Edit Collision Polygon"));
- _set_edited_shape_points(points);
- undo_redo->add_do_method(this, "_select_edited_shape_coord");
- undo_redo->add_undo_method(this, "_select_edited_shape_coord");
- undo_redo->commit_action();
- }
- } else if (edit_mode == EDITMODE_OCCLUSION) {
- if (dragging_point >= 0) {
- dragging_point = -1;
-
- Vector<Vector2> polygon;
- polygon.resize(current_shape.size());
- Vector2 *w = polygon.ptrw();
-
- for (int i = 0; i < current_shape.size(); i++) {
- w[i] = current_shape[i] - shape_anchor;
- }
-
- undo_redo->create_action(TTR("Edit Occlusion Polygon"));
- undo_redo->add_do_method(edited_occlusion_shape.ptr(), "set_polygon", polygon);
- undo_redo->add_undo_method(edited_occlusion_shape.ptr(), "set_polygon", edited_occlusion_shape->get_polygon());
- undo_redo->add_do_method(this, "_select_edited_shape_coord");
- undo_redo->add_undo_method(this, "_select_edited_shape_coord");
- undo_redo->commit_action();
- }
- } else if (edit_mode == EDITMODE_NAVIGATION) {
- if (dragging_point >= 0) {
- dragging_point = -1;
-
- Vector<Vector2> polygon;
- Vector<int> indices;
- polygon.resize(current_shape.size());
- Vector2 *w = polygon.ptrw();
-
- for (int i = 0; i < current_shape.size(); i++) {
- w[i] = current_shape[i] - shape_anchor;
- indices.push_back(i);
- }
-
- undo_redo->create_action(TTR("Edit Navigation Polygon"));
- undo_redo->add_do_method(edited_navigation_shape.ptr(), "set_vertices", polygon);
- undo_redo->add_undo_method(edited_navigation_shape.ptr(), "set_vertices", edited_navigation_shape->get_vertices());
- undo_redo->add_do_method(edited_navigation_shape.ptr(), "clear_polygons");
- undo_redo->add_undo_method(edited_navigation_shape.ptr(), "clear_polygons");
- undo_redo->add_do_method(edited_navigation_shape.ptr(), "add_polygon", indices);
- undo_redo->add_undo_method(edited_navigation_shape.ptr(), "add_polygon", edited_navigation_shape->get_polygon(0));
- undo_redo->add_do_method(this, "_select_edited_shape_coord");
- undo_redo->add_undo_method(this, "_select_edited_shape_coord");
- undo_redo->commit_action();
- }
- }
- }
- } else if (mm.is_valid()) {
- if (dragging_point >= 0) {
- current_shape.set(dragging_point, snap_point(mm->get_position()));
- workspace->update();
- }
- }
- } else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) {
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- Vector2 pos = mb->get_position();
- pos = snap_point(pos);
- if (creating_shape) {
- if (current_shape.size() > 2) {
- if (is_within_grabbing_distance_of_first_point(mb->get_position(), grab_threshold)) {
- close_shape(shape_anchor);
- workspace->update();
- return;
- }
- }
- current_shape.push_back(pos);
- workspace->update();
- } else {
- creating_shape = true;
- _set_edited_collision_shape(Ref<ConvexPolygonShape2D>());
- current_shape.resize(0);
- current_shape.push_back(snap_point(pos));
- workspace->update();
- }
- } else if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- if (creating_shape) {
- creating_shape = false;
- _select_edited_shape_coord();
- workspace->update();
- }
- }
- } else if (mm.is_valid()) {
- if (creating_shape) {
- workspace->update();
- }
- }
- } else if (tools[SHAPE_NEW_RECTANGLE]->is_pressed()) {
- if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- _set_edited_collision_shape(Ref<ConvexPolygonShape2D>());
- current_shape.resize(0);
- Vector2 pos = mb->get_position();
- pos = snap_point(pos);
- current_shape.push_back(pos);
- current_shape.push_back(pos);
- current_shape.push_back(pos);
- current_shape.push_back(pos);
- creating_shape = true;
- workspace->update();
- return;
- } else if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- if (creating_shape) {
- creating_shape = false;
- _select_edited_shape_coord();
- workspace->update();
- }
- } else if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (creating_shape) {
- // if the first two corners are within grabbing distance of one another, expand the rect to fill the tile
- if (is_within_grabbing_distance_of_first_point(current_shape[1], grab_threshold)) {
- current_shape.set(0, snap_point(shape_anchor));
- current_shape.set(1, snap_point(shape_anchor + Vector2(current_tile_region.size.x, 0)));
- current_shape.set(2, snap_point(shape_anchor + current_tile_region.size));
- current_shape.set(3, snap_point(shape_anchor + Vector2(0, current_tile_region.size.y)));
- }
-
- close_shape(shape_anchor);
- workspace->update();
- return;
- }
- }
- } else if (mm.is_valid()) {
- if (creating_shape) {
- Vector2 pos = mm->get_position();
- pos = snap_point(pos);
- Vector2 p = current_shape[2];
- current_shape.set(3, snap_point(Vector2(pos.x, p.y)));
- current_shape.set(0, snap_point(pos));
- current_shape.set(1, snap_point(Vector2(p.x, pos.y)));
- workspace->update();
- }
- }
- }
- } break;
- default: {
- }
- }
- }
- }
-}
-
-void TileSetEditor::_on_tool_clicked(int p_tool) {
- if (p_tool == BITMASK_COPY) {
- bitmask_map_copy = tileset->autotile_get_bitmask_map(get_current_tile());
- } else if (p_tool == BITMASK_PASTE) {
- undo_redo->create_action(TTR("Paste Tile Bitmask"));
- undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
- undo_redo->add_undo_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
- for (Map<Vector2, uint32_t>::Element *E = bitmask_map_copy.front(); E; E = E->next()) {
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
- }
- for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
- }
- undo_redo->add_do_method(workspace, "update");
- undo_redo->add_undo_method(workspace, "update");
- undo_redo->commit_action();
- } else if (p_tool == BITMASK_CLEAR) {
- undo_redo->create_action(TTR("Clear Tile Bitmask"));
- undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
- for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
- }
- undo_redo->add_do_method(workspace, "update");
- undo_redo->add_undo_method(workspace, "update");
- undo_redo->commit_action();
- } else if (p_tool == SHAPE_TOGGLE_TYPE) {
- if (edited_collision_shape.is_valid()) {
- Ref<ConvexPolygonShape2D> convex = edited_collision_shape;
- Ref<ConcavePolygonShape2D> concave = edited_collision_shape;
- Ref<Shape2D> previous_shape = edited_collision_shape;
- Array sd = tileset->call("tile_get_shapes", get_current_tile());
-
- if (convex.is_valid()) {
- // Make concave.
- undo_redo->create_action(TTR("Make Polygon Concave"));
- Ref<ConcavePolygonShape2D> _concave = memnew(ConcavePolygonShape2D);
- edited_collision_shape = _concave;
- _set_edited_shape_points(_get_collision_shape_points(convex));
- } else if (concave.is_valid()) {
- // Make convex.
- undo_redo->create_action(TTR("Make Polygon Convex"));
- Ref<ConvexPolygonShape2D> _convex = memnew(ConvexPolygonShape2D);
- edited_collision_shape = _convex;
- _set_edited_shape_points(_get_collision_shape_points(concave));
- }
- for (int i = 0; i < sd.size(); i++) {
- if (sd[i].get("shape") == previous_shape) {
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd.duplicate());
- sd.remove(i);
- break;
- }
- }
-
- undo_redo->add_do_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd);
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
- undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), edited_collision_shape, Transform2D(), false, edited_shape_coord);
- } else {
- undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), edited_collision_shape, Transform2D());
- }
- undo_redo->add_do_method(this, "_select_edited_shape_coord");
- undo_redo->add_undo_method(this, "_select_edited_shape_coord");
- undo_redo->commit_action();
-
- _update_toggle_shape_button();
- workspace->update();
- workspace_container->update();
- helper->notify_property_list_changed();
- }
- } else if (p_tool == SELECT_NEXT) {
- _select_next_shape();
- } else if (p_tool == SELECT_PREVIOUS) {
- _select_previous_shape();
- } else if (p_tool == SHAPE_DELETE) {
- if (creating_shape) {
- creating_shape = false;
- current_shape.resize(0);
- workspace->update();
- } else {
- switch (edit_mode) {
- case EDITMODE_REGION: {
- int t_id = get_current_tile();
- if (workspace_mode == WORKSPACE_EDIT && t_id >= 0) {
- undo_redo->create_action(TTR("Remove Tile"));
- undo_redo->add_do_method(tileset.ptr(), "remove_tile", t_id);
- _undo_tile_removal(t_id);
- undo_redo->add_do_method(this, "_validate_current_tile_id");
-
- Rect2 tile_region = tileset->tile_get_region(get_current_tile());
- Size2 tile_workspace_size = tile_region.position + tile_region.size;
- if (tile_workspace_size.x > get_current_texture()->get_size().x || tile_workspace_size.y > get_current_texture()->get_size().y) {
- undo_redo->add_do_method(this, "update_workspace_minsize");
- undo_redo->add_undo_method(this, "update_workspace_minsize");
- }
-
- undo_redo->add_do_method(workspace, "update");
- undo_redo->add_undo_method(workspace, "update");
- undo_redo->add_do_method(workspace_overlay, "update");
- undo_redo->add_undo_method(workspace_overlay, "update");
- undo_redo->commit_action();
- }
- tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true);
- workspace_mode = WORKSPACE_EDIT;
- update_workspace_tile_mode();
- } break;
- case EDITMODE_COLLISION: {
- if (!edited_collision_shape.is_null()) {
- // Necessary to get the version that returns a Array instead of a Vector.
- Array sd = tileset->call("tile_get_shapes", get_current_tile());
- for (int i = 0; i < sd.size(); i++) {
- if (sd[i].get("shape") == edited_collision_shape) {
- undo_redo->create_action(TTR("Remove Collision Polygon"));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd.duplicate());
- sd.remove(i);
- undo_redo->add_do_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd);
- undo_redo->add_do_method(this, "_select_edited_shape_coord");
- undo_redo->add_undo_method(this, "_select_edited_shape_coord");
- undo_redo->commit_action();
- break;
- }
- }
- }
- } break;
- case EDITMODE_OCCLUSION: {
- if (!edited_occlusion_shape.is_null()) {
- undo_redo->create_action(TTR("Remove Occlusion Polygon"));
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- undo_redo->add_do_method(tileset.ptr(), "tile_set_light_occluder", get_current_tile(), Ref<OccluderPolygon2D>());
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_light_occluder", get_current_tile(), tileset->tile_get_light_occluder(get_current_tile()));
- } else {
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_light_occluder", get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord);
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_light_occluder", get_current_tile(), tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord), edited_shape_coord);
- }
- undo_redo->add_do_method(this, "_select_edited_shape_coord");
- undo_redo->add_undo_method(this, "_select_edited_shape_coord");
- undo_redo->commit_action();
- }
- } break;
- case EDITMODE_NAVIGATION: {
- if (!edited_navigation_shape.is_null()) {
- undo_redo->create_action(TTR("Remove Navigation Polygon"));
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- undo_redo->add_do_method(tileset.ptr(), "tile_set_navigation_polygon", get_current_tile(), Ref<NavigationPolygon>());
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_navigation_polygon", get_current_tile(), tileset->tile_get_navigation_polygon(get_current_tile()));
- } else {
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_navigation_polygon", get_current_tile(), Ref<NavigationPolygon>(), edited_shape_coord);
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_navigation_polygon", get_current_tile(), tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord), edited_shape_coord);
- }
- undo_redo->add_do_method(this, "_select_edited_shape_coord");
- undo_redo->add_undo_method(this, "_select_edited_shape_coord");
- undo_redo->commit_action();
- }
- } break;
- default: {
- }
- }
- }
- } else if (p_tool == TOOL_SELECT || p_tool == SHAPE_NEW_POLYGON || p_tool == SHAPE_NEW_RECTANGLE) {
- if (creating_shape) {
- // Cancel Creation
- creating_shape = false;
- current_shape.resize(0);
- workspace->update();
- }
- }
-}
-
-void TileSetEditor::_on_priority_changed(float val) {
- if ((int)val == tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord)) {
- return;
- }
-
- undo_redo->create_action(TTR("Edit Tile Priority"));
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_subtile_priority", get_current_tile(), edited_shape_coord, (int)val);
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_subtile_priority", get_current_tile(), edited_shape_coord, tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord));
- undo_redo->add_do_method(workspace, "update");
- undo_redo->add_undo_method(workspace, "update");
- undo_redo->commit_action();
-}
-
-void TileSetEditor::_on_z_index_changed(float val) {
- if ((int)val == tileset->autotile_get_z_index(get_current_tile(), edited_shape_coord)) {
- return;
- }
-
- undo_redo->create_action(TTR("Edit Tile Z Index"));
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_z_index", get_current_tile(), edited_shape_coord, (int)val);
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_z_index", get_current_tile(), edited_shape_coord, tileset->autotile_get_z_index(get_current_tile(), edited_shape_coord));
- undo_redo->add_do_method(workspace, "update");
- undo_redo->add_undo_method(workspace, "update");
- undo_redo->commit_action();
-}
-
-void TileSetEditor::_on_grid_snap_toggled(bool p_val) {
- helper->set_snap_options_visible(p_val);
- workspace->update();
-}
-
-Vector<Vector2> TileSetEditor::_get_collision_shape_points(const Ref<Shape2D> &p_shape) {
- Ref<ConvexPolygonShape2D> convex = p_shape;
- Ref<ConcavePolygonShape2D> concave = p_shape;
- if (convex.is_valid()) {
- return convex->get_points();
- } else if (concave.is_valid()) {
- Vector<Vector2> points;
- for (int i = 0; i < concave->get_segments().size(); i += 2) {
- points.push_back(concave->get_segments()[i]);
- }
- return points;
- } else {
- return Vector<Vector2>();
- }
-}
-
-Vector<Vector2> TileSetEditor::_get_edited_shape_points() {
- return _get_collision_shape_points(edited_collision_shape);
-}
-
-void TileSetEditor::_set_edited_shape_points(const Vector<Vector2> &points) {
- Ref<ConvexPolygonShape2D> convex = edited_collision_shape;
- Ref<ConcavePolygonShape2D> concave = edited_collision_shape;
- if (convex.is_valid()) {
- undo_redo->add_do_method(convex.ptr(), "set_points", points);
- undo_redo->add_undo_method(convex.ptr(), "set_points", _get_edited_shape_points());
- } else if (concave.is_valid() && points.size() > 1) {
- PackedVector2Array segments;
- for (int i = 0; i < points.size() - 1; i++) {
- segments.push_back(points[i]);
- segments.push_back(points[i + 1]);
- }
- segments.push_back(points[points.size() - 1]);
- segments.push_back(points[0]);
- undo_redo->add_do_method(concave.ptr(), "set_segments", segments);
- undo_redo->add_undo_method(concave.ptr(), "set_segments", concave->get_segments());
- }
-}
-
-void TileSetEditor::_update_tile_data() {
- current_tile_data.clear();
- if (get_current_tile() < 0) {
- return;
- }
-
- Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile());
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- SubtileData data;
- for (int i = 0; i < sd.size(); i++) {
- data.collisions.push_back(sd[i].shape);
- }
- data.navigation_shape = tileset->tile_get_navigation_polygon(get_current_tile());
- data.occlusion_shape = tileset->tile_get_light_occluder(get_current_tile());
- current_tile_data[Vector2i()] = data;
- } else {
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 size = tileset->tile_get_region(get_current_tile()).size;
- Vector2 cell_count = (size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing))).floor();
- for (int y = 0; y < cell_count.y; y++) {
- for (int x = 0; x < cell_count.x; x++) {
- SubtileData data;
- Vector2i coord(x, y);
- for (int i = 0; i < sd.size(); i++) {
- if (sd[i].autotile_coord == coord) {
- data.collisions.push_back(sd[i].shape);
- }
- }
- data.navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), coord);
- data.occlusion_shape = tileset->tile_get_light_occluder(get_current_tile());
- current_tile_data[coord] = data;
- }
- }
- }
-}
-
-void TileSetEditor::_update_toggle_shape_button() {
- Ref<ConvexPolygonShape2D> convex = edited_collision_shape;
- Ref<ConcavePolygonShape2D> concave = edited_collision_shape;
- separator_shape_toggle->show();
- tools[SHAPE_TOGGLE_TYPE]->show();
- if (edit_mode != EDITMODE_COLLISION || !edited_collision_shape.is_valid()) {
- separator_shape_toggle->hide();
- tools[SHAPE_TOGGLE_TYPE]->hide();
- } else if (concave.is_valid()) {
- 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_theme_icon("ConcavePolygonShape2D", "EditorIcons"));
- tools[SHAPE_TOGGLE_TYPE]->set_text(TTR("Make Concave"));
- } else {
- // Shouldn't happen
- separator_shape_toggle->hide();
- tools[SHAPE_TOGGLE_TYPE]->hide();
- }
-}
-
-void TileSetEditor::_select_next_tile() {
- Array tiles = _get_tiles_in_current_texture(true);
- if (tiles.size() == 0) {
- set_current_tile(-1);
- } else if (get_current_tile() == -1) {
- set_current_tile(tiles[0]);
- } else {
- int index = tiles.find(get_current_tile());
- if (index < 0) {
- set_current_tile(tiles[0]);
- } else if (index == tiles.size() - 1) {
- set_current_tile(tiles[0]);
- } else {
- set_current_tile(tiles[index + 1]);
- }
- }
- if (get_current_tile() == -1) {
- return;
- } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- return;
- } else {
- switch (edit_mode) {
- case EDITMODE_COLLISION:
- case EDITMODE_OCCLUSION:
- case EDITMODE_NAVIGATION:
- case EDITMODE_PRIORITY:
- case EDITMODE_Z_INDEX: {
- edited_shape_coord = Vector2();
- _select_edited_shape_coord();
- } break;
- default: {
- }
- }
- }
-}
-
-void TileSetEditor::_select_previous_tile() {
- Array tiles = _get_tiles_in_current_texture(true);
- if (tiles.size() == 0) {
- set_current_tile(-1);
- } else if (get_current_tile() == -1) {
- set_current_tile(tiles[tiles.size() - 1]);
- } else {
- int index = tiles.find(get_current_tile());
- if (index <= 0) {
- set_current_tile(tiles[tiles.size() - 1]);
- } else {
- set_current_tile(tiles[index - 1]);
- }
- }
- if (get_current_tile() == -1) {
- return;
- } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- return;
- } else {
- switch (edit_mode) {
- case EDITMODE_COLLISION:
- case EDITMODE_OCCLUSION:
- case EDITMODE_NAVIGATION:
- case EDITMODE_PRIORITY:
- case EDITMODE_Z_INDEX: {
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 size = tileset->tile_get_region(get_current_tile()).size;
- Vector2 cell_count = (size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing))).floor();
- cell_count -= Vector2(1, 1);
- edited_shape_coord = cell_count;
- _select_edited_shape_coord();
- } break;
- default: {
- }
- }
- }
-}
-
-Array TileSetEditor::_get_tiles_in_current_texture(bool sorted) {
- Array a;
- List<int> all_tiles;
- if (!get_current_texture().is_valid()) {
- return a;
- }
- tileset->get_tile_list(&all_tiles);
- for (int i = 0; i < all_tiles.size(); i++) {
- if (tileset->tile_get_texture(all_tiles[i]) == get_current_texture()) {
- a.push_back(all_tiles[i]);
- }
- }
- if (sorted) {
- a.sort_custom(callable_mp(this, &TileSetEditor::_sort_tiles));
- }
- return a;
-}
-
-bool TileSetEditor::_sort_tiles(Variant p_a, Variant p_b) {
- int a = p_a;
- int b = p_b;
-
- Vector2 pos_a = tileset->tile_get_region(a).position;
- Vector2 pos_b = tileset->tile_get_region(b).position;
- if (pos_a.y < pos_b.y) {
- return true;
-
- } else if (pos_a.y == pos_b.y) {
- return (pos_a.x < pos_b.x);
- } else {
- return false;
- }
-}
-
-void TileSetEditor::_select_next_subtile() {
- if (get_current_tile() == -1) {
- _select_next_tile();
- return;
- }
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- _select_next_tile();
- } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) {
- _select_next_tile();
- } else {
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 size = tileset->tile_get_region(get_current_tile()).size;
- Vector2 cell_count = (size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing))).floor();
- if (edited_shape_coord.x >= cell_count.x - 1 && edited_shape_coord.y >= cell_count.y - 1) {
- _select_next_tile();
- } else {
- edited_shape_coord.x++;
- if (edited_shape_coord.x >= cell_count.x) {
- edited_shape_coord.x = 0;
- edited_shape_coord.y++;
- }
- _select_edited_shape_coord();
- }
- }
-}
-
-void TileSetEditor::_select_previous_subtile() {
- if (get_current_tile() == -1) {
- _select_previous_tile();
- return;
- }
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- _select_previous_tile();
- } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) {
- _select_previous_tile();
- } else {
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 size = tileset->tile_get_region(get_current_tile()).size;
- Vector2 cell_count = (size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing))).floor();
- if (edited_shape_coord.x <= 0 && edited_shape_coord.y <= 0) {
- _select_previous_tile();
- } else {
- edited_shape_coord.x--;
- if (edited_shape_coord.x == -1) {
- edited_shape_coord.x = cell_count.x - 1;
- edited_shape_coord.y--;
- }
- _select_edited_shape_coord();
- }
- }
-}
-
-void TileSetEditor::_select_next_shape() {
- if (get_current_tile() == -1) {
- _select_next_subtile();
- } else if (edit_mode != EDITMODE_COLLISION) {
- _select_next_subtile();
- } else {
- Vector2i edited_coord = Vector2i();
- if (tileset->tile_get_tile_mode(get_current_tile()) != TileSet::SINGLE_TILE) {
- edited_coord = Vector2i(edited_shape_coord);
- }
- SubtileData data = current_tile_data[edited_coord];
- if (data.collisions.size() == 0) {
- _select_next_subtile();
- } else {
- int index = data.collisions.find(edited_collision_shape);
- if (index < 0) {
- _set_edited_collision_shape(data.collisions[0]);
- } else if (index == data.collisions.size() - 1) {
- _select_next_subtile();
- } else {
- _set_edited_collision_shape(data.collisions[index + 1]);
- }
- }
- current_shape.resize(0);
- Rect2 current_tile_region = tileset->tile_get_region(get_current_tile());
- current_tile_region.position += WORKSPACE_MARGIN;
-
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 size = tileset->autotile_get_size(get_current_tile());
- Vector2 shape_anchor = edited_shape_coord;
- shape_anchor.x *= (size.x + spacing);
- shape_anchor.y *= (size.y + spacing);
- current_tile_region.position += shape_anchor;
-
- if (edited_collision_shape.is_valid()) {
- for (int i = 0; i < _get_edited_shape_points().size(); i++) {
- current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position);
- }
- }
- workspace->update();
- workspace_container->update();
- helper->notify_property_list_changed();
- }
-}
-
-void TileSetEditor::_select_previous_shape() {
- if (get_current_tile() == -1) {
- _select_previous_subtile();
- if (get_current_tile() != -1 && edit_mode == EDITMODE_COLLISION) {
- SubtileData data = current_tile_data[Vector2i(edited_shape_coord)];
- if (data.collisions.size() > 1) {
- _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]);
- }
- } else {
- return;
- }
- } else if (edit_mode != EDITMODE_COLLISION) {
- _select_previous_subtile();
- } else {
- Vector2i edited_coord = Vector2i();
- if (tileset->tile_get_tile_mode(get_current_tile()) != TileSet::SINGLE_TILE) {
- edited_coord = Vector2i(edited_shape_coord);
- }
- SubtileData data = current_tile_data[edited_coord];
- if (data.collisions.size() == 0) {
- _select_previous_subtile();
- data = current_tile_data[Vector2i(edited_shape_coord)];
- if (data.collisions.size() > 1) {
- _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]);
- }
- } else {
- int index = data.collisions.find(edited_collision_shape);
- if (index < 0) {
- _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]);
- } else if (index == 0) {
- _select_previous_subtile();
- data = current_tile_data[Vector2i(edited_shape_coord)];
- if (data.collisions.size() > 1) {
- _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]);
- }
- } else {
- _set_edited_collision_shape(data.collisions[index - 1]);
- }
- }
-
- current_shape.resize(0);
- Rect2 current_tile_region = tileset->tile_get_region(get_current_tile());
- current_tile_region.position += WORKSPACE_MARGIN;
-
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 size = tileset->autotile_get_size(get_current_tile());
- Vector2 shape_anchor = edited_shape_coord;
- shape_anchor.x *= (size.x + spacing);
- shape_anchor.y *= (size.y + spacing);
- current_tile_region.position += shape_anchor;
-
- if (edited_collision_shape.is_valid()) {
- for (int i = 0; i < _get_edited_shape_points().size(); i++) {
- current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position);
- }
- }
- workspace->update();
- workspace_container->update();
- helper->notify_property_list_changed();
- }
-}
-
-void TileSetEditor::_set_edited_collision_shape(const Ref<Shape2D> &p_shape) {
- edited_collision_shape = p_shape;
- _update_toggle_shape_button();
-}
-
-void TileSetEditor::_set_snap_step(Vector2 p_val) {
- snap_step.x = CLAMP(p_val.x, 1, 256);
- snap_step.y = CLAMP(p_val.y, 1, 256);
- workspace->update();
-}
-
-void TileSetEditor::_set_snap_off(Vector2 p_val) {
- snap_offset.x = CLAMP(p_val.x, 0, 256 + WORKSPACE_MARGIN.x);
- snap_offset.y = CLAMP(p_val.y, 0, 256 + WORKSPACE_MARGIN.y);
- workspace->update();
-}
-
-void TileSetEditor::_set_snap_sep(Vector2 p_val) {
- snap_separation.x = CLAMP(p_val.x, 0, 256);
- snap_separation.y = CLAMP(p_val.y, 0, 256);
- workspace->update();
-}
-
-void TileSetEditor::_validate_current_tile_id() {
- if (get_current_tile() >= 0 && !tileset->has_tile(get_current_tile())) {
- set_current_tile(-1);
- }
-}
-
-void TileSetEditor::_select_edited_shape_coord() {
- select_coord(edited_shape_coord);
-}
-
-void TileSetEditor::_undo_tile_removal(int p_id) {
- undo_redo->add_undo_method(tileset.ptr(), "create_tile", p_id);
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_name", p_id, tileset->tile_get_name(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_texture_offset", p_id, tileset->tile_get_texture_offset(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_material", p_id, tileset->tile_get_material(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_modulate", p_id, tileset->tile_get_modulate(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_occluder_offset", p_id, tileset->tile_get_occluder_offset(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_navigation_polygon_offset", p_id, tileset->tile_get_navigation_polygon_offset(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_shape_offset", p_id, 0, tileset->tile_get_shape_offset(p_id, 0));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_shape_transform", p_id, 0, tileset->tile_get_shape_transform(p_id, 0));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_z_index", p_id, tileset->tile_get_z_index(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_texture", p_id, tileset->tile_get_texture(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_region", p_id, tileset->tile_get_region(p_id));
- // Necessary to get the version that returns a Array instead of a Vector.
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", p_id, tileset->call("tile_get_shapes", p_id));
- if (tileset->tile_get_tile_mode(p_id) == TileSet::SINGLE_TILE) {
- 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()) {
- 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()) {
- 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);
- for (Map<Vector2, uint32_t>::Element *E = bitmask_map.front(); E; E = E->next()) {
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", p_id, E->key(), E->value());
- }
- Map<Vector2, int> priority_map = tileset->autotile_get_priority_map(p_id);
- for (Map<Vector2, int>::Element *E = priority_map.front(); E; E = E->next()) {
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_subtile_priority", p_id, E->key(), E->value());
- }
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_icon_coordinate", p_id, tileset->autotile_get_icon_coordinate(p_id));
- Map<Vector2, int> z_map = tileset->autotile_get_z_index_map(p_id);
- for (Map<Vector2, int>::Element *E = z_map.front(); E; E = E->next()) {
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_z_index", p_id, E->key(), E->value());
- }
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_tile_mode", p_id, tileset->tile_get_tile_mode(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_size", p_id, tileset->autotile_get_size(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_spacing", p_id, tileset->autotile_get_spacing(p_id));
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask_mode", p_id, tileset->autotile_get_bitmask_mode(p_id));
- }
-}
-
-void TileSetEditor::_zoom_in() {
- float scale = workspace->get_scale().x;
- if (scale < max_scale) {
- scale *= scale_ratio;
- workspace->set_scale(Vector2(scale, scale));
- workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale);
- workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale);
- }
-}
-
-void TileSetEditor::_zoom_out() {
- float scale = workspace->get_scale().x;
- if (scale > min_scale) {
- scale /= scale_ratio;
- workspace->set_scale(Vector2(scale, scale));
- workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale);
- workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale);
- }
-}
-
-void TileSetEditor::_zoom_reset() {
- workspace->set_scale(Vector2(1, 1));
- workspace_container->set_custom_minimum_size(workspace->get_rect().size);
- workspace_overlay->set_custom_minimum_size(workspace->get_rect().size);
-}
-
-void TileSetEditor::draw_highlight_current_tile() {
- Color shadow_color = Color(0.3, 0.3, 0.3, 0.3);
- if ((workspace_mode == WORKSPACE_EDIT && get_current_tile() >= 0) || !edited_region.has_no_area()) {
- Rect2 region;
- if (edited_region.has_no_area()) {
- region = tileset->tile_get_region(get_current_tile());
- region.position += WORKSPACE_MARGIN;
- } else {
- region = edited_region;
- }
-
- if (region.position.y >= 0) {
- workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, region.position.y), shadow_color);
- }
- if (region.position.x >= 0) {
- workspace->draw_rect(Rect2(0, MAX(0, region.position.y), region.position.x, MIN(workspace->get_rect().size.y - region.position.y, MIN(region.size.y, region.position.y + region.size.y))), shadow_color);
- }
- if (region.position.x + region.size.x <= workspace->get_rect().size.x) {
- workspace->draw_rect(Rect2(region.position.x + region.size.x, MAX(0, region.position.y), workspace->get_rect().size.x - region.position.x - region.size.x, MIN(workspace->get_rect().size.y - region.position.y, MIN(region.size.y, region.position.y + region.size.y))), shadow_color);
- }
- if (region.position.y + region.size.y <= workspace->get_rect().size.y) {
- workspace->draw_rect(Rect2(0, region.position.y + region.size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - region.size.y - region.position.y), shadow_color);
- }
- } else {
- workspace->draw_rect(Rect2(Point2(0, 0), workspace->get_rect().size), shadow_color);
- }
-}
-
-void TileSetEditor::draw_highlight_subtile(Vector2 coord, const Vector<Vector2> &other_highlighted) {
- Color shadow_color = Color(0.3, 0.3, 0.3, 0.3);
- Vector2 size = tileset->autotile_get_size(get_current_tile());
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Rect2 region = tileset->tile_get_region(get_current_tile());
- coord.x *= (size.x + spacing);
- coord.y *= (size.y + spacing);
- coord += region.position;
- coord += WORKSPACE_MARGIN;
-
- if (coord.y >= 0) {
- workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, coord.y), shadow_color);
- }
- if (coord.x >= 0) {
- workspace->draw_rect(Rect2(0, MAX(0, coord.y), coord.x, MIN(workspace->get_rect().size.y - coord.y, MIN(size.y, coord.y + size.y))), shadow_color);
- }
- if (coord.x + size.x <= workspace->get_rect().size.x) {
- workspace->draw_rect(Rect2(coord.x + size.x, MAX(0, coord.y), workspace->get_rect().size.x - coord.x - size.x, MIN(workspace->get_rect().size.y - coord.y, MIN(size.y, coord.y + size.y))), shadow_color);
- }
- if (coord.y + size.y <= workspace->get_rect().size.y) {
- workspace->draw_rect(Rect2(0, coord.y + size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - size.y - coord.y), shadow_color);
- }
-
- coord += Vector2(1, 1) / workspace->get_scale().x;
- workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0, 0), false);
- for (int i = 0; i < other_highlighted.size(); i++) {
- coord = other_highlighted[i];
- coord.x *= (size.x + spacing);
- coord.y *= (size.y + spacing);
- coord += region.position;
- coord += WORKSPACE_MARGIN;
- coord += Vector2(1, 1) / workspace->get_scale().x;
- workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0.5, 0.5), false);
- }
-}
-
-void TileSetEditor::draw_tile_subdivision(int p_id, Color p_color) const {
- Color c = p_color;
- if (tileset->tile_get_tile_mode(p_id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(p_id) == TileSet::ATLAS_TILE) {
- Rect2 region = tileset->tile_get_region(p_id);
- Size2 size = tileset->autotile_get_size(p_id);
- int spacing = tileset->autotile_get_spacing(p_id);
- float j = size.x;
-
- while (j < region.size.x) {
- if (spacing <= 0) {
- workspace->draw_line(region.position + WORKSPACE_MARGIN + Point2(j, 0), region.position + WORKSPACE_MARGIN + Point2(j, region.size.y), c);
- } else {
- workspace->draw_rect(Rect2(region.position + WORKSPACE_MARGIN + Point2(j, 0), Size2(spacing, region.size.y)), c);
- }
- j += spacing + size.x;
- }
- j = size.y;
- while (j < region.size.y) {
- if (spacing <= 0) {
- workspace->draw_line(region.position + WORKSPACE_MARGIN + Point2(0, j), region.position + WORKSPACE_MARGIN + Point2(region.size.x, j), c);
- } else {
- workspace->draw_rect(Rect2(region.position + WORKSPACE_MARGIN + Point2(0, j), Size2(region.size.x, spacing)), c);
- }
- j += spacing + size.y;
- }
- }
-}
-
-void TileSetEditor::draw_edited_region_subdivision() const {
- Color c = Color(0.3, 0.7, 0.6);
- Rect2 region = edited_region;
- Size2 size;
- int spacing;
- bool draw;
-
- if (workspace_mode == WORKSPACE_EDIT) {
- int p_id = get_current_tile();
- size = tileset->autotile_get_size(p_id);
- spacing = tileset->autotile_get_spacing(p_id);
- draw = tileset->tile_get_tile_mode(p_id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(p_id) == TileSet::ATLAS_TILE;
- } else {
- size = snap_step;
- spacing = snap_separation.x;
- draw = workspace_mode != WORKSPACE_CREATE_SINGLE;
- }
-
- if (draw) {
- float j = size.x;
- while (j < region.size.x) {
- if (spacing <= 0) {
- workspace->draw_line(region.position + Point2(j, 0), region.position + Point2(j, region.size.y), c);
- } else {
- workspace->draw_rect(Rect2(region.position + Point2(j, 0), Size2(spacing, region.size.y)), c);
- }
- j += spacing + size.x;
- }
- j = size.y;
- while (j < region.size.y) {
- if (spacing <= 0) {
- workspace->draw_line(region.position + Point2(0, j), region.position + Point2(region.size.x, j), c);
- } else {
- workspace->draw_rect(Rect2(region.position + Point2(0, j), Size2(region.size.x, spacing)), c);
- }
- j += spacing + size.y;
- }
- }
-}
-
-void TileSetEditor::draw_grid_snap() {
- if (tools[TOOL_GRID_SNAP]->is_pressed()) {
- Color grid_color = Color(0.4, 0, 1);
- Size2 s = workspace->get_size();
-
- int width_count = Math::floor((s.width - WORKSPACE_MARGIN.x) / (snap_step.x + snap_separation.x));
- int height_count = Math::floor((s.height - WORKSPACE_MARGIN.y) / (snap_step.y + snap_separation.y));
-
- int last_p = 0;
- if (snap_step.x != 0) {
- for (int i = 0; i <= width_count; i++) {
- if (i == 0 && snap_offset.x != 0) {
- last_p = snap_offset.x;
- }
- if (snap_separation.x != 0) {
- if (i != 0) {
- workspace->draw_rect(Rect2(last_p, 0, snap_separation.x, s.height), grid_color);
- last_p += snap_separation.x;
- } else {
- workspace->draw_rect(Rect2(last_p, 0, -snap_separation.x, s.height), grid_color);
- }
- } else {
- workspace->draw_line(Point2(last_p, 0), Point2(last_p, s.height), grid_color);
- }
- last_p += snap_step.x;
- }
- }
- last_p = 0;
- if (snap_step.y != 0) {
- for (int i = 0; i <= height_count; i++) {
- if (i == 0 && snap_offset.y != 0) {
- last_p = snap_offset.y;
- }
- if (snap_separation.y != 0) {
- if (i != 0) {
- workspace->draw_rect(Rect2(0, last_p, s.width, snap_separation.y), grid_color);
- last_p += snap_separation.y;
- } else {
- workspace->draw_rect(Rect2(0, last_p, s.width, -snap_separation.y), grid_color);
- }
- } else {
- workspace->draw_line(Point2(0, last_p), Point2(s.width, last_p), grid_color);
- }
- last_p += snap_step.y;
- }
- }
- }
-}
-
-void TileSetEditor::draw_polygon_shapes() {
- int t_id = get_current_tile();
- if (t_id < 0) {
- return;
- }
-
- switch (edit_mode) {
- case EDITMODE_COLLISION: {
- Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id);
- for (int i = 0; i < sd.size(); i++) {
- Vector2 coord = Vector2(0, 0);
- Vector2 anchor = Vector2(0, 0);
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
- coord = sd[i].autotile_coord;
- anchor = tileset->autotile_get_size(t_id);
- anchor.x += tileset->autotile_get_spacing(t_id);
- anchor.y += tileset->autotile_get_spacing(t_id);
- anchor.x *= coord.x;
- anchor.y *= coord.y;
- }
- anchor += WORKSPACE_MARGIN;
- anchor += tileset->tile_get_region(t_id).position;
- Ref<Shape2D> shape = sd[i].shape;
- if (shape.is_valid()) {
- Color c_bg;
- Color c_border;
- Ref<ConvexPolygonShape2D> convex = shape;
- bool is_convex = convex.is_valid();
- if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || coord == edited_shape_coord) && sd[i].shape == edited_collision_shape) {
- if (is_convex) {
- c_bg = Color(0, 1, 1, 0.5);
- c_border = Color(0, 1, 1);
- } else {
- c_bg = Color(0.8, 0, 1, 0.5);
- c_border = Color(0.8, 0, 1);
- }
- } else {
- if (is_convex) {
- c_bg = Color(0.9, 0.7, 0.07, 0.5);
- c_border = Color(0.9, 0.7, 0.07, 1);
-
- } else {
- c_bg = Color(0.9, 0.45, 0.075, 0.5);
- c_border = Color(0.9, 0.45, 0.075);
- }
- }
- Vector<Vector2> polygon;
- Vector<Color> colors;
- if (!creating_shape && shape == edited_collision_shape && current_shape.size() > 2) {
- for (int j = 0; j < current_shape.size(); j++) {
- polygon.push_back(current_shape[j]);
- colors.push_back(c_bg);
- }
- } else {
- for (int j = 0; j < _get_collision_shape_points(shape).size(); j++) {
- polygon.push_back(_get_collision_shape_points(shape)[j] + anchor);
- colors.push_back(c_bg);
- }
- }
-
- if (polygon.size() < 3) {
- continue;
- }
-
- workspace->draw_polygon(polygon, colors);
-
- if (coord == edited_shape_coord || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- if (!creating_shape && polygon.size() > 1) {
- for (int j = 0; j < polygon.size() - 1; j++) {
- workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1);
- }
- workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1);
- }
- if (shape == edited_collision_shape) {
- draw_handles = true;
- }
- }
- }
- }
- } break;
- case EDITMODE_OCCLUSION: {
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- Ref<OccluderPolygon2D> shape = edited_occlusion_shape;
- if (shape.is_valid()) {
- Color c_bg = Color(0, 1, 1, 0.5);
- Color c_border = Color(0, 1, 1);
-
- Vector<Vector2> polygon;
- Vector<Color> colors;
- Vector2 anchor = WORKSPACE_MARGIN;
- anchor += tileset->tile_get_region(get_current_tile()).position;
- if (!creating_shape && shape == edited_occlusion_shape && current_shape.size() > 2) {
- for (int j = 0; j < current_shape.size(); j++) {
- polygon.push_back(current_shape[j]);
- colors.push_back(c_bg);
- }
- } else {
- for (int j = 0; j < shape->get_polygon().size(); j++) {
- polygon.push_back(shape->get_polygon()[j] + anchor);
- colors.push_back(c_bg);
- }
- }
- workspace->draw_polygon(polygon, colors);
-
- if (!creating_shape && polygon.size() > 1) {
- for (int j = 0; j < polygon.size() - 1; j++) {
- workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1);
- }
- workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1);
- }
- if (shape == edited_occlusion_shape) {
- draw_handles = true;
- }
- }
- } 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()) {
- Vector2 coord = E->key();
- Vector2 anchor = tileset->autotile_get_size(t_id);
- anchor.x += tileset->autotile_get_spacing(t_id);
- anchor.y += tileset->autotile_get_spacing(t_id);
- anchor.x *= coord.x;
- anchor.y *= coord.y;
- anchor += WORKSPACE_MARGIN;
- anchor += tileset->tile_get_region(t_id).position;
- Ref<OccluderPolygon2D> shape = E->value();
- if (shape.is_valid()) {
- Color c_bg;
- Color c_border;
- if (coord == edited_shape_coord && shape == edited_occlusion_shape) {
- c_bg = Color(0, 1, 1, 0.5);
- c_border = Color(0, 1, 1);
- } else {
- c_bg = Color(0.9, 0.7, 0.07, 0.5);
- c_border = Color(0.9, 0.7, 0.07, 1);
- }
- Vector<Vector2> polygon;
- Vector<Color> colors;
- if (!creating_shape && shape == edited_occlusion_shape && current_shape.size() > 2) {
- for (int j = 0; j < current_shape.size(); j++) {
- polygon.push_back(current_shape[j]);
- colors.push_back(c_bg);
- }
- } else {
- for (int j = 0; j < shape->get_polygon().size(); j++) {
- polygon.push_back(shape->get_polygon()[j] + anchor);
- colors.push_back(c_bg);
- }
- }
- workspace->draw_polygon(polygon, colors);
-
- if (coord == edited_shape_coord) {
- if (!creating_shape && polygon.size() > 1) {
- for (int j = 0; j < polygon.size() - 1; j++) {
- workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1);
- }
- workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1);
- }
- if (shape == edited_occlusion_shape) {
- draw_handles = true;
- }
- }
- }
- }
- }
- } break;
- case EDITMODE_NAVIGATION: {
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- Ref<NavigationPolygon> shape = edited_navigation_shape;
-
- if (shape.is_valid()) {
- Color c_bg = Color(0, 1, 1, 0.5);
- Color c_border = Color(0, 1, 1);
-
- Vector<Vector2> polygon;
- Vector<Color> colors;
- Vector2 anchor = WORKSPACE_MARGIN;
- anchor += tileset->tile_get_region(get_current_tile()).position;
- if (!creating_shape && shape == edited_navigation_shape && current_shape.size() > 2) {
- for (int j = 0; j < current_shape.size(); j++) {
- polygon.push_back(current_shape[j]);
- colors.push_back(c_bg);
- }
- } else {
- Vector<Vector2> vertices = shape->get_vertices();
- for (int j = 0; j < shape->get_polygon(0).size(); j++) {
- polygon.push_back(vertices[shape->get_polygon(0)[j]] + anchor);
- colors.push_back(c_bg);
- }
- }
- workspace->draw_polygon(polygon, colors);
-
- if (!creating_shape && polygon.size() > 1) {
- for (int j = 0; j < polygon.size() - 1; j++) {
- workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1);
- }
- workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1);
- }
- if (shape == edited_navigation_shape) {
- draw_handles = true;
- }
- }
- } 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()) {
- Vector2 coord = E->key();
- Vector2 anchor = tileset->autotile_get_size(t_id);
- anchor.x += tileset->autotile_get_spacing(t_id);
- anchor.y += tileset->autotile_get_spacing(t_id);
- anchor.x *= coord.x;
- anchor.y *= coord.y;
- anchor += WORKSPACE_MARGIN;
- anchor += tileset->tile_get_region(t_id).position;
- Ref<NavigationPolygon> shape = E->value();
- if (shape.is_valid()) {
- Color c_bg;
- Color c_border;
- if (coord == edited_shape_coord && shape == edited_navigation_shape) {
- c_bg = Color(0, 1, 1, 0.5);
- c_border = Color(0, 1, 1);
- } else {
- c_bg = Color(0.9, 0.7, 0.07, 0.5);
- c_border = Color(0.9, 0.7, 0.07, 1);
- }
- Vector<Vector2> polygon;
- Vector<Color> colors;
- if (!creating_shape && shape == edited_navigation_shape && current_shape.size() > 2) {
- for (int j = 0; j < current_shape.size(); j++) {
- polygon.push_back(current_shape[j]);
- colors.push_back(c_bg);
- }
- } else {
- Vector<Vector2> vertices = shape->get_vertices();
- for (int j = 0; j < shape->get_polygon(0).size(); j++) {
- polygon.push_back(vertices[shape->get_polygon(0)[j]] + anchor);
- colors.push_back(c_bg);
- }
- }
- workspace->draw_polygon(polygon, colors);
-
- if (coord == edited_shape_coord) {
- if (!creating_shape && polygon.size() > 1) {
- for (int j = 0; j < polygon.size() - 1; j++) {
- workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1);
- }
- workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1);
- }
- if (shape == edited_navigation_shape) {
- draw_handles = true;
- }
- }
- }
- }
- }
- } break;
- default: {
- }
- }
-
- if (creating_shape && current_shape.size() > 1) {
- for (int j = 0; j < current_shape.size() - 1; j++) {
- workspace->draw_line(current_shape[j], current_shape[j + 1], Color(0, 1, 1), 1);
- }
- workspace->draw_line(current_shape[current_shape.size() - 1], snap_point(workspace->get_local_mouse_position()), Color(0, 1, 1), 1);
- draw_handles = true;
- }
-}
-
-void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
- creating_shape = false;
-
- if (edit_mode == EDITMODE_COLLISION) {
- if (current_shape.size() >= 3) {
- Ref<ConvexPolygonShape2D> shape = memnew(ConvexPolygonShape2D);
-
- Vector<Vector2> points;
- float p_total = 0;
-
- for (int i = 0; i < current_shape.size(); i++) {
- points.push_back(current_shape[i] - shape_anchor);
-
- if (i != current_shape.size() - 1) {
- p_total += ((current_shape[i + 1].x - current_shape[i].x) * (-current_shape[i + 1].y + (-current_shape[i].y)));
- } else {
- p_total += ((current_shape[0].x - current_shape[i].x) * (-current_shape[0].y + (-current_shape[i].y)));
- }
- }
-
- if (p_total < 0) {
- points.reverse();
- }
-
- shape->set_points(points);
-
- undo_redo->create_action(TTR("Create Collision Polygon"));
- // Necessary to get the version that returns a Array instead of a Vector.
- Array sd = tileset->call("tile_get_shapes", get_current_tile());
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd.duplicate());
- for (int i = 0; i < sd.size(); i++) {
- if (sd[i].get("shape") == edited_collision_shape) {
- sd.remove(i);
- break;
- }
- }
- undo_redo->add_do_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd);
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
- undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), shape, Transform2D(), false, edited_shape_coord);
- } else {
- undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), shape, Transform2D());
- }
- tools[TOOL_SELECT]->set_pressed(true);
- undo_redo->add_do_method(this, "_select_edited_shape_coord");
- undo_redo->add_undo_method(this, "_select_edited_shape_coord");
- undo_redo->commit_action();
- } else {
- tools[TOOL_SELECT]->set_pressed(true);
- workspace->update();
- }
- } else if (edit_mode == EDITMODE_OCCLUSION) {
- Ref<OccluderPolygon2D> shape = memnew(OccluderPolygon2D);
-
- Vector<Vector2> polygon;
- polygon.resize(current_shape.size());
- Vector2 *w = polygon.ptrw();
-
- for (int i = 0; i < current_shape.size(); i++) {
- w[i] = current_shape[i] - shape_anchor;
- }
-
- shape->set_polygon(polygon);
-
- undo_redo->create_action(TTR("Create Occlusion Polygon"));
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_light_occluder", get_current_tile(), shape, edited_shape_coord);
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_light_occluder", get_current_tile(), tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord), edited_shape_coord);
- } else {
- undo_redo->add_do_method(tileset.ptr(), "tile_set_light_occluder", get_current_tile(), shape);
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_light_occluder", get_current_tile(), tileset->tile_get_light_occluder(get_current_tile()));
- }
- tools[TOOL_SELECT]->set_pressed(true);
- undo_redo->add_do_method(this, "_select_edited_shape_coord");
- undo_redo->add_undo_method(this, "_select_edited_shape_coord");
- undo_redo->commit_action();
- } else if (edit_mode == EDITMODE_NAVIGATION) {
- Ref<NavigationPolygon> shape = memnew(NavigationPolygon);
-
- Vector<Vector2> polygon;
- Vector<int> indices;
- polygon.resize(current_shape.size());
- Vector2 *w = polygon.ptrw();
-
- for (int i = 0; i < current_shape.size(); i++) {
- w[i] = current_shape[i] - shape_anchor;
- indices.push_back(i);
- }
-
- shape->set_vertices(polygon);
- shape->add_polygon(indices);
-
- undo_redo->create_action(TTR("Create Navigation Polygon"));
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
- undo_redo->add_do_method(tileset.ptr(), "autotile_set_navigation_polygon", get_current_tile(), shape, edited_shape_coord);
- undo_redo->add_undo_method(tileset.ptr(), "autotile_set_navigation_polygon", get_current_tile(), tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord), edited_shape_coord);
- } else {
- undo_redo->add_do_method(tileset.ptr(), "tile_set_navigation_polygon", get_current_tile(), shape);
- undo_redo->add_undo_method(tileset.ptr(), "tile_set_navigation_polygon", get_current_tile(), tileset->tile_get_navigation_polygon(get_current_tile()));
- }
- tools[TOOL_SELECT]->set_pressed(true);
- undo_redo->add_do_method(this, "_select_edited_shape_coord");
- undo_redo->add_undo_method(this, "_select_edited_shape_coord");
- undo_redo->commit_action();
- }
- tileset->notify_property_list_changed();
-}
-
-void TileSetEditor::select_coord(const Vector2 &coord) {
- _update_tile_data();
- current_shape = PackedVector2Array();
- if (get_current_tile() == -1) {
- return;
- }
- Rect2 current_tile_region = tileset->tile_get_region(get_current_tile());
- current_tile_region.position += WORKSPACE_MARGIN;
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- if (edited_collision_shape != tileset->tile_get_shape(get_current_tile(), 0)) {
- _set_edited_collision_shape(tileset->tile_get_shape(get_current_tile(), 0));
- }
- if (edited_occlusion_shape != tileset->tile_get_light_occluder(get_current_tile())) {
- edited_occlusion_shape = tileset->tile_get_light_occluder(get_current_tile());
- }
- if (edited_navigation_shape != tileset->tile_get_navigation_polygon(get_current_tile())) {
- edited_navigation_shape = tileset->tile_get_navigation_polygon(get_current_tile());
- }
-
- if (edit_mode == EDITMODE_COLLISION) {
- current_shape.resize(0);
- if (edited_collision_shape.is_valid()) {
- for (int i = 0; i < _get_edited_shape_points().size(); i++) {
- current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position);
- }
- }
- } else if (edit_mode == EDITMODE_OCCLUSION) {
- current_shape.resize(0);
- if (edited_occlusion_shape.is_valid()) {
- for (int i = 0; i < edited_occlusion_shape->get_polygon().size(); i++) {
- current_shape.push_back(edited_occlusion_shape->get_polygon()[i] + current_tile_region.position);
- }
- }
- } else if (edit_mode == EDITMODE_NAVIGATION) {
- current_shape.resize(0);
- if (edited_navigation_shape.is_valid()) {
- if (edited_navigation_shape->get_polygon_count() > 0) {
- Vector<Vector2> vertices = edited_navigation_shape->get_vertices();
- for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) {
- current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + current_tile_region.position);
- }
- }
- }
- }
- } else {
- Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile());
- bool found_collision_shape = false;
- for (int i = 0; i < sd.size(); i++) {
- if (sd[i].autotile_coord == coord) {
- if (edited_collision_shape != sd[i].shape) {
- _set_edited_collision_shape(sd[i].shape);
- }
- found_collision_shape = true;
- break;
- }
- }
- if (!found_collision_shape) {
- _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)) {
- edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), coord);
- }
-
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 size = tileset->autotile_get_size(get_current_tile());
- Vector2 shape_anchor = coord;
- shape_anchor.x *= (size.x + spacing);
- shape_anchor.y *= (size.y + spacing);
- shape_anchor += current_tile_region.position;
- if (edit_mode == EDITMODE_COLLISION) {
- current_shape.resize(0);
- if (edited_collision_shape.is_valid()) {
- for (int j = 0; j < _get_edited_shape_points().size(); j++) {
- current_shape.push_back(_get_edited_shape_points()[j] + shape_anchor);
- }
- }
- } else if (edit_mode == EDITMODE_OCCLUSION) {
- current_shape.resize(0);
- if (edited_occlusion_shape.is_valid()) {
- for (int i = 0; i < edited_occlusion_shape->get_polygon().size(); i++) {
- current_shape.push_back(edited_occlusion_shape->get_polygon()[i] + shape_anchor);
- }
- }
- } else if (edit_mode == EDITMODE_NAVIGATION) {
- current_shape.resize(0);
- if (edited_navigation_shape.is_valid()) {
- if (edited_navigation_shape->get_polygon_count() > 0) {
- Vector<Vector2> vertices = edited_navigation_shape->get_vertices();
- for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) {
- current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + shape_anchor);
- }
- }
- }
- }
- }
- workspace->update();
- workspace_container->update();
- helper->notify_property_list_changed();
-}
-
-Vector2 TileSetEditor::snap_point(const Vector2 &point) {
- Vector2 p = point;
- Vector2 coord = edited_shape_coord;
- Vector2 tile_size = tileset->autotile_get_size(get_current_tile());
- int spacing = tileset->autotile_get_spacing(get_current_tile());
- Vector2 anchor = coord;
- anchor.x *= (tile_size.x + spacing);
- anchor.y *= (tile_size.y + spacing);
- anchor += tileset->tile_get_region(get_current_tile()).position;
- anchor += WORKSPACE_MARGIN;
- Rect2 region(anchor, tile_size);
- Rect2 tile_region(tileset->tile_get_region(get_current_tile()).position + WORKSPACE_MARGIN, tileset->tile_get_region(get_current_tile()).size);
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- region.position = tileset->tile_get_region(get_current_tile()).position + WORKSPACE_MARGIN;
- region.size = tileset->tile_get_region(get_current_tile()).size;
- }
-
- if (tools[TOOL_GRID_SNAP]->is_pressed()) {
- p.x = Math::snap_scalar_separation(snap_offset.x, snap_step.x, p.x, snap_separation.x);
- p.y = Math::snap_scalar_separation(snap_offset.y, snap_step.y, p.y, snap_separation.y);
- }
-
- if (tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) {
- if (p.x < region.position.x) {
- p.x = region.position.x;
- }
- if (p.y < region.position.y) {
- p.y = region.position.y;
- }
- if (p.x > region.position.x + region.size.x) {
- p.x = region.position.x + region.size.x;
- }
- if (p.y > region.position.y + region.size.y) {
- p.y = region.position.y + region.size.y;
- }
- }
-
- if (p.x < tile_region.position.x) {
- p.x = tile_region.position.x;
- }
- if (p.y < tile_region.position.y) {
- p.y = tile_region.position.y;
- }
- if (p.x > (tile_region.position.x + tile_region.size.x)) {
- p.x = (tile_region.position.x + tile_region.size.x);
- }
- if (p.y > (tile_region.position.y + tile_region.size.y)) {
- p.y = (tile_region.position.y + tile_region.size.y);
- }
-
- return p;
-}
-
-void TileSetEditor::add_texture(Ref<Texture2D> p_texture) {
- texture_list->add_item(p_texture->get_path().get_file());
- texture_map.insert(p_texture->get_rid(), p_texture);
- texture_list->set_item_metadata(texture_list->get_item_count() - 1, p_texture->get_rid());
-}
-
-void TileSetEditor::remove_texture(Ref<Texture2D> p_texture) {
- texture_list->remove_item(texture_list->find_metadata(p_texture->get_rid()));
- texture_map.erase(p_texture->get_rid());
-
- _validate_current_tile_id();
-
- if (!get_current_texture().is_valid()) {
- _on_texture_list_selected(-1);
- workspace_overlay->update();
- }
-}
-
-void TileSetEditor::update_texture_list() {
- Ref<Texture2D> selected_texture = get_current_texture();
-
- helper->set_tileset(tileset);
-
- List<int> ids;
- tileset->get_tile_list(&ids);
- Vector<int> ids_to_remove;
- for (List<int>::Element *E = ids.front(); E; E = E->next()) {
- // Clear tiles referencing gone textures (user has been already given the chance to fix broken deps)
- if (!tileset->tile_get_texture(E->get()).is_valid()) {
- ids_to_remove.push_back(E->get());
- ERR_CONTINUE(!tileset->tile_get_texture(E->get()).is_valid());
- }
-
- if (!texture_map.has(tileset->tile_get_texture(E->get())->get_rid())) {
- add_texture(tileset->tile_get_texture(E->get()));
- }
- }
- for (int i = 0; i < ids_to_remove.size(); i++) {
- tileset->remove_tile(ids_to_remove[i]);
- }
-
- if (texture_list->get_item_count() > 0 && selected_texture.is_valid()) {
- texture_list->select(texture_list->find_metadata(selected_texture->get_rid()));
- if (texture_list->get_selected_items().size() > 0) {
- _on_texture_list_selected(texture_list->get_selected_items()[0]);
- }
- } else if (get_current_texture().is_valid()) {
- _on_texture_list_selected(texture_list->find_metadata(get_current_texture()->get_rid()));
- } else {
- _validate_current_tile_id();
- _on_texture_list_selected(-1);
- workspace_overlay->update();
- }
- update_texture_list_icon();
- helper->notify_property_list_changed();
-}
-
-void TileSetEditor::update_texture_list_icon() {
- for (int current_idx = 0; current_idx < texture_list->get_item_count(); current_idx++) {
- RID rid = texture_list->get_item_metadata(current_idx);
- texture_list->set_item_icon(current_idx, texture_map[rid]);
- Size2 texture_size = texture_map[rid]->get_size();
- texture_list->set_item_icon_region(current_idx, Rect2(0, 0, MIN(texture_size.x, 150), MIN(texture_size.y, 100)));
- }
- texture_list->update();
-}
-
-void TileSetEditor::update_workspace_tile_mode() {
- if (!get_current_texture().is_valid()) {
- tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true);
- workspace_mode = WORKSPACE_EDIT;
- for (int i = 1; i < WORKSPACE_MODE_MAX; i++) {
- tool_workspacemode[i]->set_disabled(true);
- }
- tools[SELECT_NEXT]->set_disabled(true);
- tools[SELECT_PREVIOUS]->set_disabled(true);
-
- tools[ZOOM_OUT]->hide();
- tools[ZOOM_1]->hide();
- tools[ZOOM_IN]->hide();
- tools[VISIBLE_INFO]->hide();
-
- scroll->hide();
- empty_message->show();
- } else {
- for (int i = 1; i < WORKSPACE_MODE_MAX; i++) {
- tool_workspacemode[i]->set_disabled(false);
- }
- tools[SELECT_NEXT]->set_disabled(false);
- tools[SELECT_PREVIOUS]->set_disabled(false);
-
- tools[ZOOM_OUT]->show();
- tools[ZOOM_1]->show();
- tools[ZOOM_IN]->show();
- tools[VISIBLE_INFO]->show();
-
- scroll->show();
- empty_message->hide();
- }
-
- if (workspace_mode != WORKSPACE_EDIT) {
- for (int i = 0; i < EDITMODE_MAX; i++) {
- tool_editmode[i]->hide();
- }
- tool_editmode[EDITMODE_REGION]->show();
- tool_editmode[EDITMODE_REGION]->set_pressed(true);
- _on_edit_mode_changed(EDITMODE_REGION);
- separator_editmode->show();
- return;
- }
-
- if (get_current_tile() < 0) {
- for (int i = 0; i < EDITMODE_MAX; i++) {
- tool_editmode[i]->hide();
- }
- for (int i = TOOL_SELECT; i < ZOOM_OUT; i++) {
- tools[i]->hide();
- }
-
- separator_editmode->hide();
- separator_bitmask->hide();
- separator_delete->hide();
- separator_grid->hide();
- return;
- }
-
- for (int i = 0; i < EDITMODE_MAX; i++) {
- tool_editmode[i]->show();
- }
- separator_editmode->show();
-
- if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
- if (tool_editmode[EDITMODE_ICON]->is_pressed() || tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed() || tool_editmode[EDITMODE_Z_INDEX]->is_pressed()) {
- tool_editmode[EDITMODE_COLLISION]->set_pressed(true);
- edit_mode = EDITMODE_COLLISION;
- }
- select_coord(Vector2(0, 0));
-
- tool_editmode[EDITMODE_ICON]->hide();
- tool_editmode[EDITMODE_BITMASK]->hide();
- tool_editmode[EDITMODE_PRIORITY]->hide();
- tool_editmode[EDITMODE_Z_INDEX]->hide();
- } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) {
- if (edit_mode == EDITMODE_ICON) {
- select_coord(tileset->autotile_get_icon_coordinate(get_current_tile()));
- } else {
- _select_edited_shape_coord();
- }
- } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) {
- if (tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) {
- tool_editmode[EDITMODE_COLLISION]->set_pressed(true);
- edit_mode = EDITMODE_COLLISION;
- }
- if (edit_mode == EDITMODE_ICON) {
- select_coord(tileset->autotile_get_icon_coordinate(get_current_tile()));
- } else {
- _select_edited_shape_coord();
- }
-
- tool_editmode[EDITMODE_BITMASK]->hide();
- }
- _on_edit_mode_changed(edit_mode);
-}
-
-void TileSetEditor::update_workspace_minsize() {
- Size2 workspace_min_size = get_current_texture()->get_size();
- RID current_texture_rid = get_current_texture()->get_rid();
- List<int> *tiles = new List<int>();
- tileset->get_tile_list(tiles);
- for (List<int>::Element *E = tiles->front(); E; E = E->next()) {
- if (tileset->tile_get_texture(E->get())->get_rid() != current_texture_rid) {
- continue;
- }
-
- Rect2i region = tileset->tile_get_region(E->get());
- if (region.position.x + region.size.x > workspace_min_size.x) {
- workspace_min_size.x = region.position.x + region.size.x;
- }
- if (region.position.y + region.size.y > workspace_min_size.y) {
- workspace_min_size.y = region.position.y + region.size.y;
- }
- }
- delete tiles;
-
- workspace->set_custom_minimum_size(workspace_min_size + WORKSPACE_MARGIN * 2);
- workspace_container->set_custom_minimum_size(workspace_min_size * workspace->get_scale() + WORKSPACE_MARGIN * 2);
- workspace_overlay->set_custom_minimum_size(workspace_min_size * workspace->get_scale() + WORKSPACE_MARGIN * 2);
-}
-
-void TileSetEditor::update_edited_region(const Vector2 &end_point) {
- edited_region = Rect2(region_from, Size2());
- if (tools[TOOL_GRID_SNAP]->is_pressed()) {
- Vector2 grid_coord;
- grid_coord = ((region_from - snap_offset) / (snap_step + snap_separation)).floor();
- grid_coord *= (snap_step + snap_separation);
- grid_coord += snap_offset;
- edited_region.expand_to(grid_coord);
- grid_coord += snap_step;
- edited_region.expand_to(grid_coord);
-
- grid_coord = ((end_point - snap_offset) / (snap_step + snap_separation)).floor();
- grid_coord *= (snap_step + snap_separation);
- grid_coord += snap_offset;
- edited_region.expand_to(grid_coord);
- grid_coord += snap_step;
- edited_region.expand_to(grid_coord);
- } else {
- edited_region.expand_to(end_point);
- }
-}
-
-int TileSetEditor::get_current_tile() const {
- return current_tile;
-}
-
-void TileSetEditor::set_current_tile(int p_id) {
- if (current_tile != p_id) {
- current_tile = p_id;
- helper->notify_property_list_changed();
- select_coord(Vector2(0, 0));
- update_workspace_tile_mode();
- if (p_id == -1) {
- editor->get_inspector()->edit(tileset.ptr());
- } else {
- editor->get_inspector()->edit(helper);
- }
- }
-}
-
-Ref<Texture2D> TileSetEditor::get_current_texture() {
- if (texture_list->get_selected_items().size() == 0) {
- return Ref<Texture2D>();
- } else {
- return texture_map[texture_list->get_item_metadata(texture_list->get_selected_items()[0])];
- }
-}
-
-void TilesetEditorContext::set_tileset(const Ref<TileSet> &p_tileset) {
- tileset = p_tileset;
-}
-
-void TilesetEditorContext::set_snap_options_visible(bool p_visible) {
- snap_options_visible = p_visible;
- notify_property_list_changed();
-}
-
-bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name.operator String();
-
- if (name == "options_offset") {
- Vector2 snap = p_value;
- tileset_editor->_set_snap_off(snap + WORKSPACE_MARGIN);
- return true;
- } else if (name == "options_step") {
- Vector2 snap = p_value;
- tileset_editor->_set_snap_step(snap);
- return true;
- } else if (name == "options_separation") {
- Vector2 snap = p_value;
- tileset_editor->_set_snap_sep(snap);
- return true;
- } else if (p_name.operator String().left(5) == "tile_") {
- String name2 = p_name.operator String().right(5);
- bool v = false;
-
- if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) {
- return false;
- }
-
- if (name2 == "autotile_bitmask_mode") {
- tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", p_value, &v);
- } else if (name2 == "subtile_size") {
- tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", p_value, &v);
- } else if (name2 == "subtile_spacing") {
- tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", p_value, &v);
- } else {
- tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/" + name2, p_value, &v);
- }
- if (v) {
- tileset->notify_property_list_changed();
- tileset_editor->workspace->update();
- tileset_editor->workspace_overlay->update();
- }
- return v;
- } else if (name == "tileset_script") {
- tileset->set_script(p_value);
- return true;
- } else if (name == "selected_collision_one_way") {
- Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile());
- for (int index = 0; index < sd.size(); index++) {
- if (sd[index].shape == tileset_editor->edited_collision_shape) {
- tileset->tile_set_shape_one_way(tileset_editor->get_current_tile(), index, p_value);
- return true;
- }
- }
- return false;
- } else if (name == "selected_collision_one_way_margin") {
- Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile());
- for (int index = 0; index < sd.size(); index++) {
- if (sd[index].shape == tileset_editor->edited_collision_shape) {
- tileset->tile_set_shape_one_way_margin(tileset_editor->get_current_tile(), index, p_value);
- return true;
- }
- }
- return false;
- }
-
- tileset_editor->err_dialog->set_text(TTR("This property can't be changed."));
- tileset_editor->err_dialog->popup_centered(Size2(300, 60));
- return false;
-}
-
-bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name.operator String();
- bool v = false;
-
- if (name == "options_offset") {
- r_ret = tileset_editor->snap_offset - WORKSPACE_MARGIN;
- v = true;
- } else if (name == "options_step") {
- r_ret = tileset_editor->snap_step;
- v = true;
- } else if (name == "options_separation") {
- r_ret = tileset_editor->snap_separation;
- v = true;
- } else if (name.left(5) == "tile_") {
- name = name.right(5);
-
- if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) {
- return false;
- }
- if (!tileset->has_tile(tileset_editor->get_current_tile())) {
- return false;
- }
-
- if (name == "autotile_bitmask_mode") {
- r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", &v);
- } else if (name == "subtile_size") {
- r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", &v);
- } else if (name == "subtile_spacing") {
- r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", &v);
- } else {
- r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/" + name, &v);
- }
- return v;
- } else if (name == "selected_collision") {
- r_ret = tileset_editor->edited_collision_shape;
- v = true;
- } else if (name == "selected_collision_one_way") {
- Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile());
- for (int index = 0; index < sd.size(); index++) {
- if (sd[index].shape == tileset_editor->edited_collision_shape) {
- r_ret = sd[index].one_way_collision;
- v = true;
- break;
- }
- }
- } else if (name == "selected_collision_one_way_margin") {
- Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile());
- for (int index = 0; index < sd.size(); index++) {
- if (sd[index].shape == tileset_editor->edited_collision_shape) {
- r_ret = sd[index].one_way_collision_margin;
- v = true;
- break;
- }
- }
- } else if (name == "selected_navigation") {
- r_ret = tileset_editor->edited_navigation_shape;
- v = true;
- } else if (name == "selected_occlusion") {
- r_ret = tileset_editor->edited_occlusion_shape;
- v = true;
- } else if (name == "tileset_script") {
- r_ret = tileset->get_script();
- v = true;
- }
- return v;
-}
-
-void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const {
- if (snap_options_visible) {
- p_list->push_back(PropertyInfo(Variant::NIL, "Snap Options", PROPERTY_HINT_NONE, "options_", PROPERTY_USAGE_GROUP));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_offset"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_step"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_separation"));
- }
- if (tileset_editor->get_current_tile() >= 0 && !tileset.is_null()) {
- int id = tileset_editor->get_current_tile();
- p_list->push_back(PropertyInfo(Variant::NIL, "Selected Tile", PROPERTY_HINT_NONE, "tile_", PROPERTY_USAGE_GROUP));
- p_list->push_back(PropertyInfo(Variant::STRING, "tile_name"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_tex_offset"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"));
- p_list->push_back(PropertyInfo(Variant::COLOR, "tile_modulate"));
- p_list->push_back(PropertyInfo(Variant::INT, "tile_tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE,ATLAS_TILE"));
- if (tileset->tile_get_tile_mode(id) == TileSet::AUTO_TILE) {
- p_list->push_back(PropertyInfo(Variant::INT, "tile_autotile_bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_subtile_size"));
- p_list->push_back(PropertyInfo(Variant::INT, "tile_subtile_spacing", PROPERTY_HINT_RANGE, "0, 256, 1"));
- } else if (tileset->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) {
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_subtile_size"));
- p_list->push_back(PropertyInfo(Variant::INT, "tile_subtile_spacing", PROPERTY_HINT_RANGE, "0, 256, 1"));
- }
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_occluder_offset"));
- 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(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()));
- if (tileset_editor->edited_collision_shape.is_valid()) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "selected_collision_one_way", PROPERTY_HINT_NONE));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "selected_collision_one_way_margin", PROPERTY_HINT_NONE));
- }
- }
- if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_NAVIGATION && tileset_editor->edited_navigation_shape.is_valid()) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_navigation", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_navigation_shape->get_class()));
- }
- if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_OCCLUSION && tileset_editor->edited_occlusion_shape.is_valid()) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_occlusion", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_occlusion_shape->get_class()));
- }
- if (!tileset.is_null()) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "tileset_script", PROPERTY_HINT_RESOURCE_TYPE, "Script"));
- }
-}
-
-void TilesetEditorContext::_bind_methods() {
- ClassDB::bind_method("_hide_script_from_inspector", &TilesetEditorContext::_hide_script_from_inspector);
-}
-
-TilesetEditorContext::TilesetEditorContext(TileSetEditor *p_tileset_editor) {
- tileset_editor = p_tileset_editor;
- snap_options_visible = false;
-}
-
-void TileSetEditorPlugin::edit(Object *p_node) {
- if (Object::cast_to<TileSet>(p_node)) {
- tileset_editor->edit(Object::cast_to<TileSet>(p_node));
- }
-}
-
-bool TileSetEditorPlugin::handles(Object *p_node) const {
- return p_node->is_class("TileSet") || p_node->is_class("TilesetEditorContext");
-}
-
-void TileSetEditorPlugin::make_visible(bool p_visible) {
- if (p_visible) {
- tileset_editor_button->show();
- editor->make_bottom_panel_item_visible(tileset_editor);
- get_tree()->connect("idle_frame", Callable(tileset_editor, "_on_workspace_process"));
- } else {
- editor->hide_bottom_panel();
- tileset_editor_button->hide();
- get_tree()->disconnect("idle_frame", Callable(tileset_editor, "_on_workspace_process"));
- }
-}
-
-Dictionary TileSetEditorPlugin::get_state() const {
- Dictionary state;
- state["snap_offset"] = tileset_editor->snap_offset;
- state["snap_step"] = tileset_editor->snap_step;
- state["snap_separation"] = tileset_editor->snap_separation;
- state["snap_enabled"] = tileset_editor->tools[TileSetEditor::TOOL_GRID_SNAP]->is_pressed();
- state["keep_inside_tile"] = tileset_editor->tools[TileSetEditor::SHAPE_KEEP_INSIDE_TILE]->is_pressed();
- state["show_information"] = tileset_editor->tools[TileSetEditor::VISIBLE_INFO]->is_pressed();
- return state;
-}
-
-void TileSetEditorPlugin::set_state(const Dictionary &p_state) {
- Dictionary state = p_state;
- if (state.has("snap_step")) {
- tileset_editor->_set_snap_step(state["snap_step"]);
- }
-
- if (state.has("snap_offset")) {
- tileset_editor->_set_snap_off(state["snap_offset"]);
- }
-
- if (state.has("snap_separation")) {
- tileset_editor->_set_snap_sep(state["snap_separation"]);
- }
-
- if (state.has("snap_enabled")) {
- tileset_editor->tools[TileSetEditor::TOOL_GRID_SNAP]->set_pressed(state["snap_enabled"]);
- if (tileset_editor->helper) {
- tileset_editor->_on_grid_snap_toggled(state["snap_enabled"]);
- }
- }
-
- if (state.has("keep_inside_tile")) {
- tileset_editor->tools[TileSetEditor::SHAPE_KEEP_INSIDE_TILE]->set_pressed(state["keep_inside_tile"]);
- }
-
- if (state.has("show_information")) {
- tileset_editor->tools[TileSetEditor::VISIBLE_INFO]->set_pressed(state["show_information"]);
- }
-}
-
-TileSetEditorPlugin::TileSetEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- tileset_editor = memnew(TileSetEditor(p_node));
-
- tileset_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
- tileset_editor->hide();
-
- tileset_editor_button = p_node->add_bottom_panel_item(TTR("TileSet"), tileset_editor);
- tileset_editor_button->hide();
-}
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
deleted file mode 100644
index e778c18f44..0000000000
--- a/editor/plugins/tile_set_editor_plugin.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/*************************************************************************/
-/* tile_set_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef TILE_SET_EDITOR_PLUGIN_H
-#define TILE_SET_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.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"
-
-#define WORKSPACE_MARGIN Vector2(10, 10)
-class TilesetEditorContext;
-
-class TileSetEditor : public HSplitContainer {
- friend class TileSetEditorPlugin;
- friend class TilesetEditorContext;
-
- GDCLASS(TileSetEditor, HSplitContainer);
-
- enum TextureButtons {
- TOOL_TILESET_ADD_TEXTURE,
- TOOL_TILESET_REMOVE_TEXTURE,
- TOOL_TILESET_CREATE_SCENE,
- TOOL_TILESET_MERGE_SCENE,
- TOOL_TILESET_MAX
- };
-
- enum WorkspaceMode {
- WORKSPACE_EDIT,
- WORKSPACE_CREATE_SINGLE,
- WORKSPACE_CREATE_AUTOTILE,
- WORKSPACE_CREATE_ATLAS,
- WORKSPACE_MODE_MAX
- };
-
- enum EditMode {
- EDITMODE_REGION,
- EDITMODE_COLLISION,
- EDITMODE_OCCLUSION,
- EDITMODE_NAVIGATION,
- EDITMODE_BITMASK,
- EDITMODE_PRIORITY,
- EDITMODE_ICON,
- EDITMODE_Z_INDEX,
- EDITMODE_MAX
- };
-
- enum TileSetTools {
- SELECT_PREVIOUS,
- SELECT_NEXT,
- TOOL_SELECT,
- BITMASK_COPY,
- BITMASK_PASTE,
- BITMASK_CLEAR,
- SHAPE_NEW_POLYGON,
- SHAPE_NEW_RECTANGLE,
- SHAPE_TOGGLE_TYPE,
- SHAPE_DELETE,
- SHAPE_KEEP_INSIDE_TILE,
- TOOL_GRID_SNAP,
- ZOOM_OUT,
- ZOOM_1,
- ZOOM_IN,
- VISIBLE_INFO,
- TOOL_MAX
- };
-
- struct SubtileData {
- Array collisions;
- Ref<OccluderPolygon2D> occlusion_shape;
- Ref<NavigationPolygon> navigation_shape;
- };
-
- Ref<TileSet> tileset;
- TilesetEditorContext *helper;
- EditorNode *editor;
- UndoRedo *undo_redo;
-
- ConfirmationDialog *cd;
- AcceptDialog *err_dialog;
- EditorFileDialog *texture_dialog;
-
- ItemList *texture_list;
- int option;
- Button *tileset_toolbar_buttons[TOOL_TILESET_MAX];
- MenuButton *tileset_toolbar_tools;
- Map<RID, Ref<Texture2D>> texture_map;
-
- bool creating_shape;
- int dragging_point;
- bool tile_names_visible;
- Vector2 region_from;
- Rect2 edited_region;
- bool draw_edited_region;
- Vector2 edited_shape_coord;
- PackedVector2Array current_shape;
- Map<Vector2i, SubtileData> current_tile_data;
- Map<Vector2, uint32_t> bitmask_map_copy;
-
- Vector2 snap_step;
- Vector2 snap_offset;
- Vector2 snap_separation;
-
- Ref<Shape2D> edited_collision_shape;
- Ref<OccluderPolygon2D> edited_occlusion_shape;
- Ref<NavigationPolygon> edited_navigation_shape;
-
- int current_item_index;
- Sprite2D *preview;
- ScrollContainer *scroll;
- Label *empty_message;
- Control *workspace_container;
- bool draw_handles;
- Control *workspace_overlay;
- Control *workspace;
- Button *tool_workspacemode[WORKSPACE_MODE_MAX];
- Button *tool_editmode[EDITMODE_MAX];
- HSeparator *separator_editmode;
- HBoxContainer *toolbar;
- Button *tools[TOOL_MAX];
- VSeparator *separator_shape_toggle;
- VSeparator *separator_bitmask;
- VSeparator *separator_delete;
- VSeparator *separator_grid;
- SpinBox *spin_priority;
- SpinBox *spin_z_index;
- WorkspaceMode workspace_mode;
- EditMode edit_mode;
- int current_tile;
-
- float max_scale;
- float min_scale;
- float scale_ratio;
-
- void update_texture_list();
- void update_texture_list_icon();
-
- void add_texture(Ref<Texture2D> p_texture);
- void remove_texture(Ref<Texture2D> p_texture);
-
- Ref<Texture2D> get_current_texture();
-
- static void _import_node(Node *p_node, Ref<TileSet> p_library);
- static void _import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge);
- void _undo_redo_import_scene(Node *p_scene, bool p_merge);
-
- bool _is_drop_valid(const Dictionary &p_drag_data, const Dictionary &p_item_data) const;
- Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
- bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
- void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
- void _file_load_request(const Vector<String> &p_path, int p_at_pos = -1);
-
-protected:
- static void _bind_methods();
- void _notification(int p_what);
-
-public:
- void edit(const Ref<TileSet> &p_tileset);
- static Error update_library_file(Node *p_base_scene, Ref<TileSet> ml, bool p_merge = true);
-
- TileSetEditor(EditorNode *p_editor);
- ~TileSetEditor();
-
-private:
- void _on_tileset_toolbar_button_pressed(int p_index);
- void _on_tileset_toolbar_confirm();
- void _on_texture_list_selected(int p_index);
- void _on_textures_added(const PackedStringArray &p_paths);
- void _on_edit_mode_changed(int p_edit_mode);
- void _on_workspace_mode_changed(int p_workspace_mode);
- void _on_workspace_overlay_draw();
- void _on_workspace_draw();
- void _on_workspace_process();
- void _on_scroll_container_input(const Ref<InputEvent> &p_event);
- void _on_workspace_input(const Ref<InputEvent> &p_ie);
- void _on_tool_clicked(int p_tool);
- void _on_priority_changed(float val);
- void _on_z_index_changed(float val);
- void _on_grid_snap_toggled(bool p_val);
- Vector<Vector2> _get_collision_shape_points(const Ref<Shape2D> &p_shape);
- Vector<Vector2> _get_edited_shape_points();
- void _set_edited_shape_points(const Vector<Vector2> &points);
- void _update_tile_data();
- void _update_toggle_shape_button();
- void _select_next_tile();
- void _select_previous_tile();
- Array _get_tiles_in_current_texture(bool sorted = false);
- bool _sort_tiles(Variant p_a, Variant p_b);
- void _select_next_subtile();
- void _select_previous_subtile();
- void _select_next_shape();
- void _select_previous_shape();
- void _set_edited_collision_shape(const Ref<Shape2D> &p_shape);
- void _set_snap_step(Vector2 p_val);
- void _set_snap_off(Vector2 p_val);
- void _set_snap_sep(Vector2 p_val);
-
- void _validate_current_tile_id();
- void _select_edited_shape_coord();
- void _undo_tile_removal(int p_id);
-
- void _zoom_in();
- void _zoom_out();
- void _zoom_reset();
-
- void draw_highlight_current_tile();
- void draw_highlight_subtile(Vector2 coord, const Vector<Vector2> &other_highlighted = Vector<Vector2>());
- void draw_tile_subdivision(int p_id, Color p_color) const;
- void draw_edited_region_subdivision() const;
- void draw_grid_snap();
- void draw_polygon_shapes();
- void close_shape(const Vector2 &shape_anchor);
- void select_coord(const Vector2 &coord);
- Vector2 snap_point(const Vector2 &point);
- void update_workspace_tile_mode();
- void update_workspace_minsize();
- void update_edited_region(const Vector2 &end_point);
- int get_grabbed_point(const Vector2 &p_mouse_pos, real_t grab_threshold);
- bool is_within_grabbing_distance_of_first_point(const Vector2 &p_pos, real_t p_grab_threshold);
-
- int get_current_tile() const;
- void set_current_tile(int p_id);
-};
-
-class TilesetEditorContext : public Object {
- friend class TileSetEditor;
- GDCLASS(TilesetEditorContext, Object);
-
- Ref<TileSet> tileset;
- TileSetEditor *tileset_editor;
- bool snap_options_visible;
-
-public:
- bool _hide_script_from_inspector() { return true; }
- void set_tileset(const Ref<TileSet> &p_tileset);
-
-private:
- void set_snap_options_visible(bool p_visible);
-
-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;
- static void _bind_methods();
-
-public:
- TilesetEditorContext(TileSetEditor *p_tileset_editor);
-};
-
-class TileSetEditorPlugin : public EditorPlugin {
- GDCLASS(TileSetEditorPlugin, EditorPlugin);
-
- TileSetEditor *tileset_editor;
- Button *tileset_editor_button;
- EditorNode *editor;
-
-public:
- virtual String get_name() const override { return "TileSet"; }
- bool has_main_screen() const override { return false; }
- virtual void edit(Object *p_node) override;
- virtual bool handles(Object *p_node) const override;
- virtual void make_visible(bool p_visible) override;
- void set_state(const Dictionary &p_state) override;
- Dictionary get_state() const override;
-
- TileSetEditorPlugin(EditorNode *p_node);
-};
-
-#endif // TILE_SET_EDITOR_PLUGIN_H
diff --git a/editor/plugins/tiles/SCsub b/editor/plugins/tiles/SCsub
new file mode 100644
index 0000000000..359d04e5df
--- /dev/null
+++ b/editor/plugins/tiles/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.editor_sources, "*.cpp")
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
new file mode 100644
index 0000000000..78f181e321
--- /dev/null
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -0,0 +1,657 @@
+/*************************************************************************/
+/* tile_atlas_view.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "tile_atlas_view.h"
+
+#include "core/input/input.h"
+#include "core/os/keyboard.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/center_container.h"
+#include "scene/gui/label.h"
+#include "scene/gui/panel.h"
+#include "scene/gui/texture_rect.h"
+
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+
+void TileAtlasView::_gui_input(const Ref<InputEvent> &p_event) {
+ bool ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
+
+ Ref<InputEventMouseButton> b = p_event;
+ if (b.is_valid()) {
+ if (ctrl && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
+ // Zoom out
+ zoom_widget->set_zoom_by_increments(-2);
+ emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll()));
+ _update_zoom(zoom_widget->get_zoom(), true);
+ accept_event();
+ }
+
+ if (ctrl && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
+ // Zoom in
+ zoom_widget->set_zoom_by_increments(2);
+ emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll()));
+ _update_zoom(zoom_widget->get_zoom(), true);
+ accept_event();
+ }
+ }
+}
+
+Size2i TileAtlasView::_compute_base_tiles_control_size() {
+ // Update the texture.
+ Vector2i size;
+ Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
+ if (texture.is_valid()) {
+ size = texture->get_size();
+ }
+
+ // Extend the size to all existing tiles.
+ Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
+ grid_size = grid_size.max(tile_id + Vector2i(1, 1));
+ }
+ size = size.max(grid_size * (tile_set_atlas_source->get_texture_region_size() + tile_set_atlas_source->get_separation()) + tile_set_atlas_source->get_margins());
+
+ return size;
+}
+
+Size2i TileAtlasView::_compute_alternative_tiles_control_size() {
+ Vector2i size;
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
+ int alternatives_count = tile_set_atlas_source->get_alternative_tiles_count(tile_id);
+ Vector2i line_size;
+ Size2i texture_region_size = tile_set_atlas_source->get_tile_texture_region(tile_id).size;
+ for (int j = 1; j < alternatives_count; j++) {
+ int alternative_id = tile_set_atlas_source->get_alternative_tile_id(tile_id, j);
+ bool transposed = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(tile_id, alternative_id))->get_transpose();
+ line_size.x += transposed ? texture_region_size.y : texture_region_size.x;
+ line_size.y = MAX(line_size.y, transposed ? texture_region_size.x : texture_region_size.y);
+ }
+ size.x = MAX(size.x, line_size.x);
+ size.y += line_size.y;
+ }
+
+ return size;
+}
+
+void TileAtlasView::_update_zoom(float p_zoom, bool p_zoom_on_mouse_pos, Vector2i p_scroll) {
+ // Compute the minimum sizes.
+ Size2i base_tiles_control_size = _compute_base_tiles_control_size();
+ base_tiles_root_control->set_custom_minimum_size(Vector2(base_tiles_control_size) * p_zoom);
+
+ Size2i alternative_tiles_control_size = _compute_alternative_tiles_control_size();
+ alternative_tiles_root_control->set_custom_minimum_size(Vector2(alternative_tiles_control_size) * p_zoom);
+
+ // Set the texture for the base tiles.
+ Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
+
+ // Set the scales.
+ if (base_tiles_control_size.x > 0 && base_tiles_control_size.y > 0) {
+ base_tiles_drawing_root->set_scale(Vector2(p_zoom, p_zoom));
+ } else {
+ base_tiles_drawing_root->set_scale(Vector2(1, 1));
+ }
+ if (alternative_tiles_control_size.x > 0 && alternative_tiles_control_size.y > 0) {
+ alternative_tiles_drawing_root->set_scale(Vector2(p_zoom, p_zoom));
+ } else {
+ alternative_tiles_drawing_root->set_scale(Vector2(1, 1));
+ }
+
+ // Update the margin container's margins.
+ const char *constants[] = { "margin_left", "margin_top", "margin_right", "margin_bottom" };
+ for (int i = 0; i < 4; i++) {
+ margin_container->add_theme_constant_override(constants[i], margin_container_paddings[i] * p_zoom);
+ }
+
+ // Update the backgrounds.
+ background_left->update();
+ background_right->update();
+
+ if (p_scroll != Vector2i(-1, -1)) {
+ scroll_container->set_h_scroll(p_scroll.x);
+ scroll_container->set_v_scroll(p_scroll.y);
+ }
+
+ // Zoom on the position.
+ if (previous_zoom != p_zoom) {
+ // TODO: solve this.
+ // There is however an issue with scrollcainter preventing this, as it seems
+ // that the scrollbars are not updated right aways after its children update.
+
+ // Compute point on previous area.
+ /*Vector2 max = Vector2(scroll_container->get_h_scrollbar()->get_max(), scroll_container->get_v_scrollbar()->get_max());
+ Vector2 min = Vector2(scroll_container->get_h_scrollbar()->get_min(), scroll_container->get_v_scrollbar()->get_min());
+ Vector2 value = Vector2(scroll_container->get_h_scrollbar()->get_value(), scroll_container->get_v_scrollbar()->get_value());
+
+ Vector2 old_max = max * previous_zoom / p_zoom;
+
+ Vector2 max_pixel_change = max - old_max;
+ Vector2 ratio = ((value + scroll_container->get_local_mouse_position()) / old_max).max(Vector2()).min(Vector2(1,1));
+ Vector2 offset = max_pixel_change * ratio;
+
+ print_line("--- ZOOMED ---");
+ print_line(vformat("max: %s", max));
+ print_line(vformat("min: %s", min));
+ print_line(vformat("value: %s", value));
+ print_line(vformat("size: %s", scroll_container->get_size()));
+ print_line(vformat("mouse_pos: %s", scroll_container->get_local_mouse_position()));
+
+ print_line(vformat("ratio: %s", ratio));
+ print_line(vformat("max_pixel_change: %s", max_pixel_change));
+ print_line(vformat("offset: %s", offset));
+
+
+ print_line(vformat("value before: %s", Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll())));
+ scroll_container->set_h_scroll(10000);//scroll_container->get_h_scroll()+offset.x);
+ scroll_container->set_v_scroll(10000);//scroll_container->get_v_scroll()+offset.y);
+ print_line(vformat("value after: %s", Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll())));
+ */
+
+ previous_zoom = p_zoom;
+ }
+}
+
+void TileAtlasView::_scroll_changed() {
+ emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll()));
+}
+
+void TileAtlasView::_zoom_widget_changed() {
+ _update_zoom(zoom_widget->get_zoom());
+ emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll()));
+}
+
+void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) {
+ base_tiles_root_control->set_tooltip("");
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ Transform2D xform = base_tiles_drawing_root->get_transform().affine_inverse();
+ Vector2i coords = get_atlas_tile_coords_at_pos(xform.xform(mm->get_position()));
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ coords = tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ base_tiles_root_control->set_tooltip(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: 0"), source_id, coords));
+ }
+ }
+ }
+}
+
+void TileAtlasView::_draw_base_tiles() {
+ Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
+ if (texture.is_valid()) {
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
+
+ // Draw the texture, square by square.
+ Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+ for (int x = 0; x < grid_size.x; x++) {
+ for (int y = 0; y < grid_size.y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
+ Rect2i rect = Rect2i(texture_region_size * coords + margins, texture_region_size);
+ base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ }
+ }
+ }
+
+ // Draw the texture around the grid.
+ Rect2i rect;
+ // Top.
+ rect.position = Vector2i();
+ rect.set_end(Vector2i(texture->get_size().x, margins.y));
+ base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ // Bottom
+ int bottom_border = margins.y + (grid_size.y * texture_region_size.y);
+ if (bottom_border < texture->get_size().y) {
+ rect.position = Vector2i(0, bottom_border);
+ rect.set_end(texture->get_size());
+ base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ }
+ // Left
+ rect.position = Vector2i(0, margins.y);
+ rect.set_end(Vector2i(margins.x, margins.y + (grid_size.y * texture_region_size.y)));
+ base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ // Right.
+ int right_border = margins.x + (grid_size.x * texture_region_size.x);
+ if (right_border < texture->get_size().x) {
+ rect.position = Vector2i(right_border, margins.y);
+ rect.set_end(Vector2i(texture->get_size().x, margins.y + (grid_size.y * texture_region_size.y)));
+ base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
+ }
+
+ // Draw actual tiles, using their properties (modulation, etc...)
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i atlas_coords = tile_set_atlas_source->get_tile_id(i);
+
+ // Update the y to max value.
+ Vector2i offset_pos = (margins + (atlas_coords * texture_region_size) + tile_set_atlas_source->get_tile_texture_region(atlas_coords).size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0));
+
+ // Draw the tile.
+ TileSetPluginAtlasRendering::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0);
+ }
+ }
+}
+
+void TileAtlasView::_draw_base_tiles_texture_grid() {
+ Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
+ if (texture.is_valid()) {
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
+ Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
+
+ Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+
+ // Draw each tile texture region.
+ for (int x = 0; x < grid_size.x; x++) {
+ for (int y = 0; y < grid_size.y; y++) {
+ Vector2i origin = margins + (Vector2i(x, y) * (texture_region_size + separation));
+ Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(Vector2i(x, y));
+ if (base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ if (base_tile_coords == Vector2i(x, y)) {
+ // Draw existing tile.
+ Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(base_tile_coords);
+ Vector2 region_size = texture_region_size * size_in_atlas + separation * (size_in_atlas - Vector2i(1, 1));
+ base_tiles_texture_grid->draw_rect(Rect2i(origin, region_size), Color(1.0, 1.0, 1.0, 0.8), false);
+ }
+ } else {
+ // Draw the grid.
+ base_tiles_texture_grid->draw_rect(Rect2i(origin, texture_region_size), Color(0.7, 0.7, 0.7, 0.1), false);
+ }
+ }
+ }
+ }
+}
+
+void TileAtlasView::_draw_base_tiles_dark() {
+ Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
+ if (texture.is_valid()) {
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
+ Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
+
+ Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+
+ // Draw each tile texture region.
+ for (int x = 0; x < grid_size.x; x++) {
+ for (int y = 0; y < grid_size.y; y++) {
+ Vector2i origin = margins + (Vector2i(x, y) * (texture_region_size + separation));
+ Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(Vector2i(x, y));
+
+ if (base_tile_coords == TileSetSource::INVALID_ATLAS_COORDS) {
+ // Draw the grid.
+ base_tiles_dark->draw_rect(Rect2i(origin, texture_region_size), Color(0.0, 0.0, 0.0, 0.5), true);
+ }
+ }
+ }
+ }
+}
+
+void TileAtlasView::_draw_base_tiles_shape_grid() {
+ // Draw the shapes.
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Vector2i tile_shape_size = tile_set->get_tile_size();
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
+ Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_effective_texture_offset(tile_id, 0);
+ Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(tile_id);
+ Vector2 origin = texture_region.position + (texture_region.size - tile_shape_size) / 2 + in_tile_base_offset;
+
+ // Draw only if the tile shape fits in the texture region
+ tile_set->draw_tile_shape(base_tiles_shape_grid, Rect2(origin, tile_shape_size), grid_color);
+ }
+}
+
+void TileAtlasView::_alternative_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) {
+ alternative_tiles_root_control->set_tooltip("");
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ Transform2D xform = alternative_tiles_drawing_root->get_transform().affine_inverse();
+ Vector3i coords3 = get_alternative_tile_at_pos(xform.xform(mm->get_position()));
+ Vector2i coords = Vector2i(coords3.x, coords3.y);
+ int alternative_id = coords3.z;
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS && alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) {
+ alternative_tiles_root_control->set_tooltip(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: %d"), source_id, coords, alternative_id));
+ }
+ }
+}
+
+void TileAtlasView::_draw_alternatives() {
+ // Draw the alternative tiles.
+ Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
+ if (texture.is_valid()) {
+ Vector2 current_pos;
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i atlas_coords = tile_set_atlas_source->get_tile_id(i);
+ current_pos.x = 0;
+ int y_increment = 0;
+ Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(atlas_coords);
+ int alternatives_count = tile_set_atlas_source->get_alternative_tiles_count(atlas_coords);
+ for (int j = 1; j < alternatives_count; j++) {
+ int alternative_id = tile_set_atlas_source->get_alternative_tile_id(atlas_coords, j);
+ TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(atlas_coords, alternative_id));
+ bool transposed = tile_data->get_transpose();
+
+ // Update the y to max value.
+ Vector2i offset_pos = current_pos;
+ if (transposed) {
+ offset_pos = (current_pos + Vector2(texture_region.size.y, texture_region.size.x) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id));
+ y_increment = MAX(y_increment, texture_region.size.x);
+ } else {
+ offset_pos = (current_pos + texture_region.size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id));
+ y_increment = MAX(y_increment, texture_region.size.y);
+ }
+
+ // Draw the tile.
+ TileSetPluginAtlasRendering::draw_tile(alternatives_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, alternative_id);
+
+ // Increment the x position.
+ current_pos.x += transposed ? texture_region.size.y : texture_region.size.x;
+ }
+ if (alternatives_count > 1) {
+ current_pos.y += y_increment;
+ }
+ }
+ }
+}
+
+void TileAtlasView::_draw_background_left() {
+ Ref<Texture2D> texture = get_theme_icon("Checkerboard", "EditorIcons");
+ background_left->set_size(base_tiles_root_control->get_custom_minimum_size());
+ background_left->draw_texture_rect(texture, Rect2(Vector2(), background_left->get_size()), true);
+}
+
+void TileAtlasView::_draw_background_right() {
+ Ref<Texture2D> texture = get_theme_icon("Checkerboard", "EditorIcons");
+ background_right->set_size(alternative_tiles_root_control->get_custom_minimum_size());
+ background_right->draw_texture_rect(texture, Rect2(Vector2(), background_right->get_size()), true);
+}
+
+void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id) {
+ ERR_FAIL_COND(!p_tile_set);
+ ERR_FAIL_COND(!p_tile_set_atlas_source);
+ ERR_FAIL_COND(p_source_id < 0);
+ ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
+
+ tile_set = p_tile_set;
+ tile_set_atlas_source = p_tile_set_atlas_source;
+ source_id = p_source_id;
+
+ // Show or hide the view.
+ bool valid = tile_set_atlas_source->get_texture().is_valid();
+ hbox->set_visible(valid);
+ missing_source_label->set_visible(!valid);
+
+ // Update the rect cache.
+ _update_alternative_tiles_rect_cache();
+
+ // Update everything.
+ _update_zoom(zoom_widget->get_zoom());
+
+ // Change children control size.
+ Size2i base_tiles_control_size = _compute_base_tiles_control_size();
+ for (int i = 0; i < base_tiles_drawing_root->get_child_count(); i++) {
+ Control *control = Object::cast_to<Control>(base_tiles_drawing_root->get_child(i));
+ if (control) {
+ control->set_size(base_tiles_control_size);
+ }
+ }
+
+ Size2i alternative_control_size = _compute_alternative_tiles_control_size();
+ for (int i = 0; i < alternative_tiles_drawing_root->get_child_count(); i++) {
+ Control *control = Object::cast_to<Control>(alternative_tiles_drawing_root->get_child(i));
+ if (control) {
+ control->set_size(alternative_control_size);
+ }
+ }
+
+ // Update.
+ base_tiles_draw->update();
+ base_tiles_texture_grid->update();
+ base_tiles_shape_grid->update();
+ base_tiles_dark->update();
+ alternatives_draw->update();
+ background_left->update();
+ background_right->update();
+}
+
+float TileAtlasView::get_zoom() const {
+ return zoom_widget->get_zoom();
+};
+
+void TileAtlasView::set_transform(float p_zoom, Vector2i p_scroll) {
+ zoom_widget->set_zoom(p_zoom);
+ _update_zoom(zoom_widget->get_zoom(), false, p_scroll);
+};
+
+void TileAtlasView::set_padding(Side p_side, int p_padding) {
+ ERR_FAIL_COND(p_padding < 0);
+ margin_container_paddings[p_side] = p_padding;
+}
+
+Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos) const {
+ Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
+ if (texture.is_valid()) {
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
+ Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
+
+ // Compute index in atlas
+ Vector2 pos = p_pos - margins;
+ Vector2i ret = (pos / (texture_region_size + separation)).floor();
+
+ return ret;
+ }
+
+ return TileSetSource::INVALID_ATLAS_COORDS;
+}
+
+void TileAtlasView::_update_alternative_tiles_rect_cache() {
+ alternative_tiles_rect_cache.clear();
+
+ Rect2i current;
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
+ int alternatives_count = tile_set_atlas_source->get_alternative_tiles_count(tile_id);
+ Size2i texture_region_size = tile_set_atlas_source->get_tile_texture_region(tile_id).size;
+ int line_height = 0;
+ for (int j = 1; j < alternatives_count; j++) {
+ int alternative_id = tile_set_atlas_source->get_alternative_tile_id(tile_id, j);
+ TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(tile_id, alternative_id));
+ bool transposed = tile_data->get_transpose();
+ current.size = transposed ? Vector2i(texture_region_size.y, texture_region_size.x) : texture_region_size;
+
+ // Update the rect.
+ if (!alternative_tiles_rect_cache.has(tile_id)) {
+ alternative_tiles_rect_cache[tile_id] = Map<int, Rect2i>();
+ }
+ alternative_tiles_rect_cache[tile_id][alternative_id] = current;
+
+ current.position.x += transposed ? texture_region_size.y : texture_region_size.x;
+ line_height = MAX(line_height, transposed ? texture_region_size.x : texture_region_size.y);
+ }
+
+ current.position.x = 0;
+ current.position.y += line_height;
+ }
+}
+
+Vector3i TileAtlasView::get_alternative_tile_at_pos(const Vector2 p_pos) const {
+ for (Map<Vector2, Map<int, Rect2i>>::Element *E_coords = alternative_tiles_rect_cache.front(); E_coords; E_coords = E_coords->next()) {
+ for (Map<int, Rect2i>::Element *E_alternative = E_coords->value().front(); E_alternative; E_alternative = E_alternative->next()) {
+ if (E_alternative->value().has_point(p_pos)) {
+ return Vector3i(E_coords->key().x, E_coords->key().y, E_alternative->key());
+ }
+ }
+ }
+
+ return Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE);
+}
+
+Rect2i TileAtlasView::get_alternative_tile_rect(const Vector2i p_coords, int p_alternative_tile) {
+ ERR_FAIL_COND_V_MSG(!alternative_tiles_rect_cache.has(p_coords), Rect2i(), vformat("No cached rect for tile coords:%s", p_coords));
+ ERR_FAIL_COND_V_MSG(!alternative_tiles_rect_cache[p_coords].has(p_alternative_tile), Rect2i(), vformat("No cached rect for tile coords:%s alternative_id:%d", p_coords, p_alternative_tile));
+
+ return alternative_tiles_rect_cache[p_coords][p_alternative_tile];
+}
+
+void TileAtlasView::update() {
+ scroll_container->update();
+ base_tiles_texture_grid->update();
+ base_tiles_shape_grid->update();
+ base_tiles_dark->update();
+ alternatives_draw->update();
+ background_left->update();
+ background_right->update();
+}
+
+void TileAtlasView::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("transform_changed", PropertyInfo(Variant::FLOAT, "zoom"), PropertyInfo(Variant::VECTOR2, "scroll")));
+}
+
+TileAtlasView::TileAtlasView() {
+ Panel *panel_container = memnew(Panel);
+ panel_container->set_h_size_flags(SIZE_EXPAND_FILL);
+ panel_container->set_v_size_flags(SIZE_EXPAND_FILL);
+ panel_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ add_child(panel_container);
+
+ //Scrolling
+ scroll_container = memnew(ScrollContainer);
+ scroll_container->get_h_scrollbar()->connect("value_changed", callable_mp(this, &TileAtlasView::_scroll_changed).unbind(1));
+ scroll_container->get_v_scrollbar()->connect("value_changed", callable_mp(this, &TileAtlasView::_scroll_changed).unbind(1));
+ panel_container->add_child(scroll_container);
+ scroll_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+
+ zoom_widget = memnew(EditorZoomWidget);
+ add_child(zoom_widget);
+ zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);
+ zoom_widget->connect("zoom_changed", callable_mp(this, &TileAtlasView::_zoom_widget_changed).unbind(1));
+
+ CenterContainer *center_container = memnew(CenterContainer);
+ center_container->set_h_size_flags(SIZE_EXPAND_FILL);
+ center_container->set_v_size_flags(SIZE_EXPAND_FILL);
+ center_container->connect("gui_input", callable_mp(this, &TileAtlasView::_gui_input));
+ scroll_container->add_child(center_container);
+
+ missing_source_label = memnew(Label);
+ missing_source_label->set_text(TTR("No atlas source with a valid texture selected."));
+ center_container->add_child(missing_source_label);
+
+ margin_container = memnew(MarginContainer);
+ center_container->add_child(margin_container);
+
+ hbox = memnew(HBoxContainer);
+ hbox->add_theme_constant_override("separation", 10);
+ hbox->hide();
+ margin_container->add_child(hbox);
+
+ VBoxContainer *left_vbox = memnew(VBoxContainer);
+ hbox->add_child(left_vbox);
+
+ VBoxContainer *right_vbox = memnew(VBoxContainer);
+ hbox->add_child(right_vbox);
+
+ // Base tiles.
+ Label *base_tile_label = memnew(Label);
+ base_tile_label->set_text(TTR("Base Tiles"));
+ base_tile_label->set_align(Label::ALIGN_CENTER);
+ left_vbox->add_child(base_tile_label);
+
+ base_tiles_root_control = memnew(Control);
+ base_tiles_root_control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ base_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_base_tiles_root_control_gui_input));
+ left_vbox->add_child(base_tiles_root_control);
+
+ background_left = memnew(Control);
+ background_left->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ background_left->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
+ background_left->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ background_left->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_left));
+ base_tiles_root_control->add_child(background_left);
+
+ base_tiles_drawing_root = memnew(Control);
+ base_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ base_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
+ base_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ base_tiles_root_control->add_child(base_tiles_drawing_root);
+
+ base_tiles_draw = memnew(Control);
+ base_tiles_draw->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ base_tiles_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles));
+ base_tiles_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ base_tiles_drawing_root->add_child(base_tiles_draw);
+
+ base_tiles_texture_grid = memnew(Control);
+ base_tiles_texture_grid->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ base_tiles_texture_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_texture_grid));
+ base_tiles_texture_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ base_tiles_drawing_root->add_child(base_tiles_texture_grid);
+
+ base_tiles_shape_grid = memnew(Control);
+ base_tiles_shape_grid->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ base_tiles_shape_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_shape_grid));
+ base_tiles_shape_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ base_tiles_drawing_root->add_child(base_tiles_shape_grid);
+
+ base_tiles_dark = memnew(Control);
+ base_tiles_dark->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ base_tiles_dark->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_dark));
+ base_tiles_dark->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ base_tiles_drawing_root->add_child(base_tiles_dark);
+
+ // Alternative tiles.
+ Label *alternative_tiles_label = memnew(Label);
+ alternative_tiles_label->set_text(TTR("Alternative Tiles"));
+ alternative_tiles_label->set_align(Label::ALIGN_CENTER);
+ right_vbox->add_child(alternative_tiles_label);
+
+ alternative_tiles_root_control = memnew(Control);
+ alternative_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_alternative_tiles_root_control_gui_input));
+ right_vbox->add_child(alternative_tiles_root_control);
+
+ background_right = memnew(Control);
+ background_right->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
+ background_right->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_right));
+ background_right->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ alternative_tiles_root_control->add_child(background_right);
+
+ alternative_tiles_drawing_root = memnew(Control);
+ alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
+ alternative_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ alternative_tiles_root_control->add_child(alternative_tiles_drawing_root);
+
+ alternatives_draw = memnew(Control);
+ alternatives_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_alternatives));
+ alternatives_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ alternative_tiles_drawing_root->add_child(alternatives_draw);
+}
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
new file mode 100644
index 0000000000..28fd3ed1e0
--- /dev/null
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -0,0 +1,153 @@
+/*************************************************************************/
+/* tile_atlas_view.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TILE_ATLAS_VIEW_H
+#define TILE_ATLAS_VIEW_H
+
+#include "editor/editor_zoom_widget.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/label.h"
+#include "scene/gui/margin_container.h"
+#include "scene/gui/scroll_container.h"
+#include "scene/gui/texture_rect.h"
+#include "scene/resources/tile_set.h"
+
+class TileAtlasView : public Control {
+ GDCLASS(TileAtlasView, Control);
+
+private:
+ TileSet *tile_set;
+ TileSetAtlasSource *tile_set_atlas_source;
+ int source_id = -1;
+
+ float previous_zoom = 1.0;
+ EditorZoomWidget *zoom_widget;
+ void _zoom_widget_changed();
+ void _scroll_changed();
+ void _update_zoom(float p_zoom, bool p_zoom_on_mouse_pos = false, Vector2i p_scroll = Vector2i(-1, -1));
+ void _gui_input(const Ref<InputEvent> &p_event);
+
+ Map<Vector2, Map<int, Rect2i>> alternative_tiles_rect_cache;
+ void _update_alternative_tiles_rect_cache();
+
+ ScrollContainer *scroll_container;
+ MarginContainer *margin_container;
+ int margin_container_paddings[4] = { 0, 0, 0, 0 };
+ HBoxContainer *hbox;
+ Label *missing_source_label;
+
+ // Background
+ Control *background_left;
+ void _draw_background_left();
+ Control *background_right;
+ void _draw_background_right();
+
+ // Left side.
+ Control *base_tiles_root_control;
+ void _base_tiles_root_control_gui_input(const Ref<InputEvent> &p_event);
+
+ Control *base_tiles_drawing_root;
+
+ Control *base_tiles_draw;
+ void _draw_base_tiles();
+
+ Control *base_tiles_texture_grid;
+ void _draw_base_tiles_texture_grid();
+
+ Control *base_tiles_shape_grid;
+ void _draw_base_tiles_shape_grid();
+
+ Control *base_tiles_dark;
+ void _draw_base_tiles_dark();
+
+ Size2i _compute_base_tiles_control_size();
+
+ // Right side.
+ Control *alternative_tiles_root_control;
+ void _alternative_tiles_root_control_gui_input(const Ref<InputEvent> &p_event);
+
+ Control *alternative_tiles_drawing_root;
+
+ Control *alternatives_draw;
+ void _draw_alternatives();
+
+ Size2i _compute_alternative_tiles_control_size();
+
+protected:
+ static void _bind_methods();
+
+public:
+ // Global.
+ void set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id);
+
+ ScrollContainer *get_scroll_container() { return scroll_container; };
+
+ float get_zoom() const;
+ void set_transform(float p_zoom, Vector2i p_scroll);
+
+ void set_padding(Side p_side, int p_padding);
+
+ // Left side.
+ void set_texture_grid_visible(bool p_visible) { base_tiles_texture_grid->set_visible(p_visible); };
+ void set_dark_visible(bool p_visible) { base_tiles_dark->set_visible(p_visible); };
+ void set_tile_shape_grid_visible(bool p_visible) { base_tiles_shape_grid->set_visible(p_visible); };
+
+ Vector2i get_atlas_tile_coords_at_pos(const Vector2 p_pos) const;
+
+ void add_control_over_atlas_tiles(Control *p_control, bool scaled = true) {
+ if (scaled) {
+ base_tiles_drawing_root->add_child(p_control);
+ } else {
+ base_tiles_root_control->add_child(p_control);
+ }
+ p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ };
+
+ // Right side.
+ Vector3i get_alternative_tile_at_pos(const Vector2 p_pos) const;
+ Rect2i get_alternative_tile_rect(const Vector2i p_coords, int p_alternative_tile);
+
+ void add_control_over_alternative_tiles(Control *p_control, bool scaled = true) {
+ if (scaled) {
+ alternative_tiles_drawing_root->add_child(p_control);
+ } else {
+ alternative_tiles_root_control->add_child(p_control);
+ }
+ p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ };
+
+ // Update everything.
+ void update();
+
+ TileAtlasView();
+};
+
+#endif // TILE_ATLAS_VIEW
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
new file mode 100644
index 0000000000..61457e3e59
--- /dev/null
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -0,0 +1,233 @@
+/*************************************************************************/
+/* tile_data_editors.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "tile_data_editors.h"
+
+#include "tile_set_editor.h"
+
+TileData *TileDataEditor::_get_tile_data(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile) {
+ ERR_FAIL_COND_V(!p_tile_set, nullptr);
+ ERR_FAIL_COND_V(!p_tile_set->has_source(p_atlas_source_id), nullptr);
+
+ TileData *td = nullptr;
+ TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ ERR_FAIL_COND_V(!atlas_source->has_tile(p_atlas_coords), nullptr);
+ ERR_FAIL_COND_V(!atlas_source->has_alternative_tile(p_atlas_coords, p_alternative_tile), nullptr);
+ td = Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile));
+ }
+
+ return td;
+}
+
+void TileDataEditor::edit(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+}
+
+void TileDataTextureOffsetEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+ TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+ ERR_FAIL_COND(!tile_data);
+
+ bool valid;
+ Variant value = tile_data->get(p_property, &valid);
+ if (!valid) {
+ return;
+ }
+ ERR_FAIL_COND(value.get_type() != Variant::VECTOR2I);
+
+ Vector2i tile_set_tile_size = p_tile_set->get_tile_size();
+ Rect2i rect = Rect2i(-tile_set_tile_size / 2, tile_set_tile_size);
+ p_tile_set->draw_tile_shape(p_canvas_item, p_transform.xform(rect), Color(1.0, 0.0, 0.0));
+}
+
+void TileDataIntegerEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+ TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+ ERR_FAIL_COND(!tile_data);
+
+ bool valid;
+ Variant value = tile_data->get(p_property, &valid);
+ if (!valid) {
+ return;
+ }
+ ERR_FAIL_COND(value.get_type() != Variant::INT);
+
+ Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts");
+ int height = font->get_height();
+ int width = 200;
+ p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-width / 2, height / 2), vformat("%d", value), HALIGN_CENTER, width, -1, Color(1, 1, 1), 1, Color(0, 0, 0, 1));
+}
+
+void TileDataFloatEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+ TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+ ERR_FAIL_COND(!tile_data);
+
+ bool valid;
+ Variant value = tile_data->get(p_property, &valid);
+ if (!valid) {
+ return;
+ }
+ ERR_FAIL_COND(value.get_type() != Variant::FLOAT);
+
+ Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts");
+ int height = font->get_height();
+ int width = 200;
+ p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-width / 2, height / 2), vformat("%.2f", value), HALIGN_CENTER, width, -1, Color(1, 1, 1), 1, Color(0, 0, 0, 1));
+}
+
+void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+ TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+ ERR_FAIL_COND(!tile_data);
+
+ bool valid;
+ Variant value = tile_data->get(p_property, &valid);
+ if (!valid) {
+ return;
+ }
+ ERR_FAIL_COND(value.get_type() != Variant::VECTOR2I && value.get_type() != Variant::VECTOR2);
+
+ Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon("EditorPosition", "EditorIcons");
+ p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(value)) - position_icon->get_size() / 2);
+}
+
+void TileDataYSortEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+ TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+ ERR_FAIL_COND(!tile_data);
+
+ bool valid;
+ Variant value = tile_data->get(p_property, &valid);
+ if (!valid) {
+ return;
+ }
+ ERR_FAIL_COND(value.get_type() != Variant::INT);
+
+ Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon("EditorPosition", "EditorIcons");
+ p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(0, value)) - position_icon->get_size() / 2);
+}
+
+void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+ TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+ ERR_FAIL_COND(!tile_data);
+
+ Vector<String> components = String(p_property).split("/", true);
+ if (components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) {
+ int occlusion_layer = components[0].trim_prefix("occlusion_layer_").to_int();
+ if (occlusion_layer >= 0 && occlusion_layer < p_tile_set->get_occlusion_layers_count()) {
+ // Draw all shapes.
+ Vector<Color> debug_occlusion_color;
+ debug_occlusion_color.push_back(Color(0.5, 0, 0, 0.6));
+
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+ Ref<OccluderPolygon2D> occluder = tile_data->get_occluder(occlusion_layer);
+ if (occluder.is_valid() && occluder->get_polygon().size() >= 3) {
+ p_canvas_item->draw_polygon(Variant(occluder->get_polygon()), debug_occlusion_color);
+ }
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
+ }
+ }
+}
+
+void TileDataCollisionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+ TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+ ERR_FAIL_COND(!tile_data);
+
+ Vector<String> components = String(p_property).split("/", true);
+ if (components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) {
+ int physics_layer = components[0].trim_prefix("physics_layer_").to_int();
+ if (physics_layer >= 0 && physics_layer < p_tile_set->get_physics_layers_count()) {
+ // Draw all shapes.
+ Color debug_collision_color = p_canvas_item->get_tree()->get_debug_collisions_color();
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+ for (int i = 0; i < tile_data->get_collision_shapes_count(physics_layer); i++) {
+ Ref<Shape2D> shape = tile_data->get_collision_shape_shape(physics_layer, i);
+ if (shape.is_valid()) {
+ shape->draw(p_canvas_item->get_canvas_item(), debug_collision_color);
+ }
+ }
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
+ }
+ }
+}
+
+void TileDataTerrainsEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+ TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+ ERR_FAIL_COND(!tile_data);
+
+ Vector<String> components = String(p_property).split("/", true);
+ if (components[0] == "terrain_mode" || components[0] == "terrain" || components[0] == "terrains_peering_bit") {
+ TileSetPluginAtlasTerrain::draw_terrains(p_canvas_item, p_transform, p_tile_set, tile_data);
+ }
+}
+
+void TileDataNavigationPolygonEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) {
+ TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile);
+ ERR_FAIL_COND(!tile_data);
+
+ Vector<String> components = String(p_property).split("/", true);
+ if (components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) {
+ int navigation_layer = components[0].trim_prefix("navigation_layer_").to_int();
+ if (navigation_layer >= 0 && navigation_layer < p_tile_set->get_navigation_layers_count()) {
+ // Draw all shapes.
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+
+ Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer);
+ if (navigation_polygon.is_valid()) {
+ Vector<Vector2> verts = navigation_polygon->get_vertices();
+ if (verts.size() < 3) {
+ return;
+ }
+
+ Color color = p_canvas_item->get_tree()->get_debug_navigation_color();
+
+ RandomPCG rand;
+ for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) {
+ // An array of vertices for this polygon.
+ Vector<int> polygon = navigation_polygon->get_polygon(i);
+ Vector<Vector2> vertices;
+ vertices.resize(polygon.size());
+ for (int j = 0; j < polygon.size(); j++) {
+ ERR_FAIL_INDEX(polygon[j], verts.size());
+ vertices.write[j] = verts[polygon[j]];
+ }
+
+ // Generate the polygon color, slightly randomly modified from the settings one.
+ Color random_variation_color;
+ random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1);
+ random_variation_color.a = color.a;
+ Vector<Color> colors;
+ colors.push_back(random_variation_color);
+
+ RenderingServer::get_singleton()->canvas_item_add_polygon(p_canvas_item->get_canvas_item(), vertices, colors);
+ }
+ }
+
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
+ }
+ }
+}
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
new file mode 100644
index 0000000000..b82189e1ee
--- /dev/null
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -0,0 +1,117 @@
+/*************************************************************************/
+/* tile_data_editors.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TILE_DATA_EDITORS_H
+#define TILE_DATA_EDITORS_H
+
+#include "scene/gui/control.h"
+#include "scene/resources/tile_set.h"
+
+class TileDataEditor : public Control {
+ GDCLASS(TileDataEditor, Control);
+
+protected:
+ TileData *tile_data;
+ String property;
+
+ TileData *_get_tile_data(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile);
+
+public:
+ // Edits a TileData property.
+ void edit(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property);
+
+ // Used to draw the value over a tile.
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property){};
+};
+
+class TileDataTextureOffsetEditor : public TileDataEditor {
+ GDCLASS(TileDataTextureOffsetEditor, TileDataEditor);
+
+public:
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+};
+
+class TileDataIntegerEditor : public TileDataEditor {
+ GDCLASS(TileDataIntegerEditor, TileDataEditor);
+
+public:
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+};
+
+class TileDataFloatEditor : public TileDataEditor {
+ GDCLASS(TileDataFloatEditor, TileDataEditor);
+
+public:
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+};
+
+class TileDataPositionEditor : public TileDataEditor {
+ GDCLASS(TileDataPositionEditor, TileDataEditor);
+
+public:
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+};
+
+class TileDataYSortEditor : public TileDataEditor {
+ GDCLASS(TileDataYSortEditor, TileDataEditor);
+
+public:
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+};
+
+class TileDataOcclusionShapeEditor : public TileDataEditor {
+ GDCLASS(TileDataOcclusionShapeEditor, TileDataEditor);
+
+public:
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+};
+
+class TileDataCollisionShapeEditor : public TileDataEditor {
+ GDCLASS(TileDataCollisionShapeEditor, TileDataEditor);
+
+public:
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+};
+
+class TileDataTerrainsEditor : public TileDataEditor {
+ GDCLASS(TileDataTerrainsEditor, TileDataEditor);
+
+public:
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+};
+
+class TileDataNavigationPolygonEditor : public TileDataEditor {
+ GDCLASS(TileDataNavigationPolygonEditor, TileDataEditor);
+
+public:
+ virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override;
+};
+
+#endif // TILE_DATA_EDITORS_H
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
new file mode 100644
index 0000000000..ef13d8ea12
--- /dev/null
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -0,0 +1,3570 @@
+/*************************************************************************/
+/* tile_map_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "tile_map_editor.h"
+
+#include "tiles_editor_plugin.h"
+
+#include "editor/editor_resource_preview.h"
+#include "editor/editor_scale.h"
+#include "editor/plugins/canvas_item_editor_plugin.h"
+
+#include "scene/gui/center_container.h"
+#include "scene/gui/split_container.h"
+
+#include "core/input/input.h"
+#include "core/math/geometry_2d.h"
+#include "core/os/keyboard.h"
+
+void TileMapEditorTilesPlugin::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ select_tool_button->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
+ paint_tool_button->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ line_tool_button->set_icon(get_theme_icon("CurveLinear", "EditorIcons"));
+ rect_tool_button->set_icon(get_theme_icon("Rectangle", "EditorIcons"));
+ bucket_tool_button->set_icon(get_theme_icon("Bucket", "EditorIcons"));
+
+ picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons"));
+ erase_button->set_icon(get_theme_icon("Eraser", "EditorIcons"));
+
+ toggle_grid_button->set_icon(get_theme_icon("Grid", "EditorIcons"));
+
+ missing_atlas_texture_icon = get_theme_icon("TileSet", "EditorIcons");
+
+ toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid"));
+ break;
+ case NOTIFICATION_VISIBILITY_CHANGED:
+ _stop_dragging();
+ break;
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED:
+ toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid"));
+ break;
+ }
+}
+
+void TileMapEditorTilesPlugin::tile_set_changed() {
+ _update_fix_selected_and_hovered();
+ _update_tile_set_sources_list();
+ _update_bottom_panel();
+}
+
+void TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled(bool p_pressed) {
+ scatter_spinbox->set_editable(p_pressed);
+}
+
+void TileMapEditorTilesPlugin::_on_scattering_spinbox_changed(double p_value) {
+ scattering = p_value;
+}
+
+void TileMapEditorTilesPlugin::_on_grid_toggled(bool p_pressed) {
+ EditorSettings::get_singleton()->set("editors/tiles_editor/display_grid", p_pressed);
+}
+
+void TileMapEditorTilesPlugin::_update_toolbar() {
+ // Stop draggig if needed.
+ _stop_dragging();
+
+ // Hide all settings.
+ for (int i = 0; i < tools_settings->get_child_count(); i++) {
+ Object::cast_to<CanvasItem>(tools_settings->get_child(i))->hide();
+ }
+
+ // Show only the correct settings.
+ if (tool_buttons_group->get_pressed_button() == select_tool_button) {
+ } else if (tool_buttons_group->get_pressed_button() == paint_tool_button) {
+ tools_settings_vsep->show();
+ picker_button->show();
+ erase_button->show();
+ tools_settings_vsep_2->show();
+ random_tile_checkbox->show();
+ scatter_label->show();
+ scatter_spinbox->show();
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button) {
+ tools_settings_vsep->show();
+ picker_button->show();
+ erase_button->show();
+ tools_settings_vsep_2->show();
+ random_tile_checkbox->show();
+ scatter_label->show();
+ scatter_spinbox->show();
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button) {
+ tools_settings_vsep->show();
+ picker_button->show();
+ erase_button->show();
+ tools_settings_vsep_2->show();
+ random_tile_checkbox->show();
+ scatter_label->show();
+ scatter_spinbox->show();
+ } else if (tool_buttons_group->get_pressed_button() == bucket_tool_button) {
+ tools_settings_vsep->show();
+ picker_button->show();
+ erase_button->show();
+ tools_settings_vsep_2->show();
+ bucket_continuous_checkbox->show();
+ random_tile_checkbox->show();
+ scatter_label->show();
+ scatter_spinbox->show();
+ }
+}
+
+Control *TileMapEditorTilesPlugin::get_toolbar() const {
+ return toolbar;
+}
+
+void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
+ // Update the sources.
+ int old_current = sources_list->get_current();
+ sources_list->clear();
+
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ for (int i = 0; i < tile_set->get_source_count(); i++) {
+ int source_id = tile_set->get_source_id(i);
+
+ TileSetSource *source = *tile_set->get_source(source_id);
+
+ Ref<Texture2D> texture;
+ String item_text;
+
+ // Atlas source.
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ texture = atlas_source->get_texture();
+ if (texture.is_valid()) {
+ item_text = vformat("%s (id:%d)", texture->get_path().get_file(), source_id);
+ } else {
+ item_text = vformat("No Texture Atlas Source (id:%d)", source_id);
+ }
+ }
+
+ // Scene collection source.
+ TileSetScenesCollectionSource *scene_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
+ if (scene_collection_source) {
+ texture = get_theme_icon("PackedScene", "EditorIcons");
+ item_text = vformat(TTR("Scene Collection Source (id:%d)"), source_id);
+ }
+
+ // Use default if not valid.
+ if (item_text.is_empty()) {
+ item_text = vformat(TTR("Unknown Type Source (id:%d)"), source_id);
+ }
+ if (!texture.is_valid()) {
+ texture = missing_atlas_texture_icon;
+ }
+
+ sources_list->add_item(item_text, texture);
+ sources_list->set_item_metadata(i, source_id);
+ }
+
+ if (sources_list->get_item_count() > 0) {
+ if (old_current > 0) {
+ // Keep the current selected item if needed.
+ sources_list->set_current(CLAMP(old_current, 0, sources_list->get_item_count() - 1));
+ } else {
+ sources_list->set_current(0);
+ }
+ sources_list->emit_signal("item_selected", sources_list->get_current());
+ }
+
+ // Synchronize
+ TilesEditor::get_singleton()->set_atlas_sources_lists_current(sources_list->get_current());
+}
+
+void TileMapEditorTilesPlugin::_update_bottom_panel() {
+ // Update the atlas display.
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ int source_index = sources_list->get_current();
+ if (source_index >= 0 && source_index < sources_list->get_item_count()) {
+ atlas_sources_split_container->show();
+ missing_source_label->hide();
+
+ int source_id = sources_list->get_item_metadata(source_index);
+ TileSetSource *source = *tile_set->get_source(source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
+
+ if (atlas_source) {
+ tile_atlas_view->show();
+ scene_tiles_list->hide();
+ invalid_source_label->hide();
+ _update_atlas_view();
+ } else if (scenes_collection_source) {
+ tile_atlas_view->hide();
+ scene_tiles_list->show();
+ invalid_source_label->hide();
+ _update_scenes_collection_view();
+ } else {
+ tile_atlas_view->hide();
+ scene_tiles_list->hide();
+ invalid_source_label->show();
+ }
+ } else {
+ atlas_sources_split_container->hide();
+ missing_source_label->show();
+
+ tile_atlas_view->hide();
+ scene_tiles_list->hide();
+ invalid_source_label->hide();
+ }
+}
+
+void TileMapEditorTilesPlugin::_update_atlas_view() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ int source_id = sources_list->get_item_metadata(sources_list->get_current());
+ TileSetSource *source = *tile_set->get_source(source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ ERR_FAIL_COND(!atlas_source);
+
+ tile_atlas_view->set_atlas_source(*tile_map->get_tileset(), atlas_source, source_id);
+ TilesEditor::get_singleton()->synchronize_atlas_view(tile_atlas_view);
+ tile_atlas_control->update();
+}
+
+void TileMapEditorTilesPlugin::_update_scenes_collection_view() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ int source_id = sources_list->get_item_metadata(sources_list->get_current());
+ TileSetSource *source = *tile_set->get_source(source_id);
+ TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
+ ERR_FAIL_COND(!scenes_collection_source);
+
+ // Clear the list.
+ scene_tiles_list->clear();
+
+ // Rebuild the list.
+ for (int i = 0; i < scenes_collection_source->get_scene_tiles_count(); i++) {
+ int scene_id = scenes_collection_source->get_scene_tile_id(i);
+
+ Ref<PackedScene> scene = scenes_collection_source->get_scene_tile_scene(scene_id);
+
+ int item_index = 0;
+ if (scene.is_valid()) {
+ item_index = scene_tiles_list->add_item(vformat("%s (path:%s id:%d)", scene->get_path().get_file().get_basename(), scene->get_path(), scene_id));
+ Variant udata = i;
+ EditorResourcePreview::get_singleton()->queue_edited_resource_preview(scene, this, "_scene_thumbnail_done", udata);
+ } else {
+ item_index = scene_tiles_list->add_item(TTR("Tile with Invalid Scene"), get_theme_icon("PackedScene", "EditorIcons"));
+ }
+ scene_tiles_list->set_item_metadata(item_index, scene_id);
+
+ // Check if in selection.
+ if (tile_set_selection.has(TileMapCell(source_id, Vector2i(), scene_id))) {
+ scene_tiles_list->select(item_index, false);
+ }
+ }
+
+ // Icon size update.
+ int int_size = int(EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size")) * EDSCALE;
+ scene_tiles_list->set_fixed_icon_size(Vector2(int_size, int_size));
+}
+
+void TileMapEditorTilesPlugin::_scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud) {
+ int index = p_ud;
+
+ if (index >= 0 && index < scene_tiles_list->get_item_count()) {
+ scene_tiles_list->set_item_icon(index, p_preview);
+ }
+}
+
+void TileMapEditorTilesPlugin::_scenes_list_multi_selected(int p_index, bool p_selected) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ // Add or remove the Tile form the selection.
+ int scene_id = scene_tiles_list->get_item_metadata(p_index);
+ int source_id = sources_list->get_item_metadata(sources_list->get_current());
+ TileSetSource *source = *tile_set->get_source(source_id);
+ TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
+ ERR_FAIL_COND(!scenes_collection_source);
+
+ TileMapCell selected = TileMapCell(source_id, Vector2i(), scene_id);
+
+ // Clear the selection if shift is not pressed.
+ if (!Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ tile_set_selection.clear();
+ }
+
+ if (p_selected) {
+ tile_set_selection.insert(selected);
+ } else {
+ if (tile_set_selection.has(selected)) {
+ tile_set_selection.erase(selected);
+ }
+ }
+
+ _update_selection_pattern_from_tileset_selection();
+}
+
+void TileMapEditorTilesPlugin::_scenes_list_nothing_selected() {
+ scene_tiles_list->deselect_all();
+ tile_set_selection.clear();
+ tile_map_selection.clear();
+ selection_pattern->clear();
+ _update_selection_pattern_from_tileset_selection();
+}
+
+bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
+ if (!is_visible_in_tree()) {
+ // If the bottom editor is not visible, we ignore inputs.
+ return false;
+ }
+
+ if (CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) {
+ return false;
+ }
+
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return false;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return false;
+ }
+
+ // Shortcuts
+ if (ED_IS_SHORTCUT("tiles_editor/cut", p_event) || ED_IS_SHORTCUT("tiles_editor/copy", p_event)) {
+ // Fill in the clipboard.
+ if (!tile_map_selection.is_empty()) {
+ memdelete(tile_map_clipboard);
+ TypedArray<Vector2i> coords_array;
+ for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
+ coords_array.push_back(E->get());
+ }
+ tile_map_clipboard = tile_map->get_pattern(coords_array);
+ }
+
+ if (ED_IS_SHORTCUT("tiles_editor/cut", p_event)) {
+ // Delete selected tiles.
+ if (!tile_map_selection.is_empty()) {
+ undo_redo->create_action(TTR("Delete tiles"));
+ for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
+ undo_redo->add_do_method(tile_map, "set_cell", E->get(), -1, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ undo_redo->add_undo_method(tile_map, "set_cell", E->get(), tile_map->get_cell_source_id(E->get()), tile_map->get_cell_atlas_coords(E->get()), tile_map->get_cell_alternative_tile(E->get()));
+ }
+ undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
+ tile_map_selection.clear();
+ undo_redo->add_do_method(this, "_set_tile_map_selection", _get_tile_map_selection());
+ undo_redo->commit_action();
+ }
+ }
+
+ return true;
+ }
+ if (ED_IS_SHORTCUT("tiles_editor/paste", p_event)) {
+ if (drag_type == DRAG_TYPE_NONE) {
+ drag_type = DRAG_TYPE_CLIPBOARD_PASTE;
+ }
+ CanvasItemEditor::get_singleton()->update_viewport();
+ return true;
+ }
+ if (ED_IS_SHORTCUT("tiles_editor/cancel", p_event)) {
+ if (drag_type == DRAG_TYPE_CLIPBOARD_PASTE) {
+ drag_type = DRAG_TYPE_NONE;
+ CanvasItemEditor::get_singleton()->update_viewport();
+ return true;
+ }
+ }
+ if (ED_IS_SHORTCUT("tiles_editor/delete", p_event)) {
+ // Delete selected tiles.
+ if (!tile_map_selection.is_empty()) {
+ undo_redo->create_action(TTR("Delete tiles"));
+ for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
+ undo_redo->add_do_method(tile_map, "set_cell", E->get(), -1, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ undo_redo->add_undo_method(tile_map, "set_cell", E->get(), tile_map->get_cell_source_id(E->get()), tile_map->get_cell_atlas_coords(E->get()), tile_map->get_cell_alternative_tile(E->get()));
+ }
+ undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
+ tile_map_selection.clear();
+ undo_redo->add_do_method(this, "_set_tile_map_selection", _get_tile_map_selection());
+ undo_redo->commit_action();
+ }
+ return true;
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ has_mouse = true;
+ Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
+ Vector2 mpos = xform.affine_inverse().xform(mm->get_position());
+
+ switch (drag_type) {
+ case DRAG_TYPE_PAINT: {
+ Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, drag_last_mouse_pos, mpos);
+ for (Map<Vector2i, TileMapCell>::Element *E = to_draw.front(); E; E = E->next()) {
+ if (!erase_button->is_pressed() && E->get().source_id == -1) {
+ continue;
+ }
+ Vector2i coords = E->key();
+ if (!drag_modified.has(coords)) {
+ drag_modified.insert(coords, TileMapCell(tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords)));
+ }
+ tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ } break;
+ case DRAG_TYPE_BUCKET: {
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
+ for (int i = 0; i < line.size(); i++) {
+ if (!drag_modified.has(line[i])) {
+ Map<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_continuous_checkbox->is_pressed());
+ for (Map<Vector2i, TileMapCell>::Element *E = to_draw.front(); E; E = E->next()) {
+ if (!erase_button->is_pressed() && E->get().source_id == -1) {
+ continue;
+ }
+ Vector2i coords = E->key();
+ if (!drag_modified.has(coords)) {
+ drag_modified.insert(coords, TileMapCell(tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords)));
+ }
+ tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ drag_last_mouse_pos = mpos;
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ return true;
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ has_mouse = true;
+ Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
+ Vector2 mpos = xform.affine_inverse().xform(mb->get_position());
+
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ // Pressed
+ if (tool_buttons_group->get_pressed_button() == select_tool_button) {
+ drag_start_mouse_pos = mpos;
+ if (tile_map_selection.has(tile_map->world_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed()) {
+ // Move the selection
+ drag_type = DRAG_TYPE_MOVE;
+ drag_modified.clear();
+ for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
+ Vector2i coords = E->get();
+ drag_modified.insert(coords, TileMapCell(tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords)));
+ tile_map->set_cell(coords, -1, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ }
+ } else {
+ // Select tiles
+ drag_type = DRAG_TYPE_SELECT;
+ }
+ } else {
+ // Check if we are picking a tile.
+ if (picker_button->is_pressed()) {
+ drag_type = DRAG_TYPE_PICK;
+ drag_start_mouse_pos = mpos;
+ } else {
+ // Paint otherwise.
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button) {
+ drag_type = DRAG_TYPE_PAINT;
+ drag_start_mouse_pos = mpos;
+ drag_modified.clear();
+ Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, mpos, mpos);
+ for (Map<Vector2i, TileMapCell>::Element *E = to_draw.front(); E; E = E->next()) {
+ if (!erase_button->is_pressed() && E->get().source_id == -1) {
+ continue;
+ }
+ Vector2i coords = E->key();
+ if (!drag_modified.has(coords)) {
+ drag_modified.insert(coords, TileMapCell(tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords)));
+ }
+ tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button) {
+ drag_type = DRAG_TYPE_LINE;
+ drag_start_mouse_pos = mpos;
+ drag_modified.clear();
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button) {
+ drag_type = DRAG_TYPE_RECT;
+ drag_start_mouse_pos = mpos;
+ drag_modified.clear();
+ } else if (tool_buttons_group->get_pressed_button() == bucket_tool_button) {
+ drag_type = DRAG_TYPE_BUCKET;
+ drag_start_mouse_pos = mpos;
+ drag_modified.clear();
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
+ for (int i = 0; i < line.size(); i++) {
+ if (!drag_modified.has(line[i])) {
+ Map<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_continuous_checkbox->is_pressed());
+ for (Map<Vector2i, TileMapCell>::Element *E = to_draw.front(); E; E = E->next()) {
+ if (!erase_button->is_pressed() && E->get().source_id == -1) {
+ continue;
+ }
+ Vector2i coords = E->key();
+ if (!drag_modified.has(coords)) {
+ drag_modified.insert(coords, TileMapCell(tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords)));
+ }
+ tile_map->set_cell(coords, E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ } else {
+ // Released
+ _stop_dragging();
+ }
+
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ return true;
+ }
+ drag_last_mouse_pos = mpos;
+ }
+
+ return false;
+}
+
+void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ if (!tile_map->is_visible_in_tree()) {
+ return;
+ }
+
+ Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
+ Vector2i tile_shape_size = tile_set->get_tile_size();
+
+ // Draw the selection.
+ if (is_visible_in_tree() && tool_buttons_group->get_pressed_button() == select_tool_button) {
+ // In select mode, we only draw the current selection if we are modifying it (pressing control or shift).
+ if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
+ // Do nothing
+ } else {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+ tile_map->draw_cells_outline(p_overlay, tile_map_selection, selection_color, xform);
+ }
+ }
+
+ // Handle the preview of the tiles to be placed.
+ if (is_visible_in_tree() && has_mouse) { // Only if the tilemap editor is opened and the viewport is hovered.
+ Map<Vector2i, TileMapCell> preview;
+ Rect2i drawn_grid_rect;
+
+ if (drag_type == DRAG_TYPE_PICK) {
+ // Draw the area being picvked.
+ Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
+ rect.size += Vector2i(1, 1);
+ for (int x = rect.position.x; x < rect.get_end().x; x++) {
+ for (int y = rect.position.y; y < rect.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ if (tile_map->get_cell_source_id(coords) != -1) {
+ Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - tile_shape_size / 2, tile_shape_size));
+ tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0), false);
+ }
+ }
+ }
+ } else if (drag_type == DRAG_TYPE_SELECT) {
+ // Draw the area being selected.
+ Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
+ rect.size += Vector2i(1, 1);
+ Set<Vector2i> to_draw;
+ for (int x = rect.position.x; x < rect.get_end().x; x++) {
+ for (int y = rect.position.y; y < rect.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ if (tile_map->get_cell_source_id(coords) != -1) {
+ to_draw.insert(coords);
+ }
+ }
+ }
+ tile_map->draw_cells_outline(p_overlay, to_draw, Color(1.0, 1.0, 1.0), xform);
+ } else if (drag_type == DRAG_TYPE_MOVE) {
+ // Preview when moving.
+ Vector2i top_left;
+ if (!tile_map_selection.is_empty()) {
+ top_left = tile_map_selection.front()->get();
+ }
+ for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
+ top_left = top_left.min(E->get());
+ }
+ Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
+ offset = tile_map->world_to_map(drag_last_mouse_pos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
+
+ TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
+ for (int i = 0; i < selection_used_cells.size(); i++) {
+ Vector2i coords = tile_map->map_pattern(offset + top_left, selection_used_cells[i], selection_pattern);
+ preview[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i]));
+ }
+ } else if (drag_type == DRAG_TYPE_CLIPBOARD_PASTE) {
+ // Preview when pasting.
+ Vector2 mouse_offset = (Vector2(tile_map_clipboard->get_size()) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
+ TypedArray<Vector2i> clipboard_used_cells = tile_map_clipboard->get_used_cells();
+ for (int i = 0; i < clipboard_used_cells.size(); i++) {
+ Vector2i coords = tile_map->map_pattern(tile_map->world_to_map(drag_last_mouse_pos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard);
+ preview[coords] = TileMapCell(tile_map_clipboard->get_cell_source_id(clipboard_used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(clipboard_used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(clipboard_used_cells[i]));
+ }
+ } else if (!picker_button->is_pressed()) {
+ bool expand_grid = false;
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
+ // Preview for a single pattern.
+ preview = _draw_line(drag_last_mouse_pos, drag_last_mouse_pos, drag_last_mouse_pos);
+ expand_grid = true;
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button) {
+ if (drag_type == DRAG_TYPE_NONE) {
+ // Preview for a single pattern.
+ preview = _draw_line(drag_last_mouse_pos, drag_last_mouse_pos, drag_last_mouse_pos);
+ expand_grid = true;
+ } else if (drag_type == DRAG_TYPE_LINE) {
+ // Preview for a line pattern.
+ preview = _draw_line(drag_start_mouse_pos, drag_start_mouse_pos, drag_last_mouse_pos);
+ expand_grid = true;
+ }
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button && drag_type == DRAG_TYPE_RECT) {
+ // Preview for a line pattern.
+ preview = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos));
+ expand_grid = true;
+ } else if (tool_buttons_group->get_pressed_button() == bucket_tool_button && drag_type == DRAG_TYPE_NONE) {
+ // Preview for a line pattern.
+ preview = _draw_bucket_fill(tile_map->world_to_map(drag_last_mouse_pos), bucket_continuous_checkbox->is_pressed());
+ }
+
+ // Expand the grid if needed
+ if (expand_grid && !preview.is_empty()) {
+ drawn_grid_rect = Rect2i(preview.front()->key(), Vector2i(1, 1));
+ for (Map<Vector2i, TileMapCell>::Element *E = preview.front(); E; E = E->next()) {
+ drawn_grid_rect.expand_to(E->key());
+ }
+ }
+ }
+
+ if (!preview.is_empty()) {
+ const int fading = 5;
+
+ // Draw the lines of the grid behind the preview.
+ bool display_grid = EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid");
+ if (display_grid) {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ if (drawn_grid_rect.size.x > 0 && drawn_grid_rect.size.y > 0) {
+ drawn_grid_rect = drawn_grid_rect.grow(fading);
+ for (int x = drawn_grid_rect.position.x; x < (drawn_grid_rect.position.x + drawn_grid_rect.size.x); x++) {
+ for (int y = drawn_grid_rect.position.y; y < (drawn_grid_rect.position.y + drawn_grid_rect.size.y); y++) {
+ Vector2i pos_in_rect = Vector2i(x, y) - drawn_grid_rect.position;
+
+ // Fade out the border of the grid.
+ float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f);
+ float right_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.x, (float)(drawn_grid_rect.size.x - fading), (float)pos_in_rect.x), 0.0f, 1.0f);
+ float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f);
+ float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f);
+ float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
+
+ Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(Vector2(x, y)) - tile_shape_size / 2, tile_shape_size));
+ Color color = grid_color;
+ color.a = color.a * opacity;
+ tile_set->draw_tile_shape(p_overlay, cell_region, color, false);
+ }
+ }
+ }
+ }
+
+ // Draw the preview.
+ for (Map<Vector2i, TileMapCell>::Element *E = preview.front(); E; E = E->next()) {
+ Vector2i size = tile_set->get_tile_size();
+ Vector2 position = tile_map->map_to_world(E->key()) - size / 2;
+ Rect2 cell_region = xform.xform(Rect2(position, size));
+ if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
+ tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0, 0.5), true);
+ } else {
+ if (tile_set->has_source(E->get().source_id)) {
+ TileSetSource *source = *tile_set->get_source(E->get().source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile));
+
+ // Compute the offset
+ Rect2i source_rect = atlas_source->get_tile_texture_region(E->get().get_atlas_coords());
+ Vector2i tile_offset = atlas_source->get_tile_effective_texture_offset(E->get().get_atlas_coords(), E->get().alternative_tile);
+
+ // Compute the destination rectangle in the CanvasItem.
+ Rect2 dest_rect;
+ dest_rect.size = source_rect.size;
+
+ bool transpose = tile_data->get_transpose();
+ if (transpose) {
+ dest_rect.position = (tile_map->map_to_world(E->key()) - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
+ } else {
+ dest_rect.position = (tile_map->map_to_world(E->key()) - dest_rect.size / 2 - tile_offset);
+ }
+
+ dest_rect = xform.xform(dest_rect);
+
+ if (tile_data->get_flip_h()) {
+ dest_rect.size.x = -dest_rect.size.x;
+ }
+
+ if (tile_data->get_flip_v()) {
+ dest_rect.size.y = -dest_rect.size.y;
+ }
+
+ // Get the tile modulation.
+ Color modulate = tile_data->get_modulate();
+ Color self_modulate = tile_map->get_self_modulate();
+ modulate = Color(modulate.r * self_modulate.r, modulate.g * self_modulate.g, modulate.b * self_modulate.b, modulate.a * self_modulate.a);
+
+ // Draw the tile.
+ p_overlay->draw_texture_rect_region(atlas_source->get_texture(), dest_rect, source_rect, modulate * Color(1.0, 1.0, 1.0, 0.5), transpose, tile_set->is_uv_clipping());
+ } else {
+ tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0, 0.5), true);
+ }
+ } else {
+ tile_set->draw_tile_shape(p_overlay, cell_region, Color(0.0, 0.0, 0.0, 0.5), true);
+ }
+ }
+ }
+ }
+ }
+}
+
+void TileMapEditorTilesPlugin::_mouse_exited_viewport() {
+ has_mouse = false;
+ CanvasItemEditor::get_singleton()->update_viewport();
+}
+
+TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(const TileMapPattern *p_pattern) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return TileMapCell();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return TileMapCell();
+ }
+
+ TypedArray<Vector2i> used_cells = p_pattern->get_used_cells();
+ double sum = 0.0;
+ for (int i = 0; i < used_cells.size(); i++) {
+ int source_id = p_pattern->get_cell_source_id(used_cells[i]);
+ Vector2i atlas_coords = p_pattern->get_cell_atlas_coords(used_cells[i]);
+ int alternative_tile = p_pattern->get_cell_alternative_tile(used_cells[i]);
+
+ TileSetSource *source = *tile_set->get_source(source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(atlas_coords, alternative_tile));
+ ERR_FAIL_COND_V(!tile_data, TileMapCell());
+ sum += tile_data->get_probability();
+ } else {
+ sum += 1.0;
+ }
+ }
+
+ double empty_probability = sum * scattering;
+ double current = 0.0;
+ double rand = Math::random(0.0, sum + empty_probability);
+ for (int i = 0; i < used_cells.size(); i++) {
+ int source_id = p_pattern->get_cell_source_id(used_cells[i]);
+ Vector2i atlas_coords = p_pattern->get_cell_atlas_coords(used_cells[i]);
+ int alternative_tile = p_pattern->get_cell_alternative_tile(used_cells[i]);
+
+ TileSetSource *source = *tile_set->get_source(source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ current += Object::cast_to<TileData>(atlas_source->get_tile_data(atlas_coords, alternative_tile))->get_probability();
+ } else {
+ current += 1.0;
+ }
+
+ if (current >= rand) {
+ return TileMapCell(source_id, atlas_coords, alternative_tile);
+ }
+ }
+ return TileMapCell();
+}
+
+Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ // Get or create the pattern.
+ TileMapPattern erase_pattern;
+ erase_pattern.set_cell(Vector2i(0, 0), -1, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ TileMapPattern *pattern = erase_button->is_pressed() ? &erase_pattern : selection_pattern;
+
+ Map<Vector2i, TileMapCell> output;
+ if (!pattern->is_empty()) {
+ // Paint the tiles on the tile map.
+ if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
+ // Paint a random tile.
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(p_from_mouse_pos), tile_map->world_to_map(p_to_mouse_pos));
+ for (int i = 0; i < line.size(); i++) {
+ output.insert(line[i], _pick_random_tile(pattern));
+ }
+ } else {
+ // Paint the pattern.
+ // If we paint several tiles, we virtually move the mouse as if it was in the center of the "brush"
+ Vector2 mouse_offset = (Vector2(pattern->get_size()) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
+ Vector2i last_hovered_cell = tile_map->world_to_map(p_from_mouse_pos - mouse_offset);
+ Vector2i new_hovered_cell = tile_map->world_to_map(p_to_mouse_pos - mouse_offset);
+ Vector2i drag_start_cell = tile_map->world_to_map(p_start_drag_mouse_pos - mouse_offset);
+
+ TypedArray<Vector2i> used_cells = pattern->get_used_cells();
+ Vector2i offset = Vector2i(Math::posmod(drag_start_cell.x, pattern->get_size().x), Math::posmod(drag_start_cell.y, pattern->get_size().y)); // Note: no posmodv for Vector2i for now. Meh.s
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, (last_hovered_cell - offset) / pattern->get_size(), (new_hovered_cell - offset) / pattern->get_size());
+ for (int i = 0; i < line.size(); i++) {
+ Vector2i top_left = line[i] * pattern->get_size() + offset;
+ for (int j = 0; j < used_cells.size(); j++) {
+ Vector2i coords = tile_map->map_pattern(top_left, used_cells[j], pattern);
+ output.insert(coords, TileMapCell(pattern->get_cell_source_id(used_cells[j]), pattern->get_cell_atlas_coords(used_cells[j]), pattern->get_cell_alternative_tile(used_cells[j])));
+ }
+ }
+ }
+ }
+ return output;
+}
+
+Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start_cell, Vector2i p_end_cell) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ // Create the rect to draw.
+ Rect2i rect = Rect2i(p_start_cell, p_end_cell - p_start_cell).abs();
+ rect.size += Vector2i(1, 1);
+
+ // Get or create the pattern.
+ TileMapPattern erase_pattern;
+ erase_pattern.set_cell(Vector2i(0, 0), -1, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ TileMapPattern *pattern = erase_button->is_pressed() ? &erase_pattern : selection_pattern;
+
+ // Compute the offset to align things to the bottom or right.
+ bool aligned_right = p_end_cell.x < p_start_cell.x;
+ bool valigned_bottom = p_end_cell.y < p_start_cell.y;
+ Vector2i offset = Vector2i(aligned_right ? -(pattern->get_size().x - (rect.get_size().x % pattern->get_size().x)) : 0, valigned_bottom ? -(pattern->get_size().y - (rect.get_size().y % pattern->get_size().y)) : 0);
+
+ Map<Vector2i, TileMapCell> output;
+ if (!pattern->is_empty()) {
+ if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
+ // Paint a random tile.
+ for (int x = 0; x < rect.size.x; x++) {
+ for (int y = 0; y < rect.size.y; y++) {
+ Vector2i coords = rect.position + Vector2i(x, y);
+ output.insert(coords, _pick_random_tile(pattern));
+ }
+ }
+ } else {
+ // Paint the pattern.
+ TypedArray<Vector2i> used_cells = pattern->get_used_cells();
+ for (int x = 0; x <= rect.size.x / pattern->get_size().x; x++) {
+ for (int y = 0; y <= rect.size.y / pattern->get_size().y; y++) {
+ Vector2i pattern_coords = rect.position + Vector2i(x, y) * pattern->get_size() + offset;
+ for (int j = 0; j < used_cells.size(); j++) {
+ Vector2i coords = pattern_coords + used_cells[j];
+ if (rect.has_point(coords)) {
+ output.insert(coords, TileMapCell(pattern->get_cell_source_id(used_cells[j]), pattern->get_cell_atlas_coords(used_cells[j]), pattern->get_cell_alternative_tile(used_cells[j])));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return output;
+}
+
+Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i p_coords, bool p_contiguous) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ // Get or create the pattern.
+ TileMapPattern erase_pattern;
+ erase_pattern.set_cell(Vector2i(0, 0), -1, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ TileMapPattern *pattern = erase_button->is_pressed() ? &erase_pattern : selection_pattern;
+
+ Map<Vector2i, TileMapCell> output;
+ if (!pattern->is_empty()) {
+ TileMapCell source = tile_map->get_cell(p_coords);
+
+ // If we are filling empty tiles, compute the tilemap boundaries.
+ Rect2i boundaries;
+ if (source.source_id == -1) {
+ boundaries = tile_map->get_used_rect();
+ }
+
+ if (p_contiguous) {
+ // Replace continuous tiles like the source.
+ Set<Vector2i> already_checked;
+ List<Vector2i> to_check;
+ to_check.push_back(p_coords);
+ while (!to_check.is_empty()) {
+ Vector2i coords = to_check.back()->get();
+ to_check.pop_back();
+ if (!already_checked.has(coords)) {
+ if (source.source_id == tile_map->get_cell_source_id(coords) &&
+ source.get_atlas_coords() == tile_map->get_cell_atlas_coords(coords) &&
+ source.alternative_tile == tile_map->get_cell_alternative_tile(coords) &&
+ (source.source_id != -1 || boundaries.has_point(coords))) {
+ if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
+ // Paint a random tile.
+ output.insert(coords, _pick_random_tile(pattern));
+ } else {
+ // Paint the pattern.
+ Vector2i pattern_coords = (coords - p_coords) % pattern->get_size(); // Note: it would be good to have posmodv for Vector2i.
+ pattern_coords.x = pattern_coords.x < 0 ? pattern_coords.x + pattern->get_size().x : pattern_coords.x;
+ pattern_coords.y = pattern_coords.y < 0 ? pattern_coords.y + pattern->get_size().y : pattern_coords.y;
+ if (pattern->has_cell(pattern_coords)) {
+ output.insert(coords, TileMapCell(pattern->get_cell_source_id(pattern_coords), pattern->get_cell_atlas_coords(pattern_coords), pattern->get_cell_alternative_tile(pattern_coords)));
+ } else {
+ output.insert(coords, TileMapCell());
+ }
+ }
+
+ // Get surrounding tiles (handles different tile shapes).
+ TypedArray<Vector2i> around = tile_map->get_surrounding_tiles(coords);
+ for (int i = 0; i < around.size(); i++) {
+ to_check.push_back(around[i]);
+ }
+ }
+ already_checked.insert(coords);
+ }
+ }
+ } else {
+ // Replace all tiles like the source.
+ TypedArray<Vector2i> to_check;
+ if (source.source_id == -1) {
+ Rect2i rect = tile_map->get_used_rect();
+ if (rect.size.x <= 0 || rect.size.y <= 0) {
+ rect = Rect2i(p_coords, Vector2i(1, 1));
+ }
+ for (int x = boundaries.position.x; x < boundaries.get_end().x; x++) {
+ for (int y = boundaries.position.y; y < boundaries.get_end().y; y++) {
+ to_check.append(Vector2i(x, y));
+ }
+ }
+ } else {
+ to_check = tile_map->get_used_cells();
+ }
+ for (int i = 0; i < to_check.size(); i++) {
+ Vector2i coords = to_check[i];
+ if (source.source_id == tile_map->get_cell_source_id(coords) &&
+ source.get_atlas_coords() == tile_map->get_cell_atlas_coords(coords) &&
+ source.alternative_tile == tile_map->get_cell_alternative_tile(coords) &&
+ (source.source_id != -1 || boundaries.has_point(coords))) {
+ if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
+ // Paint a random tile.
+ output.insert(coords, _pick_random_tile(pattern));
+ } else {
+ // Paint the pattern.
+ Vector2i pattern_coords = (coords - p_coords) % pattern->get_size(); // Note: it would be good to have posmodv for Vector2i.
+ pattern_coords.x = pattern_coords.x < 0 ? pattern_coords.x + pattern->get_size().x : pattern_coords.x;
+ pattern_coords.y = pattern_coords.y < 0 ? pattern_coords.y + pattern->get_size().y : pattern_coords.y;
+ if (pattern->has_cell(pattern_coords)) {
+ output.insert(coords, TileMapCell(pattern->get_cell_source_id(pattern_coords), pattern->get_cell_atlas_coords(pattern_coords), pattern->get_cell_alternative_tile(pattern_coords)));
+ } else {
+ output.insert(coords, TileMapCell());
+ }
+ }
+ }
+ }
+ }
+ }
+ return output;
+}
+
+void TileMapEditorTilesPlugin::_stop_dragging() {
+ if (drag_type == DRAG_TYPE_NONE) {
+ return;
+ }
+
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
+ Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position());
+
+ switch (drag_type) {
+ case DRAG_TYPE_SELECT: {
+ undo_redo->create_action(TTR("Change selection"));
+ undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
+
+ if (!Input::get_singleton()->is_key_pressed(KEY_SHIFT) && !Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
+ tile_map_selection.clear();
+ }
+ Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
+ for (int x = rect.position.x; x <= rect.get_end().x; x++) {
+ for (int y = rect.position.y; y <= rect.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ if (Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
+ if (tile_map_selection.has(coords)) {
+ tile_map_selection.erase(coords);
+ }
+ } else {
+ if (tile_map->get_cell_source_id(coords) != -1) {
+ tile_map_selection.insert(coords);
+ }
+ }
+ }
+ }
+ undo_redo->add_do_method(this, "_set_tile_map_selection", _get_tile_map_selection());
+ undo_redo->commit_action(false);
+
+ _update_selection_pattern_from_tilemap_selection();
+ _update_tileset_selection_from_selection_pattern();
+ } break;
+ case DRAG_TYPE_MOVE: {
+ Vector2i top_left;
+ if (!tile_map_selection.is_empty()) {
+ top_left = tile_map_selection.front()->get();
+ }
+ for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
+ top_left = top_left.min(E->get());
+ }
+
+ Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
+ offset = tile_map->world_to_map(mpos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
+
+ TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
+
+ Vector2i coords;
+ Map<Vector2i, TileMapCell> cells_undo;
+ for (int i = 0; i < selection_used_cells.size(); i++) {
+ coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
+ cells_undo[coords] = TileMapCell(drag_modified[coords].source_id, drag_modified[coords].get_atlas_coords(), drag_modified[coords].alternative_tile);
+ coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
+ cells_undo[coords] = TileMapCell(tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords));
+ }
+
+ Map<Vector2i, TileMapCell> cells_do;
+ for (int i = 0; i < selection_used_cells.size(); i++) {
+ coords = tile_map->map_pattern(top_left, selection_used_cells[i], selection_pattern);
+ cells_do[coords] = TileMapCell();
+ }
+ for (int i = 0; i < selection_used_cells.size(); i++) {
+ coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
+ cells_do[coords] = TileMapCell(selection_pattern->get_cell_source_id(selection_used_cells[i]), selection_pattern->get_cell_atlas_coords(selection_used_cells[i]), selection_pattern->get_cell_alternative_tile(selection_used_cells[i]));
+ }
+ undo_redo->create_action(TTR("Move tiles"));
+ // Move the tiles.
+ for (Map<Vector2i, TileMapCell>::Element *E = cells_do.front(); E; E = E->next()) {
+ undo_redo->add_do_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ for (Map<Vector2i, TileMapCell>::Element *E = cells_undo.front(); E; E = E->next()) {
+ undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+
+ // Update the selection.
+ undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
+ tile_map_selection.clear();
+ for (int i = 0; i < selection_used_cells.size(); i++) {
+ coords = tile_map->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
+ tile_map_selection.insert(coords);
+ }
+ undo_redo->add_do_method(this, "_set_tile_map_selection", _get_tile_map_selection());
+ undo_redo->commit_action();
+ } break;
+ case DRAG_TYPE_PICK: {
+ Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
+ rect.size += Vector2i(1, 1);
+ memdelete(selection_pattern);
+ TypedArray<Vector2i> coords_array;
+ for (int x = rect.position.x; x < rect.get_end().x; x++) {
+ for (int y = rect.position.y; y < rect.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ if (tile_map->get_cell_source_id(coords) != -1) {
+ coords_array.push_back(coords);
+ }
+ }
+ }
+ selection_pattern = tile_map->get_pattern(coords_array);
+ if (!selection_pattern->is_empty()) {
+ _update_tileset_selection_from_selection_pattern();
+ } else {
+ _update_selection_pattern_from_tileset_selection();
+ }
+ picker_button->set_pressed(false);
+ } break;
+ case DRAG_TYPE_PAINT: {
+ undo_redo->create_action(TTR("Paint tiles"));
+ for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) {
+ undo_redo->add_do_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key()));
+ undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ undo_redo->commit_action(false);
+ } break;
+ case DRAG_TYPE_LINE: {
+ Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, drag_start_mouse_pos, mpos);
+ undo_redo->create_action(TTR("Paint tiles"));
+ for (Map<Vector2i, TileMapCell>::Element *E = to_draw.front(); E; E = E->next()) {
+ if (!erase_button->is_pressed() && E->get().source_id == -1) {
+ continue;
+ }
+ undo_redo->add_do_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ undo_redo->add_undo_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key()));
+ }
+ undo_redo->commit_action();
+ } break;
+ case DRAG_TYPE_RECT: {
+ Map<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos));
+ undo_redo->create_action(TTR("Paint tiles"));
+ for (Map<Vector2i, TileMapCell>::Element *E = to_draw.front(); E; E = E->next()) {
+ if (!erase_button->is_pressed() && E->get().source_id == -1) {
+ continue;
+ }
+ undo_redo->add_do_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ undo_redo->add_undo_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key()));
+ }
+ undo_redo->commit_action();
+ } break;
+ case DRAG_TYPE_BUCKET: {
+ undo_redo->create_action(TTR("Paint tiles"));
+ for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) {
+ if (!erase_button->is_pressed() && E->get().source_id == -1) {
+ continue;
+ }
+ undo_redo->add_do_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key()));
+ undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ undo_redo->commit_action(false);
+ } break;
+ case DRAG_TYPE_CLIPBOARD_PASTE: {
+ Vector2 mouse_offset = (Vector2(tile_map_clipboard->get_size()) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
+ undo_redo->create_action(TTR("Paste tiles"));
+ TypedArray<Vector2i> used_cells = tile_map_clipboard->get_used_cells();
+ for (int i = 0; i < used_cells.size(); i++) {
+ Vector2i coords = tile_map->map_pattern(tile_map->world_to_map(mpos - mouse_offset), used_cells[i], tile_map_clipboard);
+ undo_redo->add_do_method(tile_map, "set_cell", coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i]));
+ undo_redo->add_undo_method(tile_map, "set_cell", coords, tile_map->get_cell_source_id(coords), tile_map->get_cell_atlas_coords(coords), tile_map->get_cell_alternative_tile(coords));
+ }
+ undo_redo->commit_action();
+ } break;
+ default:
+ break;
+ }
+ drag_type = DRAG_TYPE_NONE;
+}
+
+void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ hovered_tile.source_id = -1;
+ hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
+ hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ tile_set_selection.clear();
+ tile_map_selection.clear();
+ selection_pattern->clear();
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ hovered_tile.source_id = -1;
+ hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
+ hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ tile_set_selection.clear();
+ tile_map_selection.clear();
+ selection_pattern->clear();
+ return;
+ }
+
+ int source_index = sources_list->get_current();
+ if (source_index < 0 || source_index >= sources_list->get_item_count()) {
+ hovered_tile.source_id = -1;
+ hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
+ hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ tile_set_selection.clear();
+ tile_map_selection.clear();
+ selection_pattern->clear();
+ return;
+ }
+
+ int source_id = sources_list->get_item_metadata(source_index);
+
+ // Clear hovered if needed.
+ if (source_id != hovered_tile.source_id ||
+ !tile_set->has_source(hovered_tile.source_id) ||
+ !tile_set->get_source(hovered_tile.source_id)->has_tile(hovered_tile.get_atlas_coords()) ||
+ !tile_set->get_source(hovered_tile.source_id)->has_alternative_tile(hovered_tile.get_atlas_coords(), hovered_tile.alternative_tile)) {
+ hovered_tile.source_id = -1;
+ hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
+ hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ }
+
+ // Selection if needed.
+ for (Set<TileMapCell>::Element *E = tile_set_selection.front(); E; E = E->next()) {
+ const TileMapCell *selected = &(E->get());
+ if (!tile_set->has_source(selected->source_id) ||
+ !tile_set->get_source(selected->source_id)->has_tile(selected->get_atlas_coords()) ||
+ !tile_set->get_source(selected->source_id)->has_alternative_tile(selected->get_atlas_coords(), selected->alternative_tile)) {
+ tile_set_selection.erase(E);
+ }
+ }
+
+ if (!tile_map_selection.is_empty()) {
+ _update_selection_pattern_from_tilemap_selection();
+ } else {
+ _update_selection_pattern_from_tileset_selection();
+ }
+}
+
+void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ memdelete(selection_pattern);
+
+ TypedArray<Vector2i> coords_array;
+ for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
+ coords_array.push_back(E->get());
+ }
+ selection_pattern = tile_map->get_pattern(coords_array);
+}
+
+void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_selection() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ // Clear the tilemap selection.
+ tile_map_selection.clear();
+
+ // Clear the selected pattern.
+ selection_pattern->clear();
+
+ // Group per source.
+ Map<int, List<const TileMapCell *>> per_source;
+ for (Set<TileMapCell>::Element *E = tile_set_selection.front(); E; E = E->next()) {
+ per_source[E->get().source_id].push_back(&(E->get()));
+ }
+
+ int vertical_offset = 0;
+ for (Map<int, List<const TileMapCell *>>::Element *E_source = per_source.front(); E_source; E_source = E_source->next()) {
+ // Per source.
+ List<const TileMapCell *> unorganized;
+ Rect2i encompassing_rect_coords;
+ Map<Vector2i, const TileMapCell *> organized_pattern;
+
+ TileSetSource *source = *tile_set->get_source(E_source->key());
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Organize using coordinates.
+ for (List<const TileMapCell *>::Element *E_cell = E_source->get().front(); E_cell; E_cell = E_cell->next()) {
+ const TileMapCell *current = E_cell->get();
+ if (current->alternative_tile == 0) {
+ organized_pattern[current->get_atlas_coords()] = current;
+ } else {
+ unorganized.push_back(current);
+ }
+ }
+
+ // Compute the encompassing rect for the organized pattern.
+ Map<Vector2i, const TileMapCell *>::Element *E_cell = organized_pattern.front();
+ if (E_cell) {
+ encompassing_rect_coords = Rect2i(E_cell->key(), Vector2i(1, 1));
+ for (; E_cell; E_cell = E_cell->next()) {
+ encompassing_rect_coords.expand_to(E_cell->key() + Vector2i(1, 1));
+ encompassing_rect_coords.expand_to(E_cell->key());
+ }
+ }
+ } else {
+ // Add everything unorganized.
+ for (List<const TileMapCell *>::Element *E_cell = E_source->get().front(); E_cell; E_cell = E_cell->next()) {
+ unorganized.push_back(E_cell->get());
+ }
+ }
+
+ // Now add everything to the output pattern.
+ for (Map<Vector2i, const TileMapCell *>::Element *E_cell = organized_pattern.front(); E_cell; E_cell = E_cell->next()) {
+ selection_pattern->set_cell(E_cell->key() - encompassing_rect_coords.position + Vector2i(0, vertical_offset), E_cell->get()->source_id, E_cell->get()->get_atlas_coords(), E_cell->get()->alternative_tile);
+ }
+ Vector2i organized_size = selection_pattern->get_size();
+ int unorganized_index = 0;
+ for (List<const TileMapCell *>::Element *E_cell = unorganized.front(); E_cell; E_cell = E_cell->next()) {
+ selection_pattern->set_cell(Vector2(organized_size.x + unorganized_index, vertical_offset), E_cell->get()->source_id, E_cell->get()->get_atlas_coords(), E_cell->get()->alternative_tile);
+ unorganized_index++;
+ }
+ vertical_offset += MAX(organized_size.y, 1);
+ }
+ CanvasItemEditor::get_singleton()->update_viewport();
+}
+
+void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern() {
+ tile_set_selection.clear();
+ TypedArray<Vector2i> used_cells = selection_pattern->get_used_cells();
+ for (int i = 0; i < used_cells.size(); i++) {
+ Vector2i coords = used_cells[i];
+ if (selection_pattern->get_cell_source_id(coords) != -1) {
+ tile_set_selection.insert(TileMapCell(selection_pattern->get_cell_source_id(coords), selection_pattern->get_cell_atlas_coords(coords), selection_pattern->get_cell_alternative_tile(coords)));
+ }
+ }
+ _update_bottom_panel();
+}
+
+void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ int source_index = sources_list->get_current();
+ if (source_index < 0 || source_index >= sources_list->get_item_count()) {
+ return;
+ }
+
+ int source_id = sources_list->get_item_metadata(source_index);
+ if (!tile_set->has_source(source_id)) {
+ return;
+ }
+
+ TileSetAtlasSource *atlas = Object::cast_to<TileSetAtlasSource>(*tile_set->get_source(source_id));
+ if (!atlas) {
+ return;
+ }
+
+ // Draw the selection.
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+ for (Set<TileMapCell>::Element *E = tile_set_selection.front(); E; E = E->next()) {
+ if (E->get().source_id == source_id && E->get().alternative_tile == 0) {
+ tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E->get().get_atlas_coords()), selection_color, false);
+ }
+ }
+
+ // Draw the hovered tile.
+ if (hovered_tile.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile == 0 && !tile_set_dragging_selection) {
+ tile_atlas_control->draw_rect(atlas->get_tile_texture_region(hovered_tile.get_atlas_coords()), Color(1.0, 1.0, 1.0), false);
+ }
+
+ // Draw the selection rect.
+ if (tile_set_dragging_selection) {
+ Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos);
+ Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+
+ Rect2i region = Rect2i(start_tile, end_tile - start_tile).abs();
+ region.size += Vector2i(1, 1);
+
+ Set<Vector2i> to_draw;
+ for (int x = region.position.x; x < region.get_end().x; x++) {
+ for (int y = region.position.y; y < region.get_end().y; y++) {
+ Vector2i tile = atlas->get_tile_at_coords(Vector2i(x, y));
+ if (tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ to_draw.insert(tile);
+ }
+ }
+ }
+ Color selection_rect_color = selection_color.lightened(0.2);
+ for (Set<Vector2i>::Element *E = to_draw.front(); E; E = E->next()) {
+ tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E->get()), selection_rect_color, false);
+ }
+ }
+}
+
+void TileMapEditorTilesPlugin::_tile_atlas_control_mouse_exited() {
+ hovered_tile.source_id = -1;
+ hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
+ hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ tile_set_dragging_selection = false;
+ tile_atlas_control->update();
+}
+
+void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ int source_index = sources_list->get_current();
+ if (source_index < 0 || source_index >= sources_list->get_item_count()) {
+ return;
+ }
+
+ int source_id = sources_list->get_item_metadata(source_index);
+ if (!tile_set->has_source(source_id)) {
+ return;
+ }
+
+ TileSetAtlasSource *atlas = Object::cast_to<TileSetAtlasSource>(*tile_set->get_source(source_id));
+ if (!atlas) {
+ return;
+ }
+
+ // Update the hovered tile
+ hovered_tile.source_id = source_id;
+ hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
+ hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ coords = atlas->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ hovered_tile.set_atlas_coords(coords);
+ hovered_tile.alternative_tile = 0;
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ tile_atlas_control->update();
+ alternative_tiles_control->update();
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) { // Pressed
+ tile_set_dragging_selection = true;
+ tile_set_drag_start_mouse_pos = tile_atlas_control->get_local_mouse_position();
+ if (!mb->is_shift_pressed()) {
+ tile_set_selection.clear();
+ }
+
+ if (hovered_tile.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile == 0) {
+ if (mb->is_shift_pressed() && tile_set_selection.has(TileMapCell(source_id, hovered_tile.get_atlas_coords(), 0))) {
+ tile_set_selection.erase(TileMapCell(source_id, hovered_tile.get_atlas_coords(), 0));
+ } else {
+ tile_set_selection.insert(TileMapCell(source_id, hovered_tile.get_atlas_coords(), 0));
+ }
+ }
+ _update_selection_pattern_from_tileset_selection();
+ } else { // Released
+ if (tile_set_dragging_selection) {
+ if (!mb->is_shift_pressed()) {
+ tile_set_selection.clear();
+ }
+ // Compute the covered area.
+ Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos);
+ Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ if (start_tile != TileSetSource::INVALID_ATLAS_COORDS && end_tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ Rect2i region = Rect2i(start_tile, end_tile - start_tile).abs();
+ region.size += Vector2i(1, 1);
+
+ // To update the selection, we copy the selected/not selected status of the tiles we drag from.
+ Vector2i start_coords = atlas->get_tile_at_coords(start_tile);
+ if (mb->is_shift_pressed() && start_coords != TileSetSource::INVALID_ATLAS_COORDS && !tile_set_selection.has(TileMapCell(source_id, start_coords, 0))) {
+ // Remove from the selection.
+ for (int x = region.position.x; x < region.get_end().x; x++) {
+ for (int y = region.position.y; y < region.get_end().y; y++) {
+ Vector2i tile_coords = atlas->get_tile_at_coords(Vector2i(x, y));
+ if (tile_coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_selection.has(TileMapCell(source_id, tile_coords, 0))) {
+ tile_set_selection.erase(TileMapCell(source_id, tile_coords, 0));
+ }
+ }
+ }
+ } else {
+ // Insert in the selection.
+ for (int x = region.position.x; x < region.get_end().x; x++) {
+ for (int y = region.position.y; y < region.get_end().y; y++) {
+ Vector2i tile_coords = atlas->get_tile_at_coords(Vector2i(x, y));
+ if (tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ tile_set_selection.insert(TileMapCell(source_id, tile_coords, 0));
+ }
+ }
+ }
+ }
+ }
+ _update_selection_pattern_from_tileset_selection();
+ }
+ tile_set_dragging_selection = false;
+ }
+ tile_atlas_control->update();
+ }
+}
+
+void TileMapEditorTilesPlugin::_tile_alternatives_control_draw() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ int source_index = sources_list->get_current();
+ if (source_index < 0 || source_index >= sources_list->get_item_count()) {
+ return;
+ }
+
+ int source_id = sources_list->get_item_metadata(source_index);
+ if (!tile_set->has_source(source_id)) {
+ return;
+ }
+
+ TileSetAtlasSource *atlas = Object::cast_to<TileSetAtlasSource>(*tile_set->get_source(source_id));
+ if (!atlas) {
+ return;
+ }
+
+ // Draw the selection.
+ for (Set<TileMapCell>::Element *E = tile_set_selection.front(); E; E = E->next()) {
+ if (E->get().source_id == source_id && E->get().get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && E->get().alternative_tile > 0) {
+ Rect2i rect = tile_atlas_view->get_alternative_tile_rect(E->get().get_atlas_coords(), E->get().alternative_tile);
+ if (rect != Rect2i()) {
+ alternative_tiles_control->draw_rect(rect, Color(0.2, 0.2, 1.0), false);
+ }
+ }
+ }
+
+ // Draw hovered tile.
+ if (hovered_tile.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile > 0) {
+ Rect2i rect = tile_atlas_view->get_alternative_tile_rect(hovered_tile.get_atlas_coords(), hovered_tile.alternative_tile);
+ if (rect != Rect2i()) {
+ alternative_tiles_control->draw_rect(rect, Color(1.0, 1.0, 1.0), false);
+ }
+ }
+}
+
+void TileMapEditorTilesPlugin::_tile_alternatives_control_mouse_exited() {
+ hovered_tile.source_id = -1;
+ hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
+ hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ tile_set_dragging_selection = false;
+ alternative_tiles_control->update();
+}
+
+void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ int source_index = sources_list->get_current();
+ if (source_index < 0 || source_index >= sources_list->get_item_count()) {
+ return;
+ }
+
+ int source_id = sources_list->get_item_metadata(source_index);
+ if (!tile_set->has_source(source_id)) {
+ return;
+ }
+
+ TileSetAtlasSource *atlas = Object::cast_to<TileSetAtlasSource>(*tile_set->get_source(source_id));
+ if (!atlas) {
+ return;
+ }
+
+ // Update the hovered tile
+ hovered_tile.source_id = source_id;
+ hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
+ hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ Vector3i alternative_coords = tile_atlas_view->get_alternative_tile_at_pos(alternative_tiles_control->get_local_mouse_position());
+ Vector2i coords = Vector2i(alternative_coords.x, alternative_coords.y);
+ int alternative = alternative_coords.z;
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS && alternative != TileSetSource::INVALID_TILE_ALTERNATIVE) {
+ hovered_tile.set_atlas_coords(coords);
+ hovered_tile.alternative_tile = alternative;
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ tile_atlas_control->update();
+ alternative_tiles_control->update();
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) { // Pressed
+ // Left click pressed.
+ if (!mb->is_shift_pressed()) {
+ tile_set_selection.clear();
+ }
+
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS && alternative != TileSetAtlasSource::INVALID_TILE_ALTERNATIVE) {
+ if (mb->is_shift_pressed() && tile_set_selection.has(TileMapCell(source_id, hovered_tile.get_atlas_coords(), hovered_tile.alternative_tile))) {
+ tile_set_selection.erase(TileMapCell(source_id, hovered_tile.get_atlas_coords(), hovered_tile.alternative_tile));
+ } else {
+ tile_set_selection.insert(TileMapCell(source_id, hovered_tile.get_atlas_coords(), hovered_tile.alternative_tile));
+ }
+ }
+ _update_selection_pattern_from_tileset_selection();
+ }
+ tile_atlas_control->update();
+ alternative_tiles_control->update();
+ }
+}
+
+void TileMapEditorTilesPlugin::_set_tile_map_selection(const TypedArray<Vector2i> &p_selection) {
+ tile_map_selection.clear();
+ for (int i = 0; i < p_selection.size(); i++) {
+ tile_map_selection.insert(p_selection[i]);
+ }
+ _update_selection_pattern_from_tilemap_selection();
+ _update_tileset_selection_from_selection_pattern();
+ CanvasItemEditor::get_singleton()->update_viewport();
+}
+
+TypedArray<Vector2i> TileMapEditorTilesPlugin::_get_tile_map_selection() const {
+ TypedArray<Vector2i> output;
+ for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) {
+ output.push_back(E->get());
+ }
+ return output;
+}
+
+void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id) {
+ tile_map_id = p_tile_map_id;
+
+ // Clear the selection.
+ tile_set_selection.clear();
+ tile_map_selection.clear();
+ selection_pattern->clear();
+}
+
+void TileMapEditorTilesPlugin::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_scene_thumbnail_done"), &TileMapEditorTilesPlugin::_scene_thumbnail_done);
+ ClassDB::bind_method(D_METHOD("_set_tile_map_selection", "selection"), &TileMapEditorTilesPlugin::_set_tile_map_selection);
+ ClassDB::bind_method(D_METHOD("_get_tile_map_selection"), &TileMapEditorTilesPlugin::_get_tile_map_selection);
+}
+
+TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
+ CanvasItemEditor::get_singleton()->get_viewport_control()->connect("mouse_exited", callable_mp(this, &TileMapEditorTilesPlugin::_mouse_exited_viewport));
+
+ // --- Shortcuts ---
+ ED_SHORTCUT("tiles_editor/cut", TTR("Cut"), KEY_MASK_CMD | KEY_X);
+ ED_SHORTCUT("tiles_editor/copy", TTR("Copy"), KEY_MASK_CMD | KEY_C);
+ ED_SHORTCUT("tiles_editor/paste", TTR("Paste"), KEY_MASK_CMD | KEY_V);
+ ED_SHORTCUT("tiles_editor/cancel", TTR("Cancel"), KEY_ESCAPE);
+ ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), KEY_DELETE);
+
+ // --- Toolbar ---
+ toolbar = memnew(HBoxContainer);
+ toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ HBoxContainer *tilemap_tiles_tools_buttons = memnew(HBoxContainer);
+
+ tool_buttons_group.instance();
+
+ select_tool_button = memnew(Button);
+ select_tool_button->set_flat(true);
+ select_tool_button->set_toggle_mode(true);
+ select_tool_button->set_button_group(tool_buttons_group);
+ select_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/selection_tool", "Selection", KEY_S));
+ select_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
+ tilemap_tiles_tools_buttons->add_child(select_tool_button);
+
+ paint_tool_button = memnew(Button);
+ paint_tool_button->set_flat(true);
+ paint_tool_button->set_toggle_mode(true);
+ paint_tool_button->set_button_group(tool_buttons_group);
+ paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_E));
+ paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
+ tilemap_tiles_tools_buttons->add_child(paint_tool_button);
+
+ line_tool_button = memnew(Button);
+ line_tool_button->set_flat(true);
+ line_tool_button->set_toggle_mode(true);
+ line_tool_button->set_button_group(tool_buttons_group);
+ line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", "Line", KEY_L));
+ line_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
+ tilemap_tiles_tools_buttons->add_child(line_tool_button);
+
+ rect_tool_button = memnew(Button);
+ rect_tool_button->set_flat(true);
+ rect_tool_button->set_toggle_mode(true);
+ rect_tool_button->set_button_group(tool_buttons_group);
+ rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", "Rect", KEY_R));
+ rect_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
+ tilemap_tiles_tools_buttons->add_child(rect_tool_button);
+
+ bucket_tool_button = memnew(Button);
+ bucket_tool_button->set_flat(true);
+ bucket_tool_button->set_toggle_mode(true);
+ bucket_tool_button->set_button_group(tool_buttons_group);
+ bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", "Bucket", KEY_B));
+ bucket_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
+ tilemap_tiles_tools_buttons->add_child(bucket_tool_button);
+ toolbar->add_child(tilemap_tiles_tools_buttons);
+
+ // -- TileMap tool settings --
+ tools_settings = memnew(HBoxContainer);
+ toolbar->add_child(tools_settings);
+
+ tools_settings_vsep = memnew(VSeparator);
+ tools_settings->add_child(tools_settings_vsep);
+
+ // Picker
+ picker_button = memnew(Button);
+ picker_button->set_flat(true);
+ picker_button->set_toggle_mode(true);
+ picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P));
+ picker_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
+ tools_settings->add_child(picker_button);
+
+ // Erase button.
+ erase_button = memnew(Button);
+ erase_button->set_flat(true);
+ erase_button->set_toggle_mode(true);
+ erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", KEY_E));
+ erase_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
+ tools_settings->add_child(erase_button);
+
+ // Separator 2.
+ tools_settings_vsep_2 = memnew(VSeparator);
+ tools_settings->add_child(tools_settings_vsep_2);
+
+ // Continuous checkbox.
+ bucket_continuous_checkbox = memnew(CheckBox);
+ bucket_continuous_checkbox->set_flat(true);
+ bucket_continuous_checkbox->set_text(TTR("Contiguous"));
+ tools_settings->add_child(bucket_continuous_checkbox);
+
+ // Random tile checkbox.
+ random_tile_checkbox = memnew(CheckBox);
+ random_tile_checkbox->set_flat(true);
+ random_tile_checkbox->set_text(TTR("Place Random Tile"));
+ random_tile_checkbox->connect("toggled", callable_mp(this, &TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled));
+ tools_settings->add_child(random_tile_checkbox);
+
+ // Random tile scattering.
+ scatter_label = memnew(Label);
+ scatter_label->set_tooltip(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
+ scatter_label->set_text(TTR("Scattering:"));
+ tools_settings->add_child(scatter_label);
+
+ scatter_spinbox = memnew(SpinBox);
+ scatter_spinbox->set_min(0.0);
+ scatter_spinbox->set_max(1000);
+ scatter_spinbox->set_step(0.001);
+ scatter_spinbox->set_tooltip(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
+ scatter_spinbox->get_line_edit()->add_theme_constant_override("minimum_character_width", 4);
+ scatter_spinbox->connect("value_changed", callable_mp(this, &TileMapEditorTilesPlugin::_on_scattering_spinbox_changed));
+ tools_settings->add_child(scatter_spinbox);
+
+ _on_random_tile_checkbox_toggled(false);
+
+ // Wide empty separation control.
+ Control *h_empty_space = memnew(Control);
+ h_empty_space->set_h_size_flags(SIZE_EXPAND_FILL);
+ toolbar->add_child(h_empty_space);
+
+ // Grid toggle.
+ toggle_grid_button = memnew(Button);
+ toggle_grid_button->set_flat(true);
+ toggle_grid_button->set_toggle_mode(true);
+ toggle_grid_button->connect("toggled", callable_mp(this, &TileMapEditorTilesPlugin::_on_grid_toggled));
+ toolbar->add_child(toggle_grid_button);
+
+ // Default tool.
+ paint_tool_button->set_pressed(true);
+ _update_toolbar();
+
+ // --- Bottom panel ---
+ set_name("Tiles");
+
+ missing_source_label = memnew(Label);
+ missing_source_label->set_text(TTR("This TileMap's TileSet has no source configured. Edit the TileSet resource to add one."));
+ missing_source_label->set_h_size_flags(SIZE_EXPAND_FILL);
+ missing_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
+ missing_source_label->set_align(Label::ALIGN_CENTER);
+ missing_source_label->set_valign(Label::VALIGN_CENTER);
+ missing_source_label->hide();
+ add_child(missing_source_label);
+
+ atlas_sources_split_container = memnew(HSplitContainer);
+ atlas_sources_split_container->set_h_size_flags(SIZE_EXPAND_FILL);
+ atlas_sources_split_container->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(atlas_sources_split_container);
+
+ sources_list = memnew(ItemList);
+ sources_list->set_fixed_icon_size(Size2i(60, 60) * EDSCALE);
+ sources_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ sources_list->set_stretch_ratio(0.25);
+ sources_list->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
+ sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
+ sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_fix_selected_and_hovered).unbind(1));
+ sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_bottom_panel).unbind(1));
+ sources_list->connect("item_selected", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_atlas_sources_lists_current));
+ sources_list->connect("visibility_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::synchronize_atlas_sources_list), varray(sources_list));
+ atlas_sources_split_container->add_child(sources_list);
+
+ // Tile atlas source.
+ tile_atlas_view = memnew(TileAtlasView);
+ tile_atlas_view->set_h_size_flags(SIZE_EXPAND_FILL);
+ tile_atlas_view->set_v_size_flags(SIZE_EXPAND_FILL);
+ tile_atlas_view->set_texture_grid_visible(false);
+ tile_atlas_view->set_tile_shape_grid_visible(false);
+ tile_atlas_view->connect("transform_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_atlas_view_transform));
+ atlas_sources_split_container->add_child(tile_atlas_view);
+
+ tile_atlas_control = memnew(Control);
+ tile_atlas_control->connect("draw", callable_mp(this, &TileMapEditorTilesPlugin::_tile_atlas_control_draw));
+ tile_atlas_control->connect("mouse_exited", callable_mp(this, &TileMapEditorTilesPlugin::_tile_atlas_control_mouse_exited));
+ tile_atlas_control->connect("gui_input", callable_mp(this, &TileMapEditorTilesPlugin::_tile_atlas_control_gui_input));
+ tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control);
+
+ alternative_tiles_control = memnew(Control);
+ alternative_tiles_control->connect("draw", callable_mp(this, &TileMapEditorTilesPlugin::_tile_alternatives_control_draw));
+ alternative_tiles_control->connect("mouse_exited", callable_mp(this, &TileMapEditorTilesPlugin::_tile_alternatives_control_mouse_exited));
+ alternative_tiles_control->connect("gui_input", callable_mp(this, &TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input));
+ tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control);
+
+ // Scenes collection source.
+ scene_tiles_list = memnew(ItemList);
+ scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ scene_tiles_list->set_drag_forwarding(this);
+ scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI);
+ scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected));
+ scene_tiles_list->connect("nothing_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_nothing_selected));
+ scene_tiles_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
+ atlas_sources_split_container->add_child(scene_tiles_list);
+
+ // Invalid source label.
+ invalid_source_label = memnew(Label);
+ invalid_source_label->set_text(TTR("Invalid source selected."));
+ invalid_source_label->set_h_size_flags(SIZE_EXPAND_FILL);
+ invalid_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
+ invalid_source_label->set_align(Label::ALIGN_CENTER);
+ invalid_source_label->set_valign(Label::VALIGN_CENTER);
+ invalid_source_label->hide();
+ atlas_sources_split_container->add_child(invalid_source_label);
+
+ _update_bottom_panel();
+}
+
+TileMapEditorTilesPlugin::~TileMapEditorTilesPlugin() {
+ memdelete(selection_pattern);
+ memdelete(tile_map_clipboard);
+}
+
+void TileMapEditorTerrainsPlugin::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ paint_tool_button->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons"));
+ erase_button->set_icon(get_theme_icon("Eraser", "EditorIcons"));
+ break;
+ }
+}
+
+void TileMapEditorTerrainsPlugin::tile_set_changed() {
+ _update_terrains_cache();
+ _update_terrains_tree();
+ _update_tiles_list();
+}
+
+void TileMapEditorTerrainsPlugin::_update_toolbar() {
+ // Hide all settings.
+ for (int i = 0; i < tools_settings->get_child_count(); i++) {
+ Object::cast_to<CanvasItem>(tools_settings->get_child(i))->hide();
+ }
+
+ // Show only the correct settings.
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button) {
+ tools_settings_vsep->show();
+ picker_button->show();
+ erase_button->show();
+ }
+}
+
+Control *TileMapEditorTerrainsPlugin::get_toolbar() const {
+ return toolbar;
+}
+
+Map<Vector2i, TileSet::CellNeighbor> TileMapEditorTerrainsPlugin::Constraint::get_overlapping_coords_and_peering_bits() const {
+ Map<Vector2i, TileSet::CellNeighbor> output;
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ ERR_FAIL_COND_V(!tile_set.is_valid(), output);
+
+ TileSet::TileShape shape = tile_set->get_tile_shape();
+ if (shape == TileSet::TILE_SHAPE_SQUARE) {
+ switch (bit) {
+ case 0:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE;
+ break;
+ case 1:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
+ break;
+ case 2:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE;
+ break;
+ case 3:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
+ break;
+ default:
+ ERR_FAIL_V(output);
+ }
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ switch (bit) {
+ case 0:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
+ break;
+ case 1:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
+ break;
+ case 2:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
+ break;
+ case 3:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
+ break;
+ default:
+ ERR_FAIL_V(output);
+ }
+ } else {
+ // Half offset shapes.
+ TileSet::TileOffsetAxis offset_axis = tile_set->get_tile_offset_axis();
+ if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ switch (bit) {
+ case 0:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE;
+ break;
+ case 1:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER;
+ break;
+ case 2:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
+ break;
+ case 3:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
+ break;
+ case 4:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
+ break;
+ default:
+ ERR_FAIL_V(output);
+ }
+ } else {
+ switch (bit) {
+ case 0:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
+ break;
+ case 1:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE;
+ break;
+ case 2:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER;
+ break;
+ case 3:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE;
+ break;
+ case 4:
+ output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE;
+ output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
+ break;
+ default:
+ ERR_FAIL_V(output);
+ }
+ }
+ }
+ return output;
+}
+
+TileMapEditorTerrainsPlugin::Constraint::Constraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain) {
+ // The way we build the constraint make it easy to detect conflicting constraints.
+ tile_map = p_tile_map;
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ TileSet::TileShape shape = tile_set->get_tile_shape();
+ if (shape == TileSet::TILE_SHAPE_SQUARE || shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
+ case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
+ bit = 0;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ bit = 1;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
+ case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
+ bit = 2;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ bit = 3;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
+ case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
+ bit = 0;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, p_bit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ bit = 1;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, p_bit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_SIDE:
+ case TileSet::CELL_NEIGHBOR_TOP_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, p_bit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ bit = 3;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, p_bit);
+ break;
+ default:
+ ERR_FAIL();
+ break;
+ }
+ } else {
+ // Half-offset shapes
+ TileSet::TileOffsetAxis offset_axis = tile_set->get_tile_offset_axis();
+ if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
+ bit = 0;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ bit = 1;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ bit = 2;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
+ bit = 3;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ bit = 4;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ bit = 1;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
+ bit = 0;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ bit = 3;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_CORNER:
+ bit = 1;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ bit = 4;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ bit = 3;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ break;
+ default:
+ ERR_FAIL();
+ break;
+ }
+ } else {
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
+ bit = 0;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ bit = 1;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ bit = 2;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
+ bit = 3;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ bit = 0;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ bit = 4;
+ base_cell_coords = p_position;
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ bit = 1;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ bit = 0;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_SIDE:
+ bit = 3;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ bit = 2;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ bit = 4;
+ base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ break;
+ default:
+ ERR_FAIL();
+ break;
+ }
+ }
+ }
+ terrain = p_terrain;
+}
+
+Set<TileMapEditorTerrainsPlugin::TerrainsTilePattern> TileMapEditorTerrainsPlugin::_get_valid_terrains_tile_patterns_for_constraints(int p_terrain_set, const Vector2i &p_position, Set<Constraint> p_constraints) const {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Set<TerrainsTilePattern>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Set<TerrainsTilePattern>();
+ }
+
+ // Returns all tiles compatible with the given constraints.
+ Set<TerrainsTilePattern> compatible_terrain_tile_patterns;
+ for (Map<TerrainsTilePattern, Set<TileMapCell>>::Element *E = per_terrain_terrains_tile_patterns_tiles[p_terrain_set].front(); E; E = E->next()) {
+ int valid = true;
+ int in_pattern_count = 0;
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, bit)) {
+ // Check if the bit is compatible with the constraints.
+ Constraint terrain_bit_constraint = Constraint(tile_map, p_position, bit, E->key()[in_pattern_count]);
+
+ Set<Constraint>::Element *in_set_constraint_element = p_constraints.find(terrain_bit_constraint);
+ if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
+ valid = false;
+ break;
+ }
+ in_pattern_count++;
+ }
+ }
+
+ if (valid) {
+ compatible_terrain_tile_patterns.insert(E->key());
+ }
+ }
+
+ return compatible_terrain_tile_patterns;
+}
+
+Set<TileMapEditorTerrainsPlugin::Constraint> TileMapEditorTerrainsPlugin::_get_constraints_from_removed_cells_list(const Set<Vector2i> &p_to_replace, int p_terrain_set) const {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Set<Constraint>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Set<Constraint>();
+ }
+
+ ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), Set<Constraint>());
+
+ // Build a set of dummy constraints get the constrained points.
+ Set<Constraint> dummy_constraints;
+ for (Set<Vector2i>::Element *E = p_to_replace.front(); E; E = E->next()) {
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over sides.
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, bit)) {
+ dummy_constraints.insert(Constraint(tile_map, E->get(), bit, -1));
+ }
+ }
+ }
+
+ // For each constrained point, we get all overlapping tiles, and select the most adequate terrain for it.
+ Set<Constraint> constraints;
+ for (Set<Constraint>::Element *E = dummy_constraints.front(); E; E = E->next()) {
+ Constraint c = E->get();
+
+ Map<int, int> terrain_count;
+
+ // Count the number of occurrences per terrain.
+ Map<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits();
+ for (Map<Vector2i, TileSet::CellNeighbor>::Element *E_overlapping = overlapping_terrain_bits.front(); E_overlapping; E_overlapping = E_overlapping->next()) {
+ if (!p_to_replace.has(E_overlapping->key())) {
+ TileMapCell neighbor_cell = tile_map->get_cell(E_overlapping->key());
+ TileData *neighbor_tile_data = nullptr;
+ if (terrain_tiles.has(neighbor_cell) && terrain_tiles[neighbor_cell]->get_terrain_set() == p_terrain_set) {
+ neighbor_tile_data = terrain_tiles[neighbor_cell];
+ }
+
+ int terrain = neighbor_tile_data ? neighbor_tile_data->get_peering_bit_terrain(TileSet::CellNeighbor(E_overlapping->get())) : -1;
+ if (terrain_count.has(terrain)) {
+ terrain_count[terrain] = 0;
+ }
+ terrain_count[terrain] += 1;
+ }
+ }
+
+ // Get the terrain with the max number of occurrences.
+ int max = 0;
+ int max_terrain = -1;
+ for (Map<int, int>::Element *E_terrain_count = terrain_count.front(); E_terrain_count; E_terrain_count = E_terrain_count->next()) {
+ if (E_terrain_count->get() > max) {
+ max = E_terrain_count->get();
+ max_terrain = E_terrain_count->key();
+ }
+ }
+
+ // Set the adequate terrain.
+ if (max > 0) {
+ c.set_terrain(max_terrain);
+ constraints.insert(c);
+ }
+ }
+
+ return constraints;
+}
+
+Set<TileMapEditorTerrainsPlugin::Constraint> TileMapEditorTerrainsPlugin::_get_constraints_from_added_tile(Vector2i p_position, int p_terrain_set, TerrainsTilePattern p_terrains_tile_pattern) const {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Set<TileMapEditorTerrainsPlugin::Constraint>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Set<TileMapEditorTerrainsPlugin::Constraint>();
+ }
+
+ // Compute the constraints needed from the surrounding tiles.
+ Set<TileMapEditorTerrainsPlugin::Constraint> output;
+ int in_pattern_count = 0;
+ for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, side)) {
+ Constraint c = Constraint(tile_map, p_position, side, p_terrains_tile_pattern[in_pattern_count]);
+ output.insert(c);
+ in_pattern_count++;
+ }
+ }
+
+ return output;
+}
+
+Map<Vector2i, TileMapEditorTerrainsPlugin::TerrainsTilePattern> TileMapEditorTerrainsPlugin::_wave_function_collapse(const Set<Vector2i> &p_to_replace, int p_terrain_set, const Set<TileMapEditorTerrainsPlugin::Constraint> p_constraints) const {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Map<Vector2i, TerrainsTilePattern>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Map<Vector2i, TileMapEditorTerrainsPlugin::TerrainsTilePattern>();
+ }
+
+ // Copy the constraints set.
+ Set<TileMapEditorTerrainsPlugin::Constraint> constraints = p_constraints;
+
+ // Compute all acceptable tiles for each cell.
+ Map<Vector2i, Set<TerrainsTilePattern>> per_cell_acceptable_tiles;
+ for (Set<Vector2i>::Element *E = p_to_replace.front(); E; E = E->next()) {
+ per_cell_acceptable_tiles[E->get()] = _get_valid_terrains_tile_patterns_for_constraints(p_terrain_set, E->get(), constraints);
+ }
+
+ // Output map.
+ Map<Vector2i, TerrainsTilePattern> output;
+
+ // Add all positions to a set.
+ Set<Vector2i> to_replace = Set<Vector2i>(p_to_replace);
+ while (!to_replace.is_empty()) {
+ // Compute the minimum number of tile possibilities for each cell.
+ int min_nb_possibilities = 100000000;
+ for (Map<Vector2i, Set<TerrainsTilePattern>>::Element *E = per_cell_acceptable_tiles.front(); E; E = E->next()) {
+ min_nb_possibilities = MIN(min_nb_possibilities, E->get().size());
+ }
+
+ // Get the set of possible cells to fill.
+ LocalVector<Vector2i> to_choose_from;
+ for (Map<Vector2i, Set<TerrainsTilePattern>>::Element *E = per_cell_acceptable_tiles.front(); E; E = E->next()) {
+ if (E->get().size() == min_nb_possibilities) {
+ to_choose_from.push_back(E->key());
+ }
+ }
+
+ // Randomly pick a tile out of the most constrained.
+ Vector2i selected_cell_to_replace = to_choose_from[Math::random(0, to_choose_from.size() - 1)];
+
+ // Randomly select a tile out of them the put it in the grid.
+ Set<TerrainsTilePattern> valid_tiles = per_cell_acceptable_tiles[selected_cell_to_replace];
+ if (valid_tiles.is_empty()) {
+ // No possibilities :/
+ break;
+ }
+ int random_terrain_tile_pattern_index = Math::random(0, valid_tiles.size() - 1);
+ Set<TerrainsTilePattern>::Element *E = valid_tiles.front();
+ for (int i = 0; i < random_terrain_tile_pattern_index; i++) {
+ E = E->next();
+ }
+ TerrainsTilePattern selected_terrain_tile_pattern = E->get();
+
+ // Set the selected cell into the output.
+ output[selected_cell_to_replace] = selected_terrain_tile_pattern;
+ to_replace.erase(selected_cell_to_replace);
+ per_cell_acceptable_tiles.erase(selected_cell_to_replace);
+
+ // Add the new constraints from the added tiles.
+ Set<TileMapEditorTerrainsPlugin::Constraint> new_constraints = _get_constraints_from_added_tile(selected_cell_to_replace, p_terrain_set, selected_terrain_tile_pattern);
+ for (Set<TileMapEditorTerrainsPlugin::Constraint>::Element *E_constraint = new_constraints.front(); E_constraint; E_constraint = E_constraint->next()) {
+ constraints.insert(E_constraint->get());
+ }
+
+ // Compute valid tiles again for neighbors.
+ for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
+ if (tile_map->is_existing_neighbor(side)) {
+ Vector2i neighbor = tile_map->get_neighbor_cell(selected_cell_to_replace, side);
+ if (to_replace.has(neighbor)) {
+ per_cell_acceptable_tiles[neighbor] = _get_valid_terrains_tile_patterns_for_constraints(p_terrain_set, neighbor, constraints);
+ }
+ }
+ }
+ }
+ return output;
+}
+
+TileMapCell TileMapEditorTerrainsPlugin::_get_random_tile_from_pattern(int p_terrain_set, TerrainsTilePattern p_terrain_tile_pattern) const {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return TileMapCell();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return TileMapCell();
+ }
+
+ // Count the sum of probabilities.
+ double sum = 0.0;
+ Set<TileMapCell> set = per_terrain_terrains_tile_patterns_tiles[p_terrain_set][p_terrain_tile_pattern];
+ for (Set<TileMapCell>::Element *E = set.front(); E; E = E->next()) {
+ if (E->get().source_id >= 0) {
+ Ref<TileSetSource> source = tile_set->get_source(E->get().source_id);
+
+ Ref<TileSetAtlasSource> atlas_source = source;
+ if (atlas_source.is_valid()) {
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile));
+ sum += tile_data->get_probability();
+ } else {
+ sum += 1.0;
+ }
+ } else {
+ sum += 1.0;
+ }
+ }
+
+ // Generate a random number.
+ double count = 0.0;
+ double picked = Math::random(0.0, sum);
+
+ // Pick the tile.
+ for (Set<TileMapCell>::Element *E = set.front(); E; E = E->next()) {
+ if (E->get().source_id >= 0) {
+ Ref<TileSetSource> source = tile_set->get_source(E->get().source_id);
+
+ Ref<TileSetAtlasSource> atlas_source = source;
+ if (atlas_source.is_valid()) {
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile));
+ count += tile_data->get_probability();
+ } else {
+ count += 1.0;
+ }
+ } else {
+ count += 1.0;
+ }
+
+ if (count >= picked) {
+ return E->get();
+ }
+ }
+
+ ERR_FAIL_V(TileMapCell());
+}
+
+Map<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrains(const Map<Vector2i, TerrainsTilePattern> &p_to_paint, int p_terrain_set) const {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ Map<Vector2i, TileMapCell> output;
+
+ // Add the constraints from the added tiles.
+ Set<TileMapEditorTerrainsPlugin::Constraint> added_tiles_constraints_set;
+ for (Map<Vector2i, TerrainsTilePattern>::Element *E_to_paint = p_to_paint.front(); E_to_paint; E_to_paint = E_to_paint->next()) {
+ Vector2i coords = E_to_paint->key();
+ TerrainsTilePattern terrains_tile_pattern = E_to_paint->get();
+
+ Set<TileMapEditorTerrainsPlugin::Constraint> cell_constraints = _get_constraints_from_added_tile(coords, p_terrain_set, terrains_tile_pattern);
+ for (Set<TileMapEditorTerrainsPlugin::Constraint>::Element *E = cell_constraints.front(); E; E = E->next()) {
+ added_tiles_constraints_set.insert(E->get());
+ }
+ }
+
+ // Build the list of potential tiles to replace.
+ Set<Vector2i> potential_to_replace;
+ for (Map<Vector2i, TerrainsTilePattern>::Element *E_to_paint = p_to_paint.front(); E_to_paint; E_to_paint = E_to_paint->next()) {
+ Vector2i coords = E_to_paint->key();
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ if (tile_map->is_existing_neighbor(TileSet::CellNeighbor(i))) {
+ Vector2i neighbor = tile_map->get_neighbor_cell(coords, TileSet::CellNeighbor(i));
+ if (!p_to_paint.has(neighbor)) {
+ potential_to_replace.insert(neighbor);
+ }
+ }
+ }
+ }
+
+ // Set of tiles to replace
+ Set<Vector2i> to_replace;
+
+ // Add the central tiles to the one to replace. TODO: maybe change that.
+ for (Map<Vector2i, TerrainsTilePattern>::Element *E_to_paint = p_to_paint.front(); E_to_paint; E_to_paint = E_to_paint->next()) {
+ to_replace.insert(E_to_paint->key());
+ }
+
+ // Add the constraints from the surroundings of the modified areas.
+ Set<TileMapEditorTerrainsPlugin::Constraint> removed_cells_constraints_set;
+ bool to_replace_modified = true;
+ while (to_replace_modified) {
+ // Get the constraints from the removed cells.
+ removed_cells_constraints_set = _get_constraints_from_removed_cells_list(to_replace, p_terrain_set);
+
+ // Filter the sources to make sure they are in the potential_to_replace.
+ Map<Constraint, Set<Vector2i>> source_tiles_of_constraint;
+ for (Set<Constraint>::Element *E = removed_cells_constraints_set.front(); E; E = E->next()) {
+ Map<Vector2i, TileSet::CellNeighbor> sources_of_constraint = E->get().get_overlapping_coords_and_peering_bits();
+ for (Map<Vector2i, TileSet::CellNeighbor>::Element *E_source_tile_of_constraint = sources_of_constraint.front(); E_source_tile_of_constraint; E_source_tile_of_constraint = E_source_tile_of_constraint->next()) {
+ if (potential_to_replace.has(E_source_tile_of_constraint->key())) {
+ source_tiles_of_constraint[E->get()].insert(E_source_tile_of_constraint->key());
+ }
+ }
+ }
+
+ to_replace_modified = false;
+ for (Set<TileMapEditorTerrainsPlugin::Constraint>::Element *E = added_tiles_constraints_set.front(); E; E = E->next()) {
+ Constraint c = E->get();
+ // Check if we have a conflict in constraints.
+ if (removed_cells_constraints_set.has(c) && removed_cells_constraints_set.find(c)->get().get_terrain() != c.get_terrain()) {
+ // If we do, we search for a neighbor to remove.
+ if (source_tiles_of_constraint.has(c) && !source_tiles_of_constraint[c].is_empty()) {
+ // Remove it.
+ Vector2i to_add_to_remove = source_tiles_of_constraint[c].front()->get();
+ potential_to_replace.erase(to_add_to_remove);
+ to_replace.insert(to_add_to_remove);
+ to_replace_modified = true;
+ for (Map<Constraint, Set<Vector2i>>::Element *E_source_tiles_of_constraint = source_tiles_of_constraint.front(); E_source_tiles_of_constraint; E_source_tiles_of_constraint = E_source_tiles_of_constraint->next()) {
+ E_source_tiles_of_constraint->get().erase(to_add_to_remove);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Combine all constraints together.
+ Set<TileMapEditorTerrainsPlugin::Constraint> constraints = removed_cells_constraints_set;
+ for (Set<TileMapEditorTerrainsPlugin::Constraint>::Element *E = added_tiles_constraints_set.front(); E; E = E->next()) {
+ constraints.insert(E->get());
+ }
+
+ // Run WFC to fill the holes with the constraints.
+ Map<Vector2i, TerrainsTilePattern> wfc_output = _wave_function_collapse(to_replace, p_terrain_set, constraints);
+
+ // Use the WFC run for the output.
+ for (Map<Vector2i, TerrainsTilePattern>::Element *E = wfc_output.front(); E; E = E->next()) {
+ output[E->key()] = _get_random_tile_from_pattern(p_terrain_set, E->get());
+ }
+
+ // Override the WFC results to make sure at least the painted tiles are actually painted.
+ for (Map<Vector2i, TerrainsTilePattern>::Element *E_to_paint = p_to_paint.front(); E_to_paint; E_to_paint = E_to_paint->next()) {
+ output[E_to_paint->key()] = _get_random_tile_from_pattern(p_terrain_set, E_to_paint->get());
+ }
+
+ return output;
+}
+
+bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
+ if (!is_visible_in_tree()) {
+ // If the bottom editor is not visible, we ignore inputs.
+ return false;
+ }
+
+ if (CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) {
+ return false;
+ }
+
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return false;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return false;
+ }
+
+ // Get the selected terrain.
+ TerrainsTilePattern selected_terrains_tile_pattern;
+ int selected_terrain_set = -1;
+
+ TreeItem *selected_tree_item = terrains_tree->get_selected();
+ if (selected_tree_item && selected_tree_item->get_metadata(0)) {
+ Dictionary metadata_dict = selected_tree_item->get_metadata(0);
+ // Selected terrain
+ selected_terrain_set = metadata_dict["terrain_set"];
+
+ // Selected tile
+ if (erase_button->is_pressed()) {
+ selected_terrains_tile_pattern.clear();
+ for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(selected_terrain_set, side)) {
+ selected_terrains_tile_pattern.push_back(-1);
+ }
+ }
+ } else if (terrains_tile_list->is_anything_selected()) {
+ metadata_dict = terrains_tile_list->get_item_metadata(terrains_tile_list->get_selected_items()[0]);
+ selected_terrains_tile_pattern = metadata_dict["terrains_tile_pattern"];
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
+ Vector2 mpos = xform.affine_inverse().xform(mm->get_position());
+
+ switch (drag_type) {
+ case DRAG_TYPE_PAINT: {
+ if (selected_terrain_set >= 0) {
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
+ Map<Vector2i, TerrainsTilePattern> to_draw;
+ for (int i = 0; i < line.size(); i++) {
+ to_draw[line[i]] = selected_terrains_tile_pattern;
+ }
+ Map<Vector2i, TileMapCell> modified = _draw_terrains(to_draw, selected_terrain_set);
+ for (Map<Vector2i, TileMapCell>::Element *E = modified.front(); E; E = E->next()) {
+ if (!drag_modified.has(E->key())) {
+ drag_modified[E->key()] = tile_map->get_cell(E->key());
+ }
+ tile_map->set_cell(E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ drag_last_mouse_pos = mpos;
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ return true;
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
+ Vector2 mpos = xform.affine_inverse().xform(mb->get_position());
+
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ // Pressed
+ if (picker_button->is_pressed()) {
+ drag_type = DRAG_TYPE_PICK;
+ } else {
+ // Paint otherwise.
+ if (selected_terrain_set >= 0 && !selected_terrains_tile_pattern.is_empty() && tool_buttons_group->get_pressed_button() == paint_tool_button) {
+ drag_type = DRAG_TYPE_PAINT;
+ drag_start_mouse_pos = mpos;
+
+ drag_modified.clear();
+
+ Map<Vector2i, TerrainsTilePattern> terrains_to_draw;
+ terrains_to_draw[tile_map->world_to_map(mpos)] = selected_terrains_tile_pattern;
+
+ Map<Vector2i, TileMapCell> to_draw = _draw_terrains(terrains_to_draw, selected_terrain_set);
+ for (Map<Vector2i, TileMapCell>::Element *E = to_draw.front(); E; E = E->next()) {
+ drag_modified[E->key()] = tile_map->get_cell(E->key());
+ tile_map->set_cell(E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ }
+ }
+ } else {
+ // Released
+ switch (drag_type) {
+ case DRAG_TYPE_PICK: {
+ Vector2i coords = tile_map->world_to_map(mpos);
+ TileMapCell tile = tile_map->get_cell(coords);
+
+ if (terrain_tiles.has(tile)) {
+ Array terrains_tile_pattern = _build_terrains_tile_pattern(terrain_tiles[tile]);
+
+ // Find the tree item for the right terrain set.
+ bool need_tree_item_switch = true;
+ TreeItem *tree_item = terrains_tree->get_selected();
+ if (tree_item) {
+ Dictionary metadata_dict = tree_item->get_metadata(0);
+ if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) {
+ int terrain_set = metadata_dict["terrain_set"];
+ int terrain_id = metadata_dict["terrain_id"];
+ if (per_terrain_terrains_tile_patterns[terrain_set][terrain_id].has(terrains_tile_pattern)) {
+ need_tree_item_switch = false;
+ }
+ }
+ }
+
+ if (need_tree_item_switch) {
+ for (tree_item = terrains_tree->get_root()->get_first_child(); tree_item; tree_item = tree_item->get_next_visible()) {
+ Dictionary metadata_dict = tree_item->get_metadata(0);
+ if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) {
+ int terrain_set = metadata_dict["terrain_set"];
+ int terrain_id = metadata_dict["terrain_id"];
+ if (per_terrain_terrains_tile_patterns[terrain_set][terrain_id].has(terrains_tile_pattern)) {
+ // Found
+ tree_item->select(0);
+ _update_tiles_list();
+ break;
+ }
+ }
+ }
+ }
+
+ // Find the list item for the given tile.
+ if (tree_item) {
+ for (int i = 0; i < terrains_tile_list->get_item_count(); i++) {
+ Dictionary metadata_dict = terrains_tile_list->get_item_metadata(i);
+ TerrainsTilePattern in_meta_terrains_tile_pattern = metadata_dict["terrains_tile_pattern"];
+ bool equals = true;
+ for (int j = 0; j < terrains_tile_pattern.size(); j++) {
+ if (terrains_tile_pattern[j] != in_meta_terrains_tile_pattern[j]) {
+ equals = false;
+ break;
+ }
+ }
+ if (equals) {
+ terrains_tile_list->select(i);
+ break;
+ }
+ }
+ } else {
+ ERR_PRINT("Terrain tile not found.");
+ }
+ }
+ picker_button->set_pressed(false);
+ } break;
+ case DRAG_TYPE_PAINT: {
+ undo_redo->create_action(TTR("Paint terrain"));
+ for (Map<Vector2i, TileMapCell>::Element *E = drag_modified.front(); E; E = E->next()) {
+ undo_redo->add_do_method(tile_map, "set_cell", E->key(), tile_map->get_cell_source_id(E->key()), tile_map->get_cell_atlas_coords(E->key()), tile_map->get_cell_alternative_tile(E->key()));
+ undo_redo->add_undo_method(tile_map, "set_cell", E->key(), E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ }
+ undo_redo->commit_action(false);
+ } break;
+ default:
+ break;
+ }
+ drag_type = DRAG_TYPE_NONE;
+ }
+
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ return true;
+ }
+ drag_last_mouse_pos = mpos;
+ }
+
+ return false;
+}
+
+TileMapEditorTerrainsPlugin::TerrainsTilePattern TileMapEditorTerrainsPlugin::_build_terrains_tile_pattern(TileData *p_tile_data) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return TerrainsTilePattern();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return TerrainsTilePattern();
+ }
+
+ TerrainsTilePattern output;
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ if (tile_set->is_valid_peering_bit_terrain(p_tile_data->get_terrain_set(), TileSet::CellNeighbor(i))) {
+ output.push_back(p_tile_data->get_peering_bit_terrain(TileSet::CellNeighbor(i)));
+ }
+ }
+ return output;
+}
+
+void TileMapEditorTerrainsPlugin::_update_terrains_cache() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ // Compute the tile sides.
+ tile_sides.clear();
+ TileSet::TileShape shape = tile_set->get_tile_shape();
+ if (shape == TileSet::TILE_SHAPE_SQUARE) {
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_RIGHT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ } else {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_RIGHT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ } else {
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ tile_sides.push_back(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ }
+ }
+
+ // Organizes tiles into structures.
+ per_terrain_terrains_tile_patterns_tiles.resize(tile_set->get_terrain_sets_count());
+ per_terrain_terrains_tile_patterns.resize(tile_set->get_terrain_sets_count());
+ for (int i = 0; i < tile_set->get_terrain_sets_count(); i++) {
+ per_terrain_terrains_tile_patterns_tiles[i].clear();
+ per_terrain_terrains_tile_patterns[i].resize(tile_set->get_terrains_count(i));
+ for (int j = 0; j < (int)per_terrain_terrains_tile_patterns[i].size(); j++) {
+ per_terrain_terrains_tile_patterns[i][j].clear();
+ }
+ }
+
+ for (int source_index = 0; source_index < tile_set->get_source_count(); source_index++) {
+ int source_id = tile_set->get_source_id(source_index);
+ Ref<TileSetSource> source = tile_set->get_source(source_id);
+
+ Ref<TileSetAtlasSource> atlas_source = source;
+ if (atlas_source.is_valid()) {
+ for (int tile_index = 0; tile_index < source->get_tiles_count(); tile_index++) {
+ Vector2i tile_id = source->get_tile_id(tile_index);
+ for (int alternative_index = 0; alternative_index < source->get_alternative_tiles_count(tile_id); alternative_index++) {
+ int alternative_id = source->get_alternative_tile_id(tile_id, alternative_index);
+
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_id, alternative_id));
+ int terrain_set = tile_data->get_terrain_set();
+ if (terrain_set >= 0) {
+ ERR_FAIL_INDEX(terrain_set, (int)per_terrain_terrains_tile_patterns.size());
+
+ TileMapCell cell;
+ cell.source_id = source_id;
+ cell.set_atlas_coords(tile_id);
+ cell.alternative_tile = alternative_id;
+
+ TerrainsTilePattern terrains_tile_pattern = _build_terrains_tile_pattern(tile_data);
+
+ // Terrain bits.
+ for (int i = 0; i < terrains_tile_pattern.size(); i++) {
+ int terrain = terrains_tile_pattern[i];
+ if (terrain >= 0 && terrain < (int)per_terrain_terrains_tile_patterns[terrain_set].size()) {
+ per_terrain_terrains_tile_patterns[terrain_set][terrain].insert(terrains_tile_pattern);
+ terrain_tiles[cell] = tile_data;
+ per_terrain_terrains_tile_patterns_tiles[terrain_set][terrains_tile_pattern].insert(cell);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Add the empty cell in the possible patterns and cells.
+ for (int i = 0; i < tile_set->get_terrain_sets_count(); i++) {
+ TerrainsTilePattern empty_pattern;
+ for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
+ if (tile_set->is_valid_peering_bit_terrain(i, TileSet::CellNeighbor(j))) {
+ empty_pattern.push_back(-1);
+ }
+ }
+
+ TileMapCell empty_cell;
+ empty_cell.source_id = -1;
+ empty_cell.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
+ empty_cell.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ per_terrain_terrains_tile_patterns_tiles[i][empty_pattern].insert(empty_cell);
+ }
+}
+
+void TileMapEditorTerrainsPlugin::_update_terrains_tree() {
+ terrains_tree->clear();
+ terrains_tree->create_item();
+
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ // Fill in the terrain list.
+ for (int terrain_set_index = 0; terrain_set_index < tile_set->get_terrain_sets_count(); terrain_set_index++) {
+ // Add an item for the terrain set.
+ TreeItem *terrain_set_tree_item = terrains_tree->create_item();
+ String matches;
+ if (tile_set->get_terrain_set_mode(terrain_set_index) == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
+ terrain_set_tree_item->set_icon(0, get_theme_icon("TerrainMatchCornersAndSides", "EditorIcons"));
+ matches = String(TTR("Matches Corners and Sides"));
+ } else if (tile_set->get_terrain_set_mode(terrain_set_index) == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
+ terrain_set_tree_item->set_icon(0, get_theme_icon("TerrainMatchCorners", "EditorIcons"));
+ matches = String(TTR("Matches Corners Only"));
+ } else {
+ terrain_set_tree_item->set_icon(0, get_theme_icon("TerrainMatchSides", "EditorIcons"));
+ matches = String(TTR("Matches Sides Only"));
+ }
+ terrain_set_tree_item->set_text(0, vformat("Terrain Set %d (%s)", terrain_set_index, matches));
+ terrain_set_tree_item->set_selectable(0, false);
+
+ for (int terrain_index = 0; terrain_index < tile_set->get_terrains_count(terrain_set_index); terrain_index++) {
+ // Compute the terrains_tile_pattern used for terrain preview (whenever possible).
+ TerrainsTilePattern terrains_tile_pattern;
+ int max_bit_count = -1;
+ for (Set<TerrainsTilePattern>::Element *E = per_terrain_terrains_tile_patterns[terrain_set_index][terrain_index].front(); E; E = E->next()) {
+ int count = 0;
+ for (int i = 0; i < E->get().size(); i++) {
+ if (int(E->get()[i]) == terrain_index) {
+ count++;
+ }
+ }
+ if (count > max_bit_count) {
+ terrains_tile_pattern = E->get();
+ max_bit_count = count;
+ }
+ }
+
+ // Get the preview.
+ Ref<Texture2D> icon;
+ Rect2 region;
+ if (max_bit_count >= 0) {
+ double max_probability = -1.0;
+ for (Set<TileMapCell>::Element *E = per_terrain_terrains_tile_patterns_tiles[terrain_set_index][terrains_tile_pattern].front(); E; E = E->next()) {
+ Ref<TileSetSource> source = tile_set->get_source(E->get().source_id);
+
+ Ref<TileSetAtlasSource> atlas_source = source;
+ if (atlas_source.is_valid()) {
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile));
+ if (tile_data->get_probability() > max_probability) {
+ icon = atlas_source->get_texture();
+ region = atlas_source->get_tile_texture_region(E->get().get_atlas_coords());
+ max_probability = tile_data->get_probability();
+ }
+ }
+ }
+ } else {
+ Ref<Image> image;
+ image.instance();
+ image->create(1, 1, false, Image::FORMAT_RGBA8);
+ image->set_pixel(0, 0, tile_set->get_terrain_color(terrain_set_index, terrain_index));
+ Ref<ImageTexture> image_texture;
+ image_texture.instance();
+ image_texture->create_from_image(image);
+ image_texture->set_size_override(Size2(32, 32) * EDSCALE);
+ icon = image_texture;
+ }
+
+ // Add the item to the terrain list.
+ TreeItem *terrain_tree_item = terrains_tree->create_item(terrain_set_tree_item);
+ terrain_tree_item->set_text(0, tile_set->get_terrain_name(terrain_set_index, terrain_index));
+ terrain_tree_item->set_icon_max_width(0, 32 * EDSCALE);
+ terrain_tree_item->set_icon(0, icon);
+ terrain_tree_item->set_icon_region(0, region);
+ Dictionary metadata_dict;
+ metadata_dict["terrain_set"] = terrain_set_index;
+ metadata_dict["terrain_id"] = terrain_index;
+ terrain_tree_item->set_metadata(0, metadata_dict);
+ }
+ }
+}
+
+void TileMapEditorTerrainsPlugin::_update_tiles_list() {
+ terrains_tile_list->clear();
+
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ TreeItem *selected_tree_item = terrains_tree->get_selected();
+ if (selected_tree_item && selected_tree_item->get_metadata(0)) {
+ Dictionary metadata_dict = selected_tree_item->get_metadata(0);
+ int selected_terrain_set = metadata_dict["terrain_set"];
+ int selected_terrain_id = metadata_dict["terrain_id"];
+ ERR_FAIL_INDEX(selected_terrain_set, (int)per_terrain_terrains_tile_patterns.size());
+ ERR_FAIL_INDEX(selected_terrain_id, (int)per_terrain_terrains_tile_patterns[selected_terrain_set].size());
+
+ // Sort the items in a map by the number of corresponding terrains.
+ Map<int, Set<TerrainsTilePattern>> sorted;
+ for (Set<TerrainsTilePattern>::Element *E = per_terrain_terrains_tile_patterns[selected_terrain_set][selected_terrain_id].front(); E; E = E->next()) {
+ // Count the number of matching sides/terrains.
+ int count = 0;
+
+ for (int i = 0; i < E->get().size(); i++) {
+ if (int(E->get()[i]) == selected_terrain_id) {
+ count++;
+ }
+ }
+ sorted[count].insert(E->get());
+ }
+
+ for (Map<int, Set<TerrainsTilePattern>>::Element *E_set = sorted.back(); E_set; E_set = E_set->prev()) {
+ for (Set<TerrainsTilePattern>::Element *E = E_set->get().front(); E; E = E->next()) {
+ TerrainsTilePattern terrains_tile_pattern = E->get();
+
+ // Get the icon.
+ Ref<Texture2D> icon;
+ Rect2 region;
+ bool transpose = false;
+
+ double max_probability = -1.0;
+ for (Set<TileMapCell>::Element *E_tile_map_cell = per_terrain_terrains_tile_patterns_tiles[selected_terrain_set][terrains_tile_pattern].front(); E_tile_map_cell; E_tile_map_cell = E_tile_map_cell->next()) {
+ Ref<TileSetSource> source = tile_set->get_source(E_tile_map_cell->get().source_id);
+
+ Ref<TileSetAtlasSource> atlas_source = source;
+ if (atlas_source.is_valid()) {
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(E_tile_map_cell->get().get_atlas_coords(), E_tile_map_cell->get().alternative_tile));
+ if (tile_data->get_probability() > max_probability) {
+ icon = atlas_source->get_texture();
+ region = atlas_source->get_tile_texture_region(E_tile_map_cell->get().get_atlas_coords());
+ if (tile_data->get_flip_h()) {
+ region.position.x += region.size.x;
+ region.size.x = -region.size.x;
+ }
+ if (tile_data->get_flip_v()) {
+ region.position.y += region.size.y;
+ region.size.y = -region.size.y;
+ }
+ transpose = tile_data->get_transpose();
+ max_probability = tile_data->get_probability();
+ }
+ }
+ }
+
+ // Create the ItemList's item.
+ int item_index = terrains_tile_list->add_item("");
+ terrains_tile_list->set_item_icon(item_index, icon);
+ terrains_tile_list->set_item_icon_region(item_index, region);
+ terrains_tile_list->set_item_icon_transposed(item_index, transpose);
+ Dictionary list_metadata_dict;
+ list_metadata_dict["terrains_tile_pattern"] = terrains_tile_pattern;
+ terrains_tile_list->set_item_metadata(item_index, list_metadata_dict);
+ }
+ }
+ if (terrains_tile_list->get_item_count() > 0) {
+ terrains_tile_list->select(0);
+ }
+ }
+}
+
+void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id) {
+ tile_map_id = p_tile_map_id;
+ _update_terrains_cache();
+ _update_terrains_tree();
+ _update_tiles_list();
+}
+
+TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
+ set_name("Terrains");
+
+ HSplitContainer *tilemap_tab_terrains = memnew(HSplitContainer);
+ tilemap_tab_terrains->set_h_size_flags(SIZE_EXPAND_FILL);
+ tilemap_tab_terrains->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(tilemap_tab_terrains);
+
+ terrains_tree = memnew(Tree);
+ terrains_tree->set_h_size_flags(SIZE_EXPAND_FILL);
+ terrains_tree->set_stretch_ratio(0.25);
+ terrains_tree->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
+ terrains_tree->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
+ terrains_tree->set_hide_root(true);
+ terrains_tree->connect("item_selected", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_tiles_list));
+ tilemap_tab_terrains->add_child(terrains_tree);
+
+ terrains_tile_list = memnew(ItemList);
+ terrains_tile_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ terrains_tile_list->set_max_columns(0);
+ terrains_tile_list->set_same_column_width(true);
+ terrains_tile_list->set_fixed_icon_size(Size2(30, 30) * EDSCALE);
+ terrains_tile_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
+ tilemap_tab_terrains->add_child(terrains_tile_list);
+
+ // --- Toolbar ---
+ toolbar = memnew(HBoxContainer);
+
+ HBoxContainer *tilemap_tiles_tools_buttons = memnew(HBoxContainer);
+
+ tool_buttons_group.instance();
+
+ paint_tool_button = memnew(Button);
+ paint_tool_button->set_flat(true);
+ paint_tool_button->set_toggle_mode(true);
+ paint_tool_button->set_button_group(tool_buttons_group);
+ paint_tool_button->set_pressed(true);
+ paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_E));
+ paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
+ tilemap_tiles_tools_buttons->add_child(paint_tool_button);
+
+ toolbar->add_child(tilemap_tiles_tools_buttons);
+
+ // -- TileMap tool settings --
+ tools_settings = memnew(HBoxContainer);
+ toolbar->add_child(tools_settings);
+
+ tools_settings_vsep = memnew(VSeparator);
+ tools_settings->add_child(tools_settings_vsep);
+
+ // Picker
+ picker_button = memnew(Button);
+ picker_button->set_flat(true);
+ picker_button->set_toggle_mode(true);
+ picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P));
+ picker_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
+ tools_settings->add_child(picker_button);
+
+ // Erase button.
+ erase_button = memnew(Button);
+ erase_button->set_flat(true);
+ erase_button->set_toggle_mode(true);
+ erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", KEY_E));
+ erase_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
+ tools_settings->add_child(erase_button);
+}
+
+TileMapEditorTerrainsPlugin::~TileMapEditorTerrainsPlugin() {
+}
+
+void TileMapEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ missing_tile_texture = get_theme_icon("StatusWarning", "EditorIcons");
+ warning_pattern_texture = get_theme_icon("WarningPattern", "EditorIcons");
+ break;
+ case NOTIFICATION_INTERNAL_PROCESS:
+ if (is_visible_in_tree() && tileset_changed_needs_update) {
+ _update_bottom_panel();
+ tile_map_editor_plugins[tabs->get_current_tab()]->tile_set_changed();
+ CanvasItemEditor::get_singleton()->update_viewport();
+ tileset_changed_needs_update = false;
+ }
+ break;
+ }
+}
+
+void TileMapEditor::_update_bottom_panel() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+
+ // Update the visibility of controls.
+ missing_tileset_label->set_visible(!tile_set.is_valid());
+ if (!tile_set.is_valid()) {
+ for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
+ tile_map_editor_plugins[i]->hide();
+ }
+ } else {
+ for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
+ tile_map_editor_plugins[i]->set_visible(i == tabs->get_current_tab());
+ }
+ }
+}
+
+Vector<Vector2i> TileMapEditor::get_line(TileMap *p_tile_map, Vector2i p_from_cell, Vector2i p_to_cell) {
+ ERR_FAIL_COND_V(!p_tile_map, Vector<Vector2i>());
+
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND_V(!tile_set.is_valid(), Vector<Vector2i>());
+
+ if (tile_set->get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) {
+ return Geometry2D::bresenham_line(p_from_cell, p_to_cell);
+ } else {
+ // Adapt the bresenham line algorithm to half-offset shapes.
+ // See this blog post: http://zvold.blogspot.com/2010/01/bresenhams-line-drawing-algorithm-on_26.html
+ Vector<Point2i> points;
+
+ bool transposed = tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL;
+ p_from_cell = TileMap::transform_coords_layout(p_from_cell, tile_set->get_tile_offset_axis(), tile_set->get_tile_layout(), TileSet::TILE_LAYOUT_STACKED);
+ p_to_cell = TileMap::transform_coords_layout(p_to_cell, tile_set->get_tile_offset_axis(), tile_set->get_tile_layout(), TileSet::TILE_LAYOUT_STACKED);
+ if (transposed) {
+ SWAP(p_from_cell.x, p_from_cell.y);
+ SWAP(p_to_cell.x, p_to_cell.y);
+ }
+
+ Vector2i delta = p_to_cell - p_from_cell;
+ delta = Vector2i(2 * delta.x + ABS(p_to_cell.y % 2) - ABS(p_from_cell.y % 2), delta.y);
+ Vector2i sign = delta.sign();
+
+ Vector2i current = p_from_cell;
+ points.push_back(TileMap::transform_coords_layout(transposed ? Vector2i(current.y, current.x) : current, tile_set->get_tile_offset_axis(), TileSet::TILE_LAYOUT_STACKED, tile_set->get_tile_layout()));
+
+ int err = 0;
+ if (ABS(delta.y) < ABS(delta.x)) {
+ Vector2i err_step = 3 * delta.abs();
+ while (current != p_to_cell) {
+ err += err_step.y;
+ if (err > ABS(delta.x)) {
+ if (sign.x == 0) {
+ current += Vector2(sign.y, 0);
+ } else {
+ current += Vector2(bool(current.y % 2) ^ (sign.x < 0) ? sign.x : 0, sign.y);
+ }
+ err -= err_step.x;
+ } else {
+ current += Vector2i(sign.x, 0);
+ err += err_step.y;
+ }
+ points.push_back(TileMap::transform_coords_layout(transposed ? Vector2i(current.y, current.x) : current, tile_set->get_tile_offset_axis(), TileSet::TILE_LAYOUT_STACKED, tile_set->get_tile_layout()));
+ }
+ } else {
+ Vector2i err_step = delta.abs();
+ while (current != p_to_cell) {
+ err += err_step.x;
+ if (err > 0) {
+ if (sign.x == 0) {
+ current += Vector2(0, sign.y);
+ } else {
+ current += Vector2(bool(current.y % 2) ^ (sign.x < 0) ? sign.x : 0, sign.y);
+ }
+ err -= err_step.y;
+ } else {
+ if (sign.x == 0) {
+ current += Vector2(0, sign.y);
+ } else {
+ current += Vector2(bool(current.y % 2) ^ (sign.x > 0) ? -sign.x : 0, sign.y);
+ }
+ err += err_step.y;
+ }
+ points.push_back(TileMap::transform_coords_layout(transposed ? Vector2i(current.y, current.x) : current, tile_set->get_tile_offset_axis(), TileSet::TILE_LAYOUT_STACKED, tile_set->get_tile_layout()));
+ }
+ }
+
+ return points;
+ }
+}
+
+void TileMapEditor::_tile_map_changed() {
+ tileset_changed_needs_update = true;
+}
+
+void TileMapEditor::_tab_changed(int p_tab_id) {
+ // Make the plugin edit the correct tilemap.
+ tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id);
+
+ // Update toolbar.
+ for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
+ tile_map_editor_plugins[i]->get_toolbar()->set_visible(i == p_tab_id);
+ }
+
+ // Update visible panel.
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map || !tile_map->get_tileset().is_valid()) {
+ for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
+ tile_map_editor_plugins[i]->hide();
+ }
+ } else {
+ for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
+ tile_map_editor_plugins[i]->set_visible(i == tabs->get_current_tab());
+ }
+ }
+
+ // Graphical update.
+ tile_map_editor_plugins[tabs->get_current_tab()]->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
+}
+
+bool TileMapEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
+ return tile_map_editor_plugins[tabs->get_current_tab()]->forward_canvas_gui_input(p_event);
+}
+
+void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ if (!tile_map->is_visible_in_tree()) {
+ return;
+ }
+
+ Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
+ Transform2D xform_inv = xform.affine_inverse();
+ Vector2i tile_shape_size = tile_set->get_tile_size();
+
+ // Draw tiles with invalid IDs in the grid.
+ float icon_ratio = MIN(missing_tile_texture->get_size().x / tile_set->get_tile_size().x, missing_tile_texture->get_size().y / tile_set->get_tile_size().y) / 3;
+ TypedArray<Vector2i> used_cells = tile_map->get_used_cells();
+ for (int i = 0; i < used_cells.size(); i++) {
+ Vector2i coords = used_cells[i];
+ int tile_source_id = tile_map->get_cell_source_id(coords);
+ if (tile_source_id >= 0) {
+ Vector2i tile_atlas_coords = tile_map->get_cell_atlas_coords(coords);
+ int tile_alternative_tile = tile_map->get_cell_alternative_tile(coords);
+
+ TileSetSource *source = nullptr;
+ if (tile_set->has_source(tile_source_id)) {
+ source = *tile_set->get_source(tile_source_id);
+ }
+
+ if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) {
+ // Generate a random color from the hashed values of the tiles.
+ Array to_hash;
+ to_hash.push_back(tile_source_id);
+ to_hash.push_back(tile_atlas_coords);
+ to_hash.push_back(tile_alternative_tile);
+ uint32_t hash = RandomPCG(to_hash.hash()).rand();
+
+ Color color;
+ color = color.from_hsv(
+ (float)((hash >> 24) & 0xFF) / 256.0,
+ Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
+ Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
+ 0.8);
+
+ // Draw the scaled tile.
+ Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - Vector2(tile_shape_size) / 2, Vector2(tile_shape_size)));
+ tile_set->draw_tile_shape(p_overlay, cell_region, color, true, warning_pattern_texture);
+
+ // Draw the warning icon.
+ Rect2 rect = Rect2(xform.xform(tile_map->map_to_world(coords)) - (icon_ratio * missing_tile_texture->get_size() * xform.get_scale() / 2), icon_ratio * missing_tile_texture->get_size() * xform.get_scale());
+ p_overlay->draw_texture_rect(missing_tile_texture, rect);
+ }
+ }
+ }
+
+ // Fading on the border.
+ const int fading = 5;
+
+ // Determine the drawn area.
+ Size2 screen_size = p_overlay->get_size();
+ Rect2i screen_rect;
+ screen_rect.position = tile_map->world_to_map(xform_inv.xform(Vector2()));
+ screen_rect.expand_to(tile_map->world_to_map(xform_inv.xform(Vector2(0, screen_size.height))));
+ screen_rect.expand_to(tile_map->world_to_map(xform_inv.xform(Vector2(screen_size.width, 0))));
+ screen_rect.expand_to(tile_map->world_to_map(xform_inv.xform(screen_size)));
+ screen_rect = screen_rect.grow(1);
+
+ Rect2i tilemap_used_rect = tile_map->get_used_rect();
+
+ Rect2i displayed_rect = tilemap_used_rect.intersection(screen_rect);
+ displayed_rect = displayed_rect.grow(fading);
+
+ // Reduce the drawn area to avoid crashes if needed.
+ int max_size = 100;
+ if (displayed_rect.size.x > max_size) {
+ displayed_rect = displayed_rect.grow_individual(-(displayed_rect.size.x - max_size) / 2, 0, -(displayed_rect.size.x - max_size) / 2, 0);
+ }
+ if (displayed_rect.size.y > max_size) {
+ displayed_rect = displayed_rect.grow_individual(0, -(displayed_rect.size.y - max_size) / 2, 0, -(displayed_rect.size.y - max_size) / 2);
+ }
+
+ // Draw the grid.
+ bool display_grid = EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid");
+ if (display_grid) {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) {
+ for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) {
+ Vector2i pos_in_rect = Vector2i(x, y) - displayed_rect.position;
+
+ // Fade out the border of the grid.
+ float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f);
+ float right_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.x, (float)(displayed_rect.size.x - fading), (float)pos_in_rect.x), 0.0f, 1.0f);
+ float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f);
+ float bottom_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.y, (float)(displayed_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f);
+ float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
+
+ Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(Vector2(x, y)) - tile_shape_size / 2, tile_shape_size));
+ Color color = grid_color;
+ color.a = color.a * opacity;
+ tile_set->draw_tile_shape(p_overlay, cell_region, color, false);
+ }
+ }
+ }
+
+ // Draw the IDs for debug.
+ /*Ref<Font> font = get_theme_font("font", "Label");
+ for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) {
+ for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) {
+ p_overlay->draw_string(font, xform.xform(tile_map->map_to_world(Vector2(x, y))) + Vector2i(-tile_shape_size.x / 2, 0), vformat("%s", Vector2(x, y)));
+ }
+ }*/
+
+ // Draw the plugins.
+ tile_map_editor_plugins[tabs->get_current_tab()]->forward_canvas_draw_over_viewport(p_overlay);
+}
+
+void TileMapEditor::edit(TileMap *p_tile_map) {
+ if (p_tile_map && p_tile_map->get_instance_id() == tile_map_id) {
+ return;
+ }
+
+ // Disconnect to changes.
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (tile_map) {
+ tile_map->disconnect("changed", callable_mp(this, &TileMapEditor::_tile_map_changed));
+ }
+
+ // Change the edited object.
+ if (p_tile_map) {
+ tile_map_id = p_tile_map->get_instance_id();
+ tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ // Connect to changes.
+ if (!tile_map->is_connected("changed", callable_mp(this, &TileMapEditor::_tile_map_changed))) {
+ tile_map->connect("changed", callable_mp(this, &TileMapEditor::_tile_map_changed));
+ }
+ } else {
+ tile_map_id = ObjectID();
+ }
+
+ // Call the plugins.
+ tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id);
+
+ _tile_map_changed();
+}
+
+TileMapEditor::TileMapEditor() {
+ set_process_internal(true);
+
+ // TileMap editor plugins
+ tile_map_editor_plugins.push_back(memnew(TileMapEditorTilesPlugin));
+ tile_map_editor_plugins.push_back(memnew(TileMapEditorTerrainsPlugin));
+
+ // Tabs.
+ tabs = memnew(Tabs);
+ tabs->set_clip_tabs(false);
+ for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
+ tabs->add_tab(tile_map_editor_plugins[i]->get_name());
+ }
+ tabs->connect("tab_changed", callable_mp(this, &TileMapEditor::_tab_changed));
+
+ // --- TileMap toolbar ---
+ tilemap_toolbar = memnew(HBoxContainer);
+ tilemap_toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
+ tilemap_toolbar->add_child(tabs);
+ for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
+ tile_map_editor_plugins[i]->get_toolbar()->hide();
+ tilemap_toolbar->add_child(tile_map_editor_plugins[i]->get_toolbar());
+ }
+
+ missing_tileset_label = memnew(Label);
+ missing_tileset_label->set_text(TTR("The edited TileMap node has no TileSet resource."));
+ missing_tileset_label->set_h_size_flags(SIZE_EXPAND_FILL);
+ missing_tileset_label->set_v_size_flags(SIZE_EXPAND_FILL);
+ missing_tileset_label->set_align(Label::ALIGN_CENTER);
+ missing_tileset_label->set_valign(Label::VALIGN_CENTER);
+ missing_tileset_label->hide();
+ add_child(missing_tileset_label);
+
+ for (int i = 0; i < tile_map_editor_plugins.size(); i++) {
+ add_child(tile_map_editor_plugins[i]);
+ tile_map_editor_plugins[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ tile_map_editor_plugins[i]->set_v_size_flags(SIZE_EXPAND_FILL);
+ tile_map_editor_plugins[i]->set_visible(i == 0);
+ }
+
+ _tab_changed(0);
+}
+
+TileMapEditor::~TileMapEditor() {
+}
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
new file mode 100644
index 0000000000..a6f4ec3021
--- /dev/null
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -0,0 +1,343 @@
+/*************************************************************************/
+/* tile_map_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TILE_MAP_EDITOR_H
+#define TILE_MAP_EDITOR_H
+
+#include "tile_atlas_view.h"
+
+#include "core/typedefs.h"
+#include "editor/editor_node.h"
+#include "scene/2d/tile_map.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/tabs.h"
+
+class TileMapEditorPlugin : public VBoxContainer {
+public:
+ virtual Control *get_toolbar() const {
+ return memnew(Control);
+ };
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; };
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay){};
+ virtual void tile_set_changed(){};
+ virtual void edit(ObjectID p_tile_map_id){};
+};
+
+class TileMapEditorTilesPlugin : public TileMapEditorPlugin {
+ GDCLASS(TileMapEditorTilesPlugin, TileMapEditorPlugin);
+
+private:
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ ObjectID tile_map_id;
+ virtual void edit(ObjectID p_tile_map_id) override;
+
+ ///// Toolbar /////
+ HBoxContainer *toolbar;
+
+ Ref<ButtonGroup> tool_buttons_group;
+ Button *select_tool_button;
+ Button *paint_tool_button;
+ Button *line_tool_button;
+ Button *rect_tool_button;
+ Button *bucket_tool_button;
+ Button *picker_button;
+
+ HBoxContainer *tools_settings;
+ VSeparator *tools_settings_vsep;
+ Button *erase_button;
+ CheckBox *bucket_continuous_checkbox;
+
+ VSeparator *tools_settings_vsep_2;
+ CheckBox *random_tile_checkbox;
+ float scattering = 0.0;
+ Label *scatter_label;
+ SpinBox *scatter_spinbox;
+ void _on_random_tile_checkbox_toggled(bool p_pressed);
+ void _on_scattering_spinbox_changed(double p_value);
+
+ Button *toggle_grid_button;
+ void _on_grid_toggled(bool p_pressed);
+
+ void _update_toolbar();
+
+ ///// Tilemap editing. /////
+ bool has_mouse = false;
+ void _mouse_exited_viewport();
+
+ enum DragType {
+ DRAG_TYPE_NONE = 0,
+ DRAG_TYPE_SELECT,
+ DRAG_TYPE_MOVE,
+ DRAG_TYPE_PAINT,
+ DRAG_TYPE_LINE,
+ DRAG_TYPE_RECT,
+ DRAG_TYPE_BUCKET,
+ DRAG_TYPE_PICK,
+ DRAG_TYPE_CLIPBOARD_PASTE,
+ };
+ DragType drag_type = DRAG_TYPE_NONE;
+ Vector2 drag_start_mouse_pos;
+ Vector2 drag_last_mouse_pos;
+ Map<Vector2i, TileMapCell> drag_modified;
+
+ TileMapCell _pick_random_tile(const TileMapPattern *p_pattern);
+ Map<Vector2i, TileMapCell> _draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos);
+ Map<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell);
+ Map<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous);
+ void _stop_dragging();
+
+ ///// Selection system. /////
+ Set<Vector2i> tile_map_selection;
+ TileMapPattern *tile_map_clipboard = memnew(TileMapPattern);
+ TileMapPattern *selection_pattern = memnew(TileMapPattern);
+ void _set_tile_map_selection(const TypedArray<Vector2i> &p_selection);
+ TypedArray<Vector2i> _get_tile_map_selection() const;
+
+ Set<TileMapCell> tile_set_selection;
+
+ void _update_selection_pattern_from_tilemap_selection();
+ void _update_selection_pattern_from_tileset_selection();
+ void _update_tileset_selection_from_selection_pattern();
+ void _update_fix_selected_and_hovered();
+
+ ///// Bottom panel. ////.
+ Label *missing_source_label;
+ Label *invalid_source_label;
+
+ ItemList *sources_list;
+
+ Ref<Texture2D> missing_atlas_texture_icon;
+ void _update_tile_set_sources_list();
+
+ void _update_bottom_panel();
+
+ // Atlas sources.
+ TileMapCell hovered_tile;
+ TileAtlasView *tile_atlas_view;
+ HSplitContainer *atlas_sources_split_container;
+
+ bool tile_set_dragging_selection = false;
+ Vector2i tile_set_drag_start_mouse_pos;
+
+ Control *tile_atlas_control;
+ void _tile_atlas_control_mouse_exited();
+ void _tile_atlas_control_gui_input(const Ref<InputEvent> &p_event);
+ void _tile_atlas_control_draw();
+
+ Control *alternative_tiles_control;
+ void _tile_alternatives_control_draw();
+ void _tile_alternatives_control_mouse_exited();
+ void _tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event);
+
+ void _update_atlas_view();
+
+ // Scenes collection sources.
+ ItemList *scene_tiles_list;
+
+ void _update_scenes_collection_view();
+ void _scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud);
+ void _scenes_list_multi_selected(int p_index, bool p_selected);
+ void _scenes_list_nothing_selected();
+
+ // Update callback
+ virtual void tile_set_changed() override;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ virtual Control *get_toolbar() const override;
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
+
+ TileMapEditorTilesPlugin();
+ ~TileMapEditorTilesPlugin();
+};
+
+class TileMapEditorTerrainsPlugin : public TileMapEditorPlugin {
+ GDCLASS(TileMapEditorTerrainsPlugin, TileMapEditorPlugin);
+
+private:
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ ObjectID tile_map_id;
+ virtual void edit(ObjectID p_tile_map_id) override;
+
+ // Toolbar.
+ HBoxContainer *toolbar;
+
+ Ref<ButtonGroup> tool_buttons_group;
+ Button *paint_tool_button;
+
+ HBoxContainer *tools_settings;
+ VSeparator *tools_settings_vsep;
+ Button *picker_button;
+ Button *erase_button;
+
+ void _update_toolbar();
+
+ // TileMap editing.
+ enum DragType {
+ DRAG_TYPE_NONE = 0,
+ DRAG_TYPE_PAINT,
+ DRAG_TYPE_PICK,
+ };
+ DragType drag_type = DRAG_TYPE_NONE;
+ Vector2 drag_start_mouse_pos;
+ Vector2 drag_last_mouse_pos;
+ Map<Vector2i, TileMapCell> drag_modified;
+
+ // Painting
+ class Constraint {
+ private:
+ const TileMap *tile_map;
+ Vector2i base_cell_coords = Vector2i();
+ int bit = -1;
+ int terrain = -1;
+
+ public:
+ // TODO implement difference operator.
+ bool operator<(const Constraint &p_other) const {
+ if (base_cell_coords == p_other.base_cell_coords) {
+ return bit < p_other.bit;
+ }
+ return base_cell_coords < p_other.base_cell_coords;
+ }
+
+ String to_string() const {
+ return vformat("Constraint {pos:%s, bit:%d, terrain:%d}", base_cell_coords, bit, terrain);
+ }
+
+ Vector2i get_base_cell_coords() const {
+ return base_cell_coords;
+ }
+
+ Map<Vector2i, TileSet::CellNeighbor> get_overlapping_coords_and_peering_bits() const;
+
+ void set_terrain(int p_terrain) {
+ terrain = p_terrain;
+ }
+
+ int get_terrain() const {
+ return terrain;
+ }
+
+ Constraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain);
+ Constraint() {}
+ };
+
+ typedef Array TerrainsTilePattern;
+
+ Set<TerrainsTilePattern> _get_valid_terrains_tile_patterns_for_constraints(int p_terrain_set, const Vector2i &p_position, Set<TileMapEditorTerrainsPlugin::Constraint> p_constraints) const;
+ Set<TileMapEditorTerrainsPlugin::Constraint> _get_constraints_from_removed_cells_list(const Set<Vector2i> &p_to_replace, int p_terrain_set) const;
+ Set<TileMapEditorTerrainsPlugin::Constraint> _get_constraints_from_added_tile(Vector2i p_position, int p_terrain_set, TerrainsTilePattern p_terrains_tile_pattern) const;
+ Map<Vector2i, TerrainsTilePattern> _wave_function_collapse(const Set<Vector2i> &p_to_replace, int p_terrain_set, const Set<TileMapEditorTerrainsPlugin::Constraint> p_constraints) const;
+ TileMapCell _get_random_tile_from_pattern(int p_terrain_set, TerrainsTilePattern p_terrain_tile_pattern) const;
+ Map<Vector2i, TileMapCell> _draw_terrains(const Map<Vector2i, TerrainsTilePattern> &p_to_paint, int p_terrain_set) const;
+
+ // Cached data.
+
+ TerrainsTilePattern _build_terrains_tile_pattern(TileData *p_tile_data);
+ LocalVector<Map<TerrainsTilePattern, Set<TileMapCell>>> per_terrain_terrains_tile_patterns_tiles;
+ LocalVector<LocalVector<Set<TerrainsTilePattern>>> per_terrain_terrains_tile_patterns;
+
+ Map<TileMapCell, TileData *> terrain_tiles;
+ LocalVector<TileSet::CellNeighbor> tile_sides;
+
+ // Bottom panel.
+ Tree *terrains_tree;
+ ItemList *terrains_tile_list;
+
+ // Update functions.
+ void _update_terrains_cache();
+ void _update_terrains_tree();
+ void _update_tiles_list();
+
+ // Update callback
+ virtual void tile_set_changed() override;
+
+protected:
+ void _notification(int p_what);
+ // static void _bind_methods();
+
+public:
+ virtual Control *get_toolbar() const override;
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
+ //virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
+
+ TileMapEditorTerrainsPlugin();
+ ~TileMapEditorTerrainsPlugin();
+};
+
+class TileMapEditor : public VBoxContainer {
+ GDCLASS(TileMapEditor, VBoxContainer);
+
+private:
+ bool tileset_changed_needs_update = false;
+ ObjectID tile_map_id;
+
+ // Vector to keep plugins.
+ Vector<TileMapEditorPlugin *> tile_map_editor_plugins;
+
+ // Toolbar.
+ HBoxContainer *tilemap_toolbar;
+
+ // Bottom panel
+ Label *missing_tileset_label;
+ Tabs *tabs;
+ void _update_bottom_panel();
+
+ // TileMap
+ Ref<Texture2D> missing_tile_texture;
+ Ref<Texture2D> warning_pattern_texture;
+
+ // CallBack
+ void _tile_map_changed();
+ void _tab_changed(int p_tab_changed);
+
+protected:
+ void _notification(int p_what);
+ void _draw_shape(Control *p_control, Rect2 p_region, TileSet::TileShape p_shape, TileSet::TileOffsetAxis p_offset_axis, Color p_color);
+
+public:
+ bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
+ void forward_canvas_draw_over_viewport(Control *p_overlay);
+
+ void edit(TileMap *p_tile_map);
+ Control *get_toolbar() { return tilemap_toolbar; };
+
+ TileMapEditor();
+ ~TileMapEditor();
+
+ // Static functions.
+ static Vector<Vector2i> get_line(TileMap *p_tile_map, Vector2i p_from_cell, Vector2i p_to_cell);
+};
+
+#endif // TILE_MAP_EDITOR_PLUGIN_H
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
new file mode 100644
index 0000000000..8e7d613027
--- /dev/null
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -0,0 +1,1863 @@
+/*************************************************************************/
+/* tile_set_atlas_source_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "tile_set_atlas_source_editor.h"
+
+#include "tiles_editor_plugin.h"
+
+#include "editor/editor_inspector.h"
+#include "editor/editor_scale.h"
+#include "editor/progress_dialog.h"
+
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/control.h"
+#include "scene/gui/item_list.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/split_container.h"
+#include "scene/gui/tab_container.h"
+
+#include "core/core_string_names.h"
+#include "core/math/geometry_2d.h"
+#include "core/os/keyboard.h"
+
+void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::set_id(int p_id) {
+ ERR_FAIL_COND(p_id < 0);
+ if (source_id == p_id) {
+ return;
+ }
+ ERR_FAIL_COND_MSG(tile_set->has_source(p_id), vformat("Cannot change TileSet Atlas Source ID. Another source exists with id %d.", p_id));
+
+ int previous_source = source_id;
+ source_id = p_id; // source_id must be updated before, because it's used by the source list update.
+ tile_set->set_source_id(previous_source, p_id);
+ emit_signal("changed", "id");
+}
+
+int TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::get_id() {
+ return source_id;
+}
+
+bool TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_set(const StringName &p_name, const Variant &p_value) {
+ bool valid = false;
+ tile_set_atlas_source->set(p_name, p_value, &valid);
+ if (valid) {
+ emit_signal("changed", String(p_name).utf8().get_data());
+ }
+ return valid;
+}
+
+bool TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get(const StringName &p_name, Variant &r_ret) const {
+ if (!tile_set_atlas_source) {
+ return false;
+ }
+ bool valid = false;
+ r_ret = tile_set_atlas_source->get(p_name, &valid);
+ return valid;
+}
+
+void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "tile_size", PROPERTY_HINT_NONE, ""));
+}
+
+void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_bind_methods() {
+ // -- Shape and layout --
+ ClassDB::bind_method(D_METHOD("set_id", "id"), &TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::set_id);
+ ClassDB::bind_method(D_METHOD("get_id"), &TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::get_id);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "id"), "set_id", "get_id");
+
+ ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what")));
+}
+
+void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id) {
+ ERR_FAIL_COND(!p_tile_set.is_valid());
+ ERR_FAIL_COND(!p_tile_set_atlas_source);
+ ERR_FAIL_COND(p_source_id < 0);
+ ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
+
+ // Disconnect to changes.
+ if (tile_set_atlas_source) {
+ tile_set_atlas_source->disconnect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
+ }
+
+ tile_set = p_tile_set;
+ tile_set_atlas_source = p_tile_set_atlas_source;
+ source_id = p_source_id;
+
+ // Connect to changes.
+ if (tile_set_atlas_source) {
+ if (!tile_set_atlas_source->is_connected(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed))) {
+ tile_set_atlas_source->connect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
+ }
+ }
+
+ notify_property_list_changed();
+}
+
+// -- Proxy object used by the tile inspector --
+bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_name, const Variant &p_value) {
+ if (!tile_set_atlas_source) {
+ return false;
+ }
+
+ if (tiles.size() == 1) {
+ const Vector2i &coords = tiles.front()->get().tile;
+ const int &alternative = tiles.front()->get().alternative;
+
+ if (alternative == 0 && p_name == "atlas_coords") {
+ Vector2i as_vector2i = Vector2i(p_value);
+ ERR_FAIL_COND_V(!tile_set_atlas_source->can_move_tile_in_atlas(coords, as_vector2i), false);
+
+ if (tiles_set_atlas_source_editor->selection.front()->get().tile == coords) {
+ tiles_set_atlas_source_editor->selection.clear();
+ tiles_set_atlas_source_editor->selection.insert({ as_vector2i, 0 });
+ tiles_set_atlas_source_editor->_update_tile_id_label();
+ }
+
+ tile_set_atlas_source->move_tile_in_atlas(coords, as_vector2i);
+ tiles.clear();
+ tiles.insert({ as_vector2i, 0 });
+ emit_signal("changed", "atlas_coords");
+ return true;
+ } else if (alternative == 0 && p_name == "size_in_atlas") {
+ Vector2i as_vector2i = Vector2i(p_value);
+ ERR_FAIL_COND_V(!tile_set_atlas_source->can_move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i), false);
+
+ tile_set_atlas_source->move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i);
+ emit_signal("changed", "size_in_atlas");
+ return true;
+ } else if (alternative > 0 && p_name == "alternative_id") {
+ int as_int = int(p_value);
+ ERR_FAIL_COND_V(as_int < 0, false);
+ ERR_FAIL_COND_V_MSG(tile_set_atlas_source->has_alternative_tile(coords, as_int), false, vformat("Cannot change alternative tile ID. Another alternative exists with id %d for tile at coords %s.", as_int, coords));
+
+ if (tiles_set_atlas_source_editor->selection.front()->get().alternative == alternative) {
+ tiles_set_atlas_source_editor->selection.clear();
+ tiles_set_atlas_source_editor->selection.insert({ coords, as_int });
+ }
+
+ int previous_alternative_tile = alternative;
+ tiles.clear();
+ tiles.insert({ coords, as_int }); // tiles must be updated before.
+ tile_set_atlas_source->set_alternative_tile_id(coords, previous_alternative_tile, as_int);
+
+ emit_signal("changed", "alternative_id");
+ return true;
+ }
+ }
+
+ bool any_valid = false;
+ for (Set<TileSelection>::Element *E = tiles.front(); E; E = E->next()) {
+ const Vector2i &coords = E->get().tile;
+ const int &alternative = E->get().alternative;
+
+ bool valid = false;
+ TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(coords, alternative));
+ ERR_FAIL_COND_V(!tile_data, false);
+ tile_data->set(p_name, p_value, &valid);
+
+ any_valid |= valid;
+ }
+
+ if (any_valid) {
+ emit_signal("changed", String(p_name).utf8().get_data());
+ }
+
+ return any_valid;
+}
+
+bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_name, Variant &r_ret) const {
+ if (!tile_set_atlas_source) {
+ return false;
+ }
+
+ if (tiles.size() == 1) {
+ const Vector2i &coords = tiles.front()->get().tile;
+ const int &alternative = tiles.front()->get().alternative;
+
+ if (alternative == 0 && p_name == "atlas_coords") {
+ r_ret = coords;
+ return true;
+ } else if (alternative == 0 && p_name == "size_in_atlas") {
+ r_ret = tile_set_atlas_source->get_tile_size_in_atlas(coords);
+ return true;
+ } else if (alternative > 0 && p_name == "alternative_id") {
+ r_ret = alternative;
+ return true;
+ }
+ }
+
+ for (Set<TileSelection>::Element *E = tiles.front(); E; E = E->next()) {
+ // Return the first tile with a property matching the name.
+ // Note: It's a little bit annoying, but the behavior is the same the one in MultiNodeEdit.
+ const Vector2i &coords = E->get().tile;
+ const int &alternative = E->get().alternative;
+
+ TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(coords, alternative));
+ ERR_FAIL_COND_V(!tile_data, false);
+
+ bool valid = false;
+ r_ret = tile_data->get(p_name, &valid);
+ if (valid) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<PropertyInfo> *p_list) const {
+ if (!tile_set_atlas_source) {
+ return;
+ }
+
+ if (tiles.size() == 1) {
+ if (tiles.front()->get().alternative == 0) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "atlas_coords", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size_in_atlas", PROPERTY_HINT_NONE, ""));
+ } else {
+ p_list->push_back(PropertyInfo(Variant::INT, "alternative_id", PROPERTY_HINT_NONE, ""));
+ }
+ }
+
+ // Get the list of properties common to all tiles (similar to what's done in MultiNodeEdit).
+ struct PropertyId {
+ int occurence_id = 0;
+ String property;
+ bool operator<(const PropertyId &p_other) const {
+ return occurence_id == p_other.occurence_id ? property < p_other.property : occurence_id < p_other.occurence_id;
+ }
+ };
+ struct PLData {
+ int uses = 0;
+ PropertyInfo property_info;
+ };
+ Map<PropertyId, PLData> usage;
+
+ List<PLData *> data_list;
+ for (Set<TileSelection>::Element *E = tiles.front(); E; E = E->next()) {
+ const Vector2i &coords = E->get().tile;
+ const int &alternative = E->get().alternative;
+
+ TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(coords, alternative));
+ ERR_FAIL_COND(!tile_data);
+
+ List<PropertyInfo> list;
+ tile_data->get_property_list(&list);
+
+ Map<String, int> counts; // Counts the number of time a property appears (useful for groups that may appear more than once)
+ for (List<PropertyInfo>::Element *E_property = list.front(); E_property; E_property = E_property->next()) {
+ const String &property_string = E_property->get().name;
+ if (!tile_data->is_allowing_transform() && (property_string == "flip_h" || property_string == "flip_v" || property_string == "transpose")) {
+ continue;
+ }
+
+ if (!counts.has(property_string)) {
+ counts[property_string] = 1;
+ } else {
+ counts[property_string] += 1;
+ }
+
+ PropertyInfo stored_property_info = E_property->get();
+ stored_property_info.usage |= PROPERTY_USAGE_STORAGE; // Ignore the storage flag in comparing properties.
+
+ PropertyId id = { counts[property_string], property_string };
+ if (!usage.has(id)) {
+ usage[id] = { 1, stored_property_info };
+ data_list.push_back(&usage[id]);
+ } else if (usage[id].property_info == stored_property_info) {
+ usage[id].uses += 1;
+ }
+ }
+ }
+
+ // Add only properties that are common to all tiles.
+ for (List<PLData *>::Element *E = data_list.front(); E; E = E->next()) {
+ if (E->get()->uses == tiles.size()) {
+ p_list->push_back(E->get()->property_info);
+ }
+ }
+}
+
+void TileSetAtlasSourceEditor::AtlasTileProxyObject::edit(TileSetAtlasSource *p_tile_set_atlas_source, Set<TileSelection> p_tiles) {
+ ERR_FAIL_COND(!p_tile_set_atlas_source);
+ ERR_FAIL_COND(p_tiles.is_empty());
+ for (Set<TileSelection>::Element *E = p_tiles.front(); E; E = E->next()) {
+ ERR_FAIL_COND(E->get().tile == TileSetSource::INVALID_ATLAS_COORDS);
+ ERR_FAIL_COND(E->get().alternative < 0);
+ }
+
+ // Disconnect to changes.
+ for (Set<TileSelection>::Element *E = tiles.front(); E; E = E->next()) {
+ const Vector2i &coords = E->get().tile;
+ const int &alternative = E->get().alternative;
+
+ if (tile_set_atlas_source && tile_set_atlas_source->has_tile(coords) && tile_set_atlas_source->has_alternative_tile(coords, alternative)) {
+ TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(coords, alternative));
+ if (tile_data->is_connected(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed))) {
+ tile_data->disconnect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
+ }
+ }
+ }
+
+ tile_set_atlas_source = p_tile_set_atlas_source;
+ tiles = Set<TileSelection>(p_tiles);
+
+ // Connect to changes.
+ for (Set<TileSelection>::Element *E = p_tiles.front(); E; E = E->next()) {
+ const Vector2i &coords = E->get().tile;
+ const int &alternative = E->get().alternative;
+
+ if (tile_set_atlas_source->has_tile(coords) && tile_set_atlas_source->has_alternative_tile(coords, alternative)) {
+ TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(coords, alternative));
+ if (!tile_data->is_connected(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed))) {
+ tile_data->connect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
+ }
+ }
+ }
+
+ notify_property_list_changed();
+}
+
+void TileSetAtlasSourceEditor::AtlasTileProxyObject::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what")));
+}
+
+void TileSetAtlasSourceEditor::_inspector_property_selected(String p_property) {
+ selected_property = p_property;
+ _update_atlas_view();
+}
+
+void TileSetAtlasSourceEditor::_update_tile_id_label() {
+ if (selection.size() == 1) {
+ TileSelection selected = selection.front()->get();
+ tool_tile_id_label->set_text(vformat("%d, %s, %d", tile_set_atlas_source_id, selected.tile, selected.alternative));
+ tool_tile_id_label->set_tooltip(vformat(TTR("Selected tile:\nSource: %d\nAtlas coordinates: %s\nAlternative: %d"), tile_set_atlas_source_id, selected.tile, selected.alternative));
+ tool_tile_id_label->show();
+ } else {
+ tool_tile_id_label->hide();
+ }
+}
+
+void TileSetAtlasSourceEditor::_update_source_inspector() {
+ // Update the proxy object.
+ atlas_source_proxy_object->edit(tile_set, tile_set_atlas_source, tile_set_atlas_source_id);
+
+ // Update the "clear outside texture" button.
+ tool_advanced_menu_buttom->get_popup()->set_item_disabled(0, !tile_set_atlas_source->has_tiles_outside_texture());
+}
+
+void TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles() {
+ // Fix selected.
+ for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) {
+ TileSelection selected = E->get();
+ if (!tile_set_atlas_source->has_tile(selected.tile) || !tile_set_atlas_source->has_alternative_tile(selected.tile, selected.alternative)) {
+ selection.erase(E);
+ }
+ }
+
+ // Fix hovered.
+ if (!tile_set_atlas_source->has_tile(hovered_base_tile_coords)) {
+ hovered_base_tile_coords = TileSetSource::INVALID_ATLAS_COORDS;
+ }
+ Vector2i coords = Vector2i(hovered_alternative_tile_coords.x, hovered_alternative_tile_coords.y);
+ int alternative = hovered_alternative_tile_coords.z;
+ if (!tile_set_atlas_source->has_tile(coords) || !tile_set_atlas_source->has_alternative_tile(coords, alternative)) {
+ hovered_alternative_tile_coords = Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ }
+}
+
+void TileSetAtlasSourceEditor::_update_tile_inspector() {
+ bool has_atlas_tile_selected = (tools_button_group->get_pressed_button() == tool_select_button) && !selection.is_empty();
+
+ // Update the proxy object.
+ if (has_atlas_tile_selected) {
+ tile_proxy_object->edit(tile_set_atlas_source, selection);
+ }
+
+ // Update visibility.
+ tile_inspector_label->set_visible(has_atlas_tile_selected);
+ tile_inspector->set_visible(has_atlas_tile_selected);
+}
+
+void TileSetAtlasSourceEditor::_update_atlas_view() {
+ // Update the atlas display.
+ tile_atlas_view->set_atlas_source(*tile_set, tile_set_atlas_source, tile_set_atlas_source_id);
+
+ // Create a bunch of buttons to add alternative tiles.
+ for (int i = 0; i < alternative_tiles_control->get_child_count(); i++) {
+ alternative_tiles_control->get_child(i)->queue_delete();
+ }
+
+ Vector2i pos;
+ Vector2 texture_region_base_size = tile_set_atlas_source->get_texture_region_size();
+ int texture_region_base_size_min = MIN(texture_region_base_size.x, texture_region_base_size.y);
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
+ int alternative_count = tile_set_atlas_source->get_alternative_tiles_count(tile_id);
+ if (alternative_count > 1) {
+ // Compute the right extremity of alternative.
+ int y_increment = 0;
+ pos.x = 0;
+ for (int j = 1; j < alternative_count; j++) {
+ int alternative_id = tile_set_atlas_source->get_alternative_tile_id(tile_id, j);
+ Rect2i rect = tile_atlas_view->get_alternative_tile_rect(tile_id, alternative_id);
+ pos.x = MAX(pos.x, rect.get_end().x);
+ y_increment = MAX(y_increment, rect.size.y);
+ }
+
+ // Create and position the button.
+ Button *button = memnew(Button);
+ alternative_tiles_control->add_child(button);
+ button->set_flat(true);
+ button->set_icon(get_theme_icon("Add", "EditorIcons"));
+ button->add_theme_style_override("normal", memnew(StyleBoxEmpty));
+ button->add_theme_style_override("hover", memnew(StyleBoxEmpty));
+ button->add_theme_style_override("focus", memnew(StyleBoxEmpty));
+ button->add_theme_style_override("pressed", memnew(StyleBoxEmpty));
+ button->connect("pressed", callable_mp(tile_set_atlas_source, &TileSetAtlasSource::create_alternative_tile), varray(tile_id, -1));
+ button->set_rect(Rect2(Vector2(pos.x, pos.y + (y_increment - texture_region_base_size.y) / 2.0), Vector2(texture_region_base_size_min, texture_region_base_size_min)));
+ button->set_expand_icon(true);
+
+ pos.y += y_increment;
+ }
+ }
+ tile_atlas_view->set_padding(Side::SIDE_RIGHT, texture_region_base_size_min);
+
+ // Redraw everything.
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ tile_atlas_view->update();
+
+ // Synchronize atlas view.
+ TilesEditor::get_singleton()->synchronize_atlas_view(tile_atlas_view);
+}
+
+void TileSetAtlasSourceEditor::_update_toolbar() {
+ // Hide all settings.
+ for (int i = 0; i < tool_settings->get_child_count(); i++) {
+ Object::cast_to<CanvasItem>(tool_settings->get_child(i))->hide();
+ }
+
+ // SHow only the correct settings.
+ if (tools_button_group->get_pressed_button() == tool_select_button) {
+ } else if (tools_button_group->get_pressed_button() == tool_add_remove_button) {
+ tool_settings_vsep->show();
+ tools_settings_erase_button->show();
+ } else if (tools_button_group->get_pressed_button() == tool_add_remove_rect_button) {
+ tool_settings_vsep->show();
+ tools_settings_erase_button->show();
+ }
+}
+
+void TileSetAtlasSourceEditor::_tile_atlas_control_mouse_exited() {
+ hovered_base_tile_coords = TileSetSource::INVALID_ATLAS_COORDS;
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ tile_atlas_view->update();
+}
+
+void TileSetAtlasSourceEditor::_tile_atlas_view_transform_changed() {
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+}
+
+void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) {
+ // Update the hovered coords.
+ hovered_base_tile_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+
+ // Handle the event.
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+
+ Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+
+ if (drag_type == DRAG_TYPE_NONE) {
+ if (selection.size() == 1) {
+ // Change the cursor depending on the hovered thing.
+ TileSelection selected = selection.front()->get();
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
+ Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
+ Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
+ Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
+ Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
+ Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
+ const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
+ const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
+ CursorShape cursor_shape = CURSOR_ARROW;
+ bool can_grow[4];
+ for (int i = 0; i < 4; i++) {
+ can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]);
+ can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
+ }
+ for (int i = 0; i < 4; i++) {
+ Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i];
+ if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
+ cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
+ }
+ Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4];
+ if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
+ cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
+ }
+ }
+ tile_atlas_control->set_default_cursor_shape(cursor_shape);
+ }
+ }
+ } else if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) {
+ // Create big tile.
+ new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+
+ Rect2i new_rect = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
+ new_rect.size += Vector2i(1, 1);
+ // Check if the new tile can fit in the new rect.
+ if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) {
+ // Move and resize the tile.
+ tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size);
+ drag_current_tile = new_rect.position;
+ }
+ } else if (drag_type == DRAG_TYPE_CREATE_TILES) {
+ // Create tiles.
+ last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+ new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+
+ Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords);
+ for (int i = 0; i < line.size(); i++) {
+ if (tile_set_atlas_source->get_tile_at_coords(line[i]) == TileSetSource::INVALID_ATLAS_COORDS) {
+ tile_set_atlas_source->create_tile(line[i]);
+ drag_modified_tiles.insert(line[i]);
+ }
+ }
+
+ drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position();
+
+ } else if (drag_type == DRAG_TYPE_REMOVE_TILES) {
+ // Remove tiles.
+ last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+ new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+
+ Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords);
+ for (int i = 0; i < line.size(); i++) {
+ Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(line[i]);
+ if (base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ drag_modified_tiles.insert(base_tile_coords);
+ }
+ }
+
+ drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position();
+ } else if (drag_type == DRAG_TYPE_MOVE_TILE) {
+ // Move tile.
+ Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset);
+ coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
+ if (drag_current_tile != coords && tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, coords)) {
+ tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords);
+ selection.clear();
+ selection.insert({ coords, 0 });
+ drag_current_tile = coords;
+
+ // Update only what's needed.
+ tile_set_atlas_source_changed_needs_update = false;
+ _update_tile_inspector();
+ _update_atlas_view();
+ _update_tile_id_label();
+ }
+ } else if (drag_type >= DRAG_TYPE_RESIZE_TOP_LEFT && drag_type <= DRAG_TYPE_RESIZE_LEFT) {
+ // Resizing a tile.
+ new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(-1, -1)).min(grid_size);
+
+ Rect2i old_rect = Rect2i(drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
+ Rect2i new_rect = old_rect;
+
+ if (drag_type == DRAG_TYPE_RESIZE_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT) {
+ new_rect.position.x = MIN(new_base_tiles_coords.x + 1, old_rect.get_end().x - 1);
+ new_rect.size.x = old_rect.get_end().x - new_rect.position.x;
+ }
+ if (drag_type == DRAG_TYPE_RESIZE_TOP || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT) {
+ new_rect.position.y = MIN(new_base_tiles_coords.y + 1, old_rect.get_end().y - 1);
+ new_rect.size.y = old_rect.get_end().y - new_rect.position.y;
+ }
+
+ if (drag_type == DRAG_TYPE_RESIZE_RIGHT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) {
+ new_rect.set_end(Vector2i(MAX(new_base_tiles_coords.x, old_rect.position.x + 1), new_rect.get_end().y));
+ }
+ if (drag_type == DRAG_TYPE_RESIZE_BOTTOM || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) {
+ new_rect.set_end(Vector2i(new_rect.get_end().x, MAX(new_base_tiles_coords.y, old_rect.position.y + 1)));
+ }
+
+ if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) {
+ tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size);
+ selection.clear();
+ selection.insert({ new_rect.position, 0 });
+ drag_current_tile = new_rect.position;
+
+ // Update only what's needed.
+ tile_set_atlas_source_changed_needs_update = false;
+ _update_tile_inspector();
+ _update_atlas_view();
+ _update_tile_id_label();
+ }
+ }
+
+ // Redraw for the hovered tile.
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ tile_atlas_view->update();
+ return;
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ // Left click pressed.
+ if (tools_button_group->get_pressed_button() == tool_add_remove_button) {
+ if (tools_settings_erase_button->is_pressed()) {
+ // Remove tiles.
+
+ // Setup the dragging info.
+ drag_type = DRAG_TYPE_REMOVE_TILES;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+
+ // Remove a first tile.
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ coords = tile_set_atlas_source->get_tile_at_coords(coords);
+ }
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ drag_modified_tiles.insert(coords);
+ }
+ } else {
+ if (mb->is_shift_pressed()) {
+ // Create a big tile.
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
+ // Setup the dragging info, only if we start on an empty tile.
+ drag_type = DRAG_TYPE_CREATE_BIG_TILE;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ drag_current_tile = coords;
+
+ // Create a tile.
+ tile_set_atlas_source->create_tile(coords);
+ }
+ } else {
+ // Create tiles.
+
+ // Setup the dragging info.
+ drag_type = DRAG_TYPE_CREATE_TILES;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+
+ // Create a first tile if needed.
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
+ tile_set_atlas_source->create_tile(coords);
+ drag_modified_tiles.insert(coords);
+ }
+ }
+ }
+ } else if (tools_button_group->get_pressed_button() == tool_add_remove_rect_button) {
+ if (tools_settings_erase_button->is_pressed()) {
+ // Remove tiles using rect.
+
+ // Setup the dragging info.
+ drag_type = DRAG_TYPE_REMOVE_TILES_USING_RECT;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ } else {
+ if (mb->is_shift_pressed()) {
+ // Create a big tile.
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
+ // Setup the dragging info, only if we start on an empty tile.
+ drag_type = DRAG_TYPE_CREATE_BIG_TILE;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ drag_current_tile = coords;
+
+ // Create a tile.
+ tile_set_atlas_source->create_tile(coords);
+ }
+ } else {
+ // Create tiles using rect.
+ drag_type = DRAG_TYPE_CREATE_TILES_USING_RECT;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ }
+ }
+ } else if (tools_button_group->get_pressed_button() == tool_select_button) {
+ // Dragging a handle.
+ drag_type = DRAG_TYPE_NONE;
+ if (selection.size() == 1) {
+ TileSelection selected = selection.front()->get();
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
+ Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
+ Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
+ Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
+ Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
+ const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
+ const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
+ CursorShape cursor_shape = CURSOR_ARROW;
+ bool can_grow[4];
+ for (int i = 0; i < 4; i++) {
+ can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]);
+ can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
+ }
+ for (int i = 0; i < 4; i++) {
+ Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i];
+ if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
+ drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP_LEFT + i * 2);
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ drag_current_tile = selected.tile;
+ drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
+ cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
+ }
+ Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4];
+ if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
+ drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP + i * 2);
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ drag_current_tile = selected.tile;
+ drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
+ cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
+ }
+ }
+ tile_atlas_control->set_default_cursor_shape(cursor_shape);
+ }
+ }
+
+ // Selecting then dragging a tile.
+ if (drag_type == DRAG_TYPE_NONE) {
+ TileSelection selected = { TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE };
+ Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ coords = tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ selected = { coords, 0 };
+ }
+ }
+
+ bool shift = mb->is_shift_pressed();
+ if (!shift && selection.size() == 1 && selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) {
+ // Start move dragging.
+ drag_type = DRAG_TYPE_MOVE_TILE;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ drag_current_tile = selected.tile;
+ drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
+ tile_atlas_control->set_default_cursor_shape(CURSOR_MOVE);
+ } else {
+ // Start selection dragging.
+ drag_type = DRAG_TYPE_RECT_SELECT;
+ drag_start_mouse_pos = mouse_local_pos;
+ drag_last_mouse_pos = drag_start_mouse_pos;
+ }
+ }
+ }
+ } else {
+ // Left click released.
+ _end_dragging();
+ }
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ tile_atlas_view->update();
+ return;
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (mb->is_pressed()) {
+ // Right click pressed.
+
+ TileSelection selected = { tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos), 0 };
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ selected.tile = tile_set_atlas_source->get_tile_at_coords(selected.tile);
+ }
+
+ // Set the selection if needed.
+ if (selection.size() <= 1) {
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ undo_redo->create_action(TTR("Select tiles"));
+ undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
+ selection.clear();
+ selection.insert(selected);
+ undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
+ undo_redo->commit_action(false);
+ _update_tile_inspector();
+ _update_tile_id_label();
+ }
+ }
+
+ // Pops up the correct menu, depending on whether we have a tile or not.
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) {
+ // We have a tile.
+ menu_option_coords = selected.tile;
+ menu_option_alternative = 0;
+ base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ } else if (hovered_base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ // We don't have a tile, but can create one.
+ menu_option_coords = hovered_base_tile_coords;
+ menu_option_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ empty_base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ }
+ } else {
+ // Right click released.
+ _end_dragging();
+ }
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ tile_atlas_view->update();
+ return;
+ }
+ }
+}
+
+void TileSetAtlasSourceEditor::_end_dragging() {
+ switch (drag_type) {
+ case DRAG_TYPE_CREATE_TILES:
+ undo_redo->create_action(TTR("Create tiles"));
+ for (Set<Vector2i>::Element *E = drag_modified_tiles.front(); E; E = E->next()) {
+ undo_redo->add_do_method(tile_set_atlas_source, "create_tile", E->get());
+ undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", E->get());
+ }
+ undo_redo->commit_action(false);
+ break;
+ case DRAG_TYPE_CREATE_BIG_TILE:
+ undo_redo->create_action(TTR("Create a tile"));
+ undo_redo->add_do_method(tile_set_atlas_source, "create_tile", drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
+ undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", drag_current_tile);
+ undo_redo->commit_action(false);
+ break;
+ case DRAG_TYPE_REMOVE_TILES: {
+ List<PropertyInfo> list;
+ tile_set_atlas_source->get_property_list(&list);
+ Map<Vector2i, List<const PropertyInfo *>> per_tile = _group_properties_per_tiles(list, tile_set_atlas_source);
+ undo_redo->create_action(TTR("Remove tiles"));
+ for (Set<Vector2i>::Element *E = drag_modified_tiles.front(); E; E = E->next()) {
+ Vector2i coords = E->get();
+ undo_redo->add_do_method(tile_set_atlas_source, "remove_tile", coords);
+ undo_redo->add_undo_method(tile_set_atlas_source, "create_tile", coords);
+ if (per_tile.has(coords)) {
+ for (List<const PropertyInfo *>::Element *E_property = per_tile[coords].front(); E_property; E_property = E_property->next()) {
+ String property = E_property->get()->name;
+ Variant value = tile_set_atlas_source->get(property);
+ if (value.get_type() != Variant::NIL) {
+ undo_redo->add_undo_method(tile_set_atlas_source, "set", E_property->get()->name, value);
+ }
+ }
+ }
+ }
+ undo_redo->commit_action();
+ } break;
+ case DRAG_TYPE_CREATE_TILES_USING_RECT: {
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
+ area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
+ undo_redo->create_action(TTR("Create tiles"));
+ for (int x = area.get_position().x; x < area.get_end().x; x++) {
+ for (int y = area.get_position().y; y < area.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
+ undo_redo->add_do_method(tile_set_atlas_source, "create_tile", coords);
+ undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", coords);
+ }
+ }
+ }
+ undo_redo->commit_action();
+ } break;
+ case DRAG_TYPE_REMOVE_TILES_USING_RECT: {
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
+ area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
+ List<PropertyInfo> list;
+ tile_set_atlas_source->get_property_list(&list);
+ Map<Vector2i, List<const PropertyInfo *>> per_tile = _group_properties_per_tiles(list, tile_set_atlas_source);
+
+ Set<Vector2i> to_delete;
+ for (int x = area.get_position().x; x < area.get_end().x; x++) {
+ for (int y = area.get_position().y; y < area.get_end().y; y++) {
+ Vector2i coords = tile_set_atlas_source->get_tile_at_coords(Vector2i(x, y));
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ to_delete.insert(coords);
+ }
+ }
+ }
+
+ undo_redo->create_action(TTR("Remove tiles"));
+ undo_redo->add_do_method(this, "_set_selection_from_array", Array());
+ for (Set<Vector2i>::Element *E = to_delete.front(); E; E = E->next()) {
+ Vector2i coords = E->get();
+ undo_redo->add_do_method(tile_set_atlas_source, "remove_tile", coords);
+ undo_redo->add_undo_method(tile_set_atlas_source, "create_tile", coords);
+ if (per_tile.has(coords)) {
+ for (List<const PropertyInfo *>::Element *E_property = per_tile[coords].front(); E_property; E_property = E_property->next()) {
+ String property = E_property->get()->name;
+ Variant value = tile_set_atlas_source->get(property);
+ if (value.get_type() != Variant::NIL) {
+ undo_redo->add_undo_method(tile_set_atlas_source, "set", E_property->get()->name, value);
+ }
+ }
+ }
+ }
+ undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
+ undo_redo->commit_action();
+ } break;
+ case DRAG_TYPE_MOVE_TILE:
+ if (drag_current_tile != drag_start_tile_shape.position) {
+ undo_redo->create_action(TTR("Move a tile"));
+ undo_redo->add_do_method(tile_set_atlas_source, "move_tile_in_atlas", drag_start_tile_shape.position, drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
+ undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
+ undo_redo->add_undo_method(tile_set_atlas_source, "move_tile_in_atlas", drag_current_tile, drag_start_tile_shape.position, drag_start_tile_shape.size);
+ Array array;
+ array.push_back(drag_start_tile_shape.position);
+ array.push_back(0);
+ undo_redo->add_undo_method(this, "_set_selection_from_array", array);
+ undo_redo->commit_action(false);
+ }
+ break;
+ case DRAG_TYPE_RECT_SELECT: {
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ ERR_FAIL_COND(start_base_tiles_coords == TileSetSource::INVALID_ATLAS_COORDS);
+ ERR_FAIL_COND(new_base_tiles_coords == TileSetSource::INVALID_ATLAS_COORDS);
+
+ Rect2i region = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
+ region.size += Vector2i(1, 1);
+
+ undo_redo->create_action(TTR("Select tiles"));
+ undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
+
+ // Determine if we clear, then add or remove to the selection.
+ bool add_to_selection = true;
+ if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ Vector2i coords = tile_set_atlas_source->get_tile_at_coords(start_base_tiles_coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ if (selection.has({ coords, 0 })) {
+ add_to_selection = false;
+ }
+ }
+ } else {
+ selection.clear();
+ }
+
+ // Modify the selection.
+ for (int x = region.position.x; x < region.get_end().x; x++) {
+ for (int y = region.position.y; y < region.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ coords = tile_set_atlas_source->get_tile_at_coords(coords);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ if (add_to_selection && !selection.has({ coords, 0 })) {
+ selection.insert({ coords, 0 });
+ } else if (!add_to_selection && selection.has({ coords, 0 })) {
+ selection.erase({ coords, 0 });
+ }
+ }
+ }
+ }
+ _update_tile_inspector();
+ _update_tile_id_label();
+ undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
+ undo_redo->commit_action(false);
+ break;
+ }
+ case DRAG_TYPE_RESIZE_TOP_LEFT:
+ case DRAG_TYPE_RESIZE_TOP:
+ case DRAG_TYPE_RESIZE_TOP_RIGHT:
+ case DRAG_TYPE_RESIZE_RIGHT:
+ case DRAG_TYPE_RESIZE_BOTTOM_RIGHT:
+ case DRAG_TYPE_RESIZE_BOTTOM:
+ case DRAG_TYPE_RESIZE_BOTTOM_LEFT:
+ case DRAG_TYPE_RESIZE_LEFT:
+ if (drag_start_tile_shape != Rect2i(drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile))) {
+ undo_redo->create_action(TTR("Resize a tile"));
+ undo_redo->add_do_method(tile_set_atlas_source, "move_tile_in_atlas", drag_start_tile_shape.position, drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
+ undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
+ undo_redo->add_undo_method(tile_set_atlas_source, "move_tile_in_atlas", drag_current_tile, drag_start_tile_shape.position, drag_start_tile_shape.size);
+ Array array;
+ array.push_back(drag_start_tile_shape.position);
+ array.push_back(0);
+ undo_redo->add_undo_method(this, "_set_selection_from_array", array);
+ undo_redo->commit_action(false);
+ }
+ break;
+ default:
+ break;
+ }
+
+ drag_modified_tiles.clear();
+ drag_type = DRAG_TYPE_NONE;
+ tile_atlas_control->set_default_cursor_shape(CURSOR_ARROW);
+}
+
+Map<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_properties_per_tiles(const List<PropertyInfo> &r_list, const TileSetAtlasSource *p_atlas) {
+ // Group properties per tile.
+ Map<Vector2i, List<const PropertyInfo *>> per_tile;
+ for (const List<PropertyInfo>::Element *E_property = r_list.front(); E_property; E_property = E_property->next()) {
+ Vector<String> components = String(E_property->get().name).split("/", true, 1);
+ if (components.size() >= 1) {
+ Vector<String> coord_arr = components[0].split(":");
+ if (coord_arr.size() == 2 && coord_arr[0].is_valid_integer() && coord_arr[1].is_valid_integer()) {
+ Vector2i coords = Vector2i(coord_arr[0].to_int(), coord_arr[1].to_int());
+ per_tile[coords].push_back(&(E_property->get()));
+ }
+ }
+ }
+ return per_tile;
+}
+
+void TileSetAtlasSourceEditor::_menu_option(int p_option) {
+ switch (p_option) {
+ case TILE_DELETE: {
+ List<PropertyInfo> list;
+ tile_set_atlas_source->get_property_list(&list);
+ Map<Vector2i, List<const PropertyInfo *>> per_tile = _group_properties_per_tiles(list, tile_set_atlas_source);
+ undo_redo->create_action(TTR("Remove tile"));
+
+ // Remove tiles
+ Set<Vector2i> removed;
+ for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) {
+ TileSelection selected = E->get();
+ if (selected.alternative == 0) {
+ // Remove a tile.
+ undo_redo->add_do_method(tile_set_atlas_source, "remove_tile", selected.tile);
+ undo_redo->add_undo_method(tile_set_atlas_source, "create_tile", selected.tile);
+ removed.insert(selected.tile);
+ if (per_tile.has(selected.tile)) {
+ for (List<const PropertyInfo *>::Element *E_property = per_tile[selected.tile].front(); E_property; E_property = E_property->next()) {
+ String property = E_property->get()->name;
+ Variant value = tile_set_atlas_source->get(property);
+ if (value.get_type() != Variant::NIL) {
+ undo_redo->add_undo_method(tile_set_atlas_source, "set", E_property->get()->name, value);
+ }
+ }
+ }
+ }
+ }
+
+ // Remove alternatives
+ for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) {
+ TileSelection selected = E->get();
+ if (selected.alternative > 0 && !removed.has(selected.tile)) {
+ // Remove an alternative tile.
+ undo_redo->add_do_method(tile_set_atlas_source, "remove_alternative_tile", selected.tile, selected.alternative);
+ undo_redo->add_undo_method(tile_set_atlas_source, "create_alternative_tile", selected.tile, selected.alternative);
+ if (per_tile.has(selected.tile)) {
+ for (List<const PropertyInfo *>::Element *E_property = per_tile[selected.tile].front(); E_property; E_property = E_property->next()) {
+ Vector<String> components = E_property->get()->name.split("/", true, 2);
+ if (components.size() >= 2 && components[1].is_valid_integer() && components[1].to_int() == selected.alternative) {
+ String property = E_property->get()->name;
+ Variant value = tile_set_atlas_source->get(property);
+ if (value.get_type() != Variant::NIL) {
+ undo_redo->add_undo_method(tile_set_atlas_source, "set", E_property->get()->name, value);
+ }
+ }
+ }
+ }
+ }
+ }
+ undo_redo->commit_action();
+ _update_fix_selected_and_hovered_tiles();
+ _update_tile_id_label();
+ } break;
+ case TILE_CREATE: {
+ undo_redo->create_action(TTR("Create a tile"));
+ undo_redo->add_do_method(tile_set_atlas_source, "create_tile", menu_option_coords);
+ Array array;
+ array.push_back(menu_option_coords);
+ array.push_back(0);
+ undo_redo->add_do_method(this, "_set_selection_from_array", array);
+ undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", menu_option_coords);
+ undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
+ undo_redo->commit_action();
+ _update_tile_id_label();
+ } break;
+ case TILE_CREATE_ALTERNATIVE: {
+ undo_redo->create_action(TTR("Create tile alternatives"));
+ Array array;
+ for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) {
+ if (E->get().alternative == 0) {
+ int next_id = tile_set_atlas_source->get_next_alternative_tile_id(E->get().tile);
+ undo_redo->add_do_method(tile_set_atlas_source, "create_alternative_tile", E->get().tile, next_id);
+ array.push_back(E->get().tile);
+ array.push_back(next_id);
+ undo_redo->add_undo_method(tile_set_atlas_source, "remove_alternative_tile", E->get().tile, next_id);
+ }
+ }
+ undo_redo->add_do_method(this, "_set_selection_from_array", array);
+ undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
+ undo_redo->commit_action();
+ _update_tile_id_label();
+ } break;
+ case ADVANCED_CLEANUP_TILES_OUTSIDE_TEXTURE: {
+ tile_set_atlas_source->clear_tiles_outside_texture();
+ } break;
+ case ADVANCED_AUTO_CREATE_TILES: {
+ _auto_create_tiles();
+ } break;
+ case ADVANCED_AUTO_REMOVE_TILES: {
+ _auto_remove_tiles();
+ } break;
+ }
+}
+
+void TileSetAtlasSourceEditor::_unhandled_key_input(const Ref<InputEvent> &p_event) {
+ // Check for shortcuts.
+ if (ED_IS_SHORTCUT("tiles_editor/delete_tile", p_event)) {
+ if (tools_button_group->get_pressed_button() == tool_select_button && !selection.is_empty()) {
+ _menu_option(TILE_DELETE);
+ accept_event();
+ }
+ }
+}
+
+void TileSetAtlasSourceEditor::_set_selection_from_array(Array p_selection) {
+ ERR_FAIL_COND((p_selection.size() % 2) != 0);
+ selection.clear();
+ for (int i = 0; i < p_selection.size() / 2; i++) {
+ TileSelection selected = { p_selection[i * 2], p_selection[i * 2 + 1] };
+ if (tile_set_atlas_source->has_tile(selected.tile) && tile_set_atlas_source->has_alternative_tile(selected.tile, selected.alternative)) {
+ selection.insert(selected);
+ }
+ }
+ _update_tile_inspector();
+ _update_tile_id_label();
+ _update_atlas_view();
+}
+
+Array TileSetAtlasSourceEditor::_get_selection_as_array() {
+ Array output;
+ for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) {
+ output.push_back(E->get().tile);
+ output.push_back(E->get().alternative);
+ }
+ return output;
+}
+
+void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
+ // Colors.
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+
+ // Draw the selected tile.
+ if (tools_button_group->get_pressed_button() == tool_select_button) {
+ for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) {
+ TileSelection selected = E->get();
+ if (selected.alternative == 0) {
+ // Draw the rect.
+ Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
+ tile_atlas_control->draw_rect(region, selection_color, false);
+ }
+ }
+
+ if (selection.size() == 1) {
+ // Draw the resize handles (only when it's possible to expand).
+ TileSelection selected = selection.front()->get();
+ Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
+ Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
+ Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
+ Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
+ Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
+ Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
+ bool can_grow[4];
+ for (int i = 0; i < 4; i++) {
+ can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]);
+ can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
+ }
+ for (int i = 0; i < 4; i++) {
+ Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i];
+ if (can_grow[i] && can_grow[(i + 3) % 4]) {
+ tile_atlas_control->draw_texture_rect(resize_handle, Rect2(pos, zoomed_size), false);
+ } else {
+ tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2(pos, zoomed_size), false);
+ }
+ Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4];
+ if (can_grow[i]) {
+ tile_atlas_control->draw_texture_rect(resize_handle, Rect2((pos + next_pos) / 2.0, zoomed_size), false);
+ } else {
+ tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2((pos + next_pos) / 2.0, zoomed_size), false);
+ }
+ }
+ }
+ }
+
+ if (drag_type == DRAG_TYPE_REMOVE_TILES) {
+ // Draw the tiles to be removed.
+ for (Set<Vector2i>::Element *E = drag_modified_tiles.front(); E; E = E->next()) {
+ tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(E->get()), Color(0.0, 0.0, 0.0), false);
+ }
+ } else if (drag_type == DRAG_TYPE_RECT_SELECT || drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT) {
+ // Draw tiles to be removed.
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
+ area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
+
+ Color color = Color(0.0, 0.0, 0.0);
+ if (drag_type == DRAG_TYPE_RECT_SELECT) {
+ color = selection_color.lightened(0.2);
+ }
+
+ Set<Vector2i> to_paint;
+ for (int x = area.get_position().x; x < area.get_end().x; x++) {
+ for (int y = area.get_position().y; y < area.get_end().y; y++) {
+ Vector2i coords = tile_set_atlas_source->get_tile_at_coords(Vector2i(x, y));
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ to_paint.insert(coords);
+ }
+ }
+ }
+
+ for (Set<Vector2i>::Element *E = to_paint.front(); E; E = E->next()) {
+ Vector2i coords = E->get();
+ tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(coords), color, false);
+ }
+ } else if (drag_type == DRAG_TYPE_CREATE_TILES_USING_RECT) {
+ // Draw tiles to be created.
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
+ Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
+
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
+ area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
+ for (int x = area.get_position().x; x < area.get_end().x; x++) {
+ for (int y = area.get_position().y; y < area.get_end().y; y++) {
+ Vector2i coords = Vector2i(x, y);
+ if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
+ Vector2i origin = margins + (coords * (tile_size + separation));
+ tile_atlas_control->draw_rect(Rect2i(origin, tile_size), Color(1.0, 1.0, 1.0), false);
+ }
+ }
+ }
+ }
+
+ // Draw the hovered tile.
+ if (drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT || drag_type == DRAG_TYPE_CREATE_TILES_USING_RECT) {
+ // Draw the rect.
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
+ area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
+ Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
+ Vector2i origin = margins + (area.position * (tile_size + separation));
+ tile_atlas_control->draw_rect(Rect2i(origin, area.size * tile_size), Color(1.0, 1.0, 1.0), false);
+ } else {
+ Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+ if (hovered_base_tile_coords.x >= 0 && hovered_base_tile_coords.y >= 0 && hovered_base_tile_coords.x < grid_size.x && hovered_base_tile_coords.y < grid_size.y) {
+ Vector2i hovered_tile = tile_set_atlas_source->get_tile_at_coords(hovered_base_tile_coords);
+ if (hovered_tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ // Draw existing hovered tile.
+ tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(hovered_tile), Color(1.0, 1.0, 1.0), false);
+ } else {
+ // Draw empty tile, only in add/remove tiles mode.
+ if (tools_button_group->get_pressed_button() == tool_add_remove_button || tools_button_group->get_pressed_button() == tool_add_remove_rect_button) {
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
+ Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
+ Vector2i origin = margins + (hovered_base_tile_coords * (tile_size + separation));
+ tile_atlas_control->draw_rect(Rect2i(origin, tile_size), Color(1.0, 1.0, 1.0), false);
+ }
+ }
+ }
+ }
+}
+
+void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() {
+ // Draw the preview of the selected property.
+ TileDataEditor *tile_data_editor = TileSetEditor::get_singleton()->get_tile_data_editor(selected_property);
+ if (tile_data_editor && tile_inspector->is_visible_in_tree()) {
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i coords = tile_set_atlas_source->get_tile_id(i);
+ Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(coords);
+ Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+
+ Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
+ xform.translate(position);
+
+ tile_data_editor->draw_over_tile(tile_atlas_control_unscaled, xform, *tile_set, tile_set_atlas_source_id, coords, 0, selected_property);
+ }
+ }
+}
+
+void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event) {
+ // Update the hovered alternative tile.
+ hovered_alternative_tile_coords = tile_atlas_view->get_alternative_tile_at_pos(alternative_tiles_control->get_local_mouse_position());
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ drag_type = DRAG_TYPE_NONE;
+
+ Vector2 mouse_local_pos = alternative_tiles_control->get_local_mouse_position();
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+ // Left click pressed.
+ if (tools_button_group->get_pressed_button() == tool_select_button) {
+ Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos);
+
+ selection.clear();
+ TileSelection selected = { Vector2i(tile.x, tile.y), int(tile.z) };
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ selection.insert(selected);
+ }
+
+ _update_tile_inspector();
+ _update_tile_id_label();
+ }
+ }
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (mb->is_pressed()) {
+ // Right click pressed
+ Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos);
+
+ selection.clear();
+ TileSelection selected = { Vector2i(tile.x, tile.y), int(tile.z) };
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ selection.insert(selected);
+ }
+
+ _update_tile_inspector();
+ _update_tile_id_label();
+
+ if (selection.size() == 1) {
+ selected = selection.front()->get();
+ menu_option_coords = selected.tile;
+ menu_option_alternative = selected.alternative;
+ alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ }
+ }
+ }
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+ }
+}
+
+void TileSetAtlasSourceEditor::_tile_alternatives_control_mouse_exited() {
+ hovered_alternative_tile_coords = Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ tile_atlas_control->update();
+ tile_atlas_control_unscaled->update();
+ alternative_tiles_control->update();
+ alternative_tiles_control_unscaled->update();
+}
+
+void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
+
+ // Update the hovered alternative tile.
+ if (tools_button_group->get_pressed_button() == tool_select_button) {
+ // Draw hovered tile.
+ Vector2i coords = Vector2(hovered_alternative_tile_coords.x, hovered_alternative_tile_coords.y);
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ Rect2i rect = tile_atlas_view->get_alternative_tile_rect(coords, hovered_alternative_tile_coords.z);
+ if (rect != Rect2i()) {
+ alternative_tiles_control->draw_rect(rect, Color(1.0, 1.0, 1.0), false);
+ }
+ }
+
+ // Draw selected tile.
+ for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) {
+ TileSelection selected = E->get();
+ if (selected.alternative >= 1) {
+ Rect2i rect = tile_atlas_view->get_alternative_tile_rect(selected.tile, selected.alternative);
+ if (rect != Rect2i()) {
+ alternative_tiles_control->draw_rect(rect, selection_color, false);
+ }
+ }
+ }
+ }
+}
+
+void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
+ //TODO
+}
+
+void TileSetAtlasSourceEditor::_tile_set_atlas_source_changed() {
+ tile_set_atlas_source_changed_needs_update = true;
+}
+
+void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what) {
+ if (p_what == "texture" && !atlas_source_proxy_object->get("texture").is_null()) {
+ confirm_auto_create_tiles->popup_centered();
+ } else if (p_what == "id") {
+ emit_signal("source_id_changed", atlas_source_proxy_object->get_id());
+ }
+}
+
+void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
+ UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
+ ERR_FAIL_COND(!undo_redo);
+
+#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, tile_data->get(property));
+
+ AtlasTileProxyObject *tile_data = Object::cast_to<AtlasTileProxyObject>(p_edited);
+ if (tile_data) {
+ Vector<String> components = String(p_property).split("/", true, 2);
+ if (components.size() == 2 && components[1] == "shapes_count") {
+ int layer_index = components[0].trim_prefix("physics_layer_").to_int();
+ int new_shapes_count = p_new_value;
+ int old_shapes_count = tile_data->get(vformat("physics_layer_%d/shapes_count", layer_index));
+ if (new_shapes_count < old_shapes_count) {
+ for (int i = new_shapes_count - 1; i < old_shapes_count; i++) {
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/shape", layer_index, i));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way", layer_index, i));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way_margin", layer_index, i));
+ }
+ }
+ }
+ }
+#undef ADD_UNDO
+}
+
+void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id) {
+ ERR_FAIL_COND(!p_tile_set.is_valid());
+ ERR_FAIL_COND(!p_tile_set_atlas_source);
+ ERR_FAIL_COND(p_source_id < 0);
+ ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
+
+ if (p_tile_set == tile_set && p_tile_set_atlas_source == tile_set_atlas_source && p_source_id == tile_set_atlas_source_id) {
+ return;
+ }
+
+ // Remove listener for old objects.
+ if (tile_set_atlas_source) {
+ tile_set_atlas_source->disconnect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_atlas_source_changed));
+ }
+
+ // Clear the selection.
+ selection.clear();
+
+ // Change the edited object.
+ tile_set = p_tile_set;
+ tile_set_atlas_source = p_tile_set_atlas_source;
+ tile_set_atlas_source_id = p_source_id;
+
+ // Add the listener again.
+ if (tile_set_atlas_source) {
+ tile_set_atlas_source->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_atlas_source_changed));
+ }
+
+ // Update everything.
+ _update_source_inspector();
+
+ // Update the selected tile.
+ _update_fix_selected_and_hovered_tiles();
+ _update_tile_id_label();
+ _update_atlas_view();
+ _update_tile_inspector();
+}
+
+void TileSetAtlasSourceEditor::init_source() {
+ confirm_auto_create_tiles->popup_centered();
+}
+
+void TileSetAtlasSourceEditor::_auto_create_tiles() {
+ if (!tile_set_atlas_source) {
+ return;
+ }
+
+ Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
+ if (texture.is_valid()) {
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
+ Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
+ Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+ undo_redo->create_action(TTR("Create tiles in non-transparent texture regions"));
+ for (int y = 0; y < grid_size.y; y++) {
+ for (int x = 0; x < grid_size.x; x++) {
+ // Check if we have a tile at the coord
+ Vector2i coords = Vector2i(x, y);
+ if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
+ // Check if the texture is empty at the given coords.
+ Rect2i region = Rect2i(margins + (coords * (texture_region_size + separation)), texture_region_size);
+ bool is_opaque = false;
+ for (int region_x = region.get_position().x; region_x < region.get_end().x; region_x++) {
+ for (int region_y = region.get_position().y; region_y < region.get_end().y; region_y++) {
+ if (texture->is_pixel_opaque(region_x, region_y)) {
+ is_opaque = true;
+ break;
+ }
+ }
+ if (is_opaque) {
+ break;
+ }
+ }
+
+ // If we do have opaque pixels, create a tile.
+ if (is_opaque) {
+ undo_redo->add_do_method(tile_set_atlas_source, "create_tile", coords);
+ undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", coords);
+ }
+ }
+ }
+ }
+ undo_redo->commit_action();
+ }
+}
+
+void TileSetAtlasSourceEditor::_auto_remove_tiles() {
+ if (!tile_set_atlas_source) {
+ return;
+ }
+
+ Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
+ if (texture.is_valid()) {
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
+ Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
+ Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
+
+ undo_redo->create_action(TTR("Remove tiles in fully transparent texture regions"));
+
+ List<PropertyInfo> list;
+ tile_set_atlas_source->get_property_list(&list);
+ Map<Vector2i, List<const PropertyInfo *>> per_tile = _group_properties_per_tiles(list, tile_set_atlas_source);
+
+ for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
+ Vector2i coords = tile_set_atlas_source->get_tile_id(i);
+ Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(coords);
+
+ // Skip tiles outside texture.
+ if ((coords.x + size_in_atlas.x) > grid_size.x || (coords.y + size_in_atlas.y) > grid_size.y) {
+ continue;
+ }
+
+ // Check if the texture is empty at the given coords.
+ Rect2i region = Rect2i(margins + (coords * (texture_region_size + separation)), texture_region_size * size_in_atlas);
+ bool is_opaque = false;
+ for (int region_x = region.get_position().x; region_x < region.get_end().x; region_x++) {
+ for (int region_y = region.get_position().y; region_y < region.get_end().y; region_y++) {
+ if (texture->is_pixel_opaque(region_x, region_y)) {
+ is_opaque = true;
+ break;
+ }
+ }
+ if (is_opaque) {
+ break;
+ }
+ }
+
+ // If we do have opaque pixels, create a tile.
+ if (!is_opaque) {
+ undo_redo->add_do_method(tile_set_atlas_source, "remove_tile", coords);
+ undo_redo->add_undo_method(tile_set_atlas_source, "create_tile", coords);
+ if (per_tile.has(coords)) {
+ for (List<const PropertyInfo *>::Element *E_property = per_tile[coords].front(); E_property; E_property = E_property->next()) {
+ String property = E_property->get()->name;
+ Variant value = tile_set_atlas_source->get(property);
+ if (value.get_type() != Variant::NIL) {
+ undo_redo->add_undo_method(tile_set_atlas_source, "set", E_property->get()->name, value);
+ }
+ }
+ }
+ }
+ }
+ undo_redo->commit_action();
+ }
+}
+
+void TileSetAtlasSourceEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ tool_select_button->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
+ tool_add_remove_button->set_icon(get_theme_icon("EditAddRemove", "EditorIcons"));
+ tool_add_remove_rect_button->set_icon(get_theme_icon("RectangleAddRemove", "EditorIcons"));
+
+ tools_settings_erase_button->set_icon(get_theme_icon("Eraser", "EditorIcons"));
+
+ tool_advanced_menu_buttom->set_icon(get_theme_icon("Tools", "EditorIcons"));
+
+ resize_handle = get_theme_icon("EditorHandle", "EditorIcons");
+ resize_handle_disabled = get_theme_icon("EditorHandleDisabled", "EditorIcons");
+ break;
+ case NOTIFICATION_INTERNAL_PROCESS:
+ if (tile_set_atlas_source_changed_needs_update) {
+ // Update everything.
+ _update_source_inspector();
+
+ // Update the selected tile.
+ _update_fix_selected_and_hovered_tiles();
+ _update_tile_id_label();
+ _update_atlas_view();
+ _update_tile_inspector();
+
+ tile_set_atlas_source_changed_needs_update = false;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void TileSetAtlasSourceEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &TileSetAtlasSourceEditor::_unhandled_key_input);
+ ClassDB::bind_method(D_METHOD("_set_selection_from_array"), &TileSetAtlasSourceEditor::_set_selection_from_array);
+
+ ADD_SIGNAL(MethodInfo("source_id_changed", PropertyInfo(Variant::INT, "source_id")));
+}
+
+TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
+ set_process_unhandled_key_input(true);
+ set_process_internal(true);
+
+ // -- Right side --
+ HSplitContainer *split_container_right_side = memnew(HSplitContainer);
+ split_container_right_side->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_child(split_container_right_side);
+
+ // Middle panel.
+ ScrollContainer *middle_panel = memnew(ScrollContainer);
+ middle_panel->set_enable_h_scroll(false);
+ middle_panel->set_custom_minimum_size(Size2i(200, 0) * EDSCALE);
+ split_container_right_side->add_child(middle_panel);
+
+ VBoxContainer *middle_vbox_container = memnew(VBoxContainer);
+ middle_vbox_container->set_h_size_flags(SIZE_EXPAND_FILL);
+ middle_panel->add_child(middle_vbox_container);
+
+ // Tile inspector.
+ tile_inspector_label = memnew(Label);
+ tile_inspector_label->set_text(TTR("Tile Properties:"));
+ tile_inspector_label->hide();
+ middle_vbox_container->add_child(tile_inspector_label);
+
+ tile_proxy_object = memnew(AtlasTileProxyObject(this));
+ tile_proxy_object->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view).unbind(1));
+
+ tile_inspector = memnew(EditorInspector);
+ tile_inspector->set_undo_redo(undo_redo);
+ tile_inspector->set_enable_v_scroll(false);
+ tile_inspector->edit(tile_proxy_object);
+ tile_inspector->set_use_folding(true);
+ tile_inspector->connect("property_selected", callable_mp(this, &TileSetAtlasSourceEditor::_inspector_property_selected));
+ middle_vbox_container->add_child(tile_inspector);
+
+ // Atlas source inspector.
+ atlas_source_inspector_label = memnew(Label);
+ atlas_source_inspector_label->set_text(TTR("Atlas Properties:"));
+ middle_vbox_container->add_child(atlas_source_inspector_label);
+
+ atlas_source_proxy_object = memnew(TileSetAtlasSourceProxyObject());
+ atlas_source_proxy_object->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed));
+
+ atlas_source_inspector = memnew(EditorInspector);
+ atlas_source_inspector->set_undo_redo(undo_redo);
+ atlas_source_inspector->set_enable_v_scroll(false);
+ atlas_source_inspector->edit(atlas_source_proxy_object);
+ middle_vbox_container->add_child(atlas_source_inspector);
+
+ // Right panel.
+ VBoxContainer *right_panel = memnew(VBoxContainer);
+ right_panel->set_h_size_flags(SIZE_EXPAND_FILL);
+ right_panel->set_v_size_flags(SIZE_EXPAND_FILL);
+ split_container_right_side->add_child(right_panel);
+
+ // -- Dialogs --
+ confirm_auto_create_tiles = memnew(AcceptDialog);
+ confirm_auto_create_tiles->set_title(TTR("Create tiles automatically in non-transparent texture regions?"));
+ confirm_auto_create_tiles->set_text(TTR("The atlas's texture was modified.\nWould you like to automatically create tiles in the atlas?"));
+ confirm_auto_create_tiles->get_ok_button()->set_text(TTR("Yes"));
+ confirm_auto_create_tiles->add_cancel_button()->set_text(TTR("No"));
+ confirm_auto_create_tiles->connect("confirmed", callable_mp(this, &TileSetAtlasSourceEditor::_auto_create_tiles));
+ add_child(confirm_auto_create_tiles);
+
+ // -- Toolbox --
+ tools_button_group.instance();
+
+ toolbox = memnew(HBoxContainer);
+ right_panel->add_child(toolbox);
+
+ tool_select_button = memnew(Button);
+ tool_select_button->set_flat(true);
+ tool_select_button->set_toggle_mode(true);
+ tool_select_button->set_pressed(true);
+ tool_select_button->set_button_group(tools_button_group);
+ tool_select_button->set_tooltip(TTR("Select tiles."));
+ tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles));
+ tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label));
+ tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector));
+ tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view));
+ tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar));
+ toolbox->add_child(tool_select_button);
+
+ tool_add_remove_button = memnew(Button);
+ tool_add_remove_button->set_flat(true);
+ tool_add_remove_button->set_toggle_mode(true);
+ tool_add_remove_button->set_button_group(tools_button_group);
+ tool_add_remove_button->set_tooltip(TTR("Add/Remove tiles tool (use the shift key to create big tiles)."));
+ tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles));
+ tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label));
+ tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector));
+ tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view));
+ tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar));
+ toolbox->add_child(tool_add_remove_button);
+
+ tool_add_remove_rect_button = memnew(Button);
+ tool_add_remove_rect_button->set_flat(true);
+ tool_add_remove_rect_button->set_toggle_mode(true);
+ tool_add_remove_rect_button->set_button_group(tools_button_group);
+ tool_add_remove_rect_button->set_tooltip(TTR("Add/Remove tiles rectangle tool (use the shift key to create big tiles)."));
+ tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles));
+ tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label));
+ tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector));
+ tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view));
+ tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar));
+ toolbox->add_child(tool_add_remove_rect_button);
+
+ // Tool settings.
+ tool_settings = memnew(HBoxContainer);
+ toolbox->add_child(tool_settings);
+
+ tool_settings_vsep = memnew(VSeparator);
+ tool_settings->add_child(tool_settings_vsep);
+
+ tools_settings_erase_button = memnew(Button);
+ tools_settings_erase_button->set_flat(true);
+ tools_settings_erase_button->set_toggle_mode(true);
+ tools_settings_erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", KEY_E));
+ tools_settings_erase_button->set_shortcut_context(this);
+ tool_settings->add_child(tools_settings_erase_button);
+
+ VSeparator *tool_advanced_vsep = memnew(VSeparator);
+ toolbox->add_child(tool_advanced_vsep);
+
+ tool_advanced_menu_buttom = memnew(MenuButton);
+ tool_advanced_menu_buttom->set_flat(true);
+ tool_advanced_menu_buttom->get_popup()->add_item(TTR("Cleanup Tiles Outside Texture"), ADVANCED_CLEANUP_TILES_OUTSIDE_TEXTURE);
+ tool_advanced_menu_buttom->get_popup()->set_item_disabled(0, true);
+ tool_advanced_menu_buttom->get_popup()->add_item(TTR("Create Tiles in Non-Transparent Texture Regions"), ADVANCED_AUTO_CREATE_TILES);
+ tool_advanced_menu_buttom->get_popup()->add_item(TTR("Remove Tiles in Fully Transparent Texture Regions"), ADVANCED_AUTO_REMOVE_TILES);
+ tool_advanced_menu_buttom->get_popup()->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
+ toolbox->add_child(tool_advanced_menu_buttom);
+
+ _update_toolbar();
+
+ // Right side of toolbar.
+ Control *middle_space = memnew(Control);
+ middle_space->set_h_size_flags(SIZE_EXPAND_FILL);
+ toolbox->add_child(middle_space);
+
+ tool_tile_id_label = memnew(Label);
+ tool_tile_id_label->set_mouse_filter(Control::MOUSE_FILTER_STOP);
+ toolbox->add_child(tool_tile_id_label);
+ _update_tile_id_label();
+
+ // Tile atlas view.
+ tile_atlas_view = memnew(TileAtlasView);
+ tile_atlas_view->set_h_size_flags(SIZE_EXPAND_FILL);
+ tile_atlas_view->set_v_size_flags(SIZE_EXPAND_FILL);
+ tile_atlas_view->connect("transform_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_atlas_view_transform));
+ tile_atlas_view->connect("transform_changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_view_transform_changed).unbind(2));
+ right_panel->add_child(tile_atlas_view);
+
+ base_tile_popup_menu = memnew(PopupMenu);
+ base_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), KEY_DELETE), TILE_DELETE);
+ base_tile_popup_menu->add_item(TTR("Create an Alternative Tile"), TILE_CREATE_ALTERNATIVE);
+ base_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
+ tile_atlas_view->add_child(base_tile_popup_menu);
+
+ empty_base_tile_popup_menu = memnew(PopupMenu);
+ empty_base_tile_popup_menu->add_item(TTR("Create a Tile"), TILE_CREATE);
+ empty_base_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
+ tile_atlas_view->add_child(empty_base_tile_popup_menu);
+
+ tile_atlas_control = memnew(Control);
+ tile_atlas_control->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_draw));
+ tile_atlas_control->connect("mouse_exited", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_mouse_exited));
+ tile_atlas_control->connect("gui_input", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_gui_input));
+ tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control);
+
+ tile_atlas_control_unscaled = memnew(Control);
+ tile_atlas_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ tile_atlas_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw));
+ tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control_unscaled, false);
+ tile_atlas_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+
+ alternative_tile_popup_menu = memnew(PopupMenu);
+ alternative_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete_tile", TTR("Delete"), KEY_DELETE), TILE_DELETE);
+ alternative_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
+ tile_atlas_view->add_child(alternative_tile_popup_menu);
+
+ alternative_tiles_control = memnew(Control);
+ alternative_tiles_control->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_draw));
+ alternative_tiles_control->connect("mouse_exited", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_mouse_exited));
+ alternative_tiles_control->connect("gui_input", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input));
+ tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control);
+
+ alternative_tiles_control_unscaled = memnew(Control);
+ alternative_tiles_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ alternative_tiles_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw));
+ tile_atlas_view->add_control_over_atlas_tiles(alternative_tiles_control_unscaled, false);
+ alternative_tiles_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+
+ tile_atlas_view_missing_source_label = memnew(Label);
+ tile_atlas_view_missing_source_label->set_text(TTR("Add or select an atlas texture to the left panel."));
+ tile_atlas_view_missing_source_label->set_align(Label::ALIGN_CENTER);
+ tile_atlas_view_missing_source_label->set_valign(Label::VALIGN_CENTER);
+ tile_atlas_view_missing_source_label->set_h_size_flags(SIZE_EXPAND_FILL);
+ tile_atlas_view_missing_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
+ tile_atlas_view_missing_source_label->hide();
+ right_panel->add_child(tile_atlas_view_missing_source_label);
+}
+
+TileSetAtlasSourceEditor::~TileSetAtlasSourceEditor() {
+ memdelete(tile_proxy_object);
+ memdelete(atlas_source_proxy_object);
+}
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
new file mode 100644
index 0000000000..70f2cdbe01
--- /dev/null
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -0,0 +1,259 @@
+/*************************************************************************/
+/* tile_set_atlas_source_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TILE_SET_ATLAS_SOURCE_EDITOR_H
+#define TILE_SET_ATLAS_SOURCE_EDITOR_H
+
+#include "tile_atlas_view.h"
+
+#include "editor/editor_node.h"
+#include "scene/gui/split_container.h"
+#include "scene/resources/tile_set.h"
+
+class TileSet;
+
+class TileSetAtlasSourceEditor : public HBoxContainer {
+ GDCLASS(TileSetAtlasSourceEditor, HBoxContainer);
+
+private:
+ // A class to store which tiles are selected.
+ struct TileSelection {
+ Vector2i tile = TileSetSource::INVALID_ATLAS_COORDS;
+ int alternative = TileSetSource::INVALID_TILE_ALTERNATIVE;
+
+ bool operator<(const TileSelection &p_other) const {
+ if (tile == p_other.tile) {
+ return alternative < p_other.alternative;
+ } else {
+ return tile < p_other.tile;
+ }
+ }
+ };
+
+ // -- Proxy object for an atlas source, needed by the inspector --
+ class TileSetAtlasSourceProxyObject : public Object {
+ GDCLASS(TileSetAtlasSourceProxyObject, Object);
+
+ private:
+ Ref<TileSet> tile_set;
+ TileSetAtlasSource *tile_set_atlas_source = nullptr;
+ int source_id = -1;
+
+ 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;
+ static void _bind_methods();
+
+ public:
+ void set_id(int p_id);
+ int get_id();
+
+ void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id);
+ };
+
+ // -- Proxy object for a tile, needed by the inspector --
+ class AtlasTileProxyObject : public Object {
+ GDCLASS(AtlasTileProxyObject, Object);
+
+ private:
+ TileSetAtlasSourceEditor *tiles_set_atlas_source_editor;
+
+ TileSetAtlasSource *tile_set_atlas_source = nullptr;
+ Set<TileSelection> tiles = Set<TileSelection>();
+
+ 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;
+
+ static void _bind_methods();
+
+ public:
+ // Update the proxyed object.
+ void edit(TileSetAtlasSource *p_tile_set_atlas_source, Set<TileSelection> p_tiles = Set<TileSelection>());
+
+ AtlasTileProxyObject(TileSetAtlasSourceEditor *p_tiles_set_atlas_source_editor) {
+ tiles_set_atlas_source_editor = p_tiles_set_atlas_source_editor;
+ }
+ };
+
+ Ref<TileSet> tile_set;
+ TileSetAtlasSource *tile_set_atlas_source = nullptr;
+ int tile_set_atlas_source_id = -1;
+
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+
+ bool tile_set_atlas_source_changed_needs_update = false;
+
+ // -- Inspector --
+ AtlasTileProxyObject *tile_proxy_object;
+ Label *tile_inspector_label;
+ EditorInspector *tile_inspector;
+ String selected_property;
+ void _inspector_property_selected(String p_property);
+
+ TileSetAtlasSourceProxyObject *atlas_source_proxy_object;
+ Label *atlas_source_inspector_label;
+ EditorInspector *atlas_source_inspector;
+
+ // -- Atlas view --
+ HBoxContainer *toolbox;
+ Label *tile_atlas_view_missing_source_label;
+ TileAtlasView *tile_atlas_view;
+
+ // Dragging
+ enum DragType {
+ DRAG_TYPE_NONE = 0,
+ DRAG_TYPE_CREATE_TILES,
+ DRAG_TYPE_CREATE_TILES_USING_RECT,
+ DRAG_TYPE_CREATE_BIG_TILE,
+ DRAG_TYPE_REMOVE_TILES,
+ DRAG_TYPE_REMOVE_TILES_USING_RECT,
+
+ DRAG_TYPE_MOVE_TILE,
+
+ DRAG_TYPE_RECT_SELECT,
+
+ // Warning: keep in this order.
+ DRAG_TYPE_RESIZE_TOP_LEFT,
+ DRAG_TYPE_RESIZE_TOP,
+ DRAG_TYPE_RESIZE_TOP_RIGHT,
+ DRAG_TYPE_RESIZE_RIGHT,
+ DRAG_TYPE_RESIZE_BOTTOM_RIGHT,
+ DRAG_TYPE_RESIZE_BOTTOM,
+ DRAG_TYPE_RESIZE_BOTTOM_LEFT,
+ DRAG_TYPE_RESIZE_LEFT,
+ };
+ DragType drag_type = DRAG_TYPE_NONE;
+ Vector2i drag_start_mouse_pos;
+ Vector2i drag_last_mouse_pos;
+ Vector2i drag_current_tile;
+
+ Rect2i drag_start_tile_shape;
+ Set<Vector2i> drag_modified_tiles;
+ void _end_dragging();
+
+ Map<Vector2i, List<const PropertyInfo *>> _group_properties_per_tiles(const List<PropertyInfo> &r_list, const TileSetAtlasSource *p_atlas);
+
+ // Popup functions.
+ enum MenuOptions {
+ TILE_CREATE,
+ TILE_CREATE_ALTERNATIVE,
+ TILE_DELETE,
+
+ ADVANCED_CLEANUP_TILES_OUTSIDE_TEXTURE,
+ ADVANCED_AUTO_CREATE_TILES,
+ ADVANCED_AUTO_REMOVE_TILES,
+ };
+ Vector2i menu_option_coords;
+ int menu_option_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE;
+ void _menu_option(int p_option);
+
+ // Tool buttons.
+ Ref<ButtonGroup> tools_button_group;
+ Button *tool_select_button;
+ Button *tool_add_remove_button;
+ Button *tool_add_remove_rect_button;
+ Label *tool_tile_id_label;
+
+ HBoxContainer *tool_settings;
+ VSeparator *tool_settings_vsep;
+ Button *tools_settings_erase_button;
+
+ MenuButton *tool_advanced_menu_buttom;
+
+ // Selection.
+ Set<TileSelection> selection;
+
+ void _set_selection_from_array(Array p_selection);
+ Array _get_selection_as_array();
+
+ // A control on the tile atlas to draw and handle input events.
+ Vector2i hovered_base_tile_coords = TileSetSource::INVALID_ATLAS_COORDS;
+
+ PopupMenu *base_tile_popup_menu;
+ PopupMenu *empty_base_tile_popup_menu;
+ Ref<Texture2D> resize_handle;
+ Ref<Texture2D> resize_handle_disabled;
+ Control *tile_atlas_control;
+ Control *tile_atlas_control_unscaled;
+ void _tile_atlas_control_draw();
+ void _tile_atlas_control_unscaled_draw();
+ void _tile_atlas_control_mouse_exited();
+ void _tile_atlas_control_gui_input(const Ref<InputEvent> &p_event);
+ void _tile_atlas_view_transform_changed();
+
+ // A control over the alternative tiles.
+ Vector3i hovered_alternative_tile_coords = Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE);
+
+ PopupMenu *alternative_tile_popup_menu;
+ Control *alternative_tiles_control;
+ Control *alternative_tiles_control_unscaled;
+ void _tile_alternatives_control_draw();
+ void _tile_alternatives_control_unscaled_draw();
+ void _tile_alternatives_control_mouse_exited();
+ void _tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event);
+
+ // -- Update functions --
+ void _update_tile_id_label();
+ void _update_source_inspector();
+ void _update_fix_selected_and_hovered_tiles();
+ void _update_tile_inspector();
+ void _update_manage_tile_properties_button();
+ void _update_atlas_view();
+ void _update_toolbar();
+
+ // -- input events --
+ void _unhandled_key_input(const Ref<InputEvent> &p_event);
+
+ // -- Misc --
+ void _auto_create_tiles();
+ void _auto_remove_tiles();
+ AcceptDialog *confirm_auto_create_tiles;
+
+ void _tile_set_atlas_source_changed();
+ void _atlas_source_proxy_object_changed(String p_what);
+
+ void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_source, int p_source_id);
+ void init_source();
+
+ TileSetAtlasSourceEditor();
+ ~TileSetAtlasSourceEditor();
+};
+
+#endif // TILE_SET_ATLAS_SOURCE_EDITOR_H
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
new file mode 100644
index 0000000000..11842981f3
--- /dev/null
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -0,0 +1,588 @@
+/*************************************************************************/
+/* tile_set_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "tile_set_editor.h"
+
+#include "tile_data_editors.h"
+#include "tiles_editor_plugin.h"
+
+#include "editor/editor_scale.h"
+
+#include "scene/gui/box_container.h"
+#include "scene/gui/control.h"
+#include "scene/gui/tab_container.h"
+
+TileSetEditor *TileSetEditor::singleton = nullptr;
+
+void TileSetEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ if (!can_drop_data_fw(p_point, p_data, p_from)) {
+ return;
+ }
+
+ if (p_from == sources_list) {
+ // Handle dropping a texture in the list of atlas resources.
+ int source_id = -1;
+ int added = 0;
+ Dictionary d = p_data;
+ Vector<String> files = d["files"];
+ for (int i = 0; i < files.size(); i++) {
+ Ref<Texture2D> resource = ResourceLoader::load(files[i]);
+ if (resource.is_valid()) {
+ // Retrieve the id for the next created source.
+ source_id = tile_set->get_next_source_id();
+
+ // Actually create the new source.
+ Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
+ atlas_source->set_texture(resource);
+ undo_redo->create_action(TTR("Add a new atlas source"));
+ undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
+ undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
+ undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
+ undo_redo->commit_action();
+ added += 1;
+ }
+ }
+
+ if (added == 1) {
+ tile_set_atlas_source_editor->init_source();
+ }
+
+ // Update the selected source (thus triggering an update).
+ _update_atlas_sources_list(source_id);
+ }
+}
+
+bool TileSetEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ ERR_FAIL_COND_V(!tile_set.is_valid(), false);
+
+ if (p_from == sources_list) {
+ Dictionary d = p_data;
+
+ if (!d.has("type")) {
+ return false;
+ }
+
+ // Check if we have a Texture2D.
+ if (String(d["type"]) == "files") {
+ Vector<String> files = d["files"];
+
+ if (files.size() == 0) {
+ return false;
+ }
+
+ for (int i = 0; i < files.size(); i++) {
+ String file = files[i];
+ String ftype = EditorFileSystem::get_singleton()->get_file_type(file);
+
+ if (!ClassDB::is_parent_class(ftype, "Texture2D")) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+ return false;
+}
+
+void TileSetEditor::_update_atlas_sources_list(int force_selected_id) {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ // Get the previously selected id.
+ int old_selected = -1;
+ if (sources_list->get_current() >= 0) {
+ int source_id = sources_list->get_item_metadata(sources_list->get_current());
+ if (tile_set->has_source(source_id)) {
+ old_selected = source_id;
+ }
+ }
+
+ int to_select = -1;
+ if (force_selected_id >= 0) {
+ to_select = force_selected_id;
+ } else if (old_selected >= 0) {
+ to_select = old_selected;
+ }
+
+ // Clear the list.
+ sources_list->clear();
+
+ // Update the atlas sources.
+ for (int i = 0; i < tile_set->get_source_count(); i++) {
+ int source_id = tile_set->get_source_id(i);
+
+ TileSetSource *source = *tile_set->get_source(source_id);
+
+ Ref<Texture2D> texture;
+ String item_text;
+
+ // Atlas source.
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ texture = atlas_source->get_texture();
+ if (texture.is_valid()) {
+ item_text = vformat("%s (id:%d)", texture->get_path().get_file(), source_id);
+ } else {
+ item_text = vformat(TTR("No Texture Atlas Source (id:%d)"), source_id);
+ }
+ }
+
+ // Scene collection source.
+ TileSetScenesCollectionSource *scene_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
+ if (scene_collection_source) {
+ texture = get_theme_icon("PackedScene", "EditorIcons");
+ item_text = vformat(TTR("Scene Collection Source (id:%d)"), source_id);
+ }
+
+ // Use default if not valid.
+ if (item_text.is_empty()) {
+ item_text = vformat(TTR("Unknown Type Source (id:%d)"), source_id);
+ }
+ if (!texture.is_valid()) {
+ texture = missing_texture_texture;
+ }
+
+ sources_list->add_item(item_text, texture);
+ sources_list->set_item_metadata(i, source_id);
+ }
+
+ // Set again the current selected item if needed.
+ if (to_select >= 0) {
+ for (int i = 0; i < sources_list->get_item_count(); i++) {
+ if ((int)sources_list->get_item_metadata(i) == to_select) {
+ sources_list->set_current(i);
+ if (old_selected != to_select) {
+ sources_list->emit_signal("item_selected", sources_list->get_current());
+ }
+ break;
+ }
+ }
+ }
+
+ // If nothing is selected, select the first entry.
+ if (sources_list->get_current() < 0 && sources_list->get_item_count() > 0) {
+ sources_list->set_current(0);
+ if (old_selected != int(sources_list->get_item_metadata(0))) {
+ sources_list->emit_signal("item_selected", sources_list->get_current());
+ }
+ }
+
+ // If there is no source left, hide all editors and show the label.
+ _source_selected(sources_list->get_current());
+
+ // Synchronize the lists.
+ TilesEditor::get_singleton()->set_atlas_sources_lists_current(sources_list->get_current());
+}
+
+void TileSetEditor::_source_selected(int p_source_index) {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ // Update the selected source.
+ sources_delete_button->set_disabled(p_source_index < 0);
+
+ if (p_source_index >= 0) {
+ int source_id = sources_list->get_item_metadata(p_source_index);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(*tile_set->get_source(source_id));
+ TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(*tile_set->get_source(source_id));
+ if (atlas_source) {
+ no_source_selected_label->hide();
+ tile_set_atlas_source_editor->edit(*tile_set, atlas_source, source_id);
+ tile_set_atlas_source_editor->show();
+ tile_set_scenes_collection_source_editor->hide();
+ } else if (scenes_collection_source) {
+ no_source_selected_label->hide();
+ tile_set_atlas_source_editor->hide();
+ tile_set_scenes_collection_source_editor->edit(*tile_set, scenes_collection_source, source_id);
+ tile_set_scenes_collection_source_editor->show();
+ } else {
+ no_source_selected_label->show();
+ tile_set_atlas_source_editor->hide();
+ tile_set_scenes_collection_source_editor->hide();
+ }
+ } else {
+ no_source_selected_label->show();
+ tile_set_atlas_source_editor->hide();
+ tile_set_scenes_collection_source_editor->hide();
+ }
+}
+
+void TileSetEditor::_source_add_id_pressed(int p_id_pressed) {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ switch (p_id_pressed) {
+ case 0: {
+ int source_id = tile_set->get_next_source_id();
+
+ Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
+
+ // Add a new source.
+ undo_redo->create_action(TTR("Add atlas source"));
+ undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
+ undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
+ undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
+ undo_redo->commit_action();
+
+ _update_atlas_sources_list(source_id);
+ } break;
+ case 1: {
+ int source_id = tile_set->get_next_source_id();
+
+ Ref<TileSetScenesCollectionSource> scene_collection_source = memnew(TileSetScenesCollectionSource);
+
+ // Add a new source.
+ undo_redo->create_action(TTR("Add atlas source"));
+ undo_redo->add_do_method(*tile_set, "add_source", scene_collection_source, source_id);
+ undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
+ undo_redo->commit_action();
+
+ _update_atlas_sources_list(source_id);
+ } break;
+ default:
+ ERR_FAIL();
+ }
+}
+
+void TileSetEditor::_source_delete_pressed() {
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ // Update the selected source.
+ int to_delete = sources_list->get_item_metadata(sources_list->get_current());
+
+ Ref<TileSetSource> source = tile_set->get_source(to_delete);
+
+ // Remove the source.
+ undo_redo->create_action(TTR("Remove source"));
+ undo_redo->add_do_method(*tile_set, "remove_source", to_delete);
+ undo_redo->add_undo_method(*tile_set, "add_source", source, to_delete);
+ undo_redo->commit_action();
+
+ _update_atlas_sources_list();
+}
+
+void TileSetEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ sources_delete_button->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ sources_add_button->set_icon(get_theme_icon("Add", "EditorIcons"));
+ missing_texture_texture = get_theme_icon("TileSet", "EditorIcons");
+ break;
+ case NOTIFICATION_INTERNAL_PROCESS:
+ if (tile_set_changed_needs_update) {
+ if (tile_set.is_valid()) {
+ tile_set->set_edited(true);
+ }
+ _update_atlas_sources_list();
+ tile_set_changed_needs_update = false;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void TileSetEditor::_tile_set_changed() {
+ tile_set_changed_needs_update = true;
+}
+
+void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
+ UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
+ ERR_FAIL_COND(!undo_redo);
+
+#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, tile_data->get(property));
+ TileSet *tile_set = Object::cast_to<TileSet>(p_edited);
+ if (tile_set) {
+ Vector<String> components = p_property.split("/", true, 3);
+ for (int i = 0; i < tile_set->get_source_count(); i++) {
+ int source_id = tile_set->get_source_id(i);
+
+ Ref<TileSetAtlasSource> tas = tile_set->get_source(source_id);
+ if (tas.is_valid()) {
+ for (int j = 0; j < tas->get_tiles_count(); j++) {
+ Vector2i tile_id = tas->get_tile_id(j);
+ for (int k = 0; k < tas->get_alternative_tiles_count(tile_id); k++) {
+ int alternative_id = tas->get_alternative_tile_id(tile_id, k);
+ TileData *tile_data = Object::cast_to<TileData>(tas->get_tile_data(tile_id, alternative_id));
+ ERR_FAIL_COND(!tile_data);
+
+ if (p_property == "occlusion_layers_count") {
+ int new_layer_count = p_new_value;
+ int old_layer_count = tile_set->get_occlusion_layers_count();
+ if (new_layer_count < old_layer_count) {
+ for (int occclusion_layer_index = new_layer_count - 1; occclusion_layer_index < old_layer_count; occclusion_layer_index++) {
+ ADD_UNDO(tile_data, vformat("occlusion_layer_%d/polygon", occclusion_layer_index));
+ }
+ }
+ } else if (p_property == "physics_layers_count") {
+ int new_layer_count = p_new_value;
+ int old_layer_count = tile_set->get_physics_layers_count();
+ if (new_layer_count < old_layer_count) {
+ for (int physics_layer_index = new_layer_count - 1; physics_layer_index < old_layer_count; physics_layer_index++) {
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/shapes_count", physics_layer_index));
+ for (int shape_index = 0; shape_index < tile_data->get_collision_shapes_count(physics_layer_index); shape_index++) {
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/shape", physics_layer_index, shape_index));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way", physics_layer_index, shape_index));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way_margin", physics_layer_index, shape_index));
+ }
+ }
+ }
+ } else if ((p_property == "terrains_sets_count" && tile_data->get_terrain_set() >= (int)p_new_value) ||
+ (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_integer() && components[1] == "mode") ||
+ (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_integer() && components[1] == "terrains_count" && tile_data->get_terrain_set() == components[0].trim_prefix("terrain_set_").to_int() && (int)p_new_value < tile_set->get_terrains_count(tile_data->get_terrain_set()))) {
+ ADD_UNDO(tile_data, "terrain_set");
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/right_side");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/right_corner");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/bottom_right_side");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/bottom_right_corner");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/bottom_side");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/bottom_corner");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/bottom_left_side");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/bottom_left_corner");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/left_side");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/left_corner");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/top_left_side");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/top_left_corner");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/top_side");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/top_corner");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/top_right_side");
+ }
+ if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/top_right_corner");
+ }
+ } else if (p_property == "navigation_layers_count") {
+ int new_layer_count = p_new_value;
+ int old_layer_count = tile_set->get_navigation_layers_count();
+ if (new_layer_count < old_layer_count) {
+ for (int navigation_layer_index = new_layer_count - 1; navigation_layer_index < old_layer_count; navigation_layer_index++) {
+ ADD_UNDO(tile_data, vformat("navigation_layer_%d/polygon", navigation_layer_index));
+ }
+ }
+ } else if (p_property == "custom_data_layers_count") {
+ int new_layer_count = p_new_value;
+ int old_layer_count = tile_set->get_custom_data_layers_count();
+ if (new_layer_count < old_layer_count) {
+ for (int custom_data_layer_index = new_layer_count - 1; custom_data_layer_index < old_layer_count; custom_data_layer_index++) {
+ ADD_UNDO(tile_data, vformat("custom_data_%d", custom_data_layer_index));
+ }
+ }
+ } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_integer() && components[1] == "type") {
+ int custom_data_layer = components[0].trim_prefix("custom_data_layer_").is_valid_integer();
+ ADD_UNDO(tile_data, vformat("custom_data_%d", custom_data_layer));
+ }
+ }
+ }
+ }
+ }
+ }
+#undef ADD_UNDO
+}
+
+void TileSetEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetEditor::drop_data_fw);
+}
+
+TileDataEditor *TileSetEditor::get_tile_data_editor(String p_property) {
+ Vector<String> components = String(p_property).split("/", true);
+
+ if (p_property == "z_index") {
+ return tile_data_integer_editor;
+ } else if (p_property == "probability") {
+ return tile_data_float_editor;
+ } else if (p_property == "y_sort_origin") {
+ return tile_data_y_sort_editor;
+ } else if (p_property == "texture_offset") {
+ return tile_data_texture_offset_editor;
+ } else if (components.size() >= 1 && components[0].begins_with("occlusion_layer_")) {
+ return tile_data_occlusion_shape_editor;
+ } else if (components.size() >= 1 && components[0].begins_with("physics_layer_")) {
+ return tile_data_collision_shape_editor;
+ } else if (p_property == "mode" || p_property == "terrain" || (components.size() >= 1 && components[0] == "terrains_peering_bit")) {
+ return tile_data_terrains_editor;
+ } else if (components.size() >= 1 && components[0].begins_with("navigation_layer_")) {
+ return tile_data_navigation_polygon_editor;
+ }
+
+ return nullptr;
+}
+
+void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
+ if (p_tile_set == tile_set) {
+ return;
+ }
+
+ // Remove listener.
+ if (tile_set.is_valid()) {
+ tile_set->disconnect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
+ }
+
+ // Change the edited object.
+ tile_set = p_tile_set;
+
+ // Add the listener again.
+ if (tile_set.is_valid()) {
+ tile_set->connect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
+ _update_atlas_sources_list();
+ }
+
+ tile_set_atlas_source_editor->hide();
+ tile_set_scenes_collection_source_editor->hide();
+ no_source_selected_label->show();
+}
+
+TileSetEditor::TileSetEditor() {
+ singleton = this;
+
+ set_process_internal(true);
+
+ // Split container.
+ HSplitContainer *split_container = memnew(HSplitContainer);
+ split_container->set_name(TTR("Tiles"));
+ split_container->set_h_size_flags(SIZE_EXPAND_FILL);
+ split_container->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(split_container);
+
+ // Sources list.
+ VBoxContainer *split_container_left_side = memnew(VBoxContainer);
+ split_container_left_side->set_h_size_flags(SIZE_EXPAND_FILL);
+ split_container_left_side->set_v_size_flags(SIZE_EXPAND_FILL);
+ split_container_left_side->set_stretch_ratio(0.25);
+ split_container_left_side->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
+ split_container->add_child(split_container_left_side);
+
+ sources_list = memnew(ItemList);
+ sources_list->set_fixed_icon_size(Size2i(60, 60) * EDSCALE);
+ sources_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ sources_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ sources_list->connect("item_selected", callable_mp(this, &TileSetEditor::_source_selected));
+ sources_list->connect("item_selected", callable_mp(TilesEditor::get_singleton(), &TilesEditor::set_atlas_sources_lists_current));
+ sources_list->connect("visibility_changed", callable_mp(TilesEditor::get_singleton(), &TilesEditor::synchronize_atlas_sources_list), varray(sources_list));
+ sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
+ sources_list->set_drag_forwarding(this);
+ split_container_left_side->add_child(sources_list);
+
+ HBoxContainer *sources_bottom_actions = memnew(HBoxContainer);
+ sources_bottom_actions->set_alignment(HBoxContainer::ALIGN_END);
+ split_container_left_side->add_child(sources_bottom_actions);
+
+ sources_delete_button = memnew(Button);
+ sources_delete_button->set_flat(true);
+ sources_delete_button->set_disabled(true);
+ sources_delete_button->connect("pressed", callable_mp(this, &TileSetEditor::_source_delete_pressed));
+ sources_bottom_actions->add_child(sources_delete_button);
+
+ sources_add_button = memnew(MenuButton);
+ sources_add_button->set_flat(true);
+ sources_add_button->get_popup()->add_item(TTR("Atlas"));
+ sources_add_button->get_popup()->add_item(TTR("Scenes Collection"));
+ sources_add_button->get_popup()->connect("id_pressed", callable_mp(this, &TileSetEditor::_source_add_id_pressed));
+ sources_bottom_actions->add_child(sources_add_button);
+
+ // Right side container.
+ VBoxContainer *split_container_right_side = memnew(VBoxContainer);
+ split_container_right_side->set_h_size_flags(SIZE_EXPAND_FILL);
+ split_container_right_side->set_v_size_flags(SIZE_EXPAND_FILL);
+ split_container->add_child(split_container_right_side);
+
+ // No source selected.
+ no_source_selected_label = memnew(Label);
+ no_source_selected_label->set_text(TTR("No TileSet source selected. Select or create a TileSet source."));
+ no_source_selected_label->set_h_size_flags(SIZE_EXPAND_FILL);
+ no_source_selected_label->set_v_size_flags(SIZE_EXPAND_FILL);
+ no_source_selected_label->set_align(Label::ALIGN_CENTER);
+ no_source_selected_label->set_valign(Label::VALIGN_CENTER);
+ split_container_right_side->add_child(no_source_selected_label);
+
+ // Atlases editor.
+ tile_set_atlas_source_editor = memnew(TileSetAtlasSourceEditor);
+ tile_set_atlas_source_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ tile_set_atlas_source_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ tile_set_atlas_source_editor->connect("source_id_changed", callable_mp(this, &TileSetEditor::_update_atlas_sources_list));
+ split_container_right_side->add_child(tile_set_atlas_source_editor);
+ tile_set_atlas_source_editor->hide();
+
+ // Scenes collection editor.
+ tile_set_scenes_collection_source_editor = memnew(TileSetScenesCollectionSourceEditor);
+ tile_set_scenes_collection_source_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ tile_set_scenes_collection_source_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ tile_set_scenes_collection_source_editor->connect("source_id_changed", callable_mp(this, &TileSetEditor::_update_atlas_sources_list));
+ split_container_right_side->add_child(tile_set_scenes_collection_source_editor);
+ tile_set_scenes_collection_source_editor->hide();
+
+ // Registers UndoRedo inspector callback.
+ EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetEditor::_undo_redo_inspector_callback));
+}
+
+TileSetEditor::~TileSetEditor() {
+ if (tile_set.is_valid()) {
+ tile_set->disconnect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
+ }
+
+ // Delete tile data editors.
+ memdelete(tile_data_texture_offset_editor);
+ memdelete(tile_data_y_sort_editor);
+ memdelete(tile_data_integer_editor);
+ memdelete(tile_data_float_editor);
+ memdelete(tile_data_occlusion_shape_editor);
+ memdelete(tile_data_collision_shape_editor);
+ memdelete(tile_data_terrains_editor);
+ memdelete(tile_data_navigation_polygon_editor);
+}
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
new file mode 100644
index 0000000000..f584c043cc
--- /dev/null
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* tile_set_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TILE_SET_EDITOR_H
+#define TILE_SET_EDITOR_H
+
+#include "scene/gui/box_container.h"
+#include "scene/resources/tile_set.h"
+#include "tile_data_editors.h"
+#include "tile_set_atlas_source_editor.h"
+#include "tile_set_scenes_collection_source_editor.h"
+
+class TileSetEditor : public VBoxContainer {
+ GDCLASS(TileSetEditor, VBoxContainer);
+
+ static TileSetEditor *singleton;
+
+private:
+ Ref<TileSet> tile_set;
+ bool tile_set_changed_needs_update = false;
+
+ Label *no_source_selected_label;
+ TileSetAtlasSourceEditor *tile_set_atlas_source_editor;
+ TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor;
+
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+
+ void _update_atlas_sources_list(int force_selected_id = -1);
+
+ // List of tile data editors.
+ TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor);
+ TileDataYSortEditor *tile_data_y_sort_editor = memnew(TileDataYSortEditor);
+ TileDataIntegerEditor *tile_data_integer_editor = memnew(TileDataIntegerEditor);
+ TileDataFloatEditor *tile_data_float_editor = memnew(TileDataFloatEditor);
+ TileDataOcclusionShapeEditor *tile_data_occlusion_shape_editor = memnew(TileDataOcclusionShapeEditor);
+ TileDataCollisionShapeEditor *tile_data_collision_shape_editor = memnew(TileDataCollisionShapeEditor);
+ TileDataTerrainsEditor *tile_data_terrains_editor = memnew(TileDataTerrainsEditor);
+ TileDataNavigationPolygonEditor *tile_data_navigation_polygon_editor = memnew(TileDataNavigationPolygonEditor);
+
+ // -- Sources management --
+ Button *sources_delete_button;
+ MenuButton *sources_add_button;
+ ItemList *sources_list;
+ Ref<Texture2D> missing_texture_texture;
+ void _source_selected(int p_source_index);
+ void _source_add_id_pressed(int p_id_pressed);
+ void _source_delete_pressed();
+
+ void _tile_set_changed();
+
+ void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ _FORCE_INLINE_ static TileSetEditor *get_singleton() { return singleton; }
+
+ TileDataEditor *get_tile_data_editor(String property);
+ void edit(Ref<TileSet> p_tile_set);
+ void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+ bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+
+ TileSetEditor();
+ ~TileSetEditor();
+};
+
+#endif // TILE_SET_EDITOR_PLUGIN_H
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
new file mode 100644
index 0000000000..568d4ca8d7
--- /dev/null
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -0,0 +1,511 @@
+/*************************************************************************/
+/* tile_set_scenes_collection_source_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "tile_set_scenes_collection_source_editor.h"
+
+#include "editor/editor_resource_preview.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+
+#include "scene/gui/item_list.h"
+
+#include "core/core_string_names.h"
+
+void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::set_id(int p_id) {
+ ERR_FAIL_COND(p_id < 0);
+ if (source_id == p_id) {
+ return;
+ }
+ ERR_FAIL_COND_MSG(tile_set->has_source(p_id), vformat("Cannot change TileSet Scenes Collection source ID. Another TileSet source exists with id %d.", p_id));
+
+ int previous_source = source_id;
+ source_id = p_id; // source_id must be updated before, because it's used by the source list update.
+ tile_set->set_source_id(previous_source, p_id);
+ emit_signal("changed", "id");
+}
+
+int TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::get_id() {
+ return source_id;
+}
+
+bool TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_set(const StringName &p_name, const Variant &p_value) {
+ bool valid = false;
+ tile_set_scenes_collection_source->set(p_name, p_value, &valid);
+ if (valid) {
+ emit_signal("changed", String(p_name).utf8().get_data());
+ }
+ return valid;
+}
+
+bool TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_get(const StringName &p_name, Variant &r_ret) const {
+ if (!tile_set_scenes_collection_source) {
+ return false;
+ }
+ bool valid = false;
+ r_ret = tile_set_scenes_collection_source->get(p_name, &valid);
+ return valid;
+}
+
+void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_bind_methods() {
+ // -- Shape and layout --
+ ClassDB::bind_method(D_METHOD("set_id", "id"), &TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::set_id);
+ ClassDB::bind_method(D_METHOD("get_id"), &TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::get_id);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "id"), "set_id", "get_id");
+
+ ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what")));
+}
+
+void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::edit(Ref<TileSet> p_tile_set, TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_source_id) {
+ ERR_FAIL_COND(!p_tile_set.is_valid());
+ ERR_FAIL_COND(!p_tile_set_scenes_collection_source);
+ ERR_FAIL_COND(p_source_id < 0);
+ ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_scenes_collection_source);
+
+ // Disconnect to changes.
+ if (tile_set_scenes_collection_source) {
+ tile_set_scenes_collection_source->disconnect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
+ }
+
+ tile_set = p_tile_set;
+ tile_set_scenes_collection_source = p_tile_set_scenes_collection_source;
+ source_id = p_source_id;
+
+ // Connect to changes.
+ if (tile_set_scenes_collection_source) {
+ if (!tile_set_scenes_collection_source->is_connected(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed))) {
+ tile_set_scenes_collection_source->connect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
+ }
+ }
+
+ notify_property_list_changed();
+}
+
+// -- Proxy object used by the tile inspector --
+bool TileSetScenesCollectionSourceEditor::SceneTileProxyObject::_set(const StringName &p_name, const Variant &p_value) {
+ if (!tile_set_scenes_collection_source) {
+ return false;
+ }
+
+ if (p_name == "id") {
+ int as_int = int(p_value);
+ ERR_FAIL_COND_V(as_int < 0, false);
+ ERR_FAIL_COND_V(tile_set_scenes_collection_source->has_scene_tile_id(as_int), false);
+ tile_set_scenes_collection_source->set_scene_tile_id(scene_id, as_int);
+ scene_id = as_int;
+ emit_signal("changed", "id");
+ for (int i = 0; i < tile_set_scenes_collection_source_editor->scene_tiles_list->get_item_count(); i++) {
+ if (int(tile_set_scenes_collection_source_editor->scene_tiles_list->get_item_metadata(i)) == scene_id) {
+ tile_set_scenes_collection_source_editor->scene_tiles_list->select(i);
+ break;
+ }
+ }
+ return true;
+ } else if (p_name == "scene") {
+ tile_set_scenes_collection_source->set_scene_tile_scene(scene_id, p_value);
+ emit_signal("changed", "scene");
+ return true;
+ } else if (p_name == "display_placeholder") {
+ tile_set_scenes_collection_source->set_scene_tile_display_placeholder(scene_id, p_value);
+ emit_signal("changed", "display_placeholder");
+ return true;
+ }
+
+ return false;
+}
+
+bool TileSetScenesCollectionSourceEditor::SceneTileProxyObject::_get(const StringName &p_name, Variant &r_ret) const {
+ if (!tile_set_scenes_collection_source) {
+ return false;
+ }
+
+ if (p_name == "id") {
+ r_ret = scene_id;
+ return true;
+ } else if (p_name == "scene") {
+ r_ret = tile_set_scenes_collection_source->get_scene_tile_scene(scene_id);
+ return true;
+ } else if (p_name == "display_placeholder") {
+ r_ret = tile_set_scenes_collection_source->get_scene_tile_display_placeholder(scene_id);
+ return true;
+ }
+
+ return false;
+}
+
+void TileSetScenesCollectionSourceEditor::SceneTileProxyObject::_get_property_list(List<PropertyInfo> *p_list) const {
+ if (!tile_set_scenes_collection_source) {
+ return;
+ }
+
+ p_list->push_back(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "scene", PROPERTY_HINT_RESOURCE_TYPE, "PackedScene"));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "display_placeholder", PROPERTY_HINT_NONE, ""));
+}
+
+void TileSetScenesCollectionSourceEditor::SceneTileProxyObject::edit(TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_scene_id) {
+ ERR_FAIL_COND(!p_tile_set_scenes_collection_source);
+ ERR_FAIL_COND(!p_tile_set_scenes_collection_source->has_scene_tile_id(p_scene_id));
+
+ tile_set_scenes_collection_source = p_tile_set_scenes_collection_source;
+ scene_id = p_scene_id;
+
+ notify_property_list_changed();
+}
+
+void TileSetScenesCollectionSourceEditor::SceneTileProxyObject::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what")));
+}
+
+void TileSetScenesCollectionSourceEditor::_scenes_collection_source_proxy_object_changed(String p_what) {
+ if (p_what == "id") {
+ emit_signal("source_id_changed", scenes_collection_source_proxy_object->get_id());
+ }
+}
+
+void TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed() {
+ tile_set_scenes_collection_source_changed_needs_update = true;
+}
+
+void TileSetScenesCollectionSourceEditor::_scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud) {
+ int index = p_ud;
+
+ if (index >= 0 && index < scene_tiles_list->get_item_count()) {
+ scene_tiles_list->set_item_icon(index, p_preview);
+ }
+}
+
+void TileSetScenesCollectionSourceEditor::_scenes_list_item_activated(int p_index) {
+ Ref<PackedScene> packed_scene = tile_set_scenes_collection_source->get_scene_tile_scene(scene_tiles_list->get_item_metadata(p_index));
+ if (packed_scene.is_valid()) {
+ EditorNode::get_singleton()->open_request(packed_scene->get_path());
+ }
+}
+
+void TileSetScenesCollectionSourceEditor::_source_add_pressed() {
+ int scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id();
+ undo_redo->create_action(TTR("Add a Scene Tile"));
+ undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", Ref<PackedScene>(), scene_id);
+ undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
+ undo_redo->commit_action();
+ _update_scenes_list();
+ _update_action_buttons();
+ _update_tile_inspector();
+}
+
+void TileSetScenesCollectionSourceEditor::_source_delete_pressed() {
+ Vector<int> selected_indices = scene_tiles_list->get_selected_items();
+ ERR_FAIL_COND(selected_indices.size() <= 0);
+ int scene_id = scene_tiles_list->get_item_metadata(selected_indices[0]);
+
+ undo_redo->create_action(TTR("Remove a Scene Tile"));
+ undo_redo->add_do_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
+ undo_redo->add_undo_method(tile_set_scenes_collection_source, "create_scene_tile", tile_set_scenes_collection_source->get_scene_tile_scene(scene_id), scene_id);
+ undo_redo->commit_action();
+ _update_scenes_list();
+ _update_action_buttons();
+ _update_tile_inspector();
+}
+
+void TileSetScenesCollectionSourceEditor::_update_source_inspector() {
+ // Update the proxy object.
+ scenes_collection_source_proxy_object->edit(tile_set, tile_set_scenes_collection_source, tile_set_source_id);
+}
+
+void TileSetScenesCollectionSourceEditor::_update_tile_inspector() {
+ Vector<int> selected_indices = scene_tiles_list->get_selected_items();
+ bool has_atlas_tile_selected = (selected_indices.size() > 0);
+
+ // Update the proxy object.
+ if (has_atlas_tile_selected) {
+ int scene_id = scene_tiles_list->get_item_metadata(selected_indices[0]);
+ tile_proxy_object->edit(tile_set_scenes_collection_source, scene_id);
+ }
+
+ // Update visibility.
+ tile_inspector_label->set_visible(has_atlas_tile_selected);
+ tile_inspector->set_visible(has_atlas_tile_selected);
+}
+
+void TileSetScenesCollectionSourceEditor::_update_action_buttons() {
+ Vector<int> selected_indices = scene_tiles_list->get_selected_items();
+ scene_tile_delete_button->set_disabled(selected_indices.size() <= 0);
+}
+
+void TileSetScenesCollectionSourceEditor::_update_scenes_list() {
+ if (!tile_set_scenes_collection_source) {
+ return;
+ }
+
+ // Get the previously selected id.
+ Vector<int> selected_indices = scene_tiles_list->get_selected_items();
+ int old_selected_scene_id = (selected_indices.size() > 0) ? int(scene_tiles_list->get_item_metadata(selected_indices[0])) : -1;
+
+ // Clear the list.
+ scene_tiles_list->clear();
+
+ // Rebuild the list.
+ int to_reselect = -1;
+ for (int i = 0; i < tile_set_scenes_collection_source->get_scene_tiles_count(); i++) {
+ int scene_id = tile_set_scenes_collection_source->get_scene_tile_id(i);
+
+ Ref<PackedScene> scene = tile_set_scenes_collection_source->get_scene_tile_scene(scene_id);
+
+ int item_index = 0;
+ if (scene.is_valid()) {
+ item_index = scene_tiles_list->add_item(vformat("%s (path:%s id:%d)", scene->get_path().get_file().get_basename(), scene->get_path(), scene_id));
+ Variant udata = i;
+ EditorResourcePreview::get_singleton()->queue_edited_resource_preview(scene, this, "_scene_thumbnail_done", udata);
+ } else {
+ item_index = scene_tiles_list->add_item(TTR("Tile with Invalid Scene"), get_theme_icon("PackedScene", "EditorIcons"));
+ }
+ scene_tiles_list->set_item_metadata(item_index, scene_id);
+
+ if (old_selected_scene_id >= 0 && scene_id == old_selected_scene_id) {
+ to_reselect = i;
+ }
+ }
+
+ // Reselect if needed.
+ if (to_reselect >= 0) {
+ scene_tiles_list->select(to_reselect);
+ }
+
+ // Icon size update.
+ int int_size = int(EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size")) * EDSCALE;
+ scene_tiles_list->set_fixed_icon_size(Vector2(int_size, int_size));
+}
+
+void TileSetScenesCollectionSourceEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ scene_tile_add_button->set_icon(get_theme_icon("Add", "EditorIcons"));
+ scene_tile_delete_button->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ _update_scenes_list();
+ break;
+ case NOTIFICATION_INTERNAL_PROCESS:
+ if (tile_set_scenes_collection_source_changed_needs_update) {
+ // Update everything.
+ _update_source_inspector();
+ _update_scenes_list();
+ _update_action_buttons();
+ _update_tile_inspector();
+ tile_set_scenes_collection_source_changed_needs_update = false;
+ }
+ break;
+ case NOTIFICATION_VISIBILITY_CHANGED:
+ // Update things just in case.
+ _update_scenes_list();
+ _update_action_buttons();
+ break;
+ default:
+ break;
+ }
+}
+
+void TileSetScenesCollectionSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_source_id) {
+ ERR_FAIL_COND(!p_tile_set.is_valid());
+ ERR_FAIL_COND(!p_tile_set_scenes_collection_source);
+ ERR_FAIL_COND(p_source_id < 0);
+ ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_scenes_collection_source);
+
+ if (p_tile_set == tile_set && p_tile_set_scenes_collection_source == tile_set_scenes_collection_source && p_source_id == tile_set_source_id) {
+ return;
+ }
+
+ // Remove listener for old objects.
+ if (tile_set_scenes_collection_source) {
+ tile_set_scenes_collection_source->disconnect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed));
+ }
+
+ // Change the edited object.
+ tile_set = p_tile_set;
+ tile_set_scenes_collection_source = p_tile_set_scenes_collection_source;
+ tile_set_source_id = p_source_id;
+
+ // Add the listener again.
+ if (tile_set_scenes_collection_source) {
+ tile_set_scenes_collection_source->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed));
+ }
+
+ // Update everything.
+ _update_source_inspector();
+ _update_scenes_list();
+ _update_action_buttons();
+ _update_tile_inspector();
+}
+
+void TileSetScenesCollectionSourceEditor::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;
+ }
+
+ if (p_from == scene_tiles_list) {
+ // Handle dropping a texture in the list of atlas resources.
+ int scene_id = -1;
+ Dictionary d = p_data;
+ Vector<String> files = d["files"];
+ for (int i = 0; i < files.size(); i++) {
+ Ref<PackedScene> resource = ResourceLoader::load(files[i]);
+ if (resource.is_valid()) {
+ scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id();
+ undo_redo->create_action(TTR("Add a Scene Tile"));
+ undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", resource, scene_id);
+ undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
+ undo_redo->commit_action();
+ }
+ }
+
+ _update_scenes_list();
+ _update_action_buttons();
+ _update_tile_inspector();
+ }
+}
+
+bool TileSetScenesCollectionSourceEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ if (p_from == scene_tiles_list) {
+ Dictionary d = p_data;
+
+ if (!d.has("type")) {
+ return false;
+ }
+
+ // Check if we have a Texture2D.
+ if (String(d["type"]) == "files") {
+ Vector<String> files = d["files"];
+
+ if (files.size() == 0) {
+ return false;
+ }
+
+ for (int i = 0; i < files.size(); i++) {
+ String file = files[i];
+ String ftype = EditorFileSystem::get_singleton()->get_file_type(file);
+
+ if (!ClassDB::is_parent_class(ftype, "PackedScene")) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+ return false;
+}
+
+void TileSetScenesCollectionSourceEditor::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("source_id_changed", PropertyInfo(Variant::INT, "source_id")));
+
+ ClassDB::bind_method(D_METHOD("_scene_thumbnail_done"), &TileSetScenesCollectionSourceEditor::_scene_thumbnail_done);
+ ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &TileSetScenesCollectionSourceEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("drop_data_fw"), &TileSetScenesCollectionSourceEditor::drop_data_fw);
+}
+
+TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
+ // -- Right side --
+ HSplitContainer *split_container_right_side = memnew(HSplitContainer);
+ split_container_right_side->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_child(split_container_right_side);
+
+ // Middle panel.
+ ScrollContainer *middle_panel = memnew(ScrollContainer);
+ middle_panel->set_enable_h_scroll(false);
+ middle_panel->set_custom_minimum_size(Size2i(200, 0) * EDSCALE);
+ split_container_right_side->add_child(middle_panel);
+
+ VBoxContainer *middle_vbox_container = memnew(VBoxContainer);
+ middle_vbox_container->set_h_size_flags(SIZE_EXPAND_FILL);
+ middle_panel->add_child(middle_vbox_container);
+
+ // Scenes collection source inspector.
+ scenes_collection_source_inspector_label = memnew(Label);
+ scenes_collection_source_inspector_label->set_text(TTR("Scenes collection properties:"));
+ middle_vbox_container->add_child(scenes_collection_source_inspector_label);
+
+ scenes_collection_source_proxy_object = memnew(TileSetScenesCollectionProxyObject());
+ scenes_collection_source_proxy_object->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_collection_source_proxy_object_changed));
+
+ scenes_collection_source_inspector = memnew(EditorInspector);
+ scenes_collection_source_inspector->set_undo_redo(undo_redo);
+ scenes_collection_source_inspector->set_enable_v_scroll(false);
+ scenes_collection_source_inspector->edit(scenes_collection_source_proxy_object);
+ middle_vbox_container->add_child(scenes_collection_source_inspector);
+
+ // Tile inspector.
+ tile_inspector_label = memnew(Label);
+ tile_inspector_label->set_text(TTR("Tile properties:"));
+ tile_inspector_label->hide();
+ middle_vbox_container->add_child(tile_inspector_label);
+
+ tile_proxy_object = memnew(SceneTileProxyObject(this));
+ tile_proxy_object->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_scenes_list).unbind(1));
+ tile_proxy_object->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_action_buttons).unbind(1));
+
+ tile_inspector = memnew(EditorInspector);
+ tile_inspector->set_undo_redo(undo_redo);
+ tile_inspector->set_enable_v_scroll(false);
+ tile_inspector->edit(tile_proxy_object);
+ tile_inspector->set_use_folding(true);
+ middle_vbox_container->add_child(tile_inspector);
+
+ // Scenes list.
+ VBoxContainer *right_vbox_container = memnew(VBoxContainer);
+ split_container_right_side->add_child(right_vbox_container);
+
+ scene_tiles_list = memnew(ItemList);
+ scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ scene_tiles_list->set_drag_forwarding(this);
+ scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_tile_inspector).unbind(1));
+ scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_action_buttons).unbind(1));
+ scene_tiles_list->connect("item_activated", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_list_item_activated));
+ scene_tiles_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
+ right_vbox_container->add_child(scene_tiles_list);
+
+ HBoxContainer *scenes_bottom_actions = memnew(HBoxContainer);
+ right_vbox_container->add_child(scenes_bottom_actions);
+
+ scene_tile_add_button = memnew(Button);
+ scene_tile_add_button->set_flat(true);
+ scene_tile_add_button->connect("pressed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_source_add_pressed));
+ scenes_bottom_actions->add_child(scene_tile_add_button);
+
+ scene_tile_delete_button = memnew(Button);
+ scene_tile_delete_button->set_flat(true);
+ scene_tile_delete_button->set_disabled(true);
+ scene_tile_delete_button->connect("pressed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_source_delete_pressed));
+ scenes_bottom_actions->add_child(scene_tile_delete_button);
+}
+
+TileSetScenesCollectionSourceEditor::~TileSetScenesCollectionSourceEditor() {
+ memdelete(scenes_collection_source_proxy_object);
+ memdelete(tile_proxy_object);
+}
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
new file mode 100644
index 0000000000..195aa79bc4
--- /dev/null
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
@@ -0,0 +1,139 @@
+/*************************************************************************/
+/* tile_set_scenes_collection_source_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TILE_SET_SCENES_COLLECTION_SOURCE_EDITOR_H
+#define TILE_SET_SCENES_COLLECTION_SOURCE_EDITOR_H
+
+#include "editor/editor_node.h"
+#include "scene/gui/box_container.h"
+#include "scene/resources/tile_set.h"
+
+class TileSetScenesCollectionSourceEditor : public HBoxContainer {
+ GDCLASS(TileSetScenesCollectionSourceEditor, HBoxContainer);
+
+private:
+ // -- Proxy object for an atlas source, needed by the inspector --
+ class TileSetScenesCollectionProxyObject : public Object {
+ GDCLASS(TileSetScenesCollectionProxyObject, Object);
+
+ private:
+ Ref<TileSet> tile_set;
+ TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr;
+ int source_id = -1;
+
+ protected:
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ static void _bind_methods();
+
+ public:
+ void set_id(int p_id);
+ int get_id();
+
+ void edit(Ref<TileSet> p_tile_set, TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_source_id);
+ };
+
+ // -- Proxy object for a tile, needed by the inspector --
+ class SceneTileProxyObject : public Object {
+ GDCLASS(SceneTileProxyObject, Object);
+
+ private:
+ TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor;
+
+ TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr;
+ int source_id;
+ int scene_id;
+
+ 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;
+
+ static void _bind_methods();
+
+ public:
+ // Update the proxyed object.
+ void edit(TileSetScenesCollectionSource *p_tile_set_atlas_source, int p_scene_id);
+
+ SceneTileProxyObject(TileSetScenesCollectionSourceEditor *p_tiles_set_scenes_collection_source_editor) {
+ tile_set_scenes_collection_source_editor = p_tiles_set_scenes_collection_source_editor;
+ }
+ };
+
+private:
+ Ref<TileSet> tile_set;
+ TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr;
+ int tile_set_source_id = -1;
+
+ UndoRedo *undo_redo = EditorNode::get_undo_redo();
+
+ bool tile_set_scenes_collection_source_changed_needs_update = false;
+
+ // Source inspector.
+ TileSetScenesCollectionProxyObject *scenes_collection_source_proxy_object;
+ Label *scenes_collection_source_inspector_label;
+ EditorInspector *scenes_collection_source_inspector;
+
+ // Tile inspector.
+ SceneTileProxyObject *tile_proxy_object;
+ Label *tile_inspector_label;
+ EditorInspector *tile_inspector;
+
+ ItemList *scene_tiles_list;
+ Button *scene_tile_add_button;
+ Button *scene_tile_delete_button;
+
+ void _tile_set_scenes_collection_source_changed();
+ void _scenes_collection_source_proxy_object_changed(String p_what);
+ void _scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud);
+ void _scenes_list_item_activated(int p_index);
+
+ void _source_add_pressed();
+ void _source_delete_pressed();
+
+ // Update methods.
+ void _update_source_inspector();
+ void _update_tile_inspector();
+ void _update_scenes_list();
+ void _update_action_buttons();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void edit(Ref<TileSet> p_tile_set, TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_source_id);
+ void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+ bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ TileSetScenesCollectionSourceEditor();
+ ~TileSetScenesCollectionSourceEditor();
+};
+
+#endif
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
new file mode 100644
index 0000000000..fb111efc17
--- /dev/null
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -0,0 +1,277 @@
+/*************************************************************************/
+/* tiles_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "tiles_editor_plugin.h"
+
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/plugins/canvas_item_editor_plugin.h"
+
+#include "scene/2d/tile_map.h"
+#include "scene/resources/tile_set.h"
+
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/control.h"
+#include "scene/gui/separator.h"
+
+#include "tile_set_editor.h"
+
+TilesEditor *TilesEditor::singleton = nullptr;
+
+void TilesEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ tileset_tilemap_switch_button->set_icon(get_theme_icon("TileSet", "EditorIcons"));
+ } break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ if (tile_map_changed_needs_update) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (tile_map) {
+ tile_set = tile_map->get_tileset();
+ }
+ _update_switch_button();
+ _update_editors();
+ }
+ } break;
+ }
+}
+
+void TilesEditor::_tile_map_changed() {
+ tile_map_changed_needs_update = true;
+}
+
+void TilesEditor::_update_switch_button() {
+ // Force the buttons status if needed.
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (tile_map && !tile_set.is_valid()) {
+ tileset_tilemap_switch_button->set_pressed(false);
+ } else if (!tile_map && tile_set.is_valid()) {
+ tileset_tilemap_switch_button->set_pressed(true);
+ }
+}
+
+void TilesEditor::_update_editors() {
+ // Set editors visibility.
+ tilemap_toolbar->set_visible(!tileset_tilemap_switch_button->is_pressed());
+ tilemap_editor->set_visible(!tileset_tilemap_switch_button->is_pressed());
+ tileset_editor->set_visible(tileset_tilemap_switch_button->is_pressed());
+
+ // Enable/disable the switch button.
+ if (!tileset_tilemap_switch_button->is_pressed()) {
+ if (!tile_set.is_valid()) {
+ tileset_tilemap_switch_button->set_disabled(true);
+ tileset_tilemap_switch_button->set_tooltip(TTR("This TileMap has no assigned TileSet, assign a TileSet to this TileMap to edit it."));
+ } else {
+ tileset_tilemap_switch_button->set_disabled(false);
+ tileset_tilemap_switch_button->set_tooltip(TTR("Switch between TileSet/TileMap editor."));
+ }
+ } else {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ tileset_tilemap_switch_button->set_disabled(true);
+ tileset_tilemap_switch_button->set_tooltip(TTR("You are editing a TileSet resource. Select a TileMap node to paint."));
+ } else {
+ tileset_tilemap_switch_button->set_disabled(false);
+ tileset_tilemap_switch_button->set_tooltip(TTR("Switch between TileSet/TileMap editor."));
+ }
+ }
+
+ // If tile_map is not edited, we change the edited only if we are not editing a tile_set.
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (tile_map) {
+ tilemap_editor->edit(tile_map);
+ } else {
+ tilemap_editor->edit(nullptr);
+ }
+ tileset_editor->edit(tile_set);
+
+ // Update the viewport
+ CanvasItemEditor::get_singleton()->update_viewport();
+}
+
+void TilesEditor::set_atlas_sources_lists_current(int p_current) {
+ atlas_sources_lists_current = p_current;
+}
+
+void TilesEditor::synchronize_atlas_sources_list(Object *p_current) {
+ ItemList *item_list = Object::cast_to<ItemList>(p_current);
+ ERR_FAIL_COND(!item_list);
+
+ if (item_list->is_visible_in_tree()) {
+ if (atlas_sources_lists_current < 0 || atlas_sources_lists_current >= item_list->get_item_count()) {
+ item_list->deselect_all();
+ } else {
+ item_list->set_current(atlas_sources_lists_current);
+ item_list->emit_signal("item_selected", atlas_sources_lists_current);
+ }
+ }
+}
+
+void TilesEditor::set_atlas_view_transform(float p_zoom, Vector2 p_scroll) {
+ atlas_view_zoom = p_zoom;
+ atlas_view_scroll = p_scroll;
+}
+
+void TilesEditor::synchronize_atlas_view(Object *p_current) {
+ TileAtlasView *tile_atlas_view = Object::cast_to<TileAtlasView>(p_current);
+ ERR_FAIL_COND(!tile_atlas_view);
+
+ if (tile_atlas_view->is_visible_in_tree()) {
+ tile_atlas_view->set_transform(atlas_view_zoom, Vector2(atlas_view_scroll.x, atlas_view_scroll.y));
+ }
+}
+
+void TilesEditor::edit(Object *p_object) {
+ // Disconnect to changes.
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (tile_map) {
+ tile_map->disconnect("changed", callable_mp(this, &TilesEditor::_tile_map_changed));
+ }
+
+ // Update edited objects.
+ tile_set = Ref<TileSet>();
+ if (p_object) {
+ if (p_object->is_class("TileMap")) {
+ tile_map_id = p_object->get_instance_id();
+ tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ tile_set = tile_map->get_tileset();
+ } else if (p_object->is_class("TileSet")) {
+ tile_set = Ref<TileSet>(p_object);
+ if (tile_map) {
+ if (tile_map->get_tileset() != tile_set) {
+ tile_map = nullptr;
+ }
+ }
+ }
+
+ // Update pressed status button.
+ if (p_object->is_class("TileMap")) {
+ tileset_tilemap_switch_button->set_pressed(false);
+ } else if (p_object->is_class("TileSet")) {
+ tileset_tilemap_switch_button->set_pressed(true);
+ }
+ }
+
+ // Update the editors.
+ _update_switch_button();
+ _update_editors();
+
+ // Add change listener.
+ if (tile_map) {
+ tile_map->connect("changed", callable_mp(this, &TilesEditor::_tile_map_changed));
+ }
+}
+
+void TilesEditor::_bind_methods() {
+}
+
+TilesEditor::TilesEditor(EditorNode *p_editor) {
+ set_process_internal(true);
+
+ // Update the singleton.
+ singleton = this;
+
+ // Toolbar.
+ HBoxContainer *toolbar = memnew(HBoxContainer);
+ toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_child(toolbar);
+
+ // Switch button.
+ tileset_tilemap_switch_button = memnew(Button);
+ tileset_tilemap_switch_button->set_flat(true);
+ tileset_tilemap_switch_button->set_toggle_mode(true);
+ tileset_tilemap_switch_button->connect("toggled", callable_mp(this, &TilesEditor::_update_editors).unbind(1));
+ toolbar->add_child(tileset_tilemap_switch_button);
+
+ // Tilemap editor.
+ tilemap_editor = memnew(TileMapEditor);
+ tilemap_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ tilemap_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ tilemap_editor->hide();
+ add_child(tilemap_editor);
+
+ tilemap_toolbar = tilemap_editor->get_toolbar();
+ toolbar->add_child(tilemap_toolbar);
+
+ // Tileset editor.
+ tileset_editor = memnew(TileSetEditor);
+ tileset_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ tileset_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ tileset_editor->hide();
+ add_child(tileset_editor);
+
+ // Initialization.
+ _update_switch_button();
+ _update_editors();
+}
+
+TilesEditor::~TilesEditor() {
+}
+
+///////////////////////////////////////////////////////////////
+
+void TilesEditorPlugin::_notification(int p_what) {
+}
+
+void TilesEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ tiles_editor_button->show();
+ editor_node->make_bottom_panel_item_visible(tiles_editor);
+ //get_tree()->connect_compat("idle_frame", tileset_editor, "_on_workspace_process");
+ } else {
+ editor_node->hide_bottom_panel();
+ tiles_editor_button->hide();
+ //get_tree()->disconnect_compat("idle_frame", tileset_editor, "_on_workspace_process");
+ }
+}
+
+void TilesEditorPlugin::edit(Object *p_object) {
+ tiles_editor->edit(p_object);
+}
+
+bool TilesEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("TileMap") || p_object->is_class("TileSet");
+}
+
+TilesEditorPlugin::TilesEditorPlugin(EditorNode *p_node) {
+ editor_node = p_node;
+
+ tiles_editor = memnew(TilesEditor(p_node));
+ tiles_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
+ tiles_editor->hide();
+
+ tiles_editor_button = p_node->add_bottom_panel_item(TTR("Tiles"), tiles_editor);
+ tiles_editor_button->hide();
+}
+
+TilesEditorPlugin::~TilesEditorPlugin() {
+}
diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h
new file mode 100644
index 0000000000..6cc6f51598
--- /dev/null
+++ b/editor/plugins/tiles/tiles_editor_plugin.h
@@ -0,0 +1,114 @@
+/*************************************************************************/
+/* tiles_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TILES_EDITOR_PLUGIN_H
+#define TILES_EDITOR_PLUGIN_H
+
+#include "editor/editor_plugin.h"
+#include "scene/gui/box_container.h"
+
+#include "tile_atlas_view.h"
+#include "tile_map_editor.h"
+#include "tile_set_editor.h"
+
+class TilesEditor : public VBoxContainer {
+ GDCLASS(TilesEditor, VBoxContainer);
+
+ static TilesEditor *singleton;
+
+private:
+ bool tile_map_changed_needs_update = false;
+ ObjectID tile_map_id;
+ Ref<TileSet> tile_set;
+
+ Button *tileset_tilemap_switch_button;
+
+ Control *tilemap_toolbar;
+ TileMapEditor *tilemap_editor;
+
+ TileSetEditor *tileset_editor;
+
+ void _update_switch_button();
+ void _update_editors();
+
+ // For synchronization.
+ int atlas_sources_lists_current = 0;
+ float atlas_view_zoom = 1.0;
+ Vector2 atlas_view_scroll = Vector2();
+
+ void _tile_map_changed();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ _FORCE_INLINE_ static TilesEditor *get_singleton() { return singleton; }
+
+ bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return tilemap_editor->forward_canvas_gui_input(p_event); }
+ void forward_canvas_draw_over_viewport(Control *p_overlay) { tilemap_editor->forward_canvas_draw_over_viewport(p_overlay); }
+
+ // To synchronize the atlas sources lists.
+ void set_atlas_sources_lists_current(int p_current);
+ void synchronize_atlas_sources_list(Object *p_current);
+
+ void set_atlas_view_transform(float p_zoom, Vector2 p_scroll);
+ void synchronize_atlas_view(Object *p_current);
+
+ void edit(Object *p_object);
+
+ TilesEditor(EditorNode *p_editor);
+ ~TilesEditor();
+};
+
+class TilesEditorPlugin : public EditorPlugin {
+ GDCLASS(TilesEditorPlugin, EditorPlugin);
+
+private:
+ EditorNode *editor_node;
+ TilesEditor *tiles_editor;
+ Button *tiles_editor_button;
+
+protected:
+ void _notification(int p_what);
+
+public:
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return tiles_editor->forward_canvas_gui_input(p_event); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { tiles_editor->forward_canvas_draw_over_viewport(p_overlay); }
+
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
+ virtual void make_visible(bool p_visible) override;
+
+ TilesEditorPlugin(EditorNode *p_node);
+ ~TilesEditorPlugin();
+};
+
+#endif // TILES_EDITOR_PLUGIN_H
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index 0af3b936cb..75a944e910 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -180,7 +180,7 @@ void VersionControlEditorPlugin::_stage_selected() {
staged_files_count = 0;
TreeItem *root = stage_files->get_root();
if (root) {
- TreeItem *file_entry = root->get_children();
+ TreeItem *file_entry = root->get_first_child();
while (file_entry) {
if (file_entry->is_checked(0)) {
EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
@@ -207,7 +207,7 @@ void VersionControlEditorPlugin::_stage_all() {
staged_files_count = 0;
TreeItem *root = stage_files->get_root();
if (root) {
- TreeItem *file_entry = root->get_children();
+ TreeItem *file_entry = root->get_first_child();
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_theme_color("success_color", "Editor"));
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index dea85e8799..e393f960bd 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -44,6 +44,7 @@
#include "scene/gui/panel.h"
#include "scene/main/window.h"
#include "scene/resources/visual_shader_nodes.h"
+#include "scene/resources/visual_shader_particle_nodes.h"
#include "scene/resources/visual_shader_sdf_nodes.h"
#include "servers/display_server.h"
#include "servers/rendering/shader_types.h"
@@ -71,13 +72,13 @@ const int MAX_FLOAT_CONST_DEFS = sizeof(float_constant_defs) / sizeof(FloatConst
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 get_script_instance()->call("_create_editor", p_parent_resource, p_node);
}
return nullptr;
}
void VisualShaderNodePlugin::_bind_methods() {
- BIND_VMETHOD(MethodInfo(Variant::OBJECT, "create_editor", PropertyInfo(Variant::OBJECT, "parent_resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::OBJECT, "for_node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode")));
+ BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_create_editor", PropertyInfo(Variant::OBJECT, "parent_resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::OBJECT, "for_node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode")));
}
///////////////////
@@ -322,6 +323,12 @@ void VisualShaderGraphPlugin::register_uniform_name(int p_node_id, LineEdit *p_u
links[p_node_id].uniform_name = p_uniform_name;
}
+void VisualShaderGraphPlugin::update_theme() {
+ vector_expanded_color[0] = VisualShaderEditor::get_singleton()->get_theme_color("axis_x_color", "Editor"); // red
+ vector_expanded_color[1] = VisualShaderEditor::get_singleton()->get_theme_color("axis_y_color", "Editor"); // green
+ vector_expanded_color[2] = VisualShaderEditor::get_singleton()->get_theme_color("axis_z_color", "Editor"); // blue
+}
+
void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
if (p_type != visual_shader->get_shader_type()) {
return;
@@ -340,6 +347,12 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
Color(1.0, 1.0, 0.0), // sampler
};
+ static const String vector_expanded_name[3] = {
+ "red",
+ "green",
+ "blue"
+ };
+
Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id);
Ref<VisualShaderNodeResizableBase> resizable_node = Object::cast_to<VisualShaderNodeResizableBase>(vsnode.ptr());
@@ -349,10 +362,17 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
Ref<VisualShaderNodeGroupBase> group_node = Object::cast_to<VisualShaderNodeGroupBase>(vsnode.ptr());
bool is_group = !group_node.is_null();
+ bool is_comment = false;
+
Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(group_node.ptr());
bool is_expression = !expression_node.is_null();
String expression = "";
+ VisualShaderNodeCustom *custom_node = Object::cast_to<VisualShaderNodeCustom>(vsnode.ptr());
+ if (custom_node) {
+ custom_node->_set_initialized(true);
+ }
+
GraphNode *node = memnew(GraphNode);
register_link(p_type, p_id, vsnode.ptr(), node);
@@ -387,17 +407,22 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
if (is_resizable) {
Ref<VisualShaderNodeComment> comment_node = Object::cast_to<VisualShaderNodeComment>(vsnode.ptr());
if (comment_node.is_valid()) {
+ is_comment = true;
node->set_comment(true);
Label *comment_label = memnew(Label);
node->add_child(comment_label);
comment_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
comment_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- comment_label->set_mouse_filter(Control::MouseFilter::MOUSE_FILTER_STOP);
comment_label->set_text(comment_node->get_description());
}
}
+ Ref<VisualShaderNodeParticleEmit> emit = vsnode;
+ if (emit.is_valid()) {
+ node->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
+ }
+
Ref<VisualShaderNodeUniform> uniform = vsnode;
if (uniform.is_valid()) {
VisualShaderEditor::get_singleton()->graph->add_child(node);
@@ -407,7 +432,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
register_uniform_name(p_id, uniform_name);
uniform_name->set_text(uniform->get_uniform_name());
node->add_child(uniform_name);
- uniform_name->connect("text_entered", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_uniform_line_edit_changed), varray(p_id));
+ uniform_name->connect("text_submitted", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_uniform_line_edit_changed), varray(p_id));
uniform_name->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_uniform_line_edit_focus_out), varray(uniform_name, p_id));
if (vsnode->get_input_port_count() == 0 && vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") {
@@ -546,13 +571,32 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
}
}
- for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) {
+ int output_port_count = 0;
+ for (int i = 0; i < vsnode->get_output_port_count(); i++) {
+ if (vsnode->_is_output_port_expanded(i)) {
+ if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) {
+ output_port_count += 3;
+ }
+ }
+ output_port_count++;
+ }
+ int max_ports = MAX(vsnode->get_input_port_count(), output_port_count);
+ VisualShaderNode::PortType expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;
+ int expanded_port_counter = 0;
+
+ for (int i = 0, j = 0; i < max_ports; i++, j++) {
+ if (expanded_type == VisualShaderNode::PORT_TYPE_VECTOR && expanded_port_counter >= 3) {
+ expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;
+ expanded_port_counter = 0;
+ i -= 3;
+ }
+
if (vsnode->is_port_separator(i)) {
node->add_child(memnew(HSeparator));
port_offset++;
}
- bool valid_left = i < vsnode->get_input_port_count();
+ bool valid_left = j < vsnode->get_input_port_count();
VisualShaderNode::PortType port_left = VisualShaderNode::PORT_TYPE_SCALAR;
bool port_left_used = false;
String name_left;
@@ -560,18 +604,24 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
name_left = vsnode->get_input_port_name(i);
port_left = vsnode->get_input_port_type(i);
for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) {
- if (E->get().to_node == p_id && E->get().to_port == i) {
+ if (E->get().to_node == p_id && E->get().to_port == j) {
port_left_used = true;
}
}
}
- bool valid_right = i < vsnode->get_output_port_count();
+ bool valid_right = true;
VisualShaderNode::PortType port_right = VisualShaderNode::PORT_TYPE_SCALAR;
String name_right;
- if (valid_right) {
- name_right = vsnode->get_output_port_name(i);
- port_right = vsnode->get_output_port_type(i);
+
+ if (expanded_type == VisualShaderNode::PORT_TYPE_SCALAR) {
+ valid_right = i < vsnode->get_output_port_count();
+ if (valid_right) {
+ name_right = vsnode->get_output_port_name(i);
+ port_right = vsnode->get_output_port_type(i);
+ }
+ } else {
+ name_right = vector_expanded_name[expanded_port_counter++];
}
HBoxContainer *hb = memnew(HBoxContainer);
@@ -616,7 +666,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0));
name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
name_box->set_text(name_left);
- name_box->connect("text_entered", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_input_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED);
+ name_box->connect("text_submitted", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_input_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED);
name_box->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_port_name_focus_out), varray(name_box, p_id, i, false), CONNECT_DEFERRED);
Button *remove_btn = memnew(Button);
@@ -657,7 +707,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0));
name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
name_box->set_text(name_right);
- name_box->connect("text_entered", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_output_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED);
+ name_box->connect("text_submitted", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_output_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED);
name_box->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_port_name_focus_out), varray(name_box, p_id, i, true), CONNECT_DEFERRED);
OptionButton *type_box = memnew(OptionButton);
@@ -679,17 +729,29 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
}
}
- if (valid_right && visual_shader->get_shader_type() == 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(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityHidden", "EditorIcons"));
- preview->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityVisible", "EditorIcons"));
- preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
+ if (valid_right) {
+ if (vsnode->is_output_port_expandable(i)) {
+ TextureButton *expand = memnew(TextureButton);
+ expand->set_toggle_mode(true);
+ expand->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiTreeArrowDown", "EditorIcons"));
+ expand->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiTreeArrowRight", "EditorIcons"));
+ expand->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
+ expand->set_pressed(vsnode->_is_output_port_expanded(i));
+ expand->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_expand_output_port), varray(p_id, i, !vsnode->_is_output_port_expanded(i)), CONNECT_DEFERRED);
+ hb->add_child(expand);
+ }
+ if (visual_shader->get_shader_type() == 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(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityHidden", "EditorIcons"));
+ preview->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityVisible", "EditorIcons"));
+ preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
- register_output_port(p_id, i, preview);
+ register_output_port(p_id, j, preview);
- preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, i), CONNECT_DEFERRED);
- hb->add_child(preview);
+ preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, j), CONNECT_DEFERRED);
+ hb->add_child(preview);
+ }
}
if (is_group) {
@@ -701,7 +763,40 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
node->add_child(hb);
+ if (expanded_type != VisualShaderNode::PORT_TYPE_SCALAR) {
+ continue;
+ }
+
node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]);
+
+ if (vsnode->_is_output_port_expanded(i)) {
+ if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) {
+ port_offset++;
+ valid_left = (i + 1) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 1);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);
+ port_offset++;
+
+ valid_left = (i + 2) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 2);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);
+ port_offset++;
+
+ valid_left = (i + 3) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 3);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]);
+ expanded_type = VisualShaderNode::PORT_TYPE_VECTOR;
+ }
+ }
}
if (vsnode->get_output_port_for_preview() >= 0) {
@@ -724,13 +819,14 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
CodeEdit *expression_box = memnew(CodeEdit);
Ref<CodeHighlighter> expression_syntax_highlighter;
expression_syntax_highlighter.instance();
- expression_node->set_control(expression_box, 0);
+ expression_node->set_ctrl_pressed(expression_box, 0);
node->add_child(expression_box);
register_expression_edit(p_id, expression_box);
Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
Color function_color = EDITOR_GET("text_editor/highlighting/function_color");
@@ -741,7 +837,11 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
expression_box->add_theme_color_override("background_color", background_color);
for (List<String>::Element *E = VisualShaderEditor::get_singleton()->keyword_list.front(); E; E = E->next()) {
- expression_syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ if (ShaderLanguage::is_control_flow_keyword(E->get())) {
+ expression_syntax_highlighter->add_keyword_color(E->get(), control_flow_keyword_color);
+ } else {
+ expression_syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ }
}
expression_box->add_theme_font_override("font", VisualShaderEditor::get_singleton()->get_theme_font("expression", "EditorFonts"));
@@ -754,6 +854,10 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
expression_syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
expression_syntax_highlighter->add_color_region("//", "", comment_color, true);
+ expression_box->clear_comment_delimiters();
+ expression_box->add_comment_delimiter("/*", "*/", false);
+ expression_box->add_comment_delimiter("//", "", true);
+
expression_box->set_text(expression);
expression_box->set_context_menu_enabled(false);
expression_box->set_draw_line_numbers(true);
@@ -763,6 +867,9 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
if (!uniform.is_valid()) {
VisualShaderEditor::get_singleton()->graph->add_child(node);
+ if (is_comment) {
+ VisualShaderEditor::get_singleton()->graph->move_child(node, 0); // to prevents a bug where comment node overlaps its content
+ }
VisualShaderEditor::get_singleton()->_update_created_node(node);
if (is_resizable) {
VisualShaderEditor::get_singleton()->call_deferred("_set_node_size", (int)p_type, p_id, size);
@@ -912,13 +1019,13 @@ bool VisualShaderEditor::_is_available(int p_mode) {
if (p_mode != -1) {
switch (current_mode) {
- case 0: // Vertex or Emit
+ case 0: // Vertex / Emit
current_mode = 1;
break;
- case 1: // Fragment or Process
+ case 1: // Fragment / Process
current_mode = 2;
break;
- case 2: // Light or End
+ case 2: // Light / Collide
current_mode = 4;
break;
default:
@@ -1120,7 +1227,7 @@ void VisualShaderEditor::_update_options_menu() {
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_theme_icon("Transform", "EditorIcons"));
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform3D", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_SAMPLER:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"));
@@ -1134,22 +1241,29 @@ void VisualShaderEditor::_update_options_menu() {
void VisualShaderEditor::_set_mode(int p_which) {
if (p_which == VisualShader::MODE_SKY) {
- edit_type_standart->set_visible(false);
+ edit_type_standard->set_visible(false);
edit_type_particles->set_visible(false);
edit_type_sky->set_visible(true);
edit_type = edit_type_sky;
+ custom_mode_box->set_visible(false);
mode = MODE_FLAGS_SKY;
} else if (p_which == VisualShader::MODE_PARTICLES) {
- edit_type_standart->set_visible(false);
+ edit_type_standard->set_visible(false);
edit_type_particles->set_visible(true);
edit_type_sky->set_visible(false);
edit_type = edit_type_particles;
+ if ((edit_type->get_selected() + 3) > VisualShader::TYPE_PROCESS) {
+ custom_mode_box->set_visible(false);
+ } else {
+ custom_mode_box->set_visible(true);
+ }
mode = MODE_FLAGS_PARTICLES;
} else {
edit_type_particles->set_visible(false);
- edit_type_standart->set_visible(true);
+ edit_type_standard->set_visible(true);
edit_type_sky->set_visible(false);
- edit_type = edit_type_standart;
+ edit_type = edit_type_standard;
+ custom_mode_box->set_visible(false);
mode = MODE_FLAGS_SPATIAL_CANVASITEM;
}
visual_shader->set_shader_type(get_current_shader_type());
@@ -1170,26 +1284,15 @@ void VisualShaderEditor::_draw_color_over_button(Object *obj, Color p_color) {
}
void VisualShaderEditor::_update_created_node(GraphNode *node) {
- if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
- Ref<StyleBoxFlat> sb = node->get_theme_stylebox("frame", "GraphNode");
- Color c = sb->get_border_color();
- Color ic;
- Color mono_color;
- if (((c.r + c.g + c.b) / 3) < 0.7) {
- mono_color = Color(1.0, 1.0, 1.0);
- ic = Color(0.0, 0.0, 0.0, 0.7);
- } else {
- mono_color = Color(0.0, 0.0, 0.0);
- ic = Color(1.0, 1.0, 1.0, 0.7);
- }
- mono_color.a = 0.85;
- c = mono_color;
+ const Ref<StyleBoxFlat> sb = node->get_theme_stylebox("frame", "GraphNode");
+ Color c = sb->get_border_color();
+ const Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0, 0.85) : Color(0.0, 0.0, 0.0, 0.85);
+ c = mono_color;
- node->add_theme_color_override("title_color", c);
- c.a = 0.7;
- node->add_theme_color_override("close_color", c);
- node->add_theme_color_override("resizer_color", ic);
- }
+ node->add_theme_color_override("title_color", c);
+ c.a = 0.7;
+ node->add_theme_color_override("close_color", c);
+ node->add_theme_color_override("resizer_color", c);
}
void VisualShaderEditor::_update_uniforms(bool p_update_refs) {
@@ -1289,6 +1392,7 @@ void VisualShaderEditor::_update_graph() {
graph_plugin->clear_links();
graph_plugin->make_dirty(true);
+ graph_plugin->update_theme();
for (int n_i = 0; n_i < nodes.size(); n_i++) {
graph_plugin->add_node(type, nodes[n_i]);
@@ -1312,9 +1416,9 @@ void VisualShaderEditor::_update_graph() {
VisualShader::Type VisualShaderEditor::get_current_shader_type() const {
VisualShader::Type type;
if (mode & MODE_FLAGS_PARTICLES) {
- type = VisualShader::Type(edit_type->get_selected() + 3);
+ type = VisualShader::Type(edit_type->get_selected() + 3 + (custom_mode_enabled ? 3 : 0));
} else if (mode & MODE_FLAGS_SKY) {
- type = VisualShader::Type(edit_type->get_selected() + 6);
+ type = VisualShader::Type(edit_type->get_selected() + 8);
} else {
type = VisualShader::Type(edit_type->get_selected());
}
@@ -1437,6 +1541,92 @@ void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *
undo_redo->commit_action();
}
+void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expand) {
+ VisualShader::Type type = get_current_shader_type();
+
+ Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);
+ ERR_FAIL_COND(!node.is_valid());
+
+ if (p_expand) {
+ undo_redo->create_action(TTR("Expand Output Port"));
+ } else {
+ undo_redo->create_action(TTR("Shrink Output Port"));
+ }
+
+ undo_redo->add_do_method(node.ptr(), "_set_output_port_expanded", p_port, p_expand);
+ undo_redo->add_undo_method(node.ptr(), "_set_output_port_expanded", p_port, !p_expand);
+
+ int type_size = 0;
+ if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_VECTOR) {
+ type_size = 3;
+ }
+
+ List<VisualShader::Connection> conns;
+ visual_shader->get_node_connections(type, &conns);
+
+ for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) {
+ int from_node = E->get().from_node;
+ int from_port = E->get().from_port;
+ int to_node = E->get().to_node;
+ int to_port = E->get().to_port;
+
+ if (from_node == p_node) {
+ if (p_expand) {
+ if (from_port > p_port) { // reconnect ports after expanded ports
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
+
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port + type_size, to_node, to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port + type_size, to_node, to_port);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port + type_size, to_node, to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port + type_size, to_node, to_port);
+ }
+ } else {
+ if (from_port > p_port + type_size) { // reconnect ports after expanded ports
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
+
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_port - type_size, to_node, to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port - type_size, to_node, to_port);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port - type_size, to_node, to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port - type_size, to_node, to_port);
+ } else if (from_port > p_port) { // disconnect component ports
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
+ }
+ }
+ }
+ }
+
+ int preview_port = node->get_output_port_for_preview();
+ if (p_expand) {
+ if (preview_port > p_port) {
+ undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port + type_size);
+ undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);
+ }
+ } else {
+ if (preview_port > p_port + type_size) {
+ undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port - type_size);
+ undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);
+ }
+ }
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);
+ undo_redo->commit_action();
+}
+
void VisualShaderEditor::_remove_input_port(int p_node, int p_port) {
VisualShader::Type type = get_current_shader_type();
Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
@@ -1585,7 +1775,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p
Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(node.ptr());
Control *text_box = nullptr;
if (!expression_node.is_null()) {
- text_box = expression_node->get_control(0);
+ text_box = expression_node->is_ctrl_pressed(0);
if (text_box) {
text_box->set_custom_minimum_size(Size2(0, 0));
}
@@ -1665,7 +1855,7 @@ void VisualShaderEditor::_comment_title_text_changed(const String &p_new_text) {
comment_title_change_popup->set_size(Size2(-1, -1));
}
-void VisualShaderEditor::_comment_title_text_entered(const String &p_new_text) {
+void VisualShaderEditor::_comment_title_text_submitted(const String &p_new_text) {
comment_title_change_popup->hide();
}
@@ -1782,8 +1972,15 @@ void VisualShaderEditor::_port_edited() {
ERR_FAIL_COND(!vsn.is_valid());
undo_redo->create_action(TTR("Set Input Default Port"));
- undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, value);
- undo_redo->add_undo_method(vsn.ptr(), "set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
+
+ Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(vsn.ptr());
+ if (custom.is_valid()) {
+ undo_redo->add_do_method(custom.ptr(), "_set_input_port_default_value", editing_port, value);
+ undo_redo->add_undo_method(custom.ptr(), "_set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
+ } else {
+ undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, value);
+ undo_redo->add_undo_method(vsn.ptr(), "set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
+ }
undo_redo->add_do_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, value);
undo_redo->add_undo_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, vsn->get_input_port_default_value(editing_port));
undo_redo->commit_action();
@@ -1806,47 +2003,6 @@ void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node,
editing_port = p_port;
}
-void VisualShaderEditor::_add_custom_node(const String &p_path) {
- int idx = -1;
-
- for (int i = custom_node_option_idx; i < add_options.size(); i++) {
- if (add_options[i].script.is_valid()) {
- if (add_options[i].script->get_path() == p_path) {
- idx = i;
- break;
- }
- }
- }
- if (idx != -1) {
- _add_node(idx);
- }
-}
-
-void VisualShaderEditor::_add_cubemap_node(const String &p_path) {
- VisualShaderNodeCubemap *cubemap = (VisualShaderNodeCubemap *)_add_node(cubemap_node_option_idx, -1);
- cubemap->set_cube_map(ResourceLoader::load(p_path));
-}
-
-void VisualShaderEditor::_add_texture2d_node(const String &p_path) {
- VisualShaderNodeTexture *texture2d = (VisualShaderNodeTexture *)_add_node(texture2d_node_option_idx, -1);
- texture2d->set_texture(ResourceLoader::load(p_path));
-}
-
-void VisualShaderEditor::_add_texture2d_array_node(const String &p_path) {
- VisualShaderNodeTexture2DArray *texture2d_array = (VisualShaderNodeTexture2DArray *)_add_node(texture2d_array_node_option_idx, -1);
- texture2d_array->set_texture_array(ResourceLoader::load(p_path));
-}
-
-void VisualShaderEditor::_add_texture3d_node(const String &p_path) {
- VisualShaderNodeTexture3D *texture3d = (VisualShaderNodeTexture3D *)_add_node(texture3d_node_option_idx, -1);
- texture3d->set_texture(ResourceLoader::load(p_path));
-}
-
-void VisualShaderEditor::_add_curve_node(const String &p_path) {
- VisualShaderNodeCurveTexture *curve = (VisualShaderNodeCurveTexture *)_add_node(curve_node_option_idx, -1);
- curve->set_texture(ResourceLoader::load(p_path));
-}
-
void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
// FLOAT_OP
{
@@ -1938,6 +2094,16 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
}
}
+ //UV_FUNC
+ {
+ VisualShaderNodeUVFunc *uvFunc = Object::cast_to<VisualShaderNodeUVFunc>(p_node);
+
+ if (uvFunc) {
+ uvFunc->set_function((VisualShaderNodeUVFunc::Function)p_op_idx);
+ return;
+ }
+ }
+
// IS
{
VisualShaderNodeIs *is = Object::cast_to<VisualShaderNodeIs>(p_node);
@@ -2035,8 +2201,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
}
}
-VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
- ERR_FAIL_INDEX_V(p_idx, add_options.size(), nullptr);
+void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_path, int p_node_idx) {
+ ERR_FAIL_INDEX(p_idx, add_options.size());
Ref<VisualShaderNode> vsnode;
@@ -2044,7 +2210,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, nullptr);
+ ERR_FAIL_COND(!vsn);
VisualShaderNodeFloatConstant *constant = Object::cast_to<VisualShaderNodeFloatConstant>(vsn);
@@ -2066,10 +2232,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(), nullptr);
+ ERR_FAIL_COND(add_options[p_idx].script.is_null());
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, nullptr);
+ ERR_FAIL_COND(!vsn);
vsnode = Ref<VisualShaderNode>(vsn);
vsnode->set_script(add_options[p_idx].script);
}
@@ -2088,7 +2254,11 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
int id_to_use = visual_shader->get_valid_node_id(type);
- undo_redo->create_action(TTR("Add Node to Visual Shader"));
+ if (p_resource_path.is_empty()) {
+ undo_redo->create_action(TTR("Add Node to Visual Shader"));
+ } else {
+ id_to_use += p_node_idx;
+ }
undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, vsnode, position, id_to_use);
undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_to_use);
undo_redo->add_do_method(graph_plugin.ptr(), "add_node", type, id_to_use);
@@ -2203,8 +2373,30 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
graph_plugin->call_deferred("update_curve", id_to_use);
}
- undo_redo->commit_action();
- return vsnode.ptr();
+ if (p_resource_path.is_empty()) {
+ undo_redo->commit_action();
+ } else {
+ //post-initialization
+
+ VisualShaderNodeTexture *texture2d = Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr());
+ VisualShaderNodeTexture3D *texture3d = Object::cast_to<VisualShaderNodeTexture3D>(vsnode.ptr());
+
+ if (texture2d || texture3d || curve) {
+ undo_redo->add_do_method(vsnode.ptr(), "set_texture", ResourceLoader::load(p_resource_path));
+ return;
+ }
+
+ VisualShaderNodeCubemap *cubemap = Object::cast_to<VisualShaderNodeCubemap>(vsnode.ptr());
+ if (cubemap) {
+ undo_redo->add_do_method(vsnode.ptr(), "set_cube_map", ResourceLoader::load(p_resource_path));
+ return;
+ }
+
+ VisualShaderNodeTexture2DArray *texture2d_array = Object::cast_to<VisualShaderNodeTexture2DArray>(vsnode.ptr());
+ if (texture2d_array) {
+ undo_redo->add_do_method(vsnode.ptr(), "set_texture_array", ResourceLoader::load(p_resource_path));
+ }
+ }
}
void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node) {
@@ -2421,7 +2613,7 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
for (Set<int>::Element *E = current_set.front(); E; E = E->next()) {
int node_id = E->get();
Ref<VisualShaderNode> node = visual_shader->get_node(type_id, node_id);
- bool catched = false;
+ bool caught = false;
Variant var;
// float
@@ -2430,112 +2622,112 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (float_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatUniform");
var = float_const->get_constant();
- catched = true;
+ caught = true;
}
} else {
Ref<VisualShaderNodeFloatUniform> float_uniform = Object::cast_to<VisualShaderNodeFloatUniform>(node.ptr());
if (float_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeFloatUniform", "VisualShaderNodeFloatConstant");
var = float_uniform->get_default_value();
- catched = true;
+ caught = true;
}
}
// int
- if (!catched) {
+ if (!caught) {
if (!p_vice_versa) {
Ref<VisualShaderNodeIntConstant> int_const = Object::cast_to<VisualShaderNodeIntConstant>(node.ptr());
if (int_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntUniform");
var = int_const->get_constant();
- catched = true;
+ caught = true;
}
} else {
Ref<VisualShaderNodeIntUniform> int_uniform = Object::cast_to<VisualShaderNodeIntUniform>(node.ptr());
if (int_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeIntUniform", "VisualShaderNodeIntConstant");
var = int_uniform->get_default_value();
- catched = true;
+ caught = true;
}
}
}
// boolean
- if (!catched) {
+ if (!caught) {
if (!p_vice_versa) {
Ref<VisualShaderNodeBooleanConstant> boolean_const = Object::cast_to<VisualShaderNodeBooleanConstant>(node.ptr());
if (boolean_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanUniform");
var = boolean_const->get_constant();
- catched = true;
+ caught = true;
}
} else {
Ref<VisualShaderNodeBooleanUniform> boolean_uniform = Object::cast_to<VisualShaderNodeBooleanUniform>(node.ptr());
if (boolean_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeBooleanUniform", "VisualShaderNodeBooleanConstant");
var = boolean_uniform->get_default_value();
- catched = true;
+ caught = true;
}
}
}
// vec3
- if (!catched) {
+ if (!caught) {
if (!p_vice_versa) {
Ref<VisualShaderNodeVec3Constant> vec3_const = Object::cast_to<VisualShaderNodeVec3Constant>(node.ptr());
if (vec3_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Uniform");
var = vec3_const->get_constant();
- catched = true;
+ caught = true;
}
} else {
Ref<VisualShaderNodeVec3Uniform> vec3_uniform = Object::cast_to<VisualShaderNodeVec3Uniform>(node.ptr());
if (vec3_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeVec3Uniform", "VisualShaderNodeVec3Constant");
var = vec3_uniform->get_default_value();
- catched = true;
+ caught = true;
}
}
}
// color
- if (!catched) {
+ if (!caught) {
if (!p_vice_versa) {
Ref<VisualShaderNodeColorConstant> color_const = Object::cast_to<VisualShaderNodeColorConstant>(node.ptr());
if (color_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorUniform");
var = color_const->get_constant();
- catched = true;
+ caught = true;
}
} else {
Ref<VisualShaderNodeColorUniform> color_uniform = Object::cast_to<VisualShaderNodeColorUniform>(node.ptr());
if (color_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeColorUniform", "VisualShaderNodeColorConstant");
var = color_uniform->get_default_value();
- catched = true;
+ caught = true;
}
}
}
// transform
- if (!catched) {
+ if (!caught) {
if (!p_vice_versa) {
Ref<VisualShaderNodeTransformConstant> transform_const = Object::cast_to<VisualShaderNodeTransformConstant>(node.ptr());
if (transform_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformUniform");
var = transform_const->get_constant();
- catched = true;
+ caught = true;
}
} else {
Ref<VisualShaderNodeTransformUniform> transform_uniform = Object::cast_to<VisualShaderNodeTransformUniform>(node.ptr());
if (transform_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeTransformUniform", "VisualShaderNodeTransformConstant");
var = transform_uniform->get_default_value();
- catched = true;
+ caught = true;
}
}
}
- ERR_CONTINUE(!catched);
+ ERR_CONTINUE(!caught);
int preview_port = node->get_output_port_for_preview();
if (!p_vice_versa) {
@@ -2756,10 +2948,10 @@ void VisualShaderEditor::_notification(int p_what) {
// collapse tree by default
- TreeItem *category = members->get_root()->get_children();
+ TreeItem *category = members->get_root()->get_first_child();
while (category) {
category->set_collapsed(true);
- TreeItem *sub_category = category->get_children();
+ TreeItem *sub_category = category->get_first_child();
while (sub_category) {
sub_category->set_collapsed(true);
sub_category = sub_category->get_next();
@@ -2780,9 +2972,6 @@ void VisualShaderEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
highend_label->set_modulate(get_theme_color("vulkan_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_theme_icon("Search", "EditorIcons"));
preview_shader->set_icon(Control::get_theme_icon("Shader", "EditorIcons"));
@@ -2791,6 +2980,7 @@ void VisualShaderEditor::_notification(int p_what) {
Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
Color function_color = EDITOR_GET("text_editor/highlighting/function_color");
@@ -2800,7 +2990,11 @@ void VisualShaderEditor::_notification(int p_what) {
preview_text->add_theme_color_override("background_color", background_color);
for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) {
- syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ if (ShaderLanguage::is_control_flow_keyword(E->get())) {
+ syntax_highlighter->add_keyword_color(E->get(), control_flow_keyword_color);
+ } else {
+ syntax_highlighter->add_keyword_color(E->get(), keyword_color);
+ }
}
preview_text->add_theme_font_override("font", get_theme_font("expression", "EditorFonts"));
@@ -2814,9 +3008,14 @@ void VisualShaderEditor::_notification(int p_what) {
syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
syntax_highlighter->add_color_region("//", "", comment_color, true);
- error_text->add_theme_font_override("font", get_theme_font("status_source", "EditorFonts"));
- error_text->add_theme_font_size_override("font_size", get_theme_font_size("status_source_size", "EditorFonts"));
- error_text->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
+ preview_text->clear_comment_delimiters();
+ preview_text->add_comment_delimiter("/*", "*/", false);
+ preview_text->add_comment_delimiter("//", "", true);
+
+ error_panel->add_theme_style_override("panel", get_theme_stylebox("panel", "Panel"));
+ error_label->add_theme_font_override("font", get_theme_font("status_source", "EditorFonts"));
+ error_label->add_theme_font_size_override("font_size", get_theme_font_size("status_source_size", "EditorFonts"));
+ error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
}
tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Tools", "EditorIcons"));
@@ -3038,8 +3237,18 @@ void VisualShaderEditor::_mode_selected(int p_id) {
int offset = 0;
if (mode & MODE_FLAGS_PARTICLES) {
offset = 3;
+ if (p_id + offset > VisualShader::TYPE_PROCESS) {
+ custom_mode_box->set_visible(false);
+ custom_mode_enabled = false;
+ } else {
+ custom_mode_box->set_visible(true);
+ if (custom_mode_box->is_pressed()) {
+ custom_mode_enabled = true;
+ offset += 3;
+ }
+ }
} else if (mode & MODE_FLAGS_SKY) {
- offset = 6;
+ offset = 8;
}
visual_shader->set_shader_type(VisualShader::Type(p_id + offset));
@@ -3047,6 +3256,21 @@ void VisualShaderEditor::_mode_selected(int p_id) {
_update_graph();
}
+void VisualShaderEditor::_custom_mode_toggled(bool p_enabled) {
+ if (!(mode & MODE_FLAGS_PARTICLES)) {
+ return;
+ }
+ custom_mode_enabled = p_enabled;
+ int id = edit_type->get_selected() + 3;
+ if (p_enabled) {
+ visual_shader->set_shader_type(VisualShader::Type(id + 3));
+ } else {
+ visual_shader->set_shader_type(VisualShader::Type(id));
+ }
+ _update_options_menu();
+ _update_graph();
+}
+
void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, String p_name) {
String prev_name = p_input->get_input_name();
@@ -3199,14 +3423,14 @@ void VisualShaderEditor::_member_cancel() {
}
void VisualShaderEditor::_tools_menu_option(int p_idx) {
- TreeItem *category = members->get_root()->get_children();
+ TreeItem *category = members->get_root()->get_first_child();
switch (p_idx) {
case EXPAND_ALL:
while (category) {
category->set_collapsed(false);
- TreeItem *sub_category = category->get_children();
+ TreeItem *sub_category = category->get_first_child();
while (sub_category) {
sub_category->set_collapsed(false);
sub_category = sub_category->get_next();
@@ -3220,7 +3444,7 @@ void VisualShaderEditor::_tools_menu_option(int p_idx) {
while (category) {
category->set_collapsed(true);
- TreeItem *sub_category = category->get_children();
+ TreeItem *sub_category = category->get_first_child();
while (sub_category) {
sub_category->set_collapsed(true);
sub_category = sub_category->get_next();
@@ -3322,47 +3546,56 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
saved_node_pos_dirty = true;
_add_node(idx, add_options[idx].sub_func);
} else if (d.has("files")) {
+ undo_redo->create_action(TTR("Add Node(s) to Visual Shader"));
+
if (d["files"].get_type() == Variant::PACKED_STRING_ARRAY) {
- int j = 0;
PackedStringArray arr = d["files"];
for (int i = 0; i < arr.size(); i++) {
String type = ResourceLoader::get_resource_type(arr[i]);
if (type == "GDScript") {
Ref<Script> script = ResourceLoader::load(arr[i]);
if (script->get_instance_base_type() == "VisualShaderNodeCustom") {
- saved_node_pos = p_point + Vector2(0, j * 210 * EDSCALE);
+ saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_custom_node(arr[i]);
- j++;
+
+ int idx = -1;
+
+ for (int j = custom_node_option_idx; j < add_options.size(); j++) {
+ if (add_options[j].script.is_valid()) {
+ if (add_options[j].script->get_path() == arr[i]) {
+ idx = j;
+ break;
+ }
+ }
+ }
+ if (idx != -1) {
+ _add_node(idx, -1, arr[i], i);
+ }
}
} else if (type == "CurveTexture") {
- saved_node_pos = p_point + Vector2(0, j * 210 * EDSCALE);
+ saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_curve_node(arr[i]);
- j++;
+ _add_node(curve_node_option_idx, -1, arr[i], i);
} else if (ClassDB::get_parent_class(type) == "Texture2D") {
- saved_node_pos = p_point + Vector2(0, j * 210 * EDSCALE);
+ saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_texture2d_node(arr[i]);
- j++;
+ _add_node(texture2d_node_option_idx, -1, arr[i], i);
} else if (type == "Texture2DArray") {
- saved_node_pos = p_point + Vector2(0, j * 210 * EDSCALE);
+ saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_texture2d_array_node(arr[i]);
- j++;
+ _add_node(texture2d_array_node_option_idx, -1, arr[i], i);
} else if (ClassDB::get_parent_class(type) == "Texture3D") {
- saved_node_pos = p_point + Vector2(0, j * 210 * EDSCALE);
+ saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_texture3d_node(arr[i]);
- j++;
+ _add_node(texture3d_node_option_idx, -1, arr[i], i);
} else if (type == "Cubemap") {
- saved_node_pos = p_point + Vector2(0, j * 210 * EDSCALE);
+ saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_cubemap_node(arr[i]);
- j++;
+ _add_node(cubemap_node_option_idx, -1, arr[i], i);
}
}
}
+ undo_redo->commit_action();
}
}
}
@@ -3418,17 +3651,18 @@ void VisualShaderEditor::_update_preview() {
Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
for (int i = 0; i < preview_text->get_line_count(); i++) {
- preview_text->set_line_as_marked(i, false);
+ preview_text->set_line_background_color(i, Color(0, 0, 0, 0));
}
if (err != OK) {
- preview_text->set_line_as_marked(sl.get_error_line() - 1, true);
- error_text->set_visible(true);
+ Color error_line_color = EDITOR_GET("text_editor/highlighting/mark_color");
+ preview_text->set_line_background_color(sl.get_error_line() - 1, error_line_color);
+ error_panel->show();
String text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text();
- error_text->set_text(text);
+ error_label->set_text(text);
shader_error = true;
} else {
- error_text->set_visible(false);
+ error_panel->hide();
shader_error = false;
}
}
@@ -3458,10 +3692,11 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_float_constant_selected", &VisualShaderEditor::_float_constant_selected);
ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant);
ClassDB::bind_method("_update_uniform", &VisualShaderEditor::_update_uniform);
+ ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &VisualShaderEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &VisualShaderEditor::drop_data_fw);
ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
}
@@ -3534,17 +3769,23 @@ VisualShaderEditor::VisualShaderEditor() {
graph->get_zoom_hbox()->add_child(vs);
graph->get_zoom_hbox()->move_child(vs, 0);
- edit_type_standart = memnew(OptionButton);
- edit_type_standart->add_item(TTR("Vertex"));
- edit_type_standart->add_item(TTR("Fragment"));
- edit_type_standart->add_item(TTR("Light"));
- edit_type_standart->select(1);
- edit_type_standart->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
+ custom_mode_box = memnew(CheckBox);
+ custom_mode_box->set_text(TTR("Custom"));
+ custom_mode_box->set_pressed(false);
+ custom_mode_box->set_visible(false);
+ custom_mode_box->connect("toggled", callable_mp(this, &VisualShaderEditor::_custom_mode_toggled));
+
+ edit_type_standard = memnew(OptionButton);
+ edit_type_standard->add_item(TTR("Vertex"));
+ edit_type_standard->add_item(TTR("Fragment"));
+ edit_type_standard->add_item(TTR("Light"));
+ edit_type_standard->select(1);
+ edit_type_standard->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
edit_type_particles = memnew(OptionButton);
- edit_type_particles->add_item(TTR("Emit"));
+ edit_type_particles->add_item(TTR("Start"));
edit_type_particles->add_item(TTR("Process"));
- edit_type_particles->add_item(TTR("End"));
+ edit_type_particles->add_item(TTR("Collide"));
edit_type_particles->select(0);
edit_type_particles->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
@@ -3553,14 +3794,16 @@ VisualShaderEditor::VisualShaderEditor() {
edit_type_sky->select(0);
edit_type_sky->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
- edit_type = edit_type_standart;
+ edit_type = edit_type_standard;
+ graph->get_zoom_hbox()->add_child(custom_mode_box);
+ graph->get_zoom_hbox()->move_child(custom_mode_box, 0);
+ graph->get_zoom_hbox()->add_child(edit_type_standard);
+ graph->get_zoom_hbox()->move_child(edit_type_standard, 0);
graph->get_zoom_hbox()->add_child(edit_type_particles);
graph->get_zoom_hbox()->move_child(edit_type_particles, 0);
graph->get_zoom_hbox()->add_child(edit_type_sky);
graph->get_zoom_hbox()->move_child(edit_type_sky, 0);
- graph->get_zoom_hbox()->add_child(edit_type_standart);
- graph->get_zoom_hbox()->move_child(edit_type_standart, 0);
add_node = memnew(Button);
add_node->set_flat(true);
@@ -3589,6 +3832,7 @@ VisualShaderEditor::VisualShaderEditor() {
preview_vbox = memnew(VBoxContainer);
preview_window->add_child(preview_vbox);
+ preview_vbox->add_theme_constant_override("separation", 0);
preview_text = memnew(CodeEdit);
syntax_highlighter.instance();
@@ -3598,10 +3842,13 @@ VisualShaderEditor::VisualShaderEditor() {
preview_text->set_draw_line_numbers(true);
preview_text->set_readonly(true);
- error_text = memnew(Label);
- preview_vbox->add_child(error_text);
- error_text->set_autowrap(true);
- error_text->set_visible(false);
+ error_panel = memnew(PanelContainer);
+ preview_vbox->add_child(error_panel);
+ error_panel->set_visible(false);
+
+ error_label = memnew(Label);
+ error_panel->add_child(error_label);
+ error_label->set_autowrap(true);
///////////////////////////////////////
// POPUP MENU
@@ -3697,7 +3944,7 @@ VisualShaderEditor::VisualShaderEditor() {
comment_title_change_edit = memnew(LineEdit);
comment_title_change_edit->set_expand_to_text_length_enabled(true);
comment_title_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_title_text_changed));
- comment_title_change_edit->connect("text_entered", callable_mp(this, &VisualShaderEditor::_comment_title_text_entered));
+ comment_title_change_edit->connect("text_submitted", callable_mp(this, &VisualShaderEditor::_comment_title_text_submitted));
comment_title_change_popup->add_child(comment_title_change_edit);
comment_title_change_edit->set_size(Size2(-1, -1));
comment_title_change_popup->set_size(Size2(-1, -1));
@@ -3776,9 +4023,10 @@ VisualShaderEditor::VisualShaderEditor() {
// INPUT
+ const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes.");
+
// SPATIAL-FOR-ALL
- const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes.");
add_options.push_back(AddOption("Camera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "camera"), "camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("InvCamera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_camera"), "inv_camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("InvProjection", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_projection"), "inv_projection", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
@@ -3797,6 +4045,23 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM));
+ // PARTICLES-FOR-ALL
+
+ add_options.push_back(AddOption("Active", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Alpha", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("AttractorForce", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "attractor_force"), "attractor_force", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Color", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Custom", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("CustomAlpha", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Delta", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("EmissionTransform", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Index", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("LifeTime", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Restart", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Transform", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Velocity", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES));
+
/////////////////
add_options.push_back(AddOption("Input", "Input", "Common", "VisualShaderNodeInput", TTR("Input parameter.")));
@@ -3809,11 +4074,12 @@ VisualShaderEditor::VisualShaderEditor() {
const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode.");
const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.");
const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.");
- const String input_param_for_emit_shader_mode = TTR("'%s' input parameter for emit shader mode.");
+ const String input_param_for_start_shader_mode = TTR("'%s' input parameter for start shader mode.");
const String input_param_for_process_shader_mode = TTR("'%s' input parameter for process shader mode.");
- const String input_param_for_end_shader_mode = TTR("'%s' input parameter for end shader mode.");
- const String input_param_for_emit_and_process_shader_mode = TTR("'%s' input parameter for emit and process shader mode.");
- const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader mode.");
+ const String input_param_for_collide_shader_mode = TTR("'%s' input parameter for collide shader mode.");
+ const String input_param_for_start_and_process_shader_mode = TTR("'%s' input parameter for start and process shader modes.");
+ const String input_param_for_process_and_collide_shader_mode = TTR("'%s' input parameter for process and collide shader modes.");
+ const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader modes.");
add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
@@ -3890,50 +4156,6 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- // PARTICLES INPUTS
-
- add_options.push_back(AddOption("Active", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Alpha", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Color", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Custom", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("CustomAlpha", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Delta", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("EmissionTransform", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Index", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("LifeTime", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Restart", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Time", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Transform", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Velocity", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
-
- add_options.push_back(AddOption("Active", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Alpha", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Color", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Custom", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("CustomAlpha", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Delta", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("EmissionTransform", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Index", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("LifeTime", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Restart", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Time", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Transform", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Velocity", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
-
- add_options.push_back(AddOption("Active", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Alpha", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Color", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Custom", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("CustomAlpha", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Delta", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("EmissionTransform", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Index", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("LifeTime", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Restart", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Time", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Transform", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Velocity", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_END, Shader::MODE_PARTICLES));
-
// SKY INPUTS
add_options.push_back(AddOption("AtCubeMapPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
@@ -3966,6 +4188,22 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("SkyCoords", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
add_options.push_back(AddOption("Time", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ // PARTICLES
+
+ add_options.push_back(AddOption("CollisionDepth", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_depth"), "collision_depth", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("CollisionNormal", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_normal"), "collision_normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
+
+ add_options.push_back(AddOption("EmitParticle", "Particles", "", "VisualShaderNodeParticleEmit", "", -1, -1, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("ParticleAccelerator", "Particles", "", "VisualShaderNodeParticleAccelerator", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("ParticleRandomness", "Particles", "", "VisualShaderNodeParticleRandomness", "", -1, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("MultiplyByAxisAngle", "Particles", "Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", "A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters.", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
+
+ add_options.push_back(AddOption("BoxEmitter", "Particles", "Emitters", "VisualShaderNodeParticleBoxEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("RingEmitter", "Particles", "Emitters", "VisualShaderNodeParticleRingEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("SphereEmitter", "Particles", "Emitters", "VisualShaderNodeParticleSphereEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
+
+ add_options.push_back(AddOption("ConeVelocity", "Particles", "Velocity", "VisualShaderNodeParticleConeVelocity", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
+
// SCALAR
add_options.push_back(AddOption("FloatFunc", "Scalar", "Common", "VisualShaderNodeFloatFunc", TTR("Float function."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
@@ -4053,6 +4291,8 @@ VisualShaderEditor::VisualShaderEditor() {
// TEXTURES
+ add_options.push_back(AddOption("UVFunc", "Textures", "Common", "VisualShaderNodeUVFunc", TTR("Function to be applied on texture coordinates."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+
cubemap_node_option_idx = add_options.size();
add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), -1, -1));
curve_node_option_idx = add_options.size();
@@ -4063,6 +4303,8 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Texture2DArray", "Textures", "Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), -1, -1, -1, -1, -1));
texture3d_node_option_idx = add_options.size();
add_options.push_back(AddOption("Texture3D", "Textures", "Functions", "VisualShaderNodeTexture3D", TTR("Perform the 3D texture lookup."), -1, -1));
+ add_options.push_back(AddOption("UVPanning", "Textures", "Functions", "VisualShaderNodeUVFunc", TTR("Apply panning function on texture coordinates."), VisualShaderNodeUVFunc::FUNC_PANNING, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("UVScaling", "Textures", "Functions", "VisualShaderNodeUVFunc", TTR("Apply scaling function on texture coordinates."), VisualShaderNodeUVFunc::FUNC_SCALING, VisualShaderNode::PORT_TYPE_VECTOR));
add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubemapUniform", TTR("Cubic texture uniform lookup."), -1, -1));
add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, -1));
@@ -4079,6 +4321,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("TransformDecompose", "Transform", "Composition", "VisualShaderNodeTransformDecompose", TTR("Decomposes transform to four vectors.")));
add_options.push_back(AddOption("Determinant", "Transform", "Functions", "VisualShaderNodeDeterminant", TTR("Calculates the determinant of a transform."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("GetBillboardMatrix", "Transform", "Functions", "VisualShaderNodeBillboard", TTR("Calculates how the object should face the camera to be applied on Model View Matrix output port for 3D objects."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Inverse", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), VisualShaderNodeTransformFunc::FUNC_INVERSE, VisualShaderNode::PORT_TYPE_TRANSFORM));
add_options.push_back(AddOption("Transpose", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the transpose of a transform."), VisualShaderNodeTransformFunc::FUNC_TRANSPOSE, VisualShaderNode::PORT_TYPE_TRANSFORM));
@@ -4181,13 +4424,6 @@ VisualShaderEditor::VisualShaderEditor() {
_update_options_menu();
- error_panel = memnew(PanelContainer);
- add_child(error_panel);
- error_label = memnew(Label);
- error_panel->add_child(error_label);
- error_label->set_text("eh");
- error_panel->hide();
-
undo_redo = EditorNode::get_singleton()->get_undo_redo();
Ref<VisualShaderNodePluginDefault> default_plugin;
@@ -4268,7 +4504,7 @@ public:
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("Transform3D", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"),
};
@@ -4313,7 +4549,7 @@ public:
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons"),
- EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform3D", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Color", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"),
};
@@ -4504,7 +4740,7 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
if (Object::cast_to<EditorPropertyResource>(prop)) {
Object::cast_to<EditorPropertyResource>(prop)->set_use_sub_inspector(false);
prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- } else if (Object::cast_to<EditorPropertyTransform>(prop) || Object::cast_to<EditorPropertyVector3>(prop)) {
+ } else if (Object::cast_to<EditorPropertyTransform3D>(prop) || Object::cast_to<EditorPropertyVector3>(prop)) {
prop->set_custom_minimum_size(Size2(250 * EDSCALE, 0));
} else if (Object::cast_to<EditorPropertyFloat>(prop)) {
prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 6d57d38cab..4c7489a694 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -41,8 +41,8 @@
#include "scene/gui/tree.h"
#include "scene/resources/visual_shader.h"
-class VisualShaderNodePlugin : public Reference {
- GDCLASS(VisualShaderNodePlugin, Reference);
+class VisualShaderNodePlugin : public RefCounted {
+ GDCLASS(VisualShaderNodePlugin, RefCounted);
protected:
static void _bind_methods();
@@ -51,8 +51,8 @@ public:
virtual Control *create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node);
};
-class VisualShaderGraphPlugin : public Reference {
- GDCLASS(VisualShaderGraphPlugin, Reference);
+class VisualShaderGraphPlugin : public RefCounted {
+ GDCLASS(VisualShaderGraphPlugin, RefCounted);
private:
struct InputPort {
@@ -83,6 +83,8 @@ private:
List<VisualShader::Connection> connections;
bool dirty = false;
+ Color vector_expanded_color[3];
+
protected:
static void _bind_methods();
@@ -119,6 +121,7 @@ public:
void set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression);
int get_constant_index(float p_constant) const;
void update_node_size(int p_node_id);
+ void update_theme();
VisualShader::Type get_shader_type() const;
VisualShaderGraphPlugin();
@@ -139,12 +142,11 @@ class VisualShaderEditor : public VBoxContainer {
Button *preview_shader;
OptionButton *edit_type = nullptr;
- OptionButton *edit_type_standart;
+ OptionButton *edit_type_standard;
OptionButton *edit_type_particles;
OptionButton *edit_type_sky;
-
- PanelContainer *error_panel;
- Label *error_label;
+ CheckBox *custom_mode_box;
+ bool custom_mode_enabled = false;
bool pending_update_preview;
bool shader_error;
@@ -152,7 +154,8 @@ class VisualShaderEditor : public VBoxContainer {
VBoxContainer *preview_vbox;
CodeEdit *preview_text;
Ref<CodeHighlighter> syntax_highlighter;
- Label *error_text;
+ PanelContainer *error_panel;
+ Label *error_label;
UndoRedo *undo_redo;
Point2 saved_node_pos;
@@ -188,7 +191,9 @@ class VisualShaderEditor : public VBoxContainer {
enum ParticlesTypeFlags {
TYPE_FLAGS_EMIT = 1,
TYPE_FLAGS_PROCESS = 2,
- TYPE_FLAGS_END = 4
+ TYPE_FLAGS_COLLIDE = 4,
+ TYPE_FLAGS_EMIT_CUSTOM = 8,
+ TYPE_FLAGS_PROCESS_CUSTOM = 16,
};
enum SkyTypeFlags {
@@ -290,15 +295,8 @@ class VisualShaderEditor : public VBoxContainer {
void _draw_color_over_button(Object *obj, Color p_color);
- void _add_custom_node(const String &p_path);
- void _add_cubemap_node(const String &p_path);
- void _add_texture2d_node(const String &p_path);
- void _add_texture2d_array_node(const String &p_path);
- void _add_texture3d_node(const String &p_path);
- void _add_curve_node(const String &p_path);
-
void _setup_node(VisualShaderNode *p_node, int p_op_idx);
- VisualShaderNode *_add_node(int p_idx, int p_op_idx = -1);
+ void _add_node(int p_idx, int p_op_idx = -1, String p_resource_path = "", int p_node_idx = -1);
void _update_options_menu();
void _set_mode(int p_which);
@@ -360,7 +358,7 @@ class VisualShaderEditor : public VBoxContainer {
void _comment_title_popup_hide();
void _comment_title_popup_focus_out();
void _comment_title_text_changed(const String &p_new_text);
- void _comment_title_text_entered(const String &p_new_text);
+ void _comment_title_text_submitted(const String &p_new_text);
void _comment_desc_popup_show(const Point2 &p_position, int p_node_id);
void _comment_desc_popup_hide();
@@ -391,6 +389,7 @@ class VisualShaderEditor : public VBoxContainer {
Ref<VisualShaderGraphPlugin> graph_plugin;
void _mode_selected(int p_id);
+ void _custom_mode_toggled(bool p_enabled);
void _input_select_item(Ref<VisualShaderNodeInput> input, String name);
void _uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform, String p_name);
@@ -408,6 +407,7 @@ class VisualShaderEditor : public VBoxContainer {
void _remove_output_port(int p_node, int p_port);
void _change_output_port_type(int p_type, int p_node, int p_port);
void _change_output_port_name(const String &p_text, Object *p_line_edit, int p_node, int p_port);
+ void _expand_output_port(int p_node, int p_port, bool p_expand);
void _expression_focus_out(Object *code_edit, int p_node);
diff --git a/editor/plugins/gi_probe_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp
index f309c5da01..d30cc7ad17 100644
--- a/editor/plugins/gi_probe_editor_plugin.cpp
+++ b/editor/plugins/voxel_gi_editor_plugin.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gi_probe_editor_plugin.cpp */
+/* voxel_gi_editor_plugin.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,49 +28,49 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "gi_probe_editor_plugin.h"
+#include "voxel_gi_editor_plugin.h"
-void GIProbeEditorPlugin::_bake() {
- if (gi_probe) {
- if (gi_probe->get_probe_data().is_null()) {
+void VoxelGIEditorPlugin::_bake() {
+ if (voxel_gi) {
+ if (voxel_gi->get_probe_data().is_null()) {
String path = get_tree()->get_edited_scene_root()->get_filename();
if (path == String()) {
- path = "res://" + gi_probe->get_name() + "_data.res";
+ path = "res://" + voxel_gi->get_name() + "_data.res";
} else {
String ext = path.get_extension();
- path = path.get_basename() + "." + gi_probe->get_name() + "_data.res";
+ path = path.get_basename() + "." + voxel_gi->get_name() + "_data.res";
}
probe_file->set_current_path(path);
probe_file->popup_file_dialog();
return;
}
- gi_probe->bake();
+ voxel_gi->bake();
}
}
-void GIProbeEditorPlugin::edit(Object *p_object) {
- GIProbe *s = Object::cast_to<GIProbe>(p_object);
+void VoxelGIEditorPlugin::edit(Object *p_object) {
+ VoxelGI *s = Object::cast_to<VoxelGI>(p_object);
if (!s) {
return;
}
- gi_probe = s;
+ voxel_gi = s;
}
-bool GIProbeEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("GIProbe");
+bool VoxelGIEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("VoxelGI");
}
-void GIProbeEditorPlugin::_notification(int p_what) {
+void VoxelGIEditorPlugin::_notification(int p_what) {
if (p_what == NOTIFICATION_PROCESS) {
- if (!gi_probe) {
+ if (!voxel_gi) {
return;
}
- const Vector3i size = gi_probe->get_estimated_cell_size();
+ const Vector3i size = voxel_gi->get_estimated_cell_size();
String text = vformat(String::utf8("%d × %d × %d"), size.x, size.y, size.z);
int data_size = 4;
- if (GLOBAL_GET("rendering/quality/gi_probes/anisotropic")) {
+ if (GLOBAL_GET("rendering/quality/voxel_gi/anisotropic")) {
data_size += 4;
}
const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0);
@@ -98,7 +98,7 @@ void GIProbeEditorPlugin::_notification(int p_what) {
}
}
-void GIProbeEditorPlugin::make_visible(bool p_visible) {
+void VoxelGIEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
bake_hb->show();
set_process(true);
@@ -108,38 +108,38 @@ void GIProbeEditorPlugin::make_visible(bool p_visible) {
}
}
-EditorProgress *GIProbeEditorPlugin::tmp_progress = nullptr;
+EditorProgress *VoxelGIEditorPlugin::tmp_progress = nullptr;
-void GIProbeEditorPlugin::bake_func_begin(int p_steps) {
+void VoxelGIEditorPlugin::bake_func_begin(int p_steps) {
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) {
+void VoxelGIEditorPlugin::bake_func_step(int p_step, const String &p_description) {
ERR_FAIL_COND(tmp_progress == nullptr);
tmp_progress->step(p_description, p_step, false);
}
-void GIProbeEditorPlugin::bake_func_end() {
+void VoxelGIEditorPlugin::bake_func_end() {
ERR_FAIL_COND(tmp_progress == nullptr);
memdelete(tmp_progress);
tmp_progress = nullptr;
}
-void GIProbeEditorPlugin::_giprobe_save_path_and_bake(const String &p_path) {
+void VoxelGIEditorPlugin::_voxel_gi_save_path_and_bake(const String &p_path) {
probe_file->hide();
- if (gi_probe) {
- gi_probe->bake();
- ERR_FAIL_COND(gi_probe->get_probe_data().is_null());
- ResourceSaver::save(p_path, gi_probe->get_probe_data(), ResourceSaver::FLAG_CHANGE_PATH);
+ if (voxel_gi) {
+ voxel_gi->bake();
+ ERR_FAIL_COND(voxel_gi->get_probe_data().is_null());
+ ResourceSaver::save(p_path, voxel_gi->get_probe_data(), ResourceSaver::FLAG_CHANGE_PATH);
}
}
-void GIProbeEditorPlugin::_bind_methods() {
+void VoxelGIEditorPlugin::_bind_methods() {
}
-GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) {
+VoxelGIEditorPlugin::VoxelGIEditorPlugin(EditorNode *p_node) {
editor = p_node;
bake_hb = memnew(HBoxContainer);
bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -148,7 +148,7 @@ GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) {
bake->set_flat(true);
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->connect("pressed", callable_mp(this, &VoxelGIEditorPlugin::_bake));
bake_hb->add_child(bake);
bake_info = memnew(Label);
bake_info->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -156,18 +156,18 @@ GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) {
bake_hb->add_child(bake_info);
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake_hb);
- gi_probe = nullptr;
+ voxel_gi = nullptr;
probe_file = memnew(EditorFileDialog);
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));
+ probe_file->connect("file_selected", callable_mp(this, &VoxelGIEditorPlugin::_voxel_gi_save_path_and_bake));
get_editor_interface()->get_base_control()->add_child(probe_file);
- probe_file->set_title(TTR("Select path for GIProbe Data File"));
+ probe_file->set_title(TTR("Select path for VoxelGI Data File"));
- GIProbe::bake_begin_function = bake_func_begin;
- GIProbe::bake_step_function = bake_func_step;
- GIProbe::bake_end_function = bake_func_end;
+ VoxelGI::bake_begin_function = bake_func_begin;
+ VoxelGI::bake_step_function = bake_func_step;
+ VoxelGI::bake_end_function = bake_func_end;
}
-GIProbeEditorPlugin::~GIProbeEditorPlugin() {
+VoxelGIEditorPlugin::~VoxelGIEditorPlugin() {
}
diff --git a/editor/plugins/gi_probe_editor_plugin.h b/editor/plugins/voxel_gi_editor_plugin.h
index fdf0623561..4d3cfe90f6 100644
--- a/editor/plugins/gi_probe_editor_plugin.h
+++ b/editor/plugins/voxel_gi_editor_plugin.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gi_probe_editor_plugin.h */
+/* voxel_gi_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,18 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GIPROBEEDITORPLUGIN_H
-#define GIPROBEEDITORPLUGIN_H
+#ifndef VOXEL_GIEDITORPLUGIN_H
+#define VOXEL_GIEDITORPLUGIN_H
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-#include "scene/3d/gi_probe.h"
+#include "scene/3d/voxel_gi.h"
#include "scene/resources/material.h"
-class GIProbeEditorPlugin : public EditorPlugin {
- GDCLASS(GIProbeEditorPlugin, EditorPlugin);
+class VoxelGIEditorPlugin : public EditorPlugin {
+ GDCLASS(VoxelGIEditorPlugin, EditorPlugin);
- GIProbe *gi_probe;
+ VoxelGI *voxel_gi;
HBoxContainer *bake_hb;
Label *bake_info;
@@ -54,21 +54,21 @@ class GIProbeEditorPlugin : public EditorPlugin {
static void bake_func_end();
void _bake();
- void _giprobe_save_path_and_bake(const String &p_path);
+ void _voxel_gi_save_path_and_bake(const String &p_path);
protected:
static void _bind_methods();
void _notification(int p_what);
public:
- virtual String get_name() const override { return "GIProbe"; }
+ virtual String get_name() const override { return "VoxelGI"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- GIProbeEditorPlugin(EditorNode *p_node);
- ~GIProbeEditorPlugin();
+ VoxelGIEditorPlugin(EditorNode *p_node);
+ ~VoxelGIEditorPlugin();
};
-#endif // GIPROBEEDITORPLUGIN_H
+#endif // VOXEL_GIEDITORPLUGIN_H
diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp
index 497cc0cbdc..b58b7e4cac 100644
--- a/editor/pot_generator.cpp
+++ b/editor/pot_generator.cpp
@@ -39,7 +39,7 @@ POTGenerator *POTGenerator::singleton = nullptr;
#ifdef DEBUG_POT
void POTGenerator::_print_all_translation_strings() {
- for (auto E = all_translation_strings.front(); E; E = E.next()) {
+ for (OrderedHashMap<String, Vector<POTGenerator::MsgidData>>::Element E = all_translation_strings.front(); E; E = E.next()) {
Vector<MsgidData> v_md = all_translation_strings[E.key()];
for (int i = 0; i < v_md.size(); i++) {
print_line("++++++");
diff --git a/editor/pot_generator.h b/editor/pot_generator.h
index ab055e0c0e..61300064ba 100644
--- a/editor/pot_generator.h
+++ b/editor/pot_generator.h
@@ -31,7 +31,7 @@
#ifndef POT_GENERATOR_H
#define POT_GENERATOR_H
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/templates/ordered_hash_map.h"
#include "core/templates/set.h"
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index 3ede50320a..ec65694772 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -31,11 +31,11 @@
#include "project_export.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/string/optimized_translation.h"
#include "editor_data.h"
@@ -795,7 +795,7 @@ void ProjectExportDialog::_tree_changed() {
}
void ProjectExportDialog::_check_dir_recursive(TreeItem *p_dir, bool p_checked) {
- for (TreeItem *child = p_dir->get_children(); child; child = child->get_next()) {
+ for (TreeItem *child = p_dir->get_first_child(); child; child = child->get_next()) {
String path = child->get_metadata(0);
child->set_checked(0, p_checked);
@@ -818,7 +818,7 @@ void ProjectExportDialog::_refresh_parent_checks(TreeItem *p_item) {
}
bool checked = true;
- for (TreeItem *child = parent->get_children(); child; child = child->get_next()) {
+ for (TreeItem *child = parent->get_first_child(); child; child = child->get_next()) {
checked = checked && child->is_checked(0);
if (!checked) {
break;
@@ -871,10 +871,10 @@ void ProjectExportDialog::_validate_export_path(const String &p_path) {
if (invalid_path) {
export_project->get_ok_button()->set_disabled(true);
- export_project->get_line_edit()->disconnect("text_entered", Callable(export_project, "_file_entered"));
+ export_project->get_line_edit()->disconnect("text_submitted", Callable(export_project, "_file_submitted"));
} else {
export_project->get_ok_button()->set_disabled(false);
- export_project->get_line_edit()->connect("text_entered", Callable(export_project, "_file_entered"));
+ export_project->get_line_edit()->connect("text_submitted", Callable(export_project, "_file_submitted"));
}
}
@@ -905,10 +905,10 @@ void ProjectExportDialog::_export_project() {
// Ensure that signal is connected if previous attempt left it disconnected
// with _validate_export_path.
// FIXME: This is a hack, we should instead change EditorFileDialog to allow
- // disabling validation by the "text_entered" signal.
- if (!export_project->get_line_edit()->is_connected("text_entered", Callable(export_project, "_file_entered"))) {
+ // disabling validation by the "text_submitted" signal.
+ if (!export_project->get_line_edit()->is_connected("text_submitted", Callable(export_project, "_file_submitted"))) {
export_project->get_ok_button()->set_disabled(false);
- export_project->get_line_edit()->connect("text_entered", Callable(export_project, "_file_entered"));
+ export_project->get_line_edit()->connect("text_submitted", Callable(export_project, "_file_submitted"));
}
export_project->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
@@ -978,9 +978,9 @@ void ProjectExportDialog::_export_all(bool p_debug) {
}
void ProjectExportDialog::_bind_methods() {
- ClassDB::bind_method("get_drag_data_fw", &ProjectExportDialog::get_drag_data_fw);
- ClassDB::bind_method("can_drop_data_fw", &ProjectExportDialog::can_drop_data_fw);
- ClassDB::bind_method("drop_data_fw", &ProjectExportDialog::drop_data_fw);
+ ClassDB::bind_method("_get_drag_data_fw", &ProjectExportDialog::get_drag_data_fw);
+ ClassDB::bind_method("_can_drop_data_fw", &ProjectExportDialog::can_drop_data_fw);
+ ClassDB::bind_method("_drop_data_fw", &ProjectExportDialog::drop_data_fw);
ClassDB::bind_method("_export_all", &ProjectExportDialog::_export_all);
ClassDB::bind_method("set_export_path", &ProjectExportDialog::set_export_path);
ClassDB::bind_method("get_export_path", &ProjectExportDialog::get_export_path);
diff --git a/editor/project_export.h b/editor/project_export.h
index cfd4934c34..aeace708b8 100644
--- a/editor/project_export.h
+++ b/editor/project_export.h
@@ -31,7 +31,7 @@
#ifndef PROJECT_EXPORT_SETTINGS_H
#define PROJECT_EXPORT_SETTINGS_H
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "core/os/thread.h"
#include "editor/editor_export.h"
#include "editor/editor_file_dialog.h"
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index e51e8ee82e..1267c7dd19 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -31,11 +31,11 @@
#include "project_manager.h"
#include "core/io/config_file.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
#include "core/io/stream_peer_ssl.h"
#include "core/io/zip_io.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/translation.h"
@@ -100,7 +100,6 @@ private:
FileDialog *fdialog_install;
String zip_path;
String zip_title;
- String zip_root;
AcceptDialog *dialog_error;
String fav_dir;
@@ -201,9 +200,7 @@ private:
char fname[16384];
ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
- String fname_str = String(fname);
- if (fname_str.ends_with("project.godot")) {
- zip_root = fname_str.substr(0, fname_str.rfind("project.godot"));
+ if (String(fname).ends_with("project.godot")) {
break;
}
@@ -524,7 +521,24 @@ private:
return;
}
+ // Find the zip_root
+ String zip_root;
int ret = unzGoToFirstFile(pkg);
+ while (ret == UNZ_OK) {
+ unz_file_info info;
+ char fname[16384];
+ unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
+
+ String name = fname;
+ if (name.ends_with("project.godot")) {
+ zip_root = name.substr(0, name.rfind("project.godot"));
+ break;
+ }
+
+ ret = unzGoToNextFile(pkg);
+ }
+
+ ret = unzGoToFirstFile(pkg);
Vector<String> failed_files;
@@ -1470,16 +1484,7 @@ Vector<ProjectList::Item> ProjectList::get_selected_projects() const {
void ProjectList::ensure_project_visible(int p_index) {
const Item &item = _projects[p_index];
-
- int item_top = item.control->get_position().y;
- int item_bottom = item.control->get_position().y + item.control->get_size().y;
-
- if (item_top < get_v_scroll()) {
- set_v_scroll(item_top);
-
- } else if (item_bottom > get_v_scroll() + get_size().y) {
- set_v_scroll(item_bottom - get_size().y);
- }
+ ensure_control_visible(item.control);
}
int ProjectList::get_single_selected_index() const {
@@ -1740,7 +1745,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
const Item &clicked_project = _projects[clicked_index];
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (mb->get_shift() && _selected_project_keys.size() > 0 && _last_clicked != "" && clicked_project.project_key != _last_clicked) {
+ if (mb->is_shift_pressed() && _selected_project_keys.size() > 0 && _last_clicked != "" && clicked_project.project_key != _last_clicked) {
int anchor_index = -1;
for (int i = 0; i < _projects.size(); ++i) {
const Item &p = _projects[i];
@@ -1752,7 +1757,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
CRASH_COND(anchor_index == -1);
select_range(anchor_index, clicked_index);
- } else if (mb->get_control()) {
+ } else if (mb->is_ctrl_pressed()) {
toggle_select(clicked_index);
} else {
@@ -1762,7 +1767,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
emit_signal(SIGNAL_SELECTION_CHANGED);
- if (!mb->get_control() && mb->is_doubleclick()) {
+ if (!mb->is_ctrl_pressed() && mb->is_double_click()) {
emit_signal(SIGNAL_PROJECT_ASK_OPEN);
}
}
@@ -1937,7 +1942,7 @@ void ProjectManager::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
} break;
case KEY_UP: {
- if (k->get_shift()) {
+ if (k->is_shift_pressed()) {
break;
}
@@ -1951,7 +1956,7 @@ void ProjectManager::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
break;
}
case KEY_DOWN: {
- if (k->get_shift()) {
+ if (k->is_shift_pressed()) {
break;
}
@@ -1964,7 +1969,7 @@ void ProjectManager::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
} break;
case KEY_F: {
- if (k->get_command()) {
+ if (k->is_command_pressed()) {
this->search_box->grab_focus();
} else {
keycode_handled = false;
@@ -2124,8 +2129,8 @@ void ProjectManager::_run_project_confirm() {
const String &selected = selected_list[i].project_key;
String path = EditorSettings::get_singleton()->get("projects/" + selected);
- // `.right(6)` on `IMPORTED_FILES_PATH` strips away the leading "res://".
- if (!DirAccess::exists(path.plus_file(ProjectSettings::IMPORTED_FILES_PATH.right(6)))) {
+ // `.substr(6)` on `IMPORTED_FILES_PATH` strips away the leading "res://".
+ if (!DirAccess::exists(path.plus_file(ProjectSettings::IMPORTED_FILES_PATH.substr(6)))) {
run_error_diag->set_text(TTR("Can't run project: Assets need to be imported.\nPlease edit the project to trigger the initial import."));
run_error_diag->popup_centered();
continue;
@@ -2371,6 +2376,7 @@ void ProjectManager::_on_search_term_changed(const String &p_term) {
void ProjectManager::_bind_methods() {
ClassDB::bind_method("_unhandled_key_input", &ProjectManager::_unhandled_key_input);
ClassDB::bind_method("_update_project_buttons", &ProjectManager::_update_project_buttons);
+ ClassDB::bind_method("_version_button_pressed", &ProjectManager::_version_button_pressed);
}
void ProjectManager::_open_asset_library() {
@@ -2378,6 +2384,10 @@ void ProjectManager::_open_asset_library() {
tabs->set_current_tab(1);
}
+void ProjectManager::_version_button_pressed() {
+ DisplayServer::get_singleton()->clipboard_set(version_btn->get_text());
+}
+
ProjectManager::ProjectManager() {
// load settings
if (!EditorSettings::get_singleton()) {
@@ -2390,34 +2400,10 @@ ProjectManager::ProjectManager() {
int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
switch (display_scale) {
- case 0: {
+ case 0:
// Try applying a suitable display scale automatically.
- // The code below is adapted in `editor/editor_settings.cpp` and `editor/editor_node.cpp`.
- // Make sure to update those when modifying the code below.
-#ifdef OSX_ENABLED
- editor_set_scale(DisplayServer::get_singleton()->screen_get_max_scale());
-#else
- const int screen = DisplayServer::get_singleton()->window_get_current_screen();
- float scale;
- if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) {
- // hiDPI display.
- scale = 2.0;
- } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) {
- // Likely a hiDPI display, but we aren't certain due to the returned DPI.
- // Use an intermediate scale to handle this situation.
- scale = 1.5;
- } else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) {
- // Small loDPI display. Use a smaller display scale so that editor elements fit more easily.
- // Icons won't look great, but this is better than having editor elements overflow from its window.
- scale = 0.75;
- } else {
- scale = 1.0;
- }
-
- editor_set_scale(scale);
-#endif
- } break;
-
+ editor_set_scale(EditorSettings::get_singleton()->get_auto_display_scale());
+ break;
case 1:
editor_set_scale(0.75);
break;
@@ -2480,7 +2466,7 @@ ProjectManager::ProjectManager() {
tabs->connect("tab_changed", callable_mp(this, &ProjectManager::_on_tab_changed));
HBoxContainer *projects_hb = memnew(HBoxContainer);
- projects_hb->set_name(TTR("Projects"));
+ projects_hb->set_name(TTR("Local Projects"));
tabs->add_child(projects_hb);
{
@@ -2601,15 +2587,30 @@ ProjectManager::ProjectManager() {
settings_hb->set_h_grow_direction(Control::GROW_DIRECTION_BEGIN);
settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT);
- Label *version_label = memnew(Label);
+ // A VBoxContainer that contains a dummy Control node to adjust the LinkButton's vertical position.
+ VBoxContainer *spacer_vb = memnew(VBoxContainer);
+ settings_hb->add_child(spacer_vb);
+
+ Control *v_spacer = memnew(Control);
+ spacer_vb->add_child(v_spacer);
+
+ version_btn = memnew(LinkButton);
String hash = String(VERSION_HASH);
if (hash.length() != 0) {
- hash = "." + hash.left(9);
+ hash = " " + vformat("[%s]", hash.left(9));
}
- version_label->set_text("v" VERSION_FULL_BUILD "" + hash);
- version_label->set_self_modulate(Color(1, 1, 1, 0.6));
- version_label->set_align(Label::ALIGN_CENTER);
- settings_hb->add_child(version_label);
+ version_btn->set_text("v" VERSION_FULL_BUILD + hash);
+ // Fade the version label to be less prominent, but still readable.
+ version_btn->set_self_modulate(Color(1, 1, 1, 0.6));
+ version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
+ version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->connect("pressed", callable_mp(this, &ProjectManager::_version_button_pressed));
+ spacer_vb->add_child(version_btn);
+
+ // Add a small horizontal spacer between the version and language buttons
+ // to distinguish them.
+ Control *h_spacer = memnew(Control);
+ settings_hb->add_child(h_spacer);
language_btn = memnew(OptionButton);
language_btn->set_flat(true);
@@ -2647,7 +2648,7 @@ ProjectManager::ProjectManager() {
if (StreamPeerSSL::is_available()) {
asset_library = memnew(EditorAssetLibrary(true));
- asset_library->set_name(TTR("Templates"));
+ asset_library->set_name(TTR("Asset Library Projects"));
tabs->add_child(asset_library);
asset_library->connect("install_asset", callable_mp(this, &ProjectManager::_install_project));
} else {
diff --git a/editor/project_manager.h b/editor/project_manager.h
index a66b7c4ab6..0fc69bd313 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -89,6 +89,7 @@ class ProjectManager : public Control {
ProjectDialog *npdialog;
OptionButton *language_btn;
+ LinkButton *version_btn;
void _open_asset_library();
void _scan_projects();
@@ -123,6 +124,7 @@ class ProjectManager : public Control {
void _unhandled_key_input(const Ref<InputEvent> &p_ev);
void _files_dropped(PackedStringArray p_files, int p_screen);
+ void _version_button_pressed();
void _on_order_option_changed(int p_idx);
void _on_tab_changed(int p_tab);
void _on_search_term_changed(const String &p_term);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index faec3355ac..e76d757516 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -72,17 +72,9 @@ void ProjectSettingsEditor::_setting_edited(const String &p_name) {
queue_save();
}
-void ProjectSettingsEditor::_advanced_pressed() {
- if (advanced->is_pressed()) {
- _update_advanced_bar();
- advanced_bar->show();
- EditorSettings::get_singleton()->set_project_metadata("project_settings", "advanced_mode", true);
- inspector->set_restrict_to_basic_settings(false);
- } else {
- advanced_bar->hide();
- EditorSettings::get_singleton()->set_project_metadata("project_settings", "advanced_mode", false);
- inspector->set_restrict_to_basic_settings(true);
- }
+void ProjectSettingsEditor::_advanced_toggled(bool p_button_pressed) {
+ EditorSettings::get_singleton()->set_project_metadata("project_settings", "advanced_mode", p_button_pressed);
+ inspector->set_restrict_to_basic_settings(!p_button_pressed);
}
void ProjectSettingsEditor::_setting_selected(const String &p_path) {
@@ -90,12 +82,9 @@ void ProjectSettingsEditor::_setting_selected(const String &p_path) {
return;
}
- category_box->set_text(inspector->get_current_section());
- property_box->set_text(p_path);
+ property_box->set_text(inspector->get_current_section() + "/" + p_path);
- if (advanced_bar->is_visible()) {
- _update_advanced_bar(); // set_text doesn't trigger text_changed
- }
+ _update_property_box(); // set_text doesn't trigger text_changed
}
void ProjectSettingsEditor::_add_setting() {
@@ -104,7 +93,7 @@ void ProjectSettingsEditor::_add_setting() {
// Initialize the property with the default value for the given type.
Callable::CallError ce;
Variant value;
- Variant::construct(Variant::Type(type->get_selected_id()), value, nullptr, 0, ce);
+ Variant::construct(Variant::Type(type_box->get_selected_id()), value, nullptr, 0, ce);
undo_redo->create_action(TTR("Add Project Setting"));
undo_redo->add_do_property(ps, setting, value);
@@ -117,19 +106,14 @@ void ProjectSettingsEditor::_add_setting() {
undo_redo->commit_action();
inspector->set_current_section(setting.get_slice("/", 1));
+ add_button->release_focus();
}
-void ProjectSettingsEditor::_delete_setting(bool p_confirmed) {
+void ProjectSettingsEditor::_delete_setting() {
String setting = _get_setting_name();
Variant value = ps->get(setting);
int order = ps->get_order(setting);
- if (!p_confirmed) {
- del_confirmation->set_text(vformat(TTR("Are you sure you want to delete '%s'?"), setting));
- del_confirmation->popup_centered();
- return;
- }
-
undo_redo->create_action(TTR("Delete Item"));
undo_redo->add_do_method(ps, "clear", setting);
@@ -144,65 +128,84 @@ void ProjectSettingsEditor::_delete_setting(bool p_confirmed) {
undo_redo->commit_action();
property_box->clear();
+ del_button->release_focus();
}
-void ProjectSettingsEditor::_text_field_changed(const String &p_text) {
- _update_advanced_bar();
+void ProjectSettingsEditor::_property_box_changed(const String &p_text) {
+ _update_property_box();
}
void ProjectSettingsEditor::_feature_selected(int p_index) {
- _update_advanced_bar();
+ Vector<String> t = property_box->get_text().strip_edges().split(".", true, 1);
+ const String feature = p_index ? "." + feature_box->get_item_text(p_index) : "";
+ property_box->set_text(t[0] + feature);
+ _update_property_box();
}
-void ProjectSettingsEditor::_update_advanced_bar() {
- const String property_text = property_box->get_text().strip_edges();
+void ProjectSettingsEditor::_update_property_box() {
+ const String setting = _get_setting_name();
+ const Vector<String> t = setting.split(".", true, 1);
+ const String name = t[0];
+ const String feature = (t.size() == 2) ? t[1] : "";
+ bool feature_invalid = (t.size() == 2) && (t[1] == "");
+
+ add_button->set_disabled(true);
+ del_button->set_disabled(true);
+
+ if (feature != "") {
+ feature_invalid = true;
+ for (int i = 1; i < feature_box->get_item_count(); i++) {
+ if (feature == feature_box->get_item_text(i)) {
+ feature_invalid = false;
+ feature_box->select(i);
+ break;
+ }
+ }
+ }
- String error_msg = "";
- bool disable_add = true;
- bool disable_del = true;
+ if (feature == "" || feature_invalid) {
+ feature_box->select(0);
+ }
- if (!property_box->get_text().is_empty()) {
- const String setting = _get_setting_name();
- bool setting_exists = ps->has_setting(setting);
- if (setting_exists) {
- error_msg = TTR(" - Cannot add already existing setting.");
+ if (property_box->get_text() == "") {
+ return;
+ }
- disable_del = ps->is_builtin_setting(setting);
- if (disable_del) {
- String msg = TTR(" - Cannot delete built-in setting.");
- error_msg += (error_msg == "") ? msg : "\n" + msg;
- }
+ if (ps->has_setting(setting)) {
+ del_button->set_disabled(ps->is_builtin_setting(setting));
+ _select_type(ps->get_setting(setting).get_type());
+ } else {
+ if (ps->has_setting(name)) {
+ _select_type(ps->get_setting(name).get_type());
} else {
- bool bad_category = false; // Allow empty string.
- Vector<String> cats = category_box->get_text().strip_edges().split("/");
- for (int i = 0; i < cats.size(); i++) {
- if (!cats[i].is_valid_identifier()) {
- bad_category = true;
- error_msg = TTR(" - Invalid category name.");
- break;
- }
- }
+ type_box->select(0);
+ }
- disable_add = bad_category;
+ if (feature_invalid) {
+ return;
+ }
- if (!property_text.is_valid_identifier()) {
- disable_add = true;
- String msg = TTR(" - Invalid property name.");
- error_msg += (error_msg == "") ? msg : "\n" + msg;
+ const Vector<String> names = name.split("/");
+ for (int i = 0; i < names.size(); i++) {
+ if (!names[i].is_valid_identifier()) {
+ return;
}
}
+
+ add_button->set_disabled(false);
}
+}
- add_button->set_disabled(disable_add);
- del_button->set_disabled(disable_del);
+void ProjectSettingsEditor::_select_type(Variant::Type p_type) {
+ type_box->select(type_box->get_item_index(p_type));
}
String ProjectSettingsEditor::_get_setting_name() const {
- const String cat = category_box->get_text();
- const String name = (cat.is_empty() ? "global" : cat.strip_edges()).plus_file(property_box->get_text().strip_edges());
- const String feature = feature_override->get_item_text(feature_override->get_selected());
-
- return (feature == "") ? name : (name + "." + feature);
+ String name = property_box->get_text().strip_edges();
+ if (name.find("/") == -1) {
+ name = "global/" + name;
+ }
+ return name;
}
void ProjectSettingsEditor::_add_feature_overrides() {
@@ -248,11 +251,11 @@ void ProjectSettingsEditor::_add_feature_overrides() {
}
}
- feature_override->clear();
- feature_override->add_item("", 0); // So it is always on top.
+ feature_box->clear();
+ feature_box->add_item(TTR("(All)"), 0); // So it is always on top.
int id = 1;
for (Set<String>::Element *E = presets.front(); E; E = E->next()) {
- feature_override->add_item(E->get(), id++);
+ feature_box->add_item(E->get(), id++);
}
}
@@ -480,9 +483,6 @@ void ProjectSettingsEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
inspector->edit(ps);
- add_button->set_icon(get_theme_icon("Add", "EditorIcons"));
- del_button->set_icon(get_theme_icon("Remove", "EditorIcons"));
-
search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
@@ -525,87 +525,56 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
general_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tab_container->add_child(general_editor);
- VBoxContainer *header = memnew(VBoxContainer);
- header->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- general_editor->add_child(header);
+ HBoxContainer *search_bar = memnew(HBoxContainer);
+ general_editor->add_child(search_bar);
- {
- // Search bar.
- search_bar = memnew(HBoxContainer);
- search_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- header->add_child(search_bar);
-
- search_box = memnew(LineEdit);
- search_box->set_placeholder(TTR("Search"));
- search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- search_bar->add_child(search_box);
-
- advanced = memnew(CheckButton);
- advanced->set_text(TTR("Advanced Settings"));
- advanced->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_advanced_pressed));
- search_bar->add_child(advanced);
- }
+ search_box = memnew(LineEdit);
+ search_box->set_placeholder(TTR("Filter Settings"));
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ search_bar->add_child(search_box);
- {
- // Advanced bar.
- advanced_bar = memnew(HBoxContainer);
- advanced_bar->hide();
- header->add_child(advanced_bar);
-
- HBoxContainer *hbc = advanced_bar;
- hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
-
- category_box = memnew(LineEdit);
- category_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- category_box->connect("text_changed", callable_mp(this, &ProjectSettingsEditor::_text_field_changed));
- category_box->set_placeholder(TTR("Category"));
- hbc->add_child(category_box);
-
- Label *l = memnew(Label);
- l->set_text(" / ");
- hbc->add_child(l);
-
- property_box = memnew(LineEdit);
- property_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- property_box->set_placeholder(TTR("Property"));
- property_box->connect("text_changed", callable_mp(this, &ProjectSettingsEditor::_text_field_changed));
- hbc->add_child(property_box);
-
- l = memnew(Label);
- l->set_text(TTR("Type:"));
- hbc->add_child(l);
-
- type = memnew(OptionButton);
- type->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
- hbc->add_child(type);
-
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- // There's no point in adding Nil types, and Object types
- // can't be serialized correctly in the project settings.
- if (i != Variant::NIL && i != Variant::OBJECT) {
- type->add_item(Variant::get_type_name(Variant::Type(i)), i);
- }
- }
+ advanced = memnew(CheckButton);
+ advanced->set_text(TTR("Advanced Settings"));
+ advanced->connect("toggled", callable_mp(this, &ProjectSettingsEditor::_advanced_toggled));
+ search_bar->add_child(advanced);
- l = memnew(Label);
- l->set_text(TTR("Feature Override:"));
- hbc->add_child(l);
+ HBoxContainer *header = memnew(HBoxContainer);
+ general_editor->add_child(header);
- feature_override = memnew(OptionButton);
- feature_override->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
- feature_override->connect("item_selected", callable_mp(this, &ProjectSettingsEditor::_feature_selected));
- hbc->add_child(feature_override);
+ property_box = memnew(LineEdit);
+ property_box->set_placeholder(TTR("Select a setting or type its name"));
+ property_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ property_box->connect("text_changed", callable_mp(this, &ProjectSettingsEditor::_property_box_changed));
+ header->add_child(property_box);
+
+ feature_box = memnew(OptionButton);
+ feature_box->set_custom_minimum_size(Size2(120, 0) * EDSCALE);
+ feature_box->connect("item_selected", callable_mp(this, &ProjectSettingsEditor::_feature_selected));
+ header->add_child(feature_box);
+
+ type_box = memnew(OptionButton);
+ type_box->set_custom_minimum_size(Size2(120, 0) * EDSCALE);
+ header->add_child(type_box);
+
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ // There's no point in adding Nil types, and Object types
+ // can't be serialized correctly in the project settings.
+ if (i != Variant::NIL && i != Variant::OBJECT) {
+ type_box->add_item(Variant::get_type_name(Variant::Type(i)), i);
+ }
+ }
- add_button = memnew(Button);
- add_button->set_flat(true);
- add_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_add_setting));
- hbc->add_child(add_button);
+ add_button = memnew(Button);
+ add_button->set_text(TTR("Add"));
+ add_button->set_disabled(true);
+ add_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_add_setting));
+ header->add_child(add_button);
- del_button = memnew(Button);
- del_button->set_flat(true);
- del_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_delete_setting), varray(false));
- hbc->add_child(del_button);
- }
+ del_button = memnew(Button);
+ del_button->set_text(TTR("Delete"));
+ del_button->set_disabled(true);
+ del_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_delete_setting));
+ header->add_child(del_button);
inspector = memnew(SectionedInspector);
inspector->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo());
@@ -649,8 +618,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
action_map->connect("action_removed", callable_mp(this, &ProjectSettingsEditor::_action_removed));
action_map->connect("action_renamed", callable_mp(this, &ProjectSettingsEditor::_action_renamed));
action_map->connect("action_reordered", callable_mp(this, &ProjectSettingsEditor::_action_reordered));
- action_map->set_toggle_editable_label(TTR("Show Built-in Actions"));
- action_map->set_show_uneditable(false);
tab_container->add_child(action_map);
localization_editor = memnew(LocalizationEditor);
@@ -678,10 +645,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
timer->set_one_shot(true);
add_child(timer);
- del_confirmation = memnew(ConfirmationDialog);
- del_confirmation->connect("confirmed", callable_mp(this, &ProjectSettingsEditor::_delete_setting), varray(true));
- add_child(del_confirmation);
-
get_ok_button()->set_text(TTR("Close"));
set_hide_on_ok(true);
@@ -689,7 +652,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
if (use_advanced) {
advanced->set_pressed(true);
- advanced_bar->show();
}
inspector->set_restrict_to_basic_settings(!use_advanced);
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index cde46ac4c4..eb6c300d5b 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -51,25 +51,20 @@ class ProjectSettingsEditor : public AcceptDialog {
TabContainer *tab_container;
SectionedInspector *inspector;
+ ActionMapEditor *action_map;
LocalizationEditor *localization_editor;
EditorAutoloadSettings *autoload_settings;
ShaderGlobalsEditor *shaders_global_variables_editor;
EditorPluginSettings *plugin_settings;
- ActionMapEditor *action_map;
- HBoxContainer *search_bar;
LineEdit *search_box;
CheckButton *advanced;
- HBoxContainer *advanced_bar;
- LineEdit *category_box;
LineEdit *property_box;
+ OptionButton *feature_box;
+ OptionButton *type_box;
Button *add_button;
Button *del_button;
- OptionButton *type;
- OptionButton *feature_override;
-
- ConfirmationDialog *del_confirmation;
Label *restart_label;
TextureRect *restart_icon;
@@ -80,16 +75,17 @@ class ProjectSettingsEditor : public AcceptDialog {
EditorData *data;
UndoRedo *undo_redo;
- void _advanced_pressed();
- void _update_advanced_bar();
- void _text_field_changed(const String &p_text);
+ void _advanced_toggled(bool p_button_pressed);
+ void _property_box_changed(const String &p_text);
+ void _update_property_box();
void _feature_selected(int p_index);
+ void _select_type(Variant::Type p_type);
String _get_setting_name() const;
void _setting_edited(const String &p_name);
void _setting_selected(const String &p_path);
void _add_setting();
- void _delete_setting(bool p_confirmed);
+ void _delete_setting();
void _editor_restart_request();
void _editor_restart();
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 1a010b9168..ba3c9aafb4 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -727,13 +727,13 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
value_editor[3]->set_text(String::num(plane.d));
} break;
- case Variant::QUAT: {
+ case Variant::QUATERNION: {
field_names.push_back("x");
field_names.push_back("y");
field_names.push_back("z");
field_names.push_back("w");
config_value_editors(4, 4, 10, field_names);
- Quat q = v;
+ Quaternion q = v;
value_editor[0]->set_text(String::num(q.x));
value_editor[1]->set_text(String::num(q.y));
value_editor[2]->set_text(String::num(q.z));
@@ -791,7 +791,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
}
} break;
- case Variant::TRANSFORM: {
+ case Variant::TRANSFORM3D: {
field_names.push_back("xx");
field_names.push_back("xy");
field_names.push_back("xz");
@@ -806,7 +806,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
field_names.push_back("zo");
config_value_editors(12, 4, 16, field_names);
- Transform tr = v;
+ Transform3D tr = v;
for (int i = 0; i < 9; i++) {
value_editor[(i / 3) * 4 + i % 3]->set_text(String::num(tr.basis.elements[i / 3][i % 3]));
}
@@ -1446,6 +1446,8 @@ void CustomPropertyEditor::_modified(String p_string) {
return;
}
+ Variant prev_v = v;
+
updating = true;
switch (type) {
case Variant::INT: {
@@ -1459,14 +1461,18 @@ void CustomPropertyEditor::_modified(String p_string) {
} else {
v = expr->execute(Array(), nullptr, false);
}
- emit_signal("variant_changed");
+ if (v != prev_v) {
+ emit_signal("variant_changed");
+ }
} break;
case Variant::FLOAT: {
if (hint != PROPERTY_HINT_EXP_EASING) {
String text = TS->parse_number(value_editor[0]->get_text());
v = _parse_real_expression(text);
- emit_signal("variant_changed");
+ if (v != prev_v) {
+ emit_signal("variant_changed");
+ }
}
} break;
@@ -1479,7 +1485,9 @@ void CustomPropertyEditor::_modified(String p_string) {
vec.x = _parse_real_expression(value_editor[0]->get_text());
vec.y = _parse_real_expression(value_editor[1]->get_text());
v = vec;
- _emit_changed_whole_or_field();
+ if (v != prev_v) {
+ _emit_changed_whole_or_field();
+ }
} break;
case Variant::RECT2: {
@@ -1490,7 +1498,9 @@ void CustomPropertyEditor::_modified(String p_string) {
r2.size.x = _parse_real_expression(value_editor[2]->get_text());
r2.size.y = _parse_real_expression(value_editor[3]->get_text());
v = r2;
- _emit_changed_whole_or_field();
+ if (v != prev_v) {
+ _emit_changed_whole_or_field();
+ }
} break;
@@ -1500,7 +1510,9 @@ void CustomPropertyEditor::_modified(String p_string) {
vec.y = _parse_real_expression(value_editor[1]->get_text());
vec.z = _parse_real_expression(value_editor[2]->get_text());
v = vec;
- _emit_changed_whole_or_field();
+ if (v != prev_v) {
+ _emit_changed_whole_or_field();
+ }
} break;
case Variant::PLANE: {
@@ -1510,17 +1522,21 @@ void CustomPropertyEditor::_modified(String p_string) {
pl.normal.z = _parse_real_expression(value_editor[2]->get_text());
pl.d = _parse_real_expression(value_editor[3]->get_text());
v = pl;
- _emit_changed_whole_or_field();
+ if (v != prev_v) {
+ _emit_changed_whole_or_field();
+ }
} break;
- case Variant::QUAT: {
- Quat q;
+ case Variant::QUATERNION: {
+ Quaternion q;
q.x = _parse_real_expression(value_editor[0]->get_text());
q.y = _parse_real_expression(value_editor[1]->get_text());
q.z = _parse_real_expression(value_editor[2]->get_text());
q.w = _parse_real_expression(value_editor[3]->get_text());
v = q;
- _emit_changed_whole_or_field();
+ if (v != prev_v) {
+ _emit_changed_whole_or_field();
+ }
} break;
case Variant::AABB: {
@@ -1534,7 +1550,9 @@ void CustomPropertyEditor::_modified(String p_string) {
size.y = _parse_real_expression(value_editor[4]->get_text());
size.z = _parse_real_expression(value_editor[5]->get_text());
v = AABB(pos, size);
- _emit_changed_whole_or_field();
+ if (v != prev_v) {
+ _emit_changed_whole_or_field();
+ }
} break;
case Variant::TRANSFORM2D: {
@@ -1544,7 +1562,9 @@ void CustomPropertyEditor::_modified(String p_string) {
}
v = m;
- _emit_changed_whole_or_field();
+ if (v != prev_v) {
+ _emit_changed_whole_or_field();
+ }
} break;
case Variant::BASIS: {
@@ -1554,10 +1574,12 @@ void CustomPropertyEditor::_modified(String p_string) {
}
v = m;
- _emit_changed_whole_or_field();
+ if (v != prev_v) {
+ _emit_changed_whole_or_field();
+ }
} break;
- case Variant::TRANSFORM: {
+ case Variant::TRANSFORM3D: {
Basis basis;
for (int i = 0; i < 9; i++) {
basis.elements[i / 3][i % 3] = _parse_real_expression(value_editor[(i / 3) * 4 + i % 3]->get_text());
@@ -1569,8 +1591,10 @@ void CustomPropertyEditor::_modified(String p_string) {
origin.y = _parse_real_expression(value_editor[7]->get_text());
origin.z = _parse_real_expression(value_editor[11]->get_text());
- v = Transform(basis, origin);
- _emit_changed_whole_or_field();
+ v = Transform3D(basis, origin);
+ if (v != prev_v) {
+ _emit_changed_whole_or_field();
+ }
} break;
case Variant::COLOR: {
@@ -1578,7 +1602,9 @@ void CustomPropertyEditor::_modified(String p_string) {
case Variant::NODE_PATH: {
v = NodePath(value_editor[0]->get_text());
- emit_signal("variant_changed");
+ if (v != prev_v) {
+ emit_signal("variant_changed");
+ }
} break;
case Variant::DICTIONARY: {
} break;
@@ -1635,11 +1661,11 @@ void CustomPropertyEditor::_focus_enter() {
case Variant::RECT2:
case Variant::VECTOR3:
case Variant::PLANE:
- case Variant::QUAT:
+ case Variant::QUATERNION:
case Variant::AABB:
case Variant::TRANSFORM2D:
case Variant::BASIS:
- case Variant::TRANSFORM: {
+ case Variant::TRANSFORM3D: {
for (int i = 0; i < MAX_VALUE_EDITORS; ++i) {
if (value_editor[i]->has_focus()) {
focused_value_editor = i;
@@ -1654,25 +1680,7 @@ void CustomPropertyEditor::_focus_enter() {
}
void CustomPropertyEditor::_focus_exit() {
- switch (type) {
- case Variant::FLOAT:
- case Variant::STRING:
- case Variant::VECTOR2:
- case Variant::RECT2:
- case Variant::VECTOR3:
- case Variant::PLANE:
- case Variant::QUAT:
- case Variant::AABB:
- case Variant::TRANSFORM2D:
- case Variant::BASIS:
- case Variant::TRANSFORM: {
- for (int i = 0; i < MAX_VALUE_EDITORS; ++i) {
- value_editor[i]->select(0, 0);
- }
- } break;
- default: {
- }
- }
+ _modified(String());
}
void CustomPropertyEditor::config_action_buttons(const List<String> &p_strings) {
@@ -1773,7 +1781,7 @@ CustomPropertyEditor::CustomPropertyEditor() {
value_hboxes[hbox_idx]->add_child(value_editor[i]);
value_editor[i]->set_h_size_flags(Control::SIZE_EXPAND_FILL);
value_editor[i]->hide();
- value_editor[i]->connect("text_entered", callable_mp(this, &CustomPropertyEditor::_modified));
+ value_editor[i]->connect("text_submitted", callable_mp(this, &CustomPropertyEditor::_modified));
value_editor[i]->connect("focus_entered", callable_mp(this, &CustomPropertyEditor::_focus_enter));
value_editor[i]->connect("focus_exited", callable_mp(this, &CustomPropertyEditor::_focus_exit));
}
@@ -1823,7 +1831,6 @@ CustomPropertyEditor::CustomPropertyEditor() {
Vector<Variant> binds;
binds.push_back(i);
action_buttons[i]->connect("pressed", callable_mp(this, &CustomPropertyEditor::_action_pressed), binds);
- action_buttons[i]->set_flat(true);
}
color_picker = nullptr;
diff --git a/editor/property_editor.h b/editor/property_editor.h
index c6929f3b42..8a587b50b0 100644
--- a/editor/property_editor.h
+++ b/editor/property_editor.h
@@ -50,8 +50,8 @@ class PropertyValueEvaluator;
class CreateDialog;
class PropertySelector;
-class EditorResourceConversionPlugin : public Reference {
- GDCLASS(EditorResourceConversionPlugin, Reference);
+class EditorResourceConversionPlugin : public RefCounted {
+ GDCLASS(EditorResourceConversionPlugin, RefCounted);
protected:
static void _bind_methods();
diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp
index da798962e5..00652c02c8 100644
--- a/editor/property_selector.cpp
+++ b/editor/property_selector.cpp
@@ -52,7 +52,7 @@ void PropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) {
search_box->accept_event();
TreeItem *root = search_options->get_root();
- if (!root->get_children()) {
+ if (!root->get_first_child()) {
break;
}
@@ -125,18 +125,23 @@ void PropertySelector::_update_search() {
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("Vector2i", "EditorIcons"),
search_options->get_theme_icon("Rect2", "EditorIcons"),
+ search_options->get_theme_icon("Rect2i", "EditorIcons"),
search_options->get_theme_icon("Vector3", "EditorIcons"),
+ search_options->get_theme_icon("Vector3i", "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("Quaternion", "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("Transform3D", "EditorIcons"),
search_options->get_theme_icon("Color", "EditorIcons"),
- search_options->get_theme_icon("Path", "EditorIcons"),
+ search_options->get_theme_icon("NodePath", "EditorIcons"),
search_options->get_theme_icon("RID", "EditorIcons"),
- search_options->get_theme_icon("Object", "EditorIcons"),
+ search_options->get_theme_icon("MiniObject", "EditorIcons"),
+ search_options->get_theme_icon("Callable", "EditorIcons"),
+ search_options->get_theme_icon("Signal", "EditorIcons"),
search_options->get_theme_icon("Dictionary", "EditorIcons"),
search_options->get_theme_icon("Array", "EditorIcons"),
search_options->get_theme_icon("PackedByteArray", "EditorIcons"),
@@ -150,7 +155,7 @@ void PropertySelector::_update_search() {
for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
if (E->get().usage == PROPERTY_USAGE_CATEGORY) {
- if (category && category->get_children() == nullptr) {
+ if (category && category->get_first_child() == nullptr) {
memdelete(category); //old category was unused
}
category = search_options->create_item(root);
@@ -192,7 +197,7 @@ void PropertySelector::_update_search() {
item->set_selectable(0, true);
}
- if (category && category->get_children() == nullptr) {
+ if (category && category->get_first_child() == nullptr) {
memdelete(category); //old category was unused
}
} else {
@@ -225,7 +230,7 @@ void PropertySelector::_update_search() {
for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
if (E->get().name.begins_with("*")) {
- if (category && category->get_children() == nullptr) {
+ if (category && category->get_first_child() == nullptr) {
memdelete(category); //old category was unused
}
category = search_options->create_item(root);
@@ -316,12 +321,12 @@ void PropertySelector::_update_search() {
}
}
- if (category && category->get_children() == nullptr) {
+ if (category && category->get_first_child() == nullptr) {
memdelete(category); //old category was unused
}
}
- get_ok_button()->set_disabled(root->get_children() == nullptr);
+ get_ok_button()->set_disabled(root->get_first_child() == nullptr);
}
void PropertySelector::_confirmed() {
diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp
index 7f720d65d0..e8e13bab21 100644
--- a/editor/quick_open.cpp
+++ b/editor/quick_open.cpp
@@ -102,7 +102,7 @@ void EditorQuickOpen::_update_search() {
ti->set_icon(0, *icons.lookup_ptr(entries[i].path.get_extension()));
}
- TreeItem *to_select = root->get_children();
+ TreeItem *to_select = root->get_first_child();
to_select->select(0);
to_select->set_as_cursor(0);
search_options->scroll_to_item(to_select);
@@ -170,7 +170,7 @@ void EditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) {
if (allow_multi_select) {
TreeItem *root = search_options->get_root();
- if (!root->get_children()) {
+ if (!root->get_first_child()) {
break;
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index a6d1a118b8..8d6b7f3389 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/io/resource_saver.h"
+#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_feature_profile.h"
@@ -1832,7 +1833,7 @@ bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const {
TreeItem *item = needs_check.back()->get();
needs_check.pop_back();
- TreeItem *child = item->get_children();
+ TreeItem *child = item->get_first_child();
is_branch_collapsed = item->is_collapsed() && child;
if (is_branch_collapsed) {
@@ -1856,7 +1857,7 @@ void SceneTreeDock::_set_collapsed_recursive(TreeItem *p_item, bool p_collapsed)
item->set_collapsed(p_collapsed);
- TreeItem *child = item->get_children();
+ TreeItem *child = item->get_first_child();
while (child) {
to_collapse.push_back(child);
child = child->get_next();
@@ -2586,14 +2587,16 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
}
}
- if (profile_allow_script_editing) {
+ if (profile_allow_editing) {
menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/cut_node"), TOOL_CUT);
menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/copy_node"), TOOL_COPY);
if (selection.size() == 1 && !node_clipboard.is_empty()) {
menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/paste_node"), TOOL_PASTE);
}
menu->add_separator();
+ }
+ if (profile_allow_script_editing) {
bool add_separator = false;
if (full_selection.size() == 1) {
@@ -2621,7 +2624,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
}
}
- if (add_separator) {
+ if (add_separator && profile_allow_editing) {
menu->add_separator();
}
}
@@ -2956,6 +2959,7 @@ void SceneTreeDock::_clear_clipboard() {
void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap) {
List<PropertyInfo> props;
p_node->get_property_list(&props);
+ bool is_instanced = EditorPropertyRevert::may_node_be_in_instance(p_node);
for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
@@ -2966,6 +2970,15 @@ void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap)
if (v.is_ref()) {
RES res = v;
if (res.is_valid()) {
+ if (is_instanced) {
+ Variant orig;
+ if (EditorPropertyRevert::get_instanced_node_original_property(p_node, E->get().name, orig)) {
+ if (!EditorPropertyRevert::is_node_property_different(p_node, v, orig)) {
+ continue;
+ }
+ }
+ }
+
if ((res->get_path() == "" || res->get_path().find("::") > -1) && !r_remap.has(res)) {
_create_remap_for_resource(res, r_remap);
}
@@ -3016,7 +3029,16 @@ void SceneTreeDock::_bind_methods() {
ADD_SIGNAL(MethodInfo("node_created", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
}
+SceneTreeDock *SceneTreeDock::singleton = nullptr;
+
+void SceneTreeDock::_update_configuration_warning() {
+ if (singleton) {
+ MessageQueue::get_singleton()->push_callable(callable_mp(singleton->scene_tree, &SceneTreeEditor::update_warning));
+ }
+}
+
SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data) {
+ singleton = this;
set_name("Scene");
editor = p_editor;
edited_scene = nullptr;
@@ -3032,7 +3054,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
ED_SHORTCUT("scene_tree/rename", TTR("Rename"), KEY_F2);
ED_SHORTCUT("scene_tree/batch_rename", TTR("Batch Rename"), KEY_MASK_SHIFT | KEY_F2);
ED_SHORTCUT("scene_tree/add_child_node", TTR("Add Child Node"), KEY_MASK_CMD | KEY_A);
- ED_SHORTCUT("scene_tree/instance_scene", TTR("Instance Child Scene"));
+ ED_SHORTCUT("scene_tree/instance_scene", TTR("Instance Child Scene"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_A);
ED_SHORTCUT("scene_tree/expand_collapse_all", TTR("Expand/Collapse All"));
ED_SHORTCUT("scene_tree/cut_node", TTR("Cut"), KEY_MASK_CMD | KEY_X);
ED_SHORTCUT("scene_tree/copy_node", TTR("Copy"), KEY_MASK_CMD | KEY_C);
@@ -3207,9 +3229,12 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
EDITOR_DEF("interface/editors/show_scene_tree_root_selection", true);
EDITOR_DEF("interface/editors/derive_script_globals_by_name", true);
EDITOR_DEF("_use_favorites_root_selection", false);
+
+ Resource::_update_configuration_warning = _update_configuration_warning;
}
SceneTreeDock::~SceneTreeDock() {
+ singleton = nullptr;
if (!node_clipboard.is_empty()) {
_clear_clipboard();
}
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index aa62c93cb5..53f31375f8 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -244,6 +244,9 @@ class SceneTreeDock : public VBoxContainer {
bool profile_allow_editing;
bool profile_allow_script_editing;
+ static SceneTreeDock *singleton;
+ static void _update_configuration_warning();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index ec37fa53b3..a5620f8cc5 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -277,7 +277,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll
}
Ref<Texture2D> icon_temp;
- auto signal_temp = BUTTON_SIGNALS;
+ SceneTreeEditorButton signal_temp = BUTTON_SIGNALS;
if (num_connections >= 1 && num_groups >= 1) {
icon_temp = get_theme_icon("SignalsAndGroups", "EditorIcons");
} else if (num_connections >= 1) {
@@ -540,6 +540,10 @@ void SceneTreeEditor::_update_tree(bool p_scroll_to_selected) {
return;
}
+ if (tree->is_editing()) {
+ return;
+ }
+
updating_tree = true;
tree->clear();
if (get_scene_node()) {
@@ -665,7 +669,7 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->connect("tree_process_mode_changed", callable_mp(this, &SceneTreeEditor::_tree_process_mode_changed));
get_tree()->connect("node_removed", callable_mp(this, &SceneTreeEditor::_node_removed));
get_tree()->connect("node_renamed", callable_mp(this, &SceneTreeEditor::_node_renamed));
- get_tree()->connect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed));
+ get_tree()->connect("node_configuration_warning_changed", callable_mp(this, &SceneTreeEditor::_warning_changed), varray(), CONNECT_DEFERRED);
tree->connect("item_collapsed", callable_mp(this, &SceneTreeEditor::_cell_collapsed));
@@ -695,7 +699,7 @@ TreeItem *SceneTreeEditor::_find(TreeItem *p_node, const NodePath &p_path) {
return p_node;
}
- TreeItem *children = p_node->get_children();
+ TreeItem *children = p_node->get_first_child();
while (children) {
TreeItem *n = _find(children, p_path);
if (n) {
@@ -879,7 +883,7 @@ void SceneTreeEditor::_update_selection(TreeItem *item) {
item->deselect(0);
}
- TreeItem *c = item->get_children();
+ TreeItem *c = item->get_first_child();
while (c) {
_update_selection(c);
@@ -1102,6 +1106,9 @@ void SceneTreeEditor::_rmb_select(const Vector2 &p_pos) {
emit_signal("rmb_pressed", tree->get_screen_transform().xform(p_pos));
}
+void SceneTreeEditor::update_warning() {
+ _warning_changed(nullptr);
+}
void SceneTreeEditor::_warning_changed(Node *p_for_node) {
//should use a timer
update_timer->start();
@@ -1122,9 +1129,9 @@ void SceneTreeEditor::_bind_methods() {
ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node);
ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &SceneTreeEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SceneTreeEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &SceneTreeEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &SceneTreeEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &SceneTreeEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &SceneTreeEditor::drop_data_fw);
ClassDB::bind_method(D_METHOD("update_tree"), &SceneTreeEditor::update_tree);
diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h
index fd5157f04f..acd49e8d92 100644
--- a/editor/scene_tree_editor.h
+++ b/editor/scene_tree_editor.h
@@ -43,7 +43,7 @@ class SceneTreeEditor : public Control {
EditorSelection *editor_selection;
- enum {
+ enum SceneTreeEditorButton {
BUTTON_SUBSCENE = 0,
BUTTON_VISIBILITY = 1,
BUTTON_SCRIPT = 2,
@@ -157,6 +157,8 @@ public:
Tree *get_scene_tree() { return tree; }
+ void update_warning();
+
SceneTreeEditor(bool p_label = true, bool p_can_rename = false, bool p_can_open_instance = false);
~SceneTreeEditor();
};
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index f3addd8904..01743bccab 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -31,9 +31,9 @@
#include "script_create_dialog.h"
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
#include "core/object/script_language.h"
-#include "core/os/file_access.h"
#include "core/string/string_builder.h"
#include "editor/create_dialog.h"
#include "editor/editor_node.h"
@@ -602,7 +602,7 @@ void ScriptCreateDialog::_path_changed(const String &p_path) {
_update_dialog();
}
-void ScriptCreateDialog::_path_entered(const String &p_path) {
+void ScriptCreateDialog::_path_submitted(const String &p_path) {
ok_pressed();
}
@@ -731,13 +731,13 @@ void ScriptCreateDialog::_update_dialog() {
get_ok_button()->set_disabled(!script_ok);
- Callable entered_call = callable_mp(this, &ScriptCreateDialog::_path_entered);
+ Callable entered_call = callable_mp(this, &ScriptCreateDialog::_path_submitted);
if (script_ok) {
- if (!file_path->is_connected("text_entered", entered_call)) {
- file_path->connect("text_entered", entered_call);
+ if (!file_path->is_connected("text_submitted", entered_call)) {
+ file_path->connect("text_submitted", entered_call);
}
- } else if (file_path->is_connected("text_entered", entered_call)) {
- file_path->disconnect("text_entered", entered_call);
+ } else if (file_path->is_connected("text_submitted", entered_call)) {
+ file_path->disconnect("text_submitted", entered_call);
}
}
@@ -838,7 +838,6 @@ ScriptCreateDialog::ScriptCreateDialog() {
parent_search_button->connect("pressed", callable_mp(this, &ScriptCreateDialog::_browse_class_in_tree));
hb->add_child(parent_search_button);
parent_browse_button = memnew(Button);
- parent_browse_button->set_flat(true);
parent_browse_button->connect("pressed", callable_mp(this, &ScriptCreateDialog::_browse_path), varray(true, false));
hb->add_child(parent_browse_button);
gc->add_child(memnew(Label(TTR("Inherits:"))));
@@ -877,7 +876,6 @@ ScriptCreateDialog::ScriptCreateDialog() {
file_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb->add_child(file_path);
path_button = memnew(Button);
- path_button->set_flat(true);
path_button->connect("pressed", callable_mp(this, &ScriptCreateDialog::_browse_path), varray(false, true));
hb->add_child(path_button);
gc->add_child(memnew(Label(TTR("Path:"))));
diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h
index d6417b9d33..a020be0478 100644
--- a/editor/script_create_dialog.h
+++ b/editor/script_create_dialog.h
@@ -105,7 +105,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
void _path_hbox_sorted();
bool _can_be_built_in();
void _path_changed(const String &p_path = String());
- void _path_entered(const String &p_path = String());
+ void _path_submitted(const String &p_path = String());
void _lang_changed(int l = 0);
void _built_in_pressed();
bool _validate_parent(const String &p_string);
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 81af4996ed..c05a3c2f89 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -235,8 +235,8 @@ void EditorSettingsDialog::_update_shortcuts() {
// Before clearing the tree, take note of which categories are collapsed so that this state can be maintained when the tree is repopulated.
Map<String, bool> collapsed;
- if (shortcuts->get_root() && shortcuts->get_root()->get_children()) {
- for (TreeItem *item = shortcuts->get_root()->get_children(); item; item = item->get_next()) {
+ if (shortcuts->get_root() && shortcuts->get_root()->get_first_child()) {
+ for (TreeItem *item = shortcuts->get_root()->get_first_child(); item; item = item->get_next()) {
collapsed[item->get_text(0)] = item->is_collapsed();
}
}
@@ -261,25 +261,22 @@ void EditorSettingsDialog::_update_shortcuts() {
for (OrderedHashMap<StringName, InputMap::Action>::Element E = action_map.front(); E; E = E.next()) {
String action_name = E.key();
- if (!shortcut_filter.is_subsequence_ofi(action_name)) {
- continue;
- }
-
InputMap::Action action = E.get();
Array events; // Need to get the list of events into an array so it can be set as metadata on the item.
Vector<String> event_strings;
- List<Ref<InputEvent>> defaults = InputMap::get_singleton()->get_builtins().find(action_name).value();
- // Remove all non-key events from the defaults.
- for (List<Ref<InputEvent>>::Element *I = defaults.front(); I; I = I->next()) {
+ List<Ref<InputEvent>> all_default_events = InputMap::get_singleton()->get_builtins().find(action_name).value();
+ List<Ref<InputEventKey>> key_default_events;
+ // Remove all non-key events from the defaults. Only check keys, since we are in the editor.
+ for (List<Ref<InputEvent>>::Element *I = all_default_events.front(); I; I = I->next()) {
Ref<InputEventKey> k = I->get();
- if (k.is_null()) {
- I->erase();
+ if (k.is_valid()) {
+ key_default_events.push_back(k);
}
}
- bool same_as_defaults = defaults.size() == action.inputs.size(); // Initially this is set to just whether the arrays are equal. Later we check the events if needed.
+ bool same_as_defaults = key_default_events.size() == action.inputs.size(); // Initially this is set to just whether the arrays are equal. Later we check the events if needed.
int count = 0;
for (List<Ref<InputEvent>>::Element *I = action.inputs.front(); I; I = I->next()) {
@@ -288,12 +285,8 @@ void EditorSettingsDialog::_update_shortcuts() {
event_strings.push_back(I->get()->as_text());
// Only check if the events have been the same so far - once one fails, we don't need to check any more.
- if (same_as_defaults) {
- Ref<InputEventKey> k = defaults[count];
- // Only check keys, since we are in the editor.
- if (k.is_valid() && !defaults[count]->shortcut_match(I->get())) {
- same_as_defaults = false;
- }
+ if (same_as_defaults && !key_default_events[count]->shortcut_match(I->get())) {
+ same_as_defaults = false;
}
count++;
}
@@ -301,6 +294,10 @@ void EditorSettingsDialog::_update_shortcuts() {
// Join the text of the events with a delimiter so they can all be displayed in one cell.
String events_display_string = event_strings.is_empty() ? "None" : String("; ").join(event_strings);
+ if (!shortcut_filter.is_subsequence_ofi(action_name) && (events_display_string == "None" || !shortcut_filter.is_subsequence_ofi(events_display_string))) {
+ continue;
+ }
+
TreeItem *item = shortcuts->create_item(common_section);
item->set_text(0, action_name);
item->set_text(1, events_display_string);
@@ -383,7 +380,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() == nullptr) {
+ if (section->get_first_child() == nullptr) {
root->remove_child(section);
}
}
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index ebef5be9ed..1893c6b6bb 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -199,7 +199,7 @@ protected:
pinfo.type = Variant::TRANSFORM2D;
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
- pinfo.type = Variant::TRANSFORM;
+ pinfo.type = Variant::TRANSFORM3D;
} break;
case RS::GLOBAL_VAR_TYPE_MAT4: {
pinfo.type = Variant::PACKED_INT32_ARRAY;
@@ -326,7 +326,7 @@ static Variant create_var(RS::GlobalVariableType p_type) {
return Transform2D();
}
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
- return Transform();
+ return Transform3D();
}
case RS::GLOBAL_VAR_TYPE_MAT4: {
Vector<real_t> xform;
diff --git a/editor/translations/af.po b/editor/translations/af.po
index 1b952d51b6..40669c01fb 100644
--- a/editor/translations/af.po
+++ b/editor/translations/af.po
@@ -1151,6 +1151,10 @@ msgstr "Verander Woordeboek Waarde"
msgid "Thanks from the Godot community!"
msgstr "Dankie van die Godot gemeenskap!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Enjin bydraers"
@@ -2589,8 +2593,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -3005,6 +3010,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -10122,7 +10131,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12196,10 +12205,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/ar.po b/editor/translations/ar.po
index 9051e2cf82..ceeda7a037 100644
--- a/editor/translations/ar.po
+++ b/editor/translations/ar.po
@@ -55,8 +55,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-16 07:52+0000\n"
-"Last-Translator: Hatim Jamal <hatimjamal8@gmail.com>\n"
+"PO-Revision-Date: 2021-05-07 02:12+0000\n"
+"Last-Translator: ILG - Game <moegypt277@gmail.com>\n"
"Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/"
"godot/ar/>\n"
"Language: ar\n"
@@ -65,7 +65,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1154,6 +1154,10 @@ msgstr "تغيير قيمة ÙÙŠ القاموس"
msgid "Thanks from the Godot community!"
msgstr "شكراً من مجتمع غودوت!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "المسهامين ÙÙŠ محرك غودوت"
@@ -2565,9 +2569,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "غير قادر علي تحميل النص البرمجي Ù„Ù„Ø¥Ø¶Ø§ÙØ© من المسار: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"غير قادر علي تحميل النص البرمجي Ø§Ù„Ø¥Ø¶Ø§ÙØ¨ من المسار: '%s' يبدو أن Ø´ÙÙØ±Ø© "
"البرمجية يوجد بها أخطاء , الرجاء مراجعة الشÙÙØ±Ø© البرمجية."
@@ -3016,6 +3022,10 @@ msgid "About"
msgstr "حول"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "تشغيل المشروع."
@@ -3826,9 +3836,8 @@ msgid "Duplicate..."
msgstr "تكرير..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Move to Trash"
-msgstr "نقل التحميل التلقائي"
+msgstr "نقل الي سلة Ø§Ù„Ù…Ø­Ø°ÙˆÙØ§Øª"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
@@ -3939,19 +3948,16 @@ msgid "Searching..."
msgstr "جاري البحث..."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d match in %d file."
-msgstr "%d تطابقات."
+msgstr "d% تطابق ÙÙŠ d% الملÙ."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d file."
-msgstr "%d تطابقات."
+msgstr "d% تطابقات ÙÙŠ d% الملÙ."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d files."
-msgstr "%d تطابقات."
+msgstr "d% تطابقات ÙÙŠ d% الملÙ."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -4088,18 +4094,16 @@ msgid "Saving..."
msgstr "جاري Ø§Ù„Ø­ÙØ¸..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "تحديد الوضع"
+msgstr "حدد المستورد"
#: editor/import_defaults_editor.cpp
msgid "Importer:"
msgstr "المستورد:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "تحميل Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ"
+msgstr "اعادة التعيين Ù„Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠØ§Øª"
#: editor/import_dock.cpp
msgid "Keep File (No Import)"
@@ -4666,7 +4670,7 @@ msgstr "أدوات الرسم المتحرك"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation"
-msgstr "الرسم المتحرك"
+msgstr "رسوم متحركة"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Edit Transitions..."
@@ -5071,9 +5075,8 @@ msgid "Got:"
msgstr "ما تم الحصول عليه:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Failed SHA-256 hash check"
-msgstr "ÙØ´Ù„ التاكد من ترميز sha256"
+msgstr "ÙØ´Ù„ ÙÙŠ تجزئة SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5238,6 +5241,7 @@ msgstr ""
"[0.0،1.0]."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
+#, fuzzy
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr "تم تجميع محرر Godot دون دعم لتتبع الأشعة. لا يمكن بناء خرائط الإضاءة."
@@ -8354,7 +8358,7 @@ msgstr "تنقل"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Bitmask"
-msgstr "قناع Ø§Ù„Ø¨ÙØª"
+msgstr "قناع-Ø§Ù„Ø¨ÙØª"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Priority"
@@ -10146,7 +10150,7 @@ msgstr "زر Ø§Ù„ÙØ£Ø±Ø©"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"اسم ÙØ¹Ø§Ù„ية غير صحيح. لا يمكن أن يكون ÙØ§Ø±ØºØ§Ù‹ أو يتضمن '/'ØŒ ':'ØŒ '='ØŒ '\\' أو "
@@ -12204,12 +12208,24 @@ msgstr ""
"لم يتم تنزيل قالب بناء Android لهذا المشروع. نزّل واحداً من قائمة المشروع."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Ù…Ùنقح أخطاء Ù…ÙØªØ§Ø­ المتجر keystore غير Ù…Ùهيئ ÙÙŠ إعدادت Ø§Ù„Ù…ÙØ­Ø±Ø± أو ÙÙŠ الإعدادات "
"الموضوعة Ø³Ù„ÙØ§Ù‹."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr "تحرر مخزن Ø§Ù„Ù…ÙØ§ØªÙŠØ­ غير Ù…Ùهيئ بشكل صحيح ÙÙŠ إعدادت المسبقة للتصدير."
diff --git a/editor/translations/az.po b/editor/translations/az.po
new file mode 100644
index 0000000000..32efc852f8
--- /dev/null
+++ b/editor/translations/az.po
@@ -0,0 +1,12578 @@
+# Azerbaijani translation of the Godot Engine editor.
+# Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
+# Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
+# This file is distributed under the same license as the Godot source code.
+#
+# Jafar Tarverdiyev <cefertarverdiyevv@gmail.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: Godot Engine editor\n"
+"PO-Revision-Date: 2021-05-14 11:20+0000\n"
+"Last-Translator: Jafar Tarverdiyev <cefertarverdiyevv@gmail.com>\n"
+"Language-Team: Azerbaijani <https://hosted.weblate.org/projects/godot-engine/"
+"godot/az/>\n"
+"Language: az\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8-bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.7-dev\n"
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+#: modules/visual_script/visual_script_builtin_funcs.cpp
+msgid "Invalid type argument to convert(), use TYPE_* constants."
+msgstr ""
+"convert() üçün uyğun olmayan növdə arqument, TYPE_* sabitlərini istifadə "
+"edin."
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+msgid "Expected a string of length 1 (a character)."
+msgstr "1 uzunluğunda mətin (bir işarə) gözlənilir."
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+#: modules/mono/glue/gd_glue.cpp
+#: modules/visual_script/visual_script_builtin_funcs.cpp
+msgid "Not enough bytes for decoding bytes, or invalid format."
+msgstr ""
+"Baytların dekodlanması üçün kifayət qədər Bayt yoxdur, və ya uyğun olmayan "
+"format."
+
+#: core/math/expression.cpp
+msgid "Invalid input %i (not passed) in expression"
+msgstr "İfadədə uyğunsuz giriş %d (ötürülmədi)"
+
+#: core/math/expression.cpp
+msgid "self can't be used because instance is null (not passed)"
+msgstr "self istifadə edilə bilməz, çünki \"instance\" null-dur (ötürülmədi)"
+
+#: core/math/expression.cpp
+#, fuzzy
+msgid "Invalid operands to operator %s, %s and %s."
+msgstr "%s, %s və %s operatoruna səhv operandlar."
+
+#: core/math/expression.cpp
+#, fuzzy
+msgid "Invalid index of type %s for base type %s"
+msgstr "%s baza növü üçün %s növünün səhv indeksi"
+
+#: core/math/expression.cpp
+msgid "Invalid named index '%s' for base type %s"
+msgstr "%s baza tipi üçün '% s' adlı etibarsız indeks"
+
+#: core/math/expression.cpp
+msgid "Invalid arguments to construct '%s'"
+msgstr "'%s' qurmaq üçün etibarsız arqumentlər"
+
+#: core/math/expression.cpp
+#, fuzzy
+msgid "On call to '%s':"
+msgstr "'%s'-ə çağırış zamanı:"
+
+#: core/ustring.cpp
+msgid "B"
+msgstr "B"
+
+#: core/ustring.cpp
+msgid "KiB"
+msgstr "KiB"
+
+#: core/ustring.cpp
+msgid "MiB"
+msgstr "MiB"
+
+#: core/ustring.cpp
+msgid "GiB"
+msgstr "GiB"
+
+#: core/ustring.cpp
+msgid "TiB"
+msgstr "TiB"
+
+#: core/ustring.cpp
+msgid "PiB"
+msgstr "PiB"
+
+#: core/ustring.cpp
+msgid "EiB"
+msgstr "EiB"
+
+#: editor/animation_bezier_editor.cpp
+#, fuzzy
+msgid "Free"
+msgstr "Sərbəst"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Balanced"
+msgstr "Balanslı"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Mirror"
+msgstr "Güzgü"
+
+#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp
+msgid "Time:"
+msgstr "Vaxt:"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Value:"
+msgstr "Dəyər:"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Insert Key Here"
+msgstr "Açar sözü buraya daxil edin"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Duplicate Selected Key(s)"
+msgstr "Seçili açar(lar)-ı çoxalt"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Delete Selected Key(s)"
+msgstr "Seçili açar(lar)ı sil"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Add Bezier Point"
+msgstr "Bezier Nöqtəsi əlavə edin"
+
+#: editor/animation_bezier_editor.cpp
+#, fuzzy
+msgid "Move Bezier Points"
+msgstr "Bezier Nöqtələrini Köçür"
+
+#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
+msgid "Anim Duplicate Keys"
+msgstr "Animasya açarlarını çoxalt"
+
+#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
+msgid "Anim Delete Keys"
+msgstr "Animasya açarlarını sil"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Keyframe Time"
+msgstr "Animasya Açar-kadr(keyframe) vaxtını dəyiş"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Transition"
+msgstr "Animasya keçidini dəyiş"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Anim Change Transform"
+msgstr "Animasya transformasiyasını dəyiş"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Keyframe Value"
+msgstr "Animasya Açar-kadr (Keyframe) dəyərini dəyiş"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Call"
+msgstr "Animasiya Dəyişim Çağırısı"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Anim Multi Change Keyframe Time"
+msgstr "Animasya Açar-kadr(Keyframe) vaxtını çoxlu(multiple) dəyiş"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Transition"
+msgstr "Animasya keçidinin çoxlu(Multi) dəyişimi"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Transform"
+msgstr "Animasya Transformasiyasinin çoxlu(Multi) deyişimi"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Keyframe Value"
+msgstr "Animasya Açar-Kadr(keyframe) dəyərinin Çoxlu (Multi) Dəyişimi"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Anim Multi Change Call"
+msgstr "Animasya Çağırışının çoxlu(Multi) Dəyişimi"
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Length"
+msgstr "Animasya Uzunluğunu Dəyiş"
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+#, fuzzy
+msgid "Change Animation Loop"
+msgstr "Animasya Döngüsünü Dəyiş"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Property Track"
+msgstr "XassÉ™"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "3D Transform Track"
+msgstr "3D Transformasya izi"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Call Method Track"
+msgstr "Metod çağırma izi"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Bezier Curve Track"
+msgstr "Bezier Æyrisi izi"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Audio Playback Track"
+msgstr "Səs oxutma izi"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Animation Playback Track"
+msgstr "Animasya oynatma izi"
+
+#: editor/animation_track_editor.cpp
+msgid "Animation length (frames)"
+msgstr "Animasiya uzunluÄŸu (kadrlar)"
+
+#: editor/animation_track_editor.cpp
+msgid "Animation length (seconds)"
+msgstr "Animasiya uzunluğu (saniyələr)"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Add Track"
+msgstr "İz əlavə et"
+
+#: editor/animation_track_editor.cpp
+msgid "Animation Looping"
+msgstr "Animasiya Döngüsü"
+
+#: editor/animation_track_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Functions:"
+msgstr "Funksiyalar:"
+
+#: editor/animation_track_editor.cpp
+msgid "Audio Clips:"
+msgstr "Audio kliplər:"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Clips:"
+msgstr "Animasiyalar:"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Change Track Path"
+msgstr "İzin yolunu dəyiş"
+
+#: editor/animation_track_editor.cpp
+msgid "Toggle this track on/off."
+msgstr "Bu izi açın / söndürün."
+
+#: editor/animation_track_editor.cpp
+msgid "Update Mode (How this property is set)"
+msgstr "Yeniləmə rejimi (bu xüsusiyyət necə qurulur)"
+
+#: editor/animation_track_editor.cpp
+msgid "Interpolation Mode"
+msgstr "İnterpolasiya rejimi"
+
+#: editor/animation_track_editor.cpp
+msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
+msgstr "Döngü Bükmə Rejimi (Döngüdə başlayan interpolasyanın sonu)"
+
+#: editor/animation_track_editor.cpp
+msgid "Remove this track."
+msgstr "Bu izi sil."
+
+#: editor/animation_track_editor.cpp
+msgid "Time (s): "
+msgstr "Vaxt (sn): "
+
+#: editor/animation_track_editor.cpp
+msgid "Toggle Track Enabled"
+msgstr "İz funksiyasını aktiv edin"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Continuous"
+msgstr "Davamlı"
+
+#: editor/animation_track_editor.cpp
+msgid "Discrete"
+msgstr "Ayrı"
+
+#: editor/animation_track_editor.cpp
+msgid "Trigger"
+msgstr "Tətikləyici"
+
+#: editor/animation_track_editor.cpp
+msgid "Capture"
+msgstr "Tutmaq"
+
+#: editor/animation_track_editor.cpp
+msgid "Nearest"
+msgstr "Æn yaxın"
+
+#: editor/animation_track_editor.cpp editor/plugins/curve_editor_plugin.cpp
+#: editor/property_editor.cpp
+msgid "Linear"
+msgstr "Xətti"
+
+#: editor/animation_track_editor.cpp
+msgid "Cubic"
+msgstr "Kubik"
+
+#: editor/animation_track_editor.cpp
+msgid "Clamp Loop Interp"
+msgstr "Döngü Aradəyərləndirməsini(İnterp) Qısqacla"
+
+#: editor/animation_track_editor.cpp
+msgid "Wrap Loop Interp"
+msgstr "Döngü Aradəyərləndirməsini(İnterp) Bük"
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert Key"
+msgstr "Açar daxil et"
+
+#: editor/animation_track_editor.cpp
+msgid "Duplicate Key(s)"
+msgstr "Açar(lar)ı çoxalt"
+
+#: editor/animation_track_editor.cpp
+msgid "Delete Key(s)"
+msgstr "Açar(lar)ı sil"
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Update Mode"
+msgstr "Animasya Yeniləmə Rejimini Dəyiş"
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Interpolation Mode"
+msgstr "Animasya Aradəyərləndirmə(İnterpolation) Rejimini Dəyiş"
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Loop Mode"
+msgstr "Animasya Döngü Rejimini Dəyiş"
+
+#: editor/animation_track_editor.cpp
+msgid "Remove Anim Track"
+msgstr "Animasya İzini Sil"
+
+#: editor/animation_track_editor.cpp
+msgid "Create NEW track for %s and insert key?"
+msgstr "%s üçün YENİ iz yaradılsın və açar daxil edilsin?"
+
+#: editor/animation_track_editor.cpp
+msgid "Create %d NEW tracks and insert keys?"
+msgstr "%d YENİ izlər yarat və açarları daxil et?"
+
+#: editor/animation_track_editor.cpp editor/create_dialog.cpp
+#: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_create_dialog.cpp
+#: modules/visual_script/visual_script_editor.cpp
+#, fuzzy
+msgid "Create"
+msgstr "Yarat"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert"
+msgstr "Animasiya Daxil Et"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "AnimationPlayer can't animate itself, only other players."
+msgstr "AnimationPlayer özünü canlandıra bilməz, yalnız digər playerlər."
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Create & Insert"
+msgstr "Animasiya yaradın və əlavə edin"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert Track & Key"
+msgstr "Animasya izi və açarı əlavə edin"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert Key"
+msgstr "Animasya açarı daxil edin"
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Step"
+msgstr "Animasiya Addımını Dəyişdirin"
+
+#: editor/animation_track_editor.cpp
+msgid "Rearrange Tracks"
+msgstr "İzləri yenidən sırala"
+
+#: editor/animation_track_editor.cpp
+msgid "Transform tracks only apply to Spatial-based nodes."
+msgstr ""
+"Transformasya izlÉ™ri yalnız MÉ™kan Æsaslı(Spatial-Based) düyünlÉ™rÉ™ uyÄŸulana "
+"bilər."
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid ""
+"Audio tracks can only point to nodes of type:\n"
+"-AudioStreamPlayer\n"
+"-AudioStreamPlayer2D\n"
+"-AudioStreamPlayer3D"
+msgstr ""
+"Audio treklər yalnız bu növ düyünlərə işarə edə bilər:\n"
+"-AudioStreamPlayer\n"
+"-AudioStreamPlayer2D\n"
+"-AudioStreamPlayer3D"
+
+#: editor/animation_track_editor.cpp
+msgid "Animation tracks can only point to AnimationPlayer nodes."
+msgstr ""
+"Animasiya parçaları yalnız AnimationPlayer düyünlərini işarə edə bilər."
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "An animation player can't animate itself, only other players."
+msgstr "Animasiya pleyeri özünü canlandıra bilməz, yalnız digər pleyerlər."
+
+#: editor/animation_track_editor.cpp
+msgid "Not possible to add a new track without a root"
+msgstr "Kök olmadan yeni iz əlavə etmək mümkün deyil"
+
+#: editor/animation_track_editor.cpp
+msgid "Invalid track for Bezier (no suitable sub-properties)"
+msgstr "Bezier üçün səhv iz (uyğun alt-xüsusiyyətlər yoxdur)"
+
+#: editor/animation_track_editor.cpp
+msgid "Add Bezier Track"
+msgstr "Bezier iz əlavə edin"
+
+#: editor/animation_track_editor.cpp
+msgid "Track path is invalid, so can't add a key."
+msgstr "Yol (Track path) keçərsizdir, buna görə açar əlavə edə bilməzsiniz."
+
+#: editor/animation_track_editor.cpp
+msgid "Track is not of type Spatial, can't insert key"
+msgstr "İz Məkan tipli deyil, açarı əlavə etmək mümkün deyil"
+
+#: editor/animation_track_editor.cpp
+msgid "Add Transform Track Key"
+msgstr "Transformasya İz Açarı əlavə edin"
+
+#: editor/animation_track_editor.cpp
+msgid "Add Track Key"
+msgstr "İz Açarı ÆlavÉ™ Et"
+
+#: editor/animation_track_editor.cpp
+msgid "Track path is invalid, so can't add a method key."
+msgstr ""
+"Yol (Track path) keçərsizdir, buna görə metod açarı əlavə edə bilməzsiniz."
+
+#: editor/animation_track_editor.cpp
+msgid "Add Method Track Key"
+msgstr "Metod İz Açarı əlavə edin"
+
+#: editor/animation_track_editor.cpp
+msgid "Method not found in object: "
+msgstr "Metod obyektdə tapılmadı: "
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Move Keys"
+msgstr "Animasya Köçürmə Açarları"
+
+#: editor/animation_track_editor.cpp
+msgid "Clipboard is empty"
+msgstr "Panel(Clipboard) boÅŸdur"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Paste Tracks"
+msgstr "İzləri yapışdır"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Scale Keys"
+msgstr "Animasya Açarlarını Ölçülə"
+
+#: editor/animation_track_editor.cpp
+msgid ""
+"This option does not work for Bezier editing, as it's only a single track."
+msgstr "Bu seçim Bezier redaktəsi üçün işləmir, çünki yalnız bir izlidir."
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid ""
+"This animation belongs to an imported scene, so changes to imported tracks "
+"will not be saved.\n"
+"\n"
+"To enable the ability to add custom tracks, navigate to the scene's import "
+"settings and set\n"
+"\"Animation > Storage\" to \"Files\", enable \"Animation > Keep Custom Tracks"
+"\", then re-import.\n"
+"Alternatively, use an import preset that imports animations to separate "
+"files."
+msgstr ""
+"Bu animasiya idxal olunan səhnəyə məxsusdur, buna görə də idxal olunan izdə "
+"edilən dəyişikliklər yadda saxlanılmayacaq.\n"
+"\n"
+"Xüsusi iz əlavə etmək imkanını təmin etmək üçün, səhnənin idxal ayarlarına "
+"istiqamətlənin və təyin edin\n"
+"\"Animation > Storage\" to \"Files\", aktivləşdir \"Animation > Keep Custom "
+"Tracks\", sonra yenidən idxal.\n"
+"Alternativ olaraq, faylları ayırmaq üçün animasiya idxal edən əvvəlcədən "
+"qurulmuÅŸ idxaldan(import preset) istifadÉ™ edin."
+
+#: editor/animation_track_editor.cpp
+msgid "Warning: Editing imported animation"
+msgstr "Xəbərdarlıq: İdxal edilmiş animasiyanın redaktəsi"
+
+#: editor/animation_track_editor.cpp
+msgid "Select an AnimationPlayer node to create and edit animations."
+msgstr "Animasiya yaratmaq və redaktə etmək üçün AnimationPlayer düyünü seçin."
+
+#: editor/animation_track_editor.cpp
+msgid "Only show tracks from nodes selected in tree."
+msgstr "Yalnız ağacda seçilən düyünlərdən izləri göstər."
+
+#: editor/animation_track_editor.cpp
+msgid "Group tracks by node or display them as plain list."
+msgstr ""
+"İzləri düyünlərə görə qruplaşdır və ya onları sadə siyahı şəklində nümayiş "
+"etdir."
+
+#: editor/animation_track_editor.cpp
+msgid "Snap:"
+msgstr "Yapışdır(Snap):"
+
+#: editor/animation_track_editor.cpp
+msgid "Animation step value."
+msgstr "Animasiya addım dəyəri."
+
+#: editor/animation_track_editor.cpp
+msgid "Seconds"
+msgstr "SaniyÉ™"
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "FPS"
+msgstr "FPS"
+
+#: editor/animation_track_editor.cpp editor/editor_properties.cpp
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/property_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Edit"
+msgstr "RedaktÉ™ et"
+
+#: editor/animation_track_editor.cpp
+msgid "Animation properties."
+msgstr "Animasiya xüsusiyyətləri."
+
+#: editor/animation_track_editor.cpp
+msgid "Copy Tracks"
+msgstr "İzləri Kopyala"
+
+#: editor/animation_track_editor.cpp
+msgid "Scale Selection"
+msgstr "Ölçmə seçimi"
+
+#: editor/animation_track_editor.cpp
+msgid "Scale From Cursor"
+msgstr "Kursordan Ölçülə"
+
+#: editor/animation_track_editor.cpp modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Duplicate Selection"
+msgstr "Seçiləni Çoxalt"
+
+#: editor/animation_track_editor.cpp
+msgid "Duplicate Transposed"
+msgstr "Tərsinə çevrilmişi Çoxalt"
+
+#: editor/animation_track_editor.cpp
+msgid "Delete Selection"
+msgstr "Seçiləni Sil"
+
+#: editor/animation_track_editor.cpp
+msgid "Go to Next Step"
+msgstr "Növbəti addıma keç"
+
+#: editor/animation_track_editor.cpp
+msgid "Go to Previous Step"
+msgstr "ÆvvÉ™lki addıma keç"
+
+#: editor/animation_track_editor.cpp
+msgid "Optimize Animation"
+msgstr "Animasiyanı Optimallaşdırma"
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up Animation"
+msgstr "Animasiyanı Təmizləmə"
+
+#: editor/animation_track_editor.cpp
+msgid "Pick the node that will be animated:"
+msgstr "Animasiya ediləcək düyünü seçin:"
+
+#: editor/animation_track_editor.cpp
+msgid "Use Bezier Curves"
+msgstr "Bezier Æyrisini istifadÉ™ edin"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim. Optimizer"
+msgstr "Animasya Optimizator"
+
+#: editor/animation_track_editor.cpp
+msgid "Max. Linear Error:"
+msgstr "Maks. Xətti Xəta:"
+
+#: editor/animation_track_editor.cpp
+msgid "Max. Angular Error:"
+msgstr "Maks.Bucaqlı Xəta:"
+
+#: editor/animation_track_editor.cpp
+msgid "Max Optimizable Angle:"
+msgstr "Maks Optimize Edilə Bilən Bucaq:"
+
+#: editor/animation_track_editor.cpp
+msgid "Optimize"
+msgstr "Optimallaşdır"
+
+#: editor/animation_track_editor.cpp
+msgid "Remove invalid keys"
+msgstr "Səhv açarları sil"
+
+#: editor/animation_track_editor.cpp
+msgid "Remove unresolved and empty tracks"
+msgstr "Həll edilməmiş və boş izləri sil"
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-up all animations"
+msgstr "Bütün animasiyaları təmizlə"
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up Animation(s) (NO UNDO!)"
+msgstr "Animasiya(lar)nı Təmizlə (GERİ QAYTARMA YOXDUR!)"
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up"
+msgstr "Təmizlə"
+
+#: editor/animation_track_editor.cpp
+msgid "Scale Ratio:"
+msgstr "Ölçüm Nisbəti:"
+
+#: editor/animation_track_editor.cpp
+msgid "Select Tracks to Copy"
+msgstr "Kopyalanacaq izləri seçin"
+
+#: editor/animation_track_editor.cpp editor/editor_log.cpp
+#: editor/editor_properties.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Copy"
+msgstr "Kopyala"
+
+#: editor/animation_track_editor.cpp
+msgid "Select All/None"
+msgstr "Hamısını Seç/Seçmə"
+
+#: editor/animation_track_editor_plugins.cpp
+#, fuzzy
+msgid "Add Audio Track Clip"
+msgstr "Audio İz Klipi əlavə et"
+
+#: editor/animation_track_editor_plugins.cpp
+#, fuzzy
+msgid "Change Audio Track Clip Start Offset"
+msgstr "Audio İz Klipinin Başlanğıc Sürüşməsini Dəyiş"
+
+#: editor/animation_track_editor_plugins.cpp
+msgid "Change Audio Track Clip End Offset"
+msgstr "Audio İz Klipinin Bitiş Sürüşməsini Dəyiş"
+
+#: editor/array_property_edit.cpp
+msgid "Resize Array"
+msgstr "Massiv Ölçüsünü Dəyiş"
+
+#: editor/array_property_edit.cpp
+msgid "Change Array Value Type"
+msgstr "Massiv Qiymət Növünü Dəyiş"
+
+#: editor/array_property_edit.cpp
+msgid "Change Array Value"
+msgstr "Massiv dəyərini dəyiş"
+
+#: editor/code_editor.cpp
+msgid "Go to Line"
+msgstr "Sətirə get"
+
+#: editor/code_editor.cpp
+msgid "Line Number:"
+msgstr "Sətir Nömrəsi:"
+
+#: editor/code_editor.cpp
+msgid "%d replaced."
+msgstr "% d dəyişdirildi."
+
+#: editor/code_editor.cpp editor/editor_help.cpp
+msgid "%d match."
+msgstr "%d uyğun gəlir."
+
+#: editor/code_editor.cpp editor/editor_help.cpp
+msgid "%d matches."
+msgstr "%d uyğun gəlir."
+
+#: editor/code_editor.cpp editor/find_in_files.cpp
+#, fuzzy
+msgid "Match Case"
+msgstr "Hərf Uyğunlaşdır"
+
+#: editor/code_editor.cpp editor/find_in_files.cpp
+msgid "Whole Words"
+msgstr "Bütün sözlər"
+
+#: editor/code_editor.cpp
+msgid "Replace"
+msgstr "ÆvÉ™z Et"
+
+#: editor/code_editor.cpp
+msgid "Replace All"
+msgstr "Hamısını ÆvÉ™z Et"
+
+#: editor/code_editor.cpp
+msgid "Selection Only"
+msgstr "Yalnız Seçim"
+
+#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
+#: editor/plugins/text_editor.cpp
+msgid "Standard"
+msgstr "Standart"
+
+#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Toggle Scripts Panel"
+msgstr "Skriptlər Panelini Aktivləşdir/Söndür"
+
+#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom In"
+msgstr "Yaxınlaşdır"
+
+#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom Out"
+msgstr "Uzaqlaşdır"
+
+#: editor/code_editor.cpp
+msgid "Reset Zoom"
+msgstr "Yaxınlaşdırmanı Sıfırla"
+
+#: editor/code_editor.cpp
+msgid "Warnings"
+msgstr "Xəbərdarlıqlar"
+
+#: editor/code_editor.cpp
+msgid "Line and column numbers."
+msgstr "Sətir və sütun ədədləri."
+
+#: editor/connections_dialog.cpp
+msgid "Method in target node must be specified."
+msgstr "Hədəf düyünündə metod göstərilməlidir."
+
+#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "Metod adı hökmlü identifikativ olmalıdır."
+
+#: editor/connections_dialog.cpp
+msgid ""
+"Target method not found. Specify a valid method or attach a script to the "
+"target node."
+msgstr ""
+"Hədəf metodu tapılmadı. Hədəf düyününə hökmlü bir metod təyin edin və ya "
+"skript yapışdırın."
+
+#: editor/connections_dialog.cpp
+msgid "Connect to Node:"
+msgstr "Düyünə qoşulun:"
+
+#: editor/connections_dialog.cpp
+msgid "Connect to Script:"
+msgstr "SkriptÉ™ qoÅŸulun:"
+
+#: editor/connections_dialog.cpp
+msgid "From Signal:"
+msgstr "Siqnaldan:"
+
+#: editor/connections_dialog.cpp
+msgid "Scene does not contain any script."
+msgstr "Səhnədə heç bir skript yoxdur."
+
+#: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp
+#: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
+msgid "Add"
+msgstr "ÆlavÉ™ Et"
+
+#: editor/connections_dialog.cpp editor/dependency_editor.cpp
+#: editor/editor_feature_profile.cpp editor/groups_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp
+msgid "Remove"
+msgstr "Sil"
+
+#: editor/connections_dialog.cpp
+msgid "Add Extra Call Argument:"
+msgstr "Ekstra Çağırış Arqumenti ÆlavÉ™ Et:"
+
+#: editor/connections_dialog.cpp
+msgid "Extra Call Arguments:"
+msgstr "Ekstra Çağırış Arqumentləri:"
+
+#: editor/connections_dialog.cpp
+msgid "Receiver Method:"
+msgstr "Alıcı metod:"
+
+#: editor/connections_dialog.cpp
+msgid "Advanced"
+msgstr "Qabaqcıl"
+
+#: editor/connections_dialog.cpp
+msgid "Deferred"
+msgstr "Təxirə salınmış"
+
+#: editor/connections_dialog.cpp
+msgid ""
+"Defers the signal, storing it in a queue and only firing it at idle time."
+msgstr ""
+"Siqnalı təxirə salar, növbədə saxlayar və yalnız prosessorun bikar vaxtında "
+"atəşlər."
+
+#: editor/connections_dialog.cpp
+msgid "Oneshot"
+msgstr "Tək atış"
+
+#: editor/connections_dialog.cpp
+msgid "Disconnects the signal after its first emission."
+msgstr "İlk buraxılışından sonra Siqnalı kəsir."
+
+#: editor/connections_dialog.cpp
+msgid "Cannot connect signal"
+msgstr "Siqnala baÄŸlana bilmir"
+
+#: editor/connections_dialog.cpp editor/dependency_editor.cpp
+#: editor/export_template_manager.cpp editor/groups_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+#: editor/plugins/version_control_editor_plugin.cpp editor/project_export.cpp
+#: editor/project_settings_editor.cpp editor/property_editor.cpp
+#: editor/run_settings_dialog.cpp editor/settings_config_dialog.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Close"
+msgstr "BaÄŸla"
+
+#: editor/connections_dialog.cpp
+msgid "Connect"
+msgstr "QoÅŸ"
+
+#: editor/connections_dialog.cpp
+msgid "Signal:"
+msgstr "Siqnal:"
+
+#: editor/connections_dialog.cpp
+msgid "Connect '%s' to '%s'"
+msgstr "'%s' ilÉ™ '%s' qoÅŸ"
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect '%s' from '%s'"
+msgstr "'%s' ilə '%s' arasında əlaqəni kəs"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Disconnect all from signal: '%s'"
+msgstr "Hamısını '% s' Siqnalından ayır"
+
+#: editor/connections_dialog.cpp
+msgid "Connect..."
+msgstr "QoÅŸ ..."
+
+#: editor/connections_dialog.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Disconnect"
+msgstr "Ayır"
+
+#: editor/connections_dialog.cpp
+msgid "Connect a Signal to a Method"
+msgstr "Siqnalı bir Metoda Bağla"
+
+#: editor/connections_dialog.cpp
+msgid "Edit Connection:"
+msgstr "ÆlaqÉ™ni redaktÉ™ edin:"
+
+#: editor/connections_dialog.cpp
+msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
+msgstr ""
+"Æminsinizmi ki, bütün É™laqÉ™lÉ™ri \"%s\" siqnalından çıxartmaq istÉ™yirsiniz?"
+
+#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
+msgid "Signals"
+msgstr "Siqnallar"
+
+#: editor/connections_dialog.cpp
+msgid "Filter signals"
+msgstr "Siqnalları filtirlə"
+
+#: editor/connections_dialog.cpp
+msgid "Are you sure you want to remove all connections from this signal?"
+msgstr "Æminsinizmi ki, bütün É™laqÉ™lÉ™ri bu siqnaldan çıxartmaq istÉ™yirsiniz?"
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect All"
+msgstr "Hamısını ayır"
+
+#: editor/connections_dialog.cpp
+msgid "Edit..."
+msgstr "RedaktÉ™ et..."
+
+#: editor/connections_dialog.cpp
+msgid "Go To Method"
+msgstr "Metoda Get"
+
+#: editor/create_dialog.cpp
+msgid "Change %s Type"
+msgstr "%s növünü dəyişdirin"
+
+#: editor/create_dialog.cpp editor/project_settings_editor.cpp
+msgid "Change"
+msgstr "Dəyişdir"
+
+#: editor/create_dialog.cpp
+msgid "Create New %s"
+msgstr "Yeni %s yarat"
+
+#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp
+msgid "Favorites:"
+msgstr "Favoritlər:"
+
+#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
+msgid "Recent:"
+msgstr "Son:"
+
+#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp editor/rename_dialog.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Search:"
+msgstr "Axtar:"
+
+#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Matches:"
+msgstr "UyÄŸunlaÅŸmalar:"
+
+#: editor/create_dialog.cpp editor/editor_plugin_settings.cpp
+#: editor/plugin_config_dialog.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/property_selector.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Description:"
+msgstr "İzah:"
+
+#: editor/dependency_editor.cpp
+msgid "Search Replacement For:"
+msgstr "Bunun üçün Dəyişdirmə Axtar:"
+
+#: editor/dependency_editor.cpp
+msgid "Dependencies For:"
+msgstr "Bunun üçün Asılılıqlar:"
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Scene '%s' is currently being edited.\n"
+"Changes will only take effect when reloaded."
+msgstr ""
+"'%s' səhnəsi hazırda redaktə olunur.\n"
+"Dəyişikliklər yalnız yenidən yükləndikdə qüvvəyə minəcək."
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Resource '%s' is in use.\n"
+"Changes will only take effect when reloaded."
+msgstr ""
+"'%s' resursu istifadədədir.\n"
+"Dəyişikliklər yalnız yenidən yükləndikdə qüvvəyə minəcək."
+
+#: editor/dependency_editor.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Dependencies"
+msgstr "Asılılıqlar"
+
+#: editor/dependency_editor.cpp
+msgid "Resource"
+msgstr "Mənbə"
+
+#: editor/dependency_editor.cpp editor/editor_autoload_settings.cpp
+#: editor/project_manager.cpp editor/project_settings_editor.cpp
+msgid "Path"
+msgstr "Yol"
+
+#: editor/dependency_editor.cpp
+msgid "Dependencies:"
+msgstr "Asılılıqlar:"
+
+#: editor/dependency_editor.cpp
+msgid "Fix Broken"
+msgstr "Qırılmışı düzəldin"
+
+#: editor/dependency_editor.cpp
+msgid "Dependency Editor"
+msgstr "Asılılıq redaktoru"
+
+#: editor/dependency_editor.cpp
+msgid "Search Replacement Resource:"
+msgstr "ÆvÉ™zetmÉ™ mÉ™nbÉ™yini axtarın:"
+
+#: editor/dependency_editor.cpp editor/editor_file_dialog.cpp
+#: editor/editor_help_search.cpp editor/editor_node.cpp
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp
+#: editor/script_create_dialog.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+#: scene/gui/file_dialog.cpp
+msgid "Open"
+msgstr "Aç"
+
+#: editor/dependency_editor.cpp
+msgid "Owners Of:"
+msgstr "Bunların Sahibləri:"
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Remove selected files from the project? (no undo)\n"
+"You can find the removed files in the system trash to restore them."
+msgstr ""
+"Seçili fayllar layihənizdən silindi? (geri qaytarma yoxdur)\n"
+"Aradan qaldırılan faylları sistemin zibil qutusunda tapıb bərpa edə "
+"bilərsiniz."
+
+#: editor/dependency_editor.cpp
+msgid ""
+"The files being removed are required by other resources in order for them to "
+"work.\n"
+"Remove them anyway? (no undo)\n"
+"You can find the removed files in the system trash to restore them."
+msgstr ""
+"Aradan qaldırılan fayllar işləməsi üçün digər resurslar tərəfindən tələb "
+"olunur.\n"
+"YenÉ™ dÉ™ onlar silinsin? (geri qaytarma yoxdur)\n"
+"Aradan qaldırılan faylları sistemin zibil qutusunda tapıb bərpa edə "
+"bilərsiniz."
+
+#: editor/dependency_editor.cpp
+msgid "Cannot remove:"
+msgstr "Silinə bilmədi:"
+
+#: editor/dependency_editor.cpp
+msgid "Error loading:"
+msgstr "Yükləmə xətası:"
+
+#: editor/dependency_editor.cpp
+msgid "Load failed due to missing dependencies:"
+msgstr "Æksik asılılıqlar sÉ™bÉ™bindÉ™n yüklÉ™nmÉ™ uÄŸursuz oldu:"
+
+#: editor/dependency_editor.cpp editor/editor_node.cpp
+msgid "Open Anyway"
+msgstr "Yenə də aç"
+
+#: editor/dependency_editor.cpp
+msgid "Which action should be taken?"
+msgstr "Hansı tədbir görülməlidir?"
+
+#: editor/dependency_editor.cpp
+msgid "Fix Dependencies"
+msgstr "Asılılıqları düzəlt"
+
+#: editor/dependency_editor.cpp
+msgid "Errors loading!"
+msgstr "Yükləmə xətaları!"
+
+#: editor/dependency_editor.cpp
+msgid "Permanently delete %d item(s)? (No undo!)"
+msgstr "%d Maddə(lər)i Qalıcı olaraq silinsin?(Geri qaytarmaq yoxdu!)"
+
+#: editor/dependency_editor.cpp
+msgid "Show Dependencies"
+msgstr "Asılılıqları göstər"
+
+#: editor/dependency_editor.cpp
+msgid "Orphan Resource Explorer"
+msgstr "Orphan qaynaq Səyyahı"
+
+#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/plugins/item_list_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp
+#: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp
+msgid "Delete"
+msgstr "Sil"
+
+#: editor/dependency_editor.cpp
+msgid "Owns"
+msgstr "Sahiblər"
+
+#: editor/dependency_editor.cpp
+msgid "Resources Without Explicit Ownership:"
+msgstr "Açıq Sahibsiz Resurslar:"
+
+#: editor/dictionary_property_edit.cpp
+msgid "Change Dictionary Key"
+msgstr "Lüğət Açarını Dəyiş"
+
+#: editor/dictionary_property_edit.cpp
+msgid "Change Dictionary Value"
+msgstr "Lüğət dəyərini dəyiş"
+
+#: editor/editor_about.cpp
+msgid "Thanks from the Godot community!"
+msgstr "Godot topluluğundan təşəkkürlər!"
+
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Godot Engine contributors"
+msgstr "Godot oyun motoruna töhvə verənlər"
+
+#: editor/editor_about.cpp
+msgid "Project Founders"
+msgstr "Layihə Qurucuları"
+
+#: editor/editor_about.cpp
+msgid "Lead Developer"
+msgstr "BaÅŸ Developer"
+
+#. TRANSLATORS: This refers to a job title.
+#. The trailing space is used to distinguish with the project list application,
+#. you do not have to keep it in your translation.
+#: editor/editor_about.cpp
+msgid "Project Manager "
+msgstr "LayihÉ™ Meneceri "
+
+#: editor/editor_about.cpp
+msgid "Developers"
+msgstr "Developers"
+
+#: editor/editor_about.cpp
+msgid "Authors"
+msgstr "Müəlliflər"
+
+#: editor/editor_about.cpp
+msgid "Platinum Sponsors"
+msgstr "Platin Sponsorlar"
+
+#: editor/editor_about.cpp
+msgid "Gold Sponsors"
+msgstr "Qızıl Sponsorlar"
+
+#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr "Gümüş Sponsorlar"
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr "Bürünc Sponsorlar"
+
+#: editor/editor_about.cpp
+msgid "Mini Sponsors"
+msgstr "Mini Sponsorlar"
+
+#: editor/editor_about.cpp
+msgid "Gold Donors"
+msgstr "Qızıl Donorlar"
+
+#: editor/editor_about.cpp
+msgid "Silver Donors"
+msgstr "Gümüş Donorlar"
+
+#: editor/editor_about.cpp
+msgid "Bronze Donors"
+msgstr "Bürünc Donorlar"
+
+#: editor/editor_about.cpp
+msgid "Donors"
+msgstr "Donorlar"
+
+#: editor/editor_about.cpp
+msgid "License"
+msgstr "Lisenziya"
+
+#: editor/editor_about.cpp
+msgid "Third-party Licenses"
+msgstr "Üçüncü tərəf Lisenziyalar"
+
+#: editor/editor_about.cpp
+msgid ""
+"Godot Engine relies on a number of third-party free and open source "
+"libraries, all compatible with the terms of its MIT license. The following "
+"is an exhaustive list of all such third-party components with their "
+"respective copyright statements and license terms."
+msgstr ""
+"Godot Engine, hamısı MIT lisenziyasının şərtlərinə uyğun bir sıra üçüncü "
+"tərəf pulsuz və açıq mənbəli kitabxanalara etibar edir. Aşağıda, müvafiq "
+"müəllif hüquqları bildirişləri və lisenziya şərtləri ilə bütün bu üçüncü "
+"tərəf komponentlərinin tam siyahısı verilmişdir."
+
+#: editor/editor_about.cpp
+msgid "All Components"
+msgstr "Bütün komponentlər"
+
+#: editor/editor_about.cpp
+msgid "Components"
+msgstr "Komponentlər"
+
+#: editor/editor_about.cpp
+msgid "Licenses"
+msgstr "Lisenziyalar"
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "Error opening package file, not in ZIP format."
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "%s (Already Exists)"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Uncompressing Assets"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "The following files failed extraction from package:"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "And %s more files."
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "Package installed successfully!"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Success!"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Package Contents:"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/editor_node.cpp
+msgid "Install"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Package Installer"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Speakers"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Rename Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Change Audio Bus Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Solo"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Mute"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Bypass Effects"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Select Audio Bus Send"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Audio Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Move Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Drag & drop to rearrange."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Solo"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Mute"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Bypass"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Bus options"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Duplicate"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Reset Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Audio"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Master bus can't be deleted!"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Duplicate Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Reset Bus Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Move Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save Audio Bus Layout As..."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Location for New Layout..."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Open Audio Bus Layout"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "There is no '%s' file."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Layout"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Invalid file, not an audio bus layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Error saving file: %s"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add a new Audio Bus to this layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
+#: editor/script_create_dialog.cpp
+msgid "Load"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Load an existing Bus Layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save As"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save this Bus Layout to a file."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/import_dock.cpp
+msgid "Load Default"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Load the default Bus Layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Create a new Bus Layout."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Invalid name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Valid characters:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing engine class name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing built-in type name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing global constant name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Keyword cannot be used as an autoload name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Autoload '%s' already exists!"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Rename Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Toggle AutoLoad Globals"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Move Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Remove Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
+msgid "Enable"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Rearrange Autoloads"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Can't add autoload:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Add AutoLoad"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp
+#: editor/editor_plugin_settings.cpp
+#: editor/plugins/animation_tree_editor_plugin.cpp
+#: editor/script_create_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Path:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Node Name:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp
+#: editor/editor_profiler.cpp editor/project_manager.cpp
+#: editor/settings_config_dialog.cpp
+msgid "Name"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Singleton"
+msgstr ""
+
+#: editor/editor_data.cpp editor/inspector_dock.cpp
+msgid "Paste Params"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Updating Scene"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Storing local changes..."
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Updating scene..."
+msgstr ""
+
+#: editor/editor_data.cpp editor/editor_properties.cpp
+msgid "[empty]"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "[unsaved]"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Please select a base directory first."
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Choose a Directory"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp editor/project_manager.cpp
+#: scene/gui/file_dialog.cpp
+msgid "Create Folder"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_export.cpp
+#: modules/visual_script/visual_script_editor.cpp scene/gui/file_dialog.cpp
+msgid "Name:"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp scene/gui/file_dialog.cpp
+msgid "Could not create folder."
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Choose"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "Storing File:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "No export template found at the expected path:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "Packing"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
+"Etc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC2' texture compression for GLES3. Enable "
+"'Import Etc 2' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC' texture compression for the driver fallback "
+"to GLES2.\n"
+"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
+"Enabled'."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
+"'Import Pvrtc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
+"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'PVRTC' texture compression for the driver fallback "
+"to GLES2.\n"
+"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
+"Enabled'."
+msgstr ""
+
+#: editor/editor_export.cpp platform/android/export/export.cpp
+#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
+#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
+msgid "Custom debug template not found."
+msgstr ""
+
+#: editor/editor_export.cpp platform/android/export/export.cpp
+#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
+#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
+msgid "Custom release template not found."
+msgstr ""
+
+#: editor/editor_export.cpp platform/javascript/export/export.cpp
+msgid "Template file not found:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "3D Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Script Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Asset Library"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Scene Tree Editing"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Node Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "FileSystem Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Import Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Erase profile '%s'? (no undo)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Profile must be a valid filename and must not contain '.'"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Profile with this name already exists."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Editor Disabled, Properties Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Properties Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Editor Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Class Options:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enable Contextual Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Properties:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Features:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Classes:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "File '%s' format is invalid, import aborted."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid ""
+"Profile '%s' already exists. Remove it first before importing, import "
+"aborted."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Error saving profile to path: '%s'."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Unset"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Current Profile:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Make Current"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "New"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp editor/editor_node.cpp
+#: editor/project_manager.cpp
+msgid "Import"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp editor/project_export.cpp
+msgid "Export"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Available Profiles:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Class Options"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "New profile name:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Erase Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Godot Feature Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Import Profile(s)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Export Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Manage Editor Feature Profiles"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Select Current Folder"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "File Exists, Overwrite?"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Select This Folder"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "Copy Path"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "Open in File Manager"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/filesystem_dock.cpp editor/project_manager.cpp
+msgid "Show in File Manager"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "New Folder..."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/find_in_files.cpp
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Refresh"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "All Recognized"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "All Files (*)"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a File"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open File(s)"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a Directory"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a File or Directory"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
+msgid "Save"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Save a File"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Back"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Forward"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Up"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Hidden Files"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Favorite"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Mode"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Focus Path"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Move Favorite Up"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Move Favorite Down"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go to previous folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go to next folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Go to parent folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Refresh files."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "(Un)favorite current folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Toggle the visibility of hidden files."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "View items as a grid of thumbnails."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "View items as a list."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Directories & Files:"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/plugins/sprite_editor_plugin.cpp
+#: editor/plugins/style_box_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
+msgid "Preview:"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "File:"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid "ScanSources"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid ""
+"There are multiple importers for different types pointing to file %s, import "
+"aborted"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid "(Re)Importing Assets"
+msgstr ""
+
+#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
+msgid "Top"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Class:"
+msgstr ""
+
+#: editor/editor_help.cpp editor/scene_tree_editor.cpp
+#: editor/script_create_dialog.cpp
+msgid "Inherits:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Inherited by:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Description"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Online Tutorials"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Properties"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "override:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "default:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Methods"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Theme Properties"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Enumerations"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Constants"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Property Descriptions"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "(value)"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid ""
+"There is currently no description for this property. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Method Descriptions"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid ""
+"There is currently no description for this method. Please help us by [color="
+"$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/editor_node.cpp
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search Help"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Case Sensitive"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Show Hierarchy"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Display All"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Classes Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Methods Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Signals Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Constants Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Properties Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Theme Properties Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Member Type"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Class"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Method"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
+msgid "Signal"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
+msgid "Constant"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Property"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Theme Property"
+msgstr ""
+
+#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
+msgid "Property:"
+msgstr ""
+
+#: editor/editor_inspector.cpp
+msgid "Set"
+msgstr ""
+
+#: editor/editor_inspector.cpp
+msgid "Set Multiple:"
+msgstr ""
+
+#: editor/editor_log.cpp
+msgid "Output:"
+msgstr ""
+
+#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp
+msgid "Copy Selection"
+msgstr ""
+
+#: editor/editor_log.cpp editor/editor_network_profiler.cpp
+#: editor/editor_profiler.cpp editor/editor_properties.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/property_editor.cpp editor/scene_tree_dock.cpp
+#: editor/script_editor_debugger.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp
+#: scene/gui/text_edit.cpp
+msgid "Clear"
+msgstr ""
+
+#: editor/editor_log.cpp
+msgid "Clear Output"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_node.cpp
+#: editor/editor_profiler.cpp
+msgid "Stop"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
+#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
+msgid "Start"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "%s/s"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Down"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Up"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_node.cpp
+msgid "Node"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Incoming RPC"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Incoming RSET"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Outgoing RPC"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Outgoing RSET"
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+msgid "New Window"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Imported resources can't be saved."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: scene/gui/dialogs.cpp
+msgid "OK"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Error saving resource!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource can't be saved because it does not belong to the edited scene. "
+"Make it unique first."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Save Resource As..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't open file for writing:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Requested file format unknown:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while saving."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Can't open '%s'. The file could have been moved or deleted."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while parsing '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unexpected end of file '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Missing '%s' or its dependencies."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while loading '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Saving Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Analyzing"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Creating Thumbnail"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a tree root."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This scene can't be saved because there is a cyclic instancing inclusion.\n"
+"Please resolve it and then attempt to save again."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't "
+"be satisfied."
+msgstr ""
+
+#: editor/editor_node.cpp editor/scene_tree_dock.cpp
+msgid "Can't overwrite scene that is still open!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't load MeshLibrary for merging!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error saving MeshLibrary!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't load TileSet for merging!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error saving TileSet!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"An error occurred while trying to save the editor layout.\n"
+"Make sure the editor's user data path is writable."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Default editor layout overridden.\n"
+"To restore the Default layout to its base settings, use the Delete Layout "
+"option and delete the Default layout."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Layout name not found!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Restored the Default layout to its base settings."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource belongs to a scene that was imported, so it's not editable.\n"
+"Please read the documentation relevant to importing scenes to better "
+"understand this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource belongs to a scene that was instanced or inherited.\n"
+"Changes to it won't be kept when saving the current scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource was imported, so it's not editable. Change its settings in the "
+"import panel and then re-import."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This scene was imported, so changes to it won't be kept.\n"
+"Instancing it or inheriting will allow making changes to it.\n"
+"Please read the documentation relevant to importing scenes to better "
+"understand this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This is a remote object, so changes to it won't be kept.\n"
+"Please read the documentation relevant to debugging to better understand "
+"this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "There is no defined scene to run."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save scene before running..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Could not start subprocess!"
+msgstr ""
+
+#: editor/editor_node.cpp editor/filesystem_dock.cpp
+msgid "Open Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Base Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open Script..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save & Close"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes to '%s' before closing?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Saved %s modified resource(s)."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "A root node is required to save the scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Scene As..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/scene_tree_dock.cpp
+msgid "This operation can't be done without a scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Mesh Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a root node."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Tile Set"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a selected node."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Current scene not saved. Open anyway?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't reload a scene that was never saved."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Reload Saved Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The current scene has unsaved changes.\n"
+"Reload the saved scene anyway? This action cannot be undone."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Run Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quit"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Yes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Exit the editor?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Project Manager?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save & Quit"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes to the following scene(s) before quitting?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes the following scene(s) before opening Project Manager?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This option is deprecated. Situations where refresh must be forced are now "
+"considered a bug. Please report."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pick a Main Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Reopen Closed Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to load addon script from path: '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Scene '%s' was automatically imported, so it can't be modified.\n"
+"To make changes to it, a new inherited scene can be created."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Error loading scene, it must be inside the project path. Use 'Import' to "
+"open the scene, then save it inside the project path."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Scene '%s' has broken dependencies:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Clear Recent Scenes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"No main scene has ever been defined, select one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Selected scene '%s' does not exist, select a valid one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Selected scene '%s' is not a scene file, select a valid one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Layout"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Delete Layout"
+msgstr ""
+
+#: editor/editor_node.cpp editor/import_dock.cpp
+#: editor/script_create_dialog.cpp
+msgid "Default"
+msgstr ""
+
+#: editor/editor_node.cpp editor/editor_properties.cpp
+#: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp
+msgid "Show in FileSystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play This Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Undo Close Tab"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Close Other Tabs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Tabs to the Right"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close All Tabs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Switch Scene Tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more files or folders"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more folders"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more files"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Dock Position"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Distraction Free Mode"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle distraction-free mode."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Add a new scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Go to previously opened scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Copy Text"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Next tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Previous tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Filter Files..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Operations with scene files."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Inherited Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Open Recent"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save All Scenes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Convert To..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "MeshLibrary..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "TileSet..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Undo"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Redo"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Miscellaneous project or scene-wide tools."
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+#: editor/script_create_dialog.cpp
+msgid "Project"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Project Settings..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
+msgid "Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
+msgid "Set Up Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Shut Down Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Install Android Build Template..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Project Data Folder"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp
+msgid "Tools"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Orphan Resource Explorer..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quit to Project List"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/project_export.cpp
+msgid "Debug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Deploy with Remote Debug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, using one-click deploy will make the executable "
+"attempt to connect to this computer's IP so the running project can be "
+"debugged.\n"
+"This option is intended to be used for remote debugging (typically with a "
+"mobile device).\n"
+"You don't need to enable it to use the GDScript debugger locally."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Small Deploy with Network Filesystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, using one-click deploy for Android will only "
+"export an executable without the project data.\n"
+"The filesystem will be provided from the project by the editor over the "
+"network.\n"
+"On Android, deploying will use the USB cable for faster performance. This "
+"option speeds up testing for projects with large assets."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Visible Collision Shapes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, collision shapes and raycast nodes (for 2D and "
+"3D) will be visible in the running project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Visible Navigation"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, navigation meshes and polygons will be visible "
+"in the running project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Synchronize Scene Changes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, any changes made to the scene in the editor "
+"will be replicated in the running project.\n"
+"When used remotely on a device, this is more efficient when the network "
+"filesystem option is enabled."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Synchronize Script Changes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, any script that is saved will be reloaded in "
+"the running project.\n"
+"When used remotely on a device, this is more efficient when the network "
+"filesystem option is enabled."
+msgstr ""
+
+#: editor/editor_node.cpp editor/script_create_dialog.cpp
+msgid "Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Editor Settings..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Editor Layout"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Take Screenshot"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Screenshots are stored in the Editor Data/Settings Folder."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle Fullscreen"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle System Console"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Data/Settings Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Data Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Settings Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Editor Features..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Export Templates..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp
+msgid "Help"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Online Docs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Q&A"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Report a Bug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Send Docs Feedback"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
+msgid "Community"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "About"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play the project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pause the scene execution for debugging."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pause Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Stop the scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play the edited scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play custom scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play Custom Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Changing the video driver requires restarting the editor."
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_settings_editor.cpp
+#: editor/settings_config_dialog.cpp
+msgid "Save & Restart"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Update Continuously"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Update When Changed"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Hide Update Spinner"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "FileSystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Inspector"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Expand Bottom Panel"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Output"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Don't Save"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Android build template is missing, please install relevant templates."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Templates"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This will set up your project for custom Android builds by installing the "
+"source template to \"res://android/build\".\n"
+"You can then apply modifications and build your own custom APK on export "
+"(adding modules, changing the AndroidManifest.xml, etc.).\n"
+"Note that in order to make custom builds instead of using pre-built APKs, "
+"the \"Use Custom Build\" option should be enabled in the Android export "
+"preset."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The Android build template is already installed in this project and it won't "
+"be overwritten.\n"
+"Remove the \"res://android/build\" directory manually before attempting this "
+"operation again."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Import Templates From ZIP File"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Template Package"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Merge With Existing"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open & Run a Script"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Inherited"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Load Errors"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
+msgid "Select"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open 2D Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open 3D Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Script Editor"
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+msgid "Open Asset Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open the next Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open the previous Editor"
+msgstr ""
+
+#: editor/editor_node.h
+msgid "Warning!"
+msgstr ""
+
+#: editor/editor_path.cpp
+msgid "No sub-resources found."
+msgstr ""
+
+#: editor/editor_plugin.cpp
+msgid "Creating Mesh Previews"
+msgstr ""
+
+#: editor/editor_plugin.cpp
+msgid "Thumbnail..."
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Main Script:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Edit Plugin"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Installed Plugins:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+msgid "Update"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Version:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+msgid "Author:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Status:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Edit:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Measure:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame Time (sec)"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Average Time (sec)"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame %"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Physics Frame %"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Inclusive"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Self"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame #:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Time"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Calls"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Edit Text:"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/script_create_dialog.cpp
+msgid "On"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Layer"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Bit %d, value %d"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "[Empty]"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
+msgid "Assign..."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Invalid RID"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"The selected resource (%s) does not match any type expected for this "
+"property (%s)."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"Can't create a ViewportTexture on resources saved as a file.\n"
+"Resource needs to belong to a scene."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"Can't create a ViewportTexture on this resource because it's not set as "
+"local to scene.\n"
+"Please switch on the 'local to scene' property on it (and all resources "
+"containing it up to a node)."
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Pick a Viewport"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "New Script"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/scene_tree_dock.cpp
+msgid "Extend Script"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "New %s"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Make Unique"
+msgstr ""
+
+#: editor/editor_properties.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Paste"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Convert To %s"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Selected node is not a Viewport!"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Size: "
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Page: "
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove Item"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "New Key:"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "New Value:"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Add Key/Value Pair"
+msgstr ""
+
+#: editor/editor_run_native.cpp
+msgid ""
+"No runnable export preset found for this platform.\n"
+"Please add a runnable preset in the Export menu or define an existing preset "
+"as runnable."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Write your logic in the _run() method."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "There is an edited scene already."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Couldn't instance script:"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Did you forget the 'tool' keyword?"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Couldn't run script:"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Did you forget the '_run' method?"
+msgstr ""
+
+#: editor/editor_spin_slider.cpp
+msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Select Node(s) to Import"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp editor/project_manager.cpp
+msgid "Browse"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Scene Path:"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Import From Node:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Redownload"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Uninstall"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Installed)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Official export templates aren't available for development builds."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Missing)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Current)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Retrieving mirrors, please wait..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Remove template version '%s'?"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't open export templates zip."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Invalid version.txt format inside templates: %s."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "No version.txt found inside templates."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error creating path for templates:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Extracting Export Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Importing:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error getting the list of mirrors."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error parsing JSON of mirror list. Please report this issue!"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid ""
+"No download links found for this version. Direct download is only available "
+"for official releases."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't resolve."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't connect."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No response."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Request Failed."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Redirect Loop."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Failed:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Download Complete."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Cannot remove temporary file:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid ""
+"Templates installation failed.\n"
+"The problematic templates archives can be found at '%s'."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error requesting URL:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connecting to Mirror..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Disconnected"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Resolving"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't Resolve"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Connecting..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't Connect"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connected"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Requesting..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Downloading"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connection Error"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "SSL Handshake Error"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Uncompressing Android Build Sources"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Current Version:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Installed Versions:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Install From File"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Remove Template"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Select Template File"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Godot Export Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Export Template Manager"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Download Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Select mirror from list: (Shift+Click: Open in Browser)"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Status: Import of file failed. Please fix file and reimport manually."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Cannot move/rename resources root."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Cannot move a folder into itself."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Error moving:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Error duplicating:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Unable to update dependencies:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/scene_tree_editor.cpp
+msgid "No name provided."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Provided name contains invalid characters."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "A file or folder with this name already exists."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Name contains invalid characters."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"The following files or folders conflict with items in the target location "
+"'%s':\n"
+"\n"
+"%s\n"
+"\n"
+"Do you wish to overwrite them?"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Renaming file:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Renaming folder:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicating file:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicating folder:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Inherited Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Set As Main Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Open Scenes"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Instance"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Add to Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Remove from Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Edit Dependencies..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "View Owners..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move To..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Scene..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+msgid "New Script..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Resource..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Expand All"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Collapse All"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicate..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Previous Folder/File"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Next Folder/File"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Re-Scan Filesystem"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Toggle Split Mode"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Search files"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Scanning Files,\n"
+"Please Wait..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Overwrite"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Create Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Create Script"
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Find in Files"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Find:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Folder:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Filters:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid ""
+"Include the files with the following extensions. Add or remove them in "
+"ProjectSettings."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find..."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_text_editor.cpp
+msgid "Replace..."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/progress_dialog.cpp scene/gui/dialogs.cpp
+msgid "Cancel"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Find: "
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Replace: "
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Replace all (no undo)"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Searching..."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d match in %d file."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d matches in %d file."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d matches in %d files."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Add to Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Remove from Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Group name already exists."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Invalid group name."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Rename Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Delete Group"
+msgstr ""
+
+#: editor/groups_editor.cpp editor/node_dock.cpp
+msgid "Groups"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Nodes Not in Group"
+msgstr ""
+
+#: editor/groups_editor.cpp editor/scene_tree_dock.cpp
+#: editor/scene_tree_editor.cpp
+msgid "Filter nodes"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Nodes in Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Empty groups will be automatically removed."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Group Editor"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Manage Groups"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Single Scene"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Materials+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Materials+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Multiple Scenes"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Multiple Scenes+Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Import Scene"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Importing Scene..."
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Generating Lightmaps"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Generating for Mesh: "
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Running Custom Script..."
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Couldn't load post-import script:"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Invalid/broken script for post-import (check console):"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Error running post-import script:"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Did you return a Node-derived object in the `post_import()` method?"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Saving..."
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "%d Files"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Set as Default for '%s'"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Clear Default for '%s'"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Import As:"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Preset"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Reimport"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Save Scenes, Re-Import, and Restart"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Changing the type of an imported file requires editor restart."
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid ""
+"WARNING: Assets exist that use this resource, they may stop loading properly."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Failed to load resource."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Expand All Properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Collapse All Properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save As..."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Copy Params"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Edit Resource Clipboard"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Copy Resource"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Make Built-In"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Make Sub-Resources Unique"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Open in Help"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Create a new resource in memory and edit it."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Load an existing resource from disk and edit it."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Save the currently edited resource."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Go to the previous edited object in history."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Go to the next edited object in history."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "History of recently edited objects."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Object properties."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Filter properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Changes may be lost!"
+msgstr ""
+
+#: editor/multi_node_edit.cpp
+msgid "MultiNode Set"
+msgstr ""
+
+#: editor/node_dock.cpp
+msgid "Select a single node to edit its signals and groups."
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Edit a Plugin"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Create a Plugin"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Plugin Name:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Subfolder:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
+msgid "Language:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Script Name:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Activate now?"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Polygon"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Create points."
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid ""
+"Edit points.\n"
+"LMB: Move Point\n"
+"RMB: Erase Point"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Erase points."
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Edit Polygon"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Insert Point"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Edit Polygon (Remove Point)"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Remove Polygon And Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Animation"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Load..."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Move Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Change BlendSpace1D Limits"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Change BlendSpace1D Labels"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "This type of node can't be used. Only root nodes are allowed."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Animation Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Remove BlendSpace1D Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Move BlendSpace1D Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid ""
+"AnimationTree is inactive.\n"
+"Activate to enable playback, check node warnings if activation fails."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Set the blending position within the space"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Select and move points, create points with RMB."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
+msgid "Enable snap and show grid."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Open Editor"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Open Animation Node"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Triangle already exists."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Triangle"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Change BlendSpace2D Limits"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Change BlendSpace2D Labels"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Remove BlendSpace2D Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Remove BlendSpace2D Triangle"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "BlendSpace2D does not belong to an AnimationTree node."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "No triangles exist, so no blending can take place."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Toggle Auto Triangles"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Create triangles by connecting points."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Erase points and triangles."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Generate blend triangles automatically (instead of manually)"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend:"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Parameter Changed"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Edit Filters"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Output node can't be added to the blend tree."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Add Node to BlendTree"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Node Moved"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Unable to connect, port may be in use or connection may be invalid."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Nodes Connected"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Nodes Disconnected"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Set Animation"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Delete Node"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Delete Node(s)"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Toggle Filter On/Off"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Change Filter"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "No animation player set, so unable to retrieve track names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Player path set is invalid, so unable to retrieve track names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid ""
+"Animation player has no valid root node path, so unable to retrieve track "
+"names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Anim Clips"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Audio Clips"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Functions"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Node Renamed"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Node..."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "Edit Filtered Tracks:"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Enable Filtering"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Toggle Autoplay"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "New Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "New Anim"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Change Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Delete Animation?"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Remove Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Invalid animation name!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation name already exists!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Rename Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Blend Next Changed"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Change Blend Time"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Load Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Duplicate Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation to copy!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation resource on clipboard!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Pasted Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Paste Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation to edit!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation backwards from current pos. (A)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation backwards from end. (Shift+A)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Stop animation playback. (S)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation from start. (Shift+D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation from current pos. (D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation position (in seconds)."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Scale animation playback globally for the node."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation Tools"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Edit Transitions..."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Open in Inspector"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Display list of animations in player."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Autoplay on Load"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Enable Onion Skinning"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Onion Skinning Options"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Directions"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Past"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Future"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Depth"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "1 step"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "2 steps"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "3 steps"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Differences Only"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Force White Modulate"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Include Gizmos (3D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Pin AnimationPlayer"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Create New Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
+msgid "Error!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Blend Times:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Next (Auto Queue):"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Cross-Animation Blend Times"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Move Node"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition exists!"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Add Transition"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Node"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "End"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Immediate"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Sync"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "At End"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Travel"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Start and end nodes are needed for a sub-transition."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "No playback resource set at path: %s."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Node Removed"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition Removed"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Set Start Node (Autoplay)"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid ""
+"Select and move nodes.\n"
+"RMB to add new nodes.\n"
+"Shift+LMB to create connections."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Create new nodes."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Connect nodes."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Remove selected node or transition."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Toggle autoplay this animation on start, restart or seek to zero."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Set the end animation. This is useful for sub-transitions."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition: "
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Play Mode:"
+msgstr ""
+
+#: editor/plugins/animation_tree_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "AnimationTree"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "New name:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Scale:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Fade In (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Fade Out (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Mix"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Auto Restart:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Restart (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Random Restart (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Start!"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Amount:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend 0:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend 1:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "X-Fade Time (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Current:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Input"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Clear Auto-Advance"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Set Auto-Advance"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Delete Input"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation tree is valid."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation tree is invalid."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "OneShot Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Mix Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend2 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend3 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend4 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "TimeScale Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "TimeSeek Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Transition Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Import Animations..."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Edit Node Filters"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Filters..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Contents:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "View Files"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Connection error, please try again."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't connect to host:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No response from host:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't resolve hostname:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, return code:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Cannot save response to:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Write error."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, too many redirects"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Redirect loop."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, timeout"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Timeout."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Bad download hash, assuming file has been tampered with."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Expected:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Got:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Failed SHA-256 hash check"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Asset Download Error:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Downloading (%s / %s)..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Downloading..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Resolving..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Error making request"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Idle"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Install..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Retry"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download Error"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download for this asset is already in progress!"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Recently Updated"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Least Recently Updated"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Name (A-Z)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Name (Z-A)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "License (A-Z)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "License (Z-A)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "First"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Previous"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Next"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Last"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "All"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No results for \"%s\"."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Import..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Plugins..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
+msgid "Sort:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Category:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Site:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Support"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Official"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Testing"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Loading..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Assets ZIP File"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Can't determine a save path for lightmap images.\n"
+"Save your scene and try again."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake "
+"Light' flag is on."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Failed creating lightmap images, make sure path is writable."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Failed determining lightmap size. Maximum lightmap size too small?"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Some mesh is invalid. Make sure the UV2 channel values are contained within "
+"the [0.0,1.0] square region."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Godot editor was built without ray tracing support, lightmaps can't be baked."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Bake Lightmaps"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Select lightmap bake file:"
+msgstr ""
+
+#: editor/plugins/camera_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Preview"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Configure Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Grid Offset:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Grid Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Primary Line Every:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "steps"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation Offset:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Remove Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Remove Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Horizontal and Vertical Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotate %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotate CanvasItem \"%s\" to %d degrees"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move CanvasItem \"%s\" Anchor"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale Node2D \"%s\" to (%s, %s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Resize Control \"%s\" to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale CanvasItem \"%s\" to (%s, %s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move CanvasItem \"%s\" to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Children of containers have their anchors and margins values overridden by "
+"their parent."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Presets for the anchors and margins values of a Control node."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"When active, moving Control nodes changes their anchors instead of their "
+"margins."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Top"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Bottom"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Left Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Right Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "VCenter Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "HCenter Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Full Rect"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Keep Ratio"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Anchors only"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Anchors and Margins"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Anchors"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Game Camera Override\n"
+"Overrides game camera with editor viewport camera."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Game Camera Override\n"
+"No game instance running."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Unlock Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Group Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Ungroup Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Paste Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Custom Bone(s) from Node(s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Make IK Chain"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear IK Chain"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Warning: Children of a container get their position and size determined only "
+"by their parent."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom Reset"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Select Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Drag: Rotate"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Alt+Drag: Move"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Alt+RMB: Depth list selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Move Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Show a list of all objects at the position clicked\n"
+"(same as Alt+RMB in select mode)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Click to change object's rotation pivot."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Pan Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Ruler Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Toggle smart snapping."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Smart Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Toggle grid snapping."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Grid Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snapping Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Rotation Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Scale Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap Relative"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Pixel Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Smart Snapping"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Configure Snap..."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Parent"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Anchor"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Sides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Center"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Other Nodes"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock the selected object in place (can't be moved)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Unlock the selected object (can be moved)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Makes sure the object's children are not selectable."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Restores the object's children's ability to be selected."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Skeleton Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Make Custom Bone(s) from Node(s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Custom Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Always Show Grid"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Helpers"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Rulers"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Origin"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Viewport"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Group And Lock Icons"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Frame Selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Preview Canvas Scale"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Translation mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert keys (based on mask)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Auto insert keys when objects are translated, rotated or scaled (based on "
+"mask).\n"
+"Keys are only added to existing tracks, no new tracks will be created.\n"
+"Keys must be inserted manually for the first time."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Auto Insert Key"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Animation Key and Pose Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert Key (Existing Tracks)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Copy Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Multiply grid step by 2"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Divide grid step by 2"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Pan View"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Add %s"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Adding %s..."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Cannot instantiate multiple nodes without root."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Create Node"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Error instancing scene from %s"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Default Type"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Drag & drop + Shift : Add node as sibling\n"
+"Drag & drop + Alt : Change node type"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Create Polygon3D"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Edit Poly"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Edit Poly (Remove Point)"
+msgstr ""
+
+#: editor/plugins/collision_shape_2d_editor_plugin.cpp
+msgid "Set Handle"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Load Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Restart"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Clear Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Particles"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generated Point Count:"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Solid Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Border Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Directed Border Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Capture from Pixel"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Emission Colors"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+msgid "CPUParticles"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emission Points From Mesh"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emission Points From Node"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Flat 0"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Flat 1"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
+msgid "Ease In"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
+msgid "Ease Out"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Smoothstep"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Modify Curve Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Modify Curve Tangent"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Load Curve Preset"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Add Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Remove Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Left Linear"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Right Linear"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Load Preset"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Remove Curve Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Toggle Curve Linear Tangent"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Hold Shift to edit tangents individually"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Right click to add point"
+msgstr ""
+
+#: editor/plugins/gi_probe_editor_plugin.cpp
+msgid "Bake GI Probe"
+msgstr ""
+
+#: editor/plugins/gradient_editor_plugin.cpp
+msgid "Gradient Edited"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Item %d"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Items"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Item List Editor"
+msgstr ""
+
+#: editor/plugins/light_occluder_2d_editor_plugin.cpp
+msgid "Create Occluder Polygon"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh is empty!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create a Trimesh collision shape."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Static Trimesh Body"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "This doesn't work on scene root!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Static Shape"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Can't create a single convex collision shape for the scene root."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create a single convex collision shape."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Single Convex Shape"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Can't create multiple convex collision shapes for the scene root."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create any collision shapes."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Multiple Convex Shapes"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Navigation Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Contained Mesh is not of type ArrayMesh."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "UV Unwrap failed, mesh may not be manifold?"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "No mesh to debug."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Model has no UV in this layer"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "MeshInstance lacks a Mesh!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh has not surface to create outlines from!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh primitive type is not PRIMITIVE_TRIANGLES!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Could not create outline!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Static Body"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a StaticBody and assigns a polygon-based collision shape to it "
+"automatically.\n"
+"This is the most accurate (but slowest) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Collision Sibling"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a polygon-based collision shape.\n"
+"This is the most accurate (but slowest) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Single Convex Collision Sibling"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a single convex collision shape.\n"
+"This is the fastest (but least accurate) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Multiple Convex Collision Siblings"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a polygon-based collision shape.\n"
+"This is a performance middle-ground between the two above options."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline Mesh..."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a static outline mesh. The outline mesh will have its normals "
+"flipped automatically.\n"
+"This can be used instead of the SpatialMaterial Grow property when using "
+"that property isn't possible."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "View UV1"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "View UV2"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Unwrap UV2 for Lightmap/AO"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Outline Size:"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "UV Channel Debug"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Remove item %d?"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid ""
+"Update from existing scene?:\n"
+"%s"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Mesh Library"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add Item"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Remove Selected Item"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Import from Scene"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Update from Scene"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No mesh source specified (and no MultiMesh set in node)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No mesh source specified (and MultiMesh contains no Mesh)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (invalid path)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (not a MeshInstance)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (contains no Mesh resource)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No surface source specified."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (invalid path)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (no geometry)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (no faces)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Select a Source Mesh:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Select a Target Surface:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate Surface"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate MultiMesh"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Target Surface:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Source Mesh:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "X-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Y-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Z-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh Up Axis:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Rotation:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Tilt:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Scale:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate"
+msgstr ""
+
+#: editor/plugins/navigation_polygon_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Convert to CPUParticles"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generating Visibility Rect"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generate Visibility Rect"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Can only set point into a ParticlesMaterial process material"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Convert to CPUParticles2D"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generation Time (sec):"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "The geometry's faces don't contain any area."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "The geometry doesn't contain any faces."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't inherit from Spatial."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't contain geometry."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't contain face geometry."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emitter"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Emission Points:"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Surface Points"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Surface Points+Normal (Directed)"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Volume"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Emission Source: "
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "A processor material of type 'ParticlesMaterial' is required."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generating AABB"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generate Visibility AABB"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove Point from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove Out-Control from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove In-Control from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Add Point to Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Split Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move Point in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move In-Control in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move Out-Control in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Select Points"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Shift+Drag: Select Control Points"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Click: Add Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Left Click: Split Segment (in curve)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Right Click: Delete Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Select Control Points (Shift+Drag)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Add Point (in empty space)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Delete Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Close Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_export.cpp
+msgid "Options"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Mirror Handle Angles"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Mirror Handle Lengths"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Curve Point #"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve Point Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve In Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve Out Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Split Path"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove Path Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove Out-Control Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove In-Control Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Split Segment (in curve)"
+msgstr ""
+
+#: editor/plugins/physical_bone_plugin.cpp
+msgid "Move Joint"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"The skeleton property of the Polygon2D does not point to a Skeleton2D node"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Sync Bones"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"No texture in this polygon.\n"
+"Set a texture to be able to edit UV."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create UV Map"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"Polygon 2D has internal vertices, so it can no longer be edited in the "
+"viewport."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Polygon & UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Internal Vertex"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Remove Internal Vertex"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Invalid Polygon (need 3 different vertices)"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Add Custom Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Remove Custom Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Transform UV Map"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Transform Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Paint Bone Weights"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Open Polygon 2D UV editor."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Polygon 2D UV Editor"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Points"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Polygons"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Bones"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Move Points"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Command: Rotate"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift: Move All"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift+Command: Scale"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Ctrl: Rotate"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift+Ctrl: Scale"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Move Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Rotate Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Scale Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create a custom polygon. Enables custom polygon rendering."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"Remove a custom polygon. If none remain, custom polygon rendering is "
+"disabled."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Paint weights with specified intensity."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Unpaint weights with specified intensity."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Radius:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Copy Polygon to UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Copy UV to Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Clear UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Settings"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Snap"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Enable Snap"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Show Grid"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Configure Grid:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Offset X:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Offset Y:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Step X:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Step Y:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Sync Bones to Polygon"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "ERROR: Couldn't load resource!"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Add Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Rename Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Delete Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Resource clipboard is empty!"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Paste Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/scene_tree_editor.cpp
+msgid "Instance:"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
+#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Type:"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp
+msgid "Open in Editor"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Load Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "ResourcePreloader"
+msgstr ""
+
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "AnimationTree has no path set to an AnimationPlayer"
+msgstr ""
+
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "Path to AnimationPlayer is invalid"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Clear Recent Files"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close and save changes?"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error writing TextFile:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Could not load file at:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error saving file!"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error while saving theme."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error Saving"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error importing theme."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error Importing"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "New Text File..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open File"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save File As..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Can't obtain the script for running."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Script failed reloading, check console for errors."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Script is not in tool mode, will not be able to run."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid ""
+"To run this script, it must inherit EditorScript and be set to tool mode."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Import Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error while saving theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error saving"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save Theme As..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "%s Class Reference"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find Next"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find Previous"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Filter scripts"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Toggle alphabetical sorting of the method list."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Filter methods"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Sort"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Move Up"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Move Down"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Next script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Previous script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "File"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Reopen Closed Script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save All"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Soft Reload Script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Copy Script Path"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "History Previous"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "History Next"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Import Theme..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Reload Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close All"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close Docs"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
+msgid "Run"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Step Into"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Step Over"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Break"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Continue"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Keep Debugger Open"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Debug with External Editor"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open Godot online documentation."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search the reference documentation."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Go to previous edited document."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Go to next edited document."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Discard"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Debugger"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search Results"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Clear Recent Scripts"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Connections to method:"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
+msgid "Source"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Target"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid ""
+"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "[Ignore]"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Function"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Only resources from filesystem can be dropped."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't drop nodes because script '%s' is not used in this scene."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Lookup Symbol"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Pick Color"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Convert Case"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Uppercase"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Lowercase"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Capitalize"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Syntax Highlighter"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+msgid "Bookmarks"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Breakpoints"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+msgid "Go To"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Cut"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
+#: scene/gui/text_edit.cpp
+msgid "Select All"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Delete Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Indent Left"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Indent Right"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Toggle Comment"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Fold/Unfold Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Fold All Lines"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Unfold All Lines"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Clone Down"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Complete Symbol"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Evaluate Selection"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Trim Trailing Whitespace"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Convert Indent to Spaces"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Convert Indent to Tabs"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Auto Indent"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Find in Files..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Contextual Help"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Toggle Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Next Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Previous Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Remove All Bookmarks"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Function..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Line..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Toggle Breakpoint"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Remove All Breakpoints"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Next Breakpoint"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Previous Breakpoint"
+msgstr ""
+
+#: editor/plugins/shader_editor_plugin.cpp
+msgid ""
+"This shader has been modified on on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Shader"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "This skeleton has no bones, create some children Bone2D nodes."
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Create Rest Pose from Bones"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Set Rest Pose to Bones"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Skeleton2D"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Make Rest Pose (From Bones)"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Set Bones to Rest Pose"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Create physical bones"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Skeleton"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Create physical skeleton"
+msgstr ""
+
+#: editor/plugins/skeleton_ik_editor_plugin.cpp
+msgid "Play IK"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Orthogonal"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Perspective"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Aborted."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "X-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Y-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Z-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Plane Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scaling: "
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translating: "
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotating %s degrees."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Keying is disabled (no key inserted)."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Animation Key Inserted."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Pitch"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Yaw"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Size"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Objects Drawn"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Material Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Shader Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Surface Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Draw Calls"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Vertices"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Top View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Align Transform with View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Align Rotation with View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "No parent to instance a child at."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "This operation requires a single selected node."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Auto Orthogonal Enabled"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock View Rotation"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Normal"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Wireframe"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Overdraw"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Unshaded"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Environment"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Gizmos"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Information"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View FPS"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Half Resolution"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Audio Listener"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Enable Doppler"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Cinematic Preview"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Not available when using the GLES2 renderer."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Left"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Right"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Forward"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Backwards"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Up"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Down"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Speed Modifier"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Slow Modifier"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Rotation Locked"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Note: The FPS value displayed is the editor's framerate.\n"
+"It cannot be used as a reliable indication of in-game performance."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "XForm Dialog"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Click to toggle between visibility states.\n"
+"\n"
+"Open eye: Gizmo is visible.\n"
+"Closed eye: Gizmo is hidden.\n"
+"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Nodes To Floor"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Couldn't find a solid floor to snap the selection to."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Drag: Rotate\n"
+"Alt+Drag: Move\n"
+"Alt+RMB: Depth list selection"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Use Local Space"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Use Snap"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Top View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Switch Perspective/Orthogonal View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Insert Animation Key"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Focus Origin"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Focus Selection"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Toggle Freelook"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Object to Floor"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Dialog..."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "1 Viewport"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "2 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "2 Viewports (Alt)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "3 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "3 Viewports (Alt)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "4 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Gizmos"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Origin"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Grid"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Settings..."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Settings"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translate Snap:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate Snap (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale Snap (%):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Viewport Settings"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Perspective FOV (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Z-Near:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Z-Far:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Change"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translate:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale (ratio):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Type"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Pre"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Post"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Nameless gizmo"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create Mesh2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Mesh2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create Polygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Polygon2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create CollisionPolygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "CollisionPolygon2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create LightOccluder2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "LightOccluder2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Sprite is empty!"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Can't convert a sprite using animation frames to mesh."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't replace by mesh."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Convert to Mesh2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create polygon."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Convert to Polygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create collision polygon."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create CollisionPolygon2D Sibling"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create light occluder."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create LightOccluder2D Sibling"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Sprite"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Simplification: "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Shrink (Pixels): "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Grow (Pixels): "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Update Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Settings:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "No Frames Selected"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add %d Frame(s)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Unable to load images"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "ERROR: Couldn't load frame resource!"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Resource clipboard is empty or not a texture!"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Paste Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Empty"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Change Animation FPS"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "(empty)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Animations:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "New Animation"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Speed:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Loop"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Animation Frames:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add a Texture from File"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Frames from a Sprite Sheet"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Insert Empty (Before)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Insert Empty (After)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move (Before)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move (After)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Select Frames"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Horizontal:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Vertical:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Select/Clear All Frames"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Create Frames from Sprite Sheet"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "SpriteFrames"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Set Region Rect"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Set Margin"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Snap Mode:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: scene/resources/visual_shader.cpp
+msgid "None"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Pixel Snap"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Grid Snap"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Auto Slice"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Offset:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Step:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Sep.:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "TextureRegion"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add All Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add All"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove All Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp editor/project_manager.cpp
+msgid "Remove All"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Edit Theme"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme editing menu."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add Class Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove Class Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create Empty Template"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create Empty Editor Template"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create From Current Editor Theme"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Toggle Button"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled Button"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Check Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Checked Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Radio Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Checked Radio Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Named Sep."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Submenu"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subitem 1"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subitem 2"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Has"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Many"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled LineEdit"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 1"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 2"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 3"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Editable Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subtree"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Has,Many,Options"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Data Type:"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Icon"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
+msgid "Style"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Font"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Color"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme File"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Erase Selection"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Fix Invalid Tiles"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cut Selection"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Paint TileMap"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Line Draw"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Bucket Fill"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Erase TileMap"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Find Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Transpose"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Disable Autotile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Enable Priority"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Filter tiles"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Give a TileSet resource to this TileMap to use its tiles."
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Paint Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid ""
+"Shift+LMB: Line Draw\n"
+"Shift+Command+LMB: Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid ""
+"Shift+LMB: Line Draw\n"
+"Shift+Ctrl+LMB: Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Pick Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rotate Left"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rotate Right"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Flip Horizontally"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Flip Vertically"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Clear Transform"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Add Texture(s) to TileSet."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove selected Texture from TileSet."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create from Scene"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Merge from Scene"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Single Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Autotile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Atlas"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Next Coordinate"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Select the next shape, subtile, or Tile."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Previous Coordinate"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Select the previous shape, subtile, or Tile."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Region"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Collision"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Occlusion"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Navigation"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Priority"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Z Index"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Region Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Collision Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Occlusion Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Navigation Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Bitmask Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Priority Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Icon Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Z Index Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Copy bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Paste bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Erase bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create a new rectangle."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Rectangle"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create a new polygon."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete Selected Shape"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Keep polygon inside region Rect."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Enable snap and show grid (configurable via the Inspector)."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Display Tile Names (Hold Alt Key)"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Add or select a texture on the left panel to edit the tiles bound to it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove selected texture? This will remove all tiles which use it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "You haven't selected a texture to remove."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create from scene? This will overwrite all current tiles."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Merge from scene?"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Texture"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "%s file(s) were not added because was already on the list."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Drag handles to edit Rect.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete selected Rect."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select current edited sub-tile.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete polygon."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"LMB: Set bit on.\n"
+"RMB: Set bit off.\n"
+"Shift+LMB: Set wildcard bit.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to use as icon, this will be also used on invalid autotile "
+"bindings.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to change its priority.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to change its z index.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Set Tile Region"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Set Tile Icon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Paste Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Clear Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Polygon Concave"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Polygon Convex"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Priority"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Z Index"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Convex"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Concave"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "This property can't be changed."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "TileSet"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No VCS addons are available."
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Error"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No files added to stage"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Commit"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "VCS Addon is not initialized"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Version Control System"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Initialize"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Staging area"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Detect new changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Modified"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Renamed"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Deleted"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Typechange"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Stage Selected"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Stage All"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Commit Changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Status"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "View file diffs before committing them to the latest version"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No file diff is active"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Detect changes in file diff"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(GLES3 only)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Output"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sampler"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add input port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add output port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change input port type"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change output port type"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change input port name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change output port name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Remove input port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Remove output port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set expression"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Resize VisualShader node"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set Uniform Name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set Input Default Port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Node to Visual Shader"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Node(s) Moved"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Duplicate Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Paste Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Delete Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Visual Shader Input Type Changed"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "UniformRef Name Changed"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vertex"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Fragment"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Light"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Show resulted shader code."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Create Shader Node"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Grayscale function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts HSV vector to RGB equivalent."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts RGB vector to HSV equivalent."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sepia function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Burn operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Darken operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Difference operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Dodge operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "HardLight operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Lighten operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Overlay operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Screen operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "SoftLight operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the boolean result of the %s comparison between two parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Equal (==)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Greater Than (>)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Greater Than or Equal (>=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated vector if the provided scalars are equal, greater or "
+"less."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between INF and a scalar "
+"parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between NaN and a scalar "
+"parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Less Than (<)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Less Than or Equal (<=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Not Equal (!=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated vector if the provided boolean value is true or false."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated scalar if the provided boolean value is true or false."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the boolean result of the comparison between two parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between INF (or NaN) and a "
+"scalar parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for all shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Input parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex and fragment shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for fragment and light shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for fragment shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for light shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex and fragment shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "E constant (2.718282). Represents the base of the natural logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Epsilon constant (0.00001). Smallest possible scalar number."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Phi constant (1.618034). Golden ratio."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi/4 constant (0.785398) or 45 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi/2 constant (1.570796) or 90 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi constant (3.141593) or 180 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Tau constant (6.283185) or 360 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sqrt2 constant (1.414214). Square root of 2."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the absolute value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-tangent of the parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Finds the nearest integer that is greater than or equal to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Constrains a value to lie between two further values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts a quantity in radians to degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-e Exponential."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-2 Exponential."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest integer less than or equal to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Computes the fractional part of the argument."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse of the square root of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Natural logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-2 logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the greater of two values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the lesser of two values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the opposite value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 - scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the value of the first parameter raised to the power of the second."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts a quantity in degrees to radians."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 / scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest integer to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest even integer to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Clamps the value between 0.0 and 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Extracts the sign of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the square root of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( scalar(edge), scalar(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the truncated value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Adds scalar to scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Divides scalar by scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies scalar by scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the remainder of the two scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Subtracts scalar from scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Perform the cubic texture lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Perform the texture lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Cubic texture uniform lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "2D texture uniform lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "2D texture uniform lookup with triplanar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Calculate the outer product of a pair of vectors.\n"
+"\n"
+"OuterProduct treats the first parameter 'c' as a column vector (matrix with "
+"one column) and the second parameter 'r' as a row vector (matrix with one "
+"row) and does a linear algebraic matrix multiply 'c * r', yielding a matrix "
+"whose number of rows is the number of components in 'c' and whose number of "
+"columns is the number of components in 'r'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Composes transform from four vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Decomposes transform to four vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the determinant of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the inverse of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the transpose of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies transform by transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies vector by transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Composes vector from three scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Decomposes vector to three scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the cross product of two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the distance between two points."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the dot product of two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the vector that points in the same direction as a reference vector. "
+"The function has three vector parameters : N, the vector to orient, I, the "
+"incident vector, and Nref, the reference vector. If the dot product of I and "
+"Nref is smaller than zero the return value is N. Otherwise -N is returned."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the length of a vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two vectors using scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the normalize product of vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 - vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 / vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the vector that points in the direction of reflection ( a : incident "
+"vector, b : normal vector )."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the vector that points in the direction of refraction."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( vector(edge), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( scalar(edge), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Adds vector to vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Divides vector by vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies vector by vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the remainder of the two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Subtracts vector from vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Custom Godot Shader Language expression, with custom amount of input and "
+"output ports. This is a direct injection of code into the vertex/fragment/"
+"light function, do not use it to write the function declarations inside."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns falloff based on the dot product of surface normal and view "
+"direction of camera (pass associated inputs to it)."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Custom Godot Shader Language expression, which is placed on top of the "
+"resulted shader. You can place various function definitions inside and call "
+"it later in the Expressions. You can also declare varyings, uniforms and "
+"constants."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "A reference to an existing uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(Fragment/Light mode only) Scalar derivative function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(Fragment/Light mode only) Vector derivative function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Derivative in 'x' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Derivative in 'x' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Derivative in 'y' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Derivative in 'y' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and "
+"'y'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and "
+"'y'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "VisualShader"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Edit Visual Property"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Visual Shader Mode Changed"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Runnable"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Delete preset '%s'?"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Failed to export the project for platform '%s'.\n"
+"Export templates seem to be missing or invalid."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Failed to export the project for platform '%s'.\n"
+"This might be due to a configuration issue in the export preset or your "
+"export settings."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Release"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Exporting All"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "The given export path doesn't exist:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export templates for this platform are missing/corrupted:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Presets"
+msgstr ""
+
+#: editor/project_export.cpp editor/project_settings_editor.cpp
+msgid "Add..."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"If checked, the preset will be available for use in one-click deploy.\n"
+"Only one preset per platform may be marked as runnable."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Path"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Resources"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export all resources in the project"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export selected scenes (and dependencies)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export selected resources (and dependencies)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Mode:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Resources to export:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Filters to export non-resource files/folders\n"
+"(comma-separated, e.g: *.json, *.txt, docs/*)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Filters to exclude files/folders from project\n"
+"(comma-separated, e.g: *.json, *.txt, docs/*)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Features"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Custom (comma-separated):"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Feature List:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script Export Mode:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Text"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Compiled"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Encrypted (Provide Key Below)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Invalid Encryption Key (must be 64 characters long)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script Encryption Key (256-bits as hex):"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export PCK/Zip"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Project"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export mode?"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export All"
+msgstr ""
+
+#: editor/project_export.cpp editor/project_manager.cpp
+msgid "ZIP File"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Godot Game Pack"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export templates for this platform are missing:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Manage Export Templates"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export With Debug"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "The path specified doesn't exist."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Error opening package file (it's not in ZIP format)."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Please choose an empty folder."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Please choose a \"project.godot\" or \".zip\" file."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "This directory already contains a Godot project."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "New Game Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Imported Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Invalid Project Name."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't create folder."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "There is already a folder in this path with the specified name."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "It would be a good idea to name your project."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Invalid project path (changed anything?)."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Couldn't load project.godot in project path (error %d). It may be missing or "
+"corrupted."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't edit project.godot in project path."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't create project.godot in project path."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Rename Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Import Existing Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Import & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Create New Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Create & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Install Project:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Install & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Name:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Path:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Installation Path:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Renderer:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "OpenGL ES 3.0"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Not supported by your GPU drivers."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Higher visual quality\n"
+"All features available\n"
+"Incompatible with older hardware\n"
+"Not recommended for web games"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "OpenGL ES 2.0"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Lower visual quality\n"
+"Some features not available\n"
+"Works on most hardware\n"
+"Recommended for web games"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Renderer can be changed later, but scenes may need to be adjusted."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Unnamed Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Missing Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Error: Project is missing on the filesystem."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Can't open project at '%s'."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Are you sure to open more than one project?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The following project settings file does not specify the version of Godot "
+"through which it was created.\n"
+"\n"
+"%s\n"
+"\n"
+"If you proceed with opening it, it will be converted to Godot's current "
+"configuration file format.\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The following project settings file was generated by an older engine "
+"version, and needs to be converted for this version:\n"
+"\n"
+"%s\n"
+"\n"
+"Do you want to convert it?\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The project settings were created by a newer engine version, whose settings "
+"are not compatible with this version."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Can't run project: no main scene defined.\n"
+"Please edit the project and set the main scene in the Project Settings under "
+"the \"Application\" category."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Can't run project: Assets need to be imported.\n"
+"Please edit the project to trigger the initial import."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Are you sure to run %d projects at once?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove %d projects from the list?\n"
+"The project folders' contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove this project from the list?\n"
+"The project folder's contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove all missing projects from the list?\n"
+"The project folders' contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Language changed.\n"
+"The interface will update after restarting the editor or project manager."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Are you sure to scan %s folders for existing Godot projects?\n"
+"This could take a while."
+msgstr ""
+
+#. TRANSLATORS: This refers to the application where users manage their Godot projects.
+#: editor/project_manager.cpp
+msgid "Project Manager"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Projects"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Last Modified"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Scan"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Select a Folder to Scan"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "New Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Remove Missing"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Templates"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Restart Now"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Can't run project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"You currently don't have any projects.\n"
+"Would you like to explore official example projects in the Asset Library?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The search box filters projects by name and last path component.\n"
+"To filter projects by name and full path, the query must contain at least "
+"one `/` character."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Key "
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joy Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joy Axis"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Mouse Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid ""
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
+"'\"'"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "An action with the name '%s' already exists."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Rename Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Change Action deadzone"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "All Devices"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Device"
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Press a Key..."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Mouse Button Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Left Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Right Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Middle Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Up Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Down Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Left Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Right Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "X Button 1"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "X Button 2"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joypad Axis Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Axis"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joypad Button Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Erase Input Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Erase Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Left Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Right Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Middle Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Up."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Down."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Global Property"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Select a setting item first!"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "No property '%s' exists."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Setting '%s' is internal, and it can't be deleted."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Delete Item"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid ""
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
+"'\"'."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Input Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Error saving settings."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Settings saved OK."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Moved Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Override for Feature"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Translation"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Translation"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Remapped Path"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Resource Remap Add Remap"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Change Resource Remap Language"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Resource Remap"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Resource Remap Option"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Changed Locale Filter"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Changed Locale Filter Mode"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Project Settings (project.godot)"
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "General"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Override For..."
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "The editor must be restarted for changes to take effect."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Input Map"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Action:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Deadzone"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Device:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Localization"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Translations"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Translations:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remaps"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Resources:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remaps by Locale:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locale"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locales Filter"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Show All Locales"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Show Selected Locales Only"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Filter mode:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locales:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "AutoLoad"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Plugins"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Preset..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Zero"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Easing In-Out"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Easing Out-In"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "File..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Dir..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Assign"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Select Node"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Error loading file: Not a resource!"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Pick a Node"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Bit %d, val %d."
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Property"
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Virtual Method"
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Method"
+msgstr ""
+
+#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Batch Rename"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Replace:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Prefix:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Suffix:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Use Regular Expressions"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Advanced Options"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Substitute"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node's parent name, if available"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node type"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Current scene name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Root node name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid ""
+"Sequential integer counter.\n"
+"Compare counter options."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Per-level Counter"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "If set, the counter restarts for each group of child nodes."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Initial value for the counter"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Step"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Amount by which counter is incremented for each node"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Padding"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid ""
+"Minimum number of digits for the counter.\n"
+"Missing digits are padded with leading zeros."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Post-Process"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Keep"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "PascalCase to snake_case"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "snake_case to PascalCase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Case"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "To Lowercase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "To Uppercase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Reset"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Regular Expression Error:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "At character %s"
+msgstr ""
+
+#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Reparent Node"
+msgstr ""
+
+#: editor/reparent_dialog.cpp
+msgid "Reparent Location (Select new Parent):"
+msgstr ""
+
+#: editor/reparent_dialog.cpp
+msgid "Keep Global Transform"
+msgstr ""
+
+#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Reparent"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Run Mode:"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Current Scene"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Main Scene"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Main Scene Arguments:"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Scene Run Settings"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "No parent to instance the scenes at."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error loading scene from %s"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Cannot instance the scene '%s' because the current scene exists within one "
+"of its nodes."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instance Scene(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Replace with Branch Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instance Child Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Detach Script"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "This operation can't be done on the tree root."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Move Node In Parent"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Move Nodes In Parent"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Duplicate Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't reparent nodes in inherited scenes, order of nodes can't change."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Node must belong to the edited scene to become root."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instantiated scenes can't become root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make node as Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete %d nodes and any children?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete %d nodes?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete the root node \"%s\"?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete node \"%s\" and its children?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete node \"%s\"?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can not perform with the root node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "This operation can't be done on instanced scenes."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Save New Scene As..."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Disabling \"editable_instance\" will cause all properties of the node to be "
+"reverted to their default."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Enabling \"Load As Placeholder\" will disable \"Editable Children\" and "
+"cause all properties of the node to be reverted to their default."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make Local"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "New Scene Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Create Root Node:"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "2D Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "3D Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "User Interface"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Other Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't operate on nodes from a foreign scene!"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't operate on nodes the current scene inherits from!"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Attach Script"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Remove Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Change type of node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Couldn't save new scene. Likely dependencies (instances) couldn't be "
+"satisfied."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error saving scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error duplicating scene to save it."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Sub-Resources"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Clear Inheritance"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Editable Children"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Load As Placeholder"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Open Documentation"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Cannot attach a script: there are no languages registered.\n"
+"This is probably because this editor was built with all language modules "
+"disabled."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Add Child Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Expand/Collapse All"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Change Type"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Reparent to New Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make Scene Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Merge From Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
+msgid "Save Branch as Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
+msgid "Copy Node Path"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete (No Confirm)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Add/Create a New Node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Instance a scene file as a Node. Creates an inherited scene if no root node "
+"exists."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Attach a new or existing script to the selected node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Detach the script from the selected node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Remote"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Local"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Clear Inheritance? (No Undo!)"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Toggle Visible"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Unlock Node"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Button Group"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "(Connecting From)"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Node configuration warning:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node has %s connection(s) and %s group(s).\n"
+"Click to show signals dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node has %s connection(s).\n"
+"Click to show signals dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node is in %s group(s).\n"
+"Click to show groups dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Open Script:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node is locked.\n"
+"Click to unlock it."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Children are not selectable.\n"
+"Click to make selectable."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Toggle Visibility"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"AnimationPlayer is pinned.\n"
+"Click to unpin."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Invalid node name, the following characters are not allowed:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Rename Node"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Scene Tree (Nodes):"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Node Configuration Warning!"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Select a Node"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Path is empty."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Filename is empty."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Path is not local."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid base path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "A directory with the same name exists."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "File does not exist."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid extension."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Wrong extension chosen."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error loading template '%s'"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error - Could not create script in filesystem."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error loading script from %s"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Overrides"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "N/A"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Open Script / Choose Location"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Open Script"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "File exists, it will be reused."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid class name."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid inherited parent name or path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Script path/name is valid."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Allowed: a-z, A-Z, 0-9, _ and ."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Built-in script (into scene file)."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Will create a new script file."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Will load an existing script file."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Script file already exists."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid ""
+"Note: Built-in scripts have some limitations and can't be edited using an "
+"external editor."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Class Name:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Template:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Built-in Script:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Attach Node Script"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Remote "
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Bytes:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Warning:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Error:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Error"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Error:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Source"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Source:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Source:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Stack Trace"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Errors"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Child process connected."
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Copy Error"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Video RAM"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Skip Breakpoints"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Inspect Previous Instance"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Inspect Next Instance"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Stack Frames"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Profiler"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Network Profiler"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Monitor"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Value"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Monitors"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Pick one or more items from the list to display the graph."
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "List of Video Memory Usage by Resource:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Total:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Export list to a CSV file"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Resource Path"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Type"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Format"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Usage"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Misc"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Clicked Control:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Clicked Control Type:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Live Edit Root:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Set From Tree"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Export measures as CSV"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Erase Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Restore Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Change Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Editor Settings"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Shortcuts"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Binding"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Light Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change AudioStreamPlayer3D Emission Angle"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Camera FOV"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Camera Size"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Notifier AABB"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Particles AABB"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Probe Extents"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
+msgid "Change Sphere Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
+msgid "Change Box Shape Extents"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Capsule Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Capsule Shape Height"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Cylinder Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Cylinder Shape Height"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Ray Shape Length"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Cylinder Radius"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Cylinder Height"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Torus Inner Radius"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Torus Outer Radius"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Select the dynamic library for this entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Select dependencies of the library for this entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Remove current entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Double click to create a new entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Platform:"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Platform"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Dynamic Library"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Add an architecture entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "GDNativeLibrary"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Enabled GDNative Singleton"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Disabled GDNative Singleton"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Library"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Libraries: "
+msgstr ""
+
+#: modules/gdnative/register_types.cpp
+msgid "GDNative"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Step argument is zero!"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not a script with an instance"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not based on a script"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not based on a resource file"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (missing @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (can't load script at @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (invalid script at @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary (invalid subclasses)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Object can't provide a length."
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Next Plane"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Previous Plane"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Plane:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Next Floor"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Previous Floor"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Floor:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Delete Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Fill Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Paste Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Paint"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Grid Map"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Snap View"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Disabled"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Above"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Below"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit X Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit Y Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit Z Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate X"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate Y"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate Z"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate X"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate Y"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate Z"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Clear Rotation"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Paste Selects"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clear Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Fill Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Settings"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Pick Distance:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Filter meshes"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Give a MeshLibrary resource to this GridMap to use its meshes."
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Begin Bake"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Preparing data structures"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Generate buffers"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Direct lighting"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Indirect lighting"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Post processing"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Plotting lightmaps"
+msgstr ""
+
+#: modules/mono/csharp_script.cpp
+msgid "Class name can't be a reserved keyword"
+msgstr ""
+
+#: modules/mono/mono_gd/gd_mono_utils.cpp
+msgid "End of inner exception stack trace"
+msgstr ""
+
+#: modules/recast/navigation_mesh_editor_plugin.cpp
+msgid "Bake NavMesh"
+msgstr ""
+
+#: modules/recast/navigation_mesh_editor_plugin.cpp
+msgid "Clear the navigation mesh."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Setting up Configuration..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Calculating grid size..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating heightfield..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Marking walkable triangles..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Constructing compact heightfield..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Eroding walkable area..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Partitioning..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating contours..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating polymesh..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Converting to native navigation mesh..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Navigation Mesh Generator Setup:"
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Parsing Geometry..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Done!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"A node yielded without working memory, please read the docs on how to yield "
+"properly!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"Node yielded, but did not return a function state in the first working "
+"memory."
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"Return value must be assigned to first element of node working memory! Fix "
+"your node please."
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Node returned an invalid sequence output: "
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Found sequence bit but not the node in the stack, report bug!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Stack overflow with stack depth: "
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Signal Arguments"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Argument Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Argument name"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Set Variable Default Value"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Set Variable Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Input Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Output Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Override an existing built-in function."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new function."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Variables:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new variable."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Signals:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new signal."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Name is not a valid identifier:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Name already in use by another func/var/signal:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Delete input port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Input Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Output Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Expression"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Duplicate VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a simple reference to the node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a simple reference to the node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a Variable Setter."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a Variable Setter."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Preload Node"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Node(s) From Tree"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid ""
+"Can't drop properties because script '%s' is not used in this scene.\n"
+"Drop holding 'Shift' to just copy the signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Getter Property"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Setter Property"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Base Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Move Node(s)"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove VisualScript Node"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Disconnect Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Node Data"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Node Sequence"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Script already has function '%s'"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Input Value"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Resize Comment"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't copy the function node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Clipboard is empty!"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Paste VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't create function with a function node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't create function of nodes from nodes of multiple functions."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Select at least one node with sequence port."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Try to only have one sequence input in selection."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Editing Variable:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Editing Signal:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Make Tool:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Members:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Base Type:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Nodes..."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Function..."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "function_name"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Select or create a function to edit its graph."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Delete Selected"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Find Node Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Copy Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Cut Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Make Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Refresh Graph"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Edit Member"
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Input type not iterable: "
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Iterator became invalid"
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Iterator became invalid: "
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Invalid index property name."
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Base object is not a Node!"
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Path does not lead Node!"
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Invalid index property name '%s' in node %s."
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ": Invalid argument of type: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ": Invalid arguments: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "VariableGet not found in script: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "VariableSet not found in script: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "Custom node has no _step() method, can't process graph."
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ""
+"Invalid return value from _step(), must be integer (seq out), or string "
+"(error)."
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Search VisualScript"
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Get %s"
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Set %s"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Package name is missing."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Package segments must be of non-zero length."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The character '%s' is not allowed in Android application package names."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "A digit cannot be the first character in a package segment."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The character '%s' cannot be the first character in a package segment."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The package must have at least one '.' separator."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Select device from the list"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find the 'apksigner' tool."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Android build template not installed in the project. Install it from the "
+"Project menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Debug keystore not configured in the Editor Settings nor in the preset."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Release keystore incorrectly configured in the export preset."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "A valid Android SDK path is required in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid Android SDK path in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Missing 'platform-tools' directory!"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find Android SDK platform-tools' adb command."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Please check in the Android SDK directory specified in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Missing 'build-tools' directory!"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find Android SDK build-tools' apksigner command."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid public key for APK expansion."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid package name:"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
+"project setting (changed in Godot 3.2.2).\n"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "\"Use Custom Build\" must be enabled to use the plugins."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
+"\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid filename! Android App Bundle requires the *.aab extension."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "APK Expansion not compatible with Android App Bundle."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid filename! Android APK requires the *.apk extension."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Trying to build from a custom built template, but no version info for it "
+"exists. Please reinstall from the 'Project' menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Android build version mismatch:\n"
+" Template installed: %s\n"
+" Godot Version: %s\n"
+"Please reinstall Android build template from 'Project' menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Building Android Project (gradle)"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Building of Android project failed, check output for the error.\n"
+"Alternatively visit docs.godotengine.org for Android build documentation."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Moving output"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Unable to copy and rename export file, check gradle project directory for "
+"outputs."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Identifier is missing."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "The character '%s' is not allowed in Identifier."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "App Store Team ID not specified - cannot configure the project."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Invalid Identifier:"
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Required icon is not specified in the preset."
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Stop HTTP Server"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Run in Browser"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Run exported HTML in the system's default browser."
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not write file:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not open template for export:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Invalid export template:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not read custom HTML shell:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not read boot splash image file:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Using default boot splash image."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package short name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package unique name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package publisher display name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid product GUID."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid publisher GUID."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid background color."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid Store Logo image dimensions (should be 50x50)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 44x44 logo image dimensions (should be 44x44)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 71x71 logo image dimensions (should be 71x71)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 150x150 logo image dimensions (should be 150x150)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 310x310 logo image dimensions (should be 310x310)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid wide 310x150 logo image dimensions (should be 310x150)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid splash screen image dimensions (should be 620x300)."
+msgstr ""
+
+#: scene/2d/animated_sprite.cpp
+msgid ""
+"A SpriteFrames resource must be created or set in the \"Frames\" property in "
+"order for AnimatedSprite to display frames."
+msgstr ""
+
+#: scene/2d/canvas_modulate.cpp
+msgid ""
+"Only one visible CanvasModulate is allowed per scene (or set of instanced "
+"scenes). The first created one will work, while the rest will be ignored."
+msgstr ""
+
+#: scene/2d/collision_object_2d.cpp
+msgid ""
+"This node has no shape, so it can't collide or interact with other objects.\n"
+"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to "
+"define its shape."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid ""
+"CollisionPolygon2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "An empty CollisionPolygon2D has no effect on collision."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"CollisionShape2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"A shape must be provided for CollisionShape2D to function. Please create a "
+"shape resource for it!"
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"Polygon-based shapes are not meant be used nor edited directly through the "
+"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
+msgstr ""
+
+#: scene/2d/cpu_particles_2d.cpp
+msgid ""
+"CPUParticles2D animation requires the usage of a CanvasItemMaterial with "
+"\"Particles Animation\" enabled."
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A and Node B must be PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A must be a PhysicsBody2D"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node B must be a PhysicsBody2D"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Joint is not connected to two PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A and Node B must be different PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/light_2d.cpp
+msgid ""
+"A texture with the shape of the light must be supplied to the \"Texture\" "
+"property."
+msgstr ""
+
+#: scene/2d/light_occluder_2d.cpp
+msgid ""
+"An occluder polygon must be set (or drawn) for this occluder to take effect."
+msgstr ""
+
+#: scene/2d/light_occluder_2d.cpp
+msgid "The occluder polygon for this occluder is empty. Please draw a polygon."
+msgstr ""
+
+#: scene/2d/navigation_polygon.cpp
+msgid ""
+"A NavigationPolygon resource must be set or created for this node to work. "
+"Please set a property or draw a polygon."
+msgstr ""
+
+#: scene/2d/navigation_polygon.cpp
+msgid ""
+"NavigationPolygonInstance must be a child or grandchild to a Navigation2D "
+"node. It only provides navigation data."
+msgstr ""
+
+#: scene/2d/parallax_layer.cpp
+msgid ""
+"ParallaxLayer node only works when set as child of a ParallaxBackground node."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp
+msgid ""
+"GPU-based particles are not supported by the GLES2 video driver.\n"
+"Use the CPUParticles2D node instead. You can use the \"Convert to "
+"CPUParticles\" option for this purpose."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp scene/3d/particles.cpp
+msgid ""
+"A material to process the particles is not assigned, so no behavior is "
+"imprinted."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp
+msgid ""
+"Particles2D animation requires the usage of a CanvasItemMaterial with "
+"\"Particles Animation\" enabled."
+msgstr ""
+
+#: scene/2d/path_2d.cpp
+msgid "PathFollow2D only works when set as a child of a Path2D node."
+msgstr ""
+
+#: scene/2d/physics_body_2d.cpp
+msgid ""
+"Size changes to RigidBody2D (in character or rigid modes) will be overridden "
+"by the physics engine when running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/2d/remote_transform_2d.cpp
+msgid "Path property must point to a valid Node2D node to work."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid "This Bone2D chain should end at a Skeleton2D node."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid "A Bone2D only works with a Skeleton2D or another Bone2D as parent node."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid ""
+"This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."
+msgstr ""
+
+#: scene/2d/tile_map.cpp
+msgid ""
+"TileMap with Use Parent on needs a parent CollisionObject2D to give shapes "
+"to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, "
+"KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/visibility_notifier_2d.cpp
+msgid ""
+"VisibilityEnabler2D works best when used with the edited scene root directly "
+"as parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRCamera must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRController must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid ""
+"The controller ID must not be 0 or this controller won't be bound to an "
+"actual controller."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRAnchor must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid ""
+"The anchor ID must not be 0 or this anchor won't be bound to an actual "
+"anchor."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVROrigin requires an ARVRCamera child node."
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Finding meshes and lights"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Preparing geometry (%d/%d)"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Preparing environment"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Generating capture"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Saving lightmaps"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Done"
+msgstr ""
+
+#: scene/3d/collision_object.cpp
+msgid ""
+"This node has no shape, so it can't collide or interact with other objects.\n"
+"Consider adding a CollisionShape or CollisionPolygon as a child to define "
+"its shape."
+msgstr ""
+
+#: scene/3d/collision_polygon.cpp
+msgid ""
+"CollisionPolygon only serves to provide a collision shape to a "
+"CollisionObject derived node. Please only use it as a child of Area, "
+"StaticBody, RigidBody, KinematicBody, etc. to give them a shape."
+msgstr ""
+
+#: scene/3d/collision_polygon.cpp
+msgid "An empty CollisionPolygon has no effect on collision."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"CollisionShape only serves to provide a collision shape to a CollisionObject "
+"derived node. Please only use it as a child of Area, StaticBody, RigidBody, "
+"KinematicBody, etc. to give them a shape."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"A shape must be provided for CollisionShape to function. Please create a "
+"shape resource for it."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"Plane shapes don't work well and will be removed in future versions. Please "
+"don't use them."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"ConcavePolygonShape doesn't support RigidBody in another mode than static."
+msgstr ""
+
+#: scene/3d/cpu_particles.cpp
+msgid "Nothing is visible because no mesh has been assigned."
+msgstr ""
+
+#: scene/3d/cpu_particles.cpp
+msgid ""
+"CPUParticles animation requires the usage of a SpatialMaterial whose "
+"Billboard Mode is set to \"Particle Billboard\"."
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid "Plotting Meshes"
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid "Finishing Plot"
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid ""
+"GIProbes are not supported by the GLES2 video driver.\n"
+"Use a BakedLightmap instead."
+msgstr ""
+
+#: scene/3d/light.cpp
+msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
+msgstr ""
+
+#: scene/3d/navigation_mesh.cpp
+msgid "A NavigationMesh resource must be set or created for this node to work."
+msgstr ""
+
+#: scene/3d/navigation_mesh.cpp
+msgid ""
+"NavigationMeshInstance must be a child or grandchild to a Navigation node. "
+"It only provides navigation data."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"GPU-based particles are not supported by the GLES2 video driver.\n"
+"Use the CPUParticles node instead. You can use the \"Convert to CPUParticles"
+"\" option for this purpose."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"Nothing is visible because meshes have not been assigned to draw passes."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"Particles animation requires the usage of a SpatialMaterial whose Billboard "
+"Mode is set to \"Particle Billboard\"."
+msgstr ""
+
+#: scene/3d/path.cpp
+msgid "PathFollow only works when set as a child of a Path node."
+msgstr ""
+
+#: scene/3d/path.cpp
+msgid ""
+"PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its "
+"parent Path's Curve resource."
+msgstr ""
+
+#: scene/3d/physics_body.cpp
+msgid ""
+"Size changes to RigidBody (in character or rigid modes) will be overridden "
+"by the physics engine when running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A and Node B must be PhysicsBodies"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A must be a PhysicsBody"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node B must be a PhysicsBody"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Joint is not connected to any PhysicsBodies"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A and Node B must be different PhysicsBodies"
+msgstr ""
+
+#: scene/3d/remote_transform.cpp
+msgid ""
+"The \"Remote Path\" property must point to a valid Spatial or Spatial-"
+"derived node to work."
+msgstr ""
+
+#: scene/3d/soft_body.cpp
+msgid "This body will be ignored until you set a mesh."
+msgstr ""
+
+#: scene/3d/soft_body.cpp
+msgid ""
+"Size changes to SoftBody will be overridden by the physics engine when "
+"running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/3d/sprite_3d.cpp
+msgid ""
+"A SpriteFrames resource must be created or set in the \"Frames\" property in "
+"order for AnimatedSprite3D to display frames."
+msgstr ""
+
+#: scene/3d/vehicle_body.cpp
+msgid ""
+"VehicleWheel serves to provide a wheel system to a VehicleBody. Please use "
+"it as a child of a VehicleBody."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"WorldEnvironment requires its \"Environment\" property to contain an "
+"Environment to have a visible effect."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set "
+"this environment's Background Mode to Canvas (for 2D scenes)."
+msgstr ""
+
+#: scene/animation/animation_blend_tree.cpp
+msgid "On BlendTree node '%s', animation not found: '%s'"
+msgstr ""
+
+#: scene/animation/animation_blend_tree.cpp
+msgid "Animation not found: '%s'"
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "In node '%s', invalid animation: '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Invalid animation: '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Nothing connected to input '%s' of node '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "No root AnimationNode for the graph is set."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Path to an AnimationPlayer node containing animations is not set."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Path set for AnimationPlayer does not lead to an AnimationPlayer node."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "The AnimationPlayer root node is not a valid node."
+msgstr ""
+
+#: scene/animation/animation_tree_player.cpp
+msgid "This node has been deprecated. Use AnimationTree instead."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid ""
+"Color: #%s\n"
+"LMB: Set color\n"
+"RMB: Remove preset"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Pick a color from the editor window."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "HSV"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Raw"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Switch between hexadecimal and code values."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Add current color as a preset."
+msgstr ""
+
+#: scene/gui/container.cpp
+msgid ""
+"Container by itself serves no purpose unless a script configures its "
+"children placement behavior.\n"
+"If you don't intend to add a script, use a plain Control node instead."
+msgstr ""
+
+#: scene/gui/control.cpp
+msgid ""
+"The Hint Tooltip won't be displayed as the control's Mouse Filter is set to "
+"\"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."
+msgstr ""
+
+#: scene/gui/dialogs.cpp
+msgid "Alert!"
+msgstr ""
+
+#: scene/gui/dialogs.cpp
+msgid "Please Confirm..."
+msgstr ""
+
+#: scene/gui/file_dialog.cpp
+msgid "Must use a valid extension."
+msgstr ""
+
+#: scene/gui/graph_edit.cpp
+msgid "Enable grid minimap."
+msgstr ""
+
+#: scene/gui/popup.cpp
+msgid ""
+"Popups will hide by default unless you call popup() or any of the popup*() "
+"functions. Making them visible for editing is fine, but they will hide upon "
+"running."
+msgstr ""
+
+#: scene/gui/range.cpp
+msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
+msgstr ""
+
+#: scene/gui/scroll_container.cpp
+msgid ""
+"ScrollContainer is intended to work with a single child control.\n"
+"Use a container as child (VBox, HBox, etc.), or a Control and set the custom "
+"minimum size manually."
+msgstr ""
+
+#: scene/gui/tree.cpp
+msgid "(Other)"
+msgstr ""
+
+#: scene/main/scene_tree.cpp
+msgid ""
+"Default Environment as specified in Project Settings (Rendering -> "
+"Environment -> Default Environment) could not be loaded."
+msgstr ""
+
+#: scene/main/viewport.cpp
+msgid ""
+"This viewport is not set as render target. If you intend for it to display "
+"its contents directly to the screen, make it a child of a Control so it can "
+"obtain a size. Otherwise, make it a RenderTarget and assign its internal "
+"texture to some node for display."
+msgstr ""
+
+#: scene/main/viewport.cpp
+msgid "Viewport size must be greater than 0 to render anything."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid ""
+"The sampler port is connected but not used. Consider changing the source to "
+"'SamplerPort'."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid source for preview."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid source for shader."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid comparison function for that type."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Assignment to function."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Assignment to uniform."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Varyings can only be assigned in vertex function."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Constants cannot be modified."
+msgstr ""
diff --git a/editor/translations/bg.po b/editor/translations/bg.po
index 548d71df18..65a77ffd74 100644
--- a/editor/translations/bg.po
+++ b/editor/translations/bg.po
@@ -1097,6 +1097,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr "БлагодарноÑти от общноÑтта на Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2454,9 +2458,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Ðе може да Ñе зареди добавката-Ñкрипт от: „%s“."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Ðе може да Ñе зареди добавката-Ñкрипт от: „%s“. Изглежда има грешка в кода. "
"МолÑ, проверете ÑинтакÑиÑа."
@@ -2884,6 +2890,10 @@ msgid "About"
msgstr "ОтноÑно"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "ПуÑкане на проекта."
@@ -5063,6 +5073,7 @@ msgstr ""
"принадлежат на квадратната облаÑÑ‚ [0.0,1.0]."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
+#, fuzzy
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
@@ -9783,7 +9794,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11800,10 +11811,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/bn.po b/editor/translations/bn.po
index 21144a829b..999d6f59d5 100644
--- a/editor/translations/bn.po
+++ b/editor/translations/bn.po
@@ -7,7 +7,7 @@
# Tahmid Karim <tahmidk15@gmail.com>, 2016.
# Tawhid H. <Tawhidk757@yahoo.com>, 2019.
# Hasibul Hasan <hasibeng78@gmail.com>, 2019.
-# Oymate <dhruboadittya96@gmail.com>, 2020.
+# Oymate <dhruboadittya96@gmail.com>, 2020, 2021.
# Mokarrom Hossain <mhb2016.bzs@gmail.com>, 2020, 2021.
# Sagen Soren <sagensoren03@gmail.com>, 2020.
# Hasibul Hasan <d1hasib@yahoo.com>, 2020.
@@ -15,7 +15,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-15 10:51+0000\n"
+"PO-Revision-Date: 2021-06-11 14:49+0000\n"
"Last-Translator: Mokarrom Hossain <mhb2016.bzs@gmail.com>\n"
"Language-Team: Bengali <https://hosted.weblate.org/projects/godot-engine/"
"godot/bn/>\n"
@@ -24,7 +24,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -47,7 +47,7 @@ msgstr "অবৈধ ইনপà§à¦Ÿ %i (পাস করা হয়নি) à¦
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
-msgstr "self বà§à¦¯à¦¬à¦¹à¦¾à¦° করা যাবে না কারণ instance যà§à¦•à§à¦¤à¦¿à¦¯à§à¦•à§à¦¤ নয়"
+msgstr "self বà§à¦¯à¦¬à¦¹à¦¾à¦° করা যাবে না কারণ instance যà§à¦•à§à¦¤à¦¿à¦¯à§à¦•à§à¦¤ নয় (not passed)"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
@@ -103,7 +103,7 @@ msgstr "মà§à¦•à§à¦¤ করে দিন"
#: editor/animation_bezier_editor.cpp
msgid "Balanced"
-msgstr "সà§à¦¥à¦¿à¦°"
+msgstr "সà§à¦·à¦®"
#: editor/animation_bezier_editor.cpp
msgid "Mirror"
@@ -591,7 +591,7 @@ msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨ (Animation) পরিচà§à¦›à¦¨à§à¦¨ à
#: editor/animation_track_editor.cpp
msgid "Pick the node that will be animated:"
-msgstr ""
+msgstr "নোডটি চয়ন করà§à¦¨ যা অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦Ÿà§‡à¦¡ হবে:"
#: editor/animation_track_editor.cpp
msgid "Use Bezier Curves"
@@ -655,22 +655,20 @@ msgid "Copy"
msgstr "পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿/কপি করà§à¦¨"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Select All/None"
-msgstr "কোনোটাই নিরà§à¦¬à¦¾à¦šà¦¨ করবেন না"
+msgstr "কোনোটাই নিরà§à¦¬à¦¾à¦šà¦¨ করবেন/না"
#: editor/animation_track_editor_plugins.cpp
-#, fuzzy
msgid "Add Audio Track Clip"
-msgstr "অডিও শà§à¦°à§‹à¦¤à¦¾"
+msgstr "অডিও টà§à¦°à§à¦¯à¦¾à¦• কà§à¦²à¦¿à¦ª যà§à¦•à§à¦¤ করà§à¦¨"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
-msgstr ""
+msgstr "অডিও টà§à¦°à§à¦¯à¦¾à¦• কà§à¦²à¦¿à¦ª শà§à¦°à§ অফসেট পরিবরà§à¦¤à¦¨ করà§à¦¨"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr ""
+msgstr "অডিও টà§à¦°à§à¦¯à¦¾à¦• কà§à¦²à¦¿à¦ª শেষ অফসেট পরিবরà§à¦¤à¦¨ করà§à¦¨"
#: editor/array_property_edit.cpp
msgid "Resize Array"
@@ -693,18 +691,16 @@ msgid "Line Number:"
msgstr "লাইন নামà§à¦¬à¦¾à¦°:"
#: editor/code_editor.cpp
-#, fuzzy
msgid "%d replaced."
-msgstr "পà§à¦°à¦¤à¦¿à¦¸à§à¦¥à¦¾à¦ªà¦¨..."
+msgstr "%d পà§à¦°à¦¤à¦¿à¦¸à§à¦¥à¦¾à¦ªà¦¨ করা হয়েছে।"
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
-msgstr ""
+msgstr "% d মিল।"
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d matches."
-msgstr "কোনো মিল নেই"
+msgstr "% d টি মিলছে।"
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
@@ -729,12 +725,11 @@ msgstr "শà§à¦§à§à¦®à¦¾à¦¤à§à¦° নিরà§à¦¬à¦¾à¦šà¦¿à¦¤à¦¸à¦®à§‚হ"
#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
#: editor/plugins/text_editor.cpp
msgid "Standard"
-msgstr ""
+msgstr "আদরà§à¦¶"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Scripts Panel"
-msgstr "ফেবরিট/পà§à¦°à¦¿à¦¯à¦¼-সমূহ অদলবদল/টগল করà§à¦¨"
+msgstr "সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿà¦¸ পà§à¦¯à¦¾à¦¨à§‡à¦² টগল করà§à¦¨"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -753,7 +748,6 @@ msgid "Reset Zoom"
msgstr "সমà§à¦ªà§à¦°à¦¸à¦¾à¦°à¦¨/সংকোচন অপসারণ করà§à¦¨ (রিসেট জà§à¦®à§)"
#: editor/code_editor.cpp
-#, fuzzy
msgid "Warnings"
msgstr "সতরà§à¦•তা"
@@ -1149,6 +1143,10 @@ msgstr "ডিকশনারি ভà§à¦¯à¦¾à¦²à§ পরিবরà§à¦¤à¦¨ à¦
msgid "Thanks from the Godot community!"
msgstr "Godot কমিউনিটি হতে আপনাকে ধনà§à¦¯à¦¬à¦¾à¦¦!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine কনà§à¦Ÿà§à¦°à¦¿à¦¬à¦¿à¦‰à¦Ÿà¦°à¦¸"
@@ -1179,11 +1177,11 @@ msgstr "লেখক"
#: editor/editor_about.cpp
msgid "Platinum Sponsors"
-msgstr "পà§à¦²à§à¦¯à¦¾à¦Ÿà¦¿à¦¨à¦¾à¦® সà§à¦ªà¦¨à¦¸à¦°"
+msgstr "পà§à¦²à§à¦¯à¦¾à¦Ÿà¦¿à¦¨à¦¾à¦® বিজà§à¦žà¦¾à¦ªà¦•"
#: editor/editor_about.cpp
msgid "Gold Sponsors"
-msgstr "গোলà§à¦¡ সà§à¦ªà¦¨à¦¸à¦°"
+msgstr "সোনালি বিজà§à¦žà¦¾à¦ªà¦•"
#: editor/editor_about.cpp
#, fuzzy
@@ -1197,7 +1195,7 @@ msgstr "বà§à¦°à§‹à¦žà§à¦œ ডোনার"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
-msgstr "মিনি সà§à¦ªà¦¨à¦¸à¦°"
+msgstr "কà§à¦·à§à¦¦à§à¦° বিজà§à¦žà¦¾à¦ªà¦•"
#: editor/editor_about.cpp
msgid "Gold Donors"
@@ -1375,7 +1373,7 @@ msgstr "ইফেকà§à¦Ÿ ডিলিট করà§à¦¨"
#: editor/editor_audio_buses.cpp
msgid "Audio"
-msgstr ""
+msgstr "শবà§à¦¦"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus"
@@ -1581,7 +1579,7 @@ msgstr "(খালি/শূনà§à¦¯)"
#: editor/editor_data.cpp
msgid "[unsaved]"
-msgstr ""
+msgstr "[অসংরকà§à¦·à¦¿à¦¤]"
#: editor/editor_dir_dialog.cpp
#, fuzzy
@@ -2598,9 +2596,8 @@ msgid "Exit the editor?"
msgstr "à¦à¦¡à¦¿à¦Ÿà¦° হতে পà§à¦°à¦¸à§à¦¥à¦¾à¦¨ করবেন?"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Open Project Manager?"
-msgstr "পà§à¦°à¦•লà§à¦ª মà§à¦¯à¦¾à¦¨à§‡à¦œà¦¾à¦°"
+msgstr "Open পà§à¦°à¦•লà§à¦ª মà§à¦¯à¦¾à¦¨à§‡à¦œà¦¾à¦°?"
#: editor/editor_node.cpp
#, fuzzy
@@ -2654,8 +2651,9 @@ msgstr "%s হতে সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ তà§à¦²à¦¤à§‡/লোডে à¦
#: editor/editor_node.cpp
#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"'%s' পাথ বà§à¦¯à¦¾à¦¬à¦¹à¦¾à¦° করে অà§à¦¯à¦¾à¦¡-অন সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ লোড করা সমà§à¦­à¦¬ হয়নি। সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿà¦Ÿà¦¿ টà§à¦² মোডে নেই।"
@@ -3135,6 +3133,10 @@ msgid "About"
msgstr "সমà§à¦¬à¦¨à§à¦§à§‡"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "পà§à¦°à¦•লà§à¦ªà¦Ÿà¦¿ চালান।"
@@ -3271,13 +3273,12 @@ msgid "Open & Run a Script"
msgstr "à¦à¦•টি সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ খà§à¦²à§à¦¨ à¦à¦¬à¦‚ চালান"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
msgstr ""
"নিমà§à¦¨à§‹à¦•à§à¦¤ ফাইলসমূহ ডিসà§à¦•ে নতà§à¦¨à¦¤à¦°à¥¤\n"
-"কোন সিধানà§à¦¤à¦Ÿà¦¿ নেয়া উচিত হবে?:"
+"কোন সিধানà§à¦¤à¦Ÿà¦¿ নেয়া উচিত হবে?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -3441,7 +3442,7 @@ msgstr "চালà§"
#: editor/editor_properties.cpp
msgid "Layer"
-msgstr ""
+msgstr "সà§à¦¤à¦°"
#: editor/editor_properties.cpp
#, fuzzy
@@ -3537,7 +3538,7 @@ msgstr "সেল (Cell)-à¦à¦° আকার:"
#: editor/editor_properties_array_dict.cpp
msgid "Page: "
-msgstr ""
+msgstr "পাতা: "
#: editor/editor_properties_array_dict.cpp
#: editor/plugins/theme_editor_plugin.cpp
@@ -3834,9 +3835,8 @@ msgid "Remove Template"
msgstr "বসà§à¦¤à§ অপসারণ করà§à¦¨"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Select Template File"
-msgstr "নিরà§à¦¬à¦¾à¦šà¦¿à¦¤ ফাইলসমূহ অপসারণ করবেন?"
+msgstr "টেমপà§à¦²à§‡à¦Ÿ ফাইল নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨"
#: editor/export_template_manager.cpp
#, fuzzy
@@ -4480,7 +4480,7 @@ msgstr "পà§à¦²à¦¾à¦—ইন-সমূহ"
#: editor/plugin_config_dialog.cpp
msgid "Subfolder:"
-msgstr ""
+msgstr "উপফোলà§à¦¡à¦¾à¦°:"
#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
#, fuzzy
@@ -4850,9 +4850,8 @@ msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨à§‡à¦° নাম পরিবরà§à¦¤à¦¨
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Delete Animation?"
-msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨ পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ করà§à¦¨"
+msgstr "Delete অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨?"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
@@ -4993,7 +4992,7 @@ msgstr "গঠনবিনà§à¦¯à¦¾à¦¸"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Depth"
-msgstr ""
+msgstr "গভীরতা"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "1 step"
@@ -5078,11 +5077,11 @@ msgstr "সমাপà§à¦¤à¦¿(সমূহ)"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Immediate"
-msgstr ""
+msgstr "তাৎকà§à¦·à¦£à¦¿à¦•"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Sync"
-msgstr ""
+msgstr "সিঙà§à¦•"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "At End"
@@ -5090,7 +5089,7 @@ msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Travel"
-msgstr ""
+msgstr "ভà§à¦°à¦®à¦£"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Start and end nodes are needed for a sub-transition."
@@ -5467,7 +5466,7 @@ msgstr "পরবরà§à¦¤à§€"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Last"
-msgstr ""
+msgstr "শেষ"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "All"
@@ -5558,9 +5557,8 @@ msgid "Bake Lightmaps"
msgstr "লাইটà§à¦®à§à¦¯à¦¾à¦ªà§‡ হসà§à¦¤à¦¾à¦¨à§à¦¤à¦° করà§à¦¨:"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "নিরà§à¦¬à¦¾à¦šà¦¿à¦¤ ফাইলসমূহ অপসারণ করবেন?"
+msgstr "লাইটমà§à¦¯à¦¾à¦ª বেক ফাইলটি নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -7021,7 +7019,7 @@ msgstr "Polygon 2D UV à¦à¦¡à¦¿à¦Ÿà¦°"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "UV"
-msgstr ""
+msgstr "অতিবেগà§à¦¨à§€"
#: editor/plugins/polygon_2d_editor_plugin.cpp
#, fuzzy
@@ -7097,7 +7095,7 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Radius:"
-msgstr ""
+msgstr "বà§à¦¯à¦¾à¦¸à¦¾à¦°à§à¦§:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
#, fuzzy
@@ -7230,11 +7228,8 @@ msgid "Clear Recent Files"
msgstr "বোনà§â€Œ/হাড় পরিষà§à¦•ার করà§à¦¨"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Close and save changes?"
-msgstr ""
-"বনà§à¦§ à¦à¦¬à¦‚ পরিবরà§à¦¤à¦¨ সংরকà§à¦·à¦£ করবেন?\n"
-"\""
+msgstr "বনà§à¦§ à¦à¦¬à¦‚ পরিবরà§à¦¤à¦¨ সংরকà§à¦·à¦£ করবেন?"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -7735,13 +7730,12 @@ msgid "Go to Previous Breakpoint"
msgstr "পূরà§à¦¬à§‡à¦° বিরতিবিনà§à¦¦à§à¦¤à§‡ যান"
#: editor/plugins/shader_editor_plugin.cpp
-#, fuzzy
msgid ""
"This shader has been modified on on disk.\n"
"What action should be taken?"
msgstr ""
"নিমà§à¦¨à§‹à¦•à§à¦¤ ফাইলসমূহ ডিসà§à¦•ে নতà§à¦¨à¦¤à¦°à¥¤\n"
-"কোন সিধানà§à¦¤à¦Ÿà¦¿ নেয়া উচিত হবে?:"
+"কোন সিধানà§à¦¤à¦Ÿà¦¿ নেয়া উচিত হবে?"
#: editor/plugins/shader_editor_plugin.cpp
msgid "Shader"
@@ -8364,7 +8358,7 @@ msgstr "ফà§à¦°à§‡à¦®à¦¸à¦®à§‚হ সà§à¦¤à§‚প করà§à¦¨"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Simplification: "
-msgstr ""
+msgstr "সরলীকরণ: "
#: editor/plugins/sprite_editor_plugin.cpp
#, fuzzy
@@ -8556,7 +8550,7 @@ msgstr "পদকà§à¦·à§‡à¦ª:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Sep.:"
-msgstr ""
+msgstr "বিভকà§à¦¤à¦•ারক:"
#: editor/plugins/texture_region_editor_plugin.cpp
#, fuzzy
@@ -10721,7 +10715,7 @@ msgstr "মাউসের বোতাম"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -10970,7 +10964,7 @@ msgstr "পà§à¦°à¦•à§à¦°à¦¿à¦¯à¦¼à¦¾/অà§à¦¯à¦¾à¦•শন"
#: editor/project_settings_editor.cpp
msgid "Deadzone"
-msgstr ""
+msgstr "মৃতসà§à¦¥à¦¾à¦¨"
#: editor/project_settings_editor.cpp
msgid "Device:"
@@ -12225,7 +12219,7 @@ msgstr "পূরà§à¦¬à§‡à¦° টà§à¦¯à¦¾à¦¬"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Plane:"
-msgstr ""
+msgstr "সমতল:"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Floor"
@@ -12238,7 +12232,7 @@ msgstr "পূরà§à¦¬à§‡à¦° টà§à¦¯à¦¾à¦¬"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Floor:"
-msgstr ""
+msgstr "মেà¦à§‡:"
#: modules/gridmap/grid_map_editor_plugin.cpp
#, fuzzy
@@ -12966,10 +12960,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
@@ -13796,7 +13802,7 @@ msgstr ""
#: scene/gui/tree.cpp
msgid "(Other)"
-msgstr ""
+msgstr "(অনà§à¦¯à¦¾à¦¨à§à¦¯)"
#: scene/main/scene_tree.cpp
msgid ""
diff --git a/editor/translations/br.po b/editor/translations/br.po
index 4d03911bbe..21e33b7372 100644
--- a/editor/translations/br.po
+++ b/editor/translations/br.po
@@ -1098,6 +1098,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2456,8 +2460,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2862,6 +2867,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9695,7 +9704,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11696,10 +11705,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/ca.po b/editor/translations/ca.po
index 01e60b0fac..26e9ac5a45 100644
--- a/editor/translations/ca.po
+++ b/editor/translations/ca.po
@@ -11,13 +11,16 @@
# Adolfo Jayme Barrientos <fitojb@ubuntu.com>, 2020.
# Xavier Gomez <hiulit@gmail.com>, 2020.
# Aina <ainasoga@gmail.com>, 2020.
-# Alex Mancha <codingstain@gmail.com>, 2020.
+# Alex Mancha <codingstain@gmail.com>, 2020, 2021.
+# Carles Pastor Badosa <cpbadosa@gmail.com>, 2021.
+# Roberto Pérez <djleizar@gmail.com>, 2021.
+# Joel Garcia Cascalló <jocsencat@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
-"Last-Translator: roger <616steam@gmail.com>\n"
+"PO-Revision-Date: 2021-05-14 11:19+0000\n"
+"Last-Translator: Joel Garcia Cascalló <jocsencat@gmail.com>\n"
"Language-Team: Catalan <https://hosted.weblate.org/projects/godot-engine/"
"godot/ca/>\n"
"Language: ca\n"
@@ -25,7 +28,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -766,17 +769,16 @@ msgid "Method in target node must be specified."
msgstr "S'ha d'especificar el mètode al node de destinació."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Method name must be a valid identifier."
-msgstr "El nom no és un identificador vàlid:"
+msgstr "El nom del mètode no és un identificador vàlid."
#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
msgstr ""
-"El mètode objectiu no s'ha trobat. Especifiqueu un mètode vàlid o adjunteu-"
-"li un script."
+"El mètode objectiu no s'ha trobat. Especifiqueu un mètode vàlid o adjunteu "
+"un script al node."
#: editor/connections_dialog.cpp
msgid "Connect to Node:"
@@ -813,7 +815,7 @@ msgstr "Treu"
#: editor/connections_dialog.cpp
msgid "Add Extra Call Argument:"
-msgstr "Arguments de Crida addicionals:"
+msgstr "Afegir arguments de crida addicionals:"
#: editor/connections_dialog.cpp
msgid "Extra Call Arguments:"
@@ -862,11 +864,11 @@ msgstr "No es pot connectar el senyal"
#: editor/run_settings_dialog.cpp editor/settings_config_dialog.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Close"
-msgstr "Tanca"
+msgstr "Tancar"
#: editor/connections_dialog.cpp
msgid "Connect"
-msgstr "Connecta"
+msgstr "Connectar"
#: editor/connections_dialog.cpp
msgid "Signal:"
@@ -874,11 +876,11 @@ msgstr "Senyal:"
#: editor/connections_dialog.cpp
msgid "Connect '%s' to '%s'"
-msgstr "Connecta '%s' amb '%s'"
+msgstr "Connectar '%s' amb '%s'"
#: editor/connections_dialog.cpp
msgid "Disconnect '%s' from '%s'"
-msgstr "Desconnecta '%s' de '%s'"
+msgstr "Desconnectar '%s' de '%s'"
#: editor/connections_dialog.cpp
msgid "Disconnect all from signal: '%s'"
@@ -886,12 +888,12 @@ msgstr "Desconnecta-ho tot del senyal: '%s'"
#: editor/connections_dialog.cpp
msgid "Connect..."
-msgstr "Connecta..."
+msgstr "Connectar..."
#: editor/connections_dialog.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Disconnect"
-msgstr "Desconnecta"
+msgstr "Desconnectar"
#: editor/connections_dialog.cpp
msgid "Connect a Signal to a Method"
@@ -911,9 +913,8 @@ msgid "Signals"
msgstr "Senyals"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Filter signals"
-msgstr "Filtrat de Fitxers"
+msgstr "Filtrat de senyals"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
@@ -1126,6 +1127,10 @@ msgstr "Modifica Valor del Diccionari"
msgid "Thanks from the Godot community!"
msgstr "Gràcies de la part de la Comunitat del Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Col·laboradors de Godot Engine"
@@ -1483,7 +1488,7 @@ msgstr "Treu Autocàrrega"
#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
msgid "Enable"
-msgstr "Activa"
+msgstr "Activar"
#: editor/editor_autoload_settings.cpp
msgid "Rearrange Autoloads"
@@ -1491,7 +1496,7 @@ msgstr "Reorganitza AutoCàrregues"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "No es pot afegir l'autocàrrega:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -2369,14 +2374,13 @@ msgstr ""
"panell d'importació i torneu-lo a importar."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"This scene was imported, so changes to it won't be kept.\n"
"Instancing it or inheriting will allow making changes to it.\n"
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
-"En ser una escena importada, no se'n conservaran els canvis. \n"
+"En ser una escena importada, no se'n conservaran els canvis.\n"
"Instanciar o heretar l'escena permetria la seva modificació.\n"
"Referiu-vos a la documentació rellevant sobre la importació d'escenes per a "
"més informació."
@@ -2558,9 +2562,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Error carregant l'Script complement des del camí: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"No es pot carregar l'script d'addon des del camí: '%s' Sembla que hi ha un "
"error en el codi, si us plau comproveu la sintaxi."
@@ -3015,6 +3021,10 @@ msgid "About"
msgstr "Quant a"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Reprodueix el projecte."
@@ -3159,13 +3169,12 @@ msgid "Open & Run a Script"
msgstr "Obre i Executa un Script"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
msgstr ""
-"El disc conté versions més recents dels fitxer següents. \n"
-"Quina acció voleu seguir?:"
+"El disc conté versions més recents dels fitxer següents.\n"
+"Quina acció voleu seguir?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -4803,9 +4812,8 @@ msgid "Move Node"
msgstr "Moure Node"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition exists!"
-msgstr "Transició: "
+msgstr "La transició existeix!"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Add Transition"
@@ -7500,9 +7508,8 @@ msgid "Yaw"
msgstr "Guinyada"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Mida: "
+msgstr "Mida:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -10406,7 +10413,7 @@ msgstr "Botó del ratolí"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Nom d'acció no vàlid. No pot estar buit ni contenir '/', ':', '=', '\\' o "
@@ -10780,9 +10787,8 @@ msgid "Batch Rename"
msgstr "Reanomena"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "Reemplaça: "
+msgstr "Reemplaça:"
#: editor/rename_dialog.cpp
#, fuzzy
@@ -11543,7 +11549,7 @@ msgstr "Procés Fill Connectat"
#: editor/script_editor_debugger.cpp
msgid "Copy Error"
-msgstr "Error de Còpia"
+msgstr "Copia l'error"
#: editor/script_editor_debugger.cpp
#, fuzzy
@@ -12566,10 +12572,22 @@ msgstr ""
"des del menú Editor."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
@@ -13258,15 +13276,15 @@ msgstr ""
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be PhysicsBodies"
-msgstr ""
+msgstr "Node A i Node B han de ser PhysicsBodies"
#: scene/3d/physics_joint.cpp
msgid "Node A must be a PhysicsBody"
-msgstr ""
+msgstr "El node A ha de ser de tipus PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Node B must be a PhysicsBody"
-msgstr ""
+msgstr "El node B ha de ser de tipus PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Joint is not connected to any PhysicsBodies"
@@ -13274,7 +13292,7 @@ msgstr ""
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be different PhysicsBodies"
-msgstr ""
+msgstr "El Node A i el Node B han de ser PhysicsBodies diferents"
#: scene/3d/remote_transform.cpp
#, fuzzy
@@ -13343,18 +13361,16 @@ msgid "On BlendTree node '%s', animation not found: '%s'"
msgstr ""
#: scene/animation/animation_blend_tree.cpp
-#, fuzzy
msgid "Animation not found: '%s'"
-msgstr "Eines d'Animació"
+msgstr "Animació no trobada: '%s'"
#: scene/animation/animation_tree.cpp
msgid "In node '%s', invalid animation: '%s'."
msgstr "En el node '%s', l'animació no és valida: '%s'."
#: scene/animation/animation_tree.cpp
-#, fuzzy
msgid "Invalid animation: '%s'."
-msgstr "ERROR: El Nom de l'Animació no és vàlid!"
+msgstr "Animació invàlida: '%s'."
#: scene/animation/animation_tree.cpp
#, fuzzy
@@ -13382,7 +13398,7 @@ msgstr "L'arbre d'animació no és vàlid."
#: scene/animation/animation_tree_player.cpp
msgid "This node has been deprecated. Use AnimationTree instead."
-msgstr ""
+msgstr "Aquest node està en desús. Fes servir AnimationTree."
#: scene/gui/color_picker.cpp
#, fuzzy
@@ -13443,9 +13459,8 @@ msgid "Must use a valid extension."
msgstr "Cal utilitzar una extensió vàlida."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "Activar Ajustament"
+msgstr "Activar graella del minimapa"
#: scene/gui/popup.cpp
#, fuzzy
diff --git a/editor/translations/cs.po b/editor/translations/cs.po
index 79163c835f..8f1e930115 100644
--- a/editor/translations/cs.po
+++ b/editor/translations/cs.po
@@ -25,12 +25,13 @@
# kubajz22 <til.jakubesko@seznam.cz>, 2020.
# Václav Blažej <vaclavblazej@seznam.cz>, 2020, 2021.
# ProfJack <profjackcz@gmail.com>, 2021.
+# swifterik <blaha.j502@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-21 07:35+0000\n"
-"Last-Translator: Zbyněk <zbynek.fiala@gmail.com>\n"
+"PO-Revision-Date: 2021-05-21 11:33+0000\n"
+"Last-Translator: swifterik <blaha.j502@gmail.com>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/"
"cs/>\n"
"Language: cs\n"
@@ -1134,6 +1135,10 @@ msgstr "Změnit hodnotu slovníku"
msgid "Thanks from the Godot community!"
msgstr "Děkujeme za komunitu Godotu!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Přispěvatelé do Godot Enginu"
@@ -2548,11 +2553,13 @@ msgstr "Nelze naÄíst skript rozšíření z cesty: '%s'."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Nelze naÄíst skript rozšíření z cesty: '%s'. Zdá se, že se v kódu nachází "
-"chyba. Prosím, zkontrolujte syntax."
+"chyba.\n"
+"Deaktivujte rozšíření '%s' abyste předešli dalším chybám."
#: editor/editor_node.cpp
msgid ""
@@ -2992,6 +2999,10 @@ msgid "About"
msgstr "O aplikaci"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Podpořte projekt Godot"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Spustit projekt."
@@ -5178,14 +5189,12 @@ msgid "Assets ZIP File"
msgstr "ZIP soubor asetů"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
"Nelze urÄit cestu pro uložení obrázků svÄ›telné mapy.\n"
-"Uložte scénu (obrázky se uloží do stejného adresáře) nebo vyberte cestu pro "
-"uložení z vlastnosti BakedLightmap."
+"Uložte scénu a zkuste to znovu."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5215,6 +5224,7 @@ msgstr ""
"Ätvercové oblasti [0.0, 1.0]."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
+#, fuzzy
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
@@ -10099,7 +10109,7 @@ msgstr "TlaÄítko myÅ¡i"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Neplatné jméno akce. Nesmí být prázdné nebo obsahovat '/', ':', '=', '\\' "
@@ -11627,7 +11637,6 @@ msgid "Post processing"
msgstr "Následné zpracování"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
msgstr "Vykreslování světelných map"
@@ -12148,12 +12157,24 @@ msgstr ""
"z nabídky Projekt."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"ÚložiÅ¡tÄ› klíÄů k ladÄ›ní není nakonfigurováno v Nastavení editoru nebo v "
"export profilu."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"ÚložiÅ¡tÄ› klíÄů pro vydání je nakonfigurováno nesprávnÄ› v profilu exportu."
diff --git a/editor/translations/da.po b/editor/translations/da.po
index 01d6dbc42e..77cd37e20b 100644
--- a/editor/translations/da.po
+++ b/editor/translations/da.po
@@ -5,7 +5,7 @@
# Dankse Memes <purplelops@gmail.com>, 2018.
# David Lamhauge <davidlamhauge@gmail.com>, 2016, 2018.
# Esben Damkjær Sørensen <esben@damkjaergaard.com>, 2018.
-# Kim Nielsen <kimmowich@stofanet.dk>, 2017, 2018.
+# Kim Nielsen <kimmowich@stofanet.dk>, 2017, 2018, 2021.
# Michael Madsen <mim@michael-madsen.dk>, 2017.
# Christoffer Schindel <ceas@outlook.com>, 2018.
# frederikzt <frederikzt@gmail.com>, 2018.
@@ -22,8 +22,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-20 04:18+0000\n"
-"Last-Translator: snakatk <snaqii@live.dk>\n"
+"PO-Revision-Date: 2021-04-26 22:31+0000\n"
+"Last-Translator: Kim Nielsen <kimmowich@stofanet.dk>\n"
"Language-Team: Danish <https://hosted.weblate.org/projects/godot-engine/"
"godot/da/>\n"
"Language: da\n"
@@ -31,7 +31,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1170,6 +1170,10 @@ msgstr "Ændre Dictionary Værdi"
msgid "Thanks from the Godot community!"
msgstr "Tak fra Godot fællesskabet!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine bidragsydere"
@@ -2636,9 +2640,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Kan ikke indlæse addon script fra stien: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Kan ikke indlæse tilføjelse script fra sti: '%s' Der ser ud til at være en "
"fejl i koden, tjek syntaksen."
@@ -3100,6 +3106,10 @@ msgid "About"
msgstr "Om"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Spil dit projekt."
@@ -4813,47 +4823,43 @@ msgstr "Animationsposition (i sekunder)."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Scale animation playback globally for the node."
-msgstr ""
+msgstr "Skalér animation afspilningen globalt for node."
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Animation Tools"
-msgstr "Animation Værktøjer"
+msgstr "Animations Værktøjer"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation"
msgstr "Animation"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Edit Transitions..."
msgstr "Rediger Overgange..."
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Open in Inspector"
-msgstr "Inspektør"
+msgstr "Ã…ben i Inspector"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Display list of animations in player."
-msgstr ""
+msgstr "Vis liste over animationer i afspiller"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Autoplay on Load"
-msgstr ""
+msgstr "Autoplay ved Load"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Enable Onion Skinning"
-msgstr ""
+msgstr "Aktivér Onion Skin"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Onion Skinning Options"
-msgstr ""
+msgstr "Onion Skin Muligheder"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Directions"
-msgstr "Beskrivelse"
+msgstr "Retninger"
#: editor/plugins/animation_player_editor_plugin.cpp
#, fuzzy
@@ -4862,7 +4868,7 @@ msgstr "Indsæt"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Future"
-msgstr ""
+msgstr "Fremtid"
#: editor/plugins/animation_player_editor_plugin.cpp
#, fuzzy
@@ -4883,15 +4889,15 @@ msgstr "3 trin"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Differences Only"
-msgstr ""
+msgstr "Kun Forskelle"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Force White Modulate"
-msgstr ""
+msgstr "Tving Hvid Modulate"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Include Gizmos (3D)"
-msgstr ""
+msgstr "Inkludér Gizmos (3D)"
#: editor/plugins/animation_player_editor_plugin.cpp
#, fuzzy
@@ -4904,7 +4910,7 @@ msgstr "Opret Ny Animation"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation Name:"
-msgstr "Animation Navn:"
+msgstr "Animations Navn:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/resource_preloader_editor_plugin.cpp
@@ -4918,7 +4924,6 @@ msgid "Blend Times:"
msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Next (Auto Queue):"
msgstr "Næste (Auto Kø):"
@@ -4927,9 +4932,8 @@ msgid "Cross-Animation Blend Times"
msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Move Node"
-msgstr "Flyt Node(s)"
+msgstr "Flyt Node"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition exists!"
@@ -4946,32 +4950,31 @@ msgstr "Tilføj Node"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "End"
-msgstr ""
+msgstr "Slut"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Immediate"
-msgstr ""
+msgstr "Umiddelbart"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Sync"
-msgstr ""
+msgstr "Synkroniser"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "At End"
-msgstr ""
+msgstr "I Slutningen"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Travel"
-msgstr ""
+msgstr "Rejse"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Start and end nodes are needed for a sub-transition."
-msgstr ""
+msgstr "Start og slut nodes er nødvendige for en under-overgang."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "No playback resource set at path: %s."
-msgstr "Ikke i stien for ressource."
+msgstr "Ingen afspilnings ressource indstillet på stien: %s"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Node Removed"
@@ -4983,7 +4986,7 @@ msgstr "Overgang Fjernet"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set Start Node (Autoplay)"
-msgstr ""
+msgstr "Sæt Start Node (Autoplay)"
#: editor/plugins/animation_state_machine_editor.cpp
msgid ""
@@ -4991,44 +4994,43 @@ msgid ""
"RMB to add new nodes.\n"
"Shift+LMB to create connections."
msgstr ""
+"Vælg og flyt nodes.\n"
+"RMB for at tilføje ny nodes.\n"
+"Shift+LMB for at oprette forbindelse."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Create new nodes."
-msgstr "Opret Ny %s"
+msgstr "Opret ny nodes."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Connect nodes."
-msgstr "Forbind Nodes"
+msgstr "Forbind nodes."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Remove selected node or transition."
-msgstr "Fjern valgte spor."
+msgstr "Fjern valgte node eller overgang."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Toggle autoplay this animation on start, restart or seek to zero."
msgstr ""
+"Skift autoplay på denne animation ved start, genstart eller seek til zero."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set the end animation. This is useful for sub-transitions."
-msgstr ""
+msgstr "Sæt slut animation. Dette er nyttigt ved under-overgange."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition: "
msgstr "Overgang: "
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Play Mode:"
-msgstr "Eksporter Projekt"
+msgstr "Afspil Mode:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
-#, fuzzy
msgid "AnimationTree"
-msgstr "Animation Zoom."
+msgstr "Animation Tree"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "New name:"
@@ -5037,7 +5039,7 @@ msgstr "Nyt navn:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Scale:"
-msgstr ""
+msgstr "Skalér:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Fade In (s):"
@@ -5062,7 +5064,7 @@ msgstr "Auto Genstart:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Restart (s):"
-msgstr ""
+msgstr "Genstart:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Random Restart (s):"
@@ -5116,11 +5118,11 @@ msgstr "Fjern Input"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Animation tree is valid."
-msgstr ""
+msgstr "Animationstræ er gyldigt."
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Animation tree is invalid."
-msgstr ""
+msgstr "Animationstræ er ugyldigt."
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Animation Node"
@@ -10355,7 +10357,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12487,10 +12489,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/de.po b/editor/translations/de.po
index 9b49a15db4..89ffa6e87c 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -44,7 +44,7 @@
# datenbauer <d-vaupel@web.de>, 2019.
# Alexander Hausmann <alexander-hausmann+weblate@posteo.de>, 2019.
# Nicolas Mohr <81moni1bif@hft-stuttgart.de>, 2019.
-# Linux User <no-ads@mail.de>, 2019.
+# Linux User <no-ads@mail.de>, 2019, 2021.
# David May <wasser@gmail.com>, 2019.
# Draco Drache <jan.holger.te@gmail.com>, 2019.
# Jonas <dotchucknorris@gmx.de>, 2019.
@@ -52,7 +52,7 @@
# artism90 <artism90@googlemail.com>, 2020.
# Jaigskim <filzstift112@gmail.com>, 2020.
# Jacqueline Ulken <Jacqueline.Ulken@protonmail.com>, 2020.
-# Günther Bohn <ciscouser@gmx.de>, 2020.
+# Günther Bohn <ciscouser@gmx.de>, 2020, 2021.
# Tom Wor <mail@tomwor.com>, 2020.
# Bjarne Hiller <bjarne.hiller@gmail.com>, 2020.
# Dirk Federmann <weblategodot@dirkfedermann.de>, 2020.
@@ -67,12 +67,14 @@
# Raphipod <podraphi@googlemail.com>, 2021.
# Daniel Plaster <danimineiromc@googlemail.com>, 2021.
# El Captian <elcaptian@posteo.me>, 2021.
+# Ron Eric Hackländer <mail@roneric.net>, 2021.
+# Stephan Kerbl <stephankerbl@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-31 03:53+0000\n"
-"Last-Translator: So Wieso <sowieso@dukun.de>\n"
+"PO-Revision-Date: 2021-06-07 23:43+0000\n"
+"Last-Translator: Linux User <no-ads@mail.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
"Language: de\n"
@@ -80,7 +82,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -176,15 +178,15 @@ msgstr "Wert:"
#: editor/animation_bezier_editor.cpp
msgid "Insert Key Here"
-msgstr "Hier Schlüsselbild einfügen"
+msgstr "Schlüsselbild hier einfügen"
#: editor/animation_bezier_editor.cpp
msgid "Duplicate Selected Key(s)"
-msgstr "Ausgewählte Schlüssel duplizieren"
+msgstr "Ausgewählte Schlüsselbilder duplizieren"
#: editor/animation_bezier_editor.cpp
msgid "Delete Selected Key(s)"
-msgstr "Ausgewählte Schlüssel löschen"
+msgstr "Ausgewählte Schlüsselbilder löschen"
#: editor/animation_bezier_editor.cpp
msgid "Add Bezier Point"
@@ -1185,6 +1187,10 @@ msgstr "Wörterbuchwert ändern"
msgid "Thanks from the Godot community!"
msgstr "Die Godot-Gemeinschaft bedankt sich!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Mitwirkende der Godot Engine"
@@ -1372,15 +1378,15 @@ msgstr "Mittels Drag&Drop umordnen."
#: editor/editor_audio_buses.cpp
msgid "Solo"
-msgstr "Solo"
+msgstr "Allein"
#: editor/editor_audio_buses.cpp
msgid "Mute"
-msgstr "Stumm"
+msgstr "Stummschalten"
#: editor/editor_audio_buses.cpp
msgid "Bypass"
-msgstr "Bypass"
+msgstr "Überbrückung"
#: editor/editor_audio_buses.cpp
msgid "Bus options"
@@ -1572,7 +1578,7 @@ msgstr "Name"
#: editor/editor_autoload_settings.cpp
msgid "Singleton"
-msgstr "Singleton"
+msgstr "Einzelelement"
#: editor/editor_data.cpp editor/inspector_dock.cpp
msgid "Paste Params"
@@ -1728,7 +1734,7 @@ msgstr "Skript Editor"
#: editor/editor_feature_profile.cpp
msgid "Asset Library"
-msgstr "Bestandsbibliothek"
+msgstr "Bestandsbibliothek (AssetLib)"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
@@ -2169,7 +2175,7 @@ msgstr "Methode"
#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
msgid "Signal"
-msgstr "Signal"
+msgstr "Ereignis"
#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Constant"
@@ -2447,8 +2453,7 @@ msgid ""
"Please read the documentation relevant to debugging to better understand "
"this workflow."
msgstr ""
-"Dies ist ein Laufzeit-Objekt Objekt, Änderungen an ihm werden nicht "
-"gespeichert.\n"
+"Dies ist ein Laufzeit-Objekt, Änderungen werden nicht gespeichert.\n"
"Die Dokumentation zum Debugging beschreibt den nötigen Arbeitsablauf."
#: editor/editor_node.cpp
@@ -2617,11 +2622,13 @@ msgstr "Erweiterungsskript konnte nicht geladen werden: ‚%s‘."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"Erweiterungsskript konnte nicht von folgendem Pfad geladen werden: ‚%s‘. Es "
-"scheint ein Fehler im Quellcode zu sein. Bitte Syntax überprüfen."
+"Erweiterungsskript auf folgendem Pfad konnte nicht geladen werden: ‚%s‘. Es "
+"scheint ein Fehler in dessen Quellcode zu sein.\n"
+"Die Erweiterung ‚%s‘ wird deaktiviert um weitere Fehler zu verhindern."
#: editor/editor_node.cpp
msgid ""
@@ -3065,13 +3072,17 @@ msgstr "Dokumentationsvorschläge senden"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
-msgstr "Gemeinschaft"
+msgstr "Community"
#: editor/editor_node.cpp
msgid "About"
msgstr "Über"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Unterstützung der Godot-Entwicklung"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Projekt abspielen."
@@ -4160,7 +4171,7 @@ msgstr "Importer auswählen"
#: editor/import_defaults_editor.cpp
msgid "Importer:"
-msgstr "Importer:"
+msgstr "Importierer:"
#: editor/import_defaults_editor.cpp
msgid "Reset to Defaults"
@@ -4933,7 +4944,7 @@ msgstr "Abspielmodus:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "AnimationTree"
-msgstr "AnimationsBaum"
+msgstr "AnimationTree"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "New name:"
@@ -5312,7 +5323,7 @@ msgstr ""
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
-"Diese Godot-Version wurde ohne Raytracing-Unterstützung erstellt, Lightmaps "
+"Der Godot-Editor wurde ohne Raytracing-Unterstützung erstellt; Lightmaps "
"können damit nicht gebacken werden."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
@@ -7142,7 +7153,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
-msgstr "Debugger"
+msgstr "Testhilfsprogramm"
#: editor/plugins/script_editor_plugin.cpp
msgid "Search Results"
@@ -7649,6 +7660,8 @@ msgstr "Sichtrotation gesperrt"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Um weiter zoomen zu können müssen die Kameraausschnittebenen geändert werden "
+"(Anzeige -> Einstellungen… )"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -7943,7 +7956,7 @@ msgstr "LightOccluder2D erzeugen"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite"
-msgstr "Sprite"
+msgstr "Bild"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Simplification: "
@@ -8712,7 +8725,7 @@ msgstr "Diese Eigenschaft kann nicht geändert werden."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "TileSet"
-msgstr "TileSet"
+msgstr "Kachelsatz"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No VCS addons are available."
@@ -8823,7 +8836,7 @@ msgstr "Boolean"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Sampler"
-msgstr "Sampler"
+msgstr "Abtaster"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add input port"
@@ -8904,7 +8917,7 @@ msgstr "UniformRef-Name geändert"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
-msgstr "Vertex"
+msgstr "Eckpunkt"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Fragment"
@@ -10240,7 +10253,7 @@ msgstr "Maustaste"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Ungültiger Aktionsname. Er kann weder leer sein noch ‚/‘, ‚:‘, ‚=‘, ‘\\‘ "
@@ -10617,7 +10630,7 @@ msgstr "Präfix:"
#: editor/rename_dialog.cpp
msgid "Suffix:"
-msgstr "Suffix:"
+msgstr "Endung:"
#: editor/rename_dialog.cpp
msgid "Use Regular Expressions"
@@ -10918,7 +10931,7 @@ msgstr "Benutzerschnittstelle"
#: editor/scene_tree_dock.cpp
msgid "Other Node"
-msgstr "Anderer Node"
+msgstr "Anderes Node"
#: editor/scene_tree_dock.cpp
msgid "Can't operate on nodes from a foreign scene!"
@@ -11055,6 +11068,10 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"Falls ausgewählt wird das Panel für den Fern-Szenenbaum jedes mal beim "
+"Aktualisieren das Projekt zum Ruckeln bringen.\n"
+"Für bessere Geschwindigkeit sollte diese Option auf Lokaler Szenenbaum "
+"gestellt werden."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12309,12 +12326,24 @@ msgstr ""
"im Projektmenü installiert werden."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Debug-Keystore wurde weder in den Editoreinstellungen noch in der Vorlage "
"konfiguriert."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Release-Keystore wurde nicht korrekt konfiguriert in den Exporteinstellungen."
@@ -13314,6 +13343,18 @@ msgid "Constants cannot be modified."
msgstr "Konstanten können nicht verändert werden."
#~ msgid ""
+#~ "Godot editor was built without ray tracing support; lightmaps can't be "
+#~ "baked.\n"
+#~ "If you are using an Apple Silicon-based Mac, try forcing Rosetta "
+#~ "emulation on Godot.app in the application settings\n"
+#~ "then restart the editor."
+#~ msgstr ""
+#~ "Der Godot-Editor wurde ohne Raytracing-Unterstützung gebaut; Lightmaps "
+#~ "können nicht gebacken werden.\n"
+#~ "Nutzer eines Macs basierend auf Apple Silicon sollten Rosetta-Emulation "
+#~ "in den Anwendungseinstellungen aktivieren und den Editor neu starten."
+
+#~ msgid ""
#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
#~ msgstr ""
#~ "InterpolatedCamera ist veraltet und wird in Godot 4.0 entfernt werden."
diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot
index 1c44e9dd5c..603b07a6d5 100644
--- a/editor/translations/editor.pot
+++ b/editor/translations/editor.pot
@@ -1076,6 +1076,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2434,8 +2438,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2840,6 +2845,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9673,7 +9682,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11674,10 +11683,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/el.po b/editor/translations/el.po
index 4648f83a72..d85918f2b2 100644
--- a/editor/translations/el.po
+++ b/editor/translations/el.po
@@ -2,22 +2,22 @@
# Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
# Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
# This file is distributed under the same license as the Godot source code.
-# George Tsiamasiotis <gtsiam@windowslive.com>, 2017-2018, 2019, 2020.
+# George Tsiamasiotis <gtsiam@windowslive.com>, 2017-2018, 2019, 2020, 2021.
# Georgios Katsanakis <geo.elgeo@gmail.com>, 2019.
# Overloaded <manoschool@yahoo.gr>, 2019.
# Eternal Death <eternaldeath0001@gmail.com>, 2019.
# Overloaded @ Orama Interactive http://orama-interactive.com/ <manoschool@yahoo.gr>, 2020.
# pandektis <pandektis@gmail.com>, 2020.
# KostasMSC <kargyris@athtech.gr>, 2020.
-# lawfulRobot <czavantias@gmail.com>, 2020.
+# lawfulRobot <czavantias@gmail.com>, 2020, 2021.
# Michalis <michalisntovas@yahoo.gr>, 2021.
# leriaz <leriaz@live.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-29 21:57+0000\n"
-"Last-Translator: leriaz <leriaz@live.com>\n"
+"PO-Revision-Date: 2021-05-30 04:15+0000\n"
+"Last-Translator: lawfulRobot <czavantias@gmail.com>\n"
"Language-Team: Greek <https://hosted.weblate.org/projects/godot-engine/godot/"
"el/>\n"
"Language: el\n"
@@ -25,7 +25,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1051,15 +1051,15 @@ msgstr ""
"επαναφέÏετε."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
"Remove them anyway? (no undo)\n"
"You can find the removed files in the system trash to restore them."
msgstr ""
-"Τα αÏχεία που αφαιÏοÏνται απαιτοÏνται από άλλους πόÏους για να δουλέψουν.\n"
-"Îα αφαιÏεθοÏν; (ΑδÏνατη η αναίÏεση)"
+"Τα αÏχεία που αφαιÏοÏνται απαιτοÏνται για την λειτουÏγία άλλων πόÏων.\n"
+"Îα αφαιÏεθοÏν; (ΑδÏνατη η αναίÏεση)\n"
+"ΜποÏείτε να τα επαναφέÏετε αÏγότεÏα από τον κάδο ανακÏκλωσης του συστήματος."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1129,6 +1129,10 @@ msgstr "Αλλαγή τιμής λεξικοÏ"
msgid "Thanks from the Godot community!"
msgstr "ΕυχαÏιστίες από την κοινότητα της Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "ΣυνεισφέÏοντες στην Godot Engine"
@@ -1614,22 +1618,20 @@ msgstr ""
"«Driver Fallback Enabled»."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"Η πλατφόÏμα Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï Î±Ï€Î±Î¹Ï„ÎµÎ¯ «ETC» συμπίεση υφών για το GLES2. "
-"ΕνεÏγοποιήστε το «Import Etc» στις Ρυθμίσεις ΈÏγου."
+"Η πλατφόÏμα Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï Î±Ï€Î±Î¹Ï„ÎµÎ¯ συμπίεση υφών 'PVRTC' για το GLES2. "
+"ΕνεÏγοποιήστε το 'Εισαγωγή PVRTC' στις Ρυθμίσεις ΈÏγου."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
-"Η πλατφόÏμα Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï Î±Ï€Î±Î¹Ï„ÎµÎ¯ «ETC2» συμπίεση υφών για το GLES3. "
-"ΕνεÏγοποιήστε το «Import Etc 2» στις Ρυθμίσεις ΈÏγου."
+"Η πλατφόÏμα Ï€ÏοοÏÎ¹ÏƒÎ¼Î¿Ï Î±Ï€Î±Î¹Ï„ÎµÎ¯ συμπίεση υφών 'ETC2' ή PVRTC' για το GLES3. "
+"ΕνεÏγοποιήστε το 'Εισαγωγή ETC2' ή 'Εισαγωγή PVRTC' στις Ρυθμίσεις ΈÏγου."
#: editor/editor_export.cpp
#, fuzzy
@@ -2323,6 +2325,10 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"ΠÏόεκυψε ένα σφάλμα κατά την αποθήκευση της διάταξης του Ï€ÏογÏάμματος "
+"επεξεÏγασίας.\n"
+"Βεβαιωθείτε ότι η διαδÏομή δεδομένων του χÏήστη του Ï€ÏογÏάμματος "
+"επεξεÏγασίας είναι εγγÏάψιμη."
#: editor/editor_node.cpp
msgid ""
@@ -2330,15 +2336,18 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Η Ï€Ïοεπιλεγμένη διάταξη του Ï€ÏογÏάμματος επεξεÏγασίας έχει παÏακαμφθεί.\n"
+"Για να επαναφέÏετε την ΠÏοεπιλεγμένη διάταξη στις βασικές Ïυθμίσεις, "
+"διαλέξτε την επιλογή ΔιαγÏαφή Διάταξης και διαγÏάψτε την ΠÏοεπιλεγμένη "
+"διάταξη."
#: editor/editor_node.cpp
msgid "Layout name not found!"
msgstr "Το όνομα της διάταξης δεν βÏέθηκε!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
-msgstr "ΕπαναφοÏά της Ï€Ïοεπιλεγμένης διάταξης στις βασικές Ïυθμίσεις."
+msgstr "Έγινε επαναφοÏά της Ï€Ïοεπιλεγμένης διάταξης στις βασικές Ïυθμίσεις."
#: editor/editor_node.cpp
msgid ""
@@ -2397,7 +2406,7 @@ msgstr "Δεν υπάÏχει καθοÏισμένη σκηνή για εκτεÎ
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Αποθήκευση σκηνής Ï€Ïιν την εκτέλεση..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2546,11 +2555,9 @@ msgstr ""
"αÏχείου ÏÏθμισης."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
-"ΑδÏνατη η έυÏεση του πεδίου 'script' για την Ï€Ïόσθετη επέκταση στο: 'res://"
-"addons/%s'."
+"ΑδÏνατη η έυÏεση του πεδίου δέσμης ενεÏγειών για το Ï€Ïόσθετο στο: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2558,11 +2565,13 @@ msgstr "ΑδÏνατη η φόÏτωση δέσμης ενεÏγειών Ï€ÏοÏ
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Αποτυχία φόÏτωσης δέσμης ενεÏγειών Ï€Ïοσθέτου από τη διαδÏομή: '%s'. Φαίνεται "
-"πως υπάÏχει λάθος στον κώδικα."
+"πως υπάÏχει λάθος στον κώδικα.\n"
+"Έγινε απενεÏγοποίηση το Ï€Ïοσθέτου '%s' για αποτÏοπή πεÏαιτέÏω Ï€Ïοβλημάτων."
#: editor/editor_node.cpp
msgid ""
@@ -3013,6 +3022,11 @@ msgid "About"
msgstr "Σχετικά"
#: editor/editor_node.cpp
+#, fuzzy
+msgid "Support Godot Development"
+msgstr "ΥποστηÏίξτε την ανάπτυξη του Godot"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "ΑναπαÏαγωγή του έÏγου."
@@ -3155,13 +3169,12 @@ msgid "Open & Run a Script"
msgstr "Άνοιξε & ΤÏέξε μία δέσμη ενεÏγειών"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
msgstr ""
"Τα ακόλουθα αÏχεία είναι νεότεÏα στον δίσκο.\n"
-"Τι δÏάση να ληφθεί;:"
+"Τι δÏάση να ληφθεί;"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -3703,9 +3716,12 @@ msgstr ""
"επανεισάγετε το χειÏοκίνητα."
#: editor/filesystem_dock.cpp
+#, fuzzy
msgid ""
"Importing has been disabled for this file, so it can't be opened for editing."
msgstr ""
+"Η εισαγωγή έχει απενεÏγοποιηθεί για αυτό το αÏχείο, οπότε δεν μποÏεί να "
+"ανοιχτεί για επεξεÏγασία."
#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
@@ -3752,6 +3768,12 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
+"Τα ακόλουθα αÏχεία ή φάκελοι συγκÏοÏονται με στοιχεία στον Ï€ÏοοÏισμό \"%s"
+"\":\n"
+"\n"
+"%s\n"
+"\n"
+"Θέλετε να τα αντικαταστήσετε;"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
@@ -3834,7 +3856,7 @@ msgstr "ΑναπαÏαγωγή..."
#: editor/filesystem_dock.cpp
#, fuzzy
msgid "Move to Trash"
-msgstr "Μετακίνηση AutoLoad"
+msgstr "Μετακίνηση στα αποÏÏίμματα"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
@@ -3945,19 +3967,16 @@ msgid "Searching..."
msgstr "Αναζήτηση..."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d match in %d file."
-msgstr "%d αποτελέσματα."
+msgstr "%d αποτέλεσμα σε %d αÏχείο."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d file."
-msgstr "%d αποτελέσματα."
+msgstr "%d αποτελέσματα σε %d αÏχείο."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d files."
-msgstr "%d αποτελέσματα."
+msgstr "%d αποτελέσματα σε %d αÏχεία."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -4097,23 +4116,20 @@ msgid "Saving..."
msgstr "Αποθήκευση..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Επιλογή ΛειτουÏγίας"
+msgstr "Επιλογή Εισαγωγέα"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Εισαγωγή"
+msgstr "Εισαγωγέας:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "ΧÏήση Ï€Ïοεπιλεγμένου sRGB"
+msgstr "ΕπαναφοÏά Ï€Ïοεπιλογών"
#: editor/import_dock.cpp
msgid "Keep File (No Import)"
-msgstr ""
+msgstr "ΔιατήÏηση αÏχειου (ΧωÏίς Εισαγωγή)"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -5218,16 +5234,13 @@ msgid "Assets ZIP File"
msgstr "ΑÏχείο ZIP των Στοιχείων"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
"Δεν ήταν δυνατός ο Ï€ÏοσδιοÏισμός διαδÏομής αποθήκευσης για εικόνες "
"lightmap.\n"
-"ΑποθηκεÏστε τη σκηνή σας (ώστε οι εικόνες να αποθηκευτοÏν στον ίδιο "
-"κατάλογο), ή επιλέξτε μία διαδÏομή αποθήκευσης από τις ιδιότητες του "
-"BakedLightMap."
+"ΑποθηκεÏστε τη σκηνή σας και δοκιμάστε ξανα."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -7423,9 +7436,8 @@ msgid "Yaw"
msgstr "ΠαÏέκκλιση"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Μέγεθος: "
+msgstr "Μέγεθος"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -10202,7 +10214,7 @@ msgstr "Κουμπί ποντικιοÏ"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"ΆκυÏο όνομα ενέÏγειας. Δεν μποÏεί να είναι άδειο ή να πεÏιέχει «/», «:», "
@@ -10362,7 +10374,7 @@ msgstr "Σφάλμα κατά την αποθήκευση Ïυθμίσεων."
#: editor/project_settings_editor.cpp
msgid "Settings saved OK."
-msgstr "Οι Ïυθμίσεις αποθηκεÏτικαν εντάξει."
+msgstr "Οι Ïυθμίσεις αποθηκεÏτηκαν εντάξει."
#: editor/project_settings_editor.cpp
msgid "Moved Input Action Event"
@@ -10758,9 +10770,8 @@ msgid "Instance Child Scene"
msgstr "ΑÏχικοποίηση σκηνής ως παιδί"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Can't paste root node into the same scene."
-msgstr "Δεν είναι δυνατή η λειτουÏγία σε κόμβους από ξένη σκηνή!"
+msgstr "Δεν είναι δυνατή η επικόλληση του ÏÎ¹Î¶Î¹ÎºÎ¿Ï ÎºÏŒÎ¼Î²Î¿Ï… στην ίδια σκηνή."
#: editor/scene_tree_dock.cpp
#, fuzzy
@@ -12287,12 +12298,24 @@ msgstr ""
"«ΈÏγο»."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Το «debug keystore» δεν έχει καθοÏιστεί στις Ρυθμίσεις ΕπεξεÏγαστή ή την "
"διαμόÏφωση."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Εσφαλμένη ÏÏθμιση αποθετηÏίου κλειδιών διανομής στην διαμόÏφωση εξαγωγής."
@@ -12814,9 +12837,8 @@ msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Ανάλυση γεωμετÏίας..."
+msgstr "ΠÏοετοιμασία γεωμετÏίας (%d/%d)"
#: scene/3d/baked_lightmap.cpp
#, fuzzy
diff --git a/editor/translations/eo.po b/editor/translations/eo.po
index 3fe7877be0..21d94bda5e 100644
--- a/editor/translations/eo.po
+++ b/editor/translations/eo.po
@@ -16,7 +16,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"PO-Revision-Date: 2021-06-02 09:04+0000\n"
"Last-Translator: mourning20s <mourning20s@protonmail.com>\n"
"Language-Team: Esperanto <https://hosted.weblate.org/projects/godot-engine/"
"godot/eo/>\n"
@@ -196,27 +196,27 @@ msgstr "Aliigi Animadon Iteracion"
#: editor/animation_track_editor.cpp
msgid "Property Track"
-msgstr "Atributo Vojeto"
+msgstr "Atributa trako"
#: editor/animation_track_editor.cpp
msgid "3D Transform Track"
-msgstr "3D Transformo Vojeto"
+msgstr "3D-transforma trako"
#: editor/animation_track_editor.cpp
msgid "Call Method Track"
-msgstr "Alvoki Metodon Vojeto"
+msgstr "Metod-alvoka trako"
#: editor/animation_track_editor.cpp
msgid "Bezier Curve Track"
-msgstr "Bezier-kurbo Vojeto"
+msgstr "Bezier-kurba trako"
#: editor/animation_track_editor.cpp
msgid "Audio Playback Track"
-msgstr "AÅ­dio Reproduktado Vojeto"
+msgstr "AÅ­dia reproduktada trako"
#: editor/animation_track_editor.cpp
msgid "Animation Playback Track"
-msgstr "Animado Reproduktado Vojeto"
+msgstr "Animacia reproduktada trako"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
@@ -228,7 +228,7 @@ msgstr "Animado loneco (sekundoj)"
#: editor/animation_track_editor.cpp
msgid "Add Track"
-msgstr "Adici Vojeton"
+msgstr "Aldoni trakon"
#: editor/animation_track_editor.cpp
msgid "Animation Looping"
@@ -249,11 +249,11 @@ msgstr "Animado Filmitaĵero:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
-msgstr "Aliigi Vojeton Vojon"
+msgstr "ÅœanÄi vojon de trako"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr "Baskuligi tio ĉi vojeto Åaltita/malÅaltita."
+msgstr "Åœalti/malÅalti ĉi tiun trakon."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
@@ -269,7 +269,7 @@ msgstr "Iteracio Volvi Modo (Interpoli finon kun komenco de iteracio)"
#: editor/animation_track_editor.cpp
msgid "Remove this track."
-msgstr "Forigi tio ĉi vojeton."
+msgstr "Forigi ĉi tiun trakon."
#: editor/animation_track_editor.cpp
msgid "Time (s): "
@@ -277,7 +277,7 @@ msgstr "Fojo (s): "
#: editor/animation_track_editor.cpp
msgid "Toggle Track Enabled"
-msgstr "Baskuligi Vojeton Åœaltitis"
+msgstr "Åœalti/malÅalti trakon"
#: editor/animation_track_editor.cpp
msgid "Continuous"
@@ -343,15 +343,15 @@ msgstr "Aliigi Animadon Iteracion Modon"
#: editor/animation_track_editor.cpp
msgid "Remove Anim Track"
-msgstr "Formovi Animadon Vojeton"
+msgstr "Forigi animacian trakon"
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
-msgstr "Fari NOVAN vojeton por %s kaj enmeti Ålosilon?"
+msgstr "Krei NOVAN trakon por %s kaj enmeti Ålosilon?"
#: editor/animation_track_editor.cpp
msgid "Create %d NEW tracks and insert keys?"
-msgstr "Fari %d NOVAJN vojetojn kaj enmeti Ålosilojn?"
+msgstr "Krei %d NOVAJN trakojn kaj enmeti Ålosilojn?"
#: editor/animation_track_editor.cpp editor/create_dialog.cpp
#: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp
@@ -379,7 +379,7 @@ msgstr "Animado Krei & Enmeti"
#: editor/animation_track_editor.cpp
msgid "Anim Insert Track & Key"
-msgstr "Animado Enmeti Vojeton & Åœlosilon"
+msgstr "Animacio enmeti trakon kaj Ålosilon"
#: editor/animation_track_editor.cpp
msgid "Anim Insert Key"
@@ -391,11 +391,12 @@ msgstr "Aliigi Animadon PaÅon"
#: editor/animation_track_editor.cpp
msgid "Rearrange Tracks"
-msgstr "RearanÄi Vojetojn"
+msgstr "RearanÄi trakojn"
#: editor/animation_track_editor.cpp
+#, fuzzy
msgid "Transform tracks only apply to Spatial-based nodes."
-msgstr "Transforma vojetoj nur almetas al Spatial nodojn."
+msgstr "Transformaj trakoj nur aplikas al Spatial-ajn nodojn."
#: editor/animation_track_editor.cpp
msgid ""
@@ -404,14 +405,14 @@ msgid ""
"-AudioStreamPlayer2D\n"
"-AudioStreamPlayer3D"
msgstr ""
-"AÅ­dio vojetoj nur volas indiki al nodojn de tipojn:\n"
+"AÅ­diaj trakoj nur eblas indiki al nodoj de tipoj:\n"
"-AudioStreamPlayer\n"
"-AudioStreamPlayer2D\n"
"-AudioStreamPlayer3D"
#: editor/animation_track_editor.cpp
msgid "Animation tracks can only point to AnimationPlayer nodes."
-msgstr "Animado vojetoj nur volas indiki al AnimationPlayer nodojn."
+msgstr "Animaciaj trakoj nur eblas indiki al AnimationPlayer-aj nodoj."
#: editor/animation_track_editor.cpp
msgid "An animation player can't animate itself, only other players."
@@ -419,39 +420,39 @@ msgstr "Animado legilo ne volas animi si mem, nur aliajn ludantojn."
#: editor/animation_track_editor.cpp
msgid "Not possible to add a new track without a root"
-msgstr "Äœi ne estas ebla adici novan vojeton sen radiko"
+msgstr "Ne eblas aldoni novan trakon sen radiko"
#: editor/animation_track_editor.cpp
msgid "Invalid track for Bezier (no suitable sub-properties)"
-msgstr "Nevalida trako por Bezier (neniu taŭga subproprietaĵoj)"
+msgstr "Nevalida trako por Bezier (neniaj taÅ­gaj atributoj)"
#: editor/animation_track_editor.cpp
msgid "Add Bezier Track"
-msgstr "Adici Bezier-vojeton"
+msgstr "Aldoni Bezier-an trakon"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a key."
-msgstr "Vojeto vojo estas malvalida, do ne volas adici Ålosilon."
+msgstr "Vojo de trako estas nevalida, do ne eblas aldoni Ålosilon."
#: editor/animation_track_editor.cpp
msgid "Track is not of type Spatial, can't insert key"
-msgstr "Vojeto ne estas de tipo Spatial, ne volas enmeti Ålosilon"
+msgstr "Trako ne estas de tipo Spatial, ne eblas enmeti Ålosilon"
#: editor/animation_track_editor.cpp
msgid "Add Transform Track Key"
-msgstr "Adici Transformon Vojeton Åœlosilon"
+msgstr "Aldoni transforman trakan Ålosilon"
#: editor/animation_track_editor.cpp
msgid "Add Track Key"
-msgstr "Adici Vojeton Åœlosilon"
+msgstr "Aldoni trakan Ålosilon"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a method key."
-msgstr "Vojeto vojo estas malvalida, do ne volas adici metodon Ålosilon."
+msgstr "Vojo de trako estas nevalida, do ne eblas aldoni metodan Ålosilon."
#: editor/animation_track_editor.cpp
msgid "Add Method Track Key"
-msgstr "Adici Metodon Vojeton Åœlosilon"
+msgstr "Aldoni metodan trakan Ålosilon"
#: editor/animation_track_editor.cpp
msgid "Method not found in object: "
@@ -467,7 +468,7 @@ msgstr "Tondujo estas malplena"
#: editor/animation_track_editor.cpp
msgid "Paste Tracks"
-msgstr "ElpoÅigi Vojetojn"
+msgstr "Alglui trakojn"
#: editor/animation_track_editor.cpp
msgid "Anim Scale Keys"
@@ -477,7 +478,8 @@ msgstr "Animado Skali Åœlosilojn"
msgid ""
"This option does not work for Bezier editing, as it's only a single track."
msgstr ""
-"Tio ĉi opcio ne funkcias por Bezier redakti, ĉar Äi estas nur unuopa vojeto."
+"Tiu ĉi opcio ne funkcias por Bezier-a redaktado, ĉar Äi estas nur unuopa "
+"trako."
#: editor/animation_track_editor.cpp
msgid ""
@@ -491,14 +493,14 @@ msgid ""
"Alternatively, use an import preset that imports animations to separate "
"files."
msgstr ""
-"Tio ĉi animado apartenas al enporta sceno, do aliigoj al enportajn vojetojn "
+"Tiu ĉi animacio apartenas enportitan scenon, do ÅanÄojn al enportitaj trakoj "
"ne konservos.\n"
"\n"
-"Por Åalti la eblecon aldoni proprajn vojetojn, navigu al la enporto-agordoj "
-"de la sceno kaj agordu \n"
-"\"Animado > Memorilo\" al \"Dosieroj\", Åaltu \"Animado -> Konservi Proprajn "
-"Vojetojn\", poste re-enportu.\n"
-"Alterne, uzu enporto-antaÅ­elekton ke enportas animadojn al malkunajn "
+"Por Åalti la eblecon de aldoni proprajn trakojn, navigu al la enportaj "
+"agordoj de la sceno kaj agordu\n"
+"\"Animacio > Memorilo\" al \"Dosieroj\", Åaltu \"Animacio -> Konservi "
+"proprajn trakojn\", poste reenportu.\n"
+"Alterne, uzu enporta antaÅ­agordo ke enportas animaciojn al malkunajn "
"dosierojn."
#: editor/animation_track_editor.cpp
@@ -507,15 +509,15 @@ msgstr "Averto: Redaktanti importis animadon"
#: editor/animation_track_editor.cpp
msgid "Select an AnimationPlayer node to create and edit animations."
-msgstr "Selektu AnimationPlayer nodo por krei kaj redakti animadoj."
+msgstr "Elektu AnimationPlayer-a nodo por krei kaj redakti animadojn."
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
-msgstr "Nur vidigi vojetojn el elektis nodojn en arbo."
+msgstr "Nur vidigi trakojn el elektitajn nodojn en la arbo."
#: editor/animation_track_editor.cpp
msgid "Group tracks by node or display them as plain list."
-msgstr "Grupigi vojetoj de nodo aÅ­ montri ilin kiel klara listo."
+msgstr "Grupigi trakojn per nodo aÅ­ vidigi ilin kiel simplan liston."
#: editor/animation_track_editor.cpp
msgid "Snap:"
@@ -542,7 +544,7 @@ msgstr "FPS"
#: editor/project_settings_editor.cpp editor/property_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Edit"
-msgstr "Editi"
+msgstr "Redakti"
#: editor/animation_track_editor.cpp
msgid "Animation properties."
@@ -550,7 +552,7 @@ msgstr "Animado atributoj."
#: editor/animation_track_editor.cpp
msgid "Copy Tracks"
-msgstr "Duplikati Vojetojn"
+msgstr "Kopii trakojn"
#: editor/animation_track_editor.cpp
msgid "Scale Selection"
@@ -622,7 +624,7 @@ msgstr "Forigi Nevalidajn Åœlosilojn"
#: editor/animation_track_editor.cpp
msgid "Remove unresolved and empty tracks"
-msgstr "Forigi maladrestrajn kaj malplenajn vojetojn"
+msgstr "Forigi nesolvitajn kaj malplenajn trakojn"
#: editor/animation_track_editor.cpp
msgid "Clean-up all animations"
@@ -642,7 +644,7 @@ msgstr "Skali RejÅo:"
#: editor/animation_track_editor.cpp
msgid "Select Tracks to Copy"
-msgstr "Elekti vojetojn por duplikati"
+msgstr "Elekti trakojn por kopii"
#: editor/animation_track_editor.cpp editor/editor_log.cpp
#: editor/editor_properties.cpp
@@ -651,7 +653,7 @@ msgstr "Elekti vojetojn por duplikati"
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
-msgstr "Duplikati"
+msgstr "Kopii"
#: editor/animation_track_editor.cpp
msgid "Select All/None"
@@ -659,15 +661,15 @@ msgstr "Elekti Ĉiuj/Neniuj"
#: editor/animation_track_editor_plugins.cpp
msgid "Add Audio Track Clip"
-msgstr "Adici Aŭdio-Vojeton Eltondaĵon"
+msgstr "Aldoni aŭdio-trakan eltondaĵon"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
-msgstr "Aliigi AÅ­dio-Vojeton Eltondaĵon Komencon DeiÄon"
+msgstr "ÅœanÄi komencan deÅovon de aÅ­dio-traka eltondaĵo"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr "Aliigi AÅ­dio-Vojeton Eltondaĵon Finon DeiÄon"
+msgstr "ÅœanÄi finan deÅovon de aÅ­dio-traka eltondaĵo"
#: editor/array_property_edit.cpp
msgid "Resize Array"
@@ -998,7 +1000,7 @@ msgstr "Rimedo"
#: editor/dependency_editor.cpp editor/editor_autoload_settings.cpp
#: editor/project_manager.cpp editor/project_settings_editor.cpp
msgid "Path"
-msgstr "dosierindiko"
+msgstr "Dosierindiko"
#: editor/dependency_editor.cpp
msgid "Dependencies:"
@@ -1117,6 +1119,10 @@ msgstr "ÅœanÄi la vortaran valoron"
msgid "Thanks from the Godot community!"
msgstr "Dankon de la komunumo de Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Kontribuantoj de Godot Engine"
@@ -1127,7 +1133,7 @@ msgstr "Fondintoj de la Projekto"
#: editor/editor_about.cpp
msgid "Lead Developer"
-msgstr "Ĉefprogramisto"
+msgstr "Ĉefa ellaboranto"
#. TRANSLATORS: This refers to a job title.
#. The trailing space is used to distinguish with the project list application,
@@ -1389,7 +1395,7 @@ msgstr "Eraris konservi dosieron: %s"
#: editor/editor_audio_buses.cpp
msgid "Add Bus"
-msgstr "Aldoni Buso"
+msgstr "Aldoni Buson"
#: editor/editor_audio_buses.cpp
msgid "Add a new Audio Bus to this layout."
@@ -1415,7 +1421,7 @@ msgstr "Konservi ĉi tiun busan aranÄon al dosiero."
#: editor/editor_audio_buses.cpp editor/import_dock.cpp
msgid "Load Default"
-msgstr "Åœargi defaÅ­lto"
+msgstr "Åœargi defaÅ­lton"
#: editor/editor_audio_buses.cpp
msgid "Load the default Bus Layout."
@@ -1831,7 +1837,7 @@ msgstr "Aktualigi"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Recognized"
-msgstr ""
+msgstr "Ĉiaj rekonaj dosiertipoj"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Files (*)"
@@ -1985,14 +1991,13 @@ msgstr "Priskribo"
#: editor/editor_help.cpp
msgid "Online Tutorials"
-msgstr "Retaj Instruiloj"
+msgstr "Retaj instruiloj"
#: editor/editor_help.cpp
msgid "Properties"
msgstr "Atributoj"
#: editor/editor_help.cpp
-#, fuzzy
msgid "override:"
msgstr "redifino:"
@@ -2006,7 +2011,7 @@ msgstr "Metodoj"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr "Etosaj Atributoj"
+msgstr "Etosaj atributoj"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -2018,7 +2023,7 @@ msgstr "Konstantoj"
#: editor/editor_help.cpp
msgid "Property Descriptions"
-msgstr "Priskribo de Atributoj"
+msgstr "Priskribo de atributoj"
#: editor/editor_help.cpp
msgid "(value)"
@@ -2034,7 +2039,7 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Method Descriptions"
-msgstr "Metodaj Priskriboj"
+msgstr "Metodaj priskriboj"
#: editor/editor_help.cpp
msgid ""
@@ -2126,7 +2131,6 @@ msgid "Set Multiple:"
msgstr "Agordi pluroblan:"
#: editor/editor_log.cpp
-#, fuzzy
msgid "Output:"
msgstr "Eligo:"
@@ -2208,13 +2212,12 @@ msgid "Error saving resource!"
msgstr "Eraras konservi risurcon!"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"This resource can't be saved because it does not belong to the edited scene. "
"Make it unique first."
msgstr ""
-"Ĉi tiu risurco ne konserveblas, ĉar Äi ne apartenas la redaktita sceno. "
-"Farigu Äin unikan unue."
+"Ĉi tiun risurcon ne konserveblas ĉar Äi ne apartenas al la redaktita sceno. "
+"Unikigu Äin unue."
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Save Resource As..."
@@ -2241,31 +2244,31 @@ msgstr "Ne malfermeblas '%s'. La dosiero estus movita aÅ­ forigita."
#: editor/editor_node.cpp
msgid "Error while parsing '%s'."
-msgstr ""
+msgstr "Eraras dum la analizo de '%s'."
#: editor/editor_node.cpp
msgid "Unexpected end of file '%s'."
-msgstr ""
+msgstr "Neatenda dosierfino '%s'."
#: editor/editor_node.cpp
msgid "Missing '%s' or its dependencies."
-msgstr ""
+msgstr "'%s' aÅ­ Äiaj dependoj forestas."
#: editor/editor_node.cpp
msgid "Error while loading '%s'."
-msgstr ""
+msgstr "Eraro dum Åarginto de '%s'."
#: editor/editor_node.cpp
msgid "Saving Scene"
-msgstr ""
+msgstr "Konservas scenon"
#: editor/editor_node.cpp
msgid "Analyzing"
-msgstr ""
+msgstr "Analizas"
#: editor/editor_node.cpp
msgid "Creating Thumbnail"
-msgstr ""
+msgstr "Kreas bildeton"
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
@@ -2276,38 +2279,44 @@ msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
msgstr ""
+"Tiun ĉi scenon ne konserveblas ĉar estas enmeto de cikla ekzemplado.\n"
+"Bonvolu solvi Äin kaj poste provu rekonservi."
#: editor/editor_node.cpp
msgid ""
"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't "
"be satisfied."
msgstr ""
+"Ne eble konservi scenon. VerÅajne dependoj (ekzemploj aÅ­ heredito) ne "
+"verigus."
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "Can't overwrite scene that is still open!"
-msgstr ""
+msgstr "Ne eble anstataÅ­igas scenon ke estas ankoraÅ­ malferma!"
#: editor/editor_node.cpp
msgid "Can't load MeshLibrary for merging!"
-msgstr ""
+msgstr "Ne eble Åargas MeshLibrary por la kunfando!"
#: editor/editor_node.cpp
msgid "Error saving MeshLibrary!"
-msgstr ""
+msgstr "Eraras konservi MeshLibrary!"
#: editor/editor_node.cpp
msgid "Can't load TileSet for merging!"
-msgstr ""
+msgstr "Ne eble Åargas TileSet por la kunfando!"
#: editor/editor_node.cpp
msgid "Error saving TileSet!"
-msgstr ""
+msgstr "Eraras konservi TileSet!"
#: editor/editor_node.cpp
msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Eraro okazis dum provas konservi la aranÄon de la redaktilon.\n"
+"Verigu la uzantan datumvojon de la redaktilo esti skribebla."
#: editor/editor_node.cpp
msgid ""
@@ -2315,14 +2324,17 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"DefaÅ­lta redaktila aranÄo transpasiÄis.\n"
+"Por restaÅ­ri la defaÅ­ltan aranÄon al Äiaj bazaj agordoj, uzu la opcion "
+"\"Forigi aranÄon\" kontraÅ­ la defaÅ­lta aranÄo."
#: editor/editor_node.cpp
msgid "Layout name not found!"
-msgstr ""
+msgstr "Nomon de aranÄo ne trovis!"
#: editor/editor_node.cpp
msgid "Restored the Default layout to its base settings."
-msgstr ""
+msgstr "RestaÅ­ris la defaÅ­ltan aranÄon al Äiaj bazaj agordoj."
#: editor/editor_node.cpp
msgid ""
@@ -2330,18 +2342,25 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
+"Tiu ĉi risurco apartenas enportitan scenon, do Äi estas ne redaktebla.\n"
+"Bonvolu legi la dokumentaron rilate enportecon de scenoj por pli bone "
+"komprenu ĉi tiun laborfluon."
#: editor/editor_node.cpp
msgid ""
"This resource belongs to a scene that was instanced or inherited.\n"
"Changes to it won't be kept when saving the current scene."
msgstr ""
+"Tiu ĉi risurco apartenas ekzemplitan aŭ hereditan scenon.\n"
+"ÅœanÄoj al Äi ne teniÄos kiam konservi la aktualan scenon."
#: editor/editor_node.cpp
msgid ""
"This resource was imported, so it's not editable. Change its settings in the "
"import panel and then re-import."
msgstr ""
+"Tiu ĉi risurco enportiÄis, do Äi ne estas redaktebla. ÅœanÄu Äiajn agordojn "
+"en la enporta panelo kaj poste reenportu."
#: editor/editor_node.cpp
msgid ""
@@ -2350,6 +2369,10 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
+"Tiu ĉi sceno enportiÄis, do ÅanÄoj al Äi ne teniÄos.\n"
+"Ekzempli Äin aÅ­ heredi permesigos ÅanÄojn al Äi.\n"
+"Bonvolu legi la dokumentaron rilate enportecon de scenoj por pli bone "
+"komprenu ĉi tiun laborfluon."
#: editor/editor_node.cpp
msgid ""
@@ -2357,26 +2380,29 @@ msgid ""
"Please read the documentation relevant to debugging to better understand "
"this workflow."
msgstr ""
+"Tio ĉi estas fora objekto, do ÅanÄoj al Äi ne teniÄos.\n"
+"Bonvolu legi la dokumentaron rilate sencimigon por pli bone komprenu ĉi tiun "
+"laborfluon."
#: editor/editor_node.cpp
msgid "There is no defined scene to run."
-msgstr ""
+msgstr "Estas ne definita sceno por ruli."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Konservu scenon antaÅ­ ruloto..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
-msgstr ""
+msgstr "Ne eble komencas subprocezon!"
#: editor/editor_node.cpp editor/filesystem_dock.cpp
msgid "Open Scene"
-msgstr ""
+msgstr "Malfermi scenon"
#: editor/editor_node.cpp
msgid "Open Base Scene"
-msgstr ""
+msgstr "Malfermi scenon de bazo"
#: editor/editor_node.cpp
msgid "Quick Open..."
@@ -2400,7 +2426,7 @@ msgstr "Konservi ÅanÄojn al '%s' antaÅ­ fermo?"
#: editor/editor_node.cpp
msgid "Saved %s modified resource(s)."
-msgstr ""
+msgstr "Konservis %s modifikita(j)n risurco(j)n."
#: editor/editor_node.cpp
msgid "A root node is required to save the scene."
@@ -2452,6 +2478,8 @@ msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"La aktuala sceno havas malkonservitajn ÅanÄojn.\n"
+"ReÅargi la konservitan scenon spite? Tiu ĉi ago ne estas malfarebla."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
@@ -2479,21 +2507,25 @@ msgstr "Konservi kaj foriri"
#: editor/editor_node.cpp
msgid "Save changes to the following scene(s) before quitting?"
-msgstr ""
+msgstr "Konservi ÅanÄojn al la jena(j) sceno(j) antaÅ­ foriri?"
#: editor/editor_node.cpp
msgid "Save changes the following scene(s) before opening Project Manager?"
msgstr ""
+"Konservi ÅanÄojn al la jena(j) sceno(j) antaÅ­ malfermi projektan mastrumilon?"
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
"This option is deprecated. Situations where refresh must be forced are now "
"considered a bug. Please report."
msgstr ""
+"Tiu ĉi opcio estas evitinda. Statoj en kiu aktualigo deviÄi estas nun "
+"konsideri kiel cimo. Bonvolu raporti."
#: editor/editor_node.cpp
msgid "Pick a Main Scene"
-msgstr ""
+msgstr "Elektu ĉefan scenon"
#: editor/editor_node.cpp
msgid "Close Scene"
@@ -2506,35 +2538,47 @@ msgstr "Remalfermi ferman scenon"
#: editor/editor_node.cpp
msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
+"Ne eblas enÅalti kromprogramon ĉe: '%s' analizo de agordaro ne sukcesis."
#: editor/editor_node.cpp
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr ""
+msgstr "Ne eblas trovi skriptan kampon por kromprogramo ĉe: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr ""
+msgstr "Ne eblas Åargi kromprograman skripton el dosierindiko: '%s'."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
+"Ne eblas Åargi kromprograman skripton el dosierindinko: '%s'. Povas esti pro "
+"koda eraro en tiu skripto.\n"
+"MalÅaltas la kromprogramon ĉe '%s' por malebligi pli erarojn."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
+"Ne eblas Åargi kromprograman skripton ĉe dosierindiko: '%s'. Baza tipo ne "
+"estas EditorPlugin."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
msgstr ""
+"Ne eblas Åargi kromprograman skripton ĉe dosierindiko: '%s'. Skripto ne "
+"estas en ila reÄimo."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
+"Sceno '%s' aÅ­tomate enportiÄis, do ne eblas redakti Äin.\n"
+"Por ÅanÄu Äin, nova heredita sceno povas kreiÄi."
#: editor/editor_node.cpp
msgid ""
@@ -2544,11 +2588,11 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Scene '%s' has broken dependencies:"
-msgstr ""
+msgstr "Sceno '%s' havas rompitajn dependojn:"
#: editor/editor_node.cpp
msgid "Clear Recent Scenes"
-msgstr ""
+msgstr "Vakigi lastajn scenojn"
#: editor/editor_node.cpp
msgid ""
@@ -2556,6 +2600,8 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"Ne ĉefa sceno definiÄis iam, elekti unu?\n"
+"Vi povas ÅanÄi Äin poste en \"Projektaj agordoj\" en la 'apliko' kategorio."
#: editor/editor_node.cpp
msgid ""
@@ -2563,6 +2609,8 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"Elektita sceno '%s' ekzisitas, elekti validan unuon?\n"
+"Vi povas ÅanÄi Äin poste en \"Projektaj agordoj\" en la 'apliko' kategorio."
#: editor/editor_node.cpp
msgid ""
@@ -2570,19 +2618,21 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"Elektita sceno '%s' ne estas scena dosiero, elekti validan unuon?\n"
+"Vi povas ÅanÄi Äin poste en \"Projektaj agordoj\" en la 'apliko' kategorio."
#: editor/editor_node.cpp
msgid "Save Layout"
-msgstr ""
+msgstr "Konservi aranÄon"
#: editor/editor_node.cpp
msgid "Delete Layout"
-msgstr ""
+msgstr "Forigi aranÄon"
#: editor/editor_node.cpp editor/import_dock.cpp
#: editor/script_create_dialog.cpp
msgid "Default"
-msgstr ""
+msgstr "DefaÅ­lto"
#: editor/editor_node.cpp editor/editor_properties.cpp
#: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp
@@ -2591,60 +2641,59 @@ msgstr "Montri en dosiersistemo"
#: editor/editor_node.cpp
msgid "Play This Scene"
-msgstr ""
+msgstr "Ludi ĉi tiun scenon"
#: editor/editor_node.cpp
msgid "Close Tab"
-msgstr ""
+msgstr "Fermi langeton"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Undo Close Tab"
-msgstr "Malfari fermi langeto"
+msgstr "Malfari ferminton de la langeto"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Close Other Tabs"
-msgstr ""
+msgstr "Fermi aliajn langetojn"
#: editor/editor_node.cpp
msgid "Close Tabs to the Right"
-msgstr ""
+msgstr "Fermi langetojn dekstre"
#: editor/editor_node.cpp
msgid "Close All Tabs"
-msgstr ""
+msgstr "Fermi ĉiu langetojn"
#: editor/editor_node.cpp
msgid "Switch Scene Tab"
-msgstr ""
+msgstr "InterÅanÄi langeton de sceno"
#: editor/editor_node.cpp
msgid "%d more files or folders"
-msgstr ""
+msgstr "%d plu dosiero(j) aÅ­ dosierujo(j)"
#: editor/editor_node.cpp
msgid "%d more folders"
-msgstr ""
+msgstr "%d plu dosierujo(j)"
#: editor/editor_node.cpp
msgid "%d more files"
-msgstr ""
+msgstr "%d plu dosiero(j)"
#: editor/editor_node.cpp
msgid "Dock Position"
-msgstr ""
+msgstr "Pozicio de doko"
#: editor/editor_node.cpp
msgid "Distraction Free Mode"
-msgstr ""
+msgstr "Sendistra reÄimo"
#: editor/editor_node.cpp
msgid "Toggle distraction-free mode."
-msgstr ""
+msgstr "Baskuli sendistran reÄimon."
#: editor/editor_node.cpp
msgid "Add a new scene."
-msgstr ""
+msgstr "Aldoni novan scenon."
#: editor/editor_node.cpp
msgid "Scene"
@@ -2652,28 +2701,27 @@ msgstr "Sceno"
#: editor/editor_node.cpp
msgid "Go to previously opened scene."
-msgstr ""
+msgstr "Iri al antaÅ­e malfermitan scenon."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Copy Text"
-msgstr "Duplikati"
+msgstr "Kopii la tekston"
#: editor/editor_node.cpp
msgid "Next tab"
-msgstr ""
+msgstr "Posta tabo"
#: editor/editor_node.cpp
msgid "Previous tab"
-msgstr ""
+msgstr "AntaÅ­a tabo"
#: editor/editor_node.cpp
msgid "Filter Files..."
-msgstr ""
+msgstr "Filtri dosierojn..."
#: editor/editor_node.cpp
msgid "Operations with scene files."
-msgstr ""
+msgstr "Operacioj kun scenaj dosieroj."
#: editor/editor_node.cpp
msgid "New Scene"
@@ -2700,7 +2748,6 @@ msgid "Save All Scenes"
msgstr "Konservi ĉiujn scenojn"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Convert To..."
msgstr "Konverti al..."
@@ -2710,7 +2757,7 @@ msgstr "MaÅo biblioteko..."
#: editor/editor_node.cpp
msgid "TileSet..."
-msgstr ""
+msgstr "TileSet..."
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
@@ -2734,7 +2781,7 @@ msgstr "Projekto"
#: editor/editor_node.cpp
msgid "Project Settings..."
-msgstr "Projekta agordoj..."
+msgstr "Projektaj agordoj..."
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
#, fuzzy
@@ -2842,9 +2889,8 @@ msgstr ""
"agordo estas Åaltita."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Scene Changes"
-msgstr "Sinkronigi scenan ÅanÄojn"
+msgstr "Sinkronigi ÅanÄojn en sceno"
#: editor/editor_node.cpp
#, fuzzy
@@ -2859,9 +2905,8 @@ msgstr ""
"Kiam uzantis malproksime en aparato, estas pli efika kun reta dosiersistemo."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Script Changes"
-msgstr "Sinkronigi skriptajn ÅanÄojn"
+msgstr "Sinkronigi ÅanÄojn en skripto"
#: editor/editor_node.cpp
#, fuzzy
@@ -2877,15 +2922,15 @@ msgstr ""
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
-msgstr ""
+msgstr "Redaktilo"
#: editor/editor_node.cpp
msgid "Editor Settings..."
-msgstr "Editila agordoj..."
+msgstr "Agordoj de la redaktilo..."
#: editor/editor_node.cpp
msgid "Editor Layout"
-msgstr "AranÄon de editilo"
+msgstr "AranÄo de la redaktilo"
#: editor/editor_node.cpp
msgid "Take Screenshot"
@@ -2894,6 +2939,8 @@ msgstr "Ekranfoti"
#: editor/editor_node.cpp
msgid "Screenshots are stored in the Editor Data/Settings Folder."
msgstr ""
+"Ekrankopioj estas konservintaj en la datumaj/agordaj dosierujo de la "
+"redaktilo."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
@@ -2901,23 +2948,23 @@ msgstr "Baskuli plenekranon"
#: editor/editor_node.cpp
msgid "Toggle System Console"
-msgstr ""
+msgstr "Baskuli la konzolon de sistemo"
#: editor/editor_node.cpp
msgid "Open Editor Data/Settings Folder"
-msgstr "Malfermi dosierujon de editilan datumoj/agordoj"
+msgstr "Malfermi datumajn/agordajn dosierujon de la redaktilo"
#: editor/editor_node.cpp
msgid "Open Editor Data Folder"
-msgstr "Malfermi dosierujon de editila datumoj"
+msgstr "Malfermi datumajn dosierujon de la redaktilo"
#: editor/editor_node.cpp
msgid "Open Editor Settings Folder"
-msgstr "Malfermi dosierujon de editila agordoj"
+msgstr "Malfermi agordajn dosierujon de la redaktilo"
#: editor/editor_node.cpp
msgid "Manage Editor Features..."
-msgstr "Mastrumi editilan eblecoj..."
+msgstr "Mastrumi eblecojn de la redaktilo..."
#: editor/editor_node.cpp
msgid "Manage Export Templates..."
@@ -2929,91 +2976,95 @@ msgstr "Helpo"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
-#, fuzzy
msgid "Online Docs"
-msgstr "Enreta dokoj"
+msgstr "Enreta dokumentaro"
#: editor/editor_node.cpp
msgid "Q&A"
-msgstr ""
+msgstr "Demandoj kaj respondoj"
#: editor/editor_node.cpp
msgid "Report a Bug"
-msgstr ""
+msgstr "Raporti cimon"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
-msgstr ""
+msgstr "Sendi rimarkojn pri la dokumentaro"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
-msgstr ""
+msgstr "Komunumo"
#: editor/editor_node.cpp
msgid "About"
-msgstr ""
+msgstr "Pri"
+
+#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Subteni Godot ellaboradon"
#: editor/editor_node.cpp
msgid "Play the project."
-msgstr ""
+msgstr "Ludi la projekton."
#: editor/editor_node.cpp
msgid "Play"
-msgstr ""
+msgstr "Ludi"
#: editor/editor_node.cpp
msgid "Pause the scene execution for debugging."
-msgstr ""
+msgstr "PaÅ­zi la plenumon de la sceno por sencimigo."
#: editor/editor_node.cpp
msgid "Pause Scene"
-msgstr ""
+msgstr "PaÅ­zi scenon"
#: editor/editor_node.cpp
msgid "Stop the scene."
-msgstr ""
+msgstr "Halti la scenon."
#: editor/editor_node.cpp
msgid "Play the edited scene."
-msgstr ""
+msgstr "Ludi la redaktantan scenon."
#: editor/editor_node.cpp
msgid "Play Scene"
-msgstr ""
+msgstr "Ludi scenon"
#: editor/editor_node.cpp
msgid "Play custom scene"
-msgstr ""
+msgstr "Ludi laÅ­mendan scenon"
#: editor/editor_node.cpp
msgid "Play Custom Scene"
-msgstr ""
+msgstr "Ludi laÅ­mendan scenon"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Changing the video driver requires restarting the editor."
-msgstr ""
+msgstr "ÅœanÄanto de la videa pelilo postulas rekomenci la redaktilon."
#: editor/editor_node.cpp editor/project_settings_editor.cpp
#: editor/settings_config_dialog.cpp
msgid "Save & Restart"
-msgstr ""
+msgstr "Konservi kaj rekomenci"
#: editor/editor_node.cpp
msgid "Spins when the editor window redraws."
-msgstr ""
+msgstr "Rotacius kiam la fenestron de la redaktilo redesegniÄi."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Update Continuously"
-msgstr "Seninterrompa"
+msgstr "Äœisdatigi kontinue"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Update When Changed"
-msgstr ""
+msgstr "Äœisdatigi kiam ÅanÄitis"
#: editor/editor_node.cpp
msgid "Hide Update Spinner"
-msgstr ""
+msgstr "KaÅi la Äisdatan indikilon"
#: editor/editor_node.cpp
msgid "FileSystem"
@@ -3021,19 +3072,19 @@ msgstr "Dosiersistemo"
#: editor/editor_node.cpp
msgid "Inspector"
-msgstr ""
+msgstr "Inspektoro"
#: editor/editor_node.cpp
msgid "Expand Bottom Panel"
-msgstr ""
+msgstr "Etendi suban panelon"
#: editor/editor_node.cpp
msgid "Output"
-msgstr ""
+msgstr "Eligo"
#: editor/editor_node.cpp
msgid "Don't Save"
-msgstr ""
+msgstr "Ne konservi"
#: editor/editor_node.cpp
msgid "Android build template is missing, please install relevant templates."
@@ -3064,7 +3115,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Import Templates From ZIP File"
-msgstr ""
+msgstr "Enporti Åablonojn el ZIP-a dosiero"
#: editor/editor_node.cpp
#, fuzzy
@@ -3073,11 +3124,11 @@ msgstr "Åœablonoj"
#: editor/editor_node.cpp
msgid "Export Library"
-msgstr ""
+msgstr "Eksporti bibliotekon"
#: editor/editor_node.cpp
msgid "Merge With Existing"
-msgstr ""
+msgstr "Kunfandi kun ekzistanta"
#: editor/editor_node.cpp
msgid "Open & Run a Script"
@@ -3088,69 +3139,70 @@ msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
msgstr ""
+"La jenaj dosieroj estas pli novaj sur disko.\n"
+"Kian agon fari?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Reload"
-msgstr ""
+msgstr "ReÅargi"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Resave"
-msgstr ""
+msgstr "Rekonservi"
#: editor/editor_node.cpp
msgid "New Inherited"
-msgstr ""
+msgstr "Nova heredita"
#: editor/editor_node.cpp
msgid "Load Errors"
-msgstr ""
+msgstr "Åœargaj eraroj"
#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Select"
-msgstr ""
+msgstr "Elekti"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
-msgstr ""
+msgstr "Malfermi 2D-an redaktilon"
#: editor/editor_node.cpp
msgid "Open 3D Editor"
-msgstr ""
+msgstr "Malfermi 3D-an redaktilon"
#: editor/editor_node.cpp
msgid "Open Script Editor"
-msgstr ""
+msgstr "Malfermi la redaktilon de skripto"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
-msgstr ""
+msgstr "Malfermi bibliotekon de havaĵo"
#: editor/editor_node.cpp
msgid "Open the next Editor"
-msgstr ""
+msgstr "Malfermi la postan redaktilon"
#: editor/editor_node.cpp
msgid "Open the previous Editor"
-msgstr ""
+msgstr "Malfermi la antaÅ­an redaktilon"
#: editor/editor_node.h
-#, fuzzy
msgid "Warning!"
-msgstr "Avertoj"
+msgstr "Avert!"
#: editor/editor_path.cpp
msgid "No sub-resources found."
-msgstr ""
+msgstr "Ne sub-risurcojn trovis."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
-msgstr ""
+msgstr "Kreas antaÅ­vidojn de maÅoj"
#: editor/editor_plugin.cpp
msgid "Thumbnail..."
-msgstr ""
+msgstr "Bildeto..."
#: editor/editor_plugin_settings.cpp
#, fuzzy
@@ -3159,112 +3211,116 @@ msgstr "Konektu al skripto:"
#: editor/editor_plugin_settings.cpp
msgid "Edit Plugin"
-msgstr ""
+msgstr "Redakti kromprogramon"
#: editor/editor_plugin_settings.cpp
msgid "Installed Plugins:"
-msgstr ""
+msgstr "Instalitaj kromprogramoj:"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
msgid "Update"
-msgstr ""
+msgstr "Äœisdatigi"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Version:"
-msgstr ""
+msgstr "Versio:"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
msgid "Author:"
-msgstr ""
+msgstr "AÅ­toro:"
#: editor/editor_plugin_settings.cpp
msgid "Status:"
-msgstr ""
+msgstr "Stato:"
#: editor/editor_plugin_settings.cpp
msgid "Edit:"
-msgstr ""
+msgstr "Redakti:"
#: editor/editor_profiler.cpp
msgid "Measure:"
-msgstr ""
+msgstr "Mezuro:"
#: editor/editor_profiler.cpp
msgid "Frame Time (sec)"
-msgstr ""
+msgstr "Tempo kadre (sekundoj)"
#: editor/editor_profiler.cpp
msgid "Average Time (sec)"
-msgstr ""
+msgstr "Meza tempo (sekundoj)"
#: editor/editor_profiler.cpp
msgid "Frame %"
-msgstr ""
+msgstr "Kadro %"
#: editor/editor_profiler.cpp
msgid "Physics Frame %"
-msgstr ""
+msgstr "Fiziko-kadro %"
#: editor/editor_profiler.cpp
msgid "Inclusive"
-msgstr ""
+msgstr "Inkluziva"
#: editor/editor_profiler.cpp
msgid "Self"
-msgstr ""
+msgstr "Memo"
#: editor/editor_profiler.cpp
msgid "Frame #:"
-msgstr ""
+msgstr "Kadro #:"
#: editor/editor_profiler.cpp
msgid "Time"
-msgstr ""
+msgstr "Tempo"
#: editor/editor_profiler.cpp
msgid "Calls"
-msgstr ""
+msgstr "Alvokoj"
#: editor/editor_properties.cpp
msgid "Edit Text:"
-msgstr ""
+msgstr "Redakti tekston:"
#: editor/editor_properties.cpp editor/script_create_dialog.cpp
msgid "On"
-msgstr ""
+msgstr "Åœaltita"
#: editor/editor_properties.cpp
msgid "Layer"
-msgstr ""
+msgstr "Tavolo"
#: editor/editor_properties.cpp
msgid "Bit %d, value %d"
-msgstr ""
+msgstr "Bito %d, valoro %d"
#: editor/editor_properties.cpp
msgid "[Empty]"
-msgstr ""
+msgstr "[Malplena]"
#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
msgid "Assign..."
-msgstr ""
+msgstr "Asigni..."
#: editor/editor_properties.cpp
msgid "Invalid RID"
-msgstr ""
+msgstr "Malvalida RID"
#: editor/editor_properties.cpp
msgid ""
"The selected resource (%s) does not match any type expected for this "
"property (%s)."
msgstr ""
+"La elektinta risurco (%s) ne kongruas ian atenditan tipon por ĉi tiu "
+"atributo (%s)."
#: editor/editor_properties.cpp
msgid ""
"Can't create a ViewportTexture on resources saved as a file.\n"
"Resource needs to belong to a scene."
msgstr ""
+"Ne eblas krei ViewportTexture por risurcoj konservite kiel dosiero.\n"
+"Risurco devas aparteni scenon."
#: editor/editor_properties.cpp
msgid ""
@@ -3273,26 +3329,30 @@ msgid ""
"Please switch on the 'local to scene' property on it (and all resources "
"containing it up to a node)."
msgstr ""
+"Ne eblas krei ViewportTexture por tiu risurco ĉar Äi ne agordas esti loke al "
+"sceno.\n"
+"Bonvolu Åalti la 'loke al sceno' atributon por Äi (kaj ĉiaj risurcoj kiu "
+"enhavas Äin, rekursie al nodo)."
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Pick a Viewport"
-msgstr ""
+msgstr "Elekti Viewport"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "New Script"
-msgstr ""
+msgstr "Nova skripto"
#: editor/editor_properties.cpp editor/scene_tree_dock.cpp
msgid "Extend Script"
-msgstr ""
+msgstr "Etendi skripton"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "New %s"
-msgstr ""
+msgstr "Nova %s"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Make Unique"
-msgstr ""
+msgstr "Farigi unikan"
#: editor/editor_properties.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
@@ -3306,40 +3366,40 @@ msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Paste"
-msgstr ""
+msgstr "Alglui"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Convert To %s"
-msgstr ""
+msgstr "Konverti al %s"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Selected node is not a Viewport!"
-msgstr ""
+msgstr "Elektinta nodo ne estas Viewport!"
#: editor/editor_properties_array_dict.cpp
msgid "Size: "
-msgstr ""
+msgstr "Grando: "
#: editor/editor_properties_array_dict.cpp
msgid "Page: "
-msgstr ""
+msgstr "PaÄo: "
#: editor/editor_properties_array_dict.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Item"
-msgstr ""
+msgstr "Forigi elementon"
#: editor/editor_properties_array_dict.cpp
msgid "New Key:"
-msgstr ""
+msgstr "Nova Ålosilo:"
#: editor/editor_properties_array_dict.cpp
msgid "New Value:"
-msgstr ""
+msgstr "Nova valoro:"
#: editor/editor_properties_array_dict.cpp
msgid "Add Key/Value Pair"
-msgstr ""
+msgstr "Aldoni Ålosilo/valoro paro"
#: editor/editor_run_native.cpp
msgid ""
@@ -3347,6 +3407,9 @@ msgid ""
"Please add a runnable preset in the Export menu or define an existing preset "
"as runnable."
msgstr ""
+"Ne rulebla eksporta antaÅ­agordo troviÄis por ĉi tiu platformo.\n"
+"Bonvolu aldoni ruleblan antaÅ­agordon per la Eksporto menuo aÅ­ defini "
+"ekzistantan antaÅ­agordon kiel rulebla."
#: editor/editor_run_script.cpp
msgid "Write your logic in the _run() method."
@@ -3354,15 +3417,15 @@ msgstr "Skribu vian logikon en la _run() metodo."
#: editor/editor_run_script.cpp
msgid "There is an edited scene already."
-msgstr ""
+msgstr "Estas redaktanta sceno jam."
#: editor/editor_run_script.cpp
msgid "Couldn't instance script:"
-msgstr ""
+msgstr "Ne eblis ekzempli skripton:"
#: editor/editor_run_script.cpp
msgid "Did you forget the 'tool' keyword?"
-msgstr ""
+msgstr "Ĉu vi forgesis la Ålosilvorton 'tool'?"
#: editor/editor_run_script.cpp
msgid "Couldn't run script:"
@@ -3375,6 +3438,8 @@ msgstr "Ĉu vi forgesis la '_run' metodo?"
#: editor/editor_spin_slider.cpp
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
msgstr ""
+"Premteni stirklavon por rondigi al entjeroj. Premteni majuskligan klavon por "
+"pli precizaj ÅanÄoj."
#: editor/editor_sub_scene.cpp
#, fuzzy
@@ -3387,7 +3452,7 @@ msgstr "Foliumi"
#: editor/editor_sub_scene.cpp
msgid "Scene Path:"
-msgstr ""
+msgstr "Scena dosierindiko:"
#: editor/editor_sub_scene.cpp
msgid "Import From Node:"
@@ -3399,11 +3464,11 @@ msgstr "ReelÅuti"
#: editor/export_template_manager.cpp
msgid "Uninstall"
-msgstr ""
+msgstr "Malinstali"
#: editor/export_template_manager.cpp
msgid "(Installed)"
-msgstr ""
+msgstr "(Instalita)"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3412,243 +3477,254 @@ msgstr "ElÅuti"
#: editor/export_template_manager.cpp
msgid "Official export templates aren't available for development builds."
-msgstr ""
+msgstr "Oficaj eksportaj Åablonoj estas ne haveblaj por programistaj muntoj."
#: editor/export_template_manager.cpp
msgid "(Missing)"
-msgstr ""
+msgstr "(Manka)"
#: editor/export_template_manager.cpp
msgid "(Current)"
-msgstr ""
+msgstr "(Aktuala)"
#: editor/export_template_manager.cpp
msgid "Retrieving mirrors, please wait..."
-msgstr ""
+msgstr "Ricevas spegulojn, bonvolu atendi..."
#: editor/export_template_manager.cpp
msgid "Remove template version '%s'?"
-msgstr ""
+msgstr "Forigi la version '%s' de Åablono?"
#: editor/export_template_manager.cpp
msgid "Can't open export templates zip."
-msgstr ""
+msgstr "Ne eblas malfermi ZIP de eksportaj Åablonoj."
#: editor/export_template_manager.cpp
msgid "Invalid version.txt format inside templates: %s."
-msgstr ""
+msgstr "Nevalida formo de version.txt en Åablonoj: %s."
#: editor/export_template_manager.cpp
msgid "No version.txt found inside templates."
-msgstr ""
+msgstr "Ne version.txt troviÄis en Åablonoj."
#: editor/export_template_manager.cpp
msgid "Error creating path for templates:"
-msgstr ""
+msgstr "Eraro dum kreo de dosierindiko por Åablonoj:"
#: editor/export_template_manager.cpp
msgid "Extracting Export Templates"
-msgstr ""
+msgstr "Ekstraktas eksportajn Åablonojn"
#: editor/export_template_manager.cpp
msgid "Importing:"
-msgstr ""
+msgstr "Enportas:"
#: editor/export_template_manager.cpp
msgid "Error getting the list of mirrors."
-msgstr ""
+msgstr "Eraro dum ricevo de la listo de speguloj."
#: editor/export_template_manager.cpp
msgid "Error parsing JSON of mirror list. Please report this issue!"
msgstr ""
+"Eraro dum analizo de la JSON de la spegula listo. Bonvolu raporti tiun "
+"problemon!"
#: editor/export_template_manager.cpp
msgid ""
"No download links found for this version. Direct download is only available "
"for official releases."
msgstr ""
+"Ne elÅutaj ligiloj troviÄis por ĉi tiu versio. Direkta elÅuto estas nur "
+"disponebla por oficaj eldonoj."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Can't resolve."
-msgstr ""
+msgstr "Ne eblas adrestrovi."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Can't connect."
-msgstr ""
+msgstr "Ne eblas konekti."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "No response."
-msgstr ""
+msgstr "Ne respondo."
#: editor/export_template_manager.cpp
msgid "Request Failed."
-msgstr ""
+msgstr "Demando eraris."
#: editor/export_template_manager.cpp
msgid "Redirect Loop."
-msgstr ""
+msgstr "Alidirekta iteracio."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Failed:"
-msgstr ""
+msgstr "Eraris:"
#: editor/export_template_manager.cpp
msgid "Download Complete."
-msgstr ""
+msgstr "ElÅuto kompleta."
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
-msgstr ""
+msgstr "Ne eblas forigi provizoran dosieron:"
#: editor/export_template_manager.cpp
msgid ""
"Templates installation failed.\n"
"The problematic templates archives can be found at '%s'."
msgstr ""
+"Instalado de Åablonoj eraris.\n"
+"La arkivoj de problemaj Åablonoj eble troviÄas ĉe '%s'."
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
-msgstr ""
+msgstr "Eraro dum demandi la URL:"
#: editor/export_template_manager.cpp
msgid "Connecting to Mirror..."
-msgstr ""
+msgstr "Konektas al spegulo..."
#: editor/export_template_manager.cpp
msgid "Disconnected"
-msgstr ""
+msgstr "Malkonektis"
#: editor/export_template_manager.cpp
msgid "Resolving"
-msgstr ""
+msgstr "Adrestrovas"
#: editor/export_template_manager.cpp
msgid "Can't Resolve"
-msgstr ""
+msgstr "Ne eblas adrestrovi"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Connecting..."
-msgstr ""
+msgstr "Konektas..."
#: editor/export_template_manager.cpp
msgid "Can't Connect"
-msgstr ""
+msgstr "Ne eblas konekti"
#: editor/export_template_manager.cpp
msgid "Connected"
-msgstr ""
+msgstr "Konektis"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Requesting..."
-msgstr ""
+msgstr "Demandas..."
#: editor/export_template_manager.cpp
msgid "Downloading"
-msgstr ""
+msgstr "ElÅutas"
#: editor/export_template_manager.cpp
msgid "Connection Error"
-msgstr ""
+msgstr "Konekta eraro"
#: editor/export_template_manager.cpp
msgid "SSL Handshake Error"
-msgstr ""
+msgstr "SSL-kvitanca eraro"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
-msgstr ""
+msgstr "Malkompaktigas kompilajn fontkodojn por Android"
#: editor/export_template_manager.cpp
msgid "Current Version:"
-msgstr ""
+msgstr "Aktuala versio:"
#: editor/export_template_manager.cpp
msgid "Installed Versions:"
-msgstr ""
+msgstr "Instalintaj versioj:"
#: editor/export_template_manager.cpp
msgid "Install From File"
-msgstr ""
+msgstr "Instali el dosiero"
#: editor/export_template_manager.cpp
msgid "Remove Template"
-msgstr ""
+msgstr "Forigi Åablonon"
#: editor/export_template_manager.cpp
msgid "Select Template File"
-msgstr ""
+msgstr "Elekti Åablonan dosieron"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Godot Export Templates"
-msgstr "Mastrumi eksportaj Åablonoj"
+msgstr "Eksportajn Åablonojn de Godot"
#: editor/export_template_manager.cpp
msgid "Export Template Manager"
-msgstr ""
+msgstr "Mastrumilo de eksportaj Åablonoj"
#: editor/export_template_manager.cpp
msgid "Download Templates"
-msgstr ""
+msgstr "ElÅutilo de Åablonoj"
#: editor/export_template_manager.cpp
msgid "Select mirror from list: (Shift+Click: Open in Browser)"
msgstr ""
+"Elekti spegulon el listo: (Majuskliga klavo+Alklako: Malfermi en retumilon)"
#: editor/filesystem_dock.cpp
msgid "Favorites"
-msgstr ""
+msgstr "Favoritaj"
#: editor/filesystem_dock.cpp
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
+"Stato: Enporto de dosiero eraris. Bonvolu ripari dosieron kaj reenporti "
+"permane."
#: editor/filesystem_dock.cpp
msgid ""
"Importing has been disabled for this file, so it can't be opened for editing."
msgstr ""
+"Enportadon malÅaltis por ĉi tiu dosiero, do Äin ne eblas malfermi por "
+"redakto."
#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
-msgstr ""
+msgstr "Ne eblas movi/renomi risurcan radikon."
#: editor/filesystem_dock.cpp
+#, fuzzy
msgid "Cannot move a folder into itself."
-msgstr ""
+msgstr "Ne eblas movi dosierujon en sin mem."
#: editor/filesystem_dock.cpp
msgid "Error moving:"
-msgstr ""
+msgstr "Eraro dum movado de:"
#: editor/filesystem_dock.cpp
msgid "Error duplicating:"
-msgstr ""
+msgstr "Eraro dum duplikati:"
#: editor/filesystem_dock.cpp
msgid "Unable to update dependencies:"
-msgstr ""
+msgstr "Ne eblas Äisdatigi dependojn:"
#: editor/filesystem_dock.cpp editor/scene_tree_editor.cpp
msgid "No name provided."
-msgstr ""
+msgstr "Ne nomon provizis."
#: editor/filesystem_dock.cpp
msgid "Provided name contains invalid characters."
-msgstr ""
+msgstr "Provizita nomo enhavas malvalidajn signojn."
#: editor/filesystem_dock.cpp
msgid "A file or folder with this name already exists."
-msgstr ""
+msgstr "Dosiero aŭ dosierujo kun ĉi tiu nomo jam ekzistas."
#: editor/filesystem_dock.cpp
msgid "Name contains invalid characters."
-msgstr ""
+msgstr "Nomo enhavas malvalidajn signojn."
#: editor/filesystem_dock.cpp
msgid ""
@@ -3659,59 +3735,64 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
+"La jenaj dosieroj aÅ­ dosierujoj konfliktas kun elementoj en la cela loko "
+"'%s':\n"
+"\n"
+"%s\n"
+"\n"
+"Ĉu vi volas anstataŭigi ilin?"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
-msgstr ""
+msgstr "Renomas dosieron:"
#: editor/filesystem_dock.cpp
msgid "Renaming folder:"
-msgstr ""
+msgstr "Renomas dosierujon:"
#: editor/filesystem_dock.cpp
msgid "Duplicating file:"
-msgstr ""
+msgstr "Duplikatas dosieron:"
#: editor/filesystem_dock.cpp
msgid "Duplicating folder:"
-msgstr ""
+msgstr "Duplikatas dosierujon:"
#: editor/filesystem_dock.cpp
msgid "New Inherited Scene"
msgstr "Nova heredita sceno"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Set As Main Scene"
-msgstr "Konservi ĉiujn scenojn"
+msgstr "Defini kiel ĉefan scenon"
#: editor/filesystem_dock.cpp
msgid "Open Scenes"
-msgstr ""
+msgstr "Malfermi scenojn"
#: editor/filesystem_dock.cpp
msgid "Instance"
-msgstr ""
+msgstr "Ekzemplodoni"
#: editor/filesystem_dock.cpp
msgid "Add to Favorites"
-msgstr ""
+msgstr "Aldoni al favoritaj"
#: editor/filesystem_dock.cpp
msgid "Remove from Favorites"
-msgstr ""
+msgstr "Forigi el favoritaj"
#: editor/filesystem_dock.cpp
msgid "Edit Dependencies..."
-msgstr ""
+msgstr "Redakti dependojn..."
#: editor/filesystem_dock.cpp
msgid "View Owners..."
-msgstr ""
+msgstr "Vidi posedojn..."
#: editor/filesystem_dock.cpp
msgid "Move To..."
-msgstr ""
+msgstr "Movi al..."
#: editor/filesystem_dock.cpp
msgid "New Scene..."
@@ -3719,63 +3800,65 @@ msgstr "Nova sceno..."
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "New Script..."
-msgstr ""
+msgstr "Nova skripto..."
#: editor/filesystem_dock.cpp
msgid "New Resource..."
-msgstr ""
+msgstr "Nova risurco..."
#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
#: editor/script_editor_debugger.cpp
msgid "Expand All"
-msgstr ""
+msgstr "Etendi tuton"
#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
#: editor/script_editor_debugger.cpp
msgid "Collapse All"
-msgstr ""
+msgstr "Maletendi tuton"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
-msgstr ""
+msgstr "Duobligi..."
#: editor/filesystem_dock.cpp
msgid "Move to Trash"
-msgstr ""
+msgstr "Movi al rubujo"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
-msgstr ""
+msgstr "Renomi..."
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
-msgstr ""
+msgstr "AntaÅ­a dosierujo/dosiero"
#: editor/filesystem_dock.cpp
msgid "Next Folder/File"
-msgstr ""
+msgstr "Posta dosierujo/dosiero"
#: editor/filesystem_dock.cpp
msgid "Re-Scan Filesystem"
-msgstr "Reesplori dosiersistemo"
+msgstr "Reesplori dosiersistemon"
#: editor/filesystem_dock.cpp
msgid "Toggle Split Mode"
-msgstr ""
+msgstr "Baskuli dividan reÄimon"
#: editor/filesystem_dock.cpp
msgid "Search files"
-msgstr "Serĉi dosieroj"
+msgstr "Serĉi dosierojn"
#: editor/filesystem_dock.cpp
msgid ""
"Scanning Files,\n"
"Please Wait..."
msgstr ""
+"Skanas dosierojn,\n"
+"Bonvolu atendi..."
#: editor/filesystem_dock.cpp
msgid "Move"
-msgstr ""
+msgstr "Movi"
#: editor/filesystem_dock.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -3850,19 +3933,16 @@ msgid "Searching..."
msgstr "Serĉas..."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d match in %d file."
-msgstr "Trovis %d matĉo(j)n."
+msgstr "%d rekono en %d dosiero."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d file."
-msgstr "Trovis %d matĉo(j)n."
+msgstr "%d rekonoj en %d dosiero."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d files."
-msgstr "Trovis %d matĉo(j)n."
+msgstr "%d rekonoj en %d dosieroj."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -3893,7 +3973,6 @@ msgid "Groups"
msgstr "Grupoj"
#: editor/groups_editor.cpp
-#, fuzzy
msgid "Nodes Not in Group"
msgstr "Nodoj ne en grupo"
@@ -3915,9 +3994,8 @@ msgid "Group Editor"
msgstr "Grupredaktilo"
#: editor/groups_editor.cpp
-#, fuzzy
msgid "Manage Groups"
-msgstr "Administri grupojn"
+msgstr "Agordi grupojn"
#: editor/import/resource_importer_scene.cpp
msgid "Import as Single Scene"
@@ -3970,54 +4048,51 @@ msgstr "Enportas scenon..."
#: editor/import/resource_importer_scene.cpp
msgid "Generating Lightmaps"
-msgstr ""
+msgstr "Naskas lummapojn"
#: editor/import/resource_importer_scene.cpp
msgid "Generating for Mesh: "
-msgstr ""
+msgstr "Naskas por maÅo: "
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Running Custom Script..."
-msgstr "Rulas propra skripto..."
+msgstr "Rulas propran skripton..."
#: editor/import/resource_importer_scene.cpp
msgid "Couldn't load post-import script:"
-msgstr ""
+msgstr "Ne elbe Åargis la post-enportan skripton:"
#: editor/import/resource_importer_scene.cpp
msgid "Invalid/broken script for post-import (check console):"
-msgstr ""
+msgstr "Nevalida/rompita skripto por post-enporto (ekzamenu konzolon):"
#: editor/import/resource_importer_scene.cpp
msgid "Error running post-import script:"
-msgstr ""
+msgstr "Eraro dum ruli post-enportan skripton:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
-msgstr ""
+msgstr "Ĉu vi revenis Nodo-devenitan objekton en la metodo `post_import()`?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
-msgstr ""
+msgstr "Konservas..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Selektu nodo(j)n por enporti"
+msgstr "Elektu enportilon"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Enporti"
+msgstr "Enportilo:"
#: editor/import_defaults_editor.cpp
msgid "Reset to Defaults"
-msgstr ""
+msgstr "Rekomencigi al defaÅ­ltoj"
#: editor/import_dock.cpp
msgid "Keep File (No Import)"
-msgstr ""
+msgstr "Konservi dosieron (ne enporto)"
#: editor/import_dock.cpp
#, fuzzy
@@ -4026,73 +4101,76 @@ msgstr "Trovi en dosierojn"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
-msgstr ""
+msgstr "Agordi kiel defaÅ­lton por '%s'"
#: editor/import_dock.cpp
msgid "Clear Default for '%s'"
-msgstr ""
+msgstr "Vakigi defaÅ­lton por '%s'"
#: editor/import_dock.cpp
msgid "Import As:"
-msgstr ""
+msgstr "Enporti kiel:"
#: editor/import_dock.cpp
msgid "Preset"
-msgstr ""
+msgstr "AntaÅ­agordo"
#: editor/import_dock.cpp
msgid "Reimport"
-msgstr ""
+msgstr "Reenporti"
#: editor/import_dock.cpp
msgid "Save Scenes, Re-Import, and Restart"
-msgstr ""
+msgstr "Konservi scenojn, reenporti, kaj rekomenci"
#: editor/import_dock.cpp
msgid "Changing the type of an imported file requires editor restart."
msgstr ""
+"ÅœanÄado de la tipo de enportita dosiero postulas redaktilan rekomencon."
#: editor/import_dock.cpp
+#, fuzzy
msgid ""
"WARNING: Assets exist that use this resource, they may stop loading properly."
msgstr ""
+"AVERTO: Havaĵoj ekzistas ke uzis ĉi tiu risurcon, ili povas ĉesi Åargi dece."
#: editor/inspector_dock.cpp
msgid "Failed to load resource."
-msgstr ""
+msgstr "Ne eblas Åargi risurcon."
#: editor/inspector_dock.cpp
msgid "Expand All Properties"
-msgstr ""
+msgstr "Etendi ĉiajn atributojn"
#: editor/inspector_dock.cpp
msgid "Collapse All Properties"
-msgstr ""
+msgstr "Maletendi ĉiajn atributojn"
#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp
msgid "Save As..."
-msgstr ""
+msgstr "Konservi kiel..."
#: editor/inspector_dock.cpp
msgid "Copy Params"
-msgstr ""
+msgstr "Kopii parametrojn"
#: editor/inspector_dock.cpp
msgid "Edit Resource Clipboard"
-msgstr ""
+msgstr "Redakti risurcan tondujon"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
-msgstr ""
+msgstr "Kopii risurcon"
#: editor/inspector_dock.cpp
msgid "Make Built-In"
-msgstr ""
+msgstr "Enkonstruigi"
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
-msgstr ""
+msgstr "Subrisurcojn unikigi"
#: editor/inspector_dock.cpp
msgid "Open in Help"
@@ -4100,39 +4178,39 @@ msgstr "Malfermi en helpo"
#: editor/inspector_dock.cpp
msgid "Create a new resource in memory and edit it."
-msgstr ""
+msgstr "Krei novan risurcon en memoro kaj redakti Äin."
#: editor/inspector_dock.cpp
msgid "Load an existing resource from disk and edit it."
-msgstr ""
+msgstr "Åœargi ekzistantan risurcon el disko kaj redakti Äin."
#: editor/inspector_dock.cpp
msgid "Save the currently edited resource."
-msgstr ""
+msgstr "Konservi la aktuale redaktantan risurcon."
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
-msgstr ""
+msgstr "Iri al la antaÅ­e redaktinta objekto en historio."
#: editor/inspector_dock.cpp
msgid "Go to the next edited object in history."
-msgstr ""
+msgstr "Iri al la poste redaktinta objekto en historio."
#: editor/inspector_dock.cpp
msgid "History of recently edited objects."
-msgstr ""
+msgstr "Historio de lastatempe redaktintaj objektoj."
#: editor/inspector_dock.cpp
msgid "Object properties."
-msgstr ""
+msgstr "Atributoj de la objekto."
#: editor/inspector_dock.cpp
msgid "Filter properties"
-msgstr ""
+msgstr "Filtri atributojn"
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
-msgstr ""
+msgstr "ÅœanÄoj eble perdiÄos!"
#: editor/multi_node_edit.cpp
msgid "MultiNode Set"
@@ -4140,46 +4218,46 @@ msgstr ""
#: editor/node_dock.cpp
msgid "Select a single node to edit its signals and groups."
-msgstr ""
+msgstr "Elektu unu nodon por redakti Äiajn signalojn kaj grupojn."
#: editor/plugin_config_dialog.cpp
msgid "Edit a Plugin"
-msgstr ""
+msgstr "Redakti kromprogramon"
#: editor/plugin_config_dialog.cpp
msgid "Create a Plugin"
-msgstr ""
+msgstr "Krei kromprogramon"
#: editor/plugin_config_dialog.cpp
msgid "Plugin Name:"
-msgstr ""
+msgstr "Nomo de kromprogramon:"
#: editor/plugin_config_dialog.cpp
msgid "Subfolder:"
-msgstr ""
+msgstr "Subdosierujo:"
#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
msgid "Language:"
-msgstr ""
+msgstr "Lingvo:"
#: editor/plugin_config_dialog.cpp
msgid "Script Name:"
-msgstr ""
+msgstr "Nomo de skripto:"
#: editor/plugin_config_dialog.cpp
msgid "Activate now?"
-msgstr ""
+msgstr "Aktivigi nun?"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Polygon"
-msgstr ""
+msgstr "Krei plurlateron"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Create points."
-msgstr ""
+msgstr "Krei punktojn."
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid ""
@@ -4187,27 +4265,30 @@ msgid ""
"LMB: Move Point\n"
"RMB: Erase Point"
msgstr ""
+"Redakti punktojn.\n"
+"Maldekstra musbutono: Movi punkton\n"
+"Dekstra musbutono: Forigi punkton"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Erase points."
-msgstr ""
+msgstr "Forigi punktojn."
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Edit Polygon"
-msgstr ""
+msgstr "Redakti plurlateron"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Insert Point"
-msgstr ""
+msgstr "Enmeti punkton"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Edit Polygon (Remove Point)"
-msgstr ""
+msgstr "Redakti plurlateron (forigi punkton)"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Remove Polygon And Point"
-msgstr ""
+msgstr "Forigi plurlateron kaj punkton"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4215,51 +4296,52 @@ msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Animation"
-msgstr ""
+msgstr "Aldoni animacion"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Load..."
-msgstr ""
+msgstr "Åœargi..."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Move Node Point"
-msgstr ""
+msgstr "Movi punkton de nodo"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Change BlendSpace1D Limits"
-msgstr ""
+msgstr "ÅœanÄi limojn de BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Change BlendSpace1D Labels"
-msgstr ""
+msgstr "ÅœanÄi etikedojn de BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "This type of node can't be used. Only root nodes are allowed."
msgstr ""
+"Tiun ĉi tipon de nodo ne eblas uzi. Nur radikaj nodoj estas permesitaj."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Add Node Point"
-msgstr ""
+msgstr "Aldoni punkton de nodo"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Add Animation Point"
-msgstr ""
+msgstr "Aldoni punkton de animacio"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Remove BlendSpace1D Point"
-msgstr ""
+msgstr "Forigi punkton de BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Move BlendSpace1D Node Point"
-msgstr ""
+msgstr "Movi punkton de BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4269,157 +4351,161 @@ msgid ""
"AnimationTree is inactive.\n"
"Activate to enable playback, check node warnings if activation fails."
msgstr ""
+"AnimationTree estas neaktiva.\n"
+"Aktivigu por Åalti reproduktado, ekzamenu avertojn de nodo se aktivigo "
+"erarus."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Set the blending position within the space"
-msgstr ""
+msgstr "Difini la miksan pozicion en la spaco"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Select and move points, create points with RMB."
-msgstr ""
+msgstr "Elekti kaj movi punktojn, krei punktojn per dekstra musbutono."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
msgid "Enable snap and show grid."
-msgstr ""
+msgstr "Åœalti kradokapton kaj vidi kradon."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Point"
-msgstr ""
+msgstr "Punkto"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Open Editor"
-msgstr ""
+msgstr "Malfermi la redaktilon"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Open Animation Node"
-msgstr ""
+msgstr "Malfermi animacian nodon"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Triangle already exists."
-msgstr ""
+msgstr "Triangulo jam ekzistas."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Add Triangle"
-msgstr ""
+msgstr "Aldoni triangulon"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Change BlendSpace2D Limits"
-msgstr ""
+msgstr "ÅœanÄi limojn de BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Change BlendSpace2D Labels"
-msgstr ""
+msgstr "ÅœanÄi etikedojn de BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Remove BlendSpace2D Point"
-msgstr ""
+msgstr "Forigi punktojn de BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Remove BlendSpace2D Triangle"
-msgstr ""
+msgstr "Forigi triangulojn de BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "BlendSpace2D does not belong to an AnimationTree node."
-msgstr ""
+msgstr "BlendSpace2D ne apartenas AnimationTree-an nodon."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "No triangles exist, so no blending can take place."
-msgstr ""
+msgstr "Ne trianguloj ekzistas, do miksado ne eblas."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Toggle Auto Triangles"
-msgstr ""
+msgstr "Baskuli aÅ­tomatajn triangulojn"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Create triangles by connecting points."
-msgstr ""
+msgstr "Krei triangulojn per konekti punktojn."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Erase points and triangles."
-msgstr ""
+msgstr "Forigi punktojn kaj triangulojn."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Generate blend triangles automatically (instead of manually)"
-msgstr ""
+msgstr "Generi miksajn triangulojn aÅ­tomate (anstataÅ­ permane)"
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend:"
-msgstr ""
+msgstr "Mikso:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Parameter Changed"
-msgstr ""
+msgstr "Parametro ÅanÄiÄis"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Edit Filters"
-msgstr ""
+msgstr "Redakti filtrojn"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Output node can't be added to the blend tree."
-msgstr ""
+msgstr "Ne eblas aldoni eligan nodon al la miksan arbon."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Add Node to BlendTree"
-msgstr ""
+msgstr "Aldoni nodon al BlendTree"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Node Moved"
-msgstr ""
+msgstr "Nodo moviÄis"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Unable to connect, port may be in use or connection may be invalid."
msgstr ""
+"Ne eblas konekti, pordo povas esti en uzo aÅ­ konekto povas esti nevalida."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Nodes Connected"
-msgstr ""
+msgstr "Nodoj konektiÄis"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Nodes Disconnected"
-msgstr ""
+msgstr "Nodoj malkonektiÄis"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Set Animation"
-msgstr ""
+msgstr "Difini animacion"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Delete Node"
-msgstr ""
+msgstr "Forigi nodon"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/scene_tree_dock.cpp
msgid "Delete Node(s)"
-msgstr ""
+msgstr "Forigi nodo(j)n"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Toggle Filter On/Off"
-msgstr ""
+msgstr "Åœalti/malÅalti filtron"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Change Filter"
-msgstr ""
+msgstr "ÅœanÄi filtron"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "No animation player set, so unable to retrieve track names."
-msgstr ""
+msgstr "Ne animacian ludilon difinas, do ne eblas ricevi nomojn de trakoj."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Player path set is invalid, so unable to retrieve track names."
-msgstr ""
+msgstr "Vojaro de ludilo estas nevalida, do ne eblas ricevi nomojn de trakoj."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/root_motion_editor_plugin.cpp
@@ -4427,6 +4513,8 @@ msgid ""
"Animation player has no valid root node path, so unable to retrieve track "
"names."
msgstr ""
+"Animacia ludilo ne havas valida radika nodo-vojo, do ne eblas ricevi nomojn "
+"de trakoj."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#, fuzzy
@@ -4446,55 +4534,56 @@ msgstr "Funkcioj:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Node Renamed"
-msgstr ""
+msgstr "Nodo renomiÄis"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add Node..."
-msgstr ""
+msgstr "Aldoni nodon..."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "Edit Filtered Tracks:"
-msgstr ""
+msgstr "Redakti filtritajn trakojn:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Enable Filtering"
-msgstr ""
+msgstr "Åœalti filtradon"
#: editor/plugins/animation_player_editor_plugin.cpp
+#, fuzzy
msgid "Toggle Autoplay"
-msgstr ""
+msgstr "Baskuli aÅ­toludadon"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "New Animation Name:"
-msgstr ""
+msgstr "Nomo de nova animacio:"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "New Anim"
-msgstr ""
+msgstr "Nova animacio"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Change Animation Name:"
-msgstr ""
+msgstr "ÅœanÄi nomon de animacio:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Delete Animation?"
-msgstr ""
+msgstr "Forigi animacion?"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Remove Animation"
-msgstr ""
+msgstr "Forigi animacion"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Invalid animation name!"
-msgstr ""
+msgstr "Nevalida nomo de animacio!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation name already exists!"
-msgstr ""
+msgstr "Nomo de animacio jam ekzistas!"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
@@ -4504,227 +4593,227 @@ msgstr "Renomi animaĵon"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Blend Next Changed"
-msgstr ""
+msgstr "Mikso sekvo ÅanÄiÄis"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Change Blend Time"
-msgstr ""
+msgstr "ÅœanÄi tempon de mikso"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Load Animation"
-msgstr ""
+msgstr "Åœargi animacion"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Duplicate Animation"
-msgstr ""
+msgstr "Duplikati animacion"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "No animation to copy!"
-msgstr ""
+msgstr "Ne animacio por kopii!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "No animation resource on clipboard!"
-msgstr ""
+msgstr "Ne animacia risurco en tondujo!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Pasted Animation"
-msgstr ""
+msgstr "Algluis animacion"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Paste Animation"
-msgstr ""
+msgstr "Alglui animacion"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "No animation to edit!"
-msgstr ""
+msgstr "Ne animacio por redakti!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation backwards from current pos. (A)"
-msgstr ""
+msgstr "Ludi elektitan animacion retre el aktuala pozicio. (A)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation backwards from end. (Shift+A)"
-msgstr ""
+msgstr "Ludi elektitan animacion retre el fino. (Majuskliga klavo+A)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Stop animation playback. (S)"
-msgstr ""
+msgstr "Halti reproduktadon de animacio. (S)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation from start. (Shift+D)"
-msgstr ""
+msgstr "Ludi elektitan animacion el komenco. (Majuskliga klavo+D)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation from current pos. (D)"
-msgstr ""
+msgstr "Ludi elektitan animacion el aktuala pozicio. (D)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation position (in seconds)."
-msgstr ""
+msgstr "Pozicio de animacio (en sekundoj)."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Scale animation playback globally for the node."
-msgstr ""
+msgstr "Skali reproduktadon de animacio malloke por la nodo."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation Tools"
-msgstr ""
+msgstr "Iloj de animacio"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation"
-msgstr ""
+msgstr "Animacio"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Edit Transitions..."
-msgstr ""
+msgstr "Redakti transpasojn..."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Open in Inspector"
-msgstr ""
+msgstr "Malfermi en la Inspektoro"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Display list of animations in player."
-msgstr ""
+msgstr "Vidigi liston de animacioj en ludilo."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Autoplay on Load"
-msgstr ""
+msgstr "AÅ­toludi al Åargo"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Enable Onion Skinning"
-msgstr ""
+msgstr "Åœalti cepo-haÅ­tadon"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Onion Skinning Options"
-msgstr ""
+msgstr "Cepo-haÅ­tadaj opcioj"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Directions"
-msgstr ""
+msgstr "Direktoj"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Past"
-msgstr ""
+msgstr "Pasinteco"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Future"
-msgstr ""
+msgstr "Estonteco"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Depth"
-msgstr ""
+msgstr "Profundo"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "1 step"
-msgstr ""
+msgstr "1 paÅo"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "2 steps"
-msgstr ""
+msgstr "2 paÅoj"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "3 steps"
-msgstr ""
+msgstr "3 paÅoj"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Differences Only"
-msgstr ""
+msgstr "Malsamoj nur"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Force White Modulate"
-msgstr ""
+msgstr "Altrudi blankan moduladon"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Include Gizmos (3D)"
-msgstr ""
+msgstr "Inkludi gizmojn (3D)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Pin AnimationPlayer"
-msgstr ""
+msgstr "Fiksi AnimationPlayer"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Create New Animation"
-msgstr ""
+msgstr "Krei novan animacion"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation Name:"
-msgstr ""
+msgstr "Nomo de animacio:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
msgid "Error!"
-msgstr ""
+msgstr "Eraro!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Blend Times:"
-msgstr ""
+msgstr "Tempoj de mikso:"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Next (Auto Queue):"
-msgstr ""
+msgstr "Sekvo (aÅ­tomata atendovico):"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Cross-Animation Blend Times"
-msgstr ""
+msgstr "Tempoj de trans-animacia mikso"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Move Node"
-msgstr ""
+msgstr "Movi nodon"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition exists!"
-msgstr ""
+msgstr "Transpaso ekzistas!"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Add Transition"
-msgstr ""
+msgstr "Aldoni transpason"
#: editor/plugins/animation_state_machine_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node"
-msgstr ""
+msgstr "Aldoni nodon"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "End"
-msgstr ""
+msgstr "Fino"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Immediate"
-msgstr ""
+msgstr "Tuja"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Sync"
-msgstr ""
+msgstr "Sinkrona"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "At End"
-msgstr ""
+msgstr "Je la fino"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Travel"
-msgstr ""
+msgstr "VojaÄa"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Start and end nodes are needed for a sub-transition."
-msgstr ""
+msgstr "Komencan kaj finan nodojn bezonas por sub-transpaso."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "No playback resource set at path: %s."
-msgstr ""
+msgstr "Ne reproduktada risurcaro al vojo: %s."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Node Removed"
-msgstr ""
+msgstr "Nodon forigis"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition Removed"
-msgstr ""
+msgstr "Transpason forigis"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set Start Node (Autoplay)"
-msgstr ""
+msgstr "Difini komencan nodon (aÅ­toludadon)"
#: editor/plugins/animation_state_machine_editor.cpp
msgid ""
@@ -4732,56 +4821,62 @@ msgid ""
"RMB to add new nodes.\n"
"Shift+LMB to create connections."
msgstr ""
+"Elekti kaj movi nodojn.\n"
+"Dekstra musbutono por aldoni novajn nodojn.\n"
+"Majuskliga klavo+maldekstra musbutono por krei konektojn."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Create new nodes."
-msgstr ""
+msgstr "Krei novajn nodojn."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Connect nodes."
-msgstr ""
+msgstr "Konekti nodojn."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Remove selected node or transition."
-msgstr ""
+msgstr "Forigi elektitan nodon aÅ­ transpason."
#: editor/plugins/animation_state_machine_editor.cpp
+#, fuzzy
msgid "Toggle autoplay this animation on start, restart or seek to zero."
msgstr ""
+"Baskuli aŭtoludadon de ĉi tiu animacio al komenco, rekomenco aŭ enpoziciigo "
+"al nulo."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set the end animation. This is useful for sub-transitions."
-msgstr ""
+msgstr "Difinu la finan animacion. Tio ĉi estas utila por sub-transpasoj."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition: "
-msgstr ""
+msgstr "Transpaso: "
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Play Mode:"
-msgstr ""
+msgstr "ReÄimo de ludado:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "AnimationTree"
-msgstr ""
+msgstr "AnimationTree"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "New name:"
-msgstr ""
+msgstr "Nova nomo:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Scale:"
-msgstr ""
+msgstr "Skalo:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Fade In (s):"
-msgstr ""
+msgstr "Maldissolvo (s):"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Fade Out (s):"
-msgstr ""
+msgstr "Fordissolvo (s):"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend"
@@ -4904,100 +4999,99 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Contents:"
-msgstr ""
+msgstr "Enhavo:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "View Files"
-msgstr ""
+msgstr "Vidi dosierojn"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Connection error, please try again."
-msgstr ""
+msgstr "Konekta eraro, bonvolu provi ree."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Can't connect to host:"
-msgstr ""
+msgstr "Ne eblas konekti al retejo:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "No response from host:"
-msgstr ""
+msgstr "Ne respondo el retejo:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Can't resolve hostname:"
-msgstr ""
+msgstr "Ne eblas adrestrovi nomon de retejo:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed, return code:"
-msgstr ""
+msgstr "Peto eraris, revena kodo:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed."
-msgstr ""
+msgstr "Peto eraris."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Cannot save response to:"
-msgstr ""
+msgstr "Ne eblas konservi respondon al:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Write error."
-msgstr ""
+msgstr "Skribada eraro."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed, too many redirects"
-msgstr ""
+msgstr "Peto eraris, tro da alidirektoj"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Redirect loop."
-msgstr ""
+msgstr "Alidirekta iteracio."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed, timeout"
-msgstr ""
+msgstr "Peto eraris, tempolimo"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Timeout."
-msgstr "Tempo:"
+msgstr "Tempolimo."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Bad download hash, assuming file has been tampered with."
-msgstr ""
+msgstr "Malbona haketaĵo el elÅutaĵo, supozas dosieron esti tuÅaĉita."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Expected:"
-msgstr ""
+msgstr "Atendito:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Got:"
-msgstr ""
+msgstr "Ricevinto:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Failed SHA-256 hash check"
-msgstr ""
+msgstr "Kontrolo de SHA-256-a haketaĵo eraris"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
-msgstr ""
+msgstr "Eraro de havaĵa elÅuto:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Downloading (%s / %s)..."
-msgstr ""
+msgstr "ElÅutas (%s / %s)..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Downloading..."
-msgstr ""
+msgstr "ElÅutas..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Resolving..."
-msgstr ""
+msgstr "Adrestrovas..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Error making request"
-msgstr ""
+msgstr "Eraro dum petado"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Idle"
-msgstr ""
+msgstr "Senokupa"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Install..."
@@ -5009,105 +5103,107 @@ msgstr "Reprovi"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download Error"
-msgstr ""
+msgstr "ElÅuta eraro"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download for this asset is already in progress!"
-msgstr ""
+msgstr "ElÅutado de ĉi tiu havaĵo estas jam farata!"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Recently Updated"
-msgstr ""
+msgstr "Plej lastatempe Äisdatigita"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Least Recently Updated"
-msgstr ""
+msgstr "Malplej lastatempe Äisdatigita"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (A-Z)"
-msgstr ""
+msgstr "Nomo (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (Z-A)"
-msgstr ""
+msgstr "Nomo (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "License (A-Z)"
-msgstr ""
+msgstr "Permesilo (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "License (Z-A)"
-msgstr ""
+msgstr "Permesilo (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "First"
-msgstr ""
+msgstr "Unua"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Previous"
-msgstr ""
+msgstr "AntaÅ­a"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Next"
-msgstr ""
+msgstr "Sekva"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Last"
-msgstr ""
+msgstr "Lasta"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "All"
-msgstr ""
+msgstr "Tuta"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "No results for \"%s\"."
-msgstr ""
+msgstr "Ne rezultoj por \"%s\"."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
-msgstr ""
+msgstr "Enporti..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Plugins..."
-msgstr ""
+msgstr "Kromprogramoj..."
#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
msgid "Sort:"
-msgstr "Ordigi:"
+msgstr "Ordigo:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Category:"
-msgstr ""
+msgstr "Kategorio:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Site:"
-msgstr ""
+msgstr "Retejo:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Support"
-msgstr ""
+msgstr "Helpo"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Official"
-msgstr ""
+msgstr "Ofica"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Testing"
-msgstr ""
+msgstr "Testada"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Loading..."
-msgstr ""
+msgstr "Åœargas..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Assets ZIP File"
-msgstr ""
+msgstr "ZIP-dosiero de havaĵoj"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
+"Ne eblas determini konservan dosierindikon por lummapaj bildoj.\n"
+"Konservu vian scenon kaj provu ree."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5136,11 +5232,11 @@ msgstr ""
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
-msgstr ""
+msgstr "Baki lummapojn"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Select lightmap bake file:"
-msgstr ""
+msgstr "Elekti dosieron por bakado de lummapo:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5149,106 +5245,103 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
-msgstr ""
+msgstr "Agordi kapton"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
-msgstr ""
+msgstr "Krada deÅovo:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Step:"
-msgstr ""
+msgstr "Krada paÅo:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Primary Line Every:"
-msgstr ""
+msgstr "Ĉefa linio al ĉiu:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "steps"
-msgstr ""
+msgstr "paÅoj"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Offset:"
-msgstr ""
+msgstr "Rotacia deÅovo:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Step:"
-msgstr ""
+msgstr "Rotacia paÅo:"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale Step:"
-msgstr "Skali RejÅo:"
+msgstr "Skala paÅo:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move Vertical Guide"
-msgstr ""
+msgstr "Movi vertikalan gvidilon"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Vertical Guide"
-msgstr ""
+msgstr "Krei vertikalan gvidilon"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Remove Vertical Guide"
-msgstr "Forigi Nevalidajn Åœlosilojn"
+msgstr "Forigi vertikalan gvidilon"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move Horizontal Guide"
-msgstr ""
+msgstr "Movi horizontalan gvidilon"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Horizontal Guide"
-msgstr ""
+msgstr "Krei horizontalan gvidilon"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Remove Horizontal Guide"
-msgstr "Forigi Nevalidajn Åœlosilojn"
+msgstr "Forigi horizontalan gvidilon"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Horizontal and Vertical Guides"
-msgstr ""
+msgstr "Krei horizontalajn kaj vertikalajn gvidilojn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr ""
+msgstr "Agordi la deÅovon de la pivoto de CanvasItem \"%s\" al (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotate %d CanvasItems"
-msgstr ""
+msgstr "Rotacii %d CanvasItem-ojn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr ""
+msgstr "Rotacii CanvasItem \"%s\" al %d gradoj"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr ""
+msgstr "Movi la ankron de CanvasItem \"%s\""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "Skali Node2D \"%s\" al (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
-msgstr ""
+msgstr "Regrandigi Control \"%s\" al (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale %d CanvasItems"
-msgstr ""
+msgstr "Skali %d CanvasItem-ojn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale CanvasItem \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "Skali CanvasItem \"%s\" al (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move %d CanvasItems"
-msgstr ""
+msgstr "Movi %d CanvasItem-ojn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move CanvasItem \"%s\" to (%d, %d)"
-msgstr ""
+msgstr "Movi CanvasItem \"%s\" al (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5268,67 +5361,67 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Left"
-msgstr ""
+msgstr "Supre maldekstre"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Right"
-msgstr ""
+msgstr "Supre dekstre"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Right"
-msgstr ""
+msgstr "Malsupre dekstre"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Left"
-msgstr ""
+msgstr "Malsupre maldekstre"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Left"
-msgstr ""
+msgstr "Centre maldekstre"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Top"
-msgstr ""
+msgstr "Centre supre"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Right"
-msgstr ""
+msgstr "Centre dekstre"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Bottom"
-msgstr ""
+msgstr "Centre malsupre"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center"
-msgstr ""
+msgstr "Centre"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Left Wide"
-msgstr ""
+msgstr "Maldekstre vaste"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Wide"
-msgstr ""
+msgstr "Supre vaste"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Right Wide"
-msgstr ""
+msgstr "Dekstre vaste"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Wide"
-msgstr ""
+msgstr "Malsupre vaste"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "VCenter Wide"
-msgstr ""
+msgstr "Vertikalcentre vaste"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "HCenter Wide"
-msgstr ""
+msgstr "Horizontalcentre vaste"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Full Rect"
-msgstr ""
+msgstr "Plene rektangula"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5337,15 +5430,15 @@ msgstr "Skali RejÅo:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Anchors only"
-msgstr ""
+msgstr "Nur ankroj"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Anchors and Margins"
-msgstr ""
+msgstr "ÅœanÄi ankrojn kaj marÄenojn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Anchors"
-msgstr ""
+msgstr "ÅœanÄi ankrojn"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5353,6 +5446,8 @@ msgid ""
"Game Camera Override\n"
"Overrides game camera with editor viewport camera."
msgstr ""
+"Transpaso de la luda fotilo\n"
+"Transpasi ludan fotilon kun viduja fotilo de la redaktilo."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5360,98 +5455,104 @@ msgid ""
"Game Camera Override\n"
"No game instance running."
msgstr ""
+"Transpaso de la luda fotilo\n"
+"Ne luda ekzemplo ruliÄas."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Lock Selected"
-msgstr ""
+msgstr "Åœlosi elektiton"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unlock Selected"
-msgstr ""
+msgstr "MalÅlosi elektiton"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Group Selected"
-msgstr ""
+msgstr "Grupigi elektiton"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Ungroup Selected"
-msgstr ""
+msgstr "Malgrupigi elektiton"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Paste Pose"
-msgstr ""
+msgstr "Alglui pozon"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Guides"
-msgstr ""
+msgstr "Vakigi gvidilojn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Custom Bone(s) from Node(s)"
-msgstr ""
+msgstr "Krei proprajn osto(j)n el nodo(j)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Bones"
-msgstr ""
+msgstr "Vakigi ostojn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make IK Chain"
-msgstr ""
+msgstr "Krei IK-an ĉenon"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear IK Chain"
-msgstr ""
+msgstr "Vakigi IK-an ĉenon"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
"Warning: Children of a container get their position and size determined only "
"by their parent."
msgstr ""
+"Verto: Infanoj de stirilujo determinas iliajn poziciojn kaj grandojn nur per "
+"ilia patro."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
msgid "Zoom Reset"
-msgstr ""
+msgstr "Rekomencigi zomon"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Select Mode"
-msgstr ""
+msgstr "Elektada reÄimo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Drag: Rotate"
-msgstr ""
+msgstr "Åœovado: Rotacii"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Alt+Drag: Move"
-msgstr ""
+msgstr "Alt-klavo+Åovado: Movi"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving)."
msgstr ""
+"Premi 'V' por ÅanÄi pivoton, 'Majuskliga klavo+V' por Åovi pivoton (dum "
+"movado)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Alt+RMB: Depth list selection"
-msgstr ""
+msgstr "Alt-klavo+dekstra musbutono: Elektado el profunda listo"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Move Mode"
-msgstr ""
+msgstr "Movada reÄimo"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Mode"
-msgstr ""
+msgstr "Rotaciada reÄimo"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Mode"
-msgstr ""
+msgstr "Skalada reÄimo"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5459,97 +5560,99 @@ msgid ""
"Show a list of all objects at the position clicked\n"
"(same as Alt+RMB in select mode)."
msgstr ""
+"Vidigi liston de ĉiuj objektoj al la alklakita pozicio.\n"
+"(samo kiel Alt-klavo+dekstra musbutono en elektada reÄimo)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Click to change object's rotation pivot."
-msgstr ""
+msgstr "Alklaku por ÅanÄi rotacian pivoton de objekto."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan Mode"
-msgstr ""
+msgstr "Panoramada reÄimo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Ruler Mode"
-msgstr ""
+msgstr "Mezurado reÄimo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle smart snapping."
-msgstr ""
+msgstr "Baskuli inteligentan kaptadon."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Smart Snap"
-msgstr ""
+msgstr "Uzi inteligentan kaptadon"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle grid snapping."
-msgstr ""
+msgstr "Baskuli kaptadon per krado."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Grid Snap"
-msgstr ""
+msgstr "Uzi kapton per krado"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snapping Options"
-msgstr ""
+msgstr "Opcioj de kaptado"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Rotation Snap"
-msgstr ""
+msgstr "Uzi rotacian kaptadon"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Scale Snap"
-msgstr ""
+msgstr "Uzi skalan kaptadon"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap Relative"
-msgstr ""
+msgstr "Kapti relative"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Pixel Snap"
-msgstr ""
+msgstr "Uzi kaptadon per rastrumero"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Smart Snapping"
-msgstr ""
+msgstr "Inteligenta kaptado"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Configure Snap..."
-msgstr ""
+msgstr "Agordi kaptadon..."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Parent"
-msgstr ""
+msgstr "Kapti al patro"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Anchor"
-msgstr ""
+msgstr "Kapti al ankro de nodo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Sides"
-msgstr ""
+msgstr "Kapti al flankoj de nodo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Center"
-msgstr ""
+msgstr "Kapti al centro de nodo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Other Nodes"
-msgstr ""
+msgstr "Kapti al aliaj nodoj"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Guides"
-msgstr ""
+msgstr "Kapti al gvidiloj"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Lock the selected object in place (can't be moved)."
-msgstr ""
+msgstr "Åœlosi la elektitan objekton samloke (ne movebla)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unlock the selected object (can be moved)."
-msgstr ""
+msgstr "MalÅlosi la elektitan objekton (movebla)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5580,7 +5683,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View"
-msgstr ""
+msgstr "Vido"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Always Show Grid"
@@ -6191,7 +6294,7 @@ msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
msgid "Convert to CPUParticles"
-msgstr ""
+msgstr "Konverti al CPUParticles"
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Generating Visibility Rect"
@@ -6207,7 +6310,7 @@ msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Convert to CPUParticles2D"
-msgstr ""
+msgstr "Konverti al CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6643,7 +6746,7 @@ msgstr ""
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp
msgid "Open in Editor"
-msgstr ""
+msgstr "Malfermi en la Redaktilo"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Load Resource"
@@ -6679,7 +6782,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Error saving file!"
-msgstr ""
+msgstr "Eraras konservi dosieron!"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error while saving theme."
@@ -6699,15 +6802,15 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "New Text File..."
-msgstr ""
+msgstr "Nova teksta dosiero..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Open File"
-msgstr ""
+msgstr "Malfermi dosieron"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save File As..."
-msgstr ""
+msgstr "Konservi dosieron kiel..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Can't obtain the script for running."
@@ -6740,7 +6843,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme As..."
-msgstr ""
+msgstr "Konservi etoson kiel..."
#: editor/plugins/script_editor_plugin.cpp
msgid "%s Class Reference"
@@ -6794,7 +6897,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "File"
-msgstr ""
+msgstr "Dosiero"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open..."
@@ -6806,11 +6909,11 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Save All"
-msgstr ""
+msgstr "Konservi tuton"
#: editor/plugins/script_editor_plugin.cpp
msgid "Soft Reload Script"
-msgstr ""
+msgstr "Varme reÅargi skripton"
#: editor/plugins/script_editor_plugin.cpp
msgid "Copy Script Path"
@@ -6863,20 +6966,20 @@ msgstr "Serĉo"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
-msgstr ""
+msgstr "PaÅi en"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Over"
-msgstr ""
+msgstr "PaÅi poste"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Break"
-msgstr ""
+msgstr "PaÅ­zi rulon"
#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
#: editor/script_editor_debugger.cpp
msgid "Continue"
-msgstr ""
+msgstr "DaÅ­rigi"
#: editor/plugins/script_editor_plugin.cpp
msgid "Keep Debugger Open"
@@ -6888,7 +6991,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Open Godot online documentation."
-msgstr ""
+msgstr "Malfermi enretan dokumentaron de Godot."
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -6915,7 +7018,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
-msgstr ""
+msgstr "Sencimigilo"
#: editor/plugins/script_editor_plugin.cpp
msgid "Search Results"
@@ -6923,19 +7026,19 @@ msgstr "Rezultoj de serĉo"
#: editor/plugins/script_editor_plugin.cpp
msgid "Clear Recent Scripts"
-msgstr ""
+msgstr "Vakigi lastajn skriptojn"
#: editor/plugins/script_text_editor.cpp
msgid "Connections to method:"
-msgstr ""
+msgstr "Konektoj al metodo:"
#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
msgid "Source"
-msgstr ""
+msgstr "Fonto"
#: editor/plugins/script_text_editor.cpp
msgid "Target"
-msgstr ""
+msgstr "Celo"
#: editor/plugins/script_text_editor.cpp
msgid ""
@@ -6948,15 +7051,15 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
msgid "Line"
-msgstr ""
+msgstr "Linio"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Function"
-msgstr ""
+msgstr "Iri al funkcio"
#: editor/plugins/script_text_editor.cpp
msgid "Only resources from filesystem can be dropped."
-msgstr "Nur risurcoj el dosiersistemo povas esti forigita."
+msgstr "Nur risurcojn el la dosiersistemo eblas forigi."
#: editor/plugins/script_text_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
@@ -6965,83 +7068,83 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
msgid "Lookup Symbol"
-msgstr ""
+msgstr "Ricevi simbolon"
#: editor/plugins/script_text_editor.cpp
msgid "Pick Color"
-msgstr ""
+msgstr "Elekti koloron"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Convert Case"
-msgstr ""
+msgstr "Konverti usklon"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Uppercase"
-msgstr ""
+msgstr "Majuskla"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Lowercase"
-msgstr ""
+msgstr "Minuskla"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Capitalize"
-msgstr ""
+msgstr "Kapitaligi"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Syntax Highlighter"
-msgstr ""
+msgstr "Sintaksa markilo"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
msgid "Bookmarks"
-msgstr ""
+msgstr "PaÄosignoj"
#: editor/plugins/script_text_editor.cpp
msgid "Breakpoints"
-msgstr ""
+msgstr "PaÅ­zpunktoj"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
msgid "Go To"
-msgstr ""
+msgstr "Iri al"
#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Cut"
-msgstr ""
+msgstr "Eltondi"
#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
#: scene/gui/text_edit.cpp
msgid "Select All"
-msgstr "Elektaro ĉiuj"
+msgstr "Elekti tutan"
#: editor/plugins/script_text_editor.cpp
msgid "Delete Line"
-msgstr ""
+msgstr "Forigi linion"
#: editor/plugins/script_text_editor.cpp
msgid "Indent Left"
-msgstr ""
+msgstr "KrommarÄeni maldekstren"
#: editor/plugins/script_text_editor.cpp
msgid "Indent Right"
-msgstr ""
+msgstr "KrommarÄeni dekstren"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Comment"
-msgstr ""
+msgstr "Baskuli komenton"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
-msgstr ""
+msgstr "Faldi/Malfaldi linion"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
-msgstr ""
+msgstr "Faldi ĉiujn liniojn"
#: editor/plugins/script_text_editor.cpp
msgid "Unfold All Lines"
-msgstr ""
+msgstr "Malfaldi ĉiujn liniojn"
#: editor/plugins/script_text_editor.cpp
msgid "Clone Down"
@@ -7062,11 +7165,11 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Spaces"
-msgstr ""
+msgstr "Konverti krommarÄenon al spacoj"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Tabs"
-msgstr ""
+msgstr "Konverti krommarÄenon al taboj"
#: editor/plugins/script_text_editor.cpp
msgid "Auto Indent"
@@ -7434,6 +7537,12 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"Alklaku por baskuli inter videblaj statoj.\n"
+"\n"
+"Malferma okulo: Gizmo estas videbla.\n"
+"Ferma okulo: Gizmo estas kaÅita.\n"
+"Duonferma okulo: Gizmo estas ankaÅ­ videbla tra maldiafanaj surfacoj (\"iks-"
+"rada\")."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -7452,11 +7561,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Local Space"
-msgstr ""
+msgstr "Uzi lokan spacon"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Snap"
-msgstr ""
+msgstr "Uzi kapton krade"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -7505,7 +7614,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Transform"
-msgstr ""
+msgstr "Transformo"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Object to Floor"
@@ -9454,7 +9563,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Script"
-msgstr ""
+msgstr "Skripto"
#: editor/project_export.cpp
msgid "Script Export Mode:"
@@ -9518,16 +9627,17 @@ msgstr ""
#: editor/project_manager.cpp
msgid "The path specified doesn't exist."
-msgstr ""
+msgstr "La provizinta dosierindiko ne ekzistas."
#: editor/project_manager.cpp
msgid "Error opening package file (it's not in ZIP format)."
-msgstr ""
+msgstr "Eraro dum malfermi pakaĵan dosieron (ne estas en ZIP-formo)."
#: editor/project_manager.cpp
msgid ""
"Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."
msgstr ""
+"Nevalida projekta \".zip\" dosiero; Äi ne enhavas dosieron \"project.godot\"."
#: editor/project_manager.cpp
msgid "Please choose an empty folder."
@@ -9535,11 +9645,11 @@ msgstr "Bonvolu, elektu malplenan dosierujon."
#: editor/project_manager.cpp
msgid "Please choose a \"project.godot\" or \".zip\" file."
-msgstr ""
+msgstr "Bonvolu elekti \"project.godot\" aÅ­ \".zip\" dosieron."
#: editor/project_manager.cpp
msgid "This directory already contains a Godot project."
-msgstr ""
+msgstr "Tiu ĉi dosierujo jam enhavas Godot-an projekton."
#: editor/project_manager.cpp
msgid "New Game Project"
@@ -9547,41 +9657,43 @@ msgstr "Nova luda projekto"
#: editor/project_manager.cpp
msgid "Imported Project"
-msgstr ""
+msgstr "Enportita projekto"
#: editor/project_manager.cpp
msgid "Invalid Project Name."
-msgstr ""
+msgstr "Nevalida nomo de projekto."
#: editor/project_manager.cpp
msgid "Couldn't create folder."
-msgstr "Ne povis krei dosierujon."
+msgstr "Ne eblas krei dosierujon."
#: editor/project_manager.cpp
msgid "There is already a folder in this path with the specified name."
-msgstr ""
+msgstr "Estas jam dosierujo en ĉi tiu dosierindiko kun la provizinta nomo."
#: editor/project_manager.cpp
msgid "It would be a good idea to name your project."
-msgstr ""
+msgstr "Nomi vian projekton estus konsilinde."
#: editor/project_manager.cpp
msgid "Invalid project path (changed anything?)."
-msgstr ""
+msgstr "Nevalida dosierindiko de projekto (ÅanÄis ion ajn?)."
#: editor/project_manager.cpp
msgid ""
"Couldn't load project.godot in project path (error %d). It may be missing or "
"corrupted."
msgstr ""
+"Ne eblas Åargi project.godot en projekta dosierindiko (eraro %d). Äœi eble "
+"estas manka aÅ­ difektita."
#: editor/project_manager.cpp
msgid "Couldn't edit project.godot in project path."
-msgstr ""
+msgstr "Ne eblas redakti project.godot en projekta dosierindiko."
#: editor/project_manager.cpp
msgid "Couldn't create project.godot in project path."
-msgstr ""
+msgstr "Ne eblas krei project.godot en projekta dosierindiko."
#: editor/project_manager.cpp
msgid "Rename Project"
@@ -9589,11 +9701,11 @@ msgstr "Renomi projekton"
#: editor/project_manager.cpp
msgid "Import Existing Project"
-msgstr ""
+msgstr "Enporti ekzistantan projekton"
#: editor/project_manager.cpp
msgid "Import & Edit"
-msgstr ""
+msgstr "Enporti kaj redakti"
#: editor/project_manager.cpp
msgid "Create New Project"
@@ -9620,9 +9732,8 @@ msgid "Project Path:"
msgstr "Projekta vojo:"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Project Installation Path:"
-msgstr "Projekta instala vojo:"
+msgstr "Dosierindiko de projekta instalo:"
#: editor/project_manager.cpp
msgid "Renderer:"
@@ -9630,68 +9741,64 @@ msgstr "Bildigilo:"
#: editor/project_manager.cpp
msgid "OpenGL ES 3.0"
-msgstr ""
+msgstr "OpenGL ES 3.0"
#: editor/project_manager.cpp
msgid "Not supported by your GPU drivers."
-msgstr ""
+msgstr "Ne subtenata de la peliloj de via grafika procesoro."
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Higher visual quality\n"
"All features available\n"
"Incompatible with older hardware\n"
"Not recommended for web games"
msgstr ""
-"Pli alta vida kvalito\n"
-"Ĉiuj ebloj disponeblaj\n"
+"Pli bona vida kvalito\n"
+"Ĉiuj eblecoj disponeblas\n"
"Nekongruas kun pli malnova aparataro\n"
-"Nerekomendita por teksaĵaj ludoj"
+"Ne rekomendas por retaj ludoj"
#: editor/project_manager.cpp
msgid "OpenGL ES 2.0"
-msgstr ""
+msgstr "OpenGL ES 2.0"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Lower visual quality\n"
"Some features not available\n"
"Works on most hardware\n"
"Recommended for web games"
msgstr ""
-"Pli malalta vida kvalito\n"
-"Iom ebloj ne disponeblaj\n"
-"Laboras en plej multaj aparataroj\n"
-"Rekomendita por teksaĵaj ludoj"
+"Malpli bona vida kvalito\n"
+"Iuj eblecoj ne disponeblas\n"
+"Kongruas kun plej de aparataro\n"
+"Rekomendas por retaj ludoj"
#: editor/project_manager.cpp
+#, fuzzy
msgid "Renderer can be changed later, but scenes may need to be adjusted."
-msgstr ""
+msgstr "Bildigilo ÅanÄeblas poste, sed scenoj eble bezonos Äustigon."
#: editor/project_manager.cpp
msgid "Unnamed Project"
-msgstr ""
+msgstr "Sennoma projekto"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Missing Project"
-msgstr "Malkanta projekto"
+msgstr "Manka projekto"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Error: Project is missing on the filesystem."
msgstr "Eraro: projekto estas manka en la dosiersistemo."
#: editor/project_manager.cpp
msgid "Can't open project at '%s'."
-msgstr "Ne povas malfermi projekto ĉe '%s'."
+msgstr "Ne eblas malfermi projekton ĉe '%s'."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Are you sure to open more than one project?"
-msgstr "Ĉu vi certa en malfermaĵo pli ol unun projekton?"
+msgstr "Ĉu vi certe volas malfermi plurajn projektojn?"
#: editor/project_manager.cpp
msgid ""
@@ -9705,6 +9812,15 @@ msgid ""
"Warning: You won't be able to open the project with previous versions of the "
"engine anymore."
msgstr ""
+"La jena projekto-agordara dosiero ne specifas la versio de Godot per kiu "
+"krei Äin.\n"
+"\n"
+"%s\n"
+"\n"
+"Se vi pluigus malfermi Äin, Äi konvertiÄos al aktuala agordo-dosierformo de "
+"Godot.\n"
+"Averto: Vi ne eblos malfermi la projekton per antaÅ­aj versioj de la "
+"videoludilo plue."
#: editor/project_manager.cpp
msgid ""
@@ -9717,12 +9833,22 @@ msgid ""
"Warning: You won't be able to open the project with previous versions of the "
"engine anymore."
msgstr ""
+"La jena projekto-agordara dosiero generiÄis per pli malnova versio de la "
+"videoludilo, kaj bezonas konverti al ĉi tiu versio:\n"
+"\n"
+"%s\n"
+"\n"
+"Ĉu vi volas konverti Äin?\n"
+"Averto: Vi ne eblos malfermi la projekton per antaÅ­aj versioj de la "
+"videoludilo plue."
#: editor/project_manager.cpp
msgid ""
"The project settings were created by a newer engine version, whose settings "
"are not compatible with this version."
msgstr ""
+"La projektaj agordoj kreiÄis per pli nova versio de la videoludilo, en kio "
+"la agordoj ne estas kongruantaj kun ĉi tiu versio."
#: editor/project_manager.cpp
msgid ""
@@ -9774,7 +9900,7 @@ msgstr ""
#. TRANSLATORS: This refers to the application where users manage their Godot projects.
#: editor/project_manager.cpp
msgid "Project Manager"
-msgstr ""
+msgstr "Mastrumilo de Projektoj"
#: editor/project_manager.cpp
msgid "Projects"
@@ -9782,12 +9908,11 @@ msgstr "Projektoj"
#: editor/project_manager.cpp
msgid "Loading, please wait..."
-msgstr ""
+msgstr "Åœargas, bonvolu atendi..."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Last Modified"
-msgstr "Modifita"
+msgstr "Lastaj modifitaj"
#: editor/project_manager.cpp
msgid "Scan"
@@ -9803,7 +9928,7 @@ msgstr "Nova projekto"
#: editor/project_manager.cpp
msgid "Remove Missing"
-msgstr ""
+msgstr "Forigi mankan"
#: editor/project_manager.cpp
msgid "Templates"
@@ -9811,17 +9936,20 @@ msgstr "Åœablonoj"
#: editor/project_manager.cpp
msgid "Restart Now"
-msgstr ""
+msgstr "Rekomenci nun"
#: editor/project_manager.cpp
msgid "Can't run project"
-msgstr ""
+msgstr "Ne eblas ruli projekton"
#: editor/project_manager.cpp
msgid ""
"You currently don't have any projects.\n"
"Would you like to explore official example projects in the Asset Library?"
msgstr ""
+"Vi aktuale ne havas iujn projektojn.\n"
+"Ĉu vi volas esplori la oficajn ekzemplajn projektojn en la biblioteko de "
+"havaĵoj?"
#: editor/project_manager.cpp
msgid ""
@@ -9832,145 +9960,147 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Key "
-msgstr ""
+msgstr "Klavo "
#: editor/project_settings_editor.cpp
msgid "Joy Button"
-msgstr ""
+msgstr "Butono de stirstango"
#: editor/project_settings_editor.cpp
msgid "Joy Axis"
-msgstr ""
+msgstr "Akso de stirstango"
#: editor/project_settings_editor.cpp
msgid "Mouse Button"
-msgstr ""
+msgstr "Musbutono"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
+"Nevalida nomo de faro. Äœi eblas nek esti malplena nek enhavi '/', ':', '=', "
+"'\\' aÅ­ '\"'"
#: editor/project_settings_editor.cpp
msgid "An action with the name '%s' already exists."
-msgstr ""
+msgstr "Faro kun la nomo '%s' jam ekzistas."
#: editor/project_settings_editor.cpp
msgid "Rename Input Action Event"
-msgstr ""
+msgstr "Renomi eventon de eniga faro"
#: editor/project_settings_editor.cpp
msgid "Change Action deadzone"
-msgstr ""
+msgstr "ÅœanÄi mortzonon de faro"
#: editor/project_settings_editor.cpp
msgid "Add Input Action Event"
-msgstr ""
+msgstr "Aldoni eventon de eniga faro"
#: editor/project_settings_editor.cpp
msgid "All Devices"
-msgstr ""
+msgstr "Ĉiuj aparatoj"
#: editor/project_settings_editor.cpp
msgid "Device"
-msgstr ""
+msgstr "Aparato"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
-msgstr ""
+msgstr "Premi klavon..."
#: editor/project_settings_editor.cpp
msgid "Mouse Button Index:"
-msgstr ""
+msgstr "Indekso de musbutono:"
#: editor/project_settings_editor.cpp
msgid "Left Button"
-msgstr ""
+msgstr "Maldekstra butono"
#: editor/project_settings_editor.cpp
msgid "Right Button"
-msgstr ""
+msgstr "Dekstra butono"
#: editor/project_settings_editor.cpp
msgid "Middle Button"
-msgstr ""
+msgstr "Meza butono"
#: editor/project_settings_editor.cpp
msgid "Wheel Up Button"
-msgstr ""
+msgstr "Radeto supren"
#: editor/project_settings_editor.cpp
msgid "Wheel Down Button"
-msgstr ""
+msgstr "Radeto malsupren"
#: editor/project_settings_editor.cpp
msgid "Wheel Left Button"
-msgstr ""
+msgstr "Radeto maldekstren"
#: editor/project_settings_editor.cpp
msgid "Wheel Right Button"
-msgstr ""
+msgstr "Radeto dekstren"
#: editor/project_settings_editor.cpp
msgid "X Button 1"
-msgstr ""
+msgstr "X-butono 1"
#: editor/project_settings_editor.cpp
msgid "X Button 2"
-msgstr ""
+msgstr "X-butono 2"
#: editor/project_settings_editor.cpp
msgid "Joypad Axis Index:"
-msgstr ""
+msgstr "Indekso de la stirstanga akso:"
#: editor/project_settings_editor.cpp
msgid "Axis"
-msgstr ""
+msgstr "Akso"
#: editor/project_settings_editor.cpp
msgid "Joypad Button Index:"
-msgstr ""
+msgstr "Indekso de la stirstanga butono:"
#: editor/project_settings_editor.cpp
msgid "Erase Input Action"
-msgstr ""
+msgstr "Forigi enigan faron"
#: editor/project_settings_editor.cpp
msgid "Erase Input Action Event"
-msgstr ""
+msgstr "Forigi eventon de eniga faro"
#: editor/project_settings_editor.cpp
msgid "Add Event"
-msgstr ""
+msgstr "Aldoni eventon"
#: editor/project_settings_editor.cpp
msgid "Button"
-msgstr ""
+msgstr "Butono"
#: editor/project_settings_editor.cpp
msgid "Left Button."
-msgstr ""
+msgstr "Maldesktra butono."
#: editor/project_settings_editor.cpp
msgid "Right Button."
-msgstr ""
+msgstr "Dekstra butono."
#: editor/project_settings_editor.cpp
msgid "Middle Button."
-msgstr ""
+msgstr "Meza butono."
#: editor/project_settings_editor.cpp
msgid "Wheel Up."
-msgstr ""
+msgstr "Radeto supren."
#: editor/project_settings_editor.cpp
msgid "Wheel Down."
-msgstr ""
+msgstr "Radeto malsupren."
#: editor/project_settings_editor.cpp
msgid "Add Global Property"
-msgstr ""
+msgstr "Aldoni mallokan atributon"
#: editor/project_settings_editor.cpp
msgid "Select a setting item first!"
@@ -9986,7 +10116,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Delete Item"
-msgstr ""
+msgstr "Forigi elementon"
#: editor/project_settings_editor.cpp
msgid ""
@@ -9996,19 +10126,19 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Add Input Action"
-msgstr ""
+msgstr "Aldoni enigan faron"
#: editor/project_settings_editor.cpp
msgid "Error saving settings."
-msgstr ""
+msgstr "Eraro dum konservi agordojn."
#: editor/project_settings_editor.cpp
msgid "Settings saved OK."
-msgstr ""
+msgstr "Agordoj konserviÄis bone."
#: editor/project_settings_editor.cpp
msgid "Moved Input Action Event"
-msgstr ""
+msgstr "Movis eventon de eniga faro"
#: editor/project_settings_editor.cpp
msgid "Override for Feature"
@@ -10016,15 +10146,15 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Add Translation"
-msgstr ""
+msgstr "Aldoni tradukon"
#: editor/project_settings_editor.cpp
msgid "Remove Translation"
-msgstr ""
+msgstr "Forigi tradukon"
#: editor/project_settings_editor.cpp
msgid "Add Remapped Path"
-msgstr ""
+msgstr "Aldoni dosierindikon de remapo"
#: editor/project_settings_editor.cpp
msgid "Resource Remap Add Remap"
@@ -10052,108 +10182,107 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Project Settings (project.godot)"
-msgstr ""
+msgstr "Projektaj agordoj (project.godot)"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "General"
-msgstr ""
+msgstr "Äœenerala"
#: editor/project_settings_editor.cpp
msgid "Override For..."
-msgstr ""
+msgstr "Redifino por..."
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "The editor must be restarted for changes to take effect."
-msgstr ""
+msgstr "La redaktilon devas rekomencigi por ÅanÄoj efektiviÄus."
#: editor/project_settings_editor.cpp
msgid "Input Map"
-msgstr ""
+msgstr "Eniga mapo"
#: editor/project_settings_editor.cpp
msgid "Action:"
-msgstr ""
+msgstr "Faro:"
#: editor/project_settings_editor.cpp
msgid "Action"
-msgstr ""
+msgstr "Faro"
#: editor/project_settings_editor.cpp
msgid "Deadzone"
-msgstr ""
+msgstr "Mortzono"
#: editor/project_settings_editor.cpp
msgid "Device:"
-msgstr ""
+msgstr "Aparato:"
#: editor/project_settings_editor.cpp
msgid "Index:"
-msgstr ""
+msgstr "Indekso:"
#: editor/project_settings_editor.cpp
msgid "Localization"
-msgstr ""
+msgstr "Lokaĵigado"
#: editor/project_settings_editor.cpp
msgid "Translations"
-msgstr ""
+msgstr "Tradukoj"
#: editor/project_settings_editor.cpp
msgid "Translations:"
-msgstr ""
+msgstr "Tradukoj:"
#: editor/project_settings_editor.cpp
msgid "Remaps"
-msgstr ""
+msgstr "Remapoj"
#: editor/project_settings_editor.cpp
msgid "Resources:"
-msgstr ""
+msgstr "Risurcoj:"
#: editor/project_settings_editor.cpp
msgid "Remaps by Locale:"
-msgstr ""
+msgstr "Remapoj per lokaĵaro:"
#: editor/project_settings_editor.cpp
msgid "Locale"
-msgstr ""
+msgstr "Lokaĵaro"
#: editor/project_settings_editor.cpp
msgid "Locales Filter"
-msgstr ""
+msgstr "Filtro de lokaĵaroj"
#: editor/project_settings_editor.cpp
msgid "Show All Locales"
-msgstr ""
+msgstr "Vidigi ĉiajn lokaĵarojn"
#: editor/project_settings_editor.cpp
msgid "Show Selected Locales Only"
-msgstr ""
+msgstr "Vidigi nur elektitajn lokaĵarojn"
#: editor/project_settings_editor.cpp
msgid "Filter mode:"
-msgstr ""
+msgstr "ReÄimo de filtro:"
#: editor/project_settings_editor.cpp
msgid "Locales:"
-msgstr ""
+msgstr "Lokaĵaroj:"
#: editor/project_settings_editor.cpp
msgid "AutoLoad"
-msgstr ""
+msgstr "AÅ­toÅargado"
#: editor/project_settings_editor.cpp
msgid "Plugins"
-msgstr ""
+msgstr "Kromprogramoj"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Enporti dokon"
+msgstr "Enporti defaÅ­ltojn"
#: editor/property_editor.cpp
msgid "Preset..."
-msgstr ""
+msgstr "AntaÅ­agordo..."
#: editor/property_editor.cpp
msgid "Zero"
@@ -10169,19 +10298,19 @@ msgstr ""
#: editor/property_editor.cpp
msgid "File..."
-msgstr ""
+msgstr "Dosiero..."
#: editor/property_editor.cpp
msgid "Dir..."
-msgstr ""
+msgstr "Dosierujo..."
#: editor/property_editor.cpp
msgid "Assign"
-msgstr ""
+msgstr "Valorizi"
#: editor/property_editor.cpp
msgid "Select Node"
-msgstr ""
+msgstr "Elekti nodon"
#: editor/property_editor.cpp
msgid "Error loading file: Not a resource!"
@@ -10189,55 +10318,55 @@ msgstr ""
#: editor/property_editor.cpp
msgid "Pick a Node"
-msgstr ""
+msgstr "Elekti nodon"
#: editor/property_editor.cpp
msgid "Bit %d, val %d."
-msgstr ""
+msgstr "Bito %d, valoro %d."
#: editor/property_selector.cpp
msgid "Select Property"
-msgstr ""
+msgstr "Elekti atributon"
#: editor/property_selector.cpp
msgid "Select Virtual Method"
-msgstr ""
+msgstr "Elekti virtualan metodon"
#: editor/property_selector.cpp
msgid "Select Method"
-msgstr ""
+msgstr "Elekti metodon"
#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
msgid "Batch Rename"
-msgstr ""
+msgstr "Renomi staple"
#: editor/rename_dialog.cpp
msgid "Replace:"
-msgstr "AnstataÅ­igi:"
+msgstr "AnstataÅ­igo:"
#: editor/rename_dialog.cpp
msgid "Prefix:"
-msgstr ""
+msgstr "Prefikso:"
#: editor/rename_dialog.cpp
msgid "Suffix:"
-msgstr ""
+msgstr "Sufikso:"
#: editor/rename_dialog.cpp
msgid "Use Regular Expressions"
-msgstr ""
+msgstr "Uzi regulesprimojn"
#: editor/rename_dialog.cpp
msgid "Advanced Options"
-msgstr ""
+msgstr "Specialaj opcioj"
#: editor/rename_dialog.cpp
msgid "Substitute"
-msgstr ""
+msgstr "AnstatÅ­igi"
#: editor/rename_dialog.cpp
msgid "Node name"
-msgstr ""
+msgstr "Nomo de nodo"
#: editor/rename_dialog.cpp
msgid "Node's parent name, if available"
@@ -10349,27 +10478,27 @@ msgstr ""
#: editor/run_settings_dialog.cpp
msgid "Run Mode:"
-msgstr ""
+msgstr "ReÄimo de rulo:"
#: editor/run_settings_dialog.cpp
msgid "Current Scene"
-msgstr ""
+msgstr "Aktuala sceno"
#: editor/run_settings_dialog.cpp
msgid "Main Scene"
-msgstr ""
+msgstr "Ĉefa sceno"
#: editor/run_settings_dialog.cpp
msgid "Main Scene Arguments:"
-msgstr ""
+msgstr "Parametroj de ĉefa sceno:"
#: editor/run_settings_dialog.cpp
msgid "Scene Run Settings"
-msgstr ""
+msgstr "Agordoj de rulo de la sceno"
#: editor/scene_tree_dock.cpp
msgid "No parent to instance the scenes at."
-msgstr ""
+msgstr "Ne patro por ekzempli la scenojn al."
#: editor/scene_tree_dock.cpp
msgid "Error loading scene from %s"
@@ -10391,7 +10520,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Instance Child Scene"
-msgstr ""
+msgstr "Ekzemplodoni infanan scenon"
#: editor/scene_tree_dock.cpp
msgid "Can't paste root node into the same scene."
@@ -10496,7 +10625,7 @@ msgstr "Nova radiko de sceno"
#: editor/scene_tree_dock.cpp
msgid "Create Root Node:"
-msgstr ""
+msgstr "Krei radikan nodon:"
#: editor/scene_tree_dock.cpp
msgid "2D Scene"
@@ -10571,7 +10700,7 @@ msgstr "Åœargi kiel lokokupilo"
#: editor/scene_tree_dock.cpp
msgid "Open Documentation"
-msgstr "Malfermi dokumentaro"
+msgstr "Malfermi dokumentaron"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10628,10 +10757,12 @@ msgid ""
"Instance a scene file as a Node. Creates an inherited scene if no root node "
"exists."
msgstr ""
+"Ekzemplodoni scenan dosieron kiel Nodo. Kreus hereditan scenon se radika "
+"nodo ne ekzistas."
#: editor/scene_tree_dock.cpp
msgid "Attach a new or existing script to the selected node."
-msgstr ""
+msgstr "Alfiksi novan aÅ­ ekzistantan skripton al la elektinta nodo."
#: editor/scene_tree_dock.cpp
msgid "Detach the script from the selected node."
@@ -11515,7 +11646,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Signals:"
-msgstr ""
+msgstr "Signaloj:"
#: modules/visual_script/visual_script_editor.cpp
#, fuzzy
@@ -11886,10 +12017,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/es.po b/editor/translations/es.po
index e83d33e9fa..660e17420d 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -60,12 +60,16 @@
# Lucasdelpiero <lucasdelpiero98@gmail.com>, 2021.
# SteamGoblin <SteamGoblin860@gmail.com>, 2021.
# Francisco C <pruebasfrancisco17@gmail.com>, 2021.
+# Cam <cameron.toms@gmail.com>, 2021.
+# Juan camilo <jugarciago01@gmail.com>, 2021.
+# Manuel González <mgoopazo@gmail.com>, 2021.
+# softonicblip <blazeawardspace@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-19 22:33+0000\n"
-"Last-Translator: Francisco C <pruebasfrancisco17@gmail.com>\n"
+"PO-Revision-Date: 2021-06-03 22:23+0000\n"
+"Last-Translator: softonicblip <blazeawardspace@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
"Language: es\n"
@@ -658,7 +662,7 @@ msgstr "Usar Curvas Bezier"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
-msgstr "Optimizador de Animación"
+msgstr "Optimizar animación"
#: editor/animation_track_editor.cpp
msgid "Max. Linear Error:"
@@ -865,7 +869,7 @@ msgstr "Eliminar"
#: editor/connections_dialog.cpp
msgid "Add Extra Call Argument:"
-msgstr "Añadir Argumento Extra de Llamada:"
+msgstr "Añadir argumento extra de llamada:"
#: editor/connections_dialog.cpp
msgid "Extra Call Arguments:"
@@ -1182,6 +1186,10 @@ msgstr "Cambiar Valor del Diccionario"
msgid "Thanks from the Godot community!"
msgstr "¡Muchas gracias de parte de la comunidad de Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Contribuidores de Godot"
@@ -2074,7 +2082,7 @@ msgstr "Métodos"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr "Propiedades del Tema"
+msgstr "Propiedades de Temas"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -2086,7 +2094,7 @@ msgstr "Constantes"
#: editor/editor_help.cpp
msgid "Property Descriptions"
-msgstr "Descripciones de Propiedad"
+msgstr "Descripciones de Propiedades"
#: editor/editor_help.cpp
msgid "(value)"
@@ -2611,11 +2619,13 @@ msgstr "No se pudo cargar el script addon desde la ruta: '%s'."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"No se puede cargar el script de addon desde la ruta: '%s' Parece que hay un "
-"error en el código, por favor compruebe la sintaxis."
+"error en el código, por favor compruebe la sintaxis.\n"
+"Desactivar el addon en '%s' para prevenir mas errores."
#: editor/editor_node.cpp
msgid ""
@@ -3065,6 +3075,10 @@ msgid "About"
msgstr "Acerca de"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Apoyar el desarrollo de Godot"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Reproducir el proyecto."
@@ -5312,7 +5326,7 @@ msgstr ""
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
-"El editor de Godot se construyó sin soporte de trazado de rayos, los "
+"El editor de Godot se construyó sin soporte para trazado de rayos, los "
"lightmaps no pueden ser bakeados."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
@@ -7647,6 +7661,8 @@ msgstr "Bloquear Rotación de Vista"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Para alejar más, cambia los planos de corte de la cámara (Vista -> "
+"Configuración...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -10234,7 +10250,7 @@ msgstr "Botón del Mouse"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Nombre de acción inválido. No puede estar vacío o contener '/', ':', '=', "
@@ -11048,6 +11064,9 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"Si está seleccionado, el panel de árbol de escena Remota provocará saltos de "
+"framerate en el proyecto cada vez que se actualice.\n"
+"Vuelve a seleccionar el árbol de escena Local para mejorar el rendimiento."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12305,11 +12324,23 @@ msgstr ""
"Instalala desde el menú de Proyecto."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Debug keystore no configurada en Configuración del Editor ni en el preset."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Release keystore no está configurado correctamente en el preset de "
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index d9e193da4e..3c3174f6c8 100644
--- a/editor/translations/es_AR.po
+++ b/editor/translations/es_AR.po
@@ -8,7 +8,7 @@
# Sebastian Silva <sebastian@sugarlabs.org>, 2016.
# Jose Luis Bossio <joseluisbossio@gmail.com>, 2018.
# Reynaldo Cruz <rcruz60@gmail.com>, 2018.
-# Javier Ocampos <xavier.ocampos@gmail.com>, 2018, 2019, 2020.
+# Javier Ocampos <xavier.ocampos@gmail.com>, 2018, 2019, 2020, 2021.
# Andrés S <andres.segovia.dev@gmail.com>, 2019.
# Florencia Menéndez <mariaflormz2@gmail.com>, 2019.
# roger <616steam@gmail.com>, 2019, 2020.
@@ -21,7 +21,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-31 03:53+0000\n"
+"PO-Revision-Date: 2021-05-29 13:49+0000\n"
"Last-Translator: Lisandro Lorea <lisandrolorea@gmail.com>\n"
"Language-Team: Spanish (Argentina) <https://hosted.weblate.org/projects/"
"godot-engine/godot/es_AR/>\n"
@@ -30,7 +30,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1136,6 +1136,10 @@ msgstr "Cambiar Valor del Diccionario"
msgid "Thanks from the Godot community!"
msgstr "Gracias de parte de la comunidad Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Colaboradores de Godot Engine"
@@ -2565,11 +2569,13 @@ msgstr "No se pudo cargar el script de addon desde la ruta: '%s'."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"No se pudo cargar el script de addon desde la ruta: '%s' Parece haber un "
-"error en el código. Por favor, revisá la sintaxis."
+"No se pudo cargar el script de addon desde la ruta: '%s'. Puede ser por un "
+"error de código en dicho script.\n"
+"Desactivando el addon en '%s' para prevenir nuevos errores."
#: editor/editor_node.cpp
msgid ""
@@ -3017,6 +3023,10 @@ msgid "About"
msgstr "Acerca de"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Apoyar el desarrollo de Godot"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Reproducir el proyecto."
@@ -5263,7 +5273,7 @@ msgstr ""
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
-"El editor de Godot se compiló sin soporte de ray tracing, los lightmaps no "
+"El editor de Godot se compiló sin soporte para ray tracing, los lightmaps no "
"pueden ser bakeados."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
@@ -7592,6 +7602,8 @@ msgstr "Rotación de Vista Trabada"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Para alejar más, cambiá los planos de corte de la cámara (Vista -> "
+"Configuración...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -10177,7 +10189,7 @@ msgstr "Botón de Mouse"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Nombre de acción inválido. No puede estar vacío o contener '/', ':', '=', "
@@ -10992,6 +11004,9 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"Al seleccionar, el panel de árbol de escena remota causará saltos de "
+"framerate en el proyecto cada vez que se actualice.\n"
+"Volvé a seleccionar escena local para mejorar el rendimiento."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12246,11 +12261,23 @@ msgstr ""
"Instalala desde el menú de Proyecto."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Keystore debug no configurada en Configuración del Editor ni en el preset."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Release keystore no está configurado correctamente en el preset de "
diff --git a/editor/translations/et.po b/editor/translations/et.po
index de0b0360ee..d81e10e9d7 100644
--- a/editor/translations/et.po
+++ b/editor/translations/et.po
@@ -10,7 +10,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2021-03-07 06:04+0000\n"
+"PO-Revision-Date: 2021-05-10 15:32+0000\n"
"Last-Translator: Kritzmensch <streef.gtx@gmail.com>\n"
"Language-Team: Estonian <https://hosted.weblate.org/projects/godot-engine/"
"godot/et/>\n"
@@ -18,7 +18,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5.1\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1091,6 +1091,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr "Suur tänu Godot kogukonnalt!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot mängumootori panustajad"
@@ -2481,9 +2485,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Lisa-skripti ei olnud võimalik laadida teelt: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Lisa-skripti ei olnud võimalik laadida teelt: '%s'. Tundub, et koodis on "
"viga, palun kontrolli süntaksi."
@@ -2895,6 +2901,10 @@ msgid "About"
msgstr "Teave"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Mängi projekti."
@@ -4058,7 +4068,7 @@ msgstr "Filtreeri atribuudid"
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
-msgstr ""
+msgstr "Muudatused võivad kaduma minna!"
#: editor/multi_node_edit.cpp
msgid "MultiNode Set"
@@ -9740,7 +9750,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11746,10 +11756,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/eu.po b/editor/translations/eu.po
index 421a255054..e21c8ce5ba 100644
--- a/editor/translations/eu.po
+++ b/editor/translations/eu.po
@@ -4,23 +4,25 @@
# This file is distributed under the same license as the Godot source code.
# Julen Irazoki <rktzbkr.julen@gmail.com>, 2019.
# Osoitz <oelkoro@gmail.com>, 2019, 2020.
+# Erik Zubiria <erik@ezsd.net>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
-"Last-Translator: Osoitz <oelkoro@gmail.com>\n"
+"PO-Revision-Date: 2021-06-14 12:34+0000\n"
+"Last-Translator: Erik Zubiria <erik@ezsd.net>\n"
"Language-Team: Basque <https://hosted.weblate.org/projects/godot-engine/"
"godot/eu/>\n"
"Language: eu\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
msgstr ""
+"'convert()'-entzat argumentu baliogabea, erabil itzazu TYPE_* konstanteak."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
@@ -34,23 +36,24 @@ msgstr "Ez daude byte nahikoa byteak deskodetzeko, edo formatua ez da zuzena."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
-msgstr ""
+msgstr "%i (onartu gabea) sarrera baliogabea espresioan"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
-msgstr ""
+msgstr "ezin da self erabili instantzia null (pasatu gabea) delako"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
-msgstr ""
+msgstr "%s, %s eta %s operatzaileentzat operando baliogabeak."
#: core/math/expression.cpp
msgid "Invalid index of type %s for base type %s"
-msgstr ""
+msgstr "%s tipo oinarriarentzat %s tipo adierazle baliogabea"
#: core/math/expression.cpp
msgid "Invalid named index '%s' for base type %s"
msgstr ""
+"'%s' izena daukan adierazleak ez dauka baliorik %s oinarri tipoarentzat"
#: core/math/expression.cpp
msgid "Invalid arguments to construct '%s'"
@@ -130,51 +133,51 @@ msgstr "Mugitu Bezier puntuak"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Duplicate Keys"
-msgstr ""
+msgstr "Animazio giltza bikoiztuak"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Delete Keys"
-msgstr ""
+msgstr "Animazio giltza ezabatuak"
#: editor/animation_track_editor.cpp
msgid "Anim Change Keyframe Time"
-msgstr ""
+msgstr "Animazioaren giltza fotogramaren denbora aldatu"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transition"
-msgstr ""
+msgstr "Animazioaren transizioa aldatu"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transform"
-msgstr ""
+msgstr "Animazioaren transformazioa aldatu"
#: editor/animation_track_editor.cpp
msgid "Anim Change Keyframe Value"
-msgstr ""
+msgstr "Animazioaren giltza fotogramen balioa aldatu"
#: editor/animation_track_editor.cpp
msgid "Anim Change Call"
-msgstr ""
+msgstr "Animazioaren deia aldatu"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Time"
-msgstr ""
+msgstr "Fotograma anitzen animazio giltzen denbora aldatu"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transition"
-msgstr ""
+msgstr "Animazio transizio anitzak aldatu"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transform"
-msgstr ""
+msgstr "Animazio Transform anitz aldatu"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Value"
-msgstr ""
+msgstr "Animazio anitzen giltza fotogramen balioa aldatu"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Call"
-msgstr ""
+msgstr "Animazio dei anitz aldatu"
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
@@ -187,27 +190,27 @@ msgstr "Aldatu animazioaren begizta"
#: editor/animation_track_editor.cpp
msgid "Property Track"
-msgstr ""
+msgstr "Propietateen pista"
#: editor/animation_track_editor.cpp
msgid "3D Transform Track"
-msgstr ""
+msgstr "3D Transformazioaren pista"
#: editor/animation_track_editor.cpp
msgid "Call Method Track"
-msgstr ""
+msgstr "Metodoen deiaren pista"
#: editor/animation_track_editor.cpp
msgid "Bezier Curve Track"
-msgstr ""
+msgstr "Bezier kurbaren pista"
#: editor/animation_track_editor.cpp
msgid "Audio Playback Track"
-msgstr ""
+msgstr "Audioaren erreprodukzio pista"
#: editor/animation_track_editor.cpp
msgid "Animation Playback Track"
-msgstr ""
+msgstr "Animazioaren erreprodukzio pista"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
@@ -219,40 +222,40 @@ msgstr "Animazioaren iraupena (segundoak)"
#: editor/animation_track_editor.cpp
msgid "Add Track"
-msgstr ""
+msgstr "Gehitu pista"
#: editor/animation_track_editor.cpp
msgid "Animation Looping"
-msgstr ""
+msgstr "Animazioaren loop-a"
#: editor/animation_track_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Functions:"
-msgstr ""
+msgstr "Funtzioak:"
#: editor/animation_track_editor.cpp
msgid "Audio Clips:"
-msgstr ""
+msgstr "Audio klipak:"
#: editor/animation_track_editor.cpp
msgid "Anim Clips:"
-msgstr ""
+msgstr "Animazio klipak:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
-msgstr ""
+msgstr "Pistaren bidea aldatu"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr ""
+msgstr "Pista hau aktibatu/desaktibatu."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
-msgstr ""
+msgstr "Eguneratze mota (Nola ezartzen da)"
#: editor/animation_track_editor.cpp
msgid "Interpolation Mode"
-msgstr ""
+msgstr "Interpolazio mota"
#: editor/animation_track_editor.cpp
msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
@@ -1088,6 +1091,10 @@ msgstr "Aldatu hiztegiaren balioa"
msgid "Thanks from the Godot community!"
msgstr "Eskerrik asko Godot komunitatearen partetik!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2449,8 +2456,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2855,6 +2863,10 @@ msgid "About"
msgstr "Honi buruz"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9706,7 +9718,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11712,10 +11724,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/fa.po b/editor/translations/fa.po
index 4a1906f4e3..ba8c4f9302 100644
--- a/editor/translations/fa.po
+++ b/editor/translations/fa.po
@@ -1126,6 +1126,10 @@ msgstr "تغییر مقدار دیکشنری"
msgid "Thanks from the Godot community!"
msgstr "با تشکر از سوی جامعه‌ی Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "شرکت‌کنندگان در ساخت موتور Godot"
@@ -2491,8 +2495,9 @@ msgstr "امکان بارگیری اسکریپت Ø§ÙØ²ÙˆÙ†Ù‡ از مسیر وج
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2906,6 +2911,10 @@ msgid "About"
msgstr "درباره"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "اجرای پروژه."
@@ -10172,7 +10181,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12327,10 +12336,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index dd1d5da4e8..4b7aad362e 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -16,8 +16,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-05 14:28+0000\n"
-"Last-Translator: Severi Vidnäs <severi.vidnas@gmail.com>\n"
+"PO-Revision-Date: 2021-05-19 20:16+0000\n"
+"Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n"
"Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/"
"godot/fi/>\n"
"Language: fi\n"
@@ -25,7 +25,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1118,6 +1118,10 @@ msgstr "Vaihda hakurakenteen arvoa"
msgid "Thanks from the Godot community!"
msgstr "Kiitos Godot-yhteisöltä!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot moottorin kehittäjät"
@@ -2540,11 +2544,13 @@ msgstr "Virhe ladattaessa lisäosaa polusta: '%s'."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"Virhe ladattaessa lisäosaa polusta: '%s'. Koodissa vaikuttaa olevan virhe, "
-"ole hyvä ja tarkista syntaksi."
+"Lisäosaskriptin lataus ei onnistunut polusta: '%s'. Tämä saattaa johtua "
+"koodivirheestä skriptissä.\n"
+"Lisäosa '%s' poistetaan käytöstä tulevien virheiden estämiseksi."
#: editor/editor_node.cpp
msgid ""
@@ -2983,6 +2989,10 @@ msgid "About"
msgstr "Tietoja"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Tue Godotin kehitystä"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Käynnistä projekti."
@@ -7545,6 +7555,8 @@ msgstr "Näkymän kierto lukittu"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Lähentääksesi tai loitontaaksesi enemmän, muuta kameran leikkaustasoja "
+"(Näytä -> Asetukset...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -10120,7 +10132,7 @@ msgstr "Hiiren painike"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Virheellinen toiminnon nimi. Se ei voi olla tyhjä eikä voi sisältää merkkejä "
@@ -10935,6 +10947,9 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"Jos tämä on valittuna, etäskenepuun telakka saa projektin nykimään aina "
+"päivittyessään.\n"
+"Vaihda takaisin paikallisen skenepuun telakkaan parantaaksesi suorituskykyä."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12185,11 +12200,23 @@ msgstr ""
"valikosta."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Debug keystore ei ole määritettynä editorin asetuksissa eikä esiasetuksissa."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr "Release keystore on konfiguroitu väärin viennin esiasetuksissa."
@@ -13157,6 +13184,19 @@ msgid "Constants cannot be modified."
msgstr "Vakioita ei voi muokata."
#~ msgid ""
+#~ "Godot editor was built without ray tracing support; lightmaps can't be "
+#~ "baked.\n"
+#~ "If you are using an Apple Silicon-based Mac, try forcing Rosetta "
+#~ "emulation on Godot.app in the application settings\n"
+#~ "then restart the editor."
+#~ msgstr ""
+#~ "Godot-editori on käännetty ilman ray tracing -tukea, joten lightmappeja "
+#~ "ei voi kehittää.\n"
+#~ "Jos käytät Apple Silicon -pohjaista Mac-tietokonetta, yritä pakottaa "
+#~ "Rosetta-emulaatio Godot.app:iin sovelluksen asetuksissa\n"
+#~ "ja käynnistä sitten editori uudestaan."
+
+#~ msgid ""
#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
#~ msgstr ""
#~ "InterpolatedCamera on vanhentunut ja poistetaan Godot 4.0 versiossa."
diff --git a/editor/translations/fil.po b/editor/translations/fil.po
index 99964e6ee8..54df144dd9 100644
--- a/editor/translations/fil.po
+++ b/editor/translations/fil.po
@@ -6,11 +6,12 @@
# Amado Wilkins <epicalert68@gmail.com>, 2019.
# Bakainkorp <Ryan.Bautista86@myhunter.cuny.edu>, 2019.
# Jethro Parker <lionbearjet@hotmail.com>, 2020.
+# Sven Sorupia <stsorupia@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2020-08-14 03:56+0000\n"
-"Last-Translator: Jethro Parker <lionbearjet@hotmail.com>\n"
+"PO-Revision-Date: 2021-06-07 23:43+0000\n"
+"Last-Translator: Sven Sorupia <stsorupia@gmail.com>\n"
"Language-Team: Filipino <https://hosted.weblate.org/projects/godot-engine/"
"godot/fil/>\n"
"Language: fil\n"
@@ -18,7 +19,7 @@ msgstr ""
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1 && n != 2 && n != 3 && (n % 10 == 4 "
"|| n % 10 == 6 || n % 10 == 9);\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -29,7 +30,7 @@ msgstr ""
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "Nanghihingi ng string na may habang 1 (character)."
+msgstr "Inasahan na ang haba ng string ay 1 (isang character)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -98,7 +99,7 @@ msgstr "EiB"
#: editor/animation_bezier_editor.cpp
msgid "Free"
-msgstr "Malaya"
+msgstr "Libre"
#: editor/animation_bezier_editor.cpp
msgid "Balanced"
@@ -138,64 +139,64 @@ msgstr "Maglipat ng (mga) Bezier Point"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Duplicate Keys"
-msgstr "I-anim ang (mga) Duplicate Key"
+msgstr "Pagduplika ng mga Animation Keys"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Delete Keys"
-msgstr "I-anim ang (mga) Delete Key"
+msgstr "Pagbura ng mga Animation Key"
#: editor/animation_track_editor.cpp
msgid "Anim Change Keyframe Time"
-msgstr "I-anim ang Oras ng Pagbago ng Keyframe"
+msgstr "Pagbago ng Keyframe Time ng Animation"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transition"
-msgstr "I-anim ang Transition ng Pagbago"
+msgstr "Pagbago ng Transition ng Animation"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transform"
-msgstr "I-anim ang Pagbabago sa Transform"
+msgstr "Pagbago ng Transform ng Animation"
#: editor/animation_track_editor.cpp
msgid "Anim Change Keyframe Value"
-msgstr "I-anim ang Halaga ng Keyframe na Binago"
+msgstr "Pagbago ng Nilalaman ng Keyframe ng Animation"
#: editor/animation_track_editor.cpp
msgid "Anim Change Call"
-msgstr ""
+msgstr "Pagbago ng Pagtawag sa Animation"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Time"
-msgstr ""
+msgstr "Pagbago ng Time ng Maraming Keyframe ng Animation"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transition"
-msgstr ""
+msgstr "Pagbago ng Maraming Transition ng Animation"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transform"
-msgstr ""
+msgstr "Pagbago ng Maraming Transform ng Animation"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Value"
-msgstr ""
+msgstr "Pagbago ng Nilalaman ng Maraming Keyframe ng Animation"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Call"
-msgstr ""
+msgstr "Pagbago ng Maraming Pagtawag ng Animation"
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
-msgstr "Ibahin ang haba ng Animation"
+msgstr "Pagbago ng Haba ng Animation"
#: editor/animation_track_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation Loop"
-msgstr "Ibahin ang ulit ng Animation"
+msgstr "Pagbago ng Animation Loop"
#: editor/animation_track_editor.cpp
msgid "Property Track"
-msgstr ""
+msgstr "Property Track"
#: editor/animation_track_editor.cpp
msgid "3D Transform Track"
@@ -236,7 +237,7 @@ msgstr "Pagulit ng Animation"
#: editor/animation_track_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Functions:"
-msgstr "Functions:"
+msgstr "Mga Functions:"
#: editor/animation_track_editor.cpp
msgid "Audio Clips:"
@@ -326,7 +327,7 @@ msgstr "Kopyahin Ang (Mga) Key(s)"
#: editor/animation_track_editor.cpp
msgid "Delete Key(s)"
-msgstr ""
+msgstr "Tanggalin Ang (Mga) Key(s)"
#: editor/animation_track_editor.cpp
msgid "Change Animation Update Mode"
@@ -575,11 +576,11 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Pick the node that will be animated:"
-msgstr ""
+msgstr "Piliin ang node na i-aanimate:"
#: editor/animation_track_editor.cpp
msgid "Use Bezier Curves"
-msgstr ""
+msgstr "Gumamit ng Bezier Curves"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -611,11 +612,11 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Clean-up all animations"
-msgstr ""
+msgstr "Linisin ang lahat ng mga animation"
#: editor/animation_track_editor.cpp
msgid "Clean-Up Animation(s) (NO UNDO!)"
-msgstr ""
+msgstr "Linisin ang (mga) Animation (HINDI MAIBABALIK!)"
#: editor/animation_track_editor.cpp
msgid "Clean-Up"
@@ -627,7 +628,7 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Select Tracks to Copy"
-msgstr ""
+msgstr "Piliin ang mga Tracks na Kokopyahin"
#: editor/animation_track_editor.cpp editor/editor_log.cpp
#: editor/editor_properties.cpp
@@ -656,15 +657,15 @@ msgstr ""
#: editor/array_property_edit.cpp
msgid "Resize Array"
-msgstr ""
+msgstr "Baguhin ang Laki ng Array"
#: editor/array_property_edit.cpp
msgid "Change Array Value Type"
-msgstr ""
+msgstr "Baguhin ang Type ng Nilalaman ng Array"
#: editor/array_property_edit.cpp
msgid "Change Array Value"
-msgstr ""
+msgstr "Baguhin ang Nilalaman ng Array"
#: editor/code_editor.cpp
msgid "Go to Line"
@@ -675,17 +676,16 @@ msgid "Line Number:"
msgstr ""
#: editor/code_editor.cpp
-#, fuzzy
msgid "%d replaced."
-msgstr "Palitan"
+msgstr "%d ay pinalitan."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
-msgstr ""
+msgstr "%d magkatugma."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d matches."
-msgstr ""
+msgstr "%d magkatugma."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
@@ -1090,6 +1090,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2449,8 +2453,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2855,6 +2860,10 @@ msgid "About"
msgstr "Tungkol"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9699,7 +9708,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11707,10 +11716,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/fr.po b/editor/translations/fr.po
index 1ce05a4b93..577c44aff0 100644
--- a/editor/translations/fr.po
+++ b/editor/translations/fr.po
@@ -78,12 +78,14 @@
# Joseph Boudou <joseph.boudou@matabio.net>, 2020.
# Vincent Foulon <vincent.foulon80@gmail.com>, 2020.
# TechnoPorg <jonah.janzen@gmail.com>, 2021.
+# ASTRALE <jules.cercy@etu.univ-lyon1.fr>, 2021.
+# Julien Vanelian <julienvanelian@hotmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-21 12:25+0000\n"
-"Last-Translator: Pierre Caye <pierrecaye@laposte.net>\n"
+"PO-Revision-Date: 2021-04-30 23:03+0000\n"
+"Last-Translator: Julien Vanelian <julienvanelian@hotmail.com>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
"godot/fr/>\n"
"Language: fr\n"
@@ -91,7 +93,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.5.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -107,7 +109,7 @@ msgstr "Une chaîne de caractères de longueur 1 est attendue (un caractère)."
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
-msgstr "Pas assez d’octets pour le décodage, ou format non valide."
+msgstr "Pas assez d’octets pour le décodage, ou format invalide."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
@@ -1199,6 +1201,10 @@ msgstr "Modifier valeur du dictionnaire"
msgid "Thanks from the Godot community!"
msgstr "La communauté Godot vous dit merci !"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Contributeurs de Godot Engine"
@@ -1244,7 +1250,7 @@ msgstr "Sponsors Bronze"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
-msgstr "Mini Sponsors"
+msgstr "Petits Sponsors"
#: editor/editor_about.cpp
msgid "Gold Donors"
@@ -2633,11 +2639,13 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"Impossible de charger le script de l’extension depuis le chemin : « %s ». Il "
-"semble y avoir une erreur dans le code, merci de vérifier la syntaxe."
+"Impossible de charger le script de l’extension depuis le chemin : « %s ». "
+"Cela peut être dû à une erreur de programmation dans ce script.\n"
+"L'extension « %s » a été désactivée pour prévenir de nouvelles erreures."
#: editor/editor_node.cpp
msgid ""
@@ -3088,6 +3096,10 @@ msgid "About"
msgstr "À propos"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Soutenir le développement de Godot"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Lancer le projet."
@@ -3194,7 +3206,7 @@ msgstr ""
"personnalisé à l'exportation (ajout de modules, modification du fichier "
"AndroidManifest.xml, etc.).\n"
"Notez que pour faire des compilations personnalisées au lieu d'utiliser des "
-"APKs pré-construits, l'option \"Use Custom Build\" doit être activée dans le "
+"APKs préconstruits, l'option \"Use Custom Build\" doit être activée dans le "
"Preset d'exportation Android."
#: editor/editor_node.cpp
@@ -5337,7 +5349,7 @@ msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
"L'éditeur Godot a été compilé sans support du ray tracing, les lightmaps ne "
-"peuvent pas être pré-calculées."
+"peuvent pas être précalculées."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
@@ -5345,7 +5357,7 @@ msgstr "Précalculer les lightmaps"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Select lightmap bake file:"
-msgstr "Sélectionnez le fichier de pré-calcul de lightmap :"
+msgstr "Sélectionnez le fichier de précalcul de lightmap :"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6315,7 +6327,7 @@ msgstr ""
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Mesh Library"
-msgstr "Mesh Library"
+msgstr "Librairie de maillages"
#: editor/plugins/mesh_library_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
@@ -7392,7 +7404,7 @@ msgstr ""
#: editor/plugins/shader_editor_plugin.cpp
msgid "Shader"
-msgstr "Shader"
+msgstr "Ombrage"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "This skeleton has no bones, create some children Bone2D nodes."
@@ -7680,6 +7692,8 @@ msgstr "Rotation de la vue verrouillée"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Pour zoomer d'avantage, modifiez les plans de détourage de la caméra "
+"(Affichage -> Paramètres...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -10275,7 +10289,7 @@ msgstr "Bouton de souris"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Nom d'action invalide. Il ne peut être vide ni contenir « / », « : », « = », "
@@ -11088,6 +11102,10 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"S'il est sélectionné, le dock de l'arborescence de la scène distante sera "
+"instable à chaque mise à jour de celui-ci.\n"
+"Revenez au dock de l'arborescence de la scène locale afin d'améliorer les "
+"performances."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -11789,7 +11807,7 @@ msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Begin Bake"
-msgstr "Commencer le pré-calcul"
+msgstr "Commencer le précalcul"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Preparing data structures"
@@ -12348,12 +12366,24 @@ msgstr ""
"Installez-le à partir du menu Projet."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Le Debug keystore n'est pas configuré dans les Paramètres de l'éditeur, ni "
"dans le préréglage."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"La clé de version n'est pas configurée correctement dans le préréglage "
diff --git a/editor/translations/ga.po b/editor/translations/ga.po
index 8a6c2a3f0b..e3b1137cee 100644
--- a/editor/translations/ga.po
+++ b/editor/translations/ga.po
@@ -1083,6 +1083,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2444,8 +2448,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2850,6 +2855,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9694,7 +9703,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11702,10 +11711,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/gl.po b/editor/translations/gl.po
index 771b0f07e6..f6905f4bef 100644
--- a/editor/translations/gl.po
+++ b/editor/translations/gl.po
@@ -5,18 +5,19 @@
#
# Andy Barcia <andybarcia4@gmail.com>, 2021.
# PokeGalaico <abloodyfreaks@gmail.com>, 2021.
+# Kkai <kaieltroll@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2021-02-15 10:51+0000\n"
-"Last-Translator: Andy Barcia <andybarcia4@gmail.com>\n"
+"PO-Revision-Date: 2021-04-26 22:32+0000\n"
+"Last-Translator: Kkai <kaieltroll@gmail.com>\n"
"Language-Team: Galician <https://hosted.weblate.org/projects/godot-engine/"
"godot/gl/>\n"
"Language: gl\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -36,7 +37,7 @@ msgstr ""
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
-msgstr "Entrada inválida %i (non recibida) na expresión"
+msgstr "Entrada inválida %i (non pasada) na expresión"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
@@ -659,11 +660,11 @@ msgstr "Engadir Clip de Pista de Audio"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
-msgstr "Cambiar Inicio do Clip na Pista de Audio"
+msgstr "Cambiar Offset de Inicio de Clip de Pista de Audio"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr "Cambiar Final do Clip na Pista de Audio"
+msgstr "Cambiar Offset Final del Clip de Pista de Audio"
#: editor/array_property_edit.cpp
msgid "Resize Array"
@@ -1116,6 +1117,10 @@ msgstr "Cambiar Valor do Dicionario"
msgid "Thanks from the Godot community!"
msgstr "Moitas grazas de parte da comunidade de Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Colaboradores de Godot Engine"
@@ -1278,7 +1283,7 @@ msgstr "Act./Desact. Silencio do Bus de Son"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Bypass Effects"
-msgstr ""
+msgstr "Act./Desact. Bypass de Efectos do Bus de Son"
#: editor/editor_audio_buses.cpp
msgid "Select Audio Bus Send"
@@ -1310,7 +1315,7 @@ msgstr "Silenciar"
#: editor/editor_audio_buses.cpp
msgid "Bypass"
-msgstr ""
+msgstr "Bypass"
#: editor/editor_audio_buses.cpp
msgid "Bus options"
@@ -1445,11 +1450,11 @@ msgstr "Non debe coincidir co nome dunha constante global xa existente."
#: editor/editor_autoload_settings.cpp
msgid "Keyword cannot be used as an autoload name."
-msgstr "Unha palabra clave non pode usarse como nome dun AutoCargador."
+msgstr "A palabra clave non pode empregarse como nome dun AutoCargador."
#: editor/editor_autoload_settings.cpp
msgid "Autoload '%s' already exists!"
-msgstr "Xa existe un AutoCargador nomeado '%s'!"
+msgstr "AutoCargador '%s' xa existe!"
#: editor/editor_autoload_settings.cpp
msgid "Rename Autoload"
@@ -1457,7 +1462,7 @@ msgstr "Renomear AutoCargador"
#: editor/editor_autoload_settings.cpp
msgid "Toggle AutoLoad Globals"
-msgstr ""
+msgstr "Act./Desact. Globais de AutoCargador"
#: editor/editor_autoload_settings.cpp
msgid "Move Autoload"
@@ -1502,7 +1507,7 @@ msgstr "Nome"
#: editor/editor_autoload_settings.cpp
msgid "Singleton"
-msgstr ""
+msgstr "Singleton"
#: editor/editor_data.cpp editor/inspector_dock.cpp
msgid "Paste Params"
@@ -1560,7 +1565,7 @@ msgstr "Elixir"
#: editor/editor_export.cpp
msgid "Storing File:"
-msgstr "Gardando Arquivo:"
+msgstr "Almacenando Arquivo:"
#: editor/editor_export.cpp
msgid "No export template found at the expected path:"
@@ -1637,7 +1642,7 @@ msgstr "Non se encontrou un modelo de depuración personalizado."
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
msgid "Custom release template not found."
-msgstr ""
+msgstr "Non se encontrou un modelo release personalizado."
#: editor/editor_export.cpp platform/javascript/export/export.cpp
msgid "Template file not found:"
@@ -1665,15 +1670,15 @@ msgstr "Edición de Ãrbore de Escenas"
#: editor/editor_feature_profile.cpp
msgid "Node Dock"
-msgstr "Panel de Nodos"
+msgstr "Nodos"
#: editor/editor_feature_profile.cpp
msgid "FileSystem Dock"
-msgstr "Panel de Sistema de Arquivos"
+msgstr "Sistema de Arquivos"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
-msgstr "Panel de Importación"
+msgstr "Importación"
#: editor/editor_feature_profile.cpp
msgid "Erase profile '%s'? (no undo)"
@@ -1732,11 +1737,11 @@ msgstr ""
#: editor/editor_feature_profile.cpp
msgid "Error saving profile to path: '%s'."
-msgstr "Erro gardando o perfil á ruta: '%s'."
+msgstr "Erro ao gardar o perfil na ruta: '%s'."
#: editor/editor_feature_profile.cpp
msgid "Unset"
-msgstr ""
+msgstr "Desactivar"
#: editor/editor_feature_profile.cpp
msgid "Current Profile:"
@@ -1755,7 +1760,7 @@ msgstr "Novo"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Importación"
+msgstr "Importar"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -1763,15 +1768,15 @@ msgstr "Exportación"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
-msgstr "Perfils Dispoñibles:"
+msgstr "Perfís Dispoñibles:"
#: editor/editor_feature_profile.cpp
msgid "Class Options"
-msgstr "Opcións de Clase"
+msgstr "Opcións de Clases"
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
-msgstr "Nome do novo perfil:"
+msgstr "Novo nome de perfil:"
#: editor/editor_feature_profile.cpp
msgid "Erase Profile"
@@ -1783,7 +1788,7 @@ msgstr "Perfil de Características de Godot"
#: editor/editor_feature_profile.cpp
msgid "Import Profile(s)"
-msgstr "Importar Perfil(s)"
+msgstr "Importar Perf(il/ís)"
#: editor/editor_feature_profile.cpp
msgid "Export Profile"
@@ -1875,7 +1880,6 @@ msgid "Go Up"
msgstr "Subir"
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Toggle Hidden Files"
msgstr "Amosar/Ocultar Arquivos Ocultos"
@@ -2001,7 +2005,6 @@ msgid "Methods"
msgstr "Métodos"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Theme Properties"
msgstr "Propiedades do Tema"
@@ -2287,19 +2290,19 @@ msgstr "Non se pode sobreescribir escena que sigue aberta!"
#: editor/editor_node.cpp
msgid "Can't load MeshLibrary for merging!"
-msgstr ""
+msgstr "Non se pode cargar MeshLibrary para fusionarse!"
#: editor/editor_node.cpp
msgid "Error saving MeshLibrary!"
-msgstr ""
+msgstr "Erro ao gardar MeshLibrary!"
#: editor/editor_node.cpp
msgid "Can't load TileSet for merging!"
-msgstr ""
+msgstr "Non se pode cargar TileSet para fusionarse!"
#: editor/editor_node.cpp
msgid "Error saving TileSet!"
-msgstr ""
+msgstr "Erro ao gardar TileSet!"
#: editor/editor_node.cpp
msgid ""
@@ -2531,11 +2534,10 @@ msgstr ""
"sintáctica da configuración de '%s'."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"Non se puido encontrar o campo do Script na característica adicional "
-"(Plugin) en 'res://addons/%s'."
+"(Plugin) en '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2543,9 +2545,11 @@ msgstr ""
"Non se puido cargar Script de característica adicional (Addon) na ruta: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Non se puido cargar Script de característica adicional (Addon) na ruta: "
"'%s'. Parece que hai un erro no código; por favor, comproba a sintaxe."
@@ -2797,7 +2801,7 @@ msgstr "Exportar..."
#: editor/editor_node.cpp
msgid "Install Android Build Template..."
-msgstr ""
+msgstr "Instalar plantilla de compilación de Android..."
#: editor/editor_node.cpp
msgid "Open Project Data Folder"
@@ -2993,6 +2997,10 @@ msgid "About"
msgstr "Acerca De"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Reproduce o proxecto."
@@ -4055,9 +4063,8 @@ msgid "Select Importer"
msgstr "Elixir Modo"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importación"
+msgstr "Importador:"
#: editor/import_defaults_editor.cpp
#, fuzzy
@@ -9915,11 +9922,8 @@ msgid "Projects"
msgstr "Proxectos"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Loading, please wait..."
-msgstr ""
-"Examinando arquivos,\n"
-"Por favor, espere..."
+msgstr "Cargando, por favor agarde..."
#: editor/project_manager.cpp
msgid "Last Modified"
@@ -9990,7 +9994,7 @@ msgstr "Botón do Rato"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Nome de acción inválido. O nome non pode estar baleiro, nin conter '/', ':', "
@@ -12000,12 +12004,24 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Non está configurado o Keystore de depuración nin na configuración do "
"editor, nin nos axustes de exportación."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"O Keystore Release non está configurado correctamente nos axustes de "
diff --git a/editor/translations/he.po b/editor/translations/he.po
index 2966711057..f0e3fa4383 100644
--- a/editor/translations/he.po
+++ b/editor/translations/he.po
@@ -19,12 +19,13 @@
# Guy Dadon <guydadon14@gmail.com>, 2020.
# bruvzg <bruvzg13@gmail.com>, 2020.
# Omer I.S. <omeritzicschwartz@gmail.com>, 2021.
+# Ram Tourgeman <ramtorgeman@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-11 22:02+0000\n"
-"Last-Translator: Omer I.S. <omeritzicschwartz@gmail.com>\n"
+"PO-Revision-Date: 2021-05-14 11:20+0000\n"
+"Last-Translator: Ram Tourgeman <ramtorgeman@gmail.com>\n"
"Language-Team: Hebrew <https://hosted.weblate.org/projects/godot-engine/"
"godot/he/>\n"
"Language: he\n"
@@ -33,7 +34,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && "
"n % 10 == 0) ? 2 : 3));\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -212,9 +213,8 @@ msgid "3D Transform Track"
msgstr "רצועת שינוי 3D"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Call Method Track"
-msgstr "רצועת שיטה"
+msgstr "רצועת קרי×ת פונקציה"
#: editor/animation_track_editor.cpp
msgid "Bezier Curve Track"
@@ -462,7 +462,7 @@ msgstr "הוספת רצועות חדשות."
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a method key."
-msgstr ""
+msgstr "הנתיב לרצועה ×ינו תקין, ולכן מפתח לשיטה (מתודה) ×œ× ×™×›×œ להתווסף"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -475,7 +475,7 @@ msgstr "×œ× × ×ž×¦××” מתודה בעצ×: "
#: editor/animation_track_editor.cpp
msgid "Anim Move Keys"
-msgstr ""
+msgstr "מפתחות הזזת ×נימצייה"
#: editor/animation_track_editor.cpp
msgid "Clipboard is empty"
@@ -487,7 +487,7 @@ msgstr "הדבקת רצועות"
#: editor/animation_track_editor.cpp
msgid "Anim Scale Keys"
-msgstr ""
+msgstr "הנפשה - שנה גודל של רצועות מפתח"
#: editor/animation_track_editor.cpp
msgid ""
@@ -883,11 +883,11 @@ msgstr "ניתוק '%s' מ-'%s'"
#: editor/connections_dialog.cpp
msgid "Disconnect all from signal: '%s'"
-msgstr ""
+msgstr "נתק הכל מה×ות '%s'"
#: editor/connections_dialog.cpp
msgid "Connect..."
-msgstr ""
+msgstr "התחבר..."
#: editor/connections_dialog.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -905,7 +905,7 @@ msgstr "עריכת חיבור:"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
-msgstr ""
+msgstr "×”×× ×תה בטוח ש×תה רוצה להסיר ×ת כל ×”×—×™×‘×•×¨×™× ×ž×”×ות \"%s\"?"
#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
msgid "Signals"
@@ -918,7 +918,7 @@ msgstr "מ×פייני פריט."
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
-msgstr ""
+msgstr "×”×× ×תה בטוח ש×תה רוצה להסיר ×ת כל ×”×—×™×‘×•×¨×™× ×ž×”×ות ×”×–×”?"
#: editor/connections_dialog.cpp
#, fuzzy
@@ -935,7 +935,7 @@ msgstr "מעבר למתודה"
#: editor/create_dialog.cpp
msgid "Change %s Type"
-msgstr ""
+msgstr "שנה ×ת הסוג של s%"
#: editor/create_dialog.cpp editor/project_settings_editor.cpp
msgid "Change"
@@ -987,12 +987,16 @@ msgid ""
"Scene '%s' is currently being edited.\n"
"Changes will only take effect when reloaded."
msgstr ""
+"סצנה 's%' נמצ×ת כרגע בעריכה.\n"
+"×©×™× ×•×™×™× ×™×›× ×¡×• לתוקף בטעינה מחדש."
#: editor/dependency_editor.cpp
msgid ""
"Resource '%s' is in use.\n"
"Changes will only take effect when reloaded."
msgstr ""
+"מש×ב 's%' × ×ž×¦× ×‘×©×™×ž×•×©.\n"
+"×©×™× ×•×™×™× ×™×›× ×¡×• לתוקף רק בטעינה מחדש."
#: editor/dependency_editor.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -1036,7 +1040,7 @@ msgstr "פתיחה"
#: editor/dependency_editor.cpp
msgid "Owners Of:"
-msgstr ""
+msgstr "×‘×¢×œ×™× ×©×œ:"
#: editor/dependency_editor.cpp
#, fuzzy
@@ -1105,7 +1109,7 @@ msgstr "מחיקה"
#: editor/dependency_editor.cpp
msgid "Owns"
-msgstr ""
+msgstr "בעליו של"
#: editor/dependency_editor.cpp
msgid "Resources Without Explicit Ownership:"
@@ -1123,6 +1127,10 @@ msgstr "החלפת ערך מילון"
msgid "Thanks from the Godot community!"
msgstr "תודה רבה מקהילת Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "מתנדבי מנוע גודו"
@@ -2537,9 +2545,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "×œ× × ×™×ª×Ÿ לטעון סקריפט הרחבה מנתיב: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"×œ× × ×™×ª×Ÿ לטעון סקריפט הרחבה מנתיב: '%s' נר××” שיש שגי××” בקוד, ×× × ×‘×“×•×§ ×ת "
"התחביר."
@@ -2974,6 +2984,10 @@ msgid "About"
msgstr "על ×ודות"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "הרצת המיז×."
@@ -6334,9 +6348,8 @@ msgid "Convert to CPUParticles"
msgstr "המרה ל×ותיות גדולות"
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Generating Visibility Rect"
-msgstr "נוצר ×ž×™×–× C#‎…"
+msgstr "חולל נר×ות ריבוע"
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Generate Visibility Rect"
@@ -10158,7 +10171,7 @@ msgstr "כפתור עכבר"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12219,10 +12232,22 @@ msgid ""
msgstr "תבנית בנייה ל×נדרו×יד ×œ× ×ž×•×ª×§× ×ª בפרוייקט. ההתקנה ×”×™× ×ž×ª×¤×¨×™×˜ המיז×."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr "מפתח לניפוי שגי×ות ×œ× × ×§×‘×¢ בהגדרות העורך ×•×œ× ×‘×”×’×“×¨×•×ª הייצו×."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr "מפתח גירסת שיחרור נקבע ב×ופן שגוי בהגדרות הייצו×."
diff --git a/editor/translations/hi.po b/editor/translations/hi.po
index 6c465ad015..a70f058a65 100644
--- a/editor/translations/hi.po
+++ b/editor/translations/hi.po
@@ -13,12 +13,13 @@
# Abhay Patel <Traumaticbean@protonmail.com>, 2020.
# Bishwajeet Parhi <bishwajeet.techmaster@gmail.com>, 2020.
# l4KKY <greenforcesave@gmail.com>, 2020.
+# harvinder rathor <harvinderr09@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-06 18:29+0000\n"
-"Last-Translator: Shirious <sad3119823@gmail.com>\n"
+"PO-Revision-Date: 2021-05-03 21:29+0000\n"
+"Last-Translator: harvinder rathor <harvinderr09@gmail.com>\n"
"Language-Team: Hindi <https://hosted.weblate.org/projects/godot-engine/godot/"
"hi/>\n"
"Language: hi\n"
@@ -26,7 +27,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.4.1-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -759,9 +760,8 @@ msgid "Method in target node must be specified."
msgstr "Method को target node में निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ कीजिà¤."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Method name must be a valid identifier."
-msgstr "Method को target node में निरà¥à¤¦à¤¿à¤·à¥à¤Ÿ कीजिà¤."
+msgstr "विधि नाम à¤à¤• मानà¥à¤¯ पहचानकरà¥à¤¤à¤¾ होना चाहिà¤à¥¤"
#: editor/connections_dialog.cpp
msgid ""
@@ -901,9 +901,8 @@ msgid "Signals"
msgstr "संकेत"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Filter signals"
-msgstr "फ़िलà¥à¤Ÿà¤° फ़ाइलें..."
+msgstr "सà¥à¤•à¥à¤°à¥€à¤¨à¤¿à¤‚ग सिगà¥à¤¨à¤²"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
@@ -1031,22 +1030,23 @@ msgid "Owners Of:"
msgstr "के सà¥à¤µà¤¾à¤®à¥€:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
-msgstr "परियोजना से चयनित फ़ाइलों को हटा दें? (बहाल नहीं किया जा सकता है)"
+msgstr ""
+"कà¥à¤¯à¤¾ आप पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ से चयनित फ़ाइल को हटाना चाहते हैं? (पूरà¥à¤µà¤µà¤¤ नहीं किया जा सकता है)\n"
+"आप सिसà¥à¤Ÿà¤® रीसायकल बिन में हटाई गई फ़ाइलों को पà¥à¤¨à¤°à¥à¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ कर सकते हैं।"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
"Remove them anyway? (no undo)\n"
"You can find the removed files in the system trash to restore them."
msgstr ""
-"निकाली गई फ़ाइलों को दूसरे संसाधनों दà¥à¤µà¤¾à¤°à¤¾ उनके लिठकाम करने के लिठआवशà¥à¤¯à¤• है\n"
-"वैसे भी उनà¥à¤¹à¥‡à¤‚ निकालें? (कोई पूरà¥à¤µà¤µà¤¤ नहीं)"
+"हटाई जाने वाली फ़ाइल अनà¥à¤¯ संसाधनों पर निरà¥à¤­à¤° है।\n"
+"कà¥à¤¯à¤¾ आप अभी भी हटाना चाहते हैं? (पूरà¥à¤µà¤µà¤¤ नहीं किया जा सकता है)\n"
+"आप सिसà¥à¤Ÿà¤® रीसायकल बिन में हटाई गई फ़ाइलों को पà¥à¤¨à¤°à¥à¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ कर सकते हैं।"
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1116,6 +1116,10 @@ msgstr "शबà¥à¤¦ बदलें मूलà¥à¤¯"
msgid "Thanks from the Godot community!"
msgstr "गोडोट समà¥à¤¦à¤¾à¤¯ से आपको धनà¥à¤¯à¤µà¤¾à¤¦!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "गॉडोट इंजन योगदानकरà¥à¤¤à¤¾"
@@ -1156,9 +1160,8 @@ msgid "Silver Sponsors"
msgstr "रजत पà¥à¤°à¤¾à¤¯à¥‹à¤œà¤•"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Bronze Sponsors"
-msgstr "कांसà¥à¤¯ दाताओं"
+msgstr "कांसà¥à¤¯ पà¥à¤°à¤¾à¤¯à¥‹à¤œà¤•"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
@@ -1598,34 +1601,31 @@ msgstr ""
"निषà¥à¤•à¥à¤°à¤¿à¤¯ करे."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"GLES2 के लिये टारà¥à¤—ेट पà¥à¤²à¥à¤Ÿà¥ˆà¥žà¥‹à¤°à¥à¤® को 'ETC' टेâ€à¤•à¥à¤¸à¤šà¤° कोमà¥à¤ªà¥à¤°à¥‡à¤¶à¤¨ की आवशà¥à¤¯à¤•ता है. 'Import Etc' "
-"को पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ सेटिनà¥à¤—स मे सकà¥à¤°à¤¿à¤¯ करे."
+"लकà¥à¤·à¥à¤¯ मंच को GLES2 के \"PVRTC\" बनावट संपीड़न की आवशà¥à¤¯à¤•ता है। पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ सेटिंगà¥à¤¸ में \"आयात "
+"Pvrtc\" सकà¥à¤·à¤® करें।"
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
-"GLES3 के लिये टारà¥à¤—ेट पà¥à¤²à¥à¤Ÿà¥ˆà¥žà¥‹à¤°à¥à¤® को 'ETC2' टेâ€à¤•à¥à¤¸à¤šà¤° कोमà¥à¤ªà¥à¤°à¥‡à¤¶à¤¨ की आवशà¥à¤¯à¤•ता है. 'Import Etc "
-"2' को पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ सेटिनà¥à¤—स मे सकà¥à¤°à¤¿à¤¯ करे."
+"लकà¥à¤·à¥à¤¯ मंच को GLES2 के \"PVRTC\" बनावट संपीड़न की आवशà¥à¤¯à¤•ता है। पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ सेटिंगà¥à¤¸ में \"आयात "
+"Pvrtc\" सकà¥à¤·à¤® करें।"
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for the driver fallback "
"to GLES2.\n"
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
-"GLES2 के लिये टारà¥à¤—ेट पà¥à¤²à¥à¤Ÿà¥ˆà¥žà¥‹à¤°à¥à¤® को 'ETC' टेâ€à¤•à¥à¤¸à¤šà¤° कोमà¥à¤ªà¥à¤°à¥‡à¤¶à¤¨ की आवशà¥à¤¯à¤•ता है. \n"
-"'Import Etc' को पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ सेटिनà¥à¤—स मे सकà¥à¤°à¤¿à¤¯ करे, या 'Driver Fallback Enabled' को "
-"निषà¥à¤•à¥à¤°à¤¿à¤¯ करे."
+"डà¥à¤°à¤¾à¤‡à¤µà¤° के लिठGLES2 पर वापस आने के लिठलकà¥à¤·à¥à¤¯ पà¥à¤²à¥‡à¤Ÿà¤«à¤¼à¥‰à¤°à¥à¤® को \"PVRTC\" बनावट संपीड़न की "
+"आवशà¥à¤¯à¤•ता होती है।\n"
+"पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ सेटिंगà¥à¤¸ में \"आयात Pvrtc\" सकà¥à¤·à¤® करें, या \"डà¥à¤°à¤¾à¤‡à¤µà¤° फ़ॉलबैक सकà¥à¤·à¤®\" अकà¥à¤·à¤® करें।"
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -1668,9 +1668,8 @@ msgid "Node Dock"
msgstr "नोड डॉक"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "फ़ाइल"
+msgstr "फाइल सिसà¥à¤Ÿà¤® पैनल"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
@@ -1755,7 +1754,7 @@ msgstr "नई"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "इंपोरà¥à¤Ÿ"
+msgstr "आयात"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -1986,7 +1985,7 @@ msgstr "ऑनलाइन टà¥à¤¯à¥‚टोरियल"
#: editor/editor_help.cpp
msgid "Properties"
-msgstr "पà¥à¤°à¥‹à¤ªà¤°à¤Ÿà¤¿à¤œ"
+msgstr "विशेषता"
#: editor/editor_help.cpp
msgid "override:"
@@ -1998,15 +1997,15 @@ msgstr "पà¥à¤°à¤¾à¤¯à¤¿à¤•:"
#: editor/editor_help.cpp
msgid "Methods"
-msgstr "मेथड"
+msgstr "तरीकों"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr "थिम पà¥à¤°à¥‹à¤ªà¤°à¤Ÿà¤¿à¤œ"
+msgstr "थीम विशेषता"
#: editor/editor_help.cpp
msgid "Enumerations"
-msgstr "à¤à¤¨à¥à¤¯à¥à¤®à¤°à¥‡à¤¶à¤¨"
+msgstr "गणना"
#: editor/editor_help.cpp
msgid "Constants"
@@ -2316,9 +2315,8 @@ msgid "Layout name not found!"
msgstr "लेआउट नाम नहीं मिला!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
-msgstr "आधार सेटिंगà¥à¤¸ के लिठडिफ़ॉलà¥à¤Ÿ लेआउट बहाल।"
+msgstr "डिफ़ॉलà¥à¤Ÿ लेआउट को मूल सामगà¥à¤°à¥€ पर बहाल कर दिया गया है।"
#: editor/editor_node.cpp
msgid ""
@@ -2374,7 +2372,7 @@ msgstr "चलाने के लिठकोई परिभाषित दà
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "अंजाम देने से पहले सीन को बचाà¤à¤‚ ..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2449,9 +2447,8 @@ msgid "Can't reload a scene that was never saved."
msgstr "à¤à¤• दृशà¥à¤¯ है कि कभी नहीं बचाया गया था फिर से लोड नहीं कर सकते ।"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Saved Scene"
-msgstr "दृशà¥à¤¯ बचाओ"
+msgstr "सहेजे गठदृशà¥à¤¯ को पà¥à¤¨à¤ƒ लोड करें"
#: editor/editor_node.cpp
msgid ""
@@ -2518,18 +2515,19 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "à¤à¤¡à¤‘न पà¥à¤²à¤—इन को सकà¥à¤·à¤® करने में असमरà¥à¤¥: '%' कॉनà¥à¤«à¤¿à¤— का पारà¥à¤¸à¤¿à¤‚ग विफल रहा।"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr "à¤à¤¡à¤‘न पà¥à¤²à¤—इन के लिठसà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ फ़ीलà¥à¤¡ खोजने में असमरà¥à¤¥: 'res://addons/% s'।"
+msgstr "à¤à¤¡-इन का सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ फ़ीलà¥à¤¡ \"% s\" पर नहीं पाया जा सका।"
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
msgstr "पथ से à¤à¤¡à¤‘न सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ लोड करने में असमरà¥à¤¥: '%' ।"
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"रासà¥à¤¤à¥‡ से à¤à¤¡à¤‘न सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ लोड करने में असमरà¥à¤¥: '% à¤à¤¸' कोड में गड़बड़ी लगती है, कृपया सिंटेकà¥à¤¸ की "
"जांच करें।"
@@ -2815,12 +2813,10 @@ msgstr ""
"इसे GDScript इसि मशीन पर डिबग करने के लिये इसे सकà¥à¤°à¤¿à¤¯ करने कि जरà¥à¤°à¤¤ नही|"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Small Deploy with Network Filesystem"
-msgstr "नेटवरà¥à¤• à¤à¤«à¤à¤¸ के साथ छोटे तैनात"
+msgstr "छोटी तैनाती के लिठनेटवरà¥à¤• फाइल सिसà¥à¤Ÿà¤® का उपयोग करें"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, using one-click deploy for Android will only "
"export an executable without the project data.\n"
@@ -2829,70 +2825,67 @@ msgid ""
"On Android, deploying will use the USB cable for faster performance. This "
"option speeds up testing for projects with large assets."
msgstr ""
-"जब यह विकलà¥à¤ª सकà¥à¤·à¤® हो जाता है, तो निरà¥à¤¯à¤¾à¤¤ या तैनाती नà¥à¤¯à¥‚नतम निषà¥à¤ªà¤¾à¤¦à¤¿à¤¤ उतà¥à¤ªà¤¾à¤¦à¤¨ करेगी।\n"
-"नेटवरà¥à¤• के ऊपर संपादक दà¥à¤µà¤¾à¤°à¤¾ परियोजना से फाइलसिसà¥à¤Ÿà¤® उपलबà¥à¤§ कराया जाà¤à¤—ा।\n"
-"à¤à¤‚डà¥à¤°à¥‰à¤¯à¤¡ पर, तैनात तेजी से पà¥à¤°à¤¦à¤°à¥à¤¶à¤¨ के लिठयूà¤à¤¸à¤¬à¥€ केबल का उपयोग करेंगे । यह विकलà¥à¤ª à¤à¤• बड़े "
-"पदचिहà¥à¤¨ के साथ खेल के लिठपरीकà¥à¤·à¤£ को गति देता है।"
+"जब यह विकलà¥à¤ª सकà¥à¤·à¤® हो जाता है, तो Android पर à¤à¤•-कà¥à¤²à¤¿à¤• परिनियोजन के दौरान निरà¥à¤¯à¤¾à¤¤ "
+"की गई निषà¥à¤ªà¤¾à¤¦à¤¨ योगà¥à¤¯ फ़ाइल में पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ डेटा नहीं होगा।\n"
+"फ़ाइल सिसà¥à¤Ÿà¤® परियोजना पर आधारित नेटवरà¥à¤• पर संपादक दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤¦à¤¾à¤¨ किया जाà¤à¤—ा।\n"
+"Android पà¥à¤²à¥‡à¤Ÿà¤«à¥‰à¤°à¥à¤® पर, पà¥à¤°à¤¦à¤°à¥à¤¶à¤¨ में सà¥à¤§à¤¾à¤° के लिठà¤à¤• USB केबल के माधà¥à¤¯à¤® से तैनाती की जाà¤à¤—ी। "
+"यदि पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ में बड़ी सामगà¥à¤°à¥€ है, तो यह विकलà¥à¤ª परीकà¥à¤·à¤£ की गति बढ़ा सकता है।"
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
msgstr "दृशà¥à¤¯à¤®à¤¾à¤¨ टकराव आकार"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, collision shapes and raycast nodes (for 2D and "
"3D) will be visible in the running project."
msgstr ""
-"यदि यह विकलà¥à¤ª चालू हो जाता है तो टकराव के आकार और रेकासà¥à¤Ÿ नोडà¥à¤¸ (2डी और 3 डी के लिà¤) "
-"चल रहे खेल पर दिखाई देंगे।"
+"जब यह विकलà¥à¤ª चालू होता है, तो पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ निषà¥à¤ªà¤¾à¤¦à¤¿à¤¤ होने पर टकà¥à¤•र कà¥à¤·à¥‡à¤¤à¥à¤° और किरण नोडà¥à¤¸ (2D "
+"और 3D) दिखाई देगा।"
#: editor/editor_node.cpp
msgid "Visible Navigation"
msgstr "दरà¥à¤¶à¤¨à¥€à¤¯ नेविगेशन"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, navigation meshes and polygons will be visible "
"in the running project."
-msgstr "यदि यह विकलà¥à¤ª चालू हो जाता है तो नेविगेशन मेशेस और बहà¥à¤­à¥à¤œ चल रहे खेल पर दिखाई देंगे।"
+msgstr ""
+"जब यह विकलà¥à¤ª सकà¥à¤·à¤® हो जाता है, तो पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ चालू होने पर नेविगेशन गà¥à¤°à¤¿à¤¡ और बहà¥à¤­à¥à¤œ दिखाई "
+"देंगे।"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Scene Changes"
-msgstr "सिंक सीन बदलता है"
+msgstr "दृशà¥à¤¯ संशोधन सिंकà¥à¤°à¤¨à¤¾à¤‡à¤œà¤¼ करें"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any changes made to the scene in the editor "
"will be replicated in the running project.\n"
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
-"जब इस विकलà¥à¤ª को चालू किया जाता है, तो संपादक में दृशà¥à¤¯ में किठगठकिसी भी परिवरà¥à¤¤à¤¨ को "
-"चल रहे खेल में दोहराया जाà¤à¤—ा।\n"
-"जब किसी डिवाइस पर दूर से उपयोग किया जाता है, तो यह नेटवरà¥à¤• फाइलसिसà¥à¤Ÿà¤® के साथ अधिक "
-"कà¥à¤¶à¤² होता है।"
+"जब यह विकलà¥à¤ª सकà¥à¤·à¤® हो जाता है, तो संपादक के दृशà¥à¤¯ में कोई भी बदलाव रनिंग पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ पर लागू "
+"किया जाà¤à¤—ा।\n"
+"यदि इसका उपयोग दूरसà¥à¤¥ डिवाइस पर किया जाता है, तो नेटवरà¥à¤• फ़ाइल सिसà¥à¤Ÿà¤® NFS का उपयोग "
+"सरà¥à¤µà¤¶à¥à¤°à¥‡à¤·à¥à¤  पà¥à¤°à¤¦à¤°à¥à¤¶à¤¨ के लिठकिया जा सकता है।"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Script Changes"
-msgstr "सिंक सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ परिवरà¥à¤¤à¤¨"
+msgstr "सिंक सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ संशोधन"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any script that is saved will be reloaded in "
"the running project.\n"
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
-"जब यह विकलà¥à¤ª चालू हो जाà¤à¤—ा, तो सहेजी गई किसी भी सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ को चल रहे गेम पर फिर से लोड "
-"किया जाà¤à¤—ा।\n"
-"जब किसी डिवाइस पर दूर से उपयोग किया जाता है, तो यह नेटवरà¥à¤• फाइलसिसà¥à¤Ÿà¤® के साथ अधिक "
-"कà¥à¤¶à¤² होता है।"
+"जब यह विकलà¥à¤ª सकà¥à¤·à¤® हो जाता है, तो किसी भी सहेजी गई सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ को रनिंग पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ दà¥à¤µà¤¾à¤°à¤¾ "
+"पà¥à¤¨à¤ƒ लोड किया जाà¤à¤—ा।\n"
+"जब दूरसà¥à¤¥ उपकरणों में उपयोग किया जाता है, तो नेटवरà¥à¤• फ़ाइल सिसà¥à¤Ÿà¤® को सकà¥à¤·à¤® करना संपादन "
+"दकà¥à¤·à¤¤à¤¾ में सà¥à¤§à¤¾à¤° कर सकता है।"
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
@@ -2972,6 +2965,10 @@ msgid "About"
msgstr "के बारे में"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ चलाà¤à¤‚।"
@@ -3110,21 +3107,22 @@ msgid "Open & Run a Script"
msgstr "ओपन à¤à¤‚ड रन à¤à¤• सà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
-msgstr "निमà¥à¤¨ फ़ाइलों का निसà¥à¤¸à¤¾à¤°à¤£ नहीं हो पाया:"
+msgstr ""
+"डिसà¥à¤• पर निमà¥à¤¨ फ़ाइलें नई हैं।\n"
+"कà¥à¤¯à¤¾ किया जाà¤?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Reload"
-msgstr ""
+msgstr "पà¥à¤¨à¤ƒ लोड करें"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Resave"
-msgstr ""
+msgstr "पà¥à¤¨: सहेज"
#: editor/editor_node.cpp
msgid "New Inherited"
@@ -3372,14 +3370,14 @@ msgid "Add Key/Value Pair"
msgstr "कà¥à¤‚जी/मूलà¥à¤¯ जोड़ी जोड़ें"
#: editor/editor_run_native.cpp
-#, fuzzy
msgid ""
"No runnable export preset found for this platform.\n"
"Please add a runnable preset in the Export menu or define an existing preset "
"as runnable."
msgstr ""
-"इस मंच के लिठकोई रननयोगà¥à¤¯ निरà¥à¤¯à¤¾à¤¤ पूरà¥à¤µ निरà¥à¤§à¤¾à¤°à¤¿à¤¤ नहीं मिला।\n"
-"कृपया निरà¥à¤¯à¤¾à¤¤ मेनू में à¤à¤• रननेबल पà¥à¤°à¥€à¤¸à¥‡à¤Ÿ जोड़ें।"
+"पà¥à¤²à¥‡à¤Ÿà¤«à¤¼à¥‰à¤°à¥à¤® के अनà¥à¤°à¥‚प कोई निषà¥à¤ªà¤¾à¤¦à¤¨ योगà¥à¤¯ पà¥à¤°à¥€à¤¸à¥‡à¤Ÿ नहीं है।\n"
+"कृपया निरà¥à¤¯à¤¾à¤¤ मेनू में à¤à¤• निषà¥à¤ªà¤¾à¤¦à¤¨ योगà¥à¤¯ पà¥à¤°à¥€à¤¸à¥‡à¤Ÿ जोड़ें, या मौजूदा पà¥à¤°à¥€à¤¸à¥‡à¤Ÿ को निषà¥à¤ªà¤¾à¤¦à¤¨ योगà¥à¤¯ के "
+"रूप में सेट करें।"
#: editor/editor_run_script.cpp
msgid "Write your logic in the _run() method."
@@ -3649,6 +3647,7 @@ msgstr ""
msgid ""
"Importing has been disabled for this file, so it can't be opened for editing."
msgstr ""
+"इस फ़ाइल का आयात अकà¥à¤·à¤® कर दिया गया है, इसलिठइसे संपादन के लिठनहीं खोला जा सकता है।"
#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
@@ -3780,9 +3779,8 @@ msgid "Duplicate..."
msgstr "डà¥à¤ªà¥à¤²à¤¿à¤•ेट..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Move to Trash"
-msgstr "औटोलोड हिलाइये"
+msgstr "टà¥à¤°à¥ˆà¤¶ में ले जाà¤à¤‚"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
@@ -3892,19 +3890,16 @@ msgid "Searching..."
msgstr "खोज..."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d match in %d file."
-msgstr "%d मिल गया।"
+msgstr "%d मैच, कà¥à¤² %d फाइलें।"
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d file."
-msgstr "%d मिल गया।"
+msgstr "%d मिलान परिणाम (%d फ़ाइलों में)।"
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d files."
-msgstr "%d मिल गया।"
+msgstr "%d मैच, कà¥à¤² %d फाइलें।"
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -9943,7 +9938,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11993,10 +11988,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/hr.po b/editor/translations/hr.po
index dc71edeec3..f49ba47c29 100644
--- a/editor/translations/hr.po
+++ b/editor/translations/hr.po
@@ -1097,6 +1097,10 @@ msgstr "Promijeni vrijednost u rjeÄniku"
msgid "Thanks from the Godot community!"
msgstr "Hvala od Godot zajednice!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine suradnici"
@@ -2456,8 +2460,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2862,6 +2867,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9715,7 +9724,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11727,10 +11736,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/hu.po b/editor/translations/hu.po
index 2ef5783de9..eda808eef4 100644
--- a/editor/translations/hu.po
+++ b/editor/translations/hu.po
@@ -1130,6 +1130,10 @@ msgstr "Szótár Érték Módosítása"
msgid "Thanks from the Godot community!"
msgstr "Köszönet a Godot közösségétől!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine közreműködők"
@@ -2561,9 +2565,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Nem sikerült az addon szkript betöltése a következő útvonalról: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Nem lehet betölteni az addon szkriptet a(z) '%s' útvonalról. Úgy tűnik, hiba "
"történt a kódban, ellenőrizze a szintaxist."
@@ -3007,6 +3013,10 @@ msgid "About"
msgstr "Névjegy"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Projekt futtatása."
@@ -9897,7 +9907,7 @@ msgstr "Egérgomb"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11911,10 +11921,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/id.po b/editor/translations/id.po
index e97e193d0f..08bfa5969d 100644
--- a/editor/translations/id.po
+++ b/editor/translations/id.po
@@ -1142,6 +1142,10 @@ msgstr "Ubah Nilai Kamus"
msgid "Thanks from the Godot community!"
msgstr "Terimakasih dari komunitas Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine kontributor"
@@ -2561,9 +2565,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Tidak bisa memuat script addon dari lokasi: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Tidak dapat memuat script addon dari path: '%s' Mungkin ada kesalahan dalam "
"kode, mohon periksa sintaks."
@@ -3009,6 +3015,10 @@ msgid "About"
msgstr "Tentang"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Mainkan proyek."
@@ -5229,6 +5239,7 @@ msgstr ""
"persegi [0.0,1.0]."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
+#, fuzzy
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
@@ -10147,7 +10158,7 @@ msgstr "Tombol Mouse"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Nama aksi tidak valid. Tidak boleh kosong atau mengandung '/', ':', '=', "
@@ -12210,12 +12221,24 @@ msgstr ""
"Proyek."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Berkas debug keystore belum dikonfigurasi dalam Pengaturan Editor maupun di "
"prasetel proyek."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr "Berkas keystore rilis belum dikonfigurasi di prasetel ekspor."
diff --git a/editor/translations/is.po b/editor/translations/is.po
index fd9e23d91b..72472c2215 100644
--- a/editor/translations/is.po
+++ b/editor/translations/is.po
@@ -1118,6 +1118,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2481,8 +2485,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2890,6 +2895,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9806,7 +9815,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11830,10 +11839,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/it.po b/editor/translations/it.po
index d1b39155c9..3d0509ba15 100644
--- a/editor/translations/it.po
+++ b/editor/translations/it.po
@@ -57,12 +57,14 @@
# Ziv D <wizdavid@gmail.com>, 2020.
# Riteo Siuga <lorenzocerqua@tutanota.com>, 2021.
# Alessandro Mandelli <mandelli.alessandro@ngi.it>, 2021.
+# Jusef Azzolina <rosarioazzolina33@gmail.com>, 2021.
+# Daniele Basso <tiziodcaio@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-16 07:52+0000\n"
-"Last-Translator: Marco Galli <mrcgll98@gmail.com>\n"
+"PO-Revision-Date: 2021-06-15 19:34+0000\n"
+"Last-Translator: Riteo Siuga <lorenzocerqua@tutanota.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot/it/>\n"
"Language: it\n"
@@ -70,7 +72,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -105,15 +107,15 @@ msgstr "Indice di tipo %s non valido per il tipo base %s"
#: core/math/expression.cpp
msgid "Invalid named index '%s' for base type %s"
-msgstr "Nome dell'indice '%s' non valido per il tipo base %s"
+msgstr "Nome dell'indice \"%s\" non valido per il tipo base %s"
#: core/math/expression.cpp
msgid "Invalid arguments to construct '%s'"
-msgstr "Argomenti non validi per costruire '%s'"
+msgstr "Argomenti non validi per costruire \"%s\""
#: core/math/expression.cpp
msgid "On call to '%s':"
-msgstr "Alla chiamata di '%s':"
+msgstr "Alla chiamata di \"%s\":"
#: core/ustring.cpp
msgid "B"
@@ -250,7 +252,7 @@ msgstr "Traccia di trasformazioni 3D"
#: editor/animation_track_editor.cpp
msgid "Call Method Track"
-msgstr "Traccia di chiamate di metodo"
+msgstr "Traccia di metodi"
#: editor/animation_track_editor.cpp
msgid "Bezier Curve Track"
@@ -258,11 +260,11 @@ msgstr "Traccia di curve di Bézier"
#: editor/animation_track_editor.cpp
msgid "Audio Playback Track"
-msgstr "Traccia di riproduzione audio"
+msgstr "Traccia sonora"
#: editor/animation_track_editor.cpp
msgid "Animation Playback Track"
-msgstr "Traccia di riproduzione di animazioni"
+msgstr "Traccia di animazioni"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
@@ -287,11 +289,11 @@ msgstr "Funzioni:"
#: editor/animation_track_editor.cpp
msgid "Audio Clips:"
-msgstr "Clip audio:"
+msgstr "Segmenti audio:"
#: editor/animation_track_editor.cpp
msgid "Anim Clips:"
-msgstr "Clip animazione:"
+msgstr "Segmenti d'animazione:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
@@ -299,7 +301,7 @@ msgstr "Cambia Percorso Traccia"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr "Attiva/Disattiva questa traccia."
+msgstr "Abilita/Disabilita questa traccia."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
@@ -385,7 +387,7 @@ msgstr "Cambia la modalità d'interpolazione di un'animazione"
#: editor/animation_track_editor.cpp
msgid "Change Animation Loop Mode"
-msgstr "Cambia Modalità Loop Animazione"
+msgstr "Cambia la modalità del ciclo di un'animazione"
#: editor/animation_track_editor.cpp
msgid "Remove Anim Track"
@@ -397,7 +399,7 @@ msgstr "Creare una NUOVA traccia per %s e inserire la chiave?"
#: editor/animation_track_editor.cpp
msgid "Create %d NEW tracks and insert keys?"
-msgstr "Crea %d NUOVE tracce ed inserire fotogrammi chiave?"
+msgstr "Creare %d NUOVE tracce e inserirci i fotogrammi chiavi?"
#: editor/animation_track_editor.cpp editor/create_dialog.cpp
#: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp
@@ -417,23 +419,23 @@ msgstr "Inserisci un'animazione"
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
-msgstr "AnimationPlayer può solo animare altri riproduttori, non se stesso."
+msgstr "AnimationPlayer non può animare se stesso, solo altri nodi."
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
-msgstr "Crea & Inserisci Animazione"
+msgstr "Crea un'animazione e inserisci un fotogramma chiave"
#: editor/animation_track_editor.cpp
msgid "Anim Insert Track & Key"
-msgstr "Inserisci Traccia e Fotogramma Chiave Animazione"
+msgstr "Inserisci un traccia con un fotogramma chiave in un'animazione"
#: editor/animation_track_editor.cpp
msgid "Anim Insert Key"
-msgstr "Inserisci Fotogramma Chiave Animazione"
+msgstr "Inserisci un fotogramma chiave in un'animazione"
#: editor/animation_track_editor.cpp
msgid "Change Animation Step"
-msgstr "Cambia passo animazione"
+msgstr "Cambia il passo di animazione"
#: editor/animation_track_editor.cpp
msgid "Rearrange Tracks"
@@ -442,8 +444,7 @@ msgstr "Riordina delle tracce"
#: editor/animation_track_editor.cpp
msgid "Transform tracks only apply to Spatial-based nodes."
msgstr ""
-"Le tracce di trasformazione possono essere applicate soltanto ai nodi basati "
-"sul nodo Spatial."
+"Le tracce di trasformazioni 3D si applicano solo a nodi di tipo Spatial."
#: editor/animation_track_editor.cpp
msgid ""
@@ -460,14 +461,11 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Animation tracks can only point to AnimationPlayer nodes."
msgstr ""
-"Le tracce di riproduzione di animazioni possono puntare solo a nodi di tipo "
-"AnimationPlayer."
+"Le tracce di animazioni possono puntare solo a nodi di tipo AnimationPlayer."
#: editor/animation_track_editor.cpp
msgid "An animation player can't animate itself, only other players."
-msgstr ""
-"Un riproduttore di animazioni può solo animare altri riproduttori, non se "
-"stesso."
+msgstr "Un AnimationPlayer non può animare se stesso, solo altri riproduttori."
#: editor/animation_track_editor.cpp
msgid "Not possible to add a new track without a root"
@@ -475,7 +473,8 @@ msgstr "Non è possibile aggiungere una nuova traccia senza un nodo radice"
#: editor/animation_track_editor.cpp
msgid "Invalid track for Bezier (no suitable sub-properties)"
-msgstr "Traccia non valida per Bezier (nessuna sotto-proprietà valida)"
+msgstr ""
+"Traccia non valida per una curva di Bézier (nessuna sotto-proprietà adatta)"
#: editor/animation_track_editor.cpp
msgid "Add Bezier Track"
@@ -500,12 +499,12 @@ msgstr "Aggiungi una chiave a una traccia"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a method key."
msgstr ""
-"La traccia non è valida, quindi, non è stato possibile aggiungere una chiave "
-"chiamata metodo."
+"La traccia non è valida, quindi non è stato possibile aggiungere una chiave "
+"di metodo."
#: editor/animation_track_editor.cpp
msgid "Add Method Track Key"
-msgstr "Aggiungi una chiave a una traccia di chiamate di metodi"
+msgstr "Aggiungi una chiave a una traccia di chiamate metodi"
#: editor/animation_track_editor.cpp
msgid "Method not found in object: "
@@ -521,11 +520,11 @@ msgstr "Gli appunti sono vuoti"
#: editor/animation_track_editor.cpp
msgid "Paste Tracks"
-msgstr "Incolla Tracce"
+msgstr "Incolla delle tracce"
#: editor/animation_track_editor.cpp
msgid "Anim Scale Keys"
-msgstr "Scala Chiavi Animazione"
+msgstr "Scala delle chiavi d'animazione"
#: editor/animation_track_editor.cpp
msgid ""
@@ -546,23 +545,24 @@ msgid ""
"Alternatively, use an import preset that imports animations to separate "
"files."
msgstr ""
-"Questa animazione appartiene ad una scena importata, quindi i cambiamenti "
-"alle tracce importate non saranno salvate.\n"
+"Quest'animazione appartiene a una scena importata, eventuali modifiche fatte "
+"alle tracce importate non verranno salvate.\n"
"\n"
-"Per abilitare l'aggiunta di tracce personalizzate, naviga alle impostazioni "
-"d'importazione della scena ed imposta\n"
-"\"Animation > Storage\" a \"Files\", abilita \"Animation > Keep Custom Tracks"
-"\", e poi re-importa.\n"
-"In alternativa, usa un preset d'importo che importa le animazioni da file "
-"separati."
+"Per abilitare la possibilità di aggiungere ulteriori tracce, è necessario "
+"andare nelle impostazioni d'importazione della scena, impostare\n"
+"\"Animation > Storage\" su \"Files\", attivare \"Animation > Keep Custom "
+"Tracks\" e infine reimportare la scena.\n"
+"In alternativa è possibile usare una preimpostazione che importi le "
+"animazioni in file separati."
#: editor/animation_track_editor.cpp
msgid "Warning: Editing imported animation"
-msgstr "Attenzione: stai modificando un'animazione importata"
+msgstr "Attenzione: sta venendo modificata un'animazione importata"
#: editor/animation_track_editor.cpp
msgid "Select an AnimationPlayer node to create and edit animations."
-msgstr "Seleziona un nodo AnimationPlayer per creare e modificare animazioni."
+msgstr ""
+"Selezionare un nodo AnimationPlayer per creare e modificare animazioni."
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
@@ -621,7 +621,7 @@ msgstr "Duplica la selezione"
#: editor/animation_track_editor.cpp
msgid "Duplicate Transposed"
-msgstr "Duplica Trasposto"
+msgstr "Duplica trasposto"
#: editor/animation_track_editor.cpp
msgid "Delete Selection"
@@ -629,11 +629,11 @@ msgstr "Elimina la selezione"
#: editor/animation_track_editor.cpp
msgid "Go to Next Step"
-msgstr "Vai allo Step Successivo"
+msgstr "Vai al passo successivo"
#: editor/animation_track_editor.cpp
msgid "Go to Previous Step"
-msgstr "Vai allo Step Precedente"
+msgstr "Vai al passo precedente"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -657,15 +657,15 @@ msgstr "Ottimizzatore anim."
#: editor/animation_track_editor.cpp
msgid "Max. Linear Error:"
-msgstr "Max Errore Lineare:"
+msgstr "Max errore lineare:"
#: editor/animation_track_editor.cpp
msgid "Max. Angular Error:"
-msgstr "Max Errore Angolare:"
+msgstr "Max errore angolare:"
#: editor/animation_track_editor.cpp
msgid "Max Optimizable Angle:"
-msgstr "Max Angolo Ottimizzabile:"
+msgstr "Max angolo ottimizzabile:"
#: editor/animation_track_editor.cpp
msgid "Optimize"
@@ -710,47 +710,47 @@ msgstr "Copia"
#: editor/animation_track_editor.cpp
msgid "Select All/None"
-msgstr "De/Seleziona Tutto"
+msgstr "Seleziona/Deseleziona tutto"
#: editor/animation_track_editor_plugins.cpp
msgid "Add Audio Track Clip"
-msgstr "Aggiungi audio in una traccia di riproduzione audio"
+msgstr "Aggiungi un segmento audio in una traccia sonora"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
-msgstr "Cambia Offset Inizio Clip Traccia Audio"
+msgstr "Cambia l'inizio di un segmento audio di una traccia sonora"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr "Cambia Offset Fine Clip Traccia Audio"
+msgstr "Cambia la fine del segmento audio di una traccia sonora"
#: editor/array_property_edit.cpp
msgid "Resize Array"
-msgstr "Ridimensiona Array"
+msgstr "Ridimensiona lista"
#: editor/array_property_edit.cpp
msgid "Change Array Value Type"
-msgstr "Cambia Tipo Valore Array"
+msgstr "Cambia il tipo del valore della lista"
#: editor/array_property_edit.cpp
msgid "Change Array Value"
-msgstr "Cambia Valore Array"
+msgstr "Cambia il valore della lista"
#: editor/code_editor.cpp
msgid "Go to Line"
-msgstr "Vai alla Linea"
+msgstr "Vai alla linea"
#: editor/code_editor.cpp
msgid "Line Number:"
-msgstr "Numero Linea:"
+msgstr "Numero della linea:"
#: editor/code_editor.cpp
msgid "%d replaced."
-msgstr "%d rimpiazzato."
+msgstr "%d sostituito."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
-msgstr "%d corrispondenza."
+msgstr "%d corrispondenze."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d matches."
@@ -758,11 +758,11 @@ msgstr "%d corrispondenze."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
-msgstr "Distingui Maiuscole"
+msgstr "Maiuscole distinte"
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Whole Words"
-msgstr "Parole Intere"
+msgstr "Parole intere"
#: editor/code_editor.cpp
msgid "Replace"
@@ -770,11 +770,11 @@ msgstr "Sostituisci"
#: editor/code_editor.cpp
msgid "Replace All"
-msgstr "Rimpiazza Tutti"
+msgstr "Sostituisci tutti"
#: editor/code_editor.cpp
msgid "Selection Only"
-msgstr "Solo Selezione"
+msgstr "Solo nella selezione"
#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
#: editor/plugins/text_editor.cpp
@@ -783,7 +783,7 @@ msgstr "Standard"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
-msgstr "Toggle Pannello Script"
+msgstr "Commuta il pannello degli script"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -799,7 +799,7 @@ msgstr "Rimpicciolisci"
#: editor/code_editor.cpp
msgid "Reset Zoom"
-msgstr "Reimposta ingrandimento"
+msgstr "Reimposta l'ingrandimento"
#: editor/code_editor.cpp
msgid "Warnings"
@@ -822,8 +822,8 @@ msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
msgstr ""
-"Metodo di destinazione non trovato. Specifica un metodo valido o attribuisci "
-"uno script al nodo di destinazione."
+"Metodo di destinazione non trovato. Specifica un metodo valido o assegna uno "
+"script al nodo di destinazione."
#: editor/connections_dialog.cpp
msgid "Connect to Node:"
@@ -831,11 +831,11 @@ msgstr "Connetti al Nodo:"
#: editor/connections_dialog.cpp
msgid "Connect to Script:"
-msgstr "Connetti allo Script:"
+msgstr "Connetti allo script:"
#: editor/connections_dialog.cpp
msgid "From Signal:"
-msgstr "Dal Segnale:"
+msgstr "Dal segnale:"
#: editor/connections_dialog.cpp
msgid "Scene does not contain any script."
@@ -860,15 +860,15 @@ msgstr "Rimuovi"
#: editor/connections_dialog.cpp
msgid "Add Extra Call Argument:"
-msgstr "Aggiungi argomento extra di chiamata:"
+msgstr "Aggiungi un argomento di chiamata aggiuntivo:"
#: editor/connections_dialog.cpp
msgid "Extra Call Arguments:"
-msgstr "Argomenti chiamata extra:"
+msgstr "Argomenti di chiamata aggiuntivi:"
#: editor/connections_dialog.cpp
msgid "Receiver Method:"
-msgstr "Metodo Ricevitore:"
+msgstr "Metodo ricevitore:"
#: editor/connections_dialog.cpp
msgid "Advanced"
@@ -882,8 +882,8 @@ msgstr "Differita"
msgid ""
"Defers the signal, storing it in a queue and only firing it at idle time."
msgstr ""
-"Differisce il segnale memorizzandolo in una coda ed emettendolo in fase di "
-"inattività."
+"Differisce il segnale memorizzandolo in una coda ed emettendolo in fase "
+"d'inattività."
#: editor/connections_dialog.cpp
msgid "Oneshot"
@@ -921,15 +921,15 @@ msgstr "Segnale:"
#: editor/connections_dialog.cpp
msgid "Connect '%s' to '%s'"
-msgstr "Connetti '%s' a '%s'"
+msgstr "Connetti \"%s\" a \"%s\""
#: editor/connections_dialog.cpp
msgid "Disconnect '%s' from '%s'"
-msgstr "Disconnetti '%s' da '%s'"
+msgstr "Disconnetti \"%s\" da \"%s\""
#: editor/connections_dialog.cpp
msgid "Disconnect all from signal: '%s'"
-msgstr "Disconnetti tutto dal segnale: '%s'"
+msgstr "Disconnetti tutto dal segnale: \"%s\""
#: editor/connections_dialog.cpp
msgid "Connect..."
@@ -942,11 +942,11 @@ msgstr "Disconnetti"
#: editor/connections_dialog.cpp
msgid "Connect a Signal to a Method"
-msgstr "Connetti un Segnale a un Metodo"
+msgstr "Connetti un segnale a un metodo"
#: editor/connections_dialog.cpp
msgid "Edit Connection:"
-msgstr "Modifica Connessione:"
+msgstr "Modifica una connessione:"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
@@ -962,7 +962,7 @@ msgstr "Filtra segnali"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
-msgstr "Sei sicuro di voler rimuovere tutte le connessioni da questo segnale?"
+msgstr "Confermare la rimozione di tutte le connessioni da questo segnale?"
#: editor/connections_dialog.cpp
msgid "Disconnect All"
@@ -974,11 +974,11 @@ msgstr "Modifica..."
#: editor/connections_dialog.cpp
msgid "Go To Method"
-msgstr "Va' al metodo"
+msgstr "Vai al metodo"
#: editor/create_dialog.cpp
msgid "Change %s Type"
-msgstr "Cambia tipo di %s"
+msgstr "Cambia il tipo di %s"
#: editor/create_dialog.cpp editor/project_settings_editor.cpp
msgid "Change"
@@ -986,7 +986,7 @@ msgstr "Cambia"
#: editor/create_dialog.cpp
msgid "Create New %s"
-msgstr "Crea nuovo %s"
+msgstr "Crea un nuovo %s"
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1030,16 +1030,16 @@ msgid ""
"Scene '%s' is currently being edited.\n"
"Changes will only take effect when reloaded."
msgstr ""
-"La scena '%s' è al momento in modifica.\n"
-"I cambiamenti avranno effetto quando sarà ricaricata."
+"La scena \"%s\" sta venendo modificata in questo momento.\n"
+"I cambiamenti avranno effetto solo una volta ricaricata."
#: editor/dependency_editor.cpp
msgid ""
"Resource '%s' is in use.\n"
"Changes will only take effect when reloaded."
msgstr ""
-"La risorsa '%s' è in uso.\n"
-"I cambiamenti avranno effetto quando sarà ricaricata."
+"La risorsa \"%s\" è in uso.\n"
+"I cambiamenti avranno effetto una volta ricaricata."
#: editor/dependency_editor.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -1061,11 +1061,11 @@ msgstr "Dipendenze:"
#: editor/dependency_editor.cpp
msgid "Fix Broken"
-msgstr "Ripara rotti"
+msgstr "Ripara le dipendenze rotte"
#: editor/dependency_editor.cpp
msgid "Dependency Editor"
-msgstr "Editor Dipendenze"
+msgstr "Editor di dipendenze"
#: editor/dependency_editor.cpp
msgid "Search Replacement Resource:"
@@ -1090,8 +1090,8 @@ msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
msgstr ""
-"Rimuovere i file selezionati dal progetto? (Non può essere annullato)\n"
-"Puoi trovare i file rimossi nel cestino di sistema per ripristinarli."
+"Rimuovere i file selezionati dal progetto? (non annullabile)\n"
+"Sarà possibile ripristinarli accedendo al cestino di sistema."
#: editor/dependency_editor.cpp
msgid ""
@@ -1103,7 +1103,7 @@ msgstr ""
"I file che stanno per essere rimossi sono richiesti per il funzionamento di "
"altre risorse.\n"
"Rimuoverli comunque? (non annullabile)\n"
-"Puoi trovare i file rimossi nel cestino di sistema per ripristinarli."
+"Sarà possibile ripristinarli accedendo al cestino di sistema."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1127,19 +1127,19 @@ msgstr "Quale azione deve essere intrapresa?"
#: editor/dependency_editor.cpp
msgid "Fix Dependencies"
-msgstr "Ripara dipendenze"
+msgstr "Ripara delle dipendenze"
#: editor/dependency_editor.cpp
msgid "Errors loading!"
-msgstr "Errori in caricamento!"
+msgstr "Errori durante il caricamento!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr "Eliminare permanentemente %d elementi? (Non annullabile!)"
+msgstr "Eliminare definitivamente %d elementi? (Non annullabile!)"
#: editor/dependency_editor.cpp
msgid "Show Dependencies"
-msgstr "Mostra Dipendenze"
+msgstr "Mostra le dipendenze"
#: editor/dependency_editor.cpp
msgid "Orphan Resource Explorer"
@@ -1159,23 +1159,27 @@ msgstr "Possiede"
#: editor/dependency_editor.cpp
msgid "Resources Without Explicit Ownership:"
-msgstr "Risorse senza proprietario esplicito:"
+msgstr "Risorse senza un proprietario esplicito:"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Key"
-msgstr "Cambia Chiave Dizionario"
+msgstr "Cambia una chiave di un dizionario"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Value"
-msgstr "Cambia valore del dizionario"
+msgstr "Cambia il valore di un dizionario"
#: editor/editor_about.cpp
msgid "Thanks from the Godot community!"
msgstr "Grazie dalla comunità di Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
-msgstr "Contributori di Godot engine"
+msgstr "Contributori di Godot Engine"
#: editor/editor_about.cpp
msgid "Project Founders"
@@ -1190,7 +1194,7 @@ msgstr "Sviluppatore principale"
#. you do not have to keep it in your translation.
#: editor/editor_about.cpp
msgid "Project Manager "
-msgstr "Gestore progetto "
+msgstr "Gestore del progetto "
#: editor/editor_about.cpp
msgid "Developers"
@@ -1210,11 +1214,11 @@ msgstr "Sponsor oro"
#: editor/editor_about.cpp
msgid "Silver Sponsors"
-msgstr "Sponsor Argento"
+msgstr "Sponsor argento"
#: editor/editor_about.cpp
msgid "Bronze Sponsors"
-msgstr "Sponsor Bronzo"
+msgstr "Sponsor bronzo"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
@@ -1242,7 +1246,7 @@ msgstr "Licenza"
#: editor/editor_about.cpp
msgid "Third-party Licenses"
-msgstr "Licenza di terze parti"
+msgstr "Licenze di terze parti"
#: editor/editor_about.cpp
msgid ""
@@ -1251,14 +1255,14 @@ msgid ""
"is an exhaustive list of all such third-party components with their "
"respective copyright statements and license terms."
msgstr ""
-"Godot Engine si basa su parecchie librerie gratuite ed open source, tutte "
-"compatibili con i termini della licenza MIT dell'engine. Qui di seguito "
-"trovi una lista esaustiva di tutti i componenti di terze parti con le "
-"rispettive dichiarazioni sui diritti d'autore e termini di licenza."
+"Godot Engine dipende da molte librerie di terze parti gratuite e aperte, "
+"tutte compatibili con i termini della sua licenza MIT. Qui di seguito una "
+"lista esaustiva di tutti i componenti di terze parti con le rispettive "
+"dichiarazioni sui loro diritti d'autore e termini di licenza."
#: editor/editor_about.cpp
msgid "All Components"
-msgstr "Tutte le componenti"
+msgstr "Tutti i componenti"
#: editor/editor_about.cpp
msgid "Components"
@@ -1270,7 +1274,7 @@ msgstr "Licenze"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Error opening package file, not in ZIP format."
-msgstr "Errore nell'apertura del file package: non è in formato ZIP."
+msgstr "Errore nell'apertura del file del pacchetto, non è in formato ZIP."
#: editor/editor_asset_installer.cpp
msgid "%s (Already Exists)"
@@ -1282,7 +1286,7 @@ msgstr "Estrazione asset"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "The following files failed extraction from package:"
-msgstr "Impossibile estrarre i file seguenti dal pacchetto:"
+msgstr "Impossibile estrarre i seguenti file dal pacchetto:"
#: editor/editor_asset_installer.cpp
msgid "And %s more files."
@@ -1307,7 +1311,7 @@ msgstr "Installa"
#: editor/editor_asset_installer.cpp
msgid "Package Installer"
-msgstr "Installatore pacchetto"
+msgstr "Installatore di pacchetti"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
@@ -1315,27 +1319,28 @@ msgstr "Altoparlanti"
#: editor/editor_audio_buses.cpp
msgid "Add Effect"
-msgstr "Aggiungi effetto"
+msgstr "Aggiungi un effetto"
#: editor/editor_audio_buses.cpp
msgid "Rename Audio Bus"
-msgstr "Rinomina bus audio"
+msgstr "Rinomina un bus audio"
#: editor/editor_audio_buses.cpp
msgid "Change Audio Bus Volume"
-msgstr "Cambia il volume del bus audio"
+msgstr "Cambia il volume di un bus audio"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Solo"
-msgstr "Imposta bus audio su solo"
+msgstr "Commuta lo stato di solista di un bus audio"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Mute"
-msgstr "Imposta bus audio su Muto"
+msgstr "Commuta l'ammutolimento di un bus audio"
#: editor/editor_audio_buses.cpp
+#, fuzzy
msgid "Toggle Audio Bus Bypass Effects"
-msgstr "Commuta bypass effetti del bus audio"
+msgstr "Commuta il bypass degli effetti del bus audio"
#: editor/editor_audio_buses.cpp
msgid "Select Audio Bus Send"
@@ -1343,15 +1348,15 @@ msgstr "Seleziona invio del bus audio"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus Effect"
-msgstr "Aggiungi un effetto bus audio"
+msgstr "Aggiungi un effetto a un bus audio"
#: editor/editor_audio_buses.cpp
msgid "Move Bus Effect"
-msgstr "Sposta effetti bus"
+msgstr "Sposta un effetto di un bus"
#: editor/editor_audio_buses.cpp
msgid "Delete Bus Effect"
-msgstr "Cancella effetto bus"
+msgstr "Cancella un effetto di un bus"
#: editor/editor_audio_buses.cpp
msgid "Drag & drop to rearrange."
@@ -1359,19 +1364,20 @@ msgstr "Trascina e rilascia per riordinare."
#: editor/editor_audio_buses.cpp
msgid "Solo"
-msgstr "Solo"
+msgstr "Solista"
#: editor/editor_audio_buses.cpp
msgid "Mute"
msgstr "Muto"
#: editor/editor_audio_buses.cpp
+#, fuzzy
msgid "Bypass"
msgstr "Bypassa"
#: editor/editor_audio_buses.cpp
msgid "Bus options"
-msgstr "Opzioni bus"
+msgstr "Opzioni del bus"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
@@ -1380,11 +1386,11 @@ msgstr "Duplica"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
-msgstr "Ripristina volume"
+msgstr "Ripristina il volume"
#: editor/editor_audio_buses.cpp
msgid "Delete Effect"
-msgstr "Elimina effetto"
+msgstr "Elimina l'effetto"
#: editor/editor_audio_buses.cpp
msgid "Audio"
@@ -1392,7 +1398,7 @@ msgstr "Audio"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus"
-msgstr "Aggiungi bus audio"
+msgstr "Aggiungi un bus audio"
#: editor/editor_audio_buses.cpp
msgid "Master bus can't be deleted!"
@@ -1400,23 +1406,23 @@ msgstr "Il bus principale non può essere cancellato!"
#: editor/editor_audio_buses.cpp
msgid "Delete Audio Bus"
-msgstr "Elimina bus audio"
+msgstr "Elimina un bus audio"
#: editor/editor_audio_buses.cpp
msgid "Duplicate Audio Bus"
-msgstr "Duplica bus audio"
+msgstr "Duplica un bus audio"
#: editor/editor_audio_buses.cpp
msgid "Reset Bus Volume"
-msgstr "Ripristina volume del Bus"
+msgstr "Ripristina il volume di un bus"
#: editor/editor_audio_buses.cpp
msgid "Move Audio Bus"
-msgstr "Sposta bus audio"
+msgstr "Sposta un bus audio"
#: editor/editor_audio_buses.cpp
msgid "Save Audio Bus Layout As..."
-msgstr "Salva disposizione del bus audio come..."
+msgstr "Salva la disposizione del bus audio come..."
#: editor/editor_audio_buses.cpp
msgid "Location for New Layout..."
@@ -1424,11 +1430,11 @@ msgstr "Posizione per la nuova disposizione..."
#: editor/editor_audio_buses.cpp
msgid "Open Audio Bus Layout"
-msgstr "Apri disposizione bus audio"
+msgstr "Apri la disposizione di un bus audio"
#: editor/editor_audio_buses.cpp
msgid "There is no '%s' file."
-msgstr "File '%s' assente."
+msgstr "File \"%s\" assente."
#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
msgid "Layout"
@@ -1440,7 +1446,7 @@ msgstr "File non valido, non è una disposizione di un bus audio."
#: editor/editor_audio_buses.cpp
msgid "Error saving file: %s"
-msgstr "Errore nel salvataggio file: %s"
+msgstr "Errore nel salvataggio del file: %s"
#: editor/editor_audio_buses.cpp
msgid "Add Bus"
@@ -1458,7 +1464,7 @@ msgstr "Carica"
#: editor/editor_audio_buses.cpp
msgid "Load an existing Bus Layout."
-msgstr "Carica una disposizione bus esistente."
+msgstr "Carica una disposizione di bus esistente."
#: editor/editor_audio_buses.cpp
msgid "Save As"
@@ -1466,19 +1472,19 @@ msgstr "Salva come"
#: editor/editor_audio_buses.cpp
msgid "Save this Bus Layout to a file."
-msgstr "Salva questa disposizione bus in un file."
+msgstr "Salva questa disposizione di bus in un file."
#: editor/editor_audio_buses.cpp editor/import_dock.cpp
msgid "Load Default"
-msgstr "Carica Predefiniti"
+msgstr "Carica i predefiniti"
#: editor/editor_audio_buses.cpp
msgid "Load the default Bus Layout."
-msgstr "Carica la disposizione dei bus predefinita."
+msgstr "Carica la disposizione di bus predefinita."
#: editor/editor_audio_buses.cpp
msgid "Create a new Bus Layout."
-msgstr "Crea una nuova disposizione dei bus."
+msgstr "Crea una nuova disposizione di bus."
#: editor/editor_autoload_settings.cpp
msgid "Invalid name."
@@ -1490,41 +1496,45 @@ msgstr "Caratteri validi:"
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing engine class name."
-msgstr ""
-"Non deve essere in conflitto con un nome di una classe esistente dell'engine."
+msgstr "Non deve collidere con il nome di una classe del motore esistente."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing built-in type name."
-msgstr "Non deve essere in conflitto con un nome di tipo built-in esistente."
+msgstr "Non deve collidere con il nome di un tipo built-in esistente."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing global constant name."
-msgstr ""
-"Non deve essere in conflitto con un nome di una costante globale esistente."
+msgstr "Non deve collidere con il nome di una costante globale esistente."
#: editor/editor_autoload_settings.cpp
+#, fuzzy
msgid "Keyword cannot be used as an autoload name."
-msgstr "La parola chiave non può essere utilizzata come nome di un Autoload."
+msgstr "Una parola chiave non può essere utilizzata come nome di un Autoload."
#: editor/editor_autoload_settings.cpp
+#, fuzzy
msgid "Autoload '%s' already exists!"
-msgstr "Autoload '%s' esiste già!"
+msgstr "L'Autoload \"%s\" esiste già!"
#: editor/editor_autoload_settings.cpp
+#, fuzzy
msgid "Rename Autoload"
-msgstr "Rinomina Autoload"
+msgstr "Rinomina un Autoload"
#: editor/editor_autoload_settings.cpp
+#, fuzzy
msgid "Toggle AutoLoad Globals"
msgstr "Commuta AutoLoad globals"
#: editor/editor_autoload_settings.cpp
+#, fuzzy
msgid "Move Autoload"
-msgstr "Sposta Autoload"
+msgstr "Sposta un Autoload"
#: editor/editor_autoload_settings.cpp
+#, fuzzy
msgid "Remove Autoload"
-msgstr "Rimuovi Autoload"
+msgstr "Rimuovi un Autoload"
#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
msgid "Enable"
@@ -1540,7 +1550,7 @@ msgstr "Non è possibile aggiungere l'autoload:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
-msgstr "Aggiungi Autoload"
+msgstr "Aggiungi un Autoload"
#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp
#: editor/editor_plugin_settings.cpp
@@ -1551,7 +1561,7 @@ msgstr "Percorso:"
#: editor/editor_autoload_settings.cpp
msgid "Node Name:"
-msgstr "Nome nodo:"
+msgstr "Nome del nodo:"
#: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp
#: editor/editor_profiler.cpp editor/project_manager.cpp
@@ -1565,11 +1575,11 @@ msgstr "Singleton"
#: editor/editor_data.cpp editor/inspector_dock.cpp
msgid "Paste Params"
-msgstr "Incolla Parametri"
+msgstr "Incolla dei parametri"
#: editor/editor_data.cpp
msgid "Updating Scene"
-msgstr "Aggiornamento scena"
+msgstr "Aggiornamento della scena"
#: editor/editor_data.cpp
msgid "Storing local changes..."
@@ -1593,13 +1603,13 @@ msgstr "Si prega di selezionare prima una cartella di base."
#: editor/editor_dir_dialog.cpp
msgid "Choose a Directory"
-msgstr "Scegli una cartella"
+msgstr "Scegliere una cartella"
#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp editor/project_manager.cpp
#: scene/gui/file_dialog.cpp
msgid "Create Folder"
-msgstr "Crea cartella"
+msgstr "Crea una cartella"
#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
#: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp
@@ -1623,7 +1633,7 @@ msgstr "Memorizzazione file:"
#: editor/editor_export.cpp
msgid "No export template found at the expected path:"
-msgstr "Nessun modello di esportazione trovato nel percorso previsto:"
+msgstr "Nessun modello d'esportazione trovato nel percorso previsto:"
#: editor/editor_export.cpp
msgid "Packing"
@@ -1634,16 +1644,16 @@ msgid ""
"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
"Etc' in Project Settings."
msgstr ""
-"La piattaforma di destinazione richiede la compressione 'ETC' delle texture "
-"per GLES2. Attiva 'Import Etc' nelle impostazioni del progetto."
+"La piattaforma di destinazione richiede la compressione \"ETC\" delle "
+"texture per GLES2. Attiva \"Import Etc\" nelle impostazioni del progetto."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' texture compression for GLES3. Enable "
"'Import Etc 2' in Project Settings."
msgstr ""
-"La piattaforma di destinazione richiede la compressione 'ETC2' delle texture "
-"per GLES3. Attiva 'Import Etc 2' nelle impostazioni del progetto."
+"La piattaforma di destinazione richiede la compressione \"ETC2\" delle "
+"texture per GLES3. Attiva \"Import Etc 2\" nelle impostazioni del progetto."
#: editor/editor_export.cpp
msgid ""
@@ -1652,26 +1662,26 @@ msgid ""
"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
-"La piattaforma di destinazione richiede la compressione 'ETC' delle texture "
-"per il fallback del driver a GLES2.\n"
-"Attivare 'Import Etc' nelle impostazioni del progetto, oppure disattivare "
-"'Driver Fallback Enabled'."
+"La piattaforma di destinazione richiede la compressione \"ETC\" delle "
+"texture per il fallback del driver a GLES2.\n"
+"Attivare \"Import Etc\" nelle impostazioni del progetto, oppure disattivare "
+"\"Driver Fallback Enabled\"."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"La piattaforma di destinazione richiede la compressione 'PVRTC' delle "
-"texture per GLES2. Attiva 'Import Pvrtc' nelle impostazioni del progetto."
+"La piattaforma di destinazione richiede la compressione \"PVRTC\" delle "
+"texture per GLES2. Attivare \"Import Pvrtc\" nelle impostazioni del progetto."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
-"La piattaforma di destinazione richiede la compressione 'ETC2' o 'PVRTC' "
-"delle texture per GLES3. Attiva 'Import Etc 2' oppure 'Import Pvrtc' nelle "
+"La piattaforma di destinazione richiede la compressione \"ETC2\" o \"PVRTC\" "
+"delle texture per GLES3. Attivare \"Import Etc 2\" o \"Import Pvrtc\" nelle "
"impostazioni del progetto."
#: editor/editor_export.cpp
@@ -1681,31 +1691,32 @@ msgid ""
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
-"La piattaforma di destinazione richiede la compressione 'PVRTC' delle "
+"La piattaforma di destinazione richiede la compressione \"PVRTC\" delle "
"texture per il fallback del driver a GLES2.\n"
-"Attiva 'Import Pvrtc' nelle impostazioni del progetto, oppure disattiva "
-"'Driver Fallback Enabled'."
+"Attiva \"Import Pvrtc\" nelle impostazioni del progetto, oppure disattiva "
+"\"Driver Fallback Enabled\"."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
msgid "Custom debug template not found."
-msgstr "Modello di debug personalizzato non trovato."
+msgstr "Modello di sviluppo personalizzato non trovato."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
msgid "Custom release template not found."
-msgstr "Modello di release personalizzato non trovato."
+msgstr "Modello di rilascio personalizzato non trovato."
#: editor/editor_export.cpp platform/javascript/export/export.cpp
msgid "Template file not found:"
-msgstr "Modello non trovato:"
+msgstr "File del modello non trovato:"
#: editor/editor_export.cpp
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
msgstr ""
-"Su export di 32-bit il PCK integrato non può essere più grande di 4 GiB."
+"Il PCK integrato non può essere più grande di 4 GiB nelle esportazioni a 32 "
+"bit."
#: editor/editor_feature_profile.cpp
msgid "3D Editor"
@@ -1713,35 +1724,38 @@ msgstr "Editor 3D"
#: editor/editor_feature_profile.cpp
msgid "Script Editor"
-msgstr "Editor script"
+msgstr "Editor degli script"
#: editor/editor_feature_profile.cpp
+#, fuzzy
msgid "Asset Library"
msgstr "Libreria degli asset"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
-msgstr "Editor delle scene"
+msgstr "Modifica delle scene"
#: editor/editor_feature_profile.cpp
msgid "Node Dock"
-msgstr "Nodo"
+msgstr "Pannello dei nodi"
#: editor/editor_feature_profile.cpp
msgid "FileSystem Dock"
-msgstr "Riquadro FileSystem"
+msgstr "Pannello del file system"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
-msgstr "Importa"
+msgstr "Pannello d'importazione"
#: editor/editor_feature_profile.cpp
msgid "Erase profile '%s'? (no undo)"
-msgstr "Eliminare il profilo '%s'? (non annullabile)"
+msgstr "Eliminare il profilo \"%s\"? (non annullabile)"
#: editor/editor_feature_profile.cpp
+#, fuzzy
msgid "Profile must be a valid filename and must not contain '.'"
-msgstr "Il profilo deve essere un nome di file valido e non può contenere '.'"
+msgstr ""
+"Il profilo deve essere un nome di file valido e non può contenere \".\""
#: editor/editor_feature_profile.cpp
msgid "Profile with this name already exists."
@@ -1781,19 +1795,19 @@ msgstr "Classi abilitate:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
-msgstr "Il formato del file '%s' non è valido, importazione annullata."
+msgstr "Il formato del file \"%s\" non è valido, importazione annullata."
#: editor/editor_feature_profile.cpp
msgid ""
"Profile '%s' already exists. Remove it first before importing, import "
"aborted."
msgstr ""
-"Il profilo '%s' è già presente, rimuovilo prima dell'importazione. "
+"Il profilo \"%s\" è già presente, rimuoverlo prima dell'importazione. "
"Operazione annullata."
#: editor/editor_feature_profile.cpp
msgid "Error saving profile to path: '%s'."
-msgstr "Errore di salvataggio del profilo nel percorso: '%s'."
+msgstr "Errore di salvataggio del profilo nel percorso: \"%s\"."
#: editor/editor_feature_profile.cpp
msgid "Unset"
@@ -1801,7 +1815,7 @@ msgstr "Disattiva"
#: editor/editor_feature_profile.cpp
msgid "Current Profile:"
-msgstr "Profilo corrente:"
+msgstr "Profilo attuale:"
#: editor/editor_feature_profile.cpp
msgid "Make Current"
@@ -1816,7 +1830,7 @@ msgstr "Nuovo"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Importare"
+msgstr "Importazione"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -1836,23 +1850,23 @@ msgstr "Nome del nuovo profilo:"
#: editor/editor_feature_profile.cpp
msgid "Erase Profile"
-msgstr "Cancella profilo"
+msgstr "Cancella il profilo"
#: editor/editor_feature_profile.cpp
msgid "Godot Feature Profile"
-msgstr "Profilo Caratteristiche Godot"
+msgstr "Profilo di funzionalità di Godot"
#: editor/editor_feature_profile.cpp
msgid "Import Profile(s)"
-msgstr "Importa profili"
+msgstr "Importa i profili"
#: editor/editor_feature_profile.cpp
msgid "Export Profile"
-msgstr "Esporta profilo"
+msgstr "Esporta il profilo"
#: editor/editor_feature_profile.cpp
msgid "Manage Editor Feature Profiles"
-msgstr "Gestisci i profili delle funzionalità dell'editor"
+msgstr "Gestisci i profili di funzionalità dell'editor"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select Current Folder"
@@ -1868,16 +1882,16 @@ msgstr "Seleziona questa cartella"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr "Copia percorso"
+msgstr "Copia il percorso"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Open in File Manager"
-msgstr "Apri nel gestore file"
+msgstr "Apri nel gestore dei file"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
#: editor/filesystem_dock.cpp editor/project_manager.cpp
msgid "Show in File Manager"
-msgstr "Mostra nel gestore file"
+msgstr "Mostra nel gestore dei file"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "New Folder..."
@@ -1902,7 +1916,7 @@ msgstr "Apri un file"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Open File(s)"
-msgstr "Apri file"
+msgstr "Apri i file"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Open a Directory"
@@ -1937,15 +1951,15 @@ msgstr "Vai su"
#: editor/editor_file_dialog.cpp
msgid "Toggle Hidden Files"
-msgstr "Mostra/nascondi file nascosti"
+msgstr "Commuta la visibilità dei file nascosti"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr "Attiva/disattiva preferito"
+msgstr "Commuta lo stato di preferito"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
-msgstr "Commuta Modalità"
+msgstr "Commuta la modalità"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
@@ -1953,11 +1967,11 @@ msgstr "Metti a fuoco il percorso"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
-msgstr "Sposta preferito in su"
+msgstr "Sposta il preferito su"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Down"
-msgstr "Sposta preferito in giù"
+msgstr "Sposta il preferito giù"
#: editor/editor_file_dialog.cpp
msgid "Go to previous folder."
@@ -1969,23 +1983,23 @@ msgstr "Vai alla cartella successiva."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Go to parent folder."
-msgstr "Va' alla cartella superiore."
+msgstr "Vai alla cartella superiore."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Refresh files."
-msgstr "Ricarica files."
+msgstr "Ricarica i file."
#: editor/editor_file_dialog.cpp
msgid "(Un)favorite current folder."
-msgstr "Aggiungi/rimuovi cartella attuale dai preferiti."
+msgstr "Aggiungi/rimuovi la cartella attuale dai preferiti."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Toggle the visibility of hidden files."
-msgstr "Attiva/disattiva visibilità dei file nascosti."
+msgstr "Commuta la visibilità dei file nascosti."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
-msgstr "Visualizza elementi in una griglia di miniature."
+msgstr "Visualizza gli elementi in una griglia di miniature."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a list."
@@ -2014,16 +2028,17 @@ msgid ""
"There are multiple importers for different types pointing to file %s, import "
"aborted"
msgstr ""
-"Ci sono importatori multipli per tipi differenti che puntano al file %s, "
+"Esistono più importatori per tipi diversi che puntano al file %s, "
"importazione annullata"
#: editor/editor_file_system.cpp
+#, fuzzy
msgid "(Re)Importing Assets"
msgstr "Reimportazione degli asset"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
-msgstr "In alto"
+msgstr "In cima"
#: editor/editor_help.cpp
msgid "Class:"
@@ -2043,6 +2058,7 @@ msgid "Description"
msgstr "Descrizione"
#: editor/editor_help.cpp
+#, fuzzy
msgid "Online Tutorials"
msgstr "Tutorial Online"
@@ -2109,7 +2125,7 @@ msgstr "Cerca aiuto"
#: editor/editor_help_search.cpp
msgid "Case Sensitive"
-msgstr "Distinzione maiuscole/minuscole"
+msgstr "Distingui tra maiuscole e minuscole"
#: editor/editor_help_search.cpp
msgid "Show Hierarchy"
@@ -2181,7 +2197,7 @@ msgstr "Imposta"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
-msgstr "Imposta multiplo:"
+msgstr "Imposta più valori:"
#: editor/editor_log.cpp
msgid "Output:"
@@ -2202,6 +2218,7 @@ msgid "Clear"
msgstr "Rimuovi tutto"
#: editor/editor_log.cpp
+#, fuzzy
msgid "Clear Output"
msgstr "Svuota output"
@@ -2221,11 +2238,11 @@ msgstr "%s/s"
#: editor/editor_network_profiler.cpp
msgid "Down"
-msgstr "Giù"
+msgstr "In entrata"
#: editor/editor_network_profiler.cpp
msgid "Up"
-msgstr "Su"
+msgstr "In uscita"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
msgid "Node"
@@ -2262,7 +2279,7 @@ msgstr "OK"
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Error saving resource!"
-msgstr "Errore nel salvataggio della risorsa!"
+msgstr "Errore durante il salvataggio della risorsa!"
#: editor/editor_node.cpp
msgid ""
@@ -2282,7 +2299,7 @@ msgstr "Impossibile aprire il file in scrittura:"
#: editor/editor_node.cpp
msgid "Requested file format unknown:"
-msgstr "Formato file richiesto sconosciuto:"
+msgstr "Formato del file richiesto sconosciuto:"
#: editor/editor_node.cpp
msgid "Error while saving."
@@ -2291,27 +2308,28 @@ msgstr "Errore durante il salvataggio."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Can't open '%s'. The file could have been moved or deleted."
msgstr ""
-"Impossibile aprire '%s'. Il file potrebbe essere stato spostato o eliminato."
+"Impossibile aprire \"%s\". Il file potrebbe essere stato spostato o "
+"eliminato."
#: editor/editor_node.cpp
msgid "Error while parsing '%s'."
-msgstr "Errore durante l'elaborazione di '%s'."
+msgstr "Errore durante l'elaborazione di \"%s\"."
#: editor/editor_node.cpp
msgid "Unexpected end of file '%s'."
-msgstr "Fine del file '%s' non prevista."
+msgstr "Fine del file \"%s\" non prevista."
#: editor/editor_node.cpp
msgid "Missing '%s' or its dependencies."
-msgstr "'%s' mancante o dipendenze mancanti."
+msgstr "\"%s\" mancante o dipendenze mancanti."
#: editor/editor_node.cpp
msgid "Error while loading '%s'."
-msgstr "Errore durante il caricamento di '%s'."
+msgstr "Errore durante il caricamento di \"%s\"."
#: editor/editor_node.cpp
msgid "Saving Scene"
-msgstr "Salvataggio scena"
+msgstr "Salvando la scena"
#: editor/editor_node.cpp
msgid "Analyzing"
@@ -2319,7 +2337,7 @@ msgstr "Analizzando"
#: editor/editor_node.cpp
msgid "Creating Thumbnail"
-msgstr "Creazione miniature"
+msgstr "Creando la miniatura"
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
@@ -2345,11 +2363,11 @@ msgstr ""
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "Can't overwrite scene that is still open!"
-msgstr "Impossibile sovrascrivere una scena che è ancora aperta!"
+msgstr "Impossibile sovrascrivere una scena ancora aperta!"
#: editor/editor_node.cpp
msgid "Can't load MeshLibrary for merging!"
-msgstr "Impossibile caricare MeshLibrary per l'unione!"
+msgstr "Impossibile caricare la MeshLibrary per l'unione!"
#: editor/editor_node.cpp
msgid "Error saving MeshLibrary!"
@@ -2357,7 +2375,7 @@ msgstr "Errore nel salvataggio della MeshLibrary!"
#: editor/editor_node.cpp
msgid "Can't load TileSet for merging!"
-msgstr "Impossibile caricare TileSet per unione!"
+msgstr "Impossibile caricare il TileSet per unione!"
#: editor/editor_node.cpp
msgid "Error saving TileSet!"
@@ -2368,9 +2386,9 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
-"Si è verificato un errore mentre si stava provando a salvare il layout "
-"dell'editor.\n"
-"Assicurati che il percorso dati dell'editor dell'utente sia scrivibile."
+"Si è verificato un errore durante un tentativo di salvataggio della "
+"disposizione dell'editor.\n"
+"Assicurarsi che il percorso dei dati dell'editor dell'utente sia scrivibile."
#: editor/editor_node.cpp
msgid ""
@@ -2378,9 +2396,9 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
-"Layout predefinito dell'editor sovrascritto.\n"
-"Per ripristinare il layout predefinito alle impostazioni di base, usare "
-"l'opzione elimina layout ed eliminare il layout predefinito."
+"Disposzione predefinita dell'editor sovrascritta.\n"
+"Per ripristinare la disposizione predefinita alle sue impostazioni di base, "
+"usare l'opzione elimina layout ed eliminare la disposizione predefinita."
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -2388,7 +2406,7 @@ msgstr "Nome della disposizione non trovato!"
#: editor/editor_node.cpp
msgid "Restored the Default layout to its base settings."
-msgstr "Ripristinato il layout default alle impostazioni base."
+msgstr "Ripristinata la disposzione predefinita alle sue impostazioni di base."
#: editor/editor_node.cpp
msgid ""
@@ -2398,8 +2416,8 @@ msgid ""
msgstr ""
"Questa risorsa appartiene a una scena che è stata importata, di conseguenza "
"non è modificabile.\n"
-"Si consiglia di leggere la documentazione riguardante l'importazione delle "
-"scene per comprendere al meglio questo workflow."
+"Si prega di leggere la documentazione relativa all'importazione delle scene "
+"per capire meglio questa prassi."
#: editor/editor_node.cpp
msgid ""
@@ -2407,15 +2425,15 @@ msgid ""
"Changes to it won't be kept when saving the current scene."
msgstr ""
"Questa risorsa appartiene a una scena istanziata o ereditata.\n"
-"Le modifiche ad essa non verranno mantenute salvando la scena corrente."
+"Essa perderà qualsiasi modifica al salvataggio della scena corrente."
#: editor/editor_node.cpp
msgid ""
"This resource was imported, so it's not editable. Change its settings in the "
"import panel and then re-import."
msgstr ""
-"Questa risorsa è stata importata, non è quindi modificabile. Modificane le "
-"impostazioni nel pannello di importazione e re-importala."
+"Questa risorsa è stata importata e non è quindi modificabile. Modificare le "
+"sue impostazioni nel pannello d'importazione e re-importarla."
#: editor/editor_node.cpp
msgid ""
@@ -2424,11 +2442,10 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
-"Questa scena è stata importata, pertanto i cambiamenti ad essa non verranno "
-"mantenuti.\n"
-"Istanziarla o ereditarla permetterà di modificarla.\n"
-"Si consiglia di leggere la documentazione relativa all'importazione delle "
-"scene per comprendere meglio questo workflow."
+"Questa scena è stata importata, perciò qualsiasi sua modifica verrà persa.\n"
+"Per modificarla, Istanziarla o ereditarla.\n"
+"Si prega di leggere la documentazione relativa all'importazione delle scene "
+"per capire meglio questa prassi."
#: editor/editor_node.cpp
msgid ""
@@ -2436,10 +2453,9 @@ msgid ""
"Please read the documentation relevant to debugging to better understand "
"this workflow."
msgstr ""
-"Questa risorsa appartiene a una scena che è stata importata, di conseguenza "
-"non è modificabile.\n"
-"Si consiglia di leggere la documentazione riguardante l'importazione delle "
-"scene per comprendere al meglio questo workflow."
+"Questo è un oggetto remoto, perciò qualsiasi sua modifica verrà persa.\n"
+"Si prega di leggere la documentazione relativa al debug per capire meglio "
+"questa prassi."
#: editor/editor_node.cpp
msgid "There is no defined scene to run."
@@ -2455,19 +2471,19 @@ msgstr "Impossibile avviare il sottoprocesso!"
#: editor/editor_node.cpp editor/filesystem_dock.cpp
msgid "Open Scene"
-msgstr "Apri scena"
+msgstr "Apri una scena"
#: editor/editor_node.cpp
msgid "Open Base Scene"
-msgstr "Apri scena di base"
+msgstr "Apri una scena di base"
#: editor/editor_node.cpp
msgid "Quick Open..."
-msgstr "Apri scena rapidamente…"
+msgstr "Apri rapidamente…"
#: editor/editor_node.cpp
msgid "Quick Open Scene..."
-msgstr "Apri scena rapidamente…"
+msgstr "Apri una scena rapidamente…"
#: editor/editor_node.cpp
msgid "Quick Open Script..."
@@ -2479,11 +2495,11 @@ msgstr "Salva e chiudi"
#: editor/editor_node.cpp
msgid "Save changes to '%s' before closing?"
-msgstr "Salvare le modifiche a '%s' prima di chiudere?"
+msgstr "Salvare le modifiche a \"%s\" prima di chiudere?"
#: editor/editor_node.cpp
msgid "Saved %s modified resource(s)."
-msgstr "Salvata(e) %s risorsa(e) modificata(e)."
+msgstr "Salvate %s risorse modificate."
#: editor/editor_node.cpp
msgid "A root node is required to save the scene."
@@ -2491,7 +2507,7 @@ msgstr "È necessario un nodo radice per salvare la scena."
#: editor/editor_node.cpp
msgid "Save Scene As..."
-msgstr "Salva scena come…"
+msgstr "Salva la scena come…"
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "This operation can't be done without a scene."
@@ -2499,7 +2515,7 @@ msgstr "Questa operazione non può essere eseguita senza una scena."
#: editor/editor_node.cpp
msgid "Export Mesh Library"
-msgstr "Esporta libreria di Mesh"
+msgstr "Esporta una libreria di Mesh"
#: editor/editor_node.cpp
msgid "This operation can't be done without a root node."
@@ -2507,7 +2523,7 @@ msgstr "Questa operazione non può essere eseguita senza un nodo radice."
#: editor/editor_node.cpp
msgid "Export Tile Set"
-msgstr "Esporta Tile Set"
+msgstr "Esporta una collezione di tasselli"
#: editor/editor_node.cpp
msgid "This operation can't be done without a selected node."
@@ -2523,19 +2539,19 @@ msgstr "Impossibile ricaricare una scena che non è mai stata salvata."
#: editor/editor_node.cpp
msgid "Reload Saved Scene"
-msgstr "Ricarica scena salvata"
+msgstr "Ricarica la scena salvata"
#: editor/editor_node.cpp
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
-"La scena attuale ha dei cambiamenti non salvati.\n"
+"La scena attuale ha delle modifiche non salvate.\n"
"Ricaricare comunque la scena salvata? Questa azione non può essere annullata."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
-msgstr "Esegui scena rapidamente…"
+msgstr "Esegui la scena rapidamente…"
#: editor/editor_node.cpp
msgid "Quit"
@@ -2551,7 +2567,7 @@ msgstr "Uscire dall'editor?"
#: editor/editor_node.cpp
msgid "Open Project Manager?"
-msgstr "Aprire il gestore dei progetti?"
+msgstr "Aprire il gestore di progetti?"
#: editor/editor_node.cpp
msgid "Save & Quit"
@@ -2564,7 +2580,7 @@ msgstr "Salvare le modifiche alle scene seguenti prima di uscire?"
#: editor/editor_node.cpp
msgid "Save changes the following scene(s) before opening Project Manager?"
msgstr ""
-"Salvare le modifiche alle scene seguenti prima di aprire il gestore dei "
+"Salvare le modifiche alle scene seguenti prima di aprire il gestore di "
"progetti?"
#: editor/editor_node.cpp
@@ -2572,16 +2588,16 @@ msgid ""
"This option is deprecated. Situations where refresh must be forced are now "
"considered a bug. Please report."
msgstr ""
-"Questa opzione è deprecata. Situazioni in cui si è obbligati a ricaricare "
-"sono ora considerate errori. Si prega di segnalarlo."
+"Questa opzione è deprecata. Le situazioni in cui si è obbligati a ricaricare "
+"sono ora considerate falle. Si prega di segnalarle."
#: editor/editor_node.cpp
msgid "Pick a Main Scene"
-msgstr "Scegli una scena principale"
+msgstr "Scegliere una scena principale"
#: editor/editor_node.cpp
msgid "Close Scene"
-msgstr "Chiudi scena"
+msgstr "Chiudi la scena"
#: editor/editor_node.cpp
msgid "Reopen Closed Scene"
@@ -2590,47 +2606,48 @@ msgstr "Riapri la scena chiusa"
#: editor/editor_node.cpp
msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
-"Impossibile abilitare il componente aggiuntivo in: '%s' lettura della "
-"configurazione fallita."
+"Impossibile abilitare l'estensione in \"%s\". Lettura della configurazione "
+"fallita."
#: editor/editor_node.cpp
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr ""
-"Impossibile trovare il campo script per il plugin addon in posizione: '%s'."
+msgstr "Impossibile trovare il campo dello script per l'estensione in: \"%s\"."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
msgstr ""
-"Impossibile caricare lo script di un componente aggiuntivo dal percorso: "
-"'%s'."
+"Impossibile caricare lo script di un componente aggiuntivo dal percorso: \"%s"
+"\"."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"Impossibile caricare uno script aggiuntivo dal percorso: '%s' Sembra esserci "
-"un errore nel codice, controlla la sintassi."
+"Impossibile caricare uno script aggiuntivo dal percorso: \"%s\" Sembra "
+"esserci un errore nel codice, controlla la sintassi.\n"
+"Disabilitata l'aggiunta di '%s' per prevenire ulteriori errori."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
-"Impossibile caricare uno script aggiuntivo dal percorso: La tipologia di "
-"base di '%s' non è EditorPlugin."
+"Impossibile caricare uno script di estensione dal percorso: il tipo base di "
+"\"%s\" non è EditorPlugin."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
msgstr ""
-"Impossibile caricare lo script di un componente aggiuntivo dal percorso: "
-"'%s' Lo script non è in modalità strumento."
+"Impossibile caricare lo script di un componente aggiuntivo dal percorso: \"%s"
+"\" Lo script non è in modalità strumento."
#: editor/editor_node.cpp
msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
-"La scena '%s' è stata automaticamente importata, pertanto non può essere "
+"La scena \"%s\" è stata automaticamente importata, pertanto non può essere "
"modificata.\n"
"Per modificarla, può essere creata una nuova scena ereditata."
@@ -2640,12 +2657,12 @@ msgid ""
"open the scene, then save it inside the project path."
msgstr ""
"Errore di caricamento della scena, deve essere all'interno del percorso del "
-"progetto. Usare 'Importa' per aprire la scena e salvarla nel percorso del "
+"progetto. Usare \"Importa\" per aprire la scena e salvarla nel percorso del "
"progetto."
#: editor/editor_node.cpp
msgid "Scene '%s' has broken dependencies:"
-msgstr "La scena '%s' ha rotto le dipendenze:"
+msgstr "La scena \"%s\" ha rotto le dipendenze:"
#: editor/editor_node.cpp
msgid "Clear Recent Scenes"
@@ -2659,7 +2676,7 @@ msgid ""
msgstr ""
"Non è stata definita alcuna scena principale, selezionarne una?\n"
"Potrai cambiarla successivamente da \"Impostazioni progetto\" sotto la "
-"categoria 'applicazioni'."
+"categoria \"applicazioni\"."
#: editor/editor_node.cpp
msgid ""
@@ -2667,9 +2684,9 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
-"La scena selezionata '%s' non esiste, sceglierne una valida?\n"
+"La scena selezionata \"%s\" non esiste, sceglierne una valida?\n"
"Puoi cambiarla successivamente da \"Impostazioni progetto\" sotto la "
-"categoria 'applicazioni'."
+"categoria \"applicazioni\"."
#: editor/editor_node.cpp
msgid ""
@@ -2677,9 +2694,9 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
-"La scena selezionata '%s non è un file scena, sceglierne una valida?\n"
+"La scena selezionata \"%s non è un file scena, sceglierne una valida?\n"
"Puoi cambiarla successivamente da \"Impostazioni progetto\" sotto la "
-"categoria 'applicazioni'."
+"categoria \"applicazioni\"."
#: editor/editor_node.cpp
msgid "Save Layout"
@@ -2701,15 +2718,15 @@ msgstr "Mostra nel filesystem"
#: editor/editor_node.cpp
msgid "Play This Scene"
-msgstr "Esegui Scena"
+msgstr "Esegui questa scena"
#: editor/editor_node.cpp
msgid "Close Tab"
-msgstr "Chiudi scheda"
+msgstr "Chiudi la scheda"
#: editor/editor_node.cpp
msgid "Undo Close Tab"
-msgstr "Annulla Chiusura Tab"
+msgstr "Annulla la chiusura di una scheda"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Close Other Tabs"
@@ -2717,15 +2734,15 @@ msgstr "Chiudi le altre schede"
#: editor/editor_node.cpp
msgid "Close Tabs to the Right"
-msgstr "Chiudi le Schede a Destra"
+msgstr "Chiudi le schede a destra"
#: editor/editor_node.cpp
msgid "Close All Tabs"
-msgstr "Chiudi Tutte le Schede"
+msgstr "Chiudi tutte le schede"
#: editor/editor_node.cpp
msgid "Switch Scene Tab"
-msgstr "Cambia Tab di Scena"
+msgstr "Cambia la scheda di una scena"
#: editor/editor_node.cpp
msgid "%d more files or folders"
@@ -2741,7 +2758,7 @@ msgstr "%d altri file"
#: editor/editor_node.cpp
msgid "Dock Position"
-msgstr "Posizione Dock"
+msgstr "Posizione del pannello"
#: editor/editor_node.cpp
msgid "Distraction Free Mode"
@@ -2749,11 +2766,11 @@ msgstr "Modalità senza distrazioni"
#: editor/editor_node.cpp
msgid "Toggle distraction-free mode."
-msgstr "Commuta modalità senza distrazioni."
+msgstr "Commuta la modalità senza distrazioni."
#: editor/editor_node.cpp
msgid "Add a new scene."
-msgstr "Aggiungi nuova scena."
+msgstr "Aggiungi una nuova scena."
#: editor/editor_node.cpp
msgid "Scene"
@@ -2761,11 +2778,11 @@ msgstr "Scena"
#: editor/editor_node.cpp
msgid "Go to previously opened scene."
-msgstr "Vai alla scena precedentemente aperta."
+msgstr "Va alla scena precedentemente aperta."
#: editor/editor_node.cpp
msgid "Copy Text"
-msgstr "Copia Testo"
+msgstr "Copia il testo"
#: editor/editor_node.cpp
msgid "Next tab"
@@ -2777,7 +2794,7 @@ msgstr "Scheda precedente"
#: editor/editor_node.cpp
msgid "Filter Files..."
-msgstr "Filtra file..."
+msgstr "Filtra i file..."
#: editor/editor_node.cpp
msgid "Operations with scene files."
@@ -2793,15 +2810,15 @@ msgstr "Nuova scena ereditata..."
#: editor/editor_node.cpp
msgid "Open Scene..."
-msgstr "Apri scena..."
+msgstr "Apri una scena..."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Open Recent"
-msgstr "Apri recente"
+msgstr "Apri una scena recente"
#: editor/editor_node.cpp
msgid "Save Scene"
-msgstr "Salva scena"
+msgstr "Salva la scena"
#: editor/editor_node.cpp
msgid "Save All Scenes"
@@ -2813,7 +2830,7 @@ msgstr "Converti in..."
#: editor/editor_node.cpp
msgid "MeshLibrary..."
-msgstr "Libreria delle Mesh..."
+msgstr "MeshLibrary..."
#: editor/editor_node.cpp
msgid "TileSet..."
@@ -2840,19 +2857,19 @@ msgstr "Progetto"
#: editor/editor_node.cpp
msgid "Project Settings..."
-msgstr "Impostazioni progetto…"
+msgstr "Impostazioni del progetto…"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control"
-msgstr "Controllo Versione"
+msgstr "Controllo della versione"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
-msgstr "Imposta Controllo Versione"
+msgstr "Imposta il controllo della versione"
#: editor/editor_node.cpp
msgid "Shut Down Version Control"
-msgstr "Arresta Controllo Versione"
+msgstr "Arresta il controllo della versione"
#: editor/editor_node.cpp
msgid "Export..."
@@ -2860,7 +2877,7 @@ msgstr "Esporta..."
#: editor/editor_node.cpp
msgid "Install Android Build Template..."
-msgstr "Installa il Modello di Costruzione di Android…"
+msgstr "Installa il modello di costruzione per Android…"
#: editor/editor_node.cpp
msgid "Open Project Data Folder"
@@ -2872,11 +2889,11 @@ msgstr "Strumenti"
#: editor/editor_node.cpp
msgid "Orphan Resource Explorer..."
-msgstr "Explorer Risorse Orfane…"
+msgstr "Explorer di risorse orfane…"
#: editor/editor_node.cpp
msgid "Quit to Project List"
-msgstr "Esci e torna alla lista progetti"
+msgstr "Esci e torna alla lista dei progetti"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/project_export.cpp
@@ -2885,7 +2902,7 @@ msgstr "Debug"
#: editor/editor_node.cpp
msgid "Deploy with Remote Debug"
-msgstr "Distribuisci con Debug remoto"
+msgstr "Distribuisci con debug remoto"
#: editor/editor_node.cpp
msgid ""
@@ -2896,16 +2913,16 @@ msgid ""
"mobile device).\n"
"You don't need to enable it to use the GDScript debugger locally."
msgstr ""
-"Quando questa opzione è abilitata, usare il deploy one-click farà tentare "
-"l'eseguibile di connettersi all'indirizzo IP di questo computer permettendo "
-"il debug del progetto in esecuzione .\n"
-"L'intesa di questa opzione è quella di essere usata per il debug remoto "
-"(normalmente un dispositivo mobile).\n"
-"Non c'è bisogno di abilitarla se utilizzi il debugger GDScript normale."
+"Quando questa opzione è abilitata, usare il rilascio in un click farà "
+"tentare all'eseguibile di connettersi all'indirizzo IP di questo computer "
+"permettendo il debug del progetto in esecuzione.\n"
+"Questa opzione è intesa per essere usata per il debug remoto (solitamente "
+"con un dispositivo mobile).\n"
+"Non c'è bisogno di abilitarla se si usa il debugger per GDScript in locale."
#: editor/editor_node.cpp
msgid "Small Deploy with Network Filesystem"
-msgstr "Small Deploy con Filesystem della rete"
+msgstr "Rilascio piccolo con un filesystem di rete"
#: editor/editor_node.cpp
msgid ""
@@ -2916,11 +2933,11 @@ msgid ""
"On Android, deploying will use the USB cable for faster performance. This "
"option speeds up testing for projects with large assets."
msgstr ""
-"Quando questa impostazione è abilitata, usare il deploy one-click per "
-"Android esporterà soltanto un eseguibile senza i dati del progetto.\n"
-"Il filesystem sarà provvisto dal progetto dell'editor nella rete.\n"
-"Su Android, il deploy userà il cavo USB per performance migliori. Questa "
-"impostazione rende i progetti con asset pesanti più veloci."
+"Quando questa impostazione è abilitata, il rilascio in un click per Android "
+"esporterà un eseguibile senza i dati del progetto.\n"
+"Il filesystem verrà provvisto dall'editor attraverso la rete.\n"
+"Su Android, esso userà il cavo USB per ottenere delle prestazioni migliori. "
+"Questa impostazione rende più veloci i progetti con risorse pesanti."
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
@@ -2931,24 +2948,24 @@ msgid ""
"When this option is enabled, collision shapes and raycast nodes (for 2D and "
"3D) will be visible in the running project."
msgstr ""
-"Quando questa opzione è abilitata, le forme di collisione ed i nodi raycast "
-"(per il 2D e 3D) sarrano visibili nel progetto in esecuzione."
+"Quando questa opzione è abilitata, le forme di collisione e i nodi RayCast "
+"(sia 2D che 3D) sarrano visibili nel progetto in esecuzione."
#: editor/editor_node.cpp
msgid "Visible Navigation"
-msgstr "Navigazione Visibile"
+msgstr "Navigazione visibile"
#: editor/editor_node.cpp
msgid ""
"When this option is enabled, navigation meshes and polygons will be visible "
"in the running project."
msgstr ""
-"Quando questa opzione è abilitata, le mesh di navigazione ed i poligoni "
+"Quando questa opzione è abilitata, le mesh di navigazione e i poligoni "
"saranno visibili nel progetto in esecuzione."
#: editor/editor_node.cpp
msgid "Synchronize Scene Changes"
-msgstr "Sincronizza Cambi Scena"
+msgstr "Sincronizza i cambi della scena"
#: editor/editor_node.cpp
msgid ""
@@ -2958,8 +2975,8 @@ msgid ""
"filesystem option is enabled."
msgstr ""
"Quando questa opzione è abilitata, ogni modifica fatta alla scena "
-"nell'editor sarà replicata nel progetto in esecuzione.\n"
-"Quando usata in remoto su un dispositivo, si può aumentare l'efficacia "
+"nell'editor verrà replicata nel progetto in esecuzione.\n"
+"Quando usata in remoto su un dispositivo, essa risulta più efficiente "
"abilitando l'opzione \"network filesystem\"."
#: editor/editor_node.cpp
@@ -2973,10 +2990,10 @@ msgid ""
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
-"Quando questa opzione è abilitata, qualsiasi script salvato sarà ricaricato "
+"Quando questa opzione è abilitata, qualsiasi script salvato verrà ricaricato "
"nel progetto in esecuzione.\n"
-"Quando usato in remoto su un dispositivo, si potrà aumentarne l'efficacia "
-"abilitando anche l'opzione \"network filesystem\"."
+"Quando usato in remoto su un dispositivo, essa risulta più efficate "
+"abilitando l'opzione \"network filesystem\"."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
@@ -2984,40 +3001,42 @@ msgstr "Editor"
#: editor/editor_node.cpp
msgid "Editor Settings..."
-msgstr "Impostazioni editor…"
+msgstr "Impostazioni dell'editor…"
#: editor/editor_node.cpp
msgid "Editor Layout"
msgstr "Disposizione dell'editor"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Take Screenshot"
msgstr "Acquisisci una schermata"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Screenshots are stored in the Editor Data/Settings Folder."
msgstr ""
"Gli screenshot vengono memorizzati nella cartella Data/Settings dell'editor."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "Abilita/Disabilita modalità a schermo intero"
+msgstr "Commuta la modalità a schermo intero"
#: editor/editor_node.cpp
msgid "Toggle System Console"
-msgstr "Abilita/Disabilita la console di sistema"
+msgstr "Commuta la console di sistema"
#: editor/editor_node.cpp
msgid "Open Editor Data/Settings Folder"
-msgstr "Apri cartella dati/impostazioni editor"
+msgstr "Apri cartella dei dati/impostazioni editor"
#: editor/editor_node.cpp
msgid "Open Editor Data Folder"
-msgstr "Apri la Cartella dei Dati dell'Editor"
+msgstr "Apri la cartella dei dati dell'editor"
#: editor/editor_node.cpp
msgid "Open Editor Settings Folder"
-msgstr "Apri cartella impostazioni editor"
+msgstr "Apri la cartella delle impostazioni editor"
#: editor/editor_node.cpp
msgid "Manage Editor Features..."
@@ -3025,7 +3044,7 @@ msgstr "Gestisci le funzionalità dell'editor…"
#: editor/editor_node.cpp
msgid "Manage Export Templates..."
-msgstr "Gestisci Modello d'Esportazione…"
+msgstr "Gestisci i modelli d'esportazione…"
#: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp
msgid "Help"
@@ -3033,6 +3052,7 @@ msgstr "Aiuto"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
+#, fuzzy
msgid "Online Docs"
msgstr "Documentazione online"
@@ -3046,7 +3066,7 @@ msgstr "Segnala un problema"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
-msgstr "Valuta documentazione"
+msgstr "Valuta la documentazione"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
@@ -3057,6 +3077,10 @@ msgid "About"
msgstr "Informazioni su Godot"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Supporta lo sviluppo di Godot"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Esegui il progetto."
@@ -3078,19 +3102,19 @@ msgstr "Ferma la scena."
#: editor/editor_node.cpp
msgid "Play the edited scene."
-msgstr "Esegui la scena in modifica."
+msgstr "Esegui la scena modificata."
#: editor/editor_node.cpp
msgid "Play Scene"
-msgstr "Esegui scena"
+msgstr "Esegui la scena"
#: editor/editor_node.cpp
msgid "Play custom scene"
-msgstr "Esegui scena personalizzata"
+msgstr "Avvia una scena personalizzata"
#: editor/editor_node.cpp
msgid "Play Custom Scene"
-msgstr "Avvia scena personalizzata"
+msgstr "Avvia una scena personalizzata"
#: editor/editor_node.cpp
msgid "Changing the video driver requires restarting the editor."
@@ -3111,11 +3135,11 @@ msgstr "Aggiorna continuamente"
#: editor/editor_node.cpp
msgid "Update When Changed"
-msgstr "Aggiorna quando modificato"
+msgstr "Aggiorna quando modificata"
#: editor/editor_node.cpp
msgid "Hide Update Spinner"
-msgstr "Disabilita l'icona girevole di aggiornamento"
+msgstr "Nascondi la rotella di aggiornamento"
#: editor/editor_node.cpp
msgid "FileSystem"
@@ -3127,7 +3151,7 @@ msgstr "Ispettore"
#: editor/editor_node.cpp
msgid "Expand Bottom Panel"
-msgstr "Espandi Pannello Inferiore"
+msgstr "Espandi il pannello inferiore"
#: editor/editor_node.cpp
msgid "Output"
@@ -3138,9 +3162,10 @@ msgid "Don't Save"
msgstr "Non salvare"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Android build template is missing, please install relevant templates."
msgstr ""
-"Modello build di Android non è presente, si prega di installare i modelli "
+"Modello di costruzione di Android mancante, si prega di installare i modelli "
"rilevanti."
#: editor/editor_node.cpp
@@ -3157,14 +3182,14 @@ msgid ""
"the \"Use Custom Build\" option should be enabled in the Android export "
"preset."
msgstr ""
-"Questo predisporrà il progetto per le build personalizzate per Android "
-"installando i template sorgente in \"res://android/build\".\n"
-"Potrai allora applicare le modifiche e costruire il tuo APK personalizzato "
-"durante l'esportazione (aggiungere moduli, cambiare l'AndroidManifest.xml, "
-"eccetera).\n"
-"Nota che per creare delle build personalizzate, invece di usare gli APK pre-"
-"costruiti, l'opzione \"Use Custom Build\" va attivata nella preimpostazione "
-"d'esportazione per Android."
+"Questo predisporrà il progetto alle costruzioni personalizzate per Android "
+"installando il modello di sorgente in \"res://android/build\".\n"
+"Sarà allora possibile applicare delle modifiche e costruire un APK "
+"personalizzato durante l'esportazione (aggiungere moduli, cambiare "
+"l'AndroidManifest.xml, eccetera).\n"
+"Va notato che per creare delle costruzioni personalizzate, invece di usare "
+"gli APK pre-costruiti, va attivata l'opzione \"Use Custom Build\" nella "
+"preimpostazione d'esportazione per Android."
#: editor/editor_node.cpp
msgid ""
@@ -3173,18 +3198,18 @@ msgid ""
"Remove the \"res://android/build\" directory manually before attempting this "
"operation again."
msgstr ""
-"Il template della build Android è già installato in questo progetto e non "
-"verrà sovrascritto.\n"
-"Rimuovi manualmente la cartella \"res://android/build\" prima di ritentare "
+"Il modello di costruzione per Android è già installato in questo progetto e "
+"non verrà sovrascritto.\n"
+"Rimuovere manualmente la cartella \"res://android/build\" prima di ritentare "
"questa operazione."
#: editor/editor_node.cpp
msgid "Import Templates From ZIP File"
-msgstr "Importa Template Da File ZIP"
+msgstr "Importa i modelli da un file ZIP"
#: editor/editor_node.cpp
msgid "Template Package"
-msgstr "Pacchetto Template"
+msgstr "Pacchetto di modelli"
#: editor/editor_node.cpp
msgid "Export Library"
@@ -3274,11 +3299,11 @@ msgstr "Script Principale:"
#: editor/editor_plugin_settings.cpp
msgid "Edit Plugin"
-msgstr "Modifica Plugin"
+msgstr "Modifica estensione"
#: editor/editor_plugin_settings.cpp
msgid "Installed Plugins:"
-msgstr "Plugins Installati:"
+msgstr "Estensioni installate:"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
msgid "Update"
@@ -3488,7 +3513,7 @@ msgstr "Impossibile istanziare script:"
#: editor/editor_run_script.cpp
msgid "Did you forget the 'tool' keyword?"
-msgstr "Hai dimenticato la keyword 'tool'?"
+msgstr "Hai dimenticato la keyword \"tool\"?"
#: editor/editor_run_script.cpp
msgid "Couldn't run script:"
@@ -3496,7 +3521,7 @@ msgstr "Impossibile eseguire lo script:"
#: editor/editor_run_script.cpp
msgid "Did you forget the '_run' method?"
-msgstr "Hai dimenticato il metodo '_run'?"
+msgstr "Hai dimenticato il metodo \"_run\"?"
#: editor/editor_spin_slider.cpp
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
@@ -3557,7 +3582,7 @@ msgstr "Recupero dei mirror, attendi..."
#: editor/export_template_manager.cpp
msgid "Remove template version '%s'?"
-msgstr "Rimuovere versione '%s' del template?"
+msgstr "Rimuovere versione \"%s\" del template?"
#: editor/export_template_manager.cpp
msgid "Can't open export templates zip."
@@ -3643,7 +3668,7 @@ msgid ""
"The problematic templates archives can be found at '%s'."
msgstr ""
"Installazione del template fallita.\n"
-"Gli archivi dei template problematici possono essere trovati qui: '%s'."
+"Gli archivi dei template problematici possono essere trovati qui: \"%s\"."
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
@@ -3749,6 +3774,8 @@ msgstr ""
msgid ""
"Importing has been disabled for this file, so it can't be opened for editing."
msgstr ""
+"L'importazione è stata disabilitata per questo file, perciò non possiamo "
+"aprirlo per modificarlo."
#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
@@ -3796,7 +3823,7 @@ msgid ""
"Do you wish to overwrite them?"
msgstr ""
"I seguenti file o cartelle vanno in conflitto con gli oggetti nel percorso "
-"di destinazione '%s':\n"
+"di destinazione \"%s\":\n"
"\n"
"%s\n"
"\n"
@@ -3898,11 +3925,11 @@ msgstr "Cartella/File successivo"
#: editor/filesystem_dock.cpp
msgid "Re-Scan Filesystem"
-msgstr "Re-Scan Filesystem"
+msgstr "Riscansiona il Filesystem"
#: editor/filesystem_dock.cpp
msgid "Toggle Split Mode"
-msgstr "Attiva/disattiva la modalità Split"
+msgstr "Commuta la modalità divisa"
#: editor/filesystem_dock.cpp
msgid "Search files"
@@ -3970,7 +3997,7 @@ msgstr "Trova..."
#: editor/find_in_files.cpp editor/plugins/script_text_editor.cpp
msgid "Replace..."
-msgstr "Rimpiazza..."
+msgstr "Sostituisci..."
#: editor/find_in_files.cpp editor/progress_dialog.cpp scene/gui/dialogs.cpp
msgid "Cancel"
@@ -4153,7 +4180,7 @@ msgstr "Ripristinare le impostazioni predefinite"
#: editor/import_dock.cpp
msgid "Keep File (No Import)"
-msgstr ""
+msgstr "Mantieni il file ( Non importare)"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -4161,11 +4188,11 @@ msgstr "%d File"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
-msgstr "Imposta come Predefinito per '%s'"
+msgstr "Imposta come Predefinito per \"%s\""
#: editor/import_dock.cpp
msgid "Clear Default for '%s'"
-msgstr "Elimina Predefinito per '%s'"
+msgstr "Elimina Predefinito per \"%s\""
#: editor/import_dock.cpp
msgid "Import As:"
@@ -4217,7 +4244,7 @@ msgstr "Copia parametri"
#: editor/inspector_dock.cpp
msgid "Edit Resource Clipboard"
-msgstr "Modifica Appunti Risorse"
+msgstr "Modifica gli appunti delle risorse"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
@@ -4281,15 +4308,15 @@ msgstr "Seleziona un singolo nodo per eliminare i suoi segnali e gruppi."
#: editor/plugin_config_dialog.cpp
msgid "Edit a Plugin"
-msgstr "Modifica un Plugin"
+msgstr "Modifica un'estensione"
#: editor/plugin_config_dialog.cpp
msgid "Create a Plugin"
-msgstr "Crea un Plugin"
+msgstr "Crea un'estensione"
#: editor/plugin_config_dialog.cpp
msgid "Plugin Name:"
-msgstr "Nome Plugin:"
+msgstr "Nome dell'estensione:"
#: editor/plugin_config_dialog.cpp
msgid "Subfolder:"
@@ -4429,7 +4456,7 @@ msgstr ""
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
msgid "Enable snap and show grid."
-msgstr "Attiva lo snap e mostra la griglia."
+msgstr "Abilita lo scatto e mostra la griglia."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4483,7 +4510,7 @@ msgstr "Non esistono triangoli, non può quindi aver luogo alcun blending."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Toggle Auto Triangles"
-msgstr "Attiva Triangolazione Automatica"
+msgstr "Attiva la triangolazione automatica"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Create triangles by connecting points."
@@ -4555,7 +4582,7 @@ msgstr "Elimina Nodo(i)"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Toggle Filter On/Off"
-msgstr "Attiva/Disattiva il Filtro"
+msgstr "Commuta il filtro"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Change Filter"
@@ -4584,11 +4611,11 @@ msgstr ""
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Anim Clips"
-msgstr "Clip d'animazione"
+msgstr "Segmenti d'animazione"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Audio Clips"
-msgstr "Clip Audio"
+msgstr "Segmenti audio"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Functions"
@@ -4615,7 +4642,7 @@ msgstr "Abilita filtraggio"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Toggle Autoplay"
-msgstr "Abilità Autoplay"
+msgstr "Commuta la riproduzione automatica"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "New Animation Name:"
@@ -4902,8 +4929,8 @@ msgstr "Rimuovi il nodo o la transizione selezionati."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Toggle autoplay this animation on start, restart or seek to zero."
msgstr ""
-"Attiva/disattiva la riproduzione automatica di questa animazione all'avvio, "
-"riavvio, o il riavvolgimento a zero."
+"Commuta la riproduzione automatica di questa animazione all'avvio, riavvio, "
+"o il riavvolgimento a zero."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set the end animation. This is useful for sub-transitions."
@@ -5224,7 +5251,7 @@ msgstr "Importa…"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Plugins..."
-msgstr "Plugins…"
+msgstr "Estensioni…"
#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
msgid "Sort:"
@@ -5273,7 +5300,7 @@ msgid ""
"Light' flag is on."
msgstr ""
"Nessuna mesh da preprocessare. Assicurarsi che contengano un canale UV2 e "
-"che la spunta 'Bake Light' sia abilitata."
+"che la spunta \"Bake Light\" sia abilitata."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed creating lightmap images, make sure path is writable."
@@ -5296,6 +5323,7 @@ msgstr ""
"all'interno nella regione [0.0,1.0] quadra."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
+#, fuzzy
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
@@ -5316,12 +5344,13 @@ msgid "Preview"
msgstr "Anteprima"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Configure Snap"
-msgstr "Configura Snap"
+msgstr "Configura lo scatto"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
-msgstr "Offset Griglia:"
+msgstr "Scostamento della griglia:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Step:"
@@ -5337,7 +5366,7 @@ msgstr "passi"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Offset:"
-msgstr "Offset Rotazione:"
+msgstr "Scostamento della rotazione:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Step:"
@@ -5345,7 +5374,7 @@ msgstr "Passo di rotazione:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Step:"
-msgstr "Passo di scala:"
+msgstr "Passo della scala:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move Vertical Guide"
@@ -5376,8 +5405,9 @@ msgid "Create Horizontal and Vertical Guides"
msgstr "Crea Guide Orizzontali e Verticali"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr "Imposta Pivot Offset CanvasItem \"%s\" a (%d, %d)"
+msgstr "Imposta lo scostamento del Pivot del CanvasItem \"%s\" a (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotate %d CanvasItems"
@@ -5607,8 +5637,8 @@ msgstr "Alt+Drag: Muovi"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving)."
msgstr ""
-"Premi 'v' per Cambiare Perno, 'Shift+v' per Trascinare il Pernno (durante lo "
-"spostamento)."
+"Premi \"v\" per Cambiare Perno, \"Shift+v\" per Trascinare il Pernno "
+"(durante lo spostamento)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Alt+RMB: Depth list selection"
@@ -5651,73 +5681,90 @@ msgid "Ruler Mode"
msgstr "Modalità righello"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Toggle smart snapping."
-msgstr "Abilita snapping intelligente."
+msgstr "Commuta lo scatto intelligente."
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Use Smart Snap"
-msgstr "Usa lo Snap intelligente"
+msgstr "Usa lo scatto intelligente"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Toggle grid snapping."
-msgstr "Abilita/Disabilita snapping magnetico."
+msgstr "Commuta la griglia magnetica."
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Use Grid Snap"
-msgstr "Usa Griglia Magnetica"
+msgstr "Usa la griglia magnetica"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Snapping Options"
-msgstr "Opzioni di Snapping"
+msgstr "Opzioni dello scatto"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Use Rotation Snap"
-msgstr "Usa lo Snap di Rotazione"
+msgstr "Scatta la rotazione"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Use Scale Snap"
-msgstr "Usa lo snap con scala"
+msgstr "Scatta la scala"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Snap Relative"
-msgstr "Snap Relativo"
+msgstr "Scatti relativi"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Use Pixel Snap"
-msgstr "Usa Pixel Snap"
+msgstr "Scatta sui pixel"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Smart Snapping"
-msgstr "Snapping intelligente"
+msgstr "Scatto intelligente"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Configure Snap..."
-msgstr "Configura Snap..."
+msgstr "Configura gli scatti..."
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Snap to Parent"
-msgstr "Snap al Genitore"
+msgstr "Scatta sul genitore"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Snap to Node Anchor"
-msgstr "Snap ad ancora del nodo"
+msgstr "Scatta sull'ancora dei nodi"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Snap to Node Sides"
-msgstr "Snap sui lati del nodo"
+msgstr "Scatta sui lati dei nodi"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Snap to Node Center"
-msgstr "Snap al centro del nodo"
+msgstr "Scatta sul centro dei nodi"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Snap to Other Nodes"
-msgstr "Snap ad altri nodi"
+msgstr "Scatta sugli altri nodi"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Snap to Guides"
-msgstr "Snap alle guide"
+msgstr "Scatta sulle guide"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6000,6 +6047,7 @@ msgid "Ease Out"
msgstr "Ease Out"
#: editor/plugins/curve_editor_plugin.cpp
+#, fuzzy
msgid "Smoothstep"
msgstr "Graduale"
@@ -6041,7 +6089,7 @@ msgstr "Rimuovi Punto"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Toggle Curve Linear Tangent"
-msgstr "Abilita Tangente di Curva Lineare"
+msgstr "Commuta la Tangente di Curva Lineare"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Hold Shift to edit tangents individually"
@@ -6468,7 +6516,7 @@ msgstr "Sorgente Emissione: "
#: editor/plugins/particles_editor_plugin.cpp
msgid "A processor material of type 'ParticlesMaterial' is required."
-msgstr "Un processor material di tipo 'ParticlesMaterial' é richiesto."
+msgstr "Un processor material di tipo \"ParticlesMaterial\" é richiesto."
#: editor/plugins/particles_editor_plugin.cpp
msgid "Generating AABB"
@@ -6779,11 +6827,11 @@ msgstr "Impostazioni griglia"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Snap"
-msgstr "Snap"
+msgstr "Scatto"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Enable Snap"
-msgstr "Abilita Snap"
+msgstr "Abilita lo scatto"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid"
@@ -6836,7 +6884,7 @@ msgstr "Elimina risorsa"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Resource clipboard is empty!"
-msgstr "La clipboard delle risorse è vuota!"
+msgstr "Gli appunti delle risorse sono vuoti!"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Paste Resource"
@@ -6979,7 +7027,7 @@ msgstr "Filtra gli script"
#: editor/plugins/script_editor_plugin.cpp
msgid "Toggle alphabetical sorting of the method list."
-msgstr "Abilita/Disabilita l'ordinamento alfabetico della lista dei metodi."
+msgstr "Commuta l'ordinamento alfabetico della lista dei metodi."
#: editor/plugins/script_editor_plugin.cpp
msgid "Filter methods"
@@ -7080,11 +7128,11 @@ msgstr "Cerca"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
-msgstr "Passo dentro all'istruzione"
+msgstr "Fai un passo all'interno"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Over"
-msgstr "Passo successivo"
+msgstr "Fai un passo"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Break"
@@ -7159,7 +7207,8 @@ msgstr "Target"
msgid ""
"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
msgstr ""
-"Manca il metodo connesso '%s' per il segnale '%s' dal nodo '%s' al nodo '%s'."
+"Manca il metodo connesso \"%s\" per il segnale \"%s\" dal nodo \"%s\" al "
+"nodo \"%s\"."
#: editor/plugins/script_text_editor.cpp
msgid "[Ignore]"
@@ -7181,7 +7230,7 @@ msgstr "Solo le risorse dal filesystem possono essere eliminate."
#: modules/visual_script/visual_script_editor.cpp
msgid "Can't drop nodes because script '%s' is not used in this scene."
msgstr ""
-"Impossibile rilasciare i nodi perché lo script '%s' non è usato in questa "
+"Impossibile rilasciare i nodi perché lo script \"%s\" non è usato in questa "
"scena."
#: editor/plugins/script_text_editor.cpp
@@ -7250,7 +7299,7 @@ msgstr "Indenta a destra"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Comment"
-msgstr "Attiva/Disattiva Commento"
+msgstr "Commuta i commenti"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
@@ -7302,7 +7351,7 @@ msgstr "Aiuto contestuale"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Bookmark"
-msgstr "Abilita/Disabilita i segnalibri"
+msgstr "Commuta i segnalibri"
#: editor/plugins/script_text_editor.cpp
msgid "Go to Next Bookmark"
@@ -7327,7 +7376,7 @@ msgstr "Vai alla linea..."
#: editor/plugins/script_text_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Toggle Breakpoint"
-msgstr "Attiva/Disattiva Punto D'Interruzione"
+msgstr "Commuta la riga corrente come punto d'interruzione"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Breakpoints"
@@ -7637,6 +7686,8 @@ msgstr "Rotazione Vista Bloccata"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Per un maggiore ingrandimento, cambia i piani del clip della videocamera "
+"(Vista -> Impostazioni...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -7667,12 +7718,15 @@ msgstr ""
"(\"raggi X\")."
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Snap Nodes To Floor"
-msgstr "Sposta i Nodi sul Pavimento"
+msgstr "Scatta i nodi sul pavimento"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Couldn't find a solid floor to snap the selection to."
-msgstr "Non si è trovato un pavimento solido al quale agganciare la selezione."
+msgstr ""
+"Impossibile trovare un pavimento solido sul quale scattare la selezione."
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -7689,8 +7743,9 @@ msgid "Use Local Space"
msgstr "Usa Spazio Locale"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Use Snap"
-msgstr "Usa Snap"
+msgstr "Scatta"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -7733,8 +7788,9 @@ msgid "Focus Selection"
msgstr "Centra la Selezione"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Toggle Freelook"
-msgstr "Abilita/Disabilita Vista libera"
+msgstr "Commuta la vista libera"
#: editor/plugins/spatial_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -7742,8 +7798,9 @@ msgid "Transform"
msgstr "Trasforma"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Snap Object to Floor"
-msgstr "Posa l'oggetto sul suolo"
+msgstr "Scatta l'oggetto sul suolo"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Dialog..."
@@ -7791,20 +7848,24 @@ msgid "Settings..."
msgstr "Impostazioni…"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Snap Settings"
-msgstr "Impostazioni Snap"
+msgstr "Impostazioni dello scatto"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Translate Snap:"
-msgstr "Trasla Snap:"
+msgstr "Scatto della traslazione:"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Rotate Snap (deg.):"
-msgstr "Snap Rotazione (gradi):"
+msgstr "Scatto della rotazione (gradi):"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Scale Snap (%):"
-msgstr "Scala Snap (%):"
+msgstr "Scatto della scala (%):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Viewport Settings"
@@ -7974,7 +8035,7 @@ msgstr "ERRORE: Impossibile caricare la risorsa frame!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Resource clipboard is empty or not a texture!"
-msgstr "Clipboard risorse vuota o non è una texture!"
+msgstr "Gli appunti delle risorse sono vuoti o non una texture!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Paste Frame"
@@ -8074,7 +8135,7 @@ msgstr "Imposta Margine"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Snap Mode:"
-msgstr "Modalità Snap:"
+msgstr "Modalità dello scatto:"
#: editor/plugins/texture_region_editor_plugin.cpp
#: scene/resources/visual_shader.cpp
@@ -8082,12 +8143,14 @@ msgid "None"
msgstr "Nessuno"
#: editor/plugins/texture_region_editor_plugin.cpp
+#, fuzzy
msgid "Pixel Snap"
-msgstr "Snap a Pixel"
+msgstr "Scatto sui pixel"
#: editor/plugins/texture_region_editor_plugin.cpp
+#, fuzzy
msgid "Grid Snap"
-msgstr "Snap Griglia"
+msgstr "Scatto sulla griglia"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Auto Slice"
@@ -8095,7 +8158,7 @@ msgstr "Auto Divisione"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Offset:"
-msgstr "Offset:"
+msgstr "Scostamento:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Step:"
@@ -8154,8 +8217,9 @@ msgid "Create From Current Editor Theme"
msgstr "Crea da Tema Editor corrente"
#: editor/plugins/theme_editor_plugin.cpp
+#, fuzzy
msgid "Toggle Button"
-msgstr "Attiva/Disattiva pulsante"
+msgstr "Interruttore"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Disabled Button"
@@ -8506,7 +8570,7 @@ msgstr "Mantieni il poligono all'interno dell'area del rettangolo."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Enable snap and show grid (configurable via the Inspector)."
-msgstr "Abilita snap e mostra la griglia (configurabile dall'Inspector)."
+msgstr "Abilita lo scatto e mostra la griglia (configurabile dall'ispettore)."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Display Tile Names (Hold Alt Key)"
@@ -9065,7 +9129,7 @@ msgstr "Uniforme booleana."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for all shader modes."
-msgstr "Parametro di input '%s' per tutte le modalità shader."
+msgstr "Parametro di input \"%s\" per tutte le modalità shader."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Input parameter."
@@ -9073,27 +9137,27 @@ msgstr "Parametro di input."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for vertex and fragment shader modes."
-msgstr "Parametro di input '%s' per le modalità shader vertice e frammento."
+msgstr "Parametro di input \"%s\" per le modalità shader vertice e frammento."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for fragment and light shader modes."
-msgstr "Parametro di input '%s' per le modalità shader frammento e luce."
+msgstr "Parametro di input \"%s\" per le modalità shader frammento e luce."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for fragment shader mode."
-msgstr "Parametro di input '%s' per la modalità shader frammento."
+msgstr "Parametro di input \"%s\" per la modalità shader frammento."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for light shader mode."
-msgstr "Parametro di input '%s' per la modalità shader luce."
+msgstr "Parametro di input \"%s\" per la modalità shader luce."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for vertex shader mode."
-msgstr "Parametro di input '%s' per la modalità shader vertice."
+msgstr "Parametro di input \"%s\" per la modalità shader vertice."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for vertex and fragment shader mode."
-msgstr "Parametro di input '%s' per la modalità shader vertice e frammento."
+msgstr "Parametro di input \"%s\" per la modalità shader vertice e frammento."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Scalar function."
@@ -9290,9 +9354,9 @@ msgid ""
msgstr ""
"SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n"
"\n"
-"Restituisce 0.0 se 'x' è più piccolo di 'edge0', o 1.0 se 'x' è più grande "
-"di 'edge1'. Altrimenti, il valore di ritorno è interpolato tra 0.0 ed 1.0 "
-"usando i polinomi di Hermite."
+"Restituisce 0.0 se \"x\" è più piccolo di \"edge0\", o 1.0 se \"x\" è più "
+"grande di \"edge1\". Altrimenti, il valore di ritorno è interpolato tra 0.0 "
+"ed 1.0 usando i polinomi di Hermite."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9302,7 +9366,7 @@ msgid ""
msgstr ""
"Step function( scalar(edge), scalar(x) ).\n"
"\n"
-"Restituisce 0.0 se 'x' è più piccolo di 'edge', altrimenti 1.0."
+"Restituisce 0.0 se \"x\" è più piccolo di \"edge\", altrimenti 1.0."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the tangent of the parameter."
@@ -9380,11 +9444,12 @@ msgid ""
msgstr ""
"Calcola il prodotto esterno di una coppia di vettori.\n"
"\n"
-"OuterProduct considera il primo parametro 'c' come un vettore colonna "
-"(matrice con una colonna) ed il secondo, 'r', come un vettore riga (matrice "
-"con una riga) ed esegue una moltiplicazione algebrica lineare di matrici 'c "
-"* r', creando una matrice i cui numeri di righe sono il numero di componenti "
-"di 'c' e le cui colonne sono il numero di componenti in 'r'."
+"OuterProduct considera il primo parametro \"c\" come un vettore colonna "
+"(matrice con una colonna) ed il secondo, \"r\", come un vettore riga "
+"(matrice con una riga) ed esegue una moltiplicazione algebrica lineare di "
+"matrici \"c * r\", creando una matrice i cui numeri di righe sono il numero "
+"di componenti di \"c\" e le cui colonne sono il numero di componenti in \"r"
+"\"."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Composes transform from four vectors."
@@ -9509,8 +9574,8 @@ msgid ""
msgstr ""
"SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n"
"\n"
-"Restituisce 0.0 se 'x' è minore di 'edge0', ed 1.0 se 'x' è più grande di "
-"'edge1'. Altrimenti, il valore di ritorno è interpolato tra 0.0 ed 1.0 "
+"Restituisce 0.0 se \"x\" è minore di \"edge0\", ed 1.0 se \"x\" è più grande "
+"di \"edge1\". Altrimenti, il valore di ritorno è interpolato tra 0.0 ed 1.0 "
"usando i polinomiali di Hermite."
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -9523,8 +9588,8 @@ msgid ""
msgstr ""
"SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n"
"\n"
-"Restituisce 0.0 se 'x' è minore di 'edge0', ed 1.0 se 'x' è più grande di "
-"'edge1'. Altrimenti, il valore di ritorno è interpolato tra 0.0 ed 1.0 "
+"Restituisce 0.0 se \"x\" è minore di \"edge0\", ed 1.0 se \"x\" è più grande "
+"di \"edge1\". Altrimenti, il valore di ritorno è interpolato tra 0.0 ed 1.0 "
"usando i polinomiali di Hermite."
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -9535,7 +9600,7 @@ msgid ""
msgstr ""
"Step function( vector(edge), vector(x) ).\n"
"\n"
-"Restituisce 0.0 se 'x' è minore di 'edge', altrimenti 1.0."
+"Restituisce 0.0 se \"x\" è minore di \"edge\", altrimenti 1.0."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9545,7 +9610,7 @@ msgid ""
msgstr ""
"Step function( scalar(edge), vector(x) ).\n"
"\n"
-"Restituisce 0.0 se 'x' è minore di 'edge', altrimenti 1.0."
+"Restituisce 0.0 se \"x\" è minore di \"edge\", altrimenti 1.0."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Adds vector to vector."
@@ -9623,7 +9688,7 @@ msgid ""
"(Fragment/Light mode only) (Vector) Derivative in 'x' using local "
"differencing."
msgstr ""
-"(Solo modalità Fragment/Light) (Vettore) Derivata in 'x' usando la "
+"(Solo modalità Fragment/Light) (Vettore) Derivata in \"x\" usando la "
"differenziazione locale."
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -9631,7 +9696,7 @@ msgid ""
"(Fragment/Light mode only) (Scalar) Derivative in 'x' using local "
"differencing."
msgstr ""
-"(Solo modalità Fragment/Light) (Scalare) Derivata in 'x' usando la "
+"(Solo modalità Fragment/Light) (Scalare) Derivata in \"x\" usando la "
"differeziazione locale."
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -9639,7 +9704,7 @@ msgid ""
"(Fragment/Light mode only) (Vector) Derivative in 'y' using local "
"differencing."
msgstr ""
-"(Soltanto modalità Fragment/Light) (Vettore) Derivata in 'y' usando la "
+"(Soltanto modalità Fragment/Light) (Vettore) Derivata in \"y\" usando la "
"differenziazione locale."
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -9647,7 +9712,7 @@ msgid ""
"(Fragment/Light mode only) (Scalar) Derivative in 'y' using local "
"differencing."
msgstr ""
-"(Soltanto modalità Fragment/Light) (Scalare) Derivata in 'y' usando la "
+"(Soltanto modalità Fragment/Light) (Scalare) Derivata in \"y\" usando la "
"differenziazione locale."
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -9656,7 +9721,7 @@ msgid ""
"'y'."
msgstr ""
"(Soltanto modalità Fragment/Light) (Vettore) Somma delle derivate assolute "
-"in 'x' ed 'y'."
+"in \"x\" ed \"y\"."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9664,7 +9729,7 @@ msgid ""
"'y'."
msgstr ""
"(Soltanto modalità Fragment/Light) (Scalare) Somma delle derivate assolute "
-"in 'x' ed 'y'."
+"in \"x\" ed \"y\"."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "VisualShader"
@@ -9684,14 +9749,14 @@ msgstr "Eseguibile"
#: editor/project_export.cpp
msgid "Delete preset '%s'?"
-msgstr "Eliminare preset '%s'?"
+msgstr "Eliminare preset \"%s\"?"
#: editor/project_export.cpp
msgid ""
"Failed to export the project for platform '%s'.\n"
"Export templates seem to be missing or invalid."
msgstr ""
-"Impossibile esportare il progetto per la piattaforma '%s'.\n"
+"Impossibile esportare il progetto per la piattaforma \"%s\".\n"
"I template di esportazione sembrano essere mancanti o non validi."
#: editor/project_export.cpp
@@ -9700,7 +9765,7 @@ msgid ""
"This might be due to a configuration issue in the export preset or your "
"export settings."
msgstr ""
-"Impossibile esportare il progetto per la piattaforma '%s'.\n"
+"Impossibile esportare il progetto per la piattaforma \"%s\".\n"
"Questo potrebbe essere dovuto ad un problema di configurazione nel preset di "
"esportazione o nelle impostazioni di esportazione."
@@ -9870,8 +9935,8 @@ msgstr "Errore nell'apertura del file package (non è in formato ZIP)."
msgid ""
"Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."
msgstr ""
-"File progetto '.zip' non valido; non contiene un file denominato 'project."
-"godot'."
+"File progetto \".zip\" non valido; non contiene un file denominato \"project."
+"godot\"."
#: editor/project_manager.cpp
msgid "Please choose an empty folder."
@@ -9879,7 +9944,7 @@ msgstr "Si prega di scegliere una cartella vuota."
#: editor/project_manager.cpp
msgid "Please choose a \"project.godot\" or \".zip\" file."
-msgstr "Perfavore, scegli un file 'project.godot' o '.zip'."
+msgstr "Perfavore, scegli un file \"project.godot\" o \".zip\"."
#: editor/project_manager.cpp
msgid "This directory already contains a Godot project."
@@ -10029,7 +10094,7 @@ msgstr "Errore: il Progetto non è presente nel filesystem."
#: editor/project_manager.cpp
msgid "Can't open project at '%s'."
-msgstr "Impossibile aprire il progetto a '%s'."
+msgstr "Impossibile aprire il progetto a \"%s\"."
#: editor/project_manager.cpp
msgid "Are you sure to open more than one project?"
@@ -10231,15 +10296,15 @@ msgstr "Pulsante Mouse"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
-"Nome dell'azione non valido. Non può essere vuoto o contenere '/', ':', '=', "
-"'\\' oppure '\"'"
+"Nome dell'azione non valido. Non può essere vuoto o contenere \"/\", \":\", "
+"\"=\", \"\\\" oppure \"\"\""
#: editor/project_settings_editor.cpp
msgid "An action with the name '%s' already exists."
-msgstr "Un'azione col nome '%s' è già esistente."
+msgstr "Un'azione col nome \"%s\" è già esistente."
#: editor/project_settings_editor.cpp
msgid "Rename Input Action Event"
@@ -10363,11 +10428,11 @@ msgstr "Prima seleziona un oggetto di impostazione!"
#: editor/project_settings_editor.cpp
msgid "No property '%s' exists."
-msgstr "Non esiste nessuna proprietà '%s'."
+msgstr "Non esiste nessuna proprietà \"%s\"."
#: editor/project_settings_editor.cpp
msgid "Setting '%s' is internal, and it can't be deleted."
-msgstr "L'impostazione '%s' è interna e non può essere rimossa."
+msgstr "L'impostazione \"%s\" è interna e non può essere rimossa."
#: editor/project_settings_editor.cpp
msgid "Delete Item"
@@ -10378,8 +10443,8 @@ msgid ""
"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'."
msgstr ""
-"Nome azione non valida. Non può essere vuoto né contenere '/', ':', '=', "
-"'\\' o '\"'."
+"Nome azione non valida. Non può essere vuoto né contenere \"/\", \":\", \"="
+"\", \"\\\" o \"\"\"."
#: editor/project_settings_editor.cpp
msgid "Add Input Action"
@@ -10531,7 +10596,7 @@ msgstr "AutoLoad"
#: editor/project_settings_editor.cpp
msgid "Plugins"
-msgstr "Plugins"
+msgstr "Estensioni"
#: editor/project_settings_editor.cpp
msgid "Import Defaults"
@@ -10771,8 +10836,8 @@ msgid ""
"Cannot instance the scene '%s' because the current scene exists within one "
"of its nodes."
msgstr ""
-"Impossibile istanziale la scena '%s' perché la scena corrente esiste in uno "
-"dei suoi nodi."
+"Impossibile istanziale la scena \"%s\" perché la scena corrente esiste in "
+"uno dei suoi nodi."
#: editor/scene_tree_dock.cpp
msgid "Instance Scene(s)"
@@ -11044,6 +11109,9 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"Se selezionato, il pannello della scena remota farà ricaricare il progetto "
+"ogni volta che viene aggiornato.\n"
+"Tornare al pannello della scena locale per migliorare le prestazioni."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -11055,7 +11123,7 @@ msgstr "Liberare ereditarietà? (No Undo!)"
#: editor/scene_tree_editor.cpp
msgid "Toggle Visible"
-msgstr "Attiva/Disattiva Visibilità"
+msgstr "Commuta visibilità"
#: editor/scene_tree_editor.cpp
msgid "Unlock Node"
@@ -11078,16 +11146,16 @@ msgid ""
"Node has %s connection(s) and %s group(s).\n"
"Click to show signals dock."
msgstr ""
-"Il nodo ha %s connessione/i e %s gruppo/i.\n"
-"Clicca per mostrare il dock dei segnali."
+"Il nodo ha %s connessioni e %s gruppi.\n"
+"Cliccare per mostrare il pannello dei segnali."
#: editor/scene_tree_editor.cpp
msgid ""
"Node has %s connection(s).\n"
"Click to show signals dock."
msgstr ""
-"Il nodo ha %s connessione/i.\n"
-"Clicca per mostrare il dock dei segnali."
+"Il nodo ha %s connessioni.\n"
+"Cliccare per mostrare il pannello dei segnali."
#: editor/scene_tree_editor.cpp
msgid ""
@@ -11095,7 +11163,7 @@ msgid ""
"Click to show groups dock."
msgstr ""
"Il nodo è in %s gruppi.\n"
-"Clicca per mostrare il dock dei gruppi."
+"Cliccare per mostrare il pannello dei gruppi."
#: editor/scene_tree_editor.cpp
msgid "Open Script:"
@@ -11119,7 +11187,7 @@ msgstr ""
#: editor/scene_tree_editor.cpp
msgid "Toggle Visibility"
-msgstr "Abilita Visibilità"
+msgstr "Commuta visibilità"
#: editor/scene_tree_editor.cpp
msgid ""
@@ -11183,7 +11251,7 @@ msgstr "Selezionata estensione errata."
#: editor/script_create_dialog.cpp
msgid "Error loading template '%s'"
-msgstr "Errore caricamento template '%s'"
+msgstr "Errore caricamento template \"%s\""
#: editor/script_create_dialog.cpp
msgid "Error - Could not create script in filesystem."
@@ -11655,20 +11723,22 @@ msgid "Grid Map"
msgstr "Mappa di Griglia"
#: modules/gridmap/grid_map_editor_plugin.cpp
+#, fuzzy
msgid "Snap View"
-msgstr "Vista Snap"
+msgstr "Scatta la vista"
#: modules/gridmap/grid_map_editor_plugin.cpp
+#, fuzzy
msgid "Clip Disabled"
msgstr "Clip Disabilitata"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Clip Above"
-msgstr "Ritaglia Sopra"
+msgstr "Taglia sopra"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Clip Below"
-msgstr "Ritaglia Sotto"
+msgstr "Taglia sotto"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Edit X Axis"
@@ -12019,9 +12089,9 @@ msgid ""
"Can't drop properties because script '%s' is not used in this scene.\n"
"Drop holding 'Shift' to just copy the signature."
msgstr ""
-"Impossibile lasciare le proprietà perché lo script '%s' non è usato nella "
+"Impossibile lasciare le proprietà perché lo script \"%s\" non è usato nella "
"scena.\n"
-"Lascia andare premendo 'Shift (Maiuscolo)' per copiare solo la firma."
+"Lascia andare premendo \"Shift (Maiuscolo)\" per copiare solo la firma."
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Getter Property"
@@ -12061,7 +12131,7 @@ msgstr "Connetti Sequenza del Nodo"
#: modules/visual_script/visual_script_editor.cpp
msgid "Script already has function '%s'"
-msgstr "Lo Script ha già la funzione '%s'"
+msgstr "Lo Script ha già la funzione \"%s\""
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Input Value"
@@ -12205,7 +12275,7 @@ msgstr "Il percorso non conduce ad un Nodo!"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Invalid index property name '%s' in node %s."
-msgstr "Nome proprietà indice invalido '%s' nel nodo %s."
+msgstr "Nome proprietà indice invalido \"%s\" nel nodo %s."
#: modules/visual_script/visual_script_nodes.cpp
msgid ": Invalid argument of type: "
@@ -12226,8 +12296,8 @@ msgstr "VariableSet non trovato nello script: "
#: modules/visual_script/visual_script_nodes.cpp
msgid "Custom node has no _step() method, can't process graph."
msgstr ""
-"Il nodo personalizzato non ha alcun metodo _step(), impossibile processare "
-"il grafico."
+"Il nodo personalizzato non ha alcun metodo _step(), impossibile elaborare il "
+"grafico."
#: modules/visual_script/visual_script_nodes.cpp
msgid ""
@@ -12260,8 +12330,8 @@ msgstr "I segmenti del pacchetto devono essere di lunghezza diversa da zero."
#: platform/android/export/export.cpp
msgid "The character '%s' is not allowed in Android application package names."
msgstr ""
-"Il carattere '%s' non è consentito nei nomi dei pacchetti delle applicazioni "
-"Android."
+"Il carattere \"%s\" non è consentito nei nomi dei pacchetti delle "
+"applicazioni Android."
#: platform/android/export/export.cpp
msgid "A digit cannot be the first character in a package segment."
@@ -12271,12 +12341,12 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "The character '%s' cannot be the first character in a package segment."
msgstr ""
-"Il carattere '%s' non può essere il primo carattere di un segmento di "
+"Il carattere \"%s\" non può essere il primo carattere di un segmento di "
"pacchetto."
#: platform/android/export/export.cpp
msgid "The package must have at least one '.' separator."
-msgstr "Il pacchetto deve avere almeno un '.' separatore."
+msgstr "Il pacchetto deve avere almeno un \".\" separatore."
#: platform/android/export/export.cpp
msgid "Select device from the list"
@@ -12284,7 +12354,7 @@ msgstr "Seleziona il dispositivo dall'elenco"
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
-msgstr "Impossibile trovare lo strumento 'apksigner'."
+msgstr "Impossibile trovare lo strumento \"apksigner\"."
#: platform/android/export/export.cpp
msgid ""
@@ -12295,11 +12365,23 @@ msgstr ""
"dal menu Progetto."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Debug keystore non configurato nelle Impostazioni dell'Editor né nel preset."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Release keystore non configurato correttamente nel preset di esportazione."
@@ -12315,7 +12397,7 @@ msgstr "Un percorso invalido per il SDK Android nelle Impostazioni Editor."
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
-msgstr "Cartella 'platform-tools' inesistente!"
+msgstr "Cartella \"platform-tools\" inesistente!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
@@ -12331,7 +12413,7 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
-msgstr "Cartella 'build-tools' inesistente!"
+msgstr "Cartella \"build-tools\" inesistente!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
@@ -12405,7 +12487,7 @@ msgid ""
msgstr ""
"Tentativo di costruire da un template build personalizzato, ma nesuna "
"informazione sulla sua versione esiste. Perfavore, reinstallalo dal menu "
-"'Progetto'."
+"\"Progetto\"."
#: platform/android/export/export.cpp
msgid ""
@@ -12417,7 +12499,7 @@ msgstr ""
"Versione build di Android non coerente:\n"
" Template installato: %s\n"
" Versione Godot: %s\n"
-"Perfavore, reinstalla il build template di Android dal menu 'Progetto'."
+"Perfavore, reinstalla il build template di Android dal menu \"Progetto\"."
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
@@ -12451,7 +12533,7 @@ msgstr "L'identificatore è mancante."
#: platform/iphone/export/export.cpp
msgid "The character '%s' is not allowed in Identifier."
-msgstr "Il carattere '%s' non è consentito nell'Identificatore."
+msgstr "Il carattere \"%s\" non è consentito nell'Identificatore."
#: platform/iphone/export/export.cpp
msgid "App Store Team ID not specified - cannot configure the project."
@@ -12614,13 +12696,13 @@ msgstr "Un CollisionPolygon2D vuoto non ha effetti sulla collisione."
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
"Poligono non valido. Sono necessari almeno 3 punti nella modalità di "
-"costruzione 'Solidi'."
+"costruzione \"Solidi\"."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
"Poligono non valido. Sono necessari almeno 2 punti nella modalità di "
-"costruzione 'Segmenti'."
+"costruzione \"Segmenti\"."
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -13093,23 +13175,23 @@ msgstr ""
#: scene/animation/animation_blend_tree.cpp
msgid "On BlendTree node '%s', animation not found: '%s'"
-msgstr "Sul nodo BlendTree '%s', animazione non trovata: '%s'"
+msgstr "Sul nodo BlendTree \"%s\", animazione non trovata: \"%s\""
#: scene/animation/animation_blend_tree.cpp
msgid "Animation not found: '%s'"
-msgstr "Animazione non trovata: '%s'"
+msgstr "Animazione non trovata: \"%s\""
#: scene/animation/animation_tree.cpp
msgid "In node '%s', invalid animation: '%s'."
-msgstr "Nel nodo '%s', animazione non valida: '%s'."
+msgstr "Nel nodo \"%s\", animazione non valida: \"%s\"."
#: scene/animation/animation_tree.cpp
msgid "Invalid animation: '%s'."
-msgstr "Animazione non valida: '%s'."
+msgstr "Animazione non valida: \"%s\"."
#: scene/animation/animation_tree.cpp
msgid "Nothing connected to input '%s' of node '%s'."
-msgstr "Nulla collegato all'ingresso '%s' del nodo '%s'."
+msgstr "Nulla collegato all'ingresso \"%s\" del nodo \"%s\"."
#: scene/animation/animation_tree.cpp
msgid "No root AnimationNode for the graph is set."
@@ -13258,7 +13340,7 @@ msgid ""
"'SamplerPort'."
msgstr ""
"La porta del sampler è connessa ma mai usata. Considera cambiare la sorgente "
-"a 'SamplerPort'."
+"a \"SamplerPort\"."
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for preview."
diff --git a/editor/translations/ja.po b/editor/translations/ja.po
index 2d694989fc..85768d721a 100644
--- a/editor/translations/ja.po
+++ b/editor/translations/ja.po
@@ -32,12 +32,13 @@
# Wataru Onuki <bettawat@yahoo.co.jp>, 2020, 2021.
# sporeball <sporeballdev@gmail.com>, 2020.
# BinotaLIU <me@binota.org>, 2020, 2021.
+# 都築 æœ¬æˆ <motonari728@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-01 02:04+0000\n"
-"Last-Translator: nitenook <admin@alterbaum.net>\n"
+"PO-Revision-Date: 2021-05-29 13:49+0000\n"
+"Last-Translator: 都築 æœ¬æˆ <motonari728@gmail.com>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot/ja/>\n"
"Language: ja\n"
@@ -45,7 +46,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1142,6 +1143,10 @@ msgstr "Dictionary 値ã®å¤‰æ›´"
msgid "Thanks from the Godot community!"
msgstr "Godot コミュニティより感è¬ã‚’ï¼"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot エンジンã«è²¢çŒ®ã—ãŸäººã€…"
@@ -2563,11 +2568,13 @@ msgstr "パス '%s' ã‹ã‚‰ã‚¢ãƒ‰ã‚ªãƒ³ã‚¹ã‚¯ãƒªãƒ—トを読込ã‚ã¾ã›ã‚“。"
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"パス '%s' ã‹ã‚‰ã‚¢ãƒ‰ã‚ªãƒ³ã‚¹ã‚¯ãƒªãƒ—トを読ã¿è¾¼ã‚ã¾ã›ã‚“。コードã«ã‚¨ãƒ©ãƒ¼ãŒã‚ã‚‹å¯èƒ½æ€§"
-"ãŒã‚りã¾ã™ã€‚構文を確èªã—ã¦ãã ã•ã„。"
+"ãŒã‚りã¾ã™ã€‚\n"
+"構文を確èªã—ã¦ãã ã•ã„。"
#: editor/editor_node.cpp
msgid ""
@@ -3011,6 +3018,10 @@ msgid "About"
msgstr "概è¦"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Godotã®é–‹ç™ºã‚’サãƒãƒ¼ãƒˆã™ã‚‹"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "プロジェクトを実行。"
@@ -3695,6 +3706,8 @@ msgstr ""
msgid ""
"Importing has been disabled for this file, so it can't be opened for editing."
msgstr ""
+"ã“ã®ãƒ•ァイルã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã¯ç„¡åŠ¹åŒ–ã•れã¦ã„ã‚‹ãŸã‚ã€ç·¨é›†ã®ãŸã‚ã«é–‹ãã“ã¨ã¯ã§ãã¾"
+"ã›ã‚“。"
#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
@@ -4095,13 +4108,12 @@ msgid "Importer:"
msgstr "インãƒãƒ¼ãƒˆ"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "デフォルトを読込む"
+msgstr "デフォルトã«ãƒªã‚»ãƒƒãƒˆã™ã‚‹"
#: editor/import_dock.cpp
msgid "Keep File (No Import)"
-msgstr ""
+msgstr "ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ä¿æŒ (インãƒãƒ¼ãƒˆã—ãªã„)"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -5235,6 +5247,7 @@ msgstr ""
"ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
+#, fuzzy
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
@@ -10131,7 +10144,7 @@ msgstr "マウスボタン"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"アクションåãŒç„¡åйã§ã™ã€‚空ã«ã—ãŸã‚Šã€'/'ã€':'ã€'='ã€'\\'ã€'\"'ã‚’å«ã‚ã‚‹ã“ã¨ã¯ã§"
@@ -12193,10 +12206,22 @@ msgstr ""
"ジェクト] メニューã‹ã‚‰ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ã¾ã™ã€‚"
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr "デãƒãƒƒã‚°ã‚­ãƒ¼ã‚¹ãƒˆã‚¢ãŒã‚¨ãƒ‡ã‚£ã‚¿è¨­å®šã«ã‚‚プリセットã«ã‚‚設定ã•れã¦ã„ã¾ã›ã‚“。"
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr "エクスãƒãƒ¼ãƒˆè¨­å®šã«ã¦ãƒªãƒªãƒ¼ã‚¹ キーストアãŒèª¤ã£ã¦è¨­å®šã•れã¦ã„ã¾ã™ã€‚"
diff --git a/editor/translations/ka.po b/editor/translations/ka.po
index 1894b0e156..ce5c6dc032 100644
--- a/editor/translations/ka.po
+++ b/editor/translations/ka.po
@@ -1162,6 +1162,10 @@ msgstr "ლექსიკáƒáƒœáƒ˜áƒ¡ მნიშვნელáƒáƒ‘ის შá
msgid "Thanks from the Godot community!"
msgstr "მáƒáƒ“ლáƒáƒ‘რGodot სáƒáƒ–áƒáƒ’áƒáƒ“áƒáƒ”ბისგáƒáƒœ!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot ძრáƒáƒ•ის ხელშემწყáƒáƒ‘ები"
@@ -2561,8 +2565,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2974,6 +2979,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -10012,7 +10021,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12068,10 +12077,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/km.po b/editor/translations/km.po
index 9e167dfe2c..ee77bab308 100644
--- a/editor/translations/km.po
+++ b/editor/translations/km.po
@@ -1082,6 +1082,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2440,8 +2444,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2846,6 +2851,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9679,7 +9688,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11680,10 +11689,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index 9770daf14a..f2f3ac1562 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -22,12 +22,13 @@
# Yongjin Jo <wnrhd114@gmail.com>, 2020.
# Yungjoong Song <yungjoong.song@gmail.com>, 2020.
# Henry LeRoux <henry.leroux@ocsbstudent.ca>, 2021.
+# Postive_ Cloud <postive12@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-11 22:02+0000\n"
-"Last-Translator: Myeongjin Lee <aranet100@gmail.com>\n"
+"PO-Revision-Date: 2021-06-11 14:49+0000\n"
+"Last-Translator: Postive_ Cloud <postive12@gmail.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/"
"godot/ko/>\n"
"Language: ko\n"
@@ -35,7 +36,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -59,7 +60,7 @@ msgstr "표현ì‹ì˜ ìž…ë ¥ %i (전달ë˜ì§€ 않ìŒ) ì´(ê°€) 올바르지 않ìŠ
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
-msgstr "ì¸ìŠ¤í„´ìŠ¤ê°€ null (전달ë˜ì§€ 않ìŒ) ì´ë¯€ë¡œ self 를 사용할 수 없습니다"
+msgstr "ì¸ìŠ¤í„´ìŠ¤ê°€ null(전달ë˜ì§€ 않ìŒ)ì´ë¯€ë¡œ self 명령어는 사용할 수 없습니다"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
@@ -1131,6 +1132,10 @@ msgstr "딕셔너리 값 변경"
msgid "Thanks from the Godot community!"
msgstr "Godot 커뮤니티ì—서 ê°ì‚¬ë“œë¦½ë‹ˆë‹¤!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine 기여ìž"
@@ -2545,11 +2550,13 @@ msgstr "ë‹¤ìŒ ê²½ë¡œì—서 애드온 스í¬ë¦½íŠ¸ë¥¼ 불러올 수 ì—†ìŒ: '%s'
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"ë‹¤ìŒ ê²½ë¡œì—서 애드온 스í¬ë¦½íŠ¸ë¥¼ 불러올 수 ì—†ìŒ: '%s' ì½”ë“œì— ì˜¤ë¥˜ê°€ 있는 것 ê°™"
-"습니다. ë¬¸ë²•ì„ í™•ì¸í•´ë³´ì„¸ìš”."
+"ë‹¤ìŒ ê²½ë¡œì—서 애드온 스í¬ë¦½íŠ¸ë¥¼ 불러올 수 ì—†ìŒ: '%s' 해당 스í¬ë¦½íŠ¸ì˜ ì½”ë“œì— "
+"오류가 있는 것 같습니다.\n"
+"추가 오류를 방지하려면 '%s'ì—서 ì• ë“œì˜¨ì„ ë¹„í™œì„±í™”í•˜ì„¸ìš”."
#: editor/editor_node.cpp
msgid ""
@@ -2794,7 +2801,7 @@ msgstr "내보내기..."
#: editor/editor_node.cpp
msgid "Install Android Build Template..."
-msgstr "안드로ì´ë“œ 빌드 템플릿 설치..."
+msgstr "Android 빌드 템플릿 설치..."
#: editor/editor_node.cpp
msgid "Open Project Data Folder"
@@ -2989,6 +2996,10 @@ msgid "About"
msgstr "ì •ë³´"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Godot 개발 ì§€ì›"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "프로ì íŠ¸ë¥¼ 실행합니다."
@@ -3071,7 +3082,7 @@ msgstr "저장하지 않ìŒ"
#: editor/editor_node.cpp
msgid "Android build template is missing, please install relevant templates."
-msgstr "안드로ì´ë“œ 빌드 í…œí”Œë¦¿ì´ ì—†ìŠµë‹ˆë‹¤, 관련 í…œí”Œë¦¿ì„ ì„¤ì¹˜í•´ì£¼ì„¸ìš”."
+msgstr "Android 빌드 í…œí”Œë¦¿ì´ ì—†ìŠµë‹ˆë‹¤, 관련 í…œí”Œë¦¿ì„ ì„¤ì¹˜í•´ì£¼ì„¸ìš”."
#: editor/editor_node.cpp
msgid "Manage Templates"
@@ -3087,12 +3098,12 @@ msgid ""
"the \"Use Custom Build\" option should be enabled in the Android export "
"preset."
msgstr ""
-"\"res://android/build\"ì— ì†ŒìŠ¤ í…œí”Œë¦¿ì„ ì„¤ì¹˜í•´ì„œ, 프로ì íŠ¸ë¥¼ 맞춤 안드로ì´ë“œ "
-"ë¹Œë“œì— ë§žê²Œ 설정할 것입니다.\n"
+"\"res://android/build\"ì— ì†ŒìŠ¤ í…œí”Œë¦¿ì„ ì„¤ì¹˜í•´ì„œ, 프로ì íŠ¸ë¥¼ 맞춤 Android 빌"
+"ë“œì— ë§žê²Œ 설정할 것입니다.\n"
"그런 ë‹¤ìŒ ìˆ˜ì • ì‚¬í•­ì„ ì ìš©í•˜ê³  맞춤 APK를 만들어 내보낼 수 있습니다 (모듈 ì¶”"
"가, AndroidManifest.xml 바꾸기 등).\n"
-"미리 ë¹Œë“œëœ APK를 사용하는 대신 맞춤 빌드를 만들려면, 안드로ì´ë“œ 내보내기 프"
-"리셋ì—서 \"맞춤 빌드 사용\" ì„¤ì •ì„ ì¼œ 놓아야 합니다."
+"미리 ë¹Œë“œëœ APK를 사용하는 대신 맞춤 빌드를 만들려면, Android 내보내기 프리셋"
+"ì—서 \"맞춤 빌드 사용\" ì„¤ì •ì„ ì¼œ 놓아야 합니다."
#: editor/editor_node.cpp
msgid ""
@@ -3101,7 +3112,7 @@ msgid ""
"Remove the \"res://android/build\" directory manually before attempting this "
"operation again."
msgstr ""
-"안드로ì´ë“œ 빌드 í…œí”Œë¦¿ì´ ì´ë¯¸ ì´ í”„ë¡œì íŠ¸ì— ì„¤ì¹˜í–ˆê³ , ë®ì–´ 쓸 수 없습니다.\n"
+"Android 빌드 í…œí”Œë¦¿ì´ ì´ë¯¸ ì´ í”„ë¡œì íŠ¸ì— ì„¤ì¹˜í–ˆê³ , ë®ì–´ 쓸 수 없습니다.\n"
"ì´ ëª…ë ¹ì„ ë‹¤ì‹œ 실행 ì „ì— \"res://android/build\" 디렉토리를 삭제하세요."
#: editor/editor_node.cpp
@@ -3616,7 +3627,7 @@ msgstr "SSL 핸드셰ì´í¬ 오류"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
-msgstr "안드로ì´ë“œ 빌드 소스 ì••ì¶• 푸는 중"
+msgstr "Android 빌드 소스 압축 푸는 중"
#: editor/export_template_manager.cpp
msgid "Current Version:"
@@ -5204,8 +5215,8 @@ msgstr ""
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
-"Godot 편집기가 ë ˆì´ íŠ¸ë ˆì´ì‹± ì§€ì› ì—†ì´ ë¹Œë“œë˜ì–´ 있어, ë¼ì´íŠ¸ë§µì´ êµ¬ì›Œì§ˆ 수 ì—†"
-"습니다."
+"Godot 편집기는 ë ˆì´ íŠ¸ë ˆì´ì‹± ì§€ì› ì—†ì´ ë¹Œë“œë˜ì—ˆìœ¼ë©° ë¼ì´íŠ¸ë§µì€ êµ¬ìš¸ 수 없습니"
+"다."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
@@ -7515,7 +7526,7 @@ msgstr "뷰 회전 잠김"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
-msgstr ""
+msgstr "ë”ìš± 확대하려면, ì¹´ë©”ë¼ì˜ í´ë¦½í•‘ í‰ë©´ì„ 변경하세요 (보기 -> 설정...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -10057,7 +10068,7 @@ msgstr "마우스 버튼"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"ìž˜ëª»ëœ ì•¡ì…˜ ì´ë¦„. 공백ì´ê±°ë‚˜, '/' , ':', '=', '\\', '\"' 를 í¬í•¨í•˜ë©´ 안 ë©ë‹ˆ"
@@ -10863,6 +10874,9 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"ì„ íƒë˜ì–´ 있다면, ì›ê²© 씬 트리 ë…ì€ ê·¸ê²ƒì´ ì—…ë°ì´íŠ¸ë  ë•Œë§ˆë‹¤ 프로ì íŠ¸ê°€ ëŠê¸°"
+"는 ì›ì¸ì´ ë©ë‹ˆë‹¤.\n"
+"ì„±ëŠ¥ì„ í–¥ìƒì‹œí‚¤ë ¤ë©´ 로컬 씬 트리 ë…으로 다시 전환하세요."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12075,8 +12089,7 @@ msgstr "패키지 세그먼트는 길ì´ê°€ 0ì´ ì•„ë‹ˆì–´ì•¼ 합니다."
#: platform/android/export/export.cpp
msgid "The character '%s' is not allowed in Android application package names."
-msgstr ""
-"ë¬¸ìž '%s'ì€(는) 안드로ì´ë“œ 애플리케ì´ì…˜ 패키지 ì´ë¦„으로 쓸 수 없습니다."
+msgstr "ë¬¸ìž '%s'ì€(는) Android 애플리케ì´ì…˜ 패키지 ì´ë¦„으로 쓸 수 없습니다."
#: platform/android/export/export.cpp
msgid "A digit cannot be the first character in a package segment."
@@ -12107,10 +12120,22 @@ msgstr ""
"하세요."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr "Debug keystore를 편집기 설정과 í”„ë¦¬ì…‹ì— ì„¤ì •í•˜ì§€ 않았습니다."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr "내보내기 í”„ë¦¬ì…‹ì— ë°°í¬ keystorkeê°€ 잘못 설정ë˜ì–´ 있습니다."
@@ -13043,6 +13068,19 @@ msgid "Constants cannot be modified."
msgstr "ìƒìˆ˜ëŠ” 수정할 수 없습니다."
#~ msgid ""
+#~ "Godot editor was built without ray tracing support; lightmaps can't be "
+#~ "baked.\n"
+#~ "If you are using an Apple Silicon-based Mac, try forcing Rosetta "
+#~ "emulation on Godot.app in the application settings\n"
+#~ "then restart the editor."
+#~ msgstr ""
+#~ "Godot 편집기는 ë ˆì´ íŠ¸ë ˆì´ì‹± ì§€ì› ì—†ì´ ë¹Œë“œë˜ì—ˆìœ¼ë©° ë¼ì´íŠ¸ë§µì€ êµ¬ìš¸ 수 ì—†"
+#~ "습니다.\n"
+#~ "Apple Silicon ê¸°ë°˜ì˜ Macì„ ì‚¬ìš© ì¤‘ì¸ ê²½ìš°, 애플리케ì´ì…˜ 설정ì—서 Godot.app"
+#~ "ì˜ Rosetta ì—뮬레ì´ì…˜ 강제로\n"
+#~ "시ë„하고 나서 편집기를 다시 시작하세요."
+
+#~ msgid ""
#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
#~ msgstr ""
#~ "InterpolatedCamera는 ë” ì´ìƒ 사용ë˜ì§€ 않으며 Godot 4.0ì—서 제거ë©ë‹ˆë‹¤."
diff --git a/editor/translations/lt.po b/editor/translations/lt.po
index e5ca1dd50c..d4520d2d76 100644
--- a/editor/translations/lt.po
+++ b/editor/translations/lt.po
@@ -1123,6 +1123,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2513,8 +2517,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2926,6 +2931,10 @@ msgid "About"
msgstr "Apie"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9985,7 +9994,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12037,10 +12046,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/lv.po b/editor/translations/lv.po
index 606c690a55..360b8bcb8f 100644
--- a/editor/translations/lv.po
+++ b/editor/translations/lv.po
@@ -1119,6 +1119,10 @@ msgstr "MainÄ«t VÄrdnÄ«cas VÄ“rtÄ«bu"
msgid "Thanks from the Godot community!"
msgstr "Paldies no Godot sabiedrības!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot DzinÄ“ja ieguldÄ«tÄji"
@@ -2486,8 +2490,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2892,6 +2897,10 @@ msgid "About"
msgstr "Par"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9810,7 +9819,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11841,10 +11850,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/mi.po b/editor/translations/mi.po
index 1259cbeed4..17b666c0e6 100644
--- a/editor/translations/mi.po
+++ b/editor/translations/mi.po
@@ -1074,6 +1074,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2432,8 +2436,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2838,6 +2843,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9671,7 +9680,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11672,10 +11681,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/mk.po b/editor/translations/mk.po
index 25f0c1bedd..0443bd589e 100644
--- a/editor/translations/mk.po
+++ b/editor/translations/mk.po
@@ -1081,6 +1081,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2439,8 +2443,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2845,6 +2850,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9678,7 +9687,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11679,10 +11688,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/ml.po b/editor/translations/ml.po
index 2ffb3793b7..a25540d2cd 100644
--- a/editor/translations/ml.po
+++ b/editor/translations/ml.po
@@ -1084,6 +1084,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2444,8 +2448,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2850,6 +2855,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9688,7 +9697,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11690,10 +11699,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/mr.po b/editor/translations/mr.po
index 119e1ce931..7e6f8f5cc5 100644
--- a/editor/translations/mr.po
+++ b/editor/translations/mr.po
@@ -1081,6 +1081,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2439,8 +2443,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2845,6 +2850,10 @@ msgid "About"
msgstr "आमचà¥à¤¯à¤¾ बदà¥à¤¦à¤²"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9679,7 +9688,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11680,10 +11689,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/ms.po b/editor/translations/ms.po
index 127e06c898..82a4443b24 100644
--- a/editor/translations/ms.po
+++ b/editor/translations/ms.po
@@ -9,11 +9,12 @@
# Muhammad Hazim bin Hafizalshah <muhammadhazimhafizalshah@gmail.com>, 2020.
# keviinx <keviinx@yahoo.com>, 2020.
# Keviindran Ramachandran <keviinx@yahoo.com>, 2020, 2021.
+# Jacque Fresco <aidter@use.startmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-12 13:32+0000\n"
+"PO-Revision-Date: 2021-05-29 13:49+0000\n"
"Last-Translator: Keviindran Ramachandran <keviinx@yahoo.com>\n"
"Language-Team: Malay <https://hosted.weblate.org/projects/godot-engine/godot/"
"ms/>\n"
@@ -22,7 +23,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.4.1-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1123,6 +1124,10 @@ msgstr "Tukar Nilai Kamus"
msgid "Thanks from the Godot community!"
msgstr "Terima kasih dari komuniti Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Penyumbang Enjin Godot"
@@ -1607,22 +1612,20 @@ msgstr ""
"Fallback Enabled'."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"Platform sasaran memerlukan pemampatan tekstur 'ETC' untuk GLES2. Aktifkan "
-"'Import Etc' dalam Tetapan Projek."
+"Platform sasaran memerlukan pemampatan tekstur 'PVRTC' untuk GLES2. Aktifkan "
+"'Import Pvrtc' dalam Tetapan Projek."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
-"Platform sasaran memerlukan pemampatan tekstur 'ETC2' untuk GLES3. Aktifkan "
-"'Import Etc 2' dalam Tetapan Projek."
+"Platform sasaran memerlukan pemampatan tekstur 'ETC2' atau 'PVRTC' untuk "
+"GLES3. Aktifkan 'Import Etc 2' atau 'Import Pvrtc' dalam Tetapan Projek."
#: editor/editor_export.cpp
#, fuzzy
@@ -1679,9 +1682,8 @@ msgid "Node Dock"
msgstr "Dok nod"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "Sistem Fail dan Dok Import"
+msgstr "Dok FileSystem"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
@@ -1768,7 +1770,7 @@ msgstr "Baru"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Import"
+msgstr "import"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -2000,7 +2002,7 @@ msgstr "Tutorial Dalam Talian"
#: editor/editor_help.cpp
msgid "Properties"
-msgstr "Sifat"
+msgstr "Sifat-sifat"
#: editor/editor_help.cpp
msgid "override:"
@@ -2396,7 +2398,7 @@ msgstr "Tiada adegan yang didefinisikan untuk dijalankan."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Simpan adegan sebelum menjalankan..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2552,9 +2554,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Tidak dapat memuatkan skrip addon dari laluan: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Tidak dapat memuat skrip addon dari laluan: '%s' Nampaknya terdapat ralat "
"dalam kod, sila periksa sintaksnya."
@@ -2593,9 +2597,8 @@ msgid "Scene '%s' has broken dependencies:"
msgstr "Adegan '%s' mengandungi kebergantungan yang pecah:"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Clear Recent Scenes"
-msgstr "Kosongkan Adegan Terbaru"
+msgstr "Kosongkan Adegan-adegan Terbaru"
#: editor/editor_node.cpp
msgid ""
@@ -2608,7 +2611,6 @@ msgstr ""
"'aplikasi'."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"Selected scene '%s' does not exist, select a valid one?\n"
"You can change it later in \"Project Settings\" under the 'application' "
@@ -2647,81 +2649,66 @@ msgid "Show in FileSystem"
msgstr "Tunjukkan dalam FileSystem"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Play This Scene"
msgstr "Mainkan Adegan Ini"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Close Tab"
msgstr "Tutup Tab"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Undo Close Tab"
msgstr "Buat Asal Tutup Tab"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Close Other Tabs"
-msgstr "Tutup Tab Lain"
+msgstr "Tutup Tab-tab Lain"
#: editor/editor_node.cpp
msgid "Close Tabs to the Right"
msgstr "Tutup Tab-tab ke Kanan"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Close All Tabs"
msgstr "Tutup Semua Tab"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Switch Scene Tab"
msgstr "Tukar Tab Adegan"
#: editor/editor_node.cpp
-#, fuzzy
msgid "%d more files or folders"
-msgstr "%d lebih banyak fail atau folder"
+msgstr "%d lebih banyak fail-fail atau folder-folder"
#: editor/editor_node.cpp
-#, fuzzy
msgid "%d more folders"
-msgstr "%d lebih banyak folder"
+msgstr "%d lebih banyak folder-folder"
#: editor/editor_node.cpp
-#, fuzzy
msgid "%d more files"
-msgstr "%d lebih banyak fail"
+msgstr "%d lebih banyak fail-fail"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Dock Position"
msgstr "Kedudukan Dok"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Distraction Free Mode"
msgstr "Mod Bebas Gangguan"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Toggle distraction-free mode."
msgstr "Togol mod bebas gangguan."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Add a new scene."
msgstr "Tambah adegan baru."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Scene"
msgstr "Adegan"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Go to previously opened scene."
msgstr "Pergi ke adegan yang dibuka sebelum ini."
@@ -2731,14 +2718,12 @@ msgid "Copy Text"
msgstr "Semua Pilihan"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Next tab"
msgstr "Tab seterusnya"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Previous tab"
-msgstr "Tab terdahulu"
+msgstr "Tab sebelumnya"
#: editor/editor_node.cpp
msgid "Filter Files..."
@@ -2749,12 +2734,10 @@ msgid "Operations with scene files."
msgstr "Operasi dengan fail adegan."
#: editor/editor_node.cpp
-#, fuzzy
msgid "New Scene"
msgstr "Adegan Baru"
#: editor/editor_node.cpp
-#, fuzzy
msgid "New Inherited Scene..."
msgstr "Adegan Baru Diwarisi..."
@@ -3052,6 +3035,10 @@ msgid "About"
msgstr "Tentang"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Sokong Pembangunan Godot"
+
+#: editor/editor_node.cpp
#, fuzzy
msgid "Play the project."
msgstr "Main projek."
@@ -3205,21 +3192,24 @@ msgid "Open & Run a Script"
msgstr "Buka & Jalankan Skrip"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
-msgstr "Fail berikut gagal diekstrak dari pakej:"
+msgstr ""
+"Fail berikut lebih baru pada cakera.\n"
+"Apakah tindakan yang harus diambil?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
+#, fuzzy
msgid "Reload"
-msgstr ""
+msgstr "Muatkan Semula"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
+#, fuzzy
msgid "Resave"
-msgstr ""
+msgstr "Simpan semula"
#: editor/editor_node.cpp
#, fuzzy
@@ -3703,152 +3693,165 @@ msgstr "Muat turun Selesai."
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
-msgstr ""
+msgstr "Tidak dapat membuang fail sementara:"
#: editor/export_template_manager.cpp
msgid ""
"Templates installation failed.\n"
"The problematic templates archives can be found at '%s'."
msgstr ""
+"Pemasangan templat gagal.\n"
+"Arkib templat yang bermasalah boleh didapati di '%s'."
#: editor/export_template_manager.cpp
+#, fuzzy
msgid "Error requesting URL:"
-msgstr ""
+msgstr "Ralat semasa meminta URL:"
#: editor/export_template_manager.cpp
msgid "Connecting to Mirror..."
-msgstr ""
+msgstr "Menyambung ke Cermin..."
#: editor/export_template_manager.cpp
msgid "Disconnected"
-msgstr ""
+msgstr "Sambungan terputus"
#: editor/export_template_manager.cpp
+#, fuzzy
msgid "Resolving"
-msgstr ""
+msgstr "Menyelesaikan"
#: editor/export_template_manager.cpp
msgid "Can't Resolve"
-msgstr ""
+msgstr "Tidak Dapat Menyelesaikan"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Connecting..."
-msgstr ""
+msgstr "Menyambung..."
#: editor/export_template_manager.cpp
msgid "Can't Connect"
-msgstr ""
+msgstr "Tidak Dapat Menyambung"
#: editor/export_template_manager.cpp
msgid "Connected"
-msgstr ""
+msgstr "Disambungkan"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
+#, fuzzy
msgid "Requesting..."
-msgstr ""
+msgstr "Meminta..."
#: editor/export_template_manager.cpp
msgid "Downloading"
-msgstr ""
+msgstr "Memuat turun"
#: editor/export_template_manager.cpp
msgid "Connection Error"
-msgstr ""
+msgstr "Ralat Sambungan"
#: editor/export_template_manager.cpp
msgid "SSL Handshake Error"
-msgstr ""
+msgstr "Ralat Jabat Tangan SSL"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
-msgstr ""
+msgstr "Nyahmemampatkan Sumber Binaan Android"
#: editor/export_template_manager.cpp
msgid "Current Version:"
-msgstr ""
+msgstr "Versi Terkini:"
#: editor/export_template_manager.cpp
+#, fuzzy
msgid "Installed Versions:"
-msgstr ""
+msgstr "Versi Yang Dipasang:"
#: editor/export_template_manager.cpp
msgid "Install From File"
-msgstr ""
+msgstr "Pasang Dari Fail"
#: editor/export_template_manager.cpp
msgid "Remove Template"
-msgstr ""
+msgstr "Alih Keluar Templat"
#: editor/export_template_manager.cpp
msgid "Select Template File"
-msgstr ""
+msgstr "Pilih Fail Templat"
#: editor/export_template_manager.cpp
msgid "Godot Export Templates"
-msgstr ""
+msgstr "Templat Eksport Godot"
#: editor/export_template_manager.cpp
msgid "Export Template Manager"
-msgstr ""
+msgstr "Pengurus Templat Eksport"
#: editor/export_template_manager.cpp
msgid "Download Templates"
-msgstr ""
+msgstr "Muat Turun Templat-templat"
#: editor/export_template_manager.cpp
+#, fuzzy
msgid "Select mirror from list: (Shift+Click: Open in Browser)"
-msgstr ""
+msgstr "Pilih cermin daripada senarai: (Shift+Click: Buka dalam Pelayar)"
#: editor/filesystem_dock.cpp
+#, fuzzy
msgid "Favorites"
-msgstr ""
+msgstr "Kegemaran"
#: editor/filesystem_dock.cpp
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
+"Status: Import fail gagal. Sila betulkan fail dan import semula secara "
+"manual."
#: editor/filesystem_dock.cpp
+#, fuzzy
msgid ""
"Importing has been disabled for this file, so it can't be opened for editing."
msgstr ""
+"Pengimportan telah dilumpuhkan untuk fail ini, jadi tidak dapat dibuka untuk "
+"diedit."
#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
-msgstr ""
+msgstr "Tidak dapat memindahkan/menamakan semula akar sumber."
#: editor/filesystem_dock.cpp
msgid "Cannot move a folder into itself."
-msgstr ""
+msgstr "Tidak dapat memindahkan folder ke dalamnya sendiri."
#: editor/filesystem_dock.cpp
msgid "Error moving:"
-msgstr ""
+msgstr "Ralat semasa memindahkan:"
#: editor/filesystem_dock.cpp
msgid "Error duplicating:"
-msgstr ""
+msgstr "Ralat penduaan:"
#: editor/filesystem_dock.cpp
msgid "Unable to update dependencies:"
-msgstr ""
+msgstr "Tidak dapat mengemaskini kebergantungan:"
#: editor/filesystem_dock.cpp editor/scene_tree_editor.cpp
msgid "No name provided."
-msgstr ""
+msgstr "Tidak ada nama yang diberikan."
#: editor/filesystem_dock.cpp
msgid "Provided name contains invalid characters."
-msgstr ""
+msgstr "Nama yang diberikan mengandungi aksara yang tidak sah."
#: editor/filesystem_dock.cpp
msgid "A file or folder with this name already exists."
-msgstr ""
+msgstr "Fail atau folder dengan nama ini sudah wujud."
#: editor/filesystem_dock.cpp
msgid "Name contains invalid characters."
-msgstr ""
+msgstr "Nama mengandungi aksara yang tidak sah."
#: editor/filesystem_dock.cpp
msgid ""
@@ -3859,84 +3862,90 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
+"Fail atau folder berikut bercanggah dengan barang-barang dalam lokasi "
+"sasaran '%s':\n"
+"\n"
+"%s\n"
+"\n"
+"Adakah anda ingin menulis ganti mereka?"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
-msgstr ""
+msgstr "Menamakan semula fail:"
#: editor/filesystem_dock.cpp
msgid "Renaming folder:"
-msgstr ""
+msgstr "Menamakan semula folder:"
#: editor/filesystem_dock.cpp
msgid "Duplicating file:"
-msgstr ""
+msgstr "Menduakan fail:"
#: editor/filesystem_dock.cpp
msgid "Duplicating folder:"
-msgstr ""
+msgstr "Menduakan folder:"
#: editor/filesystem_dock.cpp
msgid "New Inherited Scene"
-msgstr ""
+msgstr "Adegan Baru Yang Diwarisi"
#: editor/filesystem_dock.cpp
msgid "Set As Main Scene"
-msgstr ""
+msgstr "Tetapkan Sebagai Adegan Utama"
#: editor/filesystem_dock.cpp
msgid "Open Scenes"
-msgstr ""
+msgstr "Buka Adegan-adegan"
#: editor/filesystem_dock.cpp
msgid "Instance"
-msgstr ""
+msgstr "Contoh"
#: editor/filesystem_dock.cpp
msgid "Add to Favorites"
-msgstr ""
+msgstr "Tambah ke Kegemaran"
#: editor/filesystem_dock.cpp
msgid "Remove from Favorites"
-msgstr ""
+msgstr "Alih keluar dari Kegemaran"
#: editor/filesystem_dock.cpp
msgid "Edit Dependencies..."
-msgstr ""
+msgstr "Sunting Kebergantungan..."
#: editor/filesystem_dock.cpp
msgid "View Owners..."
-msgstr ""
+msgstr "Lihat Pemilik..."
#: editor/filesystem_dock.cpp
msgid "Move To..."
-msgstr ""
+msgstr "Pindah Ke..."
#: editor/filesystem_dock.cpp
msgid "New Scene..."
-msgstr ""
+msgstr "Adegan Baru..."
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "New Script..."
-msgstr ""
+msgstr "Skrip Baru..."
#: editor/filesystem_dock.cpp
msgid "New Resource..."
-msgstr ""
+msgstr "Sumber Baru..."
#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
#: editor/script_editor_debugger.cpp
msgid "Expand All"
-msgstr ""
+msgstr "Kembangkan Semua"
#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
#: editor/script_editor_debugger.cpp
msgid "Collapse All"
-msgstr ""
+msgstr "Runtuhkan Semua"
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
-msgstr ""
+msgstr "Penduakan..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3945,107 +3954,116 @@ msgstr "Pindah Autoload"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
-msgstr ""
+msgstr "Namakan semula..."
#: editor/filesystem_dock.cpp
+#, fuzzy
msgid "Previous Folder/File"
-msgstr ""
+msgstr "Folder/Fail Terdahulu"
#: editor/filesystem_dock.cpp
msgid "Next Folder/File"
-msgstr ""
+msgstr "Folder/Fail Seterusnya"
#: editor/filesystem_dock.cpp
msgid "Re-Scan Filesystem"
-msgstr ""
+msgstr "Imbas Semula Sistem Fail"
#: editor/filesystem_dock.cpp
msgid "Toggle Split Mode"
-msgstr ""
+msgstr "Togol Mod Berpisah"
#: editor/filesystem_dock.cpp
msgid "Search files"
-msgstr ""
+msgstr "Cari fail"
#: editor/filesystem_dock.cpp
msgid ""
"Scanning Files,\n"
"Please Wait..."
msgstr ""
+"Mengimbas Fail,\n"
+"Sila Tunggu..."
#: editor/filesystem_dock.cpp
msgid "Move"
-msgstr ""
+msgstr "Pindah"
#: editor/filesystem_dock.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/project_manager.cpp editor/rename_dialog.cpp
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Rename"
-msgstr ""
+msgstr "Namakan semula"
#: editor/filesystem_dock.cpp
+#, fuzzy
msgid "Overwrite"
-msgstr ""
+msgstr "Tulis ganti"
#: editor/filesystem_dock.cpp
+#, fuzzy
msgid "Create Scene"
-msgstr ""
+msgstr "Cipta Adegan"
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "Create Script"
-msgstr ""
+msgstr "Cipta Skrip"
#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
msgid "Find in Files"
-msgstr ""
+msgstr "Cari dalam Fail-fail"
#: editor/find_in_files.cpp
msgid "Find:"
-msgstr ""
+msgstr "Cari:"
#: editor/find_in_files.cpp
msgid "Folder:"
-msgstr ""
+msgstr "Folder:"
#: editor/find_in_files.cpp
msgid "Filters:"
-msgstr ""
+msgstr "Penapis:"
#: editor/find_in_files.cpp
msgid ""
"Include the files with the following extensions. Add or remove them in "
"ProjectSettings."
msgstr ""
+"Sertakan fail-fail dengan sambungan berikut. Tambah atau keluar mereka dalam "
+"ProjectSettings."
#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find..."
-msgstr ""
+msgstr "Cari..."
#: editor/find_in_files.cpp editor/plugins/script_text_editor.cpp
msgid "Replace..."
-msgstr ""
+msgstr "Ganti..."
#: editor/find_in_files.cpp editor/progress_dialog.cpp scene/gui/dialogs.cpp
msgid "Cancel"
-msgstr ""
+msgstr "Batal"
#: editor/find_in_files.cpp
msgid "Find: "
-msgstr ""
+msgstr "Cari: "
#: editor/find_in_files.cpp
msgid "Replace: "
-msgstr ""
+msgstr "Ganti: "
#: editor/find_in_files.cpp
msgid "Replace all (no undo)"
-msgstr ""
+msgstr "Ganti semua (tiada buat asal)"
#: editor/find_in_files.cpp
+#, fuzzy
msgid "Searching..."
-msgstr ""
+msgstr "Mencari..."
#: editor/find_in_files.cpp
#, fuzzy
@@ -4064,23 +4082,23 @@ msgstr "%d padan."
#: editor/groups_editor.cpp
msgid "Add to Group"
-msgstr ""
+msgstr "Tambah ke Kumpulan"
#: editor/groups_editor.cpp
msgid "Remove from Group"
-msgstr ""
+msgstr "Alih keluar dari Kumpulan"
#: editor/groups_editor.cpp
msgid "Group name already exists."
-msgstr ""
+msgstr "Nama kumpulan sudah wujud."
#: editor/groups_editor.cpp
msgid "Invalid group name."
-msgstr ""
+msgstr "Nama kumpulan tidak sah."
#: editor/groups_editor.cpp
msgid "Rename Group"
-msgstr ""
+msgstr "Namakan semula Kumpulan"
#: editor/groups_editor.cpp
#, fuzzy
@@ -4089,113 +4107,117 @@ msgstr "Semua Pilihan"
#: editor/groups_editor.cpp editor/node_dock.cpp
msgid "Groups"
-msgstr ""
+msgstr "Kumpulan"
#: editor/groups_editor.cpp
msgid "Nodes Not in Group"
-msgstr ""
+msgstr "Nod-nod Tidak dalam Kumpulan"
#: editor/groups_editor.cpp editor/scene_tree_dock.cpp
#: editor/scene_tree_editor.cpp
msgid "Filter nodes"
-msgstr ""
+msgstr "Tapis nod-nod"
#: editor/groups_editor.cpp
msgid "Nodes in Group"
-msgstr ""
+msgstr "Nod-nod dalam Kumpulan"
#: editor/groups_editor.cpp
+#, fuzzy
msgid "Empty groups will be automatically removed."
-msgstr ""
+msgstr "Kumpulan kosong akan dikeluarkan secara automatik."
#: editor/groups_editor.cpp
msgid "Group Editor"
-msgstr ""
+msgstr "Editor Kumpulan"
#: editor/groups_editor.cpp
msgid "Manage Groups"
-msgstr ""
+msgstr "Urus Kumpulan-kumpulan"
#: editor/import/resource_importer_scene.cpp
msgid "Import as Single Scene"
-msgstr ""
+msgstr "Import sebagai Satu Adegan"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Animations"
-msgstr ""
+msgstr "Import dengan Animasi Berasingan"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Materials"
-msgstr ""
+msgstr "Import dengan Bahan Berasingan"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects"
-msgstr ""
+msgstr "Import dengan Objek Berasingan"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Materials"
-msgstr ""
+msgstr "Import dengan Objek+Bahan Berasingan"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Animations"
-msgstr ""
+msgstr "Import dengan Objek+Animasi Berasingan"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Materials+Animations"
-msgstr ""
+msgstr "Import dengan Bahan+Animasi Berasingan"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Materials+Animations"
-msgstr ""
+msgstr "Import dengan Objek+Bahan+Animasi Berasingan"
#: editor/import/resource_importer_scene.cpp
+#, fuzzy
msgid "Import as Multiple Scenes"
-msgstr ""
+msgstr "Import sebagai Pelbagai Adegan"
#: editor/import/resource_importer_scene.cpp
msgid "Import as Multiple Scenes+Materials"
-msgstr ""
+msgstr "Import sebagai Pelbagai Adegan +Bahan"
#: editor/import/resource_importer_scene.cpp
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Import Scene"
-msgstr ""
+msgstr "Import Adegan"
#: editor/import/resource_importer_scene.cpp
msgid "Importing Scene..."
-msgstr ""
+msgstr "Mengimport Adegan..."
#: editor/import/resource_importer_scene.cpp
msgid "Generating Lightmaps"
-msgstr ""
+msgstr "Menjana Peta Cahaya"
#: editor/import/resource_importer_scene.cpp
msgid "Generating for Mesh: "
-msgstr ""
+msgstr "Menjana untuk Mesh: "
#: editor/import/resource_importer_scene.cpp
msgid "Running Custom Script..."
-msgstr ""
+msgstr "Menjalankan Skrip Tersuai..."
#: editor/import/resource_importer_scene.cpp
msgid "Couldn't load post-import script:"
-msgstr ""
+msgstr "Tidak dapat memuatkan skrip pasca-import:"
#: editor/import/resource_importer_scene.cpp
msgid "Invalid/broken script for post-import (check console):"
-msgstr ""
+msgstr "Skrip tidak sah/rosak untuk pasca-import (periksa konsol):"
#: editor/import/resource_importer_scene.cpp
msgid "Error running post-import script:"
-msgstr ""
+msgstr "Ralat semasa menjalankan skrip pasca-import:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
msgstr ""
+"Adakah anda mengembalikan objek yang diperolehi dari Nod dalam kaedah "
+"'post_import()'?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
-msgstr ""
+msgstr "Menyimpan..."
#: editor/import_defaults_editor.cpp
#, fuzzy
@@ -4203,9 +4225,8 @@ msgid "Select Importer"
msgstr "Pilih Nod(Nod-nod) untuk Diimport"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Import"
+msgstr "Pengimport:"
#: editor/import_defaults_editor.cpp
#, fuzzy
@@ -4214,168 +4235,171 @@ msgstr "Muatkan Lalai"
#: editor/import_dock.cpp
msgid "Keep File (No Import)"
-msgstr ""
+msgstr "Simpan Fail (Tiada Import)"
#: editor/import_dock.cpp
msgid "%d Files"
-msgstr ""
+msgstr "%d Fail-fail"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
-msgstr ""
+msgstr "Tetapkan sebagai Lalai untuk '%s'"
#: editor/import_dock.cpp
msgid "Clear Default for '%s'"
-msgstr ""
+msgstr "Kosongkan Lalai untuk '%s'"
#: editor/import_dock.cpp
msgid "Import As:"
-msgstr ""
+msgstr "Import Sebagai:"
#: editor/import_dock.cpp
msgid "Preset"
-msgstr ""
+msgstr "Pratetap"
#: editor/import_dock.cpp
msgid "Reimport"
-msgstr ""
+msgstr "Import semula"
#: editor/import_dock.cpp
msgid "Save Scenes, Re-Import, and Restart"
-msgstr ""
+msgstr "Simpan Adegan, Import semula, dan Mula Semula"
#: editor/import_dock.cpp
msgid "Changing the type of an imported file requires editor restart."
-msgstr ""
+msgstr "Mengubah jenis fail yang diimport memerlukan editor dimulakan semula."
#: editor/import_dock.cpp
msgid ""
"WARNING: Assets exist that use this resource, they may stop loading properly."
msgstr ""
+"AMARAN: Terdapat aset-aset yang menggunakan sumber ini, mereka mungkin "
+"berhenti memuat dengan betul."
#: editor/inspector_dock.cpp
msgid "Failed to load resource."
-msgstr ""
+msgstr "Gagal untuk memuatkan sumber."
#: editor/inspector_dock.cpp
msgid "Expand All Properties"
-msgstr ""
+msgstr "Kembangkan Semua Sifat-sifat"
#: editor/inspector_dock.cpp
msgid "Collapse All Properties"
-msgstr ""
+msgstr "Tutup Semua Sifat-sifat"
#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp
msgid "Save As..."
-msgstr ""
+msgstr "Simpan Sebagai..."
#: editor/inspector_dock.cpp
msgid "Copy Params"
-msgstr ""
+msgstr "Salin Parameter-parameter"
#: editor/inspector_dock.cpp
msgid "Edit Resource Clipboard"
-msgstr ""
+msgstr "Sunting Papan Klip Sumber"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
-msgstr ""
+msgstr "Salin Sumber"
#: editor/inspector_dock.cpp
msgid "Make Built-In"
-msgstr ""
+msgstr "Buat Terbina Dalaman"
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
-msgstr ""
+msgstr "Buat Sub-Sumber Unik"
#: editor/inspector_dock.cpp
msgid "Open in Help"
-msgstr ""
+msgstr "Buka dalam Bantuan"
#: editor/inspector_dock.cpp
msgid "Create a new resource in memory and edit it."
-msgstr ""
+msgstr "Cipta sumber baru dalam ingatan dan suntingnya."
#: editor/inspector_dock.cpp
msgid "Load an existing resource from disk and edit it."
-msgstr ""
+msgstr "Muatkan sumber sedia ada dari cakera dan suntingnya."
#: editor/inspector_dock.cpp
msgid "Save the currently edited resource."
-msgstr ""
+msgstr "Simpan sumber yang sedang disunting."
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
-msgstr ""
+msgstr "Pergi ke objek yang disunting sebelumnya dalam sejarah."
#: editor/inspector_dock.cpp
msgid "Go to the next edited object in history."
-msgstr ""
+msgstr "Pergi ke objek yang disunting seterusnya dalam sejarah."
#: editor/inspector_dock.cpp
msgid "History of recently edited objects."
-msgstr ""
+msgstr "Sejarah objek-objek yang baru disunting."
#: editor/inspector_dock.cpp
msgid "Object properties."
-msgstr ""
+msgstr "Sifat-sifat objek."
#: editor/inspector_dock.cpp
msgid "Filter properties"
-msgstr ""
+msgstr "Tapis sifat-sifat"
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
-msgstr ""
+msgstr "Perubahan mungkin akan hilang!"
#: editor/multi_node_edit.cpp
msgid "MultiNode Set"
-msgstr ""
+msgstr "Tetap MultiNode"
#: editor/node_dock.cpp
msgid "Select a single node to edit its signals and groups."
-msgstr ""
+msgstr "Pilih satu nod untuk menyunting isyarat dan kumpulan-kumpulannya."
#: editor/plugin_config_dialog.cpp
msgid "Edit a Plugin"
-msgstr ""
+msgstr "Sunting satu Plugin"
#: editor/plugin_config_dialog.cpp
msgid "Create a Plugin"
-msgstr ""
+msgstr "Cipta satu Plugin"
#: editor/plugin_config_dialog.cpp
+#, fuzzy
msgid "Plugin Name:"
-msgstr ""
+msgstr "Nama Plugin:"
#: editor/plugin_config_dialog.cpp
msgid "Subfolder:"
-msgstr ""
+msgstr "Subfolder:"
#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
msgid "Language:"
-msgstr ""
+msgstr "Bahasa:"
#: editor/plugin_config_dialog.cpp
msgid "Script Name:"
-msgstr ""
+msgstr "Nama Skrip:"
#: editor/plugin_config_dialog.cpp
msgid "Activate now?"
-msgstr ""
+msgstr "Aktifkan sekarang?"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Polygon"
-msgstr ""
+msgstr "Buat Poligon"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Create points."
-msgstr ""
+msgstr "Cipta titik-titik."
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid ""
@@ -4383,27 +4407,30 @@ msgid ""
"LMB: Move Point\n"
"RMB: Erase Point"
msgstr ""
+"Sunting titik-titik.\n"
+"LMB: Pindah Titik\n"
+"RMB: Padam Titik"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Erase points."
-msgstr ""
+msgstr "Padam titik-titik."
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Edit Polygon"
-msgstr ""
+msgstr "Sunting Poligon"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Insert Point"
-msgstr ""
+msgstr "Masukkan Titik"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Edit Polygon (Remove Point)"
-msgstr ""
+msgstr "Sunting Poligon (Keluarkan Titik)"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Remove Polygon And Point"
-msgstr ""
+msgstr "Keluarkan Poligon Dan Titik"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4411,38 +4438,38 @@ msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Animation"
-msgstr ""
+msgstr "Tambah Animasi"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Load..."
-msgstr ""
+msgstr "Muatkan..."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Move Node Point"
-msgstr ""
+msgstr "Pindahkan Titik Nod"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Change BlendSpace1D Limits"
-msgstr ""
+msgstr "Tukar Had-had BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Change BlendSpace1D Labels"
-msgstr ""
+msgstr "Tukar Label-label BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "This type of node can't be used. Only root nodes are allowed."
-msgstr ""
+msgstr "Nod jenis ini tidak boleh digunakan. Hanya nod-nod akar dibenarkan."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Add Node Point"
-msgstr ""
+msgstr "Tambah Titik Nod"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4451,11 +4478,11 @@ msgstr "Tambah Titik Animasi"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Remove BlendSpace1D Point"
-msgstr ""
+msgstr "Keluarkan Titik BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Move BlendSpace1D Node Point"
-msgstr ""
+msgstr "Pindahkan Titik Nod BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4465,11 +4492,15 @@ msgid ""
"AnimationTree is inactive.\n"
"Activate to enable playback, check node warnings if activation fails."
msgstr ""
+"AnimationTree tidak aktif.\n"
+"Aktifkan untuk membenarkan main balik, periksa amaran nod jika pengaktifan "
+"gagal."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
+#, fuzzy
msgid "Set the blending position within the space"
-msgstr ""
+msgstr "Tetapkan kedudukan pengadunan dalam ruang"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4811,15 +4842,15 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "1 step"
-msgstr ""
+msgstr "1 langkah"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "2 steps"
-msgstr ""
+msgstr "2 langkah"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "3 steps"
-msgstr ""
+msgstr "3 langkah"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Differences Only"
@@ -7143,7 +7174,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
msgid "Go to Function"
-msgstr ""
+msgstr "Pergi ke Fungsi"
#: editor/plugins/script_text_editor.cpp
msgid "Only resources from filesystem can be dropped."
@@ -7243,9 +7274,8 @@ msgid "Complete Symbol"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Evaluate Selection"
-msgstr "Semua Pilihan"
+msgstr "Menilai Pemilihan"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
@@ -7419,9 +7449,8 @@ msgid "Yaw"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Saiz: "
+msgstr "Saiz"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7680,7 +7709,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Insert Animation Key"
-msgstr ""
+msgstr "Masukkan Kunci Animasi"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Focus Origin"
@@ -8176,15 +8205,15 @@ msgstr "Tidak Aktif"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Tab 1"
-msgstr ""
+msgstr "Tab 1"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Tab 2"
-msgstr ""
+msgstr "Tab 2"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Tab 3"
-msgstr ""
+msgstr "Tab 3"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Editable Item"
@@ -8233,9 +8262,8 @@ msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Cut Selection"
-msgstr "Semua Pilihan"
+msgstr "Potong Pilihan"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint TileMap"
@@ -8318,9 +8346,8 @@ msgid "Flip Vertically"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Clear Transform"
-msgstr "Anim Ubah Penukaran"
+msgstr "Kosongkan Transformasi"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Add Texture(s) to TileSet."
@@ -8731,7 +8758,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(GLES3 only)"
-msgstr ""
+msgstr "(GLES3 sahaja)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add Output"
@@ -8818,7 +8845,7 @@ msgstr "Anim Menduakan Kunci"
#: editor/plugins/visual_shader_editor_plugin.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Paste Nodes"
-msgstr ""
+msgstr "Tampal Nod"
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -9608,7 +9635,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Export all resources in the project"
-msgstr ""
+msgstr "Eksport semua sumber dalam projek"
#: editor/project_export.cpp
msgid "Export selected scenes (and dependencies)"
@@ -10032,7 +10059,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -10098,11 +10125,11 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "X Button 1"
-msgstr ""
+msgstr "Butang X 1"
#: editor/project_settings_editor.cpp
msgid "X Button 2"
-msgstr ""
+msgstr "Butang X 2"
#: editor/project_settings_editor.cpp
msgid "Joypad Axis Index:"
@@ -10392,9 +10419,8 @@ msgid "Select Method"
msgstr ""
#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Batch Rename"
-msgstr "Ubah Nama Trek Anim"
+msgstr "Namakan Semula Kumpulan"
#: editor/rename_dialog.cpp
msgid "Replace:"
@@ -11001,7 +11027,7 @@ msgstr ""
#: editor/script_create_dialog.cpp
msgid "Allowed: a-z, A-Z, 0-9, _ and ."
-msgstr ""
+msgstr "Benarkan: a-z, A-Z, 0-9, _ dan ."
#: editor/script_create_dialog.cpp
msgid "Built-in script (into scene file)."
@@ -11923,15 +11949,15 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Copy Nodes"
-msgstr ""
+msgstr "Salin Nod"
#: modules/visual_script/visual_script_editor.cpp
msgid "Cut Nodes"
-msgstr ""
+msgstr "Potong Nod"
#: modules/visual_script/visual_script_editor.cpp
msgid "Make Function"
-msgstr ""
+msgstr "Buat Fungsi"
#: modules/visual_script/visual_script_editor.cpp
msgid "Refresh Graph"
@@ -12046,10 +12072,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
@@ -12338,7 +12376,7 @@ msgstr ""
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be PhysicsBody2Ds"
-msgstr ""
+msgstr "Nod A dan Nod B mestilah PhysicsBody2Ds"
#: scene/2d/joints_2d.cpp
msgid "Node A must be a PhysicsBody2D"
diff --git a/editor/translations/nb.po b/editor/translations/nb.po
index 398330b3e9..f040c4ca0e 100644
--- a/editor/translations/nb.po
+++ b/editor/translations/nb.po
@@ -17,12 +17,13 @@
# Petter Reinholdtsen <pere-weblate@hungry.com>, 2019, 2020.
# Patrick Sletvold <patricksletvold@hotmail.com>, 2021.
# Kristoffer <kskau93@gmail.com>, 2021.
+# Lili Zoey <sayaks1@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-31 03:53+0000\n"
-"Last-Translator: Kristoffer <kskau93@gmail.com>\n"
+"PO-Revision-Date: 2021-05-29 13:49+0000\n"
+"Last-Translator: Lili Zoey <sayaks1@gmail.com>\n"
"Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/godot-"
"engine/godot/nb_NO/>\n"
"Language: nb\n"
@@ -30,7 +31,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -188,9 +189,8 @@ msgid "Anim Multi Change Keyframe Value"
msgstr "Anim Endre flere Nøkkelbildeverdier"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Call"
-msgstr "Anim Forandre Kall"
+msgstr "Anim Forandre flere Kall"
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
@@ -924,9 +924,8 @@ msgid "Signals"
msgstr "Signaler"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Filter signals"
-msgstr "Filtrer Filer..."
+msgstr "Filtrer Signaler"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
@@ -939,9 +938,8 @@ msgid "Disconnect All"
msgstr "Koble Fra"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Edit..."
-msgstr "Rediger"
+msgstr "Rediger..."
#: editor/connections_dialog.cpp
#, fuzzy
@@ -1150,6 +1148,10 @@ msgstr "Endre listeverdi"
msgid "Thanks from the Godot community!"
msgstr "Takk fra Godot-samfunnet!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine sine bidragsytere"
@@ -1496,7 +1498,7 @@ msgstr ""
#: editor/editor_autoload_settings.cpp
msgid "Keyword cannot be used as an autoload name."
-msgstr ""
+msgstr "Nøkkelord kan ikke brukes som autoloadnavn."
#: editor/editor_autoload_settings.cpp
msgid "Autoload '%s' already exists!"
@@ -2640,8 +2642,9 @@ msgstr "Kan ikke laste addon-skript fra bane: '%s'."
#: editor/editor_node.cpp
#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Kunne ikke laste tillegsskript fra sti: '%s' Script er ikke i verktøymodus."
@@ -3102,6 +3105,10 @@ msgid "About"
msgstr "Om"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Spill prosjektet."
@@ -4128,7 +4135,7 @@ msgstr "Legg til i Gruppe"
#: editor/groups_editor.cpp
msgid "Empty groups will be automatically removed."
-msgstr ""
+msgstr "Tomme grupper vil automatisk bli fjernet."
#: editor/groups_editor.cpp
msgid "Group Editor"
@@ -4968,11 +4975,11 @@ msgstr "Legg til node"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "End"
-msgstr ""
+msgstr "Slutt"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Immediate"
-msgstr ""
+msgstr "Umiddelbart"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Sync"
@@ -5330,11 +5337,11 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (A-Z)"
-msgstr ""
+msgstr "Navn (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (Z-A)"
-msgstr ""
+msgstr "Navn (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
#, fuzzy
@@ -8819,9 +8826,8 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete selected Rect."
-msgstr "Slett valgte filer?"
+msgstr "Slett valgte Rect."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -10446,7 +10452,7 @@ msgstr "Museknapp"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12575,10 +12581,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/nl.po b/editor/translations/nl.po
index e12d8c9324..616c3ae69a 100644
--- a/editor/translations/nl.po
+++ b/editor/translations/nl.po
@@ -43,11 +43,14 @@
# kitfka <philipthuijs@gmail.com>, 2020.
# Mike van Leeuwen <mkvanleeuwen@gmail.com>, 2020.
# marnicq van loon <marnicqvanloon@gmail.com>, 2020.
+# T-rex08 <ipadtriceratops@gmail.com>, 2021.
+# Dwarffish <hoogvlietjohan@gmail.com>, 2021.
+# Arthur de Roos <arthur.de.roos@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-05 23:44+0000\n"
+"PO-Revision-Date: 2021-06-05 08:32+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"
@@ -56,7 +59,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1160,6 +1163,10 @@ msgstr "Waarde wijzigen"
msgid "Thanks from the Godot community!"
msgstr "Bedankt van de Godot gemeenschap!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine medewerkers"
@@ -1197,11 +1204,11 @@ msgstr "Gouden Sponsors"
#: editor/editor_about.cpp
msgid "Silver Sponsors"
-msgstr "Zilveren Sponsoren"
+msgstr "Zilveren Sponsors"
#: editor/editor_about.cpp
msgid "Bronze Sponsors"
-msgstr "Bronzen Sponsoren"
+msgstr "Bronzen Sponsors"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
@@ -1643,34 +1650,31 @@ msgstr ""
"'Driver Fallback Enabled' uit."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"Doelplatform vereist 'ETC' textuurcompressie voor GLES2. Schakel 'Import "
+"Doelplatform vereist 'PVRTC' textuurcompressie voor GLES2. Schakel 'Import "
"Etc' in bij de Projectinstellingen."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
-"Doelplatform vereist 'ETC2' textuurcompressie voor GLES3. Schakel 'Import "
-"Etc 2' in de Projectinstellingen in."
+"Doelplatform vereist 'ETC2' of 'PVRTC' textuurcompressie voor GLES3. Schakel "
+"'Import Etc 2' of 'Import Pvrtc' in de Projectinstellingen in."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for the driver fallback "
"to GLES2.\n"
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
-"Doelplatform vereist 'ETC' textuurcompressie zodat het stuurprogramma kan "
+"Doelplatform vereist 'PVRTC' textuurcompressie zodat het stuurprogramma kan "
"terugvallen op GLES2.\n"
-"Schakel 'Import Etc' in bij de Projectinstellingen, of schakel de optie "
+"Schakel 'Import Pvrtc' in bij de Projectinstellingen, of schakel de optie "
"'Driver Fallback Enabled' uit."
#: editor/editor_export.cpp platform/android/export/export.cpp
@@ -1931,7 +1935,7 @@ msgstr "Favoriet Omschakelen"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
-msgstr "Modus omschakelen"
+msgstr "Modus wisselen"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
@@ -2030,7 +2034,7 @@ msgstr "Beschrijving"
#: editor/editor_help.cpp
msgid "Online Tutorials"
-msgstr "Online Zelfstudie"
+msgstr "Online Handleidingen"
#: editor/editor_help.cpp
msgid "Properties"
@@ -2577,10 +2581,8 @@ msgstr ""
"mislukt."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr ""
-"Onmogelijk om scriptveld te vinden voor de plugin op: 'res://addons/%s'."
+msgstr "Onmogelijk om scriptveld te vinden voor de plugin op: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2588,11 +2590,13 @@ msgstr "Volgend script kon niet geladen worden: '%s'."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"Script kon niet geladen worden van het pad: '%s'. Er lijkt een fout in de "
-"code te zijn, controleer de syntax."
+"Extra script kon niet geladen worden van het pad: '%s'. Dit kan veroorzaakt "
+"worden door een fout in dat script.\n"
+"Schakel de extra uit op '%s' om toekomstige fouten te vermijden."
#: editor/editor_node.cpp
msgid ""
@@ -2884,7 +2888,6 @@ msgid "Small Deploy with Network Filesystem"
msgstr "Kleine uitrol met netwerkbestandssysteem"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, using one-click deploy for Android will only "
"export an executable without the project data.\n"
@@ -2893,11 +2896,11 @@ msgid ""
"On Android, deploying will use the USB cable for faster performance. This "
"option speeds up testing for projects with large assets."
msgstr ""
-"Wanneer deze optie is ingeschakeld, zal export of deploy een minimaal "
-"uitvoerbaar bestand creëren.\n"
+"Wanneer deze optie is ingeschakeld, zal op Android een uitvoerbaar bestand "
+"zonder de project data geëxporteerd worden.\n"
"Het bestandssysteem wordt beschikbaar gesteld aan het project door de editor "
"over het netwerk.\n"
-"Op Android zal deploy de USB verbinding gebruiken voor hogere prestaties. "
+"Op Android zal de USB verbinding gebruikt worden voor hogere prestaties. "
"Deze optie versnelt het testen van spellen met veel data."
#: editor/editor_node.cpp
@@ -2905,26 +2908,24 @@ msgid "Visible Collision Shapes"
msgstr "Botsingsvormen tonen"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, collision shapes and raycast nodes (for 2D and "
"3D) will be visible in the running project."
msgstr ""
-"Botsingsdetectievormen en raycast knopen (voor 2D en 3D) zullen zichtbaar "
-"zijn in het draaiend spel wanneer deze optie aan staat."
+"Wanneer deze optie aan staat zullen botsingsdetectievormen en raycast knopen "
+"(voor 2D en 3D) zichtbaar zijn in het draaiend spel."
#: editor/editor_node.cpp
msgid "Visible Navigation"
msgstr "Navigatie zichtbaar"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, navigation meshes and polygons will be visible "
"in the running project."
msgstr ""
-"Navigatie meshes en polygonen zijn zichtbaar in het draaiend spel wanneer "
-"deze optie aanstaat."
+"Navigatie vormen zijn zichtbaar in het draaiend spel wanneer deze optie "
+"aanstaat."
#: editor/editor_node.cpp
msgid "Synchronize Scene Changes"
@@ -2947,17 +2948,16 @@ msgid "Synchronize Script Changes"
msgstr "Veranderingen in scripts synchroniseren"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any script that is saved will be reloaded in "
"the running project.\n"
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
-"Wanneer deze optie aanstaat wordt ieder script dat wordt opgeslagen "
-"toegepast op het draaiend spel.\n"
+"Wanneer deze optie aanstaat wordt ieder script dat is opgeslagen herlopen in "
+"het draaiende spel.\n"
"Wanneer dit op afstand wordt gebruikt op een andere machine, is dit "
-"efficiënter met het netwerk bestandssysteem."
+"efficiënter met de netwerk bestandssysteem optie aan."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
@@ -3037,6 +3037,10 @@ msgid "About"
msgstr "Over"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Ondersteun Godot Development"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Speel het project."
@@ -3178,13 +3182,12 @@ msgid "Open & Run a Script"
msgstr "Voer Een Script Uit"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
msgstr ""
"De volgende bestanden zijn nieuwer op de schijf.\n"
-"Welke aktie moet worden genomen?:"
+"Welke actie moet worden genomen?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -3446,13 +3449,12 @@ msgid "Add Key/Value Pair"
msgstr "Sleutel/waarde-paar toevoegen"
#: editor/editor_run_native.cpp
-#, fuzzy
msgid ""
"No runnable export preset found for this platform.\n"
"Please add a runnable preset in the Export menu or define an existing preset "
"as runnable."
msgstr ""
-"Geen uitvoerbare export preset gevonden voor dit platform.\n"
+"Geen uitvoerbare exporteer preset gevonden voor dit platform.\n"
"Voeg een uitvoerbare preset toe in het exportmenu."
#: editor/editor_run_script.cpp
@@ -3729,6 +3731,8 @@ msgstr ""
msgid ""
"Importing has been disabled for this file, so it can't be opened for editing."
msgstr ""
+"Importeren is uitgeschakeld voor dit bestand, het kan niet worden geopend om "
+"te bewerken."
#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
@@ -3775,11 +3779,12 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
-"De volgende bestanden of mappen conflicteren met elementen in '%s':\n"
+"De volgende bestanden of folders conflicteren met de bestanden in de locatie "
+"'%s':\n"
"\n"
"%s\n"
"\n"
-"Wil je deze overschrijven?"
+"Wilt u deze bestanden overschrijven?"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
@@ -4119,23 +4124,20 @@ msgid "Saving..."
msgstr "Opslaan..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Selecteermodus"
+msgstr "Selecteer Importeren"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importeren"
+msgstr "Lader:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Laad standaard"
+msgstr "Reset naar standaard waarden"
#: editor/import_dock.cpp
msgid "Keep File (No Import)"
-msgstr ""
+msgstr "Bestand bewaren (niet importeren)"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -5104,9 +5106,8 @@ msgid "Got:"
msgstr "Gekregen:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Failed SHA-256 hash check"
-msgstr "SHA256-proef mislukt"
+msgstr "SHA256-hash controle mislukt"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5237,14 +5238,12 @@ msgid "Assets ZIP File"
msgstr "Assets ZIP Bestand"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
-"Kan geen opslag pad voor de lichtmappen bepalen.\n"
-"Sla jouw scène op (om lichtmappen op te slaan in dezelfde map) of kies een "
-"opslag pad vanaf de BakedLightmap eigenschappen."
+"Kan geen opslagplaats voor de lichtmap afbeeldingen bepalen.\n"
+"Sla uw scène op en probeer opnieuw."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5263,17 +5262,22 @@ msgstr ""
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed determining lightmap size. Maximum lightmap size too small?"
msgstr ""
+"Lichtmap grootte bepalen mislukt. Is de maximale lichtmap grootte te klein?"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Some mesh is invalid. Make sure the UV2 channel values are contained within "
"the [0.0,1.0] square region."
msgstr ""
+"Sommige vormen zijn ongeldig. Controleer of de UV2 kanaal waarden binnen het "
+"vierkante [0.0,1.0] bereik zijn."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
+"Godot editor is gemaakt zonder ray tracing ondersteuning, en lichtmappen "
+"kunnen hierdoor niet ingebakken worden."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
@@ -5350,7 +5354,7 @@ msgstr "Maak nieuwe horizontale en verticale gidsen"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr "Draaipuntverschuiving van het CanvasItem „%s“ op (%d, %d) zetten"
+msgstr "CanvasItem \"%s\" draaipunt verschuiving instellen als (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotate %d CanvasItems"
@@ -6680,7 +6684,6 @@ msgid "Shift: Move All"
msgstr "Shift: Beweeg alles"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Shift+Command: Scale"
msgstr "Shift+Ctrl: Schaal"
@@ -7416,9 +7419,8 @@ msgid "Yaw"
msgstr "Yaw"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Grootte: "
+msgstr "Grootte"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -9578,7 +9580,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "A reference to an existing uniform."
-msgstr "Een verwijzing naar een bestaande uniform."
+msgstr "Een verwijzing naar een bestaand uniform."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(Fragment/Light mode only) Scalar derivative function."
@@ -9945,7 +9947,7 @@ msgstr "OpenGL ES 3.0"
#: editor/project_manager.cpp
msgid "Not supported by your GPU drivers."
-msgstr "Niet ondersteund door de GPU drivers op dit systeem."
+msgstr "Niet ondersteund door uw GPU drivers."
#: editor/project_manager.cpp
msgid ""
@@ -10102,9 +10104,8 @@ msgid ""
"Language changed.\n"
"The interface will update after restarting the editor or project manager."
msgstr ""
-"De taal is veranderd. \n"
-"De gebruikersomgeving wordt bij het herstarten van de editor of "
-"projectbeheer bijgewerkt."
+"De taal is veranderd.\n"
+"De gebruikersomgeving wordt bijgewerkt na het herstarten."
#: editor/project_manager.cpp
msgid ""
@@ -10124,9 +10125,8 @@ msgid "Projects"
msgstr "Projecten"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Loading, please wait..."
-msgstr "Mirrors ophalen, even wachten a.u.b..."
+msgstr "Aan het laden, even wachten a.u.b..."
#: editor/project_manager.cpp
msgid "Last Modified"
@@ -10197,7 +10197,7 @@ msgstr "Muis Knop"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Ongeldige actienaam. Kan niet leeg zijn en mag niet '/', ':', '=', '\\' of "
@@ -10500,9 +10500,8 @@ msgid "Plugins"
msgstr "Plugins"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Laad standaard"
+msgstr "Import"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -10755,12 +10754,10 @@ msgid "Instance Child Scene"
msgstr "Scène instantiëren"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Can't paste root node into the same scene."
-msgstr "Kan deze operatie niet uitvoeren op knopen uit een vreemde scène!"
+msgstr "Kan de wortelknoop niet in dezelfde scène plakken."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Paste Node(s)"
msgstr "Knopen plakken"
@@ -10804,7 +10801,7 @@ msgstr "Knoop tot wortelknoop maken"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes and any children?"
-msgstr "%d knopen en hun (eventuele) kinderen verwijderen?"
+msgstr "Verwijder %d knopen en eventuele kinderen?"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes?"
@@ -10892,7 +10889,6 @@ msgid "Attach Script"
msgstr "Script toevoegen"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Cut Node(s)"
msgstr "Knopen knippen"
@@ -11410,7 +11406,7 @@ msgstr "Editor Instellingen"
#: editor/settings_config_dialog.cpp
msgid "Shortcuts"
-msgstr "Snelkoppelingen"
+msgstr "Sneltoetsen"
#: editor/settings_config_dialog.cpp
msgid "Binding"
@@ -12266,10 +12262,22 @@ msgstr ""
"projectmenu kan het geïnstalleerd worden."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr "Debug Keystore is niet ingesteld of aanwezig in de Editor Settings."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr "Release-Keystore is verkeerd ingesteld in de exportinstelingen."
@@ -12297,7 +12305,7 @@ msgstr "Ongeldig Android SDK pad voor custom build in Editor Settings."
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
-msgstr ""
+msgstr "'build tools' map ontbreekt!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
@@ -12347,19 +12355,20 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."
-msgstr ""
+msgstr "\"Export AAB\" is alleen geldig als \"Use Custom Build\" aan staat."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
msgstr ""
+"Bestandsnaam niet toegestaan! Android App Bundle vereist een *.aab extensie."
#: platform/android/export/export.cpp
msgid "APK Expansion not compatible with Android App Bundle."
-msgstr ""
+msgstr "APK Expansion werkt niet samen met Android App Bundle."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android APK requires the *.apk extension."
-msgstr ""
+msgstr "Bestandsnaam niet toegestaan! Android APK vereist een *.apk extensie."
#: platform/android/export/export.cpp
msgid ""
@@ -12395,13 +12404,15 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Moving output"
-msgstr ""
+msgstr "Output verplaatsen"
#: platform/android/export/export.cpp
msgid ""
"Unable to copy and rename export file, check gradle project directory for "
"outputs."
msgstr ""
+"Niet in staat om het export bestand te kopiëren en hernoemen. Controleer de "
+"gradle project folder voor outputs."
#: platform/iphone/export/export.cpp
msgid "Identifier is missing."
@@ -12593,6 +12604,9 @@ msgid ""
"Polygon-based shapes are not meant be used nor edited directly through the "
"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
msgstr ""
+"Op polygonen gebaseerde vormen zijn niet bedoeld om rechtstreeks via het "
+"CollisionShape2D-knooppunt te worden gebruikt of bewerkt. Gebruik in plaats "
+"daarvan het CollisionPolygon2D-knooppunt."
#: scene/2d/cpu_particles_2d.cpp
msgid ""
@@ -12604,15 +12618,15 @@ msgstr ""
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be PhysicsBody2Ds"
-msgstr ""
+msgstr "Knoop A en Knoop B moeten PhysicsBody2D zijn"
#: scene/2d/joints_2d.cpp
msgid "Node A must be a PhysicsBody2D"
-msgstr ""
+msgstr "Knoop A moet een PhysicsBody2D zijn"
#: scene/2d/joints_2d.cpp
msgid "Node B must be a PhysicsBody2D"
-msgstr ""
+msgstr "Knoop B moet een PhysicsBody2D zijn"
#: scene/2d/joints_2d.cpp
msgid "Joint is not connected to two PhysicsBody2Ds"
@@ -12620,7 +12634,7 @@ msgstr ""
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be different PhysicsBody2Ds"
-msgstr ""
+msgstr "Knoop A en Knoop B moeten verschillende PhysicsBody2D's zijn"
#: scene/2d/light_2d.cpp
msgid ""
@@ -12782,14 +12796,12 @@ msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Geometrie aan het ontleden..."
+msgstr "Geometrie aan het voorbereiden (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "Bekijk Omgeving"
+msgstr "Omgeving aan het voorbereiden"
#: scene/3d/baked_lightmap.cpp
#, fuzzy
@@ -12797,14 +12809,12 @@ msgid "Generating capture"
msgstr "Bouw Lightmappen"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Saving lightmaps"
-msgstr "Bouw Lightmappen"
+msgstr "Lightmappen aan het opslaan"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Done"
-msgstr "Klaar!"
+msgstr "Klaar"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12955,15 +12965,15 @@ msgstr ""
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be PhysicsBodies"
-msgstr ""
+msgstr "Knoop A en Knoop B moeten PhysicsBody's zijn"
#: scene/3d/physics_joint.cpp
msgid "Node A must be a PhysicsBody"
-msgstr ""
+msgstr "Knoop A moet een PhysicsBody zijn"
#: scene/3d/physics_joint.cpp
msgid "Node B must be a PhysicsBody"
-msgstr ""
+msgstr "Knoop B moet een PhysicsBody zijn"
#: scene/3d/physics_joint.cpp
msgid "Joint is not connected to any PhysicsBodies"
@@ -12971,7 +12981,7 @@ msgstr ""
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be different PhysicsBodies"
-msgstr ""
+msgstr "Knoop A en Knoop B moeten PhysicsBody's zijn"
#: scene/3d/remote_transform.cpp
msgid ""
diff --git a/editor/translations/or.po b/editor/translations/or.po
index 77e9075f6a..58214daf10 100644
--- a/editor/translations/or.po
+++ b/editor/translations/or.po
@@ -1080,6 +1080,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2438,8 +2442,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2844,6 +2849,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9677,7 +9686,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11678,10 +11687,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index 122c89f2b6..9ae69c3d75 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -52,7 +52,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"PO-Revision-Date: 2021-05-19 20:16+0000\n"
"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
@@ -1157,6 +1157,10 @@ msgstr "Zmień wartość słownika"
msgid "Thanks from the Godot community!"
msgstr "Podziękowania od społeczności Godota!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Współtwórcy Godot Engine"
@@ -2573,11 +2577,13 @@ msgstr "Nie można załadować skryptu dodatku z ścieżki: \"%s\"."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"Nie można załadować skryptu dodatku ze ścieżki: \"%s\" W kodzie znajduje się "
-"błąd, sprawdź składnię."
+"Nie można załadować skryptu dodatku ze ścieżki: \"%s\". Może to być "
+"spowodowane błędem w skrypcie.\n"
+"Wyłączam dodatek \"%s\" by uniknąć dalszych błędów."
#: editor/editor_node.cpp
msgid ""
@@ -3020,6 +3026,10 @@ msgid "About"
msgstr "O silniku"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Wesprzyj rozwój Godota"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Uruchom projekt."
@@ -3266,11 +3276,11 @@ msgstr "Zmierzono:"
#: editor/editor_profiler.cpp
msgid "Frame Time (sec)"
-msgstr "Czas ramki (sek)"
+msgstr "Czas klatki (sek)"
#: editor/editor_profiler.cpp
msgid "Average Time (sec)"
-msgstr "Åšredni Czas (sek)"
+msgstr "Åšredni czas (sek)"
#: editor/editor_profiler.cpp
msgid "Frame %"
@@ -3282,11 +3292,11 @@ msgstr "Klatka fizyki %"
#: editor/editor_profiler.cpp
msgid "Inclusive"
-msgstr "Włącznie"
+msgstr "ÅÄ…cznie"
#: editor/editor_profiler.cpp
msgid "Self"
-msgstr "Ten obiekt"
+msgstr "Pojedynczo"
#: editor/editor_profiler.cpp
msgid "Frame #:"
@@ -5254,8 +5264,8 @@ msgstr ""
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
-"Godot został zbudowany bez wsparcia ray tracingu, mapy światła nie mogą być "
-"wypalone."
+"Edytor Godota został zbudowany bez wsparcia ray tracingu, mapy światła nie "
+"mogą zostać wypalone."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
@@ -7580,6 +7590,8 @@ msgstr "Obroty widoku zablokowane"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"By przybliżyć bardziej, zmień płaszczyzny odcięcia kamery (Widok -> "
+"Ustawienia...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -10159,7 +10171,7 @@ msgstr "Przycisk myszy"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Niepoprawna nazwa akcji. Nie może być pusta ani zawierać \"/\", \":\", \"="
@@ -10971,6 +10983,9 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"Kiedy wybrany, dok zdalnego drzewa sceny będzie powodował przestoje za "
+"każdym razem, gdy się aktualizuje.\n"
+"Zmień z powrotem na drzewo lokalne, by zwiększyć wydajność."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12217,12 +12232,24 @@ msgstr ""
"go z menu Projekt."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Debugowy keystore nieskonfigurowany w Ustawieniach Edytora ani w profilu "
"eksportu."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Wydaniowy keystore jest niepoprawnie skonfigurowany w profilu eksportu."
diff --git a/editor/translations/pr.po b/editor/translations/pr.po
index 24e2c7146a..e308deb01b 100644
--- a/editor/translations/pr.po
+++ b/editor/translations/pr.po
@@ -6,12 +6,13 @@
# Zion Nimchuk <zionnimchuk@gmail.com>, 2016-2017.
# Allan Nordhøy <epost@anotheragency.no>, 2018.
# David Fatheree <david.fathereewcchs@gmail.com>, 2020.
+# Nathan Franke <natfra@pm.me>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-22 06:40+0000\n"
-"Last-Translator: David Fatheree <david.fathereewcchs@gmail.com>\n"
+"PO-Revision-Date: 2021-06-11 14:49+0000\n"
+"Last-Translator: Nathan Franke <natfra@pm.me>\n"
"Language-Team: Pirate <https://hosted.weblate.org/projects/godot-engine/"
"godot/pr/>\n"
"Language: pr\n"
@@ -19,7 +20,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -30,7 +31,7 @@ msgstr ""
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "Expected a strin' o' length 1 (a character)."
+msgstr "Expected a strin' o' length 1 (jus' a character)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -48,56 +49,55 @@ msgstr ""
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
-msgstr "Yer index property name '%s' in node %s be walkin' th' plank!"
+msgstr "Yer opera'r %s be usin' th' wrong grub, %s an' %s!"
#: core/math/expression.cpp
msgid "Invalid index of type %s for base type %s"
-msgstr "Yer index property name '%s' in node %s be walkin' th' plank!"
+msgstr "Yer index type %s o' node type %s be walkin' th' plank!"
#: core/math/expression.cpp
msgid "Invalid named index '%s' for base type %s"
msgstr ""
#: core/math/expression.cpp
-#, fuzzy
msgid "Invalid arguments to construct '%s'"
-msgstr ": Evil argument of th' type: "
+msgstr "Evil argument o' th' type '%s'"
#: core/math/expression.cpp
msgid "On call to '%s':"
-msgstr ""
+msgstr "O' th' call t' '%s':"
#: core/ustring.cpp
msgid "B"
-msgstr ""
+msgstr "' Barnacles"
#: core/ustring.cpp
msgid "KiB"
-msgstr ""
+msgstr "' Kilo-Barnacles"
#: core/ustring.cpp
msgid "MiB"
-msgstr ""
+msgstr "' Mega-Barnacles"
#: core/ustring.cpp
msgid "GiB"
-msgstr ""
+msgstr "' Giga-Barnacles"
#: core/ustring.cpp
msgid "TiB"
-msgstr ""
+msgstr "' Tera-Barnacles"
#: core/ustring.cpp
msgid "PiB"
-msgstr ""
+msgstr "' Peta-Barnacles"
#: core/ustring.cpp
msgid "EiB"
-msgstr ""
+msgstr "' Exa-Barnacles"
#: editor/animation_bezier_editor.cpp
msgid "Free"
-msgstr ""
+msgstr "O'en"
#: editor/animation_bezier_editor.cpp
msgid "Balanced"
@@ -109,11 +109,11 @@ msgstr "See'in Double"
#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp
msgid "Time:"
-msgstr ""
+msgstr "Sundial:"
#: editor/animation_bezier_editor.cpp
msgid "Value:"
-msgstr ""
+msgstr "Grub:"
#: editor/animation_bezier_editor.cpp
msgid "Insert Key Here"
@@ -125,9 +125,8 @@ msgid "Duplicate Selected Key(s)"
msgstr "Yar, Blow th' Selected Down!"
#: editor/animation_bezier_editor.cpp
-#, fuzzy
msgid "Delete Selected Key(s)"
-msgstr "Yar, Blow th' Selected Down!"
+msgstr "Yar, Plunder th' Selected!"
#: editor/animation_bezier_editor.cpp
#, fuzzy
@@ -1124,6 +1123,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2137,7 +2140,7 @@ msgstr ""
#: editor/editor_log.cpp
msgid "Output:"
-msgstr ""
+msgstr "Cap'n's Log:"
#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp
#, fuzzy
@@ -2156,7 +2159,7 @@ msgstr ""
#: editor/editor_log.cpp
msgid "Clear Output"
-msgstr ""
+msgstr "Clear Cap'n's Log"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
@@ -2519,8 +2522,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2780,7 +2784,7 @@ msgstr ""
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/project_export.cpp
msgid "Debug"
-msgstr ""
+msgstr "Debuggin'"
#: editor/editor_node.cpp
msgid "Deploy with Remote Debug"
@@ -2936,6 +2940,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -3011,7 +3019,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Output"
-msgstr ""
+msgstr "Cap'n's Log"
#: editor/editor_node.cpp
msgid "Don't Save"
@@ -10015,7 +10023,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12119,10 +12127,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/pt.po b/editor/translations/pt.po
index 26c28d5a19..d2db134026 100644
--- a/editor/translations/pt.po
+++ b/editor/translations/pt.po
@@ -13,7 +13,7 @@
# Rueben Stevens <supercell03@gmail.com>, 2017.
# SARDON <fabio3_Santos@hotmail.com>, 2017.
# Vinicius Gonçalves <viniciusgoncalves21@gmail.com>, 2017.
-# ssantos <ssantos@web.de>, 2018, 2019, 2020.
+# ssantos <ssantos@web.de>, 2018, 2019, 2020, 2021.
# Gonçalo Dinis Guerreiro João <goncalojoao205@gmail.com>, 2019.
# Manuela Silva <mmsrs@sky.com>, 2020.
# Murilo Gama <murilovsky2030@gmail.com>, 2020.
@@ -22,7 +22,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-20 22:25+0000\n"
+"PO-Revision-Date: 2021-05-18 14:51+0000\n"
"Last-Translator: João Lopes <linux-man@hotmail.com>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/godot-engine/"
"godot/pt/>\n"
@@ -1130,6 +1130,10 @@ msgstr "Mudar o valor do dicionário"
msgid "Thanks from the Godot community!"
msgstr "Agradecimentos da Comunidade Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Contribuidores do Godot Engine"
@@ -2551,11 +2555,13 @@ msgstr "Incapaz de carregar script addon do caminho: '%s'."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Incapaz de carregar script addon do caminho: '%s' Parece haver um erro no "
-"código, reveja a sintaxe."
+"código, reveja a sintaxe.\n"
+"A desativar o addon em '%s' para prevenir mais erros."
#: editor/editor_node.cpp
msgid ""
@@ -2684,7 +2690,7 @@ msgstr "%d mais Ficheiros"
#: editor/editor_node.cpp
msgid "Dock Position"
-msgstr "Posição do Painel"
+msgstr "Posição da Doca"
#: editor/editor_node.cpp
msgid "Distraction Free Mode"
@@ -2843,7 +2849,7 @@ msgstr ""
"irá tentar ligar-se ao endereço IP deste computador, para que o projeto "
"possa ser depurado.\n"
"Esta opção foi criada para ser usada pela depuração remota (tipicamente com "
-"um dispositivo móvel).\n"
+"um aparelho móvel).\n"
"Não é necessário ativá-la para usar o depurador de GDScript localmente."
#: editor/editor_node.cpp
@@ -2902,8 +2908,8 @@ msgid ""
msgstr ""
"Quando esta opção está ativada, quaisquer alterações feitas a uma cena no "
"editor serão propagadas no projeto em execução.\n"
-"Quando é usada remotamente num dispositivo, é mais eficiente quando a opção "
-"do sistema de ficheiros em rede está ativa."
+"Quando é usada remotamente num aparelho, é mais eficiente quando a opção do "
+"sistema de ficheiros em rede está ativa."
#: editor/editor_node.cpp
msgid "Synchronize Script Changes"
@@ -3000,6 +3006,10 @@ msgid "About"
msgstr "Sobre"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Apoie o Desenvolvimento do Godot"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Executa o projeto."
@@ -3476,7 +3486,7 @@ msgstr "(Instalado)"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download"
-msgstr "Download"
+msgstr "Descarrega"
#: editor/export_template_manager.cpp
msgid "Official export templates aren't available for development builds."
@@ -3572,7 +3582,7 @@ msgstr "Falhou:"
#: editor/export_template_manager.cpp
msgid "Download Complete."
-msgstr "Download Completo."
+msgstr "Descarrega completa."
#: editor/export_template_manager.cpp
msgid "Cannot remove temporary file:"
@@ -5454,8 +5464,8 @@ msgid ""
"Game Camera Override\n"
"Overrides game camera with editor viewport camera."
msgstr ""
-"Sobreposição de Câmera de Jogo\n"
-"Sobrepõe câmara de jogo com câmera viewport do editor."
+"Sobreposição de Câmara de Jogo\n"
+"Sobrepõe câmara de jogo com câmara viewport do editor."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5463,7 +5473,7 @@ msgid ""
"Game Camera Override\n"
"No game instance running."
msgstr ""
-"Sobreposição de Câmera de Jogo\n"
+"Sobreposição de Câmara de Jogo\n"
"Nenhuma instância de jogo em execução."
#: editor/plugins/canvas_item_editor_plugin.cpp
@@ -7551,6 +7561,8 @@ msgstr "Rotação da Vista Bloqueada"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Para aumentar o zoom, mude os planos de corte da câmara (Ver -> "
+"Configurações...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -9490,7 +9502,7 @@ msgid ""
"direction of camera (pass associated inputs to it)."
msgstr ""
"Devolve queda baseada no produto escalar da normal à superfície e da direção "
-"da câmera (passa entradas associadas)."
+"da câmara (passa entradas associadas)."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -10124,7 +10136,7 @@ msgstr "Botão do rato"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Nome de ação inválido. Não pode ser vazio nem conter '/', ':', '=', '\\' ou "
@@ -10936,6 +10948,9 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"Se selecionada, a doca de árvore da cena Remota vai travar o projeto cada "
+"vez que atualiza.\n"
+"Volte para a doca de árvore da cena Local para melhorar o desempenho."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -11347,11 +11362,11 @@ msgstr "Mudar ângulo de emissão de AudioStreamPlayer3D"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Camera FOV"
-msgstr "Mudar FOV da Câmera"
+msgstr "Mudar FOV da Câmara"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Camera Size"
-msgstr "Mudar tamanho da Câmera"
+msgstr "Mudar tamanho da Câmara"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Notifier AABB"
@@ -12185,12 +12200,24 @@ msgstr ""
"menu Projeto."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Keystore de depuração não configurada nas Configurações do Editor e nem na "
"predefinição."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Lançamento de keystore configurado incorretamente na predefinição exportada."
@@ -12956,7 +12983,7 @@ msgid ""
"This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set "
"this environment's Background Mode to Canvas (for 2D scenes)."
msgstr ""
-"Este WorldEnvironment é ignorado. Pode adicionar uma Câmera (para cenas 3D) "
+"Este WorldEnvironment é ignorado. Pode adicionar uma Câmara (para cenas 3D) "
"ou definir o Modo Background deste ambiente como Canvas (para cenas 2D)."
#: scene/animation/animation_blend_tree.cpp
diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po
index 3509d790d8..1fae91fc0d 100644
--- a/editor/translations/pt_BR.po
+++ b/editor/translations/pt_BR.po
@@ -88,7 +88,7 @@
# Lucas Araujo <lucassants2808@gmail.com>, 2020.
# Sr Half <flavio05@outlook.com>, 2020.
# Matheus Pesegoginski <pese.ek.tk@outlook.com>, 2020.
-# DeeJayLSP <djlsplays@gmail.com>, 2020.
+# DeeJayLSP <djlsplays@gmail.com>, 2020, 2021.
# Anonymous <noreply@weblate.org>, 2020.
# André Sousa <andrelvsousa@gmail.com>, 2020.
# Kleyton Luiz de Sousa Vieira <kleytonluizdesouzavieira@gmail.com>, 2020.
@@ -101,7 +101,7 @@
# Jairo Tuboi <tuboi.jairo@gmail.com>, 2020.
# Felipe Fetter <felipetfetter@gmail.com>, 2020.
# Rafael Henrique Capati <rhcapati@gmail.com>, 2020.
-# NogardRyuu <nogardryuu@gmail.com>, 2020.
+# NogardRyuu <nogardryuu@gmail.com>, 2020, 2021.
# Elton <eltondeoliveira@outlook.com>, 2020.
# ThiagoCTN <thiagocampostn@gmail.com>, 2020.
# Alec Santos <alecsantos96@gmail.com>, 2020.
@@ -115,12 +115,14 @@
# Lucas E. <lukas.ed45@gmail.com>, 2021.
# Gabriel Silveira <gabomfim99@gmail.com>, 2021.
# Arthur Phillip D. Silva <artphil.dev@gmail.com>, 2021.
+# Gustavo HM 102 <gustavohm102@gmail.com>, 2021.
+# Douglas Leão <djlsplays@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: 2016-05-30\n"
-"PO-Revision-Date: 2021-04-11 22:02+0000\n"
-"Last-Translator: Arthur Phillip D. Silva <artphil.dev@gmail.com>\n"
+"PO-Revision-Date: 2021-06-12 01:23+0000\n"
+"Last-Translator: Douglas Leão <djlsplays@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_BR/>\n"
"Language: pt_BR\n"
@@ -128,7 +130,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -774,7 +776,7 @@ msgstr "Mudar Deslocamento do Início do Clip de Trilha de Audio"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr "Alterar deslocamento de fim do clipe de faixa de áudio"
+msgstr "Alterar Deslocamento de Fim do Clipe de Faixa de Ãudio"
#: editor/array_property_edit.cpp
msgid "Resize Array"
@@ -1142,8 +1144,8 @@ msgid ""
"You can find the removed files in the system trash to restore them."
msgstr ""
"Remover arquivos selecionados do projeto? (irreversível)\n"
-"Você pode encontrar os arquivos removidos na lixeira e restaurá-los caso "
-"seja necessário."
+"Você pode encontrar os arquivos removidos na lixeira do sistema para "
+"restaurá-los."
#: editor/dependency_editor.cpp
msgid ""
@@ -1155,8 +1157,8 @@ msgstr ""
"Os arquivos sendo removidos são requeridos por outros recursos para que "
"funcionem.\n"
"Removê-los mesmo assim? (irreversível)\n"
-"Você pode encontrar os arquivos removidos na lixeira e restaurá-los caso "
-"necessário."
+"Você pode encontrar os arquivos removidos na lixeira do sistema para "
+"restaurá-los."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1226,6 +1228,10 @@ msgstr "Alterar Valor do Dicionário"
msgid "Thanks from the Godot community!"
msgstr "Agradecimentos da comunidade Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Contribuidores da Godot Engine"
@@ -1567,7 +1573,7 @@ msgstr "Renomear Autoload"
#: editor/editor_autoload_settings.cpp
msgid "Toggle AutoLoad Globals"
-msgstr "Alternar Auto Carregamentos de Globais"
+msgstr "Alternar Globais de AutoLoad"
#: editor/editor_autoload_settings.cpp
msgid "Move Autoload"
@@ -1721,8 +1727,8 @@ msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
-"A plataforma de destino requer compactação de textura 'ETC2' ou 'PVRTC' para "
-"GLES3. Ativar 'Importar Etc 2' ou 'Importar Pvrtc' nas Configurações do "
+"A plataforma de destino requer compressão de textura 'ETC2' ou 'PVRTC' para "
+"GLES3. Habilite 'Importar Etc 2' ou 'Importar Pvrtc' nas Configurações do "
"Projeto."
#: editor/editor_export.cpp
@@ -1869,7 +1875,7 @@ msgstr "Importar"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
-msgstr "Exportar"
+msgstr "Exportação"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
@@ -2072,7 +2078,7 @@ msgstr "(Re)Importando Assets"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
-msgstr "Cima"
+msgstr "Início"
#: editor/editor_help.cpp
msgid "Class:"
@@ -2651,11 +2657,13 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"Não foi possível localizar a área do script para o complemento do plugin em: "
-"'%s'."
+"Não foi possível localizar o script do caminho: '%s'. Isso pode ser devido a "
+"um erro de código nesse script.\n"
+"Desativando o addon em '%s' para prevenir erros futuros."
#: editor/editor_node.cpp
msgid ""
@@ -3100,6 +3108,10 @@ msgid "About"
msgstr "Sobre"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Apoie o Desenvolvimento do Godot"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Roda o projeto."
@@ -3531,7 +3543,7 @@ msgstr "Não foi possível instanciar o script:"
#: editor/editor_run_script.cpp
msgid "Did you forget the 'tool' keyword?"
-msgstr "Você esqueceu da palavra-chave \"tool\"?"
+msgstr "Você esqueceu da palavra-chave 'tool'?"
#: editor/editor_run_script.cpp
msgid "Couldn't run script:"
@@ -5343,7 +5355,7 @@ msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
"O editor Godot foi construído sem suporte à ray tracing, os lightmaps não "
-"podem ser bakeados."
+"podem ser refinados."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
@@ -5857,7 +5869,7 @@ msgstr "Máscara de Escala para inserir chaves."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert keys (based on mask)."
-msgstr "Inserir Chaves (baseado na máscara)"
+msgstr "Inserir Chaves (baseado na máscara)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5867,9 +5879,9 @@ msgid ""
"Keys must be inserted manually for the first time."
msgstr ""
"Inserir chaves automaticamente quando os objetos são transladados, "
-"rotacionados ou escalados (com base na máscara). \n"
+"rotacionados ou escalados (com base na máscara).\n"
"As chaves são adicionadas apenas às faixas existentes, nenhuma nova trilha "
-"será criada. \n"
+"será criada.\n"
"As chaves devem ser inseridas manualmente pela primeira vez."
#: editor/plugins/canvas_item_editor_plugin.cpp
@@ -6669,8 +6681,8 @@ msgid ""
"Polygon 2D has internal vertices, so it can no longer be edited in the "
"viewport."
msgstr ""
-"Polygon2D tem vértices internos, portanto não pode mais ser editado no "
-"Viewport."
+"Polygon2D tem vértices internos, portanto não pode mais ser editado na "
+"viewport."
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Polygon & UV"
@@ -7015,7 +7027,7 @@ msgstr "Alternar ordenação alfabética da lista de métodos."
#: editor/plugins/script_editor_plugin.cpp
msgid "Filter methods"
-msgstr "Métodos de filtragem"
+msgstr "Filtrar métodos"
#: editor/plugins/script_editor_plugin.cpp
msgid "Sort"
@@ -7667,6 +7679,8 @@ msgstr "Ver Rotação Bloqueada"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Para dar mais zoom, altere os planos de clipping da câmera (Visão -> "
+"Configurações...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -9827,7 +9841,7 @@ msgstr "Compilado"
#: editor/project_export.cpp
msgid "Encrypted (Provide Key Below)"
-msgstr "Criptografado (forneça chave abaixo)"
+msgstr "Criptografado (Forneça Chave Abaixo)"
#: editor/project_export.cpp
msgid "Invalid Encryption Key (must be 64 characters long)"
@@ -10228,7 +10242,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Key "
-msgstr "Chave "
+msgstr "Tecla "
#: editor/project_settings_editor.cpp
msgid "Joy Button"
@@ -10240,11 +10254,11 @@ msgstr "Eixo do Joystick"
#: editor/project_settings_editor.cpp
msgid "Mouse Button"
-msgstr "Botão do Mous"
+msgstr "Botão do Mouse"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Nome da ação inválido. Não pode estar vazio nem conter '/', ':', '=', '\\' "
@@ -10280,7 +10294,7 @@ msgstr "Pressione uma Tecla..."
#: editor/project_settings_editor.cpp
msgid "Mouse Button Index:"
-msgstr "Botão do Mouse:"
+msgstr "Ãndice do Botão do Mouse:"
#: editor/project_settings_editor.cpp
msgid "Left Button"
@@ -10540,7 +10554,7 @@ msgstr "Idiomas:"
#: editor/project_settings_editor.cpp
msgid "AutoLoad"
-msgstr "O AutoLoad"
+msgstr "AutoLoad"
#: editor/project_settings_editor.cpp
msgid "Plugins"
@@ -11056,6 +11070,9 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"Se selecionado, o painel da árvore de cena Remota vai fazer o projeto travar "
+"toda vez que atualizar.\n"
+"Volte para o painel da árvore de cena Local para melhorar o desempenho."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12307,12 +12324,24 @@ msgstr ""
"através do menu Projeto."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Porta-chaves de depuração não configurado nas Configurações do Editor e nem "
"na predefinição."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Keystore de liberação incorretamente configurada na predefinição de "
diff --git a/editor/translations/ro.po b/editor/translations/ro.po
index 5761aadd1d..ec89b47e96 100644
--- a/editor/translations/ro.po
+++ b/editor/translations/ro.po
@@ -1127,6 +1127,10 @@ msgstr "Schimbaţi Valoarea Dicţionar"
msgid "Thanks from the Godot community!"
msgstr "Mulțumesc din partea comunităţii Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Contribuabili Motor Godot"
@@ -2557,9 +2561,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Nu a putut fi încărcat scriptul add-on din calea: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Imposibil de încărcat scriptul addon din cale: '%s' Se pare că există o "
"eroare în cod, verificați sintaxa."
@@ -3009,6 +3015,10 @@ msgid "About"
msgstr "Despre"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Rulează proiectul."
@@ -10175,7 +10185,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12250,10 +12260,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index b12e95793a..fe4b510539 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -93,12 +93,14 @@
# Dmytro Meleshko <dmytro.meleshko@gmail.com>, 2021.
# narrnika <narr13niki@gmail.com>, 2021.
# nec-trou <darya.bilyalova@gmail.com>, 2021.
+# IindinAndEdresia <kapitan_pol@inbox.ru>, 2021.
+# Bualma Show <appleaidar6@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-19 22:33+0000\n"
-"Last-Translator: Danil Alexeev <danil@alexeev.xyz>\n"
+"PO-Revision-Date: 2021-06-07 23:43+0000\n"
+"Last-Translator: Bualma Show <appleaidar6@gmail.com>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ru/>\n"
"Language: ru\n"
@@ -116,7 +118,7 @@ msgstr "Ðеверный параметр типа Ð´Ð»Ñ convert(), иÑполÑ
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "ОжидалаÑÑŒ Ñтрока длиной 1 (Ñ‚.е. Ñимвол)."
+msgstr "ОжидалаÑÑŒ Ñтрока длиной 1 (Ñ‚. е. 1 Ñимвол)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -1203,6 +1205,10 @@ msgstr "Изменить значение ÑловарÑ"
msgid "Thanks from the Godot community!"
msgstr "СпаÑибо от ÑообщеÑтва Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Ðвторы Godot Engine"
@@ -2625,11 +2631,13 @@ msgstr "Ðе удалоÑÑŒ загрузить Ñкрипт из иÑточниÐ
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"Ðевозможно загрузить Ñкрипт аддона из иÑточника: «%s». Ð’ коде еÑть ошибка, "
-"пожалуйÑта, проверьте ÑинтакÑиÑ."
+"Ðевозможно загрузить Ñкрипт аддона по пути: «%s». Это может быть ÑвÑзано Ñ "
+"ошибкой в коде Ñкрипта.\n"
+"Ðддон «%s» отключён Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð´Ð°Ð»ÑŒÐ½ÐµÐ¹ÑˆÐ¸Ñ… ошибок."
#: editor/editor_node.cpp
msgid ""
@@ -3072,6 +3080,10 @@ msgid "About"
msgstr "О Godot Engine"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Поддержать разработку Godot"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "ЗапуÑтить проект."
@@ -7627,6 +7639,8 @@ msgstr "Блокировать вращение камеры"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Чтобы увеличить маÑштаб дальше, измените плоÑкоÑти отÑÐµÑ‡ÐµÐ½Ð¸Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹ (Вид -> "
+"ÐаÑтройки...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -10203,7 +10217,7 @@ msgstr "Кнопка мыши"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Ðеверное Ð¸Ð¼Ñ Ð´ÐµÐ¹ÑтвиÑ. Оно не может быть пуÑтым и не может Ñодержать Ñимволы "
@@ -10807,7 +10821,7 @@ msgstr "Сделать узел корневым"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes and any children?"
-msgstr "Удалить узел «%d» и его дочерние Ñлементы?"
+msgstr "Удалить %d узлов и их детей?"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes?"
@@ -10819,7 +10833,7 @@ msgstr "Удалить корневой узел «%s»?"
#: editor/scene_tree_dock.cpp
msgid "Delete node \"%s\" and its children?"
-msgstr "Удалить узел «%s» и его дочерние Ñлементы?"
+msgstr "Удалить узел «%s» и его детей?"
#: editor/scene_tree_dock.cpp
msgid "Delete node \"%s\"?"
@@ -11018,6 +11032,10 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"ЕÑли выбрано, панель удалённого дерева Ñцены будет вызывать задержки при "
+"каждом обновлении.\n"
+"Ð”Ð»Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñти переключитеÑÑŒ обратно в панель локального "
+"дерева Ñцены."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12265,12 +12283,24 @@ msgstr ""
"Шаблон Ñборки Android не уÑтановлен в проекте. УÑтановите его в меню проекта."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Отладочное хранилище ключей не наÑтроено ни в наÑтройках редактора, ни в "
"предуÑтановках."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Хранилище ключей не наÑтроено ни в наÑтройках редактора, ни в предуÑтановках."
diff --git a/editor/translations/si.po b/editor/translations/si.po
index 20b9001362..89c1b2ffc8 100644
--- a/editor/translations/si.po
+++ b/editor/translations/si.po
@@ -1104,6 +1104,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2464,8 +2468,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2870,6 +2875,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9756,7 +9765,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11776,10 +11785,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/sk.po b/editor/translations/sk.po
index 95b0fc7136..5d5b9cba9b 100644
--- a/editor/translations/sk.po
+++ b/editor/translations/sk.po
@@ -1114,6 +1114,10 @@ msgstr "Zmeniť Hodnotu v Slovníku"
msgid "Thanks from the Godot community!"
msgstr "VÄaka z Godot komunity!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine prispievatelia"
@@ -2531,9 +2535,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Nepodarilo sa naÄítaÅ¥ addon script z cesty: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Nepodarilo sa nájsť addon script z cesty: '%s' Vyzerá to tak že by mohol byť "
"problém v kóde, prosím skontrolujte syntax."
@@ -2978,6 +2984,10 @@ msgid "About"
msgstr "O nás"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Spustiť projekt."
@@ -10071,7 +10081,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12148,10 +12158,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/sl.po b/editor/translations/sl.po
index 500b8b1e54..2ac453123c 100644
--- a/editor/translations/sl.po
+++ b/editor/translations/sl.po
@@ -1171,6 +1171,10 @@ msgstr "Spremeni Slovarsko Vrednost"
msgid "Thanks from the Godot community!"
msgstr "Zahvaljujemo se vam iz skupnosti Godota!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine sodelovci"
@@ -2646,8 +2650,9 @@ msgstr "Ni mogoÄe naložiti dodatno skripto iz poti: '%s'."
#: editor/editor_node.cpp
#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Ni mogoÄe naložiti dodatno skripto iz poti: '%s' Skripta ni v naÄinu orodje."
@@ -3113,6 +3118,10 @@ msgid "About"
msgstr "O Programu"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Zaženi projekt."
@@ -10413,7 +10422,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12532,10 +12541,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/sq.po b/editor/translations/sq.po
index 7b2fee263a..4409a6f48a 100644
--- a/editor/translations/sq.po
+++ b/editor/translations/sq.po
@@ -1112,6 +1112,10 @@ msgstr "Ndrysho Vlerën e Fjalorit"
msgid "Thanks from the Godot community!"
msgstr "Faleminderit nga komuniteti i Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Kontribuesit e Godot Engine"
@@ -2586,9 +2590,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "I paaftë të ngarkojë shkrimin e shtojcës nga rruga: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"I paaftë të ngarkojë shkrimin e shtojcës nga rruga: '%s' Me sa duket është "
"një gabim në kod, ju lutem kontrolloni sintaksën."
@@ -3050,6 +3056,10 @@ msgid "About"
msgstr "Rreth"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Luaj projektin."
@@ -10066,7 +10076,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12131,10 +12141,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po
index cb28a6b876..3ba1c674a3 100644
--- a/editor/translations/sr_Cyrl.po
+++ b/editor/translations/sr_Cyrl.po
@@ -1226,6 +1226,10 @@ msgstr "Промени вредноÑÑ‚ речника"
msgid "Thanks from the Godot community!"
msgstr "Хвала од Godot заједнице!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine Ñарадници"
@@ -2763,8 +2767,9 @@ msgstr "ÐеуÑпех при учитавању Ñкриптице додатк
#: editor/editor_node.cpp
#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"ÐеуÑпех при учитавању Ñкриптице додатка Ñа путем „%s“. Скриптица није у "
"режиму алатке."
@@ -3241,6 +3246,10 @@ msgid "About"
msgstr "О"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Покрени пројекат."
@@ -11272,7 +11281,7 @@ msgstr "Миш Дугме"
#: editor/project_settings_editor.cpp
#, fuzzy
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Ðеважеће име акције. Ðе може бити празно или Ñадржати '/', ':', '=', '\\' "
@@ -13727,6 +13736,12 @@ msgstr ""
"менија."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
#, fuzzy
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
@@ -13734,6 +13749,12 @@ msgstr ""
"поÑтавкама."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po
index 86ce05a7f2..fcab84a2bf 100644
--- a/editor/translations/sr_Latn.po
+++ b/editor/translations/sr_Latn.po
@@ -1112,6 +1112,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2477,8 +2481,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2885,6 +2890,10 @@ msgid "About"
msgstr "O nama / O Godou"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9836,7 +9845,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11868,10 +11877,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/sv.po b/editor/translations/sv.po
index 2b3c17e07e..c5cad10f66 100644
--- a/editor/translations/sv.po
+++ b/editor/translations/sv.po
@@ -26,8 +26,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-24 23:44+0000\n"
-"Last-Translator: Jonas Robertsson <jonas.robertsson@posteo.net>\n"
+"PO-Revision-Date: 2021-05-03 21:29+0000\n"
+"Last-Translator: Alex25820 <Alexander_sjogren@hotmail.se>\n"
"Language-Team: Swedish <https://hosted.weblate.org/projects/godot-engine/"
"godot/sv/>\n"
"Language: sv\n"
@@ -35,7 +35,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1132,6 +1132,10 @@ msgstr "Ändra Ordboksvärde"
msgid "Thanks from the Godot community!"
msgstr "Tack från Godot-gemenskapen!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine bidragare"
@@ -2599,8 +2603,9 @@ msgstr "Kunde inte ladda addon script från sökväg: '%s'."
#: editor/editor_node.cpp
#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Kunde inte ladda addon script från sökväg: '%s' Skript är inte i "
"verktygsläge."
@@ -2814,7 +2819,6 @@ msgid "MeshLibrary..."
msgstr "MeshBibliotek..."
#: editor/editor_node.cpp
-#, fuzzy
msgid "TileSet..."
msgstr "TileSet..."
@@ -2830,7 +2834,7 @@ msgstr "Återställ"
#: editor/editor_node.cpp
msgid "Miscellaneous project or scene-wide tools."
-msgstr ""
+msgstr "Diverse projekt eller scenövergripande-verktyg."
#: editor/editor_node.cpp editor/project_manager.cpp
#: editor/script_create_dialog.cpp
@@ -2859,7 +2863,7 @@ msgstr "Exportera..."
#: editor/editor_node.cpp
msgid "Install Android Build Template..."
-msgstr ""
+msgstr "Installera Android Build Template..."
#: editor/editor_node.cpp
msgid "Open Project Data Folder"
@@ -3025,7 +3029,7 @@ msgstr "Importera om"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
-msgstr ""
+msgstr "Skicka Dokumentations Feedback"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
@@ -3036,6 +3040,10 @@ msgid "About"
msgstr "Om"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Spela projektet."
@@ -3114,7 +3122,7 @@ msgstr "Expandera alla"
#: editor/editor_node.cpp
msgid "Output"
-msgstr ""
+msgstr "Utdata"
#: editor/editor_node.cpp
msgid "Don't Save"
@@ -3275,7 +3283,7 @@ msgstr "Redigera:"
#: editor/editor_profiler.cpp
msgid "Measure:"
-msgstr ""
+msgstr "Mät:"
#: editor/editor_profiler.cpp
msgid "Frame Time (sec)"
@@ -3287,11 +3295,11 @@ msgstr "Genomsnittlig Tid (sek)"
#: editor/editor_profiler.cpp
msgid "Frame %"
-msgstr ""
+msgstr "Bildruta %"
#: editor/editor_profiler.cpp
msgid "Physics Frame %"
-msgstr ""
+msgstr "Fysik Bildruta %"
#: editor/editor_profiler.cpp
msgid "Inclusive"
@@ -3303,7 +3311,7 @@ msgstr "Själv"
#: editor/editor_profiler.cpp
msgid "Frame #:"
-msgstr ""
+msgstr "Bildruta #:"
#: editor/editor_profiler.cpp
msgid "Time"
@@ -3323,7 +3331,7 @@ msgstr "PÃ¥"
#: editor/editor_properties.cpp
msgid "Layer"
-msgstr ""
+msgstr "Lager"
#: editor/editor_properties.cpp
msgid "Bit %d, value %d"
@@ -3331,7 +3339,7 @@ msgstr ""
#: editor/editor_properties.cpp
msgid "[Empty]"
-msgstr ""
+msgstr "[Tom]"
#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
msgid "Assign..."
@@ -3377,11 +3385,11 @@ msgstr "Öppna Skript"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "New %s"
-msgstr ""
+msgstr "Ny %s"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Make Unique"
-msgstr ""
+msgstr "Gör Unik"
#: editor/editor_properties.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
@@ -3407,11 +3415,11 @@ msgstr ""
#: editor/editor_properties_array_dict.cpp
msgid "Size: "
-msgstr ""
+msgstr "Storlek: "
#: editor/editor_properties_array_dict.cpp
msgid "Page: "
-msgstr ""
+msgstr "Sida: "
#: editor/editor_properties_array_dict.cpp
#: editor/plugins/theme_editor_plugin.cpp
@@ -3441,7 +3449,7 @@ msgstr ""
#: editor/editor_run_script.cpp
msgid "Write your logic in the _run() method."
-msgstr ""
+msgstr "Skriv din logik i _run() metoden."
#: editor/editor_run_script.cpp
msgid "There is an edited scene already."
@@ -3461,7 +3469,7 @@ msgstr "Kunde inte köra Skript:"
#: editor/editor_run_script.cpp
msgid "Did you forget the '_run' method?"
-msgstr ""
+msgstr "Glömde du '_run' metoden?"
#: editor/editor_spin_slider.cpp
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
@@ -3558,6 +3566,8 @@ msgid ""
"No download links found for this version. Direct download is only available "
"for official releases."
msgstr ""
+"Ingen nedladdningslänk hittades för denna version. Direkt nedladdning finns "
+"endast tillgängligt för officiella utgåvor."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3576,16 +3586,16 @@ msgstr "Inget svar."
#: editor/export_template_manager.cpp
msgid "Request Failed."
-msgstr ""
+msgstr "Förfrågning Misslyckades."
#: editor/export_template_manager.cpp
msgid "Redirect Loop."
-msgstr ""
+msgstr "Omdirigera Loop."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Failed:"
-msgstr ""
+msgstr "Misslyckades:"
#: editor/export_template_manager.cpp
msgid "Download Complete."
@@ -3617,11 +3627,11 @@ msgstr "Frånkopplad"
#: editor/export_template_manager.cpp
msgid "Resolving"
-msgstr ""
+msgstr "Löser"
#: editor/export_template_manager.cpp
msgid "Can't Resolve"
-msgstr ""
+msgstr "Kan inte lösa"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3641,7 +3651,7 @@ msgstr "Ansluten"
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Requesting..."
-msgstr ""
+msgstr "Begär..."
#: editor/export_template_manager.cpp
msgid "Downloading"
@@ -3653,7 +3663,7 @@ msgstr "Anslutningsfel"
#: editor/export_template_manager.cpp
msgid "SSL Handshake Error"
-msgstr ""
+msgstr "Fel vid SSL-handskakning"
#: editor/export_template_manager.cpp
#, fuzzy
@@ -3717,7 +3727,7 @@ msgstr ""
#: editor/filesystem_dock.cpp
msgid "Cannot move a folder into itself."
-msgstr ""
+msgstr "Det går inte att flytta en mapp in i sig själv."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3736,11 +3746,11 @@ msgstr "Scen '%s' har trasiga beroenden:"
#: editor/filesystem_dock.cpp editor/scene_tree_editor.cpp
msgid "No name provided."
-msgstr ""
+msgstr "Inget namn har angetts."
#: editor/filesystem_dock.cpp
msgid "Provided name contains invalid characters."
-msgstr ""
+msgstr "Angivet namn innehåller ogiltiga tecken."
#: editor/filesystem_dock.cpp
msgid "A file or folder with this name already exists."
@@ -3748,7 +3758,7 @@ msgstr "En fil eller mapp med detta namn finns redan."
#: editor/filesystem_dock.cpp
msgid "Name contains invalid characters."
-msgstr ""
+msgstr "Namnet innehåller ogiltiga tecken."
#: editor/filesystem_dock.cpp
msgid ""
@@ -3886,6 +3896,8 @@ msgid ""
"Scanning Files,\n"
"Please Wait..."
msgstr ""
+"Skannar Filer,\n"
+"Snälla Vänta..."
#: editor/filesystem_dock.cpp
msgid "Move"
@@ -3900,7 +3912,7 @@ msgstr "Byt namn"
#: editor/filesystem_dock.cpp
msgid "Overwrite"
-msgstr ""
+msgstr "Skriv över"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -4030,7 +4042,7 @@ msgstr "Lägg till i Grupp"
#: editor/groups_editor.cpp
msgid "Empty groups will be automatically removed."
-msgstr ""
+msgstr "Tomma grupper tas automatiskt bort."
#: editor/groups_editor.cpp
#, fuzzy
@@ -4282,11 +4294,11 @@ msgstr "Skapa Prenumeration"
#: editor/plugin_config_dialog.cpp
msgid "Plugin Name:"
-msgstr ""
+msgstr "Plugin Namn:"
#: editor/plugin_config_dialog.cpp
msgid "Subfolder:"
-msgstr ""
+msgstr "Undermapp:"
#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
msgid "Language:"
@@ -4298,7 +4310,7 @@ msgstr "Skript Namn:"
#: editor/plugin_config_dialog.cpp
msgid "Activate now?"
-msgstr ""
+msgstr "Aktivera nu?"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/polygon_2d_editor_plugin.cpp
@@ -4751,9 +4763,8 @@ msgid "Onion Skinning Options"
msgstr "Alternativ"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Directions"
-msgstr "Sektioner:"
+msgstr "Riktningar"
#: editor/plugins/animation_player_editor_plugin.cpp
#, fuzzy
@@ -5386,9 +5397,8 @@ msgid "Rotate %d CanvasItems"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "Roterar %s grader."
+msgstr "Rotera CanvasItem \"%s\" till %d grader"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move CanvasItem \"%s\" Anchor"
@@ -5840,9 +5850,8 @@ msgid "Auto Insert Key"
msgstr "Anim Infoga Nyckel"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Animation Key and Pose Options"
-msgstr "Animation längd (i sekunder)."
+msgstr "Animations Nyckel och Pose Inställningar"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert Key (Existing Tracks)"
@@ -8361,9 +8370,8 @@ msgid "Enable Priority"
msgstr "Redigera Filter"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Filter tiles"
-msgstr "Filtrera Filer..."
+msgstr "Filtrera tiles"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Give a TileSet resource to this TileMap to use its tiles."
@@ -8616,9 +8624,8 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete selected Rect."
-msgstr "Ta bort valda filer?"
+msgstr "Ta bort vald Rect."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -9834,9 +9841,8 @@ msgid "Export Project"
msgstr "Exportera Projekt"
#: editor/project_export.cpp
-#, fuzzy
msgid "Export mode?"
-msgstr "Exportera Projekt"
+msgstr "Export läge?"
#: editor/project_export.cpp
#, fuzzy
@@ -10204,7 +10210,7 @@ msgstr "Musknapp"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12282,10 +12288,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/ta.po b/editor/translations/ta.po
index 9b57af9595..c630966603 100644
--- a/editor/translations/ta.po
+++ b/editor/translations/ta.po
@@ -1108,6 +1108,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2468,8 +2472,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2876,6 +2881,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9756,7 +9765,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11776,10 +11785,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/te.po b/editor/translations/te.po
index a3c48112a6..f1d857b911 100644
--- a/editor/translations/te.po
+++ b/editor/translations/te.po
@@ -1083,6 +1083,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2441,8 +2445,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2847,6 +2852,10 @@ msgid "About"
msgstr "à°—à±à°°à°¿à°‚à°šà°¿"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9681,7 +9690,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11682,10 +11691,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/th.po b/editor/translations/th.po
index d865b04b16..0edcf900b9 100644
--- a/editor/translations/th.po
+++ b/editor/translations/th.po
@@ -8,12 +8,15 @@
# Anonymous <noreply@weblate.org>, 2020.
# Lon3r <mptube.p@gmail.com>, 2020.
# Kongfa Warorot <gongpha@hotmail.com>, 2020, 2021.
+# Kongfa Waroros <gongpha@hotmail.com>, 2021.
+# Atirut Wattanamongkol <artjang301@gmail.com>, 2021.
+# PT 07 <porton555@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-05 14:28+0000\n"
-"Last-Translator: Thanachart Monpassorn <nunf_2539@hotmail.com>\n"
+"PO-Revision-Date: 2021-06-07 23:43+0000\n"
+"Last-Translator: Atirut Wattanamongkol <artjang301@gmail.com>\n"
"Language-Team: Thai <https://hosted.weblate.org/projects/godot-engine/godot/"
"th/>\n"
"Language: th\n"
@@ -21,50 +24,53 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr "ชนิดตัวà¹à¸›à¸£à¹ƒà¸™ convert() ผิดพลาด ใช้ค่าคงที่ TYPE_* เท่านั้น"
+msgstr "ชนิดตัวà¹à¸›à¸£à¹ƒà¸™ convert() ผิด ใช้ค่าคงที่ TYPE_* เท่านั้น"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "พบ String ที่มีความยาวเท่าà¸à¸±à¸š 1 (ตัวอัà¸à¸©à¸£)"
+msgstr "String นี้ต้องมีความยาวเท่าà¸à¸±à¸š 1 ตัวอัà¸à¸©à¸£"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
-msgstr "ไบต์ไม่ครบหรือผิดรูปà¹à¸šà¸š ไม่สามารถà¹à¸›à¸¥à¸‡à¸„่าได้"
+msgstr "ไบต์ไม่เพียงพอหรือรูปà¹à¸šà¸šà¹„ม่ถูà¸à¸•้องสำหรับà¸à¸²à¸£à¸–อดรหัสไบต์"
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
-msgstr "ค่าอินพุตผิดพลาด %i (ไม่ผ่าน)"
+msgstr "อินพุต %i ใน expression ไม่ถูà¸à¸•้อง (ไม่ผ่าน)"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
-msgstr "self ไม่สามารถใช้ได้เนื่องจาภinstance ว่าง (ไม่ผ่าน)"
+msgstr "ไม่สามารถใช้ self ได้เนื่องจาà¸à¸­à¸´à¸™à¸ªà¹à¸•นซ์เป็น null (ไม่ผ่าน)"
#: core/math/expression.cpp
+#, fuzzy
msgid "Invalid operands to operator %s, %s and %s."
-msgstr "ดำเนินà¸à¸²à¸£à¸œà¸´à¸”พลาดที่ตัวดำเนินà¸à¸²à¸£ %s, %s à¹à¸¥à¸° %s"
+msgstr "ตัวดำเนินà¸à¸²à¸£à¸ªà¸³à¸«à¸£à¸±à¸šà¹‚อเปอเรเตอร์ %s, %s à¹à¸¥à¸° %s ไม่ถูà¸à¸•้อง"
#: core/math/expression.cpp
+#, fuzzy
msgid "Invalid index of type %s for base type %s"
-msgstr "ดัชนีของชนิด '%s' ผิดพลาด ในชนิดà¸à¸²à¸™ %s"
+msgstr "ดัชนีของชนิด '%s' ไม่ถูà¸à¸•้องสำหรับชนิดà¸à¸²à¸™ %s"
#: core/math/expression.cpp
msgid "Invalid named index '%s' for base type %s"
-msgstr "ชื่อดัชนีของ '%s' ผิดพลาด สำหรับà¸à¸²à¸™ %s"
+msgstr "ชื่อดัชนีของ '%s' ผิดพลาดสำหรับà¸à¸²à¸™ %s"
#: core/math/expression.cpp
msgid "Invalid arguments to construct '%s'"
msgstr "อาร์à¸à¸´à¸§à¹€à¸¡à¸™à¸•์ของคอนสตรัค '%s' ผิดพลาด"
#: core/math/expression.cpp
+#, fuzzy
msgid "On call to '%s':"
-msgstr "เรียภ'%s':"
+msgstr "ขณะเรียภ'%s':"
#: core/ustring.cpp
msgid "B"
@@ -99,12 +105,14 @@ msgid "Free"
msgstr "อิสระ"
#: editor/animation_bezier_editor.cpp
+#, fuzzy
msgid "Balanced"
-msgstr "ความสมดุล"
+msgstr "สมดุล"
#: editor/animation_bezier_editor.cpp
+#, fuzzy
msgid "Mirror"
-msgstr "à¸à¸£à¸°à¸ˆà¸"
+msgstr "สะท้อน"
#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp
msgid "Time:"
@@ -115,12 +123,13 @@ msgid "Value:"
msgstr "ค่า:"
#: editor/animation_bezier_editor.cpp
+#, fuzzy
msgid "Insert Key Here"
-msgstr "เพิ่มปุ่มที่นี่"
+msgstr "เพิ่มคีย์ที่นี่"
#: editor/animation_bezier_editor.cpp
msgid "Duplicate Selected Key(s)"
-msgstr "ทำซ้ำคีย์ที่เลือà¸"
+msgstr "คัดลอà¸à¸„ีย์ที่เลือà¸"
#: editor/animation_bezier_editor.cpp
msgid "Delete Selected Key(s)"
@@ -135,8 +144,9 @@ msgid "Move Bezier Points"
msgstr "ย้ายจุดเบซิเยร์"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
+#, fuzzy
msgid "Anim Duplicate Keys"
-msgstr "ทำซ้ำคีย์à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
+msgstr "คีย์à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™à¸‹à¹‰à¸³à¸à¸±à¸™"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Delete Keys"
@@ -147,10 +157,12 @@ msgid "Anim Change Keyframe Time"
msgstr "à¹à¸à¹‰à¹„ขเวลาคีย์เฟรมà¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
#: editor/animation_track_editor.cpp
+#, fuzzy
msgid "Anim Change Transition"
-msgstr "à¹à¸à¹‰à¹„ขทรานสิชันà¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
+msgstr "เปลี่ยนทรานสิชันของà¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
#: editor/animation_track_editor.cpp
+#, fuzzy
msgid "Anim Change Transform"
msgstr "เคลื่อนย้ายà¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
@@ -171,8 +183,9 @@ msgid "Anim Multi Change Transition"
msgstr "à¹à¸à¹‰à¹„ขทรานสิชันà¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™à¹à¸šà¸šà¸«à¸¥à¸²à¸¢à¸„รั้ง"
#: editor/animation_track_editor.cpp
+#, fuzzy
msgid "Anim Multi Change Transform"
-msgstr "à¹à¸à¹‰à¹„ขà¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™à¹à¸šà¸šà¸«à¸¥à¸²à¸¢à¸„รั้ง"
+msgstr "à¹à¸à¹‰à¹„ขตำà¹à¸«à¸™à¹ˆà¸‡à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™à¹à¸šà¸šà¸«à¸¥à¸²à¸¢à¸„รั้ง"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Value"
@@ -189,11 +202,11 @@ msgstr "à¹à¸à¹‰à¹„ขความยาวà¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
#: editor/animation_track_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation Loop"
-msgstr "à¹à¸à¹‰à¹„ขà¸à¸²à¸£à¸§à¸™à¸‹à¹‰à¸³à¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
+msgstr "à¹à¸à¹‰à¹„ขà¸à¸²à¸£à¸§à¸™à¸‹à¹‰à¸³à¸‚องà¹à¸­à¸™à¸´à¹€à¸¡à¸Šà¸±à¸™"
#: editor/animation_track_editor.cpp
msgid "Property Track"
-msgstr "คุณสมบัติà¹à¸—ร็à¸"
+msgstr "à¹à¸—ร็à¸à¸„ุณสมบัติ"
#: editor/animation_track_editor.cpp
msgid "3D Transform Track"
@@ -250,7 +263,7 @@ msgstr "เปลี่ยนที่อยู่à¹à¸—ร็à¸"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr "เปิด/ปิดà¸à¸²à¸£à¸•ิดตามà¹à¸—ร็à¸à¸™à¸µà¹‰"
+msgstr "เปิด/ปิดà¹à¸—ร็à¸à¸™à¸µà¹‰"
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
@@ -261,8 +274,9 @@ msgid "Interpolation Mode"
msgstr "โหมดà¸à¸²à¸£à¹à¸à¹‰à¹„ข"
#: editor/animation_track_editor.cpp
+#, fuzzy
msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
-msgstr "โหมดลูปวาร์ป (à¹à¸à¹‰à¹„ขจุดสิ้นสุดด้วยจุดเริ่มตต้นบนลูป)"
+msgstr "โหมดวนลูป (Interpolate จุดสิ้นสุดด้วยจุดเริ่มตต้นบนลูป)"
#: editor/animation_track_editor.cpp
msgid "Remove this track."
@@ -348,7 +362,7 @@ msgstr "เพิ่มà¹à¸—ร็à¸à¹ƒà¸«à¸¡à¹ˆà¸ªà¸³à¸«à¸£à¸±à¸š %s à¹à¸¥à¸
#: editor/animation_track_editor.cpp
msgid "Create %d NEW tracks and insert keys?"
-msgstr "เพิ่ม %d à¹à¸—ร็à¸à¹ƒà¸«à¸¡à¹ˆà¹à¸¥à¸°à¹€à¸žà¸´à¹ˆà¸¡à¸„ีย์?"
+msgstr "เพิ่มà¹à¸—ร็à¸à¹ƒà¸«à¸¡à¹ˆ %d à¹à¸—ร็à¸à¹à¸¥à¸°à¹€à¸žà¸´à¹ˆà¸¡à¸„ีย์?"
#: editor/animation_track_editor.cpp editor/create_dialog.cpp
#: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp
@@ -391,17 +405,19 @@ msgid "Rearrange Tracks"
msgstr "จัดเรียงà¹à¸—ร็à¸"
#: editor/animation_track_editor.cpp
+#, fuzzy
msgid "Transform tracks only apply to Spatial-based nodes."
-msgstr "à¹à¸›à¸¥à¸‡à¹à¸—ร็à¸à¹€à¸‰à¸žà¸²à¸°à¸—ี่ Spatial-based nodes"
+msgstr "à¹à¸—ร็ภTransform ส่งผลต่อโนดประเภท Spatial-based เท่านั้น"
#: editor/animation_track_editor.cpp
+#, fuzzy
msgid ""
"Audio tracks can only point to nodes of type:\n"
"-AudioStreamPlayer\n"
"-AudioStreamPlayer2D\n"
"-AudioStreamPlayer3D"
msgstr ""
-"à¹à¸—ร็à¸à¹€à¸ªà¸µà¸¢à¸‡à¸ªà¸²à¸¡à¸²à¸£à¸–ติดไว้บนโหนดชนิดเหล่านี้เท่านั้น:\n"
+"à¹à¸—ร็à¸à¹€à¸ªà¸µà¸¢à¸‡à¸ªà¸²à¸¡à¸²à¸£à¸–ชี้ไปยังโนดชนิดเหล่านี้ได้เท่านั้น:\n"
"-AudioStreamPlayer\n"
"-AudioStreamPlayer2D\n"
"-AudioStreamPlayer3D"
@@ -505,7 +521,7 @@ msgstr "เลือà¸à¹‚หนด AnimationPlayer เพื่อสร้าà
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
-msgstr "โชว์à¹à¸—ร็à¸à¸ˆà¸²à¸à¹‚หนดที่เลือà¸à¹ƒà¸™à¸œà¸±à¸‡à¹€à¸—่านั้น"
+msgstr "à¹à¸ªà¸”งà¹à¸—ร็à¸à¸ˆà¸²à¸à¹‚หนดที่เลือà¸à¹ƒà¸™à¸œà¸±à¸‡à¹€à¸—่านั้น"
#: editor/animation_track_editor.cpp
msgid "Group tracks by node or display them as plain list."
@@ -1107,6 +1123,10 @@ msgstr "à¹à¸à¹‰à¹„ขค่าดิà¸à¸Šà¸±à¸™à¸™à¸²à¸£à¸µ"
msgid "Thanks from the Godot community!"
msgstr "ขอขอบคุณจาà¸à¸Šà¸¸à¸¡à¸Šà¸™à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰ Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "ผู้ช่วยพัฒนา Godot Engine"
@@ -1634,11 +1654,11 @@ msgstr "à¸à¸²à¸£à¸ªà¹ˆà¸‡à¸­à¸­à¸à¹à¸šà¸š 32 bit PCK à¹à¸šà¸šà¸à¸±à¸‡à¸•ั
#: editor/editor_feature_profile.cpp
msgid "3D Editor"
-msgstr "เอดิเตอร์ 3D"
+msgstr "ตัวà¹à¸à¹‰à¹„ข 3D"
#: editor/editor_feature_profile.cpp
msgid "Script Editor"
-msgstr "เอดิเตอร์สคริปต์"
+msgstr "ตัวà¹à¸à¹‰à¹„ขสคริปต์"
#: editor/editor_feature_profile.cpp
msgid "Asset Library"
@@ -1674,7 +1694,7 @@ msgstr "มีโปรไฟล์ที่มีชื่อนี้อยู
#: editor/editor_feature_profile.cpp
msgid "(Editor Disabled, Properties Disabled)"
-msgstr "(เอดิเตอร์ถูà¸à¸›à¸´à¸”à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™, คุณสมบัติถูà¸à¸›à¸´à¸”à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™)"
+msgstr "(ตัวà¹à¸à¹‰à¹„ขถูà¸à¸›à¸´à¸”à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™, คุณสมบัติถูà¸à¸›à¸´à¸”à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™)"
#: editor/editor_feature_profile.cpp
msgid "(Properties Disabled)"
@@ -1682,7 +1702,7 @@ msgstr "(ปิดà¸à¸²à¸£à¸—ำงานคุณสมบัติ)"
#: editor/editor_feature_profile.cpp
msgid "(Editor Disabled)"
-msgstr "(เอดิเตอร์ถูà¸à¸›à¸´à¸”à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™)"
+msgstr "(ตัวà¹à¸à¹‰à¹„ขถูà¸à¸›à¸´à¸”à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™)"
#: editor/editor_feature_profile.cpp
msgid "Class Options:"
@@ -1690,7 +1710,7 @@ msgstr "ตั้งค่าคลาส:"
#: editor/editor_feature_profile.cpp
msgid "Enable Contextual Editor"
-msgstr "เปิดà¸à¸²à¸£à¸—ำงานเอดิเตอร์ตามบริบท"
+msgstr "เปิดà¸à¸²à¸£à¸—ำงานตัวà¹à¸à¹‰à¹„ขตามบริบท"
#: editor/editor_feature_profile.cpp
msgid "Enabled Properties:"
@@ -1775,7 +1795,7 @@ msgstr "ส่งออà¸à¹‚ปรไฟล์"
#: editor/editor_feature_profile.cpp
msgid "Manage Editor Feature Profiles"
-msgstr "จัดà¸à¸²à¸£à¸£à¸²à¸¢à¸¥à¸°à¹€à¸­à¸µà¸¢à¸”คุณสมบัติเอดิเตอร์"
+msgstr "จัดà¸à¸²à¸£à¸£à¸²à¸¢à¸¥à¸°à¹€à¸­à¸µà¸¢à¸”คุณสมบัติตัวà¹à¸à¹‰à¹„ข"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select Current Folder"
@@ -1940,7 +1960,7 @@ msgstr "มีà¸à¸²à¸£à¸™à¸³à¹€à¸‚้าไฟล์ %s หลายอัน à
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
-msgstr "นำเข้าทรัพยาà¸à¸£(อีà¸à¸„รั้ง)"
+msgstr "à¸à¸³à¸¥à¸±à¸‡à¸™à¸³à¹€à¸‚้าทรัพยาà¸à¸£(อีà¸à¸„รั้ง)"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
@@ -1981,7 +2001,7 @@ msgstr "ค่าเริ่มต้น:"
#: editor/editor_help.cpp
msgid "Methods"
-msgstr "เมท็อด"
+msgstr "เมธอด"
#: editor/editor_help.cpp
msgid "Theme Properties"
@@ -2278,8 +2298,8 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
-"เà¸à¸´à¸”ข้อผิดพลาดขณะà¸à¸³à¸¥à¸±à¸‡à¸šà¸±à¸™à¸—ึà¸à¹€à¸¥à¹€à¸­à¸²à¸•์ของเอดิเตอร์\n"
-"ตรวจสอบให้à¹à¸™à¹ˆà¹ƒà¸ˆà¸§à¹ˆà¸²à¸—ี่อยู่ข้อมูลผู้ใช้เอดิเตอร์สามารถà¹à¸à¹‰à¹„ขได้"
+"เà¸à¸´à¸”ข้อผิดพลาดขณะà¸à¸³à¸¥à¸±à¸‡à¸šà¸±à¸™à¸—ึà¸à¹€à¸¥à¹€à¸­à¸²à¸•์ของตัวà¹à¸à¹‰à¹„ข\n"
+"ตรวจสอบให้à¹à¸™à¹ˆà¹ƒà¸ˆà¸§à¹ˆà¸²à¸—ี่อยู่ข้อมูลผู้ใช้ตัวà¹à¸à¹‰à¹„ขสามารถà¹à¸à¹‰à¹„ขได้"
#: editor/editor_node.cpp
msgid ""
@@ -2287,8 +2307,9 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
-"เลเอาต์เอดิเตอร์ดั้งเดิมถูà¸à¹€à¸‚ียนทับ\n"
-"เพื่อที่จะà¸à¸¹à¹‰à¸„ืนเลเอาต์ดั้งเดิมไปยังà¸à¸²à¸£à¸•ั้งค่าพื้นà¸à¸²à¸™ ใช้à¸à¸²à¸£à¸•ั้งค่า Delete Layout à¹à¸¥à¸°à¸¥à¸šà¹€à¸¥à¹€à¸­à¸²à¸•์ตั้งเดิม"
+"à¸à¸²à¸£à¸ˆà¸±à¸”เค้าโครงตัวà¹à¸à¹‰à¹„ขดั้งเดิมถูà¸à¹€à¸‚ียนทับ\n"
+"เพื่อที่จะà¸à¸¹à¹‰à¸„ืนเค้าโครงดั้งเดิมไปยังà¸à¸²à¸£à¸•ั้งค่าพื้นà¸à¸²à¸™ ใช้à¸à¸²à¸£à¸•ั้งค่า Delete Layout "
+"à¹à¸¥à¸°à¸¥à¸šà¹€à¸„้าโครงตั้งเดิม"
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -2497,9 +2518,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "ไม่สามารถโหลดสคริปต์จาà¸: '%s'"
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"ไม่สามารถโหลดสคริปต์ส่วนเสริมจาà¸: '%s' เหมือนว่าจะเà¸à¸´à¸”ข้อผิดพลาดขึ้นในโค้ด "
"à¸à¸£à¸¸à¸“าเช็ตรูปà¹à¸šà¸šà¸à¸²à¸£à¹€à¸‚ียนโค้ด"
@@ -2799,7 +2822,7 @@ msgid ""
msgstr ""
"ถ้าเปิดตัวเลือà¸à¸™à¸µà¹‰ à¸à¸²à¸£à¹ƒà¸Šà¹‰ deploy สำหรับà¹à¸­à¸™à¸”รอยด์จะส่งออà¸à¹€à¸‰à¸žà¸²à¸°à¹„ฟล์ปà¸à¸´à¸šà¸±à¸•ิà¸à¸²à¸£ "
"ไม่มีข้อมูลโปรเจà¸à¸•์\n"
-"ระบบไฟล์จะถูà¸à¸ˆà¸±à¸”เตรียมจาà¸à¹‚ปรเจ็à¸à¸•์โดยเอดิเตอร์บนเครือข่าย\n"
+"ระบบไฟล์จะถูà¸à¸ˆà¸±à¸”เตรียมจาà¸à¹‚ปรเจ็à¸à¸•์โดยตัวà¹à¸à¹‰à¹„ขบนเครือข่าย\n"
"บน Android จะ deploy โดยใช้สาย USB เพื่อประสิทธิภาพที่ดี "
"ตัวเลือà¸à¸™à¸µà¹‰à¸ˆà¸°à¸Šà¹ˆà¸§à¸¢à¹ƒà¸«à¹‰à¸à¸²à¸£à¸—ดสอบเà¸à¸¡à¹€à¸£à¹‡à¸§à¸‚ึ้น สำหรับโปรเจà¸à¸•์ขนาดใหà¸à¹ˆ"
@@ -2837,7 +2860,7 @@ msgid ""
"filesystem option is enabled."
msgstr ""
"เมื่อเปิดใช้งานตัวเลือà¸à¸™à¸µà¹‰ à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¹ƒà¸” ๆ "
-"ที่เà¸à¸´à¸”ขึ้นà¸à¸±à¸šà¸‰à¸²à¸à¹ƒà¸™à¹€à¸­à¸”ิเตอร์จะปราà¸à¸à¹ƒà¸™à¹‚ปรเจ็à¸à¸•์ที่à¸à¸³à¸¥à¸±à¸‡à¸—ำงานอยู่\n"
+"ที่เà¸à¸´à¸”ขึ้นà¸à¸±à¸šà¸‰à¸²à¸à¹ƒà¸™à¸•ัวà¹à¸à¹‰à¹„ขจะปราà¸à¸à¹ƒà¸™à¹‚ปรเจ็à¸à¸•์ที่à¸à¸³à¸¥à¸±à¸‡à¸—ำงานอยู่\n"
"เมื่อรีโมตผ่านอุปà¸à¸£à¸“์ นี่จะมีประสิทธิภาพมาà¸à¸‚ึ้นเมื่อเปิดใช้งานตัวเลือà¸à¸£à¸°à¸šà¸šà¹„ฟล์เครือข่าย"
#: editor/editor_node.cpp
@@ -2856,15 +2879,15 @@ msgstr ""
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
-msgstr "เอดิเตอร์"
+msgstr "ตัวà¹à¸à¹‰à¹„ข"
#: editor/editor_node.cpp
msgid "Editor Settings..."
-msgstr "ตั้งค่าเอดิเตอร์"
+msgstr "ตั้งค่าตัวà¹à¸à¹‰à¹„ข"
#: editor/editor_node.cpp
msgid "Editor Layout"
-msgstr "เลย์เอาต์เอดิเตอร์"
+msgstr "เค้าโครงตัวà¹à¸à¹‰à¹„ข"
#: editor/editor_node.cpp
msgid "Take Screenshot"
@@ -2872,7 +2895,7 @@ msgstr "ถ่ายภาพหน้าจอ"
#: editor/editor_node.cpp
msgid "Screenshots are stored in the Editor Data/Settings Folder."
-msgstr "ภาพหน้าจอจะถูà¸à¹€à¸à¹‡à¸šà¹„ว้ในโฟลเดอร์ข้อมูล/à¸à¸²à¸£à¸•ั้งค่าของเอดิเตอร์"
+msgstr "ภาพหน้าจอจะถูà¸à¹€à¸à¹‡à¸šà¹„ว้ในโฟลเดอร์ข้อมูล/à¸à¸²à¸£à¸•ั้งค่าของตัวà¹à¸à¹‰à¹„ข"
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
@@ -2884,19 +2907,19 @@ msgstr "เปิด/ปิด คอนโซลระบบ"
#: editor/editor_node.cpp
msgid "Open Editor Data/Settings Folder"
-msgstr "เปิดโฟลเดอร์ข้อมูล/ตั้งค่าของเอดิเตอร์"
+msgstr "เปิดโฟลเดอร์ข้อมูล/ตั้งค่าของตัวà¹à¸à¹‰à¹„ข"
#: editor/editor_node.cpp
msgid "Open Editor Data Folder"
-msgstr "เปิดโฟลเดอร์ของเอดิเตอร์"
+msgstr "เปิดโฟลเดอร์ของตัวà¹à¸à¹‰à¹„ข"
#: editor/editor_node.cpp
msgid "Open Editor Settings Folder"
-msgstr "เปิดโฟลเดอร์à¸à¸²à¸£à¸•ั้งค่าของเอดิเตอร์"
+msgstr "เปิดโฟลเดอร์à¸à¸²à¸£à¸•ั้งค่าของตัวà¹à¸à¹‰à¹„ข"
#: editor/editor_node.cpp
msgid "Manage Editor Features..."
-msgstr "จัดà¸à¸²à¸£à¸Ÿà¸µà¹€à¸ˆà¸­à¸£à¹Œà¸‚องเอดิเตอร์..."
+msgstr "จัดà¸à¸²à¸£à¸¥à¸±à¸à¸©à¸“ะเฉพาะของตัวà¹à¸à¹‰à¹„ข..."
#: editor/editor_node.cpp
msgid "Manage Export Templates..."
@@ -2932,6 +2955,10 @@ msgid "About"
msgstr "เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸š"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "เล่นโปรเจà¸à¸•์"
@@ -2969,7 +2996,7 @@ msgstr "เลือà¸à¹€à¸¥à¹ˆà¸™à¸‰à¸²à¸"
#: editor/editor_node.cpp
msgid "Changing the video driver requires restarting the editor."
-msgstr "à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹„ดรเวอร์à¸à¸²à¸£à¹Œà¸”จอจำเป็นต้องเริ่มเอดิเตอร์ใหม่"
+msgstr "à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹„ดรเวอร์à¸à¸²à¸£à¹Œà¸”จอจำเป็นต้องเริ่มตัวà¹à¸à¹‰à¹„ขใหม่"
#: editor/editor_node.cpp editor/project_settings_editor.cpp
#: editor/settings_config_dialog.cpp
@@ -3099,15 +3126,15 @@ msgstr "เลือà¸"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
-msgstr "เปิดเอดิเตอร์ 2D"
+msgstr "เปิดตัวà¹à¸à¹‰à¹„ข 2D"
#: editor/editor_node.cpp
msgid "Open 3D Editor"
-msgstr "เปิดเอดิเตอร์ 3D"
+msgstr "เปิดตัวà¹à¸à¹‰à¹„ข 3D"
#: editor/editor_node.cpp
msgid "Open Script Editor"
-msgstr "เปิดเอดิเตอร์สคริปต์"
+msgstr "เปิดตัวà¹à¸à¹‰à¹„ขสคริปต์"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
@@ -3115,11 +3142,11 @@ msgstr "เปิดà¹à¸«à¸¥à¹ˆà¸‡à¸£à¸§à¸¡à¸—รัพยาà¸à¸£"
#: editor/editor_node.cpp
msgid "Open the next Editor"
-msgstr "เปิดเอดิเตอร์ถัดไป"
+msgstr "เปิดตัวà¹à¸à¹‰à¹„ขถัดไป"
#: editor/editor_node.cpp
msgid "Open the previous Editor"
-msgstr "เปิดเอดิเตอร์à¸à¹ˆà¸­à¸™à¸«à¸™à¹‰à¸²"
+msgstr "เปิดตัวà¹à¸à¹‰à¹„ขà¸à¹ˆà¸­à¸™à¸«à¸™à¹‰à¸²"
#: editor/editor_node.h
msgid "Warning!"
@@ -3442,7 +3469,7 @@ msgstr "à¸à¸³à¸¥à¸±à¸‡à¸„ลายเทมเพลตส่งออà¸"
#: editor/export_template_manager.cpp
msgid "Importing:"
-msgstr "นำเข้า:"
+msgstr "à¸à¸³à¸¥à¸±à¸‡à¸™à¸³à¹€à¸‚้า:"
#: editor/export_template_manager.cpp
msgid "Error getting the list of mirrors."
@@ -4036,7 +4063,7 @@ msgstr "บันทึà¸à¸‰à¸²à¸, นำเข้าà¹à¸¥à¸°à¹€à¸£à¸´à¹ˆà¸¡à
#: editor/import_dock.cpp
msgid "Changing the type of an imported file requires editor restart."
-msgstr "à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸Šà¸™à¸´à¸”ของไฟล์ที่นำเข้า จำเป็นต้องเริ่มเอดิเตอร์ใหม่"
+msgstr "à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸Šà¸™à¸´à¸”ของไฟล์ที่นำเข้า จำเป็นต้องเริ่มตัวà¹à¸à¹‰à¹„ขใหม่"
#: editor/import_dock.cpp
msgid ""
@@ -4285,7 +4312,7 @@ msgstr "จุด"
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Open Editor"
-msgstr "เปิดเอดิเตอร์"
+msgstr "เปิดตัวà¹à¸à¹‰à¹„ข"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -5122,11 +5149,11 @@ msgid ""
msgstr "mesh บางส่วนไม่ถูà¸à¸•้อง ตรวจสอบให้à¹à¸™à¹ˆà¹ƒà¸ˆà¸§à¹ˆà¸²à¸„่า UV2 อยู่ในพื้นที่สี่เหลี่ยม [0.0,1.0]"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
+#, fuzzy
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
-"เอดิเตอร์ Godot ถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¹‚ดยไม่ได้สนับสนุน ray tracing ดังนั้นจึงไม่สามารถ bake lightmaps "
-"ได้"
+"ตัวà¹à¸à¹‰à¹„ข Godot ถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¹‚ดยไม่ได้สนับสนุน Ray Tracing ดังนั้นจึงไม่สามารถปั้น Lightmap ได้"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
@@ -5344,7 +5371,7 @@ msgid ""
"Overrides game camera with editor viewport camera."
msgstr ""
"เขียนทับà¸à¸¥à¹‰à¸­à¸‡à¸‚องเà¸à¸¡à¸ªà¹Œ\n"
-"เขียนทับà¸à¸¥à¹‰à¸­à¸‡à¸‚องเà¸à¸¡à¸ªà¹Œà¸”้วยเอดิเตอร์ของวิวพอร์ตของà¸à¸¥à¹‰à¸­à¸‡"
+"เขียนทับà¸à¸¥à¹‰à¸­à¸‡à¸‚องเà¸à¸¡à¸ªà¹Œà¸”้วยตัวà¹à¸à¹‰à¹„ขของวิวพอร์ตของà¸à¸¥à¹‰à¸­à¸‡"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6475,11 +6502,11 @@ msgstr "เติมน้ำหนัà¸à¹‚ครง"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Open Polygon 2D UV editor."
-msgstr "เปิดเอดิเตอร์ Polygon 2D UV"
+msgstr "เปิดตัวà¹à¸à¹‰à¹„ข Polygon 2D UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Polygon 2D UV Editor"
-msgstr "เอดิเตอร์ Polygon 2D UV"
+msgstr "ตัวà¹à¸à¹‰à¹„ข Polygon 2D UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "UV"
@@ -6734,7 +6761,8 @@ msgstr "สคริปต์ไม่ได้อยู่ในโหมดเ
#: editor/plugins/script_editor_plugin.cpp
msgid ""
"To run this script, it must inherit EditorScript and be set to tool mode."
-msgstr "เพื่อที่จะเริ่มสคริปต์ จำเป็นต้องสืบทอดสคริปต์เอดิเตอร์ à¹à¸¥à¸°à¸•ั้งโหมดเป็นโหมดเครื่องมือ"
+msgstr ""
+"หาà¸à¸•้องà¸à¸²à¸£à¸—ี่จะเริ่มสคริปต์ มันจำเป็นต้องสืบทอดจาภEditorScript à¹à¸¥à¸°à¸•ั้งโหมดเป็นโหมดเครื่องมือ"
#: editor/plugins/script_editor_plugin.cpp
msgid "Import Theme"
@@ -6894,7 +6922,7 @@ msgstr "เปิดตัวดีบัà¸à¸„้างไว้"
#: editor/plugins/script_editor_plugin.cpp
msgid "Debug with External Editor"
-msgstr "ดีบัà¸à¸”้วยเอดิเตอร์อื่น"
+msgstr "ดีบัà¸à¸”้วยตัวà¹à¸à¹‰à¹„ขภายนอà¸"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open Godot online documentation."
@@ -7426,14 +7454,14 @@ msgstr "ล็อคà¸à¸²à¸£à¸«à¸¡à¸¸à¸™à¸§à¸´à¸§à¹à¸¥à¹‰à¸§"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
-msgstr ""
+msgstr "หาà¸à¸•้องà¸à¸²à¸£à¸—ี่จะขยายให้ไà¸à¸¥à¸­à¸­à¸à¹„ป ให้เปลี่ยนระนอบà¸à¸²à¸£à¸•ัดของà¸à¸¥à¹‰à¸­à¸‡ (มุมมอง -> ตั้งค่า...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
-"หมายเหตุ: ค่า FPS ที่à¹à¸ªà¸”งเป็นอัตราเฟรมของเอดิเตอร์\n"
+"หมายเหตุ: ค่า FPS ที่à¹à¸ªà¸”งเป็นอัตราเฟรมของตัวà¹à¸à¹‰à¹„ข\n"
"ไม่สามารถใช้เป็นตัวบ่งชี้ประสิทธิภาพในเà¸à¸¡à¸—ี่à¹à¸—้จริงได้"
#: editor/plugins/spatial_editor_plugin.cpp
@@ -7933,7 +7961,7 @@ msgstr "สร้างเทมเพลตเปล่า"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create Empty Editor Template"
-msgstr "สร้างเทมเพลตเปล่าสำหรับเอดิเตอร์"
+msgstr "สร้างà¹à¸¡à¹ˆà¹à¸šà¸šà¹€à¸›à¸¥à¹ˆà¸²à¸ªà¸³à¸«à¸£à¸±à¸šà¸•ัวà¹à¸à¹‰à¹„ข"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create From Current Editor Theme"
@@ -9861,8 +9889,8 @@ msgid ""
"Language changed.\n"
"The interface will update after restarting the editor or project manager."
msgstr ""
-"เปลี่ยนภาษาà¹à¸¥à¹‰à¸§\n"
-"à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸ˆà¸°à¸¡à¸µà¸œà¸¥à¹€à¸¡à¸·à¹ˆà¸­à¹€à¸›à¸´à¸”เอดิเตอร์หรือตัวจัดà¸à¸²à¸£à¹‚ปรเจà¸à¸•์ใหม่"
+"ภาษาได้ถูà¸à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸¥à¹‰à¸§\n"
+"à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸ˆà¸°à¸¡à¸µà¸œà¸¥à¹€à¸¡à¸·à¹ˆà¸­à¹€à¸›à¸´à¸”ตัวà¹à¸à¹‰à¹„ขหรือตัวจัดà¸à¸²à¸£à¹‚ปรเจà¸à¸•์ใหม่"
#: editor/project_manager.cpp
msgid ""
@@ -9952,7 +9980,7 @@ msgstr "ปุ่มเมาส์"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr "ชื่อผิดพลาด ไม่สามารถเป็นช่องว่างหรือประà¸à¸­à¸šà¸”้วย '/', ':', '=', '\\' หรือ '\"'"
@@ -10168,7 +10196,7 @@ msgstr "à¸à¸³à¸«à¸™à¸”เฉพาะ..."
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "The editor must be restarted for changes to take effect."
-msgstr "ต้องเปิดเอดิเตอร์ใหม่เพื่อให้à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸¡à¸µà¸œà¸¥"
+msgstr "ต้องเปิดตัวà¹à¸à¹‰à¹„ขใหม่เพื่อให้à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸¡à¸µà¸œà¸¥"
#: editor/project_settings_editor.cpp
msgid "Input Map"
@@ -10685,8 +10713,8 @@ msgid ""
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
-"ไม่สามารถà¹à¸™à¸šà¸ªà¸„ริปต์: ไม่มีภาษาโปรà¹à¸à¸£à¸¡à¸—ี่เปิดใช้\n"
-"อาจเป็นเพราะเอดิเตอร์นี้สร้างขึ้นโดยปิดใช้งานโมดูลภาษาโปรà¹à¸à¸£à¸¡à¸—ั้งหมด"
+"ไม่สามารถà¹à¸™à¸šà¸ªà¸„ริปต์: ไม่มีภาษาที่เปิดใช้\n"
+"อาจเป็นเพราะตัวà¹à¸à¹‰à¹„ขนี้สร้างขึ้นโดยปิดใช้งานโมดูลภาษาทั้งหมด"
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10752,6 +10780,8 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"หาà¸à¹€à¸¥à¸·à¸­à¸à¹„ว้ à¹à¸œà¸‡à¸œà¸±à¸‡à¸‰à¸²à¸à¸ˆà¸²à¸à¸£à¸°à¸¢à¸°à¹„à¸à¸¥à¸ˆà¸°à¸—ำให้โปรเจà¸à¸•์เà¸à¸´à¸”à¸à¸²à¸£à¸à¸£à¸°à¸•ุà¸à¸—ุà¸à¸„รั้งที่อัปเดต\n"
+"สลับà¸à¸¥à¸±à¸šà¹„ปยัง à¹à¸œà¸‡à¸œà¸±à¸‡à¸‰à¸²à¸à¸ˆà¸²à¸à¸£à¸°à¸¢à¸°à¹ƒà¸à¸¥à¹‰à¹€à¸žà¸·à¹ˆà¸­à¹€à¸žà¸´à¹ˆà¸¡à¸›à¸£à¸°à¸ªà¸´à¸—ธิภาพในà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™"
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -10961,7 +10991,7 @@ msgstr "ไฟล์สคริปต์มีอยู่à¹à¸¥à¹‰à¸§"
msgid ""
"Note: Built-in scripts have some limitations and can't be edited using an "
"external editor."
-msgstr "หมายเหตุ: บิวท์อินสคริปต์มีข้อจำà¸à¸±à¸” ไม่สามารถà¹à¸à¹‰à¹„ขได้โดยใช้เอดิเตอร์ภายนอà¸"
+msgstr "หมายเหตุ: สคริปต์ในตัวมีข้อจำà¸à¸±à¸” ไม่สามารถà¹à¸à¹‰à¹„ขได้โดยใช้ตัวà¹à¸à¹‰à¹„ขภายนอà¸"
#: editor/script_create_dialog.cpp
msgid "Class Name:"
@@ -11141,7 +11171,7 @@ msgstr "à¹à¸à¹‰à¹„ขทางลัด"
#: editor/settings_config_dialog.cpp
msgid "Editor Settings"
-msgstr "ตั้งค่าเอดิเตอร์"
+msgstr "à¸à¸²à¸£à¸•ั้งค่าตัวà¹à¸à¹‰à¹„ข"
#: editor/settings_config_dialog.cpp
msgid "Shortcuts"
@@ -11979,8 +12009,20 @@ msgid ""
msgstr "เทมเพลตà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸ªà¸³à¸«à¸£à¸±à¸šà¹à¸­à¸™à¸”รอยด์ไม่ถูà¸à¸•ิดตั้ง สามารถติดตั้งจาà¸à¹€à¸¡à¸™à¸¹à¹‚ปรเจà¸à¸•์"
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
-msgstr "Debug keystore ไม่ได้ถูà¸à¸•ั้งไว้ในตั้งค่าของเอดิเตอร์หรือในพรีเซ็ต"
+msgstr "ดีบัภKeystore ไม่ได้ถูà¸à¸•ั้งไว้ในตั้งค่าของตัวà¹à¸à¹‰à¹„ขหรือในพรีเซ็ต"
+
+#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
@@ -11988,11 +12030,11 @@ msgstr "Release keystore à¸à¸³à¸«à¸™à¸”ค่าไว้อย่างไมà
#: platform/android/export/export.cpp
msgid "A valid Android SDK path is required in Editor Settings."
-msgstr "ต้องà¸à¸²à¸£à¸—ี่อยู่ของ Android SDK ที่ถูà¸à¸•้อง ในà¸à¸²à¸£à¸•ั้งค่าเอดิเตอร์"
+msgstr "ต้องà¸à¸²à¸£à¸—ี่อยู่ของ Android SDK ที่ถูà¸à¸•้อง ในà¸à¸²à¸£à¸•ั้งค่าตัวà¹à¸à¹‰à¹„ข"
#: platform/android/export/export.cpp
msgid "Invalid Android SDK path in Editor Settings."
-msgstr "ที่อยู่ Android SDK ไม่ถูà¸à¸•้องในตั้งค่าของเอดิเตอร์"
+msgstr "ที่อยู่ Android SDK ไม่ถูà¸à¸•้องในà¸à¸²à¸£à¸•ั้งค่าตัวà¹à¸à¹‰à¹„ข"
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
@@ -12004,7 +12046,7 @@ msgstr "ไม่พบคำสั่ง adb ของ Android SDK platform-too
#: platform/android/export/export.cpp
msgid "Please check in the Android SDK directory specified in Editor Settings."
-msgstr "โปรดตรวจสอบในไดเร็à¸à¸—อรี Android SDK ที่ระบุใตัวตั้งค่าของเอดิเตอร์"
+msgstr "à¸à¸£à¸¸à¸“าตรวจสอบในตำà¹à¸«à¸™à¹ˆà¸‡à¸‚อง Android SDK ที่ระบุไว้ในà¸à¸²à¸£à¸•ั้งค่าตัวà¹à¸à¹‰à¹„ข"
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
@@ -12737,7 +12779,7 @@ msgstr ""
#: scene/gui/color_picker.cpp
msgid "Pick a color from the editor window."
-msgstr "เลือà¸à¸ªà¸µà¸ˆà¸²à¸à¸«à¸™à¹‰à¸²à¸•่างเอดิเตอร์"
+msgstr "เลือà¸à¸ªà¸µà¸ˆà¸²à¸à¸«à¸™à¹‰à¸²à¸•่างตัวà¹à¸à¹‰à¹„ข"
#: scene/gui/color_picker.cpp
msgid "HSV"
@@ -12762,7 +12804,7 @@ msgid ""
"If you don't intend to add a script, use a plain Control node instead."
msgstr ""
"ตัวคอนเทนเนอร์เองไม่มีบทบาทเว้นà¹à¸•่คุณจะตั้งค่าลัà¸à¸©à¸“ะà¸à¸²à¸£à¸—ำงานของตำà¹à¸«à¸™à¹ˆà¸‡à¸£à¸­à¸‡à¹ƒà¸™à¸ªà¸„ริปต์\n"
-"หาà¸à¸„ุณไม่ต้องà¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸ªà¸„ริปต์ให้ใช้โหนด \"ควบคุม\" ปà¸à¸•ิà¹à¸—น"
+"หาà¸à¸„ุณไม่ต้องà¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡à¸ªà¸„ริปต์ให้ใช้โหนด Control ปà¸à¸•ิà¹à¸—น"
#: scene/gui/control.cpp
msgid ""
@@ -12795,7 +12837,7 @@ msgid ""
"running."
msgstr ""
"ป๊อปอัปจะถูà¸à¸‹à¹ˆà¸­à¸™à¸•ามค่าเริ่มต้นยà¸à¹€à¸§à¹‰à¸™à¹à¸•่คุณจะเรียà¸à¹ƒà¸Šà¹‰ popup() หรือฟังà¸à¹Œà¸Šà¸±à¸™ popup*() ใด ๆ "
-"à¸à¸²à¸£à¸—ำให้มองเห็นได้สำหรับà¸à¸²à¸£à¹à¸à¹‰à¹„ขเป็นเรื่องปà¸à¸•ิ à¹à¸•่จะซ่อนเมื่อทำงาน"
+"คุณสามารถทำให้มันมองเห็นได้เมื่อà¹à¸à¹‰à¹„ข à¹à¸•่มันจะถูà¸à¸‹à¹ˆà¸­à¸™à¹€à¸¡à¸·à¹ˆà¸­à¸—ำงานจริง"
#: scene/gui/range.cpp
msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index 47ac3ea764..5892850caf 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -57,12 +57,15 @@
# Suleyman Poyraz <zaryob.dev@gmail.com>, 2020.
# Çağlar KOPARIR <ckoparir@gmail.com>, 2021.
# Cem Eren Fukara <cefukara@hotmail.com>, 2021.
+# Jafar Tarverdiyev <cefertarverdiyevv@gmail.com>, 2021.
+# ali aydın <alimxaydin@gmail.com>, 2021.
+# Cannur Daşkıran <canndask@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-31 03:53+0000\n"
-"Last-Translator: OÄŸuz Ersen <oguzersen@protonmail.com>\n"
+"PO-Revision-Date: 2021-05-29 13:49+0000\n"
+"Last-Translator: ali aydın <alimxaydin@gmail.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/"
"godot/tr/>\n"
"Language: tr\n"
@@ -70,7 +73,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1168,6 +1171,10 @@ msgstr "Sözlükteki Değeri Değiştir"
msgid "Thanks from the Godot community!"
msgstr "Godot topluluğundan teşekkürler!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Oyun Motoru katkı sağlayanlar"
@@ -1555,7 +1562,7 @@ msgstr "İsim"
#: editor/editor_autoload_settings.cpp
msgid "Singleton"
-msgstr "Tekil"
+msgstr "Tekil nesne"
#: editor/editor_data.cpp editor/inspector_dock.cpp
msgid "Paste Params"
@@ -2039,7 +2046,7 @@ msgstr "Çevrimiçi Rehberler"
#: editor/editor_help.cpp
msgid "Properties"
-msgstr "Özellikleri"
+msgstr "Özellikler"
#: editor/editor_help.cpp
msgid "override:"
@@ -2580,7 +2587,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr "Eklentide için betik alanı bulunamıyor: '%s'."
+msgstr "Eklenti için betik alanı şu konumda bulunamıyor: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -2588,11 +2595,14 @@ msgstr "Yoldaki eklenti betiği yüklenemedi: '%s'."
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"'%s' adresindeki eklenti betik yüklenemiyor. Kodun içinde bir hata var gibi "
-"görünüyor, lütfen sözdizimini kontrol edin."
+"görünüyor.\n"
+"Daha fazla hatayı önlemek için '% s' adresindeki eklenti devre dışı "
+"bırakılıyor."
#: editor/editor_node.cpp
msgid ""
@@ -3035,6 +3045,10 @@ msgid "About"
msgstr "Hakkında"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Godot'u GeliÅŸtirmeye Destek Olun"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Projeti oynat."
@@ -4123,7 +4137,7 @@ msgstr "İçe Aktarıcı'yı seçin"
#: editor/import_defaults_editor.cpp
msgid "Importer:"
-msgstr "İçe Aktar"
+msgstr "İçe Alımcı:"
#: editor/import_defaults_editor.cpp
msgid "Reset to Defaults"
@@ -5101,7 +5115,7 @@ msgstr "Alınan:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Failed SHA-256 hash check"
-msgstr "SHA-256 hash kontrolü başarısız oldu"
+msgstr "Başarısız SHA-256 hash sınaması"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5269,8 +5283,8 @@ msgstr ""
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
-"Godot editör ışın yansıma desteği olmadan derlenmiş, ışık haritaları "
-"piÅŸirilemez."
+"Godot editör ışın yansıma desteği olmadan derlenmiş, ışık haritaları çizilip "
+"sabitlenemez."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
@@ -7589,6 +7603,8 @@ msgstr "Dönme Kilitli Görünüm"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Daha fazla yakınlaştırmak için, kameranın kırpma düzlemlerini değiştirin "
+"(Görünüm -> Ayarlar ...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -10162,7 +10178,7 @@ msgstr "Fare Düğmesi"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Geçersiz işlem adı. Boş olamaz ve '/', ':', '=', '\\' veya '\"' içeremez"
@@ -10718,11 +10734,11 @@ msgstr "Çocuk Sahnesini Örnekle"
#: editor/scene_tree_dock.cpp
msgid "Can't paste root node into the same scene."
-msgstr "Kök düğüm aynı sahneye yapıştırılamıyor."
+msgstr "Kök düğümü aynı sahne içine yapıştırılamaz."
#: editor/scene_tree_dock.cpp
msgid "Paste Node(s)"
-msgstr "Düğümleri Yapıştır"
+msgstr "Düğüm(leri) Yapıştır"
#: editor/scene_tree_dock.cpp
msgid "Detach Script"
@@ -10853,7 +10869,7 @@ msgstr "Betik İliştir"
#: editor/scene_tree_dock.cpp
msgid "Cut Node(s)"
-msgstr "Düğümleri Kes(s)"
+msgstr "Düğüm(leri) Kes"
#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
@@ -10973,6 +10989,9 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"Seçilirse, Uzak sahne ağacı yuvası, projenin her güncellendiğinde "
+"takılmasına neden olur.\n"
+"Performansı artırmak için Yerel sahne ağaç yuvasına geri dönün."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12215,12 +12234,24 @@ msgstr ""
"Android derleme şablonu projede yüklü değil. Proje menüsünden yükleyin."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"Anahtar deposunda Hata Ayıklayıcı Ayarları'nda veya ön ayarda "
"yapılandırılmamış."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Dışa aktarma ön kümesinde yanlış yapılandırılan anahtar deposunu (keystore) "
diff --git a/editor/translations/tt.po b/editor/translations/tt.po
new file mode 100644
index 0000000000..c0d7e79447
--- /dev/null
+++ b/editor/translations/tt.po
@@ -0,0 +1,12508 @@
+# Tatar translation of the Godot Engine editor.
+# Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
+# Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
+# This file is distributed under the same license as the Godot source code.
+#
+# Bualma Show <appleaidar6@gmail.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: Godot Engine editor\n"
+"PO-Revision-Date: 2021-06-07 23:43+0000\n"
+"Last-Translator: Bualma Show <appleaidar6@gmail.com>\n"
+"Language-Team: Tatar <https://hosted.weblate.org/projects/godot-engine/godot/"
+"tt/>\n"
+"Language: tt\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8-bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 4.7-dev\n"
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+#: modules/visual_script/visual_script_builtin_funcs.cpp
+msgid "Invalid type argument to convert(), use TYPE_* constants."
+msgstr "convert() өчен ÑракÑыз аргумент төре, TYPE_ * тотрыклы кулланыгыз."
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+msgid "Expected a string of length 1 (a character)."
+msgstr "Озынлык Ñызык 1 (Ñгъни Ñимвол) көтелгән иде."
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+#: modules/mono/glue/gd_glue.cpp
+#: modules/visual_script/visual_script_builtin_funcs.cpp
+msgid "Not enough bytes for decoding bytes, or invalid format."
+msgstr ""
+"Байтларны декодациÑләү өчен байтлар җитәрлек түгел Ñки Ñ€Ó©Ñ…Ñәт ителми торган "
+"формат."
+
+#: core/math/expression.cpp
+msgid "Invalid input %i (not passed) in expression"
+msgstr ""
+
+#: core/math/expression.cpp
+msgid "self can't be used because instance is null (not passed)"
+msgstr ""
+
+#: core/math/expression.cpp
+msgid "Invalid operands to operator %s, %s and %s."
+msgstr ""
+
+#: core/math/expression.cpp
+msgid "Invalid index of type %s for base type %s"
+msgstr ""
+
+#: core/math/expression.cpp
+msgid "Invalid named index '%s' for base type %s"
+msgstr ""
+
+#: core/math/expression.cpp
+msgid "Invalid arguments to construct '%s'"
+msgstr ""
+
+#: core/math/expression.cpp
+msgid "On call to '%s':"
+msgstr ""
+
+#: core/ustring.cpp
+msgid "B"
+msgstr ""
+
+#: core/ustring.cpp
+msgid "KiB"
+msgstr ""
+
+#: core/ustring.cpp
+msgid "MiB"
+msgstr ""
+
+#: core/ustring.cpp
+msgid "GiB"
+msgstr ""
+
+#: core/ustring.cpp
+msgid "TiB"
+msgstr ""
+
+#: core/ustring.cpp
+msgid "PiB"
+msgstr ""
+
+#: core/ustring.cpp
+msgid "EiB"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp
+msgid "Free"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp
+msgid "Balanced"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp
+msgid "Mirror"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp
+msgid "Time:"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp
+msgid "Value:"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp
+msgid "Insert Key Here"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp
+msgid "Duplicate Selected Key(s)"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp
+msgid "Delete Selected Key(s)"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp
+msgid "Add Bezier Point"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp
+msgid "Move Bezier Points"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
+msgid "Anim Duplicate Keys"
+msgstr ""
+
+#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
+msgid "Anim Delete Keys"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Keyframe Time"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Transition"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Transform"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Keyframe Value"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Call"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Keyframe Time"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Transition"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Transform"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Keyframe Value"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Call"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Length"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Change Animation Loop"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Property Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "3D Transform Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Call Method Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Bezier Curve Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Audio Playback Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation Playback Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation length (frames)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation length (seconds)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation Looping"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Functions:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Audio Clips:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Clips:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Track Path"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Toggle this track on/off."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Update Mode (How this property is set)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Interpolation Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove this track."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Time (s): "
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Toggle Track Enabled"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Continuous"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Discrete"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Trigger"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Capture"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Nearest"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/plugins/curve_editor_plugin.cpp
+#: editor/property_editor.cpp
+msgid "Linear"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Cubic"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clamp Loop Interp"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Wrap Loop Interp"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Duplicate Key(s)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Delete Key(s)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Update Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Interpolation Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Loop Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove Anim Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Create NEW track for %s and insert key?"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Create %d NEW tracks and insert keys?"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/create_dialog.cpp
+#: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_create_dialog.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "AnimationPlayer can't animate itself, only other players."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Create & Insert"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert Track & Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Step"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Rearrange Tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Transform tracks only apply to Spatial-based nodes."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid ""
+"Audio tracks can only point to nodes of type:\n"
+"-AudioStreamPlayer\n"
+"-AudioStreamPlayer2D\n"
+"-AudioStreamPlayer3D"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation tracks can only point to AnimationPlayer nodes."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "An animation player can't animate itself, only other players."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Not possible to add a new track without a root"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Invalid track for Bezier (no suitable sub-properties)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Bezier Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Track path is invalid, so can't add a key."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Track is not of type Spatial, can't insert key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Transform Track Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Track Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Track path is invalid, so can't add a method key."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Method Track Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Method not found in object: "
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Move Keys"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clipboard is empty"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Paste Tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Scale Keys"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid ""
+"This option does not work for Bezier editing, as it's only a single track."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid ""
+"This animation belongs to an imported scene, so changes to imported tracks "
+"will not be saved.\n"
+"\n"
+"To enable the ability to add custom tracks, navigate to the scene's import "
+"settings and set\n"
+"\"Animation > Storage\" to \"Files\", enable \"Animation > Keep Custom Tracks"
+"\", then re-import.\n"
+"Alternatively, use an import preset that imports animations to separate "
+"files."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Warning: Editing imported animation"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Select an AnimationPlayer node to create and edit animations."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Only show tracks from nodes selected in tree."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Group tracks by node or display them as plain list."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Snap:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation step value."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Seconds"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "FPS"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/editor_properties.cpp
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/property_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Edit"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation properties."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Copy Tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Scale Selection"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Scale From Cursor"
+msgstr ""
+
+#: editor/animation_track_editor.cpp modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Duplicate Selection"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Duplicate Transposed"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Delete Selection"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Go to Next Step"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Go to Previous Step"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Optimize Animation"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up Animation"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Pick the node that will be animated:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Use Bezier Curves"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim. Optimizer"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Max. Linear Error:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Max. Angular Error:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Max Optimizable Angle:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Optimize"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove invalid keys"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove unresolved and empty tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-up all animations"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up Animation(s) (NO UNDO!)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Scale Ratio:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Select Tracks to Copy"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/editor_log.cpp
+#: editor/editor_properties.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Copy"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Select All/None"
+msgstr ""
+
+#: editor/animation_track_editor_plugins.cpp
+msgid "Add Audio Track Clip"
+msgstr ""
+
+#: editor/animation_track_editor_plugins.cpp
+msgid "Change Audio Track Clip Start Offset"
+msgstr ""
+
+#: editor/animation_track_editor_plugins.cpp
+msgid "Change Audio Track Clip End Offset"
+msgstr ""
+
+#: editor/array_property_edit.cpp
+msgid "Resize Array"
+msgstr ""
+
+#: editor/array_property_edit.cpp
+msgid "Change Array Value Type"
+msgstr ""
+
+#: editor/array_property_edit.cpp
+msgid "Change Array Value"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Go to Line"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Line Number:"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "%d replaced."
+msgstr ""
+
+#: editor/code_editor.cpp editor/editor_help.cpp
+msgid "%d match."
+msgstr ""
+
+#: editor/code_editor.cpp editor/editor_help.cpp
+msgid "%d matches."
+msgstr ""
+
+#: editor/code_editor.cpp editor/find_in_files.cpp
+msgid "Match Case"
+msgstr ""
+
+#: editor/code_editor.cpp editor/find_in_files.cpp
+msgid "Whole Words"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Replace"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Replace All"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Selection Only"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
+#: editor/plugins/text_editor.cpp
+msgid "Standard"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Toggle Scripts Panel"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom In"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom Out"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Reset Zoom"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Warnings"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Line and column numbers."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Method in target node must be specified."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid ""
+"Target method not found. Specify a valid method or attach a script to the "
+"target node."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect to Node:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect to Script:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "From Signal:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Scene does not contain any script."
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp
+#: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
+msgid "Add"
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/dependency_editor.cpp
+#: editor/editor_feature_profile.cpp editor/groups_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp
+msgid "Remove"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Add Extra Call Argument:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Extra Call Arguments:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Receiver Method:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Advanced"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Deferred"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid ""
+"Defers the signal, storing it in a queue and only firing it at idle time."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Oneshot"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnects the signal after its first emission."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Cannot connect signal"
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/dependency_editor.cpp
+#: editor/export_template_manager.cpp editor/groups_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+#: editor/plugins/version_control_editor_plugin.cpp editor/project_export.cpp
+#: editor/project_settings_editor.cpp editor/property_editor.cpp
+#: editor/run_settings_dialog.cpp editor/settings_config_dialog.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Close"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Signal:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect '%s' to '%s'"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect '%s' from '%s'"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect all from signal: '%s'"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect..."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Disconnect"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect a Signal to a Method"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Edit Connection:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
+msgid "Signals"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Filter signals"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Are you sure you want to remove all connections from this signal?"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect All"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Edit..."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Go To Method"
+msgstr ""
+
+#: editor/create_dialog.cpp
+msgid "Change %s Type"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/project_settings_editor.cpp
+msgid "Change"
+msgstr ""
+
+#: editor/create_dialog.cpp
+msgid "Create New %s"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp
+msgid "Favorites:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
+msgid "Recent:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp editor/rename_dialog.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Search:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Matches:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/editor_plugin_settings.cpp
+#: editor/plugin_config_dialog.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/property_selector.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Description:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Search Replacement For:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Dependencies For:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Scene '%s' is currently being edited.\n"
+"Changes will only take effect when reloaded."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Resource '%s' is in use.\n"
+"Changes will only take effect when reloaded."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Dependencies"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Resource"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_autoload_settings.cpp
+#: editor/project_manager.cpp editor/project_settings_editor.cpp
+msgid "Path"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Dependencies:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Fix Broken"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Dependency Editor"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Search Replacement Resource:"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_file_dialog.cpp
+#: editor/editor_help_search.cpp editor/editor_node.cpp
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp
+#: editor/script_create_dialog.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+#: scene/gui/file_dialog.cpp
+msgid "Open"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Owners Of:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Remove selected files from the project? (no undo)\n"
+"You can find the removed files in the system trash to restore them."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"The files being removed are required by other resources in order for them to "
+"work.\n"
+"Remove them anyway? (no undo)\n"
+"You can find the removed files in the system trash to restore them."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Cannot remove:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Error loading:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Load failed due to missing dependencies:"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_node.cpp
+msgid "Open Anyway"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Which action should be taken?"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Fix Dependencies"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Errors loading!"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Permanently delete %d item(s)? (No undo!)"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Show Dependencies"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Orphan Resource Explorer"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/plugins/item_list_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp
+#: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp
+msgid "Delete"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Owns"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Resources Without Explicit Ownership:"
+msgstr ""
+
+#: editor/dictionary_property_edit.cpp
+msgid "Change Dictionary Key"
+msgstr ""
+
+#: editor/dictionary_property_edit.cpp
+msgid "Change Dictionary Value"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Thanks from the Godot community!"
+msgstr ""
+
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Godot Engine contributors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Project Founders"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Lead Developer"
+msgstr ""
+
+#. TRANSLATORS: This refers to a job title.
+#. The trailing space is used to distinguish with the project list application,
+#. you do not have to keep it in your translation.
+#: editor/editor_about.cpp
+msgid "Project Manager "
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Developers"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Authors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Platinum Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Gold Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Mini Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Gold Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Silver Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "License"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Third-party Licenses"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid ""
+"Godot Engine relies on a number of third-party free and open source "
+"libraries, all compatible with the terms of its MIT license. The following "
+"is an exhaustive list of all such third-party components with their "
+"respective copyright statements and license terms."
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "All Components"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Components"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Licenses"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "Error opening package file, not in ZIP format."
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "%s (Already Exists)"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Uncompressing Assets"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "The following files failed extraction from package:"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "And %s more files."
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "Package installed successfully!"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Success!"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Package Contents:"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/editor_node.cpp
+msgid "Install"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Package Installer"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Speakers"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Rename Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Change Audio Bus Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Solo"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Mute"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Bypass Effects"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Select Audio Bus Send"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Audio Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Move Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Drag & drop to rearrange."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Solo"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Mute"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Bypass"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Bus options"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Duplicate"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Reset Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Audio"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Master bus can't be deleted!"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Duplicate Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Reset Bus Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Move Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save Audio Bus Layout As..."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Location for New Layout..."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Open Audio Bus Layout"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "There is no '%s' file."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Layout"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Invalid file, not an audio bus layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Error saving file: %s"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add a new Audio Bus to this layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
+#: editor/script_create_dialog.cpp
+msgid "Load"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Load an existing Bus Layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save As"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save this Bus Layout to a file."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/import_dock.cpp
+msgid "Load Default"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Load the default Bus Layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Create a new Bus Layout."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Invalid name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Valid characters:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing engine class name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing built-in type name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing global constant name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Keyword cannot be used as an autoload name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Autoload '%s' already exists!"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Rename Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Toggle AutoLoad Globals"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Move Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Remove Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
+msgid "Enable"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Rearrange Autoloads"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Can't add autoload:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Add AutoLoad"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp
+#: editor/editor_plugin_settings.cpp
+#: editor/plugins/animation_tree_editor_plugin.cpp
+#: editor/script_create_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Path:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Node Name:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp
+#: editor/editor_profiler.cpp editor/project_manager.cpp
+#: editor/settings_config_dialog.cpp
+msgid "Name"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Singleton"
+msgstr ""
+
+#: editor/editor_data.cpp editor/inspector_dock.cpp
+msgid "Paste Params"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Updating Scene"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Storing local changes..."
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Updating scene..."
+msgstr ""
+
+#: editor/editor_data.cpp editor/editor_properties.cpp
+msgid "[empty]"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "[unsaved]"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Please select a base directory first."
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Choose a Directory"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp editor/project_manager.cpp
+#: scene/gui/file_dialog.cpp
+msgid "Create Folder"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_export.cpp
+#: modules/visual_script/visual_script_editor.cpp scene/gui/file_dialog.cpp
+msgid "Name:"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp scene/gui/file_dialog.cpp
+msgid "Could not create folder."
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Choose"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "Storing File:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "No export template found at the expected path:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "Packing"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
+"Etc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC2' texture compression for GLES3. Enable "
+"'Import Etc 2' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC' texture compression for the driver fallback "
+"to GLES2.\n"
+"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
+"Enabled'."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
+"'Import Pvrtc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
+"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'PVRTC' texture compression for the driver fallback "
+"to GLES2.\n"
+"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
+"Enabled'."
+msgstr ""
+
+#: editor/editor_export.cpp platform/android/export/export.cpp
+#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
+#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
+msgid "Custom debug template not found."
+msgstr ""
+
+#: editor/editor_export.cpp platform/android/export/export.cpp
+#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
+#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
+msgid "Custom release template not found."
+msgstr ""
+
+#: editor/editor_export.cpp platform/javascript/export/export.cpp
+msgid "Template file not found:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "3D Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Script Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Asset Library"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Scene Tree Editing"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Node Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "FileSystem Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Import Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Erase profile '%s'? (no undo)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Profile must be a valid filename and must not contain '.'"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Profile with this name already exists."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Editor Disabled, Properties Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Properties Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Editor Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Class Options:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enable Contextual Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Properties:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Features:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Classes:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "File '%s' format is invalid, import aborted."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid ""
+"Profile '%s' already exists. Remove it first before importing, import "
+"aborted."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Error saving profile to path: '%s'."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Unset"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Current Profile:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Make Current"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "New"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp editor/editor_node.cpp
+#: editor/project_manager.cpp
+msgid "Import"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp editor/project_export.cpp
+msgid "Export"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Available Profiles:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Class Options"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "New profile name:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Erase Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Godot Feature Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Import Profile(s)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Export Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Manage Editor Feature Profiles"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Select Current Folder"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "File Exists, Overwrite?"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Select This Folder"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "Copy Path"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "Open in File Manager"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/filesystem_dock.cpp editor/project_manager.cpp
+msgid "Show in File Manager"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "New Folder..."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/find_in_files.cpp
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Refresh"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "All Recognized"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "All Files (*)"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a File"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open File(s)"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a Directory"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a File or Directory"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
+msgid "Save"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Save a File"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Back"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Forward"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Up"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Hidden Files"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Favorite"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Mode"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Focus Path"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Move Favorite Up"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Move Favorite Down"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go to previous folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go to next folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Go to parent folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Refresh files."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "(Un)favorite current folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Toggle the visibility of hidden files."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "View items as a grid of thumbnails."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "View items as a list."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Directories & Files:"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/plugins/sprite_editor_plugin.cpp
+#: editor/plugins/style_box_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
+msgid "Preview:"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "File:"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid "ScanSources"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid ""
+"There are multiple importers for different types pointing to file %s, import "
+"aborted"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid "(Re)Importing Assets"
+msgstr ""
+
+#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
+msgid "Top"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Class:"
+msgstr ""
+
+#: editor/editor_help.cpp editor/scene_tree_editor.cpp
+#: editor/script_create_dialog.cpp
+msgid "Inherits:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Inherited by:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Description"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Online Tutorials"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Properties"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "override:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "default:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Methods"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Theme Properties"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Enumerations"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Constants"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Property Descriptions"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "(value)"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid ""
+"There is currently no description for this property. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Method Descriptions"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid ""
+"There is currently no description for this method. Please help us by [color="
+"$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/editor_node.cpp
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search Help"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Case Sensitive"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Show Hierarchy"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Display All"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Classes Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Methods Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Signals Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Constants Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Properties Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Theme Properties Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Member Type"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Class"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Method"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
+msgid "Signal"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
+msgid "Constant"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Property"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Theme Property"
+msgstr ""
+
+#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
+msgid "Property:"
+msgstr ""
+
+#: editor/editor_inspector.cpp
+msgid "Set"
+msgstr ""
+
+#: editor/editor_inspector.cpp
+msgid "Set Multiple:"
+msgstr ""
+
+#: editor/editor_log.cpp
+msgid "Output:"
+msgstr ""
+
+#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp
+msgid "Copy Selection"
+msgstr ""
+
+#: editor/editor_log.cpp editor/editor_network_profiler.cpp
+#: editor/editor_profiler.cpp editor/editor_properties.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/property_editor.cpp editor/scene_tree_dock.cpp
+#: editor/script_editor_debugger.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp
+#: scene/gui/text_edit.cpp
+msgid "Clear"
+msgstr ""
+
+#: editor/editor_log.cpp
+msgid "Clear Output"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_node.cpp
+#: editor/editor_profiler.cpp
+msgid "Stop"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
+#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
+msgid "Start"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "%s/s"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Down"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Up"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_node.cpp
+msgid "Node"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Incoming RPC"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Incoming RSET"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Outgoing RPC"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Outgoing RSET"
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+msgid "New Window"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Imported resources can't be saved."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: scene/gui/dialogs.cpp
+msgid "OK"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Error saving resource!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource can't be saved because it does not belong to the edited scene. "
+"Make it unique first."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Save Resource As..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't open file for writing:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Requested file format unknown:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while saving."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Can't open '%s'. The file could have been moved or deleted."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while parsing '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unexpected end of file '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Missing '%s' or its dependencies."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while loading '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Saving Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Analyzing"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Creating Thumbnail"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a tree root."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This scene can't be saved because there is a cyclic instancing inclusion.\n"
+"Please resolve it and then attempt to save again."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't "
+"be satisfied."
+msgstr ""
+
+#: editor/editor_node.cpp editor/scene_tree_dock.cpp
+msgid "Can't overwrite scene that is still open!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't load MeshLibrary for merging!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error saving MeshLibrary!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't load TileSet for merging!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error saving TileSet!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"An error occurred while trying to save the editor layout.\n"
+"Make sure the editor's user data path is writable."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Default editor layout overridden.\n"
+"To restore the Default layout to its base settings, use the Delete Layout "
+"option and delete the Default layout."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Layout name not found!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Restored the Default layout to its base settings."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource belongs to a scene that was imported, so it's not editable.\n"
+"Please read the documentation relevant to importing scenes to better "
+"understand this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource belongs to a scene that was instanced or inherited.\n"
+"Changes to it won't be kept when saving the current scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource was imported, so it's not editable. Change its settings in the "
+"import panel and then re-import."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This scene was imported, so changes to it won't be kept.\n"
+"Instancing it or inheriting will allow making changes to it.\n"
+"Please read the documentation relevant to importing scenes to better "
+"understand this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This is a remote object, so changes to it won't be kept.\n"
+"Please read the documentation relevant to debugging to better understand "
+"this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "There is no defined scene to run."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save scene before running..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Could not start subprocess!"
+msgstr ""
+
+#: editor/editor_node.cpp editor/filesystem_dock.cpp
+msgid "Open Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Base Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open Script..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save & Close"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes to '%s' before closing?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Saved %s modified resource(s)."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "A root node is required to save the scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Scene As..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/scene_tree_dock.cpp
+msgid "This operation can't be done without a scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Mesh Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a root node."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Tile Set"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a selected node."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Current scene not saved. Open anyway?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't reload a scene that was never saved."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Reload Saved Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The current scene has unsaved changes.\n"
+"Reload the saved scene anyway? This action cannot be undone."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Run Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quit"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Yes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Exit the editor?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Project Manager?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save & Quit"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes to the following scene(s) before quitting?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes the following scene(s) before opening Project Manager?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This option is deprecated. Situations where refresh must be forced are now "
+"considered a bug. Please report."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pick a Main Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Reopen Closed Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to load addon script from path: '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Scene '%s' was automatically imported, so it can't be modified.\n"
+"To make changes to it, a new inherited scene can be created."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Error loading scene, it must be inside the project path. Use 'Import' to "
+"open the scene, then save it inside the project path."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Scene '%s' has broken dependencies:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Clear Recent Scenes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"No main scene has ever been defined, select one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Selected scene '%s' does not exist, select a valid one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Selected scene '%s' is not a scene file, select a valid one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Layout"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Delete Layout"
+msgstr ""
+
+#: editor/editor_node.cpp editor/import_dock.cpp
+#: editor/script_create_dialog.cpp
+msgid "Default"
+msgstr ""
+
+#: editor/editor_node.cpp editor/editor_properties.cpp
+#: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp
+msgid "Show in FileSystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play This Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Undo Close Tab"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Close Other Tabs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Tabs to the Right"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close All Tabs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Switch Scene Tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more files or folders"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more folders"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more files"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Dock Position"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Distraction Free Mode"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle distraction-free mode."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Add a new scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Go to previously opened scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Copy Text"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Next tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Previous tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Filter Files..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Operations with scene files."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Inherited Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Open Recent"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save All Scenes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Convert To..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "MeshLibrary..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "TileSet..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Undo"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Redo"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Miscellaneous project or scene-wide tools."
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+#: editor/script_create_dialog.cpp
+msgid "Project"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Project Settings..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
+msgid "Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
+msgid "Set Up Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Shut Down Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Install Android Build Template..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Project Data Folder"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp
+msgid "Tools"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Orphan Resource Explorer..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quit to Project List"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/project_export.cpp
+msgid "Debug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Deploy with Remote Debug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, using one-click deploy will make the executable "
+"attempt to connect to this computer's IP so the running project can be "
+"debugged.\n"
+"This option is intended to be used for remote debugging (typically with a "
+"mobile device).\n"
+"You don't need to enable it to use the GDScript debugger locally."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Small Deploy with Network Filesystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, using one-click deploy for Android will only "
+"export an executable without the project data.\n"
+"The filesystem will be provided from the project by the editor over the "
+"network.\n"
+"On Android, deploying will use the USB cable for faster performance. This "
+"option speeds up testing for projects with large assets."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Visible Collision Shapes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, collision shapes and raycast nodes (for 2D and "
+"3D) will be visible in the running project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Visible Navigation"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, navigation meshes and polygons will be visible "
+"in the running project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Synchronize Scene Changes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, any changes made to the scene in the editor "
+"will be replicated in the running project.\n"
+"When used remotely on a device, this is more efficient when the network "
+"filesystem option is enabled."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Synchronize Script Changes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, any script that is saved will be reloaded in "
+"the running project.\n"
+"When used remotely on a device, this is more efficient when the network "
+"filesystem option is enabled."
+msgstr ""
+
+#: editor/editor_node.cpp editor/script_create_dialog.cpp
+msgid "Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Editor Settings..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Editor Layout"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Take Screenshot"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Screenshots are stored in the Editor Data/Settings Folder."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle Fullscreen"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle System Console"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Data/Settings Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Data Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Settings Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Editor Features..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Export Templates..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp
+msgid "Help"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Online Docs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Q&A"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Report a Bug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Send Docs Feedback"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
+msgid "Community"
+msgstr "Җәмәгать"
+
+#: editor/editor_node.cpp
+msgid "About"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play the project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pause the scene execution for debugging."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pause Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Stop the scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play the edited scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play custom scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play Custom Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Changing the video driver requires restarting the editor."
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_settings_editor.cpp
+#: editor/settings_config_dialog.cpp
+msgid "Save & Restart"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Update Continuously"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Update When Changed"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Hide Update Spinner"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "FileSystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Inspector"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Expand Bottom Panel"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Output"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Don't Save"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Android build template is missing, please install relevant templates."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Templates"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This will set up your project for custom Android builds by installing the "
+"source template to \"res://android/build\".\n"
+"You can then apply modifications and build your own custom APK on export "
+"(adding modules, changing the AndroidManifest.xml, etc.).\n"
+"Note that in order to make custom builds instead of using pre-built APKs, "
+"the \"Use Custom Build\" option should be enabled in the Android export "
+"preset."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The Android build template is already installed in this project and it won't "
+"be overwritten.\n"
+"Remove the \"res://android/build\" directory manually before attempting this "
+"operation again."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Import Templates From ZIP File"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Template Package"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Merge With Existing"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open & Run a Script"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Inherited"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Load Errors"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
+msgid "Select"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open 2D Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open 3D Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Script Editor"
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+msgid "Open Asset Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open the next Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open the previous Editor"
+msgstr ""
+
+#: editor/editor_node.h
+msgid "Warning!"
+msgstr ""
+
+#: editor/editor_path.cpp
+msgid "No sub-resources found."
+msgstr ""
+
+#: editor/editor_plugin.cpp
+msgid "Creating Mesh Previews"
+msgstr ""
+
+#: editor/editor_plugin.cpp
+msgid "Thumbnail..."
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Main Script:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Edit Plugin"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Installed Plugins:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+msgid "Update"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Version:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+msgid "Author:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Status:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Edit:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Measure:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame Time (sec)"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Average Time (sec)"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame %"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Physics Frame %"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Inclusive"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Self"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame #:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Time"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Calls"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Edit Text:"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/script_create_dialog.cpp
+msgid "On"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Layer"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Bit %d, value %d"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "[Empty]"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
+msgid "Assign..."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Invalid RID"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"The selected resource (%s) does not match any type expected for this "
+"property (%s)."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"Can't create a ViewportTexture on resources saved as a file.\n"
+"Resource needs to belong to a scene."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"Can't create a ViewportTexture on this resource because it's not set as "
+"local to scene.\n"
+"Please switch on the 'local to scene' property on it (and all resources "
+"containing it up to a node)."
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Pick a Viewport"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "New Script"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/scene_tree_dock.cpp
+msgid "Extend Script"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "New %s"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Make Unique"
+msgstr ""
+
+#: editor/editor_properties.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Paste"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Convert To %s"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Selected node is not a Viewport!"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Size: "
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Page: "
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove Item"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "New Key:"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "New Value:"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Add Key/Value Pair"
+msgstr ""
+
+#: editor/editor_run_native.cpp
+msgid ""
+"No runnable export preset found for this platform.\n"
+"Please add a runnable preset in the Export menu or define an existing preset "
+"as runnable."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Write your logic in the _run() method."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "There is an edited scene already."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Couldn't instance script:"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Did you forget the 'tool' keyword?"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Couldn't run script:"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Did you forget the '_run' method?"
+msgstr ""
+
+#: editor/editor_spin_slider.cpp
+msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Select Node(s) to Import"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp editor/project_manager.cpp
+msgid "Browse"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Scene Path:"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Import From Node:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Redownload"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Uninstall"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Installed)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Official export templates aren't available for development builds."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Missing)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Current)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Retrieving mirrors, please wait..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Remove template version '%s'?"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't open export templates zip."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Invalid version.txt format inside templates: %s."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "No version.txt found inside templates."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error creating path for templates:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Extracting Export Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Importing:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error getting the list of mirrors."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error parsing JSON of mirror list. Please report this issue!"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid ""
+"No download links found for this version. Direct download is only available "
+"for official releases."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't resolve."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't connect."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No response."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Request Failed."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Redirect Loop."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Failed:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Download Complete."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Cannot remove temporary file:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid ""
+"Templates installation failed.\n"
+"The problematic templates archives can be found at '%s'."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error requesting URL:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connecting to Mirror..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Disconnected"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Resolving"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't Resolve"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Connecting..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't Connect"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connected"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Requesting..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Downloading"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connection Error"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "SSL Handshake Error"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Uncompressing Android Build Sources"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Current Version:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Installed Versions:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Install From File"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Remove Template"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Select Template File"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Godot Export Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Export Template Manager"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Download Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Select mirror from list: (Shift+Click: Open in Browser)"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Status: Import of file failed. Please fix file and reimport manually."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Cannot move/rename resources root."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Cannot move a folder into itself."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Error moving:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Error duplicating:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Unable to update dependencies:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/scene_tree_editor.cpp
+msgid "No name provided."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Provided name contains invalid characters."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "A file or folder with this name already exists."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Name contains invalid characters."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"The following files or folders conflict with items in the target location "
+"'%s':\n"
+"\n"
+"%s\n"
+"\n"
+"Do you wish to overwrite them?"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Renaming file:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Renaming folder:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicating file:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicating folder:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Inherited Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Set As Main Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Open Scenes"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Instance"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Add to Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Remove from Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Edit Dependencies..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "View Owners..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move To..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Scene..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+msgid "New Script..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Resource..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Expand All"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Collapse All"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicate..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Previous Folder/File"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Next Folder/File"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Re-Scan Filesystem"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Toggle Split Mode"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Search files"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Scanning Files,\n"
+"Please Wait..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Overwrite"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Create Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Create Script"
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Find in Files"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Find:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Folder:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Filters:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid ""
+"Include the files with the following extensions. Add or remove them in "
+"ProjectSettings."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find..."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_text_editor.cpp
+msgid "Replace..."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/progress_dialog.cpp scene/gui/dialogs.cpp
+msgid "Cancel"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Find: "
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Replace: "
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Replace all (no undo)"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Searching..."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d match in %d file."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d matches in %d file."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d matches in %d files."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Add to Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Remove from Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Group name already exists."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Invalid group name."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Rename Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Delete Group"
+msgstr ""
+
+#: editor/groups_editor.cpp editor/node_dock.cpp
+msgid "Groups"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Nodes Not in Group"
+msgstr ""
+
+#: editor/groups_editor.cpp editor/scene_tree_dock.cpp
+#: editor/scene_tree_editor.cpp
+msgid "Filter nodes"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Nodes in Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Empty groups will be automatically removed."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Group Editor"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Manage Groups"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Single Scene"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Materials+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Materials+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Multiple Scenes"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Multiple Scenes+Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Import Scene"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Importing Scene..."
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Generating Lightmaps"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Generating for Mesh: "
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Running Custom Script..."
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Couldn't load post-import script:"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Invalid/broken script for post-import (check console):"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Error running post-import script:"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Did you return a Node-derived object in the `post_import()` method?"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Saving..."
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "%d Files"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Set as Default for '%s'"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Clear Default for '%s'"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Import As:"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Preset"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Reimport"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Save Scenes, Re-Import, and Restart"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Changing the type of an imported file requires editor restart."
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid ""
+"WARNING: Assets exist that use this resource, they may stop loading properly."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Failed to load resource."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Expand All Properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Collapse All Properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save As..."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Copy Params"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Edit Resource Clipboard"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Copy Resource"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Make Built-In"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Make Sub-Resources Unique"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Open in Help"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Create a new resource in memory and edit it."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Load an existing resource from disk and edit it."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Save the currently edited resource."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Go to the previous edited object in history."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Go to the next edited object in history."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "History of recently edited objects."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Object properties."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Filter properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Changes may be lost!"
+msgstr ""
+
+#: editor/multi_node_edit.cpp
+msgid "MultiNode Set"
+msgstr ""
+
+#: editor/node_dock.cpp
+msgid "Select a single node to edit its signals and groups."
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Edit a Plugin"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Create a Plugin"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Plugin Name:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Subfolder:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
+msgid "Language:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Script Name:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Activate now?"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Polygon"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Create points."
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid ""
+"Edit points.\n"
+"LMB: Move Point\n"
+"RMB: Erase Point"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Erase points."
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Edit Polygon"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Insert Point"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Edit Polygon (Remove Point)"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Remove Polygon And Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Animation"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Load..."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Move Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Change BlendSpace1D Limits"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Change BlendSpace1D Labels"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "This type of node can't be used. Only root nodes are allowed."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Animation Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Remove BlendSpace1D Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Move BlendSpace1D Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid ""
+"AnimationTree is inactive.\n"
+"Activate to enable playback, check node warnings if activation fails."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Set the blending position within the space"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Select and move points, create points with RMB."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
+msgid "Enable snap and show grid."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Open Editor"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Open Animation Node"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Triangle already exists."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Triangle"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Change BlendSpace2D Limits"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Change BlendSpace2D Labels"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Remove BlendSpace2D Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Remove BlendSpace2D Triangle"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "BlendSpace2D does not belong to an AnimationTree node."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "No triangles exist, so no blending can take place."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Toggle Auto Triangles"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Create triangles by connecting points."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Erase points and triangles."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Generate blend triangles automatically (instead of manually)"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend:"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Parameter Changed"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Edit Filters"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Output node can't be added to the blend tree."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Add Node to BlendTree"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Node Moved"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Unable to connect, port may be in use or connection may be invalid."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Nodes Connected"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Nodes Disconnected"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Set Animation"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Delete Node"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Delete Node(s)"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Toggle Filter On/Off"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Change Filter"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "No animation player set, so unable to retrieve track names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Player path set is invalid, so unable to retrieve track names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid ""
+"Animation player has no valid root node path, so unable to retrieve track "
+"names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Anim Clips"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Audio Clips"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Functions"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Node Renamed"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Node..."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "Edit Filtered Tracks:"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Enable Filtering"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Toggle Autoplay"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "New Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "New Anim"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Change Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Delete Animation?"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Remove Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Invalid animation name!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation name already exists!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Rename Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Blend Next Changed"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Change Blend Time"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Load Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Duplicate Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation to copy!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation resource on clipboard!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Pasted Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Paste Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation to edit!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation backwards from current pos. (A)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation backwards from end. (Shift+A)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Stop animation playback. (S)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation from start. (Shift+D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation from current pos. (D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation position (in seconds)."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Scale animation playback globally for the node."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation Tools"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Edit Transitions..."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Open in Inspector"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Display list of animations in player."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Autoplay on Load"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Enable Onion Skinning"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Onion Skinning Options"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Directions"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Past"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Future"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Depth"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "1 step"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "2 steps"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "3 steps"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Differences Only"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Force White Modulate"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Include Gizmos (3D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Pin AnimationPlayer"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Create New Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
+msgid "Error!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Blend Times:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Next (Auto Queue):"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Cross-Animation Blend Times"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Move Node"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition exists!"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Add Transition"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Node"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "End"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Immediate"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Sync"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "At End"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Travel"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Start and end nodes are needed for a sub-transition."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "No playback resource set at path: %s."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Node Removed"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition Removed"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Set Start Node (Autoplay)"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid ""
+"Select and move nodes.\n"
+"RMB to add new nodes.\n"
+"Shift+LMB to create connections."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Create new nodes."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Connect nodes."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Remove selected node or transition."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Toggle autoplay this animation on start, restart or seek to zero."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Set the end animation. This is useful for sub-transitions."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition: "
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Play Mode:"
+msgstr ""
+
+#: editor/plugins/animation_tree_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "AnimationTree"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "New name:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Scale:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Fade In (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Fade Out (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Mix"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Auto Restart:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Restart (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Random Restart (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Start!"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Amount:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend 0:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend 1:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "X-Fade Time (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Current:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Input"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Clear Auto-Advance"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Set Auto-Advance"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Delete Input"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation tree is valid."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation tree is invalid."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "OneShot Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Mix Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend2 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend3 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend4 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "TimeScale Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "TimeSeek Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Transition Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Import Animations..."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Edit Node Filters"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Filters..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Contents:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "View Files"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Connection error, please try again."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't connect to host:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No response from host:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't resolve hostname:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, return code:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Cannot save response to:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Write error."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, too many redirects"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Redirect loop."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, timeout"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Timeout."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Bad download hash, assuming file has been tampered with."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Expected:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Got:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Failed SHA-256 hash check"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Asset Download Error:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Downloading (%s / %s)..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Downloading..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Resolving..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Error making request"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Idle"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Install..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Retry"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download Error"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download for this asset is already in progress!"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Recently Updated"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Least Recently Updated"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Name (A-Z)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Name (Z-A)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "License (A-Z)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "License (Z-A)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "First"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Previous"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Next"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Last"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "All"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No results for \"%s\"."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Import..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Plugins..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
+msgid "Sort:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Category:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Site:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Support"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Official"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Testing"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Loading..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Assets ZIP File"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Can't determine a save path for lightmap images.\n"
+"Save your scene and try again."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake "
+"Light' flag is on."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Failed creating lightmap images, make sure path is writable."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Failed determining lightmap size. Maximum lightmap size too small?"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Some mesh is invalid. Make sure the UV2 channel values are contained within "
+"the [0.0,1.0] square region."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Godot editor was built without ray tracing support, lightmaps can't be baked."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Bake Lightmaps"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Select lightmap bake file:"
+msgstr ""
+
+#: editor/plugins/camera_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Preview"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Configure Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Grid Offset:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Grid Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Primary Line Every:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "steps"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation Offset:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Remove Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Remove Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Horizontal and Vertical Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotate %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotate CanvasItem \"%s\" to %d degrees"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move CanvasItem \"%s\" Anchor"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale Node2D \"%s\" to (%s, %s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Resize Control \"%s\" to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale CanvasItem \"%s\" to (%s, %s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move CanvasItem \"%s\" to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Children of containers have their anchors and margins values overridden by "
+"their parent."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Presets for the anchors and margins values of a Control node."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"When active, moving Control nodes changes their anchors instead of their "
+"margins."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Top"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Bottom"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Left Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Right Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "VCenter Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "HCenter Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Full Rect"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Keep Ratio"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Anchors only"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Anchors and Margins"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Anchors"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Game Camera Override\n"
+"Overrides game camera with editor viewport camera."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Game Camera Override\n"
+"No game instance running."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Unlock Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Group Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Ungroup Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Paste Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Custom Bone(s) from Node(s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Make IK Chain"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear IK Chain"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Warning: Children of a container get their position and size determined only "
+"by their parent."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom Reset"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Select Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Drag: Rotate"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Alt+Drag: Move"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Alt+RMB: Depth list selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Move Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Show a list of all objects at the position clicked\n"
+"(same as Alt+RMB in select mode)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Click to change object's rotation pivot."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Pan Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Ruler Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Toggle smart snapping."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Smart Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Toggle grid snapping."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Grid Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snapping Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Rotation Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Scale Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap Relative"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Pixel Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Smart Snapping"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Configure Snap..."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Parent"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Anchor"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Sides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Center"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Other Nodes"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock the selected object in place (can't be moved)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Unlock the selected object (can be moved)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Makes sure the object's children are not selectable."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Restores the object's children's ability to be selected."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Skeleton Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Make Custom Bone(s) from Node(s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Custom Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Always Show Grid"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Helpers"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Rulers"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Origin"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Viewport"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Group And Lock Icons"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Frame Selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Preview Canvas Scale"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Translation mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert keys (based on mask)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Auto insert keys when objects are translated, rotated or scaled (based on "
+"mask).\n"
+"Keys are only added to existing tracks, no new tracks will be created.\n"
+"Keys must be inserted manually for the first time."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Auto Insert Key"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Animation Key and Pose Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert Key (Existing Tracks)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Copy Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Multiply grid step by 2"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Divide grid step by 2"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Pan View"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Add %s"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Adding %s..."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Cannot instantiate multiple nodes without root."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Create Node"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Error instancing scene from %s"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Default Type"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Drag & drop + Shift : Add node as sibling\n"
+"Drag & drop + Alt : Change node type"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Create Polygon3D"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Edit Poly"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Edit Poly (Remove Point)"
+msgstr ""
+
+#: editor/plugins/collision_shape_2d_editor_plugin.cpp
+msgid "Set Handle"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Load Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Restart"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Clear Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Particles"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generated Point Count:"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Solid Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Border Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Directed Border Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Capture from Pixel"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Emission Colors"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+msgid "CPUParticles"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emission Points From Mesh"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emission Points From Node"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Flat 0"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Flat 1"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
+msgid "Ease In"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
+msgid "Ease Out"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Smoothstep"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Modify Curve Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Modify Curve Tangent"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Load Curve Preset"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Add Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Remove Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Left Linear"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Right Linear"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Load Preset"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Remove Curve Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Toggle Curve Linear Tangent"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Hold Shift to edit tangents individually"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Right click to add point"
+msgstr ""
+
+#: editor/plugins/gi_probe_editor_plugin.cpp
+msgid "Bake GI Probe"
+msgstr ""
+
+#: editor/plugins/gradient_editor_plugin.cpp
+msgid "Gradient Edited"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Item %d"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Items"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Item List Editor"
+msgstr ""
+
+#: editor/plugins/light_occluder_2d_editor_plugin.cpp
+msgid "Create Occluder Polygon"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh is empty!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create a Trimesh collision shape."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Static Trimesh Body"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "This doesn't work on scene root!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Static Shape"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Can't create a single convex collision shape for the scene root."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create a single convex collision shape."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Single Convex Shape"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Can't create multiple convex collision shapes for the scene root."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create any collision shapes."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Multiple Convex Shapes"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Navigation Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Contained Mesh is not of type ArrayMesh."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "UV Unwrap failed, mesh may not be manifold?"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "No mesh to debug."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Model has no UV in this layer"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "MeshInstance lacks a Mesh!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh has not surface to create outlines from!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh primitive type is not PRIMITIVE_TRIANGLES!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Could not create outline!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Static Body"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a StaticBody and assigns a polygon-based collision shape to it "
+"automatically.\n"
+"This is the most accurate (but slowest) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Collision Sibling"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a polygon-based collision shape.\n"
+"This is the most accurate (but slowest) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Single Convex Collision Sibling"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a single convex collision shape.\n"
+"This is the fastest (but least accurate) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Multiple Convex Collision Siblings"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a polygon-based collision shape.\n"
+"This is a performance middle-ground between the two above options."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline Mesh..."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a static outline mesh. The outline mesh will have its normals "
+"flipped automatically.\n"
+"This can be used instead of the SpatialMaterial Grow property when using "
+"that property isn't possible."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "View UV1"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "View UV2"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Unwrap UV2 for Lightmap/AO"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Outline Size:"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "UV Channel Debug"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Remove item %d?"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid ""
+"Update from existing scene?:\n"
+"%s"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Mesh Library"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add Item"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Remove Selected Item"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Import from Scene"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Update from Scene"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No mesh source specified (and no MultiMesh set in node)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No mesh source specified (and MultiMesh contains no Mesh)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (invalid path)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (not a MeshInstance)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (contains no Mesh resource)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No surface source specified."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (invalid path)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (no geometry)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (no faces)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Select a Source Mesh:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Select a Target Surface:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate Surface"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate MultiMesh"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Target Surface:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Source Mesh:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "X-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Y-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Z-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh Up Axis:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Rotation:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Tilt:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Scale:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate"
+msgstr ""
+
+#: editor/plugins/navigation_polygon_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Convert to CPUParticles"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generating Visibility Rect"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generate Visibility Rect"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Can only set point into a ParticlesMaterial process material"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Convert to CPUParticles2D"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generation Time (sec):"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "The geometry's faces don't contain any area."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "The geometry doesn't contain any faces."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't inherit from Spatial."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't contain geometry."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't contain face geometry."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emitter"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Emission Points:"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Surface Points"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Surface Points+Normal (Directed)"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Volume"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Emission Source: "
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "A processor material of type 'ParticlesMaterial' is required."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generating AABB"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generate Visibility AABB"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove Point from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove Out-Control from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove In-Control from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Add Point to Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Split Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move Point in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move In-Control in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move Out-Control in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Select Points"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Shift+Drag: Select Control Points"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Click: Add Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Left Click: Split Segment (in curve)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Right Click: Delete Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Select Control Points (Shift+Drag)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Add Point (in empty space)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Delete Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Close Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_export.cpp
+msgid "Options"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Mirror Handle Angles"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Mirror Handle Lengths"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Curve Point #"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve Point Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve In Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve Out Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Split Path"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove Path Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove Out-Control Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove In-Control Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Split Segment (in curve)"
+msgstr ""
+
+#: editor/plugins/physical_bone_plugin.cpp
+msgid "Move Joint"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"The skeleton property of the Polygon2D does not point to a Skeleton2D node"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Sync Bones"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"No texture in this polygon.\n"
+"Set a texture to be able to edit UV."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create UV Map"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"Polygon 2D has internal vertices, so it can no longer be edited in the "
+"viewport."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Polygon & UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Internal Vertex"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Remove Internal Vertex"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Invalid Polygon (need 3 different vertices)"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Add Custom Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Remove Custom Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Transform UV Map"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Transform Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Paint Bone Weights"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Open Polygon 2D UV editor."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Polygon 2D UV Editor"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Points"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Polygons"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Bones"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Move Points"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Command: Rotate"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift: Move All"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift+Command: Scale"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Ctrl: Rotate"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift+Ctrl: Scale"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Move Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Rotate Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Scale Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create a custom polygon. Enables custom polygon rendering."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"Remove a custom polygon. If none remain, custom polygon rendering is "
+"disabled."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Paint weights with specified intensity."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Unpaint weights with specified intensity."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Radius:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Copy Polygon to UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Copy UV to Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Clear UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Settings"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Snap"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Enable Snap"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Show Grid"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Configure Grid:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Offset X:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Offset Y:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Step X:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Step Y:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Sync Bones to Polygon"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "ERROR: Couldn't load resource!"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Add Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Rename Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Delete Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Resource clipboard is empty!"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Paste Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/scene_tree_editor.cpp
+msgid "Instance:"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
+#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Type:"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp
+msgid "Open in Editor"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Load Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "ResourcePreloader"
+msgstr ""
+
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "AnimationTree has no path set to an AnimationPlayer"
+msgstr ""
+
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "Path to AnimationPlayer is invalid"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Clear Recent Files"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close and save changes?"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error writing TextFile:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Could not load file at:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error saving file!"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error while saving theme."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error Saving"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error importing theme."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error Importing"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "New Text File..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open File"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save File As..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Can't obtain the script for running."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Script failed reloading, check console for errors."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Script is not in tool mode, will not be able to run."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid ""
+"To run this script, it must inherit EditorScript and be set to tool mode."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Import Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error while saving theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error saving"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save Theme As..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "%s Class Reference"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find Next"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find Previous"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Filter scripts"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Toggle alphabetical sorting of the method list."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Filter methods"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Sort"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Move Up"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Move Down"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Next script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Previous script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "File"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Reopen Closed Script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save All"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Soft Reload Script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Copy Script Path"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "History Previous"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "History Next"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Import Theme..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Reload Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close All"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close Docs"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
+msgid "Run"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Step Into"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Step Over"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Break"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Continue"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Keep Debugger Open"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Debug with External Editor"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open Godot online documentation."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search the reference documentation."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Go to previous edited document."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Go to next edited document."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Discard"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Debugger"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search Results"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Clear Recent Scripts"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Connections to method:"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
+msgid "Source"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Target"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid ""
+"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "[Ignore]"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Function"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Only resources from filesystem can be dropped."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't drop nodes because script '%s' is not used in this scene."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Lookup Symbol"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Pick Color"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Convert Case"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Uppercase"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Lowercase"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Capitalize"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Syntax Highlighter"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+msgid "Bookmarks"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Breakpoints"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+msgid "Go To"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Cut"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
+#: scene/gui/text_edit.cpp
+msgid "Select All"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Delete Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Indent Left"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Indent Right"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Toggle Comment"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Fold/Unfold Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Fold All Lines"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Unfold All Lines"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Clone Down"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Complete Symbol"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Evaluate Selection"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Trim Trailing Whitespace"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Convert Indent to Spaces"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Convert Indent to Tabs"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Auto Indent"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Find in Files..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Contextual Help"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Toggle Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Next Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Previous Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Remove All Bookmarks"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Function..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Line..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Toggle Breakpoint"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Remove All Breakpoints"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Next Breakpoint"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Previous Breakpoint"
+msgstr ""
+
+#: editor/plugins/shader_editor_plugin.cpp
+msgid ""
+"This shader has been modified on on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Shader"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "This skeleton has no bones, create some children Bone2D nodes."
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Create Rest Pose from Bones"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Set Rest Pose to Bones"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Skeleton2D"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Make Rest Pose (From Bones)"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Set Bones to Rest Pose"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Create physical bones"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Skeleton"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Create physical skeleton"
+msgstr ""
+
+#: editor/plugins/skeleton_ik_editor_plugin.cpp
+msgid "Play IK"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Orthogonal"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Perspective"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Aborted."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "X-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Y-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Z-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Plane Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scaling: "
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translating: "
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotating %s degrees."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Keying is disabled (no key inserted)."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Animation Key Inserted."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Pitch"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Yaw"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Size"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Objects Drawn"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Material Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Shader Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Surface Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Draw Calls"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Vertices"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Top View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Align Transform with View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Align Rotation with View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "No parent to instance a child at."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "This operation requires a single selected node."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Auto Orthogonal Enabled"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock View Rotation"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Normal"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Wireframe"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Overdraw"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Unshaded"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Environment"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Gizmos"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Information"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View FPS"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Half Resolution"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Audio Listener"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Enable Doppler"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Cinematic Preview"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Not available when using the GLES2 renderer."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Left"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Right"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Forward"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Backwards"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Up"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Down"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Speed Modifier"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Slow Modifier"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Rotation Locked"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Note: The FPS value displayed is the editor's framerate.\n"
+"It cannot be used as a reliable indication of in-game performance."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "XForm Dialog"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Click to toggle between visibility states.\n"
+"\n"
+"Open eye: Gizmo is visible.\n"
+"Closed eye: Gizmo is hidden.\n"
+"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Nodes To Floor"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Couldn't find a solid floor to snap the selection to."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Drag: Rotate\n"
+"Alt+Drag: Move\n"
+"Alt+RMB: Depth list selection"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Use Local Space"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Use Snap"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Top View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Switch Perspective/Orthogonal View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Insert Animation Key"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Focus Origin"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Focus Selection"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Toggle Freelook"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Object to Floor"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Dialog..."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "1 Viewport"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "2 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "2 Viewports (Alt)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "3 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "3 Viewports (Alt)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "4 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Gizmos"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Origin"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Grid"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Settings..."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Settings"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translate Snap:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate Snap (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale Snap (%):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Viewport Settings"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Perspective FOV (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Z-Near:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Z-Far:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Change"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translate:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale (ratio):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Type"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Pre"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Post"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Nameless gizmo"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create Mesh2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Mesh2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create Polygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Polygon2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create CollisionPolygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "CollisionPolygon2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create LightOccluder2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "LightOccluder2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Sprite is empty!"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Can't convert a sprite using animation frames to mesh."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't replace by mesh."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Convert to Mesh2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create polygon."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Convert to Polygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create collision polygon."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create CollisionPolygon2D Sibling"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create light occluder."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create LightOccluder2D Sibling"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Sprite"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Simplification: "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Shrink (Pixels): "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Grow (Pixels): "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Update Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Settings:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "No Frames Selected"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add %d Frame(s)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Unable to load images"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "ERROR: Couldn't load frame resource!"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Resource clipboard is empty or not a texture!"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Paste Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Empty"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Change Animation FPS"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "(empty)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Animations:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "New Animation"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Speed:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Loop"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Animation Frames:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add a Texture from File"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Frames from a Sprite Sheet"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Insert Empty (Before)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Insert Empty (After)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move (Before)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move (After)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Select Frames"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Horizontal:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Vertical:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Select/Clear All Frames"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Create Frames from Sprite Sheet"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "SpriteFrames"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Set Region Rect"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Set Margin"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Snap Mode:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: scene/resources/visual_shader.cpp
+msgid "None"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Pixel Snap"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Grid Snap"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Auto Slice"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Offset:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Step:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Sep.:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "TextureRegion"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add All Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add All"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove All Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp editor/project_manager.cpp
+msgid "Remove All"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Edit Theme"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme editing menu."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add Class Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove Class Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create Empty Template"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create Empty Editor Template"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create From Current Editor Theme"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Toggle Button"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled Button"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Check Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Checked Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Radio Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Checked Radio Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Named Sep."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Submenu"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subitem 1"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subitem 2"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Has"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Many"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled LineEdit"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 1"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 2"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 3"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Editable Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subtree"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Has,Many,Options"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Data Type:"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Icon"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
+msgid "Style"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Font"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Color"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme File"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Erase Selection"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Fix Invalid Tiles"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cut Selection"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Paint TileMap"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Line Draw"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Bucket Fill"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Erase TileMap"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Find Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Transpose"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Disable Autotile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Enable Priority"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Filter tiles"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Give a TileSet resource to this TileMap to use its tiles."
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Paint Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid ""
+"Shift+LMB: Line Draw\n"
+"Shift+Command+LMB: Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid ""
+"Shift+LMB: Line Draw\n"
+"Shift+Ctrl+LMB: Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Pick Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rotate Left"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rotate Right"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Flip Horizontally"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Flip Vertically"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Clear Transform"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Add Texture(s) to TileSet."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove selected Texture from TileSet."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create from Scene"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Merge from Scene"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Single Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Autotile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Atlas"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Next Coordinate"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Select the next shape, subtile, or Tile."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Previous Coordinate"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Select the previous shape, subtile, or Tile."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Region"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Collision"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Occlusion"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Navigation"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Priority"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Z Index"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Region Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Collision Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Occlusion Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Navigation Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Bitmask Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Priority Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Icon Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Z Index Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Copy bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Paste bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Erase bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create a new rectangle."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Rectangle"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create a new polygon."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete Selected Shape"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Keep polygon inside region Rect."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Enable snap and show grid (configurable via the Inspector)."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Display Tile Names (Hold Alt Key)"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Add or select a texture on the left panel to edit the tiles bound to it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove selected texture? This will remove all tiles which use it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "You haven't selected a texture to remove."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create from scene? This will overwrite all current tiles."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Merge from scene?"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Texture"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "%s file(s) were not added because was already on the list."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Drag handles to edit Rect.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete selected Rect."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select current edited sub-tile.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete polygon."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"LMB: Set bit on.\n"
+"RMB: Set bit off.\n"
+"Shift+LMB: Set wildcard bit.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to use as icon, this will be also used on invalid autotile "
+"bindings.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to change its priority.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to change its z index.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Set Tile Region"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Set Tile Icon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Paste Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Clear Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Polygon Concave"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Polygon Convex"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Priority"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Z Index"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Convex"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Concave"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "This property can't be changed."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "TileSet"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No VCS addons are available."
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Error"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No files added to stage"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Commit"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "VCS Addon is not initialized"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Version Control System"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Initialize"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Staging area"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Detect new changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Modified"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Renamed"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Deleted"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Typechange"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Stage Selected"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Stage All"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Commit Changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Status"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "View file diffs before committing them to the latest version"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No file diff is active"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Detect changes in file diff"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(GLES3 only)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Output"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sampler"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add input port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add output port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change input port type"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change output port type"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change input port name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change output port name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Remove input port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Remove output port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set expression"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Resize VisualShader node"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set Uniform Name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set Input Default Port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Node to Visual Shader"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Node(s) Moved"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Duplicate Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Paste Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Delete Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Visual Shader Input Type Changed"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "UniformRef Name Changed"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vertex"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Fragment"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Light"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Show resulted shader code."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Create Shader Node"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Grayscale function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts HSV vector to RGB equivalent."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts RGB vector to HSV equivalent."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sepia function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Burn operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Darken operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Difference operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Dodge operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "HardLight operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Lighten operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Overlay operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Screen operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "SoftLight operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the boolean result of the %s comparison between two parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Equal (==)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Greater Than (>)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Greater Than or Equal (>=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated vector if the provided scalars are equal, greater or "
+"less."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between INF and a scalar "
+"parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between NaN and a scalar "
+"parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Less Than (<)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Less Than or Equal (<=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Not Equal (!=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated vector if the provided boolean value is true or false."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated scalar if the provided boolean value is true or false."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the boolean result of the comparison between two parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between INF (or NaN) and a "
+"scalar parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for all shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Input parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex and fragment shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for fragment and light shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for fragment shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for light shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex and fragment shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "E constant (2.718282). Represents the base of the natural logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Epsilon constant (0.00001). Smallest possible scalar number."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Phi constant (1.618034). Golden ratio."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi/4 constant (0.785398) or 45 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi/2 constant (1.570796) or 90 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi constant (3.141593) or 180 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Tau constant (6.283185) or 360 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sqrt2 constant (1.414214). Square root of 2."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the absolute value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-tangent of the parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Finds the nearest integer that is greater than or equal to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Constrains a value to lie between two further values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts a quantity in radians to degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-e Exponential."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-2 Exponential."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest integer less than or equal to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Computes the fractional part of the argument."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse of the square root of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Natural logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-2 logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the greater of two values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the lesser of two values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the opposite value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 - scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the value of the first parameter raised to the power of the second."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts a quantity in degrees to radians."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 / scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest integer to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest even integer to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Clamps the value between 0.0 and 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Extracts the sign of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the square root of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( scalar(edge), scalar(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the truncated value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Adds scalar to scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Divides scalar by scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies scalar by scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the remainder of the two scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Subtracts scalar from scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Perform the cubic texture lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Perform the texture lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Cubic texture uniform lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "2D texture uniform lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "2D texture uniform lookup with triplanar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Calculate the outer product of a pair of vectors.\n"
+"\n"
+"OuterProduct treats the first parameter 'c' as a column vector (matrix with "
+"one column) and the second parameter 'r' as a row vector (matrix with one "
+"row) and does a linear algebraic matrix multiply 'c * r', yielding a matrix "
+"whose number of rows is the number of components in 'c' and whose number of "
+"columns is the number of components in 'r'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Composes transform from four vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Decomposes transform to four vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the determinant of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the inverse of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the transpose of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies transform by transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies vector by transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Composes vector from three scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Decomposes vector to three scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the cross product of two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the distance between two points."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the dot product of two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the vector that points in the same direction as a reference vector. "
+"The function has three vector parameters : N, the vector to orient, I, the "
+"incident vector, and Nref, the reference vector. If the dot product of I and "
+"Nref is smaller than zero the return value is N. Otherwise -N is returned."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the length of a vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two vectors using scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the normalize product of vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 - vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 / vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the vector that points in the direction of reflection ( a : incident "
+"vector, b : normal vector )."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the vector that points in the direction of refraction."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( vector(edge), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( scalar(edge), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Adds vector to vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Divides vector by vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies vector by vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the remainder of the two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Subtracts vector from vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Custom Godot Shader Language expression, with custom amount of input and "
+"output ports. This is a direct injection of code into the vertex/fragment/"
+"light function, do not use it to write the function declarations inside."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns falloff based on the dot product of surface normal and view "
+"direction of camera (pass associated inputs to it)."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Custom Godot Shader Language expression, which is placed on top of the "
+"resulted shader. You can place various function definitions inside and call "
+"it later in the Expressions. You can also declare varyings, uniforms and "
+"constants."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "A reference to an existing uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(Fragment/Light mode only) Scalar derivative function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(Fragment/Light mode only) Vector derivative function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Derivative in 'x' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Derivative in 'x' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Derivative in 'y' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Derivative in 'y' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and "
+"'y'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and "
+"'y'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "VisualShader"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Edit Visual Property"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Visual Shader Mode Changed"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Runnable"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Delete preset '%s'?"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Failed to export the project for platform '%s'.\n"
+"Export templates seem to be missing or invalid."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Failed to export the project for platform '%s'.\n"
+"This might be due to a configuration issue in the export preset or your "
+"export settings."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Release"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Exporting All"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "The given export path doesn't exist:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export templates for this platform are missing/corrupted:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Presets"
+msgstr ""
+
+#: editor/project_export.cpp editor/project_settings_editor.cpp
+msgid "Add..."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"If checked, the preset will be available for use in one-click deploy.\n"
+"Only one preset per platform may be marked as runnable."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Path"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Resources"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export all resources in the project"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export selected scenes (and dependencies)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export selected resources (and dependencies)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Mode:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Resources to export:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Filters to export non-resource files/folders\n"
+"(comma-separated, e.g: *.json, *.txt, docs/*)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Filters to exclude files/folders from project\n"
+"(comma-separated, e.g: *.json, *.txt, docs/*)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Features"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Custom (comma-separated):"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Feature List:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script Export Mode:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Text"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Compiled"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Encrypted (Provide Key Below)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Invalid Encryption Key (must be 64 characters long)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script Encryption Key (256-bits as hex):"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export PCK/Zip"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Project"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export mode?"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export All"
+msgstr ""
+
+#: editor/project_export.cpp editor/project_manager.cpp
+msgid "ZIP File"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Godot Game Pack"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export templates for this platform are missing:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Manage Export Templates"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export With Debug"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "The path specified doesn't exist."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Error opening package file (it's not in ZIP format)."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Please choose an empty folder."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Please choose a \"project.godot\" or \".zip\" file."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "This directory already contains a Godot project."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "New Game Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Imported Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Invalid Project Name."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't create folder."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "There is already a folder in this path with the specified name."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "It would be a good idea to name your project."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Invalid project path (changed anything?)."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Couldn't load project.godot in project path (error %d). It may be missing or "
+"corrupted."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't edit project.godot in project path."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't create project.godot in project path."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Rename Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Import Existing Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Import & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Create New Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Create & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Install Project:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Install & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Name:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Path:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Installation Path:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Renderer:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "OpenGL ES 3.0"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Not supported by your GPU drivers."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Higher visual quality\n"
+"All features available\n"
+"Incompatible with older hardware\n"
+"Not recommended for web games"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "OpenGL ES 2.0"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Lower visual quality\n"
+"Some features not available\n"
+"Works on most hardware\n"
+"Recommended for web games"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Renderer can be changed later, but scenes may need to be adjusted."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Unnamed Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Missing Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Error: Project is missing on the filesystem."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Can't open project at '%s'."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Are you sure to open more than one project?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The following project settings file does not specify the version of Godot "
+"through which it was created.\n"
+"\n"
+"%s\n"
+"\n"
+"If you proceed with opening it, it will be converted to Godot's current "
+"configuration file format.\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The following project settings file was generated by an older engine "
+"version, and needs to be converted for this version:\n"
+"\n"
+"%s\n"
+"\n"
+"Do you want to convert it?\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The project settings were created by a newer engine version, whose settings "
+"are not compatible with this version."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Can't run project: no main scene defined.\n"
+"Please edit the project and set the main scene in the Project Settings under "
+"the \"Application\" category."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Can't run project: Assets need to be imported.\n"
+"Please edit the project to trigger the initial import."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Are you sure to run %d projects at once?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove %d projects from the list?\n"
+"The project folders' contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove this project from the list?\n"
+"The project folder's contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove all missing projects from the list?\n"
+"The project folders' contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Language changed.\n"
+"The interface will update after restarting the editor or project manager."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Are you sure to scan %s folders for existing Godot projects?\n"
+"This could take a while."
+msgstr ""
+
+#. TRANSLATORS: This refers to the application where users manage their Godot projects.
+#: editor/project_manager.cpp
+msgid "Project Manager"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Projects"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Last Modified"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Scan"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Select a Folder to Scan"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "New Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Remove Missing"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Templates"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Restart Now"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Can't run project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"You currently don't have any projects.\n"
+"Would you like to explore official example projects in the Asset Library?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The search box filters projects by name and last path component.\n"
+"To filter projects by name and full path, the query must contain at least "
+"one `/` character."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Key "
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joy Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joy Axis"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Mouse Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid ""
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
+"'\"'"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "An action with the name '%s' already exists."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Rename Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Change Action deadzone"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "All Devices"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Device"
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Press a Key..."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Mouse Button Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Left Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Right Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Middle Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Up Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Down Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Left Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Right Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "X Button 1"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "X Button 2"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joypad Axis Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Axis"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joypad Button Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Erase Input Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Erase Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Left Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Right Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Middle Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Up."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Down."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Global Property"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Select a setting item first!"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "No property '%s' exists."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Setting '%s' is internal, and it can't be deleted."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Delete Item"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid ""
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
+"'\"'."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Input Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Error saving settings."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Settings saved OK."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Moved Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Override for Feature"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Translation"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Translation"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Remapped Path"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Resource Remap Add Remap"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Change Resource Remap Language"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Resource Remap"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Resource Remap Option"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Changed Locale Filter"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Changed Locale Filter Mode"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Project Settings (project.godot)"
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "General"
+msgstr "Төп"
+
+#: editor/project_settings_editor.cpp
+msgid "Override For..."
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "The editor must be restarted for changes to take effect."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Input Map"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Action:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Deadzone"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Device:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Localization"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Translations"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Translations:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remaps"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Resources:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remaps by Locale:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locale"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locales Filter"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Show All Locales"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Show Selected Locales Only"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Filter mode:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locales:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "AutoLoad"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Plugins"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Preset..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Zero"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Easing In-Out"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Easing Out-In"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "File..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Dir..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Assign"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Select Node"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Error loading file: Not a resource!"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Pick a Node"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Bit %d, val %d."
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Property"
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Virtual Method"
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Method"
+msgstr ""
+
+#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Batch Rename"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Replace:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Prefix:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Suffix:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Use Regular Expressions"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Advanced Options"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Substitute"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node's parent name, if available"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node type"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Current scene name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Root node name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid ""
+"Sequential integer counter.\n"
+"Compare counter options."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Per-level Counter"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "If set, the counter restarts for each group of child nodes."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Initial value for the counter"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Step"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Amount by which counter is incremented for each node"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Padding"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid ""
+"Minimum number of digits for the counter.\n"
+"Missing digits are padded with leading zeros."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Post-Process"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Keep"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "PascalCase to snake_case"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "snake_case to PascalCase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Case"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "To Lowercase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "To Uppercase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Reset"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Regular Expression Error:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "At character %s"
+msgstr ""
+
+#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Reparent Node"
+msgstr ""
+
+#: editor/reparent_dialog.cpp
+msgid "Reparent Location (Select new Parent):"
+msgstr ""
+
+#: editor/reparent_dialog.cpp
+msgid "Keep Global Transform"
+msgstr ""
+
+#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Reparent"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Run Mode:"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Current Scene"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Main Scene"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Main Scene Arguments:"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Scene Run Settings"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "No parent to instance the scenes at."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error loading scene from %s"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Cannot instance the scene '%s' because the current scene exists within one "
+"of its nodes."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instance Scene(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Replace with Branch Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instance Child Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Detach Script"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "This operation can't be done on the tree root."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Move Node In Parent"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Move Nodes In Parent"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Duplicate Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't reparent nodes in inherited scenes, order of nodes can't change."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Node must belong to the edited scene to become root."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instantiated scenes can't become root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make node as Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete %d nodes and any children?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete %d nodes?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete the root node \"%s\"?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete node \"%s\" and its children?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete node \"%s\"?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can not perform with the root node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "This operation can't be done on instanced scenes."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Save New Scene As..."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Disabling \"editable_instance\" will cause all properties of the node to be "
+"reverted to their default."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Enabling \"Load As Placeholder\" will disable \"Editable Children\" and "
+"cause all properties of the node to be reverted to their default."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make Local"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "New Scene Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Create Root Node:"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "2D Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "3D Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "User Interface"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Other Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't operate on nodes from a foreign scene!"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't operate on nodes the current scene inherits from!"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Attach Script"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Remove Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Change type of node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Couldn't save new scene. Likely dependencies (instances) couldn't be "
+"satisfied."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error saving scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error duplicating scene to save it."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Sub-Resources"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Clear Inheritance"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Editable Children"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Load As Placeholder"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Open Documentation"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Cannot attach a script: there are no languages registered.\n"
+"This is probably because this editor was built with all language modules "
+"disabled."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Add Child Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Expand/Collapse All"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Change Type"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Reparent to New Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make Scene Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Merge From Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
+msgid "Save Branch as Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
+msgid "Copy Node Path"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete (No Confirm)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Add/Create a New Node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Instance a scene file as a Node. Creates an inherited scene if no root node "
+"exists."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Attach a new or existing script to the selected node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Detach the script from the selected node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Remote"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Local"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Clear Inheritance? (No Undo!)"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Toggle Visible"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Unlock Node"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Button Group"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "(Connecting From)"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Node configuration warning:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node has %s connection(s) and %s group(s).\n"
+"Click to show signals dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node has %s connection(s).\n"
+"Click to show signals dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node is in %s group(s).\n"
+"Click to show groups dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Open Script:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node is locked.\n"
+"Click to unlock it."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Children are not selectable.\n"
+"Click to make selectable."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Toggle Visibility"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"AnimationPlayer is pinned.\n"
+"Click to unpin."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Invalid node name, the following characters are not allowed:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Rename Node"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Scene Tree (Nodes):"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Node Configuration Warning!"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Select a Node"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Path is empty."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Filename is empty."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Path is not local."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid base path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "A directory with the same name exists."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "File does not exist."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid extension."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Wrong extension chosen."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error loading template '%s'"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error - Could not create script in filesystem."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error loading script from %s"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Overrides"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "N/A"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Open Script / Choose Location"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Open Script"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "File exists, it will be reused."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid class name."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid inherited parent name or path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Script path/name is valid."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Allowed: a-z, A-Z, 0-9, _ and ."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Built-in script (into scene file)."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Will create a new script file."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Will load an existing script file."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Script file already exists."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid ""
+"Note: Built-in scripts have some limitations and can't be edited using an "
+"external editor."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Class Name:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Template:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Built-in Script:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Attach Node Script"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Remote "
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Bytes:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Warning:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Error:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Error"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Error:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Source"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Source:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Source:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Stack Trace"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Errors"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Child process connected."
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Copy Error"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Video RAM"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Skip Breakpoints"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Inspect Previous Instance"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Inspect Next Instance"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Stack Frames"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Profiler"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Network Profiler"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Monitor"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Value"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Monitors"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Pick one or more items from the list to display the graph."
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "List of Video Memory Usage by Resource:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Total:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Export list to a CSV file"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Resource Path"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Type"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Format"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Usage"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Misc"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Clicked Control:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Clicked Control Type:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Live Edit Root:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Set From Tree"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Export measures as CSV"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Erase Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Restore Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Change Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Editor Settings"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Shortcuts"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Binding"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Light Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change AudioStreamPlayer3D Emission Angle"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Camera FOV"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Camera Size"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Notifier AABB"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Particles AABB"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Probe Extents"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
+msgid "Change Sphere Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
+msgid "Change Box Shape Extents"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Capsule Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Capsule Shape Height"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Cylinder Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Cylinder Shape Height"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Ray Shape Length"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Cylinder Radius"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Cylinder Height"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Torus Inner Radius"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Torus Outer Radius"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Select the dynamic library for this entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Select dependencies of the library for this entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Remove current entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Double click to create a new entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Platform:"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Platform"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Dynamic Library"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Add an architecture entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "GDNativeLibrary"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Enabled GDNative Singleton"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Disabled GDNative Singleton"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Library"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Libraries: "
+msgstr ""
+
+#: modules/gdnative/register_types.cpp
+msgid "GDNative"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Step argument is zero!"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not a script with an instance"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not based on a script"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not based on a resource file"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (missing @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (can't load script at @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (invalid script at @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary (invalid subclasses)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Object can't provide a length."
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Next Plane"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Previous Plane"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Plane:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Next Floor"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Previous Floor"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Floor:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Delete Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Fill Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Paste Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Paint"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Grid Map"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Snap View"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Disabled"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Above"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Below"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit X Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit Y Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit Z Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate X"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate Y"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate Z"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate X"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate Y"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate Z"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Clear Rotation"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Paste Selects"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clear Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Fill Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Settings"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Pick Distance:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Filter meshes"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Give a MeshLibrary resource to this GridMap to use its meshes."
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Begin Bake"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Preparing data structures"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Generate buffers"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Direct lighting"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Indirect lighting"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Post processing"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Plotting lightmaps"
+msgstr ""
+
+#: modules/mono/csharp_script.cpp
+msgid "Class name can't be a reserved keyword"
+msgstr ""
+
+#: modules/mono/mono_gd/gd_mono_utils.cpp
+msgid "End of inner exception stack trace"
+msgstr ""
+
+#: modules/recast/navigation_mesh_editor_plugin.cpp
+msgid "Bake NavMesh"
+msgstr ""
+
+#: modules/recast/navigation_mesh_editor_plugin.cpp
+msgid "Clear the navigation mesh."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Setting up Configuration..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Calculating grid size..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating heightfield..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Marking walkable triangles..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Constructing compact heightfield..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Eroding walkable area..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Partitioning..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating contours..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating polymesh..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Converting to native navigation mesh..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Navigation Mesh Generator Setup:"
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Parsing Geometry..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Done!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"A node yielded without working memory, please read the docs on how to yield "
+"properly!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"Node yielded, but did not return a function state in the first working "
+"memory."
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"Return value must be assigned to first element of node working memory! Fix "
+"your node please."
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Node returned an invalid sequence output: "
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Found sequence bit but not the node in the stack, report bug!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Stack overflow with stack depth: "
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Signal Arguments"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Argument Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Argument name"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Set Variable Default Value"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Set Variable Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Input Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Output Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Override an existing built-in function."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new function."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Variables:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new variable."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Signals:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new signal."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Name is not a valid identifier:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Name already in use by another func/var/signal:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Delete input port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Input Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Output Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Expression"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Duplicate VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a simple reference to the node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a simple reference to the node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a Variable Setter."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a Variable Setter."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Preload Node"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Node(s) From Tree"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid ""
+"Can't drop properties because script '%s' is not used in this scene.\n"
+"Drop holding 'Shift' to just copy the signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Getter Property"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Setter Property"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Base Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Move Node(s)"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove VisualScript Node"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Disconnect Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Node Data"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Node Sequence"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Script already has function '%s'"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Input Value"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Resize Comment"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't copy the function node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Clipboard is empty!"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Paste VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't create function with a function node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't create function of nodes from nodes of multiple functions."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Select at least one node with sequence port."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Try to only have one sequence input in selection."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Editing Variable:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Editing Signal:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Make Tool:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Members:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Base Type:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Nodes..."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Function..."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "function_name"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Select or create a function to edit its graph."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Delete Selected"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Find Node Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Copy Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Cut Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Make Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Refresh Graph"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Edit Member"
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Input type not iterable: "
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Iterator became invalid"
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Iterator became invalid: "
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Invalid index property name."
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Base object is not a Node!"
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Path does not lead Node!"
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Invalid index property name '%s' in node %s."
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ": Invalid argument of type: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ": Invalid arguments: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "VariableGet not found in script: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "VariableSet not found in script: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "Custom node has no _step() method, can't process graph."
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ""
+"Invalid return value from _step(), must be integer (seq out), or string "
+"(error)."
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Search VisualScript"
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Get %s"
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Set %s"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Package name is missing."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Package segments must be of non-zero length."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The character '%s' is not allowed in Android application package names."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "A digit cannot be the first character in a package segment."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The character '%s' cannot be the first character in a package segment."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The package must have at least one '.' separator."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Select device from the list"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find the 'apksigner' tool."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Android build template not installed in the project. Install it from the "
+"Project menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Debug keystore not configured in the Editor Settings nor in the preset."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Release keystore incorrectly configured in the export preset."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "A valid Android SDK path is required in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid Android SDK path in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Missing 'platform-tools' directory!"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find Android SDK platform-tools' adb command."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Please check in the Android SDK directory specified in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Missing 'build-tools' directory!"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find Android SDK build-tools' apksigner command."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid public key for APK expansion."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid package name:"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
+"project setting (changed in Godot 3.2.2).\n"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "\"Use Custom Build\" must be enabled to use the plugins."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
+"\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid filename! Android App Bundle requires the *.aab extension."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "APK Expansion not compatible with Android App Bundle."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid filename! Android APK requires the *.apk extension."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Trying to build from a custom built template, but no version info for it "
+"exists. Please reinstall from the 'Project' menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Android build version mismatch:\n"
+" Template installed: %s\n"
+" Godot Version: %s\n"
+"Please reinstall Android build template from 'Project' menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Building Android Project (gradle)"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Building of Android project failed, check output for the error.\n"
+"Alternatively visit docs.godotengine.org for Android build documentation."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Moving output"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Unable to copy and rename export file, check gradle project directory for "
+"outputs."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Identifier is missing."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "The character '%s' is not allowed in Identifier."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "App Store Team ID not specified - cannot configure the project."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Invalid Identifier:"
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Required icon is not specified in the preset."
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Stop HTTP Server"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Run in Browser"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Run exported HTML in the system's default browser."
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not write file:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not open template for export:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Invalid export template:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not read custom HTML shell:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not read boot splash image file:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Using default boot splash image."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package short name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package unique name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package publisher display name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid product GUID."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid publisher GUID."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid background color."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid Store Logo image dimensions (should be 50x50)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 44x44 logo image dimensions (should be 44x44)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 71x71 logo image dimensions (should be 71x71)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 150x150 logo image dimensions (should be 150x150)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 310x310 logo image dimensions (should be 310x310)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid wide 310x150 logo image dimensions (should be 310x150)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid splash screen image dimensions (should be 620x300)."
+msgstr ""
+
+#: scene/2d/animated_sprite.cpp
+msgid ""
+"A SpriteFrames resource must be created or set in the \"Frames\" property in "
+"order for AnimatedSprite to display frames."
+msgstr ""
+
+#: scene/2d/canvas_modulate.cpp
+msgid ""
+"Only one visible CanvasModulate is allowed per scene (or set of instanced "
+"scenes). The first created one will work, while the rest will be ignored."
+msgstr ""
+
+#: scene/2d/collision_object_2d.cpp
+msgid ""
+"This node has no shape, so it can't collide or interact with other objects.\n"
+"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to "
+"define its shape."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid ""
+"CollisionPolygon2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "An empty CollisionPolygon2D has no effect on collision."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"CollisionShape2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"A shape must be provided for CollisionShape2D to function. Please create a "
+"shape resource for it!"
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"Polygon-based shapes are not meant be used nor edited directly through the "
+"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
+msgstr ""
+
+#: scene/2d/cpu_particles_2d.cpp
+msgid ""
+"CPUParticles2D animation requires the usage of a CanvasItemMaterial with "
+"\"Particles Animation\" enabled."
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A and Node B must be PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A must be a PhysicsBody2D"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node B must be a PhysicsBody2D"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Joint is not connected to two PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A and Node B must be different PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/light_2d.cpp
+msgid ""
+"A texture with the shape of the light must be supplied to the \"Texture\" "
+"property."
+msgstr ""
+
+#: scene/2d/light_occluder_2d.cpp
+msgid ""
+"An occluder polygon must be set (or drawn) for this occluder to take effect."
+msgstr ""
+
+#: scene/2d/light_occluder_2d.cpp
+msgid "The occluder polygon for this occluder is empty. Please draw a polygon."
+msgstr ""
+
+#: scene/2d/navigation_polygon.cpp
+msgid ""
+"A NavigationPolygon resource must be set or created for this node to work. "
+"Please set a property or draw a polygon."
+msgstr ""
+
+#: scene/2d/navigation_polygon.cpp
+msgid ""
+"NavigationPolygonInstance must be a child or grandchild to a Navigation2D "
+"node. It only provides navigation data."
+msgstr ""
+
+#: scene/2d/parallax_layer.cpp
+msgid ""
+"ParallaxLayer node only works when set as child of a ParallaxBackground node."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp
+msgid ""
+"GPU-based particles are not supported by the GLES2 video driver.\n"
+"Use the CPUParticles2D node instead. You can use the \"Convert to "
+"CPUParticles\" option for this purpose."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp scene/3d/particles.cpp
+msgid ""
+"A material to process the particles is not assigned, so no behavior is "
+"imprinted."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp
+msgid ""
+"Particles2D animation requires the usage of a CanvasItemMaterial with "
+"\"Particles Animation\" enabled."
+msgstr ""
+
+#: scene/2d/path_2d.cpp
+msgid "PathFollow2D only works when set as a child of a Path2D node."
+msgstr ""
+
+#: scene/2d/physics_body_2d.cpp
+msgid ""
+"Size changes to RigidBody2D (in character or rigid modes) will be overridden "
+"by the physics engine when running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/2d/remote_transform_2d.cpp
+msgid "Path property must point to a valid Node2D node to work."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid "This Bone2D chain should end at a Skeleton2D node."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid "A Bone2D only works with a Skeleton2D or another Bone2D as parent node."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid ""
+"This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."
+msgstr ""
+
+#: scene/2d/tile_map.cpp
+msgid ""
+"TileMap with Use Parent on needs a parent CollisionObject2D to give shapes "
+"to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, "
+"KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/visibility_notifier_2d.cpp
+msgid ""
+"VisibilityEnabler2D works best when used with the edited scene root directly "
+"as parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRCamera must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRController must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid ""
+"The controller ID must not be 0 or this controller won't be bound to an "
+"actual controller."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRAnchor must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid ""
+"The anchor ID must not be 0 or this anchor won't be bound to an actual "
+"anchor."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVROrigin requires an ARVRCamera child node."
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Finding meshes and lights"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Preparing geometry (%d/%d)"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Preparing environment"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Generating capture"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Saving lightmaps"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Done"
+msgstr ""
+
+#: scene/3d/collision_object.cpp
+msgid ""
+"This node has no shape, so it can't collide or interact with other objects.\n"
+"Consider adding a CollisionShape or CollisionPolygon as a child to define "
+"its shape."
+msgstr ""
+
+#: scene/3d/collision_polygon.cpp
+msgid ""
+"CollisionPolygon only serves to provide a collision shape to a "
+"CollisionObject derived node. Please only use it as a child of Area, "
+"StaticBody, RigidBody, KinematicBody, etc. to give them a shape."
+msgstr ""
+
+#: scene/3d/collision_polygon.cpp
+msgid "An empty CollisionPolygon has no effect on collision."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"CollisionShape only serves to provide a collision shape to a CollisionObject "
+"derived node. Please only use it as a child of Area, StaticBody, RigidBody, "
+"KinematicBody, etc. to give them a shape."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"A shape must be provided for CollisionShape to function. Please create a "
+"shape resource for it."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"Plane shapes don't work well and will be removed in future versions. Please "
+"don't use them."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"ConcavePolygonShape doesn't support RigidBody in another mode than static."
+msgstr ""
+
+#: scene/3d/cpu_particles.cpp
+msgid "Nothing is visible because no mesh has been assigned."
+msgstr ""
+
+#: scene/3d/cpu_particles.cpp
+msgid ""
+"CPUParticles animation requires the usage of a SpatialMaterial whose "
+"Billboard Mode is set to \"Particle Billboard\"."
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid "Plotting Meshes"
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid "Finishing Plot"
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid ""
+"GIProbes are not supported by the GLES2 video driver.\n"
+"Use a BakedLightmap instead."
+msgstr ""
+
+#: scene/3d/light.cpp
+msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
+msgstr ""
+
+#: scene/3d/navigation_mesh.cpp
+msgid "A NavigationMesh resource must be set or created for this node to work."
+msgstr ""
+
+#: scene/3d/navigation_mesh.cpp
+msgid ""
+"NavigationMeshInstance must be a child or grandchild to a Navigation node. "
+"It only provides navigation data."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"GPU-based particles are not supported by the GLES2 video driver.\n"
+"Use the CPUParticles node instead. You can use the \"Convert to CPUParticles"
+"\" option for this purpose."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"Nothing is visible because meshes have not been assigned to draw passes."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"Particles animation requires the usage of a SpatialMaterial whose Billboard "
+"Mode is set to \"Particle Billboard\"."
+msgstr ""
+
+#: scene/3d/path.cpp
+msgid "PathFollow only works when set as a child of a Path node."
+msgstr ""
+
+#: scene/3d/path.cpp
+msgid ""
+"PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its "
+"parent Path's Curve resource."
+msgstr ""
+
+#: scene/3d/physics_body.cpp
+msgid ""
+"Size changes to RigidBody (in character or rigid modes) will be overridden "
+"by the physics engine when running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A and Node B must be PhysicsBodies"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A must be a PhysicsBody"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node B must be a PhysicsBody"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Joint is not connected to any PhysicsBodies"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A and Node B must be different PhysicsBodies"
+msgstr ""
+
+#: scene/3d/remote_transform.cpp
+msgid ""
+"The \"Remote Path\" property must point to a valid Spatial or Spatial-"
+"derived node to work."
+msgstr ""
+
+#: scene/3d/soft_body.cpp
+msgid "This body will be ignored until you set a mesh."
+msgstr ""
+
+#: scene/3d/soft_body.cpp
+msgid ""
+"Size changes to SoftBody will be overridden by the physics engine when "
+"running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/3d/sprite_3d.cpp
+msgid ""
+"A SpriteFrames resource must be created or set in the \"Frames\" property in "
+"order for AnimatedSprite3D to display frames."
+msgstr ""
+
+#: scene/3d/vehicle_body.cpp
+msgid ""
+"VehicleWheel serves to provide a wheel system to a VehicleBody. Please use "
+"it as a child of a VehicleBody."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"WorldEnvironment requires its \"Environment\" property to contain an "
+"Environment to have a visible effect."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set "
+"this environment's Background Mode to Canvas (for 2D scenes)."
+msgstr ""
+
+#: scene/animation/animation_blend_tree.cpp
+msgid "On BlendTree node '%s', animation not found: '%s'"
+msgstr ""
+
+#: scene/animation/animation_blend_tree.cpp
+msgid "Animation not found: '%s'"
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "In node '%s', invalid animation: '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Invalid animation: '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Nothing connected to input '%s' of node '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "No root AnimationNode for the graph is set."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Path to an AnimationPlayer node containing animations is not set."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Path set for AnimationPlayer does not lead to an AnimationPlayer node."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "The AnimationPlayer root node is not a valid node."
+msgstr ""
+
+#: scene/animation/animation_tree_player.cpp
+msgid "This node has been deprecated. Use AnimationTree instead."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid ""
+"Color: #%s\n"
+"LMB: Set color\n"
+"RMB: Remove preset"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Pick a color from the editor window."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "HSV"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Raw"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Switch between hexadecimal and code values."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Add current color as a preset."
+msgstr ""
+
+#: scene/gui/container.cpp
+msgid ""
+"Container by itself serves no purpose unless a script configures its "
+"children placement behavior.\n"
+"If you don't intend to add a script, use a plain Control node instead."
+msgstr ""
+
+#: scene/gui/control.cpp
+msgid ""
+"The Hint Tooltip won't be displayed as the control's Mouse Filter is set to "
+"\"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."
+msgstr ""
+
+#: scene/gui/dialogs.cpp
+msgid "Alert!"
+msgstr ""
+
+#: scene/gui/dialogs.cpp
+msgid "Please Confirm..."
+msgstr ""
+
+#: scene/gui/file_dialog.cpp
+msgid "Must use a valid extension."
+msgstr ""
+
+#: scene/gui/graph_edit.cpp
+msgid "Enable grid minimap."
+msgstr ""
+
+#: scene/gui/popup.cpp
+msgid ""
+"Popups will hide by default unless you call popup() or any of the popup*() "
+"functions. Making them visible for editing is fine, but they will hide upon "
+"running."
+msgstr ""
+
+#: scene/gui/range.cpp
+msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
+msgstr ""
+
+#: scene/gui/scroll_container.cpp
+msgid ""
+"ScrollContainer is intended to work with a single child control.\n"
+"Use a container as child (VBox, HBox, etc.), or a Control and set the custom "
+"minimum size manually."
+msgstr ""
+
+#: scene/gui/tree.cpp
+msgid "(Other)"
+msgstr ""
+
+#: scene/main/scene_tree.cpp
+msgid ""
+"Default Environment as specified in Project Settings (Rendering -> "
+"Environment -> Default Environment) could not be loaded."
+msgstr ""
+
+#: scene/main/viewport.cpp
+msgid ""
+"This viewport is not set as render target. If you intend for it to display "
+"its contents directly to the screen, make it a child of a Control so it can "
+"obtain a size. Otherwise, make it a RenderTarget and assign its internal "
+"texture to some node for display."
+msgstr ""
+
+#: scene/main/viewport.cpp
+msgid "Viewport size must be greater than 0 to render anything."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid ""
+"The sampler port is connected but not used. Consider changing the source to "
+"'SamplerPort'."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid source for preview."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid source for shader."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid comparison function for that type."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Assignment to function."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Assignment to uniform."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Varyings can only be assigned in vertex function."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Constants cannot be modified."
+msgstr ""
diff --git a/editor/translations/tzm.po b/editor/translations/tzm.po
index d13e2e5705..629220c426 100644
--- a/editor/translations/tzm.po
+++ b/editor/translations/tzm.po
@@ -1081,6 +1081,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2439,8 +2443,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2845,6 +2850,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9678,7 +9687,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11679,10 +11688,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/uk.po b/editor/translations/uk.po
index 1eed824645..67f369bb15 100644
--- a/editor/translations/uk.po
+++ b/editor/translations/uk.po
@@ -20,7 +20,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-31 03:53+0000\n"
+"PO-Revision-Date: 2021-05-18 14:51+0000\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot/uk/>\n"
@@ -30,7 +30,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.6-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1135,6 +1135,10 @@ msgstr "Змінити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñловника"
msgid "Thanks from the Godot community!"
msgstr "СпаÑибі від Ñпільноти Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Ðвтори Ñ€ÑƒÑˆÑ–Ñ Godot"
@@ -2557,11 +2561,13 @@ msgstr "Ðеможливо завантажити Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ ÑкриÐ
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"Ðеможливо завантажити Ñкрипт Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð· шлÑху «%s». ЗдаєтьÑÑ, у коді Ñ” "
-"помилка, будь лаÑка, перевірте ÑинтакÑиÑ."
+"Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ додатковий Ñкрипт з такою адреÑою: «%s». Причиною "
+"може бути помилка у коді цього Ñкрипту.\n"
+"Вимикаємо додаток у «%s», щоб запобігти подальшим помилкам."
#: editor/editor_node.cpp
msgid ""
@@ -3008,6 +3014,10 @@ msgid "About"
msgstr "Про"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "Підтримати розробку Godot"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "ЗапуÑтити проєкт."
@@ -7576,6 +7586,8 @@ msgstr "ÐžÐ±ÐµÑ€Ñ‚Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду заблоковано"
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
+"Ð”Ð»Ñ Ð¿Ð¾Ð´Ð°Ð»ÑŒÑˆÐ¾Ð³Ð¾ маÑÑˆÑ‚Ð°Ð±ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð¼Ñ–Ð½Ñ–Ñ‚ÑŒ площини Ð¾Ð±Ñ€Ñ–Ð·Ð°Ð½Ð½Ñ ÐºÐ°Ð¼ÐµÑ€Ð¸ (ПереглÑд -> "
+"Параметри...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -10160,7 +10172,7 @@ msgstr "Кнопка миші"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
"Ðекоректна назва дії. Ðазва не може бути порожньою Ñ– не може міÑтити "
@@ -10974,6 +10986,10 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"Якщо позначено, бічна панель ієрархії віддаленої Ñцени призупинÑтиме роботу "
+"проєкту під Ñ‡Ð°Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ Ñвого оновленнÑ.\n"
+"ПеремкнітьÑÑ Ð½Ð°Ð·Ð°Ð´ на бічну панель ієрархії локальної Ñцени, щоб пришвидшити "
+"роботу."
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12224,12 +12240,24 @@ msgstr ""
"допомогою меню «Проєкт»."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
"ÐÑ– у параметрах редактора, ні у шаблоні не налаштовано діагноÑтичне Ñховище "
"ключів."
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"У шаблоні екÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð¾ налаштовано Ñховище ключів випуÑку."
@@ -13217,6 +13245,19 @@ msgid "Constants cannot be modified."
msgstr "Сталі не можна змінювати."
#~ msgid ""
+#~ "Godot editor was built without ray tracing support; lightmaps can't be "
+#~ "baked.\n"
+#~ "If you are using an Apple Silicon-based Mac, try forcing Rosetta "
+#~ "emulation on Godot.app in the application settings\n"
+#~ "then restart the editor."
+#~ msgstr ""
+#~ "Редактор Godot було зібрано без підтримки траÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð¼ÐµÐ½Ñ–Ð²; мапи "
+#~ "оÑÐ²Ñ–Ñ‚Ð»ÐµÐ½Ð½Ñ Ñтворити не вдаÑтьÑÑ.\n"
+#~ "Якщо ви кориÑтуєтеÑÑ Mac на оÑнові Apple Silicon, Ñпробуйте примуÑово "
+#~ "вÑтановити емулÑцію Rosetta Ð´Ð»Ñ Godot.app у параметрах програми,\n"
+#~ "а потім перезапуÑтіть редактор."
+
+#~ msgid ""
#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
#~ msgstr ""
#~ "InterpolatedCamera вважаєтьÑÑ Ð·Ð°Ñтарілою, Ñ—Ñ— буде вилучено у Godot 4.0."
diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po
index 697cc3e5a4..3af1eac2ef 100644
--- a/editor/translations/ur_PK.po
+++ b/editor/translations/ur_PK.po
@@ -1101,6 +1101,10 @@ msgstr ""
msgid "Thanks from the Godot community!"
msgstr ""
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr ""
@@ -2489,8 +2493,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -2899,6 +2904,10 @@ msgid "About"
msgstr ""
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr ""
@@ -9927,7 +9936,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -11987,10 +11996,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/vi.po b/editor/translations/vi.po
index 74d8666e35..8a34f898b8 100644
--- a/editor/translations/vi.po
+++ b/editor/translations/vi.po
@@ -18,11 +18,13 @@
# LetterC67 <hoangdeptoong@gmail.com>, 2020, 2021.
# Rev <revolnoom7801@gmail.com>, 2021.
# SyliawDeV <thanhlongstranger@gmail.com>, 2021.
+# IoeCmcomc <hopdaigia2004@gmail.com>, 2021.
+# Hung <hungthitkhia@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"PO-Revision-Date: 2021-05-14 11:20+0000\n"
"Last-Translator: Rev <revolnoom7801@gmail.com>\n"
"Language-Team: Vietnamese <https://hosted.weblate.org/projects/godot-engine/"
"godot/vi/>\n"
@@ -904,7 +906,7 @@ msgstr "Bạn muốn xoá tất cả kết nối từ tín hiệu \"%s\"?"
#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
msgid "Signals"
-msgstr "Tín hiệu (Signal)"
+msgstr "Tín hiệu"
#: editor/connections_dialog.cpp
msgid "Filter signals"
@@ -936,7 +938,7 @@ msgstr "Äổi"
#: editor/create_dialog.cpp
msgid "Create New %s"
-msgstr "Tạo %s Mới"
+msgstr "Tạo %s mới"
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
@@ -1122,6 +1124,10 @@ msgstr "Äổi giá trị từ Ä‘iển"
msgid "Thanks from the Godot community!"
msgstr "Cảm ơn từ cộng đồng Godot!"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Cá nhân đóng góp của Godot Engine"
@@ -1316,7 +1322,7 @@ msgstr "Tắt tiếng"
#: editor/editor_audio_buses.cpp
msgid "Bypass"
-msgstr ""
+msgstr "Bá» qua"
#: editor/editor_audio_buses.cpp
msgid "Bus options"
@@ -1381,7 +1387,7 @@ msgstr "Không có tệp tin '%s'."
#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
msgid "Layout"
-msgstr "Bố trí"
+msgstr "Bố cục"
#: editor/editor_audio_buses.cpp
msgid "Invalid file, not an audio bus layout."
@@ -1467,7 +1473,7 @@ msgstr ""
#: editor/editor_autoload_settings.cpp
msgid "Move Autoload"
-msgstr ""
+msgstr "Di chuyển Tự nạp"
#: editor/editor_autoload_settings.cpp
msgid "Remove Autoload"
@@ -1620,16 +1626,15 @@ msgstr ""
"ETC2' hoặc 'Nhập Pvrtc' trong Cài đặt Dự án."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for the driver fallback "
"to GLES2.\n"
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
-"Ná»n tảng yêu cầu kiểu nén 'ETC' cho trình Ä‘iá»u khiển dá»± phòng GLES2.\n"
-"Chá»n kích hoạt 'Nhập ETC' trong Cài đặt Dá»± án, hoặc chá»n tắt 'Kích hoạt "
-"Trình Ä‘iá»u khiển Dá»± phòng'."
+"Ná»n tảng yêu cầu kiểu nén 'PVRTC' cho driver tương thích ngược GLES2.\n"
+"Chá»n kích hoạt 'Nhập PVRTC' trong Cài đặt Dá»± án, hoặc tắt 'Kích hoạt Driver "
+"Tương thích Ngược'."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -1649,7 +1654,7 @@ msgstr "Không tìm thấy tệp tin mẫu:"
#: editor/editor_export.cpp
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
-msgstr ""
+msgstr "Ở các bản xuất 32-bit thì PCK được nhúng vào không thể lớn hơn 4 GiB."
#: editor/editor_feature_profile.cpp
msgid "3D Editor"
@@ -1781,9 +1786,8 @@ msgid "Erase Profile"
msgstr "Xoá hồ sơ"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Godot Feature Profile"
-msgstr "Quản lý trình tính năng"
+msgstr "Quản lý Tính năng Godot"
#: editor/editor_feature_profile.cpp
msgid "Import Profile(s)"
@@ -1892,7 +1896,7 @@ msgstr "Bật tắt Chức năng"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
-msgstr "Tập trung ÄÆ°á»ng dẫn"
+msgstr "ÄÆ°á»ng dẫn Tập trung"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
@@ -1983,7 +1987,7 @@ msgstr "ÄÆ°á»£c thừa kế bởi:"
#: editor/editor_help.cpp
msgid "Description"
-msgstr "Mô tả"
+msgstr "Ná»™i dung"
#: editor/editor_help.cpp
msgid "Online Tutorials"
@@ -2007,11 +2011,11 @@ msgstr "Hàm"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr "Cài đặt Tông màu"
+msgstr "Thuá»™c tính Chá»§ Ä‘á»"
#: editor/editor_help.cpp
msgid "Enumerations"
-msgstr ""
+msgstr "Liệt kê"
#: editor/editor_help.cpp
msgid "Constants"
@@ -2019,7 +2023,7 @@ msgstr "Hằng số"
#: editor/editor_help.cpp
msgid "Property Descriptions"
-msgstr "Mô tả thuộc tính"
+msgstr "Nội dung Thuộc tính"
#: editor/editor_help.cpp
msgid "(value)"
@@ -2035,7 +2039,7 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Method Descriptions"
-msgstr "Mô tả hàm"
+msgstr "Nội dung Hàm"
#: editor/editor_help.cpp
msgid ""
@@ -2318,7 +2322,7 @@ msgid ""
"option and delete the Default layout."
msgstr ""
"Bố cục mặc định của trình chỉnh sửa đã bị ghi đè.\n"
-"Äể hồi lại bố cục mặc định vá» cài đặt gốc, sá»­ dụng tùy chá»n \"Xóa bố cục\" "
+"Äể khôi phục bố cục mặc định vá» cài đặt gốc, sá»­ dụng tùy chá»n \"Xóa bố cục\" "
"rồi xóa bố cục \"Mặc định\"."
#: editor/editor_node.cpp
@@ -2480,7 +2484,7 @@ msgstr "Có"
#: editor/editor_node.cpp
msgid "Exit the editor?"
-msgstr "Thoát trình biên tập?"
+msgstr "Thoát trình chỉnh sửa?"
#: editor/editor_node.cpp
msgid "Open Project Manager?"
@@ -2521,33 +2525,38 @@ msgstr "Mở lại Cảnh đã đóng"
#: editor/editor_node.cpp
msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr ""
+"Không thể kích hoạt plugin addon tại: '%s' phân tích thiết lập thất bại."
#: editor/editor_node.cpp
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr ""
+msgstr "Không thể tìm trưá»ng tập lệnh cá»§a plugin addon tại: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr "Không thể nạp tệp lệnh bổ trợ từ đưá»ng dẫn: '%s'."
+msgstr "Không thể tải tệp addon từ đưá»ng dẫn: '%s'."
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
-"Không thể nạp tệp lệnh bổ trợ từ đưá»ng dẫn: '%s' Có vẻ có lá»—i trong mã "
-"nguồn, hãy kiểm tra lại cú pháp."
+"Không thể nạp tệp lệnh bổ trợ từ đưá»ng dẫn: '%s' Có vẻ có lá»—i trong mã, hãy "
+"kiểm tra lại cú pháp."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
-"Không thể tải script addon từ đưá»ng dẫn: '%s' Kiểu gốc không phải "
+"Không thể tải tập lệnh addon từ đưá»ng dẫn: '%s' Kiểu gốc không phải "
"EditorPlugin."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
msgstr ""
+"Không thể tải script addon từ đưá»ng dẫn: '%s' Script không ở trong \"trạng "
+"thái công cụ\"."
#: editor/editor_node.cpp
msgid ""
@@ -2790,9 +2799,8 @@ msgid "Tools"
msgstr "Công cụ"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Orphan Resource Explorer..."
-msgstr "Lưu tài nguyên thành ..."
+msgstr "Tìm kiếm tài nguyên mất gốc..."
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -2819,10 +2827,9 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Small Deploy with Network Filesystem"
-msgstr ""
+msgstr "Triển khai nhỠvới hệ thống tệp mạng"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, using one-click deploy for Android will only "
"export an executable without the project data.\n"
@@ -2831,9 +2838,9 @@ msgid ""
"On Android, deploying will use the USB cable for faster performance. This "
"option speeds up testing for projects with large assets."
msgstr ""
-"Khi tuỳ chá»n này được bật, lúc xuất hoặc triển khai sẽ tạo má»™t tệp thá»±c thi "
-"tối giản nhất.\n"
-"Hệ thống tệp tin sẽ được cung cấp từ dự án bởi trình soạn thảo qua mạng.\n"
+"Khi tuỳ chá»n này được bật, lúc xuất hoặc triển khai ra Android sẽ chỉ tạo "
+"một tệp thực thi tối giản nhất.\n"
+"Hệ thống tệp tin sẽ được cung cấp từ dự án bởi trình chỉnh sửa qua mạng.\n"
"Trên ná»n tảng Android, triển khai sẽ sá»­ dụng cáp USB để có hiệu suất nhanh "
"hÆ¡n. Tuỳ chá»n này tăng tốc độ khi thá»­ nghiệm cho các trò chÆ¡i nặng."
@@ -2872,6 +2879,10 @@ msgid ""
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
+"Khi tuỳ chá»n này được bật, bất cứ thay đổi nào được tạo ra lên cảnh trong "
+"trình chỉnh sửa sẽ được sao lại trong dự án đang chạy.\n"
+"Khi được dùng từ xa trên một thiết bị, làm như vậy sẽ hiệu quả hơn khi tuỳ "
+"chá»n hệ thống tệp mạng được bật."
#: editor/editor_node.cpp
msgid "Synchronize Script Changes"
@@ -2887,11 +2898,11 @@ msgstr ""
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
-msgstr "Editor (trình biên tập)"
+msgstr "Trình chỉnh sửa"
#: editor/editor_node.cpp
msgid "Editor Settings..."
-msgstr "Cài đặt Trình biên tập..."
+msgstr "Cài đặt trình chỉnh sửa..."
#: editor/editor_node.cpp
msgid "Editor Layout"
@@ -2904,32 +2915,31 @@ msgstr "Chụp màn hình"
#: editor/editor_node.cpp
msgid "Screenshots are stored in the Editor Data/Settings Folder."
msgstr ""
-"Ảnh chụp màn hình được lưu ở thư mục Dữ liệu/Cài đặt của trình biên tập."
+"Ảnh chụp màn hình được lưu ở thư mục Dữ liệu/Cài đặt của trình chỉnh sửa."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
msgstr "Chế độ Toàn màn hình"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Toggle System Console"
-msgstr "Chế độ Phân chia"
+msgstr "Kích hoạt Console Hệ thống"
#: editor/editor_node.cpp
msgid "Open Editor Data/Settings Folder"
-msgstr "Mở thư mục dữ liệu Trình biên tập"
+msgstr "Mở thư mục dữ liệu của trình chỉnh sửa"
#: editor/editor_node.cpp
msgid "Open Editor Data Folder"
-msgstr "Mở thư mục dữ liệu Trình biên tập"
+msgstr "Mở thư mục dữ liệu của trình chỉnh sửa"
#: editor/editor_node.cpp
msgid "Open Editor Settings Folder"
-msgstr "Mở thư mục Thiết lập Trình biên tập"
+msgstr "Mở thư mục Thiết lập trình chỉnh sửa"
#: editor/editor_node.cpp
msgid "Manage Editor Features..."
-msgstr "Quản lý tính năng Trình biên tập..."
+msgstr "Quản lý tính năng trình chỉnh sửa..."
#: editor/editor_node.cpp
msgid "Manage Export Templates..."
@@ -2965,6 +2975,10 @@ msgid "About"
msgstr "VỠchúng tôi"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "Chạy dự án."
@@ -3002,7 +3016,8 @@ msgstr "Chạy Cảnh Tuỳ Chá»n"
#: editor/editor_node.cpp
msgid "Changing the video driver requires restarting the editor."
-msgstr "Thay đổi trình Ä‘iá»u khiển Video cần phải khởi động lại Trình biên tập."
+msgstr ""
+"Thay đổi trình Ä‘iá»u khiển Video cần phải khởi động lại trình chỉnh sá»­a."
#: editor/editor_node.cpp editor/project_settings_editor.cpp
#: editor/settings_config_dialog.cpp
@@ -3011,7 +3026,7 @@ msgstr "Lưu & Khởi động lại"
#: editor/editor_node.cpp
msgid "Spins when the editor window redraws."
-msgstr "Xoay khi cửa sổ trình biên soạn được vẽ lại."
+msgstr "Xoay khi cửa sổ trình chỉnh sửa được vẽ lại."
#: editor/editor_node.cpp
msgid "Update Continuously"
@@ -3134,15 +3149,15 @@ msgstr "Chá»n"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
-msgstr "Mở Trình biên tập 2D"
+msgstr "Mở trình chỉnh sửa 2D"
#: editor/editor_node.cpp
msgid "Open 3D Editor"
-msgstr "Mở Trình biên tập 3D"
+msgstr "Mở trình chỉnh sửa 3D"
#: editor/editor_node.cpp
msgid "Open Script Editor"
-msgstr "Mở Trình biên soạn Mã lệnh"
+msgstr "Mở trình chỉnh sửa tập lệnh"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
@@ -3150,11 +3165,11 @@ msgstr "Mở Thư viện Nguyên liệu"
#: editor/editor_node.cpp
msgid "Open the next Editor"
-msgstr "Mở Trình biên soạn tiếp theo"
+msgstr "Mở trình chỉnh sửa tiếp theo"
#: editor/editor_node.cpp
msgid "Open the previous Editor"
-msgstr "Mở Trình biên soạn trước đó"
+msgstr "Mở trình chỉnh sửa trước đó"
#: editor/editor_node.h
msgid "Warning!"
@@ -3231,7 +3246,7 @@ msgstr "Bao gồm"
#: editor/editor_profiler.cpp
msgid "Self"
-msgstr ""
+msgstr "Chính nó"
#: editor/editor_profiler.cpp
msgid "Frame #:"
@@ -3243,7 +3258,7 @@ msgstr "Thá»i gian"
#: editor/editor_profiler.cpp
msgid "Calls"
-msgstr ""
+msgstr "Lượt gá»i"
#: editor/editor_properties.cpp
msgid "Edit Text:"
@@ -3305,13 +3320,12 @@ msgid "New Script"
msgstr "Mã lệnh mới"
#: editor/editor_properties.cpp editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Extend Script"
-msgstr "Tạo Script"
+msgstr "Mở rộng Script"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "New %s"
-msgstr "Má»›i %s"
+msgstr "%s má»›i"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Make Unique"
@@ -3416,9 +3430,8 @@ msgid "Import From Node:"
msgstr "Nhập từ Nút:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Redownload"
-msgstr "Tải lại"
+msgstr "Tải lại xuống"
#: editor/export_template_manager.cpp
msgid "Uninstall"
@@ -3446,9 +3459,8 @@ msgid "(Current)"
msgstr "(Hiện tại)"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Retrieving mirrors, please wait..."
-msgstr "Äang tìm các trang mirror, đợi xíu..."
+msgstr "Äang tìm các trang dá»± phòng, đợi xíu..."
#: editor/export_template_manager.cpp
msgid "Remove template version '%s'?"
@@ -3483,9 +3495,9 @@ msgid "Error getting the list of mirrors."
msgstr "Có lỗi khi lấy các trang mirror."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error parsing JSON of mirror list. Please report this issue!"
-msgstr "Có lỗi khi phân tích JSON của danh sách trang mirror. Hãy báo cáo lỗi!"
+msgstr ""
+"Có lỗi khi phân tích JSON của danh sách trang dự phòng. Hãy báo cáo lỗi!"
#: editor/export_template_manager.cpp
msgid ""
@@ -3528,9 +3540,8 @@ msgid "Download Complete."
msgstr "Tải xuống xong."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Cannot remove temporary file:"
-msgstr "Không thể gỡ bá»:"
+msgstr "Không thể gỡ bá» tệp tạm thá»i:"
#: editor/export_template_manager.cpp
msgid ""
@@ -3611,9 +3622,8 @@ msgid "Remove Template"
msgstr "Xóa Template"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Select Template File"
-msgstr "Chá»n file template"
+msgstr "Chá»n tệp bản mẫu"
#: editor/export_template_manager.cpp
msgid "Godot Export Templates"
@@ -3628,9 +3638,9 @@ msgid "Download Templates"
msgstr "Tải Xuống Các Mẫu Xuất Bản"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Select mirror from list: (Shift+Click: Open in Browser)"
-msgstr "Chá»n trang mirror từ danh sách: (Shift+Nhấp: Mở trong trình duyệt)"
+msgstr ""
+"Chá»n trang dá»± phòng từ danh sách: (Shift + Chuá»™t trái: Mở trong trình duyệt)"
#: editor/filesystem_dock.cpp
msgid "Favorites"
@@ -3718,9 +3728,8 @@ msgid "New Inherited Scene"
msgstr "Tạo Cảnh kế thừa mới"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Set As Main Scene"
-msgstr "Chá»n má»™t Scene chính"
+msgstr "Chá»n làm Scene chính"
#: editor/filesystem_dock.cpp
msgid "Open Scenes"
@@ -3777,9 +3786,8 @@ msgid "Duplicate..."
msgstr "Nhân đôi..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Move to Trash"
-msgstr "Di chuyển Nút"
+msgstr "Di chuyển vào Thùng rác"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
@@ -3829,9 +3837,8 @@ msgid "Overwrite"
msgstr "Ghi đè"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Create Scene"
-msgstr "Tạo từ Scene"
+msgstr "Tạo Scene"
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "Create Script"
@@ -3891,19 +3898,16 @@ msgid "Searching..."
msgstr "Äang tìm kiếm ..."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d match in %d file."
-msgstr "Tìm thấy %d khớp."
+msgstr "Tìm thấy %d điểm khớp trong %d tệp."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d file."
-msgstr "Tìm thấy %d khớp."
+msgstr "Tìm thấy %d điểm khớp trong %d tệp."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d files."
-msgstr "Tìm thấy %d khớp."
+msgstr "Tìm thấy %d điểm khớp trong %d tệp."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -3922,14 +3926,12 @@ msgid "Invalid group name."
msgstr "Tên nhóm không hợp lệ."
#: editor/groups_editor.cpp
-#, fuzzy
msgid "Rename Group"
-msgstr "Quản lý Nhóm"
+msgstr "Äổi tên Nhóm"
#: editor/groups_editor.cpp
-#, fuzzy
msgid "Delete Group"
-msgstr "Xoá bố cục"
+msgstr "Xoá Nhóm"
#: editor/groups_editor.cpp editor/node_dock.cpp
msgid "Groups"
@@ -3953,9 +3955,8 @@ msgid "Empty groups will be automatically removed."
msgstr "Các nhóm trống sẽ tự động bị xóa."
#: editor/groups_editor.cpp
-#, fuzzy
msgid "Group Editor"
-msgstr "Trình viết mã lệnh"
+msgstr "Trình chỉnh sửa Nhóm"
#: editor/groups_editor.cpp
msgid "Manage Groups"
@@ -3999,7 +4000,7 @@ msgstr "Nhập vào Nhiá»u cảnh"
#: editor/import/resource_importer_scene.cpp
msgid "Import as Multiple Scenes+Materials"
-msgstr ""
+msgstr "Nhập nhiá»u Scene + Vật liệu"
#: editor/import/resource_importer_scene.cpp
#: editor/plugins/mesh_library_editor_plugin.cpp
@@ -4044,18 +4045,16 @@ msgid "Saving..."
msgstr "Äang lưu ..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Chế độ chá»n"
+msgstr "Chá»n bá»™ nhập"
#: editor/import_defaults_editor.cpp
msgid "Importer:"
msgstr "Công cụ nhập:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Nạp mặc định"
+msgstr "Äặt lại thành mặc định"
#: editor/import_dock.cpp
msgid "Keep File (No Import)"
@@ -4091,7 +4090,7 @@ msgstr "Lưu các cảnh, nhập lại, rồi tái khởi động"
#: editor/import_dock.cpp
msgid "Changing the type of an imported file requires editor restart."
-msgstr "Sửa kiểu của tệp đã nhập yêu cầu khởi động lại trình biên soạn."
+msgstr "Sửa kiểu của tệp đã nhập yêu cầu khởi động lại trình chỉnh sửa."
#: editor/import_dock.cpp
msgid ""
@@ -4340,7 +4339,7 @@ msgstr "Äiểm"
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Open Editor"
-msgstr "Mở Trình biên soạn"
+msgstr "Mở trình chỉnh sửa"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4358,23 +4357,20 @@ msgid "Add Triangle"
msgstr "Thêm Tam giác"
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "Change BlendSpace2D Limits"
-msgstr "Äổi Thá»i gian Chuyển Animation"
+msgstr "Äổi các giá»›i hạn BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "Change BlendSpace2D Labels"
-msgstr "Äổi Thá»i gian Chuyển Animation"
+msgstr "Äổi các nhãn BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Remove BlendSpace2D Point"
msgstr "Xóa điểm BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "Remove BlendSpace2D Triangle"
-msgstr "Xoá Variable"
+msgstr "BỠcác tam giác BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "BlendSpace2D does not belong to an AnimationTree node."
@@ -4749,11 +4745,11 @@ msgstr "Äồng bá»™ hoá"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "At End"
-msgstr ""
+msgstr "Ở cuối"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Travel"
-msgstr ""
+msgstr "Di chuyển"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Start and end nodes are needed for a sub-transition."
@@ -4839,11 +4835,11 @@ msgstr "Giảm dần (s):"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend"
-msgstr ""
+msgstr "Hoà"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Mix"
-msgstr ""
+msgstr "Trá»™n"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Auto Restart:"
@@ -4978,7 +4974,7 @@ msgstr "Không có phản hồi từ host:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Can't resolve hostname:"
-msgstr ""
+msgstr "Không thể phân giải tên máy lưu trữ:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed, return code:"
@@ -5001,7 +4997,6 @@ msgid "Request failed, too many redirects"
msgstr "Yêu cầu thất bại, chuyển hướng quá nhiá»u"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Redirect loop."
msgstr "Chuyển hướng vòng lặp."
@@ -5224,7 +5219,7 @@ msgstr "bước"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Offset:"
-msgstr ""
+msgstr "Äá»™ lệch xoay:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Step:"
@@ -5336,43 +5331,40 @@ msgid "Bottom Left"
msgstr "Góc dưới trái"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Center Left"
-msgstr "Trung tâm Bên trái"
+msgstr "Giữa bên trái"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Top"
-msgstr ""
+msgstr "Trên giữa"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Right"
-msgstr ""
+msgstr "Phải giữa"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Bottom"
-msgstr ""
+msgstr "Dưới giữa"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center"
-msgstr ""
+msgstr "Giữa"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Left Wide"
-msgstr "Tịnh tuyến"
+msgstr "Rộng bên trái"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Wide"
-msgstr ""
+msgstr "Rộng bên trên"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Right Wide"
-msgstr "Tịnh tuyến"
+msgstr "Rộng bên phải"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Wide"
-msgstr ""
+msgstr "Rộng bên dưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "VCenter Wide"
@@ -5408,6 +5400,8 @@ msgid ""
"Game Camera Override\n"
"Overrides game camera with editor viewport camera."
msgstr ""
+"Ghi đè máy quay trò chơi\n"
+"Ghi đè máy quay trò chơi bằng máy quay cổng xem của trình chỉnh sửa."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5415,6 +5409,8 @@ msgid ""
"Game Camera Override\n"
"No game instance running."
msgstr ""
+"Ghi đè máy quay trò chơi\n"
+"Không có thực thể trò chơi này đang chạy."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5438,7 +5434,7 @@ msgstr "Bá» nhóm đã chá»n"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Paste Pose"
-msgstr ""
+msgstr "Dán tư thé"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Guides"
@@ -5528,9 +5524,8 @@ msgid "Pan Mode"
msgstr "Chế độ Xoay"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Ruler Mode"
-msgstr "Chế độ Tỉ lệ"
+msgstr "Chế độ thước"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle smart snapping."
@@ -5635,7 +5630,7 @@ msgstr "Tạo xương tuỳ chá»n từ các nút"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Custom Bones"
-msgstr ""
+msgstr "Xoá sạch các xương tuỳ chỉnh"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5643,9 +5638,8 @@ msgid "View"
msgstr "Hiện thị"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Always Show Grid"
-msgstr "Hiện lưới"
+msgstr "Luôn hiện lưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Helpers"
@@ -5673,7 +5667,7 @@ msgstr "Hiện biểu tượng Nhóm và Khóa"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Selection"
-msgstr ""
+msgstr "Căn giữa phần được chá»n"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Frame Selection"
@@ -5681,7 +5675,7 @@ msgstr "Lá»±a chá»n khung hình"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
-msgstr ""
+msgstr "Xem trước tỉ lệ bức vẽ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Translation mask for inserting keys."
@@ -5696,9 +5690,8 @@ msgid "Scale mask for inserting keys."
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Insert keys (based on mask)."
-msgstr "Chèn Khóa (dựa trên mask)."
+msgstr "Chèn khóa (dựa trên mặt nạ)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5709,9 +5702,8 @@ msgid ""
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Auto Insert Key"
-msgstr "Chèn Key Anim"
+msgstr "Tự chèn khoá"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5728,7 +5720,7 @@ msgstr "Sao chép Tư thế"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Pose"
-msgstr ""
+msgstr "Xoá sạch tư thế"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -5740,7 +5732,7 @@ msgstr "Chia đôi bước lưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan View"
-msgstr ""
+msgstr "Di chuyển tầm nhìn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
@@ -5837,9 +5829,8 @@ msgstr "Äiểm ảnh viá»n"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Directed Border Pixels"
-msgstr "Các Thư mục và Tệp tin:"
+msgstr "Pixel ở Viá»n cạnh Có hướng"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5853,7 +5844,7 @@ msgstr ""
#: editor/plugins/cpu_particles_editor_plugin.cpp
msgid "CPUParticles"
-msgstr ""
+msgstr "CPUParticles"
#: editor/plugins/cpu_particles_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -5907,14 +5898,12 @@ msgid "Remove Point"
msgstr "Xoá điểm"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Left Linear"
-msgstr "Tịnh tuyến"
+msgstr "Tịnh tuyến trái"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Right Linear"
-msgstr "Tịnh tuyến"
+msgstr "Tịnh tuyến phải"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Load Preset"
@@ -5954,7 +5943,7 @@ msgstr "Mục"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item List Editor"
-msgstr ""
+msgstr "Trình chỉnh sửa ItemList"
#: editor/plugins/light_occluder_2d_editor_plugin.cpp
msgid "Create Occluder Polygon"
@@ -6225,7 +6214,7 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Target Surface:"
-msgstr ""
+msgstr "BỠmặt mục tiêu:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Source Mesh:"
@@ -6261,7 +6250,7 @@ msgstr "Thu phóng ngẫu nhiên:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Populate"
-msgstr ""
+msgstr "Äiá»n"
#: editor/plugins/navigation_polygon_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp
@@ -6325,7 +6314,7 @@ msgstr ""
#: editor/plugins/particles_editor_plugin.cpp
msgid "Surface Points"
-msgstr ""
+msgstr "Các điểm bỠmặt"
#: editor/plugins/particles_editor_plugin.cpp
msgid "Surface Points+Normal (Directed)"
@@ -6337,7 +6326,7 @@ msgstr "Âm lượng"
#: editor/plugins/particles_editor_plugin.cpp
msgid "Emission Source: "
-msgstr ""
+msgstr "Nguồn phát ra: "
#: editor/plugins/particles_editor_plugin.cpp
msgid "A processor material of type 'ParticlesMaterial' is required."
@@ -6345,7 +6334,7 @@ msgstr ""
#: editor/plugins/particles_editor_plugin.cpp
msgid "Generating AABB"
-msgstr ""
+msgstr "Äang sinh AABB"
#: editor/plugins/particles_editor_plugin.cpp
msgid "Generate Visibility AABB"
@@ -6392,7 +6381,7 @@ msgstr "Chá»n Points"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
msgid "Shift+Drag: Select Control Points"
-msgstr ""
+msgstr "Shift+Kéo: Chá»n các Ä‘iểm Ä‘iá»u khiển"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
@@ -6467,7 +6456,7 @@ msgstr "Tách đưá»ng"
#: editor/plugins/path_editor_plugin.cpp
msgid "Remove Path Point"
-msgstr ""
+msgstr "Loại bá» Ä‘iểm đưá»ng dẫn"
#: editor/plugins/path_editor_plugin.cpp
msgid "Remove Out-Control Point"
@@ -6499,22 +6488,24 @@ msgid ""
"No texture in this polygon.\n"
"Set a texture to be able to edit UV."
msgstr ""
+"Không có hình kết cấu nào trong đa giác này.\n"
+"Äặt má»™ hình kết cấu để có thể chỉnh sá»­a UV."
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create UV Map"
-msgstr ""
+msgstr "Tạo bản đồ UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid ""
"Polygon 2D has internal vertices, so it can no longer be edited in the "
"viewport."
msgstr ""
-"Äa giác 2D có đỉnh nằm trong, vì vậy không thể chỉnh sá»­a trong cổng xem."
+"Äa giác 2D có đỉnh nằm trong, vì vậy nó không thể được chỉnh sá»­a trong cổng "
+"xem."
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Polygon & UV"
-msgstr ""
+msgstr "Tạo đa giác & UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Internal Vertex"
@@ -6558,7 +6549,7 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "UV"
-msgstr ""
+msgstr "UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Points"
@@ -6715,7 +6706,7 @@ msgstr "Dán tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/scene_tree_editor.cpp
msgid "Instance:"
-msgstr ""
+msgstr "Thế:"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
@@ -6948,7 +6939,7 @@ msgstr "Tìm kiếm"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
-msgstr ""
+msgstr "Bước vào"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Over"
@@ -6956,7 +6947,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Break"
-msgstr ""
+msgstr "Thoát"
#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
#: editor/script_editor_debugger.cpp
@@ -7263,11 +7254,11 @@ msgstr "Chạy IK"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Orthogonal"
-msgstr ""
+msgstr "Vuông góc"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Perspective"
-msgstr ""
+msgstr "Phối cảnh"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Aborted."
@@ -7355,7 +7346,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom"
-msgstr ""
+msgstr "Dưới"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Left View."
@@ -7363,7 +7354,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Left"
-msgstr ""
+msgstr "Trái"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Right View."
@@ -7371,7 +7362,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Right"
-msgstr ""
+msgstr "Phải"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Front View."
@@ -7379,7 +7370,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Front"
-msgstr ""
+msgstr "Trước"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rear View."
@@ -7760,7 +7751,7 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't replace by mesh."
-msgstr ""
+msgstr "Hình không hợp lệ, không thể thay thế bằng lưới."
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Convert to Mesh2D"
@@ -7768,7 +7759,7 @@ msgstr "Chuyển thành Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create polygon."
-msgstr ""
+msgstr "Hình không hợp lệ, không thể tạo đa giác."
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Convert to Polygon2D"
@@ -7776,20 +7767,19 @@ msgstr "Chuyển thành Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create collision polygon."
-msgstr ""
+msgstr "Hình há»c không hợp lệ, không thể tạo Ä‘a giác va chạm."
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create CollisionPolygon2D Sibling"
-msgstr "Tạo"
+msgstr "Tạo CollisionPolygon2D cùng bậc"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create light occluder."
-msgstr ""
+msgstr "Hình há»c không rõ, không thể tạo bá»™ tá»a ánh sáng."
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create LightOccluder2D Sibling"
-msgstr ""
+msgstr "Tạo LightOccluder2D cùng bậc"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite"
@@ -7805,7 +7795,7 @@ msgstr "Thu nhá» (Äiểm ảnh): "
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Grow (Pixels): "
-msgstr ""
+msgstr "Phóng to (Äiểm ảnh): "
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Update Preview"
@@ -8101,7 +8091,7 @@ msgstr "Cây con"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Has,Many,Options"
-msgstr ""
+msgstr "Có, Nhiá»u, Tùy Chá»n"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Data Type:"
@@ -8114,7 +8104,7 @@ msgstr "Biểu tượng"
#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
msgid "Style"
-msgstr ""
+msgstr "Kiểu"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Font"
@@ -8298,7 +8288,7 @@ msgstr "Ưu tiên"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Z Index"
-msgstr ""
+msgstr "Chỉ số Z"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Region Mode"
@@ -8382,6 +8372,8 @@ msgstr "Hiển thị tên ô (Giữ phím Alt)"
msgid ""
"Add or select a texture on the left panel to edit the tiles bound to it."
msgstr ""
+"Thêm hoặc chá»n má»™t há»a tiết ở bảng bên trái để chỉnh sá»­a các ô bị nó giá»›i "
+"hạn."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Remove selected texture? This will remove all tiles which use it."
@@ -8429,12 +8421,17 @@ msgid "Delete polygon."
msgstr "Xóa đa giác."
#: editor/plugins/tile_set_editor_plugin.cpp
+#, fuzzy
msgid ""
"LMB: Set bit on.\n"
"RMB: Set bit off.\n"
"Shift+LMB: Set wildcard bit.\n"
"Click on another Tile to edit it."
msgstr ""
+"Chuột trái: Bật bit.\n"
+"Chuột phải: Tắt bit.\n"
+"Shift + Chuá»™t trái: Äặt bit biến hóa.\n"
+"Bấm chuột vào ô khác để chỉnh sửa nó."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8559,7 +8556,7 @@ msgstr "Lá»—i"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No files added to stage"
-msgstr ""
+msgstr "Không có tệp nào trong giai Ä‘oạn chá»"
#: editor/plugins/version_control_editor_plugin.cpp
#, fuzzy
@@ -8568,7 +8565,7 @@ msgstr "Cộng đồng"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "VCS Addon is not initialized"
-msgstr ""
+msgstr "Trình kiểm soát phiên bản chưa được khởi tạo"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control System"
@@ -8580,7 +8577,7 @@ msgstr "Khởi tạo"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Staging area"
-msgstr ""
+msgstr "Vùng chá»"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Detect new changes"
@@ -8629,7 +8626,7 @@ msgstr "Trạng thái"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "View file diffs before committing them to the latest version"
-msgstr ""
+msgstr "Kiểm tra các khác biệt trước khi xác nhận vào phiên bản mới nhất"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No file diff is active"
@@ -8696,9 +8693,8 @@ msgid "Remove output port"
msgstr "Xóa Cổng ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Set expression"
-msgstr "Phiên bản hiện tại:"
+msgstr "Äặt phép diá»…n đạt"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Resize VisualShader node"
@@ -8778,11 +8774,11 @@ msgstr "Tạo Function"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts HSV vector to RGB equivalent."
-msgstr "Chuyển đổi vector HSV sang RGB tương đương."
+msgstr "Chuyển vector màu HSV sang RGB tương ứng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts RGB vector to HSV equivalent."
-msgstr "Chuyển đổi vector RGB sang HSV tương đương."
+msgstr "Chuyển vector màu RGB sang HSV tương ứng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Sepia function."
@@ -8954,7 +8950,7 @@ msgstr "Chá»n Scale"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Scalar operator."
-msgstr ""
+msgstr "Toán tử vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "E constant (2.718282). Represents the base of the natural logarithm."
@@ -8994,56 +8990,56 @@ msgstr "Trả vỠgiá trị tuyệt đối của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-cosine of the parameter."
-msgstr "Trả vỠarc-cosine của tham số."
+msgstr "Trả vỠcôsin nghịch đảo của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic cosine of the parameter."
-msgstr ""
+msgstr "Trả vỠcôsin hyperbolic nghịch đảo của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-sine of the parameter."
-msgstr "Trả vỠarc-sin của tham số."
+msgstr "Trả vỠsin nghịch đảo của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic sine of the parameter."
-msgstr ""
+msgstr "Trả vỠsin hyperbolic nghịch đảo của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-tangent of the parameter."
-msgstr "Trả vỠarc-tan của tham số."
+msgstr "Trả vỠtan nghịch đảo của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-tangent of the parameters."
-msgstr "Trả vỠarc-tan của các tham số."
+msgstr "Trả vỠtan nghịch đảo của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic tangent of the parameter."
-msgstr ""
+msgstr "Trả vỠtan hyperbolic nghịch đảo của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Finds the nearest integer that is greater than or equal to the parameter."
-msgstr "Tìm số nguyên gần nhất lớn hơn hoặc bằng tham số."
+msgstr "Trả vỠsố nguyên nhỠnhất lớn hơn hoặc bằng tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Constrains a value to lie between two further values."
-msgstr ""
+msgstr "Kẹp một giá trị giữa hai biên."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the cosine of the parameter."
-msgstr "Trả vỠcosine của tham số."
+msgstr "Trả vỠcôsin của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic cosine of the parameter."
-msgstr ""
+msgstr "Trả vỠcôsin hyperbolic của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts a quantity in radians to degrees."
-msgstr "Äổi radian vỠđộ."
+msgstr "Chuyển đổi đơn vị radian sang độ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-e Exponential."
-msgstr "Lũy thừa cơ số e."
+msgstr "Lũy thừa cơ số e (hằng số Euler)."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-2 Exponential."
@@ -9051,23 +9047,23 @@ msgstr "Lũy thừa cơ số 2."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest integer less than or equal to the parameter."
-msgstr "Tìm số nguyên gần nhất nhỠhơn hoặc bằng tham số."
+msgstr "Tìm số nguyên lớn nhất nhỠhơn hoặc bằng tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Computes the fractional part of the argument."
-msgstr "Tính phần phân số của tham số."
+msgstr "Tính phần thập phân của phép chia."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse of the square root of the parameter."
-msgstr ""
+msgstr "Trả vỠnghịch đảo căn bậc hai của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Natural logarithm."
-msgstr "Logarit tự nhiên."
+msgstr "Lôgarit tự nhiên."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-2 logarithm."
-msgstr "Logarit cơ số 2."
+msgstr "Lôgarit cơ số 2."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the greater of two values."
@@ -9096,7 +9092,7 @@ msgstr "Trả vỠlũy thừa cơ số tham số đầu tiên có số mũ tham
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts a quantity in degrees to radians."
-msgstr "Äổi từ độ vá» radian."
+msgstr "Chuyển đơn vị độ thành radian."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 / scalar"
@@ -9124,7 +9120,7 @@ msgstr "Trả vỠsin của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic sine of the parameter."
-msgstr "Trả vỠsin hyperbolic của tham số."
+msgstr "Trả vỠsin hyperbol của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the square root of the parameter."
@@ -9152,7 +9148,7 @@ msgstr "Trả vỠtan của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic tangent of the parameter."
-msgstr "Trả vỠtan hyperbolic của tham số."
+msgstr "Trả vỠtan hyperbol của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the truncated value of the parameter."
@@ -9284,7 +9280,7 @@ msgstr "Tách vector thành ba giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the cross product of two vectors."
-msgstr "Tính tích chéo của hai vector."
+msgstr "Tính tích có hướng của hai vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the distance between two points."
@@ -9376,7 +9372,7 @@ msgstr "Cá»™ng vector vá»›i vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Divides vector by vector."
-msgstr "Chia vector cho vector."
+msgstr "Chia hai vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies vector by vector."
@@ -10005,7 +10001,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Key "
-msgstr ""
+msgstr "Khoá "
#: editor/project_settings_editor.cpp
msgid "Joy Button"
@@ -10021,7 +10017,7 @@ msgstr "Nút chuột"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr "Tên hành động không được trống hoặc chứa '/', ':', '=', '\\' hoặc '\"'"
@@ -10170,7 +10166,7 @@ msgstr "Tên hành động không thể trống hoặc chứa '/', ':', '=', '\\
#: editor/project_settings_editor.cpp
msgid "Add Input Action"
-msgstr ""
+msgstr "Thêm hành động đầu vào"
#: editor/project_settings_editor.cpp
msgid "Error saving settings."
@@ -10242,7 +10238,7 @@ msgstr "Thay đổi sẽ được áp dụng sau khi Trình biên tập khởi Ä
#: editor/project_settings_editor.cpp
msgid "Input Map"
-msgstr ""
+msgstr "Ãnh xạ đầu vào"
#: editor/project_settings_editor.cpp
msgid "Action:"
@@ -10263,19 +10259,19 @@ msgstr "Thiết bị:"
#: editor/project_settings_editor.cpp
msgid "Index:"
-msgstr ""
+msgstr "Chỉ mục:"
#: editor/project_settings_editor.cpp
msgid "Localization"
-msgstr ""
+msgstr "Bản địa hoá"
#: editor/project_settings_editor.cpp
msgid "Translations"
-msgstr ""
+msgstr "Bản dịch"
#: editor/project_settings_editor.cpp
msgid "Translations:"
-msgstr ""
+msgstr "Bản dịch:"
#: editor/project_settings_editor.cpp
msgid "Remaps"
@@ -10291,7 +10287,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Locale"
-msgstr ""
+msgstr "Vùng vị trí"
#: editor/project_settings_editor.cpp
msgid "Locales Filter"
@@ -10316,7 +10312,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "AutoLoad"
-msgstr ""
+msgstr "Tự nạp"
#: editor/project_settings_editor.cpp
msgid "Plugins"
@@ -10333,7 +10329,7 @@ msgstr "Cài sẵn ..."
#: editor/property_editor.cpp
msgid "Zero"
-msgstr ""
+msgstr "Không"
#: editor/property_editor.cpp
msgid "Easing In-Out"
@@ -10528,7 +10524,7 @@ msgstr ""
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent"
-msgstr ""
+msgstr "Äổi nút cha"
#: editor/run_settings_dialog.cpp
msgid "Run Mode:"
@@ -12106,10 +12102,22 @@ msgstr ""
"Dá»± Ãn."
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po
index e5826da638..53259bcc6f 100644
--- a/editor/translations/zh_CN.po
+++ b/editor/translations/zh_CN.po
@@ -78,11 +78,12 @@
# Weiduo Xie <xwditfr@gmail.com>, 2021.
# suplife <2634557184@qq.com>, 2021.
# luoji <564144019@qq.com>, 2021.
+# zeng haochen <m18621006730@163.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"PO-Revision-Date: 2021-05-29 13:49+0000\n"
"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hans/>\n"
@@ -100,7 +101,7 @@ msgstr "convert() çš„å‚æ•°ç±»åž‹æ— æ•ˆï¼Œè¯·ä½¿ç”¨ TYPE_* 常é‡ã€‚"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "应为长度为 1 的字符串(1 字符)。"
+msgstr "应为长度为 1 的字符串(1个字符)。"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -1176,6 +1177,10 @@ msgstr "改å˜å­—典值"
msgid "Thanks from the Godot community!"
msgstr "Godot 社区感谢你ï¼"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine 贡献者"
@@ -2565,9 +2570,12 @@ msgstr "无法从路径 “%s†中加载加载项脚本。"
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
-msgstr "无法从路径 “%s†加载加载项脚本:脚本似乎有代ç é”™è¯¯ï¼Œè¯·æ£€æŸ¥å…¶è¯­æ³•。"
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
+msgstr ""
+"无法从路径“%sâ€åŠ è½½åŠ è½½é¡¹è„šæœ¬ï¼šè¯¥è„šæœ¬å¯èƒ½æœ‰ä»£ç é”™è¯¯ã€‚\n"
+"ç¦ç”¨åŠ è½½é¡¹â€œ%sâ€å¯é˜»æ­¢å…¶è¿›ä¸€æ­¥æŠ¥é”™ã€‚"
#: editor/editor_node.cpp
msgid ""
@@ -2993,6 +3001,10 @@ msgid "About"
msgstr "关于"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "æ”¯æŒ Godot å¼€å‘"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "è¿è¡Œæ­¤é¡¹ç›®ã€‚"
@@ -5184,7 +5196,7 @@ msgstr "æŸäº›ç½‘格无效。确ä¿UV2通é“值包å«åœ¨[0.0,1.0]平方区域内
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
-msgstr "Godot编辑器是在没有光线跟踪支æŒçš„æƒ…况下构建的,光照贴图无法烘焙。"
+msgstr "Godot 编辑器是在没有光线跟踪支æŒçš„æƒ…况下构建的,无法烘焙光照贴图。"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
@@ -7477,12 +7489,12 @@ msgstr "缓慢自由视图速度"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Rotation Locked"
-msgstr "é”定视角旋转"
+msgstr "å·²é”定视角旋转"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
-msgstr ""
+msgstr "修改相机的è£å‰ªå¹³é¢åŽæ‰èƒ½è¿›ä¸€æ­¥ç¼©æ”¾ï¼ˆè§†å›¾ -> 设置...)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -7595,27 +7607,27 @@ msgstr "å˜æ¢å¯¹è¯æ¡†..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "1 Viewport"
-msgstr "1 个视å£"
+msgstr "1 个视窗"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports"
-msgstr "2 个视å£"
+msgstr "2 个视窗"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports (Alt)"
-msgstr "2 个视å£ï¼ˆå¤‡é€‰ï¼‰"
+msgstr "2 个视窗(备选)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports"
-msgstr "3 个视å£"
+msgstr "3 个视窗"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports (Alt)"
-msgstr "3 个视å£ï¼ˆå¤‡é€‰ï¼‰"
+msgstr "3 个视窗(备选)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "4 Viewports"
-msgstr "4 个视å£"
+msgstr "4 个视窗"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Gizmos"
@@ -10000,7 +10012,7 @@ msgstr "鼠标按键"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr "无效的æ“作å称。æ“作åä¸èƒ½ä¸ºç©ºï¼Œä¹Ÿä¸èƒ½åŒ…å« â€œ/â€, “:â€, “=â€, “\\†或 “\"â€"
@@ -10798,6 +10810,8 @@ msgid ""
"every time it updates.\n"
"Switch back to the Local scene tree dock to improve performance."
msgstr ""
+"选中åŽï¼Œè¿œç¨‹åœºæ™¯æ ‘颿¿åœ¨æ›´æ–°æ—¶ä¼šé€ æˆé¡¹ç›®çš„å¡é¡¿ã€‚\n"
+"åˆ‡å›žæœ¬åœ°åœºæ™¯æ ‘é¢æ¿å¯ä»¥æå‡æ€§èƒ½ã€‚"
#: editor/scene_tree_dock.cpp
msgid "Local"
@@ -12026,10 +12040,22 @@ msgid ""
msgstr "未在项目中安装 Android 构建模æ¿ã€‚从项目èœå•安装它。"
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr "未在编辑器设置或预设中é…置调试密钥库。"
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr "用于å‘布的密钥存储在导出预设中未被正确设置。"
@@ -12921,6 +12947,18 @@ msgid "Constants cannot be modified."
msgstr "ä¸å…许修改常é‡ã€‚"
#~ msgid ""
+#~ "Godot editor was built without ray tracing support; lightmaps can't be "
+#~ "baked.\n"
+#~ "If you are using an Apple Silicon-based Mac, try forcing Rosetta "
+#~ "emulation on Godot.app in the application settings\n"
+#~ "then restart the editor."
+#~ msgstr ""
+#~ "Godot 编辑器是在没有光线跟踪支æŒçš„æƒ…况下构建的;无法烘焙光照贴图。\n"
+#~ "如果你使用的是基于 Apple Silicon çš„ Mac,å¯ä»¥å°è¯•在应用设置中让 Godot.app "
+#~ "强制使用 Rosetta 模拟\n"
+#~ "å¹¶é‡å¯ç¼–辑器。"
+
+#~ msgid ""
#~ "InterpolatedCamera has been deprecated and will be removed in Godot 4.0."
#~ msgstr "InterpolatedCamera 已废弃,将在 Godot 4.0 中删除。"
diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po
index 37e8f6ab61..eee6eb62b7 100644
--- a/editor/translations/zh_HK.po
+++ b/editor/translations/zh_HK.po
@@ -1155,6 +1155,10 @@ msgstr "動畫變化數值"
msgid "Thanks from the Godot community!"
msgstr "Godot社å€çš„æ„Ÿè¬ï¼"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine è²¢ç»è€…"
@@ -2609,8 +2613,9 @@ msgstr "載入字形出ç¾éŒ¯èª¤"
#: editor/editor_node.cpp
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr ""
#: editor/editor_node.cpp
@@ -3058,6 +3063,10 @@ msgid "About"
msgstr "關於"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr ""
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "é‹è¡Œå°ˆæ¡ˆ"
@@ -10360,7 +10369,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
@@ -12503,10 +12512,22 @@ msgid ""
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr ""
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po
index 50b323130e..7aee72ee43 100644
--- a/editor/translations/zh_TW.po
+++ b/editor/translations/zh_TW.po
@@ -6,7 +6,7 @@
# Billy SU <g4691821@gmail.com>, 2018.
# Chao Yu <casd82@gmail.com>, 2017.
# Cliffs Dover <bottle@dancingbottle.com>, 2017.
-# Kisaragi Hiu <mail@kisaragi-hiu.com>, 2018.
+# Kisaragi Hiu <mail@kisaragi-hiu.com>, 2018, 2021.
# Matt <chchwy@gmail.com>, 2017.
# popcade <popcade@gmail.com>, 2016.
# Qing <icinriiq@gmail.com>, 2018.
@@ -29,8 +29,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-16 10:40+0000\n"
-"Last-Translator: BinotaLIU <me@binota.org>\n"
+"PO-Revision-Date: 2021-05-24 21:36+0000\n"
+"Last-Translator: Kisaragi Hiu <mail@kisaragi-hiu.com>\n"
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hant/>\n"
"Language: zh_TW\n"
@@ -38,7 +38,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.5.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1123,6 +1123,10 @@ msgstr "改變字典值"
msgid "Thanks from the Godot community!"
msgstr "Godot 社群感è¬ä½ ï¼"
+#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp
+msgid "Click to copy."
+msgstr ""
+
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
msgstr "Godot Engine è²¢ç»è€…"
@@ -2513,9 +2517,11 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "無法自路徑「%sã€è¼‰å…¥æ“´å……腳本。"
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
-"Unable to load addon script from path: '%s' There seems to be an error in "
-"the code, please check the syntax."
+"Unable to load addon script from path: '%s'. This might be due to a code "
+"error in that script.\n"
+"Disabling the addon at '%s' to prevent further errors."
msgstr "無法自路徑「%sã€è¼‰å…¥æ“´å……腳本。å¯èƒ½ç‚ºç¨‹å¼ç¢¼ä¸­æœ‰éŒ¯èª¤ï¼Œè«‹æª¢æŸ¥èªžæ³•。"
#: editor/editor_node.cpp
@@ -2942,6 +2948,10 @@ msgid "About"
msgstr "關於"
#: editor/editor_node.cpp
+msgid "Support Godot Development"
+msgstr "æ”¯æ´ Godot 開發"
+
+#: editor/editor_node.cpp
msgid "Play the project."
msgstr "執行該專案。"
@@ -4013,7 +4023,7 @@ msgstr "é‡è¨­ç‚ºé è¨­"
#: editor/import_dock.cpp
msgid "Keep File (No Import)"
-msgstr ""
+msgstr "ä¿ç•™æª”案(ä¸åŒ¯å…¥ï¼‰"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -5131,6 +5141,7 @@ msgid ""
msgstr "éƒ¨åˆ†ç¶²æ ¼ç„¡æ•ˆã€‚è«‹ç¢ºä¿ UV2 通é“çš„å€¼ä½æ–¼ [0.0,1.0] 矩形內。"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
+#, fuzzy
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
@@ -7432,7 +7443,7 @@ msgstr "視圖旋轉已鎖定"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
-msgstr ""
+msgstr "è‹¥è¦å†ç¹¼çºŒæ”¾å¤§ï¼Œè«‹è‡³ 檢視 -> 設定... 修改æ”影機的剪è£å¹³é¢"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -9951,7 +9962,7 @@ msgstr "滑鼠按鈕"
#: editor/project_settings_editor.cpp
msgid ""
-"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr "無效的æ“作å稱。å稱ä¸å¯ç•™ç©ºæˆ–åŒ…å« â€œ/â€, “:â€, “=â€, “\\†或 “\"â€"
@@ -11975,10 +11986,22 @@ msgid ""
msgstr "å°šæœªæ–¼å°ˆæ¡ˆä¸­å®‰è£ Android 建置樣æ¿ã€‚請先於專案目錄中進行安è£ã€‚"
#: platform/android/export/export.cpp
+msgid ""
+"Either Debug Keystore, Debug User AND Debug Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr "尚未於編輯器設定或é è¨­è¨­å®šä¸­è¨­å®šé‡‘é‘°å„²å­˜å€ (Keystore)。"
#: platform/android/export/export.cpp
+msgid ""
+"Either Release Keystore, Release User AND Release Password settings must be "
+"configured OR none of them."
+msgstr ""
+
+#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr "發行金鑰儲存å€ä¸­ä¸æ­£ç¢ºä¹‹çµ„態設定至匯出é è¨­è¨­å®šã€‚"
diff --git a/icon_outlined.png b/icon_outlined.png
new file mode 100644
index 0000000000..5f1440f287
--- /dev/null
+++ b/icon_outlined.png
Binary files differ
diff --git a/icon_outlined.svg b/icon_outlined.svg
new file mode 100644
index 0000000000..08f9f6f863
--- /dev/null
+++ b/icon_outlined.svg
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1024"
+ height="1024"
+ id="svg3030"
+ version="1.1"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ sodipodi:docname="icon_outlined.svg"
+ inkscape:export-filename="/home/riteo/srg/godot-riteo/icon_outlined.png"
+ inkscape:export-xdpi="24"
+ inkscape:export-ydpi="24">
+ <defs
+ id="defs3032" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.8359375"
+ inkscape:cx="512"
+ inkscape:cy="512"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1916"
+ inkscape:window-height="1025"
+ inkscape:window-x="1360"
+ inkscape:window-y="53"
+ inkscape:window-maximized="1"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="true"
+ inkscape:snap-smooth-nodes="true"
+ inkscape:snap-intersection-paths="true"
+ inkscape:object-paths="true"
+ showguides="false" />
+ <metadata
+ id="metadata3035">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-98.519719)">
+ <g
+ id="g78-3-5"
+ transform="matrix(4.1626099,0,0,-4.1626099,919.24188,771.67092)"
+ style="fill:none;fill-opacity:0.527344;stroke:#ffffff;stroke-width:15.58077612;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal">
+ <path
+ id="path80-6-3"
+ style="fill:none;fill-opacity:0.527344;fill-rule:nonzero;stroke:#ffffff;stroke-width:23.49692134;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
+ d="m 226.33398,222.09961 c -15.35819,3.41427 -30.55118,8.16852 -44.79492,15.33789 0.32575,12.57731 1.13879,24.62813 2.78711,36.86914 -5.5316,3.54397 -11.34506,6.58567 -16.51172,10.73438 -5.24959,4.03861 -10.60984,7.90172 -15.36328,12.625 -9.49632,-6.28112 -19.54792,-12.18415 -29.90234,-17.39454 -11.16124,12.01179 -21.59792,24.97673 -30.123049,39.48438 6.699845,10.51682 13.887809,21.08874 20.542969,29.33203 0.0561,36.95701 -0.082,77.98955 0,113.01958 0,51.83844 65.75967,76.75448 147.46094,77.04102 h 0.0996 0.0996 c 81.70127,-0.28654 147.43945,-25.20258 147.43945,-77.04102 0.0505,-37.842 0.0165,-79.50966 0.0214,-113.01953 7.68652,-9.6765 14.96452,-20.35178 20.54102,-29.33203 -8.52211,-14.50765 -18.96376,-27.47259 -30.125,-39.48438 -10.3514,5.21039 -20.40602,11.11342 -29.90234,17.39454 -4.75194,-4.72328 -10.1042,-8.58639 -15.36133,-12.625 -5.16515,-4.14871 -10.98481,-7.19041 -16.50586,-10.73438 1.6438,-12.24101 2.45595,-24.29183 2.7832,-36.86914 -14.24524,-7.16937 -29.43699,-11.92362 -44.80273,-15.33789 -6.13484,10.31068 -11.74471,21.47716 -16.63086,32.39258 -5.79401,-0.96818 -11.61467,-1.32712 -17.44336,-1.39649 v -0.01 c -0.0407,0 -0.0786,0.01 -0.11328,0.01 -0.0362,0 -0.0732,-0.01 -0.10938,-0.01 v 0.01 c -5.83925,0.0694 -11.65565,0.42831 -17.45117,1.39649 -4.88313,-10.91542 -10.49088,-22.0819 -16.63477,-32.39258 z"
+ transform="matrix(0.66309862,0,0,-0.66309862,-270.58935,290.52015)"
+ sodipodi:nodetypes="ccccccccccccccccccccccccsccccc" />
+ </g>
+ <g
+ id="g78"
+ transform="matrix(4.162611,0,0,-4.162611,919.24059,771.67186)"
+ style="stroke-width:0.32031175">
+ <path
+ d="m 0,0 c 0,0 -0.325,1.994 -0.515,1.976 l -36.182,-3.491 c -2.879,-0.278 -5.115,-2.574 -5.317,-5.459 l -0.994,-14.247 -27.992,-1.997 -1.904,12.912 c -0.424,2.872 -2.932,5.037 -5.835,5.037 h -38.188 c -2.902,0 -5.41,-2.165 -5.834,-5.037 l -1.905,-12.912 -27.992,1.997 -0.994,14.247 c -0.202,2.886 -2.438,5.182 -5.317,5.46 l -36.2,3.49 c -0.187,0.018 -0.324,-1.978 -0.511,-1.978 l -0.049,-7.83 30.658,-4.944 1.004,-14.374 c 0.203,-2.91 2.551,-5.263 5.463,-5.472 l 38.551,-2.75 c 0.146,-0.01 0.29,-0.016 0.434,-0.016 2.897,0 5.401,2.166 5.825,5.038 l 1.959,13.286 h 28.005 l 1.959,-13.286 c 0.423,-2.871 2.93,-5.037 5.831,-5.037 0.142,0 0.284,0.005 0.423,0.015 l 38.556,2.75 c 2.911,0.209 5.26,2.562 5.463,5.472 l 1.003,14.374 30.645,4.966 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32031175"
+ id="path80"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g82-3"
+ transform="matrix(4.162611,0,0,-4.162611,104.69892,525.90697)"
+ style="stroke-width:0.32031175">
+ <path
+ d="m 0,0 v -47.514 -6.035 -5.492 c 0.108,-0.001 0.216,-0.005 0.323,-0.015 l 36.196,-3.49 c 1.896,-0.183 3.382,-1.709 3.514,-3.609 l 1.116,-15.978 31.574,-2.253 2.175,14.747 c 0.282,1.912 1.922,3.329 3.856,3.329 h 38.188 c 1.933,0 3.573,-1.417 3.855,-3.329 l 2.175,-14.747 31.575,2.253 1.115,15.978 c 0.133,1.9 1.618,3.425 3.514,3.609 l 36.182,3.49 c 0.107,0.01 0.214,0.014 0.322,0.015 v 4.711 l 0.015,0.005 V 0 c 5.09692,6.4164715 9.92323,13.494208 13.621,19.449 -5.651,9.62 -12.575,18.217 -19.976,26.182 -6.864,-3.455 -13.531,-7.369 -19.828,-11.534 -3.151,3.132 -6.7,5.694 -10.186,8.372 -3.425,2.751 -7.285,4.768 -10.946,7.118 1.09,8.117 1.629,16.108 1.846,24.448 -9.446,4.754 -19.519,7.906 -29.708,10.17 -4.068,-6.837 -7.788,-14.241 -11.028,-21.479 -3.842,0.642 -7.702,0.88 -11.567,0.926 v 0.006 c -0.027,0 -0.052,-0.006 -0.075,-0.006 -0.024,0 -0.049,0.006 -0.073,0.006 V 63.652 C 93.903,63.606 90.046,63.368 86.203,62.726 82.965,69.964 79.247,77.368 75.173,84.205 64.989,81.941 54.915,78.789 45.47,74.035 45.686,65.695 46.225,57.704 47.318,49.587 43.65,47.237 39.795,45.22 36.369,42.469 32.888,39.791 29.333,37.229 26.181,34.097 19.884,38.262 13.219,42.176 6.353,45.631 -1.048,37.666 -7.968,29.069 -13.621,19.449 -9.1783421,12.475308 -4.4130298,5.4661124 0,0 Z"
+ style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312"
+ id="path84-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccsssscccccccccccccccccccsccccccccccc" />
+ </g>
+ <g
+ id="g86-7"
+ transform="matrix(4.162611,0,0,-4.162611,784.07144,817.24284)"
+ style="stroke-width:0.32031175">
+ <path
+ d="m 0,0 -1.121,-16.063 c -0.135,-1.936 -1.675,-3.477 -3.611,-3.616 l -38.555,-2.751 c -0.094,-0.007 -0.188,-0.01 -0.281,-0.01 -1.916,0 -3.569,1.406 -3.852,3.33 l -2.211,14.994 H -81.09 l -2.211,-14.994 c -0.297,-2.018 -2.101,-3.469 -4.133,-3.32 l -38.555,2.751 c -1.936,0.139 -3.476,1.68 -3.611,3.616 L -130.721,0 -163.268,3.138 c 0.015,-3.498 0.06,-7.33 0.06,-8.093 0,-34.374 43.605,-50.896 97.781,-51.086 h 0.066 0.067 c 54.176,0.19 97.766,16.712 97.766,51.086 0,0.777 0.047,4.593 0.063,8.093 z"
+ style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32031175"
+ id="path88-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g90-3"
+ transform="matrix(4.162611,0,0,-4.162611,389.21484,625.67104)"
+ style="stroke-width:0.32031175">
+ <path
+ d="m 0,0 c 0,-12.052 -9.765,-21.815 -21.813,-21.815 -12.042,0 -21.81,9.763 -21.81,21.815 0,12.044 9.768,21.802 21.81,21.802 C -9.765,21.802 0,12.044 0,0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32031175"
+ id="path92-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g94-6"
+ transform="matrix(4.162611,0,0,-4.162611,367.36686,631.05679)"
+ style="stroke-width:0.32031175">
+ <path
+ d="m 0,0 c 0,-7.994 -6.479,-14.473 -14.479,-14.473 -7.996,0 -14.479,6.479 -14.479,14.473 0,7.994 6.483,14.479 14.479,14.479 C -6.479,14.479 0,7.994 0,0"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32031175"
+ id="path96-2"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g98-9"
+ transform="matrix(4.162611,0,0,-4.162611,511.99336,724.73954)"
+ style="stroke-width:0.32031175">
+ <path
+ d="m 0,0 c -3.878,0 -7.021,2.858 -7.021,6.381 v 20.081 c 0,3.52 3.143,6.381 7.021,6.381 3.878,0 7.028,-2.861 7.028,-6.381 V 6.381 C 7.028,2.858 3.878,0 0,0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32031175"
+ id="path100-1"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g102-2"
+ transform="matrix(4.162611,0,0,-4.162611,634.78706,625.67104)"
+ style="stroke-width:0.32031175">
+ <path
+ d="m 0,0 c 0,-12.052 9.765,-21.815 21.815,-21.815 12.041,0 21.808,9.763 21.808,21.815 0,12.044 -9.767,21.802 -21.808,21.802 C 9.765,21.802 0,12.044 0,0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32031175"
+ id="path104-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g106-0"
+ transform="matrix(4.162611,0,0,-4.162611,656.64056,631.05679)"
+ style="stroke-width:0.32031175">
+ <path
+ d="m 0,0 c 0,-7.994 6.477,-14.473 14.471,-14.473 8.002,0 14.479,6.479 14.479,14.473 0,7.994 -6.477,14.479 -14.479,14.479 C 6.477,14.479 0,7.994 0,0"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.32031175"
+ id="path108-9"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g78-3"
+ transform="matrix(4.1626558,0,0,-4.1626558,918.83083,771.66929)"
+ style="fill:#000000;fill-opacity:0.527344;stroke:none;stroke-width:10.0248;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/logo_outlined.png b/logo_outlined.png
new file mode 100644
index 0000000000..44b85cde57
--- /dev/null
+++ b/logo_outlined.png
Binary files differ
diff --git a/logo_outlined.svg b/logo_outlined.svg
new file mode 100644
index 0000000000..4079a1dd56
--- /dev/null
+++ b/logo_outlined.svg
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg2"
+ version="1.1"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ xml:space="preserve"
+ width="1024"
+ height="414"
+ viewBox="0 0 960.00002 388.12499"
+ sodipodi:docname="logo_outlined.svg"
+ inkscape:export-filename="/home/riteo/srg/godot-riteo/logo_outlined.png"
+ inkscape:export-xdpi="48"
+ inkscape:export-ydpi="48"><metadata
+ id="metadata8"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs6"><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath16"><path
+ d="M 0,595.276 H 841.89 V 0 H 0 Z"
+ id="path18"
+ inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1916"
+ inkscape:window-height="1025"
+ id="namedview4"
+ showgrid="false"
+ inkscape:zoom="1.2041016"
+ inkscape:cx="512"
+ inkscape:cy="207"
+ inkscape:window-x="1360"
+ inkscape:window-y="53"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="g14"
+ fit-margin-top="48"
+ fit-margin-left="48"
+ fit-margin-right="48"
+ fit-margin-bottom="48"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="true"
+ inkscape:snap-intersection-paths="true"
+ inkscape:object-paths="true"
+ inkscape:snap-smooth-nodes="true"
+ inkscape:snap-midpoints="true"
+ inkscape:snap-bbox="false"
+ inkscape:bbox-paths="false"
+ inkscape:snap-bbox-edge-midpoints="false"
+ inkscape:snap-bbox-midpoints="false"
+ inkscape:object-nodes="true"
+ inkscape:snap-others="false"
+ units="px" /><g
+ id="g10"
+ inkscape:groupmode="layer"
+ inkscape:label="godot_engine_logo_2017_curves-01"
+ transform="matrix(1.25,0,0,-1.25,-94.249997,597.49874)"><g
+ id="g12"><g
+ id="g14"
+ clip-path="url(#clipPath16)"><g
+ id="g78-3"
+ transform="matrix(1.1310535,0,0,1.1310535,348.13118,279.26721)"
+ style="fill:none;stroke:#ffffff;stroke-width:15.5885606;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"><path
+ id="path80-6"
+ style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:23.50866089;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 226.33398,222.09961 c -15.35819,3.41427 -30.55118,8.16852 -44.79492,15.33789 0.32575,12.57731 1.13879,24.62813 2.78711,36.86914 -5.5316,3.54397 -11.34506,6.58567 -16.51172,10.73438 -5.24959,4.03861 -10.60984,7.90172 -15.36328,12.625 -9.49632,-6.28112 -19.54792,-12.18415 -29.90234,-17.39454 -11.16124,12.01179 -21.59792,24.97673 -30.123049,39.48438 6.699845,10.51682 13.887809,21.08874 20.542969,29.33203 0.0561,36.95701 -0.082,77.98955 0,113.01958 0,51.83844 65.75967,76.75448 147.46094,77.04102 h 0.0996 0.0996 c 81.70127,-0.28654 147.43945,-25.20258 147.43945,-77.04102 0.0505,-37.842 0.0165,-79.50966 0.0214,-113.01953 7.68652,-9.6765 14.96452,-20.35178 20.54102,-29.33203 -8.52211,-14.50765 -18.96376,-27.47259 -30.125,-39.48438 -10.3514,5.21039 -20.40602,11.11342 -29.90234,17.39454 -4.75194,-4.72328 -10.1042,-8.58639 -15.36133,-12.625 -5.16515,-4.14871 -10.98481,-7.19041 -16.50586,-10.73438 1.6438,-12.24101 2.45595,-24.29183 2.7832,-36.86914 -14.24524,-7.16937 -29.43699,-11.92362 -44.80273,-15.33789 -6.13484,10.31068 -11.74471,21.47716 -16.63086,32.39258 -5.79401,-0.96818 -11.61467,-1.32712 -17.44336,-1.39649 v -0.01 c -0.0407,0 -0.0786,0.01 -0.11328,0.01 -0.0362,0 -0.0732,-0.01 -0.10938,-0.01 v 0.01 c -5.83925,0.0694 -11.65565,0.42831 -17.45117,1.39649 -4.88313,-10.91542 -10.49088,-22.0819 -16.63477,-32.39258 z"
+ transform="matrix(0.66309862,0,0,-0.66309862,-270.58935,290.52015)"
+ sodipodi:nodetypes="ccccccccccccccccccccccccsccccc" /></g><g
+ id="g20"
+ transform="matrix(1.1310535,0,0,1.1310535,531.44953,355.31567)"
+ style="stroke:none;stroke-width:10.60874228;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g24"
+ transform="matrix(1.1310535,0,0,1.1310535,607.8515,354.43097)"
+ style="stroke:none;stroke-width:10.60874228;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g28"
+ transform="matrix(1.1310535,0,0,1.1310535,700.81066,355.31567)"
+ style="stroke:none;stroke-width:10.60874228;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g32"
+ transform="matrix(1.1310535,0,0,1.1310535,789.01132,291.33514)"
+ style="stroke:none;stroke-width:10.60874228;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g36"
+ transform="matrix(1.1310535,0,0,1.1310535,468.26549,336.71278)"
+ style="stroke:none;stroke-width:10.60874228;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"><path
+ id="path38"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:15.5885606;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
+ d="m 0,0 c -6.078,0.094 -13.034,-1.173 -13.034,-1.173 v -11.863 h 6.995 l -0.078,-5.288 c 0,-1.959 -1.942,-2.943 -5.815,-2.943 -3.878,0 -7.303,1.642 -10.274,4.917 -2.978,3.279 -4.459,8.072 -4.459,14.388 0,6.329 1.447,10.995 4.345,14.006 2.892,3.008 6.683,4.517 11.346,4.517 1.959,0 3.987,-0.316 6.096,-0.961 2.11,-0.639 3.519,-1.238 4.238,-1.799 0.713,-0.577 1.391,-0.85 2.032,-0.85 0.638,0 1.671,0.746 3.1,2.255 1.431,1.505 2.713,3.786 3.844,6.827 1.126,3.057 1.69,5.4 1.69,7.062 0,1.649 -0.036,2.786 -0.109,3.386 -1.581,1.73 -4.499,3.102 -8.755,4.122 -4.248,1.017 -9.011,1.522 -14.28,1.522 -11.594,0 -20.66,-3.65 -27.207,-10.95 -6.552,-7.303 -9.822,-16.783 -9.822,-28.452 0,-13.701 3.347,-24.087 10.041,-31.162 6.706,-7.074 15.51,-10.607 26.425,-10.607 5.87,0 11.08,0.505 15.632,1.522 4.557,1.013 7.586,2.053 9.093,3.105 l 0.452,35.33 C 11.496,-1.036 6.078,-0.104 0,0 m 283.58148,-40.1198 c 0,-1.496 -3.721,-2.255 -11.176,-2.255 -7.448,0 -11.18,0.759 -11.18,2.255 v 56.681 h -13.545 c -1.281,0 -2.185,1.727 -2.71,5.198 -0.226,1.652 -0.334,3.343 -0.334,5.077 0,1.724 0.108,3.422 0.334,5.077 0.525,3.462 1.429,5.202 2.71,5.202 h 49.112 c 1.279,0 2.179,-1.74 2.712,-5.202 0.221,-1.655 0.335,-3.353 0.335,-5.077 0,-1.734 -0.114,-3.425 -0.335,-5.077 -0.533,-3.471 -1.433,-5.198 -2.712,-5.198 h -13.211 z M 205.6005,16.447401 c -3.612,0 -6.645,-1.659 -9.095,-4.967 -2.44,-3.3110004 -3.662,-7.9580004 -3.662,-13.9380004 0,-5.993 1.169,-10.5809996 3.499,-13.7779996 2.33,-3.207 5.398,-4.804 9.2,-4.804 3.801,0 6.89,1.617 9.258,4.862 2.372,3.233 3.56,7.8609996 3.56,13.8859996 0,6.02 -1.225,10.654 -3.671,13.8900004 -2.447,3.232 -5.473,4.849 -9.089,4.849 m -0.058,-59.493 c -10.577,0 -19.193,3.46 -25.851,10.379 -6.663,6.925 -9.993,17.03 -9.993,30.3139996 0,13.2920004 3.367,23.3560004 10.1,30.2090004 6.741,6.844 15.431,10.269 26.086,10.269 10.651,0 19.246,-3.363 25.797,-10.109 6.55,-6.733 9.822,-16.94 9.822,-30.5910004 0,-13.6609996 -3.349,-23.8219996 -10.05,-30.4899996 -6.699,-6.654 -15.338,-9.981 -25.911,-9.981 m -82.13011,58.710808 v -33.768 c 0,-1.577 0.116,-2.571 0.342,-2.988 0.224,-0.415 0.903,-0.623 2.029,-0.623 4.144,0 7.283,1.548 9.429,4.634 2.151,3.083 3.215,8.2160005 3.215,15.4050005 0,7.192 -1.113,11.8779995 -3.325,14.0549995 -2.223,2.183 -5.744,3.285 -10.561,3.285 z m -21.675,-52.392 v 67.735 c 0,1.883 0.468,3.369 1.413,4.471 0.939,1.085 2.161,1.636 3.671,1.636 h 18.854 c 11.965,0 21.053,-3.018 27.257,-9.04 6.215,-6.02 9.322,-15.499 9.322,-28.44699953 0,-27.70000047 -11.821,-41.54700047 -35.456,-41.54700047 h -19.302 c -3.836,0 -5.759,1.727 -5.759,5.192 M 55.862999,16.447401 c -3.611,0 -6.636,-1.659 -9.09,-4.967 -2.441,-3.3110004 -3.668,-7.9580004 -3.668,-13.9380004 0,-5.993 1.166,-10.5809996 3.503,-13.7779996 2.333,-3.207 5.398,-4.804 9.2,-4.804 3.8,0 6.887,1.617 9.258,4.862 2.371,3.233 3.559,7.8609996 3.559,13.8859996 0,6.02 -1.227,10.654 -3.673,13.8900004 -2.443,3.232 -5.473,4.849 -9.089,4.849 m -0.055,-59.493 c -10.573,0 -19.195,3.46 -25.859,10.379 -6.655,6.925 -9.984,17.03 -9.984,30.3139996 0,13.2920004 3.367,23.3560004 10.101,30.2090004 6.736,6.844 15.431,10.269 26.082,10.269 10.649,0 19.251,-3.363 25.794,-10.109 6.555,-6.733 9.827,-16.94 9.827,-30.5910004 0,-13.6609996 -3.348,-23.8219996 -10.05,-30.4899996 -6.702,-6.654 -15.333,-9.981 -25.911,-9.981" /></g><g
+ id="g40"
+ transform="matrix(1.1310535,0,0,1.1310535,441.34721,235.75121)"
+ style="stroke:none;stroke-width:4.31066306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g44"
+ transform="matrix(1.1310535,0,0,1.1310535,456.01527,232.82495)"
+ style="stroke:none;stroke-width:4.31066306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g48"
+ transform="matrix(1.1310535,0,0,1.1310535,476.7303,259.10521)"
+ style="stroke:none;stroke-width:4.31066306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g52"
+ transform="matrix(1.1310535,0,0,1.1310535,522.82277,256.83868)"
+ style="stroke:none;stroke-width:4.31066306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g56"
+ transform="matrix(1.1310535,0,0,1.1310535,558.0805,256.83868)"
+ style="stroke:none;stroke-width:4.31066306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g60"
+ transform="matrix(1.1310535,0,0,1.1310535,575.91679,259.10521)"
+ style="stroke:none;stroke-width:4.31066306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g64"
+ transform="matrix(1.1310535,0,0,1.1310535,600.8685,242.30884)"
+ style="stroke:none;stroke-width:4.31066306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g70"
+ transform="matrix(1.1310535,0,0,1.1310535,638.15379,259.10521)"
+ style="stroke:none;stroke-width:4.31066306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" /><g
+ id="g74"
+ transform="matrix(1.1310535,0,0,1.1310535,669.70883,256.83868)"
+ style="stroke:none;stroke-width:4.31066306;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"><path
+ id="path76"
+ style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:15.5885606;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
+ d="M 0,0 C -1.763,0 -3.208,-0.802 -4.334,-2.402 -5.463,-4.008 -6.052,-5.987 -6.102,-8.346 H 5.56 v 1.082 c 0,2.086 -0.486,3.823 -1.47,5.201 C 3.109,-0.684 1.747,0 0,0 m 0.401,-23.76 c -2.733,0 -4.958,1.026 -6.681,3.073 -1.73,2.043 -2.595,4.657 -2.595,7.841 v 4.197 c 0,3.19 0.865,5.85 2.6,7.965 1.739,2.105 3.831,3.158 6.275,3.158 2.646,0 4.706,-0.939 6.172,-2.823 1.462,-1.887 2.195,-4.422 2.195,-7.603 v -2.773 H -6.102 v -2.102 c 0,-2.447 0.59,-4.484 1.757,-6.11 1.166,-1.63 2.748,-2.438 4.746,-2.438 1.382,0 2.579,0.244 3.578,0.724 1.012,0.491 1.869,1.179 2.591,2.082 l 1.147,-1.988 c -0.769,-0.968 -1.755,-1.75 -2.962,-2.33 -1.203,-0.577 -2.658,-0.873 -4.354,-0.873 m -28.299804,25.7639105 0.23,-4.178 c 0.676,1.48300001 1.562,2.63400001 2.678,3.435 1.115,0.805 2.422,1.213 3.916,1.213 2.258,0 3.995,-0.835 5.199,-2.51299999 1.211,-1.67500001 1.807,-4.27900001 1.807,-7.81200001 V -23.271089 h -2.825 v 15.3939995 c 0,2.888 -0.422,4.905 -1.261,6.075 -0.843,1.17000001 -2.063,1.75300001 -3.668,1.75300001 -1.434,0 -2.635,-0.466 -3.599,-1.41400001 -0.967,-0.939 -1.692,-2.19 -2.171,-3.767 V -23.271089 h -2.809 V 2.0039105 Z m -9.133591,-25.2752055 h -2.830008 V 2.0037072 h 2.830008 z m 0,32.4710013 h -2.830008 v 3.9819957 h 2.830008 z M -60.863903,-12.846289 c 0,-2.565 0.486,-4.605 1.472,-6.123 0.974,-1.532 2.457,-2.288 4.436,-2.288 1.356,0 2.498,0.361 3.435,1.101 0.934,0.74 1.672,1.77 2.218,3.077 v 12.5200001 c -0.525,1.346 -1.246,2.434 -2.157,3.272 -0.91,0.82400002 -2.062,1.23800002 -3.448,1.23800002 -1.975,0 -3.468,-0.86 -4.46,-2.58700002 -0.999,-1.73 -1.496,-3.986 -1.496,-6.756 z m -2.833,3.4540001 c 0,3.582 0.723,6.459 2.177,8.62700002 1.442,2.15699998 3.448,3.23899998 6.004,3.23899998 1.419,0 2.664,-0.346 3.728,-1.04 1.066,-0.68099998 1.947,-1.67799998 2.654,-2.946 l 0.274,3.516 h 2.381 V -23.294289 c 0,-3.239 -0.751,-5.749 -2.26,-7.525 -1.511,-1.769 -3.657,-2.665 -6.428,-2.665 -0.996,0 -2.067,0.156 -3.212,0.459 -1.147,0.303 -2.162,0.701 -3.052,1.2 l 0.776,2.463 c 0.759,-0.492 1.608,-0.873 2.548,-1.141 0.932,-0.277 1.895,-0.41 2.894,-0.41 2.009,0 3.498,0.645 4.46,1.932 0.966,1.304 1.45,3.19 1.45,5.687 v 3.057 c -0.717,-1.138 -1.597,-2.011 -2.64,-2.614 -1.039,-0.606 -2.253,-0.909 -3.622,-0.909 -2.539,0 -4.53,0.994 -5.968,2.982 -1.441,1.984 -2.164,4.631 -2.164,7.932 z m -19.227592,11.3961994 0.23,-4.178 c 0.674,1.48300001 1.564,2.63400001 2.682,3.435 1.108,0.805 2.413,1.213 3.914,1.213 2.258,0 3.988,-0.835 5.189,-2.51299999 1.214,-1.67500001 1.815,-4.27900001 1.815,-7.81200001 V -23.271089 h -2.825 v 15.3939995 c 0,2.888 -0.423,4.905 -1.264,6.075 -0.836,1.17000001 -2.065,1.75300001 -3.665,1.75300001 -1.435,0 -2.638,-0.466 -3.603,-1.41400001 -0.969,-0.939 -1.691,-2.19 -2.172,-3.767 V -23.271089 h -2.805 V 2.0039105 Z M -98.69412,0 c -1.763,0 -3.21,-0.802 -4.341,-2.402 -1.126,-1.606 -1.712,-3.585 -1.763,-5.944 h 11.663 v 1.082 c 0,2.086 -0.488,3.823 -1.474,5.201 -0.981,1.379 -2.341,2.063 -4.085,2.063 m 0.394,-23.76 c -2.726,0 -4.951,1.026 -6.679,3.073 -1.733,2.043 -2.6,4.657 -2.6,7.841 v 4.197 c 0,3.19 0.871,5.85 2.602,7.965 1.744,2.105 3.834,3.158 6.283,3.158 2.643,0 4.703,-0.939 6.164,-2.823 1.463,-1.887 2.197,-4.422 2.197,-7.603 v -2.773 h -14.465 v -2.102 c 0,-2.447 0.587,-4.484 1.76,-6.11 1.162,-1.63 2.742,-2.438 4.738,-2.438 1.387,0 2.585,0.244 3.585,0.724 1.007,0.491 1.866,1.179 2.589,2.082 l 1.141,-1.988 c -0.764,-0.968 -1.75,-1.75 -2.959,-2.33 -1.204,-0.577 -2.658,-0.873 -4.356,-0.873 M -129.86659,0 c -1.758,0 -3.202,-0.802 -4.334,-2.402 -1.133,-1.606 -1.718,-3.585 -1.765,-5.944 h 11.66 v 1.082 c 0,2.086 -0.489,3.823 -1.469,5.201 -0.986,1.379 -2.347,2.063 -4.092,2.063 m 0.397,-23.76 c -2.725,0 -4.954,1.026 -6.685,3.073 -1.726,2.043 -2.591,4.657 -2.591,7.841 v 4.197 c 0,3.19 0.867,5.85 2.602,7.965 1.739,2.105 3.828,3.158 6.277,3.158 2.648,0 4.699,-0.939 6.164,-2.823 1.468,-1.887 2.201,-4.422 2.201,-7.603 v -2.773 h -14.464 v -2.102 c 0,-2.447 0.586,-4.484 1.752,-6.11 1.168,-1.63 2.755,-2.438 4.744,-2.438 1.382,0 2.585,0.244 3.588,0.724 1.003,0.491 1.863,1.179 2.578,2.082 l 1.149,-1.988 c -0.763,-0.968 -1.752,-1.75 -2.959,-2.33 -1.204,-0.577 -2.659,-0.873 -4.356,-0.873 m -41.1488,25.7639105 0.24,-3.923 c 0.664,1.40400001 1.554,2.48600001 2.657,3.255 1.107,0.759 2.41,1.138 3.906,1.138 1.527,0 2.814,-0.444 3.852,-1.343 1.039,-0.89599999 1.805,-2.252 2.292,-4.074 0.623,1.682 1.505,3.01100001 2.65,3.973 1.145,0.964 2.534,1.444 4.143,1.444 2.217,0 3.937,-0.897 5.156,-2.69199999 1.224,-1.79900001 1.834,-4.55900001 1.834,-8.28800001 V -23.271089 h -2.823 v 14.8139995 c 0,3.1 -0.429,5.283 -1.263,6.538 -0.839,1.25700001 -2.042,1.89000001 -3.598,1.89000001 -1.637,0 -2.915,-0.691 -3.834,-2.09600001 -0.914,-1.405 -1.478,-3.161 -1.683,-5.282 v -0.655 -15.2089995 h -2.809 v 14.7979995 c 0,3.027 -0.424,5.194 -1.292,6.488 -0.864,1.29400001 -2.066,1.93600001 -3.609,1.93600001 -1.475,0 -2.668,-0.45 -3.562,-1.34200001 -0.9,-0.897 -1.54,-2.125 -1.928,-3.683 V -23.271089 h -2.806 V 2.0039105 Z M -188.9332,-21.231295 c 1.553,0 2.936,0.44 4.144,1.336 1.21,0.9 2.058,2.037 2.561,3.422 v 5.468 h -4.492 c -1.91,0 -3.44,-0.541 -4.585,-1.623 -1.148,-1.075 -1.716,-2.418 -1.716,-4.015 0,-1.349 0.355,-2.457 1.074,-3.311 0.718,-0.857 1.722,-1.277 3.014,-1.277 m 7.124,-2.04 c -0.14,0.876 -0.249,1.587 -0.318,2.144 -0.067,0.567 -0.101,1.131 -0.101,1.704 -0.767,-1.254 -1.757,-2.294 -2.98,-3.109 -1.221,-0.821 -2.579,-1.228 -4.075,-1.228 -2.092,0 -3.701,0.648 -4.84,1.946 -1.132,1.303 -1.704,3.059 -1.704,5.276 0,2.343 0.823,4.223 2.473,5.618 1.649,1.3950005 3.89,2.0920005 6.709,2.0920005 h 4.417 v 3.106 c 0,1.786 -0.456,3.193 -1.351,4.21 -0.914,1.00399996 -2.17,1.51199995911 -3.791,1.51199995911 -1.508,0 -2.752,-0.47899999911 -3.728,-1.44999995911 -0.973,-0.965 -1.456,-2.144 -1.456,-3.549 l -2.623,0.023 -0.046,0.137 c -0.074,1.906 0.647,3.591 2.168,5.08399996 1.515,1.48900004 3.459,2.22900004 5.825,2.22900004 2.338,0 4.22,-0.711 5.657,-2.12800004 1.429,-1.43099996 2.146,-3.47099996 2.146,-6.12399996 V -18.174295 c 0,-0.903 0.042,-1.78 0.121,-2.617 0.081,-0.848 0.212,-1.665 0.417,-2.48 z m -20.0925,4.627199 c -0.624,-1.28 -1.771,-2.454 -3.449,-3.516 -1.676,-1.069 -3.805,-1.6 -6.391,-1.6 -3.412,0 -6.156,1.075 -8.24,3.249 -2.076,2.157 -3.116,5.266 -3.116,9.323 v 10.116 c 0,3.969 0.98,7.013 2.946,9.138 1.962,2.108 4.59,3.177 7.872,3.177 3.208,0 5.695,-0.844 7.455,-2.513 1.755,-1.675 2.677,-4.015 2.757,-7.003 l -0.044,-0.133 h -2.619 c -0.094,2.29 -0.759,4.057 -2.01,5.305 -1.244,1.238 -3.095,1.864 -5.539,1.864 -2.473,0 -4.432,-0.837 -5.866,-2.516 -1.43,-1.675 -2.143,-4.103 -2.143,-7.293 v -10.174 c 0,-3.308 0.771,-5.83 2.311,-7.567 1.54,-1.724 3.616,-2.588 6.236,-2.588 1.913,0 3.451,0.339 4.602,1.033 1.155,0.684 1.956,1.519 2.409,2.51 v 8.861 h -7.06 v 2.463 h 9.889 z" /></g><g
+ id="g78"
+ transform="matrix(1.1310535,0,0,1.1310535,348.13109,279.2668)"
+ style="stroke-width:0.884131"><path
+ d="m 0,0 c 0,0 -0.325,1.994 -0.515,1.976 l -36.182,-3.491 c -2.879,-0.278 -5.115,-2.574 -5.317,-5.459 l -0.994,-14.247 -27.992,-1.997 -1.904,12.912 c -0.424,2.872 -2.932,5.037 -5.835,5.037 h -38.188 c -2.902,0 -5.41,-2.165 -5.834,-5.037 l -1.905,-12.912 -27.992,1.997 -0.994,14.247 c -0.202,2.886 -2.438,5.182 -5.317,5.46 l -36.2,3.49 c -0.187,0.018 -0.324,-1.978 -0.511,-1.978 l -0.049,-7.83 30.658,-4.944 1.004,-14.374 c 0.203,-2.91 2.551,-5.263 5.463,-5.472 l 38.551,-2.75 c 0.146,-0.01 0.29,-0.016 0.434,-0.016 2.897,0 5.401,2.166 5.825,5.038 l 1.959,13.286 h 28.005 l 1.959,-13.286 c 0.423,-2.871 2.93,-5.037 5.831,-5.037 0.142,0 0.284,0.005 0.423,0.015 l 38.556,2.75 c 2.911,0.209 5.26,2.562 5.463,5.472 l 1.003,14.374 30.645,4.966 z"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.884131"
+ id="path80"
+ inkscape:connector-curvature="0" /></g><g
+ id="g82"
+ transform="matrix(1.1310535,0,0,1.1310535,126.80608,346.04533)"
+ style="stroke-width:0.884131"><path
+ d="m 0,0 v -47.514 -6.035 -5.492 c 0.108,-0.001 0.216,-0.005 0.323,-0.015 l 36.196,-3.49 c 1.896,-0.183 3.382,-1.709 3.514,-3.609 l 1.116,-15.978 31.574,-2.253 2.175,14.747 c 0.282,1.912 1.922,3.329 3.856,3.329 h 38.188 c 1.933,0 3.573,-1.417 3.855,-3.329 l 2.175,-14.747 31.575,2.253 1.115,15.978 c 0.133,1.9 1.618,3.425 3.514,3.609 l 36.182,3.49 c 0.107,0.01 0.214,0.014 0.322,0.015 v 4.711 l 0.015,0.005 V 0 c 5.09692,6.4164715 9.92323,13.494208 13.621,19.449 -5.651,9.62 -12.575,18.217 -19.976,26.182 -6.864,-3.455 -13.531,-7.369 -19.828,-11.534 -3.151,3.132 -6.7,5.694 -10.186,8.372 -3.425,2.751 -7.285,4.768 -10.946,7.118 1.09,8.117 1.629,16.108 1.846,24.448 -9.446,4.754 -19.519,7.906 -29.708,10.17 -4.068,-6.837 -7.788,-14.241 -11.028,-21.479 -3.842,0.642 -7.702,0.88 -11.567,0.926 v 0.006 c -0.027,0 -0.052,-0.006 -0.075,-0.006 -0.024,0 -0.049,0.006 -0.073,0.006 V 63.652 C 93.903,63.606 90.046,63.368 86.203,62.726 82.965,69.964 79.247,77.368 75.173,84.205 64.989,81.941 54.915,78.789 45.47,74.035 45.686,65.695 46.225,57.704 47.318,49.587 43.65,47.237 39.795,45.22 36.369,42.469 32.888,39.791 29.333,37.229 26.181,34.097 19.884,38.262 13.219,42.176 6.353,45.631 -1.048,37.666 -7.968,29.069 -13.621,19.449 -9.1783421,12.475308 -4.4130298,5.4661124 0,0 Z"
+ style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.884131"
+ id="path84"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccsssscccccccccccccccccccsccccccccccc" /></g><g
+ id="g86"
+ transform="matrix(1.1310535,0,0,1.1310535,311.40329,266.88437)"
+ style="stroke-width:0.884131"><path
+ d="m 0,0 -1.121,-16.063 c -0.135,-1.936 -1.675,-3.477 -3.611,-3.616 l -38.555,-2.751 c -0.094,-0.007 -0.188,-0.01 -0.281,-0.01 -1.916,0 -3.569,1.406 -3.852,3.33 l -2.211,14.994 H -81.09 l -2.211,-14.994 c -0.297,-2.018 -2.101,-3.469 -4.133,-3.32 l -38.555,2.751 c -1.936,0.139 -3.476,1.68 -3.611,3.616 L -130.721,0 -163.268,3.138 c 0.015,-3.498 0.06,-7.33 0.06,-8.093 0,-34.374 43.605,-50.896 97.781,-51.086 h 0.066 0.067 c 54.176,0.19 97.766,16.712 97.766,51.086 0,0.777 0.047,4.593 0.063,8.093 z"
+ style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.884131"
+ id="path88"
+ inkscape:connector-curvature="0" /></g><g
+ id="g90"
+ transform="matrix(1.1310535,0,0,1.1310535,204.11393,318.93771)"
+ style="stroke-width:0.884131"><path
+ d="m 0,0 c 0,-12.052 -9.765,-21.815 -21.813,-21.815 -12.042,0 -21.81,9.763 -21.81,21.815 0,12.044 9.768,21.802 21.81,21.802 C -9.765,21.802 0,12.044 0,0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.884131"
+ id="path92"
+ inkscape:connector-curvature="0" /></g><g
+ id="g94"
+ transform="matrix(1.1310535,0,0,1.1310535,198.17748,317.47435)"
+ style="stroke-width:0.884131"><path
+ d="m 0,0 c 0,-7.994 -6.479,-14.473 -14.479,-14.473 -7.996,0 -14.479,6.479 -14.479,14.473 0,7.994 6.483,14.479 14.479,14.479 C -6.479,14.479 0,7.994 0,0"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.884131"
+ id="path96"
+ inkscape:connector-curvature="0" /></g><g
+ id="g98"
+ transform="matrix(1.1310535,0,0,1.1310535,237.47503,292.01909)"
+ style="stroke-width:0.884131"><path
+ d="m 0,0 c -3.878,0 -7.021,2.858 -7.021,6.381 v 20.081 c 0,3.52 3.143,6.381 7.021,6.381 3.878,0 7.028,-2.861 7.028,-6.381 V 6.381 C 7.028,2.858 3.878,0 0,0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.884131"
+ id="path100"
+ inkscape:connector-curvature="0" /></g><g
+ id="g102"
+ transform="matrix(1.1310535,0,0,1.1310535,270.84021,318.93771)"
+ style="stroke-width:0.884131"><path
+ d="m 0,0 c 0,-12.052 9.765,-21.815 21.815,-21.815 12.041,0 21.808,9.763 21.808,21.815 0,12.044 -9.767,21.802 -21.808,21.802 C 9.765,21.802 0,12.044 0,0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.884131"
+ id="path104"
+ inkscape:connector-curvature="0" /></g><g
+ id="g106"
+ transform="matrix(1.1310535,0,0,1.1310535,276.77813,317.47435)"
+ style="stroke-width:0.884131"><path
+ d="m 0,0 c 0,-7.994 6.477,-14.473 14.471,-14.473 8.002,0 14.479,6.479 14.479,14.473 0,7.994 -6.477,14.479 -14.479,14.479 C 6.477,14.479 0,7.994 0,0"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.884131"
+ id="path108"
+ inkscape:connector-curvature="0" /></g></g></g></g></svg>
diff --git a/main/main.cpp b/main/main.cpp
index bf7b88bdc9..667aebebae 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -36,6 +36,7 @@
#include "core/debugger/engine_debugger.h"
#include "core/input/input.h"
#include "core/input/input_map.h"
+#include "core/io/dir_access.h"
#include "core/io/file_access_network.h"
#include "core/io/file_access_pack.h"
#include "core/io/file_access_zip.h"
@@ -43,8 +44,8 @@
#include "core/io/ip.h"
#include "core/io/resource_loader.h"
#include "core/object/message_queue.h"
-#include "core/os/dir_access.h"
#include "core/os/os.h"
+#include "core/os/time.h"
#include "core/register_core_types.h"
#include "core/string/translation.h"
#include "core/version.h"
@@ -101,6 +102,7 @@ static InputMap *input_map = nullptr;
static TranslationServer *translation_server = nullptr;
static Performance *performance = nullptr;
static PackedData *packed_data = nullptr;
+static Time *time_singleton = nullptr;
#ifdef MINIZIP_ENABLED
static ZipArchive *zip_packed_data = nullptr;
#endif
@@ -135,6 +137,7 @@ static int audio_driver_idx = -1;
static bool single_window = false;
static bool editor = false;
static bool project_manager = false;
+static bool cmdline_tool = false;
static String locale;
static bool show_help = false;
static bool auto_quit = false;
@@ -183,6 +186,10 @@ bool Main::is_project_manager() {
return project_manager;
}
+bool Main::is_cmdline_tool() {
+ return cmdline_tool;
+}
+
static String unescape_cmdline(const String &p_str) {
return p_str.replace("%20", " ");
}
@@ -532,6 +539,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
MAIN_PRINT("Main: Initialize Globals");
input_map = memnew(InputMap);
+ time_singleton = memnew(Time);
globals = memnew(ProjectSettings);
register_core_settings(); //here globals are present
@@ -878,18 +886,25 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
auto_build_solutions = true;
editor = true;
+ cmdline_tool = true;
#ifdef DEBUG_METHODS_ENABLED
} else if (I->get() == "--gdnative-generate-json-api" || I->get() == "--gdnative-generate-json-builtin-api") {
// Register as an editor instance to use low-end fallback if relevant.
editor = true;
+ cmdline_tool = true;
// We still pass it to the main arguments since the argument handling itself is not done in this function
main_args.push_back(I->get());
#endif
} else if (I->get() == "--export" || I->get() == "--export-debug" ||
I->get() == "--export-pack") { // Export project
-
+ // Actually handling is done in start().
editor = true;
+ cmdline_tool = true;
+ main_args.push_back(I->get());
+ } else if (I->get() == "--doctool") {
+ // Actually handling is done in start().
+ cmdline_tool = true;
main_args.push_back(I->get());
#endif
} else if (I->get() == "--path") { // set path of project to start or edit
@@ -1122,8 +1137,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
if (!project_manager && !editor) {
- // Determine if the project manager should be requested
- project_manager = main_args.size() == 0 && !found_project;
+ // If we didn't find a project, we fall back to the project manager.
+ project_manager = !found_project && !cmdline_tool;
}
#endif
@@ -1253,6 +1268,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
GLOBAL_DEF("internationalization/rendering/force_right_to_left_layout_direction", false);
+ GLOBAL_DEF("internationalization/locale/include_text_server_data", false);
if (!force_lowdpi) {
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
@@ -1326,35 +1342,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") {
- window_orientation = DisplayServer::SCREEN_PORTRAIT;
- } else if (orientation == "reverse_landscape") {
- window_orientation = DisplayServer::SCREEN_REVERSE_LANDSCAPE;
- } else if (orientation == "reverse_portrait") {
- window_orientation = DisplayServer::SCREEN_REVERSE_PORTRAIT;
- } else if (orientation == "sensor_landscape") {
- window_orientation = DisplayServer::SCREEN_SENSOR_LANDSCAPE;
- } else if (orientation == "sensor_portrait") {
- window_orientation = DisplayServer::SCREEN_SENSOR_PORTRAIT;
- } else if (orientation == "sensor") {
- window_orientation = DisplayServer::SCREEN_SENSOR;
- } else {
- window_orientation = DisplayServer::SCREEN_LANDSCAPE;
- }
+ window_orientation = DisplayServer::ScreenOrientation(int(GLOBAL_DEF_BASIC("display/window/handheld/orientation", DisplayServer::ScreenOrientation::SCREEN_LANDSCAPE)));
}
Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF_BASIC("physics/common/physics_fps", 60));
ProjectSettings::get_singleton()->set_custom_property_info("physics/common/physics_fps",
PropertyInfo(Variant::INT, "physics/common/physics_fps",
- PROPERTY_HINT_RANGE, "1,120,1,or_greater"));
+ PROPERTY_HINT_RANGE, "1,1000,1"));
Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
Engine::get_singleton()->set_target_fps(GLOBAL_DEF("debug/settings/fps/force_fps", 0));
ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/fps/force_fps",
PropertyInfo(Variant::INT,
"debug/settings/fps/force_fps",
- PROPERTY_HINT_RANGE, "0,120,1,or_greater"));
+ PROPERTY_HINT_RANGE, "0,1000,1"));
GLOBAL_DEF("debug/settings/stdout/print_fps", false);
GLOBAL_DEF("debug/settings/stdout/verbose_stdout", false);
@@ -1417,6 +1417,9 @@ error:
if (input_map) {
memdelete(input_map);
}
+ if (time_singleton) {
+ memdelete(time_singleton);
+ }
if (translation_server) {
memdelete(translation_server);
}
@@ -1460,6 +1463,12 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
}
#endif
+#ifdef TOOLS_ENABLED
+ if (editor || project_manager || cmdline_tool) {
+ EditorPaths::create();
+ }
+#endif
+
/* Determine text driver */
if (text_driver == "") {
@@ -1580,7 +1589,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
print_verbose("Using \"" + tablet_driver + "\" pen tablet driver...");
- /* Initialize Visual Server */
+ /* Initialize Rendering Server */
rendering_server = memnew(RenderingServerDefault(OS::get_singleton()->get_render_thread_mode() == OS::RENDER_SEPARATE_THREAD));
@@ -1831,13 +1840,13 @@ bool Main::start() {
ERR_FAIL_COND_V(!_start_success, false);
bool hasicon = false;
- String doc_tool_path;
String positional_arg;
String game_path;
String script;
bool check_only = false;
#ifdef TOOLS_ENABLED
+ String doc_tool_path;
bool doc_base = true;
String _export_preset;
bool export_debug = false;
@@ -1847,8 +1856,9 @@ bool Main::start() {
main_timer_sync.init(OS::get_singleton()->get_ticks_usec());
List<String> args = OS::get_singleton()->get_cmdline_args();
- // parameters that do not have an argument to the right
for (int i = 0; i < args.size(); i++) {
+ // First check parameters that do not have an argument to the right.
+
// Doctest Unit Testing Handler
// Designed to override and pass arguments to the unit test handler.
if (args[i] == "--check-only") {
@@ -1878,7 +1888,7 @@ bool Main::start() {
game_path = args[i];
}
}
- //parameters that have an argument to the right
+ // Then parameters that have an argument to the right.
else if (i < (args.size() - 1)) {
bool parsed_pair = true;
if (args[i] == "-s" || args[i] == "--script") {
@@ -1910,16 +1920,19 @@ bool Main::start() {
if (parsed_pair) {
i++;
}
- } else if (args[i] == "--doctool") {
- // Handle case where no path is given to --doctool.
+ }
+#ifdef TOOLS_ENABLED
+ // Handle case where no path is given to --doctool.
+ else if (args[i] == "--doctool") {
doc_tool_path = ".";
}
+#endif
}
#ifdef TOOLS_ENABLED
if (doc_tool_path != "") {
- Engine::get_singleton()->set_editor_hint(
- true); // Needed to instance editor-only classes for their default values
+ // Needed to instance editor-only classes for their default values
+ Engine::get_singleton()->set_editor_hint(true);
{
DirAccessRef da = DirAccess::open(doc_tool_path);
@@ -1991,17 +2004,26 @@ bool Main::start() {
return false;
}
-
#endif
if (script == "" && game_path == "" && String(GLOBAL_GET("application/run/main_scene")) != "") {
game_path = GLOBAL_GET("application/run/main_scene");
}
+#ifdef TOOLS_ENABLED
+ if (!editor && !project_manager && !cmdline_tool && script == "" && game_path == "") {
+ // If we end up here, it means we didn't manage to detect what we want to run.
+ // Let's throw an error gently. The code leading to this is pretty brittle so
+ // this might end up triggered by valid usage, in which case we'll have to
+ // fine-tune further.
+ ERR_FAIL_V_MSG(false, "Couldn't detect whether to run the editor, the project manager or a specific project. Aborting.");
+ }
+#endif
+
MainLoop *main_loop = nullptr;
if (editor) {
main_loop = memnew(SceneTree);
- };
+ }
String main_loop_type = GLOBAL_DEF("application/run/main_loop_type", "SceneTree");
if (script != "") {
@@ -2251,7 +2273,7 @@ bool Main::start() {
ProjectSettings::get_singleton()->set_custom_property_info(
"rendering/textures/canvas_textures/default_texture_filter",
PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM,
- "Nearest,Linear,MipmapLinear,MipmapNearest"));
+ "Nearest,Linear,Linear Mipmap,Nearest Mipmap"));
GLOBAL_DEF_BASIC("rendering/textures/canvas_textures/default_texture_repeat", 0);
ProjectSettings::get_singleton()->set_custom_property_info(
"rendering/textures/canvas_textures/default_texture_repeat",
@@ -2363,14 +2385,13 @@ bool Main::start() {
}
#ifdef TOOLS_ENABLED
- if (project_manager || (script == "" && game_path == "" && !editor)) {
+ if (project_manager) {
Engine::get_singleton()->set_editor_hint(true);
ProjectManager *pmanager = memnew(ProjectManager);
ProgressDialog *progress_dialog = memnew(ProgressDialog);
pmanager->add_child(progress_dialog);
sml->get_root()->add_child(pmanager);
DisplayServer::get_singleton()->set_context(DisplayServer::CONTEXT_PROJECTMAN);
- project_manager = true;
}
if (project_manager || editor) {
@@ -2382,10 +2403,8 @@ bool Main::start() {
}
// Load SSL Certificates from Editor Settings (or builtin)
- Crypto::load_default_certificates(EditorSettings::get_singleton()->get_setting(
- "network/ssl/editor_ssl_certificates")
- .
- operator String());
+ Crypto::load_default_certificates(
+ EditorSettings::get_singleton()->get_setting("network/ssl/editor_ssl_certificates").operator String());
}
#endif
}
@@ -2676,6 +2695,9 @@ void Main::cleanup(bool p_force) {
if (input_map) {
memdelete(input_map);
}
+ if (time_singleton) {
+ memdelete(time_singleton);
+ }
if (translation_server) {
memdelete(translation_server);
}
diff --git a/main/main.h b/main/main.h
index f4fff6b97e..84077137ba 100644
--- a/main/main.h
+++ b/main/main.h
@@ -45,6 +45,7 @@ class Main {
public:
static bool is_project_manager();
+ static bool is_cmdline_tool();
static int test_entrypoint(int argc, char *argv[], bool &tests_need_run);
static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true);
static Error setup2(Thread::ID p_main_tid_override = 0);
diff --git a/methods.py b/methods.py
index 6f1e7a7279..1afd1ca0d4 100644
--- a/methods.py
+++ b/methods.py
@@ -787,9 +787,18 @@ def get_compiler_version(env):
return None
else: # TODO: Implement for MSVC
return None
- match = re.search("[0-9]+\.[0-9.]+", version)
+ match = re.search(
+ "(?:(?<=version )|(?<=\) )|(?<=^))"
+ "(?P<major>\d+)"
+ "(?:\.(?P<minor>\d*))?"
+ "(?:\.(?P<patch>\d*))?"
+ "(?:-(?P<metadata1>[0-9a-zA-Z-]*))?"
+ "(?:\+(?P<metadata2>[0-9a-zA-Z-]*))?"
+ "(?: (?P<date>[0-9]{8}|[0-9]{6})(?![0-9a-zA-Z]))?",
+ version,
+ )
if match is not None:
- return list(map(int, match.group().split(".")))
+ return match.groupdict()
else:
return None
diff --git a/misc/dist/html/fixed-size.html b/misc/dist/html/fixed-size.html
deleted file mode 100644
index 9d0a946497..0000000000
--- a/misc/dist/html/fixed-size.html
+++ /dev/null
@@ -1,389 +0,0 @@
-<!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
-<head>
- <meta charset="utf-8" />
- <link id='-gd-engine-icon' rel='icon' type='image/png' href='favicon.png' />
- <title>$GODOT_PROJECT_NAME</title>
- <style type="text/css">
-
- body {
- margin: 0;
- border: 0 none;
- padding: 0;
- text-align: center;
- background-color: #222226;
- font-family: 'Noto Sans', Arial, sans-serif;
- }
-
-
- /* Godot Engine default theme style
- * ================================ */
-
- .godot {
- color: #e0e0e0;
- background-color: #3b3943;
- background-image: linear-gradient(to bottom, #403e48, #35333c);
- border: 1px solid #45434e;
- box-shadow: 0 0 1px 1px #2f2d35;
- }
-
- button.godot {
- font-family: 'Droid Sans', Arial, sans-serif; /* override user agent style */
- padding: 1px 5px;
- background-color: #37353f;
- background-image: linear-gradient(to bottom, #413e49, #3a3842);
- border: 1px solid #514f5d;
- border-radius: 1px;
- box-shadow: 0 0 1px 1px #2a2930;
- }
-
- button.godot:hover {
- color: #f0f0f0;
- background-color: #44414e;
- background-image: linear-gradient(to bottom, #494652, #423f4c);
- border: 1px solid #5a5667;
- box-shadow: 0 0 1px 1px #26252b;
- }
-
- button.godot:active {
- color: #fff;
- background-color: #3e3b46;
- background-image: linear-gradient(to bottom, #36343d, #413e49);
- border: 1px solid #4f4c59;
- box-shadow: 0 0 1px 1px #26252b;
- }
-
- button.godot:disabled {
- color: rgba(230, 230, 230, 0.2);
- background-color: #3d3d3d;
- background-image: linear-gradient(to bottom, #434343, #393939);
- border: 1px solid #474747;
- box-shadow: 0 0 1px 1px #2d2b33;
- }
-
-
- /* Canvas / wrapper
- * ================ */
-
- #container {
- display: inline-block; /* scale with canvas */
- vertical-align: top; /* prevent extra height */
- position: relative; /* root for absolutely positioned overlay */
- margin: 0;
- border: 0 none;
- padding: 0;
- background-color: #0c0c0c;
- }
-
- #canvas {
- display: block;
- margin: 0 auto;
- color: white;
- }
-
- #canvas:focus {
- outline: none;
- }
-
-
- /* Status display
- * ============== */
-
- #status {
- position: absolute;
- left: 0;
- top: 0;
- right: 0;
- bottom: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- /* don't consume click events - make children visible explicitly */
- visibility: hidden;
- }
-
- #status-progress {
- width: 244px;
- height: 7px;
- background-color: #38363A;
- border: 1px solid #444246;
- padding: 1px;
- box-shadow: 0 0 2px 1px #1B1C22;
- border-radius: 2px;
- visibility: visible;
- }
-
- #status-progress-inner {
- height: 100%;
- width: 0;
- box-sizing: border-box;
- transition: width 0.5s linear;
- background-color: #202020;
- border: 1px solid #222223;
- box-shadow: 0 0 1px 1px #27282E;
- border-radius: 3px;
- }
-
- #status-indeterminate {
- visibility: visible;
- position: relative;
- }
-
- #status-indeterminate > div {
- width: 3px;
- height: 0;
- border-style: solid;
- border-width: 6px 2px 0 2px;
- border-color: #2b2b2b transparent transparent transparent;
- transform-origin: center 14px;
- position: absolute;
- }
-
- #status-indeterminate > div:nth-child(1) { transform: rotate( 22.5deg); }
- #status-indeterminate > div:nth-child(2) { transform: rotate( 67.5deg); }
- #status-indeterminate > div:nth-child(3) { transform: rotate(112.5deg); }
- #status-indeterminate > div:nth-child(4) { transform: rotate(157.5deg); }
- #status-indeterminate > div:nth-child(5) { transform: rotate(202.5deg); }
- #status-indeterminate > div:nth-child(6) { transform: rotate(247.5deg); }
- #status-indeterminate > div:nth-child(7) { transform: rotate(292.5deg); }
- #status-indeterminate > div:nth-child(8) { transform: rotate(337.5deg); }
-
- #status-notice {
- margin: 0 100px;
- line-height: 1.3;
- visibility: visible;
- padding: 4px 6px;
- visibility: visible;
- }
-
-
- /* Debug output
- * ============ */
-
- #output-panel {
- display: none;
- max-width: 700px;
- font-size: small;
- margin: 6px auto 0;
- padding: 0 4px 4px;
- text-align: left;
- line-height: 2.2;
- }
-
- #output-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
-
- #output-container {
- padding: 6px;
- background-color: #2c2a32;
- box-shadow: inset 0 0 1px 1px #232127;
- color: #bbb;
- }
-
- #output-scroll {
- line-height: 1;
- height: 12em;
- overflow-y: scroll;
- white-space: pre-wrap;
- font-size: small;
- font-family: "Lucida Console", Monaco, monospace;
- }
- </style>
-$GODOT_HEAD_INCLUDE
-</head>
-<body>
- <div id="container">
- <canvas id="canvas" width="640" height="480">
- HTML5 canvas appears to be unsupported in the current browser.<br />
- Please try updating or use a different browser.
- </canvas>
- <div id="status">
- <div id='status-progress' style='display: none;' oncontextmenu="event.preventDefault();"><div id ='status-progress-inner'></div></div>
- <div id='status-indeterminate' style='display: none;' oncontextmenu="event.preventDefault();">
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- </div>
- <div id="status-notice" class="godot" style='display: none;'></div>
- </div>
- </div>
- <div id="output-panel" class="godot">
- <div id="output-header">
- Output:
- <button id='output-clear' class='godot' type='button' autocomplete='off'>Clear</button>
- </div>
- <div id="output-container"><div id="output-scroll"></div></div>
- </div>
-
- <script type="text/javascript" src="$GODOT_BASENAME.js"></script>
- <script type="text/javascript">//<![CDATA[
-
- var engine = new Engine;
-
- (function() {
- const EXECUTABLE_NAME = '$GODOT_BASENAME';
- const MAIN_PACK = '$GODOT_BASENAME.pck';
- const EXTRA_ARGS = JSON.parse('$GODOT_ARGS');
- const DEBUG_ENABLED = $GODOT_DEBUG_ENABLED;
- const INDETERMINATE_STATUS_STEP_MS = 100;
-
- var canvas = document.getElementById('canvas');
- var statusProgress = document.getElementById('status-progress');
- var statusProgressInner = document.getElementById('status-progress-inner');
- var statusIndeterminate = document.getElementById('status-indeterminate');
- var statusNotice = document.getElementById('status-notice');
-
- var initializing = true;
- var statusMode = 'hidden';
- var indeterminiateStatusAnimationId = 0;
-
- function setStatusMode(mode) {
- if (statusMode === mode || !initializing)
- return;
- [statusProgress, statusIndeterminate, statusNotice].forEach(elem => {
- elem.style.display = 'none';
- });
- if (indeterminiateStatusAnimationId !== 0) {
- cancelAnimationFrame(indeterminiateStatusAnimationId);
- indeterminiateStatusAnimationId = 0;
- }
- switch (mode) {
- case 'progress':
- statusProgress.style.display = 'block';
- break;
- case 'indeterminate':
- statusIndeterminate.style.display = 'block';
- indeterminiateStatusAnimationId = requestAnimationFrame(animateStatusIndeterminate);
- break;
- case 'notice':
- statusNotice.style.display = 'block';
- break;
- case 'hidden':
- break;
- default:
- throw new Error("Invalid status mode");
- }
- statusMode = mode;
- }
-
- function animateStatusIndeterminate(ms) {
- var i = Math.floor(ms / INDETERMINATE_STATUS_STEP_MS % 8);
- if (statusIndeterminate.children[i].style.borderTopColor == '') {
- Array.prototype.slice.call(statusIndeterminate.children).forEach(child => {
- child.style.borderTopColor = '';
- });
- statusIndeterminate.children[i].style.borderTopColor = '#dfdfdf';
- }
- requestAnimationFrame(animateStatusIndeterminate);
- }
-
- function setStatusNotice(text) {
- while (statusNotice.lastChild) {
- statusNotice.removeChild(statusNotice.lastChild);
- }
- var lines = text.split('\n');
- lines.forEach((line, index) => {
- statusNotice.appendChild(document.createTextNode(line));
- statusNotice.appendChild(document.createElement('br'));
- });
- };
-
- engine.setProgressFunc((current, total) => {
- if (total > 0) {
- statusProgressInner.style.width = current/total * 100 + '%';
- setStatusMode('progress');
- if (current === total) {
- // wait for progress bar animation
- setTimeout(() => {
- setStatusMode('indeterminate');
- }, 500);
- }
- } else {
- setStatusMode('indeterminate');
- }
- });
-
- if (DEBUG_ENABLED) {
- var outputRoot = document.getElementById("output-panel");
- var outputScroll = document.getElementById("output-scroll");
- var OUTPUT_MSG_COUNT_MAX = 400;
-
- document.getElementById('output-clear').addEventListener('click', () => {
- while (outputScroll.firstChild) {
- outputScroll.firstChild.remove();
- }
- });
-
- outputRoot.style.display = 'block';
-
- function print(text) {
- while (outputScroll.childElementCount >= OUTPUT_MSG_COUNT_MAX) {
- outputScroll.firstChild.remove();
- }
- var msg = document.createElement("div");
- if (String.prototype.trim.call(text).startsWith("**ERROR**")) {
- msg.style.color = "#d44";
- } else if (String.prototype.trim.call(text).startsWith("**WARNING**")) {
- msg.style.color = "#ccc000";
- } else if (String.prototype.trim.call(text).startsWith("**SCRIPT ERROR**")) {
- msg.style.color = "#c6d";
- }
- msg.textContent = text;
- var scrollToBottom = outputScroll.scrollHeight - (outputScroll.clientHeight + outputScroll.scrollTop) < 10;
- outputScroll.appendChild(msg);
- if (scrollToBottom) {
- outputScroll.scrollTop = outputScroll.scrollHeight;
- }
- };
-
- function printError(text) {
- if (!String.prototype.trim.call(text).startsWith('**ERROR**: ')) {
- text = '**ERROR**: ' + text;
- }
- print(text);
- }
-
- engine.setStdoutFunc(text => {
- print(text);
- console.log(text);
- });
-
- engine.setStderrFunc(text => {
- printError(text);
- console.warn(text);
- });
- }
-
- function displayFailureNotice(err) {
- var msg = err.message || err;
- if (DEBUG_ENABLED) {
- printError(msg);
- }
- console.error(msg);
- setStatusNotice(msg);
- setStatusMode('notice');
- initializing = false;
- };
-
- if (!Engine.isWebGLAvailable()) {
- displayFailureNotice("WebGL not available");
- } else {
- setStatusMode('indeterminate');
- engine.setCanvas(canvas);
- engine.startGame(EXECUTABLE_NAME, MAIN_PACK, EXTRA_ARGS).then(() => {
- setStatusMode('hidden');
- initializing = false;
- }, displayFailureNotice);
- }
- })();
- //]]></script>
-</body>
-</html>
diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html
index abc0479739..7afb6fdb6b 100644
--- a/misc/dist/html/full-size.html
+++ b/misc/dist/html/full-size.html
@@ -3,7 +3,6 @@
<head>
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, user-scalable=no' />
- <link id='-gd-engine-icon' rel='icon' type='image/png' href='favicon.png' />
<title>$GODOT_PROJECT_NAME</title>
<style type='text/css'>
diff --git a/misc/dist/html/offline-export.html b/misc/dist/html/offline-export.html
new file mode 100644
index 0000000000..41ab42b04b
--- /dev/null
+++ b/misc/dist/html/offline-export.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <title>You are offline</title>
+ <style>
+ html {
+ background-color: #000000;
+ color: #ffffff;
+ }
+
+ body {
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ margin: 2rem;
+ }
+
+ p {
+ margin-block: 1rem;
+ }
+
+ button {
+ display: block;
+ padding: 1rem 2rem;
+ margin: 3rem auto 0;
+ }
+ </style>
+</head>
+<body>
+ <h1>You are offline</h1>
+ <p>This application requires an Internet connection to run for the first time.</p>
+ <p>Press the button below to try reloading:</p>
+ <button type="button">Reload</button>
+
+ <script>
+ document.querySelector("button").addEventListener("click", () => {
+ window.location.reload();
+ });
+ </script>
+</body>
+</html>
diff --git a/misc/dist/html/service-worker.js b/misc/dist/html/service-worker.js
index d4eaed2b17..063e40a6cb 100644
--- a/misc/dist/html/service-worker.js
+++ b/misc/dist/html/service-worker.js
@@ -1,26 +1,15 @@
// This service worker is required to expose an exported Godot project as a
// Progressive Web App. It provides an offline fallback page telling the user
-// that they need an Internet conneciton to run the project if desired.
+// that they need an Internet connection to run the project if desired.
// Incrementing CACHE_VERSION will kick off the install event and force
// previously cached resources to be updated from the network.
const CACHE_VERSION = "@GODOT_VERSION@";
const CACHE_NAME = "@GODOT_NAME@-cache";
-const OFFLINE_URL = "offline.html";
+const OFFLINE_URL = "@GODOT_OFFLINE_PAGE@";
// Files that will be cached on load.
-const CACHED_FILES = [
- "godot.tools.html",
- "offline.html",
- "godot.tools.js",
- "godot.tools.worker.js",
- "godot.tools.audio.worklet.js",
- "logo.svg",
- "favicon.png",
-];
-
+const CACHED_FILES = @GODOT_CACHE@;
// Files that we might not want the user to preload, and will only be cached on first load.
-const CACHABLE_FILES = [
- "godot.tools.wasm",
-];
+const CACHABLE_FILES = @GODOT_OPT_CACHE@;
const FULL_CACHE = CACHED_FILES.concat(CACHABLE_FILES);
self.addEventListener("install", (event) => {
diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
index b9ad431e6e..fd69725a21 100644
--- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
+++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
@@ -255,7 +255,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
OTHER_LDFLAGS = "$linker_flags";
SDKROOT = iphoneos;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = "$targeted_device_family";
};
name = Debug;
};
@@ -294,7 +294,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
OTHER_LDFLAGS = "$linker_flags";
SDKROOT = iphoneos;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = "$targeted_device_family";
VALIDATE_PRODUCT = YES;
};
name = Release;
@@ -323,7 +323,7 @@
PRODUCT_BUNDLE_IDENTIFIER = $bundle_identifier;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "$provisioning_profile_uuid_debug";
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = "$targeted_device_family";
VALID_ARCHS = "armv7 armv7s arm64 i386 x86_64";
WRAPPER_EXTENSION = app;
};
@@ -353,7 +353,7 @@
PRODUCT_BUNDLE_IDENTIFIER = $bundle_identifier;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "$provisioning_profile_uuid_release";
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = "$targeted_device_family";
VALID_ARCHS = "armv7 armv7s arm64 i386 x86_64";
WRAPPER_EXTENSION = app;
};
diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme b/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme
index b6beeb012f..d61a53d5c2 100644
--- a/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme
+++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme
@@ -23,7 +23,7 @@
</BuildActionEntries>
</BuildAction>
<TestAction
- buildConfiguration = "Debug"
+ buildConfiguration = "$default_build_config"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
@@ -42,7 +42,7 @@
</AdditionalOptions>
</TestAction>
<LaunchAction
- buildConfiguration = "Debug"
+ buildConfiguration = "$default_build_config"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
@@ -67,7 +67,7 @@
</AdditionalOptions>
</LaunchAction>
<ProfileAction
- buildConfiguration = "Debug"
+ buildConfiguration = "$default_build_config"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
@@ -84,10 +84,10 @@
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
- buildConfiguration = "Debug">
+ buildConfiguration = "$default_build_config">
</AnalyzeAction>
<ArchiveAction
- buildConfiguration = "Debug"
+ buildConfiguration = "$default_build_config"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
diff --git a/misc/dist/linux/org.godotengine.Godot.xml b/misc/dist/linux/org.godotengine.Godot.xml
index 2f647f71a6..e51179cd61 100644
--- a/misc/dist/linux/org.godotengine.Godot.xml
+++ b/misc/dist/linux/org.godotengine.Godot.xml
@@ -21,6 +21,12 @@
<glob pattern="*.escn"/>
</mime-type>
+ <mime-type type="application/x-godot-shader">
+ <comment>Godot Engine shader</comment>
+ <icon name="x-godot-shader" />
+ <glob pattern="*.gdshader"/>
+ </mime-type>
+
<mime-type type="application/x-gdscript">
<comment>GDScript script</comment>
<icon name="x-gdscript" />
diff --git a/misc/dist/osx/editor.entitlements b/misc/dist/osx/editor.entitlements
new file mode 100644
index 0000000000..5496f65dcc
--- /dev/null
+++ b/misc/dist/osx/editor.entitlements
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.device.audio-input</key>
+ <true/>
+ <key>com.apple.security.device.camera</key>
+ <true/>
+ <key>com.apple.security.cs.disable-library-validation</key>
+ <true/>
+</dict>
+</plist>
diff --git a/misc/dist/osx/editor_mono.entitlements b/misc/dist/osx/editor_mono.entitlements
new file mode 100644
index 0000000000..c61c287652
--- /dev/null
+++ b/misc/dist/osx/editor_mono.entitlements
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.cs.allow-dyld-environment-variables</key>
+ <true/>
+ <key>com.apple.security.cs.allow-jit</key>
+ <true/>
+ <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
+ <true/>
+ <key>com.apple.security.cs.disable-library-validation</key>
+ <true/>
+ <key>com.apple.security.device.audio-input</key>
+ <true/>
+ <key>com.apple.security.device.camera</key>
+ <true/>
+</dict>
+</plist>
diff --git a/misc/dist/osx_template.app/Contents/Info.plist b/misc/dist/osx_template.app/Contents/Info.plist
index aad24935d0..8e221df946 100644
--- a/misc/dist/osx_template.app/Contents/Info.plist
+++ b/misc/dist/osx_template.app/Contents/Info.plist
@@ -36,6 +36,8 @@
</array>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
+ <key>LSApplicationCategoryType</key>
+ <string>public.app-category.$app_category</string>
<key>LSMinimumSystemVersion</key>
<string>10.12</string>
<key>LSMinimumSystemVersionByArchitecture</key>
diff --git a/misc/dist/osx_tools.app/Contents/Info.plist b/misc/dist/osx_tools.app/Contents/Info.plist
index 1c682f339f..8e70d4c203 100644
--- a/misc/dist/osx_tools.app/Contents/Info.plist
+++ b/misc/dist/osx_tools.app/Contents/Info.plist
@@ -38,6 +38,8 @@
</array>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
+ <key>LSApplicationCategoryType</key>
+ <string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>
<string>10.12</string>
<key>LSMinimumSystemVersionByArchitecture</key>
diff --git a/misc/hooks/canonicalize_filename.sh b/misc/hooks/canonicalize_filename.sh
index 5eecabf5bc..5fcae6ee70 100755
--- a/misc/hooks/canonicalize_filename.sh
+++ b/misc/hooks/canonicalize_filename.sh
@@ -13,7 +13,7 @@
# There should be no need to change anything below this line.
# Canonicalize by recursively following every symlink in every component of the
-# specified filename. This should reproduce the results of the GNU version of
+# specified filename. This should reproduce the results of the GNU version of
# readlink with the -f option.
#
# Reference: http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format
index 7c6e5fcb42..81bc412944 100755
--- a/misc/hooks/pre-commit-clang-format
+++ b/misc/hooks/pre-commit-clang-format
@@ -76,7 +76,8 @@ fi
# To get consistent formatting, we recommend contributors to use the same
# clang-format version as CI.
-RECOMMENDED_CLANG_FORMAT_MAJOR="11"
+RECOMMENDED_CLANG_FORMAT_MAJOR_MIN="11"
+RECOMMENDED_CLANG_FORMAT_MAJOR_MAX="12"
if [ ! -x "$CLANG_FORMAT" ] ; then
message="Error: clang-format executable not found. Please install clang-format $RECOMMENDED_CLANG_FORMAT_MAJOR.x.x."
@@ -99,11 +100,15 @@ if [ ! -x "$CLANG_FORMAT" ] ; then
exit 1
fi
-CLANG_FORMAT_VERSION="$(clang-format --version | cut -d' ' -f3)"
-CLANG_FORMAT_MAJOR="$(echo "$CLANG_FORMAT_VERSION" | cut -d'.' -f1)"
+# The returned string can be inconsistent depending on where clang-format comes from.
+# Example output strings reported by `clang-format --version`:
+# - Ubuntu: "Ubuntu clang-format version 11.0.0-2"
+# - Fedora: "clang-format version 11.0.0 (Fedora 11.0.0-2.fc33)"
+CLANG_FORMAT_VERSION="$(clang-format --version | sed "s/[^0-9\.]*\([0-9\.]*\).*/\1/")"
+CLANG_FORMAT_MAJOR="$(echo "$CLANG_FORMAT_VERSION" | cut -d. -f1)"
-if [ "$CLANG_FORMAT_MAJOR" != "$RECOMMENDED_CLANG_FORMAT_MAJOR" ]; then
- echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected $RECOMMENDED_CLANG_FORMAT_MAJOR.x.x)."
+if [[ "$CLANG_FORMAT_MAJOR" -lt "$RECOMMENDED_CLANG_FORMAT_MAJOR_MIN" || "$CLANG_FORMAT_MAJOR" -gt "$RECOMMENDED_CLANG_FORMAT_MAJOR_MAX" ]]; then
+ echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected between $RECOMMENDED_CLANG_FORMAT_MAJOR_MIN.x.x and $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX.x.x)."
echo " Consider upgrading or downgrading clang-format as formatting may not be applied correctly."
fi
diff --git a/misc/scripts/check_ci_log.py b/misc/scripts/check_ci_log.py
index f2cdf95c7b..56c32b154c 100755
--- a/misc/scripts/check_ci_log.py
+++ b/misc/scripts/check_ci_log.py
@@ -53,11 +53,11 @@ if file_contents.find("ObjectDB instances leaked at exit") != -1:
# execution of project
if file_contents.find("Assertion failed") != -1:
- print("ERROR: Assertion failed in project, check exectution log for more info")
+ print("ERROR: Assertion failed in project, check execution log for more info")
sys.exit(1)
# For now Godot leaks a lot of rendering stuff so for now we just show info
-# about it and this needs to be reenabled after fixing this memory leaks.
+# about it and this needs to be re-enabled after fixing this memory leaks.
if file_contents.find("were leaked") != -1 or file_contents.find("were never freed") != -1:
print("WARNING: Memory leak was found")
diff --git a/modules/SCsub b/modules/SCsub
index 64da3bd0be..5ff4623743 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -10,6 +10,7 @@ env_modules = env.Clone()
Export("env_modules")
# Header with MODULE_*_ENABLED defines.
+env.Depends("modules_enabled.gen.h", Value(env.module_list))
env.CommandNoCache(
"modules_enabled.gen.h",
Value(env.module_list),
@@ -23,6 +24,7 @@ env.CommandNoCache(
# Header to be included in `tests/test_main.cpp` to run module-specific tests.
if env["tests"]:
+ env.Depends("modules_tests.gen.h", Value(env.module_list))
env.CommandNoCache(
"modules_tests.gen.h",
Value(env.module_list),
diff --git a/modules/basis_universal/SCsub b/modules/basis_universal/SCsub
index 351628a0e3..1f9fde966d 100644
--- a/modules/basis_universal/SCsub
+++ b/modules/basis_universal/SCsub
@@ -11,40 +11,45 @@ thirdparty_obj = []
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/basis_universal/"
-tool_sources = [
+# Sync list with upstream CMakeLists.txt
+encoder_sources = [
+ "apg_bmp.c",
"basisu_astc_decomp.cpp",
"basisu_backend.cpp",
"basisu_basis_file.cpp",
+ "basisu_bc7enc.cpp",
"basisu_comp.cpp",
"basisu_enc.cpp",
"basisu_etc.cpp",
"basisu_frontend.cpp",
"basisu_global_selector_palette_helpers.cpp",
"basisu_gpu_texture.cpp",
+ "basisu_kernels_sse.cpp",
"basisu_pvrtc1_4.cpp",
- "basisu_resample_filters.cpp",
"basisu_resampler.cpp",
+ "basisu_resample_filters.cpp",
"basisu_ssim.cpp",
+ "basisu_uastc_enc.cpp",
+ "jpgd.cpp",
"lodepng.cpp",
]
-tool_sources = [thirdparty_dir + file for file in tool_sources]
+encoder_sources = [thirdparty_dir + "encoder/" + file for file in encoder_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])
else:
- env_basisu.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "transcoder"])
+ env_basisu.Prepend(CPPPATH=[thirdparty_dir])
if env["target"] == "debug":
- env_basisu.Append(CPPFLAGS=["-DBASISU_DEVEL_MESSAGES=1", "-DBASISD_ENABLE_DEBUG_FLAGS=1"])
+ env_basisu.Append(CPPDEFINES=[("BASISU_DEVEL_MESSAGES", 1), ("BASISD_ENABLE_DEBUG_FLAGS", 1)])
env_thirdparty = env_basisu.Clone()
env_thirdparty.disable_warnings()
if env["tools"]:
- env_thirdparty.add_source_files(thirdparty_obj, tool_sources)
+ env_thirdparty.Append(CPPDEFINES=["BASISU_NO_IMG_LOADERS"])
+ env_thirdparty.add_source_files(thirdparty_obj, encoder_sources)
env_thirdparty.add_source_files(thirdparty_obj, transcoder_sources)
env.modules_sources += thirdparty_obj
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp
index cf5581265b..772ac87dbf 100644
--- a/modules/basis_universal/register_types.cpp
+++ b/modules/basis_universal/register_types.cpp
@@ -35,7 +35,7 @@
#include "texture_basisu.h"
#ifdef TOOLS_ENABLED
-#include <basisu_comp.h>
+#include <encoder/basisu_comp.h>
#endif
#include <transcoder/basisu_transcoder.h>
@@ -233,7 +233,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
basist::basisu_image_info info;
tr.get_image_info(ptr, size, info, 0);
- int block_size = basist::basis_get_bytes_per_block(format);
+ int block_size = basist::basis_get_bytes_per_block_or_pixel(format);
Vector<uint8_t> gpudata;
gpudata.resize(info.m_total_blocks * block_size);
diff --git a/modules/basis_universal/texture_basisu.cpp b/modules/basis_universal/texture_basisu.cpp
index 92882a1cc8..6a5f6313c4 100644
--- a/modules/basis_universal/texture_basisu.cpp
+++ b/modules/basis_universal/texture_basisu.cpp
@@ -33,7 +33,7 @@
#include "core/os/os.h"
#ifdef TOOLS_ENABLED
-#include <basisu_comp.h>
+#include <encoder/basisu_comp.h>
#endif
#include <transcoder/basisu_transcoder.h>
diff --git a/modules/basis_universal/texture_basisu.h b/modules/basis_universal/texture_basisu.h
index 282a0dfc8a..3316035404 100644
--- a/modules/basis_universal/texture_basisu.h
+++ b/modules/basis_universal/texture_basisu.h
@@ -34,7 +34,7 @@
#include "scene/resources/texture.h"
#ifdef TOOLS_ENABLED
-#include <basisu_comp.h>
+#include <encoder/basisu_comp.h>
#endif
#include <transcoder/basisu_transcoder.h>
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index c7fdf56af4..27b49a6609 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -130,23 +130,19 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
line_ptr += 1;
} break;
case 24: {
- uint32_t color = *((uint32_t *)line_ptr);
-
- write_buffer[index + 2] = color & 0xff;
- write_buffer[index + 1] = (color >> 8) & 0xff;
- write_buffer[index + 0] = (color >> 16) & 0xff;
+ write_buffer[index + 2] = line_ptr[0];
+ write_buffer[index + 1] = line_ptr[1];
+ write_buffer[index + 0] = line_ptr[2];
write_buffer[index + 3] = 0xff;
index += 4;
line_ptr += 3;
} break;
case 32: {
- uint32_t color = *((uint32_t *)line_ptr);
-
- write_buffer[index + 2] = color & 0xff;
- write_buffer[index + 1] = (color >> 8) & 0xff;
- write_buffer[index + 0] = (color >> 16) & 0xff;
- write_buffer[index + 3] = color >> 24;
+ write_buffer[index + 2] = line_ptr[0];
+ write_buffer[index + 1] = line_ptr[1];
+ write_buffer[index + 0] = line_ptr[2];
+ write_buffer[index + 3] = line_ptr[3];
index += 4;
line_ptr += 4;
@@ -172,11 +168,9 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
const uint8_t *cb = p_color_buffer;
for (unsigned int i = 0; i < color_table_size; ++i) {
- uint32_t color = *((uint32_t *)cb);
-
- pal[i * 4 + 0] = (color >> 16) & 0xff;
- pal[i * 4 + 1] = (color >> 8) & 0xff;
- pal[i * 4 + 2] = (color)&0xff;
+ pal[i * 4 + 0] = cb[2];
+ pal[i * 4 + 1] = cb[1];
+ pal[i * 4 + 2] = cb[0];
pal[i * 4 + 3] = 0xff;
cb += 4;
@@ -211,7 +205,7 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f,
// A valid bmp file should always at least have a
// file header and a minimal info header
- if (f->get_len() > BITMAP_FILE_HEADER_SIZE + BITMAP_INFO_HEADER_MIN_SIZE) {
+ if (f->get_length() > BITMAP_FILE_HEADER_SIZE + BITMAP_INFO_HEADER_MIN_SIZE) {
// File Header
bmp_header.bmp_file_header.bmp_signature = f->get_16();
if (bmp_header.bmp_file_header.bmp_signature == BITMAP_SIGNATURE) {
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 93642f2d5c..e07be14c5b 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -268,7 +268,7 @@ PhysicsServer3D::AreaSpaceOverrideMode BulletPhysicsServer3D::area_get_space_ove
return area->get_spOv_mode();
}
-void BulletPhysicsServer3D::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 Transform3D &p_transform, bool p_disabled) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
@@ -288,7 +288,7 @@ void BulletPhysicsServer3D::area_set_shape(RID p_area, int p_shape_idx, RID p_sh
area->set_shape(p_shape_idx, shape);
}
-void BulletPhysicsServer3D::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 Transform3D &p_transform) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
@@ -309,9 +309,9 @@ RID BulletPhysicsServer3D::area_get_shape(RID p_area, int p_shape_idx) const {
return area->get_shape(p_shape_idx)->get_self();
}
-Transform BulletPhysicsServer3D::area_get_shape_transform(RID p_area, int p_shape_idx) const {
+Transform3D 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());
+ ERR_FAIL_COND_V(!area, Transform3D());
return area->get_shape_transform(p_shape_idx);
}
@@ -382,15 +382,15 @@ Variant BulletPhysicsServer3D::area_get_param(RID p_area, AreaParameter p_param)
}
}
-void BulletPhysicsServer3D::area_set_transform(RID p_area, const Transform &p_transform) {
+void BulletPhysicsServer3D::area_set_transform(RID p_area, const Transform3D &p_transform) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_transform(p_transform);
}
-Transform BulletPhysicsServer3D::area_get_transform(RID p_area) const {
+Transform3D BulletPhysicsServer3D::area_get_transform(RID p_area) const {
AreaBullet *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Transform());
+ ERR_FAIL_COND_V(!area, Transform3D());
return area->get_transform();
}
@@ -484,7 +484,7 @@ PhysicsServer3D::BodyMode BulletPhysicsServer3D::body_get_mode(RID p_body) const
return body->get_mode();
}
-void BulletPhysicsServer3D::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 Transform3D &p_transform, bool p_disabled) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -504,7 +504,7 @@ void BulletPhysicsServer3D::body_set_shape(RID p_body, int p_shape_idx, RID p_sh
body->set_shape(p_shape_idx, shape);
}
-void BulletPhysicsServer3D::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 Transform3D &p_transform) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -527,9 +527,9 @@ RID BulletPhysicsServer3D::body_get_shape(RID p_body, int p_shape_idx) const {
return shape->get_self();
}
-Transform BulletPhysicsServer3D::body_get_shape_transform(RID p_body, int p_shape_idx) const {
+Transform3D 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());
+ ERR_FAIL_COND_V(!body, Transform3D());
return body->get_shape_transform(p_shape_idx);
}
@@ -824,10 +824,10 @@ bool BulletPhysicsServer3D::body_is_omitting_force_integration(RID p_body) const
return body->get_omit_forces_integration();
}
-void BulletPhysicsServer3D::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
+void BulletPhysicsServer3D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
+ body->set_force_integration_callback(p_callable, p_udata);
}
void BulletPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) {
@@ -842,7 +842,7 @@ PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_bod
return BulletPhysicsDirectBodyState3D::get_singleton(body);
}
-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) {
+bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &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);
@@ -850,7 +850,7 @@ bool BulletPhysicsServer3D::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 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, real_t p_margin) {
+int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
ERR_FAIL_COND_V(!body->get_space(), 0);
@@ -990,7 +990,7 @@ Variant BulletPhysicsServer3D::soft_body_get_state(RID p_body, BodyState p_state
return Variant();
}
-void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform &p_transform) {
+void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform3D &p_transform) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -1205,7 +1205,7 @@ Vector3 BulletPhysicsServer3D::pin_joint_get_local_b(RID p_joint) const {
return pin_joint->getPivotInB();
}
-RID BulletPhysicsServer3D::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 Transform3D &p_hinge_A, RID p_body_B, const Transform3D &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());
@@ -1277,7 +1277,7 @@ bool BulletPhysicsServer3D::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_f
return hinge_joint->get_flag(p_flag);
}
-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) {
+RID BulletPhysicsServer3D::joint_create_slider(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &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());
@@ -1313,7 +1313,7 @@ real_t BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointPar
return slider_joint->get_param(p_param);
}
-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) {
+RID BulletPhysicsServer3D::joint_create_cone_twist(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &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());
@@ -1347,7 +1347,7 @@ real_t BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJ
return coneTwist_joint->get_param(p_param);
}
-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) {
+RID BulletPhysicsServer3D::joint_create_generic_6dof(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &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());
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 856ff74963..d34d619ba2 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -134,12 +134,12 @@ public:
virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) override;
virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const override;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) override;
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override;
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) override;
- virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) override;
+ virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) override;
virtual int area_get_shape_count(RID p_area) const override;
virtual RID area_get_shape(RID p_area, int p_shape_idx) const override;
- virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const override;
+ virtual Transform3D area_get_shape_transform(RID p_area, int p_shape_idx) const override;
virtual void area_remove_shape(RID p_area, int p_shape_idx) override;
virtual void area_clear_shapes(RID p_area) override;
virtual void area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) override;
@@ -153,8 +153,8 @@ public:
virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) override;
virtual Variant area_get_param(RID p_area, AreaParameter p_param) const override;
- virtual void area_set_transform(RID p_area, const Transform &p_transform) override;
- virtual Transform area_get_transform(RID p_area) const override;
+ virtual void area_set_transform(RID p_area, const Transform3D &p_transform) override;
+ virtual Transform3D area_get_transform(RID p_area) const override;
virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override;
virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override;
@@ -166,7 +166,7 @@ public:
/* RIGID BODY API */
- virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false) override;
+ virtual RID body_create(BodyMode p_mode = BODY_MODE_DYNAMIC, bool p_init_sleeping = false) override;
virtual void body_set_space(RID p_body, RID p_space) override;
virtual RID body_get_space(RID p_body) const override;
@@ -174,14 +174,14 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode) override;
virtual BodyMode body_get_mode(RID p_body) const override;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) override;
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override;
// Not supported, Please remove and add new shape
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) override;
- virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) override;
+ virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) override;
virtual int body_get_shape_count(RID p_body) const override;
virtual RID body_get_shape(RID p_body, int p_shape_idx) const override;
- virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const override;
+ virtual Transform3D body_get_shape_transform(RID p_body, int p_shape_idx) const override;
virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) override;
@@ -246,15 +246,15 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) override;
virtual bool body_is_omitting_force_integration(RID p_body) const override;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
- virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
- virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
+ virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
+ virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
/* SOFT BODY API */
@@ -283,7 +283,7 @@ public:
virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override;
/// Special function. This function has bad performance
- virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override;
+ virtual void soft_body_set_transform(RID p_body, const Transform3D &p_transform) override;
virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override;
@@ -333,7 +333,7 @@ public:
virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) override;
virtual Vector3 pin_joint_get_local_b(RID p_joint) const override;
- virtual RID joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) override;
+ virtual RID joint_create_hinge(RID p_body_A, const Transform3D &p_hinge_A, RID p_body_B, const Transform3D &p_hinge_B) override;
virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override;
virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) override;
@@ -343,19 +343,19 @@ public:
virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const override;
/// Reference frame is A
- virtual RID joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override;
+ virtual RID joint_create_slider(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override;
virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) override;
virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override;
/// Reference frame is A
- virtual RID joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override;
+ virtual RID joint_create_cone_twist(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override;
virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) override;
virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override;
/// Reference frame is A
- virtual RID joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override;
+ virtual RID joint_create_generic_6dof(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override;
virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) override;
virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) override;
diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp
index 19d4816372..01461767bd 100644
--- a/modules/bullet/bullet_types_converter.cpp
+++ b/modules/bullet/bullet_types_converter.cpp
@@ -59,7 +59,7 @@ void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal) {
INVERT_B_TO_G(inVal[2], outVal[2]);
}
-void B_TO_G(btTransform const &inVal, Transform &outVal) {
+void B_TO_G(btTransform const &inVal, Transform3D &outVal) {
B_TO_G(inVal.getBasis(), outVal.basis);
B_TO_G(inVal.getOrigin(), outVal.origin);
}
@@ -89,7 +89,7 @@ void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal) {
INVERT_G_TO_B(inVal[2], outVal[2]);
}
-void G_TO_B(Transform const &inVal, btTransform &outVal) {
+void G_TO_B(Transform3D const &inVal, btTransform &outVal) {
G_TO_B(inVal.basis, outVal.getBasis());
G_TO_B(inVal.origin, outVal.getOrigin());
}
diff --git a/modules/bullet/bullet_types_converter.h b/modules/bullet/bullet_types_converter.h
index ca9b7175dd..e184fe1769 100644
--- a/modules/bullet/bullet_types_converter.h
+++ b/modules/bullet/bullet_types_converter.h
@@ -32,7 +32,7 @@
#define BULLET_TYPES_CONVERTER_H
#include "core/math/basis.h"
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include "core/math/vector3.h"
#include "core/typedefs.h"
@@ -49,14 +49,14 @@ extern void B_TO_G(btVector3 const &inVal, Vector3 &outVal);
extern void INVERT_B_TO_G(btVector3 const &inVal, Vector3 &outVal);
extern void B_TO_G(btMatrix3x3 const &inVal, Basis &outVal);
extern void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal);
-extern void B_TO_G(btTransform const &inVal, Transform &outVal);
+extern void B_TO_G(btTransform const &inVal, Transform3D &outVal);
// Godot TO Bullet
extern void G_TO_B(Vector3 const &inVal, btVector3 &outVal);
extern void INVERT_G_TO_B(Vector3 const &inVal, btVector3 &outVal);
extern void G_TO_B(Basis const &inVal, btMatrix3x3 &outVal);
extern void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal);
-extern void G_TO_B(Transform const &inVal, btTransform &outVal);
+extern void G_TO_B(Transform3D const &inVal, btTransform &outVal);
extern void UNSCALE_BT_BASIS(btTransform &scaledBasis);
#endif
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index d9f5beb5a1..c45bd5bbc0 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -49,7 +49,7 @@
CollisionObjectBullet::ShapeWrapper::~ShapeWrapper() {}
-void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform &p_transform) {
+void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform3D &p_transform) {
G_TO_B(p_transform.get_basis().get_scale_abs(), scale);
G_TO_B(p_transform, transform);
UNSCALE_BT_BASIS(transform);
@@ -193,7 +193,7 @@ int CollisionObjectBullet::get_godot_object_flags() const {
return bt_collision_object->getUserIndex2();
}
-void CollisionObjectBullet::set_transform(const Transform &p_global_transform) {
+void CollisionObjectBullet::set_transform(const Transform3D &p_global_transform) {
set_body_scale(p_global_transform.basis.get_scale_abs());
btTransform bt_transform;
@@ -203,8 +203,8 @@ void CollisionObjectBullet::set_transform(const Transform &p_global_transform) {
set_transform__bullet(bt_transform);
}
-Transform CollisionObjectBullet::get_transform() const {
- Transform t;
+Transform3D CollisionObjectBullet::get_transform() const {
+ Transform3D t;
B_TO_G(get_transform__bullet(), t);
t.basis.scale(body_scale);
return t;
@@ -230,7 +230,7 @@ RigidCollisionObjectBullet::~RigidCollisionObjectBullet() {
}
}
-void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform &p_transform, bool p_disabled) {
+void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform3D &p_transform, bool p_disabled) {
shapes.push_back(ShapeWrapper(p_shape, p_transform, !p_disabled));
p_shape->add_owner(this);
reload_shapes();
@@ -296,7 +296,7 @@ void RigidCollisionObjectBullet::remove_all_shapes(bool p_permanentlyFromThisBod
}
}
-void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) {
+void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform3D &p_transform) {
ERR_FAIL_INDEX(p_index, get_shape_count());
shapes.write[p_index].set_transform(p_transform);
@@ -307,8 +307,8 @@ const btTransform &RigidCollisionObjectBullet::get_bt_shape_transform(int p_inde
return shapes[p_index].transform;
}
-Transform RigidCollisionObjectBullet::get_shape_transform(int p_index) const {
- Transform trs;
+Transform3D RigidCollisionObjectBullet::get_shape_transform(int p_index) const {
+ Transform3D trs;
B_TO_G(shapes[p_index].transform, trs);
return trs;
}
diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h
index c8081a53f1..944ab89b87 100644
--- a/modules/bullet/collision_object_bullet.h
+++ b/modules/bullet/collision_object_bullet.h
@@ -31,7 +31,7 @@
#ifndef COLLISION_OBJECT_BULLET_H
#define COLLISION_OBJECT_BULLET_H
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include "core/math/vector3.h"
#include "core/object/class_db.h"
#include "core/templates/vset.h"
@@ -83,7 +83,7 @@ public:
set_transform(p_transform);
}
- ShapeWrapper(ShapeBullet *p_shape, const Transform &p_transform, bool p_active) :
+ ShapeWrapper(ShapeBullet *p_shape, const Transform3D &p_transform, bool p_active) :
shape(p_shape),
active(p_active) {
set_transform(p_transform);
@@ -102,7 +102,7 @@ public:
active = otherShape.active;
}
- void set_transform(const Transform &p_transform);
+ void set_transform(const Transform3D &p_transform);
void set_transform(const btTransform &p_transform);
btTransform get_adjusted_transform() const;
@@ -202,8 +202,8 @@ public:
void set_godot_object_flags(int flags);
int get_godot_object_flags() const;
- void set_transform(const Transform &p_global_transform);
- Transform get_transform() const;
+ void set_transform(const Transform3D &p_global_transform);
+ Transform3D get_transform() const;
virtual void set_transform__bullet(const btTransform &p_global_transform);
virtual const btTransform &get_transform__bullet() const;
@@ -225,7 +225,7 @@ public:
_FORCE_INLINE_ btCollisionShape *get_main_shape() const { return mainShape; }
- void add_shape(ShapeBullet *p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
+ void add_shape(ShapeBullet *p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false);
void set_shape(int p_index, ShapeBullet *p_shape);
int get_shape_count() const;
@@ -238,10 +238,10 @@ public:
void remove_shape_full(int p_index);
void remove_all_shapes(bool p_permanentlyFromThisBody = false, bool p_force_not_reload = false);
- void set_shape_transform(int p_index, const Transform &p_transform);
+ void set_shape_transform(int p_index, const Transform3D &p_transform);
const btTransform &get_bt_shape_transform(int p_index) const;
- Transform get_shape_transform(int p_index) const;
+ Transform3D get_shape_transform(int p_index) const;
void set_shape_disabled(int p_index, bool p_disabled);
bool is_shape_disabled(int p_index);
diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp
index e785780c5b..34516d8b3b 100644
--- a/modules/bullet/cone_twist_joint_bullet.cpp
+++ b/modules/bullet/cone_twist_joint_bullet.cpp
@@ -40,16 +40,16 @@
@author AndreaCatania
*/
-ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame) :
+ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame) :
JointBullet() {
- Transform scaled_AFrame(rbAFrame.scaled(rbA->get_body_scale()));
+ Transform3D scaled_AFrame(rbAFrame.scaled(rbA->get_body_scale()));
scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis);
btTransform btFrameA;
G_TO_B(scaled_AFrame, btFrameA);
if (rbB) {
- Transform scaled_BFrame(rbBFrame.scaled(rbB->get_body_scale()));
+ Transform3D scaled_BFrame(rbBFrame.scaled(rbB->get_body_scale()));
scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis);
btTransform btFrameB;
diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/bullet/cone_twist_joint_bullet.h
index 7d6bafd292..7e51f7d644 100644
--- a/modules/bullet/cone_twist_joint_bullet.h
+++ b/modules/bullet/cone_twist_joint_bullet.h
@@ -43,7 +43,7 @@ class ConeTwistJointBullet : public JointBullet {
class btConeTwistConstraint *coneConstraint;
public:
- ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame);
+ ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame);
virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_CONE_TWIST; }
diff --git a/modules/bullet/config.py b/modules/bullet/config.py
index be7cf74f6f..83605f1f9b 100644
--- a/modules/bullet/config.py
+++ b/modules/bullet/config.py
@@ -1,6 +1,7 @@
def can_build(env, platform):
# API Changed and bullet is disabled at the moment
return False
+ # Later change to return not env["disable_3d"]
def configure(env):
diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp
index 43ad6c56d5..7e04d57b9d 100644
--- a/modules/bullet/generic_6dof_joint_bullet.cpp
+++ b/modules/bullet/generic_6dof_joint_bullet.cpp
@@ -40,7 +40,7 @@
@author AndreaCatania
*/
-Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB) :
+Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB) :
JointBullet() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < PhysicsServer3D::G6DOF_JOINT_FLAG_MAX; j++) {
@@ -48,7 +48,7 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu
}
}
- Transform scaled_AFrame(frameInA.scaled(rbA->get_body_scale()));
+ Transform3D scaled_AFrame(frameInA.scaled(rbA->get_body_scale()));
scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis);
@@ -56,7 +56,7 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu
G_TO_B(scaled_AFrame, btFrameA);
if (rbB) {
- Transform scaled_BFrame(frameInB.scaled(rbB->get_body_scale()));
+ Transform3D scaled_BFrame(frameInB.scaled(rbB->get_body_scale()));
scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis);
@@ -71,30 +71,30 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu
setup(sixDOFConstraint);
}
-Transform Generic6DOFJointBullet::getFrameOffsetA() const {
+Transform3D Generic6DOFJointBullet::getFrameOffsetA() const {
btTransform btTrs = sixDOFConstraint->getFrameOffsetA();
- Transform gTrs;
+ Transform3D gTrs;
B_TO_G(btTrs, gTrs);
return gTrs;
}
-Transform Generic6DOFJointBullet::getFrameOffsetB() const {
+Transform3D Generic6DOFJointBullet::getFrameOffsetB() const {
btTransform btTrs = sixDOFConstraint->getFrameOffsetB();
- Transform gTrs;
+ Transform3D gTrs;
B_TO_G(btTrs, gTrs);
return gTrs;
}
-Transform Generic6DOFJointBullet::getFrameOffsetA() {
+Transform3D Generic6DOFJointBullet::getFrameOffsetA() {
btTransform btTrs = sixDOFConstraint->getFrameOffsetA();
- Transform gTrs;
+ Transform3D gTrs;
B_TO_G(btTrs, gTrs);
return gTrs;
}
-Transform Generic6DOFJointBullet::getFrameOffsetB() {
+Transform3D Generic6DOFJointBullet::getFrameOffsetB() {
btTransform btTrs = sixDOFConstraint->getFrameOffsetB();
- Transform gTrs;
+ Transform3D gTrs;
B_TO_G(btTrs, gTrs);
return gTrs;
}
diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h
index 62b8e85a81..00567e3085 100644
--- a/modules/bullet/generic_6dof_joint_bullet.h
+++ b/modules/bullet/generic_6dof_joint_bullet.h
@@ -48,14 +48,14 @@ class Generic6DOFJointBullet : public JointBullet {
bool flags[3][PhysicsServer3D::G6DOF_JOINT_FLAG_MAX];
public:
- Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB);
+ Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB);
virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_6DOF; }
- Transform getFrameOffsetA() const;
- Transform getFrameOffsetB() const;
- Transform getFrameOffsetA();
- Transform getFrameOffsetB();
+ Transform3D getFrameOffsetA() const;
+ Transform3D getFrameOffsetB() const;
+ Transform3D getFrameOffsetA();
+ Transform3D getFrameOffsetB();
void set_linear_lower_limit(const Vector3 &linearLower);
void set_linear_upper_limit(const Vector3 &linearUpper);
diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp
index 4ceb98729f..b5fe50cf5f 100644
--- a/modules/bullet/hinge_joint_bullet.cpp
+++ b/modules/bullet/hinge_joint_bullet.cpp
@@ -40,16 +40,16 @@
@author AndreaCatania
*/
-HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB) :
+HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameA, const Transform3D &frameB) :
JointBullet() {
- Transform scaled_AFrame(frameA.scaled(rbA->get_body_scale()));
+ Transform3D scaled_AFrame(frameA.scaled(rbA->get_body_scale()));
scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis);
btTransform btFrameA;
G_TO_B(scaled_AFrame, btFrameA);
if (rbB) {
- Transform scaled_BFrame(frameB.scaled(rbB->get_body_scale()));
+ Transform3D scaled_BFrame(frameB.scaled(rbB->get_body_scale()));
scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis);
btTransform btFrameB;
diff --git a/modules/bullet/hinge_joint_bullet.h b/modules/bullet/hinge_joint_bullet.h
index 06a95be374..dd0f69ba68 100644
--- a/modules/bullet/hinge_joint_bullet.h
+++ b/modules/bullet/hinge_joint_bullet.h
@@ -41,7 +41,7 @@ class HingeJointBullet : public JointBullet {
class btHingeConstraint *hingeConstraint;
public:
- HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB);
+ HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameA, const Transform3D &frameB);
HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB);
virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_HINGE; }
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 433bff8c38..ce39d4f0df 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -106,11 +106,11 @@ Vector3 BulletPhysicsDirectBodyState3D::get_angular_velocity() const {
return body->get_angular_velocity();
}
-void BulletPhysicsDirectBodyState3D::set_transform(const Transform &p_transform) {
+void BulletPhysicsDirectBodyState3D::set_transform(const Transform3D &p_transform) {
body->set_transform(p_transform);
}
-Transform BulletPhysicsDirectBodyState3D::get_transform() const {
+Transform3D BulletPhysicsDirectBodyState3D::get_transform() const {
return body->get_transform();
}
@@ -268,7 +268,7 @@ RigidBodyBullet::RigidBodyBullet() :
reload_shapes();
setupBulletCollisionObject(btBody);
- set_mode(PhysicsServer3D::BODY_MODE_RIGID);
+ set_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
reload_axis_lock();
areasWhereIam.resize(maxAreasWhereIam);
@@ -346,16 +346,17 @@ void RigidBodyBullet::dispatch_callbacks() {
Variant variantBodyDirect = bodyDirect;
- Object *obj = ObjectDB::get_instance(force_integration_callback->id);
+ Object *obj = force_integration_callback->callable.get_object();
if (!obj) {
// Remove integration callback
- set_force_integration_callback(ObjectID(), StringName());
+ set_force_integration_callback(Callable());
} else {
const Variant *vp[2] = { &variantBodyDirect, &force_integration_callback->udata };
Callable::CallError responseCallError;
int argc = (force_integration_callback->udata.get_type() == Variant::NIL) ? 1 : 2;
- obj->call(force_integration_callback->method, vp, argc, responseCallError);
+ Variant rv;
+ force_integration_callback->callable.call(vp, argc, rv, responseCallError);
}
}
@@ -371,16 +372,15 @@ void RigidBodyBullet::dispatch_callbacks() {
previousActiveState = btBody->isActive();
}
-void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+void RigidBodyBullet::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
if (force_integration_callback) {
memdelete(force_integration_callback);
force_integration_callback = nullptr;
}
- if (p_id.is_valid()) {
+ if (p_callable.get_object()) {
force_integration_callback = memnew(ForceIntegrationCallback);
- force_integration_callback->id = p_id;
- force_integration_callback->method = p_method;
+ force_integration_callback->callable = p_callable;
force_integration_callback->udata = p_udata;
}
}
@@ -531,14 +531,14 @@ void RigidBodyBullet::set_mode(PhysicsServer3D::BodyMode p_mode) {
reload_axis_lock();
_internal_set_mass(0);
break;
- case PhysicsServer3D::BODY_MODE_RIGID:
- mode = PhysicsServer3D::BODY_MODE_RIGID;
+ case PhysicsServer3D::BODY_MODE_DYNAMIC:
+ mode = PhysicsServer3D::BODY_MODE_DYNAMIC;
reload_axis_lock();
_internal_set_mass(0 == mass ? 1 : mass);
scratch_space_override_modificator();
break;
- case PhysicsServer3D::BODY_MODE_CHARACTER:
- mode = PhysicsServer3D::BODY_MODE_CHARACTER;
+ case PhysicsServer3D::MODE_DYNAMIC_LOCKED:
+ mode = PhysicsServer3D::MODE_DYNAMIC_LOCKED;
reload_axis_lock();
_internal_set_mass(0 == mass ? 1 : mass);
scratch_space_override_modificator();
@@ -711,7 +711,7 @@ bool RigidBodyBullet::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const {
void RigidBodyBullet::reload_axis_lock() {
btBody->setLinearFactor(btVector3(btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z))));
- if (PhysicsServer3D::BODY_MODE_CHARACTER == mode) {
+ if (PhysicsServer3D::MODE_DYNAMIC_LOCKED == mode) {
/// When character angular is always locked
btBody->setAngularFactor(btVector3(0., 0., 0.));
} else {
@@ -1006,7 +1006,7 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) {
// Rigidbody is dynamic if and only if mass is non Zero, otherwise static
const bool isDynamic = p_mass != 0.f;
if (isDynamic) {
- if (PhysicsServer3D::BODY_MODE_RIGID != mode && PhysicsServer3D::BODY_MODE_CHARACTER != mode) {
+ if (PhysicsServer3D::BODY_MODE_DYNAMIC != mode && PhysicsServer3D::MODE_DYNAMIC_LOCKED != mode) {
return;
}
@@ -1015,7 +1015,7 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) {
mainShape->calculateLocalInertia(p_mass, localInertia);
}
- if (PhysicsServer3D::BODY_MODE_RIGID == mode) {
+ if (PhysicsServer3D::BODY_MODE_DYNAMIC == mode) {
btBody->setCollisionFlags(clearedCurrentFlags); // Just set the flags without Kin and Static
} else {
btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_CHARACTER_OBJECT);
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index a4be7f9e07..606df7134b 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -107,8 +107,8 @@ public:
virtual void set_angular_velocity(const Vector3 &p_velocity) override;
virtual Vector3 get_angular_velocity() const override;
- virtual void set_transform(const Transform &p_transform) override;
- virtual Transform get_transform() const override;
+ virtual void set_transform(const Transform3D &p_transform) override;
+ virtual Transform3D get_transform() const override;
virtual void add_central_force(const Vector3 &p_force) override;
virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override;
@@ -154,8 +154,7 @@ public:
};
struct ForceIntegrationCallback {
- ObjectID id;
- StringName method;
+ Callable callable;
Variant udata;
};
@@ -240,7 +239,7 @@ public:
virtual void set_space(SpaceBullet *p_space);
virtual void dispatch_callbacks();
- void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
void scratch_space_override_modificator();
virtual void on_collision_filters_change();
diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp
index 45c892851b..1d83118468 100644
--- a/modules/bullet/slider_joint_bullet.cpp
+++ b/modules/bullet/slider_joint_bullet.cpp
@@ -40,16 +40,16 @@
@author AndreaCatania
*/
-SliderJointBullet::SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB) :
+SliderJointBullet::SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB) :
JointBullet() {
- Transform scaled_AFrame(frameInA.scaled(rbA->get_body_scale()));
+ Transform3D scaled_AFrame(frameInA.scaled(rbA->get_body_scale()));
scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis);
btTransform btFrameA;
G_TO_B(scaled_AFrame, btFrameA);
if (rbB) {
- Transform scaled_BFrame(frameInB.scaled(rbB->get_body_scale()));
+ Transform3D scaled_BFrame(frameInB.scaled(rbB->get_body_scale()));
scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis);
btTransform btFrameB;
@@ -70,44 +70,44 @@ const RigidBodyBullet *SliderJointBullet::getRigidBodyB() const {
return static_cast<RigidBodyBullet *>(sliderConstraint->getRigidBodyB().getUserPointer());
}
-const Transform SliderJointBullet::getCalculatedTransformA() const {
+const Transform3D SliderJointBullet::getCalculatedTransformA() const {
btTransform btTransform = sliderConstraint->getCalculatedTransformA();
- Transform gTrans;
+ Transform3D gTrans;
B_TO_G(btTransform, gTrans);
return gTrans;
}
-const Transform SliderJointBullet::getCalculatedTransformB() const {
+const Transform3D SliderJointBullet::getCalculatedTransformB() const {
btTransform btTransform = sliderConstraint->getCalculatedTransformB();
- Transform gTrans;
+ Transform3D gTrans;
B_TO_G(btTransform, gTrans);
return gTrans;
}
-const Transform SliderJointBullet::getFrameOffsetA() const {
+const Transform3D SliderJointBullet::getFrameOffsetA() const {
btTransform btTransform = sliderConstraint->getFrameOffsetA();
- Transform gTrans;
+ Transform3D gTrans;
B_TO_G(btTransform, gTrans);
return gTrans;
}
-const Transform SliderJointBullet::getFrameOffsetB() const {
+const Transform3D SliderJointBullet::getFrameOffsetB() const {
btTransform btTransform = sliderConstraint->getFrameOffsetB();
- Transform gTrans;
+ Transform3D gTrans;
B_TO_G(btTransform, gTrans);
return gTrans;
}
-Transform SliderJointBullet::getFrameOffsetA() {
+Transform3D SliderJointBullet::getFrameOffsetA() {
btTransform btTransform = sliderConstraint->getFrameOffsetA();
- Transform gTrans;
+ Transform3D gTrans;
B_TO_G(btTransform, gTrans);
return gTrans;
}
-Transform SliderJointBullet::getFrameOffsetB() {
+Transform3D SliderJointBullet::getFrameOffsetB() {
btTransform btTransform = sliderConstraint->getFrameOffsetB();
- Transform gTrans;
+ Transform3D gTrans;
B_TO_G(btTransform, gTrans);
return gTrans;
}
diff --git a/modules/bullet/slider_joint_bullet.h b/modules/bullet/slider_joint_bullet.h
index 90964671c2..0c93558449 100644
--- a/modules/bullet/slider_joint_bullet.h
+++ b/modules/bullet/slider_joint_bullet.h
@@ -44,18 +44,18 @@ class SliderJointBullet : public JointBullet {
public:
/// Reference frame is A
- SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB);
+ SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB);
virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_SLIDER; }
const RigidBodyBullet *getRigidBodyA() const;
const RigidBodyBullet *getRigidBodyB() const;
- const Transform getCalculatedTransformA() const;
- const Transform getCalculatedTransformB() const;
- const Transform getFrameOffsetA() const;
- const Transform getFrameOffsetB() const;
- Transform getFrameOffsetA();
- Transform getFrameOffsetB();
+ const Transform3D getCalculatedTransformA() const;
+ const Transform3D getCalculatedTransformB() const;
+ const Transform3D getFrameOffsetA() const;
+ const Transform3D getFrameOffsetB() const;
+ Transform3D getFrameOffsetA();
+ Transform3D getFrameOffsetB();
real_t getLowerLinLimit() const;
void setLowerLinLimit(real_t lowerLimit);
real_t getUpperLinLimit() const;
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index 2c8727baf2..bbbb0e7851 100644
--- a/modules/bullet/soft_body_bullet.cpp
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -136,7 +136,7 @@ void SoftBodyBullet::destroy_soft_body() {
bt_soft_body = nullptr;
}
-void SoftBodyBullet::set_soft_transform(const Transform &p_transform) {
+void SoftBodyBullet::set_soft_transform(const Transform3D &p_transform) {
reset_all_node_positions();
move_all_nodes(p_transform);
}
@@ -159,7 +159,7 @@ AABB SoftBodyBullet::get_bounds() const {
return aabb;
}
-void SoftBodyBullet::move_all_nodes(const Transform &p_transform) {
+void SoftBodyBullet::move_all_nodes(const Transform3D &p_transform) {
if (!bt_soft_body) {
return;
}
diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h
index 87023b2517..63708b57a7 100644
--- a/modules/bullet/soft_body_bullet.h
+++ b/modules/bullet/soft_body_bullet.h
@@ -104,11 +104,11 @@ public:
void destroy_soft_body();
// Special function. This function has bad performance
- void set_soft_transform(const Transform &p_transform);
+ void set_soft_transform(const Transform3D &p_transform);
AABB get_bounds() const;
- void move_all_nodes(const Transform &p_transform);
+ void move_all_nodes(const Transform3D &p_transform);
void set_node_position(int node_index, const Vector3 &p_global_position);
void set_node_position(int node_index, const btVector3 &p_global_position);
void get_node_position(int node_index, Vector3 &r_position) const;
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index bdaec4a09e..33dd9ef56d 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -117,7 +117,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V
}
}
-int BulletPhysicsDirectSpaceState::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) {
+int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform3D &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;
}
@@ -152,7 +152,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra
return btQuery.m_count;
}
-bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_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) {
+bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_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) {
r_closest_safe = 0.0f;
r_closest_unsafe = 0.0f;
btVector3 bt_motion;
@@ -214,7 +214,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf
}
/// Returns the list of contacts pairs in this order: Local contact, other body contact
-bool BulletPhysicsDirectSpaceState::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) {
+bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform3D &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 false;
}
@@ -250,7 +250,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &
return btQuery.m_count;
}
-bool BulletPhysicsDirectSpaceState::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) {
+bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform3D &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) {
ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->getornull(p_shape);
ERR_FAIL_COND_V(!shape, false);
@@ -445,7 +445,7 @@ real_t SpaceBullet::get_param(PhysicsServer3D::SpaceParameter p_param) {
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.");
+ WARN_PRINT("The SpaceBullet doesn't support this get parameter (" + itos(p_param) + "), 0 is returned.");
return 0.f;
}
}
@@ -908,7 +908,7 @@ 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, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &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
@@ -1062,7 +1062,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, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) {
+int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) {
btTransform body_transform;
G_TO_B(p_transform, body_transform);
UNSCALE_BT_BASIS(body_transform);
diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h
index 87aa2b9e93..36d0538e6b 100644
--- a/modules/bullet/space_bullet.h
+++ b/modules/bullet/space_bullet.h
@@ -78,11 +78,11 @@ 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) override;
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) override;
- 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) override;
- virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &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) override;
+ virtual int intersect_shape(const RID &p_shape, const Transform3D &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) override;
+ virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &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) override;
/// 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, 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) override;
- 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) override;
+ virtual bool collide_shape(RID p_shape, const Transform3D &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) override;
+ virtual bool rest_info(RID p_shape, const Transform3D &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) override;
virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override;
};
@@ -188,8 +188,8 @@ public:
real_t get_linear_damp() const { return linear_damp; }
real_t get_angular_damp() const { return angular_damp; }
- 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, real_t p_margin);
+ bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &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 Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin);
private:
void create_empty_world(bool p_create_soft_world);
diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_osx.mm
index 3d2053ad23..9b59b68075 100644
--- a/modules/camera/camera_osx.mm
+++ b/modules/camera/camera_osx.mm
@@ -106,15 +106,15 @@
if (input) {
[self removeInput:input];
// don't release this
- input = NULL;
+ input = nullptr;
}
// free up our output
if (output) {
[self removeOutput:output];
- [output setSampleBufferDelegate:nil queue:NULL];
+ [output setSampleBufferDelegate:nil queue:nullptr];
[output release];
- output = NULL;
+ output = nullptr;
}
[self commitConfiguration];
@@ -141,9 +141,9 @@
// get our buffers
unsigned char *dataY = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
unsigned char *dataCbCr = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
- if (dataY == NULL) {
+ if (dataY == nullptr) {
print_line("Couldn't access Y pixel buffer data");
- } else if (dataCbCr == NULL) {
+ } else if (dataCbCr == nullptr) {
print_line("Couldn't access CbCr pixel buffer data");
} else {
Ref<Image> img[2];
@@ -220,8 +220,8 @@ AVCaptureDevice *CameraFeedOSX::get_device() const {
};
CameraFeedOSX::CameraFeedOSX() {
- device = NULL;
- capture_session = NULL;
+ device = nullptr;
+ capture_session = nullptr;
};
void CameraFeedOSX::set_device(AVCaptureDevice *p_device) {
@@ -240,14 +240,14 @@ void CameraFeedOSX::set_device(AVCaptureDevice *p_device) {
};
CameraFeedOSX::~CameraFeedOSX() {
- if (capture_session != NULL) {
+ if (capture_session != nullptr) {
[capture_session release];
- capture_session = NULL;
+ capture_session = nullptr;
};
- if (device != NULL) {
+ if (device != nullptr) {
[device release];
- device = NULL;
+ device = nullptr;
};
};
@@ -267,7 +267,7 @@ void CameraFeedOSX::deactivate_feed() {
if (capture_session) {
[capture_session cleanup];
[capture_session release];
- capture_session = NULL;
+ capture_session = nullptr;
};
};
diff --git a/modules/csg/config.py b/modules/csg/config.py
index 9106cbceca..3991b846f9 100644
--- a/modules/csg/config.py
+++ b/modules/csg/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return True
+ return not env["disable_3d"]
def configure(env):
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 7387842259..5a37486568 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -265,7 +265,7 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<
_regen_face_aabbs();
}
-void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform &p_xform) {
+void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform3D &p_xform) {
faces = p_brush.faces;
materials = p_brush.materials;
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index 3fbed66e5c..c872860486 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -33,10 +33,10 @@
#include "core/math/aabb.h"
#include "core/math/plane.h"
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include "core/math/vector2.h"
#include "core/math/vector3.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/templates/list.h"
#include "core/templates/map.h"
#include "core/templates/oa_hash_map.h"
@@ -60,7 +60,7 @@ struct CSGBrush {
// 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 copy_from(const CSGBrush &p_brush, const Transform &p_xform);
+ void copy_from(const CSGBrush &p_brush, const Transform3D &p_xform);
};
struct CSGBrushOperation {
@@ -165,8 +165,8 @@ struct CSGBrushOperation {
Vector<Vertex2D> vertices;
Vector<Face2D> faces;
Plane plane;
- Transform to_2D;
- Transform to_3D;
+ Transform3D to_2D;
+ Transform3D to_3D;
float vertex_snap2 = 0.0;
inline int _get_point_idx(const Vector2 &p_point);
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index e23442ef99..37a7d96de5 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -99,9 +99,9 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int
void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
- Transform gt = cs->get_global_transform();
+ Transform3D gt = cs->get_global_transform();
//gt.orthonormalize();
- Transform gi = gt.affine_inverse();
+ Transform3D gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -292,27 +292,16 @@ bool CSGShape3DGizmoPlugin::is_selectable_when_hidden() const {
}
void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
-
p_gizmo->clear();
- Ref<Material> material;
- switch (cs->get_operation()) {
- case CSGShape3D::OPERATION_UNION:
- material = get_material("shape_union_material", p_gizmo);
- break;
- case CSGShape3D::OPERATION_INTERSECTION:
- material = get_material("shape_intersection_material", p_gizmo);
- break;
- case CSGShape3D::OPERATION_SUBTRACTION:
- material = get_material("shape_subtraction_material", p_gizmo);
- break;
- }
-
- Ref<Material> handles_material = get_material("handles");
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
Vector<Vector3> faces = cs->get_brush_faces();
+ if (faces.size() == 0) {
+ return;
+ }
+
Vector<Vector3> lines;
lines.resize(faces.size() * 2);
{
@@ -328,6 +317,21 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
+ Ref<Material> material;
+ switch (cs->get_operation()) {
+ case CSGShape3D::OPERATION_UNION:
+ material = get_material("shape_union_material", p_gizmo);
+ break;
+ case CSGShape3D::OPERATION_INTERSECTION:
+ material = get_material("shape_intersection_material", p_gizmo);
+ break;
+ case CSGShape3D::OPERATION_SUBTRACTION:
+ material = get_material("shape_subtraction_material", p_gizmo);
+ break;
+ }
+
+ Ref<Material> handles_material = get_material("handles");
+
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 77be493be9..d6690bb96c 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -89,6 +89,7 @@ uint32_t CSGShape3D::get_collision_mask() const {
}
void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -99,20 +100,23 @@ void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool CSGShape3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void CSGShape3D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_layer();
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+ uint32_t layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ layer |= 1 << p_bit;
} else {
- mask &= ~(1 << p_bit);
+ layer &= ~(1 << p_bit);
}
- set_collision_layer(mask);
+ set_collision_layer(layer);
}
bool CSGShape3D::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
@@ -574,7 +578,7 @@ Array CSGShape3D::get_meshes() const {
if (root_mesh.is_valid()) {
Array arr;
arr.resize(2);
- arr[0] = Transform();
+ arr[0] = Transform3D();
arr[1] = root_mesh;
return arr;
}
@@ -880,7 +884,7 @@ void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) {
mesh->connect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed));
}
- _make_dirty();
+ _mesh_changed();
}
Ref<Mesh> CSGMesh3D::get_mesh() {
@@ -919,45 +923,43 @@ CSGBrush *CSGSphere3D::_build_brush() {
Ref<Material> *materialsw = materials.ptrw();
bool *invertw = invert.ptrw();
+ const double lat_step = 1.0 / rings;
+ const double lon_step = 1.0 / radial_segments;
int face = 0;
- const double lat_step = Math_TAU / rings;
- const double lon_step = Math_TAU / radial_segments;
-
for (int i = 1; i <= rings; i++) {
- double lat0 = lat_step * (i - 1) - Math_TAU / 4;
- double z0 = Math::sin(lat0);
- double zr0 = Math::cos(lat0);
- double u0 = double(i - 1) / rings;
-
- double lat1 = lat_step * i - Math_TAU / 4;
- double z1 = Math::sin(lat1);
- double zr1 = Math::cos(lat1);
- double u1 = double(i) / rings;
-
- for (int j = radial_segments; j >= 1; j--) {
- double lng0 = lon_step * (j - 1);
+ double lat0 = Math_PI * (0.5 - (i - 1) * lat_step);
+ double c0 = Math::cos(lat0);
+ double s0 = Math::sin(lat0);
+ double v0 = double(i - 1) / rings;
+
+ double lat1 = Math_PI * (0.5 - i * lat_step);
+ double c1 = Math::cos(lat1);
+ double s1 = Math::sin(lat1);
+ double v1 = double(i) / rings;
+
+ for (int j = 1; j <= radial_segments; j++) {
+ double lng0 = Math_TAU * (0.5 - (j - 1) * lon_step);
double x0 = Math::cos(lng0);
double y0 = Math::sin(lng0);
- double v0 = double(i - 1) / radial_segments;
+ double u0 = double(j - 1) / radial_segments;
- double lng1 = lon_step * j;
+ double lng1 = Math_TAU * (0.5 - j * lon_step);
double x1 = Math::cos(lng1);
double y1 = Math::sin(lng1);
- double v1 = double(i) / radial_segments;
+ double u1 = double(j) / radial_segments;
Vector3 v[4] = {
- Vector3(x1 * zr0, z0, y1 * zr0) * radius,
- Vector3(x1 * zr1, z1, y1 * zr1) * radius,
- Vector3(x0 * zr1, z1, y0 * zr1) * radius,
- Vector3(x0 * zr0, z0, y0 * zr0) * radius
+ Vector3(x0 * c0, s0, y0 * c0) * radius,
+ Vector3(x1 * c0, s0, y1 * c0) * radius,
+ Vector3(x1 * c1, s1, y1 * c1) * radius,
+ Vector3(x0 * c1, s1, y0 * c1) * radius,
};
Vector2 u[4] = {
- Vector2(v1, u0),
- Vector2(v1, u1),
- Vector2(v0, u1),
- Vector2(v0, u0),
-
+ Vector2(u0, v0),
+ Vector2(u1, v0),
+ Vector2(u1, v1),
+ Vector2(u0, v1),
};
if (i < rings) {
@@ -1741,7 +1743,6 @@ CSGBrush *CSGPolygon3D::_build_brush() {
path_cache->connect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
path_cache->connect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
- path_cache = nullptr;
}
curve = path->get_curve();
if (curve.is_null()) {
@@ -1977,13 +1978,13 @@ CSGBrush *CSGPolygon3D::_build_brush() {
float u1 = 0.0;
float u2 = path_continuous_u ? 0.0 : 1.0;
- Transform path_to_this;
+ Transform3D path_to_this;
if (!path_local) {
// center on paths origin
path_to_this = get_global_transform().affine_inverse() * path->get_global_transform();
}
- Transform prev_xf;
+ Transform3D prev_xf;
Vector3 lookat_dir;
@@ -2005,7 +2006,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
ofs = 0.0;
}
- Transform xf;
+ Transform3D xf;
xf.origin = curve->interpolate_baked(ofs);
Vector3 local_dir;
@@ -2226,7 +2227,7 @@ void CSGPolygon3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees");
ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path"), "set_path_node", "get_path_node");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_path_interval", "get_path_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local");
diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml
index 1bab8f4ee9..5fa8427843 100644
--- a/modules/csg/doc_classes/CSGMesh3D.xml
+++ b/modules/csg/doc_classes/CSGMesh3D.xml
@@ -4,7 +4,7 @@
A CSG Mesh shape that uses a mesh resource.
</brief_description>
<description>
- This CSG node allows you to use any mesh resource as a CSG shape, provided it is closed, does not self-intersect, does not contain internal faces and has no edges that connect to more then two faces.
+ This CSG node allows you to use any mesh resource as a CSG shape, provided it is closed, does not self-intersect, does not contain internal faces and has no edges that connect to more than two faces.
</description>
<tutorials>
</tutorials>
@@ -16,6 +16,7 @@
</member>
<member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
The [Mesh] resource to use as a CSG shape.
+ [b]Note:[/b] When using an [ArrayMesh], avoid meshes with vertex normals unless a flat shader is required. By default, CSGMesh will ignore the mesh's vertex normals and use a smooth shader calculated using the faces' normals. If a flat shader is required, ensure that all faces' vertex normals are parallel.
</member>
</members>
<constants>
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
index dac556c7f1..01ec46e707 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -31,7 +31,7 @@
<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.
+ Returns an [Array] with two elements, the first is the [Transform3D] 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">
diff --git a/modules/csg/icons/CSGBox3D.svg b/modules/csg/icons/CSGBox3D.svg
index ceef9196a7..2740cc2f8c 100644
--- a/modules/csg/icons/CSGBox3D.svg
+++ b/modules/csg/icons/CSGBox3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/><path d="m8 .94531-7 3.5v7.2227l7 3.5.29492-.14844c-.18282-.30101-.29492-.64737-.29492-1.0195v-2c0-.72651.40824-1.3664 1-1.7168v-1.6699l4-2v1.3867h1c.36419 0 .70336.10754 1 .2832v-3.8379zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002z" fill="#fc9c9c" stroke-width="1.0667"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/><path d="m8 .94531-7 3.5v7.2227l7 3.5.29492-.14844c-.18282-.30101-.29492-.64737-.29492-1.0195v-2c0-.72651.40824-1.3664 1-1.7168v-1.6699l4-2v1.3867h1c.36419 0 .70336.10754 1 .2832v-3.8379zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002z" fill="#fc7f7f" stroke-width="1.0667"/></svg>
diff --git a/modules/csg/icons/CSGCapsule3D.svg b/modules/csg/icons/CSGCapsule3D.svg
index 14e582ee84..db4f71864b 100644
--- a/modules/csg/icons/CSGCapsule3D.svg
+++ b/modules/csg/icons/CSGCapsule3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.7527 0-5 2.2418-5 4.9902v4.0176c0 2.7484 2.2473 4.9922 5 4.9922.092943 0 .18367-.008623.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72887.41095-1.3691 1.0059-1.7188v-.28125c.34771-.034464.68259-.10691 1.0156-.19922.10394-.99856.95603-1.8008 1.9785-1.8008h1v-2.0098c0-2.7484-2.2473-4.9902-5-4.9902zm-1.0059 2.127v4.8574c-.66556-.1047-1.2974-.37231-1.9941-.66211v-1.3223c0-1.3474.79841-2.4642 1.9941-2.873zm2.0117 0c1.1957.4088 1.9941 1.5256 1.9941 2.873v1.3457c-.68406.3054-1.3142.57292-1.9941.66602v-4.8848zm-4.0059 6.334c.67836.2231 1.3126.44599 1.9941.52539v2.8848c-1.1957-.4092-1.9941-1.5237-1.9941-2.8711v-.53906z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.7527 0-5 2.2418-5 4.9902v4.0176c0 2.7484 2.2473 4.9922 5 4.9922.092943 0 .18367-.008623.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72887.41095-1.3691 1.0059-1.7188v-.28125c.34771-.034464.68259-.10691 1.0156-.19922.10394-.99856.95603-1.8008 1.9785-1.8008h1v-2.0098c0-2.7484-2.2473-4.9902-5-4.9902zm-1.0059 2.127v4.8574c-.66556-.1047-1.2974-.37231-1.9941-.66211v-1.3223c0-1.3474.79841-2.4642 1.9941-2.873zm2.0117 0c1.1957.4088 1.9941 1.5256 1.9941 2.873v1.3457c-.68406.3054-1.3142.57292-1.9941.66602v-4.8848zm-4.0059 6.334c.67836.2231 1.3126.44599 1.9941.52539v2.8848c-1.1957-.4092-1.9941-1.5237-1.9941-2.8711v-.53906z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/icons/CSGCombiner3D.svg b/modules/csg/icons/CSGCombiner3D.svg
index 50ce4179d9..692ba54cb8 100644
--- a/modules/csg/icons/CSGCombiner3D.svg
+++ b/modules/csg/icons/CSGCombiner3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/><path d="m3 1c-1.1046 0-2 .89543-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm0 4c0 1.1046.89543 2 2 2v-2zm4 0v2h2v-2z" fill="#fc9c9c"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/><path d="m3 1c-1.1046 0-2 .89543-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm0 4c0 1.1046.89543 2 2 2v-2zm4 0v2h2v-2z" fill="#fc7f7f"/></svg>
diff --git a/modules/csg/icons/CSGCylinder3D.svg b/modules/csg/icons/CSGCylinder3D.svg
index c84594928a..4bc2427887 100644
--- a/modules/csg/icons/CSGCylinder3D.svg
+++ b/modules/csg/icons/CSGCylinder3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-1.7469 0-3.328.22648-4.5586.63672-.61528.20512-1.1471.45187-1.5898.80078-.44272.34891-.85156.88101-.85156 1.5625v8c0 .68149.40884 1.2155.85156 1.5645.44272.34891.97457.59577 1.5898.80078 1.2306.41024 2.8117.63477 4.5586.63477.095648 0 .18467-.008426.2793-.009766-.1722-.29446-.2793-.62995-.2793-.99023v-1c-1.5668 0-2.9867-.2195-3.9277-.5332-.46329-.15435-.90474-.33752-1.0723-.4668v-5.8125c.1468.058667.2835.12515.44141.17773 1.2306.41024 2.8117.63477 4.5586.63477s3.328-.22453 4.5586-.63477c.15791-.052267.29461-.11864.44141-.17773v1.8125h1c.36396 0 .70348.10774 1 .2832v-4.2832c0-.68149-.40884-1.2136-.85156-1.5625-.44272-.34891-.97457-.59566-1.5898-.80078-1.2306-.41024-2.8117-.63672-4.5586-.63672zm0 2c1.5668 0 2.9867.22145 3.9277.53516.46368.15456.80138.33741.96875.4668-.16752.12928-.50546.3105-.96875.46484-.94102.31371-2.361.5332-3.9277.5332s-2.9867-.2195-3.9277-.5332c-.46329-.15435-.80123-.33556-.96875-.46484.16737-.12939.50507-.31224.96875-.4668.94102-.31371 2.361-.53516 3.9277-.53516z" fill="#fc9c9c" stroke-width="1.0667" transform="scale(.9375)"/><path d="m11.25 8.4375c-.51938 0-.9375.41812-.9375.9375v.9375h1.875v1.875h.9375c.51938 0 .9375-.41812.9375-.9375v-1.875c0-.51938-.41812-.9375-.9375-.9375zm.9375 3.75h-1.875v-1.875h-.9375c-.51938 0-.9375.41812-.9375.9375v1.875c0 .51938.41812.9375.9375.9375h1.875c.51938 0 .9375-.41812.9375-.9375z" fill="#84c2ff"/></svg>
+<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-1.7469 0-3.328.22648-4.5586.63672-.61528.20512-1.1471.45187-1.5898.80078-.44272.34891-.85156.88101-.85156 1.5625v8c0 .68149.40884 1.2155.85156 1.5645.44272.34891.97457.59577 1.5898.80078 1.2306.41024 2.8117.63477 4.5586.63477.095648 0 .18467-.008426.2793-.009766-.1722-.29446-.2793-.62995-.2793-.99023v-1c-1.5668 0-2.9867-.2195-3.9277-.5332-.46329-.15435-.90474-.33752-1.0723-.4668v-5.8125c.1468.058667.2835.12515.44141.17773 1.2306.41024 2.8117.63477 4.5586.63477s3.328-.22453 4.5586-.63477c.15791-.052267.29461-.11864.44141-.17773v1.8125h1c.36396 0 .70348.10774 1 .2832v-4.2832c0-.68149-.40884-1.2136-.85156-1.5625-.44272-.34891-.97457-.59566-1.5898-.80078-1.2306-.41024-2.8117-.63672-4.5586-.63672zm0 2c1.5668 0 2.9867.22145 3.9277.53516.46368.15456.80138.33741.96875.4668-.16752.12928-.50546.3105-.96875.46484-.94102.31371-2.361.5332-3.9277.5332s-2.9867-.2195-3.9277-.5332c-.46329-.15435-.80123-.33556-.96875-.46484.16737-.12939.50507-.31224.96875-.4668.94102-.31371 2.361-.53516 3.9277-.53516z" fill="#fc7f7f" stroke-width="1.0667" transform="scale(.9375)"/><path d="m11.25 8.4375c-.51938 0-.9375.41812-.9375.9375v.9375h1.875v1.875h.9375c.51938 0 .9375-.41812.9375-.9375v-1.875c0-.51938-.41812-.9375-.9375-.9375zm.9375 3.75h-1.875v-1.875h-.9375c-.51938 0-.9375.41812-.9375.9375v1.875c0 .51938.41812.9375.9375.9375h1.875c.51938 0 .9375-.41812.9375-.9375z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/icons/CSGMesh3D.svg b/modules/csg/icons/CSGMesh3D.svg
index 962e71f6ae..8f4a1736fb 100644
--- a/modules/csg/icons/CSGMesh3D.svg
+++ b/modules/csg/icons/CSGMesh3D.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 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h3.2695v-2h-3.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l4.916 4.916c.31428-.20669.68609-.33008 1.084-.33008 0-.3979.12338-.76971.33008-1.084l-4.916-4.916h5.8574c.17478.30301.42598.55488.72852.73047v3.2695h2v-3.2715c.61771-.35663.99874-1.0152 1-1.7285 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg>
+<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 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h3.2695v-2h-3.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l4.916 4.916c.31428-.20669.68609-.33008 1.084-.33008 0-.3979.12338-.76971.33008-1.084l-4.916-4.916h5.8574c.17478.30301.42598.55488.72852.73047v3.2695h2v-3.2715c.61771-.35663.99874-1.0152 1-1.7285 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/icons/CSGPolygon3D.svg b/modules/csg/icons/CSGPolygon3D.svg
index 1d496e5fd9..971f3577bb 100644
--- a/modules/csg/icons/CSGPolygon3D.svg
+++ b/modules/csg/icons/CSGPolygon3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9629 1.002c-.14254.00487-.28238.04016-.41016.10352l-6 3c-.33878.16944-.55276.51574-.55273.89453v5.832c-.105.61631.37487 1.1768 1 1.168h5v2c.0000216.67546.64487 1.1297 1.2617.95898-.16118-.28721-.26172-.61135-.26172-.95898v-2c0-.72673.40794-1.3664 1-1.7168v-1.666l4-2v1.3828h1c.36397 0 .70348.10774 1 .2832v-3.2773c.000006-.00195.000006-.0039094 0-.0058594.000026-.37879-.21395-.72509-.55273-.89453l-6-3c-.15022-.074574-.31679-.11017-.48438-.10352zm.037109 2.1172 3.7637 1.8809-2.7637 1.3809v-1.3809c-.0000552-.55226-.44774-.99994-1-1h-1.7617l1.7617-.88086zm-5 2.8809h4v4h-4z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9629 1.002c-.14254.00487-.28238.04016-.41016.10352l-6 3c-.33878.16944-.55276.51574-.55273.89453v5.832c-.105.61631.37487 1.1768 1 1.168h5v2c.0000216.67546.64487 1.1297 1.2617.95898-.16118-.28721-.26172-.61135-.26172-.95898v-2c0-.72673.40794-1.3664 1-1.7168v-1.666l4-2v1.3828h1c.36397 0 .70348.10774 1 .2832v-3.2773c.000006-.00195.000006-.0039094 0-.0058594.000026-.37879-.21395-.72509-.55273-.89453l-6-3c-.15022-.074574-.31679-.11017-.48438-.10352zm.037109 2.1172 3.7637 1.8809-2.7637 1.3809v-1.3809c-.0000552-.55226-.44774-.99994-1-1h-1.7617l1.7617-.88086zm-5 2.8809h4v4h-4z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/icons/CSGSphere3D.svg b/modules/csg/icons/CSGSphere3D.svg
index 639e38f49f..770af80632 100644
--- a/modules/csg/icons/CSGSphere3D.svg
+++ b/modules/csg/icons/CSGSphere3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7 .093042 0 .18321-.01004.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72673.40794-1.3664 1-1.7168v-.33398c.34074-.019259.67728-.069097 1.0156-.10547.083091-1.0187.94713-1.8438 1.9844-1.8438h2c.35841 0 .69292.10484.98633.27539.003633-.092184.013672-.18235.013672-.27539 0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-.071342-2.6061-.29819-3.9434-.69141.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549.41253 3.637 2.0767 3.9414 4.1699-1.3046.36677-2.6158.60259-3.9414.6875zm-5.7793 6.2988c1.2733.31892 2.5337.50215 3.7793.5625v2.9414c-1.8291-.36719-3.266-1.7339-3.7793-3.5039z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7 .093042 0 .18321-.01004.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72673.40794-1.3664 1-1.7168v-.33398c.34074-.019259.67728-.069097 1.0156-.10547.083091-1.0187.94713-1.8438 1.9844-1.8438h2c.35841 0 .69292.10484.98633.27539.003633-.092184.013672-.18235.013672-.27539 0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-.071342-2.6061-.29819-3.9434-.69141.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549.41253 3.637 2.0767 3.9414 4.1699-1.3046.36677-2.6158.60259-3.9414.6875zm-5.7793 6.2988c1.2733.31892 2.5337.50215 3.7793.5625v2.9414c-1.8291-.36719-3.266-1.7339-3.7793-3.5039z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/icons/CSGTorus3D.svg b/modules/csg/icons/CSGTorus3D.svg
index eb8c0f37cb..ece9c68d28 100644
--- a/modules/csg/icons/CSGTorus3D.svg
+++ b/modules/csg/icons/CSGTorus3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3c-1.8145 0-3.4691.41721-4.7461 1.1621-1.277.745-2.2539 1.9082-2.2539 3.3379 0 1.4298.9769 2.5949 2.2539 3.3398s2.9316 1.1602 4.7461 1.1602c0-1.0907.90931-2 2-2 0-.080836.013744-.15778.023438-.23633-.61769.14673-1.3008.23633-2.0234.23633-1.4992 0-2.8437-.36687-3.7383-.88867-.89456-.5219-1.2617-1.108-1.2617-1.6113 0-.5032.36716-1.0876 1.2617-1.6094.89456-.5219 2.2391-.89062 3.7383-.89062s2.8437.36872 3.7383.89062c.89456.5218 1.2617 1.1062 1.2617 1.6094 0 .15978-.053679.32822-.13281.5h1.1328c.32481 0 .62893.088408.90234.23047.057552-.23582.097656-.47718.097656-.73047 0-1.4297-.9769-2.5929-2.2539-3.3379-1.277-.7449-2.9316-1.1621-4.7461-1.1621z" fill="#fc9c9c"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#84c2ff"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3c-1.8145 0-3.4691.41721-4.7461 1.1621-1.277.745-2.2539 1.9082-2.2539 3.3379 0 1.4298.9769 2.5949 2.2539 3.3398s2.9316 1.1602 4.7461 1.1602c0-1.0907.90931-2 2-2 0-.080836.013744-.15778.023438-.23633-.61769.14673-1.3008.23633-2.0234.23633-1.4992 0-2.8437-.36687-3.7383-.88867-.89456-.5219-1.2617-1.108-1.2617-1.6113 0-.5032.36716-1.0876 1.2617-1.6094.89456-.5219 2.2391-.89062 3.7383-.89062s2.8437.36872 3.7383.89062c.89456.5218 1.2617 1.1062 1.2617 1.6094 0 .15978-.053679.32822-.13281.5h1.1328c.32481 0 .62893.088408.90234.23047.057552-.23582.097656-.47718.097656-.73047 0-1.4297-.9769-2.5929-2.2539-3.3379-1.277-.7449-2.9316-1.1621-4.7461-1.1621z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg>
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index 2fef576b77..fced61a600 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -30,7 +30,7 @@
#include "texture_loader_dds.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#define PF_FOURCC(s) ((uint32_t)(((s)[3] << 24U) | ((s)[2] << 16U) | ((s)[1] << 8U) | ((s)[0])))
diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
index c8f32ffde6..271cb03c9f 100644
--- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
+++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
@@ -33,10 +33,10 @@
</argument>
<argument index="3" name="out_bandwidth" type="int" default="0">
</argument>
- <argument index="4" name="client_port" type="int" default="0">
+ <argument index="4" name="local_port" type="int" default="0">
</argument>
<description>
- Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]client_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques.
+ Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques.
</description>
</method>
<method name="create_server">
@@ -72,6 +72,13 @@
Returns the channel of the last packet fetched via [method PacketPeer.get_packet].
</description>
</method>
+ <method name="get_local_port" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the local port to which this peer is bound.
+ </description>
+ </method>
<method name="get_packet_channel" qualifiers="const">
<return type="int">
</return>
@@ -137,7 +144,7 @@
</argument>
<description>
Sets the timeout parameters for a peer. The timeout parameters control how and when a peer will timeout from a failure to acknowledge reliable traffic. Timeout values are expressed in milliseconds.
- The [code]timeout_limit[/code] is a factor that, multiplied by a value based on the avarage round trip time, will determine the timeout limit for a reliable packet. When that limit is reached, the timeout will be doubled, and the peer will be disconnected if that limit has reached [code]timeout_min[/code]. The [code]timeout_max[/code] parameter, on the other hand, defines a fixed timeout for which any packet must be acknowledged or the peer will be dropped.
+ The [code]timeout_limit[/code] is a factor that, multiplied by a value based on the average round trip time, will determine the timeout limit for a reliable packet. When that limit is reached, the timeout will be doubled, and the peer will be disconnected if that limit has reached [code]timeout_min[/code]. The [code]timeout_max[/code] parameter, on the other hand, defines a fixed timeout for which any packet must be acknowledged or the peer will be dropped.
</description>
</method>
</methods>
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp
index 25b87145b6..94260e8c13 100644
--- a/modules/enet/networked_multiplayer_enet.cpp
+++ b/modules/enet/networked_multiplayer_enet.cpp
@@ -68,7 +68,7 @@ int NetworkedMultiplayerENet::get_last_packet_channel() const {
Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) {
ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
- ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The port number must be set between 0 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
ERR_FAIL_COND_V_MSG(p_max_clients < 1 || p_max_clients > 4095, ERR_INVALID_PARAMETER, "The number of clients must be set between 1 and 4095 (inclusive).");
ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
@@ -115,46 +115,37 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int
connection_status = CONNECTION_CONNECTED;
return OK;
}
-
-Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_client_port) {
+Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) {
ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
- ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The server port number must be set between 0 and 65535 (inclusive).");
- ERR_FAIL_COND_V_MSG(p_client_port < 0 || p_client_port > 65535, ERR_INVALID_PARAMETER, "The client port number must be set between 0 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, ERR_INVALID_PARAMETER, "The remote port number must be between 1 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(p_local_port < 0 || p_local_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
- if (p_client_port != 0) {
- ENetAddress c_client;
+ ENetAddress c_client;
#ifdef GODOT_ENET
- if (bind_ip.is_wildcard()) {
- c_client.wildcard = 1;
- } else {
- enet_address_set_ip(&c_client, bind_ip.get_ipv6(), 16);
- }
+ if (bind_ip.is_wildcard()) {
+ c_client.wildcard = 1;
+ } else {
+ enet_address_set_ip(&c_client, bind_ip.get_ipv6(), 16);
+ }
#else
- if (bind_ip.is_wildcard()) {
- c_client.host = 0;
- } else {
- ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6.");
- c_client.host = *(uint32_t *)bind_ip.get_ipv4();
- }
+ if (bind_ip.is_wildcard()) {
+ c_client.host = 0;
+ } else {
+ ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6.");
+ c_client.host = *(uint32_t *)bind_ip.get_ipv4();
+ }
#endif
- c_client.port = p_client_port;
+ c_client.port = p_local_port;
- host = enet_host_create(&c_client /* create a client host */,
- 1 /* only allow 1 outgoing connection */,
- channel_count /* allow up to channel_count to be used */,
- p_in_bandwidth /* limit incoming bandwidth if > 0 */,
- p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
- } else {
- host = enet_host_create(nullptr /* create a client host */,
- 1 /* only allow 1 outgoing connection */,
- channel_count /* allow up to channel_count to be used */,
- p_in_bandwidth /* limit incoming bandwidth if > 0 */,
- p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
- }
+ host = enet_host_create(&c_client /* create a client host */,
+ 1 /* only allow 1 outgoing connection */,
+ channel_count /* allow up to channel_count to be used */,
+ p_in_bandwidth /* limit incoming bandwidth if > 0 */,
+ p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create the ENet client host.");
#ifdef GODOT_ENET
@@ -166,7 +157,7 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por
_setup_compressor();
- IP_Address ip;
+ IPAddress ip;
if (p_address.is_valid_ip_address()) {
ip = p_address;
} else {
@@ -371,7 +362,10 @@ void NetworkedMultiplayerENet::poll() {
// To myself and only myself
incoming_packets.push_back(packet);
} else if (!server_relay) {
- // No other destination is allowed when server is not relaying
+ // When relaying is disabled, other destinations will only be processed by the server.
+ if (target == 0 || target < -1) {
+ incoming_packets.push_back(packet);
+ }
continue;
} else if (target == 0) {
// Re-send to everyone but sender :|
@@ -562,7 +556,7 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer
ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size + 8, packet_flags);
encode_uint32(unique_id, &packet->data[0]); // Source ID
encode_uint32(target_peer, &packet->data[4]); // Dest ID
- copymem(&packet->data[8], p_buffer, p_buffer_size);
+ memcpy(&packet->data[8], p_buffer, p_buffer_size);
if (server) {
if (target_peer == 0) {
@@ -673,7 +667,7 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer *
while (total) {
for (size_t i = 0; i < inBufferCount; i++) {
int to_copy = MIN(total, int(inBuffers[i].dataLength));
- copymem(&enet->src_compressor_mem.write[ofs], inBuffers[i].data, to_copy);
+ memcpy(&enet->src_compressor_mem.write[ofs], inBuffers[i].data, to_copy);
ofs += to_copy;
total -= to_copy;
}
@@ -710,7 +704,7 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer *
return 0; // Do not bother
}
- copymem(outData, enet->dst_compressor_mem.ptr(), ret);
+ memcpy(outData, enet->dst_compressor_mem.ptr(), ret);
return ret;
}
@@ -758,12 +752,12 @@ void NetworkedMultiplayerENet::enet_compressor_destroy(void *context) {
// Nothing to do
}
-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] == nullptr, IP_Address(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
+IPAddress NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const {
+ ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), IPAddress(), 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, IPAddress(), "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] == nullptr, IPAddress(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
- IP_Address out;
+ IPAddress out;
#ifdef GODOT_ENET
out.set_ipv6((uint8_t *)&(peer_map[p_peer_id]->address.host));
#else
@@ -784,6 +778,11 @@ int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const {
#endif
}
+int NetworkedMultiplayerENet::get_local_port() const {
+ ERR_FAIL_COND_V_MSG(!active || !host, 0, "The multiplayer instance isn't currently active.");
+ return host->address.port;
+}
+
void NetworkedMultiplayerENet::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) {
ERR_FAIL_COND_MSG(!peer_map.has(p_peer_id), vformat("Peer ID %d not found in the list of peers.", p_peer_id));
ERR_FAIL_COND_MSG(!is_server() && p_peer_id != 1, "Can't change the timeout of peers other then the server when acting as a client.");
@@ -832,7 +831,7 @@ bool NetworkedMultiplayerENet::is_server_relay_enabled() const {
void NetworkedMultiplayerENet::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &NetworkedMultiplayerENet::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "client_port"), &NetworkedMultiplayerENet::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "local_port"), &NetworkedMultiplayerENet::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0));
ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &NetworkedMultiplayerENet::close_connection, DEFVAL(100));
ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "now"), &NetworkedMultiplayerENet::disconnect_peer, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &NetworkedMultiplayerENet::set_compression_mode);
@@ -846,6 +845,7 @@ void NetworkedMultiplayerENet::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &NetworkedMultiplayerENet::is_dtls_verify_enabled);
ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &NetworkedMultiplayerENet::get_peer_address);
ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &NetworkedMultiplayerENet::get_peer_port);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &NetworkedMultiplayerENet::get_local_port);
ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &NetworkedMultiplayerENet::set_peer_timeout);
ClassDB::bind_method(D_METHOD("get_packet_channel"), &NetworkedMultiplayerENet::get_packet_channel);
@@ -880,7 +880,7 @@ NetworkedMultiplayerENet::NetworkedMultiplayerENet() {
enet_compressor.decompress = enet_decompress;
enet_compressor.destroy = enet_compressor_destroy;
- bind_ip = IP_Address("*");
+ bind_ip = IPAddress("*");
}
NetworkedMultiplayerENet::~NetworkedMultiplayerENet() {
@@ -891,7 +891,7 @@ NetworkedMultiplayerENet::~NetworkedMultiplayerENet() {
// Sets IP for ENet to bind when using create_server or create_client
// if no IP is set, then ENet bind to ENET_HOST_ANY
-void NetworkedMultiplayerENet::set_bind_ip(const IP_Address &p_ip) {
+void NetworkedMultiplayerENet::set_bind_ip(const IPAddress &p_ip) {
ERR_FAIL_COND_MSG(!p_ip.is_valid() && !p_ip.is_wildcard(), vformat("Invalid bind IP address: %s", String(p_ip)));
bind_ip = p_ip;
diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/networked_multiplayer_enet.h
index b99b14d218..2d928859fa 100644
--- a/modules/enet/networked_multiplayer_enet.h
+++ b/modules/enet/networked_multiplayer_enet.h
@@ -108,7 +108,7 @@ private:
static void enet_compressor_destroy(void *context);
void _setup_compressor();
- IP_Address bind_ip;
+ IPAddress bind_ip;
bool dtls_enabled = false;
Ref<CryptoKey> dtls_key;
@@ -125,12 +125,13 @@ public:
virtual int get_packet_peer() const override;
- virtual IP_Address get_peer_address(int p_peer_id) const;
+ virtual IPAddress get_peer_address(int p_peer_id) const;
virtual int get_peer_port(int p_peer_id) const;
+ virtual int get_local_port() const;
void set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max);
Error create_server(int p_port, int p_max_clients = 32, int p_in_bandwidth = 0, int p_out_bandwidth = 0);
- Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_client_port = 0);
+ Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_local_port = 0);
void close_connection(uint32_t wait_usec = 100);
@@ -170,7 +171,7 @@ public:
NetworkedMultiplayerENet();
~NetworkedMultiplayerENet();
- void set_bind_ip(const IP_Address &p_ip);
+ void set_bind_ip(const IPAddress &p_ip);
void set_dtls_enabled(bool p_enabled);
bool is_dtls_enabled() const;
void set_dtls_verify_enabled(bool p_enabled);
diff --git a/modules/fbx/README.md b/modules/fbx/README.md
index 2a2f186463..8eca4bd3c9 100644
--- a/modules/fbx/README.md
+++ b/modules/fbx/README.md
@@ -15,7 +15,7 @@ functionality. If anything we should give this parser back to assimp at some poi
# Updating assimp fbx parser
-Don't. it's not possible the code is rewritten in many areas to remove thirdparty deps and various bugs are fixed.
+Don't. It's not possible the code is rewritten in many areas to remove thirdparty deps and various bugs are fixed.
Many days were put into rewriting the parser to use safe code and safe memory accessors.
@@ -79,23 +79,23 @@ enum RotOrder {
// references: ComputePivotTransform / run the calculation
// This is the local pivot transform for the node, not the global transforms
Transform ComputePivotTransform(
- Transform chain[TransformationComp_MAXIMUM],
- Transform &geometric_transform) {
+ Transform3D chain[TransformationComp_MAXIMUM],
+ Transform3D &geometric_transform) {
// Maya pivots
- Transform T = chain[TransformationComp_Translation];
- Transform Roff = chain[TransformationComp_RotationOffset];
- Transform Rp = chain[TransformationComp_RotationPivot];
- Transform Rpre = chain[TransformationComp_PreRotation];
- Transform R = chain[TransformationComp_Rotation];
- Transform Rpost = chain[TransformationComp_PostRotation];
- Transform Soff = chain[TransformationComp_ScalingOffset];
- Transform Sp = chain[TransformationComp_ScalingPivot];
- Transform S = chain[TransformationComp_Scaling];
+ Transform3D T = chain[TransformationComp_Translation];
+ Transform3D Roff = chain[TransformationComp_RotationOffset];
+ Transform3D Rp = chain[TransformationComp_RotationPivot];
+ Transform3D Rpre = chain[TransformationComp_PreRotation];
+ Transform3D R = chain[TransformationComp_Rotation];
+ Transform3D Rpost = chain[TransformationComp_PostRotation];
+ Transform3D Soff = chain[TransformationComp_ScalingOffset];
+ Transform3D Sp = chain[TransformationComp_ScalingPivot];
+ Transform3D S = chain[TransformationComp_Scaling];
// 3DS Max Pivots
- Transform OT = chain[TransformationComp_GeometricTranslation];
- Transform OR = chain[TransformationComp_GeometricRotation];
- Transform OS = chain[TransformationComp_GeometricScaling];
+ Transform3D OT = chain[TransformationComp_GeometricTranslation];
+ Transform3D OR = chain[TransformationComp_GeometricRotation];
+ Transform3D OS = chain[TransformationComp_GeometricScaling];
// Calculate 3DS max pivot transform - use geometric space (e.g doesn't effect children nodes only the current node)
geometric_transform = OT * OR * OS;
diff --git a/modules/fbx/SCsub b/modules/fbx/SCsub
index 84220a66fa..0311fddfee 100644
--- a/modules/fbx/SCsub
+++ b/modules/fbx/SCsub
@@ -8,6 +8,9 @@ env_fbx = env_modules.Clone()
# Make includes relative to the folder path specified here so our includes are clean
env_fbx.Prepend(CPPPATH=["#modules/fbx/"])
+if env["builtin_zlib"]:
+ env_fbx.Prepend(CPPPATH=["#thirdparty/zlib/"])
+
# Godot's own source files
env_fbx.add_source_files(env.modules_sources, "tools/*.cpp")
env_fbx.add_source_files(env.modules_sources, "data/*.cpp")
diff --git a/modules/fbx/data/fbx_bone.h b/modules/fbx/data/fbx_bone.h
index efba147b89..83918ad1e2 100644
--- a/modules/fbx/data/fbx_bone.h
+++ b/modules/fbx/data/fbx_bone.h
@@ -38,7 +38,7 @@
struct PivotTransform;
-struct FBXBone : public Reference {
+struct FBXBone : public RefCounted {
uint64_t parent_bone_id = 0;
uint64_t bone_id = 0;
diff --git a/modules/fbx/data/fbx_material.h b/modules/fbx/data/fbx_material.h
index 23310b8e1d..5fd4d9212b 100644
--- a/modules/fbx/data/fbx_material.h
+++ b/modules/fbx/data/fbx_material.h
@@ -33,10 +33,10 @@
#include "tools/import_utils.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
-struct FBXMaterial : public Reference {
+struct FBXMaterial : public RefCounted {
String material_name = String();
bool warning_non_pbr_material = false;
FBXDocParser::Material *material = nullptr;
@@ -266,7 +266,7 @@ struct FBXMaterial : public Reference {
/* storing the texture properties like color */
template <class T>
- struct TexturePropertyMapping : Reference {
+ struct TexturePropertyMapping : RefCounted {
StandardMaterial3D::TextureParam map_mode = StandardMaterial3D::TextureParam::TEXTURE_ALBEDO;
const T property = T();
};
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index 304d1598f6..8f32c523f9 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -945,7 +945,7 @@ void FBXMeshData::triangulate_polygon(SurfaceData *surface, const Vector<int> &p
for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) {
TPPLPoly &tp = I->get();
- ERR_FAIL_COND_MSG(tp.GetNumPoints() != 3, "The triangulator retuned more points, how this is possible?");
+ ERR_FAIL_COND_MSG(tp.GetNumPoints() != 3, "The triangulator returned more points, how this is possible?");
// Find Index
for (int i = 2; i >= 0; i -= 1) {
const Vector2 vertex = tp.GetPoint(i);
@@ -1126,8 +1126,8 @@ HashMap<int, R> FBXMeshData::extract_per_vertex_data(
}
const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index);
ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR8");
- ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR9.");
- ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] < 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR10.");
+ ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR9.");
+ ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] < 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR10.");
ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] >= (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR11.");
aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_mapping_data.data[p_mapping_data.index[polygon_vertex_index]] });
}
diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h
index 575f833584..7486c5c59c 100644
--- a/modules/fbx/data/fbx_mesh_data.h
+++ b/modules/fbx/data/fbx_mesh_data.h
@@ -78,7 +78,7 @@ struct VertexData {
};
// Caches mesh information and instantiates meshes for you using helper functions.
-struct FBXMeshData : Reference {
+struct FBXMeshData : RefCounted {
struct MorphVertexData {
// TODO we have only these??
/// Each element is a vertex. Not supposed to be void.
@@ -156,7 +156,7 @@ private:
/// [0, 2, 1, 3, 4]
/// The negative values are computed using this formula: `(-value) - 1`
///
- /// Returns the vertex index from the poligon vertex.
+ /// Returns the vertex index from the polygon vertex.
/// Returns -1 if `p_index` is invalid.
int get_vertex_from_polygon_vertex(const std::vector<int> &p_face_indices, int p_index) const;
diff --git a/modules/fbx/data/fbx_node.h b/modules/fbx/data/fbx_node.h
index a6f62f3388..75461e397d 100644
--- a/modules/fbx/data/fbx_node.h
+++ b/modules/fbx/data/fbx_node.h
@@ -40,7 +40,7 @@
class Node3D;
struct PivotTransform;
-struct FBXNode : Reference, ModelAbstraction {
+struct FBXNode : RefCounted, ModelAbstraction {
uint64_t current_node_id = 0;
String node_name = String();
Node3D *godot_node = nullptr;
diff --git a/modules/fbx/data/fbx_skeleton.h b/modules/fbx/data/fbx_skeleton.h
index df937cde49..b6103df949 100644
--- a/modules/fbx/data/fbx_skeleton.h
+++ b/modules/fbx/data/fbx_skeleton.h
@@ -35,14 +35,14 @@
#include "fbx_node.h"
#include "model_abstraction.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "scene/3d/skeleton_3d.h"
struct FBXNode;
struct ImportState;
struct FBXBone;
-struct FBXSkeleton : Reference {
+struct FBXSkeleton : RefCounted {
Ref<FBXNode> fbx_node = Ref<FBXNode>();
Vector<Ref<FBXBone>> skeleton_bones = Vector<Ref<FBXBone>>();
Skeleton3D *skeleton = nullptr;
diff --git a/modules/fbx/data/pivot_transform.cpp b/modules/fbx/data/pivot_transform.cpp
index f4055c830f..4cf42257a4 100644
--- a/modules/fbx/data/pivot_transform.cpp
+++ b/modules/fbx/data/pivot_transform.cpp
@@ -90,7 +90,7 @@ void PivotTransform::ReadTransformChain() {
if (ok) {
geometric_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(GeometricRotation));
} else {
- geometric_rotation = Quat();
+ geometric_rotation = Quaternion();
}
const Vector3 &GeometricTranslation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricTranslation", ok));
@@ -100,7 +100,7 @@ void PivotTransform::ReadTransformChain() {
geometric_translation = Vector3(0, 0, 0);
}
- if (geometric_rotation != Quat()) {
+ if (geometric_rotation != Quaternion()) {
print_error("geometric rotation is unsupported!");
//CRASH_COND(true);
}
@@ -116,8 +116,8 @@ void PivotTransform::ReadTransformChain() {
}
}
-Transform PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const {
- Transform T, Roff, Rp, Soff, Sp, S;
+Transform3D PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const {
+ Transform3D T, Roff, Rp, Soff, Sp, S;
// Here I assume this is the operation which needs done.
// Its WorldTransform * V
@@ -132,29 +132,29 @@ Transform PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quat p_ro
// Scaling node
S.scale(p_scaling);
// Rotation pivots
- Transform Rpre = Transform(pre_rotation);
- Transform R = Transform(p_rotation);
- Transform Rpost = Transform(post_rotation);
+ Transform3D Rpre = Transform3D(pre_rotation);
+ Transform3D R = Transform3D(p_rotation);
+ Transform3D Rpost = Transform3D(post_rotation);
return T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
}
-Transform PivotTransform::ComputeGlobalTransform(Transform t) const {
+Transform3D PivotTransform::ComputeGlobalTransform(Transform3D t) const {
Vector3 pos = t.origin;
Vector3 scale = t.basis.get_scale();
- Quat rot = t.basis.get_rotation_quat();
+ Quaternion rot = t.basis.get_rotation_quaternion();
return ComputeGlobalTransform(pos, rot, scale);
}
-Transform PivotTransform::ComputeLocalTransform(Transform t) const {
+Transform3D PivotTransform::ComputeLocalTransform(Transform3D t) const {
Vector3 pos = t.origin;
Vector3 scale = t.basis.get_scale();
- Quat rot = t.basis.get_rotation_quat();
+ Quaternion rot = t.basis.get_rotation_quaternion();
return ComputeLocalTransform(pos, rot, scale);
}
-Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const {
- Transform T, Roff, Rp, Soff, Sp, S;
+Transform3D PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const {
+ Transform3D T, Roff, Rp, Soff, Sp, S;
// Here I assume this is the operation which needs done.
// Its WorldTransform * V
@@ -170,26 +170,26 @@ Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_r
S.scale(p_scaling);
// Rotation pivots
- Transform Rpre = Transform(pre_rotation);
- Transform R = Transform(p_rotation);
- Transform Rpost = Transform(post_rotation);
+ Transform3D Rpre = Transform3D(pre_rotation);
+ Transform3D R = Transform3D(p_rotation);
+ Transform3D Rpost = Transform3D(post_rotation);
- Transform parent_global_xform;
- Transform parent_local_scaling_m;
+ Transform3D parent_global_xform;
+ Transform3D parent_local_scaling_m;
if (parent_transform.is_valid()) {
parent_global_xform = parent_transform->GlobalTransform;
parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
}
- Transform local_rotation_m, parent_global_rotation_m;
- Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat();
- parent_global_rotation_m.basis.set_quat(parent_global_rotation);
+ Transform3D local_rotation_m, parent_global_rotation_m;
+ Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion();
+ parent_global_rotation_m.basis.set_quaternion(parent_global_rotation);
local_rotation_m = Rpre * R * Rpost;
- //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized());
+ //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized());
- Transform local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
+ Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
Vector3 parent_translation = parent_global_xform.get_origin();
parent_shear_translation.origin = parent_translation;
parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform;
@@ -197,26 +197,26 @@ Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_r
local_shear_scaling = S;
// Inherit type handler - we don't care about T here, just reordering RSrs etc.
- Transform global_rotation_scale;
+ Transform3D global_rotation_scale;
if (inherit_type == FBXDocParser::Transform_RrSs) {
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
} else if (inherit_type == FBXDocParser::Transform_RSrs) {
global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
} else if (inherit_type == FBXDocParser::Transform_Rrs) {
- Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse();
+ Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse();
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
}
- Transform local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
- //Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin);
+ Transform3D local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
+ //Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin);
- ERR_FAIL_COND_V_MSG(local_transform.basis.determinant() == 0, Transform(), "Det == 0 prevented in scene file");
+ ERR_FAIL_COND_V_MSG(local_transform.basis.determinant() == 0, Transform3D(), "Det == 0 prevented in scene file");
// manual hack to force SSC not to be compensated for - until we can handle it properly with tests
return parent_global_xform * local_transform;
}
void PivotTransform::ComputePivotTransform() {
- Transform T, Roff, Rp, Soff, Sp, S;
+ Transform3D T, Roff, Rp, Soff, Sp, S;
// Here I assume this is the operation which needs done.
// Its WorldTransform * V
@@ -237,26 +237,26 @@ void PivotTransform::ComputePivotTransform() {
Local_Scaling_Matrix = S; // copy for when node / child is looking for the value of this.
// Rotation pivots
- Transform Rpre = Transform(pre_rotation);
- Transform R = Transform(rotation);
- Transform Rpost = Transform(post_rotation);
+ Transform3D Rpre = Transform3D(pre_rotation);
+ Transform3D R = Transform3D(rotation);
+ Transform3D Rpost = Transform3D(post_rotation);
- Transform parent_global_xform;
- Transform parent_local_scaling_m;
+ Transform3D parent_global_xform;
+ Transform3D parent_local_scaling_m;
if (parent_transform.is_valid()) {
parent_global_xform = parent_transform->GlobalTransform;
parent_local_scaling_m = parent_transform->Local_Scaling_Matrix;
}
- Transform local_rotation_m, parent_global_rotation_m;
- Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat();
- parent_global_rotation_m.basis.set_quat(parent_global_rotation);
+ Transform3D local_rotation_m, parent_global_rotation_m;
+ Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion();
+ parent_global_rotation_m.basis.set_quaternion(parent_global_rotation);
local_rotation_m = Rpre * R * Rpost;
- //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized());
+ //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized());
- Transform local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
+ Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation;
Vector3 parent_translation = parent_global_xform.get_origin();
parent_shear_translation.origin = parent_translation;
parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform;
@@ -264,24 +264,24 @@ void PivotTransform::ComputePivotTransform() {
local_shear_scaling = S;
// Inherit type handler - we don't care about T here, just reordering RSrs etc.
- Transform global_rotation_scale;
+ Transform3D global_rotation_scale;
if (inherit_type == FBXDocParser::Transform_RrSs) {
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling;
} else if (inherit_type == FBXDocParser::Transform_RSrs) {
global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling;
} else if (inherit_type == FBXDocParser::Transform_Rrs) {
- Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse();
+ Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse();
global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling;
}
- LocalTransform = Transform();
+ LocalTransform = Transform3D();
LocalTransform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse();
ERR_FAIL_COND_MSG(LocalTransform.basis.determinant() == 0, "invalid scale reset");
- Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin);
- GlobalTransform = Transform();
+ Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin);
+ GlobalTransform = Transform3D();
//GlobalTransform = parent_global_xform * LocalTransform;
- Transform global_origin = Transform(Basis(), parent_translation);
+ Transform3D global_origin = Transform3D(Basis(), parent_translation);
GlobalTransform = (global_origin * local_translation_pivoted) * global_rotation_scale;
ImportUtils::debug_xform("local xform calculation", LocalTransform);
diff --git a/modules/fbx/data/pivot_transform.h b/modules/fbx/data/pivot_transform.h
index 9996027870..099b268075 100644
--- a/modules/fbx/data/pivot_transform.h
+++ b/modules/fbx/data/pivot_transform.h
@@ -31,8 +31,8 @@
#ifndef PIVOT_TRANSFORM_H
#define PIVOT_TRANSFORM_H
-#include "core/math/transform.h"
-#include "core/object/reference.h"
+#include "core/math/transform_3d.h"
+#include "core/object/ref_counted.h"
#include "model_abstraction.h"
@@ -55,13 +55,13 @@ enum TransformationComp {
TransformationComp_MAXIMUM
};
// Abstract away pivot data so its simpler to handle
-struct PivotTransform : Reference, ModelAbstraction {
+struct PivotTransform : RefCounted, ModelAbstraction {
// at the end we want to keep geometric_ everything, post and pre rotation
// these are used during animation data processing / keyframe ingestion the rest can be simplified down / out.
- Quat pre_rotation = Quat();
- Quat post_rotation = Quat();
- Quat rotation = Quat();
- Quat geometric_rotation = Quat();
+ Quaternion pre_rotation = Quaternion();
+ Quaternion post_rotation = Quaternion();
+ Quaternion rotation = Quaternion();
+ Quaternion geometric_rotation = Quaternion();
Vector3 rotation_pivot = Vector3();
Vector3 rotation_offset = Vector3();
Vector3 scaling_offset = Vector3(1.0, 1.0, 1.0);
@@ -85,10 +85,10 @@ struct PivotTransform : Reference, ModelAbstraction {
print_verbose("raw post_rotation " + raw_post_rotation * (180 / Math_PI));
}
- Transform ComputeGlobalTransform(Transform t) const;
- Transform ComputeLocalTransform(Transform t) const;
- Transform ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const;
- Transform ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const;
+ Transform3D ComputeGlobalTransform(Transform3D t) const;
+ Transform3D ComputeLocalTransform(Transform3D t) const;
+ Transform3D ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const;
+ Transform3D ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const;
/* Extract into xforms and calculate once */
void ComputePivotTransform();
@@ -105,10 +105,10 @@ struct PivotTransform : Reference, ModelAbstraction {
//Transform chain[TransformationComp_MAXIMUM];
// cached for later use
- Transform GlobalTransform = Transform();
- Transform LocalTransform = Transform();
- Transform Local_Scaling_Matrix = Transform(); // used for inherit type.
- Transform GeometricTransform = Transform(); // 3DS max only
+ Transform3D GlobalTransform = Transform3D();
+ Transform3D LocalTransform = Transform3D();
+ Transform3D Local_Scaling_Matrix = Transform3D(); // used for inherit type.
+ Transform3D GeometricTransform = Transform3D(); // 3DS max only
FBXDocParser::TransformInheritance inherit_type = FBXDocParser::TransformInheritance_MAX; // maya fbx requires this - sorry <3
};
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index b23a58a414..40deaae74d 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -102,9 +102,9 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
FBXDocParser::TokenList tokens;
bool is_binary = false;
- data.resize(f->get_len());
+ data.resize(f->get_length());
- ERR_FAIL_COND_V(data.size() < 64, NULL);
+ ERR_FAIL_COND_V(data.size() < 64, nullptr);
f->get_buffer(data.ptrw(), data.size());
PackedByteArray fbx_header;
@@ -258,24 +258,24 @@ struct EditorSceneImporterAssetImportInterpolate {
//thank you for existing, partial specialization
template <>
-struct EditorSceneImporterAssetImportInterpolate<Quat> {
- Quat lerp(const Quat &a, const Quat &b, float c) const {
- ERR_FAIL_COND_V(!a.is_normalized(), Quat());
- ERR_FAIL_COND_V(!b.is_normalized(), Quat());
+struct EditorSceneImporterAssetImportInterpolate<Quaternion> {
+ Quaternion lerp(const Quaternion &a, const Quaternion &b, float c) const {
+ ERR_FAIL_COND_V(!a.is_normalized(), Quaternion());
+ ERR_FAIL_COND_V(!b.is_normalized(), Quaternion());
return a.slerp(b, c).normalized();
}
- Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, float c) {
- ERR_FAIL_COND_V(!p1.is_normalized(), Quat());
- ERR_FAIL_COND_V(!p2.is_normalized(), Quat());
+ Quaternion catmull_rom(const Quaternion &p0, const Quaternion &p1, const Quaternion &p2, const Quaternion &p3, float c) {
+ ERR_FAIL_COND_V(!p1.is_normalized(), Quaternion());
+ ERR_FAIL_COND_V(!p2.is_normalized(), Quaternion());
return p1.slerp(p2, c).normalized();
}
- Quat bezier(Quat start, Quat control_1, Quat control_2, Quat end, float t) {
- ERR_FAIL_COND_V(!start.is_normalized(), Quat());
- ERR_FAIL_COND_V(!end.is_normalized(), Quat());
+ Quaternion bezier(Quaternion start, Quaternion control_1, Quaternion control_2, Quaternion end, float t) {
+ ERR_FAIL_COND_V(!start.is_normalized(), Quaternion());
+ ERR_FAIL_COND_V(!end.is_normalized(), Quaternion());
return start.slerp(end, t).normalized();
}
@@ -888,7 +888,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
// we need to know what object the curves are for.
// we need the target ID and the target name for the track reduction.
- FBXDocParser::Model::RotOrder quat_rotation_order = FBXDocParser::Model::RotOrder_EulerXYZ;
+ FBXDocParser::Model::RotOrder quaternion_rotation_order = FBXDocParser::Model::RotOrder_EulerXYZ;
// T:: R:: S:: Visible:: Custom::
for (const FBXDocParser::AnimationCurveNode *curve_node : node_list) {
@@ -910,7 +910,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
continue;
} else {
//print_verbose("[doc] applied rotation order: " + itos(target->RotationOrder()));
- quat_rotation_order = target->RotationOrder();
+ quaternion_rotation_order = target->RotationOrder();
}
uint64_t target_id = target->ID();
@@ -1011,10 +1011,9 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
// track count is 5.
// next track id is 5.
const uint64_t target_id = track->key();
- int track_idx = animation->add_track(Animation::TYPE_TRANSFORM);
+ int track_idx = animation->add_track(Animation::TYPE_TRANSFORM3D);
// animation->track_set_path(track_idx, node_path);
- // animation->track_set_path(track_idx, node_path);
Ref<FBXBone> bone;
// note we must not run the below code if the entry doesn't exist, it will create dummy entries which is very bad.
@@ -1024,7 +1023,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
bone = state.fbx_bone_map[target_id];
}
- Transform target_transform;
+ Transform3D target_transform;
if (state.fbx_target_map.has(target_id)) {
Ref<FBXNode> node_ref = state.fbx_target_map[target_id];
@@ -1057,7 +1056,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
//print_verbose("[doc] node animation path: " + node_path);
}
} else {
- // note: this could actually be unsafe this means we should be careful about continuing here, if we see bizzare effects later we should disable this.
+ // note: this could actually be unsafe this means we should be careful about continuing here, if we see bizarre effects later we should disable this.
// I am not sure if this is unsafe or not, testing will tell us this.
print_error("[doc] invalid fbx target detected for this track");
continue;
@@ -1087,7 +1086,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
Vector<float> pos_times;
Vector<Vector3> scale_values;
Vector<float> scale_times;
- Vector<Quat> rot_values;
+ Vector<Quaternion> rot_values;
Vector<float> rot_times;
double max_duration = 0;
@@ -1123,8 +1122,8 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
bool got_pre = false;
bool got_post = false;
- Quat post_rotation;
- Quat pre_rotation;
+ Quaternion post_rotation;
+ Quaternion pre_rotation;
// Rotation matrix
const Vector3 &PreRotation = FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", got_pre);
@@ -1138,24 +1137,24 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
post_rotation = ImportUtils::EulerToQuaternion(rot_order, ImportUtils::deg2rad(PostRotation));
}
- Quat lastQuat = Quat();
+ Quaternion lastQuaternion = Quaternion();
for (std::pair<int64_t, Vector3> rotation_key : rotation_keys.keyframes) {
double animation_track_time = CONVERT_FBX_TIME(rotation_key.first);
//print_verbose("euler rotation key: " + rotation_key.second);
- Quat rot_key_value = ImportUtils::EulerToQuaternion(quat_rotation_order, ImportUtils::deg2rad(rotation_key.second));
+ Quaternion rot_key_value = ImportUtils::EulerToQuaternion(quaternion_rotation_order, ImportUtils::deg2rad(rotation_key.second));
- if (lastQuat != Quat() && rot_key_value.dot(lastQuat) < 0) {
+ if (lastQuaternion != Quaternion() && rot_key_value.dot(lastQuaternion) < 0) {
rot_key_value.x = -rot_key_value.x;
rot_key_value.y = -rot_key_value.y;
rot_key_value.z = -rot_key_value.z;
rot_key_value.w = -rot_key_value.w;
}
// pre_post rotation possibly could fix orientation
- Quat final_rotation = pre_rotation * rot_key_value * post_rotation;
+ Quaternion final_rotation = pre_rotation * rot_key_value * post_rotation;
- lastQuat = final_rotation;
+ lastQuaternion = final_rotation;
if (animation_track_time > max_duration) {
max_duration = animation_track_time;
@@ -1166,7 +1165,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
}
bool valid_rest = false;
- Transform bone_rest;
+ Transform3D bone_rest;
int skeleton_bone = -1;
if (state.fbx_bone_map.has(target_id)) {
if (bone.is_valid() && bone->fbx_skeleton.is_valid()) {
@@ -1183,13 +1182,13 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
}
const Vector3 def_pos = translation_keys.has_default ? (translation_keys.default_value * state.scale) : bone_rest.origin;
- const Quat def_rot = rotation_keys.has_default ? ImportUtils::EulerToQuaternion(quat_rotation_order, ImportUtils::deg2rad(rotation_keys.default_value)) : bone_rest.basis.get_rotation_quat();
+ const Quaternion def_rot = rotation_keys.has_default ? ImportUtils::EulerToQuaternion(quaternion_rotation_order, ImportUtils::deg2rad(rotation_keys.default_value)) : bone_rest.basis.get_rotation_quaternion();
const Vector3 def_scale = scale_keys.has_default ? scale_keys.default_value : bone_rest.basis.get_scale();
print_verbose("track defaults: p(" + def_pos + ") s(" + def_scale + ") r(" + def_rot + ")");
while (true) {
Vector3 pos = def_pos;
- Quat rot = def_rot;
+ Quaternion rot = def_rot;
Vector3 scale = def_scale;
if (pos_values.size()) {
@@ -1198,7 +1197,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
}
if (rot_values.size()) {
- rot = _interpolate_track<Quat>(rot_times, rot_values, time,
+ rot = _interpolate_track<Quaternion>(rot_times, rot_values, time,
AssetImportAnimation::INTERP_LINEAR);
}
@@ -1209,13 +1208,13 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
// node animations must also include pivots
if (skeleton_bone >= 0) {
- Transform xform = Transform();
- xform.basis.set_quat_scale(rot, scale);
+ Transform3D xform = Transform3D();
+ xform.basis.set_quaternion_scale(rot, scale);
xform.origin = pos;
- const Transform t = bone_rest.affine_inverse() * xform;
+ const Transform3D t = bone_rest.affine_inverse() * xform;
// populate this again
- rot = t.basis.get_rotation_quat();
+ rot = t.basis.get_rotation_quaternion();
rot.normalize();
scale = t.basis.get_scale();
pos = t.origin;
diff --git a/modules/fbx/fbx_parser/FBXAnimation.cpp b/modules/fbx/fbx_parser/FBXAnimation.cpp
index 1690df6943..0fbff035fd 100644
--- a/modules/fbx/fbx_parser/FBXAnimation.cpp
+++ b/modules/fbx/fbx_parser/FBXAnimation.cpp
@@ -128,7 +128,7 @@ AnimationCurve::~AnimationCurve() {
// ------------------------------------------------------------------------------------------------
AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name,
- const Document &doc, const char *const *target_prop_whitelist /*= NULL*/,
+ const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
size_t whitelist_size /*= 0*/) :
Object(id, element, name), target(), doc(doc) {
// find target node
diff --git a/modules/fbx/fbx_parser/FBXDeformer.cpp b/modules/fbx/fbx_parser/FBXDeformer.cpp
index 039718ae15..4220ba62a7 100644
--- a/modules/fbx/fbx_parser/FBXDeformer.cpp
+++ b/modules/fbx/fbx_parser/FBXDeformer.cpp
@@ -78,7 +78,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXMeshGeometry.h"
#include "FBXParser.h"
#include "core/math/math_funcs.h"
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include <iostream>
diff --git a/modules/fbx/fbx_parser/FBXDocument.cpp b/modules/fbx/fbx_parser/FBXDocument.cpp
index bb85d6ff7c..89c69d2ee8 100644
--- a/modules/fbx/fbx_parser/FBXDocument.cpp
+++ b/modules/fbx/fbx_parser/FBXDocument.cpp
@@ -487,7 +487,7 @@ const std::vector<const AnimationStack *> &Document::AnimationStacks() const {
const AnimationStack *stack = lazy->Get<AnimationStack>();
ERR_CONTINUE_MSG(!stack, "invalid ptr to AnimationStack - conversion failure");
- // We push back the weak reference :) to keep things simple, as ownership is on the parser side so it wont be cleaned up.
+ // We push back the weak reference :) to keep things simple, as ownership is on the parser side so it won't be cleaned up.
animationStacksResolved.push_back(stack);
}
diff --git a/modules/fbx/fbx_parser/FBXDocument.h b/modules/fbx/fbx_parser/FBXDocument.h
index 49b7c11c31..885ff8fca4 100644
--- a/modules/fbx/fbx_parser/FBXDocument.h
+++ b/modules/fbx/fbx_parser/FBXDocument.h
@@ -37,7 +37,7 @@
#include "FBXCommon.h"
#include "FBXParser.h"
#include "FBXProperties.h"
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include "core/math/vector2.h"
#include "core/math/vector3.h"
#include "core/string/print_string.h"
@@ -242,13 +242,13 @@ public:
return target_id;
}
- Transform GetBindPose() const {
+ Transform3D GetBindPose() const {
return transform;
}
private:
uint64_t target_id = 0;
- Transform transform;
+ Transform3D transform;
};
/** DOM base class for FBX cameras attached to a node */
@@ -699,7 +699,7 @@ private:
typedef std::vector<int64_t> KeyTimeList;
typedef std::vector<float> KeyValueList;
-/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefor) */
+/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefore) */
class AnimationCurve : public Object {
public:
AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
@@ -759,7 +759,7 @@ public:
const AnimationMap &Curves() const;
- /** Object the curve is assigned to, this can be NULL if the
+ /** Object the curve is assigned to, this can be nullptr if the
* target object has no DOM representation or could not
* be read for other reasons.*/
Object *Target() const {
@@ -905,11 +905,11 @@ public:
}
/** */
- const Transform &GetTransform() const {
+ const Transform3D &GetTransform() const {
return transform;
}
- const Transform &TransformLink() const {
+ const Transform3D &TransformLink() const {
return transformLink;
}
@@ -917,7 +917,7 @@ public:
return node;
}
- const Transform &TransformAssociateModel() const {
+ const Transform3D &TransformAssociateModel() const {
return transformAssociateModel;
}
@@ -941,9 +941,9 @@ private:
std::vector<float> weights;
std::vector<unsigned int> indices;
- Transform transform;
- Transform transformLink;
- Transform transformAssociateModel;
+ Transform3D transform;
+ Transform3D transformLink;
+ Transform3D transformAssociateModel;
SkinLinkMode link_mode;
bool valid_transformAssociateModel = false;
const Model *node = nullptr;
@@ -989,7 +989,7 @@ public:
// note: a connection ensures that the source and dest objects exist, but
// not that they have DOM representations, so the return value of one of
- // these functions can still be NULL.
+ // these functions can still be nullptr.
Object *SourceObject() const;
Object *DestinationObject() const;
diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
index 3930e005c3..4a33024969 100644
--- a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
+++ b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
@@ -95,14 +95,14 @@ void DOMError(const std::string &message, const std::shared_ptr<Token> token) {
print_error("[FBX-DOM]" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
}
-void DOMError(const std::string &message, const Element *element /*= NULL*/) {
+void DOMError(const std::string &message, const Element *element /*= nullptr*/) {
if (element) {
DOMError(message, element->KeyToken());
}
print_error("[FBX-DOM] " + String(message.c_str()));
}
-void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) {
+void DOMError(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) {
if (element) {
DOMError(message, element->KeyToken());
}
@@ -117,7 +117,7 @@ void DOMWarning(const std::string &message, const Token *token) {
print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
}
-void DOMWarning(const std::string &message, const Element *element /*= NULL*/) {
+void DOMWarning(const std::string &message, const Element *element /*= nullptr*/) {
if (element) {
DOMWarning(message, element->KeyToken());
return;
@@ -129,7 +129,7 @@ void DOMWarning(const std::string &message, const std::shared_ptr<Token> token)
print_verbose("[FBX-DOM] warning:" + String(message.c_str()) + ";" + String(token->StringContents().c_str()));
}
-void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= NULL*/) {
+void DOMWarning(const std::string &message, const std::shared_ptr<Element> element /*= nullptr*/) {
if (element) {
DOMWarning(message, element->KeyToken());
return;
diff --git a/modules/fbx/fbx_parser/FBXMaterial.cpp b/modules/fbx/fbx_parser/FBXMaterial.cpp
index 08fff5714a..bf8922267e 100644
--- a/modules/fbx/fbx_parser/FBXMaterial.cpp
+++ b/modules/fbx/fbx_parser/FBXMaterial.cpp
@@ -325,7 +325,7 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s
DOMError("embedded content is not surrounded by quotation marks", element);
} else {
size_t targetLength = 0;
- auto numTokens = Content->Tokens().size();
+ const size_t numTokens = Content->Tokens().size();
// First time compute size (it could be large like 64Gb and it is good to allocate it once)
for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
const Token *dataToken = GetRequiredToken(Content, tokenIdx);
diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
index a28e7565c6..2cc25a0690 100644
--- a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
+++ b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
@@ -125,7 +125,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::str
ScopePtr sc = element->Compound();
ERR_FAIL_COND_MSG(sc == nullptr, "failed to read geometry, prevented crash");
- ERR_FAIL_COND_MSG(!HasElement(sc, "Vertices"), "Detected mesh with no vertexes, didn't populate the mesh");
+ ERR_FAIL_COND_MSG(!HasElement(sc, "Vertices"), "Detected mesh with no vertices, didn't populate the mesh");
// must have Mesh elements:
const ElementPtr Vertices = GetRequiredElement(sc, "Vertices", element);
@@ -140,7 +140,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::str
ParseVectorDataArray(m_vertices, Vertices);
ParseVectorDataArray(m_face_indices, PolygonVertexIndex);
- ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertexes in FBX file, did you mean to delete it?");
+ ERR_FAIL_COND_MSG(m_vertices.empty(), "mesh with no vertices in FBX file, did you mean to delete it?");
ERR_FAIL_COND_MSG(m_face_indices.empty(), "mesh has no faces, was this intended?");
// Retrieve layer elements, for all of the mesh
@@ -278,7 +278,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const ElementPtr element, const std::str
}
}
// As the algorithm above, this check is useless. Because the first
- // ever vertex is always considered the begining of a polygon.
+ // ever vertex is always considered the beginning of a polygon.
ERR_FAIL_COND_MSG(found_it == false, "Was not possible to find the first vertex of this polygon. FBX file is corrupted.");
} else {
@@ -418,7 +418,7 @@ MeshGeometry::MappingData<T> MeshGeometry::resolve_vertex_data_array(
// parse data into array
ParseVectorDataArray(tempData.data, GetRequiredElement(source, dataElementName));
- // index array wont always exist
+ // index array won't always exist
const ElementPtr element = GetOptionalElement(source, indexDataElementName);
if (element) {
ParseVectorDataArray(tempData.index, element);
diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.h b/modules/fbx/fbx_parser/FBXMeshGeometry.h
index 710e644c68..c9b25f008d 100644
--- a/modules/fbx/fbx_parser/FBXMeshGeometry.h
+++ b/modules/fbx/fbx_parser/FBXMeshGeometry.h
@@ -96,7 +96,7 @@ public:
Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
virtual ~Geometry();
- /** Get the Skin attached to this geometry or NULL */
+ /** Get the Skin attached to this geometry or nullptr */
const Skin *DeformerSkin() const;
const std::vector<const BlendShape *> &get_blend_shapes() const;
@@ -122,7 +122,7 @@ typedef std::vector<int> MatIndexArray;
/// ## Map Type:
/// * None The mapping is undetermined.
/// * ByVertex There will be one mapping coordinate for each surface control point/vertex (ControlPoint is a vertex).
-/// * If you have direct reference type verticies[x]
+/// * If you have direct reference type vertices[x]
/// * If you have IndexToDirect reference type the UV
/// * ByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. (Sorted by polygon, referencing vertex)
/// * ByPolygon There can be only one mapping coordinate for the whole polygon.
@@ -186,7 +186,7 @@ public:
/// Returns -1 if the vertices doesn't form an edge. Vertex order, doesn't
// matter.
static int get_edge_id(const std::vector<Edge> &p_map, int p_vertex_a, int p_vertex_b);
- // Retuns the edge point bu that ID, or the edge with -1 vertices if the
+ // Returns the edge point bu that ID, or the edge with -1 vertices if the
// id is not valid.
static Edge get_edge(const std::vector<Edge> &p_map, int p_id);
diff --git a/modules/fbx/fbx_parser/FBXParser.cpp b/modules/fbx/fbx_parser/FBXParser.cpp
index 82d532e0b8..163518d18f 100644
--- a/modules/fbx/fbx_parser/FBXParser.cpp
+++ b/modules/fbx/fbx_parser/FBXParser.cpp
@@ -74,15 +74,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the FBX parser and the rudimentary DOM that we use
*/
-#include "thirdparty/zlib/zlib.h"
#include <stdlib.h> /* strtol */
+#include <zlib.h>
#include "ByteSwapper.h"
#include "FBXParseTools.h"
#include "FBXParser.h"
#include "FBXTokenizer.h"
#include "core/math/math_defs.h"
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include "core/math/vector3.h"
#include "core/string/print_string.h"
@@ -1157,7 +1157,7 @@ void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el) {
}
// ------------------------------------------------------------------------------------------------
-Transform ReadMatrix(const ElementPtr element) {
+Transform3D ReadMatrix(const ElementPtr element) {
std::vector<float> values;
ParseVectorDataArray(values, element);
@@ -1172,7 +1172,7 @@ Transform ReadMatrix(const ElementPtr element) {
}
}
- Transform xform;
+ Transform3D xform;
Basis basis;
basis.set(
@@ -1206,7 +1206,7 @@ std::string ParseTokenAsString(const TokenPtr t) {
// ------------------------------------------------------------------------------------------------
// extract a required element from a scope, abort if the element cannot be found
-ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= NULL*/) {
+ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= nullptr*/) {
const ElementPtr el = sc->GetElement(index);
TokenPtr token = el->KeyToken();
ERR_FAIL_COND_V(!token, nullptr);
@@ -1227,7 +1227,7 @@ bool HasElement(const ScopePtr sc, const std::string &index) {
// ------------------------------------------------------------------------------------------------
// extract a required element from a scope, abort if the element cannot be found
-ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= NULL*/) {
+ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element /*= nullptr*/) {
const ElementPtr el = sc->GetElement(index);
return el;
}
diff --git a/modules/fbx/fbx_parser/FBXParser.h b/modules/fbx/fbx_parser/FBXParser.h
index bfbcb22ffa..93836c2205 100644
--- a/modules/fbx/fbx_parser/FBXParser.h
+++ b/modules/fbx/fbx_parser/FBXParser.h
@@ -81,7 +81,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory>
#include "core/math/color.h"
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include "core/math/vector2.h"
#include "core/math/vector3.h"
@@ -160,7 +160,7 @@ public:
}
ElementPtr FindElementCaseInsensitive(const std::string &elementName) const {
- for (auto element = elements.begin(); element != elements.end(); ++element) {
+ for (FBXDocParser::ElementMap::const_iterator element = elements.begin(); element != elements.end(); ++element) {
if (element->first.compare(elementName)) {
return element->second;
}
@@ -264,7 +264,7 @@ TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index);
// ------------------------------------------------------------------------------------------------
// read a 4x4 matrix from an array of 16 floats
-Transform ReadMatrix(const ElementPtr element);
+Transform3D ReadMatrix(const ElementPtr element);
} // namespace FBXDocParser
#endif // FBX_PARSER_H
diff --git a/modules/fbx/fbx_parser/FBXProperties.cpp b/modules/fbx/fbx_parser/FBXProperties.cpp
index 1b3f29ec04..37717e9109 100644
--- a/modules/fbx/fbx_parser/FBXProperties.cpp
+++ b/modules/fbx/fbx_parser/FBXProperties.cpp
@@ -94,7 +94,7 @@ Property::~Property() {
namespace {
// ------------------------------------------------------------------------------------------------
-// read a typed property out of a FBX element. The return value is NULL if the property cannot be read.
+// read a typed property out of a FBX element. The return value is nullptr if the property cannot be read.
PropertyPtr ReadTypedProperty(const ElementPtr element) {
//ai_assert(element.KeyToken().StringContents() == "P");
diff --git a/modules/fbx/fbx_parser/FBXUtil.cpp b/modules/fbx/fbx_parser/FBXUtil.cpp
index 4295cb6f5e..1f14a69099 100644
--- a/modules/fbx/fbx_parser/FBXUtil.cpp
+++ b/modules/fbx/fbx_parser/FBXUtil.cpp
@@ -121,7 +121,7 @@ static const uint8_t base64DecodeTable[128] = {
};
uint8_t DecodeBase64(char ch) {
- const auto idx = static_cast<uint8_t>(ch);
+ const uint8_t idx = static_cast<uint8_t>(ch);
if (idx > 127) {
return 255;
}
diff --git a/modules/fbx/tools/import_utils.cpp b/modules/fbx/tools/import_utils.cpp
index c87dd1fd3a..66b0153308 100644
--- a/modules/fbx/tools/import_utils.cpp
+++ b/modules/fbx/tools/import_utils.cpp
@@ -80,7 +80,7 @@ Basis ImportUtils::EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector
return ret;
}
-Quat ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) {
+Quaternion ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) {
return ImportUtils::EulerToBasis(mode, p_rotation);
}
@@ -117,18 +117,18 @@ Vector3 ImportUtils::BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basi
}
}
-Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation) {
+Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation) {
return BasisToEuler(mode, p_rotation);
}
-Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale) {
- Transform unscaled = Transform(p_initial.basis, p_initial.origin * p_scale);
- ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform(), "det is zero unscaled?");
+Transform3D get_unscaled_transform(const Transform3D &p_initial, real_t p_scale) {
+ Transform3D unscaled = Transform3D(p_initial.basis, p_initial.origin * p_scale);
+ ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform3D(), "det is zero unscaled?");
return unscaled;
}
Vector3 get_poly_normal(const std::vector<Vector3> &p_vertices) {
- ERR_FAIL_COND_V_MSG(p_vertices.size() < 3, Vector3(0, 0, 0), "At least 3 vertices are necesary");
+ ERR_FAIL_COND_V_MSG(p_vertices.size() < 3, Vector3(0, 0, 0), "At least 3 vertices are necessary");
// Using long double to make sure that normal is computed for even really tiny objects.
typedef long double ldouble;
ldouble x = 0.0;
diff --git a/modules/fbx/tools/import_utils.h b/modules/fbx/tools/import_utils.h
index bea28ffeda..7625f67256 100644
--- a/modules/fbx/tools/import_utils.h
+++ b/modules/fbx/tools/import_utils.h
@@ -56,15 +56,15 @@ public:
static Basis EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
/// Converts rotation order vector (in rad) to quaternion.
- static Quat EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
+ static Quaternion EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation);
/// Converts basis into rotation order vector (in rad).
static Vector3 BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation);
/// Converts quaternion into rotation order vector (in rad).
- static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation);
+ static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation);
- static void debug_xform(String name, const Transform &t) {
+ static void debug_xform(String name, const Transform3D &t) {
print_verbose(name + " " + t.origin + " rotation: " + (t.basis.get_euler() * (180 / Math_PI)));
}
@@ -267,7 +267,7 @@ public:
*/
// static void set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<ImageTexture> texture) {
// ERR_FAIL_COND(texture.is_null());
- // ERR_FAIL_COND(map_mode == NULL);
+ // ERR_FAIL_COND(map_mode == nullptr);
// aiTextureMapMode tex_mode = map_mode[0];
// int32_t flags = Texture::FLAGS_DEFAULT;
@@ -382,7 +382,7 @@ public:
// String &path,
// AssimpImageData &image_state) {
// aiString ai_filename = aiString();
- // if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, NULL, NULL, NULL, NULL, image_state.map_mode)) {
+ // if (AI_SUCCESS == ai_material->GetTexture(texture_type, 0, &ai_filename, nullptr, nullptr, nullptr, nullptr, image_state.map_mode)) {
// return CreateAssimpTexture(state, ai_filename, filename, path, image_state);
// }
@@ -391,7 +391,7 @@ public:
};
// Apply the transforms so the basis will have scale 1.
-Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale);
+Transform3D get_unscaled_transform(const Transform3D &p_initial, real_t p_scale);
/// Uses the Newell's method to compute any polygon normal.
/// The polygon must be at least size of 3 or bigger.
diff --git a/modules/fbx/tools/validation_tools.h b/modules/fbx/tools/validation_tools.h
index fe0c92b22f..6c15eb7e12 100644
--- a/modules/fbx/tools/validation_tools.h
+++ b/modules/fbx/tools/validation_tools.h
@@ -33,8 +33,8 @@
#ifdef TOOLS_ENABLED
+#include "core/io/file_access.h"
#include "core/io/json.h"
-#include "core/os/file_access.h"
#include "core/string/ustring.h"
#include "core/templates/local_vector.h"
#include "core/templates/map.h"
diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml
index 44d9e32ed8..4f1530598c 100644
--- a/modules/gdnative/doc_classes/GDNative.xml
+++ b/modules/gdnative/doc_classes/GDNative.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDNative" inherits="Reference" version="4.0">
+<class name="GDNative" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index 0de6b27d27..e552f443cf 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -32,8 +32,9 @@
#include "core/config/project_settings.h"
#include "core/core_constants.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_encrypted.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "scene/main/scene_tree.h"
@@ -335,9 +336,18 @@ bool GDNative::initialize() {
// On OSX the exported libraries are located under the Frameworks directory.
// So we need to replace the library path.
String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
- if (!FileAccess::exists(path)) {
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ if (!da->file_exists(path) && !da->dir_exists(path)) {
path = OS::get_singleton()->get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(lib_path.get_file());
}
+
+ if (da->dir_exists(path)) { // Target library is a ".framework", add library base name to the path.
+ path = path.plus_file(path.get_file().get_basename());
+ }
+
+ memdelete(da);
+
#else
String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
#endif
diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h
index a28c58ec0d..0cc6487ea4 100644
--- a/modules/gdnative/gdnative.h
+++ b/modules/gdnative/gdnative.h
@@ -138,8 +138,8 @@ struct GDNativeCallRegistry {
Vector<StringName> get_native_call_types();
};
-class GDNative : public Reference {
- GDCLASS(GDNative, Reference);
+class GDNative : public RefCounted {
+ GDCLASS(GDNative, RefCounted);
Ref<GDNativeLibrary> library;
diff --git a/modules/gdnative/gdnative/quat.cpp b/modules/gdnative/gdnative/quaternion.cpp
index 8ebcf7c91f..62bcbbd382 100644
--- a/modules/gdnative/gdnative/quat.cpp
+++ b/modules/gdnative/gdnative/quaternion.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* quat.cpp */
+/* quaternion.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,31 +28,31 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "gdnative/quat.h"
+#include "gdnative/quaternion.h"
-#include "core/math/quat.h"
+#include "core/math/quaternion.h"
-static_assert(sizeof(godot_quat) == sizeof(Quat), "Quat size mismatch");
+static_assert(sizeof(godot_quaternion) == sizeof(Quaternion), "Quaternion size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-void GDAPI godot_quat_new(godot_quat *p_self) {
- memnew_placement(p_self, Quat);
+void GDAPI godot_quaternion_new(godot_quaternion *p_self) {
+ memnew_placement(p_self, Quaternion);
}
-void GDAPI godot_quat_new_copy(godot_quat *r_dest, const godot_quat *p_src) {
- memnew_placement(r_dest, Quat(*(Quat *)p_src));
+void GDAPI godot_quaternion_new_copy(godot_quaternion *r_dest, const godot_quaternion *p_src) {
+ memnew_placement(r_dest, Quaternion(*(Quaternion *)p_src));
}
-godot_real_t GDAPI *godot_quat_operator_index(godot_quat *p_self, godot_int p_index) {
- Quat *self = (Quat *)p_self;
+godot_real_t GDAPI *godot_quaternion_operator_index(godot_quaternion *p_self, godot_int p_index) {
+ Quaternion *self = (Quaternion *)p_self;
return (godot_real_t *)&self->operator[](p_index);
}
-const godot_real_t GDAPI *godot_quat_operator_index_const(const godot_quat *p_self, godot_int p_index) {
- const Quat *self = (const Quat *)p_self;
+const godot_real_t GDAPI *godot_quaternion_operator_index_const(const godot_quaternion *p_self, godot_int p_index) {
+ const Quaternion *self = (const Quaternion *)p_self;
return (const godot_real_t *)&self->operator[](p_index);
}
diff --git a/modules/gdnative/gdnative/transform.cpp b/modules/gdnative/gdnative/transform_3d.cpp
index bfaaa13db2..8bd2a68d63 100644
--- a/modules/gdnative/gdnative/transform.cpp
+++ b/modules/gdnative/gdnative/transform_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* transform.cpp */
+/* transform_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,22 +28,22 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "gdnative/transform.h"
+#include "gdnative/transform_3d.h"
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
-static_assert(sizeof(godot_transform) == sizeof(Transform), "Transform size mismatch");
+static_assert(sizeof(godot_transform3d) == sizeof(Transform3D), "Transform3D size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
-void GDAPI godot_transform_new(godot_transform *p_self) {
- memnew_placement(p_self, Transform);
+void GDAPI godot_transform3d_new(godot_transform3d *p_self) {
+ memnew_placement(p_self, Transform3D);
}
-void GDAPI godot_transform_new_copy(godot_transform *r_dest, const godot_transform *p_src) {
- memnew_placement(r_dest, Transform(*(Transform *)p_src));
+void GDAPI godot_transform3d_new_copy(godot_transform3d *r_dest, const godot_transform3d *p_src) {
+ memnew_placement(r_dest, Transform3D(*(Transform3D *)p_src));
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp
index 7801e21ab2..cfb57137bb 100644
--- a/modules/gdnative/gdnative/variant.cpp
+++ b/modules/gdnative/gdnative/variant.cpp
@@ -30,7 +30,7 @@
#include "gdnative/variant.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/variant/variant.h"
#ifdef __cplusplus
@@ -143,10 +143,10 @@ void GDAPI godot_variant_new_plane(godot_variant *r_dest, const godot_plane *p_p
memnew_placement_custom(dest, Variant, Variant(*plane));
}
-void GDAPI godot_variant_new_quat(godot_variant *r_dest, const godot_quat *p_quat) {
+void GDAPI godot_variant_new_quaternion(godot_variant *r_dest, const godot_quaternion *p_quaternion) {
Variant *dest = (Variant *)r_dest;
- const Quat *quat = (const Quat *)p_quat;
- memnew_placement_custom(dest, Variant, Variant(*quat));
+ const Quaternion *quaternion = (const Quaternion *)p_quaternion;
+ memnew_placement_custom(dest, Variant, Variant(*quaternion));
}
void GDAPI godot_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aabb) {
@@ -161,9 +161,9 @@ void GDAPI godot_variant_new_basis(godot_variant *r_dest, const godot_basis *p_b
memnew_placement_custom(dest, Variant, Variant(*basis));
}
-void GDAPI godot_variant_new_transform(godot_variant *r_dest, const godot_transform *p_trans) {
+void GDAPI godot_variant_new_transform3d(godot_variant *r_dest, const godot_transform3d *p_trans) {
Variant *dest = (Variant *)r_dest;
- const Transform *trans = (const Transform *)p_trans;
+ const Transform3D *trans = (const Transform3D *)p_trans;
memnew_placement_custom(dest, Variant, Variant(*trans));
}
@@ -200,17 +200,17 @@ void GDAPI godot_variant_new_signal(godot_variant *r_dest, const godot_signal *p
void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p_obj) {
Variant *dest = (Variant *)r_dest;
const Object *obj = (const Object *)p_obj;
- const Reference *reference = Object::cast_to<Reference>(obj);
+ const RefCounted *ref_counted = Object::cast_to<RefCounted>(obj);
REF ref;
- if (reference) {
- ref = REF(reference);
+ if (ref_counted) {
+ ref = REF(ref_counted);
}
if (!ref.is_null()) {
memnew_placement_custom(dest, Variant, Variant(ref));
} else {
#if defined(DEBUG_METHODS_ENABLED)
- if (reference) {
- ERR_PRINT("Reference object has 0 refcount in godot_variant_new_object - you lost it somewhere.");
+ if (ref_counted) {
+ ERR_PRINT("RefCounted object has 0 refcount in godot_variant_new_object - you lost it somewhere.");
}
#endif
memnew_placement_custom(dest, Variant, Variant(obj));
@@ -378,10 +378,10 @@ godot_plane GDAPI godot_variant_as_plane(const godot_variant *p_self) {
return raw_dest;
}
-godot_quat GDAPI godot_variant_as_quat(const godot_variant *p_self) {
- godot_quat raw_dest;
+godot_quaternion GDAPI godot_variant_as_quaternion(const godot_variant *p_self) {
+ godot_quaternion raw_dest;
const Variant *self = (const Variant *)p_self;
- Quat *dest = (Quat *)&raw_dest;
+ Quaternion *dest = (Quaternion *)&raw_dest;
*dest = *self;
return raw_dest;
}
@@ -402,10 +402,10 @@ godot_basis GDAPI godot_variant_as_basis(const godot_variant *p_self) {
return raw_dest;
}
-godot_transform GDAPI godot_variant_as_transform(const godot_variant *p_self) {
- godot_transform raw_dest;
+godot_transform3d GDAPI godot_variant_as_transform3d(const godot_variant *p_self) {
+ godot_transform3d raw_dest;
const Variant *self = (const Variant *)p_self;
- Transform *dest = (Transform *)&raw_dest;
+ Transform3D *dest = (Transform3D *)&raw_dest;
*dest = *self;
return raw_dest;
}
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 489083e795..8c65447e5d 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -469,7 +469,7 @@
]
},
{
- "name": "godot_variant_new_quat",
+ "name": "godot_variant_new_quaternion",
"return_type": "void",
"arguments": [
[
@@ -477,8 +477,8 @@
"r_dest"
],
[
- "const godot_quat *",
- "p_quat"
+ "const godot_quaternion *",
+ "p_quaternion"
]
]
},
@@ -511,7 +511,7 @@
]
},
{
- "name": "godot_variant_new_transform",
+ "name": "godot_variant_new_transform3d",
"return_type": "void",
"arguments": [
[
@@ -519,7 +519,7 @@
"r_dest"
],
[
- "const godot_transform *",
+ "const godot_transform3d *",
"p_trans"
]
]
@@ -893,8 +893,8 @@
]
},
{
- "name": "godot_variant_as_quat",
- "return_type": "godot_quat",
+ "name": "godot_variant_as_quaternion",
+ "return_type": "godot_quaternion",
"arguments": [
[
"const godot_variant *",
@@ -923,8 +923,8 @@
]
},
{
- "name": "godot_variant_as_transform",
- "return_type": "godot_transform",
+ "name": "godot_variant_as_transform3d",
+ "return_type": "godot_transform3d",
"arguments": [
[
"const godot_variant *",
@@ -3866,35 +3866,35 @@
]
},
{
- "name": "godot_quat_new",
+ "name": "godot_quaternion_new",
"return_type": "void",
"arguments": [
[
- "godot_quat *",
+ "godot_quaternion *",
"p_self"
]
]
},
{
- "name": "godot_quat_new_copy",
+ "name": "godot_quaternion_new_copy",
"return_type": "void",
"arguments": [
[
- "godot_quat *",
+ "godot_quaternion *",
"r_dest"
],
[
- "const godot_quat *",
+ "const godot_quaternion *",
"p_src"
]
]
},
{
- "name": "godot_quat_operator_index",
+ "name": "godot_quaternion_operator_index",
"return_type": "godot_real_t *",
"arguments": [
[
- "godot_quat *",
+ "godot_quaternion *",
"p_self"
],
[
@@ -3904,11 +3904,11 @@
]
},
{
- "name": "godot_quat_operator_index_const",
+ "name": "godot_quaternion_operator_index_const",
"return_type": "const godot_real_t *",
"arguments": [
[
- "const godot_quat *",
+ "const godot_quaternion *",
"p_self"
],
[
@@ -4344,25 +4344,25 @@
]
},
{
- "name": "godot_transform_new",
+ "name": "godot_transform3d_new",
"return_type": "void",
"arguments": [
[
- "godot_transform *",
+ "godot_transform3d *",
"r_dest"
]
]
},
{
- "name": "godot_transform_new_copy",
+ "name": "godot_transform3d_new_copy",
"return_type": "void",
"arguments": [
[
- "godot_transform *",
+ "godot_transform3d *",
"r_dest"
],
[
- "const godot_transform *",
+ "const godot_transform3d *",
"p_src"
]
]
@@ -5068,12 +5068,12 @@
},
{
"name": "godot_xr_get_worldscale",
- "return_type": "godot_float",
+ "return_type": "godot_real_t",
"arguments": []
},
{
"name": "godot_xr_get_reference_frame",
- "return_type": "godot_transform",
+ "return_type": "godot_transform3d",
"arguments": []
},
{
@@ -5145,7 +5145,7 @@
"p_controller_id"
],
[
- "godot_transform *",
+ "godot_transform3d *",
"p_transform"
],
[
@@ -5189,7 +5189,7 @@
"p_exis"
],
[
- "godot_float",
+ "godot_real_t",
"p_value"
],
[
@@ -5200,7 +5200,7 @@
},
{
"name": "godot_xr_get_controller_rumble",
- "return_type": "godot_float",
+ "return_type": "godot_real_t",
"arguments": [
[
"godot_int",
diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp
index dfb26c13e3..b4ac0d886e 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.cpp
+++ b/modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -131,7 +131,7 @@ void GDNativeLibraryEditor::_on_item_button(Object *item, int column, int id) {
EditorFileDialog::FileMode mode = EditorFileDialog::FILE_MODE_OPEN_FILE;
if (id == BUTTON_SELECT_DEPENDENCES) {
mode = EditorFileDialog::FILE_MODE_OPEN_FILES;
- } else if (treeItem->get_text(0) == "iOS") {
+ } else if (treeItem->get_text(0) == "iOS" || treeItem->get_text(0) == "macOS") {
mode = EditorFileDialog::FILE_MODE_OPEN_ANY;
}
@@ -278,11 +278,10 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
platforms["X11"] = platform_linux;
NativePlatformConfig platform_osx;
- platform_osx.name = "Mac OSX";
+ platform_osx.name = "macOS";
platform_osx.entries.push_back("64");
- platform_osx.entries.push_back("32");
- platform_osx.library_extension = "*.dylib";
- platforms["OSX"] = platform_osx;
+ platform_osx.library_extension = "*.framework; Framework, *.dylib; Dynamic Library";
+ platforms["macOS"] = platform_osx;
NativePlatformConfig platform_haiku;
platform_haiku.name = "Haiku";
diff --git a/modules/gdnative/include/gdnative/callable.h b/modules/gdnative/include/gdnative/callable.h
index b84b0c1f1f..1d52ca7a68 100644
--- a/modules/gdnative/include/gdnative/callable.h
+++ b/modules/gdnative/include/gdnative/callable.h
@@ -37,6 +37,7 @@ extern "C" {
#include <stdint.h>
+// Alignment hardcoded in `core/variant/callable.h`.
#define GODOT_CALLABLE_SIZE (16)
#ifndef GODOT_CORE_API_GODOT_CALLABLE_TYPE_DEFINED
diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h
index 9af9226a79..d8c290f6bd 100644
--- a/modules/gdnative/include/gdnative/gdnative.h
+++ b/modules/gdnative/include/gdnative/gdnative.h
@@ -149,9 +149,9 @@ typedef void godot_object;
#include <gdnative/plane.h>
-/////// Quat
+/////// Quaternion
-#include <gdnative/quat.h>
+#include <gdnative/quaternion.h>
/////// AABB
@@ -161,9 +161,9 @@ typedef void godot_object;
#include <gdnative/basis.h>
-/////// Transform
+/////// Transform3D
-#include <gdnative/transform.h>
+#include <gdnative/transform_3d.h>
/////// Color
diff --git a/modules/gdnative/include/gdnative/transform.h b/modules/gdnative/include/gdnative/quaternion.h
index 3861b5683a..75754e6ab5 100644
--- a/modules/gdnative/include/gdnative/transform.h
+++ b/modules/gdnative/include/gdnative/quaternion.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* transform.h */
+/* quaternion.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GODOT_TRANSFORM_H
-#define GODOT_TRANSFORM_H
+#ifndef GODOT_QUATERNION_H
+#define GODOT_QUATERNION_H
#ifdef __cplusplus
extern "C" {
@@ -37,22 +37,24 @@ extern "C" {
#include <gdnative/math_defs.h>
-#define GODOT_TRANSFORM_SIZE (sizeof(godot_real_t) * 12)
+#define GODOT_QUATERNION_SIZE (sizeof(godot_real_t) * 4)
-#ifndef GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED
-#define GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED
+#ifndef GODOT_CORE_API_GODOT_QUATERNION_TYPE_DEFINED
+#define GODOT_CORE_API_GODOT_QUATERNION_TYPE_DEFINED
typedef struct {
- uint8_t _dont_touch_that[GODOT_TRANSFORM_SIZE];
-} godot_transform;
+ uint8_t _dont_touch_that[GODOT_QUATERNION_SIZE];
+} godot_quaternion;
#endif
#include <gdnative/gdnative.h>
-void GDAPI godot_transform_new(godot_transform *p_self);
-void GDAPI godot_transform_new_copy(godot_transform *r_dest, const godot_transform *p_src);
+void GDAPI godot_quaternion_new(godot_quaternion *p_self);
+void GDAPI godot_quaternion_new_copy(godot_quaternion *r_dest, const godot_quaternion *p_src);
+godot_real_t GDAPI *godot_quaternion_operator_index(godot_quaternion *p_self, godot_int p_index);
+const godot_real_t GDAPI *godot_quaternion_operator_index_const(const godot_quaternion *p_self, godot_int p_index);
#ifdef __cplusplus
}
#endif
-#endif // GODOT_TRANSFORM_H
+#endif // GODOT_QUATERNION_H
diff --git a/modules/gdnative/include/gdnative/signal.h b/modules/gdnative/include/gdnative/signal.h
index f4dc17e089..41a76d0510 100644
--- a/modules/gdnative/include/gdnative/signal.h
+++ b/modules/gdnative/include/gdnative/signal.h
@@ -37,6 +37,7 @@ extern "C" {
#include <stdint.h>
+// Alignment hardcoded in `core/variant/callable.h`.
#define GODOT_SIGNAL_SIZE (16)
#ifndef GODOT_CORE_API_GODOT_SIGNAL_TYPE_DEFINED
diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/transform_3d.h
index 00abdb4404..97ad451e9b 100644
--- a/modules/gdnative/include/gdnative/quat.h
+++ b/modules/gdnative/include/gdnative/transform_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* quat.h */
+/* transform_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GODOT_QUAT_H
-#define GODOT_QUAT_H
+#ifndef GODOT_TRANSFORM3D_H
+#define GODOT_TRANSFORM3D_H
#ifdef __cplusplus
extern "C" {
@@ -37,24 +37,24 @@ extern "C" {
#include <gdnative/math_defs.h>
-#define GODOT_QUAT_SIZE (sizeof(godot_real_t) * 4)
+#define GODOT_TRANSFORM3D_SIZE (sizeof(godot_real_t) * 12)
-#ifndef GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED
-#define GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED
+#ifndef GODOT_CORE_API_GODOT_TRANSFORM3D_TYPE_DEFINED
+#define GODOT_CORE_API_GODOT_TRANSFORM3D_TYPE_DEFINED
typedef struct {
- uint8_t _dont_touch_that[GODOT_QUAT_SIZE];
-} godot_quat;
+ uint8_t _dont_touch_that[GODOT_TRANSFORM3D_SIZE];
+} godot_transform3d;
#endif
#include <gdnative/gdnative.h>
-void GDAPI godot_quat_new(godot_quat *p_self);
-void GDAPI godot_quat_new_copy(godot_quat *r_dest, const godot_quat *p_src);
-godot_real_t GDAPI *godot_quat_operator_index(godot_quat *p_self, godot_int p_index);
-const godot_real_t GDAPI *godot_quat_operator_index_const(const godot_quat *p_self, godot_int p_index);
+void GDAPI godot_transform3d_new(godot_transform3d *p_self);
+void GDAPI godot_transform3d_new_copy(godot_transform3d *r_dest, const godot_transform3d *p_src);
+godot_vector3 GDAPI *godot_transform3d_operator_index(godot_transform3d *p_self, godot_int p_index);
+const godot_vector3 GDAPI *godot_transform3d_operator_index_const(const godot_transform3d *p_self, godot_int p_index);
#ifdef __cplusplus
}
#endif
-#endif // GODOT_QUAT_H
+#endif // GODOT_TRANSFORM3D_H
diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h
index 3e06ed9aa4..dd4f76cf57 100644
--- a/modules/gdnative/include/gdnative/variant.h
+++ b/modules/gdnative/include/gdnative/variant.h
@@ -56,10 +56,10 @@ typedef enum godot_variant_type {
GODOT_VARIANT_TYPE_VECTOR3I,
GODOT_VARIANT_TYPE_TRANSFORM2D,
GODOT_VARIANT_TYPE_PLANE,
- GODOT_VARIANT_TYPE_QUAT,
+ GODOT_VARIANT_TYPE_QUATERNION,
GODOT_VARIANT_TYPE_AABB,
GODOT_VARIANT_TYPE_BASIS,
- GODOT_VARIANT_TYPE_TRANSFORM,
+ GODOT_VARIANT_TYPE_TRANSFORM3D,
// misc types
GODOT_VARIANT_TYPE_COLOR,
@@ -177,14 +177,14 @@ typedef void (*godot_ptr_utility_function)(void *r_return, const void **p_argume
#include <gdnative/node_path.h>
#include <gdnative/packed_arrays.h>
#include <gdnative/plane.h>
-#include <gdnative/quat.h>
+#include <gdnative/quaternion.h>
#include <gdnative/rect2.h>
#include <gdnative/rid.h>
#include <gdnative/signal.h>
#include <gdnative/string.h>
#include <gdnative/string_name.h>
-#include <gdnative/transform.h>
#include <gdnative/transform2d.h>
+#include <gdnative/transform_3d.h>
#include <gdnative/variant.h>
#include <gdnative/vector2.h>
#include <gdnative/vector3.h>
@@ -208,10 +208,10 @@ void GDAPI godot_variant_new_vector3(godot_variant *r_dest, const godot_vector3
void GDAPI godot_variant_new_vector3i(godot_variant *r_dest, const godot_vector3i *p_v3);
void GDAPI godot_variant_new_transform2d(godot_variant *r_dest, const godot_transform2d *p_t2d);
void GDAPI godot_variant_new_plane(godot_variant *r_dest, const godot_plane *p_plane);
-void GDAPI godot_variant_new_quat(godot_variant *r_dest, const godot_quat *p_quat);
+void GDAPI godot_variant_new_quaternion(godot_variant *r_dest, const godot_quaternion *p_quaternion);
void GDAPI godot_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aabb);
void GDAPI godot_variant_new_basis(godot_variant *r_dest, const godot_basis *p_basis);
-void GDAPI godot_variant_new_transform(godot_variant *r_dest, const godot_transform *p_trans);
+void GDAPI godot_variant_new_transform3d(godot_variant *r_dest, const godot_transform3d *p_trans);
void GDAPI godot_variant_new_color(godot_variant *r_dest, const godot_color *p_color);
void GDAPI godot_variant_new_string_name(godot_variant *r_dest, const godot_string_name *p_s);
void GDAPI godot_variant_new_node_path(godot_variant *r_dest, const godot_node_path *p_np);
@@ -243,10 +243,10 @@ godot_vector3 GDAPI godot_variant_as_vector3(const godot_variant *p_self);
godot_vector3i GDAPI godot_variant_as_vector3i(const godot_variant *p_self);
godot_transform2d GDAPI godot_variant_as_transform2d(const godot_variant *p_self);
godot_plane GDAPI godot_variant_as_plane(const godot_variant *p_self);
-godot_quat GDAPI godot_variant_as_quat(const godot_variant *p_self);
+godot_quaternion GDAPI godot_variant_as_quaternion(const godot_variant *p_self);
godot_aabb GDAPI godot_variant_as_aabb(const godot_variant *p_self);
godot_basis GDAPI godot_variant_as_basis(const godot_variant *p_self);
-godot_transform GDAPI godot_variant_as_transform(const godot_variant *p_self);
+godot_transform3d GDAPI godot_variant_as_transform3d(const godot_variant *p_self);
godot_color GDAPI godot_variant_as_color(const godot_variant *p_self);
godot_string_name GDAPI godot_variant_as_string_name(const godot_variant *p_self);
godot_node_path GDAPI godot_variant_as_node_path(const godot_variant *p_self);
diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h
index b76f89cc99..34ed4f097d 100644
--- a/modules/gdnative/include/pluginscript/godot_pluginscript.h
+++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h
@@ -61,7 +61,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 nullptr 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;
@@ -121,12 +121,12 @@ typedef struct {
const char *name;
const char *type;
const char *extension;
- const char **recognized_extensions; // nullptr 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; // nullptr terminated array
- const char **comment_delimiters; // nullptr terminated array
- const char **string_delimiters; // nullptr 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_bool can_inherit_from_file;
diff --git a/modules/gdnative/include/xr/godot_xr.h b/modules/gdnative/include/xr/godot_xr.h
index 7eaf1c7ec3..53cb830cbb 100644
--- a/modules/gdnative/include/xr/godot_xr.h
+++ b/modules/gdnative/include/xr/godot_xr.h
@@ -41,8 +41,8 @@ extern "C" {
// 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
+#define GODOTVR_API_MAJOR 4
+#define GODOTVR_API_MINOR 0
typedef struct {
godot_gdnative_api_version version; /* version of our API */
@@ -52,25 +52,32 @@ typedef struct {
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_int (*get_view_count)(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_float *, godot_int, godot_float, godot_float, godot_float);
- void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *);
+
+ godot_transform3d (*get_camera_transform)(void *);
+ godot_transform3d (*get_transform_for_view)(void *, godot_int, godot_transform3d *);
+ void (*fill_projection_for_view)(void *, godot_real_t *, godot_int, godot_real_t, godot_real_t, godot_real_t);
+ void (*commit_views)(void *, 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 *);
+
+ // possibly deprecate but adding/keeping as a reminder these are in Godot 3
+ void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *);
+ godot_int (*get_external_texture_for_eye)(void *, godot_int);
+ godot_int (*get_external_depth_for_eye)(void *, godot_int);
} godot_xr_interface_gdnative;
void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_interface);
// helper functions to access XRServer data
-godot_float GDAPI godot_xr_get_worldscale();
-godot_transform GDAPI godot_xr_get_reference_frame();
+godot_real_t GDAPI godot_xr_get_worldscale();
+godot_transform3d 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);
@@ -79,10 +86,10 @@ 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_transform(godot_int p_controller_id, godot_transform3d *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_float p_value, godot_bool p_can_be_negative);
-godot_float GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id);
+void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real_t p_value, godot_bool p_can_be_negative);
+godot_real_t GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id);
#ifdef __cplusplus
}
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index f184c84615..57717010f7 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -34,10 +34,11 @@
#include "core/config/engine.h"
#include "core/core_constants.h"
+#include "core/io/file_access.h"
#include "core/object/class_db.h"
-#include "core/os/file_access.h"
#include "core/string/string_builder.h"
#include "core/templates/pair.h"
+#include "core/variant/variant_parser.h"
// helper stuff
@@ -121,7 +122,7 @@ struct ClassAPI {
String singleton_name;
bool is_instantiable = false;
// @Unclear
- bool is_reference = false;
+ bool is_ref_counted = false;
bool has_indexing = false; // For builtin types.
String indexed_type; // For builtin types.
bool is_keyed = false; // For builtin types.
@@ -254,10 +255,10 @@ List<ClassAPI> generate_c_api_classes() {
{
List<StringName> inheriters;
- ClassDB::get_inheriters_from_class("Reference", &inheriters);
- bool is_reference = !!inheriters.find(class_name) || class_name == "Reference";
+ ClassDB::get_inheriters_from_class("RefCounted", &inheriters);
+ bool is_ref_counted = !!inheriters.find(class_name) || class_name == "RefCounted";
// @Unclear
- class_api.is_reference = !class_api.is_singleton && is_reference;
+ class_api.is_ref_counted = !class_api.is_singleton && is_ref_counted;
}
// constants
@@ -509,10 +510,10 @@ List<ClassAPI> generate_c_builtin_api_types() {
case Variant::PACKED_VECTOR2_ARRAY:
case Variant::PACKED_VECTOR3_ARRAY:
case Variant::PACKED_COLOR_ARRAY:
- class_api.is_reference = true;
+ class_api.is_ref_counted = true;
break;
default:
- class_api.is_reference = false;
+ class_api.is_ref_counted = false;
break;
}
@@ -638,6 +639,7 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
// I'm sorry for the \t mess
List<String> source;
+ VariantWriter writer;
source.push_back("[\n");
@@ -652,7 +654,7 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
source.push_back(String("\t\t\"singleton\": ") + (api.is_singleton ? "true" : "false") + ",\n");
source.push_back("\t\t\"singleton_name\": \"" + api.singleton_name + "\",\n");
source.push_back(String("\t\t\"instantiable\": ") + (api.is_instantiable ? "true" : "false") + ",\n");
- source.push_back(String("\t\t\"is_reference\": ") + (api.is_reference ? "true" : "false") + ",\n");
+ source.push_back(String("\t\t\"is_ref_counted\": ") + (api.is_ref_counted ? "true" : "false") + ",\n");
source.push_back("\t\t\"constants\": {\n");
for (List<ConstantAPI>::Element *e = api.constants.front(); e; e = e->next()) {
@@ -682,7 +684,12 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
source.push_back("\t\t\t\t\t\t\"name\": \"" + e->get().argument_names[i] + "\",\n");
source.push_back("\t\t\t\t\t\t\"type\": \"" + e->get().argument_types[i] + "\",\n");
source.push_back(String("\t\t\t\t\t\t\"has_default_value\": ") + (e->get().default_arguments.has(i) ? "true" : "false") + ",\n");
- source.push_back("\t\t\t\t\t\t\"default_value\": \"" + (e->get().default_arguments.has(i) ? (String)e->get().default_arguments[i] : "") + "\"\n");
+ String default_value;
+ if (e->get().default_arguments.has(i)) {
+ writer.write_to_string(e->get().default_arguments[i], default_value);
+ default_value = default_value.replace("\n", "").json_escape();
+ }
+ source.push_back("\t\t\t\t\t\t\"default_value\": \"" + default_value + "\"\n");
source.push_back(String("\t\t\t\t\t}") + ((i < e->get().argument_names.size() - 1) ? "," : "") + "\n");
}
source.push_back("\t\t\t\t]\n");
@@ -708,7 +715,12 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
source.push_back("\t\t\t\t\t\t\"name\": \"" + e->get().argument_names[i] + "\",\n");
source.push_back("\t\t\t\t\t\t\"type\": \"" + e->get().argument_types[i] + "\",\n");
source.push_back(String("\t\t\t\t\t\t\"has_default_value\": ") + (e->get().default_arguments.has(i) ? "true" : "false") + ",\n");
- source.push_back("\t\t\t\t\t\t\"default_value\": \"" + (e->get().default_arguments.has(i) ? (String)e->get().default_arguments[i] : "") + "\"\n");
+ String default_value;
+ if (e->get().default_arguments.has(i)) {
+ writer.write_to_string(e->get().default_arguments[i], default_value);
+ default_value = default_value.replace("\n", "").json_escape();
+ }
+ source.push_back("\t\t\t\t\t\t\"default_value\": \"" + default_value + "\"\n");
source.push_back(String("\t\t\t\t\t}") + ((i < e->get().argument_names.size() - 1) ? "," : "") + "\n");
}
source.push_back("\t\t\t\t]\n");
@@ -756,6 +768,8 @@ static void append_indented(StringBuilder &p_source, const char *p_text) {
}
static void write_builtin_method(StringBuilder &p_source, const MethodAPI &p_method) {
+ VariantWriter writer;
+
append_indented(p_source, vformat(R"("name": "%s",)", p_method.method_name));
append_indented(p_source, vformat(R"("return_type": "%s",)", p_method.return_type));
append_indented(p_source, vformat(R"("is_const": %s,)", p_method.is_const ? "true" : "false"));
@@ -771,7 +785,12 @@ static void write_builtin_method(StringBuilder &p_source, const MethodAPI &p_met
append_indented(p_source, vformat(R"("name": "%s",)", p_method.argument_names[i]));
append_indented(p_source, vformat(R"("type": "%s",)", p_method.argument_types[i]));
append_indented(p_source, vformat(R"("has_default_value": %s,)", p_method.default_arguments.has(i) ? "true" : "false"));
- append_indented(p_source, vformat(R"("default_value": "%s")", p_method.default_arguments.has(i) ? p_method.default_arguments[i].operator String() : ""));
+ String default_value;
+ if (p_method.default_arguments.has(i)) {
+ writer.write_to_string(p_method.default_arguments[i], default_value);
+ default_value = default_value.replace("\n", "").json_escape();
+ }
+ append_indented(p_source, vformat(R"("default_value": "%s")", default_value));
indent_level--;
append_indented(p_source, i < p_method.argument_count - 1 ? "}," : "}");
@@ -794,7 +813,7 @@ static List<String> generate_c_builtin_api_json(const List<ClassAPI> &p_api) {
append_indented(source, vformat(R"("name": "%s",)", class_api.class_name));
append_indented(source, vformat(R"("is_instantiable": %s,)", class_api.is_instantiable ? "true" : "false"));
- append_indented(source, vformat(R"("is_reference": %s,)", class_api.is_reference ? "true" : "false"));
+ append_indented(source, vformat(R"("is_ref_counted": %s,)", class_api.is_ref_counted ? "true" : "false"));
append_indented(source, vformat(R"("has_indexing": %s,)", class_api.has_indexing ? "true" : "false"));
append_indented(source, vformat(R"("indexed_type": "%s",)", class_api.has_indexing && class_api.indexed_type == "Nil" ? "Variant" : class_api.indexed_type));
append_indented(source, vformat(R"("is_keyed": %s,)", class_api.is_keyed ? "true" : "false"));
diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp
index b2abf8b8ae..b10a747568 100644
--- a/modules/gdnative/nativescript/godot_nativescript.cpp
+++ b/modules/gdnative/nativescript/godot_nativescript.cpp
@@ -70,8 +70,7 @@ void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char
const NativeScriptDesc *b = desc.base_data;
while (b) {
- desc.rpc_count += b->rpc_count;
- desc.rset_count += b->rset_count;
+ desc.rpc_methods.append_array(b->rpc_methods);
b = b->base_data;
}
@@ -94,8 +93,6 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const
desc.destroy_func = p_destroy_func;
desc.is_tool = true;
desc.base = p_base;
- desc.rpc_count = 0;
- desc.rset_count = 0;
if (classes->has(p_base)) {
desc.base_data = &(*classes)[p_base];
@@ -103,8 +100,7 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const
const NativeScriptDesc *b = desc.base_data;
while (b) {
- desc.rpc_count += b->rpc_count;
- desc.rset_count += b->rset_count;
+ desc.rpc_methods.append_array(b->rpc_methods);
b = b->base_data;
}
@@ -126,13 +122,16 @@ void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const cha
method.method = p_method;
method.rpc_mode = p_attr.rpc_type;
method.rpc_method_id = UINT16_MAX;
- if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) {
- method.rpc_method_id = E->get().rpc_count;
- E->get().rpc_count += 1;
- }
method.info = MethodInfo(p_function_name);
E->get().methods.insert(p_function_name, method);
+
+ if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) {
+ MultiplayerAPI::RPCConfig nd;
+ nd.name = String(p_name);
+ nd.rpc_mode = MultiplayerAPI::RPCMode(p_attr.rpc_type);
+ E->get().rpc_methods.push_back(nd);
+ }
}
void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_nativescript_property_attributes *p_attr, godot_nativescript_property_set_func p_set_func, godot_nativescript_property_get_func p_get_func) {
@@ -144,11 +143,6 @@ void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const c
NativeScriptDesc::Property property;
property.default_value = *(Variant *)&p_attr->default_value;
property.getter = p_get_func;
- property.rset_mode = p_attr->rset_type;
- if (p_attr->rset_type != GODOT_METHOD_RPC_MODE_DISABLED) {
- property.rset_property_id = E->get().rset_count;
- E->get().rset_count += 1;
- }
property.setter = p_set_func;
property.info = PropertyInfo((Variant::Type)p_attr->type,
p_path,
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index f795bef59f..6c2d038654 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -37,10 +37,12 @@
#include "core/config/project_settings.h"
#include "core/core_constants.h"
#include "core/core_string_names.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_encrypted.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
+#include "main/main.h"
+
#include "scene/main/scene_tree.h"
#include "scene/resources/resource_format_text.h"
@@ -413,245 +415,11 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const {
}
}
-Vector<ScriptNetData> NativeScript::get_rpc_methods() const {
- Vector<ScriptNetData> v;
-
+const Vector<MultiplayerAPI::RPCConfig> NativeScript::get_rpc_methods() const {
NativeScriptDesc *script_data = get_script_desc();
+ ERR_FAIL_COND_V(!script_data, Vector<MultiplayerAPI::RPCConfig>());
- while (script_data) {
- for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
- if (E->get().rpc_mode != GODOT_METHOD_RPC_MODE_DISABLED) {
- ScriptNetData nd;
- nd.name = E->key();
- nd.mode = MultiplayerAPI::RPCMode(E->get().rpc_mode);
- v.push_back(nd);
- }
- }
-
- script_data = script_data->base_data;
- }
-
- return v;
-}
-
-uint16_t NativeScript::get_rpc_method_id(const StringName &p_method) const {
- NativeScriptDesc *script_data = get_script_desc();
-
- while (script_data) {
- Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
- if (E) {
- return E->get().rpc_method_id;
- }
-
- script_data = script_data->base_data;
- }
-
- return UINT16_MAX;
-}
-
-StringName NativeScript::get_rpc_method(uint16_t p_id) const {
- ERR_FAIL_COND_V(p_id == UINT16_MAX, StringName());
-
- NativeScriptDesc *script_data = get_script_desc();
-
- while (script_data) {
- for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
- if (E->get().rpc_method_id == p_id) {
- return E->key();
- }
- }
-
- script_data = script_data->base_data;
- }
-
- return StringName();
-}
-
-MultiplayerAPI::RPCMode NativeScript::get_rpc_mode_by_id(uint16_t p_id) const {
- ERR_FAIL_COND_V(p_id == UINT16_MAX, MultiplayerAPI::RPC_MODE_DISABLED);
-
- NativeScriptDesc *script_data = get_script_desc();
-
- while (script_data) {
- for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
- if (E->get().rpc_method_id == p_id) {
- switch (E->get().rpc_mode) {
- case GODOT_METHOD_RPC_MODE_DISABLED:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- case GODOT_METHOD_RPC_MODE_REMOTE:
- return MultiplayerAPI::RPC_MODE_REMOTE;
- case GODOT_METHOD_RPC_MODE_MASTER:
- return MultiplayerAPI::RPC_MODE_MASTER;
- case GODOT_METHOD_RPC_MODE_PUPPET:
- return MultiplayerAPI::RPC_MODE_PUPPET;
- case GODOT_METHOD_RPC_MODE_REMOTESYNC:
- return MultiplayerAPI::RPC_MODE_REMOTESYNC;
- case GODOT_METHOD_RPC_MODE_MASTERSYNC:
- return MultiplayerAPI::RPC_MODE_MASTERSYNC;
- case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
- return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
- default:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
- }
- }
-
- script_data = script_data->base_data;
- }
-
- return MultiplayerAPI::RPC_MODE_DISABLED;
-}
-
-MultiplayerAPI::RPCMode NativeScript::get_rpc_mode(const StringName &p_method) const {
- NativeScriptDesc *script_data = get_script_desc();
-
- while (script_data) {
- Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
- if (E) {
- switch (E->get().rpc_mode) {
- case GODOT_METHOD_RPC_MODE_DISABLED:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- case GODOT_METHOD_RPC_MODE_REMOTE:
- return MultiplayerAPI::RPC_MODE_REMOTE;
- case GODOT_METHOD_RPC_MODE_MASTER:
- return MultiplayerAPI::RPC_MODE_MASTER;
- case GODOT_METHOD_RPC_MODE_PUPPET:
- return MultiplayerAPI::RPC_MODE_PUPPET;
- case GODOT_METHOD_RPC_MODE_REMOTESYNC:
- return MultiplayerAPI::RPC_MODE_REMOTESYNC;
- case GODOT_METHOD_RPC_MODE_MASTERSYNC:
- return MultiplayerAPI::RPC_MODE_MASTERSYNC;
- case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
- return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
- default:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
- }
-
- script_data = script_data->base_data;
- }
-
- return MultiplayerAPI::RPC_MODE_DISABLED;
-}
-
-Vector<ScriptNetData> NativeScript::get_rset_properties() const {
- Vector<ScriptNetData> v;
-
- NativeScriptDesc *script_data = get_script_desc();
-
- while (script_data) {
- for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) {
- if (E.get().rset_mode != GODOT_METHOD_RPC_MODE_DISABLED) {
- ScriptNetData nd;
- nd.name = E.key();
- nd.mode = MultiplayerAPI::RPCMode(E.get().rset_mode);
- v.push_back(nd);
- }
- }
- script_data = script_data->base_data;
- }
-
- return v;
-}
-
-uint16_t NativeScript::get_rset_property_id(const StringName &p_variable) const {
- NativeScriptDesc *script_data = get_script_desc();
-
- while (script_data) {
- OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable);
- if (E) {
- return E.get().rset_property_id;
- }
-
- script_data = script_data->base_data;
- }
-
- return UINT16_MAX;
-}
-
-StringName NativeScript::get_rset_property(uint16_t p_id) const {
- ERR_FAIL_COND_V(p_id == UINT16_MAX, StringName());
-
- NativeScriptDesc *script_data = get_script_desc();
-
- while (script_data) {
- for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) {
- if (E.get().rset_property_id == p_id) {
- return E.key();
- }
- }
-
- script_data = script_data->base_data;
- }
-
- return StringName();
-}
-
-MultiplayerAPI::RPCMode NativeScript::get_rset_mode_by_id(uint16_t p_id) const {
- ERR_FAIL_COND_V(p_id == UINT16_MAX, MultiplayerAPI::RPC_MODE_DISABLED);
-
- NativeScriptDesc *script_data = get_script_desc();
-
- while (script_data) {
- for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) {
- if (E.get().rset_property_id == p_id) {
- switch (E.get().rset_mode) {
- case GODOT_METHOD_RPC_MODE_DISABLED:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- case GODOT_METHOD_RPC_MODE_REMOTE:
- return MultiplayerAPI::RPC_MODE_REMOTE;
- case GODOT_METHOD_RPC_MODE_MASTER:
- return MultiplayerAPI::RPC_MODE_MASTER;
- case GODOT_METHOD_RPC_MODE_PUPPET:
- return MultiplayerAPI::RPC_MODE_PUPPET;
- case GODOT_METHOD_RPC_MODE_REMOTESYNC:
- return MultiplayerAPI::RPC_MODE_REMOTESYNC;
- case GODOT_METHOD_RPC_MODE_MASTERSYNC:
- return MultiplayerAPI::RPC_MODE_MASTERSYNC;
- case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
- return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
- default:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
- }
- }
-
- script_data = script_data->base_data;
- }
-
- return MultiplayerAPI::RPC_MODE_DISABLED;
-}
-
-MultiplayerAPI::RPCMode NativeScript::get_rset_mode(const StringName &p_variable) const {
- NativeScriptDesc *script_data = get_script_desc();
-
- while (script_data) {
- OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable);
- if (E) {
- switch (E.get().rset_mode) {
- case GODOT_METHOD_RPC_MODE_DISABLED:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- case GODOT_METHOD_RPC_MODE_REMOTE:
- return MultiplayerAPI::RPC_MODE_REMOTE;
- case GODOT_METHOD_RPC_MODE_MASTER:
- return MultiplayerAPI::RPC_MODE_MASTER;
- case GODOT_METHOD_RPC_MODE_PUPPET:
- return MultiplayerAPI::RPC_MODE_PUPPET;
- case GODOT_METHOD_RPC_MODE_REMOTESYNC:
- return MultiplayerAPI::RPC_MODE_REMOTESYNC;
- case GODOT_METHOD_RPC_MODE_MASTERSYNC:
- return MultiplayerAPI::RPC_MODE_MASTERSYNC;
- case GODOT_METHOD_RPC_MODE_PUPPETSYNC:
- return MultiplayerAPI::RPC_MODE_PUPPETSYNC;
- default:
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
- }
-
- script_data = script_data->base_data;
- }
-
- return MultiplayerAPI::RPC_MODE_DISABLED;
+ return script_data->rpc_methods;
}
String NativeScript::get_class_documentation() const {
@@ -737,7 +505,7 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
if (!(script_data->base_native_type == "")) {
owner = ClassDB::instance(script_data->base_native_type);
} else {
- owner = memnew(Reference);
+ owner = memnew(RefCounted);
}
if (!owner) {
@@ -745,7 +513,7 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
return Variant();
}
- Reference *r = Object::cast_to<Reference>(owner);
+ RefCounted *r = Object::cast_to<RefCounted>(owner);
if (r) {
ref = REF(r);
}
@@ -1044,46 +812,10 @@ Ref<Script> NativeScriptInstance::get_script() const {
return script;
}
-Vector<ScriptNetData> NativeScriptInstance::get_rpc_methods() const {
+const Vector<MultiplayerAPI::RPCConfig> NativeScriptInstance::get_rpc_methods() const {
return script->get_rpc_methods();
}
-uint16_t NativeScriptInstance::get_rpc_method_id(const StringName &p_method) const {
- return script->get_rpc_method_id(p_method);
-}
-
-StringName NativeScriptInstance::get_rpc_method(uint16_t p_id) const {
- return script->get_rpc_method(p_id);
-}
-
-MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode_by_id(uint16_t p_id) const {
- return script->get_rpc_mode_by_id(p_id);
-}
-
-MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode(const StringName &p_method) const {
- return script->get_rpc_mode(p_method);
-}
-
-Vector<ScriptNetData> NativeScriptInstance::get_rset_properties() const {
- return script->get_rset_properties();
-}
-
-uint16_t NativeScriptInstance::get_rset_property_id(const StringName &p_variable) const {
- return script->get_rset_property_id(p_variable);
-}
-
-StringName NativeScriptInstance::get_rset_property(uint16_t p_id) const {
- return script->get_rset_property(p_id);
-}
-
-MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode_by_id(uint16_t p_id) const {
- return script->get_rset_mode_by_id(p_id);
-}
-
-MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const {
- return script->get_rset_mode(p_variable);
-}
-
ScriptLanguage *NativeScriptInstance::get_language() {
return NativeScriptLanguage::get_singleton();
}
@@ -1248,6 +980,7 @@ void NativeScriptLanguage::init() {
if (generate_c_api(E->next()->get()) != OK) {
ERR_PRINT("Failed to generate C API\n");
}
+ Main::cleanup(true);
exit(0);
}
@@ -1257,6 +990,7 @@ void NativeScriptLanguage::init() {
if (generate_c_builtin_api(E->next()->get()) != OK) {
ERR_PRINT("Failed to generate C builtin API\n");
}
+ Main::cleanup(true);
exit(0);
}
#endif
@@ -1285,6 +1019,10 @@ void NativeScriptLanguage::finish() {
void NativeScriptLanguage::get_reserved_words(List<String> *p_words) const {
}
+bool NativeScriptLanguage::is_control_flow_keyword(String p_keyword) const {
+ return false;
+}
+
void NativeScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
}
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index d6ba2bbec1..1756321281 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -62,8 +62,6 @@ struct NativeScriptDesc {
godot_nativescript_property_get_func getter;
PropertyInfo info;
Variant default_value;
- int rset_mode = 0;
- uint16_t rset_property_id;
String documentation;
};
@@ -72,9 +70,8 @@ struct NativeScriptDesc {
String documentation;
};
- uint16_t rpc_count = 0;
Map<StringName, Method> methods;
- uint16_t rset_count = 0;
+ Vector<MultiplayerAPI::RPCConfig> rpc_methods;
OrderedHashMap<StringName, Property> properties;
Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals
StringName base;
@@ -90,8 +87,8 @@ struct NativeScriptDesc {
bool is_tool = false;
inline NativeScriptDesc() {
- zeromem(&create_func, sizeof(godot_nativescript_instance_create_func));
- zeromem(&destroy_func, sizeof(godot_nativescript_instance_destroy_func));
+ memset(&create_func, 0, sizeof(godot_nativescript_instance_create_func));
+ memset(&destroy_func, 0, sizeof(godot_nativescript_instance_destroy_func));
}
};
@@ -178,17 +175,7 @@ public:
virtual void get_script_method_list(List<MethodInfo> *p_list) const override;
virtual void get_script_property_list(List<PropertyInfo> *p_list) const override;
- virtual Vector<ScriptNetData> get_rpc_methods() const override;
- virtual uint16_t get_rpc_method_id(const StringName &p_method) const override;
- virtual StringName get_rpc_method(uint16_t p_id) const override;
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const override;
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
-
- virtual Vector<ScriptNetData> get_rset_properties() const override;
- virtual uint16_t get_rset_property_id(const StringName &p_variable) const override;
- virtual StringName get_rset_property(uint16_t p_id) const override;
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const override;
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
String get_class_documentation() const;
String get_method_documentation(const StringName &p_method) const;
@@ -226,17 +213,7 @@ public:
String to_string(bool *r_valid);
virtual Ref<Script> get_script() const;
- virtual Vector<ScriptNetData> get_rpc_methods() const;
- virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
- virtual StringName get_rpc_method(uint16_t p_id) const;
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const;
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
-
- virtual Vector<ScriptNetData> get_rset_properties() const;
- virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
- virtual StringName get_rset_property(uint16_t p_id) const;
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const;
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const;
virtual ScriptLanguage *get_language();
@@ -336,6 +313,7 @@ public:
virtual Error execute_file(const String &p_path);
virtual void finish();
virtual void get_reserved_words(List<String> *p_words) const;
+ virtual bool is_control_flow_keyword(String p_keyword) const;
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;
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp
index 7f8dba0906..ed1c0af3ed 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp
@@ -100,46 +100,10 @@ String PluginScriptInstance::to_string(bool *r_valid) {
return str_ret;
}
-Vector<ScriptNetData> PluginScriptInstance::get_rpc_methods() const {
+const Vector<MultiplayerAPI::RPCConfig> PluginScriptInstance::get_rpc_methods() const {
return _script->get_rpc_methods();
}
-uint16_t PluginScriptInstance::get_rpc_method_id(const StringName &p_variable) const {
- return _script->get_rpc_method_id(p_variable);
-}
-
-StringName PluginScriptInstance::get_rpc_method(uint16_t p_id) const {
- return _script->get_rpc_method(p_id);
-}
-
-MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode_by_id(uint16_t p_id) const {
- return _script->get_rpc_mode_by_id(p_id);
-}
-
-MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode(const StringName &p_method) const {
- return _script->get_rpc_mode(p_method);
-}
-
-Vector<ScriptNetData> PluginScriptInstance::get_rset_properties() const {
- return _script->get_rset_properties();
-}
-
-uint16_t PluginScriptInstance::get_rset_property_id(const StringName &p_variable) const {
- return _script->get_rset_property_id(p_variable);
-}
-
-StringName PluginScriptInstance::get_rset_property(uint16_t p_id) const {
- return _script->get_rset_property(p_id);
-}
-
-MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode_by_id(uint16_t p_id) const {
- return _script->get_rset_mode_by_id(p_id);
-}
-
-MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode(const StringName &p_variable) const {
- return _script->get_rset_mode(p_variable);
-}
-
void PluginScriptInstance::refcount_incremented() {
if (_desc->refcount_decremented) {
_desc->refcount_incremented(_data);
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h
index b263c0e62c..25b62ae8ab 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.h
+++ b/modules/gdnative/pluginscript/pluginscript_instance.h
@@ -71,17 +71,7 @@ public:
void set_path(const String &p_path);
- virtual Vector<ScriptNetData> get_rpc_methods() const;
- virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
- virtual StringName get_rpc_method(uint16_t p_id) const;
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const;
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
-
- virtual Vector<ScriptNetData> get_rset_properties() const;
- virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
- virtual StringName get_rset_property(uint16_t p_id) const;
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const;
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const;
virtual void refcount_incremented();
virtual bool refcount_decremented();
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
index 3ed1dcaca9..0291ae560b 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -30,7 +30,7 @@
// Godot imports
#include "core/config/project_settings.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/os.h"
// PluginScript imports
#include "pluginscript_language.h"
@@ -77,6 +77,10 @@ void PluginScriptLanguage::get_reserved_words(List<String> *p_words) const {
}
}
+bool PluginScriptLanguage::is_control_flow_keyword(String p_keyword) const {
+ return false;
+}
+
void PluginScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
if (_desc.comment_delimiters) {
const char **w = _desc.comment_delimiters;
diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h
index 226b039265..957bf355ca 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.h
+++ b/modules/gdnative/pluginscript/pluginscript_language.h
@@ -71,6 +71,7 @@ public:
/* EDITOR FUNCTIONS */
virtual void get_reserved_words(List<String> *p_words) const;
+ virtual bool is_control_flow_keyword(String p_keyword) const;
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;
diff --git a/modules/gdnative/pluginscript/pluginscript_loader.cpp b/modules/gdnative/pluginscript/pluginscript_loader.cpp
index f2165cd225..462452a897 100644
--- a/modules/gdnative/pluginscript/pluginscript_loader.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_loader.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
// Godot imports
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
// Pythonscript imports
#include "pluginscript_language.h"
#include "pluginscript_loader.h"
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index 31e6a81975..1dabb1db63 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
// Godot imports
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
// PluginScript imports
#include "pluginscript_instance.h"
#include "pluginscript_script.h"
@@ -94,7 +94,7 @@ Variant PluginScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
Object *owner = nullptr;
if (get_instance_base_type() == "") {
- owner = memnew(Reference);
+ owner = memnew(RefCounted);
} else {
owner = ClassDB::instance(get_instance_base_type());
}
@@ -104,7 +104,7 @@ Variant PluginScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
return Variant();
}
- Reference *r = Object::cast_to<Reference>(owner);
+ RefCounted *r = Object::cast_to<RefCounted>(owner);
if (r) {
ref = REF(r);
}
@@ -212,6 +212,8 @@ ScriptInstance *PluginScript::instance_create(Object *p_this) {
}
bool PluginScript::instance_has(const Object *p_this) const {
+ ERR_FAIL_COND_V(!_language, false);
+
_language->lock();
bool hasit = _instances.has((Object *)p_this);
_language->unlock();
@@ -310,10 +312,9 @@ Error PluginScript::reload(bool p_keep_state) {
}
Array *methods = (Array *)&manifest.methods;
_rpc_methods.clear();
- _rpc_variables.clear();
if (_ref_base_parent.is_valid()) {
+ /// XXX TODO Should this be _rpc_methods.append_array(...)
_rpc_methods = _ref_base_parent->get_rpc_methods();
- _rpc_variables = _ref_base_parent->get_rset_properties();
}
for (int i = 0; i < methods->size(); ++i) {
Dictionary v = (*methods)[i];
@@ -322,9 +323,10 @@ Error PluginScript::reload(bool p_keep_state) {
// rpc_mode is passed as an optional field and is not part of MethodInfo
Variant var = v["rpc_mode"];
if (var != Variant()) {
- ScriptNetData nd;
+ MultiplayerAPI::RPCConfig nd;
nd.name = mi.name;
- nd.mode = MultiplayerAPI::RPCMode(int(var));
+ nd.rpc_mode = MultiplayerAPI::RPCMode(int(var));
+ // TODO Transfer Channel
if (_rpc_methods.find(nd) == -1) {
_rpc_methods.push_back(nd);
}
@@ -332,7 +334,7 @@ Error PluginScript::reload(bool p_keep_state) {
}
// Sort so we are 100% that they are always the same.
- _rpc_methods.sort_custom<SortNetData>();
+ _rpc_methods.sort_custom<MultiplayerAPI::SortRPCConfig>();
Array *signals = (Array *)&manifest.signals;
for (int i = 0; i < signals->size(); ++i) {
@@ -346,21 +348,8 @@ Error PluginScript::reload(bool p_keep_state) {
PropertyInfo pi = PropertyInfo::from_dict(v);
_properties_info[pi.name] = pi;
_properties_default_values[pi.name] = v["default_value"];
- // rset_mode is passed as an optional field and is not part of PropertyInfo
- Variant var = v["rset_mode"];
- if (var != Variant()) {
- ScriptNetData nd;
- nd.name = pi.name;
- nd.mode = MultiplayerAPI::RPCMode(int(var));
- if (_rpc_variables.find(nd) == -1) {
- _rpc_variables.push_back(nd);
- }
- }
}
- // Sort so we are 100% that they are always the same.
- _rpc_variables.sort_custom<SortNetData>();
-
#ifdef TOOLS_ENABLED
/*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
@@ -441,10 +430,10 @@ Error PluginScript::load_source_code(const String &p_path) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + p_path + "'.");
- int len = f->get_len();
+ uint64_t len = f->get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
- int r = f->get_buffer(w, len);
+ uint64_t r = f->get_buffer(w, len);
f->close();
memdelete(f);
ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
@@ -484,76 +473,10 @@ int PluginScript::get_member_line(const StringName &p_member) const {
return -1;
}
-Vector<ScriptNetData> PluginScript::get_rpc_methods() const {
+const Vector<MultiplayerAPI::RPCConfig> PluginScript::get_rpc_methods() const {
return _rpc_methods;
}
-uint16_t PluginScript::get_rpc_method_id(const StringName &p_method) const {
- ASSERT_SCRIPT_VALID_V(UINT16_MAX);
- for (int i = 0; i < _rpc_methods.size(); i++) {
- if (_rpc_methods[i].name == p_method) {
- return i;
- }
- }
- return UINT16_MAX;
-}
-
-StringName PluginScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
- ASSERT_SCRIPT_VALID_V(StringName());
- if (p_rpc_method_id >= _rpc_methods.size()) {
- return StringName();
- }
- return _rpc_methods[p_rpc_method_id].name;
-}
-
-MultiplayerAPI::RPCMode PluginScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
- ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
- if (p_rpc_method_id >= _rpc_methods.size()) {
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
- return _rpc_methods[p_rpc_method_id].mode;
-}
-
-MultiplayerAPI::RPCMode PluginScript::get_rpc_mode(const StringName &p_method) const {
- ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
- return get_rpc_mode_by_id(get_rpc_method_id(p_method));
-}
-
-Vector<ScriptNetData> PluginScript::get_rset_properties() const {
- return _rpc_variables;
-}
-
-uint16_t PluginScript::get_rset_property_id(const StringName &p_property) const {
- ASSERT_SCRIPT_VALID_V(UINT16_MAX);
- for (int i = 0; i < _rpc_variables.size(); i++) {
- if (_rpc_variables[i].name == p_property) {
- return i;
- }
- }
- return UINT16_MAX;
-}
-
-StringName PluginScript::get_rset_property(const uint16_t p_rset_property_id) const {
- ASSERT_SCRIPT_VALID_V(StringName());
- if (p_rset_property_id >= _rpc_variables.size()) {
- return StringName();
- }
- return _rpc_variables[p_rset_property_id].name;
-}
-
-MultiplayerAPI::RPCMode PluginScript::get_rset_mode_by_id(const uint16_t p_rset_property_id) const {
- ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
- if (p_rset_property_id >= _rpc_variables.size()) {
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
- return _rpc_variables[p_rset_property_id].mode;
-}
-
-MultiplayerAPI::RPCMode PluginScript::get_rset_mode(const StringName &p_variable) const {
- ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED);
- return get_rset_mode_by_id(get_rset_property_id(p_variable));
-}
-
PluginScript::PluginScript() :
_script_list(this) {
}
diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h
index 1c86f2056d..97989a19d8 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.h
+++ b/modules/gdnative/pluginscript/pluginscript_script.h
@@ -61,8 +61,7 @@ private:
Map<StringName, PropertyInfo> _properties_info;
Map<StringName, MethodInfo> _signals_info;
Map<StringName, MethodInfo> _methods_info;
- Vector<ScriptNetData> _rpc_methods;
- Vector<ScriptNetData> _rpc_variables;
+ Vector<MultiplayerAPI::RPCConfig> _rpc_methods;
Set<Object *> _instances;
//exported members
@@ -137,17 +136,7 @@ public:
virtual int get_member_line(const StringName &p_member) const override;
- virtual Vector<ScriptNetData> get_rpc_methods() const override;
- virtual uint16_t get_rpc_method_id(const StringName &p_method) const override;
- virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override;
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override;
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
-
- virtual Vector<ScriptNetData> get_rset_properties() const override;
- virtual uint16_t get_rset_property_id(const StringName &p_property) const override;
- virtual StringName get_rset_property(const uint16_t p_rset_property_id) const override;
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const override;
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
PluginScript();
void init(PluginScriptLanguage *language);
diff --git a/modules/gdnative/pluginscript/register_types.cpp b/modules/gdnative/pluginscript/register_types.cpp
index b94538b2f7..433544178f 100644
--- a/modules/gdnative/pluginscript/register_types.cpp
+++ b/modules/gdnative/pluginscript/register_types.cpp
@@ -31,9 +31,9 @@
#include "register_types.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/os/dir_access.h"
#include "core/os/os.h"
#include "scene/main/scene_tree.h"
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index d08bde9e23..cf19c0c44c 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -363,7 +363,7 @@ void unregister_gdnative_types() {
print_line(String("aabb:\t") + itos(sizeof(AABB)));
print_line(String("rid:\t") + itos(sizeof(RID)));
print_line(String("string:\t") + itos(sizeof(String)));
- print_line(String("transform:\t") + itos(sizeof(Transform)));
+ print_line(String("transform:\t") + itos(sizeof(Transform3D)));
print_line(String("transfo2D:\t") + itos(sizeof(Transform2D)));
print_line(String("variant:\t") + itos(sizeof(Variant)));
print_line(String("vector2:\t") + itos(sizeof(Vector2)));
diff --git a/modules/gdnative/tests/test_variant.h b/modules/gdnative/tests/test_variant.h
index aeceb6e68f..2850036604 100644
--- a/modules/gdnative/tests/test_variant.h
+++ b/modules/gdnative/tests/test_variant.h
@@ -107,7 +107,7 @@ TEST_CASE("[GDNative Variant] Variant call") {
godot_string_name_new_with_latin1_chars(&method, "is_valid_identifier");
godot_variant_call_error error;
- godot_variant_call(&self, &method, NULL, 0, &ret, &error);
+ godot_variant_call(&self, &method, nullptr, 0, &ret, &error);
CHECK(godot_variant_get_type(&ret) == GODOT_VARIANT_TYPE_BOOL);
CHECK(godot_variant_as_bool(&ret));
diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp
index f2fb0a2fdc..8b0434c7dd 100644
--- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp
+++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp
@@ -47,11 +47,7 @@ godot_int GDAPI godot_videodecoder_file_read(void *ptr, uint8_t *buf, int buf_si
// if file exists
if (file) {
- long bytes_read = file->get_buffer(buf, buf_size);
- // No bytes to read => EOF
- if (bytes_read == 0) {
- return 0;
- }
+ int64_t bytes_read = file->get_buffer(buf, buf_size);
return bytes_read;
}
return -1;
@@ -62,41 +58,35 @@ int64_t GDAPI godot_videodecoder_file_seek(void *ptr, int64_t pos, int whence) {
FileAccess *file = reinterpret_cast<FileAccess *>(ptr);
if (file) {
- size_t len = file->get_len();
+ int64_t len = file->get_length();
switch (whence) {
case SEEK_SET: {
- // Just for explicitness
- size_t new_pos = static_cast<size_t>(pos);
- if (new_pos > len) {
+ if (pos > len) {
return -1;
}
- file->seek(new_pos);
- pos = static_cast<int64_t>(file->get_position());
- return pos;
+ file->seek(pos);
+ return file->get_position();
} break;
case SEEK_CUR: {
// Just in case it doesn't exist
- if (pos < 0 && (size_t)-pos > file->get_position()) {
+ if (pos < 0 && -pos > (int64_t)file->get_position()) {
return -1;
}
- pos = pos + static_cast<int>(file->get_position());
- file->seek(pos);
- pos = static_cast<int64_t>(file->get_position());
- return pos;
+ file->seek(file->get_position() + pos);
+ return file->get_position();
} break;
case SEEK_END: {
// Just in case something goes wrong
- if ((size_t)-pos > len) {
+ if (-pos > len) {
return -1;
}
file->seek_end(pos);
- pos = static_cast<int64_t>(file->get_position());
- return pos;
+ return file->get_position();
} break;
default: {
// Only 4 possible options, hence default = AVSEEK_SIZE
// Asks to return the length of file
- return static_cast<int64_t>(len);
+ return len;
} break;
}
}
diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.h b/modules/gdnative/videodecoder/video_stream_gdnative.h
index 140888cd4b..c605dbb433 100644
--- a/modules/gdnative/videodecoder/video_stream_gdnative.h
+++ b/modules/gdnative/videodecoder/video_stream_gdnative.h
@@ -32,7 +32,7 @@
#define VIDEO_STREAM_GDNATIVE_H
#include "../gdnative.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "scene/resources/texture.h"
#include "scene/resources/video_stream.h"
diff --git a/modules/gdnative/xr/xr_interface_gdnative.cpp b/modules/gdnative/xr/xr_interface_gdnative.cpp
index 122cb5849b..ff959affa3 100644
--- a/modules/gdnative/xr/xr_interface_gdnative.cpp
+++ b/modules/gdnative/xr/xr_interface_gdnative.cpp
@@ -70,8 +70,13 @@ void XRInterfaceGDNative::set_interface(const godot_xr_interface_gdnative *p_int
// this should only be called once, just being paranoid..
if (interface) {
cleanup();
+ interface = NULL;
}
+ // validate
+ ERR_FAIL_NULL(p_interface);
+ ERR_FAIL_COND_MSG(p_interface->version.major < 4, "This is an incompatible GDNative XR plugin.");
+
// bind to our interface
interface = p_interface;
@@ -119,14 +124,14 @@ int XRInterfaceGDNative::get_camera_feed_id() {
return (unsigned int)interface->get_camera_feed_id(data);
}
-bool XRInterfaceGDNative::is_stereo() {
- bool stereo;
+uint32_t XRInterfaceGDNative::get_view_count() {
+ uint32_t view_count;
- ERR_FAIL_COND_V(interface == nullptr, false);
+ ERR_FAIL_COND_V(interface == nullptr, 1);
- stereo = interface->is_stereo(data);
+ view_count = interface->get_view_count(data);
- return stereo;
+ return view_count;
}
bool XRInterfaceGDNative::is_initialized() const {
@@ -173,28 +178,52 @@ Size2 XRInterfaceGDNative::get_render_targetsize() {
return *vec;
}
-Transform XRInterfaceGDNative::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) {
- Transform *ret;
+Transform3D XRInterfaceGDNative::get_camera_transform() {
+ Transform3D *ret;
+
+ ERR_FAIL_COND_V(interface == nullptr, Transform3D());
+
+ godot_transform3d t = interface->get_camera_transform(data);
+
+ ret = (Transform3D *)&t;
+
+ return *ret;
+}
+
+Transform3D XRInterfaceGDNative::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
+ Transform3D *ret;
- ERR_FAIL_COND_V(interface == nullptr, Transform());
+ ERR_FAIL_COND_V(interface == nullptr, Transform3D());
- godot_transform t = interface->get_transform_for_eye(data, (int)p_eye, (godot_transform *)&p_cam_transform);
+ godot_transform3d t = interface->get_transform_for_view(data, (int)p_view, (godot_transform3d *)&p_cam_transform);
- ret = (Transform *)&t;
+ ret = (Transform3D *)&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 XRInterfaceGDNative::get_projection_for_view(uint32_t p_view, 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_float *)cm.matrix, (godot_int)p_eye, p_aspect, p_z_near, p_z_far);
+ interface->fill_projection_for_view(data, (godot_real_t *)cm.matrix, (godot_int)p_view, p_aspect, p_z_near, p_z_far);
return cm;
}
+Vector<BlitToScreen> XRInterfaceGDNative::commit_views(RID p_render_target, const Rect2 &p_screen_rect) {
+ // possibly move this as a member variable and add a callback to populate?
+ Vector<BlitToScreen> blit_to_screen;
+
+ ERR_FAIL_COND_V(interface == nullptr, blit_to_screen);
+
+ // must implement
+ interface->commit_views(data, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect);
+
+ return blit_to_screen;
+}
+
unsigned int XRInterfaceGDNative::get_external_texture_for_eye(XRInterface::Eyes p_eye) {
ERR_FAIL_COND_V(interface == nullptr, 0);
@@ -234,22 +263,22 @@ void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_inte
XRServer::get_singleton()->add_interface(new_interface);
}
-godot_float GDAPI godot_xr_get_worldscale() {
+godot_real_t 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;
+godot_transform3d GDAPI godot_xr_get_reference_frame() {
+ godot_transform3d reference_frame;
+ Transform3D *reference_frame_ptr = (Transform3D *)&reference_frame;
XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
*reference_frame_ptr = xr_server->get_reference_frame();
} else {
- memnew_placement(&reference_frame, Transform);
+ memnew_placement(&reference_frame, Transform3D);
}
return reference_frame;
@@ -356,13 +385,13 @@ 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_transform(godot_int p_controller_id, godot_transform3d *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (tracker.is_valid()) {
- Transform *transform = (Transform *)p_transform;
+ Transform3D *transform = (Transform3D *)p_transform;
if (p_tracks_orientation) {
tracker->set_orientation(transform->basis);
}
@@ -388,7 +417,7 @@ void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p
}
}
-void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_float p_value, godot_bool p_can_be_negative) {
+void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real_t p_value, godot_bool p_can_be_negative) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
@@ -407,7 +436,7 @@ void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_a
}
}
-godot_float GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) {
+godot_real_t 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);
diff --git a/modules/gdnative/xr/xr_interface_gdnative.h b/modules/gdnative/xr/xr_interface_gdnative.h
index 84bd8fc731..42e9206c1f 100644
--- a/modules/gdnative/xr/xr_interface_gdnative.h
+++ b/modules/gdnative/xr/xr_interface_gdnative.h
@@ -72,20 +72,24 @@ public:
/** rendering and internal **/
virtual Size2 get_render_targetsize() override;
- virtual bool is_stereo() override;
- virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override;
+ virtual uint32_t get_view_count() override;
+ virtual Transform3D get_camera_transform() override;
+ virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
// 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) override;
+ virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override;
- virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override;
- virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override;
+ virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override;
virtual void process() override;
virtual void notification(int p_what) override;
+
+ // deprecated
+ virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override;
+ virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override;
};
#endif // XR_INTERFACE_GDNATIVE_H
diff --git a/modules/gdnavigation/gd_navigation_server.cpp b/modules/gdnavigation/gd_navigation_server.cpp
index 39f208c7a4..d5e6e5e69f 100644
--- a/modules/gdnavigation/gd_navigation_server.cpp
+++ b/modules/gdnavigation/gd_navigation_server.cpp
@@ -122,7 +122,7 @@ GdNavigationServer::~GdNavigationServer() {
}
void GdNavigationServer::add_command(SetCommand *command) const {
- auto mut_this = const_cast<GdNavigationServer *>(this);
+ GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this);
{
MutexLock lock(commands_mutex);
mut_this->commands.push_back(command);
@@ -130,7 +130,7 @@ void GdNavigationServer::add_command(SetCommand *command) const {
}
RID GdNavigationServer::map_create() const {
- auto mut_this = const_cast<GdNavigationServer *>(this);
+ GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
NavMap *space = memnew(NavMap);
RID rid = map_owner.make_rid(space);
@@ -240,7 +240,7 @@ RID GdNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3 &p_
}
RID GdNavigationServer::region_create() const {
- auto mut_this = const_cast<GdNavigationServer *>(this);
+ GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
NavRegion *reg = memnew(NavRegion);
RID rid = region_owner.make_rid(reg);
@@ -270,7 +270,7 @@ COMMAND_2(region_set_map, RID, p_region, RID, p_map) {
}
}
-COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform) {
+COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform) {
NavRegion *region = region_owner.getornull(p_region);
ERR_FAIL_COND(region == nullptr);
@@ -330,7 +330,7 @@ Vector3 GdNavigationServer::region_get_connection_pathway_end(RID p_region, int
}
RID GdNavigationServer::agent_create() const {
- auto mut_this = const_cast<GdNavigationServer *>(this);
+ GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
RvoAgent *agent = memnew(RvoAgent());
RID rid = agent_owner.make_rid(agent);
@@ -504,7 +504,7 @@ COMMAND_1(free, RID, p_object) {
}
void GdNavigationServer::set_active(bool p_active) const {
- auto mut_this = const_cast<GdNavigationServer *>(this);
+ GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
mut_this->active = p_active;
}
diff --git a/modules/gdnavigation/gd_navigation_server.h b/modules/gdnavigation/gd_navigation_server.h
index 2f51f6431e..759d15e508 100644
--- a/modules/gdnavigation/gd_navigation_server.h
+++ b/modules/gdnavigation/gd_navigation_server.h
@@ -113,7 +113,7 @@ public:
COMMAND_2(region_set_map, RID, p_region, RID, p_map);
COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers);
virtual uint32_t region_get_layers(RID p_region) const;
- COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform);
+ COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform);
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh);
virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const;
virtual int region_get_connections_count(RID p_region) const;
diff --git a/modules/gdnavigation/nav_map.cpp b/modules/gdnavigation/nav_map.cpp
index 464082221f..41306f0687 100644
--- a/modules/gdnavigation/nav_map.cpp
+++ b/modules/gdnavigation/nav_map.cpp
@@ -112,7 +112,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
}
}
- // Check for trival cases
+ // Check for trivial cases
if (!begin_poly || !end_poly) {
return Vector<Vector3>();
}
@@ -168,7 +168,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, pathway);
const float new_distance = least_cost_poly->entry.distance_to(new_entry) + least_cost_poly->traveled_distance;
- auto it = std::find(
+ const std::vector<gd::NavigationPoly>::iterator it = std::find(
navigation_polys.begin(),
navigation_polys.end(),
gd::NavigationPoly(connection.polygon));
@@ -504,7 +504,7 @@ void NavMap::add_region(NavRegion *p_region) {
}
void NavMap::remove_region(NavRegion *p_region) {
- std::vector<NavRegion *>::iterator it = std::find(regions.begin(), regions.end(), p_region);
+ const std::vector<NavRegion *>::iterator it = std::find(regions.begin(), regions.end(), p_region);
if (it != regions.end()) {
regions.erase(it);
regenerate_links = true;
@@ -524,7 +524,7 @@ void NavMap::add_agent(RvoAgent *agent) {
void NavMap::remove_agent(RvoAgent *agent) {
remove_agent_as_controlled(agent);
- auto it = std::find(agents.begin(), agents.end(), agent);
+ const std::vector<RvoAgent *>::iterator it = std::find(agents.begin(), agents.end(), agent);
if (it != agents.end()) {
agents.erase(it);
agents_dirty = true;
@@ -540,7 +540,7 @@ void NavMap::set_agent_as_controlled(RvoAgent *agent) {
}
void NavMap::remove_agent_as_controlled(RvoAgent *agent) {
- auto it = std::find(controlled_agents.begin(), controlled_agents.end(), agent);
+ const std::vector<RvoAgent *>::iterator it = std::find(controlled_agents.begin(), controlled_agents.end(), agent);
if (it != controlled_agents.end()) {
controlled_agents.erase(it);
}
diff --git a/modules/gdnavigation/nav_region.cpp b/modules/gdnavigation/nav_region.cpp
index c1690b2a4b..81b15a49f5 100644
--- a/modules/gdnavigation/nav_region.cpp
+++ b/modules/gdnavigation/nav_region.cpp
@@ -52,7 +52,7 @@ uint32_t NavRegion::get_layers() const {
return layers;
}
-void NavRegion::set_transform(Transform p_transform) {
+void NavRegion::set_transform(Transform3D p_transform) {
transform = p_transform;
polygons_dirty = true;
}
diff --git a/modules/gdnavigation/nav_region.h b/modules/gdnavigation/nav_region.h
index 527b2500ac..f8b067e638 100644
--- a/modules/gdnavigation/nav_region.h
+++ b/modules/gdnavigation/nav_region.h
@@ -46,7 +46,7 @@ class NavRegion;
class NavRegion : public NavRid {
NavMap *map = nullptr;
- Transform transform;
+ Transform3D transform;
Ref<NavigationMesh> mesh;
uint32_t layers = 1;
Vector<gd::Edge::Connection> connections;
@@ -71,8 +71,8 @@ public:
void set_layers(uint32_t p_layers);
uint32_t get_layers() const;
- void set_transform(Transform transform);
- const Transform &get_transform() const {
+ void set_transform(Transform3D transform);
+ const Transform3D &get_transform() const {
return transform;
}
diff --git a/modules/gdnavigation/navigation_mesh_generator.cpp b/modules/gdnavigation/navigation_mesh_generator.cpp
index a7d4e79148..d69c9114b9 100644
--- a/modules/gdnavigation/navigation_mesh_generator.cpp
+++ b/modules/gdnavigation/navigation_mesh_generator.cpp
@@ -32,7 +32,7 @@
#include "navigation_mesh_generator.h"
-#include "core/math/quick_hull.h"
+#include "core/math/convex_hull.h"
#include "core/os/thread.h"
#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/mesh_instance_3d.h"
@@ -68,7 +68,7 @@ void NavigationMeshGenerator::_add_vertex(const Vector3 &p_vec3, Vector<float> &
p_verticies.push_back(p_vec3.z);
}
-void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) {
+void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) {
int current_vertex_count;
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
@@ -123,7 +123,7 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform
}
}
-void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) {
+void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) {
int face_count = p_faces.size() / 3;
int current_vertex_count = p_verticies.size() / 3;
@@ -138,7 +138,7 @@ 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) {
+void NavigationMeshGenerator::_parse_geometry(Transform3D 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<MeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_node);
Ref<Mesh> mesh = mesh_instance->get_mesh();
@@ -169,7 +169,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
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();
+ Transform3D transform = p_accumulated_transform * static_body->get_transform() * col_shape->get_transform();
Ref<Mesh> mesh;
Ref<Shape3D> s = col_shape->get_shape();
@@ -220,7 +220,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
Vector<Vector3> varr = Variant(convex_polygon->get_points());
Geometry3D::MeshData md;
- Error err = QuickHull::build(varr, md);
+ Error err = ConvexHullComputer::convex_hull(varr, md);
if (err == OK) {
PackedVector3Array faces;
@@ -251,7 +251,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
if (Object::cast_to<GridMap>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
GridMap *gridmap_instance = Object::cast_to<GridMap>(p_node);
Array meshes = gridmap_instance->get_meshes();
- Transform xform = gridmap_instance->get_transform();
+ Transform3D xform = gridmap_instance->get_transform();
for (int i = 0; i < meshes.size(); i += 2) {
Ref<Mesh> mesh = meshes[i + 1];
if (mesh.is_valid()) {
@@ -513,7 +513,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<Node3D>(p_node)->get_transform().affine_inverse();
+ Transform3D 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();
diff --git a/modules/gdnavigation/navigation_mesh_generator.h b/modules/gdnavigation/navigation_mesh_generator.h
index 88ccdb1c41..847c7d097b 100644
--- a/modules/gdnavigation/navigation_mesh_generator.h
+++ b/modules/gdnavigation/navigation_mesh_generator.h
@@ -50,9 +50,9 @@ protected:
static void _bind_methods();
static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies);
- static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices);
- static void _add_faces(const PackedVector3Array &p_faces, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices);
- static void _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);
+ static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices);
+ static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices);
+ static void _parse_geometry(Transform3D 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);
static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh);
static void _build_recast_navigation_mesh(
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 9e974b6fdc..58620f2b3e 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -240,10 +240,10 @@
</method>
</methods>
<constants>
- <constant name="PI" value="3.141593">
+ <constant name="PI" value="3.14159265358979">
Constant that represents how many times the diameter of a circle fits around its perimeter. This is equivalent to [code]TAU / 2[/code].
</constant>
- <constant name="TAU" value="6.283185">
+ <constant name="TAU" value="6.28318530717959">
The circle constant, the circumference of the unit circle in radians.
</constant>
<constant name="INF" value="inf">
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index ccc942d86b..b867b03903 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -64,6 +64,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line)
bool in_function_args = false;
bool in_member_variable = false;
bool in_node_path = false;
+ bool in_annotation = false;
bool is_hex_notation = false;
bool is_bin_notation = false;
bool expect_type = false;
@@ -357,9 +358,18 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line)
in_node_path = false;
}
+ if (!in_annotation && in_region == -1 && str[j] == '@') {
+ in_annotation = true;
+ } else if (in_region != -1 || is_a_symbol) {
+ in_annotation = false;
+ }
+
if (in_node_path) {
next_type = NODE_PATH;
color = node_path_color;
+ } else if (in_annotation) {
+ next_type = ANNOTATION;
+ color = annotation_color;
} else if (in_keyword) {
next_type = KEYWORD;
color = keyword_color;
@@ -485,10 +495,15 @@ void GDScriptSyntaxHighlighter::_update_cache() {
/* Reserved words. */
const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
+ const Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color");
List<String> keyword_list;
gdscript->get_reserved_words(&keyword_list);
for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) {
- keywords[E->get()] = keyword_color;
+ if (gdscript->is_control_flow_keyword(E->get())) {
+ keywords[E->get()] = control_flow_keyword_color;
+ } else {
+ keywords[E->get()] = keyword_color;
+ }
}
/* Comments */
@@ -541,19 +556,22 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
const String text_edit_color_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
- const bool default_theme = text_edit_color_theme == "Default";
+ const bool godot_2_theme = text_edit_color_theme == "Godot 2";
- if (default_theme || EditorSettings::get_singleton()->is_dark_theme()) {
+ if (godot_2_theme || EditorSettings::get_singleton()->is_dark_theme()) {
function_definition_color = Color(0.4, 0.9, 1.0);
node_path_color = Color(0.39, 0.76, 0.35);
+ annotation_color = Color(1.0, 0.7, 0.45);
} else {
function_definition_color = Color(0.0, 0.65, 0.73);
node_path_color = Color(0.32, 0.55, 0.29);
+ annotation_color = Color(0.8, 0.5, 0.25);
}
EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", function_definition_color);
EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", node_path_color);
- if (text_edit_color_theme == "Adaptive" || default_theme) {
+ EDITOR_DEF("text_editor/highlighting/gdscript/annotation_color", annotation_color);
+ if (text_edit_color_theme == "Default" || godot_2_theme) {
EditorSettings::get_singleton()->set_initial_value(
"text_editor/highlighting/gdscript/function_definition_color",
function_definition_color,
@@ -562,10 +580,15 @@ void GDScriptSyntaxHighlighter::_update_cache() {
"text_editor/highlighting/gdscript/node_path_color",
node_path_color,
true);
+ EditorSettings::get_singleton()->set_initial_value(
+ "text_editor/highlighting/gdscript/annotation_color",
+ annotation_color,
+ true);
}
function_definition_color = EDITOR_GET("text_editor/highlighting/gdscript/function_definition_color");
node_path_color = EDITOR_GET("text_editor/highlighting/gdscript/node_path_color");
+ annotation_color = EDITOR_GET("text_editor/highlighting/gdscript/annotation_color");
type_color = EDITOR_GET("text_editor/highlighting/base_type_color");
}
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index 1b57cb1923..d07c182aa6 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -54,6 +54,7 @@ private:
NONE,
REGION,
NODE_PATH,
+ ANNOTATION,
SYMBOL,
NUMBER,
FUNCTION,
@@ -72,6 +73,7 @@ private:
Color number_color;
Color member_color;
Color node_path_color;
+ Color annotation_color;
Color type_color;
void add_color_region(const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only = false);
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 5f590383d0..1567576009 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -36,8 +36,8 @@
#include "core/config/project_settings.h"
#include "core/core_constants.h"
#include "core/core_string_names.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_encrypted.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "gdscript_analyzer.h"
#include "gdscript_cache.h"
@@ -75,9 +75,9 @@ Variant GDScriptNativeClass::_new() {
Object *o = instance();
ERR_FAIL_COND_V_MSG(!o, Variant(), "Class type: '" + String(name) + "' is not instantiable.");
- Reference *ref = Object::cast_to<Reference>(o);
- if (ref) {
- return REF(ref);
+ RefCounted *rc = Object::cast_to<RefCounted>(o);
+ if (rc) {
+ return REF(rc);
} else {
return o;
}
@@ -98,11 +98,11 @@ void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance
p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error);
}
-GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error) {
+GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) {
/* STEP 1, CREATE */
GDScriptInstance *instance = memnew(GDScriptInstance);
- instance->base_ref = p_isref;
+ instance->base_ref_counted = p_is_ref_counted;
instance->members.resize(member_indices.size());
instance->script = Ref<GDScript>(this);
instance->owner = p_owner;
@@ -172,11 +172,11 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
if (_baseptr->native.ptr()) {
owner = _baseptr->native->instance();
} else {
- owner = memnew(Reference); //by default, no base means use reference
+ owner = memnew(RefCounted); //by default, no base means use reference
}
ERR_FAIL_COND_V_MSG(!owner, Variant(), "Can't inherit from a virtual class.");
- Reference *r = Object::cast_to<Reference>(owner);
+ RefCounted *r = Object::cast_to<RefCounted>(owner);
if (r) {
ref = REF(r);
}
@@ -353,14 +353,14 @@ ScriptInstance *GDScript::instance_create(Object *p_this) {
}
Callable::CallError unchecked_error;
- return _create_instance(nullptr, 0, p_this, Object::cast_to<Reference>(p_this) != nullptr, unchecked_error);
+ return _create_instance(nullptr, 0, p_this, Object::cast_to<RefCounted>(p_this) != nullptr, unchecked_error);
}
PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) {
#ifdef TOOLS_ENABLED
PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this));
placeholders.insert(si);
- _update_exports();
+ _update_exports(nullptr, false, si);
return si;
#else
return nullptr;
@@ -481,7 +481,7 @@ void GDScript::_update_doc() {
methods[i].return_val.class_name = _get_gdscript_reference_class_name(Object::cast_to<GDScript>(return_type.script_type));
}
- // Change class name if argumetn is script reference.
+ // Change class name if argument is script reference.
for (int j = 0; j < fn->get_argument_count(); j++) {
GDScriptDataType arg_type = fn->get_argument_type(j);
if (arg_type.kind == GDScriptDataType::GDSCRIPT) {
@@ -584,7 +584,7 @@ void GDScript::_update_doc() {
}
#endif
-bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) {
+bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderScriptInstance *p_instance_to_update) {
#ifdef TOOLS_ENABLED
static Vector<GDScript *> base_caches;
@@ -721,15 +721,19 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) {
}
}
- if (placeholders.size()) { //hm :(
+ if ((changed || p_instance_to_update) && placeholders.size()) { //hm :(
// update placeholders if any
Map<StringName, Variant> values;
List<PropertyInfo> propnames;
_update_exports_values(values, propnames);
- for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
- E->get()->update(propnames, values);
+ if (changed) {
+ for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ E->get()->update(propnames, values);
+ }
+ } else {
+ p_instance_to_update->update(propnames, values);
}
}
@@ -897,68 +901,10 @@ void GDScript::get_members(Set<StringName> *p_members) {
}
}
-Vector<ScriptNetData> GDScript::get_rpc_methods() const {
+const Vector<MultiplayerAPI::RPCConfig> GDScript::get_rpc_methods() const {
return rpc_functions;
}
-uint16_t GDScript::get_rpc_method_id(const StringName &p_method) const {
- for (int i = 0; i < rpc_functions.size(); i++) {
- if (rpc_functions[i].name == p_method) {
- return i;
- }
- }
- return UINT16_MAX;
-}
-
-StringName GDScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
- if (p_rpc_method_id >= rpc_functions.size()) {
- return StringName();
- }
- return rpc_functions[p_rpc_method_id].name;
-}
-
-MultiplayerAPI::RPCMode GDScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
- if (p_rpc_method_id >= rpc_functions.size()) {
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
- return rpc_functions[p_rpc_method_id].mode;
-}
-
-MultiplayerAPI::RPCMode GDScript::get_rpc_mode(const StringName &p_method) const {
- return get_rpc_mode_by_id(get_rpc_method_id(p_method));
-}
-
-Vector<ScriptNetData> GDScript::get_rset_properties() const {
- return rpc_variables;
-}
-
-uint16_t GDScript::get_rset_property_id(const StringName &p_variable) const {
- for (int i = 0; i < rpc_variables.size(); i++) {
- if (rpc_variables[i].name == p_variable) {
- return i;
- }
- }
- return UINT16_MAX;
-}
-
-StringName GDScript::get_rset_property(const uint16_t p_rset_member_id) const {
- if (p_rset_member_id >= rpc_variables.size()) {
- return StringName();
- }
- return rpc_variables[p_rset_member_id].name;
-}
-
-MultiplayerAPI::RPCMode GDScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
- if (p_rset_member_id >= rpc_variables.size()) {
- return MultiplayerAPI::RPC_MODE_DISABLED;
- }
- return rpc_variables[p_rset_member_id].mode;
-}
-
-MultiplayerAPI::RPCMode GDScript::get_rset_mode(const StringName &p_variable) const {
- return get_rset_mode_by_id(get_rset_property_id(p_variable));
-}
-
Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
GDScript *top = this;
while (top) {
@@ -1045,10 +991,10 @@ Error GDScript::load_source_code(const String &p_path) {
ERR_FAIL_COND_V(err, err);
}
- int len = f->get_len();
+ uint64_t len = f->get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
- int r = f->get_buffer(w, len);
+ uint64_t r = f->get_buffer(w, len);
f->close();
memdelete(f);
ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
@@ -1210,10 +1156,8 @@ 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;
@@ -1222,25 +1166,17 @@ void GDScript::_init_rpc_methods_properties() {
// 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;
+ MultiplayerAPI::RPCConfig nd;
nd.name = E->key();
- nd.mode = E->get()->get_rpc_mode();
+ nd.rpc_mode = E->get()->get_rpc_mode();
+ // TODO
+ nd.transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE;
+ nd.channel = 0;
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();
@@ -1254,8 +1190,7 @@ void GDScript::_init_rpc_methods_properties() {
}
// Sort so we are 100% that they are always the same.
- rpc_functions.sort_custom<SortNetData>();
- rpc_variables.sort_custom<SortNetData>();
+ rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>();
}
GDScript::~GDScript() {
@@ -1611,46 +1546,10 @@ ScriptLanguage *GDScriptInstance::get_language() {
return GDScriptLanguage::get_singleton();
}
-Vector<ScriptNetData> GDScriptInstance::get_rpc_methods() const {
+const Vector<MultiplayerAPI::RPCConfig> GDScriptInstance::get_rpc_methods() const {
return script->get_rpc_methods();
}
-uint16_t GDScriptInstance::get_rpc_method_id(const StringName &p_method) const {
- return script->get_rpc_method_id(p_method);
-}
-
-StringName GDScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const {
- return script->get_rpc_method(p_rpc_method_id);
-}
-
-MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
- return script->get_rpc_mode_by_id(p_rpc_method_id);
-}
-
-MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const {
- return script->get_rpc_mode(p_method);
-}
-
-Vector<ScriptNetData> GDScriptInstance::get_rset_properties() const {
- return script->get_rset_properties();
-}
-
-uint16_t GDScriptInstance::get_rset_property_id(const StringName &p_variable) const {
- return script->get_rset_property_id(p_variable);
-}
-
-StringName GDScriptInstance::get_rset_property(const uint16_t p_rset_member_id) const {
- return script->get_rset_property(p_rset_member_id);
-}
-
-MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
- return script->get_rset_mode_by_id(p_rset_member_id);
-}
-
-MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const {
- return script->get_rset_mode(p_variable);
-}
-
void GDScriptInstance::reload_members() {
#ifdef DEBUG_ENABLED
@@ -1681,7 +1580,7 @@ void GDScriptInstance::reload_members() {
GDScriptInstance::GDScriptInstance() {
owner = nullptr;
- base_ref = false;
+ base_ref_counted = false;
}
GDScriptInstance::~GDScriptInstance() {
@@ -2135,6 +2034,19 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
}
}
+bool GDScriptLanguage::is_control_flow_keyword(String p_keyword) const {
+ return p_keyword == "break" ||
+ p_keyword == "continue" ||
+ p_keyword == "elif" ||
+ p_keyword == "else" ||
+ p_keyword == "if" ||
+ p_keyword == "for" ||
+ p_keyword == "match" ||
+ p_keyword == "pass" ||
+ p_keyword == "return" ||
+ p_keyword == "while";
+}
+
bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
return p_type == "GDScript";
}
@@ -2156,7 +2068,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
if (err == OK) {
const GDScriptParser::ClassNode *c = parser.get_tree();
if (r_icon_path) {
- if (c->icon_path.is_empty() || c->icon_path.is_abs_path()) {
+ if (c->icon_path.is_empty() || c->icon_path.is_absolute_path()) {
*r_icon_path = c->icon_path;
} else if (c->icon_path.is_rel_path()) {
*r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path();
@@ -2224,7 +2136,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
break;
}
} else {
- *r_base_type = "Reference";
+ *r_base_type = "RefCounted";
subclass = nullptr;
}
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 12c909fd4f..602553bb1a 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -39,8 +39,8 @@
#include "core/object/script_language.h"
#include "gdscript_function.h"
-class GDScriptNativeClass : public Reference {
- GDCLASS(GDScriptNativeClass, Reference);
+class GDScriptNativeClass : public RefCounted {
+ GDCLASS(GDScriptNativeClass, RefCounted);
StringName name;
@@ -86,8 +86,7 @@ class GDScript : public Script {
Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script.
Map<StringName, Ref<GDScript>> subclasses;
Map<StringName, Vector<StringName>> _signals;
- Vector<ScriptNetData> rpc_functions;
- Vector<ScriptNetData> rpc_variables;
+ Vector<MultiplayerAPI::RPCConfig> rpc_functions;
#ifdef TOOLS_ENABLED
@@ -133,7 +132,7 @@ class GDScript : public Script {
SelfList<GDScriptFunctionState>::List pending_func_states;
void _super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error);
- GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error);
+ GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error);
void _set_subclass_path(Ref<GDScript> &p_sc, const String &p_path);
@@ -149,7 +148,7 @@ class GDScript : public Script {
#endif
- bool _update_exports(bool *r_err = nullptr, bool p_recursive_call = false);
+ bool _update_exports(bool *r_err = nullptr, bool p_recursive_call = false, PlaceHolderScriptInstance *p_instance_to_update = nullptr);
void _save_orphaned_subclasses();
void _init_rpc_methods_properties();
@@ -158,7 +157,7 @@ class GDScript : public Script {
void _get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const;
void _get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const;
- // This method will map the class name from "Reference" to "MyClass.InnerClass".
+ // This method will map the class name from "RefCounted" to "MyClass.InnerClass".
static String _get_gdscript_reference_class_name(const GDScript *p_gdscript);
protected:
@@ -247,17 +246,7 @@ public:
virtual void get_constants(Map<StringName, Variant> *p_constants) override;
virtual void get_members(Set<StringName> *p_members) override;
- virtual Vector<ScriptNetData> get_rpc_methods() const override;
- virtual uint16_t get_rpc_method_id(const StringName &p_method) const override;
- virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override;
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override;
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
-
- virtual Vector<ScriptNetData> get_rset_properties() const override;
- virtual uint16_t get_rset_property_id(const StringName &p_variable) const override;
- virtual StringName get_rset_property(const uint16_t p_variable_id) const override;
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override;
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
#ifdef TOOLS_ENABLED
virtual bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; }
@@ -270,6 +259,7 @@ public:
class GDScriptInstance : public ScriptInstance {
friend class GDScript;
friend class GDScriptFunction;
+ friend class GDScriptLambdaCallable;
friend class GDScriptCompiler;
friend struct GDScriptUtilityFunctionsDefinitions;
@@ -280,7 +270,7 @@ class GDScriptInstance : public ScriptInstance {
Map<StringName, int> member_indices_cache; //used only for hot script reloading
#endif
Vector<Variant> members;
- bool base_ref;
+ bool base_ref_counted;
SelfList<GDScriptFunctionState>::List pending_func_states;
@@ -309,17 +299,7 @@ public:
void reload_members();
- virtual Vector<ScriptNetData> get_rpc_methods() const;
- virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
- virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
-
- virtual Vector<ScriptNetData> get_rset_properties() const;
- virtual uint16_t get_rset_property_id(const StringName &p_variable) const;
- virtual StringName get_rset_property(const uint16_t p_variable_id) const;
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const;
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const;
GDScriptInstance();
~GDScriptInstance();
@@ -460,6 +440,7 @@ public:
/* EDITOR FUNCTIONS */
virtual void get_reserved_words(List<String> *p_words) const;
+ virtual bool is_control_flow_keyword(String p_keywords) const;
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual String _get_processed_template(const String &p_template, const String &p_base_class_name) const;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index bdca64c146..c3edc813d2 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -31,10 +31,10 @@
#include "gdscript_analyzer.h"
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/object/class_db.h"
#include "core/object/script_language.h"
-#include "core/os/file_access.h"
#include "core/templates/hash_map.h"
#include "gdscript.h"
#include "gdscript_utility_functions.h"
@@ -163,7 +163,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
if (!p_class->extends_used) {
result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
result.kind = GDScriptParser::DataType::NATIVE;
- result.native_type = "Reference";
+ result.native_type = "RefCounted";
} else {
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
@@ -543,6 +543,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
} else {
// TODO: Add warning.
mark_node_unsafe(member.variable->initializer);
+ member.variable->use_conversion_assign = true;
}
} else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) {
#ifdef DEBUG_ENABLED
@@ -552,6 +553,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
if (member.variable->initializer->get_datatype().is_variant()) {
// TODO: Warn unsafe assign.
mark_node_unsafe(member.variable->initializer);
+ member.variable->use_conversion_assign = true;
}
}
} else if (member.variable->infer_datatype) {
@@ -856,6 +858,7 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node) {
case GDScriptParser::Node::DICTIONARY:
case GDScriptParser::Node::GET_NODE:
case GDScriptParser::Node::IDENTIFIER:
+ case GDScriptParser::Node::LAMBDA:
case GDScriptParser::Node::LITERAL:
case GDScriptParser::Node::PRELOAD:
case GDScriptParser::Node::SELF:
@@ -1144,6 +1147,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
} else {
// TODO: Add warning.
mark_node_unsafe(p_variable->initializer);
+ p_variable->use_conversion_assign = true;
}
#ifdef DEBUG_ENABLED
} else if (type.builtin_type == Variant::INT && p_variable->initializer->get_datatype().builtin_type == Variant::FLOAT) {
@@ -1153,6 +1157,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
if (p_variable->initializer->get_datatype().is_variant()) {
// TODO: Warn unsafe assign.
mark_node_unsafe(p_variable->initializer);
+ p_variable->use_conversion_assign = true;
}
}
} else if (p_variable->infer_datatype) {
@@ -1458,6 +1463,9 @@ void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expre
case GDScriptParser::Node::IDENTIFIER:
reduce_identifier(static_cast<GDScriptParser::IdentifierNode *>(p_expression));
break;
+ case GDScriptParser::Node::LAMBDA:
+ reduce_lambda(static_cast<GDScriptParser::LambdaNode *>(p_expression));
+ break;
case GDScriptParser::Node::LITERAL:
reduce_literal(static_cast<GDScriptParser::LiteralNode *>(p_expression));
break;
@@ -1604,10 +1612,12 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
} else {
// TODO: Add warning.
mark_node_unsafe(p_assignment);
+ p_assignment->use_conversion_assign = true;
}
} else {
// TODO: Warning in this case.
mark_node_unsafe(p_assignment);
+ p_assignment->use_conversion_assign = true;
}
}
} else {
@@ -1617,6 +1627,9 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
if (assignee_type.has_no_type() || assigned_value_type.is_variant()) {
mark_node_unsafe(p_assignment);
+ if (assignee_type.is_hard_type()) {
+ p_assignment->use_conversion_assign = true;
+ }
}
if (p_assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) {
@@ -2055,12 +2068,20 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
if (p_call->is_super) {
base_type = parser->current_class->base_type;
+ base_type.is_meta_type = false;
is_self = true;
} else if (callee_type == GDScriptParser::Node::IDENTIFIER) {
base_type = parser->current_class->get_datatype();
+ base_type.is_meta_type = false;
is_self = true;
} else if (callee_type == GDScriptParser::Node::SUBSCRIPT) {
GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(p_call->callee);
+ if (subscript->base == nullptr) {
+ // Invalid syntax, error already set on parser.
+ p_call->set_datatype(call_type);
+ mark_node_unsafe(p_call);
+ return;
+ }
if (!subscript->is_attribute) {
// Invalid call. Error already sent in parser.
// TODO: Could check if Callable here.
@@ -2068,9 +2089,23 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
mark_node_unsafe(p_call);
return;
}
- reduce_expression(subscript->base);
+ if (subscript->attribute == nullptr) {
+ // Invalid call. Error already sent in parser.
+ p_call->set_datatype(call_type);
+ mark_node_unsafe(p_call);
+ return;
+ }
- base_type = subscript->base->get_datatype();
+ GDScriptParser::IdentifierNode *base_id = nullptr;
+ if (subscript->base->type == GDScriptParser::Node::IDENTIFIER) {
+ base_id = static_cast<GDScriptParser::IdentifierNode *>(subscript->base);
+ }
+ if (base_id && GDScriptParser::get_builtin_type(base_id->name) < Variant::VARIANT_MAX) {
+ base_type = make_builtin_meta_type(GDScriptParser::get_builtin_type(base_id->name));
+ } else {
+ reduce_expression(subscript->base);
+ base_type = subscript->base->get_datatype();
+ }
} else {
// Invalid call. Error already sent in parser.
// TODO: Could check if Callable here too.
@@ -2097,6 +2132,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) {
push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parser->current_function->identifier->name), p_call->callee);
+ } else if (is_self && !is_static && !lambda_stack.is_empty()) {
+ push_error(vformat(R"*(Cannot call non-static function "%s()" from a lambda function.)*", p_call->function_name), p_call->callee);
}
call_type = return_type;
@@ -2219,6 +2256,8 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
if (!ClassDB::is_parent_class(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), result.native_type)) {
push_error(R"*(Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.)*", p_get_node);
+ } else if (!lambda_stack.is_empty()) {
+ push_error(R"*(Cannot use shorthand "get_node()" notation ("$") inside a lambda. Use a captured variable instead.)*", p_get_node);
}
p_get_node->set_datatype(result);
@@ -2346,6 +2385,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
case GDScriptParser::ClassNode::Member::ENUM_VALUE:
p_identifier->is_constant = true;
p_identifier->reduced_value = member.enum_value.value;
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
break;
case GDScriptParser::ClassNode::Member::VARIABLE:
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_VARIABLE;
@@ -2446,42 +2486,65 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
}
}
+ bool found_source = false;
// Check if identifier is local.
// If that's the case, the declaration already was solved before.
switch (p_identifier->source) {
case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER:
p_identifier->set_datatype(p_identifier->parameter_source->get_datatype());
- return;
+ found_source = true;
+ break;
case GDScriptParser::IdentifierNode::LOCAL_CONSTANT:
case GDScriptParser::IdentifierNode::MEMBER_CONSTANT:
p_identifier->set_datatype(p_identifier->constant_source->get_datatype());
p_identifier->is_constant = true;
// TODO: Constant should have a value on the node itself.
p_identifier->reduced_value = p_identifier->constant_source->initializer->reduced_value;
- return;
+ found_source = true;
+ break;
case GDScriptParser::IdentifierNode::MEMBER_VARIABLE:
p_identifier->variable_source->usages++;
[[fallthrough]];
case GDScriptParser::IdentifierNode::LOCAL_VARIABLE:
p_identifier->set_datatype(p_identifier->variable_source->get_datatype());
- return;
+ found_source = true;
+ break;
case GDScriptParser::IdentifierNode::LOCAL_ITERATOR:
p_identifier->set_datatype(p_identifier->bind_source->get_datatype());
- return;
+ found_source = true;
+ break;
case GDScriptParser::IdentifierNode::LOCAL_BIND: {
GDScriptParser::DataType result = p_identifier->bind_source->get_datatype();
result.is_constant = true;
p_identifier->set_datatype(result);
- return;
- }
+ found_source = true;
+ } break;
case GDScriptParser::IdentifierNode::UNDEFINED_SOURCE:
break;
}
// Not a local, so check members.
- reduce_identifier_from_base(p_identifier);
- if (p_identifier->get_datatype().is_set()) {
- // Found.
+ if (!found_source) {
+ reduce_identifier_from_base(p_identifier);
+ if (p_identifier->source != GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->get_datatype().is_set()) {
+ // Found.
+ found_source = true;
+ }
+ }
+
+ if (found_source) {
+ // If the identifier is local, check if it's any kind of capture by comparing their source function.
+ // Only capture locals and members and enum values. Constants are still accessible from the lambda using the script reference.
+ if (p_identifier->source == GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_CONSTANT || lambda_stack.is_empty()) {
+ return;
+ }
+
+ GDScriptParser::FunctionNode *function_test = lambda_stack.back()->get()->function;
+ while (function_test != nullptr && function_test != p_identifier->source_function && function_test->source_lambda != nullptr && !function_test->source_lambda->captures_indices.has(p_identifier->name)) {
+ function_test->source_lambda->captures_indices[p_identifier->name] = function_test->source_lambda->captures.size();
+ function_test->source_lambda->captures.push_back(p_identifier);
+ function_test = function_test->source_lambda->parent_function;
+ }
return;
}
@@ -2563,6 +2626,57 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
p_identifier->set_datatype(dummy); // Just so type is set to something.
}
+void GDScriptAnalyzer::reduce_lambda(GDScriptParser::LambdaNode *p_lambda) {
+ // Lambda is always a Callable.
+ GDScriptParser::DataType lambda_type;
+ lambda_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
+ lambda_type.kind = GDScriptParser::DataType::BUILTIN;
+ lambda_type.builtin_type = Variant::CALLABLE;
+ p_lambda->set_datatype(lambda_type);
+
+ if (p_lambda->function == nullptr) {
+ return;
+ }
+
+ GDScriptParser::FunctionNode *previous_function = parser->current_function;
+ parser->current_function = p_lambda->function;
+
+ lambda_stack.push_back(p_lambda);
+
+ for (int i = 0; i < p_lambda->function->parameters.size(); i++) {
+ resolve_parameter(p_lambda->function->parameters[i]);
+ }
+
+ resolve_suite(p_lambda->function->body);
+
+ int captures_amount = p_lambda->captures.size();
+ if (captures_amount > 0) {
+ // Create space for lambda parameters.
+ // At the beginning to not mess with optional parameters.
+ int param_count = p_lambda->function->parameters.size();
+ p_lambda->function->parameters.resize(param_count + captures_amount);
+ for (int i = param_count - 1; i >= 0; i--) {
+ p_lambda->function->parameters.write[i + captures_amount] = p_lambda->function->parameters[i];
+ p_lambda->function->parameters_indices[p_lambda->function->parameters[i]->identifier->name] = i + captures_amount;
+ }
+
+ // Add captures as extra parameters at the beginning.
+ for (int i = 0; i < p_lambda->captures.size(); i++) {
+ GDScriptParser::IdentifierNode *capture = p_lambda->captures[i];
+ GDScriptParser::ParameterNode *capture_param = parser->alloc_node<GDScriptParser::ParameterNode>();
+ capture_param->identifier = capture;
+ capture_param->usages = capture->usages;
+ capture_param->set_datatype(capture->get_datatype());
+
+ p_lambda->function->parameters.write[i] = capture_param;
+ p_lambda->function->parameters_indices[capture->name] = i;
+ }
+ }
+
+ lambda_stack.pop_back();
+ parser->current_function = previous_function;
+}
+
void GDScriptAnalyzer::reduce_literal(GDScriptParser::LiteralNode *p_literal) {
p_literal->reduced_value = p_literal->value;
p_literal->is_constant = true;
@@ -2621,25 +2735,6 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
GDScriptParser::DataType result_type;
- // Reduce index first. If it's a constant StringName, use attribute instead.
- if (!p_subscript->is_attribute) {
- if (p_subscript->index == nullptr) {
- return;
- }
- reduce_expression(p_subscript->index);
-
- if (p_subscript->index->is_constant && p_subscript->index->reduced_value.get_type() == Variant::STRING_NAME) {
- GDScriptParser::IdentifierNode *attribute = parser->alloc_node<GDScriptParser::IdentifierNode>();
- // Copy location for better error message.
- attribute->start_line = p_subscript->index->start_line;
- attribute->end_line = p_subscript->index->end_line;
- attribute->leftmost_column = p_subscript->index->leftmost_column;
- attribute->rightmost_column = p_subscript->index->rightmost_column;
- p_subscript->is_attribute = true;
- p_subscript->attribute = attribute;
- }
- }
-
if (p_subscript->is_attribute) {
if (p_subscript->attribute == nullptr) {
return;
@@ -2682,7 +2777,10 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
}
}
} else {
- // Index was already reduced before.
+ if (p_subscript->index == nullptr) {
+ return;
+ }
+ reduce_expression(p_subscript->index);
if (p_subscript->base->is_constant && p_subscript->index->is_constant) {
// Just try to get it.
@@ -2727,7 +2825,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
case Variant::RECT2:
case Variant::RECT2I:
case Variant::PLANE:
- case Variant::QUAT:
+ case Variant::QUATERNION:
case Variant::AABB:
case Variant::OBJECT:
error = index_type.builtin_type != Variant::STRING;
@@ -2738,8 +2836,8 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
case Variant::VECTOR2I:
case Variant::VECTOR3:
case Variant::VECTOR3I:
- case Variant::TRANSFORM:
case Variant::TRANSFORM2D:
+ case Variant::TRANSFORM3D:
error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::FLOAT &&
index_type.builtin_type != Variant::STRING;
break;
@@ -2806,7 +2904,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
case Variant::PACKED_FLOAT64_ARRAY:
case Variant::VECTOR2:
case Variant::VECTOR3:
- case Variant::QUAT:
+ case Variant::QUATERNION:
result_type.builtin_type = Variant::FLOAT;
break;
// Return Color.
@@ -2835,7 +2933,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
result_type.builtin_type = Variant::VECTOR3;
break;
// Depends on the index.
- case Variant::TRANSFORM:
+ case Variant::TRANSFORM3D:
case Variant::PLANE:
case Variant::COLOR:
case Variant::DICTIONARY:
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 8430d3f4a5..8cd3fcf837 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -32,7 +32,7 @@
#define GDSCRIPT_ANALYZER_H
#include "core/object/object.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/templates/set.h"
#include "gdscript_cache.h"
#include "gdscript_parser.h"
@@ -42,6 +42,7 @@ class GDScriptAnalyzer {
HashMap<String, Ref<GDScriptParserRef>> depended_parsers;
const GDScriptParser::EnumNode *current_enum = nullptr;
+ List<const GDScriptParser::LambdaNode *> lambda_stack;
Error resolve_inheritance(GDScriptParser::ClassNode *p_class, bool p_recursive = true);
GDScriptParser::DataType resolve_datatype(GDScriptParser::TypeNode *p_type);
@@ -82,6 +83,7 @@ class GDScriptAnalyzer {
void reduce_get_node(GDScriptParser::GetNodeNode *p_get_node);
void reduce_identifier(GDScriptParser::IdentifierNode *p_identifier, bool can_be_builtin = false);
void reduce_identifier_from_base(GDScriptParser::IdentifierNode *p_identifier, GDScriptParser::DataType *p_base = nullptr);
+ void reduce_lambda(GDScriptParser::LambdaNode *p_lambda);
void reduce_literal(GDScriptParser::LiteralNode *p_literal);
void reduce_preload(GDScriptParser::PreloadNode *p_preload);
void reduce_self(GDScriptParser::SelfNode *p_self);
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 89c5f5482b..6998cc5bb7 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -85,10 +85,10 @@ uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type
case Variant::VECTOR3I:
case Variant::TRANSFORM2D:
case Variant::PLANE:
- case Variant::QUAT:
+ case Variant::QUATERNION:
case Variant::AABB:
case Variant::BASIS:
- case Variant::TRANSFORM:
+ case Variant::TRANSFORM3D:
case Variant::COLOR:
case Variant::STRING_NAME:
case Variant::NODE_PATH:
@@ -129,12 +129,6 @@ uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type
int idx = temporaries.size();
pool.push_back(idx);
temporaries.push_back(new_temp);
-
- // First time using this, so adjust to the proper type.
- if (temp_type != Variant::NIL) {
- Address addr(Address::TEMPORARY, idx, p_type);
- write_type_adjust(addr, temp_type);
- }
}
int slot = pool.front()->get();
pool.pop_front();
@@ -189,8 +183,12 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
append(GDScriptFunction::OPCODE_END, 0);
for (int i = 0; i < temporaries.size(); i++) {
+ int stack_index = i + max_locals + RESERVED_STACK;
for (int j = 0; j < temporaries[i].bytecode_indices.size(); j++) {
- opcodes.write[temporaries[i].bytecode_indices[j]] = (i + max_locals + RESERVED_STACK) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
+ opcodes.write[temporaries[i].bytecode_indices[j]] = stack_index | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
+ }
+ if (temporaries[i].type != Variant::NIL) {
+ function->temporary_slots[stack_index] = temporaries[i].type;
}
}
@@ -383,6 +381,18 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->_methods_count = 0;
}
+ if (lambdas_map.size()) {
+ function->lambdas.resize(lambdas_map.size());
+ function->_lambdas_ptr = function->lambdas.ptrw();
+ function->_lambdas_count = lambdas_map.size();
+ for (const Map<GDScriptFunction *, int>::Element *E = lambdas_map.front(); E; E = E->next()) {
+ function->lambdas.write[E->get()] = E->key();
+ }
+ } else {
+ function->_lambdas_ptr = nullptr;
+ function->_lambdas_count = 0;
+ }
+
if (debug_stack) {
function->stack_debug = stack_debug;
}
@@ -448,8 +458,8 @@ void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Varia
case Variant::PLANE:
append(GDScriptFunction::OPCODE_TYPE_ADJUST_PLANE, 1);
break;
- case Variant::QUAT:
- append(GDScriptFunction::OPCODE_TYPE_ADJUST_QUAT, 1);
+ case Variant::QUATERNION:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_QUATERNION, 1);
break;
case Variant::AABB:
append(GDScriptFunction::OPCODE_TYPE_ADJUST_AABB, 1);
@@ -457,7 +467,7 @@ void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Varia
case Variant::BASIS:
append(GDScriptFunction::OPCODE_TYPE_ADJUST_BASIS, 1);
break;
- case Variant::TRANSFORM:
+ case Variant::TRANSFORM3D:
append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM, 1);
break;
case Variant::COLOR:
@@ -769,63 +779,43 @@ void GDScriptByteCodeGenerator::write_get_member(const Address &p_target, const
append(p_name);
}
-void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) {
- if (p_target.type.has_type && !p_source.type.has_type) {
- // Typed assignment.
- switch (p_target.type.kind) {
- case GDScriptDataType::BUILTIN: {
- if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) {
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY, 2);
- append(p_target);
- append(p_source);
- } else {
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
- append(p_target);
- append(p_source);
- append(p_target.type.builtin_type);
- }
- } break;
- case GDScriptDataType::NATIVE: {
- int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type];
- Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
- class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE, 3);
- append(p_target);
- append(p_source);
- append(class_idx);
- } break;
- case GDScriptDataType::SCRIPT:
- case GDScriptDataType::GDSCRIPT: {
- Variant script = p_target.type.script_type;
- int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
-
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT, 3);
+void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_target, const Address &p_source) {
+ switch (p_target.type.kind) {
+ case GDScriptDataType::BUILTIN: {
+ if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) {
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY, 2);
append(p_target);
append(p_source);
- append(idx);
- } break;
- default: {
- ERR_PRINT("Compiler bug: unresolved assign.");
-
- // Shouldn't get here, but fail-safe to a regular assignment
- append(GDScriptFunction::OPCODE_ASSIGN, 2);
+ } else {
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
append(p_target);
append(p_source);
+ append(p_target.type.builtin_type);
}
- }
- } else {
- if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) {
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY, 2);
+ } break;
+ case GDScriptDataType::NATIVE: {
+ int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type];
+ Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
+ class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE, 3);
append(p_target);
append(p_source);
- } else if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) {
- // Need conversion..
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
+ append(class_idx);
+ } break;
+ case GDScriptDataType::SCRIPT:
+ case GDScriptDataType::GDSCRIPT: {
+ Variant script = p_target.type.script_type;
+ int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
+
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT, 3);
append(p_target);
append(p_source);
- append(p_target.type.builtin_type);
- } else {
- // Either untyped assignment or already type-checked by the parser
+ append(idx);
+ } break;
+ default: {
+ ERR_PRINT("Compiler bug: unresolved assign.");
+
+ // Shouldn't get here, but fail-safe to a regular assignment
append(GDScriptFunction::OPCODE_ASSIGN, 2);
append(p_target);
append(p_source);
@@ -833,6 +823,24 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
}
}
+void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) {
+ if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) {
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY, 2);
+ append(p_target);
+ append(p_source);
+ } else if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) {
+ // Need conversion.
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
+ append(p_target);
+ append(p_source);
+ append(p_target.type.builtin_type);
+ } else {
+ append(GDScriptFunction::OPCODE_ASSIGN, 2);
+ append(p_target);
+ append(p_source);
+ }
+}
+
void GDScriptByteCodeGenerator::write_assign_true(const Address &p_target) {
append(GDScriptFunction::OPCODE_ASSIGN_TRUE, 1);
append(p_target);
@@ -1005,6 +1013,56 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target,
append(Variant::get_validated_builtin_method(p_type, p_method));
}
+void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) {
+ bool is_validated = false;
+
+ // Check if all types are correct.
+ if (Variant::is_builtin_method_vararg(p_type, p_method)) {
+ is_validated = true; // Vararg works fine with any argument, since they can be any type.
+ } else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) {
+ bool all_types_exact = true;
+ for (int i = 0; i < p_arguments.size(); i++) {
+ if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_builtin_method_argument_type(p_type, p_method, i))) {
+ all_types_exact = false;
+ break;
+ }
+ }
+
+ is_validated = all_types_exact;
+ }
+
+ if (!is_validated) {
+ // Perform regular call.
+ append(GDScriptFunction::OPCODE_CALL_BUILTIN_STATIC, p_arguments.size() + 1);
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ append(p_type);
+ append(p_method);
+ append(p_arguments.size());
+ return;
+ }
+
+ if (p_target.mode == Address::TEMPORARY) {
+ Variant::Type result_type = Variant::get_builtin_method_return_type(p_type, p_method);
+ Variant::Type temp_type = temporaries[p_target.address].type;
+ if (result_type != temp_type) {
+ write_type_adjust(p_target, result_type);
+ }
+ }
+
+ append(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size());
+
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(Address()); // No base since it's static.
+ append(p_target);
+ append(p_arguments.size());
+ append(Variant::get_validated_builtin_method(p_type, p_method));
+}
+
void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {
append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
@@ -1042,12 +1100,12 @@ void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, cons
CASE_TYPE(PLANE);
CASE_TYPE(AABB);
CASE_TYPE(BASIS);
- CASE_TYPE(TRANSFORM);
+ CASE_TYPE(TRANSFORM3D);
CASE_TYPE(COLOR);
CASE_TYPE(STRING_NAME);
CASE_TYPE(NODE_PATH);
CASE_TYPE(RID);
- CASE_TYPE(QUAT);
+ CASE_TYPE(QUATERNION);
CASE_TYPE(OBJECT);
CASE_TYPE(CALLABLE);
CASE_TYPE(SIGNAL);
@@ -1118,6 +1176,17 @@ void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_targ
append(p_function_name);
}
+void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) {
+ append(GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size());
+ for (int i = 0; i < p_captures.size(); i++) {
+ append(p_captures[i]);
+ }
+
+ append(p_target);
+ append(p_captures.size());
+ append(p_function);
+}
+
void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) {
// Try to find an appropriate constructor.
bool all_have_type = true;
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index 17d681d7bb..b1f3cd5fb3 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -93,6 +93,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
Map<Variant::ValidatedUtilityFunction, int> utilities_map;
Map<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map;
Map<MethodBind *, int> method_bind_map;
+ Map<GDScriptFunction *, int> lambdas_map;
// Lists since these can be nested.
List<int> if_jmp_addrs;
@@ -293,6 +294,15 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return pos;
}
+ int get_lambda_function_pos(GDScriptFunction *p_lambda_function) {
+ if (lambdas_map.has(p_lambda_function)) {
+ return lambdas_map[p_lambda_function];
+ }
+ int pos = lambdas_map.size();
+ lambdas_map[p_lambda_function] = pos;
+ return pos;
+ }
+
void alloc_ptrcall(int p_params) {
if (p_params >= ptrcall_max) {
ptrcall_max = p_params;
@@ -386,6 +396,10 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
opcodes.push_back(get_method_bind_pos(p_method));
}
+ void append(GDScriptFunction *p_lambda_function) {
+ opcodes.push_back(get_lambda_function_pos(p_lambda_function));
+ }
+
void patch_jump(int p_address) {
opcodes.write[p_address] = opcodes.size();
}
@@ -436,6 +450,7 @@ public:
virtual void write_set_member(const Address &p_value, const StringName &p_name) override;
virtual void write_get_member(const Address &p_target, const StringName &p_name) override;
virtual void write_assign(const Address &p_target, const Address &p_source) override;
+ virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) override;
virtual void write_assign_true(const Address &p_target) override;
virtual void write_assign_false(const Address &p_target) override;
virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override;
@@ -447,11 +462,13 @@ public:
virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) override;
virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) override;
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
+ virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
+ virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) override;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) override;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) override;
virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) override;
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index 113d36be98..a3b1fb93f9 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -30,7 +30,7 @@
#include "gdscript_cache.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/templates/vector.h"
#include "gdscript.h"
#include "gdscript_analyzer.h"
@@ -153,9 +153,9 @@ String GDScriptCache::get_source_code(const String &p_path) {
ERR_FAIL_COND_V(err, "");
}
- int len = f->get_len();
+ uint64_t len = f->get_length();
source_file.resize(len + 1);
- int r = f->get_buffer(source_file.ptrw(), len);
+ uint64_t r = f->get_buffer(source_file.ptrw(), len);
f->close();
ERR_FAIL_COND_V(r != len, "");
source_file.write[len] = 0;
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index d1d2a2abbf..943638d29f 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -31,7 +31,7 @@
#ifndef GDSCRIPT_CACHE_H
#define GDSCRIPT_CACHE_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/os/mutex.h"
#include "core/templates/hash_map.h"
#include "core/templates/set.h"
@@ -40,7 +40,7 @@
class GDScriptAnalyzer;
class GDScriptParser;
-class GDScriptParserRef : public Reference {
+class GDScriptParserRef : public RefCounted {
public:
enum Status {
EMPTY,
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index b377beefdb..cac6544f03 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -111,6 +111,7 @@ public:
virtual void write_set_member(const Address &p_value, const StringName &p_name) = 0;
virtual void write_get_member(const Address &p_target, const StringName &p_name) = 0;
virtual void write_assign(const Address &p_target, const Address &p_source) = 0;
+ virtual void write_assign_with_conversion(const Address &p_target, const Address &p_source) = 0;
virtual void write_assign_true(const Address &p_target) = 0;
virtual void write_assign_false(const Address &p_target) = 0;
virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0;
@@ -122,11 +123,13 @@ public:
virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) = 0;
virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) = 0;
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
+ virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) = 0;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 7429e3cc0b..6d6b9e15af 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -427,8 +427,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
break;
case GDScriptParser::DictionaryNode::LUA_TABLE:
- // Lua-style: key is an identifier interpreted as string.
- String key = static_cast<const GDScriptParser::IdentifierNode *>(dn->elements[i].key)->name;
+ // Lua-style: key is an identifier interpreted as StringName.
+ StringName key = static_cast<const GDScriptParser::IdentifierNode *>(dn->elements[i].key)->name;
element = codegen.add_constant(key);
break;
}
@@ -537,39 +537,44 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
if (subscript->is_attribute) {
- GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
- if (r_error) {
- return GDScriptCodeGenerator::Address();
- }
- if (within_await) {
- gen->write_call_async(result, base, call->function_name, arguments);
- } else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) {
- // Native method, use faster path.
- StringName class_name;
- if (base.type.kind == GDScriptDataType::NATIVE) {
- class_name = base.type.native_type;
- } else {
- class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type;
+ // May be static built-in method call.
+ if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) {
+ gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments);
+ } else {
+ GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
- if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) {
- MethodBind *method = ClassDB::get_method(class_name, call->function_name);
- if (_have_exact_arguments(method, arguments)) {
- // Exact arguments, use ptrcall.
- gen->write_call_ptrcall(result, base, method, arguments);
+ if (within_await) {
+ gen->write_call_async(result, base, call->function_name, arguments);
+ } else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) {
+ // Native method, use faster path.
+ StringName class_name;
+ if (base.type.kind == GDScriptDataType::NATIVE) {
+ class_name = base.type.native_type;
} else {
- // Not exact arguments, but still can use method bind call.
- gen->write_call_method_bind(result, base, method, arguments);
+ class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type;
}
+ if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) {
+ MethodBind *method = ClassDB::get_method(class_name, call->function_name);
+ if (_have_exact_arguments(method, arguments)) {
+ // Exact arguments, use ptrcall.
+ gen->write_call_ptrcall(result, base, method, arguments);
+ } else {
+ // Not exact arguments, but still can use method bind call.
+ gen->write_call_method_bind(result, base, method, arguments);
+ }
+ } else {
+ gen->write_call(result, base, call->function_name, arguments);
+ }
+ } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) {
+ gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments);
} else {
gen->write_call(result, base, call->function_name, arguments);
}
- } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) {
- gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments);
- } else {
- gen->write_call(result, base, call->function_name, arguments);
- }
- if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
}
} else {
_set_error("Cannot call something that isn't a function.", call->callee);
@@ -680,9 +685,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
name = subscript->attribute->name;
named = true;
} else {
- if (subscript->index->type == GDScriptParser::Node::LITERAL && static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value.get_type() == Variant::STRING) {
+ if (subscript->index->is_constant && subscript->index->reduced_value.get_type() == Variant::STRING_NAME) {
// Also, somehow, named (speed up anyway).
- name = static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value;
+ name = subscript->index->reduced_value;
named = true;
} else {
// Regular indexing.
@@ -966,6 +971,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} else {
gen->write_set(prev_base, key, assigned);
}
+ if (key.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
}
@@ -1076,7 +1084,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), setter_function, args);
} else {
// Just assign.
- gen->write_assign(target, op_result);
+ if (assignment->use_conversion_assign) {
+ gen->write_assign_with_conversion(target, op_result);
+ } else {
+ gen->write_assign(target, op_result);
+ }
}
if (op_result.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -1091,6 +1103,34 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
return GDScriptCodeGenerator::Address(); // Assignment does not return a value.
} break;
+ case GDScriptParser::Node::LAMBDA: {
+ const GDScriptParser::LambdaNode *lambda = static_cast<const GDScriptParser::LambdaNode *>(p_expression);
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(lambda->get_datatype()));
+
+ Vector<GDScriptCodeGenerator::Address> captures;
+ captures.resize(lambda->captures.size());
+ for (int i = 0; i < lambda->captures.size(); i++) {
+ captures.write[i] = _parse_expression(codegen, r_error, lambda->captures[i]);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+ }
+
+ GDScriptFunction *function = _parse_function(r_error, codegen.script, codegen.class_node, lambda->function, false, true);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+
+ gen->write_lambda(result, function, captures);
+
+ for (int i = 0; i < captures.size(); i++) {
+ if (captures[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ }
+
+ return result;
+ } break;
default: {
ERR_FAIL_V_MSG(GDScriptCodeGenerator::Address(), "Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); // Unreachable code.
} break;
@@ -1756,7 +1796,11 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
if (error) {
return error;
}
- gen->write_assign(local, src_address);
+ if (lv->use_conversion_assign) {
+ gen->write_assign_with_conversion(local, src_address);
+ } else {
+ gen->write_assign(local, src_address);
+ }
if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
@@ -1804,8 +1848,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
return OK;
}
-Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready) {
- Error error = OK;
+GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready, bool p_for_lambda) {
+ r_error = OK;
CodeGen codegen;
codegen.generator = memnew(GDScriptByteCodeGenerator);
@@ -1822,7 +1866,11 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
return_type.builtin_type = Variant::NIL;
if (p_func) {
- func_name = p_func->identifier->name;
+ if (p_func->identifier) {
+ func_name = p_func->identifier->name;
+ } else {
+ func_name = "<anonymous lambda>";
+ }
is_static = p_func->is_static;
rpc_mode = p_func->rpc_mode;
return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script);
@@ -1853,11 +1901,11 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
}
// Parse initializer if applies.
- bool is_implicit_initializer = !p_for_ready && !p_func;
- bool is_initializer = p_func && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init;
- bool is_for_ready = p_for_ready || (p_func && String(p_func->identifier->name) == "_ready");
+ bool is_implicit_initializer = !p_for_ready && !p_func && !p_for_lambda;
+ bool is_initializer = p_func && !p_for_lambda && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init;
+ bool is_for_ready = p_for_ready || (p_func && !p_for_lambda && String(p_func->identifier->name) == "_ready");
- if (is_implicit_initializer || is_for_ready) {
+ if (!p_for_lambda && (is_implicit_initializer || is_for_ready)) {
// Initialize class fields.
for (int i = 0; i < p_class->members.size(); i++) {
if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) {
@@ -1884,13 +1932,17 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
codegen.generator->write_construct_array(dst_address, Vector<GDScriptCodeGenerator::Address>());
}
}
- GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, field->initializer, false, true);
- if (error) {
+ GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, r_error, field->initializer, false, true);
+ if (r_error) {
memdelete(codegen.generator);
- return error;
+ return nullptr;
}
- codegen.generator->write_assign(dst_address, src_address);
+ if (field->use_conversion_assign) {
+ codegen.generator->write_assign_with_conversion(dst_address, src_address);
+ } else {
+ codegen.generator->write_assign(dst_address, src_address);
+ }
if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
@@ -1914,10 +1966,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
codegen.generator->start_parameters();
for (int i = p_func->parameters.size() - optional_parameters; i < p_func->parameters.size(); i++) {
const GDScriptParser::ParameterNode *parameter = p_func->parameters[i];
- GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, error, parameter->default_value, true);
- if (error) {
+ GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value, true);
+ if (r_error) {
memdelete(codegen.generator);
- return error;
+ return nullptr;
}
GDScriptCodeGenerator::Address dst_addr = codegen.parameters[parameter->identifier->name];
codegen.generator->write_assign_default_parameter(dst_addr, src_addr);
@@ -1928,10 +1980,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
codegen.generator->end_parameters();
}
- Error err = _parse_block(codegen, p_func->body);
- if (err) {
+ r_error = _parse_block(codegen, p_func->body);
+ if (r_error) {
memdelete(codegen.generator);
- return err;
+ return nullptr;
}
}
@@ -1957,6 +2009,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
signature += "::" + String(func_name);
}
+ if (p_for_lambda) {
+ signature += "(lambda)";
+ }
+
codegen.generator->set_signature(signature);
}
#endif
@@ -1964,8 +2020,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
if (p_func) {
codegen.generator->set_initial_line(p_func->start_line);
#ifdef TOOLS_ENABLED
- p_script->member_lines[func_name] = p_func->start_line;
- p_script->doc_functions[func_name] = p_func->doc_description;
+ if (!p_for_lambda) {
+ p_script->member_lines[func_name] = p_func->start_line;
+ p_script->doc_functions[func_name] = p_func->doc_description;
+ }
#endif
} else {
codegen.generator->set_initial_line(0);
@@ -1994,11 +2052,13 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
#endif
}
- p_script->member_functions[func_name] = gd_function;
+ if (!p_for_lambda) {
+ p_script->member_functions[func_name] = gd_function;
+ }
memdelete(codegen.generator);
- return OK;
+ return gd_function;
}
Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) {
@@ -2163,7 +2223,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
if (err) {
return err;
}
- if (base.is_null() && !base->is_valid()) {
+ if (base.is_null() || !base->is_valid()) {
return ERR_COMPILATION_FAILED;
}
}
@@ -2222,9 +2282,10 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
}
prop_info.hint = export_info.hint;
prop_info.hint_string = export_info.hint_string;
- prop_info.usage = export_info.usage;
+ prop_info.usage = export_info.usage | PROPERTY_USAGE_SCRIPT_VARIABLE;
+ } else {
+ prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE;
}
- prop_info.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
#ifdef TOOLS_ENABLED
p_script->doc_variables[name] = variable->doc_description;
#endif
@@ -2391,7 +2452,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
if (!has_ready && function->identifier->name == "_ready") {
has_ready = true;
}
- Error err = _parse_function(p_script, p_class, function);
+ Error err = OK;
+ _parse_function(err, p_script, p_class, function);
if (err) {
return err;
}
@@ -2416,7 +2478,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
{
// Create an implicit constructor in any case.
- Error err = _parse_function(p_script, p_class, nullptr);
+ Error err = OK;
+ _parse_function(err, p_script, p_class, nullptr);
if (err) {
return err;
}
@@ -2424,7 +2487,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
if (!has_ready && p_class->onready_used) {
//create a _ready constructor
- Error err = _parse_function(p_script, p_class, nullptr, true);
+ Error err = OK;
+ _parse_function(err, p_script, p_class, nullptr, true);
if (err) {
return err;
}
@@ -2448,7 +2512,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
p_script->placeholders.erase(psi); //remove placeholder
GDScriptInstance *instance = memnew(GDScriptInstance);
- instance->base_ref = Object::cast_to<Reference>(E->get());
+ instance->base_ref_counted = Object::cast_to<RefCounted>(E->get());
instance->members.resize(p_script->member_indices.size());
instance->script = Ref<GDScript>(p_script);
instance->owner = E->get();
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index c405eadb07..7d5bee93ac 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -128,7 +128,7 @@ class GDScriptCompiler {
GDScriptCodeGenerator::Address _parse_match_pattern(CodeGen &codegen, Error &r_error, const GDScriptParser::PatternNode *p_pattern, const GDScriptCodeGenerator::Address &p_value_addr, const GDScriptCodeGenerator::Address &p_type_addr, const GDScriptCodeGenerator::Address &p_previous_test, bool p_is_first, bool p_is_nested);
void _add_locals_in_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block);
Error _parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, bool p_add_locals = true);
- Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false);
+ GDScriptFunction *_parse_function(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false, bool p_for_lambda = false);
Error _parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter);
Error _parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 0d0afcc741..1acb9ceddc 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -397,7 +397,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += DADDR(1 + argc);
text += " = ";
- text += "<unkown type>(";
+ text += "<unknown type>(";
for (int i = 0; i < argc; i++) {
if (i > 0) {
text += ", ";
@@ -542,6 +542,28 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 5 + argc;
} break;
+ case OPCODE_CALL_BUILTIN_STATIC: {
+ Variant::Type type = (Variant::Type)_code_ptr[ip + 1 + instr_var_args];
+ int argc = _code_ptr[ip + 3 + instr_var_args];
+
+ text += "call built-in method static ";
+ text += DADDR(1 + argc);
+ text += " = ";
+ text += Variant::get_type_name(type);
+ text += ".";
+ text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]].operator String();
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0) {
+ text += ", ";
+ }
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr += 5 + argc;
+ } break;
case OPCODE_CALL_PTRCALL_NO_RETURN: {
text += "call-ptrcall (no return) ";
@@ -598,12 +620,12 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
DISASSEMBLE_PTRCALL(PLANE);
DISASSEMBLE_PTRCALL(AABB);
DISASSEMBLE_PTRCALL(BASIS);
- DISASSEMBLE_PTRCALL(TRANSFORM);
+ DISASSEMBLE_PTRCALL(TRANSFORM3D);
DISASSEMBLE_PTRCALL(COLOR);
DISASSEMBLE_PTRCALL(STRING_NAME);
DISASSEMBLE_PTRCALL(NODE_PATH);
DISASSEMBLE_PTRCALL(RID);
- DISASSEMBLE_PTRCALL(QUAT);
+ DISASSEMBLE_PTRCALL(QUATERNION);
DISASSEMBLE_PTRCALL(OBJECT);
DISASSEMBLE_PTRCALL(CALLABLE);
DISASSEMBLE_PTRCALL(SIGNAL);
@@ -666,7 +688,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
int argc = _code_ptr[ip + 1 + instr_var_args];
text += DADDR(1 + argc) + " = ";
- text += "<unkown function>";
+ text += "<unknown function>";
text += "(";
for (int i = 0; i < argc; i++) {
@@ -721,7 +743,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "await ";
text += DADDR(1);
- incr += 2;
+ incr = 2;
} break;
case OPCODE_AWAIT_RESUME: {
text += "await resume ";
@@ -729,6 +751,25 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 2;
} break;
+ case OPCODE_CREATE_LAMBDA: {
+ int captures_count = _code_ptr[ip + 1 + instr_var_args];
+ GDScriptFunction *lambda = _lambdas_ptr[_code_ptr[ip + 2 + instr_var_args]];
+
+ text += DADDR(1 + captures_count);
+ text += "create lambda from ";
+ text += lambda->name.operator String();
+ text += "function, captures (";
+
+ for (int i = 0; i < captures_count; i++) {
+ if (i > 0) {
+ text += ", ";
+ }
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 3 + captures_count;
+ } break;
case OPCODE_JUMP: {
text += "jump ";
text += itos(_code_ptr[ip + 1]);
@@ -916,7 +957,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
DISASSEMBLE_TYPE_ADJUST(VECTOR3I);
DISASSEMBLE_TYPE_ADJUST(TRANSFORM2D);
DISASSEMBLE_TYPE_ADJUST(PLANE);
- DISASSEMBLE_TYPE_ADJUST(QUAT);
+ DISASSEMBLE_TYPE_ADJUST(QUATERNION);
DISASSEMBLE_TYPE_ADJUST(AABB);
DISASSEMBLE_TYPE_ADJUST(BASIS);
DISASSEMBLE_TYPE_ADJUST(TRANSFORM);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index ae3b16a9d7..18b7810919 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -32,7 +32,7 @@
#include "core/config/engine.h"
#include "core/core_constants.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "gdscript_analyzer.h"
#include "gdscript_compiler.h"
#include "gdscript_parser.h"
@@ -738,7 +738,13 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, Map<String, ScriptCodeCompletionOption> &r_result) {
for (int i = 0; i < p_suite->locals.size(); i++) {
- ScriptCodeCompletionOption option(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_VARIABLE);
+ ScriptCodeCompletionOption option;
+ if (p_suite->locals[i].type == GDScriptParser::SuiteNode::Local::CONSTANT) {
+ option = ScriptCodeCompletionOption(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_CONSTANT);
+ option.default_value = p_suite->locals[i].constant->initializer->reduced_value;
+ } else {
+ option = ScriptCodeCompletionOption(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_VARIABLE);
+ }
r_result.insert(option.display, option);
}
if (p_suite->parent_block) {
@@ -1023,7 +1029,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
}
static const char *_type_names[Variant::VARIANT_MAX] = {
- "null", "bool", "int", "float", "String", "StringName", "Vector2", "Vector2i", "Rect2", "Rect2i", "Vector3", "Vector3i", "Transform2D", "Plane", "Quat", "AABB", "Basis", "Transform",
+ "null", "bool", "int", "float", "String", "StringName", "Vector2", "Vector2i", "Rect2", "Rect2i", "Vector3", "Vector3i", "Transform2D", "Plane", "Quaternion", "AABB", "Basis", "Transform3D",
"Color", "NodePath", "RID", "Signal", "Callable", "Object", "Dictionary", "Array", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "PackedFloat32Array", "PackedFloat64Array", "PackedStringArray",
"PackedVector2Array", "PackedVector3Array", "PackedColorArray"
};
@@ -2867,7 +2873,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
StringName parent = ClassDB::get_parent_class(class_name);
if (parent != StringName()) {
if (String(parent).begins_with("_")) {
- base_type.native_type = String(parent).right(1);
+ base_type.native_type = String(parent).substr(1);
} else {
base_type.native_type = parent;
}
@@ -2993,6 +2999,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol
is_function = true;
[[fallthrough]];
}
+ case GDScriptParser::COMPLETION_CALL_ARGUMENTS:
case GDScriptParser::COMPLETION_IDENTIFIER: {
GDScriptParser::DataType base_type;
if (context.current_class) {
@@ -3060,7 +3067,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol
// proxy class remove the underscore.
if (r_result.class_name.begins_with("_")) {
- r_result.class_name = r_result.class_name.right(1);
+ r_result.class_name = r_result.class_name.substr(1);
}
return OK;
}
@@ -3070,7 +3077,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 7b37aa40a2..78399114a5 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -150,6 +150,10 @@ GDScriptFunction::GDScriptFunction() {
}
GDScriptFunction::~GDScriptFunction() {
+ for (int i = 0; i < lambdas.size(); i++) {
+ memdelete(lambdas[i]);
+ }
+
#ifdef DEBUG_ENABLED
MutexLock lock(GDScriptLanguage::get_singleton()->lock);
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index fbec734a28..553c2ecc01 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -31,7 +31,7 @@
#ifndef GDSCRIPT_FUNCTION_H
#define GDSCRIPT_FUNCTION_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
#include "core/os/thread.h"
#include "core/string/string_name.h"
@@ -263,6 +263,7 @@ public:
OPCODE_CALL_SELF_BASE,
OPCODE_CALL_METHOD_BIND,
OPCODE_CALL_METHOD_BIND_RET,
+ OPCODE_CALL_BUILTIN_STATIC,
// ptrcall have one instruction per return type.
OPCODE_CALL_PTRCALL_NO_RETURN,
OPCODE_CALL_PTRCALL_BOOL,
@@ -277,10 +278,10 @@ public:
OPCODE_CALL_PTRCALL_VECTOR3I,
OPCODE_CALL_PTRCALL_TRANSFORM2D,
OPCODE_CALL_PTRCALL_PLANE,
- OPCODE_CALL_PTRCALL_QUAT,
+ OPCODE_CALL_PTRCALL_QUATERNION,
OPCODE_CALL_PTRCALL_AABB,
OPCODE_CALL_PTRCALL_BASIS,
- OPCODE_CALL_PTRCALL_TRANSFORM,
+ OPCODE_CALL_PTRCALL_TRANSFORM3D,
OPCODE_CALL_PTRCALL_COLOR,
OPCODE_CALL_PTRCALL_STRING_NAME,
OPCODE_CALL_PTRCALL_NODE_PATH,
@@ -301,6 +302,7 @@ public:
OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY,
OPCODE_AWAIT,
OPCODE_AWAIT_RESUME,
+ OPCODE_CREATE_LAMBDA,
OPCODE_JUMP,
OPCODE_JUMP_IF,
OPCODE_JUMP_IF_NOT,
@@ -363,7 +365,7 @@ public:
OPCODE_TYPE_ADJUST_VECTOR3I,
OPCODE_TYPE_ADJUST_TRANSFORM2D,
OPCODE_TYPE_ADJUST_PLANE,
- OPCODE_TYPE_ADJUST_QUAT,
+ OPCODE_TYPE_ADJUST_QUATERNION,
OPCODE_TYPE_ADJUST_AABB,
OPCODE_TYPE_ADJUST_BASIS,
OPCODE_TYPE_ADJUST_TRANSFORM,
@@ -459,6 +461,8 @@ private:
const GDScriptUtilityFunctions::FunctionPtr *_gds_utilities_ptr = nullptr;
int _methods_count = 0;
MethodBind **_methods_ptr = nullptr;
+ int _lambdas_count = 0;
+ GDScriptFunction **_lambdas_ptr = nullptr;
const int *_code_ptr = nullptr;
int _code_size = 0;
int _argument_count = 0;
@@ -488,10 +492,13 @@ private:
Vector<Variant::ValidatedUtilityFunction> utilities;
Vector<GDScriptUtilityFunctions::FunctionPtr> gds_utilities;
Vector<MethodBind *> methods;
+ Vector<GDScriptFunction *> lambdas;
Vector<int> code;
Vector<GDScriptDataType> argument_types;
GDScriptDataType return_type;
+ Map<int, Variant::Type> temporary_slots;
+
#ifdef TOOLS_ENABLED
Vector<StringName> arg_names;
Vector<Variant> default_arg_values;
@@ -590,8 +597,8 @@ public:
~GDScriptFunction();
};
-class GDScriptFunctionState : public Reference {
- GDCLASS(GDScriptFunctionState, Reference);
+class GDScriptFunctionState : public RefCounted {
+ GDCLASS(GDScriptFunctionState, RefCounted);
friend class GDScriptFunction;
GDScriptFunction *function = nullptr;
GDScriptFunction::CallState state;
diff --git a/platform/javascript/javascript_eval.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
index cb19dd20d4..0bc109b6e1 100644
--- a/platform/javascript/javascript_eval.cpp
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* javascript_eval.cpp */
+/* gdscript_lambda_callable.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,52 +28,68 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef JAVASCRIPT_EVAL_ENABLED
+#include "gdscript_lambda_callable.h"
-#include "api/javascript_eval.h"
-#include "emscripten.h"
+#include "core/templates/hashfuncs.h"
+#include "gdscript.h"
-extern "C" {
-union js_eval_ret {
- uint32_t b;
- double d;
- char *s;
-};
+bool GDScriptLambdaCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ // Lambda callables are only compared by reference.
+ return p_a == p_b;
+}
-extern int godot_js_eval(const char *p_js, int p_use_global_ctx, union js_eval_ret *p_union_ptr, void *p_byte_arr, void *p_byte_arr_write, void *(*p_callback)(void *p_ptr, void *p_ptr2, int p_len));
+bool GDScriptLambdaCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
+ // Lambda callables are only compared by reference.
+ return p_a < p_b;
}
-void *resize_PackedByteArray_and_open_write(void *p_arr, void *r_write, int p_len) {
- PackedByteArray *arr = (PackedByteArray *)p_arr;
- VectorWriteProxy<uint8_t> *write = (VectorWriteProxy<uint8_t> *)r_write;
- arr->resize(p_len);
- *write = arr->write;
- return arr->ptrw();
+uint32_t GDScriptLambdaCallable::hash() const {
+ return h;
}
-Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
- union js_eval_ret js_data;
- PackedByteArray arr;
- VectorWriteProxy<uint8_t> arr_write;
+String GDScriptLambdaCallable::get_as_text() const {
+ if (function->get_name() != StringName()) {
+ return function->get_name().operator String() + "(lambda)";
+ }
+ return "(anonymous lambda)";
+}
- Variant::Type return_type = static_cast<Variant::Type>(godot_js_eval(p_code.utf8().get_data(), p_use_global_exec_context, &js_data, &arr, &arr_write, resize_PackedByteArray_and_open_write));
+CallableCustom::CompareEqualFunc GDScriptLambdaCallable::get_compare_equal_func() const {
+ return compare_equal;
+}
- switch (return_type) {
- case Variant::BOOL:
- return js_data.b;
- case Variant::FLOAT:
- return js_data.d;
- case Variant::STRING: {
- String str = String::utf8(js_data.s);
- free(js_data.s); // Must free the string allocated in JS.
- return str;
+CallableCustom::CompareLessFunc GDScriptLambdaCallable::get_compare_less_func() const {
+ return compare_less;
+}
+
+ObjectID GDScriptLambdaCallable::get_object() const {
+ return script->get_instance_id();
+}
+
+void GDScriptLambdaCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ int captures_amount = captures.size();
+
+ if (captures_amount > 0) {
+ Vector<const Variant *> args;
+ args.resize(p_argcount + captures_amount);
+ for (int i = 0; i < captures_amount; i++) {
+ args.write[i] = &captures[i];
+ }
+ for (int i = 0; i < p_argcount; i++) {
+ args.write[i + captures_amount] = p_arguments[i];
}
- case Variant::PACKED_BYTE_ARRAY:
- arr_write = VectorWriteProxy<uint8_t>();
- return arr;
- default:
- return Variant();
+
+ r_return_value = function->call(nullptr, args.ptrw(), args.size(), r_call_error);
+ r_call_error.argument -= captures_amount;
+ } else {
+ r_return_value = function->call(nullptr, p_arguments, p_argcount, r_call_error);
}
}
-#endif // JAVASCRIPT_EVAL_ENABLED
+GDScriptLambdaCallable::GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures) {
+ script = p_script;
+ function = p_function;
+ captures = p_captures;
+
+ h = (uint32_t)hash_djb2_one_64((uint64_t)this);
+}
diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h
new file mode 100644
index 0000000000..336778d549
--- /dev/null
+++ b/modules/gdscript/gdscript_lambda_callable.h
@@ -0,0 +1,65 @@
+/*************************************************************************/
+/* gdscript_lambda_callable.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GDSCRIPT_LAMBDA_CALLABLE
+#define GDSCRIPT_LAMBDA_CALLABLE
+
+#include "core/object/ref_counted.h"
+#include "core/templates/vector.h"
+#include "core/variant/callable.h"
+#include "core/variant/variant.h"
+
+class GDScript;
+class GDScriptFunction;
+class GDScriptInstance;
+
+class GDScriptLambdaCallable : public CallableCustom {
+ GDScriptFunction *function = nullptr;
+ Ref<GDScript> script;
+ uint32_t h;
+
+ Vector<Variant> captures;
+
+ static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
+
+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;
+
+ GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
+ virtual ~GDScriptLambdaCallable() = default;
+};
+
+#endif // GDSCRIPT_LAMBDA_CALLABLE
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index ca8bb8fcae..ba208ebfe8 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -31,9 +31,9 @@
#include "gdscript_parser.h"
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/math/math_defs.h"
-#include "core/os/file_access.h"
#include "gdscript.h"
#ifdef DEBUG_ENABLED
@@ -61,9 +61,9 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
builtin_types["Vector3i"] = Variant::VECTOR3I;
builtin_types["AABB"] = Variant::AABB;
builtin_types["Plane"] = Variant::PLANE;
- builtin_types["Quat"] = Variant::QUAT;
+ builtin_types["Quaternion"] = Variant::QUATERNION;
builtin_types["Basis"] = Variant::BASIS;
- builtin_types["Transform"] = Variant::TRANSFORM;
+ builtin_types["Transform3D"] = Variant::TRANSFORM3D;
builtin_types["Color"] = Variant::COLOR;
builtin_types["RID"] = Variant::RID;
builtin_types["Object"] = Variant::OBJECT;
@@ -402,6 +402,8 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
}
GDScriptTokenizer::Token GDScriptParser::advance() {
+ lambda_ended = false; // Empty marker since we're past the end in any case.
+
if (current.type == GDScriptTokenizer::Token::TK_EOF) {
ERR_FAIL_COND_V_MSG(current.type == GDScriptTokenizer::Token::TK_EOF, current, "GDScript parser bug: Trying to advance past the end of stream.");
}
@@ -428,7 +430,7 @@ bool GDScriptParser::match(GDScriptTokenizer::Token::Type p_token_type) {
return true;
}
-bool GDScriptParser::check(GDScriptTokenizer::Token::Type p_token_type) {
+bool GDScriptParser::check(GDScriptTokenizer::Token::Type p_token_type) const {
if (p_token_type == GDScriptTokenizer::Token::IDENTIFIER) {
return current.is_identifier();
}
@@ -443,7 +445,7 @@ bool GDScriptParser::consume(GDScriptTokenizer::Token::Type p_token_type, const
return false;
}
-bool GDScriptParser::is_at_end() {
+bool GDScriptParser::is_at_end() const {
return check(GDScriptTokenizer::Token::TK_EOF);
}
@@ -494,16 +496,34 @@ void GDScriptParser::pop_multiline() {
tokenizer.set_multiline_mode(multiline_stack.size() > 0 ? multiline_stack.back()->get() : false);
}
-bool GDScriptParser::is_statement_end() {
+bool GDScriptParser::is_statement_end_token() const {
return check(GDScriptTokenizer::Token::NEWLINE) || check(GDScriptTokenizer::Token::SEMICOLON) || check(GDScriptTokenizer::Token::TK_EOF);
}
+bool GDScriptParser::is_statement_end() const {
+ return lambda_ended || in_lambda || is_statement_end_token();
+}
+
void GDScriptParser::end_statement(const String &p_context) {
bool found = false;
while (is_statement_end() && !is_at_end()) {
// Remove sequential newlines/semicolons.
+ if (is_statement_end_token()) {
+ // Only consume if this is an actual token.
+ advance();
+ } else if (lambda_ended) {
+ lambda_ended = false; // Consume this "token".
+ found = true;
+ break;
+ } else {
+ if (!found) {
+ lambda_ended = true; // Mark the lambda as done since we found something else to end the statement.
+ found = true;
+ }
+ break;
+ }
+
found = true;
- advance();
}
if (!found && !is_at_end()) {
push_error(vformat(R"(Expected end of statement after %s, found "%s" instead.)", p_context, current.get_name()));
@@ -1153,7 +1173,7 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
consume(GDScriptTokenizer::Token::BRACE_CLOSE, R"(Expected closing "}" for enum.)");
#ifdef TOOLS_ENABLED
- // Enum values documentaion.
+ // Enum values documentation.
for (int i = 0; i < enum_node->values.size(); i++) {
if (i == enum_node->values.size() - 1) {
// If close bracket is same line as last value.
@@ -1182,36 +1202,7 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
return enum_node;
}
-GDScriptParser::FunctionNode *GDScriptParser::parse_function() {
- bool _static = false;
- if (previous.type == GDScriptTokenizer::Token::STATIC) {
- // TODO: Improve message if user uses "static" with "var" or "const"
- if (!consume(GDScriptTokenizer::Token::FUNC, R"(Expected "func" after "static".)")) {
- return nullptr;
- }
- _static = true;
- }
-
- FunctionNode *function = alloc_node<FunctionNode>();
- make_completion_context(COMPLETION_OVERRIDE_METHOD, function);
-
- if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after "func".)")) {
- return nullptr;
- }
-
- FunctionNode *previous_function = current_function;
- current_function = function;
-
- function->identifier = parse_identifier();
- function->is_static = _static;
-
- push_multiline(true);
- consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after function name.)");
-
- SuiteNode *body = alloc_node<SuiteNode>();
- SuiteNode *previous_suite = current_suite;
- current_suite = body;
-
+void GDScriptParser::parse_function_signature(FunctionNode *p_function, SuiteNode *p_body, const String &p_type) {
if (!check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE) && !is_at_end()) {
bool default_used = false;
do {
@@ -1231,29 +1222,61 @@ GDScriptParser::FunctionNode *GDScriptParser::parse_function() {
continue;
}
}
- if (function->parameters_indices.has(parameter->identifier->name)) {
- push_error(vformat(R"(Parameter with name "%s" was already declared for this function.)", parameter->identifier->name));
+ if (p_function->parameters_indices.has(parameter->identifier->name)) {
+ push_error(vformat(R"(Parameter with name "%s" was already declared for this %s.)", parameter->identifier->name, p_type));
} else {
- function->parameters_indices[parameter->identifier->name] = function->parameters.size();
- function->parameters.push_back(parameter);
- body->add_local(parameter);
+ p_function->parameters_indices[parameter->identifier->name] = p_function->parameters.size();
+ p_function->parameters.push_back(parameter);
+ p_body->add_local(parameter, current_function);
}
} while (match(GDScriptTokenizer::Token::COMMA));
}
pop_multiline();
- consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after function parameters.)*");
+ consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, vformat(R"*(Expected closing ")" after %s parameters.)*", p_type));
if (match(GDScriptTokenizer::Token::FORWARD_ARROW)) {
- make_completion_context(COMPLETION_TYPE_NAME_OR_VOID, function);
- function->return_type = parse_type(true);
- if (function->return_type == nullptr) {
+ make_completion_context(COMPLETION_TYPE_NAME_OR_VOID, p_function);
+ p_function->return_type = parse_type(true);
+ if (p_function->return_type == nullptr) {
push_error(R"(Expected return type or "void" after "->".)");
}
}
// TODO: Improve token consumption so it synchronizes to a statement boundary. This way we can get into the function body with unrecognized tokens.
- consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after function declaration.)");
+ consume(GDScriptTokenizer::Token::COLON, vformat(R"(Expected ":" after %s declaration.)", p_type));
+}
+
+GDScriptParser::FunctionNode *GDScriptParser::parse_function() {
+ bool _static = false;
+ if (previous.type == GDScriptTokenizer::Token::STATIC) {
+ // TODO: Improve message if user uses "static" with "var" or "const"
+ if (!consume(GDScriptTokenizer::Token::FUNC, R"(Expected "func" after "static".)")) {
+ return nullptr;
+ }
+ _static = true;
+ }
+
+ FunctionNode *function = alloc_node<FunctionNode>();
+ make_completion_context(COMPLETION_OVERRIDE_METHOD, function);
+
+ if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected function name after "func".)")) {
+ return nullptr;
+ }
+
+ FunctionNode *previous_function = current_function;
+ current_function = function;
+
+ function->identifier = parse_identifier();
+ function->is_static = _static;
+
+ SuiteNode *body = alloc_node<SuiteNode>();
+ SuiteNode *previous_suite = current_suite;
+ current_suite = body;
+
+ push_multiline(true);
+ consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after function name.)");
+ parse_function_signature(function, body, "function");
current_suite = previous_suite;
function->body = parse_suite("function declaration", body);
@@ -1339,29 +1362,34 @@ bool GDScriptParser::register_annotation(const MethodInfo &p_info, uint32_t p_ta
return true;
}
-GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, SuiteNode *p_suite) {
+GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context, SuiteNode *p_suite, bool p_for_lambda) {
SuiteNode *suite = p_suite != nullptr ? p_suite : alloc_node<SuiteNode>();
suite->parent_block = current_suite;
+ suite->parent_function = current_function;
current_suite = suite;
bool multiline = false;
- if (check(GDScriptTokenizer::Token::NEWLINE)) {
+ if (match(GDScriptTokenizer::Token::NEWLINE)) {
multiline = true;
}
if (multiline) {
- consume(GDScriptTokenizer::Token::NEWLINE, vformat(R"(Expected newline after %s.)", p_context));
-
if (!consume(GDScriptTokenizer::Token::INDENT, vformat(R"(Expected indented block after %s.)", p_context))) {
current_suite = suite->parent_block;
return suite;
}
}
+ int error_count = 0;
+
do {
Node *statement = parse_statement();
if (statement == nullptr) {
+ if (error_count++ > 100) {
+ push_error("Too many statement errors.", suite);
+ break;
+ }
continue;
}
suite->statements.push_back(statement);
@@ -1374,7 +1402,7 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context,
if (local.type != SuiteNode::Local::UNDEFINED) {
push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", local.get_name(), variable->identifier->name));
}
- current_suite->add_local(variable);
+ current_suite->add_local(variable, current_function);
break;
}
case Node::CONSTANT: {
@@ -1389,19 +1417,29 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context,
}
push_error(vformat(R"(There is already a %s named "%s" declared in this scope.)", name, constant->identifier->name));
}
- current_suite->add_local(constant);
+ current_suite->add_local(constant, current_function);
break;
}
default:
break;
}
- } while (multiline && !check(GDScriptTokenizer::Token::DEDENT) && !is_at_end());
+ } while (multiline && !check(GDScriptTokenizer::Token::DEDENT) && !lambda_ended && !is_at_end());
if (multiline) {
- consume(GDScriptTokenizer::Token::DEDENT, vformat(R"(Missing unindent at the end of %s.)", p_context));
+ if (!lambda_ended) {
+ consume(GDScriptTokenizer::Token::DEDENT, vformat(R"(Missing unindent at the end of %s.)", p_context));
+
+ } else {
+ match(GDScriptTokenizer::Token::DEDENT);
+ }
+ } else if (previous.type == GDScriptTokenizer::Token::SEMICOLON) {
+ consume(GDScriptTokenizer::Token::NEWLINE, vformat(R"(Expected newline after ";" at the end of %s.)", p_context));
}
+ if (p_for_lambda) {
+ lambda_ended = true;
+ }
current_suite = suite->parent_block;
return suite;
}
@@ -1458,6 +1496,10 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
push_error(R"(Constructor cannot return a value.)");
}
n_return->return_value = parse_expression(false);
+ } else if (in_lambda && !is_statement_end_token()) {
+ // Try to parse it anyway as this might not be the statement end in a lambda.
+ // If this fails the expression will be nullptr, but that's the same as no return, so it's fine.
+ n_return->return_value = parse_expression(false);
}
result = n_return;
@@ -1486,10 +1528,18 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
default: {
// Expression statement.
ExpressionNode *expression = parse_expression(true); // Allow assignment here.
+ bool has_ended_lambda = false;
if (expression == nullptr) {
- push_error(vformat(R"(Expected statement, found "%s" instead.)", previous.get_name()));
+ if (in_lambda) {
+ // If it's not a valid expression beginning, it might be the continuation of the outer expression where this lambda is.
+ lambda_ended = true;
+ has_ended_lambda = true;
+ } else {
+ push_error(vformat(R"(Expected statement, found "%s" instead.)", previous.get_name()));
+ }
}
end_statement("expression");
+ lambda_ended = lambda_ended || has_ended_lambda;
result = expression;
#ifdef DEBUG_ENABLED
@@ -1513,7 +1563,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
if (unreachable && result != nullptr) {
current_suite->has_unreachable_code = true;
if (current_function) {
- push_warning(result, GDScriptWarning::UNREACHABLE_CODE, current_function->identifier->name);
+ push_warning(result, GDScriptWarning::UNREACHABLE_CODE, current_function->identifier ? current_function->identifier->name : "<anonymous lambda>");
} else {
// TODO: Properties setters and getters with unreachable code are not being warned
}
@@ -1598,7 +1648,7 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() {
SuiteNode *suite = alloc_node<SuiteNode>();
if (n_for->variable) {
- suite->add_local(SuiteNode::Local(n_for->variable));
+ suite->add_local(SuiteNode::Local(n_for->variable, current_function));
}
suite->parent_for = n_for;
@@ -1753,7 +1803,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
branch->patterns[0]->binds.get_key_list(&binds);
for (List<StringName>::Element *E = binds.front(); E != nullptr; E = E->next()) {
- SuiteNode::Local local(branch->patterns[0]->binds[E->get()]);
+ SuiteNode::Local local(branch->patterns[0]->binds[E->get()], current_function);
suite->add_local(local);
}
}
@@ -1953,7 +2003,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr
// Completion can appear whenever an expression is expected.
make_completion_context(COMPLETION_IDENTIFIER, nullptr);
- GDScriptTokenizer::Token token = advance();
+ GDScriptTokenizer::Token token = current;
ParseFunction prefix_rule = get_rule(token.type)->prefix;
if (prefix_rule == nullptr) {
@@ -1961,6 +2011,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr
return nullptr;
}
+ advance(); // Only consume the token if there's a valid rule.
+
ExpressionNode *previous_operand = (this->*prefix_rule)(nullptr, p_can_assign);
while (p_precedence <= get_rule(current.type)->precedence) {
@@ -2002,6 +2054,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_identifier(ExpressionNode
if (current_suite != nullptr && current_suite->has_local(identifier->name)) {
const SuiteNode::Local &declaration = current_suite->get_local(identifier->name);
+
+ identifier->source_function = declaration.source_function;
switch (declaration.type) {
case SuiteNode::Local::CONSTANT:
identifier->source = IdentifierNode::LOCAL_CONSTANT;
@@ -2055,6 +2109,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_self(ExpressionNode *p_pre
if (current_function && current_function->is_static) {
push_error(R"(Cannot use "self" inside a static function.)");
}
+ if (in_lambda) {
+ push_error(R"(Cannot use "self" inside a lambda.)");
+ }
SelfNode *self = alloc_node<SelfNode>();
self->current_class = current_class;
return self;
@@ -2440,6 +2497,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
push_error(R"(Expected "=" after dictionary key.)");
}
}
+ key->is_constant = true;
+ key->reduced_value = static_cast<IdentifierNode *>(key)->name;
break;
case DictionaryNode::PYTHON_DICT:
if (!match(GDScriptTokenizer::Token::COLON)) {
@@ -2486,7 +2545,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_attribute(ExpressionNode *
if (for_completion) {
bool is_builtin = false;
- if (p_previous_operand->type == Node::IDENTIFIER) {
+ if (p_previous_operand && p_previous_operand->type == Node::IDENTIFIER) {
const IdentifierNode *id = static_cast<const IdentifierNode *>(p_previous_operand);
Variant::Type builtin_type = get_builtin_type(id->name);
if (builtin_type < Variant::VARIANT_MAX) {
@@ -2673,6 +2732,65 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_preload(ExpressionNode *p_
return preload;
}
+GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_previous_operand, bool p_can_assign) {
+ LambdaNode *lambda = alloc_node<LambdaNode>();
+ lambda->parent_function = current_function;
+ FunctionNode *function = alloc_node<FunctionNode>();
+ function->source_lambda = lambda;
+
+ function->is_static = current_function != nullptr ? current_function->is_static : false;
+
+ if (match(GDScriptTokenizer::Token::IDENTIFIER)) {
+ function->identifier = parse_identifier();
+ }
+
+ bool multiline_context = multiline_stack.back()->get();
+
+ // Reset the multiline stack since we don't want the multiline mode one in the lambda body.
+ push_multiline(false);
+ if (multiline_context) {
+ tokenizer.push_expression_indented_block();
+ }
+
+ push_multiline(true); // For the parameters.
+ if (function->identifier) {
+ consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after lambda name.)");
+ } else {
+ consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected opening "(" after "func".)");
+ }
+
+ FunctionNode *previous_function = current_function;
+ current_function = function;
+
+ SuiteNode *body = alloc_node<SuiteNode>();
+ SuiteNode *previous_suite = current_suite;
+ current_suite = body;
+
+ parse_function_signature(function, body, "lambda");
+
+ current_suite = previous_suite;
+
+ bool previous_in_lambda = in_lambda;
+ in_lambda = true;
+
+ function->body = parse_suite("lambda declaration", body, true);
+
+ pop_multiline();
+
+ if (multiline_context) {
+ // If we're in multiline mode, we want to skip the spurious DEDENT and NEWLINE tokens.
+ while (check(GDScriptTokenizer::Token::DEDENT) || check(GDScriptTokenizer::Token::INDENT) || check(GDScriptTokenizer::Token::NEWLINE)) {
+ current = tokenizer.scan(); // Not advance() since we don't want to change the previous token.
+ }
+ tokenizer.pop_expression_indented_block();
+ }
+
+ current_function = previous_function;
+ in_lambda = previous_in_lambda;
+ lambda->function = function;
+ return lambda;
+}
+
GDScriptParser::ExpressionNode *GDScriptParser::parse_invalid_token(ExpressionNode *p_previous_operand, bool p_can_assign) {
// Just for better error messages.
GDScriptTokenizer::Token::Type invalid = previous.type;
@@ -3017,7 +3135,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ nullptr, nullptr, PREC_NONE }, // CONST,
{ nullptr, nullptr, PREC_NONE }, // ENUM,
{ nullptr, nullptr, PREC_NONE }, // EXTENDS,
- { nullptr, nullptr, PREC_NONE }, // FUNC,
+ { &GDScriptParser::parse_lambda, nullptr, PREC_NONE }, // FUNC,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_CONTENT_TEST }, // IN,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_TYPE_TEST }, // IS,
{ nullptr, nullptr, PREC_NONE }, // NAMESPACE,
@@ -3753,6 +3871,10 @@ void GDScriptParser::TreePrinter::print_dictionary(DictionaryNode *p_dictionary)
}
void GDScriptParser::TreePrinter::print_expression(ExpressionNode *p_expression) {
+ if (p_expression == nullptr) {
+ push_text("<invalid expression>");
+ return;
+ }
switch (p_expression->type) {
case Node::ARRAY:
print_array(static_cast<ArrayNode *>(p_expression));
@@ -3781,6 +3903,9 @@ void GDScriptParser::TreePrinter::print_expression(ExpressionNode *p_expression)
case Node::IDENTIFIER:
print_identifier(static_cast<IdentifierNode *>(p_expression));
break;
+ case Node::LAMBDA:
+ print_lambda(static_cast<LambdaNode *>(p_expression));
+ break;
case Node::LITERAL:
print_literal(static_cast<LiteralNode *>(p_expression));
break;
@@ -3840,12 +3965,17 @@ void GDScriptParser::TreePrinter::print_for(ForNode *p_for) {
decrease_indent();
}
-void GDScriptParser::TreePrinter::print_function(FunctionNode *p_function) {
+void GDScriptParser::TreePrinter::print_function(FunctionNode *p_function, const String &p_context) {
for (const List<AnnotationNode *>::Element *E = p_function->annotations.front(); E != nullptr; E = E->next()) {
print_annotation(E->get());
}
- push_text("Function ");
- print_identifier(p_function->identifier);
+ push_text(p_context);
+ push_text(" ");
+ if (p_function->identifier) {
+ print_identifier(p_function->identifier);
+ } else {
+ push_text("<anonymous>");
+ }
push_text("( ");
for (int i = 0; i < p_function->parameters.size(); i++) {
if (i > 0) {
@@ -3899,6 +4029,18 @@ void GDScriptParser::TreePrinter::print_if(IfNode *p_if, bool p_is_elif) {
}
}
+void GDScriptParser::TreePrinter::print_lambda(LambdaNode *p_lambda) {
+ print_function(p_lambda->function, "Lambda");
+ push_text("| captures [ ");
+ for (int i = 0; i < p_lambda->captures.size(); i++) {
+ if (i > 0) {
+ push_text(" , ");
+ }
+ push_text(p_lambda->captures[i]->name.operator String());
+ }
+ push_line(" ]");
+}
+
void GDScriptParser::TreePrinter::print_literal(LiteralNode *p_literal) {
// Prefix for string types.
switch (p_literal->value.get_type()) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 272d21ffce..9e0b60a407 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -33,7 +33,7 @@
#include "core/io/multiplayer_api.h"
#include "core/io/resource.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
#include "core/string/string_name.h"
#include "core/string/ustring.h"
@@ -76,6 +76,7 @@ public:
struct GetNodeNode;
struct IdentifierNode;
struct IfNode;
+ struct LambdaNode;
struct LiteralNode;
struct MatchNode;
struct MatchBranchNode;
@@ -267,6 +268,7 @@ public:
GET_NODE,
IDENTIFIER,
IF,
+ LAMBDA,
LITERAL,
MATCH,
MATCH_BRANCH,
@@ -368,6 +370,7 @@ public:
Variant::Operator variant_op = Variant::OP_MAX;
ExpressionNode *assignee = nullptr;
ExpressionNode *assigned_value = nullptr;
+ bool use_conversion_assign = false;
AssignmentNode() {
type = ASSIGNMENT;
@@ -728,6 +731,7 @@ public:
bool is_coroutine = false;
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
MethodInfo info;
+ LambdaNode *source_lambda = nullptr;
#ifdef TOOLS_ENABLED
Vector<Variant> default_arg_values;
String doc_description;
@@ -771,6 +775,7 @@ public:
VariableNode *variable_source;
IdentifierNode *bind_source;
};
+ FunctionNode *source_function = nullptr;
int usages = 0; // Useful for binds/iterator variable.
@@ -789,6 +794,21 @@ public:
}
};
+ struct LambdaNode : public ExpressionNode {
+ FunctionNode *function = nullptr;
+ FunctionNode *parent_function = nullptr;
+ Vector<IdentifierNode *> captures;
+ Map<StringName, int> captures_indices;
+
+ bool has_name() const {
+ return function && function->identifier;
+ }
+
+ LambdaNode() {
+ type = LAMBDA;
+ }
+ };
+
struct LiteralNode : public ExpressionNode {
Variant value;
@@ -942,6 +962,7 @@ public:
IdentifierNode *bind;
};
StringName name;
+ FunctionNode *source_function = nullptr;
int start_line = 0, end_line = 0;
int start_column = 0, end_column = 0;
@@ -951,10 +972,11 @@ public:
String get_name() const;
Local() {}
- Local(ConstantNode *p_constant) {
+ Local(ConstantNode *p_constant, FunctionNode *p_source_function) {
type = CONSTANT;
constant = p_constant;
name = p_constant->identifier->name;
+ source_function = p_source_function;
start_line = p_constant->start_line;
end_line = p_constant->end_line;
@@ -963,10 +985,11 @@ public:
leftmost_column = p_constant->leftmost_column;
rightmost_column = p_constant->rightmost_column;
}
- Local(VariableNode *p_variable) {
+ Local(VariableNode *p_variable, FunctionNode *p_source_function) {
type = VARIABLE;
variable = p_variable;
name = p_variable->identifier->name;
+ source_function = p_source_function;
start_line = p_variable->start_line;
end_line = p_variable->end_line;
@@ -975,10 +998,11 @@ public:
leftmost_column = p_variable->leftmost_column;
rightmost_column = p_variable->rightmost_column;
}
- Local(ParameterNode *p_parameter) {
+ Local(ParameterNode *p_parameter, FunctionNode *p_source_function) {
type = PARAMETER;
parameter = p_parameter;
name = p_parameter->identifier->name;
+ source_function = p_source_function;
start_line = p_parameter->start_line;
end_line = p_parameter->end_line;
@@ -987,10 +1011,11 @@ public:
leftmost_column = p_parameter->leftmost_column;
rightmost_column = p_parameter->rightmost_column;
}
- Local(IdentifierNode *p_identifier) {
+ Local(IdentifierNode *p_identifier, FunctionNode *p_source_function) {
type = FOR_VARIABLE;
bind = p_identifier;
name = p_identifier->name;
+ source_function = p_source_function;
start_line = p_identifier->start_line;
end_line = p_identifier->end_line;
@@ -1015,9 +1040,9 @@ public:
bool has_local(const StringName &p_name) const;
const Local &get_local(const StringName &p_name) const;
template <class T>
- void add_local(T *p_local) {
+ void add_local(T *p_local, FunctionNode *p_source_function) {
locals_indices[p_local->identifier->name] = locals.size();
- locals.push_back(Local(p_local));
+ locals.push_back(Local(p_local, p_source_function));
}
void add_local(const Local &p_local) {
locals_indices[p_local.name] = locals.size();
@@ -1095,6 +1120,7 @@ public:
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
int assignments = 0;
int usages = 0;
+ bool use_conversion_assign = false;
#ifdef TOOLS_ENABLED
String doc_description;
#endif // TOOLS_ENABLED
@@ -1191,6 +1217,8 @@ private:
CompletionCall completion_call;
List<CompletionCall> completion_call_stack;
bool passed_cursor = false;
+ bool in_lambda = false;
+ bool lambda_ended = false; // Marker for when a lambda ends, to apply an end of statement if needed.
typedef bool (GDScriptParser::*AnnotationAction)(const AnnotationNode *p_annotation, Node *p_target);
struct AnnotationInfo {
@@ -1278,10 +1306,11 @@ private:
GDScriptTokenizer::Token advance();
bool match(GDScriptTokenizer::Token::Type p_token_type);
- bool check(GDScriptTokenizer::Token::Type p_token_type);
+ bool check(GDScriptTokenizer::Token::Type p_token_type) const;
bool consume(GDScriptTokenizer::Token::Type p_token_type, const String &p_error_message);
- bool is_at_end();
- bool is_statement_end();
+ bool is_at_end() const;
+ bool is_statement_end_token() const;
+ bool is_statement_end() const;
void end_statement(const String &p_context);
void synchronize();
void push_multiline(bool p_state);
@@ -1299,7 +1328,8 @@ private:
EnumNode *parse_enum();
ParameterNode *parse_parameter();
FunctionNode *parse_function();
- SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr);
+ void parse_function_signature(FunctionNode *p_function, SuiteNode *p_body, const String &p_type);
+ SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr, bool p_for_lambda = false);
// Annotations
AnnotationNode *parse_annotation(uint32_t p_valid_targets);
bool register_annotation(const MethodInfo &p_info, uint32_t p_target_kinds, AnnotationAction p_apply, int p_optional_arguments = 0, bool p_is_vararg = false);
@@ -1354,6 +1384,7 @@ private:
ExpressionNode *parse_await(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_attribute(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_subscript(ExpressionNode *p_previous_operand, bool p_can_assign);
+ ExpressionNode *parse_lambda(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_invalid_token(ExpressionNode *p_previous_operand, bool p_can_assign);
TypeNode *parse_type(bool p_allow_void = false);
#ifdef TOOLS_ENABLED
@@ -1415,10 +1446,11 @@ public:
void print_expression(ExpressionNode *p_expression);
void print_enum(EnumNode *p_enum);
void print_for(ForNode *p_for);
- void print_function(FunctionNode *p_function);
+ void print_function(FunctionNode *p_function, const String &p_context = "Function");
void print_get_node(GetNodeNode *p_get_node);
void print_if(IfNode *p_if, bool p_is_elif = false);
void print_identifier(IdentifierNode *p_identifier);
+ void print_lambda(LambdaNode *p_lambda);
void print_literal(LiteralNode *p_literal);
void print_match(MatchNode *p_match);
void print_match_branch(MatchBranchNode *p_match_branch);
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index e432dfc891..3f14156dfa 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -242,6 +242,16 @@ void GDScriptTokenizer::set_multiline_mode(bool p_state) {
multiline_mode = p_state;
}
+void GDScriptTokenizer::push_expression_indented_block() {
+ indent_stack_stack.push_back(indent_stack);
+}
+
+void GDScriptTokenizer::pop_expression_indented_block() {
+ ERR_FAIL_COND(indent_stack_stack.size() == 0);
+ indent_stack = indent_stack_stack.back()->get();
+ indent_stack_stack.pop_back();
+}
+
int GDScriptTokenizer::get_cursor_line() const {
return cursor_line;
}
@@ -633,6 +643,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
push_error(error);
}
previous_was_underscore = true;
+ } else {
+ previous_was_underscore = false;
}
_advance();
}
@@ -704,6 +716,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
push_error(error);
}
previous_was_underscore = true;
+ } else {
+ previous_was_underscore = false;
}
_advance();
}
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index bea4b14019..84b82c07f0 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -217,6 +217,7 @@ private:
Token last_newline;
int pending_indents = 0;
List<int> indent_stack;
+ List<List<int>> indent_stack_stack; // For lambdas, which require manipulating the indentation point.
List<char32_t> paren_stack;
char32_t indent_char = '\0';
int position = 0;
@@ -263,6 +264,8 @@ public:
void set_multiline_mode(bool p_state);
bool is_past_cursor() const;
static String get_token_name(Token::Type p_token_type);
+ void push_expression_indented_block(); // For lambdas, or blocks inside expressions.
+ void pop_expression_indented_block(); // For lambdas, or blocks inside expressions.
GDScriptTokenizer();
};
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index b47a4eb992..8a261a88e3 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -33,6 +33,7 @@
#include "core/core_string_names.h"
#include "core/os/os.h"
#include "gdscript.h"
+#include "gdscript_lambda_callable.h"
Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const {
int address = p_address & ADDR_MASK;
@@ -151,6 +152,44 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
return err_text;
}
+void (*type_init_function_table[])(Variant *) = {
+ nullptr, // NIL (shouldn't be called).
+ &VariantInitializer<bool>::init, // BOOL.
+ &VariantInitializer<int64_t>::init, // INT.
+ &VariantInitializer<double>::init, // FLOAT.
+ &VariantInitializer<String>::init, // STRING.
+ &VariantInitializer<Vector2>::init, // VECTOR2.
+ &VariantInitializer<Vector2i>::init, // VECTOR2I.
+ &VariantInitializer<Rect2>::init, // RECT2.
+ &VariantInitializer<Rect2i>::init, // RECT2I.
+ &VariantInitializer<Vector3>::init, // VECTOR3.
+ &VariantInitializer<Vector3i>::init, // VECTOR3I.
+ &VariantInitializer<Transform2D>::init, // TRANSFORM2D.
+ &VariantInitializer<Plane>::init, // PLANE.
+ &VariantInitializer<Quaternion>::init, // QUATERNION.
+ &VariantInitializer<AABB>::init, // AABB.
+ &VariantInitializer<Basis>::init, // BASIS.
+ &VariantInitializer<Transform3D>::init, // TRANSFORM3D.
+ &VariantInitializer<Color>::init, // COLOR.
+ &VariantInitializer<StringName>::init, // STRING_NAME.
+ &VariantInitializer<NodePath>::init, // NODE_PATH.
+ &VariantInitializer<RID>::init, // RID.
+ &VariantTypeAdjust<Object *>::adjust, // OBJECT.
+ &VariantInitializer<Callable>::init, // CALLABLE.
+ &VariantInitializer<Signal>::init, // SIGNAL.
+ &VariantInitializer<Dictionary>::init, // DICTIONARY.
+ &VariantInitializer<Array>::init, // ARRAY.
+ &VariantInitializer<PackedByteArray>::init, // PACKED_BYTE_ARRAY.
+ &VariantInitializer<PackedInt32Array>::init, // PACKED_INT32_ARRAY.
+ &VariantInitializer<PackedInt64Array>::init, // PACKED_INT64_ARRAY.
+ &VariantInitializer<PackedFloat32Array>::init, // PACKED_FLOAT32_ARRAY.
+ &VariantInitializer<PackedFloat64Array>::init, // PACKED_FLOAT64_ARRAY.
+ &VariantInitializer<PackedStringArray>::init, // PACKED_STRING_ARRAY.
+ &VariantInitializer<PackedVector2Array>::init, // PACKED_VECTOR2_ARRAY.
+ &VariantInitializer<PackedVector3Array>::init, // PACKED_VECTOR3_ARRAY.
+ &VariantInitializer<PackedColorArray>::init, // PACKED_COLOR_ARRAY.
+};
+
#if defined(__GNUC__)
#define OPCODES_TABLE \
static const void *switch_table_ops[] = { \
@@ -195,6 +234,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CALL_SELF_BASE, \
&&OPCODE_CALL_METHOD_BIND, \
&&OPCODE_CALL_METHOD_BIND_RET, \
+ &&OPCODE_CALL_BUILTIN_STATIC, \
&&OPCODE_CALL_PTRCALL_NO_RETURN, \
&&OPCODE_CALL_PTRCALL_BOOL, \
&&OPCODE_CALL_PTRCALL_INT, \
@@ -208,10 +248,10 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CALL_PTRCALL_VECTOR3I, \
&&OPCODE_CALL_PTRCALL_TRANSFORM2D, \
&&OPCODE_CALL_PTRCALL_PLANE, \
- &&OPCODE_CALL_PTRCALL_QUAT, \
+ &&OPCODE_CALL_PTRCALL_QUATERNION, \
&&OPCODE_CALL_PTRCALL_AABB, \
&&OPCODE_CALL_PTRCALL_BASIS, \
- &&OPCODE_CALL_PTRCALL_TRANSFORM, \
+ &&OPCODE_CALL_PTRCALL_TRANSFORM3D, \
&&OPCODE_CALL_PTRCALL_COLOR, \
&&OPCODE_CALL_PTRCALL_STRING_NAME, \
&&OPCODE_CALL_PTRCALL_NODE_PATH, \
@@ -232,6 +272,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY, \
&&OPCODE_AWAIT, \
&&OPCODE_AWAIT_RESUME, \
+ &&OPCODE_CREATE_LAMBDA, \
&&OPCODE_JUMP, \
&&OPCODE_JUMP_IF, \
&&OPCODE_JUMP_IF_NOT, \
@@ -294,7 +335,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_TYPE_ADJUST_VECTOR3I, \
&&OPCODE_TYPE_ADJUST_TRANSFORM2D, \
&&OPCODE_TYPE_ADJUST_PLANE, \
- &&OPCODE_TYPE_ADJUST_QUAT, \
+ &&OPCODE_TYPE_ADJUST_QUATERNION, \
&&OPCODE_TYPE_ADJUST_AABB, \
&&OPCODE_TYPE_ADJUST_BASIS, \
&&OPCODE_TYPE_ADJUST_TRANSFORM, \
@@ -357,7 +398,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
#define OP_GET_VECTOR3I get_vector3i
#define OP_GET_RECT2 get_rect2
#define OP_GET_RECT2I get_rect2i
-#define OP_GET_QUAT get_quat
+#define OP_GET_QUATERNION get_quaternion
#define OP_GET_COLOR get_color
#define OP_GET_STRING get_string
#define OP_GET_STRING_NAME get_string_name
@@ -375,7 +416,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
#define OP_GET_PACKED_VECTOR2_ARRAY get_vector2_array
#define OP_GET_PACKED_VECTOR3_ARRAY get_vector3_array
#define OP_GET_PACKED_COLOR_ARRAY get_color_array
-#define OP_GET_TRANSFORM get_transform
+#define OP_GET_TRANSFORM3D get_transform
#define OP_GET_TRANSFORM2D get_transform2d
#define OP_GET_PLANE get_plane
#define OP_GET_AABB get_aabb
@@ -489,6 +530,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
+ for (const Map<int, Variant::Type>::Element *E = temporary_slots.front(); E; E = E->next()) {
+ type_init_function_table[E->get()](&stack[E->key()]);
+ }
+
String err_text;
#ifdef DEBUG_ENABLED
@@ -1452,13 +1497,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (err.error != Callable::CallError::CALL_OK) {
String methodstr = *methodname;
String basestr = _get_var_type(base);
+ bool is_callable = false;
if (methodstr == "call") {
- if (argc >= 1) {
+ if (argc >= 1 && base->get_type() != Variant::CALLABLE) {
methodstr = String(*argptrs[0]) + " (via call)";
if (err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
err.argument += 1;
}
+ } else {
+ methodstr = base->operator String() + " (Callable)";
+ is_callable = true;
}
} else if (methodstr == "free") {
if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
@@ -1478,7 +1527,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
}
}
- err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
+ err_text = _get_call_error(err, "function '" + methodstr + (is_callable ? "" : "' in base '" + basestr) + "'", (const Variant **)argptrs);
OPCODE_BREAK;
}
#endif
@@ -1567,6 +1616,51 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_CALL_BUILTIN_STATIC) {
+ CHECK_SPACE(4 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ GD_ERR_BREAK(_code_ptr[ip + 1] < 0 || _code_ptr[ip + 1] >= Variant::VARIANT_MAX);
+ Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 1];
+
+ int methodname_idx = _code_ptr[ip + 2];
+ GD_ERR_BREAK(methodname_idx < 0 || methodname_idx >= _global_names_count);
+ const StringName *methodname = &_global_names_ptr[methodname_idx];
+
+ int argc = _code_ptr[ip + 3];
+ GD_ERR_BREAK(argc < 0);
+
+ GET_INSTRUCTION_ARG(ret, argc);
+
+ const Variant **argptrs = const_cast<const Variant **>(instruction_args);
+
+#ifdef DEBUG_ENABLED
+ uint64_t call_time = 0;
+
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ call_time = OS::get_singleton()->get_ticks_usec();
+ }
+#endif
+
+ Callable::CallError err;
+ Variant::call_static(builtin_type, *methodname, argptrs, argc, *ret, err);
+
+#ifdef DEBUG_ENABLED
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
+ }
+
+ if (err.error != Callable::CallError::CALL_OK) {
+ err_text = _get_call_error(err, "static function '" + methodname->operator String() + "' in type '" + Variant::get_type_name(builtin_type) + "'", argptrs);
+ OPCODE_BREAK;
+ }
+#endif
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
#ifdef DEBUG_ENABLED
#define OPCODE_CALL_PTR(m_type) \
OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
@@ -1639,10 +1733,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE_CALL_PTR(VECTOR3I);
OPCODE_CALL_PTR(TRANSFORM2D);
OPCODE_CALL_PTR(PLANE);
- OPCODE_CALL_PTR(QUAT);
+ OPCODE_CALL_PTR(QUATERNION);
OPCODE_CALL_PTR(AABB);
OPCODE_CALL_PTR(BASIS);
- OPCODE_CALL_PTR(TRANSFORM);
+ OPCODE_CALL_PTR(TRANSFORM3D);
OPCODE_CALL_PTR(COLOR);
OPCODE_CALL_PTR(STRING_NAME);
OPCODE_CALL_PTR(NODE_PATH);
@@ -1876,7 +1970,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (err.error != Callable::CallError::CALL_OK) {
// TODO: Add this information in debug.
- String methodstr = "<unkown function>";
+ String methodstr = "<unknown function>";
if (dst->get_type() == Variant::STRING) {
// Call provided error string.
err_text = "Error calling GDScript utility function '" + methodstr + "': " + String(*dst);
@@ -1895,7 +1989,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
ip += instr_arg_count;
- int self_fun = _code_ptr[ip + 1];
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ int self_fun = _code_ptr[ip + 2];
#ifdef DEBUG_ENABLED
if (self_fun < 0 || self_fun >= _global_names_count) {
err_text = "compiler bug, function name not found";
@@ -1904,9 +2001,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#endif
const StringName *methodname = &_global_names_ptr[self_fun];
- int argc = _code_ptr[ip + 2];
- GD_ERR_BREAK(argc < 0);
-
Variant **argptrs = instruction_args;
GET_INSTRUCTION_ARG(dst, argc);
@@ -2057,6 +2151,34 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_CREATE_LAMBDA) {
+ CHECK_SPACE(2 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int captures_count = _code_ptr[ip + 1];
+ GD_ERR_BREAK(captures_count < 0);
+
+ int lambda_index = _code_ptr[ip + 2];
+ GD_ERR_BREAK(lambda_index < 0 || lambda_index >= _lambdas_count);
+ GDScriptFunction *lambda = _lambdas_ptr[lambda_index];
+
+ Vector<Variant> captures;
+ captures.resize(captures_count);
+ for (int i = 0; i < captures_count; i++) {
+ GET_INSTRUCTION_ARG(arg, i);
+ captures.write[i] = *arg;
+ }
+
+ GDScriptLambdaCallable *callable = memnew(GDScriptLambdaCallable(Ref<GDScript>(script), lambda, captures));
+
+ GET_INSTRUCTION_ARG(result, captures_count);
+ *result = Callable(callable);
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_JUMP) {
CHECK_SPACE(2);
int to = _code_ptr[ip + 1];
@@ -3028,10 +3150,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE_TYPE_ADJUST(VECTOR3I, Vector3i);
OPCODE_TYPE_ADJUST(TRANSFORM2D, Transform2D);
OPCODE_TYPE_ADJUST(PLANE, Plane);
- OPCODE_TYPE_ADJUST(QUAT, Quat);
+ OPCODE_TYPE_ADJUST(QUATERNION, Quaternion);
OPCODE_TYPE_ADJUST(AABB, AABB);
OPCODE_TYPE_ADJUST(BASIS, Basis);
- OPCODE_TYPE_ADJUST(TRANSFORM, Transform);
+ OPCODE_TYPE_ADJUST(TRANSFORM, Transform3D);
OPCODE_TYPE_ADJUST(COLOR, Color);
OPCODE_TYPE_ADJUST(STRING_NAME, StringName);
OPCODE_TYPE_ADJUST(NODE_PATH, NodePath);
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index e63b6ab20e..15236d900d 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -49,8 +49,9 @@ void ExtendGDScriptParser::update_diagnostics() {
diagnostic.code = -1;
lsp::Range range;
lsp::Position pos;
- int line = LINE_NUMBER_TO_INDEX(error.line);
- const String &line_text = get_lines()[line];
+ const PackedStringArray lines = get_lines();
+ int line = CLAMP(LINE_NUMBER_TO_INDEX(error.line), 0, lines.size() - 1);
+ const String &line_text = lines[line];
pos.line = line;
pos.character = line_text.length() - line_text.strip_edges(true, false).length();
range.start = pos;
@@ -361,24 +362,73 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
r_symbol.detail += " -> " + p_func->get_datatype().to_string();
}
- for (int i = 0; i < p_func->body->locals.size(); i++) {
- const SuiteNode::Local &local = p_func->body->locals[i];
- lsp::DocumentSymbol symbol;
- symbol.name = local.name;
- symbol.kind = local.type == SuiteNode::Local::CONSTANT ? lsp::SymbolKind::Constant : lsp::SymbolKind::Variable;
- symbol.range.start.line = LINE_NUMBER_TO_INDEX(local.start_line);
- symbol.range.start.character = LINE_NUMBER_TO_INDEX(local.start_column);
- symbol.range.end.line = LINE_NUMBER_TO_INDEX(local.end_line);
- symbol.range.end.character = LINE_NUMBER_TO_INDEX(local.end_column);
- symbol.uri = uri;
- symbol.script_path = path;
- symbol.detail = SuiteNode::Local::CONSTANT ? "const " : "var ";
- symbol.detail += symbol.name;
- if (local.get_datatype().is_hard_type()) {
- symbol.detail += ": " + local.get_datatype().to_string();
+ List<GDScriptParser::SuiteNode *> function_nodes;
+
+ List<GDScriptParser::Node *> node_stack;
+ node_stack.push_back(p_func->body);
+
+ while (!node_stack.is_empty()) {
+ GDScriptParser::Node *node = node_stack[0];
+ node_stack.pop_front();
+
+ switch (node->type) {
+ case GDScriptParser::TypeNode::IF: {
+ GDScriptParser::IfNode *if_node = (GDScriptParser::IfNode *)node;
+ node_stack.push_back(if_node->true_block);
+ if (if_node->false_block) {
+ node_stack.push_back(if_node->false_block);
+ }
+ } break;
+
+ case GDScriptParser::TypeNode::FOR: {
+ GDScriptParser::ForNode *for_node = (GDScriptParser::ForNode *)node;
+ node_stack.push_back(for_node->loop);
+ } break;
+
+ case GDScriptParser::TypeNode::WHILE: {
+ GDScriptParser::WhileNode *while_node = (GDScriptParser::WhileNode *)node;
+ node_stack.push_back(while_node->loop);
+ } break;
+
+ case GDScriptParser::TypeNode::MATCH_BRANCH: {
+ GDScriptParser::MatchBranchNode *match_node = (GDScriptParser::MatchBranchNode *)node;
+ node_stack.push_back(match_node->block);
+ } break;
+
+ case GDScriptParser::TypeNode::SUITE: {
+ GDScriptParser::SuiteNode *suite_node = (GDScriptParser::SuiteNode *)node;
+ function_nodes.push_back(suite_node);
+ for (int i = 0; i < suite_node->statements.size(); ++i) {
+ node_stack.push_back(suite_node->statements[i]);
+ }
+ } break;
+
+ default:
+ continue;
+ }
+ }
+
+ for (List<GDScriptParser::SuiteNode *>::Element *N = function_nodes.front(); N; N = N->next()) {
+ const GDScriptParser::SuiteNode *suite_node = N->get();
+ for (int i = 0; i < suite_node->locals.size(); i++) {
+ const SuiteNode::Local &local = suite_node->locals[i];
+ lsp::DocumentSymbol symbol;
+ symbol.name = local.name;
+ symbol.kind = local.type == SuiteNode::Local::CONSTANT ? lsp::SymbolKind::Constant : lsp::SymbolKind::Variable;
+ symbol.range.start.line = LINE_NUMBER_TO_INDEX(local.start_line);
+ symbol.range.start.character = LINE_NUMBER_TO_INDEX(local.start_column);
+ symbol.range.end.line = LINE_NUMBER_TO_INDEX(local.end_line);
+ symbol.range.end.character = LINE_NUMBER_TO_INDEX(local.end_column);
+ symbol.uri = uri;
+ symbol.script_path = path;
+ symbol.detail = local.type == SuiteNode::Local::CONSTANT ? "const " : "var ";
+ symbol.detail += symbol.name;
+ if (local.get_datatype().is_hard_type()) {
+ symbol.detail += ": " + local.get_datatype().to_string();
+ }
+ symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(local.start_line));
+ r_symbol.children.push_back(symbol);
}
- symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(local.start_line));
- r_symbol.children.push_back(symbol);
}
}
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index 912c9a174e..c16a7fa889 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -32,7 +32,6 @@
#include "core/config/project_settings.h"
#include "core/io/json.h"
-#include "core/os/copymem.h"
#include "editor/doc_tools.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
@@ -256,7 +255,7 @@ void GDScriptLanguageProtocol::poll() {
}
}
-Error GDScriptLanguageProtocol::start(int p_port, const IP_Address &p_bind_ip) {
+Error GDScriptLanguageProtocol::start(int p_port, const IPAddress &p_bind_ip) {
return server->listen(p_port, p_bind_ip);
}
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h
index 8b08ae0655..969c38eab6 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.h
+++ b/modules/gdscript/language_server/gdscript_language_protocol.h
@@ -46,7 +46,7 @@ class GDScriptLanguageProtocol : public JSONRPC {
GDCLASS(GDScriptLanguageProtocol, JSONRPC)
private:
- struct LSPeer : Reference {
+ struct LSPeer : RefCounted {
Ref<StreamPeerTCP> connection;
uint8_t req_buf[LSP_MAX_BUFFER_SIZE];
@@ -69,7 +69,7 @@ private:
static GDScriptLanguageProtocol *singleton;
HashMap<int, Ref<LSPeer>> clients;
- Ref<TCP_Server> server;
+ Ref<TCPServer> server;
int latest_client_id = 0;
int next_client_id = 0;
@@ -97,7 +97,7 @@ public:
_FORCE_INLINE_ bool is_initialized() const { return _initialized; }
void poll();
- Error start(int p_port, const IP_Address &p_bind_ip);
+ Error start(int p_port, const IPAddress &p_bind_ip);
void stop();
void notify_client(const String &p_method, const Variant &p_params = Variant(), int p_client_id = -1);
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index 98ada9de4d..33597c286f 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -30,7 +30,7 @@
#include "gdscript_language_server.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/os.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
@@ -78,7 +78,7 @@ void GDScriptLanguageServer::thread_main(void *p_userdata) {
void GDScriptLanguageServer::start() {
port = (int)_EDITOR_GET("network/language_server/remote_port");
use_thread = (bool)_EDITOR_GET("network/language_server/use_thread");
- if (protocol.start(port, IP_Address("127.0.0.1")) == OK) {
+ if (protocol.start(port, IPAddress("127.0.0.1")) == OK) {
EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR);
if (use_thread) {
thread_running = true;
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 9f2373bf56..030633274c 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -400,6 +400,7 @@ GDScriptTextDocument::~GDScriptTextDocument() {
void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path);
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
+ EditorFileSystem::get_singleton()->update_file(path);
}
void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) {
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index 792e601bc1..17f1d5d5e3 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -31,12 +31,12 @@
#ifndef GDSCRIPT_TEXT_DOCUMENT_H
#define GDSCRIPT_TEXT_DOCUMENT_H
-#include "core/object/reference.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
+#include "core/object/ref_counted.h"
#include "lsp.hpp"
-class GDScriptTextDocument : public Reference {
- GDCLASS(GDScriptTextDocument, Reference)
+class GDScriptTextDocument : public RefCounted {
+ GDCLASS(GDScriptTextDocument, RefCounted)
protected:
static void _bind_methods();
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 69cad1a335..9b7b2b36b4 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -42,6 +42,7 @@
#include "scene/resources/packed_scene.h"
void GDScriptWorkspace::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("didDeleteFiles"), &GDScriptWorkspace::did_delete_files);
ClassDB::bind_method(D_METHOD("symbol"), &GDScriptWorkspace::symbol);
ClassDB::bind_method(D_METHOD("parse_script", "path", "content"), &GDScriptWorkspace::parse_script);
ClassDB::bind_method(D_METHOD("parse_local_script", "path"), &GDScriptWorkspace::parse_local_script);
@@ -51,6 +52,16 @@ void GDScriptWorkspace::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_script_api", "path"), &GDScriptWorkspace::generate_script_api);
}
+void GDScriptWorkspace::did_delete_files(const Dictionary &p_params) {
+ Array files = p_params["files"];
+ for (int i = 0; i < files.size(); ++i) {
+ Dictionary file = files[i];
+ String uri = file["uri"];
+ String path = get_file_path(uri);
+ parse_script(path, "");
+ }
+}
+
void GDScriptWorkspace::remove_cache_parser(const String &p_path) {
Map<String, ExtendGDScriptParser *>::Element *parser = parse_results.find(p_path);
Map<String, ExtendGDScriptParser *>::Element *script = scripts.find(p_path);
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index 7fd8bfcf20..8b166a873c 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -37,8 +37,8 @@
#include "gdscript_extend_parser.h"
#include "lsp.hpp"
-class GDScriptWorkspace : public Reference {
- GDCLASS(GDScriptWorkspace, Reference);
+class GDScriptWorkspace : public RefCounted {
+ GDCLASS(GDScriptWorkspace, RefCounted);
private:
void _get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners);
@@ -89,6 +89,7 @@ public:
void resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list);
Dictionary generate_script_api(const String &p_path);
Error resolve_signature(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::SignatureHelp &r_signature);
+ void did_delete_files(const Dictionary &p_params);
GDScriptWorkspace();
~GDScriptWorkspace();
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index 6635098be2..a7dcfdb22d 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -766,7 +766,7 @@ struct MarkupContent {
// Use namespace instead of enumeration to follow the LSP specifications
// lsp::EnumName::EnumValue is OK but lsp::EnumValue is not
-// And here C++ compilers are unhappy with our enumeration name like Color, File, Reference etc.
+// And here C++ compilers are unhappy with our enumeration name like Color, File, RefCounted etc.
/**
* The kind of a completion entry.
*/
@@ -788,7 +788,7 @@ static const int Keyword = 14;
static const int Snippet = 15;
static const int Color = 16;
static const int File = 17;
-static const int Reference = 18;
+static const int RefCounted = 18;
static const int Folder = 19;
static const int EnumMember = 20;
static const int Constant = 21;
@@ -1528,6 +1528,114 @@ struct SignatureHelp {
}
};
+/**
+ * A pattern to describe in which file operation requests or notifications
+ * the server is interested in.
+ */
+struct FileOperationPattern {
+ /**
+ * The glob pattern to match.
+ */
+ String glob = "**/*.gd";
+
+ /**
+ * Whether to match `file`s or `folder`s with this pattern.
+ *
+ * Matches both if undefined.
+ */
+ String matches = "file";
+
+ Dictionary to_json() const {
+ Dictionary dict;
+
+ dict["glob"] = glob;
+ dict["matches"] = matches;
+
+ return dict;
+ }
+};
+
+/**
+ * A filter to describe in which file operation requests or notifications
+ * the server is interested in.
+ */
+struct FileOperationFilter {
+ /**
+ * The actual file operation pattern.
+ */
+ FileOperationPattern pattern;
+
+ Dictionary to_json() const {
+ Dictionary dict;
+
+ dict["pattern"] = pattern.to_json();
+
+ return dict;
+ }
+};
+
+/**
+ * The options to register for file operations.
+ */
+struct FileOperationRegistrationOptions {
+ /**
+ * The actual filters.
+ */
+ Vector<FileOperationFilter> filters;
+
+ FileOperationRegistrationOptions() {
+ filters.push_back(FileOperationFilter());
+ }
+
+ Dictionary to_json() const {
+ Dictionary dict;
+
+ Array filts;
+ for (int i = 0; i < filters.size(); i++) {
+ filts.push_back(filters[i].to_json());
+ }
+ dict["filters"] = filts;
+
+ return dict;
+ }
+};
+
+/**
+ * The server is interested in file notifications/requests.
+ */
+struct FileOperations {
+ /**
+ * The server is interested in receiving didDeleteFiles file notifications.
+ */
+ FileOperationRegistrationOptions didDelete;
+
+ Dictionary to_json() const {
+ Dictionary dict;
+
+ dict["didDelete"] = didDelete.to_json();
+
+ return dict;
+ }
+};
+
+/**
+ * Workspace specific server capabilities
+ */
+struct Workspace {
+ /**
+ * The server is interested in file notifications/requests.
+ */
+ FileOperations fileOperations;
+
+ Dictionary to_json() const {
+ Dictionary dict;
+
+ dict["fileOperations"] = fileOperations.to_json();
+
+ return dict;
+ }
+};
+
struct ServerCapabilities {
/**
* Defines how text documents are synced. Is either a detailed structure defining each notification or
@@ -1590,6 +1698,11 @@ struct ServerCapabilities {
bool workspaceSymbolProvider = true;
/**
+ * The server supports workspace folder.
+ */
+ Workspace workspace;
+
+ /**
* The server provides code actions. The `CodeActionOptions` return type is only
* valid if the client signals code action literal support via the property
* `textDocument.codeAction.codeActionLiteralSupport`.
@@ -1676,6 +1789,7 @@ struct ServerCapabilities {
dict["documentHighlightProvider"] = documentHighlightProvider;
dict["documentSymbolProvider"] = documentSymbolProvider;
dict["workspaceSymbolProvider"] = workspaceSymbolProvider;
+ dict["workspace"] = workspace.to_json();
dict["codeActionProvider"] = codeActionProvider;
dict["documentFormattingProvider"] = documentFormattingProvider;
dict["documentRangeFormattingProvider"] = documentRangeFormattingProvider;
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 2d2f94f5e0..867142019f 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -30,10 +30,10 @@
#include "register_types.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/resource_loader.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "gdscript.h"
#include "gdscript_analyzer.h"
#include "gdscript_cache.h"
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index f53c3046e6..67bc927517 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -37,8 +37,8 @@
#include "core/config/project_settings.h"
#include "core/core_string_names.h"
+#include "core/io/dir_access.h"
#include "core/io/file_access_pack.h"
-#include "core/os/dir_access.h"
#include "core/os/os.h"
#include "core/string/string_builder.h"
#include "scene/resources/packed_scene.h"
@@ -257,6 +257,7 @@ bool GDScriptTestRunner::make_tests() {
ERR_FAIL_COND_V_MSG(err != OK, false, "Could not open specified test directory.");
+ source_dir = dir->get_current_dir() + "/"; // Make it absolute path.
return make_tests_for_dir(dir->get_current_dir());
}
@@ -361,11 +362,9 @@ void GDScriptTest::error_handler(void *p_this, const char *p_function, const cha
break;
}
- builder.append("\n>> ");
- builder.append(p_function);
- builder.append("\n>> ");
+ builder.append("\n>> on function: ");
builder.append(p_function);
- builder.append("\n>> ");
+ builder.append("()\n>> ");
builder.append(String(p_file).trim_prefix(self->base_dir));
builder.append("\n>> ");
builder.append(itos(p_line));
@@ -441,7 +440,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
result.output = get_text_for_status(result.status) + "\n";
const List<GDScriptParser::ParserError> &errors = parser.get_errors();
- for (auto *E = errors.front(); E; E = E->next()) {
+ for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E; E = E->next()) {
result.output += E->get().message + "\n"; // TODO: line, column?
break; // Only the first error since the following might be cascading.
}
@@ -460,7 +459,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
result.output = get_text_for_status(result.status) + "\n";
const List<GDScriptParser::ParserError> &errors = parser.get_errors();
- for (auto *E = errors.front(); E; E = E->next()) {
+ for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E; E = E->next()) {
result.output += E->get().message + "\n"; // TODO: line, column?
break; // Only the first error since the following might be cascading.
}
@@ -512,9 +511,9 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
// Create object instance for test.
Object *obj = ClassDB::instance(script->get_native()->get_name());
- Ref<Reference> obj_ref;
- if (obj->is_reference()) {
- obj_ref = Ref<Reference>(Object::cast_to<Reference>(obj));
+ Ref<RefCounted> obj_ref;
+ if (obj->is_ref_counted()) {
+ obj_ref = Ref<RefCounted>(Object::cast_to<RefCounted>(obj));
}
obj->set_script(script);
GDScriptInstance *instance = static_cast<GDScriptInstance *>(obj->get_script_instance());
diff --git a/modules/gdscript/tests/gdscript_test_runner_suite.h b/modules/gdscript/tests/gdscript_test_runner_suite.h
index 136907b316..cf4e61f07d 100644
--- a/modules/gdscript/tests/gdscript_test_runner_suite.h
+++ b/modules/gdscript/tests/gdscript_test_runner_suite.h
@@ -48,6 +48,27 @@ TEST_SUITE("[Modules][GDScript]") {
}
}
+TEST_CASE("[Modules][GDScript] Load source code dynamically and run it") {
+ Ref<GDScript> gdscript = memnew(GDScript);
+ gdscript->set_source_code(R"(
+extends RefCounted
+
+func _init():
+ set_meta("result", 42)
+)");
+ // A spurious `Condition "err" is true` message is printed (despite parsing being successful and returning `OK`).
+ // Silence it.
+ ERR_PRINT_OFF;
+ const Error error = gdscript->reload();
+ ERR_PRINT_ON;
+ CHECK_MESSAGE(error == OK, "The script should parse successfully.");
+
+ // Run the script by assigning it to a reference-counted object.
+ Ref<RefCounted> ref_counted = memnew(RefCounted);
+ ref_counted->set_script(gdscript);
+ CHECK_MESSAGE(int(ref_counted->get_meta("result")) == 42, "The script should assign object metadata successfully.");
+}
+
} // namespace GDScriptTests
#endif // GDSCRIPT_TEST_RUNNER_SUITE_H
diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.gd b/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.gd
new file mode 100644
index 0000000000..d21d8bce96
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.gd
@@ -0,0 +1,9 @@
+extends Node
+
+func test():
+ set_name("TestNodeName")
+ if get_name() == &"TestNodeName":
+ print("Name is equal")
+ else:
+ print("Name is not equal")
+ print(get_name() is StringName)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out b/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out
new file mode 100644
index 0000000000..dc4348d9c3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/call_self_get_name.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+Name is equal
+True
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-argument.gd b/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd
index c56ad94095..c56ad94095 100644
--- a/modules/gdscript/tests/scripts/parser-errors/missing-argument.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-argument.out b/modules/gdscript/tests/scripts/parser/errors/missing_argument.out
index fc2a891109..fc2a891109 100644
--- a/modules/gdscript/tests/scripts/parser-errors/missing-argument.out
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_argument.out
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.gd b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd
index a1077e1985..a1077e1985 100644
--- a/modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.out b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.out
index 7326afa33d..7326afa33d 100644
--- a/modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.out
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.out
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-colon.gd b/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd
index 62cb633e9e..62cb633e9e 100644
--- a/modules/gdscript/tests/scripts/parser-errors/missing-colon.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-colon.out b/modules/gdscript/tests/scripts/parser/errors/missing_colon.out
index 687b963bc8..687b963bc8 100644
--- a/modules/gdscript/tests/scripts/parser-errors/missing-colon.out
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_colon.out
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.gd b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd
index 116b0151da..116b0151da 100644
--- a/modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.out b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.out
index 34ea7ac323..34ea7ac323 100644
--- a/modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.out
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.out
diff --git a/modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.gd b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.gd
index 9ad77f1432..9ad77f1432 100644
--- a/modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.gd
diff --git a/modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.out b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out
index 6390de9788..6390de9788 100644
--- a/modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.out
+++ b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out
diff --git a/modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.gd b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd
index 3875ce3936..3875ce3936 100644
--- a/modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd
diff --git a/modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.out b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out
index b3dc181a22..b3dc181a22 100644
--- a/modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.out
+++ b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out
diff --git a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.gd b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd
index 6fd2692d47..6fd2692d47 100644
--- a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd
diff --git a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.out b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out
index b3dc181a22..b3dc181a22 100644
--- a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.out
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out
diff --git a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.gd b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd
index 1836d42226..1836d42226 100644
--- a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd
diff --git a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.out b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out
index dcb4ccecb0..dcb4ccecb0 100644
--- a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.out
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out
diff --git a/modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.gd b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd
index 08f2eedb2d..08f2eedb2d 100644
--- a/modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.gd
+++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd
diff --git a/modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.out b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out
index fc03f3efe8..fc03f3efe8 100644
--- a/modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.out
+++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out
diff --git a/modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.gd b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.gd
index 6097b11b10..6097b11b10 100644
--- a/modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.gd
+++ b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.gd
diff --git a/modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.out b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.out
index 94e2ec2af8..94e2ec2af8 100644
--- a/modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.out
+++ b/modules/gdscript/tests/scripts/parser/features/trailing_comma_in_function_args.out
diff --git a/modules/gdscript/tests/scripts/parser-features/variable-declaration.gd b/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd
index 3b48f10ca7..3b48f10ca7 100644
--- a/modules/gdscript/tests/scripts/parser-features/variable-declaration.gd
+++ b/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd
diff --git a/modules/gdscript/tests/scripts/parser-features/variable-declaration.out b/modules/gdscript/tests/scripts/parser/features/variable_declaration.out
index 2e0a63c024..2e0a63c024 100644
--- a/modules/gdscript/tests/scripts/parser-features/variable-declaration.out
+++ b/modules/gdscript/tests/scripts/parser/features/variable_declaration.out
diff --git a/modules/gdscript/tests/scripts/parser-warnings/unused-variable.gd b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd
index 68e3bd424f..68e3bd424f 100644
--- a/modules/gdscript/tests/scripts/parser-warnings/unused-variable.gd
+++ b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd
diff --git a/modules/gdscript/tests/scripts/parser-warnings/unused-variable.out b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.out
index 270e0e69c0..270e0e69c0 100644
--- a/modules/gdscript/tests/scripts/parser-warnings/unused-variable.out
+++ b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.out
diff --git a/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.gd b/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.gd
new file mode 100644
index 0000000000..10780b5379
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.gd
@@ -0,0 +1,5 @@
+func test():
+ var node := Node.new()
+ var inside_tree = node.is_inside_tree
+ node.free()
+ inside_tree.call()
diff --git a/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.out b/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.out
new file mode 100644
index 0000000000..e585c374e2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/callable_call_after_free_object.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/callable_call_after_free_object.gd
+>> 5
+>> Attempt to call function 'null::is_inside_tree (Callable)' on a null instance.
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index e70f221c0a..c37d52febd 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -31,8 +31,8 @@
#include "test_gdscript.h"
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_pack.h"
-#include "core/os/file_access.h"
#include "core/os/main_loop.h"
#include "core/os/os.h"
#include "core/string/string_builder.h"
@@ -66,7 +66,7 @@ static void test_tokenizer(const String &p_code, const Vector<String> &p_lines)
StringBuilder token;
token += " --> "; // Padding for line number.
- for (int l = current.start_line; l <= current.end_line; l++) {
+ for (int l = current.start_line; l <= current.end_line && l <= p_lines.size(); l++) {
print_line(vformat("%04d %s", l, p_lines[l - 1]).replace("\t", tab));
}
@@ -118,6 +118,18 @@ static void test_parser(const String &p_code, const String &p_script_path, const
print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message));
}
}
+
+ GDScriptAnalyzer analyzer(&parser);
+ analyzer.analyze();
+
+ if (err != OK) {
+ const List<GDScriptParser::ParserError> &errors = parser.get_errors();
+ for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) {
+ const GDScriptParser::ParserError &error = E->get();
+ print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message));
+ }
+ }
+
#ifdef TOOLS_ENABLED
GDScriptParser::TreePrinter printer;
printer.print_tree(parser);
@@ -203,8 +215,8 @@ void test(TestType p_type) {
init_language(fa->get_path_absolute().get_base_dir());
Vector<uint8_t> buf;
- int flen = fa->get_len();
- buf.resize(fa->get_len() + 1);
+ uint64_t flen = fa->get_length();
+ buf.resize(flen + 1);
fa->get_buffer(buf.ptrw(), flen);
buf.write[flen] = 0;
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index 14135265b9..730c6b89f7 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -116,6 +116,10 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
}
}
+ if (p_capabilities->supports_multiview) {
+ preamble += "#define has_VK_KHR_multiview 1\n";
+ }
+
if (preamble != "") {
shader.setPreamble(preamble.c_str());
}
@@ -173,17 +177,24 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
ret.resize(SpirV.size() * sizeof(uint32_t));
{
uint8_t *w = ret.ptrw();
- copymem(w, &SpirV[0], SpirV.size() * sizeof(uint32_t));
+ memcpy(w, &SpirV[0], SpirV.size() * sizeof(uint32_t));
}
return ret;
}
+static String _get_cache_key_function_glsl(const RenderingDevice::Capabilities *p_capabilities) {
+ String version;
+ version = "SpirVGen=" + itos(glslang::GetSpirvGeneratorVersion()) + ", major=" + itos(p_capabilities->version_major) + ", minor=" + itos(p_capabilities->version_minor) + " , subgroup_size=" + itos(p_capabilities->subgroup_operations) + " , subgroup_ops=" + itos(p_capabilities->subgroup_operations) + " , subgroup_in_shaders=" + itos(p_capabilities->subgroup_in_shaders);
+ return version;
+}
+
void preregister_glslang_types() {
// initialize in case it's not initialized. This is done once per thread
// and it's safe to call multiple times
glslang::InitializeProcess();
RenderingDevice::shader_set_compile_function(_compile_shader_glsl);
+ RenderingDevice::shader_set_get_cache_key_function(_get_cache_key_function_glsl);
}
void register_glslang_types() {
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index 5b7d4fadec..5d84d7088b 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -13,8 +13,6 @@
</member>
<member name="children" type="PackedInt32Array" setter="set_children" getter="get_children" default="PackedInt32Array( )">
</member>
- <member name="fake_joint_parent" type="int" setter="set_fake_joint_parent" getter="get_fake_joint_parent" default="-1">
- </member>
<member name="height" type="int" setter="set_height" getter="get_height" default="-1">
</member>
<member name="joint" type="bool" setter="set_joint" getter="get_joint" default="false">
@@ -25,7 +23,7 @@
</member>
<member name="parent" type="int" setter="set_parent" getter="get_parent" default="-1">
</member>
- <member name="rotation" type="Quat" setter="set_rotation" getter="get_rotation" default="Quat( 0, 0, 0, 1 )">
+ <member name="rotation" type="Quaternion" setter="set_rotation" getter="get_rotation" default="Quaternion( 0, 0, 0, 1 )">
</member>
<member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3( 1, 1, 1 )">
</member>
@@ -35,7 +33,7 @@
</member>
<member name="translation" type="Vector3" setter="set_translation" getter="get_translation" default="Vector3( 0, 0, 0 )">
</member>
- <member name="xform" type="Transform" setter="set_xform" getter="get_xform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ <member name="xform" type="Transform3D" setter="set_xform" getter="get_xform" default="Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
</member>
</members>
<constants>
diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp
index 35f44ca122..21b4bb75fb 100644
--- a/modules/gltf/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor_scene_importer_gltf.cpp
@@ -29,10 +29,10 @@
/*************************************************************************/
#include "core/crypto/crypto_core.h"
+#include "core/io/file_access.h"
#include "core/io/json.h"
#include "core/math/disjoint_set.h"
#include "core/math/math_defs.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "editor/import/resource_importer_scene.h"
#include "modules/gltf/gltf_state.h"
diff --git a/modules/gltf/gltf_animation.h b/modules/gltf/gltf_animation.h
index a494e6bd67..216d2161c4 100644
--- a/modules/gltf/gltf_animation.h
+++ b/modules/gltf/gltf_animation.h
@@ -56,7 +56,7 @@ public:
struct Track {
Channel<Vector3> translation_track;
- Channel<Quat> rotation_track;
+ Channel<Quaternion> rotation_track;
Channel<Vector3> scale_track;
Vector<Channel<float>> weight_tracks;
};
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 027a054b70..988a75ac93 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -49,9 +49,9 @@
#include "core/core_bind.h"
#include "core/crypto/crypto_core.h"
+#include "core/io/file_access.h"
#include "core/io/json.h"
#include "core/math/disjoint_set.h"
-#include "core/os/file_access.h"
#include "core/variant/typed_array.h"
#include "core/version.h"
#include "core/version_hash.gen.h"
@@ -233,7 +233,7 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
}
Vector<uint8_t> array;
- array.resize(f->get_len());
+ array.resize(f->get_length());
f->get_buffer(array.ptrw(), array.size());
String text;
text.parse_utf8((const char *)array.ptr(), array.size());
@@ -342,25 +342,25 @@ static Vector3 _arr_to_vec3(const Array &p_array) {
return Vector3(p_array[0], p_array[1], p_array[2]);
}
-static Array _quat_to_array(const Quat &p_quat) {
+static Array _quaternion_to_array(const Quaternion &p_quaternion) {
Array array;
array.resize(4);
- array[0] = p_quat.x;
- array[1] = p_quat.y;
- array[2] = p_quat.z;
- array[3] = p_quat.w;
+ array[0] = p_quaternion.x;
+ array[1] = p_quaternion.y;
+ array[2] = p_quaternion.z;
+ array[3] = p_quaternion.w;
return array;
}
-static Quat _arr_to_quat(const Array &p_array) {
- ERR_FAIL_COND_V(p_array.size() != 4, Quat());
- return Quat(p_array[0], p_array[1], p_array[2], p_array[3]);
+static Quaternion _arr_to_quaternion(const Array &p_array) {
+ ERR_FAIL_COND_V(p_array.size() != 4, Quaternion());
+ return Quaternion(p_array[0], p_array[1], p_array[2], p_array[3]);
}
-static Transform _arr_to_xform(const Array &p_array) {
- ERR_FAIL_COND_V(p_array.size() != 16, Transform());
+static Transform3D _arr_to_xform(const Array &p_array) {
+ ERR_FAIL_COND_V(p_array.size() != 16, Transform3D());
- Transform xform;
+ Transform3D xform;
xform.basis.set_axis(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2]));
xform.basis.set_axis(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6]));
xform.basis.set_axis(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10]));
@@ -369,7 +369,7 @@ static Transform _arr_to_xform(const Array &p_array) {
return xform;
}
-static Vector<real_t> _xform_to_array(const Transform p_transform) {
+static Vector<real_t> _xform_to_array(const Transform3D p_transform) {
Vector<real_t> array;
array.resize(16);
Vector3 axis_x = p_transform.get_basis().get_axis(Vector3::AXIS_X);
@@ -421,12 +421,12 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
}
if (n->skeleton != -1 && n->skin < 0) {
}
- if (n->xform != Transform()) {
+ if (n->xform != Transform3D()) {
node["matrix"] = _xform_to_array(n->xform);
}
- if (!n->rotation.is_equal_approx(Quat())) {
- node["rotation"] = _quat_to_array(n->rotation);
+ if (!n->rotation.is_equal_approx(Quaternion())) {
+ node["rotation"] = _quaternion_to_array(n->rotation);
}
if (!n->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) {
@@ -591,13 +591,13 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) {
node->translation = _arr_to_vec3(n["translation"]);
}
if (n.has("rotation")) {
- node->rotation = _arr_to_quat(n["rotation"]);
+ node->rotation = _arr_to_quaternion(n["rotation"]);
}
if (n.has("scale")) {
node->scale = _arr_to_vec3(n["scale"]);
}
- node->xform.basis.set_quat_scale(node->rotation, node->scale);
+ node->xform.basis.set_quaternion_scale(node->rotation, node->scale);
node->xform.origin = node->translation;
}
@@ -664,7 +664,7 @@ static Vector<uint8_t> _parse_base64_uri(const String &uri) {
int start = uri.find(",");
ERR_FAIL_COND_V(start == -1, Vector<uint8_t>());
- CharString substr = uri.right(start + 1).ascii();
+ CharString substr = uri.substr(start + 1).ascii();
int strlen = substr.length();
@@ -1157,7 +1157,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
}
int64_t old_size = gltf_buffer.size();
gltf_buffer.resize(old_size + (buffer.size() * sizeof(int8_t)));
- copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int8_t));
+ memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int8_t));
bv->byte_length = buffer.size() * sizeof(int8_t);
} break;
case COMPONENT_TYPE_UNSIGNED_BYTE: {
@@ -1203,7 +1203,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
}
int64_t old_size = gltf_buffer.size();
gltf_buffer.resize(old_size + (buffer.size() * sizeof(int16_t)));
- copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int16_t));
+ memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int16_t));
bv->byte_length = buffer.size() * sizeof(int16_t);
} break;
case COMPONENT_TYPE_UNSIGNED_SHORT: {
@@ -1227,7 +1227,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
}
int64_t old_size = gltf_buffer.size();
gltf_buffer.resize(old_size + (buffer.size() * sizeof(uint16_t)));
- copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(uint16_t));
+ memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(uint16_t));
bv->byte_length = buffer.size() * sizeof(uint16_t);
} break;
case COMPONENT_TYPE_INT: {
@@ -1247,7 +1247,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
}
int64_t old_size = gltf_buffer.size();
gltf_buffer.resize(old_size + (buffer.size() * sizeof(int32_t)));
- copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int32_t));
+ memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(int32_t));
bv->byte_length = buffer.size() * sizeof(int32_t);
} break;
case COMPONENT_TYPE_FLOAT: {
@@ -1267,7 +1267,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src,
}
int64_t old_size = gltf_buffer.size();
gltf_buffer.resize(old_size + (buffer.size() * sizeof(float)));
- copymem(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(float));
+ memcpy(gltf_buffer.ptrw() + old_size, buffer.ptrw(), buffer.size() * sizeof(float));
bv->byte_length = buffer.size() * sizeof(float);
} break;
}
@@ -1779,7 +1779,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state,
return state->accessors.size() - 1;
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quats(Ref<GLTFState> state, const Vector<Quat> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> state, const Vector<Quaternion> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -1794,11 +1794,11 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quats(Ref<GLTFState> state,
Vector<double> type_min;
type_min.resize(element_count);
for (int i = 0; i < p_attribs.size(); i++) {
- Quat quat = p_attribs[i];
- attribs.write[(i * element_count) + 0] = Math::snapped(quat.x, CMP_NORMALIZE_TOLERANCE);
- attribs.write[(i * element_count) + 1] = Math::snapped(quat.y, CMP_NORMALIZE_TOLERANCE);
- attribs.write[(i * element_count) + 2] = Math::snapped(quat.z, CMP_NORMALIZE_TOLERANCE);
- attribs.write[(i * element_count) + 3] = Math::snapped(quat.w, CMP_NORMALIZE_TOLERANCE);
+ Quaternion quaternion = p_attribs[i];
+ attribs.write[(i * element_count) + 0] = Math::snapped(quaternion.x, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 1] = Math::snapped(quaternion.y, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 2] = Math::snapped(quaternion.z, CMP_NORMALIZE_TOLERANCE);
+ attribs.write[(i * element_count) + 3] = Math::snapped(quaternion.w, CMP_NORMALIZE_TOLERANCE);
_calc_accessor_min_max(i, element_count, type_max, attribs, type_min);
}
@@ -1939,7 +1939,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c
return state->accessors.size() - 1;
}
-GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, const Vector<Transform> p_attribs, const bool p_for_vertex) {
+GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) {
if (p_attribs.size() == 0) {
return -1;
}
@@ -1953,7 +1953,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state,
Vector<double> type_min;
type_min.resize(element_count);
for (int i = 0; i < p_attribs.size(); i++) {
- Transform attrib = p_attribs[i];
+ Transform3D attrib = p_attribs[i];
Basis basis = attrib.get_basis();
Vector3 axis_0 = basis.get_axis(Vector3::AXIS_X);
@@ -2053,9 +2053,9 @@ Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, cons
}
return ret;
}
-Vector<Quat> GLTFDocument::_decode_accessor_as_quat(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
- Vector<Quat> ret;
+ Vector<Quaternion> ret;
if (attribs.size() == 0) {
return ret;
@@ -2067,7 +2067,7 @@ Vector<Quat> GLTFDocument::_decode_accessor_as_quat(Ref<GLTFState> state, const
ret.resize(ret_size);
{
for (int i = 0; i < ret_size; i++) {
- ret.write[i] = Quat(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized();
+ ret.write[i] = Quaternion(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized();
}
}
return ret;
@@ -2107,9 +2107,9 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons
return ret;
}
-Vector<Transform> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
+Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) {
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
- Vector<Transform> ret;
+ Vector<Transform3D> ret;
if (attribs.size() == 0) {
return ret;
@@ -2389,9 +2389,9 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
for (int i = 0; i < ret_size; i++) {
Color tangent;
tangent.r = tarr[(i * 4) + 0];
- tangent.r = tarr[(i * 4) + 1];
- tangent.r = tarr[(i * 4) + 2];
- tangent.r = tarr[(i * 4) + 3];
+ tangent.g = tarr[(i * 4) + 1];
+ tangent.b = tarr[(i * 4) + 2];
+ tangent.a = tarr[(i * 4) + 3];
}
t["TANGENT"] = _encode_accessor_as_color(state, attribs, true);
}
@@ -2653,10 +2653,10 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
//must generate mikktspace tangents.. ergh..
Ref<SurfaceTool> st;
st.instance();
+ st->create_from_triangle_arrays(array);
if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
}
- st->create_from_triangle_arrays(array);
st->generate_tangents();
array = st->commit_to_arrays();
}
@@ -2772,10 +2772,10 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
if (generate_tangents) {
Ref<SurfaceTool> st;
st.instance();
+ st->create_from_triangle_arrays(array_copy);
if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
}
- st->create_from_triangle_arrays(array_copy);
st->deindex();
st->generate_tangents();
array_copy = st->commit_to_arrays();
@@ -2821,8 +2821,8 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
}
blend_weights.write[j] = weights[j];
}
- mesh->set_blend_weights(blend_weights);
}
+ mesh->set_blend_weights(blend_weights);
mesh->set_mesh(import_mesh);
state->meshes.push_back(mesh);
@@ -2864,7 +2864,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
bv->byte_length = buffer.size();
state->buffers.write[bi].resize(state->buffers[bi].size() + bv->byte_length);
- copymem(&state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size());
+ memcpy(&state->buffers.write[bi].write[bv->byte_offset], buffer.ptr(), buffer.size());
ERR_FAIL_COND_V(bv->byte_offset + bv->byte_length > state->buffers[bi].size(), ERR_FILE_CORRUPT);
state->buffer_views.push_back(bv);
@@ -3031,8 +3031,11 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat
}
}
- ERR_FAIL_COND_V_MSG(img.is_null(), ERR_FILE_CORRUPT,
- vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s.", i, mimetype));
+ if (img.is_null()) {
+ ERR_PRINT(vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s.", i, mimetype));
+ state->images.push_back(Ref<Texture2D>());
+ continue;
+ }
Ref<ImageTexture> t;
t.instance();
@@ -4105,81 +4108,10 @@ Error GLTFDocument::_reparent_non_joint_skeleton_subtrees(Ref<GLTFState> state,
subtree_set.get_members(subtree_nodes, subtree_root);
for (int subtree_i = 0; subtree_i < subtree_nodes.size(); ++subtree_i) {
- ERR_FAIL_COND_V(_reparent_to_fake_joint(state, skeleton, subtree_nodes[subtree_i]), FAILED);
-
- // We modified the tree, recompute all the heights
- _compute_node_heights(state);
- }
- }
-
- return OK;
-}
-
-Error GLTFDocument::_reparent_to_fake_joint(Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton, const GLTFNodeIndex node_index) {
- Ref<GLTFNode> node = state->nodes[node_index];
-
- // Can we just "steal" this joint if it is just a spatial node?
- if (node->skin < 0 && node->mesh < 0 && node->camera < 0) {
- node->joint = true;
- // Add the joint to the skeletons joints
- skeleton->joints.push_back(node_index);
- return OK;
- }
-
- GLTFNode *fake_joint = memnew(GLTFNode);
- const GLTFNodeIndex fake_joint_index = state->nodes.size();
- state->nodes.push_back(fake_joint);
-
- // We better not be a joint, or we messed up in our logic
- if (node->joint) {
- return FAILED;
- }
-
- fake_joint->translation = node->translation;
- fake_joint->rotation = node->rotation;
- fake_joint->scale = node->scale;
- fake_joint->xform = node->xform;
- fake_joint->joint = true;
-
- // We can use the exact same name here, because the joint will be inside a skeleton and not the scene
- fake_joint->set_name(node->get_name());
-
- // Clear the nodes transforms, since it will be parented to the fake joint
- node->translation = Vector3(0, 0, 0);
- node->rotation = Quat();
- node->scale = Vector3(1, 1, 1);
- node->xform = Transform();
-
- // Transfer the node children to the fake joint
- for (int child_i = 0; child_i < node->children.size(); ++child_i) {
- Ref<GLTFNode> child = state->nodes[node->children[child_i]];
- child->parent = fake_joint_index;
- }
-
- fake_joint->children = node->children;
- node->children.clear();
-
- // add the fake joint to the parent and remove the original joint
- if (node->parent >= 0) {
- Ref<GLTFNode> parent = state->nodes[node->parent];
- parent->children.erase(node_index);
- parent->children.push_back(fake_joint_index);
- fake_joint->parent = node->parent;
- }
-
- // Add the node to the fake joint
- fake_joint->children.push_back(node_index);
- node->parent = fake_joint_index;
- node->fake_joint_parent = fake_joint_index;
-
- // Add the fake joint to the skeletons joints
- skeleton->joints.push_back(fake_joint_index);
-
- // Replace skin_skeletons with fake joints if we must.
- for (GLTFSkinIndex skin_i = 0; skin_i < state->skins.size(); ++skin_i) {
- Ref<GLTFSkin> skin = state->skins.write[skin_i];
- if (skin->skin_root == node_index) {
- skin->skin_root = fake_joint_index;
+ Ref<GLTFNode> node = state->nodes[subtree_nodes[subtree_i]];
+ node->joint = true;
+ // Add the joint to the skeletons joints
+ skeleton->joints.push_back(subtree_nodes[subtree_i]);
}
}
@@ -4347,7 +4279,7 @@ Error GLTFDocument::_create_skins(Ref<GLTFState> state) {
GLTFNodeIndex node = gltf_skin->joints_original[joint_i];
String bone_name = state->nodes[node]->get_name();
- Transform xform;
+ Transform3D xform;
if (has_ibms) {
xform = gltf_skin->inverse_binds[joint_i];
}
@@ -4387,9 +4319,12 @@ bool GLTFDocument::_skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_
if (skin_a->get_bind_bone(i) != skin_b->get_bind_bone(i)) {
return false;
}
+ if (skin_a->get_bind_name(i) != skin_b->get_bind_name(i)) {
+ return false;
+ }
- Transform a_xform = skin_a->get_bind_pose(i);
- Transform b_xform = skin_b->get_bind_pose(i);
+ Transform3D a_xform = skin_a->get_bind_pose(i);
+ Transform3D b_xform = skin_b->get_bind_pose(i);
if (a_xform != b_xform) {
return false;
@@ -4672,8 +4607,8 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
s["interpolation"] = interpolation_to_string(track.rotation_track.interpolation);
Vector<real_t> times = Variant(track.rotation_track.times);
s["input"] = _encode_accessor_as_floats(state, times, false);
- Vector<Quat> values = track.rotation_track.values;
- s["output"] = _encode_accessor_as_quats(state, values, false);
+ Vector<Quaternion> values = track.rotation_track.values;
+ s["output"] = _encode_accessor_as_quaternions(state, values, false);
samplers.push_back(s);
@@ -4842,7 +4777,7 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
track->translation_track.times = Variant(times); //convert via variant
track->translation_track.values = Variant(translations); //convert via variant
} else if (path == "rotation") {
- const Vector<Quat> rotations = _decode_accessor_as_quat(state, output, false);
+ const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(state, output, false);
track->rotation_track.interpolation = interp;
track->rotation_track.times = Variant(times); //convert via variant
track->rotation_track.values = rotations;
@@ -4914,10 +4849,9 @@ void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) {
}
}
-BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state, Skeleton3D *skeleton, const GLTFNodeIndex node_index) {
+BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state, Skeleton3D *skeleton, const GLTFNodeIndex node_index, const GLTFNodeIndex bone_index) {
Ref<GLTFNode> gltf_node = state->nodes[node_index];
- Ref<GLTFNode> bone_node = state->nodes[gltf_node->parent];
-
+ Ref<GLTFNode> bone_node = state->nodes[bone_index];
BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D);
print_verbose("glTF: Creating bone attachment for: " + gltf_node->get_name());
@@ -5002,7 +4936,7 @@ EditorSceneImporterMeshNode3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFSta
return mi;
}
-Light3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
+Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
Ref<GLTFNode> gltf_node = state->nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->light, state->lights.size(), nullptr);
@@ -5051,7 +4985,7 @@ Light3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent,
light->set_param(SpotLight3D::PARAM_SPOT_ATTENUATION, angle_attenuation);
return light;
}
- return nullptr;
+ return memnew(Node3D);
}
Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
@@ -5141,9 +5075,9 @@ GLTFSkeletonIndex GLTFDocument::_convert_skeleton(Ref<GLTFState> state, Skeleton
}
void GLTFDocument::_convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node) {
- Transform xform = p_spatial->get_transform();
+ Transform3D xform = p_spatial->get_transform();
p_node->scale = xform.basis.get_scale();
- p_node->rotation = xform.basis.get_rotation_quat();
+ p_node->rotation = xform.basis.get_rotation_quaternion();
p_node->translation = xform.origin;
}
@@ -5306,7 +5240,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(Node *p_scene_parent, const GLTFNod
Vector3(cell_location.x, cell_location.y, cell_location.z));
EditorSceneImporterMeshNode3D *import_mesh_node = memnew(EditorSceneImporterMeshNode3D);
import_mesh_node->set_mesh(grid_map->get_mesh_library()->get_item_mesh(cell));
- Transform cell_xform;
+ Transform3D cell_xform;
cell_xform.basis.set_orthogonal_index(
grid_map->get_cell_item_orientation(
Vector3(cell_location.x, cell_location.y, cell_location.z)));
@@ -5334,15 +5268,15 @@ void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, con
for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count();
instance_i++) {
GLTFNode *new_gltf_node = memnew(GLTFNode);
- Transform transform;
+ Transform3D transform;
if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) {
Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i);
transform.origin =
Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y);
real_t rotation = xform_2d.get_rotation();
- Quat quat(Vector3(0, 1, 0), rotation);
+ Quaternion quaternion(Vector3(0, 1, 0), rotation);
Size2 scale = xform_2d.get_scale();
- transform.basis.set_quat_scale(quat,
+ transform.basis.set_quaternion_scale(quaternion,
Vector3(scale.x, 0, scale.y));
transform =
multi_mesh_instance->get_transform() * transform;
@@ -5423,31 +5357,22 @@ void GLTFDocument::_convert_mesh_to_gltf(Node *p_scene_parent, Ref<GLTFState> st
void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) {
Ref<GLTFNode> gltf_node = state->nodes[node_index];
+ if (gltf_node->skeleton >= 0) {
+ _generate_skeleton_bone_node(state, scene_parent, scene_root, node_index);
+ return;
+ }
+
Node3D *current_node = nullptr;
// Is our parent a skeleton
Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(scene_parent);
- if (gltf_node->skeleton >= 0) {
- Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton;
+ const bool non_bone_parented_to_skeleton = active_skeleton;
- if (active_skeleton != skeleton) {
- ERR_FAIL_COND_MSG(active_skeleton != nullptr, "glTF: Generating scene detected direct parented Skeletons");
-
- // Add it to the scene if it has not already been added
- if (skeleton->get_parent() == nullptr) {
- scene_parent->add_child(skeleton);
- skeleton->set_owner(scene_root);
- }
- }
-
- active_skeleton = skeleton;
- current_node = skeleton;
- }
-
- // 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) {
- BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index);
+ // skinned meshes must not be placed in a bone attachment.
+ if (non_bone_parented_to_skeleton && gltf_node->skin < 0) {
+ // Bone Attachment - Parent Case
+ BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent);
scene_parent->add_child(bone_attachment);
bone_attachment->set_owner(scene_root);
@@ -5461,7 +5386,86 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
}
// We still have not managed to make a node
- if (current_node == nullptr) {
+ if (gltf_node->mesh >= 0) {
+ current_node = _generate_mesh_instance(state, scene_parent, node_index);
+ } else if (gltf_node->camera >= 0) {
+ current_node = _generate_camera(state, scene_parent, node_index);
+ } else if (gltf_node->light >= 0) {
+ current_node = _generate_light(state, scene_parent, node_index);
+ } else {
+ current_node = _generate_spatial(state, scene_parent, node_index);
+ }
+
+ scene_parent->add_child(current_node);
+ if (current_node != scene_root) {
+ current_node->set_owner(scene_root);
+ }
+ current_node->set_transform(gltf_node->xform);
+ current_node->set_name(gltf_node->get_name());
+
+ state->scene_nodes.insert(node_index, current_node);
+
+ for (int i = 0; i < gltf_node->children.size(); ++i) {
+ _generate_scene_node(state, current_node, scene_root, gltf_node->children[i]);
+ }
+}
+
+void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) {
+ Ref<GLTFNode> gltf_node = state->nodes[node_index];
+
+ Node3D *current_node = nullptr;
+
+ Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton;
+ // In this case, this node is already a bone in skeleton.
+ const bool is_skinned_mesh = (gltf_node->skin >= 0 && gltf_node->mesh >= 0);
+ const bool requires_extra_node = (gltf_node->mesh >= 0 || gltf_node->camera >= 0 || gltf_node->light >= 0);
+
+ Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(scene_parent);
+ if (active_skeleton != skeleton) {
+ if (active_skeleton) {
+ // Bone Attachment - Direct Parented Skeleton Case
+ BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent);
+
+ scene_parent->add_child(bone_attachment);
+ bone_attachment->set_owner(scene_root);
+
+ // There is no gltf_node that represent this, so just directly create a unique name
+ bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D"));
+
+ // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
+ // and attach it to the bone_attachment
+ scene_parent = bone_attachment;
+ WARN_PRINT(vformat("glTF: Generating scene detected direct parented Skeletons at node %d", node_index));
+ }
+
+ // Add it to the scene if it has not already been added
+ if (skeleton->get_parent() == nullptr) {
+ scene_parent->add_child(skeleton);
+ skeleton->set_owner(scene_root);
+ }
+ }
+
+ active_skeleton = skeleton;
+ current_node = skeleton;
+
+ if (requires_extra_node) {
+ // skinned meshes must not be placed in a bone attachment.
+ if (!is_skinned_mesh) {
+ // Bone Attachment - Same Node Case
+ BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, node_index);
+
+ scene_parent->add_child(bone_attachment);
+ bone_attachment->set_owner(scene_root);
+
+ // There is no gltf_node that represent this, so just directly create a unique name
+ bone_attachment->set_name(_gen_unique_name(state, "BoneAttachment3D"));
+
+ // We change the scene_parent to our bone attachment now. We do not set current_node because we want to make the node
+ // and attach it to the bone_attachment
+ scene_parent = bone_attachment;
+ }
+
+ // We still have not managed to make a node
if (gltf_node->mesh >= 0) {
current_node = _generate_mesh_instance(state, scene_parent, node_index);
} else if (gltf_node->camera >= 0) {
@@ -5470,22 +5474,18 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
current_node = _generate_light(state, scene_parent, node_index);
}
- if (!current_node) {
- current_node = _generate_spatial(state, scene_parent, node_index);
- }
-
scene_parent->add_child(current_node);
if (current_node != scene_root) {
current_node->set_owner(scene_root);
}
- current_node->set_transform(gltf_node->xform);
+ // Do not set transform here. Transform is already applied to our bone.
current_node->set_name(gltf_node->get_name());
}
state->scene_nodes.insert(node_index, current_node);
for (int i = 0; i < gltf_node->children.size(); ++i) {
- _generate_scene_node(state, current_node, scene_root, gltf_node->children[i]);
+ _generate_scene_node(state, active_skeleton, scene_root, gltf_node->children[i]);
}
}
@@ -5516,24 +5516,24 @@ struct EditorSceneImporterGLTFInterpolate {
// thank you for existing, partial specialization
template <>
-struct EditorSceneImporterGLTFInterpolate<Quat> {
- Quat lerp(const Quat &a, const Quat &b, const float c) const {
- ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quat(), "The quaternion \"a\" must be normalized.");
- ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quat(), "The quaternion \"b\" must be normalized.");
+struct EditorSceneImporterGLTFInterpolate<Quaternion> {
+ Quaternion lerp(const Quaternion &a, const Quaternion &b, const float c) const {
+ ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quaternion(), "The quaternion \"a\" must be normalized.");
+ ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quaternion(), "The quaternion \"b\" must be normalized.");
return a.slerp(b, c).normalized();
}
- Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, const float c) {
- ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quat(), "The quaternion \"p1\" must be normalized.");
- ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quat(), "The quaternion \"p2\" must be normalized.");
+ Quaternion catmull_rom(const Quaternion &p0, const Quaternion &p1, const Quaternion &p2, const Quaternion &p3, const float c) {
+ ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quaternion(), "The quaternion \"p1\" must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quaternion(), "The quaternion \"p2\" must be normalized.");
return p1.slerp(p2, c).normalized();
}
- Quat bezier(const Quat start, const Quat control_1, const Quat control_2, const Quat end, const float t) {
- ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quat(), "The start quaternion must be normalized.");
- ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quat(), "The end quaternion must be normalized.");
+ Quaternion bezier(const Quaternion start, const Quaternion control_1, const Quaternion control_2, const Quaternion end, const float t) {
+ ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quaternion(), "The start quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
return start.slerp(end, t).normalized();
}
@@ -5626,28 +5626,30 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
for (Map<int, GLTFAnimation::Track>::Element *track_i = anim->get_tracks().front(); track_i; track_i = track_i->next()) {
const GLTFAnimation::Track &track = track_i->get();
- //need to find the path
+ //need to find the path: for skeletons, weight tracks will affect the mesh
NodePath node_path;
+ //for skeletons, transform tracks always affect bones
+ NodePath transform_node_path;
GLTFNodeIndex node_index = track_i->key();
- if (state->nodes[node_index]->fake_joint_parent >= 0) {
- // Should be same as parent
- node_index = state->nodes[node_index]->fake_joint_parent;
- }
const Ref<GLTFNode> gltf_node = state->nodes[track_i->key()];
+ Node *root = ap->get_parent();
+ ERR_FAIL_COND(root == nullptr);
+ Map<GLTFNodeIndex, Node *>::Element *node_element = state->scene_nodes.find(node_index);
+ ERR_CONTINUE_MSG(node_element == nullptr, vformat("Unable to find node %d for animation", node_index));
+ node_path = root->get_path_to(node_element->get());
+
if (gltf_node->skeleton >= 0) {
- const Skeleton3D *sk = Object::cast_to<Skeleton3D>(state->scene_nodes.find(node_index)->get());
+ const Skeleton3D *sk = state->skeletons[gltf_node->skeleton]->godot_skeleton;
ERR_FAIL_COND(sk == nullptr);
const String path = ap->get_parent()->get_path_to(sk);
const String bone = gltf_node->get_name();
- node_path = path + ":" + bone;
+ transform_node_path = path + ":" + bone;
} else {
- Node *root = ap->get_parent();
- Node *godot_node = state->scene_nodes.find(node_index)->get();
- node_path = root->get_path_to(godot_node);
+ transform_node_path = node_path;
}
for (int i = 0; i < track.rotation_track.times.size(); i++) {
@@ -5666,18 +5668,20 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
}
- if (track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) {
+ // Animated TRS properties will not affect a skinned mesh.
+ const bool transform_affects_skinned_mesh_instance = gltf_node->skeleton < 0 && gltf_node->skin >= 0;
+ if ((track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) && !transform_affects_skinned_mesh_instance) {
//make transform track
int track_idx = animation->get_track_count();
- animation->add_track(Animation::TYPE_TRANSFORM);
- animation->track_set_path(track_idx, node_path);
+ animation->add_track(Animation::TYPE_TRANSFORM3D);
+ animation->track_set_path(track_idx, transform_node_path);
//first determine animation length
const double increment = 1.0 / bake_fps;
double time = 0.0;
Vector3 base_pos;
- Quat base_rot;
+ Quaternion base_rot;
Vector3 base_scale = Vector3(1, 1, 1);
if (!track.rotation_track.values.size()) {
@@ -5695,7 +5699,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
bool last = false;
while (true) {
Vector3 pos = base_pos;
- Quat rot = base_rot;
+ Quaternion rot = base_rot;
Vector3 scale = base_scale;
if (track.translation_track.times.size()) {
@@ -5703,7 +5707,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
if (track.rotation_track.times.size()) {
- rot = _interpolate_track<Quat>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation);
+ rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation);
}
if (track.scale_track.times.size()) {
@@ -5711,15 +5715,15 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
if (gltf_node->skeleton >= 0) {
- Transform xform;
- xform.basis.set_quat_scale(rot, scale);
+ Transform3D xform;
+ xform.basis.set_quaternion_scale(rot, scale);
xform.origin = pos;
const Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton;
const int bone_idx = skeleton->find_bone(gltf_node->get_name());
xform = skeleton->get_bone_rest(bone_idx).affine_inverse() * xform;
- rot = xform.basis.get_rotation_quat();
+ rot = xform.basis.get_rotation_quaternion();
rot.normalize();
scale = xform.basis.get_scale();
pos = xform.origin;
@@ -5804,9 +5808,9 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
}
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get());
ERR_CONTINUE(!mi);
- Transform mi_xform = mi->get_transform();
+ Transform3D mi_xform = mi->get_transform();
node->scale = mi_xform.basis.get_scale();
- node->rotation = mi_xform.basis.get_rotation_quat();
+ node->rotation = mi_xform.basis.get_rotation_quaternion();
node->translation = mi_xform.origin;
Dictionary json_skin;
@@ -5868,9 +5872,9 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
String gltf_bone_name = _gen_unique_bone_name(state, skeleton_gltf_i, godot_bone_name);
joint_node->set_name(gltf_bone_name);
- Transform bone_rest_xform = skeleton->get_bone_rest(bone_index);
+ Transform3D bone_rest_xform = skeleton->get_bone_rest(bone_index);
joint_node->scale = bone_rest_xform.basis.get_scale();
- joint_node->rotation = bone_rest_xform.basis.get_rotation_quat();
+ joint_node->rotation = bone_rest_xform.basis.get_rotation_quaternion();
joint_node->translation = bone_rest_xform.origin;
joint_node->joint = true;
@@ -5975,13 +5979,15 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo
const GLTFSkinIndex skin_i = node->skin;
Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(node_i);
+ ERR_CONTINUE_MSG(mi_element == nullptr, vformat("Unable to find node %d", node_i));
+
EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(mi_element->get());
- ERR_FAIL_COND(mi == nullptr);
+ ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to EditorSceneImporterMeshNode3D", node_i, mi_element->get()->get_class_name()));
const GLTFSkeletonIndex skel_i = state->skins.write[node->skin]->skeleton;
Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i];
Skeleton3D *skeleton = gltf_skeleton->godot_skeleton;
- ERR_FAIL_COND(skeleton == nullptr);
+ ERR_CONTINUE_MSG(skeleton == nullptr, vformat("Unable to find Skeleton for node %d skin %d", node_i, skin_i));
mi->get_parent()->remove_child(mi);
skeleton->add_child(mi);
@@ -5989,12 +5995,12 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo
mi->set_skin(state->skins.write[skin_i]->godot_skin);
mi->set_skeleton_path(mi->get_path_to(skeleton));
- mi->set_transform(Transform());
+ mi->set_transform(Transform3D());
}
}
}
-GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, Transform p_bone_rest, int32_t p_track_i, GLTFNodeIndex p_node_i) {
+GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, Transform3D p_bone_rest, int32_t p_track_i, GLTFNodeIndex p_node_i) {
Animation::InterpolationType interpolation = p_animation->track_get_interpolation_type(p_track_i);
GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
@@ -6014,7 +6020,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i);
}
const float BAKE_FPS = 30.0f;
- if (track_type == Animation::TYPE_TRANSFORM) {
+ if (track_type == Animation::TYPE_TRANSFORM3D) {
p_track.translation_track.times = times;
p_track.translation_track.interpolation = gltf_interpolation;
p_track.rotation_track.times = times;
@@ -6030,16 +6036,16 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
p_track.rotation_track.interpolation = gltf_interpolation;
for (int32_t key_i = 0; key_i < key_count; key_i++) {
Vector3 translation;
- Quat rotation;
+ Quaternion rotation;
Vector3 scale;
Error err = p_animation->transform_track_get_key(p_track_i, key_i, &translation, &rotation, &scale);
ERR_CONTINUE(err != OK);
- Transform xform;
- xform.basis.set_quat_scale(rotation, scale);
+ Transform3D xform;
+ xform.basis.set_quaternion_scale(rotation, scale);
xform.origin = translation;
xform = p_bone_rest * xform;
p_track.translation_track.values.write[key_i] = xform.get_origin();
- p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quat();
+ p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quaternion();
p_track.scale_track.values.write[key_i] = xform.basis.get_scale();
}
} else if (path.find(":transform") != -1) {
@@ -6057,9 +6063,9 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
p_track.rotation_track.values.resize(key_count);
p_track.rotation_track.interpolation = gltf_interpolation;
for (int32_t key_i = 0; key_i < key_count; key_i++) {
- Transform xform = p_animation->track_get_key_value(p_track_i, key_i);
+ Transform3D xform = p_animation->track_get_key_value(p_track_i, key_i);
p_track.translation_track.values.write[key_i] = xform.get_origin();
- p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quat();
+ p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quaternion();
p_track.scale_track.values.write[key_i] = xform.basis.get_scale();
}
} else if (track_type == Animation::TYPE_VALUE) {
@@ -6071,7 +6077,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
p_track.rotation_track.interpolation = gltf_interpolation;
for (int32_t key_i = 0; key_i < key_count; key_i++) {
- Quat rotation_track = p_animation->track_get_key_value(p_track_i, key_i);
+ Quaternion rotation_track = p_animation->track_get_key_value(p_track_i, key_i);
p_track.rotation_track.values.write[key_i] = rotation_track;
}
} else if (path.find(":translation") != -1) {
@@ -6098,7 +6104,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
rotation_radian.x = Math::deg2rad(rotation_degrees.x);
rotation_radian.y = Math::deg2rad(rotation_degrees.y);
rotation_radian.z = Math::deg2rad(rotation_degrees.z);
- p_track.rotation_track.values.write[key_i] = Quat(rotation_radian);
+ p_track.rotation_track.values.write[key_i] = Quaternion(rotation_radian);
}
} else if (path.find(":scale") != -1) {
p_track.scale_track.times = times;
@@ -6204,7 +6210,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (translation_track_i) {
track = translation_track_i->get();
}
- track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index);
+ track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
}
}
@@ -6220,7 +6226,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (rotation_degree_track_i) {
track = rotation_degree_track_i->get();
}
- track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index);
+ track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
}
}
@@ -6236,7 +6242,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (scale_track_i) {
track = scale_track_i->get();
}
- track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index);
+ track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
}
}
@@ -6247,7 +6253,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
for (Map<GLTFNodeIndex, Node *>::Element *transform_track_i = state->scene_nodes.front(); transform_track_i; transform_track_i = transform_track_i->next()) {
if (transform_track_i->get() == node) {
GLTFAnimation::Track track;
- track = _convert_animation_track(state, track, animation, Transform(), track_i, transform_track_i->key());
+ track = _convert_animation_track(state, track, animation, Transform3D(), track_i, transform_track_i->key());
gltf_animation->get_tracks().insert(transform_track_i->key(), track);
}
}
@@ -6335,7 +6341,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
Ref<GLTFSkeleton> skeleton_gltf = state->skeletons[skeleton_gltf_i];
int32_t bone = skeleton->find_bone(suffix);
ERR_CONTINUE(bone == -1);
- Transform xform = skeleton->get_bone_rest(bone);
+ Transform3D xform = skeleton->get_bone_rest(bone);
if (!skeleton_gltf->godot_bone_node.has(bone)) {
continue;
}
@@ -6362,7 +6368,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (node_track_i) {
track = node_track_i->get();
}
- track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index);
+ track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
break;
}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index bda1ce87d6..514373c4f0 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -205,7 +205,7 @@ private:
Vector<Color> _decode_accessor_as_color(Ref<GLTFState> state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<Quat> _decode_accessor_as_quat(Ref<GLTFState> state,
+ Vector<Quaternion> _decode_accessor_as_quaternion(Ref<GLTFState> state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
Vector<Transform2D> _decode_accessor_as_xform2d(Ref<GLTFState> state,
@@ -214,7 +214,7 @@ private:
Vector<Basis> _decode_accessor_as_basis(Ref<GLTFState> state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
- Vector<Transform> _decode_accessor_as_xform(Ref<GLTFState> state,
+ Vector<Transform3D> _decode_accessor_as_xform(Ref<GLTFState> state,
const GLTFAccessorIndex p_accessor,
const bool p_for_vertex);
Error _parse_meshes(Ref<GLTFState> state);
@@ -260,11 +260,12 @@ private:
Error _serialize_animations(Ref<GLTFState> state);
BoneAttachment3D *_generate_bone_attachment(Ref<GLTFState> state,
Skeleton3D *skeleton,
- const GLTFNodeIndex node_index);
+ const GLTFNodeIndex node_index,
+ const GLTFNodeIndex bone_index);
EditorSceneImporterMeshNode3D *_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
Camera3D *_generate_camera(Ref<GLTFState> state, Node *scene_parent,
const GLTFNodeIndex node_index);
- Light3D *_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
+ Node3D *_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
Node3D *_generate_spatial(Ref<GLTFState> state, Node *scene_parent,
const GLTFNodeIndex node_index);
void _assign_scene_names(Ref<GLTFState> state);
@@ -272,8 +273,8 @@ private:
T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values,
const float p_time,
const GLTFAnimation::Interpolation p_interp);
- GLTFAccessorIndex _encode_accessor_as_quats(Ref<GLTFState> state,
- const Vector<Quat> p_attribs,
+ GLTFAccessorIndex _encode_accessor_as_quaternions(Ref<GLTFState> state,
+ const Vector<Quaternion> p_attribs,
const bool p_for_vertex);
GLTFAccessorIndex _encode_accessor_as_weights(Ref<GLTFState> state,
const Vector<Color> p_attribs,
@@ -316,7 +317,7 @@ private:
const Vector<int32_t> p_attribs,
const bool p_for_vertex);
GLTFAccessorIndex _encode_accessor_as_xform(Ref<GLTFState> state,
- const Vector<Transform> p_attribs,
+ const Vector<Transform3D> p_attribs,
const bool p_for_vertex);
Error _encode_buffer_view(Ref<GLTFState> state, const double *src,
const int count, const GLTFType type,
@@ -332,7 +333,7 @@ private:
String interpolation_to_string(const GLTFAnimation::Interpolation p_interp);
GLTFAnimation::Track _convert_animation_track(Ref<GLTFState> state,
GLTFAnimation::Track p_track,
- Ref<Animation> p_animation, Transform p_bone_rest,
+ Ref<Animation> p_animation, Transform3D p_bone_rest,
int32_t p_track_i,
GLTFNodeIndex p_node_i);
Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path);
@@ -365,6 +366,7 @@ public:
void _generate_scene_node(Ref<GLTFState> state, Node *scene_parent,
Node3D *scene_root,
const GLTFNodeIndex node_index);
+ void _generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index);
void _import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
const GLTFAnimationIndex index, const int bake_fps);
GLTFMeshIndex _convert_mesh_instance(Ref<GLTFState> state,
diff --git a/modules/gltf/gltf_node.cpp b/modules/gltf/gltf_node.cpp
index 777c6fbd9a..5db7ad66c3 100644
--- a/modules/gltf/gltf_node.cpp
+++ b/modules/gltf/gltf_node.cpp
@@ -55,24 +55,21 @@ void GLTFNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &GLTFNode::set_scale);
ClassDB::bind_method(D_METHOD("get_children"), &GLTFNode::get_children);
ClassDB::bind_method(D_METHOD("set_children", "children"), &GLTFNode::set_children);
- ClassDB::bind_method(D_METHOD("get_fake_joint_parent"), &GLTFNode::get_fake_joint_parent);
- ClassDB::bind_method(D_METHOD("set_fake_joint_parent", "fake_joint_parent"), &GLTFNode::set_fake_joint_parent);
ClassDB::bind_method(D_METHOD("get_light"), &GLTFNode::get_light);
ClassDB::bind_method(D_METHOD("set_light", "light"), &GLTFNode::set_light);
ADD_PROPERTY(PropertyInfo(Variant::INT, "parent"), "set_parent", "get_parent"); // GLTFNodeIndex
ADD_PROPERTY(PropertyInfo(Variant::INT, "height"), "set_height", "get_height"); // int
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "xform"), "set_xform", "get_xform"); // Transform
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "xform"), "set_xform", "get_xform"); // Transform3D
ADD_PROPERTY(PropertyInfo(Variant::INT, "mesh"), "set_mesh", "get_mesh"); // GLTFMeshIndex
ADD_PROPERTY(PropertyInfo(Variant::INT, "camera"), "set_camera", "get_camera"); // GLTFCameraIndex
ADD_PROPERTY(PropertyInfo(Variant::INT, "skin"), "set_skin", "get_skin"); // GLTFSkinIndex
ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton"), "set_skeleton", "get_skeleton"); // GLTFSkeletonIndex
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "joint"), "set_joint", "get_joint"); // bool
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation"), "set_translation", "get_translation"); // Vector3
- ADD_PROPERTY(PropertyInfo(Variant::QUAT, "rotation"), "set_rotation", "get_rotation"); // Quat
+ ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "rotation"), "set_rotation", "get_rotation"); // Quaternion
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale"), "set_scale", "get_scale"); // Vector3
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "children"), "set_children", "get_children"); // Vector<int>
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fake_joint_parent"), "set_fake_joint_parent", "get_fake_joint_parent"); // GLTFNodeIndex
ADD_PROPERTY(PropertyInfo(Variant::INT, "light"), "set_light", "get_light"); // GLTFLightIndex
}
@@ -92,11 +89,11 @@ void GLTFNode::set_height(int p_height) {
height = p_height;
}
-Transform GLTFNode::get_xform() {
+Transform3D GLTFNode::get_xform() {
return xform;
}
-void GLTFNode::set_xform(Transform p_xform) {
+void GLTFNode::set_xform(Transform3D p_xform) {
xform = p_xform;
}
@@ -148,11 +145,11 @@ void GLTFNode::set_translation(Vector3 p_translation) {
translation = p_translation;
}
-Quat GLTFNode::get_rotation() {
+Quaternion GLTFNode::get_rotation() {
return rotation;
}
-void GLTFNode::set_rotation(Quat p_rotation) {
+void GLTFNode::set_rotation(Quaternion p_rotation) {
rotation = p_rotation;
}
@@ -172,14 +169,6 @@ void GLTFNode::set_children(Vector<int> p_children) {
children = p_children;
}
-GLTFNodeIndex GLTFNode::get_fake_joint_parent() {
- return fake_joint_parent;
-}
-
-void GLTFNode::set_fake_joint_parent(GLTFNodeIndex p_fake_joint_parent) {
- fake_joint_parent = p_fake_joint_parent;
-}
-
GLTFLightIndex GLTFNode::get_light() {
return light;
}
diff --git a/modules/gltf/gltf_node.h b/modules/gltf/gltf_node.h
index ce8aff8944..378b6da8bf 100644
--- a/modules/gltf/gltf_node.h
+++ b/modules/gltf/gltf_node.h
@@ -43,17 +43,16 @@ private:
// matrices need to be transformed to this
GLTFNodeIndex parent = -1;
int height = -1;
- Transform xform;
+ Transform3D xform;
GLTFMeshIndex mesh = -1;
GLTFCameraIndex camera = -1;
GLTFSkinIndex skin = -1;
GLTFSkeletonIndex skeleton = -1;
bool joint = false;
Vector3 translation;
- Quat rotation;
+ Quaternion rotation;
Vector3 scale = Vector3(1, 1, 1);
Vector<int> children;
- GLTFNodeIndex fake_joint_parent = -1;
GLTFLightIndex light = -1;
protected:
@@ -66,8 +65,8 @@ public:
int get_height();
void set_height(int p_height);
- Transform get_xform();
- void set_xform(Transform p_xform);
+ Transform3D get_xform();
+ void set_xform(Transform3D p_xform);
GLTFMeshIndex get_mesh();
void set_mesh(GLTFMeshIndex p_mesh);
@@ -87,8 +86,8 @@ public:
Vector3 get_translation();
void set_translation(Vector3 p_translation);
- Quat get_rotation();
- void set_rotation(Quat p_rotation);
+ Quaternion get_rotation();
+ void set_rotation(Quaternion p_rotation);
Vector3 get_scale();
void set_scale(Vector3 p_scale);
@@ -96,9 +95,6 @@ public:
Vector<int> get_children();
void set_children(Vector<int> p_children);
- GLTFNodeIndex get_fake_joint_parent();
- void set_fake_joint_parent(GLTFNodeIndex p_fake_joint_parent);
-
GLTFLightIndex get_light();
void set_light(GLTFLightIndex p_light);
};
diff --git a/modules/gltf/gltf_skin.cpp b/modules/gltf/gltf_skin.cpp
index 5a61e5778c..5cf17135ac 100644
--- a/modules/gltf/gltf_skin.cpp
+++ b/modules/gltf/gltf_skin.cpp
@@ -54,7 +54,7 @@ void GLTFSkin::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "skin_root"), "set_skin_root", "get_skin_root"); // GLTFNodeIndex
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints_original"), "set_joints_original", "get_joints_original"); // Vector<GLTFNodeIndex>
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "inverse_binds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_inverse_binds", "get_inverse_binds"); // Vector<Transform>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "inverse_binds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_inverse_binds", "get_inverse_binds"); // Vector<Transform3D>
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints"), "set_joints", "get_joints"); // Vector<GLTFNodeIndex>
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "non_joints"), "set_non_joints", "get_non_joints"); // Vector<GLTFNodeIndex>
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "roots"), "set_roots", "get_roots"); // Vector<GLTFNodeIndex>
diff --git a/modules/gltf/gltf_skin.h b/modules/gltf/gltf_skin.h
index 7cc09d85bc..e32e2d397c 100644
--- a/modules/gltf/gltf_skin.h
+++ b/modules/gltf/gltf_skin.h
@@ -43,7 +43,7 @@ private:
GLTFNodeIndex skin_root = -1;
Vector<GLTFNodeIndex> joints_original;
- Vector<Transform> inverse_binds;
+ Vector<Transform3D> inverse_binds;
// Note: joints + non_joints should form a complete subtree, or subtrees
// with a common parent
diff --git a/modules/gridmap/config.py b/modules/gridmap/config.py
index a6319fe1ea..720401b92d 100644
--- a/modules/gridmap/config.py
+++ b/modules/gridmap/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return True
+ return not env["disable_3d"]
def configure(env):
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 9b6fa138e5..fb0a2c9953 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -41,7 +41,7 @@
<return type="Array">
</return>
<description>
- Returns an array of [ArrayMesh]es and [Transform] references of all bake meshes that exist within the current GridMap.
+ Returns an array of [ArrayMesh]es and [Transform3D] references of all bake meshes that exist within the current GridMap.
</description>
</method>
<method name="get_cell_item" qualifiers="const">
@@ -84,7 +84,7 @@
<return type="Array">
</return>
<description>
- Returns an array of [Transform] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in world space.
+ Returns an array of [Transform3D] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in world space.
</description>
</method>
<method name="get_used_cells" qualifiers="const">
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 4e4f88ed6a..45af59622f 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -152,6 +152,7 @@ uint32_t GridMap::get_collision_mask() const {
}
void GridMap::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -162,20 +163,23 @@ void GridMap::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool GridMap::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void GridMap::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_layer();
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+ uint32_t layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ layer |= 1 << p_bit;
} else {
- mask &= ~(1 << p_bit);
+ layer &= ~(1 << p_bit);
}
- set_collision_layer(mask);
+ set_collision_layer(layer);
}
bool GridMap::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
@@ -442,7 +446,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<Transform3D, IndexKey>>> multimesh_items;
for (Set<IndexKey>::Element *E = g.cells.front(); E; E = E->next()) {
ERR_CONTINUE(!cell_map.has(E->get()));
@@ -455,7 +459,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
Vector3 cellpos = Vector3(E->get().x, E->get().y, E->get().z);
Vector3 ofs = _get_offset();
- Transform xform;
+ Transform3D xform;
xform.basis.set_orthogonal_index(c.rot);
xform.set_origin(cellpos * cell_size + ofs);
@@ -463,10 +467,10 @@ 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<Transform3D, IndexKey>>();
}
- Pair<Transform, IndexKey> p;
+ Pair<Transform3D, IndexKey> p;
p.first = xform;
p.second = E->get();
multimesh_items[c.item].push_back(p);
@@ -507,7 +511,7 @@ 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<Transform3D, IndexKey>>>::Element *E = multimesh_items.front(); E; E = E->next()) {
Octant::MultimeshInstance mmi;
RID mm = RS::get_singleton()->multimesh_create();
@@ -515,7 +519,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
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()) {
+ for (List<Pair<Transform3D, 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
@@ -668,7 +672,7 @@ void GridMap::_notification(int p_what) {
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
- Transform new_xform = get_global_transform();
+ Transform3D new_xform = get_global_transform();
if (new_xform == last_transform) {
break;
}
@@ -682,7 +686,6 @@ void GridMap::_notification(int p_what) {
for (int i = 0; i < baked_meshes.size(); i++) {
RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
}
-
} break;
case NOTIFICATION_EXIT_WORLD: {
for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) {
@@ -930,7 +933,7 @@ Array GridMap::get_meshes() {
Vector3 cellpos = Vector3(ik.x, ik.y, ik.z);
- Transform xform;
+ Transform3D xform;
xform.basis.set_orthogonal_index(E->get().rot);
@@ -984,7 +987,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
Vector3 cellpos = Vector3(key.x, key.y, key.z);
Vector3 ofs = _get_offset();
- Transform xform;
+ Transform3D xform;
xform.basis.set_orthogonal_index(E->get().rot);
xform.set_origin(cellpos * cell_size + ofs);
@@ -1053,7 +1056,7 @@ Array GridMap::get_bake_meshes() {
Array arr;
for (int i = 0; i < baked_meshes.size(); i++) {
arr.push_back(baked_meshes[i].mesh);
- arr.push_back(Transform());
+ arr.push_back(Transform3D());
}
return arr;
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index 4c04d492f7..8cd82e1f4c 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -89,7 +89,7 @@ class GridMap : public Node3D {
struct Octant {
struct NavMesh {
RID region;
- Transform xform;
+ Transform3D xform;
};
struct MultimeshInstance {
@@ -97,7 +97,7 @@ class GridMap : public Node3D {
RID multimesh;
struct Item {
int index = 0;
- Transform transform;
+ Transform3D transform;
IndexKey key;
};
@@ -137,7 +137,7 @@ class GridMap : public Node3D {
bool bake_navigation = false;
uint32_t navigation_layers = 1;
- Transform last_transform;
+ Transform3D last_transform;
bool _in_tree = false;
Vector3 cell_size = Vector3(2, 2, 2);
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index 4b241aa9a7..80551de1ba 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -62,12 +62,6 @@ void GridMapEditor::_menu_option(int p_option) {
floor->set_value(floor->get_value() + 1);
} break;
- case MENU_OPTION_LOCK_VIEW: {
- int index = options->get_popup()->get_item_index(MENU_OPTION_LOCK_VIEW);
- lock_view = !options->get_popup()->is_item_checked(index);
-
- options->get_popup()->set_item_checked(index, lock_view);
- } break;
case MENU_OPTION_CLIP_DISABLED:
case MENU_OPTION_CLIP_ABOVE:
case MENU_OPTION_CLIP_BELOW: {
@@ -255,7 +249,7 @@ void GridMapEditor::_menu_option(int p_option) {
}
void GridMapEditor::_update_cursor_transform() {
- cursor_transform = Transform();
+ cursor_transform = Transform3D();
cursor_transform.origin = cursor_origin;
cursor_transform.basis.set_orthogonal_index(cursor_rot);
cursor_transform.basis *= node->get_cell_scale();
@@ -268,7 +262,7 @@ void GridMapEditor::_update_cursor_transform() {
}
void GridMapEditor::_update_selection_transform() {
- Transform xf_zero;
+ Transform3D xf_zero;
xf_zero.basis.set_zero();
if (!selection.active) {
@@ -279,7 +273,7 @@ void GridMapEditor::_update_selection_transform() {
return;
}
- Transform xf;
+ Transform3D xf;
xf.scale((Vector3(1, 1, 1) + (selection.end - selection.begin)) * node->get_cell_size());
xf.origin = selection.begin * node->get_cell_size();
@@ -297,7 +291,7 @@ void GridMapEditor::_update_selection_transform() {
scale *= node->get_cell_size();
position *= node->get_cell_size();
- Transform xf2;
+ Transform3D xf2;
xf2.basis.scale(scale);
xf2.origin = position;
@@ -362,7 +356,7 @@ bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, b
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();
+ Transform3D local_xform = node->get_global_transform().affine_inverse();
Vector<Plane> planes = camera->get_frustum();
from = local_xform.xform(from);
normal = local_xform.basis.xform(normal).normalized();
@@ -540,7 +534,7 @@ void GridMapEditor::_set_clipboard_data() {
void GridMapEditor::_update_paste_indicator() {
if (input_action != INPUT_PASTE) {
- Transform xf;
+ Transform3D xf;
xf.basis.set_zero();
RenderingServer::get_singleton()->instance_set_transform(paste_instance, xf);
return;
@@ -548,7 +542,7 @@ void GridMapEditor::_update_paste_indicator() {
Vector3 center = 0.5 * Vector3(real_t(node->get_center_x()), real_t(node->get_center_y()), real_t(node->get_center_z()));
Vector3 scale = (Vector3(1, 1, 1) + (paste_indicator.end - paste_indicator.begin)) * node->get_cell_size();
- Transform xf;
+ Transform3D xf;
xf.scale(scale);
xf.origin = (paste_indicator.begin + (paste_indicator.current - paste_indicator.click) + center) * node->get_cell_size();
Basis rot;
@@ -561,7 +555,7 @@ void GridMapEditor::_update_paste_indicator() {
for (List<ClipboardItem>::Element *E = clipboard_items.front(); E; E = E->next()) {
ClipboardItem &item = E->get();
- xf = Transform();
+ xf = Transform3D();
xf.origin = (paste_indicator.begin + (paste_indicator.current - paste_indicator.click) + center) * node->get_cell_size();
xf.basis = rot * xf.basis;
xf.translate(item.grid_offset * node->get_cell_size());
@@ -615,13 +609,13 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && (mb->get_command() || mb->get_shift())) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && (mb->is_command_pressed() || mb->is_shift_pressed())) {
if (mb->is_pressed()) {
floor->set_value(floor->get_value() + mb->get_factor());
}
return true; // Eaten.
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && (mb->get_command() || mb->get_shift())) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && (mb->is_command_pressed() || mb->is_shift_pressed())) {
if (mb->is_pressed()) {
floor->set_value(floor->get_value() - mb->get_factor());
}
@@ -630,7 +624,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
if (mb->is_pressed()) {
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()) {
+ if ((nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA || nav_scheme == Node3DEditorViewport::NAVIGATION_MODO) && mb->is_alt_pressed()) {
input_action = INPUT_NONE;
} else if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
bool can_edit = (node && node->get_mesh_library().is_valid());
@@ -638,10 +632,10 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
_do_paste();
input_action = INPUT_NONE;
_update_paste_indicator();
- } else if (mb->get_shift() && can_edit) {
+ } else if (mb->is_shift_pressed() && can_edit) {
input_action = INPUT_SELECT;
last_selection = selection;
- } else if (mb->get_command() && can_edit) {
+ } else if (mb->is_command_pressed() && can_edit) {
input_action = INPUT_PICK;
} else {
input_action = INPUT_PAINT;
@@ -732,7 +726,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
}
}
- if (k->get_shift() && selection.active && input_action != INPUT_PASTE) {
+ if (k->is_shift_pressed() && selection.active && input_action != INPUT_PASTE) {
if (k->get_keycode() == options->get_popup()->get_item_accelerator(options->get_popup()->get_item_index(MENU_OPTION_PREV_LEVEL))) {
selection.click[edit_axis]--;
_validate_selection();
@@ -749,7 +743,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid()) {
- if (pan_gesture->get_alt() && (pan_gesture->get_command() || pan_gesture->get_shift())) {
+ if (pan_gesture->is_alt_pressed() && (pan_gesture->is_command_pressed() || pan_gesture->is_shift_pressed())) {
const real_t delta = pan_gesture->get_delta().y * 0.5;
accumulated_floor_delta += delta;
int step = 0;
@@ -810,7 +804,7 @@ void GridMapEditor::_mesh_library_palette_input(const Ref<InputEvent> &p_ie) {
const Ref<InputEventMouseButton> mb = p_ie;
// Zoom in/out using Ctrl + mouse wheel
- if (mb.is_valid() && mb->is_pressed() && mb->get_command()) {
+ if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed()) {
if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
size_slider->set_value(size_slider->get_value() + 0.2);
}
@@ -1068,7 +1062,7 @@ void GridMapEditor::_notification(int p_what) {
return;
}
- Transform xf = node->get_global_transform();
+ Transform3D xf = node->get_global_transform();
if (xf != grid_xform) {
for (int i = 0; i < 3; i++) {
@@ -1080,20 +1074,6 @@ void GridMapEditor::_notification(int p_what) {
if (cgmt.operator->() != last_mesh_library) {
update_palette();
}
-
- if (lock_view) {
- EditorNode *editor = Object::cast_to<EditorNode>(get_tree()->get_root()->get_child(0));
-
- Plane p;
- p.normal[edit_axis] = 1.0;
- p.d = edit_floor[edit_axis] * node->get_cell_size()[edit_axis];
- p = node->get_transform().xform(p); // plane to snap
-
- Node3DEditorPlugin *sep = Object::cast_to<Node3DEditorPlugin>(editor->get_editor_plugin_screen());
- if (sep) {
- sep->snap_cursor_to_plane(p);
- }
- }
} break;
case NOTIFICATION_THEME_CHANGED: {
@@ -1197,8 +1177,6 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
spatial_editor_hb->hide();
options->set_text(TTR("Grid Map"));
- options->get_popup()->add_check_item(TTR("Snap View"), MENU_OPTION_LOCK_VIEW);
- options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Previous Floor"), MENU_OPTION_PREV_LEVEL, KEY_Q);
options->get_popup()->add_item(TTR("Next Floor"), MENU_OPTION_NEXT_LEVEL, KEY_E);
options->get_popup()->add_separator();
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
index 6c7f0bedf6..4bc849e071 100644
--- a/modules/gridmap/grid_map_editor_plugin.h
+++ b/modules/gridmap/grid_map_editor_plugin.h
@@ -94,9 +94,8 @@ class GridMapEditor : public VBoxContainer {
MeshLibrary *last_mesh_library;
ClipMode clip_mode = CLIP_DISABLED;
- bool lock_view = false;
- Transform grid_xform;
- Transform edit_grid_xform;
+ Transform3D grid_xform;
+ Transform3D edit_grid_xform;
Vector3::Axis edit_axis;
int edit_floor[3];
Vector3 grid_ofs;
@@ -146,7 +145,7 @@ class GridMapEditor : public VBoxContainer {
PasteIndicator paste_indicator;
bool cursor_visible = false;
- Transform cursor_transform;
+ Transform3D cursor_transform;
Vector3 cursor_origin;
diff --git a/modules/gridmap/icons/GridMap.svg b/modules/gridmap/icons/GridMap.svg
index 7a36fd888c..e208257855 100644
--- a/modules/gridmap/icons/GridMap.svg
+++ b/modules/gridmap/icons/GridMap.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1-6 3v8l6 3 6-3v-2l-2-1-4 2-2-1v-4l2-1v-2l2-1zm4 2-2 1v2l2 1 2-1v-2z" fill="#fc9c9c" fill-opacity=".99608"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1-6 3v8l6 3 6-3v-2l-2-1-4 2-2-1v-4l2-1v-2l2-1zm4 2-2 1v2l2 1 2-1v-2z" fill="#fc7f7f" fill-opacity=".99608"/></svg>
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index 7daf6a3a57..d237544d66 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -105,7 +105,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
- int src_image_len = f->get_len();
+ uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
src_image.resize(src_image_len);
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 61ebabdfb6..3b0fbb1c47 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -162,8 +162,8 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
MeshInstance &mi = mesh_instances.write[m_i];
Size2i s = Size2i(mi.data.albedo_on_uv2->get_width(), mi.data.albedo_on_uv2->get_height());
sizes.push_back(s);
- atlas_size.width = MAX(atlas_size.width, s.width);
- atlas_size.height = MAX(atlas_size.height, s.height);
+ atlas_size.width = MAX(atlas_size.width, s.width + 2);
+ atlas_size.height = MAX(atlas_size.height, s.height + 2);
}
int max = nearest_power_of_2_templated(atlas_size.width);
@@ -186,10 +186,12 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
//determine best texture array atlas size by bruteforce fitting
while (atlas_size.x <= p_max_texture_size && atlas_size.y <= p_max_texture_size) {
- Vector<Vector2i> source_sizes = sizes;
+ Vector<Vector2i> source_sizes;
Vector<int> source_indices;
- source_indices.resize(source_sizes.size());
+ source_sizes.resize(sizes.size());
+ source_indices.resize(sizes.size());
for (int i = 0; i < source_indices.size(); i++) {
+ source_sizes.write[i] = sizes[i] + Vector2i(2, 2); // Add padding between lightmaps
source_indices.write[i] = i;
}
Vector<Vector3i> atlas_offsets;
@@ -207,7 +209,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
if (ofs.z > 0) {
//valid
ofs.z = slices;
- atlas_offsets.write[sidx] = ofs;
+ atlas_offsets.write[sidx] = ofs + Vector3i(1, 1, 0); // Center lightmap in the reserved oversized region
} else {
new_indices.push_back(sidx);
new_sources.push_back(source_sizes[i]);
@@ -272,7 +274,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
return BAKE_OK;
}
-void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &grid_texture_sdf, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) {
+void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) {
HashMap<Vertex, uint32_t, VertexHash> vertex_map;
//fill triangles array and vertex array
@@ -432,10 +434,10 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
triangle_indices.resize(triangle_sort.size());
Vector<uint32_t> grid_indices;
grid_indices.resize(grid_size * grid_size * grid_size * 2);
- zeromem(grid_indices.ptrw(), grid_indices.size() * sizeof(uint32_t));
+ memset(grid_indices.ptrw(), 0, grid_indices.size() * sizeof(uint32_t));
Vector<bool> solid;
solid.resize(grid_size * grid_size * grid_size);
- zeromem(solid.ptrw(), solid.size() * sizeof(bool));
+ memset(solid.ptrw(), 0, solid.size() * sizeof(bool));
{
uint32_t *tiw = triangle_indices.ptrw();
@@ -482,14 +484,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
img->save_png("res://grid_layer_" + itos(1000 + i).substr(1, 3) + ".png");
}
#endif
- if (p_step_function) {
- p_step_function(0.45, TTR("Generating Signed Distance Field"), p_bake_userdata, true);
- }
-
- //generate SDF for raytracing
- Vector<uint32_t> euclidean_pos = Geometry3D::generate_edf(solid, Vector3i(grid_size, grid_size, grid_size), false);
- Vector<uint32_t> euclidean_neg = Geometry3D::generate_edf(solid, Vector3i(grid_size, grid_size, grid_size), true);
- Vector<int8_t> sdf8 = Geometry3D::generate_sdf8(euclidean_pos, euclidean_neg);
/*****************************/
/*** CREATE GPU STRUCTURES ***/
@@ -551,10 +545,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
tf.format = RD::DATA_FORMAT_R32G32_UINT;
texdata.write[0] = grid_indices.to_byte_array();
grid_texture = rd->texture_create(tf, RD::TextureView(), texdata);
- //sdf
- tf.format = RD::DATA_FORMAT_R8_SNORM;
- texdata.write[0] = sdf8.to_byte_array();
- grid_texture_sdf = rd->texture_create(tf, RD::TextureView(), texdata);
}
}
@@ -755,8 +745,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
light_environment_tex = rd->texture_create(tfp, RD::TextureView(), tdata);
#ifdef DEBUG_TEXTURES
- panorama_tex->convert(Image::FORMAT_RGB8);
- panorama_tex->save_png("res://0_panorama.png");
+ panorama_tex->save_exr("res://0_panorama.exr", false);
#endif
}
}
@@ -770,7 +759,6 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RID lights_buffer;
RID triangle_cell_indices_buffer;
RID grid_texture;
- RID grid_texture_sdf;
RID seams_buffer;
RID probe_positions_buffer;
@@ -783,11 +771,10 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->free(lights_buffer); \
rd->free(triangle_cell_indices_buffer); \
rd->free(grid_texture); \
- rd->free(grid_texture_sdf); \
rd->free(seams_buffer); \
rd->free(probe_positions_buffer);
- _create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, box_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, grid_texture_sdf, seams_buffer, p_step_function, p_bake_userdata);
+ _create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, box_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, seams_buffer, p_step_function, p_bake_userdata);
if (p_step_function) {
p_step_function(0.47, TTR("Preparing shaders"), p_bake_userdata, true);
@@ -883,27 +870,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9;
- u.ids.push_back(grid_texture_sdf);
- base_uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 10;
u.ids.push_back(albedo_array_tex);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 11;
+ u.binding = 10;
u.ids.push_back(emission_array_tex);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 12;
+ u.binding = 11;
u.ids.push_back(sampler);
base_uniforms.push_back(u);
}
@@ -937,13 +917,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img;
img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAF, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://1_position_" + itos(i) + ".png");
+ img->save_exr("res://1_position_" + itos(i) + ".exr", false);
s = rd->texture_get_data(normal_tex, i);
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://1_normal_" + itos(i) + ".png");
+ img->save_exr("res://1_normal_" + itos(i) + ".exr", false);
}
#endif
@@ -966,27 +944,27 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
- //unoccluder
+ // Unoccluder
RID compute_shader_unocclude = rd->shader_create_from_bytecode(compute_shader->get_bytecode("unocclude"));
ERR_FAIL_COND_V(compute_shader_unocclude.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen
RID compute_shader_unocclude_pipeline = rd->compute_pipeline_create(compute_shader_unocclude);
- //direct light
+ // Direct light
RID compute_shader_primary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("primary"));
ERR_FAIL_COND_V(compute_shader_primary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen
RID compute_shader_primary_pipeline = rd->compute_pipeline_create(compute_shader_primary);
- //indirect light
+ // Indirect light
RID compute_shader_secondary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("secondary"));
ERR_FAIL_COND_V(compute_shader_secondary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_secondary_pipeline = rd->compute_pipeline_create(compute_shader_secondary);
- //dilate
+ // Dilate
RID compute_shader_dilate = rd->shader_create_from_bytecode(compute_shader->get_bytecode("dilate"));
ERR_FAIL_COND_V(compute_shader_dilate.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_dilate_pipeline = rd->compute_pipeline_create(compute_shader_dilate);
- //dilate
+ // Light probes
RID compute_shader_light_probes = rd->shader_create_from_bytecode(compute_shader->get_bytecode("light_probes"));
ERR_FAIL_COND_V(compute_shader_light_probes.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_light_probes_pipeline = rd->compute_pipeline_create(compute_shader_light_probes);
@@ -1153,8 +1131,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img;
img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://2_light_primary_" + itos(i) + ".png");
+ img->save_exr("res://2_light_primary_" + itos(i) + ".exr", false);
}
#endif
@@ -1212,7 +1189,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 6;
- u.ids.push_back(light_environment_tex); //reuse unocclude tex
+ u.ids.push_back(light_environment_tex);
uniforms.push_back(u);
}
}
@@ -1298,7 +1275,15 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
}
}
+
+ if (b == 0) {
+ // This disables the environment for subsequent bounces
+ push_constant.environment_xform[3] = -99.0f;
+ }
}
+
+ // Restore the correct environment transform
+ push_constant.environment_xform[3] = 0.0f;
}
/* LIGHPROBES */
@@ -1449,8 +1434,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img;
img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://4_light_secondary_" + itos(i) + ".png");
+ img->save_exr("res://4_light_secondary_" + itos(i) + ".exr", false);
}
#endif
@@ -1582,6 +1566,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
clear_colors.push_back(Color(0, 0, 0, 1));
for (int i = 0; i < atlas_slices; i++) {
int subslices = (p_bake_sh ? 4 : 1);
+
+ if (slice_seam_count[i] == 0) {
+ continue;
+ }
+
for (int k = 0; k < subslices; k++) {
RasterSeamsPushConstant seams_push_constant;
seams_push_constant.slice = uint32_t(i * subslices + k);
@@ -1654,8 +1643,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img;
img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://5_blendseams" + itos(i) + ".png");
+ img->save_exr("res://5_blendseams" + itos(i) + ".exr", false);
}
#endif
if (p_step_function) {
@@ -1674,7 +1662,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (probe_positions.size() > 0) {
probe_values.resize(probe_positions.size() * 9);
Vector<uint8_t> probe_data = rd->buffer_get_data(light_probe_buffer);
- copymem(probe_values.ptrw(), probe_data.ptr(), probe_data.size());
+ memcpy(probe_values.ptrw(), probe_data.ptr(), probe_data.size());
rd->free(light_probe_buffer);
#ifdef DEBUG_TEXTURES
@@ -1682,7 +1670,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img2;
img2.instance();
img2->create(probe_values.size(), 1, false, Image::FORMAT_RGBAF, probe_data);
- img2->save_png("res://6_lightprobes.png");
+ img2->save_exr("res://6_lightprobes.exr", false);
}
#endif
}
@@ -1743,7 +1731,7 @@ Vector<Color> LightmapperRD::get_bake_probe_sh(int p_probe) const {
ERR_FAIL_INDEX_V(p_probe, probe_positions.size(), Vector<Color>());
Vector<Color> ret;
ret.resize(9);
- copymem(ret.ptrw(), &probe_values[p_probe * 9], sizeof(Color) * 9);
+ memcpy(ret.ptrw(), &probe_values[p_probe * 9], sizeof(Color) * 9);
return ret;
}
diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h
index f2a826a447..7ab7f34464 100644
--- a/modules/lightmapper_rd/lightmapper_rd.h
+++ b/modules/lightmapper_rd/lightmapper_rd.h
@@ -231,7 +231,7 @@ class LightmapperRD : public Lightmapper {
Vector<Color> probe_values;
BakeError _blit_meshes_into_atlas(int p_max_texture_size, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata);
- void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &grid_texture_sdf, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata);
+ void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata);
void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform);
public:
diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl
index f8a0cd16de..1581639036 100644
--- a/modules/lightmapper_rd/lm_common_inc.glsl
+++ b/modules/lightmapper_rd/lm_common_inc.glsl
@@ -84,9 +84,8 @@ layout(set = 0, binding = 7, std430) restrict readonly buffer Probes {
probe_positions;
layout(set = 0, binding = 8) uniform utexture3D grid;
-layout(set = 0, binding = 9) uniform texture3D grid_sdf;
-layout(set = 0, binding = 10) uniform texture2DArray albedo_tex;
-layout(set = 0, binding = 11) uniform texture2DArray emission_tex;
+layout(set = 0, binding = 9) uniform texture2DArray albedo_tex;
+layout(set = 0, binding = 10) uniform texture2DArray emission_tex;
-layout(set = 0, binding = 12) uniform sampler linear_sampler;
+layout(set = 0, binding = 11) uniform sampler linear_sampler;
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index 3dd96893fb..9ca40535f9 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -96,15 +96,22 @@ params;
bool ray_hits_triangle(vec3 from, vec3 dir, float max_dist, vec3 p0, vec3 p1, vec3 p2, out float r_distance, out vec3 r_barycentric) {
const vec3 e0 = p1 - p0;
const vec3 e1 = p0 - p2;
- vec3 triangleNormal = cross(e1, e0);
+ vec3 triangle_normal = cross(e1, e0);
- const vec3 e2 = (1.0 / dot(triangleNormal, dir)) * (p0 - from);
+ float n_dot_dir = dot(triangle_normal, dir);
+
+ if (abs(n_dot_dir) < 0.01) {
+ return false;
+ }
+
+ const vec3 e2 = (p0 - from) / n_dot_dir;
const vec3 i = cross(dir, e2);
r_barycentric.y = dot(i, e1);
r_barycentric.z = dot(i, e0);
r_barycentric.x = 1.0 - (r_barycentric.z + r_barycentric.y);
- r_distance = dot(triangleNormal, e2);
+ r_distance = dot(triangle_normal, e2);
+
return (r_distance > params.bias) && (r_distance < max_dist) && all(greaterThanEqual(r_barycentric, vec3(0.0)));
}
@@ -307,8 +314,6 @@ void main() {
continue;
}
- d /= lights.data[i].range;
-
attenuation = get_omni_attenuation(d, 1.0 / lights.data[i].range, lights.data[i].attenuation);
if (lights.data[i].type == LIGHT_TYPE_SPOT) {
@@ -410,7 +415,7 @@ void main() {
uint tidx;
vec3 barycentric;
- vec3 light;
+ vec3 light = vec3(0.0);
if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) {
//hit a triangle
vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv;
@@ -419,8 +424,8 @@ void main() {
vec3 uvw = vec3(barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2, float(triangles.data[tidx].slice));
light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
- } else {
- //did not hit a triangle, reach out for the sky
+ } else if (params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce
+ // Did not hit a triangle, reach out for the sky
vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
vec2 st = vec2(
diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp
index 73931b0365..3cd2da3d85 100644
--- a/modules/mbedtls/crypto_mbedtls.cpp
+++ b/modules/mbedtls/crypto_mbedtls.cpp
@@ -30,7 +30,7 @@
#include "crypto_mbedtls.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
@@ -58,7 +58,7 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'.");
- int flen = f->get_len();
+ uint64_t flen = f->get_length();
out.resize(flen + 1);
f->get_buffer(out.ptrw(), flen);
out.write[flen] = 0; // string terminator
@@ -146,7 +146,7 @@ Error X509CertificateMbedTLS::load(String p_path) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'.");
- int flen = f->get_len();
+ uint64_t flen = f->get_length();
out.resize(flen + 1);
f->get_buffer(out.ptrw(), flen);
out.write[flen] = 0; // string terminator
@@ -409,7 +409,7 @@ Vector<uint8_t> CryptoMbedTLS::sign(HashingContext::HashType p_hash_type, Vector
int ret = mbedtls_pk_sign(&(key->pkey), type, p_hash.ptr(), size, buf, &sig_size, mbedtls_ctr_drbg_random, &ctr_drbg);
ERR_FAIL_COND_V_MSG(ret, out, "Error while signing: " + itos(ret));
out.resize(sig_size);
- copymem(out.ptrw(), buf, sig_size);
+ memcpy(out.ptrw(), buf, sig_size);
return out;
}
@@ -432,7 +432,7 @@ Vector<uint8_t> CryptoMbedTLS::encrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_p
int ret = mbedtls_pk_encrypt(&(key->pkey), p_plaintext.ptr(), p_plaintext.size(), buf, &size, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
ERR_FAIL_COND_V_MSG(ret, out, "Error while encrypting: " + itos(ret));
out.resize(size);
- copymem(out.ptrw(), buf, size);
+ memcpy(out.ptrw(), buf, size);
return out;
}
@@ -446,6 +446,6 @@ Vector<uint8_t> CryptoMbedTLS::decrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_c
int ret = mbedtls_pk_decrypt(&(key->pkey), p_ciphertext.ptr(), p_ciphertext.size(), buf, &size, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
ERR_FAIL_COND_V_MSG(ret, out, "Error while decrypting: " + itos(ret));
out.resize(size);
- copymem(out.ptrw(), buf, size);
+ memcpy(out.ptrw(), buf, size);
return out;
}
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp
index 8a6cdfb131..11c9f64e21 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.cpp
+++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp
@@ -31,8 +31,8 @@
#include "packet_peer_mbed_dtls.h"
#include "mbedtls/platform_util.h"
+#include "core/io/file_access.h"
#include "core/io/stream_peer_ssl.h"
-#include "core/os/file_access.h"
int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
if (buf == nullptr || len <= 0) {
@@ -74,7 +74,7 @@ int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
if (err != OK) {
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
- copymem(buf, buffer, buffer_size);
+ memcpy(buf, buffer, buffer_size);
return buffer_size;
}
@@ -87,10 +87,10 @@ void PacketPeerMbedDTLS::_cleanup() {
int PacketPeerMbedDTLS::_set_cookie() {
// Setup DTLS session cookie for this client
uint8_t client_id[18];
- IP_Address addr = base->get_packet_address();
+ IPAddress addr = base->get_packet_address();
uint16_t port = base->get_packet_port();
- copymem(client_id, addr.get_ipv6(), 16);
- copymem(&client_id[16], (uint8_t *)&port, 2);
+ memcpy(client_id, addr.get_ipv6(), 16);
+ memcpy(&client_id[16], (uint8_t *)&port, 2);
return mbedtls_ssl_set_client_transport_id(ssl_ctx->get_context(), client_id, 18);
}
diff --git a/modules/mbedtls/ssl_context_mbedtls.h b/modules/mbedtls/ssl_context_mbedtls.h
index 30632018a8..1b55a54a10 100644
--- a/modules/mbedtls/ssl_context_mbedtls.h
+++ b/modules/mbedtls/ssl_context_mbedtls.h
@@ -33,9 +33,9 @@
#include "crypto_mbedtls.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include <mbedtls/config.h>
#include <mbedtls/ctr_drbg.h>
@@ -46,7 +46,7 @@
class SSLContextMbedTLS;
-class CookieContextMbedTLS : public Reference {
+class CookieContextMbedTLS : public RefCounted {
friend class SSLContextMbedTLS;
protected:
@@ -63,7 +63,7 @@ public:
~CookieContextMbedTLS();
};
-class SSLContextMbedTLS : public Reference {
+class SSLContextMbedTLS : public RefCounted {
protected:
bool inited = false;
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index b39a6ecc2f..bc72b04fa4 100644
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -30,8 +30,8 @@
#include "stream_peer_mbedtls.h"
+#include "core/io/file_access.h"
#include "core/io/stream_peer_tcp.h"
-#include "core/os/file_access.h"
int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
if (buf == nullptr || len <= 0) {
@@ -242,7 +242,7 @@ void StreamPeerMbedTLS::poll() {
return;
}
- // We could pass NULL as second parameter, but some behaviour sanitizers don't seem to like that.
+ // We could pass nullptr as second parameter, but some behaviour sanitizers don't seem to like that.
// Passing a 1 byte buffer to workaround it.
uint8_t byte;
int ret = mbedtls_ssl_read(ssl_ctx->get_context(), &byte, 0);
diff --git a/modules/meshoptimizer/config.py b/modules/meshoptimizer/config.py
index 82e4e43397..b7e69569b9 100644
--- a/modules/meshoptimizer/config.py
+++ b/modules/meshoptimizer/config.py
@@ -1,6 +1,6 @@
def can_build(env, platform):
# Having this on release by default, it's small and a lot of users like to do procedural stuff
- return True
+ return not env["disable_3d"]
def configure(env):
diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp
index a03310f518..77cc82a4e2 100644
--- a/modules/meshoptimizer/register_types.cpp
+++ b/modules/meshoptimizer/register_types.cpp
@@ -35,6 +35,7 @@
void register_meshoptimizer_types() {
SurfaceTool::optimize_vertex_cache_func = meshopt_optimizeVertexCache;
SurfaceTool::simplify_func = meshopt_simplify;
+ SurfaceTool::simplify_with_attrib_func = meshopt_simplifyWithAttributes;
SurfaceTool::simplify_scale_func = meshopt_simplifyScale;
SurfaceTool::simplify_sloppy_func = meshopt_simplifySloppy;
}
diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp
index aaa05a910c..600bbe9bb5 100644
--- a/modules/minimp3/audio_stream_mp3.cpp
+++ b/modules/minimp3/audio_stream_mp3.cpp
@@ -35,7 +35,7 @@
#include "audio_stream_mp3.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
void AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) {
ERR_FAIL_COND(!active);
@@ -172,7 +172,7 @@ void AudioStreamMP3::set_data(const Vector<uint8_t> &p_data) {
clear_data();
data = memalloc(src_data_len);
- copymem(data, src_datar, src_data_len);
+ memcpy(data, src_datar, src_data_len);
data_len = src_data_len;
}
@@ -183,7 +183,7 @@ Vector<uint8_t> AudioStreamMP3::get_data() const {
vdata.resize(data_len);
{
uint8_t *w = vdata.ptrw();
- copymem(w, data, data_len);
+ memcpy(w, data, data_len);
}
}
diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp
index afd26fb79e..dc16125726 100644
--- a/modules/minimp3/resource_importer_mp3.cpp
+++ b/modules/minimp3/resource_importer_mp3.cpp
@@ -30,8 +30,8 @@
#include "resource_importer_mp3.h"
+#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
#include "scene/resources/texture.h"
String ResourceImporterMP3::get_importer_name() const {
@@ -79,7 +79,7 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s
ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
- size_t len = f->get_len();
+ uint64_t len = f->get_length();
Vector<uint8_t> data;
data.resize(len);
diff --git a/modules/mobile_vr/config.py b/modules/mobile_vr/config.py
index ee401c1a2a..f6b64fb690 100644
--- a/modules/mobile_vr/config.py
+++ b/modules/mobile_vr/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return True
+ return not env["disable_3d"]
def configure(env):
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index 5140cfbbaf..590b95ab79 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -185,8 +185,8 @@ void MobileVRInterface::set_position_from_sensors() {
// if you have a gyro + accelerometer that combo tends to be better than combining all three but without a gyro you need the magnetometer..
if (has_magneto && has_grav && !has_gyro) {
// convert to quaternions, easier to smooth those out
- Quat transform_quat(orientation);
- Quat acc_mag_quat(combine_acc_mag(grav, magneto));
+ Quaternion transform_quat(orientation);
+ Quaternion acc_mag_quat(combine_acc_mag(grav, magneto));
transform_quat = transform_quat.slerp(acc_mag_quat, 0.1);
orientation = Basis(transform_quat);
@@ -300,9 +300,9 @@ real_t MobileVRInterface::get_k2() const {
return k2;
};
-bool MobileVRInterface::is_stereo() {
+uint32_t MobileVRInterface::get_view_count() {
// needs stereo...
- return true;
+ return 2;
};
bool MobileVRInterface::is_initialized() const {
@@ -361,10 +361,32 @@ Size2 MobileVRInterface::get_render_targetsize() {
return target_size;
};
-Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) {
+Transform3D MobileVRInterface::get_camera_transform() {
_THREAD_SAFE_METHOD_
- Transform transform_for_eye;
+ Transform3D transform_for_eye;
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, transform_for_eye);
+
+ if (initialized) {
+ float world_scale = xr_server->get_world_scale();
+
+ // just scale our origin point of our transform
+ Transform3D hmd_transform;
+ hmd_transform.basis = orientation;
+ hmd_transform.origin = Vector3(0.0, eye_height * world_scale, 0.0);
+
+ transform_for_eye = (xr_server->get_reference_frame()) * hmd_transform;
+ }
+
+ return transform_for_eye;
+};
+
+Transform3D MobileVRInterface::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
+ _THREAD_SAFE_METHOD_
+
+ Transform3D transform_for_eye;
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, transform_for_eye);
@@ -374,16 +396,16 @@ Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, cons
// we don't need to check for the existence of our HMD, doesn't affect our values...
// note * 0.01 to convert cm to m and * 0.5 as we're moving half in each direction...
- if (p_eye == XRInterface::EYE_LEFT) {
+ if (p_view == 0) {
transform_for_eye.origin.x = -(intraocular_dist * 0.01 * 0.5 * world_scale);
- } else if (p_eye == XRInterface::EYE_RIGHT) {
+ } else if (p_view == 1) {
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.
+ // should not have any other values..
};
// just scale our origin point of our transform
- Transform hmd_transform;
+ Transform3D hmd_transform;
hmd_transform.basis = orientation;
hmd_transform.origin = Vector3(0.0, eye_height * world_scale, 0.0);
@@ -396,21 +418,13 @@ Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, cons
return transform_for_eye;
};
-CameraMatrix MobileVRInterface::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+CameraMatrix MobileVRInterface::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
_THREAD_SAFE_METHOD_
CameraMatrix eye;
- if (p_eye == XRInterface::EYE_MONO) {
- ///@TODO for now hardcode some of this, what is really needed here is that this needs to be in sync with the real camera's properties
- // which probably means implementing a specific class for iOS and Android. For now this is purely here as an example.
- // Note also that if you use a normal viewport with AR/VR turned off you can still use the tracker output of this interface
- // to position a stock standard Godot camera and have control over this.
- // 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 == XRInterface::EYE_LEFT ? 1 : 2, p_aspect, intraocular_dist, display_width, display_to_lens, oversample, p_z_near, p_z_far);
- };
+ aspect = p_aspect;
+ eye.set_for_hmd(p_view + 1, p_aspect, intraocular_dist, display_width, display_to_lens, oversample, p_z_near, p_z_far);
return eye;
};
@@ -440,6 +454,45 @@ void MobileVRInterface::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_tar
eye_center.y = 0.0;
}
+Vector<BlitToScreen> MobileVRInterface::commit_views(RID p_render_target, const Rect2 &p_screen_rect) {
+ _THREAD_SAFE_METHOD_
+
+ Vector<BlitToScreen> blit_to_screen;
+
+ // We must have a valid render target
+ ERR_FAIL_COND_V(!p_render_target.is_valid(), blit_to_screen);
+
+ // Because we are rendering to our device we must use our main viewport!
+ ERR_FAIL_COND_V(p_screen_rect == Rect2(), blit_to_screen);
+
+ // and add our blits
+ BlitToScreen blit;
+ blit.render_target = p_render_target;
+ blit.multi_view.use_layer = true;
+ blit.lens_distortion.apply = true;
+ blit.lens_distortion.k1 = k1;
+ blit.lens_distortion.k2 = k2;
+ blit.lens_distortion.upscale = oversample;
+ blit.lens_distortion.aspect_ratio = aspect;
+
+ // left eye
+ blit.rect = p_screen_rect;
+ blit.rect.size.width *= 0.5;
+ blit.multi_view.layer = 0;
+ blit.lens_distortion.eye_center.x = ((-intraocular_dist / 2.0) + (display_width / 4.0)) / (display_width / 2.0);
+ blit_to_screen.push_back(blit);
+
+ // right eye
+ blit.rect = p_screen_rect;
+ blit.rect.size.width *= 0.5;
+ blit.rect.position.x = blit.rect.size.width;
+ blit.multi_view.layer = 1;
+ blit.lens_distortion.eye_center.x = ((intraocular_dist / 2.0) - (display_width / 4.0)) / (display_width / 2.0);
+ blit_to_screen.push_back(blit);
+
+ return blit_to_screen;
+}
+
void MobileVRInterface::process() {
_THREAD_SAFE_METHOD_
diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h
index d28c2196af..29ce0f92c8 100644
--- a/modules/mobile_vr/mobile_vr_interface.h
+++ b/modules/mobile_vr/mobile_vr_interface.h
@@ -63,9 +63,9 @@ private:
real_t display_to_lens = 4.0;
real_t oversample = 1.5;
- //@TODO not yet used, these are needed in our distortion shader...
real_t k1 = 0.215;
real_t k2 = 0.215;
+ real_t aspect = 1.0;
/*
logic for processing our sensor data, this was originally in our positional tracker logic but I think
@@ -138,16 +138,20 @@ public:
virtual void uninitialize() override;
virtual Size2 get_render_targetsize() override;
- virtual bool is_stereo() override;
- virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override;
- virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) override;
- virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override;
+ virtual uint32_t get_view_count() override;
+ virtual Transform3D get_camera_transform() override;
+ virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
+ virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override;
+ virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override;
virtual void process() override;
virtual void notification(int p_what) override {}
MobileVRInterface();
~MobileVRInterface();
+
+ // deprecated
+ virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override;
};
#endif // !MOBILE_VR_INTERFACE_H
diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp
index 553c6eca53..bd02ec0eac 100644
--- a/modules/mono/class_db_api_json.cpp
+++ b/modules/mono/class_db_api_json.cpp
@@ -33,8 +33,8 @@
#ifdef DEBUG_METHODS_ENABLED
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/json.h"
-#include "core/os/file_access.h"
#include "core/version.h"
void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 43f57a7caa..576256b6ec 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -37,8 +37,8 @@
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
+#include "core/io/file_access.h"
#include "core/io/json.h"
-#include "core/os/file_access.h"
#include "core/os/mutex.h"
#include "core/os/os.h"
#include "core/os/thread.h"
@@ -304,6 +304,26 @@ void CSharpLanguage::get_reserved_words(List<String> *p_words) const {
}
}
+bool CSharpLanguage::is_control_flow_keyword(String p_keyword) const {
+ return p_keyword == "break" ||
+ p_keyword == "case" ||
+ p_keyword == "catch" ||
+ p_keyword == "continue" ||
+ p_keyword == "default" ||
+ p_keyword == "do" ||
+ p_keyword == "else" ||
+ p_keyword == "finally" ||
+ p_keyword == "for" ||
+ p_keyword == "foreach" ||
+ p_keyword == "goto" ||
+ p_keyword == "if" ||
+ p_keyword == "return" ||
+ p_keyword == "switch" ||
+ p_keyword == "throw" ||
+ p_keyword == "try" ||
+ p_keyword == "while";
+}
+
void CSharpLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("//"); // single-line comment
p_delimiters->push_back("/* */"); // delimited comment
@@ -348,7 +368,7 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin
"}\n";
// Replaces all spaces in p_class_name with underscores to prevent
- // erronous C# Script templates from being generated when the object name
+ // invalid C# Script templates from being generated when the object name
// has spaces in it.
String class_name_no_spaces = p_class_name.replace(" ", "_");
String base_class_name = get_base_class_name(p_base_class_name, class_name_no_spaces);
@@ -476,10 +496,10 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
Variant::VECTOR3I,
Variant::TRANSFORM2D,
Variant::PLANE,
- Variant::QUAT,
+ Variant::QUATERNION,
Variant::AABB,
Variant::BASIS,
- Variant::TRANSFORM,
+ Variant::TRANSFORM3D,
Variant::COLOR,
Variant::STRING_NAME,
Variant::NODE_PATH,
@@ -843,13 +863,13 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
List<Ref<CSharpScript>> to_reload;
// We need to keep reference instances alive during reloading
- List<Ref<Reference>> ref_instances;
+ List<Ref<RefCounted>> rc_instances;
for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
CSharpScriptBinding &script_binding = E->value();
- Reference *ref = Object::cast_to<Reference>(script_binding.owner);
- if (ref) {
- ref_instances.push_back(Ref<Reference>(ref));
+ RefCounted *rc = Object::cast_to<RefCounted>(script_binding.owner);
+ if (rc) {
+ rc_instances.push_back(Ref<RefCounted>(rc));
}
}
@@ -872,9 +892,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
Object *obj = F->get();
script->pending_reload_instances.insert(obj->get_instance_id());
- Reference *ref = Object::cast_to<Reference>(obj);
- if (ref) {
- ref_instances.push_back(Ref<Reference>(ref));
+ RefCounted *rc = Object::cast_to<RefCounted>(obj);
+ if (rc) {
+ rc_instances.push_back(Ref<RefCounted>(rc));
}
}
@@ -883,9 +903,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
Object *obj = F->get()->get_owner();
script->pending_reload_instances.insert(obj->get_instance_id());
- Reference *ref = Object::cast_to<Reference>(obj);
- if (ref) {
- ref_instances.push_back(Ref<Reference>(ref));
+ RefCounted *rc = Object::cast_to<RefCounted>(obj);
+ if (rc) {
+ rc_instances.push_back(Ref<RefCounted>(rc));
}
}
#endif
@@ -1418,16 +1438,16 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
r_script_binding.owner = p_object;
// Tie managed to unmanaged
- Reference *ref = Object::cast_to<Reference>(p_object);
+ RefCounted *rc = Object::cast_to<RefCounted>(p_object);
- if (ref) {
+ if (rc) {
// Unsafe refcount increment. The managed instance also counts as a reference.
// This way if the unmanaged world has no references to our owner
// but the managed instance is alive, the refcount will be 1 instead of 0.
- // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
+ // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
- ref->reference();
- CSharpLanguage::get_singleton()->post_unsafe_reference(ref);
+ rc->reference();
+ CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
}
return true;
@@ -1491,10 +1511,10 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
}
void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
- Reference *ref_owner = Object::cast_to<Reference>(p_object);
+ RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object);
#ifdef DEBUG_ENABLED
- CRASH_COND(!ref_owner);
+ CRASH_COND(!rc_owner);
CRASH_COND(!p_object->has_script_instance_binding(get_language_index()));
#endif
@@ -1508,7 +1528,7 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
return;
}
- if (ref_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ if (rc_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.
@@ -1528,10 +1548,10 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
}
bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
- Reference *ref_owner = Object::cast_to<Reference>(p_object);
+ RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object);
#ifdef DEBUG_ENABLED
- CRASH_COND(!ref_owner);
+ CRASH_COND(!rc_owner);
CRASH_COND(!p_object->has_script_instance_binding(get_language_index()));
#endif
@@ -1541,7 +1561,7 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
MonoGCHandleData &gchandle = script_binding.gchandle;
- int refcount = ref_owner->reference_get_count();
+ int refcount = rc_owner->reference_get_count();
if (!script_binding.inited) {
return refcount == 0;
@@ -1572,13 +1592,13 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(p_script)));
- Reference *ref = Object::cast_to<Reference>(p_owner);
+ RefCounted *rc = Object::cast_to<RefCounted>(p_owner);
- instance->base_ref = ref != nullptr;
+ instance->base_ref_counted = rc != nullptr;
instance->owner = p_owner;
instance->gchandle = p_gchandle;
- if (instance->base_ref) {
+ if (instance->base_ref_counted) {
instance->_reference_owner_unsafe();
}
@@ -1880,7 +1900,7 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args,
bool CSharpInstance::_reference_owner_unsafe() {
#ifdef DEBUG_ENABLED
- CRASH_COND(!base_ref);
+ CRASH_COND(!base_ref_counted);
CRASH_COND(owner == nullptr);
CRASH_COND(unsafe_referenced); // already referenced
#endif
@@ -1891,7 +1911,7 @@ bool CSharpInstance::_reference_owner_unsafe() {
// See: _unreference_owner_unsafe()
// May not me referenced yet, so we must use init_ref() instead of reference()
- if (static_cast<Reference *>(owner)->init_ref()) {
+ if (static_cast<RefCounted *>(owner)->init_ref()) {
CSharpLanguage::get_singleton()->post_unsafe_reference(owner);
unsafe_referenced = true;
}
@@ -1901,7 +1921,7 @@ bool CSharpInstance::_reference_owner_unsafe() {
bool CSharpInstance::_unreference_owner_unsafe() {
#ifdef DEBUG_ENABLED
- CRASH_COND(!base_ref);
+ CRASH_COND(!base_ref_counted);
CRASH_COND(owner == nullptr);
#endif
@@ -1918,7 +1938,7 @@ bool CSharpInstance::_unreference_owner_unsafe() {
// Destroying the owner here means self destructing, so we defer the owner destruction to the caller.
CSharpLanguage::get_singleton()->pre_unsafe_unreference(owner);
- return static_cast<Reference *>(owner)->unreference();
+ return static_cast<RefCounted *>(owner)->unreference();
}
MonoObject *CSharpInstance::_internal_new_managed() {
@@ -1950,7 +1970,7 @@ MonoObject *CSharpInstance::_internal_new_managed() {
// Tie managed to unmanaged
gchandle = MonoGCHandleData::new_strong_handle(mono_object);
- if (base_ref) {
+ if (base_ref_counted) {
_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
}
@@ -1967,7 +1987,7 @@ void CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
disconnect_event_signals();
#ifdef DEBUG_ENABLED
- CRASH_COND(base_ref);
+ CRASH_COND(base_ref_counted);
CRASH_COND(gchandle.is_released());
#endif
CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
@@ -1975,7 +1995,7 @@ void CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance) {
#ifdef DEBUG_ENABLED
- CRASH_COND(!base_ref);
+ CRASH_COND(!base_ref_counted);
CRASH_COND(gchandle.is_released());
#endif
@@ -2016,7 +2036,7 @@ void CSharpInstance::connect_event_signals() {
StringName signal_name = event_signal.field->get_name();
// TODO: Use pooling for ManagedCallable instances.
- auto event_signal_callable = memnew(EventSignalCallable(owner, &event_signal));
+ EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, &event_signal));
Callable callable(event_signal_callable);
connected_event_signals.push_back(callable);
@@ -2027,7 +2047,7 @@ void CSharpInstance::connect_event_signals() {
void CSharpInstance::disconnect_event_signals() {
for (const List<Callable>::Element *E = connected_event_signals.front(); E; E = E->next()) {
const Callable &callable = E->get();
- auto event_signal_callable = static_cast<const EventSignalCallable *>(callable.get_custom());
+ const EventSignalCallable *event_signal_callable = static_cast<const EventSignalCallable *>(callable.get_custom());
owner->disconnect(event_signal_callable->get_signal(), callable);
}
@@ -2036,13 +2056,13 @@ void CSharpInstance::disconnect_event_signals() {
void CSharpInstance::refcount_incremented() {
#ifdef DEBUG_ENABLED
- CRASH_COND(!base_ref);
+ CRASH_COND(!base_ref_counted);
CRASH_COND(owner == nullptr);
#endif
- Reference *ref_owner = Object::cast_to<Reference>(owner);
+ RefCounted *rc_owner = Object::cast_to<RefCounted>(owner);
- if (ref_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ if (rc_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.
@@ -2058,13 +2078,13 @@ void CSharpInstance::refcount_incremented() {
bool CSharpInstance::refcount_decremented() {
#ifdef DEBUG_ENABLED
- CRASH_COND(!base_ref);
+ CRASH_COND(!base_ref_counted);
CRASH_COND(owner == nullptr);
#endif
- Reference *ref_owner = Object::cast_to<Reference>(owner);
+ RefCounted *rc_owner = Object::cast_to<RefCounted>(owner);
- int refcount = ref_owner->reference_get_count();
+ int refcount = rc_owner->reference_get_count();
if (refcount == 1 && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
GD_MONO_SCOPE_THREAD_ATTACH;
@@ -2085,46 +2105,10 @@ bool CSharpInstance::refcount_decremented() {
return ref_dying;
}
-Vector<ScriptNetData> CSharpInstance::get_rpc_methods() const {
+const Vector<MultiplayerAPI::RPCConfig> CSharpInstance::get_rpc_methods() const {
return script->get_rpc_methods();
}
-uint16_t CSharpInstance::get_rpc_method_id(const StringName &p_method) const {
- return script->get_rpc_method_id(p_method);
-}
-
-StringName CSharpInstance::get_rpc_method(const uint16_t p_rpc_method_id) const {
- return script->get_rpc_method(p_rpc_method_id);
-}
-
-MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
- return script->get_rpc_mode_by_id(p_rpc_method_id);
-}
-
-MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const {
- return script->get_rpc_mode(p_method);
-}
-
-Vector<ScriptNetData> CSharpInstance::get_rset_properties() const {
- return script->get_rset_properties();
-}
-
-uint16_t CSharpInstance::get_rset_property_id(const StringName &p_variable) const {
- return script->get_rset_property_id(p_variable);
-}
-
-StringName CSharpInstance::get_rset_property(const uint16_t p_rset_member_id) const {
- return script->get_rset_property(p_rset_member_id);
-}
-
-MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
- return script->get_rset_mode_by_id(p_rset_member_id);
-}
-
-MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const {
- return script->get_rset_mode(p_variable);
-}
-
void CSharpInstance::notification(int p_notification) {
GD_MONO_SCOPE_THREAD_ATTACH;
@@ -2135,12 +2119,12 @@ void CSharpInstance::notification(int p_notification) {
predelete_notified = true;
- if (base_ref) {
- // It's not safe to proceed if the owner derives Reference and the refcount reached 0.
+ if (base_ref_counted) {
+ // It's not safe to proceed if the owner derives RefCounted and the refcount reached 0.
// At this point, Dispose() was already called (manually or from the finalizer) so
// that's not a problem. The refcount wouldn't have reached 0 otherwise, since the
// managed side references it and Dispose() needs to be called to release it.
- // However, this means C# Reference scripts can't receive NOTIFICATION_PREDELETE, but
+ // However, this means C# RefCounted scripts can't receive NOTIFICATION_PREDELETE, but
// this is likely the case with GDScript as well: https://github.com/godotengine/godot/issues/6784
return;
}
@@ -2266,15 +2250,15 @@ CSharpInstance::~CSharpInstance() {
}
// If not being called from the owner's destructor, and we still hold a reference to the owner
- if (base_ref && !ref_dying && owner && unsafe_referenced) {
+ if (base_ref_counted && !ref_dying && owner && unsafe_referenced) {
// The owner's script or script instance is being replaced (or removed)
// Transfer ownership to an "instance binding"
- Reference *ref_owner = static_cast<Reference *>(owner);
+ RefCounted *rc_owner = static_cast<RefCounted *>(owner);
// We will unreference the owner before referencing it again, so we need to keep it alive
- Ref<Reference> scope_keep_owner_alive(ref_owner);
+ Ref<RefCounted> scope_keep_owner_alive(rc_owner);
(void)scope_keep_owner_alive;
// Unreference the owner here, before the new "instance binding" references it.
@@ -2299,7 +2283,7 @@ CSharpInstance::~CSharpInstance() {
#ifdef DEBUG_ENABLED
// The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope
- CRASH_COND(ref_owner->reference_get_count() <= 1);
+ CRASH_COND(rc_owner->reference_get_count() <= 1);
#endif
}
@@ -2386,7 +2370,7 @@ void CSharpScript::_update_member_info_no_exports() {
}
#endif
-bool CSharpScript::_update_exports() {
+bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_update) {
#ifdef TOOLS_ENABLED
bool is_editor = Engine::get_singleton()->is_editor_hint();
if (is_editor) {
@@ -2527,7 +2511,7 @@ bool CSharpScript::_update_exports() {
#ifdef TOOLS_ENABLED
if (is_editor) {
// Need to check this here, before disposal
- bool base_ref = Object::cast_to<Reference>(tmp_native) != nullptr;
+ bool base_ref_counted = Object::cast_to<RefCounted>(tmp_native) != nullptr;
// Dispose the temporary managed instance
@@ -2542,7 +2526,7 @@ bool CSharpScript::_update_exports() {
GDMonoUtils::free_gchandle(tmp_pinned_gchandle);
tmp_object = nullptr;
- if (tmp_native && !base_ref) {
+ if (tmp_native && !base_ref_counted) {
Node *node = Object::cast_to<Node>(tmp_native);
if (node && node->is_inside_tree()) {
ERR_PRINT("Temporary instance was added to the scene tree.");
@@ -2558,14 +2542,18 @@ bool CSharpScript::_update_exports() {
if (is_editor) {
placeholder_fallback_enabled = false;
- if (placeholders.size()) {
+ if ((changed || p_instance_to_update) && placeholders.size()) {
// Update placeholders if any
Map<StringName, Variant> values;
List<PropertyInfo> propnames;
_update_exports_values(values, propnames);
- for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
- E->get()->update(propnames, values);
+ if (changed) {
+ for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ E->get()->update(propnames, values);
+ }
+ } else {
+ p_instance_to_update->update(propnames, values);
}
}
}
@@ -3026,7 +3014,6 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native);
p_script->rpc_functions.clear();
- p_script->rpc_variables.clear();
GDMonoClass *top = p_script->script_class;
while (top && top != p_script->native) {
@@ -3040,9 +3027,12 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
if (!methods[i]->is_static()) {
MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]);
if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
- ScriptNetData nd;
+ MultiplayerAPI::RPCConfig nd;
nd.name = methods[i]->get_name();
- nd.mode = mode;
+ nd.rpc_mode = mode;
+ // TODO Transfer mode, channel
+ nd.transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE;
+ nd.channel = 0;
if (-1 == p_script->rpc_functions.find(nd)) {
p_script->rpc_functions.push_back(nd);
}
@@ -3051,46 +3041,11 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
}
}
- {
- Vector<GDMonoField *> fields = top->get_all_fields();
- for (int i = 0; i < fields.size(); i++) {
- if (!fields[i]->is_static()) {
- MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(fields[i]);
- if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
- ScriptNetData nd;
- nd.name = fields[i]->get_name();
- nd.mode = mode;
- if (-1 == p_script->rpc_variables.find(nd)) {
- p_script->rpc_variables.push_back(nd);
- }
- }
- }
- }
- }
-
- {
- Vector<GDMonoProperty *> properties = top->get_all_properties();
- for (int i = 0; i < properties.size(); i++) {
- if (!properties[i]->is_static()) {
- MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(properties[i]);
- if (MultiplayerAPI::RPC_MODE_DISABLED != mode) {
- ScriptNetData nd;
- nd.name = properties[i]->get_name();
- nd.mode = mode;
- if (-1 == p_script->rpc_variables.find(nd)) {
- p_script->rpc_variables.push_back(nd);
- }
- }
- }
- }
- }
-
top = top->get_parent_class();
}
// Sort so we are 100% that they are always the same.
- p_script->rpc_functions.sort_custom<SortNetData>();
- p_script->rpc_variables.sort_custom<SortNetData>();
+ p_script->rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>();
p_script->load_script_signals(p_script->script_class, p_script->native);
}
@@ -3126,7 +3081,7 @@ StringName CSharpScript::get_instance_base_type() const {
}
}
-CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error) {
+CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) {
GD_MONO_ASSERT_THREAD_ATTACHED;
/* STEP 1, CREATE */
@@ -3142,10 +3097,10 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
ERR_FAIL_V_MSG(nullptr, "Constructor not found.");
}
- Ref<Reference> ref;
- if (p_isref) {
+ Ref<RefCounted> ref;
+ if (p_is_ref_counted) {
// Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance.
- ref = Ref<Reference>(static_cast<Reference *>(p_owner));
+ ref = Ref<RefCounted>(static_cast<RefCounted *>(p_owner));
}
// If the object had a script instance binding, dispose it before adding the CSharpInstance
@@ -3171,7 +3126,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
}
CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(this)));
- instance->base_ref = p_isref;
+ instance->base_ref_counted = p_is_ref_counted;
instance->owner = p_owner;
instance->owner->set_script_instance(instance);
@@ -3196,7 +3151,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
// Tie managed to unmanaged
instance->gchandle = MonoGCHandleData::new_strong_handle(mono_object);
- if (instance->base_ref) {
+ if (instance->base_ref_counted) {
instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
}
@@ -3231,7 +3186,7 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
Object *owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native));
REF ref;
- Reference *r = Object::cast_to<Reference>(owner);
+ RefCounted *r = Object::cast_to<RefCounted>(owner);
if (r) {
ref = REF(r);
}
@@ -3272,14 +3227,14 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
GD_MONO_SCOPE_THREAD_ATTACH;
Callable::CallError unchecked_error;
- return _create_instance(nullptr, 0, p_this, Object::cast_to<Reference>(p_this) != nullptr, unchecked_error);
+ return _create_instance(nullptr, 0, p_this, Object::cast_to<RefCounted>(p_this) != nullptr, unchecked_error);
}
PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_this) {
#ifdef TOOLS_ENABLED
PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this));
placeholders.insert(si);
- _update_exports();
+ _update_exports(si);
return si;
#else
return nullptr;
@@ -3523,60 +3478,10 @@ MultiplayerAPI::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_m
return MultiplayerAPI::RPC_MODE_DISABLED;
}
-Vector<ScriptNetData> CSharpScript::get_rpc_methods() const {
+const Vector<MultiplayerAPI::RPCConfig> CSharpScript::get_rpc_methods() const {
return rpc_functions;
}
-uint16_t CSharpScript::get_rpc_method_id(const StringName &p_method) const {
- for (int i = 0; i < rpc_functions.size(); i++) {
- if (rpc_functions[i].name == p_method) {
- return i;
- }
- }
- return UINT16_MAX;
-}
-
-StringName CSharpScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
- ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName());
- return rpc_functions[p_rpc_method_id].name;
-}
-
-MultiplayerAPI::RPCMode CSharpScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
- ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
- return rpc_functions[p_rpc_method_id].mode;
-}
-
-MultiplayerAPI::RPCMode CSharpScript::get_rpc_mode(const StringName &p_method) const {
- return get_rpc_mode_by_id(get_rpc_method_id(p_method));
-}
-
-Vector<ScriptNetData> CSharpScript::get_rset_properties() const {
- return rpc_variables;
-}
-
-uint16_t CSharpScript::get_rset_property_id(const StringName &p_variable) const {
- for (int i = 0; i < rpc_variables.size(); i++) {
- if (rpc_variables[i].name == p_variable) {
- return i;
- }
- }
- return UINT16_MAX;
-}
-
-StringName CSharpScript::get_rset_property(const uint16_t p_rset_member_id) const {
- ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), StringName());
- return rpc_variables[p_rset_member_id].name;
-}
-
-MultiplayerAPI::RPCMode CSharpScript::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;
-}
-
-MultiplayerAPI::RPCMode CSharpScript::get_rset_mode(const StringName &p_variable) const {
- return get_rset_mode_by_id(get_rset_property_id(p_variable));
-}
-
Error CSharpScript::load_source_code(const String &p_path) {
Error ferr = read_all_file_utf8(p_path, source);
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index dd93a86d7a..965e882c5b 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -136,8 +136,7 @@ private:
Map<StringName, EventSignal> event_signals;
bool signals_invalidated = true;
- Vector<ScriptNetData> rpc_functions;
- Vector<ScriptNetData> rpc_variables;
+ Vector<MultiplayerAPI::RPCConfig> rpc_functions;
#ifdef TOOLS_ENABLED
List<PropertyInfo> exported_members_cache; // members_cache
@@ -164,14 +163,14 @@ private:
void load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class);
bool _get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_invoke, Vector<SignalParameter> &params);
- bool _update_exports();
+ bool _update_exports(PlaceHolderScriptInstance *p_instance_to_update = nullptr);
bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported);
#ifdef TOOLS_ENABLED
static int _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);
#endif
- CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error);
+ CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error);
Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
// Do not use unless you know what you are doing
@@ -235,17 +234,7 @@ public:
int get_member_line(const StringName &p_member) const override;
- Vector<ScriptNetData> get_rpc_methods() const override;
- uint16_t get_rpc_method_id(const StringName &p_method) const override;
- StringName get_rpc_method(const uint16_t p_rpc_method_id) const override;
- MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override;
- MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
-
- Vector<ScriptNetData> get_rset_properties() const override;
- uint16_t get_rset_property_id(const StringName &p_variable) const override;
- StringName get_rset_property(const uint16_t p_variable_id) const override;
- MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override;
- MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
+ const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
#ifdef TOOLS_ENABLED
bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; }
@@ -262,7 +251,7 @@ class CSharpInstance : public ScriptInstance {
friend class CSharpLanguage;
Object *owner = nullptr;
- bool base_ref = false;
+ bool base_ref_counted = false;
bool ref_dying = false;
bool unsafe_referenced = false;
bool predelete_notified = false;
@@ -322,17 +311,7 @@ public:
void refcount_incremented() override;
bool refcount_decremented() override;
- Vector<ScriptNetData> get_rpc_methods() const override;
- uint16_t get_rpc_method_id(const StringName &p_method) const override;
- StringName get_rpc_method(const uint16_t p_rpc_method_id) const override;
- MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override;
- MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
-
- Vector<ScriptNetData> get_rset_properties() const override;
- uint16_t get_rset_property_id(const StringName &p_variable) const override;
- StringName get_rset_property(const uint16_t p_variable_id) const override;
- MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override;
- MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
+ const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
void notification(int p_notification) override;
void _call_notification(int p_notification);
@@ -470,6 +449,7 @@ public:
/* EDITOR FUNCTIONS */
void get_reserved_words(List<String> *p_words) const override;
+ bool is_control_flow_keyword(String p_keyword) const override;
void get_comment_delimiters(List<String> *p_delimiters) const override;
void get_string_delimiters(List<String> *p_delimiters) const override;
Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const override;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
index 51055dc9b9..27737c3da0 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
@@ -7,7 +7,7 @@ using Path = System.IO.Path;
namespace GodotTools.Build
{
[Serializable]
- public sealed class BuildInfo : Reference // TODO Remove Reference once we have proper serialization
+ public sealed class BuildInfo : RefCounted // TODO Remove RefCounted once we have proper serialization
{
public string Solution { get; }
public string[] Targets { get; }
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index 1a1639aac7..c380707587 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -11,7 +11,7 @@ namespace GodotTools.Build
public class BuildOutputView : VBoxContainer, ISerializationListener
{
[Serializable]
- private class BuildIssue : Reference // TODO Remove Reference once we have proper serialization
+ private class BuildIssue : RefCounted // TODO Remove RefCounted once we have proper serialization
{
public bool Warning { get; set; }
public string File { get; set; }
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 58561c5097..c71c44d79d 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -371,7 +371,7 @@ namespace GodotTools
return (ExternalEditorId)editorSettings.GetSetting("mono/editor/external_editor") != ExternalEditorId.None;
}
- public override bool Build()
+ public override bool _Build()
{
return BuildManager.EditorBuildCallback();
}
@@ -413,9 +413,9 @@ namespace GodotTools
bottomPanelBtn.Icon = MSBuildPanel.BuildOutputView.BuildStateIcon;
}
- public override void EnablePlugin()
+ public override void _EnablePlugin()
{
- base.EnablePlugin();
+ base._EnablePlugin();
if (Instance != null)
throw new InvalidOperationException();
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index b48e5df9eb..7e944ed4a5 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -35,8 +35,8 @@
#include "core/config/engine.h"
#include "core/core_constants.h"
#include "core/io/compression.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/os/os.h"
#include "core/string/ucaps.h"
#include "main/main.h"
@@ -1260,7 +1260,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
CRASH_COND(itype.cname != name_cache.type_Object);
CRASH_COND(!itype.is_instantiable);
CRASH_COND(itype.api_type != ClassDB::API_CORE);
- CRASH_COND(itype.is_reference);
+ CRASH_COND(itype.is_ref_counted);
CRASH_COND(itype.is_singleton);
}
@@ -2284,8 +2284,8 @@ 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 ? "" : " = nullptr";
+ ptrcall_return_type = return_type->is_ref_counted ? "Ref<RefCounted>" : return_type->c_type;
+ initialization = return_type->is_ref_counted ? "" : " = nullptr";
} else {
ptrcall_return_type = return_type->c_type;
}
@@ -2520,10 +2520,10 @@ bool BindingsGenerator::_arg_default_value_is_assignable_to_type(const Variant &
p_arg_type.name == name_cache.type_NodePath;
case Variant::NODE_PATH:
return p_arg_type.name == name_cache.type_NodePath;
- case Variant::TRANSFORM:
case Variant::TRANSFORM2D:
+ case Variant::TRANSFORM3D:
case Variant::BASIS:
- case Variant::QUAT:
+ case Variant::QUATERNION:
case Variant::PLANE:
case Variant::AABB:
case Variant::COLOR:
@@ -2600,12 +2600,12 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
itype.base_name = ClassDB::get_parent_class(type_cname);
itype.is_singleton = Engine::get_singleton()->has_singleton(itype.proxy_name);
itype.is_instantiable = class_info->creation_func && !itype.is_singleton;
- itype.is_reference = ClassDB::is_parent_class(type_cname, name_cache.type_Reference);
- itype.memory_own = itype.is_reference;
+ itype.is_ref_counted = ClassDB::is_parent_class(type_cname, name_cache.type_RefCounted);
+ itype.memory_own = itype.is_ref_counted;
itype.c_out = "\treturn ";
itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED;
- itype.c_out += itype.is_reference ? "(%1.ptr());\n" : "(%1);\n";
+ itype.c_out += itype.is_ref_counted ? "(%1.ptr());\n" : "(%1);\n";
itype.cs_in = itype.is_singleton ? BINDINGS_PTR_FIELD : "Object." CS_SMETHOD_GETINSTANCE "(%0)";
@@ -2741,7 +2741,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
imethod.return_type.cname = return_info.class_name;
bool bad_reference_hint = !imethod.is_virtual && return_info.hint != PROPERTY_HINT_RESOURCE_TYPE &&
- ClassDB::is_parent_class(return_info.class_name, name_cache.type_Reference);
+ ClassDB::is_parent_class(return_info.class_name, name_cache.type_RefCounted);
ERR_FAIL_COND_V_MSG(bad_reference_hint, false,
String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." +
" Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'.");
@@ -3053,28 +3053,25 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
break;
case Variant::PLANE: {
Plane plane = p_val.operator Plane();
- r_iarg.default_argument = "new Plane(new Vector3(" + plane.normal.operator String() + "), " + rtos(plane.d) + ")";
+ r_iarg.default_argument = "new Plane(new Vector3" + plane.normal.operator String() + ", " + rtos(plane.d) + ")";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
case Variant::AABB: {
AABB aabb = p_val.operator ::AABB();
- r_iarg.default_argument = "new AABB(new Vector3(" + aabb.position.operator String() + "), new Vector3(" + aabb.position.operator String() + "))";
+ r_iarg.default_argument = "new AABB(new Vector3" + aabb.position.operator String() + ", new Vector3" + aabb.position.operator String() + ")";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
case Variant::RECT2: {
Rect2 rect = p_val.operator Rect2();
- r_iarg.default_argument = "new Rect2(new Vector2(" + rect.position.operator String() + "), new Vector2(" + rect.position.operator String() + "))";
+ r_iarg.default_argument = "new Rect2(new Vector2" + rect.position.operator String() + ", new Vector2" + rect.position.operator String() + ")";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
case Variant::RECT2I: {
Rect2i rect = p_val.operator Rect2i();
- r_iarg.default_argument = "new Rect2i(new Vector2i(" + rect.position.operator String() + "), new Vector2i(" + rect.position.operator String() + "))";
+ r_iarg.default_argument = "new Rect2i(new Vector2i" + rect.position.operator String() + ", new Vector2i" + rect.position.operator String() + ")";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
case Variant::COLOR:
- r_iarg.default_argument = "new %s(" + r_iarg.default_argument + ")";
- r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
- break;
case Variant::VECTOR2:
case Variant::VECTOR2I:
case Variant::VECTOR3:
@@ -3123,13 +3120,13 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
}
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
- case Variant::TRANSFORM: {
- Transform transform = p_val.operator Transform();
- if (transform == Transform()) {
- r_iarg.default_argument = "Transform.Identity";
+ case Variant::TRANSFORM3D: {
+ Transform3D transform = p_val.operator Transform3D();
+ if (transform == Transform3D()) {
+ r_iarg.default_argument = "Transform3D.Identity";
} else {
Basis basis = transform.basis;
- r_iarg.default_argument = "new Transform(new Vector3" + basis.get_column(0).operator String() + ", new Vector3" + basis.get_column(1).operator String() + ", new Vector3" + basis.get_column(2).operator String() + ", new Vector3" + transform.origin.operator String() + ")";
+ r_iarg.default_argument = "new Transform3D(new Vector3" + basis.get_column(0).operator String() + ", new Vector3" + basis.get_column(1).operator String() + ", new Vector3" + basis.get_column(2).operator String() + ", new Vector3" + transform.origin.operator String() + ")";
}
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
@@ -3142,12 +3139,12 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
}
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
- case Variant::QUAT: {
- Quat quat = p_val.operator Quat();
- if (quat == Quat()) {
- r_iarg.default_argument = "Quat.Identity";
+ case Variant::QUATERNION: {
+ Quaternion quaternion = p_val.operator Quaternion();
+ if (quaternion == Quaternion()) {
+ r_iarg.default_argument = "Quaternion.Identity";
} else {
- r_iarg.default_argument = "new Quat" + quat.operator String();
+ r_iarg.default_argument = "new Quaternion" + quaternion.operator String();
}
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
@@ -3196,8 +3193,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
INSERT_STRUCT_TYPE(Vector3)
INSERT_STRUCT_TYPE(Vector3i)
INSERT_STRUCT_TYPE(Basis)
- INSERT_STRUCT_TYPE(Quat)
- INSERT_STRUCT_TYPE(Transform)
+ INSERT_STRUCT_TYPE(Quaternion)
+ INSERT_STRUCT_TYPE(Transform3D)
INSERT_STRUCT_TYPE(AABB)
INSERT_STRUCT_TYPE(Color)
INSERT_STRUCT_TYPE(Plane)
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index 876046176b..48c0e02723 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -216,7 +216,7 @@ class BindingsGenerator {
bool is_enum = false;
bool is_object_type = false;
bool is_singleton = false;
- bool is_reference = false;
+ bool is_ref_counted = false;
/**
* Used only by Object-derived types.
@@ -228,7 +228,7 @@ class BindingsGenerator {
/**
* Used only by Object-derived types.
* Determines if the C# class owns the native handle and must free it somehow when disposed.
- * e.g.: Reference types must notify when the C# instance is disposed, for proper refcounting.
+ * e.g.: RefCounted types must notify when the C# instance is disposed, for proper refcounting.
*/
bool memory_own = false;
@@ -295,7 +295,7 @@ class BindingsGenerator {
* VarArg (fictitious type to represent variable arguments): Array
* float: double (because ptrcall only supports double)
* int: int64_t (because ptrcall only supports int64_t and uint64_t)
- * Reference types override this for the type of the return variable: Ref<Reference>
+ * RefCounted types override this for the type of the return variable: Ref<RefCounted>
*/
String c_type;
@@ -534,7 +534,7 @@ class BindingsGenerator {
StringName type_Variant = StaticCString::create("Variant");
StringName type_VarArg = StaticCString::create("VarArg");
StringName type_Object = StaticCString::create("Object");
- StringName type_Reference = StaticCString::create("Reference");
+ StringName type_RefCounted = StaticCString::create("RefCounted");
StringName type_RID = StaticCString::create("RID");
StringName type_String = StaticCString::create("String");
StringName type_StringName = StaticCString::create("StringName");
@@ -623,7 +623,7 @@ class BindingsGenerator {
}
inline String get_unique_sig(const TypeInterface &p_type) {
- if (p_type.is_reference) {
+ if (p_type.is_ref_counted) {
return "Ref";
} else if (p_type.is_object_type) {
return "Obj";
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index 4b858c0e82..54dbaebf38 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -91,7 +91,7 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, MonoAssemblyName *re
mono_assembly_get_assemblyref(image, i, reusable_aname);
- GDMonoAssembly *ref_assembly = NULL;
+ GDMonoAssembly *ref_assembly = nullptr;
if (!GDMono::get_singleton()->load_assembly(ref_name, reusable_aname, &ref_assembly, /* refonly: */ true, p_search_dirs)) {
ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'.");
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
index 3aecce50f5..2b641a8937 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
@@ -676,7 +676,7 @@ namespace Godot
public override string ToString()
{
- return String.Format("{0} - {1}", new object[]
+ return String.Format("{0}, {1}", new object[]
{
_position.ToString(),
_size.ToString()
@@ -685,7 +685,7 @@ namespace Godot
public string ToString(string format)
{
- return String.Format("{0} - {1}", new object[]
+ return String.Format("{0}, {1}", new object[]
{
_position.ToString(format),
_size.ToString(format)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
index 3f1120575f..5dbf5d5657 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -207,7 +207,7 @@ namespace Godot
}
}
- public Quat RotationQuat()
+ public Quaternion RotationQuaternion()
{
Basis orthonormalizedBasis = Orthonormalized();
real_t det = orthonormalizedBasis.Determinant();
@@ -218,18 +218,18 @@ namespace Godot
orthonormalizedBasis = orthonormalizedBasis.Scaled(-Vector3.One);
}
- return orthonormalizedBasis.Quat();
+ return orthonormalizedBasis.Quaternion();
}
- internal void SetQuatScale(Quat quat, Vector3 scale)
+ internal void SetQuaternionScale(Quaternion quaternion, Vector3 scale)
{
SetDiagonal(scale);
- Rotate(quat);
+ Rotate(quaternion);
}
- private void Rotate(Quat quat)
+ private void Rotate(Quaternion quaternion)
{
- this *= new Basis(quat);
+ this *= new Basis(quaternion);
}
private void SetDiagonal(Vector3 diagonal)
@@ -263,8 +263,8 @@ namespace Godot
/// The returned vector contains the rotation angles in
/// the format (X angle, Y angle, Z angle).
///
- /// Consider using the <see cref="Basis.Quat()"/> method instead, which
- /// returns a <see cref="Godot.Quat"/> quaternion instead of Euler angles.
+ /// Consider using the <see cref="Basis.Quaternion()"/> method instead, which
+ /// returns a <see cref="Godot.Quaternion"/> quaternion instead of Euler angles.
/// </summary>
/// <returns>A Vector3 representing the basis rotation in Euler angles.</returns>
public Vector3 GetEuler()
@@ -486,8 +486,8 @@ namespace Godot
/// <returns>The resulting basis matrix of the interpolation.</returns>
public Basis Slerp(Basis target, real_t weight)
{
- Quat from = new Quat(this);
- Quat to = new Quat(target);
+ Quaternion from = new Quaternion(this);
+ Quaternion to = new Quaternion(target);
Basis b = new Basis(from.Slerp(to, weight));
b.Row0 *= Mathf.Lerp(Row0.Length(), target.Row0.Length(), weight);
@@ -588,8 +588,8 @@ namespace Godot
/// See <see cref="GetEuler()"/> if you need Euler angles, but keep in
/// mind that quaternions should generally be preferred to Euler angles.
/// </summary>
- /// <returns>A <see cref="Godot.Quat"/> representing the basis's rotation.</returns>
- public Quat Quat()
+ /// <returns>A <see cref="Godot.Quaternion"/> representing the basis's rotation.</returns>
+ public Quaternion Quaternion()
{
real_t trace = Row0[0] + Row1[1] + Row2[2];
@@ -597,7 +597,7 @@ namespace Godot
{
real_t s = Mathf.Sqrt(trace + 1.0f) * 2f;
real_t inv_s = 1f / s;
- return new Quat(
+ return new Quaternion(
(Row2[1] - Row1[2]) * inv_s,
(Row0[2] - Row2[0]) * inv_s,
(Row1[0] - Row0[1]) * inv_s,
@@ -609,7 +609,7 @@ namespace Godot
{
real_t s = Mathf.Sqrt(Row0[0] - Row1[1] - Row2[2] + 1.0f) * 2f;
real_t inv_s = 1f / s;
- return new Quat(
+ return new Quaternion(
s * 0.25f,
(Row0[1] + Row1[0]) * inv_s,
(Row0[2] + Row2[0]) * inv_s,
@@ -621,7 +621,7 @@ namespace Godot
{
real_t s = Mathf.Sqrt(-Row0[0] + Row1[1] - Row2[2] + 1.0f) * 2f;
real_t inv_s = 1f / s;
- return new Quat(
+ return new Quaternion(
(Row0[1] + Row1[0]) * inv_s,
s * 0.25f,
(Row1[2] + Row2[1]) * inv_s,
@@ -632,7 +632,7 @@ namespace Godot
{
real_t s = Mathf.Sqrt(-Row0[0] - Row1[1] + Row2[2] + 1.0f) * 2f;
real_t inv_s = 1f / s;
- return new Quat(
+ return new Quaternion(
(Row0[2] + Row2[0]) * inv_s,
(Row1[2] + Row2[1]) * inv_s,
s * 0.25f,
@@ -699,23 +699,23 @@ namespace Godot
/// <summary>
/// Constructs a pure rotation basis matrix from the given quaternion.
/// </summary>
- /// <param name="quat">The quaternion to create the basis from.</param>
- public Basis(Quat quat)
+ /// <param name="quaternion">The quaternion to create the basis from.</param>
+ public Basis(Quaternion quaternion)
{
- real_t s = 2.0f / quat.LengthSquared;
+ real_t s = 2.0f / quaternion.LengthSquared;
- real_t xs = quat.x * s;
- real_t ys = quat.y * s;
- real_t zs = quat.z * s;
- real_t wx = quat.w * xs;
- real_t wy = quat.w * ys;
- real_t wz = quat.w * zs;
- real_t xx = quat.x * xs;
- real_t xy = quat.x * ys;
- real_t xz = quat.x * zs;
- real_t yy = quat.y * ys;
- real_t yz = quat.y * zs;
- real_t zz = quat.z * zs;
+ real_t xs = quaternion.x * s;
+ real_t ys = quaternion.y * s;
+ real_t zs = quaternion.z * s;
+ real_t wx = quaternion.w * xs;
+ real_t wy = quaternion.w * ys;
+ real_t wz = quaternion.w * zs;
+ real_t xx = quaternion.x * xs;
+ real_t xy = quaternion.x * ys;
+ real_t xz = quaternion.x * zs;
+ real_t yy = quaternion.y * ys;
+ real_t yz = quaternion.y * zs;
+ real_t zz = quaternion.z * zs;
Row0 = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
Row1 = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
@@ -727,8 +727,8 @@ namespace Godot
/// (in the YXZ convention: when *composing*, first Y, then X, and Z last),
/// given in the vector format as (X angle, Y angle, Z angle).
///
- /// Consider using the <see cref="Basis(Quat)"/> constructor instead, which
- /// uses a <see cref="Godot.Quat"/> quaternion instead of Euler angles.
+ /// Consider using the <see cref="Basis(Quaternion)"/> constructor instead, which
+ /// uses a <see cref="Godot.Quaternion"/> quaternion instead of Euler angles.
/// </summary>
/// <param name="eulerYXZ">The Euler angles to create the basis from.</param>
public Basis(Vector3 eulerYXZ)
@@ -863,22 +863,16 @@ namespace Godot
public override string ToString()
{
- return String.Format("({0}, {1}, {2})", new object[]
- {
- Row0.ToString(),
- Row1.ToString(),
- Row2.ToString()
- });
+ return "[X: " + x.ToString() +
+ ", Y: " + y.ToString() +
+ ", Z: " + z.ToString() + "]";
}
public string ToString(string format)
{
- return String.Format("({0}, {1}, {2})", new object[]
- {
- Row0.ToString(format),
- Row1.ToString(format),
- Row2.ToString(format)
- });
+ return "[X: " + x.ToString(format) +
+ ", Y: " + y.ToString(format) +
+ ", Z: " + z.ToString(format) + "]";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index 0c333d06ef..155ffcff32 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -257,6 +257,27 @@ namespace Godot
}
/// <summary>
+ /// Returns a new color with all components clamped between the
+ /// components of `min` and `max` using
+ /// <see cref="Mathf.Clamp(float, float, float)"/>.
+ /// </summary>
+ /// <param name="min">The color with minimum allowed values.</param>
+ /// <param name="max">The color with maximum allowed values.</param>
+ /// <returns>The color with all components clamped.</returns>
+ public Color Clamp(Color? min = null, Color? max = null)
+ {
+ Color minimum = min ?? new Color(0, 0, 0, 0);
+ Color maximum = max ?? new Color(1, 1, 1, 1);
+ return new Color
+ (
+ (float)Mathf.Clamp(r, minimum.r, maximum.r),
+ (float)Mathf.Clamp(g, minimum.g, maximum.g),
+ (float)Mathf.Clamp(b, minimum.b, maximum.b),
+ (float)Mathf.Clamp(a, minimum.a, maximum.a)
+ );
+ }
+
+ /// <summary>
/// Returns a new color resulting from making this color darker
/// by the specified ratio (on the range of 0 to 1).
/// </summary>
@@ -681,7 +702,7 @@ namespace Godot
name = name.Replace("_", String.Empty);
name = name.Replace("'", String.Empty);
name = name.Replace(".", String.Empty);
- name = name.ToLower();
+ name = name.ToUpper();
if (!Colors.namedColors.ContainsKey(name))
{
@@ -989,12 +1010,12 @@ namespace Godot
public override string ToString()
{
- return String.Format("{0},{1},{2},{3}", r.ToString(), g.ToString(), b.ToString(), a.ToString());
+ return String.Format("({0}, {1}, {2}, {3})", r.ToString(), g.ToString(), b.ToString(), a.ToString());
}
public string ToString(string format)
{
- return String.Format("{0},{1},{2},{3}", r.ToString(format), g.ToString(format), b.ToString(format), a.ToString(format));
+ return String.Format("({0}, {1}, {2}, {3})", r.ToString(format), g.ToString(format), b.ToString(format), a.ToString(format));
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
index d05a0414aa..4bb727bd35 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
@@ -9,301 +9,301 @@ namespace Godot
/// </summary>
public static class Colors
{
- // Color names and values are derived from core/color_names.inc
+ // Color names and values are derived from core/math/color_names.inc
internal static readonly Dictionary<string, Color> namedColors = new Dictionary<string, Color> {
- {"aliceblue", new Color(0.94f, 0.97f, 1.00f)},
- {"antiquewhite", new Color(0.98f, 0.92f, 0.84f)},
- {"aqua", new Color(0.00f, 1.00f, 1.00f)},
- {"aquamarine", new Color(0.50f, 1.00f, 0.83f)},
- {"azure", new Color(0.94f, 1.00f, 1.00f)},
- {"beige", new Color(0.96f, 0.96f, 0.86f)},
- {"bisque", new Color(1.00f, 0.89f, 0.77f)},
- {"black", new Color(0.00f, 0.00f, 0.00f)},
- {"blanchedalmond", new Color(1.00f, 0.92f, 0.80f)},
- {"blue", new Color(0.00f, 0.00f, 1.00f)},
- {"blueviolet", new Color(0.54f, 0.17f, 0.89f)},
- {"brown", new Color(0.65f, 0.16f, 0.16f)},
- {"burlywood", new Color(0.87f, 0.72f, 0.53f)},
- {"cadetblue", new Color(0.37f, 0.62f, 0.63f)},
- {"chartreuse", new Color(0.50f, 1.00f, 0.00f)},
- {"chocolate", new Color(0.82f, 0.41f, 0.12f)},
- {"coral", new Color(1.00f, 0.50f, 0.31f)},
- {"cornflower", new Color(0.39f, 0.58f, 0.93f)},
- {"cornsilk", new Color(1.00f, 0.97f, 0.86f)},
- {"crimson", new Color(0.86f, 0.08f, 0.24f)},
- {"cyan", new Color(0.00f, 1.00f, 1.00f)},
- {"darkblue", new Color(0.00f, 0.00f, 0.55f)},
- {"darkcyan", new Color(0.00f, 0.55f, 0.55f)},
- {"darkgoldenrod", new Color(0.72f, 0.53f, 0.04f)},
- {"darkgray", new Color(0.66f, 0.66f, 0.66f)},
- {"darkgreen", new Color(0.00f, 0.39f, 0.00f)},
- {"darkkhaki", new Color(0.74f, 0.72f, 0.42f)},
- {"darkmagenta", new Color(0.55f, 0.00f, 0.55f)},
- {"darkolivegreen", new Color(0.33f, 0.42f, 0.18f)},
- {"darkorange", new Color(1.00f, 0.55f, 0.00f)},
- {"darkorchid", new Color(0.60f, 0.20f, 0.80f)},
- {"darkred", new Color(0.55f, 0.00f, 0.00f)},
- {"darksalmon", new Color(0.91f, 0.59f, 0.48f)},
- {"darkseagreen", new Color(0.56f, 0.74f, 0.56f)},
- {"darkslateblue", new Color(0.28f, 0.24f, 0.55f)},
- {"darkslategray", new Color(0.18f, 0.31f, 0.31f)},
- {"darkturquoise", new Color(0.00f, 0.81f, 0.82f)},
- {"darkviolet", new Color(0.58f, 0.00f, 0.83f)},
- {"deeppink", new Color(1.00f, 0.08f, 0.58f)},
- {"deepskyblue", new Color(0.00f, 0.75f, 1.00f)},
- {"dimgray", new Color(0.41f, 0.41f, 0.41f)},
- {"dodgerblue", new Color(0.12f, 0.56f, 1.00f)},
- {"firebrick", new Color(0.70f, 0.13f, 0.13f)},
- {"floralwhite", new Color(1.00f, 0.98f, 0.94f)},
- {"forestgreen", new Color(0.13f, 0.55f, 0.13f)},
- {"fuchsia", new Color(1.00f, 0.00f, 1.00f)},
- {"gainsboro", new Color(0.86f, 0.86f, 0.86f)},
- {"ghostwhite", new Color(0.97f, 0.97f, 1.00f)},
- {"gold", new Color(1.00f, 0.84f, 0.00f)},
- {"goldenrod", new Color(0.85f, 0.65f, 0.13f)},
- {"gray", new Color(0.75f, 0.75f, 0.75f)},
- {"green", new Color(0.00f, 1.00f, 0.00f)},
- {"greenyellow", new Color(0.68f, 1.00f, 0.18f)},
- {"honeydew", new Color(0.94f, 1.00f, 0.94f)},
- {"hotpink", new Color(1.00f, 0.41f, 0.71f)},
- {"indianred", new Color(0.80f, 0.36f, 0.36f)},
- {"indigo", new Color(0.29f, 0.00f, 0.51f)},
- {"ivory", new Color(1.00f, 1.00f, 0.94f)},
- {"khaki", new Color(0.94f, 0.90f, 0.55f)},
- {"lavender", new Color(0.90f, 0.90f, 0.98f)},
- {"lavenderblush", new Color(1.00f, 0.94f, 0.96f)},
- {"lawngreen", new Color(0.49f, 0.99f, 0.00f)},
- {"lemonchiffon", new Color(1.00f, 0.98f, 0.80f)},
- {"lightblue", new Color(0.68f, 0.85f, 0.90f)},
- {"lightcoral", new Color(0.94f, 0.50f, 0.50f)},
- {"lightcyan", new Color(0.88f, 1.00f, 1.00f)},
- {"lightgoldenrod", new Color(0.98f, 0.98f, 0.82f)},
- {"lightgray", new Color(0.83f, 0.83f, 0.83f)},
- {"lightgreen", new Color(0.56f, 0.93f, 0.56f)},
- {"lightpink", new Color(1.00f, 0.71f, 0.76f)},
- {"lightsalmon", new Color(1.00f, 0.63f, 0.48f)},
- {"lightseagreen", new Color(0.13f, 0.70f, 0.67f)},
- {"lightskyblue", new Color(0.53f, 0.81f, 0.98f)},
- {"lightslategray", new Color(0.47f, 0.53f, 0.60f)},
- {"lightsteelblue", new Color(0.69f, 0.77f, 0.87f)},
- {"lightyellow", new Color(1.00f, 1.00f, 0.88f)},
- {"lime", new Color(0.00f, 1.00f, 0.00f)},
- {"limegreen", new Color(0.20f, 0.80f, 0.20f)},
- {"linen", new Color(0.98f, 0.94f, 0.90f)},
- {"magenta", new Color(1.00f, 0.00f, 1.00f)},
- {"maroon", new Color(0.69f, 0.19f, 0.38f)},
- {"mediumaquamarine", new Color(0.40f, 0.80f, 0.67f)},
- {"mediumblue", new Color(0.00f, 0.00f, 0.80f)},
- {"mediumorchid", new Color(0.73f, 0.33f, 0.83f)},
- {"mediumpurple", new Color(0.58f, 0.44f, 0.86f)},
- {"mediumseagreen", new Color(0.24f, 0.70f, 0.44f)},
- {"mediumslateblue", new Color(0.48f, 0.41f, 0.93f)},
- {"mediumspringgreen", new Color(0.00f, 0.98f, 0.60f)},
- {"mediumturquoise", new Color(0.28f, 0.82f, 0.80f)},
- {"mediumvioletred", new Color(0.78f, 0.08f, 0.52f)},
- {"midnightblue", new Color(0.10f, 0.10f, 0.44f)},
- {"mintcream", new Color(0.96f, 1.00f, 0.98f)},
- {"mistyrose", new Color(1.00f, 0.89f, 0.88f)},
- {"moccasin", new Color(1.00f, 0.89f, 0.71f)},
- {"navajowhite", new Color(1.00f, 0.87f, 0.68f)},
- {"navyblue", new Color(0.00f, 0.00f, 0.50f)},
- {"oldlace", new Color(0.99f, 0.96f, 0.90f)},
- {"olive", new Color(0.50f, 0.50f, 0.00f)},
- {"olivedrab", new Color(0.42f, 0.56f, 0.14f)},
- {"orange", new Color(1.00f, 0.65f, 0.00f)},
- {"orangered", new Color(1.00f, 0.27f, 0.00f)},
- {"orchid", new Color(0.85f, 0.44f, 0.84f)},
- {"palegoldenrod", new Color(0.93f, 0.91f, 0.67f)},
- {"palegreen", new Color(0.60f, 0.98f, 0.60f)},
- {"paleturquoise", new Color(0.69f, 0.93f, 0.93f)},
- {"palevioletred", new Color(0.86f, 0.44f, 0.58f)},
- {"papayawhip", new Color(1.00f, 0.94f, 0.84f)},
- {"peachpuff", new Color(1.00f, 0.85f, 0.73f)},
- {"peru", new Color(0.80f, 0.52f, 0.25f)},
- {"pink", new Color(1.00f, 0.75f, 0.80f)},
- {"plum", new Color(0.87f, 0.63f, 0.87f)},
- {"powderblue", new Color(0.69f, 0.88f, 0.90f)},
- {"purple", new Color(0.63f, 0.13f, 0.94f)},
- {"rebeccapurple", new Color(0.40f, 0.20f, 0.60f)},
- {"red", new Color(1.00f, 0.00f, 0.00f)},
- {"rosybrown", new Color(0.74f, 0.56f, 0.56f)},
- {"royalblue", new Color(0.25f, 0.41f, 0.88f)},
- {"saddlebrown", new Color(0.55f, 0.27f, 0.07f)},
- {"salmon", new Color(0.98f, 0.50f, 0.45f)},
- {"sandybrown", new Color(0.96f, 0.64f, 0.38f)},
- {"seagreen", new Color(0.18f, 0.55f, 0.34f)},
- {"seashell", new Color(1.00f, 0.96f, 0.93f)},
- {"sienna", new Color(0.63f, 0.32f, 0.18f)},
- {"silver", new Color(0.75f, 0.75f, 0.75f)},
- {"skyblue", new Color(0.53f, 0.81f, 0.92f)},
- {"slateblue", new Color(0.42f, 0.35f, 0.80f)},
- {"slategray", new Color(0.44f, 0.50f, 0.56f)},
- {"snow", new Color(1.00f, 0.98f, 0.98f)},
- {"springgreen", new Color(0.00f, 1.00f, 0.50f)},
- {"steelblue", new Color(0.27f, 0.51f, 0.71f)},
- {"tan", new Color(0.82f, 0.71f, 0.55f)},
- {"teal", new Color(0.00f, 0.50f, 0.50f)},
- {"thistle", new Color(0.85f, 0.75f, 0.85f)},
- {"tomato", new Color(1.00f, 0.39f, 0.28f)},
- {"transparent", new Color(1.00f, 1.00f, 1.00f, 0.00f)},
- {"turquoise", new Color(0.25f, 0.88f, 0.82f)},
- {"violet", new Color(0.93f, 0.51f, 0.93f)},
- {"webgreen", new Color(0.00f, 0.50f, 0.00f)},
- {"webgray", new Color(0.50f, 0.50f, 0.50f)},
- {"webmaroon", new Color(0.50f, 0.00f, 0.00f)},
- {"webpurple", new Color(0.50f, 0.00f, 0.50f)},
- {"wheat", new Color(0.96f, 0.87f, 0.70f)},
- {"white", new Color(1.00f, 1.00f, 1.00f)},
- {"whitesmoke", new Color(0.96f, 0.96f, 0.96f)},
- {"yellow", new Color(1.00f, 1.00f, 0.00f)},
- {"yellowgreen", new Color(0.60f, 0.80f, 0.20f)},
+ {"ALICEBLUE", new Color(0.94f, 0.97f, 1.00f)},
+ {"ANTIQUEWHITE", new Color(0.98f, 0.92f, 0.84f)},
+ {"AQUA", new Color(0.00f, 1.00f, 1.00f)},
+ {"AQUAMARINE", new Color(0.50f, 1.00f, 0.83f)},
+ {"AZURE", new Color(0.94f, 1.00f, 1.00f)},
+ {"BEIGE", new Color(0.96f, 0.96f, 0.86f)},
+ {"BISQUE", new Color(1.00f, 0.89f, 0.77f)},
+ {"BLACK", new Color(0.00f, 0.00f, 0.00f)},
+ {"BLANCHEDALMOND", new Color(1.00f, 0.92f, 0.80f)},
+ {"BLUE", new Color(0.00f, 0.00f, 1.00f)},
+ {"BLUEVIOLET", new Color(0.54f, 0.17f, 0.89f)},
+ {"BROWN", new Color(0.65f, 0.16f, 0.16f)},
+ {"BURLYWOOD", new Color(0.87f, 0.72f, 0.53f)},
+ {"CADETBLUE", new Color(0.37f, 0.62f, 0.63f)},
+ {"CHARTREUSE", new Color(0.50f, 1.00f, 0.00f)},
+ {"CHOCOLATE", new Color(0.82f, 0.41f, 0.12f)},
+ {"CORAL", new Color(1.00f, 0.50f, 0.31f)},
+ {"CORNFLOWERBLUE", new Color(0.39f, 0.58f, 0.93f)},
+ {"CORNSILK", new Color(1.00f, 0.97f, 0.86f)},
+ {"CRIMSON", new Color(0.86f, 0.08f, 0.24f)},
+ {"CYAN", new Color(0.00f, 1.00f, 1.00f)},
+ {"DARKBLUE", new Color(0.00f, 0.00f, 0.55f)},
+ {"DARKCYAN", new Color(0.00f, 0.55f, 0.55f)},
+ {"DARKGOLDENROD", new Color(0.72f, 0.53f, 0.04f)},
+ {"DARKGRAY", new Color(0.66f, 0.66f, 0.66f)},
+ {"DARKGREEN", new Color(0.00f, 0.39f, 0.00f)},
+ {"DARKKHAKI", new Color(0.74f, 0.72f, 0.42f)},
+ {"DARKMAGENTA", new Color(0.55f, 0.00f, 0.55f)},
+ {"DARKOLIVEGREEN", new Color(0.33f, 0.42f, 0.18f)},
+ {"DARKORANGE", new Color(1.00f, 0.55f, 0.00f)},
+ {"DARKORCHID", new Color(0.60f, 0.20f, 0.80f)},
+ {"DARKRED", new Color(0.55f, 0.00f, 0.00f)},
+ {"DARKSALMON", new Color(0.91f, 0.59f, 0.48f)},
+ {"DARKSEAGREEN", new Color(0.56f, 0.74f, 0.56f)},
+ {"DARKSLATEBLUE", new Color(0.28f, 0.24f, 0.55f)},
+ {"DARKSLATEGRAY", new Color(0.18f, 0.31f, 0.31f)},
+ {"DARKTURQUOISE", new Color(0.00f, 0.81f, 0.82f)},
+ {"DARKVIOLET", new Color(0.58f, 0.00f, 0.83f)},
+ {"DEEPPINK", new Color(1.00f, 0.08f, 0.58f)},
+ {"DEEPSKYBLUE", new Color(0.00f, 0.75f, 1.00f)},
+ {"DIMGRAY", new Color(0.41f, 0.41f, 0.41f)},
+ {"DODGERBLUE", new Color(0.12f, 0.56f, 1.00f)},
+ {"FIREBRICK", new Color(0.70f, 0.13f, 0.13f)},
+ {"FLORALWHITE", new Color(1.00f, 0.98f, 0.94f)},
+ {"FORESTGREEN", new Color(0.13f, 0.55f, 0.13f)},
+ {"FUCHSIA", new Color(1.00f, 0.00f, 1.00f)},
+ {"GAINSBORO", new Color(0.86f, 0.86f, 0.86f)},
+ {"GHOSTWHITE", new Color(0.97f, 0.97f, 1.00f)},
+ {"GOLD", new Color(1.00f, 0.84f, 0.00f)},
+ {"GOLDENROD", new Color(0.85f, 0.65f, 0.13f)},
+ {"GRAY", new Color(0.75f, 0.75f, 0.75f)},
+ {"GREEN", new Color(0.00f, 1.00f, 0.00f)},
+ {"GREENYELLOW", new Color(0.68f, 1.00f, 0.18f)},
+ {"HONEYDEW", new Color(0.94f, 1.00f, 0.94f)},
+ {"HOTPINK", new Color(1.00f, 0.41f, 0.71f)},
+ {"INDIANRED", new Color(0.80f, 0.36f, 0.36f)},
+ {"INDIGO", new Color(0.29f, 0.00f, 0.51f)},
+ {"IVORY", new Color(1.00f, 1.00f, 0.94f)},
+ {"KHAKI", new Color(0.94f, 0.90f, 0.55f)},
+ {"LAVENDER", new Color(0.90f, 0.90f, 0.98f)},
+ {"LAVENDERBLUSH", new Color(1.00f, 0.94f, 0.96f)},
+ {"LAWNGREEN", new Color(0.49f, 0.99f, 0.00f)},
+ {"LEMONCHIFFON", new Color(1.00f, 0.98f, 0.80f)},
+ {"LIGHTBLUE", new Color(0.68f, 0.85f, 0.90f)},
+ {"LIGHTCORAL", new Color(0.94f, 0.50f, 0.50f)},
+ {"LIGHTCYAN", new Color(0.88f, 1.00f, 1.00f)},
+ {"LIGHTGOLDENROD", new Color(0.98f, 0.98f, 0.82f)},
+ {"LIGHTGRAY", new Color(0.83f, 0.83f, 0.83f)},
+ {"LIGHTGREEN", new Color(0.56f, 0.93f, 0.56f)},
+ {"LIGHTPINK", new Color(1.00f, 0.71f, 0.76f)},
+ {"LIGHTSALMON", new Color(1.00f, 0.63f, 0.48f)},
+ {"LIGHTSEAGREEN", new Color(0.13f, 0.70f, 0.67f)},
+ {"LIGHTSKYBLUE", new Color(0.53f, 0.81f, 0.98f)},
+ {"LIGHTSLATEGRAY", new Color(0.47f, 0.53f, 0.60f)},
+ {"LIGHTSTEELBLUE", new Color(0.69f, 0.77f, 0.87f)},
+ {"LIGHTYELLOW", new Color(1.00f, 1.00f, 0.88f)},
+ {"LIME", new Color(0.00f, 1.00f, 0.00f)},
+ {"LIMEGREEN", new Color(0.20f, 0.80f, 0.20f)},
+ {"LINEN", new Color(0.98f, 0.94f, 0.90f)},
+ {"MAGENTA", new Color(1.00f, 0.00f, 1.00f)},
+ {"MAROON", new Color(0.69f, 0.19f, 0.38f)},
+ {"MEDIUMAQUAMARINE", new Color(0.40f, 0.80f, 0.67f)},
+ {"MEDIUMBLUE", new Color(0.00f, 0.00f, 0.80f)},
+ {"MEDIUMORCHID", new Color(0.73f, 0.33f, 0.83f)},
+ {"MEDIUMPURPLE", new Color(0.58f, 0.44f, 0.86f)},
+ {"MEDIUMSEAGREEN", new Color(0.24f, 0.70f, 0.44f)},
+ {"MEDIUMSLATEBLUE", new Color(0.48f, 0.41f, 0.93f)},
+ {"MEDIUMSPRINGGREEN", new Color(0.00f, 0.98f, 0.60f)},
+ {"MEDIUMTURQUOISE", new Color(0.28f, 0.82f, 0.80f)},
+ {"MEDIUMVIOLETRED", new Color(0.78f, 0.08f, 0.52f)},
+ {"MIDNIGHTBLUE", new Color(0.10f, 0.10f, 0.44f)},
+ {"MINTCREAM", new Color(0.96f, 1.00f, 0.98f)},
+ {"MISTYROSE", new Color(1.00f, 0.89f, 0.88f)},
+ {"MOCCASIN", new Color(1.00f, 0.89f, 0.71f)},
+ {"NAVAJOWHITE", new Color(1.00f, 0.87f, 0.68f)},
+ {"NAVYBLUE", new Color(0.00f, 0.00f, 0.50f)},
+ {"OLDLACE", new Color(0.99f, 0.96f, 0.90f)},
+ {"OLIVE", new Color(0.50f, 0.50f, 0.00f)},
+ {"OLIVEDRAB", new Color(0.42f, 0.56f, 0.14f)},
+ {"ORANGE", new Color(1.00f, 0.65f, 0.00f)},
+ {"ORANGERED", new Color(1.00f, 0.27f, 0.00f)},
+ {"ORCHID", new Color(0.85f, 0.44f, 0.84f)},
+ {"PALEGOLDENROD", new Color(0.93f, 0.91f, 0.67f)},
+ {"PALEGREEN", new Color(0.60f, 0.98f, 0.60f)},
+ {"PALETURQUOISE", new Color(0.69f, 0.93f, 0.93f)},
+ {"PALEVIOLETRED", new Color(0.86f, 0.44f, 0.58f)},
+ {"PAPAYAWHIP", new Color(1.00f, 0.94f, 0.84f)},
+ {"PEACHPUFF", new Color(1.00f, 0.85f, 0.73f)},
+ {"PERU", new Color(0.80f, 0.52f, 0.25f)},
+ {"PINK", new Color(1.00f, 0.75f, 0.80f)},
+ {"PLUM", new Color(0.87f, 0.63f, 0.87f)},
+ {"POWDERBLUE", new Color(0.69f, 0.88f, 0.90f)},
+ {"PURPLE", new Color(0.63f, 0.13f, 0.94f)},
+ {"REBECCAPURPLE", new Color(0.40f, 0.20f, 0.60f)},
+ {"RED", new Color(1.00f, 0.00f, 0.00f)},
+ {"ROSYBROWN", new Color(0.74f, 0.56f, 0.56f)},
+ {"ROYALBLUE", new Color(0.25f, 0.41f, 0.88f)},
+ {"SADDLEBROWN", new Color(0.55f, 0.27f, 0.07f)},
+ {"SALMON", new Color(0.98f, 0.50f, 0.45f)},
+ {"SANDYBROWN", new Color(0.96f, 0.64f, 0.38f)},
+ {"SEAGREEN", new Color(0.18f, 0.55f, 0.34f)},
+ {"SEASHELL", new Color(1.00f, 0.96f, 0.93f)},
+ {"SIENNA", new Color(0.63f, 0.32f, 0.18f)},
+ {"SILVER", new Color(0.75f, 0.75f, 0.75f)},
+ {"SKYBLUE", new Color(0.53f, 0.81f, 0.92f)},
+ {"SLATEBLUE", new Color(0.42f, 0.35f, 0.80f)},
+ {"SLATEGRAY", new Color(0.44f, 0.50f, 0.56f)},
+ {"SNOW", new Color(1.00f, 0.98f, 0.98f)},
+ {"SPRINGGREEN", new Color(0.00f, 1.00f, 0.50f)},
+ {"STEELBLUE", new Color(0.27f, 0.51f, 0.71f)},
+ {"TAN", new Color(0.82f, 0.71f, 0.55f)},
+ {"TEAL", new Color(0.00f, 0.50f, 0.50f)},
+ {"THISTLE", new Color(0.85f, 0.75f, 0.85f)},
+ {"TOMATO", new Color(1.00f, 0.39f, 0.28f)},
+ {"TRANSPARENT", new Color(1.00f, 1.00f, 1.00f, 0.00f)},
+ {"TURQUOISE", new Color(0.25f, 0.88f, 0.82f)},
+ {"VIOLET", new Color(0.93f, 0.51f, 0.93f)},
+ {"WEBGRAY", new Color(0.50f, 0.50f, 0.50f)},
+ {"WEBGREEN", new Color(0.00f, 0.50f, 0.00f)},
+ {"WEBMAROON", new Color(0.50f, 0.00f, 0.00f)},
+ {"WEBPURPLE", new Color(0.50f, 0.00f, 0.50f)},
+ {"WHEAT", new Color(0.96f, 0.87f, 0.70f)},
+ {"WHITE", new Color(1.00f, 1.00f, 1.00f)},
+ {"WHITESMOKE", new Color(0.96f, 0.96f, 0.96f)},
+ {"YELLOW", new Color(1.00f, 1.00f, 0.00f)},
+ {"YELLOWGREEN", new Color(0.60f, 0.80f, 0.20f)},
};
- public static Color AliceBlue { get { return namedColors["aliceblue"]; } }
- public static Color AntiqueWhite { get { return namedColors["antiquewhite"]; } }
- public static Color Aqua { get { return namedColors["aqua"]; } }
- public static Color Aquamarine { get { return namedColors["aquamarine"]; } }
- public static Color Azure { get { return namedColors["azure"]; } }
- public static Color Beige { get { return namedColors["beige"]; } }
- public static Color Bisque { get { return namedColors["bisque"]; } }
- public static Color Black { get { return namedColors["black"]; } }
- public static Color BlanchedAlmond { get { return namedColors["blanchedalmond"]; } }
- public static Color Blue { get { return namedColors["blue"]; } }
- public static Color BlueViolet { get { return namedColors["blueviolet"]; } }
- public static Color Brown { get { return namedColors["brown"]; } }
- public static Color BurlyWood { get { return namedColors["burlywood"]; } }
- public static Color CadetBlue { get { return namedColors["cadetblue"]; } }
- public static Color Chartreuse { get { return namedColors["chartreuse"]; } }
- public static Color Chocolate { get { return namedColors["chocolate"]; } }
- public static Color Coral { get { return namedColors["coral"]; } }
- public static Color Cornflower { get { return namedColors["cornflower"]; } }
- public static Color Cornsilk { get { return namedColors["cornsilk"]; } }
- public static Color Crimson { get { return namedColors["crimson"]; } }
- public static Color Cyan { get { return namedColors["cyan"]; } }
- public static Color DarkBlue { get { return namedColors["darkblue"]; } }
- public static Color DarkCyan { get { return namedColors["darkcyan"]; } }
- public static Color DarkGoldenrod { get { return namedColors["darkgoldenrod"]; } }
- public static Color DarkGray { get { return namedColors["darkgray"]; } }
- public static Color DarkGreen { get { return namedColors["darkgreen"]; } }
- public static Color DarkKhaki { get { return namedColors["darkkhaki"]; } }
- public static Color DarkMagenta { get { return namedColors["darkmagenta"]; } }
- public static Color DarkOliveGreen { get { return namedColors["darkolivegreen"]; } }
- public static Color DarkOrange { get { return namedColors["darkorange"]; } }
- public static Color DarkOrchid { get { return namedColors["darkorchid"]; } }
- public static Color DarkRed { get { return namedColors["darkred"]; } }
- public static Color DarkSalmon { get { return namedColors["darksalmon"]; } }
- public static Color DarkSeaGreen { get { return namedColors["darkseagreen"]; } }
- public static Color DarkSlateBlue { get { return namedColors["darkslateblue"]; } }
- public static Color DarkSlateGray { get { return namedColors["darkslategray"]; } }
- public static Color DarkTurquoise { get { return namedColors["darkturquoise"]; } }
- public static Color DarkViolet { get { return namedColors["darkviolet"]; } }
- public static Color DeepPink { get { return namedColors["deeppink"]; } }
- public static Color DeepSkyBlue { get { return namedColors["deepskyblue"]; } }
- public static Color DimGray { get { return namedColors["dimgray"]; } }
- public static Color DodgerBlue { get { return namedColors["dodgerblue"]; } }
- public static Color Firebrick { get { return namedColors["firebrick"]; } }
- public static Color FloralWhite { get { return namedColors["floralwhite"]; } }
- public static Color ForestGreen { get { return namedColors["forestgreen"]; } }
- public static Color Fuchsia { get { return namedColors["fuchsia"]; } }
- public static Color Gainsboro { get { return namedColors["gainsboro"]; } }
- public static Color GhostWhite { get { return namedColors["ghostwhite"]; } }
- public static Color Gold { get { return namedColors["gold"]; } }
- public static Color Goldenrod { get { return namedColors["goldenrod"]; } }
- public static Color Gray { get { return namedColors["gray"]; } }
- public static Color Green { get { return namedColors["green"]; } }
- public static Color GreenYellow { get { return namedColors["greenyellow"]; } }
- public static Color Honeydew { get { return namedColors["honeydew"]; } }
- public static Color HotPink { get { return namedColors["hotpink"]; } }
- public static Color IndianRed { get { return namedColors["indianred"]; } }
- public static Color Indigo { get { return namedColors["indigo"]; } }
- public static Color Ivory { get { return namedColors["ivory"]; } }
- public static Color Khaki { get { return namedColors["khaki"]; } }
- public static Color Lavender { get { return namedColors["lavender"]; } }
- public static Color LavenderBlush { get { return namedColors["lavenderblush"]; } }
- public static Color LawnGreen { get { return namedColors["lawngreen"]; } }
- public static Color LemonChiffon { get { return namedColors["lemonchiffon"]; } }
- public static Color LightBlue { get { return namedColors["lightblue"]; } }
- public static Color LightCoral { get { return namedColors["lightcoral"]; } }
- public static Color LightCyan { get { return namedColors["lightcyan"]; } }
- public static Color LightGoldenrod { get { return namedColors["lightgoldenrod"]; } }
- public static Color LightGray { get { return namedColors["lightgray"]; } }
- public static Color LightGreen { get { return namedColors["lightgreen"]; } }
- public static Color LightPink { get { return namedColors["lightpink"]; } }
- public static Color LightSalmon { get { return namedColors["lightsalmon"]; } }
- public static Color LightSeaGreen { get { return namedColors["lightseagreen"]; } }
- public static Color LightSkyBlue { get { return namedColors["lightskyblue"]; } }
- public static Color LightSlateGray { get { return namedColors["lightslategray"]; } }
- public static Color LightSteelBlue { get { return namedColors["lightsteelblue"]; } }
- public static Color LightYellow { get { return namedColors["lightyellow"]; } }
- public static Color Lime { get { return namedColors["lime"]; } }
- public static Color Limegreen { get { return namedColors["limegreen"]; } }
- public static Color Linen { get { return namedColors["linen"]; } }
- public static Color Magenta { get { return namedColors["magenta"]; } }
- public static Color Maroon { get { return namedColors["maroon"]; } }
- public static Color MediumAquamarine { get { return namedColors["mediumaquamarine"]; } }
- public static Color MediumBlue { get { return namedColors["mediumblue"]; } }
- public static Color MediumOrchid { get { return namedColors["mediumorchid"]; } }
- public static Color MediumPurple { get { return namedColors["mediumpurple"]; } }
- public static Color MediumSeaGreen { get { return namedColors["mediumseagreen"]; } }
- public static Color MediumSlateBlue { get { return namedColors["mediumslateblue"]; } }
- public static Color MediumSpringGreen { get { return namedColors["mediumspringgreen"]; } }
- public static Color MediumTurquoise { get { return namedColors["mediumturquoise"]; } }
- public static Color MediumVioletRed { get { return namedColors["mediumvioletred"]; } }
- public static Color MidnightBlue { get { return namedColors["midnightblue"]; } }
- public static Color MintCream { get { return namedColors["mintcream"]; } }
- public static Color MistyRose { get { return namedColors["mistyrose"]; } }
- public static Color Moccasin { get { return namedColors["moccasin"]; } }
- public static Color NavajoWhite { get { return namedColors["navajowhite"]; } }
- public static Color NavyBlue { get { return namedColors["navyblue"]; } }
- public static Color OldLace { get { return namedColors["oldlace"]; } }
- public static Color Olive { get { return namedColors["olive"]; } }
- public static Color OliveDrab { get { return namedColors["olivedrab"]; } }
- public static Color Orange { get { return namedColors["orange"]; } }
- public static Color OrangeRed { get { return namedColors["orangered"]; } }
- public static Color Orchid { get { return namedColors["orchid"]; } }
- public static Color PaleGoldenrod { get { return namedColors["palegoldenrod"]; } }
- public static Color PaleGreen { get { return namedColors["palegreen"]; } }
- public static Color PaleTurquoise { get { return namedColors["paleturquoise"]; } }
- public static Color PaleVioletRed { get { return namedColors["palevioletred"]; } }
- public static Color PapayaWhip { get { return namedColors["papayawhip"]; } }
- public static Color PeachPuff { get { return namedColors["peachpuff"]; } }
- public static Color Peru { get { return namedColors["peru"]; } }
- public static Color Pink { get { return namedColors["pink"]; } }
- public static Color Plum { get { return namedColors["plum"]; } }
- public static Color PowderBlue { get { return namedColors["powderblue"]; } }
- public static Color Purple { get { return namedColors["purple"]; } }
- public static Color RebeccaPurple { get { return namedColors["rebeccapurple"]; } }
- public static Color Red { get { return namedColors["red"]; } }
- public static Color RosyBrown { get { return namedColors["rosybrown"]; } }
- public static Color RoyalBlue { get { return namedColors["royalblue"]; } }
- public static Color SaddleBrown { get { return namedColors["saddlebrown"]; } }
- public static Color Salmon { get { return namedColors["salmon"]; } }
- public static Color SandyBrown { get { return namedColors["sandybrown"]; } }
- public static Color SeaGreen { get { return namedColors["seagreen"]; } }
- public static Color SeaShell { get { return namedColors["seashell"]; } }
- public static Color Sienna { get { return namedColors["sienna"]; } }
- public static Color Silver { get { return namedColors["silver"]; } }
- public static Color SkyBlue { get { return namedColors["skyblue"]; } }
- public static Color SlateBlue { get { return namedColors["slateblue"]; } }
- public static Color SlateGray { get { return namedColors["slategray"]; } }
- public static Color Snow { get { return namedColors["snow"]; } }
- public static Color SpringGreen { get { return namedColors["springgreen"]; } }
- public static Color SteelBlue { get { return namedColors["steelblue"]; } }
- public static Color Tan { get { return namedColors["tan"]; } }
- public static Color Teal { get { return namedColors["teal"]; } }
- public static Color Thistle { get { return namedColors["thistle"]; } }
- public static Color Tomato { get { return namedColors["tomato"]; } }
- public static Color Transparent { get { return namedColors["transparent"]; } }
- public static Color Turquoise { get { return namedColors["turquoise"]; } }
- public static Color Violet { get { return namedColors["violet"]; } }
- public static Color WebGreen { get { return namedColors["webgreen"]; } }
- public static Color WebGray { get { return namedColors["webgray"]; } }
- public static Color WebMaroon { get { return namedColors["webmaroon"]; } }
- public static Color WebPurple { get { return namedColors["webpurple"]; } }
- public static Color Wheat { get { return namedColors["wheat"]; } }
- public static Color White { get { return namedColors["white"]; } }
- public static Color WhiteSmoke { get { return namedColors["whitesmoke"]; } }
- public static Color Yellow { get { return namedColors["yellow"]; } }
- public static Color YellowGreen { get { return namedColors["yellowgreen"]; } }
+ public static Color AliceBlue { get { return namedColors["ALICEBLUE"]; } }
+ public static Color AntiqueWhite { get { return namedColors["ANTIQUEWHITE"]; } }
+ public static Color Aqua { get { return namedColors["AQUA"]; } }
+ public static Color Aquamarine { get { return namedColors["AQUAMARINE"]; } }
+ public static Color Azure { get { return namedColors["AZURE"]; } }
+ public static Color Beige { get { return namedColors["BEIGE"]; } }
+ public static Color Bisque { get { return namedColors["BISQUE"]; } }
+ public static Color Black { get { return namedColors["BLACK"]; } }
+ public static Color BlanchedAlmond { get { return namedColors["BLANCHEDALMOND"]; } }
+ public static Color Blue { get { return namedColors["BLUE"]; } }
+ public static Color BlueViolet { get { return namedColors["BLUEVIOLET"]; } }
+ public static Color Brown { get { return namedColors["BROWN"]; } }
+ public static Color Burlywood { get { return namedColors["BURLYWOOD"]; } }
+ public static Color CadetBlue { get { return namedColors["CADETBLUE"]; } }
+ public static Color Chartreuse { get { return namedColors["CHARTREUSE"]; } }
+ public static Color Chocolate { get { return namedColors["CHOCOLATE"]; } }
+ public static Color Coral { get { return namedColors["CORAL"]; } }
+ public static Color CornflowerBlue { get { return namedColors["CORNFLOWERBLUE"]; } }
+ public static Color Cornsilk { get { return namedColors["CORNSILK"]; } }
+ public static Color Crimson { get { return namedColors["CRIMSON"]; } }
+ public static Color Cyan { get { return namedColors["CYAN"]; } }
+ public static Color DarkBlue { get { return namedColors["DARKBLUE"]; } }
+ public static Color DarkCyan { get { return namedColors["DARKCYAN"]; } }
+ public static Color DarkGoldenrod { get { return namedColors["DARKGOLDENROD"]; } }
+ public static Color DarkGray { get { return namedColors["DARKGRAY"]; } }
+ public static Color DarkGreen { get { return namedColors["DARKGREEN"]; } }
+ public static Color DarkKhaki { get { return namedColors["DARKKHAKI"]; } }
+ public static Color DarkMagenta { get { return namedColors["DARKMAGENTA"]; } }
+ public static Color DarkOliveGreen { get { return namedColors["DARKOLIVEGREEN"]; } }
+ public static Color DarkOrange { get { return namedColors["DARKORANGE"]; } }
+ public static Color DarkOrchid { get { return namedColors["DARKORCHID"]; } }
+ public static Color DarkRed { get { return namedColors["DARKRED"]; } }
+ public static Color DarkSalmon { get { return namedColors["DARKSALMON"]; } }
+ public static Color DarkSeaGreen { get { return namedColors["DARKSEAGREEN"]; } }
+ public static Color DarkSlateBlue { get { return namedColors["DARKSLATEBLUE"]; } }
+ public static Color DarkSlateGray { get { return namedColors["DARKSLATEGRAY"]; } }
+ public static Color DarkTurquoise { get { return namedColors["DARKTURQUOISE"]; } }
+ public static Color DarkViolet { get { return namedColors["DARKVIOLET"]; } }
+ public static Color DeepPink { get { return namedColors["DEEPPINK"]; } }
+ public static Color DeepSkyBlue { get { return namedColors["DEEPSKYBLUE"]; } }
+ public static Color DimGray { get { return namedColors["DIMGRAY"]; } }
+ public static Color DodgerBlue { get { return namedColors["DODGERBLUE"]; } }
+ public static Color Firebrick { get { return namedColors["FIREBRICK"]; } }
+ public static Color FloralWhite { get { return namedColors["FLORALWHITE"]; } }
+ public static Color ForestGreen { get { return namedColors["FORESTGREEN"]; } }
+ public static Color Fuchsia { get { return namedColors["FUCHSIA"]; } }
+ public static Color Gainsboro { get { return namedColors["GAINSBORO"]; } }
+ public static Color GhostWhite { get { return namedColors["GHOSTWHITE"]; } }
+ public static Color Gold { get { return namedColors["GOLD"]; } }
+ public static Color Goldenrod { get { return namedColors["GOLDENROD"]; } }
+ public static Color Gray { get { return namedColors["GRAY"]; } }
+ public static Color Green { get { return namedColors["GREEN"]; } }
+ public static Color GreenYellow { get { return namedColors["GREENYELLOW"]; } }
+ public static Color Honeydew { get { return namedColors["HONEYDEW"]; } }
+ public static Color HotPink { get { return namedColors["HOTPINK"]; } }
+ public static Color IndianRed { get { return namedColors["INDIANRED"]; } }
+ public static Color Indigo { get { return namedColors["INDIGO"]; } }
+ public static Color Ivory { get { return namedColors["IVORY"]; } }
+ public static Color Khaki { get { return namedColors["KHAKI"]; } }
+ public static Color Lavender { get { return namedColors["LAVENDER"]; } }
+ public static Color LavenderBlush { get { return namedColors["LAVENDERBLUSH"]; } }
+ public static Color LawnGreen { get { return namedColors["LAWNGREEN"]; } }
+ public static Color LemonChiffon { get { return namedColors["LEMONCHIFFON"]; } }
+ public static Color LightBlue { get { return namedColors["LIGHTBLUE"]; } }
+ public static Color LightCoral { get { return namedColors["LIGHTCORAL"]; } }
+ public static Color LightCyan { get { return namedColors["LIGHTCYAN"]; } }
+ public static Color LightGoldenrod { get { return namedColors["LIGHTGOLDENROD"]; } }
+ public static Color LightGray { get { return namedColors["LIGHTGRAY"]; } }
+ public static Color LightGreen { get { return namedColors["LIGHTGREEN"]; } }
+ public static Color LightPink { get { return namedColors["LIGHTPINK"]; } }
+ public static Color LightSalmon { get { return namedColors["LIGHTSALMON"]; } }
+ public static Color LightSeaGreen { get { return namedColors["LIGHTSEAGREEN"]; } }
+ public static Color LightSkyBlue { get { return namedColors["LIGHTSKYBLUE"]; } }
+ public static Color LightSlateGray { get { return namedColors["LIGHTSLATEGRAY"]; } }
+ public static Color LightSteelBlue { get { return namedColors["LIGHTSTEELBLUE"]; } }
+ public static Color LightYellow { get { return namedColors["LIGHTYELLOW"]; } }
+ public static Color Lime { get { return namedColors["LIME"]; } }
+ public static Color LimeGreen { get { return namedColors["LIMEGREEN"]; } }
+ public static Color Linen { get { return namedColors["LINEN"]; } }
+ public static Color Magenta { get { return namedColors["MAGENTA"]; } }
+ public static Color Maroon { get { return namedColors["MAROON"]; } }
+ public static Color MediumAquamarine { get { return namedColors["MEDIUMAQUAMARINE"]; } }
+ public static Color MediumBlue { get { return namedColors["MEDIUMBLUE"]; } }
+ public static Color MediumOrchid { get { return namedColors["MEDIUMORCHID"]; } }
+ public static Color MediumPurple { get { return namedColors["MEDIUMPURPLE"]; } }
+ public static Color MediumSeaGreen { get { return namedColors["MEDIUMSEAGREEN"]; } }
+ public static Color MediumSlateBlue { get { return namedColors["MEDIUMSLATEBLUE"]; } }
+ public static Color MediumSpringGreen { get { return namedColors["MEDIUMSPRINGGREEN"]; } }
+ public static Color MediumTurquoise { get { return namedColors["MEDIUMTURQUOISE"]; } }
+ public static Color MediumVioletRed { get { return namedColors["MEDIUMVIOLETRED"]; } }
+ public static Color MidnightBlue { get { return namedColors["MIDNIGHTBLUE"]; } }
+ public static Color MintCream { get { return namedColors["MINTCREAM"]; } }
+ public static Color MistyRose { get { return namedColors["MISTYROSE"]; } }
+ public static Color Moccasin { get { return namedColors["MOCCASIN"]; } }
+ public static Color NavajoWhite { get { return namedColors["NAVAJOWHITE"]; } }
+ public static Color NavyBlue { get { return namedColors["NAVYBLUE"]; } }
+ public static Color OldLace { get { return namedColors["OLDLACE"]; } }
+ public static Color Olive { get { return namedColors["OLIVE"]; } }
+ public static Color OliveDrab { get { return namedColors["OLIVEDRAB"]; } }
+ public static Color Orange { get { return namedColors["ORANGE"]; } }
+ public static Color OrangeRed { get { return namedColors["ORANGERED"]; } }
+ public static Color Orchid { get { return namedColors["ORCHID"]; } }
+ public static Color PaleGoldenrod { get { return namedColors["PALEGOLDENROD"]; } }
+ public static Color PaleGreen { get { return namedColors["PALEGREEN"]; } }
+ public static Color PaleTurquoise { get { return namedColors["PALETURQUOISE"]; } }
+ public static Color PaleVioletRed { get { return namedColors["PALEVIOLETRED"]; } }
+ public static Color PapayaWhip { get { return namedColors["PAPAYAWHIP"]; } }
+ public static Color PeachPuff { get { return namedColors["PEACHPUFF"]; } }
+ public static Color Peru { get { return namedColors["PERU"]; } }
+ public static Color Pink { get { return namedColors["PINK"]; } }
+ public static Color Plum { get { return namedColors["PLUM"]; } }
+ public static Color PowderBlue { get { return namedColors["POWDERBLUE"]; } }
+ public static Color Purple { get { return namedColors["PURPLE"]; } }
+ public static Color RebeccaPurple { get { return namedColors["REBECCAPURPLE"]; } }
+ public static Color Red { get { return namedColors["RED"]; } }
+ public static Color RosyBrown { get { return namedColors["ROSYBROWN"]; } }
+ public static Color RoyalBlue { get { return namedColors["ROYALBLUE"]; } }
+ public static Color SaddleBrown { get { return namedColors["SADDLEBROWN"]; } }
+ public static Color Salmon { get { return namedColors["SALMON"]; } }
+ public static Color SandyBrown { get { return namedColors["SANDYBROWN"]; } }
+ public static Color SeaGreen { get { return namedColors["SEAGREEN"]; } }
+ public static Color Seashell { get { return namedColors["SEASHELL"]; } }
+ public static Color Sienna { get { return namedColors["SIENNA"]; } }
+ public static Color Silver { get { return namedColors["SILVER"]; } }
+ public static Color SkyBlue { get { return namedColors["SKYBLUE"]; } }
+ public static Color SlateBlue { get { return namedColors["SLATEBLUE"]; } }
+ public static Color SlateGray { get { return namedColors["SLATEGRAY"]; } }
+ public static Color Snow { get { return namedColors["SNOW"]; } }
+ public static Color SpringGreen { get { return namedColors["SPRINGGREEN"]; } }
+ public static Color SteelBlue { get { return namedColors["STEELBLUE"]; } }
+ public static Color Tan { get { return namedColors["TAN"]; } }
+ public static Color Teal { get { return namedColors["TEAL"]; } }
+ public static Color Thistle { get { return namedColors["THISTLE"]; } }
+ public static Color Tomato { get { return namedColors["TOMATO"]; } }
+ public static Color Transparent { get { return namedColors["TRANSPARENT"]; } }
+ public static Color Turquoise { get { return namedColors["TURQUOISE"]; } }
+ public static Color Violet { get { return namedColors["VIOLET"]; } }
+ public static Color WebGray { get { return namedColors["WEBGRAY"]; } }
+ public static Color WebGreen { get { return namedColors["WEBGREEN"]; } }
+ public static Color WebMaroon { get { return namedColors["WEBMAROON"]; } }
+ public static Color WebPurple { get { return namedColors["WEBPURPLE"]; } }
+ public static Color Wheat { get { return namedColors["WHEAT"]; } }
+ public static Color White { get { return namedColors["WHITE"]; } }
+ public static Color WhiteSmoke { get { return namedColors["WHITESMOKE"]; } }
+ public static Color Yellow { get { return namedColors["YELLOW"]; } }
+ public static Color YellowGreen { get { return namedColors["YELLOWGREEN"]; } }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 48582d5ad8..d486d79557 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -66,7 +66,7 @@ namespace Godot
if (memoryOwn)
{
memoryOwn = false;
- godot_icall_Reference_Disposed(this, ptr, !disposing);
+ godot_icall_RefCounted_Disposed(this, ptr, !disposing);
}
else
{
@@ -129,7 +129,7 @@ namespace Godot
internal static extern void godot_icall_Object_Disposed(Object obj, IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Reference_Disposed(Object obj, IntPtr ptr, bool isFinalizer);
+ internal static extern void godot_icall_RefCounted_Disposed(Object obj, IntPtr ptr, bool isFinalizer);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void godot_icall_Object_ConnectEventSignals(IntPtr obj);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
index 2f8b5f297c..ad6ca51e8b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
@@ -355,7 +355,7 @@ namespace Godot
public override string ToString()
{
- return String.Format("({0}, {1})", new object[]
+ return String.Format("{0}, {1}", new object[]
{
_normal.ToString(),
D.ToString()
@@ -364,7 +364,7 @@ namespace Godot
public string ToString(string format)
{
- return String.Format("({0}, {1})", new object[]
+ return String.Format("{0}, {1}", new object[]
{
_normal.ToString(format),
D.ToString(format)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
index bd3bcb0c58..b087b4c200 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
@@ -15,7 +15,7 @@ namespace Godot
/// It is similar to Basis, which implements matrix representation of
/// rotations, and can be parametrized using both an axis-angle pair
/// or Euler angles. Basis stores rotation, scale, and shearing,
- /// while Quat only stores rotation.
+ /// while Quaternion only stores rotation.
///
/// Due to its compactness and the way it is stored in memory, certain
/// operations (obtaining axis-angle and performing SLERP, in particular)
@@ -23,7 +23,7 @@ namespace Godot
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
- public struct Quat : IEquatable<Quat>
+ public struct Quaternion : IEquatable<Quaternion>
{
/// <summary>
/// X component of the quaternion (imaginary `i` axis part).
@@ -122,11 +122,11 @@ namespace Godot
/// <param name="postB">A quaternion after `b`.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated quaternion.</returns>
- public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t weight)
+ public Quaternion CubicSlerp(Quaternion b, Quaternion preA, Quaternion postB, real_t weight)
{
real_t t2 = (1.0f - weight) * weight * 2f;
- Quat sp = Slerp(b, weight);
- Quat sq = preA.Slerpni(postB, weight);
+ Quaternion sp = Slerp(b, weight);
+ Quaternion sq = preA.Slerpni(postB, weight);
return sp.Slerpni(sq, t2);
}
@@ -135,7 +135,7 @@ namespace Godot
/// </summary>
/// <param name="b">The other quaternion.</param>
/// <returns>The dot product.</returns>
- public real_t Dot(Quat b)
+ public real_t Dot(Quaternion b)
{
return x * b.x + y * b.y + z * b.z + w * b.w;
}
@@ -152,7 +152,7 @@ namespace Godot
#if DEBUG
if (!IsNormalized())
{
- throw new InvalidOperationException("Quat is not normalized");
+ throw new InvalidOperationException("Quaternion is not normalized");
}
#endif
var basis = new Basis(this);
@@ -163,15 +163,15 @@ namespace Godot
/// Returns the inverse of the quaternion.
/// </summary>
/// <returns>The inverse quaternion.</returns>
- public Quat Inverse()
+ public Quaternion Inverse()
{
#if DEBUG
if (!IsNormalized())
{
- throw new InvalidOperationException("Quat is not normalized");
+ throw new InvalidOperationException("Quaternion is not normalized");
}
#endif
- return new Quat(-x, -y, -z, w);
+ return new Quaternion(-x, -y, -z, w);
}
/// <summary>
@@ -187,7 +187,7 @@ namespace Godot
/// Returns a copy of the quaternion, normalized to unit length.
/// </summary>
/// <returns>The normalized quaternion.</returns>
- public Quat Normalized()
+ public Quaternion Normalized()
{
return this / Length;
}
@@ -201,12 +201,12 @@ namespace Godot
/// <param name="to">The destination quaternion for interpolation. Must be normalized.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting quaternion of the interpolation.</returns>
- public Quat Slerp(Quat to, real_t weight)
+ public Quaternion Slerp(Quaternion to, real_t weight)
{
#if DEBUG
if (!IsNormalized())
{
- throw new InvalidOperationException("Quat is not normalized");
+ throw new InvalidOperationException("Quaternion is not normalized");
}
if (!to.IsNormalized())
{
@@ -217,7 +217,7 @@ namespace Godot
// Calculate cosine.
real_t cosom = x * to.x + y * to.y + z * to.z + w * to.w;
- var to1 = new Quat();
+ var to1 = new Quaternion();
// Adjust signs if necessary.
if (cosom < 0.0)
@@ -255,7 +255,7 @@ namespace Godot
}
// Calculate final values.
- return new Quat
+ return new Quaternion
(
scale0 * x + scale1 * to1.x,
scale0 * y + scale1 * to1.y,
@@ -272,7 +272,7 @@ namespace Godot
/// <param name="to">The destination quaternion for interpolation. Must be normalized.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting quaternion of the interpolation.</returns>
- public Quat Slerpni(Quat to, real_t weight)
+ public Quaternion Slerpni(Quaternion to, real_t weight)
{
real_t dot = Dot(to);
@@ -286,7 +286,7 @@ namespace Godot
real_t newFactor = Mathf.Sin(weight * theta) * sinT;
real_t invFactor = Mathf.Sin((1.0f - weight) * theta) * sinT;
- return new Quat
+ return new Quaternion
(
invFactor * x + newFactor * to.x,
invFactor * y + newFactor * to.y,
@@ -305,7 +305,7 @@ namespace Godot
#if DEBUG
if (!IsNormalized())
{
- throw new InvalidOperationException("Quat is not normalized");
+ throw new InvalidOperationException("Quaternion is not normalized");
}
#endif
var u = new Vector3(x, y, z);
@@ -314,15 +314,15 @@ namespace Godot
}
// Constants
- private static readonly Quat _identity = new Quat(0, 0, 0, 1);
+ private static readonly Quaternion _identity = new Quaternion(0, 0, 0, 1);
/// <summary>
/// The identity quaternion, representing no rotation.
/// Equivalent to an identity <see cref="Basis"/> matrix. If a vector is transformed by
/// an identity quaternion, it will not change.
/// </summary>
- /// <value>Equivalent to `new Quat(0, 0, 0, 1)`.</value>
- public static Quat Identity { get { return _identity; } }
+ /// <value>Equivalent to `new Quaternion(0, 0, 0, 1)`.</value>
+ public static Quaternion Identity { get { return _identity; } }
/// <summary>
/// Constructs a quaternion defined by the given values.
@@ -331,7 +331,7 @@ namespace Godot
/// <param name="y">Y component of the quaternion (imaginary `j` axis part).</param>
/// <param name="z">Z component of the quaternion (imaginary `k` axis part).</param>
/// <param name="w">W component of the quaternion (real part).</param>
- public Quat(real_t x, real_t y, real_t z, real_t w)
+ public Quaternion(real_t x, real_t y, real_t z, real_t w)
{
this.x = x;
this.y = y;
@@ -343,7 +343,7 @@ namespace Godot
/// Constructs a quaternion from the given quaternion.
/// </summary>
/// <param name="q">The existing quaternion.</param>
- public Quat(Quat q)
+ public Quaternion(Quaternion q)
{
this = q;
}
@@ -352,9 +352,9 @@ namespace Godot
/// Constructs a quaternion from the given <see cref="Basis"/>.
/// </summary>
/// <param name="basis">The basis to construct from.</param>
- public Quat(Basis basis)
+ public Quaternion(Basis basis)
{
- this = basis.Quat();
+ this = basis.Quaternion();
}
/// <summary>
@@ -364,7 +364,7 @@ namespace Godot
/// given in the vector format as (X angle, Y angle, Z angle).
/// </summary>
/// <param name="eulerYXZ"></param>
- public Quat(Vector3 eulerYXZ)
+ public Quaternion(Vector3 eulerYXZ)
{
real_t half_a1 = eulerYXZ.y * 0.5f;
real_t half_a2 = eulerYXZ.x * 0.5f;
@@ -393,7 +393,7 @@ namespace Godot
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate, in radians.</param>
- public Quat(Vector3 axis, real_t angle)
+ public Quaternion(Vector3 axis, real_t angle)
{
#if DEBUG
if (!axis.IsNormalized())
@@ -424,9 +424,9 @@ namespace Godot
}
}
- public static Quat operator *(Quat left, Quat right)
+ public static Quaternion operator *(Quaternion left, Quaternion right)
{
- return new Quat
+ return new Quaternion
(
left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y,
left.w * right.y + left.y * right.w + left.z * right.x - left.x * right.z,
@@ -435,24 +435,24 @@ namespace Godot
);
}
- public static Quat operator +(Quat left, Quat right)
+ public static Quaternion operator +(Quaternion left, Quaternion right)
{
- return new Quat(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
+ return new Quaternion(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
}
- public static Quat operator -(Quat left, Quat right)
+ public static Quaternion operator -(Quaternion left, Quaternion right)
{
- return new Quat(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
+ return new Quaternion(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
}
- public static Quat operator -(Quat left)
+ public static Quaternion operator -(Quaternion left)
{
- return new Quat(-left.x, -left.y, -left.z, -left.w);
+ return new Quaternion(-left.x, -left.y, -left.z, -left.w);
}
- public static Quat operator *(Quat left, Vector3 right)
+ public static Quaternion operator *(Quaternion left, Vector3 right)
{
- return new Quat
+ return new Quaternion
(
left.w * right.x + left.y * right.z - left.z * right.y,
left.w * right.y + left.z * right.x - left.x * right.z,
@@ -461,9 +461,9 @@ namespace Godot
);
}
- public static Quat operator *(Vector3 left, Quat right)
+ public static Quaternion operator *(Vector3 left, Quaternion right)
{
- return new Quat
+ return new Quaternion
(
right.w * left.x + right.y * left.z - right.z * left.y,
right.w * left.y + right.z * left.x - right.x * left.z,
@@ -472,42 +472,42 @@ namespace Godot
);
}
- public static Quat operator *(Quat left, real_t right)
+ public static Quaternion operator *(Quaternion left, real_t right)
{
- return new Quat(left.x * right, left.y * right, left.z * right, left.w * right);
+ return new Quaternion(left.x * right, left.y * right, left.z * right, left.w * right);
}
- public static Quat operator *(real_t left, Quat right)
+ public static Quaternion operator *(real_t left, Quaternion right)
{
- return new Quat(right.x * left, right.y * left, right.z * left, right.w * left);
+ return new Quaternion(right.x * left, right.y * left, right.z * left, right.w * left);
}
- public static Quat operator /(Quat left, real_t right)
+ public static Quaternion operator /(Quaternion left, real_t right)
{
return left * (1.0f / right);
}
- public static bool operator ==(Quat left, Quat right)
+ public static bool operator ==(Quaternion left, Quaternion right)
{
return left.Equals(right);
}
- public static bool operator !=(Quat left, Quat right)
+ public static bool operator !=(Quaternion left, Quaternion right)
{
return !left.Equals(right);
}
public override bool Equals(object obj)
{
- if (obj is Quat)
+ if (obj is Quaternion)
{
- return Equals((Quat)obj);
+ return Equals((Quaternion)obj);
}
return false;
}
- public bool Equals(Quat other)
+ public bool Equals(Quaternion other)
{
return x == other.x && y == other.y && z == other.z && w == other.w;
}
@@ -518,7 +518,7 @@ namespace Godot
/// </summary>
/// <param name="other">The other quaternion to compare.</param>
/// <returns>Whether or not the quaternions are approximately equal.</returns>
- public bool IsEqualApprox(Quat other)
+ public bool IsEqualApprox(Quaternion other)
{
return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
index 868c3536fe..612fb64a3d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -405,7 +405,7 @@ namespace Godot
public override string ToString()
{
- return String.Format("({0}, {1})", new object[]
+ return String.Format("{0}, {1}", new object[]
{
_position.ToString(),
_size.ToString()
@@ -414,7 +414,7 @@ namespace Godot
public string ToString(string format)
{
- return String.Format("({0}, {1})", new object[]
+ return String.Format("{0}, {1}", new object[]
{
_position.ToString(format),
_size.ToString(format)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index bc0f81b2a7..fe93592667 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -492,22 +492,16 @@ namespace Godot
public override string ToString()
{
- return String.Format("({0}, {1}, {2})", new object[]
- {
- x.ToString(),
- y.ToString(),
- origin.ToString()
- });
+ return "[X: " + x.ToString() +
+ ", Y: " + y.ToString() +
+ ", O: " + origin.ToString() + "]";
}
public string ToString(string format)
{
- return String.Format("({0}, {1}, {2})", new object[]
- {
- x.ToString(format),
- y.ToString(format),
- origin.ToString(format)
- });
+ return "[X: " + x.ToString(format) +
+ ", Y: " + y.ToString(format) +
+ ", O: " + origin.ToString(format) + "]";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
index ac47f6029f..26b1a9e8b2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -19,7 +19,7 @@ namespace Godot
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
- public struct Transform : IEquatable<Transform>
+ public struct Transform3D : IEquatable<Transform3D>
{
/// <summary>
/// The <see cref="Basis"/> of this transform. Contains the X, Y, and Z basis
@@ -107,10 +107,10 @@ namespace Godot
/// the transformation is composed of rotation, scaling, and translation.
/// </summary>
/// <returns>The inverse transformation matrix.</returns>
- public Transform AffineInverse()
+ public Transform3D AffineInverse()
{
Basis basisInv = basis.Inverse();
- return new Transform(basisInv, basisInv.Xform(-origin));
+ return new Transform3D(basisInv, basisInv.Xform(-origin));
}
/// <summary>
@@ -119,20 +119,20 @@ namespace Godot
/// <param name="transform">The other transform.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated transform.</returns>
- public Transform InterpolateWith(Transform transform, real_t weight)
+ public Transform3D InterpolateWith(Transform3D transform, real_t weight)
{
/* not sure if very "efficient" but good enough? */
Vector3 sourceScale = basis.Scale;
- Quat sourceRotation = basis.RotationQuat();
+ Quaternion sourceRotation = basis.RotationQuaternion();
Vector3 sourceLocation = origin;
Vector3 destinationScale = transform.basis.Scale;
- Quat destinationRotation = transform.basis.RotationQuat();
+ Quaternion destinationRotation = transform.basis.RotationQuaternion();
Vector3 destinationLocation = transform.origin;
- var interpolated = new Transform();
- interpolated.basis.SetQuatScale(sourceRotation.Slerp(destinationRotation, weight).Normalized(), sourceScale.Lerp(destinationScale, weight));
+ var interpolated = new Transform3D();
+ interpolated.basis.SetQuaternionScale(sourceRotation.Slerp(destinationRotation, weight).Normalized(), sourceScale.Lerp(destinationScale, weight));
interpolated.origin = sourceLocation.Lerp(destinationLocation, weight);
return interpolated;
@@ -144,10 +144,10 @@ namespace Godot
/// (no scaling, use <see cref="AffineInverse"/> for transforms with scaling).
/// </summary>
/// <returns>The inverse matrix.</returns>
- public Transform Inverse()
+ public Transform3D Inverse()
{
Basis basisTr = basis.Transposed();
- return new Transform(basisTr, basisTr.Xform(-origin));
+ return new Transform3D(basisTr, basisTr.Xform(-origin));
}
/// <summary>
@@ -163,7 +163,7 @@ namespace Godot
/// <param name="target">The object to look at.</param>
/// <param name="up">The relative up direction</param>
/// <returns>The resulting transform.</returns>
- public Transform LookingAt(Vector3 target, Vector3 up)
+ public Transform3D LookingAt(Vector3 target, Vector3 up)
{
var t = this;
t.SetLookAt(origin, target, up);
@@ -175,9 +175,9 @@ namespace Godot
/// and normalized axis vectors (scale of 1 or -1).
/// </summary>
/// <returns>The orthonormalized transform.</returns>
- public Transform Orthonormalized()
+ public Transform3D Orthonormalized()
{
- return new Transform(basis.Orthonormalized(), origin);
+ return new Transform3D(basis.Orthonormalized(), origin);
}
/// <summary>
@@ -187,9 +187,9 @@ namespace Godot
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="phi">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
- public Transform Rotated(Vector3 axis, real_t phi)
+ public Transform3D Rotated(Vector3 axis, real_t phi)
{
- return new Transform(new Basis(axis, phi), new Vector3()) * this;
+ return new Transform3D(new Basis(axis, phi), new Vector3()) * this;
}
/// <summary>
@@ -197,9 +197,9 @@ namespace Godot
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
- public Transform Scaled(Vector3 scale)
+ public Transform3D Scaled(Vector3 scale)
{
- return new Transform(basis.Scaled(scale), origin * scale);
+ return new Transform3D(basis.Scaled(scale), origin * scale);
}
private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up)
@@ -234,9 +234,9 @@ namespace Godot
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
- public Transform Translated(Vector3 offset)
+ public Transform3D Translated(Vector3 offset)
{
- return new Transform(basis, new Vector3
+ return new Transform3D(basis, new Vector3
(
origin[0] += basis.Row0.Dot(offset),
origin[1] += basis.Row1.Dot(offset),
@@ -280,10 +280,10 @@ namespace Godot
}
// Constants
- private static readonly Transform _identity = new Transform(Basis.Identity, Vector3.Zero);
- private static readonly Transform _flipX = new Transform(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero);
- private static readonly Transform _flipY = new Transform(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero);
- private static readonly Transform _flipZ = new Transform(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero);
+ private static readonly Transform3D _identity = new Transform3D(Basis.Identity, Vector3.Zero);
+ private static readonly Transform3D _flipX = new Transform3D(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero);
+ private static readonly Transform3D _flipY = new Transform3D(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero);
+ private static readonly Transform3D _flipZ = new Transform3D(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero);
/// <summary>
/// The identity transform, with no translation, rotation, or scaling applied.
@@ -291,22 +291,22 @@ namespace Godot
/// Do not use `new Transform()` with no arguments in C#, because it sets all values to zero.
/// </summary>
/// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Up, Vector3.Back, Vector3.Zero)`.</value>
- public static Transform Identity { get { return _identity; } }
+ public static Transform3D Identity { get { return _identity; } }
/// <summary>
/// The transform that will flip something along the X axis.
/// </summary>
/// <value>Equivalent to `new Transform(Vector3.Left, Vector3.Up, Vector3.Back, Vector3.Zero)`.</value>
- public static Transform FlipX { get { return _flipX; } }
+ public static Transform3D FlipX { get { return _flipX; } }
/// <summary>
/// The transform that will flip something along the Y axis.
/// </summary>
/// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Down, Vector3.Back, Vector3.Zero)`.</value>
- public static Transform FlipY { get { return _flipY; } }
+ public static Transform3D FlipY { get { return _flipY; } }
/// <summary>
/// The transform that will flip something along the Z axis.
/// </summary>
/// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Up, Vector3.Forward, Vector3.Zero)`.</value>
- public static Transform FlipZ { get { return _flipZ; } }
+ public static Transform3D FlipZ { get { return _flipZ; } }
/// <summary>
/// Constructs a transformation matrix from 4 vectors (matrix columns).
@@ -315,7 +315,7 @@ namespace Godot
/// <param name="column1">The Y vector, or column index 1.</param>
/// <param name="column2">The Z vector, or column index 2.</param>
/// <param name="origin">The origin vector, or column index 3.</param>
- public Transform(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin)
+ public Transform3D(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin)
{
basis = new Basis(column0, column1, column2);
this.origin = origin;
@@ -324,11 +324,11 @@ namespace Godot
/// <summary>
/// Constructs a transformation matrix from the given quaternion and origin vector.
/// </summary>
- /// <param name="quat">The <see cref="Godot.Quat"/> to create the basis from.</param>
+ /// <param name="quaternion">The <see cref="Godot.Quaternion"/> to create the basis from.</param>
/// <param name="origin">The origin vector, or column index 3.</param>
- public Transform(Quat quat, Vector3 origin)
+ public Transform3D(Quaternion quaternion, Vector3 origin)
{
- basis = new Basis(quat);
+ basis = new Basis(quaternion);
this.origin = origin;
}
@@ -337,40 +337,40 @@ namespace Godot
/// </summary>
/// <param name="basis">The <see cref="Godot.Basis"/> to create the basis from.</param>
/// <param name="origin">The origin vector, or column index 3.</param>
- public Transform(Basis basis, Vector3 origin)
+ public Transform3D(Basis basis, Vector3 origin)
{
this.basis = basis;
this.origin = origin;
}
- public static Transform operator *(Transform left, Transform right)
+ public static Transform3D operator *(Transform3D left, Transform3D right)
{
left.origin = left.Xform(right.origin);
left.basis *= right.basis;
return left;
}
- public static bool operator ==(Transform left, Transform right)
+ public static bool operator ==(Transform3D left, Transform3D right)
{
return left.Equals(right);
}
- public static bool operator !=(Transform left, Transform right)
+ public static bool operator !=(Transform3D left, Transform3D right)
{
return !left.Equals(right);
}
public override bool Equals(object obj)
{
- if (obj is Transform)
+ if (obj is Transform3D)
{
- return Equals((Transform)obj);
+ return Equals((Transform3D)obj);
}
return false;
}
- public bool Equals(Transform other)
+ public bool Equals(Transform3D other)
{
return basis.Equals(other.basis) && origin.Equals(other.origin);
}
@@ -381,7 +381,7 @@ namespace Godot
/// </summary>
/// <param name="other">The other transform to compare.</param>
/// <returns>Whether or not the matrices are approximately equal.</returns>
- public bool IsEqualApprox(Transform other)
+ public bool IsEqualApprox(Transform3D other)
{
return basis.IsEqualApprox(other.basis) && origin.IsEqualApprox(other.origin);
}
@@ -393,20 +393,18 @@ namespace Godot
public override string ToString()
{
- return String.Format("{0} - {1}", new object[]
- {
- basis.ToString(),
- origin.ToString()
- });
+ return "[X: " + basis.x.ToString() +
+ ", Y: " + basis.y.ToString() +
+ ", Z: " + basis.z.ToString() +
+ ", O: " + origin.ToString() + "]";
}
public string ToString(string format)
{
- return String.Format("{0} - {1}", new object[]
- {
- basis.ToString(format),
- origin.ToString(format)
- });
+ return "[X: " + basis.x.ToString(format) +
+ ", Y: " + basis.y.ToString(format) +
+ ", Z: " + basis.z.ToString(format) +
+ ", O: " + origin.ToString(format) + "]";
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index 6279ea1ace..af053bd263 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -160,22 +160,20 @@ namespace Godot
}
/// <summary>
- /// Returns the vector with a maximum length by limiting its length to `length`.
+ /// Returns a new vector with all components clamped between the
+ /// components of `min` and `max` using
+ /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>.
/// </summary>
- /// <param name="length">The length to limit to.</param>
- /// <returns>The vector with its length limited.</returns>
- public Vector2 Clamped(real_t length)
+ /// <param name="min">The vector with minimum allowed values.</param>
+ /// <param name="max">The vector with maximum allowed values.</param>
+ /// <returns>The vector with all components clamped.</returns>
+ public Vector2 Clamp(Vector2 min, Vector2 max)
{
- var v = this;
- real_t l = Length();
-
- if (l > 0 && length < l)
- {
- v /= l;
- v *= length;
- }
-
- return v;
+ return new Vector2
+ (
+ Mathf.Clamp(x, min.x, max.x),
+ Mathf.Clamp(y, min.y, max.y)
+ );
}
/// <summary>
@@ -335,6 +333,25 @@ namespace Godot
}
/// <summary>
+ /// Returns the vector with a maximum length by limiting its length to `length`.
+ /// </summary>
+ /// <param name="length">The length to limit to.</param>
+ /// <returns>The vector with its length limited.</returns>
+ public Vector2 LimitLength(real_t length = 1.0f)
+ {
+ Vector2 v = this;
+ real_t l = Length();
+
+ if (l > 0 && length < l)
+ {
+ v /= l;
+ v *= length;
+ }
+
+ return v;
+ }
+
+ /// <summary>
/// Returns the axis of the vector's largest value. See <see cref="Axis"/>.
/// If both components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
@@ -425,7 +442,7 @@ namespace Godot
#if DEBUG
if (!normal.IsNormalized())
{
- throw new ArgumentException("Argument is not normalized", nameof(normal));
+ throw new ArgumentException("Argument is not normalized", nameof(normal));
}
#endif
return 2 * Dot(normal) * normal - this;
@@ -519,7 +536,7 @@ namespace Godot
/// compared to the original, with the same length.
/// </summary>
/// <returns>The perpendicular vector.</returns>
- public Vector2 Perpendicular()
+ public Vector2 Orthogonal()
{
return new Vector2(y, -x);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
index 8dd9ab2f0d..9068593fd8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
@@ -120,6 +120,23 @@ namespace Godot
}
/// <summary>
+ /// Returns a new vector with all components clamped between the
+ /// components of `min` and `max` using
+ /// <see cref="Mathf.Clamp(int, int, int)"/>.
+ /// </summary>
+ /// <param name="min">The vector with minimum allowed values.</param>
+ /// <param name="max">The vector with maximum allowed values.</param>
+ /// <returns>The vector with all components clamped.</returns>
+ public Vector2i Clamp(Vector2i min, Vector2i max)
+ {
+ return new Vector2i
+ (
+ Mathf.Clamp(x, min.x, max.x),
+ Mathf.Clamp(y, min.y, max.y)
+ );
+ }
+
+ /// <summary>
/// Returns the cross product of this vector and `b`.
/// </summary>
/// <param name="b">The other vector.</param>
@@ -248,13 +265,13 @@ namespace Godot
}
/// <summary>
- /// Returns a vector rotated 90 degrees counter-clockwise
+ /// Returns a perpendicular vector rotated 90 degrees counter-clockwise
/// compared to the original, with the same length.
/// </summary>
/// <returns>The perpendicular vector.</returns>
- public Vector2 Perpendicular()
+ public Vector2i Orthogonal()
{
- return new Vector2(y, -x);
+ return new Vector2i(y, -x);
}
// Constants
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 3b895bbbf6..31a9af2d9e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -140,6 +140,24 @@ namespace Godot
}
/// <summary>
+ /// Returns a new vector with all components clamped between the
+ /// components of `min` and `max` using
+ /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>.
+ /// </summary>
+ /// <param name="min">The vector with minimum allowed values.</param>
+ /// <param name="max">The vector with maximum allowed values.</param>
+ /// <returns>The vector with all components clamped.</returns>
+ public Vector3 Clamp(Vector3 min, Vector3 max)
+ {
+ return new Vector3
+ (
+ Mathf.Clamp(x, min.x, max.x),
+ Mathf.Clamp(y, min.y, max.y),
+ Mathf.Clamp(z, min.z, max.z)
+ );
+ }
+
+ /// <summary>
/// Returns the cross product of this vector and `b`.
/// </summary>
/// <param name="b">The other vector.</param>
@@ -313,6 +331,25 @@ namespace Godot
}
/// <summary>
+ /// Returns the vector with a maximum length by limiting its length to `length`.
+ /// </summary>
+ /// <param name="length">The length to limit to.</param>
+ /// <returns>The vector with its length limited.</returns>
+ public Vector3 LimitLength(real_t length = 1.0f)
+ {
+ Vector3 v = this;
+ real_t l = Length();
+
+ if (l > 0 && length < l)
+ {
+ v /= l;
+ v *= length;
+ }
+
+ return v;
+ }
+
+ /// <summary>
/// Returns the axis of the vector's largest value. See <see cref="Axis"/>.
/// If all components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
@@ -419,7 +456,7 @@ namespace Godot
#if DEBUG
if (!normal.IsNormalized())
{
- throw new ArgumentException("Argument is not normalized", nameof(normal));
+ throw new ArgumentException("Argument is not normalized", nameof(normal));
}
#endif
return 2.0f * Dot(normal) * normal - this;
@@ -437,7 +474,7 @@ namespace Godot
#if DEBUG
if (!axis.IsNormalized())
{
- throw new ArgumentException("Argument is not normalized", nameof(axis));
+ throw new ArgumentException("Argument is not normalized", nameof(axis));
}
#endif
return new Basis(axis, phi).Xform(this);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
index bf25ba9cb3..e727afa3ff 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
@@ -89,6 +89,24 @@ namespace Godot
}
/// <summary>
+ /// Returns a new vector with all components clamped between the
+ /// components of `min` and `max` using
+ /// <see cref="Mathf.Clamp(int, int, int)"/>.
+ /// </summary>
+ /// <param name="min">The vector with minimum allowed values.</param>
+ /// <param name="max">The vector with maximum allowed values.</param>
+ /// <returns>The vector with all components clamped.</returns>
+ public Vector3i Clamp(Vector3i min, Vector3i max)
+ {
+ return new Vector3i
+ (
+ Mathf.Clamp(x, min.x, max.x),
+ Mathf.Clamp(y, min.y, max.y),
+ Mathf.Clamp(z, min.z, max.z)
+ );
+ }
+
+ /// <summary>
/// Returns the squared distance between this vector and `b`.
/// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
/// you need to compare vectors or need the squared distance for some formula.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 54aaaf1f92..1fcfe74c86 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -50,7 +50,7 @@
<Compile Include="Core\NodePath.cs" />
<Compile Include="Core\Object.base.cs" />
<Compile Include="Core\Plane.cs" />
- <Compile Include="Core\Quat.cs" />
+ <Compile Include="Core\Quaternion.cs" />
<Compile Include="Core\Rect2.cs" />
<Compile Include="Core\Rect2i.cs" />
<Compile Include="Core\RID.cs" />
@@ -58,8 +58,8 @@
<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\Transform3D.cs" />
<Compile Include="Core\UnhandledExceptionArgs.cs" />
<Compile Include="Core\Vector2.cs" />
<Compile Include="Core\Vector2i.cs" />
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index 34a96eba17..2b6d2761ca 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -31,7 +31,7 @@
#ifdef MONO_GLUE_ENABLED
#include "core/object/class_db.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/string/string_name.h"
#include "../csharp_script.h"
@@ -78,17 +78,17 @@ 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) {
+void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_ptr == nullptr);
- // This is only called with Reference derived classes
- CRASH_COND(!Object::cast_to<Reference>(p_ptr));
+ // This is only called with RefCounted derived classes
+ CRASH_COND(!Object::cast_to<RefCounted>(p_ptr));
#endif
- Reference *ref = static_cast<Reference *>(p_ptr);
+ RefCounted *rc = static_cast<RefCounted *>(p_ptr);
- if (ref->get_script_instance()) {
- CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(ref->get_script_instance());
+ if (rc->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(rc->get_script_instance());
if (cs_instance) {
if (!cs_instance->is_destructing_script_instance()) {
bool delete_owner;
@@ -97,9 +97,9 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea
cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, delete_owner, remove_script_instance);
if (delete_owner) {
- memdelete(ref);
+ memdelete(rc);
} else if (remove_script_instance) {
- ref->set_script_instance(nullptr);
+ rc->set_script_instance(nullptr);
}
}
return;
@@ -108,11 +108,11 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea
// Unsafe refcount decrement. The managed instance also counts as a reference.
// See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
- CSharpLanguage::get_singleton()->pre_unsafe_unreference(ref);
- if (ref->unreference()) {
- memdelete(ref);
+ CSharpLanguage::get_singleton()->pre_unsafe_unreference(rc);
+ if (rc->unreference()) {
+ memdelete(rc);
} else {
- void *data = ref->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+ void *data = rc->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
if (data) {
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
@@ -145,10 +145,10 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
}
Ref<WeakRef> wref;
- Reference *ref = Object::cast_to<Reference>(p_ptr);
+ RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
- if (ref) {
- REF r = ref;
+ if (rc) {
+ REF r = rc;
if (!r.is_valid()) {
return nullptr;
}
@@ -242,7 +242,7 @@ MonoString *godot_icall_Object_ToString(Object *p_ptr) {
void godot_register_object_icalls() {
GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Ctor", godot_icall_Object_Ctor);
GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed);
- GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Reference_Disposed", godot_icall_Reference_Disposed);
+ GDMonoUtils::add_internal_call("Godot.Object::godot_icall_RefCounted_Disposed", godot_icall_RefCounted_Disposed);
GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals);
GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", godot_icall_Object_ClassDB_get_method);
GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString);
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
index 3db52d7c30..eed3bd2167 100644
--- a/modules/mono/glue/glue_header.h
+++ b/modules/mono/glue/glue_header.h
@@ -61,7 +61,7 @@ void godot_register_glue_header_icalls() {
#include "core/config/engine.h"
#include "core/object/class_db.h"
#include "core/object/method_bind.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/string/node_path.h"
#include "core/string/ustring.h"
#include "core/typedefs.h"
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 020a40575c..375ad413c4 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -31,7 +31,7 @@
#include "godotsharp_dirs.h"
#include "core/config/project_settings.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "core/os/os.h"
#ifdef TOOLS_ENABLED
@@ -63,8 +63,8 @@ String _get_expected_build_config() {
String _get_mono_user_dir() {
#ifdef TOOLS_ENABLED
- if (EditorSettings::get_singleton()) {
- return EditorSettings::get_singleton()->get_data_dir().plus_file("mono");
+ if (EditorPaths::get_singleton()) {
+ return EditorPaths::get_singleton()->get_data_dir().plus_file("mono");
} else {
String settings_path;
diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h
index f435aab3dd..d0e51d159f 100644
--- a/modules/mono/mono_gc_handle.h
+++ b/modules/mono/mono_gc_handle.h
@@ -33,7 +33,7 @@
#include <mono/jit/jit.h>
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
namespace gdmono {
@@ -79,8 +79,8 @@ struct MonoGCHandleData {
static MonoGCHandleData new_weak_handle(MonoObject *p_object);
};
-class MonoGCHandleRef : public Reference {
- GDCLASS(MonoGCHandleRef, Reference);
+class MonoGCHandleRef : public RefCounted {
+ GDCLASS(MonoGCHandleRef, RefCounted);
MonoGCHandleData data;
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 560788fb3a..a3acfbd995 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -39,8 +39,8 @@
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/os/os.h"
#include "core/os/thread.h"
@@ -119,11 +119,11 @@ void gd_mono_profiler_init() {
const String env_var_name = "MONO_ENV_OPTIONS";
if (OS::get_singleton()->has_environment(env_var_name)) {
- const auto mono_env_ops = OS::get_singleton()->get_environment(env_var_name);
+ const String mono_env_ops = OS::get_singleton()->get_environment(env_var_name);
// Usually MONO_ENV_OPTIONS looks like: --profile=jb:prof=timeline,ctl=remote,host=127.0.0.1:55467
const String prefix = "--profile=";
if (mono_env_ops.begins_with(prefix)) {
- const auto ops = mono_env_ops.substr(prefix.length(), mono_env_ops.length());
+ const String ops = mono_env_ops.substr(prefix.length(), mono_env_ops.length());
mono_profiler_load(ops.utf8());
}
}
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index a1556bace5..67d6f3ef29 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -34,8 +34,8 @@
#include <mono/metadata/tokentype.h>
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_pack.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/templates/list.h"
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index d66cc29b9a..341ca88728 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -109,8 +109,8 @@ void CachedData::clear_godot_api_cache() {
class_Vector3 = nullptr;
class_Vector3i = nullptr;
class_Basis = nullptr;
- class_Quat = nullptr;
- class_Transform = nullptr;
+ class_Quaternion = nullptr;
+ class_Transform3D = nullptr;
class_AABB = nullptr;
class_Color = nullptr;
class_Plane = nullptr;
@@ -238,8 +238,8 @@ void update_godot_api_cache() {
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(Quaternion, GODOT_API_CLASS(Quaternion));
+ CACHE_CLASS_AND_CHECK(Transform3D, GODOT_API_CLASS(Transform3D));
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));
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 51370da452..3d867060f5 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -80,8 +80,8 @@ struct CachedData {
GDMonoClass *class_Vector3;
GDMonoClass *class_Vector3i;
GDMonoClass *class_Basis;
- GDMonoClass *class_Quat;
- GDMonoClass *class_Transform;
+ GDMonoClass *class_Quaternion;
+ GDMonoClass *class_Transform3D;
GDMonoClass *class_AABB;
GDMonoClass *class_Color;
GDMonoClass *class_Plane;
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 1d4d52dfce..111eaa0bbf 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -146,14 +146,14 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
- if (tclass == CACHED_CLASS(Quat)) {
- GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat());
+ if (tclass == CACHED_CLASS(Quaternion)) {
+ GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion());
mono_field_set_value(p_object, mono_field, &from);
break;
}
- if (tclass == CACHED_CLASS(Transform)) {
- GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform());
+ if (tclass == CACHED_CLASS(Transform3D)) {
+ GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D());
mono_field_set_value(p_object, mono_field, &from);
break;
}
@@ -336,8 +336,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane());
mono_field_set_value(p_object, mono_field, &from);
} break;
- case Variant::QUAT: {
- GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat());
+ case Variant::QUATERNION: {
+ GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion());
mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::AABB: {
@@ -348,8 +348,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis());
mono_field_set_value(p_object, mono_field, &from);
} break;
- case Variant::TRANSFORM: {
- GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform());
+ case Variant::TRANSFORM3D: {
+ GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D());
mono_field_set_value(p_object, mono_field, &from);
} break;
case Variant::COLOR: {
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
index fa93c6533a..d7df18d5da 100644
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ b/modules/mono/mono_gd/gd_mono_internals.cpp
@@ -51,7 +51,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
// All mono objects created from the managed world (e.g.: 'new Player()')
// need to have a CSharpScript in order for their methods to be callable from the unmanaged side
- Reference *ref = Object::cast_to<Reference>(unmanaged);
+ RefCounted *rc = Object::cast_to<RefCounted>(unmanaged);
GDMonoClass *klass = GDMonoUtils::get_object_class(managed);
@@ -73,18 +73,18 @@ 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 ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed);
+ script_binding.gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed);
script_binding.owner = unmanaged;
- if (ref) {
+ if (rc) {
// Unsafe refcount increment. The managed instance also counts as a reference.
// This way if the unmanaged world has no references to our owner
// but the managed instance is alive, the refcount will be 1 instead of 0.
- // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
+ // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
// May not me referenced yet, so we must use init_ref() instead of reference()
- if (ref->init_ref()) {
- CSharpLanguage::get_singleton()->post_unsafe_reference(ref);
+ if (rc->init_ref()) {
+ CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
}
}
@@ -99,7 +99,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
return;
}
- MonoGCHandleData gchandle = ref ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed);
+ MonoGCHandleData gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed);
Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass, native);
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index dafd36c36b..179bbfb40c 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -32,7 +32,7 @@
#include <stdlib.h> // abort
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "core/os/os.h"
#include "../godotsharp_dirs.h"
@@ -161,8 +161,8 @@ void GDMonoLog::initialize() {
OS::Time time_now = OS::get_singleton()->get_time();
String log_file_name = str_format("%04d-%02d-%02d_%02d.%02d.%02d",
- date_now.year, date_now.month, date_now.day,
- time_now.hour, time_now.min, time_now.sec);
+ (int)date_now.year, (int)date_now.month, (int)date_now.day,
+ (int)time_now.hour, (int)time_now.minute, (int)time_now.second);
log_file_name += str_format("_%d", OS::get_singleton()->get_process_id());
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
index f7a53156ab..9ddbd251ac 100644
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ b/modules/mono/mono_gd/gd_mono_log.h
@@ -41,7 +41,7 @@
#endif
#ifdef GD_MONO_LOG_ENABLED
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#endif
class GDMonoLog {
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 359f6bba4d..9f2977bfa2 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -104,12 +104,12 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_
return Variant::BASIS;
}
- if (vtclass == CACHED_CLASS(Quat)) {
- return Variant::QUAT;
+ if (vtclass == CACHED_CLASS(Quaternion)) {
+ return Variant::QUATERNION;
}
- if (vtclass == CACHED_CLASS(Transform)) {
- return Variant::TRANSFORM;
+ if (vtclass == CACHED_CLASS(Transform3D)) {
+ return Variant::TRANSFORM3D;
}
if (vtclass == CACHED_CLASS(AABB)) {
@@ -508,9 +508,9 @@ MonoObject *variant_to_mono_object(const Variant &p_var) {
GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
}
- case Variant::QUAT: {
- GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var.operator ::Quat());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
+ case Variant::QUATERNION: {
+ GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_var.operator ::Quaternion());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quaternion), &from);
}
case Variant::AABB: {
GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB());
@@ -520,9 +520,9 @@ MonoObject *variant_to_mono_object(const Variant &p_var) {
GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
}
- case Variant::TRANSFORM: {
- GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var.operator ::Transform());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
+ case Variant::TRANSFORM3D: {
+ GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_var.operator ::Transform3D());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform3D), &from);
}
case Variant::COLOR: {
GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color());
@@ -619,8 +619,8 @@ size_t variant_get_managed_unboxed_size(const ManagedType &p_type) {
RETURN_CHECK_FOR_STRUCT(Vector3);
RETURN_CHECK_FOR_STRUCT(Vector3i);
RETURN_CHECK_FOR_STRUCT(Basis);
- RETURN_CHECK_FOR_STRUCT(Quat);
- RETURN_CHECK_FOR_STRUCT(Transform);
+ RETURN_CHECK_FOR_STRUCT(Quaternion);
+ RETURN_CHECK_FOR_STRUCT(Transform3D);
RETURN_CHECK_FOR_STRUCT(AABB);
RETURN_CHECK_FOR_STRUCT(Color);
RETURN_CHECK_FOR_STRUCT(Plane);
@@ -724,8 +724,8 @@ void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type
RETURN_CHECK_FOR_STRUCT(Vector3);
RETURN_CHECK_FOR_STRUCT(Vector3i);
RETURN_CHECK_FOR_STRUCT(Basis);
- RETURN_CHECK_FOR_STRUCT(Quat);
- RETURN_CHECK_FOR_STRUCT(Transform);
+ RETURN_CHECK_FOR_STRUCT(Quaternion);
+ RETURN_CHECK_FOR_STRUCT(Transform3D);
RETURN_CHECK_FOR_STRUCT(AABB);
RETURN_CHECK_FOR_STRUCT(Color);
RETURN_CHECK_FOR_STRUCT(Plane);
@@ -880,8 +880,8 @@ MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_ty
RETURN_CHECK_FOR_STRUCT(Vector3);
RETURN_CHECK_FOR_STRUCT(Vector3i);
RETURN_CHECK_FOR_STRUCT(Basis);
- RETURN_CHECK_FOR_STRUCT(Quat);
- RETURN_CHECK_FOR_STRUCT(Transform);
+ RETURN_CHECK_FOR_STRUCT(Quaternion);
+ RETURN_CHECK_FOR_STRUCT(Transform3D);
RETURN_CHECK_FOR_STRUCT(AABB);
RETURN_CHECK_FOR_STRUCT(Color);
RETURN_CHECK_FOR_STRUCT(Plane);
@@ -1036,12 +1036,12 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return MARSHALLED_IN(Basis, unbox_addr<GDMonoMarshal::M_Basis>(p_obj));
}
- if (vtclass == CACHED_CLASS(Quat)) {
- return MARSHALLED_IN(Quat, unbox_addr<GDMonoMarshal::M_Quat>(p_obj));
+ if (vtclass == CACHED_CLASS(Quaternion)) {
+ return MARSHALLED_IN(Quaternion, unbox_addr<GDMonoMarshal::M_Quaternion>(p_obj));
}
- if (vtclass == CACHED_CLASS(Transform)) {
- return MARSHALLED_IN(Transform, unbox_addr<GDMonoMarshal::M_Transform>(p_obj));
+ if (vtclass == CACHED_CLASS(Transform3D)) {
+ return MARSHALLED_IN(Transform3D, unbox_addr<GDMonoMarshal::M_Transform3D>(p_obj));
}
if (vtclass == CACHED_CLASS(AABB)) {
@@ -1136,8 +1136,8 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
if (ptr != nullptr) {
- Reference *ref = Object::cast_to<Reference>(ptr);
- return ref ? Variant(Ref<Reference>(ref)) : Variant(ptr);
+ RefCounted *rc = Object::cast_to<RefCounted>(ptr);
+ return rc ? Variant(Ref<RefCounted>(rc)) : Variant(ptr);
}
return Variant();
}
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 668809ae5d..88afc7ebc5 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -263,15 +263,15 @@ enum {
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)) &&
- offsetof(Quat, x) == (sizeof(real_t) * 0) &&
- offsetof(Quat, y) == (sizeof(real_t) * 1) &&
- offsetof(Quat, z) == (sizeof(real_t) * 2) &&
- offsetof(Quat, w) == (sizeof(real_t) * 3)),
+ MATCHES_Quaternion = (MATCHES_real_t && (sizeof(Quaternion) == (sizeof(real_t) * 4)) &&
+ offsetof(Quaternion, x) == (sizeof(real_t) * 0) &&
+ offsetof(Quaternion, y) == (sizeof(real_t) * 1) &&
+ offsetof(Quaternion, z) == (sizeof(real_t) * 2) &&
+ offsetof(Quaternion, w) == (sizeof(real_t) * 3)),
- MATCHES_Transform = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform) == (sizeof(Basis) + sizeof(Vector3))) &&
- offsetof(Transform, basis) == 0 &&
- offsetof(Transform, origin) == sizeof(Basis)),
+ MATCHES_Transform3D = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform3D) == (sizeof(Basis) + sizeof(Vector3))) &&
+ offsetof(Transform3D, basis) == 0 &&
+ offsetof(Transform3D, origin) == sizeof(Basis)),
MATCHES_AABB = (MATCHES_Vector3 && (sizeof(AABB) == (sizeof(Vector3) * 2)) &&
offsetof(AABB, position) == (sizeof(Vector3) * 0) &&
@@ -292,7 +292,7 @@ enum {
#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY
/* clang-format off */
static_assert(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 &&
- MATCHES_Basis && MATCHES_Quat && MATCHES_Transform && MATCHES_AABB && MATCHES_Color &&
+ MATCHES_Basis && MATCHES_Quaternion && MATCHES_Transform3D && MATCHES_AABB && MATCHES_Color &&
MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i);
/* clang-format on */
#endif
@@ -420,29 +420,29 @@ struct M_Basis {
}
};
-struct M_Quat {
+struct M_Quaternion {
real_t x, y, z, w;
- static _FORCE_INLINE_ Quat convert_to(const M_Quat &p_from) {
- return Quat(p_from.x, p_from.y, p_from.z, p_from.w);
+ static _FORCE_INLINE_ Quaternion convert_to(const M_Quaternion &p_from) {
+ return Quaternion(p_from.x, p_from.y, p_from.z, p_from.w);
}
- static _FORCE_INLINE_ M_Quat convert_from(const Quat &p_from) {
- M_Quat ret = { p_from.x, p_from.y, p_from.z, p_from.w };
+ static _FORCE_INLINE_ M_Quaternion convert_from(const Quaternion &p_from) {
+ M_Quaternion ret = { p_from.x, p_from.y, p_from.z, p_from.w };
return ret;
}
};
-struct M_Transform {
+struct M_Transform3D {
M_Basis basis;
M_Vector3 origin;
- static _FORCE_INLINE_ Transform convert_to(const M_Transform &p_from) {
- return Transform(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin));
+ static _FORCE_INLINE_ Transform3D convert_to(const M_Transform3D &p_from) {
+ return Transform3D(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin));
}
- static _FORCE_INLINE_ M_Transform convert_from(const Transform &p_from) {
- M_Transform ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) };
+ static _FORCE_INLINE_ M_Transform3D convert_from(const Transform3D &p_from) {
+ M_Transform3D ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) };
return ret;
}
};
@@ -533,8 +533,8 @@ 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)
+DECL_TYPE_MARSHAL_TEMPLATES(Quaternion)
+DECL_TYPE_MARSHAL_TEMPLATES(Transform3D)
DECL_TYPE_MARSHAL_TEMPLATES(AABB)
DECL_TYPE_MARSHAL_TEMPLATES(Color)
DECL_TYPE_MARSHAL_TEMPLATES(Plane)
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 6e0a263c7f..df45cb8e92 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -35,8 +35,8 @@
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
-#include "core/object/reference.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
+#include "core/object/ref_counted.h"
#include "core/os/mutex.h"
#include "core/os/os.h"
@@ -108,15 +108,15 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
gchandle = MonoGCHandleData::new_strong_handle(mono_object);
// Tie managed to unmanaged
- Reference *ref = Object::cast_to<Reference>(unmanaged);
+ RefCounted *rc = Object::cast_to<RefCounted>(unmanaged);
- if (ref) {
+ if (rc) {
// Unsafe refcount increment. The managed instance also counts as a reference.
// This way if the unmanaged world has no references to our owner
// but the managed instance is alive, the refcount will be 1 instead of 0.
- // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr)
- ref->reference();
- CSharpLanguage::get_singleton()->post_unsafe_reference(ref);
+ // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
+ rc->reference();
+ CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
}
return mono_object;
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 9e024418e1..773501e93d 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -41,7 +41,7 @@
#endif
#include "core/object/class_db.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#define UNHANDLED_EXCEPTION(m_exc) \
if (unlikely(m_exc != nullptr)) { \
diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm
index cdee04edcf..23424fbaf9 100644
--- a/modules/mono/mono_gd/support/ios_support.mm
+++ b/modules/mono/mono_gd/support/ios_support.mm
@@ -57,9 +57,9 @@ void ios_mono_log_callback(const char *log_domain, const char *log_level, const
}
void initialize() {
- mono_dllmap_insert(NULL, "System.Native", NULL, "__Internal", NULL);
- mono_dllmap_insert(NULL, "System.IO.Compression.Native", NULL, "__Internal", NULL);
- mono_dllmap_insert(NULL, "System.Security.Cryptography.Native.Apple", NULL, "__Internal", NULL);
+ mono_dllmap_insert(nullptr, "System.Native", nullptr, "__Internal", nullptr);
+ mono_dllmap_insert(nullptr, "System.IO.Compression.Native", nullptr, "__Internal", nullptr);
+ mono_dllmap_insert(nullptr, "System.Security.Cryptography.Native.Apple", nullptr, "__Internal", nullptr);
#ifdef IOS_DEVICE
// This function is defined in an auto-generated source file
@@ -85,7 +85,7 @@ void cleanup() {
GD_PINVOKE_EXPORT const char *xamarin_get_locale_country_code() {
NSLocale *locale = [NSLocale currentLocale];
NSString *countryCode = [locale objectForKey:NSLocaleCountryCode];
- if (countryCode == NULL) {
+ if (countryCode == nullptr) {
return strdup("US");
}
return strdup([countryCode UTF8String]);
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index 4c77f8cfed..e12ea45b3f 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -31,7 +31,7 @@
#ifndef SIGNAL_AWAITER_UTILS_H
#define SIGNAL_AWAITER_UTILS_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "csharp_script.h"
#include "mono_gc_handle.h"
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
index bb1265e959..6b616dd52d 100644
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "mono_reg_utils.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#ifdef WINDOWS_ENABLED
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index 93d44628ac..ec04d50704 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -31,8 +31,8 @@
#include "path_utils.h"
#include "core/config/project_settings.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/os/os.h"
#ifdef WINDOWS_ENABLED
@@ -80,7 +80,7 @@ String cwd() {
}
String abspath(const String &p_path) {
- if (p_path.is_abs_path()) {
+ if (p_path.is_absolute_path()) {
return p_path.simplify_path();
} else {
return path::join(path::cwd(), p_path).simplify_path();
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index 43de77005e..053618ebe4 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -30,7 +30,7 @@
#include "string_utils.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include <stdio.h>
#include <stdlib.h>
@@ -170,10 +170,10 @@ Error read_all_file_utf8(const String &p_path, String &r_content) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'.");
- int len = f->get_len();
+ uint64_t len = f->get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
- int r = f->get_buffer(w, len);
+ uint64_t r = f->get_buffer(w, len);
f->close();
memdelete(f);
ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml
index 38c5138482..a12412a9cd 100644
--- a/modules/opensimplex/doc_classes/NoiseTexture.xml
+++ b/modules/opensimplex/doc_classes/NoiseTexture.xml
@@ -31,6 +31,9 @@
<member name="noise" type="OpenSimplexNoise" setter="set_noise" getter="get_noise">
The [OpenSimplexNoise] instance used to generate the noise.
</member>
+ <member name="noise_offset" type="Vector2" setter="set_noise_offset" getter="get_noise_offset" default="Vector2( 0, 0 )">
+ An offset used to specify the noise space coordinate of the top left corner of the generated noise. This value is ignored if [member seamless] is enabled.
+ </member>
<member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false">
Whether the texture can be tiled without visible seams or not. Seamless textures take longer to generate.
[b]Note:[/b] Seamless noise has a lower contrast compared to non-seamless noise. This is due to the way noise uses higher dimensions for generating seamless noise.
diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
index ad82f87213..2fdbd61ee7 100644
--- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
+++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
@@ -31,8 +31,10 @@
</argument>
<argument index="1" name="height" type="int">
</argument>
+ <argument index="2" name="noise_offset" type="Vector2" default="Vector2( 0, 0 )">
+ </argument>
<description>
- Generate a noise image in [constant Image.FORMAT_L8] format with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters.
+ Generate a noise image in [constant Image.FORMAT_L8] format with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters. If [code]noise_offset[/code] is specified, then the offset value is used as the coordinates of the top-left corner of the generated noise.
</description>
</method>
<method name="get_noise_1d" qualifiers="const">
diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp
index 7272d32fac..9e0155da94 100644
--- a/modules/opensimplex/noise_texture.cpp
+++ b/modules/opensimplex/noise_texture.cpp
@@ -52,6 +52,9 @@ void NoiseTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise);
ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise);
+ ClassDB::bind_method(D_METHOD("set_noise_offset", "noise_offset"), &NoiseTexture::set_noise_offset);
+ ClassDB::bind_method(D_METHOD("get_noise_offset"), &NoiseTexture::get_noise_offset);
+
ClassDB::bind_method(D_METHOD("set_seamless", "seamless"), &NoiseTexture::set_seamless);
ClassDB::bind_method(D_METHOD("get_seamless"), &NoiseTexture::get_seamless);
@@ -71,6 +74,7 @@ void NoiseTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "as_normal_map"), "set_as_normal_map", "is_normal_map");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bump_strength", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_bump_strength", "get_bump_strength");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "OpenSimplexNoise"), "set_noise", "get_noise");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "noise_offset"), "set_noise_offset", "get_noise_offset");
}
void NoiseTexture::_validate_property(PropertyInfo &property) const {
@@ -130,7 +134,7 @@ Ref<Image> NoiseTexture::_generate_texture() {
if (seamless) {
image = ref_noise->get_seamless_image(size.x);
} else {
- image = ref_noise->get_image(size.x, size.y);
+ image = ref_noise->get_image(size.x, size.y, noise_offset);
}
if (as_normal_map) {
@@ -198,6 +202,14 @@ void NoiseTexture::set_height(int p_height) {
_queue_update();
}
+void NoiseTexture::set_noise_offset(Vector2 p_noise_offset) {
+ if (noise_offset == p_noise_offset) {
+ return;
+ }
+ noise_offset = p_noise_offset;
+ _queue_update();
+}
+
void NoiseTexture::set_seamless(bool p_seamless) {
if (p_seamless == seamless) {
return;
@@ -245,6 +257,10 @@ int NoiseTexture::get_height() const {
return size.y;
}
+Vector2 NoiseTexture::get_noise_offset() const {
+ return noise_offset;
+}
+
RID NoiseTexture::get_rid() const {
if (!texture.is_valid()) {
texture = RS::get_singleton()->texture_2d_placeholder_create();
diff --git a/modules/opensimplex/noise_texture.h b/modules/opensimplex/noise_texture.h
index 6983ae18fe..6237b6460d 100644
--- a/modules/opensimplex/noise_texture.h
+++ b/modules/opensimplex/noise_texture.h
@@ -34,7 +34,7 @@
#include "open_simplex_noise.h"
#include "core/io/image.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/property_editor.h"
@@ -56,6 +56,7 @@ private:
Ref<OpenSimplexNoise> noise;
Vector2i size = Vector2i(512, 512);
+ Vector2 noise_offset;
bool seamless = false;
bool as_normal_map = false;
float bump_strength = 8.0;
@@ -79,6 +80,9 @@ public:
void set_width(int p_width);
void set_height(int p_height);
+ void set_noise_offset(Vector2 p_noise_offset);
+ Vector2 get_noise_offset() const;
+
void set_seamless(bool p_seamless);
bool get_seamless();
diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp
index 3773946112..f0a8867284 100644
--- a/modules/opensimplex/open_simplex_noise.cpp
+++ b/modules/opensimplex/open_simplex_noise.cpp
@@ -96,7 +96,7 @@ void OpenSimplexNoise::set_lacunarity(float p_lacunarity) {
emit_changed();
}
-Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) const {
+Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height, const Vector2 &p_noise_offset) const {
Vector<uint8_t> data;
data.resize(p_width * p_height);
@@ -104,7 +104,7 @@ Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) const {
for (int i = 0; i < p_height; i++) {
for (int j = 0; j < p_width; j++) {
- float v = get_noise_2d(j, i);
+ float v = get_noise_2d(float(j) + p_noise_offset.x, float(i) + p_noise_offset.y);
v = v * 0.5 + 0.5; // Normalize [0..1]
wd8[(i * p_width + j)] = uint8_t(CLAMP(v * 255.0, 0, 255));
}
@@ -161,7 +161,7 @@ void OpenSimplexNoise::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lacunarity", "lacunarity"), &OpenSimplexNoise::set_lacunarity);
ClassDB::bind_method(D_METHOD("get_lacunarity"), &OpenSimplexNoise::get_lacunarity);
- ClassDB::bind_method(D_METHOD("get_image", "width", "height"), &OpenSimplexNoise::get_image);
+ ClassDB::bind_method(D_METHOD("get_image", "width", "height", "noise_offset"), &OpenSimplexNoise::get_image, DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("get_seamless_image", "size"), &OpenSimplexNoise::get_seamless_image);
ClassDB::bind_method(D_METHOD("get_noise_1d", "x"), &OpenSimplexNoise::get_noise_1d);
diff --git a/modules/opensimplex/open_simplex_noise.h b/modules/opensimplex/open_simplex_noise.h
index 847c157409..dcf922a8bf 100644
--- a/modules/opensimplex/open_simplex_noise.h
+++ b/modules/opensimplex/open_simplex_noise.h
@@ -32,7 +32,7 @@
#define OPEN_SIMPLEX_NOISE_H
#include "core/io/image.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "scene/resources/texture.h"
#include "thirdparty/misc/open-simplex-noise.h"
@@ -75,7 +75,7 @@ public:
void set_lacunarity(float p_lacunarity);
float get_lacunarity() const { return lacunarity; }
- Ref<Image> get_image(int p_width, int p_height) const;
+ Ref<Image> get_image(int p_width, int p_height, const Vector2 &p_noise_offset = Vector2()) const;
Ref<Image> get_seamless_image(int p_size) const;
float get_noise_1d(float x) const;
diff --git a/modules/pvr/image_compress_pvrtc.cpp b/modules/pvr/image_compress_pvrtc.cpp
index d2d8976694..4d0430fa92 100644
--- a/modules/pvr/image_compress_pvrtc.cpp
+++ b/modules/pvr/image_compress_pvrtc.cpp
@@ -31,7 +31,7 @@
#include "image_compress_pvrtc.h"
#include "core/io/image.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include <PvrTcEncoder.h>
#include <RgbaBitmap.h>
@@ -65,7 +65,7 @@ static void _compress_pvrtc1_4bpp(Image *p_img) {
img->get_mipmap_offset_size_and_dimensions(i, ofs, size, w, h);
Javelin::RgbaBitmap bm(w, h);
void *dst = (void *)bm.GetData();
- copymem(dst, &r[ofs], size);
+ memcpy(dst, &r[ofs], size);
Javelin::ColorRgba<unsigned char> *dp = bm.GetData();
for (int j = 0; j < size / 4; j++) {
// Red and blue colors are swapped.
diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp
index 83f032ca2b..cb12976090 100644
--- a/modules/pvr/texture_loader_pvr.cpp
+++ b/modules/pvr/texture_loader_pvr.cpp
@@ -30,7 +30,7 @@
#include "texture_loader_pvr.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
static void _pvrtc_decompress(Image *p_img);
diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub
new file mode 100644
index 0000000000..6e7b3e7b8d
--- /dev/null
+++ b/modules/raycast/SCsub
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_raycast = env_modules.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+if env["builtin_embree"]:
+ thirdparty_dir = "#thirdparty/embree/"
+
+ embree_src = [
+ "common/sys/sysinfo.cpp",
+ "common/sys/alloc.cpp",
+ "common/sys/filename.cpp",
+ "common/sys/library.cpp",
+ "common/sys/thread.cpp",
+ "common/sys/string.cpp",
+ "common/sys/regression.cpp",
+ "common/sys/mutex.cpp",
+ "common/sys/condition.cpp",
+ "common/sys/barrier.cpp",
+ "common/math/constants.cpp",
+ "common/simd/sse.cpp",
+ "common/lexers/stringstream.cpp",
+ "common/lexers/tokenstream.cpp",
+ "common/tasking/taskschedulerinternal.cpp",
+ "kernels/common/device.cpp",
+ "kernels/common/stat.cpp",
+ "kernels/common/acceln.cpp",
+ "kernels/common/accelset.cpp",
+ "kernels/common/state.cpp",
+ "kernels/common/rtcore.cpp",
+ "kernels/common/rtcore_builder.cpp",
+ "kernels/common/scene.cpp",
+ "kernels/common/alloc.cpp",
+ "kernels/common/geometry.cpp",
+ "kernels/common/scene_triangle_mesh.cpp",
+ "kernels/geometry/primitive4.cpp",
+ "kernels/builders/primrefgen.cpp",
+ "kernels/bvh/bvh.cpp",
+ "kernels/bvh/bvh_statistics.cpp",
+ "kernels/bvh/bvh4_factory.cpp",
+ "kernels/bvh/bvh8_factory.cpp",
+ "kernels/bvh/bvh_collider.cpp",
+ "kernels/bvh/bvh_rotate.cpp",
+ "kernels/bvh/bvh_refit.cpp",
+ "kernels/bvh/bvh_builder.cpp",
+ "kernels/bvh/bvh_builder_morton.cpp",
+ "kernels/bvh/bvh_builder_sah.cpp",
+ "kernels/bvh/bvh_builder_sah_spatial.cpp",
+ "kernels/bvh/bvh_builder_sah_mb.cpp",
+ "kernels/bvh/bvh_builder_twolevel.cpp",
+ "kernels/bvh/bvh_intersector1_bvh4.cpp",
+ ]
+
+ thirdparty_sources = [thirdparty_dir + file for file in embree_src]
+
+ env_raycast.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "include"])
+ env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL", "NDEBUG"])
+
+ if not env.msvc:
+ if env["arch"] in ["x86", "x86_64"]:
+ env_raycast.Append(CPPFLAGS=["-msse2", "-mxsave"])
+
+ if env["platform"] == "windows":
+ env_raycast.Append(CPPFLAGS=["-mstackrealign"])
+
+ if env["platform"] == "windows":
+ if env.msvc:
+ env.Append(LINKFLAGS=["psapi.lib"])
+ else:
+ env.Append(LIBS=["psapi"])
+
+ env_thirdparty = env_raycast.Clone()
+ env_thirdparty.disable_warnings()
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+
+ if not env["arch"] in ["x86", "x86_64"] or env.msvc:
+ # Embree needs those, it will automatically use SSE2NEON in ARM
+ env_thirdparty.Append(CPPDEFINES=["__SSE2__", "__SSE__"])
+
+ env.modules_sources += thirdparty_obj
+
+
+# Godot source files
+
+module_obj = []
+
+env_raycast.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/raycast/config.py b/modules/raycast/config.py
new file mode 100644
index 0000000000..5de36c5322
--- /dev/null
+++ b/modules/raycast/config.py
@@ -0,0 +1,17 @@
+def can_build(env, platform):
+ # Depends on Embree library, which only supports x86_64 and aarch64.
+
+ if platform == "android":
+ return env["android_arch"] in ["arm64v8", "x86_64"]
+
+ if platform == "javascript":
+ return False # No SIMD support yet
+
+ if env["bits"] == "32":
+ return False
+
+ return True
+
+
+def configure(env):
+ pass
diff --git a/modules/raycast/godot_update_embree.py b/modules/raycast/godot_update_embree.py
new file mode 100644
index 0000000000..31a25a318f
--- /dev/null
+++ b/modules/raycast/godot_update_embree.py
@@ -0,0 +1,251 @@
+import glob, os, shutil, subprocess, re
+
+include_dirs = [
+ "common/tasking",
+ "kernels/bvh",
+ "kernels/builders",
+ "common/sys",
+ "kernels",
+ "kernels/common",
+ "common/math",
+ "common/algorithms",
+ "common/lexers",
+ "common/simd",
+ "common/simd/arm",
+ "include/embree3",
+ "kernels/subdiv",
+ "kernels/geometry",
+]
+
+cpp_files = [
+ "common/sys/sysinfo.cpp",
+ "common/sys/alloc.cpp",
+ "common/sys/filename.cpp",
+ "common/sys/library.cpp",
+ "common/sys/thread.cpp",
+ "common/sys/string.cpp",
+ "common/sys/regression.cpp",
+ "common/sys/mutex.cpp",
+ "common/sys/condition.cpp",
+ "common/sys/barrier.cpp",
+ "common/math/constants.cpp",
+ "common/simd/sse.cpp",
+ "common/lexers/stringstream.cpp",
+ "common/lexers/tokenstream.cpp",
+ "common/tasking/taskschedulerinternal.cpp",
+ "kernels/common/device.cpp",
+ "kernels/common/stat.cpp",
+ "kernels/common/acceln.cpp",
+ "kernels/common/accelset.cpp",
+ "kernels/common/state.cpp",
+ "kernels/common/rtcore.cpp",
+ "kernels/common/rtcore_builder.cpp",
+ "kernels/common/scene.cpp",
+ "kernels/common/alloc.cpp",
+ "kernels/common/geometry.cpp",
+ "kernels/common/scene_triangle_mesh.cpp",
+ "kernels/geometry/primitive4.cpp",
+ "kernels/builders/primrefgen.cpp",
+ "kernels/bvh/bvh.cpp",
+ "kernels/bvh/bvh_statistics.cpp",
+ "kernels/bvh/bvh4_factory.cpp",
+ "kernels/bvh/bvh8_factory.cpp",
+ "kernels/bvh/bvh_collider.cpp",
+ "kernels/bvh/bvh_rotate.cpp",
+ "kernels/bvh/bvh_refit.cpp",
+ "kernels/bvh/bvh_builder.cpp",
+ "kernels/bvh/bvh_builder_morton.cpp",
+ "kernels/bvh/bvh_builder_sah.cpp",
+ "kernels/bvh/bvh_builder_sah_spatial.cpp",
+ "kernels/bvh/bvh_builder_sah_mb.cpp",
+ "kernels/bvh/bvh_builder_twolevel.cpp",
+ "kernels/bvh/bvh_intersector1.cpp",
+ "kernels/bvh/bvh_intersector1_bvh4.cpp",
+]
+
+os.chdir("../../thirdparty")
+
+dir_name = "embree"
+if os.path.exists(dir_name):
+ shutil.rmtree(dir_name)
+
+subprocess.run(["git", "clone", "https://github.com/embree/embree.git", "embree-tmp"])
+os.chdir("embree-tmp")
+
+commit_hash = str(subprocess.check_output(["git", "rev-parse", "HEAD"], universal_newlines=True)).strip()
+
+all_files = set(cpp_files)
+
+dest_dir = os.path.join("..", dir_name)
+for include_dir in include_dirs:
+ headers = glob.iglob(os.path.join(include_dir, "*.h"))
+ all_files.update(headers)
+
+for f in all_files:
+ d = os.path.join(dest_dir, os.path.dirname(f))
+ if not os.path.exists(d):
+ os.makedirs(d)
+ shutil.copy2(f, d)
+
+with open(os.path.join(dest_dir, "kernels/hash.h"), "w") as hash_file:
+ hash_file.write(
+ f"""
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#define RTC_HASH "{commit_hash}"
+"""
+ )
+
+with open(os.path.join(dest_dir, "kernels/config.h"), "w") as config_file:
+ config_file.write(
+ """
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+/* #undef EMBREE_RAY_MASK */
+/* #undef EMBREE_STAT_COUNTERS */
+/* #undef EMBREE_BACKFACE_CULLING */
+/* #undef EMBREE_BACKFACE_CULLING_CURVES */
+#define EMBREE_FILTER_FUNCTION
+/* #undef EMBREE_IGNORE_INVALID_RAYS */
+#define EMBREE_GEOMETRY_TRIANGLE
+/* #undef EMBREE_GEOMETRY_QUAD */
+/* #undef EMBREE_GEOMETRY_CURVE */
+/* #undef EMBREE_GEOMETRY_SUBDIVISION */
+/* #undef EMBREE_GEOMETRY_USER */
+/* #undef EMBREE_GEOMETRY_INSTANCE */
+/* #undef EMBREE_GEOMETRY_GRID */
+/* #undef EMBREE_GEOMETRY_POINT */
+/* #undef EMBREE_RAY_PACKETS */
+/* #undef EMBREE_COMPACT_POLYS */
+
+#define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR 2.0
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ #define IF_ENABLED_TRIS(x) x
+#else
+ #define IF_ENABLED_TRIS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ #define IF_ENABLED_QUADS(x) x
+#else
+ #define IF_ENABLED_QUADS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT)
+ #define IF_ENABLED_CURVES_OR_POINTS(x) x
+#else
+ #define IF_ENABLED_CURVES_OR_POINTS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_CURVE)
+ #define IF_ENABLED_CURVES(x) x
+#else
+ #define IF_ENABLED_CURVES(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_POINT)
+ #define IF_ENABLED_POINTS(x) x
+#else
+ #define IF_ENABLED_POINTS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ #define IF_ENABLED_SUBDIV(x) x
+#else
+ #define IF_ENABLED_SUBDIV(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ #define IF_ENABLED_USER(x) x
+#else
+ #define IF_ENABLED_USER(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ #define IF_ENABLED_INSTANCE(x) x
+#else
+ #define IF_ENABLED_INSTANCE(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_GRID)
+ #define IF_ENABLED_GRIDS(x) x
+#else
+ #define IF_ENABLED_GRIDS(x)
+#endif
+"""
+ )
+
+
+with open("CMakeLists.txt", "r") as cmake_file:
+ cmake_content = cmake_file.read()
+ major_version = int(re.compile(r"EMBREE_VERSION_MAJOR\s(\d+)").findall(cmake_content)[0])
+ minor_version = int(re.compile(r"EMBREE_VERSION_MINOR\s(\d+)").findall(cmake_content)[0])
+ patch_version = int(re.compile(r"EMBREE_VERSION_PATCH\s(\d+)").findall(cmake_content)[0])
+
+with open(os.path.join(dest_dir, "include/embree3/rtcore_config.h"), "w") as config_file:
+ config_file.write(
+ f"""
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define RTC_VERSION_MAJOR {major_version}
+#define RTC_VERSION_MINOR {minor_version}
+#define RTC_VERSION_PATCH {patch_version}
+#define RTC_VERSION {major_version}{minor_version:02d}{patch_version:02d}
+#define RTC_VERSION_STRING "{major_version}.{minor_version}.{patch_version}"
+
+#define RTC_MAX_INSTANCE_LEVEL_COUNT 1
+
+#define EMBREE_MIN_WIDTH 0
+#define RTC_MIN_WIDTH EMBREE_MIN_WIDTH
+
+#define EMBREE_STATIC_LIB
+/* #undef EMBREE_API_NAMESPACE */
+
+#if defined(EMBREE_API_NAMESPACE)
+# define RTC_NAMESPACE
+# define RTC_NAMESPACE_BEGIN namespace {{
+# define RTC_NAMESPACE_END }}
+# define RTC_NAMESPACE_USE using namespace ;
+# define RTC_API_EXTERN_C
+# undef EMBREE_API_NAMESPACE
+#else
+# define RTC_NAMESPACE_BEGIN
+# define RTC_NAMESPACE_END
+# define RTC_NAMESPACE_USE
+# if defined(__cplusplus)
+# define RTC_API_EXTERN_C extern "C"
+# else
+# define RTC_API_EXTERN_C
+# endif
+#endif
+
+#if defined(ISPC)
+# define RTC_API_IMPORT extern "C" unmasked
+# define RTC_API_EXPORT extern "C" unmasked
+#elif defined(EMBREE_STATIC_LIB)
+# define RTC_API_IMPORT RTC_API_EXTERN_C
+# define RTC_API_EXPORT RTC_API_EXTERN_C
+#elif defined(_WIN32)
+# define RTC_API_IMPORT RTC_API_EXTERN_C __declspec(dllimport)
+# define RTC_API_EXPORT RTC_API_EXTERN_C __declspec(dllexport)
+#else
+# define RTC_API_IMPORT RTC_API_EXTERN_C
+# define RTC_API_EXPORT RTC_API_EXTERN_C __attribute__ ((visibility ("default")))
+#endif
+
+#if defined(RTC_EXPORT_API)
+# define RTC_API RTC_API_EXPORT
+#else
+# define RTC_API RTC_API_IMPORT
+#endif
+"""
+ )
+
+os.chdir("..")
+shutil.rmtree("embree-tmp")
diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster.cpp
new file mode 100644
index 0000000000..0583acc119
--- /dev/null
+++ b/modules/raycast/lightmap_raycaster.cpp
@@ -0,0 +1,201 @@
+/*************************************************************************/
+/* lightmap_raycaster.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef TOOLS_ENABLED
+
+#include "lightmap_raycaster.h"
+
+#ifdef __SSE2__
+#include <pmmintrin.h>
+#endif
+
+LightmapRaycaster *LightmapRaycasterEmbree::create_embree_raycaster() {
+ return memnew(LightmapRaycasterEmbree);
+}
+
+void LightmapRaycasterEmbree::make_default_raycaster() {
+ create_function = create_embree_raycaster;
+}
+
+void LightmapRaycasterEmbree::filter_function(const struct RTCFilterFunctionNArguments *p_args) {
+ RTCHit *hit = (RTCHit *)p_args->hit;
+
+ unsigned int geomID = hit->geomID;
+ float u = hit->u;
+ float v = hit->v;
+
+ LightmapRaycasterEmbree *scene = (LightmapRaycasterEmbree *)p_args->geometryUserPtr;
+ RTCGeometry geom = rtcGetGeometry(scene->embree_scene, geomID);
+
+ rtcInterpolate0(geom, hit->primID, hit->u, hit->v, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, &hit->u, 2);
+
+ if (scene->alpha_textures.has(geomID)) {
+ const AlphaTextureData &alpha_texture = scene->alpha_textures[geomID];
+
+ if (alpha_texture.sample(hit->u, hit->v) < 128) {
+ p_args->valid[0] = 0;
+ return;
+ }
+ }
+
+ rtcInterpolate0(geom, hit->primID, u, v, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, &hit->Ng_x, 3);
+}
+
+bool LightmapRaycasterEmbree::intersect(Ray &r_ray) {
+ RTCIntersectContext context;
+
+ rtcInitIntersectContext(&context);
+
+ rtcIntersect1(embree_scene, &context, (RTCRayHit *)&r_ray);
+ return r_ray.geomID != RTC_INVALID_GEOMETRY_ID;
+}
+
+void LightmapRaycasterEmbree::intersect(Vector<Ray> &r_rays) {
+ Ray *rays = r_rays.ptrw();
+ for (int i = 0; i < r_rays.size(); ++i) {
+ intersect(rays[i]);
+ }
+}
+
+void LightmapRaycasterEmbree::set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) {
+ if (p_alpha_texture.is_valid() && p_alpha_texture->get_size() != Vector2i()) {
+ AlphaTextureData tex;
+ tex.size = p_alpha_texture->get_size();
+ tex.data = p_alpha_texture->get_data();
+ alpha_textures.insert(p_id, tex);
+ }
+}
+
+float blerp(float c00, float c10, float c01, float c11, float tx, float ty) {
+ return Math::lerp(Math::lerp(c00, c10, tx), Math::lerp(c01, c11, tx), ty);
+}
+
+uint8_t LightmapRaycasterEmbree::AlphaTextureData::sample(float u, float v) const {
+ float x = u * size.x;
+ float y = v * size.y;
+ int xi = (int)x;
+ int yi = (int)y;
+
+ uint8_t texels[4];
+
+ for (int i = 0; i < 4; ++i) {
+ int sample_x = CLAMP(xi + i % 2, 0, size.x - 1);
+ int sample_y = CLAMP(yi + i / 2, 0, size.y - 1);
+ texels[i] = data[sample_y * size.x + sample_x];
+ }
+
+ return Math::round(blerp(texels[0], texels[1], texels[2], texels[3], x - xi, y - yi));
+}
+
+void LightmapRaycasterEmbree::add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) {
+ RTCGeometry embree_mesh = rtcNewGeometry(embree_device, RTC_GEOMETRY_TYPE_TRIANGLE);
+
+ rtcSetGeometryVertexAttributeCount(embree_mesh, 2);
+
+ int vertex_count = p_vertices.size();
+
+ ERR_FAIL_COND(vertex_count % 3 != 0);
+ ERR_FAIL_COND(vertex_count != p_uv2s.size());
+ ERR_FAIL_COND(!p_normals.is_empty() && vertex_count != p_normals.size());
+
+ Vector3 *embree_vertices = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count);
+ memcpy(embree_vertices, p_vertices.ptr(), sizeof(Vector3) * vertex_count);
+
+ Vector2 *embree_light_uvs = (Vector2 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, RTC_FORMAT_FLOAT2, sizeof(Vector2), vertex_count);
+ memcpy(embree_light_uvs, p_uv2s.ptr(), sizeof(Vector2) * vertex_count);
+
+ uint32_t *embree_triangles = (uint32_t *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(uint32_t) * 3, vertex_count / 3);
+ for (int i = 0; i < vertex_count; i++) {
+ embree_triangles[i] = i;
+ }
+
+ if (!p_normals.is_empty()) {
+ Vector3 *embree_normals = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count);
+ memcpy(embree_normals, p_normals.ptr(), sizeof(Vector3) * vertex_count);
+ }
+
+ rtcCommitGeometry(embree_mesh);
+ rtcSetGeometryIntersectFilterFunction(embree_mesh, filter_function);
+ rtcSetGeometryUserData(embree_mesh, this);
+ rtcAttachGeometryByID(embree_scene, embree_mesh, p_id);
+ rtcReleaseGeometry(embree_mesh);
+}
+
+void LightmapRaycasterEmbree::commit() {
+ rtcCommitScene(embree_scene);
+}
+
+void LightmapRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) {
+ for (Set<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) {
+ rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get()));
+ }
+ rtcCommitScene(embree_scene);
+ filter_meshes = p_mesh_ids;
+}
+
+void LightmapRaycasterEmbree::clear_mesh_filter() {
+ for (Set<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
+ rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get()));
+ }
+ rtcCommitScene(embree_scene);
+ filter_meshes.clear();
+}
+
+void embree_error_handler(void *p_user_data, RTCError p_code, const char *p_str) {
+ print_error("Embree error: " + String(p_str));
+}
+
+LightmapRaycasterEmbree::LightmapRaycasterEmbree() {
+#ifdef __SSE2__
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
+#endif
+
+ embree_device = rtcNewDevice(nullptr);
+ rtcSetDeviceErrorFunction(embree_device, &embree_error_handler, nullptr);
+ embree_scene = rtcNewScene(embree_device);
+}
+
+LightmapRaycasterEmbree::~LightmapRaycasterEmbree() {
+#ifdef __SSE2__
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
+#endif
+
+ if (embree_scene != nullptr) {
+ rtcReleaseScene(embree_scene);
+ }
+
+ if (embree_device != nullptr) {
+ rtcReleaseDevice(embree_device);
+ }
+}
+
+#endif
diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster.h
new file mode 100644
index 0000000000..4c3de27837
--- /dev/null
+++ b/modules/raycast/lightmap_raycaster.h
@@ -0,0 +1,77 @@
+/*************************************************************************/
+/* lightmap_raycaster.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef TOOLS_ENABLED
+
+#include "core/object/object.h"
+#include "scene/3d/lightmapper.h"
+#include "scene/resources/mesh.h"
+
+#include <embree3/rtcore.h>
+
+class LightmapRaycasterEmbree : public LightmapRaycaster {
+ GDCLASS(LightmapRaycasterEmbree, LightmapRaycaster);
+
+private:
+ struct AlphaTextureData {
+ Vector<uint8_t> data;
+ Vector2i size;
+
+ uint8_t sample(float u, float v) const;
+ };
+
+ RTCDevice embree_device;
+ RTCScene embree_scene;
+
+ static void filter_function(const struct RTCFilterFunctionNArguments *p_args);
+
+ Map<unsigned int, AlphaTextureData> alpha_textures;
+ Set<int> filter_meshes;
+
+public:
+ virtual bool intersect(Ray &p_ray) override;
+
+ virtual void intersect(Vector<Ray> &r_rays) override;
+
+ virtual void add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) override;
+ virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) override;
+ virtual void commit() override;
+
+ virtual void set_mesh_filter(const Set<int> &p_mesh_ids) override;
+ virtual void clear_mesh_filter() override;
+
+ static LightmapRaycaster *create_embree_raycaster();
+ static void make_default_raycaster();
+
+ LightmapRaycasterEmbree();
+ ~LightmapRaycasterEmbree();
+};
+
+#endif
diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp
new file mode 100644
index 0000000000..88c0145ebc
--- /dev/null
+++ b/modules/raycast/raycast_occlusion_cull.cpp
@@ -0,0 +1,583 @@
+/*************************************************************************/
+/* raycast_occlusion_cull.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "raycast_occlusion_cull.h"
+#include "core/config/project_settings.h"
+#include "core/templates/local_vector.h"
+
+#ifdef __SSE2__
+#include <pmmintrin.h>
+#endif
+
+RaycastOcclusionCull *RaycastOcclusionCull::raycast_singleton = nullptr;
+
+void RaycastOcclusionCull::RaycastHZBuffer::clear() {
+ HZBuffer::clear();
+
+ camera_rays.clear();
+ camera_ray_masks.clear();
+ packs_size = Size2i();
+}
+
+void RaycastOcclusionCull::RaycastHZBuffer::resize(const Size2i &p_size) {
+ if (p_size == Size2i()) {
+ clear();
+ return;
+ }
+
+ if (!sizes.is_empty() && p_size == sizes[0]) {
+ return; // Size didn't change
+ }
+
+ HZBuffer::resize(p_size);
+
+ packs_size = Size2i(Math::ceil(p_size.x / (float)TILE_SIZE), Math::ceil(p_size.y / (float)TILE_SIZE));
+ int ray_packets_count = packs_size.x * packs_size.y;
+ camera_rays.resize(ray_packets_count);
+ camera_ray_masks.resize(ray_packets_count * TILE_SIZE * TILE_SIZE);
+}
+
+void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool) {
+ CameraRayThreadData td;
+ td.camera_matrix = p_cam_projection;
+ td.camera_transform = p_cam_transform;
+ td.camera_orthogonal = p_cam_orthogonal;
+ td.thread_count = p_thread_work_pool.get_thread_count();
+
+ p_thread_work_pool.do_work(td.thread_count, this, &RaycastHZBuffer::_camera_rays_threaded, &td);
+}
+
+void RaycastOcclusionCull::RaycastHZBuffer::_camera_rays_threaded(uint32_t p_thread, RaycastOcclusionCull::RaycastHZBuffer::CameraRayThreadData *p_data) {
+ uint32_t packs_total = camera_rays.size();
+ uint32_t total_threads = p_data->thread_count;
+ uint32_t from = p_thread * packs_total / total_threads;
+ uint32_t to = (p_thread + 1 == total_threads) ? packs_total : ((p_thread + 1) * packs_total / total_threads);
+ _generate_camera_rays(p_data->camera_transform, p_data->camera_matrix, p_data->camera_orthogonal, from, to);
+}
+
+void RaycastOcclusionCull::RaycastHZBuffer::_generate_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to) {
+ Size2i buffer_size = sizes[0];
+
+ CameraMatrix inv_camera_matrix = p_cam_projection.inverse();
+ float z_far = p_cam_projection.get_z_far() * 1.05f;
+ debug_tex_range = z_far;
+
+ RayPacket *ray_packets = camera_rays.ptr();
+ uint32_t *ray_masks = camera_ray_masks.ptr();
+
+ for (int i = p_from; i < p_to; i++) {
+ RayPacket &packet = ray_packets[i];
+ int tile_x = (i % packs_size.x) * TILE_SIZE;
+ int tile_y = (i / packs_size.x) * TILE_SIZE;
+
+ for (int j = 0; j < TILE_RAYS; j++) {
+ float x = tile_x + j % TILE_SIZE;
+ float y = tile_y + j / TILE_SIZE;
+
+ ray_masks[i * TILE_RAYS + j] = ~0U;
+
+ if (x >= buffer_size.x || y >= buffer_size.y) {
+ ray_masks[i * TILE_RAYS + j] = 0U;
+ } else {
+ float u = x / (buffer_size.x - 1);
+ float v = y / (buffer_size.y - 1);
+ u = u * 2.0f - 1.0f;
+ v = v * 2.0f - 1.0f;
+
+ Plane pixel_proj = Plane(u, v, -1.0, 1.0);
+ Plane pixel_view = inv_camera_matrix.xform4(pixel_proj);
+ Vector3 pixel_world = p_cam_transform.xform(pixel_view.normal);
+
+ Vector3 dir;
+ if (p_cam_orthogonal) {
+ dir = -p_cam_transform.basis.get_axis(2);
+ } else {
+ dir = (pixel_world - p_cam_transform.origin).normalized();
+ }
+
+ packet.ray.org_x[j] = pixel_world.x;
+ packet.ray.org_y[j] = pixel_world.y;
+ packet.ray.org_z[j] = pixel_world.z;
+
+ packet.ray.dir_x[j] = dir.x;
+ packet.ray.dir_y[j] = dir.y;
+ packet.ray.dir_z[j] = dir.z;
+
+ packet.ray.tnear[j] = 0.0f;
+
+ packet.ray.time[j] = 0.0f;
+
+ packet.ray.flags[j] = 0;
+ packet.ray.mask[j] = -1;
+ packet.hit.geomID[j] = RTC_INVALID_GEOMETRY_ID;
+ }
+
+ packet.ray.tfar[j] = z_far;
+ }
+ }
+}
+
+void RaycastOcclusionCull::RaycastHZBuffer::sort_rays() {
+ if (is_empty()) {
+ return;
+ }
+
+ Size2i buffer_size = sizes[0];
+ for (int i = 0; i < packs_size.y; i++) {
+ for (int j = 0; j < packs_size.x; j++) {
+ for (int tile_i = 0; tile_i < TILE_SIZE; tile_i++) {
+ for (int tile_j = 0; tile_j < TILE_SIZE; tile_j++) {
+ int x = j * TILE_SIZE + tile_j;
+ int y = i * TILE_SIZE + tile_i;
+ if (x >= buffer_size.x || y >= buffer_size.y) {
+ continue;
+ }
+ int k = tile_i * TILE_SIZE + tile_j;
+ int packet_index = i * packs_size.x + j;
+ mips[0][y * buffer_size.x + x] = camera_rays[packet_index].ray.tfar[k];
+ }
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////
+
+bool RaycastOcclusionCull::is_occluder(RID p_rid) {
+ return occluder_owner.owns(p_rid);
+}
+
+RID RaycastOcclusionCull::occluder_allocate() {
+ return occluder_owner.allocate_rid();
+}
+
+void RaycastOcclusionCull::occluder_initialize(RID p_occluder) {
+ Occluder *occluder = memnew(Occluder);
+ occluder_owner.initialize_rid(p_occluder, occluder);
+}
+
+void RaycastOcclusionCull::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {
+ Occluder *occluder = occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ occluder->vertices = p_vertices;
+ occluder->indices = p_indices;
+
+ for (Set<InstanceID>::Element *E = occluder->users.front(); E; E = E->next()) {
+ RID scenario_rid = E->get().scenario;
+ RID instance_rid = E->get().instance;
+ ERR_CONTINUE(!scenarios.has(scenario_rid));
+ Scenario &scenario = scenarios[scenario_rid];
+ ERR_CONTINUE(!scenario.instances.has(instance_rid));
+
+ if (!scenario.dirty_instances.has(instance_rid)) {
+ scenario.dirty_instances.insert(instance_rid);
+ scenario.dirty_instances_array.push_back(instance_rid);
+ }
+ }
+}
+
+void RaycastOcclusionCull::free_occluder(RID p_occluder) {
+ Occluder *occluder = occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+ memdelete(occluder);
+ occluder_owner.free(p_occluder);
+}
+
+////////////////////////////////////////////////////////
+
+void RaycastOcclusionCull::add_scenario(RID p_scenario) {
+ if (scenarios.has(p_scenario)) {
+ scenarios[p_scenario].removed = false;
+ } else {
+ scenarios[p_scenario] = Scenario();
+ }
+}
+
+void RaycastOcclusionCull::remove_scenario(RID p_scenario) {
+ ERR_FAIL_COND(!scenarios.has(p_scenario));
+ Scenario &scenario = scenarios[p_scenario];
+ scenario.removed = true;
+}
+
+void RaycastOcclusionCull::scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform3D &p_xform, bool p_enabled) {
+ ERR_FAIL_COND(!scenarios.has(p_scenario));
+ Scenario &scenario = scenarios[p_scenario];
+
+ if (!scenario.instances.has(p_instance)) {
+ scenario.instances[p_instance] = OccluderInstance();
+ }
+
+ OccluderInstance &instance = scenario.instances[p_instance];
+
+ if (instance.removed) {
+ instance.removed = false;
+ scenario.removed_instances.erase(p_instance);
+ }
+
+ bool changed = false;
+
+ if (instance.occluder != p_occluder) {
+ Occluder *old_occluder = occluder_owner.getornull(instance.occluder);
+ if (old_occluder) {
+ old_occluder->users.erase(InstanceID(p_scenario, p_instance));
+ }
+
+ instance.occluder = p_occluder;
+
+ if (p_occluder.is_valid()) {
+ Occluder *occluder = occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+ occluder->users.insert(InstanceID(p_scenario, p_instance));
+ }
+ changed = true;
+ }
+
+ if (instance.xform != p_xform) {
+ scenario.instances[p_instance].xform = p_xform;
+ changed = true;
+ }
+
+ if (instance.enabled != p_enabled) {
+ instance.enabled = p_enabled;
+ scenario.dirty = true; // The scenario needs a scene re-build, but the instance doesn't need update
+ }
+
+ if (changed && !scenario.dirty_instances.has(p_instance)) {
+ scenario.dirty_instances.insert(p_instance);
+ scenario.dirty_instances_array.push_back(p_instance);
+ scenario.dirty = true;
+ }
+}
+
+void RaycastOcclusionCull::scenario_remove_instance(RID p_scenario, RID p_instance) {
+ ERR_FAIL_COND(!scenarios.has(p_scenario));
+ Scenario &scenario = scenarios[p_scenario];
+
+ if (scenario.instances.has(p_instance)) {
+ OccluderInstance &instance = scenario.instances[p_instance];
+
+ if (!instance.removed) {
+ Occluder *occluder = occluder_owner.getornull(instance.occluder);
+ if (occluder) {
+ occluder->users.erase(InstanceID(p_scenario, p_instance));
+ }
+
+ scenario.removed_instances.push_back(p_instance);
+ instance.removed = true;
+ }
+ }
+}
+
+void RaycastOcclusionCull::Scenario::_update_dirty_instance_thread(int p_idx, RID *p_instances) {
+ _update_dirty_instance(p_idx, p_instances, nullptr);
+}
+
+void RaycastOcclusionCull::Scenario::_update_dirty_instance(int p_idx, RID *p_instances, ThreadWorkPool *p_thread_pool) {
+ OccluderInstance *occ_inst = instances.getptr(p_instances[p_idx]);
+
+ if (!occ_inst) {
+ return;
+ }
+
+ Occluder *occ = raycast_singleton->occluder_owner.getornull(occ_inst->occluder);
+
+ if (!occ) {
+ return;
+ }
+
+ int vertices_size = occ->vertices.size();
+
+ // Embree requires the last element to be readable by a 16-byte SSE load instruction, so we add padding to be safe.
+ occ_inst->xformed_vertices.resize(vertices_size + 1);
+
+ const Vector3 *read_ptr = occ->vertices.ptr();
+ Vector3 *write_ptr = occ_inst->xformed_vertices.ptr();
+
+ if (p_thread_pool && vertices_size > 1024) {
+ TransformThreadData td;
+ td.xform = occ_inst->xform;
+ td.read = read_ptr;
+ td.write = write_ptr;
+ td.vertex_count = vertices_size;
+ td.thread_count = p_thread_pool->get_thread_count();
+ p_thread_pool->do_work(td.thread_count, this, &Scenario::_transform_vertices_thread, &td);
+ } else {
+ _transform_vertices_range(read_ptr, write_ptr, occ_inst->xform, 0, vertices_size);
+ }
+
+ occ_inst->indices.resize(occ->indices.size());
+ memcpy(occ_inst->indices.ptr(), occ->indices.ptr(), occ->indices.size() * sizeof(int32_t));
+}
+
+void RaycastOcclusionCull::Scenario::_transform_vertices_thread(uint32_t p_thread, TransformThreadData *p_data) {
+ uint32_t vertex_total = p_data->vertex_count;
+ uint32_t total_threads = p_data->thread_count;
+ uint32_t from = p_thread * vertex_total / total_threads;
+ uint32_t to = (p_thread + 1 == total_threads) ? vertex_total : ((p_thread + 1) * vertex_total / total_threads);
+ _transform_vertices_range(p_data->read, p_data->write, p_data->xform, from, to);
+}
+
+void RaycastOcclusionCull::Scenario::_transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform3D &p_xform, int p_from, int p_to) {
+ for (int i = p_from; i < p_to; i++) {
+ p_write[i] = p_xform.xform(p_read[i]);
+ }
+}
+
+void RaycastOcclusionCull::Scenario::_commit_scene(void *p_ud) {
+ Scenario *scenario = (Scenario *)p_ud;
+ int commit_idx = 1 - (scenario->current_scene_idx);
+ rtcCommitScene(scenario->ebr_scene[commit_idx]);
+ scenario->commit_done = true;
+}
+
+bool RaycastOcclusionCull::Scenario::update(ThreadWorkPool &p_thread_pool) {
+ ERR_FAIL_COND_V(singleton == nullptr, false);
+
+ if (commit_thread == nullptr) {
+ commit_thread = memnew(Thread);
+ }
+
+ if (commit_thread->is_started()) {
+ if (commit_done) {
+ commit_thread->wait_to_finish();
+ current_scene_idx = 1 - current_scene_idx;
+ } else {
+ return false;
+ }
+ }
+
+ if (removed) {
+ if (ebr_scene[0]) {
+ rtcReleaseScene(ebr_scene[0]);
+ }
+ if (ebr_scene[1]) {
+ rtcReleaseScene(ebr_scene[1]);
+ }
+ return true;
+ }
+
+ if (!dirty && removed_instances.is_empty() && dirty_instances_array.is_empty()) {
+ return false;
+ }
+
+ for (unsigned int i = 0; i < removed_instances.size(); i++) {
+ instances.erase(removed_instances[i]);
+ }
+
+ if (dirty_instances_array.size() / p_thread_pool.get_thread_count() > 128) {
+ // Lots of instances, use per-instance threading
+ p_thread_pool.do_work(dirty_instances_array.size(), this, &Scenario::_update_dirty_instance_thread, dirty_instances_array.ptr());
+ } else {
+ // Few instances, use threading on the vertex transforms
+ for (unsigned int i = 0; i < dirty_instances_array.size(); i++) {
+ _update_dirty_instance(i, dirty_instances_array.ptr(), &p_thread_pool);
+ }
+ }
+
+ dirty_instances.clear();
+ dirty_instances_array.clear();
+ removed_instances.clear();
+
+ if (raycast_singleton->ebr_device == nullptr) {
+ raycast_singleton->_init_embree();
+ }
+
+ int next_scene_idx = 1 - current_scene_idx;
+ RTCScene &next_scene = ebr_scene[next_scene_idx];
+
+ if (next_scene) {
+ rtcReleaseScene(next_scene);
+ }
+
+ next_scene = rtcNewScene(raycast_singleton->ebr_device);
+ rtcSetSceneBuildQuality(next_scene, RTCBuildQuality(raycast_singleton->build_quality));
+
+ const RID *inst_rid = nullptr;
+ while ((inst_rid = instances.next(inst_rid))) {
+ OccluderInstance *occ_inst = instances.getptr(*inst_rid);
+ Occluder *occ = raycast_singleton->occluder_owner.getornull(occ_inst->occluder);
+
+ if (!occ || !occ_inst->enabled) {
+ continue;
+ }
+
+ RTCGeometry geom = rtcNewGeometry(raycast_singleton->ebr_device, RTC_GEOMETRY_TYPE_TRIANGLE);
+ rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, occ_inst->xformed_vertices.ptr(), 0, sizeof(Vector3), occ_inst->xformed_vertices.size());
+ rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, occ_inst->indices.ptr(), 0, sizeof(uint32_t) * 3, occ_inst->indices.size() / 3);
+ rtcCommitGeometry(geom);
+ rtcAttachGeometry(next_scene, geom);
+ rtcReleaseGeometry(geom);
+ }
+
+ dirty = false;
+ commit_done = false;
+ commit_thread->start(&Scenario::_commit_scene, this);
+ return false;
+}
+
+void RaycastOcclusionCull::Scenario::_raycast(uint32_t p_idx, const RaycastThreadData *p_raycast_data) const {
+ RTCIntersectContext ctx;
+ rtcInitIntersectContext(&ctx);
+ ctx.flags = RTC_INTERSECT_CONTEXT_FLAG_COHERENT;
+
+ rtcIntersect16((const int *)&p_raycast_data->masks[p_idx * TILE_RAYS], ebr_scene[current_scene_idx], &ctx, &p_raycast_data->rays[p_idx]);
+}
+
+void RaycastOcclusionCull::Scenario::raycast(LocalVector<RayPacket> &r_rays, const LocalVector<uint32_t> p_valid_masks, ThreadWorkPool &p_thread_pool) const {
+ ERR_FAIL_COND(singleton == nullptr);
+ if (raycast_singleton->ebr_device == nullptr) {
+ return; // Embree is initialized on demand when there is some scenario with occluders in it.
+ }
+
+ if (ebr_scene[current_scene_idx] == nullptr) {
+ return;
+ }
+
+ RaycastThreadData td;
+ td.rays = r_rays.ptr();
+ td.masks = p_valid_masks.ptr();
+
+ p_thread_pool.do_work(r_rays.size(), this, &Scenario::_raycast, &td);
+}
+
+////////////////////////////////////////////////////////
+
+void RaycastOcclusionCull::add_buffer(RID p_buffer) {
+ ERR_FAIL_COND(buffers.has(p_buffer));
+ buffers[p_buffer] = RaycastHZBuffer();
+}
+
+void RaycastOcclusionCull::remove_buffer(RID p_buffer) {
+ ERR_FAIL_COND(!buffers.has(p_buffer));
+ buffers.erase(p_buffer);
+}
+
+void RaycastOcclusionCull::buffer_set_scenario(RID p_buffer, RID p_scenario) {
+ ERR_FAIL_COND(!buffers.has(p_buffer));
+ ERR_FAIL_COND(p_scenario.is_valid() && !scenarios.has(p_scenario));
+ buffers[p_buffer].scenario_rid = p_scenario;
+}
+
+void RaycastOcclusionCull::buffer_set_size(RID p_buffer, const Vector2i &p_size) {
+ ERR_FAIL_COND(!buffers.has(p_buffer));
+ buffers[p_buffer].resize(p_size);
+}
+
+void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) {
+ if (!buffers.has(p_buffer)) {
+ return;
+ }
+
+ RaycastHZBuffer &buffer = buffers[p_buffer];
+
+ if (buffer.is_empty() || !scenarios.has(buffer.scenario_rid)) {
+ return;
+ }
+
+ Scenario &scenario = scenarios[buffer.scenario_rid];
+
+ bool removed = scenario.update(p_thread_pool);
+
+ if (removed) {
+ scenarios.erase(buffer.scenario_rid);
+ return;
+ }
+
+ buffer.update_camera_rays(p_cam_transform, p_cam_projection, p_cam_orthogonal, p_thread_pool);
+
+ scenario.raycast(buffer.camera_rays, buffer.camera_ray_masks, p_thread_pool);
+ buffer.sort_rays();
+ buffer.update_mips();
+}
+
+RaycastOcclusionCull::HZBuffer *RaycastOcclusionCull::buffer_get_ptr(RID p_buffer) {
+ if (!buffers.has(p_buffer)) {
+ return nullptr;
+ }
+ return &buffers[p_buffer];
+}
+
+RID RaycastOcclusionCull::buffer_get_debug_texture(RID p_buffer) {
+ ERR_FAIL_COND_V(!buffers.has(p_buffer), RID());
+ return buffers[p_buffer].get_debug_texture();
+}
+
+////////////////////////////////////////////////////////
+
+void RaycastOcclusionCull::set_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) {
+ if (build_quality == p_quality) {
+ return;
+ }
+
+ build_quality = p_quality;
+
+ const RID *scenario_rid = nullptr;
+ while ((scenario_rid = scenarios.next(scenario_rid))) {
+ scenarios[*scenario_rid].dirty = true;
+ }
+}
+
+void RaycastOcclusionCull::_init_embree() {
+#ifdef __SSE2__
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
+#endif
+
+ String settings = vformat("threads=%d", MAX(1, OS::get_singleton()->get_processor_count() - 2));
+ ebr_device = rtcNewDevice(settings.utf8().ptr());
+}
+
+RaycastOcclusionCull::RaycastOcclusionCull() {
+ raycast_singleton = this;
+ int default_quality = GLOBAL_GET("rendering/occlusion_culling/bvh_build_quality");
+ build_quality = RS::ViewportOcclusionCullingBuildQuality(default_quality);
+}
+
+RaycastOcclusionCull::~RaycastOcclusionCull() {
+ const RID *scenario_rid = nullptr;
+ while ((scenario_rid = scenarios.next(scenario_rid))) {
+ Scenario &scenario = scenarios[*scenario_rid];
+ if (scenario.commit_thread) {
+ scenario.commit_thread->wait_to_finish();
+ memdelete(scenario.commit_thread);
+ }
+ }
+
+ if (ebr_device != nullptr) {
+#ifdef __SSE2__
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
+#endif
+ rtcReleaseDevice(ebr_device);
+ }
+
+ raycast_singleton = nullptr;
+}
diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h
new file mode 100644
index 0000000000..85710a790c
--- /dev/null
+++ b/modules/raycast/raycast_occlusion_cull.h
@@ -0,0 +1,184 @@
+/*************************************************************************/
+/* raycast_occlusion_cull.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OCCLUSION_CULL_RAYCASTER_H
+#define OCCLUSION_CULL_RAYCASTER_H
+
+#include "core/io/image.h"
+#include "core/math/camera_matrix.h"
+#include "core/object/object.h"
+#include "core/object/ref_counted.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/rid_owner.h"
+#include "scene/resources/mesh.h"
+#include "servers/rendering/renderer_scene_occlusion_cull.h"
+
+#include <embree3/rtcore.h>
+
+class RaycastOcclusionCull : public RendererSceneOcclusionCull {
+ typedef RTCRayHit16 RayPacket;
+
+public:
+ class RaycastHZBuffer : public HZBuffer {
+ private:
+ Size2i packs_size;
+
+ struct CameraRayThreadData {
+ CameraMatrix camera_matrix;
+ Transform3D camera_transform;
+ bool camera_orthogonal;
+ int thread_count;
+ Size2i buffer_size;
+ };
+
+ void _camera_rays_threaded(uint32_t p_thread, CameraRayThreadData *p_data);
+ void _generate_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to);
+
+ public:
+ LocalVector<RayPacket> camera_rays;
+ LocalVector<uint32_t> camera_ray_masks;
+ RID scenario_rid;
+
+ virtual void clear() override;
+ virtual void resize(const Size2i &p_size) override;
+ void sort_rays();
+ void update_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool);
+ };
+
+private:
+ struct InstanceID {
+ RID scenario;
+ RID instance;
+
+ bool operator<(const InstanceID &rhs) const {
+ if (instance == rhs.instance) {
+ return rhs.scenario < scenario;
+ }
+ return instance < rhs.instance;
+ }
+
+ InstanceID() {}
+ InstanceID(RID s, RID i) :
+ scenario(s), instance(i) {}
+ };
+
+ struct Occluder {
+ PackedVector3Array vertices;
+ PackedInt32Array indices;
+ Set<InstanceID> users;
+ };
+
+ struct OccluderInstance {
+ RID occluder;
+ LocalVector<uint32_t> indices;
+ LocalVector<Vector3> xformed_vertices;
+ Transform3D xform;
+ bool enabled = true;
+ bool removed = false;
+ };
+
+ struct Scenario {
+ struct RaycastThreadData {
+ RayPacket *rays;
+ const uint32_t *masks;
+ };
+
+ struct TransformThreadData {
+ uint32_t thread_count;
+ uint32_t vertex_count;
+ Transform3D xform;
+ const Vector3 *read;
+ Vector3 *write;
+ };
+
+ Thread *commit_thread = nullptr;
+ bool commit_done = true;
+ bool dirty = false;
+ bool removed = false;
+
+ RTCScene ebr_scene[2] = { nullptr, nullptr };
+ int current_scene_idx = 0;
+
+ HashMap<RID, OccluderInstance> instances;
+ Set<RID> dirty_instances; // To avoid duplicates
+ LocalVector<RID> dirty_instances_array; // To iterate and split into threads
+ LocalVector<RID> removed_instances;
+
+ void _update_dirty_instance_thread(int p_idx, RID *p_instances);
+ void _update_dirty_instance(int p_idx, RID *p_instances, ThreadWorkPool *p_thread_pool);
+ void _transform_vertices_thread(uint32_t p_thread, TransformThreadData *p_data);
+ void _transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform3D &p_xform, int p_from, int p_to);
+ static void _commit_scene(void *p_ud);
+ bool update(ThreadWorkPool &p_thread_pool);
+
+ void _raycast(uint32_t p_thread, const RaycastThreadData *p_raycast_data) const;
+ void raycast(LocalVector<RayPacket> &r_rays, const LocalVector<uint32_t> p_valid_masks, ThreadWorkPool &p_thread_pool) const;
+ };
+
+ static RaycastOcclusionCull *raycast_singleton;
+
+ static const int TILE_SIZE = 4;
+ static const int TILE_RAYS = TILE_SIZE * TILE_SIZE;
+
+ RTCDevice ebr_device = nullptr;
+ RID_PtrOwner<Occluder> occluder_owner;
+ HashMap<RID, Scenario> scenarios;
+ HashMap<RID, RaycastHZBuffer> buffers;
+ RS::ViewportOcclusionCullingBuildQuality build_quality;
+
+ void _init_embree();
+
+public:
+ virtual bool is_occluder(RID p_rid) override;
+ virtual RID occluder_allocate() override;
+ virtual void occluder_initialize(RID p_occluder) override;
+ virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) override;
+ virtual void free_occluder(RID p_occluder) override;
+
+ virtual void add_scenario(RID p_scenario) override;
+ virtual void remove_scenario(RID p_scenario) override;
+ virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform3D &p_xform, bool p_enabled) override;
+ virtual void scenario_remove_instance(RID p_scenario, RID p_instance) override;
+
+ virtual void add_buffer(RID p_buffer) override;
+ virtual void remove_buffer(RID p_buffer) override;
+ virtual HZBuffer *buffer_get_ptr(RID p_buffer) override;
+ virtual void buffer_set_scenario(RID p_buffer, RID p_scenario) override;
+ virtual void buffer_set_size(RID p_buffer, const Vector2i &p_size) override;
+ virtual void buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) override;
+ virtual RID buffer_get_debug_texture(RID p_buffer) override;
+
+ virtual void set_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) override;
+
+ RaycastOcclusionCull();
+ ~RaycastOcclusionCull();
+};
+
+#endif // OCCLUSION_CULL_RAYCASTER_H
diff --git a/core/os/copymem.h b/modules/raycast/register_types.cpp
index 6fd559356c..78ca91309f 100644
--- a/core/os/copymem.h
+++ b/modules/raycast/register_types.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* copymem.h */
+/* register_types.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,23 +28,22 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COPYMEM_H
-#define COPYMEM_H
+#include "register_types.h"
-#include "core/typedefs.h"
+#include "lightmap_raycaster.h"
+#include "raycast_occlusion_cull.h"
-#ifdef PLATFORM_COPYMEM
-
-#include "platform_copymem.h" // included from platform/<current_platform>/platform_copymem.h"
-
-#else
-
-#include <string.h>
-
-#define copymem(to, from, count) memcpy(to, from, count)
-#define zeromem(to, count) memset(to, 0, count)
-#define movemem(to, from, count) memmove(to, from, count)
+RaycastOcclusionCull *raycast_occlusion_cull = nullptr;
+void register_raycast_types() {
+#ifdef TOOLS_ENABLED
+ LightmapRaycasterEmbree::make_default_raycaster();
#endif
-
-#endif // COPYMEM_H
+ raycast_occlusion_cull = memnew(RaycastOcclusionCull);
+}
+
+void unregister_raycast_types() {
+ if (raycast_occlusion_cull) {
+ memdelete(raycast_occlusion_cull);
+ }
+}
diff --git a/scene/2d/y_sort.h b/modules/raycast/register_types.h
index 7d36ee3391..789604a491 100644
--- a/scene/2d/y_sort.h
+++ b/modules/raycast/register_types.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* y_sort.h */
+/* register_types.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,20 +28,5 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef Y_SORT_H
-#define Y_SORT_H
-
-#include "scene/2d/node_2d.h"
-
-class YSort : public Node2D {
- GDCLASS(YSort, Node2D);
- bool sort_enabled = true;
- static void _bind_methods();
-
-public:
- void set_sort_enabled(bool p_enabled);
- bool is_sort_enabled() const;
- YSort();
-};
-
-#endif // Y_SORT_H
+void register_raycast_types();
+void unregister_raycast_types();
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index b21f5d1e7a..7f5a0dfecb 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RegEx" inherits="Reference" version="4.0">
+<class name="RegEx" inherits="RefCounted" version="4.0">
<brief_description>
Class for searching text for patterns using regular expressions.
</brief_description>
diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml
index a45de60aef..cfe00f83ee 100644
--- a/modules/regex/doc_classes/RegExMatch.xml
+++ b/modules/regex/doc_classes/RegExMatch.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RegExMatch" inherits="Reference" version="4.0">
+<class name="RegExMatch" inherits="RefCounted" version="4.0">
<brief_description>
Contains the results of a [RegEx] search.
</brief_description>
diff --git a/modules/regex/regex.h b/modules/regex/regex.h
index f5773042fb..68fe2bc6e0 100644
--- a/modules/regex/regex.h
+++ b/modules/regex/regex.h
@@ -31,15 +31,15 @@
#ifndef REGEX_H
#define REGEX_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
#include "core/templates/map.h"
#include "core/templates/vector.h"
#include "core/variant/array.h"
#include "core/variant/dictionary.h"
-class RegExMatch : public Reference {
- GDCLASS(RegExMatch, Reference);
+class RegExMatch : public RefCounted {
+ GDCLASS(RegExMatch, RefCounted);
struct Range {
int start = 0;
@@ -68,8 +68,8 @@ public:
int get_end(const Variant &p_name) const;
};
-class RegEx : public Reference {
- GDCLASS(RegEx, Reference);
+class RegEx : public RefCounted {
+ GDCLASS(RegEx, RefCounted);
void *general_ctx;
void *code = nullptr;
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
index 6732078efc..78b4749939 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
@@ -30,7 +30,7 @@
#include "audio_stream_ogg_vorbis.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) {
ERR_FAIL_COND(!active);
@@ -204,7 +204,7 @@ void AudioStreamOGGVorbis::set_data(const Vector<uint8_t> &p_data) {
clear_data();
data = memalloc(src_data_len);
- copymem(data, src_datar, src_data_len);
+ memcpy(data, src_datar, src_data_len);
data_len = src_data_len;
break;
@@ -221,7 +221,7 @@ Vector<uint8_t> AudioStreamOGGVorbis::get_data() const {
vdata.resize(data_len);
{
uint8_t *w = vdata.ptrw();
- copymem(w, data, data_len);
+ memcpy(w, data, data_len);
}
}
diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp
index ec1c30783a..a0de5e5f0f 100644
--- a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp
@@ -30,8 +30,8 @@
#include "resource_importer_ogg_vorbis.h"
+#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
#include "scene/resources/texture.h"
String ResourceImporterOGGVorbis::get_importer_name() const {
@@ -79,7 +79,7 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'.");
- size_t len = f->get_len();
+ uint64_t len = f->get_length();
Vector<uint8_t> data;
data.resize(len);
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index 6ce3e4b4b3..4911346b96 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -140,7 +140,7 @@ Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, const char *p
}
Error ImageLoaderSVG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
- uint32_t size = f->get_len();
+ uint64_t size = f->get_length();
Vector<uint8_t> src_image;
src_image.resize(size + 1);
uint8_t *src_w = src_image.ptrw();
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index e7863f88a3..d06c5c2f14 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -131,7 +131,7 @@ if env["builtin_harfbuzz"]:
]
)
- if env["platform"] == "android" or env["platform"] == "linuxbsd" or env["platform"] == "server":
+ if env["platform"] == "android" or env["platform"] == "linuxbsd":
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
if env["platform"] == "javascript":
@@ -448,7 +448,7 @@ if env["builtin_icu"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- icu_data_name = "icudt68l.dat"
+ icu_data_name = "icudt69l.dat"
if env_icu["tools"]:
env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name)
diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp
index 326af7f0ee..c29aac05bb 100644
--- a/modules/text_server_adv/dynamic_font_adv.cpp
+++ b/modules/text_server_adv/dynamic_font_adv.cpp
@@ -66,7 +66,7 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'.");
}
- size_t len = f->get_len();
+ uint64_t len = f->get_length();
font_mem_cache.resize(len);
f->get_buffer(font_mem_cache.ptrw(), len);
font_mem = font_mem_cache.ptr();
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 8b8b6b7cd3..906ebe4993 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -181,7 +181,7 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
UErrorCode err = U_ZERO_ERROR;
// ICU data found.
- size_t len = f->get_len();
+ uint64_t len = f->get_length();
icu_data = (uint8_t *)memalloc(len);
f->get_buffer(icu_data, len);
f->close();
@@ -2352,24 +2352,22 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
sd->glyphs.push_back(gl);
} else {
Vector<RID> fonts;
- // Push fonts with the language and script support first.
- for (int l = 0; l < span.fonts.size(); l++) {
- if ((font_is_language_supported(span.fonts[l], span.language)) && (font_is_script_supported(span.fonts[l], script))) {
- fonts.push_back(sd->spans[k].fonts[l]);
- }
- }
- // Push fonts with the script support.
- for (int l = 0; l < sd->spans[k].fonts.size(); l++) {
- if (!(font_is_language_supported(span.fonts[l], span.language)) && (font_is_script_supported(span.fonts[l], script))) {
- fonts.push_back(sd->spans[k].fonts[l]);
- }
- }
- // Push the rest valid fonts.
- for (int l = 0; l < sd->spans[k].fonts.size(); l++) {
- if (!(font_is_language_supported(span.fonts[l], span.language)) && !(font_is_script_supported(span.fonts[l], script))) {
- fonts.push_back(sd->spans[k].fonts[l]);
+ Vector<RID> fonts_scr_only;
+ Vector<RID> fonts_no_match;
+ int font_count = span.fonts.size();
+ for (int l = 0; l < font_count; l++) {
+ if (font_is_script_supported(span.fonts[l], script)) {
+ if (font_is_language_supported(span.fonts[l], span.language)) {
+ fonts.push_back(sd->spans[k].fonts[l]);
+ } else {
+ fonts_scr_only.push_back(sd->spans[k].fonts[l]);
+ }
+ } else {
+ fonts_no_match.push_back(sd->spans[k].fonts[l]);
}
}
+ fonts.append_array(fonts_scr_only);
+ fonts.append_array(fonts_no_match);
_shape_run(sd, MAX(sd->spans[k].start, script_run_start), MIN(sd->spans[k].end, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0);
}
}
diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp
index dec1d6f83f..a261ba8f37 100644
--- a/modules/text_server_fb/dynamic_font_fb.cpp
+++ b/modules/text_server_fb/dynamic_font_fb.cpp
@@ -65,7 +65,7 @@ DynamicFontDataFallback::DataAtSize *DynamicFontDataFallback::get_data_for_size(
ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'.");
}
- size_t len = f->get_len();
+ uint64_t len = f->get_length();
font_mem_cache.resize(len);
f->get_buffer(font_mem_cache.ptrw(), len);
font_mem = font_mem_cache.ptr();
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 98a67ef309..a22559efdd 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -634,17 +634,17 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te
span.start = sd->text.length();
span.end = span.start + p_text.length();
// Pre-sort fonts, push fonts with the language support first.
- for (int i = 0; i < p_fonts.size(); i++) {
+ Vector<RID> fonts_no_match;
+ int font_count = p_fonts.size();
+ for (int i = 0; i < font_count; i++) {
if (font_is_language_supported(p_fonts[i], p_language)) {
span.fonts.push_back(p_fonts[i]);
+ } else {
+ fonts_no_match.push_back(p_fonts[i]);
}
}
- // Push the rest valid fonts.
- for (int i = 0; i < p_fonts.size(); i++) {
- if (!font_is_language_supported(p_fonts[i], p_language)) {
- span.fonts.push_back(p_fonts[i]);
- }
- }
+ span.fonts.append_array(fonts_no_match);
+
ERR_FAIL_COND_V(span.fonts.is_empty(), false);
span.font_size = p_size;
span.language = p_language;
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index ef53661557..6eaa2d24a8 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -35,7 +35,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size) {
+Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size, size_t p_input_size) {
Error error;
Vector<uint8_t> pixels;
@@ -56,11 +56,14 @@ Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t
compressed_pos += 1;
count = (c & 0x7f) + 1;
- if (output_pos + count * p_pixel_size > output_pos) {
+ if (output_pos + count * p_pixel_size > p_output_size) {
return ERR_PARSE_ERROR;
}
if (c & 0x80) {
+ if (compressed_pos + p_pixel_size > p_input_size) {
+ return ERR_PARSE_ERROR;
+ }
for (size_t i = 0; i < p_pixel_size; i++) {
pixels_w[i] = p_compressed_buffer[compressed_pos];
compressed_pos += 1;
@@ -72,6 +75,9 @@ Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t
output_pos += p_pixel_size;
}
} else {
+ if (compressed_pos + count * p_pixel_size > p_input_size) {
+ return ERR_PARSE_ERROR;
+ }
count *= p_pixel_size;
for (size_t i = 0; i < count; i++) {
p_uncompressed_buffer[output_pos] = p_compressed_buffer[compressed_pos];
@@ -83,7 +89,7 @@ Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t
return OK;
}
-Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_output_size) {
+Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size) {
#define TGA_PUT_PIXEL(r, g, b, a) \
int image_data_ofs = ((y * width) + x); \
image_data_w[image_data_ofs * 4 + 0] = r; \
@@ -134,7 +140,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
if (p_is_monochrome) {
while (y != y_end) {
while (x != x_end) {
- if (i > p_output_size) {
+ if (i >= p_input_size) {
return ERR_PARSE_ERROR;
}
uint8_t shade = p_buffer[i];
@@ -150,7 +156,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
} else {
while (y != y_end) {
while (x != x_end) {
- if (i > p_output_size) {
+ if (i >= p_input_size) {
return ERR_PARSE_ERROR;
}
uint8_t index = p_buffer[i];
@@ -181,7 +187,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
} else if (p_header.pixel_depth == 24) {
while (y != y_end) {
while (x != x_end) {
- if (i + 2 > p_output_size) {
+ if (i + 2 >= p_input_size) {
return ERR_PARSE_ERROR;
}
@@ -200,7 +206,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
} else if (p_header.pixel_depth == 32) {
while (y != y_end) {
while (x != x_end) {
- if (i + 3 > p_output_size) {
+ if (i + 3 >= p_input_size) {
return ERR_PARSE_ERROR;
}
@@ -226,9 +232,9 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
- int src_image_len = f->get_len();
+ uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
- ERR_FAIL_COND_V(src_image_len < (int)sizeof(tga_header_s), ERR_FILE_CORRUPT);
+ ERR_FAIL_COND_V(src_image_len < (int64_t)sizeof(tga_header_s), ERR_FILE_CORRUPT);
src_image.resize(src_image_len);
Error err = OK;
@@ -307,7 +313,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
const uint8_t *buffer = nullptr;
if (is_encoded) {
- err = decode_tga_rle(src_image_r, pixel_size, uncompressed_buffer_w, buffer_size);
+ err = decode_tga_rle(src_image_r, pixel_size, uncompressed_buffer_w, buffer_size, src_image_len);
if (err == OK) {
uncompressed_buffer_r = uncompressed_buffer.ptr();
diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h
index cb2ce07edd..e4463a322f 100644
--- a/modules/tga/image_loader_tga.h
+++ b/modules/tga/image_loader_tga.h
@@ -72,8 +72,8 @@ class ImageLoaderTGA : public ImageFormatLoader {
uint8_t pixel_depth = 0;
uint8_t image_descriptor = 0;
};
- static Error decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size);
- static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_output_size);
+ static Error decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size, size_t p_input_size);
+ static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size);
public:
virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 19f26c87cd..4400445f30 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -58,7 +58,7 @@ int VideoStreamPlaybackTheora::buffer_data() {
#else
- int bytes = file->get_buffer((uint8_t *)buffer, 4096);
+ uint64_t bytes = file->get_buffer((uint8_t *)buffer, 4096);
ogg_sync_wrote(&oy, bytes);
return (bytes);
@@ -176,7 +176,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
thread_eof = false;
//pre-fill buffer
int to_read = ring_buffer.space_left();
- int read = file->get_buffer(read_buffer.ptr(), to_read);
+ uint64_t read = file->get_buffer(read_buffer.ptr(), to_read);
ring_buffer.write(read_buffer.ptr(), read);
thread.start(_streaming_thread, this);
@@ -225,7 +225,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
/* identify the codec: try theora */
if (!theora_p && th_decode_headerin(&ti, &tc, &ts, &op) >= 0) {
/* it is theora */
- copymem(&to, &test, sizeof(test));
+ memcpy(&to, &test, sizeof(test));
theora_p = 1;
} else if (!vorbis_p && vorbis_synthesis_headerin(&vi, &vc, &op) >= 0) {
/* it is vorbis */
@@ -238,7 +238,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
audio_track_skip--;
} else {
- copymem(&vo, &test, sizeof(test));
+ memcpy(&vo, &test, sizeof(test));
vorbis_p = 1;
}
} else {
@@ -302,7 +302,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
}
}
- /* and now we have it all. initialize decoders */
+ /* And now we have it all. Initialize decoders. */
if (theora_p) {
td = th_decode_alloc(&ti, ts);
px_fmt = ti.pixel_fmt;
@@ -484,10 +484,10 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
//printf("frame time %f, play time %f, ready %i\n", (float)videobuf_time, get_time(), videobuf_ready);
- /* is it already too old to be useful? This is only actually
- useful cosmetically after a SIGSTOP. Note that we have to
+ /* is it already too old to be useful? This is only actually
+ useful cosmetically after a SIGSTOP. Note that we have to
decode the frame even if we don't show it (for now) due to
- keyframing. Soon enough libtheora will be able to deal
+ keyframing. Soon enough libtheora will be able to deal
with non-keyframe seeks. */
if (videobuf_time >= get_time()) {
@@ -632,8 +632,8 @@ void VideoStreamPlaybackTheora::_streaming_thread(void *ud) {
//just fill back the buffer
if (!vs->thread_eof) {
int to_read = vs->ring_buffer.space_left();
- if (to_read) {
- int read = vs->file->get_buffer(vs->read_buffer.ptr(), to_read);
+ if (to_read > 0) {
+ uint64_t read = vs->file->get_buffer(vs->read_buffer.ptr(), to_read);
vs->ring_buffer.write(vs->read_buffer.ptr(), read);
vs->thread_eof = vs->file->eof_reached();
}
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index 2685a8a013..760173d0df 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -31,8 +31,8 @@
#ifndef VIDEO_STREAM_THEORA_H
#define VIDEO_STREAM_THEORA_H
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
-#include "core/os/file_access.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
#include "core/templates/ring_buffer.h"
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index 47214e6974..eb7a8597e6 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -37,7 +37,7 @@
Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
- int src_image_len = f->get_len();
+ uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
src_image.resize(src_image_len);
diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp
index f747763248..6a2fb0f666 100644
--- a/modules/tinyexr/image_saver_tinyexr.cpp
+++ b/modules/tinyexr/image_saver_tinyexr.cpp
@@ -169,7 +169,7 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
{ 0 }, // R
{ 1, 0 }, // GR
{ 2, 1, 0 }, // BGR
- { 2, 1, 0, 3 } // BGRA
+ { 3, 2, 1, 0 } // ABGR
};
int channel_count = get_channel_count(format);
diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml
index 785c8dad50..09a2c8a88c 100644
--- a/modules/upnp/doc_classes/UPNP.xml
+++ b/modules/upnp/doc_classes/UPNP.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="UPNP" inherits="Reference" version="4.0">
+<class name="UPNP" inherits="RefCounted" version="4.0">
<brief_description>
UPNP network functions.
</brief_description>
diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml
index f3b96bb89d..f7b5386d86 100644
--- a/modules/upnp/doc_classes/UPNPDevice.xml
+++ b/modules/upnp/doc_classes/UPNPDevice.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="UPNPDevice" inherits="Reference" version="4.0">
+<class name="UPNPDevice" inherits="RefCounted" version="4.0">
<brief_description>
UPNP device.
</brief_description>
diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h
index a0cca96bc8..b961a9667f 100644
--- a/modules/upnp/upnp.h
+++ b/modules/upnp/upnp.h
@@ -31,14 +31,14 @@
#ifndef GODOT_UPNP_H
#define GODOT_UPNP_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "upnp_device.h"
#include <miniupnpc/miniupnpc.h>
-class UPNP : public Reference {
- GDCLASS(UPNP, Reference);
+class UPNP : public RefCounted {
+ GDCLASS(UPNP, RefCounted);
private:
String discover_multicast_if = "";
diff --git a/modules/upnp/upnp_device.h b/modules/upnp/upnp_device.h
index 126e761a56..0a66c36ab9 100644
--- a/modules/upnp/upnp_device.h
+++ b/modules/upnp/upnp_device.h
@@ -31,10 +31,10 @@
#ifndef GODOT_UPNP_DEVICE_H
#define GODOT_UPNP_DEVICE_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
-class UPNPDevice : public Reference {
- GDCLASS(UPNPDevice, Reference);
+class UPNPDevice : public RefCounted {
+ GDCLASS(UPNPDevice, RefCounted);
public:
enum IGDStatus {
diff --git a/modules/vhacd/config.py b/modules/vhacd/config.py
index d22f9454ed..a42f27fbe1 100644
--- a/modules/vhacd/config.py
+++ b/modules/vhacd/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return True
+ return not env["disable_3d"]
def configure(env):
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
index 5112ea43a7..0798375a96 100644
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ b/modules/visual_script/doc_classes/VisualScript.xml
@@ -4,7 +4,7 @@
A script implemented in the Visual Script programming environment.
</brief_description>
<description>
- A script implemented in the Visual Script programming environment. The script extends the functionality of all objects that instance it.
+ A script implemented in the Visual Script programming environment. The script extends the functionality of all objects that instance it.
[method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
You are most likely to use this class via the Visual Script editor or when writing plugins for it.
</description>
diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
index de5d731cc0..d6b96957f5 100644
--- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
@@ -15,10 +15,10 @@
<methods>
</methods>
<members>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@&quot;Object&quot;">
+ <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
The constant's parent class.
</member>
- <member name="constant" type="StringName" setter="set_class_constant" getter="get_class_constant" default="@&quot;&quot;">
+ <member name="constant" type="StringName" setter="set_class_constant" getter="get_class_constant" default="&amp;&quot;&quot;">
The constant to return. See the given class for its available constants.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
index 5c9c8d3eca..df3121d093 100644
--- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
@@ -15,7 +15,7 @@
<methods>
</methods>
<members>
- <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="@&quot;&quot;">
+ <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&amp;&quot;&quot;">
The signal to emit.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
index 2d0fac1fa0..48104afcf7 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
@@ -11,13 +11,13 @@
<members>
<member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
</member>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@&quot;Object&quot;">
+ <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
</member>
<member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type">
</member>
<member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptFunctionCall.CallMode" default="0">
</member>
- <member name="function" type="StringName" setter="set_function" getter="get_function" default="@&quot;&quot;">
+ <member name="function" type="StringName" setter="set_function" getter="get_function" default="&amp;&quot;&quot;">
</member>
<member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
</member>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
index 68083614a6..9ed71bf10e 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptFunctionState" inherits="Reference" version="4.0">
+<class name="VisualScriptFunctionState" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
@@ -28,7 +28,7 @@
<method name="resume">
<return type="Variant">
</return>
- <argument index="0" name="args" type="Array" default="null">
+ <argument index="0" name="args" type="Array" default="[ ]">
</argument>
<description>
</description>
diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
index 6c296fdb4b..9ca67feacb 100644
--- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml
+++ b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
@@ -9,7 +9,7 @@
<methods>
</methods>
<members>
- <member name="action" type="StringName" setter="set_action_name" getter="get_action_name" default="@&quot;&quot;">
+ <member name="action" type="StringName" setter="set_action_name" getter="get_action_name" default="&amp;&quot;&quot;">
</member>
<member name="mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="VisualScriptInputAction.Mode" default="0">
</member>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
index c3741eea89..185f0f1ffb 100644
--- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
@@ -18,7 +18,7 @@
<member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0">
The local variable's type.
</member>
- <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="@&quot;new_local&quot;">
+ <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="&amp;&quot;new_local&quot;">
The local variable's name.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
index 619bbb90ca..865f0153c9 100644
--- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
@@ -20,7 +20,7 @@
<member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0">
The local variable's type.
</member>
- <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="@&quot;new_local&quot;">
+ <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="&amp;&quot;new_local&quot;">
The local variable's name.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
index 1c22070ab1..ff6c723a3e 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
@@ -11,7 +11,7 @@
<members>
<member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
</member>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@&quot;Object&quot;">
+ <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
</member>
<member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type">
</member>
@@ -19,7 +19,7 @@
</member>
<member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
</member>
- <member name="property" type="StringName" setter="set_property" getter="get_property" default="@&quot;&quot;">
+ <member name="property" type="StringName" setter="set_property" getter="get_property" default="&amp;&quot;&quot;">
</member>
<member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertyGet.CallMode" default="0">
</member>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
index 629576e261..71bfc4c8a5 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
@@ -13,7 +13,7 @@
</member>
<member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
</member>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@&quot;Object&quot;">
+ <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
</member>
<member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type">
</member>
@@ -21,7 +21,7 @@
</member>
<member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
</member>
- <member name="property" type="StringName" setter="set_property" getter="get_property" default="@&quot;&quot;">
+ <member name="property" type="StringName" setter="set_property" getter="get_property" default="&amp;&quot;&quot;">
</member>
<member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertySet.CallMode" default="0">
</member>
diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
index 80a8d31041..9e3e020f2d 100644
--- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
+++ b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
@@ -11,7 +11,7 @@
<members>
<member name="base_script" type="String" setter="set_base_script" getter="get_base_script" default="&quot;&quot;">
</member>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@&quot;Object&quot;">
+ <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
</member>
</members>
<constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
index d182e14e4d..df20ac53f2 100644
--- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
@@ -15,7 +15,7 @@
<methods>
</methods>
<members>
- <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="@&quot;&quot;">
+ <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&amp;&quot;&quot;">
The variable's name.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
index 3bd392dd85..eb8ebbe338 100644
--- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
@@ -16,7 +16,7 @@
<methods>
</methods>
<members>
- <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="@&quot;&quot;">
+ <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&amp;&quot;&quot;">
The variable's name.
</member>
</members>
diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
index 483cdfeaf8..c59234433f 100644
--- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
+++ b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
@@ -9,13 +9,13 @@
<methods>
</methods>
<members>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@&quot;Object&quot;">
+ <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
</member>
<member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptYieldSignal.CallMode" default="0">
</member>
<member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
</member>
- <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="@&quot;&quot;">
+ <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&amp;&quot;&quot;">
</member>
</members>
<constants>
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 6d5fff88d9..7badb1b717 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -954,60 +954,10 @@ bool VisualScript::are_subnodes_edited() const {
}
#endif
-Vector<ScriptNetData> VisualScript::get_rpc_methods() const {
+const Vector<MultiplayerAPI::RPCConfig> VisualScript::get_rpc_methods() const {
return rpc_functions;
}
-uint16_t VisualScript::get_rpc_method_id(const StringName &p_method) const {
- for (int i = 0; i < rpc_functions.size(); i++) {
- if (rpc_functions[i].name == p_method) {
- return i;
- }
- }
- return UINT16_MAX;
-}
-
-StringName VisualScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
- ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName());
- return rpc_functions[p_rpc_method_id].name;
-}
-
-MultiplayerAPI::RPCMode VisualScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
- ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
- return rpc_functions[p_rpc_method_id].mode;
-}
-
-MultiplayerAPI::RPCMode VisualScript::get_rpc_mode(const StringName &p_method) const {
- return get_rpc_mode_by_id(get_rpc_method_id(p_method));
-}
-
-Vector<ScriptNetData> VisualScript::get_rset_properties() const {
- return rpc_variables;
-}
-
-uint16_t VisualScript::get_rset_property_id(const StringName &p_variable) const {
- for (int i = 0; i < rpc_variables.size(); i++) {
- if (rpc_variables[i].name == p_variable) {
- return i;
- }
- }
- return UINT16_MAX;
-}
-
-StringName VisualScript::get_rset_property(const uint16_t p_rset_property_id) const {
- ERR_FAIL_COND_V(p_rset_property_id >= rpc_variables.size(), StringName());
- return rpc_variables[p_rset_property_id].name;
-}
-
-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_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 {
- return get_rset_mode_by_id(get_rset_property_id(p_variable));
-}
-
void VisualScript::_set_data(const Dictionary &p_data) {
Dictionary d = p_data;
if (d.has("base_type")) {
@@ -1065,7 +1015,6 @@ void VisualScript::_set_data(const Dictionary &p_data) {
// Takes all the rpc methods.
rpc_functions.clear();
- rpc_variables.clear();
List<StringName> fns;
functions.get_key_list(&fns);
for (const List<StringName>::Element *E = fns.front(); E; E = E->next()) {
@@ -1073,9 +1022,10 @@ void VisualScript::_set_data(const Dictionary &p_data) {
Ref<VisualScriptFunction> vsf = nodes[functions[E->get()].func_id].node;
if (vsf.is_valid()) {
if (vsf->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
- ScriptNetData nd;
+ MultiplayerAPI::RPCConfig nd;
nd.name = E->get();
- nd.mode = vsf->get_rpc_mode();
+ nd.rpc_mode = vsf->get_rpc_mode();
+ nd.transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE; // TODO
if (rpc_functions.find(nd) == -1) {
rpc_functions.push_back(nd);
}
@@ -1085,7 +1035,7 @@ void VisualScript::_set_data(const Dictionary &p_data) {
}
// Sort so we are 100% that they are always the same.
- rpc_functions.sort_custom<SortNetData>();
+ rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>();
}
Dictionary VisualScript::_get_data() const {
@@ -1537,7 +1487,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
state->flow_stack_pos = flow_stack_pos;
state->stack.resize(p_stack_size);
state->pass = p_pass;
- copymem(state->stack.ptrw(), p_stack, p_stack_size);
+ memcpy(state->stack.ptrw(), p_stack, p_stack_size);
// Step 2, run away, return directly.
r_error.error = Callable::CallError::CALL_OK;
@@ -1607,7 +1557,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
}
next = node->sequence_outputs[output];
- VSDEBUG("GOT NEXT NODE - " + (next ? itos(next->get_id()) : "NULL"));
+ VSDEBUG("GOT NEXT NODE - " + (next ? itos(next->get_id()) : "Null"));
}
if (flow_stack) {
@@ -1802,7 +1752,7 @@ Variant VisualScriptInstance::call(const StringName &p_method, const Variant **p
sequence_bits[i] = false; // All starts as false.
}
- zeromem(pass_stack, f->pass_stack_size * sizeof(int));
+ memset(pass_stack, 0, f->pass_stack_size * sizeof(int));
Map<int, VisualScriptNodeInstance *>::Element *E = instances.find(f->node);
if (!E) {
@@ -1882,46 +1832,10 @@ Ref<Script> VisualScriptInstance::get_script() const {
return script;
}
-Vector<ScriptNetData> VisualScriptInstance::get_rpc_methods() const {
+const Vector<MultiplayerAPI::RPCConfig> VisualScriptInstance::get_rpc_methods() const {
return script->get_rpc_methods();
}
-uint16_t VisualScriptInstance::get_rpc_method_id(const StringName &p_method) const {
- return script->get_rpc_method_id(p_method);
-}
-
-StringName VisualScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const {
- return script->get_rpc_method(p_rpc_method_id);
-}
-
-MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
- return script->get_rpc_mode_by_id(p_rpc_method_id);
-}
-
-MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode(const StringName &p_method) const {
- return script->get_rpc_mode(p_method);
-}
-
-Vector<ScriptNetData> VisualScriptInstance::get_rset_properties() const {
- return script->get_rset_properties();
-}
-
-uint16_t VisualScriptInstance::get_rset_property_id(const StringName &p_variable) const {
- return script->get_rset_property_id(p_variable);
-}
-
-StringName VisualScriptInstance::get_rset_property(const uint16_t p_rset_property_id) const {
- return script->get_rset_property(p_rset_property_id);
-}
-
-MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_variable_id) const {
- return script->get_rset_mode_by_id(p_rset_variable_id);
-}
-
-MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode(const StringName &p_variable) const {
- return script->get_rset_mode(p_variable);
-}
-
void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_owner) {
script = p_script;
owner = p_owner;
@@ -2290,7 +2204,7 @@ Variant VisualScriptFunctionState::resume(Array p_args) {
void VisualScriptFunctionState::_bind_methods() {
ClassDB::bind_method(D_METHOD("connect_to_signal", "obj", "signals", "args"), &VisualScriptFunctionState::connect_to_signal);
- ClassDB::bind_method(D_METHOD("resume", "args"), &VisualScriptFunctionState::resume, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("resume", "args"), &VisualScriptFunctionState::resume, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("is_valid"), &VisualScriptFunctionState::is_valid);
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &VisualScriptFunctionState::_signal_callback, MethodInfo("_signal_callback"));
}
@@ -2336,6 +2250,10 @@ void VisualScriptLanguage::finish() {
void VisualScriptLanguage::get_reserved_words(List<String> *p_words) const {
}
+bool VisualScriptLanguage::is_control_flow_keyword(String p_keyword) const {
+ return false;
+}
+
void VisualScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
}
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index 72362e0ef4..438ec99a56 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -234,8 +234,7 @@ private:
HashMap<StringName, Function> functions;
HashMap<StringName, Variable> variables;
Map<StringName, Vector<Argument>> custom_signals;
- Vector<ScriptNetData> rpc_functions;
- Vector<ScriptNetData> rpc_variables;
+ Vector<MultiplayerAPI::RPCConfig> rpc_functions;
Map<Object *, VisualScriptInstance *> instances;
@@ -363,17 +362,7 @@ public:
virtual int get_member_line(const StringName &p_member) const override;
- virtual Vector<ScriptNetData> get_rpc_methods() const override;
- virtual uint16_t get_rpc_method_id(const StringName &p_method) const override;
- virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override;
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override;
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override;
-
- virtual Vector<ScriptNetData> get_rset_properties() const override;
- virtual uint16_t get_rset_property_id(const StringName &p_property) const override;
- virtual StringName get_rset_property(const uint16_t p_rset_property_id) const override;
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const override;
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override;
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override;
#ifdef TOOLS_ENABLED
virtual bool are_subnodes_edited() const;
@@ -454,24 +443,14 @@ public:
virtual ScriptLanguage *get_language();
- virtual Vector<ScriptNetData> get_rpc_methods() const;
- virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
- virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const;
- virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
- virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
-
- virtual Vector<ScriptNetData> get_rset_properties() const;
- virtual uint16_t get_rset_property_id(const StringName &p_property) const;
- virtual StringName get_rset_property(const uint16_t p_rset_property_id) const;
- virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
- virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
+ virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const;
VisualScriptInstance();
~VisualScriptInstance();
};
-class VisualScriptFunctionState : public Reference {
- GDCLASS(VisualScriptFunctionState, Reference);
+class VisualScriptFunctionState : public RefCounted {
+ GDCLASS(VisualScriptFunctionState, RefCounted);
friend class VisualScriptInstance;
ObjectID instance_id;
@@ -586,6 +565,7 @@ public:
/* EDITOR FUNCTIONS */
virtual void get_reserved_words(List<String> *p_words) const;
+ virtual bool is_control_flow_keyword(String p_keyword) const;
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;
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 7ca14fbca8..a3133f126d 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -33,7 +33,7 @@
#include "core/io/marshalls.h"
#include "core/math/math_funcs.h"
#include "core/object/class_db.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/os/os.h"
#include "core/variant/variant_parser.h"
@@ -132,6 +132,7 @@ bool VisualScriptBuiltinFunc::has_input_sequence_port() const {
case TEXT_PRINT:
case TEXT_PRINTERR:
case TEXT_PRINTRAW:
+ case MATH_SEED:
return true;
default:
return false;
@@ -723,7 +724,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
case VisualScriptBuiltinFunc::MATH_POSMOD: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- *r_return = Math::posmod((int)*p_inputs[0], (int)*p_inputs[1]);
+ *r_return = Math::posmod((int64_t)*p_inputs[0], (int64_t)*p_inputs[1]);
} break;
case VisualScriptBuiltinFunc::MATH_FLOOR: {
VALIDATE_ARG_NUM(0);
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 02ec9ccd06..96f103f95a 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -381,7 +381,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
case Variant::PLANE:
color = Color(0.97, 0.44, 0.44);
break;
- case Variant::QUAT:
+ case Variant::QUATERNION:
color = Color(0.93, 0.41, 0.64);
break;
case Variant::AABB:
@@ -390,7 +390,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
case Variant::BASIS:
color = Color(0.89, 0.93, 0.41);
break;
- case Variant::TRANSFORM:
+ case Variant::TRANSFORM3D:
color = Color(0.96, 0.66, 0.43);
break;
@@ -487,7 +487,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
case Variant::PLANE:
color = Color(0.97, 0.44, 0.44);
break;
- case Variant::QUAT:
+ case Variant::QUATERNION:
color = Color(0.93, 0.41, 0.64);
break;
case Variant::AABB:
@@ -496,7 +496,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
case Variant::BASIS:
color = Color(0.7, 0.73, 0.1);
break;
- case Variant::TRANSFORM:
+ case Variant::TRANSFORM3D:
color = Color(0.96, 0.56, 0.28);
break;
@@ -624,10 +624,10 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
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("Quaternion", "EditorIcons"),
Control::get_theme_icon("AABB", "EditorIcons"),
Control::get_theme_icon("Basis", "EditorIcons"),
- Control::get_theme_icon("Transform", "EditorIcons"),
+ Control::get_theme_icon("Transform3D", "EditorIcons"),
Control::get_theme_icon("Color", "EditorIcons"),
Control::get_theme_icon("NodePath", "EditorIcons"),
Control::get_theme_icon("RID", "EditorIcons"),
@@ -739,22 +739,10 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
}
Color c = sbf->get_border_color();
+ c = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0, 0.85) : Color(0.0, 0.0, 0.0, 0.85);
Color ic = c;
- c.a = 1;
- if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
- Color mono_color;
- if (((c.r + c.g + c.b) / 3) < 0.7) {
- mono_color = Color(1.0, 1.0, 1.0);
- ic = Color(0.0, 0.0, 0.0, 0.7);
- } else {
- mono_color = Color(0.0, 0.0, 0.0);
- ic = Color(1.0, 1.0, 1.0, 0.7);
- }
- mono_color.a = 0.85;
- c = mono_color;
- }
gnode->add_theme_color_override("title_color", c);
- c.a = 0.7;
+ c.a = 1;
gnode->add_theme_color_override("close_color", c);
gnode->add_theme_color_override("resizer_color", ic);
gnode->add_theme_style_override("frame", sbf);
@@ -1087,10 +1075,10 @@ void VisualScriptEditor::_update_members() {
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("Quaternion", "EditorIcons"),
Control::get_theme_icon("AABB", "EditorIcons"),
Control::get_theme_icon("Basis", "EditorIcons"),
- Control::get_theme_icon("Transform", "EditorIcons"),
+ Control::get_theme_icon("Transform3D", "EditorIcons"),
Control::get_theme_icon("Color", "EditorIcons"),
Control::get_theme_icon("NodePath", "EditorIcons"),
Control::get_theme_icon("RID", "EditorIcons"),
@@ -1181,11 +1169,11 @@ void VisualScriptEditor::_member_selected() {
selected = ti->get_metadata(0);
- if (ti->get_parent() == members->get_root()->get_children()) {
+ if (ti->get_parent() == members->get_root()->get_first_child()) {
#ifdef OSX_ENABLED
bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_META);
#else
- bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
#endif
if (held_ctrl) {
ERR_FAIL_COND(!script->has_function(selected));
@@ -1227,7 +1215,7 @@ void VisualScriptEditor::_member_edited() {
TreeItem *root = members->get_root();
- if (ti->get_parent() == root->get_children()) {
+ if (ti->get_parent() == root->get_first_child()) {
selected = new_name;
int node_id = script->get_function_node_id(name);
@@ -1268,7 +1256,7 @@ void VisualScriptEditor::_member_edited() {
return; // Or crash because it will become invalid.
}
- if (ti->get_parent() == root->get_children()->get_next()) {
+ if (ti->get_parent() == root->get_first_child()->get_next()) {
selected = new_name;
undo_redo->create_action(TTR("Rename Variable"));
undo_redo->add_do_method(script.ptr(), "rename_variable", name, new_name);
@@ -1284,7 +1272,7 @@ void VisualScriptEditor::_member_edited() {
return; // Or crash because it will become invalid.
}
- if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
+ if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {
selected = new_name;
undo_redo->create_action(TTR("Rename Signal"));
undo_redo->add_do_method(script.ptr(), "rename_custom_signal", name, new_name);
@@ -1418,7 +1406,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
if (ti->get_parent() == root) {
//main buttons
- if (ti == root->get_children()) {
+ if (ti == root->get_first_child()) {
// Add function, this one uses menu.
if (p_button == 1) {
@@ -1455,7 +1443,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
return; // Or crash because it will become invalid.
}
- if (ti == root->get_children()->get_next()) {
+ if (ti == root->get_first_child()->get_next()) {
// Add variable.
String name = _validate_name("new_variable");
selected = name;
@@ -1471,7 +1459,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
return; // Or crash because it will become invalid.
}
- if (ti == root->get_children()->get_next()->get_next()) {
+ if (ti == root->get_first_child()->get_next()->get_next()) {
// Add variable.
String name = _validate_name("new_signal");
selected = name;
@@ -1486,7 +1474,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
undo_redo->commit_action();
return; // Or crash because it will become invalid.
}
- } else if (ti->get_parent() == root->get_children()) {
+ } else if (ti->get_parent() == root->get_first_child()) {
selected = ti->get_text(0);
function_name_edit->set_position(Input::get_singleton()->get_mouse_position() - Vector2(60, -10));
function_name_edit->popup();
@@ -1854,18 +1842,18 @@ void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
TreeItem *ti = members->get_selected();
if (ti) {
TreeItem *root = members->get_root();
- if (ti->get_parent() == root->get_children()) {
+ if (ti->get_parent() == root->get_first_child()) {
member_type = MEMBER_FUNCTION;
}
- if (ti->get_parent() == root->get_children()->get_next()) {
+ if (ti->get_parent() == root->get_first_child()->get_next()) {
member_type = MEMBER_VARIABLE;
}
- if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
+ if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {
member_type = MEMBER_SIGNAL;
}
member_name = ti->get_text(0);
}
- if (ED_IS_SHORTCUT("visual_script_editor/delete_selected", p_event)) {
+ if (ED_IS_SHORTCUT("ui_graph_delete", p_event)) {
_member_option(MEMBER_REMOVE);
}
if (ED_IS_SHORTCUT("visual_script_editor/edit_member", p_event)) {
@@ -1875,9 +1863,9 @@ void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> btn = p_event;
- if (btn.is_valid() && btn->is_doubleclick()) {
+ if (btn.is_valid() && btn->is_double_click()) {
TreeItem *ti = members->get_selected();
- if (ti && ti->get_parent() == members->get_root()->get_children()) { // to check if it's a function
+ if (ti && ti->get_parent() == members->get_root()->get_first_child()) { // to check if it's a function
_center_on_node(script->get_function_node_id(ti->get_metadata(0)));
}
}
@@ -1959,13 +1947,13 @@ Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f
Dictionary dd;
TreeItem *root = members->get_root();
- if (it->get_parent() == root->get_children()) {
+ if (it->get_parent() == root->get_first_child()) {
dd["type"] = "visual_script_function_drag";
dd["function"] = type;
- } else if (it->get_parent() == root->get_children()->get_next()) {
+ } else if (it->get_parent() == root->get_first_child()->get_next()) {
dd["type"] = "visual_script_variable_drag";
dd["variable"] = type;
- } else if (it->get_parent() == root->get_children()->get_next()->get_next()) {
+ } else if (it->get_parent() == root->get_first_child()->get_next()->get_next()) {
dd["type"] = "visual_script_signal_drag";
dd["signal"] = type;
@@ -2083,7 +2071,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
#ifdef OSX_ENABLED
bool use_set = Input::get_singleton()->is_key_pressed(KEY_META);
#else
- bool use_set = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool use_set = Input::get_singleton()->is_key_pressed(KEY_CTRL);
#endif
Vector2 ofs = graph->get_scroll_ofs() + p_point;
if (graph->is_using_snap()) {
@@ -2271,7 +2259,7 @@ 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);
#else
- bool use_node = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool use_node = Input::get_singleton()->is_key_pressed(KEY_CTRL);
#endif
Array nodes = d["nodes"];
@@ -2354,7 +2342,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
#ifdef OSX_ENABLED
bool use_get = Input::get_singleton()->is_key_pressed(KEY_META);
#else
- bool use_get = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool use_get = Input::get_singleton()->is_key_pressed(KEY_CTRL);
#endif
if (!node || Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
@@ -2723,6 +2711,10 @@ void VisualScriptEditor::set_debugger_active(bool p_active) {
}
}
+Control *VisualScriptEditor::get_base_editor() const {
+ return graph;
+}
+
void VisualScriptEditor::set_tooltip_request_func(String p_method, Object *p_obj) {
}
@@ -3623,32 +3615,33 @@ void VisualScriptEditor::_notification(int p_what) {
bool dark_theme = tm->get_constant("dark_theme", "Editor");
- 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)));
- colors.push_back(Pair<String, Color>("data", Color(0.5, 0.96, 0.81)));
- colors.push_back(Pair<String, Color>("operators", Color(0.67, 0.59, 0.87)));
- colors.push_back(Pair<String, Color>("custom", Color(0.5, 0.73, 0.96)));
- colors.push_back(Pair<String, Color>("constants", Color(0.96, 0.5, 0.69)));
+ node_colors["flow_control"] = Color(0.96, 0.96, 0.96);
+ node_colors["functions"] = Color(0.96, 0.52, 0.51);
+ node_colors["data"] = Color(0.5, 0.96, 0.81);
+ node_colors["operators"] = Color(0.67, 0.59, 0.87);
+ node_colors["custom"] = Color(0.5, 0.73, 0.96);
+ node_colors["constants"] = Color(0.96, 0.5, 0.69);
} else {
- colors.push_back(Pair<String, Color>("flow_control", Color(0.26, 0.26, 0.26)));
- colors.push_back(Pair<String, Color>("functions", Color(0.95, 0.4, 0.38)));
- colors.push_back(Pair<String, Color>("data", Color(0.07, 0.73, 0.51)));
- colors.push_back(Pair<String, Color>("operators", Color(0.51, 0.4, 0.82)));
- colors.push_back(Pair<String, Color>("custom", Color(0.31, 0.63, 0.95)));
- colors.push_back(Pair<String, Color>("constants", Color(0.94, 0.18, 0.49)));
+ node_colors["flow_control"] = Color(0.26, 0.26, 0.26);
+ node_colors["functions"] = Color(0.95, 0.4, 0.38);
+ node_colors["data"] = Color(0.07, 0.73, 0.51);
+ node_colors["operators"] = Color(0.51, 0.4, 0.82);
+ node_colors["custom"] = Color(0.31, 0.63, 0.95);
+ node_colors["constants"] = Color(0.94, 0.18, 0.49);
}
- for (List<Pair<String, Color>>::Element *E = colors.front(); E; E = E->next()) {
- Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode");
+ for (Map<StringName, Color>::Element *E = node_colors.front(); E; E = E->next()) {
+ const Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode");
+
if (!sb.is_null()) {
Ref<StyleBoxFlat> frame_style = sb->duplicate();
- Color c = sb->get_border_color();
- Color cn = E->get().second;
- cn.a = c.a;
- frame_style->set_border_color(cn);
- node_styles[E->get().first] = frame_style;
+ // Adjust the border color to be close to the GraphNode's background color.
+ // This keeps the node's title area from being too distracting.
+ Color color = dark_theme ? E->get().darkened(0.75) : E->get().lightened(0.75);
+ color.a = 0.9;
+ frame_style->set_border_color(color);
+ node_styles[E->key()] = frame_style;
}
}
@@ -4123,32 +4116,32 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
Ref<Texture2D> edit_icon = Control::get_theme_icon("Edit", "EditorIcons");
- if (ti->get_parent() == root->get_children()) {
+ if (ti->get_parent() == root->get_first_child()) {
member_type = MEMBER_FUNCTION;
member_name = ti->get_text(0);
member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
member_popup->add_separator();
- member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE);
+ member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE);
member_popup->popup();
return;
}
- if (ti->get_parent() == root->get_children()->get_next()) {
+ if (ti->get_parent() == root->get_first_child()->get_next()) {
member_type = MEMBER_VARIABLE;
member_name = ti->get_text(0);
member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
member_popup->add_separator();
- member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE);
+ member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE);
member_popup->popup();
return;
}
- if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
+ if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {
member_type = MEMBER_SIGNAL;
member_name = ti->get_text(0);
member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
member_popup->add_separator();
- member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE);
+ member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE);
member_popup->popup();
return;
}
@@ -4250,9 +4243,9 @@ void VisualScriptEditor::_bind_methods() {
ClassDB::bind_method("_create_new_node_from_name", &VisualScriptEditor::_create_new_node_from_name);
- ClassDB::bind_method("get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw);
- ClassDB::bind_method("can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw);
- ClassDB::bind_method("drop_data_fw", &VisualScriptEditor::drop_data_fw);
+ ClassDB::bind_method("_get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw);
+ ClassDB::bind_method("_can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw);
+ ClassDB::bind_method("_drop_data_fw", &VisualScriptEditor::drop_data_fw);
ClassDB::bind_method("_input", &VisualScriptEditor::_input);
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index bb6f194286..ca06b807cc 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -135,6 +135,7 @@ class VisualScriptEditor : public ScriptEditorBase {
Vector<Pair<Variant::Type, String>> args;
};
+ Map<StringName, Color> node_colors;
HashMap<StringName, Ref<StyleBox>> node_styles;
void _update_graph_connections();
@@ -316,9 +317,12 @@ public:
virtual void set_tooltip_request_func(String p_method, Object *p_obj) override;
virtual Control *get_edit_menu() override;
virtual void clear_edit_menu() override;
+ virtual void set_find_replace_bar(FindReplaceBar *p_bar) override { p_bar->hide(); }; // Not needed here.
virtual bool can_lose_focus_on_node_selection() override { return false; }
virtual void validate() override;
+ virtual Control *get_base_editor() const override;
+
static void register_editor();
static void free_clipboard();
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 9310b86627..a0ba7b1962 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -737,20 +737,22 @@ public:
}
int to_id = 0;
- bool reliable = true;
+ //bool reliable = true;
if (rpc_mode >= VisualScriptFunctionCall::RPC_RELIABLE_TO_ID) {
to_id = *p_args[0];
p_args += 1;
p_argcount -= 1;
- if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) {
- reliable = false;
- }
- } else if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE) {
- reliable = false;
+ //if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) {
+ //reliable = false;
+ //}
}
+ //else if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE) {
+ //reliable = false;
+ //}
- node->rpcp(to_id, !reliable, function, p_args, p_argcount);
+ // TODO reliable?
+ node->rpcp(to_id, function, p_args, p_argcount);
return true;
}
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index fed6637acb..07dc3dfaf6 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -3918,10 +3918,10 @@ void register_visual_script_nodes() {
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>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUATERNION), create_node_deconst_typed<Variant::Type::QUATERNION>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::AABB), create_node_deconst_typed<Variant::Type::AABB>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::BASIS), create_node_deconst_typed<Variant::Type::BASIS>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM), create_node_deconst_typed<Variant::Type::TRANSFORM>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM3D), create_node_deconst_typed<Variant::Type::TRANSFORM3D>);
VisualScriptLanguage::singleton->add_register_func("functions/compose_array", create_node_generic<VisualScriptComposeArray>);
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index 862cac5c67..4a1e020bd4 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -59,7 +59,7 @@ void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) {
search_box->accept_event();
TreeItem *root = search_options->get_root();
- if (!root->get_children()) {
+ if (!root->get_first_child()) {
break;
}
@@ -108,10 +108,10 @@ void VisualScriptPropertySelector::_update_search() {
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("Quaternion", "EditorIcons"),
vbc->get_theme_icon("AABB", "EditorIcons"),
vbc->get_theme_icon("Basis", "EditorIcons"),
- vbc->get_theme_icon("Transform", "EditorIcons"),
+ vbc->get_theme_icon("Transform3D", "EditorIcons"),
vbc->get_theme_icon("Color", "EditorIcons"),
vbc->get_theme_icon("Path", "EditorIcons"),
vbc->get_theme_icon("RID", "EditorIcons"),
@@ -265,7 +265,7 @@ void VisualScriptPropertySelector::_update_search() {
item->set_metadata(2, connecting);
}
- if (category && category->get_children() == nullptr) {
+ if (category && category->get_first_child() == nullptr) {
memdelete(category); //old category was unused
}
}
@@ -310,7 +310,7 @@ void VisualScriptPropertySelector::_update_search() {
found = true;
}
- get_ok_button()->set_disabled(root->get_children() == nullptr);
+ get_ok_button()->set_disabled(root->get_first_child() == nullptr);
}
void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) {
diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub
index 67d3f1bebd..4334cf732b 100644
--- a/modules/webm/libvpx/SCsub
+++ b/modules/webm/libvpx/SCsub
@@ -235,7 +235,7 @@ if env["platform"] == "uwp":
else:
import platform
- is_x11_or_server_arm = (env["platform"] == "linuxbsd" or env["platform"] == "server") and (
+ is_x11_or_server_arm = env["platform"] == "linuxbsd" and (
platform.machine().startswith("arm") or platform.machine().startswith("aarch")
)
is_macos_x86 = env["platform"] == "osx" and ("arch" in env and (env["arch"] != "arm64"))
@@ -314,12 +314,7 @@ if webm_cpu_x86:
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"] == "linuxbsd"
- or env["platform"] == "server"
- ):
+ elif env["platform"] == "android" and env["android_arch"] == "armv7" or env["platform"] == "linuxbsd":
env_libvpx["ASFLAGS"] = "-mfpu=neon"
elif env["platform"] == "uwp":
env_libvpx["AS"] = "armasm"
diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp
index a6b64b342e..6ec0bde7bd 100644
--- a/modules/webm/video_stream_webm.cpp
+++ b/modules/webm/video_stream_webm.cpp
@@ -31,7 +31,7 @@
#include "video_stream_webm.h"
#include "core/config/project_settings.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/os.h"
#include "servers/audio_server.h"
@@ -62,10 +62,10 @@ public:
virtual int Read(long long pos, long len, unsigned char *buf) {
if (file) {
- if (file->get_position() != (size_t)pos) {
+ if (file->get_position() != (uint64_t)pos) {
file->seek(pos);
}
- if (file->get_buffer(buf, len) == len) {
+ if (file->get_buffer(buf, len) == (uint64_t)len) {
return 0;
}
}
@@ -74,7 +74,7 @@ public:
virtual int Length(long long *total, long long *available) {
if (file) {
- const size_t len = file->get_len();
+ const uint64_t len = file->get_length();
if (total) {
*total = len;
}
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp
index b304c4824f..772445190c 100644
--- a/modules/webp/image_loader_webp.cpp
+++ b/modules/webp/image_loader_webp.cpp
@@ -30,6 +30,7 @@
#include "image_loader_webp.h"
+#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -68,13 +69,78 @@ static Vector<uint8_t> _webp_lossy_pack(const Ref<Image> &p_image, float p_quali
w[1] = 'E';
w[2] = 'B';
w[3] = 'P';
- copymem(&w[4], dst_buff, dst_size);
- free(dst_buff);
+ memcpy(&w[4], dst_buff, dst_size);
+ WebPFree(dst_buff);
return dst;
}
-static Ref<Image> _webp_lossy_unpack(const Vector<uint8_t> &p_buffer) {
+static Vector<uint8_t> _webp_lossless_pack(const Ref<Image> &p_image) {
+ ERR_FAIL_COND_V(p_image.is_null() || p_image->is_empty(), Vector<uint8_t>());
+
+ int compression_level = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/webp_compression_level");
+ compression_level = CLAMP(compression_level, 0, 9);
+
+ Ref<Image> img = p_image->duplicate();
+ if (img->detect_alpha()) {
+ img->convert(Image::FORMAT_RGBA8);
+ } else {
+ img->convert(Image::FORMAT_RGB8);
+ }
+
+ Size2 s(img->get_width(), img->get_height());
+ Vector<uint8_t> data = img->get_data();
+ const uint8_t *r = data.ptr();
+
+ // we need to use the more complex API in order to access the 'exact' flag...
+
+ WebPConfig config;
+ WebPPicture pic;
+ if (!WebPConfigInit(&config) || !WebPConfigLosslessPreset(&config, compression_level) || !WebPPictureInit(&pic)) {
+ ERR_FAIL_V(Vector<uint8_t>());
+ }
+
+ WebPMemoryWriter wrt;
+ config.exact = 1;
+ pic.use_argb = 1;
+ pic.width = s.width;
+ pic.height = s.height;
+ pic.writer = WebPMemoryWrite;
+ pic.custom_ptr = &wrt;
+ WebPMemoryWriterInit(&wrt);
+
+ bool success_import = false;
+ if (img->get_format() == Image::FORMAT_RGB8) {
+ success_import = WebPPictureImportRGB(&pic, r, 3 * s.width);
+ } else {
+ success_import = WebPPictureImportRGBA(&pic, r, 4 * s.width);
+ }
+ bool success_encode = false;
+ if (success_import) {
+ success_encode = WebPEncode(&config, &pic);
+ }
+ WebPPictureFree(&pic);
+
+ if (!success_encode) {
+ WebPMemoryWriterClear(&wrt);
+ ERR_FAIL_V_MSG(Vector<uint8_t>(), "WebP packing failed.");
+ }
+
+ // copy from wrt
+ Vector<uint8_t> dst;
+ dst.resize(4 + wrt.size);
+ uint8_t *w = dst.ptrw();
+ w[0] = 'W';
+ w[1] = 'E';
+ w[2] = 'B';
+ w[3] = 'P';
+ memcpy(&w[4], wrt.mem, wrt.size);
+ WebPMemoryWriterClear(&wrt);
+
+ return dst;
+}
+
+static Ref<Image> _webp_unpack(const Vector<uint8_t> &p_buffer) {
int size = p_buffer.size() - 4;
ERR_FAIL_COND_V(size <= 0, Ref<Image>());
const uint8_t *r = p_buffer.ptr();
@@ -147,7 +213,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) {
Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
- int src_image_len = f->get_len();
+ uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
src_image.resize(src_image_len);
@@ -168,6 +234,7 @@ void ImageLoaderWEBP::get_recognized_extensions(List<String> *p_extensions) cons
ImageLoaderWEBP::ImageLoaderWEBP() {
Image::_webp_mem_loader_func = _webp_mem_loader_func;
- Image::lossy_packer = _webp_lossy_pack;
- Image::lossy_unpacker = _webp_lossy_unpack;
+ Image::webp_lossy_packer = _webp_lossy_pack;
+ Image::webp_lossless_packer = _webp_lossless_pack;
+ Image::webp_unpacker = _webp_unpack;
}
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
index e21dee8eff..62e524825d 100644
--- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebRTCPeerConnection" inherits="Reference" version="4.0">
+<class name="WebRTCPeerConnection" inherits="RefCounted" version="4.0">
<brief_description>
Interface to a WebRTC peer connection.
</brief_description>
@@ -48,7 +48,7 @@
Valid [code]options[/code] are:
[codeblock]
{
- "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.
+ "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.
"id": 1, # When "negotiated" is true this value must also be set to the same value on both peer.
# Only one of maxRetransmits and maxPacketLifeTime can be specified, not both. They make the channel unreliable (but also better at real time).
diff --git a/modules/webrtc/webrtc_multiplayer.h b/modules/webrtc/webrtc_multiplayer.h
index 6b4ae6fcc8..2ddb98f656 100644
--- a/modules/webrtc/webrtc_multiplayer.h
+++ b/modules/webrtc/webrtc_multiplayer.h
@@ -48,7 +48,7 @@ private:
CH_RESERVED_MAX = 3
};
- class ConnectedPeer : public Reference {
+ class ConnectedPeer : public RefCounted {
public:
Ref<WebRTCPeerConnection> connection;
List<Ref<WebRTCDataChannel>> channels;
diff --git a/modules/webrtc/webrtc_peer_connection.h b/modules/webrtc/webrtc_peer_connection.h
index ae75864489..fcfb9ae9ae 100644
--- a/modules/webrtc/webrtc_peer_connection.h
+++ b/modules/webrtc/webrtc_peer_connection.h
@@ -34,8 +34,8 @@
#include "core/io/packet_peer.h"
#include "modules/webrtc/webrtc_data_channel.h"
-class WebRTCPeerConnection : public Reference {
- GDCLASS(WebRTCPeerConnection, Reference);
+class WebRTCPeerConnection : public RefCounted {
+ GDCLASS(WebRTCPeerConnection, RefCounted);
public:
enum ConnectionState {
diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp
index 25b6d6ef0e..626498e1ae 100644
--- a/modules/websocket/emws_client.cpp
+++ b/modules/websocket/emws_client.cpp
@@ -121,8 +121,8 @@ void EMWSClient::disconnect_from_host(int p_code, String p_reason) {
_peer->close(p_code, p_reason);
}
-IP_Address EMWSClient::get_connected_host() const {
- ERR_FAIL_V_MSG(IP_Address(), "Not supported in HTML5 export.");
+IPAddress EMWSClient::get_connected_host() const {
+ ERR_FAIL_V_MSG(IPAddress(), "Not supported in HTML5 export.");
}
uint16_t EMWSClient::get_connected_port() const {
diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h
index 2ab7dc83d0..ca2d7ed986 100644
--- a/modules/websocket/emws_client.h
+++ b/modules/websocket/emws_client.h
@@ -56,7 +56,7 @@ public:
Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>());
Ref<WebSocketPeer> get_peer(int p_peer_id) const;
void disconnect_from_host(int p_code = 1000, String p_reason = "");
- IP_Address get_connected_host() const;
+ IPAddress get_connected_host() const;
uint16_t get_connected_port() const;
virtual ConnectionStatus get_connection_status() const;
int get_max_packet_size() const;
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
index 5e75e10d68..1ad3bdc825 100644
--- a/modules/websocket/emws_peer.cpp
+++ b/modules/websocket/emws_peer.cpp
@@ -93,8 +93,8 @@ void EMWSPeer::close(int p_code, String p_reason) {
peer_sock = -1;
};
-IP_Address EMWSPeer::get_connected_host() const {
- ERR_FAIL_V_MSG(IP_Address(), "Not supported in HTML5 export.");
+IPAddress EMWSPeer::get_connected_host() const {
+ ERR_FAIL_V_MSG(IPAddress(), "Not supported in HTML5 export.");
};
uint16_t EMWSPeer::get_connected_port() const {
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
index abe5bf2bdb..73e701720b 100644
--- a/modules/websocket/emws_peer.h
+++ b/modules/websocket/emws_peer.h
@@ -73,7 +73,7 @@ public:
virtual void close(int p_code = 1000, String p_reason = "");
virtual bool is_connected_to_host() const;
- virtual IP_Address get_connected_host() const;
+ virtual IPAddress get_connected_host() const;
virtual uint16_t get_connected_port() const;
virtual WriteMode get_write_mode() const;
diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp
index a35d84f372..4a4f09a943 100644
--- a/modules/websocket/emws_server.cpp
+++ b/modules/websocket/emws_server.cpp
@@ -58,8 +58,8 @@ Vector<String> EMWSServer::get_protocols() const {
return out;
}
-IP_Address EMWSServer::get_peer_address(int p_peer_id) const {
- return IP_Address();
+IPAddress EMWSServer::get_peer_address(int p_peer_id) const {
+ return IPAddress();
}
int EMWSServer::get_peer_port(int p_peer_id) const {
diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h
index 4179b20ffe..d36e3a3557 100644
--- a/modules/websocket/emws_server.h
+++ b/modules/websocket/emws_server.h
@@ -33,7 +33,7 @@
#ifdef JAVASCRIPT_ENABLED
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "emws_peer.h"
#include "websocket_server.h"
@@ -47,7 +47,7 @@ public:
bool is_listening() const;
bool has_peer(int p_id) const;
Ref<WebSocketPeer> get_peer(int p_id) const;
- IP_Address get_peer_address(int p_peer_id) const;
+ IPAddress get_peer_address(int p_peer_id) const;
int get_peer_port(int p_peer_id) const;
void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
int get_max_packet_size() const;
diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h
index ed756363cf..e99a379767 100644
--- a/modules/websocket/packet_buffer.h
+++ b/modules/websocket/packet_buffer.h
@@ -31,7 +31,6 @@
#ifndef PACKET_BUFFER_H
#define PACKET_BUFFER_H
-#include "core/os/copymem.h"
#include "core/templates/ring_buffer.h"
template <class T>
@@ -66,7 +65,7 @@ public:
if (p_info) {
_Packet p;
p.size = p_size;
- copymem(&p.info, p_info, sizeof(T));
+ memcpy(&p.info, p_info, sizeof(T));
_packets.write(p);
}
@@ -86,7 +85,7 @@ public:
ERR_FAIL_COND_V(p_bytes < (int)p.size, ERR_OUT_OF_MEMORY);
r_read = p.size;
- copymem(r_info, &p.info, sizeof(T));
+ memcpy(r_info, &p.info, sizeof(T));
_payload.read(r_payload, p.size);
return OK;
}
diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp
index 425013f811..1e9183ebfa 100644
--- a/modules/websocket/websocket_client.cpp
+++ b/modules/websocket/websocket_client.cpp
@@ -43,34 +43,18 @@ Error WebSocketClient::connect_to_url(String p_url, const Vector<String> p_proto
String host = p_url;
String path = "/";
- int p_len = -1;
+ String scheme = "";
int port = 80;
- bool ssl = false;
- if (host.begins_with("wss://")) {
- ssl = true; // we should implement this
- host = host.substr(6, host.length() - 6);
- port = 443;
- } else {
- ssl = false;
- if (host.begins_with("ws://")) {
- host = host.substr(5, host.length() - 5);
- }
- }
+ Error err = p_url.parse_url(scheme, host, port, path);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Invalid URL: " + p_url);
- // Path
- p_len = host.find("/");
- if (p_len != -1) {
- path = host.substr(p_len, host.length() - p_len);
- host = host.substr(0, p_len);
+ bool ssl = false;
+ if (scheme == "wss://") {
+ ssl = true;
}
-
- // Port
- p_len = host.rfind(":");
- if (p_len != -1 && p_len == host.find(":")) {
- port = host.substr(p_len, host.length() - p_len).to_int();
- host = host.substr(0, p_len);
+ if (port == 0) {
+ port = ssl ? 443 : 80;
}
-
return connect_to_host(host, path, port, ssl, p_protocols, p_custom_headers);
}
diff --git a/modules/websocket/websocket_client.h b/modules/websocket/websocket_client.h
index 0225c9b3d3..c7f17f1ffb 100644
--- a/modules/websocket/websocket_client.h
+++ b/modules/websocket/websocket_client.h
@@ -57,7 +57,7 @@ public:
virtual Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) = 0;
virtual void disconnect_from_host(int p_code = 1000, String p_reason = "") = 0;
- virtual IP_Address get_connected_host() const = 0;
+ virtual IPAddress get_connected_host() const = 0;
virtual uint16_t get_connected_port() const = 0;
virtual bool is_server() const override;
diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp
index 758ed66c80..fa0ef7060f 100644
--- a/modules/websocket/websocket_multiplayer_peer.cpp
+++ b/modules/websocket/websocket_multiplayer_peer.cpp
@@ -99,6 +99,8 @@ Error WebSocketMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buff
_current_packet.data = nullptr;
}
+ ERR_FAIL_COND_V(_incoming_packets.size() == 0, ERR_UNAVAILABLE);
+
_current_packet = _incoming_packets.front()->get();
_incoming_packets.pop_front();
@@ -168,10 +170,10 @@ Vector<uint8_t> WebSocketMultiplayerPeer::_make_pkt(uint8_t p_type, int32_t p_fr
out.resize(PROTO_SIZE + p_data_size);
uint8_t *w = out.ptrw();
- copymem(&w[0], &p_type, 1);
- copymem(&w[1], &p_from, 4);
- copymem(&w[5], &p_to, 4);
- copymem(&w[PROTO_SIZE], p_data, p_data_size);
+ memcpy(&w[0], &p_type, 1);
+ memcpy(&w[1], &p_from, 4);
+ memcpy(&w[5], &p_to, 4);
+ memcpy(&w[PROTO_SIZE], p_data, p_data_size);
return out;
}
@@ -211,7 +213,7 @@ void WebSocketMultiplayerPeer::_store_pkt(int32_t p_source, int32_t p_dest, cons
packet.size = p_data_size;
packet.source = p_source;
packet.destination = p_dest;
- copymem(packet.data, &p_data[PROTO_SIZE], p_data_size);
+ memcpy(packet.data, &p_data[PROTO_SIZE], p_data_size);
_incoming_packets.push_back(packet);
emit_signal("peer_packet", p_source);
}
@@ -263,9 +265,9 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u
uint8_t type = 0;
uint32_t from = 0;
int32_t to = 0;
- copymem(&type, in_buffer, 1);
- copymem(&from, &in_buffer[1], 4);
- copymem(&to, &in_buffer[5], 4);
+ memcpy(&type, in_buffer, 1);
+ memcpy(&from, &in_buffer[1], 4);
+ memcpy(&to, &in_buffer[5], 4);
if (is_server()) { // Server can resend
@@ -299,7 +301,7 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u
// System message
ERR_FAIL_COND(data_size < 4);
int id = 0;
- copymem(&id, &in_buffer[PROTO_SIZE], 4);
+ memcpy(&id, &in_buffer[PROTO_SIZE], 4);
switch (type) {
case SYS_ADD: // Add peer
diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h
index 2ba83637f9..e9bb20f21f 100644
--- a/modules/websocket/websocket_peer.h
+++ b/modules/websocket/websocket_peer.h
@@ -55,7 +55,7 @@ public:
virtual void close(int p_code = 1000, String p_reason = "") = 0;
virtual bool is_connected_to_host() const = 0;
- virtual IP_Address get_connected_host() const = 0;
+ virtual IPAddress get_connected_host() const = 0;
virtual uint16_t get_connected_port() const = 0;
virtual bool was_string_packet() const = 0;
virtual void set_no_delay(bool p_enabled) = 0;
diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp
index f57e8d959c..7cf68b835c 100644
--- a/modules/websocket/websocket_server.cpp
+++ b/modules/websocket/websocket_server.cpp
@@ -34,7 +34,7 @@ GDCINULL(WebSocketServer);
WebSocketServer::WebSocketServer() {
_peer_id = 1;
- bind_ip = IP_Address("*");
+ bind_ip = IPAddress("*");
}
WebSocketServer::~WebSocketServer() {
@@ -71,11 +71,11 @@ void WebSocketServer::_bind_methods() {
ADD_SIGNAL(MethodInfo("data_received", PropertyInfo(Variant::INT, "id")));
}
-IP_Address WebSocketServer::get_bind_ip() const {
+IPAddress WebSocketServer::get_bind_ip() const {
return bind_ip;
}
-void WebSocketServer::set_bind_ip(const IP_Address &p_bind_ip) {
+void WebSocketServer::set_bind_ip(const IPAddress &p_bind_ip) {
ERR_FAIL_COND(is_listening());
ERR_FAIL_COND(!p_bind_ip.is_valid() && !p_bind_ip.is_wildcard());
bind_ip = p_bind_ip;
diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h
index 3fbd5e3b95..bc5e591e7b 100644
--- a/modules/websocket/websocket_server.h
+++ b/modules/websocket/websocket_server.h
@@ -32,7 +32,7 @@
#define WEBSOCKET_H
#include "core/crypto/crypto.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "websocket_multiplayer_peer.h"
#include "websocket_peer.h"
@@ -40,7 +40,7 @@ class WebSocketServer : public WebSocketMultiplayerPeer {
GDCLASS(WebSocketServer, WebSocketMultiplayerPeer);
GDCICLASS(WebSocketServer);
- IP_Address bind_ip;
+ IPAddress bind_ip;
protected:
static void _bind_methods();
@@ -57,7 +57,7 @@ public:
virtual bool is_server() const override;
ConnectionStatus get_connection_status() const override;
- virtual IP_Address get_peer_address(int p_peer_id) const = 0;
+ virtual IPAddress get_peer_address(int p_peer_id) const = 0;
virtual int get_peer_port(int p_peer_id) const = 0;
virtual void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") = 0;
@@ -66,8 +66,8 @@ public:
void _on_disconnect(int32_t p_peer_id, bool p_was_clean);
void _on_close_request(int32_t p_peer_id, int p_code, String p_reason);
- IP_Address get_bind_ip() const;
- void set_bind_ip(const IP_Address &p_bind_ip);
+ IPAddress get_bind_ip() const;
+ void set_bind_ip(const IPAddress &p_bind_ip);
Ref<CryptoKey> get_private_key() const;
void set_private_key(Ref<CryptoKey> p_key);
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
index a075ae3982..111d2178d6 100644
--- a/modules/websocket/wsl_client.cpp
+++ b/modules/websocket/wsl_client.cpp
@@ -160,7 +160,7 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
ERR_FAIL_COND_V(_connection.is_valid(), ERR_ALREADY_IN_USE);
_peer = Ref<WSLPeer>(memnew(WSLPeer));
- IP_Address addr;
+ IPAddress addr;
if (!p_host.is_valid_ip_address()) {
addr = IP::get_singleton()->resolve_hostname(p_host);
@@ -316,8 +316,8 @@ void WSLClient::disconnect_from_host(int p_code, String p_reason) {
_resp_pos = 0;
}
-IP_Address WSLClient::get_connected_host() const {
- ERR_FAIL_COND_V(!_peer->is_connected_to_host(), IP_Address());
+IPAddress WSLClient::get_connected_host() const {
+ ERR_FAIL_COND_V(!_peer->is_connected_to_host(), IPAddress());
return _peer->get_connected_host();
}
diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h
index e7c91ed333..849639ee8b 100644
--- a/modules/websocket/wsl_client.h
+++ b/modules/websocket/wsl_client.h
@@ -75,7 +75,7 @@ public:
int get_max_packet_size() const;
Ref<WebSocketPeer> get_peer(int p_peer_id) const;
void disconnect_from_host(int p_code = 1000, String p_reason = "");
- IP_Address get_connected_host() const;
+ IPAddress get_connected_host() const;
uint16_t get_connected_port() const;
virtual ConnectionStatus get_connection_status() const;
virtual void poll();
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index dbbf86d0da..1dbadfed74 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -305,8 +305,8 @@ void WSLPeer::close(int p_code, String p_reason) {
_packet_buffer.resize(0);
}
-IP_Address WSLPeer::get_connected_host() const {
- ERR_FAIL_COND_V(!is_connected_to_host() || _data->tcp.is_null(), IP_Address());
+IPAddress WSLPeer::get_connected_host() const {
+ ERR_FAIL_COND_V(!is_connected_to_host() || _data->tcp.is_null(), IPAddress());
return _data->tcp->get_connected_host();
}
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index 5e6a7e8554..f1ea98d384 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -90,7 +90,7 @@ public:
virtual void close_now();
virtual void close(int p_code = 1000, String p_reason = "");
virtual bool is_connected_to_host() const;
- virtual IP_Address get_connected_host() const;
+ virtual IPAddress get_connected_host() const;
virtual uint16_t get_connected_port() const;
virtual WriteMode get_write_mode() const;
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
index 437eb2061b..dc5b23c31e 100644
--- a/modules/websocket/wsl_server.cpp
+++ b/modules/websocket/wsl_server.cpp
@@ -272,8 +272,8 @@ Ref<WebSocketPeer> WSLServer::get_peer(int p_id) const {
return _peer_map[p_id];
}
-IP_Address WSLServer::get_peer_address(int p_peer_id) const {
- ERR_FAIL_COND_V(!has_peer(p_peer_id), IP_Address());
+IPAddress WSLServer::get_peer_address(int p_peer_id) const {
+ ERR_FAIL_COND_V(!has_peer(p_peer_id), IPAddress());
return _peer_map[p_peer_id]->get_connected_host();
}
diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h
index 75669e12ee..39177a16a8 100644
--- a/modules/websocket/wsl_server.h
+++ b/modules/websocket/wsl_server.h
@@ -46,7 +46,7 @@ class WSLServer : public WebSocketServer {
GDCIIMPL(WSLServer, WebSocketServer);
private:
- class PendingPeer : public Reference {
+ class PendingPeer : public RefCounted {
private:
bool _parse_request(const Vector<String> p_protocols);
@@ -73,7 +73,7 @@ private:
int _out_pkt_size = DEF_PKT_SHIFT;
List<Ref<PendingPeer>> _pending;
- Ref<TCP_Server> _server;
+ Ref<TCPServer> _server;
Vector<String> _protocols;
public:
@@ -84,7 +84,7 @@ public:
int get_max_packet_size() const;
bool has_peer(int p_id) const;
Ref<WebSocketPeer> get_peer(int p_id) const;
- IP_Address get_peer_address(int p_peer_id) const;
+ IPAddress get_peer_address(int p_peer_id) const;
int get_peer_port(int p_peer_id) const;
void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
virtual void poll();
diff --git a/modules/webxr/config.py b/modules/webxr/config.py
index 9efebed4e6..f676ef3483 100644
--- a/modules/webxr/config.py
+++ b/modules/webxr/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return True
+ return not env["disable_3d"]
def configure(env):
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
index 2407d44496..9b3a063ef5 100644
--- a/modules/webxr/doc_classes/WebXRInterface.xml
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -7,7 +7,7 @@
WebXR is an open standard that allows creating VR and AR applications that run in the web browser.
As such, this interface is only available when running in an HTML5 export.
WebXR supports a wide range of devices, from the very capable (like Valve Index, HTC Vive, Oculus Rift and Quest) down to the much less capable (like Google Cardboard, Oculus Go, GearVR, or plain smartphones).
- Since WebXR is based on Javascript, it makes extensive use of callbacks, which means that [WebXRInterface] is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes [WebXRInterface] quite a bit more complicated to intialize than other AR/VR interfaces.
+ Since WebXR is based on Javascript, it makes extensive use of callbacks, which means that [WebXRInterface] is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes [WebXRInterface] quite a bit more complicated to initialize than other AR/VR interfaces.
Here's the minimum code required to start an immersive VR session:
[codeblock]
extends Node3D
diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js
index 8e9ef8a73c..6e19a8ac6e 100644
--- a/modules/webxr/native/library_godot_webxr.js
+++ b/modules/webxr/native/library_godot_webxr.js
@@ -71,10 +71,8 @@ const GodotWebXR = {
// enabled or disabled. When using the WebXR API Emulator, this
// gets picked up automatically, however, in the Oculus Browser
// on the Quest, we need to pause and resume the main loop.
- Browser.pauseAsyncCallbacks();
Browser.mainLoop.pause();
window.setTimeout(function () {
- Browser.resumeAsyncCallbacks();
Browser.mainLoop.resume();
}, 0);
},
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 4dce2c2b23..13981e73e1 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -253,7 +253,7 @@ bool WebXRInterfaceJS::initialize() {
void WebXRInterfaceJS::uninitialize() {
if (initialized) {
XRServer *xr_server = XRServer::get_singleton();
- if (xr_server != NULL) {
+ if (xr_server != nullptr) {
// no longer our primary interface
xr_server->clear_primary_interface_if(this);
}
@@ -265,8 +265,8 @@ void WebXRInterfaceJS::uninitialize() {
};
};
-Transform WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) {
- Transform transform;
+Transform3D WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) {
+ Transform3D transform;
transform.basis.elements[0].x = p_js_matrix[0];
transform.basis.elements[1].x = p_js_matrix[1];
@@ -305,13 +305,30 @@ Size2 WebXRInterfaceJS::get_render_targetsize() {
return render_targetsize;
};
-Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) {
- Transform transform_for_eye;
+Transform3D WebXRInterfaceJS::get_camera_transform() {
+ Transform3D transform_for_eye;
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, transform_for_eye);
- float *js_matrix = godot_webxr_get_transform_for_eye(p_eye);
+ float *js_matrix = godot_webxr_get_transform_for_eye(0);
+ if (!initialized || js_matrix == nullptr) {
+ return transform_for_eye;
+ }
+
+ transform_for_eye = _js_matrix_to_transform(js_matrix);
+ free(js_matrix);
+
+ return xr_server->get_reference_frame() * transform_for_eye;
+};
+
+Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
+ Transform3D transform_for_eye;
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, transform_for_eye);
+
+ float *js_matrix = godot_webxr_get_transform_for_eye(p_view + 1);
if (!initialized || js_matrix == nullptr) {
transform_for_eye = p_cam_transform;
return transform_for_eye;
@@ -323,10 +340,10 @@ Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const
return p_cam_transform * xr_server->get_reference_frame() * transform_for_eye;
};
-CameraMatrix WebXRInterfaceJS::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+CameraMatrix WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
CameraMatrix eye;
- float *js_matrix = godot_webxr_get_projection_for_eye(p_eye);
+ float *js_matrix = godot_webxr_get_projection_for_eye(p_view + 1);
if (!initialized || js_matrix == nullptr) {
return eye;
}
@@ -399,7 +416,7 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
float *tracker_matrix = godot_webxr_get_controller_transform(p_controller_id);
if (tracker_matrix) {
- Transform transform = _js_matrix_to_transform(tracker_matrix);
+ Transform3D transform = _js_matrix_to_transform(tracker_matrix);
tracker->set_position(transform.origin);
tracker->set_orientation(transform.basis);
free(tracker_matrix);
diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h
index 7c841c1911..723ab952cd 100644
--- a/modules/webxr/webxr_interface_js.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -56,7 +56,7 @@ private:
bool controllers_state[2];
Size2 render_targetsize;
- Transform _js_matrix_to_transform(float *p_js_matrix);
+ Transform3D _js_matrix_to_transform(float *p_js_matrix);
void _update_tracker(int p_controller_id);
public:
@@ -84,8 +84,9 @@ public:
virtual Size2 get_render_targetsize() override;
virtual bool is_stereo() override;
- virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override;
- virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) override;
+ virtual Transform3D get_camera_transform() override;
+ virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
+ virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override;
virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override;
virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override;
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index e1f9521a48..8913ef1b65 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -29,26 +29,19 @@
/*************************************************************************/
#include "register_types.h"
-
-#include "core/error/error_macros.h"
-
#include "core/crypto/crypto_core.h"
-
#include "thirdparty/xatlas/xatlas.h"
-#include <stdio.h>
-#include <stdlib.h>
+extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, 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);
-extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache);
-
-bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uvs, int **r_vertices, int *r_vertex_count, int **r_indices, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache) {
+bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, 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) {
CryptoCore::MD5Context ctx;
ctx.start();
ctx.update((unsigned char *)&p_texel_size, sizeof(float));
ctx.update((unsigned char *)p_indices, sizeof(int) * p_index_count);
- ctx.update((unsigned char *)p_vertices, sizeof(float) * p_vertex_count);
- ctx.update((unsigned char *)p_normals, sizeof(float) * p_vertex_count);
+ ctx.update((unsigned char *)p_vertices, sizeof(float) * p_vertex_count * 3);
+ ctx.update((unsigned char *)p_normals, sizeof(float) * p_vertex_count * 3);
unsigned char hash[16];
ctx.finish(hash);
@@ -56,38 +49,37 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
bool cached = false;
unsigned int cache_idx = 0;
- if (r_used_cache && r_cache_size) {
- //Check if hash is in cache data
+ *r_mesh_cache = nullptr;
+ *r_mesh_cache_size = 0;
- int *cache_data = r_cache_data;
+ if (p_cache_data) {
+ //Check if hash is in cache data
+ int *cache_data = (int *)p_cache_data;
int n_entries = cache_data[0];
- unsigned int r_idx = 1;
+ unsigned int read_idx = 1;
for (int i = 0; i < n_entries; ++i) {
- if (memcmp(&cache_data[r_idx], hash, 16) == 0) {
+ if (memcmp(&cache_data[read_idx], hash, 16) == 0) {
cached = true;
- cache_idx = r_idx;
+ cache_idx = read_idx;
break;
}
- r_idx += 4; // hash
- r_idx += 2; // size hint
+ read_idx += 4; // hash
+ read_idx += 2; // size hint
- int vertex_count = cache_data[r_idx];
- r_idx += 1; // vertex count
- r_idx += vertex_count; // vertex
- r_idx += vertex_count * 2; // uvs
+ int vertex_count = cache_data[read_idx];
+ read_idx += 1; // vertex count
+ read_idx += vertex_count; // vertex
+ read_idx += vertex_count * 2; // uvs
- int index_count = cache_data[r_idx];
- r_idx += 1; // index count
- r_idx += index_count; // indices
+ int index_count = cache_data[read_idx];
+ read_idx += 1; // index count
+ read_idx += index_count; // indices
}
}
- if (r_used_cache && cached) {
- int *cache_data = r_cache_data;
-
- // Return cache data pointer to the caller
- r_cache_data = &cache_data[cache_idx];
+ if (cached) {
+ int *cache_data = (int *)p_cache_data;
cache_idx += 4;
@@ -99,96 +91,92 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
// Load vertices
*r_vertex_count = cache_data[cache_idx];
cache_idx++;
- *r_vertices = &cache_data[cache_idx];
+ *r_vertex = &cache_data[cache_idx];
cache_idx += *r_vertex_count;
// Load UVs
- *r_uvs = (float *)&cache_data[cache_idx];
+ *r_uv = (float *)&cache_data[cache_idx];
cache_idx += *r_vertex_count * 2;
// Load indices
*r_index_count = cache_data[cache_idx];
cache_idx++;
- *r_indices = &cache_data[cache_idx];
-
- // Return cache data size to the caller
- r_cache_size = sizeof(int) * (4 + 2 + 1 + *r_vertex_count + (*r_vertex_count * 2) + 1 + *r_index_count); // hash + size hint + vertex_count + vertices + uvs + index_count + indices
- r_used_cache = true;
- return true;
- }
-
- //set up input mesh
- xatlas::MeshDecl input_mesh;
- input_mesh.indexData = p_indices;
- input_mesh.indexCount = p_index_count;
- input_mesh.indexFormat = xatlas::IndexFormat::UInt32;
-
- input_mesh.vertexCount = p_vertex_count;
- input_mesh.vertexPositionData = p_vertices;
- input_mesh.vertexPositionStride = sizeof(float) * 3;
- input_mesh.vertexNormalData = p_normals;
- input_mesh.vertexNormalStride = sizeof(uint32_t) * 3;
- input_mesh.vertexUvData = nullptr;
- input_mesh.vertexUvStride = 0;
-
- xatlas::ChartOptions chart_options;
- xatlas::PackOptions pack_options;
-
- pack_options.maxChartSize = 4096;
- pack_options.blockAlign = true;
- pack_options.padding = 1;
- pack_options.texelsPerUnit = 1.0 / p_texel_size;
+ *r_index = &cache_data[cache_idx];
+ } else {
+ // set up input mesh
+ xatlas::MeshDecl input_mesh;
+ input_mesh.indexData = p_indices;
+ input_mesh.indexCount = p_index_count;
+ input_mesh.indexFormat = xatlas::IndexFormat::UInt32;
+
+ input_mesh.vertexCount = p_vertex_count;
+ input_mesh.vertexPositionData = p_vertices;
+ input_mesh.vertexPositionStride = sizeof(float) * 3;
+ input_mesh.vertexNormalData = p_normals;
+ input_mesh.vertexNormalStride = sizeof(uint32_t) * 3;
+ input_mesh.vertexUvData = NULL;
+ input_mesh.vertexUvStride = 0;
+
+ xatlas::ChartOptions chart_options;
+ chart_options.fixWinding = true;
+
+ xatlas::PackOptions pack_options;
+ pack_options.padding = 1;
+ pack_options.maxChartSize = 4094; // Lightmap atlassing needs 2 for padding between meshes, so 4096-2
+ pack_options.blockAlign = true;
+ pack_options.texelsPerUnit = 1.0 / p_texel_size;
+
+ xatlas::Atlas *atlas = xatlas::Create();
+
+ xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
+ ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
+
+ xatlas::Generate(atlas, chart_options, pack_options);
+
+ *r_size_hint_x = atlas->width;
+ *r_size_hint_y = atlas->height;
+
+ float w = *r_size_hint_x;
+ float h = *r_size_hint_y;
+
+ if (w == 0 || h == 0) {
+ xatlas::Destroy(atlas);
+ return false; //could not bake because there is no area
+ }
- xatlas::Atlas *atlas = xatlas::Create();
- printf("Adding mesh..\n");
- xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
- ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
+ const xatlas::Mesh &output = atlas->meshes[0];
+
+ *r_vertex = (int *)memalloc(sizeof(int) * output.vertexCount);
+ ERR_FAIL_NULL_V_MSG(*r_vertex, false, "Out of memory.");
+ *r_uv = (float *)memalloc(sizeof(float) * output.vertexCount * 2);
+ ERR_FAIL_NULL_V_MSG(*r_uv, false, "Out of memory.");
+ *r_index = (int *)memalloc(sizeof(int) * output.indexCount);
+ ERR_FAIL_NULL_V_MSG(*r_index, false, "Out of memory.");
+
+ float max_x = 0;
+ float max_y = 0;
+ for (uint32_t i = 0; i < output.vertexCount; i++) {
+ (*r_vertex)[i] = output.vertexArray[i].xref;
+ (*r_uv)[i * 2 + 0] = output.vertexArray[i].uv[0] / w;
+ (*r_uv)[i * 2 + 1] = output.vertexArray[i].uv[1] / h;
+ max_x = MAX(max_x, output.vertexArray[i].uv[0]);
+ max_y = MAX(max_y, output.vertexArray[i].uv[1]);
+ }
- printf("Generate..\n");
- xatlas::Generate(atlas, chart_options, pack_options);
+ *r_vertex_count = output.vertexCount;
- *r_size_hint_x = atlas->width;
- *r_size_hint_y = atlas->height;
+ for (uint32_t i = 0; i < output.indexCount; i++) {
+ (*r_index)[i] = output.indexArray[i];
+ }
- float w = *r_size_hint_x;
- float h = *r_size_hint_y;
+ *r_index_count = output.indexCount;
- if (w == 0 || h == 0) {
xatlas::Destroy(atlas);
- return false; //could not bake because there is no area
- }
-
- const xatlas::Mesh &output = atlas->meshes[0];
-
- *r_vertices = (int *)malloc(sizeof(int) * output.vertexCount);
- ERR_FAIL_NULL_V_MSG(*r_vertices, false, "Out of memory.");
- *r_uvs = (float *)malloc(sizeof(float) * output.vertexCount * 2);
- ERR_FAIL_NULL_V_MSG(*r_uvs, false, "Out of memory.");
- *r_indices = (int *)malloc(sizeof(int) * output.indexCount);
- ERR_FAIL_NULL_V_MSG(*r_indices, false, "Out of memory.");
-
- float max_x = 0.0;
- float max_y = 0.0;
- for (uint32_t i = 0; i < output.vertexCount; i++) {
- (*r_vertices)[i] = output.vertexArray[i].xref;
- (*r_uvs)[i * 2 + 0] = output.vertexArray[i].uv[0] / w;
- (*r_uvs)[i * 2 + 1] = output.vertexArray[i].uv[1] / h;
- max_x = MAX(max_x, output.vertexArray[i].uv[0]);
- max_y = MAX(max_y, output.vertexArray[i].uv[1]);
}
- printf("Final texture size: %f,%f - max %f,%f\n", w, h, max_x, max_y);
- *r_vertex_count = output.vertexCount;
+ if (*r_use_cache) {
+ // Build cache data for current mesh
- for (uint32_t i = 0; i < output.indexCount; i++) {
- (*r_indices)[i] = output.indexArray[i];
- }
-
- *r_index_count = output.indexCount;
-
- xatlas::Destroy(atlas);
-
- if (r_used_cache) {
unsigned int new_cache_size = 4 + 2 + 1 + *r_vertex_count + (*r_vertex_count * 2) + 1 + *r_index_count; // hash + size hint + vertex_count + vertices + uvs + index_count + indices
new_cache_size *= sizeof(int);
int *new_cache_data = (int *)memalloc(new_cache_size);
@@ -208,11 +196,11 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
new_cache_idx++;
// vertices
- memcpy(&new_cache_data[new_cache_idx], *r_vertices, sizeof(int) * *r_vertex_count);
+ memcpy(&new_cache_data[new_cache_idx], *r_vertex, sizeof(int) * (*r_vertex_count));
new_cache_idx += *r_vertex_count;
// uvs
- memcpy(&new_cache_data[new_cache_idx], *r_uvs, sizeof(float) * *r_vertex_count * 2);
+ memcpy(&new_cache_data[new_cache_idx], *r_uv, sizeof(float) * (*r_vertex_count) * 2);
new_cache_idx += *r_vertex_count * 2;
// index count
@@ -220,15 +208,15 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
new_cache_idx++;
// indices
- memcpy(&new_cache_data[new_cache_idx], *r_indices, sizeof(int) * *r_index_count);
- new_cache_idx += *r_index_count;
+ memcpy(&new_cache_data[new_cache_idx], *r_index, sizeof(int) * (*r_index_count));
// Return cache data to the caller
- r_cache_data = new_cache_data;
- r_cache_size = new_cache_size;
- r_used_cache = false;
+ *r_mesh_cache = (uint8_t *)new_cache_data;
+ *r_mesh_cache_size = new_cache_size;
}
+ *r_use_cache = cached; // Return whether cache was used.
+
return true;
}
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 7e9dac926c..56fbd2f7e4 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -9,7 +9,6 @@ android_files = [
"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",
diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h
index e0ee2888c0..6d25a366a4 100644
--- a/platform/android/android_keys_utils.h
+++ b/platform/android/android_keys_utils.h
@@ -127,8 +127,8 @@ static _WinTranslatePair _ak_to_keycode[] = {
{ KEY_BACKSLASH, AKEYCODE_BACKSLASH },
{ KEY_BRACKETLEFT, AKEYCODE_LEFT_BRACKET },
{ KEY_BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET },
- { KEY_CONTROL, AKEYCODE_CTRL_LEFT },
- { KEY_CONTROL, AKEYCODE_CTRL_RIGHT },
+ { KEY_CTRL, AKEYCODE_CTRL_LEFT },
+ { KEY_CTRL, AKEYCODE_CTRL_RIGHT },
{ KEY_UNKNOWN, 0 }
};
/*
diff --git a/platform/android/api/java_class_wrapper.h b/platform/android/api/java_class_wrapper.h
index d6c7a1abe5..ff7bf43573 100644
--- a/platform/android/api/java_class_wrapper.h
+++ b/platform/android/api/java_class_wrapper.h
@@ -31,7 +31,7 @@
#ifndef JAVA_CLASS_WRAPPER_H
#define JAVA_CLASS_WRAPPER_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#ifdef ANDROID_ENABLED
#include <android/log.h>
@@ -42,8 +42,8 @@
class JavaObject;
#endif
-class JavaClass : public Reference {
- GDCLASS(JavaClass, Reference);
+class JavaClass : public RefCounted {
+ GDCLASS(JavaClass, RefCounted);
#ifdef ANDROID_ENABLED
enum ArgumentType{
@@ -184,8 +184,8 @@ public:
JavaClass();
};
-class JavaObject : public Reference {
- GDCLASS(JavaObject, Reference);
+class JavaObject : public RefCounted {
+ GDCLASS(JavaObject, RefCounted);
#ifdef ANDROID_ENABLED
Ref<JavaClass> base_class;
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp
deleted file mode 100644
index 3a2ccac481..0000000000
--- a/platform/android/audio_driver_jandroid.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*************************************************************************/
-/* audio_driver_jandroid.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "audio_driver_jandroid.h"
-
-#include "core/config/project_settings.h"
-#include "core/os/os.h"
-#include "thread_jandroid.h"
-
-AudioDriverAndroid *AudioDriverAndroid::s_ad = nullptr;
-
-jobject AudioDriverAndroid::io;
-jmethodID AudioDriverAndroid::_init_audio;
-jmethodID AudioDriverAndroid::_write_buffer;
-jmethodID AudioDriverAndroid::_quit;
-jmethodID AudioDriverAndroid::_pause;
-bool AudioDriverAndroid::active = false;
-jclass AudioDriverAndroid::cls;
-int AudioDriverAndroid::audioBufferFrames = 0;
-int AudioDriverAndroid::mix_rate = 44100;
-bool AudioDriverAndroid::quit = false;
-jobject AudioDriverAndroid::audioBuffer = nullptr;
-void *AudioDriverAndroid::audioBufferPinned = nullptr;
-Mutex AudioDriverAndroid::mutex;
-int32_t *AudioDriverAndroid::audioBuffer32 = nullptr;
-
-const char *AudioDriverAndroid::get_name() const {
- return "Android";
-}
-
-Error AudioDriverAndroid::init() {
- /*
- // TODO: pass in/return a (Java) device ID, also whether we're opening for input or output
- this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
- SDL_CalculateAudioSpec(&this->spec);
-
- if (this->spec.samples == 0) {
- // Init failed?
- SDL_SetError("Java-side initialization failed!");
- return 0;
- }
-*/
-
- //Android_JNI_SetupThread();
-
- // __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
-
- JNIEnv *env = get_jni_env();
- int mix_rate = GLOBAL_GET("audio/driver/mix_rate");
-
- int latency = GLOBAL_GET("audio/driver/output_latency");
- unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000);
- print_verbose("Audio buffer size: " + itos(buffer_size));
-
- audioBuffer = env->CallObjectMethod(io, _init_audio, mix_rate, buffer_size);
-
- ERR_FAIL_COND_V(audioBuffer == nullptr, ERR_INVALID_PARAMETER);
-
- audioBuffer = env->NewGlobalRef(audioBuffer);
-
- jboolean isCopy = JNI_FALSE;
- audioBufferPinned = env->GetShortArrayElements((jshortArray)audioBuffer, &isCopy);
- audioBufferFrames = env->GetArrayLength((jshortArray)audioBuffer);
- audioBuffer32 = memnew_arr(int32_t, audioBufferFrames);
-
- return OK;
-}
-
-void AudioDriverAndroid::start() {
- active = true;
-}
-
-void AudioDriverAndroid::setup(jobject p_io) {
- JNIEnv *env = get_jni_env();
- io = p_io;
-
- jclass c = env->GetObjectClass(io);
- cls = (jclass)env->NewGlobalRef(c);
-
- _init_audio = env->GetMethodID(cls, "audioInit", "(II)Ljava/lang/Object;");
- _write_buffer = env->GetMethodID(cls, "audioWriteShortBuffer", "([S)V");
- _quit = env->GetMethodID(cls, "audioQuit", "()V");
- _pause = env->GetMethodID(cls, "audioPause", "(Z)V");
-}
-
-void AudioDriverAndroid::thread_func(JNIEnv *env) {
- jclass cls = env->FindClass("org/godotengine/godot/Godot");
- if (cls) {
- cls = (jclass)env->NewGlobalRef(cls);
- }
- jfieldID fid = env->GetStaticFieldID(cls, "io", "Lorg/godotengine/godot/GodotIO;");
- jobject ob = env->GetStaticObjectField(cls, fid);
- jobject gob = env->NewGlobalRef(ob);
- jclass c = env->GetObjectClass(gob);
- jclass lcls = (jclass)env->NewGlobalRef(c);
- _write_buffer = env->GetMethodID(lcls, "audioWriteShortBuffer", "([S)V");
-
- while (!quit) {
- int16_t *ptr = (int16_t *)audioBufferPinned;
- int fc = audioBufferFrames;
-
- if (!s_ad->active || mutex.try_lock() != OK) {
- for (int i = 0; i < fc; i++) {
- ptr[i] = 0;
- }
-
- } else {
- s_ad->audio_server_process(fc / 2, audioBuffer32);
-
- mutex.unlock();
-
- for (int i = 0; i < fc; i++) {
- ptr[i] = audioBuffer32[i] >> 16;
- }
- }
- env->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)ptr, JNI_COMMIT);
- env->CallVoidMethod(gob, _write_buffer, (jshortArray)audioBuffer);
- }
-}
-
-int AudioDriverAndroid::get_mix_rate() const {
- return mix_rate;
-}
-
-AudioDriver::SpeakerMode AudioDriverAndroid::get_speaker_mode() const {
- return SPEAKER_MODE_STEREO;
-}
-
-void AudioDriverAndroid::lock() {
- mutex.lock();
-}
-
-void AudioDriverAndroid::unlock() {
- mutex.unlock();
-}
-
-void AudioDriverAndroid::finish() {
- JNIEnv *env = get_jni_env();
- env->CallVoidMethod(io, _quit);
-
- if (audioBuffer) {
- env->DeleteGlobalRef(audioBuffer);
- audioBuffer = nullptr;
- audioBufferPinned = nullptr;
- }
-
- active = false;
-}
-
-void AudioDriverAndroid::set_pause(bool p_pause) {
- JNIEnv *env = get_jni_env();
- env->CallVoidMethod(io, _pause, p_pause);
-}
-
-AudioDriverAndroid::AudioDriverAndroid() {
- s_ad = this;
- active = false;
-}
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 2a80a3c45b..1b6af8662e 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -250,7 +250,7 @@ def configure(env):
env["RANLIB"] = tools_path + "/ranlib"
env["AS"] = tools_path + "/as"
- common_opts = ["-fno-integrated-as", "-gcc-toolchain", gcc_toolchain_path]
+ common_opts = ["-gcc-toolchain", gcc_toolchain_path]
# Compile flags
@@ -285,6 +285,9 @@ def configure(env):
)
env.Append(CPPDEFINES=["NO_STATVFS", "GLES_ENABLED"])
+ if get_platform(env["ndk_platform"]) >= 24:
+ env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
+
env["neon_enabled"] = False
if env["android_arch"] == "x86":
target_opts = ["-target", "i686-none-linux-android"]
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index f8ac29c738..0bae090702 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -201,8 +201,7 @@ String DirAccessJAndroid::get_filesystem_type() const {
return "APK";
}
-//FileType get_file_type() const;
-size_t DirAccessJAndroid::get_space_left() {
+uint64_t DirAccessJAndroid::get_space_left() {
return 0;
}
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index fed468d051..cdf98187ed 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/platform/android/dir_access_jandroid.h
@@ -31,7 +31,7 @@
#ifndef DIR_ACCESS_JANDROID_H
#define DIR_ACCESS_JANDROID_H
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "java_godot_lib_jni.h"
#include <stdio.h>
@@ -74,10 +74,13 @@ public:
virtual Error rename(String p_from, String p_to);
virtual Error remove(String p_name);
+ virtual bool is_link(String p_file) { return false; }
+ virtual String read_link(String p_file) { return p_file; }
+ virtual Error create_link(String p_source, String p_target) { return FAILED; }
+
virtual String get_filesystem_type() const;
- //virtual FileType get_file_type() const;
- size_t get_space_left();
+ uint64_t get_space_left();
static void setup(jobject p_io);
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index dd001baba9..ff61eeaee1 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -36,8 +36,6 @@
#include "java_godot_wrapper.h"
#include "os_android.h"
-#include <android/input.h>
-
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
#include "platform/android/vulkan/vulkan_context_android.h"
@@ -51,7 +49,7 @@ DisplayServerAndroid *DisplayServerAndroid::get_singleton() {
bool DisplayServerAndroid::has_feature(Feature p_feature) const {
switch (p_feature) {
//case FEATURE_CONSOLE_WINDOW:
- //case FEATURE_CURSOR_SHAPE:
+ case FEATURE_CURSOR_SHAPE:
//case FEATURE_CUSTOM_CURSOR_SHAPE:
//case FEATURE_GLOBAL_MENU:
//case FEATURE_HIDPI:
@@ -61,7 +59,6 @@ bool DisplayServerAndroid::has_feature(Feature p_feature) const {
//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:
@@ -199,7 +196,7 @@ void DisplayServerAndroid::window_set_input_text_callback(const Callable &p_call
}
void DisplayServerAndroid::window_set_rect_changed_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
- // Not supported on Android.
+ rect_changed_callback = p_callable;
}
void DisplayServerAndroid::window_set_drop_files_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
@@ -392,6 +389,19 @@ void DisplayServerAndroid::reset_window() {
#endif
}
+void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) {
+ if (rect_changed_callback.is_null()) {
+ return;
+ }
+
+ const Variant size = Rect2i(0, 0, p_width, p_height);
+ const Variant *sizep = &size;
+ Variant ret;
+ Callable::CallError ce;
+
+ rect_changed_callback.call(reinterpret_cast<const Variant **>(&sizep), 1, ret, ce);
+}
+
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;
@@ -491,10 +501,10 @@ void DisplayServerAndroid::process_joy_event(DisplayServerAndroid::JoypadEvent p
}
void DisplayServerAndroid::_set_key_modifier_state(Ref<InputEventWithModifiers> ev) {
- ev->set_shift(shift_mem);
- ev->set_alt(alt_mem);
- ev->set_metakey(meta_mem);
- ev->set_control(control_mem);
+ ev->set_shift_pressed(shift_mem);
+ ev->set_alt_pressed(alt_mem);
+ ev->set_meta_pressed(meta_mem);
+ ev->set_ctrl_pressed(control_mem);
}
void DisplayServerAndroid::process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed) {
@@ -529,7 +539,7 @@ void DisplayServerAndroid::process_key_event(int p_keycode, int p_scancode, int
if (keycode == KEY_ALT) {
alt_mem = p_pressed;
}
- if (keycode == KEY_CONTROL) {
+ if (keycode == KEY_CTRL) {
control_mem = p_pressed;
}
if (keycode == KEY_META) {
@@ -778,7 +788,7 @@ void DisplayServerAndroid::process_double_tap(int event_android_button_mask, Poi
ev->set_pressed(event_button_mask != 0);
ev->set_button_index(_button_index_from_mask(event_button_mask));
ev->set_button_mask(event_button_mask);
- ev->set_doubleclick(true);
+ ev->set_double_click(true);
Input::get_singleton()->accumulate_input_event(ev);
}
@@ -830,6 +840,12 @@ void DisplayServerAndroid::mouse_set_mode(MouseMode p_mode) {
return;
}
+ if (p_mode == MouseMode::MOUSE_MODE_HIDDEN) {
+ OS_Android::get_singleton()->get_godot_java()->get_godot_view()->set_pointer_icon(CURSOR_TYPE_NULL);
+ } else {
+ cursor_set_shape(cursor_shape);
+ }
+
if (p_mode == MouseMode::MOUSE_MODE_CAPTURED) {
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->request_pointer_capture();
} else {
@@ -871,3 +887,19 @@ int DisplayServerAndroid::_android_button_mask_to_godot_button_mask(int android_
return godot_button_mask;
}
+
+void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) {
+ if (cursor_shape == p_shape) {
+ return;
+ }
+
+ cursor_shape = p_shape;
+
+ if (mouse_mode == MouseMode::MOUSE_MODE_VISIBLE || mouse_mode == MouseMode::MOUSE_MODE_CONFINED) {
+ OS_Android::get_singleton()->get_godot_java()->get_godot_view()->set_pointer_icon(android_cursors[cursor_shape]);
+ }
+}
+
+DisplayServer::CursorShape DisplayServerAndroid::cursor_get_shape() const {
+ return cursor_shape;
+}
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index b9d1641656..a2f47dcccb 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -70,6 +70,28 @@ private:
int buttons_state;
+ // https://developer.android.com/reference/android/view/PointerIcon
+ // mapping between Godot's cursor shape to Android's'
+ int android_cursors[CURSOR_MAX] = {
+ 1000, //CURSOR_ARROW
+ 1008, //CURSOR_IBEAM
+ 1002, //CURSOR_POINTIN
+ 1007, //CURSOR_CROSS
+ 1004, //CURSOR_WAIT
+ 1004, //CURSOR_BUSY
+ 1021, //CURSOR_DRAG
+ 1021, //CURSOR_CAN_DRO
+ 1000, //CURSOR_FORBIDD (no corresponding icon in Android's icon so fallback to default)
+ 1015, //CURSOR_VSIZE
+ 1014, //CURSOR_HSIZE
+ 1017, //CURSOR_BDIAGSI
+ 1016, //CURSOR_FDIAGSI
+ 1020, //CURSOR_MOVE
+ 1015, //CURSOR_VSPLIT
+ 1014, //CURSOR_HSPLIT
+ 1003, //CURSOR_HELP
+ };
+ const int CURSOR_TYPE_NULL = 0;
MouseMode mouse_mode;
bool keep_screen_on;
@@ -78,6 +100,8 @@ private:
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
+ CursorShape cursor_shape = CursorShape::CURSOR_ARROW;
+
#if defined(VULKAN_ENABLED)
VulkanContextAndroid *context_vulkan;
RenderingDeviceVulkan *rendering_device_vulkan;
@@ -88,6 +112,7 @@ private:
Callable window_event_callback;
Callable input_event_callback;
Callable input_text_callback;
+ Callable rect_changed_callback;
void _window_callback(const Callable &p_callable, const Variant &p_arg) const;
@@ -180,6 +205,9 @@ public:
void process_joy_event(JoypadEvent p_event);
void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed);
+ virtual void cursor_set_shape(CursorShape p_shape);
+ virtual CursorShape cursor_get_shape() const;
+
void mouse_set_mode(MouseMode p_mode);
MouseMode mouse_get_mode() const;
@@ -188,6 +216,7 @@ public:
static void register_android_driver();
void reset_window();
+ void notify_surface_changed(int p_width, int p_height);
virtual Point2i mouse_get_position() const;
virtual int mouse_get_button_state() const;
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index f3502b2220..1a0c206e28 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -31,11 +31,11 @@
#include "export.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/image_loader.h"
#include "core/io/marshalls.h"
#include "core/io/zip_io.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/templates/safe_refcount.h"
#include "core/version.h"
@@ -609,9 +609,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
zip_fileinfo zipfi;
zipfi.tmz_date.tm_hour = time.hour;
zipfi.tmz_date.tm_mday = date.day;
- zipfi.tmz_date.tm_min = time.min;
+ zipfi.tmz_date.tm_min = time.minute;
zipfi.tmz_date.tm_mon = date.month - 1; // tm_mon is zero indexed
- zipfi.tmz_date.tm_sec = time.sec;
+ zipfi.tmz_date.tm_sec = time.second;
zipfi.tmz_date.tm_year = date.year;
zipfi.dosDate = 0;
zipfi.external_fa = 0;
@@ -847,7 +847,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
int version_code = p_preset->get("version/code");
String package_name = p_preset->get("package/unique_name");
- const int screen_orientation = _get_android_orientation_value(_get_screen_orientation());
+ const int screen_orientation =
+ _get_android_orientation_value(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));
bool screen_support_small = p_preset->get("screen/support_small");
bool screen_support_normal = p_preset->get("screen/support_normal");
@@ -855,7 +856,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
bool screen_support_xlarge = p_preset->get("screen/support_xlarge");
int xr_mode_index = p_preset->get("xr_features/xr_mode");
- bool focus_awareness = p_preset->get("xr_features/focus_awareness");
+
+ bool backup_allowed = p_preset->get("user_data_backup/allow");
Vector<String> perms;
// Write permissions into the perms variable.
@@ -921,7 +923,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String tname = string_table[name];
uint32_t attrcount = decode_uint32(&p_manifest[iofs + 20]);
iofs += 28;
- bool is_focus_aware_metadata = false;
for (uint32_t i = 0; i < attrcount; i++) {
uint32_t attr_nspace = decode_uint32(&p_manifest[iofs]);
@@ -950,6 +951,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
}
+ if (tname == "application" && attrname == "allowBackup") {
+ encode_uint32(backup_allowed, &p_manifest.write[iofs + 16]);
+ }
+
if (tname == "instrumentation" && attrname == "targetPackage") {
string_table.write[attr_value] = get_package_name(package_name);
}
@@ -973,28 +978,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
}
- // FIXME: `attr_value != 0xFFFFFFFF` below added as a stopgap measure for GH-32553,
- // but the issue should be debugged further and properly addressed.
- if (tname == "meta-data" && attrname == "name" && value == "xr_mode_metadata_name") {
- // Update the meta-data 'android:name' attribute based on the selected XR mode.
- if (xr_mode_index == 1 /* XRMode.OVR */) {
- string_table.write[attr_value] = "com.samsung.android.vr.application.mode";
- }
- }
-
- if (tname == "meta-data" && attrname == "value" && value == "xr_mode_metadata_value") {
- // Update the meta-data 'android:value' attribute based on the selected XR mode.
- if (xr_mode_index == 1 /* XRMode.OVR */) {
- string_table.write[attr_value] = "vr_only";
- }
- }
-
- if (tname == "meta-data" && attrname == "value" && is_focus_aware_metadata) {
- // Update the focus awareness meta-data value
- encode_uint32(xr_mode_index == /* XRMode.OVR */ 1 && focus_awareness ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
- }
-
- is_focus_aware_metadata = tname == "meta-data" && attrname == "name" && value == "com.oculus.vr.focusaware";
iofs += 20;
}
@@ -1010,15 +993,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
Vector<int> feature_versions;
if (xr_mode_index == 1 /* XRMode.OVR */) {
- // Check for degrees of freedom
- int dof_index = p_preset->get("xr_features/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof
-
- if (dof_index > 0) {
- feature_names.push_back("android.hardware.vr.headtracking");
- feature_required_list.push_back(dof_index == 2);
- feature_versions.push_back(1);
- }
-
// Check for hand tracking
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
if (hand_tracking_index > 0) {
@@ -1708,9 +1682,7 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/degrees_of_freedom", PROPERTY_HINT_ENUM, "None,3DOF and 6DOF,6DOF"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "xr_features/focus_awareness"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true));
@@ -1718,6 +1690,8 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_large"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_xlarge"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data_backup/allow"), false));
+
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "apk_expansion/enable"), false));
@@ -1819,7 +1793,7 @@ public:
p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST;
}
- String tmp_export_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
+ String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
#define CLEANUP_AND_RETURN(m_err) \
{ \
@@ -2063,6 +2037,13 @@ public:
// Validate the rest of the configuration.
String dk = p_preset->get("keystore/debug");
+ String dk_user = p_preset->get("keystore/debug_user");
+ String dk_password = p_preset->get("keystore/debug_password");
+
+ if ((dk.is_empty() || dk_user.is_empty() || dk_password.is_empty()) && (!dk.is_empty() || !dk_user.is_empty() || !dk_password.is_empty())) {
+ valid = false;
+ err += TTR("Either Debug Keystore, Debug User AND Debug Password settings must be configured OR none of them.") + "\n";
+ }
if (!FileAccess::exists(dk)) {
dk = EditorSettings::get_singleton()->get("export/android/debug_keystore");
@@ -2073,6 +2054,13 @@ public:
}
String rk = p_preset->get("keystore/release");
+ String rk_user = p_preset->get("keystore/release_user");
+ String rk_password = p_preset->get("keystore/release_password");
+
+ if ((rk.is_empty() || rk_user.is_empty() || rk_password.is_empty()) && (!rk.is_empty() || !rk_user.is_empty() || !rk_password.is_empty())) {
+ valid = false;
+ err += TTR("Either Release Keystore, Release User AND Release Password settings must be configured OR none of them.") + "\n";
+ }
if (!rk.is_empty() && !FileAccess::exists(rk)) {
valid = false;
@@ -2159,27 +2147,13 @@ public:
// Validate the Xr features are properly populated
int xr_mode_index = p_preset->get("xr_features/xr_mode");
- int degrees_of_freedom = p_preset->get("xr_features/degrees_of_freedom");
int hand_tracking = p_preset->get("xr_features/hand_tracking");
- bool focus_awareness = p_preset->get("xr_features/focus_awareness");
if (xr_mode_index != /* XRMode.OVR*/ 1) {
- if (degrees_of_freedom > 0) {
- valid = false;
- err += TTR("\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\".");
- err += "\n";
- }
-
if (hand_tracking > 0) {
valid = false;
err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\".");
err += "\n";
}
-
- if (focus_awareness) {
- valid = false;
- err += TTR("\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\".");
- err += "\n";
- }
}
if (int(p_preset->get("custom_template/export_format")) == EXPORT_FORMAT_AAB &&
@@ -2296,7 +2270,7 @@ public:
}
r_command_line_flags.resize(base + 4 + length);
encode_uint32(length, &r_command_line_flags.write[base]);
- copymem(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length);
+ memcpy(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length);
}
}
}
@@ -2691,7 +2665,7 @@ public:
FileAccess *dst_f = nullptr;
io2.opaque = &dst_f;
- String tmp_unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
+ String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
#define CLEANUP_AND_RETURN(m_err) \
{ \
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 40b8e90c6f..6ab678b8a1 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -31,9 +31,9 @@
#ifndef GODOT_GRADLE_EXPORT_UTIL_H
#define GODOT_GRADLE_EXPORT_UTIL_H
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/zip_io.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "editor/editor_export.h"
@@ -44,28 +44,6 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut
</resources>
)";
-DisplayServer::ScreenOrientation _get_screen_orientation() {
- String orientation_settings = ProjectSettings::get_singleton()->get("display/window/handheld/orientation");
- DisplayServer::ScreenOrientation screen_orientation;
- if (orientation_settings == "portrait") {
- screen_orientation = DisplayServer::SCREEN_PORTRAIT;
- } else if (orientation_settings == "reverse_landscape") {
- screen_orientation = DisplayServer::SCREEN_REVERSE_LANDSCAPE;
- } else if (orientation_settings == "reverse_portrait") {
- screen_orientation = DisplayServer::SCREEN_REVERSE_PORTRAIT;
- } else if (orientation_settings == "sensor_landscape") {
- screen_orientation = DisplayServer::SCREEN_SENSOR_LANDSCAPE;
- } else if (orientation_settings == "sensor_portrait") {
- screen_orientation = DisplayServer::SCREEN_SENSOR_PORTRAIT;
- } else if (orientation_settings == "sensor") {
- screen_orientation = DisplayServer::SCREEN_SENSOR;
- } else {
- screen_orientation = DisplayServer::SCREEN_LANDSCAPE;
- }
-
- return screen_orientation;
-}
-
int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation) {
switch (screen_orientation) {
case DisplayServer::SCREEN_PORTRAIT:
@@ -241,12 +219,6 @@ String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) {
String manifest_xr_features;
bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
if (uses_xr) {
- int dof_index = p_preset->get("xr_features/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof
- if (dof_index == 1) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"false\" android:version=\"1\" />\n";
- } else if (dof_index == 2) {
- manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"true\" android:version=\"1\" />\n";
- }
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
if (hand_tracking_index == 1) {
manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n";
@@ -272,16 +244,13 @@ String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset) {
String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
- String orientation = _get_android_orientation_label(_get_screen_orientation());
+ String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));
String manifest_activity_text = vformat(
" <activity android:name=\"com.godot.game.GodotApp\" "
"tools:replace=\"android:screenOrientation\" "
"android:screenOrientation=\"%s\">\n",
orientation);
- if (uses_xr) {
- String focus_awareness = bool_to_string(p_preset->get("xr_features/focus_awareness"));
- manifest_activity_text += vformat(" <meta-data tools:node=\"replace\" android:name=\"com.oculus.vr.focusaware\" android:value=\"%s\" />\n", focus_awareness);
- } else {
+ if (!uses_xr) {
manifest_activity_text += " <meta-data tools:node=\"remove\" android:name=\"com.oculus.vr.focusaware\" />\n";
}
manifest_activity_text += " </activity>\n";
@@ -289,16 +258,12 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
}
String _get_application_tag(const Ref<EditorExportPreset> &p_preset) {
- bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
- String manifest_application_text =
+ String manifest_application_text = vformat(
" <application android:label=\"@string/godot_project_name_string\"\n"
- " android:allowBackup=\"false\" tools:ignore=\"GoogleAppIndexingWarning\"\n"
- " android:icon=\"@mipmap/icon\">\n\n"
- " <meta-data tools:node=\"remove\" android:name=\"xr_mode_metadata_name\" />\n";
+ " android:allowBackup=\"%s\" tools:ignore=\"GoogleAppIndexingWarning\"\n"
+ " android:icon=\"@mipmap/icon\">\n\n",
+ bool_to_string(p_preset->get("user_data_backup/allow")));
- if (uses_xr) {
- manifest_application_text += " <meta-data tools:node=\"replace\" android:name=\"com.samsung.android.vr.application.mode\" android:value=\"vr_only\" />\n";
- }
manifest_application_text += _get_activity_tag(p_preset);
manifest_application_text += " </application>\n";
return manifest_application_text;
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index e288c16777..90370878b7 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -71,8 +71,9 @@ bool FileAccessAndroid::is_open() const {
return a != nullptr;
}
-void FileAccessAndroid::seek(size_t p_position) {
+void FileAccessAndroid::seek(uint64_t p_position) {
ERR_FAIL_COND(!a);
+
AAsset_seek(a, p_position, SEEK_SET);
pos = p_position;
if (pos > len) {
@@ -89,11 +90,11 @@ void FileAccessAndroid::seek_end(int64_t p_position) {
pos = len + p_position;
}
-size_t FileAccessAndroid::get_position() const {
+uint64_t FileAccessAndroid::get_position() const {
return pos;
}
-size_t FileAccessAndroid::get_len() const {
+uint64_t FileAccessAndroid::get_length() const {
return len;
}
@@ -113,11 +114,10 @@ uint8_t FileAccessAndroid::get_8() const {
return byte;
}
-int FileAccessAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
- ERR_FAIL_COND_V(!p_dst, -1);
- ERR_FAIL_COND_V(p_length < 0, -1);
+uint64_t FileAccessAndroid::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- off_t r = AAsset_read(a, p_dst, p_length);
+ int r = AAsset_read(a, p_dst, p_length);
if (pos + p_length > len) {
eof = true;
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index 56010c918a..bb4ce36947 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -31,7 +31,7 @@
#ifndef FILE_ACCESS_ANDROID_H
#define FILE_ACCESS_ANDROID_H
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include <android/asset_manager.h>
#include <android/log.h>
#include <stdio.h>
@@ -40,8 +40,8 @@
class FileAccessAndroid : public FileAccess {
static FileAccess *create_android();
mutable AAsset *a = nullptr;
- mutable size_t len = 0;
- mutable size_t pos = 0;
+ mutable uint64_t len = 0;
+ mutable uint64_t pos = 0;
mutable bool eof = false;
public:
@@ -51,15 +51,15 @@ public:
virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
- virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek(uint64_t p_position); ///< seek to a given position
virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual size_t get_position() const; ///< get position in the file
- virtual size_t get_len() const; ///< get size of the file
+ virtual uint64_t get_position() const; ///< get position in the file
+ virtual uint64_t get_length() const; ///< get size of the file
virtual bool eof_reached() const; ///< reading passed EOF
virtual uint8_t get_8() const; ///< get a byte
- virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
virtual Error get_error() const; ///< get last error
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index 948fa8c00b..15feea15a4 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -30,11 +30,6 @@
<!-- The following metadata values are replaced when Godot exports, modifying them here has no effect. -->
<!-- Do these changes in the export preset. Adding new ones is fine. -->
- <!-- XR mode metadata. This is modified by the exporter based on the selected xr mode. DO NOT CHANGE the values here. -->
- <meta-data
- android:name="xr_mode_metadata_name"
- android:value="xr_mode_metadata_value" />
-
<activity
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
@@ -45,8 +40,8 @@
android:resizeableActivity="false"
tools:ignore="UnusedAttribute" >
- <!-- Focus awareness metadata is updated at export time if the user enables it in the 'Xr Features' section. -->
- <meta-data android:name="com.oculus.vr.focusaware" android:value="false" />
+ <!-- Focus awareness metadata is removed at export time if the xr mode is not VR. -->
+ <meta-data android:name="com.oculus.vr.focusaware" android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index ad9a19e2af..b278d15bdf 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -3,7 +3,7 @@ ext.versions = [
compileSdk : 29,
minSdk : 18,
targetSdk : 29,
- buildTools : '30.0.1',
+ buildTools : '30.0.3',
supportCoreUtils : '1.0.0',
kotlinVersion : '1.4.10',
v4Support : '1.0.0',
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index 81570d9d86..a28888d80d 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -112,14 +112,14 @@ task copyReleaseAARToBin(type: Copy) {
* The zip file also includes some gradle tools to allow building of the custom build.
*/
task zipCustomBuild(type: Zip) {
- dependsOn ':generateGodotTemplates'
+ onlyIf { generateGodotTemplates.state.executed || generateDevTemplate.state.executed }
doFirst {
logger.lifecycle("Generating Godot custom build template")
}
from(fileTree(dir: 'app', excludes: ['**/build/**', '**/.gradle/**', '**/*.iml']), fileTree(dir: '.', includes: ['gradle.properties', 'gradlew', 'gradlew.bat', 'gradle/**']))
include '**/*'
- archiveName 'android_source.zip'
- destinationDir(file(binDir))
+ archiveFileName = 'android_source.zip'
+ destinationDirectory = file(binDir)
}
def templateExcludedBuildTask() {
diff --git a/platform/android/java/gradlew.bat b/platform/android/java/gradlew.bat
index f9553162f1..11cc30edb0 100644
--- a/platform/android/java/gradlew.bat
+++ b/platform/android/java/gradlew.bat
@@ -1,7 +1,7 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
-@rem Gradle startup script for Windows
+@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@@ -75,7 +75,7 @@ if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
diff --git a/platform/android/java/lib/res/values/strings.xml b/platform/android/java/lib/res/values/strings.xml
index 590b066d8a..010006b81e 100644
--- a/platform/android/java/lib/res/values/strings.xml
+++ b/platform/android/java/lib/res/values/strings.xml
@@ -6,7 +6,7 @@
<string name="text_button_resume_cellular">Resume download</string>
<string name="text_button_wifi_settings">Wi-Fi settings</string>
<string name="text_verifying_download">Verifying Download</string>
- <string name="text_validation_complete">XAPK File Validation Complete. Select OK to exit.</string>
+ <string name="text_validation_complete">XAPK File Validation Complete. Select OK to exit.</string>
<string name="text_validation_failed">XAPK File Validation Failed.</string>
<string name="text_button_pause">Pause Download</string>
<string name="text_button_resume">Resume Download</string>
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
index 63c91561ff..b3ee55ea64 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
@@ -44,11 +44,15 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PixelFormat;
import android.opengl.GLSurfaceView;
+import android.os.Build;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.SurfaceView;
+import androidx.annotation.Keep;
+
/**
* A simple GLSurfaceView sub-class that demonstrate how to perform
* OpenGL ES 2.0 rendering into a GL Surface. Note the following important
@@ -72,6 +76,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
private final GodotInputHandler inputHandler;
private final GestureDetector detector;
private final GodotRenderer godotRenderer;
+ private PointerIcon pointerIcon;
public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_32_bits,
boolean p_use_debug_opengl) {
@@ -83,6 +88,9 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
this.inputHandler = new GodotInputHandler(this);
this.detector = new GestureDetector(context, new GodotGestureHandler(this));
this.godotRenderer = new GodotRenderer();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
+ }
init(xrMode, false, 16, 0);
}
@@ -149,6 +157,21 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
return inputHandler.onGenericMotionEvent(event);
}
+ /**
+ * called from JNI to change pointer icon
+ */
+ @Keep
+ public void setPointerIcon(int pointerType) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
+ }
+ }
+
+ @Override
+ public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
+ return pointerIcon;
+ }
+
private void init(XRMode xrMode, boolean translucent, int depth, int stencil) {
setPreserveEGLContextOnPause(true);
setFocusableInTouchMode(true);
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 c7c7c1b40c..12a8bdb90b 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
@@ -328,95 +328,6 @@ public class GodotIO {
}
/////////////////////////
- // AUDIO
- /////////////////////////
-
- private Object buf;
- private Thread mAudioThread;
- private AudioTrack mAudioTrack;
-
- public Object audioInit(int sampleRate, int desiredFrames) {
- int channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
- int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
- int frameSize = 4;
-
- System.out.printf("audioInit: initializing audio:\n");
-
- //Log.v("Godot", "Godot audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
-
- // Let the user pick a larger buffer if they really want -- but ye
- // gods they probably shouldn't, the minimums are horrifyingly high
- // latency already
- desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
-
- mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
- channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
-
- audioStartThread();
-
- //Log.v("Godot", "Godot audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + ((float)mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
-
- buf = new short[desiredFrames * 2];
- return buf;
- }
-
- public void audioStartThread() {
- mAudioThread = new Thread(new Runnable() {
- public void run() {
- mAudioTrack.play();
- GodotLib.audio();
- }
- });
-
- // I'd take REALTIME if I could get it!
- mAudioThread.setPriority(Thread.MAX_PRIORITY);
- mAudioThread.start();
- }
-
- public void audioWriteShortBuffer(short[] buffer) {
- for (int i = 0; i < buffer.length;) {
- int result = mAudioTrack.write(buffer, i, buffer.length - i);
- if (result > 0) {
- i += result;
- } else if (result == 0) {
- try {
- Thread.sleep(1);
- } catch (InterruptedException e) {
- // Nom nom
- }
- } else {
- Log.w("Godot", "Godot audio: error return from write(short)");
- return;
- }
- }
- }
-
- public void audioQuit() {
- if (mAudioThread != null) {
- try {
- mAudioThread.join();
- } catch (Exception e) {
- Log.v("Godot", "Problem stopping audio thread: " + e);
- }
- mAudioThread = null;
-
- //Log.v("Godot", "Finished waiting for audio thread");
- }
-
- if (mAudioTrack != null) {
- mAudioTrack.stop();
- mAudioTrack = null;
- }
- }
-
- public void audioPause(boolean p_pause) {
- if (p_pause)
- mAudioTrack.pause();
- else
- mAudioTrack.play();
- }
-
- /////////////////////////
// MISCELLANEOUS OS IO
/////////////////////////
@@ -452,6 +363,10 @@ public class GodotIO {
return activity.getFilesDir().getAbsolutePath();
}
+ public String getExternalDataDir() {
+ return activity.getExternalFilesDir(null).getAbsolutePath();
+ }
+
public String getLocale() {
return Locale.getDefault().toString();
}
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 534a50e9ed..8108118388 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -175,11 +175,6 @@ public class GodotLib {
public static native void focusout();
/**
- * Invoked when the audio thread is started.
- */
- public static native void audio();
-
- /**
* Used to access Godot global properties.
* @param p_key Property key
* @return String value of the property
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java
index 2047c88070..ac333dd827 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java
@@ -47,4 +47,6 @@ public interface GodotRenderView {
abstract public void onBackPressed();
abstract public GodotInputHandler getInputHandler();
+
+ abstract public void setPointerIcon(int pointerType);
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
index 2e59dbc0d0..169c6cf770 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
@@ -37,17 +37,22 @@ import org.godotengine.godot.vulkan.VkSurfaceView;
import android.annotation.SuppressLint;
import android.content.Context;
+import android.os.Build;
import android.view.GestureDetector;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.SurfaceView;
+import androidx.annotation.Keep;
+
public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
private final Godot godot;
private final GodotInputHandler mInputHandler;
private final GestureDetector mGestureDetector;
private final VkRenderer mRenderer;
+ private PointerIcon pointerIcon;
public GodotVulkanRenderView(Context context, Godot godot) {
super(context);
@@ -56,7 +61,9 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
mInputHandler = new GodotInputHandler(this);
mGestureDetector = new GestureDetector(context, new GodotGestureHandler(this));
mRenderer = new VkRenderer();
-
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
+ }
setFocusableInTouchMode(true);
startRenderer(mRenderer);
}
@@ -124,6 +131,21 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
return mInputHandler.onGenericMotionEvent(event);
}
+ /**
+ * called from JNI to change pointer icon
+ */
+ @Keep
+ public void setPointerIcon(int pointerType) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
+ }
+ }
+
+ @Override
+ public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
+ return pointerIcon;
+ }
+
@Override
public void onResume() {
super.onResume();
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 f0e37d80b8..b01dc2653a 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
@@ -115,7 +115,7 @@ open internal class VkSurfaceView(context: Context) : SurfaceView(context), Surf
/**
* Tear down the rendering thread.
*
- * Must not be called before a [VkRenderer] has been set.
+ * Must not be called before a [VkRenderer] has been set.
*/
fun onDestroy() {
vkThread.blockingExit()
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 b967fd5f24..6e59268076 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
@@ -61,6 +61,7 @@ internal class VkThread(private val vkSurfaceView: VkSurfaceView, private val vk
private var rendererInitialized = false
private var rendererResumed = false
private var resumed = false
+ private var surfaceChanged = false
private var hasSurface = false
private var width = 0
private var height = 0
@@ -141,8 +142,10 @@ internal class VkThread(private val vkSurfaceView: VkSurfaceView, private val vk
fun onSurfaceChanged(width: Int, height: Int) {
lock.withLock {
hasSurface = true
+ surfaceChanged = true;
this.width = width
this.height = height
+
lockCondition.signalAll()
}
}
@@ -188,8 +191,11 @@ internal class VkThread(private val vkSurfaceView: VkSurfaceView, private val vk
rendererInitialized = true
vkRenderer.onVkSurfaceCreated(vkSurfaceView.holder.surface)
}
+ }
+ if (surfaceChanged) {
vkRenderer.onVkSurfaceChanged(vkSurfaceView.holder.surface, width, height)
+ surfaceChanged = false
}
// Break out of the loop so drawing can occur without holding onto the lock.
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index f49b0e843a..ed6b5c3e14 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -102,7 +102,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
if (p_args[i]->get_type() != Variant::OBJECT)
arg_expected = Variant::OBJECT;
else {
- Ref<Reference> ref = *p_args[i];
+ Ref<RefCounted> ref = *p_args[i];
if (!ref.is_null()) {
if (Object::cast_to<JavaObject>(ref.ptr())) {
Ref<JavaObject> jo = ref;
@@ -488,7 +488,7 @@ Variant JavaClass::call(const StringName &p_method, const Variant **p_args, int
return ret;
}
- return Reference::call(p_method, p_args, p_argcount, r_error);
+ return RefCounted::call(p_method, p_args, p_argcount, r_error);
}
JavaClass::JavaClass() {
diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
index ec3b6f8ac0..5e99135498 100644
--- a/platform/android/java_godot_io_wrapper.cpp
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -49,6 +49,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
_open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I");
_get_data_dir = p_env->GetMethodID(cls, "getDataDir", "()Ljava/lang/String;");
+ _get_external_data_dir = p_env->GetMethodID(cls, "getExternalDataDir", "()Ljava/lang/String;");
_get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;");
_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
@@ -92,6 +93,17 @@ String GodotIOJavaWrapper::get_user_data_dir() {
}
}
+String GodotIOJavaWrapper::get_external_data_dir() {
+ if (_get_external_data_dir) {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND_V(env == nullptr, String());
+ jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_external_data_dir);
+ return jstring_to_string(s, env);
+ } else {
+ return String();
+ }
+}
+
String GodotIOJavaWrapper::get_locale() {
if (_get_locale) {
JNIEnv *env = get_jni_env();
diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h
index 394e97effa..e4c0a4b2c7 100644
--- a/platform/android/java_godot_io_wrapper.h
+++ b/platform/android/java_godot_io_wrapper.h
@@ -47,6 +47,7 @@ private:
jmethodID _open_URI = 0;
jmethodID _get_data_dir = 0;
+ jmethodID _get_external_data_dir = 0;
jmethodID _get_locale = 0;
jmethodID _get_model = 0;
jmethodID _get_screen_DPI = 0;
@@ -66,6 +67,7 @@ public:
Error open_uri(const String &p_uri);
String get_user_data_dir();
+ String get_external_data_dir();
String get_locale();
String get_model();
int get_screen_dpi();
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 0c342dc280..d59366bb64 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -36,7 +36,6 @@
#include "android/asset_manager_jni.h"
#include "api/java_class_wrapper.h"
#include "api/jni_singleton.h"
-#include "audio_driver_jandroid.h"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/input/input.h"
@@ -94,7 +93,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr);
DirAccessJAndroid::setup(godot_io_java->get_instance());
- AudioDriverAndroid::setup(godot_io_java->get_instance());
NetSocketAndroid::setup(godot_java->get_member_object("netUtils", "Lorg/godotengine/godot/utils/GodotNetUtils;", env));
os_android = new OS_Android(godot_java, godot_io_java, p_use_apk_expansion);
@@ -173,6 +171,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j
os_android->set_native_window(native_window);
DisplayServerAndroid::get_singleton()->reset_window();
+ DisplayServerAndroid::get_singleton()->notify_surface_changed(p_width, p_height);
}
}
}
@@ -384,11 +383,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env,
os_android->main_loop_focusout();
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jclass clazz) {
- setup_android_thread();
- AudioDriverAndroid::thread_func(env);
-}
-
JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jclass clazz, jstring path) {
String js = jstring_to_string(path, env);
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index a3e2933185..63e9e6d8e5 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -56,7 +56,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jclass clazz, jint p_device, jboolean p_connected, jstring p_name);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z);
diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp
index 6b5e44f371..837d2aeced 100644
--- a/platform/android/java_godot_view_wrapper.cpp
+++ b/platform/android/java_godot_view_wrapper.cpp
@@ -43,6 +43,7 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
if (android_get_device_api_level() >= __ANDROID_API_O__) {
_request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V");
_release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V");
+ _set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V");
}
}
@@ -64,6 +65,15 @@ void GodotJavaViewWrapper::release_pointer_capture() {
}
}
+void GodotJavaViewWrapper::set_pointer_icon(int pointer_type) {
+ if (_set_pointer_icon != 0) {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+
+ env->CallVoidMethod(_godot_view, _set_pointer_icon, pointer_type);
+ }
+}
+
GodotJavaViewWrapper::~GodotJavaViewWrapper() {
JNIEnv *env = get_jni_env();
ERR_FAIL_COND(env == nullptr);
diff --git a/platform/android/java_godot_view_wrapper.h b/platform/android/java_godot_view_wrapper.h
index bfb4369fb8..da547d8118 100644
--- a/platform/android/java_godot_view_wrapper.h
+++ b/platform/android/java_godot_view_wrapper.h
@@ -45,12 +45,14 @@ private:
jmethodID _request_pointer_capture = 0;
jmethodID _release_pointer_capture = 0;
+ jmethodID _set_pointer_icon = 0;
public:
GodotJavaViewWrapper(jobject godot_view);
void request_pointer_capture();
void release_pointer_capture();
+ void set_pointer_icon(int pointer_type);
~GodotJavaViewWrapper();
};
diff --git a/platform/android/net_socket_android.cpp b/platform/android/net_socket_android.cpp
index ddc2368793..dbd1870ee6 100644
--- a/platform/android/net_socket_android.cpp
+++ b/platform/android/net_socket_android.cpp
@@ -103,7 +103,7 @@ Error NetSocketAndroid::set_broadcasting_enabled(bool p_enabled) {
return OK;
}
-Error NetSocketAndroid::join_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+Error NetSocketAndroid::join_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
Error err = NetSocketPosix::join_multicast_group(p_multi_address, p_if_name);
if (err != OK)
return err;
@@ -115,7 +115,7 @@ Error NetSocketAndroid::join_multicast_group(const IP_Address &p_multi_address,
return OK;
}
-Error NetSocketAndroid::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+Error NetSocketAndroid::leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
Error err = NetSocketPosix::leave_multicast_group(p_multi_address, p_if_name);
if (err != OK)
return err;
diff --git a/platform/android/net_socket_android.h b/platform/android/net_socket_android.h
index cc2a68ac49..60090c26bb 100644
--- a/platform/android/net_socket_android.h
+++ b/platform/android/net_socket_android.h
@@ -67,8 +67,8 @@ public:
virtual void close();
virtual Error set_broadcasting_enabled(bool p_enabled);
- virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name);
- virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name);
+ virtual Error join_multicast_group(const IPAddress &p_multi_address, String p_if_name);
+ virtual Error leave_multicast_group(const IPAddress &p_multi_address, String p_if_name);
NetSocketAndroid() {}
~NetSocketAndroid();
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 422814dd50..222976d948 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -45,6 +45,23 @@
#include "java_godot_io_wrapper.h"
#include "java_godot_wrapper.h"
+String _remove_symlink(const String &dir) {
+ // Workaround for Android 6.0+ using a symlink.
+ // Save the current directory.
+ char current_dir_name[2048];
+ getcwd(current_dir_name, 2048);
+ // Change directory to the external data directory.
+ chdir(dir.utf8().get_data());
+ // Get the actual directory without the potential symlink.
+ char dir_name_wihout_symlink[2048];
+ getcwd(dir_name_wihout_symlink, 2048);
+ // Convert back to a String.
+ String dir_without_symlink(dir_name_wihout_symlink);
+ // Restore original current directory.
+ chdir(current_dir_name);
+ return dir_without_symlink;
+}
+
class AndroidLogger : public Logger {
public:
virtual void logv(const char *p_format, va_list p_list, bool p_err) {
@@ -199,26 +216,18 @@ String OS_Android::get_user_data_dir() const {
String data_dir = godot_io_java->get_user_data_dir();
if (data_dir != "") {
- //store current dir
- char real_current_dir_name[2048];
- getcwd(real_current_dir_name, 2048);
-
- //go to data dir
- chdir(data_dir.utf8().get_data());
-
- //get actual data dir, so we resolve potential symlink (Android 6.0+ seems to use symlink)
- char data_current_dir_name[2048];
- getcwd(data_current_dir_name, 2048);
-
- //cache by parsing utf8
- data_dir_cache.parse_utf8(data_current_dir_name);
-
- //restore original dir so we don't mess things up
- chdir(real_current_dir_name);
-
+ data_dir_cache = _remove_symlink(data_dir);
return data_dir_cache;
}
+ return ".";
+}
+String OS_Android::get_external_data_dir() const {
+ String data_dir = godot_io_java->get_external_data_dir();
+ if (data_dir != "") {
+ data_dir = _remove_symlink(data_dir);
+ return data_dir;
+ }
return ".";
}
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index dd14b69cf9..1e89e9211d 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -31,7 +31,6 @@
#ifndef OS_ANDROID_H
#define OS_ANDROID_H
-#include "audio_driver_jandroid.h"
#include "audio_driver_opensl.h"
#include "core/os/main_loop.h"
#include "drivers/unix/os_unix.h"
@@ -59,7 +58,6 @@ private:
mutable String data_dir_cache;
- //AudioDriverAndroid audio_driver_android;
AudioDriverOpenSL audio_driver_android;
MainLoop *main_loop;
@@ -111,6 +109,7 @@ public:
virtual Error shell_open(String p_uri) override;
virtual String get_user_data_dir() const override;
+ virtual String get_external_data_dir() const override;
virtual String get_resource_dir() const override;
virtual String get_locale() const override;
virtual String get_model_name() const override;
diff --git a/platform/android/plugin/godot_plugin_config.h b/platform/android/plugin/godot_plugin_config.h
index 173ac115a2..6b708548ae 100644
--- a/platform/android/plugin/godot_plugin_config.h
+++ b/platform/android/plugin/godot_plugin_config.h
@@ -37,8 +37,8 @@
/*
The `config` section and fields are required and defined as follow:
-- **name**: name of the plugin
-- **binary_type**: can be either `local` or `remote`. The type affects the **binary** field
+- **name**: name of the plugin.
+- **binary_type**: can be either `local` or `remote`. The type affects the **binary** field.
- **binary**:
- if **binary_type** is `local`, then this should be the filename of the plugin `aar` file in the `res://android/plugins` directory (e.g: `MyPlugin.aar`).
- if **binary_type** is `remote`, then this should be a declaration for a remote gradle binary (e.g: "org.godot.example:my-plugin:0.0.0").
@@ -102,7 +102,7 @@ struct PluginConfigAndroid {
static inline String resolve_local_dependency_path(String plugin_config_dir, String dependency_path) {
String absolute_path;
if (!dependency_path.is_empty()) {
- if (dependency_path.is_abs_path()) {
+ if (dependency_path.is_absolute_path()) {
absolute_path = ProjectSettings::get_singleton()->globalize_path(dependency_path);
} else {
absolute_path = plugin_config_dir.plus_file(dependency_path);
diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub
index ee7b2f4ab5..58b574a72f 100644
--- a/platform/iphone/SCsub
+++ b/platform/iphone/SCsub
@@ -19,7 +19,6 @@ iphone_lib = [
"godot_view_gesture_recognizer.mm",
"device_metrics.m",
"keyboard_input_view.mm",
- "native_video_view.m",
]
env_ios = env.Clone()
diff --git a/platform/iphone/display_server_iphone.h b/platform/iphone/display_server_iphone.h
index 31a44723a5..34c56382a4 100644
--- a/platform/iphone/display_server_iphone.h
+++ b/platform/iphone/display_server_iphone.h
@@ -99,7 +99,7 @@ public:
// MARK: Touches
- void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick);
+ void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click);
void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y);
void touches_cancelled(int p_idx);
@@ -190,12 +190,6 @@ public:
virtual void screen_set_keep_on(bool p_enable) override;
virtual bool screen_is_kept_on() const override;
- 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) override;
- virtual bool native_video_is_playing() const override;
- virtual void native_video_pause() override;
- virtual void native_video_unpause() override;
- virtual void native_video_stop() override;
-
void resize_window(CGSize size);
};
diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm
index 05dc78bb4d..9e74de0842 100644
--- a/platform/iphone/display_server_iphone.mm
+++ b/platform/iphone/display_server_iphone.mm
@@ -36,7 +36,6 @@
#import "godot_view.h"
#include "ios.h"
#import "keyboard_input_view.h"
-#import "native_video_view.h"
#include "os_iphone.h"
#import "view_controller.h"
@@ -136,13 +135,13 @@ DisplayServerIPhone::~DisplayServerIPhone() {
if (rendering_device_vulkan) {
rendering_device_vulkan->finalize();
memdelete(rendering_device_vulkan);
- rendering_device_vulkan = NULL;
+ rendering_device_vulkan = nullptr;
}
if (context_vulkan) {
context_vulkan->window_destroy(MAIN_WINDOW_ID);
memdelete(context_vulkan);
- context_vulkan = NULL;
+ context_vulkan = nullptr;
}
}
#endif
@@ -222,7 +221,7 @@ void DisplayServerIPhone::_window_callback(const Callable &p_callable, const Var
// MARK: Touches
-void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick) {
+void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) {
if (!GLOBAL_DEF("debug/disable_touch", false)) {
Ref<InputEventScreenTouch> ev;
ev.instance();
@@ -305,7 +304,6 @@ bool DisplayServerIPhone::has_feature(Feature p_feature) const {
// 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:
@@ -569,69 +567,6 @@ bool DisplayServerIPhone::screen_is_kept_on() const {
return [UIApplication sharedApplication].idleTimerDisabled;
}
-Error DisplayServerIPhone::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track, int p_screen) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- bool exists = f && f->is_open();
-
- String user_data_dir = OSIPhone::get_singleton()->get_user_data_dir();
-
- if (!exists) {
- return FAILED;
- }
-
- String tempFile = OSIPhone::get_singleton()->get_user_data_dir();
-
- if (p_path.begins_with("res://")) {
- if (PackedData::get_singleton()->has_path(p_path)) {
- printf("Unable to play %s using the native player as it resides in a .pck file\n", p_path.utf8().get_data());
- return ERR_INVALID_PARAMETER;
- } else {
- p_path = p_path.replace("res:/", ProjectSettings::get_singleton()->get_resource_path());
- }
- } else if (p_path.begins_with("user://")) {
- p_path = p_path.replace("user:/", user_data_dir);
- }
-
- memdelete(f);
-
- printf("Playing video: %s\n", p_path.utf8().get_data());
-
- String file_path = ProjectSettings::get_singleton()->globalize_path(p_path);
-
- NSString *filePath = [[NSString alloc] initWithUTF8String:file_path.utf8().get_data()];
- NSString *audioTrack = [NSString stringWithUTF8String:p_audio_track.utf8()];
- NSString *subtitleTrack = [NSString stringWithUTF8String:p_subtitle_track.utf8()];
-
- if (![AppDelegate.viewController playVideoAtPath:filePath
- volume:p_volume
- audio:audioTrack
- subtitle:subtitleTrack]) {
- return OK;
- }
-
- return FAILED;
-}
-
-bool DisplayServerIPhone::native_video_is_playing() const {
- return [AppDelegate.viewController.videoView isVideoPlaying];
-}
-
-void DisplayServerIPhone::native_video_pause() {
- if (native_video_is_playing()) {
- [AppDelegate.viewController.videoView pauseVideo];
- }
-}
-
-void DisplayServerIPhone::native_video_unpause() {
- [AppDelegate.viewController.videoView unpauseVideo];
-};
-
-void DisplayServerIPhone::native_video_stop() {
- if (native_video_is_playing()) {
- [AppDelegate.viewController.videoView stopVideo];
- }
-}
-
void DisplayServerIPhone::resize_window(CGSize viewSize) {
Size2i size = Size2i(viewSize.width, viewSize.height) * screen_get_max_scale();
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index c585c2afbe..e2df573b09 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -31,11 +31,11 @@
#include "export.h"
#include "core/config/project_settings.h"
+#include "core/io/file_access.h"
#include "core/io/image_loader.h"
#include "core/io/marshalls.h"
#include "core/io/resource_saver.h"
#include "core/io/zip_io.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/templates/safe_refcount.h"
#include "core/version.h"
@@ -353,6 +353,8 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_release", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Distribution"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_release", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/targeted_device_family", PROPERTY_HINT_ENUM, "iPhone,iPad,iPhone & iPad"), 2));
+
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
@@ -378,11 +380,6 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape_left"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape_right"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait_upside_down"), true));
-
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "icons/generate_missing"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone/iPod Touch with retina display
@@ -453,6 +450,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n";
} else if (lines[i].find("$team_id") != -1) {
strnew += lines[i].replace("$team_id", p_preset->get("application/app_store_team_id")) + "\n";
+ } else if (lines[i].find("$default_build_config") != -1) {
+ strnew += lines[i].replace("$default_build_config", p_debug ? "Debug" : "Release") + "\n";
} else if (lines[i].find("$export_method") != -1) {
int export_method = p_preset->get(p_debug ? "application/export_method_debug" : "application/export_method_release");
strnew += lines[i].replace("$export_method", export_method_string[export_method]) + "\n";
@@ -473,6 +472,20 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$godot_archs", p_config.architectures) + "\n";
} else if (lines[i].find("$linker_flags") != -1) {
strnew += lines[i].replace("$linker_flags", p_config.linker_flags) + "\n";
+ } else if (lines[i].find("$targeted_device_family") != -1) {
+ String xcode_value;
+ switch ((int)p_preset->get("application/targeted_device_family")) {
+ case 0: // iPhone
+ xcode_value = "1";
+ break;
+ case 1: // iPad
+ xcode_value = "2";
+ break;
+ case 2: // iPhone & iPad
+ xcode_value = "1,2";
+ break;
+ }
+ strnew += lines[i].replace("$targeted_device_family", xcode_value) + "\n";
} else if (lines[i].find("$cpp_code") != -1) {
strnew += lines[i].replace("$cpp_code", p_config.cpp_code) + "\n";
} else if (lines[i].find("$docs_in_place") != -1) {
@@ -501,18 +514,39 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$required_device_capabilities", capabilities);
} else if (lines[i].find("$interface_orientations") != -1) {
String orientations;
+ const DisplayServer::ScreenOrientation screen_orientation =
+ DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation")));
- if ((bool)p_preset->get("orientation/portrait")) {
- orientations += "<string>UIInterfaceOrientationPortrait</string>\n";
- }
- if ((bool)p_preset->get("orientation/landscape_left")) {
- orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n";
- }
- if ((bool)p_preset->get("orientation/landscape_right")) {
- orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n";
- }
- if ((bool)p_preset->get("orientation/portrait_upside_down")) {
- orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n";
+ switch (screen_orientation) {
+ case DisplayServer::SCREEN_LANDSCAPE:
+ orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n";
+ break;
+ case DisplayServer::SCREEN_PORTRAIT:
+ orientations += "<string>UIInterfaceOrientationPortrait</string>\n";
+ break;
+ case DisplayServer::SCREEN_REVERSE_LANDSCAPE:
+ orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n";
+ break;
+ case DisplayServer::SCREEN_REVERSE_PORTRAIT:
+ orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n";
+ break;
+ case DisplayServer::SCREEN_SENSOR_LANDSCAPE:
+ // Allow both landscape orientations depending on sensor direction.
+ orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n";
+ orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n";
+ break;
+ case DisplayServer::SCREEN_SENSOR_PORTRAIT:
+ // Allow both portrait orientations depending on sensor direction.
+ orientations += "<string>UIInterfaceOrientationPortrait</string>\n";
+ orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n";
+ break;
+ case DisplayServer::SCREEN_SENSOR:
+ // Allow all screen orientations depending on sensor direction.
+ orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n";
+ orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n";
+ orientations += "<string>UIInterfaceOrientationPortrait</string>\n";
+ orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n";
+ break;
}
strnew += lines[i].replace("$interface_orientations", orientations);
diff --git a/platform/iphone/godot_app_delegate.m b/platform/iphone/godot_app_delegate.m
index 3ce9bffc79..6c433c5c3c 100644
--- a/platform/iphone/godot_app_delegate.m
+++ b/platform/iphone/godot_app_delegate.m
@@ -56,7 +56,7 @@ static NSMutableArray<ApplicationDelegateService *> *services = nil;
[services addObject:service];
}
-// UIApplicationDelegate documantation can be found here: https://developer.apple.com/documentation/uikit/uiapplicationdelegate
+// UIApplicationDelegate documentation can be found here: https://developer.apple.com/documentation/uikit/uiapplicationdelegate
// MARK: Window
diff --git a/platform/iphone/godot_iphone.mm b/platform/iphone/godot_iphone.mm
index 62bc2e6e52..6c3e1eabde 100644
--- a/platform/iphone/godot_iphone.mm
+++ b/platform/iphone/godot_iphone.mm
@@ -50,7 +50,7 @@ int add_path(int p_argc, char **p_args) {
p_args[p_argc++] = (char *)"--path";
p_args[p_argc++] = (char *)[str cStringUsingEncoding:NSUTF8StringEncoding];
- p_args[p_argc] = NULL;
+ p_args[p_argc] = nullptr;
return p_argc;
};
@@ -69,7 +69,7 @@ int add_cmdline(int p_argc, char **p_args) {
p_args[p_argc++] = (char *)[str cStringUsingEncoding:NSUTF8StringEncoding];
};
- p_args[p_argc] = NULL;
+ p_args[p_argc] = nullptr;
return p_argc;
};
diff --git a/platform/iphone/godot_view.mm b/platform/iphone/godot_view.mm
index 468fa2928a..00a88d79c5 100644
--- a/platform/iphone/godot_view.mm
+++ b/platform/iphone/godot_view.mm
@@ -291,14 +291,14 @@ static const float earth_gravity = 9.80665;
- (void)initTouches {
for (int i = 0; i < max_touches; i++) {
- godot_touches[i] = NULL;
+ godot_touches[i] = nullptr;
}
}
- (int)getTouchIDForTouch:(UITouch *)p_touch {
int first = -1;
for (int i = 0; i < max_touches; i++) {
- if (first == -1 && godot_touches[i] == NULL) {
+ if (first == -1 && godot_touches[i] == nullptr) {
first = i;
continue;
}
@@ -318,11 +318,11 @@ static const float earth_gravity = 9.80665;
- (int)removeTouch:(UITouch *)p_touch {
int remaining = 0;
for (int i = 0; i < max_touches; i++) {
- if (godot_touches[i] == NULL) {
+ if (godot_touches[i] == nullptr) {
continue;
}
if (godot_touches[i] == p_touch) {
- godot_touches[i] = NULL;
+ godot_touches[i] = nullptr;
} else {
++remaining;
}
@@ -332,7 +332,7 @@ static const float earth_gravity = 9.80665;
- (void)clearTouches {
for (int i = 0; i < max_touches; i++) {
- godot_touches[i] = NULL;
+ godot_touches[i] = nullptr;
}
}
diff --git a/platform/iphone/ios.mm b/platform/iphone/ios.mm
index cef03534c4..3430a9cba7 100644
--- a/platform/iphone/ios.mm
+++ b/platform/iphone/ios.mm
@@ -56,16 +56,16 @@ void iOS::alert(const char *p_alert, const char *p_title) {
String iOS::get_model() const {
// [[UIDevice currentDevice] model] only returns "iPad" or "iPhone".
size_t size;
- sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+ sysctlbyname("hw.machine", nullptr, &size, nullptr, 0);
char *model = (char *)malloc(size);
- if (model == NULL) {
+ if (model == nullptr) {
return "";
}
- sysctlbyname("hw.machine", model, &size, NULL, 0);
+ sysctlbyname("hw.machine", model, &size, nullptr, 0);
NSString *platform = [NSString stringWithCString:model encoding:NSUTF8StringEncoding];
free(model);
const char *str = [platform UTF8String];
- return String(str != NULL ? str : "");
+ return String(str != nullptr ? str : "");
}
String iOS::get_rate_url(int p_app_id) const {
diff --git a/platform/iphone/keyboard_input_view.mm b/platform/iphone/keyboard_input_view.mm
index 1408f78e90..0e5a98a3e6 100644
--- a/platform/iphone/keyboard_input_view.mm
+++ b/platform/iphone/keyboard_input_view.mm
@@ -88,13 +88,15 @@
self.text = existingString;
self.previousText = existingString;
+ NSInteger safeStartIndex = MAX(start, 0);
+
NSRange textRange;
// Either a simple cursor or a selection.
if (end > 0) {
- textRange = NSMakeRange(start, end - start);
+ textRange = NSMakeRange(safeStartIndex, end - start);
} else {
- textRange = NSMakeRange(start, 0);
+ textRange = NSMakeRange(safeStartIndex, 0);
}
self.selectedRange = textRange;
diff --git a/platform/iphone/native_video_view.h b/platform/iphone/native_video_view.h
deleted file mode 100644
index 2df5e27fa4..0000000000
--- a/platform/iphone/native_video_view.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*************************************************************************/
-/* native_video_view.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#import <UIKit/UIKit.h>
-
-@interface GodotNativeVideoView : UIView
-
-- (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NSString *)audioTrack subtitle:(NSString *)subtitleTrack;
-- (BOOL)isVideoPlaying;
-- (void)pauseVideo;
-- (void)unpauseVideo;
-- (void)stopVideo;
-
-@end
diff --git a/platform/iphone/native_video_view.m b/platform/iphone/native_video_view.m
deleted file mode 100644
index f126749600..0000000000
--- a/platform/iphone/native_video_view.m
+++ /dev/null
@@ -1,266 +0,0 @@
-/*************************************************************************/
-/* native_video_view.m */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#import "native_video_view.h"
-#import <AVFoundation/AVFoundation.h>
-
-@interface GodotNativeVideoView ()
-
-@property(strong, nonatomic) AVAsset *avAsset;
-@property(strong, nonatomic) AVPlayerItem *avPlayerItem;
-@property(strong, nonatomic) AVPlayer *avPlayer;
-@property(strong, nonatomic) AVPlayerLayer *avPlayerLayer;
-@property(assign, nonatomic) CMTime videoCurrentTime;
-@property(assign, nonatomic) BOOL isVideoCurrentlyPlaying;
-
-@end
-
-@implementation GodotNativeVideoView
-
-- (instancetype)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
-
- if (self) {
- [self godot_commonInit];
- }
-
- return self;
-}
-
-- (instancetype)initWithCoder:(NSCoder *)coder {
- self = [super initWithCoder:coder];
-
- if (self) {
- [self godot_commonInit];
- }
-
- return self;
-}
-
-- (void)godot_commonInit {
- self.isVideoCurrentlyPlaying = NO;
- self.videoCurrentTime = kCMTimeZero;
-
- [self observeVideoAudio];
-}
-
-- (void)layoutSubviews {
- [super layoutSubviews];
-
- self.avPlayerLayer.frame = self.bounds;
-}
-
-- (void)observeVideoAudio {
- printf("******** adding observer for sound routing changes\n");
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(audioRouteChangeListenerCallback:)
- name:AVAudioSessionRouteChangeNotification
- object:nil];
-}
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
- if (object == self.avPlayerItem && [keyPath isEqualToString:@"status"]) {
- [self handleVideoOrPlayerStatus];
- }
-
- if (object == self.avPlayer && [keyPath isEqualToString:@"rate"]) {
- [self handleVideoPlayRate];
- }
-}
-
-// MARK: Video Audio
-
-- (void)audioRouteChangeListenerCallback:(NSNotification *)notification {
- printf("*********** route changed!\n");
- NSDictionary *interuptionDict = notification.userInfo;
-
- NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
-
- switch (routeChangeReason) {
- case AVAudioSessionRouteChangeReasonNewDeviceAvailable: {
- NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable");
- NSLog(@"Headphone/Line plugged in");
- } break;
- case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: {
- NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable");
- NSLog(@"Headphone/Line was pulled. Resuming video play....");
- if ([self isVideoPlaying]) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
- [self.avPlayer play]; // NOTE: change this line according your current player implementation
- NSLog(@"resumed play");
- });
- }
- } break;
- case AVAudioSessionRouteChangeReasonCategoryChange: {
- // called at start - also when other audio wants to play
- NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");
- } break;
- }
-}
-
-// MARK: Native Video Player
-
-- (void)handleVideoOrPlayerStatus {
- if (self.avPlayerItem.status == AVPlayerItemStatusFailed || self.avPlayer.status == AVPlayerStatusFailed) {
- [self stopVideo];
- }
-
- if (self.avPlayer.status == AVPlayerStatusReadyToPlay && self.avPlayerItem.status == AVPlayerItemStatusReadyToPlay && CMTimeCompare(self.videoCurrentTime, kCMTimeZero) == 0) {
- // NSLog(@"time: %@", self.video_current_time);
- [self.avPlayer seekToTime:self.videoCurrentTime];
- self.videoCurrentTime = kCMTimeZero;
- }
-}
-
-- (void)handleVideoPlayRate {
- NSLog(@"Player playback rate changed: %.5f", self.avPlayer.rate);
- if ([self isVideoPlaying] && self.avPlayer.rate == 0.0 && !self.avPlayer.error) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
- [self.avPlayer play]; // NOTE: change this line according your current player implementation
- NSLog(@"resumed play");
- });
-
- NSLog(@" . . . PAUSED (or just started)");
- }
-}
-
-- (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NSString *)audioTrack subtitle:(NSString *)subtitleTrack {
- self.avAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:filePath]];
-
- self.avPlayerItem = [AVPlayerItem playerItemWithAsset:self.avAsset];
- [self.avPlayerItem addObserver:self forKeyPath:@"status" options:0 context:nil];
-
- self.avPlayer = [AVPlayer playerWithPlayerItem:self.avPlayerItem];
- self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
-
- [self.avPlayer addObserver:self forKeyPath:@"status" options:0 context:nil];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(playerItemDidReachEnd:)
- name:AVPlayerItemDidPlayToEndTimeNotification
- object:[self.avPlayer currentItem]];
-
- [self.avPlayer addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:0];
-
- [self.avPlayerLayer setFrame:self.bounds];
- [self.layer addSublayer:self.avPlayerLayer];
- [self.avPlayer play];
-
- AVMediaSelectionGroup *audioGroup = [self.avAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible];
-
- NSMutableArray *allAudioParams = [NSMutableArray array];
- for (id track in audioGroup.options) {
- NSString *language = [[track locale] localeIdentifier];
- NSLog(@"subtitle lang: %@", language);
-
- if ([language isEqualToString:audioTrack]) {
- AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
- [audioInputParams setVolume:videoVolume atTime:kCMTimeZero];
- [audioInputParams setTrackID:[track trackID]];
- [allAudioParams addObject:audioInputParams];
-
- AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
- [audioMix setInputParameters:allAudioParams];
-
- [self.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup:audioGroup];
- [self.avPlayer.currentItem setAudioMix:audioMix];
-
- break;
- }
- }
-
- AVMediaSelectionGroup *subtitlesGroup = [self.avAsset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible];
- NSArray *useableTracks = [AVMediaSelectionGroup mediaSelectionOptionsFromArray:subtitlesGroup.options withoutMediaCharacteristics:[NSArray arrayWithObject:AVMediaCharacteristicContainsOnlyForcedSubtitles]];
-
- for (id track in useableTracks) {
- NSString *language = [[track locale] localeIdentifier];
- NSLog(@"subtitle lang: %@", language);
-
- if ([language isEqualToString:subtitleTrack]) {
- [self.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup:subtitlesGroup];
- break;
- }
- }
-
- self.isVideoCurrentlyPlaying = YES;
-
- return true;
-}
-
-- (BOOL)isVideoPlaying {
- if (self.avPlayer.error) {
- printf("Error during playback\n");
- }
- return (self.avPlayer.rate > 0 && !self.avPlayer.error);
-}
-
-- (void)pauseVideo {
- self.videoCurrentTime = self.avPlayer.currentTime;
- [self.avPlayer pause];
- self.isVideoCurrentlyPlaying = NO;
-}
-
-- (void)unpauseVideo {
- [self.avPlayer play];
- self.isVideoCurrentlyPlaying = YES;
-}
-
-- (void)playerItemDidReachEnd:(NSNotification *)notification {
- [self stopVideo];
-}
-
-- (void)finishPlayingVideo {
- [self.avPlayer pause];
- [self.avPlayerLayer removeFromSuperlayer];
- self.avPlayerLayer = nil;
-
- if (self.avPlayerItem) {
- [self.avPlayerItem removeObserver:self forKeyPath:@"status"];
- self.avPlayerItem = nil;
- }
-
- if (self.avPlayer) {
- [self.avPlayer removeObserver:self forKeyPath:@"status"];
- self.avPlayer = nil;
- }
-
- self.avAsset = nil;
-
- self.isVideoCurrentlyPlaying = NO;
-}
-
-- (void)stopVideo {
- [self finishPlayingVideo];
-
- [self removeFromSuperview];
-}
-
-@end
diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm
index 51c4da2960..1f08901082 100644
--- a/platform/iphone/os_iphone.mm
+++ b/platform/iphone/os_iphone.mm
@@ -33,9 +33,9 @@
#include "os_iphone.h"
#import "app_delegate.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/file_access_pack.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "display_server_iphone.h"
#include "drivers/unix/syslog_logger.h"
#import "godot_view.h"
@@ -301,10 +301,6 @@ void OSIPhone::on_focus_out() {
[AppDelegate.viewController.godotView stopRendering];
- if (DisplayServerIPhone::get_singleton() && DisplayServerIPhone::get_singleton()->native_video_is_playing()) {
- DisplayServerIPhone::get_singleton()->native_video_pause();
- }
-
audio_driver.stop();
}
}
@@ -319,10 +315,6 @@ void OSIPhone::on_focus_in() {
[AppDelegate.viewController.godotView startRendering];
- if (DisplayServerIPhone::get_singleton() && DisplayServerIPhone::get_singleton()->native_video_is_playing()) {
- DisplayServerIPhone::get_singleton()->native_video_unpause();
- }
-
audio_driver.start();
}
}
diff --git a/platform/iphone/plugin/godot_plugin_config.h b/platform/iphone/plugin/godot_plugin_config.h
index e2546e733c..4d0c67bfff 100644
--- a/platform/iphone/plugin/godot_plugin_config.h
+++ b/platform/iphone/plugin/godot_plugin_config.h
@@ -104,7 +104,7 @@ static inline String resolve_local_dependency_path(String plugin_config_dir, Str
return absolute_path;
}
- if (dependency_path.is_abs_path()) {
+ if (dependency_path.is_absolute_path()) {
return dependency_path;
}
@@ -121,7 +121,7 @@ static inline String resolve_system_dependency_path(String dependency_path) {
return absolute_path;
}
- if (dependency_path.is_abs_path()) {
+ if (dependency_path.is_absolute_path()) {
return dependency_path;
}
diff --git a/platform/iphone/view_controller.h b/platform/iphone/view_controller.h
index 52fb6fbbf2..400145b8b7 100644
--- a/platform/iphone/view_controller.h
+++ b/platform/iphone/view_controller.h
@@ -37,11 +37,6 @@
@interface ViewController : UIViewController
@property(nonatomic, readonly, strong) GodotView *godotView;
-@property(nonatomic, readonly, strong) GodotNativeVideoView *videoView;
@property(nonatomic, readonly, strong) GodotKeyboardInputView *keyboardView;
-// MARK: Native Video Player
-
-- (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NSString *)audioTrack subtitle:(NSString *)subtitleTrack;
-
@end
diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm
index 6cef244567..2723ac4706 100644
--- a/platform/iphone/view_controller.mm
+++ b/platform/iphone/view_controller.mm
@@ -34,7 +34,6 @@
#import "godot_view.h"
#import "godot_view_renderer.h"
#import "keyboard_input_view.h"
-#import "native_video_view.h"
#include "os_iphone.h"
#import <AVFoundation/AVFoundation.h>
@@ -43,7 +42,6 @@
@interface ViewController () <GodotViewDelegate>
@property(strong, nonatomic) GodotViewRenderer *renderer;
-@property(strong, nonatomic) GodotNativeVideoView *videoView;
@property(strong, nonatomic) GodotKeyboardInputView *keyboardView;
@property(strong, nonatomic) UIView *godotLoadingOverlay;
@@ -151,10 +149,6 @@
}
- (void)dealloc {
- [self.videoView stopVideo];
-
- self.videoView = nil;
-
self.keyboardView = nil;
self.renderer = nil;
@@ -243,22 +237,4 @@
}
}
-// MARK: Native Video Player
-
-- (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NSString *)audioTrack subtitle:(NSString *)subtitleTrack {
- // If we are showing some video already, reuse existing view for new video.
- if (self.videoView) {
- return [self.videoView playVideoAtPath:filePath volume:videoVolume audio:audioTrack subtitle:subtitleTrack];
- } else {
- // Create autoresizing view for video playback.
- GodotNativeVideoView *videoView = [[GodotNativeVideoView alloc] initWithFrame:self.view.bounds];
- videoView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- [self.view addSubview:videoView];
-
- self.videoView = videoView;
-
- return [self.videoView playVideoAtPath:filePath volume:videoVolume audio:audioTrack subtitle:subtitleTrack];
- }
-}
-
@end
diff --git a/platform/iphone/vulkan_context_iphone.mm b/platform/iphone/vulkan_context_iphone.mm
index b980ae99f0..08c9007fbb 100644
--- a/platform/iphone/vulkan_context_iphone.mm
+++ b/platform/iphone/vulkan_context_iphone.mm
@@ -38,13 +38,13 @@ const char *VulkanContextIPhone::_get_platform_surface_extension() const {
Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, CALayer *p_metal_layer, int p_width, int p_height) {
VkIOSSurfaceCreateInfoMVK createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
- createInfo.pNext = NULL;
+ createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.pView = (__bridge const void *)p_metal_layer;
VkSurfaceKHR surface;
VkResult err =
- vkCreateIOSSurfaceMVK(_get_instance(), &createInfo, NULL, &surface);
+ vkCreateIOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
return _window_create(p_window_id, surface, p_width, p_height);
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index a760e36982..62a8660ae4 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -6,7 +6,7 @@ javascript_files = [
"audio_driver_javascript.cpp",
"display_server_javascript.cpp",
"http_client_javascript.cpp",
- "javascript_eval.cpp",
+ "javascript_singleton.cpp",
"javascript_main.cpp",
"os_javascript.cpp",
"api/javascript_tools_editor_plugin.cpp",
@@ -23,10 +23,8 @@ sys_env.AddJSLibraries(
]
)
-if env["tools"]:
- sys_env.AddJSLibraries(["js/libs/library_godot_editor_tools.js"])
if env["javascript_eval"]:
- sys_env.AddJSLibraries(["js/libs/library_godot_eval.js"])
+ sys_env.AddJSLibraries(["js/libs/library_godot_javascript_singleton.js"])
for lib in sys_env["JS_LIBS"]:
sys_env.Append(LINKFLAGS=["--js-library", lib])
@@ -47,6 +45,7 @@ if env["gdnative_enabled"]:
sys_env.Append(LINKFLAGS=["-s", "MAIN_MODULE=1"])
sys_env.Append(CCFLAGS=["-s", "EXPORT_ALL=1"])
sys_env.Append(LINKFLAGS=["-s", "EXPORT_ALL=1"])
+ sys_env.Append(LINKFLAGS=["-s", "WARN_ON_UNDEFINED_SYMBOLS=0"])
# Force exporting the standard library (printf, malloc, etc.)
sys_env["ENV"]["EMCC_FORCE_STDLIBS"] = "libc,libc++,libc++abi"
# The main emscripten runtime, with exported standard libraries.
diff --git a/platform/javascript/api/api.cpp b/platform/javascript/api/api.cpp
index 2f7bde065f..5ad2bf56cf 100644
--- a/platform/javascript/api/api.cpp
+++ b/platform/javascript/api/api.cpp
@@ -30,13 +30,14 @@
#include "api.h"
#include "core/config/engine.h"
-#include "javascript_eval.h"
+#include "javascript_singleton.h"
#include "javascript_tools_editor_plugin.h"
static JavaScript *javascript_eval;
void register_javascript_api() {
JavaScriptToolsEditorPlugin::initialize();
+ ClassDB::register_virtual_class<JavaScriptObject>();
ClassDB::register_virtual_class<JavaScript>();
javascript_eval = memnew(JavaScript);
Engine::get_singleton()->add_singleton(Engine::Singleton("JavaScript", javascript_eval));
@@ -61,10 +62,46 @@ JavaScript::~JavaScript() {}
void JavaScript::_bind_methods() {
ClassDB::bind_method(D_METHOD("eval", "code", "use_global_execution_context"), &JavaScript::eval, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_interface", "interface"), &JavaScript::get_interface);
+ ClassDB::bind_method(D_METHOD("create_callback", "callable"), &JavaScript::create_callback);
+ {
+ MethodInfo mi;
+ mi.name = "create_object";
+ mi.arguments.push_back(PropertyInfo(Variant::STRING, "object"));
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_object", &JavaScript::_create_object_bind, mi);
+ }
+ ClassDB::bind_method(D_METHOD("download_buffer", "buffer", "name", "mime"), &JavaScript::download_buffer, DEFVAL("application/octet-stream"));
}
#if !defined(JAVASCRIPT_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED)
Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
return Variant();
}
+
+Ref<JavaScriptObject> JavaScript::get_interface(const String &p_interface) {
+ return Ref<JavaScriptObject>();
+}
+
+Ref<JavaScriptObject> JavaScript::create_callback(const Callable &p_callable) {
+ return Ref<JavaScriptObject>();
+}
+
+Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_argcount < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ return Ref<JavaScriptObject>();
+ }
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ return Ref<JavaScriptObject>();
+ }
+ return Ref<JavaScriptObject>();
+}
+#endif
+#if !defined(JAVASCRIPT_ENABLED)
+void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
+}
#endif
diff --git a/platform/javascript/api/javascript_singleton.h b/platform/javascript/api/javascript_singleton.h
new file mode 100644
index 0000000000..9d7a392278
--- /dev/null
+++ b/platform/javascript/api/javascript_singleton.h
@@ -0,0 +1,68 @@
+/*************************************************************************/
+/* javascript_singleton.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef JAVASCRIPT_SINGLETON_H
+#define JAVASCRIPT_SINGLETON_H
+
+#include "core/object/class_db.h"
+#include "core/object/ref_counted.h"
+
+class JavaScriptObject : public RefCounted {
+private:
+ GDCLASS(JavaScriptObject, RefCounted);
+
+protected:
+ virtual bool _set(const StringName &p_name, const Variant &p_value) { return false; }
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const { return false; }
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const {}
+};
+
+class JavaScript : public Object {
+private:
+ GDCLASS(JavaScript, Object);
+
+ static JavaScript *singleton;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Variant eval(const String &p_code, bool p_use_global_exec_context = false);
+ Ref<JavaScriptObject> get_interface(const String &p_interface);
+ Ref<JavaScriptObject> create_callback(const Callable &p_callable);
+ Variant _create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ void download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime = "application/octet-stream");
+
+ static JavaScript *get_singleton();
+ JavaScript();
+ ~JavaScript();
+};
+
+#endif // JAVASCRIPT_SINGLETON_H
diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/javascript/api/javascript_tools_editor_plugin.cpp
index 8355faccc2..54f541f607 100644
--- a/platform/javascript/api/javascript_tools_editor_plugin.cpp
+++ b/platform/javascript/api/javascript_tools_editor_plugin.cpp
@@ -33,15 +33,15 @@
#include "core/config/engine.h"
#include "core/config/project_settings.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "editor/editor_node.h"
#include <emscripten/emscripten.h>
// JavaScript functions defined in library_godot_editor_tools.js
extern "C" {
-extern void godot_js_editor_download_file(const char *p_path, const char *p_name, const char *p_mime);
+extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime);
}
static void _javascript_editor_init_callback() {
@@ -65,11 +65,16 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) {
FileAccess *src_f;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- zipFile zip = zipOpen2("/tmp/project.zip", APPEND_STATUS_CREATE, NULL, &io);
+ zipFile zip = zipOpen2("/tmp/project.zip", APPEND_STATUS_CREATE, nullptr, &io);
String base_path = resource_path.substr(0, resource_path.rfind("/")) + "/";
_zip_recursive(resource_path, base_path, zip);
- zipClose(zip, NULL);
- godot_js_editor_download_file("/tmp/project.zip", "project.zip", "application/zip");
+ zipClose(zip, nullptr);
+ FileAccess *f = FileAccess::open("/tmp/project.zip", FileAccess::READ);
+ ERR_FAIL_COND_MSG(!f, "Unable to create zip file");
+ Vector<uint8_t> buf;
+ buf.resize(f->get_length());
+ f->get_buffer(buf.ptrw(), buf.size());
+ godot_js_os_download_buffer(buf.ptr(), buf.size(), "project.zip", "application/zip");
}
void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, zipFile p_zip) {
@@ -79,7 +84,7 @@ void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, z
return;
}
Vector<uint8_t> data;
- int len = f->get_len();
+ uint64_t len = f->get_length();
data.resize(len);
f->get_buffer(data.ptrw(), len);
f->close();
@@ -88,12 +93,12 @@ void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, z
String path = p_path.replace_first(p_base_path, "");
zipOpenNewFileInZip(p_zip,
path.utf8().get_data(),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
zipWriteInFileInZip(p_zip, data.ptr(), data.size());
@@ -116,12 +121,12 @@ void JavaScriptToolsEditorPlugin::_zip_recursive(String p_path, String p_base_pa
String path = cs.replace_first(p_base_path, "") + "/";
zipOpenNewFileInZip(p_zip,
path.utf8().get_data(),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
zipCloseFileInZip(p_zip);
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 09c4bd931a..da6adc4cd8 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -53,6 +53,7 @@ def get_flags():
# in this platform. For the available networking methods, the browser
# manages TLS.
("module_mbedtls_enabled", False),
+ ("vulkan", False),
]
@@ -175,7 +176,7 @@ def configure(env):
# Program() output consists of multiple files, so specify suffixes manually at builder.
env["PROGSUFFIX"] = ""
env["LIBPREFIX"] = "lib"
- env["LIBSUFFIX"] = ".bc"
+ env["LIBSUFFIX"] = ".a"
env["LIBPREFIXES"] = ["$LIBPREFIX"]
env["LIBSUFFIXES"] = ["$LIBSUFFIX"]
@@ -229,8 +230,8 @@ def configure(env):
# Allow use to take control of swapping WebGL buffers.
env.Append(LINKFLAGS=["-s", "OFFSCREEN_FRAMEBUFFER=1"])
- # callMain for manual start.
- env.Append(LINKFLAGS=["-s", "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain','cwrap']"])
+ # callMain for manual start, cwrap for the mono version.
+ env.Append(LINKFLAGS=["-s", "EXPORTED_RUNTIME_METHODS=['callMain','cwrap']"])
# Add code that allow exiting runtime.
env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"])
@@ -239,6 +240,6 @@ def configure(env):
env.Append(
LINKFLAGS=[
"-s",
- "EXPORTED_FUNCTIONS=['_main', '_emscripten_webgl_get_current_context', '_emscripten_webgl_commit_frame', '_emscripten_webgl_create_context']",
+ "EXPORTED_FUNCTIONS=['_main', '_emscripten_webgl_get_current_context']",
]
)
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index fa6f5c1e9e..1cc05a2e19 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -30,8 +30,8 @@
#include "platform/javascript/display_server_javascript.h"
-#include "drivers/dummy/rasterizer_dummy.h"
#include "platform/javascript/os_javascript.h"
+#include "servers/rendering/rasterizer_dummy.h"
#include <emscripten.h>
#include <png.h>
@@ -120,10 +120,10 @@ void DisplayServerJavaScript::request_quit_callback() {
template <typename T>
void DisplayServerJavaScript::dom2godot_mod(T *emscripten_event_ptr, Ref<InputEventWithModifiers> godot_event) {
- godot_event->set_shift(emscripten_event_ptr->shiftKey);
- godot_event->set_alt(emscripten_event_ptr->altKey);
- godot_event->set_control(emscripten_event_ptr->ctrlKey);
- godot_event->set_metakey(emscripten_event_ptr->metaKey);
+ godot_event->set_shift_pressed(emscripten_event_ptr->shiftKey);
+ godot_event->set_alt_pressed(emscripten_event_ptr->altKey);
+ godot_event->set_ctrl_pressed(emscripten_event_ptr->ctrlKey);
+ godot_event->set_meta_pressed(emscripten_event_ptr->metaKey);
}
Ref<InputEventKey> DisplayServerJavaScript::setup_key_event(const EmscriptenKeyboardEvent *emscripten_event) {
@@ -215,14 +215,14 @@ EM_BOOL DisplayServerJavaScript::mouse_button_callback(int p_event_type, const E
display->last_click_ms = 0;
display->last_click_pos = Point2(-100, -100);
display->last_click_button_index = -1;
- ev->set_doubleclick(true);
+ ev->set_double_click(true);
}
} else {
display->last_click_button_index = ev->get_button_index();
}
- if (!ev->is_doubleclick()) {
+ if (!ev->is_double_click()) {
display->last_click_ms += diff;
display->last_click_pos = ev->get_position();
}
@@ -399,7 +399,7 @@ void DisplayServerJavaScript::cursor_set_custom_image(const RES &p_cursor, Curso
godot_js_display_cursor_set_custom_shape(godot2dom_cursor(p_shape), png.ptr(), len, p_hotspot.x, p_hotspot.y);
} else {
- godot_js_display_cursor_set_custom_shape(godot2dom_cursor(p_shape), NULL, 0, 0, 0);
+ godot_js_display_cursor_set_custom_shape(godot2dom_cursor(p_shape), nullptr, 0, 0, 0);
}
cursor_set_shape(cursor_shape);
@@ -407,9 +407,10 @@ void DisplayServerJavaScript::cursor_set_custom_image(const RES &p_cursor, Curso
// Mouse mode
void DisplayServerJavaScript::mouse_set_mode(MouseMode p_mode) {
- ERR_FAIL_COND_MSG(p_mode == MOUSE_MODE_CONFINED, "MOUSE_MODE_CONFINED is not supported for the HTML5 platform.");
- if (p_mode == mouse_get_mode())
+ ERR_FAIL_COND_MSG(p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN, "MOUSE_MODE_CONFINED is not supported for the HTML5 platform.");
+ if (p_mode == mouse_get_mode()) {
return;
+ }
if (p_mode == MOUSE_MODE_VISIBLE) {
godot_js_display_cursor_set_visible(1);
@@ -455,10 +456,10 @@ EM_BOOL DisplayServerJavaScript::wheel_callback(int p_event_type, const Emscript
ev->set_position(input->get_mouse_position());
ev->set_global_position(ev->get_position());
- ev->set_shift(input->is_key_pressed(KEY_SHIFT));
- ev->set_alt(input->is_key_pressed(KEY_ALT));
- ev->set_control(input->is_key_pressed(KEY_CONTROL));
- ev->set_metakey(input->is_key_pressed(KEY_META));
+ ev->set_shift_pressed(input->is_key_pressed(KEY_SHIFT));
+ ev->set_alt_pressed(input->is_key_pressed(KEY_ALT));
+ ev->set_ctrl_pressed(input->is_key_pressed(KEY_CTRL));
+ ev->set_meta_pressed(input->is_key_pressed(KEY_META));
if (p_event->deltaY < 0)
ev->set_button_index(MOUSE_BUTTON_WHEEL_UP);
@@ -536,7 +537,7 @@ bool DisplayServerJavaScript::screen_is_touchscreen(int p_screen) const {
return godot_js_display_touchscreen_is_available();
}
-// Virtual Keybaord
+// Virtual Keyboard
void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_cursor) {
DisplayServerJavaScript *ds = DisplayServerJavaScript::get_singleton();
if (!ds || ds->input_text_callback.is_null()) {
@@ -771,8 +772,8 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
#define SET_EM_CALLBACK(target, ev, cb) \
result = emscripten_set_##ev##_callback(target, nullptr, true, &cb); \
EM_CHECK(ev)
-#define SET_EM_WINDOW_CALLBACK(ev, cb) \
- result = emscripten_set_##ev##_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, &cb); \
+#define SET_EM_WINDOW_CALLBACK(ev, cb) \
+ result = emscripten_set_##ev##_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, false, &cb); \
EM_CHECK(ev)
// These callbacks from Emscripten's html5.h suffice to access most
// JavaScript APIs.
@@ -827,7 +828,6 @@ bool DisplayServerJavaScript::has_feature(Feature p_feature) const {
//case FEATURE_MOUSE_WARP:
//case FEATURE_NATIVE_DIALOG:
//case FEATURE_NATIVE_ICON:
- //case FEATURE_NATIVE_VIDEO:
//case FEATURE_WINDOW_TRANSPARENCY:
//case FEATURE_KEEP_SCREEN_ON:
//case FEATURE_ORIENTATION:
diff --git a/platform/javascript/dom_keys.inc b/platform/javascript/dom_keys.inc
index 7902efafe0..69340ff58c 100644
--- a/platform/javascript/dom_keys.inc
+++ b/platform/javascript/dom_keys.inc
@@ -159,8 +159,8 @@ int dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], b
DOM2GODOT("Backspace", BACKSPACE);
DOM2GODOT("CapsLock", CAPSLOCK);
DOM2GODOT("ContextMenu", MENU);
- DOM2GODOT("ControlLeft", CONTROL);
- DOM2GODOT("ControlRight", CONTROL);
+ DOM2GODOT("ControlLeft", CTRL);
+ DOM2GODOT("ControlRight", CTRL);
DOM2GODOT("Enter", ENTER);
DOM2GODOT("MetaLeft", SUPER_L);
DOM2GODOT("MetaRight", SUPER_R);
diff --git a/platform/javascript/emscripten_helpers.py b/platform/javascript/emscripten_helpers.py
index b3b15a1574..ab98838e20 100644
--- a/platform/javascript/emscripten_helpers.py
+++ b/platform/javascript/emscripten_helpers.py
@@ -1,4 +1,4 @@
-import os
+import os, json
from SCons.Util import WhereIs
@@ -59,7 +59,23 @@ def create_template_zip(env, js, wasm, extra):
if env["tools"]:
# HTML
html = "#misc/dist/html/editor.html"
- subst_dict = {"@GODOT_VERSION@": get_build_version(), "@GODOT_NAME@": "GodotEngine"}
+ cache = [
+ "godot.tools.html",
+ "offline.html",
+ "godot.tools.js",
+ "godot.tools.worker.js",
+ "godot.tools.audio.worklet.js",
+ "logo.svg",
+ "favicon.png",
+ ]
+ opt_cache = ["godot.tools.wasm"]
+ subst_dict = {
+ "@GODOT_VERSION@": get_build_version(),
+ "@GODOT_NAME@": "GodotEngine",
+ "@GODOT_CACHE@": json.dumps(cache),
+ "@GODOT_OPT_CACHE@": json.dumps(opt_cache),
+ "@GODOT_OFFLINE_PAGE@": "offline.html",
+ }
html = env.Substfile(target="#bin/godot${PROGSUFFIX}.html", source=html, SUBST_DICT=subst_dict)
in_files.append(html)
out_files.append(zip_dir.File(binary_name + ".html"))
@@ -82,6 +98,10 @@ def create_template_zip(env, js, wasm, extra):
# HTML
in_files.append("#misc/dist/html/full-size.html")
out_files.append(zip_dir.File(binary_name + ".html"))
+ in_files.append(service_worker)
+ out_files.append(zip_dir.File(binary_name + ".service.worker.js"))
+ in_files.append("#misc/dist/html/offline-export.html")
+ out_files.append(zip_dir.File("godot.offline.html"))
zip_files = env.InstallAs(out_files, in_files)
env.Zip(
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 3f04bedea2..7e49feee61 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -28,7 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "core/io/image_loader.h"
#include "core/io/json.h"
+#include "core/io/stream_peer_ssl.h"
#include "core/io/tcp_server.h"
#include "core/io/zip_io.h"
#include "editor/editor_export.h"
@@ -37,23 +39,58 @@
#include "platform/javascript/logo.gen.h"
#include "platform/javascript/run_icon.gen.h"
-class EditorHTTPServer : public Reference {
+class EditorHTTPServer : public RefCounted {
private:
- Ref<TCP_Server> server;
- Ref<StreamPeerTCP> connection;
+ Ref<TCPServer> server;
+ Map<String, String> mimes;
+ Ref<StreamPeerTCP> tcp;
+ Ref<StreamPeerSSL> ssl;
+ Ref<StreamPeer> peer;
+ Ref<CryptoKey> key;
+ Ref<X509Certificate> cert;
+ bool use_ssl = false;
uint64_t time = 0;
uint8_t req_buf[4096];
int req_pos = 0;
void _clear_client() {
- connection = Ref<StreamPeerTCP>();
+ peer = Ref<StreamPeer>();
+ ssl = Ref<StreamPeerSSL>();
+ tcp = Ref<StreamPeerTCP>();
memset(req_buf, 0, sizeof(req_buf));
time = 0;
req_pos = 0;
}
+ void _set_internal_certs(Ref<Crypto> p_crypto) {
+ const String cache_path = EditorPaths::get_singleton()->get_cache_dir();
+ const String key_path = cache_path.plus_file("html5_server.key");
+ const String crt_path = cache_path.plus_file("html5_server.crt");
+ bool regen = !FileAccess::exists(key_path) || !FileAccess::exists(crt_path);
+ if (!regen) {
+ key = Ref<CryptoKey>(CryptoKey::create());
+ cert = Ref<X509Certificate>(X509Certificate::create());
+ if (key->load(key_path) != OK || cert->load(crt_path) != OK) {
+ regen = true;
+ }
+ }
+ if (regen) {
+ key = p_crypto->generate_rsa(2048);
+ key->save(key_path);
+ cert = p_crypto->generate_self_signed_certificate(key, "CN=godot-debug.local,O=A Game Dev,C=XXA", "20140101000000", "20340101000000");
+ cert->save(crt_path);
+ }
+ }
+
public:
EditorHTTPServer() {
+ mimes["html"] = "text/html";
+ mimes["js"] = "application/javascript";
+ mimes["json"] = "application/json";
+ mimes["pck"] = "application/octet-stream";
+ mimes["png"] = "image/png";
+ mimes["svg"] = "image/svg";
+ mimes["wasm"] = "application/wasm";
server.instance();
stop();
}
@@ -63,7 +100,24 @@ public:
_clear_client();
}
- Error listen(int p_port, IP_Address p_address) {
+ Error listen(int p_port, IPAddress p_address, bool p_use_ssl, String p_ssl_key, String p_ssl_cert) {
+ use_ssl = p_use_ssl;
+ if (use_ssl) {
+ Ref<Crypto> crypto = Crypto::create();
+ if (crypto.is_null()) {
+ return ERR_UNAVAILABLE;
+ }
+ if (!p_ssl_key.is_empty() && !p_ssl_cert.is_empty()) {
+ key = Ref<CryptoKey>(CryptoKey::create());
+ Error err = key->load(p_ssl_key);
+ ERR_FAIL_COND_V(err != OK, err);
+ cert = Ref<X509Certificate>(X509Certificate::create());
+ err = cert->load(p_ssl_cert);
+ ERR_FAIL_COND_V(err != OK, err);
+ } else {
+ _set_internal_certs(crypto);
+ }
+ }
return server->listen(p_port, p_address);
}
@@ -82,51 +136,21 @@ public:
// Wrong protocol
ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version.");
- const String cache_path = EditorSettings::get_singleton()->get_cache_dir();
- const String basereq = "/tmp_js_export";
- String filepath;
- String ctype;
- if (req[1] == basereq + ".html") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "text/html";
- } else if (req[1] == basereq + ".js") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/javascript";
- } else if (req[1] == basereq + ".audio.worklet.js") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/javascript";
- } else if (req[1] == basereq + ".worker.js") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/javascript";
- } else if (req[1] == basereq + ".pck") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/octet-stream";
- } else if (req[1] == basereq + ".png" || req[1] == "/favicon.png") {
- // Also allow serving the generated favicon for a smoother loading experience.
- if (req[1] == "/favicon.png") {
- filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png");
- } else {
- filepath = basereq + ".png";
- }
- ctype = "image/png";
- } else if (req[1] == basereq + ".side.wasm") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/wasm";
- } else if (req[1] == basereq + ".wasm") {
- filepath = cache_path.plus_file(req[1].get_file());
- ctype = "application/wasm";
- } else if (req[1].ends_with(".wasm")) {
- filepath = cache_path.plus_file(req[1].get_file()); // TODO dangerous?
- ctype = "application/wasm";
- }
- if (filepath.is_empty() || !FileAccess::exists(filepath)) {
+ const String req_file = req[1].get_file();
+ const String req_ext = req[1].get_extension();
+ const String cache_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
+ const String filepath = cache_path.plus_file(req_file);
+
+ if (!mimes.has(req_ext) || !FileAccess::exists(filepath)) {
String s = "HTTP/1.1 404 Not Found\r\n";
s += "Connection: Close\r\n";
s += "\r\n";
CharString cs = s.utf8();
- connection->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
+ peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
return;
}
+ const String ctype = mimes[req_ext];
+
FileAccess *f = FileAccess::open(filepath, FileAccess::READ);
ERR_FAIL_COND(!f);
String s = "HTTP/1.1 200 OK\r\n";
@@ -138,7 +162,7 @@ public:
s += "Cache-Control: no-store, max-age=0\r\n";
s += "\r\n";
CharString cs = s.utf8();
- Error err = connection->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
+ Error err = peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
if (err != OK) {
memdelete(f);
ERR_FAIL();
@@ -146,11 +170,11 @@ public:
while (true) {
uint8_t bytes[4096];
- int read = f->get_buffer(bytes, 4096);
- if (read < 1) {
+ uint64_t read = f->get_buffer(bytes, 4096);
+ if (read == 0) {
break;
}
- err = connection->put_data(bytes, read);
+ err = peer->put_data(bytes, read);
if (err != OK) {
memdelete(f);
ERR_FAIL();
@@ -163,21 +187,43 @@ public:
if (!server->is_listening()) {
return;
}
- if (connection.is_null()) {
+ if (tcp.is_null()) {
if (!server->is_connection_available()) {
return;
}
- connection = server->take_connection();
+ tcp = server->take_connection();
+ peer = tcp;
time = OS::get_singleton()->get_ticks_usec();
}
if (OS::get_singleton()->get_ticks_usec() - time > 1000000) {
_clear_client();
return;
}
- if (connection->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
+ if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
return;
}
+ if (use_ssl) {
+ if (ssl.is_null()) {
+ ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
+ peer = ssl;
+ ssl->set_blocking_handshake_enabled(false);
+ if (ssl->accept_stream(tcp, key, cert) != OK) {
+ _clear_client();
+ return;
+ }
+ }
+ ssl->poll();
+ if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) {
+ // Still handshaking, keep waiting.
+ return;
+ }
+ if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
+ _clear_client();
+ return;
+ }
+ }
+
while (true) {
char *r = (char *)req_buf;
int l = req_pos - 1;
@@ -189,7 +235,7 @@ public:
int read = 0;
ERR_FAIL_COND(req_pos >= 4096);
- Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
+ Error err = peer->get_partial_data(&req_buf[req_pos], 1, read);
if (err != OK) {
// Got an error
_clear_client();
@@ -242,7 +288,32 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform {
return name;
}
+ Ref<Image> _get_project_icon() const {
+ Ref<Image> icon;
+ icon.instance();
+ const String icon_path = String(GLOBAL_GET("application/config/icon")).strip_edges();
+ if (icon_path.is_empty() || ImageLoader::load_image(icon_path, icon) != OK) {
+ return EditorNode::get_singleton()->get_editor_theme()->get_icon("DefaultProjectIcon", "EditorIcons")->get_image();
+ }
+ return icon;
+ }
+
+ Ref<Image> _get_project_splash() const {
+ Ref<Image> splash;
+ splash.instance();
+ const String splash_path = String(GLOBAL_GET("application/boot_splash/image")).strip_edges();
+ if (splash_path.is_empty() || ImageLoader::load_image(splash_path, splash) != OK) {
+ return Ref<Image>(memnew(Image(boot_splash_png)));
+ }
+ return splash;
+ }
+
+ Error _extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa);
+ void _replace_strings(Map<String, String> p_replaces, Vector<uint8_t> &r_template);
void _fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes);
+ Error _add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr);
+ Error _build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects);
+ Error _write_or_error(const uint8_t *p_content, int p_len, String p_path);
static void _server_thread_poll(void *data);
@@ -281,10 +352,90 @@ public:
~EditorExportPlatformJavaScript();
};
-void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes) {
- String str_template = String::utf8(reinterpret_cast<const char *>(p_html.ptr()), p_html.size());
- String str_export;
+Error EditorExportPlatformJavaScript::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) {
+ FileAccess *src_f = nullptr;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+ unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io);
+
+ if (!pkg) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not open template for export:") + "\n" + p_template);
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ if (unzGoToFirstFile(pkg) != UNZ_OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid export template:") + "\n" + p_template);
+ unzClose(pkg);
+ return ERR_FILE_CORRUPT;
+ }
+
+ do {
+ //get filename
+ unz_file_info info;
+ char fname[16384];
+ unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
+
+ String file = fname;
+
+ // Skip service worker and offline page if not exporting pwa.
+ if (!pwa && (file == "godot.service.worker.js" || file == "godot.offline.html")) {
+ continue;
+ }
+ Vector<uint8_t> data;
+ data.resize(info.uncompressed_size);
+
+ //read
+ unzOpenCurrentFile(pkg);
+ unzReadCurrentFile(pkg, data.ptrw(), data.size());
+ unzCloseCurrentFile(pkg);
+
+ //write
+ String dst = p_dir.plus_file(file.replace("godot", p_name));
+ FileAccess *f = FileAccess::open(dst, FileAccess::WRITE);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + dst);
+ unzClose(pkg);
+ return ERR_FILE_CANT_WRITE;
+ }
+ f->store_buffer(data.ptr(), data.size());
+ memdelete(f);
+
+ } while (unzGoToNextFile(pkg) == UNZ_OK);
+ unzClose(pkg);
+ return OK;
+}
+
+Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, int p_size, String p_path) {
+ FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path);
+ return ERR_FILE_CANT_WRITE;
+ }
+ f->store_buffer(p_content, p_size);
+ memdelete(f);
+ return OK;
+}
+
+void EditorExportPlatformJavaScript::_replace_strings(Map<String, String> p_replaces, Vector<uint8_t> &r_template) {
+ String str_template = String::utf8(reinterpret_cast<const char *>(r_template.ptr()), r_template.size());
+ String out;
Vector<String> lines = str_template.split("\n");
+ for (int i = 0; i < lines.size(); i++) {
+ String current_line = lines[i];
+ for (Map<String, String>::Element *E = p_replaces.front(); E; E = E->next()) {
+ current_line = current_line.replace(E->key(), E->get());
+ }
+ out += current_line + "\n";
+ }
+ CharString cs = out.utf8();
+ r_template.resize(cs.length());
+ for (int i = 0; i < cs.length(); i++) {
+ r_template.write[i] = cs[i];
+ }
+}
+
+void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes) {
+ // Engine.js config
+ Dictionary config;
Array libs;
for (int i = 0; i < p_shared_objects.size(); i++) {
libs.push_back(p_shared_objects[i].path.get_file());
@@ -295,29 +446,172 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
for (int i = 0; i < flags.size(); i++) {
args.push_back(flags[i]);
}
- Dictionary config;
config["canvasResizePolicy"] = p_preset->get("html/canvas_resize_policy");
config["experimentalVK"] = p_preset->get("html/experimental_virtual_keyboard");
config["gdnativeLibs"] = libs;
config["executable"] = p_name;
config["args"] = args;
config["fileSizes"] = p_file_sizes;
+
+ String head_include;
+ if (p_preset->get("html/export_icon")) {
+ head_include += "<link id='-gd-engine-icon' rel='icon' type='image/png' href='" + p_name + ".icon.png' />\n";
+ head_include += "<link rel='apple-touch-icon' href='" + p_name + ".apple-touch-icon.png'/>\n";
+ }
+ if (p_preset->get("progressive_web_app/enabled")) {
+ head_include += "<link rel='manifest' href='" + p_name + ".manifest.json'>\n";
+ head_include += "<script type='application/javascript'>window.addEventListener('load', () => {if ('serviceWorker' in navigator) {navigator.serviceWorker.register('" +
+ p_name + ".service.worker.js');}});</script>\n";
+ }
+
+ // Replaces HTML string
const String str_config = JSON::print(config);
+ const String custom_head_include = p_preset->get("html/head_include");
+ Map<String, String> replaces;
+ replaces["$GODOT_URL"] = p_name + ".js";
+ replaces["$GODOT_PROJECT_NAME"] = ProjectSettings::get_singleton()->get_setting("application/config/name");
+ replaces["$GODOT_HEAD_INCLUDE"] = head_include + custom_head_include;
+ replaces["$GODOT_CONFIG"] = str_config;
+ _replace_strings(replaces, p_html);
+}
- for (int i = 0; i < lines.size(); i++) {
- String current_line = lines[i];
- current_line = current_line.replace("$GODOT_URL", p_name + ".js");
- current_line = current_line.replace("$GODOT_PROJECT_NAME", ProjectSettings::get_singleton()->get_setting("application/config/name"));
- current_line = current_line.replace("$GODOT_HEAD_INCLUDE", p_preset->get("html/head_include"));
- current_line = current_line.replace("$GODOT_CONFIG", str_config);
- str_export += current_line + "\n";
+Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr) {
+ const String name = p_path.get_file().get_basename();
+ const String icon_name = vformat("%s.%dx%d.png", name, p_size, p_size);
+ const String icon_dest = p_path.get_base_dir().plus_file(icon_name);
+
+ Ref<Image> icon;
+ if (!p_icon.is_empty()) {
+ icon.instance();
+ const Error err = ImageLoader::load_image(p_icon, icon);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + p_icon);
+ return err;
+ }
+ if (icon->get_width() != p_size || icon->get_height() != p_size) {
+ icon->resize(p_size, p_size);
+ }
+ } else {
+ icon = _get_project_icon();
+ icon->resize(p_size, p_size);
+ }
+ const Error err = icon->save_png(icon_dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + icon_dest);
+ return err;
}
+ Dictionary icon_dict;
+ icon_dict["sizes"] = vformat("%dx%d", p_size, p_size);
+ icon_dict["type"] = "image/png";
+ icon_dict["src"] = icon_name;
+ r_arr.push_back(icon_dict);
+ return err;
+}
- CharString cs = str_export.utf8();
- p_html.resize(cs.length());
- for (int i = 0; i < cs.length(); i++) {
- p_html.write[i] = cs[i];
+Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) {
+ // Service worker
+ const String dir = p_path.get_base_dir();
+ const String name = p_path.get_file().get_basename();
+ const ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ Map<String, String> replaces;
+ replaces["@GODOT_VERSION@"] = "1";
+ replaces["@GODOT_NAME@"] = name;
+ replaces["@GODOT_OFFLINE_PAGE@"] = name + ".offline.html";
+ Array files;
+ replaces["@GODOT_OPT_CACHE@"] = JSON::print(files);
+ files.push_back(name + ".html");
+ files.push_back(name + ".js");
+ files.push_back(name + ".wasm");
+ files.push_back(name + ".pck");
+ files.push_back(name + ".offline.html");
+ if (p_preset->get("html/export_icon")) {
+ files.push_back(name + ".icon.png");
+ files.push_back(name + ".apple-touch-icon.png");
+ }
+ if (mode == EXPORT_MODE_THREADS) {
+ files.push_back(name + ".worker.js");
+ files.push_back(name + ".audio.worklet.js");
+ } else if (mode == EXPORT_MODE_GDNATIVE) {
+ files.push_back(name + ".side.wasm");
+ for (int i = 0; i < p_shared_objects.size(); i++) {
+ files.push_back(p_shared_objects[i].path.get_file());
+ }
+ }
+ replaces["@GODOT_CACHE@"] = JSON::print(files);
+
+ const String sw_path = dir.plus_file(name + ".service.worker.js");
+ Vector<uint8_t> sw;
+ {
+ FileAccess *f = FileAccess::open(sw_path, FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + sw_path);
+ return ERR_FILE_CANT_READ;
+ }
+ sw.resize(f->get_length());
+ f->get_buffer(sw.ptrw(), sw.size());
+ memdelete(f);
+ f = nullptr;
+ }
+ _replace_strings(replaces, sw);
+ Error err = _write_or_error(sw.ptr(), sw.size(), dir.plus_file(name + ".service.worker.js"));
+ if (err != OK) {
+ return err;
}
+
+ // Custom offline page
+ const String offline_page = p_preset->get("progressive_web_app/offline_page");
+ if (!offline_page.is_empty()) {
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ const String offline_dest = dir.plus_file(name + ".offline.html");
+ err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + offline_dest);
+ return err;
+ }
+ }
+
+ // Manifest
+ const char *modes[4] = { "fullscreen", "standalone", "minimal-ui", "browser" };
+ const char *orientations[3] = { "any", "landscape", "portrait" };
+ const int display = CLAMP(int(p_preset->get("progressive_web_app/display")), 0, 4);
+ const int orientation = CLAMP(int(p_preset->get("progressive_web_app/orientation")), 0, 3);
+
+ Dictionary manifest;
+ String proj_name = ProjectSettings::get_singleton()->get_setting("application/config/name");
+ if (proj_name.is_empty()) {
+ proj_name = "Godot Game";
+ }
+ manifest["name"] = proj_name;
+ manifest["start_url"] = "./" + name + ".html";
+ manifest["display"] = String::utf8(modes[display]);
+ manifest["orientation"] = String::utf8(orientations[orientation]);
+ manifest["background_color"] = "#" + p_preset->get("progressive_web_app/background_color").operator Color().to_html(false);
+
+ Array icons_arr;
+ const String icon144_path = p_preset->get("progressive_web_app/icon_144x144");
+ err = _add_manifest_icon(p_path, icon144_path, 144, icons_arr);
+ if (err != OK) {
+ return err;
+ }
+ const String icon180_path = p_preset->get("progressive_web_app/icon_180x180");
+ err = _add_manifest_icon(p_path, icon180_path, 180, icons_arr);
+ if (err != OK) {
+ return err;
+ }
+ const String icon512_path = p_preset->get("progressive_web_app/icon_512x512");
+ err = _add_manifest_icon(p_path, icon512_path, 512, icons_arr);
+ if (err != OK) {
+ return err;
+ }
+ manifest["icons"] = icons_arr;
+
+ CharString cs = JSON::print(manifest).utf8();
+ err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.plus_file(name + ".manifest.json"));
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
}
void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
@@ -350,10 +644,19 @@ void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_op
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/export_icon"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_FILE, "*.html"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "html/canvas_resize_policy", PROPERTY_HINT_ENUM, "None,Project,Adaptive"), 2));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/experimental_virtual_keyboard"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "progressive_web_app/enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/offline_page", PROPERTY_HINT_FILE, "*.html"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "progressive_web_app/display", PROPERTY_HINT_ENUM, "Fullscreen,Standalone,Minimal UI,Browser"), 1));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "progressive_web_app/orientation", PROPERTY_HINT_ENUM, "Any,Landscape,Portrait"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_144x144", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_180x180", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/icon_512x512", PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "progressive_web_app/background_color", PROPERTY_HINT_COLOR_NO_ALPHA), Color()));
}
String EditorExportPlatformJavaScript::get_name() const {
@@ -419,20 +722,25 @@ List<String> EditorExportPlatformJavaScript::get_binary_extensions(const Ref<Edi
Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
- String custom_debug = p_preset->get("custom_template/debug");
- String custom_release = p_preset->get("custom_template/release");
- String custom_html = p_preset->get("html/custom_html_shell");
+ const String custom_debug = p_preset->get("custom_template/debug");
+ const String custom_release = p_preset->get("custom_template/release");
+ const String custom_html = p_preset->get("html/custom_html_shell");
+ const bool export_icon = p_preset->get("html/export_icon");
+ const bool pwa = p_preset->get("progressive_web_app/enabled");
- String template_path = p_debug ? custom_debug : custom_release;
+ const String base_dir = p_path.get_base_dir();
+ const String base_path = p_path.get_basename();
+ const String base_name = p_path.get_file().get_basename();
+ // Find the correct template
+ String template_path = p_debug ? custom_debug : custom_release;
template_path = template_path.strip_edges();
-
if (template_path == String()) {
ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
template_path = find_export_template(_get_template_name(mode, p_debug));
}
- if (!DirAccess::exists(p_path.get_base_dir())) {
+ if (!DirAccess::exists(base_dir)) {
return ERR_FILE_BAD_PATH;
}
@@ -441,8 +749,9 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
return ERR_FILE_NOT_FOUND;
}
+ // Export pck and shared objects
Vector<SharedObject> shared_objects;
- String pck_path = p_path.get_basename() + ".pck";
+ String pck_path = base_path + ".pck";
Error error = save_pack(p_preset, pck_path, &shared_objects);
if (error != OK) {
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + pck_path);
@@ -450,7 +759,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
}
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) {
- String dst = p_path.get_base_dir().plus_file(shared_objects[i].path.get_file());
+ String dst = base_dir.plus_file(shared_objects[i].path.get_file());
error = da->copy(shared_objects[i].path, dst);
if (error != OK) {
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + shared_objects[i].path.get_file());
@@ -459,124 +768,54 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
}
}
memdelete(da);
+ da = nullptr;
- FileAccess *src_f = nullptr;
- zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- unzFile pkg = unzOpen2(template_path.utf8().get_data(), &io);
-
- if (!pkg) {
- EditorNode::get_singleton()->show_warning(TTR("Could not open template for export:") + "\n" + template_path);
- return ERR_FILE_NOT_FOUND;
- }
-
- if (unzGoToFirstFile(pkg) != UNZ_OK) {
- EditorNode::get_singleton()->show_warning(TTR("Invalid export template:") + "\n" + template_path);
- unzClose(pkg);
- return ERR_FILE_CORRUPT;
+ // Extract templates.
+ error = _extract_template(template_path, base_dir, base_name, pwa);
+ if (error) {
+ return error;
}
- Vector<uint8_t> html;
+ // Parse generated file sizes (pck and wasm, to help show a meaningful loading bar).
Dictionary file_sizes;
- do {
- //get filename
- unz_file_info info;
- char fname[16384];
- unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
-
- String file = fname;
-
- // HTML is handled later
- if (file == "godot.html") {
- if (custom_html.is_empty()) {
- html.resize(info.uncompressed_size);
- unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, html.ptrw(), html.size());
- unzCloseCurrentFile(pkg);
- }
- continue;
- }
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
-
- //read
- unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptrw(), data.size());
- unzCloseCurrentFile(pkg);
-
- //write
-
- if (file == "godot.js") {
- file = p_path.get_file().get_basename() + ".js";
-
- } else if (file == "godot.worker.js") {
- file = p_path.get_file().get_basename() + ".worker.js";
-
- } else if (file == "godot.side.wasm") {
- file = p_path.get_file().get_basename() + ".side.wasm";
-
- } else if (file == "godot.audio.worklet.js") {
- file = p_path.get_file().get_basename() + ".audio.worklet.js";
-
- } else if (file == "godot.wasm") {
- file = p_path.get_file().get_basename() + ".wasm";
- file_sizes[file.get_file()] = (uint64_t)info.uncompressed_size;
- }
-
- String dst = p_path.get_base_dir().plus_file(file);
- FileAccess *f = FileAccess::open(dst, FileAccess::WRITE);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + dst);
- unzClose(pkg);
- return ERR_FILE_CANT_WRITE;
- }
- f->store_buffer(data.ptr(), data.size());
- memdelete(f);
-
- } while (unzGoToNextFile(pkg) == UNZ_OK);
- unzClose(pkg);
-
- if (!custom_html.is_empty()) {
- FileAccess *f = FileAccess::open(custom_html, FileAccess::READ);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read custom HTML shell:") + "\n" + custom_html);
- return ERR_FILE_CANT_READ;
- }
- html.resize(f->get_len());
- f->get_buffer(html.ptrw(), html.size());
+ FileAccess *f = nullptr;
+ f = FileAccess::open(pck_path, FileAccess::READ);
+ if (f) {
+ file_sizes[pck_path.get_file()] = (uint64_t)f->get_length();
memdelete(f);
+ f = nullptr;
}
- {
- FileAccess *f = FileAccess::open(pck_path, FileAccess::READ);
- if (f) {
- file_sizes[pck_path.get_file()] = (uint64_t)f->get_len();
- memdelete(f);
- f = nullptr;
- }
- _fix_html(html, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects, file_sizes);
- f = FileAccess::open(p_path, FileAccess::WRITE);
- if (!f) {
- EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path);
- return ERR_FILE_CANT_WRITE;
- }
- f->store_buffer(html.ptr(), html.size());
+ f = FileAccess::open(base_path + ".wasm", FileAccess::READ);
+ if (f) {
+ file_sizes[base_name + ".wasm"] = (uint64_t)f->get_length();
memdelete(f);
- html.resize(0);
+ f = nullptr;
}
- Ref<Image> splash;
- const String splash_path = String(GLOBAL_GET("application/boot_splash/image")).strip_edges();
- if (!splash_path.is_empty()) {
- splash.instance();
- const Error err = splash->load(splash_path);
- if (err) {
- EditorNode::get_singleton()->show_warning(TTR("Could not read boot splash image file:") + "\n" + splash_path + "\n" + TTR("Using default boot splash image."));
- splash.unref();
- }
- }
- if (splash.is_null()) {
- splash = Ref<Image>(memnew(Image(boot_splash_png)));
+ // Read the HTML shell file (custom or from template).
+ const String html_path = custom_html.is_empty() ? base_path + ".html" : custom_html;
+ Vector<uint8_t> html;
+ f = FileAccess::open(html_path, FileAccess::READ);
+ if (!f) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not read HTML shell:") + "\n" + html_path);
+ return ERR_FILE_CANT_READ;
+ }
+ html.resize(f->get_length());
+ f->get_buffer(html.ptrw(), html.size());
+ memdelete(f);
+ f = nullptr;
+
+ // Generate HTML file with replaced strings.
+ _fix_html(html, p_preset, base_name, p_debug, p_flags, shared_objects, file_sizes);
+ Error err = _write_or_error(html.ptr(), html.size(), p_path);
+ if (err != OK) {
+ return err;
}
- const String splash_png_path = p_path.get_base_dir().plus_file(p_path.get_file().get_basename() + ".png");
+ html.resize(0);
+
+ // Export splash (why?)
+ Ref<Image> splash = _get_project_splash();
+ const String splash_png_path = base_path + ".png";
if (splash->save_png(splash_png_path) != OK) {
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + splash_png_path);
return ERR_FILE_CANT_WRITE;
@@ -584,22 +823,27 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
// Save a favicon that can be accessed without waiting for the project to finish loading.
// This way, the favicon can be displayed immediately when loading the page.
- Ref<Image> favicon;
- const String favicon_path = String(GLOBAL_GET("application/config/icon")).strip_edges();
- if (!favicon_path.is_empty()) {
- favicon.instance();
- const Error err = favicon->load(favicon_path);
- if (err) {
- favicon.unref();
- }
- }
-
- if (favicon.is_valid()) {
- const String favicon_png_path = p_path.get_base_dir().plus_file("favicon.png");
+ if (export_icon) {
+ Ref<Image> favicon = _get_project_icon();
+ const String favicon_png_path = base_path + ".icon.png";
if (favicon->save_png(favicon_png_path) != OK) {
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + favicon_png_path);
return ERR_FILE_CANT_WRITE;
}
+ favicon->resize(180, 180);
+ const String apple_icon_png_path = base_path + ".apple-touch-icon.png";
+ if (favicon->save_png(apple_icon_png_path) != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + apple_icon_png_path);
+ return ERR_FILE_CANT_WRITE;
+ }
+ }
+
+ // Generate the PWA worker and manifest
+ if (pwa) {
+ err = _build_pwa(p_preset, p_path, shared_objects);
+ if (err != OK) {
+ return err;
+ }
}
return OK;
@@ -644,26 +888,38 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
return OK;
}
- const String basepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export");
+ const String dest = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (!da->dir_exists(dest)) {
+ Error err = da->make_dir_recursive(dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not create HTTP server directory:") + "\n" + dest);
+ return err;
+ }
+ }
+ const String basepath = dest.plus_file("tmp_js_export");
Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
if (err != OK) {
// Export generates several files, clean them up on failure.
DirAccess::remove_file_or_error(basepath + ".html");
+ DirAccess::remove_file_or_error(basepath + ".offline.html");
DirAccess::remove_file_or_error(basepath + ".js");
DirAccess::remove_file_or_error(basepath + ".worker.js");
DirAccess::remove_file_or_error(basepath + ".audio.worklet.js");
+ DirAccess::remove_file_or_error(basepath + ".service.worker.js");
DirAccess::remove_file_or_error(basepath + ".pck");
DirAccess::remove_file_or_error(basepath + ".png");
DirAccess::remove_file_or_error(basepath + ".side.wasm");
DirAccess::remove_file_or_error(basepath + ".wasm");
- DirAccess::remove_file_or_error(EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png"));
+ DirAccess::remove_file_or_error(basepath + ".icon.png");
+ DirAccess::remove_file_or_error(basepath + ".apple-touch-icon.png");
return err;
}
const uint16_t bind_port = EDITOR_GET("export/web/http_port");
// Resolve host if needed.
const String bind_host = EDITOR_GET("export/web/http_host");
- IP_Address bind_ip;
+ IPAddress bind_ip;
if (bind_host.is_valid_ip_address()) {
bind_ip = bind_host;
} else {
@@ -671,16 +927,23 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
}
ERR_FAIL_COND_V_MSG(!bind_ip.is_valid(), ERR_INVALID_PARAMETER, "Invalid editor setting 'export/web/http_host': '" + bind_host + "'. Try using '127.0.0.1'.");
+ const bool use_ssl = EDITOR_GET("export/web/use_ssl");
+ const String ssl_key = EDITOR_GET("export/web/ssl_key");
+ const String ssl_cert = EDITOR_GET("export/web/ssl_certificate");
+
// Restart server.
{
MutexLock lock(server_lock);
server->stop();
- err = server->listen(bind_port, bind_ip);
+ err = server->listen(bind_port, bind_ip, use_ssl, ssl_key, ssl_cert);
+ }
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Error starting HTTP server:") + "\n" + itos(err));
+ return err;
}
- ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to start HTTP server.");
- OS::get_singleton()->shell_open(String("http://" + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html"));
+ OS::get_singleton()->shell_open(String((use_ssl ? "https://" : "http://") + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html"));
// FIXME: Find out how to clean up export files after running the successfully
// exported game. Might not be trivial.
return OK;
@@ -730,7 +993,12 @@ EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() {
void register_javascript_exporter() {
EDITOR_DEF("export/web/http_host", "localhost");
EDITOR_DEF("export/web/http_port", 8060);
+ EDITOR_DEF("export/web/use_ssl", false);
+ EDITOR_DEF("export/web/ssl_key", "");
+ EDITOR_DEF("export/web/ssl_certificate", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "export/web/http_port", PROPERTY_HINT_RANGE, "1,65535,1"));
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/ssl_key", PROPERTY_HINT_GLOBAL_FILE, "*.key"));
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/ssl_certificate", PROPERTY_HINT_GLOBAL_FILE, "*.crt,*.pem"));
Ref<EditorExportPlatformJavaScript> platform;
platform.instance();
diff --git a/platform/javascript/godot_js.h b/platform/javascript/godot_js.h
index 8927a83cb3..d332af2c31 100644
--- a/platform/javascript/godot_js.h
+++ b/platform/javascript/godot_js.h
@@ -84,7 +84,7 @@ extern void godot_js_display_cursor_set_custom_shape(const char *p_shape, const
extern void godot_js_display_cursor_set_visible(int p_visible);
// Display gamepad
-extern char *godot_js_display_gamepad_cb(void (*p_on_change)(int p_index, int p_connected, const char *p_id, const char *p_guid));
+extern void godot_js_display_gamepad_cb(void (*p_on_change)(int p_index, int p_connected, const char *p_id, const char *p_guid));
extern int godot_js_display_gamepad_sample();
extern int godot_js_display_gamepad_sample_count();
extern int godot_js_display_gamepad_sample_get(int p_idx, float r_btns[16], int32_t *r_btns_num, float r_axes[10], int32_t *r_axes_num, int32_t *r_standard);
diff --git a/platform/javascript/http_client.h.inc b/platform/javascript/http_client.h.inc
index 842a93fcba..6544d41c98 100644
--- a/platform/javascript/http_client.h.inc
+++ b/platform/javascript/http_client.h.inc
@@ -34,7 +34,8 @@ Error make_request(Method p_method, const String &p_url, const Vector<String> &p
static void _parse_headers(int p_len, const char **p_headers, void *p_ref);
int js_id = 0;
-int read_limit = 4096;
+// 64 KiB by default (favors fast download speeds at the cost of memory usage).
+int read_limit = 65536;
Status status = STATUS_DISCONNECTED;
String host;
diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp
index b79c965854..a6cf4b0eb8 100644
--- a/platform/javascript/http_client_javascript.cpp
+++ b/platform/javascript/http_client_javascript.cpp
@@ -209,7 +209,7 @@ PackedByteArray HTTPClient::read_response_body_chunk() {
return chunk;
}
chunk.resize(read);
- copymem(chunk.ptrw(), response_buffer.ptr(), read);
+ memcpy(chunk.ptrw(), response_buffer.ptr(), read);
return chunk;
}
diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp
index 0fe95b0a8f..40771d1882 100644
--- a/platform/javascript/javascript_main.cpp
+++ b/platform/javascript/javascript_main.cpp
@@ -66,6 +66,11 @@ void main_loop_callback() {
int target_fps = Engine::get_singleton()->get_target_fps();
if (target_fps > 0) {
+ if (current_ticks - target_ticks > 1000000) {
+ // When the window loses focus, we stop getting updates and accumulate delay.
+ // For this reason, if the difference is too big, we reset target ticks to the current ticks.
+ target_ticks = current_ticks;
+ }
target_ticks += (uint64_t)(1000000 / target_fps);
}
if (os->main_loop_iterate()) {
diff --git a/platform/javascript/javascript_singleton.cpp b/platform/javascript/javascript_singleton.cpp
new file mode 100644
index 0000000000..c441ed0517
--- /dev/null
+++ b/platform/javascript/javascript_singleton.cpp
@@ -0,0 +1,346 @@
+/*************************************************************************/
+/* javascript_singleton.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "api/javascript_singleton.h"
+#include "emscripten.h"
+
+extern "C" {
+extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime);
+}
+
+#ifdef JAVASCRIPT_EVAL_ENABLED
+
+extern "C" {
+typedef union {
+ int64_t i;
+ double r;
+ void *p;
+} godot_js_wrapper_ex;
+
+typedef int (*GodotJSWrapperVariant2JSCallback)(const void **p_args, int p_pos, godot_js_wrapper_ex *r_val, void **p_lock);
+typedef void (*GodotJSWrapperFreeLockCallback)(void **p_lock, int p_type);
+extern int godot_js_wrapper_interface_get(const char *p_name);
+extern int godot_js_wrapper_object_call(int p_id, const char *p_method, void **p_args, int p_argc, GodotJSWrapperVariant2JSCallback p_variant2js_callback, godot_js_wrapper_ex *p_cb_rval, void **p_lock, GodotJSWrapperFreeLockCallback p_lock_callback);
+extern int godot_js_wrapper_object_get(int p_id, godot_js_wrapper_ex *p_val, const char *p_prop);
+extern int godot_js_wrapper_object_getvar(int p_id, int p_type, godot_js_wrapper_ex *p_val);
+extern int godot_js_wrapper_object_setvar(int p_id, int p_key_type, godot_js_wrapper_ex *p_key_ex, int p_val_type, godot_js_wrapper_ex *p_val_ex);
+extern void godot_js_wrapper_object_set(int p_id, const char *p_name, int p_type, godot_js_wrapper_ex *p_val);
+extern void godot_js_wrapper_object_unref(int p_id);
+extern int godot_js_wrapper_create_cb(void *p_ref, void (*p_callback)(void *p_ref, int p_arg_id, int p_argc));
+extern int godot_js_wrapper_create_object(const char *p_method, void **p_args, int p_argc, GodotJSWrapperVariant2JSCallback p_variant2js_callback, godot_js_wrapper_ex *p_cb_rval, void **p_lock, GodotJSWrapperFreeLockCallback p_lock_callback);
+};
+
+class JavaScriptObjectImpl : public JavaScriptObject {
+private:
+ friend class JavaScript;
+
+ int _js_id = 0;
+ Callable _callable;
+
+ static int _variant2js(const void **p_args, int p_pos, godot_js_wrapper_ex *r_val, void **p_lock);
+ static void _free_lock(void **p_lock, int p_type);
+ static Variant _js2variant(int p_type, godot_js_wrapper_ex *p_val);
+ static void *_alloc_variants(int p_size);
+ static void _callback(void *p_ref, int p_arg_id, int p_argc);
+
+protected:
+ bool _set(const StringName &p_name, const Variant &p_value) override;
+ bool _get(const StringName &p_name, Variant &r_ret) const override;
+ void _get_property_list(List<PropertyInfo> *p_list) const override;
+
+public:
+ Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const override;
+ void setvar(const Variant &p_key, const Variant &p_value, bool *r_valid = nullptr) override;
+ Variant call(const StringName &p_method, const Variant **p_args, int p_argc, Callable::CallError &r_error) override;
+ JavaScriptObjectImpl() {}
+ JavaScriptObjectImpl(int p_id) { _js_id = p_id; }
+ ~JavaScriptObjectImpl() {
+ if (_js_id) {
+ godot_js_wrapper_object_unref(_js_id);
+ }
+ }
+};
+
+bool JavaScriptObjectImpl::_set(const StringName &p_name, const Variant &p_value) {
+ ERR_FAIL_COND_V_MSG(!_js_id, false, "Invalid JS instance");
+ const String name = p_name;
+ godot_js_wrapper_ex exchange;
+ void *lock = nullptr;
+ const Variant *v = &p_value;
+ int type = _variant2js((const void **)&v, 0, &exchange, &lock);
+ godot_js_wrapper_object_set(_js_id, name.utf8().get_data(), type, &exchange);
+ if (lock) {
+ _free_lock(&lock, type);
+ }
+ return true;
+}
+
+bool JavaScriptObjectImpl::_get(const StringName &p_name, Variant &r_ret) const {
+ ERR_FAIL_COND_V_MSG(!_js_id, false, "Invalid JS instance");
+ const String name = p_name;
+ godot_js_wrapper_ex exchange;
+ int type = godot_js_wrapper_object_get(_js_id, &exchange, name.utf8().get_data());
+ r_ret = _js2variant(type, &exchange);
+ return true;
+}
+
+Variant JavaScriptObjectImpl::getvar(const Variant &p_key, bool *r_valid) const {
+ if (r_valid) {
+ *r_valid = false;
+ }
+ godot_js_wrapper_ex exchange;
+ void *lock = nullptr;
+ const Variant *v = &p_key;
+ int prop_type = _variant2js((const void **)&v, 0, &exchange, &lock);
+ int type = godot_js_wrapper_object_getvar(_js_id, prop_type, &exchange);
+ if (lock) {
+ _free_lock(&lock, prop_type);
+ }
+ if (type < 0) {
+ return Variant();
+ }
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return _js2variant(type, &exchange);
+}
+
+void JavaScriptObjectImpl::setvar(const Variant &p_key, const Variant &p_value, bool *r_valid) {
+ if (r_valid) {
+ *r_valid = false;
+ }
+ godot_js_wrapper_ex kex, vex;
+ void *klock = nullptr;
+ void *vlock = nullptr;
+ const Variant *kv = &p_key;
+ const Variant *vv = &p_value;
+ int ktype = _variant2js((const void **)&kv, 0, &kex, &klock);
+ int vtype = _variant2js((const void **)&vv, 0, &vex, &vlock);
+ int ret = godot_js_wrapper_object_setvar(_js_id, ktype, &kex, vtype, &vex);
+ if (klock) {
+ _free_lock(&klock, ktype);
+ }
+ if (vlock) {
+ _free_lock(&vlock, vtype);
+ }
+ if (ret == 0 && r_valid) {
+ *r_valid = true;
+ }
+}
+
+void JavaScriptObjectImpl::_get_property_list(List<PropertyInfo> *p_list) const {
+}
+
+void JavaScriptObjectImpl::_free_lock(void **p_lock, int p_type) {
+ ERR_FAIL_COND_MSG(*p_lock == nullptr, "No lock to free!");
+ const Variant::Type type = (Variant::Type)p_type;
+ switch (type) {
+ case Variant::STRING: {
+ CharString *cs = (CharString *)(*p_lock);
+ memdelete(cs);
+ *p_lock = nullptr;
+ } break;
+ default:
+ ERR_FAIL_MSG("Unknown lock type to free. Likely a bug.");
+ }
+}
+
+Variant JavaScriptObjectImpl::_js2variant(int p_type, godot_js_wrapper_ex *p_val) {
+ Variant::Type type = (Variant::Type)p_type;
+ switch (type) {
+ case Variant::BOOL:
+ return Variant((bool)p_val->i);
+ case Variant::INT:
+ return p_val->i;
+ case Variant::FLOAT:
+ return p_val->r;
+ case Variant::STRING: {
+ String out((const char *)p_val->p);
+ free(p_val->p);
+ return out;
+ }
+ case Variant::OBJECT: {
+ return memnew(JavaScriptObjectImpl(p_val->i));
+ }
+ default:
+ return Variant();
+ }
+}
+
+int JavaScriptObjectImpl::_variant2js(const void **p_args, int p_pos, godot_js_wrapper_ex *r_val, void **p_lock) {
+ const Variant **args = (const Variant **)p_args;
+ const Variant *v = args[p_pos];
+ Variant::Type type = v->get_type();
+ switch (type) {
+ case Variant::BOOL:
+ r_val->i = v->operator bool() ? 1 : 0;
+ break;
+ case Variant::INT: {
+ const int64_t tmp = v->operator int64_t();
+ if (tmp >= 1 << 31) {
+ r_val->r = (double)tmp;
+ return Variant::FLOAT;
+ }
+ r_val->i = v->operator int64_t();
+ } break;
+ case Variant::FLOAT:
+ r_val->r = v->operator real_t();
+ break;
+ case Variant::STRING: {
+ CharString *cs = memnew(CharString(v->operator String().utf8()));
+ r_val->p = (void *)cs->get_data();
+ *p_lock = (void *)cs;
+ } break;
+ case Variant::OBJECT: {
+ JavaScriptObject *js_obj = Object::cast_to<JavaScriptObject>(v->operator Object *());
+ r_val->i = js_obj != nullptr ? ((JavaScriptObjectImpl *)js_obj)->_js_id : 0;
+ } break;
+ default:
+ break;
+ }
+ return type;
+}
+
+Variant JavaScriptObjectImpl::call(const StringName &p_method, const Variant **p_args, int p_argc, Callable::CallError &r_error) {
+ godot_js_wrapper_ex exchange;
+ const String method = p_method;
+ void *lock = nullptr;
+ const int type = godot_js_wrapper_object_call(_js_id, method.utf8().get_data(), (void **)p_args, p_argc, &_variant2js, &exchange, &lock, &_free_lock);
+ r_error.error = Callable::CallError::CALL_OK;
+ if (type < 0) {
+ r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return Variant();
+ }
+ return _js2variant(type, &exchange);
+}
+
+void JavaScriptObjectImpl::_callback(void *p_ref, int p_args_id, int p_argc) {
+ const JavaScriptObjectImpl *obj = (JavaScriptObjectImpl *)p_ref;
+ ERR_FAIL_COND_MSG(obj->_callable.is_null(), "JavaScript callback failed.");
+ Vector<const Variant *> argp;
+ Array arg_arr;
+ for (int i = 0; i < p_argc; i++) {
+ godot_js_wrapper_ex exchange;
+ exchange.i = i;
+ int type = godot_js_wrapper_object_getvar(p_args_id, Variant::INT, &exchange);
+ arg_arr.push_back(_js2variant(type, &exchange));
+ }
+ Variant arg = arg_arr;
+ const Variant *argv[1] = { &arg };
+ Callable::CallError err;
+ Variant ret;
+ obj->_callable.call(argv, 1, ret, err);
+}
+
+Ref<JavaScriptObject> JavaScript::create_callback(const Callable &p_callable) {
+ Ref<JavaScriptObjectImpl> out = memnew(JavaScriptObjectImpl);
+ out->_callable = p_callable;
+ out->_js_id = godot_js_wrapper_create_cb(out.ptr(), JavaScriptObjectImpl::_callback);
+ return out;
+}
+
+Ref<JavaScriptObject> JavaScript::get_interface(const String &p_interface) {
+ int js_id = godot_js_wrapper_interface_get(p_interface.utf8().get_data());
+ ERR_FAIL_COND_V_MSG(!js_id, Ref<JavaScriptObject>(), "No interface '" + p_interface + "' registered.");
+ return Ref<JavaScriptObject>(memnew(JavaScriptObjectImpl(js_id)));
+}
+
+Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_argcount < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ return Ref<JavaScriptObject>();
+ }
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ return Ref<JavaScriptObject>();
+ }
+ godot_js_wrapper_ex exchange;
+ const String object = *p_args[0];
+ void *lock = nullptr;
+ const Variant **args = p_argcount > 1 ? &p_args[1] : nullptr;
+ const int type = godot_js_wrapper_create_object(object.utf8().get_data(), (void **)args, p_argcount - 1, &JavaScriptObjectImpl::_variant2js, &exchange, &lock, &JavaScriptObjectImpl::_free_lock);
+ r_error.error = Callable::CallError::CALL_OK;
+ if (type < 0) {
+ r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return Ref<JavaScriptObject>();
+ }
+ return JavaScriptObjectImpl::_js2variant(type, &exchange);
+}
+
+extern "C" {
+union js_eval_ret {
+ uint32_t b;
+ double d;
+ char *s;
+};
+
+extern int godot_js_eval(const char *p_js, int p_use_global_ctx, union js_eval_ret *p_union_ptr, void *p_byte_arr, void *p_byte_arr_write, void *(*p_callback)(void *p_ptr, void *p_ptr2, int p_len));
+}
+
+void *resize_PackedByteArray_and_open_write(void *p_arr, void *r_write, int p_len) {
+ PackedByteArray *arr = (PackedByteArray *)p_arr;
+ VectorWriteProxy<uint8_t> *write = (VectorWriteProxy<uint8_t> *)r_write;
+ arr->resize(p_len);
+ *write = arr->write;
+ return arr->ptrw();
+}
+
+Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
+ union js_eval_ret js_data;
+ PackedByteArray arr;
+ VectorWriteProxy<uint8_t> arr_write;
+
+ Variant::Type return_type = static_cast<Variant::Type>(godot_js_eval(p_code.utf8().get_data(), p_use_global_exec_context, &js_data, &arr, &arr_write, resize_PackedByteArray_and_open_write));
+
+ switch (return_type) {
+ case Variant::BOOL:
+ return js_data.b;
+ case Variant::FLOAT:
+ return js_data.d;
+ case Variant::STRING: {
+ String str = String::utf8(js_data.s);
+ free(js_data.s); // Must free the string allocated in JS.
+ return str;
+ }
+ case Variant::PACKED_BYTE_ARRAY:
+ arr_write = VectorWriteProxy<uint8_t>();
+ return arr;
+ default:
+ return Variant();
+ }
+}
+#endif // JAVASCRIPT_EVAL_ENABLED
+
+void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
+ godot_js_os_download_buffer(p_arr.ptr(), p_arr.size(), p_name.utf8().get_data(), p_mime.utf8().get_data());
+}
diff --git a/platform/javascript/js/libs/library_godot_audio.js b/platform/javascript/js/libs/library_godot_audio.js
index ac4055516c..45c3a3fe2e 100644
--- a/platform/javascript/js/libs/library_godot_audio.js
+++ b/platform/javascript/js/libs/library_godot_audio.js
@@ -59,7 +59,7 @@ const GodotAudio = {
}
onstatechange(state);
};
- ctx.onstatechange(); // Immeditately notify state.
+ ctx.onstatechange(); // Immediately notify state.
// Update computed latency
GodotAudio.interval = setInterval(function () {
let computed_latency = 0;
diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js
index 91cab5eacc..affae90370 100644
--- a/platform/javascript/js/libs/library_godot_display.js
+++ b/platform/javascript/js/libs/library_godot_display.js
@@ -683,7 +683,7 @@ const GodotDisplay = {
return GodotDisplayScreen.exitFullscreen();
},
- godot_js_display_desired_size_set__sig: 'v',
+ godot_js_display_desired_size_set__sig: 'vii',
godot_js_display_desired_size_set: function (width, height) {
GodotDisplayScreen.desired_size = [width, height];
GodotDisplayScreen.updateSize();
diff --git a/platform/javascript/js/libs/library_godot_editor_tools.js b/platform/javascript/js/libs/library_godot_editor_tools.js
deleted file mode 100644
index d7f1ad5ea1..0000000000
--- a/platform/javascript/js/libs/library_godot_editor_tools.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*************************************************************************/
-/* library_godot_editor_tools.js */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-const GodotEditorTools = {
- godot_js_editor_download_file__deps: ['$FS'],
- godot_js_editor_download_file__sig: 'viii',
- godot_js_editor_download_file: function (p_path, p_name, p_mime) {
- const path = GodotRuntime.parseString(p_path);
- const name = GodotRuntime.parseString(p_name);
- const mime = GodotRuntime.parseString(p_mime);
- const size = FS.stat(path)['size'];
- const buf = new Uint8Array(size);
- const fd = FS.open(path, 'r');
- FS.read(fd, buf, 0, size);
- FS.close(fd);
- FS.unlink(path);
- const blob = new Blob([buf], { type: mime });
- const url = window.URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = name;
- a.style.display = 'none';
- document.body.appendChild(a);
- a.click();
- a.remove();
- window.URL.revokeObjectURL(url);
- },
-};
-
-mergeInto(LibraryManager.library, GodotEditorTools);
diff --git a/platform/javascript/js/libs/library_godot_eval.js b/platform/javascript/js/libs/library_godot_eval.js
deleted file mode 100644
index 9ab392b813..0000000000
--- a/platform/javascript/js/libs/library_godot_eval.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/*************************************************************************/
-/* library_godot_eval.js */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-const GodotEval = {
- godot_js_eval__deps: ['$GodotRuntime'],
- godot_js_eval__sig: 'iiiiiii',
- godot_js_eval: function (p_js, p_use_global_ctx, p_union_ptr, p_byte_arr, p_byte_arr_write, p_callback) {
- const js_code = GodotRuntime.parseString(p_js);
- let eval_ret = null;
- try {
- if (p_use_global_ctx) {
- // indirect eval call grants global execution context
- const global_eval = eval; // eslint-disable-line no-eval
- eval_ret = global_eval(js_code);
- } else {
- eval_ret = eval(js_code); // eslint-disable-line no-eval
- }
- } catch (e) {
- GodotRuntime.error(e);
- }
-
- switch (typeof eval_ret) {
- case 'boolean':
- GodotRuntime.setHeapValue(p_union_ptr, eval_ret, 'i32');
- return 1; // BOOL
-
- case 'number':
- GodotRuntime.setHeapValue(p_union_ptr, eval_ret, 'double');
- return 3; // REAL
-
- case 'string':
- GodotRuntime.setHeapValue(p_union_ptr, GodotRuntime.allocString(eval_ret), '*');
- return 4; // STRING
-
- case 'object':
- if (eval_ret === null) {
- break;
- }
-
- if (ArrayBuffer.isView(eval_ret) && !(eval_ret instanceof Uint8Array)) {
- eval_ret = new Uint8Array(eval_ret.buffer);
- } else if (eval_ret instanceof ArrayBuffer) {
- eval_ret = new Uint8Array(eval_ret);
- }
- if (eval_ret instanceof Uint8Array) {
- const func = GodotRuntime.get_func(p_callback);
- const bytes_ptr = func(p_byte_arr, p_byte_arr_write, eval_ret.length);
- HEAPU8.set(eval_ret, bytes_ptr);
- return 20; // POOL_BYTE_ARRAY
- }
- break;
-
- // no default
- }
- return 0; // NIL
- },
-};
-
-mergeInto(LibraryManager.library, GodotEval);
diff --git a/platform/javascript/js/libs/library_godot_fetch.js b/platform/javascript/js/libs/library_godot_fetch.js
index de5ae2b1ae..615f9de8b0 100644
--- a/platform/javascript/js/libs/library_godot_fetch.js
+++ b/platform/javascript/js/libs/library_godot_fetch.js
@@ -29,7 +29,7 @@
/*************************************************************************/
const GodotFetch = {
- $GodotFetch__deps: ['$GodotRuntime'],
+ $GodotFetch__deps: ['$IDHandler', '$GodotRuntime'],
$GodotFetch: {
onread: function (id, result) {
@@ -126,7 +126,7 @@ const GodotFetch = {
},
},
- godot_js_fetch_create__sig: 'iii',
+ godot_js_fetch_create__sig: 'iiiiiii',
godot_js_fetch_create: function (p_method, p_url, p_headers, p_headers_size, p_body, p_body_size) {
const method = GodotRuntime.parseString(p_method);
const url = GodotRuntime.parseString(p_url);
@@ -176,7 +176,7 @@ const GodotFetch = {
return obj.status;
},
- godot_js_fetch_read_headers__sig: 'iii',
+ godot_js_fetch_read_headers__sig: 'iiii',
godot_js_fetch_read_headers: function (p_id, p_parse_cb, p_ref) {
const obj = IDHandler.get(p_id);
if (!obj || !obj.response) {
@@ -193,7 +193,7 @@ const GodotFetch = {
return 0;
},
- godot_js_fetch_read_chunk__sig: 'ii',
+ godot_js_fetch_read_chunk__sig: 'iiii',
godot_js_fetch_read_chunk: function (p_id, p_buf, p_buf_size) {
const obj = IDHandler.get(p_id);
if (!obj || !obj.response) {
diff --git a/platform/javascript/js/libs/library_godot_javascript_singleton.js b/platform/javascript/js/libs/library_godot_javascript_singleton.js
new file mode 100644
index 0000000000..cb80273ca8
--- /dev/null
+++ b/platform/javascript/js/libs/library_godot_javascript_singleton.js
@@ -0,0 +1,333 @@
+/*************************************************************************/
+/* library_godot_eval.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+const GodotJSWrapper = {
+
+ $GodotJSWrapper__deps: ['$GodotRuntime', '$IDHandler'],
+ $GodotJSWrapper__postset: 'GodotJSWrapper.proxies = new Map();',
+ $GodotJSWrapper: {
+ proxies: null,
+
+ MyProxy: function (val) {
+ const id = IDHandler.add(this);
+ GodotJSWrapper.proxies.set(val, id);
+ let refs = 1;
+ this.ref = function () {
+ refs++;
+ };
+ this.unref = function () {
+ refs--;
+ if (refs === 0) {
+ IDHandler.remove(id);
+ GodotJSWrapper.proxies.delete(val);
+ }
+ };
+ this.get_val = function () {
+ return val;
+ };
+ this.get_id = function () {
+ return id;
+ };
+ },
+
+ get_proxied: function (val) {
+ const id = GodotJSWrapper.proxies.get(val);
+ if (id === undefined) {
+ const proxy = new GodotJSWrapper.MyProxy(val);
+ return proxy.get_id();
+ }
+ IDHandler.get(id).ref();
+ return id;
+ },
+
+ get_proxied_value: function (id) {
+ const proxy = IDHandler.get(id);
+ if (proxy === undefined) {
+ return undefined;
+ }
+ return proxy.get_val();
+ },
+
+ variant2js: function (type, val) {
+ switch (type) {
+ case 0:
+ return null;
+ case 1:
+ return !!GodotRuntime.getHeapValue(val, 'i64');
+ case 2:
+ return GodotRuntime.getHeapValue(val, 'i64');
+ case 3:
+ return GodotRuntime.getHeapValue(val, 'double');
+ case 4:
+ return GodotRuntime.parseString(GodotRuntime.getHeapValue(val, '*'));
+ case 21: // OBJECT
+ return GodotJSWrapper.get_proxied_value(GodotRuntime.getHeapValue(val, 'i64'));
+ default:
+ return undefined;
+ }
+ },
+
+ js2variant: function (p_val, p_exchange) {
+ if (p_val === undefined || p_val === null) {
+ return 0; // NIL
+ }
+ const type = typeof (p_val);
+ if (type === 'boolean') {
+ GodotRuntime.setHeapValue(p_exchange, p_val, 'i64');
+ return 1; // BOOL
+ } else if (type === 'number') {
+ if (Number.isInteger(p_val)) {
+ GodotRuntime.setHeapValue(p_exchange, p_val, 'i64');
+ return 2; // INT
+ }
+ GodotRuntime.setHeapValue(p_exchange, p_val, 'double');
+ return 3; // REAL
+ } else if (type === 'string') {
+ const c_str = GodotRuntime.allocString(p_val);
+ GodotRuntime.setHeapValue(p_exchange, c_str, '*');
+ return 4; // STRING
+ }
+ const id = GodotJSWrapper.get_proxied(p_val);
+ GodotRuntime.setHeapValue(p_exchange, id, 'i64');
+ return 21;
+ },
+ },
+
+ godot_js_wrapper_interface_get__sig: 'ii',
+ godot_js_wrapper_interface_get: function (p_name) {
+ const name = GodotRuntime.parseString(p_name);
+ if (typeof (window[name]) !== 'undefined') {
+ return GodotJSWrapper.get_proxied(window[name]);
+ }
+ return 0;
+ },
+
+ godot_js_wrapper_object_get__sig: 'iiii',
+ godot_js_wrapper_object_get: function (p_id, p_exchange, p_prop) {
+ const obj = GodotJSWrapper.get_proxied_value(p_id);
+ if (obj === undefined) {
+ return 0;
+ }
+ if (p_prop) {
+ const prop = GodotRuntime.parseString(p_prop);
+ try {
+ return GodotJSWrapper.js2variant(obj[prop], p_exchange);
+ } catch (e) {
+ GodotRuntime.error(`Error getting variable ${prop} on object`, obj);
+ return 0; // NIL
+ }
+ }
+ return GodotJSWrapper.js2variant(obj, p_exchange);
+ },
+
+ godot_js_wrapper_object_set__sig: 'viiii',
+ godot_js_wrapper_object_set: function (p_id, p_name, p_type, p_exchange) {
+ const obj = GodotJSWrapper.get_proxied_value(p_id);
+ if (obj === undefined) {
+ return;
+ }
+ const name = GodotRuntime.parseString(p_name);
+ try {
+ obj[name] = GodotJSWrapper.variant2js(p_type, p_exchange);
+ } catch (e) {
+ GodotRuntime.error(`Error setting variable ${name} on object`, obj);
+ }
+ },
+
+ godot_js_wrapper_object_call__sig: 'iiiiiiiii',
+ godot_js_wrapper_object_call: function (p_id, p_method, p_args, p_argc, p_convert_callback, p_exchange, p_lock, p_free_lock_callback) {
+ const obj = GodotJSWrapper.get_proxied_value(p_id);
+ if (obj === undefined) {
+ return -1;
+ }
+ const method = GodotRuntime.parseString(p_method);
+ const convert = GodotRuntime.get_func(p_convert_callback);
+ const freeLock = GodotRuntime.get_func(p_free_lock_callback);
+ const args = new Array(p_argc);
+ for (let i = 0; i < p_argc; i++) {
+ const type = convert(p_args, i, p_exchange, p_lock);
+ const lock = GodotRuntime.getHeapValue(p_lock, '*');
+ args[i] = GodotJSWrapper.variant2js(type, p_exchange);
+ if (lock) {
+ freeLock(p_lock, type);
+ }
+ }
+ try {
+ const res = obj[method](...args);
+ return GodotJSWrapper.js2variant(res, p_exchange);
+ } catch (e) {
+ GodotRuntime.error(`Error calling method ${method} on:`, obj, 'error:', e);
+ return -1;
+ }
+ },
+
+ godot_js_wrapper_object_unref__sig: 'vi',
+ godot_js_wrapper_object_unref: function (p_id) {
+ const proxy = IDHandler.get(p_id);
+ if (proxy !== undefined) {
+ proxy.unref();
+ }
+ },
+
+ godot_js_wrapper_create_cb__sig: 'iii',
+ godot_js_wrapper_create_cb: function (p_ref, p_func) {
+ const func = GodotRuntime.get_func(p_func);
+ let id = 0;
+ const cb = function () {
+ if (!GodotJSWrapper.get_proxied_value(id)) {
+ return;
+ }
+ const args = Array.from(arguments);
+ func(p_ref, GodotJSWrapper.get_proxied(args), args.length);
+ };
+ id = GodotJSWrapper.get_proxied(cb);
+ return id;
+ },
+
+ godot_js_wrapper_object_getvar__sig: 'iiii',
+ godot_js_wrapper_object_getvar: function (p_id, p_type, p_exchange) {
+ const obj = GodotJSWrapper.get_proxied_value(p_id);
+ if (obj === undefined) {
+ return -1;
+ }
+ const prop = GodotJSWrapper.variant2js(p_type, p_exchange);
+ if (prop === undefined || prop === null) {
+ return -1;
+ }
+ try {
+ return GodotJSWrapper.js2variant(obj[prop], p_exchange);
+ } catch (e) {
+ GodotRuntime.error(`Error getting variable ${prop} on object`, obj, e);
+ return -1;
+ }
+ },
+
+ godot_js_wrapper_object_setvar__sig: 'iiiiii',
+ godot_js_wrapper_object_setvar: function (p_id, p_key_type, p_key_ex, p_val_type, p_val_ex) {
+ const obj = GodotJSWrapper.get_proxied_value(p_id);
+ if (obj === undefined) {
+ return -1;
+ }
+ const key = GodotJSWrapper.variant2js(p_key_type, p_key_ex);
+ try {
+ obj[key] = GodotJSWrapper.variant2js(p_val_type, p_val_ex);
+ return 0;
+ } catch (e) {
+ GodotRuntime.error(`Error setting variable ${key} on object`, obj);
+ return -1;
+ }
+ },
+
+ godot_js_wrapper_create_object__sig: 'iiiiiiii',
+ godot_js_wrapper_create_object: function (p_object, p_args, p_argc, p_convert_callback, p_exchange, p_lock, p_free_lock_callback) {
+ const name = GodotRuntime.parseString(p_object);
+ if (typeof (window[name]) === 'undefined') {
+ return -1;
+ }
+ const convert = GodotRuntime.get_func(p_convert_callback);
+ const freeLock = GodotRuntime.get_func(p_free_lock_callback);
+ const args = new Array(p_argc);
+ for (let i = 0; i < p_argc; i++) {
+ const type = convert(p_args, i, p_exchange, p_lock);
+ const lock = GodotRuntime.getHeapValue(p_lock, '*');
+ args[i] = GodotJSWrapper.variant2js(type, p_exchange);
+ if (lock) {
+ freeLock(p_lock, type);
+ }
+ }
+ try {
+ const res = new window[name](...args);
+ return GodotJSWrapper.js2variant(res, p_exchange);
+ } catch (e) {
+ GodotRuntime.error(`Error calling constructor ${name} with args:`, args, 'error:', e);
+ return -1;
+ }
+ },
+};
+
+autoAddDeps(GodotJSWrapper, '$GodotJSWrapper');
+mergeInto(LibraryManager.library, GodotJSWrapper);
+
+const GodotEval = {
+ godot_js_eval__deps: ['$GodotRuntime'],
+ godot_js_eval__sig: 'iiiiiii',
+ godot_js_eval: function (p_js, p_use_global_ctx, p_union_ptr, p_byte_arr, p_byte_arr_write, p_callback) {
+ const js_code = GodotRuntime.parseString(p_js);
+ let eval_ret = null;
+ try {
+ if (p_use_global_ctx) {
+ // indirect eval call grants global execution context
+ const global_eval = eval; // eslint-disable-line no-eval
+ eval_ret = global_eval(js_code);
+ } else {
+ eval_ret = eval(js_code); // eslint-disable-line no-eval
+ }
+ } catch (e) {
+ GodotRuntime.error(e);
+ }
+
+ switch (typeof eval_ret) {
+ case 'boolean':
+ GodotRuntime.setHeapValue(p_union_ptr, eval_ret, 'i32');
+ return 1; // BOOL
+
+ case 'number':
+ GodotRuntime.setHeapValue(p_union_ptr, eval_ret, 'double');
+ return 3; // REAL
+
+ case 'string':
+ GodotRuntime.setHeapValue(p_union_ptr, GodotRuntime.allocString(eval_ret), '*');
+ return 4; // STRING
+
+ case 'object':
+ if (eval_ret === null) {
+ break;
+ }
+
+ if (ArrayBuffer.isView(eval_ret) && !(eval_ret instanceof Uint8Array)) {
+ eval_ret = new Uint8Array(eval_ret.buffer);
+ } else if (eval_ret instanceof ArrayBuffer) {
+ eval_ret = new Uint8Array(eval_ret);
+ }
+ if (eval_ret instanceof Uint8Array) {
+ const func = GodotRuntime.get_func(p_callback);
+ const bytes_ptr = func(p_byte_arr, p_byte_arr_write, eval_ret.length);
+ HEAPU8.set(eval_ret, bytes_ptr);
+ return 20; // POOL_BYTE_ARRAY
+ }
+ break;
+
+ // no default
+ }
+ return 0; // NIL
+ },
+};
+
+mergeInto(LibraryManager.library, GodotEval);
diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js
index 1d9f889bce..7414b8cc47 100644
--- a/platform/javascript/js/libs/library_godot_os.js
+++ b/platform/javascript/js/libs/library_godot_os.js
@@ -304,6 +304,23 @@ const GodotOS = {
godot_js_os_hw_concurrency_get: function () {
return navigator.hardwareConcurrency || 1;
},
+
+ godot_js_os_download_buffer__sig: 'viiii',
+ godot_js_os_download_buffer: function (p_ptr, p_size, p_name, p_mime) {
+ const buf = GodotRuntime.heapSlice(HEAP8, p_ptr, p_size);
+ const name = GodotRuntime.parseString(p_name);
+ const mime = GodotRuntime.parseString(p_mime);
+ const blob = new Blob([buf], { type: mime });
+ const url = window.URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = name;
+ a.style.display = 'none';
+ document.body.appendChild(a);
+ a.click();
+ a.remove();
+ window.URL.revokeObjectURL(url);
+ },
};
autoAddDeps(GodotOS, '$GodotOS');
diff --git a/platform/javascript/package-lock.json b/platform/javascript/package-lock.json
index b8c434b3dd..8003619576 100644
--- a/platform/javascript/package-lock.json
+++ b/platform/javascript/package-lock.json
@@ -5,27 +5,27 @@
"requires": true,
"dependencies": {
"@babel/code-frame": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
- "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
+ "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
"dev": true,
"requires": {
"@babel/highlight": "^7.10.4"
}
},
"@babel/helper-validator-identifier": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
- "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
+ "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
"dev": true
},
"@babel/highlight": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
- "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
+ "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.10.4",
+ "@babel/helper-validator-identifier": "^7.14.5",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
},
@@ -40,39 +40,38 @@
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
}
}
},
"@babel/parser": {
- "version": "7.13.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.4.tgz",
- "integrity": "sha512-uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA==",
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.5.tgz",
+ "integrity": "sha512-TM8C+xtH/9n1qzX+JNHi7AN2zHMTiPUtspO0ZdHflW8KaskkALhMmuMHb4bCmNdv9VAPzJX3/bXqkVLnAvsPfg==",
"dev": true
},
"@eslint/eslintrc": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz",
- "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==",
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz",
+ "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
"debug": "^4.1.1",
"espree": "^7.3.0",
- "globals": "^12.1.0",
+ "globals": "^13.9.0",
"ignore": "^4.0.6",
"import-fresh": "^3.2.1",
"js-yaml": "^3.13.1",
- "lodash": "^4.17.19",
"minimatch": "^3.0.4",
"strip-json-comments": "^3.1.1"
}
},
- "@types/color-name": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
- "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
- "dev": true
- },
"@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -80,9 +79,9 @@
"dev": true
},
"acorn": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
- "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==",
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
"dev": true
},
"acorn-jsx": {
@@ -92,9 +91,9 @@
"dev": true
},
"ajv": {
- "version": "6.12.5",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz",
- "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==",
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
@@ -134,78 +133,39 @@
}
},
"array-includes": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz",
- "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz",
+ "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==",
"dev": true,
"requires": {
+ "call-bind": "^1.0.2",
"define-properties": "^1.1.3",
- "es-abstract": "^1.17.0",
+ "es-abstract": "^1.18.0-next.2",
+ "get-intrinsic": "^1.1.1",
"is-string": "^1.0.5"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.17.6",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
- "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
- "dev": true,
- "requires": {
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.0",
- "is-regex": "^1.1.0",
- "object-inspect": "^1.7.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.0",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
- }
- }
}
},
"array.prototype.flat": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz",
- "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==",
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz",
+ "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==",
"dev": true,
"requires": {
+ "call-bind": "^1.0.0",
"define-properties": "^1.1.3",
- "es-abstract": "^1.17.0-next.1"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.17.6",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
- "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
- "dev": true,
- "requires": {
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.0",
- "is-regex": "^1.1.0",
- "object-inspect": "^1.7.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.0",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
- }
- }
+ "es-abstract": "^1.18.0-next.1"
}
},
"astral-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
- "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
"dev": true
},
"balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"bluebird": {
@@ -224,6 +184,16 @@
"concat-map": "0.0.1"
}
},
+ "call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
"callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -231,18 +201,18 @@
"dev": true
},
"catharsis": {
- "version": "0.8.11",
- "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz",
- "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==",
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
+ "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
"dev": true,
"requires": {
- "lodash": "^4.17.14"
+ "lodash": "^4.17.15"
}
},
"chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+ "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
@@ -250,12 +220,11 @@
},
"dependencies": {
"ansi-styles": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
- "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
- "@types/color-name": "^1.1.1",
"color-convert": "^2.0.1"
}
},
@@ -313,15 +282,9 @@
"dev": true
},
"confusing-browser-globals": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz",
- "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==",
- "dev": true
- },
- "contains-path": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
- "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=",
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz",
+ "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==",
"dev": true
},
"cross-spawn": {
@@ -336,12 +299,12 @@
}
},
"debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"dev": true,
"requires": {
- "ms": "^2.1.1"
+ "ms": "2.1.2"
}
},
"deep-is": {
@@ -369,9 +332,9 @@
}
},
"emoji-regex": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
- "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"enquirer": {
@@ -399,23 +362,27 @@
}
},
"es-abstract": {
- "version": "1.18.0-next.0",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz",
- "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==",
+ "version": "1.18.3",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz",
+ "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==",
"dev": true,
"requires": {
+ "call-bind": "^1.0.2",
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
+ "get-intrinsic": "^1.1.1",
"has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.0",
- "is-negative-zero": "^2.0.0",
- "is-regex": "^1.1.1",
- "object-inspect": "^1.8.0",
+ "has-symbols": "^1.0.2",
+ "is-callable": "^1.2.3",
+ "is-negative-zero": "^2.0.1",
+ "is-regex": "^1.1.3",
+ "is-string": "^1.0.6",
+ "object-inspect": "^1.10.3",
"object-keys": "^1.1.1",
- "object.assign": "^4.1.0",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
+ "object.assign": "^4.1.2",
+ "string.prototype.trimend": "^1.0.4",
+ "string.prototype.trimstart": "^1.0.4",
+ "unbox-primitive": "^1.0.1"
}
},
"es-to-primitive": {
@@ -430,35 +397,37 @@
}
},
"escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true
},
"eslint": {
- "version": "7.9.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.9.0.tgz",
- "integrity": "sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA==",
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz",
+ "integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.0.0",
- "@eslint/eslintrc": "^0.1.3",
+ "@babel/code-frame": "7.12.11",
+ "@eslint/eslintrc": "^0.4.2",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.0.1",
"doctrine": "^3.0.0",
"enquirer": "^2.3.5",
- "eslint-scope": "^5.1.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^5.1.1",
"eslint-utils": "^2.1.0",
- "eslint-visitor-keys": "^1.3.0",
- "espree": "^7.3.0",
- "esquery": "^1.2.0",
+ "eslint-visitor-keys": "^2.0.0",
+ "espree": "^7.3.1",
+ "esquery": "^1.4.0",
"esutils": "^2.0.2",
- "file-entry-cache": "^5.0.1",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
"functional-red-black-tree": "^1.0.1",
- "glob-parent": "^5.0.0",
- "globals": "^12.1.0",
+ "glob-parent": "^5.1.2",
+ "globals": "^13.6.0",
"ignore": "^4.0.6",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
@@ -466,7 +435,7 @@
"js-yaml": "^3.13.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
- "lodash": "^4.17.19",
+ "lodash.merge": "^4.6.2",
"minimatch": "^3.0.4",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
@@ -475,19 +444,19 @@
"semver": "^7.2.1",
"strip-ansi": "^6.0.0",
"strip-json-comments": "^3.1.0",
- "table": "^5.2.3",
+ "table": "^6.0.9",
"text-table": "^0.2.0",
"v8-compile-cache": "^2.0.3"
}
},
"eslint-config-airbnb-base": {
- "version": "14.2.0",
- "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz",
- "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==",
+ "version": "14.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz",
+ "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==",
"dev": true,
"requires": {
- "confusing-browser-globals": "^1.0.9",
- "object.assign": "^4.1.0",
+ "confusing-browser-globals": "^1.0.10",
+ "object.assign": "^4.1.2",
"object.entries": "^1.1.2"
}
},
@@ -519,50 +488,46 @@
}
},
"eslint-module-utils": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz",
- "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==",
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz",
+ "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==",
"dev": true,
"requires": {
- "debug": "^2.6.9",
+ "debug": "^3.2.7",
"pkg-dir": "^2.0.0"
},
"dependencies": {
"debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"requires": {
- "ms": "2.0.0"
+ "ms": "^2.1.1"
}
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
}
}
},
"eslint-plugin-import": {
- "version": "2.22.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz",
- "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==",
+ "version": "2.23.4",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz",
+ "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==",
"dev": true,
"requires": {
- "array-includes": "^3.1.1",
- "array.prototype.flat": "^1.2.3",
- "contains-path": "^0.1.0",
+ "array-includes": "^3.1.3",
+ "array.prototype.flat": "^1.2.4",
"debug": "^2.6.9",
- "doctrine": "1.5.0",
- "eslint-import-resolver-node": "^0.3.3",
- "eslint-module-utils": "^2.6.0",
+ "doctrine": "^2.1.0",
+ "eslint-import-resolver-node": "^0.3.4",
+ "eslint-module-utils": "^2.6.1",
+ "find-up": "^2.0.0",
"has": "^1.0.3",
+ "is-core-module": "^2.4.0",
"minimatch": "^3.0.4",
- "object.values": "^1.1.1",
- "read-pkg-up": "^2.0.0",
- "resolve": "^1.17.0",
+ "object.values": "^1.1.3",
+ "pkg-up": "^2.0.0",
+ "read-pkg-up": "^3.0.0",
+ "resolve": "^1.20.0",
"tsconfig-paths": "^3.9.0"
},
"dependencies": {
@@ -576,13 +541,12 @@
}
},
"doctrine": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
- "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"requires": {
- "esutils": "^2.0.2",
- "isarray": "^1.0.0"
+ "esutils": "^2.0.2"
}
},
"ms": {
@@ -610,23 +574,39 @@
"dev": true,
"requires": {
"eslint-visitor-keys": "^1.1.0"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true
+ }
}
},
"eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+ "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
"dev": true
},
"espree": {
- "version": "7.3.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz",
- "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==",
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
+ "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
"dev": true,
"requires": {
"acorn": "^7.4.0",
- "acorn-jsx": "^5.2.0",
+ "acorn-jsx": "^5.3.1",
"eslint-visitor-keys": "^1.3.0"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true
+ }
}
},
"esprima": {
@@ -636,9 +616,9 @@
"dev": true
},
"esquery": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
- "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+ "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
"dev": true,
"requires": {
"estraverse": "^5.1.0"
@@ -700,12 +680,12 @@
"dev": true
},
"file-entry-cache": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
- "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
"dev": true,
"requires": {
- "flat-cache": "^2.0.1"
+ "flat-cache": "^3.0.4"
}
},
"find-up": {
@@ -718,20 +698,19 @@
}
},
"flat-cache": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
- "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
"dev": true,
"requires": {
- "flatted": "^2.0.0",
- "rimraf": "2.6.3",
- "write": "1.0.3"
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
}
},
"flatted": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
- "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz",
+ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
"dev": true
},
"fs.realpath": {
@@ -752,10 +731,21 @@
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
"dev": true
},
+ "get-intrinsic": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+ "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ }
+ },
"glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "version": "7.1.7",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
+ "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
@@ -767,27 +757,27 @@
}
},
"glob-parent": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
- "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
},
"globals": {
- "version": "12.4.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
- "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+ "version": "13.9.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz",
+ "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==",
"dev": true,
"requires": {
- "type-fest": "^0.8.1"
+ "type-fest": "^0.20.2"
}
},
"graceful-fs": {
- "version": "4.2.4",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
- "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "version": "4.2.6",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
+ "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
"dev": true
},
"has": {
@@ -799,6 +789,12 @@
"function-bind": "^1.1.1"
}
},
+ "has-bigints": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
+ "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==",
+ "dev": true
+ },
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@@ -806,15 +802,15 @@
"dev": true
},
"has-symbols": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
- "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
"dev": true
},
"hosted-git-info": {
- "version": "2.8.8",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
- "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
"ignore": {
@@ -824,9 +820,9 @@
"dev": true
},
"import-fresh": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
- "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
"dev": true,
"requires": {
"parent-module": "^1.0.0",
@@ -861,16 +857,40 @@
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
"dev": true
},
+ "is-bigint": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz",
+ "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==",
+ "dev": true
+ },
+ "is-boolean-object": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz",
+ "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.2"
+ }
+ },
"is-callable": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz",
- "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==",
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
+ "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==",
"dev": true
},
+ "is-core-module": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz",
+ "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
"is-date-object": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
- "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz",
+ "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==",
"dev": true
},
"is-extglob": {
@@ -880,9 +900,9 @@
"dev": true
},
"is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"is-glob": {
@@ -895,41 +915,42 @@
}
},
"is-negative-zero": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz",
- "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
+ "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==",
+ "dev": true
+ },
+ "is-number-object": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz",
+ "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==",
"dev": true
},
"is-regex": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
- "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz",
+ "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==",
"dev": true,
"requires": {
- "has-symbols": "^1.0.1"
+ "call-bind": "^1.0.2",
+ "has-symbols": "^1.0.2"
}
},
"is-string": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
- "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz",
+ "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==",
"dev": true
},
"is-symbol": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
- "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+ "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
"dev": true,
"requires": {
- "has-symbols": "^1.0.1"
+ "has-symbols": "^1.0.2"
}
},
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
- },
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -943,9 +964,9 @@
"dev": true
},
"js-yaml": {
- "version": "3.14.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
- "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
@@ -962,25 +983,25 @@
}
},
"jsdoc": {
- "version": "3.6.6",
- "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.6.tgz",
- "integrity": "sha512-znR99e1BHeyEkSvgDDpX0sTiTu+8aQyDl9DawrkOGZTTW8hv0deIFXx87114zJ7gRaDZKVQD/4tr1ifmJp9xhQ==",
+ "version": "3.6.7",
+ "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz",
+ "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==",
"dev": true,
"requires": {
"@babel/parser": "^7.9.4",
"bluebird": "^3.7.2",
- "catharsis": "^0.8.11",
+ "catharsis": "^0.9.0",
"escape-string-regexp": "^2.0.0",
"js2xmlparser": "^4.0.1",
"klaw": "^3.0.0",
"markdown-it": "^10.0.0",
"markdown-it-anchor": "^5.2.7",
- "marked": "^0.8.2",
+ "marked": "^2.0.3",
"mkdirp": "^1.0.4",
"requizzle": "^0.2.3",
"strip-json-comments": "^3.1.0",
"taffydb": "2.6.2",
- "underscore": "~1.10.2"
+ "underscore": "~1.13.1"
},
"dependencies": {
"escape-string-regexp": {
@@ -988,15 +1009,15 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
"dev": true
- },
- "mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
- "dev": true
}
}
},
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -1047,14 +1068,14 @@
}
},
"load-json-file": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
- "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
- "parse-json": "^2.2.0",
- "pify": "^2.0.0",
+ "parse-json": "^4.0.0",
+ "pify": "^3.0.0",
"strip-bom": "^3.0.0"
}
},
@@ -1069,11 +1090,38 @@
}
},
"lodash": {
- "version": "4.17.20",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
- "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
+ "dev": true
+ },
+ "lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "lodash.truncate": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
+ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
"dev": true
},
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
"markdown-it": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
@@ -1094,9 +1142,9 @@
"dev": true
},
"marked": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz",
- "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==",
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.7.tgz",
+ "integrity": "sha512-BJXxkuIfJchcXOJWTT2DOL+yFWifFv2yGYOUzvXg8Qz610QKw+sHCvTMYwA+qWGhlA2uivBezChZ/pBy1tWdkQ==",
"dev": true
},
"mdurl": {
@@ -1121,13 +1169,10 @@
"dev": true
},
"mkdirp": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
- "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.5"
- }
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
},
"ms": {
"version": "2.1.2",
@@ -1162,9 +1207,9 @@
}
},
"object-inspect": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
- "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
+ "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==",
"dev": true
},
"object-keys": {
@@ -1174,80 +1219,37 @@
"dev": true
},
"object.assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz",
- "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==",
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+ "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
"dev": true,
"requires": {
+ "call-bind": "^1.0.0",
"define-properties": "^1.1.3",
- "es-abstract": "^1.18.0-next.0",
"has-symbols": "^1.0.1",
"object-keys": "^1.1.1"
}
},
"object.entries": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz",
- "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==",
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz",
+ "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==",
"dev": true,
"requires": {
+ "call-bind": "^1.0.2",
"define-properties": "^1.1.3",
- "es-abstract": "^1.17.5",
- "has": "^1.0.3"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.17.6",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
- "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
- "dev": true,
- "requires": {
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.0",
- "is-regex": "^1.1.0",
- "object-inspect": "^1.7.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.0",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
- }
- }
+ "es-abstract": "^1.18.2"
}
},
"object.values": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz",
- "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==",
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz",
+ "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==",
"dev": true,
"requires": {
+ "call-bind": "^1.0.2",
"define-properties": "^1.1.3",
- "es-abstract": "^1.17.0-next.1",
- "function-bind": "^1.1.1",
- "has": "^1.0.3"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.17.6",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
- "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
- "dev": true,
- "requires": {
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.0",
- "is-regex": "^1.1.0",
- "object-inspect": "^1.7.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.0",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
- }
- }
+ "es-abstract": "^1.18.2"
}
},
"once": {
@@ -1307,12 +1309,13 @@
}
},
"parse-json": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
- "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
"dev": true,
"requires": {
- "error-ex": "^1.2.0"
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
}
},
"path-exists": {
@@ -1334,24 +1337,24 @@
"dev": true
},
"path-parse": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
- "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"path-type": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
- "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"requires": {
- "pify": "^2.0.0"
+ "pify": "^3.0.0"
}
},
"pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true
},
"pkg-dir": {
@@ -1363,6 +1366,15 @@
"find-up": "^2.1.0"
}
},
+ "pkg-up": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
+ "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
+ "dev": true,
+ "requires": {
+ "find-up": "^2.1.0"
+ }
+ },
"prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -1382,30 +1394,36 @@
"dev": true
},
"read-pkg": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
- "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
"dev": true,
"requires": {
- "load-json-file": "^2.0.0",
+ "load-json-file": "^4.0.0",
"normalize-package-data": "^2.3.2",
- "path-type": "^2.0.0"
+ "path-type": "^3.0.0"
}
},
"read-pkg-up": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
- "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+ "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
"dev": true,
"requires": {
"find-up": "^2.0.0",
- "read-pkg": "^2.0.0"
+ "read-pkg": "^3.0.0"
}
},
"regexpp": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
- "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+ "dev": true
+ },
+ "require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true
},
"requizzle": {
@@ -1418,11 +1436,12 @@
}
},
"resolve": {
- "version": "1.17.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
- "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
+ "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
"dev": true,
"requires": {
+ "is-core-module": "^2.2.0",
"path-parse": "^1.0.6"
}
},
@@ -1433,19 +1452,22 @@
"dev": true
},
"rimraf": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
- "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
},
"semver": {
- "version": "7.3.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
- "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
- "dev": true
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
},
"shebang-command": {
"version": "2.0.0",
@@ -1463,14 +1485,40 @@
"dev": true
},
"slice-ansi": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
- "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
"dev": true,
"requires": {
- "ansi-styles": "^3.2.0",
- "astral-regex": "^1.0.0",
- "is-fullwidth-code-point": "^2.0.0"
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ }
}
},
"spdx-correct": {
@@ -1500,9 +1548,9 @@
}
},
"spdx-license-ids": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz",
- "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz",
+ "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==",
"dev": true
},
"sprintf-js": {
@@ -1512,93 +1560,34 @@
"dev": true
},
"string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
+ "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
"dev": true,
"requires": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
- "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
- "dev": true
- },
- "strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "dev": true,
- "requires": {
- "ansi-regex": "^4.1.0"
- }
- }
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
}
},
"string.prototype.trimend": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
- "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
+ "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
"dev": true,
"requires": {
- "define-properties": "^1.1.3",
- "es-abstract": "^1.17.5"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.17.6",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
- "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
- "dev": true,
- "requires": {
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.0",
- "is-regex": "^1.1.0",
- "object-inspect": "^1.7.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.0",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
- }
- }
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
}
},
"string.prototype.trimstart": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
- "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
+ "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
"dev": true,
"requires": {
- "define-properties": "^1.1.3",
- "es-abstract": "^1.17.5"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.17.6",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
- "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
- "dev": true,
- "requires": {
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.0",
- "is-regex": "^1.1.0",
- "object-inspect": "^1.7.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.0",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
- }
- }
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
}
},
"strip-ansi": {
@@ -1632,15 +1621,37 @@
}
},
"table": {
- "version": "5.4.6",
- "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
- "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+ "version": "6.7.1",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz",
+ "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==",
"dev": true,
"requires": {
- "ajv": "^6.10.2",
- "lodash": "^4.17.14",
- "slice-ansi": "^2.1.0",
- "string-width": "^3.0.0"
+ "ajv": "^8.0.1",
+ "lodash.clonedeep": "^4.5.0",
+ "lodash.truncate": "^4.4.2",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz",
+ "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ }
}
},
"taffydb": {
@@ -1677,9 +1688,9 @@
}
},
"type-fest": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
- "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true
},
"uc.micro": {
@@ -1688,25 +1699,37 @@
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
"dev": true
},
+ "unbox-primitive": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
+ "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has-bigints": "^1.0.1",
+ "has-symbols": "^1.0.2",
+ "which-boxed-primitive": "^1.0.2"
+ }
+ },
"underscore": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz",
- "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==",
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz",
+ "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==",
"dev": true
},
"uri-js": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
- "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
"requires": {
"punycode": "^2.1.0"
}
},
"v8-compile-cache": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
- "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
"dev": true
},
"validate-npm-package-license": {
@@ -1728,6 +1751,19 @@
"isexe": "^2.0.0"
}
},
+ "which-boxed-primitive": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
+ "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+ "dev": true,
+ "requires": {
+ "is-bigint": "^1.0.1",
+ "is-boolean-object": "^1.1.0",
+ "is-number-object": "^1.0.4",
+ "is-string": "^1.0.5",
+ "is-symbol": "^1.0.3"
+ }
+ },
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -1740,20 +1776,17 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
- "write": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
- "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
- "dev": true,
- "requires": {
- "mkdirp": "^0.5.1"
- }
- },
"xmlcreate": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz",
"integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==",
"dev": true
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
}
}
}
diff --git a/platform/javascript/package.json b/platform/javascript/package.json
index d9d272923e..9dafae30c5 100644
--- a/platform/javascript/package.json
+++ b/platform/javascript/package.json
@@ -20,9 +20,9 @@
"author": "Godot Engine contributors",
"license": "MIT",
"devDependencies": {
- "eslint": "^7.9.0",
- "eslint-config-airbnb-base": "^14.2.0",
- "eslint-plugin-import": "^2.22.0",
- "jsdoc": "^3.6.6"
+ "eslint": "^7.28.0",
+ "eslint-config-airbnb-base": "^14.2.1",
+ "eslint-plugin-import": "^2.23.4",
+ "jsdoc": "^3.6.7"
}
}
diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub
index 46714e9502..1751d56e71 100644
--- a/platform/linuxbsd/SCsub
+++ b/platform/linuxbsd/SCsub
@@ -5,21 +5,27 @@ Import("env")
from platform_methods import run_in_subprocess
import platform_linuxbsd_builders
-common_x11 = [
+common_linuxbsd = [
"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",
]
+if "x11" in env and env["x11"]:
+ common_linuxbsd += [
+ "context_gl_x11.cpp",
+ "detect_prime_x11.cpp",
+ "display_server_x11.cpp",
+ "key_mapping_x11.cpp",
+ ]
+
+if "vulkan" in env and env["vulkan"]:
+ common_linuxbsd.append("vulkan_context_x11.cpp")
+
if "udev" in env and env["udev"]:
- common_x11.append("libudev-so_wrap.c")
+ common_linuxbsd.append("libudev-so_wrap.c")
-prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_x11)
+prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd)
if env["debug_symbols"] and env["separate_debug_symbols"]:
env.AddPostAction(prog, run_in_subprocess(platform_linuxbsd_builders.make_debug_linuxbsd))
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 646ae4d457..1487210174 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -73,6 +73,7 @@ def get_opts():
BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False),
BoolVariable("pulseaudio", "Detect and use PulseAudio", True),
BoolVariable("udev", "Use udev for gamepad connection callbacks", True),
+ BoolVariable("x11", "Enable X11 display", True),
BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
BoolVariable("touch", "Enable touch events", True),
@@ -325,6 +326,10 @@ def configure(env):
if not env["builtin_pcre2"]:
env.ParseConfig("pkg-config libpcre2-32 --cflags --libs")
+ if not env["builtin_embree"]:
+ # No pkgconfig file so far, hardcode expected lib name.
+ env.Append(LIBS=["embree3"])
+
## Flags
if os.system("pkg-config --exists alsa") == 0: # 0 means found
@@ -358,17 +363,26 @@ def configure(env):
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"])
+ if env["x11"]:
+ if not env["vulkan"]:
+ print("Error: X11 support requires vulkan=yes")
+ env.Exit(255)
+ env.Append(CPPDEFINES=["X11_ENABLED"])
+
+ env.Append(CPPDEFINES=["UNIX_ENABLED"])
+ env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
+
+ if env["vulkan"]:
+ env.Append(CPPDEFINES=["VULKAN_ENABLED"])
+ if not env["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(CPPDEFINES=['OPENGL_ENABLED'])
+ env.Append(LIBS=["GL"])
env.Append(LIBS=["pthread"])
@@ -408,10 +422,7 @@ def configure(env):
# Link those statically for portability
if env["use_static_cpp"]:
- # Workaround for GH-31743, Ubuntu 18.04 i386 crashes when it's used.
- # That doesn't make any sense but it's likely a Ubuntu bug?
- if is64 or env["bits"] == "64":
- env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
+ env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
if env["use_llvm"]:
env["LINKCOM"] = env["LINKCOM"] + " -l:libatomic.a"
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 8dc1b41702..8b6922699c 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -360,7 +360,7 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
return;
}
- if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
XUngrabPointer(x11_display, CurrentTime);
}
@@ -376,7 +376,7 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
}
mouse_mode = p_mode;
- if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
//flush pending motion events
_flush_mouse_motion();
WindowData &main_window = windows[MAIN_WINDOW_ID];
@@ -2166,10 +2166,10 @@ static Atom pick_target_from_atoms(Display *p_disp, Atom p_t1, Atom p_t2, Atom p
}
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));
+ state->set_shift_pressed((p_x11_state & ShiftMask));
+ state->set_ctrl_pressed((p_x11_state & ControlMask));
+ state->set_alt_pressed((p_x11_state & Mod1Mask /*|| p_x11_state&Mod5Mask*/)); //altgr should not count as alt
+ state->set_meta_pressed((p_x11_state & Mod4Mask));
}
unsigned int DisplayServerX11::_get_mouse_button_state(unsigned int p_x11_button, int p_x11_type) {
@@ -2281,7 +2281,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
//make it consistent across platforms.
k->set_keycode(KEY_TAB);
k->set_physical_keycode(KEY_TAB);
- k->set_shift(true);
+ k->set_shift_pressed(true);
}
Input::get_singleton()->accumulate_input_event(k);
@@ -2409,20 +2409,20 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
//make it consistent across platforms.
k->set_keycode(KEY_TAB);
k->set_physical_keycode(KEY_TAB);
- k->set_shift(true);
+ k->set_shift_pressed(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);
+ k->set_shift_pressed(false);
+ } else if (k->get_keycode() == KEY_CTRL) {
+ k->set_ctrl_pressed(false);
} else if (k->get_keycode() == KEY_ALT) {
- k->set_alt(false);
+ k->set_alt_pressed(false);
} else if (k->get_keycode() == KEY_META) {
- k->set_metakey(false);
+ k->set_meta_pressed(false);
}
}
@@ -2606,7 +2606,6 @@ void DisplayServerX11::_window_changed(XEvent *event) {
}
#endif
- print_line("DisplayServer::_window_changed: " + itos(window_id) + " rect: " + new_rect);
if (!wd.rect_changed_callback.is_null()) {
Rect2i r = new_rect;
@@ -2767,7 +2766,7 @@ void DisplayServerX11::process_events() {
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;
+ bool mouse_mode_grab = mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN;
xi.pressure = 0;
xi.tilt = Vector2();
@@ -3031,7 +3030,7 @@ void DisplayServerX11::process_events() {
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
+ } else if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { // Or re-hide it.
XDefineCursor(x11_display, E->get().x11_window, null_cursor);
}
@@ -3162,14 +3161,14 @@ void DisplayServerX11::process_events() {
last_click_ms = 0;
last_click_pos = Point2i(-100, -100);
last_click_button_index = -1;
- mb->set_doubleclick(true);
+ mb->set_double_click(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()) {
+ if (!mb->is_double_click()) {
last_click_ms += diff;
last_click_pos = Point2i(event.xbutton.x, event.xbutton.y);
}
@@ -3833,8 +3832,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
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
diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp
index cb95068314..3ee088dd35 100644
--- a/platform/linuxbsd/export/export.cpp
+++ b/platform/linuxbsd/export/export.cpp
@@ -30,7 +30,7 @@
#include "export.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "editor/editor_export.h"
#include "platform/linuxbsd/logo.gen.h"
#include "scene/resources/texture.h"
diff --git a/platform/linuxbsd/key_mapping_x11.cpp b/platform/linuxbsd/key_mapping_x11.cpp
index f9f612fa74..74257a7e61 100644
--- a/platform/linuxbsd/key_mapping_x11.cpp
+++ b/platform/linuxbsd/key_mapping_x11.cpp
@@ -61,8 +61,8 @@ static _XTranslatePair _xkeysym_to_keycode[] = {
{ XK_Shift_L, KEY_SHIFT },
{ XK_Shift_R, KEY_SHIFT },
{ XK_Shift_Lock, KEY_SHIFT },
- { XK_Control_L, KEY_CONTROL },
- { XK_Control_R, KEY_CONTROL },
+ { XK_Control_L, KEY_CTRL },
+ { XK_Control_R, KEY_CTRL },
{ XK_Meta_L, KEY_META },
{ XK_Meta_R, KEY_META },
{ XK_Alt_L, KEY_ALT },
@@ -213,7 +213,7 @@ static _TranslatePair _scancode_to_keycode[] = {
{ KEY_BRACELEFT, 0x22 },
{ KEY_BRACERIGHT, 0x23 },
{ KEY_ENTER, 0x24 },
- { KEY_CONTROL, 0x25 },
+ { KEY_CTRL, 0x25 },
{ KEY_A, 0x26 },
{ KEY_S, 0x27 },
{ KEY_D, 0x28 },
@@ -272,7 +272,7 @@ static _TranslatePair _scancode_to_keycode[] = {
{ KEY_F11, 0x5F },
{ KEY_F12, 0x60 },
{ KEY_KP_ENTER, 0x68 },
- { KEY_CONTROL, 0x69 },
+ { KEY_CTRL, 0x69 },
{ KEY_KP_DIVIDE, 0x6A },
{ KEY_PRINT, 0x6B },
{ KEY_ALT, 0x6C },
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 09e1f9461c..c6a2fa5be7 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -30,7 +30,7 @@
#include "os_linuxbsd.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "main/main.h"
#ifdef X11_ENABLED
@@ -116,6 +116,8 @@ String OS_LinuxBSD::get_name() const {
return "FreeBSD";
#elif defined(__NetBSD__)
return "NetBSD";
+#elif defined(__OpenBSD__)
+ return "OpenBSD";
#else
return "BSD";
#endif
@@ -164,7 +166,12 @@ bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) {
String OS_LinuxBSD::get_config_path() const {
if (has_environment("XDG_CONFIG_HOME")) {
- return get_environment("XDG_CONFIG_HOME");
+ if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) {
+ return get_environment("XDG_CONFIG_HOME");
+ } else {
+ WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.config` or `.` per the XDG Base Directory specification.");
+ return has_environment("HOME") ? get_environment("HOME").plus_file(".config") : ".";
+ }
} else if (has_environment("HOME")) {
return get_environment("HOME").plus_file(".config");
} else {
@@ -174,7 +181,12 @@ String OS_LinuxBSD::get_config_path() const {
String OS_LinuxBSD::get_data_path() const {
if (has_environment("XDG_DATA_HOME")) {
- return get_environment("XDG_DATA_HOME");
+ if (get_environment("XDG_DATA_HOME").is_absolute_path()) {
+ return get_environment("XDG_DATA_HOME");
+ } else {
+ WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.local/share` or `get_config_path()` per the XDG Base Directory specification.");
+ return has_environment("HOME") ? get_environment("HOME").plus_file(".local/share") : get_config_path();
+ }
} else if (has_environment("HOME")) {
return get_environment("HOME").plus_file(".local/share");
} else {
@@ -184,7 +196,12 @@ String OS_LinuxBSD::get_data_path() const {
String OS_LinuxBSD::get_cache_path() const {
if (has_environment("XDG_CACHE_HOME")) {
- return get_environment("XDG_CACHE_HOME");
+ if (get_environment("XDG_CACHE_HOME").is_absolute_path()) {
+ return get_environment("XDG_CACHE_HOME");
+ } else {
+ WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.cache` or `get_config_path()` per the XDG Base Directory specification.");
+ return has_environment("HOME") ? get_environment("HOME").plus_file(".cache") : get_config_path();
+ }
} else if (has_environment("HOME")) {
return get_environment("HOME").plus_file(".cache");
} else {
@@ -408,8 +425,8 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
// Generates the .trashinfo file
OS::Date date = OS::get_singleton()->get_date(false);
OS::Time time = OS::get_singleton()->get_time(false);
- String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", date.year, date.month, date.day, time.hour, time.min);
- timestamp = vformat("%s%02d", timestamp, time.sec); // vformat only supports up to 6 arguments.
+ String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", date.year, date.month, date.day, time.hour, time.minute);
+ timestamp = vformat("%s%02d", timestamp, time.second); // vformat only supports up to 6 arguments.
String trash_info = "[Trash Info]\nPath=" + p_path.uri_encode() + "\nDeletionDate=" + timestamp + "\n";
{
Error err;
diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm
index 147ce26779..0f128d504f 100644
--- a/platform/osx/crash_handler_osx.mm
+++ b/platform/osx/crash_handler_osx.mm
@@ -70,7 +70,7 @@ static uint64_t load_address() {
}
static void handle_crash(int sig) {
- if (OS::get_singleton() == NULL) {
+ if (OS::get_singleton() == nullptr) {
abort();
}
@@ -105,7 +105,7 @@ static void handle_crash(int sig) {
if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
if (info.dli_sname[0] == '_') {
int status;
- char *demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
+ char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status);
if (status == 0 && demangled) {
snprintf(fname, 1024, "%s", demangled);
@@ -167,9 +167,9 @@ void CrashHandler::disable() {
return;
#ifdef CRASH_HANDLER_ENABLED
- signal(SIGSEGV, NULL);
- signal(SIGFPE, NULL);
- signal(SIGILL, NULL);
+ signal(SIGSEGV, nullptr);
+ signal(SIGFPE, nullptr);
+ signal(SIGILL, nullptr);
#endif
disabled = true;
diff --git a/platform/osx/dir_access_osx.h b/platform/osx/dir_access_osx.h
index f61581979f..a894723e64 100644
--- a/platform/osx/dir_access_osx.h
+++ b/platform/osx/dir_access_osx.h
@@ -38,7 +38,7 @@
#include <sys/types.h>
#include <unistd.h>
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "drivers/unix/dir_access_unix.h"
class DirAccessOSX : public DirAccessUnix {
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 6b838b6d14..408feb4db9 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -66,10 +66,10 @@
static bool ignore_momentum_scroll = false;
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));
+ r_state->set_shift_pressed((p_osx_state & NSEventModifierFlagShift));
+ r_state->set_ctrl_pressed((p_osx_state & NSEventModifierFlagControl));
+ r_state->set_alt_pressed((p_osx_state & NSEventModifierFlagOption));
+ r_state->set_meta_pressed((p_osx_state & NSEventModifierFlagCommand));
}
static Vector2i _get_mouse_pos(DisplayServerOSX::WindowData &p_wd, NSPoint p_locationInWindow) {
@@ -368,6 +368,10 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
if (wd.resize_disabled) {
[wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable];
}
+
+ if (wd.on_top) {
+ [wd.window_object setLevel:NSFloatingWindowLevel];
+ }
}
- (void)windowDidChangeBackingProperties:(NSNotification *)notification {
@@ -830,7 +834,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
mb->set_global_position(pos);
mb->set_button_mask(DS_OSX->last_button_state);
if (index == MOUSE_BUTTON_LEFT && pressed) {
- mb->set_doubleclick([event clickCount] == 2);
+ mb->set_double_click([event clickCount] == 2);
}
Input::get_singleton()->accumulate_input_event(mb);
@@ -880,7 +884,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
return;
}
- if (DS_OSX->mouse_mode == DisplayServer::MOUSE_MODE_CONFINED) {
+ if (DS_OSX->mouse_mode == DisplayServer::MOUSE_MODE_CONFINED || DS_OSX->mouse_mode == DisplayServer::MOUSE_MODE_CONFINED_HIDDEN) {
// Discard late events
if (([event timestamp]) < DS_OSX->last_warp) {
return;
@@ -1133,10 +1137,10 @@ static int translateKey(unsigned int key) {
/* 38 */ KEY_SHIFT,
/* 39 */ KEY_CAPSLOCK,
/* 3a */ KEY_ALT,
- /* 3b */ KEY_CONTROL,
+ /* 3b */ KEY_CTRL,
/* 3c */ KEY_SHIFT,
/* 3d */ KEY_ALT,
- /* 3e */ KEY_CONTROL,
+ /* 3e */ KEY_CTRL,
/* 3f */ KEY_UNKNOWN, /* Function */
/* 40 */ KEY_UNKNOWN, /* F17 */
/* 41 */ KEY_KP_PERIOD,
@@ -1640,7 +1644,7 @@ String DisplayServerOSX::get_name() const {
}
const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const {
- const NSMenu *menu = NULL;
+ const NSMenu *menu = nullptr;
if (p_menu_root == "") {
// Main menu.x
menu = [NSApp mainMenu];
@@ -1655,13 +1659,13 @@ const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const
}
if (menu == apple_menu) {
// Do not allow to change Apple menu.
- return NULL;
+ return nullptr;
}
return menu;
}
NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) {
- NSMenu *menu = NULL;
+ NSMenu *menu = nullptr;
if (p_menu_root == "") {
// Main menu.
menu = [NSApp mainMenu];
@@ -1678,7 +1682,7 @@ NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) {
}
if (menu == apple_menu) {
// Do not allow to change Apple menu.
- return NULL;
+ return nullptr;
}
return menu;
}
@@ -2102,7 +2106,12 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) {
} else if (p_mode == MOUSE_MODE_CONFINED) {
CGDisplayShowCursor(kCGDirectMainDisplay);
CGAssociateMouseAndMouseCursorPosition(false);
- } else {
+ } else if (p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
+ if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ CGDisplayHideCursor(kCGDirectMainDisplay);
+ }
+ CGAssociateMouseAndMouseCursorPosition(false);
+ } else { // MOUSE_MODE_VISIBLE
CGDisplayShowCursor(kCGDirectMainDisplay);
CGAssociateMouseAndMouseCursorPosition(true);
}
@@ -2139,7 +2148,7 @@ void DisplayServerOSX::mouse_warp_to_position(const Point2i &p_to) {
CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0);
CGAssociateMouseAndMouseCursorPosition(false);
CGWarpMouseCursorPosition(lMouseWarpPos);
- if (mouse_mode != MOUSE_MODE_CONFINED) {
+ if (mouse_mode != MOUSE_MODE_CONFINED && mouse_mode != MOUSE_MODE_CONFINED_HIDDEN) {
CGAssociateMouseAndMouseCursorPosition(true);
}
}
@@ -2437,7 +2446,7 @@ void DisplayServerOSX::_update_window(WindowData p_wd) {
[p_wd.window_object setHidesOnDeactivate:YES];
} else {
// Reset these when our window is not a borderless window that covers up the screen
- if (p_wd.on_top) {
+ if (p_wd.on_top && !p_wd.fullscreen) {
[p_wd.window_object setLevel:NSFloatingWindowLevel];
} else {
[p_wd.window_object setLevel:NSNormalWindowLevel];
@@ -2786,6 +2795,7 @@ void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) {
[wd.window_object deminiaturize:nil];
} break;
case WINDOW_MODE_FULLSCREEN: {
+ [wd.window_object setLevel:NSNormalWindowLevel];
if (wd.layered_window) {
_set_window_per_pixel_transparency_enabled(true, p_window);
}
@@ -2903,6 +2913,9 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
} break;
case WINDOW_FLAG_ALWAYS_ON_TOP: {
wd.on_top = p_enabled;
+ if (wd.fullscreen) {
+ return;
+ }
if (p_enabled) {
[wd.window_object setLevel:NSFloatingWindowLevel];
} else {
@@ -2940,7 +2953,11 @@ bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) co
return [wd.window_object styleMask] == NSWindowStyleMaskBorderless;
} break;
case WINDOW_FLAG_ALWAYS_ON_TOP: {
- return [wd.window_object level] == NSFloatingWindowLevel;
+ if (wd.fullscreen) {
+ return wd.on_top;
+ } else {
+ return [wd.window_object level] == NSFloatingWindowLevel;
+ }
} break;
case WINDOW_FLAG_TRANSPARENT: {
return wd.layered_window;
@@ -3029,7 +3046,7 @@ void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) {
return;
}
- if (cursors[p_shape] != NULL) {
+ if (cursors[p_shape] != nullptr) {
[cursors[p_shape] set];
} else {
switch (p_shape) {
@@ -3202,9 +3219,9 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape
[nsimage release];
} else {
// Reset to default system cursor
- if (cursors[p_shape] != NULL) {
+ if (cursors[p_shape] != nullptr) {
[cursors[p_shape] release];
- cursors[p_shape] = NULL;
+ cursors[p_shape] = nullptr;
}
CursorShape c = cursor_shape;
@@ -3467,7 +3484,7 @@ void DisplayServerOSX::set_native_icon(const String &p_filename) {
ERR_FAIL_COND(!f);
Vector<uint8_t> data;
- uint32_t len = f->get_len();
+ uint64_t len = f->get_length();
data.resize(len);
f->get_buffer((uint8_t *)&data.write[0], len);
memdelete(f);
@@ -3759,12 +3776,12 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
// Register to be notified on keyboard layout changes
CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),
- NULL, keyboard_layout_changed,
- kTISNotifySelectedKeyboardInputSourceChanged, NULL,
+ nullptr, keyboard_layout_changed,
+ kTISNotifySelectedKeyboardInputSourceChanged, nullptr,
CFNotificationSuspensionBehaviorDeliverImmediately);
// Register to be notified on displays arrangement changes
- CGDisplayRegisterReconfigurationCallback(displays_arrangement_changed, NULL);
+ CGDisplayRegisterReconfigurationCallback(displays_arrangement_changed, nullptr);
// Menu bar setup must go between sharedApplication above and
// finishLaunching below, in order to properly emulate the behavior
@@ -3854,7 +3871,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
context_vulkan = memnew(VulkanContextOSX);
if (context_vulkan->initialize() != OK) {
memdelete(context_vulkan);
- context_vulkan = NULL;
+ context_vulkan = nullptr;
r_error = ERR_CANT_CREATE;
ERR_FAIL_MSG("Could not initialize Vulkan");
}
@@ -3926,8 +3943,8 @@ DisplayServerOSX::~DisplayServerOSX() {
}
#endif
- CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
- CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
+ CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), nullptr, kTISNotifySelectedKeyboardInputSourceChanged, nullptr);
+ CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, nullptr);
cursors_cache.clear();
}
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index aca9471849..f52853ca9e 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -31,11 +31,11 @@
#include "export.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/marshalls.h"
#include "core/io/resource_saver.h"
#include "core/io/zip_io.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/version.h"
#include "editor/editor_export.h"
@@ -147,6 +147,7 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
@@ -215,7 +216,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source,
if ((p_source.ptr()[(i + 1) * 4 + p_ch] == cur) && (p_source.ptr()[(i + 2) * 4 + p_ch] == cur)) {
if (buf_size > 0) {
result.write[res_size++] = (uint8_t)(buf_size - 1);
- copymem(&result.write[res_size], &buf, buf_size);
+ memcpy(&result.write[res_size], &buf, buf_size);
res_size += buf_size;
buf_size = 0;
}
@@ -241,7 +242,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source,
buf[buf_size++] = cur;
if (buf_size == 128) {
result.write[res_size++] = (uint8_t)(buf_size - 1);
- copymem(&result.write[res_size], &buf, buf_size);
+ memcpy(&result.write[res_size], &buf, buf_size);
res_size += buf_size;
buf_size = 0;
}
@@ -249,7 +250,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source,
} else {
buf[buf_size++] = cur;
result.write[res_size++] = (uint8_t)(buf_size - 1);
- copymem(&result.write[res_size], &buf, buf_size);
+ memcpy(&result.write[res_size], &buf, buf_size);
res_size += buf_size;
buf_size = 0;
}
@@ -259,7 +260,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source,
int ofs = p_dest.size();
p_dest.resize(p_dest.size() + res_size);
- copymem(&p_dest.write[ofs], result.ptr(), res_size);
+ memcpy(&p_dest.write[ofs], result.ptr(), res_size);
}
void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
@@ -301,7 +302,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
if (icon_infos[i].is_png) {
// Encode PNG icon.
it->create_from_image(copy);
- String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("icon.png");
+ String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png");
ResourceSaver::save(path, it);
FileAccess *f = FileAccess::open(path, FileAccess::READ);
@@ -312,13 +313,13 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
}
int ofs = data.size();
- uint32_t len = f->get_len();
+ uint64_t len = f->get_length();
data.resize(data.size() + len + 8);
f->get_buffer(&data.write[ofs + 8], len);
memdelete(f);
len += 8;
len = BSWAP32(len);
- copymem(&data.write[ofs], icon_infos[i].name, 4);
+ memcpy(&data.write[ofs], icon_infos[i].name, 4);
encode_uint32(len, &data.write[ofs + 4]);
// Clean up generated file.
@@ -338,7 +339,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
int len = data.size() - ofs;
len = BSWAP32(len);
- copymem(&data.write[ofs], icon_infos[i].name, 4);
+ memcpy(&data.write[ofs], icon_infos[i].name, 4);
encode_uint32(len, &data.write[ofs + 4]);
}
@@ -353,7 +354,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_
}
len += 8;
len = BSWAP32(len);
- copymem(&data.write[ofs], icon_infos[i].mask_name, 4);
+ memcpy(&data.write[ofs], icon_infos[i].mask_name, 4);
encode_uint32(len, &data.write[ofs + 4]);
}
}
@@ -386,6 +387,9 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset
strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n";
} else if (lines[i].find("$signature") != -1) {
strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
+ } else if (lines[i].find("$app_category") != -1) {
+ String cat = p_preset->get("application/app_category");
+ strnew += lines[i].replace("$app_category", cat.to_lower()) + "\n";
} else if (lines[i].find("$copyright") != -1) {
strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n";
} else if (lines[i].find("$highres") != -1) {
@@ -610,7 +614,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
// Create our application bundle.
String tmp_app_dir_name = pkg_name + ".app";
- String tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(tmp_app_dir_name);
+ String tmp_app_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(tmp_app_dir_name);
print_line("Exporting to " + tmp_app_path_name);
Error err = OK;
@@ -689,8 +693,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (iconpath.get_extension() == "icns") {
FileAccess *icon = FileAccess::open(iconpath, FileAccess::READ);
if (icon) {
- data.resize(icon->get_len());
- icon->get_buffer(&data.write[0], icon->get_len());
+ data.resize(icon->get_length());
+ icon->get_buffer(&data.write[0], icon->get_length());
icon->close();
memdelete(icon);
}
@@ -774,7 +778,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
String ent_path = p_preset->get("codesign/entitlements/custom_file");
if (sign_enabled && (ent_path == "")) {
- ent_path = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
+ ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
FileAccess *ent_f = FileAccess::open(ent_path, FileAccess::WRITE);
if (ent_f) {
@@ -894,9 +898,22 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (err == OK) {
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) {
- err = da->copy(shared_objects[i].path, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file());
+ String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
+ if (da->dir_exists(src_path)) {
+#ifndef UNIX_ENABLED
+ WARN_PRINT("Relative symlinks are not supported, exported " + src_path.get_file() + " might be broken!");
+#endif
+ print_verbose("export framework: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+ err = da->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+ if (err == OK) {
+ err = da->copy_dir(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), -1, true);
+ }
+ } else {
+ print_verbose("export dylib: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+ err = da->copy(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+ }
if (err == OK && sign_enabled) {
- err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file(), ent_path);
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), ent_path);
}
}
memdelete(da);
@@ -946,7 +963,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
zlib_filefunc_def io_dst = zipio_create_io_from_file(&dst_f);
zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
- _zip_folder_recursive(zip, EditorSettings::get_singleton()->get_cache_dir(), pkg_name + ".app", pkg_name);
+ _zip_folder_recursive(zip, EditorPaths::get_singleton()->get_cache_dir(), pkg_name + ".app", pkg_name);
zipClose(zip, nullptr);
}
@@ -980,7 +997,48 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
if (f == "." || f == "..") {
continue;
}
- if (da->current_is_dir()) {
+ if (da->is_link(f)) {
+ OS::Time time = OS::get_singleton()->get_time();
+ OS::Date date = OS::get_singleton()->get_date();
+
+ zip_fileinfo zipfi;
+ zipfi.tmz_date.tm_hour = time.hour;
+ zipfi.tmz_date.tm_mday = date.day;
+ zipfi.tmz_date.tm_min = time.minute;
+ zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/
+ zipfi.tmz_date.tm_sec = time.second;
+ zipfi.tmz_date.tm_year = date.year;
+ zipfi.dosDate = 0;
+ // 0120000: symbolic link type
+ // 0000755: permissions rwxr-xr-x
+ // 0000644: permissions rw-r--r--
+ uint32_t _mode = 0120644;
+ zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
+ zipfi.internal_fa = 0;
+
+ zipOpenNewFileInZip4(p_zip,
+ p_folder.plus_file(f).utf8().get_data(),
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION,
+ 0,
+ -MAX_WBITS,
+ DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY,
+ nullptr,
+ 0,
+ 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
+ 0);
+
+ String target = da->read_link(f);
+ zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
+ zipCloseFileInZip(p_zip);
+ } else if (da->current_is_dir()) {
_zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name);
} else {
bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name));
@@ -991,9 +1049,9 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
zip_fileinfo zipfi;
zipfi.tmz_date.tm_hour = time.hour;
zipfi.tmz_date.tm_mday = date.day;
- zipfi.tmz_date.tm_min = time.min;
+ zipfi.tmz_date.tm_min = time.minute;
zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/
- zipfi.tmz_date.tm_sec = time.sec;
+ zipfi.tmz_date.tm_sec = time.second;
zipfi.tmz_date.tm_year = date.year;
zipfi.dosDate = 0;
// 0100000: regular file type
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 7b5daf5bfb..b65d84d900 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -101,7 +101,7 @@ String OS_OSX::get_unique_id() const {
if (serial_number.is_empty()) {
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
- CFStringRef serialNumberAsCFString = NULL;
+ CFStringRef serialNumberAsCFString = nullptr;
if (platformExpert) {
serialNumberAsCFString = (CFStringRef)IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0);
IOObjectRelease(platformExpert);
@@ -158,7 +158,7 @@ void OS_OSX::delete_main_loop() {
if (!main_loop)
return;
memdelete(main_loop);
- main_loop = NULL;
+ main_loop = nullptr;
}
String OS_OSX::get_name() const {
@@ -188,31 +188,45 @@ MainLoop *OS_OSX::get_main_loop() const {
}
String OS_OSX::get_config_path() const {
+ // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well.
if (has_environment("XDG_CONFIG_HOME")) {
- return get_environment("XDG_CONFIG_HOME");
- } else if (has_environment("HOME")) {
+ if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) {
+ return get_environment("XDG_CONFIG_HOME");
+ } else {
+ WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/Library/Application Support` or `.` per the XDG Base Directory specification.");
+ }
+ }
+ if (has_environment("HOME")) {
return get_environment("HOME").plus_file("Library/Application Support");
- } else {
- return ".";
}
+ return ".";
}
String OS_OSX::get_data_path() const {
+ // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well.
if (has_environment("XDG_DATA_HOME")) {
- return get_environment("XDG_DATA_HOME");
- } else {
- return get_config_path();
+ if (get_environment("XDG_DATA_HOME").is_absolute_path()) {
+ return get_environment("XDG_DATA_HOME");
+ } else {
+ WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `get_config_path()` per the XDG Base Directory specification.");
+ }
}
+ return get_config_path();
}
String OS_OSX::get_cache_path() const {
+ // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well.
if (has_environment("XDG_CACHE_HOME")) {
- return get_environment("XDG_CACHE_HOME");
- } else if (has_environment("HOME")) {
+ if (get_environment("XDG_CACHE_HOME").is_absolute_path()) {
+ return get_environment("XDG_CACHE_HOME");
+ } else {
+ WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/Libary/Caches` or `get_config_path()` per the XDG Base Directory specification.");
+ }
+ }
+ if (has_environment("HOME")) {
return get_environment("HOME").plus_file("Library/Caches");
- } else {
- return get_config_path();
}
+ return get_config_path();
}
String OS_OSX::get_bundle_resource_dir() const {
@@ -346,7 +360,7 @@ Error OS_OSX::move_to_trash(const String &p_path) {
}
OS_OSX::OS_OSX() {
- main_loop = NULL;
+ main_loop = nullptr;
force_quit = false;
Vector<Logger *> loggers;
diff --git a/platform/osx/vulkan_context_osx.mm b/platform/osx/vulkan_context_osx.mm
index 75a4fc990f..6b87fbd489 100644
--- a/platform/osx/vulkan_context_osx.mm
+++ b/platform/osx/vulkan_context_osx.mm
@@ -38,12 +38,12 @@ const char *VulkanContextOSX::_get_platform_surface_extension() const {
Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, id p_window, int p_width, int p_height) {
VkMacOSSurfaceCreateInfoMVK createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
- createInfo.pNext = NULL;
+ createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.pView = p_window;
VkSurfaceKHR surface;
- VkResult err = vkCreateMacOSSurfaceMVK(_get_instance(), &createInfo, NULL, &surface);
+ VkResult err = vkCreateMacOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
return _window_create(p_window_id, surface, p_width, p_height);
}
diff --git a/platform/server/SCsub b/platform/server/SCsub
deleted file mode 100644
index 15b9af4d25..0000000000
--- a/platform/server/SCsub
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-
-Import("env")
-
-common_server = [
- "os_server.cpp",
-]
-
-if sys.platform == "darwin":
- common_server.append("#platform/osx/crash_handler_osx.mm")
-else:
- common_server.append("#platform/x11/crash_handler_x11.cpp")
-
-prog = env.add_program("#bin/godot_server", ["godot_server.cpp"] + common_server)
diff --git a/platform/server/detect.py b/platform/server/detect.py
deleted file mode 100644
index 478bcad212..0000000000
--- a/platform/server/detect.py
+++ /dev/null
@@ -1,296 +0,0 @@
-import os
-import platform
-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
-
-
-def get_name():
- return "Server"
-
-
-def get_program_suffix():
- if sys.platform == "darwin":
- return "osx"
- return "linuxbsd"
-
-
-def can_build():
- if os.name != "posix":
- return False
-
- return True
-
-
-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", True),
- BoolVariable("use_coverage", "Test Godot coverage", False),
- BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
- BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False),
- BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN)", False),
- BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
- BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False),
- BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
- BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
- BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False),
- ]
-
-
-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"])
- elif env["optimize"] == "size": # optimize for size
- env.Prepend(CCFLAGS=["-Os"])
-
- if env["debug_symbols"]:
- env.Prepend(CCFLAGS=["-g2"])
-
- elif env["target"] == "release_debug":
- if env["optimize"] == "speed": # optimize for speed (default)
- env.Prepend(CCFLAGS=["-O2"])
- elif env["optimize"] == "size": # optimize for size
- env.Prepend(CCFLAGS=["-Os"])
- env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
-
- if env["debug_symbols"]:
- env.Prepend(CCFLAGS=["-g2"])
-
- elif env["target"] == "debug":
- env.Prepend(CCFLAGS=["-g3"])
- env.Prepend(CPPDEFINES=["DEBUG_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.extra_suffix = ".llvm" + env.extra_suffix
- env.Append(LIBS=["atomic"])
-
- if env["use_coverage"]:
- env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"])
- env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"])
-
- if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"] or env["use_msan"]:
- env.extra_suffix += "s"
-
- if env["use_ubsan"]:
- env.Append(
- CCFLAGS=[
- "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin"
- ]
- )
- env.Append(LINKFLAGS=["-fsanitize=undefined"])
- if env["use_llvm"]:
- env.Append(
- CCFLAGS=[
- "-fsanitize=nullability-return,nullability-arg,function,nullability-assign,implicit-integer-sign-change"
- ]
- )
- else:
- env.Append(CCFLAGS=["-fsanitize=bounds-strict"])
-
- if env["use_asan"]:
- env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"])
- 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_msan"] and env["use_llvm"]:
- env.Append(CCFLAGS=["-fsanitize=memory"])
- env.Append(CCFLAGS=["-fsanitize-memory-track-origins"])
- env.Append(CCFLAGS=["-fsanitize-recover=memory"])
- env.Append(LINKFLAGS=["-fsanitize=memory"])
-
- if env["use_lto"]:
- env.Append(CCFLAGS=["-flto"])
- if not env["use_llvm"] and env.GetOption("num_jobs") > 1:
- 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(CCFLAGS=["-pipe"])
- env.Append(LINKFLAGS=["-pipe"])
-
- ## Dependencies
-
- # 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"]
- or env["builtin_graphite"]
- or env["builtin_harfbuzz"]
- ):
- env["builtin_freetype"] = True
- env["builtin_libpng"] = True
- env["builtin_zlib"] = True
- env["builtin_graphite"] = True
- env["builtin_harfbuzz"] = True
-
- if not env["builtin_freetype"]:
- env.ParseConfig("pkg-config freetype2 --cflags --libs")
-
- if not env["builtin_graphite"]:
- env.ParseConfig("pkg-config graphite2 --cflags --libs")
-
- if not env["builtin_icu"]:
- env.ParseConfig("pkg-config icu-uc --cflags --libs")
-
- if not env["builtin_harfbuzz"]:
- env.ParseConfig("pkg-config harfbuzz harfbuzz-icu --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
-
- # 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/server"])
- env.Append(CPPDEFINES=["SERVER_ENABLED", "UNIX_ENABLED"])
-
- if platform.system() == "Darwin":
- env.Append(
- LINKFLAGS=[
- "-framework",
- "Cocoa",
- "-framework",
- "Carbon",
- "-lz",
- "-framework",
- "IOKit",
- ]
- )
-
- 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"])
-
- # Link those statically for portability
- if env["use_static_cpp"]:
- env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
diff --git a/platform/server/godot_server.cpp b/platform/server/godot_server.cpp
deleted file mode 100644
index 1ced95fcbc..0000000000
--- a/platform/server/godot_server.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*************************************************************************/
-/* godot_server.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "main/main.h"
-#include "os_server.h"
-
-int main(int argc, char *argv[]) {
- OS_Server os;
-
- // We must override main when testing is enabled
- TEST_MAIN_OVERRIDE
-
- Error err = Main::setup(argv[0], argc - 1, &argv[1]);
- if (err != OK)
- return 255;
-
- if (Main::start())
- os.run(); // it is actually the OS that decides how to run
- Main::cleanup();
-
- return os.get_exit_code();
-}
diff --git a/platform/server/logo.png b/platform/server/logo.png
deleted file mode 100644
index 8666ada9ca..0000000000
--- a/platform/server/logo.png
+++ /dev/null
Binary files differ
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
deleted file mode 100644
index 852ec7c4ef..0000000000
--- a/platform/server/os_server.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-/*************************************************************************/
-/* os_server.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "os_server.h"
-
-#include "core/string/print_string.h"
-#include "drivers/dummy/rasterizer_dummy.h"
-#include "drivers/dummy/texture_loader_dummy.h"
-#include "servers/rendering/rendering_server_default.h"
-
-#include "main/main.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-int OS_Server::get_video_driver_count() const {
- return 1;
-}
-
-const char *OS_Server::get_video_driver_name(int p_driver) const {
- return "Dummy";
-}
-
-int OS_Server::get_current_video_driver() const {
- return video_driver_index;
-}
-
-void OS_Server::initialize_core() {
- crash_handler.initialize();
-
- OS_Unix::initialize_core();
-}
-
-Error OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
- args = OS::get_singleton()->get_cmdline_args();
- current_videomode = p_desired;
- main_loop = nullptr;
-
- RasterizerDummy::make_current();
-
- video_driver_index = p_video_driver; // unused in server platform, but should still be initialized
-
- rendering_server = memnew(RenderingServerDefault);
- rendering_server->init();
-
- AudioDriverManager::initialize(p_audio_driver);
-
- input = memnew(InputDefault);
-
- _ensure_user_data_dir();
-
- resource_loader_dummy.instance();
- ResourceLoader::add_resource_format_loader(resource_loader_dummy);
-
- return OK;
-}
-
-void OS_Server::finalize() {
- if (main_loop)
- memdelete(main_loop);
- main_loop = nullptr;
-
- rendering_server->finish();
- memdelete(rendering_server);
-
- memdelete(input);
-
- ResourceLoader::remove_resource_format_loader(resource_loader_dummy);
- resource_loader_dummy.unref();
-
- args.clear();
-}
-
-void OS_Server::set_mouse_show(bool p_show) {
-}
-
-void OS_Server::set_mouse_grab(bool p_grab) {
- grab = p_grab;
-}
-
-bool OS_Server::is_mouse_grab_enabled() const {
- return grab;
-}
-
-int OS_Server::get_mouse_button_state() const {
- return 0;
-}
-
-Point2 OS_Server::get_mouse_position() const {
- return Point2();
-}
-
-void OS_Server::set_window_title(const String &p_title) {
-}
-
-void OS_Server::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
-}
-
-OS::VideoMode OS_Server::get_video_mode(int p_screen) const {
- return current_videomode;
-}
-
-Size2 OS_Server::get_window_size() const {
- return Vector2(current_videomode.width, current_videomode.height);
-}
-
-void OS_Server::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
-}
-
-MainLoop *OS_Server::get_main_loop() const {
- return main_loop;
-}
-
-void OS_Server::delete_main_loop() {
- if (main_loop)
- memdelete(main_loop);
- main_loop = nullptr;
-}
-
-void OS_Server::set_main_loop(MainLoop *p_main_loop) {
- main_loop = p_main_loop;
- input->set_main_loop(p_main_loop);
-}
-
-String OS_Server::get_name() const {
- return "Server";
-}
-
-void OS_Server::move_window_to_foreground() {
-}
-
-bool OS_Server::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc";
-}
-
-void OS_Server::run() {
- force_quit = false;
-
- if (!main_loop)
- return;
-
- main_loop->init();
-
- while (!force_quit) {
- if (Main::iteration())
- break;
- };
-
- main_loop->finish();
-}
-
-String OS_Server::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_Server::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_Server::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_Server::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_Server *>(this)->execute("xdg-user-dir", arg, true, nullptr, &pipe);
- if (err != OK)
- return ".";
- return pipe.strip_edges();
-}
-
-void OS_Server::disable_crash_handler() {
- crash_handler.disable();
-}
-
-bool OS_Server::is_disable_crash_handler() const {
- return crash_handler.is_disabled();
-}
-
-OS_Server::OS_Server() {
- //adriver here
- grab = false;
-};
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
deleted file mode 100644
index 61025fa14b..0000000000
--- a/platform/server/os_server.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*************************************************************************/
-/* os_server.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef OS_SERVER_H
-#define OS_SERVER_H
-
-#include "core/input/input.h"
-#include "drivers/dummy/texture_loader_dummy.h"
-#include "drivers/unix/os_unix.h"
-#ifdef __APPLE__
-#include "platform/osx/crash_handler_osx.h"
-#include "platform/osx/semaphore_osx.h"
-#else
-#include "platform/x11/crash_handler_linuxbsd.h"
-#endif
-#include "servers/audio_server.h"
-#include "servers/rendering/renderer_compositor.h"
-#include "servers/rendering_server.h"
-
-#undef CursorShape
-
-class OS_Server : public OS_Unix {
- RenderingServer *rendering_server = nullptr;
- VideoMode current_videomode;
- List<String> args;
- MainLoop *main_loop = nullptr;
-
- bool grab = false;
-
- virtual void delete_main_loop();
-
- bool force_quit = false;
-
- InputDefault *input = nullptr;
-
- CrashHandler crash_handler;
-
- int video_driver_index = 0;
-
- Ref<ResourceFormatDummyTexture> resource_loader_dummy;
-
-protected:
- 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;
-
- 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);
-
-public:
- virtual String get_name() const;
-
- 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 MainLoop *get_main_loop() 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 Size2 get_window_size() const;
-
- virtual void move_window_to_foreground();
-
- void run();
-
- virtual bool _check_internal_feature_support(const String &p_feature);
-
- 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;
-
- void disable_crash_handler();
- bool is_disable_crash_handler() const;
-
- OS_Server();
-};
-
-#endif
diff --git a/platform/server/platform_config.h b/platform/server/platform_config.h
deleted file mode 100644
index 32a19d811b..0000000000
--- a/platform/server/platform_config.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*************************************************************************/
-/* platform_config.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#if defined(__linux__) || defined(__APPLE__)
-#include <alloca.h>
-#endif
-
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
-#include <stdlib.h> // alloca
-// FreeBSD and OpenBSD use pthread_set_name_np, while other platforms,
-// include NetBSD, use pthread_setname_np. NetBSD's version however requires
-// a different format, we handle this directly in thread_posix.
-#ifdef __NetBSD__
-#define PTHREAD_NETBSD_SET_NAME
-#else
-#define PTHREAD_BSD_SET_NAME
-#endif
-#endif
-
-#ifdef __APPLE__
-#define PTHREAD_RENAME_SELF
-#endif
diff --git a/platform/uwp/SCsub b/platform/uwp/SCsub
index 4358b0eead..71c402358f 100644
--- a/platform/uwp/SCsub
+++ b/platform/uwp/SCsub
@@ -3,7 +3,6 @@
Import("env")
files = [
- "thread_uwp.cpp",
"#platform/windows/key_mapping_windows.cpp",
"#platform/windows/windows_terminal_logger.cpp",
"joypad_uwp.cpp",
diff --git a/platform/uwp/app.cpp b/platform/uwp/app.cpp
index b7e4361831..67f054aeaa 100644
--- a/platform/uwp/app.cpp
+++ b/platform/uwp/app.cpp
@@ -34,8 +34,8 @@
#include "app.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/os/keyboard.h"
#include "main/main.h"
@@ -333,8 +333,9 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co
os->input_event(screen_drag);
} else {
// In case the mouse grabbed, MouseMoved will handle this
- if (os->get_mouse_mode() == OS::MouseMode::MOUSE_MODE_CAPTURED)
+ if (os->get_mouse_mode() == OS::MouseMode::MOUSE_MODE_CAPTURED) {
return;
+ }
Ref<InputEventMouseMotion> mouse_motion;
mouse_motion.instance();
@@ -351,8 +352,9 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co
void App::OnMouseMoved(MouseDevice ^ mouse_device, MouseEventArgs ^ args) {
// In case the mouse isn't grabbed, PointerMoved will handle this
- if (os->get_mouse_mode() != OS::MouseMode::MOUSE_MODE_CAPTURED)
+ if (os->get_mouse_mode() != OS::MouseMode::MOUSE_MODE_CAPTURED) {
return;
+ }
Windows::Foundation::Point pos;
pos.X = last_mouse_pos.X + args->MouseDelta.X;
@@ -383,7 +385,7 @@ void App::key_event(Windows::UI::Core::CoreWindow ^ sender, bool p_pressed, Wind
ke.type = OS_UWP::KeyEvent::MessageType::KEY_EVENT_MESSAGE;
ke.unicode = 0;
ke.keycode = KeyMappingWindows::get_keysym((unsigned int)key_args->VirtualKey);
- ke.physical_keycode = KeyMappingWindows::get_scansym((unsigned int)key_args->KeyStatus.ScanCode);
+ ke.physical_keycode = KeyMappingWindows::get_scansym((unsigned int)key_args->KeyStatus.ScanCode, key_args->KeyStatus.IsExtendedKey);
ke.echo = (!p_pressed && !key_args->KeyStatus.IsKeyReleased) || (p_pressed && key_args->KeyStatus.WasKeyDown);
} else {
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index 800a728033..1b14aac3da 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -33,11 +33,11 @@
#include "core/config/project_settings.h"
#include "core/core_bind.h"
#include "core/crypto/crypto_core.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/marshalls.h"
#include "core/io/zip_io.h"
#include "core/object/class_db.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/version.h"
#include "editor/editor_export.h"
#include "editor/editor_node.h"
@@ -567,12 +567,12 @@ void AppxPackager::finish() {
// Create and add block map file
EditorNode::progress_task_step("export", "Creating block map...", 4);
- const String &tmp_blockmap_file_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml");
+ const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml");
make_block_map(tmp_blockmap_file_path);
FileAccess *blockmap_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::READ);
Vector<uint8_t> blockmap_buffer;
- blockmap_buffer.resize(blockmap_file->get_len());
+ blockmap_buffer.resize(blockmap_file->get_length());
blockmap_file->get_buffer(blockmap_buffer.ptrw(), blockmap_buffer.size());
@@ -585,12 +585,12 @@ void AppxPackager::finish() {
EditorNode::progress_task_step("export", "Setting content types...", 5);
- const String &tmp_content_types_file_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml");
+ const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml");
make_content_types(tmp_content_types_file_path);
FileAccess *types_file = FileAccess::open(tmp_content_types_file_path, FileAccess::READ);
Vector<uint8_t> types_buffer;
- types_buffer.resize(types_file->get_len());
+ types_buffer.resize(types_file->get_length());
types_file->get_buffer(types_buffer.ptrw(), types_buffer.size());
@@ -879,7 +879,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
return data;
}
- String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
+ String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
Error err = texture->get_image()->save_png(tmp_path);
@@ -900,7 +900,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
ERR_FAIL_V_MSG(data, err_string);
}
- data.resize(f->get_len());
+ data.resize(f->get_length());
f->get_buffer(data.ptrw(), data.size());
f->close();
@@ -1336,7 +1336,7 @@ public:
int base = clf.size();
clf.resize(base + 4 + txt.length());
encode_uint32(txt.length(), &clf.write[base]);
- copymem(&clf.write[base + 4], txt.ptr(), txt.length());
+ memcpy(&clf.write[base + 4], txt.ptr(), txt.length());
print_line(itos(i) + " param: " + cl[i]);
}
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 33992069f9..65934b6681 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -147,7 +147,7 @@ void OS_UWP::initialize_core() {
ticks_start = 0;
ticks_start = get_ticks_usec();
- IP_Unix::make_default();
+ IPUnix::make_default();
cursor_shape = CURSOR_ARROW;
}
@@ -400,14 +400,12 @@ void OS_UWP::ManagedType::on_gyroscope_reading_changed(Gyrometer ^ sender, Gyrom
void OS_UWP::set_mouse_mode(MouseMode p_mode) {
if (p_mode == MouseMode::MOUSE_MODE_CAPTURED) {
CoreWindow::GetForCurrentThread()->SetPointerCapture();
-
} else {
CoreWindow::GetForCurrentThread()->ReleasePointerCapture();
}
- if (p_mode == MouseMode::MOUSE_MODE_CAPTURED || p_mode == MouseMode::MOUSE_MODE_HIDDEN) {
+ if (p_mode == MouseMode::MOUSE_MODE_HIDDEN || p_mode == MouseMode::MOUSE_MODE_CAPTURED || p_mode == MouseMode::MOUSE_MODE_CONFINED_HIDDEN) {
CoreWindow::GetForCurrentThread()->PointerCursor = nullptr;
-
} else {
CoreWindow::GetForCurrentThread()->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
}
@@ -565,9 +563,9 @@ void OS_UWP::process_key_events() {
Ref<InputEventKey> key_event;
key_event.instance();
- key_event->set_alt(kev.alt);
- key_event->set_shift(kev.shift);
- key_event->set_control(kev.control);
+ key_event->set_alt_pressed(kev.alt);
+ key_event->set_shift_pressed(kev.shift);
+ key_event->set_ctrl_pressed(kev.control);
key_event->set_echo(kev.echo);
key_event->set_keycode(kev.keycode);
key_event->set_physical_keycode(kev.physical_keycode);
diff --git a/platform/windows/context_gl_windows.cpp b/platform/windows/context_gl_windows.cpp
index 207b0a1168..7cf9738f13 100644
--- a/platform/windows/context_gl_windows.cpp
+++ b/platform/windows/context_gl_windows.cpp
@@ -94,7 +94,7 @@ void ContextGL_Windows::swap_buffers() {
if (vsync_via_compositor_now != vsync_via_compositor) {
// The previous frame had a different operating mode than this
- // frame. Set the 'vsync_via_compositor' member variable and the
+ // frame. Set the 'vsync_via_compositor' member variable and the
// OpenGL swap interval to their proper values.
set_use_vsync(true);
}
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 86f20f1dd7..f16595f379 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -84,7 +84,8 @@ void DisplayServerWindows::alert(const String &p_alert, const String &p_title) {
}
void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
- if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED) {
+ if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
+ // Mouse is grabbed (captured or confined).
WindowData &wd = windows[MAIN_WINDOW_ID];
RECT clipRect;
@@ -100,11 +101,12 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
SetCapture(wd.hWnd);
}
} else {
+ // Mouse is free to move around (not captured or confined).
ReleaseCapture();
ClipCursor(nullptr);
}
- if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_HIDDEN) {
+ if (p_mode == MOUSE_MODE_HIDDEN || p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
if (hCursor == nullptr) {
hCursor = SetCursor(nullptr);
} else {
@@ -332,7 +334,7 @@ static BOOL CALLBACK _MonitorEnumProcUsableSize(HMONITOR hMonitor, HDC hdcMonito
EnumRectData *data = (EnumRectData *)dwData;
if (data->count == data->screen) {
MONITORINFO minfo;
- zeromem(&minfo, sizeof(MONITORINFO));
+ memset(&minfo, 0, sizeof(MONITORINFO));
minfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfoA(hMonitor, &minfo);
@@ -715,7 +717,7 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window
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) {
+ if (mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
RECT rect;
GetClientRect(wd.hWnd, &rect);
ClientToScreen(wd.hWnd, (POINT *)&rect.left);
@@ -841,7 +843,7 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
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) {
+ if (mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
RECT crect;
GetClientRect(wd.hWnd, &crect);
ClientToScreen(wd.hWnd, (POINT *)&crect.left);
@@ -1119,7 +1121,7 @@ bool DisplayServerWindows::window_can_draw(WindowID p_window) const {
ERR_FAIL_COND_V(!windows.has(p_window), false);
const WindowData &wd = windows[p_window];
- return wd.minimized;
+ return !wd.minimized;
}
bool DisplayServerWindows::can_any_window_draw() const {
@@ -1419,13 +1421,13 @@ void DisplayServerWindows::enable_for_stealing_focus(OS::ProcessID pid) {
}
int DisplayServerWindows::keyboard_get_layout_count() const {
- return GetKeyboardLayoutList(0, NULL);
+ return GetKeyboardLayoutList(0, nullptr);
}
int DisplayServerWindows::keyboard_get_current_layout() const {
HKL cur_layout = GetKeyboardLayout(0);
- int layout_count = GetKeyboardLayoutList(0, NULL);
+ int layout_count = GetKeyboardLayoutList(0, nullptr);
HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
GetKeyboardLayoutList(layout_count, layouts);
@@ -1440,7 +1442,7 @@ int DisplayServerWindows::keyboard_get_current_layout() const {
}
void DisplayServerWindows::keyboard_set_current_layout(int p_index) {
- int layout_count = GetKeyboardLayoutList(0, NULL);
+ int layout_count = GetKeyboardLayoutList(0, nullptr);
ERR_FAIL_INDEX(p_index, layout_count);
@@ -1451,7 +1453,7 @@ void DisplayServerWindows::keyboard_set_current_layout(int p_index) {
}
String DisplayServerWindows::keyboard_get_layout_language(int p_index) const {
- int layout_count = GetKeyboardLayoutList(0, NULL);
+ int layout_count = GetKeyboardLayoutList(0, nullptr);
ERR_FAIL_INDEX_V(p_index, layout_count, "");
@@ -1481,7 +1483,7 @@ String _get_full_layout_name_from_registry(HKL p_layout) {
DWORD buffer = 1024;
DWORD vtype = REG_SZ;
- if (RegQueryValueExW(hkey, L"Layout Text", NULL, &vtype, (LPBYTE)layout_text, &buffer) == ERROR_SUCCESS) {
+ if (RegQueryValueExW(hkey, L"Layout Text", nullptr, &vtype, (LPBYTE)layout_text, &buffer) == ERROR_SUCCESS) {
ret = String::utf16((const char16_t *)layout_text);
}
RegCloseKey(hkey);
@@ -1489,7 +1491,7 @@ String _get_full_layout_name_from_registry(HKL p_layout) {
}
String DisplayServerWindows::keyboard_get_layout_name(int p_index) const {
- int layout_count = GetKeyboardLayoutList(0, NULL);
+ int layout_count = GetKeyboardLayoutList(0, nullptr);
ERR_FAIL_INDEX_V(p_index, layout_count, "");
@@ -1889,7 +1891,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Run a timer to prevent event catching warning if the focused window is closing.
windows[window_id].focus_timer_id = SetTimer(windows[window_id].hWnd, 2, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
}
- return 0; // Return To The Message Loop
+ return 0; // Return To The Message Loop
}
case WM_GETMINMAXINFO: {
if (windows[window_id].resizable && !windows[window_id].fullscreen) {
@@ -1966,9 +1968,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
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_ctrl_pressed(control_mem);
+ mm->set_shift_pressed(shift_mem);
+ mm->set_alt_pressed(alt_mem);
mm->set_pressure((raw->data.mouse.ulButtons & RI_MOUSE_LEFT_BUTTON_DOWN) ? 1.0f : 0.0f);
@@ -2062,9 +2064,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
Ref<InputEventMouseMotion> mm;
mm.instance();
mm->set_window_id(window_id);
- mm->set_control(GetKeyState(VK_CONTROL) < 0);
- mm->set_shift(GetKeyState(VK_SHIFT) < 0);
- mm->set_alt(alt_mem);
+ mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0);
+ mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0);
+ mm->set_alt_pressed(alt_mem);
mm->set_pressure(windows[window_id].last_pressure);
mm->set_tilt(windows[window_id].last_tilt);
@@ -2189,8 +2191,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
// 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)
+ if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) {
break;
+ }
Ref<InputEventMouseMotion> mm;
mm.instance();
@@ -2205,9 +2208,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_tilt(Vector2((float)pen_info.tiltX / 90, (float)pen_info.tiltY / 90));
}
- mm->set_control(GetKeyState(VK_CONTROL) < 0);
- mm->set_shift(GetKeyState(VK_SHIFT) < 0);
- mm->set_alt(alt_mem);
+ mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0);
+ mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0);
+ mm->set_alt_pressed(alt_mem);
mm->set_button_mask(last_button_state);
@@ -2294,15 +2297,16 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
// 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)
+ 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_ctrl_pressed((wParam & MK_CONTROL) != 0);
+ mm->set_shift_pressed((wParam & MK_SHIFT) != 0);
+ mm->set_alt_pressed(alt_mem);
if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
// Note: WinTab sends both WT_PACKET and WM_xBUTTONDOWN/UP/MOUSEMOVE events, use mouse 1/0 pressure only when last_pressure was not updated recently.
@@ -2412,35 +2416,38 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_LBUTTONDBLCLK: {
mb->set_pressed(true);
mb->set_button_index(1);
- mb->set_doubleclick(true);
+ mb->set_double_click(true);
} break;
case WM_RBUTTONDBLCLK: {
mb->set_pressed(true);
mb->set_button_index(2);
- mb->set_doubleclick(true);
+ mb->set_double_click(true);
} break;
case WM_MBUTTONDBLCLK: {
mb->set_pressed(true);
mb->set_button_index(3);
- mb->set_doubleclick(true);
+ mb->set_double_click(true);
} break;
case WM_MOUSEWHEEL: {
mb->set_pressed(true);
int motion = (short)HIWORD(wParam);
- if (!motion)
+ if (!motion) {
return 0;
+ }
- if (motion > 0)
+ if (motion > 0) {
mb->set_button_index(MOUSE_BUTTON_WHEEL_UP);
- else
+ } else {
mb->set_button_index(MOUSE_BUTTON_WHEEL_DOWN);
+ }
} break;
case WM_MOUSEHWHEEL: {
mb->set_pressed(true);
int motion = (short)HIWORD(wParam);
- if (!motion)
+ if (!motion) {
return 0;
+ }
if (motion < 0) {
mb->set_button_index(MOUSE_BUTTON_WHEEL_LEFT);
@@ -2452,39 +2459,43 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WM_XBUTTONDOWN: {
mb->set_pressed(true);
- if (HIWORD(wParam) == XBUTTON1)
+ if (HIWORD(wParam) == XBUTTON1) {
mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
- else
+ } else {
mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
+ }
} break;
case WM_XBUTTONUP: {
mb->set_pressed(false);
- if (HIWORD(wParam) == XBUTTON1)
+ if (HIWORD(wParam) == XBUTTON1) {
mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
- else
+ } else {
mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
+ }
} break;
case WM_XBUTTONDBLCLK: {
mb->set_pressed(true);
- if (HIWORD(wParam) == XBUTTON1)
+ if (HIWORD(wParam) == XBUTTON1) {
mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
- else
+ } else {
mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
- mb->set_doubleclick(true);
+ }
+ mb->set_double_click(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())
+ mb->set_ctrl_pressed((wParam & MK_CONTROL) != 0);
+ mb->set_shift_pressed((wParam & MK_SHIFT) != 0);
+ mb->set_alt_pressed(alt_mem);
+ //mb->is_alt_pressed()=(wParam&MK_MENU)!=0;
+ if (mb->is_pressed()) {
last_button_state |= (1 << (mb->get_button_index() - 1));
- else
+ } 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)));
@@ -2726,7 +2737,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} 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)) {
+ if (windows[window_id].window_has_focus && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
//Hide the cursor
if (hCursor == nullptr) {
hCursor = SetCursor(nullptr);
@@ -2835,17 +2846,17 @@ void DisplayServerWindows::_process_key_events() {
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_shift_pressed(ke.shift);
+ k->set_alt_pressed(ke.alt);
+ k->set_ctrl_pressed(ke.control);
+ k->set_meta_pressed(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(unicode);
if (k->get_unicode() && gr_mem) {
- k->set_alt(false);
- k->set_control(false);
+ k->set_alt_pressed(false);
+ k->set_ctrl_pressed(false);
}
if (k->get_unicode() < 32)
@@ -2862,10 +2873,10 @@ void DisplayServerWindows::_process_key_events() {
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_shift_pressed(ke.shift);
+ k->set_alt_pressed(ke.alt);
+ k->set_ctrl_pressed(ke.control);
+ k->set_meta_pressed(ke.meta);
k->set_pressed(ke.uMsg == WM_KEYDOWN);
@@ -2900,8 +2911,8 @@ void DisplayServerWindows::_process_key_events() {
k->set_unicode(unicode);
}
if (k->get_unicode() && gr_mem) {
- k->set_alt(false);
- k->set_control(false);
+ k->set_alt_pressed(false);
+ k->set_ctrl_pressed(false);
}
if (k->get_unicode() < 32)
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 222597b3ff..803d9371f5 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/os.h"
#include "editor/editor_export.h"
#include "editor/editor_node.h"
diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis
index 857c6a88f1..bb855e4ac8 100644
--- a/platform/windows/godot.natvis
+++ b/platform/windows/godot.natvis
@@ -40,13 +40,13 @@
<DisplayString Condition="type == Variant::TRANSFORM2D">{_data._transform2d}</DisplayString>
<DisplayString Condition="type == Variant::AABB">{_data._aabb}</DisplayString>
<DisplayString Condition="type == Variant::BASIS">{_data._basis}</DisplayString>
- <DisplayString Condition="type == Variant::TRANSFORM">{_data._transform}</DisplayString>
+ <DisplayString Condition="type == Variant::TRANSFORM3D">{_data._transform}</DisplayString>
<DisplayString Condition="type == Variant::STRING">{*(String *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::VECTOR2">{*(Vector2 *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::RECT2">{*(Rect2 *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::VECTOR3">{*(Vector3 *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::PLANE">{*(Plane *)_data._mem}</DisplayString>
- <DisplayString Condition="type == Variant::QUAT">{*(Quat *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::QUATERNION">{*(Quaternion *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::COLOR">{*(Color *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::NODE_PATH">{*(NodePath *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::RID">{*(::RID *)_data._mem}</DisplayString>
@@ -72,13 +72,13 @@
<Item Name="[value]" Condition="type == Variant::TRANSFORM2D">_data._transform2d</Item>
<Item Name="[value]" Condition="type == Variant::AABB">_data._aabb</Item>
<Item Name="[value]" Condition="type == Variant::BASIS">_data._basis</Item>
- <Item Name="[value]" Condition="type == Variant::TRANSFORM">_data._transform</Item>
+ <Item Name="[value]" Condition="type == Variant::TRANSFORM3D">_data._transform</Item>
<Item Name="[value]" Condition="type == Variant::STRING">*(String *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::VECTOR2">*(Vector2 *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::RECT2">*(Rect2 *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::VECTOR3">*(Vector3 *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::PLANE">*(Plane *)_data._mem</Item>
- <Item Name="[value]" Condition="type == Variant::QUAT">*(Quat *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::QUATERNION">*(Quaternion *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::COLOR">*(Color *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::NODE_PATH">*(NodePath *)_data._mem</Item>
<Item Name="[value]" Condition="type == Variant::RID">*(::RID *)_data._mem</Item>
@@ -128,8 +128,8 @@
</Expand>
</Type>
- <Type Name="Quat">
- <DisplayString>Quat {{{x},{y},{z},{w}}}</DisplayString>
+ <Type Name="Quaternion">
+ <DisplayString>Quaternion {{{x},{y},{z},{w}}}</DisplayString>
<Expand>
<Item Name="x">x</Item>
<Item Name="y">y</Item>
diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp
index 3312c91932..c367c69826 100644
--- a/platform/windows/key_mapping_windows.cpp
+++ b/platform/windows/key_mapping_windows.cpp
@@ -47,7 +47,7 @@ static _WinTranslatePair _vk_to_keycode[] = {
{ KEY_SHIFT, VK_SHIFT }, //(0x10)
- { KEY_CONTROL, VK_CONTROL }, //(0x11)
+ { KEY_CTRL, VK_CONTROL }, //(0x11)
{ KEY_ALT, VK_MENU }, //(0x12)
@@ -166,8 +166,8 @@ static _WinTranslatePair _vk_to_keycode[] = {
{ KEY_SCROLLLOCK, VK_SCROLL }, // (0x91)
{ KEY_SHIFT, VK_LSHIFT }, // (0xA0)
{ KEY_SHIFT, VK_RSHIFT }, // (0xA1)
- { KEY_CONTROL, VK_LCONTROL }, // (0xA2)
- { KEY_CONTROL, VK_RCONTROL }, // (0xA3)
+ { KEY_CTRL, VK_LCONTROL }, // (0xA2)
+ { KEY_CTRL, VK_RCONTROL }, // (0xA3)
{ KEY_MENU, VK_LMENU }, // (0xA4)
{ KEY_MENU, VK_RMENU }, // (0xA5)
@@ -265,7 +265,7 @@ static _WinTranslatePair _scancode_to_keycode[] = {
{ KEY_BRACELEFT, 0x1A },
{ KEY_BRACERIGHT, 0x1B },
{ KEY_ENTER, 0x1C },
- { KEY_CONTROL, 0x1D },
+ { KEY_CTRL, 0x1D },
{ KEY_A, 0x1E },
{ KEY_S, 0x1F },
{ KEY_D, 0x20 },
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 1e9cdd241d..c956fe49ae 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -204,7 +204,7 @@ void OS_Windows::initialize() {
current_pi.pi.hProcess = GetCurrentProcess();
process_map->insert(GetCurrentProcessId(), current_pi);
- IP_Unix::make_default();
+ IPUnix::make_default();
main_loop = nullptr;
}
@@ -315,8 +315,8 @@ OS::Time OS_Windows::get_time(bool utc) const {
Time time;
time.hour = systemtime.wHour;
- time.min = systemtime.wMinute;
- time.sec = systemtime.wSecond;
+ time.minute = systemtime.wMinute;
+ time.second = systemtime.wSecond;
return time;
}
@@ -631,31 +631,45 @@ MainLoop *OS_Windows::get_main_loop() const {
}
String OS_Windows::get_config_path() const {
- if (has_environment("XDG_CONFIG_HOME")) { // unlikely, but after all why not?
- return get_environment("XDG_CONFIG_HOME");
- } else if (has_environment("APPDATA")) {
+ // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
+ if (has_environment("XDG_CONFIG_HOME")) {
+ if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) {
+ return get_environment("XDG_CONFIG_HOME");
+ } else {
+ WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `%APPDATA%` or `.` per the XDG Base Directory specification.");
+ }
+ }
+ if (has_environment("APPDATA")) {
return get_environment("APPDATA");
- } else {
- return ".";
}
+ return ".";
}
String OS_Windows::get_data_path() const {
+ // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
if (has_environment("XDG_DATA_HOME")) {
- return get_environment("XDG_DATA_HOME");
- } else {
- return get_config_path();
+ if (get_environment("XDG_DATA_HOME").is_absolute_path()) {
+ return get_environment("XDG_DATA_HOME");
+ } else {
+ WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `get_config_path()` per the XDG Base Directory specification.");
+ }
}
+ return get_config_path();
}
String OS_Windows::get_cache_path() const {
+ // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
if (has_environment("XDG_CACHE_HOME")) {
- return get_environment("XDG_CACHE_HOME");
- } else if (has_environment("TEMP")) {
+ if (get_environment("XDG_CACHE_HOME").is_absolute_path()) {
+ return get_environment("XDG_CACHE_HOME");
+ } else {
+ WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `%TEMP%` or `get_config_path()` per the XDG Base Directory specification.");
+ }
+ }
+ if (has_environment("TEMP")) {
return get_environment("TEMP");
- } else {
- return get_config_path();
}
+ return get_config_path();
}
// Get properly capitalized engine name for system paths
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 9dfdd7bd0e..597693aa6a 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -118,7 +118,7 @@ void Area2D::_body_enter_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
}
@@ -132,7 +132,7 @@ void Area2D::_body_exit_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
}
@@ -154,6 +154,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
if (body_in) {
if (!E) {
E = body_map.insert(objid, BodyState());
+ E->get().rid = p_body;
E->get().rc = 0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
@@ -170,7 +171,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
}
if (!node || E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);
}
} else {
@@ -192,7 +193,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
}
}
if (!node || in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_area_shape);
}
}
@@ -211,7 +212,7 @@ void Area2D::_area_enter_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_entered, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
}
@@ -225,7 +226,7 @@ void Area2D::_area_exit_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
}
@@ -246,6 +247,7 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
if (area_in) {
if (!E) {
E = area_map.insert(objid, AreaState());
+ E->get().rid = p_area;
E->get().rc = 0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
@@ -262,7 +264,7 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
}
if (!node || E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_entered, objid, node, p_area_shape, p_self_shape);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_area, node, p_area_shape, p_self_shape);
}
} else {
@@ -284,7 +286,7 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
}
}
if (!node || in_tree) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_exited, objid, obj, p_area_shape, p_self_shape);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_area, obj, p_area_shape, p_self_shape);
}
}
@@ -315,7 +317,7 @@ void Area2D::_clear_monitoring() {
}
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_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
@@ -343,7 +345,7 @@ void Area2D::_clear_monitoring() {
}
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_shape_exited, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
@@ -532,13 +534,13 @@ void Area2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_body_inout"), &Area2D::_body_inout);
ClassDB::bind_method(D_METHOD("_area_inout"), &Area2D::_area_inout);
- ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D")));
ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D")));
- ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D")));
ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D")));
@@ -551,7 +553,7 @@ void Area2D::_bind_methods() {
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::VECTOR2, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.001"), "set_gravity", "get_gravity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-4096,4096,0.001,or_lesser,or_greater"), "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");
@@ -568,7 +570,7 @@ void Area2D::_bind_methods() {
Area2D::Area2D() :
CollisionObject2D(PhysicsServer2D::get_singleton()->area_create(), true) {
- set_gravity(98);
+ set_gravity(980);
set_gravity_vector(Vector2(0, 1));
set_monitoring(true);
set_monitorable(true);
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index d6fcb2c2a5..2c29e4660d 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -83,6 +83,7 @@ private:
};
struct BodyState {
+ RID rid;
int rc = 0;
bool in_tree = false;
VSet<ShapePair> shapes;
@@ -114,6 +115,7 @@ private:
};
struct AreaState {
+ RID rid;
int rc = 0;
bool in_tree = false;
VSet<AreaShapePair> shapes;
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 6d8d6058eb..127ef6762d 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -170,7 +170,6 @@ void AudioStreamPlayer2D::_notification(int p_what) {
//update anything related to position first, if possible of course
if (!output_ready.is_set()) {
- List<Viewport *> viewports;
Ref<World2D> world_2d = get_world_2d();
ERR_FAIL_COND(world_2d.is_null());
@@ -203,8 +202,9 @@ void AudioStreamPlayer2D::_notification(int p_what) {
break;
}
- world_2d->get_viewport_list(&viewports);
- for (List<Viewport *>::Element *E = viewports.front(); E; E = E->next()) {
+ const Set<Viewport *> viewports = world_2d->get_viewports();
+
+ for (Set<Viewport *>::Element *E = viewports.front(); E; E = E->next()) {
Viewport *vp = E->get();
if (vp->is_audio_listener_2d()) {
//compute matrix to convert to screen
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 01045502d5..ca4b8d72a1 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -270,11 +270,10 @@ void Camera2D::_notification(int p_what) {
}
if (screen_drawing_enabled) {
- Color area_axis_color(0.5, 0.42, 0.87, 0.63);
+ Color area_axis_color(1, 0.4, 1, 0.63);
real_t area_axis_width = 1;
if (is_current()) {
area_axis_width = 3;
- area_axis_color.a = 0.83;
}
Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
@@ -295,10 +294,9 @@ void Camera2D::_notification(int p_what) {
}
if (limit_drawing_enabled) {
- Color limit_drawing_color(1, 1, 0, 0.63);
+ Color limit_drawing_color(1, 1, 0.25, 0.63);
real_t limit_drawing_width = 1;
if (is_current()) {
- limit_drawing_color.a = 0.83;
limit_drawing_width = 3;
}
@@ -317,11 +315,10 @@ void Camera2D::_notification(int p_what) {
}
if (margin_drawing_enabled) {
- Color margin_drawing_color(0, 1, 1, 0.63);
+ Color margin_drawing_color(0.25, 1, 1, 0.63);
real_t margin_drawing_width = 1;
if (is_current()) {
margin_drawing_width = 3;
- margin_drawing_color.a = 0.83;
}
Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 530303f128..a633923be7 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -127,6 +127,7 @@ uint32_t CollisionObject2D::get_collision_mask() const {
}
void CollisionObject2D::set_collision_layer_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t collision_layer = get_collision_layer();
if (p_value) {
collision_layer |= 1 << p_bit;
@@ -137,10 +138,12 @@ void CollisionObject2D::set_collision_layer_bit(int p_bit, bool p_value) {
}
bool CollisionObject2D::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
void CollisionObject2D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -151,6 +154,7 @@ void CollisionObject2D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool CollisionObject2D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
@@ -404,6 +408,10 @@ void CollisionObject2D::set_only_update_transform_changes(bool p_enable) {
only_update_transform_changes = p_enable;
}
+bool CollisionObject2D::is_only_update_transform_changes_enabled() const {
+ return only_update_transform_changes;
+}
+
void CollisionObject2D::_update_pickable() {
if (!is_inside_tree()) {
return;
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index bb1a9dfcf5..e10f3097d9 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -62,7 +62,7 @@ class CollisionObject2D : public Node2D {
int total_subshapes = 0;
Map<uint32_t, ShapeData> shapes;
- bool only_update_transform_changes = false; //this is used for sync physics in KinematicBody
+ bool only_update_transform_changes = false; //this is used for sync physics in CharacterBody2D
protected:
CollisionObject2D(RID p_rid, bool p_area);
@@ -77,6 +77,7 @@ protected:
void _mouse_exit();
void set_only_update_transform_changes(bool p_enable);
+ bool is_only_update_transform_changes_enabled() const;
public:
void set_collision_layer(uint32_t p_layer);
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index a69ef73a54..2a2fde80e2 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -244,7 +244,7 @@ TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
- warnings.push_back(TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));
+ warnings.push_back(TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape."));
}
int polygon_count = polygon.size();
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index d9009ef85c..60780f1cc3 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -181,7 +181,7 @@ TypedArray<String> CollisionShape2D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
- warnings.push_back(TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));
+ warnings.push_back(TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
warnings.push_back(TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"));
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 5f2efeb8ca..1578643d14 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -976,7 +976,7 @@ void CPUParticles2D::_update_particle_data_buffer() {
ptr[7] = t.elements[2][1];
} else {
- zeromem(ptr, sizeof(float) * 8);
+ memset(ptr, 0, sizeof(float) * 8);
}
Color c = r[idx].color;
@@ -1080,7 +1080,7 @@ void CPUParticles2D::_notification(int p_what) {
ptr[7] = t.elements[2][1];
} else {
- zeromem(ptr, sizeof(float) * 8);
+ memset(ptr, 0, sizeof(float) * 8);
}
ptr += 16;
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index ba34a0f45d..92b8be77cf 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -169,7 +169,7 @@ private:
Vector<Color> emission_colors;
int emission_point_count = 0;
- Vector2 gravity = Vector2(0, 98);
+ Vector2 gravity = Vector2(0, 980);
void _update_internal();
void _particles_process(float p_delta);
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 8a0631a614..d7404ff479 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -115,7 +115,7 @@ void GPUParticles2D::set_use_local_coordinates(bool p_enable) {
void GPUParticles2D::_update_particle_emission_transform() {
Transform2D xf2d = get_global_transform();
- Transform xf;
+ Transform3D 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));
@@ -140,6 +140,62 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
update_configuration_warnings();
}
+void GPUParticles2D::set_trail_enabled(bool p_enabled) {
+ trail_enabled = p_enabled;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ update_configuration_warnings();
+ update();
+
+ RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED);
+}
+void GPUParticles2D::set_trail_length(float p_seconds) {
+ ERR_FAIL_COND(p_seconds < 0.001);
+ trail_length = p_seconds;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ update();
+}
+
+void GPUParticles2D::set_trail_sections(int p_sections) {
+ ERR_FAIL_COND(p_sections < 2);
+ ERR_FAIL_COND(p_sections > 128);
+
+ trail_sections = p_sections;
+ update();
+}
+void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) {
+ ERR_FAIL_COND(trail_section_subdivisions < 1);
+ ERR_FAIL_COND(trail_section_subdivisions > 1024);
+
+ trail_section_subdivisions = p_subdivisions;
+ update();
+}
+
+bool GPUParticles2D::is_trail_enabled() const {
+ return trail_enabled;
+}
+float GPUParticles2D::get_trail_length() const {
+ return trail_length;
+}
+
+void GPUParticles2D::_update_collision_size() {
+ float csize = collision_base_size;
+
+ if (texture.is_valid()) {
+ csize *= (texture->get_width() + texture->get_height()) / 4.0; //half size since its a radius
+ }
+
+ RS::get_singleton()->particles_set_collision_base_size(particles, csize);
+}
+
+void GPUParticles2D::set_collision_base_size(float p_size) {
+ collision_base_size = p_size;
+ _update_collision_size();
+}
+
+float GPUParticles2D::get_collision_base_size() const {
+ return collision_base_size;
+}
+
void GPUParticles2D::set_speed_scale(float p_scale) {
speed_scale = p_scale;
RS::get_singleton()->particles_set_speed_scale(particles, p_scale);
@@ -157,6 +213,13 @@ float GPUParticles2D::get_lifetime() const {
return lifetime;
}
+int GPUParticles2D::get_trail_sections() const {
+ return trail_sections;
+}
+int GPUParticles2D::get_trail_section_subdivisions() const {
+ return trail_section_subdivisions;
+}
+
bool GPUParticles2D::get_one_shot() const {
return one_shot;
}
@@ -253,6 +316,7 @@ Rect2 GPUParticles2D::capture_rect() const {
void GPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) {
texture = p_texture;
+ _update_collision_size();
update();
}
@@ -271,10 +335,119 @@ void GPUParticles2D::restart() {
void GPUParticles2D::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
RID texture_rid;
+ Size2 size;
if (texture.is_valid()) {
texture_rid = texture->get_rid();
+ size = texture->get_size();
+ } else {
+ size = Size2(1, 1);
}
+ if (trail_enabled) {
+ RS::get_singleton()->mesh_clear(mesh);
+ PackedVector2Array points;
+ PackedVector2Array uvs;
+ PackedInt32Array bone_indices;
+ PackedFloat32Array bone_weights;
+ PackedInt32Array indices;
+
+ int total_segments = trail_sections * trail_section_subdivisions;
+ float depth = size.height * trail_sections;
+
+ for (int j = 0; j <= total_segments; j++) {
+ float v = j;
+ v /= total_segments;
+
+ float y = depth * v;
+ y = (depth * 0.5) - y;
+
+ int bone = j / trail_section_subdivisions;
+ float blend = 1.0 - float(j % trail_section_subdivisions) / float(trail_section_subdivisions);
+
+ float s = size.width;
+
+ points.push_back(Vector2(-s * 0.5, 0));
+ points.push_back(Vector2(+s * 0.5, 0));
+
+ uvs.push_back(Vector2(0, v));
+ uvs.push_back(Vector2(1, v));
+
+ for (int i = 0; i < 2; i++) {
+ bone_indices.push_back(bone);
+ bone_indices.push_back(MIN(trail_sections, bone + 1));
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(blend);
+ bone_weights.push_back(1.0 - blend);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ }
+
+ if (j > 0) {
+ int base = j * 2 - 2;
+ indices.push_back(base + 0);
+ indices.push_back(base + 1);
+ indices.push_back(base + 2);
+
+ indices.push_back(base + 1);
+ indices.push_back(base + 3);
+ indices.push_back(base + 2);
+ }
+ }
+
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ arr[RS::ARRAY_VERTEX] = points;
+ arr[RS::ARRAY_TEX_UV] = uvs;
+ arr[RS::ARRAY_BONES] = bone_indices;
+ arr[RS::ARRAY_WEIGHTS] = bone_weights;
+ arr[RS::ARRAY_INDEX] = indices;
+
+ RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
+
+ Vector<Transform3D> xforms;
+ for (int i = 0; i <= trail_sections; i++) {
+ Transform3D xform;
+ /*
+ xform.origin.y = depth / 2.0 - size.height * float(i);
+ xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y */
+ xforms.push_back(xform);
+ }
+
+ RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms);
+
+ } else {
+ RS::get_singleton()->mesh_clear(mesh);
+ Vector<Vector2> points;
+ points.resize(4);
+ points.write[0] = Vector2(-size.x / 2.0, -size.y / 2.0);
+ points.write[1] = Vector2(size.x / 2.0, -size.y / 2.0);
+ points.write[2] = Vector2(size.x / 2.0, size.y / 2.0);
+ points.write[3] = Vector2(-size.x / 2.0, size.y / 2.0);
+ Vector<Vector2> uvs;
+ uvs.resize(4);
+ uvs.write[0] = Vector2(0, 0);
+ uvs.write[1] = Vector2(1, 0);
+ uvs.write[2] = Vector2(1, 1);
+ uvs.write[3] = Vector2(0, 1);
+ Vector<int> indices;
+ indices.resize(6);
+ indices.write[0] = 0;
+ indices.write[1] = 1;
+ indices.write[2] = 2;
+ indices.write[3] = 0;
+ indices.write[4] = 2;
+ indices.write[5] = 3;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ arr[RS::ARRAY_VERTEX] = points;
+ arr[RS::ARRAY_TEX_UV] = uvs;
+ arr[RS::ARRAY_INDEX] = indices;
+
+ RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
+ RS::get_singleton()->particles_set_trail_bind_poses(particles, Vector<Transform3D>());
+ }
RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid);
#ifdef TOOLS_ENABLED
@@ -318,6 +491,7 @@ void GPUParticles2D::_bind_methods() {
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("set_collision_base_size", "size"), &GPUParticles2D::set_collision_base_size);
ClassDB::bind_method(D_METHOD("is_emitting"), &GPUParticles2D::is_emitting);
ClassDB::bind_method(D_METHOD("get_amount"), &GPUParticles2D::get_amount);
@@ -332,6 +506,7 @@ void GPUParticles2D::_bind_methods() {
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("get_collision_base_size"), &GPUParticles2D::get_collision_base_size);
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);
@@ -343,6 +518,18 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart"), &GPUParticles2D::restart);
+ ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles2D::set_trail_enabled);
+ ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles2D::set_trail_length);
+
+ ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles2D::is_trail_enabled);
+ ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles2D::get_trail_length);
+
+ ClassDB::bind_method(D_METHOD("set_trail_sections", "sections"), &GPUParticles2D::set_trail_sections);
+ ClassDB::bind_method(D_METHOD("get_trail_sections"), &GPUParticles2D::get_trail_sections);
+
+ ClassDB::bind_method(D_METHOD("set_trail_section_subdivisions", "subdivisions"), &GPUParticles2D::set_trail_section_subdivisions);
+ ClassDB::bind_method(D_METHOD("get_trail_section_subdivisions"), &GPUParticles2D::get_trail_section_subdivisions);
+
ADD_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", "");
@@ -354,10 +541,17 @@ void GPUParticles2D::_bind_methods() {
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("Collision", "collision_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size");
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_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime"), "set_draw_order", "get_draw_order");
+ ADD_GROUP("Trails", "trail_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_trail_length", "get_trail_length");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_trail_sections", "get_trail_sections");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_section_subdivisions", PROPERTY_HINT_RANGE, "1,1024,1"), "set_trail_section_subdivisions", "get_trail_section_subdivisions");
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", "");
@@ -365,10 +559,16 @@ void GPUParticles2D::_bind_methods() {
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_REVERSE_LIFETIME);
}
GPUParticles2D::GPUParticles2D() {
particles = RS::get_singleton()->particles_create();
+ RS::get_singleton()->particles_set_mode(particles, RS::PARTICLES_MODE_2D);
+
+ mesh = RS::get_singleton()->mesh_create();
+ RS::get_singleton()->particles_set_draw_passes(particles, 1);
+ RS::get_singleton()->particles_set_draw_pass_mesh(particles, 0, mesh);
one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
set_emitting(true);
@@ -382,10 +582,13 @@ GPUParticles2D::GPUParticles2D() {
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_draw_order(DRAW_ORDER_LIFETIME);
set_speed_scale(1);
+ set_fixed_fps(30);
+ set_collision_base_size(collision_base_size);
}
GPUParticles2D::~GPUParticles2D() {
RS::get_singleton()->free(particles);
+ RS::get_singleton()->free(mesh);
}
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index 20f9f768ed..9d8e61daf7 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -43,6 +43,7 @@ public:
enum DrawOrder {
DRAW_ORDER_INDEX,
DRAW_ORDER_LIFETIME,
+ DRAW_ORDER_REVERSE_LIFETIME,
};
private:
@@ -68,11 +69,23 @@ private:
void _update_particle_emission_transform();
+ NodePath sub_emitter;
+ float collision_base_size = 1.0;
+
+ bool trail_enabled = false;
+ float trail_length = 0.3;
+ int trail_sections = 8;
+ int trail_section_subdivisions = 4;
+
+ RID mesh;
+
protected:
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const override;
void _notification(int p_what);
+ void _update_collision_size();
+
public:
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
@@ -85,6 +98,11 @@ public:
void set_use_local_coordinates(bool p_enable);
void set_process_material(const Ref<Material> &p_material);
void set_speed_scale(float p_scale);
+ void set_collision_base_size(float p_ratio);
+ void set_trail_enabled(bool p_enabled);
+ void set_trail_length(float p_seconds);
+ void set_trail_sections(int p_sections);
+ void set_trail_section_subdivisions(int p_subdivisions);
bool is_emitting() const;
int get_amount() const;
@@ -98,6 +116,12 @@ public:
Ref<Material> get_process_material() const;
float get_speed_scale() const;
+ float get_collision_base_size() const;
+ bool is_trail_enabled() const;
+ float get_trail_length() const;
+ int get_trail_sections() const;
+ int get_trail_section_subdivisions() const;
+
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 8fb765f16b..ce57895341 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -281,7 +281,7 @@ void Light2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_energy", "get_energy");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Add,Sub,Mix"), "set_blend_mode", "get_blend_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Add,Subtract,Mix"), "set_blend_mode", "get_blend_mode");
ADD_GROUP("Range", "range_");
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");
@@ -292,7 +292,7 @@ void Light2D::_bind_methods() {
ADD_GROUP("Shadow", "shadow_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow_enabled", "is_shadow_enabled");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_filter", PROPERTY_HINT_ENUM, "None,PCF5,PCF13"), "set_shadow_filter", "get_shadow_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_filter", PROPERTY_HINT_ENUM, "None (Fast),PCF5 (Average),PCF13 (Slow)"), "set_shadow_filter", "get_shadow_filter");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shadow_filter_smooth", PROPERTY_HINT_RANGE, "0,64,0.1"), "set_shadow_smooth", "get_shadow_smooth");
ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_item_cull_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_item_shadow_cull_mask", "get_item_shadow_cull_mask");
diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp
index b7a0028199..15008390b7 100644
--- a/scene/2d/mesh_instance_2d.cpp
+++ b/scene/2d/mesh_instance_2d.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "mesh_instance_2d.h"
+#include "scene/scene_string_names.h"
void MeshInstance2D::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
@@ -70,7 +71,7 @@ void MeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) {
}
texture = p_texture;
update();
- emit_signal("texture_changed");
+ emit_signal(SceneStringNames::get_singleton()->texture_changed);
}
void MeshInstance2D::set_normal_map(const Ref<Texture2D> &p_texture) {
diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp
index 72a899370e..1bff2f337d 100644
--- a/scene/2d/multimesh_instance_2d.cpp
+++ b/scene/2d/multimesh_instance_2d.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "multimesh_instance_2d.h"
+#include "scene/scene_string_names.h"
void MultiMeshInstance2D::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
@@ -70,7 +71,7 @@ void MultiMeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) {
}
texture = p_texture;
update();
- emit_signal("texture_changed");
+ emit_signal(SceneStringNames::get_singleton()->texture_changed);
}
Ref<Texture2D> MultiMeshInstance2D::get_texture() const {
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index a18687afed..f9cbdbf377 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -35,6 +35,8 @@
#include "servers/navigation_server_2d.h"
void NavigationAgent2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent2D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent2D::set_target_desired_distance);
ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent2D::get_target_desired_distance);
@@ -88,9 +90,11 @@ void NavigationAgent2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
agent_parent = Object::cast_to<Node2D>(get_parent());
-
- NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
-
+ if (agent_parent != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map());
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+ }
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -100,12 +104,7 @@ void NavigationAgent2D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().get_origin());
- if (!target_reached) {
- if (distance_to_target() < target_desired_distance) {
- emit_signal("target_reached");
- target_reached = true;
- }
- }
+ _check_distance_to_target();
}
} break;
}
@@ -301,6 +300,7 @@ void NavigationAgent2D::update_navigation() {
while (o.distance_to(navigation_path[nav_path_index]) < target_desired_distance) {
nav_path_index += 1;
if (nav_path_index == navigation_path.size()) {
+ _check_distance_to_target();
nav_path_index -= 1;
navigation_finished = true;
emit_signal("navigation_finished");
@@ -309,3 +309,12 @@ void NavigationAgent2D::update_navigation() {
}
}
}
+
+void NavigationAgent2D::_check_distance_to_target() {
+ if (!target_reached) {
+ if (distance_to_target() < target_desired_distance) {
+ emit_signal("target_reached");
+ target_reached = true;
+ }
+ }
+}
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 138ba3bc64..234cad333f 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -140,6 +140,7 @@ public:
private:
void update_navigation();
+ void _check_distance_to_target();
};
#endif
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 8afc43ddc9..049d121213 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -391,6 +391,15 @@ Point2 Node2D::to_global(Point2 p_local) const {
return get_global_transform().xform(p_local);
}
+void Node2D::set_y_sort_enabled(bool p_enabled) {
+ y_sort_enabled = p_enabled;
+ RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), y_sort_enabled);
+}
+
+bool Node2D::is_y_sort_enabled() const {
+ return y_sort_enabled;
+}
+
void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_position", "position"), &Node2D::set_position);
ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Node2D::set_rotation);
@@ -437,6 +446,9 @@ void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &Node2D::set_z_as_relative);
ClassDB::bind_method(D_METHOD("is_z_relative"), &Node2D::is_z_relative);
+ ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enabled"), &Node2D::set_y_sort_enabled);
+ ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &Node2D::is_y_sort_enabled);
+
ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent);
ADD_GROUP("Transform", "");
@@ -454,7 +466,8 @@ void Node2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", 0), "set_global_scale", "get_global_scale");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
- ADD_GROUP("Z Index", "");
+ ADD_GROUP("Ordering", "");
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");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "y_sort_enabled"), "set_y_sort_enabled", "is_y_sort_enabled");
}
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 358b7e6520..339efd9179 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -42,6 +42,7 @@ class Node2D : public CanvasItem {
real_t skew = 0.0;
int z_index = 0;
bool z_relative = true;
+ bool y_sort_enabled = false;
Transform2D _mat;
@@ -117,6 +118,9 @@ public:
void set_z_as_relative(bool p_enabled);
bool is_z_relative() const;
+ virtual void set_y_sort_enabled(bool p_enabled);
+ virtual bool is_y_sort_enabled() const;
+
Transform2D get_relative_transform_to_parent(const Node *p_parent) const;
Transform2D get_transform() const override;
diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp
new file mode 100644
index 0000000000..0c1be16174
--- /dev/null
+++ b/scene/2d/physical_bone_2d.cpp
@@ -0,0 +1,303 @@
+/*************************************************************************/
+/* physical_bone_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "physical_bone_2d.h"
+
+void PhysicalBone2D::_notification(int p_what) {
+ if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
+ // Position the RigidBody in the correct position
+ if (follow_bone_when_simulating) {
+ _position_at_bone2d();
+ }
+
+ // Keep the child joint in the correct position.
+ if (child_joint && auto_configure_joint) {
+ child_joint->set_global_position(get_global_position());
+ }
+ } else if (p_what == NOTIFICATION_READY) {
+ _find_skeleton_parent();
+ _find_joint_child();
+
+ // Configure joint
+ if (child_joint && auto_configure_joint) {
+ _auto_configure_joint();
+ }
+
+ // Simulate physics if set
+ if (simulate_physics) {
+ _start_physics_simulation();
+ } else {
+ _stop_physics_simulation();
+ }
+
+ set_physics_process_internal(true);
+ }
+}
+
+void PhysicalBone2D::_position_at_bone2d() {
+ // Reset to Bone2D position
+ if (parent_skeleton) {
+ Bone2D *bone_to_use = parent_skeleton->get_bone(bone2d_index);
+ ERR_FAIL_COND_MSG(bone_to_use == nullptr, "It's not possible to position the bone with ID: " + itos(bone2d_index));
+ set_global_transform(bone_to_use->get_global_transform());
+ }
+}
+
+void PhysicalBone2D::_find_skeleton_parent() {
+ Node *current_parent = get_parent();
+
+ while (current_parent != nullptr) {
+ Skeleton2D *potential_skeleton = Object::cast_to<Skeleton2D>(current_parent);
+ if (potential_skeleton) {
+ parent_skeleton = potential_skeleton;
+ break;
+ } else {
+ PhysicalBone2D *potential_parent_bone = Object::cast_to<PhysicalBone2D>(current_parent);
+ if (potential_parent_bone) {
+ current_parent = potential_parent_bone->get_parent();
+ } else {
+ current_parent = nullptr;
+ }
+ }
+ }
+}
+
+void PhysicalBone2D::_find_joint_child() {
+ for (int i = 0; i < get_child_count(); i++) {
+ Node *child_node = get_child(i);
+ Joint2D *potential_joint = Object::cast_to<Joint2D>(child_node);
+ if (potential_joint) {
+ child_joint = potential_joint;
+ break;
+ }
+ }
+}
+
+TypedArray<String> PhysicalBone2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (!parent_skeleton) {
+ warnings.push_back(TTR("A PhysicalBone2D only works with a Skeleton2D or another PhysicalBone2D as a parent node!"));
+ }
+ if (parent_skeleton && bone2d_index <= -1) {
+ warnings.push_back(TTR("A PhysicalBone2D needs to be assigned to a Bone2D node in order to function! Please set a Bone2D node in the inspector."));
+ }
+ if (!child_joint) {
+ PhysicalBone2D *parent_bone = Object::cast_to<PhysicalBone2D>(get_parent());
+ if (parent_bone) {
+ warnings.push_back(TTR("A PhysicalBone2D node should have a Joint2D-based child node to keep bones connected! Please add a Joint2D-based node as a child to this node!"));
+ }
+ }
+
+ return warnings;
+}
+
+void PhysicalBone2D::_auto_configure_joint() {
+ if (!auto_configure_joint) {
+ return;
+ }
+
+ if (child_joint) {
+ // Node A = parent | Node B = this node
+ Node *parent_node = get_parent();
+ PhysicalBone2D *potential_parent_bone = Object::cast_to<PhysicalBone2D>(parent_node);
+
+ if (potential_parent_bone) {
+ child_joint->set_node_a(child_joint->get_path_to(potential_parent_bone));
+ child_joint->set_node_b(child_joint->get_path_to(this));
+ } else {
+ WARN_PRINT("Cannot setup joint without a parent PhysicalBone2D node.");
+ }
+
+ // Place the child joint at this node's position.
+ child_joint->set_global_position(get_global_position());
+ }
+}
+
+void PhysicalBone2D::_start_physics_simulation() {
+ if (_internal_simulate_physics) {
+ return;
+ }
+
+ // Reset to Bone2D position
+ _position_at_bone2d();
+
+ // Apply the layers and masks
+ PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
+ PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
+
+ // Apply the correct mode
+ RigidBody2D::Mode rigid_mode = get_mode();
+ if (rigid_mode == RigidBody2D::MODE_STATIC) {
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC);
+ } else if (rigid_mode == RigidBody2D::MODE_DYNAMIC) {
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_DYNAMIC);
+ } else if (rigid_mode == RigidBody2D::MODE_KINEMATIC) {
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_KINEMATIC);
+ } else if (rigid_mode == RigidBody2D::MODE_DYNAMIC_LOCKED) {
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_DYNAMIC_LOCKED);
+ } else {
+ // Default to Rigid
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_DYNAMIC);
+ }
+
+ _internal_simulate_physics = true;
+ set_physics_process_internal(true);
+}
+
+void PhysicalBone2D::_stop_physics_simulation() {
+ if (_internal_simulate_physics) {
+ _internal_simulate_physics = false;
+
+ // Reset to Bone2D position
+ _position_at_bone2d();
+
+ set_physics_process_internal(false);
+ PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0);
+ PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0);
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC);
+ }
+}
+
+Joint2D *PhysicalBone2D::get_joint() const {
+ return child_joint;
+}
+
+bool PhysicalBone2D::get_auto_configure_joint() const {
+ return auto_configure_joint;
+}
+
+void PhysicalBone2D::set_auto_configure_joint(bool p_auto_configure) {
+ auto_configure_joint = p_auto_configure;
+ _auto_configure_joint();
+}
+
+void PhysicalBone2D::set_simulate_physics(bool p_simulate) {
+ if (p_simulate == simulate_physics) {
+ return;
+ }
+ simulate_physics = p_simulate;
+
+ if (simulate_physics) {
+ _start_physics_simulation();
+ } else {
+ _stop_physics_simulation();
+ }
+}
+
+bool PhysicalBone2D::get_simulate_physics() const {
+ return simulate_physics;
+}
+
+bool PhysicalBone2D::is_simulating_physics() const {
+ return _internal_simulate_physics;
+}
+
+void PhysicalBone2D::set_bone2d_nodepath(const NodePath &p_nodepath) {
+ bone2d_nodepath = p_nodepath;
+ notify_property_list_changed();
+}
+
+NodePath PhysicalBone2D::get_bone2d_nodepath() const {
+ return bone2d_nodepath;
+}
+
+void PhysicalBone2D::set_bone2d_index(int p_bone_idx) {
+ ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
+
+ if (!is_inside_tree()) {
+ bone2d_index = p_bone_idx;
+ return;
+ }
+
+ if (parent_skeleton) {
+ ERR_FAIL_INDEX_MSG(p_bone_idx, parent_skeleton->get_bone_count(), "Passed-in Bone index is out of range!");
+ bone2d_index = p_bone_idx;
+
+ bone2d_nodepath = get_path_to(parent_skeleton->get_bone(bone2d_index));
+ } else {
+ WARN_PRINT("Cannot verify bone index...");
+ bone2d_index = p_bone_idx;
+ }
+
+ notify_property_list_changed();
+}
+
+int PhysicalBone2D::get_bone2d_index() const {
+ return bone2d_index;
+}
+
+void PhysicalBone2D::set_follow_bone_when_simulating(bool p_follow_bone) {
+ follow_bone_when_simulating = p_follow_bone;
+
+ if (_internal_simulate_physics) {
+ _stop_physics_simulation();
+ _start_physics_simulation();
+ }
+}
+
+bool PhysicalBone2D::get_follow_bone_when_simulating() const {
+ return follow_bone_when_simulating;
+}
+
+void PhysicalBone2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_joint"), &PhysicalBone2D::get_joint);
+ ClassDB::bind_method(D_METHOD("get_auto_configure_joint"), &PhysicalBone2D::get_auto_configure_joint);
+ ClassDB::bind_method(D_METHOD("set_auto_configure_joint", "auto_configure_joint"), &PhysicalBone2D::set_auto_configure_joint);
+
+ ClassDB::bind_method(D_METHOD("set_simulate_physics", "simulate_physics"), &PhysicalBone2D::set_simulate_physics);
+ ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone2D::get_simulate_physics);
+ ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone2D::is_simulating_physics);
+
+ ClassDB::bind_method(D_METHOD("set_bone2d_nodepath", "nodepath"), &PhysicalBone2D::set_bone2d_nodepath);
+ ClassDB::bind_method(D_METHOD("get_bone2d_nodepath"), &PhysicalBone2D::get_bone2d_nodepath);
+ ClassDB::bind_method(D_METHOD("set_bone2d_index", "bone_index"), &PhysicalBone2D::set_bone2d_index);
+ ClassDB::bind_method(D_METHOD("get_bone2d_index"), &PhysicalBone2D::get_bone2d_index);
+ ClassDB::bind_method(D_METHOD("set_follow_bone_when_simulating", "follow_bone"), &PhysicalBone2D::set_follow_bone_when_simulating);
+ ClassDB::bind_method(D_METHOD("get_follow_bone_when_simulating"), &PhysicalBone2D::get_follow_bone_when_simulating);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "bone2d_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D"), "set_bone2d_nodepath", "get_bone2d_nodepath");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bone2d_index", PROPERTY_HINT_RANGE, "-1, 1000, 1"), "set_bone2d_index", "get_bone2d_index");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_configure_joint"), "set_auto_configure_joint", "get_auto_configure_joint");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simulate_physics"), "set_simulate_physics", "get_simulate_physics");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_bone_when_simulating"), "set_follow_bone_when_simulating", "get_follow_bone_when_simulating");
+}
+
+PhysicalBone2D::PhysicalBone2D() {
+ // Stop the RigidBody from executing its force integration.
+ PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0);
+ PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0);
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC);
+
+ child_joint = nullptr;
+}
+
+PhysicalBone2D::~PhysicalBone2D() {
+}
diff --git a/scene/2d/physical_bone_2d.h b/scene/2d/physical_bone_2d.h
new file mode 100644
index 0000000000..46a2772bad
--- /dev/null
+++ b/scene/2d/physical_bone_2d.h
@@ -0,0 +1,88 @@
+/*************************************************************************/
+/* physical_bone_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PHYSICAL_BONE_2D_H
+#define PHYSICAL_BONE_2D_H
+
+#include "scene/2d/joints_2d.h"
+#include "scene/2d/physics_body_2d.h"
+
+#include "scene/2d/skeleton_2d.h"
+
+class PhysicalBone2D : public RigidBody2D {
+ GDCLASS(PhysicalBone2D, RigidBody2D);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+private:
+ Skeleton2D *parent_skeleton = nullptr;
+ int bone2d_index = -1;
+ NodePath bone2d_nodepath;
+ bool follow_bone_when_simulating = false;
+
+ Joint2D *child_joint;
+ bool auto_configure_joint = true;
+
+ bool simulate_physics = false;
+ bool _internal_simulate_physics = false;
+
+ void _find_skeleton_parent();
+ void _find_joint_child();
+ void _auto_configure_joint();
+
+ void _start_physics_simulation();
+ void _stop_physics_simulation();
+ void _position_at_bone2d();
+
+public:
+ Joint2D *get_joint() const;
+ bool get_auto_configure_joint() const;
+ void set_auto_configure_joint(bool p_auto_configure);
+
+ void set_simulate_physics(bool p_simulate);
+ bool get_simulate_physics() const;
+ bool is_simulating_physics() const;
+
+ void set_bone2d_nodepath(const NodePath &p_nodepath);
+ NodePath get_bone2d_nodepath() const;
+ void set_bone2d_index(int p_bone_idx);
+ int get_bone2d_index() const;
+ void set_follow_bone_when_simulating(bool p_follow);
+ bool get_follow_bone_when_simulating() const;
+
+ TypedArray<String> get_configuration_warnings() const override;
+
+ PhysicalBone2D();
+ ~PhysicalBone2D();
+};
+
+#endif // PHYSICAL_BONE_2D_H
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 69d146f2ea..4b72043a46 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -38,10 +38,10 @@
#include "core/templates/rid.h"
#include "scene/scene_string_names.h"
-void PhysicsBody2D::_notification(int p_what) {
-}
-
void PhysicsBody2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false), DEFVAL(0.08));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()), DEFVAL(0.08));
+
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody2D::remove_collision_exception_with);
@@ -53,6 +53,56 @@ PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) :
set_pickable(false);
}
+PhysicsBody2D::~PhysicsBody2D() {
+ if (motion_cache.is_valid()) {
+ motion_cache->owner = nullptr;
+ }
+}
+
+Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only, real_t p_margin) {
+ PhysicsServer2D::MotionResult result;
+
+ if (move_and_collide(p_motion, p_infinite_inertia, result, p_margin, p_exclude_raycast_shapes, p_test_only)) {
+ if (motion_cache.is_null()) {
+ motion_cache.instance();
+ motion_cache->owner = this;
+ }
+
+ motion_cache->result = result;
+
+ return motion_cache;
+ }
+
+ return Ref<KinematicCollision2D>();
+}
+
+bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only) {
+ if (is_only_update_transform_changes_enabled()) {
+ ERR_PRINT("Move functions do not work together with 'sync to physics' option. Please read the documentation.");
+ }
+ Transform2D gt = get_global_transform();
+ bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes);
+
+ if (!p_test_only) {
+ gt.elements[2] += r_result.motion;
+ set_global_transform(gt);
+ }
+
+ return colliding;
+}
+
+bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) {
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
+
+ PhysicsServer2D::MotionResult *r = nullptr;
+ if (r_collision.is_valid()) {
+ // Needs const_cast because method bindings don't support non-const Ref.
+ r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result);
+ }
+
+ return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes);
+}
+
TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {
List<RID> exceptions;
PhysicsServer2D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions);
@@ -83,12 +133,22 @@ void PhysicsBody2D::remove_collision_exception_with(Node *p_node) {
void StaticBody2D::set_constant_linear_velocity(const Vector2 &p_vel) {
constant_linear_velocity = p_vel;
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
+
+ if (kinematic_motion) {
+ _update_kinematic_motion();
+ } else {
+ 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;
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
+
+ if (kinematic_motion) {
+ _update_kinematic_motion();
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
+ }
}
Vector2 StaticBody2D::get_constant_linear_velocity() const {
@@ -118,27 +178,74 @@ Ref<PhysicsMaterial> StaticBody2D::get_physics_material_override() const {
return physics_material_override;
}
+void StaticBody2D::set_kinematic_motion_enabled(bool p_enabled) {
+ if (p_enabled == kinematic_motion) {
+ return;
+ }
+
+ kinematic_motion = p_enabled;
+
+ if (kinematic_motion) {
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_KINEMATIC);
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_STATIC);
+ }
+
+ _update_kinematic_motion();
+}
+
+bool StaticBody2D::is_kinematic_motion_enabled() const {
+ return kinematic_motion;
+}
+
+void StaticBody2D::_notification(int p_what) {
+ if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+#endif
+
+ ERR_FAIL_COND(!kinematic_motion);
+
+ real_t delta_time = get_physics_process_delta_time();
+
+ Transform2D new_transform = get_global_transform();
+
+ new_transform.translate(constant_linear_velocity * delta_time);
+ new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time);
+
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform);
+
+ // Propagate transform change to node.
+ set_block_transform_notify(true);
+ set_global_transform(new_transform);
+ set_block_transform_notify(false);
+ }
+}
+
void StaticBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody2D::set_constant_linear_velocity);
ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody2D::set_constant_angular_velocity);
ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody2D::get_constant_linear_velocity);
ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody2D::get_constant_angular_velocity);
+ ClassDB::bind_method(D_METHOD("set_kinematic_motion_enabled", "enabled"), &StaticBody2D::set_kinematic_motion_enabled);
+ ClassDB::bind_method(D_METHOD("is_kinematic_motion_enabled"), &StaticBody2D::is_kinematic_motion_enabled);
+
ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override);
ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override);
+ 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::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
- 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::BOOL, "kinematic_motion"), "set_kinematic_motion_enabled", "is_kinematic_motion_enabled");
}
StaticBody2D::StaticBody2D() :
PhysicsBody2D(PhysicsServer2D::BODY_MODE_STATIC) {
}
-StaticBody2D::~StaticBody2D() {
-}
-
void StaticBody2D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0);
@@ -149,6 +256,23 @@ void StaticBody2D::_reload_physics_characteristics() {
}
}
+void StaticBody2D::_update_kinematic_motion() {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+#endif
+
+ if (kinematic_motion) {
+ if (!Math::is_zero_approx(constant_angular_velocity) || !constant_linear_velocity.is_equal_approx(Vector2())) {
+ set_physics_process_internal(true);
+ return;
+ }
+ }
+
+ set_physics_process_internal(false);
+}
+
void RigidBody2D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
@@ -165,7 +289,7 @@ void RigidBody2D::_body_enter_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
}
contact_monitor->locked = false;
@@ -186,13 +310,13 @@ void RigidBody2D::_body_exit_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
}
contact_monitor->locked = false;
}
-void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape) {
+void RigidBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
bool body_in = p_status == 1;
ObjectID objid = p_instance;
@@ -207,6 +331,7 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
if (body_in) {
if (!E) {
E = contact_monitor->body_map.insert(objid, BodyState());
+ E->get().rid = p_body;
//E->get().rc=0;
E->get().in_scene = node && node->is_inside_tree();
if (node) {
@@ -225,7 +350,7 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
}
if (E->get().in_scene) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_local_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_local_shape);
}
} else {
@@ -249,28 +374,22 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
contact_monitor->body_map.erase(E);
}
if (node && in_scene) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, node, p_body_shape, p_local_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, node, p_body_shape, p_local_shape);
}
}
}
struct _RigidBody2DInOut {
+ RID rid;
ObjectID id;
int shape = 0;
int local_shape = 0;
};
-bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult2D> &p_result) {
- PhysicsServer2D::MotionResult *r = nullptr;
- if (p_result.is_valid()) {
- r = p_result->get_result_ptr();
- }
- 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<PhysicsDirectBodyState2D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");
#else
state = (PhysicsDirectBodyState2D *)p_state; //trust it
#endif
@@ -310,6 +429,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
//put the ones to add
for (int i = 0; i < state->get_contact_count(); i++) {
+ RID rid = state->get_contact_collider(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);
@@ -318,6 +438,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(obj);
if (!E) {
+ toadd[toadd_count].rid = rid;
toadd[toadd_count].local_shape = local_shape;
toadd[toadd_count].id = obj;
toadd[toadd_count].shape = shape;
@@ -328,6 +449,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
ShapePair sp(shape, local_shape);
int idx = E->get().shapes.find(sp);
if (idx == -1) {
+ toadd[toadd_count].rid = rid;
toadd[toadd_count].local_shape = local_shape;
toadd[toadd_count].id = obj;
toadd[toadd_count].shape = shape;
@@ -343,6 +465,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
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].rid = E->get().rid;
toremove[toremove_count].body_id = E->key();
toremove[toremove_count].pair = E->get().shapes[i];
toremove_count++;
@@ -353,13 +476,13 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
//process removals
for (int i = 0; i < toremove_count; i++) {
- _body_inout(0, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape);
+ _body_inout(0, toremove[i].rid, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape);
}
//process additions
for (int i = 0; i < toadd_count; i++) {
- _body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
+ _body_inout(1, toadd[i].rid, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
}
contact_monitor->locked = false;
@@ -371,8 +494,8 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
void RigidBody2D::set_mode(Mode p_mode) {
mode = p_mode;
switch (p_mode) {
- case MODE_RIGID: {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_RIGID);
+ case MODE_DYNAMIC: {
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_DYNAMIC);
} break;
case MODE_STATIC: {
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_STATIC);
@@ -382,8 +505,8 @@ void RigidBody2D::set_mode(Mode p_mode) {
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_KINEMATIC);
} break;
- case MODE_CHARACTER: {
- PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_CHARACTER);
+ case MODE_DYNAMIC_LOCKED: {
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED);
} break;
}
@@ -659,8 +782,8 @@ TypedArray<String> RigidBody2D::get_configuration_warnings() const {
TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings();
- if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05)) {
- warnings.push_back(TTR("Size changes to RigidBody2D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ if ((get_mode() == MODE_DYNAMIC || get_mode() == MODE_DYNAMIC_LOCKED) && (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05)) {
+ warnings.push_back(TTR("Size changes to RigidBody2D (in dynamic modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
return warnings;
@@ -727,15 +850,11 @@ void RigidBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody2D::set_can_sleep);
ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody2D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("test_motion", "motion", "infinite_inertia", "margin", "result"), &RigidBody2D::_test_motion, DEFVAL(true), DEFVAL(0.08), DEFVAL(Variant()));
-
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody2D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies);
BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState2D")));
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,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, "inertia", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", 0), "set_inertia", "get_inertia");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
@@ -756,15 +875,15 @@ void RigidBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "applied_force"), "set_applied_force", "get_applied_force");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "applied_torque"), "set_applied_torque", "get_applied_torque");
- 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_shape_entered", PropertyInfo(Variant::RID, "body_rid"), 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::RID, "body_rid"), 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_DYNAMIC);
BIND_ENUM_CONSTANT(MODE_STATIC);
- BIND_ENUM_CONSTANT(MODE_CHARACTER);
+ BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED);
BIND_ENUM_CONSTANT(MODE_KINEMATIC);
BIND_ENUM_CONSTANT(CCD_MODE_DISABLED);
@@ -773,8 +892,8 @@ void RigidBody2D::_bind_methods() {
}
RigidBody2D::RigidBody2D() :
- PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsBody2D(PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody2D::_direct_state_changed));
}
RigidBody2D::~RigidBody2D() {
@@ -795,95 +914,13 @@ void RigidBody2D::_reload_physics_characteristics() {
//////////////////////////
-Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &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<KinematicCollision2D>();
-}
-
-bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {
- PhysicsServer2D::SeparationResult sep_res[8]; //max 8 rays
-
- Transform2D gt = get_global_transform();
-
- Vector2 recover;
- int hits = PhysicsServer2D::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
- int deepest = -1;
- real_t 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.elements[2] += 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 = Vector2();
-
- return true;
- } else {
- return false;
- }
-}
-
-bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) {
- if (sync_to_physics) {
- 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();
- 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;
- 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;
- }
-
- if (!p_test_only) {
- gt.elements[2] += 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
-Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) {
- Vector2 body_velocity = p_linear_velocity;
- Vector2 body_velocity_normal = body_velocity.normalized();
- Vector2 up_direction = p_up_direction.normalized();
+void CharacterBody2D::move_and_slide() {
+ Vector2 body_velocity_normal = linear_velocity.normalized();
+
+ bool was_on_floor = on_floor;
Vector2 current_floor_velocity = floor_velocity;
if (on_floor && on_floor_body.is_valid()) {
@@ -895,69 +932,71 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
}
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
- Vector2 motion = (current_floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
+ Vector2 motion = (current_floor_velocity + linear_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();
+ motion_results.clear();
floor_normal = Vector2();
floor_velocity = Vector2();
- while (p_max_slides) {
- Collision collision;
+ int slide_count = max_slides;
+ while (slide_count) {
+ PhysicsServer2D::MotionResult result;
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);
+ collided = move_and_collide(motion, infinite_inertia, result, margin);
if (!collided) {
motion = Vector2(); //clear because no collision happened and motion completed
}
} else { //separate raycasts (if any)
- collided = separate_raycast_shapes(p_infinite_inertia, collision);
+ collided = separate_raycast_shapes(result);
if (collided) {
- collision.remainder = motion; //keep
- collision.travel = Vector2();
+ result.remainder = motion; //keep
+ result.motion = Vector2();
}
}
if (collided) {
found_collision = true;
- colliders.push_back(collision);
- motion = collision.remainder;
+ motion_results.push_back(result);
+ motion = result.remainder;
if (up_direction == Vector2()) {
//all is a wall
on_wall = true;
} else {
- if (Math::acos(collision.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
+ if (Math::acos(result.collision_normal.dot(up_direction)) <= 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;
+ floor_normal = result.collision_normal;
+ on_floor_body = result.collider;
+ floor_velocity = result.collider_velocity;
- if (p_stop_on_slope) {
- if ((body_velocity_normal + up_direction).length() < 0.01 && collision.travel.length() < 1) {
+ if (stop_on_slope) {
+ if ((body_velocity_normal + up_direction).length() < 0.01 && result.motion.length() < 1) {
Transform2D gt = get_global_transform();
- gt.elements[2] -= collision.travel.slide(up_direction);
+ gt.elements[2] -= result.motion.slide(up_direction);
set_global_transform(gt);
- return Vector2();
+ linear_velocity = Vector2();
+ return;
}
}
- } else if (Math::acos(collision.normal.dot(-up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
+ } else if (Math::acos(result.collision_normal.dot(-up_direction)) <= 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);
+ motion = motion.slide(result.collision_normal);
+ linear_velocity = linear_velocity.slide(result.collision_normal);
}
}
@@ -965,36 +1004,28 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
break;
}
- --p_max_slides;
+ --slide_count;
}
- return body_velocity;
-}
-
-Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) {
- Vector2 up_direction = p_up_direction.normalized();
- bool was_on_floor = on_floor;
-
- Vector2 ret = move_and_slide(p_linear_velocity, up_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia);
- if (!was_on_floor || p_snap == Vector2()) {
- return ret;
+ if (!was_on_floor || snap == Vector2()) {
+ return;
}
- Collision col;
+ // Apply snap.
Transform2D gt = get_global_transform();
-
- if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) {
+ PhysicsServer2D::MotionResult result;
+ if (move_and_collide(snap, infinite_inertia, result, margin, false, true)) {
bool apply = true;
if (up_direction != Vector2()) {
- if (Math::acos(col.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
on_floor = true;
- floor_normal = col.normal;
- on_floor_body = col.collider_rid;
- floor_velocity = col.collider_vel;
- if (p_stop_on_slope) {
+ floor_normal = result.collision_normal;
+ on_floor_body = result.collider;
+ floor_velocity = result.collider_velocity;
+ if (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 = up_direction * up_direction.dot(col.travel);
+ result.motion = up_direction * up_direction.dot(result.motion);
}
} else {
@@ -1003,59 +1034,87 @@ Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_veloci
}
if (apply) {
- gt.elements[2] += col.travel;
+ gt.elements[2] += result.motion;
set_global_transform(gt);
}
}
-
- return ret;
}
-bool KinematicBody2D::is_on_floor() const {
- return on_floor;
-}
+bool CharacterBody2D::separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result) {
+ PhysicsServer2D::SeparationResult sep_res[8]; //max 8 rays
-bool KinematicBody2D::is_on_wall() const {
- return on_wall;
+ Transform2D gt = get_global_transform();
+
+ Vector2 recover;
+ int hits = PhysicsServer2D::get_singleton()->body_test_ray_separation(get_rid(), gt, infinite_inertia, recover, sep_res, 8, margin);
+ int deepest = -1;
+ real_t 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.elements[2] += recover;
+ set_global_transform(gt);
+
+ if (deepest != -1) {
+ r_result.collider_id = sep_res[deepest].collider_id;
+ r_result.collider_metadata = sep_res[deepest].collider_metadata;
+ r_result.collider_shape = sep_res[deepest].collider_shape;
+ r_result.collider_velocity = sep_res[deepest].collider_velocity;
+ r_result.collision_point = sep_res[deepest].collision_point;
+ r_result.collision_normal = sep_res[deepest].collision_normal;
+ r_result.collision_local_shape = sep_res[deepest].collision_local_shape;
+ r_result.motion = recover;
+ r_result.remainder = Vector2();
+
+ return true;
+ } else {
+ return false;
+ }
}
-bool KinematicBody2D::is_on_ceiling() const {
- return on_ceiling;
+const Vector2 &CharacterBody2D::get_linear_velocity() const {
+ return linear_velocity;
}
-Vector2 KinematicBody2D::get_floor_normal() const {
- return floor_normal;
+void CharacterBody2D::set_linear_velocity(const Vector2 &p_velocity) {
+ linear_velocity = p_velocity;
}
-Vector2 KinematicBody2D::get_floor_velocity() const {
- return floor_velocity;
+bool CharacterBody2D::is_on_floor() const {
+ return on_floor;
}
-bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia) {
- ERR_FAIL_COND_V(!is_inside_tree(), false);
+bool CharacterBody2D::is_on_wall() const {
+ return on_wall;
+}
- return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, margin);
+bool CharacterBody2D::is_on_ceiling() const {
+ return on_ceiling;
}
-void KinematicBody2D::set_safe_margin(real_t p_margin) {
- margin = p_margin;
+Vector2 CharacterBody2D::get_floor_normal() const {
+ return floor_normal;
}
-real_t KinematicBody2D::get_safe_margin() const {
- return margin;
+Vector2 CharacterBody2D::get_floor_velocity() const {
+ return floor_velocity;
}
-int KinematicBody2D::get_slide_count() const {
- return colliders.size();
+int CharacterBody2D::get_slide_count() const {
+ return motion_results.size();
}
-KinematicBody2D::Collision KinematicBody2D::get_slide_collision(int p_bounce) const {
- ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Collision());
- return colliders[p_bounce];
+PhysicsServer2D::MotionResult CharacterBody2D::get_slide_collision(int p_bounce) const {
+ ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), PhysicsServer2D::MotionResult());
+ return motion_results[p_bounce];
}
-Ref<KinematicCollision2D> KinematicBody2D::_get_slide_collision(int p_bounce) {
- ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Ref<KinematicCollision2D>());
+Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) {
+ ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), Ref<KinematicCollision2D>());
if (p_bounce >= slide_colliders.size()) {
slide_colliders.resize(p_bounce + 1);
}
@@ -1065,11 +1124,11 @@ Ref<KinematicCollision2D> KinematicBody2D::_get_slide_collision(int p_bounce) {
slide_colliders.write[p_bounce]->owner = this;
}
- slide_colliders.write[p_bounce]->collision = colliders[p_bounce];
+ slide_colliders.write[p_bounce]->result = motion_results[p_bounce];
return slide_colliders[p_bounce];
}
-void KinematicBody2D::set_sync_to_physics(bool p_enable) {
+void CharacterBody2D::set_sync_to_physics(bool p_enable) {
if (sync_to_physics == p_enable) {
return;
}
@@ -1080,26 +1139,27 @@ void KinematicBody2D::set_sync_to_physics(bool p_enable) {
}
if (p_enable) {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &CharacterBody2D::_direct_state_changed));
set_only_update_transform_changes(true);
set_notify_local_transform(true);
} else {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, "");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
set_only_update_transform_changes(false);
set_notify_local_transform(false);
}
}
-bool KinematicBody2D::is_sync_to_physics_enabled() const {
+bool CharacterBody2D::is_sync_to_physics_enabled() const {
return sync_to_physics;
}
-void KinematicBody2D::_direct_state_changed(Object *p_state) {
+void CharacterBody2D::_direct_state_changed(Object *p_state) {
if (!sync_to_physics) {
return;
}
PhysicsDirectBodyState2D *state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");
last_valid_transform = state->get_transform();
set_notify_local_transform(false);
@@ -1107,7 +1167,71 @@ void KinematicBody2D::_direct_state_changed(Object *p_state) {
set_notify_local_transform(true);
}
-void KinematicBody2D::_notification(int p_what) {
+void CharacterBody2D::set_safe_margin(real_t p_margin) {
+ margin = p_margin;
+}
+
+real_t CharacterBody2D::get_safe_margin() const {
+ return margin;
+}
+
+bool CharacterBody2D::is_stop_on_slope_enabled() const {
+ return stop_on_slope;
+}
+
+void CharacterBody2D::set_stop_on_slope_enabled(bool p_enabled) {
+ stop_on_slope = p_enabled;
+}
+
+bool CharacterBody2D::is_infinite_inertia_enabled() const {
+ return infinite_inertia;
+}
+void CharacterBody2D::set_infinite_inertia_enabled(bool p_enabled) {
+ infinite_inertia = p_enabled;
+}
+
+int CharacterBody2D::get_max_slides() const {
+ return max_slides;
+}
+
+void CharacterBody2D::set_max_slides(int p_max_slides) {
+ ERR_FAIL_COND(p_max_slides > 0);
+ max_slides = p_max_slides;
+}
+
+real_t CharacterBody2D::get_floor_max_angle() const {
+ return floor_max_angle;
+}
+
+void CharacterBody2D::set_floor_max_angle(real_t p_radians) {
+ floor_max_angle = p_radians;
+}
+
+real_t CharacterBody2D::get_floor_max_angle_degrees() const {
+ return Math::rad2deg(floor_max_angle);
+}
+
+void CharacterBody2D::set_floor_max_angle_degrees(real_t p_degrees) {
+ floor_max_angle = Math::deg2rad(p_degrees);
+}
+
+const Vector2 &CharacterBody2D::get_snap() const {
+ return snap;
+}
+
+void CharacterBody2D::set_snap(const Vector2 &p_snap) {
+ snap = p_snap;
+}
+
+const Vector2 &CharacterBody2D::get_up_direction() const {
+ return up_direction;
+}
+
+void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) {
+ up_direction = p_up_direction.normalized();
+}
+
+void CharacterBody2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
last_valid_transform = get_global_transform();
@@ -1116,7 +1240,7 @@ void KinematicBody2D::_notification(int p_what) {
on_floor_body = RID();
on_ceiling = false;
on_wall = false;
- colliders.clear();
+ motion_results.clear();
floor_velocity = Vector2();
}
@@ -1131,49 +1255,58 @@ void KinematicBody2D::_notification(int p_what) {
}
}
-void KinematicBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody2D::_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"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody2D::move_and_slide_with_snap, DEFVAL(Vector2(0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true));
-
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody2D::test_move, DEFVAL(true));
-
- ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody2D::is_on_floor);
- ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody2D::is_on_ceiling);
- ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody2D::is_on_wall);
- ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody2D::get_floor_normal);
- ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody2D::get_floor_velocity);
-
- ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody2D::set_safe_margin);
- ClassDB::bind_method(D_METHOD("get_safe_margin"), &KinematicBody2D::get_safe_margin);
+void CharacterBody2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody2D::move_and_slide);
+
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &CharacterBody2D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &CharacterBody2D::get_linear_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody2D::set_safe_margin);
+ ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin);
+ ClassDB::bind_method(D_METHOD("is_stop_on_slope_enabled"), &CharacterBody2D::is_stop_on_slope_enabled);
+ ClassDB::bind_method(D_METHOD("set_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_stop_on_slope_enabled);
+ ClassDB::bind_method(D_METHOD("is_infinite_inertia_enabled"), &CharacterBody2D::is_infinite_inertia_enabled);
+ ClassDB::bind_method(D_METHOD("set_infinite_inertia_enabled", "enabled"), &CharacterBody2D::set_infinite_inertia_enabled);
+ ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody2D::get_max_slides);
+ ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides);
+ ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody2D::get_floor_max_angle);
+ ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody2D::set_floor_max_angle);
+ ClassDB::bind_method(D_METHOD("get_floor_max_angle_degrees"), &CharacterBody2D::get_floor_max_angle_degrees);
+ ClassDB::bind_method(D_METHOD("set_floor_max_angle_degrees", "degrees"), &CharacterBody2D::set_floor_max_angle_degrees);
+ ClassDB::bind_method(D_METHOD("get_snap"), &CharacterBody2D::get_snap);
+ ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CharacterBody2D::set_snap);
+ ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody2D::get_up_direction);
+ ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_up_direction);
+
+ ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody2D::is_on_floor);
+ ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody2D::is_on_ceiling);
+ ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody2D::is_on_wall);
+ ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody2D::get_floor_normal);
+ ClassDB::bind_method(D_METHOD("get_floor_velocity"), &CharacterBody2D::get_floor_velocity);
+ ClassDB::bind_method(D_METHOD("get_slide_count"), &CharacterBody2D::get_slide_count);
+ ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody2D::_get_slide_collision);
+
+ ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &CharacterBody2D::set_sync_to_physics);
+ ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &CharacterBody2D::is_sync_to_physics_enabled);
- ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody2D::get_slide_count);
- ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody2D::_get_slide_collision);
-
- ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &KinematicBody2D::set_sync_to_physics);
- ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &KinematicBody2D::is_sync_to_physics_enabled);
-
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody2D::_direct_state_changed);
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stop_on_slope"), "set_stop_on_slope_enabled", "is_stop_on_slope_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "infinite_inertia"), "set_infinite_inertia_enabled", "is_infinite_inertia_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides"), "set_max_slides", "get_max_slides");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_floor_max_angle", "get_floor_max_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle_degrees", PROPERTY_HINT_RANGE, "0,180,0.1", PROPERTY_USAGE_EDITOR), "set_floor_max_angle_degrees", "get_floor_max_angle_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap"), "set_snap", "get_snap");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "motion/sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
}
-KinematicBody2D::KinematicBody2D() :
+CharacterBody2D::CharacterBody2D() :
PhysicsBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) {
- margin = 0.08;
-
- on_floor = false;
- on_ceiling = false;
- on_wall = false;
- sync_to_physics = false;
}
-KinematicBody2D::~KinematicBody2D() {
- if (motion_cache.is_valid()) {
- motion_cache->owner = nullptr;
- }
-
+CharacterBody2D::~CharacterBody2D() {
for (int i = 0; i < slide_colliders.size(); i++) {
if (slide_colliders[i].is_valid()) {
slide_colliders.write[i]->owner = nullptr;
@@ -1184,39 +1317,39 @@ KinematicBody2D::~KinematicBody2D() {
////////////////////////
Vector2 KinematicCollision2D::get_position() const {
- return collision.collision;
+ return result.collision_point;
}
Vector2 KinematicCollision2D::get_normal() const {
- return collision.normal;
+ return result.collision_normal;
}
Vector2 KinematicCollision2D::get_travel() const {
- return collision.travel;
+ return result.motion;
}
Vector2 KinematicCollision2D::get_remainder() const {
- return collision.remainder;
+ return result.remainder;
}
Object *KinematicCollision2D::get_local_shape() const {
if (!owner) {
return nullptr;
}
- uint32_t ownerid = owner->shape_find_owner(collision.local_shape);
+ uint32_t ownerid = owner->shape_find_owner(result.collision_local_shape);
return owner->shape_owner_get_owner(ownerid);
}
Object *KinematicCollision2D::get_collider() const {
- if (collision.collider.is_valid()) {
- return ObjectDB::get_instance(collision.collider);
+ if (result.collider_id.is_valid()) {
+ return ObjectDB::get_instance(result.collider_id);
}
return nullptr;
}
ObjectID KinematicCollision2D::get_collider_id() const {
- return collision.collider;
+ return result.collider_id;
}
Object *KinematicCollision2D::get_collider_shape() const {
@@ -1224,7 +1357,7 @@ Object *KinematicCollision2D::get_collider_shape() const {
if (collider) {
CollisionObject2D *obj2d = Object::cast_to<CollisionObject2D>(collider);
if (obj2d) {
- uint32_t ownerid = obj2d->shape_find_owner(collision.collider_shape);
+ uint32_t ownerid = obj2d->shape_find_owner(result.collider_shape);
return obj2d->shape_owner_get_owner(ownerid);
}
}
@@ -1233,11 +1366,11 @@ Object *KinematicCollision2D::get_collider_shape() const {
}
int KinematicCollision2D::get_collider_shape_index() const {
- return collision.collider_shape;
+ return result.collider_shape;
}
Vector2 KinematicCollision2D::get_collider_velocity() const {
- return collision.collider_vel;
+ return result.collider_velocity;
}
Variant KinematicCollision2D::get_collider_metadata() const {
@@ -1269,9 +1402,3 @@ void KinematicCollision2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity");
ADD_PROPERTY(PropertyInfo(Variant::NIL, "collider_metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "", "get_collider_metadata");
}
-
-KinematicCollision2D::KinematicCollision2D() {
- collision.collider_shape = 0;
- collision.local_shape = 0;
- owner = nullptr;
-}
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index e0fc0766bc..423f792132 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -42,17 +42,22 @@ class PhysicsBody2D : public CollisionObject2D {
GDCLASS(PhysicsBody2D, CollisionObject2D);
protected:
- void _notification(int p_what);
+ static void _bind_methods();
PhysicsBody2D(PhysicsServer2D::BodyMode p_mode);
- static void _bind_methods();
+ Ref<KinematicCollision2D> motion_cache;
+
+ Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.08);
public:
+ bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
+ bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08);
+
TypedArray<PhysicsBody2D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
- PhysicsBody2D();
+ virtual ~PhysicsBody2D();
};
class StaticBody2D : public PhysicsBody2D {
@@ -63,7 +68,10 @@ class StaticBody2D : public PhysicsBody2D {
Ref<PhysicsMaterial> physics_material_override;
+ bool kinematic_motion = false;
+
protected:
+ void _notification(int p_what);
static void _bind_methods();
public:
@@ -77,10 +85,14 @@ public:
real_t get_constant_angular_velocity() const;
StaticBody2D();
- ~StaticBody2D();
private:
void _reload_physics_characteristics();
+
+ void _update_kinematic_motion();
+
+ void set_kinematic_motion_enabled(bool p_enabled);
+ bool is_kinematic_motion_enabled() const;
};
class RigidBody2D : public PhysicsBody2D {
@@ -88,9 +100,9 @@ class RigidBody2D : public PhysicsBody2D {
public:
enum Mode {
- MODE_RIGID,
+ MODE_DYNAMIC,
MODE_STATIC,
- MODE_CHARACTER,
+ MODE_DYNAMIC_LOCKED,
MODE_KINEMATIC,
};
@@ -103,7 +115,7 @@ public:
private:
bool can_sleep = true;
PhysicsDirectBodyState2D *state = nullptr;
- Mode mode = MODE_RIGID;
+ Mode mode = MODE_DYNAMIC;
real_t mass = 1.0;
Ref<PhysicsMaterial> physics_material_override;
@@ -140,10 +152,12 @@ private:
}
};
struct RigidBody2D_RemoveAction {
+ RID rid;
ObjectID body_id;
ShapePair pair;
};
struct BodyState {
+ RID rid;
//int rc;
bool in_scene = false;
VSet<ShapePair> shapes;
@@ -158,11 +172,9 @@ private:
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);
+ void _body_inout(int p_status, const RID &p_body, 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, real_t p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>());
-
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -243,62 +255,73 @@ private:
VARIANT_ENUM_CAST(RigidBody2D::Mode);
VARIANT_ENUM_CAST(RigidBody2D::CCDMode);
-class KinematicBody2D : public PhysicsBody2D {
- GDCLASS(KinematicBody2D, PhysicsBody2D);
-
-public:
- struct Collision {
- Vector2 collision;
- Vector2 normal;
- Vector2 collider_vel;
- ObjectID collider;
- RID collider_rid;
- int collider_shape = 0;
- Variant collider_metadata;
- Vector2 remainder;
- Vector2 travel;
- int local_shape = 0;
- };
+class CharacterBody2D : public PhysicsBody2D {
+ GDCLASS(CharacterBody2D, PhysicsBody2D);
private:
- real_t margin;
+ real_t margin = 0.08;
+
+ bool stop_on_slope = false;
+ bool infinite_inertia = true;
+ int max_slides = 4;
+ real_t floor_max_angle = Math::deg2rad((real_t)45.0);
+ Vector2 snap;
+ Vector2 up_direction = Vector2(0.0, -1.0);
+
+ Vector2 linear_velocity;
Vector2 floor_normal;
Vector2 floor_velocity;
RID on_floor_body;
- bool on_floor;
- bool on_ceiling;
- bool on_wall;
- bool sync_to_physics;
+ bool on_floor = false;
+ bool on_ceiling = false;
+ bool on_wall = false;
+ bool sync_to_physics = false;
- Vector<Collision> colliders;
+ Vector<PhysicsServer2D::MotionResult> motion_results;
Vector<Ref<KinematicCollision2D>> slide_colliders;
- Ref<KinematicCollision2D> motion_cache;
- _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);
+ bool separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result);
+
Transform2D last_valid_transform;
void _direct_state_changed(Object *p_state);
+ void set_safe_margin(real_t p_margin);
+ real_t get_safe_margin() const;
+
+ bool is_stop_on_slope_enabled() const;
+ void set_stop_on_slope_enabled(bool p_enabled);
+
+ bool is_infinite_inertia_enabled() const;
+ void set_infinite_inertia_enabled(bool p_enabled);
+
+ int get_max_slides() const;
+ void set_max_slides(int p_max_slides);
+
+ real_t get_floor_max_angle() const;
+ void set_floor_max_angle(real_t p_radians);
+
+ real_t get_floor_max_angle_degrees() const;
+ void set_floor_max_angle_degrees(real_t p_degrees);
+
+ const Vector2 &get_snap() const;
+ void set_snap(const Vector2 &p_snap);
+
+ const Vector2 &get_up_direction() const;
+ void set_up_direction(const Vector2 &p_up_direction);
+
protected:
void _notification(int p_what);
static void _bind_methods();
public:
- bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
-
- bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia = true);
-
- bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
+ void move_and_slide();
- void set_safe_margin(real_t p_margin);
- real_t get_safe_margin() const;
+ const Vector2 &get_linear_velocity() const;
+ void set_linear_velocity(const Vector2 &p_velocity);
- Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_up_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true);
- Vector2 move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_up_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true);
bool is_on_floor() const;
bool is_on_wall() const;
bool is_on_ceiling() const;
@@ -306,21 +329,22 @@ public:
Vector2 get_floor_velocity() const;
int get_slide_count() const;
- Collision get_slide_collision(int p_bounce) const;
+ PhysicsServer2D::MotionResult get_slide_collision(int p_bounce) const;
void set_sync_to_physics(bool p_enable);
bool is_sync_to_physics_enabled() const;
- KinematicBody2D();
- ~KinematicBody2D();
+ CharacterBody2D();
+ ~CharacterBody2D();
};
-class KinematicCollision2D : public Reference {
- GDCLASS(KinematicCollision2D, Reference);
+class KinematicCollision2D : public RefCounted {
+ GDCLASS(KinematicCollision2D, RefCounted);
- KinematicBody2D *owner;
- friend class KinematicBody2D;
- KinematicBody2D::Collision collision;
+ PhysicsBody2D *owner = nullptr;
+ friend class PhysicsBody2D;
+ friend class CharacterBody2D;
+ PhysicsServer2D::MotionResult result;
protected:
static void _bind_methods();
@@ -337,8 +361,6 @@ public:
int get_collider_shape_index() const;
Vector2 get_collider_velocity() const;
Variant get_collider_metadata() const;
-
- KinematicCollision2D();
};
#endif // PHYSICS_BODY_2D_H
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 1a7038bb80..21083e6a4b 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -302,17 +302,18 @@ void Polygon2D::_notification(int p_what) {
colors.write[i] = color_r[i];
}
} else {
- colors.push_back(color);
+ colors.resize(len);
+ for (int i = 0; i < len; i++) {
+ colors.write[i] = color;
+ }
}
+ Vector<int> index_array;
+
if (invert || polygons.size() == 0) {
- Vector<int> indices = Geometry2D::triangulate_polygon(points);
- if (indices.size()) {
- 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);
- }
+ index_array = Geometry2D::triangulate_polygon(points);
} else {
//draw individual polygons
- Vector<int> total_indices;
for (int i = 0; i < polygons.size(); i++) {
Vector<int> src_indices = polygons[i];
int ic = src_indices.size();
@@ -333,18 +334,38 @@ void Polygon2D::_notification(int p_what) {
int ic2 = indices.size();
const int *r2 = indices.ptr();
- int bic = total_indices.size();
- total_indices.resize(bic + ic2);
- int *w2 = total_indices.ptrw();
+ int bic = index_array.size();
+ index_array.resize(bic + ic2);
+ int *w2 = index_array.ptrw();
for (int j = 0; j < ic2; j++) {
w2[j + bic] = r[r2[j]];
}
}
+ }
+
+ RS::get_singleton()->mesh_clear(mesh);
+
+ if (index_array.size()) {
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ arr[RS::ARRAY_VERTEX] = points;
+ if (uvs.size() == points.size()) {
+ arr[RS::ARRAY_TEX_UV] = uvs;
+ }
+ if (colors.size() == points.size()) {
+ arr[RS::ARRAY_COLOR] = colors;
+ }
- if (total_indices.size()) {
- 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());
+ if (bones.size() == points.size() * 4) {
+ arr[RS::ARRAY_BONES] = bones;
+ arr[RS::ARRAY_WEIGHTS] = weights;
}
+
+ arr[RS::ARRAY_INDEX] = index_array;
+
+ RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
+ RS::get_singleton()->canvas_item_add_mesh(get_canvas_item(), mesh, Transform2D(), Color(), texture.is_valid() ? texture->get_rid() : RID());
}
} break;
@@ -655,4 +676,9 @@ void Polygon2D::_bind_methods() {
}
Polygon2D::Polygon2D() {
+ mesh = RS::get_singleton()->mesh_create();
+}
+
+Polygon2D::~Polygon2D() {
+ RS::get_singleton()->free(mesh);
}
diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h
index c207024a53..f9f36ff9a2 100644
--- a/scene/2d/polygon_2d.h
+++ b/scene/2d/polygon_2d.h
@@ -72,6 +72,8 @@ class Polygon2D : public Node2D {
void _skeleton_bone_setup_changed();
+ RID mesh;
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -149,6 +151,7 @@ public:
NodePath get_skeleton() const;
Polygon2D();
+ ~Polygon2D();
};
#endif // POLYGON_2D_H
diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp
index 5c7d65e3e0..1019f85c8a 100644
--- a/scene/2d/position_2d.cpp
+++ b/scene/2d/position_2d.cpp
@@ -36,10 +36,41 @@
const real_t DEFAULT_GIZMO_EXTENTS = 10.0;
void Position2D::_draw_cross() {
- real_t extents = get_gizmo_extents();
- // Colors taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`)
- draw_line(Point2(-extents, 0), Point2(+extents, 0), Color(0.96, 0.20, 0.32));
- draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.53, 0.84, 0.01));
+ const real_t extents = get_gizmo_extents();
+
+ // Add more points to create a "hard stop" in the color gradient.
+ PackedVector2Array points_x;
+ points_x.push_back(Point2(+extents, 0));
+ points_x.push_back(Point2());
+ points_x.push_back(Point2());
+ points_x.push_back(Point2(-extents, 0));
+
+ PackedVector2Array points_y;
+ points_y.push_back(Point2(0, +extents));
+ points_y.push_back(Point2());
+ points_y.push_back(Point2());
+ points_y.push_back(Point2(0, -extents));
+
+ // Use the axis color which is brighter for the positive axis.
+ // Use a darkened axis color for the negative axis.
+ // This makes it possible to see in which direction the Position3D node is rotated
+ // (which can be important depending on how it's used).
+ // Axis colors are taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`).
+ PackedColorArray colors_x;
+ const Color color_x = Color(0.96, 0.20, 0.32);
+ colors_x.push_back(color_x);
+ colors_x.push_back(color_x);
+ colors_x.push_back(color_x.lerp(Color(0, 0, 0), 0.5));
+ colors_x.push_back(color_x.lerp(Color(0, 0, 0), 0.5));
+ draw_multiline_colors(points_x, colors_x);
+
+ PackedColorArray colors_y;
+ const Color color_y = Color(0.53, 0.84, 0.01);
+ colors_y.push_back(color_y);
+ colors_y.push_back(color_y);
+ colors_y.push_back(color_y.lerp(Color(0, 0, 0), 0.5));
+ colors_y.push_back(color_y.lerp(Color(0, 0, 0), 0.5));
+ draw_multiline_colors(points_y, colors_y);
}
#ifdef TOOLS_ENABLED
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 50625a0f39..f6740040c1 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -55,6 +55,7 @@ uint32_t RayCast2D::get_collision_mask() const {
}
void RayCast2D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -65,6 +66,7 @@ void RayCast2D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool RayCast2D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 22180797f0..8f1f5fadbc 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -30,6 +30,69 @@
#include "skeleton_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#include "editor/plugins/canvas_item_editor_plugin.h"
+#endif //TOOLS_ENABLED
+
+bool Bone2D::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+ if (path.begins_with("auto_calculate_length_and_angle")) {
+ set_autocalculate_length_and_angle(p_value);
+ } else if (path.begins_with("length")) {
+ set_length(p_value);
+ } else if (path.begins_with("bone_angle")) {
+ set_bone_angle(Math::deg2rad(float(p_value)));
+ } else if (path.begins_with("default_length")) {
+ set_length(p_value);
+ }
+
+#ifdef TOOLS_ENABLED
+ if (path.begins_with("editor_settings/show_bone_gizmo")) {
+ _editor_set_show_bone_gizmo(p_value);
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+}
+
+bool Bone2D::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path.begins_with("auto_calculate_length_and_angle")) {
+ r_ret = get_autocalculate_length_and_angle();
+ } else if (path.begins_with("length")) {
+ r_ret = get_length();
+ } else if (path.begins_with("bone_angle")) {
+ r_ret = Math::rad2deg(get_bone_angle());
+ } else if (path.begins_with("default_length")) {
+ r_ret = get_length();
+ }
+
+#ifdef TOOLS_ENABLED
+ if (path.begins_with("editor_settings/show_bone_gizmo")) {
+ r_ret = _editor_get_show_bone_gizmo();
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+}
+
+void Bone2D::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "auto_calculate_length_and_angle", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ if (!autocalculate_length_and_angle) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1, 1024, 1", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "bone_angle", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
+ }
+
+#ifdef TOOLS_ENABLED
+ p_list->push_back(PropertyInfo(Variant::BOOL, "editor_settings/show_bone_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+#endif // TOOLS_ENABLED
+}
+
void Bone2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
Node *parent = get_parent();
@@ -53,19 +116,54 @@ void Bone2D::_notification(int p_what) {
skeleton->bones.push_back(bone);
skeleton->_make_bone_setup_dirty();
}
+
+ cache_transform = get_transform();
+ copy_transform_to_cache = true;
+
+#ifdef TOOLS_ENABLED
+ // Only draw the gizmo in the editor!
+ if (Engine::get_singleton()->is_editor_hint() == false) {
+ return;
+ }
+
+ update();
+#endif // TOOLS_ENABLED
}
- if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
+
+ else if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (skeleton) {
skeleton->_make_transform_dirty();
}
+ if (copy_transform_to_cache) {
+ cache_transform = get_transform();
+ }
+#ifdef TOOLS_ENABLED
+ // Only draw the gizmo in the editor!
+ if (Engine::get_singleton()->is_editor_hint() == false) {
+ return;
+ }
+
+ update();
+
+ if (get_parent()) {
+ Bone2D *parent_bone = Object::cast_to<Bone2D>(get_parent());
+ if (parent_bone) {
+ parent_bone->update();
+ }
+ }
+#endif // TOOLS_ENABLED
}
- if (p_what == NOTIFICATION_MOVED_IN_PARENT) {
+
+ else if (p_what == NOTIFICATION_MOVED_IN_PARENT) {
if (skeleton) {
skeleton->_make_bone_setup_dirty();
}
+ if (copy_transform_to_cache) {
+ cache_transform = get_transform();
+ }
}
- if (p_what == NOTIFICATION_EXIT_TREE) {
+ else if (p_what == NOTIFICATION_EXIT_TREE) {
if (skeleton) {
for (int i = 0; i < skeleton->bones.size(); i++) {
if (skeleton->bones[i].bone == this) {
@@ -77,9 +175,200 @@ void Bone2D::_notification(int p_what) {
skeleton = nullptr;
}
parent_bone = nullptr;
+ set_transform(cache_transform);
}
+
+ else if (p_what == NOTIFICATION_READY) {
+ if (autocalculate_length_and_angle) {
+ calculate_length_and_rotation();
+ }
+ }
+#ifdef TOOLS_ENABLED
+ else if (p_what == NOTIFICATION_EDITOR_PRE_SAVE || p_what == NOTIFICATION_EDITOR_POST_SAVE) {
+ Transform2D tmp_trans = get_transform();
+ set_transform(cache_transform);
+ cache_transform = tmp_trans;
+ }
+ // Bone2D Editor gizmo drawing:
+#ifndef _MSC_VER
+#warning TODO Bone2D gizmo drawing needs to be moved to an editor plugin
+#endif
+ else if (p_what == NOTIFICATION_DRAW) {
+ // Only draw the gizmo in the editor!
+ if (Engine::get_singleton()->is_editor_hint() == false) {
+ return;
+ }
+
+ if (editor_gizmo_rid.is_null()) {
+ editor_gizmo_rid = RenderingServer::get_singleton()->canvas_item_create();
+ RenderingServer::get_singleton()->canvas_item_set_parent(editor_gizmo_rid, get_canvas_item());
+ RenderingServer::get_singleton()->canvas_item_set_z_as_relative_to_parent(editor_gizmo_rid, true);
+ RenderingServer::get_singleton()->canvas_item_set_z_index(editor_gizmo_rid, 10);
+ }
+ RenderingServer::get_singleton()->canvas_item_clear(editor_gizmo_rid);
+
+ if (!_editor_show_bone_gizmo) {
+ return;
+ }
+
+ // Undo scaling
+ Transform2D editor_gizmo_trans = Transform2D();
+ editor_gizmo_trans.set_scale(Vector2(1, 1) / get_global_scale());
+ RenderingServer::get_singleton()->canvas_item_set_transform(editor_gizmo_rid, editor_gizmo_trans);
+
+ Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1");
+ Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2");
+ Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
+ Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color");
+ Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color");
+
+ bool Bone2D_found = false;
+ for (int i = 0; i < get_child_count(); i++) {
+ Bone2D *child_node = nullptr;
+ child_node = Object::cast_to<Bone2D>(get_child(i));
+ if (!child_node) {
+ continue;
+ }
+ Bone2D_found = true;
+
+ Vector<Vector2> bone_shape;
+ Vector<Vector2> bone_shape_outline;
+
+ _editor_get_bone_shape(&bone_shape, &bone_shape_outline, child_node);
+
+ Vector<Color> colors;
+ if (has_meta("_local_pose_override_enabled_")) {
+ colors.push_back(bone_ik_color);
+ colors.push_back(bone_ik_color);
+ colors.push_back(bone_ik_color);
+ colors.push_back(bone_ik_color);
+ } else {
+ colors.push_back(bone_color1);
+ colors.push_back(bone_color2);
+ colors.push_back(bone_color1);
+ colors.push_back(bone_color2);
+ }
+
+ Vector<Color> outline_colors;
+ if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) {
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ } else {
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ }
+
+ RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors);
+ RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors);
+ }
+
+ if (!Bone2D_found) {
+ Vector<Vector2> bone_shape;
+ Vector<Vector2> bone_shape_outline;
+
+ _editor_get_bone_shape(&bone_shape, &bone_shape_outline, nullptr);
+
+ Vector<Color> colors;
+ if (has_meta("_local_pose_override_enabled_")) {
+ colors.push_back(bone_ik_color);
+ colors.push_back(bone_ik_color);
+ colors.push_back(bone_ik_color);
+ colors.push_back(bone_ik_color);
+ } else {
+ colors.push_back(bone_color1);
+ colors.push_back(bone_color2);
+ colors.push_back(bone_color1);
+ colors.push_back(bone_color2);
+ }
+
+ Vector<Color> outline_colors;
+ if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) {
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ outline_colors.push_back(bone_selected_color);
+ } else {
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ outline_colors.push_back(bone_outline_color);
+ }
+
+ RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors);
+ RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors);
+ }
+ }
+#endif // TOOLS_ENALBED
}
+#ifdef TOOLS_ENABLED
+bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p_outline_shape, Bone2D *p_other_bone) {
+ int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width");
+ int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size");
+
+ if (!is_inside_tree()) {
+ return false; //may have been removed
+ }
+ if (!p_other_bone && length <= 0) {
+ return false;
+ }
+
+ Vector2 rel;
+ if (p_other_bone) {
+ rel = (p_other_bone->get_global_transform().get_origin() - get_global_transform().get_origin());
+ rel = rel.rotated(-get_global_rotation()); // Undo Bone2D node's rotation so its drawn correctly regardless of the node's rotation
+ } else {
+ float angle_to_use = get_rotation() + bone_angle;
+ rel = Vector2(cos(angle_to_use), sin(angle_to_use)) * (length * MIN(get_global_scale().x, get_global_scale().y));
+ rel = rel.rotated(-get_rotation()); // Undo Bone2D node's rotation so its drawn correctly regardless of the node's rotation
+ }
+
+ Vector2 relt = rel.rotated(Math_PI * 0.5).normalized() * bone_width;
+ Vector2 reln = rel.normalized();
+ Vector2 reltn = relt.normalized();
+
+ if (p_shape) {
+ p_shape->clear();
+ p_shape->push_back(Vector2(0, 0));
+ p_shape->push_back(rel * 0.2 + relt);
+ p_shape->push_back(rel);
+ p_shape->push_back(rel * 0.2 - relt);
+ }
+
+ if (p_outline_shape) {
+ p_outline_shape->clear();
+ p_outline_shape->push_back((-reln - reltn) * bone_outline_width);
+ p_outline_shape->push_back((-reln + reltn) * bone_outline_width);
+ p_outline_shape->push_back(rel * 0.2 + relt + reltn * bone_outline_width);
+ p_outline_shape->push_back(rel + (reln + reltn) * bone_outline_width);
+ p_outline_shape->push_back(rel + (reln - reltn) * bone_outline_width);
+ p_outline_shape->push_back(rel * 0.2 - relt - reltn * bone_outline_width);
+ }
+ return true;
+}
+
+void Bone2D::_editor_set_show_bone_gizmo(bool p_show_gizmo) {
+ _editor_show_bone_gizmo = p_show_gizmo;
+ update();
+}
+
+bool Bone2D::_editor_get_show_bone_gizmo() const {
+ return _editor_show_bone_gizmo;
+}
+#endif // TOOLS_ENABLED
+
void Bone2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rest", "rest"), &Bone2D::set_rest);
ClassDB::bind_method(D_METHOD("get_rest"), &Bone2D::get_rest);
@@ -90,8 +379,14 @@ void Bone2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_length", "default_length"), &Bone2D::set_default_length);
ClassDB::bind_method(D_METHOD("get_default_length"), &Bone2D::get_default_length);
+ ClassDB::bind_method(D_METHOD("set_autocalculate_length_and_angle", "auto_calculate"), &Bone2D::set_autocalculate_length_and_angle);
+ ClassDB::bind_method(D_METHOD("get_autocalculate_length_and_angle"), &Bone2D::get_autocalculate_length_and_angle);
+ ClassDB::bind_method(D_METHOD("set_length", "length"), &Bone2D::set_length);
+ ClassDB::bind_method(D_METHOD("get_length"), &Bone2D::get_length);
+ ClassDB::bind_method(D_METHOD("set_bone_angle", "angle"), &Bone2D::set_bone_angle);
+ ClassDB::bind_method(D_METHOD("get_bone_angle"), &Bone2D::get_bone_angle);
+
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "rest"), "set_rest", "get_rest");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_length", PROPERTY_HINT_RANGE, "1,1024,1"), "set_default_length", "get_default_length");
}
void Bone2D::set_rest(const Transform2D &p_rest) {
@@ -119,12 +414,14 @@ void Bone2D::apply_rest() {
set_transform(rest);
}
-void Bone2D::set_default_length(real_t p_length) {
- default_length = p_length;
+void Bone2D::set_default_length(float p_length) {
+ WARN_DEPRECATED_MSG("set_default_length is deprecated. Please use set_length instead!");
+ set_length(p_length);
}
-real_t Bone2D::get_default_length() const {
- return default_length;
+float Bone2D::get_default_length() const {
+ WARN_DEPRECATED_MSG("get_default_length is deprecated. Please use get_length instead!");
+ return get_length();
}
int Bone2D::get_index_in_skeleton() const {
@@ -150,16 +447,121 @@ TypedArray<String> Bone2D::get_configuration_warnings() const {
return warnings;
}
+void Bone2D::calculate_length_and_rotation() {
+ // if there is at least a single child Bone2D node, we can calculate
+ // the length and direction. We will always just use the first Bone2D for this.
+ bool calculated = false;
+ int child_count = get_child_count();
+ if (child_count > 0) {
+ for (int i = 0; i < child_count; i++) {
+ Bone2D *child = Object::cast_to<Bone2D>(get_child(i));
+ if (child) {
+ Vector2 child_local_pos = to_local(child->get_global_transform().get_origin());
+ length = child_local_pos.length();
+ bone_angle = Math::atan2(child_local_pos.normalized().y, child_local_pos.normalized().x);
+ calculated = true;
+ break;
+ }
+ }
+ }
+ if (calculated) {
+ return; // Finished!
+ } else {
+ WARN_PRINT("No Bone2D children of node " + get_name() + ". Cannot calculate bone length or angle reliably.\nUsing transform rotation for bone angle");
+ bone_angle = get_transform().get_rotation();
+ return;
+ }
+}
+
+void Bone2D::set_autocalculate_length_and_angle(bool p_autocalculate) {
+ autocalculate_length_and_angle = p_autocalculate;
+ if (autocalculate_length_and_angle) {
+ calculate_length_and_rotation();
+ }
+ notify_property_list_changed();
+}
+
+bool Bone2D::get_autocalculate_length_and_angle() const {
+ return autocalculate_length_and_angle;
+}
+
+void Bone2D::set_length(float p_length) {
+ length = p_length;
+
+#ifdef TOOLS_ENABLED
+ update();
+#endif // TOOLS_ENABLED
+}
+
+float Bone2D::get_length() const {
+ return length;
+}
+
+void Bone2D::set_bone_angle(float p_angle) {
+ bone_angle = p_angle;
+
+#ifdef TOOLS_ENABLED
+ update();
+#endif // TOOLS_ENABLED
+}
+
+float Bone2D::get_bone_angle() const {
+ return bone_angle;
+}
+
Bone2D::Bone2D() {
+ skeleton = nullptr;
+ parent_bone = nullptr;
+ skeleton_index = -1;
+ length = 16;
+ bone_angle = 0;
+ autocalculate_length_and_angle = true;
set_notify_local_transform(true);
//this is a clever hack so the bone knows no rest has been set yet, allowing to show an error.
for (int i = 0; i < 3; i++) {
rest[i] = Vector2(0, 0);
}
+ copy_transform_to_cache = true;
+}
+
+Bone2D::~Bone2D() {
+#ifdef TOOLS_ENABLED
+ if (!editor_gizmo_rid.is_null()) {
+ RenderingServer::get_singleton()->free(editor_gizmo_rid);
+ }
+#endif // TOOLS_ENABLED
}
//////////////////////////////////////
+bool Skeleton2D::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+ if (path.begins_with("modification_stack")) {
+ set_modification_stack(p_value);
+ return true;
+ }
+ return true;
+}
+
+bool Skeleton2D::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path.begins_with("modification_stack")) {
+ r_ret = get_modification_stack();
+ return true;
+ }
+ return true;
+}
+
+void Skeleton2D::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(
+ PropertyInfo(Variant::OBJECT, "modification_stack",
+ PROPERTY_HINT_RESOURCE_TYPE,
+ "SkeletonModificationStack2D",
+ PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+}
+
void Skeleton2D::_make_bone_setup_dirty() {
if (bone_setup_dirty) {
return;
@@ -189,6 +591,8 @@ void Skeleton2D::_update_bone_setup() {
} else {
bones.write[i].parent_index = -1;
}
+
+ bones.write[i].local_pose_override = bones[i].bone->get_skeleton_rest();
}
transform_dirty = true;
@@ -257,19 +661,121 @@ void Skeleton2D::_notification(int p_what) {
if (transform_dirty) {
_update_transform();
}
-
request_ready();
}
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
RS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform());
+ } else if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+ if (modification_stack.is_valid()) {
+ execute_modifications(get_process_delta_time(), SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_process);
+ }
+ } else if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
+ if (modification_stack.is_valid()) {
+ execute_modifications(get_physics_process_delta_time(), SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_physics_process);
+ }
}
+#ifdef TOOLS_ENABLED
+ else if (p_what == NOTIFICATION_DRAW) {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (modification_stack.is_valid()) {
+ modification_stack->draw_editor_gizmos();
+ }
+ }
+ }
+#endif // TOOLS_ENABLED
}
RID Skeleton2D::get_skeleton() const {
return skeleton;
}
+void Skeleton2D::set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, float p_amount, bool p_persistent) {
+ ERR_FAIL_INDEX_MSG(p_bone_idx, bones.size(), "Bone index is out of range!");
+ bones.write[p_bone_idx].local_pose_override = p_override;
+ bones.write[p_bone_idx].local_pose_override_amount = p_amount;
+ bones.write[p_bone_idx].local_pose_override_persistent = p_persistent;
+}
+
+Transform2D Skeleton2D::get_bone_local_pose_override(int p_bone_idx) {
+ ERR_FAIL_INDEX_V_MSG(p_bone_idx, bones.size(), Transform2D(), "Bone index is out of range!");
+ return bones[p_bone_idx].local_pose_override;
+}
+
+void Skeleton2D::set_modification_stack(Ref<SkeletonModificationStack2D> p_stack) {
+ if (modification_stack.is_valid()) {
+ modification_stack->is_setup = false;
+ modification_stack->set_skeleton(nullptr);
+
+ set_process_internal(false);
+ set_physics_process_internal(false);
+ }
+ modification_stack = p_stack;
+ if (modification_stack.is_valid()) {
+ modification_stack->set_skeleton(this);
+ modification_stack->setup();
+
+ set_process_internal(true);
+ set_physics_process_internal(true);
+
+#ifdef TOOLS_ENABLED
+ modification_stack->set_editor_gizmos_dirty(true);
+#endif // TOOLS_ENABLED
+ }
+}
+
+Ref<SkeletonModificationStack2D> Skeleton2D::get_modification_stack() const {
+ return modification_stack;
+}
+
+void Skeleton2D::execute_modifications(float p_delta, int p_execution_mode) {
+ if (!modification_stack.is_valid()) {
+ return;
+ }
+
+ // Do not cache the transform changes caused by the modifications!
+ for (int i = 0; i < bones.size(); i++) {
+ bones[i].bone->copy_transform_to_cache = false;
+ }
+
+ if (modification_stack->skeleton != this) {
+ modification_stack->set_skeleton(this);
+ }
+
+ modification_stack->execute(p_delta, p_execution_mode);
+
+ // Only apply the local pose override on _process. Otherwise, just calculate the local_pose_override and reset the transform.
+ if (p_execution_mode == SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_process) {
+ for (int i = 0; i < bones.size(); i++) {
+ if (bones[i].local_pose_override_amount > 0) {
+ bones[i].bone->set_meta("_local_pose_override_enabled_", true);
+
+ Transform2D final_trans = bones[i].bone->cache_transform;
+ final_trans = final_trans.interpolate_with(bones[i].local_pose_override, bones[i].local_pose_override_amount);
+ bones[i].bone->set_transform(final_trans);
+ bones[i].bone->propagate_call("force_update_transform");
+
+ if (bones[i].local_pose_override_persistent) {
+ bones.write[i].local_pose_override_amount = 0.0;
+ }
+ } else {
+ // TODO: see if there is a way to undo the override without having to resort to setting every bone's transform.
+ bones[i].bone->remove_meta("_local_pose_override_enabled_");
+ bones[i].bone->set_transform(bones[i].bone->cache_transform);
+ }
+ }
+ }
+
+ // Cache any future transform changes
+ for (int i = 0; i < bones.size(); i++) {
+ bones[i].bone->copy_transform_to_cache = true;
+ }
+
+#ifdef TOOLS_ENABLED
+ modification_stack->set_editor_gizmos_dirty(true);
+#endif // TOOLS_ENABLED
+}
+
void Skeleton2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_bone_setup"), &Skeleton2D::_update_bone_setup);
ClassDB::bind_method(D_METHOD("_update_transform"), &Skeleton2D::_update_transform);
@@ -279,6 +785,13 @@ void Skeleton2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_skeleton"), &Skeleton2D::get_skeleton);
+ ClassDB::bind_method(D_METHOD("set_modification_stack", "modification_stack"), &Skeleton2D::set_modification_stack);
+ ClassDB::bind_method(D_METHOD("get_modification_stack"), &Skeleton2D::get_modification_stack);
+ ClassDB::bind_method(D_METHOD("execute_modifications", "delta", "execution_mode"), &Skeleton2D::execute_modifications);
+
+ ClassDB::bind_method(D_METHOD("set_bone_local_pose_override", "bone_idx", "override_pose", "strength", "persistent"), &Skeleton2D::set_bone_local_pose_override);
+ ClassDB::bind_method(D_METHOD("get_bone_local_pose_override", "bone_idx"), &Skeleton2D::get_bone_local_pose_override);
+
ADD_SIGNAL(MethodInfo("bone_setup_changed"));
}
diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h
index fd62b87bde..59bd711960 100644
--- a/scene/2d/skeleton_2d.h
+++ b/scene/2d/skeleton_2d.h
@@ -32,6 +32,7 @@
#define SKELETON_2D_H
#include "scene/2d/node_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
class Skeleton2D;
@@ -46,15 +47,32 @@ class Bone2D : public Node2D {
Bone2D *parent_bone = nullptr;
Skeleton2D *skeleton = nullptr;
Transform2D rest;
- real_t default_length = 16.0;
+
+ bool autocalculate_length_and_angle = true;
+ float length = 16;
+ float bone_angle = 0;
int skeleton_index = -1;
+ void calculate_length_and_rotation();
+
+#ifdef TOOLS_ENABLED
+ RID editor_gizmo_rid;
+ bool _editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p_outline_shape, Bone2D *p_other_bone);
+ bool _editor_show_bone_gizmo = true;
+#endif // TOOLS ENABLED
+
protected:
void _notification(int p_what);
static void _bind_methods();
+ bool _set(const StringName &p_path, const Variant &p_value);
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
public:
+ Transform2D cache_transform;
+ bool copy_transform_to_cache = true;
+
void set_rest(const Transform2D &p_rest);
Transform2D get_rest() const;
void apply_rest();
@@ -65,11 +83,26 @@ public:
void set_default_length(real_t p_length);
real_t get_default_length() const;
+ void set_autocalculate_length_and_angle(bool p_autocalculate);
+ bool get_autocalculate_length_and_angle() const;
+ void set_length(float p_length);
+ float get_length() const;
+ void set_bone_angle(float p_angle);
+ float get_bone_angle() const;
+
int get_index_in_skeleton() const;
+#ifdef TOOLS_ENABLED
+ void _editor_set_show_bone_gizmo(bool p_show_gizmo);
+ bool _editor_get_show_bone_gizmo() const;
+#endif // TOOLS_ENABLED
+
Bone2D();
+ ~Bone2D();
};
+class SkeletonModificationStack2D;
+
class Skeleton2D : public Node2D {
GDCLASS(Skeleton2D, Node2D);
@@ -86,6 +119,11 @@ class Skeleton2D : public Node2D {
int parent_index = 0;
Transform2D accum_transform;
Transform2D rest_inverse;
+
+ //Transform2D local_pose_cache;
+ Transform2D local_pose_override;
+ float local_pose_override_amount = 0;
+ bool local_pose_override_persistent = false;
};
Vector<Bone> bones;
@@ -100,15 +138,28 @@ class Skeleton2D : public Node2D {
RID skeleton;
+ Ref<SkeletonModificationStack2D> modification_stack;
+
protected:
void _notification(int p_what);
static void _bind_methods();
+ bool _set(const StringName &p_path, const Variant &p_value);
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
public:
int get_bone_count() const;
Bone2D *get_bone(int p_idx);
RID get_skeleton() const;
+
+ void set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, float p_amount, bool p_persistent = true);
+ Transform2D get_bone_local_pose_override(int p_bone_idx);
+
+ Ref<SkeletonModificationStack2D> get_modification_stack() const;
+ void set_modification_stack(Ref<SkeletonModificationStack2D> p_stack);
+ void execute_modifications(float p_delta, int p_execution_mode);
+
Skeleton2D();
~Skeleton2D();
};
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index 7c93edbff9..40e0f4523f 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -153,7 +153,7 @@ void Sprite2D::set_texture(const Ref<Texture2D> &p_texture) {
}
update();
- emit_signal("texture_changed");
+ emit_signal(SceneStringNames::get_singleton()->texture_changed);
item_rect_changed();
}
@@ -254,15 +254,15 @@ 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);
+void Sprite2D::set_frame_coords(const Vector2i &p_coord) {
+ ERR_FAIL_INDEX(p_coord.x, hframes);
+ ERR_FAIL_INDEX(p_coord.y, vframes);
- set_frame(int(p_coord.y) * hframes + int(p_coord.x));
+ set_frame(p_coord.y * hframes + p_coord.x);
}
-Vector2 Sprite2D::get_frame_coords() const {
- return Vector2(frame % hframes, frame / hframes);
+Vector2i Sprite2D::get_frame_coords() const {
+ return Vector2i(frame % hframes, frame / hframes);
}
void Sprite2D::set_vframes(int p_amount) {
@@ -452,7 +452,7 @@ void Sprite2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
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_PROPERTY(PropertyInfo(Variant::VECTOR2I, "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_enabled", "is_region_enabled");
diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h
index 9db74cfe26..49df78c59d 100644
--- a/scene/2d/sprite_2d.h
+++ b/scene/2d/sprite_2d.h
@@ -109,8 +109,8 @@ public:
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_frame_coords(const Vector2i &p_coord);
+ Vector2i get_frame_coords() const;
void set_vframes(int p_amount);
int get_vframes() const;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 776d3bca5f..e39c8841cd 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -30,258 +30,314 @@
#include "tile_map.h"
-#include "collision_object_2d.h"
#include "core/io/marshalls.h"
+#include "core/math/geometry_2d.h"
#include "core/os/os.h"
-#include "scene/2d/area_2d.h"
-#include "servers/navigation_server_2d.h"
-#include "servers/physics_server_2d.h"
-int TileMap::_get_quadrant_size() const {
- if (use_y_sort) {
- return 1;
- } else {
- return quadrant_size;
- }
+void TileMapPattern::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
+ ERR_FAIL_COND_MSG(p_coords.x < 0 || p_coords.y < 0, vformat("Cannot set cell with negative coords in a TileMapPattern. Wrong coords: %s", p_coords));
+
+ size = size.max(p_coords + Vector2i(1, 1));
+ pattern[p_coords] = TileMapCell(p_source_id, p_atlas_coords, p_alternative_tile);
}
-void TileMap::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- if (use_parent) {
- _clear_quadrants();
- collision_parent = Object::cast_to<CollisionObject2D>(get_parent());
- }
+bool TileMapPattern::has_cell(const Vector2i &p_coords) const {
+ return pattern.has(p_coords);
+}
- pending_update = true;
- _recreate_quadrants();
- update_dirty_quadrants();
- RID space = get_world_2d()->get_space();
- _update_quadrant_transform();
- _update_quadrant_space(space);
- update_configuration_warnings();
+void TileMapPattern::remove_cell(const Vector2i &p_coords, bool p_update_size) {
+ ERR_FAIL_COND(!pattern.has(p_coords));
- } break;
+ pattern.erase(p_coords);
+ if (p_update_size) {
+ size = Vector2i();
+ for (Map<Vector2i, TileMapCell>::Element *E = pattern.front(); E; E = E->next()) {
+ size = size.max(E->key() + Vector2i(1, 1));
+ }
+ }
+}
- case NOTIFICATION_EXIT_TREE: {
- _update_quadrant_space(RID());
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- Quadrant &q = E->get();
- for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) {
- NavigationServer2D::get_singleton()->region_set_map(F->get().region, RID());
- }
- q.navpoly_ids.clear();
+int TileMapPattern::get_cell_source_id(const Vector2i &p_coords) const {
+ ERR_FAIL_COND_V(!pattern.has(p_coords), -1);
- if (collision_parent) {
- collision_parent->remove_shape_owner(q.shape_owner_id);
- q.shape_owner_id = -1;
- }
+ return pattern[p_coords].source_id;
+}
- for (Map<PosKey, Quadrant::Occluder>::Element *F = q.occluder_instances.front(); F; F = F->next()) {
- RS::get_singleton()->free(F->get().id);
- }
- q.occluder_instances.clear();
- }
+Vector2i TileMapPattern::get_cell_atlas_coords(const Vector2i &p_coords) const {
+ ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_ATLAS_COORDS);
- collision_parent = nullptr;
- } break;
+ return pattern[p_coords].get_atlas_coords();
+}
- case NOTIFICATION_TRANSFORM_CHANGED: {
- //move stuff
- _update_quadrant_transform();
+int TileMapPattern::get_cell_alternative_tile(const Vector2i &p_coords) const {
+ ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_TILE_ALTERNATIVE);
- } break;
- case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- if (use_parent) {
- _recreate_quadrants();
- }
+ return pattern[p_coords].alternative_tile;
+}
- } break;
+TypedArray<Vector2i> TileMapPattern::get_used_cells() const {
+ // Returns the cells used in the tilemap.
+ TypedArray<Vector2i> a;
+ a.resize(pattern.size());
+ int i = 0;
+ for (Map<Vector2i, TileMapCell>::Element *E = pattern.front(); E; E = E->next()) {
+ Vector2i p(E->key().x, E->key().y);
+ a[i++] = p;
}
+
+ return a;
}
-void TileMap::_update_quadrant_space(const RID &p_space) {
- if (!use_parent) {
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- Quadrant &q = E->get();
- PhysicsServer2D::get_singleton()->body_set_space(q.body, p_space);
- }
- }
+Vector2i TileMapPattern::get_size() const {
+ return size;
}
-void TileMap::_update_quadrant_transform() {
- if (!is_inside_tree()) {
- return;
+void TileMapPattern::set_size(const Vector2i &p_size) {
+ for (Map<Vector2i, TileMapCell>::Element *E = pattern.front(); E; E = E->next()) {
+ Vector2i coords = E->key();
+ if (p_size.x <= coords.x || p_size.y <= coords.y) {
+ ERR_FAIL_MSG(vformat("Cannot set pattern size to %s, it contains a tile at %s. Size can only be increased.", p_size, coords));
+ };
}
- Transform2D global_transform = get_global_transform();
-
- Transform2D local_transform;
- if (collision_parent) {
- local_transform = get_transform();
- }
+ size = p_size;
+}
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- Quadrant &q = E->get();
- Transform2D xform;
- xform.set_origin(q.pos);
+bool TileMapPattern::is_empty() const {
+ return pattern.is_empty();
+};
- if (!use_parent) {
- xform = global_transform * xform;
- PhysicsServer2D::get_singleton()->body_set_state(q.body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
- }
+void TileMapPattern::clear() {
+ size = Vector2i();
+ pattern.clear();
+};
- if (bake_navigation) {
- for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) {
- NavigationServer2D::get_singleton()->region_set_transform(F->get().region, F->get().xform);
- }
- }
+void TileMapPattern::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapPattern::set_cell, DEFVAL(-1), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE));
+ ClassDB::bind_method(D_METHOD("has_cell", "coords"), &TileMapPattern::has_cell);
+ ClassDB::bind_method(D_METHOD("remove_cell", "coords"), &TileMapPattern::remove_cell);
+ ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMapPattern::get_cell_source_id);
+ ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "coords"), &TileMapPattern::get_cell_atlas_coords);
+ ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "coords"), &TileMapPattern::get_cell_alternative_tile);
- for (Map<PosKey, Quadrant::Occluder>::Element *F = q.occluder_instances.front(); F; F = F->next()) {
- RS::get_singleton()->canvas_light_occluder_set_transform(F->get().id, global_transform * F->get().xform);
- }
- }
+ ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMapPattern::get_used_cells);
+ ClassDB::bind_method(D_METHOD("get_size"), &TileMapPattern::get_size);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &TileMapPattern::set_size);
+ ClassDB::bind_method(D_METHOD("is_empty"), &TileMapPattern::is_empty);
}
-void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
- if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileMap::_recreate_quadrants));
+Vector2i TileMap::transform_coords_layout(Vector2i p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout) {
+ // Transform to stacked layout.
+ Vector2i output = p_coords;
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
+ SWAP(output.x, output.y);
+ }
+ switch (p_from_layout) {
+ case TileSet::TILE_LAYOUT_STACKED:
+ break;
+ case TileSet::TILE_LAYOUT_STACKED_OFFSET:
+ if (output.y % 2) {
+ output.x -= 1;
+ }
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
+ case TileSet::TILE_LAYOUT_STAIRS_DOWN:
+ if ((p_from_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
+ if (output.y < 0 && bool(output.y % 2)) {
+ output = Vector2i(output.x + output.y / 2 - 1, output.y);
+ } else {
+ output = Vector2i(output.x + output.y / 2, output.y);
+ }
+ } else {
+ if (output.x < 0 && bool(output.x % 2)) {
+ output = Vector2i(output.x / 2 - 1, output.x + output.y * 2);
+ } else {
+ output = Vector2i(output.x / 2, output.x + output.y * 2);
+ }
+ }
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
+ case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
+ if ((p_from_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
+ if ((output.x + output.y) < 0 && (output.x - output.y) % 2) {
+ output = Vector2i((output.x + output.y) / 2 - 1, output.y - output.x);
+ } else {
+ output = Vector2i((output.x + output.y) / 2, -output.x + output.y);
+ }
+ } else {
+ if ((output.x - output.y) < 0 && (output.x + output.y) % 2) {
+ output = Vector2i((output.x - output.y) / 2 - 1, output.x + output.y);
+ } else {
+ output = Vector2i((output.x - output.y) / 2, output.x + output.y);
+ }
+ }
+ break;
}
- _clear_quadrants();
- tile_set = p_tileset;
+ switch (p_to_layout) {
+ case TileSet::TILE_LAYOUT_STACKED:
+ break;
+ case TileSet::TILE_LAYOUT_STACKED_OFFSET:
+ if (output.y % 2) {
+ output.x += 1;
+ }
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
+ case TileSet::TILE_LAYOUT_STAIRS_DOWN:
+ if ((p_to_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
+ if (output.y < 0 && (output.y % 2)) {
+ output = Vector2i(output.x - output.y / 2 + 1, output.y);
+ } else {
+ output = Vector2i(output.x - output.y / 2, output.y);
+ }
+ } else {
+ if (output.y % 2) {
+ if (output.y < 0) {
+ output = Vector2i(2 * output.x + 1, -output.x + output.y / 2 - 1);
+ } else {
+ output = Vector2i(2 * output.x + 1, -output.x + output.y / 2);
+ }
+ } else {
+ output = Vector2i(2 * output.x, -output.x + output.y / 2);
+ }
+ }
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
+ case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
+ if ((p_to_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
+ if (output.y % 2) {
+ if (output.y > 0) {
+ output = Vector2i(output.x - output.y / 2, output.x + output.y / 2 + 1);
+ } else {
+ output = Vector2i(output.x - output.y / 2 + 1, output.x + output.y / 2);
+ }
+ } else {
+ output = Vector2i(output.x - output.y / 2, output.x + output.y / 2);
+ }
+ } else {
+ if (output.y % 2) {
+ if (output.y < 0) {
+ output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2 - 1);
+ } else {
+ output = Vector2i(output.x + output.y / 2 + 1, -output.x + output.y / 2);
+ }
+ } else {
+ output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2);
+ }
+ }
+ break;
+ }
- if (tile_set.is_valid()) {
- tile_set->connect("changed", callable_mp(this, &TileMap::_recreate_quadrants));
- } else {
- clear();
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
+ SWAP(output.x, output.y);
}
- _recreate_quadrants();
- emit_signal("settings_changed");
+ return output;
}
-Ref<TileSet> TileMap::get_tileset() const {
- return tile_set;
+int TileMap::get_effective_quadrant_size() const {
+ // When using YSort, the quadrant size is reduced to 1 to have one CanvasItem per quadrant
+ if (tile_set.is_valid() && tile_set->is_y_sorting()) {
+ return 1;
+ } else {
+ return quadrant_size;
+ }
}
-void TileMap::set_cell_size(Size2 p_size) {
- ERR_FAIL_COND(p_size.x < 1 || p_size.y < 1);
-
- _clear_quadrants();
- cell_size = p_size;
- _recreate_quadrants();
- emit_signal("settings_changed");
-}
+Vector2i TileMap::_coords_to_quadrant_coords(const Vector2i &p_coords) const {
+ int quadrant_size = get_effective_quadrant_size();
-Size2 TileMap::get_cell_size() const {
- return cell_size;
+ // Rounding down, instead of simply rounding towards zero (truncating)
+ return Vector2i(
+ p_coords.x > 0 ? p_coords.x / quadrant_size : (p_coords.x - (quadrant_size - 1)) / quadrant_size,
+ p_coords.y > 0 ? p_coords.y / quadrant_size : (p_coords.y - (quadrant_size - 1)) / quadrant_size);
}
-void TileMap::set_quadrant_size(int p_size) {
- ERR_FAIL_COND_MSG(p_size < 1, "Quadrant size cannot be smaller than 1.");
+void TileMap::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ pending_update = true;
+ _recreate_quadrants();
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ _clear_quadrants();
+ } break;
+ }
- _clear_quadrants();
- quadrant_size = p_size;
- _recreate_quadrants();
- emit_signal("settings_changed");
+ // Transfers the notification to tileset plugins.
+ if (tile_set.is_valid()) {
+ for (int i = 0; i < tile_set->get_tile_set_atlas_plugins().size(); i++) {
+ tile_set->get_tile_set_atlas_plugins()[i]->tilemap_notification(this, p_what);
+ }
+ }
}
-int TileMap::get_quadrant_size() const {
- return quadrant_size;
+Ref<TileSet> TileMap::get_tileset() const {
+ return tile_set;
}
-void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Vector2 &p_offset, const Size2 &p_sc) {
- Size2 s = p_sc;
- Vector2 offset = p_offset;
-
- if (compatibility_mode && !centered_textures) {
- if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) {
- offset.y += cell_size.y;
- } else if (tile_origin == TILE_ORIGIN_CENTER) {
- offset += cell_size / 2;
- }
-
- if (s.y > s.x) {
- if ((p_cell.flip_h && (p_cell.flip_v || p_cell.transpose)) || (p_cell.flip_v && !p_cell.transpose)) {
- offset.y += s.y - s.x;
- }
- } else if (s.y < s.x) {
- if ((p_cell.flip_v && (p_cell.flip_h || p_cell.transpose)) || (p_cell.flip_h && !p_cell.transpose)) {
- offset.x += s.x - s.y;
- }
- }
+void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
+ if (p_tileset == tile_set) {
+ return;
}
- if (p_cell.transpose) {
- SWAP(xform.elements[0].x, xform.elements[0].y);
- SWAP(xform.elements[1].x, xform.elements[1].y);
- SWAP(offset.x, offset.y);
- SWAP(s.x, s.y);
+ // Set the tileset, registering to its changes.
+ if (tile_set.is_valid()) {
+ tile_set->disconnect("changed", callable_mp(this, &TileMap::_make_all_quadrants_dirty));
+ tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed));
}
- if (p_cell.flip_h) {
- xform.elements[0].x = -xform.elements[0].x;
- xform.elements[1].x = -xform.elements[1].x;
- if (compatibility_mode && !centered_textures) {
- if (tile_origin == TILE_ORIGIN_TOP_LEFT || tile_origin == TILE_ORIGIN_BOTTOM_LEFT) {
- offset.x = s.x - offset.x;
- } else if (tile_origin == TILE_ORIGIN_CENTER) {
- offset.x = s.x - offset.x / 2;
- }
- } else {
- offset.x = s.x - offset.x;
- }
+ if (!p_tileset.is_valid()) {
+ _clear_quadrants();
}
- if (p_cell.flip_v) {
- xform.elements[0].y = -xform.elements[0].y;
- xform.elements[1].y = -xform.elements[1].y;
- if (compatibility_mode && !centered_textures) {
- if (tile_origin == TILE_ORIGIN_TOP_LEFT) {
- offset.y = s.y - offset.y;
- } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) {
- offset.y += s.y;
- } else if (tile_origin == TILE_ORIGIN_CENTER) {
- offset.y += s.y;
- }
- } else {
- offset.y = s.y - offset.y;
- }
- }
+ tile_set = p_tileset;
- if (centered_textures) {
- offset += cell_size / 2 - s / 2;
+ if (tile_set.is_valid()) {
+ tile_set->connect("changed", callable_mp(this, &TileMap::_make_all_quadrants_dirty), varray(true));
+ tile_set->connect("changed", callable_mp(this, &TileMap::_tile_set_changed));
+ _recreate_quadrants();
}
- xform.elements[2] += offset;
+
+ emit_signal("changed");
}
-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) {
- PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
+int TileMap::get_quadrant_size() const {
+ return quadrant_size;
+}
+
+void TileMap::set_quadrant_size(int p_size) {
+ ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1.");
+
+ quadrant_size = p_size;
+ _recreate_quadrants();
+ emit_signal("changed");
+}
- if (!use_parent) {
- ps->body_add_shape(p_q.body, p_shape->get_rid(), p_xform);
- ps->body_set_shape_metadata(p_q.body, shape_idx, p_metadata);
- ps->body_set_shape_as_one_way_collision(p_q.body, shape_idx, p_shape_data.one_way_collision, p_shape_data.one_way_collision_margin);
+void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_collision) {
+ show_collision = p_show_collision;
+ _recreate_quadrants();
+ emit_signal("changed");
+}
- } else if (collision_parent) {
- Transform2D xform = p_xform;
- xform.set_origin(xform.get_origin() + p_q.pos);
+TileMap::VisibilityMode TileMap::get_collision_visibility_mode() {
+ return show_collision;
+}
- collision_parent->shape_owner_add_shape(p_q.shape_owner_id, p_shape);
+void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navigation) {
+ show_navigation = p_show_navigation;
+ _recreate_quadrants();
+ emit_signal("changed");
+}
- int real_index = collision_parent->shape_owner_get_shape_index(p_q.shape_owner_id, shape_idx);
- RID rid = collision_parent->get_rid();
+TileMap::VisibilityMode TileMap::get_navigation_visibility_mode() {
+ return show_navigation;
+}
- 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);
- ps->body_set_shape_metadata(rid, real_index, p_metadata);
- ps->body_set_shape_as_one_way_collision(rid, real_index, p_shape_data.one_way_collision, p_shape_data.one_way_collision_margin);
- }
- }
- shape_idx++;
+void TileMap::set_y_sort_enabled(bool p_enable) {
+ Node2D::set_y_sort_enabled(p_enable);
+ _recreate_quadrants();
+ emit_signal("changed");
}
void TileMap::update_dirty_quadrants() {
@@ -293,387 +349,47 @@ void TileMap::update_dirty_quadrants() {
return;
}
- RenderingServer *vs = RenderingServer::get_singleton();
- PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
- Vector2 tofs = get_cell_draw_offset();
- Vector2 qofs;
-
- SceneTree *st = SceneTree::get_singleton();
- Color debug_collision_color;
- Color debug_navigation_color;
-
- bool debug_shapes = st && st->is_debugging_collisions_hint();
- if (debug_shapes) {
- debug_collision_color = st->get_debug_collisions_color();
+ // Update the coords cache.
+ for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
+ q->self()->map_to_world.clear();
+ q->self()->world_to_map.clear();
+ for (Set<Vector2i>::Element *E = q->self()->cells.front(); E; E = E->next()) {
+ Vector2i pk = E->get();
+ Vector2i pk_world_coords = map_to_world(pk);
+ q->self()->map_to_world[pk] = pk_world_coords;
+ q->self()->world_to_map[pk_world_coords] = pk;
+ }
}
- bool debug_navigation = st && st->is_debugging_navigation_hint();
- if (debug_navigation) {
- debug_navigation_color = st->get_debug_navigation_color();
+ // Call the update_dirty_quadrant method on plugins.
+ for (int i = 0; i < tile_set->get_tile_set_atlas_plugins().size(); i++) {
+ tile_set->get_tile_set_atlas_plugins()[i]->update_dirty_quadrants(this, dirty_quadrant_list);
}
- while (dirty_quadrant_list.first()) {
- Quadrant &q = *dirty_quadrant_list.first()->self();
-
- for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
- vs->free(E->get());
- }
-
- q.canvas_items.clear();
-
- if (!use_parent) {
- ps->body_clear_shapes(q.body);
- } else if (collision_parent) {
- collision_parent->shape_owner_clear_shapes(q.shape_owner_id);
- }
- int shape_idx = 0;
-
- for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
- NavigationServer2D::get_singleton()->region_set_map(E->get().region, RID());
- }
- q.navpoly_ids.clear();
-
- for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) {
- RS::get_singleton()->free(E->get().id);
- }
- q.occluder_instances.clear();
- Ref<ShaderMaterial> prev_material;
- int prev_z_index = 0;
- RID prev_canvas_item;
- RID prev_debug_canvas_item;
-
- for (int i = 0; i < q.cells.size(); i++) {
- Map<PosKey, Cell>::Element *E = tile_map.find(q.cells[i]);
- Cell &c = E->get();
- //moment of truth
- if (!tile_set->has_tile(c.id)) {
- continue;
- }
- Ref<Texture2D> tex = tile_set->tile_get_texture(c.id);
- Vector2 tile_ofs = tile_set->tile_get_texture_offset(c.id);
-
- Vector2 wofs = _map_to_world(E->key().x, E->key().y);
- Vector2 offset = wofs - q.pos + tofs;
-
- if (!tex.is_valid()) {
- continue;
- }
-
- Ref<ShaderMaterial> mat = tile_set->tile_get_material(c.id);
- int z_index = tile_set->tile_get_z_index(c.id);
-
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE ||
- tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) {
- z_index += tile_set->autotile_get_z_index(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y));
- }
-
- RID canvas_item;
- RID debug_canvas_item;
-
- if (prev_canvas_item == RID() || prev_material != mat || prev_z_index != z_index) {
- canvas_item = vs->canvas_item_create();
- if (mat.is_valid()) {
- vs->canvas_item_set_material(canvas_item, mat->get_rid());
- }
- vs->canvas_item_set_parent(canvas_item, get_canvas_item());
- _update_item_material_state(canvas_item);
- Transform2D xform;
- xform.set_origin(q.pos);
- vs->canvas_item_set_transform(canvas_item, xform);
- vs->canvas_item_set_light_mask(canvas_item, get_light_mask());
- vs->canvas_item_set_z_index(canvas_item, z_index);
-
- vs->canvas_item_set_default_texture_filter(canvas_item, RS::CanvasItemTextureFilter(CanvasItem::get_texture_filter()));
- vs->canvas_item_set_default_texture_repeat(canvas_item, RS::CanvasItemTextureRepeat(CanvasItem::get_texture_repeat()));
-
- q.canvas_items.push_back(canvas_item);
-
- if (debug_shapes) {
- 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, RS::CANVAS_ITEM_Z_MAX - 1);
- q.canvas_items.push_back(debug_canvas_item);
- prev_debug_canvas_item = debug_canvas_item;
- }
-
- prev_canvas_item = canvas_item;
- prev_material = mat;
- prev_z_index = z_index;
-
- } else {
- canvas_item = prev_canvas_item;
- if (debug_shapes) {
- debug_canvas_item = prev_debug_canvas_item;
- }
- }
-
- Rect2 r = tile_set->tile_get_region(c.id);
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) {
- int spacing = tile_set->autotile_get_spacing(c.id);
- r.size = tile_set->autotile_get_size(c.id);
- r.position += (r.size + Vector2(spacing, spacing)) * Vector2(c.autotile_coord_x, c.autotile_coord_y);
- }
-
- Size2 s;
- if (r == Rect2()) {
- s = tex->get_size();
- } else {
- s = r.size;
- }
-
- Rect2 rect;
- rect.position = offset.floor();
- rect.size = s;
- rect.size.x += fp_adjust;
- rect.size.y += fp_adjust;
-
- if (compatibility_mode && !centered_textures) {
- if (rect.size.y > rect.size.x) {
- if ((c.flip_h && (c.flip_v || c.transpose)) || (c.flip_v && !c.transpose)) {
- tile_ofs.y += rect.size.y - rect.size.x;
- }
- } else if (rect.size.y < rect.size.x) {
- if ((c.flip_v && (c.flip_h || c.transpose)) || (c.flip_h && !c.transpose)) {
- tile_ofs.x += rect.size.x - rect.size.y;
- }
- }
- }
-
- if (c.transpose) {
- SWAP(tile_ofs.x, tile_ofs.y);
- if (centered_textures) {
- rect.position.x += cell_size.x / 2 - rect.size.y / 2;
- rect.position.y += cell_size.y / 2 - rect.size.x / 2;
- }
- } else if (centered_textures) {
- rect.position += cell_size / 2 - rect.size / 2;
- }
-
- if (c.flip_h) {
- rect.size.x = -rect.size.x;
- tile_ofs.x = -tile_ofs.x;
- }
-
- if (c.flip_v) {
- rect.size.y = -rect.size.y;
- tile_ofs.y = -tile_ofs.y;
- }
-
- if (compatibility_mode && !centered_textures) {
- if (tile_origin == TILE_ORIGIN_TOP_LEFT) {
- rect.position += tile_ofs;
-
- } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) {
- rect.position += tile_ofs;
-
- if (c.transpose) {
- if (c.flip_h) {
- rect.position.x -= cell_size.x;
- } else {
- rect.position.x += cell_size.x;
- }
- } else {
- if (c.flip_v) {
- rect.position.y -= cell_size.y;
- } else {
- rect.position.y += cell_size.y;
- }
- }
-
- } else if (tile_origin == TILE_ORIGIN_CENTER) {
- rect.position += tile_ofs;
-
- if (c.flip_h) {
- rect.position.x -= cell_size.x / 2;
- } else {
- rect.position.x += cell_size.x / 2;
- }
-
- if (c.flip_v) {
- rect.position.y -= cell_size.y / 2;
- } else {
- rect.position.y += cell_size.y / 2;
- }
- }
- } else {
- rect.position += tile_ofs;
- }
-
- Color modulate = tile_set->tile_get_modulate(c.id);
- Color self_modulate = get_self_modulate();
- modulate = Color(modulate.r * self_modulate.r, modulate.g * self_modulate.g,
- modulate.b * self_modulate.b, modulate.a * self_modulate.a);
- if (r == Rect2()) {
- tex->draw_rect(canvas_item, rect, false, modulate, c.transpose);
- } else {
- tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose, clip_uv);
- }
-
- Vector<TileSet::ShapeData> shapes = tile_set->tile_get_shapes(c.id);
-
- for (int j = 0; j < shapes.size(); j++) {
- Ref<Shape2D> shape = shapes[j].shape;
- if (shape.is_valid()) {
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::SINGLE_TILE || (shapes[j].autotile_coord.x == c.autotile_coord_x && shapes[j].autotile_coord.y == c.autotile_coord_y)) {
- Transform2D xform;
- xform.set_origin(offset.floor());
-
- Vector2 shape_ofs = shapes[j].shape_transform.get_origin();
-
- _fix_cell_transform(xform, c, shape_ofs, s);
-
- xform *= shapes[j].shape_transform.untranslated();
-
- if (debug_canvas_item.is_valid()) {
- vs->canvas_item_add_set_transform(debug_canvas_item, xform);
- shape->draw(debug_canvas_item, debug_collision_color);
- }
-
- if (shape->has_meta("decomposed")) {
- Array _shapes = shape->get_meta("decomposed");
- for (int k = 0; k < _shapes.size(); k++) {
- Ref<ConvexPolygonShape2D> convex = _shapes[k];
- if (convex.is_valid()) {
- _add_shape(shape_idx, q, convex, shapes[j], xform, Vector2(E->key().x, E->key().y));
-#ifdef DEBUG_ENABLED
- } else {
- print_error("The TileSet assigned to the TileMap " + get_name() + " has an invalid convex shape.");
-#endif
- }
- }
- } else {
- _add_shape(shape_idx, q, shape, shapes[j], xform, Vector2(E->key().x, E->key().y));
- }
- }
- }
- }
-
- if (debug_canvas_item.is_valid()) {
- vs->canvas_item_add_set_transform(debug_canvas_item, Transform2D());
- }
-
- if (bake_navigation) {
- Ref<NavigationPolygon> navpoly;
- Vector2 npoly_ofs;
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) {
- navpoly = tile_set->autotile_get_navigation_polygon(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y));
- npoly_ofs = Vector2();
- } else {
- navpoly = tile_set->tile_get_navigation_polygon(c.id);
- npoly_ofs = tile_set->tile_get_navigation_polygon_offset(c.id);
- }
-
- if (navpoly.is_valid()) {
- Transform2D xform;
- xform.set_origin(offset.floor() + q.pos);
- _fix_cell_transform(xform, c, npoly_ofs, s);
-
- RID region = NavigationServer2D::get_singleton()->region_create();
- NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
- NavigationServer2D::get_singleton()->region_set_transform(region, xform);
- NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly);
-
- Quadrant::NavPoly np;
- np.region = region;
- np.xform = xform;
- q.navpoly_ids[E->key()] = np;
-
- if (debug_navigation) {
- 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, 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();
- int vsize = navigation_polygon_vertices.size();
-
- if (vsize > 2) {
- Vector<Color> colors;
- Vector<Vector2> vertices;
- vertices.resize(vsize);
- colors.resize(vsize);
- {
- const Vector2 *vr = navigation_polygon_vertices.ptr();
- for (int j = 0; j < vsize; j++) {
- vertices.write[j] = vr[j];
- colors.write[j] = debug_navigation_color;
- }
- }
-
- Vector<int> indices;
-
- for (int j = 0; j < navpoly->get_polygon_count(); j++) {
- Vector<int> polygon = navpoly->get_polygon(j);
-
- for (int k = 2; k < polygon.size(); k++) {
- int kofs[3] = { 0, k - 1, k };
- for (int l = 0; l < 3; l++) {
- int idx = polygon[kofs[l]];
- ERR_FAIL_INDEX(idx, vsize);
- indices.push_back(idx);
- }
- }
- }
- Transform2D navxform;
- navxform.set_origin(offset.floor());
- _fix_cell_transform(navxform, c, npoly_ofs, s);
-
- vs->canvas_item_set_transform(debug_navigation_item, navxform);
- vs->canvas_item_add_triangle_array(debug_navigation_item, indices, vertices, colors);
- }
- }
- }
- }
- }
-
- Ref<OccluderPolygon2D> occluder;
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) {
- occluder = tile_set->autotile_get_light_occluder(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y));
- } else {
- occluder = tile_set->tile_get_light_occluder(c.id);
- }
- if (occluder.is_valid()) {
- Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id);
- Transform2D xform;
- xform.set_origin(offset.floor() + q.pos);
- _fix_cell_transform(xform, c, occluder_ofs, s);
-
- 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;
- q.occluder_instances[E->key()] = oc;
- }
+ // Redraw the debug canvas_items.
+ RenderingServer *rs = RenderingServer::get_singleton();
+ for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
+ rs->canvas_item_clear(q->self()->debug_canvas_item);
+ Transform2D xform;
+ xform.set_origin(map_to_world(q->self()->coords * get_effective_quadrant_size()));
+ rs->canvas_item_set_transform(q->self()->debug_canvas_item, xform);
+ for (int i = 0; i < tile_set->get_tile_set_atlas_plugins().size(); i++) {
+ tile_set->get_tile_set_atlas_plugins()[i]->draw_quadrant_debug(this, q->self());
}
+ }
+ // Clear the list
+ while (dirty_quadrant_list.first()) {
dirty_quadrant_list.remove(dirty_quadrant_list.first());
- quadrant_order_dirty = true;
}
pending_update = false;
- if (quadrant_order_dirty) {
- int index = -(int64_t)0x80000000; //always must be drawn below children
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- Quadrant &q = E->get();
- for (List<RID>::Element *F = q.canvas_items.front(); F; F = F->next()) {
- RS::get_singleton()->canvas_item_set_draw_index(F->get(), index++);
- }
- }
-
- quadrant_order_dirty = false;
- }
-
_recompute_rect_cache();
}
void TileMap::_recompute_rect_cache() {
+ // Compute the displayed area of the tilemap.
#ifdef DEBUG_ENABLED
if (!rect_cache_dirty) {
@@ -681,12 +397,12 @@ void TileMap::_recompute_rect_cache() {
}
Rect2 r_total;
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
+ for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
Rect2 r;
- r.position = _map_to_world(E->key().x * _get_quadrant_size(), E->key().y * _get_quadrant_size());
- r.expand_to(_map_to_world(E->key().x * _get_quadrant_size() + _get_quadrant_size(), E->key().y * _get_quadrant_size()));
- r.expand_to(_map_to_world(E->key().x * _get_quadrant_size() + _get_quadrant_size(), E->key().y * _get_quadrant_size() + _get_quadrant_size()));
- r.expand_to(_map_to_world(E->key().x * _get_quadrant_size(), E->key().y * _get_quadrant_size() + _get_quadrant_size()));
+ r.position = map_to_world(E->key() * get_effective_quadrant_size());
+ r.expand_to(map_to_world((E->key() + Vector2i(1, 0)) * get_effective_quadrant_size()));
+ r.expand_to(map_to_world((E->key() + Vector2i(1, 1)) * get_effective_quadrant_size()));
+ r.expand_to(map_to_world((E->key() + Vector2i(0, 1)) * get_effective_quadrant_size()));
if (E == quadrant_map.front()) {
r_total = r;
} else {
@@ -702,83 +418,58 @@ void TileMap::_recompute_rect_cache() {
#endif
}
-Map<TileMap::PosKey, TileMap::Quadrant>::Element *TileMap::_create_quadrant(const PosKey &p_qk) {
- Transform2D xform;
- //xform.set_origin(Point2(p_qk.x,p_qk.y)*cell_size*quadrant_size);
- Quadrant q;
- q.pos = _map_to_world(p_qk.x * _get_quadrant_size(), p_qk.y * _get_quadrant_size());
- q.pos += get_cell_draw_offset();
- if (tile_origin == TILE_ORIGIN_CENTER) {
- q.pos += cell_size / 2;
- } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) {
- q.pos.y += cell_size.y;
- }
-
- xform.set_origin(q.pos);
- //q.canvas_item = RenderingServer::get_singleton()->canvas_item_create();
- if (!use_parent) {
- 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);
-
- 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();
- PhysicsServer2D::get_singleton()->body_set_space(q.body, space);
- }
+Map<Vector2i, TileMapQuadrant>::Element *TileMap::_create_quadrant(const Vector2i &p_qk) {
+ TileMapQuadrant q;
+ q.coords = p_qk;
- 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);
- } else {
- q.shape_owner_id = -1;
+ rect_cache_dirty = true;
+
+ // Create the debug canvas item.
+ RenderingServer *rs = RenderingServer::get_singleton();
+ q.debug_canvas_item = rs->canvas_item_create();
+ rs->canvas_item_set_z_index(q.debug_canvas_item, RS::CANVAS_ITEM_Z_MAX - 1);
+ rs->canvas_item_set_parent(q.debug_canvas_item, get_canvas_item());
+
+ // Call the create_quadrant method on plugins
+ if (tile_set.is_valid()) {
+ for (int i = 0; i < tile_set->get_tile_set_atlas_plugins().size(); i++) {
+ tile_set->get_tile_set_atlas_plugins()[i]->create_quadrant(this, &q);
+ }
}
- rect_cache_dirty = true;
- quadrant_order_dirty = true;
return quadrant_map.insert(p_qk, q);
}
-void TileMap::_erase_quadrant(Map<PosKey, Quadrant>::Element *Q) {
- Quadrant &q = Q->get();
- if (!use_parent) {
- PhysicsServer2D::get_singleton()->free(q.body);
- } else if (collision_parent) {
- collision_parent->remove_shape_owner(q.shape_owner_id);
- }
+void TileMap::_erase_quadrant(Map<Vector2i, TileMapQuadrant>::Element *Q) {
+ // Remove a quadrant.
+ TileMapQuadrant *q = &(Q->get());
- for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
- RenderingServer::get_singleton()->free(E->get());
- }
- q.canvas_items.clear();
- if (q.dirty_list.in_list()) {
- dirty_quadrant_list.remove(&q.dirty_list);
+ // Call the cleanup_quadrant method on plugins.
+ if (tile_set.is_valid()) {
+ for (int i = 0; i < tile_set->get_tile_set_atlas_plugins().size(); i++) {
+ tile_set->get_tile_set_atlas_plugins()[i]->cleanup_quadrant(this, q);
+ }
}
- for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
- NavigationServer2D::get_singleton()->region_set_map(E->get().region, RID());
+ // Remove the quadrant from the dirty_list if it is there.
+ if (q->dirty_list_element.in_list()) {
+ dirty_quadrant_list.remove(&(q->dirty_list_element));
}
- q.navpoly_ids.clear();
- for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) {
- RS::get_singleton()->free(E->get().id);
- }
- q.occluder_instances.clear();
+ // Free the debug canvas item.
+ RenderingServer *rs = RenderingServer::get_singleton();
+ rs->free(q->debug_canvas_item);
quadrant_map.erase(Q);
rect_cache_dirty = true;
}
-void TileMap::_make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool update) {
- Quadrant &q = Q->get();
- if (!q.dirty_list.in_list()) {
- dirty_quadrant_list.add(&q.dirty_list);
+void TileMap::_make_all_quadrants_dirty(bool p_update) {
+ // Make all quandrants dirty, then trigger an update later.
+ for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
+ if (!E->value().dirty_list_element.in_list()) {
+ dirty_quadrant_list.add(&E->value().dirty_list_element);
+ }
}
if (pending_update) {
@@ -788,39 +479,68 @@ void TileMap::_make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool updat
if (!is_inside_tree()) {
return;
}
-
- if (update) {
+ if (p_update) {
call_deferred("update_dirty_quadrants");
}
}
-void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose) {
- set_cell(p_pos.x, p_pos.y, p_tile, p_flip_x, p_flip_y, p_transpose);
-}
+void TileMap::_make_quadrant_dirty(Map<Vector2i, TileMapQuadrant>::Element *Q, bool p_update) {
+ // Make the given quadrant dirty, then trigger an update later.
+ TileMapQuadrant &q = Q->get();
+ if (!q.dirty_list_element.in_list()) {
+ dirty_quadrant_list.add(&q.dirty_list_element);
+ }
+
+ if (pending_update) {
+ return;
+ }
+ pending_update = true;
+ if (!is_inside_tree()) {
+ return;
+ }
-void TileMap::_set_celld(const Vector2 &p_pos, const Dictionary &p_data) {
- Variant v_pos_x = p_pos.x, v_pos_y = p_pos.y, v_tile = p_data["id"], v_flip_h = p_data["flip_h"], v_flip_v = p_data["flip_y"], v_transpose = p_data["transpose"], v_autotile_coord = p_data["auto_coord"];
- const Variant *args[7] = { &v_pos_x, &v_pos_y, &v_tile, &v_flip_h, &v_flip_v, &v_transpose, &v_autotile_coord };
- Callable::CallError ce;
- call("set_cell", args, 7, ce);
+ if (p_update) {
+ call_deferred("update_dirty_quadrants");
+ }
}
-void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose, Vector2 p_autotile_coord) {
- PosKey pk(p_x, p_y);
+void TileMap::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
+ // Set the current cell tile (using integer position).
+ Vector2i pk(p_coords);
+ Map<Vector2i, TileMapCell>::Element *E = tile_map.find(pk);
+
+ int source_id = p_source_id;
+ Vector2i atlas_coords = p_atlas_coords;
+ int alternative_tile = p_alternative_tile;
- Map<PosKey, Cell>::Element *E = tile_map.find(pk);
- if (!E && p_tile == INVALID_CELL) {
- return; //nothing to do
+ if ((source_id == -1 || atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE) &&
+ (source_id != -1 || atlas_coords != TileSetSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE)) {
+ WARN_PRINT("Setting a cell a cell as empty requires both source_id, atlas_coord and alternative_tile to be set to their respective \"invalid\" values. Values were thus changes accordingly.");
+ source_id = -1;
+ atlas_coords = TileSetSource::INVALID_ATLAS_COORDS;
+ alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
}
- PosKey qk = pk.to_quadrant(_get_quadrant_size());
- if (p_tile == INVALID_CELL) {
- //erase existing
+ if (!E && source_id == -1) {
+ return; // Nothing to do, the tile is already empty.
+ }
+
+ // Get the quadrant
+ Vector2i qk = _coords_to_quadrant_coords(pk);
+
+ Map<Vector2i, TileMapQuadrant>::Element *Q = quadrant_map.find(qk);
+
+ if (source_id == -1) {
+ // Erase existing cell in the tile map.
tile_map.erase(pk);
- Map<PosKey, Quadrant>::Element *Q = quadrant_map.find(qk);
+
+ // Erase existing cell in the quadrant.
ERR_FAIL_COND(!Q);
- Quadrant &q = Q->get();
+ TileMapQuadrant &q = Q->get();
+
q.cells.erase(pk);
+
+ // Remove or make the quadrant dirty.
if (q.cells.size() == 0) {
_erase_quadrant(Q);
} else {
@@ -828,331 +548,242 @@ void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_
}
used_size_cache_dirty = true;
- return;
- }
-
- Map<PosKey, Quadrant>::Element *Q = quadrant_map.find(qk);
-
- if (!E) {
- E = tile_map.insert(pk, Cell());
- if (!Q) {
- Q = _create_quadrant(qk);
- }
- Quadrant &q = Q->get();
- q.cells.insert(pk);
} else {
- ERR_FAIL_COND(!Q); // quadrant should exist...
-
- if (E->get().id == p_tile && E->get().flip_h == p_flip_x && E->get().flip_v == p_flip_y && E->get().transpose == p_transpose && E->get().autotile_coord_x == (uint16_t)p_autotile_coord.x && E->get().autotile_coord_y == (uint16_t)p_autotile_coord.y) {
- return; //nothing changed
- }
- }
-
- Cell &c = E->get();
+ if (!E) {
+ // Insert a new cell in the tile map.
+ E = tile_map.insert(pk, TileMapCell());
- c.id = p_tile;
- c.flip_h = p_flip_x;
- c.flip_v = p_flip_y;
- c.transpose = p_transpose;
- c.autotile_coord_x = (uint16_t)p_autotile_coord.x;
- c.autotile_coord_y = (uint16_t)p_autotile_coord.y;
-
- _make_quadrant_dirty(Q);
- used_size_cache_dirty = true;
-}
-
-int TileMap::get_cellv(const Vector2 &p_pos) const {
- return get_cell(p_pos.x, p_pos.y);
-}
-
-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) == nullptr) {
- dirty_bitmask.push_back(p);
- }
- }
- }
-}
-
-void TileMap::update_bitmask_area(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++) {
- update_cell_bitmask(x, y);
- }
- }
-}
-
-void TileMap::update_bitmask_region(const Vector2 &p_start, const Vector2 &p_end) {
- if ((p_end.x < p_start.x || p_end.y < p_start.y) || (p_end.x == p_start.x && p_end.y == p_start.y)) {
- Array a = get_used_cells();
- for (int i = 0; i < a.size(); i++) {
- Vector2 vector = (Vector2)a[i];
- update_cell_bitmask(vector.x, vector.y);
- }
- return;
- }
- for (int x = p_start.x - 1; x <= p_end.x + 1; x++) {
- for (int y = p_start.y - 1; y <= p_end.y + 1; y++) {
- update_cell_bitmask(x, y);
- }
- }
-}
-
-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 != nullptr) {
- int id = get_cell(p_x, p_y);
- if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE) {
- uint16_t mask = 0;
- if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_2X2) {
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
- mask |= TileSet::BIND_TOPLEFT;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
- mask |= TileSet::BIND_TOPRIGHT;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
- mask |= TileSet::BIND_BOTTOMLEFT;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
- mask |= TileSet::BIND_BOTTOMRIGHT;
- }
- } else {
- if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_3X3_MINIMAL) {
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
- mask |= TileSet::BIND_TOPLEFT;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
- mask |= TileSet::BIND_TOPRIGHT;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
- mask |= TileSet::BIND_BOTTOMLEFT;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
- mask |= TileSet::BIND_BOTTOMRIGHT;
- }
- } else {
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1))) {
- mask |= TileSet::BIND_TOPLEFT;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1))) {
- mask |= TileSet::BIND_TOPRIGHT;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1))) {
- mask |= TileSet::BIND_BOTTOMLEFT;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1))) {
- mask |= TileSet::BIND_BOTTOMRIGHT;
- }
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1))) {
- mask |= TileSet::BIND_TOP;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
- mask |= TileSet::BIND_LEFT;
- }
- mask |= TileSet::BIND_CENTER;
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
- mask |= TileSet::BIND_RIGHT;
- }
- if (tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1))) {
- mask |= TileSet::BIND_BOTTOM;
- }
+ // Create a new quadrant if needed, then insert the cell if needed.
+ if (!Q) {
+ Q = _create_quadrant(qk);
}
- Vector2 coord = tile_set->autotile_get_subtile_for_bitmask(id, mask, this, Vector2(p_x, p_y));
- E->get().autotile_coord_x = (int)coord.x;
- E->get().autotile_coord_y = (int)coord.y;
+ TileMapQuadrant &q = Q->get();
+ q.cells.insert(pk);
- PosKey qk = p.to_quadrant(_get_quadrant_size());
- Map<PosKey, Quadrant>::Element *Q = quadrant_map.find(qk);
- _make_quadrant_dirty(Q);
-
- } else if (tile_set->tile_get_tile_mode(id) == TileSet::SINGLE_TILE) {
- E->get().autotile_coord_x = 0;
- E->get().autotile_coord_y = 0;
- } else if (tile_set->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) {
- if (tile_set->autotile_get_bitmask(id, Vector2(p_x, p_y)) == TileSet::BIND_CENTER) {
- Vector2 coord = tile_set->atlastile_get_subtile_by_priority(id, this, Vector2(p_x, p_y));
+ } else {
+ ERR_FAIL_COND(!Q); // TileMapQuadrant should exist...
- E->get().autotile_coord_x = (int)coord.x;
- E->get().autotile_coord_y = (int)coord.y;
+ if (E->get().source_id == source_id && E->get().get_atlas_coords() == atlas_coords && E->get().alternative_tile == alternative_tile) {
+ return; // Nothing changed.
}
}
- }
-}
-void TileMap::update_dirty_bitmask() {
- while (dirty_bitmask.size() > 0) {
- update_cell_bitmask(dirty_bitmask[0].x, dirty_bitmask[0].y);
- dirty_bitmask.pop_front();
- }
-}
+ TileMapCell &c = E->get();
-void TileMap::fix_invalid_tiles() {
- ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open.");
+ c.source_id = source_id;
+ c.set_atlas_coords(atlas_coords);
+ c.alternative_tile = alternative_tile;
- Map<PosKey, Cell> temp_tile_map = tile_map;
- for (Map<PosKey, Cell>::Element *E = temp_tile_map.front(); E; E = E->next()) {
- if (!tile_set->has_tile(get_cell(E->key().x, E->key().y))) {
- set_cell(E->key().x, E->key().y, INVALID_CELL);
- }
+ _make_quadrant_dirty(Q);
+ used_size_cache_dirty = true;
}
}
-int TileMap::get_cell(int p_x, int p_y) const {
- PosKey pk(p_x, p_y);
-
- const Map<PosKey, Cell>::Element *E = tile_map.find(pk);
+int TileMap::get_cell_source_id(const Vector2i &p_coords) const {
+ // Get a cell source id from position
+ const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords);
if (!E) {
- return INVALID_CELL;
+ return -1;
}
- return E->get().id;
+ return E->get().source_id;
}
-bool TileMap::is_cell_x_flipped(int p_x, int p_y) const {
- PosKey pk(p_x, p_y);
-
- const Map<PosKey, Cell>::Element *E = tile_map.find(pk);
+Vector2i TileMap::get_cell_atlas_coords(const Vector2i &p_coords) const {
+ // Get a cell source id from position
+ const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords);
if (!E) {
- return false;
+ return TileSetSource::INVALID_ATLAS_COORDS;
}
- return E->get().flip_h;
+ return E->get().get_atlas_coords();
}
-bool TileMap::is_cell_y_flipped(int p_x, int p_y) const {
- PosKey pk(p_x, p_y);
-
- const Map<PosKey, Cell>::Element *E = tile_map.find(pk);
+int TileMap::get_cell_alternative_tile(const Vector2i &p_coords) const {
+ // Get a cell source id from position
+ const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords);
if (!E) {
- return false;
+ return TileSetSource::INVALID_TILE_ALTERNATIVE;
}
- return E->get().flip_v;
+ return E->get().alternative_tile;
}
-bool TileMap::is_cell_transposed(int p_x, int p_y) const {
- PosKey pk(p_x, p_y);
+TileMapPattern *TileMap::get_pattern(TypedArray<Vector2i> p_coords_array) {
+ ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr);
- const Map<PosKey, Cell>::Element *E = tile_map.find(pk);
+ TileMapPattern *output = memnew(TileMapPattern);
+ if (p_coords_array.is_empty()) {
+ return output;
+ }
- if (!E) {
- return false;
+ Vector2i min = Vector2i(p_coords_array[0]);
+ for (int i = 1; i < p_coords_array.size(); i++) {
+ min = min.min(p_coords_array[i]);
}
- return E->get().transpose;
-}
+ Vector<Vector2i> coords_in_pattern_array;
+ coords_in_pattern_array.resize(p_coords_array.size());
+ Vector2i ensure_positive_offset;
+ for (int i = 0; i < p_coords_array.size(); i++) {
+ Vector2i coords = p_coords_array[i];
+ Vector2i coords_in_pattern = coords - min;
+ if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) {
+ if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) {
+ coords_in_pattern.x -= 1;
+ if (coords_in_pattern.x < 0) {
+ ensure_positive_offset.x = 1;
+ }
+ } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) {
+ coords_in_pattern.y -= 1;
+ if (coords_in_pattern.y < 0) {
+ ensure_positive_offset.y = 1;
+ }
+ }
+ } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(min.y % 2) && bool(coords_in_pattern.y % 2)) {
+ coords_in_pattern.x += 1;
+ } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(min.x % 2) && bool(coords_in_pattern.x % 2)) {
+ coords_in_pattern.y += 1;
+ }
+ }
+ }
+ coords_in_pattern_array.write[i] = coords_in_pattern;
+ }
+
+ for (int i = 0; i < coords_in_pattern_array.size(); i++) {
+ Vector2i coords = p_coords_array[i];
+ Vector2i coords_in_pattern = coords_in_pattern_array[i];
+ output->set_cell(coords_in_pattern + ensure_positive_offset, get_cell_source_id(coords), get_cell_atlas_coords(coords), get_cell_alternative_tile(coords));
+ }
-void TileMap::set_cell_autotile_coord(int p_x, int p_y, const Vector2 &p_coord) {
- PosKey pk(p_x, p_y);
+ return output;
+}
- const Map<PosKey, Cell>::Element *E = tile_map.find(pk);
+Vector2i TileMap::map_pattern(Vector2i p_position_in_tilemap, Vector2i p_coords_in_pattern, const TileMapPattern *p_pattern) {
+ ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i());
- if (!E) {
- return;
+ Vector2i output = p_position_in_tilemap + p_coords_in_pattern;
+ if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE) {
+ if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED) {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
+ output.x += 1;
+ } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
+ output.y += 1;
+ }
+ } else if (tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
+ output.x -= 1;
+ } else if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
+ output.y -= 1;
+ }
+ }
}
- Cell c = E->get();
- c.autotile_coord_x = p_coord.x;
- c.autotile_coord_y = p_coord.y;
- tile_map[pk] = c;
+ return output;
+}
- PosKey qk = pk.to_quadrant(_get_quadrant_size());
- Map<PosKey, Quadrant>::Element *Q = quadrant_map.find(qk);
+void TileMap::set_pattern(Vector2i p_position, const TileMapPattern *p_pattern) {
+ ERR_FAIL_COND(!tile_set.is_valid());
- if (!Q) {
- return;
+ TypedArray<Vector2i> used_cells = p_pattern->get_used_cells();
+ for (int i = 0; i < used_cells.size(); i++) {
+ Vector2i coords = map_pattern(p_position, used_cells[i], p_pattern);
+ set_cell(coords, p_pattern->get_cell_source_id(coords), p_pattern->get_cell_atlas_coords(coords), p_pattern->get_cell_alternative_tile(coords));
}
+}
- _make_quadrant_dirty(Q);
+TileMapCell TileMap::get_cell(const Vector2i &p_coords) const {
+ if (!tile_map.has(p_coords)) {
+ return TileMapCell();
+ } else {
+ return tile_map.find(p_coords)->get();
+ }
}
-Vector2 TileMap::get_cell_autotile_coord(int p_x, int p_y) const {
- PosKey pk(p_x, p_y);
+Map<Vector2i, TileMapQuadrant> &TileMap::get_quadrant_map() {
+ return quadrant_map;
+}
- const Map<PosKey, Cell>::Element *E = tile_map.find(pk);
+void TileMap::fix_invalid_tiles() {
+ ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open.");
- if (!E) {
- return Vector2();
+ Set<Vector2i> coords;
+ for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
+ TileSetSource *source = *tile_set->get_source(E->get().source_id);
+ if (!source || !source->has_tile(E->get().get_atlas_coords()) || !source->has_alternative_tile(E->get().get_atlas_coords(), E->get().alternative_tile)) {
+ coords.insert(E->key());
+ }
+ }
+ for (Set<Vector2i>::Element *E = coords.front(); E; E = E->next()) {
+ set_cell(E->get(), -1, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
}
-
- return Vector2(E->get().autotile_coord_x, E->get().autotile_coord_y);
}
void TileMap::_recreate_quadrants() {
+ // Clear then recreate all quadrants.
_clear_quadrants();
- for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
- PosKey qk = PosKey(E->key().x, E->key().y).to_quadrant(_get_quadrant_size());
+ for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
+ Vector2i qk = _coords_to_quadrant_coords(Vector2i(E->key().x, E->key().y));
- Map<PosKey, Quadrant>::Element *Q = quadrant_map.find(qk);
+ Map<Vector2i, TileMapQuadrant>::Element *Q = quadrant_map.find(qk);
if (!Q) {
Q = _create_quadrant(qk);
- dirty_quadrant_list.add(&Q->get().dirty_list);
+ dirty_quadrant_list.add(&Q->get().dirty_list_element);
}
- Q->get().cells.insert(E->key());
+ Vector2i pk = E->key();
+ Q->get().cells.insert(pk);
+
_make_quadrant_dirty(Q, false);
}
+
update_dirty_quadrants();
}
void TileMap::_clear_quadrants() {
+ // Clear quadrants.
while (quadrant_map.size()) {
_erase_quadrant(quadrant_map.front());
}
-}
-
-void TileMap::set_material(const Ref<Material> &p_material) {
- CanvasItem::set_material(p_material);
- _update_all_items_material_state();
-}
-void TileMap::set_use_parent_material(bool p_use_parent_material) {
- CanvasItem::set_use_parent_material(p_use_parent_material);
- _update_all_items_material_state();
-}
-
-void TileMap::_update_all_items_material_state() {
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- Quadrant &q = E->get();
- for (List<RID>::Element *F = q.canvas_items.front(); F; F = F->next()) {
- _update_item_material_state(F->get());
- }
+ // Clear the dirty quadrants list.
+ while (dirty_quadrant_list.first()) {
+ dirty_quadrant_list.remove(dirty_quadrant_list.first());
}
}
-void TileMap::_update_item_material_state(const RID &p_canvas_item) {
- RS::get_singleton()->canvas_item_set_use_parent_material(p_canvas_item, get_use_parent_material() || get_material().is_valid());
-}
-
void TileMap::clear() {
+ // Remove all tiles.
_clear_quadrants();
tile_map.clear();
used_size_cache_dirty = true;
}
void TileMap::_set_tile_data(const Vector<int> &p_data) {
- ERR_FAIL_COND(format > FORMAT_2);
+ // Set data for a given tile from raw data.
+ ERR_FAIL_COND(format > FORMAT_3);
int c = p_data.size();
const int *r = p_data.ptr();
- int offset = (format == FORMAT_2) ? 3 : 2;
+ int offset = (format >= FORMAT_2) ? 3 : 2;
clear();
+
+#ifdef DISABLE_DEPRECATED
+ ERR_FAIL_COND_MSG(format != FORMAT_3, vformat("Cannot handle deprecated TileMap data format version %d. This Godot version was compiled with no support for deprecated data.", format));
+#endif
+
for (int i = 0; i < c; i += offset) {
const uint8_t *ptr = (const uint8_t *)&r[i];
uint8_t local[12];
- for (int j = 0; j < ((format == FORMAT_2) ? 12 : 8); j++) {
+ for (int j = 0; j < ((format >= FORMAT_2) ? 12 : 8); j++) {
local[j] = ptr[j];
}
@@ -1163,31 +794,51 @@ void TileMap::_set_tile_data(const Vector<int> &p_data) {
SWAP(local[4], local[7]);
SWAP(local[5], local[6]);
//TODO: ask someone to check this...
- if (FORMAT == FORMAT_2) {
+ if (FORMAT >= FORMAT_2) {
SWAP(local[8], local[11]);
SWAP(local[9], local[10]);
}
#endif
+ int16_t x = decode_uint16(&local[0]);
+ int16_t y = decode_uint16(&local[2]);
+
+ if (format == FORMAT_3) {
+ uint16_t source_id = decode_uint16(&local[4]);
+ uint16_t atlas_coords_x = decode_uint16(&local[6]);
+ uint16_t atlas_coords_y = decode_uint32(&local[8]);
+ uint16_t alternative_tile = decode_uint16(&local[10]);
+ set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile);
+ } else {
+#ifndef DISABLE_DEPRECATED
+ uint32_t v = decode_uint32(&local[4]);
+ v &= (1 << 29) - 1;
+
+ // We generate an alternative tile number out of the the flags
+ // An option should create the alternative in the tileset for compatibility
+ bool flip_h = v & (1 << 29);
+ bool flip_v = v & (1 << 30);
+ bool transpose = v & (1 << 31);
+ int16_t coord_x = 0;
+ int16_t coord_y = 0;
+ if (format == FORMAT_2) {
+ coord_x = decode_uint16(&local[8]);
+ coord_y = decode_uint16(&local[10]);
+ }
- uint16_t x = decode_uint16(&local[0]);
- uint16_t y = decode_uint16(&local[2]);
- uint32_t v = decode_uint32(&local[4]);
- bool flip_h = v & (1 << 29);
- bool flip_v = v & (1 << 30);
- bool transpose = v & (1 << 31);
- v &= (1 << 29) - 1;
- int16_t coord_x = 0;
- int16_t coord_y = 0;
- if (format == FORMAT_2) {
- coord_x = decode_uint16(&local[8]);
- coord_y = decode_uint16(&local[10]);
- }
+ int compatibility_alternative_tile = ((int)flip_h) + ((int)flip_v << 1) + ((int)transpose << 2);
- set_cell(x, y, v, flip_h, flip_v, transpose, Vector2(coord_x, coord_y));
+ if (tile_set.is_valid()) {
+ v = tile_set->compatibility_get_source_for_tile_id(v);
+ }
+
+ set_cell(Vector2i(x, y), v, Vector2i(coord_x, coord_y), compatibility_alternative_tile);
+#endif
+ }
}
}
Vector<int> TileMap::_get_tile_data() const {
+ // Export tile data to raw format
Vector<int> data;
data.resize(tile_map.size() * 3);
int *w = data.ptrw();
@@ -1195,23 +846,14 @@ Vector<int> TileMap::_get_tile_data() const {
// Save in highest format
int idx = 0;
- for (const Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
+ for (const Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
uint8_t *ptr = (uint8_t *)&w[idx];
- encode_uint16(E->key().x, &ptr[0]);
- encode_uint16(E->key().y, &ptr[2]);
- uint32_t val = E->get().id;
- if (E->get().flip_h) {
- val |= (1 << 29);
- }
- if (E->get().flip_v) {
- val |= (1 << 30);
- }
- if (E->get().transpose) {
- val |= (1 << 31);
- }
- encode_uint32(val, &ptr[4]);
- encode_uint16(E->get().autotile_coord_x, &ptr[8]);
- encode_uint16(E->get().autotile_coord_y, &ptr[10]);
+ encode_uint16((int16_t)(E->key().x), &ptr[0]);
+ encode_uint16((int16_t)(E->key().y), &ptr[2]);
+ encode_uint16(E->get().source_id, &ptr[4]);
+ encode_uint16(E->get().coord_x, &ptr[6]);
+ encode_uint16(E->get().coord_y, &ptr[8]);
+ encode_uint16(E->get().alternative_tile, &ptr[10]);
idx += 3;
}
@@ -1220,6 +862,7 @@ Vector<int> TileMap::_get_tile_data() const {
#ifdef TOOLS_ENABLED
Rect2 TileMap::_edit_get_rect() const {
+ // Return the visible rect of the tilemap
if (pending_update) {
const_cast<TileMap *>(this)->update_dirty_quadrants();
} else {
@@ -1229,251 +872,6 @@ Rect2 TileMap::_edit_get_rect() const {
}
#endif
-void TileMap::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- if (!use_parent) {
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- Quadrant &q = E->get();
- PhysicsServer2D::get_singleton()->body_set_collision_layer(q.body, collision_layer);
- }
- }
-}
-
-void TileMap::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- if (!use_parent) {
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- Quadrant &q = E->get();
- PhysicsServer2D::get_singleton()->body_set_collision_mask(q.body, collision_mask);
- }
- }
-}
-
-void TileMap::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);
-}
-
-void TileMap::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 TileMap::get_collision_use_kinematic() const {
- return use_kinematic;
-}
-
-void TileMap::set_collision_use_kinematic(bool p_use_kinematic) {
- _clear_quadrants();
- use_kinematic = p_use_kinematic;
- _recreate_quadrants();
-}
-
-bool TileMap::get_collision_use_parent() const {
- return use_parent;
-}
-
-void TileMap::set_collision_use_parent(bool p_use_parent) {
- if (use_parent == p_use_parent) {
- return;
- }
-
- _clear_quadrants();
-
- use_parent = p_use_parent;
- set_notify_local_transform(use_parent);
-
- if (use_parent && is_inside_tree()) {
- collision_parent = Object::cast_to<CollisionObject2D>(get_parent());
- } else {
- collision_parent = nullptr;
- }
-
- _recreate_quadrants();
- notify_property_list_changed();
- update_configuration_warnings();
-}
-
-void TileMap::set_collision_friction(float p_friction) {
- friction = p_friction;
- if (!use_parent) {
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- Quadrant &q = E->get();
- PhysicsServer2D::get_singleton()->body_set_param(q.body, PhysicsServer2D::BODY_PARAM_FRICTION, p_friction);
- }
- }
-}
-
-float TileMap::get_collision_friction() const {
- return friction;
-}
-
-void TileMap::set_collision_bounce(float p_bounce) {
- bounce = p_bounce;
- if (!use_parent) {
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
- Quadrant &q = E->get();
- PhysicsServer2D::get_singleton()->body_set_param(q.body, PhysicsServer2D::BODY_PARAM_BOUNCE, p_bounce);
- }
- }
-}
-
-float TileMap::get_collision_bounce() const {
- return bounce;
-}
-
-void TileMap::set_bake_navigation(bool p_bake_navigation) {
- bake_navigation = p_bake_navigation;
- for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) {
- _make_quadrant_dirty(F);
- }
-}
-
-bool TileMap::is_baking_navigation() {
- return bake_navigation;
-}
-
-uint32_t TileMap::get_collision_layer() const {
- return collision_layer;
-}
-
-uint32_t TileMap::get_collision_mask() const {
- return collision_mask;
-}
-
-bool TileMap::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
-}
-
-bool TileMap::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void TileMap::set_mode(Mode p_mode) {
- _clear_quadrants();
- mode = p_mode;
- _recreate_quadrants();
- emit_signal("settings_changed");
-}
-
-TileMap::Mode TileMap::get_mode() const {
- return mode;
-}
-
-void TileMap::set_half_offset(HalfOffset p_half_offset) {
- _clear_quadrants();
- half_offset = p_half_offset;
- _recreate_quadrants();
- emit_signal("settings_changed");
-}
-
-void TileMap::set_tile_origin(TileOrigin p_tile_origin) {
- _clear_quadrants();
- tile_origin = p_tile_origin;
- _recreate_quadrants();
- emit_signal("settings_changed");
-}
-
-TileMap::TileOrigin TileMap::get_tile_origin() const {
- return tile_origin;
-}
-
-Vector2 TileMap::get_cell_draw_offset() const {
- switch (mode) {
- case MODE_SQUARE: {
- return Vector2();
- } break;
- case MODE_ISOMETRIC: {
- return Vector2(-cell_size.x * 0.5, 0);
-
- } break;
- case MODE_CUSTOM: {
- Vector2 min;
- min.x = MIN(custom_transform[0].x, min.x);
- min.y = MIN(custom_transform[0].y, min.y);
- min.x = MIN(custom_transform[1].x, min.x);
- min.y = MIN(custom_transform[1].y, min.y);
- return min;
- } break;
- }
-
- return Vector2();
-}
-
-TileMap::HalfOffset TileMap::get_half_offset() const {
- return half_offset;
-}
-
-Transform2D TileMap::get_cell_transform() const {
- switch (mode) {
- case MODE_SQUARE: {
- Transform2D m;
- m[0] *= cell_size.x;
- m[1] *= cell_size.y;
- return m;
- } break;
- case MODE_ISOMETRIC: {
- //isometric only makes sense when y is positive in both x and y vectors, otherwise
- //the drawing of tiles will overlap
- Transform2D m;
- m[0] = Vector2(cell_size.x * 0.5, cell_size.y * 0.5);
- m[1] = Vector2(-cell_size.x * 0.5, cell_size.y * 0.5);
- return m;
-
- } break;
- case MODE_CUSTOM: {
- return custom_transform;
- } break;
- }
-
- return Transform2D();
-}
-
-void TileMap::set_custom_transform(const Transform2D &p_xform) {
- _clear_quadrants();
- custom_transform = p_xform;
- _recreate_quadrants();
- emit_signal("settings_changed");
-}
-
-Transform2D TileMap::get_custom_transform() const {
- return custom_transform;
-}
-
-Vector2 TileMap::_map_to_world(int p_x, int p_y, bool p_ignore_ofs) const {
- Vector2 ret = get_cell_transform().xform(Vector2(p_x, p_y));
- if (!p_ignore_ofs) {
- switch (half_offset) {
- case HALF_OFFSET_X:
- case HALF_OFFSET_NEGATIVE_X: {
- if (ABS(p_y) & 1) {
- ret += get_cell_transform()[0] * (half_offset == HALF_OFFSET_X ? 0.5 : -0.5);
- }
- } break;
- case HALF_OFFSET_Y:
- case HALF_OFFSET_NEGATIVE_Y: {
- if (ABS(p_x) & 1) {
- ret += get_cell_transform()[1] * (half_offset == HALF_OFFSET_Y ? 0.5 : -0.5);
- }
- } break;
- case HALF_OFFSET_DISABLED: {
- // Nothing to do.
- }
- }
- }
- return ret;
-}
-
bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == "format") {
if (p_value.get_type() == Variant::INT) {
@@ -1492,7 +890,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
bool TileMap::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "format") {
- r_ret = FORMAT_2; // When saving, always save highest format
+ r_ret = FORMAT_3; // When saving, always save highest format
return true;
} else if (p_name == "tile_data") {
r_ret = _get_tile_data();
@@ -1509,92 +907,632 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(p);
}
-void TileMap::_validate_property(PropertyInfo &property) const {
- if (use_parent && property.name != "collision_use_parent" && property.name.begins_with("collision_")) {
- property.usage = PROPERTY_USAGE_NOEDITOR;
+Vector2 TileMap::map_to_world(const Vector2i &p_pos) const {
+ // SHOULD RETURN THE CENTER OF THE TILE
+ ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2());
+
+ Vector2 ret = p_pos;
+ TileSet::TileShape tile_shape = tile_set->get_tile_shape();
+ TileSet::TileOffsetAxis tile_offset_axis = tile_set->get_tile_offset_axis();
+
+ if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
+ // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap
+ if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ switch (tile_set->get_tile_layout()) {
+ case TileSet::TILE_LAYOUT_STACKED:
+ ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 0 ? 0.0 : 0.5), ret.y);
+ break;
+ case TileSet::TILE_LAYOUT_STACKED_OFFSET:
+ ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 1 ? 0.0 : 0.5), ret.y);
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
+ ret = Vector2(ret.x + ret.y / 2, ret.y);
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_DOWN:
+ ret = Vector2(ret.x / 2, ret.y * 2 + ret.x);
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
+ ret = Vector2((ret.x + ret.y) / 2, ret.y - ret.x);
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
+ ret = Vector2((ret.x - ret.y) / 2, ret.y + ret.x);
+ break;
+ }
+ } else { // TILE_OFFSET_AXIS_VERTICAL
+ switch (tile_set->get_tile_layout()) {
+ case TileSet::TILE_LAYOUT_STACKED:
+ ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 0 ? 0.0 : 0.5));
+ break;
+ case TileSet::TILE_LAYOUT_STACKED_OFFSET:
+ ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 1 ? 0.0 : 0.5));
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
+ ret = Vector2(ret.x * 2 + ret.y, ret.y / 2);
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_DOWN:
+ ret = Vector2(ret.x, ret.y + ret.x / 2);
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
+ ret = Vector2(ret.x + ret.y, (ret.y - ret.x) / 2);
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
+ ret = Vector2(ret.x - ret.y, (ret.y + ret.x) / 2);
+ break;
+ }
+ }
}
-}
-Vector2 TileMap::map_to_world(const Vector2 &p_pos, bool p_ignore_ofs) const {
- return _map_to_world(p_pos.x, p_pos.y, p_ignore_ofs);
+ // Multiply by the overlapping ratio
+ double overlapping_ratio = 1.0;
+ if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ overlapping_ratio = 0.5;
+ } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
+ overlapping_ratio = 0.75;
+ }
+ ret.y *= overlapping_ratio;
+ } else { // TILE_OFFSET_AXIS_VERTICAL
+ if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ overlapping_ratio = 0.5;
+ } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
+ overlapping_ratio = 0.75;
+ }
+ ret.x *= overlapping_ratio;
+ }
+
+ return (ret + Vector2(0.5, 0.5)) * tile_set->get_tile_size();
}
-Vector2 TileMap::world_to_map(const Vector2 &p_pos) const {
- Vector2 ret = get_cell_transform().affine_inverse().xform(p_pos);
+Vector2i TileMap::world_to_map(const Vector2 &p_pos) const {
+ ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2i());
+
+ Vector2 ret = p_pos;
+ ret /= tile_set->get_tile_size();
- switch (half_offset) {
- case HALF_OFFSET_X: {
- if (int(floor(ret.y)) & 1) {
- ret.x -= 0.5;
+ TileSet::TileShape tile_shape = tile_set->get_tile_shape();
+ TileSet::TileOffsetAxis tile_offset_axis = tile_set->get_tile_offset_axis();
+ TileSet::TileLayout tile_layout = tile_set->get_tile_layout();
+
+ // Divide by the overlapping ratio
+ double overlapping_ratio = 1.0;
+ if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ overlapping_ratio = 0.5;
+ } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
+ overlapping_ratio = 0.75;
+ }
+ ret.y /= overlapping_ratio;
+ } else { // TILE_OFFSET_AXIS_VERTICAL
+ if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ overlapping_ratio = 0.5;
+ } else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
+ overlapping_ratio = 0.75;
+ }
+ ret.x /= overlapping_ratio;
+ }
+
+ // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the world position accordingly.
+ if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
+ // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap
+ if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ // Smart floor of the position
+ Vector2 raw_pos = ret;
+ if (Math::posmod(Math::floor(ret.y), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) {
+ ret = Vector2(Math::floor(ret.x + 0.5) - 0.5, Math::floor(ret.y));
+ } else {
+ ret = ret.floor();
}
- } break;
- case HALF_OFFSET_NEGATIVE_X: {
- if (int(floor(ret.y)) & 1) {
- ret.x += 0.5;
+
+ // Compute the tile offset, and if we might the output for a neighbour top tile
+ Vector2 in_tile_pos = raw_pos - ret;
+ bool in_top_left_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(-0.5, 1.0 / overlapping_ratio - 1)) <= 0;
+ bool in_top_right_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(0.5, 1.0 / overlapping_ratio - 1)) > 0;
+
+ switch (tile_layout) {
+ case TileSet::TILE_LAYOUT_STACKED:
+ ret = ret.floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : -1, -1);
+ } else if (in_top_right_triangle) {
+ ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 1 : 0, -1);
+ }
+ break;
+ case TileSet::TILE_LAYOUT_STACKED_OFFSET:
+ ret = ret.floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? -1 : 0, -1);
+ } else if (in_top_right_triangle) {
+ ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : 1, -1);
+ }
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
+ ret = Vector2(ret.x - ret.y / 2, ret.y).floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(0, -1);
+ } else if (in_top_right_triangle) {
+ ret += Vector2i(1, -1);
+ }
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_DOWN:
+ ret = Vector2(ret.x * 2, ret.y / 2 - ret.x).floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(-1, 0);
+ } else if (in_top_right_triangle) {
+ ret += Vector2i(1, -1);
+ }
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
+ ret = Vector2(ret.x - ret.y / 2, ret.y / 2 + ret.x).floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(0, -1);
+ } else if (in_top_right_triangle) {
+ ret += Vector2i(1, 0);
+ }
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
+ ret = Vector2(ret.x + ret.y / 2, ret.y / 2 - ret.x).floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(-1, 0);
+ } else if (in_top_right_triangle) {
+ ret += Vector2i(0, -1);
+ }
+ break;
}
- } break;
- case HALF_OFFSET_Y: {
- if (int(floor(ret.x)) & 1) {
- ret.y -= 0.5;
+ } else { // TILE_OFFSET_AXIS_VERTICAL
+ // Smart floor of the position
+ Vector2 raw_pos = ret;
+ if (Math::posmod(Math::floor(ret.x), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) {
+ ret = Vector2(Math::floor(ret.x), Math::floor(ret.y + 0.5) - 0.5);
+ } else {
+ ret = ret.floor();
}
- } break;
- case HALF_OFFSET_NEGATIVE_Y: {
- if (int(floor(ret.x)) & 1) {
- ret.y += 0.5;
+
+ // Compute the tile offset, and if we might the output for a neighbour top tile
+ Vector2 in_tile_pos = raw_pos - ret;
+ bool in_top_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, -0.5)) > 0;
+ bool in_bottom_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, 0.5)) <= 0;
+
+ switch (tile_layout) {
+ case TileSet::TILE_LAYOUT_STACKED:
+ ret = ret.floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : -1);
+ } else if (in_bottom_left_triangle) {
+ ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 1 : 0);
+ }
+ break;
+ case TileSet::TILE_LAYOUT_STACKED_OFFSET:
+ ret = ret.floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? -1 : 0);
+ } else if (in_bottom_left_triangle) {
+ ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : 1);
+ }
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
+ ret = Vector2(ret.x / 2 - ret.y, ret.y * 2).floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(0, -1);
+ } else if (in_bottom_left_triangle) {
+ ret += Vector2i(-1, 1);
+ }
+ break;
+ case TileSet::TILE_LAYOUT_STAIRS_DOWN:
+ ret = Vector2(ret.x, ret.y - ret.x / 2).floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(-1, 0);
+ } else if (in_bottom_left_triangle) {
+ ret += Vector2i(-1, 1);
+ }
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
+ ret = Vector2(ret.x / 2 - ret.y, ret.y + ret.x / 2).floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(0, -1);
+ } else if (in_bottom_left_triangle) {
+ ret += Vector2i(-1, 0);
+ }
+ break;
+ case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
+ ret = Vector2(ret.x / 2 + ret.y, ret.y - ret.x / 2).floor();
+ if (in_top_left_triangle) {
+ ret += Vector2i(-1, 0);
+ } else if (in_bottom_left_triangle) {
+ ret += Vector2i(0, 1);
+ }
+ break;
}
- } break;
- case HALF_OFFSET_DISABLED: {
- // Nothing to do.
+ }
+ } else {
+ ret = (ret + Vector2(0.00005, 0.00005)).floor();
+ }
+ return Vector2i(ret);
+}
+
+bool TileMap::is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const {
+ ERR_FAIL_COND_V(!tile_set.is_valid(), false);
+
+ TileSet::TileShape shape = tile_set->get_tile_shape();
+ if (shape == TileSet::TILE_SHAPE_SQUARE) {
+ return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
+
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
+ } else {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
+ } else {
+ return p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
+ p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
}
}
-
- // Account for precision errors on the border (GH-23250).
- // 0.00005 is 5*CMP_EPSILON, results would start being unpredictable if
- // cell size is > 15,000, but we can hardly have more precision anyway with
- // floating point.
- ret += Vector2(0.00005, 0.00005);
- return ret.floor();
}
-void TileMap::set_y_sort_enabled(bool p_enable) {
- _clear_quadrants();
- use_y_sort = p_enable;
- RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), use_y_sort);
- _recreate_quadrants();
- emit_signal("settings_changed");
-}
-
-bool TileMap::is_y_sort_enabled() const {
- return use_y_sort;
-}
+Vector2i TileMap::get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const {
+ ERR_FAIL_COND_V(!tile_set.is_valid(), p_coords);
+
+ TileSet::TileShape shape = tile_set->get_tile_shape();
+ if (shape == TileSet::TILE_SHAPE_SQUARE) {
+ switch (p_cell_neighbor) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
+ return p_coords + Vector2i(1, 0);
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ return p_coords + Vector2i(1, 1);
+ case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
+ return p_coords + Vector2i(0, 1);
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ return p_coords + Vector2i(-1, 1);
+ case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
+ return p_coords + Vector2i(-1, 0);
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ return p_coords + Vector2i(-1, -1);
+ case TileSet::CELL_NEIGHBOR_TOP_SIDE:
+ return p_coords + Vector2i(0, -1);
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ return p_coords + Vector2i(1, -1);
+ default:
+ ERR_FAIL_V(p_coords);
+ }
+ } else { // Half-offset shapes (square and hexagon)
+ switch (tile_set->get_tile_layout()) {
+ case TileSet::TILE_LAYOUT_STACKED: {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ bool is_offset = p_coords.y % 2;
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
+ return p_coords + Vector2i(1, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(is_offset ? 1 : 0, 1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
+ return p_coords + Vector2i(0, 2);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(is_offset ? 0 : -1, 1);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
+ return p_coords + Vector2i(-1, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(is_offset ? 0 : -1, -1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
+ return p_coords + Vector2i(0, -2);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(is_offset ? 1 : 0, -1);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
+ } else {
+ bool is_offset = p_coords.x % 2;
+
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
+ return p_coords + Vector2i(0, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, is_offset ? 1 : 0);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
+ return p_coords + Vector2i(2, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, is_offset ? 0 : -1);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
+ return p_coords + Vector2i(0, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, is_offset ? 0 : -1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
+ return p_coords + Vector2i(-2, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, is_offset ? 1 : 0);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
+ }
+ } break;
+ case TileSet::TILE_LAYOUT_STACKED_OFFSET: {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ bool is_offset = p_coords.y % 2;
+
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
+ return p_coords + Vector2i(1, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(is_offset ? 0 : 1, 1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
+ return p_coords + Vector2i(0, 2);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(is_offset ? -1 : 0, 1);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
+ return p_coords + Vector2i(-1, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(is_offset ? -1 : 0, -1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
+ return p_coords + Vector2i(0, -2);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(is_offset ? 0 : 1, -1);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
+ } else {
+ bool is_offset = p_coords.x % 2;
+
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
+ return p_coords + Vector2i(0, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, is_offset ? 0 : 1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
+ return p_coords + Vector2i(2, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, is_offset ? -1 : 0);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
+ return p_coords + Vector2i(0, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, is_offset ? -1 : 0);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
+ return p_coords + Vector2i(-2, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, is_offset ? 0 : 1);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
+ }
+ } break;
+ case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
+ case TileSet::TILE_LAYOUT_STAIRS_DOWN: {
+ if ((tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
+ return p_coords + Vector2i(1, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(0, 1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
+ return p_coords + Vector2i(-1, 2);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, 1);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
+ return p_coords + Vector2i(-1, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(0, -1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
+ return p_coords + Vector2i(1, -2);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, -1);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
-void TileMap::set_compatibility_mode(bool p_enable) {
- _clear_quadrants();
- compatibility_mode = p_enable;
- _recreate_quadrants();
- emit_signal("settings_changed");
-}
+ } else {
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
+ return p_coords + Vector2i(0, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, 0);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
+ return p_coords + Vector2i(2, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, -1);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
+ return p_coords + Vector2i(0, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, 0);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
+ return p_coords + Vector2i(-2, 1);
+
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, 1);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
+ }
+ } else {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
+ return p_coords + Vector2i(2, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, 0);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
+ return p_coords + Vector2i(0, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, 1);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
+ return p_coords + Vector2i(-2, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, 0);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
+ return p_coords + Vector2i(0, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, -1);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
-bool TileMap::is_compatibility_mode_enabled() const {
- return compatibility_mode;
-}
+ } else {
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
+ return p_coords + Vector2i(-1, 2);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(0, 1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
+ return p_coords + Vector2i(1, 0);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, -1);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
+ return p_coords + Vector2i(1, -2);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(0, -1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
+ return p_coords + Vector2i(-1, 0);
+
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, 1);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
+ }
+ }
+ } break;
+ case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
+ case TileSet::TILE_LAYOUT_DIAMOND_DOWN: {
+ if ((tile_set->get_tile_layout() == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
+ return p_coords + Vector2i(1, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(0, 1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
+ return p_coords + Vector2i(-1, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, 0);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
+ return p_coords + Vector2i(-1, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(0, -1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
+ return p_coords + Vector2i(1, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, 0);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
-void TileMap::set_centered_textures(bool p_enable) {
- _clear_quadrants();
- centered_textures = p_enable;
- _recreate_quadrants();
- emit_signal("settings_changed");
-}
+ } else {
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
+ return p_coords + Vector2i(1, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, 0);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
+ return p_coords + Vector2i(1, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(0, -1);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
+ return p_coords + Vector2i(-1, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, 0);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
+ return p_coords + Vector2i(-1, 1);
+
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(0, 1);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
+ }
+ } else {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
+ return p_coords + Vector2i(1, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, 0);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
+ return p_coords + Vector2i(1, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(0, 1);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
+ return p_coords + Vector2i(-1, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, 0);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
+ return p_coords + Vector2i(-1, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(0, -1);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
-bool TileMap::is_centered_textures_enabled() const {
- return centered_textures;
+ } else {
+ if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
+ return p_coords + Vector2i(-1, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
+ return p_coords + Vector2i(0, 1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
+ return p_coords + Vector2i(1, 1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return p_coords + Vector2i(1, 0);
+ } else if ((shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
+ (shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
+ return p_coords + Vector2i(1, -1);
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
+ return p_coords + Vector2i(0, -1);
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
+ return p_coords + Vector2i(-1, -1);
+
+ } else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
+ return p_coords + Vector2i(-1, 0);
+ } else {
+ ERR_FAIL_V(p_coords);
+ }
+ }
+ }
+ } break;
+ default:
+ ERR_FAIL_V(p_coords);
+ }
+ }
}
TypedArray<Vector2i> TileMap::get_used_cells() const {
+ // Returns the cells used in the tilemap.
TypedArray<Vector2i> a;
a.resize(tile_map.size());
int i = 0;
- for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
+ for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
Vector2i p(E->key().x, E->key().y);
a[i++] = p;
}
@@ -1602,25 +1540,13 @@ TypedArray<Vector2i> TileMap::get_used_cells() const {
return a;
}
-TypedArray<Vector2i> TileMap::get_used_cells_by_index(int p_id) const {
- TypedArray<Vector2i> a;
- for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
- if (E->value().id == p_id) {
- Vector2i p(E->key().x, E->key().y);
- a.push_back(p);
- }
- }
-
- return a;
-}
-
Rect2 TileMap::get_used_rect() { // Not const because of cache
-
+ // Return the rect of the currently used area
if (used_size_cache_dirty) {
if (tile_map.size() > 0) {
used_size_cache = Rect2(tile_map.front()->key().x, tile_map.front()->key().y, 0, 0);
- for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
+ for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
used_size_cache.expand_to(Vector2(E->key().x, E->key().y));
}
@@ -1635,46 +1561,49 @@ Rect2 TileMap::get_used_rect() { // Not const because of cache
return used_size_cache;
}
-void TileMap::set_occluder_light_mask(int p_mask) {
- occluder_light_mask = 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()) {
- RenderingServer::get_singleton()->canvas_light_occluder_set_light_mask(F->get().id, occluder_light_mask);
- }
- }
-}
-
-int TileMap::get_occluder_light_mask() const {
- return occluder_light_mask;
-}
+// --- Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems ---
void TileMap::set_light_mask(int p_light_mask) {
+ // Occlusion: set light mask.
CanvasItem::set_light_mask(p_light_mask);
- for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
+ for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
for (List<RID>::Element *F = E->get().canvas_items.front(); F; F = F->next()) {
RenderingServer::get_singleton()->canvas_item_set_light_mask(F->get(), get_light_mask());
}
}
}
-void TileMap::set_clip_uv(bool p_enable) {
- if (clip_uv == p_enable) {
- return;
- }
+void TileMap::set_material(const Ref<Material> &p_material) {
+ // Set material for the whole tilemap.
+ CanvasItem::set_material(p_material);
- _clear_quadrants();
- clip_uv = p_enable;
- _recreate_quadrants();
+ // Update material for the whole tilemap.
+ for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
+ TileMapQuadrant &q = E->get();
+ for (List<RID>::Element *F = q.canvas_items.front(); F; F = F->next()) {
+ RS::get_singleton()->canvas_item_set_use_parent_material(F->get(), get_use_parent_material() || get_material().is_valid());
+ }
+ }
}
-bool TileMap::get_clip_uv() const {
- return clip_uv;
+void TileMap::set_use_parent_material(bool p_use_parent_material) {
+ // Set use_parent_material for the whole tilemap.
+ CanvasItem::set_use_parent_material(p_use_parent_material);
+
+ // Update use_parent_material for the whole tilemap.
+ for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
+ TileMapQuadrant &q = E->get();
+ for (List<RID>::Element *F = q.canvas_items.front(); F; F = F->next()) {
+ RS::get_singleton()->canvas_item_set_use_parent_material(F->get(), get_use_parent_material() || get_material().is_valid());
+ }
+ }
}
void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
+ // Set a default texture filter for the whole tilemap
CanvasItem::set_texture_filter(p_texture_filter);
- for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) {
- Quadrant &q = F->get();
+ for (Map<Vector2i, TileMapQuadrant>::Element *F = quadrant_map.front(); F; F = F->next()) {
+ TileMapQuadrant &q = F->get();
for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(E->get(), RS::CanvasItemTextureFilter(p_texture_filter));
_make_quadrant_dirty(F);
@@ -1683,9 +1612,10 @@ void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
}
void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
+ // Set a default texture repeat for the whole tilemap
CanvasItem::set_texture_repeat(p_texture_repeat);
- for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) {
- Quadrant &q = F->get();
+ for (Map<Vector2i, TileMapQuadrant>::Element *F = quadrant_map.front(); F; F = F->next()) {
+ TileMapQuadrant &q = F->get();
for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(E->get(), RS::CanvasItemTextureRepeat(p_texture_repeat));
_make_quadrant_dirty(F);
@@ -1693,160 +1623,149 @@ void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
}
}
-TypedArray<String> TileMap::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+TypedArray<Vector2i> TileMap::get_surrounding_tiles(Vector2i coords) {
+ if (!tile_set.is_valid()) {
+ return TypedArray<Vector2i>();
+ }
- if (use_parent && !collision_parent) {
- warnings.push_back(TTR("TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));
+ TypedArray<Vector2i> around;
+ TileSet::TileShape shape = tile_set->get_tile_shape();
+ if (shape == TileSet::TILE_SHAPE_SQUARE) {
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_SIDE));
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
+ } else {
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
+ } else {
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_SIDE));
+ around.push_back(get_neighbor_cell(coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
+ }
}
- return warnings;
+ return around;
}
-void TileMap::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMap::set_tileset);
- ClassDB::bind_method(D_METHOD("get_tileset"), &TileMap::get_tileset);
-
- ClassDB::bind_method(D_METHOD("set_mode", "mode"), &TileMap::set_mode);
- ClassDB::bind_method(D_METHOD("get_mode"), &TileMap::get_mode);
+void TileMap::draw_cells_outline(Control *p_control, Set<Vector2i> p_cells, Color p_color, Transform2D p_transform) {
+ if (!tile_set.is_valid()) {
+ return;
+ }
- ClassDB::bind_method(D_METHOD("set_half_offset", "half_offset"), &TileMap::set_half_offset);
- ClassDB::bind_method(D_METHOD("get_half_offset"), &TileMap::get_half_offset);
+ // Create a set.
+ Vector2i tile_size = tile_set->get_tile_size();
+ Vector<Vector2> uvs;
- ClassDB::bind_method(D_METHOD("set_custom_transform", "custom_transform"), &TileMap::set_custom_transform);
- ClassDB::bind_method(D_METHOD("get_custom_transform"), &TileMap::get_custom_transform);
+ if (tile_set->get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) {
+ uvs.append(Vector2(1.0, 0.0));
+ uvs.append(Vector2(1.0, 1.0));
+ uvs.append(Vector2(0.0, 1.0));
+ uvs.append(Vector2(0.0, 0.0));
+ } else {
+ float overlap = 0.0;
+ switch (tile_set->get_tile_shape()) {
+ case TileSet::TILE_SHAPE_ISOMETRIC:
+ overlap = 0.5;
+ break;
+ case TileSet::TILE_SHAPE_HEXAGON:
+ overlap = 0.25;
+ break;
+ case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
+ overlap = 0.0;
+ break;
+ default:
+ break;
+ }
+ uvs.append(Vector2(1.0, overlap));
+ uvs.append(Vector2(1.0, 1.0 - overlap));
+ uvs.append(Vector2(0.5, 1.0));
+ uvs.append(Vector2(0.0, 1.0 - overlap));
+ uvs.append(Vector2(0.0, overlap));
+ uvs.append(Vector2(0.5, 0.0));
+ if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
+ for (int i = 0; i < uvs.size(); i++) {
+ uvs.write[i] = Vector2(uvs[i].y, uvs[i].x);
+ }
+ }
+ }
- ClassDB::bind_method(D_METHOD("set_cell_size", "size"), &TileMap::set_cell_size);
- ClassDB::bind_method(D_METHOD("get_cell_size"), &TileMap::get_cell_size);
+ for (Set<Vector2i>::Element *E = p_cells.front(); E; E = E->next()) {
+ Vector2 top_left = map_to_world(E->get()) - tile_size / 2;
+ TypedArray<Vector2i> surrounding_tiles = get_surrounding_tiles(E->get());
+ for (int i = 0; i < surrounding_tiles.size(); i++) {
+ if (!p_cells.has(surrounding_tiles[i])) {
+ p_control->draw_line(p_transform.xform(top_left + uvs[i] * tile_size), p_transform.xform(top_left + uvs[(i + 1) % uvs.size()] * tile_size), p_color);
+ }
+ }
+ }
+}
- ClassDB::bind_method(D_METHOD("_set_old_cell_size", "size"), &TileMap::_set_old_cell_size);
- ClassDB::bind_method(D_METHOD("_get_old_cell_size"), &TileMap::_get_old_cell_size);
+void TileMap::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMap::set_tileset);
+ ClassDB::bind_method(D_METHOD("get_tileset"), &TileMap::get_tileset);
ClassDB::bind_method(D_METHOD("set_quadrant_size", "size"), &TileMap::set_quadrant_size);
ClassDB::bind_method(D_METHOD("get_quadrant_size"), &TileMap::get_quadrant_size);
- ClassDB::bind_method(D_METHOD("set_tile_origin", "origin"), &TileMap::set_tile_origin);
- ClassDB::bind_method(D_METHOD("get_tile_origin"), &TileMap::get_tile_origin);
-
- ClassDB::bind_method(D_METHOD("set_clip_uv", "enable"), &TileMap::set_clip_uv);
- ClassDB::bind_method(D_METHOD("get_clip_uv"), &TileMap::get_clip_uv);
-
- ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enable"), &TileMap::set_y_sort_enabled);
- ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &TileMap::is_y_sort_enabled);
+ ClassDB::bind_method(D_METHOD("set_collision_visibility_mode", "show_collision"), &TileMap::set_collision_visibility_mode);
+ ClassDB::bind_method(D_METHOD("get_collision_visibility_mode"), &TileMap::get_collision_visibility_mode);
- ClassDB::bind_method(D_METHOD("set_compatibility_mode", "enable"), &TileMap::set_compatibility_mode);
- ClassDB::bind_method(D_METHOD("is_compatibility_mode_enabled"), &TileMap::is_compatibility_mode_enabled);
+ ClassDB::bind_method(D_METHOD("set_navigation_visibility_mode", "show_navigation"), &TileMap::set_navigation_visibility_mode);
+ ClassDB::bind_method(D_METHOD("get_navigation_visibility_mode"), &TileMap::get_navigation_visibility_mode);
- ClassDB::bind_method(D_METHOD("set_centered_textures", "enable"), &TileMap::set_centered_textures);
- ClassDB::bind_method(D_METHOD("is_centered_textures_enabled"), &TileMap::is_centered_textures_enabled);
-
- ClassDB::bind_method(D_METHOD("set_collision_use_kinematic", "use_kinematic"), &TileMap::set_collision_use_kinematic);
- ClassDB::bind_method(D_METHOD("get_collision_use_kinematic"), &TileMap::get_collision_use_kinematic);
-
- ClassDB::bind_method(D_METHOD("set_collision_use_parent", "use_parent"), &TileMap::set_collision_use_parent);
- ClassDB::bind_method(D_METHOD("get_collision_use_parent"), &TileMap::get_collision_use_parent);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &TileMap::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &TileMap::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &TileMap::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &TileMap::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &TileMap::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &TileMap::get_collision_layer_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &TileMap::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &TileMap::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_friction", "value"), &TileMap::set_collision_friction);
- ClassDB::bind_method(D_METHOD("get_collision_friction"), &TileMap::get_collision_friction);
-
- ClassDB::bind_method(D_METHOD("set_collision_bounce", "value"), &TileMap::set_collision_bounce);
- ClassDB::bind_method(D_METHOD("get_collision_bounce"), &TileMap::get_collision_bounce);
-
- ClassDB::bind_method(D_METHOD("set_bake_navigation", "bake_navigation"), &TileMap::set_bake_navigation);
- ClassDB::bind_method(D_METHOD("is_baking_navigation"), &TileMap::is_baking_navigation);
-
- ClassDB::bind_method(D_METHOD("set_occluder_light_mask", "mask"), &TileMap::set_occluder_light_mask);
- ClassDB::bind_method(D_METHOD("get_occluder_light_mask"), &TileMap::get_occluder_light_mask);
-
- ClassDB::bind_method(D_METHOD("set_cell", "x", "y", "tile", "flip_x", "flip_y", "transpose", "autotile_coord"), &TileMap::set_cell, DEFVAL(false), DEFVAL(false), DEFVAL(false), DEFVAL(Vector2()));
- ClassDB::bind_method(D_METHOD("set_cellv", "position", "tile", "flip_x", "flip_y", "transpose"), &TileMap::set_cellv, DEFVAL(false), DEFVAL(false), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("_set_celld", "position", "data"), &TileMap::_set_celld);
- ClassDB::bind_method(D_METHOD("get_cell", "x", "y"), &TileMap::get_cell);
- ClassDB::bind_method(D_METHOD("get_cellv", "position"), &TileMap::get_cellv);
- ClassDB::bind_method(D_METHOD("is_cell_x_flipped", "x", "y"), &TileMap::is_cell_x_flipped);
- ClassDB::bind_method(D_METHOD("is_cell_y_flipped", "x", "y"), &TileMap::is_cell_y_flipped);
- ClassDB::bind_method(D_METHOD("is_cell_transposed", "x", "y"), &TileMap::is_cell_transposed);
-
- ClassDB::bind_method(D_METHOD("get_cell_autotile_coord", "x", "y"), &TileMap::get_cell_autotile_coord);
+ ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(-1), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE));
+ ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMap::get_cell_source_id);
+ ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "coords"), &TileMap::get_cell_atlas_coords);
+ ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "coords"), &TileMap::get_cell_alternative_tile);
ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles);
+ ClassDB::bind_method(D_METHOD("get_surrounding_tiles", "coords"), &TileMap::get_surrounding_tiles);
ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear);
ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMap::get_used_cells);
- ClassDB::bind_method(D_METHOD("get_used_cells_by_index", "index"), &TileMap::get_used_cells_by_index);
ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect);
- ClassDB::bind_method(D_METHOD("map_to_world", "map_position", "ignore_half_ofs"), &TileMap::map_to_world, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("map_to_world", "map_position"), &TileMap::map_to_world);
ClassDB::bind_method(D_METHOD("world_to_map", "world_position"), &TileMap::world_to_map);
- ClassDB::bind_method(D_METHOD("_clear_quadrants"), &TileMap::_clear_quadrants);
- ClassDB::bind_method(D_METHOD("update_dirty_quadrants"), &TileMap::update_dirty_quadrants);
+ ClassDB::bind_method(D_METHOD("get_neighbor_cell", "coords", "neighbor"), &TileMap::get_neighbor_cell);
- ClassDB::bind_method(D_METHOD("update_bitmask_area", "position"), &TileMap::update_bitmask_area);
- ClassDB::bind_method(D_METHOD("update_bitmask_region", "start", "end"), &TileMap::update_bitmask_region, DEFVAL(Vector2()), DEFVAL(Vector2()));
+ ClassDB::bind_method(D_METHOD("update_dirty_quadrants"), &TileMap::update_dirty_quadrants);
ClassDB::bind_method(D_METHOD("_set_tile_data"), &TileMap::_set_tile_data);
ClassDB::bind_method(D_METHOD("_get_tile_data"), &TileMap::_get_tile_data);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Square,Isometric,Custom"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset");
-
- ADD_GROUP("Cell", "cell_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size", PROPERTY_HINT_RANGE, "1,8192,1"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_quadrant_size", "get_quadrant_size");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "cell_custom_transform"), "set_custom_transform", "get_custom_transform");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_half_offset", PROPERTY_HINT_ENUM, "Offset X,Offset Y,Disabled,Offset Negative X,Offset Negative Y"), "set_half_offset", "get_half_offset");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_tile_origin", PROPERTY_HINT_ENUM, "Top Left,Center,Bottom Left"), "set_tile_origin", "get_tile_origin");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_y_sort"), "set_y_sort_enabled", "is_y_sort_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "compatibility_mode"), "set_compatibility_mode", "is_compatibility_mode_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered_textures"), "set_centered_textures", "is_centered_textures_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_clip_uv"), "set_clip_uv", "get_clip_uv");
-
- ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_parent", PROPERTY_HINT_NONE, ""), "set_collision_use_parent", "get_collision_use_parent");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_kinematic", PROPERTY_HINT_NONE, ""), "set_collision_use_kinematic", "get_collision_use_kinematic");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
-
- ADD_GROUP("Occluder", "occluder_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "occluder_light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask");
-
- ADD_GROUP("Navigation", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_navigation"), "set_bake_navigation", "is_baking_navigation");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "show_collision", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_collision_visibility_mode", "get_collision_visibility_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "show_navigation", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_navigation_visibility_mode", "get_navigation_visibility_mode");
ADD_PROPERTY_DEFAULT("format", FORMAT_1);
- ADD_SIGNAL(MethodInfo("settings_changed"));
-
- BIND_CONSTANT(INVALID_CELL);
-
- BIND_ENUM_CONSTANT(MODE_SQUARE);
- BIND_ENUM_CONSTANT(MODE_ISOMETRIC);
- BIND_ENUM_CONSTANT(MODE_CUSTOM);
+ ADD_SIGNAL(MethodInfo("changed"));
- BIND_ENUM_CONSTANT(HALF_OFFSET_X);
- BIND_ENUM_CONSTANT(HALF_OFFSET_Y);
- BIND_ENUM_CONSTANT(HALF_OFFSET_DISABLED);
- BIND_ENUM_CONSTANT(HALF_OFFSET_NEGATIVE_X);
- BIND_ENUM_CONSTANT(HALF_OFFSET_NEGATIVE_Y);
+ BIND_ENUM_CONSTANT(VISIBILITY_MODE_DEFAULT);
+ BIND_ENUM_CONSTANT(VISIBILITY_MODE_FORCE_HIDE);
+ BIND_ENUM_CONSTANT(VISIBILITY_MODE_FORCE_SHOW);
+}
- BIND_ENUM_CONSTANT(TILE_ORIGIN_TOP_LEFT);
- BIND_ENUM_CONSTANT(TILE_ORIGIN_CENTER);
- BIND_ENUM_CONSTANT(TILE_ORIGIN_BOTTOM_LEFT);
+void TileMap::_tile_set_changed() {
+ emit_signal("changed");
+ _make_all_quadrants_dirty(true);
}
TileMap::TileMap() {
@@ -1855,5 +1774,8 @@ TileMap::TileMap() {
}
TileMap::~TileMap() {
- clear();
+ if (tile_set.is_valid()) {
+ tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed));
+ }
+ _clear_quadrants();
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 9d27053fee..3001e6b471 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -34,193 +34,204 @@
#include "core/templates/self_list.h"
#include "core/templates/vset.h"
#include "scene/2d/node_2d.h"
+#include "scene/gui/control.h"
#include "scene/resources/tile_set.h"
-class CollisionObject2D;
+class TileSetAtlasSource;
-class TileMap : public Node2D {
- GDCLASS(TileMap, Node2D);
-
-public:
- enum Mode {
- MODE_SQUARE,
- MODE_ISOMETRIC,
- MODE_CUSTOM
- };
-
- enum HalfOffset {
- HALF_OFFSET_X,
- HALF_OFFSET_Y,
- HALF_OFFSET_DISABLED,
- HALF_OFFSET_NEGATIVE_X,
- HALF_OFFSET_NEGATIVE_Y,
- };
-
- enum TileOrigin {
- TILE_ORIGIN_TOP_LEFT,
- TILE_ORIGIN_CENTER,
- TILE_ORIGIN_BOTTOM_LEFT
- };
-
-private:
- enum DataFormat {
- FORMAT_1 = 0,
- FORMAT_2
+union TileMapCell {
+ struct {
+ int32_t source_id : 16;
+ int16_t coord_x : 16;
+ int16_t coord_y : 16;
+ int32_t alternative_tile : 16;
};
- Ref<TileSet> tile_set;
- Size2i cell_size = Size2(64, 64);
- int quadrant_size = 16;
- Mode mode = MODE_SQUARE;
- Transform2D custom_transform = Transform2D(64, 0, 0, 64, 0, 0);
- HalfOffset half_offset = HALF_OFFSET_DISABLED;
- bool use_parent = false;
- CollisionObject2D *collision_parent = nullptr;
- bool use_kinematic = false;
- bool bake_navigation = false;
-
- union PosKey {
- struct {
- int16_t x;
- int16_t y;
- };
- uint32_t key = 0;
-
- //using a more precise comparison so the regions can be sorted later
- bool operator<(const PosKey &p_k) const { return (y == p_k.y) ? x < p_k.x : y < p_k.y; }
-
- bool operator==(const PosKey &p_k) const { return (y == p_k.y && x == p_k.x); }
-
- PosKey to_quadrant(const int &p_quadrant_size) const {
- // rounding down, instead of simply rounding towards zero (truncating)
- return PosKey(
- x > 0 ? x / p_quadrant_size : (x - (p_quadrant_size - 1)) / p_quadrant_size,
- y > 0 ? y / p_quadrant_size : (y - (p_quadrant_size - 1)) / p_quadrant_size);
+ uint64_t _u64t;
+ TileMapCell(int p_source_id = -1, Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) {
+ source_id = p_source_id;
+ set_atlas_coords(p_atlas_coords);
+ alternative_tile = p_alternative_tile;
+ }
+
+ Vector2i get_atlas_coords() const {
+ return Vector2i(coord_x, coord_y);
+ }
+
+ void set_atlas_coords(const Vector2i &r_coords) {
+ coord_x = r_coords.x;
+ coord_y = r_coords.y;
+ }
+
+ bool operator<(const TileMapCell &p_other) const {
+ if (source_id == p_other.source_id) {
+ if (coord_x == p_other.coord_x) {
+ if (coord_y == p_other.coord_y) {
+ return alternative_tile < p_other.alternative_tile;
+ } else {
+ return coord_y < p_other.coord_y;
+ }
+ } else {
+ return coord_x < p_other.coord_x;
+ }
+ } else {
+ return source_id < p_other.source_id;
}
+ }
- PosKey(int16_t p_x, int16_t p_y) {
- x = p_x;
- y = p_y;
- }
- PosKey() {
- x = 0;
- y = 0;
+ bool operator!=(const TileMapCell &p_other) const {
+ return !(source_id == p_other.source_id && coord_x == p_other.coord_x && coord_y == p_other.coord_y && alternative_tile == p_other.alternative_tile);
+ }
+};
+
+struct TileMapQuadrant {
+ struct CoordsWorldComparator {
+ _ALWAYS_INLINE_ bool operator()(const Vector2i &p_a, const Vector2i &p_b) const {
+ // We sort the cells by their world coords, as it is needed by rendering.
+ if (p_a.y == p_b.y) {
+ return p_a.x > p_b.x;
+ } else {
+ return p_a.y < p_b.y;
+ }
}
};
- union Cell {
- struct {
- int32_t id : 24;
- bool flip_h : 1;
- bool flip_v : 1;
- bool transpose : 1;
- int16_t autotile_coord_x : 16;
- int16_t autotile_coord_y : 16;
- };
-
- uint64_t _u64t = 0;
- };
+ // Dirty list element
+ SelfList<TileMapQuadrant> dirty_list_element;
+
+ // Quadrant coords.
+ Vector2i coords;
+
+ // TileMapCells
+ Set<Vector2i> cells;
+ // We need those two maps to sort by world position for rendering
+ // This is kind of workaround, it would be better to sort the cells directly in the "cells" set instead.
+ Map<Vector2i, Vector2i> map_to_world;
+ Map<Vector2i, Vector2i, CoordsWorldComparator> world_to_map;
+
+ // Debug.
+ RID debug_canvas_item;
+
+ // Rendering.
+ List<RID> canvas_items;
+ List<RID> occluders;
+
+ // Physics.
+ List<RID> bodies;
+
+ // Navigation.
+ Map<Vector2i, Vector<RID>> navigation_regions;
+
+ // Scenes.
+ Map<Vector2i, String> scenes;
+
+ void operator=(const TileMapQuadrant &q) {
+ coords = q.coords;
+ debug_canvas_item = q.debug_canvas_item;
+ canvas_items = q.canvas_items;
+ occluders = q.occluders;
+ bodies = q.bodies;
+ navigation_regions = q.navigation_regions;
+ }
+
+ TileMapQuadrant(const TileMapQuadrant &q) :
+ dirty_list_element(this) {
+ coords = q.coords;
+ debug_canvas_item = q.debug_canvas_item;
+ canvas_items = q.canvas_items;
+ occluders = q.occluders;
+ bodies = q.bodies;
+ navigation_regions = q.navigation_regions;
+ }
+
+ TileMapQuadrant() :
+ dirty_list_element(this) {
+ }
+};
- Map<PosKey, Cell> tile_map;
- List<PosKey> dirty_bitmask;
+class TileMapPattern : public Object {
+ GDCLASS(TileMapPattern, Object);
- struct Quadrant {
- Vector2 pos;
- List<RID> canvas_items;
- RID body;
- uint32_t shape_owner_id = 0;
+ Vector2i size;
+ Map<Vector2i, TileMapCell> pattern;
- SelfList<Quadrant> dirty_list;
+protected:
+ static void _bind_methods();
- struct NavPoly {
- RID region;
- Transform2D xform;
- };
+public:
+ void set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile = 0);
+ bool has_cell(const Vector2i &p_coords) const;
+ void remove_cell(const Vector2i &p_coords, bool p_update_size = true);
+ int get_cell_source_id(const Vector2i &p_coords) const;
+ Vector2i get_cell_atlas_coords(const Vector2i &p_coords) const;
+ int get_cell_alternative_tile(const Vector2i &p_coords) const;
- struct Occluder {
- RID id;
- Transform2D xform;
- };
+ TypedArray<Vector2i> get_used_cells() const;
- Map<PosKey, NavPoly> navpoly_ids;
- Map<PosKey, Occluder> occluder_instances;
+ Vector2i get_size() const;
+ void set_size(const Vector2i &p_size);
+ bool is_empty() const;
- VSet<PosKey> cells;
+ void clear();
+};
- void operator=(const Quadrant &q) {
- pos = q.pos;
- canvas_items = q.canvas_items;
- body = q.body;
- shape_owner_id = q.shape_owner_id;
- cells = q.cells;
- navpoly_ids = q.navpoly_ids;
- occluder_instances = q.occluder_instances;
- }
- Quadrant(const Quadrant &q) :
- dirty_list(this) {
- pos = q.pos;
- canvas_items = q.canvas_items;
- body = q.body;
- shape_owner_id = q.shape_owner_id;
- cells = q.cells;
- occluder_instances = q.occluder_instances;
- navpoly_ids = q.navpoly_ids;
- }
- Quadrant() :
- dirty_list(this) {}
+class TileMap : public Node2D {
+ GDCLASS(TileMap, Node2D);
+
+public:
+ enum VisibilityMode {
+ VISIBILITY_MODE_DEFAULT,
+ VISIBILITY_MODE_FORCE_SHOW,
+ VISIBILITY_MODE_FORCE_HIDE,
};
- Map<PosKey, Quadrant> quadrant_map;
+private:
+ friend class TileSetPlugin;
- SelfList<Quadrant>::List dirty_quadrant_list;
+ // A compatibility enum to specify how is the data if formatted.
+ enum DataFormat {
+ FORMAT_1 = 0,
+ FORMAT_2,
+ FORMAT_3
+ };
+ mutable DataFormat format = FORMAT_1; // Assume lowest possible format if none is present;
+ // Properties.
+ Ref<TileSet> tile_set;
+ int quadrant_size = 16;
+ VisibilityMode show_collision = VISIBILITY_MODE_DEFAULT;
+ VisibilityMode show_navigation = VISIBILITY_MODE_DEFAULT;
+
+ // Updates.
bool pending_update = false;
+ // Rect.
Rect2 rect_cache;
bool rect_cache_dirty = true;
Rect2 used_size_cache;
bool used_size_cache_dirty = true;
- bool quadrant_order_dirty = false;
- bool use_y_sort = false;
- bool compatibility_mode = false;
- bool centered_textures = false;
- bool clip_uv = false;
- float fp_adjust = 0.00001;
- float friction = 1.0;
- float bounce = 0.0;
- uint32_t collision_layer = 1;
- uint32_t collision_mask = 1;
- mutable DataFormat format = FORMAT_1; // Assume lowest possible format if none is present
-
- TileOrigin tile_origin = TILE_ORIGIN_TOP_LEFT;
-
- int occluder_light_mask = 1;
- void _fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Vector2 &p_offset, const Size2 &p_sc);
+ // Map of cells.
+ Map<Vector2i, TileMapCell> tile_map;
- void _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);
+ // Quadrants management.
+ Map<Vector2i, TileMapQuadrant> quadrant_map;
+ Vector2i _coords_to_quadrant_coords(const Vector2i &p_coords) const;
+ SelfList<TileMapQuadrant>::List dirty_quadrant_list;
- Map<PosKey, Quadrant>::Element *_create_quadrant(const PosKey &p_qk);
- void _erase_quadrant(Map<PosKey, Quadrant>::Element *Q);
- void _make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool update = true);
+ Map<Vector2i, TileMapQuadrant>::Element *_create_quadrant(const Vector2i &p_qk);
+ void _erase_quadrant(Map<Vector2i, TileMapQuadrant>::Element *Q);
+ void _make_all_quadrants_dirty(bool p_update = true);
+ void _make_quadrant_dirty(Map<Vector2i, TileMapQuadrant>::Element *Q, bool p_update = true);
void _recreate_quadrants();
void _clear_quadrants();
- void _update_quadrant_space(const RID &p_space);
- void _update_quadrant_transform();
void _recompute_rect_cache();
- void _update_all_items_material_state();
- _FORCE_INLINE_ void _update_item_material_state(const RID &p_canvas_item);
-
- _FORCE_INLINE_ int _get_quadrant_size() const;
-
+ // Set and get tiles from data arrays.
void _set_tile_data(const Vector<int> &p_data);
Vector<int> _get_tile_data() const;
- void _set_old_cell_size(int p_size) { set_cell_size(Size2(p_size, p_size)); }
- int _get_old_cell_size() const { return cell_size.x; }
-
- _FORCE_INLINE_ Vector2 _map_to_world(int p_x, int p_y, bool p_ignore_ofs = false) const;
+ void _tile_set_changed();
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -230,9 +241,9 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
-
public:
+ static Vector2i transform_coords_layout(Vector2i p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout);
+
enum {
INVALID_CELL = -1
};
@@ -244,117 +255,59 @@ public:
void set_tileset(const Ref<TileSet> &p_tileset);
Ref<TileSet> get_tileset() const;
- void set_cell_size(Size2 p_size);
- Size2 get_cell_size() const;
-
void set_quadrant_size(int p_size);
int get_quadrant_size() const;
- void set_cell(int p_x, int p_y, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false, Vector2 p_autotile_coord = Vector2());
- int get_cell(int p_x, int p_y) const;
- bool is_cell_x_flipped(int p_x, int p_y) const;
- bool is_cell_y_flipped(int p_x, int p_y) const;
- bool is_cell_transposed(int p_x, int p_y) const;
- void set_cell_autotile_coord(int p_x, int p_y, const Vector2 &p_coord);
- Vector2 get_cell_autotile_coord(int p_x, int p_y) const;
-
- void _set_celld(const Vector2 &p_pos, const Dictionary &p_data);
- void set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false);
- int get_cellv(const Vector2 &p_pos) const;
-
- void make_bitmask_area_dirty(const Vector2 &p_pos);
- void update_bitmask_area(const Vector2 &p_pos);
- void update_bitmask_region(const Vector2 &p_start = Vector2(), const Vector2 &p_end = Vector2());
- void update_cell_bitmask(int p_x, int p_y);
- void update_dirty_bitmask();
-
- void update_dirty_quadrants();
-
- 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_visibility_mode(VisibilityMode p_show_collision);
+ VisibilityMode get_collision_visibility_mode();
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_navigation_visibility_mode(VisibilityMode p_show_navigation);
+ VisibilityMode get_navigation_visibility_mode();
- void set_collision_use_kinematic(bool p_use_kinematic);
- bool get_collision_use_kinematic() const;
+ void set_cell(const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE);
+ int get_cell_source_id(const Vector2i &p_coords) const;
+ Vector2i get_cell_atlas_coords(const Vector2i &p_coords) const;
+ int get_cell_alternative_tile(const Vector2i &p_coords) const;
- void set_collision_use_parent(bool p_use_parent);
- bool get_collision_use_parent() const;
+ TileMapPattern *get_pattern(TypedArray<Vector2i> p_coords_array);
+ Vector2i map_pattern(Vector2i p_position_in_tilemap, Vector2i p_coords_in_pattern, const TileMapPattern *p_pattern);
+ void set_pattern(Vector2i p_position, const TileMapPattern *p_pattern);
- void set_collision_friction(float p_friction);
- float get_collision_friction() const;
+ // Not exposed to users
+ TileMapCell get_cell(const Vector2i &p_coords) const;
+ Map<Vector2i, TileMapQuadrant> &get_quadrant_map();
+ int get_effective_quadrant_size() const;
- void set_collision_bounce(float p_bounce);
- float get_collision_bounce() const;
-
- void set_bake_navigation(bool p_bake_navigation);
- bool is_baking_navigation();
-
- void set_mode(Mode p_mode);
- Mode get_mode() const;
-
- void set_half_offset(HalfOffset p_half_offset);
- HalfOffset get_half_offset() const;
-
- void set_tile_origin(TileOrigin p_tile_origin);
- TileOrigin get_tile_origin() const;
-
- void set_custom_transform(const Transform2D &p_xform);
- Transform2D get_custom_transform() const;
-
- Transform2D get_cell_transform() const;
- Vector2 get_cell_draw_offset() const;
-
- Vector2 map_to_world(const Vector2 &p_pos, bool p_ignore_ofs = false) const;
- Vector2 world_to_map(const Vector2 &p_pos) const;
-
- void set_y_sort_enabled(bool p_enable);
- bool is_y_sort_enabled() const;
+ void update_dirty_quadrants();
+ virtual void set_y_sort_enabled(bool p_enable) override;
- void set_compatibility_mode(bool p_enable);
- bool is_compatibility_mode_enabled() const;
+ Vector2 map_to_world(const Vector2i &p_pos) const;
+ Vector2i world_to_map(const Vector2 &p_pos) const;
- void set_centered_textures(bool p_enable);
- bool is_centered_textures_enabled() const;
+ bool is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const;
+ Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const;
TypedArray<Vector2i> get_used_cells() const;
- TypedArray<Vector2i> get_used_cells_by_index(int p_index) const;
Rect2 get_used_rect(); // Not const because of cache
- void set_occluder_light_mask(int p_mask);
- int get_occluder_light_mask() const;
-
+ // Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems
virtual void set_light_mask(int p_light_mask) override;
-
virtual void set_material(const Ref<Material> &p_material) override;
-
virtual void set_use_parent_material(bool p_use_parent_material) override;
-
- void set_clip_uv(bool p_enable);
- bool get_clip_uv() const;
-
- TypedArray<String> get_configuration_warnings() const override;
-
virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override;
-
virtual void set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) override;
void fix_invalid_tiles();
void clear();
+ // Helpers
+ TypedArray<Vector2i> get_surrounding_tiles(Vector2i coords);
+ void draw_cells_outline(Control *p_control, Set<Vector2i> p_cells, Color p_color, Transform2D p_transform = Transform2D());
+
TileMap();
~TileMap();
};
-VARIANT_ENUM_CAST(TileMap::Mode);
-VARIANT_ENUM_CAST(TileMap::HalfOffset);
-VARIANT_ENUM_CAST(TileMap::TileOrigin);
+VARIANT_ENUM_CAST(TileMap::VisibilityMode);
#endif // TILE_MAP_H
diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp
index 8feb47f1cc..a73d60ada5 100644
--- a/scene/2d/visibility_notifier_2d.cpp
+++ b/scene/2d/visibility_notifier_2d.cpp
@@ -48,46 +48,29 @@ bool VisibilityNotifier2D::_edit_use_rect() const {
}
#endif
-void VisibilityNotifier2D::_enter_viewport(Viewport *p_viewport) {
- ERR_FAIL_COND(viewports.has(p_viewport));
- viewports.insert(p_viewport);
-
- if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) {
+void VisibilityNotifier2D::_visibility_enter() {
+ if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
return;
}
- if (viewports.size() == 1) {
- emit_signal(SceneStringNames::get_singleton()->screen_entered);
-
- _screen_enter();
- }
- emit_signal(SceneStringNames::get_singleton()->viewport_entered, p_viewport);
+ on_screen = true;
+ emit_signal(SceneStringNames::get_singleton()->screen_entered);
+ _screen_enter();
}
-
-void VisibilityNotifier2D::_exit_viewport(Viewport *p_viewport) {
- ERR_FAIL_COND(!viewports.has(p_viewport));
- viewports.erase(p_viewport);
-
- if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) {
+void VisibilityNotifier2D::_visibility_exit() {
+ if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
return;
}
- emit_signal(SceneStringNames::get_singleton()->viewport_exited, p_viewport);
- if (viewports.size() == 0) {
- emit_signal(SceneStringNames::get_singleton()->screen_exited);
-
- _screen_exit();
- }
+ on_screen = false;
+ emit_signal(SceneStringNames::get_singleton()->screen_exited);
+ _screen_exit();
}
void VisibilityNotifier2D::set_rect(const Rect2 &p_rect) {
rect = p_rect;
if (is_inside_tree()) {
- get_world_2d()->_update_notifier(this, get_global_transform().xform(rect));
- if (Engine::get_singleton()->is_editor_hint()) {
- update();
- item_rect_changed();
- }
+ RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibilityNotifier2D::_visibility_enter), callable_mp(this, &VisibilityNotifier2D::_visibility_exit));
}
}
@@ -99,11 +82,8 @@ void VisibilityNotifier2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
//get_world_2d()->
- get_world_2d()->_register_notifier(this, get_global_transform().xform(rect));
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
- //get_world_2d()->
- get_world_2d()->_update_notifier(this, get_global_transform().xform(rect));
+ on_screen = false;
+ RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibilityNotifier2D::_visibility_enter), callable_mp(this, &VisibilityNotifier2D::_visibility_exit));
} break;
case NOTIFICATION_DRAW: {
if (Engine::get_singleton()->is_editor_hint()) {
@@ -111,13 +91,14 @@ void VisibilityNotifier2D::_notification(int p_what) {
}
} break;
case NOTIFICATION_EXIT_TREE: {
- get_world_2d()->_remove_notifier(this);
+ on_screen = false;
+ RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), false, Rect2(), Callable(), Callable());
} break;
}
}
bool VisibilityNotifier2D::is_on_screen() const {
- return viewports.size() > 0;
+ return on_screen;
}
void VisibilityNotifier2D::_bind_methods() {
@@ -127,235 +108,106 @@ void VisibilityNotifier2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "rect"), "set_rect", "get_rect");
- ADD_SIGNAL(MethodInfo("viewport_entered", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport")));
- ADD_SIGNAL(MethodInfo("viewport_exited", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport")));
ADD_SIGNAL(MethodInfo("screen_entered"));
ADD_SIGNAL(MethodInfo("screen_exited"));
}
VisibilityNotifier2D::VisibilityNotifier2D() {
rect = Rect2(-10, -10, 20, 20);
- set_notify_transform(true);
}
//////////////////////////////////////
void VisibilityEnabler2D::_screen_enter() {
- for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
- _change_node_state(E->key(), true);
- }
-
- if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) {
- get_parent()->set_physics_process(true);
- }
- if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) {
- get_parent()->set_process(true);
- }
-
- visible = true;
+ _update_enable_mode(true);
}
void VisibilityEnabler2D::_screen_exit() {
- for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
- _change_node_state(E->key(), false);
- }
-
- if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) {
- get_parent()->set_physics_process(false);
- }
- if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) {
- get_parent()->set_process(false);
- }
-
- visible = false;
+ _update_enable_mode(false);
}
-void VisibilityEnabler2D::_find_nodes(Node *p_node) {
- bool add = false;
- Variant meta;
-
- {
- RigidBody2D *rb2d = Object::cast_to<RigidBody2D>(p_node);
- if (rb2d && ((rb2d->get_mode() == RigidBody2D::MODE_CHARACTER || rb2d->get_mode() == RigidBody2D::MODE_RIGID))) {
- add = true;
- meta = rb2d->get_mode();
- }
- }
-
- {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
- if (ap) {
- add = true;
- }
- }
-
- {
- AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node);
- if (as) {
- add = true;
- }
- }
-
- {
- GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
- if (ps) {
- add = true;
- }
+void VisibilityEnabler2D::set_enable_mode(EnableMode p_mode) {
+ enable_mode = p_mode;
+ if (is_inside_tree()) {
+ _update_enable_mode(is_on_screen());
}
+}
+VisibilityEnabler2D::EnableMode VisibilityEnabler2D::get_enable_mode() {
+ return enable_mode;
+}
- if (add) {
- p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler2D::_node_removed), varray(p_node), CONNECT_ONESHOT);
- nodes[p_node] = meta;
- _change_node_state(p_node, false);
+void VisibilityEnabler2D::set_enable_node_path(NodePath p_path) {
+ if (enable_node_path == p_path) {
+ return;
}
-
- 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
+ enable_node_path = p_path;
+ if (is_inside_tree()) {
+ node_id = ObjectID();
+ Node *node = get_node(enable_node_path);
+ if (node) {
+ node_id = node->get_instance_id();
+ _update_enable_mode(is_on_screen());
+ }
+ }
+}
+NodePath VisibilityEnabler2D::get_enable_node_path() {
+ return enable_node_path;
+}
+
+void VisibilityEnabler2D::_update_enable_mode(bool p_enable) {
+ Node *node = static_cast<Node *>(ObjectDB::get_instance(node_id));
+ if (node) {
+ if (p_enable) {
+ switch (enable_mode) {
+ case ENABLE_MODE_INHERIT: {
+ node->set_process_mode(PROCESS_MODE_INHERIT);
+ } break;
+ case ENABLE_MODE_ALWAYS: {
+ node->set_process_mode(PROCESS_MODE_ALWAYS);
+ } break;
+ case ENABLE_MODE_WHEN_PAUSED: {
+ node->set_process_mode(PROCESS_MODE_WHEN_PAUSED);
+ } break;
+ }
+ } else {
+ node->set_process_mode(PROCESS_MODE_DISABLED);
}
-
- _find_nodes(c);
}
}
-
void VisibilityEnabler2D::_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);
-
- // We need to defer the call of set_process and set_physics_process,
- // otherwise they are overwritten inside NOTIFICATION_READY.
- // We can't use call_deferred, because it happens after a physics frame.
- // The ready signal works as it's emitted immediately after NOTIFICATION_READY.
-
- if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) {
- get_parent()->connect(SceneStringNames::get_singleton()->ready,
- callable_mp(get_parent(), &Node::set_physics_process), varray(false), CONNECT_ONESHOT);
- }
- if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) {
- get_parent()->connect(SceneStringNames::get_singleton()->ready,
- callable_mp(get_parent(), &Node::set_process), varray(false), CONNECT_ONESHOT);
+ node_id = ObjectID();
+ Node *node = get_node(enable_node_path);
+ if (node) {
+ node_id = node->get_instance_id();
+ node->set_process_mode(PROCESS_MODE_DISABLED);
}
}
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, &VisibilityEnabler2D::_node_removed));
- }
-
- nodes.clear();
- }
-}
-
-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) {
- 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);
- }
- }
-
- if (enabler[ENABLER_PAUSE_ANIMATED_SPRITES]) {
- AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node);
-
- if (as) {
- if (p_enabled) {
- as->play();
- } else {
- as->stop();
- }
- }
- }
-
- if (enabler[ENABLER_PAUSE_PARTICLES]) {
- GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
-
- if (ps) {
- ps->set_emitting(p_enabled);
- }
- }
-}
-
-void VisibilityEnabler2D::_node_removed(Node *p_node) {
- if (!visible) {
- _change_node_state(p_node, true);
+ node_id = ObjectID();
}
- nodes.erase(p_node);
-}
-
-TypedArray<String> VisibilityEnabler2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
-
-#ifdef TOOLS_ENABLED
- if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) {
- warnings.push_back(TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent."));
- }
-#endif
- return warnings;
}
void VisibilityEnabler2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_enabler", "enabler", "enabled"), &VisibilityEnabler2D::set_enabler);
- ClassDB::bind_method(D_METHOD("is_enabler_enabled", "enabler"), &VisibilityEnabler2D::is_enabler_enabled);
- ClassDB::bind_method(D_METHOD("_node_removed"), &VisibilityEnabler2D::_node_removed);
+ ClassDB::bind_method(D_METHOD("set_enable_mode", "mode"), &VisibilityEnabler2D::set_enable_mode);
+ ClassDB::bind_method(D_METHOD("get_enable_mode"), &VisibilityEnabler2D::get_enable_mode);
- 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);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_particles"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_PARTICLES);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animated_sprites"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATED_SPRITES);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "process_parent"), "set_enabler", "is_enabler_enabled", ENABLER_PARENT_PROCESS);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "physics_process_parent"), "set_enabler", "is_enabler_enabled", ENABLER_PARENT_PHYSICS_PROCESS);
+ ClassDB::bind_method(D_METHOD("set_enable_node_path", "path"), &VisibilityEnabler2D::set_enable_node_path);
+ ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibilityEnabler2D::get_enable_node_path);
- BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS);
- BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES);
- BIND_ENUM_CONSTANT(ENABLER_PAUSE_PARTICLES);
- BIND_ENUM_CONSTANT(ENABLER_PARENT_PROCESS);
- BIND_ENUM_CONSTANT(ENABLER_PARENT_PHYSICS_PROCESS);
- BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATED_SPRITES);
- BIND_ENUM_CONSTANT(ENABLER_MAX);
-}
+ ADD_GROUP("Enabling", "enable_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path");
-void VisibilityEnabler2D::set_enabler(Enabler p_enabler, bool p_enable) {
- ERR_FAIL_INDEX(p_enabler, ENABLER_MAX);
- enabler[p_enabler] = p_enable;
-}
-
-bool VisibilityEnabler2D::is_enabler_enabled(Enabler p_enabler) const {
- ERR_FAIL_INDEX_V(p_enabler, ENABLER_MAX, false);
- return enabler[p_enabler];
+ BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT);
+ BIND_ENUM_CONSTANT(ENABLE_MODE_ALWAYS);
+ BIND_ENUM_CONSTANT(ENABLE_MODE_WHEN_PAUSED);
}
VisibilityEnabler2D::VisibilityEnabler2D() {
- for (int i = 0; i < ENABLER_MAX; i++) {
- enabler[i] = true;
- }
- enabler[ENABLER_PARENT_PROCESS] = false;
- enabler[ENABLER_PARENT_PHYSICS_PROCESS] = false;
}
diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h
index 7f4a5bc193..8cb0989787 100644
--- a/scene/2d/visibility_notifier_2d.h
+++ b/scene/2d/visibility_notifier_2d.h
@@ -41,12 +41,12 @@ class VisibilityNotifier2D : public Node2D {
Rect2 rect;
-protected:
- friend struct SpatialIndexer2D;
-
- void _enter_viewport(Viewport *p_viewport);
- void _exit_viewport(Viewport *p_viewport);
+private:
+ bool on_screen = false;
+ void _visibility_enter();
+ void _visibility_exit();
+protected:
virtual void _screen_enter() {}
virtual void _screen_exit() {}
@@ -71,42 +71,35 @@ class VisibilityEnabler2D : public VisibilityNotifier2D {
GDCLASS(VisibilityEnabler2D, VisibilityNotifier2D);
public:
- enum Enabler {
- ENABLER_PAUSE_ANIMATIONS,
- ENABLER_FREEZE_BODIES,
- ENABLER_PAUSE_PARTICLES,
- ENABLER_PARENT_PROCESS,
- ENABLER_PARENT_PHYSICS_PROCESS,
- ENABLER_PAUSE_ANIMATED_SPRITES,
- ENABLER_MAX
+ enum EnableMode {
+ ENABLE_MODE_INHERIT,
+ ENABLE_MODE_ALWAYS,
+ ENABLE_MODE_WHEN_PAUSED,
};
protected:
+ ObjectID node_id;
virtual void _screen_enter() override;
virtual void _screen_exit() override;
- bool visible = false;
-
- 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);
+ EnableMode enable_mode = ENABLE_MODE_INHERIT;
+ NodePath enable_node_path = NodePath("..");
void _notification(int p_what);
static void _bind_methods();
+ void _update_enable_mode(bool p_enable);
+
public:
- void set_enabler(Enabler p_enabler, bool p_enable);
- bool is_enabler_enabled(Enabler p_enabler) const;
+ void set_enable_mode(EnableMode p_mode);
+ EnableMode get_enable_mode();
- TypedArray<String> get_configuration_warnings() const override;
+ void set_enable_node_path(NodePath p_path);
+ NodePath get_enable_node_path();
VisibilityEnabler2D();
};
-VARIANT_ENUM_CAST(VisibilityEnabler2D::Enabler);
+VARIANT_ENUM_CAST(VisibilityEnabler2D::EnableMode);
#endif // VISIBILITY_NOTIFIER_2D_H
diff --git a/scene/2d/y_sort.cpp b/scene/2d/y_sort.cpp
deleted file mode 100644
index 7e7bc27cc2..0000000000
--- a/scene/2d/y_sort.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*************************************************************************/
-/* y_sort.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "y_sort.h"
-
-void YSort::set_sort_enabled(bool p_enabled) {
- sort_enabled = p_enabled;
- RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), sort_enabled);
-}
-
-bool YSort::is_sort_enabled() const {
- return sort_enabled;
-}
-
-void YSort::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_sort_enabled", "enabled"), &YSort::set_sort_enabled);
- ClassDB::bind_method(D_METHOD("is_sort_enabled"), &YSort::is_sort_enabled);
-
- ADD_GROUP("Sort", "sort_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sort_enabled"), "set_sort_enabled", "is_sort_enabled");
-}
-
-YSort::YSort() {
- 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 ce69e8aa19..40bdaee47d 100644
--- a/scene/3d/SCsub
+++ b/scene/3d/SCsub
@@ -4,6 +4,5 @@ Import("env")
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_3d.cpp b/scene/3d/area_3d.cpp
index e187e06308..44708cddff 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -118,7 +118,7 @@ void Area3D::_body_enter_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
}
@@ -132,7 +132,7 @@ void Area3D::_body_exit_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
}
@@ -154,6 +154,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
if (body_in) {
if (!E) {
E = body_map.insert(objid, BodyState());
+ E->get().rid = p_body;
E->get().rc = 0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
@@ -170,7 +171,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
}
if (E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);
}
} else {
@@ -192,7 +193,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
}
}
if (node && in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_area_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_area_shape);
}
}
@@ -224,7 +225,7 @@ void Area3D::_clear_monitoring() {
}
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_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
@@ -253,7 +254,7 @@ void Area3D::_clear_monitoring() {
}
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_shape_exited, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
@@ -298,7 +299,7 @@ void Area3D::_area_enter_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_entered, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
}
@@ -312,7 +313,7 @@ void Area3D::_area_exit_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
}
}
@@ -334,6 +335,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
if (area_in) {
if (!E) {
E = area_map.insert(objid, AreaState());
+ E->get().rid = p_area;
E->get().rc = 0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
@@ -350,7 +352,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
}
if (!node || E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_entered, objid, node, p_area_shape, p_self_shape);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_area, node, p_area_shape, p_self_shape);
}
} else {
@@ -372,7 +374,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
}
}
if (!node || in_tree) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_exited, objid, obj, p_area_shape, p_self_shape);
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_area, obj, p_area_shape, p_self_shape);
}
}
@@ -582,13 +584,13 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_reverb_uniformity", "amount"), &Area3D::set_reverb_uniformity);
ClassDB::bind_method(D_METHOD("get_reverb_uniformity"), &Area3D::get_reverb_uniformity);
- ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D")));
ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D")));
- ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
- ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D")));
ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D")));
@@ -601,7 +603,7 @@ void Area3D::_bind_methods() {
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, "gravity", PROPERTY_HINT_RANGE, "-32,32,0.001,or_lesser,or_greater"), "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");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 9605a937af..5b8d612717 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -83,6 +83,7 @@ private:
};
struct BodyState {
+ RID rid;
int rc = 0;
bool in_tree = false;
VSet<ShapePair> shapes;
@@ -114,6 +115,7 @@ private:
};
struct AreaState {
+ RID rid;
int rc = 0;
bool in_tree = false;
VSet<AreaShapePair> shapes;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 72392be5bd..9640043031 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -404,10 +404,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
break;
}
- List<Camera3D *> cameras;
- world_3d->get_camera_list(&cameras);
-
- for (List<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
+ for (const Set<Camera3D *>::Element *E = world_3d->get_cameras().front(); E; E = E->next()) {
Camera3D *camera = E->get();
Viewport *vp = camera->get_viewport();
if (!vp->is_audio_listener()) {
@@ -962,9 +959,9 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,InverseSquare,Log,Disabled"), "set_attenuation_model", "get_attenuation_model");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,Inverse Square,Log,Disabled"), "set_attenuation_model", "get_attenuation_model");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_db", PROPERTY_HINT_RANGE, "-80,80"), "set_unit_db", "get_unit_db");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.1"), "set_unit_size", "get_unit_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.01,or_greater"), "set_unit_size", "get_unit_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_db", PROPERTY_HINT_RANGE, "-24,6"), "set_max_db", "get_max_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 70c535bd89..8aec493602 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -98,7 +98,7 @@ private:
AttenuationModel attenuation_model = ATTENUATION_INVERSE_DISTANCE;
float unit_db = 0.0;
- float unit_size = 1.0;
+ float unit_size = 10.0;
float max_db = 3.0;
float pitch_scale = 1.0;
bool autoplay = false;
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index cd8d02233b..62bbebe6e7 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -93,10 +93,6 @@ void Camera3D::_update_camera() {
}
get_viewport()->_camera_transform_changed_notify();
-
- if (get_world_3d().is_valid()) {
- get_world_3d()->_update_camera(this);
- }
}
void Camera3D::_notification(int p_what) {
@@ -150,8 +146,8 @@ void Camera3D::_notification(int p_what) {
}
}
-Transform Camera3D::get_camera_transform() const {
- Transform tr = get_global_transform().orthonormalized();
+Transform3D Camera3D::get_camera_transform() const {
+ Transform3D 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;
@@ -318,7 +314,7 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const {
};
bool Camera3D::is_position_behind(const Vector3 &p_pos) const {
- Transform t = get_global_transform();
+ Transform3D t = get_global_transform();
Vector3 eyedir = -t.basis.get_axis(2).normalized();
return eyedir.dot(p_pos - t.origin) < near;
}
@@ -337,7 +333,7 @@ Vector<Vector3> Camera3D::get_near_plane_points() const {
}
Vector3 endpoints[8];
- cm.get_endpoints(Transform(), endpoints);
+ cm.get_endpoints(Transform3D(), endpoints);
Vector<Vector3> points;
points.push_back(Vector3());
@@ -500,6 +496,7 @@ void Camera3D::_bind_methods() {
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("is_position_in_frustum", "world_point"), &Camera3D::is_position_in_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);
@@ -623,6 +620,16 @@ Vector<Plane> Camera3D::get_frustum() const {
return cm.get_projection_planes(get_camera_transform());
}
+bool Camera3D::is_position_in_frustum(const Vector3 &p_position) const {
+ Vector<Plane> frustum = get_frustum();
+ for (int i = 0; i < frustum.size(); i++) {
+ if (frustum[i].is_point_over(p_position)) {
+ return false;
+ }
+ }
+ return true;
+}
+
void Camera3D::set_v_offset(float p_offset) {
v_offset = p_offset;
_update_camera();
@@ -686,8 +693,8 @@ ClippedCamera3D::ClipProcessCallback ClippedCamera3D::get_process_callback() con
return process_callback;
}
-Transform ClippedCamera3D::get_camera_transform() const {
- Transform t = Camera3D::get_camera_transform();
+Transform3D ClippedCamera3D::get_camera_transform() const {
+ Transform3D t = Camera3D::get_camera_transform();
t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
return t;
}
@@ -735,7 +742,7 @@ void ClippedCamera3D::_notification(int p_what) {
}
}
- Transform xf = get_global_transform();
+ Transform3D xf = get_global_transform();
xf.origin = ray_from;
xf.orthonormalize();
@@ -761,6 +768,7 @@ uint32_t ClippedCamera3D::get_collision_mask() const {
}
void ClippedCamera3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -771,6 +779,7 @@ void ClippedCamera3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool ClippedCamera3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index cea61e4db8..c6efc8f9a9 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -134,7 +134,7 @@ public:
void set_near(float p_near);
void set_frustum_offset(Vector2 p_offset);
- virtual Transform get_camera_transform() const;
+ virtual Transform3D get_camera_transform() const;
virtual Vector3 project_ray_normal(const Point2 &p_pos) const;
virtual Vector3 project_ray_origin(const Point2 &p_pos) const;
@@ -153,6 +153,7 @@ public:
bool get_cull_mask_bit(int p_layer) const;
virtual Vector<Plane> get_frustum() const;
+ bool is_position_in_frustum(const Vector3 &p_position) const;
void set_environment(const Ref<Environment> &p_environment);
Ref<Environment> get_environment() const;
@@ -207,7 +208,7 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
- virtual Transform get_camera_transform() const override;
+ virtual Transform3D get_camera_transform() const override;
public:
void set_clip_to_areas(bool p_clip);
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 44de4eb449..a04667e53b 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -31,12 +31,27 @@
#include "collision_object_3d.h"
#include "core/config/engine.h"
-#include "mesh_instance_3d.h"
#include "scene/scene_string_names.h"
#include "servers/physics_server_3d.h"
void CollisionObject3D::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (_are_collision_shapes_visible()) {
+ debug_shape_old_transform = get_global_transform();
+ for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ debug_shapes_to_update.insert(E->key());
+ }
+ _update_debug_shapes();
+ }
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ if (debug_shapes_count > 0) {
+ _clear_debug_shapes();
+ }
+ } break;
+
case NOTIFICATION_ENTER_WORLD: {
if (area) {
PhysicsServer3D::get_singleton()->area_set_transform(rid, get_global_transform());
@@ -62,6 +77,8 @@ void CollisionObject3D::_notification(int p_what) {
PhysicsServer3D::get_singleton()->body_set_state(rid, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
}
+ _on_transform_changed();
+
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable();
@@ -75,11 +92,6 @@ void CollisionObject3D::_notification(int p_what) {
}
} break;
- case NOTIFICATION_PREDELETE: {
- if (debug_shape_count > 0) {
- _clear_debug_shapes();
- }
- } break;
}
}
@@ -110,6 +122,7 @@ uint32_t CollisionObject3D::get_collision_mask() const {
}
void CollisionObject3D::set_collision_layer_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t collision_layer = get_collision_layer();
if (p_value) {
collision_layer |= 1 << p_bit;
@@ -120,10 +133,12 @@ void CollisionObject3D::set_collision_layer_bit(int p_bit, bool p_value) {
}
bool CollisionObject3D::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
void CollisionObject3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -134,6 +149,7 @@ void CollisionObject3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool CollisionObject3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
@@ -171,30 +187,69 @@ void CollisionObject3D::_update_pickable() {
}
}
+bool CollisionObject3D::_are_collision_shapes_visible() {
+ return is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint();
+}
+
+void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
+ if (_are_collision_shapes_visible()) {
+ if (debug_shapes_to_update.is_empty()) {
+ callable_mp(this, &CollisionObject3D::_update_debug_shapes).call_deferred({}, 0);
+ }
+ debug_shapes_to_update.insert(p_owner);
+ }
+}
+
+void CollisionObject3D::_shape_changed(const Ref<Shape3D> &p_shape) {
+ for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ ShapeData &shapedata = E->get();
+ ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
+ for (int i = 0; i < shapedata.shapes.size(); i++) {
+ ShapeData::ShapeBase &s = shapes[i];
+ if (s.shape == p_shape && s.debug_shape.is_valid()) {
+ Ref<Mesh> mesh = s.shape->get_debug_mesh();
+ RS::get_singleton()->instance_set_base(s.debug_shape, mesh->get_rid());
+ }
+ }
+ }
+}
+
void CollisionObject3D::_update_debug_shapes() {
+ if (!is_inside_tree()) {
+ debug_shapes_to_update.clear();
+ return;
+ }
+
for (Set<uint32_t>::Element *shapedata_idx = debug_shapes_to_update.front(); shapedata_idx; shapedata_idx = shapedata_idx->next()) {
if (shapes.has(shapedata_idx->get())) {
ShapeData &shapedata = shapes[shapedata_idx->get()];
ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
ShapeData::ShapeBase &s = shapes[i];
- if (s.debug_shape) {
- s.debug_shape->queue_delete();
- s.debug_shape = nullptr;
- --debug_shape_count;
- }
if (s.shape.is_null() || shapedata.disabled) {
+ if (s.debug_shape.is_valid()) {
+ RS::get_singleton()->free(s.debug_shape);
+ s.debug_shape = RID();
+ --debug_shapes_count;
+ }
continue;
}
+ if (s.debug_shape.is_null()) {
+ s.debug_shape = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_scenario(s.debug_shape, get_world_3d()->get_scenario());
+
+ if (!s.shape->is_connected("changed", callable_mp(this, &CollisionObject3D::_shape_changed))) {
+ s.shape->connect("changed", callable_mp(this, &CollisionObject3D::_shape_changed),
+ varray(s.shape), CONNECT_DEFERRED);
+ }
+
+ ++debug_shapes_count;
+ }
+
Ref<Mesh> mesh = s.shape->get_debug_mesh();
- MeshInstance3D *mi = memnew(MeshInstance3D);
- mi->set_transform(shapedata.xform);
- mi->set_mesh(mesh);
- add_child(mi);
- mi->force_update_transform();
- s.debug_shape = mi;
- ++debug_shape_count;
+ RS::get_singleton()->instance_set_base(s.debug_shape, mesh->get_rid());
+ RS::get_singleton()->instance_set_transform(s.debug_shape, get_global_transform() * shapedata.xform);
}
}
}
@@ -207,23 +262,28 @@ void CollisionObject3D::_clear_debug_shapes() {
ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
ShapeData::ShapeBase &s = shapes[i];
- if (s.debug_shape) {
- s.debug_shape->queue_delete();
- s.debug_shape = nullptr;
- --debug_shape_count;
+ if (s.debug_shape.is_valid()) {
+ RS::get_singleton()->free(s.debug_shape);
+ s.debug_shape = RID();
+ if (s.shape.is_valid() && s.shape->is_connected("changed", callable_mp(this, &CollisionObject3D::_update_shape_data))) {
+ s.shape->disconnect("changed", callable_mp(this, &CollisionObject3D::_update_shape_data));
+ }
}
}
}
-
- debug_shape_count = 0;
+ debug_shapes_count = 0;
}
-void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
- if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint()) {
- if (debug_shapes_to_update.is_empty()) {
- call_deferred("_update_debug_shapes");
+void CollisionObject3D::_on_transform_changed() {
+ if (debug_shapes_count > 0 && !debug_shape_old_transform.is_equal_approx(get_global_transform())) {
+ debug_shape_old_transform = get_global_transform();
+ for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ ShapeData &shapedata = E->get();
+ const ShapeData::ShapeBase *shapes = shapedata.shapes.ptr();
+ for (int i = 0; i < shapedata.shapes.size(); i++) {
+ RS::get_singleton()->instance_set_transform(shapes[i].debug_shape, debug_shape_old_transform * shapedata.xform);
+ }
}
- debug_shapes_to_update.insert(p_owner);
}
}
@@ -266,11 +326,9 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject3D::shape_owner_clear_shapes);
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject3D::shape_find_owner);
- ClassDB::bind_method(D_METHOD("_update_debug_shapes"), &CollisionObject3D::_update_debug_shapes);
+ BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx")));
- 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("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited"));
@@ -312,7 +370,11 @@ void CollisionObject3D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabl
ERR_FAIL_COND(!shapes.has(p_owner));
ShapeData &sd = shapes[p_owner];
+ if (sd.disabled == p_disabled) {
+ return;
+ }
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);
@@ -344,7 +406,7 @@ Array CollisionObject3D::_get_shape_owners() {
return ret;
}
-void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform) {
+void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transform3D &p_transform) {
ERR_FAIL_COND(!shapes.has(p_owner));
ShapeData &sd = shapes[p_owner];
@@ -359,9 +421,8 @@ void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transf
_update_shape_data(p_owner);
}
-
-Transform CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const {
- ERR_FAIL_COND_V(!shapes.has(p_owner), Transform());
+Transform3D CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const {
+ ERR_FAIL_COND_V(!shapes.has(p_owner), Transform3D());
return shapes[p_owner].xform;
}
@@ -417,7 +478,7 @@ 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());
- const ShapeData::ShapeBase &s = shapes[p_owner].shapes[p_shape];
+ ShapeData::ShapeBase &s = shapes[p_owner].shapes.write[p_shape];
int index_to_remove = s.index;
if (area) {
@@ -426,8 +487,12 @@ void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape)
PhysicsServer3D::get_singleton()->body_remove_shape(rid, index_to_remove);
}
- if (s.debug_shape) {
- s.debug_shape->queue_delete();
+ if (s.debug_shape.is_valid()) {
+ RS::get_singleton()->free(s.debug_shape);
+ if (s.shape.is_valid() && s.shape->is_connected("changed", callable_mp(this, &CollisionObject3D::_shape_changed))) {
+ s.shape->disconnect("changed", callable_mp(this, &CollisionObject3D::_shape_changed));
+ }
+ --debug_shapes_count;
}
shapes[p_owner].shapes.remove(p_shape);
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index e3901979d3..50a9b4fcd0 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -46,9 +46,9 @@ class CollisionObject3D : public Node3D {
struct ShapeData {
Object *owner = nullptr;
- Transform xform;
+ Transform3D xform;
struct ShapeBase {
- Node *debug_shape = nullptr;
+ RID debug_shape;
Ref<Shape3D> shape;
int index = 0;
};
@@ -65,25 +65,30 @@ class CollisionObject3D : public Node3D {
bool ray_pickable = true;
Set<uint32_t> debug_shapes_to_update;
- int debug_shape_count = 0;
+ int debug_shapes_count = 0;
+ Transform3D debug_shape_old_transform;
void _update_pickable();
+ bool _are_collision_shapes_visible();
void _update_shape_data(uint32_t p_owner);
+ void _shape_changed(const Ref<Shape3D> &p_shape);
+ void _update_debug_shapes();
+ void _clear_debug_shapes();
protected:
CollisionObject3D(RID p_rid, bool p_area);
void _notification(int p_what);
static void _bind_methods();
+
+ void _on_transform_changed();
+
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();
- void _update_debug_shapes();
- void _clear_debug_shapes();
-
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
@@ -102,8 +107,8 @@ public:
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;
+ void shape_owner_set_transform(uint32_t p_owner, const Transform3D &p_transform);
+ Transform3D 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);
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index ac715b22b2..8a4f8b639b 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -171,7 +171,7 @@ TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- warnings.push_back(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."));
+ warnings.push_back(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (polygon.is_empty()) {
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index bec87914c0..be3fde8013 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -124,7 +124,7 @@ TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- warnings.push_back(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."));
+ warnings.push_back(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
@@ -161,12 +161,10 @@ 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) {
@@ -176,8 +174,9 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
}
}
- if (is_inside_tree()) {
- _shape_changed();
+ if (is_inside_tree() && parent) {
+ // If this is a heightfield shape our center may have changed
+ _update_in_shape_owner(true);
}
update_configuration_warnings();
}
@@ -209,10 +208,3 @@ CollisionShape3D::~CollisionShape3D() {
}
//RenderingServer::get_singleton()->free(indicator);
}
-
-void CollisionShape3D::_shape_changed() {
- // If this is a heightfield shape our center may have changed
- if (parent) {
- _update_in_shape_owner(true);
- }
-}
diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h
index 56a4ae3039..f69c1e38eb 100644
--- a/scene/3d/collision_shape_3d.h
+++ b/scene/3d/collision_shape_3d.h
@@ -47,8 +47,6 @@ class CollisionShape3D : public Node3D {
bool disabled = false;
protected:
- void _shape_changed();
-
void _update_in_shape_owner(bool p_xform_only = false);
protected:
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 780773bb57..2301fef651 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -574,7 +574,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
}
}
- Transform emission_xform;
+ Transform3D emission_xform;
Basis velocity_xform;
if (!local_coords) {
emission_xform = get_global_transform();
@@ -693,7 +693,7 @@ void CPUParticles3D::_particles_process(float p_delta) {
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.transform = Transform3D();
p.time = 0;
p.lifetime = lifetime * (1.0 - Math::randf() * lifetime_randomness);
p.base_color = Color(1, 1, 1, 1);
@@ -1030,7 +1030,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
for (int i = 0; i < pc; i++) {
int idx = order ? order[i] : i;
- Transform t = r[idx].transform;
+ Transform3D t = r[idx].transform;
if (!local_coords) {
t = inv_emission_transform * t;
@@ -1050,7 +1050,7 @@ void CPUParticles3D::_update_particle_data_buffer() {
ptr[10] = t.basis.elements[2][2];
ptr[11] = t.origin.z;
} else {
- zeromem(ptr, sizeof(float) * 12);
+ memset(ptr, 0, sizeof(float) * 12);
}
Color c = r[idx].color;
@@ -1139,7 +1139,7 @@ void CPUParticles3D::_notification(int p_what) {
float *ptr = w;
for (int i = 0; i < pc; i++) {
- Transform t = inv_emission_transform * r[i].transform;
+ Transform3D t = inv_emission_transform * r[i].transform;
if (r[i].active) {
ptr[0] = t.basis.elements[0][0];
@@ -1155,7 +1155,7 @@ void CPUParticles3D::_notification(int p_what) {
ptr[10] = t.basis.elements[2][2];
ptr[11] = t.origin.z;
} else {
- zeromem(ptr, sizeof(float) * 12);
+ memset(ptr, 0, sizeof(float) * 12);
}
ptr += 20;
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index c073c93c47..b35e659757 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -83,7 +83,7 @@ private:
bool emitting = false;
struct Particle {
- Transform transform;
+ Transform3D transform;
Color color;
float custom[4] = {};
Vector3 velocity;
@@ -141,7 +141,7 @@ private:
int fixed_fps = 0;
bool fractional_delta = true;
- Transform inv_emission_transform;
+ Transform3D inv_emission_transform;
SafeFlag can_update;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index a075dcf990..d7f4bfeb4e 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -181,12 +181,33 @@ void GPUParticles3D::set_draw_order(DrawOrder p_order) {
RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
}
+void GPUParticles3D::set_trail_enabled(bool p_enabled) {
+ trail_enabled = p_enabled;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ update_configuration_warnings();
+}
+void GPUParticles3D::set_trail_length(float p_seconds) {
+ ERR_FAIL_COND(p_seconds < 0.001);
+ trail_length = p_seconds;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+}
+
+bool GPUParticles3D::is_trail_enabled() const {
+ return trail_enabled;
+}
+float GPUParticles3D::get_trail_length() const {
+ return trail_length;
+}
+
GPUParticles3D::DrawOrder GPUParticles3D::get_draw_order() const {
return draw_order;
}
void GPUParticles3D::set_draw_passes(int p_count) {
ERR_FAIL_COND(p_count < 1);
+ for (int i = p_count; i < draw_passes.size(); i++) {
+ set_draw_pass_mesh(i, Ref<Mesh>());
+ }
draw_passes.resize(p_count);
RS::get_singleton()->particles_set_draw_passes(particles, p_count);
notify_property_list_changed();
@@ -199,8 +220,16 @@ int GPUParticles3D::get_draw_passes() const {
void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
ERR_FAIL_INDEX(p_pass, draw_passes.size());
+ if (Engine::get_singleton()->is_editor_hint() && draw_passes.write[p_pass].is_valid()) {
+ draw_passes.write[p_pass]->disconnect("changed", callable_mp((Node *)this, &Node::update_configuration_warnings));
+ }
+
draw_passes.write[p_pass] = p_mesh;
+ if (Engine::get_singleton()->is_editor_hint() && draw_passes.write[p_pass].is_valid()) {
+ draw_passes.write[p_pass]->connect("changed", callable_mp((Node *)this, &Node::update_configuration_warnings), varray(), CONNECT_DEFERRED);
+ }
+
RID mesh_rid;
if (p_mesh.is_valid()) {
mesh_rid = p_mesh->get_rid();
@@ -208,6 +237,7 @@ void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
RS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid);
+ _skinning_changed();
update_configuration_warnings();
}
@@ -235,6 +265,15 @@ bool GPUParticles3D::get_fractional_delta() const {
return fractional_delta;
}
+void GPUParticles3D::set_interpolate(bool p_enable) {
+ interpolate = p_enable;
+ RS::get_singleton()->particles_set_interpolate(particles, p_enable);
+}
+
+bool GPUParticles3D::get_interpolate() const {
+ return interpolate;
+}
+
TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
@@ -250,7 +289,7 @@ TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
meshes_found = true;
for (int j = 0; j < draw_passes[i]->get_surface_count(); j++) {
anim_material_found = Object::cast_to<ShaderMaterial>(draw_passes[i]->surface_get_material(j).ptr()) != nullptr;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
}
if (anim_material_found) {
@@ -260,8 +299,10 @@ TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
}
anim_material_found = anim_material_found || Object::cast_to<ShaderMaterial>(get_material_override().ptr()) != nullptr;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_material_override().ptr());
- anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
+ {
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(get_material_override().ptr());
+ anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == BaseMaterial3D::BILLBOARD_PARTICLES);
+ }
if (!meshes_found) {
warnings.push_back(TTR("Nothing is visible because meshes have not been assigned to draw passes."));
@@ -274,7 +315,57 @@ TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
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())) {
- warnings.push_back(TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
+ warnings.push_back(TTR("Particles animation requires the usage of a BaseMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
+ }
+ }
+
+ if (trail_enabled) {
+ int dp_count = 0;
+ bool missing_trails = false;
+ bool no_materials = false;
+
+ for (int i = 0; i < draw_passes.size(); i++) {
+ Ref<Mesh> draw_pass = draw_passes[i];
+ if (draw_pass.is_valid() && draw_pass->get_builtin_bind_pose_count() > 0) {
+ dp_count++;
+ }
+
+ if (draw_pass.is_valid()) {
+ int mats_found = 0;
+ for (int j = 0; j < draw_passes[i]->get_surface_count(); j++) {
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(draw_passes[i]->surface_get_material(j).ptr());
+ if (spat) {
+ mats_found++;
+ }
+ if (spat && !spat->get_flag(BaseMaterial3D::FLAG_PARTICLE_TRAILS_MODE)) {
+ missing_trails = true;
+ }
+ }
+
+ if (mats_found != draw_passes[i]->get_surface_count()) {
+ no_materials = true;
+ }
+ }
+ }
+
+ BaseMaterial3D *spat = Object::cast_to<BaseMaterial3D>(get_material_override().ptr());
+ if (spat) {
+ no_materials = false;
+ }
+ if (spat && !spat->get_flag(BaseMaterial3D::FLAG_PARTICLE_TRAILS_MODE)) {
+ missing_trails = true;
+ }
+
+ if (dp_count && skin.is_valid()) {
+ warnings.push_back(TTR("Using Trail meshes with a skin causes Skin to override Trail poses. Suggest removing the Skin."));
+ } else if (dp_count == 0 && skin.is_null()) {
+ warnings.push_back(TTR("Trails active, but neither Trail meshes or a Skin were found."));
+ } else if (dp_count > 1) {
+ warnings.push_back(TTR("Only one Trail mesh is supported. If you want to use more than a single mesh, a Skin is needed (see documentation)."));
+ }
+
+ if ((dp_count || !skin.is_null()) && (missing_trails || no_materials)) {
+ warnings.push_back(TTR("Trails enabled, but one or more mesh materials are either missing or not set for trails rendering."));
}
}
@@ -300,7 +391,7 @@ void GPUParticles3D::_validate_property(PropertyInfo &property) const {
}
}
-void GPUParticles3D::emit_particle(const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
+void GPUParticles3D::emit_particle(const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
RS::get_singleton()->particles_emit(particles, p_transform, p_velocity, p_color, p_custom, p_emit_flags);
}
@@ -366,6 +457,47 @@ void GPUParticles3D::_notification(int p_what) {
}
}
+void GPUParticles3D::_skinning_changed() {
+ Vector<Transform3D> xforms;
+ if (skin.is_valid()) {
+ xforms.resize(skin->get_bind_count());
+ for (int i = 0; i < skin->get_bind_count(); i++) {
+ xforms.write[i] = skin->get_bind_pose(i);
+ }
+ } else {
+ for (int i = 0; i < draw_passes.size(); i++) {
+ Ref<Mesh> draw_pass = draw_passes[i];
+ if (draw_pass.is_valid() && draw_pass->get_builtin_bind_pose_count() > 0) {
+ xforms.resize(draw_pass->get_builtin_bind_pose_count());
+ for (int j = 0; j < draw_pass->get_builtin_bind_pose_count(); j++) {
+ xforms.write[i] = draw_pass->get_builtin_bind_pose(j);
+ }
+ break;
+ }
+ }
+ }
+
+ RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms);
+ update_configuration_warnings();
+}
+
+void GPUParticles3D::set_skin(const Ref<Skin> &p_skin) {
+ skin = p_skin;
+ _skinning_changed();
+}
+Ref<Skin> GPUParticles3D::get_skin() const {
+ return skin;
+}
+
+void GPUParticles3D::set_transform_align(TransformAlign p_align) {
+ ERR_FAIL_INDEX(uint32_t(p_align), 4);
+ transform_align = p_align;
+ RS::get_singleton()->particles_set_transform_align(particles, RS::ParticlesTransformAlign(transform_align));
+}
+GPUParticles3D::TransformAlign GPUParticles3D::get_transform_align() const {
+ return transform_align;
+}
+
void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &GPUParticles3D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &GPUParticles3D::set_amount);
@@ -378,6 +510,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &GPUParticles3D::set_use_local_coordinates);
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &GPUParticles3D::set_fixed_fps);
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles3D::set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("set_interpolate", "enable"), &GPUParticles3D::set_interpolate);
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles3D::set_process_material);
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles3D::set_speed_scale);
ClassDB::bind_method(D_METHOD("set_collision_base_size", "size"), &GPUParticles3D::set_collision_base_size);
@@ -393,6 +526,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &GPUParticles3D::get_use_local_coordinates);
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &GPUParticles3D::get_fixed_fps);
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles3D::get_fractional_delta);
+ ClassDB::bind_method(D_METHOD("get_interpolate"), &GPUParticles3D::get_interpolate);
ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles3D::get_process_material);
ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles3D::get_speed_scale);
ClassDB::bind_method(D_METHOD("get_collision_base_size"), &GPUParticles3D::get_collision_base_size);
@@ -407,6 +541,9 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_draw_passes"), &GPUParticles3D::get_draw_passes);
ClassDB::bind_method(D_METHOD("get_draw_pass_mesh", "pass"), &GPUParticles3D::get_draw_pass_mesh);
+ ClassDB::bind_method(D_METHOD("set_skin", "skin"), &GPUParticles3D::set_skin);
+ ClassDB::bind_method(D_METHOD("get_skin"), &GPUParticles3D::get_skin);
+
ClassDB::bind_method(D_METHOD("restart"), &GPUParticles3D::restart);
ClassDB::bind_method(D_METHOD("capture_aabb"), &GPUParticles3D::capture_aabb);
@@ -415,6 +552,15 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle);
+ ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles3D::set_trail_enabled);
+ ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles3D::set_trail_length);
+
+ ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles3D::is_trail_enabled);
+ ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles3D::get_trail_length);
+
+ ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align);
+ ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter");
@@ -426,13 +572,18 @@ void GPUParticles3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interpolate"), "set_interpolate", "get_interpolate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size");
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_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime,View Depth"), "set_draw_order", "get_draw_order");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,ZBillboard,YToVelocity,ZBillboardYToVelocity"), "set_transform_align", "get_transform_align");
+ ADD_GROUP("Trails", "trail_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_trail_length", "get_trail_length");
ADD_GROUP("Process Material", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
ADD_GROUP("Draw Passes", "draw_");
@@ -440,9 +591,11 @@ void GPUParticles3D::_bind_methods() {
for (int i = 0; i < MAX_DRAW_PASSES; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "draw_pass_" + itos(i + 1), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_draw_pass_mesh", "get_draw_pass_mesh", i);
}
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "draw_skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_REVERSE_LIFETIME);
BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION);
@@ -452,27 +605,36 @@ void GPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM);
BIND_CONSTANT(MAX_DRAW_PASSES);
+
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_DISABLED);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Z_BILLBOARD);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY);
}
GPUParticles3D::GPUParticles3D() {
particles = RS::get_singleton()->particles_create();
+ RS::get_singleton()->particles_set_mode(particles, RS::PARTICLES_MODE_3D);
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_fixed_fps(30);
set_fractional_delta(true);
+ set_interpolate(true);
set_pre_process_time(0);
set_explosiveness_ratio(0);
set_randomness_ratio(0);
+ set_trail_length(0.3);
set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)));
set_use_local_coordinates(true);
set_draw_passes(1);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
- set_collision_base_size(0.01);
+ set_collision_base_size(collision_base_size);
+ set_transform_align(TRANSFORM_ALIGN_DISABLED);
}
GPUParticles3D::~GPUParticles3D() {
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index b9e2b5ccef..7b21cf03f1 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -34,6 +34,7 @@
#include "core/templates/rid.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/material.h"
+#include "scene/resources/skin.h"
class GPUParticles3D : public GeometryInstance3D {
private:
@@ -43,9 +44,17 @@ public:
enum DrawOrder {
DRAW_ORDER_INDEX,
DRAW_ORDER_LIFETIME,
+ DRAW_ORDER_REVERSE_LIFETIME,
DRAW_ORDER_VIEW_DEPTH,
};
+ enum TransformAlign {
+ TRANSFORM_ALIGN_DISABLED,
+ TRANSFORM_ALIGN_Z_BILLBOARD,
+ TRANSFORM_ALIGN_Y_TO_VELOCITY,
+ TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY
+ };
+
enum {
MAX_DRAW_PASSES = 4
};
@@ -64,17 +73,26 @@ private:
bool local_coords;
int fixed_fps;
bool fractional_delta;
+ bool interpolate = true;
NodePath sub_emitter;
- float collision_base_size;
+ float collision_base_size = 0.01;
+
+ bool trail_enabled = false;
+ float trail_length = 0.3;
+
+ TransformAlign transform_align = TRANSFORM_ALIGN_DISABLED;
Ref<Material> process_material;
DrawOrder draw_order;
Vector<Ref<Mesh>> draw_passes;
+ Ref<Skin> skin;
void _attach_sub_emitter();
+ void _skinning_changed();
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -96,6 +114,8 @@ public:
void set_process_material(const Ref<Material> &p_material);
void set_speed_scale(float p_scale);
void set_collision_base_size(float p_ratio);
+ void set_trail_enabled(bool p_enabled);
+ void set_trail_length(float p_seconds);
bool is_emitting() const;
int get_amount() const;
@@ -109,6 +129,8 @@ public:
Ref<Material> get_process_material() const;
float get_speed_scale() const;
float get_collision_base_size() const;
+ bool is_trail_enabled() const;
+ float get_trail_length() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
@@ -116,6 +138,9 @@ public:
void set_fractional_delta(bool p_enable);
bool get_fractional_delta() const;
+ void set_interpolate(bool p_enable);
+ bool get_interpolate() const;
+
void set_draw_order(DrawOrder p_order);
DrawOrder get_draw_order() const;
@@ -130,6 +155,12 @@ public:
void set_sub_emitter(const NodePath &p_path);
NodePath get_sub_emitter() const;
+ void set_skin(const Ref<Skin> &p_skin);
+ Ref<Skin> get_skin() const;
+
+ void set_transform_align(TransformAlign p_align);
+ TransformAlign get_transform_align() const;
+
void restart();
enum EmitFlags {
@@ -140,7 +171,7 @@ public:
EMIT_FLAG_CUSTOM = RS::PARTICLES_EMIT_FLAG_CUSTOM
};
- void emit_particle(const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
+ void emit_particle(const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
AABB capture_aabb() const;
GPUParticles3D();
@@ -148,6 +179,7 @@ public:
};
VARIANT_ENUM_CAST(GPUParticles3D::DrawOrder)
+VARIANT_ENUM_CAST(GPUParticles3D::TransformAlign)
VARIANT_ENUM_CAST(GPUParticles3D::EmitFlags)
#endif // PARTICLES_H
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 628b823f89..322bc60fce 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -131,7 +131,7 @@ void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node,
if (mesh.is_valid()) {
AABB aabb = mesh->get_aabb();
- Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform();
+ Transform3D xf = get_global_transform().affine_inverse() * mi->get_global_transform();
if (p_aabb.intersects(xf.xform(aabb))) {
PlotMesh pm;
@@ -147,7 +147,7 @@ void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node,
if (s->is_visible_in_tree()) {
Array meshes = p_at_node->call("get_meshes");
for (int i = 0; i < meshes.size(); i += 2) {
- Transform mxf = meshes[i];
+ Transform3D mxf = meshes[i];
Ref<Mesh> mesh = meshes[i + 1];
if (!mesh.is_valid()) {
continue;
@@ -155,7 +155,7 @@ void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node,
AABB aabb = mesh->get_aabb();
- Transform xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
+ Transform3D xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
if (p_aabb.intersects(xf.xform(aabb))) {
PlotMesh pm;
@@ -598,14 +598,14 @@ void GPUParticlesCollisionHeightField::_notification(int p_what) {
if (follow_camera_mode && get_viewport()) {
Camera3D *cam = get_viewport()->get_camera();
if (cam) {
- Transform xform = get_global_transform();
+ Transform3D xform = get_global_transform();
Vector3 x_axis = xform.basis.get_axis(Vector3::AXIS_X).normalized();
Vector3 z_axis = xform.basis.get_axis(Vector3::AXIS_Z).normalized();
float x_len = xform.basis.get_scale().x;
float z_len = xform.basis.get_scale().z;
Vector3 cam_pos = cam->get_global_transform().origin;
- Transform new_xform = xform;
+ Transform3D new_xform = xform;
while (x_axis.dot(cam_pos - new_xform.origin) > x_len) {
new_xform.origin += x_axis * x_len;
@@ -653,7 +653,7 @@ void GPUParticlesCollisionHeightField::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents");
ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "256,512,1024,2048,4096,8192"), "set_resolution", "get_resolution");
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "WhenMoved,Always"), "set_update_mode", "get_update_mode");
- ADD_GROUP("Folow Camera", "follow_camera_");
+ ADD_GROUP("Follow Camera", "follow_camera_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_camera_enabled"), "set_follow_camera_mode", "is_follow_camera_mode_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_camera_push_ratio", PROPERTY_HINT_RANGE, "0.01,1,0.01"), "set_follow_camera_push_ratio", "get_follow_camera_push_ratio");
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
index 81c33663f3..c55463378d 100644
--- a/scene/3d/gpu_particles_collision_3d.h
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -119,7 +119,7 @@ private:
struct PlotMesh {
Ref<Mesh> mesh;
- Transform local_xform;
+ Transform3D local_xform;
};
void _find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes);
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/lightmap_gi.cpp
index 2e1b77dfe5..a3f681e53c 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* baked_lightmap.cpp */
+/* lightmap_gi.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,19 +28,19 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "baked_lightmap.h"
+#include "lightmap_gi.h"
#include "core/io/config_file.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
#include "core/math/camera_matrix.h"
#include "core/math/delaunay_3d.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/templates/sort_array.h"
#include "lightmap_probe.h"
-void BakedLightmapData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) {
+void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) {
User user;
user.path = p_path;
user.uv_scale = p_uv_scale;
@@ -49,35 +49,35 @@ void BakedLightmapData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale
users.push_back(user);
}
-int BakedLightmapData::get_user_count() const {
+int LightmapGIData::get_user_count() const {
return users.size();
}
-NodePath BakedLightmapData::get_user_path(int p_user) const {
+NodePath LightmapGIData::get_user_path(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), NodePath());
return users[p_user].path;
}
-int32_t BakedLightmapData::get_user_sub_instance(int p_user) const {
+int32_t LightmapGIData::get_user_sub_instance(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), -1);
return users[p_user].sub_instance;
}
-Rect2 BakedLightmapData::get_user_lightmap_uv_scale(int p_user) const {
+Rect2 LightmapGIData::get_user_lightmap_uv_scale(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), Rect2());
return users[p_user].uv_scale;
}
-int BakedLightmapData::get_user_lightmap_slice_index(int p_user) const {
+int LightmapGIData::get_user_lightmap_slice_index(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), -1);
return users[p_user].slice_index;
}
-void BakedLightmapData::clear_users() {
+void LightmapGIData::clear_users() {
users.clear();
}
-void BakedLightmapData::_set_user_data(const Array &p_data) {
+void LightmapGIData::_set_user_data(const Array &p_data) {
ERR_FAIL_COND(p_data.size() <= 0);
ERR_FAIL_COND((p_data.size() % 4) != 0);
@@ -86,7 +86,7 @@ void BakedLightmapData::_set_user_data(const Array &p_data) {
}
}
-Array BakedLightmapData::_get_user_data() const {
+Array LightmapGIData::_get_user_data() const {
Array ret;
for (int i = 0; i < users.size(); i++) {
ret.push_back(users[i].path);
@@ -97,33 +97,33 @@ Array BakedLightmapData::_get_user_data() const {
return ret;
}
-RID BakedLightmapData::get_rid() const {
+RID LightmapGIData::get_rid() const {
return lightmap;
}
-void BakedLightmapData::clear() {
+void LightmapGIData::clear() {
users.clear();
}
-void BakedLightmapData::set_light_texture(const Ref<TextureLayered> &p_light_texture) {
+void LightmapGIData::set_light_texture(const Ref<TextureLayered> &p_light_texture) {
light_texture = p_light_texture;
RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics);
}
-Ref<TextureLayered> BakedLightmapData::get_light_texture() const {
+Ref<TextureLayered> LightmapGIData::get_light_texture() const {
return light_texture;
}
-void BakedLightmapData::set_uses_spherical_harmonics(bool p_enable) {
+void LightmapGIData::set_uses_spherical_harmonics(bool p_enable) {
uses_spherical_harmonics = p_enable;
RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics);
}
-bool BakedLightmapData::is_using_spherical_harmonics() const {
+bool LightmapGIData::is_using_spherical_harmonics() const {
return uses_spherical_harmonics;
}
-void BakedLightmapData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) {
+void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) {
if (p_points.size()) {
int pc = p_points.size();
ERR_FAIL_COND(pc * 9 != p_point_sh.size());
@@ -141,31 +141,31 @@ void BakedLightmapData::set_capture_data(const AABB &p_bounds, bool p_interior,
bounds = p_bounds;
}
-PackedVector3Array BakedLightmapData::get_capture_points() const {
+PackedVector3Array LightmapGIData::get_capture_points() const {
return RS::get_singleton()->lightmap_get_probe_capture_points(lightmap);
}
-PackedColorArray BakedLightmapData::get_capture_sh() const {
+PackedColorArray LightmapGIData::get_capture_sh() const {
return RS::get_singleton()->lightmap_get_probe_capture_sh(lightmap);
}
-PackedInt32Array BakedLightmapData::get_capture_tetrahedra() const {
+PackedInt32Array LightmapGIData::get_capture_tetrahedra() const {
return RS::get_singleton()->lightmap_get_probe_capture_tetrahedra(lightmap);
}
-PackedInt32Array BakedLightmapData::get_capture_bsp_tree() const {
+PackedInt32Array LightmapGIData::get_capture_bsp_tree() const {
return RS::get_singleton()->lightmap_get_probe_capture_bsp_tree(lightmap);
}
-AABB BakedLightmapData::get_capture_bounds() const {
+AABB LightmapGIData::get_capture_bounds() const {
return bounds;
}
-bool BakedLightmapData::is_interior() const {
+bool LightmapGIData::is_interior() const {
return interior;
}
-void BakedLightmapData::_set_probe_data(const Dictionary &p_data) {
+void LightmapGIData::_set_probe_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("bounds"));
ERR_FAIL_COND(!p_data.has("points"));
ERR_FAIL_COND(!p_data.has("tetrahedra"));
@@ -175,7 +175,7 @@ void BakedLightmapData::_set_probe_data(const Dictionary &p_data) {
set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"]);
}
-Dictionary BakedLightmapData::_get_probe_data() const {
+Dictionary LightmapGIData::_get_probe_data() const {
Dictionary d;
d["bounds"] = get_capture_bounds();
d["points"] = get_capture_points();
@@ -186,23 +186,23 @@ Dictionary BakedLightmapData::_get_probe_data() const {
return d;
}
-void BakedLightmapData::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &BakedLightmapData::_set_user_data);
- ClassDB::bind_method(D_METHOD("_get_user_data"), &BakedLightmapData::_get_user_data);
+void LightmapGIData::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &LightmapGIData::_set_user_data);
+ ClassDB::bind_method(D_METHOD("_get_user_data"), &LightmapGIData::_get_user_data);
- ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &BakedLightmapData::set_light_texture);
- ClassDB::bind_method(D_METHOD("get_light_texture"), &BakedLightmapData::get_light_texture);
+ ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture);
+ ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture);
- ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &BakedLightmapData::set_uses_spherical_harmonics);
- ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &BakedLightmapData::is_using_spherical_harmonics);
+ ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics);
+ ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics);
- ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &BakedLightmapData::add_user);
- ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count);
- ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path);
- ClassDB::bind_method(D_METHOD("clear_users"), &BakedLightmapData::clear_users);
+ ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &LightmapGIData::add_user);
+ ClassDB::bind_method(D_METHOD("get_user_count"), &LightmapGIData::get_user_count);
+ ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &LightmapGIData::get_user_path);
+ ClassDB::bind_method(D_METHOD("clear_users"), &LightmapGIData::clear_users);
- ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &BakedLightmapData::_set_probe_data);
- ClassDB::bind_method(D_METHOD("_get_probe_data"), &BakedLightmapData::_get_probe_data);
+ ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &LightmapGIData::_set_probe_data);
+ ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered"), "set_light_texture", "get_light_texture");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics");
@@ -210,17 +210,17 @@ void BakedLightmapData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data");
}
-BakedLightmapData::BakedLightmapData() {
+LightmapGIData::LightmapGIData() {
lightmap = RS::get_singleton()->lightmap_create();
}
-BakedLightmapData::~BakedLightmapData() {
+LightmapGIData::~LightmapGIData() {
RS::get_singleton()->free(lightmap);
}
///////////////////////////
-void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &meshes, Vector<LightsFound> &lights, Vector<Vector3> &probes) {
+void LightmapGI::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &meshes, Vector<LightsFound> &lights, Vector<Vector3> &probes) {
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_BAKED && mi->is_visible_in_tree()) {
Ref<Mesh> mesh = mi->get_mesh();
@@ -273,7 +273,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
if (!mi && s) {
Array bmeshes = p_at_node->call("get_bake_bmeshes");
if (bmeshes.size() && (bmeshes.size() & 1) == 0) {
- Transform xf = get_global_transform().affine_inverse() * s->get_global_transform();
+ Transform3D xf = get_global_transform().affine_inverse() * s->get_global_transform();
for (int i = 0; i < bmeshes.size(); i += 2) {
Ref<Mesh> mesh = bmeshes[i];
if (!mesh.is_valid()) {
@@ -282,7 +282,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
MeshesFound mf;
- Transform mesh_xf = bmeshes[i + 1];
+ Transform3D mesh_xf = bmeshes[i + 1];
mf.xform = xf * mesh_xf;
mf.node_path = get_path_to(s);
mf.subindex = i / 2;
@@ -306,7 +306,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
LightmapProbe *probe = Object::cast_to<LightmapProbe>(p_at_node);
if (probe) {
- Transform xf = get_global_transform().affine_inverse() * probe->get_global_transform();
+ Transform3D xf = get_global_transform().affine_inverse() * probe->get_global_transform();
probes.push_back(xf.origin);
}
@@ -320,7 +320,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
}
}
-int BakedLightmap::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const LocalVector<BSPSimplex> &p_simplices, const Plane &p_plane, uint32_t p_simplex) const {
+int LightmapGI::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const LocalVector<BSPSimplex> &p_simplices, const Plane &p_plane, uint32_t p_simplex) const {
int over = 0;
int under = 0;
int coplanar = 0;
@@ -348,7 +348,7 @@ int BakedLightmap::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const
//#define DEBUG_BSP
-int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const LocalVector<Plane> &p_planes, LocalVector<int32_t> &planes_tested, const LocalVector<BSPSimplex> &p_simplices, const LocalVector<int32_t> &p_simplex_indices, LocalVector<BSPNode> &bsp_nodes) {
+int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const LocalVector<Plane> &p_planes, LocalVector<int32_t> &planes_tested, const LocalVector<BSPSimplex> &p_simplices, const LocalVector<int32_t> &p_simplex_indices, LocalVector<BSPNode> &bsp_nodes) {
//if we reach here, it means there is more than one simplex
int32_t node_index = (int32_t)bsp_nodes.size();
bsp_nodes.push_back(BSPNode());
@@ -533,7 +533,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const
return node_index;
}
-bool BakedLightmap::_lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh) {
+bool LightmapGI::_lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh) {
BakeStepUD *bsud = (BakeStepUD *)ud;
bool ret = false;
if (bsud->func) {
@@ -542,7 +542,7 @@ bool BakedLightmap::_lightmap_bake_step_function(float p_completion, const Strin
return ret;
}
-void BakedLightmap::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle) {
+void LightmapGI::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle) {
for (int i = 0; i < 8; i++) {
Vector3i pos = p_cell->offset;
uint32_t half_size = p_cell->size / 2;
@@ -578,7 +578,7 @@ void BakedLightmap::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_
}
}
-void BakedLightmap::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool, Vector3iHash> &positions_used, const AABB &p_bounds) {
+void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool, Vector3iHash> &positions_used, const AABB &p_bounds) {
for (int i = 0; i < 8; i++) {
Vector3i pos = p_cell->offset;
if (i & 1) {
@@ -618,11 +618,7 @@ void BakedLightmap::_gen_new_positions_from_octree(const GenProbesOctree *p_cell
}
}
-BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_data_path, Lightmapper::BakeStepFunc p_bake_step, void *p_bake_userdata) {
- if (p_image_data_path == "" && (get_light_data().is_null() || !get_light_data()->get_path().is_resource_file())) {
- return BAKE_ERROR_NO_SAVE_PATH;
- }
-
+LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_path, Lightmapper::BakeStepFunc p_bake_step, void *p_bake_userdata) {
if (p_image_data_path == "") {
if (get_light_data().is_null()) {
return BAKE_ERROR_NO_SAVE_PATH;
@@ -891,7 +887,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d
}
for (int i = 0; i < lights_found.size(); i++) {
Light3D *light = lights_found[i].light;
- Transform xf = lights_found[i].xform;
+ Transform3D xf = lights_found[i].xform;
if (Object::cast_to<DirectionalLight3D>(light)) {
DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light);
@@ -1015,10 +1011,10 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d
/* POSTBAKE: Save Light Data */
- Ref<BakedLightmapData> data;
+ Ref<LightmapGIData> data;
if (get_light_data().is_valid()) {
data = get_light_data();
- set_light_data(Ref<BakedLightmapData>()); //clear
+ set_light_data(Ref<LightmapGIData>()); //clear
data->clear();
} else {
data.instance();
@@ -1187,7 +1183,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d
return BAKE_ERROR_OK;
}
-void BakedLightmap::_notification(int p_what) {
+void LightmapGI::_notification(int p_what) {
if (p_what == NOTIFICATION_POST_ENTER_TREE) {
if (light_data.is_valid()) {
_assign_lightmaps();
@@ -1201,7 +1197,7 @@ void BakedLightmap::_notification(int p_what) {
}
}
-void BakedLightmap::_assign_lightmaps() {
+void LightmapGI::_assign_lightmaps() {
ERR_FAIL_COND(!light_data.is_valid());
for (int i = 0; i < light_data->get_user_count(); i++) {
@@ -1220,7 +1216,7 @@ void BakedLightmap::_assign_lightmaps() {
}
}
-void BakedLightmap::_clear_lightmaps() {
+void LightmapGI::_clear_lightmaps() {
ERR_FAIL_COND(!light_data.is_valid());
for (int i = 0; i < light_data->get_user_count(); i++) {
Node *node = get_node(light_data->get_user_path(i));
@@ -1238,7 +1234,7 @@ void BakedLightmap::_clear_lightmaps() {
}
}
-void BakedLightmap::set_light_data(const Ref<BakedLightmapData> &p_data) {
+void LightmapGI::set_light_data(const Ref<LightmapGIData> &p_data) {
if (light_data.is_valid()) {
if (is_inside_tree()) {
_clear_lightmaps();
@@ -1257,119 +1253,119 @@ void BakedLightmap::set_light_data(const Ref<BakedLightmapData> &p_data) {
update_gizmo();
}
-Ref<BakedLightmapData> BakedLightmap::get_light_data() const {
+Ref<LightmapGIData> LightmapGI::get_light_data() const {
return light_data;
}
-void BakedLightmap::set_bake_quality(BakeQuality p_quality) {
+void LightmapGI::set_bake_quality(BakeQuality p_quality) {
bake_quality = p_quality;
}
-BakedLightmap::BakeQuality BakedLightmap::get_bake_quality() const {
+LightmapGI::BakeQuality LightmapGI::get_bake_quality() const {
return bake_quality;
}
-AABB BakedLightmap::get_aabb() const {
+AABB LightmapGI::get_aabb() const {
return AABB();
}
-Vector<Face3> BakedLightmap::get_faces(uint32_t p_usage_flags) const {
+Vector<Face3> LightmapGI::get_faces(uint32_t p_usage_flags) const {
return Vector<Face3>();
}
-void BakedLightmap::set_use_denoiser(bool p_enable) {
+void LightmapGI::set_use_denoiser(bool p_enable) {
use_denoiser = p_enable;
}
-bool BakedLightmap::is_using_denoiser() const {
+bool LightmapGI::is_using_denoiser() const {
return use_denoiser;
}
-void BakedLightmap::set_directional(bool p_enable) {
+void LightmapGI::set_directional(bool p_enable) {
directional = p_enable;
}
-bool BakedLightmap::is_directional() const {
+bool LightmapGI::is_directional() const {
return directional;
}
-void BakedLightmap::set_interior(bool p_enable) {
+void LightmapGI::set_interior(bool p_enable) {
interior = p_enable;
}
-bool BakedLightmap::is_interior() const {
+bool LightmapGI::is_interior() const {
return interior;
}
-void BakedLightmap::set_environment_mode(EnvironmentMode p_mode) {
+void LightmapGI::set_environment_mode(EnvironmentMode p_mode) {
environment_mode = p_mode;
notify_property_list_changed();
}
-BakedLightmap::EnvironmentMode BakedLightmap::get_environment_mode() const {
+LightmapGI::EnvironmentMode LightmapGI::get_environment_mode() const {
return environment_mode;
}
-void BakedLightmap::set_environment_custom_sky(const Ref<Sky> &p_sky) {
+void LightmapGI::set_environment_custom_sky(const Ref<Sky> &p_sky) {
environment_custom_sky = p_sky;
}
-Ref<Sky> BakedLightmap::get_environment_custom_sky() const {
+Ref<Sky> LightmapGI::get_environment_custom_sky() const {
return environment_custom_sky;
}
-void BakedLightmap::set_environment_custom_color(const Color &p_color) {
+void LightmapGI::set_environment_custom_color(const Color &p_color) {
environment_custom_color = p_color;
}
-Color BakedLightmap::get_environment_custom_color() const {
+Color LightmapGI::get_environment_custom_color() const {
return environment_custom_color;
}
-void BakedLightmap::set_environment_custom_energy(float p_energy) {
+void LightmapGI::set_environment_custom_energy(float p_energy) {
environment_custom_energy = p_energy;
}
-float BakedLightmap::get_environment_custom_energy() const {
+float LightmapGI::get_environment_custom_energy() const {
return environment_custom_energy;
}
-void BakedLightmap::set_bounces(int p_bounces) {
+void LightmapGI::set_bounces(int p_bounces) {
ERR_FAIL_COND(p_bounces < 0 || p_bounces > 16);
bounces = p_bounces;
}
-int BakedLightmap::get_bounces() const {
+int LightmapGI::get_bounces() const {
return bounces;
}
-void BakedLightmap::set_bias(float p_bias) {
+void LightmapGI::set_bias(float p_bias) {
ERR_FAIL_COND(p_bias < 0.00001);
bias = p_bias;
}
-float BakedLightmap::get_bias() const {
+float LightmapGI::get_bias() const {
return bias;
}
-void BakedLightmap::set_max_texture_size(int p_size) {
+void LightmapGI::set_max_texture_size(int p_size) {
ERR_FAIL_COND(p_size < 2048);
max_texture_size = p_size;
}
-int BakedLightmap::get_max_texture_size() const {
+int LightmapGI::get_max_texture_size() const {
return max_texture_size;
}
-void BakedLightmap::set_generate_probes(GenerateProbes p_generate_probes) {
+void LightmapGI::set_generate_probes(GenerateProbes p_generate_probes) {
gen_probes = p_generate_probes;
}
-BakedLightmap::GenerateProbes BakedLightmap::get_generate_probes() const {
+LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const {
return gen_probes;
}
-void BakedLightmap::_validate_property(PropertyInfo &property) const {
+void LightmapGI::_validate_property(PropertyInfo &property) const {
if (property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
property.usage = 0;
}
@@ -1381,47 +1377,47 @@ void BakedLightmap::_validate_property(PropertyInfo &property) const {
}
}
-void BakedLightmap::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_light_data", "data"), &BakedLightmap::set_light_data);
- ClassDB::bind_method(D_METHOD("get_light_data"), &BakedLightmap::get_light_data);
+void LightmapGI::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_light_data", "data"), &LightmapGI::set_light_data);
+ ClassDB::bind_method(D_METHOD("get_light_data"), &LightmapGI::get_light_data);
- ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &BakedLightmap::set_bake_quality);
- ClassDB::bind_method(D_METHOD("get_bake_quality"), &BakedLightmap::get_bake_quality);
+ ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &LightmapGI::set_bake_quality);
+ ClassDB::bind_method(D_METHOD("get_bake_quality"), &LightmapGI::get_bake_quality);
- ClassDB::bind_method(D_METHOD("set_bounces", "bounces"), &BakedLightmap::set_bounces);
- ClassDB::bind_method(D_METHOD("get_bounces"), &BakedLightmap::get_bounces);
+ ClassDB::bind_method(D_METHOD("set_bounces", "bounces"), &LightmapGI::set_bounces);
+ ClassDB::bind_method(D_METHOD("get_bounces"), &LightmapGI::get_bounces);
- ClassDB::bind_method(D_METHOD("set_generate_probes", "subdivision"), &BakedLightmap::set_generate_probes);
- ClassDB::bind_method(D_METHOD("get_generate_probes"), &BakedLightmap::get_generate_probes);
+ ClassDB::bind_method(D_METHOD("set_generate_probes", "subdivision"), &LightmapGI::set_generate_probes);
+ ClassDB::bind_method(D_METHOD("get_generate_probes"), &LightmapGI::get_generate_probes);
- ClassDB::bind_method(D_METHOD("set_bias", "bias"), &BakedLightmap::set_bias);
- ClassDB::bind_method(D_METHOD("get_bias"), &BakedLightmap::get_bias);
+ ClassDB::bind_method(D_METHOD("set_bias", "bias"), &LightmapGI::set_bias);
+ ClassDB::bind_method(D_METHOD("get_bias"), &LightmapGI::get_bias);
- ClassDB::bind_method(D_METHOD("set_environment_mode", "mode"), &BakedLightmap::set_environment_mode);
- ClassDB::bind_method(D_METHOD("get_environment_mode"), &BakedLightmap::get_environment_mode);
+ ClassDB::bind_method(D_METHOD("set_environment_mode", "mode"), &LightmapGI::set_environment_mode);
+ ClassDB::bind_method(D_METHOD("get_environment_mode"), &LightmapGI::get_environment_mode);
- ClassDB::bind_method(D_METHOD("set_environment_custom_sky", "sky"), &BakedLightmap::set_environment_custom_sky);
- ClassDB::bind_method(D_METHOD("get_environment_custom_sky"), &BakedLightmap::get_environment_custom_sky);
+ ClassDB::bind_method(D_METHOD("set_environment_custom_sky", "sky"), &LightmapGI::set_environment_custom_sky);
+ ClassDB::bind_method(D_METHOD("get_environment_custom_sky"), &LightmapGI::get_environment_custom_sky);
- ClassDB::bind_method(D_METHOD("set_environment_custom_color", "color"), &BakedLightmap::set_environment_custom_color);
- ClassDB::bind_method(D_METHOD("get_environment_custom_color"), &BakedLightmap::get_environment_custom_color);
+ ClassDB::bind_method(D_METHOD("set_environment_custom_color", "color"), &LightmapGI::set_environment_custom_color);
+ ClassDB::bind_method(D_METHOD("get_environment_custom_color"), &LightmapGI::get_environment_custom_color);
- ClassDB::bind_method(D_METHOD("set_environment_custom_energy", "energy"), &BakedLightmap::set_environment_custom_energy);
- ClassDB::bind_method(D_METHOD("get_environment_custom_energy"), &BakedLightmap::get_environment_custom_energy);
+ ClassDB::bind_method(D_METHOD("set_environment_custom_energy", "energy"), &LightmapGI::set_environment_custom_energy);
+ ClassDB::bind_method(D_METHOD("get_environment_custom_energy"), &LightmapGI::get_environment_custom_energy);
- ClassDB::bind_method(D_METHOD("set_max_texture_size", "max_texture_size"), &BakedLightmap::set_max_texture_size);
- ClassDB::bind_method(D_METHOD("get_max_texture_size"), &BakedLightmap::get_max_texture_size);
+ ClassDB::bind_method(D_METHOD("set_max_texture_size", "max_texture_size"), &LightmapGI::set_max_texture_size);
+ ClassDB::bind_method(D_METHOD("get_max_texture_size"), &LightmapGI::get_max_texture_size);
- ClassDB::bind_method(D_METHOD("set_use_denoiser", "use_denoiser"), &BakedLightmap::set_use_denoiser);
- ClassDB::bind_method(D_METHOD("is_using_denoiser"), &BakedLightmap::is_using_denoiser);
+ ClassDB::bind_method(D_METHOD("set_use_denoiser", "use_denoiser"), &LightmapGI::set_use_denoiser);
+ ClassDB::bind_method(D_METHOD("is_using_denoiser"), &LightmapGI::is_using_denoiser);
- ClassDB::bind_method(D_METHOD("set_interior", "enable"), &BakedLightmap::set_interior);
- ClassDB::bind_method(D_METHOD("is_interior"), &BakedLightmap::is_interior);
+ ClassDB::bind_method(D_METHOD("set_interior", "enable"), &LightmapGI::set_interior);
+ ClassDB::bind_method(D_METHOD("is_interior"), &LightmapGI::is_interior);
- ClassDB::bind_method(D_METHOD("set_directional", "directional"), &BakedLightmap::set_directional);
- ClassDB::bind_method(D_METHOD("is_directional"), &BakedLightmap::is_directional);
+ ClassDB::bind_method(D_METHOD("set_directional", "directional"), &LightmapGI::set_directional);
+ ClassDB::bind_method(D_METHOD("is_directional"), &LightmapGI::is_directional);
- // ClassDB::bind_method(D_METHOD("bake", "from_node"), &BakedLightmap::bake, DEFVAL(Variant()));
+ // ClassDB::bind_method(D_METHOD("bake", "from_node"), &LightmapGI::bake, DEFVAL(Variant()));
ADD_GROUP("Tweaks", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "quality", PROPERTY_HINT_ENUM, "Low,Medium,High,Ultra"), "set_bake_quality", "get_bake_quality");
@@ -1439,7 +1435,7 @@ void BakedLightmap::_bind_methods() {
ADD_GROUP("Gen Probes", "generate_probes_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "generate_probes_subdiv", PROPERTY_HINT_ENUM, "Disabled,4,8,16,32"), "set_generate_probes", "get_generate_probes");
ADD_GROUP("Data", "");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedLightmapData"), "set_light_data", "get_light_data");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "LightmapGIData"), "set_light_data", "get_light_data");
BIND_ENUM_CONSTANT(BAKE_QUALITY_LOW);
BIND_ENUM_CONSTANT(BAKE_QUALITY_MEDIUM);
@@ -1466,5 +1462,5 @@ void BakedLightmap::_bind_methods() {
BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_CUSTOM_COLOR);
}
-BakedLightmap::BakedLightmap() {
+LightmapGI::LightmapGI() {
}
diff --git a/scene/3d/baked_lightmap.h b/scene/3d/lightmap_gi.h
index e2d89ab2d0..8a54512383 100644
--- a/scene/3d/baked_lightmap.h
+++ b/scene/3d/lightmap_gi.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* baked_lightmap.h */
+/* lightmap_gi.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BAKED_LIGHTMAP_H
-#define BAKED_LIGHTMAP_H
+#ifndef LIGHTMAP_GI_H
+#define LIGHTMAP_GI_H
#include "core/templates/local_vector.h"
#include "scene/3d/light_3d.h"
@@ -39,8 +39,8 @@
#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/sky.h"
-class BakedLightmapData : public Resource {
- GDCLASS(BakedLightmapData, Resource);
+class LightmapGIData : public Resource {
+ GDCLASS(LightmapGIData, Resource);
RES_BASE_EXTENSION("lmbake")
Ref<TextureLayered> light_texture;
@@ -95,12 +95,12 @@ public:
void clear();
virtual RID get_rid() const override;
- BakedLightmapData();
- ~BakedLightmapData();
+ LightmapGIData();
+ ~LightmapGIData();
};
-class BakedLightmap : public VisualInstance3D {
- GDCLASS(BakedLightmap, VisualInstance3D);
+class LightmapGI : public VisualInstance3D {
+ GDCLASS(LightmapGI, VisualInstance3D);
public:
enum BakeQuality {
@@ -149,15 +149,15 @@ private:
bool directional = false;
GenerateProbes gen_probes = GENERATE_PROBES_DISABLED;
- Ref<BakedLightmapData> light_data;
+ Ref<LightmapGIData> light_data;
struct LightsFound {
- Transform xform;
+ Transform3D xform;
Light3D *light = nullptr;
};
struct MeshesFound {
- Transform xform;
+ Transform3D xform;
NodePath node_path;
int32_t subindex = 0;
Ref<Mesh> mesh;
@@ -230,8 +230,8 @@ protected:
void _notification(int p_what);
public:
- void set_light_data(const Ref<BakedLightmapData> &p_data);
- Ref<BakedLightmapData> get_light_data() const;
+ void set_light_data(const Ref<LightmapGIData> &p_data);
+ Ref<LightmapGIData> get_light_data() const;
void set_bake_quality(BakeQuality p_quality);
BakeQuality get_bake_quality() const;
@@ -273,12 +273,12 @@ public:
Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
BakeError bake(Node *p_from_node, String p_image_data_path = "", Lightmapper::BakeStepFunc p_bake_step = nullptr, void *p_bake_userdata = nullptr);
- BakedLightmap();
+ LightmapGI();
};
-VARIANT_ENUM_CAST(BakedLightmap::BakeQuality);
-VARIANT_ENUM_CAST(BakedLightmap::GenerateProbes);
-VARIANT_ENUM_CAST(BakedLightmap::BakeError);
-VARIANT_ENUM_CAST(BakedLightmap::EnvironmentMode);
+VARIANT_ENUM_CAST(LightmapGI::BakeQuality);
+VARIANT_ENUM_CAST(LightmapGI::GenerateProbes);
+VARIANT_ENUM_CAST(LightmapGI::BakeError);
+VARIANT_ENUM_CAST(LightmapGI::EnvironmentMode);
#endif // BAKED_LIGHTMAP_H
diff --git a/scene/3d/lightmapper.cpp b/scene/3d/lightmapper.cpp
index c17ac52aa2..9e5078ba95 100644
--- a/scene/3d/lightmapper.cpp
+++ b/scene/3d/lightmapper.cpp
@@ -39,6 +39,15 @@ Ref<LightmapDenoiser> LightmapDenoiser::create() {
return Ref<LightmapDenoiser>();
}
+LightmapRaycaster *(*LightmapRaycaster::create_function)() = nullptr;
+
+Ref<LightmapRaycaster> LightmapRaycaster::create() {
+ if (create_function) {
+ return Ref<LightmapRaycaster>(create_function());
+ }
+ return Ref<LightmapRaycaster>();
+}
+
Lightmapper::CreateFunc Lightmapper::create_custom = nullptr;
Lightmapper::CreateFunc Lightmapper::create_gpu = nullptr;
Lightmapper::CreateFunc Lightmapper::create_cpu = nullptr;
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index a07a964c01..3a6a88d435 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -34,8 +34,18 @@
#include "scene/resources/mesh.h"
#include "servers/rendering/rendering_device.h"
-class LightmapDenoiser : public Reference {
- GDCLASS(LightmapDenoiser, Reference)
+#if !defined(__aligned)
+
+#if defined(_WIN32) && defined(_MSC_VER)
+#define __aligned(...) __declspec(align(__VA_ARGS__))
+#else
+#define __aligned(...) __attribute__((aligned(__VA_ARGS__)))
+#endif
+
+#endif
+
+class LightmapDenoiser : public RefCounted {
+ GDCLASS(LightmapDenoiser, RefCounted)
protected:
static LightmapDenoiser *(*create_function)();
@@ -44,8 +54,75 @@ public:
static Ref<LightmapDenoiser> create();
};
-class Lightmapper : public Reference {
- GDCLASS(Lightmapper, Reference)
+class LightmapRaycaster : public RefCounted {
+ GDCLASS(LightmapRaycaster, RefCounted)
+protected:
+ static LightmapRaycaster *(*create_function)();
+
+public:
+ // compatible with embree3 rays
+ struct __aligned(16) Ray {
+ const static unsigned int INVALID_GEOMETRY_ID = ((unsigned int)-1); // from rtcore_common.h
+
+ /*! Default construction does nothing. */
+ _FORCE_INLINE_ Ray() :
+ geomID(INVALID_GEOMETRY_ID) {}
+
+ /*! Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far. */
+ _FORCE_INLINE_ Ray(const Vector3 &org,
+ const Vector3 &dir,
+ float tnear = 0.0f,
+ float tfar = INFINITY) :
+ org(org),
+ tnear(tnear),
+ dir(dir),
+ time(0.0f),
+ tfar(tfar),
+ mask(-1),
+ u(0.0),
+ v(0.0),
+ primID(INVALID_GEOMETRY_ID),
+ geomID(INVALID_GEOMETRY_ID),
+ instID(INVALID_GEOMETRY_ID) {}
+
+ /*! Tests if we hit something. */
+ _FORCE_INLINE_ explicit operator bool() const { return geomID != INVALID_GEOMETRY_ID; }
+
+ public:
+ Vector3 org; //!< Ray origin + tnear
+ float tnear; //!< Start of ray segment
+ Vector3 dir; //!< Ray direction + tfar
+ float time; //!< Time of this ray for motion blur.
+ float tfar; //!< End of ray segment
+ unsigned int mask; //!< used to mask out objects during traversal
+ unsigned int id; //!< ray ID
+ unsigned int flags; //!< ray flags
+
+ Vector3 normal; //!< Not normalized geometry normal
+ float u; //!< Barycentric u coordinate of hit
+ float v; //!< Barycentric v coordinate of hit
+ unsigned int primID; //!< primitive ID
+ unsigned int geomID; //!< geometry ID
+ unsigned int instID; //!< instance ID
+ };
+
+ virtual bool intersect(Ray &p_ray) = 0;
+
+ virtual void intersect(Vector<Ray> &r_rays) = 0;
+
+ virtual void add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) = 0;
+ virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) = 0;
+ virtual void commit() = 0;
+
+ virtual void set_mesh_filter(const Set<int> &p_mesh_ids) = 0;
+ virtual void clear_mesh_filter() = 0;
+
+ static Ref<LightmapRaycaster> create();
+};
+
+class Lightmapper : public RefCounted {
+ GDCLASS(Lightmapper, RefCounted)
public:
enum GenerateProbes {
GENERATE_PROBES_DISABLED,
diff --git a/scene/3d/listener_3d.cpp b/scene/3d/listener_3d.cpp
index 9842f152d7..636be083ab 100644
--- a/scene/3d/listener_3d.cpp
+++ b/scene/3d/listener_3d.cpp
@@ -105,7 +105,7 @@ void Listener3D::_notification(int p_what) {
}
}
-Transform Listener3D::get_listener_transform() const {
+Transform3D Listener3D::get_listener_transform() const {
return get_global_transform().orthonormalized();
}
diff --git a/scene/3d/listener_3d.h b/scene/3d/listener_3d.h
index 85657a8e53..bcc66f167c 100644
--- a/scene/3d/listener_3d.h
+++ b/scene/3d/listener_3d.h
@@ -65,7 +65,7 @@ public:
void clear_current();
bool is_current() const;
- virtual Transform get_listener_transform() const;
+ virtual Transform3D get_listener_transform() const;
void set_visible_layers(uint32_t p_layers);
uint32_t get_visible_layers() const;
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index 7623ede0fc..c495f68890 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -271,6 +271,41 @@ void MeshInstance3D::create_convex_collision() {
}
}
+Node *MeshInstance3D::create_multiple_convex_collisions_node() {
+ if (mesh.is_null()) {
+ return nullptr;
+ }
+
+ Vector<Ref<Shape3D>> shapes = mesh->convex_decompose();
+ if (!shapes.size()) {
+ return nullptr;
+ }
+
+ StaticBody3D *static_body = memnew(StaticBody3D);
+ for (int i = 0; i < shapes.size(); i++) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shapes[i]);
+ static_body->add_child(cshape);
+ }
+ return static_body;
+}
+
+void MeshInstance3D::create_multiple_convex_collisions() {
+ StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_multiple_convex_collisions_node());
+ ERR_FAIL_COND(!static_body);
+ static_body->set_name(String(get_name()) + "_col");
+
+ add_child(static_body);
+ if (get_owner()) {
+ static_body->set_owner(get_owner());
+ int count = static_body->get_child_count();
+ for (int i = 0; i < count; i++) {
+ CollisionShape3D *cshape = Object::cast_to<CollisionShape3D>(static_body->get_child(i));
+ cshape->set_owner(get_owner());
+ }
+ }
+}
+
void MeshInstance3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
_resolve_skeleton_path();
@@ -321,6 +356,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
void MeshInstance3D::_mesh_changed() {
ERR_FAIL_COND(mesh.is_null());
surface_override_materials.resize(mesh->get_surface_count());
+ update_gizmo();
}
void MeshInstance3D::create_debug_tangents() {
@@ -391,7 +427,7 @@ void MeshInstance3D::create_debug_tangents() {
add_child(mi);
#ifdef TOOLS_ENABLED
- if (this == get_tree()->get_edited_scene_root()) {
+ if (is_inside_tree() && this == get_tree()->get_edited_scene_root()) {
mi->set_owner(this);
} else {
mi->set_owner(get_owner());
@@ -417,6 +453,8 @@ void MeshInstance3D::_bind_methods() {
ClassDB::set_method_flags("MeshInstance3D", "create_trimesh_collision", METHOD_FLAGS_DEFAULT);
ClassDB::bind_method(D_METHOD("create_convex_collision"), &MeshInstance3D::create_convex_collision);
ClassDB::set_method_flags("MeshInstance3D", "create_convex_collision", METHOD_FLAGS_DEFAULT);
+ ClassDB::bind_method(D_METHOD("create_multiple_convex_collisions"), &MeshInstance3D::create_multiple_convex_collisions);
+ ClassDB::set_method_flags("MeshInstance3D", "create_multiple_convex_collisions", METHOD_FLAGS_DEFAULT);
ClassDB::bind_method(D_METHOD("create_debug_tangents"), &MeshInstance3D::create_debug_tangents);
ClassDB::set_method_flags("MeshInstance3D", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index 8aec227337..9dea5804e0 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -86,6 +86,9 @@ public:
Node *create_convex_collision_node();
void create_convex_collision();
+ Node *create_multiple_convex_collisions_node();
+ void create_multiple_convex_collisions();
+
void create_debug_tangents();
virtual AABB get_aabb() const override;
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 7346f243ba..64cfe4dca7 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -34,6 +34,8 @@
#include "servers/navigation_server_3d.h"
void NavigationAgent3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent3D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent3D::set_target_desired_distance);
ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent3D::get_target_desired_distance);
@@ -95,8 +97,11 @@ 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");
+ if (agent_parent != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map());
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+ }
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -106,12 +111,7 @@ void NavigationAgent3D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
- if (!target_reached) {
- if (distance_to_target() < target_desired_distance) {
- emit_signal("target_reached");
- target_reached = true;
- }
- }
+ _check_distance_to_target();
}
} break;
}
@@ -309,6 +309,7 @@ void NavigationAgent3D::update_navigation() {
while (o.distance_to(navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0)) < target_desired_distance) {
nav_path_index += 1;
if (nav_path_index == navigation_path.size()) {
+ _check_distance_to_target();
nav_path_index -= 1;
navigation_finished = true;
emit_signal("navigation_finished");
@@ -317,3 +318,12 @@ void NavigationAgent3D::update_navigation() {
}
}
}
+
+void NavigationAgent3D::_check_distance_to_target() {
+ if (!target_reached) {
+ if (distance_to_target() < target_desired_distance) {
+ emit_signal("target_reached");
+ target_reached = true;
+ }
+ }
+}
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 814c0714e8..56da2d1acf 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -147,6 +147,7 @@ public:
private:
void update_navigation();
+ void _check_distance_to_target();
};
#endif
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index ba0f8cc870..e96b8ee1f9 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -32,6 +32,7 @@
#include "core/config/engine.h"
#include "core/object/message_queue.h"
+#include "scene/3d/visual_instance_3d.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
@@ -148,6 +149,7 @@ void Node3D::_notification(int p_what) {
_notify_dirty();
notification(NOTIFICATION_ENTER_WORLD);
+ _update_visibility_parent(true);
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -161,6 +163,7 @@ void Node3D::_notification(int p_what) {
data.parent = nullptr;
data.C = nullptr;
data.top_level_active = false;
+ _update_visibility_parent(true);
} break;
case NOTIFICATION_ENTER_WORLD: {
data.inside_world = true;
@@ -223,7 +226,7 @@ void Node3D::_notification(int p_what) {
}
}
-void Node3D::set_transform(const Transform &p_transform) {
+void Node3D::set_transform(const Transform3D &p_transform) {
data.local_transform = p_transform;
data.dirty |= DIRTY_VECTORS;
_propagate_transform_changed(this);
@@ -232,8 +235,8 @@ void Node3D::set_transform(const Transform &p_transform) {
}
}
-void Node3D::set_global_transform(const Transform &p_transform) {
- Transform xform =
+void Node3D::set_global_transform(const Transform3D &p_transform) {
+ Transform3D xform =
(data.parent && !data.top_level_active) ?
data.parent->get_global_transform().affine_inverse() * p_transform :
p_transform;
@@ -241,16 +244,15 @@ void Node3D::set_global_transform(const Transform &p_transform) {
set_transform(xform);
}
-Transform Node3D::get_transform() const {
+Transform3D 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());
+Transform3D Node3D::get_global_transform() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), Transform3D());
if (data.dirty & DIRTY_GLOBAL) {
if (data.dirty & DIRTY_LOCAL) {
@@ -274,25 +276,28 @@ Transform Node3D::get_global_transform() const {
}
#ifdef TOOLS_ENABLED
-Transform Node3D::get_global_gizmo_transform() const {
+Transform3D Node3D::get_global_gizmo_transform() const {
return get_global_transform();
}
-Transform Node3D::get_local_gizmo_transform() const {
+Transform3D Node3D::get_local_gizmo_transform() const {
return get_transform();
}
#endif
-Node3D *Node3D::get_parent_spatial() const {
- return data.parent;
+Node3D *Node3D::get_parent_node_3d() const {
+ if (data.top_level) {
+ return nullptr;
+ }
+
+ return Object::cast_to<Node3D>(get_parent());
}
-Transform Node3D::get_relative_transform(const Node *p_parent) const {
- if (p_parent == this) {
- return Transform();
- }
+Transform3D Node3D::get_relative_transform(const Node *p_parent) const {
+ if (p_parent == this)
+ return Transform3D();
- ERR_FAIL_COND_V(!data.parent, Transform());
+ ERR_FAIL_COND_V(!data.parent, Transform3D());
if (p_parent == data.parent) {
return get_transform();
@@ -301,8 +306,8 @@ Transform Node3D::get_relative_transform(const Node *p_parent) const {
}
}
-void Node3D::set_translation(const Vector3 &p_translation) {
- data.local_transform.origin = p_translation;
+void Node3D::set_position(const Vector3 &p_position) {
+ data.local_transform.origin = p_position;
_propagate_transform_changed(this);
if (data.notify_local_transform) {
notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
@@ -341,7 +346,7 @@ void Node3D::set_scale(const Vector3 &p_scale) {
}
}
-Vector3 Node3D::get_translation() const {
+Vector3 Node3D::get_position() const {
return data.local_transform.origin;
}
@@ -557,87 +562,87 @@ bool Node3D::is_visible() const {
}
void Node3D::rotate_object_local(const Vector3 &p_axis, float p_angle) {
- Transform t = get_transform();
+ Transform3D 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();
+ Transform3D t = get_transform();
t.basis.rotate(p_axis, p_angle);
set_transform(t);
}
void Node3D::rotate_x(float p_angle) {
- Transform t = get_transform();
+ Transform3D 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();
+ Transform3D 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();
+ Transform3D 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();
+ Transform3D t = get_transform();
t.translate(p_offset);
set_transform(t);
}
void Node3D::translate_object_local(const Vector3 &p_offset) {
- Transform t = get_transform();
+ Transform3D t = get_transform();
- Transform s;
+ Transform3D s;
s.translate(p_offset);
set_transform(t * s);
}
void Node3D::scale(const Vector3 &p_ratio) {
- Transform t = get_transform();
+ Transform3D t = get_transform();
t.basis.scale(p_ratio);
set_transform(t);
}
void Node3D::scale_object_local(const Vector3 &p_scale) {
- Transform t = get_transform();
+ Transform3D 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();
+ Transform3D 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();
+ Transform3D 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();
+ Transform3D t = get_global_transform();
t.origin += p_offset;
set_global_transform(t);
}
void Node3D::orthonormalize() {
- Transform t = get_transform();
+ Transform3D t = get_transform();
t.orthonormalize();
set_transform(t);
}
void Node3D::set_identity() {
- set_transform(Transform());
+ set_transform(Transform3D());
}
void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) {
@@ -649,7 +654,7 @@ void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target
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;
+ Transform3D lookat;
lookat.origin = p_pos;
Vector3 original_scale(get_scale());
@@ -692,11 +697,56 @@ void Node3D::force_update_transform() {
notification(NOTIFICATION_TRANSFORM_CHANGED);
}
+void Node3D::_update_visibility_parent(bool p_update_root) {
+ RID new_parent;
+
+ if (!visibility_parent_path.is_empty()) {
+ if (!p_update_root) {
+ return;
+ }
+ Node *parent = get_node_or_null(visibility_parent_path);
+ ERR_FAIL_COND_MSG(!parent, "Can't find visibility parent node at path: " + visibility_parent_path);
+ ERR_FAIL_COND_MSG(parent == this, "The visibility parent can't be the same node.");
+ GeometryInstance3D *gi = Object::cast_to<GeometryInstance3D>(parent);
+ ERR_FAIL_COND_MSG(!gi, "The visibility parent node must be a GeometryInstance3D, at path: " + visibility_parent_path);
+ new_parent = gi ? gi->get_instance() : RID();
+ } else if (data.parent) {
+ new_parent = data.parent->data.visibility_parent;
+ }
+
+ if (new_parent == data.visibility_parent) {
+ return;
+ }
+
+ data.visibility_parent = new_parent;
+
+ VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(this);
+ if (vi) {
+ RS::get_singleton()->instance_set_visibility_parent(vi->get_instance(), data.visibility_parent);
+ }
+
+ for (List<Node3D *>::Element *E = data.children.front(); E; E = E->next()) {
+ Node3D *c = E->get();
+ c->_update_visibility_parent(false);
+ }
+}
+
+void Node3D::set_visibility_parent(const NodePath &p_path) {
+ visibility_parent_path = p_path;
+ if (is_inside_tree()) {
+ _update_visibility_parent(true);
+ }
+}
+
+NodePath Node3D::get_visibility_parent() const {
+ return visibility_parent_path;
+}
+
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_position", "position"), &Node3D::set_position);
+ ClassDB::bind_method(D_METHOD("get_position"), &Node3D::get_position);
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);
@@ -705,7 +755,7 @@ void Node3D::_bind_methods() {
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("get_parent_node_3d"), &Node3D::get_parent_node_3d);
ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Node3D::set_ignore_transform_notification);
ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &Node3D::set_as_top_level);
ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &Node3D::is_set_as_top_level);
@@ -715,6 +765,9 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_update_transform"), &Node3D::force_update_transform);
+ ClassDB::bind_method(D_METHOD("set_visibility_parent", "path"), &Node3D::set_visibility_parent);
+ ClassDB::bind_method(D_METHOD("get_visibility_parent"), &Node3D::get_visibility_parent);
+
ClassDB::bind_method(D_METHOD("_update_gizmo"), &Node3D::_update_gizmo);
ClassDB::bind_method(D_METHOD("update_gizmo"), &Node3D::update_gizmo);
@@ -758,18 +811,19 @@ void Node3D::_bind_methods() {
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_PROPERTY( PropertyInfo(Variant::TRANSFORM3D,"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::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
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_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level");
ADD_GROUP("Matrix", "");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "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::NODE_PATH, "visibility_parent", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GeometryInstance3D"), "set_visibility_parent", "get_visibility_parent");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "Node3DGizmo", 0), "set_gizmo", "get_gizmo");
ADD_SIGNAL(MethodInfo("visibility_changed"));
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index a62c7b31a8..c7e36cf2ec 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -34,8 +34,8 @@
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
-class Node3DGizmo : public Reference {
- GDCLASS(Node3DGizmo, Reference);
+class Node3DGizmo : public RefCounted {
+ GDCLASS(Node3DGizmo, RefCounted);
public:
virtual void create() = 0;
@@ -62,8 +62,8 @@ class Node3D : public Node {
mutable SelfList<Node> xform_change;
struct Data {
- mutable Transform global_transform;
- mutable Transform local_transform;
+ mutable Transform3D global_transform;
+ mutable Transform3D local_transform;
mutable Vector3 rotation;
mutable Vector3 scale = Vector3(1, 1, 1);
@@ -75,6 +75,8 @@ class Node3D : public Node {
bool top_level = false;
bool inside_world = false;
+ RID visibility_parent;
+
int children_lock = 0;
Node3D *parent = nullptr;
List<Node3D *> children;
@@ -95,12 +97,17 @@ class Node3D : public Node {
} data;
+ NodePath visibility_parent_path;
+
void _update_gizmo();
void _notify_dirty();
void _propagate_transform_changed(Node3D *p_origin);
void _propagate_visibility_changed();
+ void _propagate_visibility_parent();
+ void _update_visibility_parent(bool p_update_root);
+
protected:
_FORCE_INLINE_ void set_ignore_transform_notification(bool p_ignore) { data.ignore_notification = p_ignore; }
@@ -118,29 +125,29 @@ public:
NOTIFICATION_LOCAL_TRANSFORM_CHANGED = 44,
};
- Node3D *get_parent_spatial() const;
+ Node3D *get_parent_node_3d() const;
Ref<World3D> get_world_3d() const;
- void set_translation(const Vector3 &p_translation);
+ void set_position(const Vector3 &p_position);
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_position() 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);
+ void set_transform(const Transform3D &p_transform);
+ void set_global_transform(const Transform3D &p_transform);
- Transform get_transform() const;
- Transform get_global_transform() const;
+ Transform3D get_transform() const;
+ Transform3D get_global_transform() const;
#ifdef TOOLS_ENABLED
- virtual Transform get_global_gizmo_transform() const;
- virtual Transform get_local_gizmo_transform() const;
+ virtual Transform3D get_global_gizmo_transform() const;
+ virtual Transform3D get_local_gizmo_transform() const;
#endif
void set_as_top_level(bool p_enabled);
@@ -156,7 +163,7 @@ public:
_FORCE_INLINE_ bool is_inside_world() const { return data.inside_world; }
- Transform get_relative_transform(const Node *p_parent) const;
+ Transform3D get_relative_transform(const Node *p_parent) const;
void rotate(const Vector3 &p_axis, float p_angle);
void rotate_x(float p_angle);
@@ -196,6 +203,9 @@ public:
void force_update_transform();
+ void set_visibility_parent(const NodePath &p_path);
+ NodePath get_visibility_parent() const;
+
Node3D();
};
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
new file mode 100644
index 0000000000..429e1d4b98
--- /dev/null
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -0,0 +1,335 @@
+/*************************************************************************/
+/* occluder_instance_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "occluder_instance_3d.h"
+#include "core/core_string_names.h"
+#include "scene/3d/mesh_instance_3d.h"
+
+RID Occluder3D::get_rid() const {
+ if (!occluder.is_valid()) {
+ occluder = RS::get_singleton()->occluder_create();
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ return occluder;
+}
+
+void Occluder3D::set_vertices(PackedVector3Array p_vertices) {
+ vertices = p_vertices;
+ if (occluder.is_valid()) {
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ _update_changes();
+}
+
+PackedVector3Array Occluder3D::get_vertices() const {
+ return vertices;
+}
+
+void Occluder3D::set_indices(PackedInt32Array p_indices) {
+ indices = p_indices;
+ if (occluder.is_valid()) {
+ RS::get_singleton()->occluder_set_mesh(occluder, vertices, indices);
+ }
+ _update_changes();
+}
+
+PackedInt32Array Occluder3D::get_indices() const {
+ return indices;
+}
+
+void Occluder3D::_update_changes() {
+ aabb = AABB();
+
+ const Vector3 *ptr = vertices.ptr();
+ for (int i = 0; i < vertices.size(); i++) {
+ aabb.expand_to(ptr[i]);
+ }
+
+ debug_lines.clear();
+ debug_mesh.unref();
+
+ emit_changed();
+}
+
+Vector<Vector3> Occluder3D::get_debug_lines() const {
+ if (!debug_lines.is_empty()) {
+ return debug_lines;
+ }
+
+ if (indices.size() % 3 != 0) {
+ return Vector<Vector3>();
+ }
+
+ for (int i = 0; i < indices.size() / 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ int a = indices[i * 3 + j];
+ int b = indices[i * 3 + (j + 1) % 3];
+ ERR_FAIL_INDEX_V_MSG(a, vertices.size(), Vector<Vector3>(), "Occluder indices are out of range.");
+ ERR_FAIL_INDEX_V_MSG(b, vertices.size(), Vector<Vector3>(), "Occluder indices are out of range.");
+ debug_lines.push_back(vertices[a]);
+ debug_lines.push_back(vertices[b]);
+ }
+ }
+ return debug_lines;
+}
+
+Ref<ArrayMesh> Occluder3D::get_debug_mesh() const {
+ if (debug_mesh.is_valid()) {
+ return debug_mesh;
+ }
+
+ if (indices.size() % 3 != 0) {
+ return debug_mesh;
+ }
+
+ Array arrays;
+ arrays.resize(Mesh::ARRAY_MAX);
+ arrays[Mesh::ARRAY_VERTEX] = vertices;
+ arrays[Mesh::ARRAY_INDEX] = indices;
+
+ debug_mesh.instance();
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
+ return debug_mesh;
+}
+
+AABB Occluder3D::get_aabb() const {
+ return aabb;
+}
+
+void Occluder3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &Occluder3D::set_vertices);
+ ClassDB::bind_method(D_METHOD("get_vertices"), &Occluder3D::get_vertices);
+
+ ClassDB::bind_method(D_METHOD("set_indices", "indices"), &Occluder3D::set_indices);
+ ClassDB::bind_method(D_METHOD("get_indices"), &Occluder3D::get_indices);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_vertices", "get_vertices");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "indices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_indices", "get_indices");
+}
+
+Occluder3D::Occluder3D() {
+}
+
+Occluder3D::~Occluder3D() {
+ if (occluder.is_valid()) {
+ RS::get_singleton()->free(occluder);
+ }
+}
+/////////////////////////////////////////////////
+
+AABB OccluderInstance3D::get_aabb() const {
+ if (occluder.is_valid()) {
+ return occluder->get_aabb();
+ }
+ return AABB();
+}
+
+Vector<Face3> OccluderInstance3D::get_faces(uint32_t p_usage_flags) const {
+ return Vector<Face3>();
+}
+
+void OccluderInstance3D::set_occluder(const Ref<Occluder3D> &p_occluder) {
+ if (occluder == p_occluder) {
+ return;
+ }
+
+ if (occluder.is_valid()) {
+ occluder->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &OccluderInstance3D::_occluder_changed));
+ }
+
+ occluder = p_occluder;
+
+ if (occluder.is_valid()) {
+ set_base(occluder->get_rid());
+ occluder->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &OccluderInstance3D::_occluder_changed));
+ } else {
+ set_base(RID());
+ }
+
+ update_gizmo();
+}
+
+void OccluderInstance3D::_occluder_changed() {
+ update_gizmo();
+}
+
+Ref<Occluder3D> OccluderInstance3D::get_occluder() const {
+ return occluder;
+}
+
+void OccluderInstance3D::set_bake_mask(uint32_t p_mask) {
+ bake_mask = p_mask;
+}
+
+uint32_t OccluderInstance3D::get_bake_mask() const {
+ return bake_mask;
+}
+
+void OccluderInstance3D::set_bake_mask_bit(int p_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_layer, 32);
+ if (p_enable) {
+ set_bake_mask(bake_mask | (1 << p_layer));
+ } else {
+ set_bake_mask(bake_mask & (~(1 << p_layer)));
+ }
+}
+
+bool OccluderInstance3D::get_bake_mask_bit(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, 32, false);
+ return (bake_mask & (1 << p_layer));
+}
+
+bool OccluderInstance3D::_bake_material_check(Ref<Material> p_material) {
+ StandardMaterial3D *standard_mat = Object::cast_to<StandardMaterial3D>(p_material.ptr());
+ if (standard_mat && standard_mat->get_transparency() != StandardMaterial3D::TRANSPARENCY_DISABLED) {
+ return false;
+ }
+ return true;
+}
+
+void OccluderInstance3D::_bake_node(Node *p_node, PackedVector3Array &r_vertices, PackedInt32Array &r_indices) {
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
+ if (mi && mi->is_visible_in_tree()) {
+ Ref<Mesh> mesh = mi->get_mesh();
+ bool valid = true;
+
+ if (mesh.is_null()) {
+ valid = false;
+ }
+
+ if (valid && !_bake_material_check(mi->get_material_override())) {
+ valid = false;
+ }
+
+ if ((mi->get_layer_mask() & bake_mask) == 0) {
+ valid = false;
+ }
+
+ if (valid) {
+ Transform3D global_to_local = get_global_transform().affine_inverse() * mi->get_global_transform();
+
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ continue;
+ }
+
+ if (mi->get_surface_override_material(i).is_valid()) {
+ if (!_bake_material_check(mi->get_surface_override_material(i))) {
+ continue;
+ }
+ } else {
+ if (!_bake_material_check(mesh->surface_get_material(i))) {
+ continue;
+ }
+ }
+
+ Array arrays = mesh->surface_get_arrays(i);
+
+ int vertex_offset = r_vertices.size();
+ PackedVector3Array vertices = arrays[Mesh::ARRAY_VERTEX];
+ r_vertices.resize(r_vertices.size() + vertices.size());
+
+ Vector3 *vtx_ptr = r_vertices.ptrw();
+ for (int j = 0; j < vertices.size(); j++) {
+ vtx_ptr[vertex_offset + j] = global_to_local.xform(vertices[j]);
+ }
+
+ int index_offset = r_indices.size();
+ PackedInt32Array indices = arrays[Mesh::ARRAY_INDEX];
+ r_indices.resize(r_indices.size() + indices.size());
+
+ int *idx_ptr = r_indices.ptrw();
+ for (int j = 0; j < indices.size(); j++) {
+ idx_ptr[index_offset + j] = vertex_offset + indices[j];
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ if (!child->get_owner()) {
+ continue; //maybe a helper
+ }
+
+ _bake_node(child, r_vertices, r_indices);
+ }
+}
+
+OccluderInstance3D::BakeError OccluderInstance3D::bake(Node *p_from_node, String p_occluder_path) {
+ if (p_occluder_path == "") {
+ if (get_occluder().is_null()) {
+ return BAKE_ERROR_NO_SAVE_PATH;
+ }
+ }
+
+ PackedVector3Array vertices;
+ PackedInt32Array indices;
+
+ _bake_node(p_from_node, vertices, indices);
+
+ if (vertices.is_empty() || indices.is_empty()) {
+ return BAKE_ERROR_NO_MESHES;
+ }
+
+ Ref<Occluder3D> occ;
+ if (get_occluder().is_valid()) {
+ occ = get_occluder();
+ } else {
+ occ.instance();
+ occ->set_path(p_occluder_path);
+ }
+
+ occ->set_vertices(vertices);
+ occ->set_indices(indices);
+ set_occluder(occ);
+
+ return BAKE_ERROR_OK;
+}
+
+void OccluderInstance3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_bake_mask", "mask"), &OccluderInstance3D::set_bake_mask);
+ ClassDB::bind_method(D_METHOD("get_bake_mask"), &OccluderInstance3D::get_bake_mask);
+ ClassDB::bind_method(D_METHOD("set_bake_mask_bit", "layer", "enabled"), &OccluderInstance3D::set_bake_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_bake_mask_bit", "layer"), &OccluderInstance3D::get_bake_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("set_occluder", "occluder"), &OccluderInstance3D::set_occluder);
+ ClassDB::bind_method(D_METHOD("get_occluder"), &OccluderInstance3D::get_occluder);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "occluder", PROPERTY_HINT_RESOURCE_TYPE, "Occluder3D"), "set_occluder", "get_occluder");
+ ADD_GROUP("Bake", "bake_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask");
+}
+
+OccluderInstance3D::OccluderInstance3D() {
+}
+
+OccluderInstance3D::~OccluderInstance3D() {
+}
diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h
new file mode 100644
index 0000000000..4bb468274d
--- /dev/null
+++ b/scene/3d/occluder_instance_3d.h
@@ -0,0 +1,108 @@
+/*************************************************************************/
+/* occluder_instance_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef OCCLUDER_INSTANCE_3D_H
+#define OCCLUDER_INSTANCE_3D_H
+
+#include "scene/3d/visual_instance_3d.h"
+
+class Occluder3D : public Resource {
+ GDCLASS(Occluder3D, Resource);
+ RES_BASE_EXTENSION("occ");
+
+ mutable RID occluder;
+ mutable Ref<ArrayMesh> debug_mesh;
+ mutable Vector<Vector3> debug_lines;
+ AABB aabb;
+
+ PackedVector3Array vertices;
+ PackedInt32Array indices;
+
+ void _update_changes();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_vertices(PackedVector3Array p_vertices);
+ PackedVector3Array get_vertices() const;
+
+ void set_indices(PackedInt32Array p_indices);
+ PackedInt32Array get_indices() const;
+
+ Vector<Vector3> get_debug_lines() const;
+ Ref<ArrayMesh> get_debug_mesh() const;
+ AABB get_aabb() const;
+
+ virtual RID get_rid() const override;
+ Occluder3D();
+ ~Occluder3D();
+};
+
+class OccluderInstance3D : public VisualInstance3D {
+ GDCLASS(OccluderInstance3D, Node3D);
+
+private:
+ Ref<Occluder3D> occluder;
+ uint32_t bake_mask = 0xFFFFFFFF;
+
+ void _occluder_changed();
+
+ bool _bake_material_check(Ref<Material> p_material);
+ void _bake_node(Node *p_node, PackedVector3Array &r_vertices, PackedInt32Array &r_indices);
+
+protected:
+ static void _bind_methods();
+
+public:
+ enum BakeError {
+ BAKE_ERROR_OK,
+ BAKE_ERROR_NO_SAVE_PATH,
+ BAKE_ERROR_NO_MESHES,
+ };
+
+ void set_occluder(const Ref<Occluder3D> &p_occluder);
+ Ref<Occluder3D> get_occluder() const;
+
+ virtual AABB get_aabb() const override;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
+
+ void set_bake_mask(uint32_t p_mask);
+ uint32_t get_bake_mask() const;
+
+ void set_bake_mask_bit(int p_layer, bool p_enable);
+ bool get_bake_mask_bit(int p_layer) const;
+ BakeError bake(Node *p_from_node, String p_occluder_path = "");
+
+ OccluderInstance3D();
+ ~OccluderInstance3D();
+};
+
+#endif
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 4ec4ee6207..de115b35e3 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -108,7 +108,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
}
Vector3 pos = c->interpolate_baked(offset, cubic);
- Transform t = get_transform();
+ Transform3D 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
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 2476cc3471..25c7c3d798 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -43,16 +43,35 @@
#include "editor/plugins/node_3d_editor_plugin.h"
#endif
-Vector3 PhysicsBody3D::get_linear_velocity() const {
- return Vector3();
+void PhysicsBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only", "safe_margin"), &PhysicsBody3D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false), DEFVAL(0.001));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision", "safe_margin"), &PhysicsBody3D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()), DEFVAL(0.001));
+
+ ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock);
+ ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock);
+
+ 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_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);
}
-Vector3 PhysicsBody3D::get_angular_velocity() const {
- return Vector3();
+PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) :
+ CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode);
}
-real_t PhysicsBody3D::get_inverse_mass() const {
- return 0;
+PhysicsBody3D::~PhysicsBody3D() {
+ if (motion_cache.is_valid()) {
+ motion_cache->owner = nullptr;
+ }
}
TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() {
@@ -83,11 +102,75 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
-void PhysicsBody3D::_bind_methods() {}
+Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only, real_t p_margin) {
+ PhysicsServer3D::MotionResult result;
+ if (move_and_collide(p_motion, p_infinite_inertia, result, p_margin, p_exclude_raycast_shapes, p_test_only)) {
+ if (motion_cache.is_null()) {
+ motion_cache.instance();
+ motion_cache->owner = this;
+ }
+
+ motion_cache->result = result;
-PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) :
- CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) {
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode);
+ return motion_cache;
+ }
+
+ return Ref<KinematicCollision3D>();
+}
+
+bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only) {
+ Transform3D gt = get_global_transform();
+ bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes);
+
+ for (int i = 0; i < 3; i++) {
+ if (locked_axis & (1 << i)) {
+ r_result.motion[i] = 0;
+ }
+ }
+
+ if (!p_test_only) {
+ gt.origin += r_result.motion;
+ set_global_transform(gt);
+ }
+
+ return colliding;
+}
+
+bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision3D> &r_collision, real_t p_margin) {
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
+
+ PhysicsServer3D::MotionResult *r = nullptr;
+ if (r_collision.is_valid()) {
+ // Needs const_cast because method bindings don't support non-const Ref.
+ r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result);
+ }
+
+ return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes);
+}
+
+void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
+ if (p_lock) {
+ locked_axis |= p_axis;
+ } else {
+ locked_axis &= (~p_axis);
+ }
+ PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
+}
+
+bool PhysicsBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const {
+ return (locked_axis & p_axis);
+}
+
+Vector3 PhysicsBody3D::get_linear_velocity() const {
+ return Vector3();
+}
+
+Vector3 PhysicsBody3D::get_angular_velocity() const {
+ return Vector3();
+}
+
+real_t PhysicsBody3D::get_inverse_mass() const {
+ return 0;
}
void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
@@ -109,14 +192,44 @@ Ref<PhysicsMaterial> StaticBody3D::get_physics_material_override() const {
return physics_material_override;
}
+void StaticBody3D::set_kinematic_motion_enabled(bool p_enabled) {
+ if (p_enabled == kinematic_motion) {
+ return;
+ }
+
+ kinematic_motion = p_enabled;
+
+ if (kinematic_motion) {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC);
+ }
+
+ _update_kinematic_motion();
+}
+
+bool StaticBody3D::is_kinematic_motion_enabled() const {
+ return kinematic_motion;
+}
+
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);
+
+ if (kinematic_motion) {
+ _update_kinematic_motion();
+ } else {
+ 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);
+
+ if (kinematic_motion) {
+ _update_kinematic_motion();
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
+ }
}
Vector3 StaticBody3D::get_constant_linear_velocity() const {
@@ -127,30 +240,81 @@ Vector3 StaticBody3D::get_constant_angular_velocity() const {
return constant_angular_velocity;
}
+Vector3 StaticBody3D::get_linear_velocity() const {
+ return linear_velocity;
+}
+
+Vector3 StaticBody3D::get_angular_velocity() const {
+ return angular_velocity;
+}
+
+void StaticBody3D::_notification(int p_what) {
+ if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+#endif
+
+ ERR_FAIL_COND(!kinematic_motion);
+
+ real_t delta_time = get_physics_process_delta_time();
+
+ Transform3D new_transform = get_global_transform();
+ new_transform.origin += constant_linear_velocity * delta_time;
+
+ real_t ang_vel = constant_angular_velocity.length();
+ if (!Math::is_zero_approx(ang_vel)) {
+ Vector3 ang_vel_axis = constant_angular_velocity / ang_vel;
+ Basis rot(ang_vel_axis, ang_vel * delta_time);
+ new_transform.basis = rot * new_transform.basis;
+ new_transform.orthonormalize();
+ }
+
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform);
+
+ // Propagate transform change to node.
+ set_ignore_transform_notification(true);
+ set_global_transform(new_transform);
+ set_ignore_transform_notification(false);
+ _on_transform_changed();
+ }
+}
+
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_kinematic_motion_enabled", "enabled"), &StaticBody3D::set_kinematic_motion_enabled);
+ ClassDB::bind_method(D_METHOD("is_kinematic_motion_enabled"), &StaticBody3D::is_kinematic_motion_enabled);
+
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");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "kinematic_motion"), "set_kinematic_motion_enabled", "is_kinematic_motion_enabled");
+}
+
+void StaticBody3D::_direct_state_changed(Object *p_state) {
+#ifdef DEBUG_ENABLED
+ PhysicsDirectBodyState3D *state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
+#else
+ PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; //trust it
+#endif
+
+ linear_velocity = state->get_linear_velocity();
+ angular_velocity = state->get_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);
@@ -161,6 +325,27 @@ void StaticBody3D::_reload_physics_characteristics() {
}
}
+void StaticBody3D::_update_kinematic_motion() {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+#endif
+
+ if (kinematic_motion) {
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &StaticBody3D::_direct_state_changed));
+
+ if (!constant_angular_velocity.is_equal_approx(Vector3()) || !constant_linear_velocity.is_equal_approx(Vector3())) {
+ set_physics_process_internal(true);
+ return;
+ }
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
+ }
+
+ set_physics_process_internal(false);
+}
+
void RigidBody3D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
@@ -178,7 +363,7 @@ void RigidBody3D::_body_enter_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
}
contact_monitor->locked = false;
@@ -199,13 +384,13 @@ void RigidBody3D::_body_exit_tree(ObjectID p_id) {
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);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, 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) {
+void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
bool body_in = p_status == 1;
ObjectID objid = p_instance;
@@ -220,6 +405,7 @@ void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
if (body_in) {
if (!E) {
E = contact_monitor->body_map.insert(objid, BodyState());
+ E->get().rid = p_body;
//E->get().rc=0;
E->get().in_tree = node && node->is_inside_tree();
if (node) {
@@ -236,7 +422,7 @@ void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
}
if (E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_local_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_local_shape);
}
} else {
@@ -260,12 +446,13 @@ void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
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);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_local_shape);
}
}
}
struct _RigidBodyInOut {
+ RID rid;
ObjectID id;
int shape = 0;
int local_shape = 0;
@@ -274,6 +461,7 @@ struct _RigidBodyInOut {
void RigidBody3D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
#else
state = (PhysicsDirectBodyState3D *)p_state; //trust it
#endif
@@ -291,6 +479,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
get_script_instance()->call("_integrate_forces", state);
}
set_ignore_transform_notification(false);
+ _on_transform_changed();
if (contact_monitor) {
contact_monitor->locked = true;
@@ -312,6 +501,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
//put the ones to add
for (int i = 0; i < state->get_contact_count(); i++) {
+ RID rid = state->get_contact_collider(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);
@@ -320,6 +510,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(obj);
if (!E) {
+ toadd[toadd_count].rid = rid;
toadd[toadd_count].local_shape = local_shape;
toadd[toadd_count].id = obj;
toadd[toadd_count].shape = shape;
@@ -330,6 +521,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
ShapePair sp(shape, local_shape);
int idx = E->get().shapes.find(sp);
if (idx == -1) {
+ toadd[toadd_count].rid = rid;
toadd[toadd_count].local_shape = local_shape;
toadd[toadd_count].id = obj;
toadd[toadd_count].shape = shape;
@@ -345,6 +537,7 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
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].rid = E->get().rid;
toremove[toremove_count].body_id = E->key();
toremove[toremove_count].pair = E->get().shapes[i];
toremove_count++;
@@ -355,13 +548,13 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
//process removals
for (int i = 0; i < toremove_count; i++) {
- _body_inout(0, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape);
+ _body_inout(0, toremove[i].rid, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape);
}
//process additions
for (int i = 0; i < toadd_count; i++) {
- _body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
+ _body_inout(1, toremove[i].rid, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
}
contact_monitor->locked = false;
@@ -390,15 +583,15 @@ void RigidBody3D::_notification(int p_what) {
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);
+ case MODE_DYNAMIC: {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_DYNAMIC);
} 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);
+ case MODE_DYNAMIC_LOCKED: {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED);
} break;
case MODE_KINEMATIC: {
@@ -509,7 +702,7 @@ Vector3 RigidBody3D::get_angular_velocity() const {
return angular_velocity;
}
-Basis RigidBody3D::get_inverse_inertia_tensor() {
+Basis RigidBody3D::get_inverse_inertia_tensor() const {
return inverse_inertia_tensor;
}
@@ -619,14 +812,6 @@ 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());
@@ -646,12 +831,12 @@ Array RigidBody3D::get_colliding_bodies() const {
}
TypedArray<String> RigidBody3D::get_configuration_warnings() const {
- Transform t = get_transform();
+ Transform3D t = get_transform();
TypedArray<String> warnings = Node::get_configuration_warnings();
- if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
- warnings.push_back(TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ if ((get_mode() == MODE_DYNAMIC || get_mode() == MODE_DYNAMIC_LOCKED) && (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)) {
+ warnings.push_back(TTR("Size changes to RigidBody3D (in dynamic modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
return warnings;
@@ -712,16 +897,11 @@ void RigidBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody3D::set_can_sleep);
ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody3D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody3D::_direct_state_changed);
-
- ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &RigidBody3D::set_axis_lock);
- ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &RigidBody3D::get_axis_lock);
-
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::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,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::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");
@@ -731,13 +911,6 @@ void RigidBody3D::_bind_methods() {
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");
@@ -745,21 +918,21 @@ void RigidBody3D::_bind_methods() {
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_shape_entered", PropertyInfo(Variant::RID, "body_rid"), 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::RID, "body_rid"), 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_DYNAMIC);
BIND_ENUM_CONSTANT(MODE_STATIC);
- BIND_ENUM_CONSTANT(MODE_CHARACTER);
+ BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED);
BIND_ENUM_CONSTANT(MODE_KINEMATIC);
}
RigidBody3D::RigidBody3D() :
- PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsBody3D(PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody3D::_direct_state_changed));
}
RigidBody3D::~RigidBody3D() {
@@ -778,147 +951,92 @@ void RigidBody3D::_reload_physics_characteristics() {
}
}
-//////////////////////////////////////////////////////
-//////////////////////////
-
-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, real_t p_floor_max_angle, bool p_infinite_inertia) {
- Vector3 body_velocity = p_linear_velocity;
- Vector3 body_velocity_normal = body_velocity.normalized();
- Vector3 up_direction = p_up_direction.normalized();
+void CharacterBody3D::move_and_slide() {
+ Vector3 body_velocity_normal = linear_velocity.normalized();
+
+ bool was_on_floor = on_floor;
for (int i = 0; i < 3; i++) {
if (locked_axis & (1 << i)) {
- body_velocity[i] = 0;
+ linear_velocity[i] = 0.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());
+ Vector3 motion = (floor_velocity + linear_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();
+ motion_results.clear();
floor_normal = Vector3();
floor_velocity = Vector3();
- while (p_max_slides) {
- Collision collision;
+ int slide_count = max_slides;
+ while (slide_count) {
+ PhysicsServer3D::MotionResult result;
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);
+ collided = move_and_collide(motion, infinite_inertia, result, margin);
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);
+ collided = separate_raycast_shapes(result);
if (collided) {
- collision.remainder = motion; //keep
- collision.travel = Vector3();
+ result.remainder = motion; //keep
+ result.motion = Vector3();
}
}
if (collided) {
found_collision = true;
- colliders.push_back(collision);
- motion = collision.remainder;
+ motion_results.push_back(result);
+ motion = result.remainder;
if (up_direction == Vector3()) {
//all is a wall
on_wall = true;
} else {
- if (Math::acos(collision.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
+ if (Math::acos(result.collision_normal.dot(up_direction)) <= 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 + up_direction).length() < 0.01 && collision.travel.length() < 1) {
- Transform gt = get_global_transform();
- gt.origin -= collision.travel.slide(up_direction);
+ floor_normal = result.collision_normal;
+ on_floor_body = result.collider;
+ floor_velocity = result.collider_velocity;
+
+ if (stop_on_slope) {
+ if ((body_velocity_normal + up_direction).length() < 0.01 && result.motion.length() < 1) {
+ Transform3D gt = get_global_transform();
+ gt.origin -= result.motion.slide(up_direction);
set_global_transform(gt);
- return Vector3();
+ linear_velocity = Vector3();
+ return;
}
}
- } else if (Math::acos(collision.normal.dot(-up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
+ } else if (Math::acos(result.collision_normal.dot(-up_direction)) <= 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);
+ motion = motion.slide(result.collision_normal);
+ linear_velocity = linear_velocity.slide(result.collision_normal);
for (int j = 0; j < 3; j++) {
if (locked_axis & (1 << j)) {
- body_velocity[j] = 0;
+ linear_velocity[j] = 0.0;
}
}
}
@@ -928,83 +1046,47 @@ Vector3 KinematicBody3D::move_and_slide(const Vector3 &p_linear_velocity, const
break;
}
- --p_max_slides;
+ --slide_count;
}
- 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, real_t p_floor_max_angle, bool p_infinite_inertia) {
- Vector3 up_direction = p_up_direction.normalized();
- bool was_on_floor = on_floor;
-
- Vector3 ret = move_and_slide(p_linear_velocity, 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;
+ if (!was_on_floor || snap == Vector3()) {
+ return;
}
- Collision col;
- Transform gt = get_global_transform();
-
- if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) {
+ // Apply snap.
+ Transform3D gt = get_global_transform();
+ PhysicsServer3D::MotionResult result;
+ if (move_and_collide(snap, infinite_inertia, result, margin, false, true)) {
bool apply = true;
if (up_direction != Vector3()) {
- if (Math::acos(col.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
on_floor = true;
- floor_normal = col.normal;
- on_floor_body = col.collider_rid;
- floor_velocity = col.collider_vel;
- if (p_stop_on_slope) {
+ floor_normal = result.collision_normal;
+ on_floor_body = result.collider;
+ floor_velocity = result.collider_velocity;
+ if (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(up_direction);
+ result.motion = result.motion.project(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;
+ gt.origin += result.motion;
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) {
+bool CharacterBody3D::separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result) {
PhysicsServer3D::SeparationResult sep_res[8]; //max 8 rays
- Transform gt = get_global_transform();
+ Transform3D 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 hits = PhysicsServer3D::get_singleton()->body_test_ray_separation(get_rid(), gt, infinite_inertia, recover, sep_res, 8, margin);
int deepest = -1;
real_t deepest_depth;
for (int i = 0; i < hits; i++) {
@@ -1018,15 +1100,15 @@ bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision
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();
+ r_result.collider_id = sep_res[deepest].collider_id;
+ r_result.collider_metadata = sep_res[deepest].collider_metadata;
+ r_result.collider_shape = sep_res[deepest].collider_shape;
+ r_result.collider_velocity = sep_res[deepest].collider_velocity;
+ r_result.collision_point = sep_res[deepest].collision_point;
+ r_result.collision_normal = sep_res[deepest].collision_normal;
+ r_result.collision_local_shape = sep_res[deepest].collision_local_shape;
+ r_result.motion = recover;
+ r_result.remainder = Vector3();
return true;
} else {
@@ -1034,39 +1116,53 @@ bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision
}
}
-void KinematicBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
- if (p_lock) {
- locked_axis |= p_axis;
- } else {
- locked_axis &= (~p_axis);
- }
- PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
+void CharacterBody3D::set_safe_margin(real_t p_margin) {
+ margin = p_margin;
}
-bool KinematicBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const {
- return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis);
+real_t CharacterBody3D::get_safe_margin() const {
+ return margin;
}
-void KinematicBody3D::set_safe_margin(real_t p_margin) {
- margin = p_margin;
- PhysicsServer3D::get_singleton()->body_set_kinematic_safe_margin(get_rid(), margin);
+Vector3 CharacterBody3D::get_linear_velocity() const {
+ return linear_velocity;
}
-real_t KinematicBody3D::get_safe_margin() const {
- return margin;
+void CharacterBody3D::set_linear_velocity(const Vector3 &p_velocity) {
+ linear_velocity = p_velocity;
}
-int KinematicBody3D::get_slide_count() const {
- return colliders.size();
+bool CharacterBody3D::is_on_floor() const {
+ return on_floor;
+}
+
+bool CharacterBody3D::is_on_wall() const {
+ return on_wall;
+}
+
+bool CharacterBody3D::is_on_ceiling() const {
+ return on_ceiling;
+}
+
+Vector3 CharacterBody3D::get_floor_normal() const {
+ return floor_normal;
}
-KinematicBody3D::Collision KinematicBody3D::get_slide_collision(int p_bounce) const {
- ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Collision());
- return colliders[p_bounce];
+Vector3 CharacterBody3D::get_floor_velocity() const {
+ return floor_velocity;
+}
+
+int CharacterBody3D::get_slide_count() const {
+ return motion_results.size();
+}
+
+PhysicsServer3D::MotionResult CharacterBody3D::get_slide_collision(int p_bounce) const {
+ ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), PhysicsServer3D::MotionResult());
+ return motion_results[p_bounce];
}
-Ref<KinematicCollision3D> KinematicBody3D::_get_slide_collision(int p_bounce) {
- ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Ref<KinematicCollision3D>());
+Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) {
+ ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), Ref<KinematicCollision3D>());
if (p_bounce >= slide_colliders.size()) {
slide_colliders.resize(p_bounce + 1);
}
@@ -1076,76 +1172,126 @@ Ref<KinematicCollision3D> KinematicBody3D::_get_slide_collision(int p_bounce) {
slide_colliders.write[p_bounce]->owner = this;
}
- slide_colliders.write[p_bounce]->collision = colliders[p_bounce];
+ slide_colliders.write[p_bounce]->result = motion_results[p_bounce];
return slide_colliders[p_bounce];
}
-void KinematicBody3D::_notification(int p_what) {
+bool CharacterBody3D::is_stop_on_slope_enabled() const {
+ return stop_on_slope;
+}
+
+void CharacterBody3D::set_stop_on_slope_enabled(bool p_enabled) {
+ stop_on_slope = p_enabled;
+}
+
+bool CharacterBody3D::is_infinite_inertia_enabled() const {
+ return infinite_inertia;
+}
+void CharacterBody3D::set_infinite_inertia_enabled(bool p_enabled) {
+ infinite_inertia = p_enabled;
+}
+
+int CharacterBody3D::get_max_slides() const {
+ return max_slides;
+}
+
+void CharacterBody3D::set_max_slides(int p_max_slides) {
+ ERR_FAIL_COND(p_max_slides > 0);
+ max_slides = p_max_slides;
+}
+
+real_t CharacterBody3D::get_floor_max_angle() const {
+ return floor_max_angle;
+}
+
+void CharacterBody3D::set_floor_max_angle(real_t p_radians) {
+ floor_max_angle = p_radians;
+}
+
+real_t CharacterBody3D::get_floor_max_angle_degrees() const {
+ return Math::rad2deg(floor_max_angle);
+}
+
+void CharacterBody3D::set_floor_max_angle_degrees(real_t p_degrees) {
+ floor_max_angle = Math::deg2rad(p_degrees);
+}
+
+const Vector3 &CharacterBody3D::get_snap() const {
+ return snap;
+}
+
+void CharacterBody3D::set_snap(const Vector3 &p_snap) {
+ snap = p_snap;
+}
+
+const Vector3 &CharacterBody3D::get_up_direction() const {
+ return up_direction;
+}
+
+void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) {
+ up_direction = p_up_direction.normalized();
+}
+
+void CharacterBody3D::_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();
+ motion_results.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((real_t)45.0)), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true));
-
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody3D::test_move, DEFVAL(true));
+void CharacterBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide);
- 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_linear_velocity", "linear_velocity"), &CharacterBody3D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &CharacterBody3D::get_linear_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"), &CharacterBody3D::set_safe_margin);
+ ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin);
+ ClassDB::bind_method(D_METHOD("is_stop_on_slope_enabled"), &CharacterBody3D::is_stop_on_slope_enabled);
+ ClassDB::bind_method(D_METHOD("set_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_stop_on_slope_enabled);
+ ClassDB::bind_method(D_METHOD("is_infinite_inertia_enabled"), &CharacterBody3D::is_infinite_inertia_enabled);
+ ClassDB::bind_method(D_METHOD("set_infinite_inertia_enabled", "enabled"), &CharacterBody3D::set_infinite_inertia_enabled);
+ ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody3D::get_max_slides);
+ ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody3D::set_max_slides);
+ ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody3D::get_floor_max_angle);
+ ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody3D::set_floor_max_angle);
+ ClassDB::bind_method(D_METHOD("get_floor_max_angle_degrees"), &CharacterBody3D::get_floor_max_angle_degrees);
+ ClassDB::bind_method(D_METHOD("set_floor_max_angle_degrees", "degrees"), &CharacterBody3D::set_floor_max_angle_degrees);
+ ClassDB::bind_method(D_METHOD("get_snap"), &CharacterBody3D::get_snap);
+ ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CharacterBody3D::set_snap);
+ ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody3D::get_up_direction);
+ ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody3D::set_up_direction);
- 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("is_on_floor"), &CharacterBody3D::is_on_floor);
+ ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody3D::is_on_ceiling);
+ ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody3D::is_on_wall);
+ ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody3D::get_floor_normal);
+ ClassDB::bind_method(D_METHOD("get_floor_velocity"), &CharacterBody3D::get_floor_velocity);
- 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_GROUP("Axis Lock", "axis_lock_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_motion_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_motion_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_motion_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z);
+ ClassDB::bind_method(D_METHOD("get_slide_count"), &CharacterBody3D::get_slide_count);
+ ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_slide_collision);
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stop_on_slope"), "set_stop_on_slope_enabled", "is_stop_on_slope_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "infinite_inertia"), "set_infinite_inertia_enabled", "is_infinite_inertia_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides"), "set_max_slides", "get_max_slides");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_floor_max_angle", "get_floor_max_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle_degrees", PROPERTY_HINT_RANGE, "0,180,0.1", PROPERTY_USAGE_EDITOR), "set_floor_max_angle_degrees", "get_floor_max_angle_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "snap"), "set_snap", "get_snap");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction");
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() :
+CharacterBody3D::CharacterBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) {
- set_safe_margin(0.001);
- 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;
- }
-
+CharacterBody3D::~CharacterBody3D() {
for (int i = 0; i < slide_colliders.size(); i++) {
if (slide_colliders[i].is_valid()) {
slide_colliders.write[i]->owner = nullptr;
@@ -1156,39 +1302,39 @@ KinematicBody3D::~KinematicBody3D() {
///////////////////////////////////////
Vector3 KinematicCollision3D::get_position() const {
- return collision.collision;
+ return result.collision_point;
}
Vector3 KinematicCollision3D::get_normal() const {
- return collision.normal;
+ return result.collision_normal;
}
Vector3 KinematicCollision3D::get_travel() const {
- return collision.travel;
+ return result.motion;
}
Vector3 KinematicCollision3D::get_remainder() const {
- return collision.remainder;
+ return result.remainder;
}
Object *KinematicCollision3D::get_local_shape() const {
if (!owner) {
return nullptr;
}
- uint32_t ownerid = owner->shape_find_owner(collision.local_shape);
+ uint32_t ownerid = owner->shape_find_owner(result.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);
+ if (result.collider_id.is_valid()) {
+ return ObjectDB::get_instance(result.collider_id);
}
return nullptr;
}
ObjectID KinematicCollision3D::get_collider_id() const {
- return collision.collider;
+ return result.collider_id;
}
Object *KinematicCollision3D::get_collider_shape() const {
@@ -1196,7 +1342,7 @@ Object *KinematicCollision3D::get_collider_shape() const {
if (collider) {
CollisionObject3D *obj2d = Object::cast_to<CollisionObject3D>(collider);
if (obj2d) {
- uint32_t ownerid = obj2d->shape_find_owner(collision.collider_shape);
+ uint32_t ownerid = obj2d->shape_find_owner(result.collider_shape);
return obj2d->shape_owner_get_owner(ownerid);
}
}
@@ -1205,11 +1351,11 @@ Object *KinematicCollision3D::get_collider_shape() const {
}
int KinematicCollision3D::get_collider_shape_index() const {
- return collision.collider_shape;
+ return result.collider_shape;
}
Vector3 KinematicCollision3D::get_collider_velocity() const {
- return collision.collider_vel;
+ return result.collider_velocity;
}
Variant KinematicCollision3D::get_collider_metadata() const {
@@ -1242,12 +1388,6 @@ void KinematicCollision3D::_bind_methods() {
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) {
@@ -1953,6 +2093,8 @@ void PhysicalBone3D::_notification(int p_what) {
if (parent_skeleton) {
if (-1 != bone_id) {
parent_skeleton->unbind_physical_bone_from_bone(bone_id);
+ parent_skeleton->unbind_child_node_from_bone(bone_id, this);
+ bone_id = -1;
}
}
parent_skeleton = nullptr;
@@ -1977,15 +2119,17 @@ void PhysicalBone3D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
#else
state = (PhysicsDirectBodyState3D *)p_state; //trust it
#endif
- Transform global_transform(state->get_transform());
+ Transform3D global_transform(state->get_transform());
set_ignore_transform_notification(true);
set_global_transform(global_transform);
set_ignore_transform_notification(false);
+ _on_transform_changed();
// Update skeleton
if (parent_skeleton) {
@@ -1999,8 +2143,6 @@ void PhysicalBone3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &PhysicalBone3D::apply_central_impulse);
ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &PhysicalBone3D::apply_impulse, Vector3());
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &PhysicalBone3D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone3D::set_joint_type);
ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone3D::get_joint_type);
@@ -2041,16 +2183,13 @@ void PhysicalBone3D::_bind_methods() {
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::TRANSFORM3D, "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::TRANSFORM3D, "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, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
@@ -2060,14 +2199,6 @@ void PhysicalBone3D::_bind_methods() {
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);
@@ -2117,8 +2248,8 @@ void PhysicalBone3D::_reload_joint() {
return;
}
- Transform joint_transf = get_global_transform() * joint_offset;
- Transform local_a = body_a->get_global_transform().affine_inverse() * joint_transf;
+ Transform3D joint_transf = get_global_transform() * joint_offset;
+ Transform3D local_a = body_a->get_global_transform().affine_inverse() * joint_transf;
local_a.orthonormalize();
switch (get_joint_type()) {
@@ -2211,11 +2342,11 @@ void PhysicalBone3D::_set_gizmo_move_joint(bool p_move_joint) {
}
#ifdef TOOLS_ENABLED
-Transform PhysicalBone3D::get_global_gizmo_transform() const {
+Transform3D 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 {
+Transform3D PhysicalBone3D::get_local_gizmo_transform() const {
return gizmo_move_joint ? get_transform() * joint_offset : get_transform();
}
#endif
@@ -2271,13 +2402,13 @@ 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) {
+void PhysicalBone3D::set_joint_offset(const Transform3D &p_offset) {
joint_offset = p_offset;
_update_joint_offset();
}
-const Transform &PhysicalBone3D::get_joint_offset() const {
+const Transform3D &PhysicalBone3D::get_joint_offset() const {
return joint_offset;
}
@@ -2299,11 +2430,11 @@ Vector3 PhysicalBone3D::get_joint_rotation_degrees() const {
return get_joint_rotation() * (180.0 / Math_PI);
}
-const Transform &PhysicalBone3D::get_body_offset() const {
+const Transform3D &PhysicalBone3D::get_body_offset() const {
return body_offset;
}
-void PhysicalBone3D::set_body_offset(const Transform &p_offset) {
+void PhysicalBone3D::set_body_offset(const Transform3D &p_offset) {
body_offset = p_offset;
body_offset_inverse = body_offset.affine_inverse();
@@ -2409,14 +2540,6 @@ 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) {
joint = PhysicsServer3D::get_singleton()->joint_create();
@@ -2456,7 +2579,7 @@ void PhysicalBone3D::update_bone_id() {
void PhysicalBone3D::update_offset() {
#ifdef TOOLS_ENABLED
if (parent_skeleton) {
- Transform bone_transform(parent_skeleton->get_global_transform());
+ Transform3D bone_transform(parent_skeleton->get_global_transform());
if (-1 != bone_id) {
bone_transform *= parent_skeleton->get_bone_global_pose(bone_id);
}
@@ -2476,10 +2599,10 @@ void PhysicalBone3D::_start_physics_simulation() {
return;
}
reset_to_rest_position();
- PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_RIGID);
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_DYNAMIC);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_direct_state_changed));
set_as_top_level(true);
_internal_simulate_physics = true;
}
@@ -2498,8 +2621,8 @@ void PhysicalBone3D::_stop_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0);
}
if (_internal_simulate_physics) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, "");
- parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false);
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
+ parent_skeleton->set_bone_global_pose_override(bone_id, Transform3D(), 0.0, false);
set_as_top_level(false);
_internal_simulate_physics = false;
}
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 21afe66861..8df3635be0 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -37,6 +37,8 @@
#include "servers/physics_server_3d.h"
#include "skeleton_3d.h"
+class KinematicCollision3D;
+
class PhysicsBody3D : public CollisionObject3D {
GDCLASS(PhysicsBody3D, CollisionObject3D);
@@ -44,7 +46,19 @@ protected:
static void _bind_methods();
PhysicsBody3D(PhysicsServer3D::BodyMode p_mode);
+ Ref<KinematicCollision3D> motion_cache;
+
+ uint16_t locked_axis = 0;
+
+ Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.001);
+
public:
+ bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
+ bool test_move(const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001);
+
+ void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
+ bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
+
virtual Vector3 get_linear_velocity() const;
virtual Vector3 get_angular_velocity() const;
virtual real_t get_inverse_mass() const;
@@ -53,7 +67,7 @@ public:
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
- PhysicsBody3D();
+ virtual ~PhysicsBody3D();
};
class StaticBody3D : public PhysicsBody3D {
@@ -62,11 +76,19 @@ class StaticBody3D : public PhysicsBody3D {
Vector3 constant_linear_velocity;
Vector3 constant_angular_velocity;
+ Vector3 linear_velocity;
+ Vector3 angular_velocity;
+
Ref<PhysicsMaterial> physics_material_override;
+ bool kinematic_motion = false;
+
protected:
+ void _notification(int p_what);
static void _bind_methods();
+ void _direct_state_changed(Object *p_state);
+
public:
void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
Ref<PhysicsMaterial> get_physics_material_override() const;
@@ -77,11 +99,18 @@ public:
Vector3 get_constant_linear_velocity() const;
Vector3 get_constant_angular_velocity() const;
+ virtual Vector3 get_linear_velocity() const override;
+ virtual Vector3 get_angular_velocity() const override;
+
StaticBody3D();
- ~StaticBody3D();
private:
void _reload_physics_characteristics();
+
+ void _update_kinematic_motion();
+
+ void set_kinematic_motion_enabled(bool p_enabled);
+ bool is_kinematic_motion_enabled() const;
};
class RigidBody3D : public PhysicsBody3D {
@@ -89,16 +118,16 @@ class RigidBody3D : public PhysicsBody3D {
public:
enum Mode {
- MODE_RIGID,
+ MODE_DYNAMIC,
MODE_STATIC,
- MODE_CHARACTER,
+ MODE_DYNAMIC_LOCKED,
MODE_KINEMATIC,
};
protected:
bool can_sleep = true;
PhysicsDirectBodyState3D *state = nullptr;
- Mode mode = MODE_RIGID;
+ Mode mode = MODE_DYNAMIC;
real_t mass = 1.0;
Ref<PhysicsMaterial> physics_material_override;
@@ -137,10 +166,12 @@ protected:
}
};
struct RigidBody3D_RemoveAction {
+ RID rid;
ObjectID body_id;
ShapePair pair;
};
struct BodyState {
+ RID rid;
//int rc;
bool in_tree = false;
VSet<ShapePair> shapes;
@@ -155,7 +186,7 @@ protected:
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);
+ void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape);
virtual void _direct_state_changed(Object *p_state);
void _notification(int p_what);
@@ -181,7 +212,7 @@ public:
void set_angular_velocity(const Vector3 &p_velocity);
Vector3 get_angular_velocity() const override;
- Basis get_inverse_inertia_tensor();
+ Basis get_inverse_inertia_tensor() const;
void set_gravity_scale(real_t p_gravity_scale);
real_t get_gravity_scale() const;
@@ -210,9 +241,6 @@ public:
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);
@@ -236,30 +264,20 @@ 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 = 0;
- Variant collider_metadata;
- Vector3 remainder;
- Vector3 travel;
- int local_shape = 0;
- };
+class CharacterBody3D : public PhysicsBody3D {
+ GDCLASS(CharacterBody3D, PhysicsBody3D);
private:
- Vector3 linear_velocity;
- Vector3 angular_velocity;
+ real_t margin = 0.001;
- uint16_t locked_axis = 0;
+ bool stop_on_slope = false;
+ bool infinite_inertia = true;
+ int max_slides = 4;
+ real_t floor_max_angle = Math::deg2rad((real_t)45.0);
+ Vector3 snap;
+ Vector3 up_direction = Vector3(0.0, 1.0, 0.0);
- real_t margin;
+ Vector3 linear_velocity;
Vector3 floor_normal;
Vector3 floor_velocity;
@@ -267,38 +285,47 @@ private:
bool on_floor = false;
bool on_ceiling = false;
bool on_wall = false;
- Vector<Collision> colliders;
+ Vector<PhysicsServer3D::MotionResult> motion_results;
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();
+ bool separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result);
- virtual void _direct_state_changed(Object *p_state);
+ void set_safe_margin(real_t p_margin);
+ real_t get_safe_margin() const;
-public:
- virtual Vector3 get_linear_velocity() const override;
- virtual Vector3 get_angular_velocity() const override;
+ bool is_stop_on_slope_enabled() const;
+ void set_stop_on_slope_enabled(bool p_enabled);
- 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 is_infinite_inertia_enabled() const;
+ void set_infinite_inertia_enabled(bool p_enabled);
- bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
+ int get_max_slides() const;
+ void set_max_slides(int p_max_slides);
- void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
- bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
+ real_t get_floor_max_angle() const;
+ void set_floor_max_angle(real_t p_radians);
- void set_safe_margin(real_t p_margin);
- real_t get_safe_margin() const;
+ real_t get_floor_max_angle_degrees() const;
+ void set_floor_max_angle_degrees(real_t p_degrees);
+
+ const Vector3 &get_snap() const;
+ void set_snap(const Vector3 &p_snap);
+
+ const Vector3 &get_up_direction() const;
+ void set_up_direction(const Vector3 &p_up_direction);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void move_and_slide();
+
+ virtual Vector3 get_linear_velocity() const override;
+ void set_linear_velocity(const Vector3 &p_velocity);
- 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, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), 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, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true);
bool is_on_floor() const;
bool is_on_wall() const;
bool is_on_ceiling() const;
@@ -306,18 +333,19 @@ public:
Vector3 get_floor_velocity() const;
int get_slide_count() const;
- Collision get_slide_collision(int p_bounce) const;
+ PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const;
- KinematicBody3D();
- ~KinematicBody3D();
+ CharacterBody3D();
+ ~CharacterBody3D();
};
-class KinematicCollision3D : public Reference {
- GDCLASS(KinematicCollision3D, Reference);
+class KinematicCollision3D : public RefCounted {
+ GDCLASS(KinematicCollision3D, RefCounted);
- KinematicBody3D *owner;
- friend class KinematicBody3D;
- KinematicBody3D::Collision collision;
+ PhysicsBody3D *owner = nullptr;
+ friend class PhysicsBody3D;
+ friend class CharacterBody3D;
+ PhysicsServer3D::MotionResult result;
protected:
static void _bind_methods();
@@ -334,8 +362,6 @@ public:
int get_collider_shape_index() const;
Vector3 get_collider_velocity() const;
Variant get_collider_metadata() const;
-
- KinematicCollision3D();
};
class PhysicalBone3D : public PhysicsBody3D {
@@ -465,12 +491,12 @@ private:
#endif
JointData *joint_data = nullptr;
- Transform joint_offset;
+ Transform3D joint_offset;
RID joint;
Skeleton3D *parent_skeleton = nullptr;
- Transform body_offset;
- Transform body_offset_inverse;
+ Transform3D body_offset;
+ Transform3D body_offset_inverse;
bool simulate_physics = false;
bool _internal_simulate_physics = false;
int bone_id = -1;
@@ -506,8 +532,8 @@ public:
public:
#ifdef TOOLS_ENABLED
- virtual Transform get_global_gizmo_transform() const override;
- virtual Transform get_local_gizmo_transform() const override;
+ virtual Transform3D get_global_gizmo_transform() const override;
+ virtual Transform3D get_local_gizmo_transform() const override;
#endif
const JointData *get_joint_data() const;
@@ -518,8 +544,8 @@ public:
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_offset(const Transform3D &p_offset);
+ const Transform3D &get_joint_offset() const;
void set_joint_rotation(const Vector3 &p_euler_rad);
Vector3 get_joint_rotation() const;
@@ -527,8 +553,8 @@ public:
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_body_offset(const Transform3D &p_offset);
+ const Transform3D &get_body_offset() const;
void set_simulate_physics(bool p_simulate);
bool get_simulate_physics();
@@ -558,9 +584,6 @@ public:
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_impulse, const Vector3 &p_position = Vector3());
diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp
index 3d58d1c10e..01f10c171f 100644
--- a/scene/3d/physics_joint_3d.cpp
+++ b/scene/3d/physics_joint_3d.cpp
@@ -372,15 +372,15 @@ bool HingeJoint3D::get_flag(Flag p_flag) const {
}
void HingeJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
- Transform gt = get_global_transform();
- Transform ainv = body_a->get_global_transform().affine_inverse();
+ Transform3D gt = get_global_transform();
+ Transform3D ainv = body_a->get_global_transform().affine_inverse();
- Transform local_a = ainv * gt;
+ Transform3D local_a = ainv * gt;
local_a.orthonormalize();
- Transform local_b = gt;
+ Transform3D local_b = gt;
if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
+ Transform3D binv = body_b->get_global_transform().affine_inverse();
local_b = binv * gt;
}
@@ -506,15 +506,15 @@ real_t SliderJoint3D::get_param(Param p_param) const {
}
void SliderJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
- Transform gt = get_global_transform();
- Transform ainv = body_a->get_global_transform().affine_inverse();
+ Transform3D gt = get_global_transform();
+ Transform3D ainv = body_a->get_global_transform().affine_inverse();
- Transform local_a = ainv * gt;
+ Transform3D local_a = ainv * gt;
local_a.orthonormalize();
- Transform local_b = gt;
+ Transform3D local_b = gt;
if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
+ Transform3D binv = body_b->get_global_transform().affine_inverse();
local_b = binv * gt;
}
@@ -611,18 +611,18 @@ real_t ConeTwistJoint3D::get_param(Param p_param) const {
}
void ConeTwistJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
- Transform gt = get_global_transform();
+ Transform3D 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();
+ Transform3D ainv = body_a->get_global_transform().affine_inverse();
- Transform local_a = ainv * gt;
+ Transform3D local_a = ainv * gt;
local_a.orthonormalize();
- Transform local_b = gt;
+ Transform3D local_b = gt;
if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
+ Transform3D binv = body_b->get_global_transform().affine_inverse();
local_b = binv * gt;
}
@@ -936,18 +936,18 @@ bool Generic6DOFJoint3D::get_flag_z(Flag p_flag) const {
}
void Generic6DOFJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
- Transform gt = get_global_transform();
+ Transform3D 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();
+ Transform3D ainv = body_a->get_global_transform().affine_inverse();
- Transform local_a = ainv * gt;
+ Transform3D local_a = ainv * gt;
local_a.orthonormalize();
- Transform local_b = gt;
+ Transform3D local_b = gt;
if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
+ Transform3D binv = body_b->get_global_transform().affine_inverse();
local_b = binv * gt;
}
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 66f3e539a2..db841101e5 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -61,6 +61,7 @@ uint32_t RayCast3D::get_collision_mask() const {
}
void RayCast3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -71,6 +72,7 @@ void RayCast3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool RayCast3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
@@ -203,7 +205,7 @@ void RayCast3D::_update_raycast_state() {
PhysicsDirectSpaceState3D *dss = PhysicsServer3D::get_singleton()->space_get_direct_state(w3d->get_space());
ERR_FAIL_COND(!dss);
- Transform gt = get_global_transform();
+ Transform3D gt = get_global_transform();
Vector3 to = target_position;
if (to == Vector3()) {
@@ -426,7 +428,7 @@ void RayCast3D::_update_debug_shape_material(bool p_check_collision) {
color = get_tree()->get_debug_collisions_color();
}
- if (p_check_collision) {
+ if (p_check_collision && collided) {
if ((color.get_h() < 0.055 || color.get_h() > 0.945) && color.get_s() > 0.5 && color.get_v() > 0.5) {
// If base color is already quite reddish, highlight collision with green color
color = Color(0.0, 1.0, 0.0, color.a);
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index ad24f39bce..7762156b4a 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -230,7 +230,7 @@ void ReflectionProbe::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_update_mode", "mode"), &ReflectionProbe::set_update_mode);
ClassDB::bind_method(D_METHOD("get_update_mode"), &ReflectionProbe::get_update_mode);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once,Always"), "set_update_mode", "get_update_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once (Fast),Always (Slow)"), "set_update_mode", "get_update_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "intensity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_intensity", "get_intensity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,16384,0.1,or_greater"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
@@ -242,7 +242,7 @@ void ReflectionProbe::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_lod_threshold", "get_lod_threshold");
ADD_GROUP("Ambient", "ambient_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "ambient_mode", PROPERTY_HINT_ENUM, "Disabled,Environment,ConstantColor"), "set_ambient_mode", "get_ambient_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "ambient_mode", PROPERTY_HINT_ENUM, "Disabled,Environment,Constant Color"), "set_ambient_mode", "get_ambient_mode");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ambient_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ambient_color", "get_ambient_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ambient_color_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_ambient_color_energy", "get_ambient_color_energy");
diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp
index 29a407905b..a7b3a6f1ec 100644
--- a/scene/3d/remote_transform_3d.cpp
+++ b/scene/3d/remote_transform_3d.cpp
@@ -65,7 +65,7 @@ void RemoteTransform3D::_update_remote() {
if (update_remote_position && update_remote_rotation && update_remote_scale) {
n->set_global_transform(get_global_transform());
} else {
- Transform our_trans = get_global_transform();
+ Transform3D our_trans = get_global_transform();
if (update_remote_rotation) {
n->set_rotation(our_trans.basis.get_rotation());
@@ -76,7 +76,7 @@ void RemoteTransform3D::_update_remote() {
}
if (update_remote_position) {
- Transform n_trans = n->get_global_transform();
+ Transform3D n_trans = n->get_global_transform();
n_trans.set_origin(our_trans.get_origin());
n->set_global_transform(n_trans);
@@ -87,7 +87,7 @@ void RemoteTransform3D::_update_remote() {
if (update_remote_position && update_remote_rotation && update_remote_scale) {
n->set_transform(get_transform());
} else {
- Transform our_trans = get_transform();
+ Transform3D our_trans = get_transform();
if (update_remote_rotation) {
n->set_rotation(our_trans.basis.get_rotation());
@@ -98,7 +98,7 @@ void RemoteTransform3D::_update_remote() {
}
if (update_remote_position) {
- Transform n_trans = n->get_transform();
+ Transform3D n_trans = n->get_transform();
n_trans.set_origin(our_trans.get_origin());
n->set_transform(n_trans);
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index ebbb8985c9..f9d613a4bb 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -94,20 +94,6 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
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;
}
@@ -137,19 +123,6 @@ bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const {
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;
}
@@ -162,10 +135,9 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {
String prep = "bones/" + itos(i) + "/";
p_list->push_back(PropertyInfo(Variant::STRING, prep + "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
}
@@ -237,53 +209,57 @@ void Skeleton3D::_notification(int p_what) {
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;
- }
+ if (b.disable_rest) {
+ if (b.enabled) {
+ Transform3D 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;
+ b.pose_global_no_override = bonesptr[b.parent].pose_global * pose;
} else {
- if (b.parent >= 0) {
- b.pose_global = bonesptr[b.parent].pose_global;
- } else {
- b.pose_global = Transform();
- }
+ b.pose_global = pose;
+ b.pose_global_no_override = pose;
}
-
} 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;
- }
+ if (b.parent >= 0) {
+ b.pose_global = bonesptr[b.parent].pose_global;
+ b.pose_global_no_override = bonesptr[b.parent].pose_global;
} else {
- if (b.parent >= 0) {
- b.pose_global = bonesptr[b.parent].pose_global * b.rest;
- } else {
- b.pose_global = b.rest;
- }
+ b.pose_global = Transform3D();
+ b.pose_global_no_override = Transform3D();
}
}
- 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);
+ } else {
+ if (b.enabled) {
+ Transform3D 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);
+ b.pose_global_no_override = bonesptr[b.parent].pose_global * (b.rest * pose);
+ } else {
+ b.pose_global = b.rest * pose;
+ b.pose_global_no_override = b.rest * pose;
+ }
+ } else {
+ if (b.parent >= 0) {
+ b.pose_global = bonesptr[b.parent].pose_global * b.rest;
+ b.pose_global_no_override = bonesptr[b.parent].pose_global * b.rest;
+ } else {
+ b.pose_global = b.rest;
+ b.pose_global_no_override = 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;
}
@@ -361,7 +337,6 @@ void Skeleton3D::_notification(int p_what) {
} 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.
@@ -380,7 +355,6 @@ void Skeleton3D::_notification(int p_what) {
set_physics_process_internal(true);
}
} break;
-#endif
}
}
@@ -392,7 +366,7 @@ void Skeleton3D::clear_bones_global_pose_override() {
_make_dirty();
}
-void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent) {
+void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &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;
@@ -400,14 +374,22 @@ void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform &p_po
_make_dirty();
}
-Transform Skeleton3D::get_bone_global_pose(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+Transform3D Skeleton3D::get_bone_global_pose(int p_bone) const {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
if (dirty) {
const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
}
return bones[p_bone].pose_global;
}
+Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
+ if (dirty) {
+ const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
+ }
+ return bones[p_bone].pose_global_no_override;
+}
+
// skeleton creation api
void Skeleton3D::add_bone(const String &p_name) {
ERR_FAIL_COND(p_name == "" || p_name.find(":") != -1 || p_name.find("/") != -1);
@@ -512,15 +494,14 @@ int Skeleton3D::get_bone_parent(int p_bone) const {
return bones[p_bone].parent;
}
-void Skeleton3D::set_bone_rest(int p_bone, const Transform &p_rest) {
+void Skeleton3D::set_bone_rest(int p_bone, const Transform3D &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());
+Transform3D Skeleton3D::get_bone_rest(int p_bone) const {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
return bones[p_bone].rest;
}
@@ -579,7 +560,7 @@ void Skeleton3D::clear_bones() {
// posing api
-void Skeleton3D::set_bone_pose(int p_bone, const Transform &p_pose) {
+void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) {
ERR_FAIL_INDEX(p_bone, bones.size());
bones.write[p_bone].pose = p_pose;
@@ -587,24 +568,23 @@ void Skeleton3D::set_bone_pose(int p_bone, const Transform &p_pose) {
_make_dirty();
}
}
-
-Transform Skeleton3D::get_bone_pose(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+Transform3D Skeleton3D::get_bone_pose(int p_bone) const {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
return bones[p_bone].pose;
}
-void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) {
+void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform3D &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_enable = (p_custom_pose != Transform3D());
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());
+Transform3D Skeleton3D::get_bone_custom_pose(int p_bone) const {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D());
return bones[p_bone].custom_pose;
}
@@ -639,8 +619,6 @@ void Skeleton3D::localize_rests() {
}
}
-#ifndef _3D_DISABLED
-
void Skeleton3D::set_animate_physical_bones(bool p_animate) {
animate_physical_bones = p_animate;
@@ -714,7 +692,7 @@ 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) {
+ if (parent_pb != bones[i].cache_parent_physical_bone) {
bones.write[i].cache_parent_physical_bone = parent_pb;
if (bones[i].physical_bone) {
bones[i].physical_bone->_on_bone_parent_changed();
@@ -801,8 +779,6 @@ 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();
}
@@ -868,11 +844,11 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
}
// helper functions
-Transform Skeleton3D::bone_transform_to_world_transform(Transform p_bone_transform) {
+Transform3D Skeleton3D::bone_transform_to_world_transform(Transform3D p_bone_transform) {
return get_global_transform() * p_bone_transform;
}
-Transform Skeleton3D::world_transform_to_bone_transform(Transform p_world_transform) {
+Transform3D Skeleton3D::world_transform_to_bone_transform(Transform3D p_world_transform) {
return get_global_transform().affine_inverse() * p_world_transform;
}
@@ -900,10 +876,6 @@ void Skeleton3D::_bind_methods() {
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);
@@ -912,6 +884,7 @@ void Skeleton3D::_bind_methods() {
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_global_pose_no_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_no_override);
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);
@@ -919,8 +892,6 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("bone_transform_to_world_transform", "bone_transform"), &Skeleton3D::bone_transform_to_world_transform);
ClassDB::bind_method(D_METHOD("world_transform_to_bone_transform", "world_transform"), &Skeleton3D::world_transform_to_bone_transform);
-#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);
@@ -930,7 +901,6 @@ void Skeleton3D::_bind_methods() {
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
#ifdef TOOLS_ENABLED
ADD_SIGNAL(MethodInfo("pose_updated"));
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 2941ac2c45..2f6e416c8c 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -35,16 +35,13 @@
#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)
+class SkinReference : public RefCounted {
+ GDCLASS(SkinReference, RefCounted)
friend class Skeleton3D;
Skeleton3D *skeleton_node;
@@ -79,22 +76,21 @@ private:
int sort_index = 0; //used for re-sorting process order
bool disable_rest = false;
- Transform rest;
+ Transform3D rest;
- Transform pose;
- Transform pose_global;
+ Transform3D pose;
+ Transform3D pose_global;
+ Transform3D pose_global_no_override;
bool custom_pose_enable = false;
- Transform custom_pose;
+ Transform3D custom_pose;
float global_pose_override_amount = 0.0;
bool global_pose_override_reset = false;
- Transform global_pose_override;
+ Transform3D global_pose_override;
-#ifndef _3D_DISABLED
PhysicalBone3D *physical_bone = nullptr;
PhysicalBone3D *cache_parent_physical_bone = nullptr;
-#endif // _3D_DISABLED
List<ObjectID> nodes_bound;
};
@@ -113,18 +109,6 @@ private:
uint64_t version = 1;
- // 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:
@@ -157,12 +141,13 @@ public:
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_rest(int p_bone, const Transform3D &p_rest);
+ Transform3D get_bone_rest(int p_bone) const;
+ Transform3D get_bone_global_pose(int p_bone) const;
+ Transform3D get_bone_global_pose_no_override(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_global_pose_override(int p_bone, const Transform3D &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;
@@ -175,11 +160,11 @@ public:
// posing api
- void set_bone_pose(int p_bone, const Transform &p_pose);
- Transform get_bone_pose(int p_bone) const;
+ void set_bone_pose(int p_bone, const Transform3D &p_pose);
+ Transform3D 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 set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose);
+ Transform3D get_bone_custom_pose(int p_bone) const;
void localize_rests(); // used for loaders and tools
int get_process_order(int p_idx);
@@ -188,10 +173,9 @@ public:
Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
// Helper functions
- Transform bone_transform_to_world_transform(Transform p_transform);
- Transform world_transform_to_bone_transform(Transform p_transform);
+ Transform3D bone_transform_to_world_transform(Transform3D p_transform);
+ Transform3D world_transform_to_bone_transform(Transform3D p_transform);
-#ifndef _3D_DISABLED
// Physical bone API
void set_animate_physical_bones(bool p_animate);
@@ -213,7 +197,6 @@ public:
void physical_bones_start_simulation_on(const TypedArray<StringName> &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();
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index 898f94ccc1..1005d51e63 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -129,7 +129,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain
return true;
}
-void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet) {
+void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet, Vector3 p_origin_pos) {
real_t distance_to_goal(1e4);
real_t previous_distance_to_goal(0);
int can_solve(p_task->max_iterations);
@@ -138,7 +138,7 @@ void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet) {
--can_solve;
solve_simple_backwards(p_task->chain, p_solve_magnet);
- solve_simple_forwards(p_task->chain, p_solve_magnet);
+ solve_simple_forwards(p_task->chain, p_solve_magnet, p_origin_pos);
distance_to_goal = (p_task->chain.tips[0].chain_item->current_pos - p_task->chain.tips[0].end_effector->goal_transform.origin).length();
}
@@ -176,13 +176,13 @@ void FabrikInverseKinematic::solve_simple_backwards(Chain &r_chain, bool p_solve
}
}
-void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_magnet) {
+void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_magnet, Vector3 p_origin_pos) {
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);
+ Vector3 origin = p_origin_pos;
while (sub_chain_root) { // Reach the tip
sub_chain_root->current_pos = origin;
@@ -212,7 +212,7 @@ void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_
}
}
-FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform) {
+FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform3D &goal_transform) {
FabrikInverseKinematic::EndEffector ee;
ee.tip_bone = tip_bone;
@@ -236,17 +236,17 @@ void FabrikInverseKinematic::free_task(Task *p_task) {
}
}
-void FabrikInverseKinematic::set_goal(Task *p_task, const Transform &p_goal) {
+void FabrikInverseKinematic::set_goal(Task *p_task, const Transform3D &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) {
+void FabrikInverseKinematic::make_goal(Task *p_task, const Transform3D &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[0].tip_bone));
+ const Transform3D end_effector_pose(p_task->skeleton->get_bone_global_pose_no_override(p_task->end_effectors[0].tip_bone));
// Update the end_effector (local transform) by blending with current pose
p_task->end_effectors.write[0].goal_transform = end_effector_pose.interpolate_with(p_inverse_transf * p_task->goal_global_transform, blending_delta);
@@ -270,76 +270,42 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
return; // Skip solving
}
- p_task->skeleton->set_bone_global_pose_override(p_task->chain.chain_root.bone, Transform(), 0.0, true);
-
- if (p_task->chain.middle_chain_item) {
- p_task->skeleton->set_bone_global_pose_override(p_task->chain.middle_chain_item->bone, Transform(), 0.0, true);
- }
-
- for (int i = 0; i < p_task->chain.tips.size(); i += 1) {
- p_task->skeleton->set_bone_global_pose_override(p_task->chain.tips[i].chain_item->bone, Transform(), 0.0, true);
- }
-
- // Update the transforms to their global poses
- // (Needed to sync IK with animation)
+ // Update the initial root transform so its synced with any animation changes
_update_chain(p_task->skeleton, &p_task->chain.chain_root);
+ p_task->skeleton->set_bone_global_pose_override(p_task->chain.chain_root.bone, Transform3D(), 0.0, false);
+ Vector3 origin_pos = p_task->skeleton->get_bone_global_pose(p_task->chain.chain_root.bone).origin;
+
make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse(), blending_delta);
if (p_use_magnet && p_task->chain.middle_chain_item) {
p_task->chain.magnet_position = p_task->chain.middle_chain_item->initial_transform.origin.lerp(p_magnet_position, blending_delta);
- solve_simple(p_task, true);
+ solve_simple(p_task, true, origin_pos);
}
- solve_simple(p_task, false);
+ solve_simple(p_task, false, origin_pos);
// Assign new bone position.
ChainItem *ci(&p_task->chain.chain_root);
while (ci) {
- Transform new_bone_pose(ci->initial_transform);
+ Transform3D new_bone_pose(ci->initial_transform);
new_bone_pose.origin = ci->current_pos;
- // The root bone needs to be rotated differently so it isn't frozen in place.
- if (ci == &p_task->chain.chain_root && !ci->children.is_empty()) {
- new_bone_pose = new_bone_pose.looking_at(ci->children[0].current_pos);
- const Vector3 bone_rest_dir = p_task->skeleton->get_bone_rest(ci->children[0].bone).origin.normalized().abs();
- const Vector3 bone_rest_dir_abs = bone_rest_dir.abs();
- if (bone_rest_dir_abs.x > bone_rest_dir_abs.y && bone_rest_dir_abs.x > bone_rest_dir_abs.z) {
- if (bone_rest_dir.x < 0) {
- new_bone_pose.basis.rotate_local(Vector3(0, 1, 0), -Math_PI / 2.0f);
- } else {
- new_bone_pose.basis.rotate_local(Vector3(0, 1, 0), Math_PI / 2.0f);
- }
- } else if (bone_rest_dir_abs.y > bone_rest_dir_abs.x && bone_rest_dir_abs.y > bone_rest_dir_abs.z) {
- if (bone_rest_dir.y < 0) {
- new_bone_pose.basis.rotate_local(Vector3(1, 0, 0), Math_PI / 2.0f);
- } else {
- new_bone_pose.basis.rotate_local(Vector3(1, 0, 0), -Math_PI / 2.0f);
- }
- } else {
- if (bone_rest_dir.z < 0) {
- // Do nothing!
- } else {
- new_bone_pose.basis.rotate_local(Vector3(0, 0, 1), Math_PI);
- }
- }
- } else {
- if (!ci->children.is_empty()) {
- /// Rotate basis
- const Vector3 initial_ori((ci->children[0].initial_transform.origin - ci->initial_transform.origin).normalized());
- const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized());
+ if (!ci->children.is_empty()) {
+ /// Rotate basis
+ const Vector3 initial_ori((ci->children[0].initial_transform.origin - ci->initial_transform.origin).normalized());
+ const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized());
- if (rot_axis[0] != 0 && rot_axis[1] != 0 && rot_axis[2] != 0) {
- const real_t rot_angle(Math::acos(CLAMP(initial_ori.dot(ci->current_ori), -1, 1)));
- new_bone_pose.basis.rotate(rot_axis, rot_angle);
- }
+ 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 {
- // 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;
- }
+ new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis;
}
}
@@ -362,7 +328,7 @@ void FabrikInverseKinematic::_update_chain(const Skeleton3D *p_sk, ChainItem *p_
return;
}
- p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone);
+ p_chain_item->initial_transform = p_sk->get_bone_global_pose_no_override(p_chain_item->bone);
p_chain_item->current_pos = p_chain_item->initial_transform.origin;
ChainItem *items = p_chain_item->children.ptrw();
@@ -431,7 +397,7 @@ void SkeletonIK3D::_bind_methods() {
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::TRANSFORM3D, "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");
@@ -495,12 +461,12 @@ real_t SkeletonIK3D::get_interpolation() const {
return interpolation;
}
-void SkeletonIK3D::set_target_transform(const Transform &p_target) {
+void SkeletonIK3D::set_target_transform(const Transform3D &p_target) {
target = p_target;
reload_goal();
}
-const Transform &SkeletonIK3D::get_target_transform() const {
+const Transform3D &SkeletonIK3D::get_target_transform() const {
return target;
}
@@ -571,7 +537,7 @@ void SkeletonIK3D::stop() {
}
}
-Transform SkeletonIK3D::_get_target_transform() {
+Transform3D 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));
}
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
index 9255e18b72..81dfe675c3 100644
--- a/scene/3d/skeleton_ik_3d.h
+++ b/scene/3d/skeleton_ik_3d.h
@@ -37,13 +37,13 @@
* @author AndreaCatania
*/
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include "scene/3d/skeleton_3d.h"
class FabrikInverseKinematic {
struct EndEffector {
BoneId tip_bone;
- Transform goal_transform;
+ Transform3D goal_transform;
};
struct ChainItem {
@@ -55,7 +55,7 @@ class FabrikInverseKinematic {
real_t length = 0.0;
/// Positions relative to root bone
- Transform initial_transform;
+ Transform3D initial_transform;
Vector3 current_pos;
// Direction from this bone to child
Vector3 current_ori;
@@ -97,7 +97,7 @@ public:
BoneId root_bone = -1;
Vector<EndEffector> end_effectors;
- Transform goal_global_transform;
+ Transform3D goal_global_transform;
Task() {}
};
@@ -106,17 +106,17 @@ 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 solve_simple(Task *p_task, bool p_solve_magnet);
+ static void solve_simple(Task *p_task, bool p_solve_magnet, Vector3 p_origin_pos);
/// 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);
+ static void solve_simple_forwards(Chain &r_chain, bool p_solve_magnet, Vector3 p_origin_pos);
public:
- static Task *create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform);
+ static Task *create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform3D &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 set_goal(Task *p_task, const Transform3D &p_goal);
+ static void make_goal(Task *p_task, const Transform3D &p_inverse_transf, real_t blending_delta);
static void solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position);
static void _update_chain(const Skeleton3D *p_skeleton, ChainItem *p_chain_item);
@@ -128,7 +128,7 @@ class SkeletonIK3D : public Node {
StringName root_bone;
StringName tip_bone;
real_t interpolation = 1.0;
- Transform target;
+ Transform3D target;
NodePath target_node_path_override;
bool override_tip_basis = true;
bool use_magnet = false;
@@ -161,8 +161,8 @@ public:
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_transform(const Transform3D &p_target);
+ const Transform3D &get_target_transform() const;
void set_target_node(const NodePath &p_node);
NodePath get_target_node();
@@ -190,7 +190,7 @@ public:
void stop();
private:
- Transform _get_target_transform();
+ Transform3D _get_target_transform();
void reload_chain();
void reload_goal();
void _solve_chain();
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 98ac6aa65e..df5474d03e 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -85,11 +85,11 @@ void SoftBodyRenderingServerHandler::commit_changes() {
}
void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
- copymem(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
+ memcpy(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
}
void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
- copymem(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
+ memcpy(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
}
void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
@@ -283,7 +283,7 @@ void SoftBody3D::_notification(int p_what) {
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_top_level(true);
- set_transform(Transform());
+ set_transform(Transform3D());
set_notify_transform(true);
} break;
@@ -373,7 +373,7 @@ TypedArray<String> SoftBody3D::get_configuration_warnings() const {
warnings.push_back(TTR("This body will be ignored until you set a mesh."));
}
- Transform t = get_transform();
+ Transform3D 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)) {
warnings.push_back(TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
@@ -408,7 +408,7 @@ void SoftBody3D::_draw_soft_mesh() {
/// Necessary in order to render the mesh correctly (Soft body nodes are in global space)
simulation_started = true;
call_deferred("set_as_top_level", true);
- call_deferred("set_transform", Transform());
+ call_deferred("set_transform", Transform3D());
}
_update_physics_server();
@@ -496,6 +496,7 @@ uint32_t SoftBody3D::get_collision_layer() const {
}
void SoftBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -506,10 +507,12 @@ void SoftBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool SoftBody3D::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
void SoftBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
uint32_t layer = get_collision_layer();
if (p_value) {
layer |= 1 << p_bit;
@@ -520,6 +523,7 @@ void SoftBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
}
bool SoftBody3D::get_collision_layer_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
return get_collision_layer() & (1 << p_bit);
}
diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp
index 9518b47696..1911e14d54 100644
--- a/scene/3d/spring_arm_3d.cpp
+++ b/scene/3d/spring_arm_3d.cpp
@@ -153,7 +153,7 @@ void SpringArm3D::process_spring() {
}
current_spring_length = spring_length * motion_delta;
- Transform childs_transform;
+ Transform3D 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) {
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 33b8b488c6..9ec461d973 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -505,6 +505,7 @@ void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) {
texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite3D::_texture_changed));
}
_queue_update();
+ emit_signal(SceneStringNames::get_singleton()->texture_changed);
}
Ref<Texture2D> Sprite3D::get_texture() const {
@@ -551,15 +552,15 @@ int Sprite3D::get_frame() const {
return frame;
}
-void Sprite3D::set_frame_coords(const Vector2 &p_coord) {
- ERR_FAIL_INDEX(int(p_coord.x), hframes);
- ERR_FAIL_INDEX(int(p_coord.y), vframes);
+void Sprite3D::set_frame_coords(const Vector2i &p_coord) {
+ ERR_FAIL_INDEX(p_coord.x, hframes);
+ ERR_FAIL_INDEX(p_coord.y, vframes);
- set_frame(int(p_coord.y) * hframes + int(p_coord.x));
+ set_frame(p_coord.y * hframes + p_coord.x);
}
-Vector2 Sprite3D::get_frame_coords() const {
- return Vector2(frame % hframes, frame / hframes);
+Vector2i Sprite3D::get_frame_coords() const {
+ return Vector2i(frame % hframes, frame / hframes);
}
void Sprite3D::set_vframes(int p_amount) {
@@ -657,12 +658,13 @@ void Sprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
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_PROPERTY(PropertyInfo(Variant::VECTOR2I, "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_enabled", "is_region_enabled");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
ADD_SIGNAL(MethodInfo("frame_changed"));
+ ADD_SIGNAL(MethodInfo("texture_changed"));
}
Sprite3D::Sprite3D() {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 5e47e66bcb..e3dd117804 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -176,8 +176,8 @@ public:
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_frame_coords(const Vector2i &p_coord);
+ Vector2i get_frame_coords() const;
void set_vframes(int p_amount);
int get_vframes() const;
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index edd58347f0..0d88769b70 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -346,7 +346,7 @@ VehicleWheel3D::VehicleWheel3D() {
void VehicleBody3D::_update_wheel_transform(VehicleWheel3D &wheel, PhysicsDirectBodyState3D *s) {
wheel.m_raycastInfo.m_isInContact = false;
- Transform chassisTrans = s->get_transform();
+ Transform3D chassisTrans = s->get_transform();
/*
if (interpolatedTransform && (getRigidBody()->getMotionState())) {
getRigidBody()->getMotionState()->getWorldTransform(chassisTrans);
@@ -784,7 +784,7 @@ void VehicleBody3D::_update_friction(PhysicsDirectBodyState3D *s) {
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);
+ Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1]; //getRigidBody()->getCenterOfMassTransform3D().getBasis().getColumn(m_indexUpAxis);
rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f - wheelInfo.m_rollInfluence));
#else
rel_pos[1] *= wheelInfo.m_rollInfluence; //?
@@ -803,6 +803,7 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) {
RigidBody3D::_direct_state_changed(p_state);
state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
real_t step = state->get_step();
@@ -840,7 +841,7 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) {
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();
+ const Transform3D &chassisWorldTransform = state->get_transform();
Vector3 fwd(
chassisWorldTransform.basis[0][Vector3::AXIS_Z],
@@ -922,7 +923,7 @@ void VehicleBody3D::_bind_methods() {
VehicleBody3D::VehicleBody3D() {
exclude.insert(get_rid());
- //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &VehicleBody3D::_direct_state_changed));
set_mass(40);
}
diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h
index 646071a363..2c10205ea3 100644
--- a/scene/3d/vehicle_body_3d.h
+++ b/scene/3d/vehicle_body_3d.h
@@ -40,8 +40,8 @@ class VehicleWheel3D : public Node3D {
friend class VehicleBody3D;
- Transform m_worldTransform;
- Transform local_xform;
+ Transform3D m_worldTransform;
+ Transform3D local_xform;
bool engine_traction = false;
bool steers = false;
diff --git a/scene/3d/velocity_tracker_3d.h b/scene/3d/velocity_tracker_3d.h
index e971f4755a..827c3f5bd8 100644
--- a/scene/3d/velocity_tracker_3d.h
+++ b/scene/3d/velocity_tracker_3d.h
@@ -33,8 +33,8 @@
#include "scene/3d/node_3d.h"
-class VelocityTracker3D : public Reference {
- GDCLASS(VelocityTracker3D, Reference);
+class VelocityTracker3D : public RefCounted {
+ GDCLASS(VelocityTracker3D, RefCounted);
struct PositionHistory {
uint64_t frame = 0;
diff --git a/scene/3d/visibility_notifier_3d.cpp b/scene/3d/visibility_notifier_3d.cpp
index 471838b9d1..39b17d195b 100644
--- a/scene/3d/visibility_notifier_3d.cpp
+++ b/scene/3d/visibility_notifier_3d.cpp
@@ -36,27 +36,23 @@
#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();
+void VisibilityNotifier3D::_visibility_enter() {
+ if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
+ return;
}
- emit_signal(SceneStringNames::get_singleton()->camera_entered, p_camera);
+ on_screen = true;
+ emit_signal(SceneStringNames::get_singleton()->screen_entered);
+ _screen_enter();
}
-
-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::_visibility_exit() {
+ if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
+ return;
}
+
+ on_screen = false;
+ emit_signal(SceneStringNames::get_singleton()->screen_exited);
+ _screen_exit();
}
void VisibilityNotifier3D::set_aabb(const AABB &p_aabb) {
@@ -65,9 +61,7 @@ void VisibilityNotifier3D::set_aabb(const AABB &p_aabb) {
}
aabb = p_aabb;
- if (is_inside_world()) {
- get_world_3d()->_update_notifier(this, get_global_transform().xform(aabb));
- }
+ RS::get_singleton()->visibility_notifier_set_aabb(get_base(), aabb);
update_gizmo();
}
@@ -76,178 +70,129 @@ AABB VisibilityNotifier3D::get_aabb() const {
return aabb;
}
-void VisibilityNotifier3D::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_WORLD: {
- world = get_world_3d();
- ERR_FAIL_COND(!world.is_valid());
- world->_register_notifier(this, get_global_transform().xform(aabb));
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
- world->_update_notifier(this, get_global_transform().xform(aabb));
- } break;
- case NOTIFICATION_EXIT_WORLD: {
- ERR_FAIL_COND(!world.is_valid());
- world->_remove_notifier(this);
- } break;
- }
+bool VisibilityNotifier3D::is_on_screen() const {
+ return on_screen;
}
-bool VisibilityNotifier3D::is_on_screen() const {
- return cameras.size() != 0;
+void VisibilityNotifier3D::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_EXIT_TREE) {
+ on_screen = false;
+ }
}
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"));
}
+Vector<Face3> VisibilityNotifier3D::get_faces(uint32_t p_usage_flags) const {
+ return Vector<Face3>();
+}
+
VisibilityNotifier3D::VisibilityNotifier3D() {
- set_notify_transform(true);
+ RID notifier = RS::get_singleton()->visibility_notifier_create();
+ RS::get_singleton()->visibility_notifier_set_aabb(notifier, aabb);
+ RS::get_singleton()->visibility_notifier_set_callbacks(notifier, callable_mp(this, &VisibilityNotifier3D::_visibility_enter), callable_mp(this, &VisibilityNotifier3D::_visibility_exit));
+ set_base(notifier);
}
//////////////////////////////////////
void VisibilityEnabler3D::_screen_enter() {
- for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
- _change_node_state(E->key(), true);
- }
-
- visible = true;
+ _update_enable_mode(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;
+ _update_enable_mode(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();
- }
+void VisibilityEnabler3D::set_enable_mode(EnableMode p_mode) {
+ enable_mode = p_mode;
+ if (is_inside_tree()) {
+ _update_enable_mode(is_on_screen());
}
+}
+VisibilityEnabler3D::EnableMode VisibilityEnabler3D::get_enable_mode() {
+ return enable_mode;
+}
- {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
- if (ap) {
- add = true;
- }
+void VisibilityEnabler3D::set_enable_node_path(NodePath p_path) {
+ if (enable_node_path == p_path) {
+ return;
}
-
- 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);
+ enable_node_path = p_path;
+ if (is_inside_tree()) {
+ node_id = ObjectID();
+ Node *node = get_node(enable_node_path);
+ if (node) {
+ node_id = node->get_instance_id();
+ _update_enable_mode(is_on_screen());
+ }
}
-
- 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
+}
+NodePath VisibilityEnabler3D::get_enable_node_path() {
+ return enable_node_path;
+}
+
+void VisibilityEnabler3D::_update_enable_mode(bool p_enable) {
+ Node *node = static_cast<Node *>(ObjectDB::get_instance(node_id));
+ if (node) {
+ if (p_enable) {
+ switch (enable_mode) {
+ case ENABLE_MODE_INHERIT: {
+ node->set_process_mode(PROCESS_MODE_INHERIT);
+ } break;
+ case ENABLE_MODE_ALWAYS: {
+ node->set_process_mode(PROCESS_MODE_ALWAYS);
+ } break;
+ case ENABLE_MODE_WHEN_PAUSED: {
+ node->set_process_mode(PROCESS_MODE_WHEN_PAUSED);
+ } break;
+ }
+ } else {
+ node->set_process_mode(PROCESS_MODE_DISABLED);
}
-
- _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();
+ node_id = ObjectID();
+ Node *node = get_node(enable_node_path);
+ if (node) {
+ node_id = node->get_instance_id();
+ node->set_process_mode(PROCESS_MODE_DISABLED);
}
-
- _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);
- }
+ node_id = ObjectID();
}
}
-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);
+ ClassDB::bind_method(D_METHOD("set_enable_mode", "mode"), &VisibilityEnabler3D::set_enable_mode);
+ ClassDB::bind_method(D_METHOD("get_enable_mode"), &VisibilityEnabler3D::get_enable_mode);
- 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);
+ ClassDB::bind_method(D_METHOD("set_enable_node_path", "path"), &VisibilityEnabler3D::set_enable_node_path);
+ ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibilityEnabler3D::get_enable_node_path);
- BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS);
- BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES);
- BIND_ENUM_CONSTANT(ENABLER_MAX);
-}
+ ADD_GROUP("Enabling", "enable_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path");
-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];
+ BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT);
+ BIND_ENUM_CONSTANT(ENABLE_MODE_ALWAYS);
+ BIND_ENUM_CONSTANT(ENABLE_MODE_WHEN_PAUSED);
}
VisibilityEnabler3D::VisibilityEnabler3D() {
- for (int i = 0; i < ENABLER_MAX; i++) {
- enabler[i] = true;
- }
}
diff --git a/scene/3d/visibility_notifier_3d.h b/scene/3d/visibility_notifier_3d.h
index 9f7705067f..878c97e35e 100644
--- a/scene/3d/visibility_notifier_3d.h
+++ b/scene/3d/visibility_notifier_3d.h
@@ -31,34 +31,34 @@
#ifndef VISIBILITY_NOTIFIER_H
#define VISIBILITY_NOTIFIER_H
-#include "scene/3d/node_3d.h"
+#include "scene/3d/visual_instance_3d.h"
class World3D;
class Camera3D;
-class VisibilityNotifier3D : public Node3D {
- GDCLASS(VisibilityNotifier3D, Node3D);
-
- Ref<World3D> world;
- Set<Camera3D *> cameras;
+class VisibilityNotifier3D : public VisualInstance3D {
+ GDCLASS(VisibilityNotifier3D, VisualInstance3D);
AABB aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+private:
+ bool on_screen = false;
+ void _visibility_enter();
+ void _visibility_exit();
+
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;
+ virtual AABB get_aabb() const override;
bool is_on_screen() const;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
+
VisibilityNotifier3D();
};
@@ -66,36 +66,35 @@ class VisibilityEnabler3D : public VisibilityNotifier3D {
GDCLASS(VisibilityEnabler3D, VisibilityNotifier3D);
public:
- enum Enabler {
- ENABLER_PAUSE_ANIMATIONS,
- ENABLER_FREEZE_BODIES,
- ENABLER_MAX
+ enum EnableMode {
+ ENABLE_MODE_INHERIT,
+ ENABLE_MODE_ALWAYS,
+ ENABLE_MODE_WHEN_PAUSED,
};
protected:
+ ObjectID node_id;
virtual void _screen_enter() override;
virtual void _screen_exit() override;
- bool visible = false;
-
- 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);
+ EnableMode enable_mode = ENABLE_MODE_INHERIT;
+ NodePath enable_node_path = NodePath("..");
void _notification(int p_what);
static void _bind_methods();
+ void _update_enable_mode(bool p_enable);
+
public:
- void set_enabler(Enabler p_enabler, bool p_enable);
- bool is_enabler_enabled(Enabler p_enabler) const;
+ void set_enable_mode(EnableMode p_mode);
+ EnableMode get_enable_mode();
+
+ void set_enable_node_path(NodePath p_path);
+ NodePath get_enable_node_path();
VisibilityEnabler3D();
};
-VARIANT_ENUM_CAST(VisibilityEnabler3D::Enabler);
+VARIANT_ENUM_CAST(VisibilityEnabler3D::EnableMode);
#endif // VISIBILITY_NOTIFIER_H
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 394c67e873..c16e3c2d78 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -61,7 +61,7 @@ void VisualInstance3D::_notification(int p_what) {
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
- Transform gt = get_global_transform();
+ Transform3D gt = get_global_transform();
RenderingServer::get_singleton()->instance_set_transform(instance, gt);
} break;
case NOTIFICATION_EXIT_WORLD: {
@@ -150,40 +150,40 @@ 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);
+void GeometryInstance3D::set_visibility_range_begin(float p_dist) {
+ visibility_range_begin = p_dist;
+ RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
}
-float GeometryInstance3D::get_lod_min_distance() const {
- return lod_min_distance;
+float GeometryInstance3D::get_visibility_range_begin() const {
+ return visibility_range_begin;
}
-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);
+void GeometryInstance3D::set_visibility_range_end(float p_dist) {
+ visibility_range_end = p_dist;
+ RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
}
-float GeometryInstance3D::get_lod_max_distance() const {
- return lod_max_distance;
+float GeometryInstance3D::get_visibility_range_end() const {
+ return visibility_range_end;
}
-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);
+void GeometryInstance3D::set_visibility_range_begin_margin(float p_dist) {
+ visibility_range_begin_margin = p_dist;
+ RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
}
-float GeometryInstance3D::get_lod_min_hysteresis() const {
- return lod_min_hysteresis;
+float GeometryInstance3D::get_visibility_range_begin_margin() const {
+ return visibility_range_begin_margin;
}
-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);
+void GeometryInstance3D::set_visibility_range_end_margin(float p_dist) {
+ visibility_range_end_margin = p_dist;
+ RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
}
-float GeometryInstance3D::get_lod_max_hysteresis() const {
- return lod_max_hysteresis;
+float GeometryInstance3D::get_visibility_range_end_margin() const {
+ return visibility_range_end_margin;
}
void GeometryInstance3D::_notification(int p_what) {
@@ -338,6 +338,15 @@ GeometryInstance3D::GIMode GeometryInstance3D::get_gi_mode() const {
return gi_mode;
}
+void GeometryInstance3D::set_ignore_occlusion_culling(bool p_enabled) {
+ ignore_occlusion_culling = p_enabled;
+ RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, ignore_occlusion_culling);
+}
+
+bool GeometryInstance3D::is_ignoring_occlusion_culling() {
+ return ignore_occlusion_culling;
+}
+
void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance3D::set_material_override);
ClassDB::bind_method(D_METHOD("get_material_override"), &GeometryInstance3D::get_material_override);
@@ -345,20 +354,23 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cast_shadows_setting", "shadow_casting_setting"), &GeometryInstance3D::set_cast_shadows_setting);
ClassDB::bind_method(D_METHOD("get_cast_shadows_setting"), &GeometryInstance3D::get_cast_shadows_setting);
- ClassDB::bind_method(D_METHOD("set_lod_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_bias", "bias"), &GeometryInstance3D::set_lod_bias);
+ ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias);
- ClassDB::bind_method(D_METHOD("set_lod_max_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_visibility_range_end_margin", "distance"), &GeometryInstance3D::set_visibility_range_end_margin);
+ ClassDB::bind_method(D_METHOD("get_visibility_range_end_margin"), &GeometryInstance3D::get_visibility_range_end_margin);
- ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
- ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
+ ClassDB::bind_method(D_METHOD("set_visibility_range_end", "distance"), &GeometryInstance3D::set_visibility_range_end);
+ ClassDB::bind_method(D_METHOD("get_visibility_range_end"), &GeometryInstance3D::get_visibility_range_end);
+
+ ClassDB::bind_method(D_METHOD("set_visibility_range_begin_margin", "distance"), &GeometryInstance3D::set_visibility_range_begin_margin);
+ ClassDB::bind_method(D_METHOD("get_visibility_range_begin_margin"), &GeometryInstance3D::get_visibility_range_begin_margin);
- 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_visibility_range_begin", "distance"), &GeometryInstance3D::set_visibility_range_begin);
+ ClassDB::bind_method(D_METHOD("get_visibility_range_begin"), &GeometryInstance3D::get_visibility_range_begin);
- ClassDB::bind_method(D_METHOD("set_lod_min_distance", "mode"), &GeometryInstance3D::set_lod_min_distance);
- ClassDB::bind_method(D_METHOD("get_lod_min_distance"), &GeometryInstance3D::get_lod_min_distance);
+ ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
+ ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance3D::set_extra_cull_margin);
ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance3D::get_extra_cull_margin);
@@ -369,8 +381,8 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_gi_mode", "mode"), &GeometryInstance3D::set_gi_mode);
ClassDB::bind_method(D_METHOD("get_gi_mode"), &GeometryInstance3D::get_gi_mode);
- ClassDB::bind_method(D_METHOD("set_lod_bias", "bias"), &GeometryInstance3D::set_lod_bias);
- ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias);
+ ClassDB::bind_method(D_METHOD("set_ignore_occlusion_culling", "ignore_culling"), &GeometryInstance3D::set_ignore_occlusion_culling);
+ ClassDB::bind_method(D_METHOD("is_ignoring_occlusion_culling"), &GeometryInstance3D::is_ignoring_occlusion_culling);
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance3D::set_custom_aabb);
@@ -381,15 +393,16 @@ void GeometryInstance3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_bias", PROPERTY_HINT_RANGE, "0.001,128,0.001"), "set_lod_bias", "get_lod_bias");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_occlusion_culling"), "set_ignore_occlusion_culling", "is_ignoring_occlusion_culling");
ADD_GROUP("Global Illumination", "gi_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Baked,Dynamic"), "set_gi_mode", "get_gi_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, "1x,2x,4x,8x"), "set_lightmap_scale", "get_lightmap_scale");
- 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_GROUP("Visibility Range", "visibility_range_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_begin", "get_visibility_range_begin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_begin_margin", "get_visibility_range_begin_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_end", "get_visibility_range_end");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_end_margin", "get_visibility_range_end_margin");
//ADD_SIGNAL( MethodInfo("visibility_changed"));
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 7fed8095ef..2d5699859b 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -107,10 +107,13 @@ public:
private:
ShadowCastingSetting shadow_casting_setting = SHADOW_CASTING_SETTING_ON;
Ref<Material> material_override;
- float lod_min_distance = 0.0;
- float lod_max_distance = 0.0;
- float lod_min_hysteresis = 0.0;
- float lod_max_hysteresis = 0.0;
+
+ float visibility_range_begin = 0.0;
+ float visibility_range_end = 0.0;
+ float visibility_range_begin_margin = 0.0;
+ float visibility_range_end_margin = 0.0;
+
+ Vector<NodePath> visibility_range_children;
float lod_bias = 1.0;
@@ -120,6 +123,7 @@ private:
float extra_cull_margin = 0.0;
LightmapScale lightmap_scale = LIGHTMAP_SCALE_1X;
GIMode gi_mode = GI_MODE_DISABLED;
+ bool ignore_occlusion_culling = false;
const StringName *_instance_uniform_get_remap(const StringName p_name) const;
@@ -135,17 +139,20 @@ public:
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_visibility_range_begin(float p_dist);
+ float get_visibility_range_begin() const;
- void set_lod_max_distance(float p_dist);
- float get_lod_max_distance() const;
+ void set_visibility_range_end(float p_dist);
+ float get_visibility_range_end() const;
- void set_lod_min_hysteresis(float p_dist);
- float get_lod_min_hysteresis() const;
+ void set_visibility_range_begin_margin(float p_dist);
+ float get_visibility_range_begin_margin() const;
- void set_lod_max_hysteresis(float p_dist);
- float get_lod_max_hysteresis() const;
+ void set_visibility_range_end_margin(float p_dist);
+ float get_visibility_range_end_margin() const;
+
+ void set_visibility_range_parent(const Node *p_parent);
+ void clear_visibility_range_parent();
void set_material_override(const Ref<Material> &p_material);
Ref<Material> get_material_override() const;
@@ -167,6 +174,9 @@ public:
void set_custom_aabb(AABB aabb);
+ void set_ignore_occlusion_culling(bool p_enabled);
+ bool is_ignoring_occlusion_culling();
+
GeometryInstance3D();
};
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/voxel_gi.cpp
index 4d7fc29f15..e00be9204c 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gi_probe.cpp */
+/* voxel_gi.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,14 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "gi_probe.h"
+#include "voxel_gi.h"
#include "core/os/os.h"
#include "mesh_instance_3d.h"
#include "voxelizer.h"
-void GIProbeData::_set_data(const Dictionary &p_data) {
+void VoxelGIData::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("bounds"));
ERR_FAIL_COND(!p_data.has("octree_size"));
ERR_FAIL_COND(!p_data.has("octree_cells"));
@@ -62,12 +62,12 @@ void GIProbeData::_set_data(const Dictionary &p_data) {
octree_df = img->get_data();
}
Vector<int> octree_levels = p_data["level_counts"];
- Transform to_cell_xform = p_data["to_cell_xform"];
+ Transform3D to_cell_xform = p_data["to_cell_xform"];
allocate(to_cell_xform, bounds, octree_size, octree_cells, octree_data, octree_df, octree_levels);
}
-Dictionary GIProbeData::_get_data() const {
+Dictionary VoxelGIData::_get_data() const {
Dictionary d;
d["bounds"] = get_bounds();
Vector3i otsize = get_octree_size();
@@ -90,186 +90,186 @@ Dictionary GIProbeData::_get_data() const {
return d;
}
-void GIProbeData::allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
- RS::get_singleton()->gi_probe_allocate_data(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts);
+void VoxelGIData::allocate(const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
+ RS::get_singleton()->voxel_gi_allocate_data(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts);
bounds = p_aabb;
to_cell_xform = p_to_cell_xform;
octree_size = p_octree_size;
}
-AABB GIProbeData::get_bounds() const {
+AABB VoxelGIData::get_bounds() const {
return bounds;
}
-Vector3 GIProbeData::get_octree_size() const {
+Vector3 VoxelGIData::get_octree_size() const {
return octree_size;
}
-Vector<uint8_t> GIProbeData::get_octree_cells() const {
- return RS::get_singleton()->gi_probe_get_octree_cells(probe);
+Vector<uint8_t> VoxelGIData::get_octree_cells() const {
+ return RS::get_singleton()->voxel_gi_get_octree_cells(probe);
}
-Vector<uint8_t> GIProbeData::get_data_cells() const {
- return RS::get_singleton()->gi_probe_get_data_cells(probe);
+Vector<uint8_t> VoxelGIData::get_data_cells() const {
+ return RS::get_singleton()->voxel_gi_get_data_cells(probe);
}
-Vector<uint8_t> GIProbeData::get_distance_field() const {
- return RS::get_singleton()->gi_probe_get_distance_field(probe);
+Vector<uint8_t> VoxelGIData::get_distance_field() const {
+ return RS::get_singleton()->voxel_gi_get_distance_field(probe);
}
-Vector<int> GIProbeData::get_level_counts() const {
- return RS::get_singleton()->gi_probe_get_level_counts(probe);
+Vector<int> VoxelGIData::get_level_counts() const {
+ return RS::get_singleton()->voxel_gi_get_level_counts(probe);
}
-Transform GIProbeData::get_to_cell_xform() const {
+Transform3D VoxelGIData::get_to_cell_xform() const {
return to_cell_xform;
}
-void GIProbeData::set_dynamic_range(float p_range) {
- RS::get_singleton()->gi_probe_set_dynamic_range(probe, p_range);
+void VoxelGIData::set_dynamic_range(float p_range) {
+ RS::get_singleton()->voxel_gi_set_dynamic_range(probe, p_range);
dynamic_range = p_range;
}
-float GIProbeData::get_dynamic_range() const {
+float VoxelGIData::get_dynamic_range() const {
return dynamic_range;
}
-void GIProbeData::set_propagation(float p_propagation) {
- RS::get_singleton()->gi_probe_set_propagation(probe, p_propagation);
+void VoxelGIData::set_propagation(float p_propagation) {
+ RS::get_singleton()->voxel_gi_set_propagation(probe, p_propagation);
propagation = p_propagation;
}
-float GIProbeData::get_propagation() const {
+float VoxelGIData::get_propagation() const {
return propagation;
}
-void GIProbeData::set_anisotropy_strength(float p_anisotropy_strength) {
- RS::get_singleton()->gi_probe_set_anisotropy_strength(probe, p_anisotropy_strength);
+void VoxelGIData::set_anisotropy_strength(float p_anisotropy_strength) {
+ RS::get_singleton()->voxel_gi_set_anisotropy_strength(probe, p_anisotropy_strength);
anisotropy_strength = p_anisotropy_strength;
}
-float GIProbeData::get_anisotropy_strength() const {
+float VoxelGIData::get_anisotropy_strength() const {
return anisotropy_strength;
}
-void GIProbeData::set_energy(float p_energy) {
- RS::get_singleton()->gi_probe_set_energy(probe, p_energy);
+void VoxelGIData::set_energy(float p_energy) {
+ RS::get_singleton()->voxel_gi_set_energy(probe, p_energy);
energy = p_energy;
}
-float GIProbeData::get_energy() const {
+float VoxelGIData::get_energy() const {
return energy;
}
-void GIProbeData::set_ao(float p_ao) {
- RS::get_singleton()->gi_probe_set_ao(probe, p_ao);
+void VoxelGIData::set_ao(float p_ao) {
+ RS::get_singleton()->voxel_gi_set_ao(probe, p_ao);
ao = p_ao;
}
-float GIProbeData::get_ao() const {
+float VoxelGIData::get_ao() const {
return ao;
}
-void GIProbeData::set_ao_size(float p_ao_size) {
- RS::get_singleton()->gi_probe_set_ao_size(probe, p_ao_size);
+void VoxelGIData::set_ao_size(float p_ao_size) {
+ RS::get_singleton()->voxel_gi_set_ao_size(probe, p_ao_size);
ao_size = p_ao_size;
}
-float GIProbeData::get_ao_size() const {
+float VoxelGIData::get_ao_size() const {
return ao_size;
}
-void GIProbeData::set_bias(float p_bias) {
- RS::get_singleton()->gi_probe_set_bias(probe, p_bias);
+void VoxelGIData::set_bias(float p_bias) {
+ RS::get_singleton()->voxel_gi_set_bias(probe, p_bias);
bias = p_bias;
}
-float GIProbeData::get_bias() const {
+float VoxelGIData::get_bias() const {
return bias;
}
-void GIProbeData::set_normal_bias(float p_normal_bias) {
- RS::get_singleton()->gi_probe_set_normal_bias(probe, p_normal_bias);
+void VoxelGIData::set_normal_bias(float p_normal_bias) {
+ RS::get_singleton()->voxel_gi_set_normal_bias(probe, p_normal_bias);
normal_bias = p_normal_bias;
}
-float GIProbeData::get_normal_bias() const {
+float VoxelGIData::get_normal_bias() const {
return normal_bias;
}
-void GIProbeData::set_interior(bool p_enable) {
- RS::get_singleton()->gi_probe_set_interior(probe, p_enable);
+void VoxelGIData::set_interior(bool p_enable) {
+ RS::get_singleton()->voxel_gi_set_interior(probe, p_enable);
interior = p_enable;
}
-bool GIProbeData::is_interior() const {
+bool VoxelGIData::is_interior() const {
return interior;
}
-void GIProbeData::set_use_two_bounces(bool p_enable) {
- RS::get_singleton()->gi_probe_set_use_two_bounces(probe, p_enable);
+void VoxelGIData::set_use_two_bounces(bool p_enable) {
+ RS::get_singleton()->voxel_gi_set_use_two_bounces(probe, p_enable);
use_two_bounces = p_enable;
}
-bool GIProbeData::is_using_two_bounces() const {
+bool VoxelGIData::is_using_two_bounces() const {
return use_two_bounces;
}
-RID GIProbeData::get_rid() const {
+RID VoxelGIData::get_rid() const {
return probe;
}
-void GIProbeData::_validate_property(PropertyInfo &property) const {
+void VoxelGIData::_validate_property(PropertyInfo &property) const {
if (property.name == "anisotropy_strength") {
- bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/global_illumination/gi_probes/anisotropic");
+ bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/global_illumination/voxel_gi/anisotropic");
if (!anisotropy_enabled) {
property.usage = PROPERTY_USAGE_NOEDITOR;
}
}
}
-void GIProbeData::_bind_methods() {
- ClassDB::bind_method(D_METHOD("allocate", "to_cell_xform", "aabb", "octree_size", "octree_cells", "data_cells", "distance_field", "level_counts"), &GIProbeData::allocate);
+void VoxelGIData::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("allocate", "to_cell_xform", "aabb", "octree_size", "octree_cells", "data_cells", "distance_field", "level_counts"), &VoxelGIData::allocate);
- ClassDB::bind_method(D_METHOD("get_bounds"), &GIProbeData::get_bounds);
- ClassDB::bind_method(D_METHOD("get_octree_size"), &GIProbeData::get_octree_size);
- ClassDB::bind_method(D_METHOD("get_to_cell_xform"), &GIProbeData::get_to_cell_xform);
- ClassDB::bind_method(D_METHOD("get_octree_cells"), &GIProbeData::get_octree_cells);
- ClassDB::bind_method(D_METHOD("get_data_cells"), &GIProbeData::get_data_cells);
- ClassDB::bind_method(D_METHOD("get_level_counts"), &GIProbeData::get_level_counts);
+ ClassDB::bind_method(D_METHOD("get_bounds"), &VoxelGIData::get_bounds);
+ ClassDB::bind_method(D_METHOD("get_octree_size"), &VoxelGIData::get_octree_size);
+ ClassDB::bind_method(D_METHOD("get_to_cell_xform"), &VoxelGIData::get_to_cell_xform);
+ ClassDB::bind_method(D_METHOD("get_octree_cells"), &VoxelGIData::get_octree_cells);
+ ClassDB::bind_method(D_METHOD("get_data_cells"), &VoxelGIData::get_data_cells);
+ ClassDB::bind_method(D_METHOD("get_level_counts"), &VoxelGIData::get_level_counts);
- ClassDB::bind_method(D_METHOD("set_dynamic_range", "dynamic_range"), &GIProbeData::set_dynamic_range);
- ClassDB::bind_method(D_METHOD("get_dynamic_range"), &GIProbeData::get_dynamic_range);
+ ClassDB::bind_method(D_METHOD("set_dynamic_range", "dynamic_range"), &VoxelGIData::set_dynamic_range);
+ ClassDB::bind_method(D_METHOD("get_dynamic_range"), &VoxelGIData::get_dynamic_range);
- ClassDB::bind_method(D_METHOD("set_energy", "energy"), &GIProbeData::set_energy);
- ClassDB::bind_method(D_METHOD("get_energy"), &GIProbeData::get_energy);
+ ClassDB::bind_method(D_METHOD("set_energy", "energy"), &VoxelGIData::set_energy);
+ ClassDB::bind_method(D_METHOD("get_energy"), &VoxelGIData::get_energy);
- ClassDB::bind_method(D_METHOD("set_bias", "bias"), &GIProbeData::set_bias);
- ClassDB::bind_method(D_METHOD("get_bias"), &GIProbeData::get_bias);
+ ClassDB::bind_method(D_METHOD("set_bias", "bias"), &VoxelGIData::set_bias);
+ ClassDB::bind_method(D_METHOD("get_bias"), &VoxelGIData::get_bias);
- ClassDB::bind_method(D_METHOD("set_normal_bias", "bias"), &GIProbeData::set_normal_bias);
- ClassDB::bind_method(D_METHOD("get_normal_bias"), &GIProbeData::get_normal_bias);
+ ClassDB::bind_method(D_METHOD("set_normal_bias", "bias"), &VoxelGIData::set_normal_bias);
+ ClassDB::bind_method(D_METHOD("get_normal_bias"), &VoxelGIData::get_normal_bias);
- ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &GIProbeData::set_propagation);
- ClassDB::bind_method(D_METHOD("get_propagation"), &GIProbeData::get_propagation);
+ ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &VoxelGIData::set_propagation);
+ ClassDB::bind_method(D_METHOD("get_propagation"), &VoxelGIData::get_propagation);
- ClassDB::bind_method(D_METHOD("set_anisotropy_strength", "strength"), &GIProbeData::set_anisotropy_strength);
- ClassDB::bind_method(D_METHOD("get_anisotropy_strength"), &GIProbeData::get_anisotropy_strength);
+ ClassDB::bind_method(D_METHOD("set_anisotropy_strength", "strength"), &VoxelGIData::set_anisotropy_strength);
+ ClassDB::bind_method(D_METHOD("get_anisotropy_strength"), &VoxelGIData::get_anisotropy_strength);
- ClassDB::bind_method(D_METHOD("set_ao", "ao"), &GIProbeData::set_ao);
- ClassDB::bind_method(D_METHOD("get_ao"), &GIProbeData::get_ao);
+ ClassDB::bind_method(D_METHOD("set_ao", "ao"), &VoxelGIData::set_ao);
+ ClassDB::bind_method(D_METHOD("get_ao"), &VoxelGIData::get_ao);
- ClassDB::bind_method(D_METHOD("set_ao_size", "strength"), &GIProbeData::set_ao_size);
- ClassDB::bind_method(D_METHOD("get_ao_size"), &GIProbeData::get_ao_size);
+ ClassDB::bind_method(D_METHOD("set_ao_size", "strength"), &VoxelGIData::set_ao_size);
+ ClassDB::bind_method(D_METHOD("get_ao_size"), &VoxelGIData::get_ao_size);
- ClassDB::bind_method(D_METHOD("set_interior", "interior"), &GIProbeData::set_interior);
- ClassDB::bind_method(D_METHOD("is_interior"), &GIProbeData::is_interior);
+ ClassDB::bind_method(D_METHOD("set_interior", "interior"), &VoxelGIData::set_interior);
+ ClassDB::bind_method(D_METHOD("is_interior"), &VoxelGIData::is_interior);
- ClassDB::bind_method(D_METHOD("set_use_two_bounces", "enable"), &GIProbeData::set_use_two_bounces);
- ClassDB::bind_method(D_METHOD("is_using_two_bounces"), &GIProbeData::is_using_two_bounces);
+ ClassDB::bind_method(D_METHOD("set_use_two_bounces", "enable"), &VoxelGIData::set_use_two_bounces);
+ ClassDB::bind_method(D_METHOD("is_using_two_bounces"), &VoxelGIData::is_using_two_bounces);
- ClassDB::bind_method(D_METHOD("_set_data", "data"), &GIProbeData::_set_data);
- ClassDB::bind_method(D_METHOD("_get_data"), &GIProbeData::_get_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &VoxelGIData::_set_data);
+ ClassDB::bind_method(D_METHOD("_get_data"), &VoxelGIData::_get_data);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
@@ -285,18 +285,18 @@ void GIProbeData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
}
-GIProbeData::GIProbeData() {
- probe = RS::get_singleton()->gi_probe_create();
+VoxelGIData::VoxelGIData() {
+ probe = RS::get_singleton()->voxel_gi_create();
}
-GIProbeData::~GIProbeData() {
+VoxelGIData::~VoxelGIData() {
RS::get_singleton()->free(probe);
}
//////////////////////
//////////////////////
-void GIProbe::set_probe_data(const Ref<GIProbeData> &p_data) {
+void VoxelGI::set_probe_data(const Ref<VoxelGIData> &p_data) {
if (p_data.is_valid()) {
RS::get_singleton()->instance_set_base(get_instance(), p_data->get_rid());
} else {
@@ -306,37 +306,37 @@ void GIProbe::set_probe_data(const Ref<GIProbeData> &p_data) {
probe_data = p_data;
}
-Ref<GIProbeData> GIProbe::get_probe_data() const {
+Ref<VoxelGIData> VoxelGI::get_probe_data() const {
return probe_data;
}
-void GIProbe::set_subdiv(Subdiv p_subdiv) {
+void VoxelGI::set_subdiv(Subdiv p_subdiv) {
ERR_FAIL_INDEX(p_subdiv, SUBDIV_MAX);
subdiv = p_subdiv;
update_gizmo();
}
-GIProbe::Subdiv GIProbe::get_subdiv() const {
+VoxelGI::Subdiv VoxelGI::get_subdiv() const {
return subdiv;
}
-void GIProbe::set_extents(const Vector3 &p_extents) {
+void VoxelGI::set_extents(const Vector3 &p_extents) {
extents = p_extents;
update_gizmo();
}
-Vector3 GIProbe::get_extents() const {
+Vector3 VoxelGI::get_extents() const {
return extents;
}
-void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
+void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_BAKED && mi->is_visible_in_tree()) {
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
AABB aabb = mesh->get_aabb();
- Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform();
+ Transform3D xf = get_global_transform().affine_inverse() * mi->get_global_transform();
if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) {
PlotMesh pm;
@@ -356,7 +356,7 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
if (s->is_visible_in_tree()) {
Array meshes = p_at_node->call("get_meshes");
for (int i = 0; i < meshes.size(); i += 2) {
- Transform mxf = meshes[i];
+ Transform3D mxf = meshes[i];
Ref<Mesh> mesh = meshes[i + 1];
if (!mesh.is_valid()) {
continue;
@@ -364,7 +364,7 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
AABB aabb = mesh->get_aabb();
- Transform xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
+ Transform3D xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) {
PlotMesh pm;
@@ -382,11 +382,11 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
}
}
-GIProbe::BakeBeginFunc GIProbe::bake_begin_function = nullptr;
-GIProbe::BakeStepFunc GIProbe::bake_step_function = nullptr;
-GIProbe::BakeEndFunc GIProbe::bake_end_function = nullptr;
+VoxelGI::BakeBeginFunc VoxelGI::bake_begin_function = nullptr;
+VoxelGI::BakeStepFunc VoxelGI::bake_step_function = nullptr;
+VoxelGI::BakeEndFunc VoxelGI::bake_end_function = nullptr;
-Vector3i GIProbe::get_estimated_cell_size() const {
+Vector3i VoxelGI::get_estimated_cell_size() const {
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
int cell_subdiv = subdiv_value[subdiv];
int axis_cell_size[3];
@@ -412,7 +412,7 @@ Vector3i GIProbe::get_estimated_cell_size() const {
return Vector3i(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]);
}
-void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
+void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
p_from_node = p_from_node ? p_from_node : get_parent();
@@ -454,7 +454,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
mmi->set_multimesh(baker.create_debug_multimesh());
add_child(mmi);
#ifdef TOOLS_ENABLED
- if (get_tree()->get_edited_scene_root() == this) {
+ if (is_inside_tree() && get_tree()->get_edited_scene_root() == this) {
mmi->set_owner(this);
} else {
mmi->set_owner(get_owner());
@@ -464,7 +464,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
#endif
} else {
- Ref<GIProbeData> probe_data = get_probe_data();
+ Ref<VoxelGIData> probe_data = get_probe_data();
if (probe_data.is_null()) {
probe_data.instance();
@@ -476,7 +476,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
Vector<uint8_t> df = baker.get_sdf_3d_image();
- probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_giprobe_octree_size(), baker.get_giprobe_octree_cells(), baker.get_giprobe_data_cells(), df, baker.get_giprobe_level_cell_count());
+ probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
set_probe_data(probe_data);
#ifdef TOOLS_ENABLED
@@ -491,46 +491,46 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
notify_property_list_changed(); //bake property may have changed
}
-void GIProbe::_debug_bake() {
+void VoxelGI::_debug_bake() {
bake(nullptr, true);
}
-AABB GIProbe::get_aabb() const {
+AABB VoxelGI::get_aabb() const {
return AABB(-extents, extents * 2);
}
-Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
+Vector<Face3> VoxelGI::get_faces(uint32_t p_usage_flags) const {
return Vector<Face3>();
}
-TypedArray<String> GIProbe::get_configuration_warnings() const {
+TypedArray<String> VoxelGI::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (RenderingServer::get_singleton()->is_low_end()) {
- warnings.push_back(TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."));
+ warnings.push_back(TTR("VoxelGIs are not supported by the GLES2 video driver.\nUse a LightmapGI instead."));
} else if (probe_data.is_null()) {
- warnings.push_back(TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI."));
+ warnings.push_back(TTR("No VoxelGI data set, so this node is disabled. Bake static objects to enable GI."));
}
return warnings;
}
-void GIProbe::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_probe_data", "data"), &GIProbe::set_probe_data);
- ClassDB::bind_method(D_METHOD("get_probe_data"), &GIProbe::get_probe_data);
+void VoxelGI::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_probe_data", "data"), &VoxelGI::set_probe_data);
+ ClassDB::bind_method(D_METHOD("get_probe_data"), &VoxelGI::get_probe_data);
- ClassDB::bind_method(D_METHOD("set_subdiv", "subdiv"), &GIProbe::set_subdiv);
- ClassDB::bind_method(D_METHOD("get_subdiv"), &GIProbe::get_subdiv);
+ ClassDB::bind_method(D_METHOD("set_subdiv", "subdiv"), &VoxelGI::set_subdiv);
+ ClassDB::bind_method(D_METHOD("get_subdiv"), &VoxelGI::get_subdiv);
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GIProbe::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &GIProbe::get_extents);
+ ClassDB::bind_method(D_METHOD("set_extents", "extents"), &VoxelGI::set_extents);
+ ClassDB::bind_method(D_METHOD("get_extents"), &VoxelGI::get_extents);
- ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &GIProbe::bake, DEFVAL(Variant()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("debug_bake"), &GIProbe::_debug_bake);
+ ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &VoxelGI::bake, DEFVAL(Variant()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("debug_bake"), &VoxelGI::_debug_bake);
ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "GIProbeData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "VoxelGIData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data");
BIND_ENUM_CONSTANT(SUBDIV_64);
BIND_ENUM_CONSTANT(SUBDIV_128);
@@ -539,11 +539,11 @@ void GIProbe::_bind_methods() {
BIND_ENUM_CONSTANT(SUBDIV_MAX);
}
-GIProbe::GIProbe() {
- gi_probe = RS::get_singleton()->gi_probe_create();
+VoxelGI::VoxelGI() {
+ voxel_gi = RS::get_singleton()->voxel_gi_create();
set_disable_scale(true);
}
-GIProbe::~GIProbe() {
- RS::get_singleton()->free(gi_probe);
+VoxelGI::~VoxelGI() {
+ RS::get_singleton()->free(voxel_gi);
}
diff --git a/scene/3d/gi_probe.h b/scene/3d/voxel_gi.h
index dac7dd3e17..5b9ee28b33 100644
--- a/scene/3d/gi_probe.h
+++ b/scene/3d/voxel_gi.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gi_probe.h */
+/* voxel_gi.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,21 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GIPROBE_H
-#define GIPROBE_H
+#ifndef VOXEL_GI_H
+#define VOXEL_GI_H
#include "multimesh_instance_3d.h"
#include "scene/3d/visual_instance_3d.h"
-class GIProbeData : public Resource {
- GDCLASS(GIProbeData, Resource);
+class VoxelGIData : public Resource {
+ GDCLASS(VoxelGIData, Resource);
RID probe;
void _set_data(const Dictionary &p_data);
Dictionary _get_data() const;
- Transform to_cell_xform;
+ Transform3D to_cell_xform;
AABB bounds;
Vector3 octree_size;
@@ -62,14 +62,14 @@ protected:
void _validate_property(PropertyInfo &property) const override;
public:
- void 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);
+ void allocate(const Transform3D &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);
AABB get_bounds() const;
Vector3 get_octree_size() const;
Vector<uint8_t> get_octree_cells() const;
Vector<uint8_t> get_data_cells() const;
Vector<uint8_t> get_distance_field() const;
Vector<int> get_level_counts() const;
- Transform get_to_cell_xform() const;
+ Transform3D get_to_cell_xform() const;
void set_dynamic_range(float p_range);
float get_dynamic_range() const;
@@ -103,12 +103,12 @@ public:
virtual RID get_rid() const override;
- GIProbeData();
- ~GIProbeData();
+ VoxelGIData();
+ ~VoxelGIData();
};
-class GIProbe : public VisualInstance3D {
- GDCLASS(GIProbe, VisualInstance3D);
+class VoxelGI : public VisualInstance3D {
+ GDCLASS(VoxelGI, VisualInstance3D);
public:
enum Subdiv {
@@ -125,9 +125,9 @@ public:
typedef void (*BakeEndFunc)();
private:
- Ref<GIProbeData> probe_data;
+ Ref<VoxelGIData> probe_data;
- RID gi_probe;
+ RID voxel_gi;
Subdiv subdiv = SUBDIV_128;
Vector3 extents = Vector3(10, 10, 10);
@@ -136,7 +136,7 @@ private:
Ref<Material> override_material;
Vector<Ref<Material>> instance_materials;
Ref<Mesh> mesh;
- Transform local_xform;
+ Transform3D local_xform;
};
void _find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes);
@@ -150,8 +150,8 @@ public:
static BakeStepFunc bake_step_function;
static BakeEndFunc bake_end_function;
- void set_probe_data(const Ref<GIProbeData> &p_data);
- Ref<GIProbeData> get_probe_data() const;
+ void set_probe_data(const Ref<VoxelGIData> &p_data);
+ Ref<VoxelGIData> get_probe_data() const;
void set_subdiv(Subdiv p_subdiv);
Subdiv get_subdiv() const;
@@ -167,10 +167,10 @@ public:
TypedArray<String> get_configuration_warnings() const override;
- GIProbe();
- ~GIProbe();
+ VoxelGI();
+ ~VoxelGI();
};
-VARIANT_ENUM_CAST(GIProbe::Subdiv)
+VARIANT_ENUM_CAST(VoxelGI::Subdiv)
-#endif // GIPROBE_H
+#endif // VOXEL_GI_H
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 1b9ce0201f..ee0c3fe9b6 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -378,7 +378,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 Transform3D &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++) {
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
continue; //only triangles
@@ -647,11 +647,11 @@ void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) {
po2_bounds.size[i] = po2_bounds.size[longest_axis];
}
- Transform to_bounds;
+ Transform3D to_bounds;
to_bounds.basis.scale(Vector3(po2_bounds.size[longest_axis], po2_bounds.size[longest_axis], po2_bounds.size[longest_axis]));
to_bounds.origin = po2_bounds.position;
- Transform to_grid;
+ Transform3D to_grid;
to_grid.basis.scale(Vector3(axis_cell_size[longest_axis], axis_cell_size[longest_axis], axis_cell_size[longest_axis]));
to_cell_space = to_grid * to_bounds.affine_inverse();
@@ -668,19 +668,19 @@ void Voxelizer::end_bake() {
//create the data for visual server
-int Voxelizer::get_gi_probe_octree_depth() const {
+int Voxelizer::get_voxel_gi_octree_depth() const {
return cell_subdiv;
}
-Vector3i Voxelizer::get_giprobe_octree_size() const {
+Vector3i Voxelizer::get_voxel_gi_octree_size() const {
return Vector3i(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]);
}
-int Voxelizer::get_giprobe_cell_count() const {
+int Voxelizer::get_voxel_gi_cell_count() const {
return bake_cells.size();
}
-Vector<uint8_t> Voxelizer::get_giprobe_octree_cells() const {
+Vector<uint8_t> Voxelizer::get_voxel_gi_octree_cells() const {
Vector<uint8_t> data;
data.resize((8 * 4) * bake_cells.size()); //8 uint32t values
{
@@ -700,7 +700,7 @@ Vector<uint8_t> Voxelizer::get_giprobe_octree_cells() const {
return data;
}
-Vector<uint8_t> Voxelizer::get_giprobe_data_cells() const {
+Vector<uint8_t> Voxelizer::get_voxel_gi_data_cells() const {
Vector<uint8_t> data;
data.resize((4 * 4) * bake_cells.size()); //8 uint32t values
{
@@ -755,7 +755,7 @@ Vector<uint8_t> Voxelizer::get_giprobe_data_cells() const {
return data;
}
-Vector<int> Voxelizer::get_giprobe_level_cell_count() const {
+Vector<int> Voxelizer::get_voxel_gi_level_cell_count() const {
uint32_t cell_count = bake_cells.size();
const Cell *cells = bake_cells.ptr();
Vector<int> level_count;
@@ -819,7 +819,7 @@ static void edt(float *f, int stride, int n) {
#undef square
Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
- Vector3i octree_size = get_giprobe_octree_size();
+ Vector3i octree_size = get_voxel_gi_octree_size();
uint32_t float_count = octree_size.x * octree_size.y * octree_size.z;
float *work_memory = memnew_arr(float, float_count);
@@ -891,7 +891,7 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx) {
if (p_level == cell_subdiv - 1) {
Vector3 center = p_aabb.position + p_aabb.size * 0.5;
- Transform xform;
+ Transform3D xform;
xform.origin = center;
xform.basis.scale(p_aabb.size * 0.5);
p_multimesh->set_instance_transform(idx, xform);
@@ -1002,7 +1002,7 @@ Ref<MultiMesh> Voxelizer::create_debug_multimesh() {
return mm;
}
-Transform Voxelizer::get_to_cell_space_xform() const {
+Transform3D Voxelizer::get_to_cell_space_xform() const {
return to_cell_space;
}
diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h
index 87f949e7db..e500d2d4c3 100644
--- a/scene/3d/voxelizer.h
+++ b/scene/3d/voxelizer.h
@@ -93,7 +93,7 @@ private:
AABB po2_bounds;
int axis_cell_size[3] = {};
- Transform to_cell_space;
+ Transform3D to_cell_space;
int color_scan_cell_width = 4;
int bake_texture_size = 128;
@@ -114,20 +114,20 @@ 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 Transform3D &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;
- Vector3i get_giprobe_octree_size() const;
- int get_giprobe_cell_count() const;
- Vector<uint8_t> get_giprobe_octree_cells() const;
- Vector<uint8_t> get_giprobe_data_cells() const;
- Vector<int> get_giprobe_level_cell_count() const;
+ int get_voxel_gi_octree_depth() const;
+ Vector3i get_voxel_gi_octree_size() const;
+ int get_voxel_gi_cell_count() const;
+ Vector<uint8_t> get_voxel_gi_octree_cells() const;
+ Vector<uint8_t> get_voxel_gi_data_cells() const;
+ Vector<int> get_voxel_gi_level_cell_count() const;
Vector<uint8_t> get_sdf_3d_image() const;
Ref<MultiMesh> create_debug_multimesh();
- Transform get_to_cell_space_xform() const;
+ Transform3D get_to_cell_space_xform() const;
Voxelizer();
};
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index b5037f9be7..4f2c816934 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -86,7 +86,8 @@ Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
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_near(), get_far());
+ // Just use the first view, if multiple views are supported this function has no good result
+ CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
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_near()).normalized();
@@ -108,7 +109,8 @@ Point2 XRCamera3D::unproject_position(const Vector3 &p_pos) const {
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far());
+ // Just use the first view, if multiple views are supported this function has no good result
+ CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
Plane p(get_camera_transform().xform_inv(p_pos), 1.0);
@@ -137,7 +139,8 @@ Vector3 XRCamera3D::project_position(const Point2 &p_point, float p_z_depth) con
Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far());
+ // Just use the first view, if multiple views are supported this function has no good result
+ CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
Vector2 vp_he = cm.get_viewport_half_extents();
@@ -165,7 +168,8 @@ Vector<Plane> XRCamera3D::get_frustum() const {
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_near(), get_far());
+ // TODO Just use the first view for now, this is mostly for debugging so we may look into using our combined projection here.
+ CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far());
return cm.get_projection_planes(get_camera_transform());
};
@@ -397,7 +401,7 @@ void XRAnchor3D::_notification(int p_what) {
is_active = false;
} else {
is_active = true;
- Transform transform;
+ Transform3D transform;
// we'll need our world_scale
real_t world_scale = xr_server->get_world_scale();
@@ -493,7 +497,7 @@ TypedArray<String> XRAnchor3D::get_configuration_warnings() const {
};
Plane XRAnchor3D::get_plane() const {
- Vector3 location = get_translation();
+ Vector3 location = get_position();
Basis orientation = get_transform().basis;
Plane plane(location, orientation.get_axis(1).normalized());
@@ -516,6 +520,11 @@ TypedArray<String> XROrigin3D::get_configuration_warnings() const {
}
}
+ bool xr_enabled = GLOBAL_GET("rendering/xr/enabled");
+ if (!xr_enabled) {
+ warnings.push_back(TTR("XR is not enabled in rendering project settings. Stereoscopic output is not supported unless this is enabled."));
+ }
+
return warnings;
};
@@ -571,7 +580,7 @@ void XROrigin3D::_notification(int p_what) {
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());
+ Transform3D t = xr_interface->get_camera_transform();
// now apply this to our camera
tracked_camera->set_transform(t);
diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp
index 689acdd57b..b8980fd56b 100644
--- a/scene/animation/animation_cache.cpp
+++ b/scene/animation/animation_cache.cpp
@@ -80,10 +80,11 @@ void AnimationCache::_update_cache() {
Ref<Resource> res;
- if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM) {
+ if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D) {
+#ifndef _3D_DISABLED
if (np.get_subname_count() > 1) {
path_cache.push_back(Path());
- ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM, "Transform tracks can't have a subpath '" + np + "'.");
+ ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D, "Transform tracks can't have a subpath '" + np + "'.");
}
Node3D *sp = Object::cast_to<Node3D>(node);
@@ -113,8 +114,8 @@ void AnimationCache::_update_cache() {
path.skeleton = sk;
}
- path.spatial = sp;
-
+ path.node_3d = sp;
+#endif // _3D_DISABLED
} else {
if (np.get_subname_count() > 0) {
RES res2;
@@ -167,7 +168,7 @@ void AnimationCache::_update_cache() {
cache_valid = true;
}
-void AnimationCache::set_track_transform(int p_idx, const Transform &p_transform) {
+void AnimationCache::set_track_transform(int p_idx, const Transform3D &p_transform) {
if (cache_dirty) {
_update_cache();
}
@@ -179,14 +180,16 @@ void AnimationCache::set_track_transform(int p_idx, const Transform &p_transform
return;
}
+#ifndef _3D_DISABLED
ERR_FAIL_COND(!p.node);
- ERR_FAIL_COND(!p.spatial);
+ ERR_FAIL_COND(!p.node_3d);
if (p.skeleton) {
p.skeleton->set_bone_pose(p.bone_idx, p_transform);
} else {
- p.spatial->set_transform(p_transform);
+ p.node_3d->set_transform(p_transform);
}
+#endif // _3D_DISABLED
}
void AnimationCache::set_track_value(int p_idx, const Variant &p_value) {
@@ -231,11 +234,11 @@ void AnimationCache::set_all(float p_time, float p_delta) {
int tc = animation->get_track_count();
for (int i = 0; i < tc; i++) {
switch (animation->track_get_type(i)) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
Vector3 loc, scale;
- Quat rot;
+ Quaternion rot;
animation->transform_track_interpolate(i, p_time, &loc, &rot, &scale);
- Transform tr(Basis(rot), loc);
+ Transform3D tr(Basis(rot), loc);
tr.basis.scale(scale);
set_track_transform(i, tr);
diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h
index 07c9d09ae0..c856e644f7 100644
--- a/scene/animation/animation_cache.h
+++ b/scene/animation/animation_cache.h
@@ -40,9 +40,11 @@ class AnimationCache : public Object {
struct Path {
RES resource;
Object *object = nullptr;
- Skeleton3D *skeleton = nullptr; // haxor
+#ifndef _3D_DISABLED
+ Skeleton3D *skeleton = nullptr;
+ Node3D *node_3d = nullptr;
+#endif // _3D_DISABLED
Node *node = nullptr;
- Node3D *spatial = nullptr;
int bone_idx = -1;
Vector<StringName> subpath;
@@ -67,7 +69,7 @@ protected:
static void _bind_methods();
public:
- void set_track_transform(int p_idx, const Transform &p_transform);
+ void set_track_transform(int p_idx, const Transform3D &p_transform);
void set_track_value(int p_idx, const Variant &p_value);
void call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 246fff6d57..65918a2989 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -115,7 +115,7 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &AnimationNodeStateMachineTransition::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &AnimationNodeStateMachineTransition::get_priority);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,AtEnd"), "set_switch_mode", "get_switch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_advance"), "set_auto_advance", "has_auto_advance");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "advance_condition"), "set_advance_condition", "get_advance_condition");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01"), "set_xfade_time", "get_xfade_time");
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 0c1798a876..2d565fc47a 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -252,6 +252,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
ObjectID id = resource.is_valid() ? resource->get_instance_id() : child->get_instance_id();
int bone_idx = -1;
+#ifndef _3D_DISABLED
if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton3D>(child)) {
Skeleton3D *sk = Object::cast_to<Skeleton3D>(child);
bone_idx = sk->find_bone(a->track_get_path(i).get_subname(0));
@@ -259,6 +260,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
continue;
}
}
+#endif // _3D_DISABLED
{
if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) {
@@ -279,11 +281,12 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
p_anim->node_cache[i]->node = child;
p_anim->node_cache[i]->resource = resource;
p_anim->node_cache[i]->node_2d = Object::cast_to<Node2D>(child);
- if (a->track_get_type(i) == Animation::TYPE_TRANSFORM) {
+#ifndef _3D_DISABLED
+ if (a->track_get_type(i) == Animation::TYPE_TRANSFORM3D) {
// special cases and caches for transform tracks
- // cache spatial
- p_anim->node_cache[i]->spatial = Object::cast_to<Node3D>(child);
+ // cache node_3d
+ p_anim->node_cache[i]->node_3d = Object::cast_to<Node3D>(child);
// cache skeleton
p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton3D>(child);
if (p_anim->node_cache[i]->skeleton) {
@@ -294,7 +297,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
if (p_anim->node_cache[i]->bone_idx < 0) {
// broken track (nonexistent bone)
p_anim->node_cache[i]->skeleton = nullptr;
- p_anim->node_cache[i]->spatial = nullptr;
+ p_anim->node_cache[i]->node_3d = nullptr;
ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0);
}
} else {
@@ -303,6 +306,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
}
}
}
+#endif // _3D_DISABLED
if (a->track_get_type(i) == Animation::TYPE_VALUE) {
if (!p_anim->node_cache[i]->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
@@ -366,13 +370,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
}
switch (a->track_get_type(i)) {
- case Animation::TYPE_TRANSFORM: {
- if (!nc->spatial) {
+ case Animation::TYPE_TRANSFORM3D: {
+#ifndef _3D_DISABLED
+ if (!nc->node_3d) {
continue;
}
Vector3 loc;
- Quat rot;
+ Quaternion rot;
Vector3 scale;
Error err = a->transform_track_interpolate(i, p_time, &loc, &rot, &scale);
@@ -395,7 +400,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
nc->rot_accum = nc->rot_accum.slerp(rot, p_interp);
nc->scale_accum = nc->scale_accum.lerp(scale, p_interp);
}
-
+#endif // _3D_DISABLED
} break;
case Animation::TYPE_VALUE: {
if (!nc->node) {
@@ -838,20 +843,21 @@ void AnimationPlayer::_animation_process2(float p_delta, bool p_started) {
void AnimationPlayer::_animation_update_transforms() {
{
- Transform t;
+ Transform3D t;
for (int i = 0; i < cache_update_size; i++) {
TrackNodeCache *nc = cache_update[i];
ERR_CONTINUE(nc->accum_pass != accum_pass);
t.origin = nc->loc_accum;
- t.basis.set_quat_scale(nc->rot_accum, nc->scale_accum);
+ t.basis.set_quaternion_scale(nc->rot_accum, nc->scale_accum);
+#ifndef _3D_DISABLED
if (nc->skeleton && nc->bone_idx >= 0) {
nc->skeleton->set_bone_pose(nc->bone_idx, t);
-
- } else if (nc->spatial) {
- nc->spatial->set_transform(t);
+ } else if (nc->node_3d) {
+ nc->node_3d->set_transform(t);
}
+#endif // _3D_DISABLED
}
}
@@ -1523,11 +1529,11 @@ Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values(Node *p_root_o
entry.value = nc->skeleton->get_bone_pose(nc->bone_idx);
backup->entries.push_back(entry);
} else {
- if (nc->spatial) {
+ if (nc->node_3d) {
AnimatedValuesBackup::Entry entry;
- entry.object = nc->spatial;
+ entry.object = nc->node_3d;
entry.subpath.push_back("transform");
- entry.value = nc->spatial->get_transform();
+ entry.value = nc->node_3d->get_transform();
entry.bone_idx = -1;
backup->entries.push_back(entry);
} else {
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 2a1821c215..7cd9de1fa1 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -37,8 +37,8 @@
#include "scene/resources/animation.h"
#ifdef TOOLS_ENABLED
-class AnimatedValuesBackup : public Reference {
- GDCLASS(AnimatedValuesBackup, Reference);
+class AnimatedValuesBackup : public RefCounted {
+ GDCLASS(AnimatedValuesBackup, RefCounted);
struct Entry {
Object *object = nullptr;
@@ -93,14 +93,16 @@ private:
uint32_t id = 0;
RES resource;
Node *node = nullptr;
- Node3D *spatial = nullptr;
Node2D *node_2d = nullptr;
+#ifndef _3D_DISABLED
+ Node3D *node_3d = nullptr;
Skeleton3D *skeleton = nullptr;
+#endif // _3D_DISABLED
int bone_idx = -1;
// accumulated transforms
Vector3 loc_accum;
- Quat rot_accum;
+ Quaternion rot_accum;
Vector3 scale_accum;
uint64_t accum_pass = 0;
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 44f2d38a84..6fac70bdd5 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -37,7 +37,7 @@
void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
if (get_script_instance()) {
- Array parameters = get_script_instance()->call("get_parameter_list");
+ Array parameters = get_script_instance()->call("_get_parameter_list");
for (int i = 0; i < parameters.size(); i++) {
Dictionary d = parameters[i];
ERR_CONTINUE(d.is_empty());
@@ -48,7 +48,7 @@ void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {
if (get_script_instance()) {
- return get_script_instance()->call("get_parameter_default_value", p_parameter);
+ return get_script_instance()->call("_get_parameter_default_value", p_parameter);
}
return Variant();
}
@@ -73,7 +73,7 @@ Variant AnimationNode::get_parameter(const StringName &p_name) const {
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
if (get_script_instance()) {
- Dictionary cn = get_script_instance()->call("get_child_nodes");
+ Dictionary cn = get_script_instance()->call("_get_child_nodes");
List<Variant> keys;
cn.get_key_list(&keys);
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
@@ -299,7 +299,7 @@ String AnimationNode::get_input_name(int p_input) {
String AnimationNode::get_caption() const {
if (get_script_instance()) {
- return get_script_instance()->call("get_caption");
+ return get_script_instance()->call("_get_caption");
}
return "Node";
@@ -330,7 +330,7 @@ void AnimationNode::remove_input(int p_index) {
float AnimationNode::process(float p_time, bool p_seek) {
if (get_script_instance()) {
- return get_script_instance()->call("process", p_time, p_seek);
+ return get_script_instance()->call("_process", p_time, p_seek);
}
return 0;
@@ -357,6 +357,10 @@ bool AnimationNode::is_path_filtered(const NodePath &p_path) const {
}
bool AnimationNode::has_filter() const {
+ if (get_script_instance()) {
+ return get_script_instance()->call("_has_filter");
+ }
+
return false;
}
@@ -387,7 +391,7 @@ void AnimationNode::_validate_property(PropertyInfo &property) const {
Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
if (get_script_instance()) {
- return get_script_instance()->call("get_child_by_name", p_name);
+ return get_script_instance()->call("_get_child_by_name", p_name);
}
return Ref<AnimationNode>();
}
@@ -418,17 +422,17 @@ void AnimationNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_filter_enabled", "is_filter_enabled");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters");
- BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "get_child_nodes"));
- BIND_VMETHOD(MethodInfo(Variant::ARRAY, "get_parameter_list"));
- BIND_VMETHOD(MethodInfo(Variant::OBJECT, "get_child_by_name", PropertyInfo(Variant::STRING, "name")));
+ BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "_get_child_nodes"));
+ BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_parameter_list"));
+ BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_get_child_by_name", PropertyInfo(Variant::STRING, "name")));
{
- MethodInfo mi = MethodInfo(Variant::NIL, "get_parameter_default_value", PropertyInfo(Variant::STRING_NAME, "name"));
+ MethodInfo mi = MethodInfo(Variant::NIL, "_get_parameter_default_value", PropertyInfo(Variant::STRING_NAME, "name"));
mi.return_val.usage = PROPERTY_USAGE_NIL_IS_VARIANT;
BIND_VMETHOD(mi);
}
- BIND_VMETHOD(MethodInfo("process", PropertyInfo(Variant::FLOAT, "time"), PropertyInfo(Variant::BOOL, "seek")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "get_caption"));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_filter"));
+ BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::FLOAT, "time"), PropertyInfo(Variant::BOOL, "seek")));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_caption"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_has_filter"));
ADD_SIGNAL(MethodInfo("removed_from_graph"));
@@ -581,34 +585,35 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
track = track_value;
} break;
- case Animation::TYPE_TRANSFORM: {
- Node3D *spatial = Object::cast_to<Node3D>(child);
+ case Animation::TYPE_TRANSFORM3D: {
+#ifndef _3D_DISABLED
+ Node3D *node_3d = Object::cast_to<Node3D>(child);
- if (!spatial) {
- ERR_PRINT("AnimationTree: '" + String(E->get()) + "', transform track does not point to spatial: '" + String(path) + "'");
+ if (!node_3d) {
+ ERR_PRINT("AnimationTree: '" + String(E->get()) + "', transform track does not point to Node3D: '" + String(path) + "'");
continue;
}
TrackCacheTransform *track_xform = memnew(TrackCacheTransform);
- track_xform->spatial = spatial;
+ track_xform->node_3d = node_3d;
track_xform->skeleton = nullptr;
track_xform->bone_idx = -1;
- if (path.get_subname_count() == 1 && Object::cast_to<Skeleton3D>(spatial)) {
- Skeleton3D *sk = Object::cast_to<Skeleton3D>(spatial);
+ if (path.get_subname_count() == 1 && Object::cast_to<Skeleton3D>(node_3d)) {
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d);
+ track_xform->skeleton = sk;
int bone_idx = sk->find_bone(path.get_subname(0));
if (bone_idx != -1) {
- track_xform->skeleton = sk;
track_xform->bone_idx = bone_idx;
}
}
- track_xform->object = spatial;
+ track_xform->object = node_3d;
track_xform->object_id = track_xform->object->get_instance_id();
track = track_xform;
-
+#endif // _3D_DISABLED
} break;
case Animation::TYPE_METHOD: {
TrackCacheMethod *track_method = memnew(TrackCacheMethod);
@@ -718,7 +723,7 @@ void AnimationTree::_process_graph(float p_delta) {
//check all tracks, see if they need modification
- root_motion_transform = Transform();
+ root_motion_transform = Transform3D();
if (!root.is_valid()) {
ERR_PRINT("AnimationTree: root AnimationNode is not set, disabling playback.");
@@ -844,14 +849,15 @@ void AnimationTree::_process_graph(float p_delta) {
}
switch (track->type) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
+#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion) {
if (t->process_pass != process_pass) {
t->process_pass = process_pass;
t->loc = Vector3();
- t->rot = Quat();
+ t->rot = Quaternion();
t->rot_blend_accum = 0;
t->scale = Vector3(1, 1, 1);
}
@@ -866,7 +872,7 @@ void AnimationTree::_process_graph(float p_delta) {
}
Vector3 loc[2];
- Quat rot[2];
+ Quaternion rot[2];
Vector3 scale[2];
if (prev_time > time) {
@@ -879,7 +885,7 @@ void AnimationTree::_process_graph(float p_delta) {
t->loc += (loc[1] - loc[0]) * blend;
t->scale += (scale[1] - scale[0]) * blend;
- Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
+ Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
t->rot = (t->rot * q).normalized();
prev_time = 0;
@@ -894,14 +900,14 @@ void AnimationTree::_process_graph(float p_delta) {
t->loc += (loc[1] - loc[0]) * blend;
t->scale += (scale[1] - scale[0]) * blend;
- Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
+ Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
t->rot = (t->rot * q).normalized();
prev_time = 0;
} else {
Vector3 loc;
- Quat rot;
+ Quaternion rot;
Vector3 scale;
Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale);
@@ -930,7 +936,7 @@ void AnimationTree::_process_graph(float p_delta) {
}
t->scale = t->scale.lerp(scale, blend);
}
-
+#endif // _3D_DISABLED
} break;
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
@@ -1188,13 +1194,14 @@ void AnimationTree::_process_graph(float p_delta) {
}
switch (track->type) {
- case Animation::TYPE_TRANSFORM: {
+ case Animation::TYPE_TRANSFORM3D: {
+#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
- Transform xform;
+ Transform3D xform;
xform.origin = t->loc;
- xform.basis.set_quat_scale(t->rot, t->scale);
+ xform.basis.set_quaternion_scale(t->rot, t->scale);
if (t->root_motion) {
root_motion_transform = xform;
@@ -1205,10 +1212,10 @@ void AnimationTree::_process_graph(float p_delta) {
} else if (t->skeleton && t->bone_idx >= 0) {
t->skeleton->set_bone_pose(t->bone_idx, xform);
- } else {
- t->spatial->set_transform(xform);
+ } else if (!t->skeleton) {
+ t->node_3d->set_transform(xform);
}
-
+#endif // _3D_DISABLED
} break;
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
@@ -1311,7 +1318,7 @@ NodePath AnimationTree::get_root_motion_track() const {
return root_motion_track;
}
-Transform AnimationTree::get_root_motion_transform() const {
+Transform3D AnimationTree::get_root_motion_transform() const {
return root_motion_transform;
}
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 700ff1cb5b..60e0c7200a 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -184,16 +184,18 @@ private:
};
struct TrackCacheTransform : public TrackCache {
- Node3D *spatial = nullptr;
+#ifndef _3D_DISABLED
+ Node3D *node_3d = nullptr;
Skeleton3D *skeleton = nullptr;
+#endif // _3D_DISABLED
int bone_idx = -1;
Vector3 loc;
- Quat rot;
+ Quaternion rot;
float rot_blend_accum = 0.0;
Vector3 scale;
TrackCacheTransform() {
- type = Animation::TYPE_TRANSFORM;
+ type = Animation::TYPE_TRANSFORM3D;
}
};
@@ -257,7 +259,7 @@ private:
bool started = true;
NodePath root_motion_track;
- Transform root_motion_transform;
+ Transform3D root_motion_transform;
friend class AnimationNode;
bool properties_dirty = true;
@@ -308,7 +310,7 @@ public:
void set_root_motion_track(const NodePath &p_track);
NodePath get_root_motion_track() const;
- Transform get_root_motion_transform() const;
+ Transform3D get_root_motion_transform() const;
float get_connection_activity(const StringName &p_path, int p_connection) const;
void advance(float p_time);
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index 9ee1f32581..b963cf5702 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -82,7 +82,7 @@ void RootMotionView::_notification(int p_what) {
}
if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
- Transform transform;
+ Transform3D transform;
if (has_node(path)) {
Node *node = get_node(path);
@@ -103,7 +103,7 @@ void RootMotionView::_notification(int p_what) {
}
}
- if (!first && transform == Transform()) {
+ if (!first && transform == Transform3D()) {
return;
}
diff --git a/scene/animation/root_motion_view.h b/scene/animation/root_motion_view.h
index afcff6137f..4cd3c7b443 100644
--- a/scene/animation/root_motion_view.h
+++ b/scene/animation/root_motion_view.h
@@ -46,7 +46,7 @@ public:
bool first = true;
bool zero_y = true;
- Transform accumulated;
+ Transform3D accumulated;
private:
void _notification(int p_what);
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 2030808724..b4e597f75e 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -519,11 +519,11 @@ Variant Tween::_run_equation(InterpolateData &p_data) {
result = r;
} break;
- case Variant::QUAT: {
+ case Variant::QUATERNION: {
// Get the quaternian for the initial and delta values
- Quat i = initial_val;
- Quat d = delta_val;
- Quat r;
+ Quaternion i = initial_val;
+ Quaternion d = delta_val;
+ Quaternion r;
// Execute the equation on the quaternian values and mutate the r quaternian
// This uses the custom APPLY_EQUATION macro defined above
@@ -571,11 +571,11 @@ Variant Tween::_run_equation(InterpolateData &p_data) {
result = r;
} break;
- case Variant::TRANSFORM: {
+ case Variant::TRANSFORM3D: {
// Get the transforms for the initial and delta values
- Transform i = initial_val;
- Transform d = delta_val;
- Transform r;
+ Transform3D i = initial_val;
+ Transform3D d = delta_val;
+ Transform3D r;
// Execute the equation for each of the transforms and their origin and mutate the r transform
// This uses the custom APPLY_EQUATION macro defined above
@@ -1202,9 +1202,9 @@ bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final
delta_val = d;
} break;
- case Variant::QUAT:
+ case Variant::QUATERNION:
// Convert to quaternianls and find the delta
- delta_val = final_val.operator Quat() - initial_val.operator Quat();
+ delta_val = final_val.operator Quaternion() - initial_val.operator Quaternion();
break;
case Variant::AABB: {
@@ -1229,11 +1229,11 @@ bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final
f.elements[2][2] - i.elements[2][2]);
} break;
- case Variant::TRANSFORM: {
+ case Variant::TRANSFORM3D: {
// Build a new transform which is the difference between the initial and final values
- Transform i = initial_val;
- Transform f = final_val;
- Transform d;
+ Transform3D i = initial_val;
+ Transform3D f = final_val;
+ Transform3D d;
d.set(f.basis.elements[0][0] - i.basis.elements[0][0],
f.basis.elements[0][1] - i.basis.elements[0][1],
f.basis.elements[0][2] - i.basis.elements[0][2],
@@ -1266,10 +1266,10 @@ bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final
Variant::RECT2,
Variant::VECTOR3,
Variant::TRANSFORM2D,
- Variant::QUAT,
+ Variant::QUATERNION,
Variant::AABB,
Variant::BASIS,
- Variant::TRANSFORM,
+ Variant::TRANSFORM3D,
Variant::COLOR,
};
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index a1d4adcd41..11ce9b2ddc 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -98,7 +98,7 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra
} else if (p_msg == "override_camera_3D:transform") {
ERR_FAIL_COND_V(p_args.size() < 5, ERR_INVALID_DATA);
- Transform transform = p_args[0];
+ Transform3D transform = p_args[0];
bool is_perspective = p_args[1];
float size_or_fov = p_args[2];
float near = p_args[3];
diff --git a/scene/gui/aspect_ratio_container.cpp b/scene/gui/aspect_ratio_container.cpp
index c7f6c0e2da..fb6fa9dec9 100644
--- a/scene/gui/aspect_ratio_container.cpp
+++ b/scene/gui/aspect_ratio_container.cpp
@@ -155,7 +155,7 @@ void AspectRatioContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_alignment_vertical"), &AspectRatioContainer::get_alignment_vertical);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ratio"), "set_ratio", "get_ratio");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Width controls height,Height controls width,Fit,Cover"), "set_stretch_mode", "get_stretch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Width Controls Height,Height Controls Width,Fit,Cover"), "set_stretch_mode", "get_stretch_mode");
ADD_GROUP("Alignment", "alignment_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment_horizontal", PROPERTY_HINT_ENUM, "Begin,Center,End"), "set_alignment_horizontal", "get_alignment_horizontal");
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 826fd0189b..66155958cf 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -98,17 +98,14 @@ void BaseButton::_notification(int p_what) {
}
if (p_what == NOTIFICATION_FOCUS_ENTER) {
- status.hovering = true;
update();
}
if (p_what == NOTIFICATION_FOCUS_EXIT) {
if (status.press_attempt) {
status.press_attempt = false;
- status.hovering = false;
update();
} else if (status.hovering) {
- status.hovering = false;
update();
}
}
@@ -155,6 +152,9 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
}
status.pressed = !status.pressed;
_unpress_group();
+ if (button_group.is_valid()) {
+ button_group->emit_signal("pressed", this);
+ }
_toggled(status.pressed);
_pressed();
}
@@ -172,10 +172,9 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
status.hovering = false;
}
}
- // pressed state should be correct with button_up signal
- emit_signal("button_up");
status.press_attempt = false;
status.pressing_inside = false;
+ emit_signal("button_up");
}
update();
@@ -218,6 +217,9 @@ void BaseButton::set_pressed(bool p_pressed) {
if (p_pressed) {
_unpress_group();
+ if (button_group.is_valid()) {
+ button_group->emit_signal("pressed", this);
+ }
}
_toggled(status.pressed);
@@ -487,6 +489,7 @@ BaseButton *ButtonGroup::get_pressed_button() {
void ButtonGroup::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_pressed_button"), &ButtonGroup::get_pressed_button);
ClassDB::bind_method(D_METHOD("get_buttons"), &ButtonGroup::_get_buttons);
+ ADD_SIGNAL(MethodInfo("pressed", PropertyInfo(Variant::OBJECT, "button")));
}
ButtonGroup::ButtonGroup() {
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index b0bcde8865..c0df5271b4 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -533,7 +533,7 @@ void Button::_bind_methods() {
BIND_ENUM_CONSTANT(ALIGN_RIGHT);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_button_icon", "get_button_icon");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 28a0ea0100..5b720945b8 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -30,6 +30,18 @@
#include "code_edit.h"
+#include "core/os/keyboard.h"
+#include "core/string/string_builder.h"
+#include "core/string/ustring.h"
+
+static bool _is_whitespace(char32_t c) {
+ return c == '\t' || c == ' ';
+}
+
+static bool _is_char(char32_t c) {
+ return !is_symbol(c);
+}
+
void CodeEdit::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED:
@@ -52,12 +64,379 @@ void CodeEdit::_notification(int p_what) {
folding_color = get_theme_color("code_folding_color");
can_fold_icon = get_theme_icon("can_fold");
folded_icon = get_theme_icon("folded");
+
+ code_completion_max_width = get_theme_constant("completion_max_width") * cache.font->get_char_size('x').x;
+ code_completion_max_lines = get_theme_constant("completion_lines");
+ code_completion_scroll_width = get_theme_constant("completion_scroll_width");
+ code_completion_scroll_color = get_theme_color("completion_scroll_color");
+ code_completion_background_color = get_theme_color("completion_background_color");
+ code_completion_selected_color = get_theme_color("completion_selected_color");
+ code_completion_existing_color = get_theme_color("completion_existing_color");
} break;
case NOTIFICATION_DRAW: {
+ RID ci = get_canvas_item();
+ const bool caret_visible = is_caret_visible();
+ const bool rtl = is_layout_rtl();
+ const int row_height = get_row_height();
+
+ bool code_completion_below = false;
+ if (caret_visible && code_completion_active && code_completion_options.size() > 0) {
+ Ref<StyleBox> csb = get_theme_stylebox("completion");
+
+ const int code_completion_options_count = code_completion_options.size();
+ const int lines = MIN(code_completion_options_count, code_completion_max_lines);
+ const int icon_hsep = get_theme_constant("hseparation", "ItemList");
+ const Size2 icon_area_size(row_height, row_height);
+
+ code_completion_rect.size.width = code_completion_longest_line + icon_hsep + icon_area_size.width + 2;
+ code_completion_rect.size.height = lines * row_height;
+
+ const Point2 caret_pos = get_caret_draw_pos();
+ const int total_height = csb->get_minimum_size().y + code_completion_rect.size.height;
+ if (caret_pos.y + row_height + total_height > get_size().height) {
+ code_completion_rect.position.y = (caret_pos.y - total_height - row_height) + cache.line_spacing;
+ } else {
+ code_completion_rect.position.y = caret_pos.y + (cache.line_spacing / 2.0f);
+ code_completion_below = true;
+ }
+
+ const int scroll_width = code_completion_options_count > code_completion_max_lines ? code_completion_scroll_width : 0;
+ const int code_completion_base_width = cache.font->get_string_size(code_completion_base).width;
+ if (caret_pos.x - code_completion_base_width + code_completion_rect.size.width + scroll_width > get_size().width) {
+ code_completion_rect.position.x = get_size().width - code_completion_rect.size.width - scroll_width;
+ } else {
+ code_completion_rect.position.x = caret_pos.x - code_completion_base_width;
+ }
+
+ draw_style_box(csb, Rect2(code_completion_rect.position - csb->get_offset(), code_completion_rect.size + csb->get_minimum_size() + Size2(scroll_width, 0)));
+ if (code_completion_background_color.a > 0.01) {
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(code_completion_rect.position, code_completion_rect.size + Size2(scroll_width, 0)), code_completion_background_color);
+ }
+
+ code_completion_line_ofs = CLAMP(code_completion_current_selected - lines / 2, 0, code_completion_options_count - lines);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(code_completion_rect.position.x, code_completion_rect.position.y + (code_completion_current_selected - code_completion_line_ofs) * row_height), Size2(code_completion_rect.size.width, row_height)), code_completion_selected_color);
+ draw_rect(Rect2(code_completion_rect.position + Vector2(icon_area_size.x + icon_hsep, 0), Size2(MIN(code_completion_base_width, code_completion_rect.size.width - (icon_area_size.x + icon_hsep)), code_completion_rect.size.height)), code_completion_existing_color);
+
+ for (int i = 0; i < lines; i++) {
+ int l = code_completion_line_ofs + i;
+ ERR_CONTINUE(l < 0 || l >= code_completion_options_count);
+
+ Ref<TextLine> tl;
+ tl.instance();
+ tl->add_string(code_completion_options[l].display, cache.font, cache.font_size);
+
+ int yofs = (row_height - tl->get_size().y) / 2;
+ Point2 title_pos(code_completion_rect.position.x, code_completion_rect.position.y + i * row_height + yofs);
+
+ /* Draw completion icon if it is valid. */
+ const Ref<Texture2D> &icon = code_completion_options[l].icon;
+ Rect2 icon_area(code_completion_rect.position.x, code_completion_rect.position.y + i * row_height, icon_area_size.width, icon_area_size.height);
+ if (icon.is_valid()) {
+ Size2 icon_size = icon_area.size * 0.7;
+ icon->draw_rect(ci, Rect2(icon_area.position + (icon_area.size - icon_size) / 2, icon_size));
+ }
+ title_pos.x = icon_area.position.x + icon_area.size.width + icon_hsep;
+
+ tl->set_width(code_completion_rect.size.width - (icon_area_size.x + icon_hsep));
+ if (rtl) {
+ if (code_completion_options[l].default_value.get_type() == Variant::COLOR) {
+ draw_rect(Rect2(Point2(code_completion_rect.position.x, icon_area.position.y), icon_area_size), (Color)code_completion_options[l].default_value);
+ }
+ tl->set_align(HALIGN_RIGHT);
+ } else {
+ if (code_completion_options[l].default_value.get_type() == Variant::COLOR) {
+ draw_rect(Rect2(Point2(code_completion_rect.position.x + code_completion_rect.size.width - icon_area_size.x, icon_area.position.y), icon_area_size), (Color)code_completion_options[l].default_value);
+ }
+ tl->set_align(HALIGN_LEFT);
+ }
+ tl->draw(ci, title_pos, code_completion_options[l].font_color);
+ }
+
+ /* Draw a small scroll rectangle to show a position in the options. */
+ if (scroll_width) {
+ float r = (float)code_completion_max_lines / code_completion_options_count;
+ float o = (float)code_completion_line_ofs / code_completion_options_count;
+ draw_rect(Rect2(code_completion_rect.position.x + code_completion_rect.size.width, code_completion_rect.position.y + o * code_completion_rect.size.y, scroll_width, code_completion_rect.size.y * r), code_completion_scroll_color);
+ }
+ }
+
+ /* Code hint */
+ if (caret_visible && code_hint != "" && (!code_completion_active || (code_completion_below != code_hint_draw_below))) {
+ const Ref<Font> font = cache.font;
+ const int font_height = font->get_height(cache.font_size);
+ Ref<StyleBox> sb = get_theme_stylebox("panel", "TooltipPanel");
+ Color font_color = get_theme_color("font_color", "TooltipLabel");
+
+ Vector<String> code_hint_lines = code_hint.split("\n");
+ int line_count = code_hint_lines.size();
+
+ int max_width = 0;
+ for (int i = 0; i < line_count; i++) {
+ max_width = MAX(max_width, font->get_string_size(code_hint_lines[i], cache.font_size).x);
+ }
+ Size2 minsize = sb->get_minimum_size() + Size2(max_width, line_count * font_height + (cache.line_spacing * line_count - 1));
+
+ int offset = font->get_string_size(code_hint_lines[0].substr(0, code_hint_lines[0].find(String::chr(0xFFFF))), cache.font_size).x;
+ if (code_hint_xpos == -0xFFFF) {
+ code_hint_xpos = get_caret_draw_pos().x - offset;
+ }
+ Point2 hint_ofs = Vector2(code_hint_xpos, get_caret_draw_pos().y);
+ if (code_hint_draw_below) {
+ hint_ofs.y += cache.line_spacing / 2.0f;
+ } else {
+ hint_ofs.y -= (minsize.y + row_height) - cache.line_spacing;
+ }
+
+ draw_style_box(sb, Rect2(hint_ofs, minsize));
+
+ int line_spacing = 0;
+ for (int i = 0; i < line_count; i++) {
+ const String &line = code_hint_lines[i];
+
+ int begin = 0;
+ int end = 0;
+ if (line.find(String::chr(0xFFFF)) != -1) {
+ begin = font->get_string_size(line.substr(0, line.find(String::chr(0xFFFF))), cache.font_size).x;
+ end = font->get_string_size(line.substr(0, line.rfind(String::chr(0xFFFF))), cache.font_size).x;
+ }
+
+ Point2 round_ofs = hint_ofs + sb->get_offset() + Vector2(0, font->get_ascent() + font_height * i + line_spacing);
+ round_ofs = round_ofs.round();
+ draw_string(font, round_ofs, line.replace(String::chr(0xFFFF), ""), HALIGN_LEFT, -1, cache.font_size, font_color);
+ if (end > 0) {
+ Vector2 b = hint_ofs + sb->get_offset() + Vector2(begin, font_height + font_height * i + line_spacing - 1);
+ draw_line(b, b + Vector2(end - begin, 0), font_color);
+ }
+ line_spacing += cache.line_spacing;
+ }
+ }
} break;
}
}
+void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
+ Ref<InputEventMouseButton> mb = p_gui_input;
+
+ if (mb.is_valid()) {
+ /* Ignore mouse clicks in IME input mode. */
+ if (has_ime_text()) {
+ return;
+ }
+
+ if (code_completion_active && code_completion_rect.has_point(mb->get_position())) {
+ if (!mb->is_pressed()) {
+ return;
+ }
+
+ switch (mb->get_button_index()) {
+ case MOUSE_BUTTON_WHEEL_UP: {
+ if (code_completion_current_selected > 0) {
+ code_completion_current_selected--;
+ update();
+ }
+ } break;
+ case MOUSE_BUTTON_WHEEL_DOWN: {
+ if (code_completion_current_selected < code_completion_options.size() - 1) {
+ code_completion_current_selected++;
+ update();
+ }
+ } break;
+ case MOUSE_BUTTON_LEFT: {
+ code_completion_current_selected = CLAMP(code_completion_line_ofs + (mb->get_position().y - code_completion_rect.position.y) / get_row_height(), 0, code_completion_options.size() - 1);
+ if (mb->is_double_click()) {
+ confirm_code_completion();
+ }
+ update();
+ } break;
+ }
+ return;
+ }
+ cancel_code_completion();
+ set_code_hint("");
+
+ if (mb->is_pressed()) {
+ Vector2i mpos = mb->get_position();
+ if (is_layout_rtl()) {
+ mpos.x = get_size().x - mpos.x;
+ }
+
+ int line, col;
+ _get_mouse_pos(Point2i(mpos.x, mpos.y), line, col);
+
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (is_line_folded(line)) {
+ int wrap_index = get_line_wrap_index_at_col(line, col);
+ if (wrap_index == times_line_wraps(line)) {
+ int eol_icon_width = cache.folded_eol_icon->get_width();
+ int left_margin = get_total_gutter_width() + eol_icon_width + get_line_width(line, wrap_index) - get_h_scroll();
+ if (mpos.x > left_margin && mpos.x <= left_margin + eol_icon_width + 3) {
+ unfold_line(line);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Ref<InputEventKey> k = p_gui_input;
+ bool update_code_completion = false;
+ if (!k.is_valid()) {
+ TextEdit::_gui_input(p_gui_input);
+ return;
+ }
+
+ /* If a modifier has been pressed, and nothing else, return. */
+ if (!k->is_pressed() || k->get_keycode() == KEY_CTRL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT || k->get_keycode() == KEY_META) {
+ return;
+ }
+
+ /* Allow unicode handling if: */
+ /* No Modifiers are pressed (except shift) */
+ bool allow_unicode_handling = !(k->is_command_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
+
+ /* AUTO-COMPLETE */
+ if (code_completion_enabled && k->is_action("ui_text_completion_query", true)) {
+ request_code_completion(true);
+ accept_event();
+ return;
+ }
+
+ if (code_completion_active) {
+ if (k->is_action("ui_up", true)) {
+ if (code_completion_current_selected > 0) {
+ code_completion_current_selected--;
+ } else {
+ code_completion_current_selected = code_completion_options.size() - 1;
+ }
+ update();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_down", true)) {
+ if (code_completion_current_selected < code_completion_options.size() - 1) {
+ code_completion_current_selected++;
+ } else {
+ code_completion_current_selected = 0;
+ }
+ update();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_page_up", true)) {
+ code_completion_current_selected = MAX(0, code_completion_current_selected - code_completion_max_lines);
+ update();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_page_down", true)) {
+ code_completion_current_selected = MIN(code_completion_options.size() - 1, code_completion_current_selected + code_completion_max_lines);
+ update();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_home", true)) {
+ code_completion_current_selected = 0;
+ update();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_end", true)) {
+ code_completion_current_selected = MIN(code_completion_options.size() - 1, code_completion_current_selected + code_completion_max_lines);
+ update();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_completion_replace", true) || k->is_action("ui_text_completion_accept", true)) {
+ confirm_code_completion(k->is_action("ui_text_completion_replace", true));
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_cancel", true)) {
+ cancel_code_completion();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_backspace", true)) {
+ backspace_at_cursor();
+ _filter_code_completion_candidates();
+ accept_event();
+ return;
+ }
+
+ if (k->is_action("ui_left", true) || k->is_action("ui_right", true)) {
+ update_code_completion = true;
+ } else {
+ update_code_completion = (allow_unicode_handling && k->get_unicode() >= 32);
+ }
+
+ if (!update_code_completion) {
+ cancel_code_completion();
+ }
+ }
+
+ /* MISC */
+ if (k->is_action("ui_cancel", true)) {
+ set_code_hint("");
+ accept_event();
+ return;
+ }
+ if (allow_unicode_handling && k->get_unicode() == ')') {
+ set_code_hint("");
+ }
+
+ /* Override input to unfold lines where needed. */
+ if (!is_readonly()) {
+ if (k->is_action("ui_text_newline_above", true) || k->is_action("ui_text_newline_blank", true) || k->is_action("ui_text_newline", true)) {
+ unfold_line(cursor_get_line());
+ }
+ if (cursor_get_line() > 0 && k->is_action("ui_text_backspace", true)) {
+ unfold_line(cursor_get_line() - 1);
+ }
+ }
+
+ /* Remove shift otherwise actions will not match. */
+ k = k->duplicate();
+ k->set_shift_pressed(false);
+
+ if (k->is_action("ui_text_caret_up", true) ||
+ k->is_action("ui_text_caret_down", true) ||
+ k->is_action("ui_text_caret_line_start", true) ||
+ k->is_action("ui_text_caret_line_end", true) ||
+ k->is_action("ui_text_caret_page_up", true) ||
+ k->is_action("ui_text_caret_page_down", true)) {
+ set_code_hint("");
+ }
+
+ TextEdit::_gui_input(p_gui_input);
+
+ if (update_code_completion) {
+ _filter_code_completion_candidates();
+ }
+}
+
+Control::CursorShape CodeEdit::get_cursor_shape(const Point2 &p_pos) const {
+ if ((code_completion_active && code_completion_rect.has_point(p_pos)) || (is_readonly() && (!is_selecting_enabled() || get_line_count() == 0))) {
+ return CURSOR_ARROW;
+ }
+
+ int line, col;
+ _get_mouse_pos(p_pos, line, col);
+
+ if (is_line_folded(line)) {
+ int wrap_index = get_line_wrap_index_at_col(line, col);
+ if (wrap_index == times_line_wraps(line)) {
+ int eol_icon_width = cache.folded_eol_icon->get_width();
+ int left_margin = get_total_gutter_width() + eol_icon_width + get_line_width(line, wrap_index) - get_h_scroll();
+ if (p_pos.x > left_margin && p_pos.x <= left_margin + eol_icon_width + 3) {
+ return CURSOR_POINTING_HAND;
+ }
+ }
+ }
+
+ return TextEdit::get_cursor_shape(p_pos);
+}
+
/* Main Gutter */
void CodeEdit::_update_draw_main_gutter() {
set_gutter_draw(main_gutter, draw_breakpoints || draw_bookmarks || draw_executing_lines);
@@ -256,7 +635,7 @@ bool CodeEdit::is_drawing_fold_gutter() const {
}
void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region) {
- if (!can_fold(p_line) && !is_folded(p_line)) {
+ if (!can_fold_line(p_line) && !is_line_folded(p_line)) {
set_line_gutter_clickable(p_line, fold_gutter, false);
return;
}
@@ -268,13 +647,642 @@ void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_regi
p_region.position += Point2(horizontal_padding, vertical_padding);
p_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
- if (can_fold(p_line)) {
+ if (can_fold_line(p_line)) {
can_fold_icon->draw_rect(get_canvas_item(), p_region, false, folding_color);
return;
}
folded_icon->draw_rect(get_canvas_item(), p_region, false, folding_color);
}
+/* Line Folding */
+void CodeEdit::set_line_folding_enabled(bool p_enabled) {
+ line_folding_enabled = p_enabled;
+ set_hiding_enabled(p_enabled);
+}
+
+bool CodeEdit::is_line_folding_enabled() const {
+ return line_folding_enabled;
+}
+
+bool CodeEdit::can_fold_line(int p_line) const {
+ ERR_FAIL_INDEX_V(p_line, get_line_count(), false);
+ if (!line_folding_enabled) {
+ return false;
+ }
+
+ if (p_line + 1 >= get_line_count() || get_line(p_line).strip_edges().size() == 0) {
+ return false;
+ }
+
+ if (is_line_hidden(p_line) || is_line_folded(p_line)) {
+ return false;
+ }
+
+ /* Check for full multiline line or block strings / comments. */
+ int in_comment = is_in_comment(p_line);
+ int in_string = (in_comment == -1) ? is_in_string(p_line) : -1;
+ if (in_string != -1 || in_comment != -1) {
+ if (get_delimiter_start_position(p_line, get_line(p_line).size() - 1).y != p_line) {
+ return false;
+ }
+
+ int delimter_end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y;
+ /* No end line, therefore we have a multiline region over the rest of the file. */
+ if (delimter_end_line == -1) {
+ return true;
+ }
+ /* End line is the same therefore we have a block. */
+ if (delimter_end_line == p_line) {
+ /* Check we are the start of the block. */
+ if (p_line - 1 >= 0) {
+ if ((in_string != -1 && is_in_string(p_line - 1) != -1) || (in_comment != -1 && is_in_comment(p_line - 1) != -1)) {
+ return false;
+ }
+ }
+ /* Check it continues for at least one line. */
+ return ((in_string != -1 && is_in_string(p_line + 1) != -1) || (in_comment != -1 && is_in_comment(p_line + 1) != -1));
+ }
+ return ((in_string != -1 && is_in_string(delimter_end_line) != -1) || (in_comment != -1 && is_in_comment(delimter_end_line) != -1));
+ }
+
+ /* Otherwise check indent levels. */
+ int start_indent = get_indent_level(p_line);
+ for (int i = p_line + 1; i < get_line_count(); i++) {
+ if (is_in_string(i) != -1 || is_in_comment(i) != -1 || get_line(i).strip_edges().size() == 0) {
+ continue;
+ }
+ return (get_indent_level(i) > start_indent);
+ }
+ return false;
+}
+
+void CodeEdit::fold_line(int p_line) {
+ ERR_FAIL_INDEX(p_line, get_line_count());
+ if (!is_line_folding_enabled() || !can_fold_line(p_line)) {
+ return;
+ }
+
+ /* Find the last line to be hidden. */
+ int end_line = get_line_count();
+
+ int in_comment = is_in_comment(p_line);
+ int in_string = (in_comment == -1) ? is_in_string(p_line) : -1;
+ if (in_string != -1 || in_comment != -1) {
+ end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y;
+ /* End line is the same therefore we have a block. */
+ if (end_line == p_line) {
+ for (int i = p_line + 1; i < get_line_count(); i++) {
+ if ((in_string != -1 && is_in_string(i) == -1) || (in_comment != -1 && is_in_comment(i) == -1)) {
+ end_line = i - 1;
+ break;
+ }
+ }
+ }
+ } else {
+ int start_indent = get_indent_level(p_line);
+ for (int i = p_line + 1; i < get_line_count(); i++) {
+ if (get_line(p_line).strip_edges().size() == 0 || is_in_string(i) != -1 || is_in_comment(i) != -1) {
+ end_line = i;
+ continue;
+ }
+
+ if (get_indent_level(i) <= start_indent && get_line(i).strip_edges().size() != 0) {
+ end_line = i - 1;
+ break;
+ }
+ }
+ }
+
+ for (int i = p_line + 1; i <= end_line; i++) {
+ set_line_as_hidden(i, true);
+ }
+
+ /* Fix selection. */
+ if (is_selection_active()) {
+ if (is_line_hidden(get_selection_from_line()) && is_line_hidden(get_selection_to_line())) {
+ deselect();
+ } else if (is_line_hidden(get_selection_from_line())) {
+ select(p_line, 9999, get_selection_to_line(), get_selection_to_column());
+ } else if (is_line_hidden(get_selection_to_line())) {
+ select(get_selection_from_line(), get_selection_from_column(), p_line, 9999);
+ }
+ }
+
+ /* Reset caret. */
+ if (is_line_hidden(cursor_get_line())) {
+ cursor_set_line(p_line, false, false);
+ cursor_set_column(get_line(p_line).length(), false);
+ }
+ update();
+}
+
+void CodeEdit::unfold_line(int p_line) {
+ ERR_FAIL_INDEX(p_line, get_line_count());
+ if (!is_line_folded(p_line) && !is_line_hidden(p_line)) {
+ return;
+ }
+
+ int fold_start = p_line;
+ for (; fold_start > 0; fold_start--) {
+ if (is_line_folded(fold_start)) {
+ break;
+ }
+ }
+ fold_start = is_line_folded(fold_start) ? fold_start : p_line;
+
+ for (int i = fold_start + 1; i < get_line_count(); i++) {
+ if (!is_line_hidden(i)) {
+ break;
+ }
+ set_line_as_hidden(i, false);
+ }
+ update();
+}
+
+void CodeEdit::fold_all_lines() {
+ for (int i = 0; i < get_line_count(); i++) {
+ fold_line(i);
+ }
+ update();
+}
+
+void CodeEdit::unfold_all_lines() {
+ unhide_all_lines();
+}
+
+void CodeEdit::toggle_foldable_line(int p_line) {
+ ERR_FAIL_INDEX(p_line, get_line_count());
+ if (is_line_folded(p_line)) {
+ unfold_line(p_line);
+ return;
+ }
+ fold_line(p_line);
+}
+
+bool CodeEdit::is_line_folded(int p_line) const {
+ ERR_FAIL_INDEX_V(p_line, get_line_count(), false);
+ return p_line + 1 < get_line_count() && !is_line_hidden(p_line) && is_line_hidden(p_line + 1);
+}
+
+TypedArray<int> CodeEdit::get_folded_lines() const {
+ TypedArray<int> folded_lines;
+ for (int i = 0; i < get_line_count(); i++) {
+ if (is_line_folded(i)) {
+ folded_lines.push_back(i);
+ }
+ }
+ return folded_lines;
+}
+
+/* Delimiters */
+// Strings
+void CodeEdit::add_string_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only) {
+ _add_delimiter(p_start_key, p_end_key, p_line_only, TYPE_STRING);
+}
+
+void CodeEdit::remove_string_delimiter(const String &p_start_key) {
+ _remove_delimiter(p_start_key, TYPE_STRING);
+}
+
+bool CodeEdit::has_string_delimiter(const String &p_start_key) const {
+ return _has_delimiter(p_start_key, TYPE_STRING);
+}
+
+void CodeEdit::set_string_delimiters(const TypedArray<String> &p_string_delimiters) {
+ _set_delimiters(p_string_delimiters, TYPE_STRING);
+}
+
+void CodeEdit::clear_string_delimiters() {
+ _clear_delimiters(TYPE_STRING);
+}
+
+TypedArray<String> CodeEdit::get_string_delimiters() const {
+ return _get_delimiters(TYPE_STRING);
+}
+
+int CodeEdit::is_in_string(int p_line, int p_column) const {
+ return _is_in_delimiter(p_line, p_column, TYPE_STRING);
+}
+
+// Comments
+void CodeEdit::add_comment_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only) {
+ _add_delimiter(p_start_key, p_end_key, p_line_only, TYPE_COMMENT);
+}
+
+void CodeEdit::remove_comment_delimiter(const String &p_start_key) {
+ _remove_delimiter(p_start_key, TYPE_COMMENT);
+}
+
+bool CodeEdit::has_comment_delimiter(const String &p_start_key) const {
+ return _has_delimiter(p_start_key, TYPE_COMMENT);
+}
+
+void CodeEdit::set_comment_delimiters(const TypedArray<String> &p_comment_delimiters) {
+ _set_delimiters(p_comment_delimiters, TYPE_COMMENT);
+}
+
+void CodeEdit::clear_comment_delimiters() {
+ _clear_delimiters(TYPE_COMMENT);
+}
+
+TypedArray<String> CodeEdit::get_comment_delimiters() const {
+ return _get_delimiters(TYPE_COMMENT);
+}
+
+int CodeEdit::is_in_comment(int p_line, int p_column) const {
+ return _is_in_delimiter(p_line, p_column, TYPE_COMMENT);
+}
+
+String CodeEdit::get_delimiter_start_key(int p_delimiter_idx) const {
+ ERR_FAIL_INDEX_V(p_delimiter_idx, delimiters.size(), "");
+ return delimiters[p_delimiter_idx].start_key;
+}
+
+String CodeEdit::get_delimiter_end_key(int p_delimiter_idx) const {
+ ERR_FAIL_INDEX_V(p_delimiter_idx, delimiters.size(), "");
+ return delimiters[p_delimiter_idx].end_key;
+}
+
+Point2 CodeEdit::get_delimiter_start_position(int p_line, int p_column) const {
+ if (delimiters.size() == 0) {
+ return Point2(-1, -1);
+ }
+ ERR_FAIL_INDEX_V(p_line, get_line_count(), Point2(-1, -1));
+ ERR_FAIL_COND_V(p_column - 1 > get_line(p_line).size(), Point2(-1, -1));
+
+ Point2 start_position;
+ start_position.y = -1;
+ start_position.x = -1;
+
+ bool in_region = ((p_line <= 0 || delimiter_cache[p_line - 1].size() < 1) ? -1 : delimiter_cache[p_line - 1].back()->value()) != -1;
+
+ /* Check the keys for this line. */
+ for (Map<int, int>::Element *E = delimiter_cache[p_line].front(); E; E = E->next()) {
+ if (E->key() > p_column) {
+ break;
+ }
+ in_region = E->value() != -1;
+ start_position.x = in_region ? E->key() : -1;
+ }
+
+ /* Region was found on this line and is not a multiline continuation. */
+ if (start_position.x != -1 && start_position.x != get_line(p_line).length() + 1) {
+ start_position.y = p_line;
+ return start_position;
+ }
+
+ /* Not in a region */
+ if (!in_region) {
+ return start_position;
+ }
+
+ /* Region starts on a previous line */
+ for (int i = p_line - 1; i >= 0; i--) {
+ if (delimiter_cache[i].size() < 1) {
+ continue;
+ }
+ start_position.y = i;
+ start_position.x = delimiter_cache[i].back()->key();
+
+ /* Make sure it's not a multiline continuation. */
+ if (start_position.x != get_line(i).length() + 1) {
+ break;
+ }
+ }
+ return start_position;
+}
+
+Point2 CodeEdit::get_delimiter_end_position(int p_line, int p_column) const {
+ if (delimiters.size() == 0) {
+ return Point2(-1, -1);
+ }
+ ERR_FAIL_INDEX_V(p_line, get_line_count(), Point2(-1, -1));
+ ERR_FAIL_COND_V(p_column - 1 > get_line(p_line).size(), Point2(-1, -1));
+
+ Point2 end_position;
+ end_position.y = -1;
+ end_position.x = -1;
+
+ int region = (p_line <= 0 || delimiter_cache[p_line - 1].size() < 1) ? -1 : delimiter_cache[p_line - 1].back()->value();
+
+ /* Check the keys for this line. */
+ for (Map<int, int>::Element *E = delimiter_cache[p_line].front(); E; E = E->next()) {
+ end_position.x = (E->value() == -1) ? E->key() : -1;
+ if (E->key() > p_column) {
+ break;
+ }
+ region = E->value();
+ }
+
+ /* Region was found on this line and is not a multiline continuation. */
+ if (region != -1 && end_position.x != -1 && (delimiters[region].line_only || end_position.x != get_line(p_line).length() + 1)) {
+ end_position.y = p_line;
+ return end_position;
+ }
+
+ /* Not in a region */
+ if (region == -1) {
+ end_position.x = -1;
+ return end_position;
+ }
+
+ /* Region ends on a later line */
+ for (int i = p_line + 1; i < get_line_count(); i++) {
+ if (delimiter_cache[i].size() < 1 || delimiter_cache[i].front()->value() != -1) {
+ continue;
+ }
+ end_position.x = delimiter_cache[i].front()->key();
+
+ /* Make sure it's not a multiline continuation. */
+ if (get_line(i).length() > 0 && end_position.x != get_line(i).length() + 1) {
+ end_position.y = i;
+ break;
+ }
+ end_position.x = -1;
+ }
+ return end_position;
+}
+
+/* Code hint */
+void CodeEdit::set_code_hint(const String &p_hint) {
+ code_hint = p_hint;
+ code_hint_xpos = -0xFFFF;
+ update();
+}
+
+void CodeEdit::set_code_hint_draw_below(bool p_below) {
+ code_hint_draw_below = p_below;
+ update();
+}
+
+/* Code Completion */
+void CodeEdit::set_code_completion_enabled(bool p_enable) {
+ code_completion_enabled = p_enable;
+}
+
+bool CodeEdit::is_code_completion_enabled() const {
+ return code_completion_enabled;
+}
+
+void CodeEdit::set_code_completion_prefixes(const TypedArray<String> &p_prefixes) {
+ code_completion_prefixes.clear();
+ for (int i = 0; i < p_prefixes.size(); i++) {
+ code_completion_prefixes.insert(p_prefixes[i]);
+ }
+}
+
+TypedArray<String> CodeEdit::get_code_completion_prefixes() const {
+ TypedArray<String> prefixes;
+ for (Set<String>::Element *E = code_completion_prefixes.front(); E; E = E->next()) {
+ prefixes.push_back(E->get());
+ }
+ return prefixes;
+}
+
+String CodeEdit::get_text_for_code_completion() const {
+ StringBuilder completion_text;
+ const int text_size = get_line_count();
+ for (int i = 0; i < text_size; i++) {
+ String line = get_line(i);
+
+ if (i == cursor_get_line()) {
+ completion_text += line.substr(0, cursor_get_column());
+ /* Not unicode, represents the caret. */
+ completion_text += String::chr(0xFFFF);
+ completion_text += line.substr(cursor_get_column(), line.size());
+ } else {
+ completion_text += line;
+ }
+
+ if (i != text_size - 1) {
+ completion_text += "\n";
+ }
+ }
+ return completion_text.as_string();
+}
+
+void CodeEdit::request_code_completion(bool p_force) {
+ ScriptInstance *si = get_script_instance();
+ if (si && si->has_method("_request_code_completion")) {
+ si->call("_request_code_completion", p_force);
+ return;
+ }
+
+ /* Don't re-query if all existing options are quoted types, eg path, signal. */
+ bool ignored = code_completion_active && !code_completion_options.is_empty();
+ if (ignored) {
+ ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_PLAIN_TEXT;
+ const ScriptCodeCompletionOption *previous_option = nullptr;
+ for (int i = 0; i < code_completion_options.size(); i++) {
+ const ScriptCodeCompletionOption &current_option = code_completion_options[i];
+ if (!previous_option) {
+ previous_option = &current_option;
+ kind = current_option.kind;
+ }
+ if (previous_option->kind != current_option.kind) {
+ ignored = false;
+ break;
+ }
+ }
+ ignored = ignored && (kind == ScriptCodeCompletionOption::KIND_FILE_PATH || kind == ScriptCodeCompletionOption::KIND_NODE_PATH || kind == ScriptCodeCompletionOption::KIND_SIGNAL);
+ }
+
+ if (ignored) {
+ return;
+ }
+
+ if (p_force) {
+ emit_signal("request_code_completion");
+ return;
+ }
+
+ String line = get_line(cursor_get_line());
+ int ofs = CLAMP(cursor_get_column(), 0, line.length());
+
+ if (ofs > 0 && (is_in_string(cursor_get_line(), ofs) != -1 || _is_char(line[ofs - 1]) || code_completion_prefixes.has(String::chr(line[ofs - 1])))) {
+ emit_signal("request_code_completion");
+ } else if (ofs > 1 && line[ofs - 1] == ' ' && code_completion_prefixes.has(String::chr(line[ofs - 2]))) {
+ emit_signal("request_code_completion");
+ }
+}
+
+void CodeEdit::add_code_completion_option(CodeCompletionKind p_type, const String &p_display_text, const String &p_insert_text, const Color &p_text_color, const RES &p_icon, const Variant &p_value) {
+ ScriptCodeCompletionOption completion_option;
+ completion_option.kind = (ScriptCodeCompletionOption::Kind)p_type;
+ completion_option.display = p_display_text;
+ completion_option.insert_text = p_insert_text;
+ completion_option.font_color = p_text_color;
+ completion_option.icon = p_icon;
+ completion_option.default_value = p_value;
+ code_completion_option_submitted.push_back(completion_option);
+}
+
+void CodeEdit::update_code_completion_options(bool p_forced) {
+ code_completion_forced = p_forced;
+ code_completion_option_sources = code_completion_option_submitted;
+ code_completion_option_submitted.clear();
+ _filter_code_completion_candidates();
+}
+
+TypedArray<Dictionary> CodeEdit::get_code_completion_options() const {
+ if (!code_completion_active) {
+ return TypedArray<Dictionary>();
+ }
+
+ TypedArray<Dictionary> completion_options;
+ completion_options.resize(code_completion_options.size());
+ for (int i = 0; i < code_completion_options.size(); i++) {
+ Dictionary option;
+ option["kind"] = code_completion_options[i].kind;
+ option["display_text"] = code_completion_options[i].display;
+ option["insert_text"] = code_completion_options[i].insert_text;
+ option["font_color"] = code_completion_options[i].font_color;
+ option["icon"] = code_completion_options[i].icon;
+ option["default_value"] = code_completion_options[i].default_value;
+ completion_options[i] = option;
+ }
+ return completion_options;
+}
+
+Dictionary CodeEdit::get_code_completion_option(int p_index) const {
+ if (!code_completion_active) {
+ return Dictionary();
+ }
+ ERR_FAIL_INDEX_V(p_index, code_completion_options.size(), Dictionary());
+
+ Dictionary option;
+ option["kind"] = code_completion_options[p_index].kind;
+ option["display_text"] = code_completion_options[p_index].display;
+ option["insert_text"] = code_completion_options[p_index].insert_text;
+ option["font_color"] = code_completion_options[p_index].font_color;
+ option["icon"] = code_completion_options[p_index].icon;
+ option["default_value"] = code_completion_options[p_index].default_value;
+ return option;
+}
+
+int CodeEdit::get_code_completion_selected_index() const {
+ return (code_completion_active) ? code_completion_current_selected : -1;
+}
+
+void CodeEdit::set_code_completion_selected_index(int p_index) {
+ if (!code_completion_active) {
+ return;
+ }
+ ERR_FAIL_INDEX(p_index, code_completion_options.size());
+ code_completion_current_selected = p_index;
+ update();
+}
+
+void CodeEdit::confirm_code_completion(bool p_replace) {
+ if (is_readonly() || !code_completion_active) {
+ return;
+ }
+
+ ScriptInstance *si = get_script_instance();
+ if (si && si->has_method("_confirm_code_completion")) {
+ si->call("_confirm_code_completion", p_replace);
+ return;
+ }
+ begin_complex_operation();
+
+ int caret_line = cursor_get_line();
+
+ const String &insert_text = code_completion_options[code_completion_current_selected].insert_text;
+ const String &display_text = code_completion_options[code_completion_current_selected].display;
+
+ if (p_replace) {
+ /* Find end of current section */
+ const String line = get_line(caret_line);
+ int caret_col = cursor_get_column();
+ int caret_remove_line = caret_line;
+
+ bool merge_text = true;
+ int in_string = is_in_string(caret_line, caret_col);
+ if (in_string != -1) {
+ Point2 string_end = get_delimiter_end_position(caret_line, caret_col);
+ if (string_end.x != -1) {
+ merge_text = false;
+ caret_remove_line = string_end.y;
+ caret_col = string_end.x - 1;
+ }
+ }
+
+ if (merge_text) {
+ for (; caret_col < line.length(); caret_col++) {
+ if (!_is_char(line[caret_col])) {
+ break;
+ }
+ }
+ }
+
+ /* Replace. */
+ _remove_text(caret_line, cursor_get_column() - code_completion_base.length(), caret_remove_line, caret_col);
+ cursor_set_column(cursor_get_column() - code_completion_base.length(), false);
+ insert_text_at_cursor(insert_text);
+ } else {
+ /* Get first non-matching char. */
+ const String line = get_line(caret_line);
+ int caret_col = cursor_get_column();
+ int matching_chars = code_completion_base.length();
+ for (; matching_chars <= insert_text.length(); matching_chars++) {
+ if (caret_col >= line.length() || line[caret_col] != insert_text[matching_chars]) {
+ break;
+ }
+ caret_col++;
+ }
+
+ /* Remove base completion text. */
+ _remove_text(caret_line, cursor_get_column() - code_completion_base.length(), caret_line, cursor_get_column());
+ cursor_set_column(cursor_get_column() - code_completion_base.length(), false);
+
+ /* Merge with text. */
+ insert_text_at_cursor(insert_text.substr(0, code_completion_base.length()));
+ cursor_set_column(caret_col, false);
+ insert_text_at_cursor(insert_text.substr(matching_chars));
+ }
+
+ /* TODO: merge with autobrace completion, when in CodeEdit. */
+ /* Handle merging of symbols eg strings, brackets. */
+ const String line = get_line(caret_line);
+ char32_t next_char = line[cursor_get_column()];
+ char32_t last_completion_char = insert_text[insert_text.length() - 1];
+ char32_t last_completion_char_display = display_text[display_text.length() - 1];
+
+ if ((last_completion_char == '"' || last_completion_char == '\'') && (last_completion_char == next_char || last_completion_char_display == next_char)) {
+ _remove_text(caret_line, cursor_get_column(), caret_line, cursor_get_column() + 1);
+ }
+
+ if (last_completion_char == '(') {
+ if (next_char == last_completion_char) {
+ _remove_text(caret_line, cursor_get_column() - 1, caret_line, cursor_get_column());
+ } else if (auto_brace_completion_enabled) {
+ insert_text_at_cursor(")");
+ cursor_set_column(cursor_get_column() - 1);
+ }
+ } else if (last_completion_char == ')' && next_char == '(') {
+ _remove_text(caret_line, cursor_get_column() - 2, caret_line, cursor_get_column());
+ if (line[cursor_get_column() + 1] != ')') {
+ cursor_set_column(cursor_get_column() - 1);
+ }
+ }
+
+ end_complex_operation();
+
+ cancel_code_completion();
+ if (last_completion_char == '(') {
+ request_code_completion();
+ }
+}
+
+void CodeEdit::cancel_code_completion() {
+ if (!code_completion_active) {
+ return;
+ }
+ code_completion_forced = false;
+ code_completion_active = false;
+ update();
+}
+
void CodeEdit::_bind_methods() {
/* Main Gutter */
ClassDB::bind_method(D_METHOD("_main_gutter_draw_callback"), &CodeEdit::_main_gutter_draw_callback);
@@ -320,6 +1328,91 @@ void CodeEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_draw_fold_gutter", "enable"), &CodeEdit::set_draw_fold_gutter);
ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &CodeEdit::is_drawing_fold_gutter);
+ /* Line folding */
+ ClassDB::bind_method(D_METHOD("set_line_folding_enabled", "enabled"), &CodeEdit::set_line_folding_enabled);
+ ClassDB::bind_method(D_METHOD("is_line_folding_enabled"), &CodeEdit::is_line_folding_enabled);
+
+ ClassDB::bind_method(D_METHOD("can_fold_line", "line"), &CodeEdit::can_fold_line);
+
+ ClassDB::bind_method(D_METHOD("fold_line", "line"), &CodeEdit::fold_line);
+ ClassDB::bind_method(D_METHOD("unfold_line", "line"), &CodeEdit::unfold_line);
+ ClassDB::bind_method(D_METHOD("fold_all_lines"), &CodeEdit::fold_all_lines);
+ ClassDB::bind_method(D_METHOD("unfold_all_lines"), &CodeEdit::unfold_all_lines);
+ ClassDB::bind_method(D_METHOD("toggle_foldable_line", "line"), &CodeEdit::toggle_foldable_line);
+
+ ClassDB::bind_method(D_METHOD("is_line_folded", "line"), &CodeEdit::is_line_folded);
+ ClassDB::bind_method(D_METHOD("get_folded_lines"), &CodeEdit::get_folded_lines);
+
+ /* Delimiters */
+ // Strings
+ ClassDB::bind_method(D_METHOD("add_string_delimiter", "start_key", "end_key", "line_only"), &CodeEdit::add_string_delimiter, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("remove_string_delimiter", "start_key"), &CodeEdit::remove_string_delimiter);
+ ClassDB::bind_method(D_METHOD("has_string_delimiter", "start_key"), &CodeEdit::has_string_delimiter);
+
+ ClassDB::bind_method(D_METHOD("set_string_delimiters", "string_delimiters"), &CodeEdit::set_string_delimiters);
+ ClassDB::bind_method(D_METHOD("clear_string_delimiters"), &CodeEdit::clear_string_delimiters);
+ ClassDB::bind_method(D_METHOD("get_string_delimiters"), &CodeEdit::get_string_delimiters);
+
+ ClassDB::bind_method(D_METHOD("is_in_string", "line", "column"), &CodeEdit::is_in_string, DEFVAL(-1));
+
+ // Comments
+ ClassDB::bind_method(D_METHOD("add_comment_delimiter", "start_key", "end_key", "line_only"), &CodeEdit::add_comment_delimiter, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("remove_comment_delimiter", "start_key"), &CodeEdit::remove_comment_delimiter);
+ ClassDB::bind_method(D_METHOD("has_comment_delimiter", "start_key"), &CodeEdit::has_comment_delimiter);
+
+ ClassDB::bind_method(D_METHOD("set_comment_delimiters", "comment_delimiters"), &CodeEdit::set_comment_delimiters);
+ ClassDB::bind_method(D_METHOD("clear_comment_delimiters"), &CodeEdit::clear_comment_delimiters);
+ ClassDB::bind_method(D_METHOD("get_comment_delimiters"), &CodeEdit::get_comment_delimiters);
+
+ ClassDB::bind_method(D_METHOD("is_in_comment", "line", "column"), &CodeEdit::is_in_comment, DEFVAL(-1));
+
+ // Util
+ ClassDB::bind_method(D_METHOD("get_delimiter_start_key", "delimiter_index"), &CodeEdit::get_delimiter_start_key);
+ ClassDB::bind_method(D_METHOD("get_delimiter_end_key", "delimiter_index"), &CodeEdit::get_delimiter_end_key);
+
+ ClassDB::bind_method(D_METHOD("get_delimiter_start_position", "line", "column"), &CodeEdit::get_delimiter_start_position);
+ ClassDB::bind_method(D_METHOD("get_delimiter_end_position", "line", "column"), &CodeEdit::get_delimiter_end_position);
+
+ /* Code hint */
+ ClassDB::bind_method(D_METHOD("set_code_hint", "code_hint"), &CodeEdit::set_code_hint);
+ ClassDB::bind_method(D_METHOD("set_code_hint_draw_below", "draw_below"), &CodeEdit::set_code_hint_draw_below);
+
+ /* Code Completion */
+ BIND_ENUM_CONSTANT(KIND_CLASS);
+ BIND_ENUM_CONSTANT(KIND_FUNCTION);
+ BIND_ENUM_CONSTANT(KIND_SIGNAL);
+ BIND_ENUM_CONSTANT(KIND_VARIABLE);
+ BIND_ENUM_CONSTANT(KIND_MEMBER);
+ BIND_ENUM_CONSTANT(KIND_ENUM);
+ BIND_ENUM_CONSTANT(KIND_CONSTANT);
+ BIND_ENUM_CONSTANT(KIND_NODE_PATH);
+ BIND_ENUM_CONSTANT(KIND_FILE_PATH);
+ BIND_ENUM_CONSTANT(KIND_PLAIN_TEXT);
+
+ ClassDB::bind_method(D_METHOD("get_text_for_code_completion"), &CodeEdit::get_text_for_code_completion);
+ ClassDB::bind_method(D_METHOD("request_code_completion", "force"), &CodeEdit::request_code_completion, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_code_completion_option", "type", "display_text", "insert_text", "text_color", "icon", "value"), &CodeEdit::add_code_completion_option, DEFVAL(Color(1, 1, 1)), DEFVAL(RES()), DEFVAL(Variant::NIL));
+ ClassDB::bind_method(D_METHOD("update_code_completion_options", "force"), &CodeEdit::update_code_completion_options);
+ ClassDB::bind_method(D_METHOD("get_code_completion_options"), &CodeEdit::get_code_completion_options);
+ ClassDB::bind_method(D_METHOD("get_code_completion_option", "index"), &CodeEdit::get_code_completion_option);
+ ClassDB::bind_method(D_METHOD("get_code_completion_selected_index"), &CodeEdit::get_code_completion_selected_index);
+ ClassDB::bind_method(D_METHOD("set_code_completion_selected_index", "index"), &CodeEdit::set_code_completion_selected_index);
+
+ ClassDB::bind_method(D_METHOD("confirm_code_completion", "replace"), &CodeEdit::confirm_code_completion, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("cancel_code_completion"), &CodeEdit::cancel_code_completion);
+
+ ClassDB::bind_method(D_METHOD("set_code_completion_enabled", "enable"), &CodeEdit::set_code_completion_enabled);
+ ClassDB::bind_method(D_METHOD("is_code_completion_enabled"), &CodeEdit::is_code_completion_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_code_completion_prefixes", "prefixes"), &CodeEdit::set_code_completion_prefixes);
+ ClassDB::bind_method(D_METHOD("get_code_comletion_prefixes"), &CodeEdit::get_code_completion_prefixes);
+
+ // Overridable
+ BIND_VMETHOD(MethodInfo("_confirm_code_completion", PropertyInfo(Variant::BOOL, "replace")));
+ BIND_VMETHOD(MethodInfo("_request_code_completion", PropertyInfo(Variant::BOOL, "force")));
+ BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_filter_code_completion_candidates", PropertyInfo(Variant::ARRAY, "candidates")));
+
+ /* Inspector */
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_breakpoints_gutter"), "set_draw_breakpoints_gutter", "is_drawing_breakpoints_gutter");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_bookmarks"), "set_draw_bookmarks_gutter", "is_drawing_bookmarks_gutter");
@@ -331,7 +1424,19 @@ void CodeEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_fold_gutter"), "set_draw_fold_gutter", "is_drawing_fold_gutter");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "line_folding"), "set_line_folding_enabled", "is_line_folding_enabled");
+
+ ADD_GROUP("Delimiters", "delimiter_");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "delimiter_strings"), "set_string_delimiters", "get_string_delimiters");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "delimiter_comments"), "set_comment_delimiters", "get_comment_delimiters");
+
+ ADD_GROUP("Code Completion", "code_completion_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "code_completion_enabled"), "set_code_completion_enabled", "is_code_completion_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "code_completion_prefixes"), "set_code_completion_prefixes", "get_code_comletion_prefixes");
+
+ /* Signals */
ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::INT, "line")));
+ ADD_SIGNAL(MethodInfo("request_code_completion"));
}
void CodeEdit::_gutter_clicked(int p_line, int p_gutter) {
@@ -351,16 +1456,578 @@ void CodeEdit::_gutter_clicked(int p_line, int p_gutter) {
}
if (p_gutter == fold_gutter) {
- if (is_folded(p_line)) {
+ if (is_line_folded(p_line)) {
unfold_line(p_line);
- } else if (can_fold(p_line)) {
+ } else if (can_fold_line(p_line)) {
fold_line(p_line);
}
return;
}
}
+void CodeEdit::_update_gutter_indexes() {
+ for (int i = 0; i < get_gutter_count(); i++) {
+ if (get_gutter_name(i) == "main_gutter") {
+ main_gutter = i;
+ continue;
+ }
+
+ if (get_gutter_name(i) == "line_numbers") {
+ line_number_gutter = i;
+ continue;
+ }
+
+ if (get_gutter_name(i) == "fold_gutter") {
+ fold_gutter = i;
+ continue;
+ }
+ }
+}
+
+/* Delimiters */
+void CodeEdit::_update_delimiter_cache(int p_from_line, int p_to_line) {
+ if (delimiters.size() == 0) {
+ return;
+ }
+
+ int line_count = get_line_count();
+ if (p_to_line == -1) {
+ p_to_line = line_count;
+ }
+
+ int start_line = MIN(p_from_line, p_to_line);
+ int end_line = MAX(p_from_line, p_to_line);
+
+ /* Make sure delimiter_cache has all the lines. */
+ if (start_line != end_line) {
+ if (p_to_line < p_from_line) {
+ for (int i = end_line; i > start_line; i--) {
+ delimiter_cache.remove(i);
+ }
+ } else {
+ for (int i = start_line; i < end_line; i++) {
+ delimiter_cache.insert(i, Map<int, int>());
+ }
+ }
+ }
+
+ int in_region = -1;
+ for (int i = start_line; i < MIN(end_line + 1, line_count); i++) {
+ int current_end_region = (i <= 0 || delimiter_cache[i].size() < 1) ? -1 : delimiter_cache[i].back()->value();
+ in_region = (i <= 0 || delimiter_cache[i - 1].size() < 1) ? -1 : delimiter_cache[i - 1].back()->value();
+
+ const String &str = get_line(i);
+ const int line_length = str.length();
+ delimiter_cache.write[i].clear();
+
+ if (str.length() == 0) {
+ if (in_region != -1) {
+ delimiter_cache.write[i][0] = in_region;
+ }
+ if (i == end_line && current_end_region != in_region) {
+ end_line++;
+ end_line = MIN(end_line, line_count);
+ }
+ continue;
+ }
+
+ int end_region = -1;
+ for (int j = 0; j < line_length; j++) {
+ int from = j;
+ for (; from < line_length; from++) {
+ if (str[from] == '\\') {
+ from++;
+ continue;
+ }
+ break;
+ }
+
+ /* check if we are in entering a region */
+ bool same_line = false;
+ if (in_region == -1) {
+ for (int d = 0; d < delimiters.size(); d++) {
+ /* check there is enough room */
+ int chars_left = line_length - from;
+ int start_key_length = delimiters[d].start_key.length();
+ int end_key_length = delimiters[d].end_key.length();
+ if (chars_left < start_key_length) {
+ continue;
+ }
+
+ /* search the line */
+ bool match = true;
+ const char32_t *start_key = delimiters[d].start_key.get_data();
+ for (int k = 0; k < start_key_length; k++) {
+ if (start_key[k] != str[from + k]) {
+ match = false;
+ break;
+ }
+ }
+ if (!match) {
+ continue;
+ }
+ same_line = true;
+ in_region = d;
+ delimiter_cache.write[i][from + 1] = d;
+ from += start_key_length;
+
+ /* check if it's the whole line */
+ if (end_key_length == 0 || delimiters[d].line_only || from + end_key_length > line_length) {
+ j = line_length;
+ if (delimiters[d].line_only) {
+ delimiter_cache.write[i][line_length + 1] = -1;
+ } else {
+ end_region = in_region;
+ }
+ }
+ break;
+ }
+
+ if (j == line_length || in_region == -1) {
+ continue;
+ }
+ }
+
+ /* if we are in one find the end key */
+ /* search the line */
+ int region_end_index = -1;
+ int end_key_length = delimiters[in_region].end_key.length();
+ const char32_t *end_key = delimiters[in_region].end_key.get_data();
+ for (; from < line_length; from++) {
+ if (line_length - from < end_key_length) {
+ break;
+ }
+
+ if (!is_symbol(str[from])) {
+ continue;
+ }
+
+ if (str[from] == '\\') {
+ from++;
+ continue;
+ }
+
+ region_end_index = from;
+ for (int k = 0; k < end_key_length; k++) {
+ if (end_key[k] != str[from + k]) {
+ region_end_index = -1;
+ break;
+ }
+ }
+
+ if (region_end_index != -1) {
+ break;
+ }
+ }
+
+ j = from + (end_key_length - 1);
+ end_region = (region_end_index == -1) ? in_region : -1;
+ if (!same_line || region_end_index != -1) {
+ delimiter_cache.write[i][j + 1] = end_region;
+ }
+ in_region = -1;
+ }
+
+ if (i == end_line && current_end_region != end_region) {
+ end_line++;
+ end_line = MIN(end_line, line_count);
+ }
+ }
+}
+
+int CodeEdit::_is_in_delimiter(int p_line, int p_column, DelimiterType p_type) const {
+ if (delimiters.size() == 0) {
+ return -1;
+ }
+ ERR_FAIL_INDEX_V(p_line, get_line_count(), 0);
+
+ int region = (p_line <= 0 || delimiter_cache[p_line - 1].size() < 1) ? -1 : delimiter_cache[p_line - 1].back()->value();
+ bool in_region = region != -1 && delimiters[region].type == p_type;
+ for (Map<int, int>::Element *E = delimiter_cache[p_line].front(); E; E = E->next()) {
+ /* If column is specified, loop untill the key is larger then the column. */
+ if (p_column != -1) {
+ if (E->key() > p_column) {
+ break;
+ }
+ in_region = E->value() != -1 && delimiters[E->value()].type == p_type;
+ region = in_region ? E->value() : -1;
+ continue;
+ }
+
+ /* If no column, calulate if the entire line is a region */
+ /* excluding whitespace. */
+ const String line = get_line(p_line);
+ if (!in_region) {
+ if (E->value() == -1 || delimiters[E->value()].type != p_type) {
+ break;
+ }
+
+ region = E->value();
+ in_region = true;
+ for (int i = E->key() - 2; i >= 0; i--) {
+ if (!_is_whitespace(line[i])) {
+ return -1;
+ }
+ }
+ }
+
+ if (delimiters[region].line_only) {
+ return region;
+ }
+
+ int end_col = E->key();
+ if (E->value() != -1) {
+ if (!E->next()) {
+ return region;
+ }
+ end_col = E->next()->key();
+ }
+
+ for (int i = end_col; i < line.length(); i++) {
+ if (!_is_whitespace(line[i])) {
+ return -1;
+ }
+ }
+ return region;
+ }
+ return in_region ? region : -1;
+}
+
+void CodeEdit::_add_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only, DelimiterType p_type) {
+ if (p_start_key.length() > 0) {
+ for (int i = 0; i < p_start_key.length(); i++) {
+ ERR_FAIL_COND_MSG(!is_symbol(p_start_key[i]), "delimiter must start with a symbol");
+ }
+ }
+
+ if (p_end_key.length() > 0) {
+ for (int i = 0; i < p_end_key.length(); i++) {
+ ERR_FAIL_COND_MSG(!is_symbol(p_end_key[i]), "delimiter must end with a symbol");
+ }
+ }
+
+ int at = 0;
+ for (int i = 0; i < delimiters.size(); i++) {
+ ERR_FAIL_COND_MSG(delimiters[i].start_key == p_start_key, "delimiter with start key '" + p_start_key + "' already exists.");
+ if (p_start_key.length() < delimiters[i].start_key.length()) {
+ at++;
+ }
+ }
+
+ Delimiter delimiter;
+ delimiter.type = p_type;
+ delimiter.start_key = p_start_key;
+ delimiter.end_key = p_end_key;
+ delimiter.line_only = p_line_only || p_end_key == "";
+ delimiters.insert(at, delimiter);
+ if (!setting_delimiters) {
+ delimiter_cache.clear();
+ _update_delimiter_cache();
+ }
+}
+
+void CodeEdit::_remove_delimiter(const String &p_start_key, DelimiterType p_type) {
+ for (int i = 0; i < delimiters.size(); i++) {
+ if (delimiters[i].start_key != p_start_key) {
+ continue;
+ }
+
+ if (delimiters[i].type != p_type) {
+ break;
+ }
+
+ delimiters.remove(i);
+ if (!setting_delimiters) {
+ delimiter_cache.clear();
+ _update_delimiter_cache();
+ }
+ break;
+ }
+}
+
+bool CodeEdit::_has_delimiter(const String &p_start_key, DelimiterType p_type) const {
+ for (int i = 0; i < delimiters.size(); i++) {
+ if (delimiters[i].start_key == p_start_key) {
+ return delimiters[i].type == p_type;
+ }
+ }
+ return false;
+}
+
+void CodeEdit::_set_delimiters(const TypedArray<String> &p_delimiters, DelimiterType p_type) {
+ setting_delimiters = true;
+ _clear_delimiters(p_type);
+
+ for (int i = 0; i < p_delimiters.size(); i++) {
+ String key = p_delimiters[i].is_null() ? "" : p_delimiters[i];
+
+ const String start_key = key.get_slice(" ", 0);
+ const String end_key = key.get_slice_count(" ") > 1 ? key.get_slice(" ", 1) : String();
+
+ _add_delimiter(start_key, end_key, end_key == "", p_type);
+ }
+ setting_delimiters = false;
+ _update_delimiter_cache();
+}
+
+void CodeEdit::_clear_delimiters(DelimiterType p_type) {
+ for (int i = delimiters.size() - 1; i >= 0; i--) {
+ if (delimiters[i].type == p_type) {
+ delimiters.remove(i);
+ }
+ }
+ delimiter_cache.clear();
+ if (!setting_delimiters) {
+ _update_delimiter_cache();
+ }
+}
+
+TypedArray<String> CodeEdit::_get_delimiters(DelimiterType p_type) const {
+ TypedArray<String> r_delimiters;
+ for (int i = 0; i < delimiters.size(); i++) {
+ if (delimiters[i].type != p_type) {
+ continue;
+ }
+ r_delimiters.push_back(delimiters[i].start_key + (delimiters[i].end_key.is_empty() ? "" : " " + delimiters[i].end_key));
+ }
+ return r_delimiters;
+}
+
+/* Code Completion */
+void CodeEdit::_filter_code_completion_candidates() {
+ ScriptInstance *si = get_script_instance();
+ if (si && si->has_method("_filter_code_completion_candidates")) {
+ code_completion_options.clear();
+ code_completion_base = "";
+
+ /* Build options argument. */
+ TypedArray<Dictionary> completion_options_sources;
+ completion_options_sources.resize(code_completion_option_sources.size());
+ int i = 0;
+ for (List<ScriptCodeCompletionOption>::Element *E = code_completion_option_sources.front(); E; E = E->next()) {
+ Dictionary option;
+ option["kind"] = E->get().kind;
+ option["display_text"] = E->get().display;
+ option["insert_text"] = E->get().insert_text;
+ option["font_color"] = E->get().font_color;
+ option["icon"] = E->get().icon;
+ option["default_value"] = E->get().default_value;
+ completion_options_sources[i] = option;
+ i++;
+ }
+
+ TypedArray<Dictionary> completion_options = si->call("_filter_code_completion_candidates", completion_options_sources);
+
+ /* No options to complete, cancel. */
+ if (completion_options.size() == 0) {
+ cancel_code_completion();
+ return;
+ }
+
+ /* Convert back into options. */
+ int max_width = 0;
+ for (i = 0; i < completion_options.size(); i++) {
+ ScriptCodeCompletionOption option;
+ option.kind = (ScriptCodeCompletionOption::Kind)(int)completion_options[i].get("kind");
+ option.display = completion_options[i].get("display_text");
+ option.insert_text = completion_options[i].get("insert_text");
+ option.font_color = completion_options[i].get("font_color");
+ option.icon = completion_options[i].get("icon");
+ option.default_value = completion_options[i].get("default_value");
+
+ max_width = MAX(max_width, cache.font->get_string_size(option.display).width);
+ code_completion_options.push_back(option);
+ }
+
+ code_completion_longest_line = MIN(max_width, code_completion_max_width);
+ code_completion_current_selected = 0;
+ code_completion_active = true;
+ update();
+ return;
+ }
+
+ const int caret_line = cursor_get_line();
+ const int caret_column = cursor_get_column();
+ const String line = get_line(caret_line);
+
+ if (caret_column > 0 && line[caret_column - 1] == '(' && !code_completion_forced) {
+ cancel_code_completion();
+ return;
+ }
+
+ /* Get string status, are we in one or at the close. */
+ int in_string = is_in_string(caret_line, caret_column);
+ int first_quote_col = -1;
+ if (in_string != -1) {
+ Point2 string_start_pos = get_delimiter_start_position(caret_line, caret_column);
+ first_quote_col = (string_start_pos.y == caret_line) ? string_start_pos.x : -1;
+ } else if (caret_column > 0) {
+ if (is_in_string(caret_line, caret_column - 1) != -1) {
+ first_quote_col = caret_column - 1;
+ }
+ }
+
+ int cofs = caret_column;
+ String string_to_complete;
+ bool prev_is_word = false;
+
+ /* Cancel if we are at the close of a string. */
+ if (in_string == -1 && first_quote_col == cofs - 1) {
+ cancel_code_completion();
+ return;
+ /* In a string, therefore we are trying to complete the string text. */
+ } else if (in_string != -1 && first_quote_col != -1) {
+ int key_length = delimiters[in_string].start_key.length();
+ string_to_complete = line.substr(first_quote_col - key_length, (cofs - first_quote_col) + key_length);
+ /* If we have a space, previous word might be a keyword. eg "func |". */
+ } else if (cofs > 0 && line[cofs - 1] == ' ') {
+ int ofs = cofs - 1;
+ while (ofs >= 0 && line[ofs] == ' ') {
+ ofs--;
+ }
+ prev_is_word = _is_char(line[ofs]);
+ /* Otherwise get current word and set cofs to the start. */
+ } else {
+ int start_cofs = cofs;
+ while (cofs > 0 && line[cofs - 1] > 32 && (line[cofs - 1] == '/' || _is_char(line[cofs - 1]))) {
+ cofs--;
+ }
+ string_to_complete = line.substr(cofs, start_cofs - cofs);
+ }
+
+ /* If all else fails, check for a prefix. */
+ /* Single space between caret and prefix is okay. */
+ bool prev_is_prefix = false;
+ if (cofs > 0 && code_completion_prefixes.has(String::chr(line[cofs - 1]))) {
+ prev_is_prefix = true;
+ } else if (cofs > 1 && line[cofs - 1] == ' ' && code_completion_prefixes.has(String::chr(line[cofs - 2]))) {
+ prev_is_prefix = true;
+ }
+
+ if (!prev_is_word && string_to_complete.is_empty() && (cofs == 0 || !prev_is_prefix)) {
+ cancel_code_completion();
+ return;
+ }
+
+ /* Filter Options. */
+ /* For now handle only tradional quoted strings. */
+ bool single_quote = in_string != -1 && first_quote_col > 0 && delimiters[in_string].start_key == "'";
+
+ code_completion_options.clear();
+ code_completion_base = string_to_complete;
+
+ Vector<ScriptCodeCompletionOption> completion_options_casei;
+ Vector<ScriptCodeCompletionOption> completion_options_subseq;
+ Vector<ScriptCodeCompletionOption> completion_options_subseq_casei;
+
+ int max_width = 0;
+ String string_to_complete_lower = string_to_complete.to_lower();
+ for (List<ScriptCodeCompletionOption>::Element *E = code_completion_option_sources.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption &option = E->get();
+
+ if (single_quote && option.display.is_quoted()) {
+ option.display = option.display.unquote().quote("'");
+ }
+
+ if (in_string != -1) {
+ String quote = single_quote ? "'" : "\"";
+ option.display = option.display.unquote().quote(quote);
+ option.insert_text = option.insert_text.unquote().quote(quote);
+ }
+
+ if (option.display.length() == 0) {
+ continue;
+ }
+
+ if (string_to_complete.length() == 0) {
+ code_completion_options.push_back(option);
+ max_width = MAX(max_width, cache.font->get_string_size(option.display).width);
+ continue;
+ }
+
+ /* This code works the same as:
+
+ if (option.display.begins_with(s)) {
+ completion_options.push_back(option);
+ } else if (option.display.to_lower().begins_with(s.to_lower())) {
+ completion_options_casei.push_back(option);
+ } else if (s.is_subsequence_of(option.display)) {
+ completion_options_subseq.push_back(option);
+ } else if (s.is_subsequence_ofi(option.display)) {
+ completion_options_subseq_casei.push_back(option);
+ }
+
+ But is more performant due to being inlined and looping over the characters only once
+ */
+
+ String display_lower = option.display.to_lower();
+
+ const char32_t *ssq = &string_to_complete[0];
+ const char32_t *ssq_lower = &string_to_complete_lower[0];
+
+ const char32_t *tgt = &option.display[0];
+ const char32_t *tgt_lower = &display_lower[0];
+
+ const char32_t *ssq_last_tgt = nullptr;
+ const char32_t *ssq_lower_last_tgt = nullptr;
+
+ for (; *tgt; tgt++, tgt_lower++) {
+ if (*ssq == *tgt) {
+ ssq++;
+ ssq_last_tgt = tgt;
+ }
+ if (*ssq_lower == *tgt_lower) {
+ ssq_lower++;
+ ssq_lower_last_tgt = tgt;
+ }
+ }
+
+ /* Matched the whole subsequence in s. */
+ if (!*ssq) {
+ /* Finished matching in the first s.length() characters. */
+ if (ssq_last_tgt == &option.display[string_to_complete.length() - 1]) {
+ code_completion_options.push_back(option);
+ } else {
+ completion_options_subseq.push_back(option);
+ }
+ max_width = MAX(max_width, cache.font->get_string_size(option.display).width);
+ /* Matched the whole subsequence in s_lower. */
+ } else if (!*ssq_lower) {
+ /* Finished matching in the first s.length() characters. */
+ if (ssq_lower_last_tgt == &option.display[string_to_complete.length() - 1]) {
+ completion_options_casei.push_back(option);
+ } else {
+ completion_options_subseq_casei.push_back(option);
+ }
+ max_width = MAX(max_width, cache.font->get_string_size(option.display).width);
+ }
+ }
+
+ code_completion_options.append_array(completion_options_casei);
+ code_completion_options.append_array(completion_options_subseq);
+ code_completion_options.append_array(completion_options_subseq_casei);
+
+ /* No options to complete, cancel. */
+ if (code_completion_options.size() == 0) {
+ cancel_code_completion();
+ return;
+ }
+
+ /* A perfect match, stop completion. */
+ if (code_completion_options.size() == 1 && string_to_complete == code_completion_options[0].display) {
+ cancel_code_completion();
+ return;
+ }
+
+ code_completion_longest_line = MIN(max_width, code_completion_max_width);
+ code_completion_current_selected = 0;
+ code_completion_active = true;
+ update();
+}
+
void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) {
+ _update_delimiter_cache(p_from_line, p_to_line);
+
if (p_from_line == p_to_line) {
return;
}
@@ -392,25 +2059,6 @@ void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) {
}
}
-void CodeEdit::_update_gutter_indexes() {
- for (int i = 0; i < get_gutter_count(); i++) {
- if (get_gutter_name(i) == "main_gutter") {
- main_gutter = i;
- continue;
- }
-
- if (get_gutter_name(i) == "line_numbers") {
- line_number_gutter = i;
- continue;
- }
-
- if (get_gutter_name(i) == "fold_gutter") {
- fold_gutter = i;
- continue;
- }
- }
-}
-
CodeEdit::CodeEdit() {
/* Text Direction */
set_layout_direction(LAYOUT_DIRECTION_LTR);
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index d0c39ec0f1..52b3f52a03 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -36,6 +36,22 @@
class CodeEdit : public TextEdit {
GDCLASS(CodeEdit, TextEdit)
+public:
+ /* Keep enum in sync with: */
+ /* /core/object/script_language.h - ScriptCodeCompletionOption::Kind */
+ enum CodeCompletionKind {
+ KIND_CLASS,
+ KIND_FUNCTION,
+ KIND_SIGNAL,
+ KIND_VARIABLE,
+ KIND_MEMBER,
+ KIND_ENUM,
+ KIND_CONSTANT,
+ KIND_NODE_PATH,
+ KIND_FILE_PATH,
+ KIND_PLAIN_TEXT,
+ };
+
private:
/* Main Gutter */
enum MainGutterType {
@@ -80,16 +96,116 @@ private:
void _fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region);
void _gutter_clicked(int p_line, int p_gutter);
- void _lines_edited_from(int p_from_line, int p_to_line);
-
void _update_gutter_indexes();
+ /* Line Folding */
+ bool line_folding_enabled = true;
+
+ /* Delimiters */
+ enum DelimiterType {
+ TYPE_STRING,
+ TYPE_COMMENT,
+ };
+
+ struct Delimiter {
+ DelimiterType type;
+ String start_key = "";
+ String end_key = "";
+ bool line_only = true;
+ };
+ bool setting_delimiters = false;
+ Vector<Delimiter> delimiters;
+ /*
+ * Vector entry per line, contains a Map of column numbers to delimiter index, -1 marks the end of a region.
+ * e.g the following text will be stored as so:
+ *
+ * 0: nothing here
+ * 1:
+ * 2: # test
+ * 3: "test" text "multiline
+ * 4:
+ * 5: test
+ * 6: string"
+ *
+ * Vector [
+ * 0 = []
+ * 1 = []
+ * 2 = [
+ * 1 = 1
+ * 6 = -1
+ * ]
+ * 3 = [
+ * 1 = 0
+ * 6 = -1
+ * 13 = 0
+ * ]
+ * 4 = [
+ * 0 = 0
+ * ]
+ * 5 = [
+ * 5 = 0
+ * ]
+ * 6 = [
+ * 7 = -1
+ * ]
+ * ]
+ */
+ Vector<Map<int, int>> delimiter_cache;
+
+ void _update_delimiter_cache(int p_from_line = 0, int p_to_line = -1);
+ int _is_in_delimiter(int p_line, int p_column, DelimiterType p_type) const;
+
+ void _add_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only, DelimiterType p_type);
+ void _remove_delimiter(const String &p_start_key, DelimiterType p_type);
+ bool _has_delimiter(const String &p_start_key, DelimiterType p_type) const;
+
+ void _set_delimiters(const TypedArray<String> &p_delimiters, DelimiterType p_type);
+ void _clear_delimiters(DelimiterType p_type);
+ TypedArray<String> _get_delimiters(DelimiterType p_type) const;
+
+ /* Code Hint */
+ String code_hint = "";
+
+ bool code_hint_draw_below = true;
+ int code_hint_xpos = -0xFFFF;
+
+ /* Code Completion */
+ bool code_completion_enabled = false;
+ bool code_completion_forced = false;
+
+ int code_completion_max_width = 0;
+ int code_completion_max_lines = 7;
+ int code_completion_scroll_width = 0;
+ Color code_completion_scroll_color = Color(0, 0, 0, 0);
+ Color code_completion_background_color = Color(0, 0, 0, 0);
+ Color code_completion_selected_color = Color(0, 0, 0, 0);
+ Color code_completion_existing_color = Color(0, 0, 0, 0);
+
+ bool code_completion_active = false;
+ Vector<ScriptCodeCompletionOption> code_completion_options;
+ int code_completion_line_ofs = 0;
+ int code_completion_current_selected = 0;
+ int code_completion_longest_line = 0;
+ Rect2i code_completion_rect;
+
+ Set<String> code_completion_prefixes;
+ List<ScriptCodeCompletionOption> code_completion_option_submitted;
+ List<ScriptCodeCompletionOption> code_completion_option_sources;
+ String code_completion_base;
+
+ void _filter_code_completion_candidates();
+
+ void _lines_edited_from(int p_from_line, int p_to_line);
+
protected:
+ void _gui_input(const Ref<InputEvent> &p_gui_input) override;
void _notification(int p_what);
static void _bind_methods();
public:
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
+
/* Main Gutter */
void set_draw_breakpoints_gutter(bool p_draw);
bool is_drawing_breakpoints_gutter() const;
@@ -128,8 +244,79 @@ public:
void set_draw_fold_gutter(bool p_draw);
bool is_drawing_fold_gutter() const;
+ /* Line Folding */
+ void set_line_folding_enabled(bool p_enabled);
+ bool is_line_folding_enabled() const;
+
+ bool can_fold_line(int p_line) const;
+
+ void fold_line(int p_line);
+ void unfold_line(int p_line);
+ void fold_all_lines();
+ void unfold_all_lines();
+ void toggle_foldable_line(int p_line);
+
+ bool is_line_folded(int p_line) const;
+ TypedArray<int> get_folded_lines() const;
+
+ /* Delimiters */
+ void add_string_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only = false);
+ void remove_string_delimiter(const String &p_start_key);
+ bool has_string_delimiter(const String &p_start_key) const;
+
+ void set_string_delimiters(const TypedArray<String> &p_string_delimiters);
+ void clear_string_delimiters();
+ TypedArray<String> get_string_delimiters() const;
+
+ int is_in_string(int p_line, int p_column = -1) const;
+
+ void add_comment_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only = false);
+ void remove_comment_delimiter(const String &p_start_key);
+ bool has_comment_delimiter(const String &p_start_key) const;
+
+ void set_comment_delimiters(const TypedArray<String> &p_comment_delimiters);
+ void clear_comment_delimiters();
+ TypedArray<String> get_comment_delimiters() const;
+
+ int is_in_comment(int p_line, int p_column = -1) const;
+
+ String get_delimiter_start_key(int p_delimiter_idx) const;
+ String get_delimiter_end_key(int p_delimiter_idx) const;
+
+ Point2 get_delimiter_start_position(int p_line, int p_column) const;
+ Point2 get_delimiter_end_position(int p_line, int p_column) const;
+
+ /* Code hint */
+ void set_code_hint(const String &p_hint);
+ void set_code_hint_draw_below(bool p_below);
+
+ /* Code Completion */
+ void set_code_completion_enabled(bool p_enable);
+ bool is_code_completion_enabled() const;
+
+ void set_code_completion_prefixes(const TypedArray<String> &p_prefixes);
+ TypedArray<String> get_code_completion_prefixes() const;
+
+ String get_text_for_code_completion() const;
+
+ void request_code_completion(bool p_force = false);
+
+ void add_code_completion_option(CodeCompletionKind p_type, const String &p_display_text, const String &p_insert_text, const Color &p_text_color = Color(1, 1, 1), const RES &p_icon = RES(), const Variant &p_value = Variant::NIL);
+ void update_code_completion_options(bool p_forced = false);
+
+ TypedArray<Dictionary> get_code_completion_options() const;
+ Dictionary get_code_completion_option(int p_index) const;
+
+ int get_code_completion_selected_index() const;
+ void set_code_completion_selected_index(int p_index);
+
+ void confirm_code_completion(bool p_replace = false);
+ void cancel_code_completion();
+
CodeEdit();
~CodeEdit();
};
+VARIANT_ENUM_CAST(CodeEdit::CodeCompletionKind);
+
#endif // CODEEDIT_H
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index b78f9cad24..f394b9e3a5 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -84,6 +84,55 @@ void ColorPicker::_notification(int p_what) {
}
}
+Ref<Shader> ColorPicker::wheel_shader;
+Ref<Shader> ColorPicker::circle_shader;
+
+void ColorPicker::init_shaders() {
+ wheel_shader.instance();
+ wheel_shader->set_code(
+ "shader_type canvas_item;"
+ "void fragment() {"
+ " float x = UV.x - 0.5;"
+ " float y = UV.y - 0.5;"
+ " float a = atan(y, x);"
+ " x += 0.001;"
+ " y += 0.001;"
+ " float b = float(sqrt(x * x + y * y) < 0.5) * float(sqrt(x * x + y * y) > 0.42);"
+ " x -= 0.002;"
+ " float b2 = float(sqrt(x * x + y * y) < 0.5) * float(sqrt(x * x + y * y) > 0.42);"
+ " y -= 0.002;"
+ " float b3 = float(sqrt(x * x + y * y) < 0.5) * float(sqrt(x * x + y * y) > 0.42);"
+ " x += 0.002;"
+ " float b4 = float(sqrt(x * x + y * y) < 0.5) * float(sqrt(x * x + y * y) > 0.42);"
+ " COLOR = vec4(clamp((abs(fract(((a - TAU) / TAU) + vec3(3.0, 2.0, 1.0) / 3.0) * 6.0 - 3.0) - 1.0), 0.0, 1.0), (b + b2 + b3 + b4) / 4.00);"
+ "}");
+
+ circle_shader.instance();
+ circle_shader->set_code(
+ "shader_type canvas_item;"
+ "uniform float v = 1.0;"
+ "void fragment() {"
+ " float x = UV.x - 0.5;"
+ " float y = UV.y - 0.5;"
+ " float a = atan(y, x);"
+ " x += 0.001;"
+ " y += 0.001;"
+ " float b = float(sqrt(x * x + y * y) < 0.5);"
+ " x -= 0.002;"
+ " float b2 = float(sqrt(x * x + y * y) < 0.5);"
+ " y -= 0.002;"
+ " float b3 = float(sqrt(x * x + y * y) < 0.5);"
+ " x += 0.002;"
+ " float b4 = float(sqrt(x * x + y * y) < 0.5);"
+ " COLOR = vec4(mix(vec3(1.0), clamp(abs(fract(vec3((a - TAU) / TAU) + vec3(1.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - vec3(3.0)) - vec3(1.0), 0.0, 1.0), ((float(sqrt(x * x + y * y)) * 2.0)) / 1.0) * vec3(v), (b + b2 + b3 + b4) / 4.00);"
+ "}");
+}
+
+void ColorPicker::finish_shaders() {
+ wheel_shader.unref();
+ circle_shader.unref();
+}
+
void ColorPicker::set_focus_on_line_edit() {
c_text->call_deferred("grab_focus");
}
@@ -189,6 +238,18 @@ void ColorPicker::set_pick_color(const Color &p_color) {
_set_pick_color(p_color, true); //because setters can't have more arguments
}
+void ColorPicker::set_old_color(const Color &p_color) {
+ old_color = p_color;
+}
+
+void ColorPicker::set_display_old_color(bool p_enabled) {
+ display_old_color = p_enabled;
+}
+
+bool ColorPicker::is_displaying_old_color() const {
+ return display_old_color;
+}
+
void ColorPicker::set_edit_alpha(bool p_show) {
edit_alpha = p_show;
_update_controls();
@@ -228,7 +289,7 @@ void ColorPicker::_value_changed(double) {
emit_signal("color_changed", color);
}
-void ColorPicker::_html_entered(const String &p_html) {
+void ColorPicker::_html_submitted(const String &p_html) {
if (updating || text_is_constructor || !c_text->is_visible()) {
return;
}
@@ -458,18 +519,53 @@ void ColorPicker::_update_text_value() {
c_text->set_visible(visible);
}
+void ColorPicker::_sample_input(const Ref<InputEvent> &p_event) {
+ const Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95));
+ if (rect_old.has_point(mb->get_position())) {
+ // Revert to the old color when left-clicking the old color sample.
+ color = old_color;
+ _update_color();
+ emit_signal("color_changed", color);
+ }
+ }
+}
+
void ColorPicker::_sample_draw() {
- const Rect2 r = Rect2(Point2(), Size2(sample->get_size().width, sample->get_size().height * 0.95));
+ // Covers the right half of the sample if the old color is being displayed,
+ // or the whole sample if it's not being displayed.
+ Rect2 rect_new;
+
+ if (display_old_color) {
+ rect_new = Rect2(Point2(sample->get_size().width * 0.5, 0), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95));
+
+ // Draw both old and new colors for easier comparison (only if spawned from a ColorPickerButton).
+ const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95));
+
+ if (display_old_color && old_color.a < 1.0) {
+ sample->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), rect_old, true);
+ }
+
+ sample->draw_rect(rect_old, old_color);
+
+ if (old_color.r > 1 || old_color.g > 1 || old_color.b > 1) {
+ // Draw an indicator to denote that the old color is "overbright" and can't be displayed accurately in the preview.
+ sample->draw_texture(get_theme_icon("overbright_indicator", "ColorPicker"), Point2());
+ }
+ } else {
+ rect_new = Rect2(Point2(), Size2(sample->get_size().width, sample->get_size().height * 0.95));
+ }
if (color.a < 1.0) {
- sample->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), r, true);
+ sample->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), rect_new, true);
}
- sample->draw_rect(r, color);
+ sample->draw_rect(rect_new, 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_theme_icon("overbright_indicator", "ColorPicker"), Point2());
+ // Draw an indicator to denote that the new color is "overbright" and can't be displayed accurately in the preview.
+ sample->draw_texture(get_theme_icon("overbright_indicator", "ColorPicker"), Point2(uv_edit->get_size().width * 0.5, 0));
}
}
@@ -945,7 +1041,7 @@ void ColorPicker::_html_focus_exit() {
if (c_text->get_menu()->is_visible()) {
return;
}
- _html_entered(c_text->get_text());
+ _html_submitted(c_text->get_text());
_focus_exit();
}
@@ -1033,6 +1129,7 @@ ColorPicker::ColorPicker() :
hb_smpl->add_child(sample);
sample->set_h_size_flags(SIZE_EXPAND_FILL);
+ sample->connect("gui_input", callable_mp(this, &ColorPicker::_sample_input));
sample->connect("draw", callable_mp(this, &ColorPicker::_sample_draw));
btn_pick->set_flat(true);
@@ -1107,7 +1204,7 @@ ColorPicker::ColorPicker() :
hhb->add_child(c_text);
c_text->set_h_size_flags(SIZE_EXPAND_FILL);
- c_text->connect("text_entered", callable_mp(this, &ColorPicker::_html_entered));
+ c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted));
c_text->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter));
c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit));
@@ -1117,14 +1214,8 @@ ColorPicker::ColorPicker() :
hb_edit->add_child(wheel_edit);
wheel_mat.instance();
- circle_mat.instance();
-
- Ref<Shader> wheel_shader(memnew(Shader));
- wheel_shader->set_code("shader_type canvas_item;const float TAU=6.28318530718;void fragment(){float x=UV.x-0.5;float y=UV.y-0.5;float a=atan(y,x);x+=0.001;y+=0.001;float b=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);x-=0.002;float b2=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);y-=0.002;float b3=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);x+=0.002;float b4=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);COLOR=vec4(clamp((abs(fract(((a-TAU)/TAU)+vec3(3.0,2.0,1.0)/3.0)*6.0-3.0)-1.0),0.0,1.0),(b+b2+b3+b4)/4.00);}");
wheel_mat->set_shader(wheel_shader);
-
- Ref<Shader> circle_shader(memnew(Shader));
- circle_shader->set_code("shader_type canvas_item;const float TAU=6.28318530718;uniform float v=1.0;void fragment(){float x=UV.x-0.5;float y=UV.y-0.5;float a=atan(y,x);x+=0.001;y+=0.001;float b=float(sqrt(x*x+y*y)<0.5);x-=0.002;float b2=float(sqrt(x*x+y*y)<0.5);y-=0.002;float b3=float(sqrt(x*x+y*y)<0.5);x+=0.002;float b4=float(sqrt(x*x+y*y)<0.5);COLOR=vec4(mix(vec3(1.0),clamp(abs(fract(vec3((a-TAU)/TAU)+vec3(1.0,2.0/3.0,1.0/3.0))*6.0-vec3(3.0))-vec3(1.0),0.0,1.0),((float(sqrt(x*x+y*y))*2.0))/1.0)*vec3(v),(b+b2+b3+b4)/4.00);}");
+ circle_mat.instance();
circle_mat->set_shader(circle_shader);
MarginContainer *wheel_margin(memnew(MarginContainer));
@@ -1174,6 +1265,13 @@ ColorPicker::ColorPicker() :
/////////////////
+void ColorPickerButton::_about_to_popup() {
+ set_pressed(true);
+ if (picker) {
+ picker->set_old_color(color);
+ }
+}
+
void ColorPickerButton::_color_changed(const Color &p_color) {
color = p_color;
update();
@@ -1286,10 +1384,11 @@ void ColorPickerButton::_update_picker() {
popup->add_child(picker);
add_child(popup);
picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed));
- popup->connect("about_to_popup", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true));
+ popup->connect("about_to_popup", callable_mp(this, &ColorPickerButton::_about_to_popup));
popup->connect("popup_hide", callable_mp(this, &ColorPickerButton::_modal_closed));
picker->set_pick_color(color);
picker->set_edit_alpha(edit_alpha);
+ picker->set_display_old_color(true);
emit_signal("picker_created");
}
}
@@ -1301,6 +1400,7 @@ void ColorPickerButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_popup"), &ColorPickerButton::get_popup);
ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPickerButton::set_edit_alpha);
ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPickerButton::is_editing_alpha);
+ ClassDB::bind_method(D_METHOD("_about_to_popup"), &ColorPickerButton::_about_to_popup);
ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
ADD_SIGNAL(MethodInfo("popup_closed"));
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index a0d2aa95ca..3bd2ff9375 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -56,6 +56,9 @@ public:
};
private:
+ static Ref<Shader> wheel_shader;
+ static Ref<Shader> circle_shader;
+
Control *screen = nullptr;
Control *uv_edit = memnew(Control);
Control *w_edit = memnew(Control);
@@ -86,6 +89,8 @@ private:
PickerShapeType picker_type = SHAPE_HSV_WHEEL;
Color color;
+ Color old_color;
+ bool display_old_color = false;
bool raw_mode_enabled = false;
bool hsv_mode_enabled = false;
bool deferred_mode_enabled = false;
@@ -99,13 +104,14 @@ private:
float v = 0.0;
Color last_hsv;
- void _html_entered(const String &p_html);
+ void _html_submitted(const String &p_html);
void _value_changed(double);
void _update_controls();
void _update_color(bool p_update_sliders = true);
void _update_presets();
void _update_text_value();
void _text_type_toggled();
+ void _sample_input(const Ref<InputEvent> &p_event);
void _sample_draw();
void _hsv_draw(int p_which, Control *c);
void _slider_draw(int p_which);
@@ -125,12 +131,19 @@ protected:
static void _bind_methods();
public:
+ static void init_shaders();
+ static void finish_shaders();
+
void set_edit_alpha(bool p_show);
bool is_editing_alpha() const;
void _set_pick_color(const Color &p_color, bool p_update_sliders);
void set_pick_color(const Color &p_color);
Color get_pick_color() const;
+ void set_old_color(const Color &p_color);
+
+ void set_display_old_color(bool p_enabled);
+ bool is_displaying_old_color() const;
void set_picker_shape(PickerShapeType p_picker_type);
PickerShapeType get_picker_shape() const;
@@ -171,6 +184,7 @@ class ColorPickerButton : public Button {
Color color;
bool edit_alpha = true;
+ void _about_to_popup();
void _color_changed(const Color &p_color);
void _modal_closed();
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index f569fbc420..c84627c21e 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -168,6 +168,12 @@ Size2 Control::_edit_get_minimum_size() const {
}
#endif
+void Control::accept_event() {
+ if (is_inside_tree()) {
+ get_viewport()->_gui_accept_event();
+ }
+}
+
void Control::set_custom_minimum_size(const Size2 &p_custom) {
if (p_custom == data.custom_minimum_size) {
return;
@@ -345,72 +351,72 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const {
List<StringName> names;
theme->get_icon_list(get_class_name(), &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
+ uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
if (data.icon_override.has(E->get())) {
- hint |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
+ usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
}
- p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_icons/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", hint));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_icons/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", usage));
}
}
{
List<StringName> names;
theme->get_stylebox_list(get_class_name(), &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
+ uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
if (data.style_override.has(E->get())) {
- hint |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
+ usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
}
- p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_styles/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", hint));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_styles/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", usage));
}
}
{
List<StringName> names;
theme->get_font_list(get_class_name(), &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
+ uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
if (data.font_override.has(E->get())) {
- hint |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
+ usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
}
- p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_fonts/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "Font", hint));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_fonts/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "Font", usage));
}
}
{
List<StringName> names;
theme->get_font_size_list(get_class_name(), &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
+ uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
if (data.font_size_override.has(E->get())) {
- hint |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
+ usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
}
- p_list->push_back(PropertyInfo(Variant::INT, "custom_font_sizes/" + E->get(), PROPERTY_HINT_NONE, "", hint));
+ p_list->push_back(PropertyInfo(Variant::INT, "custom_font_sizes/" + E->get(), PROPERTY_HINT_NONE, "", usage));
}
}
{
List<StringName> names;
theme->get_color_list(get_class_name(), &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
+ uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
if (data.color_override.has(E->get())) {
- hint |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
+ usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
}
- p_list->push_back(PropertyInfo(Variant::COLOR, "custom_colors/" + E->get(), PROPERTY_HINT_NONE, "", hint));
+ p_list->push_back(PropertyInfo(Variant::COLOR, "custom_colors/" + E->get(), PROPERTY_HINT_NONE, "", usage));
}
}
{
List<StringName> names;
theme->get_constant_list(get_class_name(), &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- uint32_t hint = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
+ uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE;
if (data.constant_override.has(E->get())) {
- hint |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
+ usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
}
- p_list->push_back(PropertyInfo(Variant::INT, "custom_constants/" + E->get(), PROPERTY_HINT_RANGE, "-16384,16384", hint));
+ p_list->push_back(PropertyInfo(Variant::INT, "custom_constants/" + E->get(), PROPERTY_HINT_RANGE, "-16384,16384", usage));
}
}
}
@@ -509,7 +515,9 @@ void Control::_notification(int p_notification) {
get_viewport()->_gui_remove_control(this);
} break;
case NOTIFICATION_READY: {
+#ifdef DEBUG_ENABLED
connect("ready", callable_mp(this, &Control::_clear_size_warning), varray(), CONNECT_DEFERRED | CONNECT_ONESHOT);
+#endif
} break;
case NOTIFICATION_ENTER_CANVAS: {
@@ -654,7 +662,7 @@ bool Control::has_point(const Point2 &p_point) const {
Variant v = p_point;
const Variant *p = &v;
Callable::CallError ce;
- Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->has_point, &p, 1, ce);
+ Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_has_point, &p, 1, ce);
if (ce.error == Callable::CallError::CALL_OK) {
return ret;
}
@@ -679,7 +687,7 @@ Variant Control::get_drag_data(const Point2 &p_point) {
Object *obj = ObjectDB::get_instance(data.drag_owner);
if (obj) {
Control *c = Object::cast_to<Control>(obj);
- return c->call("get_drag_data_fw", p_point, this);
+ return c->call("_get_drag_data_fw", p_point, this);
}
}
@@ -687,7 +695,7 @@ Variant Control::get_drag_data(const Point2 &p_point) {
Variant v = p_point;
const Variant *p = &v;
Callable::CallError ce;
- Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->get_drag_data, &p, 1, ce);
+ Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_get_drag_data, &p, 1, ce);
if (ce.error == Callable::CallError::CALL_OK) {
return ret;
}
@@ -701,7 +709,7 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const
Object *obj = ObjectDB::get_instance(data.drag_owner);
if (obj) {
Control *c = Object::cast_to<Control>(obj);
- return c->call("can_drop_data_fw", p_point, p_data, this);
+ return c->call("_can_drop_data_fw", p_point, p_data, this);
}
}
@@ -709,7 +717,7 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const
Variant v = p_point;
const Variant *p[2] = { &v, &p_data };
Callable::CallError ce;
- Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->can_drop_data, p, 2, ce);
+ Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_can_drop_data, p, 2, ce);
if (ce.error == Callable::CallError::CALL_OK) {
return ret;
}
@@ -723,7 +731,7 @@ void Control::drop_data(const Point2 &p_point, const Variant &p_data) {
Object *obj = ObjectDB::get_instance(data.drag_owner);
if (obj) {
Control *c = Object::cast_to<Control>(obj);
- c->call("drop_data_fw", p_point, p_data, this);
+ c->call("_drop_data_fw", p_point, p_data, this);
return;
}
}
@@ -732,7 +740,7 @@ void Control::drop_data(const Point2 &p_point, const Variant &p_data) {
Variant v = p_point;
const Variant *p[2] = { &v, &p_data };
Callable::CallError ce;
- Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->drop_data, p, 2, ce);
+ Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_drop_data, p, 2, ce);
if (ce.error == Callable::CallError::CALL_OK) {
return;
}
@@ -765,32 +773,27 @@ Size2 Control::get_minimum_size() 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_node_type) {
- // try with custom themes
+T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
+ ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified.");
+
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // For each control iterate through its inheritance chain and see if p_name exists in any of them.
Control *theme_owner = p_theme_owner;
Window *theme_owner_window = p_theme_owner_window;
while (theme_owner || theme_owner_window) {
- StringName class_name = p_node_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;
+ for (List<StringName>::Element *E = p_theme_types.front(); E; E = E->next()) {
+ if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E->get())) {
+ return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E->get());
}
- 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;
+ if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E->get())) {
+ return theme_owner_window->theme->get_theme_item(p_data_type, p_name, E->get());
}
-
- 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;
@@ -805,33 +808,47 @@ bool Control::_find_theme_item(Control *p_theme_owner, Window *p_theme_owner_win
}
}
}
- return false;
+
+ // Secondly, check the project-defined Theme resource.
+ if (Theme::get_project_default().is_valid()) {
+ for (List<StringName>::Element *E = p_theme_types.front(); E; E = E->next()) {
+ if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E->get())) {
+ return Theme::get_project_default()->get_theme_item(p_data_type, p_name, E->get());
+ }
+ }
+ }
+
+ // Lastly, fall back on the items defined in the default Theme, if they exist.
+ for (List<StringName>::Element *E = p_theme_types.front(); E; E = E->next()) {
+ if (Theme::get_default()->has_theme_item(p_data_type, p_name, E->get())) {
+ return Theme::get_default()->get_theme_item(p_data_type, p_name, E->get());
+ }
+ }
+ // If they don't exist, use any type to return the default/empty value.
+ return Theme::get_default()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
}
-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_node_type) {
- // try with custom themes
+bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
+ ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
+
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // For each control iterate through its inheritance chain and see if p_name exists in any of them.
Control *theme_owner = p_theme_owner;
Window *theme_owner_window = p_theme_owner_window;
while (theme_owner || theme_owner_window) {
- StringName class_name = p_node_type;
-
- while (class_name != StringName()) {
- if (theme_owner && (theme_owner->data.theme.operator->()->*has_func)(p_name, class_name)) {
+ for (List<StringName>::Element *E = p_theme_types.front(); E; E = E->next()) {
+ if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E->get())) {
return true;
}
- if (theme_owner_window && (theme_owner_window->theme.operator->()->*has_func)(p_name, class_name)) {
+ if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E->get())) {
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;
@@ -846,179 +863,112 @@ bool Control::_has_theme_item(Control *p_theme_owner, Window *p_theme_owner_wind
}
}
}
- return false;
-}
-Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
- const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
- if (tex) {
- return *tex;
+ // Secondly, check the project-defined Theme resource.
+ if (Theme::get_project_default().is_valid()) {
+ for (List<StringName>::Element *E = p_theme_types.front(); E; E = E->next()) {
+ if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E->get())) {
+ return true;
+ }
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return get_icons(data.theme_owner, data.theme_owner_window, p_name, type);
+ // Lastly, fall back on the items defined in the default Theme, if they exist.
+ for (List<StringName>::Element *E = p_theme_types.front(); E; E = E->next()) {
+ if (Theme::get_default()->has_theme_item(p_data_type, p_name, E->get())) {
+ return true;
+ }
+ }
+ return false;
}
-Ref<Texture2D> Control::get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_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_node_type)) {
- return icon;
+void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ if (data.theme_custom_type != StringName()) {
+ p_list->push_back(data.theme_custom_type);
+ }
+ Theme::get_type_dependencies(get_class_name(), p_list);
+ } else {
+ Theme::get_type_dependencies(p_theme_type, p_list);
}
+}
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_icon(p_name, p_node_type)) {
- return Theme::get_project_default()->get_icon(p_name, p_node_type);
+Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
+ const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
+ if (tex) {
+ return *tex;
}
}
- return Theme::get_default()->get_icon(p_name, p_node_type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
}
-Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
const Ref<StyleBox> *style = data.style_override.getptr(p_name);
if (style) {
return *style;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return get_styleboxs(data.theme_owner, data.theme_owner_window, p_name, type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
-Ref<StyleBox> Control::get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- Ref<StyleBox> stylebox;
-
- if (_find_theme_item(p_theme_owner, p_theme_owner_window, stylebox, &Theme::get_stylebox, &Theme::has_stylebox, p_name, p_node_type)) {
- return stylebox;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_stylebox(p_name, p_node_type)) {
- return Theme::get_project_default()->get_stylebox(p_name, p_node_type);
- }
- }
-
- return Theme::get_default()->get_stylebox(p_name, p_node_type);
-}
-
-Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
const Ref<Font> *font = data.font_override.getptr(p_name);
if (font) {
return *font;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return get_fonts(data.theme_owner, data.theme_owner_window, p_name, type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
}
-int Control::get_theme_font_size(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+int Control::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
const int *font_size = data.font_size_override.getptr(p_name);
if (font_size) {
return *font_size;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return get_font_sizes(data.theme_owner, data.theme_owner_window, p_name, type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
-Ref<Font> Control::get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- Ref<Font> font;
-
- if (_find_theme_item(p_theme_owner, p_theme_owner_window, font, &Theme::get_font, &Theme::has_font, p_name, p_node_type)) {
- return font;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_font(p_name, p_node_type)) {
- return Theme::get_project_default()->get_font(p_name, p_node_type);
- }
- }
-
- return Theme::get_default()->get_font(p_name, p_node_type);
-}
-
-int Control::get_font_sizes(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- int font_size;
-
- if (_find_theme_item(p_theme_owner, p_theme_owner_window, font_size, &Theme::get_font_size, &Theme::has_font_size, p_name, p_node_type)) {
- return font_size;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_font_size(p_name, p_node_type)) {
- return Theme::get_project_default()->get_font_size(p_name, p_node_type);
- }
- }
-
- return Theme::get_default()->get_font_size(p_name, p_node_type);
-}
-
-Color Control::get_theme_color(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+Color Control::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
const Color *color = data.color_override.getptr(p_name);
if (color) {
return *color;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return get_colors(data.theme_owner, data.theme_owner_window, p_name, type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
-Color Control::get_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- Color color;
-
- if (_find_theme_item(p_theme_owner, p_theme_owner_window, color, &Theme::get_color, &Theme::has_color, p_name, p_node_type)) {
- return color;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_color(p_name, p_node_type)) {
- return Theme::get_project_default()->get_color(p_name, p_node_type);
- }
- }
- return Theme::get_default()->get_color(p_name, p_node_type);
-}
-
-int Control::get_theme_constant(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+int Control::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
const int *constant = data.constant_override.getptr(p_name);
if (constant) {
return *constant;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return get_constants(data.theme_owner, data.theme_owner_window, p_name, type);
-}
-
-int Control::get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- int constant;
-
- if (_find_theme_item(p_theme_owner, p_theme_owner_window, constant, &Theme::get_constant, &Theme::has_constant, p_name, p_node_type)) {
- return constant;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_constant(p_name, p_node_type)) {
- return Theme::get_project_default()->get_constant(p_name, p_node_type);
- }
- }
- return Theme::get_default()->get_constant(p_name, p_node_type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
bool Control::has_theme_icon_override(const StringName &p_name) const {
@@ -1051,154 +1001,76 @@ bool Control::has_theme_constant_override(const StringName &p_name) const {
return constant != nullptr;
}
-bool Control::has_theme_icon(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
if (has_theme_icon_override(p_name)) {
return true;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return has_icons(data.theme_owner, data.theme_owner_window, p_name, type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
}
-bool Control::has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_icon, p_name, p_node_type)) {
- return true;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_color(p_name, p_node_type)) {
- return true;
- }
- }
- return Theme::get_default()->has_icon(p_name, p_node_type);
-}
-
-bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
if (has_theme_stylebox_override(p_name)) {
return true;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return has_styleboxs(data.theme_owner, data.theme_owner_window, p_name, type);
-}
-
-bool Control::has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_stylebox, p_name, p_node_type)) {
- return true;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_stylebox(p_name, p_node_type)) {
- return true;
- }
- }
- return Theme::get_default()->has_stylebox(p_name, p_node_type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
-bool Control::has_theme_font(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
if (has_theme_font_override(p_name)) {
return true;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return has_fonts(data.theme_owner, data.theme_owner_window, p_name, type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
}
-bool Control::has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_font, p_name, p_node_type)) {
- return true;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_font(p_name, p_node_type)) {
- return true;
- }
- }
- return Theme::get_default()->has_font(p_name, p_node_type);
-}
-
-bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
if (has_theme_font_size_override(p_name)) {
return true;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return has_font_sizes(data.theme_owner, data.theme_owner_window, p_name, type);
-}
-
-bool Control::has_font_sizes(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_font_size, p_name, p_node_type)) {
- return true;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_font_size(p_name, p_node_type)) {
- return true;
- }
- }
- return Theme::get_default()->has_font_size(p_name, p_node_type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
-bool Control::has_theme_color(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+bool Control::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
if (has_theme_color_override(p_name)) {
return true;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- 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_node_type) {
- if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_color, p_name, p_node_type)) {
- return true;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_color(p_name, p_node_type)) {
- return true;
- }
- }
- return Theme::get_default()->has_color(p_name, p_node_type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
-bool Control::has_theme_constant(const StringName &p_name, const StringName &p_node_type) const {
- if (p_node_type == StringName() || p_node_type == get_class_name()) {
+bool Control::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_custom_type) {
if (has_theme_constant_override(p_name)) {
return true;
}
}
- StringName type = p_node_type ? p_node_type : get_class_name();
-
- return has_constants(data.theme_owner, data.theme_owner_window, p_name, p_node_type);
-}
-
-bool Control::has_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type) {
- if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_constant, p_name, p_node_type)) {
- return true;
- }
-
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_constant(p_name, p_node_type)) {
- return true;
- }
- }
- return Theme::get_default()->has_constant(p_name, p_node_type);
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
Rect2 Control::get_parent_anchorable_rect() const {
@@ -1709,8 +1581,8 @@ void Control::set_rect(const Rect2 &p_rect) {
void Control::_set_size(const Size2 &p_size) {
#ifdef DEBUG_ENABLED
- if (data.size_warning) {
- WARN_PRINT("Adjusting the size of Control nodes before they are fully initialized is unreliable. Consider deferring it with set_deferred().");
+ if (data.size_warning && (data.anchor[SIDE_LEFT] != data.anchor[SIDE_RIGHT] || data.anchor[SIDE_TOP] != data.anchor[SIDE_BOTTOM])) {
+ WARN_PRINT("Nodes with non-equal opposite anchors will have their size overriden after _ready(). \nIf you want to set size, change the anchors or consider using set_deferred().");
}
#endif
set_size(p_size);
@@ -2171,16 +2043,19 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
}
}
-void Control::accept_event() {
- if (is_inside_tree()) {
- get_viewport()->_gui_accept_event();
- }
-}
-
Ref<Theme> Control::get_theme() const {
return data.theme;
}
+void Control::set_theme_custom_type(const StringName &p_theme_type) {
+ data.theme_custom_type = p_theme_type;
+ _propagate_theme_changed(this, data.theme_owner, data.theme_owner_window);
+}
+
+StringName Control::get_theme_custom_type() const {
+ return data.theme_custom_type;
+}
+
void Control::set_tooltip(const String &p_tooltip) {
data.tooltip = p_tooltip;
update_configuration_warnings();
@@ -2499,9 +2374,9 @@ bool Control::is_text_field() const {
return false;
}
-Vector<Vector2i> Control::structured_text_parser(StructuredTextParser p_node_type, const Array &p_args, const String p_text) const {
+Vector<Vector2i> Control::structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String p_text) const {
Vector<Vector2i> ret;
- switch (p_node_type) {
+ switch (p_theme_type) {
case STRUCTURED_TEXT_URI: {
int prev = 0;
for (int i = 0; i < p_text.length(); i++) {
@@ -2688,15 +2563,15 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
if (p_idx == 0) {
List<StringName> sn;
String pf = p_function;
- if (pf == "add_color_override" || pf == "has_color" || pf == "has_color_override" || pf == "get_color") {
+ if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color") {
Theme::get_default()->get_color_list(get_class(), &sn);
- } else if (pf == "add_style_override" || pf == "has_style" || pf == "has_style_override" || pf == "get_style") {
+ } else if (pf == "add_theme_style_override" || pf == "has_theme_style" || pf == "has_theme_style_override" || pf == "get_theme_style") {
Theme::get_default()->get_stylebox_list(get_class(), &sn);
- } else if (pf == "add_font_override" || pf == "has_font" || pf == "has_font_override" || pf == "get_font") {
+ } else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font") {
Theme::get_default()->get_font_list(get_class(), &sn);
- } else if (pf == "add_font_size_override" || pf == "has_font_size" || pf == "has_font_size_override" || pf == "get_font_size") {
+ } else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size") {
Theme::get_default()->get_font_size_list(get_class(), &sn);
- } else if (pf == "add_constant_override" || pf == "has_constant" || pf == "has_constant_override" || pf == "get_constant") {
+ } else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant") {
Theme::get_default()->get_constant_list(get_class(), &sn);
}
@@ -2811,6 +2686,9 @@ 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("set_theme_custom_type", "theme_type"), &Control::set_theme_custom_type);
+ ClassDB::bind_method(D_METHOD("get_theme_custom_type"), &Control::get_theme_custom_type);
+
ClassDB::bind_method(D_METHOD("add_theme_icon_override", "name", "texture"), &Control::add_theme_icon_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);
@@ -2825,12 +2703,12 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_theme_color_override", "name"), &Control::remove_theme_color_override);
ClassDB::bind_method(D_METHOD("remove_theme_constant_override", "name"), &Control::remove_theme_constant_override);
- ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "node_type"), &Control::get_theme_icon, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "node_type"), &Control::get_theme_stylebox, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_theme_font", "name", "node_type"), &Control::get_theme_font, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_theme_font_size", "name", "node_type"), &Control::get_theme_font_size, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_theme_color", "name", "node_type"), &Control::get_theme_color, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "node_type"), &Control::get_theme_constant, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "theme_type"), &Control::get_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "theme_type"), &Control::get_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_font", "name", "theme_type"), &Control::get_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_font_size", "name", "theme_type"), &Control::get_theme_font_size, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_color", "name", "theme_type"), &Control::get_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "theme_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_stylebox_override", "name"), &Control::has_theme_stylebox_override);
@@ -2839,12 +2717,12 @@ void Control::_bind_methods() {
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", "node_type"), &Control::has_theme_icon, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "node_type"), &Control::has_theme_stylebox, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_font", "name", "node_type"), &Control::has_theme_font, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_font_size", "name", "node_type"), &Control::has_theme_font_size, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_color", "name", "node_type"), &Control::has_theme_color, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "node_type"), &Control::has_theme_constant, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_icon", "name", "theme_type"), &Control::has_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "theme_type"), &Control::has_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_font", "name", "theme_type"), &Control::has_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_font_size", "name", "theme_type"), &Control::has_theme_font_size, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Control::has_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Control::has_theme_constant, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_parent_control"), &Control::get_parent_control);
@@ -2897,12 +2775,12 @@ void Control::_bind_methods() {
BIND_VMETHOD(MethodInfo("_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_get_minimum_size"));
- MethodInfo get_drag_data = MethodInfo("get_drag_data", PropertyInfo(Variant::VECTOR2, "position"));
+ MethodInfo get_drag_data = MethodInfo("_get_drag_data", PropertyInfo(Variant::VECTOR2, "position"));
get_drag_data.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
BIND_VMETHOD(get_drag_data);
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
- BIND_VMETHOD(MethodInfo("drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
+ BIND_VMETHOD(MethodInfo("_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
BIND_VMETHOD(MethodInfo(
PropertyInfo(Variant::OBJECT, "control", PROPERTY_HINT_RESOURCE_TYPE, "Control"),
"_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text")));
@@ -2925,7 +2803,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_vertical", PROPERTY_HINT_ENUM, "Begin,End,Both"), "set_v_grow_direction", "get_v_grow_direction");
ADD_GROUP("Layout Direction", "layout_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-right,Right-to-left"), "set_layout_direction", "get_layout_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
ADD_GROUP("Rect", "rect_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_position", "get_position");
@@ -2952,14 +2830,15 @@ void Control::_bind_methods() {
ADD_GROUP("Mouse", "mouse_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_filter", PROPERTY_HINT_ENUM, "Stop,Pass,Ignore"), "set_mouse_filter", "get_mouse_filter");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_default_cursor_shape", PROPERTY_HINT_ENUM, "Arrow,Ibeam,Pointing hand,Cross,Wait,Busy,Drag,Can drop,Forbidden,Vertical resize,Horizontal resize,Secondary diagonal resize,Main diagonal resize,Move,Vertical split,Horizontal split,Help"), "set_default_cursor_shape", "get_default_cursor_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_default_cursor_shape", PROPERTY_HINT_ENUM, "Arrow,I-Beam,Pointing Hand,Cross,Wait,Busy,Drag,Can Drop,Forbidden,Vertical Resize,Horizontal Resize,Secondary Diagonal Resize,Main Diagonal Resize,Move,Vertical Split,Horizontal Split,Help"), "set_default_cursor_shape", "get_default_cursor_shape");
ADD_GROUP("Size Flags", "size_flags_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_horizontal", PROPERTY_HINT_FLAGS, "Fill,Expand,Shrink Center,Shrink End"), "set_h_size_flags", "get_h_size_flags");
ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_vertical", PROPERTY_HINT_FLAGS, "Fill,Expand,Shrink Center,Shrink End"), "set_v_size_flags", "get_v_size_flags");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size_flags_stretch_ratio", PROPERTY_HINT_RANGE, "0,20,0.01,or_greater"), "set_stretch_ratio", "get_stretch_ratio");
- ADD_GROUP("Theme", "");
+ ADD_GROUP("Theme", "theme_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_custom_type"), "set_theme_custom_type", "get_theme_custom_type");
ADD_GROUP("", "");
BIND_ENUM_CONSTANT(FOCUS_NONE);
@@ -3061,5 +2940,5 @@ void Control::_bind_methods() {
ADD_SIGNAL(MethodInfo("minimum_size_changed"));
ADD_SIGNAL(MethodInfo("theme_changed"));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_point", PropertyInfo(Variant::VECTOR2, "point")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_has_point", PropertyInfo(Variant::VECTOR2, "point")));
}
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 1f397df589..a05025c32d 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -201,6 +201,8 @@ private:
Ref<Theme> theme;
Control *theme_owner = nullptr;
Window *theme_owner_window = nullptr;
+ StringName theme_custom_type;
+
String tooltip;
CursorShape default_cursor = CURSOR_ARROW;
@@ -258,23 +260,9 @@ private:
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_node_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_node_type);
-
- static Ref<Texture2D> get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static Ref<StyleBox> get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static Ref<Font> get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static int get_font_sizes(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static Color get_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static int get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
-
- static bool has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static bool has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static bool has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static bool has_font_sizes(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static bool has_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
- static bool has_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_node_type = StringName());
+ static T get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
+ static bool has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
+ _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
protected:
virtual void add_child_notify(Node *p_child) override;
@@ -282,7 +270,7 @@ protected:
//virtual void _window_gui_input(InputEvent p_event);
- virtual Vector<Vector2i> structured_text_parser(StructuredTextParser p_node_type, const Array &p_args, const String p_text) const;
+ virtual Vector<Vector2i> structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String p_text) const;
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -415,6 +403,9 @@ public:
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
+ void set_theme_custom_type(const StringName &p_theme_type);
+ StringName get_theme_custom_type() const;
+
void set_h_size_flags(int p_flags);
int get_h_size_flags() const;
@@ -466,12 +457,12 @@ public:
void remove_theme_color_override(const StringName &p_name);
void remove_theme_constant_override(const StringName &p_name);
- Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- int get_theme_font_size(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- Color get_theme_color(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- int get_theme_constant(const StringName &p_name, const StringName &p_node_type = StringName()) const;
+ Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ int get_theme_font_size(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Color get_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ int get_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
bool has_theme_icon_override(const StringName &p_name) const;
bool has_theme_stylebox_override(const StringName &p_name) const;
@@ -480,12 +471,12 @@ public:
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_node_type = StringName()) const;
- bool has_theme_stylebox(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- bool has_theme_font(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- bool has_theme_font_size(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- bool has_theme_color(const StringName &p_name, const StringName &p_node_type = StringName()) const;
- bool has_theme_constant(const StringName &p_name, const StringName &p_node_type = StringName()) const;
+ bool has_theme_icon(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_font(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_font_size(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
/* TOOLTIP */
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index b6884bd37d..f63ae7569f 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -97,7 +97,7 @@ void AcceptDialog::_notification(int p_what) {
}
}
-void AcceptDialog::_text_entered(const String &p_text) {
+void AcceptDialog::_text_submitted(const String &p_text) {
_ok_pressed();
}
@@ -155,11 +155,11 @@ bool AcceptDialog::has_autowrap() {
return label->has_autowrap();
}
-void AcceptDialog::register_text_enter(Node *p_line_edit) {
+void AcceptDialog::register_text_enter(Control *p_line_edit) {
ERR_FAIL_NULL(p_line_edit);
LineEdit *line_edit = Object::cast_to<LineEdit>(p_line_edit);
if (line_edit) {
- line_edit->connect("text_entered", callable_mp(this, &AcceptDialog::_text_entered));
+ line_edit->connect("text_submitted", callable_mp(this, &AcceptDialog::_text_submitted));
}
}
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index b072055d49..d389806fff 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -69,7 +69,7 @@ protected:
virtual void custom_action(const String &) {}
// Not private since used by derived classes signal.
- void _text_entered(const String &p_text);
+ void _text_submitted(const String &p_text);
void _ok_pressed();
void _cancel_pressed();
@@ -77,7 +77,7 @@ public:
Label *get_label() { return label; }
static void set_swap_cancel_ok(bool p_swap);
- void register_text_enter(Node *p_line_edit);
+ void register_text_enter(Control *p_line_edit);
Button *get_ok_button() { return ok; }
Button *add_button(const String &p_text, bool p_right = false, const String &p_action = "");
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 5409b44b9e..f8cee6daec 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -105,7 +105,7 @@ void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
switch (k->get_keycode()) {
case KEY_H: {
- if (k->get_command()) {
+ if (k->is_command_pressed()) {
set_show_hidden_files(!show_hidden_files);
} else {
handled = false;
@@ -116,7 +116,7 @@ void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
invalidate();
} break;
case KEY_BACKSPACE: {
- _dir_entered("..");
+ _dir_submitted("..");
} break;
default: {
handled = false;
@@ -156,7 +156,7 @@ void FileDialog::update_dir() {
deselect_all();
}
-void FileDialog::_dir_entered(String p_dir) {
+void FileDialog::_dir_submitted(String p_dir) {
dir_access->change_dir(p_dir);
file->set_text("");
invalidate();
@@ -164,7 +164,7 @@ void FileDialog::_dir_entered(String p_dir) {
_push_history();
}
-void FileDialog::_file_entered(const String &p_file) {
+void FileDialog::_file_submitted(const String &p_file) {
_action_pressed();
}
@@ -589,8 +589,8 @@ void FileDialog::update_file_list() {
files.pop_front();
}
- if (tree->get_root() && tree->get_root()->get_children() && tree->get_selected() == nullptr) {
- tree->get_root()->get_children()->select(0);
+ if (tree->get_root() && tree->get_root()->get_first_child() && tree->get_selected() == nullptr) {
+ tree->get_root()->get_first_child()->select(0);
}
}
@@ -1020,8 +1020,8 @@ FileDialog::FileDialog() {
tree->connect("cell_selected", callable_mp(this, &FileDialog::_tree_selected), varray(), CONNECT_DEFERRED);
tree->connect("item_activated", callable_mp(this, &FileDialog::_tree_item_activated), varray());
tree->connect("nothing_selected", callable_mp(this, &FileDialog::deselect_all));
- dir->connect("text_entered", callable_mp(this, &FileDialog::_dir_entered));
- file->connect("text_entered", callable_mp(this, &FileDialog::_file_entered));
+ dir->connect("text_submitted", callable_mp(this, &FileDialog::_dir_submitted));
+ file->connect("text_submitted", callable_mp(this, &FileDialog::_file_submitted));
filter->connect("item_selected", callable_mp(this, &FileDialog::_filter_selected));
confirm_save = memnew(ConfirmationDialog);
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 4996f00cb3..7fbafc4bb4 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -32,7 +32,7 @@
#define FILE_DIALOG_H
#include "box_container.h"
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/option_button.h"
@@ -118,8 +118,8 @@ private:
void _select_drive(int p_idx);
void _tree_item_activated();
- void _dir_entered(String p_dir);
- void _file_entered(const String &p_file);
+ void _dir_submitted(String p_dir);
+ void _file_submitted(const String &p_file);
void _action_pressed();
void _save_confirm_pressed();
void _cancel_pressed();
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index e72709e847..7278ca6e94 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -107,7 +107,7 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
//Show color picker on double click.
- if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_doubleclick() && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_double_click() && mb->is_pressed()) {
grabbed = _get_point_from_pos(mb->get_position().x);
_show_color_picker();
accept_event();
@@ -127,7 +127,7 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
//Hold alt key to duplicate selected color
- if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed() && mb->get_alt()) {
+ if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed() && mb->is_alt_pressed()) {
int x = mb->get_position().x;
grabbed = _get_point_from_pos(x);
@@ -236,9 +236,9 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
// Snap to "round" coordinates if holding Ctrl.
// Be more precise if holding Shift as well
- if (mm->get_control()) {
- newofs = Math::snapped(newofs, mm->get_shift() ? 0.025 : 0.1);
- } else if (mm->get_shift()) {
+ if (mm->is_ctrl_pressed()) {
+ newofs = Math::snapped(newofs, mm->is_shift_pressed() ? 0.025 : 0.1);
+ } else if (mm->is_shift_pressed()) {
// Snap to nearest point if holding just Shift
const float snap_threshold = 0.03;
float smallest_ofs = snap_threshold;
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 06c9cf1b63..57d395e894 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -40,11 +40,6 @@
#include "editor/editor_scale.h"
#endif
-#define ZOOM_SCALE 1.2
-
-#define MIN_ZOOM (((1 / ZOOM_SCALE) / ZOOM_SCALE) / ZOOM_SCALE)
-#define MAX_ZOOM (1 * ZOOM_SCALE * ZOOM_SCALE * ZOOM_SCALE)
-
#define MINIMAP_OFFSET 12
#define MINIMAP_PADDING 5
@@ -824,7 +819,7 @@ void GraphEdit::_bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors,
}
}
-void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio = 1.0) {
+void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio) {
//cubic bezier code
float diff = p_to.x - p_from.x;
float cp_offset;
@@ -1091,7 +1086,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() ^ Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
const int snap = get_snap();
pos = pos.snapped(Vector2(snap, snap));
}
@@ -1174,7 +1169,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
}
if (b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed() && dragging) {
- if (!just_selected && drag_accum == Vector2() && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (!just_selected && drag_accum == Vector2() && Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
//deselect current node
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -1238,7 +1233,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
dragging = true;
drag_accum = Vector2();
just_selected = !gn->is_selected();
- if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (o_gn) {
@@ -1275,7 +1270,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
box_selecting = true;
box_selecting_from = b->get_position();
- if (b->get_control()) {
+ if (b->is_ctrl_pressed()) {
box_selection_mode_additive = true;
previous_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -1286,7 +1281,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
previous_selected.push_back(gn2);
}
- } else if (b->get_shift()) {
+ } else if (b->is_shift_pressed()) {
box_selection_mode_additive = false;
previous_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -1322,10 +1317,10 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
minimap->update();
}
- if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
- set_zoom_custom(zoom * ZOOM_SCALE, b->get_position());
- } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
- set_zoom_custom(zoom / ZOOM_SCALE, b->get_position());
+ if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
+ set_zoom_custom(zoom * zoom_step, b->get_position());
+ } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
+ set_zoom_custom(zoom / zoom_step, b->get_position());
} else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8);
} else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
@@ -1392,19 +1387,19 @@ void GraphEdit::set_zoom(float p_zoom) {
}
void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) {
- p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM);
+ p_zoom = CLAMP(p_zoom, zoom_min, zoom_max);
if (zoom == p_zoom) {
return;
}
- zoom_minus->set_disabled(zoom == MIN_ZOOM);
- zoom_plus->set_disabled(zoom == MAX_ZOOM);
-
Vector2 sbofs = (Vector2(h_scroll->get_value(), v_scroll->get_value()) + p_center) / zoom;
zoom = p_zoom;
top_layer->update();
+ zoom_minus->set_disabled(zoom == zoom_min);
+ zoom_plus->set_disabled(zoom == zoom_max);
+
_update_scroll();
minimap->update();
connections_layer->update();
@@ -1415,6 +1410,7 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) {
v_scroll->set_value(ofs.y);
}
+ _update_zoom_label();
update();
}
@@ -1422,6 +1418,61 @@ float GraphEdit::get_zoom() const {
return zoom;
}
+void GraphEdit::set_zoom_step(float p_zoom_step) {
+ p_zoom_step = abs(p_zoom_step);
+ if (zoom_step == p_zoom_step) {
+ return;
+ }
+
+ zoom_step = p_zoom_step;
+}
+
+float GraphEdit::get_zoom_step() const {
+ return zoom_step;
+}
+
+void GraphEdit::set_zoom_min(float p_zoom_min) {
+ ERR_FAIL_COND_MSG(p_zoom_min > zoom_max, "Cannot set min zoom level greater than max zoom level.");
+
+ if (zoom_min == p_zoom_min) {
+ return;
+ }
+
+ zoom_min = p_zoom_min;
+ set_zoom(zoom);
+}
+
+float GraphEdit::get_zoom_min() const {
+ return zoom_min;
+}
+
+void GraphEdit::set_zoom_max(float p_zoom_max) {
+ ERR_FAIL_COND_MSG(p_zoom_max < zoom_min, "Cannot set max zoom level lesser than min zoom level.");
+
+ if (zoom_max == p_zoom_max) {
+ return;
+ }
+
+ zoom_max = p_zoom_max;
+ set_zoom(zoom);
+}
+
+float GraphEdit::get_zoom_max() const {
+ return zoom_max;
+}
+
+void GraphEdit::set_show_zoom_label(bool p_enable) {
+ if (zoom_label->is_visible() == p_enable) {
+ return;
+ }
+
+ zoom_label->set_visible(p_enable);
+}
+
+bool GraphEdit::is_showing_zoom_label() const {
+ return zoom_label->is_visible();
+}
+
void GraphEdit::set_right_disconnects(bool p_enable) {
right_disconnects = p_enable;
}
@@ -1462,7 +1513,7 @@ Array GraphEdit::_get_connection_list() const {
}
void GraphEdit::_zoom_minus() {
- set_zoom(zoom / ZOOM_SCALE);
+ set_zoom(zoom / zoom_step);
}
void GraphEdit::_zoom_reset() {
@@ -1470,7 +1521,13 @@ void GraphEdit::_zoom_reset() {
}
void GraphEdit::_zoom_plus() {
- set_zoom(zoom * ZOOM_SCALE);
+ set_zoom(zoom * zoom_step);
+}
+
+void GraphEdit::_update_zoom_label() {
+ int zoom_percent = static_cast<int>(Math::round(zoom * 100));
+ String zoom_text = itos(zoom_percent) + "%";
+ zoom_label->set_text(zoom_text);
}
void GraphEdit::add_valid_connection_type(int p_type, int p_with_type) {
@@ -1611,6 +1668,18 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &GraphEdit::set_zoom);
ClassDB::bind_method(D_METHOD("get_zoom"), &GraphEdit::get_zoom);
+ ClassDB::bind_method(D_METHOD("set_zoom_min", "zoom_min"), &GraphEdit::set_zoom_min);
+ ClassDB::bind_method(D_METHOD("get_zoom_min"), &GraphEdit::get_zoom_min);
+
+ ClassDB::bind_method(D_METHOD("set_zoom_max", "zoom_max"), &GraphEdit::set_zoom_max);
+ ClassDB::bind_method(D_METHOD("get_zoom_max"), &GraphEdit::get_zoom_max);
+
+ ClassDB::bind_method(D_METHOD("set_zoom_step", "zoom_step"), &GraphEdit::set_zoom_step);
+ ClassDB::bind_method(D_METHOD("get_zoom_step"), &GraphEdit::get_zoom_step);
+
+ ClassDB::bind_method(D_METHOD("set_show_zoom_label", "enable"), &GraphEdit::set_show_zoom_label);
+ ClassDB::bind_method(D_METHOD("is_showing_zoom_label"), &GraphEdit::is_showing_zoom_label);
+
ClassDB::bind_method(D_METHOD("set_snap", "pixels"), &GraphEdit::set_snap);
ClassDB::bind_method(D_METHOD("get_snap"), &GraphEdit::get_snap);
@@ -1645,9 +1714,18 @@ void GraphEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset"), "set_scroll_ofs", "get_scroll_ofs");
ADD_PROPERTY(PropertyInfo(Variant::INT, "snap_distance"), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_snap"), "set_use_snap", "is_using_snap");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom"), "set_zoom", "get_zoom");
+
+ ADD_GROUP("Connection Lines", "connection_lines");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_thickness"), "set_connection_lines_thickness", "get_connection_lines_thickness");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "connection_lines_antialiased"), "set_connection_lines_antialiased", "is_connection_lines_antialiased");
+
+ ADD_GROUP("Zoom", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom"), "set_zoom", "get_zoom");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom_min"), "set_zoom_min", "get_zoom_min");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom_max"), "set_zoom_max", "get_zoom_max");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom_step"), "set_zoom_step", "get_zoom_step");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_zoom_label"), "set_show_zoom_label", "is_showing_zoom_label");
+
ADD_GROUP("Minimap", "minimap");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "minimap_enabled"), "set_minimap_enabled", "is_minimap_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimap_size"), "set_minimap_size", "get_minimap_size");
@@ -1672,6 +1750,13 @@ void GraphEdit::_bind_methods() {
GraphEdit::GraphEdit() {
set_focus_mode(FOCUS_ALL);
+ // Allow dezooming 8 times from the default zoom level.
+ // At low zoom levels, text is unreadable due to its small size and poor filtering,
+ // but this is still useful for previewing purposes.
+ zoom_min = (1 / Math::pow(zoom_step, 8));
+ // Allow zooming 4 times from the default zoom level.
+ zoom_max = (1 * Math::pow(zoom_step, 4));
+
top_layer = memnew(GraphEditFilter(this));
add_child(top_layer);
top_layer->set_mouse_filter(MOUSE_FILTER_PASS);
@@ -1708,6 +1793,18 @@ GraphEdit::GraphEdit() {
top_layer->add_child(zoom_hb);
zoom_hb->set_position(Vector2(10, 10));
+ zoom_label = memnew(Label);
+ zoom_hb->add_child(zoom_label);
+ zoom_label->set_visible(false);
+ zoom_label->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
+ zoom_label->set_align(Label::ALIGN_CENTER);
+#ifdef TOOLS_ENABLED
+ zoom_label->set_custom_minimum_size(Size2(48, 0) * EDSCALE);
+#else
+ zoom_label->set_custom_minimum_size(Size2(48, 0));
+#endif
+ _update_zoom_label();
+
zoom_minus = memnew(Button);
zoom_minus->set_flat(true);
zoom_hb->add_child(zoom_minus);
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index fa3b113705..e8300f901c 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -34,6 +34,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/graph_node.h"
+#include "scene/gui/label.h"
#include "scene/gui/scroll_bar.h"
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
@@ -105,6 +106,7 @@ public:
};
private:
+ Label *zoom_label;
Button *zoom_minus;
Button *zoom_reset;
Button *zoom_plus;
@@ -114,10 +116,6 @@ private:
Button *minimap_button;
- void _zoom_minus();
- void _zoom_reset();
- void _zoom_plus();
-
HScrollBar *h_scroll;
VScrollBar *v_scroll;
@@ -144,6 +142,14 @@ private:
Vector2 drag_accum;
float zoom = 1.0;
+ float zoom_step = 1.2;
+ float zoom_min;
+ float zoom_max;
+
+ void _zoom_minus();
+ void _zoom_reset();
+ void _zoom_plus();
+ void _update_zoom_label();
bool box_selecting = false;
bool box_selection_mode_additive = false;
@@ -163,7 +169,7 @@ private:
void _bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const;
- void _draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio);
+ void _draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio = 1.0);
void _graph_node_raised(Node *p_gn);
void _graph_node_moved(Node *p_gn);
@@ -247,6 +253,18 @@ public:
void set_zoom_custom(float p_zoom, const Vector2 &p_center);
float get_zoom() const;
+ void set_zoom_min(float p_zoom_min);
+ float get_zoom_min() const;
+
+ void set_zoom_max(float p_zoom_max);
+ float get_zoom_max() const;
+
+ void set_zoom_step(float p_zoom_step);
+ float get_zoom_step() const;
+
+ void set_show_zoom_label(bool p_enable);
+ bool is_showing_zoom_label() const;
+
void set_minimap_size(Vector2 p_size);
Vector2 get_minimap_size() const;
void set_minimap_opacity(float p_opacity);
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 7d5c53effe..77c502cf8d 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -228,7 +228,7 @@ void GraphNode::_resort() {
}
stretch_avail += stretch_diff - sb->get_margin(SIDE_BOTTOM) - sb->get_margin(SIDE_TOP); //available stretch space.
- /** Second, pass sucessively to discard elements that can't be stretched, this will run while stretchable
+ /** Second, pass successively to discard elements that can't be stretched, this will run while stretchable
elements exist */
while (stretch_ratio_total > 0) { // first of all, don't even be here if no stretchable objects exist
@@ -459,7 +459,7 @@ void GraphNode::_shape() {
}
void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left, const Ref<Texture2D> &p_custom_right) {
- ERR_FAIL_COND(p_idx < 0);
+ ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set slot with p_idx (%d) lesser than zero.", p_idx));
if (!p_enable_left && p_type_left == 0 && p_color_left == Color(1, 1, 1, 1) &&
!p_enable_right && p_type_right == 0 && p_color_right == Color(1, 1, 1, 1) &&
@@ -503,6 +503,26 @@ bool GraphNode::is_slot_enabled_left(int p_idx) const {
return slot_info[p_idx].enable_left;
}
+void GraphNode::set_slot_enabled_left(int p_idx, bool p_enable_left) {
+ ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set enable_left for the slot with p_idx (%d) lesser than zero.", p_idx));
+
+ slot_info[p_idx].enable_left = p_enable_left;
+ update();
+ connpos_dirty = true;
+
+ emit_signal("slot_updated", p_idx);
+}
+
+void GraphNode::set_slot_type_left(int p_idx, int p_type_left) {
+ ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set type_left for the slot '%d' because it hasn't been enabled.", p_idx));
+
+ slot_info[p_idx].type_left = p_type_left;
+ update();
+ connpos_dirty = true;
+
+ emit_signal("slot_updated", p_idx);
+}
+
int GraphNode::get_slot_type_left(int p_idx) const {
if (!slot_info.has(p_idx)) {
return 0;
@@ -510,6 +530,16 @@ int GraphNode::get_slot_type_left(int p_idx) const {
return slot_info[p_idx].type_left;
}
+void GraphNode::set_slot_color_left(int p_idx, const Color &p_color_left) {
+ ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set color_left for the slot '%d' because it hasn't been enabled.", p_idx));
+
+ slot_info[p_idx].color_left = p_color_left;
+ update();
+ connpos_dirty = true;
+
+ emit_signal("slot_updated", p_idx);
+}
+
Color GraphNode::get_slot_color_left(int p_idx) const {
if (!slot_info.has(p_idx)) {
return Color(1, 1, 1, 1);
@@ -524,6 +554,26 @@ bool GraphNode::is_slot_enabled_right(int p_idx) const {
return slot_info[p_idx].enable_right;
}
+void GraphNode::set_slot_enabled_right(int p_idx, bool p_enable_right) {
+ ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set enable_right for the slot with p_idx (%d) lesser than zero.", p_idx));
+
+ slot_info[p_idx].enable_right = p_enable_right;
+ update();
+ connpos_dirty = true;
+
+ emit_signal("slot_updated", p_idx);
+}
+
+void GraphNode::set_slot_type_right(int p_idx, int p_type_right) {
+ ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set type_right for the slot '%d' because it hasn't been enabled.", p_idx));
+
+ slot_info[p_idx].type_right = p_type_right;
+ update();
+ connpos_dirty = true;
+
+ emit_signal("slot_updated", p_idx);
+}
+
int GraphNode::get_slot_type_right(int p_idx) const {
if (!slot_info.has(p_idx)) {
return 0;
@@ -531,6 +581,16 @@ int GraphNode::get_slot_type_right(int p_idx) const {
return slot_info[p_idx].type_right;
}
+void GraphNode::set_slot_color_right(int p_idx, const Color &p_color_right) {
+ ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set color_right for the slot '%d' because it hasn't been enabled.", p_idx));
+
+ slot_info[p_idx].color_right = p_color_right;
+ update();
+ connpos_dirty = true;
+
+ emit_signal("slot_updated", p_idx);
+}
+
Color GraphNode::get_slot_color_right(int p_idx) const {
if (!slot_info.has(p_idx)) {
return Color(1, 1, 1, 1);
@@ -891,11 +951,23 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slot", "idx", "enable_left", "type_left", "color_left", "enable_right", "type_right", "color_right", "custom_left", "custom_right"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()));
ClassDB::bind_method(D_METHOD("clear_slot", "idx"), &GraphNode::clear_slot);
ClassDB::bind_method(D_METHOD("clear_all_slots"), &GraphNode::clear_all_slots);
+
ClassDB::bind_method(D_METHOD("is_slot_enabled_left", "idx"), &GraphNode::is_slot_enabled_left);
+ ClassDB::bind_method(D_METHOD("set_slot_enabled_left", "idx", "enable_left"), &GraphNode::set_slot_enabled_left);
+
+ ClassDB::bind_method(D_METHOD("set_slot_type_left", "idx", "type_left"), &GraphNode::set_slot_type_left);
ClassDB::bind_method(D_METHOD("get_slot_type_left", "idx"), &GraphNode::get_slot_type_left);
+
+ ClassDB::bind_method(D_METHOD("set_slot_color_left", "idx", "color_left"), &GraphNode::set_slot_color_left);
ClassDB::bind_method(D_METHOD("get_slot_color_left", "idx"), &GraphNode::get_slot_color_left);
+
ClassDB::bind_method(D_METHOD("is_slot_enabled_right", "idx"), &GraphNode::is_slot_enabled_right);
+ ClassDB::bind_method(D_METHOD("set_slot_enabled_right", "idx", "enable_right"), &GraphNode::set_slot_enabled_right);
+
+ ClassDB::bind_method(D_METHOD("set_slot_type_right", "idx", "type_right"), &GraphNode::set_slot_type_right);
ClassDB::bind_method(D_METHOD("get_slot_type_right", "idx"), &GraphNode::get_slot_type_right);
+
+ ClassDB::bind_method(D_METHOD("set_slot_color_right", "idx", "color_right"), &GraphNode::set_slot_color_right);
ClassDB::bind_method(D_METHOD("get_slot_color_right", "idx"), &GraphNode::get_slot_color_right);
ClassDB::bind_method(D_METHOD("set_position_offset", "offset"), &GraphNode::set_position_offset);
@@ -927,7 +999,7 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_overlay"), &GraphNode::get_overlay);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position_offset"), "set_position_offset", "get_position_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_close"), "set_show_close_button", "is_close_button_visible");
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 1bc54dddb7..c70f616b47 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -113,11 +113,23 @@ public:
void set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left = Ref<Texture2D>(), const Ref<Texture2D> &p_custom_right = Ref<Texture2D>());
void clear_slot(int p_idx);
void clear_all_slots();
+
bool is_slot_enabled_left(int p_idx) const;
+ void set_slot_enabled_left(int p_idx, bool p_enable_left);
+
+ void set_slot_type_left(int p_idx, int p_type_left);
int get_slot_type_left(int p_idx) const;
+
+ void set_slot_color_left(int p_idx, const Color &p_color_left);
Color get_slot_color_left(int p_idx) const;
+
bool is_slot_enabled_right(int p_idx) const;
+ void set_slot_enabled_right(int p_idx, bool p_enable_right);
+
+ void set_slot_type_right(int p_idx, int p_type_right);
int get_slot_type_right(int p_idx) const;
+
+ void set_slot_color_right(int p_idx, const Color &p_color_right);
Color get_slot_color_right(int p_idx) const;
void set_title(const String &p_title);
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index 541925a802..a54f5eef06 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -33,7 +33,7 @@
void GridContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
- Map<int, int> col_minw; // Max of min_width of all controls in each col (indexed by col).
+ Map<int, int> col_minw; // Max of min_width of all controls in each col (indexed by col).
Map<int, int> row_minh; // Max of min_height of all controls in each row (indexed by row).
Set<int> col_expanded; // Columns which have the SIZE_EXPAND flag set.
Set<int> row_expanded; // Rows which have the SIZE_EXPAND flag set.
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 86d070f9b1..150980b2e9 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -406,6 +406,9 @@ void ItemList::remove_item(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
items.remove(p_idx);
+ if (current == p_idx) {
+ current = -1;
+ }
update();
shape_changed = true;
defer_select_single = -1;
@@ -578,11 +581,11 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
if (closest != -1) {
int i = closest;
- if (select_mode == SELECT_MULTI && items[i].selected && mb->get_command()) {
+ if (select_mode == SELECT_MULTI && items[i].selected && mb->is_command_pressed()) {
deselect(i);
emit_signal("multi_selected", i, false);
- } else if (select_mode == SELECT_MULTI && mb->get_shift() && current >= 0 && current < items.size() && current != i) {
+ } else if (select_mode == SELECT_MULTI && mb->is_shift_pressed() && current >= 0 && current < items.size() && current != i) {
int from = current;
int to = i;
if (i < current) {
@@ -600,7 +603,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
}
} else {
- if (!mb->is_doubleclick() && !mb->get_command() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (!mb->is_double_click() && !mb->is_command_pressed() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
defer_select_single = i;
return;
}
@@ -610,7 +613,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
} else {
bool selected = items[i].selected;
- select(i, select_mode == SELECT_SINGLE || !mb->get_command());
+ select(i, select_mode == SELECT_SINGLE || !mb->is_command_pressed());
if (!selected || allow_reselect) {
if (select_mode == SELECT_SINGLE) {
@@ -622,7 +625,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
- } else if (/*select_mode==SELECT_SINGLE &&*/ mb->is_doubleclick()) {
+ } else if (/*select_mode==SELECT_SINGLE &&*/ mb->is_double_click()) {
emit_signal("item_activated", i);
}
}
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index be73fd8f51..0ce0130ad5 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -217,6 +217,7 @@ void Label::_notification(int p_what) {
for (int64_t i = lines_skipped; i < last_line; i++) {
total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing;
}
+ total_h += style->get_margin(SIDE_TOP) + style->get_margin(SIDE_BOTTOM);
int vbegin = 0, vsep = 0;
if (lines_visible > 0) {
@@ -695,7 +696,7 @@ void Label::_bind_methods() {
BIND_ENUM_CONSTANT(VALIGN_FILL);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align");
ADD_PROPERTY(PropertyInfo(Variant::INT, "valign", PROPERTY_HINT_ENUM, "Top,Center,Bottom,Fill"), "set_valign", "get_valign");
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 124a07fa65..089893e63b 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -155,6 +155,7 @@ void LineEdit::_backspace(bool p_word, bool p_all_to_left) {
for (int i = words.size() - 1; i >= 0; i--) {
if (words[i].x < cc) {
cc = words[i].x;
+ break;
}
}
@@ -202,6 +203,7 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
}
delete_text(caret_column, cc);
+ set_caret_column(caret_column);
} else {
if (caret_mid_grapheme_enabled) {
set_caret_column(caret_column + 1);
@@ -248,25 +250,25 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
return;
}
- shift_selection_check_pre(b->get_shift());
+ shift_selection_check_pre(b->is_shift_pressed());
set_caret_at_pixel_pos(b->get_position().x);
- if (b->get_shift()) {
+ if (b->is_shift_pressed()) {
selection_fill_at_caret();
selection.creating = true;
} else {
if (selecting_enabled) {
- if (!b->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) {
+ if (!b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) {
// Triple-click select all.
selection.enabled = true;
selection.begin = 0;
selection.end = text.length();
- selection.doubleclick = true;
+ selection.double_click = true;
selection.last_dblclk = 0;
caret_column = selection.begin;
- } else if (b->is_doubleclick()) {
+ } else if (b->is_double_click()) {
// Double-click select word.
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
for (int i = 0; i < words.size(); i++) {
@@ -274,7 +276,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
selection.enabled = true;
selection.begin = words[i].x;
selection.end = words[i].y;
- selection.doubleclick = true;
+ selection.double_click = true;
selection.last_dblclk = OS::get_singleton()->get_ticks_msec();
caret_column = selection.end;
break;
@@ -306,11 +308,11 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
}
- if ((!selection.creating) && (!selection.doubleclick)) {
+ if ((!selection.creating) && (!selection.double_click)) {
deselect();
}
selection.creating = false;
- selection.doubleclick = false;
+ selection.double_click = false;
show_virtual_keyboard();
}
@@ -355,9 +357,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
}
- // Default is ENTER, KP_ENTER. Cannot use ui_accept as default includes SPACE
- if (k->is_action("ui_text_newline", true)) {
- emit_signal("text_entered", text);
+ // Default is ENTER and KP_ENTER. Cannot use ui_accept as default includes SPACE
+ if (k->is_action("ui_text_submit", false)) {
+ emit_signal("text_submitted", text);
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
DisplayServer::get_singleton()->virtual_keyboard_hide();
}
@@ -440,9 +442,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
// Cursor Movement
k = k->duplicate();
- bool shift_pressed = k->get_shift();
+ bool shift_pressed = k->is_shift_pressed();
// Remove shift or else actions will not match. Use above variable for selection.
- k->set_shift(false);
+ k->set_shift_pressed(false);
if (k->is_action("ui_text_caret_word_left", true)) {
_move_caret_left(shift_pressed, true);
@@ -488,7 +490,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
// Allow unicode handling if:
// * No Modifiers are pressed (except shift)
- bool allow_unicode_handling = !(k->get_command() || k->get_control() || k->get_alt() || k->get_metakey());
+ bool allow_unicode_handling = !(k->is_command_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
if (allow_unicode_handling && editable && k->get_unicode() >= 32) {
// Handle Unicode (if no modifiers active)
@@ -555,7 +557,7 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
}
Control::CursorShape LineEdit::get_cursor_shape(const Point2 &p_pos) const {
- if (!text.is_empty() && is_editable() && _is_over_clear_button(p_pos)) {
+ if ((!text.is_empty() && is_editable() && _is_over_clear_button(p_pos)) || (!is_editable() && (!is_selecting_enabled() || text.is_empty()))) {
return CURSOR_ARROW;
}
return Control::get_cursor_shape(p_pos);
@@ -1530,7 +1532,7 @@ void LineEdit::deselect() {
selection.start_column = 0;
selection.enabled = false;
selection.creating = false;
- selection.doubleclick = false;
+ selection.double_click = false;
update();
}
@@ -1657,7 +1659,7 @@ void LineEdit::select(int p_from, int p_to) {
selection.begin = p_from;
selection.end = p_to;
selection.creating = false;
- selection.doubleclick = false;
+ selection.double_click = false;
update();
}
@@ -2157,7 +2159,7 @@ void LineEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text")));
ADD_SIGNAL(MethodInfo("text_change_rejected"));
- ADD_SIGNAL(MethodInfo("text_entered", PropertyInfo(Variant::STRING, "new_text")));
+ ADD_SIGNAL(MethodInfo("text_submitted", PropertyInfo(Variant::STRING, "new_text")));
BIND_ENUM_CONSTANT(ALIGN_LEFT);
BIND_ENUM_CONSTANT(ALIGN_CENTER);
@@ -2207,7 +2209,7 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_right_icon", "get_right_icon");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars"), "set_draw_control_chars", "get_draw_control_chars");
ADD_GROUP("Structured Text", "structured_text_");
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index f4f0ff0629..12fec2f98b 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -134,7 +134,7 @@ private:
int start_column = 0;
bool enabled = false;
bool creating = false;
- bool doubleclick = false;
+ bool double_click = false;
bool drag_attempt = false;
uint64_t last_dblclk = 0;
} selection;
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index 1f7b61e3d1..d45ffde715 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -292,7 +292,7 @@ void LinkButton::_bind_methods() {
BIND_ENUM_CONSTANT(UNDERLINE_MODE_NEVER);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::INT, "underline", PROPERTY_HINT_ENUM, "Always,On Hover,Never"), "set_underline_mode", "get_underline_mode");
ADD_GROUP("Structured Text", "structured_text_");
diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp
index 29a38ad5e3..8bf25ac915 100644
--- a/scene/gui/nine_patch_rect.cpp
+++ b/scene/gui/nine_patch_rect.cpp
@@ -30,6 +30,7 @@
#include "nine_patch_rect.h"
+#include "scene/scene_string_names.h"
#include "servers/rendering_server.h"
void NinePatchRect::_notification(int p_what) {
@@ -97,7 +98,7 @@ void NinePatchRect::set_texture(const Ref<Texture2D> &p_tex) {
texture->set_flags(texture->get_flags()&(~Texture::FLAG_REPEAT)); //remove repeat from texture, it looks bad in sprites
*/
minimum_size_changed();
- emit_signal("texture_changed");
+ emit_signal(SceneStringNames::get_singleton()->texture_changed);
}
Ref<Texture2D> NinePatchRect::get_texture() const {
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 44df8eafdc..2100707d2d 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -1282,16 +1282,16 @@ bool PopupMenu::activate_item_by_event(const Ref<InputEvent> &p_event, bool p_fo
if (code == 0) {
code = k->get_unicode();
}
- if (k->get_control()) {
+ if (k->is_ctrl_pressed()) {
code |= KEY_MASK_CTRL;
}
- if (k->get_alt()) {
+ if (k->is_alt_pressed()) {
code |= KEY_MASK_ALT;
}
- if (k->get_metakey()) {
+ if (k->is_meta_pressed()) {
code |= KEY_MASK_META;
}
- if (k->get_shift()) {
+ if (k->is_shift_pressed()) {
code |= KEY_MASK_SHIFT;
}
}
diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h
index f2e2823eff..d809fd502f 100644
--- a/scene/gui/rich_text_effect.h
+++ b/scene/gui/rich_text_effect.h
@@ -47,8 +47,8 @@ public:
RichTextEffect();
};
-class CharFXTransform : public Reference {
- GDCLASS(CharFXTransform, Reference);
+class CharFXTransform : public RefCounted {
+ GDCLASS(CharFXTransform, RefCounted);
protected:
static void _bind_methods();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index c763ae6bd6..987d05bf71 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1432,10 +1432,11 @@ void RichTextLabel::_notification(int p_what) {
}
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
- float dt = get_process_delta_time();
-
- _update_fx(main, dt);
- update();
+ if (is_visible_in_tree()) {
+ float dt = get_process_delta_time();
+ _update_fx(main, dt);
+ update();
+ }
}
}
}
@@ -1482,7 +1483,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (b->is_pressed() && !b->is_doubleclick()) {
+ if (b->is_pressed() && !b->is_double_click()) {
scroll_updated = false;
ItemFrame *c_frame = nullptr;
int c_line = 0;
@@ -1514,8 +1515,8 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
}
}
- } else if (b->is_pressed() && b->is_doubleclick() && selection.enabled) {
- //doubleclick: select word
+ } else if (b->is_pressed() && b->is_double_click() && selection.enabled) {
+ //double_click: select word
ItemFrame *c_frame = nullptr;
int c_line = 0;
@@ -1549,7 +1550,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
} else if (!b->is_pressed()) {
selection.click_item = nullptr;
- if (!b->is_doubleclick() && !scroll_updated) {
+ if (!b->is_double_click() && !scroll_updated) {
Item *c_item = nullptr;
bool outside = true;
@@ -2231,18 +2232,22 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
int size = p_item->subitems.size();
if (size == 0) {
p_item->parent->subitems.erase(p_item);
+ // If a newline was erased, all lines AFTER the newline need to be decremented.
if (p_item->type == ITEM_NEWLINE) {
current_frame->lines.remove(p_line);
- for (int i = p_subitem_line; i < current->subitems.size(); i++) {
- if (current->subitems[i]->line > 0) {
+ for (int i = 0; i < current->subitems.size(); i++) {
+ if (current->subitems[i]->line > p_subitem_line) {
current->subitems[i]->line--;
}
}
}
} else {
+ // First, remove all child items for the provided item.
for (int i = 0; i < size; i++) {
_remove_item(p_item->subitems.front()->get(), p_line, p_subitem_line);
}
+ // Then remove the provided item itself.
+ p_item->parent->subitems.erase(p_item);
}
}
@@ -2302,21 +2307,23 @@ bool RichTextLabel::remove_line(const int p_line) {
return false;
}
- int i = 0;
- while (i < current->subitems.size() && current->subitems[i]->line < p_line) {
- i++;
+ // Remove all subitems with the same line as that provided.
+ Vector<int> subitem_indices_to_remove;
+ for (int i = 0; i < current->subitems.size(); i++) {
+ if (current->subitems[i]->line == p_line) {
+ subitem_indices_to_remove.push_back(i);
+ }
}
- bool was_newline = false;
- while (i < current->subitems.size()) {
- was_newline = current->subitems[i]->type == ITEM_NEWLINE;
- _remove_item(current->subitems[i], current->subitems[i]->line, p_line);
- if (was_newline) {
- break;
- }
+ bool had_newline = false;
+ // Reverse for loop to remove items from the end first.
+ for (int i = subitem_indices_to_remove.size() - 1; i >= 0; i--) {
+ int subitem_idx = subitem_indices_to_remove[i];
+ had_newline = had_newline || current->subitems[subitem_idx]->type == ITEM_NEWLINE;
+ _remove_item(current->subitems[subitem_idx], current->subitems[subitem_idx]->line, p_line);
}
- if (!was_newline) {
+ if (!had_newline) {
current_frame->lines.remove(p_line);
if (current_frame->lines.size() == 0) {
current_frame->lines.resize(1);
@@ -2328,6 +2335,7 @@ bool RichTextLabel::remove_line(const int p_line) {
}
main->first_invalid_line = 0; // p_line ???
+ update();
return true;
}
@@ -3444,7 +3452,30 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) {
}
}
-bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to) {
+bool RichTextLabel::_search_table(ItemTable *p_table, List<Item *>::Element *p_from, const String &p_string, bool p_reverse_search) {
+ List<Item *>::Element *E = p_from;
+ while (E != nullptr) {
+ ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
+ ItemFrame *frame = static_cast<ItemFrame *>(E->get());
+ if (p_reverse_search) {
+ for (int i = frame->lines.size() - 1; i >= 0; i--) {
+ if (_search_line(frame, i, p_string, -1, p_reverse_search)) {
+ return true;
+ }
+ }
+ } else {
+ for (int i = 0; i < frame->lines.size(); i++) {
+ if (_search_line(frame, i, p_string, 0, p_reverse_search)) {
+ return true;
+ }
+ }
+ }
+ E = p_reverse_search ? E->prev() : E->next();
+ }
+ return false;
+}
+
+bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search) {
ERR_FAIL_COND_V(p_frame == nullptr, false);
ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), false);
@@ -3466,24 +3497,23 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
} break;
case ITEM_TABLE: {
ItemTable *table = static_cast<ItemTable *>(it);
- int idx = 0;
- for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
- ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames.
- ItemFrame *frame = static_cast<ItemFrame *>(E->get());
-
- for (int i = 0; i < frame->lines.size(); i++) {
- if (_search_line(frame, i, p_string, p_from, p_to)) {
- return true;
- }
- }
- idx++;
+ List<Item *>::Element *E = p_reverse_search ? table->subitems.back() : table->subitems.front();
+ if (_search_table(table, E, p_string, p_reverse_search)) {
+ return true;
}
} break;
default:
break;
}
}
- int sp = text.findn(p_string, 0);
+
+ int sp = -1;
+ if (p_reverse_search) {
+ sp = text.rfindn(p_string, p_char_idx);
+ } else {
+ sp = text.findn(p_string, p_char_idx);
+ }
+
if (sp != -1) {
selection.from_frame = p_frame;
selection.from_line = p_line;
@@ -3491,8 +3521,8 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
selection.from_char = sp;
selection.to_frame = p_frame;
selection.to_line = p_line;
- selection.to_item = _get_item_at_pos(l.from, it_to, sp + p_string.length() - 1);
- selection.to_char = sp + p_string.length() - 1;
+ selection.to_item = _get_item_at_pos(l.from, it_to, sp + p_string.length());
+ selection.to_char = sp + p_string.length();
selection.active = true;
return true;
}
@@ -3503,23 +3533,81 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) {
ERR_FAIL_COND_V(!selection.enabled, false);
+ if (p_string.size() == 0) {
+ selection.active = false;
+ return false;
+ }
+
+ int char_idx = p_search_previous ? -1 : 0;
+ int current_line = 0;
+ int ending_line = main->lines.size() - 1;
if (p_from_selection && selection.active) {
- for (int i = 0; i < main->lines.size(); i++) {
- if (_search_line(main, i, p_string, selection.from_item, selection.to_item)) {
- update();
- return true;
- }
+ // First check to see if other results exist in current line
+ char_idx = p_search_previous ? selection.from_char - 1 : selection.to_char;
+ if (!(p_search_previous && char_idx < 0) &&
+ _search_line(selection.from_frame, selection.from_line, p_string, char_idx, p_search_previous)) {
+ scroll_to_line(selection.from_frame->line + selection.from_line);
+ update();
+ return true;
}
- } else {
- for (int i = 0; i < main->lines.size(); i++) {
- if (_search_line(main, i, p_string, nullptr, nullptr)) {
- update();
- return true;
+ char_idx = p_search_previous ? -1 : 0;
+
+ // Next, check to see if the current search result is in a table
+ if (selection.from_frame->parent != nullptr && selection.from_frame->parent->type == ITEM_TABLE) {
+ // Find last search result in table
+ ItemTable *parent_table = static_cast<ItemTable *>(selection.from_frame->parent);
+ List<Item *>::Element *parent_element = p_search_previous ? parent_table->subitems.back() : parent_table->subitems.front();
+
+ while (parent_element->get() != selection.from_frame) {
+ parent_element = p_search_previous ? parent_element->prev() : parent_element->next();
+ ERR_FAIL_COND_V(parent_element == nullptr, false);
+ }
+
+ // Search remainder of table
+ if (!(p_search_previous && parent_element == parent_table->subitems.front()) &&
+ parent_element != parent_table->subitems.back()) {
+ parent_element = p_search_previous ? parent_element->prev() : parent_element->next(); // Don't want to search current item
+ ERR_FAIL_COND_V(parent_element == nullptr, false);
+
+ // Search for next element
+ if (_search_table(parent_table, parent_element, p_string, p_search_previous)) {
+ scroll_to_line(selection.from_frame->line + selection.from_line);
+ update();
+ return true;
+ }
}
}
+
+ ending_line = selection.from_frame->line + selection.from_line;
+ current_line = p_search_previous ? ending_line - 1 : ending_line + 1;
+ } else if (p_search_previous) {
+ current_line = ending_line;
+ ending_line = 0;
}
- return false;
+ // Search remainder of the file
+ while (current_line != ending_line) {
+ // Wrap around
+ if (current_line < 0) {
+ current_line = main->lines.size() - 1;
+ } else if (current_line >= main->lines.size()) {
+ current_line = 0;
+ }
+
+ if (_search_line(main, current_line, p_string, char_idx, p_search_previous)) {
+ scroll_to_line(current_line);
+ update();
+ return true;
+ }
+ p_search_previous ? current_line-- : current_line++;
+ }
+
+ if (p_from_selection && selection.active) {
+ // Check contents of selection
+ return _search_line(main, current_line, p_string, char_idx, p_search_previous);
+ } else {
+ return false;
+ }
}
String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) const {
@@ -3926,7 +4014,7 @@ void RichTextLabel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, "RichTextEffect", (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
ADD_GROUP("Structured Text", "structured_text_");
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index e3e457d1f2..9cf94b0cd7 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -392,7 +392,8 @@ private:
void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel) const;
- bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to);
+ bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search);
+ bool _search_table(ItemTable *p_table, List<Item *>::Element *p_from, const String &p_string, bool p_reverse_search);
void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset);
void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width);
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 73c6371658..5f872644ab 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -98,7 +98,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb.is_valid()) {
if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
// only horizontal is enabled, scroll horizontally
- if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) {
+ if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->is_shift_pressed())) {
h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() / 8 * mb->get_factor());
} else if (v_scroll->is_visible_in_tree()) {
v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() / 8 * mb->get_factor());
@@ -107,7 +107,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
// only horizontal is enabled, scroll horizontally
- if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) {
+ if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->is_shift_pressed())) {
h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() / 8 * mb->get_factor());
} else if (v_scroll->is_visible()) {
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() / 8 * mb->get_factor());
@@ -238,32 +238,25 @@ void ScrollContainer::_update_scrollbar_position() {
_updating_scrollbars = false;
}
-void ScrollContainer::_ensure_focused_visible(Control *p_control) {
- if (!follow_focus) {
- return;
+void ScrollContainer::_gui_focus_changed(Control *p_control) {
+ if (follow_focus && is_a_parent_of(p_control)) {
+ ensure_control_visible(p_control);
}
+}
- if (is_a_parent_of(p_control)) {
- Rect2 global_rect = get_global_rect();
- Rect2 other_rect = p_control->get_global_rect();
- float right_margin = 0.0;
- if (v_scroll->is_visible()) {
- right_margin += v_scroll->get_size().x;
- }
- float bottom_margin = 0.0;
- if (h_scroll->is_visible()) {
- bottom_margin += h_scroll->get_size().y;
- }
+void ScrollContainer::ensure_control_visible(Control *p_control) {
+ ERR_FAIL_COND_MSG(!is_a_parent_of(p_control), "Must be a parent of the control.");
- float diff = MAX(MIN(other_rect.position.y, global_rect.position.y), other_rect.position.y + other_rect.size.y - global_rect.size.y + bottom_margin);
- set_v_scroll(get_v_scroll() + (diff - global_rect.position.y));
- if (is_layout_rtl()) {
- diff = MAX(MIN(other_rect.position.x, global_rect.position.x), other_rect.position.x + other_rect.size.x - global_rect.size.x);
- } else {
- diff = MAX(MIN(other_rect.position.x, global_rect.position.x), other_rect.position.x + other_rect.size.x - global_rect.size.x + right_margin);
- }
- set_h_scroll(get_h_scroll() + (diff - global_rect.position.x));
- }
+ Rect2 global_rect = get_global_rect();
+ Rect2 other_rect = p_control->get_global_rect();
+ float right_margin = v_scroll->is_visible() ? v_scroll->get_size().x : 0.0f;
+ float bottom_margin = h_scroll->is_visible() ? h_scroll->get_size().y : 0.0f;
+
+ Vector2 diff = Vector2(MAX(MIN(other_rect.position.x, global_rect.position.x), other_rect.position.x + other_rect.size.x - global_rect.size.x + (!is_layout_rtl() ? right_margin : 0.0f)),
+ MAX(MIN(other_rect.position.y, global_rect.position.y), other_rect.position.y + other_rect.size.y - global_rect.size.y + bottom_margin));
+
+ set_h_scroll(get_h_scroll() + (diff.x - global_rect.position.x));
+ set_v_scroll(get_v_scroll() + (diff.y - global_rect.position.y));
}
void ScrollContainer::_update_dimensions() {
@@ -299,7 +292,7 @@ void ScrollContainer::_update_dimensions() {
child_max_size.x = MAX(child_max_size.x, minsize.x);
child_max_size.y = MAX(child_max_size.y, minsize.y);
- Rect2 r = Rect2(-scroll, minsize);
+ Rect2 r = Rect2(-Size2(get_h_scroll(), get_v_scroll()), minsize);
if (!scroll_h || (!h_scroll->is_visible_in_tree() && c->get_h_size_flags() & SIZE_EXPAND)) {
r.position.x = 0;
if (c->get_h_size_flags() & SIZE_EXPAND) {
@@ -334,7 +327,7 @@ void ScrollContainer::_notification(int p_what) {
};
if (p_what == NOTIFICATION_READY) {
- get_viewport()->connect("gui_focus_changed", callable_mp(this, &ScrollContainer::_ensure_focused_visible));
+ get_viewport()->connect("gui_focus_changed", callable_mp(this, &ScrollContainer::_gui_focus_changed));
_update_dimensions();
}
@@ -434,40 +427,16 @@ void ScrollContainer::update_scrollbars() {
Size2 min = child_max_size;
- bool hide_scroll_v = !scroll_v || min.height <= size.height;
- bool hide_scroll_h = !scroll_h || min.width <= size.width;
-
- v_scroll->set_max(min.height);
- if (hide_scroll_v) {
- v_scroll->set_page(size.height);
- v_scroll->hide();
- scroll.y = 0;
- } else {
- v_scroll->show();
- if (hide_scroll_h) {
- v_scroll->set_page(size.height);
- } else {
- v_scroll->set_page(size.height - hmin.height);
- }
-
- scroll.y = v_scroll->get_value();
- }
+ bool hide_scroll_h = !scroll_h || min.width <= size.width || !h_scroll_visible;
+ bool hide_scroll_v = !scroll_v || min.height <= size.height || !v_scroll_visible;
h_scroll->set_max(min.width);
- if (hide_scroll_h) {
- h_scroll->set_page(size.width);
- h_scroll->hide();
- scroll.x = 0;
- } else {
- h_scroll->show();
- if (hide_scroll_v) {
- h_scroll->set_page(size.width);
- } else {
- h_scroll->set_page(size.width - vmin.width);
- }
+ h_scroll->set_page(size.width - (hide_scroll_v ? 0 : vmin.width));
+ h_scroll->set_visible(!hide_scroll_h);
- scroll.x = h_scroll->get_value();
- }
+ v_scroll->set_max(min.height);
+ v_scroll->set_page(size.height - (hide_scroll_h ? 0 : hmin.height));
+ v_scroll->set_visible(!hide_scroll_v);
// Avoid scrollbar overlapping.
h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, hide_scroll_v ? 0 : -vmin.width);
@@ -475,13 +444,28 @@ void ScrollContainer::update_scrollbars() {
}
void ScrollContainer::_scroll_moved(float) {
- scroll.x = h_scroll->get_value();
- scroll.y = v_scroll->get_value();
queue_sort();
-
update();
};
+void ScrollContainer::set_h_scroll(int p_pos) {
+ h_scroll->set_value(p_pos);
+ _cancel_drag();
+}
+
+int ScrollContainer::get_h_scroll() const {
+ return h_scroll->get_value();
+}
+
+void ScrollContainer::set_v_scroll(int p_pos) {
+ v_scroll->set_value(p_pos);
+ _cancel_drag();
+}
+
+int ScrollContainer::get_v_scroll() const {
+ return v_scroll->get_value();
+}
+
void ScrollContainer::set_enable_h_scroll(bool p_enable) {
if (scroll_h == p_enable) {
return;
@@ -510,22 +494,30 @@ bool ScrollContainer::is_v_scroll_enabled() const {
return scroll_v;
}
-int ScrollContainer::get_v_scroll() const {
- return v_scroll->get_value();
+void ScrollContainer::set_h_scroll_visible(bool p_visible) {
+ if (h_scroll_visible == p_visible) {
+ return;
+ }
+
+ h_scroll_visible = p_visible;
+ update_scrollbars();
}
-void ScrollContainer::set_v_scroll(int p_pos) {
- v_scroll->set_value(p_pos);
- _cancel_drag();
+bool ScrollContainer::is_h_scroll_visible() const {
+ return h_scroll_visible;
}
-int ScrollContainer::get_h_scroll() const {
- return h_scroll->get_value();
+void ScrollContainer::set_v_scroll_visible(bool p_visible) {
+ if (v_scroll_visible == p_visible) {
+ return;
+ }
+
+ v_scroll_visible = p_visible;
+ update_scrollbars();
}
-void ScrollContainer::set_h_scroll(int p_pos) {
- h_scroll->set_value(p_pos);
- _cancel_drag();
+bool ScrollContainer::is_v_scroll_visible() const {
+ return v_scroll_visible;
}
int ScrollContainer::get_deadzone() const {
@@ -581,22 +573,35 @@ VScrollBar *ScrollContainer::get_v_scrollbar() {
void ScrollContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &ScrollContainer::_gui_input);
- ClassDB::bind_method(D_METHOD("set_enable_h_scroll", "enable"), &ScrollContainer::set_enable_h_scroll);
- ClassDB::bind_method(D_METHOD("is_h_scroll_enabled"), &ScrollContainer::is_h_scroll_enabled);
- ClassDB::bind_method(D_METHOD("set_enable_v_scroll", "enable"), &ScrollContainer::set_enable_v_scroll);
- ClassDB::bind_method(D_METHOD("is_v_scroll_enabled"), &ScrollContainer::is_v_scroll_enabled);
ClassDB::bind_method(D_METHOD("_update_scrollbar_position"), &ScrollContainer::_update_scrollbar_position);
+
ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &ScrollContainer::set_h_scroll);
ClassDB::bind_method(D_METHOD("get_h_scroll"), &ScrollContainer::get_h_scroll);
+
ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &ScrollContainer::set_v_scroll);
ClassDB::bind_method(D_METHOD("get_v_scroll"), &ScrollContainer::get_v_scroll);
+
+ ClassDB::bind_method(D_METHOD("set_enable_h_scroll", "enable"), &ScrollContainer::set_enable_h_scroll);
+ ClassDB::bind_method(D_METHOD("is_h_scroll_enabled"), &ScrollContainer::is_h_scroll_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_enable_v_scroll", "enable"), &ScrollContainer::set_enable_v_scroll);
+ ClassDB::bind_method(D_METHOD("is_v_scroll_enabled"), &ScrollContainer::is_v_scroll_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_h_scroll_visible", "visible"), &ScrollContainer::set_h_scroll_visible);
+ ClassDB::bind_method(D_METHOD("is_h_scroll_visible"), &ScrollContainer::is_h_scroll_visible);
+
+ ClassDB::bind_method(D_METHOD("set_v_scroll_visible", "visible"), &ScrollContainer::set_v_scroll_visible);
+ ClassDB::bind_method(D_METHOD("is_v_scroll_visible"), &ScrollContainer::is_v_scroll_visible);
+
ClassDB::bind_method(D_METHOD("set_deadzone", "deadzone"), &ScrollContainer::set_deadzone);
ClassDB::bind_method(D_METHOD("get_deadzone"), &ScrollContainer::get_deadzone);
+
ClassDB::bind_method(D_METHOD("set_follow_focus", "enabled"), &ScrollContainer::set_follow_focus);
ClassDB::bind_method(D_METHOD("is_following_focus"), &ScrollContainer::is_following_focus);
ClassDB::bind_method(D_METHOD("get_h_scrollbar"), &ScrollContainer::get_h_scrollbar);
ClassDB::bind_method(D_METHOD("get_v_scrollbar"), &ScrollContainer::get_v_scrollbar);
+ ClassDB::bind_method(D_METHOD("ensure_control_visible", "control"), &ScrollContainer::ensure_control_visible);
ADD_SIGNAL(MethodInfo("scroll_started"));
ADD_SIGNAL(MethodInfo("scroll_ended"));
@@ -604,10 +609,12 @@ void ScrollContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_focus"), "set_follow_focus", "is_following_focus");
ADD_GROUP("Scroll", "scroll_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal_enabled"), "set_enable_h_scroll", "is_h_scroll_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_horizontal"), "set_h_scroll", "get_h_scroll");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical_enabled"), "set_enable_v_scroll", "is_v_scroll_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_vertical"), "set_v_scroll", "get_v_scroll");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal_enabled"), "set_enable_h_scroll", "is_h_scroll_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical_enabled"), "set_enable_v_scroll", "is_v_scroll_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal_visible"), "set_h_scroll_visible", "is_h_scroll_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical_visible"), "set_v_scroll_visible", "is_v_scroll_visible");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_deadzone"), "set_deadzone", "get_deadzone");
GLOBAL_DEF("gui/common/default_scroll_deadzone", 0);
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index e7d73bab0a..c77a0d62f5 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -42,7 +42,6 @@ class ScrollContainer : public Container {
VScrollBar *v_scroll;
Size2 child_max_size;
- Size2 scroll;
void update_scrollbars();
@@ -50,16 +49,17 @@ class ScrollContainer : public Container {
Vector2 drag_accum;
Vector2 drag_from;
Vector2 last_drag_accum;
- float last_drag_time = 0.0;
- float time_since_motion = 0.0;
+ float time_since_motion = 0.0f;
bool drag_touching = false;
bool drag_touching_deaccel = false;
- bool click_handled = false;
bool beyond_deadzone = false;
bool scroll_h = true;
bool scroll_v = true;
+ bool h_scroll_visible = true;
+ bool v_scroll_visible = true;
+
int deadzone = 0;
bool follow_focus = false;
@@ -69,6 +69,7 @@ protected:
Size2 get_minimum_size() const override;
void _gui_input(const Ref<InputEvent> &p_gui_input);
+ void _gui_focus_changed(Control *p_control);
void _update_dimensions();
void _notification(int p_what);
@@ -77,14 +78,13 @@ protected:
bool _updating_scrollbars = false;
void _update_scrollbar_position();
- void _ensure_focused_visible(Control *p_node);
public:
- int get_v_scroll() const;
- void set_v_scroll(int p_pos);
-
- int get_h_scroll() const;
void set_h_scroll(int p_pos);
+ int get_h_scroll() const;
+
+ void set_v_scroll(int p_pos);
+ int get_v_scroll() const;
void set_enable_h_scroll(bool p_enable);
bool is_h_scroll_enabled() const;
@@ -92,6 +92,12 @@ public:
void set_enable_v_scroll(bool p_enable);
bool is_v_scroll_enabled() const;
+ void set_h_scroll_visible(bool p_visible);
+ bool is_h_scroll_visible() const;
+
+ void set_v_scroll_visible(bool p_visible);
+ bool is_v_scroll_visible() const;
+
int get_deadzone() const;
void set_deadzone(int p_deadzone);
@@ -100,6 +106,7 @@ public:
HScrollBar *get_h_scrollbar();
VScrollBar *get_v_scrollbar();
+ void ensure_control_visible(Control *p_control);
virtual bool clips_input() const override;
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index a407ef21cb..5947f3b99e 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -172,7 +172,7 @@ void Slider::_notification(int p_what) {
int widget_width = style->get_minimum_size().width + style->get_center_size().width;
float areasize = size.height - grabber->get_size().height;
style->draw(ci, Rect2i(Point2i(size.width / 2 - widget_width / 2, 0), Size2i(widget_width, size.height)));
- grabber_area->draw(ci, Rect2i(Point2i((size.width - widget_width) / 2, size.height - areasize * ratio - grabber->get_size().height / 2), Size2i(widget_width, areasize * ratio + grabber->get_size().width / 2)));
+ grabber_area->draw(ci, Rect2i(Point2i((size.width - widget_width) / 2, size.height - areasize * ratio - grabber->get_size().height / 2), Size2i(widget_width, areasize * ratio + grabber->get_size().height / 2)));
if (ticks > 1) {
int grabber_offset = (grabber->get_size().height / 2 - tick->get_height() / 2);
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 9dc2afdb2d..4ac73ae6b5 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -50,7 +50,7 @@ void SpinBox::_value_changed(double) {
line_edit->set_text(value);
}
-void SpinBox::_text_entered(const String &p_string) {
+void SpinBox::_text_submitted(const String &p_string) {
Ref<Expression> expr;
expr.instance();
@@ -172,7 +172,7 @@ void SpinBox::_line_edit_focus_exit() {
return;
}
- _text_entered(line_edit->get_text());
+ _text_submitted(line_edit->get_text());
}
inline void SpinBox::_adjust_width_for_icon(const Ref<Texture2D> &icon) {
@@ -251,7 +251,7 @@ bool SpinBox::is_editable() const {
}
void SpinBox::apply() {
- _text_entered(line_edit->get_text());
+ _text_submitted(line_edit->get_text());
}
void SpinBox::_bind_methods() {
@@ -283,7 +283,7 @@ SpinBox::SpinBox() {
line_edit->set_align(LineEdit::ALIGN_LEFT);
//connect("value_changed",this,"_value_changed");
- line_edit->connect("text_entered", callable_mp(this, &SpinBox::_text_entered), Vector<Variant>(), CONNECT_DEFERRED);
+ line_edit->connect("text_submitted", callable_mp(this, &SpinBox::_text_submitted), Vector<Variant>(), CONNECT_DEFERRED);
line_edit->connect("focus_exited", callable_mp(this, &SpinBox::_line_edit_focus_exit), Vector<Variant>(), CONNECT_DEFERRED);
line_edit->connect("gui_input", callable_mp(this, &SpinBox::_line_edit_input));
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index e116adb64c..fb10379296 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -45,7 +45,7 @@ class SpinBox : public Range {
void _range_click_timeout();
void _release_mouse();
- void _text_entered(const String &p_string);
+ void _text_submitted(const String &p_string);
virtual void _value_changed(double) override;
String prefix;
String suffix;
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 13ff2c5b86..df4cf9a740 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -353,7 +353,7 @@ void SplitContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "split_offset"), "set_split_offset", "get_split_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "dragger_visibility", PROPERTY_HINT_ENUM, "Visible,Hidden,Hidden & Collapsed"), "set_dragger_visibility", "get_dragger_visibility");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "dragger_visibility", PROPERTY_HINT_ENUM, "Visible,Hidden,Hidden and Collapsed"), "set_dragger_visibility", "get_dragger_visibility");
BIND_ENUM_CONSTANT(DRAGGER_VISIBLE);
BIND_ENUM_CONSTANT(DRAGGER_HIDDEN);
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index ff9dafa0f9..acf0641005 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -394,6 +394,7 @@ void TabContainer::_notification(int p_what) {
Vector<int> tab_widths;
for (int i = first_tab_cache; i < tabs.size(); i++) {
if (get_tab_hidden(i)) {
+ tab_widths.push_back(0);
continue;
}
int tab_width = _get_tab_width(i);
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 6cbc5890ce..11096e7976 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -127,7 +127,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !mb->get_command()) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !mb->is_command_pressed()) {
if (scrolling_enabled && buttons_visible) {
if (offset > 0) {
offset--;
@@ -136,7 +136,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !mb->get_command()) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !mb->is_command_pressed()) {
if (scrolling_enabled && buttons_visible) {
if (missing_right) {
offset++;
@@ -256,6 +256,7 @@ void Tabs::_notification(int p_what) {
_update_cache();
update();
} break;
+ case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
for (int i = 0; i < tabs.size(); ++i) {
_shape(i);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 4f508423b3..6f78d586f1 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -137,8 +137,11 @@ void TextEdit::Text::set_draw_control_chars(bool p_draw_control_chars) {
draw_control_chars = p_draw_control_chars;
}
-int TextEdit::Text::get_line_width(int p_line) const {
+int TextEdit::Text::get_line_width(int p_line, int p_wrap_index) const {
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
+ if (p_wrap_index != -1) {
+ return text[p_line].data_buf->get_line_width(p_wrap_index);
+ }
return text[p_line].data_buf->get_size().x;
}
@@ -253,7 +256,6 @@ void TextEdit::Text::set(int p_line, const String &p_text, const Vector<Vector2i
void TextEdit::Text::insert(int p_at, const String &p_text, const Vector<Vector2i> &p_bidi_override) {
Line line;
line.gutters.resize(gutter_count);
- line.marked = false;
line.hidden = false;
line.data = p_text;
line.bidi_override = p_bidi_override;
@@ -802,9 +804,6 @@ void TextEdit::_notification(int p_what) {
}
}
- bool is_cursor_line_visible = false;
- Point2 cursor_pos;
-
// Get the highlighted words.
String highlighted_text = get_selection_text();
@@ -867,6 +866,8 @@ void TextEdit::_notification(int p_what) {
Dictionary color_map = _get_line_syntax_highlighting(minimap_line);
+ Color line_background_color = text.get_line_background_color(minimap_line);
+ line_background_color.a *= 0.6;
Color current_color = cache.font_color;
if (readonly) {
current_color = cache.font_readonly_color;
@@ -901,6 +902,12 @@ void TextEdit::_notification(int p_what) {
} else {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, cache.minimap_width, 2), cache.current_line_color);
}
+ } else if (line_background_color != Color(0, 0, 0, 0)) {
+ if (rtl) {
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - cache.minimap_width, i * 3, cache.minimap_width, 2), line_background_color);
+ } else {
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, cache.minimap_width, 2), line_background_color);
+ }
}
Color previous_color;
@@ -980,6 +987,8 @@ void TextEdit::_notification(int p_what) {
}
// draw main text
+ cursor.visible = false;
+ const int caret_wrap_index = get_cursor_wrap_index();
int row_height = get_row_height();
int line = first_visible_line;
for (int i = 0; i < draw_amount; i++) {
@@ -1048,11 +1057,11 @@ void TextEdit::_notification(int p_what) {
break;
}
- if (text.is_marked(line)) {
+ if (text.get_line_background_color(line) != Color(0, 0, 0, 0)) {
if (rtl) {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), cache.mark_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), text.get_line_background_color(line));
} else {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, row_height), cache.mark_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, row_height), text.get_line_background_color(line));
}
}
@@ -1180,7 +1189,8 @@ void TextEdit::_notification(int p_what) {
if (rect.position.x < xmargin_beg) {
rect.size.x -= (xmargin_beg - rect.position.x);
rect.position.x = xmargin_beg;
- } else if (rect.position.x + rect.size.x > xmargin_end) {
+ }
+ if (rect.position.x + rect.size.x > xmargin_end) {
rect.size.x = xmargin_end - rect.position.x;
}
draw_rect(rect, cache.selection_color, true);
@@ -1259,7 +1269,6 @@ void TextEdit::_notification(int p_what) {
}
}
- const int line_top_offset_y = ofs_y;
ofs_y += (row_height - text_height) / 2;
const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(rid);
@@ -1348,7 +1357,8 @@ void TextEdit::_notification(int p_what) {
}
}
- if (line_wrap_index == line_wrap_amount && is_folded(line)) {
+ // is_line_folded
+ if (line_wrap_index == line_wrap_amount && line < text.size() - 1 && is_line_hidden(line + 1)) {
int xofs = char_ofs + char_margin + ofs_x + (cache.folded_eol_icon->get_width() / 2);
if (xofs >= xmargin_beg && xofs < xmargin_end) {
int yofs = (text_height - cache.folded_eol_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
@@ -1364,9 +1374,9 @@ void TextEdit::_notification(int p_what) {
#else
int caret_width = 1;
#endif
- if (!clipped && cursor.line == line && ((line_wrap_index == line_wrap_amount) || (cursor.column != TS->shaped_text_get_range(rid).y))) {
- is_cursor_line_visible = true;
- cursor_pos.y = line_top_offset_y;
+
+ if (!clipped && cursor.line == line && line_wrap_index == caret_wrap_index) {
+ cursor.draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index);
if (ime_text.length() == 0) {
Rect2 l_caret, t_caret;
@@ -1387,57 +1397,60 @@ void TextEdit::_notification(int p_what) {
}
if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
- cursor_pos.x = char_margin + ofs_x + l_caret.position.x;
+ cursor.draw_pos.x = char_margin + ofs_x + l_caret.position.x;
} else {
- cursor_pos.x = char_margin + ofs_x + t_caret.position.x;
+ cursor.draw_pos.x = char_margin + ofs_x + t_caret.position.x;
}
- if (draw_caret && cursor_pos.x >= xmargin_beg && cursor_pos.x < xmargin_end) {
- if (block_caret || insert_mode) {
- //Block or underline caret, draw trailing carets at full height.
- int h = cache.font->get_height(cache.font_size);
-
- if (t_caret != Rect2()) {
- if (insert_mode) {
- t_caret.position.y = TS->shaped_text_get_descent(rid);
- t_caret.size.y = caret_width;
- } else {
- t_caret.position.y = -TS->shaped_text_get_ascent(rid);
- t_caret.size.y = h;
- }
- t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+ if (cursor.draw_pos.x >= xmargin_beg && cursor.draw_pos.x < xmargin_end) {
+ cursor.visible = true;
+ if (draw_caret) {
+ if (block_caret || insert_mode) {
+ //Block or underline caret, draw trailing carets at full height.
+ int h = cache.font->get_height(cache.font_size);
+
+ if (t_caret != Rect2()) {
+ if (insert_mode) {
+ t_caret.position.y = TS->shaped_text_get_descent(rid);
+ t_caret.size.y = caret_width;
+ } else {
+ t_caret.position.y = -TS->shaped_text_get_ascent(rid);
+ t_caret.size.y = h;
+ }
+ t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+
+ draw_rect(t_caret, cache.caret_color, false);
+ } else { // End of the line.
+ if (insert_mode) {
+ l_caret.position.y = TS->shaped_text_get_descent(rid);
+ l_caret.size.y = caret_width;
+ } else {
+ l_caret.position.y = -TS->shaped_text_get_ascent(rid);
+ l_caret.size.y = h;
+ }
+ l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+ l_caret.size.x = cache.font->get_char_size('M', 0, cache.font_size).x;
- draw_rect(t_caret, cache.caret_color, false);
- } else { // End of the line.
- if (insert_mode) {
- l_caret.position.y = TS->shaped_text_get_descent(rid);
- l_caret.size.y = caret_width;
- } else {
- l_caret.position.y = -TS->shaped_text_get_ascent(rid);
- l_caret.size.y = h;
+ draw_rect(l_caret, cache.caret_color, false);
+ }
+ } else {
+ // Normal caret.
+ if (l_caret != Rect2() && l_dir == TextServer::DIRECTION_AUTO) {
+ // Draw extra marker on top of mid caret.
+ Rect2 trect = Rect2(l_caret.position.x - 3 * caret_width, l_caret.position.y, 6 * caret_width, caret_width);
+ trect.position += Vector2(char_margin + ofs_x, ofs_y);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, cache.caret_color);
}
l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
- l_caret.size.x = cache.font->get_char_size('M', 0, cache.font_size).x;
-
- draw_rect(l_caret, cache.caret_color, false);
- }
- } else {
- // Normal caret.
- if (l_caret != Rect2() && l_dir == TextServer::DIRECTION_AUTO) {
- // Draw extra marker on top of mid caret.
- Rect2 trect = Rect2(l_caret.position.x - 3 * caret_width, l_caret.position.y, 6 * caret_width, caret_width);
- trect.position += Vector2(char_margin + ofs_x, ofs_y);
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, cache.caret_color);
- }
- l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
- l_caret.size.x = caret_width;
+ l_caret.size.x = caret_width;
- draw_rect(l_caret, cache.caret_color);
+ draw_rect(l_caret, cache.caret_color);
- t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
- t_caret.size.x = caret_width;
+ t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+ t_caret.size.x = caret_width;
- draw_rect(t_caret, cache.caret_color);
+ draw_rect(t_caret, cache.caret_color);
+ }
}
}
} else {
@@ -1457,7 +1470,7 @@ void TextEdit::_notification(int p_what) {
}
rect.size.y = caret_width;
draw_rect(rect, cache.caret_color);
- cursor_pos.x = rect.position.x;
+ cursor.draw_pos.x = rect.position.x;
}
}
{
@@ -1476,7 +1489,7 @@ void TextEdit::_notification(int p_what) {
}
rect.size.y = caret_width * 3;
draw_rect(rect, cache.caret_color);
- cursor_pos.x = rect.position.x;
+ cursor.draw_pos.x = rect.position.x;
}
}
}
@@ -1484,227 +1497,10 @@ void TextEdit::_notification(int p_what) {
}
}
- bool completion_below = false;
- if (completion_active && is_cursor_line_visible && completion_options.size() > 0) {
- // Completion panel
-
- const Ref<StyleBox> csb = get_theme_stylebox("completion");
- const int maxlines = get_theme_constant("completion_lines");
- const int cmax_width = get_theme_constant("completion_max_width") * cache.font->get_char_size('x', 0, cache.font_size).x;
- const Color scrollc = get_theme_color("completion_scroll_color");
-
- const int completion_options_size = completion_options.size();
- const int row_count = MIN(completion_options_size, maxlines);
- const int completion_rows_height = row_count * row_height;
- const int completion_base_width = cache.font->get_string_size(completion_base, cache.font_size).width;
-
- int scroll_rectangle_width = get_theme_constant("completion_scroll_width");
- int width = 0;
-
- // Compute max width of the panel based on the longest completion option
- if (completion_options_size < 50) {
- for (int i = 0; i < completion_options_size; i++) {
- int line_width = MIN(cache.font->get_string_size(completion_options[i].display, cache.font_size).x, cmax_width);
- if (line_width > width) {
- width = line_width;
- }
- }
- } else {
- width = cmax_width;
- }
-
- // Add space for completion icons.
- const int icon_hsep = get_theme_constant("hseparation", "ItemList");
- const Size2 icon_area_size(row_height, row_height);
- const int icon_area_width = icon_area_size.width + icon_hsep;
- width += icon_area_width;
-
- const int line_from = CLAMP(completion_index - row_count / 2, 0, completion_options_size - row_count);
-
- for (int i = 0; i < row_count; i++) {
- int l = line_from + i;
- ERR_CONTINUE(l < 0 || l >= completion_options_size);
- if (completion_options[l].default_value.get_type() == Variant::COLOR) {
- width += icon_area_size.width;
- break;
- }
- }
-
- // Position completion panel
- completion_rect.size.width = width + 2;
- completion_rect.size.height = completion_rows_height;
-
- if (completion_options_size <= maxlines) {
- scroll_rectangle_width = 0;
- }
-
- const Point2 csb_offset = csb->get_offset();
-
- const int total_width = completion_rect.size.width + csb->get_minimum_size().x + scroll_rectangle_width;
- const int total_height = completion_rect.size.height + csb->get_minimum_size().y;
-
- const int rect_left_border_x = cursor_pos.x - completion_base_width - icon_area_width - csb_offset.x;
- const int rect_right_border_x = rect_left_border_x + total_width;
-
- if (rect_left_border_x < 0) {
- // Anchor the completion panel to the left
- completion_rect.position.x = 0;
- } else if (rect_right_border_x > get_size().width) {
- // Anchor the completion panel to the right
- completion_rect.position.x = get_size().width - total_width;
- } else {
- // Let the completion panel float with the cursor
- completion_rect.position.x = rect_left_border_x;
- }
-
- if (cursor_pos.y + row_height + total_height > get_size().height && cursor_pos.y > total_height) {
- // Completion panel above the cursor line
- completion_rect.position.y = cursor_pos.y - total_height;
- } else {
- // Completion panel below the cursor line
- completion_rect.position.y = cursor_pos.y + row_height;
- completion_below = true;
- }
-
- draw_style_box(csb, Rect2(completion_rect.position - csb_offset, completion_rect.size + csb->get_minimum_size() + Size2(scroll_rectangle_width, 0)));
-
- if (cache.completion_background_color.a > 0.01) {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(completion_rect.position, completion_rect.size + Size2(scroll_rectangle_width, 0)), cache.completion_background_color);
- }
- 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(completion_base_width, completion_rect.size.width - (icon_area_size.x + icon_hsep)), completion_rect.size.height)), cache.completion_existing_color);
-
- for (int i = 0; i < row_count; i++) {
- int l = line_from + i;
- ERR_CONTINUE(l < 0 || l >= completion_options_size);
-
- Ref<TextLine> tl;
- tl.instance();
- tl->add_string(completion_options[l].display, cache.font, cache.font_size);
-
- int yofs = (row_height - tl->get_size().y) / 2;
- Point2 title_pos(completion_rect.position.x, completion_rect.position.y + i * row_height + yofs);
-
- // Draw completion icon if it is valid.
- Ref<Texture2D> icon = completion_options[l].icon;
- Rect2 icon_area(completion_rect.position.x, completion_rect.position.y + i * row_height, icon_area_size.width, icon_area_size.height);
- if (icon.is_valid()) {
- const real_t max_scale = 0.7f;
- const real_t side = max_scale * icon_area.size.width;
- real_t scale = MIN(side / icon->get_width(), side / icon->get_height());
- Size2 icon_size = icon->get_size() * scale;
- draw_texture_rect(icon, Rect2(icon_area.position + (icon_area.size - icon_size) / 2, icon_size));
- }
-
- title_pos.x = icon_area.position.x + icon_area.size.width + icon_hsep;
-
- tl->set_width(completion_rect.size.width - (icon_area_size.x + icon_hsep));
-
- if (rtl) {
- if (completion_options[l].default_value.get_type() == Variant::COLOR) {
- draw_rect(Rect2(Point2(completion_rect.position.x, icon_area.position.y), icon_area_size), (Color)completion_options[l].default_value);
- }
- tl->set_align(HALIGN_RIGHT);
- } else {
- if (completion_options[l].default_value.get_type() == Variant::COLOR) {
- draw_rect(Rect2(Point2(completion_rect.position.x + completion_rect.size.width - icon_area_size.x, icon_area.position.y), icon_area_size), (Color)completion_options[l].default_value);
- }
- tl->set_align(HALIGN_LEFT);
- }
- if (cache.outline_size > 0 && cache.outline_color.a > 0) {
- tl->draw_outline(ci, title_pos, cache.outline_size, cache.outline_color);
- }
- tl->draw(ci, title_pos, completion_options[l].font_color);
- }
-
- if (scroll_rectangle_width) {
- // Draw a small scroll rectangle to show a position in the options.
- 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, scroll_rectangle_width, completion_rect.size.y * r), scrollc);
- }
-
- completion_line_ofs = line_from;
- }
-
- // Check to see if the hint should be drawn.
- bool show_hint = false;
- if (is_cursor_line_visible && completion_hint != "") {
- if (completion_active) {
- if (completion_below && !callhint_below) {
- show_hint = true;
- } else if (!completion_below && callhint_below) {
- show_hint = true;
- }
- } else {
- show_hint = true;
- }
- }
-
- if (show_hint) {
- Ref<StyleBox> sb = get_theme_stylebox("panel", "TooltipPanel");
- Ref<Font> font = cache.font;
- Color font_color = get_theme_color("font_color", "TooltipLabel");
-
- int max_w = 0;
- int sc = completion_hint.get_slice_count("\n");
- int offset = 0;
- int spacing = 0;
- for (int i = 0; i < sc; i++) {
- String l = completion_hint.get_slice("\n", i);
- int len = font->get_string_size(l, cache.font_size).x;
- max_w = MAX(len, max_w);
- if (i == 0) {
- offset = font->get_string_size(l.substr(0, l.find(String::chr(0xFFFF))), cache.font_size).x;
- } else {
- spacing += cache.line_spacing;
- }
- }
-
- Size2 size2 = Size2(max_w, sc * font->get_height(cache.font_size) + spacing);
- Size2 minsize = size2 + sb->get_minimum_size();
-
- if (completion_hint_offset == -0xFFFF) {
- completion_hint_offset = cursor_pos.x - offset;
- }
-
- Point2 hint_ofs = Vector2(completion_hint_offset, cursor_pos.y) + callhint_offset;
-
- if (callhint_below) {
- hint_ofs.y += row_height + sb->get_offset().y;
- } else {
- hint_ofs.y -= minsize.y + sb->get_offset().y;
- }
-
- draw_style_box(sb, Rect2(hint_ofs, minsize));
-
- spacing = 0;
- for (int i = 0; i < sc; i++) {
- int begin = 0;
- int end = 0;
- String l = completion_hint.get_slice("\n", i);
-
- if (l.find(String::chr(0xFFFF)) != -1) {
- begin = font->get_string_size(l.substr(0, l.find(String::chr(0xFFFF))), cache.font_size).x;
- end = font->get_string_size(l.substr(0, l.rfind(String::chr(0xFFFF))), cache.font_size).x;
- }
-
- Point2 round_ofs = hint_ofs + sb->get_offset() + Vector2(0, font->get_ascent(cache.font_size) + font->get_height(cache.font_size) * i + spacing);
- round_ofs = round_ofs.round();
- draw_string(font, round_ofs, l.replace(String::chr(0xFFFF), ""), HALIGN_LEFT, -1, cache.font_size, font_color);
- if (end > 0) {
- Vector2 b = hint_ofs + sb->get_offset() + Vector2(begin, font->get_height(cache.font_size) + font->get_height(cache.font_size) * i + spacing - 1);
- draw_line(b, b + Vector2(end - begin, 0), font_color);
- }
- spacing += cache.line_spacing;
- }
- }
-
if (has_focus()) {
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
- DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id());
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor.draw_pos, get_viewport()->get_window_id());
}
}
} break;
@@ -2054,6 +1850,7 @@ void TextEdit::indent_selected_lines_left() {
if (is_selection_active() && get_selection_to_column() == 0) {
end_line--;
}
+ String first_line_text = get_line(start_line);
String last_line_text = get_line(end_line);
for (int i = start_line; i <= end_line; i++) {
@@ -2078,10 +1875,17 @@ void TextEdit::indent_selected_lines_left() {
}
}
- // Fix selection and cursor being off by one on the last line.
- if (is_selection_active() && last_line_text != get_line(end_line)) {
- select(selection.from_line, selection.from_column - removed_characters,
- selection.to_line, initial_selection_end_column - removed_characters);
+ if (is_selection_active()) {
+ // Fix selection being off by one on the first line.
+ if (first_line_text != get_line(start_line)) {
+ select(selection.from_line, selection.from_column - removed_characters,
+ selection.to_line, initial_selection_end_column);
+ }
+ // Fix selection being off by one on the last line.
+ if (last_line_text != get_line(end_line)) {
+ select(selection.from_line, selection.from_column,
+ selection.to_line, initial_selection_end_column - removed_characters);
+ }
}
cursor_set_column(initial_cursor_column - removed_characters, false);
end_complex_operation();
@@ -2143,10 +1947,6 @@ void TextEdit::_new_line(bool p_split_current_line, bool p_above) {
}
}
- if (is_folded(cursor.line)) {
- unfold_line(cursor.line);
- }
-
bool brace_indent = false;
// No need to indent if we are going upwards.
@@ -2411,8 +2211,6 @@ void TextEdit::_move_cursor_up(bool p_select) {
if (p_select) {
_post_shift_selection();
}
-
- _cancel_code_hint();
}
void TextEdit::_move_cursor_down(bool p_select) {
@@ -2435,8 +2233,6 @@ void TextEdit::_move_cursor_down(bool p_select) {
if (p_select) {
_post_shift_selection();
}
-
- _cancel_code_hint();
}
void TextEdit::_move_cursor_to_line_start(bool p_select) {
@@ -2476,9 +2272,6 @@ void TextEdit::_move_cursor_to_line_start(bool p_select) {
if (p_select) {
_post_shift_selection();
}
-
- _cancel_completion();
- completion_hint = "";
}
void TextEdit::_move_cursor_to_line_end(bool p_select) {
@@ -2504,8 +2297,6 @@ void TextEdit::_move_cursor_to_line_end(bool p_select) {
if (p_select) {
_post_shift_selection();
}
- _cancel_completion();
- completion_hint = "";
}
void TextEdit::_move_cursor_page_up(bool p_select) {
@@ -2522,9 +2313,6 @@ void TextEdit::_move_cursor_page_up(bool p_select) {
if (p_select) {
_post_shift_selection();
}
-
- _cancel_completion();
- completion_hint = "";
}
void TextEdit::_move_cursor_page_down(bool p_select) {
@@ -2541,9 +2329,6 @@ void TextEdit::_move_cursor_page_down(bool p_select) {
if (p_select) {
_post_shift_selection();
}
-
- _cancel_completion();
- completion_hint = "";
}
void TextEdit::_backspace(bool p_word, bool p_all_to_left) {
@@ -2576,10 +2361,6 @@ void TextEdit::_backspace(bool p_word, bool p_all_to_left) {
cursor_set_line(line, false);
cursor_set_column(column);
} else {
- // One character.
- if (cursor.line > 0 && is_line_hidden(cursor.line - 1)) {
- unfold_line(cursor.line - 1);
- }
backspace_at_cursor();
}
}
@@ -2676,11 +2457,7 @@ void TextEdit::_move_cursor_document_end(bool p_select) {
}
}
-void TextEdit::_handle_unicode_character(uint32_t unicode, bool p_had_selection, bool p_update_auto_complete) {
- if (p_update_auto_complete) {
- _reset_caret_blink_timer();
- }
-
+void TextEdit::_handle_unicode_character(uint32_t unicode, bool p_had_selection) {
if (p_had_selection) {
_delete_selection();
}
@@ -2697,11 +2474,6 @@ void TextEdit::_handle_unicode_character(uint32_t unicode, bool p_had_selection,
const char32_t chr[2] = { (char32_t)unicode, 0 };
- // Clear completion hint when function closed
- if (completion_hint != "" && unicode == ')') {
- completion_hint = "";
- }
-
if (auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
_consume_pair_symbol(chr[0]);
} else {
@@ -2711,10 +2483,6 @@ void TextEdit::_handle_unicode_character(uint32_t unicode, bool p_had_selection,
if ((insert_mode && !p_had_selection) || (selection.active != p_had_selection)) {
end_complex_operation();
}
-
- if (p_update_auto_complete) {
- _update_completion_candidates();
- }
}
void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const {
@@ -2870,53 +2638,27 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
// Ignore mouse clicks in IME input mode.
return;
}
- if (completion_active && completion_rect.has_point(mpos)) {
- if (!mb->is_pressed()) {
- return;
- }
-
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
- if (completion_index > 0) {
- completion_index--;
- completion_current = completion_options[completion_index];
- update();
- }
- }
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
- if (completion_index < completion_options.size() - 1) {
- completion_index++;
- completion_current = completion_options[completion_index];
- update();
- }
- }
-
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- completion_index = CLAMP(completion_line_ofs + (mpos.y - completion_rect.position.y) / get_row_height(), 0, completion_options.size() - 1);
-
- completion_current = completion_options[completion_index];
- update();
- if (mb->is_doubleclick()) {
- _confirm_completion();
- }
- }
- return;
- } else {
- _cancel_completion();
- _cancel_code_hint();
- }
if (mb->is_pressed()) {
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !mb->get_command()) {
- if (mb->get_shift()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !mb->is_command_pressed()) {
+ if (mb->is_shift_pressed()) {
h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor()));
+ } else if (mb->is_alt_pressed()) {
+ // Scroll 5 times as fast as normal (like in Visual Studio Code).
+ _scroll_up(15 * mb->get_factor());
} else if (v_scroll->is_visible()) {
+ // Scroll 3 lines.
_scroll_up(3 * mb->get_factor());
}
}
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !mb->get_command()) {
- if (mb->get_shift()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !mb->is_command_pressed()) {
+ if (mb->is_shift_pressed()) {
h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor()));
+ } else if (mb->is_alt_pressed()) {
+ // Scroll 5 times as fast as normal (like in Visual Studio Code).
+ _scroll_down(15 * mb->get_factor());
} else if (v_scroll->is_visible()) {
+ // Scroll 3 lines.
_scroll_down(3 * mb->get_factor());
}
}
@@ -2946,15 +2688,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
left_margin += gutters[i].width;
}
- // Unfold on folded icon click.
- if (is_folded(row)) {
- left_margin += gutter_padding + text.get_line_width(row) - cursor.x_ofs;
- if (mpos.x > left_margin && mpos.x <= left_margin + cache.folded_eol_icon->get_width() + 3) {
- unfold_line(row);
- return;
- }
- }
-
// minimap
if (draw_minimap) {
_update_minimap_click();
@@ -2969,7 +2702,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
cursor_set_line(row, false, false);
cursor_set_column(col);
- if (mb->get_shift() && (cursor.column != prev_col || cursor.line != prev_line)) {
+ if (mb->is_shift_pressed() && (cursor.column != prev_col || cursor.line != prev_line)) {
if (!selection.active) {
selection.active = true;
selection.selecting_mode = SelectionMode::SELECTION_MODE_POINTER;
@@ -3018,12 +2751,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
selection.selecting_column = col;
}
- if (!mb->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < 600 && cursor.line == prev_line) {
+ if (!mb->is_double_click() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < 600 && cursor.line == prev_line) {
// Triple-click select line.
selection.selecting_mode = SelectionMode::SELECTION_MODE_LINE;
_update_selection_mode_line();
last_dblclk = 0;
- } else if (mb->is_doubleclick() && text[cursor.line].length()) {
+ } else if (mb->is_double_click() && text[cursor.line].length()) {
// Double-click select word.
selection.selecting_mode = SelectionMode::SELECTION_MODE_WORD;
_update_selection_mode_word();
@@ -3065,7 +2798,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
} else {
if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (mb->get_command() && highlighted_word != String()) {
+ if (mb->is_command_pressed() && highlighted_word != String()) {
int row, col;
_get_mouse_pos(Point2i(mpos.x, mpos.y), row, col);
@@ -3108,7 +2841,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
mpos.x = get_size().x - mpos.x;
}
if (select_identifiers_enabled) {
- if (!dragging_minimap && !dragging_selection && mm->get_command() && mm->get_button_mask() == 0) {
+ if (!dragging_minimap && !dragging_selection && mm->is_command_pressed() && mm->get_button_mask() == 0) {
String new_word = get_word_at_pos(mpos);
if (new_word != highlighted_word) {
emit_signal("symbol_validate", new_word);
@@ -3157,7 +2890,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
#ifdef OSX_ENABLED
if (k->get_keycode() == KEY_META) {
#else
- if (k->get_keycode() == KEY_CONTROL) {
+ if (k->get_keycode() == KEY_CTRL) {
#endif
if (select_identifiers_enabled) {
if (k->is_pressed() && !dragging_minimap && !dragging_selection) {
@@ -3175,7 +2908,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
// If a modifier has been pressed, and nothing else, return.
- if (k->get_keycode() == KEY_CONTROL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT || k->get_keycode() == KEY_META) {
+ if (k->get_keycode() == KEY_CTRL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT || k->get_keycode() == KEY_META) {
return;
}
@@ -3183,7 +2916,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
// Allow unicode handling if:
// * No Modifiers are pressed (except shift)
- bool allow_unicode_handling = !(k->get_command() || k->get_control() || k->get_alt() || k->get_metakey());
+ bool allow_unicode_handling = !(k->is_command_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
// Save here for insert mode, just in case it is cleared in the following section.
bool had_selection = selection.active;
@@ -3192,96 +2925,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
// Check and handle all built in shortcuts.
- // AUTO-COMPLETE
-
- if (k->is_action("ui_text_completion_query", true)) {
- query_code_comple();
- accept_event();
- return;
- }
-
- if (completion_active) {
- if (k->is_action("ui_up", true)) {
- if (completion_index > 0) {
- completion_index--;
- } else {
- completion_index = completion_options.size() - 1;
- }
- completion_current = completion_options[completion_index];
- update();
- accept_event();
- return;
- }
- if (k->is_action("ui_down", true)) {
- if (completion_index < completion_options.size() - 1) {
- completion_index++;
- } else {
- completion_index = 0;
- }
- completion_current = completion_options[completion_index];
- update();
- accept_event();
- return;
- }
- if (k->is_action("ui_page_up", true)) {
- completion_index -= get_theme_constant("completion_lines");
- if (completion_index < 0) {
- completion_index = 0;
- }
- completion_current = completion_options[completion_index];
- update();
- accept_event();
- return;
- }
- if (k->is_action("ui_page_down", true)) {
- completion_index += get_theme_constant("completion_lines");
- if (completion_index >= completion_options.size()) {
- completion_index = completion_options.size() - 1;
- }
- completion_current = completion_options[completion_index];
- update();
- accept_event();
- return;
- }
- if (k->is_action("ui_home", true)) {
- if (completion_index > 0) {
- completion_index = 0;
- completion_current = completion_options[completion_index];
- update();
- }
- accept_event();
- return;
- }
- if (k->is_action("ui_end", true)) {
- if (completion_index < completion_options.size() - 1) {
- completion_index = completion_options.size() - 1;
- completion_current = completion_options[completion_index];
- update();
- }
- accept_event();
- return;
- }
- if (k->is_action("ui_text_completion_accept", true)) {
- _confirm_completion();
- accept_event();
- return;
- }
- if (k->is_action("ui_cancel", true)) {
- _cancel_completion();
- accept_event();
- return;
- }
-
- // Handle Unicode here (if no modifiers active) and update autocomplete.
- if (k->get_unicode() >= 32) {
- if (allow_unicode_handling && !readonly) {
- _handle_unicode_character(k->get_unicode(), had_selection, true);
- accept_event();
- return;
- }
- }
- }
-
// NEWLINES.
if (k->is_action("ui_text_newline_above", true)) {
_new_line(false, true);
@@ -3324,9 +2967,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (k->is_action("ui_text_backspace", true)) {
_backspace();
- if (completion_active) {
- _update_completion_candidates();
- }
accept_event();
return;
}
@@ -3358,13 +2998,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- // SELECT ALL, CUT, COPY, PASTE.
+ // SELECT ALL, SELECT WORD UNDER CARET, CUT, COPY, PASTE.
if (k->is_action("ui_text_select_all", true)) {
select_all();
accept_event();
return;
}
+ if (k->is_action("ui_text_select_word_under_caret", true)) {
+ select_word_under_caret();
+ accept_event();
+ return;
+ }
if (k->is_action("ui_cut", true)) {
cut();
accept_event();
@@ -3394,7 +3039,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
// MISC.
-
if (k->is_action("ui_menu", true)) {
if (context_menu_enabled) {
menu->set_position(get_screen_transform().xform(_get_cursor_pixel_pos()));
@@ -3411,14 +3055,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
accept_event();
return;
}
- if (k->is_action("ui_cancel", true)) {
- if (completion_hint != "") {
- completion_hint = "";
- update();
- }
- accept_event();
- return;
- }
if (k->is_action("ui_swap_input_direction", true)) {
_swap_current_input_direction();
accept_event();
@@ -3428,9 +3064,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
// CURSOR MOVEMENT
k = k->duplicate();
- bool shift_pressed = k->get_shift();
+ bool shift_pressed = k->is_shift_pressed();
// Remove shift or else actions will not match. Use above variable for selection.
- k->set_shift(false);
+ k->set_shift_pressed(false);
// CURSOR MOVEMENT - LEFT, RIGHT.
if (k->is_action("ui_text_caret_word_left", true)) {
@@ -3504,7 +3140,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (allow_unicode_handling && !readonly && k->get_unicode() >= 32) {
// Handle Unicode (if no modifiers active).
- _handle_unicode_character(k->get_unicode(), had_selection, false);
+ _handle_unicode_character(k->get_unicode(), had_selection);
accept_event();
return;
}
@@ -4054,10 +3690,6 @@ void TextEdit::center_viewport_to_cursor() {
scrolling = false;
minimap_clicked = false;
- if (is_line_hidden(cursor.line)) {
- unfold_line(cursor.line);
- }
-
set_line_as_center_visible(cursor.line, get_cursor_wrap_index());
int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding - cache.minimap_width;
if (v_scroll->is_visible_in_tree()) {
@@ -4265,6 +3897,14 @@ void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_
}
}
+Point2 TextEdit::get_caret_draw_pos() const {
+ return cursor.draw_pos;
+}
+
+bool TextEdit::is_caret_visible() const {
+ return cursor.visible;
+}
+
int TextEdit::cursor_get_column() const {
return cursor.column;
}
@@ -4442,10 +4082,6 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
return CURSOR_POINTING_HAND;
}
- if ((completion_active && completion_rect.has_point(p_pos))) {
- return CURSOR_ARROW;
- }
-
int row, col;
_get_mouse_pos(p_pos, row, col);
@@ -4471,15 +4107,6 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
if (draw_minimap && p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) {
return CURSOR_ARROW;
}
-
- // EOL fold icon.
- if (is_folded(row)) {
- gutter += gutter_padding + text.get_line_width(row) - cursor.x_ofs;
- if (p_pos.x > gutter - 3 && p_pos.x <= gutter + cache.folded_eol_icon->get_width() + 3) {
- return CURSOR_POINTING_HAND;
- }
- }
-
return get_default_cursor_shape();
}
@@ -4657,26 +4284,6 @@ String TextEdit::get_text_for_lookup_completion() {
return longthing;
}
-String TextEdit::get_text_for_completion() {
- String longthing;
- int len = text.size();
- for (int i = 0; i < len; i++) {
- if (i == cursor.line) {
- longthing += text[i].substr(0, cursor.column);
- longthing += String::chr(0xFFFF); // Not unicode, represents the cursor.
- longthing += text[i].substr(cursor.column, text[i].size());
- } else {
- longthing += text[i];
- }
-
- if (i != len - 1) {
- longthing += "\n";
- }
- }
-
- return longthing;
-};
-
String TextEdit::get_line(int line) const {
if (line < 0 || line >= text.size()) {
return "";
@@ -4685,6 +4292,10 @@ String TextEdit::get_line(int line) const {
return text[line];
};
+bool TextEdit::has_ime_text() const {
+ return !ime_text.is_empty();
+}
+
void TextEdit::_clear() {
clear_undo_history();
text.clear();
@@ -4759,10 +4370,6 @@ void TextEdit::_update_caches() {
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.font_size = get_theme_font_size("font_size");
cache.outline_color = get_theme_color("font_outline_color");
@@ -4773,10 +4380,9 @@ void TextEdit::_update_caches() {
cache.font_selected_color = get_theme_color("font_selected_color");
cache.font_readonly_color = get_theme_color("font_readonly_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.code_folding_color = get_theme_color("code_folding_color");
+ cache.code_folding_color = get_theme_color("code_folding_color", "CodeEdit");
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");
@@ -4789,7 +4395,7 @@ void TextEdit::_update_caches() {
#endif
cache.tab_icon = get_theme_icon("tab");
cache.space_icon = get_theme_icon("space");
- cache.folded_eol_icon = get_theme_icon("GuiEllipsis", "EditorIcons");
+ cache.folded_eol_icon = get_theme_icon("folded_eol_icon", "CodeEdit");
TextServer::Direction dir;
if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
@@ -4898,6 +4504,10 @@ int TextEdit::get_gutter_width(int p_gutter) const {
return gutters[p_gutter].width;
}
+int TextEdit::get_total_gutter_width() const {
+ return gutters_width + gutter_padding;
+}
+
void TextEdit::set_gutter_draw(int p_gutter, bool p_draw) {
ERR_FAIL_INDEX(p_gutter, gutters.size());
gutters.write[p_gutter].draw = p_draw;
@@ -5003,6 +4613,18 @@ bool TextEdit::is_line_gutter_clickable(int p_line, int p_gutter) const {
return text.is_line_gutter_clickable(p_line, p_gutter);
}
+// Line style
+void TextEdit::set_line_background_color(int p_line, const Color &p_color) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ text.set_line_background_color(p_line, p_color);
+ update();
+}
+
+Color TextEdit::get_line_background_color(int p_line) {
+ ERR_FAIL_INDEX_V(p_line, text.size(), Color());
+ return text.get_line_background_color(p_line);
+}
+
void TextEdit::add_keyword(const String &p_keyword) {
keywords.insert(p_keyword);
}
@@ -5115,6 +4737,39 @@ void TextEdit::select_all() {
update();
}
+void TextEdit::select_word_under_caret() {
+ if (!selecting_enabled) {
+ return;
+ }
+
+ if (text.size() == 1 && text[0].length() == 0) {
+ return;
+ }
+
+ if (selection.active) {
+ // Allow toggling selection by pressing the shortcut a second time.
+ // This is also usable as a general-purpose "deselect" shortcut after
+ // selecting anything.
+ deselect();
+ return;
+ }
+
+ int begin = 0;
+ int end = 0;
+ const Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(cursor.line)->get_rid());
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].x <= cursor.column && words[i].y >= cursor.column) {
+ begin = words[i].x;
+ end = words[i].y;
+ break;
+ }
+ }
+
+ select(cursor.line, begin, cursor.line, end);
+ // Move the cursor to the end of the word for easier editing.
+ cursor_set_column(end, false);
+}
+
void TextEdit::deselect() {
selection.active = false;
update();
@@ -5421,12 +5076,6 @@ void TextEdit::_text_changed_emit() {
text_changed_dirty = false;
}
-void TextEdit::set_line_as_marked(int p_line, bool p_marked) {
- ERR_FAIL_INDEX(p_line, text.size());
- text.set_marked(p_line, p_marked);
- update();
-}
-
void TextEdit::set_line_as_hidden(int p_line, bool p_hidden) {
ERR_FAIL_INDEX(p_line, text.size());
if (is_hiding_enabled() || !p_hidden) {
@@ -5440,14 +5089,6 @@ bool TextEdit::is_line_hidden(int p_line) const {
return text.is_hidden(p_line);
}
-void TextEdit::fold_all_lines() {
- for (int i = 0; i < text.size(); i++) {
- fold_line(i);
- }
- _update_scrollbars();
- update();
-}
-
void TextEdit::unhide_all_lines() {
for (int i = 0; i < text.size(); i++) {
text.set_hidden(i, false);
@@ -5595,151 +5236,14 @@ bool TextEdit::is_line_comment(int p_line) const {
return false;
}
-bool TextEdit::can_fold(int p_line) const {
- ERR_FAIL_INDEX_V(p_line, text.size(), false);
- if (!is_hiding_enabled()) {
- return false;
- }
- if (p_line + 1 >= text.size()) {
- return false;
- }
- if (text[p_line].strip_edges().size() == 0) {
- return false;
- }
- if (is_folded(p_line)) {
- return false;
- }
- if (is_line_hidden(p_line)) {
- return false;
- }
- if (is_line_comment(p_line)) {
- return false;
- }
-
- int start_indent = get_indent_level(p_line);
-
- for (int i = p_line + 1; i < text.size(); i++) {
- if (text[i].strip_edges().size() == 0) {
- continue;
- }
- int next_indent = get_indent_level(i);
- if (is_line_comment(i)) {
- continue;
- } else if (next_indent > start_indent) {
- return true;
- } else {
- return false;
- }
- }
-
- return false;
-}
-
-bool TextEdit::is_folded(int p_line) const {
- ERR_FAIL_INDEX_V(p_line, text.size(), false);
- if (p_line + 1 >= text.size()) {
- return false;
- }
- return !is_line_hidden(p_line) && is_line_hidden(p_line + 1);
-}
-
-Vector<int> TextEdit::get_folded_lines() const {
- Vector<int> folded_lines;
-
- for (int i = 0; i < text.size(); i++) {
- if (is_folded(i)) {
- folded_lines.push_back(i);
- }
- }
- return folded_lines;
-}
-
-void TextEdit::fold_line(int p_line) {
- ERR_FAIL_INDEX(p_line, text.size());
- if (!is_hiding_enabled()) {
- return;
- }
- if (!can_fold(p_line)) {
- return;
- }
-
- // Hide lines below this one.
- int start_indent = get_indent_level(p_line);
- int last_line = start_indent;
- for (int i = p_line + 1; i < text.size(); i++) {
- if (text[i].strip_edges().size() != 0) {
- if (is_line_comment(i)) {
- continue;
- } else if (get_indent_level(i) > start_indent) {
- last_line = i;
- } else {
- break;
- }
- }
- }
- for (int i = p_line + 1; i <= last_line; i++) {
- set_line_as_hidden(i, true);
- }
-
- // Fix selection.
- if (is_selection_active()) {
- if (is_line_hidden(selection.from_line) && is_line_hidden(selection.to_line)) {
- deselect();
- } else if (is_line_hidden(selection.from_line)) {
- select(p_line, 9999, selection.to_line, selection.to_column);
- } else if (is_line_hidden(selection.to_line)) {
- select(selection.from_line, selection.from_column, p_line, 9999);
- }
- }
-
- // Reset cursor.
- if (is_line_hidden(cursor.line)) {
- cursor_set_line(p_line, false, false);
- cursor_set_column(get_line(p_line).length(), false);
- }
- _update_scrollbars();
- update();
-}
-
-void TextEdit::unfold_line(int p_line) {
- ERR_FAIL_INDEX(p_line, text.size());
-
- if (!is_folded(p_line) && !is_line_hidden(p_line)) {
- return;
- }
- int fold_start;
- for (fold_start = p_line; fold_start > 0; fold_start--) {
- if (is_folded(fold_start)) {
- break;
- }
- }
- fold_start = is_folded(fold_start) ? fold_start : p_line;
-
- for (int i = fold_start + 1; i < text.size(); i++) {
- if (is_line_hidden(i)) {
- set_line_as_hidden(i, false);
- } else {
- break;
- }
- }
- _update_scrollbars();
- update();
-}
-
-void TextEdit::toggle_fold_line(int p_line) {
- ERR_FAIL_INDEX(p_line, text.size());
-
- if (!is_folded(p_line)) {
- fold_line(p_line);
- } else {
- unfold_line(p_line);
- }
-}
-
int TextEdit::get_line_count() const {
return text.size();
}
+int TextEdit::get_line_width(int p_line, int p_wrap_offset) const {
+ return text.get_line_width(p_line, p_wrap_offset);
+}
+
void TextEdit::_do_text_op(const TextOperation &p_op, bool p_reverse) {
ERR_FAIL_COND(p_op.type == TextOperation::TYPE_NONE);
@@ -5819,7 +5323,6 @@ void TextEdit::undo() {
if (undo_stack_pos->get().type == TextOperation::TYPE_REMOVE) {
cursor_set_line(undo_stack_pos->get().to_line, false);
cursor_set_column(undo_stack_pos->get().to_column);
- _cancel_code_hint();
} else {
cursor_set_line(undo_stack_pos->get().from_line, false);
cursor_set_column(undo_stack_pos->get().from_column);
@@ -6095,313 +5598,6 @@ float TextEdit::get_v_scroll_speed() const {
return v_scroll_speed;
}
-void TextEdit::set_completion(bool p_enabled, const Vector<String> &p_prefixes) {
- completion_prefixes.clear();
- completion_enabled = p_enabled;
- for (int i = 0; i < p_prefixes.size(); i++) {
- completion_prefixes.insert(p_prefixes[i]);
- }
-}
-
-void TextEdit::_confirm_completion() {
- begin_complex_operation();
-
- _remove_text(cursor.line, cursor.column - completion_base.length(), cursor.line, cursor.column);
- cursor_set_column(cursor.column - completion_base.length(), false);
- insert_text_at_cursor(completion_current.insert_text);
-
- // When inserted into the middle of an existing string/method, don't add an unnecessary quote/bracket.
- String line = text[cursor.line];
- char32_t next_char = line[cursor.column];
- char32_t last_completion_char = completion_current.insert_text[completion_current.insert_text.length() - 1];
- char32_t last_completion_char_display = completion_current.display[completion_current.display.length() - 1];
-
- if ((last_completion_char == '"' || last_completion_char == '\'') && (last_completion_char == next_char || last_completion_char_display == next_char)) {
- _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
- }
-
- if (last_completion_char == '(') {
- if (next_char == last_completion_char) {
- _base_remove_text(cursor.line, cursor.column - 1, cursor.line, cursor.column);
- } else if (auto_brace_completion_enabled) {
- insert_text_at_cursor(")");
- cursor.column--;
- }
- } else if (last_completion_char == ')' && next_char == '(') {
- _base_remove_text(cursor.line, cursor.column - 2, cursor.line, cursor.column);
- if (line[cursor.column + 1] != ')') {
- cursor.column--;
- }
- }
-
- end_complex_operation();
-
- _cancel_completion();
-
- if (last_completion_char == '(') {
- query_code_comple();
- }
-}
-
-void TextEdit::_cancel_code_hint() {
- completion_hint = "";
- update();
-}
-
-void TextEdit::_cancel_completion() {
- if (!completion_active) {
- return;
- }
-
- completion_active = false;
- completion_forced = false;
- update();
-}
-
-static bool _is_completable(char32_t c) {
- return !_is_symbol(c) || c == '"' || c == '\'';
-}
-
-void TextEdit::_update_completion_candidates() {
- String l = text[cursor.line];
- int cofs = CLAMP(cursor.column, 0, l.length());
-
- String s;
-
- // Look for keywords first.
-
- bool inquote = false;
- int first_quote = -1;
- int restore_quotes = -1;
-
- int c = cofs - 1;
- while (c >= 0) {
- if (l[c] == '"' || l[c] == '\'') {
- inquote = !inquote;
- if (first_quote == -1) {
- first_quote = c;
- }
- restore_quotes = 0;
- } else if (restore_quotes == 0 && l[c] == '$') {
- restore_quotes = 1;
- } else if (restore_quotes == 0 && !_is_whitespace(l[c])) {
- restore_quotes = -1;
- }
- c--;
- }
-
- bool pre_keyword = false;
- bool cancel = false;
-
- if (!inquote && first_quote == cofs - 1) {
- // No completion here.
- cancel = true;
- } else if (inquote && first_quote != -1) {
- s = l.substr(first_quote, cofs - first_quote);
- } else if (cofs > 0 && l[cofs - 1] == ' ') {
- int kofs = cofs - 1;
- String kw;
- while (kofs >= 0 && l[kofs] == ' ') {
- kofs--;
- }
-
- while (kofs >= 0 && l[kofs] > 32 && _is_completable(l[kofs])) {
- kw = String::chr(l[kofs]) + kw;
- kofs--;
- }
-
- pre_keyword = keywords.has(kw);
-
- } else {
- while (cofs > 0 && l[cofs - 1] > 32 && (l[cofs - 1] == '/' || _is_completable(l[cofs - 1]))) {
- s = String::chr(l[cofs - 1]) + s;
- if (l[cofs - 1] == '\'' || l[cofs - 1] == '"' || l[cofs - 1] == '$') {
- break;
- }
-
- cofs--;
- }
- }
-
- if (cursor.column > 0 && l[cursor.column - 1] == '(' && !pre_keyword && !completion_forced) {
- cancel = true;
- }
-
- update();
-
- bool prev_is_prefix = false;
- if (cofs > 0 && completion_prefixes.has(String::chr(l[cofs - 1]))) {
- prev_is_prefix = true;
- }
- // Check with one space before prefix, to allow indent.
- if (cofs > 1 && l[cofs - 1] == ' ' && completion_prefixes.has(String::chr(l[cofs - 2]))) {
- prev_is_prefix = true;
- }
-
- if (cancel || (!pre_keyword && s == "" && (cofs == 0 || !prev_is_prefix))) {
- // None to complete, cancel.
- _cancel_completion();
- return;
- }
-
- completion_options.clear();
- completion_index = 0;
- completion_base = s;
- Vector<float> sim_cache;
- bool single_quote = s.begins_with("'");
- Vector<ScriptCodeCompletionOption> completion_options_casei;
- Vector<ScriptCodeCompletionOption> completion_options_subseq;
- Vector<ScriptCodeCompletionOption> completion_options_subseq_casei;
-
- String s_lower = s.to_lower();
-
- for (List<ScriptCodeCompletionOption>::Element *E = completion_sources.front(); E; E = E->next()) {
- ScriptCodeCompletionOption &option = E->get();
-
- if (single_quote && option.display.is_quoted()) {
- option.display = option.display.unquote().quote("'");
- }
-
- if (inquote && restore_quotes == 1 && !option.display.is_quoted()) {
- String quote = single_quote ? "'" : "\"";
- option.display = option.display.quote(quote);
- option.insert_text = option.insert_text.quote(quote);
- }
-
- if (option.display.length() == 0) {
- continue;
- } else if (s.length() == 0) {
- completion_options.push_back(option);
- } else {
- // This code works the same as:
- /*
- if (option.display.begins_with(s)) {
- completion_options.push_back(option);
- } else if (option.display.to_lower().begins_with(s.to_lower())) {
- completion_options_casei.push_back(option);
- } else if (s.is_subsequence_of(option.display)) {
- completion_options_subseq.push_back(option);
- } else if (s.is_subsequence_ofi(option.display)) {
- completion_options_subseq_casei.push_back(option);
- }
- */
- // But is more performant due to being inlined and looping over the characters only once
-
- String display_lower = option.display.to_lower();
-
- const char32_t *ssq = &s[0];
- const char32_t *ssq_lower = &s_lower[0];
-
- const char32_t *tgt = &option.display[0];
- const char32_t *tgt_lower = &display_lower[0];
-
- const char32_t *ssq_last_tgt = nullptr;
- const char32_t *ssq_lower_last_tgt = nullptr;
-
- for (; *tgt; tgt++, tgt_lower++) {
- if (*ssq == *tgt) {
- ssq++;
- ssq_last_tgt = tgt;
- }
- if (*ssq_lower == *tgt_lower) {
- ssq_lower++;
- ssq_lower_last_tgt = tgt;
- }
- }
-
- if (!*ssq) { // Matched the whole subsequence in s
- if (ssq_last_tgt == &option.display[s.length() - 1]) { // Finished matching in the first s.length() characters
- completion_options.push_back(option);
- } else {
- completion_options_subseq.push_back(option);
- }
- } else if (!*ssq_lower) { // Matched the whole subsequence in s_lower
- if (ssq_lower_last_tgt == &option.display[s.length() - 1]) { // Finished matching in the first s.length() characters
- completion_options_casei.push_back(option);
- } else {
- completion_options_subseq_casei.push_back(option);
- }
- }
- }
- }
-
- completion_options.append_array(completion_options_casei);
- completion_options.append_array(completion_options_subseq);
- completion_options.append_array(completion_options_subseq_casei);
-
- if (completion_options.size() == 0) {
- // No options to complete, cancel.
- _cancel_completion();
- return;
- }
-
- if (completion_options.size() == 1 && s == completion_options[0].display) {
- // A perfect match, stop completion.
- _cancel_completion();
- return;
- }
-
- // The top of the list is the best match.
- completion_current = completion_options[0];
- completion_enabled = true;
-}
-
-void TextEdit::query_code_comple() {
- String l = text[cursor.line];
- int ofs = CLAMP(cursor.column, 0, l.length());
-
- bool inquote = false;
-
- int c = ofs - 1;
- while (c >= 0) {
- if (l[c] == '"' || l[c] == '\'') {
- inquote = !inquote;
- }
- c--;
- }
-
- bool ignored = completion_active && !completion_options.is_empty();
- if (ignored) {
- ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_PLAIN_TEXT;
- const ScriptCodeCompletionOption *previous_option = nullptr;
- for (int i = 0; i < completion_options.size(); i++) {
- const ScriptCodeCompletionOption &current_option = completion_options[i];
- if (!previous_option) {
- previous_option = &current_option;
- kind = current_option.kind;
- }
- if (previous_option->kind != current_option.kind) {
- ignored = false;
- break;
- }
- }
- ignored = ignored && (kind == ScriptCodeCompletionOption::KIND_FILE_PATH || kind == ScriptCodeCompletionOption::KIND_NODE_PATH || kind == ScriptCodeCompletionOption::KIND_SIGNAL);
- }
-
- if (!ignored) {
- if (ofs > 0 && (inquote || _is_completable(l[ofs - 1]) || completion_prefixes.has(String::chr(l[ofs - 1])))) {
- emit_signal("request_completion");
- } else if (ofs > 1 && l[ofs - 1] == ' ' && completion_prefixes.has(String::chr(l[ofs - 2]))) { // Make it work with a space too, it's good enough.
- emit_signal("request_completion");
- }
- }
-}
-
-void TextEdit::set_code_hint(const String &p_hint) {
- completion_hint = p_hint;
- completion_hint_offset = -0xFFFF;
- update();
-}
-
-void TextEdit::code_complete(const List<ScriptCodeCompletionOption> &p_strings, bool p_forced) {
- completion_sources = p_strings;
- completion_active = true;
- completion_forced = p_forced;
- completion_current = ScriptCodeCompletionOption();
- completion_index = 0;
- _update_completion_candidates();
-}
-
String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
int row, col;
_get_mouse_pos(p_pos, row, col);
@@ -6837,6 +6033,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_count"), &TextEdit::get_line_count);
ClassDB::bind_method(D_METHOD("get_text"), &TextEdit::get_text);
ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line);
+ ClassDB::bind_method(D_METHOD("get_visible_line_count"), &TextEdit::get_total_visible_rows);
ClassDB::bind_method(D_METHOD("set_line", "line", "new_text"), &TextEdit::set_line);
ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override", "parser"), &TextEdit::set_structured_text_bidi_override);
@@ -6848,6 +6045,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("cursor_set_column", "column", "adjust_viewport"), &TextEdit::cursor_set_column, DEFVAL(true));
ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport", "can_be_hidden", "wrap_index"), &TextEdit::cursor_set_line, DEFVAL(true), DEFVAL(true), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_caret_draw_pos"), &TextEdit::get_caret_draw_pos);
+ ClassDB::bind_method(D_METHOD("is_caret_visible"), &TextEdit::is_caret_visible);
ClassDB::bind_method(D_METHOD("cursor_get_column"), &TextEdit::cursor_get_column);
ClassDB::bind_method(D_METHOD("cursor_get_line"), &TextEdit::cursor_get_line);
ClassDB::bind_method(D_METHOD("cursor_set_blink_enabled", "enable"), &TextEdit::cursor_set_blink_enabled);
@@ -6908,18 +6107,6 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_draw_spaces"), &TextEdit::set_draw_spaces);
ClassDB::bind_method(D_METHOD("is_drawing_spaces"), &TextEdit::is_drawing_spaces);
- ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled);
- ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled);
- ClassDB::bind_method(D_METHOD("set_line_as_hidden", "line", "enable"), &TextEdit::set_line_as_hidden);
- ClassDB::bind_method(D_METHOD("is_line_hidden", "line"), &TextEdit::is_line_hidden);
- ClassDB::bind_method(D_METHOD("fold_all_lines"), &TextEdit::fold_all_lines);
- ClassDB::bind_method(D_METHOD("unhide_all_lines"), &TextEdit::unhide_all_lines);
- ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line);
- ClassDB::bind_method(D_METHOD("unfold_line", "line"), &TextEdit::unfold_line);
- ClassDB::bind_method(D_METHOD("toggle_fold_line", "line"), &TextEdit::toggle_fold_line);
- ClassDB::bind_method(D_METHOD("can_fold", "line"), &TextEdit::can_fold);
- ClassDB::bind_method(D_METHOD("is_folded", "line"), &TextEdit::is_folded);
-
ClassDB::bind_method(D_METHOD("set_highlight_all_occurrences", "enable"), &TextEdit::set_highlight_all_occurrences);
ClassDB::bind_method(D_METHOD("is_highlight_all_occurrences_enabled"), &TextEdit::is_highlight_all_occurrences_enabled);
@@ -6963,6 +6150,10 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_line_gutter_clickable", "line", "gutter", "clickable"), &TextEdit::set_line_gutter_clickable);
ClassDB::bind_method(D_METHOD("is_line_gutter_clickable", "line", "gutter"), &TextEdit::is_line_gutter_clickable);
+ // Line style
+ ClassDB::bind_method(D_METHOD("set_line_background_color", "line", "color"), &TextEdit::set_line_background_color);
+ ClassDB::bind_method(D_METHOD("get_line_background_color", "line"), &TextEdit::get_line_background_color);
+
ClassDB::bind_method(D_METHOD("set_highlight_current_line", "enabled"), &TextEdit::set_highlight_current_line);
ClassDB::bind_method(D_METHOD("is_highlight_current_line_enabled"), &TextEdit::is_highlight_current_line_enabled);
@@ -6984,7 +6175,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_minimap_width"), &TextEdit::get_minimap_width);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars"), "set_draw_control_chars", "get_draw_control_chars");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "readonly"), "set_readonly", "is_readonly");
@@ -6999,7 +6190,6 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hiding_enabled"), "set_hiding_enabled", "is_hiding_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_enabled"), "set_wrap_enabled", "is_wrap_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_vertical"), "set_v_scroll", "get_v_scroll");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_horizontal"), "set_h_scroll", "get_h_scroll");
@@ -7024,7 +6214,6 @@ void TextEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("cursor_changed"));
ADD_SIGNAL(MethodInfo("text_changed"));
ADD_SIGNAL(MethodInfo("lines_edited_from", PropertyInfo(Variant::INT, "from_line"), PropertyInfo(Variant::INT, "to_line")));
- ADD_SIGNAL(MethodInfo("request_completion"));
ADD_SIGNAL(MethodInfo("gutter_clicked", PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::INT, "gutter")));
ADD_SIGNAL(MethodInfo("gutter_added"));
ADD_SIGNAL(MethodInfo("gutter_removed"));
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index b0c7314c65..c04d758abb 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -92,7 +92,7 @@ private:
Vector<Vector2i> bidi_override;
Ref<TextParagraph> data_buf;
- bool marked = false;
+ Color background_color = Color(0, 0, 0, 0);
bool hidden = false;
Line() {
@@ -124,17 +124,16 @@ private:
void set_draw_control_chars(bool p_draw_control_chars);
int get_line_height(int p_line, int p_wrap_index) const;
- int get_line_width(int p_line) const;
+ int get_line_width(int p_line, int p_wrap_index = -1) const;
int get_max_width(bool p_exclude_hidden = false) const;
void set_width(float p_width);
int get_line_wrap_amount(int p_line) const;
+
Vector<Vector2i> get_line_wrap_ranges(int p_line) const;
const Ref<TextParagraph> get_line_data(int p_line) const;
void set(int p_line, const String &p_text, const Vector<Vector2i> &p_bidi_override);
- void set_marked(int p_line, bool p_marked) { text.write[p_line].marked = p_marked; }
- bool is_marked(int p_line) const { return text[p_line].marked; }
void set_hidden(int p_line, bool p_hidden) { text.write[p_line].hidden = p_hidden; }
bool is_hidden(int p_line) const { return text[p_line].hidden; }
void insert(int p_at, const String &p_text, const Vector<Vector2i> &p_bidi_override);
@@ -167,9 +166,15 @@ private:
void set_line_gutter_clickable(int p_line, int p_gutter, bool p_clickable) { text.write[p_line].gutters.write[p_gutter].clickable = p_clickable; }
bool is_line_gutter_clickable(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].clickable; }
+
+ /* Line style. */
+ void set_line_background_color(int p_line, const Color &p_color) { text.write[p_line].background_color = p_color; }
+ const Color get_line_background_color(int p_line) const { return text[p_line].background_color; }
};
struct Cursor {
+ Point2 draw_pos;
+ bool visible = false;
int last_fit_x = 0;
int line = 0;
int column = 0; ///< cursor
@@ -236,20 +241,6 @@ private:
Dictionary _get_line_syntax_highlighting(int p_line);
- Set<String> completion_prefixes;
- bool completion_enabled = false;
- List<ScriptCodeCompletionOption> completion_sources;
- Vector<ScriptCodeCompletionOption> completion_options;
- bool completion_active = false;
- bool completion_forced = false;
- ScriptCodeCompletionOption completion_current;
- String completion_base;
- int completion_index = 0;
- Rect2i completion_rect;
- int completion_line_ofs = 0;
- String completion_hint;
- int completion_hint_offset = 0;
-
bool setting_text = false;
// data
@@ -303,10 +294,10 @@ private:
bool highlight_all_occurrences = false;
bool scroll_past_end_of_file_enabled = false;
- bool auto_brace_completion_enabled = false;
bool brace_matching_enabled = false;
bool highlight_current_line = false;
bool auto_indent = false;
+
String cut_copy_line;
bool insert_mode = false;
bool select_identifiers_enabled = false;
@@ -338,9 +329,6 @@ private:
bool next_operation_is_complex = false;
- bool callhint_below = false;
- Vector2 callhint_offset;
-
String search_text;
uint32_t search_flags = 0;
int search_result_line = 0;
@@ -361,11 +349,8 @@ private:
void update_cursor_wrap_offset();
void _update_wrap_at(bool p_force = false);
- bool line_wraps(int line) const;
- int times_line_wraps(int line) const;
Vector<String> get_wrap_rows_text(int p_line) const;
int get_cursor_wrap_index() const;
- int get_line_wrap_index_at_col(int p_line, int p_column) const;
int get_char_count();
double get_scroll_pos_for_line(int p_line, int p_wrap_index = 0) const;
@@ -434,10 +419,6 @@ private:
PopupMenu *menu_ctl;
void _clear();
- void _cancel_completion();
- void _cancel_code_hint();
- void _confirm_completion();
- void _update_completion_candidates();
int _calculate_spaces_till_next_left_indent(int column);
int _calculate_spaces_till_next_right_indent(int column);
@@ -460,9 +441,11 @@ private:
void _delete_selection();
void _move_cursor_document_start(bool p_select);
void _move_cursor_document_end(bool p_select);
- void _handle_unicode_character(uint32_t unicode, bool p_had_selection, bool p_update_auto_complete);
+ void _handle_unicode_character(uint32_t unicode, bool p_had_selection);
protected:
+ bool auto_brace_completion_enabled = false;
+
struct Cache {
Ref<Texture2D> tab_icon;
Ref<Texture2D> space_icon;
@@ -474,17 +457,12 @@ protected:
int font_size = 16;
int outline_size = 0;
Color outline_color;
- Color completion_background_color;
- Color completion_selected_color;
- Color completion_existing_color;
- Color completion_font_color;
Color caret_color;
Color caret_background_color;
Color font_color;
Color font_selected_color;
Color font_readonly_color;
Color selection_color;
- Color mark_color;
Color code_folding_color;
Color current_line_color;
Color line_length_guideline_color;
@@ -503,7 +481,7 @@ protected:
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);
+ virtual void _gui_input(const Ref<InputEvent> &p_gui_input);
void _notification(int p_what);
void _consume_pair_symbol(char32_t ch);
@@ -533,6 +511,7 @@ public:
void set_gutter_width(int p_gutter, int p_width);
int get_gutter_width(int p_gutter) const;
+ int get_total_gutter_width() const;
void set_gutter_draw(int p_gutter, bool p_draw);
bool is_gutter_drawn(int p_gutter) const;
@@ -561,6 +540,10 @@ public:
void set_line_gutter_clickable(int p_line, int p_gutter, bool p_clickable);
bool is_line_gutter_clickable(int p_line, int p_gutter) const;
+ // Line style
+ void set_line_background_color(int p_line, const Color &p_color);
+ Color get_line_background_color(int p_line);
+
enum MenuItems {
MENU_CUT,
MENU_COPY,
@@ -637,25 +620,19 @@ public:
void insert_text_at_cursor(const String &p_text);
void insert_at(const String &p_text, int at);
int get_line_count() const;
- void set_line_as_marked(int p_line, bool p_marked);
+ int get_line_width(int p_line, int p_wrap_offset = -1) const;
+ int get_line_wrap_index_at_col(int p_line, int p_column) const;
void set_line_as_hidden(int p_line, bool p_hidden);
bool is_line_hidden(int p_line) const;
- void fold_all_lines();
void unhide_all_lines();
int num_lines_from(int p_line_from, int visible_amount) const;
int num_lines_from_rows(int p_line_from, int p_wrap_index_from, int visible_amount, int &wrap_index) const;
int get_last_unhidden_line() const;
- bool can_fold(int p_line) const;
- bool is_folded(int p_line) const;
- Vector<int> get_folded_lines() const;
- void fold_line(int p_line);
- void unfold_line(int p_line);
- void toggle_fold_line(int p_line);
-
String get_text();
String get_line(int line) const;
+ bool has_ime_text() const;
void set_line(int line, String new_text);
int get_row_height() const;
void backspace_at_cursor();
@@ -676,10 +653,6 @@ public:
brace_matching_enabled = p_enabled;
update();
}
- inline void set_callhint_settings(bool below, Vector2 offset) {
- callhint_below = below;
- callhint_offset = offset;
- }
void set_auto_indent(bool p_auto_indent);
void center_viewport_to_cursor();
@@ -690,6 +663,8 @@ public:
void cursor_set_column(int p_col, bool p_adjust_viewport = true);
void cursor_set_line(int p_row, bool p_adjust_viewport = true, bool p_can_be_hidden = true, int p_wrap_index = 0);
+ Point2 get_caret_draw_pos() const;
+ bool is_caret_visible() const;
int cursor_get_column() const;
int cursor_get_line() const;
Vector2i _get_cursor_pixel_pos(bool p_adjust_viewport = true);
@@ -719,6 +694,8 @@ public:
void set_wrap_enabled(bool p_wrap_enabled);
bool is_wrap_enabled() const;
+ bool line_wraps(int line) const;
+ int times_line_wraps(int line) const;
void clear();
@@ -726,6 +703,7 @@ public:
void copy();
void paste();
void select_all();
+ void select_word_under_caret();
void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column);
void deselect();
void swap_lines(int line1, int line2);
@@ -805,11 +783,6 @@ public:
void set_tooltip_request_func(Object *p_obj, const StringName &p_function, const Variant &p_udata);
- void set_completion(bool p_enabled, const Vector<String> &p_prefixes);
- void code_complete(const List<ScriptCodeCompletionOption> &p_strings, bool p_forced = false);
- void set_code_hint(const String &p_hint);
- void query_code_comple();
-
void set_select_identifiers_on_hover(bool p_enable);
bool is_selecting_identifiers_on_hover_enabled() const;
@@ -827,7 +800,6 @@ public:
PopupMenu *get_menu() const;
- String get_text_for_completion();
String get_text_for_lookup_completion();
virtual bool is_text_field() const override;
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index f43e3d1a9d..8659ea06a2 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -295,11 +295,13 @@ void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) {
void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) {
pressed = p_pressed;
update();
+ minimum_size_changed();
}
void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) {
hover = p_hover;
update();
+ minimum_size_changed();
}
void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) {
@@ -310,6 +312,7 @@ void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) {
void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) {
click_mask = p_click_mask;
update();
+ minimum_size_changed();
}
Ref<Texture2D> TextureButton::get_normal_texture() const {
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 73fd9dbcd7..26d881955b 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -47,36 +47,6 @@
#include <limits.h>
-void TreeItem::move_to_top() {
- if (!parent || parent->children == this) {
- return; //already on top
- }
- TreeItem *prev = get_prev();
- prev->next = next;
- next = parent->children;
- parent->children = this;
-}
-
-void TreeItem::move_to_bottom() {
- if (!parent || !next) {
- return;
- }
-
- TreeItem *prev = get_prev();
- TreeItem *last = next;
- while (last->next) {
- last = last->next;
- }
-
- if (prev) {
- prev->next = next;
- } else {
- parent->children = next;
- }
- last->next = this;
- next = nullptr;
-}
-
Size2 TreeItem::Cell::get_icon_size() const {
if (icon.is_null()) {
return Size2();
@@ -118,6 +88,54 @@ void TreeItem::_cell_deselected(int p_cell) {
tree->item_deselected(p_cell, this);
}
+void TreeItem::_change_tree(Tree *p_tree) {
+ if (p_tree == tree) {
+ return;
+ }
+
+ TreeItem *c = first_child;
+ while (c) {
+ c->_change_tree(p_tree);
+ c = c->next;
+ }
+
+ if (tree && tree->root == this) {
+ tree->root = nullptr;
+ }
+
+ if (tree && tree->popup_edited_item == this) {
+ tree->popup_edited_item = nullptr;
+ tree->pressing_for_editor = false;
+ }
+
+ if (tree && tree->cache.hover_item == this) {
+ tree->cache.hover_item = nullptr;
+ }
+
+ if (tree && tree->selected_item == this) {
+ tree->selected_item = nullptr;
+ }
+
+ if (tree && tree->drop_mode_over == this) {
+ tree->drop_mode_over = nullptr;
+ }
+
+ if (tree && tree->single_select_defer == this) {
+ tree->single_select_defer = nullptr;
+ }
+
+ if (tree && tree->edited_item == this) {
+ tree->edited_item = nullptr;
+ tree->pressing_for_editor = false;
+ }
+
+ tree = p_tree;
+
+ if (tree) {
+ cells.resize(tree->columns.size());
+ }
+}
+
/* cell mode */
void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) {
ERR_FAIL_INDEX(p_column, cells.size());
@@ -427,20 +445,74 @@ int TreeItem::get_custom_minimum_height() const {
return custom_min_height;
}
+/* Item manipulation */
+
+TreeItem *TreeItem::create_child(int p_idx) {
+ TreeItem *ti = memnew(TreeItem(tree));
+ if (tree) {
+ ti->cells.resize(tree->columns.size());
+ }
+
+ TreeItem *l_prev = nullptr;
+ TreeItem *c = first_child;
+ int idx = 0;
+
+ while (c) {
+ if (idx++ == p_idx) {
+ c->prev = ti;
+ ti->next = c;
+ break;
+ }
+ l_prev = c;
+ c = c->next;
+ }
+
+ if (l_prev) {
+ l_prev->next = ti;
+ ti->prev = l_prev;
+ if (!children_cache.is_empty()) {
+ if (ti->next) {
+ children_cache.insert(p_idx, ti);
+ } else {
+ children_cache.append(ti);
+ }
+ }
+ } else {
+ first_child = ti;
+ if (!children_cache.is_empty()) {
+ children_cache.insert(0, ti);
+ }
+ }
+
+ ti->parent = this;
+
+ return ti;
+}
+
+Tree *TreeItem::get_tree() {
+ return tree;
+}
+
TreeItem *TreeItem::get_next() {
return next;
}
TreeItem *TreeItem::get_prev() {
- if (!parent || parent->children == this) {
- return nullptr;
+ if (prev) {
+ return prev;
}
- TreeItem *prev = parent->children;
- while (prev && prev->next != this) {
- prev = prev->next;
+ if (!parent || parent->first_child == this) {
+ return nullptr;
+ }
+ // This is an edge case
+ TreeItem *l_prev = parent->first_child;
+ while (l_prev && l_prev->next != this) {
+ l_prev = l_prev->next;
}
+ prev = l_prev;
+
return prev;
}
@@ -448,8 +520,8 @@ TreeItem *TreeItem::get_parent() {
return parent;
}
-TreeItem *TreeItem::get_children() {
- return children;
+TreeItem *TreeItem::get_first_child() {
+ return first_child;
}
TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
@@ -475,10 +547,10 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
}
} else {
current = prev;
- while (!current->collapsed && current->children) {
+ while (!current->collapsed && current->first_child) {
//go to the very end
- current = current->children;
+ current = current->first_child;
while (current->next) {
current = current->next;
}
@@ -491,8 +563,8 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
TreeItem *TreeItem::get_next_visible(bool p_wrap) {
TreeItem *current = this;
- if (!current->collapsed && current->children) {
- current = current->children;
+ if (!current->collapsed && current->first_child) {
+ current = current->first_child;
} else if (current->next) {
current = current->next;
@@ -515,24 +587,136 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) {
return current;
}
-void TreeItem::remove_child(TreeItem *p_item) {
+TreeItem *TreeItem::get_child(int p_idx) {
+ _create_children_cache();
+ ERR_FAIL_INDEX_V(p_idx, children_cache.size(), nullptr);
+ return children_cache.get(p_idx);
+}
+
+int TreeItem::get_child_count() {
+ _create_children_cache();
+ return children_cache.size();
+}
+
+Array TreeItem::get_children() {
+ int size = get_child_count();
+ Array arr;
+ arr.resize(size);
+ for (int i = 0; i < size; i++) {
+ arr[i] = children_cache[i];
+ }
+
+ return arr;
+}
+
+int TreeItem::get_index() {
+ int idx = 0;
+ TreeItem *c = this;
+
+ while (c) {
+ c = c->get_prev();
+ idx++;
+ }
+ return idx - 1;
+}
+
+void TreeItem::move_before(TreeItem *p_item) {
+ ERR_FAIL_NULL(p_item);
+ ERR_FAIL_COND(is_root);
+ ERR_FAIL_COND(!p_item->parent);
+
+ if (p_item == this) {
+ return;
+ }
+
+ TreeItem *p = p_item->parent;
+ while (p) {
+ ERR_FAIL_COND_MSG(p == this, "Can't move to a descendant");
+ p = p->parent;
+ }
+
+ Tree *old_tree = tree;
+ _unlink_from_tree();
+ _change_tree(p_item->tree);
+
+ parent = p_item->parent;
+
+ TreeItem *item_prev = p_item->get_prev();
+ if (item_prev) {
+ item_prev->next = this;
+ parent->children_cache.clear();
+ } else {
+ parent->first_child = this;
+ parent->children_cache.insert(0, this);
+ }
+
+ prev = item_prev;
+ next = p_item;
+ p_item->prev = this;
+
+ if (old_tree && old_tree != tree) {
+ old_tree->update();
+ }
+
+ if (tree) {
+ tree->update();
+ }
+}
+
+void TreeItem::move_after(TreeItem *p_item) {
ERR_FAIL_NULL(p_item);
- TreeItem **c = &children;
+ ERR_FAIL_COND(is_root);
+ ERR_FAIL_COND(!p_item->parent);
- while (*c) {
- if ((*c) == p_item) {
- TreeItem *aux = *c;
+ if (p_item == this) {
+ return;
+ }
- *c = (*c)->next;
+ TreeItem *p = p_item->parent;
+ while (p) {
+ ERR_FAIL_COND_MSG(p == this, "Can't move to a descendant");
+ p = p->parent;
+ }
- aux->parent = nullptr;
- return;
- }
+ Tree *old_tree = tree;
+ _unlink_from_tree();
+ _change_tree(p_item->tree);
+
+ if (p_item->next) {
+ p_item->next->prev = this;
+ }
+ parent = p_item->parent;
+ prev = p_item;
+ next = p_item->next;
+ p_item->next = this;
+
+ if (next) {
+ parent->children_cache.clear();
+ } else {
+ parent->children_cache.append(this);
+ }
- c = &(*c)->next;
+ if (old_tree && old_tree != tree) {
+ old_tree->update();
}
- ERR_FAIL();
+ if (tree) {
+ tree->update();
+ }
+}
+
+void TreeItem::remove_child(TreeItem *p_item) {
+ ERR_FAIL_NULL(p_item);
+ ERR_FAIL_COND(p_item->parent != this);
+
+ p_item->_unlink_from_tree();
+ p_item->prev = nullptr;
+ p_item->next = nullptr;
+ p_item->parent = nullptr;
+
+ if (tree) {
+ tree->update();
+ }
}
void TreeItem::set_selectable(int p_column, bool p_selectable) {
@@ -686,6 +870,15 @@ void TreeItem::clear_custom_color(int p_column) {
_changed_notify(p_column);
}
+void TreeItem::set_custom_font(int p_column, const Ref<Font> &p_font) {
+ ERR_FAIL_INDEX(p_column, cells.size());
+ cells.write[p_column].custom_font = p_font;
+}
+Ref<Font> TreeItem::get_custom_font(int p_column) const {
+ ERR_FAIL_INDEX_V(p_column, cells.size(), Ref<Font>());
+ return cells[p_column].custom_font;
+}
+
void TreeItem::set_tooltip(int p_column, const String &p_tooltip) {
ERR_FAIL_INDEX(p_column, cells.size());
cells.write[p_column].tooltip = p_tooltip;
@@ -785,7 +978,7 @@ void recursive_call_aux(TreeItem *p_item, const StringName &p_method, const Vari
return;
}
p_item->call(p_method, p_args, p_argcount, r_error);
- TreeItem *c = p_item->get_children();
+ TreeItem *c = p_item->get_first_child();
while (c) {
recursive_call_aux(c, p_method, p_args, p_argcount, r_error);
c = c->get_next();
@@ -855,16 +1048,6 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_minimum_height", "height"), &TreeItem::set_custom_minimum_height);
ClassDB::bind_method(D_METHOD("get_custom_minimum_height"), &TreeItem::get_custom_minimum_height);
- ClassDB::bind_method(D_METHOD("get_next"), &TreeItem::get_next);
- ClassDB::bind_method(D_METHOD("get_prev"), &TreeItem::get_prev);
- ClassDB::bind_method(D_METHOD("get_parent"), &TreeItem::get_parent);
- ClassDB::bind_method(D_METHOD("get_children"), &TreeItem::get_children);
-
- ClassDB::bind_method(D_METHOD("get_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_visible, DEFVAL(false));
-
- ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::_remove_child);
-
ClassDB::bind_method(D_METHOD("set_selectable", "column", "selectable"), &TreeItem::set_selectable);
ClassDB::bind_method(D_METHOD("is_selectable", "column"), &TreeItem::is_selectable);
@@ -876,8 +1059,11 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_editable", "column"), &TreeItem::is_editable);
ClassDB::bind_method(D_METHOD("set_custom_color", "column", "color"), &TreeItem::set_custom_color);
- ClassDB::bind_method(D_METHOD("clear_custom_color", "column"), &TreeItem::clear_custom_color);
ClassDB::bind_method(D_METHOD("get_custom_color", "column"), &TreeItem::get_custom_color);
+ ClassDB::bind_method(D_METHOD("clear_custom_color", "column"), &TreeItem::clear_custom_color);
+
+ ClassDB::bind_method(D_METHOD("set_custom_font", "column", "font"), &TreeItem::set_custom_font);
+ ClassDB::bind_method(D_METHOD("get_custom_font", "column"), &TreeItem::get_custom_font);
ClassDB::bind_method(D_METHOD("set_custom_bg_color", "column", "color", "just_outline"), &TreeItem::set_custom_bg_color, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_custom_bg_color", "column"), &TreeItem::clear_custom_bg_color);
@@ -895,19 +1081,38 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled);
ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled);
- ClassDB::bind_method(D_METHOD("set_expand_right", "column", "enable"), &TreeItem::set_expand_right);
- ClassDB::bind_method(D_METHOD("get_expand_right", "column"), &TreeItem::get_expand_right);
-
ClassDB::bind_method(D_METHOD("set_tooltip", "column", "tooltip"), &TreeItem::set_tooltip);
ClassDB::bind_method(D_METHOD("get_tooltip", "column"), &TreeItem::get_tooltip);
ClassDB::bind_method(D_METHOD("set_text_align", "column", "text_align"), &TreeItem::set_text_align);
ClassDB::bind_method(D_METHOD("get_text_align", "column"), &TreeItem::get_text_align);
- ClassDB::bind_method(D_METHOD("move_to_top"), &TreeItem::move_to_top);
- ClassDB::bind_method(D_METHOD("move_to_bottom"), &TreeItem::move_to_bottom);
+
+ ClassDB::bind_method(D_METHOD("set_expand_right", "column", "enable"), &TreeItem::set_expand_right);
+ ClassDB::bind_method(D_METHOD("get_expand_right", "column"), &TreeItem::get_expand_right);
ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding);
ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled);
+ ClassDB::bind_method(D_METHOD("create_child", "idx"), &TreeItem::create_child, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("get_tree"), &TreeItem::get_tree);
+
+ ClassDB::bind_method(D_METHOD("get_next"), &TreeItem::get_next);
+ ClassDB::bind_method(D_METHOD("get_prev"), &TreeItem::get_prev);
+ ClassDB::bind_method(D_METHOD("get_parent"), &TreeItem::get_parent);
+ ClassDB::bind_method(D_METHOD("get_first_child"), &TreeItem::get_first_child);
+
+ ClassDB::bind_method(D_METHOD("get_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_visible, DEFVAL(false));
+
+ ClassDB::bind_method(D_METHOD("get_child", "idx"), &TreeItem::get_child);
+ ClassDB::bind_method(D_METHOD("get_child_count"), &TreeItem::get_child_count);
+ ClassDB::bind_method(D_METHOD("get_children"), &TreeItem::get_children);
+ ClassDB::bind_method(D_METHOD("get_index"), &TreeItem::get_index);
+
+ ClassDB::bind_method(D_METHOD("move_before", "item"), &TreeItem::_move_before);
+ ClassDB::bind_method(D_METHOD("move_after", "item"), &TreeItem::_move_after);
+
+ ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::_remove_child);
+
{
MethodInfo mi;
mi.name = "call_recursive";
@@ -932,7 +1137,7 @@ void TreeItem::_bind_methods() {
}
void TreeItem::clear_children() {
- TreeItem *c = children;
+ TreeItem *c = first_child;
while (c) {
TreeItem *aux = c;
c = c->get_next();
@@ -940,56 +1145,18 @@ void TreeItem::clear_children() {
memdelete(aux);
}
- children = nullptr;
+ first_child = nullptr;
};
TreeItem::TreeItem(Tree *p_tree) {
tree = p_tree;
- collapsed = false;
- disable_folding = false;
- custom_min_height = 0;
-
- parent = nullptr; // parent item
- next = nullptr; // next in list
- children = nullptr; //child items
}
TreeItem::~TreeItem() {
+ _unlink_from_tree();
+ prev = nullptr;
clear_children();
-
- if (parent) {
- parent->remove_child(this);
- }
-
- if (tree && tree->root == this) {
- tree->root = nullptr;
- }
-
- if (tree && tree->popup_edited_item == this) {
- tree->popup_edited_item = nullptr;
- tree->pressing_for_editor = false;
- }
-
- if (tree && tree->cache.hover_item == this) {
- tree->cache.hover_item = nullptr;
- }
-
- if (tree && tree->selected_item == this) {
- tree->selected_item = nullptr;
- }
-
- if (tree && tree->drop_mode_over == this) {
- tree->drop_mode_over = nullptr;
- }
-
- if (tree && tree->single_select_defer == this) {
- tree->single_select_defer = nullptr;
- }
-
- if (tree && tree->edited_item == this) {
- tree->edited_item = nullptr;
- tree->pressing_for_editor = false;
- }
+ _change_tree(nullptr);
}
/**********************************************/
@@ -1029,15 +1196,23 @@ void Tree::update_cache() {
cache.font_color = get_theme_color("font_color");
cache.font_selected_color = get_theme_color("font_selected_color");
- 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.guide_color = get_theme_color("guide_color");
cache.draw_relationship_lines = get_theme_constant("draw_relationship_lines");
+ cache.relationship_line_width = get_theme_constant("relationship_line_width");
+ cache.parent_hl_line_width = get_theme_constant("parent_hl_line_width");
+ cache.children_hl_line_width = get_theme_constant("children_hl_line_width");
+ cache.parent_hl_line_margin = get_theme_constant("parent_hl_line_margin");
cache.relationship_line_color = get_theme_color("relationship_line_color");
+ cache.parent_hl_line_color = get_theme_color("parent_hl_line_color");
+ cache.children_hl_line_color = get_theme_color("children_hl_line_color");
+
cache.scroll_border = get_theme_constant("scroll_border");
cache.scroll_speed = get_theme_constant("scroll_speed");
@@ -1116,7 +1291,7 @@ int Tree::get_item_height(TreeItem *p_item) const {
if (!p_item->collapsed) { /* if not collapsed, check the children */
- TreeItem *c = p_item->children;
+ TreeItem *c = p_item->first_child;
while (c) {
height += get_item_height(c);
@@ -1209,6 +1384,7 @@ void Tree::update_column(int p_col) {
} else {
columns.write[p_col].text_buf->set_direction((TextServer::Direction)columns[p_col].text_direction);
}
+
columns.write[p_col].text_buf->add_string(columns[p_col].title, cache.font, cache.font_size, columns[p_col].opentype_features, (columns[p_col].language != "") ? columns[p_col].language : TranslationServer::get_singleton()->get_tool_locale());
}
@@ -1253,7 +1429,14 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) {
} else {
p_item->cells.write[p_col].text_buf->set_direction((TextServer::Direction)p_item->cells[p_col].text_direction);
}
- p_item->cells.write[p_col].text_buf->add_string(valtext, cache.font, cache.font_size, p_item->cells[p_col].opentype_features, (p_item->cells[p_col].language != "") ? p_item->cells[p_col].language : TranslationServer::get_singleton()->get_tool_locale());
+
+ Ref<Font> font;
+ if (p_item->cells[p_col].custom_font.is_valid()) {
+ font = p_item->cells[p_col].custom_font;
+ } else {
+ font = cache.font;
+ }
+ p_item->cells.write[p_col].text_buf->add_string(valtext, font, cache.font_size, p_item->cells[p_col].opentype_features, (p_item->cells[p_col].language != "") ? p_item->cells[p_col].language : TranslationServer::get_singleton()->get_tool_locale());
TS->shaped_text_set_bidi_override(p_item->cells[p_col].text_buf->get_rid(), structured_text_parser(p_item->cells[p_col].st_parser, p_item->cells[p_col].st_args, valtext));
p_item->cells.write[p_col].dirty = false;
}
@@ -1263,7 +1446,7 @@ void Tree::update_item_cache(TreeItem *p_item) {
update_item_cell(p_item, i);
}
- TreeItem *c = p_item->children;
+ TreeItem *c = p_item->first_child;
while (c) {
update_item_cache(c);
c = c->next;
@@ -1388,7 +1571,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
}
- if ((select_mode == SELECT_ROW && selected_item == p_item) || p_item->cells[i].selected) {
+ if ((select_mode == SELECT_ROW && selected_item == p_item) || p_item->cells[i].selected || !p_item->has_meta("__focus_rect")) {
Rect2i r(cell_rect.position, cell_rect.size);
p_item->set_meta("__focus_rect", Rect2(r.position, r.size));
@@ -1430,7 +1613,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (drop_mode_flags && drop_mode_over == p_item) {
Rect2 r = cell_rect;
- bool has_parent = p_item->get_children() != nullptr;
+ bool has_parent = p_item->get_first_child() != nullptr;
if (rtl) {
r.position.x = get_size().width - r.position.x - r.size.x;
}
@@ -1626,7 +1809,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
}
- if (!p_item->disable_folding && !hide_folding && p_item->children) { //has children, draw the guide box
+ if (!p_item->disable_folding && !hide_folding && p_item->first_child) { //has children, draw the guide box
Ref<Texture2D> arrow;
@@ -1656,40 +1839,81 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (!p_item->collapsed) { /* if not collapsed, check the children */
- TreeItem *c = p_item->children;
+ TreeItem *c = p_item->first_child;
- int prev_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y;
+ int base_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y;
+ int prev_ofs = base_ofs;
+ int prev_hl_ofs = base_ofs;
while (c) {
if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) {
int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
- int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
+ int parent_ofs = p_pos.x + cache.item_margin;
Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
- if (c->get_children() != nullptr) {
+ if (c->get_first_child() != nullptr) {
root_pos -= Point2i(cache.arrow->get_width(), 0);
}
- float line_width = 1.0;
+ float line_width = cache.relationship_line_width;
+ float parent_line_width = cache.parent_hl_line_width;
+ float children_line_width = cache.children_hl_line_width;
+
#ifdef TOOLS_ENABLED
- line_width *= EDSCALE;
+ line_width *= Math::round(EDSCALE);
+ parent_line_width *= Math::round(EDSCALE);
+ children_line_width *= Math::round(EDSCALE);
#endif
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;
+ int more_prev_ofs = 0;
+
if (root_pos.y + line_width >= 0) {
if (rtl) {
root_pos.x = get_size().width - root_pos.x;
parent_pos.x = get_size().width - parent_pos.x;
}
- 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);
+
+ // Order of parts on this bend: the horizontal line first, then the vertical line.
+ if (_is_branch_selected(c)) {
+ // If this item or one of its children is selected, we draw the line using parent highlight style.
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.parent_hl_line_color, parent_line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
+
+ more_prev_ofs = cache.parent_hl_line_margin;
+ prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
+ } else if (p_item->is_selected(0)) {
+ // If parent item is selected (but this item is not), we draw the line using children highlight style.
+ // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted.
+ if (_is_sibling_branch_selected(c)) {
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
+
+ prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
+ } else {
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(children_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), cache.children_hl_line_color, children_line_width);
+ }
+ } else {
+ // If nothing of the above is true, we draw the line using normal style.
+ // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted.
+ if (_is_sibling_branch_selected(c)) {
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + cache.parent_hl_line_margin, root_pos.y), cache.relationship_line_color, line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width);
+
+ prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2);
+ } else {
+ 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 + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), cache.relationship_line_color, line_width);
+ }
+ }
}
if (htotal < 0) {
return -1;
}
- prev_ofs = root_pos.y;
+ prev_ofs = root_pos.y + more_prev_ofs;
}
if (htotal >= 0) {
@@ -1698,10 +1922,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (child_h < 0) {
if (cache.draw_relationship_lines == 0) {
return -1; // break, stop drawing, no need to anymore
- } else {
- htotal = -1;
- children_pos.y = cache.offset.y + p_draw_size.height;
}
+
+ htotal = -1;
+ children_pos.y = cache.offset.y + p_draw_size.height;
} else {
htotal += child_h;
children_pos.y += child_h;
@@ -1723,8 +1947,8 @@ int Tree::_count_selected_items(TreeItem *p_from) const {
}
}
- if (p_from->get_children()) {
- count += _count_selected_items(p_from->get_children());
+ if (p_from->get_first_child()) {
+ count += _count_selected_items(p_from->get_first_child());
}
if (p_from->get_next()) {
@@ -1734,6 +1958,36 @@ int Tree::_count_selected_items(TreeItem *p_from) const {
return count;
}
+bool Tree::_is_branch_selected(TreeItem *p_from) const {
+ for (int i = 0; i < columns.size(); i++) {
+ if (p_from->is_selected(i)) {
+ return true;
+ }
+ }
+
+ TreeItem *child_item = p_from->get_first_child();
+ while (child_item) {
+ if (_is_branch_selected(child_item)) {
+ return true;
+ }
+ child_item = child_item->get_next();
+ }
+
+ return false;
+}
+
+bool Tree::_is_sibling_branch_selected(TreeItem *p_from) const {
+ TreeItem *sibling_item = p_from->get_next();
+ while (sibling_item) {
+ if (_is_branch_selected(sibling_item)) {
+ return true;
+ }
+ sibling_item = sibling_item->get_next();
+ }
+
+ return false;
+}
+
void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev, bool *r_in_range, bool p_force_deselect) {
TreeItem::Cell &selected_cell = p_selected->cells.write[p_col];
@@ -1812,7 +2066,7 @@ void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_c
*r_in_range = false;
}
- TreeItem *c = p_current->children;
+ TreeItem *c = p_current->first_child;
while (c) {
select_single_item(p_selected, c, p_col, p_prev, r_in_range, p_current->is_collapsed() || p_force_deselect);
@@ -1839,7 +2093,6 @@ void Tree::_range_click_timeout() {
click_handled = false;
Ref<InputEventMouseButton> mb;
mb.instance();
- ;
propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case)
blocked++;
@@ -1866,7 +2119,7 @@ void Tree::_range_click_timeout() {
}
}
-int Tree::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) {
+int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_double_click, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod) {
int item_h = compute_item_height(p_item) + cache.vseparation;
bool skip = (p_item == root && hide_root);
@@ -1879,7 +2132,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
}
if (!p_item->disable_folding && !hide_folding && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) {
- if (p_item->children) {
+ if (p_item->first_child) {
p_item->set_collapsed(!p_item->is_collapsed());
}
@@ -1926,7 +2179,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
x -= cache.hseparation;
}
- if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_children()) {
+ if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_first_child()) {
p_item->set_collapsed(!p_item->is_collapsed());
return -1; //collapse/uncollapse because nothing can be done with item
}
@@ -1963,7 +2216,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
if (p_button == MOUSE_BUTTON_LEFT || (p_button == MOUSE_BUTTON_RIGHT && allow_rmb_select)) {
/* process selection */
- if (p_doubleclick && (!c.editable || c.mode == TreeItem::CELL_MODE_CUSTOM || c.mode == TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it's confusing for check
+ if (p_double_click && (!c.editable || c.mode == TreeItem::CELL_MODE_CUSTOM || c.mode == TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it's confusing for check
propagate_mouse_activated = true;
@@ -1971,7 +2224,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
return -1;
}
- if (select_mode == SELECT_MULTI && p_mod->get_command() && c.selectable) {
+ if (select_mode == SELECT_MULTI && p_mod->is_command_pressed() && c.selectable) {
if (!c.selected || p_button == MOUSE_BUTTON_RIGHT) {
p_item->select(col);
emit_signal("multi_selected", p_item, col, true);
@@ -1988,7 +2241,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
} else {
if (c.selectable) {
- if (select_mode == SELECT_MULTI && p_mod->get_shift() && selected_item && selected_item != p_item) {
+ if (select_mode == SELECT_MULTI && p_mod->is_shift_pressed() && selected_item && selected_item != p_item) {
bool inrange = false;
select_single_item(p_item, root, col, selected_item, &inrange);
@@ -2164,10 +2417,10 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
if (!p_item->collapsed) { /* if not collapsed, check the children */
- TreeItem *c = p_item->children;
+ TreeItem *c = p_item->first_child;
while (c) {
- int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, p_doubleclick, c, p_button, p_mod);
+ int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, p_double_click, c, p_button, p_mod);
if (child_h < 0) {
return -1; // break, stop propagating, no need to anymore
@@ -2198,10 +2451,10 @@ void Tree::_text_editor_modal_close() {
return;
}
- _text_editor_enter(text_editor->get_text());
+ _text_editor_submit(text_editor->get_text());
}
-void Tree::_text_editor_enter(String p_text) {
+void Tree::_text_editor_submit(String p_text) {
popup_editor->hide();
if (!popup_edited_item) {
@@ -2270,7 +2523,7 @@ void Tree::popup_select(int p_option) {
void Tree::_go_left() {
if (selected_col == 0) {
- if (selected_item->get_children() != nullptr && !selected_item->is_collapsed()) {
+ if (selected_item->get_first_child() != nullptr && !selected_item->is_collapsed()) {
selected_item->set_collapsed(true);
} else {
if (columns.size() == 1) { // goto parent with one column
@@ -2298,7 +2551,7 @@ void Tree::_go_left() {
void Tree::_go_right() {
if (selected_col == (columns.size() - 1)) {
- if (selected_item->get_children() != nullptr && selected_item->is_collapsed()) {
+ if (selected_item->get_first_child() != nullptr && selected_item->is_collapsed()) {
selected_item->set_collapsed(false);
} else if (selected_item->get_next_visible()) {
selected_col = 0;
@@ -2406,7 +2659,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventKey> k = p_event;
- bool is_command = k.is_valid() && k->get_command();
+ bool is_command = k.is_valid() && k->is_command_pressed();
if (p_event->is_action("ui_right") && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
@@ -2415,9 +2668,9 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
if (!selected_item || select_mode == SELECT_ROW || selected_col > (columns.size() - 1)) {
return;
}
- if (k.is_valid() && k->get_alt()) {
+ if (k.is_valid() && k->is_alt_pressed()) {
selected_item->set_collapsed(false);
- TreeItem *next = selected_item->get_children();
+ TreeItem *next = selected_item->get_first_child();
while (next && next != selected_item->next) {
next->set_collapsed(false);
next = next->get_next_visible();
@@ -2434,9 +2687,9 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
return;
}
- if (k.is_valid() && k->get_alt()) {
+ if (k.is_valid() && k->is_alt_pressed()) {
selected_item->set_collapsed(true);
- TreeItem *next = selected_item->get_children();
+ TreeItem *next = selected_item->get_first_child();
while (next && next != selected_item->next) {
next->set_collapsed(true);
next = next->get_next_visible();
@@ -2564,7 +2817,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
if (!k->is_pressed()) {
return;
}
- if (k->get_command() || (k->get_shift() && k->get_unicode() == 0) || k->get_metakey()) {
+ if (k->is_command_pressed() || (k->is_shift_pressed() && k->get_unicode() == 0) || k->is_meta_pressed()) {
return;
}
if (!root) {
@@ -2834,7 +3087,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
break;
}
}
- if (!root || (!root->get_children() && hide_root)) {
+ if (!root || (!root->get_first_child() && hide_root)) {
if (b->get_button_index() == MOUSE_BUTTON_RIGHT && allow_rmb_select) {
emit_signal("empty_tree_rmb_selected", get_local_mouse_position());
}
@@ -2846,7 +3099,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
propagate_mouse_activated = false;
blocked++;
- propagate_mouse_event(pos + cache.offset, 0, 0, b->is_doubleclick(), root, b->get_button_index(), b);
+ propagate_mouse_event(pos + cache.offset, 0, 0, b->is_double_click(), root, b->get_button_index(), b);
blocked--;
if (pressing_for_editor) {
@@ -2873,14 +3126,14 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
drag_accum = 0;
//last_drag_accum=0;
drag_from = v_scroll->get_value();
- drag_touching = !DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()));
+ 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() == MOUSE_BUTTON_LEFT) {
- if (get_item_at_position(b->get_position()) == nullptr && !b->get_shift() && !b->get_control() && !b->get_command()) {
+ if (get_item_at_position(b->get_position()) == nullptr && !b->is_shift_pressed() && !b->is_ctrl_pressed() && !b->is_command_pressed()) {
emit_signal("nothing_selected");
}
}
@@ -3013,6 +3266,10 @@ bool Tree::edit_selected() {
return false;
}
+bool Tree::is_editing() {
+ return popup_editor->is_visible();
+}
+
Size2 Tree::get_internal_min_size() const {
Size2i size = cache.bg->get_offset();
if (root) {
@@ -3174,7 +3431,6 @@ void Tree::_notification(int p_what) {
RID ci = get_canvas_item();
Ref<StyleBox> bg = cache.bg;
- Ref<StyleBox> bg_focus = get_theme_stylebox("bg_focus");
Color font_outline_color = get_theme_color("font_outline_color");
int outline_size = get_theme_constant("outline_size");
@@ -3183,11 +3439,6 @@ void Tree::_notification(int p_what) {
Size2 draw_size = get_size() - bg->get_minimum_size();
bg->draw(ci, Rect2(Point2(), get_size()));
- if (has_focus()) {
- RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
- bg_focus->draw(ci, Rect2(Point2(), get_size()));
- RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
- }
int tbh = _get_title_button_height();
@@ -3221,6 +3472,15 @@ void Tree::_notification(int p_what) {
columns[i].text_buf->draw(ci, text_pos, cache.title_button_color);
}
}
+
+ // Draw the background focus outline last, so that it is drawn in front of the section headings.
+ // Otherwise, section heading backgrounds can appear to be in front of the focus outline when scrolling.
+ if (has_focus()) {
+ RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
+ const Ref<StyleBox> bg_focus = get_theme_stylebox("bg_focus");
+ bg_focus->draw(ci, Rect2(Point2(), get_size()));
+ RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
+ }
}
if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED || p_what == NOTIFICATION_TRANSLATION_CHANGED) {
@@ -3262,38 +3522,15 @@ TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) {
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, nullptr);
- ti->cells.resize(columns.size());
-
- TreeItem *prev = nullptr;
- TreeItem *c = p_parent->children;
- int idx = 0;
-
- while (c) {
- if (idx++ == p_idx) {
- ti->next = c;
- break;
- }
- prev = c;
- c = c->next;
- }
-
- if (prev) {
- prev->next = ti;
- } else {
- p_parent->children = ti;
- }
- ti->parent = p_parent;
-
+ ERR_FAIL_COND_V_MSG(p_parent->tree != this, nullptr, "A different tree owns the given parent");
+ ti = p_parent->create_child(p_idx);
} else {
if (!root) {
// No root exists, make the given item the new root.
ti = memnew(TreeItem(this));
ERR_FAIL_COND_V(!ti, nullptr);
ti->cells.resize(columns.size());
-
+ ti->is_root = true;
root = ti;
} else {
// Root exists, append or insert to root.
@@ -3314,8 +3551,8 @@ TreeItem *Tree::get_last_item() {
while (last) {
if (last->next) {
last = last->next;
- } else if (last->children) {
- last = last->children;
+ } else if (last->first_child) {
+ last = last->first_child;
} else {
break;
}
@@ -3484,8 +3721,8 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) {
if (!p_item) {
p_item = root;
} else {
- if (p_item->children) {
- p_item = p_item->children;
+ if (p_item->first_child) {
+ p_item = p_item->first_child;
} else if (p_item->next) {
p_item = p_item->next;
@@ -3554,7 +3791,7 @@ int Tree::get_column_width(int p_column) const {
void Tree::propagate_set_columns(TreeItem *p_item) {
p_item->cells.resize(columns.size());
- TreeItem *c = p_item->get_children();
+ TreeItem *c = p_item->get_first_child();
while (c) {
propagate_set_columns(c);
c = c->next;
@@ -3604,8 +3841,8 @@ int Tree::get_item_offset(TreeItem *p_item) const {
ofs += cache.vseparation;
}
- if (it->children && !it->collapsed) {
- it = it->children;
+ if (it->first_child && !it->collapsed) {
+ it = it->first_child;
} else if (it->next) {
it = it->next;
@@ -3928,7 +4165,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
return nullptr; // do not try children, it's collapsed
}
- TreeItem *n = p_item->get_children();
+ TreeItem *n = p_item->get_first_child();
while (n) {
int ch;
TreeItem *r = _find_item_at_pos(n, pos, r_column, ch, section);
@@ -4248,7 +4485,7 @@ void Tree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_folding"), "set_hide_folding", "is_folding_hidden");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_root"), "set_hide_root", "is_root_hidden");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "drop_mode_flags", PROPERTY_HINT_FLAGS, "On Item,In between"), "set_drop_mode_flags", "get_drop_mode_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "drop_mode_flags", PROPERTY_HINT_FLAGS, "On Item,In Between"), "set_drop_mode_flags", "get_drop_mode_flags");
ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Row,Multi"), "set_select_mode", "get_select_mode");
ADD_SIGNAL(MethodInfo("item_selected"));
@@ -4262,7 +4499,7 @@ void Tree::_bind_methods() {
ADD_SIGNAL(MethodInfo("item_custom_button_pressed"));
ADD_SIGNAL(MethodInfo("item_double_clicked"));
ADD_SIGNAL(MethodInfo("item_collapsed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem")));
- //ADD_SIGNAL( MethodInfo("item_doubleclicked" ) );
+ //ADD_SIGNAL( MethodInfo("item_double_clicked" ) );
ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("custom_popup_edited", PropertyInfo(Variant::BOOL, "arrow_clicked")));
ADD_SIGNAL(MethodInfo("item_activated"));
@@ -4317,7 +4554,7 @@ 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("text_submitted", callable_mp(this, &Tree::_text_editor_submit));
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));
@@ -4327,6 +4564,8 @@ Tree::Tree() {
set_mouse_filter(MOUSE_FILTER_STOP);
set_clip_contents(true);
+
+ update_cache();
}
Tree::~Tree() {
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index d1407e24d4..0571a605a5 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -112,6 +112,8 @@ private:
Vector<Button> buttons;
+ Ref<Font> custom_font;
+
Cell() {
text_buf.instance();
}
@@ -122,14 +124,18 @@ private:
Vector<Cell> cells;
- bool collapsed; // won't show children
- bool disable_folding;
- int custom_min_height;
+ bool collapsed = false; // won't show children
+ bool disable_folding = false;
+ int custom_min_height = 0;
+
+ TreeItem *parent = nullptr; // parent item
+ TreeItem *prev = nullptr; // previous in list
+ TreeItem *next = nullptr; // next in list
+ TreeItem *first_child = nullptr;
- TreeItem *parent; // parent item
- TreeItem *next; // next in list
- TreeItem *children; //child items
- Tree *tree; //tree (for reference)
+ Vector<TreeItem *> children_cache;
+ bool is_root = false; // for tree root
+ Tree *tree; // tree (for reference)
TreeItem(Tree *p_tree);
@@ -138,9 +144,40 @@ private:
void _cell_selected(int p_cell);
void _cell_deselected(int p_cell);
+ void _change_tree(Tree *p_tree);
+
+ _FORCE_INLINE_ void _create_children_cache() {
+ if (children_cache.is_empty()) {
+ TreeItem *c = first_child;
+ while (c) {
+ children_cache.append(c);
+ c = c->next;
+ }
+ }
+ }
+
+ _FORCE_INLINE_ void _unlink_from_tree() {
+ TreeItem *p = get_prev();
+ if (p) {
+ p->next = next;
+ }
+ if (next) {
+ next->prev = p;
+ }
+ if (parent) {
+ if (!parent->children_cache.is_empty()) {
+ parent->children_cache.remove(get_index());
+ }
+ if (parent->first_child == this) {
+ parent->first_child = next;
+ }
+ }
+ }
+
protected:
static void _bind_methods();
- //bind helpers
+
+ // Bind helpers
Dictionary _get_range_config(int p_column) {
Dictionary d;
double min = 0.0, max = 0.0, step = 0.0;
@@ -156,6 +193,13 @@ protected:
remove_child(Object::cast_to<TreeItem>(p_child));
}
+ void _move_before(Object *p_item) {
+ move_before(Object::cast_to<TreeItem>(p_item));
+ }
+ void _move_after(Object *p_item) {
+ move_after(Object::cast_to<TreeItem>(p_item));
+ }
+
Variant _call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
public:
@@ -234,16 +278,6 @@ public:
void set_custom_minimum_height(int p_height);
int get_custom_minimum_height() const;
- TreeItem *get_prev();
- TreeItem *get_next();
- TreeItem *get_parent();
- TreeItem *get_children();
-
- TreeItem *get_prev_visible(bool p_wrap = false);
- TreeItem *get_next_visible(bool p_wrap = false);
-
- void remove_child(TreeItem *p_item);
-
void set_selectable(int p_column, bool p_selectable);
bool is_selectable(int p_column) const;
@@ -259,6 +293,9 @@ public:
Color get_custom_color(int p_column) const;
void clear_custom_color(int p_column);
+ void set_custom_font(int p_column, const Ref<Font> &p_font);
+ Ref<Font> get_custom_font(int p_column) const;
+
void set_custom_bg_color(int p_column, const Color &p_color, bool p_bg_outline = false);
void clear_custom_bg_color(int p_column);
Color get_custom_bg_color(int p_column) const;
@@ -269,22 +306,43 @@ public:
void set_tooltip(int p_column, const String &p_tooltip);
String get_tooltip(int p_column) const;
- void clear_children();
-
void set_text_align(int p_column, TextAlign p_align);
TextAlign get_text_align(int p_column) const;
void set_expand_right(int p_column, bool p_enable);
bool get_expand_right(int p_column) const;
- void move_to_top();
- void move_to_bottom();
-
void set_disable_folding(bool p_disable);
bool is_folding_disabled() const;
+ /* Item manipulation */
+
+ TreeItem *create_child(int p_idx = -1);
+
+ Tree *get_tree();
+
+ TreeItem *get_prev();
+ TreeItem *get_next();
+ TreeItem *get_parent();
+ TreeItem *get_first_child();
+
+ TreeItem *get_prev_visible(bool p_wrap = false);
+ TreeItem *get_next_visible(bool p_wrap = false);
+
+ TreeItem *get_child(int p_idx);
+ int get_child_count();
+ Array get_children();
+ int get_index();
+
+ void move_before(TreeItem *p_item);
+ void move_after(TreeItem *p_item);
+
+ void remove_child(TreeItem *p_item);
+
void call_recursive(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ void clear_children();
+
~TreeItem();
};
@@ -390,8 +448,8 @@ private:
void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color);
int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item);
void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = nullptr, bool *r_in_range = nullptr, bool p_force_deselect = false);
- int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_doubleclick, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod);
- void _text_editor_enter(String p_text);
+ int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_double_click, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod);
+ void _text_editor_submit(String p_text);
void _text_editor_modal_close();
void value_editor_changed(double p_value);
@@ -441,6 +499,8 @@ private:
Color guide_color;
Color drop_position_color;
Color relationship_line_color;
+ Color parent_hl_line_color;
+ Color children_hl_line_color;
Color custom_button_font_highlight;
int hseparation = 0;
@@ -449,6 +509,10 @@ private:
int button_margin = 0;
Point2 offset;
int draw_relationship_lines = 0;
+ int relationship_line_width = 0;
+ int parent_hl_line_width = 0;
+ int children_hl_line_width = 0;
+ int parent_hl_line_margin = 0;
int draw_guides = 0;
int scroll_border = 0;
int scroll_speed = 0;
@@ -521,6 +585,8 @@ private:
bool hide_folding = false;
int _count_selected_items(TreeItem *p_from) const;
+ bool _is_branch_selected(TreeItem *p_from) const;
+ bool _is_sibling_branch_selected(TreeItem *p_from) const;
void _go_left();
void _go_right();
void _go_down();
@@ -604,6 +670,7 @@ public:
int get_item_offset(TreeItem *p_item) const;
Rect2 get_item_rect(TreeItem *p_item, int p_column = -1) const;
bool edit_selected();
+ bool is_editing();
// 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 = nullptr, bool p_selectable = false);
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 55529517f1..181fe606c8 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -271,7 +271,7 @@ void CanvasItemMaterial::_bind_methods() {
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, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Subtract,Multiply,Premultiplied 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");
@@ -1210,7 +1210,7 @@ void CanvasItem::_bind_methods() {
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, "Inherit,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
ADD_GROUP("Material", "");
@@ -1414,7 +1414,7 @@ CanvasItem::~CanvasItem() {
///////////////////////////////////////////////////////////////////
void CanvasTexture::set_diffuse_texture(const Ref<Texture2D> &p_diffuse) {
- ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_diffuse.ptr()) != nullptr, "Cant self-assign a CanvasTexture");
+ ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_diffuse.ptr()) != nullptr, "Can't self-assign a CanvasTexture");
diffuse_texture = p_diffuse;
RID tex_rid = diffuse_texture.is_valid() ? diffuse_texture->get_rid() : RID();
@@ -1426,7 +1426,7 @@ Ref<Texture2D> CanvasTexture::get_diffuse_texture() const {
}
void CanvasTexture::set_normal_texture(const Ref<Texture2D> &p_normal) {
- ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_normal.ptr()) != nullptr, "Cant self-assign a CanvasTexture");
+ ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_normal.ptr()) != nullptr, "Can't self-assign a CanvasTexture");
normal_texture = p_normal;
RID tex_rid = normal_texture.is_valid() ? normal_texture->get_rid() : RID();
RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_NORMAL, tex_rid);
@@ -1436,7 +1436,7 @@ Ref<Texture2D> CanvasTexture::get_normal_texture() const {
}
void CanvasTexture::set_specular_texture(const Ref<Texture2D> &p_specular) {
- ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_specular.ptr()) != nullptr, "Cant self-assign a CanvasTexture");
+ ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_specular.ptr()) != nullptr, "Can't self-assign a CanvasTexture");
specular_texture = p_specular;
RID tex_rid = specular_texture.is_valid() ? specular_texture->get_rid() : RID();
RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_SPECULAR, tex_rid);
@@ -1554,7 +1554,7 @@ void CanvasTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "specular_shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_specular_shininess", "get_specular_shininess");
ADD_GROUP("Texture", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
}
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 64df37654b..927b114fbc 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -40,9 +40,7 @@ Error HTTPRequest::_request() {
}
Error HTTPRequest::_parse_url(const String &p_url) {
- url = p_url;
use_ssl = false;
-
request_string = "";
port = 80;
request_sent = false;
@@ -52,35 +50,20 @@ Error HTTPRequest::_parse_url(const String &p_url) {
downloaded.set(0);
redirections = 0;
- String url_lower = url.to_lower();
- if (url_lower.begins_with("http://")) {
- url = url.substr(7, url.length() - 7);
- } else if (url_lower.begins_with("https://")) {
- url = url.substr(8, url.length() - 8);
+ String scheme;
+ Error err = p_url.parse_url(scheme, url, port, request_string);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing URL: " + p_url + ".");
+ if (scheme == "https://") {
use_ssl = true;
- port = 443;
- } else {
- ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Malformed URL: " + url + ".");
+ } else if (scheme != "http://") {
+ ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Invalid URL scheme: " + scheme + ".");
}
-
- ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short: " + url + ".");
-
- int slash_pos = url.find("/");
-
- if (slash_pos != -1) {
- request_string = url.substr(slash_pos, url.length());
- url = url.substr(0, slash_pos);
- } else {
- request_string = "/";
+ if (port == 0) {
+ port = use_ssl ? 443 : 80;
}
-
- int colon_pos = url.find(":");
- if (colon_pos != -1) {
- port = url.substr(colon_pos + 1, url.length()).to_int();
- url = url.substr(0, colon_pos);
- ERR_FAIL_COND_V(port < 1 || port > 65535, ERR_INVALID_PARAMETER);
+ if (request_string.is_empty()) {
+ request_string = "/";
}
-
return OK;
}
@@ -123,7 +106,7 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
size_t len = charstr.length();
raw_data.resize(len);
uint8_t *w = raw_data.ptrw();
- copymem(w, charstr.ptr(), len);
+ memcpy(w, charstr.ptr(), len);
return request_raw(p_url, p_custom_headers, p_ssl_validate_domain, p_method, raw_data);
}
@@ -392,17 +375,19 @@ bool HTTPRequest::_update_connection() {
}
PackedByteArray chunk = client->read_response_body_chunk();
- downloaded.add(chunk.size());
- if (file) {
- const uint8_t *r = chunk.ptr();
- file->store_buffer(r, chunk.size());
- if (file->get_error() != OK) {
- call_deferred("_request_done", RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray());
- return true;
+ if (chunk.size()) {
+ downloaded.add(chunk.size());
+ if (file) {
+ const uint8_t *r = chunk.ptr();
+ file->store_buffer(r, chunk.size());
+ if (file->get_error() != OK) {
+ call_deferred("_request_done", RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray());
+ return true;
+ }
+ } else {
+ body.append_array(chunk);
}
- } else {
- body.append_array(chunk);
}
if (body_size_limit >= 0 && downloaded.get() > body_size_limit) {
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index 92b0ff28e9..22e822253f 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -31,8 +31,8 @@
#ifndef HTTPREQUEST_H
#define HTTPREQUEST_H
+#include "core/io/file_access.h"
#include "core/io/http_client.h"
-#include "core/os/file_access.h"
#include "core/os/thread.h"
#include "core/templates/safe_refcount.h"
#include "node.h"
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index b7313749d6..622c271935 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -292,7 +292,7 @@ void Node::_propagate_exit_tree() {
void Node::move_child(Node *p_child, int p_pos) {
ERR_FAIL_NULL(p_child);
- ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1, "Invalid new child position: " + itos(p_pos) + ".");
+ ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1, vformat("Invalid new child position: %d.", p_pos));
ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node.");
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup).");
@@ -491,36 +491,24 @@ bool Node::is_network_master() const {
/***** RPC CONFIG ********/
-uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode) {
- uint16_t mid = get_node_rpc_method_id(p_method);
- if (mid == UINT16_MAX) {
- // It's new
- NetData nd;
- nd.name = p_method;
- nd.mode = p_mode;
- data.rpc_methods.push_back(nd);
- return ((uint16_t)data.rpc_methods.size() - 1) | (1 << 15);
- } else {
- int c_mid = (~(1 << 15)) & mid;
- data.rpc_methods.write[c_mid].mode = p_mode;
- return mid;
- }
-}
-
-uint16_t Node::rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode) {
- uint16_t pid = get_node_rset_property_id(p_property);
- if (pid == UINT16_MAX) {
- // It's new
- NetData nd;
- nd.name = p_property;
- nd.mode = p_mode;
- data.rpc_properties.push_back(nd);
- return ((uint16_t)data.rpc_properties.size() - 1) | (1 << 15);
- } else {
- int c_pid = (~(1 << 15)) & pid;
- data.rpc_properties.write[c_pid].mode = p_mode;
- return pid;
+uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, NetworkedMultiplayerPeer::TransferMode p_transfer_mode, int p_channel) {
+ for (int i = 0; i < data.rpc_methods.size(); i++) {
+ if (data.rpc_methods[i].name == p_method) {
+ MultiplayerAPI::RPCConfig &nd = data.rpc_methods.write[i];
+ nd.rpc_mode = p_rpc_mode;
+ nd.transfer_mode = p_transfer_mode;
+ nd.channel = p_channel;
+ return i | (1 << 15);
+ }
}
+ // New method
+ MultiplayerAPI::RPCConfig nd;
+ nd.name = p_method;
+ nd.rpc_mode = p_rpc_mode;
+ nd.transfer_mode = p_transfer_mode;
+ nd.channel = p_channel;
+ data.rpc_methods.push_back(nd);
+ return ((uint16_t)data.rpc_methods.size() - 1) | (1 << 15);
}
/***** RPC FUNCTIONS ********/
@@ -536,7 +524,7 @@ void Node::rpc(const StringName &p_method, VARIANT_ARG_DECLARE) {
argc++;
}
- rpcp(0, false, p_method, argptr, argc);
+ rpcp(0, p_method, argptr, argc);
}
void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
@@ -550,35 +538,7 @@ void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE
argc++;
}
- rpcp(p_peer_id, false, p_method, argptr, argc);
-}
-
-void Node::rpc_unreliable(const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- rpcp(0, true, p_method, argptr, argc);
-}
-
-void Node::rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) {
- VARIANT_ARGPTRS;
-
- int argc = 0;
- for (int i = 0; i < VARIANT_ARG_MAX; i++) {
- if (argptr[i]->get_type() == Variant::NIL) {
- break;
- }
- argc++;
- }
-
- rpcp(p_peer_id, true, p_method, argptr, argc);
+ rpcp(p_peer_id, p_method, argptr, argc);
}
Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
@@ -591,13 +551,13 @@ Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallEr
if (p_args[0]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
- r_error.expected = Variant::STRING;
+ r_error.expected = Variant::STRING_NAME;
return Variant();
}
StringName method = *p_args[0];
- rpcp(0, false, method, &p_args[1], p_argcount - 1);
+ rpcp(0, method, &p_args[1], p_argcount - 1);
r_error.error = Callable::CallError::CALL_OK;
return Variant();
@@ -620,99 +580,24 @@ Variant Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::Cal
if (p_args[1]->get_type() != Variant::STRING_NAME) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 1;
- r_error.expected = Variant::STRING;
+ r_error.expected = Variant::STRING_NAME;
return Variant();
}
int peer_id = *p_args[0];
StringName method = *p_args[1];
- rpcp(peer_id, false, method, &p_args[2], p_argcount - 2);
+ rpcp(peer_id, method, &p_args[2], p_argcount - 2);
r_error.error = Callable::CallError::CALL_OK;
return Variant();
}
-Variant Node::_rpc_unreliable_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- return Variant();
- }
-
- if (p_args[0]->get_type() != Variant::STRING_NAME) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- return Variant();
- }
-
- StringName method = *p_args[0];
-
- rpcp(0, true, method, &p_args[1], p_argcount - 1);
-
- r_error.error = Callable::CallError::CALL_OK;
- return Variant();
-}
-
-Variant Node::_rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 2;
- return Variant();
- }
-
- if (p_args[0]->get_type() != Variant::INT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::INT;
- return Variant();
- }
-
- if (p_args[1]->get_type() != Variant::STRING_NAME) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING;
- return Variant();
- }
-
- int peer_id = *p_args[0];
- StringName method = *p_args[1];
-
- rpcp(peer_id, true, method, &p_args[2], p_argcount - 2);
-
- r_error.error = Callable::CallError::CALL_OK;
- return Variant();
-}
-
-void Node::rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) {
- ERR_FAIL_COND(!is_inside_tree());
- get_multiplayer()->rpcp(this, p_peer_id, p_unreliable, p_method, p_arg, p_argcount);
-}
-
-void Node::rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) {
+void Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) {
ERR_FAIL_COND(!is_inside_tree());
- get_multiplayer()->rsetp(this, p_peer_id, p_unreliable, p_property, p_value);
-}
-
-/******** RSET *********/
-void Node::rset(const StringName &p_property, const Variant &p_value) {
- rsetp(0, false, p_property, p_value);
+ get_multiplayer()->rpcp(this, p_peer_id, true, p_method, p_arg, p_argcount);
}
-void Node::rset_id(int p_peer_id, const StringName &p_property, const Variant &p_value) {
- rsetp(p_peer_id, false, p_property, p_value);
-}
-
-void Node::rset_unreliable(const StringName &p_property, const Variant &p_value) {
- rsetp(0, true, p_property, p_value);
-}
-
-void Node::rset_unreliable_id(int p_peer_id, const StringName &p_property, const Variant &p_value) {
- rsetp(p_peer_id, true, p_property, p_value);
-}
-
-//////////// end of rpc
Ref<MultiplayerAPI> Node::get_multiplayer() const {
if (multiplayer.is_valid()) {
return multiplayer;
@@ -731,99 +616,11 @@ void Node::set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
multiplayer = p_multiplayer;
}
-uint16_t Node::get_node_rpc_method_id(const StringName &p_method) const {
- for (int i = 0; i < data.rpc_methods.size(); i++) {
- if (data.rpc_methods[i].name == p_method) {
- // Returns `i` with the high bit set to 1 so we know that this id comes
- // from the node and not the script.
- return i | (1 << 15);
- }
- }
- return UINT16_MAX;
-}
-
-StringName Node::get_node_rpc_method(const uint16_t p_rpc_method_id) const {
- // Make sure this is a node generated ID.
- if (((1 << 15) & p_rpc_method_id) > 0) {
- int mid = (~(1 << 15)) & p_rpc_method_id;
- if (mid < data.rpc_methods.size()) {
- return data.rpc_methods[mid].name;
- }
- }
- return StringName();
-}
-
-MultiplayerAPI::RPCMode Node::get_node_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
- // Make sure this is a node generated ID.
- if (((1 << 15) & p_rpc_method_id) > 0) {
- int mid = (~(1 << 15)) & p_rpc_method_id;
- if (mid < data.rpc_methods.size()) {
- return data.rpc_methods[mid].mode;
- }
- }
- return MultiplayerAPI::RPC_MODE_DISABLED;
+Vector<MultiplayerAPI::RPCConfig> Node::get_node_rpc_methods() const {
+ return data.rpc_methods;
}
-MultiplayerAPI::RPCMode Node::get_node_rpc_mode(const StringName &p_method) const {
- return get_node_rpc_mode_by_id(get_node_rpc_method_id(p_method));
-}
-
-uint16_t Node::get_node_rset_property_id(const StringName &p_property) const {
- for (int i = 0; i < data.rpc_properties.size(); i++) {
- if (data.rpc_properties[i].name == p_property) {
- // Returns `i` with the high bit set to 1 so we know that this id comes
- // from the node and not the script.
- return i | (1 << 15);
- }
- }
- return UINT16_MAX;
-}
-
-StringName Node::get_node_rset_property(const uint16_t p_rset_property_id) const {
- // Make sure this is a node generated ID.
- if (((1 << 15) & p_rset_property_id) > 0) {
- int mid = (~(1 << 15)) & p_rset_property_id;
- if (mid < data.rpc_properties.size()) {
- return data.rpc_properties[mid].name;
- }
- }
- return StringName();
-}
-
-MultiplayerAPI::RPCMode Node::get_node_rset_mode_by_id(const uint16_t p_rset_property_id) const {
- if (((1 << 15) & p_rset_property_id) > 0) {
- int mid = (~(1 << 15)) & p_rset_property_id;
- if (mid < data.rpc_properties.size()) {
- return data.rpc_properties[mid].mode;
- }
- }
- return MultiplayerAPI::RPC_MODE_DISABLED;
-}
-
-MultiplayerAPI::RPCMode Node::get_node_rset_mode(const StringName &p_property) const {
- return get_node_rset_mode_by_id(get_node_rset_property_id(p_property));
-}
-
-String Node::get_rpc_md5() const {
- String rpc_list;
- for (int i = 0; i < data.rpc_methods.size(); i += 1) {
- rpc_list += String(data.rpc_methods[i].name);
- }
- for (int i = 0; i < data.rpc_properties.size(); i += 1) {
- rpc_list += String(data.rpc_properties[i].name);
- }
- if (get_script_instance()) {
- Vector<ScriptNetData> rpc = get_script_instance()->get_rpc_methods();
- for (int i = 0; i < rpc.size(); i += 1) {
- rpc_list += String(rpc[i].name);
- }
- rpc = get_script_instance()->get_rset_properties();
- for (int i = 0; i < rpc.size(); i += 1) {
- rpc_list += String(rpc[i].name);
- }
- }
- return rpc_list.md5_text();
-}
+//////////// end of rpc
bool Node::can_process_notification(int p_what) const {
switch (p_what) {
@@ -1240,8 +1037,11 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
void Node::add_child(Node *p_child, bool p_legible_unique_name) {
ERR_FAIL_NULL(p_child);
- ERR_FAIL_COND_MSG(p_child == this, "Can't add child '" + p_child->get_name() + "' to itself."); // adding to itself!
- ERR_FAIL_COND_MSG(p_child->data.parent, "Can't add child '" + p_child->get_name() + "' to '" + get_name() + "', already has a parent '" + p_child->data.parent->get_name() + "'."); //Fail if node has a parent
+ ERR_FAIL_COND_MSG(p_child == this, vformat("Can't add child '%s' to itself.", p_child->get_name())); // adding to itself!
+ ERR_FAIL_COND_MSG(p_child->data.parent, vformat("Can't add child '%s' to '%s', already has a parent '%s'.", p_child->get_name(), get_name(), p_child->data.parent->get_name())); //Fail if node has a parent
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(p_child->is_a_parent_of(this), vformat("Can't add child '%s' to '%s' as it would result in a cyclic dependency since '%s' is already a parent of '%s'.", p_child->get_name(), get_name(), p_child->get_name(), get_name()));
+#endif
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_node() failed. Consider using call_deferred(\"add_child\", child) instead.");
/* Validate name */
@@ -1252,7 +1052,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name) {
void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) {
ERR_FAIL_NULL(p_sibling);
- ERR_FAIL_COND_MSG(p_sibling == this, "Can't add sibling '" + p_sibling->get_name() + "' to itself."); // adding to itself!
+ ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself!
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_sibling() failed. Consider using call_deferred(\"add_sibling\", sibling) instead.");
get_parent()->add_child(p_sibling, p_legible_unique_name);
@@ -1307,7 +1107,7 @@ void Node::remove_child(Node *p_child) {
}
}
- ERR_FAIL_COND_MSG(idx == -1, "Cannot remove child node " + p_child->get_name() + " as it is not a child of this node.");
+ ERR_FAIL_COND_MSG(idx == -1, vformat("Cannot remove child node '%s' as it is not a child of this node.", p_child->get_name()));
//ERR_FAIL_COND( p_child->data.blocked > 0 );
//if (data.scene) { does not matter
@@ -2391,7 +2191,7 @@ void Node::_replace_connections_target(Node *p_new_target) {
if (c.flags & CONNECT_PERSIST) {
c.signal.get_object()->disconnect(c.signal.get_name(), Callable(this, c.callable.get_method()));
bool valid = p_new_target->has_method(c.callable.get_method()) || Ref<Script>(p_new_target->get_script()).is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.callable.get_method());
- ERR_CONTINUE_MSG(!valid, "Attempt to connect signal '" + c.signal.get_object()->get_class() + "." + c.signal.get_name() + "' to nonexistent method '" + c.callable.get_object()->get_class() + "." + c.callable.get_method() + "'.");
+ ERR_CONTINUE_MSG(!valid, vformat("Attempt to connect signal '%s.%s' to nonexistent method '%s.%s'.", c.signal.get_object()->get_class(), c.signal.get_name(), c.callable.get_object()->get_class(), c.callable.get_method()));
c.signal.get_object()->connect(c.signal.get_name(), Callable(p_new_target, c.callable.get_method()), c.binds, c.flags);
}
}
@@ -2776,8 +2576,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_multiplayer"), &Node::get_multiplayer);
ClassDB::bind_method(D_METHOD("get_custom_multiplayer"), &Node::get_custom_multiplayer);
ClassDB::bind_method(D_METHOD("set_custom_multiplayer", "api"), &Node::set_custom_multiplayer);
- ClassDB::bind_method(D_METHOD("rpc_config", "method", "mode"), &Node::rpc_config);
- ClassDB::bind_method(D_METHOD("rset_config", "property", "mode"), &Node::rset_config);
+ ClassDB::bind_method(D_METHOD("rpc_config", "method", "rpc_mode", "transfer_mode", "channel"), &Node::rpc_config, DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE), DEFVAL(0));
ClassDB::bind_method(D_METHOD("set_editor_description", "editor_description"), &Node::set_editor_description);
ClassDB::bind_method(D_METHOD("get_editor_description"), &Node::get_editor_description);
@@ -2794,22 +2593,13 @@ void Node::_bind_methods() {
mi.name = "rpc";
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc", &Node::_rpc_bind, mi);
- mi.name = "rpc_unreliable";
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_unreliable", &Node::_rpc_unreliable_bind, mi);
mi.arguments.push_front(PropertyInfo(Variant::INT, "peer_id"));
mi.name = "rpc_id";
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_id", &Node::_rpc_id_bind, mi);
- mi.name = "rpc_unreliable_id";
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_unreliable_id", &Node::_rpc_unreliable_id_bind, mi);
}
- ClassDB::bind_method(D_METHOD("rset", "property", "value"), &Node::rset);
- ClassDB::bind_method(D_METHOD("rset_id", "peer_id", "property", "value"), &Node::rset_id);
- ClassDB::bind_method(D_METHOD("rset_unreliable", "property", "value"), &Node::rset_unreliable);
- ClassDB::bind_method(D_METHOD("rset_unreliable_id", "peer_id", "property", "value"), &Node::rset_unreliable_id);
-
ClassDB::bind_method(D_METHOD("update_configuration_warnings"), &Node::update_configuration_warnings);
BIND_CONSTANT(NOTIFICATION_ENTER_TREE);
@@ -2830,6 +2620,9 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE);
+ BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE);
+ BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE);
+
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER);
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT);
BIND_CONSTANT(NOTIFICATION_WM_WINDOW_FOCUS_IN);
@@ -2872,7 +2665,7 @@ void Node::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer", "get_custom_multiplayer");
ADD_GROUP("Process", "process_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Inherit,Pausable,WhenPaused,Always,Disabled"), "set_process_mode", "get_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Inherit,Pausable,When Paused,Always,Disabled"), "set_process_mode", "get_process_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_priority"), "set_process_priority", "get_process_priority");
ADD_GROUP("Editor Description", "editor_");
diff --git a/scene/main/node.h b/scene/main/node.h
index 6ca2317d9e..e7b36f351b 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -80,11 +80,6 @@ private:
SceneTree::Group *group = nullptr;
};
- struct NetData {
- StringName name;
- MultiplayerAPI::RPCMode mode = MultiplayerAPI::RPCMode::RPC_MODE_DISABLED;
- };
-
struct Data {
String filename;
Ref<SceneState> instance_state;
@@ -116,8 +111,7 @@ private:
Node *process_owner = nullptr;
int network_master = 1; // Server by default.
- Vector<NetData> rpc_methods;
- Vector<NetData> rpc_properties;
+ Vector<MultiplayerAPI::RPCConfig> rpc_methods;
// Variables used to properly sort the node when processing, ignored otherwise.
// TODO: Should move all the stuff below to bits.
@@ -179,9 +173,7 @@ private:
Array _get_groups() const;
Variant _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant _rpc_unreliable_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Variant _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant _rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
friend class SceneTree;
@@ -253,6 +245,10 @@ public:
NOTIFICATION_APPLICATION_FOCUS_IN = MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN,
NOTIFICATION_APPLICATION_FOCUS_OUT = MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT,
NOTIFICATION_TEXT_SERVER_CHANGED = MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED,
+
+ // Editor specific node notifications
+ NOTIFICATION_EDITOR_PRE_SAVE = 9001,
+ NOTIFICATION_EDITOR_POST_SAVE = 9002,
};
/* NODE/TREE */
@@ -425,42 +421,17 @@ public:
int get_network_master() const;
bool is_network_master() const;
- uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode); // config a local method for RPC
- uint16_t rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode); // config a local property for RPC
+ uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, NetworkedMultiplayerPeer::TransferMode p_transfer_mode, int p_channel = 0); // config a local method for RPC
+ Vector<MultiplayerAPI::RPCConfig> get_node_rpc_methods() const;
- void rpc(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
- void rpc_unreliable(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
- void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
- void rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
-
- void rset(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
- void rset_unreliable(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
- void rset_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
- void rset_unreliable_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
-
- void rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount);
- void rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value);
+ void rpc(const StringName &p_method, VARIANT_ARG_LIST); // RPC, honors RPCMode, TransferMode, channel
+ void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); // RPC to specific peer(s), honors RPCMode, TransferMode, channel
+ void rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount);
Ref<MultiplayerAPI> get_multiplayer() const;
Ref<MultiplayerAPI> get_custom_multiplayer() const;
void set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
- /// Returns the rpc method ID, otherwise UINT32_MAX
- uint16_t get_node_rpc_method_id(const StringName &p_method) const;
- StringName get_node_rpc_method(const uint16_t p_rpc_method_id) const;
- MultiplayerAPI::RPCMode get_node_rpc_mode_by_id(const uint16_t p_rpc_method_id) const;
- MultiplayerAPI::RPCMode get_node_rpc_mode(const StringName &p_method) const;
-
- /// Returns the rpc property ID, otherwise UINT32_MAX
- uint16_t get_node_rset_property_id(const StringName &p_property) const;
- StringName get_node_rset_property(const uint16_t p_rset_property_id) const;
- MultiplayerAPI::RPCMode get_node_rset_mode_by_id(const uint16_t p_rpc_method_id) const;
- MultiplayerAPI::RPCMode get_node_rset_mode(const StringName &p_property) const;
-
- /// Can be used to check if the rpc methods and the rset properties are the
- /// same across the peers.
- String get_rpc_md5() const;
-
Node();
~Node();
};
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 66f3a2ebde..f588e000f9 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -33,10 +33,10 @@
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
#include "core/input/input.h"
+#include "core/io/dir_access.h"
#include "core/io/marshalls.h"
#include "core/io/resource_loader.h"
#include "core/object/message_queue.h"
-#include "core/os/dir_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -413,7 +413,6 @@ bool SceneTree::physics_process(float p_time) {
_flush_ugc();
MessageQueue::get_singleton()->flush(); //small little hack
flush_transform_notifications();
- call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds");
root_lock--;
_flush_delete_queue();
@@ -445,7 +444,6 @@ bool SceneTree::process(float p_time) {
_flush_ugc();
MessageQueue::get_singleton()->flush(); //small little hack
flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications
- call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds");
root_lock--;
@@ -1267,7 +1265,7 @@ void SceneTree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multiplayer_poll"), "set_multiplayer_poll_enabled", "is_multiplayer_poll_enabled");
ADD_SIGNAL(MethodInfo("tree_changed"));
- ADD_SIGNAL(MethodInfo("tree_process_mode_changed")); //editor only signal, but due to API hash it cant be removed in run-time
+ ADD_SIGNAL(MethodInfo("tree_process_mode_changed")); //editor only signal, but due to API hash it can't be removed in run-time
ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
@@ -1349,6 +1347,8 @@ SceneTree::SceneTree() {
GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
+ Math::randomize();
+
// Create with mainloop.
root = memnew(Window);
@@ -1376,6 +1376,9 @@ SceneTree::SceneTree() {
const bool use_debanding = GLOBAL_DEF("rendering/anti_aliasing/quality/use_debanding", false);
root->set_use_debanding(use_debanding);
+ const bool use_occlusion_culling = GLOBAL_DEF("rendering/occlusion_culling/use_occlusion_culling", false);
+ root->set_use_occlusion_culling(use_occlusion_culling);
+
float lod_threshold = GLOBAL_DEF("rendering/mesh_lod/lod_change/threshold_pixels", 1.0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/mesh_lod/lod_change/threshold_pixels", PropertyInfo(Variant::FLOAT, "rendering/mesh_lod/lod_change/threshold_pixels", PROPERTY_HINT_RANGE, "0,1024,0.1"));
root->set_lod_threshold(lod_threshold);
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index a2f2adb8f8..78c4c14e97 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -48,8 +48,8 @@ class Material;
class Mesh;
class SceneDebugger;
-class SceneTreeTimer : public Reference {
- GDCLASS(SceneTreeTimer, Reference);
+class SceneTreeTimer : public RefCounted {
+ GDCLASS(SceneTreeTimer, RefCounted);
float time_left = 0.0;
bool process_always = true;
diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp
index cb3b2cb392..3d65c12cb7 100644
--- a/scene/main/shader_globals_override.cpp
+++ b/scene/main/shader_globals_override.cpp
@@ -169,7 +169,7 @@ void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const
pinfo.type = Variant::TRANSFORM2D;
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
- pinfo.type = Variant::TRANSFORM;
+ pinfo.type = Variant::TRANSFORM3D;
} break;
case RS::GLOBAL_VAR_TYPE_MAT4: {
pinfo.type = Variant::PACKED_INT32_ARRAY;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 4c9ebe016e..59ec0e6345 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -183,22 +183,9 @@ public:
/////////////////////////////////////
-void Viewport::update_worlds() {
- if (!is_inside_tree()) {
- return;
- }
-
- Rect2 abstracted_rect = Rect2(Vector2(), get_visible_rect().size);
- Rect2 xformed_rect = (global_canvas_transform * canvas_transform).affine_inverse().xform(abstracted_rect);
- find_world_2d()->_update_viewport(this, xformed_rect);
- find_world_2d()->_update();
-
- find_world_3d()->_update(get_tree()->get_frame());
-}
-
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();
+ Transform3D object_transform = p_object->get_global_transform();
+ Transform3D camera_transform = p_camera->get_global_transform();
ObjectID id = p_object->get_instance_id();
//avoid sending the fake event unnecessarily if nothing really changed in the context
@@ -441,8 +428,6 @@ void Viewport::_notification(int p_what) {
_update_listener();
_update_listener_2d();
- find_world_2d()->_register_viewport(this, Rect2());
-
add_to_group("_viewports");
if (get_tree()->is_debugging_collisions_hint()) {
//2D
@@ -499,9 +484,6 @@ void Viewport::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
_gui_cancel_tooltip();
- if (world_2d.is_valid()) {
- world_2d->_remove_viewport(this);
- }
RenderingServer::get_singleton()->viewport_set_scenario(viewport, RID());
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
@@ -553,7 +535,7 @@ void Viewport::_notification(int p_what) {
RS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
for (int i = 0; i < point_count; i++) {
- Transform point_transform;
+ Transform3D point_transform;
point_transform.origin = points[i];
RS::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh, i, point_transform);
}
@@ -617,10 +599,10 @@ void Viewport::_process_picking() {
mm->set_device(InputEvent::DEVICE_ID_INTERNAL);
mm->set_global_position(physics_last_mousepos);
mm->set_position(physics_last_mousepos);
- mm->set_alt(physics_last_mouse_state.alt);
- mm->set_shift(physics_last_mouse_state.shift);
- mm->set_control(physics_last_mouse_state.control);
- mm->set_metakey(physics_last_mouse_state.meta);
+ mm->set_alt_pressed(physics_last_mouse_state.alt);
+ mm->set_shift_pressed(physics_last_mouse_state.shift);
+ mm->set_ctrl_pressed(physics_last_mouse_state.control);
+ mm->set_meta_pressed(physics_last_mouse_state.meta);
mm->set_button_mask(physics_last_mouse_state.mouse_mask);
physics_picking_events.push_back(mm);
}
@@ -641,10 +623,10 @@ void Viewport::_process_picking() {
physics_has_last_mousepos = true;
physics_last_mousepos = pos;
- physics_last_mouse_state.alt = mm->get_alt();
- physics_last_mouse_state.shift = mm->get_shift();
- physics_last_mouse_state.control = mm->get_control();
- physics_last_mouse_state.meta = mm->get_metakey();
+ physics_last_mouse_state.alt = mm->is_alt_pressed();
+ physics_last_mouse_state.shift = mm->is_shift_pressed();
+ physics_last_mouse_state.control = mm->is_ctrl_pressed();
+ physics_last_mouse_state.meta = mm->is_meta_pressed();
physics_last_mouse_state.mouse_mask = mm->get_button_mask();
}
@@ -656,10 +638,10 @@ void Viewport::_process_picking() {
physics_has_last_mousepos = true;
physics_last_mousepos = pos;
- physics_last_mouse_state.alt = mb->get_alt();
- physics_last_mouse_state.shift = mb->get_shift();
- physics_last_mouse_state.control = mb->get_control();
- physics_last_mouse_state.meta = mb->get_metakey();
+ physics_last_mouse_state.alt = mb->is_alt_pressed();
+ physics_last_mouse_state.shift = mb->is_shift_pressed();
+ physics_last_mouse_state.control = mb->is_ctrl_pressed();
+ physics_last_mouse_state.meta = mb->is_meta_pressed();
if (mb->is_pressed()) {
physics_last_mouse_state.mouse_mask |= (1 << (mb->get_button_index() - 1));
@@ -676,10 +658,10 @@ void Viewport::_process_picking() {
Ref<InputEventKey> k = ev;
if (k.is_valid()) {
//only for mask
- physics_last_mouse_state.alt = k->get_alt();
- physics_last_mouse_state.shift = k->get_shift();
- physics_last_mouse_state.control = k->get_control();
- physics_last_mouse_state.meta = k->get_metakey();
+ physics_last_mouse_state.alt = k->is_alt_pressed();
+ physics_last_mouse_state.shift = k->is_shift_pressed();
+ physics_last_mouse_state.control = k->is_ctrl_pressed();
+ physics_last_mouse_state.meta = k->is_meta_pressed();
continue;
}
@@ -1156,7 +1138,6 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
}
if (is_inside_tree()) {
- find_world_2d()->_remove_viewport(this);
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
}
@@ -1172,7 +1153,6 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
if (is_inside_tree()) {
current_canvas = find_world_2d()->get_canvas();
RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
- find_world_2d()->_register_viewport(this, Rect2());
}
}
@@ -1341,19 +1321,19 @@ bool Viewport::is_camera_override_enabled() const {
return camera_override;
}
-void Viewport::set_camera_override_transform(const Transform &p_transform) {
+void Viewport::set_camera_override_transform(const Transform3D &p_transform) {
if (camera_override) {
camera_override.transform = p_transform;
RenderingServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform);
}
}
-Transform Viewport::get_camera_override_transform() const {
+Transform3D Viewport::get_camera_override_transform() const {
if (camera_override) {
return camera_override.transform;
}
- return Transform();
+ return Transform3D();
}
void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
@@ -1412,6 +1392,16 @@ void Viewport::_update_canvas_items(Node *p_node) {
}
}
+void Viewport::set_use_xr(bool p_use_xr) {
+ use_xr = p_use_xr;
+
+ RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+}
+
+bool Viewport::is_using_xr() {
+ return use_xr;
+}
+
Ref<ViewportTexture> Viewport::get_texture() const {
return default_texture;
}
@@ -1830,6 +1820,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = nullptr;
Point2 mpos = mb->get_position();
+ gui.last_mouse_pos = mpos;
if (mb->is_pressed()) {
Size2 pos = mpos;
if (gui.mouse_focus_mask) {
@@ -2391,10 +2382,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
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()) {
+ //if (from && p_event->is_pressed() && !p_event->is_alt_pressed() && !p_event->is_meta_pressed() && !p_event->key->is_command_pressed()) {
Ref<InputEventKey> k = p_event;
//need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/right/etc> is handled here when it shouldn't be.
- bool mods = k.is_valid() && (k->get_control() || k->get_alt() || k->get_shift() || k->get_metakey());
+ bool mods = k.is_valid() && (k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_shift_pressed() || k->is_meta_pressed());
if (from && p_event->is_pressed()) {
Control *next = nullptr;
@@ -2536,6 +2527,8 @@ void Viewport::_gui_remove_control(Control *p_control) {
}
Window *Viewport::get_base_window() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
+
Viewport *v = const_cast<Viewport *>(this);
Window *w = Object::cast_to<Window>(v);
while (!w) {
@@ -3242,6 +3235,21 @@ float Viewport::get_lod_threshold() const {
return lod_threshold;
}
+void Viewport::set_use_occlusion_culling(bool p_use_occlusion_culling) {
+ if (use_occlusion_culling == p_use_occlusion_culling) {
+ return;
+ }
+
+ use_occlusion_culling = p_use_occlusion_culling;
+ RS::get_singleton()->viewport_set_use_occlusion_culling(viewport, p_use_occlusion_culling);
+
+ notify_property_list_changed();
+}
+
+bool Viewport::is_using_occlusion_culling() const {
+ return use_occlusion_culling;
+}
+
void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
debug_draw = p_debug_draw;
RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw));
@@ -3310,6 +3318,7 @@ bool Viewport::is_input_handled() const {
return local_input_handled;
} else {
const Viewport *vp = this;
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
while (true) {
if (Object::cast_to<Window>(vp)) {
break;
@@ -3331,9 +3340,6 @@ bool Viewport::is_handling_input_locally() const {
return handle_input_locally;
}
-void Viewport::_validate_property(PropertyInfo &property) const {
-}
-
void Viewport::set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter) {
ERR_FAIL_INDEX(p_filter, DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX);
@@ -3478,11 +3484,17 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_debanding", "enable"), &Viewport::set_use_debanding);
ClassDB::bind_method(D_METHOD("is_using_debanding"), &Viewport::is_using_debanding);
+ ClassDB::bind_method(D_METHOD("set_use_occlusion_culling", "enable"), &Viewport::set_use_occlusion_culling);
+ ClassDB::bind_method(D_METHOD("is_using_occlusion_culling"), &Viewport::is_using_occlusion_culling);
+
ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw);
ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw);
ClassDB::bind_method(D_METHOD("get_render_info", "info"), &Viewport::get_render_info);
+ ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &Viewport::set_use_xr);
+ ClassDB::bind_method(D_METHOD("is_using_xr"), &Viewport::is_using_xr);
+
ClassDB::bind_method(D_METHOD("get_texture"), &Viewport::get_texture);
ClassDB::bind_method(D_METHOD("set_physics_object_picking", "enable"), &Viewport::set_physics_object_picking);
@@ -3493,8 +3505,6 @@ void Viewport::_bind_methods() {
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);
-
ClassDB::bind_method(D_METHOD("set_use_own_world_3d", "enable"), &Viewport::set_use_own_world_3d);
ClassDB::bind_method(D_METHOD("is_using_own_world_3d"), &Viewport::is_using_own_world_3d);
@@ -3563,6 +3573,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("_process_picking"), &Viewport::_process_picking);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
@@ -3571,13 +3582,14 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled");
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::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Fast),4x (Average),8x (Slow),16x (Slower)"), "set_msaa", "get_msaa");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_lod_threshold", "get_lod_threshold");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
ADD_GROUP("Canvas Items", "canvas_item_");
- 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_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), "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");
ADD_GROUP("Audio Listener", "audio_listener_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_2d"), "set_as_audio_listener_2d", "is_audio_listener_2d");
@@ -3638,9 +3650,9 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEBUG_DRAW_OVERDRAW);
BIND_ENUM_CONSTANT(DEBUG_DRAW_WIREFRAME);
BIND_ENUM_CONSTANT(DEBUG_DRAW_NORMAL_BUFFER);
- BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_ALBEDO);
- BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_LIGHTING);
- BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_EMISSION);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_VOXEL_GI_ALBEDO);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_VOXEL_GI_LIGHTING);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_VOXEL_GI_EMISSION);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SHADOW_ATLAS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SCENE_LUMINANCE);
@@ -3655,6 +3667,7 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_SPOT_LIGHTS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_DECALS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_REFLECTION_PROBES);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_OCCLUDERS)
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
@@ -3729,16 +3742,6 @@ Viewport::~Viewport() {
/////////////////////////////////
-void SubViewport::set_use_xr(bool p_use_xr) {
- xr = p_use_xr;
-
- RS::get_singleton()->viewport_set_use_xr(get_viewport_rid(), xr);
-}
-
-bool SubViewport::is_using_xr() {
- return xr;
-}
-
void SubViewport::set_size(const Size2i &p_size) {
_set_size(p_size, _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
}
@@ -3811,9 +3814,6 @@ void SubViewport::_notification(int p_what) {
}
void SubViewport::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &SubViewport::set_use_xr);
- ClassDB::bind_method(D_METHOD("is_using_xr"), &SubViewport::is_using_xr);
-
ClassDB::bind_method(D_METHOD("set_size", "size"), &SubViewport::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &SubViewport::get_size);
@@ -3829,7 +3829,6 @@ void SubViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_clear_mode", "mode"), &SubViewport::set_clear_mode);
ClassDB::bind_method(D_METHOD("get_clear_mode"), &SubViewport::get_clear_mode);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "xr"), "set_use_xr", "is_using_xr");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_2d_override"), "set_size_2d_override", "get_size_2d_override");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "size_2d_override_stretch"), "set_size_2d_override_stretch", "is_size_2d_override_stretch_enabled");
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index e8a88debf1..d905e44a82 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -130,9 +130,9 @@ public:
DEBUG_DRAW_OVERDRAW,
DEBUG_DRAW_WIREFRAME,
DEBUG_DRAW_NORMAL_BUFFER,
- DEBUG_DRAW_GI_PROBE_ALBEDO,
- DEBUG_DRAW_GI_PROBE_LIGHTING,
- DEBUG_DRAW_GI_PROBE_EMISSION,
+ DEBUG_DRAW_VOXEL_GI_ALBEDO,
+ DEBUG_DRAW_VOXEL_GI_LIGHTING,
+ DEBUG_DRAW_VOXEL_GI_EMISSION,
DEBUG_DRAW_SHADOW_ATLAS,
DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
DEBUG_DRAW_SCENE_LUMINANCE,
@@ -147,6 +147,7 @@ public:
DEBUG_DRAW_CLUSTER_SPOT_LIGHTS,
DEBUG_DRAW_CLUSTER_DECALS,
DEBUG_DRAW_CLUSTER_REFLECTION_PROBES,
+ DEBUG_DRAW_OCCLUDERS,
};
enum DefaultCanvasItemTextureFilter {
@@ -192,7 +193,7 @@ private:
Set<Listener3D *> listeners;
struct CameraOverrideData {
- Transform transform;
+ Transform3D transform;
enum Projection {
PROJECTION_PERSPECTIVE,
PROJECTION_ORTHOGONAL
@@ -230,9 +231,10 @@ private:
Transform2D global_canvas_transform;
Transform2D stretch_transform;
- Size2i size;
+ Size2i size = Size2i(512, 512);
Size2i size_2d_override;
bool size_allocated = false;
+ bool use_xr = false;
RID contact_2d_debug;
RID contact_3d_debug_multimesh;
@@ -252,8 +254,8 @@ private:
List<Ref<InputEvent>> physics_picking_events;
ObjectID physics_object_capture;
ObjectID physics_object_over;
- Transform physics_last_object_transform;
- Transform physics_last_camera_transform;
+ Transform3D physics_last_object_transform;
+ Transform3D physics_last_camera_transform;
ObjectID physics_last_id;
bool physics_has_last_mousepos = false;
Vector2 physics_last_mousepos = Vector2(Math_INF, Math_INF);
@@ -304,6 +306,7 @@ private:
ScreenSpaceAA screen_space_aa = SCREEN_SPACE_AA_DISABLED;
bool use_debanding = false;
float lod_threshold = 1.0;
+ bool use_occlusion_culling = false;
Ref<ViewportTexture> default_texture;
Set<ViewportTexture *> viewport_textures;
@@ -394,8 +397,6 @@ private:
void _gui_input_event(Ref<InputEvent> p_event);
- void update_worlds();
-
_FORCE_INLINE_ Transform2D _get_input_pre_xform() const;
Ref<InputEvent> _make_input_local(const Ref<InputEvent> &ev);
@@ -480,7 +481,6 @@ protected:
void _notification(int p_what);
void _process_picking();
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
public:
uint64_t get_processed_events_count() const { return event_count; }
@@ -491,8 +491,8 @@ public:
void enable_camera_override(bool p_enable);
bool is_camera_override_enabled() const;
- void set_camera_override_transform(const Transform &p_transform);
- Transform get_camera_override_transform() const;
+ void set_camera_override_transform(const Transform3D &p_transform);
+ Transform3D get_camera_override_transform() const;
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);
@@ -533,6 +533,9 @@ public:
void set_transparent_background(bool p_enable);
bool has_transparent_background() const;
+ void set_use_xr(bool p_use_xr);
+ bool is_using_xr();
+
Ref<ViewportTexture> get_texture() const;
void set_shadow_atlas_size(int p_size);
@@ -556,6 +559,9 @@ public:
void set_lod_threshold(float p_pixels);
float get_lod_threshold() const;
+ void set_use_occlusion_culling(bool p_us_occlusion_culling);
+ bool is_using_occlusion_culling() const;
+
Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;
@@ -652,7 +658,6 @@ public:
private:
UpdateMode update_mode = UPDATE_WHEN_VISIBLE;
ClearMode clear_mode = CLEAR_MODE_ALWAYS;
- bool xr = false;
bool size_2d_override_stretch = false;
protected:
@@ -668,9 +673,6 @@ public:
void set_size_2d_override(const Size2i &p_size);
Size2i get_size_2d_override() const;
- void set_use_xr(bool p_use_xr);
- bool is_using_xr();
-
void set_size_2d_override_stretch(bool p_enable);
bool is_size_2d_override_stretch_enabled() const;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index bacb0030bb..d793be1869 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -1169,64 +1169,96 @@ 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);
+void Window::set_theme_custom_type(const StringName &p_theme_type) {
+ theme_custom_type = p_theme_type;
+ Control::_propagate_theme_changed(this, theme_owner, theme_owner_window);
}
-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);
+StringName Window::get_theme_custom_type() const {
+ return theme_custom_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);
+void Window::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
+ if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_custom_type) {
+ if (theme_custom_type != StringName()) {
+ p_list->push_back(theme_custom_type);
+ }
+ Theme::get_type_dependencies(get_class_name(), p_list);
+ } else {
+ Theme::get_type_dependencies(p_theme_type, p_list);
+ }
+}
+
+Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<Ref<Texture2D>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
}
-int Window::get_theme_font_size(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::get_font_sizes(theme_owner, theme_owner_window, p_name, type);
+Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<Ref<StyleBox>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
-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);
+Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<Ref<Font>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
}
-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);
+int Window::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
-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);
+Color Window::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<Color>(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
-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);
+int Window::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
-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_icon(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
}
-bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_type) const {
- StringName type = p_type ? p_type : get_class_name();
- return Control::has_font_sizes(theme_owner, theme_owner_window, p_name, type);
+bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
-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_font(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
}
-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);
+bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+}
+
+bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+}
+
+bool Window::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
+ List<StringName> theme_types;
+ _get_theme_type_dependencies(p_theme_type, &theme_types);
+ return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
Rect2i Window::get_parent_rect() const {
@@ -1382,19 +1414,22 @@ void Window::_bind_methods() {
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_font_size", "name", "type"), &Window::get_theme_font_size, 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("set_theme_custom_type", "theme_type"), &Window::set_theme_custom_type);
+ ClassDB::bind_method(D_METHOD("get_theme_custom_type"), &Window::get_theme_custom_type);
+
+ ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "theme_type"), &Window::get_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "theme_type"), &Window::get_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_font", "name", "theme_type"), &Window::get_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_font_size", "name", "theme_type"), &Window::get_theme_font_size, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_color", "name", "theme_type"), &Window::get_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "theme_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_font_size", "name", "type"), &Window::has_theme_font_size, 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("has_theme_icon", "name", "theme_type"), &Window::has_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "theme_type"), &Window::has_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_font", "name", "theme_type"), &Window::has_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_font_size", "name", "theme_type"), &Window::has_theme_font_size, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Window::has_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Window::has_theme_constant, DEFVAL(""));
ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Window::set_layout_direction);
ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction);
@@ -1409,7 +1444,7 @@ void Window::_bind_methods() {
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::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");
@@ -1426,10 +1461,11 @@ void Window::_bind_methods() {
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,CanvasItems,Viewport"), "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::INT, "content_scale_mode", PROPERTY_HINT_ENUM, "Disabled,Canvas Items,Viewport"), "set_content_scale_mode", "get_content_scale_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_aspect", PROPERTY_HINT_ENUM, "Ignore,Keep,Keep Width,Keep Height,Expand"), "set_content_scale_aspect", "get_content_scale_aspect");
+ ADD_GROUP("Theme", "theme_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_custom_type"), "set_theme_custom_type", "get_theme_custom_type");
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")));
diff --git a/scene/main/window.h b/scene/main/window.h
index 38846ed00e..494c386606 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -130,6 +130,7 @@ private:
Ref<Theme> theme;
Control *theme_owner = nullptr;
Window *theme_owner_window = nullptr;
+ StringName theme_custom_type;
Viewport *embedder = nullptr;
@@ -241,6 +242,10 @@ public:
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
+ void set_theme_custom_type(const StringName &p_theme_type);
+ StringName get_theme_custom_type() const;
+ _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
+
Size2 get_contents_minimum_size() const;
void grab_focus();
@@ -252,19 +257,19 @@ public:
Rect2i get_usable_parent_rect() const;
- Ref<Texture2D> get_theme_icon(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;
- int get_theme_font_size(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_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_font_size(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;
+ Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ int get_theme_font_size(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Color get_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ int get_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+
+ bool has_theme_icon(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_font(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_font_size(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
Rect2i get_parent_rect() const;
virtual DisplayServer::WindowID get_window_id() const override;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 232ad278dd..332976a18d 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -55,6 +55,7 @@
#include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h"
#include "scene/2d/path_2d.h"
+#include "scene/2d/physical_bone_2d.h"
#include "scene/2d/physics_body_2d.h"
#include "scene/2d/polygon_2d.h"
#include "scene/2d/position_2d.h"
@@ -65,7 +66,6 @@
#include "scene/2d/tile_map.h"
#include "scene/2d/touch_screen_button.h"
#include "scene/2d/visibility_notifier_2d.h"
-#include "scene/2d/y_sort.h"
#include "scene/animation/animation_blend_space_1d.h"
#include "scene/animation/animation_blend_space_2d.h"
#include "scene/animation/animation_blend_tree.h"
@@ -161,6 +161,15 @@
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/resource_format_text.h"
#include "scene/resources/segment_shape_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
+#include "scene/resources/skeleton_modification_2d_ccdik.h"
+#include "scene/resources/skeleton_modification_2d_fabrik.h"
+#include "scene/resources/skeleton_modification_2d_jiggle.h"
+#include "scene/resources/skeleton_modification_2d_lookat.h"
+#include "scene/resources/skeleton_modification_2d_physicalbones.h"
+#include "scene/resources/skeleton_modification_2d_stackholder.h"
+#include "scene/resources/skeleton_modification_2d_twoboneik.h"
+#include "scene/resources/skeleton_modification_stack_2d.h"
#include "scene/resources/sky.h"
#include "scene/resources/sky_material.h"
#include "scene/resources/sphere_shape_3d.h"
@@ -174,33 +183,29 @@
#include "scene/resources/video_stream.h"
#include "scene/resources/visual_shader.h"
#include "scene/resources/visual_shader_nodes.h"
+#include "scene/resources/visual_shader_particle_nodes.h"
#include "scene/resources/visual_shader_sdf_nodes.h"
#include "scene/resources/world_2d.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"
-
#include "scene/main/shader_globals_override.h"
#ifndef _3D_DISABLED
#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_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/gpu_particles_3d.h"
#include "scene/3d/gpu_particles_collision_3d.h"
#include "scene/3d/immediate_geometry_3d.h"
#include "scene/3d/light_3d.h"
+#include "scene/3d/lightmap_gi.h"
#include "scene/3d/lightmap_probe.h"
#include "scene/3d/listener_3d.h"
#include "scene/3d/mesh_instance_3d.h"
@@ -208,6 +213,8 @@
#include "scene/3d/navigation_agent_3d.h"
#include "scene/3d/navigation_obstacle_3d.h"
#include "scene/3d/navigation_region_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/occluder_instance_3d.h"
#include "scene/3d/path_3d.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/3d/physics_joint_3d.h"
@@ -216,12 +223,14 @@
#include "scene/3d/ray_cast_3d.h"
#include "scene/3d/reflection_probe.h"
#include "scene/3d/remote_transform_3d.h"
+#include "scene/3d/skeleton_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_3d.h"
#include "scene/3d/visibility_notifier_3d.h"
+#include "scene/3d/voxel_gi.h"
#include "scene/3d/world_environment.h"
#include "scene/3d/xr_nodes.h"
#include "scene/resources/environment.h"
@@ -394,14 +403,7 @@ void register_scene_types() {
AcceptDialog::set_swap_cancel_ok(swap_cancel_ok);
#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>();
+ /* REGISTER ANIMATION */
ClassDB::register_class<AnimationPlayer>();
ClassDB::register_class<Tween>();
@@ -431,7 +433,14 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
+ /* REGISTER 3D */
+
#ifndef _3D_DISABLED
+ ClassDB::register_class<Node3D>();
+ ClassDB::register_virtual_class<Node3DGizmo>();
+ ClassDB::register_class<Skin>();
+ ClassDB::register_virtual_class<SkinReference>();
+ ClassDB::register_class<Skeleton3D>();
ClassDB::register_virtual_class<VisualInstance3D>();
ClassDB::register_virtual_class<GeometryInstance3D>();
ClassDB::register_class<Camera3D>();
@@ -442,6 +451,8 @@ void register_scene_types() {
ClassDB::register_class<XRAnchor3D>();
ClassDB::register_class<XROrigin3D>();
ClassDB::register_class<MeshInstance3D>();
+ ClassDB::register_class<OccluderInstance3D>();
+ ClassDB::register_class<Occluder3D>();
ClassDB::register_class<ImmediateGeometry3D>();
ClassDB::register_virtual_class<SpriteBase3D>();
ClassDB::register_class<Sprite3D>();
@@ -452,10 +463,10 @@ void register_scene_types() {
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<VoxelGI>();
+ ClassDB::register_class<VoxelGIData>();
+ ClassDB::register_class<LightmapGI>();
+ ClassDB::register_class<LightmapGIData>();
ClassDB::register_class<LightmapProbe>();
ClassDB::register_virtual_class<Lightmapper>();
ClassDB::register_class<GPUParticles3D>();
@@ -481,7 +492,7 @@ void register_scene_types() {
ClassDB::register_class<StaticBody3D>();
ClassDB::register_class<RigidBody3D>();
ClassDB::register_class<KinematicCollision3D>();
- ClassDB::register_class<KinematicBody3D>();
+ ClassDB::register_class<CharacterBody3D>();
ClassDB::register_class<SpringArm3D>();
ClassDB::register_class<PhysicalBone3D>();
@@ -550,6 +561,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeVectorFunc>();
ClassDB::register_class<VisualShaderNodeColorFunc>();
ClassDB::register_class<VisualShaderNodeTransformFunc>();
+ ClassDB::register_class<VisualShaderNodeUVFunc>();
ClassDB::register_class<VisualShaderNodeDotProduct>();
ClassDB::register_class<VisualShaderNodeVectorLen>();
ClassDB::register_class<VisualShaderNodeDeterminant>();
@@ -594,6 +606,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeIs>();
ClassDB::register_class<VisualShaderNodeCompare>();
ClassDB::register_class<VisualShaderNodeMultiplyAdd>();
+ ClassDB::register_class<VisualShaderNodeBillboard>();
ClassDB::register_class<VisualShaderNodeSDFToScreenUV>();
ClassDB::register_class<VisualShaderNodeScreenUVToSDF>();
@@ -601,6 +614,17 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeTextureSDFNormal>();
ClassDB::register_class<VisualShaderNodeSDFRaymarch>();
+ ClassDB::register_class<VisualShaderNodeParticleOutput>();
+ ClassDB::register_virtual_class<VisualShaderNodeParticleEmitter>();
+ ClassDB::register_class<VisualShaderNodeParticleSphereEmitter>();
+ ClassDB::register_class<VisualShaderNodeParticleBoxEmitter>();
+ ClassDB::register_class<VisualShaderNodeParticleRingEmitter>();
+ ClassDB::register_class<VisualShaderNodeParticleMultiplyByAxisAngle>();
+ ClassDB::register_class<VisualShaderNodeParticleConeVelocity>();
+ ClassDB::register_class<VisualShaderNodeParticleRandomness>();
+ ClassDB::register_class<VisualShaderNodeParticleAccelerator>();
+ ClassDB::register_class<VisualShaderNodeParticleEmit>();
+
ClassDB::register_class<ShaderMaterial>();
ClassDB::register_virtual_class<CanvasItem>();
ClassDB::register_class<CanvasTexture>();
@@ -625,7 +649,7 @@ void register_scene_types() {
ClassDB::register_virtual_class<PhysicsBody2D>();
ClassDB::register_class<StaticBody2D>();
ClassDB::register_class<RigidBody2D>();
- ClassDB::register_class<KinematicBody2D>();
+ ClassDB::register_class<CharacterBody2D>();
ClassDB::register_class<KinematicCollision2D>();
ClassDB::register_class<Area2D>();
ClassDB::register_class<CollisionShape2D>();
@@ -641,7 +665,6 @@ void register_scene_types() {
ClassDB::register_class<DirectionalLight2D>();
ClassDB::register_class<LightOccluder2D>();
ClassDB::register_class<OccluderPolygon2D>();
- ClassDB::register_class<YSort>();
ClassDB::register_class<BackBufferCopy>();
OS::get_singleton()->yield(); //may take time to init
@@ -652,12 +675,28 @@ void register_scene_types() {
ClassDB::register_class<GrooveJoint2D>();
ClassDB::register_class<DampedSpringJoint2D>();
ClassDB::register_class<TileSet>();
+ ClassDB::register_virtual_class<TileSetSource>();
+ ClassDB::register_class<TileSetAtlasSource>();
+ ClassDB::register_class<TileSetScenesCollectionSource>();
+ ClassDB::register_class<TileData>();
ClassDB::register_class<TileMap>();
ClassDB::register_class<ParallaxBackground>();
ClassDB::register_class<ParallaxLayer>();
ClassDB::register_class<TouchScreenButton>();
ClassDB::register_class<RemoteTransform2D>();
+ ClassDB::register_class<SkeletonModificationStack2D>();
+ ClassDB::register_class<SkeletonModification2D>();
+ ClassDB::register_class<SkeletonModification2DLookAt>();
+ ClassDB::register_class<SkeletonModification2DCCDIK>();
+ ClassDB::register_class<SkeletonModification2DFABRIK>();
+ ClassDB::register_class<SkeletonModification2DJiggle>();
+ ClassDB::register_class<SkeletonModification2DTwoBoneIK>();
+ ClassDB::register_class<SkeletonModification2DStackHolder>();
+
+ ClassDB::register_class<PhysicalBone2D>();
+ ClassDB::register_class<SkeletonModification2DPhysicalBones>();
+
OS::get_singleton()->yield(); //may take time to init
/* REGISTER RESOURCES */
@@ -686,6 +725,8 @@ void register_scene_types() {
ClassDB::register_class<PrismMesh>();
ClassDB::register_class<QuadMesh>();
ClassDB::register_class<SphereMesh>();
+ ClassDB::register_class<TubeTrailMesh>();
+ ClassDB::register_class<RibbonTrailMesh>();
ClassDB::register_class<PointMesh>();
ClassDB::register_virtual_class<Material>();
ClassDB::register_virtual_class<BaseMaterial3D>();
@@ -726,7 +767,6 @@ void register_scene_types() {
ClassDB::register_class<ImageTexture>();
ClassDB::register_class<AtlasTexture>();
ClassDB::register_class<MeshTexture>();
- ClassDB::register_class<LargeTexture>();
ClassDB::register_class<CurveTexture>();
ClassDB::register_class<GradientTexture>();
ClassDB::register_class<ProxyTexture>();
@@ -813,6 +853,11 @@ void register_scene_types() {
ClassDB::add_compatibility_class("ToolButton", "Button");
ClassDB::add_compatibility_class("Navigation3D", "Node3D");
ClassDB::add_compatibility_class("Navigation2D", "Node2D");
+ ClassDB::add_compatibility_class("YSort", "Node2D");
+ ClassDB::add_compatibility_class("GIProbe", "VoxelGI");
+ ClassDB::add_compatibility_class("GIProbeData", "VoxelGIData");
+ ClassDB::add_compatibility_class("BakedLightmap", "LightmapGI");
+ ClassDB::add_compatibility_class("BakedLightmapData", "LightmapGIData");
// Renamed in 4.0.
// Keep alphabetical ordering to easily locate classes and avoid duplicates.
@@ -858,7 +903,8 @@ void register_scene_types() {
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("KinematicBody", "CharacterBody3D");
+ ClassDB::add_compatibility_class("KinematicBody2D", "CharacterBody2D");
ClassDB::add_compatibility_class("KinematicCollision", "KinematicCollision3D");
ClassDB::add_compatibility_class("Light", "Light3D");
ClassDB::add_compatibility_class("Listener", "Listener3D");
@@ -972,6 +1018,7 @@ void register_scene_types() {
// Always make the default theme to avoid invalid default font/icon/style in the given theme.
if (RenderingServer::get_singleton()) {
make_default_theme(default_theme_hidpi, font);
+ ColorPicker::init_shaders(); // RenderingServer needs to exist for this to succeed.
}
if (theme_path != String()) {
@@ -1028,5 +1075,6 @@ void unregister_scene_types() {
ParticlesMaterial::finish_shaders();
CanvasItemMaterial::finish_shaders();
+ ColorPicker::finish_shaders();
SceneStringNames::free();
}
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 6f64ac6d04..640ec50eb9 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -43,8 +43,8 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
if (tracks.size() == track && what == "type") {
String type = p_value;
- if (type == "transform") {
- add_track(TYPE_TRANSFORM);
+ if (type == "transform" || type == "transform3d") {
+ add_track(TYPE_TRANSFORM3D);
} else if (type == "value") {
add_track(TYPE_VALUE);
} else if (type == "method") {
@@ -75,7 +75,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
} else if (what == "enabled") {
track_set_enabled(track, p_value);
} else if (what == "keys" || what == "key_values") {
- if (track_get_type(track) == TYPE_TRANSFORM) {
+ if (track_get_type(track) == TYPE_TRANSFORM3D) {
TransformTrack *tt = static_cast<TransformTrack *>(tracks[track]);
Vector<float> values = p_value;
int vcount = values.size();
@@ -318,7 +318,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
ERR_FAIL_INDEX_V(track, tracks.size(), false);
if (what == "type") {
switch (track_get_type(track)) {
- case TYPE_TRANSFORM:
+ case TYPE_TRANSFORM3D:
r_ret = "transform";
break;
case TYPE_VALUE:
@@ -351,7 +351,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
} else if (what == "enabled") {
r_ret = track_is_enabled(track);
} else if (what == "keys") {
- if (track_get_type(track) == TYPE_TRANSFORM) {
+ if (track_get_type(track) == TYPE_TRANSFORM3D) {
Vector<float> keys;
int kk = track_get_key_count(track);
keys.resize(kk * 12);
@@ -361,7 +361,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
int idx = 0;
for (int i = 0; i < track_get_key_count(track); i++) {
Vector3 loc;
- Quat rot;
+ Quaternion rot;
Vector3 scale;
transform_track_get_key(track, i, &loc, &rot, &scale);
@@ -590,7 +590,7 @@ int Animation::add_track(TrackType p_type, int p_at_pos) {
}
switch (p_type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = memnew(TransformTrack);
tracks.insert(p_at_pos, tt);
} break;
@@ -628,7 +628,7 @@ void Animation::remove_track(int p_track) {
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = static_cast<TransformTrack *>(t);
_clear(tt->transforms);
@@ -671,7 +671,7 @@ int Animation::get_track_count() const {
}
Animation::TrackType Animation::track_get_type(int p_track) const {
- ERR_FAIL_INDEX_V(p_track, tracks.size(), TYPE_TRANSFORM);
+ ERR_FAIL_INDEX_V(p_track, tracks.size(), TYPE_TRANSFORM3D);
return tracks[p_track]->type;
}
@@ -773,12 +773,12 @@ void Animation::_clear(T &p_keys) {
p_keys.clear();
}
-Error Animation::transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const {
+Error Animation::transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER);
Track *t = tracks[p_track];
TransformTrack *tt = static_cast<TransformTrack *>(t);
- ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, ERR_INVALID_PARAMETER);
ERR_FAIL_INDEX_V(p_key, tt->transforms.size(), ERR_INVALID_PARAMETER);
if (r_loc) {
@@ -794,10 +794,10 @@ Error Animation::transform_track_get_key(int p_track, int p_key, Vector3 *r_loc,
return OK;
}
-int Animation::transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quat &p_rot, const Vector3 &p_scale) {
+int Animation::transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quaternion &p_rot, const Vector3 &p_scale) {
ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
Track *t = tracks[p_track];
- ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM, -1);
+ ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, -1);
TransformTrack *tt = static_cast<TransformTrack *>(t);
@@ -823,7 +823,7 @@ void Animation::track_remove_key(int p_track, int p_idx) {
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = static_cast<TransformTrack *>(t);
ERR_FAIL_INDEX(p_idx, tt->transforms.size());
tt->transforms.remove(p_idx);
@@ -869,7 +869,7 @@ int Animation::track_find_key(int p_track, float p_time, bool p_exact) const {
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = static_cast<TransformTrack *>(t);
int k = _find(tt->transforms, p_time);
if (k < 0 || k >= tt->transforms.size()) {
@@ -951,14 +951,14 @@ void Animation::track_insert_key(int p_track, float p_time, const Variant &p_key
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
Dictionary d = p_key;
Vector3 loc;
if (d.has("location")) {
loc = d["location"];
}
- Quat rot;
+ Quaternion rot;
if (d.has("rotation")) {
rot = d["rotation"];
}
@@ -1053,7 +1053,7 @@ int Animation::track_get_key_count(int p_track) const {
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = static_cast<TransformTrack *>(t);
return tt->transforms.size();
} break;
@@ -1088,7 +1088,7 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const {
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = static_cast<TransformTrack *>(t);
ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), Variant());
@@ -1156,7 +1156,7 @@ float Animation::track_get_key_time(int p_track, int p_key_idx) const {
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = static_cast<TransformTrack *>(t);
ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), -1);
return tt->transforms[p_key_idx].time;
@@ -1201,7 +1201,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, float p_time) {
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = static_cast<TransformTrack *>(t);
ERR_FAIL_INDEX(p_key_idx, tt->transforms.size());
TKey<TransformKey> key = tt->transforms[p_key_idx];
@@ -1265,7 +1265,7 @@ float Animation::track_get_key_transition(int p_track, int p_key_idx) const {
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = static_cast<TransformTrack *>(t);
ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), -1);
return tt->transforms[p_key_idx].transition;
@@ -1301,7 +1301,7 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = static_cast<TransformTrack *>(t);
ERR_FAIL_INDEX(p_key_idx, tt->transforms.size());
@@ -1384,7 +1384,7 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_tra
Track *t = tracks[p_track];
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
TransformTrack *tt = static_cast<TransformTrack *>(t);
ERR_FAIL_INDEX(p_key_idx, tt->transforms.size());
tt->transforms.write[p_key_idx].transition = p_transition;
@@ -1462,7 +1462,7 @@ Vector3 Animation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, float p_
return p_a.lerp(p_b, p_c);
}
-Quat Animation::_interpolate(const Quat &p_a, const Quat &p_b, float p_c) const {
+Quaternion Animation::_interpolate(const Quaternion &p_a, const Quaternion &p_b, float p_c) const {
return p_a.slerp(p_b, p_c);
}
@@ -1490,7 +1490,7 @@ Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a
return p_a.cubic_interpolate(p_b, p_pre_a, p_post_b, p_c);
}
-Quat Animation::_cubic_interpolate(const Quat &p_pre_a, const Quat &p_a, const Quat &p_b, const Quat &p_post_b, float p_c) const {
+Quaternion Animation::_cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, float p_c) const {
return p_a.cubic_slerp(p_b, p_pre_a, p_post_b, p_c);
}
@@ -1555,11 +1555,11 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
return a.cubic_interpolate(b, pa, pb, p_c);
}
- case Variant::QUAT: {
- Quat a = p_a;
- Quat b = p_b;
- Quat pa = p_pre_a;
- Quat pb = p_post_b;
+ case Variant::QUATERNION: {
+ Quaternion a = p_a;
+ Quaternion b = p_b;
+ Quaternion pa = p_pre_a;
+ Quaternion pb = p_post_b;
return a.cubic_slerp(b, pa, pb, p_c);
}
@@ -1728,10 +1728,10 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola
// do a barrel roll
}
-Error Animation::transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const {
+Error Animation::transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER);
Track *t = tracks[p_track];
- ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, ERR_INVALID_PARAMETER);
TransformTrack *tt = static_cast<TransformTrack *>(t);
@@ -1932,7 +1932,7 @@ void Animation::track_get_key_indices_in_range(int p_track, float p_time, float
// handle loop by splitting
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
const TransformTrack *tt = static_cast<const TransformTrack *>(t);
_track_get_key_indices_in_range(tt->transforms, from_time, length, p_indices);
_track_get_key_indices_in_range(tt->transforms, 0, to_time, p_indices);
@@ -1988,7 +1988,7 @@ void Animation::track_get_key_indices_in_range(int p_track, float p_time, float
}
switch (t->type) {
- case TYPE_TRANSFORM: {
+ case TYPE_TRANSFORM3D: {
const TransformTrack *tt = static_cast<const TransformTrack *>(t);
_track_get_key_indices_in_range(tt->transforms, from_time, to_time, p_indices);
@@ -2681,7 +2681,7 @@ void Animation::_bind_methods() {
ADD_SIGNAL(MethodInfo("tracks_changed"));
BIND_ENUM_CONSTANT(TYPE_VALUE);
- BIND_ENUM_CONSTANT(TYPE_TRANSFORM);
+ BIND_ENUM_CONSTANT(TYPE_TRANSFORM3D);
BIND_ENUM_CONSTANT(TYPE_METHOD);
BIND_ENUM_CONSTANT(TYPE_BEZIER);
BIND_ENUM_CONSTANT(TYPE_AUDIO);
@@ -2751,9 +2751,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
{ //rotation
- const Quat &q0 = t0.value.rot;
- const Quat &q1 = t1.value.rot;
- const Quat &q2 = t2.value.rot;
+ const Quaternion &q0 = t0.value.rot;
+ const Quaternion &q1 = t1.value.rot;
+ const Quaternion &q2 = t2.value.rot;
//localize both to rotation from q0
@@ -2763,8 +2763,8 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
}
} else {
- Quat r02 = (q0.inverse() * q2).normalized();
- Quat r01 = (q0.inverse() * q1).normalized();
+ Quaternion r02 = (q0.inverse() * q2).normalized();
+ Quaternion r01 = (q0.inverse() * q1).normalized();
Vector3 v02, v01;
real_t a02, a01;
@@ -2877,7 +2877,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
void Animation::_transform_track_optimize(int p_idx, float p_allowed_linear_err, float p_allowed_angular_err, float p_max_optimizable_angle) {
ERR_FAIL_INDEX(p_idx, tracks.size());
- ERR_FAIL_COND(tracks[p_idx]->type != TYPE_TRANSFORM);
+ ERR_FAIL_COND(tracks[p_idx]->type != TYPE_TRANSFORM3D);
TransformTrack *tt = static_cast<TransformTrack *>(tracks[p_idx]);
bool prev_erased = false;
TKey<TransformKey> first_erased;
@@ -2917,7 +2917,7 @@ void Animation::_transform_track_optimize(int p_idx, float p_allowed_linear_err,
void Animation::optimize(float p_allowed_linear_err, float p_allowed_angular_err, float p_max_optimizable_angle) {
for (int i = 0; i < tracks.size(); i++) {
- if (tracks[i]->type == TYPE_TRANSFORM) {
+ if (tracks[i]->type == TYPE_TRANSFORM3D) {
_transform_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle);
}
}
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 66bc71c834..1484007333 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -42,7 +42,7 @@ class Animation : public Resource {
public:
enum TrackType {
TYPE_VALUE, ///< Set a value in a property, can be interpolated.
- TYPE_TRANSFORM, ///< Transform a node or a bone.
+ TYPE_TRANSFORM3D, ///< Transform a node or a bone.
TYPE_METHOD, ///< Call any method on a specific node.
TYPE_BEZIER, ///< Bezier curve
TYPE_AUDIO,
@@ -88,7 +88,7 @@ private:
struct TransformKey {
Vector3 loc;
- Quat rot;
+ Quaternion rot;
Vector3 scale;
};
@@ -97,7 +97,7 @@ private:
struct TransformTrack : public Track {
Vector<TKey<TransformKey>> transforms;
- TransformTrack() { type = TYPE_TRANSFORM; }
+ TransformTrack() { type = TYPE_TRANSFORM3D; }
};
/* PROPERTY VALUE TRACK */
@@ -186,13 +186,13 @@ private:
_FORCE_INLINE_ Animation::TransformKey _interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, float p_c) const;
_FORCE_INLINE_ Vector3 _interpolate(const Vector3 &p_a, const Vector3 &p_b, float p_c) const;
- _FORCE_INLINE_ Quat _interpolate(const Quat &p_a, const Quat &p_b, float p_c) const;
+ _FORCE_INLINE_ Quaternion _interpolate(const Quaternion &p_a, const Quaternion &p_b, float p_c) const;
_FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, float p_c) const;
_FORCE_INLINE_ float _interpolate(const float &p_a, const float &p_b, float p_c) const;
_FORCE_INLINE_ Animation::TransformKey _cubic_interpolate(const Animation::TransformKey &p_pre_a, const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, const Animation::TransformKey &p_post_b, float p_c) const;
_FORCE_INLINE_ Vector3 _cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, float p_c) const;
- _FORCE_INLINE_ Quat _cubic_interpolate(const Quat &p_pre_a, const Quat &p_a, const Quat &p_b, const Quat &p_post_b, float p_c) const;
+ _FORCE_INLINE_ Quaternion _cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, float p_c) const;
_FORCE_INLINE_ Variant _cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, float p_c) const;
_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;
@@ -213,7 +213,7 @@ private:
private:
Array _transform_track_interpolate(int p_track, float p_time) const {
Vector3 loc;
- Quat rot;
+ Quaternion rot;
Vector3 scale;
transform_track_interpolate(p_track, p_time, &loc, &rot, &scale);
Array ret;
@@ -291,8 +291,8 @@ public:
float track_get_key_time(int p_track, int p_key_idx) const;
float track_get_key_transition(int p_track, int p_key_idx) const;
- int transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quat &p_rot = Quat(), const Vector3 &p_scale = Vector3());
- Error transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const;
+ int transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quaternion &p_rot = Quaternion(), const Vector3 &p_scale = Vector3());
+ Error transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const;
void track_set_interpolation_type(int p_track, InterpolationType p_interp);
InterpolationType track_get_interpolation_type(int p_track) const;
@@ -321,7 +321,7 @@ public:
void track_set_interpolation_loop_wrap(int p_track, bool p_enable);
bool track_get_interpolation_loop_wrap(int p_track) const;
- Error transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const;
+ Error transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const;
Variant value_track_interpolate(int p_track, float p_time) const;
void value_track_get_key_indices(int p_track, float p_time, float p_delta, List<int> *p_indices) const;
diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp
index 06a91fb2f8..81062feb46 100644
--- a/scene/resources/audio_stream_sample.cpp
+++ b/scene/resources/audio_stream_sample.cpp
@@ -30,8 +30,8 @@
#include "audio_stream_sample.h"
+#include "core/io/file_access.h"
#include "core/io/marshalls.h"
-#include "core/os/file_access.h"
void AudioStreamPlaybackSample::start(float p_from_pos) {
if (base->format == AudioStreamSample::FORMAT_IMA_ADPCM) {
@@ -490,9 +490,9 @@ void AudioStreamSample::set_data(const Vector<uint8_t> &p_data) {
const uint8_t *r = p_data.ptr();
int alloc_len = datalen + DATA_PAD * 2;
data = memalloc(alloc_len); //alloc with some padding for interpolation
- zeromem(data, alloc_len);
+ memset(data, 0, alloc_len);
uint8_t *dataptr = (uint8_t *)data;
- copymem(dataptr + DATA_PAD, r, datalen);
+ memcpy(dataptr + DATA_PAD, r, datalen);
data_bytes = datalen;
}
@@ -507,7 +507,7 @@ Vector<uint8_t> AudioStreamSample::get_data() const {
{
uint8_t *w = pv.ptrw();
uint8_t *dataptr = (uint8_t *)data;
- copymem(w, dataptr + DATA_PAD, data_bytes);
+ memcpy(w, dataptr + DATA_PAD, data_bytes);
}
}
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 3cc1af59ae..0ffeb8a5bf 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -38,8 +38,8 @@ void BitMap::create(const Size2 &p_size) {
width = p_size.width;
height = p_size.height;
- bitmask.resize(((width * height) / 8) + 1);
- zeromem(bitmask.ptrw(), bitmask.size());
+ bitmask.resize((((width * height) - 1) / 8) + 1);
+ memset(bitmask.ptrw(), 0, bitmask.size());
}
void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshold) {
diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp
index 9e030bc077..6b895da606 100644
--- a/scene/resources/convex_polygon_shape_3d.cpp
+++ b/scene/resources/convex_polygon_shape_3d.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "convex_polygon_shape_3d.h"
-#include "core/math/quick_hull.h"
+#include "core/math/convex_hull.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
@@ -38,7 +38,7 @@ Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
if (points.size() > 3) {
Vector<Vector3> varr = Variant(points);
Geometry3D::MeshData md;
- Error err = QuickHull::build(varr, md);
+ Error err = ConvexHullComputer::convex_hull(varr, md);
if (err == OK) {
Vector<Vector3> lines;
lines.resize(md.edges.size() * 2);
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index bc479e557a..846da39221 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -445,10 +445,10 @@ void Curve::set_bake_resolution(int p_resolution) {
_baked_cache_dirty = true;
}
-real_t Curve::interpolate_baked(real_t offset) {
+real_t Curve::interpolate_baked(real_t offset) const {
if (_baked_cache_dirty) {
// Last-second bake if not done already
- bake();
+ const_cast<Curve *>(this)->bake();
}
// Special cases if the cache is too small
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 402c893cd8..746c6fa597 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -122,7 +122,7 @@ public:
void bake();
int get_bake_resolution() const { return _bake_resolution; }
void set_bake_resolution(int p_resolution);
- real_t interpolate_baked(real_t offset);
+ real_t interpolate_baked(real_t offset) const;
void ensure_default_setup(float p_min, float p_max);
diff --git a/scene/resources/default_theme/SCsub b/scene/resources/default_theme/SCsub
index fc61250247..0fb6bb2c62 100644
--- a/scene/resources/default_theme/SCsub
+++ b/scene/resources/default_theme/SCsub
@@ -2,4 +2,16 @@
Import("env")
+import os
+import os.path
+from platform_methods import run_in_subprocess
+import default_theme_builders
+
env.add_source_files(env.scene_sources, "*.cpp")
+
+env.Depends("#scene/resources/default_theme/default_font.gen.h", "#thirdparty/fonts/OpenSans_SemiBold.ttf")
+env.CommandNoCache(
+ "#scene/resources/default_theme/default_font.gen.h",
+ "#thirdparty/fonts/OpenSans_SemiBold.ttf",
+ run_in_subprocess(default_theme_builders.make_fonts_header),
+)
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index b9f4a7a741..a4228d48b4 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -30,15 +30,12 @@
#include "default_theme.h"
-#include "scene/resources/theme.h"
-
#include "core/os/os.h"
-#include "theme_data.h"
-
-#include "font_hidpi.inc"
-#include "font_lodpi.inc"
-
+#include "default_font.gen.h"
+#include "scene/resources/font.h"
+#include "scene/resources/theme.h"
#include "servers/text_server.h"
+#include "theme_data.h"
typedef Map<const void *, Ref<ImageTexture>> TexCacheMap;
@@ -128,38 +125,6 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
return texture;
}
-static Ref<FontData> make_font(int p_height, int p_ascent, int p_charcount, const int *p_char_rects, int p_kerning_count, const int *p_kernings, int p_w, int p_h, const unsigned char *p_img) {
- Ref<FontData> font(memnew(FontData));
- font->new_bitmap(p_height, p_ascent, p_height);
-
- Ref<Image> image = memnew(Image(p_img));
- Ref<ImageTexture> tex = memnew(ImageTexture);
- tex->create_from_image(image);
-
- font->bitmap_add_texture(tex);
-
- for (int i = 0; i < p_charcount; i++) {
- const int *c = &p_char_rects[i * 8];
-
- int chr = c[0];
- Rect2 frect;
- frect.position.x = c[1];
- frect.position.y = c[2];
- frect.size.x = c[3];
- frect.size.y = c[4];
- Point2 align(c[6], c[5]);
- int advance = c[7];
-
- font->bitmap_add_char(chr, 0, frect, align, advance);
- }
-
- for (int i = 0; i < p_kerning_count; i++) {
- font->bitmap_add_kerning_pair(p_kernings[i * 3 + 0], p_kernings[i * 3 + 1], p_kernings[i * 3 + 2]);
- }
-
- return font;
-}
-
static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
Ref<StyleBox> style(memnew(StyleBoxEmpty));
@@ -467,7 +432,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("normal", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_stylebox("focus", "TextEdit", focus);
theme->set_stylebox("read_only", "TextEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4, 0, 0, 0, 0));
- theme->set_stylebox("completion", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_icon("tab", "TextEdit", make_icon(tab_png));
theme->set_icon("space", "TextEdit", make_icon(space_png));
@@ -476,27 +440,17 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font_size("font_size", "TextEdit", -1);
theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0));
- theme->set_color("completion_background_color", "TextEdit", Color(0.17, 0.16, 0.2));
- theme->set_color("completion_selected_color", "TextEdit", Color(0.26, 0.26, 0.27));
- theme->set_color("completion_existing_color", "TextEdit", Color(0.87, 0.87, 0.87, 0.13));
- theme->set_color("completion_scroll_color", "TextEdit", control_font_pressed_color);
- theme->set_color("completion_font_color", "TextEdit", Color(0.67, 0.67, 0.67));
theme->set_color("font_color", "TextEdit", control_font_color);
theme->set_color("font_selected_color", "TextEdit", Color(0, 0, 0));
theme->set_color("font_readonly_color", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1));
theme->set_color("selection_color", "TextEdit", control_selection_color);
- theme->set_color("mark_color", "TextEdit", Color(1.0, 0.4, 0.4, 0.4));
- theme->set_color("code_folding_color", "TextEdit", Color(0.8, 0.8, 0.8, 0.8));
theme->set_color("current_line_color", "TextEdit", Color(0.25, 0.25, 0.26, 0.8));
theme->set_color("caret_color", "TextEdit", control_font_color);
theme->set_color("caret_background_color", "TextEdit", Color(0, 0, 0));
theme->set_color("brace_mismatch_color", "TextEdit", Color(1, 0.2, 0.2));
theme->set_color("word_highlighted_color", "TextEdit", Color(0.8, 0.9, 0.9, 0.15));
- theme->set_constant("completion_lines", "TextEdit", 7);
- theme->set_constant("completion_max_width", "TextEdit", 50);
- theme->set_constant("completion_scroll_width", "TextEdit", 3);
theme->set_constant("line_spacing", "TextEdit", 4 * scale);
theme->set_constant("outline_size", "TextEdit", 0);
@@ -514,6 +468,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("executing_line", "CodeEdit", make_icon(arrow_right_png));
theme->set_icon("can_fold", "CodeEdit", make_icon(arrow_down_png));
theme->set_icon("folded", "CodeEdit", make_icon(arrow_right_png));
+ theme->set_icon("folded_eol_icon", "CodeEdit", make_icon(ellipsis_png));
theme->set_font("font", "CodeEdit", Ref<Font>());
theme->set_font_size("font_size", "CodeEdit", -1);
@@ -529,12 +484,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_readonly_color", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
theme->set_color("font_outline_color", "CodeEdit", Color(1, 1, 1));
theme->set_color("selection_color", "CodeEdit", control_selection_color);
- theme->set_color("mark_color", "CodeEdit", Color(1.0, 0.4, 0.4, 0.4));
theme->set_color("bookmark_color", "CodeEdit", Color(0.5, 0.64, 1, 0.8));
theme->set_color("breakpoint_color", "CodeEdit", Color(0.9, 0.29, 0.3));
theme->set_color("executing_line_color", "CodeEdit", Color(0.98, 0.89, 0.27));
- theme->set_color("code_folding_color", "CodeEdit", Color(0.8, 0.8, 0.8, 0.8));
theme->set_color("current_line_color", "CodeEdit", Color(0.25, 0.25, 0.26, 0.8));
+ theme->set_color("code_folding_color", "CodeEdit", Color(0.8, 0.8, 0.8, 0.8));
theme->set_color("caret_color", "CodeEdit", control_font_color);
theme->set_color("caret_background_color", "CodeEdit", Color(0, 0, 0));
theme->set_color("brace_mismatch_color", "CodeEdit", Color(1, 0.2, 0.2));
@@ -756,6 +710,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("guide_color", "Tree", Color(0, 0, 0, 0.1));
theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2));
theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27));
+ theme->set_color("parent_hl_line_color", "Tree", Color(0.27, 0.27, 0.27));
+ theme->set_color("children_hl_line_color", "Tree", Color(0.27, 0.27, 0.27));
theme->set_color("custom_button_font_highlight", "Tree", control_font_hover_color);
theme->set_constant("hseparation", "Tree", 4 * scale);
@@ -763,6 +719,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("item_margin", "Tree", 12 * scale);
theme->set_constant("button_margin", "Tree", 4 * scale);
theme->set_constant("draw_relationship_lines", "Tree", 0);
+ theme->set_constant("relationship_line_width", "Tree", 1);
+ theme->set_constant("parent_hl_line_width", "Tree", 1);
+ theme->set_constant("children_hl_line_width", "Tree", 1);
+ theme->set_constant("parent_hl_line_margin", "Tree", 0);
theme->set_constant("draw_guides", "Tree", 1);
theme->set_constant("scroll_border", "Tree", 4);
theme->set_constant("scroll_speed", "Tree", 12);
@@ -830,7 +790,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("tab_selected", "Tabs", sb_expand(make_stylebox(tab_current_png, 4, 3, 4, 1, 16, 3, 16, 2), 2, 2, 2, 2));
theme->set_stylebox("tab_unselected", "Tabs", sb_expand(make_stylebox(tab_behind_png, 5, 4, 5, 1, 16, 5, 16, 2), 3, 3, 3, 3));
theme->set_stylebox("tab_disabled", "Tabs", sb_expand(make_stylebox(tab_disabled_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 3));
- theme->set_stylebox("panel", "Tabs", tc_sb);
theme->set_stylebox("button_pressed", "Tabs", make_stylebox(button_pressed_png, 4, 4, 4, 4));
theme->set_stylebox("button", "Tabs", make_stylebox(button_normal_png, 4, 4, 4, 4));
@@ -1025,18 +984,25 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) {
Ref<StyleBox> default_style;
Ref<Texture2D> default_icon;
Ref<Font> default_font;
- int default_font_size = 14;
+ int default_font_size = 16;
if (p_font.is_valid()) {
+ // Use the custom font defined in the Project Settings.
default_font = p_font;
- } else if (p_hidpi) {
- Ref<FontData> font_data = make_font(_hidpi_font_height, _hidpi_font_ascent, _hidpi_font_charcount, &_hidpi_font_charrects[0][0], _hidpi_font_kerning_pair_count, &_hidpi_font_kerning_pairs[0][0], _hidpi_font_img_width, _hidpi_font_img_height, _hidpi_font_img_data);
- default_font.instance();
- default_font->add_data(font_data);
} else {
- Ref<FontData> font_data = make_font(_lodpi_font_height, _lodpi_font_ascent, _lodpi_font_charcount, &_lodpi_font_charrects[0][0], _lodpi_font_kerning_pair_count, &_lodpi_font_kerning_pairs[0][0], _lodpi_font_img_width, _lodpi_font_img_height, _lodpi_font_img_data);
- default_font.instance();
- default_font->add_data(font_data);
+ // Use the default DynamicFont (separate from the editor font).
+ // The default DynamicFont is chosen to have a small file size since it's
+ // embedded in both editor and export template binaries.
+ Ref<Font> dynamic_font;
+ dynamic_font.instance();
+
+ Ref<FontData> dynamic_font_data;
+ dynamic_font_data.instance();
+ dynamic_font_data->load_memory(_font_OpenSans_SemiBold, _font_OpenSans_SemiBold_size, "ttf", default_font_size);
+ dynamic_font->add_data(dynamic_font_data);
+
+ default_font = dynamic_font;
}
+
Ref<Font> large_font = default_font;
fill_default_theme(t, default_font, large_font, default_icon, default_style, p_hidpi ? 2.0 : 1.0);
diff --git a/scene/resources/default_theme/default_theme_builders.py b/scene/resources/default_theme/default_theme_builders.py
new file mode 100644
index 0000000000..0455d6d246
--- /dev/null
+++ b/scene/resources/default_theme/default_theme_builders.py
@@ -0,0 +1,40 @@
+"""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
+import os.path
+from platform_methods import subprocess_main
+
+
+def make_fonts_header(target, source, env):
+ dst = target[0]
+
+ g = open(dst, "w", encoding="utf-8")
+
+ g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ g.write("#ifndef _DEFAULT_FONTS_H\n")
+ g.write("#define _DEFAULT_FONTS_H\n")
+
+ # Saving uncompressed, since FreeType will reference from memory pointer.
+ for i in range(len(source)):
+ with open(source[i], "rb") as f:
+ buf = f.read()
+
+ name = os.path.splitext(os.path.basename(source[i]))[0]
+
+ 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" + str(buf[j]) + ",\n")
+
+ g.write("};\n")
+
+ g.write("#endif")
+
+ g.close()
+
+
+if __name__ == "__main__":
+ subprocess_main(globals())
diff --git a/scene/resources/default_theme/ellipsis.png b/scene/resources/default_theme/ellipsis.png
new file mode 100644
index 0000000000..c949e2c95b
--- /dev/null
+++ b/scene/resources/default_theme/ellipsis.png
Binary files differ
diff --git a/scene/resources/default_theme/font_hidpi.inc b/scene/resources/default_theme/font_hidpi.inc
deleted file mode 100644
index 4860149e6b..0000000000
--- a/scene/resources/default_theme/font_hidpi.inc
+++ /dev/null
@@ -1,25463 +0,0 @@
-/* clang-format off */
-static const int _hidpi_font_height=25;
-static const int _hidpi_font_ascent=19;
-static const int _hidpi_font_charcount=191;
-static const int _hidpi_font_charrects[191][8]={
-/* charidx , ofs_x, ofs_y, size_x, size_y, valign, halign, advance */
-{192,63,23,16,23,-4,-1,15},
-{224,184,182,10,19,0,1,13},
-{64,98,2,18,19,2,1,21},
-{96,159,234,5,4,0,5,14},
-{160,0,0,0,0,19,0,6},
-{32,0,0,0,0,19,0,6},
-{33,2,249,3,17,2,2,6},
-{193,83,25,16,23,-4,-1,15},
-{225,92,160,10,19,0,1,13},
-{65,163,23,16,17,2,-1,15},
-{161,246,236,3,17,6,2,6},
-{97,142,190,10,13,6,1,13},
-{162,67,214,9,17,2,2,13},
-{98,242,136,11,18,1,2,14},
-{194,103,25,16,23,-4,-1,15},
-{226,106,160,10,19,0,1,13},
-{66,122,146,11,17,2,2,15},
-{34,226,203,8,6,2,1,10},
-{35,189,44,14,17,2,1,16},
-{163,62,166,11,17,2,1,13},
-{195,123,23,16,23,-4,-1,15},
-{227,134,167,10,19,0,1,13},
-{67,209,65,12,17,2,1,14},
-{99,225,186,9,13,6,1,11},
-{228,170,182,10,18,1,1,13},
-{100,227,143,11,18,1,1,14},
-{196,23,23,16,22,-3,-1,15},
-{36,2,179,10,20,1,2,13},
-{68,193,65,12,17,2,2,16},
-{164,176,65,13,12,5,0,13},
-{37,120,2,18,17,2,1,20},
-{69,41,222,9,17,2,2,13},
-{165,98,99,12,17,2,1,13},
-{197,43,23,16,21,-2,-1,15},
-{229,16,179,10,20,-1,1,13},
-{101,189,109,11,13,6,1,13},
-{38,183,23,16,17,2,1,17},
-{70,54,222,9,17,2,2,12},
-{198,75,2,19,17,2,-1,20},
-{102,202,212,8,18,1,1,8},
-{166,44,268,2,24,1,6,13},
-{230,142,2,18,13,6,1,20},
-{71,2,71,14,17,2,1,17},
-{167,176,160,10,18,1,0,12},
-{199,146,94,12,23,2,1,14},
-{103,159,67,13,19,6,0,13},
-{231,212,189,9,19,6,1,11},
-{39,30,271,3,6,2,1,5},
-{72,130,99,12,17,2,2,17},
-{104,162,160,10,18,1,2,14},
-{200,238,186,9,23,-4,2,13},
-{40,46,243,7,21,2,1,7},
-{232,2,156,11,19,0,1,13},
-{168,68,235,7,3,1,4,14},
-{73,106,209,8,17,2,0,9},
-{169,230,2,17,17,2,1,20},
-{105,222,232,4,18,1,1,6},
-{201,28,222,9,23,-4,2,13},
-{41,130,238,6,21,2,0,7},
-{233,197,126,11,19,0,1,13},
-{202,93,209,9,23,-4,2,13},
-{74,13,225,7,22,2,-2,7},
-{234,167,137,11,19,0,1,13},
-{42,82,120,12,11,1,0,13},
-{170,100,236,6,8,2,1,8},
-{106,110,237,6,24,1,-1,6},
-{171,144,121,11,10,8,0,12},
-{43,2,119,12,12,5,1,13},
-{203,80,209,9,22,-3,2,13},
-{107,32,177,11,18,1,2,12},
-{235,77,166,11,18,1,1,13},
-{75,74,77,13,17,2,2,14},
-{44,230,213,4,6,16,1,6},
-{172,204,109,11,7,10,1,13},
-{236,204,234,5,19,0,0,6},
-{204,130,211,8,23,-4,0,9},
-{108,23,271,3,18,1,2,6},
-{76,86,188,10,17,2,2,12},
-{173,140,238,6,2,12,1,8},
-{45,120,237,6,2,12,1,8},
-{109,208,2,18,13,6,2,22},
-{205,178,205,8,23,-4,0,9},
-{237,213,234,5,19,0,2,6},
-{77,143,19,16,17,2,2,21},
-{46,9,251,3,3,16,2,6},
-{110,100,183,10,13,6,2,14},
-{206,154,207,8,23,-4,0,9},
-{238,238,213,8,19,0,-1,6},
-{174,2,23,17,17,2,1,20},
-{78,91,78,13,17,2,2,18},
-{175,18,125,12,2,-1,0,12},
-{111,162,90,12,13,6,1,14},
-{207,118,211,8,22,-3,0,9},
-{239,24,249,7,18,1,0,6},
-{79,203,23,15,17,2,1,18},
-{47,120,167,10,17,2,-1,9},
-{176,166,207,8,8,2,1,10},
-{112,212,143,11,19,6,2,14},
-{240,18,103,12,18,1,1,14},
-{208,171,44,14,17,2,0,16},
-{80,128,190,10,17,2,2,14},
-{48,234,115,11,17,2,1,13},
-{177,66,127,12,14,5,1,13},
-{113,182,126,11,19,6,1,14},
-{241,30,199,10,19,0,2,14},
-{81,97,52,15,22,2,1,18},
-{209,142,67,13,23,-4,2,18},
-{49,57,243,7,17,2,2,13},
-{178,190,206,8,10,2,0,8},
-{114,142,207,8,13,6,2,10},
-{242,242,87,12,19,0,1,14},
-{210,59,50,15,23,-4,1,18},
-{82,82,99,12,17,2,2,14},
-{50,2,135,11,17,2,1,13},
-{179,35,249,7,10,2,0,8},
-{115,72,188,10,13,6,0,11},
-{243,226,92,12,19,0,1,14},
-{211,40,49,15,23,-4,1,18},
-{83,129,125,11,17,2,0,13},
-{51,17,135,11,17,2,1,13},
-{180,168,219,5,4,0,5,14},
-{116,214,212,8,16,3,0,8},
-{244,194,86,12,19,0,1,14},
-{212,21,49,15,23,-4,1,18},
-{84,66,106,12,17,2,0,13},
-{52,125,78,13,17,2,0,13},
-{53,32,156,11,17,2,1,13},
-{85,50,106,12,17,2,2,17},
-{181,204,166,10,19,6,2,14},
-{117,198,189,10,13,6,2,14},
-{245,178,86,12,19,0,1,14},
-{213,2,44,15,23,-4,1,18},
-{54,47,156,11,17,2,1,13},
-{86,222,23,15,17,2,-1,14},
-{246,241,65,12,18,1,1,14},
-{214,116,52,15,22,-3,1,18},
-{182,34,131,12,21,1,1,16},
-{118,135,50,14,13,6,-1,12},
-{55,62,145,11,17,2,1,13},
-{87,2,2,22,17,2,-1,21},
-{119,28,2,20,13,6,-1,18},
-{215,114,125,11,11,5,1,13},
-{247,210,92,12,10,6,0,13},
-{183,16,251,3,3,9,2,6},
-{56,77,145,11,17,2,1,13},
-{88,225,44,14,17,2,-1,13},
-{216,78,52,15,19,1,1,18},
-{248,98,120,12,15,5,1,14},
-{120,50,127,12,13,6,0,12},
-{184,150,234,5,6,19,0,5},
-{89,207,44,14,17,2,-1,13},
-{121,153,44,14,19,6,-1,12},
-{217,225,65,12,23,-4,2,17},
-{249,44,199,10,19,0,2,14},
-{57,92,139,11,17,2,1,13},
-{185,177,232,5,10,2,0,8},
-{218,2,92,12,23,-4,2,17},
-{250,156,184,10,19,0,2,14},
-{90,232,165,10,17,2,1,13},
-{122,148,167,10,13,6,1,11},
-{58,37,263,3,13,6,2,6},
-{186,90,236,6,8,2,1,8},
-{219,34,104,12,23,-4,2,17},
-{123,2,224,7,21,2,1,9},
-{91,186,232,5,21,2,2,7},
-{251,58,191,10,19,0,2,14},
-{59,238,236,4,16,6,1,6},
-{187,47,177,11,10,8,1,12},
-{188,164,2,18,17,2,0,18},
-{252,190,149,10,18,1,2,14},
-{124,50,268,2,24,1,6,13},
-{220,114,99,12,22,-3,2,17},
-{92,137,146,11,17,2,-1,9},
-{60,159,121,11,12,5,1,13},
-{189,186,2,18,17,2,0,18},
-{253,56,77,14,25,0,-1,12},
-{221,20,76,14,23,-4,-1,13},
-{125,79,235,7,21,2,1,9},
-{93,195,234,5,21,2,0,7},
-{61,152,137,11,6,8,1,13},
-{190,52,2,19,17,2,0,18},
-{222,114,188,10,17,2,2,14},
-{254,219,115,11,24,1,2,14},
-{62,174,109,11,12,5,1,13},
-{94,108,78,13,11,2,0,13},
-{126,107,140,11,5,8,1,13},
-{223,17,156,11,18,1,2,14},
-{191,15,203,9,18,6,0,10},
-{255,38,76,14,24,1,-1,12},
-{63,2,203,9,17,2,0,10},
-{95,218,166,10,2,21,0,10},
-};
-static const int _hidpi_font_kerning_pair_count=0;
-static const int _hidpi_font_kerning_pairs[1][3]={
-{0,0,0}
-};
-static const int _hidpi_font_img_width=256;
-static const int _hidpi_font_img_height=512;
-static const int _hidpi_font_img_data_size=25255;
-static const unsigned char _hidpi_font_img_data[25255]={
-137,
-80,
-78,
-71,
-13,
-10,
-26,
-10,
-0,
-0,
-0,
-13,
-73,
-72,
-68,
-82,
-0,
-0,
-1,
-0,
-0,
-0,
-2,
-0,
-8,
-6,
-0,
-0,
-0,
-109,
-154,
-178,
-251,
-0,
-0,
-32,
-0,
-73,
-68,
-65,
-84,
-120,
-156,
-236,
-157,
-119,
-184,
-38,
-53,
-245,
-199,
-51,
-84,
-165,
-55,
-1,
-21,
-16,
-41,
-34,
-42,
-130,
-98,
-23,
-1,
-21,
-20,
-84,
-108,
-40,
-138,
-138,
-10,
-34,
-40,
-86,
-148,
-159,
-216,
-11,
-34,
-138,
-130,
-162,
-40,
-32,
-160,
-128,
-160,
-2,
-162,
-32,
-162,
-34,
-34,
-29,
-145,
-142,
-235,
-210,
-219,
-210,
-151,
-14,
-219,
-251,
-231,
-247,
-199,
-57,
-97,
-114,
-231,
-205,
-204,
-100,
-102,
-50,
-239,
-189,
-119,
-111,
-190,
-207,
-179,
-207,
-221,
-55,
-57,
-57,
-147,
-153,
-73,
-206,
-36,
-39,
-167,
-24,
-147,
-144,
-144,
-144,
-144,
-144,
-144,
-48,
-129,
-1,
-172,
-75,
-142,
-45,
-74,
-104,
-158,
-231,
-208,
-188,
-176,
-132,
-230,
-85,
-14,
-205,
-58,
-158,
-250,
-245,
-156,
-250,
-103,
-121,
-234,
-95,
-237,
-212,
-239,
-225,
-169,
-95,
-25,
-88,
-160,
-245,
-235,
-122,
-234,
-55,
-5,
-78,
-0,
-238,
-5,
-230,
-2,
-83,
-128,
-95,
-2,
-107,
-149,
-244,
-119,
-105,
-224,
-22,
-224,
-65,
-96,
-37,
-31,
-77,
-8,
-128,
-143,
-211,
-0,
-129,
-60,
-215,
-1,
-190,
-8,
-156,
-15,
-220,
-13,
-204,
-1,
-30,
-7,
-38,
-1,
-63,
-3,
-182,
-12,
-228,
-243,
-33,
-224,
-102,
-109,
-255,
-63,
-224,
-109,
-21,
-180,
-235,
-3,
-179,
-244,
-249,
-173,
-88,
-195,
-119,
-109,
-224,
-43,
-192,
-101,
-192,
-19,
-250,
-188,
-239,
-5,
-126,
-3,
-108,
-160,
-52,
-27,
-0,
-191,
-7,
-30,
-86,
-190,
-215,
-0,
-159,
-0,
-150,
-168,
-224,
-187,
-42,
-112,
-172,
-62,
-170,
-211,
-42,
-232,
-26,
-189,
-187,
-62,
-248,
-42,
-175,
-235,
-244,
-255,
-239,
-211,
-103,
-49,
-67,
-223,
-211,
-133,
-246,
-89,
-3,
-75,
-0,
-159,
-5,
-174,
-211,
-231,
-240,
-36,
-240,
-79,
-224,
-117,
-117,
-253,
-214,
-246,
-43,
-105,
-251,
-127,
-1,
-143,
-0,
-243,
-245,
-239,
-185,
-192,
-103,
-234,
-222,
-85,
-16,
-128,
-27,
-244,
-134,
-246,
-45,
-169,
-255,
-164,
-51,
-134,
-247,
-41,
-161,
-249,
-138,
-214,
-79,
-174,
-184,
-206,
-205,
-74,
-243,
-126,
-79,
-221,
-33,
-206,
-53,
-78,
-247,
-212,
-239,
-164,
-117,
-55,
-150,
-240,
-254,
-43,
-48,
-93,
-7,
-225,
-87,
-129,
-95,
-1,
-139,
-128,
-127,
-149,
-208,
-127,
-65,
-249,
-125,
-188,
-172,
-191,
-33,
-0,
-174,
-5,
-22,
-2,
-151,
-56,
-253,
-191,
-86,
-127,
-15,
-252,
-171,
-225,
-245,
-52,
-224,
-251,
-192,
-108,
-229,
-115,
-43,
-112,
-6,
-112,
-52,
-112,
-18,
-112,
-149,
-94,
-11,
-224,
-52,
-96,
-149,
-10,
-94,
-175,
-215,
-251,
-183,
-130,
-240,
-126,
-29,
-60,
-94,
-225,
-1,
-156,
-165,
-124,
-119,
-14,
-184,
-231,
-43,
-149,
-118,
-1,
-112,
-35,
-112,
-5,
-50,
-209,
-1,
-30,
-211,
-107,
-63,
-166,
-191,
-239,
-214,
-241,
-101,
-251,
-125,
-98,
-9,
-207,
-247,
-2,
-83,
-129,
-187,
-128,
-153,
-84,
-79,
-212,
-224,
-119,
-215,
-35,
-95,
-144,
-9,
-253,
-85,
-253,
-255,
-125,
-250,
-126,
-158,
-212,
-223,
-139,
-128,
-157,
-245,
-61,
-161,
-215,
-191,
-70,
-251,
-128,
-190,
-139,
-87,
-215,
-92,
-99,
-39,
-224,
-81,
-100,
-194,
-31,
-13,
-236,
-14,
-188,
-93,
-255,
-30,
-173,
-229,
-143,
-80,
-33,
-216,
-131,
-0,
-28,
-166,
-157,
-250,
-75,
-73,
-253,
-105,
-136,
-148,
-159,
-11,
-156,
-82,
-66,
-115,
-142,
-242,
-56,
-164,
-226,
-58,
-63,
-87,
-154,
-35,
-60,
-117,
-183,
-235,
-96,
-189,
-18,
-145,
-164,
-79,
-43,
-212,
-31,
-170,
-109,
-127,
-90,
-194,
-123,
-85,
-96,
-181,
-66,
-217,
-121,
-192,
-116,
-15,
-237,
-26,
-136,
-164,
-254,
-47,
-21,
-95,
-164,
-58,
-0,
-175,
-209,
-62,
-253,
-85,
-127,
-91,
-120,
-87,
-82,
-53,
-188,
-214,
-0,
-254,
-173,
-237,
-79,
-1,
-94,
-80,
-66,
-183,
-46,
-240,
-107,
-165,
-187,
-17,
-88,
-181,
-132,
-238,
-79,
-74,
-179,
-137,
-254,
-126,
-169,
-254,
-62,
-201,
-67,
-251,
-110,
-247,
-62,
-2,
-250,
-250,
-38,
-224,
-115,
-238,
-243,
-70,
-190,
-158,
-71,
-58,
-131,
-127,
-33,
-176,
-139,
-83,
-255,
-34,
-100,
-34,
-2,
-188,
-215,
-195,
-243,
-64,
-224,
-183,
-192,
-234,
-84,
-76,
-212,
-166,
-239,
-174,
-71,
-190,
-22,
-243,
-129,
-15,
-58,
-229,
-203,
-33,
-31,
-35,
-128,
-121,
-200,
-234,
-235,
-237,
-133,
-235,
-92,
-163,
-245,
-103,
-84,
-240,
-255,
-178,
-62,
-195,
-31,
-0,
-43,
-148,
-208,
-172,
-0,
-28,
-172,
-116,
-95,
-174,
-235,
-115,
-213,
-205,
-236,
-168,
-29,
-122,
-18,
-88,
-178,
-80,
-183,
-4,
-34,
-133,
-174,
-212,
-127,
-15,
-120,
-218,
-47,
-67,
-46,
-217,
-182,
-171,
-184,
-206,
-59,
-148,
-102,
-114,
-161,
-124,
-11,
-45,
-63,
-94,
-111,
-24,
-224,
-45,
-5,
-154,
-171,
-181,
-188,
-86,
-218,
-33,
-95,
-210,
-215,
-35,
-203,
-211,
-223,
-122,
-234,
-127,
-161,
-188,
-222,
-80,
-199,
-171,
-230,
-58,
-191,
-85,
-62,
-239,
-208,
-223,
-22,
-141,
-4,
-0,
-176,
-20,
-178,
-66,
-152,
-15,
-236,
-22,
-216,
-102,
-95,
-189,
-214,
-159,
-75,
-234,
-239,
-5,
-110,
-45,
-148,
-221,
-9,
-220,
-89,
-40,
-91,
-1,
-184,
-7,
-249,
-154,
-61,
-183,
-73,
-191,
-61,
-215,
-92,
-203,
-121,
-6,
-199,
-121,
-234,
-247,
-215,
-186,
-127,
-212,
-240,
-129,
-242,
-137,
-218,
-250,
-221,
-197,
-228,
-235,
-220,
-231,
-209,
-158,
-186,
-45,
-156,
-250,
-67,
-61,
-245,
-239,
-209,
-186,
-7,
-75,
-120,
-239,
-132,
-76,
-234,
-93,
-245,
-247,
-18,
-192,
-222,
-200,
-252,
-155,
-137,
-204,
-199,
-75,
-128,
-79,
-107,
-253,
-110,
-74,
-223,
-110,
-37,
-128,
-72,
-173,
-57,
-218,
-169,
-87,
-20,
-234,
-236,
-151,
-227,
-112,
-231,
-33,
-109,
-82,
-160,
-217,
-74,
-203,
-103,
-0,
-203,
-86,
-92,
-103,
-37,
-29,
-228,
-139,
-128,
-213,
-157,
-242,
-3,
-180,
-253,
-135,
-145,
-175,
-11,
-192,
-145,
-78,
-253,
-202,
-122,
-131,
-243,
-40,
-145,
-134,
-14,
-173,
-139,
-127,
-22,
-251,
-3,
-188,
-0,
-89,
-186,
-122,
-39,
-78,
-40,
-128,
-103,
-32,
-43,
-162,
-251,
-80,
-161,
-233,
-92,
-183,
-169,
-0,
-248,
-134,
-182,
-251,
-124,
-195,
-118,
-118,
-121,
-249,
-90,
-79,
-221,
-60,
-224,
-226,
-66,
-217,
-165,
-192,
-220,
-66,
-217,
-143,
-149,
-199,
-87,
-155,
-92,
-187,
-162,
-79,
-115,
-149,
-223,
-174,
-158,
-186,
-55,
-106,
-221,
-35,
-53,
-60,
-192,
-51,
-81,
-187,
-190,
-187,
-152,
-124,
-157,
-119,
-61,
-48,
-233,
-128,
-167,
-59,
-245,
-59,
-120,
-234,
-55,
-211,
-186,
-5,
-37,
-109,
-31,
-6,
-14,
-114,
-202,
-78,
-82,
-250,
-169,
-250,
-255,
-211,
-149,
-230,
-215,
-14,
-205,
-193,
-200,
-118,
-160,
-157,
-78,
-0,
-81,
-42,
-0,
-236,
-95,
-40,
-255,
-63,
-251,
-66,
-129,
-15,
-234,
-255,
-247,
-46,
-208,
-216,
-1,
-124,
-86,
-192,
-117,
-46,
-85,
-218,
-119,
-56,
-101,
-215,
-35,
-66,
-97,
-45,
-125,
-0,
-179,
-129,
-123,
-157,
-122,
-187,
-255,
-191,
-48,
-128,
-255,
-14,
-200,
-222,
-235,
-8,
-109,
-115,
-80,
-161,
-254,
-108,
-100,
-114,
-108,
-92,
-199,
-171,
-230,
-58,
-86,
-231,
-241,
-93,
-167,
-204,
-34,
-88,
-0,
-32,
-66,
-241,
-9,
-100,
-133,
-147,
-57,
-229,
-203,
-34,
-203,
-192,
-201,
-136,
-112,
-158,
-141,
-124,
-193,
-207,
-36,
-95,
-214,
-219,
-47,
-141,
-111,
-75,
-53,
-157,
-130,
-206,
-1,
-217,
-98,
-76,
-115,
-126,
-111,
-142,
-12,
-252,
-27,
-128,
-165,
-27,
-244,
-121,
-73,
-68,
-241,
-117,
-18,
-162,
-220,
-186,
-31,
-152,
-166,
-207,
-53,
-4,
-11,
-107,
-248,
-131,
-127,
-162,
-118,
-122,
-119,
-49,
-249,
-58,
-247,
-178,
-89,
-77,
-253,
-139,
-61,
-117,
-27,
-217,
-74,
-79,
-221,
-199,
-16,
-37,
-228,
-242,
-250,
-251,
-189,
-74,
-122,
-5,
-35,
-63,
-154,
-203,
-0,
-43,
-59,
-191,
-87,
-64,
-4,
-192,
-103,
-66,
-239,
-161,
-120,
-97,
-59,
-209,
-255,
-81,
-40,
-63,
-91,
-203,
-159,
-173,
-255,
-0,
-126,
-87,
-160,
-57,
-79,
-203,
-63,
-29,
-112,
-157,
-111,
-43,
-237,
-161,
-250,
-219,
-158,
-48,
-92,
-234,
-208,
-252,
-93,
-203,
-94,
-170,
-191,
-237,
-254,
-255,
-107,
-13,
-239,
-233,
-66,
-224,
-9,
-231,
-183,
-221,
-234,
-252,
-184,
-9,
-31,
-15,
-223,
-37,
-16,
-125,
-197,
-66,
-224,
-57,
-78,
-185,
-69,
-19,
-1,
-176,
-151,
-182,
-249,
-136,
-83,
-182,
-52,
-114,
-2,
-0,
-162,
-80,
-60,
-4,
-89,
-129,
-221,
-173,
-101,
-175,
-117,
-104,
-239,
-3,
-174,
-247,
-240,
-189,
-137,
-193,
-45,
-192,
-20,
-84,
-137,
-10,
-100,
-228,
-58,
-135,
-109,
-27,
-244,
-119,
-13,
-70,
-42,
-1,
-255,
-131,
-40,
-94,
-127,
-10,
-28,
-228,
-60,
-131,
-235,
-40,
-81,
-132,
-82,
-175,
-12,
-133,
-194,
-68,
-141,
-241,
-238,
-98,
-242,
-117,
-238,
-115,
-163,
-166,
-245,
-84,
-11,
-128,
-243,
-25,
-185,
-250,
-253,
-135,
-146,
-110,
-19,
-208,
-167,
-163,
-129,
-115,
-155,
-220,
-135,
-219,
-120,
-115,
-189,
-208,
-12,
-244,
-107,
-64,
-190,
-183,
-191,
-201,
-161,
-187,
-13,
-184,
-207,
-249,
-189,
-44,
-185,
-214,
-218,
-251,
-48,
-10,
-215,
-121,
-173,
-210,
-94,
-166,
-191,
-191,
-172,
-191,
-247,
-115,
-104,
-62,
-165,
-101,
-223,
-208,
-223,
-118,
-192,
-189,
-162,
-130,
-239,
-42,
-133,
-223,
-75,
-34,
-95,
-182,
-71,
-244,
-247,
-82,
-246,
-183,
-75,
-11,
-124,
-196,
-55,
-48,
-106,
-238,
-225,
-237,
-218,
-230,
-239,
-133,
-242,
-90,
-120,
-120,
-157,
-170,
-85,
-207,
-112,
-202,
-172,
-48,
-62,
-13,
-88,
-202,
-41,
-63,
-89,
-203,
-95,
-228,
-148,
-93,
-12,
-60,
-238,
-225,
-251,
-59,
-165,
-45,
-42,
-1,
-79,
-214,
-223,
-123,
-235,
-239,
-19,
-244,
-119,
-208,
-145,
-33,
-162,
-167,
-1,
-81,
-150,
-61,
-167,
-80,
-151,
-57,
-183,
-218,
-90,
-191,
-82,
-124,
-31,
-177,
-222,
-93,
-13,
-223,
-117,
-17,
-1,
-118,
-135,
-62,
-131,
-59,
-145,
-15,
-79,
-153,
-2,
-206,
-34,
-182,
-0,
-120,
-20,
-248,
-168,
-243,
-219,
-30,
-253,
-45,
-89,
-164,
-245,
-180,
-221,
-157,
-154,
-237,
-85,
-85,
-227,
-12,
-120,
-64,
-251,
-181,
-149,
-150,
-109,
-173,
-191,
-143,
-112,
-232,
-236,
-121,
-234,
-70,
-250,
-123,
-91,
-253,
-125,
-91,
-224,
-117,
-150,
-66,
-148,
-141,
-115,
-144,
-47,
-157,
-61,
-62,
-219,
-208,
-161,
-89,
-95,
-203,
-46,
-66,
-20,
-122,
-243,
-245,
-193,
-84,
-157,
-33,
-207,
-65,
-142,
-204,
-190,
-11,
-124,
-29,
-153,
-24,
-0,
-7,
-107,
-253,
-167,
-245,
-247,
-167,
-156,
-54,
-175,
-64,
-246,
-85,
-115,
-66,
-7,
-145,
-182,
-179,
-171,
-162,
-119,
-21,
-202,
-45,
-130,
-143,
-1,
-145,
-163,
-190,
-187,
-10,
-101,
-147,
-148,
-207,
-250,
-37,
-215,
-93,
-199,
-41,
-59,
-135,
-194,
-190,
-94,
-203,
-95,
-137,
-124,
-161,
-167,
-144,
-31,
-3,
-46,
-68,
-236,
-45,
-158,
-129,
-28,
-211,
-61,
-166,
-255,
-15,
-62,
-50,
-212,
-247,
-0,
-126,
-77,
-254,
-218,
-206,
-51,
-104,
-183,
-20,
-53,
-222,
-137,
-26,
-229,
-221,
-85,
-241,
-5,
-254,
-172,
-207,
-224,
-12,
-228,
-163,
-100,
-79,
-90,
-6,
-148,
-200,
-14,
-47,
-136,
-47,
-0,
-22,
-48,
-242,
-212,
-96,
-62,
-30,
-197,
-123,
-201,
-53,
-223,
-14,
-204,
-15,
-161,
-45,
-99,
-240,
-27,
-237,
-151,
-253,
-242,
-126,
-71,
-127,
-191,
-199,
-161,
-249,
-144,
-150,
-125,
-76,
-127,
-219,
-37,
-253,
-207,
-27,
-92,
-231,
-207,
-218,
-230,
-213,
-200,
-222,
-107,
-146,
-135,
-102,
-178,
-214,
-109,
-163,
-180,
-127,
-168,
-225,
-121,
-16,
-114,
-44,
-54,
-83,
-7,
-197,
-100,
-196,
-152,
-102,
-73,
-228,
-136,
-240,
-17,
-68,
-215,
-176,
-148,
-210,
-175,
-141,
-104,
-202,
-247,
-68,
-20,
-87,
-161,
-131,
-104,
-35,
-29,
-40,
-247,
-227,
-124,
-157,
-181,
-206,
-162,
-201,
-22,
-224,
-73,
-224,
-170,
-66,
-217,
-108,
-224,
-81,
-15,
-237,
-85,
-202,
-127,
-69,
-167,
-236,
-106,
-28,
-125,
-73,
-129,
-254,
-29,
-200,
-23,
-110,
-174,
-254,
-221,
-89,
-203,
-237,
-123,
-222,
-75,
-127,
-255,
-81,
-127,
-23,
-87,
-11,
-3,
-103,
-246,
-228,
-202,
-226,
-55,
-122,
-234,
-236,
-106,
-14,
-224,
-114,
-28,
-157,
-70,
-19,
-104,
-251,
-211,
-244,
-255,
-49,
-223,
-93,
-41,
-95,
-96,
-53,
-224,
-85,
-5,
-250,
-243,
-128,
-89,
-21,
-188,
-160,
-255,
-21,
-192,
-195,
-200,
-60,
-8,
-57,
-154,
-108,
-191,
-2,
-80,
-6,
-86,
-201,
-247,
-47,
-253,
-125,
-1,
-131,
-26,
-251,
-117,
-148,
-230,
-4,
-135,
-6,
-26,
-28,
-65,
-144,
-75,
-222,
-163,
-245,
-239,
-119,
-60,
-52,
-7,
-219,
-235,
-232,
-223,
-214,
-6,
-59,
-192,
-79,
-148,
-199,
-14,
-250,
-123,
-25,
-68,
-25,
-249,
-91,
-253,
-253,
-212,
-192,
-8,
-224,
-101,
-245,
-17,
-85,
-104,
-34,
-0,
-230,
-1,
-255,
-46,
-148,
-61,
-12,
-60,
-89,
-40,
-179,
-43,
-39,
-236,
-96,
-32,
-63,
-189,
-105,
-162,
-189,
-182,
-43,
-182,
-127,
-163,
-19,
-20,
-255,
-145,
-225,
-20,
-10,
-71,
-134,
-90,
-110,
-183,
-99,
-167,
-0,
-203,
-104,
-89,
-134,
-28,
-69,
-205,
-70,
-116,
-2,
-183,
-43,
-205,
-177,
-192,
-154,
-78,
-219,
-117,
-16,
-163,
-178,
-183,
-54,
-232,
-111,
-180,
-119,
-87,
-197,
-183,
-132,
-230,
-122,
-60,
-31,
-39,
-231,
-186,
-16,
-95,
-0,
-92,
-200,
-72,
-29,
-128,
-213,
-135,
-189,
-38,
-224,
-158,
-142,
-166,
-196,
-240,
-45,
-8,
-192,
-154,
-200,
-132,
-159,
-142,
-44,
-207,
-103,
-162,
-230,
-142,
-5,
-186,
-219,
-144,
-189,
-210,
-82,
-250,
-210,
-231,
-160,
-90,
-203,
-192,
-235,
-108,
-162,
-55,
-53,
-189,
-108,
-194,
-0,
-175,
-211,
-186,
-25,
-250,
-119,
-253,
-150,
-247,
-180,
-49,
-50,
-201,
-254,
-238,
-148,
-253,
-18,
-217,
-195,
-46,
-167,
-191,
-131,
-6,
-17,
-114,
-66,
-241,
-168,
-62,
-35,
-223,
-18,
-223,
-162,
-137,
-0,
-152,
-138,
-163,
-99,
-209,
-178,
-127,
-41,
-159,
-173,
-156,
-178,
-143,
-146,
-91,
-211,
-109,
-168,
-101,
-86,
-87,
-50,
-112,
-228,
-86,
-114,
-173,
-101,
-144,
-85,
-210,
-124,
-28,
-237,
-180,
-62,
-31,
-223,
-137,
-129,
-111,
-107,
-177,
-141,
-211,
-143,
-135,
-145,
-21,
-136,
-181,
-250,
-187,
-9,
-153,
-228,
-47,
-39,
-223,
-42,
-44,
-210,
-255,
-91,
-59,
-17,
-8,
-80,
-22,
-235,
-181,
-162,
-189,
-187,
-58,
-190,
-30,
-154,
-207,
-107,
-223,
-119,
-42,
-169,
-183,
-136,
-45,
-0,
-246,
-98,
-228,
-41,
-128,
-181,
-25,
-248,
-15,
-176,
-70,
-129,
-118,
-25,
-231,
-255,
-246,
-20,
-224,
-115,
-229,
-119,
-30,
-0,
-114,
-43,
-165,
-119,
-234,
-95,
-159,
-33,
-131,
-213,
-3,
-216,
-115,
-221,
-198,
-154,
-71,
-114,
-141,
-246,
-192,
-87,
-70,
-235,
-151,
-116,
-6,
-214,
-45,
-109,
-238,
-69,
-249,
-156,
-137,
-12,
-248,
-23,
-232,
-239,
-79,
-40,
-223,
-13,
-28,
-154,
-160,
-65,
-4,
-236,
-81,
-117,
-191,
-206,
-75,
-111,
-34,
-0,
-46,
-213,
-254,
-173,
-224,
-148,
-189,
-81,
-7,
-223,
-147,
-136,
-117,
-221,
-73,
-58,
-96,
-63,
-141,
-28,
-25,
-94,
-139,
-216,
-100,
-204,
-210,
-246,
-75,
-85,
-93,
-195,
-225,
-251,
-53,
-223,
-59,
-37,
-224,
-200,
-176,
-80,
-183,
-53,
-114,
-108,
-252,
-48,
-50,
-177,
-111,
-68,
-108,
-57,
-220,
-99,
-169,
-231,
-32,
-71,
-177,
-119,
-34,
-203,
-244,
-25,
-218,
-239,
-131,
-128,
-181,
-3,
-251,
-27,
-237,
-221,
-85,
-241,
-245,
-212,
-127,
-82,
-235,
-247,
-172,
-224,
-97,
-17,
-91,
-0,
-44,
-135,
-8,
-204,
-239,
-57,
-101,
-118,
-203,
-246,
-16,
-162,
-8,
-62,
-22,
-177,
-113,
-113,
-143,
-116,
-127,
-160,
-207,
-102,
-229,
-34,
-207,
-70,
-64,
-108,
-209,
-33,
-215,
-56,
-15,
-44,
-215,
-200,
-245,
-0,
-182,
-99,
-251,
-249,
-120,
-141,
-54,
-200,
-5,
-212,
-207,
-157,
-178,
-186,
-179,
-234,
-245,
-43,
-248,
-217,
-229,
-239,
-46,
-37,
-245,
-22,
-77,
-4,
-192,
-129,
-218,
-230,
-125,
-133,
-242,
-183,
-34,
-75,
-208,
-185,
-136,
-118,
-126,
-119,
-45,
-223,
-17,
-89,
-98,
-63,
-170,
-207,
-127,
-117,
-63,
-231,
-129,
-235,
-108,
-128,
-8,
-140,
-187,
-41,
-104,
-182,
-41,
-63,
-50,
-108,
-45,
-120,
-187,
-34,
-246,
-187,
-171,
-226,
-91,
-168,
-255,
-54,
-34,
-120,
-223,
-226,
-171,
-31,
-6,
-128,
-119,
-225,
-152,
-82,
-35,
-91,
-172,
-61,
-80,
-161,
-140,
-163,
-220,
-213,
-250,
-15,
-40,
-253,
-59,
-99,
-92,
-252,
-245,
-250,
-128,
-158,
-64,
-164,
-224,
-128,
-101,
-17,
-185,
-30,
-224,
-113,
-253,
-251,
-34,
-31,
-175,
-209,
-4,
-178,
-130,
-248,
-175,
-246,
-209,
-213,
-97,
-124,
-222,
-243,
-15,
-228,
-220,
-250,
-243,
-148,
-120,
-129,
-33,
-90,
-103,
-144,
-229,
-153,
-215,
-104,
-198,
-25,
-136,
-77,
-4,
-192,
-198,
-250,
-66,
-175,
-43,
-227,
-27,
-3,
-192,
-223,
-180,
-111,
-239,
-242,
-212,
-149,
-29,
-25,
-54,
-222,
-91,
-199,
-64,
-236,
-119,
-87,
-199,
-215,
-169,
-251,
-37,
-34,
-12,
-159,
-223,
-215,
-189,
-133,
-2,
-57,
-201,
-90,
-8,
-124,
-143,
-146,
-237,
-53,
-176,
-60,
-242,
-193,
-94,
-8,
-124,
-61,
-214,
-133,
-151,
-33,
-223,
-119,
-95,
-86,
-65,
-119,
-155,
-210,
-220,
-19,
-229,
-194,
-145,
-65,
-110,
-96,
-227,
-245,
-112,
-44,
-208,
-214,
-14,
-118,
-114,
-101,
-228,
-193,
-53,
-124,
-160,
-161,
-55,
-32,
-185,
-213,
-226,
-81,
-116,
-112,
-78,
-170,
-232,
-151,
-221,
-71,
-122,
-45,
-53,
-41,
-63,
-50,
-12,
-114,
-89,
-141,
-141,
-216,
-239,
-46,
-132,
-47,
-114,
-252,
-55,
-19,
-248,
-166,
-71,
-200,
-120,
-173,
-253,
-250,
-6,
-178,
-18,
-120,
-28,
-249,
-232,
-28,
-137,
-232,
-129,
-222,
-174,
-127,
-143,
-212,
-242,
-199,
-136,
-241,
-229,
-47,
-92,
-248,
-47,
-250,
-160,
-190,
-87,
-65,
-99,
-245,
-0,
-199,
-70,
-189,
-120,
-4,
-32,
-230,
-181,
-15,
-34,
-190,
-221,
-181,
-95,
-213,
-186,
-65,
-132,
-120,
-146,
-205,
-70,
-246,
-229,
-165,
-198,
-78,
-4,
-160,
-164,
-221,
-178,
-228,
-74,
-196,
-243,
-241,
-216,
-246,
-59,
-180,
-27,
-0,
-95,
-168,
-187,
-39,
-135,
-126,
-69,
-68,
-203,
-63,
-139,
-234,
-237,
-205,
-187,
-144,
-189,
-252,
-92,
-253,
-235,
-221,
-230,
-244,
-141,
-216,
-239,
-46,
-148,
-111,
-205,
-107,
-251,
-68,
-219,
-251,
-233,
-10,
-96,
-21,
-228,
-56,
-251,
-2,
-100,
-219,
-183,
-64,
-255,
-94,
-128,
-184,
-47,
-119,
-219,
-243,
-39,
-140,
-13,
-168,
-16,
-248,
-57,
-178,
-237,
-2,
-57,
-29,
-248,
-27,
-112,
-34,
-162,
-4,
-252,
-7,
-98,
-246,
-91,
-42,
-72,
-134,
-216,
-87,
-23,
-63,
-11,
-160,
-255,
-180,
-219,
-96,
-24,
-125,
-76,
-72,
-24,
-151,
-0,
-158,
-139,
-24,
-96,
-93,
-128,
-44,
-197,
-231,
-32,
-202,
-175,
-135,
-16,
-37,
-208,
-143,
-40,
-24,
-172,
-140,
-66,
-31,
-93,
-220,
-75,
-141,
-193,
-15,
-35,
-143,
-72,
-147,
-0,
-72,
-72,
-24,
-207,
-208,
-121,
-188,
-8,
-177,
-182,
-132,
-10,
-35,
-21,
-68,
-97,
-188,
-8,
-81,
-212,
-37,
-1,
-48,
-70,
-16,
-93,
-209,
-148,
-48,
-225,
-144,
-25,
-99,
-206,
-214,
-255,
-191,
-167,
-130,
-238,
-125,
-74,
-219,
-41,
-254,
-66,
-194,
-144,
-64,
-79,
-65,
-8,
-17,
-207,
-182,
-219,
-172,
-210,
-2,
-177,
-197,
-190,
-3,
-245,
-78,
-107,
-201,
-115,
-51,
-196,
-230,
-124,
-134,
-46,
-153,
-91,
-251,
-248,
-147,
-219,
-217,
-79,
-199,
-241,
-204,
-155,
-104,
-32,
-204,
-235,
-204,
-194,
-6,
-111,
-185,
-171,
-130,
-246,
-74,
-29,
-67,
-79,
-5,
-141,
-109,
-208,
-151,
-23,
-58,
-215,
-218,
-60,
-180,
-93,
-129,
-199,
-43,
-16,
-95,
-135,
-169,
-228,
-78,
-101,
-127,
-35,
-192,
-189,
-182,
-132,
-223,
-106,
-72,
-28,
-192,
-75,
-17,
-165,
-226,
-60,
-253,
-123,
-9,
-240,
-37,
-234,
-143,
-34,
-215,
-38,
-183,
-164,
-172,
-220,
-202,
-57,
-207,
-108,
-33,
-129,
-198,
-83,
-157,
-64,
-143,
-65,
-8,
-201,
-157,
-72,
-94,
-171,
-191,
-109,
-20,
-161,
-217,
-29,
-250,
-123,
-57,
-162,
-28,
-219,
-6,
-241,
-138,
-187,
-168,
-3,
-175,
-231,
-234,
-139,
-4,
-79,
-128,
-141,
-197,
-9,
-58,
-8,
-207,
-67,
-142,
-152,
-78,
-67,
-237,
-22,
-16,
-123,
-254,
-251,
-2,
-218,
-91,
-108,
-130,
-24,
-43,
-129,
-199,
-85,
-27,
-57,
-177,
-0,
-241,
-98,
-124,
-81,
-11,
-1,
-240,
-67,
-231,
-90,
-3,
-22,
-169,
-1,
-237,
-183,
-39,
-87,
-170,
-62,
-138,
-152,
-45,
-91,
-19,
-229,
-133,
-148,
-152,
-249,
-86,
-240,
-123,
-55,
-185,
-237,
-11,
-136,
-149,
-227,
-21,
-228,
-71,
-226,
-232,
-24,
-26,
-112,
-148,
-42,
-240,
-185,
-64,
-105,
-75,
-143,
-148,
-149,
-206,
-250,
-195,
-92,
-208,
-164,
-159,
-173,
-64,
-207,
-65,
-8,
-25,
-92,
-1,
-172,
-130,
-172,
-0,
-188,
-65,
-70,
-3,
-121,
-206,
-68,
-221,
-82,
-129,
-93,
-240,
-4,
-0,
-109,
-200,
-111,
-75,
-196,
-0,
-106,
-33,
-240,
-242,
-46,
-188,
-10,
-124,
-215,
-36,
-183,
-173,
-184,
-162,
-3,
-31,
-87,
-155,
-30,
-100,
-79,
-95,
-194,
-231,
-56,
-228,
-88,
-112,
-50,
-178,
-63,
-183,
-251,
-249,
-89,
-192,
-49,
-1,
-237,
-45,
-54,
-35,
-247,
-24,
-253,
-145,
-135,
-206,
-70,
-204,
-253,
-8,
-121,
-188,
-137,
-208,
-208,
-232,
-75,
-34,
-167,
-30,
-211,
-244,
-223,
-3,
-4,
-172,
-78,
-10,
-60,
-236,
-170,
-238,
-120,
-52,
-52,
-28,
-114,
-218,
-98,
-45,
-88,
-7,
-252,
-92,
-42,
-120,
-237,
-72,
-30,
-150,
-254,
-116,
-10,
-199,
-193,
-136,
-233,
-243,
-239,
-181,
-126,
-14,
-21,
-95,
-119,
-114,
-31,
-142,
-74,
-75,
-75,
-228,
-200,
-18,
-28,
-55,
-232,
-94,
-192,
-96,
-16,
-66,
-23,
-179,
-16,
-5,
-206,
-103,
-28,
-250,
-110,
-65,
-8,
-35,
-1,
-89,
-94,
-158,
-133,
-216,
-166,
-159,
-67,
-64,
-200,
-176,
-0,
-158,
-91,
-234,
-96,
-187,
-33,
-70,
-31,
-149,
-231,
-81,
-250,
-44,
-31,
-160,
-16,
-68,
-163,
-1,
-143,
-23,
-33,
-66,
-196,
-78,
-136,
-25,
-148,
-216,
-178,
-7,
-240,
-154,
-10,
-124,
-64,
-255,
-255,
-98,
-68,
-56,
-63,
-137,
-172,
-10,
-188,
-121,
-20,
-10,
-237,
-45,
-182,
-32,
-143,
-111,
-119,
-135,
-135,
-110,
-146,
-78,
-134,
-149,
-112,
-2,
-101,
-6,
-246,
-241,
-205,
-74,
-126,
-166,
-254,
-3,
-216,
-177,
-225,
-125,
-218,
-85,
-231,
-75,
-10,
-229,
-91,
-218,
-137,
-26,
-200,
-231,
-105,
-200,
-105,
-7,
-72,
-0,
-151,
-210,
-83,
-15,
-228,
-216,
-22,
-196,
-124,
-219,
-43,
-176,
-24,
-185,
-13,
-240,
-90,
-209,
-146,
-111,
-127,
-250,
-93,
-254,
-227,
-15,
-66,
-8,
-178,
-23,
-62,
-10,
-248,
-3,
-185,
-27,
-234,
-199,
-28,
-154,
-110,
-65,
-8,
-35,
-0,
-177,
-129,
-182,
-152,
-6,
-60,
-111,
-180,
-250,
-82,
-6,
-196,
-51,
-110,
-33,
-178,
-116,
-108,
-28,
-46,
-92,
-121,
-172,
-133,
-44,
-55,
-167,
-33,
-49,
-20,
-94,
-167,
-2,
-224,
-142,
-144,
-9,
-235,
-225,
-23,
-228,
-60,
-84,
-209,
-254,
-41,
-1,
-160,
-191,
-109,
-190,
-135,
-45,
-29,
-154,
-77,
-181,
-236,
-116,
-253,
-221,
-84,
-0,
-216,
-136,
-203,
-123,
-34,
-113,
-242,
-0,
-126,
-223,
-176,
-159,
-214,
-225,
-236,
-205,
-133,
-114,
-203,
-47,
-200,
-215,
-129,
-220,
-77,
-126,
-54,
-142,
-123,
-115,
-9,
-173,
-13,
-63,
-14,
-78,
-220,
-75,
-15,
-221,
-133,
-74,
-243,
-141,
-146,
-250,
-175,
-107,
-125,
-231,
-143,
-90,
-37,
-40,
-4,
-33,
-212,
-50,
-128,
-41,
-206,
-239,
-151,
-105,
-217,
-121,
-78,
-89,
-227,
-32,
-132,
-68,
-80,
-234,
-20,
-248,
-117,
-218,
-35,
-14,
-3,
-136,
-85,
-221,
-84,
-2,
-179,
-249,
-148,
-240,
-184,
-10,
-49,
-211,
-117,
-93,
-120,
-95,
-138,
-36,
-155,
-184,
-170,
-170,
-109,
-31,
-240,
-8,
-0,
-235,
-208,
-244,
-125,
-135,
-198,
-110,
-13,
-172,
-67,
-75,
-176,
-0,
-64,
-172,
-23,
-103,
-34,
-75,
-238,
-103,
-32,
-138,
-183,
-121,
-200,
-106,
-52,
-56,
-139,
-19,
-121,
-20,
-235,
-243,
-200,
-99,
-31,
-108,
-71,
-190,
-143,
-31,
-240,
-139,
-40,
-225,
-99,
-151,
-246,
-65,
-39,
-25,
-228,
-1,
-86,
-142,
-175,
-160,
-177,
-219,
-185,
-107,
-75,
-234,
-109,
-24,
-252,
-214,
-91,
-189,
-32,
-80,
-8,
-66,
-168,
-101,
-69,
-1,
-176,
-162,
-150,
-253,
-175,
-64,
-215,
-40,
-8,
-97,
-204,
-9,
-75,
-132,
-61,
-162,
-135,
-103,
-84,
-1,
-53,
-214,
-209,
-246,
-126,
-61,
-2,
-192,
-78,
-238,
-91,
-28,
-154,
-155,
-144,
-85,
-202,
-114,
-5,
-154,
-16,
-1,
-96,
-221,
-174,
-255,
-233,
-148,
-89,
-103,
-166,
-143,
-85,
-181,
-45,
-240,
-121,
-22,
-185,
-75,
-249,
-49,
-200,
-170,
-98,
-17,
-34,
-76,
-62,
-217,
-128,
-143,
-93,
-225,
-4,
-133,
-78,
-39,
-143,
-140,
-52,
-16,
-172,
-213,
-161,
-113,
-183,
-1,
-235,
-23,
-234,
-108,
-26,
-189,
-133,
-192,
-51,
-67,
-251,
-217,
-10,
-20,
-66,
-16,
-105,
-217,
-83,
-2,
-0,
-241,
-79,
-182,
-46,
-194,
-71,
-20,
-232,
-130,
-67,
-16,
-197,
-158,
-176,
-68,
-216,
-35,
-122,
-120,
-142,
-249,
-21,
-69,
-76,
-180,
-189,
-223,
-162,
-0,
-208,
-178,
-91,
-181,
-108,
-115,
-103,
-178,
-255,
-214,
-169,
-111,
-34,
-0,
-172,
-150,
-124,
-79,
-167,
-236,
-35,
-90,
-214,
-104,
-73,
-76,
-158,
-245,
-200,
-226,
-82,
-52,
-218,
-116,
-3,
-30,
-118,
-11,
-252,
-161,
-64,
-250,
-221,
-148,
-254,
-177,
-26,
-58,
-187,
-13,
-216,
-183,
-80,
-254,
-89,
-45,
-111,
-125,
-170,
-21,
-12,
-10,
-65,
-8,
-181,
-12,
-68,
-82,
-90,
-205,
-181,
-125,
-112,
-69,
-23,
-202,
-224,
-32,
-132,
-68,
-158,
-176,
-68,
-216,
-35,
-22,
-248,
-141,
-249,
-21,
-69,
-76,
-126,
-93,
-238,
-215,
-233,
-131,
-43,
-0,
-108,
-70,
-167,
-3,
-157,
-255,
-239,
-228,
-212,
-7,
-9,
-0,
-68,
-155,
-110,
-191,
-210,
-110,
-234,
-177,
-149,
-17,
-165,
-222,
-34,
-2,
-163,
-67,
-33,
-43,
-9,
-155,
-142,
-204,
-226,
-7,
-33,
-109,
-11,
-124,
-172,
-246,
-191,
-54,
-111,
-162,
-210,
-239,
-172,
-244,
-149,
-115,
-131,
-124,
-27,
-80,
-76,
-224,
-114,
-190,
-150,
-183,
-14,
-172,
-26,
-12,
-202,
-87,
-0,
-51,
-16,
-39,
-148,
-187,
-245,
-1,
-108,
-224,
-105,
-219,
-100,
-5,
-16,
-109,
-194,
-18,
-105,
-143,
-88,
-224,
-57,
-230,
-87,
-20,
-49,
-249,
-117,
-185,
-95,
-167,
-15,
-174,
-0,
-176,
-154,
-245,
-155,
-17,
-229,
-228,
-99,
-140,
-12,
-89,
-21,
-42,
-0,
-108,
-146,
-153,
-129,
-112,
-93,
-136,
-203,
-46,
-192,
-55,
-107,
-120,
-44,
-137,
-28,
-117,
-218,
-113,
-252,
-85,
-36,
-145,
-137,
-205,
-90,
-244,
-253,
-2,
-189,
-53,
-104,
-242,
-70,
-182,
-70,
-142,
-134,
-33,
-60,
-109,
-91,
-232,
-10,
-224,
-153,
-200,
-50,
-127,
-33,
-170,
-92,
-68,
-242,
-46,
-44,
-64,
-4,
-221,
-64,
-22,
-237,
-232,
-160,
-16,
-132,
-80,
-203,
-32,
-223,
-2,
-216,
-24,
-248,
-190,
-140,
-42,
-65,
-65,
-8,
-137,
-60,
-97,
-137,
-180,
-71,
-44,
-240,
-28,
-211,
-43,
-138,
-30,
-248,
-181,
-190,
-95,
-114,
-108,
-81,
-40,
-191,
-195,
-169,
-59,
-182,
-80,
-23,
-42,
-0,
-110,
-161,
-30,
-183,
-214,
-240,
-176,
-123,
-240,
-135,
-113,
-210,
-217,
-35,
-81,
-150,
-236,
-209,
-160,
-171,
-176,
-252,
-165,
-150,
-121,
-147,
-131,
-32,
-138,
-92,
-8,
-215,
-1,
-212,
-102,
-202,
-118,
-104,
-47,
-82,
-218,
-143,
-235,
-239,
-143,
-234,
-239,
-139,
-235,
-218,
-70,
-1,
-133,
-32,
-132,
-90,
-6,
-35,
-149,
-128,
-231,
-107,
-217,
-235,
-157,
-178,
-224,
-32,
-132,
-68,
-158,
-176,
-68,
-220,
-35,
-106,
-219,
-49,
-191,
-162,
-136,
-201,
-175,
-235,
-253,
-146,
-163,
-40,
-0,
-126,
-228,
-212,
-109,
-87,
-168,
-171,
-21,
-0,
-200,
-17,
-39,
-200,
-87,
-187,
-44,
-171,
-144,
-13,
-36,
-91,
-229,
-128,
-100,
-163,
-18,
-15,
-164,
-178,
-71,
-12,
-122,
-158,
-18,
-2,
-72,
-102,
-170,
-57,
-136,
-197,
-160,
-215,
-148,
-156,
-60,
-55,
-95,
-232,
-41,
-128,
-205,
-204,
-60,
-144,
-32,
-213,
-67,
-251,
-25,
-165,
-61,
-189,
-208,
-246,
-179,
-33,
-215,
-234,
-12,
-252,
-65,
-8,
-97,
-164,
-0,
-216,
-18,
-89,
-146,
-92,
-75,
-30,
-146,
-58,
-56,
-8,
-33,
-113,
-149,
-58,
-207,
-33,
-210,
-30,
-209,
-105,
-59,
-30,
-86,
-20,
-49,
-183,
-80,
-157,
-238,
-151,
-28,
-69,
-1,
-96,
-195,
-166,
-77,
-101,
-48,
-203,
-116,
-136,
-0,
-176,
-6,
-83,
-135,
-87,
-208,
-252,
-76,
-105,
-142,
-170,
-160,
-177,
-177,
-3,
-183,
-45,
-169,
-127,
-51,
-121,
-54,
-43,
-123,
-74,
-240,
-195,
-10,
-126,
-239,
-83,
-154,
-57,
-52,
-179,
-3,
-120,
-123,
-21,
-173,
-210,
-219,
-109,
-192,
-147,
-200,
-92,
-156,
-174,
-99,
-248,
-217,
-117,
-109,
-163,
-129,
-193,
-32,
-132,
-224,
-8,
-0,
-45,
-179,
-22,
-78,
-31,
-163,
-65,
-16,
-66,
-34,
-79,
-88,
-34,
-236,
-17,
-61,
-237,
-198,
-244,
-138,
-162,
-7,
-126,
-81,
-239,
-55,
-6,
-16,
-19,
-93,
-59,
-25,
-95,
-89,
-65,
-103,
-29,
-100,
-30,
-163,
-36,
-19,
-53,
-146,
-238,
-28,
-224,
-43,
-21,
-124,
-118,
-37,
-199,
-29,
-84,
-68,
-31,
-210,
-190,
-221,
-165,
-180,
-191,
-43,
-163,
-83,
-90,
-107,
-102,
-124,
-19,
-225,
-74,
-85,
-187,
-13,
-248,
-162,
-254,
-173,
-204,
-157,
-216,
-11,
-232,
-41,
-8,
-97,
-236,
-9,
-75,
-132,
-61,
-98,
-129,
-223,
-115,
-24,
-227,
-43,
-138,
-152,
-252,
-250,
-184,
-223,
-24,
-32,
-143,
-91,
-88,
-107,
-157,
-71,
-190,
-196,
-247,
-186,
-33,
-147,
-39,
-253,
-152,
-173,
-207,
-206,
-205,
-175,
-184,
-30,
-146,
-123,
-241,
-225,
-194,
-152,
-57,
-160,
-230,
-154,
-111,
-34,
-63,
-13,
-56,
-133,
-193,
-188,
-136,
-235,
-145,
-7,
-87,
-157,
-67,
-133,
-16,
-243,
-240,
-182,
-219,
-128,
-251,
-245,
-111,
-183,
-216,
-254,
-109,
-65,
-15,
-65,
-8,
-137,
-56,
-97,
-137,
-180,
-71,
-44,
-240,
-28,
-15,
-43,
-138,
-152,
-91,
-168,
-232,
-247,
-27,
-3,
-228,
-113,
-40,
-107,
-175,
-77,
-110,
-121,
-120,
-102,
-73,
-253,
-74,
-136,
-167,
-168,
-197,
-124,
-228,
-52,
-203,
-245,
-228,
-91,
-136,
-108,
-57,
-118,
-116,
-198,
-204,
-64,
-134,
-170,
-2,
-223,
-119,
-21,
-120,
-220,
-166,
-215,
-113,
-189,
-1,
-167,
-226,
-232,
-202,
-2,
-239,
-253,
-89,
-136,
-224,
-69,
-255,
-174,
-83,
-223,
-170,
-39,
-16,
-49,
-8,
-33,
-145,
-39,
-44,
-145,
-246,
-136,
-5,
-250,
-49,
-189,
-162,
-232,
-129,
-95,
-212,
-251,
-141,
-1,
-100,
-91,
-99,
-221,
-118,
-7,
-142,
-155,
-61,
-244,
-214,
-207,
-96,
-30,
-37,
-177,
-27,
-144,
-204,
-86,
-159,
-68,
-20,
-216,
-54,
-174,
-197,
-99,
-136,
-99,
-219,
-161,
-56,
-161,
-191,
-145,
-109,
-133,
-61,
-234,
-251,
-118,
-205,
-181,
-215,
-64,
-132,
-232,
-101,
-72,
-152,
-54,
-27,
-174,
-237,
-98,
-100,
-101,
-209,
-54,
-94,
-134,
-77,
-102,
-251,
-239,
-122,
-234,
-113,
-2,
-34,
-78,
-88,
-34,
-238,
-17,
-29,
-218,
-49,
-191,
-162,
-136,
-201,
-175,
-143,
-251,
-77,
-72,
-240,
-34,
-246,
-132,
-37,
-226,
-30,
-209,
-161,
-27,
-15,
-43,
-138,
-152,
-91,
-168,
-232,
-247,
-155,
-144,
-224,
-69,
-236,
-9,
-75,
-196,
-61,
-162,
-210,
-140,
-249,
-21,
-69,
-76,
-126,
-125,
-220,
-111,
-66,
-66,
-41,
-98,
-78,
-88,
-250,
-217,
-35,
-142,
-249,
-21,
-69,
-76,
-126,
-125,
-220,
-111,
-194,
-4,
-3,
-225,
-231,
-154,
-209,
-39,
-108,
-108,
-196,
-20,
-80,
-74,
-19,
-123,
-203,
-19,
-155,
-95,
-212,
-251,
-13,
-1,
-162,
-48,
-179,
-86,
-119,
-165,
-249,
-246,
-144,
-252,
-136,
-32,
-182,
-250,
-107,
-84,
-208,
-21,
-177,
-16,
-57,
-206,
-187,
-4,
-177,
-247,
-95,
-181,
-97,
-255,
-214,
-82,
-62,
-39,
-20,
-202,
-47,
-3,
-30,
-172,
-104,
-183,
-10,
-185,
-210,
-240,
-131,
-21,
-116,
-239,
-82,
-154,
-39,
-129,
-85,
-60,
-245,
-43,
-146,
-219,
-44,
-236,
-81,
-193,
-103,
-71,
-165,
-185,
-135,
-190,
-3,
-240,
-208,
-49,
-96,
-228,
-120,
-0,
-227,
-96,
-69,
-17,
-147,
-95,
-31,
-247,
-27,
-10,
-242,
-179,
-241,
-42,
-75,
-187,
-131,
-148,
-230,
-212,
-26,
-94,
-22,
-54,
-247,
-226,
-127,
-200,
-163,
-254,
-160,
-99,
-118,
-32,
-155,
-117,
-5,
-191,
-237,
-181,
-221,
-23,
-157,
-178,
-12,
-217,
-86,
-253,
-179,
-166,
-237,
-183,
-181,
-109,
-105,
-92,
-65,
-114,
-205,
-254,
-129,
-21,
-52,
-86,
-72,
-60,
-130,
-39,
-211,
-51,
-18,
-142,
-204,
-190,
-223,
-119,
-135,
-222,
-91,
-107,
-208,
-49,
-96,
-228,
-68,
-5,
-241,
-87,
-20,
-67,
-255,
-98,
-247,
-1,
-36,
-98,
-51,
-136,
-243,
-210,
-64,
-40,
-50,
-96,
-9,
-242,
-120,
-123,
-111,
-170,
-225,
-101,
-81,
-52,
-65,
-222,
-20,
-248,
-179,
-214,
-45,
-160,
-196,
-4,
-216,
-195,
-239,
-11,
-218,
-102,
-123,
-167,
-204,
-70,
-50,
-174,
-244,
-182,
-100,
-228,
-42,
-224,
-205,
-158,
-122,
-27,
-69,
-107,
-186,
-111,
-98,
-23,
-104,
-109,
-223,
-127,
-229,
-169,
-179,
-130,
-198,
-155,
-216,
-53,
-58,
-232,
-24,
-48,
-114,
-34,
-130,
-200,
-95,
-216,
-216,
-252,
-70,
-27,
-136,
-89,
-44,
-120,
-108,
-227,
-129,
-29,
-180,
-110,
-10,
-53,
-153,
-145,
-203,
-4,
-128,
-214,
-101,
-192,
-201,
-90,
-127,
-23,
-97,
-137,
-69,
-143,
-87,
-250,
-181,
-157,
-178,
-119,
-106,
-217,
-71,
-3,
-218,
-219,
-201,
-57,
-224,
-17,
-75,
-190,
-242,
-25,
-136,
-150,
-236,
-161,
-93,
-151,
-220,
-7,
-96,
-43,
-167,
-124,
-67,
-196,
-154,
-113,
-38,
-195,
-178,
-206,
-164,
-99,
-192,
-200,
-132,
-132,
-34,
-200,
-191,
-180,
-103,
-120,
-234,
-78,
-209,
-186,
-111,
-5,
-240,
-41,
-21,
-0,
-90,
-191,
-6,
-185,
-147,
-207,
-7,
-2,
-248,
-93,
-13,
-60,
-84,
-40,
-179,
-118,
-23,
-181,
-81,
-131,
-24,
-185,
-10,
-112,
-3,
-162,
-174,
-163,
-2,
-124,
-22,
-129,
-31,
-77,
-96,
-95,
-229,
-243,
-63,
-59,
-7,
-201,
-205,
-189,
-27,
-133,
-224,
-31,
-115,
-32,
-82,
-60,
-123,
-135,
-95,
-148,
-56,
-251,
-9,
-195,
-1,
-226,
-33,
-103,
-93,
-110,
-215,
-116,
-202,
-87,
-213,
-242,
-133,
-192,
-122,
-1,
-124,
-42,
-5,
-128,
-210,
-216,
-128,
-156,
-94,
-167,
-29,
-90,
-160,
-166,
-79,
-118,
-21,
-112,
-170,
-83,
-102,
-19,
-122,
-252,
-180,
-238,
-158,
-156,
-54,
-75,
-2,
-215,
-104,
-187,
-47,
-145,
-235,
-6,
-38,
-19,
-176,
-154,
-137,
-2,
-58,
-166,
-61,
-42,
-225,
-25,
-45,
-158,
-189,
-195,
-179,
-83,
-156,
-125,
-82,
-26,
-176,
-74,
-32,
-91,
-16,
-235,
-82,
-91,
-186,
-5,
-1,
-54,
-82,
-154,
-218,
-173,
-7,
-185,
-59,
-243,
-126,
-78,
-153,
-77,
-144,
-113,
-118,
-85,
-91,
-135,
-222,
-162,
-74,
-0,
-236,
-175,
-52,
-94,
-227,
-40,
-224,
-88,
-253,
-119,
-186,
-210,
-93,
-227,
-148,
-29,
-139,
-172,
-32,
-30,
-118,
-203,
-106,
-250,
-100,
-87,
-1,
-11,
-144,
-37,
-251,
-242,
-200,
-137,
-204,
-28,
-26,
-186,
-244,
-34,
-122,
-131,
-133,
-58,
-71,
-238,
-69,
-182,
-4,
-175,
-107,
-194,
-163,
-53,
-136,
-148,
-246,
-168,
-192,
-51,
-106,
-60,
-123,
-229,
-25,
-35,
-206,
-254,
-132,
-73,
-3,
-214,
-22,
-228,
-138,
-169,
-82,
-37,
-36,
-240,
-93,
-165,
-249,
-99,
-0,
-191,
-173,
-149,
-246,
-122,
-167,
-204,
-10,
-226,
-247,
-214,
-180,
-173,
-68,
-129,
-214,
-134,
-227,
-122,
-162,
-134,
-167,
-141,
-219,
-183,
-135,
-83,
-182,
-188,
-142,
-173,
-63,
-212,
-221,
-79,
-129,
-151,
-93,
-5,
-28,
-65,
-190,
-218,
-109,
-101,
-73,
-73,
-110,
-215,
-1,
-240,
-235,
-54,
-60,
-218,
-92,
-52,
-90,
-218,
-163,
-66,
-187,
-232,
-241,
-236,
-137,
-16,
-103,
-95,
-249,
-244,
-146,
-6,
-172,
-112,
-141,
-12,
-9,
-38,
-81,
-171,
-87,
-33,
-242,
-234,
-139,
-142,
-201,
-88,
-201,
-163,
-233,
-122,
-143,
-33,
-245,
-222,
-166,
-40,
-77,
-80,
-134,
-40,
-242,
-208,
-90,
-47,
-37,
-87,
-92,
-62,
-140,
-19,
-59,
-176,
-164,
-157,
-181,
-122,
-180,
-184,
-214,
-41,
-187,
-164,
-64,
-107,
-39,
-246,
-188,
-26,
-158,
-7,
-40,
-157,
-187,
-119,
-183,
-1,
-77,
-188,
-201,
-58,
-42,
-120,
-217,
-85,
-192,
-44,
-125,
-38,
-243,
-105,
-169,
-180,
-3,
-246,
-113,
-238,
-179,
-113,
-0,
-211,
-54,
-23,
-140,
-154,
-246,
-104,
-60,
-129,
-142,
-105,
-192,
-60,
-147,
-118,
-46,
-98,
-172,
-113,
-1,
-226,
-137,
-182,
-159,
-62,
-175,
-223,
-214,
-240,
-9,
-89,
-125,
-61,
-68,
-33,
-204,
-86,
-13,
-207,
-78,
-201,
-88,
-129,
-101,
-144,
-179,
-105,
-240,
-8,
-124,
-224,
-245,
-90,
-231,
-61,
-222,
-43,
-225,
-249,
-121,
-109,
-115,
-32,
-185,
-178,
-205,
-27,
-135,
-175,
-164,
-189,
-69,
-213,
-22,
-224,
-163,
-74,
-83,
-25,
-172,
-22,
-9,
-171,
-182,
-0,
-120,
-154,
-83,
-182,
-167,
-182,
-13,
-118,
-119,
-119,
-218,
-126,
-219,
-233,
-95,
-171,
-47,
-55,
-226,
-225,
-249,
-48,
-162,
-245,
-159,
-133,
-108,
-71,
-106,
-117,
-35,
-157,
-64,
-15,
-105,
-143,
-38,
-2,
-60,
-147,
-246,
-14,
-157,
-180,
-247,
-144,
-251,
-118,
-131,
-124,
-201,
-189,
-249,
-223,
-148,
-79,
-211,
-213,
-87,
-168,
-87,
-98,
-231,
-100,
-172,
-192,
-225,
-122,
-221,
-95,
-120,
-234,
-236,
-17,
-90,
-169,
-129,
-143,
-167,
-205,
-106,
-58,
-206,
-46,
-35,
-95,
-254,
-7,
-235,
-131,
-2,
-5,
-128,
-205,
-72,
-52,
-201,
-83,
-231,
-238,
-245,
-31,
-211,
-177,
-236,
-150,
-93,
-171,
-109,
-255,
-68,
-192,
-254,
-191,
-192,
-123,
-21,
-167,
-127,
-175,
-14,
-109,
-87,
-224,
-113,
-168,
-182,
-255,
-46,
-121,
-124,
-197,
-147,
-218,
-240,
-106,
-114,
-209,
-232,
-105,
-143,
-148,
-46,
-218,
-146,
-54,
-38,
-175,
-24,
-40,
-76,
-218,
-211,
-128,
-13,
-11,
-245,
-27,
-147,
-235,
-24,
-230,
-80,
-72,
-78,
-233,
-208,
-181,
-89,
-125,
-221,
-194,
-144,
-142,
-106,
-201,
-141,
-89,
-30,
-193,
-209,
-68,
-35,
-123,
-101,
-235,
-132,
-84,
-106,
-226,
-91,
-194,
-243,
-68,
-125,
-127,
-139,
-128,
-203,
-26,
-182,
-181,
-168,
-18,
-0,
-231,
-42,
-205,
-128,
-209,
-26,
-45,
-16,
-187,
-127,
-21,
-109,
-55,
-66,
-86,
-144,
-15,
-34,
-38,
-194,
-107,
-144,
-219,
-6,
-116,
-218,
-238,
-214,
-93,
-184,
-143,
-180,
-71,
-209,
-20,
-138,
-49,
-121,
-41,
-191,
-78,
-194,
-132,
-145,
-147,
-246,
-119,
-120,
-38,
-45,
-240,
-33,
-173,
-183,
-198,
-60,
-215,
-151,
-208,
-181,
-93,
-125,
-5,
-229,
-180,
-139,
-1,
-228,
-24,
-10,
-156,
-21,
-31,
-240,
-97,
-45,
-107,
-52,
-129,
-181,
-173,
-221,
-138,
-64,
-243,
-112,
-102,
-22,
-101,
-118,
-0,
-27,
-147,
-167,
-219,
-42,
-53,
-9,
-38,
-87,
-72,
-126,
-163,
-80,
-254,
-16,
-112,
-121,
-147,
-62,
-53,
-233,
-95,
-77,
-91,
-27,
-219,
-97,
-31,
-167,
-236,
-123,
-90,
-118,
-126,
-219,
-62,
-133,
-92,
-56,
-106,
-218,
-35,
-226,
-230,
-81,
-143,
-170,
-156,
-36,
-130,
-48,
-33,
-159,
-180,
-179,
-240,
-56,
-174,
-32,
-146,
-251,
-97,
-29,
-136,
-111,
-35,
-159,
-180,
-3,
-138,
-50,
-198,
-199,
-234,
-235,
-255,
-244,
-154,
-238,
-57,
-183,
-253,
-202,
-238,
-21,
-202,
-199,
-105,
-187,
-190,
-182,
-157,
-14,
-172,
-208,
-176,
-173,
-133,
-207,
-18,
-240,
-233,
-228,
-138,
-194,
-201,
-84,
-175,
-166,
-62,
-169,
-116,
-174,
-80,
-123,
-166,
-150,
-5,
-47,
-251,
-155,
-244,
-175,
-166,
-157,
-213,
-167,
-220,
-204,
-200,
-248,
-133,
-171,
-146,
-27,
-26,
-213,
-70,
-24,
-110,
-5,
-34,
-166,
-61,
-34,
-162,
-66,
-49,
-38,
-47,
-165,
-137,
-34,
-76,
-28,
-26,
-239,
-209,
-23,
-121,
-84,
-216,
-159,
-233,
-111,
-27,
-231,
-221,
-183,
-36,
-109,
-187,
-250,
-42,
-85,
-90,
-18,
-127,
-197,
-244,
-76,
-125,
-110,
-51,
-145,
-176,
-213,
-107,
-33,
-194,
-173,
-109,
-68,
-98,
-155,
-246,
-186,
-241,
-68,
-115,
-250,
-239,
-102,
-36,
-90,
-2,
-216,
-22,
-184,
-82,
-235,
-102,
-81,
-51,
-1,
-129,
-159,
-43,
-237,
-115,
-157,
-50,
-155,
-29,
-168,
-117,
-64,
-78,
-95,
-255,
-2,
-218,
-44,
-129,
-132,
-41,
-3,
-143,
-179,
-15,
-240,
-45,
-173,
-187,
-145,
-62,
-182,
-126,
-68,
-76,
-123,
-68,
-68,
-133,
-98,
-100,
-94,
-49,
-5,
-147,
-157,
-180,
-251,
-123,
-234,
-172,
-119,
-217,
-221,
-232,
-215,
-141,
-138,
-44,
-49,
-180,
-95,
-125,
-61,
-94,
-82,
-223,
-215,
-113,
-174,
-53,
-73,
-221,
-25,
-216,
-91,
-255,
-127,
-98,
-72,
-219,
-2,
-159,
-165,
-16,
-129,
-4,
-240,
-178,
-22,
-237,
-45,
-236,
-49,
-224,
-181,
-228,
-46,
-211,
-32,
-199,
-203,
-175,
-8,
-224,
-115,
-62,
-98,
-155,
-146,
-57,
-101,
-246,
-196,
-230,
-13,
-77,
-251,
-229,
-233,
-95,
-19,
-1,
-176,
-151,
-182,
-185,
-180,
-164,
-126,
-37,
-36,
-38,
-39,
-120,
-18,
-157,
-116,
-6,
-17,
-211,
-30,
-17,
-113,
-73,
-27,
-153,
-87,
-76,
-97,
-226,
-157,
-180,
-200,
-215,
-209,
-166,
-198,
-122,
-171,
-83,
-110,
-245,
-1,
-143,
-122,
-120,
-181,
-93,
-125,
-45,
-240,
-212,
-245,
-118,
-156,
-75,
-158,
-24,
-227,
-120,
-224,
-239,
-250,
-255,
-70,
-19,
-5,
-57,
-86,
-180,
-167,
-10,
-23,
-52,
-105,
-235,
-240,
-40,
-98,
-54,
-114,
-234,
-114,
-38,
-240,
-113,
-2,
-35,
-24,
-33,
-123,
-253,
-127,
-23,
-202,
-78,
-80,
-158,
-149,
-227,
-35,
-176,
-127,
-65,
-2,
-0,
-153,
-220,
-86,
-89,
-92,
-149,
-233,
-200,
-206,
-185,
-135,
-136,
-173,
-240,
-38,
-98,
-218,
-35,
-34,
-42,
-20,
-35,
-243,
-138,
-41,
-76,
-188,
-147,
-150,
-252,
-216,
-230,
-228,
-66,
-121,
-213,
-150,
-169,
-237,
-234,
-107,
-154,
-167,
-174,
-183,
-227,
-92,
-68,
-184,
-216,
-112,
-241,
-179,
-144,
-175,
-120,
-169,
-128,
-113,
-218,
-173,
-132,
-40,
-64,
-175,
-32,
-183,
-41,
-120,
-130,
-0,
-15,
-199,
-132,
-126,
-225,
-186,
-93,
-254,
-69,
-255,
-190,
-57,
-100,
-224,
-24,
-99,
-172,
-239,
-243,
-233,
-30,
-18,
-235,
-86,
-121,
-119,
-96,
-63,
-108,
-128,
-145,
-103,
-246,
-204,
-203,
-122,
-118,
-133,
-106,
-120,
-175,
-212,
-191,
-62,
-11,
-193,
-233,
-250,
-247,
-233,
-182,
-0,
-241,
-28,
-219,
-215,
-24,
-243,
-152,
-49,
-166,
-184,
-135,
-92,
-174,
-208,
-206,
-197,
-3,
-250,
-119,
-221,
-192,
-126,
-217,
-120,
-241,
-119,
-121,
-234,
-172,
-146,
-241,
-156,
-44,
-203,
-30,
-242,
-212,
-63,
-133,
-44,
-203,
-30,
-53,
-198,
-88,
-251,
-251,
-218,
-19,
-133,
-44,
-203,
-230,
-24,
-99,
-78,
-49,
-198,
-172,
-105,
-228,
-190,
-79,
-200,
-178,
-44,
-228,
-136,
-108,
-145,
-49,
-102,
-101,
-99,
-204,
-22,
-198,
-152,
-101,
-140,
-140,
-181,
-151,
-100,
-89,
-118,
-71,
-64,
-219,
-132,
-30,
-225,
-10,
-128,
-51,
-140,
-76,
-178,
-101,
-141,
-49,
-135,
-213,
-180,
-251,
-137,
-145,
-1,
-125,
-179,
-49,
-230,
-175,
-158,
-122,
-155,
-81,
-40,
-200,
-218,
-204,
-24,
-51,
-75,
-255,
-250,
-194,
-28,
-197,
-228,
-21,
-83,
-152,
-216,
-201,
-181,
-142,
-49,
-198,
-32,
-75,
-232,
-99,
-140,
-49,
-75,
-26,
-99,
-246,
-203,
-178,
-172,
-24,
-74,
-202,
-78,
-218,
-251,
-61,
-188,
-174,
-214,
-191,
-161,
-89,
-100,
-172,
-64,
-242,
-153,
-81,
-199,
-20,
-114,
-3,
-200,
-178,
-236,
-19,
-89,
-142,
-111,
-7,
-182,
-153,
-145,
-101,
-217,
-58,
-89,
-150,
-45,
-147,
-101,
-217,
-74,
-89,
-150,
-189,
-61,
-203,
-178,
-59,
-3,
-251,
-151,
-208,
-35,
-158,
-18,
-0,
-89,
-150,
-205,
-53,
-198,
-124,
-220,
-24,
-179,
-208,
-24,
-179,
-43,
-21,
-105,
-143,
-140,
-49,
-187,
-25,
-99,
-230,
-26,
-99,
-62,
-146,
-101,
-217,
-66,
-15,
-223,
-25,
-250,
-119,
-57,
-79,
-157,
-15,
-85,
-95,
-199,
-152,
-188,
-98,
-10,
-19,
-59,
-249,
-236,
-196,
-217,
-215,
-200,
-228,
-59,
-47,
-203,
-50,
-95,
-54,
-88,
-75,
-119,
-165,
-167,
-174,
-237,
-234,
-107,
-192,
-175,
-222,
-196,
-21,
-114,
-9,
-139,
-57,
-70,
-68,
-94,
-201,
-178,
-236,
-28,
-99,
-204,
-123,
-141,
-49,
-79,
-24,
-99,
-118,
-49,
-198,
-76,
-193,
-73,
-123,
-100,
-100,
-201,
-185,
-171,
-49,
-230,
-65,
-99,
-204,
-142,
-89,
-150,
-149,
-125,
-101,
-218,
-46,
-105,
-125,
-95,
-199,
-152,
-188,
-98,
-10,
-147,
-127,
-232,
-223,
-29,
-16,
-141,
-243,
-119,
-140,
-8,
-150,
-189,
-139,
-132,
-1,
-91,
-166,
-54,
-171,
-175,
-27,
-77,
-46,
-56,
-92,
-196,
-20,
-114,
-227,
-2,
-136,
-157,
-197,
-41,
-148,
-28,
-143,
-33,
-217,
-129,
-254,
-136,
-39,
-100,
-151,
-214,
-23,
-209,
-58,
-200,
-40,
-18,
-196,
-117,
-111,
-224,
-31,
-192,
-125,
-136,
-237,
-197,
-52,
-228,
-136,
-239,
-135,
-56,
-14,
-113,
-37,
-237,
-59,
-185,
-168,
-211,
-209,
-249,
-203,
-50,
-233,
-148,
-246,
-136,
-184,
-10,
-197,
-152,
-188,
-98,
-158,
-116,
-44,
-67,
-158,
-196,
-209,
-42,
-210,
-6,
-142,
-4,
-149,
-182,
-54,
-83,
-44,
-205,
-146,
-78,
-206,
-162,
-228,
-152,
-139,
-136,
-199,
-185,
-227,
-5,
-58,
-232,
-209,
-231,
-252,
-101,
-224,
-6,
-125,
-39,
-147,
-145,
-99,
-189,
-83,
-181,
-222,
-39,
-48,
-125,
-199,
-138,
-173,
-130,
-140,
-34,
-169,
-207,
-111,
-119,
-218,
-77,
-69,
-20,
-159,
-55,
-146,
-91,
-38,
-86,
-230,
-112,
-164,
-163,
-139,
-58,
-29,
-157,
-191,
-162,
-128,
-136,
-121,
-212,
-35,
-243,
-138,
-38,
-76,
-180,
-126,
-123,
-231,
-197,
-78,
-7,
-54,
-45,
-212,
-55,
-202,
-20,
-75,
-120,
-210,
-201,
-109,
-43,
-120,
-68,
-19,
-114,
-49,
-64,
-216,
-241,
-226,
-234,
-192,
-33,
-136,
-127,
-195,
-92,
-202,
-225,
-245,
-55,
-64,
-162,
-232,
-252,
-202,
-161,
-187,
-29,
-17,
-162,
-147,
-157,
-178,
-83,
-40,
-113,
-55,
-118,
-104,
-90,
-7,
-25,
-5,
-94,
-64,
-46,
-124,
-255,
-11,
-108,
-83,
-168,
-95,
-11,
-137,
-16,
-84,
-155,
-48,
-148,
-14,
-46,
-234,
-68,
-112,
-254,
-234,
-12,
-34,
-230,
-81,
-143,
-204,
-43,
-154,
-48,
-81,
-154,
-103,
-146,
-219,
-3,
-128,
-56,
-108,
-220,
-197,
-160,
-197,
-93,
-112,
-166,
-88,
-6,
-87,
-95,
-11,
-201,
-133,
-204,
-69,
-212,
-251,
-40,
-68,
-21,
-114,
-129,
-60,
-90,
-135,
-144,
-215,
-251,
-181,
-95,
-205,
-219,
-129,
-99,
-128,
-163,
-129,
-91,
-157,
-231,
-119,
-55,
-226,
-33,
-87,
-122,
-239,
-228,
-246,
-242,
-199,
-49,
-210,
-97,
-201,
-90,
-28,
-126,
-161,
-162,
-173,
-69,
-171,
-32,
-163,
-74,
-99,
-45,
-16,
-175,
-37,
-66,
-204,
-126,
-58,
-186,
-168,
-143,
-58,
-136,
-152,
-71,
-61,
-22,
-47,
-34,
-10,
-19,
-165,
-57,
-70,
-105,
-14,
-71,
-246,
-138,
-255,
-209,
-151,
-22,
-37,
-83,
-172,
-115,
-29,
-43,
-184,
-102,
-2,
-149,
-186,
-16,
-34,
-11,
-185,
-192,
-254,
-29,
-71,
-203,
-16,
-242,
-192,
-79,
-245,
-250,
-255,
-194,
-49,
-224,
-65,
-246,
-237,
-103,
-107,
-93,
-109,
-48,
-76,
-100,
-245,
-48,
-3,
-88,
-190,
-80,
-158,
-33,
-1,
-54,
-7,
-220,
-130,
-29,
-26,
-139,
-86,
-65,
-70,
-201,
-45,
-63,
-33,
-32,
-136,
-232,
-132,
-1,
-17,
-243,
-168,
-199,
-226,
-69,
-92,
-193,
-180,
-2,
-146,
-66,
-189,
-215,
-220,
-121,
-200,
-18,
-215,
-46,
-103,
-47,
-5,
-158,
-94,
-65,
-27,
-85,
-200,
-5,
-246,
-175,
-117,
-8,
-121,
-114,
-147,
-224,
-29,
-61,
-117,
-111,
-214,
-186,
-255,
-5,
-244,
-97,
-54,
-37,
-201,
-57,
-144,
-85,
-209,
-204,
-138,
-182,
-22,
-173,
-130,
-140,
-34,
-43,
-22,
-40,
-49,
-227,
-29,
-22,
-144,
-109,
-198,
-65,
-136,
-192,
-155,
-129,
-8,
-247,
-255,
-34,
-65,
-74,
-26,
-101,
-75,
-50,
-192,
-243,
-145,
-101,
-213,
-165,
-200,
-87,
-109,
-46,
-98,
-111,
-125,
-35,
-98,
-6,
-250,
-57,
-28,
-39,
-138,
-10,
-62,
-209,
-242,
-168,
-199,
-226,
-69,
-68,
-193,
-52,
-44,
-32,
-49,
-16,
-173,
-91,
-241,
-5,
-84,
-36,
-153,
-32,
-162,
-144,
-11,
-236,
-91,
-107,
-231,
-20,
-242,
-61,
-255,
-102,
-158,
-186,
-205,
-180,
-110,
-150,
-175,
-109,
-129,
-246,
-118,
-68,
-219,
-62,
-32,
-28,
-17,
-13,
-252,
-109,
-21,
-109,
-67,
-4,
-64,
-105,
-144,
-81,
-157,
-112,
-0,
-223,
-173,
-235,
-103,
-9,
-239,
-5,
-250,
-111,
-243,
-10,
-154,
-45,
-108,
-39,
-75,
-234,
-95,
-69,
-110,
-101,
-57,
-11,
-9,
-117,
-126,
-13,
-249,
-202,
-229,
-30,
-42,
-2,
-210,
-184,
-140,
-150,
-71,
-150,
-116,
-118,
-223,
-185,
-0,
-89,
-94,
-93,
-142,
-104,
-87,
-109,
-148,
-88,
-232,
-224,
-49,
-53,
-218,
-32,
-162,
-96,
-26,
-22,
-16,
-51,
-95,
-27,
-101,
-168,
-50,
-172,
-58,
-227,
-68,
-200,
-145,
-231,
-196,
-27,
-176,
-68,
-36,
-79,
-206,
-225,
-59,
-210,
-45,
-210,
-218,
-40,
-58,
-199,
-48,
-210,
-149,
-214,
-78,
-220,
-210,
-12,
-63,
-206,
-243,
-168,
-18,
-0,
-165,
-65,
-70,
-157,
-231,
-252,
-209,
-186,
-126,
-118,
-184,
-126,
-169,
-0,
-64,
-20,
-125,
-246,
-68,
-234,
-199,
-56,
-66,
-16,
-153,
-207,
-214,
-235,
-241,
-14,
-10,
-91,
-164,
-34,
-163,
-21,
-201,
-195,
-33,
-61,
-12,
-124,
-134,
-194,
-210,
-1,
-89,
-98,
-110,
-143,
-68,
-62,
-45,
-93,
-138,
-38,
-244,
-3,
-96,
-23,
-2,
-61,
-240,
-232,
-81,
-200,
-21,
-132,
-72,
-41,
-159,
-170,
-129,
-171,
-245,
-214,
-49,
-104,
-50,
-78,
-0,
-77,
-36,
-169,
-198,
-127,
-237,
-164,
-174,
-233,
-75,
-230,
-240,
-1,
-249,
-96,
-157,
-236,
-180,
-135,
-138,
-175,
-115,
-224,
-4,
-44,
-13,
-50,
-74,
-67,
-103,
-174,
-150,
-215,
-175,
-18,
-0,
-214,
-255,
-165,
-204,
-147,
-48,
-67,
-20,
-211,
-0,
-159,
-173,
-234,
-136,
-117,
-150,
-185,
-135,
-228,
-168,
-145,
-80,
-1,
-70,
-162,
-42,
-225,
-103,
-157,
-0,
-88,
-93,
-39,
-44,
-136,
-128,
-186,
-65,
-133,
-129,
-221,
-26,
-76,
-193,
-73,
-217,
-85,
-194,
-227,
-56,
-165,
-253,
-13,
-162,
-140,
-189,
-17,
-89,
-6,
-223,
-164,
-191,
-109,
-236,
-127,
-239,
-185,
-122,
-224,
-4,
-252,
-168,
-210,
-12,
-4,
-25,
-37,
-63,
-254,
-251,
-112,
-85,
-63,
-43,
-120,
-119,
-21,
-0,
-151,
-106,
-213,
-167,
-42,
-218,
-127,
-86,
-105,
-46,
-40,
-35,
-120,
-137,
-211,
-145,
-237,
-189,
-68,
-9,
-9,
-10,
-29,
-39,
-139,
-16,
-101,
-211,
-92,
-10,
-49,
-7,
-28,
-186,
-74,
-1,
-160,
-52,
-171,
-146,
-123,
-125,
-46,
-64,
-244,
-18,
-55,
-35,
-231,
-230,
-171,
-5,
-244,
-229,
-173,
-192,
-31,
-40,
-183,
-4,
-92,
-22,
-73,
-178,
-234,
-141,
-242,
-27,
-56,
-1,
-171,
-130,
-140,
-90,
-219,
-139,
-218,
-4,
-174,
-29,
-174,
-95,
-37,
-0,
-108,
-44,
-132,
-82,
-215,
-108,
-224,
-141,
-101,
-2,
-204,
-18,
-28,
-166,
-4,
-215,
-182,
-185,
-137,
-16,
-208,
-33,
-149,
-23,
-49,
-76,
-28,
-19,
-162,
-193,
-25,
-180,
-223,
-210,
-191,
-139,
-86,
-90,
-155,
-0,
-0,
-32,
-0,
-73,
-68,
-65,
-84,
-222,
-140,
-196,
-129,
-2,
-224,
-215,
-136,
-206,
-105,
-167,
-254,
-122,
-92,
-142,
-192,
-9,
-88,
-21,
-100,
-212,
-218,
-94,
-84,
-166,
-18,
-239,
-120,
-253,
-42,
-1,
-96,
-149,
-195,
-85,
-39,
-86,
-175,
-84,
-154,
-1,
-119,
-116,
-75,
-96,
-247,
-254,
-223,
-111,
-115,
-19,
-33,
-160,
-67,
-42,
-47,
-122,
-48,
-113,
-108,
-34,
-144,
-234,
-94,
-18,
-178,
-207,
-178,
-3,
-225,
-34,
-156,
-56,
-243,
-139,
-35,
-156,
-231,
-241,
-108,
-242,
-0,
-40,
-3,
-105,
-189,
-3,
-5,
-192,
-44,
-228,
-200,
-106,
-83,
-106,
-50,
-3,
-247,
-129,
-128,
-119,
-91,
-25,
-100,
-20,
-120,
-175,
-214,
-45,
-4,
-158,
-23,
-251,
-250,
-74,
-83,
-37,
-0,
-108,
-164,
-160,
-170,
-24,
-150,
-219,
-41,
-205,
-64,
-64,
-154,
-34,
-147,
-221,
-155,
-222,
-64,
-8,
-232,
-152,
-202,
-139,
-30,
-76,
-28,
-105,
-32,
-144,
-2,
-6,
-137,
-53,
-104,
-249,
-175,
-237,
-99,
-5,
-143,
-78,
-138,
-51,
-15,
-253,
-174,
-74,
-94,
-155,
-89,
-55,
-128,
-215,
-55,
-156,
-126,
-174,
-82,
-65,
-103,
-177,
-62,
-185,
-130,
-236,
-6,
-10,
-203,
-240,
-144,
-123,
-97,
-164,
-25,
-175,
-139,
-25,
-136,
-113,
-85,
-109,
-134,
-223,
-46,
-168,
-122,
-183,
-4,
-4,
-25,
-69,
-140,
-150,
-172,
-53,
-227,
-165,
-64,
-168,
-179,
-89,
-237,
-245,
-29,
-154,
-42,
-1,
-112,
-145,
-86,
-149,
-42,
-248,
-144,
-99,
-123,
-128,
-139,
-203,
-8,
-236,
-50,
-194,
-171,
-201,
-44,
-121,
-65,
-193,
-241,
-210,
-137,
-148,
-202,
-43,
-22,
-104,
-40,
-144,
-106,
-6,
-137,
-53,
-55,
-189,
-3,
-40,
-117,
-171,
-45,
-60,
-186,
-214,
-138,
-179,
-2,
-173,
-59,
-248,
-158,
-164,
-194,
-62,
-32,
-128,
-151,
-107,
-107,
-0,
-97,
-2,
-96,
-83,
-253,
-125,
-158,
-254,
-254,
-92,
-129,
-174,
-78,
-9,
-248,
-2,
-68,
-121,
-103,
-147,
-97,
-62,
-162,
-255,
-30,
-103,
-100,
-98,
-149,
-248,
-113,
-240,
-6,
-239,
-165,
-117,
-144,
-81,
-36,
-196,
-184,
-85,
-92,
-94,
-173,
-109,
-151,
-40,
-208,
-108,
-4,
-236,
-27,
-114,
-125,
-15,
-77,
-149,
-0,
-176,
-153,
-150,
-188,
-222,
-185,
-140,
-60,
-5,
-248,
-82,
-217,
-5,
-172,
-34,
-225,
-35,
-37,
-245,
-151,
-56,
-255,
-174,
-45,
-235,
-204,
-120,
-1,
-13,
-5,
-82,
-217,
-75,
-34,
-15,
-142,
-249,
-32,
-37,
-138,
-176,
-2,
-143,
-40,
-138,
-51,
-135,
-246,
-51,
-74,
-106,
-99,
-244,
-253,
-40,
-228,
-126,
-60,
-124,
-150,
-67,
-180,
-230,
-247,
-146,
-159,
-41,
-135,
-8,
-128,
-23,
-235,
-239,
-23,
-35,
-10,
-188,
-199,
-113,
-194,
-164,
-215,
-12,
-220,
-237,
-17,
-205,
-255,
-21,
-192,
-11,
-61,
-245,
-43,
-146,
-39,
-30,
-237,
-197,
-89,
-169,
-112,
-47,
-93,
-131,
-140,
-190,
-9,
-57,
-102,
-181,
-120,
-20,
-49,
-198,
-185,
-66,
-199,
-90,
-217,
-115,
-240,
-142,
-173,
-2,
-77,
-213,
-115,
-92,
-158,
-252,
-35,
-240,
-115,
-156,
-179,
-126,
-125,
-175,
-246,
-136,
-244,
-94,
-74,
-86,
-167,
-6,
-152,
-164,
-68,
-7,
-4,
-220,
-104,
-163,
-37,
-106,
-27,
-32,
-103,
-216,
-118,
-223,
-95,
-154,
-117,
-6,
-217,
-159,
-129,
-76,
-168,
-129,
-248,
-252,
-17,
-251,
-51,
-240,
-146,
-144,
-189,
-223,
-66,
-228,
-203,
-235,
-205,
-250,
-83,
-194,
-227,
-91,
-250,
-183,
-181,
-226,
-76,
-233,
-86,
-68,
-4,
-207,
-253,
-200,
-82,
-245,
-106,
-228,
-75,
-245,
-172,
-22,
-247,
-247,
-11,
-189,
-228,
-62,
-206,
-96,
-13,
-17,
-0,
-238,
-243,
-56,
-82,
-203,
-142,
-114,
-202,
-170,
-6,
-174,
-61,
-254,
-219,
-164,
-226,
-58,
-171,
-42,
-77,
-111,
-238,
-172,
-12,
-162,
-85,
-144,
-81,
-229,
-181,
-18,
-226,
-130,
-124,
-62,
-178,
-181,
-156,
-175,
-255,
-30,
-68,
-44,
-56,
-7,
-188,
-52,
-125,
-207,
-210,
-67,
-83,
-183,
-146,
-122,
-33,
-185,
-11,
-243,
-108,
-68,
-240,
-216,
-241,
-128,
-94,
-191,
-60,
-2,
-51,
-249,
-126,
-216,
-191,
-71,
-8,
-236,
-12,
-121,
-134,
-84,
-128,
-15,
-86,
-240,
-120,
-151,
-210,
-60,
-89,
-54,
-208,
-200,
-205,
-85,
-171,
-150,
-203,
-7,
-41,
-205,
-169,
-101,
-52,
-49,
-80,
-124,
-73,
-136,
-82,
-101,
-46,
-34,
-164,
-182,
-109,
-200,
-163,
-179,
-226,
-76,
-233,
-236,
-209,
-212,
-167,
-244,
-247,
-219,
-245,
-247,
-145,
-13,
-239,
-109,
-7,
-109,
-247,
-111,
-196,
-239,
-192,
-42,
-70,
-155,
-10,
-128,
-53,
-144,
-21,
-192,
-83,
-102,
-173,
-53,
-99,
-197,
-46,
-153,
-253,
-95,
-37,
-243,
-212,
-22,
-1,
-96,
-177,
-141,
-31,
-232,
-60,
-239,
-82,
-171,
-76,
-224,
-13,
-74,
-227,
-11,
-78,
-99,
-105,
-86,
-65,
-236,
-254,
-255,
-139,
-40,
-85,
-103,
-34,
-102,
-202,
-223,
-163,
-238,
-227,
-232,
-92,
-0,
-106,
-150,
-197,
-117,
-3,
-148,
-60,
-67,
-170,
-215,
-57,
-67,
-105,
-46,
-86,
-154,
-3,
-43,
-104,
-182,
-81,
-26,
-111,
-230,
-89,
-100,
-159,
-102,
-67,
-96,
-15,
-76,
-36,
-165,
-137,
-178,
-146,
-112,
-7,
-60,
-226,
-170,
-57,
-29,
-249,
-250,
-15,
-36,
-113,
-168,
-184,
-134,
-69,
-12,
-197,
-217,
-154,
-218,
-135,
-187,
-112,
-252,
-220,
-17,
-201,
-63,
-143,
-64,
-67,
-46,
-196,
-16,
-231,
-126,
-229,
-181,
-161,
-150,
-89,
-115,
-239,
-70,
-2,
-64,
-203,
-173,
-178,
-233,
-124,
-253,
-253,
-162,
-178,
-123,
-33,
-223,
-95,
-123,
-93,
-117,
-145,
-252,
-5,
-151,
-43,
-205,
-183,
-67,
-238,
-103,
-60,
-130,
-124,
-245,
-253,
-241,
-10,
-26,
-155,
-197,
-168,
-116,
-78,
-197,
-232,
-200,
-191,
-157,
-65,
-89,
-234,
-74,
-90,
-55,
-64,
-25,
-185,
-10,
-24,
-8,
-195,
-68,
-158,
-108,
-114,
-58,
-53,
-74,
-43,
-100,
-95,
-10,
-254,
-0,
-31,
-246,
-203,
-53,
-133,
-138,
-227,
-35,
-34,
-172,
-36,
-156,
-1,
-191,
-3,
-185,
-208,
-241,
-133,
-247,
-170,
-186,
-23,
-139,
-78,
-138,
-51,
-165,
-177,
-246,
-221,
-123,
-22,
-202,
-173,
-253,
-124,
-80,
-54,
-89,
-114,
-47,
-183,
-61,
-156,
-50,
-171,
-124,
-107,
-35,
-0,
-150,
-210,
-241,
-3,
-240,
-30,
-36,
-194,
-141,
-247,
-94,
-16,
-197,
-153,
-93,
-162,
-254,
-27,
-217,
-171,
-254,
-16,
-248,
-37,
-162,
-217,
-182,
-10,
-201,
-83,
-41,
-9,
-230,
-177,
-56,
-128,
-60,
-148,
-252,
-85,
-248,
-79,
-25,
-50,
-242,
-172,
-65,
-223,
-235,
-179,
-35,
-27,
-146,
-31,
-7,
-222,
-141,
-56,
-64,
-12,
-228,
-109,
-67,
-60,
-143,
-234,
-6,
-168,
-93,
-5,
-252,
-203,
-83,
-103,
-39,
-100,
-173,
-194,
-10,
-248,
-130,
-210,
-14,
-4,
-192,
-68,
-60,
-221,
-160,
-230,
-248,
-139,
-56,
-43,
-9,
-139,
-251,
-116,
-130,
-44,
-212,
-191,
-193,
-137,
-49,
-28,
-30,
-173,
-21,
-103,
-90,
-191,
-33,
-242,
-149,
-190,
-181,
-120,
-63,
-206,
-96,
-89,
-72,
-141,
-247,
-23,
-185,
-121,
-235,
-31,
-11,
-229,
-22,
-141,
-5,
-128,
-214,
-89,
-55,
-222,
-41,
-228,
-57,
-0,
-203,
-238,
-101,
-19,
-100,
-251,
-121,
-51,
-34,
-12,
-22,
-32,
-219,
-194,
-73,
-136,
-99,
-207,
-152,
-241,
-200,
-236,
-11,
-136,
-223,
-131,
-13,
-44,
-115,
-56,
-206,
-156,
-67,
-244,
-60,
-86,
-183,
-242,
-8,
-53,
-102,
-209,
-49,
-58,
-243,
-60,
-242,
-37,
-9,
-58,
-208,
-110,
-38,
-207,
-229,
-126,
-47,
-206,
-241,
-76,
-5,
-31,
-119,
-21,
-176,
-165,
-83,
-190,
-14,
-34,
-217,
-103,
-81,
-227,
-43,
-174,
-244,
-171,
-35,
-75,
-248,
-249,
-56,
-171,
-18,
-68,
-57,
-52,
-71,
-7,
-250,
-122,
-1,
-124,
-58,
-173,
-36,
-156,
-231,
-49,
-21,
-73,
-189,
-101,
-87,
-12,
-247,
-16,
-232,
-107,
-237,
-155,
-52,
-52,
-84,
-156,
-105,
-189,
-141,
-80,
-227,
-77,
-37,
-134,
-228,
-5,
-4,
-143,
-208,
-116,
-104,
-214,
-215,
-65,
-119,
-63,
-133,
-85,
-152,
-211,
-207,
-86,
-2,
-64,
-235,
-255,
-162,
-245,
-7,
-215,
-141,
-149,
-97,
-129,
-6,
-49,
-15,
-128,
-79,
-59,
-247,
-88,
-233,
-121,
-25,
-3,
-58,
-166,
-108,
-112,
-22,
-87,
-137,
-103,
-221,
-121,
-31,
-167,
-16,
-102,
-172,
-207,
-206,
-44,
-1,
-188,
-31,
-89,
-122,
-77,
-33,
-151,
-204,
-51,
-144,
-227,
-134,
-115,
-244,
-197,
-122,
-163,
-172,
-58,
-124,
-236,
-42,
-192,
-205,
-40,
-107,
-7,
-196,
-79,
-27,
-244,
-231,
-183,
-218,
-102,
-63,
-167,
-236,
-83,
-90,
-118,
-118,
-85,
-91,
-135,
-190,
-211,
-74,
-194,
-25,
-12,
-175,
-210,
-223,
-75,
-147,
-71,
-112,
-13,
-50,
-70,
-242,
-77,
-26,
-154,
-43,
-206,
-182,
-68,
-4,
-240,
-13,
-148,
-11,
-171,
-140,
-92,
-136,
-15,
-28,
-95,
-233,
-251,
-189,
-72,
-249,
-248,
-148,
-144,
-22,
-93,
-4,
-192,
-198,
-228,
-74,
-82,
-239,
-189,
-244,
-1,
-58,
-132,
-39,
-115,
-120,
-188,
-72,
-199,
-250,
-52,
-253,
-55,
-3,
-120,
-65,
-191,
-61,
-55,
-6,
-217,
-46,
-253,
-28,
-57,
-29,
-153,
-173,
-215,
-189,
-30,
-217,
-34,
-4,
-127,
-249,
-233,
-24,
-89,
-56,
-26,
-200,
-87,
-1,
-11,
-144,
-101,
-235,
-242,
-200,
-249,
-234,
-28,
-224,
-217,
-13,
-248,
-216,
-60,
-238,
-215,
-59,
-101,
-246,
-38,
-223,
-27,
-200,
-163,
-211,
-74,
-162,
-100,
-242,
-110,
-66,
-46,
-181,
-107,
-61,
-193,
-202,
-38,
-13,
-205,
-20,
-103,
-255,
-12,
-185,
-111,
-100,
-255,
-13,
-112,
-174,
-167,
-206,
-250,
-200,
-123,
-67,
-144,
-59,
-253,
-108,
-45,
-0,
-148,
-230,
-71,
-14,
-221,
-176,
-4,
-192,
-113,
-180,
-12,
-79,
-166,
-237,
-215,
-66,
-162,
-20,
-77,
-3,
-94,
-13,
-188,
-14,
-153,
-136,
-119,
-16,
-176,
-98,
-29,
-11,
-160,
-99,
-100,
-225,
-216,
-157,
-177,
-171,
-128,
-35,
-200,
-151,
-85,
-71,
-213,
-183,
-28,
-224,
-99,
-61,
-174,
-94,
-138,
-216,
-140,
-131,
-196,
-44,
-8,
-86,
-14,
-209,
-97,
-37,
-81,
-54,
-224,
-201,
-181,
-179,
-79,
-226,
-248,
-179,
-55,
-228,
-17,
-172,
-56,
-139,
-1,
-242,
-227,
-183,
-91,
-116,
-114,
-20,
-255,
-89,
-88,
-215,
-92,
-95,
-88,
-116,
-239,
-189,
-20,
-104,
-86,
-162,
-194,
-0,
-166,
-15,
-208,
-33,
-60,
-153,
-182,
-185,
-10,
-89,
-245,
-190,
-216,
-41,
-123,
-41,
-114,
-218,
-226,
-203,
-196,
-52,
-38,
-65,
-135,
-200,
-194,
-177,
-59,
-98,
-87,
-1,
-179,
-244,
-193,
-206,
-175,
-155,
-40,
-37,
-124,
-172,
-185,
-227,
-129,
-228,
-246,
-234,
-63,
-110,
-200,
-163,
-245,
-74,
-162,
-106,
-192,
-3,
-103,
-105,
-221,
-37,
-84,
-236,
-51,
-107,
-120,
-4,
-43,
-206,
-186,
-130,
-22,
-232,
-163,
-31,
-37,
-125,
-235,
-20,
-215,
-142,
-14,
-225,
-201,
-22,
-55,
-48,
-86,
-34,
-11,
-147,
-175,
-2,
-0,
-126,
-221,
-146,
-199,
-106,
-200,
-190,
-200,
-42,
-35,
-161,
-197,
-190,
-140,
-150,
-43,
-137,
-154,
-201,
-187,
-38,
-249,
-146,
-235,
-235,
-109,
-120,
-104,
-253,
-152,
-80,
-156,
-57,
-253,
-44,
-221,
-2,
-244,
-116,
-221,
-56,
-113,
-237,
-18,
-226,
-129,
-14,
-62,
-252,
-14,
-143,
-85,
-156,
-65,
-245,
-234,
-14,
-125,
-57,
-17,
-57,
-149,
-88,
-4,
-92,
-214,
-146,
-71,
-171,
-149,
-68,
-192,
-228,
-125,
-155,
-214,
-207,
-167,
-100,
-201,
-21,
-192,
-99,
-84,
-20,
-103,
-158,
-126,
-12,
-93,
-0,
-16,
-41,
-174,
-29,
-221,
-87,
-16,
-209,
-34,
-235,
-34,
-167,
-103,
-181,
-122,
-135,
-26,
-30,
-157,
-231,
-95,
-39,
-208,
-193,
-135,
-191,
-192,
-167,
-114,
-240,
-7,
-242,
-216,
-202,
-225,
-243,
-177,
-150,
-60,
-90,
-173,
-36,
-66,
-250,
-143,
-232,
-57,
-64,
-246,
-214,
-3,
-131,
-52,
-144,
-199,
-208,
-21,
-103,
-158,
-62,
-140,
-134,
-0,
-232,
-28,
-215,
-142,
-142,
-43,
-136,
-174,
-237,
-61,
-252,
-126,
-5,
-124,
-38,
-148,
-190,
-132,
-71,
-163,
-249,
-71,
-228,
-208,
-224,
-157,
-124,
-248,
-11,
-188,
-106,
-7,
-127,
-0,
-15,
-187,
-55,
-158,
-142,
-199,
-64,
-169,
-1,
-159,
-206,
-43,
-137,
-150,
-215,
-13,
-17,
-0,
-67,
-87,
-156,
-121,
-250,
-208,
-73,
-0,
-208,
-34,
-65,
-38,
-29,
-227,
-218,
-209,
-113,
-5,
-209,
-181,
-125,
-31,
-104,
-58,
-255,
-136,
-189,
-133,
-34,
-162,
-15,
-127,
-36,
-1,
-96,
-253,
-238,
-143,
-237,
-216,
-151,
-206,
-43,
-137,
-4,
-63,
-104,
-153,
-32,
-147,
-142,
-113,
-237,
-232,
-184,
-130,
-232,
-218,
-190,
-15,
-52,
-153,
-127,
-99,
-81,
-128,
-21,
-59,
-216,
-73,
-0,
-32,
-71,
-101,
-119,
-42,
-143,
-114,
-183,
-198,
-48,
-94,
-81,
-86,
-18,
-9,
-35,
-65,
-135,
-4,
-153,
-116,
-140,
-107,
-71,
-247,
-21,
-68,
-140,
-21,
-72,
-40,
-46,
-41,
-187,
-70,
-91,
-208,
-82,
-128,
-141,
-139,
-35,
-19,
-68,
-67,
-127,
-168,
-49,
-102,
-125,
-99,
-204,
-133,
-89,
-150,
-117,
-61,
-143,
-181,
-38,
-180,
-167,
-100,
-89,
-54,
-163,
-35,
-175,
-4,
-35,
-3,
-204,
-24,
-115,
-130,
-49,
-102,
-101,
-99,
-204,
-117,
-198,
-152,
-173,
-179,
-44,
-27,
-225,
-186,
-154,
-101,
-217,
-131,
-198,
-24,
-111,
-10,
-117,
-99,
-204,
-52,
-99,
-204,
-106,
-198,
-152,
-42,
-129,
-188,
-162,
-67,
-91,
-132,
-205,
-204,
-124,
-99,
-69,
-123,
-123,
-252,
-235,
-91,
-6,
-119,
-109,
-191,
-192,
-24,
-19,
-154,
-26,
-172,
-52,
-79,
-97,
-7,
-216,
-128,
-170,
-222,
-116,
-112,
-89,
-150,
-129,
-56,
-136,
-189,
-220,
-24,
-243,
-110,
-99,
-204,
-207,
-70,
-16,
-16,
-33,
-61,
-81,
-21,
-28,
-233,
-23,
-180,
-2,
-64,
-246,
-194,
-215,
-171,
-212,
-178,
-251,
-154,
-39,
-232,
-152,
-175,
-128,
-136,
-43,
-137,
-132,
-28,
-116,
-76,
-144,
-73,
-199,
-184,
-118,
-116,
-95,
-65,
-116,
-143,
-172,
-27,
-1,
-180,
-84,
-226,
-209,
-53,
-52,
-120,
-200,
-4,
-237,
-34,
-0,
-154,
-2,
-73,
-188,
-121,
-47,
-185,
-2,
-233,
-76,
-2,
-114,
-17,
-214,
-240,
-92,
-134,
-60,
-60,
-210,
-5,
-145,
-186,
-106,
-121,
-23,
-49,
-23,
-217,
-147,
-253,
-3,
-248,
-24,
-53,
-6,
-42,
-228,
-129,
-39,
-75,
-51,
-225,
-146,
-251,
-51,
-84,
-126,
-105,
-104,
-17,
-66,
-189,
-235,
-251,
-167,
-99,
-130,
-76,
-58,
-198,
-181,
-163,
-99,
-100,
-220,
-174,
-237,
-99,
-128,
-14,
-74,
-60,
-186,
-10,
-176,
-174,
-3,
-96,
-172,
-130,
-158,
-86,
-18,
-158,
-235,
-88,
-216,
-184,
-114,
-87,
-58,
-215,
-3,
-9,
-128,
-82,
-26,
-45,
-150,
-220,
-142,
-224,
-94,
-252,
-57,
-232,
-151,
-32,
-87,
-174,
-13,
-228,
-209,
-43,
-208,
-54,
-14,
-161,
-222,
-245,
-253,
-211,
-61,
-65,
-102,
-167,
-184,
-118,
-116,
-95,
-65,
-116,
-143,
-172,
-59,
-72,
-255,
-107,
-2,
-143,
-1,
-233,
-126,
-138,
-209,
-77,
-128,
-117,
-29,
-0,
-99,
-21,
-244,
-176,
-146,
-40,
-185,
-206,
-192,
-243,
-67,
-38,
-237,
-174,
-228,
-19,
-242,
-59,
-21,
-237,
-109,
-30,
-123,
-240,
-231,
-160,
-183,
-2,
-226,
-22,
-106,
-98,
-231,
-211,
-34,
-132,
-122,
-215,
-247,
-79,
-199,
-4,
-153,
-202,
-163,
-117,
-92,
-59,
-186,
-175,
-32,
-186,
-71,
-214,
-29,
-108,
-115,
-51,
-112,
-116,
-32,
-109,
-215,
-83,
-140,
-110,
-2,
-172,
-235,
-0,
-152,
-232,
-168,
-122,
-126,
-192,
-207,
-180,
-174,
-74,
-193,
-100,
-128,
-15,
-41,
-221,
-149,
-158,
-186,
-127,
-104,
-221,
-39,
-98,
-246,
-219,
-225,
-223,
-233,
-253,
-211,
-49,
-65,
-166,
-195,
-167,
-85,
-92,
-59,
-186,
-175,
-32,
-186,
-71,
-214,
-237,
-118,
-223,
-93,
-79,
-33,
-186,
-9,
-176,
-174,
-3,
-192,
-211,
-153,
-115,
-129,
-29,
-156,
-178,
-231,
-33,
-174,
-154,
-222,
-32,
-22,
-227,
-29,
-85,
-207,
-15,
-137,
-173,
-0,
-48,
-167,
-134,
-135,
-171,
-160,
-220,
-202,
-41,
-223,
-4,
-49,
-90,
-122,
-136,
-158,
-50,
-50,
-119,
-125,
-255,
-116,
-76,
-144,
-25,
-3,
-116,
-140,
-140,
-219,
-181,
-125,
-199,
-190,
-119,
-181,
-131,
-232,
-38,
-192,
-186,
-14,
-128,
-2,
-221,
-1,
-228,
-246,
-203,
-23,
-35,
-89,
-135,
-23,
-34,
-231,
-238,
-223,
-174,
-106,
-235,
-240,
-24,
-106,
-68,
-150,
-174,
-168,
-122,
-126,
-72,
-104,
-105,
-0,
-223,
-241,
-85,
-145,
-214,
-222,
-247,
-31,
-157,
-50,
-251,
-242,
-170,
-2,
-150,
-116,
-58,
-197,
-233,
-250,
-254,
-233,
-152,
-32,
-51,
-22,
-232,
-18,
-25,
-55,
-66,
-251,
-14,
-253,
-238,
-124,
-10,
-65,
-23,
-1,
-214,
-117,
-0,
-120,
-104,
-119,
-33,
-247,
-59,
-7,
-177,
-189,
-175,
-205,
-244,
-170,
-109,
-71,
-37,
-34,
-75,
-23,
-84,
-61,
-63,
-36,
-200,
-37,
-4,
-68,
-47,
-66,
-226,
-251,
-63,
-132,
-8,
-204,
-231,
-34,
-49,
-225,
-166,
-233,
-75,
-172,
-90,
-2,
-119,
-157,
-192,
-93,
-219,
-119,
-74,
-144,
-57,
-209,
-65,
-164,
-83,
-8,
-218,
-10,
-176,
-88,
-2,
-0,
-216,
-131,
-60,
-28,
-213,
-125,
-136,
-115,
-203,
-44,
-100,
-9,
-91,
-27,
-189,
-135,
-150,
-17,
-89,
-136,
-247,
-5,
-12,
-66,
-69,
-251,
-162,
-18,
-112,
-119,
-68,
-186,
-47,
-162,
-66,
-186,
-23,
-120,
-89,
-147,
-231,
-159,
-144,
-103,
-254,
-169,
-140,
-236,
-210,
-245,
-253,
-69,
-184,
-255,
-78,
-9,
-50,
-39,
-58,
-232,
-225,
-20,
-34,
-4,
-125,
-88,
-2,
-46,
-105,
-140,
-153,
-103,
-140,
-217,
-205,
-136,
-165,
-221,
-124,
-36,
-212,
-213,
-89,
-198,
-152,
-223,
-0,
-87,
-102,
-89,
-54,
-165,
-162,
-253,
-95,
-141,
-49,
-153,
-49,
-102,
-171,
-44,
-203,
-38,
-25,
-99,
-12,
-176,
-181,
-49,
-230,
-116,
-173,
-43,
-219,
-131,
-217,
-64,
-28,
-3,
-97,
-149,
-3,
-225,
-211,
-190,
-190,
-86,
-255,
-94,
-103,
-140,
-153,
-25,
-200,
-231,
-56,
-96,
-166,
-49,
-102,
-89,
-99,
-204,
-6,
-70,
-172,
-219,
-102,
-24,
-99,
-246,
-200,
-178,
-204,
-171,
-160,
-241,
-224,
-23,
-198,
-152,
-47,
-25,
-99,
-62,
-102,
-140,
-121,
-208,
-24,
-179,
-200,
-24,
-211,
-40,
-248,
-73,
-7,
-84,
-221,
-235,
-242,
-198,
-152,
-50,
-1,
-115,
-134,
-49,
-230,
-14,
-35,
-247,
-124,
-28,
-176,
-125,
-150,
-101,
-179,
-122,
-232,
-223,
-226,
-138,
-63,
-25,
-99,
-94,
-103,
-140,
-249,
-160,
-41,
-90,
-233,
-25,
-81,
-226,
-105,
-157,
-49,
-198,
-252,
-37,
-250,
-213,
-187,
-126,
-65,
-2,
-248,
-31,
-170,
-77,
-91,
-103,
-243,
-173,
-225,
-31,
-189,
-255,
-33,
-60,
-61,
-180,
-69,
-60,
-66,
-96,
-96,
-70,
-242,
-48,
-221,
-85,
-240,
-234,
-67,
-186,
-222,
-127,
-140,
-231,
-71,
-135,
-4,
-153,
-19,
-29,
-140,
-242,
-41,
-132,
-33,
-82,
-122,
-162,
-138,
-182,
-171,
-144,
-159,
-21,
-15,
-229,
-28,
-222,
-67,
-51,
-12,
-1,
-224,
-110,
-1,
-206,
-215,
-178,
-61,
-170,
-218,
-58,
-244,
-59,
-50,
-50,
-9,
-171,
-197,
-181,
-78,
-153,
-55,
-19,
-81,
-215,
-251,
-143,
-245,
-252,
-104,
-153,
-32,
-179,
-41,
-144,
-60,
-123,
-219,
-118,
-228,
-241,
-44,
-228,
-136,
-246,
-118,
-196,
-86,
-227,
-17,
-36,
-188,
-155,
-55,
-55,
-132,
-182,
-9,
-70,
-139,
-254,
-140,
-218,
-41,
-132,
-33,
-82,
-122,
-34,
-224,
-53,
-136,
-214,
-255,
-110,
-228,
-107,
-48,
-93,
-95,
-254,
-231,
-145,
-68,
-15,
-0,
-159,
-247,
-180,
-27,
-85,
-45,
-118,
-9,
-125,
-45,
-207,
-42,
-90,
-224,
-37,
-200,
-158,
-248,
-65,
-90,
-72,
-237,
-174,
-215,
-247,
-208,
-12,
-229,
-249,
-209,
-34,
-65,
-102,
-83,
-144,
-107,
-205,
-91,
-9,
-2,
-196,
-215,
-222,
-42,
-222,
-166,
-33,
-147,
-237,
-86,
-231,
-57,
-120,
-141,
-182,
-24,
-41,
-160,
-203,
-254,
-61,
-25,
-58,
-198,
-60,
-252,
-71,
-229,
-20,
-194,
-16,
-33,
-61,
-17,
-240,
-85,
-242,
-164,
-33,
-211,
-148,
-151,
-43,
-193,
-30,
-208,
-191,
-255,
-240,
-180,
-29,
-51,
-3,
-184,
-9,
-207,
-58,
-90,
-36,
-42,
-12,
-192,
-192,
-190,
-206,
-195,
-99,
-92,
-111,
-1,
-74,
-218,
-188,
-4,
-249,
-154,
-109,
-90,
-79,
-29,
-14,
-196,
-165,
-251,
-23,
-228,
-99,
-43,
-88,
-16,
-32,
-2,
-234,
-30,
-109,
-247,
-45,
-70,
-230,
-86,
-220,
-1,
-249,
-104,
-65,
-131,
-172,
-79,
-5,
-254,
-151,
-52,
-121,
-70,
-99,
-2,
-116,
-76,
-79,
-68,
-126,
-68,
-177,
-200,
-243,
-80,
-159,
-142,
-8,
-7,
-139,
-123,
-60,
-237,
-199,
-220,
-0,
-14,
-225,
-89,
-71,
-11,
-60,
-83,
-7,
-212,
-2,
-60,
-145,
-112,
-10,
-180,
-227,
-126,
-11,
-224,
-105,
-243,
-7,
-29,
-19,
-231,
-19,
-89,
-8,
-40,
-255,
-53,
-17,
-239,
-57,
-107,
-136,
-84,
-43,
-8,
-128,
-47,
-42,
-173,
-55,
-115,
-18,
-240,
-93,
-173,
-255,
-83,
-203,
-62,
-141,
-63,
-1,
-96,
-204,
-83,
-3,
-176,
-85,
-122,
-34,
-242,
-208,
-216,
-165,
-81,
-127,
-129,
-19,
-44,
-111,
-79,
-221,
-152,
-27,
-192,
-33,
-60,
-67,
-104,
-129,
-175,
-105,
-221,
-69,
-33,
-215,
-141,
-125,
-125,
-135,
-102,
-52,
-4,
-192,
-187,
-17,
-223,
-4,
-128,
-107,
-67,
-219,
-53,
-5,
-242,
-85,
-223,
-159,
-124,
-149,
-89,
-42,
-8,
-128,
-11,
-149,
-198,
-107,
-181,
-136,
-232,
-49,
-0,
-166,
-182,
-236,
-203,
-248,
-20,
-0,
-198,
-24,
-67,
-203,
-244,
-68,
-72,
-104,
-109,
-128,
-247,
-87,
-208,
-188,
-85,
-105,
-230,
-122,
-234,
-198,
-220,
-0,
-142,
-53,
-1,
-145,
-21,
-208,
-93,
-90,
-255,
-65,
-95,
-251,
-62,
-175,
-239,
-208,
-12,
-93,
-0,
-56,
-109,
-47,
-5,
-158,
-104,
-218,
-174,
-197,
-117,
-150,
-5,
-62,
-129,
-56,
-67,
-129,
-223,
-110,
-222,
-245,
-210,
-172,
-194,
-194,
-150,
-125,
-24,
-55,
-2,
-96,
-192,
-14,
-32,
-203,
-178,
-59,
-141,
-49,
-109,
-76,
-111,
-173,
-146,
-235,
-222,
-10,
-154,
-39,
-245,
-239,
-99,
-45,
-248,
-143,
-91,
-100,
-89,
-54,
-27,
-241,
-243,
-255,
-157,
-49,
-230,
-71,
-192,
-153,
-197,
-104,
-57,
-17,
-48,
-211,
-200,
-57,
-125,
-85,
-228,
-87,
-107,
-137,
-57,
-148,
-40,
-72,
-136,
-99,
-16,
-70,
-108,
-7,
-182,
-52,
-198,
-252,
-97,
-24,
-215,
-213,
-107,
-90,
-248,
-140,
-146,
-236,
-88,
-253,
-175,
-233,
-231,
-89,
-124,
-222,
-24,
-51,
-16,
-80,
-213,
-17,
-10,
-27,
-103,
-89,
-118,
-91,
-27,
-198,
-192,
-134,
-198,
-152,
-111,
-24,
-99,
-182,
-55,
-198,
-172,
-110,
-196,
-78,
-228,
-76,
-99,
-204,
-1,
-89,
-150,
-61,
-220,
-174,
-187,
-17,
-64,
-190,
-244,
-218,
-165,
-130,
-230,
-195,
-74,
-243,
-119,
-79,
-221,
-152,
-251,
-130,
-133,
-240,
-28,
-43,
-32,
-210,
-41,
-78,
-228,
-62,
-205,
-64,
-180,
-245,
-83,
-144,
-227,
-182,
-222,
-130,
-81,
-34,
-91,
-128,
-47,
-57,
-227,
-112,
-10,
-176,
-15,
-176,
-172,
-135,
-214,
-58,
-222,
-148,
-154,
-221,
-246,
-212,
-71,
-139,
-141,
-90,
-182,
-127,
-41,
-185,
-158,
-110,
-6,
-146,
-241,
-218,
-42,
-65,
-239,
-35,
-32,
-75,
-118,
-111,
-32,
-79,
-89,
-253,
-199,
-10,
-154,
-191,
-41,
-205,
-94,
-158,
-186,
-174,
-2,
-32,
-186,
-29,
-195,
-56,
-19,
-0,
-157,
-79,
-113,
-198,
-35,
-16,
-37,
-224,
-247,
-200,
-109,
-76,
-110,
-70,
-204,
-175,
-75,
-173,
-92,
-201,
-93,
-111,
-191,
-48,
-228,
-190,
-182,
-22,
-0,
-136,
-89,
-185,
-77,
-113,
-127,
-2,
-42,
-76,
-129,
-149,
-17,
-69,
-43,
-104,
-114,
-217,
-81,
-1,
-114,
-220,
-99,
-207,
-102,
-191,
-138,
-35,
-121,
-145,
-125,
-217,
-119,
-156,
-23,
-52,
-224,
-210,
-26,
-65,
-0,
-68,
-255,
-2,
-142,
-51,
-1,
-208,
-233,
-20,
-103,
-188,
-1,
-57,
-6,
-252,
-57,
-249,
-23,
-112,
-18,
-226,
-118,
-93,
-25,
-44,
-69,
-219,
-238,
-167,
-109,
-174,
-199,
-19,
-125,
-169,
-47,
-116,
-20,
-0,
-111,
-215,
-182,
-247,
-2,
-79,
-43,
-212,
-45,
-79,
-158,
-154,
-238,
-85,
-49,
-59,
-124,
-24,
-13,
-98,
-160,
-3,
-31,
-32,
-63,
-49,
-152,
-129,
-156,
-32,
-92,
-77,
-254,
-117,
-190,
-7,
-120,
-97,
-73,
-219,
-174,
-2,
-32,
-250,
-23,
-112,
-60,
-9,
-0,
-99,
-186,
-157,
-226,
-140,
-55,
-144,
-127,
-108,
-174,
-4,
-222,
-233,
-123,
-231,
-21,
-109,
-87,
-64,
-182,
-8,
-32,
-17,
-162,
-54,
-44,
-212,
-63,
-7,
-81,
-36,
-238,
-80,
-198,
-163,
-101,
-159,
-187,
-8,
-0,
-43,
-192,
-189,
-246,
-36,
-228,
-89,
-169,
-126,
-208,
-189,
-167,
-57,
-83,
-104,
-24,
-195,
-28,
-9,
-252,
-113,
-4,
-249,
-41,
-130,
-141,
-106,
-250,
-29,
-186,
-231,
-155,
-175,
-18,
-0,
-209,
-191,
-128,
-93,
-5,
-0,
-34,
-248,
-162,
-41,
-153,
-144,
-124,
-134,
-223,
-167,
-58,
-55,
-94,
-171,
-83,
-156,
-241,
-6,
-196,
-123,
-238,
-205,
-29,
-218,
-111,
-70,
-126,
-50,
-3,
-242,
-5,
-157,
-66,
-110,
-4,
-4,
-145,
-227,
-80,
-56,
-124,
-159,
-131,
-28,
-143,
-90,
-171,
-65,
-155,
-190,
-252,
-45,
-21,
-109,
-255,
-163,
-109,
-119,
-43,
-169,
-223,
-93,
-235,
-207,
-139,
-221,
-225,
-232,
-73,
-12,
-74,
-174,
-213,
-121,
-15,
-79,
-228,
-47,
-96,
-4,
-1,
-112,
-59,
-208,
-72,
-219,
-203,
-96,
-88,
-232,
-39,
-245,
-30,
-190,
-133,
-44,
-119,
-103,
-0,
-207,
-106,
-211,
-159,
-190,
-129,
-68,
-93,
-62,
-7,
-103,
-27,
-230,
-43,
-107,
-200,
-115,
-91,
-34,
-71,
-112,
-118,
-120,
-175,
-12,
-124,
-5,
-89,
-69,
-76,
-67,
-140,
-181,
-30,
-211,
-201,
-246,
-157,
-216,
-2,
-211,
-25,
-79,
-63,
-212,
-191,
-247,
-1,
-151,
-147,
-7,
-3,
-5,
-143,
-153,
-188,
-182,
-181,
-202,
-77,
-239,
-252,
-32,
-143,
-22,
-52,
-96,
-100,
-215,
-181,
-195,
-195,
-18,
-0,
-177,
-124,
-17,
-162,
-125,
-1,
-35,
-8,
-128,
-127,
-211,
-32,
-76,
-54,
-254,
-176,
-208,
-147,
-28,
-1,
-6,
-112,
-112,
-155,
-190,
-12,
-3,
-120,
-150,
-169,
-190,
-178,
-64,
-94,
-219,
-34,
-198,
-60,
-208,
-99,
-28,
-254,
-97,
-194,
-121,
-135,
-115,
-113,
-98,
-99,
-32,
-219,
-83,
-27,
-247,
-97,
-30,
-158,
-120,
-10,
-228,
-186,
-14,
-111,
-206,
-5,
-224,
-101,
-90,
-31,
-239,
-88,
-115,
-200,
-2,
-96,
-92,
-107,
-177,
-129,
-53,
-144,
-200,
-174,
-155,
-57,
-101,
-167,
-227,
-152,
-147,
-34,
-169,
-179,
-190,
-136,
-39,
-203,
-43,
-213,
-97,
-161,
-63,
-224,
-12,
-158,
-41,
-140,
-193,
-116,
-102,
-228,
-71,
-188,
-215,
-160,
-10,
-96,
-95,
-89,
-0,
-31,
-119,
-226,
-207,
-70,
-236,
-253,
-215,
-239,
-181,
-243,
-67,
-130,
-243,
-14,
-189,
-193,
-93,
-200,
-79,
-201,
-14,
-241,
-212,
-217,
-188,
-138,
-155,
-149,
-180,
-125,
-177,
-214,
-183,
-50,
-94,
-50,
-192,
-15,
-8,
-199,
-59,
-91,
-93,
-164,
-250,
-250,
-227,
-90,
-139,
-141,
-248,
-194,
-91,
-220,
-141,
-164,
-117,
-190,
-88,
-255,
-29,
-73,
-174,
-116,
-2,
-216,
-201,
-211,
-222,
-27,
-22,
-26,
-241,
-37,
-176,
-86,
-150,
-118,
-25,
-232,
-93,
-38,
-142,
-22,
-128,
-205,
-145,
-47,
-212,
-116,
-244,
-235,
-229,
-43,
-171,
-225,
-225,
-78,
-252,
-39,
-16,
-93,
-199,
-154,
-253,
-247,
-126,
-120,
-112,
-222,
-255,
-219,
-74,
-234,
-109,
-236,
-200,
-171,
-61,
-117,
-118,
-107,
-91,
-183,
-2,
-8,
-13,
-92,
-51,
-192,
-224,
-19,
-12,
-186,
-53,
-162,
-147,
-178,
-88,
-254,
-186,
-138,
-155,
-11,
-66,
-73,
-31,
-198,
-173,
-22,
-27,
-17,
-0,
-255,
-208,
-254,
-22,
-149,
-73,
-211,
-181,
-236,
-106,
-100,
-63,
-60,
-224,
-111,
-142,
-39,
-44,
-52,
-178,
-234,
-177,
-225,
-192,
-143,
-5,
-246,
-213,
-255,
-15,
-100,
-215,
-85,
-250,
-205,
-41,
-28,
-17,
-57,
-117,
-75,
-81,
-227,
-75,
-142,
-104,
-199,
-191,
-174,
-207,
-221,
-26,
-241,
-60,
-140,
-8,
-177,
-239,
-80,
-208,
-150,
-107,
-155,
-149,
-200,
-205,
-110,
-63,
-92,
-86,
-86,
-113,
-77,
-119,
-226,
-79,
-69,
-4,
-225,
-74,
-85,
-109,
-198,
-43,
-156,
-241,
-80,
-246,
-21,
-127,
-189,
-214,
-15,
-152,
-76,
-35,
-250,
-2,
-168,
-215,
-1,
-60,
-16,
-187,
-195,
-65,
-91,
-0,
-36,
-40,
-100,
-240,
-191,
-10,
-62,
-139,
-133,
-22,
-27,
-145,
-230,
-243,
-16,
-79,
-184,
-218,
-88,
-254,
-228,
-214,
-105,
-175,
-119,
-202,
-108,
-172,
-247,
-91,
-144,
-179,
-222,
-29,
-244,
-183,
-47,
-44,
-244,
-11,
-17,
-69,
-214,
-63,
-138,
-66,
-0,
-88,
-26,
-217,
-142,
-204,
-161,
-228,
-156,
-24,
-81,
-62,
-222,
-172,
-252,
-23,
-234,
-4,
-190,
-18,
-39,
-136,
-7,
-254,
-132,
-26,
-43,
-147,
-135,
-50,
-255,
-112,
-89,
-89,
-201,
-53,
-237,
-196,
-191,
-3,
-209,
-239,
-120,
-133,
-87,
-23,
-32,
-31,
-149,
-243,
-200,
-181,
-237,
-23,
-163,
-43,
-88,
-116,
-75,
-217,
-128,
-215,
-154,
-228,
-202,
-234,
-43,
-90,
-244,
-197,
-98,
-227,
-146,
-250,
-170,
-220,
-133,
-54,
-102,
-96,
-153,
-3,
-147,
-61,
-5,
-184,
-172,
-105,
-191,
-234,
-58,
-60,
-20,
-29,
-64,
-87,
-32,
-57,
-7,
-64,
-190,
-164,
-3,
-86,
-96,
-200,
-23,
-208,
-126,
-101,
-75,
-61,
-22,
-11,
-109,
-26,
-217,
-65,
-56,
-237,
-94,
-128,
-172,
-100,
-78,
-1,
-206,
-70,
-4,
-153,
-87,
-234,
-59,
-109,
-70,
-132,
-133,
-70,
-142,
-169,
-230,
-32,
-66,
-228,
-101,
-90,
-246,
-170,
-138,
-1,
-178,
-52,
-112,
-134,
-214,
-63,
-37,
-4,
-16,
-45,
-252,
-153,
-90,
-126,
-22,
-37,
-123,
-113,
-224,
-120,
-165,
-185,
-141,
-66,
-4,
-102,
-196,
-200,
-235,
-8,
-74,
-162,
-58,
-35,
-38,
-170,
-179,
-25,
-185,
-5,
-24,
-40,
-243,
-180,
-179,
-58,
-143,
-219,
-145,
-21,
-104,
-84,
-1,
-64,
-158,
-72,
-3,
-100,
-251,
-228,
-70,
-37,
-250,
-50,
-170,
-88,
-107,
-192,
-239,
-40,
-135,
-215,
-128,
-30,
-39,
-160,
-189,
-133,
-55,
-232,
-13,
-249,
-87,
-252,
-113,
-79,
-221,
-33,
-90,
-119,
-120,
-73,
-219,
-95,
-104,
-125,
-101,
-240,
-216,
-54,
-29,
-30,
-47,
-2,
-96,
-57,
-96,
-178,
-246,
-249,
-32,
-79,
-253,
-247,
-181,
-110,
-18,
-129,
-201,
-53,
-218,
-220,
-63,
-226,
-249,
-103,
-83,
-124,
-109,
-79,
-254,
-213,
-190,
-145,
-234,
-243,
-123,
-27,
-157,
-230,
-77,
-192,
-211,
-28,
-30,
-95,
-118,
-104,
-42,
-195,
-66,
-35,
-66,
-224,
-207,
-74,
-115,
-54,
-242,
-37,
-254,
-171,
-254,
-46,
-157,
-252,
-218,
-214,
-158,
-62,
-148,
-250,
-114,
-212,
-220,
-183,
-253,
-2,
-185,
-74,
-192,
-129,
-178,
-66,
-155,
-101,
-17,
-123,
-125,
-171,
-31,
-153,
-138,
-184,
-244,
-118,
-222,
-2,
-0,
-27,
-147,
-199,
-39,
-252,
-63,
-84,
-177,
-140,
-108,
-171,
-62,
-70,
-174,
-84,
-11,
-245,
-11,
-121,
-185,
-182,
-121,
-156,
-246,
-167,
-66,
-22,
-239,
-40,
-169,
-255,
-148,
-214,
-95,
-229,
-169,
-179,
-249,
-29,
-239,
-163,
-218,
-18,
-208,
-171,
-95,
-104,
-5,
-101,
-56,
-46,
-4,
-128,
-49,
-198,
-0,
-155,
-34,
-75,
-180,
-69,
-192,
-118,
-78,
-249,
-246,
-90,
-54,
-29,
-216,
-164,
-1,
-191,
-198,
-247,
-79,
-158,
-6,
-236,
-78,
-29,
-108,
-25,
-112,
-131,
-150,
-253,
-178,
-162,
-221,
-83,
-97,
-161,
-129,
-159,
-234,
-255,
-207,
-199,
-49,
-109,
-37,
-32,
-44,
-52,
-242,
-197,
-183,
-66,
-192,
-218,
-199,
-87,
-78,
-126,
-109,
-103,
-151,
-182,
-91,
-85,
-209,
-213,
-240,
-176,
-249,
-15,
-126,
-86,
-85,
-230,
-105,
-183,
-52,
-34,
-44,
-236,
-22,
-228,
-9,
-196,
-22,
-162,
-181,
-18,
-144,
-60,
-8,
-173,
-215,
-48,
-134,
-60,
-54,
-69,
-168,
-0,
-184,
-17,
-17,
-80,
-91,
-118,
-232,
-147,
-197,
-175,
-74,
-234,
-207,
-211,
-250,
-31,
-150,
-212,
-91,
-189,
-220,
-111,
-200,
-125,
-1,
-86,
-4,
-78,
-213,
-242,
-235,
-9,
-48,
-133,
-110,
-210,
-225,
-237,
-232,
-43,
-8,
-97,
-79,
-0,
-62,
-168,
-15,
-99,
-42,
-178,
-175,
-93,
-139,
-124,
-217,
-87,
-26,
-171,
-160,
-132,
-23,
-52,
-23,
-0,
-107,
-35,
-58,
-140,
-253,
-157,
-178,
-143,
-35,
-91,
-148,
-117,
-42,
-218,
-89,
-5,
-223,
-221,
-136,
-176,
-122,
-12,
-88,
-215,
-169,
-15,
-78,
-78,
-137,
-40,
-243,
-236,
-201,
-193,
-163,
-192,
-138,
-1,
-253,
-182,
-118,
-24,
-165,
-9,
-76,
-3,
-120,
-44,
-139,
-40,
-57,
-247,
-170,
-42,
-171,
-104,
-111,
-147,
-169,
-218,
-213,
-207,
-44,
-125,
-150,
-235,
-183,
-232,
-203,
-53,
-202,
-99,
-159,
-146,
-250,
-157,
-155,
-8,
-128,
-24,
-112,
-4,
-192,
-2,
-36,
-252,
-155,
-187,
-42,
-249,
-63,
-173,
-155,
-75,
-137,
-169,
-48,
-162,
-31,
-179,
-39,
-65,
-51,
-16,
-161,
-100,
-149,
-230,
-143,
-83,
-19,
-113,
-106,
-204,
-67,
-7,
-192,
-62,
-136,
-1,
-141,
-61,
-18,
-244,
-162,
-134,
-143,
-205,
-85,
-127,
-142,
-254,
-131,
-22,
-123,
-35,
-109,
-55,
-44,
-59,
-136,
-21,
-200,
-21,
-103,
-224,
-40,
-123,
-104,
-16,
-22,
-154,
-145,
-219,
-0,
-43,
-4,
-254,
-130,
-19,
-162,
-173,
-164,
-157,
-141,
-90,
-52,
-15,
-89,
-138,
-46,
-89,
-69,
-223,
-39,
-116,
-66,
-188,
-19,
-81,
-66,
-66,
-11,
-67,
-32,
-242,
-16,
-97,
-222,
-184,
-126,
-136,
-94,
-163,
-118,
-44,
-197,
-132,
-243,
-110,
-109,
-170,
-239,
-7,
-24,
-180,
-4,
-172,
-212,
-57,
-33,
-31,
-152,
-35,
-17,
-191,
-154,
-185,
-250,
-247,
-215,
-140,
-119,
-91,
-9,
-125,
-233,
-127,
-28,
-152,
-233,
-57,
-30,
-66,
-20,
-84,
-15,
-213,
-189,
-52,
-100,
-15,
-125,
-157,
-211,
-246,
-42,
-234,
-151,
-192,
-163,
-106,
-7,
-161,
-125,
-248,
-142,
-115,
-141,
-89,
-72,
-44,
-192,
-38,
-201,
-45,
-93,
-69,
-224,
-25,
-200,
-222,
-240,
-116,
-253,
-93,
-41,
-4,
-180,
-173,
-213,
-23,
-128,
-8,
-163,
-175,
-50,
-202,
-103,
-241,
-192,
-155,
-105,
-24,
-74,
-77,
-219,
-217,
-108,
-197,
-175,
-40,
-169,
-223,
-216,
-222,
-104,
-5,
-143,
-198,
-97,
-195,
-107,
-250,
-100,
-241,
-44,
-100,
-165,
-243,
-31,
-100,
-91,
-58,
-29,
-9,
-83,
-22,
-111,
-255,
-62,
-222,
-64,
-158,
-65,
-183,
-12,
-159,
-80,
-186,
-79,
-84,
-189,
-52,
-135,
-159,
-155,
-92,
-116,
-239,
-0,
-250,
-78,
-118,
-16,
-93,
-1,
-60,
-3,
-249,
-106,
-205,
-5,
-14,
-70,
-150,
-228,
-51,
-144,
-37,
-222,
-36,
-234,
-211,
-99,
-219,
-163,
-62,
-244,
-239,
-210,
-78,
-185,
-141,
-201,
-119,
-38,
-213,
-66,
-96,
-9,
-125,
-110,
-246,
-204,
-25,
-29,
-248,
-63,
-165,
-143,
-100,
-20,
-61,
-130,
-124,
-5,
-89,
-22,
-195,
-114,
-51,
-123,
-131,
-37,
-245,
-173,
-194,
-134,
-215,
-244,
-201,
-98,
-192,
-158,
-98,
-194,
-131,
-220,
-12,
-178,
-12,
-193,
-2,
-0,
-241,
-182,
-122,
-2,
-209,
-218,
-46,
-68,
-246,
-211,
-165,
-251,
-239,
-10,
-62,
-48,
-188,
-45,
-192,
-114,
-58,
-201,
-127,
-212,
-178,
-253,
-243,
-145,
-125,
-224,
-83,
-147,
-223,
-169,
-91,
-10,
-9,
-216,
-50,
-147,
-18,
-75,
-50,
-15,
-253,
-206,
-228,
-138,
-73,
-16,
-5,
-221,
-184,
-177,
-204,
-35,
-95,
-1,
-238,
-89,
-82,
-255,
-182,
-50,
-1,
-64,
-79,
-97,
-195,
-157,
-103,
-217,
-42,
-34,
-80,
-239,
-64,
-236,
-217,
-191,
-133,
-72,
-187,
-39,
-145,
-165,
-231,
-36,
-36,
-81,
-65,
-165,
-253,
-57,
-34,
-81,
-15,
-71,
-52,
-222,
-51,
-144,
-51,
-224,
-155,
-144,
-4,
-151,
-181,
-222,
-107,
-228,
-202,
-141,
-78,
-2,
-0,
-88,
-18,
-49,
-246,
-0,
-49,
-30,
-178,
-231,
-167,
-23,
-208,
-80,
-67,
-170,
-237,
-198,
-211,
-41,
-200,
-243,
-139,
-147,
-223,
-169,
-91,
-146,
-22,
-74,
-34,
-36,
-144,
-171,
-221,
-79,
-7,
-217,
-79,
-140,
-5,
-144,
-159,
-164,
-120,
-243,
-232,
-145,
-155,
-150,
-251,
-4,
-64,
-47,
-97,
-195,
-199,
-180,
-0,
-0,
-62,
-68,
-190,
-108,
-90,
-128,
-236,
-123,
-220,
-165,
-224,
-245,
-128,
-55,
-224,
-164,
-78,
-124,
-155,
-16,
-100,
-14,
-98,
-185,
-118,
-143,
-83,
-246,
-48,
-53,
-199,
-111,
-140,
-76,
-37,
-238,
-67,
-168,
-0,
-248,
-166,
-210,
-79,
-66,
-52,
-208,
-203,
-146,
-107,
-184,
-191,
-214,
-240,
-153,
-192,
-56,
-18,
-0,
-125,
-193,
-62,
-115,
-224,
-161,
-209,
-238,
-75,
-40,
-16,
-97,
-104,
-141,
-171,
-246,
-41,
-212,
-189,
-7,
-81,
-118,
-226,
-27,
-75,
-244,
-20,
-54,
-220,
-25,
-203,
-209,
-5,
-64,
-103,
-222,
-58,
-137,
-231,
-81,
-56,
-127,
-5,
-94,
-65,
-254,
-117,
-246,
-102,
-168,
-37,
-143,
-199,
-254,
-49,
-70,
-122,
-177,
-61,
-31,
-57,
-170,
-128,
-18,
-73,
-236,
-208,
-186,
-46,
-175,
-173,
-4,
-0,
-146,
-78,
-124,
-1,
-34,
-76,
-94,
-236,
-148,
-111,
-174,
-101,
-243,
-9,
-76,
-209,
-173,
-237,
-146,
-0,
-48,
-198,
-0,
-175,
-213,
-103,
-49,
-16,
-206,
-61,
-160,
-109,
-48,
-2,
-120,
-185,
-122,
-157,
-218,
-96,
-29,
-228,
-71,
-171,
-144,
-251,
-222,
-219,
-165,
-189,
-253,
-138,
-251,
-4,
-64,
-47,
-97,
-195,
-157,
-118,
-99,
-82,
-0,
-44,
-65,
-121,
-184,
-174,
-189,
-148,
-249,
-93,
-21,
-109,
-189,
-91,
-4,
-224,
-29,
-218,
-182,
-210,
-79,
-153,
-145,
-222,
-114,
-62,
-84,
-10,
-0,
-100,
-223,
-118,
-135,
-210,
-250,
-108,
-214,
-247,
-215,
-186,
-219,
-9,
-56,
-23,
-215,
-54,
-227,
-206,
-14,
-162,
-15,
-56,
-239,
-255,
-198,
-22,
-109,
-67,
-114,
-233,
-93,
-66,
-141,
-160,
-5,
-94,
-132,
-108,
-45,
-167,
-233,
-191,
-25,
-20,
-76,
-150,
-75,
-218,
-189,
-13,
-249,
-162,
-91,
-109,
-251,
-127,
-128,
-247,
-2,
-235,
-218,
-129,
-229,
-105,
-99,
-87,
-14,
-215,
-117,
-233,
-179,
-135,
-111,
-183,
-73,
-58,
-74,
-188,
-173,
-70,
-20,
-96,
-94,
-139,
-182,
-219,
-106,
-219,
-1,
-251,
-230,
-2,
-221,
-239,
-171,
-231,
-127,
-173,
-0,
-56,
-73,
-233,
-46,
-194,
-179,
-215,
-71,
-132,
-148,
-85,
-106,
-157,
-232,
-169,
-247,
-157,
-2,
-148,
-253,
-235,
-124,
-10,
-128,
-8,
-151,
-179,
-144,
-175,
-205,
-28,
-68,
-195,
-124,
-8,
-125,
-38,
-128,
-44,
-239,
-203,
-230,
-200,
-113,
-215,
-43,
-139,
-207,
-14,
-177,
-162,
-180,
-95,
-196,
-74,
-3,
-164,
-30,
-251,
-183,
-22,
-114,
-44,
-57,
-13,
-89,
-229,
-189,
-14,
-17,
-0,
-119,
-0,
-107,
-181,
-228,
-185,
-161,
-29,
-88,
-158,
-186,
-81,
-9,
-27,
-222,
-5,
-125,
-11,
-0,
-187,
-231,
-169,
-74,
-250,
-81,
-214,
-214,
-58,
-41,
-84,
-42,
-144,
-24,
-233,
-79,
-223,
-88,
-0,
-116,
-5,
-67,
-180,
-3,
-32,
-95,
-141,
-128,
-124,
-149,
-110,
-38,
-215,
-129,
-220,
-71,
-3,
-115,
-229,
-24,
-32,
-119,
-50,
-2,
-153,
-100,
-215,
-33,
-138,
-96,
-55,
-205,
-247,
-31,
-168,
-8,
-181,
-221,
-115,
-255,
-174,
-66,
-86,
-136,
-238,
-182,
-238,
-165,
-72,
-76,
-191,
-1,
-187,
-249,
-64,
-158,
-27,
-217,
-27,
-243,
-212,
-141,
-74,
-216,
-240,
-46,
-112,
-222,
-211,
-6,
-125,
-48,
-183,
-17,
-71,
-143,
-9,
-164,
-95,
-6,
-217,
-255,
-255,
-4,
-81,
-4,
-94,
-67,
-137,
-39,
-89,
-161,
-221,
-215,
-201,
-21,
-135,
-69,
-244,
-42,
-0,
-134,
-5,
-228,
-43,
-187,
-72,
-39,
-252,
-7,
-200,
-205,
-65,
-159,
-129,
-216,
-254,
-163,
-19,
-208,
-231,
-209,
-248,
-74,
-224,
-159,
-200,
-215,
-111,
-22,
-98,
-26,
-252,
-85,
-224,
-185,
-14,
-205,
-218,
-192,
-111,
-27,
-246,
-105,
-69,
-36,
-54,
-222,
-121,
-200,
-22,
-105,
-58,
-162,
-15,
-186,
-15,
-49,
-40,
-122,
-87,
-135,
-251,
-13,
-70,
-219,
-107,
-180,
-236,
-87,
-149,
-0,
-24,
-149,
-176,
-225,
-93,
-224,
-60,
-198,
-117,
-128,
-93,
-16,
-33,
-22,
-20,
-112,
-180,
-142,
-241,
-115,
-144,
-37,
-234,
-2,
-2,
-150,
-23,
-133,
-119,
-58,
-9,
-177,
-121,
-14,
-126,
-136,
-136,
-100,
-63,
-88,
-7,
-222,
-223,
-201,
-221,
-124,
-23,
-23,
-1,
-96,
-183,
-42,
-62,
-143,
-197,
-101,
-201,
-245,
-24,
-239,
-241,
-212,
-91,
-69,
-230,
-181,
-140,
-52,
-74,
-1,
-81,
-182,
-94,
-133,
-76,
-220,
-57,
-195,
-185,
-155,
-122,
-16,
-73,
-7,
-208,
-67,
-191,
-170,
-4,
-192,
-168,
-132,
-13,
-239,
-2,
-103,
-28,
-88,
-147,
-241,
-224,
-128,
-163,
-85,
-76,
-151,
-6,
-46,
-211,
-198,
-65,
-241,
-198,
-145,
-175,
-215,
-36,
-196,
-1,
-103,
-33,
-114,
-58,
-112,
-8,
-29,
-44,
-201,
-22,
-51,
-1,
-112,
-183,
-222,
-207,
-75,
-74,
-234,
-109,
-16,
-144,
-147,
-61,
-117,
-39,
-1,
-207,
-116,
-126,
-111,
-4,
-124,
-67,
-5,
-194,
-60,
-196,
-208,
-231,
-92,
-26,
-156,
-116,
-140,
-7,
-16,
-217,
-36,
-87,
-121,
-150,
-10,
-0,
-173,
-111,
-21,
-54,
-92,
-203,
-175,
-211,
-255,
-55,
-10,
-253,
-221,
-165,
-207,
-78,
-159,
-230,
-225,
-56,
-189,
-17,
-16,
-112,
-180,
-234,
-130,
-191,
-210,
-134,
-151,
-208,
-98,
-255,
-135,
-44,
-107,
-191,
-174,
-23,
-190,
-159,
-246,
-57,
-209,
-22,
-39,
-1,
-96,
-207,
-159,
-159,
-81,
-82,
-111,
-143,
-220,
-90,
-37,
-143,
-92,
-220,
-64,
-15,
-38,
-185,
-202,
-183,
-82,
-0,
-40,
-77,
-227,
-176,
-225,
-202,
-114,
-22,
-178,
-53,
-131,
-24,
-95,
-226,
-128,
-62,
-59,
-188,
-27,
-7,
-28,
-45,
-187,
-216,
-193,
-218,
-224,
-150,
-178,
-193,
-218,
-160,
-227,
-214,
-56,
-231,
-172,
-150,
-237,
-163,
-11,
-0,
-26,
-160,
-130,
-199,
-70,
-136,
-95,
-249,
-125,
-200,
-210,
-252,
-126,
-196,
-87,
-187,
-84,
-202,
-234,
-64,
-2,
-120,
-126,
-73,
-253,
-139,
-180,
-62,
-118,
-246,
-224,
-113,
-7,
-122,
-50,
-201,
-237,
-19,
-206,
-176,
-105,
-28,
-250,
-59,
-128,
-119,
-136,
-0,
-104,
-28,
-112,
-212,
-71,
-252,
-37,
-37,
-190,
-31,
-71,
-193,
-212,
-22,
-228,
-199,
-136,
-173,
-34,
-150,
-106,
-219,
-216,
-2,
-96,
-114,
-205,
-191,
-59,
-170,
-250,
-140,
-28,
-157,
-89,
-203,
-201,
-153,
-136,
-38,
-223,
-250,
-102,
-79,
-163,
-124,
-137,
-111,
-51,
-188,
-120,
-29,
-148,
-200,
-5,
-111,
-212,
-88,
-248,
-248,
-49,
-27,
-89,
-214,
-158,
-137,
-196,
-81,
-240,
-154,
-74,
-3,
-171,
-43,
-237,
-28,
-58,
-126,
-12,
-26,
-246,
-185,
-23,
-147,
-220,
-62,
-225,
-60,
-219,
-56,
-95,
-226,
-145,
-109,
-67,
-4,
-128,
-215,
-220,
-155,
-138,
-128,
-163,
-69,
-66,
-43,
-41,
-30,
-2,
-54,
-109,
-218,
-201,
-18,
-158,
-219,
-40,
-207,
-39,
-91,
-182,
-135,
-33,
-111,
-1,
-16,
-255,
-7,
-128,
-95,
-148,
-212,
-159,
-171,
-245,
-167,
-161,
-70,
-80,
-136,
-242,
-200,
-122,
-222,
-157,
-91,
-210,
-110,
-31,
-173,
-191,
-31,
-71,
-72,
-32,
-118,
-10,
-159,
-33,
-15,
-85,
-85,
-105,
-55,
-209,
-226,
-126,
-44,
-174,
-37,
-87,
-188,
-93,
-67,
-110,
-231,
-15,
-162,
-120,
-245,
-230,
-216,
-67,
-124,
-206,
-1,
-190,
-26,
-179,
-95,
-53,
-125,
-238,
-197,
-36,
-183,
-79,
-56,
-207,
-178,
-251,
-151,
-120,
-176,
-109,
-136,
-0,
-40,
-139,
-191,
-88,
-26,
-112,
-212,
-37,
-218,
-133,
-220,
-123,
-46,
-90,
-66,
-76,
-242,
-0,
-8,
-173,
-242,
-150,
-105,
-219,
-161,
-9,
-0,
-196,
-51,
-239,
-17,
-125,
-22,
-94,
-215,
-77,
-114,
-31,
-253,
-77,
-10,
-229,
-207,
-215,
-242,
-178,
-149,
-195,
-146,
-72,
-188,
-62,
-144,
-109,
-195,
-69,
-200,
-23,
-248,
-78,
-189,
-158,
-77,
-144,
-50,
-37,
-242,
-61,
-89,
-108,
-81,
-40,
-95,
-18,
-216,
-155,
-252,
-248,
-213,
-123,
-228,
-135,
-156,
-206,
-128,
-40,
-49,
-135,
-18,
-44,
-132,
-158,
-76,
-114,
-251,
-132,
-211,
-167,
-198,
-161,
-191,
-29,
-154,
-98,
-36,
-227,
-75,
-16,
-235,
-197,
-245,
-44,
-243,
-138,
-235,
-54,
-10,
-56,
-234,
-198,
-155,
-219,
-193,
-24,
-115,
-146,
-49,
-102,
-166,
-49,
-102,
-199,
-44,
-203,
-130,
-82,
-104,
-107,
-219,
-115,
-145,
-44,
-48,
-43,
-23,
-202,
-215,
-0,
-14,
-52,
-198,
-88,
-103,
-12,
-175,
-47,
-193,
-24,
-196,
-158,
-198,
-152,
-213,
-141,
-49,
-103,
-100,
-89,
-118,
-123,
-9,
-205,
-52,
-253,
-187,
-160,
-80,
-190,
-72,
-255,
-122,
-95,
-112,
-150,
-101,
-11,
-141,
-49,
-59,
-25,
-99,
-190,
-96,
-140,
-153,
-108,
-140,
-121,
-153,
-49,
-102,
-107,
-99,
-204,
-29,
-198,
-152,
-237,
-140,
-49,
-147,
-148,
-244,
-250,
-86,
-61,
-111,
-136,
-44,
-203,
-22,
-102,
-89,
-246,
-75,
-99,
-204,
-63,
-181,
-104,
-235,
-18,
-186,
-107,
-140,
-49,
-151,
-25,
-99,
-214,
-53,
-198,
-120,
-131,
-90,
-246,
-0,
-59,
-158,
-254,
-107,
-140,
-185,
-180,
-226,
-95,
-235,
-80,
-216,
-200,
-138,
-237,
-54,
-59,
-118,
-129,
-85,
-145,
-237,
-223,
-192,
-41,
-76,
-67,
-148,
-29,
-197,
-206,
-210,
-191,
-222,
-0,
-177,
-72,
-68,
-160,
-191,
-25,
-99,
-94,
-175,
-180,
-55,
-27,
-99,
-54,
-50,
-198,
-156,
-106,
-140,
-217,
-55,
-224,
-186,
-235,
-151,
-148,
-91,
-157,
-147,
-127,
-60,
-147,
-239,
-95,
-167,
-82,
-189,
-55,
-30,
-152,
-196,
-142,
-244,
-89,
-132,
-40,
-109,
-254,
-135,
-124,
-209,
-236,
-87,
-101,
-1,
-78,
-116,
-219,
-166,
-80,
-30,
-67,
-89,
-1,
-32,
-190,
-240,
-246,
-248,
-231,
-213,
-21,
-116,
-39,
-42,
-205,
-247,
-10,
-229,
-54,
-241,
-99,
-144,
-209,
-148,
-135,
-175,
-221,
-215,
-182,
-142,
-205,
-87,
-194,
-215,
-194,
-187,
-178,
-67,
-18,
-143,
-0,
-28,
-86,
-193,
-99,
-87,
-165,
-137,
-151,
-129,
-182,
-2,
-12,
-193,
-36,
-23,
-209,
-107,
-0,
-188,
-86,
-127,
-219,
-232,
-187,
-179,
-91,
-242,
-179,
-104,
-19,
-250,
-187,
-117,
-36,
-99,
-231,
-186,
-173,
-2,
-142,
-54,
-209,
-138,
-159,
-230,
-105,
-187,
-35,
-162,
-13,
-159,
-132,
-156,
-151,
-206,
-71,
-20,
-97,
-147,
-17,
-43,
-194,
-78,
-193,
-10,
-245,
-186,
-195,
-18,
-0,
-187,
-233,
-245,
-42,
-147,
-122,
-34,
-203,
-49,
-235,
-37,
-249,
-83,
-96,
-3,
-242,
-173,
-206,
-245,
-180,
-8,
-158,
-161,
-47,
-218,
-186,
-46,
-87,
-230,
-17,
-104,
-193,
-219,
-98,
-64,
-0,
-32,
-250,
-7,
-27,
-64,
-99,
-192,
-0,
-201,
-161,
-91,
-218,
-185,
-103,
-175,
-227,
-88,
-76,
-48,
-4,
-147,
-92,
-6,
-87,
-0,
-171,
-32,
-43,
-128,
-83,
-90,
-242,
-179,
-104,
-19,
-250,
-187,
-117,
-36,
-99,
-231,
-186,
-173,
-2,
-142,
-38,
-152,
-167,
-30,
-150,
-141,
-72,
-91,
-107,
-254,
-138,
-72,
-236,
-171,
-25,
-137,
-95,
-2,
-171,
-180,
-188,
-190,
-245,
-186,
-59,
-191,
-77,
-251,
-26,
-222,
-3,
-2,
-0,
-49,
-217,
-222,
-20,
-56,
-70,
-235,
-254,
-76,
-137,
-18,
-208,
-105,
-99,
-227,
-22,
-30,
-25,
-187,
-143,
-158,
-107,
-141,
-103,
-147,
-220,
-198,
-95,
-98,
-58,
-68,
-50,
-214,
-226,
-7,
-201,
-117,
-72,
-141,
-3,
-142,
-78,
-120,
-32,
-209,
-111,
-64,
-108,
-31,
-106,
-163,
-7,
-233,
-132,
-189,
-23,
-145,
-186,
-214,
-113,
-230,
-6,
-26,
-154,
-136,
-34,
-193,
-59,
-191,
-170,
-124,
-102,
-81,
-178,
-124,
-236,
-2,
-170,
-113,
-17,
-162,
-195,
-169,
-156,
-252,
-202,
-231,
-89,
-200,
-57,
-246,
-116,
-122,
-142,
-19,
-200,
-248,
-54,
-201,
-109,
-252,
-37,
-166,
-67,
-36,
-99,
-45,
-254,
-147,
-254,
-63,
-5,
-28,
-109,
-3,
-114,
-119,
-225,
-79,
-214,
-208,
-45,
-1,
-252,
-86,
-105,
-47,
-70,
-52,
-255,
-203,
-34,
-73,
-61,
-158,
-64,
-116,
-31,
-7,
-86,
-180,
-255,
-53,
-146,
-190,
-235,
-207,
-72,
-8,
-116,
-27,
-12,
-229,
-1,
-122,
-74,
-126,
-234,
-12,
-76,
-247,
-24,
-240,
-74,
-36,
-142,
-224,
-2,
-189,
-247,
-215,
-4,
-242,
-58,
-89,
-121,
-125,
-174,
-143,
-190,
-22,
-174,
-213,
-202,
-36,
-55,
-128,
-175,
-133,
-111,
-34,
-214,
-90,
-9,
-6,
-240,
-109,
-28,
-250,
-155,
-8,
-145,
-140,
-19,
-90,
-2,
-241,
-51,
-7,
-9,
-95,
-86,
-153,
-58,
-140,
-220,
-162,
-235,
-66,
-10,
-81,
-118,
-145,
-175,
-210,
-157,
-90,
-255,
-145,
-146,
-246,
-199,
-32,
-147,
-126,
-1,
-114,
-212,
-117,
-33,
-98,
-244,
-210,
-219,
-23,
-213,
-25,
-124,
-190,
-99,
-192,
-143,
-146,
-7,
-80,
-173,
-253,
-154,
-146,
-43,
-202,
-110,
-33,
-96,
-213,
-208,
-21,
-180,
-48,
-201,
-13,
-224,
-217,
-183,
-0,
-104,
-28,
-250,
-155,
-142,
-145,
-140,
-163,
-0,
-241,
-40,
-67,
-59,
-28,
-108,
-245,
-165,
-15,
-237,
-24,
-68,
-241,
-247,
-184,
-182,
-191,
-9,
-113,
-96,
-241,
-90,
-197,
-105,
-187,
-189,
-169,
-135,
-215,
-168,
-166,
-192,
-103,
-101,
-100,
-207,
-120,
-33,
-50,
-169,
-230,
-107,
-31,
-130,
-246,
-170,
-228,
-201,
-52,
-106,
-181,
-239,
-228,
-169,
-175,
-203,
-94,
-148,
-205,
-225,
-55,
-102,
-236,
-249,
-157,
-103,
-89,
-119,
-10,
-16,
-116,
-164,
-134,
-172,
-36,
-96,
-12,
-45,
-191,
-155,
-192,
-121,
-30,
-125,
-9,
-128,
-198,
-161,
-191,
-233,
-16,
-201,
-56,
-26,
-144,
-244,
-67,
-54,
-209,
-96,
-80,
-54,
-29,
-196,
-44,
-214,
-218,
-184,
-207,
-69,
-20,
-105,
-215,
-144,
-47,
-211,
-230,
-1,
-59,
-149,
-180,
-253,
-134,
-210,
-84,
-29,
-63,
-86,
-30,
-169,
-33,
-150,
-134,
-110,
-84,
-225,
-7,
-181,
-221,
-20,
-224,
-204,
-128,
-254,
-111,
-138,
-44,
-219,
-103,
-19,
-32,
-244,
-200,
-29,
-122,
-188,
-209,
-142,
-129,
-103,
-107,
-253,
-88,
-114,
-203,
-173,
-19,
-0,
-31,
-209,
-250,
-89,
-190,
-122,
-15,
-253,
-158,
-74,
-223,
-202,
-191,
-99,
-180,
-49,
-4,
-1,
-208,
-88,
-219,
-78,
-135,
-72,
-198,
-81,
-1,
-108,
-73,
-30,
-87,
-255,
-229,
-1,
-244,
-103,
-105,
-191,
-46,
-99,
-100,
-64,
-209,
-229,
-200,
-143,
-46,
-38,
-151,
-180,
-181,
-254,
-203,
-94,
-205,
-103,
-192,
-181,
-55,
-35,
-183,
-202,
-251,
-13,
-133,
-227,
-41,
-2,
-180,
-199,
-228,
-49,
-7,
-74,
-147,
-119,
-22,
-232,
-173,
-75,
-175,
-247,
-235,
-135,
-88,
-84,
-2,
-220,
-20,
-118,
-23,
-253,
-35,
-64,
-0,
-216,
-19,
-136,
-202,
-216,
-141,
-14,
-253,
-211,
-17,
-47,
-189,
-133,
-244,
-17,
-133,
-166,
-103,
-140,
-81,
-1,
-208,
-58,
-146,
-113,
-116,
-168,
-16,
-120,
-0,
-184,
-33,
-128,
-214,
-106,
-47,
-7,
-98,
-229,
-145,
-155,
-144,
-122,
-191,
-134,
-192,
-41,
-90,
-223,
-202,
-186,
-140,
-252,
-88,
-165,
-84,
-233,
-86,
-211,
-126,
-29,
-125,
-176,
-139,
-8,
-244,
-208,
-34,
-63,
-175,
-189,
-157,
-130,
-177,
-16,
-98,
-19,
-97,
-87,
-80,
-251,
-151,
-241,
-24,
-54,
-2,
-4,
-128,
-117,
-253,
-190,
-188,
-1,
-79,
-123,
-228,
-116,
-104,
-188,
-158,
-14,
-7,
-99,
-81,
-0,
-104,
-251,
-170,
-72,
-198,
-95,
-71,
-21,
-198,
-109,
-120,
-247,
-134,
-154,
-135,
-121,
-144,
-214,
-253,
-179,
-164,
-237,
-249,
-90,
-95,
-187,
-210,
-240,
-180,
-125,
-177,
-182,
-157,
-66,
-77,
-242,
-203,
-10,
-30,
-118,
-50,
-255,
-185,
-65,
-155,
-21,
-201,
-189,
-250,
-64,
-190,
-132,
-55,
-50,
-50,
-161,
-233,
-25,
-4,
-158,
-93,
-3,
-107,
-146,
-167,
-231,
-190,
-34,
-176,
-77,
-211,
-16,
-217,
-22,
-69,
-37,
-96,
-6,
-236,
-65,
-174,
-129,
-174,
-205,
-226,
-235,
-180,
-125,
-46,
-185,
-239,
-200,
-114,
-161,
-237,
-106,
-250,
-215,
-118,
-226,
-108,
-139,
-124,
-76,
-110,
-211,
-73,
-50,
-3,
-49,
-170,
-58,
-20,
-143,
-14,
-170,
-102,
-204,
-142,
-154,
-0,
-80,
-30,
-222,
-72,
-198,
-90,
-119,
-93,
-155,
-228,
-11,
-222,
-105,
-0,
-0,
-32,
-0,
-73,
-68,
-65,
-84,
-126,
-245,
-10,
-223,
-77,
-35,
-103,
-184,
-54,
-55,
-252,
-109,
-192,
-179,
-75,
-218,
-94,
-175,
-52,
-222,
-250,
-154,
-235,
-30,
-168,
-109,
-127,
-210,
-178,
-223,
-171,
-146,
-235,
-41,
-26,
-69,
-250,
-69,
-172,
-226,
-246,
-65,
-142,
-207,
-30,
-211,
-9,
-244,
-40,
-18,
-179,
-239,
-169,
-88,
-127,
-129,
-188,
-142,
-210,
-62,
-60,
-0,
-60,
-39,
-128,
-190,
-113,
-136,
-108,
-231,
-29,
-185,
-199,
-128,
-151,
-147,
-103,
-16,
-6,
-57,
-222,
-107,
-154,
-61,
-233,
-47,
-218,
-246,
-227,
-77,
-218,
-85,
-244,
-175,
-205,
-210,
-217,
-21,
-134,
-183,
-35,
-177,
-18,
-239,
-33,
-55,
-157,
-29,
-88,
-29,
-86,
-93,
-143,
-252,
-195,
-50,
-42,
-2,
-96,
-84,
-65,
-139,
-240,
-75,
-197,
-155,
-70,
-190,
-12,
-54,
-106,
-203,
-239,
-168,
-176,
-140,
-115,
-6,
-224,
-13,
-228,
-122,
-135,
-25,
-136,
-34,
-241,
-48,
-96,
-227,
-138,
-182,
-214,
-183,
-250,
-3,
-136,
-34,
-240,
-92,
-228,
-4,
-194,
-102,
-214,
-221,
-151,
-81,
-138,
-100,
-27,
-10,
-36,
-86,
-194,
-66,
-237,
-119,
-173,
-7,
-38,
-45,
-67,
-100,
-227,
-199,
-34,
-114,
-161,
-181,
-107,
-203,
-254,
-91,
-151,
-220,
-255,
-182,
-105,
-239,
-233,
-95,
-27,
-1,
-96,
-141,
-176,
-182,
-43,
-148,
-175,
-130,
-152,
-118,
-15,
-40,
-107,
-201,
-133,
-195,
-139,
-60,
-117,
-54,
-151,
-197,
-216,
-250,
-210,
-246,
-13,
-90,
-134,
-95,
-42,
-190,
-60,
-242,
-188,
-238,
-181,
-54,
-220,
-192,
-57,
-74,
-251,
-24,
-18,
-84,
-99,
-50,
-249,
-30,
-26,
-68,
-8,
-121,
-191,
-46,
-228,
-86,
-98,
-135,
-32,
-95,
-224,
-123,
-144,
-47,
-210,
-69,
-228,
-10,
-147,
-191,
-50,
-138,
-185,
-238,
-235,
-128,
-108,
-29,
-166,
-2,
-91,
-6,
-210,
-71,
-15,
-145,
-61,
-22,
-208,
-81,
-0,
-216,
-49,
-251,
-170,
-6,
-109,
-236,
-24,
-123,
-183,
-167,
-238,
-232,
-9,
-39,
-0,
-232,
-16,
-126,
-201,
-35,
-0,
-172,
-86,
-62,
-40,
-35,
-47,
-158,
-76,
-61,
-192,
-243,
-200,
-45,
-206,
-22,
-1,
-219,
-122,
-104,
-158,
-112,
-234,
-191,
-228,
-78,
-116,
-196,
-108,
-210,
-30,
-13,
-214,
-166,
-7,
-79,
-24,
-93,
-116,
-20,
-0,
-214,
-131,
-114,
-26,
-18,
-200,
-165,
-54,
-89,
-8,
-185,
-221,
-199,
-21,
-56,
-33,
-235,
-17,
-109,
-187,
-213,
-196,
-79,
-40,
-1,
-208,
-58,
-252,
-146,
-71,
-0,
-156,
-161,
-191,
-255,
-71,
-71,
-175,
-54,
-135,
-215,
-217,
-158,
-58,
-171,
-184,
-250,
-105,
-73,
-91,
-107,
-100,
-84,
-233,
-217,
-151,
-48,
-250,
-112,
-198,
-208,
-250,
-72,
-120,
-178,
-43,
-244,
-67,
-242,
-36,
-178,
-69,
-169,
-212,
-209,
-0,
-7,
-56,
-60,
-230,
-35,
-137,
-76,
-94,
-91,
-65,
-255,
-26,
-103,
-252,
-204,
-64,
-156,
-186,
-172,
-201,
-241,
-183,
-24,
-35,
-218,
-118,
-2,
-17,
-227,
-66,
-173,
-195,
-47,
-57,
-253,
-176,
-2,
-96,
-53,
-196,
-198,
-29,
-100,
-41,
-254,
-77,
-90,
-46,
-195,
-145,
-99,
-53,
-240,
-251,
-79,
-91,
-205,
-185,
-55,
-12,
-54,
-98,
-224,
-3,
-53,
-161,
-200,
-144,
-213,
-198,
-137,
-200,
-82,
-124,
-62,
-178,
-31,
-191,
-4,
-201,
-224,
-227,
-205,
-136,
-172,
-237,
-90,
-5,
-147,
-64,
-146,
-119,
-124,
-13,
-81,
-194,
-77,
-211,
-107,
-78,
-69,
-132,
-221,
-86,
-177,
-219,
-141,
-7,
-56,
-99,
-200,
-166,
-115,
-191,
-27,
-217,
-130,
-218,
-119,
-60,
-159,
-146,
-248,
-12,
-192,
-203,
-144,
-45,
-228,
-99,
-200,
-135,
-234,
-50,
-135,
-223,
-241,
-192,
-178,
-37,
-237,
-222,
-128,
-156,
-66,
-77,
-67,
-38,
-252,
-53,
-168,
-249,
-54,
-37,
-218,
-246,
-226,
-88,
-47,
-212,
-133,
-132,
-236,
-170,
-132,
-167,
-93,
-85,
-46,
-5,
-107,
-143,
-210,
-42,
-212,
-94,
-241,
-66,
-173,
-195,
-47,
-249,
-30,
-10,
-162,
-37,
-255,
-6,
-121,
-128,
-131,
-179,
-129,
-167,
-181,
-232,
-151,
-245,
-128,
-26,
-8,
-208,
-128,
-40,
-42,
-161,
-160,
-252,
-113,
-234,
-159,
-161,
-245,
-165,
-89,
-109,
-17,
-187,
-118,
-235,
-140,
-51,
-23,
-209,
-67,
-184,
-105,
-209,
-75,
-99,
-236,
-211,
-50,
-152,
-4,
-185,
-185,
-245,
-124,
-228,
-20,
-228,
-42,
-242,
-237,
-204,
-2,
-224,
-245,
-49,
-219,
-85,
-244,
-227,
-45,
-218,
-54,
-232,
-232,
-209,
-211,
-126,
-64,
-168,
-35,
-19,
-174,
-18,
-37,
-188,
-44,
-230,
-3,
-187,
-56,
-229,
-171,
-59,
-247,
-93,
-182,
-58,
-181,
-31,
-155,
-55,
-59,
-101,
-219,
-144,
-7,
-118,
-245,
-174,
-16,
-219,
-192,
-233,
-103,
-83,
-1,
-112,
-82,
-200,
-191,
-6,
-253,
-88,
-146,
-252,
-4,
-173,
-117,
-176,
-29,
-151,
-97,
-235,
-140,
-168,
-53,
-15,
-101,
-11,
-114,
-79,
-168,
-160,
-228,
-34,
-133,
-246,
-239,
-212,
-182,
-183,
-122,
-234,
-172,
-17,
-145,
-247,
-1,
-144,
-11,
-143,
-187,
-43,
-248,
-219,
-243,
-252,
-75,
-113,
-204,
-128,
-17,
-171,
-172,
-255,
-171,
-233,
-91,
-171,
-96,
-18,
-136,
-78,
-229,
-211,
-56,
-206,
-63,
-136,
-213,
-164,
-221,
-151,
-150,
-5,
-20,
-109,
-213,
-174,
-162,
-31,
-246,
-20,
-197,
-187,
-234,
-83,
-154,
-181,
-17,
-99,
-171,
-199,
-245,
-126,
-183,
-208,
-242,
-221,
-128,
-251,
-60,
-244,
-239,
-69,
-242,
-44,
-22,
-255,
-253,
-81,
-175,
-229,
-181,
-52,
-116,
-198,
-208,
-81,
-158,
-58,
-235,
-7,
-255,
-96,
-73,
-91,
-43,
-192,
-87,
-45,
-148,
-111,
-169,
-229,
-211,
-124,
-237,
-218,
-160,
-102,
-172,
-183,
-182,
-31,
-104,
-209,
-15,
-107,
-185,
-121,
-55,
-45,
-62,
-172,
-62,
-134,
-173,
-195,
-47,
-85,
-61,
-20,
-173,
-183,
-166,
-177,
-222,
-244,
-226,
-53,
-188,
-173,
-153,
-241,
-64,
-116,
-94,
-29,
-108,
-32,
-202,
-203,
-1,
-15,
-62,
-224,
-251,
-90,
-95,
-154,
-43,
-143,
-124,
-133,
-210,
-58,
-99,
-75,
-44,
-144,
-123,
-36,
-54,
-90,
-210,
-181,
-105,
-135,
-100,
-199,
-93,
-132,
-28,
-161,
-121,
-151,
-200,
-74,
-119,
-28,
-178,
-23,
-159,
-172,
-244,
-139,
-244,
-255,
-179,
-8,
-207,
-21,
-185,
-20,
-249,
-87,
-220,
-235,
-106,
-237,
-140,
-161,
-1,
-111,
-57,
-242,
-92,
-9,
-197,
-248,
-139,
-182,
-222,
-58,
-103,
-125,
-177,
-80,
-190,
-154,
-150,
-63,
-28,
-210,
-207,
-16,
-140,
-5,
-1,
-128,
-196,
-143,
-176,
-10,
-238,
-82,
-225,
-221,
-148,
-105,
-235,
-240,
-75,
-1,
-2,
-96,
-11,
-173,
-247,
-45,
-227,
-255,
-12,
-236,
-4,
-172,
-84,
-40,
-127,
-22,
-185,
-121,
-234,
-116,
-96,
-125,
-79,
-219,
-165,
-200,
-61,
-168,
-46,
-70,
-181,
-191,
-136,
-117,
-219,
-222,
-200,
-228,
-94,
-68,
-197,
-241,
-144,
-211,
-247,
-129,
-243,
-224,
-97,
-131,
-138,
-156,
-245,
-177,
-219,
-1,
-63,
-214,
-38,
-3,
-57,
-10,
-11,
-116,
-83,
-129,
-15,
-232,
-255,
-95,
-140,
-172,
-2,
-108,
-154,
-171,
-160,
-212,
-220,
-136,
-82,
-13,
-224,
-156,
-10,
-26,
-139,
-1,
-165,
-113,
-221,
-196,
-66,
-44,
-231,
-108,
-252,
-201,
-19,
-201,
-117,
-81,
-54,
-191,
-197,
-9,
-33,
-253,
-12,
-188,
-151,
-210,
-177,
-94,
-215,
-207,
-136,
-125,
-248,
-182,
-94,
-230,
-26,
-98,
-185,
-99,
-211,
-33,
-252,
-146,
-251,
-80,
-244,
-101,
-63,
-203,
-169,
-91,
-154,
-220,
-34,
-112,
-96,
-175,
-233,
-180,
-93,
-132,
-68,
-215,
-185,
-158,
-145,
-250,
-136,
-71,
-41,
-217,
-227,
-107,
-251,
-231,
-147,
-239,
-217,
-231,
-33,
-123,
-120,
-55,
-88,
-68,
-229,
-254,
-200,
-161,
-107,
-44,
-0,
-104,
-153,
-179,
-14,
-17,
-92,
-31,
-68,
-142,
-57,
-39,
-33,
-210,
-124,
-58,
-185,
-86,
-186,
-108,
-160,
-183,
-106,
-231,
-225,
-179,
-28,
-121,
-32,
-144,
-245,
-234,
-250,
-26,
-194,
-179,
-162,
-253,
-75,
-245,
-189,
-60,
-65,
-197,
-177,
-176,
-59,
-134,
-60,
-117,
-33,
-105,
-188,
-94,
-67,
-190,
-202,
-88,
-132,
-40,
-74,
-23,
-33,
-218,
-253,
-213,
-187,
-220,
-67,
-204,
-126,
-70,
-184,
-254,
-51,
-201,
-21,
-163,
-241,
-130,
-165,
-210,
-33,
-252,
-146,
-251,
-80,
-156,
-23,
-112,
-51,
-98,
-16,
-100,
-39,
-243,
-130,
-146,
-182,
-111,
-67,
-162,
-235,
-220,
-138,
-44,
-43,
-109,
-176,
-135,
-203,
-144,
-211,
-131,
-218,
-224,
-154,
-136,
-178,
-239,
-80,
-229,
-49,
-87,
-219,
-159,
-77,
-64,
-242,
-72,
-167,
-239,
-141,
-4,
-0,
-237,
-141,
-166,
-214,
-36,
-247,
-165,
-183,
-207,
-197,
-70,
-82,
-182,
-171,
-25,
-159,
-18,
-169,
-85,
-187,
-146,
-62,
-216,
-253,
-227,
-233,
-77,
-238,
-185,
-41,
-144,
-152,
-131,
-54,
-198,
-226,
-110,
-53,
-180,
-79,
-141,
-33,
-79,
-93,
-240,
-196,
-2,
-94,
-133,
-172,
-28,
-109,
-148,
-235,
-203,
-112,
-18,
-170,
-118,
-69,
-172,
-126,
-118,
-184,
-190,
-141,
-223,
-248,
-215,
-62,
-152,
-119,
-201,
-136,
-138,
-62,
-128,
-189,
-244,
-161,
-79,
-67,
-36,
-255,
-20,
-100,
-153,
-223,
-200,
-214,
-190,
-111,
-144,
-107,
-240,
-189,
-168,
-105,
-219,
-197,
-104,
-234,
-55,
-90,
-55,
-21,
-49,
-58,
-121,
-186,
-83,
-87,
-165,
-69,
-110,
-213,
-174,
-164,
-255,
-255,
-85,
-242,
-202,
-47,
-8,
-29,
-143,
-29,
-17,
-229,
-31,
-4,
-164,
-238,
-114,
-199,
-144,
-167,
-174,
-241,
-196,
-66,
-78,
-15,
-78,
-213,
-102,
-165,
-91,
-143,
-166,
-168,
-233,
-103,
-175,
-17,
-123,
-128,
-23,
-34,
-130,
-127,
-1,
-125,
-69,
-101,
-166,
-135,
-240,
-75,
-99,
-17,
-136,
-143,
-194,
-105,
-206,
-11,
-61,
-71,
-127,
-159,
-134,
-39,
-244,
-121,
-161,
-109,
-23,
-163,
-41,
-187,
-106,
-24,
-8,
-23,
-70,
-158,
-67,
-209,
-39,
-0,
-90,
-181,
-243,
-208,
-110,
-173,
-164,
-33,
-110,
-222,
-173,
-143,
-29,
-17,
-197,
-164,
-13,
-150,
-26,
-178,
-138,
-171,
-154,
-88,
-173,
-190,
-172,
-136,
-16,
-128,
-192,
-32,
-39,
-129,
-60,
-45,
-124,
-62,
-4,
-189,
-70,
-236,
-33,
-63,
-181,
-57,
-186,
-15,
-254,
-19,
-18,
-85,
-47,
-180,
-162,
-77,
-23,
-163,
-41,
-123,
-234,
-176,
-173,
-167,
-206,
-38,
-21,
-241,
-9,
-128,
-86,
-237,
-60,
-180,
-246,
-171,
-248,
-169,
-0,
-218,
-182,
-199,
-149,
-79,
-71,
-182,
-128,
-224,
-177,
-181,
-47,
-105,
-211,
-74,
-0,
-32,
-142,
-103,
-251,
-81,
-80,
-18,
-35,
-129,
-91,
-191,
-172,
-205,
-188,
-193,
-104,
-218,
-192,
-233,
-167,
-207,
-135,
-224,
-136,
-190,
-4,
-0,
-121,
-66,
-145,
-25,
-44,
-38,
-31,
-225,
-49,
-129,
-150,
-2,
-160,
-139,
-209,
-148,
-221,
-175,
-31,
-135,
-42,
-216,
-116,
-176,
-238,
-69,
-133,
-50,
-175,
-109,
-187,
-2,
-143,
-103,
-145,
-39,
-109,
-25,
-240,
-191,
-104,
-112,
-255,
-149,
-199,
-142,
-136,
-98,
-20,
-224,
-196,
-6,
-60,
-45,
-154,
-10,
-128,
-45,
-156,
-182,
-83,
-145,
-149,
-235,
-21,
-228,
-43,
-166,
-57,
-56,
-6,
-66,
-93,
-225,
-92,
-171,
-232,
-67,
-240,
-46,
-122,
-138,
-216,
-163,
-239,
-217,
-234,
-127,
-190,
-21,
-147,
-247,
-168,
-163,
-234,
-197,
-7,
-180,
-253,
-56,
-18,
-94,
-123,
-153,
-170,
-178,
-138,
-246,
-75,
-59,
-215,
-127,
-126,
-29,
-189,
-211,
-174,
-139,
-209,
-212,
-78,
-133,
-1,
-123,
-53,
-185,
-13,
-198,
-126,
-168,
-34,
-54,
-86,
-187,
-2,
-15,
-107,
-47,
-255,
-243,
-208,
-123,
-45,
-225,
-83,
-122,
-236,
-136,
-36,
-191,
-180,
-39,
-58,
-193,
-9,
-82,
-170,
-198,
-1,
-213,
-2,
-96,
-57,
-224,
-115,
-250,
-188,
-109,
-92,
-134,
-199,
-16,
-229,
-227,
-49,
-68,
-202,
-112,
-237,
-233,
-39,
-228,
-62,
-4,
-174,
-242,
-124,
-126,
-221,
-123,
-104,
-113,
-205,
-143,
-40,
-255,
-7,
-0,
-111,
-78,
-193,
-113,
-139,
-170,
-23,
-31,
-208,
-214,
-198,
-19,
-60,
-162,
-170,
-172,
-162,
-253,
-122,
-206,
-245,
-87,
-171,
-163,
-119,
-218,
-117,
-202,
-89,
-135,
-248,
-155,
-95,
-142,
-40,
-11,
-167,
-33,
-166,
-172,
-239,
-214,
-186,
-147,
-203,
-6,
-80,
-219,
-118,
-90,
-239,
-166,
-245,
-10,
-18,
-118,
-180,
-56,
-118,
-116,
-38,
-195,
-121,
-248,
-45,
-2,
-127,
-0,
-172,
-27,
-246,
-164,
-198,
-30,
-156,
-241,
-178,
-23,
-114,
-234,
-51,
-15,
-17,
-118,
-135,
-33,
-6,
-58,
-255,
-139,
-41,
-0,
-144,
-237,
-148,
-85,
-56,
-119,
-10,
-186,
-210,
-244,
-194,
-0,
-199,
-55,
-108,
-179,
-153,
-14,
-208,
-25,
-192,
-5,
-84,
-4,
-243,
-40,
-92,
-167,
-173,
-0,
-88,
-150,
-124,
-105,
-180,
-91,
-89,
-89,
-69,
-123,
-155,
-171,
-189,
-209,
-30,
-145,
-33,
-228,
-172,
-139,
-13,
-36,
-104,
-10,
-4,
-154,
-11,
-211,
-254,
-184,
-50,
-4,
-193,
-126,
-251,
-99,
-13,
-206,
-61,
-84,
-218,
-79,
-68,
-188,
-222,
-87,
-236,
-24,
-101,
-152,
-113,
-45,
-90,
-10,
-128,
-203,
-145,
-229,
-247,
-54,
-136,
-86,
-253,
-162,
-192,
-235,
-180,
-18,
-0,
-218,
-254,
-121,
-136,
-192,
-153,
-137,
-6,
-201,
-240,
-149,
-121,
-218,
-109,
-133,
-236,
-229,
-231,
-18,
-96,
-47,
-80,
-104,
-59,
-30,
-115,
-214,
-89,
-135,
-153,
-218,
-156,
-135,
-74,
-31,
-237,
-216,
-113,
-113,
-130,
-51,
-94,
-135,
-18,
-9,
-153,
-60,
-206,
-228,
-221,
-52,
-216,
-106,
-182,
-189,
-216,
-26,
-136,
-59,
-166,
-53,
-222,
-88,
-136,
-44,
-233,
-206,
-69,
-114,
-215,
-85,
-38,
-59,
-208,
-9,
-103,
-131,
-23,
-238,
-2,
-76,
-15,
-184,
-102,
-39,
-1,
-160,
-60,
-62,
-172,
-60,
-110,
-69,
-77,
-138,
-125,
-101,
-37,
-215,
-125,
-130,
-234,
-116,
-232,
-3,
-171,
-3,
-198,
-89,
-206,
-58,
-114,
-167,
-168,
-187,
-8,
-252,
-138,
-16,
-233,
-216,
-113,
-113,
-67,
-140,
-241,
-218,
-242,
-122,
-149,
-136,
-113,
-161,
-13,
-200,
-227,
-243,
-89,
-239,
-170,
-39,
-201,
-205,
-14,
-161,
-102,
-201,
-139,
-104,
-96,
-207,
-66,
-206,
-154,
-207,
-1,
-46,
-108,
-112,
-131,
-27,
-21,
-202,
-215,
-118,
-38,
-217,
-55,
-107,
-120,
-216,
-201,
-126,
-39,
-185,
-103,
-222,
-64,
-89,
-201,
-117,
-91,
-61,
-92,
-122,
-202,
-89,
-215,
-7,
-144,
-92,
-132,
-0,
-95,
-105,
-208,
-38,
-202,
-177,
-99,
-108,
-208,
-62,
-6,
-67,
-171,
-140,
-87,
-30,
-62,
-222,
-241,
-58,
-238,
-1,
-252,
-93,
-111,
-236,
-100,
-228,
-11,
-7,
-226,
-219,
-157,
-33,
-129,
-53,
-190,
-10,
-172,
-80,
-195,
-99,
-115,
-228,
-120,
-100,
-38,
-226,
-156,
-83,
-27,
-103,
-223,
-247,
-64,
-245,
-250,
-54,
-237,
-118,
-93,
-86,
-160,
-231,
-233,
-75,
-157,
-141,
-134,
-127,
-246,
-149,
-245,
-1,
-250,
-203,
-89,
-119,
-157,
-254,
-191,
-113,
-100,
-28,
-15,
-191,
-213,
-180,
-253,
-156,
-38,
-3,
-159,
-8,
-199,
-142,
-125,
-128,
-246,
-49,
-24,
-26,
-103,
-188,
-42,
-225,
-179,
-216,
-10,
-0,
-251,
-213,
-127,
-174,
-254,
-134,
-134,
-58,
-128,
-150,
-215,
-29,
-241,
-64,
-17,
-205,
-179,
-21,
-70,
-103,
-81,
-177,
-100,
-101,
-164,
-194,
-239,
-163,
-101,
-101,
-227,
-9,
-218,
-239,
-89,
-136,
-9,
-46,
-52,
-136,
-140,
-19,
-185,
-31,
-157,
-143,
-29,
-27,
-92,
-43,
-56,
-47,
-2,
-45,
-99,
-48,
-40,
-109,
-163,
-140,
-87,
-37,
-60,
-22,
-91,
-1,
-96,
-131,
-118,
-188,
-64,
-127,
-15,
-91,
-0,
-172,
-171,
-191,
-173,
-179,
-195,
-21,
-212,
-156,
-121,
-146,
-31,
-249,
-29,
-85,
-85,
-54,
-158,
-224,
-60,
-143,
-198,
-145,
-113,
-122,
-232,
-75,
-235,
-99,
-199,
-134,
-215,
-105,
-148,
-23,
-161,
-227,
-181,
-130,
-51,
-94,
-77,
-40,
-144,
-107,
-125,
-207,
-71,
-210,
-101,
-5,
-11,
-0,
-58,
-56,
-141,
-56,
-3,
-126,
-37,
-242,
-175,
-222,
-109,
-132,
-217,
-143,
-239,
-133,
-232,
-26,
-150,
-169,
-42,
-27,
-79,
-112,
-158,
-71,
-227,
-200,
-56,
-227,
-17,
-52,
-204,
-139,
-176,
-56,
-3,
-120,
-1,
-146,
-165,
-249,
-78,
-68,
-7,
-243,
-32,
-178,
-157,
-252,
-70,
-9,
-125,
-20,
-189,
-134,
-101,
-182,
-22,
-185,
-59,
-171,
-53,
-105,
-60,
-139,
-138,
-104,
-49,
-158,
-142,
-180,
-113,
-26,
-65,
-7,
-192,
-251,
-201,
-131,
-58,
-116,
-138,
-36,
-60,
-158,
-225,
-8,
-128,
-198,
-145,
-113,
-198,
-35,
-104,
-144,
-23,
-161,
-203,
-135,
-102,
-172,
-3,
-9,
-125,
-103,
-183,
-225,
-243,
-17,
-155,
-11,
-155,
-113,
-219,
-235,
-250,
-75,
-36,
-189,
-134,
-203,
-112,
-5,
-196,
-189,
-213,
-77,
-181,
-253,
-40,
-146,
-130,
-107,
-224,
-40,
-205,
-105,
-215,
-58,
-86,
-157,
-35,
-0,
-102,
-59,
-215,
-236,
-100,
-170,
-218,
-7,
-144,
-147,
-141,
-63,
-170,
-144,
-156,
-141,
-40,
-58,
-39,
-35,
-22,
-96,
-3,
-251,
-73,
-231,
-94,
-26,
-125,
-213,
-156,
-118,
-141,
-34,
-227,
-180,
-189,
-222,
-120,
-2,
-237,
-131,
-169,
-142,
-105,
-193,
-129,
-164,
-147,
-183,
-167,
-71,
-191,
-64,
-77,
-168,
-17,
-5,
-252,
-22,
-84,
-40,
-178,
-137,
-160,
-215,
-240,
-49,
-93,
-74,
-59,
-243,
-8,
-249,
-106,
-224,
-54,
-26,
-90,
-63,
-17,
-16,
-171,
-206,
-25,
-184,
-23,
-0,
-219,
-59,
-15,
-98,
-224,
-11,
-56,
-90,
-0,
-118,
-37,
-95,
-157,
-216,
-140,
-173,
-55,
-145,
-167,
-151,
-58,
-204,
-211,
-166,
-171,
-0,
-104,
-27,
-118,
-122,
-113,
-22,
-0,
-109,
-189,
-19,
-27,
-11,
-142,
-182,
-239,
-193,
-161,
-9,
-94,
-206,
-147,
-39,
-208,
-253,
-119,
-248,
-211,
-24,
-209,
-62,
-190,
-94,
-67,
-59,
-116,
-60,
-34,
-157,
-172,
-251,
-107,
-35,
-229,
-19,
-1,
-177,
-234,
-138,
-15,
-26,
-201,
-84,
-11,
-226,
-71,
-62,
-38,
-220,
-30,
-201,
-131,
-78,
-126,
-169,
-80,
-190,
-58,
-240,
-73,
-60,
-130,
-177,
-237,
-132,
-108,
-59,
-240,
-34,
-92,
-207,
-98,
-158,
-14,
-166,
-179,
-245,
-93,
-84,
-157,
-194,
-52,
-254,
-178,
-182,
-189,
-191,
-154,
-123,
-168,
-243,
-78,
-108,
-44,
-56,
-186,
-244,
-147,
-134,
-203,
-121,
-68,
-225,
-13,
-99,
-196,
-110,
-196,
-24,
-51,
-242,
-20,
-0,
-216,
-68,
-127,
-151,
-133,
-116,
-110,
-29,
-171,
-206,
-247,
-160,
-201,
-67,
-72,
-159,
-67,
-172,
-160,
-135,
-35,
-175,
-217,
-52,
-181,
-182,
-53,
-138,
-121,
-69,
-131,
-107,
-88,
-12,
-91,
-0,
-88,
-204,
-67,
-38,
-227,
-57,
-192,
-158,
-148,
-196,
-246,
-115,
-232,
-109,
-214,
-224,
-171,
-16,
-133,
-156,
-197,
-69,
-148,
-164,
-254,
-102,
-20,
-190,
-172,
-37,
-253,
-104,
-27,
-76,
-181,
-84,
-112,
-116,
-120,
-15,
-141,
-151,
-243,
-228,
-199,
-171,
-3,
-17,
-164,
-70,
-13,
-218,
-161,
-227,
-245,
-255,
-214,
-231,
-218,
-151,
-157,
-167,
-83,
-172,
-58,
-223,
-131,
-70,
-190,
-172,
-54,
-208,
-231,
-126,
-145,
-239,
-171,
-77,
-106,
-109,
-187,
-2,
-186,
-140,
-26,
-115,
-104,
-167,
-141,
-197,
-176,
-5,
-64,
-217,
-68,
-190,
-20,
-207,
-177,
-170,
-175,
-159,
-72,
-210,
-137,
-221,
-201,
-183,
-56,
-7,
-148,
-244,
-117,
-216,
-95,
-214,
-40,
-65,
-81,
-29,
-126,
-85,
-110,
-205,
-109,
-223,
-67,
-227,
-229,
-60,
-185,
-123,
-121,
-155,
-15,
-76,
-41,
-66,
-121,
-89,
-134,
-199,
-2,
-219,
-162,
-199,
-103,
-202,
-227,
-120,
-36,
-20,
-180,
-205,
-246,
-251,
-27,
-79,
-187,
-78,
-78,
-35,
-101,
-15,
-26,
-209,
-7,
-44,
-66,
-190,
-190,
-47,
-109,
-116,
-51,
-229,
-215,
-106,
-155,
-90,
-251,
-185,
-228,
-89,
-102,
-108,
-222,
-185,
-186,
-120,
-122,
-22,
-163,
-182,
-5,
-96,
-112,
-34,
-127,
-183,
-73,
-63,
-117,
-76,
-0,
-220,
-212,
-240,
-30,
-250,
-248,
-178,
-182,
-254,
-208,
-208,
-206,
-173,
-185,
-109,
-63,
-27,
-47,
-231,
-201,
-87,
-77,
-219,
-54,
-104,
-99,
-97,
-5,
-126,
-55,
-7,
-33,
-135,
-225,
-28,
-242,
-227,
-192,
-69,
-78,
-249,
-36,
-60,
-103,
-243,
-116,
-116,
-26,
-169,
-121,
-208,
-54,
-118,
-253,
-77,
-68,
-8,
-132,
-64,
-135,
-212,
-218,
-200,
-151,
-237,
-235,
-140,
-60,
-33,
-249,
-95,
-217,
-75,
-115,
-104,
-70,
-93,
-7,
-64,
-197,
-68,
-174,
-105,
-183,
-187,
-29,
-19,
-13,
-239,
-161,
-143,
-47,
-107,
-219,
-96,
-170,
-93,
-221,
-154,
-155,
-246,
-179,
-241,
-114,
-30,
-177,
-244,
-132,
-6,
-89,
-172,
-171,
-222,
-91,
-43,
-32,
-190,
-241,
-127,
-67,
-150,
-222,
-118,
-73,
-50,
-13,
-56,
-29,
-217,
-67,
-150,
-37,
-88,
-28,
-147,
-78,
-35,
-125,
-1,
-9,
-172,
-241,
-254,
-194,
-160,
-218,
-217,
-67,
-215,
-234,
-5,
-117,
-24,
-120,
-165,
-215,
-163,
-98,
-34,
-215,
-180,
-219,
-77,
-235,
-158,
-40,
-233,
-235,
-48,
-191,
-172,
-109,
-131,
-169,
-182,
-21,
-28,
-109,
-251,
-217,
-102,
-57,
-127,
-176,
-182,
-57,
-191,
-65,
-155,
-210,
-247,
-22,
-5,
-202,
-252,
-248,
-0,
-186,
-49,
-233,
-52,
-210,
-55,
-244,
-30,
-109,
-16,
-200,
-41,
-158,
-250,
-126,
-95,
-80,
-131,
-235,
-81,
-49,
-145,
-107,
-218,
-157,
-160,
-117,
-255,
-242,
-212,
-13,
-251,
-203,
-218,
-54,
-152,
-106,
-91,
-193,
-81,
-213,
-207,
-23,
-87,
-180,
-107,
-179,
-156,
-95,
-151,
-60,
-143,
-193,
-33,
-56,
-241,
-26,
-145,
-20,
-110,
-187,
-86,
-244,
-111,
-212,
-5,
-192,
-208,
-156,
-70,
-186,
-160,
-237,
-192,
-171,
-225,
-249,
-82,
-109,
-214,
-232,
-203,
-218,
-7,
-170,
-174,
-71,
-245,
-68,
-30,
-104,
-135,
-56,
-84,
-125,
-158,
-92,
-119,
-240,
-78,
-79,
-187,
-62,
-190,
-172,
-85,
-19,
-171,
-109,
-48,
-213,
-182,
-130,
-195,
-222,
-187,
-47,
-252,
-247,
-59,
-42,
-218,
-53,
-94,
-206,
-107,
-187,
-247,
-145,
-219,
-220,
-204,
-67,
-156,
-192,
-102,
-233,
-239,
-255,
-120,
-232,
-75,
-223,
-119,
-20,
-40,
-243,
-227,
-3,
-105,
-135,
-226,
-52,
-210,
-5,
-53,
-3,
-175,
-106,
-192,
-110,
-128,
-132,
-151,
-222,
-160,
-80,
-254,
-52,
-114,
-39,
-150,
-43,
-43,
-174,
-55,
-106,
-2,
-128,
-176,
-137,
-108,
-97,
-149,
-73,
-215,
-49,
-50,
-6,
-196,
-129,
-37,
-215,
-107,
-251,
-101,
-109,
-59,
-177,
-218,
-6,
-83,
-109,
-43,
-56,
-172,
-137,
-173,
-47,
-252,
-247,
-209,
-21,
-237,
-26,
-47,
-231,
-157,
-182,
-155,
-35,
-185,
-13,
-239,
-65,
-182,
-18,
-51,
-144,
-147,
-167,
-15,
-121,
-104,
-7,
-222,
-247,
-98,
-5,
-106,
-34,
-215,
-208,
-208,
-17,
-194,
-121,
-96,
-93,
-194,
-78,
-63,
-128,
-104,
-121,
-175,
-36,
-15,
-213,
-52,
-11,
-216,
-186,
-226,
-122,
-195,
-22,
-0,
-77,
-39,
-114,
-17,
-179,
-144,
-19,
-143,
-147,
-80,
-159,
-251,
-146,
-118,
-109,
-191,
-172,
-173,
-38,
-150,
-214,
-55,
-254,
-208,
-208,
-94,
-112,
-216,
-163,
-204,
-98,
-248,
-239,
-247,
-144,
-239,
-243,
-125,
-237,
-26,
-47,
-231,
-219,
-192,
-243,
-222,
-6,
-16,
-227,
-58,
-189,
-130,
-134,
-185,
-231,
-11,
-109,
-27,
-57,
-66,
-56,
-207,
-165,
-75,
-216,
-233,
-71,
-145,
-175,
-198,
-227,
-136,
-31,
-192,
-49,
-192,
-38,
-53,
-215,
-27,
-182,
-0,
-176,
-8,
-157,
-200,
-173,
-250,
-73,
-251,
-47,
-107,
-171,
-137,
-213,
-5,
-180,
-19,
-28,
-175,
-113,
-238,
-195,
-134,
-255,
-182,
-17,
-160,
-190,
-133,
-90,
-250,
-149,
-92,
-175,
-209,
-114,
-190,
-229,
-61,
-89,
-196,
-57,
-6,
-28,
-13,
-208,
-49,
-247,
-60,
-13,
-28,
-33,
-156,
-7,
-54,
-148,
-164,
-142,
-109,
-39,
-214,
-176,
-175,
-215,
-161,
-93,
-219,
-47,
-107,
-235,
-137,
-53,
-108,
-0,
-111,
-64,
-220,
-227,
-167,
-105,
-191,
-174,
-65,
-183,
-60,
-168,
-0,
-172,
-104,
-27,
-188,
-156,
-111,
-217,
-183,
-161,
-142,
-175,
-94,
-64,
-156,
-220,
-243,
-65,
-142,
-16,
-73,
-0,
-196,
-109,
-167,
-109,
-219,
-230,
-55,
-104,
-61,
-177,
-198,
-27,
-144,
-128,
-172,
-179,
-233,
-47,
-65,
-73,
-52,
-59,
-128,
-149,
-129,
-207,
-34,
-182,
-223,
-143,
-35,
-75,
-151,
-59,
-145,
-163,
-174,
-210,
-188,
-238,
-5,
-30,
-63,
-69,
-246,
-63,
-191,
-8,
-164,
-239,
-148,
-123,
-190,
-9,
-70,
-81,
-0,
-148,
-46,
-209,
-208,
-8,
-202,
-145,
-175,
-55,
-52,
-1,
-144,
-80,
-15,
-196,
-106,
-116,
-145,
-10,
-188,
-82,
-33,
-64,
-190,
-69,
-216,
-190,
-170,
-204,
-169,
-139,
-46,
-0,
-174,
-115,
-152,
-62,
-142,
-132,
-8,
-179,
-150,
-128,
-15,
-17,
-96,
-3,
-79,
-238,
-241,
-52,
-51,
-74,
-167,
-34,
-162,
-70,
-0,
-148,
-30,
-63,
-69,
-184,
-94,
-21,
-62,
-223,
-195,
-245,
-146,
-0,
-24,
-67,
-0,
-222,
-77,
-158,
-133,
-250,
-218,
-10,
-186,
-187,
-138,
-239,
-193,
-87,
-230,
-212,
-69,
-23,
-0,
-123,
-0,
-63,
-193,
-201,
-59,
-142,
-36,
-147,
-188,
-64,
-47,
-116,
-106,
-0,
-143,
-35,
-145,
-229,
-78,
-200,
-254,
-29,
-90,
-68,
-191,
-173,
-153,
-200,
-85,
-202,
-188,
-86,
-199,
-79,
-139,
-59,
-22,
-87,
-1,
-64,
-131,
-64,
-163,
-67,
-234,
-207,
-165,
-148,
-88,
-84,
-106,
-189,
-61,
-213,
-90,
-167,
-170,
-204,
-169,
-27,
-206,
-123,
-3,
-94,
-168,
-23,
-122,
-44,
-50,
-95,
-104,
-17,
-253,
-182,
-131,
-0,
-104,
-125,
-252,
-180,
-56,
-99,
-49,
-22,
-0,
-149,
-129,
-70,
-145,
-232,
-87,
-7,
-33,
-39,
-37,
-115,
-144,
-237,
-238,
-161,
-212,
-132,
-190,
-111,
-216,
-135,
-157,
-145,
-21,
-192,
-1,
-122,
-141,
-210,
-108,
-201,
-72,
-252,
-5,
-112,
-76,
-238,
-125,
-101,
-78,
-221,
-208,
-4,
-192,
-202,
-118,
-178,
-70,
-230,
-107,
-209,
-40,
-250,
-109,
-7,
-1,
-48,
-244,
-227,
-167,
-197,
-25,
-250,
-184,
-46,
-215,
-255,
-175,
-173,
-19,
-238,
-110,
-68,
-195,
-127,
-123,
-69,
-187,
-224,
-88,
-12,
-200,
-10,
-244,
-100,
-100,
-85,
-248,
-36,
-240,
-59,
-2,
-130,
-196,
-16,
-16,
-104,
-84,
-199,
-195,
-34,
-36,
-120,
-201,
-151,
-201,
-147,
-167,
-252,
-182,
-142,
-127,
-40,
-144,
-143,
-217,
-124,
-228,
-68,
-228,
-103,
-84,
-56,
-180,
-33,
-39,
-6,
-211,
-234,
-202,
-156,
-58,
-139,
-126,
-143,
-1,
-17,
-141,
-45,
-212,
-36,
-208,
-68,
-206,
-203,
-33,
-48,
-96,
-165,
-115,
-3,
-141,
-162,
-223,
-118,
-16,
-0,
-227,
-230,
-248,
-105,
-60,
-64,
-159,
-219,
-61,
-72,
-26,
-180,
-41,
-250,
-123,
-33,
-162,
-60,
-190,
-180,
-164,
-77,
-112,
-44,
-6,
-157,
-252,
-54,
-83,
-213,
-249,
-72,
-128,
-218,
-121,
-200,
-74,
-174,
-82,
-8,
-16,
-16,
-104,
-20,
-73,
-152,
-242,
-170,
-66,
-217,
-121,
-68,
-254,
-208,
-133,
-2,
-241,
-124,
-189,
-163,
-174,
-204,
-169,
-171,
-69,
-140,
-78,
-173,
-64,
-238,
-240,
-241,
-165,
-26,
-218,
-87,
-148,
-77,
-218,
-154,
-27,
-104,
-20,
-253,
-214,
-105,
-215,
-38,
-160,
-68,
-47,
-199,
-79,
-180,
-76,
-87,
-165,
-180,
-65,
-95,
-68,
-242,
-56,
-141,
-62,
-188,
-172,
-77,
-191,
-187,
-64,
-175,
-59,
-31,
-17,
-164,
-255,
-3,
-222,
-132,
-38,
-74,
-197,
-241,
-11,
-112,
-232,
-27,
-197,
-98,
-64,
-143,
-17,
-113,
-50,
-60,
-35,
-66,
-124,
-62,
-112,
-82,
-79,
-247,
-116,
-61,
-48,
-169,
-15,
-222,
-227,
-14,
-72,
-162,
-208,
-203,
-245,
-37,
-92,
-74,
-69,
-22,
-92,
-196,
-2,
-236,
-159,
-74,
-91,
-155,
-161,
-69,
-219,
-88,
-180,
-141,
-126,
-59,
-148,
-227,
-188,
-16,
-208,
-62,
-93,
-85,
-163,
-232,
-68,
-72,
-172,
-185,
-67,
-157,
-103,
-240,
-123,
-224,
-67,
-68,
-136,
-149,
-208,
-20,
-78,
-31,
-30,
-194,
-217,
-82,
-85,
-208,
-55,
-138,
-197,
-160,
-207,
-99,
-96,
-43,
-1,
-252,
-133,
-10,
-101,
-90,
-91,
-32,
-62,
-19,
-139,
-128,
-157,
-98,
-243,
-30,
-119,
-64,
-210,
-45,
-93,
-175,
-47,
-248,
-106,
-52,
-174,
-89,
-5,
-189,
-85,
-162,
-205,
-2,
-158,
-31,
-120,
-141,
-86,
-19,
-121,
-140,
-10,
-128,
-198,
-233,
-170,
-104,
-25,
-157,
-72,
-219,
-90,
-84,
-42,
-128,
-60,
-253,
-170,
-92,
-153,
-208,
-192,
-191,
-194,
-233,
-195,
-103,
-171,
-232,
-218,
-66,
-251,
-112,
-139,
-167,
-252,
-12,
-60,
-251,
-98,
-58,
-172,
-144,
-144,
-192,
-174,
-243,
-129,
-61,
-99,
-222,
-195,
-184,
-5,
-18,
-204,
-16,
-224,
-6,
-106,
-164,
-59,
-146,
-4,
-19,
-100,
-73,
-61,
-96,
-176,
-80,
-209,
-174,
-15,
-1,
-16,
-253,
-60,
-191,
-47,
-208,
-45,
-58,
-81,
-168,
-0,
-104,
-180,
-50,
-161,
-129,
-127,
-133,
-211,
-135,
-94,
-146,
-175,
-146,
-7,
-134,
-117,
-21,
-196,
-47,
-71,
-156,
-144,
-188,
-71,
-210,
-180,
-88,
-33,
-1,
-223,
-70,
-20,
-140,
-111,
-9,
-236,
-215,
-146,
-218,
-230,
-38,
-196,
-232,
-237,
-33,
-42,
-182,
-122,
-228,
-130,
-125,
-131,
-50,
-154,
-49,
-7,
-242,
-176,
-87,
-219,
-212,
-208,
-109,
-133,
-44,
-155,
-230,
-1,
-219,
-53,
-188,
-70,
-91,
-1,
-48,
-225,
-207,
-243,
-27,
-8,
-128,
-54,
-43,
-147,
-32,
-255,
-138,
-170,
-247,
-87,
-66,
-223,
-232,
-11,
-13,
-172,
-135,
-248,
-22,
-44,
-2,
-206,
-5,
-206,
-68,
-4,
-218,
-163,
-192,
-179,
-107,
-174,
-85,
-251,
-124,
-116,
-34,
-255,
-82,
-39,
-114,
-208,
-170,
-85,
-219,
-125,
-67,
-121,
-47,
-66,
-244,
-70,
-183,
-0,
-191,
-175,
-160,
-183,
-31,
-211,
-198,
-201,
-68,
-201,
-243,
-100,
-222,
-83,
-65,
-211,
-40,
-194,
-117,
-232,
-133,
-237,
-36,
-27,
-80,
-230,
-20,
-232,
-78,
-87,
-186,
-111,
-182,
-184,
-70,
-233,
-0,
-98,
-140,
-156,
-231,
-59,
-125,
-44,
-53,
-89,
-174,
-24,
-212,
-79,
-33,
-70,
-95,
-74,
-174,
-217,
-203,
-25,
-48,
-1,
-254,
-21,
-85,
-239,
-175,
-162,
-77,
-163,
-47,
-52,
-34,
-4,
-78,
-35,
-215,
-145,
-156,
-74,
-128,
-89,
-122,
-200,
-243,
-65,
-182,
-18,
-51,
-129,
-111,
-34,
-251,
-127,
-247,
-95,
-105,
-106,
-58,
-242,
-120,
-153,
-95,
-112,
-202,
-202,
-66,
-174,
-175,
-134,
-156,
-70,
-52,
-122,
-78,
-78,
-251,
-255,
-105,
-91,
-111,
-162,
-91,
-90,
-68,
-184,
-142,
-10,
-231,
-230,
-26,
-101,
-12,
-210,
-182,
-165,
-3,
-136,
-49,
-114,
-158,
-239,
-244,
-177,
-106,
-9,
-105,
-17,
-124,
-30,
-75,
-0,
-2,
-251,
-53,
-106,
-198,
-59,
-85,
-239,
-175,
-65,
-219,
-190,
-4,
-88,
-45,
-255,
-154,
-199,
-255,
-137,
-138,
-118,
-214,
-205,
-183,
-46,
-148,
-252,
-81,
-228,
-113,
-1,
-138,
-152,
-26,
-112,
-15,
-171,
-146,
-155,
-226,
-15,
-196,
-23,
-164,
-131,
-14,
-201,
-69,
-87,
-103,
-28,
-59,
-1,
-163,
-90,
-9,
-214,
-224,
-96,
-99,
-204,
-91,
-141,
-49,
-47,
-55,
-198,
-220,
-13,
-220,
-108,
-140,
-89,
-195,
-24,
-179,
-158,
-49,
-230,
-219,
-198,
-152,
-47,
-27,
-99,
-158,
-214,
-150,
-57,
-34,
-205,
-247,
-51,
-198,
-236,
-229,
-20,
-79,
-7,
-238,
-50,
-198,
-252,
-57,
-203,
-178,
-50,
-251,
-253,
-221,
-179,
-44,
-187,
-174,
-225,
-229,
-174,
-51,
-198,
-244,
-226,
-55,
-161,
-247,
-49,
-191,
-164,
-250,
-229,
-89,
-150,
-85,
-234,
-25,
-22,
-119,
-100,
-89,
-214,
-56,
-225,
-12,
-146,
-164,
-198,
-158,
-134,
-205,
-171,
-33,
-127,
-194,
-24,
-115,
-184,
-49,
-102,
-127,
-253,
-253,
-75,
-45,
-51,
-198,
-152,
-233,
-1,
-151,
-219,
-198,
-24,
-147,
-25,
-99,
-174,
-206,
-178,
-204,
-103,
-202,
-252,
-87,
-173,
-223,
-42,
-203,
-178,
-73,
-218,
-191,
-173,
-141,
-49,
-167,
-107,
-93,
-187,
-163,
-97,
-100,
-95,
-52,
-27,
-56,
-60,
-128,
-246,
-30,
-149,
-80,
-3,
-38,
-187,
-1,
-109,
-75,
-191,
-32,
-140,
-210,
-121,
-190,
-182,
-63,
-217,
-233,
-219,
-44,
-196,
-168,
-228,
-94,
-253,
-253,
-231,
-138,
-251,
-8,
-254,
-154,
-181,
-105,
-211,
-166,
-61,
-13,
-150,
-220,
-52,
-223,
-163,
-151,
-190,
-191,
-88,
-253,
-111,
-139,
-62,
-248,
-35,
-123,
-255,
-219,
-125,
-15,
-39,
-176,
-47,
-141,
-158,
-19,
-98,
-57,
-8,
-145,
-34,
-8,
-53,
-185,
-176,
-117,
-65,
-172,
-61,
-107,
-69,
-156,
-127,
-64,
-38,
-224,
-250,
-78,
-249,
-166,
-136,
-107,
-240,
-238,
-189,
-118,
-54,
-50,
-144,
-100,
-36,
-22,
-135,
-224,
-164,
-196,
-2,
-214,
-199,
-227,
-206,
-217,
-102,
-176,
-117,
-29,
-160,
-77,
-219,
-135,
-210,
-211,
-76,
-96,
-180,
-26,
-216,
-109,
-250,
-63,
-22,
-248,
-3,
-63,
-208,
-127,
-22,
-71,
-217,
-178,
-192,
-190,
-52,
-21,
-0,
-183,
-234,
-191,
-202,
-208,
-120,
-209,
-65,
-179,
-21,
-192,
-218,
-136,
-253,
-183,
-197,
-253,
-228,
-81,
-97,
-64,
-189,
-253,
-198,
-11,
-200,
-163,
-231,
-94,
-220,
-160,
-77,
-227,
-193,
-214,
-117,
-128,
-54,
-109,
-223,
-7,
-253,
-48,
-5,
-0,
-13,
-61,
-251,
-186,
-62,
-223,
-64,
-222,
-161,
-167,
-31,
-173,
-159,
-83,
-95,
-125,
-114,
-177,
-68,
-177,
-32,
-203,
-178,
-189,
-179,
-44,
-123,
-122,
-150,
-101,
-159,
-169,
-107,
-156,
-101,
-217,
-84,
-35,
-123,
-141,
-195,
-141,
-49,
-83,
-140,
-236,
-197,
-151,
-48,
-198,
-92,
-108,
-140,
-249,
-156,
-49,
-102,
-219,
-166,
-29,
-26,
-101,
-88,
-101,
-75,
-173,
-9,
-239,
-68,
-71,
-150,
-227,
-182,
-33,
-92,
-238,
-0,
-99,
-204,
-242,
-198,
-152,
-169,
-198,
-152,
-104,
-65,
-84,
-18,
-186,
-43,
-1,
-77,
-150,
-101,
-15,
-25,
-99,
-62,
-171,
-255,
-198,
-59,
-236,
-17,
-211,
-141,
-45,
-218,
-94,
-75,
-201,
-118,
-176,
-141,
-194,
-41,
-65,
-128,
-216,
-34,
-124,
-220,
-136,
-2,
-109,
-199,
-44,
-203,
-238,
-26,
-229,
-46,
-45,
-86,
-24,
-90,
-72,
-174,
-50,
-32,
-249,
-6,
-239,
-48,
-34,
-225,
-175,
-204,
-178,
-204,
-119,
-228,
-81,
-171,
-212,
-43,
-78,
-178,
-54,
-109,
-140,
-49,
-118,
-207,
-239,
-77,
-131,
-94,
-131,
-54,
-26,
-253,
-36,
-52,
-234,
-241,
-27,
-99,
-204,
-195,
-198,
-152,
-183,
-182,
-56,
-101,
-73,
-168,
-193,
-168,
-11,
-0,
-211,
-108,
-121,
-215,
-102,
-146,
-53,
-105,
-51,
-199,
-136,
-16,
-88,
-174,
-142,
-208,
-131,
-49,
-117,
-12,
-184,
-184,
-32,
-203,
-178,
-168,
-193,
-52,
-19,
-2,
-129,
-132,
-8,
-251,
-15,
-240,
-120,
-143,
-215,
-168,
-13,
-220,
-160,
-116,
-67,
-81,
-180,
-33,
-102,
-179,
-0,
-123,
-213,
-83,
-15,
-183,
-111,
-218,
-238,
-29,
-12,
-106,
-233,
-63,
-136,
-115,
-90,
-17,
-227,
-122,
-125,
-42,
-209,
-198,
-59,
-255,
-166,
-10,
-55,
-52,
-206,
-4,
-145,
-82,
-220,
-199,
-232,
-147,
-139,
-1,
-37,
-160,
-50,
-220,
-223,
-24,
-243,
-43,
-99,
-204,
-43,
-141,
-49,
-247,
-55,
-232,
-64,
-211,
-7,
-110,
-151,
-119,
-219,
-141,
-145,
-229,
-221,
-213,
-250,
-119,
-151,
-74,
-170,
-81,
-0,
-98,
-216,
-115,
-134,
-49,
-230,
-11,
-78,
-241,
-251,
-141,
-49,
-39,
-25,
-99,
-134,
-103,
-254,
-153,
-208,
-20,
-183,
-234,
-223,
-49,
-55,
-166,
-140,
-41,
-17,
-0,
-198,
-152,
-125,
-245,
-239,
-39,
-178,
-44,
-123,
-97,
-9,
-77,
-103,
-100,
-89,
-182,
-105,
-150,
-101,
-107,
-103,
-89,
-118,
-117,
-61,
-245,
-80,
-96,
-195,
-65,
-189,
-17,
-248,
-46,
-35,
-227,
-179,
-173,
-5,
-188,
-125,
-148,
-250,
-101,
-178,
-44,
-91,
-144,
-149,
-99,
-66,
-91,
-245,
-89,
-216,
-21,
-146,
-83,
-180,
-127,
-200,
-10,
-169,
-103,
-28,
-235,
-244,
-229,
-102,
-196,
-132,
-189,
-214,
-20,
-120,
-84,
-225,
-124,
-209,
-155,
-250,
-246,
-143,
-153,
-37,
-93,
-219,
-62,
-145,
-59,
-56,
-129,
-156,
-61,
-223,
-64,
-30,
-154,
-42,
-74,
-150,
-214,
-190,
-159,
-87,
-215,
-235,
-141,
-197,
-247,
-25,
-192,
-115,
-40,
-17,
-147,
-28,
-158,
-161,
-91,
-128,
-12,
-216,
-95,
-199,
-209,
-108,
-196,
-122,
-213,
-27,
-50,
-109,
-88,
-125,
-114,
-81,
-167,
-4,
-12,
-138,
-239,
-215,
-4,
-208,
-74,
-59,
-63,
-76,
-236,
-98,
-140,
-249,
-146,
-49,
-102,
-79,
-99,
-204,
-250,
-198,
-24,
-171,
-132,
-186,
-195,
-24,
-83,
-26,
-213,
-53,
-161,
-30,
-192,
-59,
-140,
-49,
-110,
-34,
-213,
-253,
-129,
-179,
-140,
-49,
-167,
-103,
-89,
-214,
-41,
-22,
-95,
-150,
-101,
-11,
-140,
-216,
-198,
-143,
-41,
-100,
-89,
-134,
-17,
-255,
-149,
-131,
-71,
-187,
-47,
-62,
-140,
-230,
-41,
-192,
-176,
-142,
-205,
-26,
-181,
-201,
-178,
-108,
-190,
-49,
-230,
-123,
-198,
-152,
-239,
-57,
-194,
-106,
-165,
-44,
-203,
-234,
-28,
-56,
-142,
-163,
-36,
-33,
-74,
-150,
-101,
-91,
-213,
-180,
-93,
-236,
-65,
-174,
-195,
-112,
-241,
-126,
-253,
-247,
-114,
-99,
-76,
-218,
-198,
-140,
-2,
-70,
-83,
-0,
-12,
-235,
-216,
-44,
-198,
-81,
-91,
-101,
-108,
-63,
-69,
-155,
-229,
-236,
-132,
-17,
-26,
-99,
-245,
-11,
-221,
-20,
-139,
-155,
-125,
-198,
-128,
-0,
-96,
-100,
-18,
-133,
-97,
-186,
-249,
-134,
-160,
-141,
-208,
-104,
-211,
-198,
-24,
-19,
-246,
-178,
-59,
-14,
-136,
-94,
-117,
-0,
-125,
-46,
-185,
-19,
-22,
-51,
-0,
-203,
-3,
-47,
-3,
-254,
-165,
-10,
-133,
-191,
-53,
-104,
-27,
-172,
-212,
-25,
-150,
-210,
-172,
-111,
-69,
-214,
-88,
-71,
-27,
-165,
-24,
-45,
-237,
-12,
-198,
-2,
-144,
-0,
-26,
-199,
-106,
-191,
-79,
-243,
-212,
-15,
-96,
-52,
-250,
-233,
-244,
-103,
-105,
-228,
-68,
-224,
-78,
-26,
-4,
-240,
-232,
-179,
-67,
-22,
-55,
-2,
-95,
-1,
-130,
-131,
-106,
-36,
-1,
-48,
-254,
-209,
-70,
-96,
-140,
-21,
-0,
-239,
-69,
-162,
-83,
-221,
-133,
-68,
-225,
-169,
-18,
-0,
-87,
-17,
-51,
-115,
-78,
-75,
-0,
-27,
-58,
-125,
-26,
-181,
-227,
-101,
-215,
-14,
-224,
-127,
-70,
-246,
-202,
-235,
-25,
-99,
-94,
-104,
-196,
-60,
-55,
-97,
-130,
-160,
-15,
-59,
-3,
-224,
-37,
-200,
-209,
-151,
-215,
-156,
-151,
-6,
-97,
-200,
-107,
-176,
-185,
-49,
-230,
-95,
-198,
-152,
-16,
-107,
-187,
-247,
-103,
-89,
-182,
-149,
-79,
-199,
-226,
-147,
-124,
-109,
-251,
-76,
-189,
-11,
-243,
-221,
-198,
-152,
-43,
-141,
-49,
-119,
-26,
-99,
-46,
-15,
-232,
-119,
-255,
-0,
-86,
-68,
-242,
-145,
-1,
-252,
-179,
-65,
-187,
-224,
-175,
-109,
-197,
-87,
-166,
-234,
-161,
-7,
-243,
-239,
-210,
-70,
-219,
-5,
-199,
-210,
-71,
-76,
-152,
-255,
-3,
-236,
-209,
-228,
-26,
-19,
-5,
-192,
-31,
-144,
-184,
-118,
-231,
-251,
-132,
-0,
-13,
-194,
-144,
-55,
-184,
-38,
-84,
-175,
-0,
-74,
-207,
-202,
-201,
-227,
-56,
-218,
-73,
-238,
-27,
-139,
-65,
-125,
-166,
-38,
-57,
-233,
-152,
-5,
-176,
-142,
-243,
-176,
-86,
-10,
-108,
-19,
-60,
-217,
-28,
-218,
-54,
-65,
-52,
-135,
-33,
-0,
-130,
-99,
-233,
-147,
-39,
-79,
-1,
-248,
-98,
-13,
-223,
-37,
-144,
-40,
-67,
-143,
-35,
-65,
-83,
-14,
-68,
-98,
-204,
-21,
-233,
-62,
-15,
-92,
-134,
-132,
-230,
-126,
-20,
-248,
-59,
-240,
-188,
-38,
-247,
-48,
-86,
-128,
-100,
-198,
-61,
-205,
-190,
-239,
-18,
-154,
-160,
-48,
-228,
-13,
-174,
-9,
-45,
-5,
-128,
-67,
-91,
-23,
-146,
-174,
-178,
-207,
-4,
-250,
-184,
-116,
-5,
-18,
-54,
-124,
-54,
-240,
-75,
-79,
-221,
-47,
-144,
-237,
-208,
-79,
-219,
-48,
-182,
-216,
-176,
-33,
-125,
-223,
-58,
-128,
-94,
-133,
-134,
-182,
-107,
-20,
-75,
-31,
-201,
-42,
-3,
-240,
-64,
-13,
-223,
-47,
-34,
-81,
-139,
-191,
-160,
-255,
-230,
-227,
-137,
-62,
-139,
-164,
-146,
-62,
-20,
-120,
-63,
-176,
-59,
-146,
-120,
-226,
-162,
-10,
-190,
-149,
-202,
-36,
-74,
-80,
-255,
-36,
-226,
-1,
-73,
-45,
-87,
-26,
-98,
-142,
-128,
-48,
-228,
-13,
-174,
-5,
-61,
-11,
-128,
-186,
-62,
-19,
-144,
-156,
-180,
-105,
-159,
-74,
-218,
-219,
-240,
-125,
-3,
-238,
-235,
-78,
-221,
-147,
-109,
-24,
-55,
-234,
-88,
-147,
-201,
-214,
-132,
-214,
-211,
-166,
-20,
-49,
-174,
-211,
-6,
-192,
-243,
-235,
-6,
-139,
-210,
-93,
-11,
-252,
-213,
-249,
-253,
-87,
-60,
-166,
-197,
-158,
-118,
-135,
-81,
-145,
-177,
-150,
-26,
-101,
-18,
-178,
-162,
-25,
-248,
-231,
-161,
-179,
-193,
-80,
-127,
-94,
-211,
-159,
-208,
-231,
-191,
-51,
-178,
-2,
-56,
-64,
-175,
-57,
-20,
-43,
-74,
-237,
-78,
-239,
-2,
-32,
-6,
-154,
-244,
-169,
-164,
-253,
-145,
-200,
-10,
-224,
-23,
-158,
-58,
-187,
-58,
-56,
-178,
-247,
-142,
-53,
-153,
-108,
-195,
-154,
-152,
-195,
-66,
-232,
-96,
-65,
-210,
-79,
-29,
-230,
-252,
-62,
-12,
-24,
-176,
-179,
-64,
-146,
-178,
-254,
-12,
-177,
-29,
-159,
-129,
-198,
-134,
-175,
-224,
-107,
-87,
-0,
-141,
-226,
-193,
-123,
-248,
-172,
-6,
-220,
-167,
-183,
-242,
-158,
-10,
-186,
-80,
-129,
-50,
-3,
-89,
-229,
-76,
-209,
-251,
-25,
-138,
-82,
-121,
-34,
-9,
-128,
-24,
-24,
-11,
-1,
-65,
-38,
-10,
-22,
-153,
-145,
-150,
-112,
-101,
-158,
-152,
-191,
-49,
-18,
-19,
-254,
-48,
-99,
-204,
-100,
-99,
-204,
-206,
-250,
-207,
-11,
-53,
-93,
-30,
-136,
-162,
-212,
-20,
-89,
-150,
-61,
-134,
-164,
-150,
-250,
-147,
-49,
-230,
-112,
-224,
-239,
-89,
-150,
-13,
-88,
-41,
-102,
-89,
-22,
-116,
-60,
-156,
-101,
-217,
-10,
-93,
-251,
-52,
-150,
-225,
-8,
-135,
-141,
-139,
-113,
-17,
-171,
-234,
-198,
-26,
-202,
-6,
-161,
-117,
-2,
-170,
-76,
-13,
-150,
-208,
-8,
-183,
-24,
-99,
-54,
-113,
-126,
-63,
-207,
-228,
-190,
-226,
-46,
-182,
-54,
-198,
-28,
-159,
-101,
-217,
-215,
-178,
-44,
-251,
-189,
-49,
-102,
-152,
-97,
-161,
-207,
-48,
-198,
-220,
-100,
-140,
-89,
-219,
-24,
-19,
-39,
-207,
-92,
-194,
-168,
-0,
-248,
-152,
-174,
-46,
-94,
-92,
-69,
-87,
-38,
-0,
-172,
-212,
-122,
-83,
-192,
-133,
-92,
-30,
-115,
-3,
-251,
-183,
-56,
-225,
-169,
-136,
-73,
-192,
-186,
-21,
-116,
-71,
-27,
-99,
-182,
-3,
-246,
-3,
-246,
-51,
-198,
-108,
-103,
-114,
-95,
-113,
-23,
-119,
-24,
-99,
-182,
-69,
-148,
-128,
-223,
-51,
-198,
-188,
-173,
-174,
-3,
-177,
-150,
-146,
-234,
-185,
-102,
-253,
-233,
-247,
-41,
-188,
-219,
-113,
-1,
-181,
-91,
-40,
-221,
-194,
-76,
-32,
-172,
-84,
-248,
-27,
-14,
-196,
-178,
-202,
-226,
-250,
-26,
-218,
-245,
-148,
-110,
-33,
-1,
-199,
-134,
-14,
-223,
-96,
-141,
-126,
-0,
-207,
-159,
-43,
-207,
-63,
-4,
-208,
-238,
-66,
-158,
-179,
-109,
-149,
-166,
-215,
-42,
-225,
-121,
-182,
-242,
-59,
-23,
-209,
-14,
-15,
-152,
-206,
-34,
-126,
-225,
-223,
-36,
-63,
-6,
-252,
-14,
-254,
-99,
-192,
-215,
-144,
-251,
-142,
-159,
-13,
-236,
-90,
-183,
-23,
-141,
-185,
-151,
-68,
-108,
-65,
-108,
-142,
-197,
-215,
-117,
-229,
-55,
-86,
-208,
-228,
-25,
-17,
-118,
-10,
-80,
-202,
-47,
-244,
-90,
-49,
-223,
-155,
-135,
-247,
-55,
-149,
-119,
-80,
-218,
-115,
-31,
-131,
-119,
-2,
-23,
-227,
-81,
-84,
-57,
-52,
-75,
-3,
-39,
-233,
-133,
-74,
-143,
-170,
-10,
-109,
-106,
-209,
-176,
-159,
-59,
-107,
-179,
-251,
-129,
-213,
-43,
-232,
-50,
-68,
-35,
-237,
-34,
-150,
-0,
-120,
-58,
-98,
-62,
-125,
-99,
-155,
-123,
-136,
-112,
-253,
-168,
-3,
-9,
-248,
-183,
-242,
-59,
-48,
-6,
-191,
-177,
-128,
-38,
-207,
-136,
-197,
-67,
-0,
-28,
-162,
-188,
-223,
-87,
-69,
-87,
-170,
-4,
-204,
-178,
-236,
-12,
-51,
-232,
-191,
-109,
-153,
-223,
-103,
-140,
-185,
-215,
-136,
-217,
-240,
-218,
-70,
-162,
-233,
-238,
-23,
-210,
-177,
-152,
-238,
-148,
-72,
-250,
-114,
-155,
-193,
-232,
-179,
-89,
-150,
-61,
-90,
-66,
-183,
-188,
-145,
-96,
-30,
-239,
-50,
-18,
-247,
-111,
-99,
-211,
-102,
-105,
-84,
-142,
-21,
-140,
-49,
-47,
-50,
-242,
-60,
-102,
-26,
-89,
-198,
-143,
-103,
-156,
-103,
-140,
-121,
-181,
-49,
-166,
-242,
-28,
-59,
-97,
-76,
-35,
-104,
-11,
-208,
-118,
-143,
-55,
-199,
-136,
-221,
-245,
-211,
-140,
-49,
-103,
-25,
-99,
-94,
-155,
-249,
-51,
-152,
-246,
-141,
-221,
-141,
-49,
-207,
-52,
-198,
-220,
-108,
-140,
-249,
-99,
-5,
-221,
-95,
-140,
-76,
-254,
-11,
-141,
-236,
-189,
-99,
-251,
-116,
-159,
-98,
-140,
-249,
-128,
-17,
-13,
-250,
-218,
-89,
-150,
-85,
-42,
-94,
-198,
-1,
-172,
-0,
-171,
-210,
-105,
-36,
-140,
-50,
-144,
-179,
-126,
-128,
-123,
-60,
-213,
-43,
-234,
-223,
-74,
-1,
-208,
-234,
-24,
-48,
-203,
-178,
-32,
-11,
-193,
-62,
-129,
-36,
-77,
-180,
-230,
-183,
-135,
-168,
-2,
-171,
-12,
-63,
-54,
-198,
-220,
-99,
-140,
-249,
-120,
-150,
-101,
-243,
-104,
-224,
-233,
-24,
-208,
-143,
-149,
-141,
-49,
-175,
-215,
-159,
-95,
-201,
-178,
-172,
-77,
-82,
-145,
-177,
-134,
-135,
-244,
-239,
-26,
-163,
-218,
-139,
-132,
-58,
-188,
-74,
-255,
-254,
-213,
-83,
-103,
-39,
-254,
-138,
-158,
-186,
-167,
-48,
-158,
-237,
-0,
-94,
-105,
-140,
-217,
-192,
-200,
-145,
-165,
-215,
-76,
-215,
-34,
-203,
-178,
-179,
-140,
-172,
-84,
-44,
-150,
-46,
-163,
-109,
-129,
-167,
-38,
-73,
-150,
-101,
-247,
-70,
-228,
-59,
-154,
-120,
-68,
-255,
-174,
-54,
-170,
-189,
-72,
-40,
-5,
-176,
-170,
-17,
-175,
-93,
-99,
-140,
-249,
-181,
-135,
-164,
-217,
-22,
-0,
-152,
-171,
-203,
-137,
-168,
-174,
-137,
-52,
-243,
-174,
-219,
-20,
-201,
-208,
-123,
-175,
-246,
-103,
-10,
-146,
-173,
-216,
-103,
-225,
-182,
-173,
-254,
-189,
-34,
-32,
-94,
-95,
-159,
-88,
-172,
-66,
-68,
-41,
-150,
-209,
-191,
-211,
-70,
-181,
-23,
-9,
-85,
-216,
-198,
-200,
-216,
-187,
-186,
-100,
-251,
-221,
-120,
-11,
-48,
-221,
-24,
-179,
-186,
-137,
-255,
-210,
-223,
-102,
-140,
-89,
-214,
-136,
-146,
-236,
-82,
-35,
-82,
-235,
-185,
-70,
-246,
-238,
-69,
-28,
-98,
-196,
-16,
-230,
-116,
-35,
-6,
-41,
-27,
-26,
-73,
-12,
-185,
-145,
-49,
-230,
-141,
-5,
-218,
-109,
-244,
-239,
-121,
-145,
-251,
-155,
-144,
-191,
-155,
-135,
-71,
-181,
-23,
-139,
-57,
-58,
-42,
-196,
-223,
-160,
-127,
-15,
-45,
-169,
-111,
-188,
-5,
-152,
-102,
-74,
-4,
-0,
-226,
-110,
-248,
-97,
-99,
-204,
-113,
-89,
-150,
-237,
-19,
-90,
-167,
-56,
-203,
-72,
-236,
-187,
-201,
-250,
-123,
-178,
-145,
-32,
-8,
-87,
-122,
-104,
-63,
-100,
-228,
-185,
-60,
-117,
-244,
-8,
-60,
-215,
-248,
-77,
-93,
-173,
-143,
-245,
-120,
-215,
-184,
-143,
-69,
-88,
-247,
-227,
-74,
-15,
-199,
-113,
-138,
-147,
-81,
-223,
-133,
-113,
-30,
-120,
-117,
-71,
-35,
-6,
-123,
-167,
-150,
-212,
-55,
-51,
-4,
-2,
-174,
-211,
-45,
-192,
-241,
-158,
-186,
-16,
-183,
-195,
-168,
-202,
-47,
-224,
-105,
-192,
-235,
-17,
-191,
-235,
-223,
-122,
-234,
-109,
-178,
-142,
-183,
-182,
-224,
-109,
-209,
-217,
-14,
-0,
-216,
-76,
-121,
-205,
-235,
-202,
-171,
-67,
-31,
-162,
-158,
-39,
-3,
-103,
-41,
-191,
-178,
-175,
-203,
-184,
-3,
-30,
-84,
-208,
-14,
-197,
-14,
-160,
-79,
-56,
-91,
-250,
-202,
-36,
-36,
-197,
-45,
-128,
-49,
-254,
-45,
-192,
-137,
-70,
-190,
-242,
-191,
-241,
-212,
-157,
-96,
-140,
-249,
-168,
-254,
-141,
-130,
-194,
-131,
-63,
-215,
-24,
-227,
-139,
-184,
-99,
-39,
-175,
-247,
-236,
-127,
-136,
-216,
-65,
-255,
-250,
-236,
-250,
-199,
-29,
-144,
-19,
-146,
-109,
-245,
-231,
-57,
-163,
-216,
-149,
-168,
-8,
-89,
-110,
-147,
-91,
-161,
-214,
-158,
-18,
-85,
-241,
-27,
-11,
-161,
-195,
-179,
-44,
-91,
-182,
-158,
-202,
-1,
-226,
-159,
-14,
-61,
-89,
-127,
-53,
-145,
-138,
-192,
-14,
-136,
-133,
-223,
-17,
-218,
-230,
-32,
-15,
-205,
-227,
-90,
-183,
-181,
-143,
-71,
-96,
-95,
-58,
-173,
-0,
-16,
-147,
-93,
-139,
-82,
-143,
-189,
-190,
-17,
-243,
-139,
-131,
-248,
-32,
-128,
-132,
-189,
-90,
-166,
-190,
-197,
-226,
-131,
-38,
-171,
-132,
-197,
-14,
-72,
-8,
-104,
-144,
-204,
-192,
-125,
-240,
-111,
-53,
-72,
-129,
-11,
-241,
-68,
-147,
-1,
-110,
-85,
-126,
-141,
-179,
-174,
-70,
-20,
-0,
-143,
-33,
-230,
-210,
-239,
-236,
-194,
-167,
-43,
-34,
-11,
-128,
-75,
-149,
-215,
-119,
-99,
-244,
-45,
-97,
-108,
-35,
-116,
-11,
-48,
-20,
-0,
-171,
-100,
-89,
-246,
-132,
-243,
-123,
-73,
-99,
-204,
-51,
-140,
-63,
-71,
-225,
-253,
-70,
-78,
-7,
-188,
-17,
-103,
-135,
-129,
-44,
-203,
-22,
-171,
-115,
-114,
-196,
-113,
-228,
-53,
-70,
-18,
-194,
-44,
-54,
-251,
-255,
-132,
-114,
-184,
-166,
-192,
-211,
-10,
-127,
-71,
-3,
-83,
-129,
-51,
-144,
-212,
-220,
-95,
-55,
-198,
-92,
-96,
-100,
-130,
-255,
-202,
-67,
-107,
-247,
-107,
-111,
-240,
-212,
-77,
-24,
-48,
-210,
-243,
-176,
-52,
-238,
-94,
-0,
-159,
-149,
-141,
-49,
-71,
-233,
-207,
-207,
-186,
-130,
-56,
-97,
-2,
-128,
-220,
-125,
-176,
-151,
-36,
-5,
-33,
-203,
-84,
-224,
-32,
-196,
-163,
-110,
-38,
-18,
-106,
-106,
-50,
-18,
-76,
-115,
-32,
-40,
-6,
-240,
-70,
-229,
-55,
-151,
-134,
-153,
-107,
-98,
-109,
-1,
-198,
-2,
-128,
-183,
-235,
-189,
-60,
-94,
-79,
-93,
-201,
-199,
-134,
-131,
-111,
-30,
-67,
-46,
-97,
-252,
-3,
-216,
-87,
-7,
-192,
-182,
-61,
-241,
-143,
-182,
-79,
-85,
-126,
-203,
-34,
-145,
-87,
-1,
-118,
-107,
-217,
-151,
-113,
-43,
-0,
-128,
-187,
-145,
-248,
-245,
-243,
-244,
-94,
-14,
-24,
-237,
-62,
-37,
-140,
-99,
-144,
-135,
-16,
-10,
-201,
-174,
-210,
-134,
-127,
-84,
-1,
-160,
-60,
-247,
-87,
-158,
-147,
-98,
-241,
-28,
-47,
-64,
-148,
-160,
-243,
-144,
-64,
-158,
-95,
-247,
-173,
-146,
-18,
-18,
-198,
-12,
-122,
-18,
-0,
-43,
-34,
-201,
-51,
-0,
-106,
-67,
-103,
-37,
-36,
-36,
-140,
-18,
-250,
-16,
-0,
-202,
-247,
-67,
-202,
-247,
-238,
-241,
-188,
-164,
-79,
-72,
-24,
-85,
-32,
-94,
-119,
-179,
-129,
-195,
-235,
-169,
-91,
-241,
-15,
-22,
-0,
-84,
-164,
-60,
-42,
-161,
-63,
-82,
-121,
-255,
-174,
-123,
-79,
-19,
-18,
-38,
-32,
-200,
-109,
-250,
-123,
-57,
-254,
-105,
-40,
-0,
-122,
-241,
-47,
-72,
-72,
-72,
-24,
-9,
-215,
-14,
-224,
-68,
-35,
-161,
-190,
-134,
-146,
-194,
-169,
-6,
-39,
-24,
-233,
-75,
-52,
-255,
-130,
-132,
-132,
-132,
-81,
-68,
-95,
-58,
-128,
-132,
-132,
-132,
-132,
-132,
-132,
-132,
-137,
-0,
-93,
-69,
-148,
-165,
-3,
-111,
-156,
-84,
-36,
-33,
-97,
-34,
-99,
-220,
-165,
-126,
-74,
-72,
-72,
-136,
-135,
-36,
-0,
-18,
-18,
-38,
-48,
-122,
-21,
-0,
-85,
-138,
-63,
-231,
-168,
-111,
-251,
-62,
-251,
-144,
-144,
-144,
-80,
-142,
-209,
-92,
-1,
-60,
-92,
-248,
-155,
-144,
-144,
-48,
-100,
-140,
-5,
-1,
-240,
-72,
-177,
-194,
-177,
-74,
-60,
-98,
-200,
-125,
-74,
-72,
-152,
-80,
-24,
-77,
-1,
-96,
-39,
-190,
-111,
-5,
-176,
-155,
-145,
-192,
-140,
-31,
-30,
-94,
-119,
-18,
-18,
-38,
-30,
-70,
-123,
-5,
-48,
-61,
-203,
-178,
-185,
-158,
-58,
-107,
-149,
-232,
-139,
-66,
-156,
-144,
-144,
-16,
-9,
-163,
-153,
-27,
-240,
-97,
-227,
-89,
-254,
-27,
-99,
-76,
-150,
-101,
-123,
-27,
-99,
-246,
-30,
-110,
-119,
-18,
-18,
-18,
-162,
-98,
-152,
-230,
-191,
-201,
-16,
-40,
-33,
-161,
-57,
-146,
-29,
-64,
-66,
-194,
-4,
-70,
-18,
-0,
-9,
-9,
-19,
-24,
-73,
-0,
-36,
-36,
-76,
-96,
-36,
-1,
-144,
-144,
-48,
-129,
-145,
-4,
-64,
-66,
-194,
-4,
-198,
-184,
-19,
-0,
-73,
-219,
-159,
-144,
-16,
-15,
-227,
-78,
-0,
-36,
-36,
-36,
-196,
-67,
-18,
-0,
-9,
-9,
-19,
-24,
-73,
-0,
-36,
-36,
-76,
-96,
-36,
-1,
-144,
-144,
-48,
-117,
-14,
-169,
-49,
-0,
-0,
-2,
-74,
-73,
-68,
-65,
-84,
-129,
-145,
-4,
-64,
-66,
-194,
-4,
-70,
-175,
-206,
-64,
-89,
-150,
-101,
-125,
-242,
-79,
-72,
-72,
-232,
-134,
-180,
-2,
-72,
-72,
-152,
-192,
-72,
-2,
-32,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-33,
-225,
-255,
-219,
-131,
-3,
-2,
-0,
-0,
-0,
-0,
-33,
-253,
-95,
-221,
-17,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-0,
-208,
-17,
-112,
-180,
-144,
-16,
-164,
-2,
-78,
-0,
-0,
-0,
-0,
-73,
-69,
-78,
-68,
-174,
-66,
-96,
-130,
-};
-/* clang-format on */
diff --git a/scene/resources/default_theme/font_lodpi.inc b/scene/resources/default_theme/font_lodpi.inc
deleted file mode 100644
index d2f5851224..0000000000
--- a/scene/resources/default_theme/font_lodpi.inc
+++ /dev/null
@@ -1,13117 +0,0 @@
-/* clang-format off */
-static const int _lodpi_font_height=14;
-static const int _lodpi_font_ascent=11;
-static const int _lodpi_font_charcount=191;
-static const int _lodpi_font_charrects[191][8]={
-/* charidx , ofs_x, ofs_y, size_x, size_y, valign, halign, advance */
-{64,72,34,10,11,1,1,12},
-{224,85,180,5,11,0,1,7},
-{192,32,16,11,13,-2,-1,9},
-{96,2,216,3,2,0,3,8},
-{160,0,0,0,0,11,0,4},
-{32,0,0,0,0,11,0,4},
-{33,65,234,2,10,1,1,4},
-{225,112,169,5,11,0,1,7},
-{193,17,16,11,13,-2,-1,9},
-{161,2,222,2,11,3,1,4},
-{65,2,16,11,10,1,-1,9},
-{97,76,188,5,8,3,1,7},
-{98,102,165,6,11,0,1,8},
-{226,72,143,6,11,0,1,7},
-{194,113,2,11,13,-2,-1,9},
-{66,46,109,7,10,1,1,9},
-{162,12,136,6,10,1,1,8},
-{34,49,187,5,4,1,1,6},
-{35,78,66,8,10,1,0,9},
-{163,22,167,6,10,1,1,8},
-{195,53,2,11,14,-3,-1,9},
-{227,2,155,6,12,-1,1,7},
-{67,68,115,7,10,1,1,8},
-{99,40,179,5,8,3,1,7},
-{228,121,169,5,11,0,1,7},
-{196,98,2,11,13,-2,-1,9},
-{36,102,137,6,12,0,1,8},
-{100,82,150,6,11,0,1,8},
-{68,90,66,8,10,1,1,10},
-{164,14,79,8,7,3,0,8},
-{37,2,30,10,10,1,1,12},
-{69,29,191,5,10,1,1,7},
-{165,79,98,7,10,1,0,8},
-{229,20,196,5,12,-1,1,7},
-{197,83,2,11,12,-1,-1,9},
-{101,32,124,6,8,3,1,8},
-{38,67,49,9,10,1,1,10},
-{70,101,105,6,10,1,1,7},
-{198,21,2,12,10,1,-1,12},
-{166,95,228,2,14,0,3,7},
-{102,2,201,5,11,0,0,4},
-{230,58,34,10,8,3,1,12},
-{71,66,65,8,10,1,1,10},
-{231,2,186,5,11,3,1,7},
-{199,57,97,7,13,1,1,8},
-{103,13,107,7,11,3,1,7},
-{167,112,131,6,11,0,0,7},
-{39,119,219,2,4,1,1,3},
-{72,54,65,8,10,1,1,10},
-{232,62,143,6,11,0,1,8},
-{200,47,195,5,13,-2,1,7},
-{40,93,212,4,12,1,1,4},
-{104,72,158,6,11,0,1,8},
-{168,77,217,4,2,0,2,8},
-{73,38,191,5,10,1,0,5},
-{169,44,34,10,10,1,1,12},
-{233,52,142,6,11,0,1,8},
-{201,56,197,5,13,-2,1,7},
-{41,51,226,3,12,1,0,4},
-{105,109,213,3,11,0,0,4},
-{106,101,213,4,14,0,-1,4},
-{74,92,195,5,13,1,-2,3},
-{202,65,202,5,13,-2,1,7},
-{42,108,80,7,6,0,0,8},
-{170,29,205,4,5,1,0,5},
-{234,12,181,6,11,0,1,8},
-{171,22,181,5,6,4,1,7},
-{43,101,94,7,7,3,0,8},
-{107,112,92,7,11,0,1,7},
-{203,83,200,5,13,-2,1,7},
-{235,2,171,6,11,0,1,8},
-{75,102,66,8,10,1,1,8},
-{44,107,231,2,3,9,1,4},
-{172,2,104,7,4,6,0,8},
-{108,113,228,2,11,0,1,4},
-{204,101,196,5,13,-2,0,5},
-{236,30,214,3,11,0,0,4},
-{76,22,124,6,10,1,1,7},
-{173,16,229,3,2,7,1,5},
-{45,123,201,3,2,7,1,5},
-{109,68,2,11,8,3,1,13},
-{205,11,211,5,13,-2,0,5},
-{237,37,214,3,11,0,1,4},
-{77,62,20,10,10,1,1,12},
-{46,101,231,2,2,9,1,4},
-{110,111,107,6,8,3,1,8},
-{206,20,212,5,13,-2,0,5},
-{238,11,196,5,11,0,-1,4},
-{174,30,33,10,10,1,1,12},
-{78,2,79,8,10,1,1,10},
-{175,35,111,7,1,-1,0,7},
-{111,102,153,6,8,3,1,8},
-{207,119,184,5,13,-2,0,5},
-{239,69,219,4,11,0,0,4},
-{79,41,66,9,10,1,1,11},
-{47,90,105,7,10,1,-1,5},
-{176,61,219,4,4,1,1,6},
-{112,32,150,6,11,3,1,8},
-{240,82,165,6,11,0,1,8},
-{208,86,33,9,10,1,0,10},
-{80,52,128,6,10,1,1,8},
-{48,42,135,6,10,1,1,8},
-{177,46,97,7,8,3,0,8},
-{113,22,152,6,11,3,1,8},
-{241,2,112,6,12,-1,1,8},
-{81,15,59,9,13,1,1,11},
-{209,74,80,8,14,-3,1,10},
-{49,45,212,4,10,1,2,8},
-{178,58,187,5,6,1,0,5},
-{114,85,217,4,8,3,1,5},
-{210,2,62,9,13,-2,1,11},
-{242,62,165,6,11,0,1,8},
-{82,35,97,7,10,1,1,8},
-{50,57,114,7,10,1,1,8},
-{179,53,214,4,6,1,0,5},
-{115,112,146,6,8,3,0,7},
-{211,106,49,9,13,-2,1,11},
-{243,52,172,6,11,0,1,8},
-{83,24,96,7,10,1,0,7},
-{51,22,138,6,10,1,1,8},
-{180,9,228,3,2,0,3,8},
-{116,67,188,5,10,1,0,5},
-{212,93,49,9,13,-2,1,11},
-{244,42,164,6,11,0,1,8},
-{84,13,93,7,10,1,0,7},
-{52,24,110,7,10,1,1,8},
-{53,92,119,6,10,1,1,8},
-{85,114,66,8,10,1,1,10},
-{213,2,44,9,14,-3,1,11},
-{117,42,123,6,8,3,1,8},
-{181,2,140,6,11,3,1,8},
-{245,12,165,6,12,-1,1,8},
-{54,82,121,6,10,1,1,8},
-{86,76,18,10,10,1,-1,8},
-{246,72,173,6,11,0,1,8},
-{214,80,49,9,13,-2,1,11},
-{182,68,98,7,13,0,1,9},
-{118,15,47,9,8,3,-1,7},
-{55,72,129,6,10,1,1,8},
-{87,2,2,15,10,1,-1,13},
-{119,37,2,12,8,3,-1,10},
-{247,90,94,7,7,3,0,8},
-{215,2,93,7,7,3,0,8},
-{183,77,223,2,2,5,1,4},
-{56,62,129,6,10,1,1,8},
-{88,90,19,10,10,1,-1,8},
-{216,99,33,9,12,0,1,11},
-{248,2,128,6,8,3,1,8},
-{120,119,80,7,8,3,0,7},
-{184,116,212,3,3,11,0,3},
-{89,28,65,9,10,1,-1,7},
-{217,38,80,8,13,-2,1,10},
-{249,52,157,6,11,0,1,8},
-{121,112,33,9,11,3,-1,7},
-{57,12,122,6,10,1,1,8},
-{185,23,229,3,6,1,0,5},
-{218,26,79,8,13,-2,1,10},
-{250,42,149,6,11,0,1,8},
-{90,32,136,6,10,1,1,8},
-{122,112,119,6,8,3,1,7},
-{58,89,229,2,8,3,1,4},
-{186,37,205,4,5,1,0,5},
-{219,50,80,8,13,-2,1,10},
-{91,58,227,3,12,1,1,4},
-{123,103,180,5,12,1,0,5},
-{251,12,150,6,11,0,1,8},
-{59,71,234,2,9,3,1,4},
-{187,31,181,5,6,4,1,7},
-{188,16,33,10,10,1,0,10},
-{124,83,229,2,14,0,3,7},
-{220,62,79,8,13,-2,1,10},
-{252,92,133,6,11,0,1,8},
-{92,97,80,7,10,1,-1,5},
-{60,92,153,6,7,3,1,8},
-{189,47,20,11,10,1,0,10},
-{253,28,47,9,14,0,-1,7},
-{221,54,48,9,13,-2,-1,7},
-{93,44,226,3,12,1,0,4},
-{125,110,196,5,12,1,0,5},
-{61,79,112,7,5,4,0,8},
-{190,104,19,10,10,1,0,10},
-{222,32,165,6,10,1,1,8},
-{254,102,119,6,14,0,1,8},
-{62,112,158,6,7,3,1,8},
-{94,86,80,7,6,1,0,7},
-{126,62,158,6,3,5,1,8},
-{223,82,135,6,11,0,1,8},
-{255,41,48,9,14,0,-1,7},
-{191,94,180,5,11,3,0,6},
-{63,74,202,5,10,1,0,6},
-{95,92,148,6,1,12,0,6},
-};
-static const int _lodpi_font_kerning_pair_count=0;
-static const int _lodpi_font_kerning_pairs[1][3]={
-{0,0,0},
-};
-static const int _lodpi_font_img_width=128;
-static const int _lodpi_font_img_height=256;
-static const int _lodpi_font_img_data_size=12909;
-static const unsigned char _lodpi_font_img_data[12909]={
-137,
-80,
-78,
-71,
-13,
-10,
-26,
-10,
-0,
-0,
-0,
-13,
-73,
-72,
-68,
-82,
-0,
-0,
-0,
-128,
-0,
-0,
-1,
-0,
-8,
-6,
-0,
-0,
-0,
-123,
-249,
-126,
-167,
-0,
-0,
-32,
-0,
-73,
-68,
-65,
-84,
-120,
-156,
-237,
-157,
-119,
-184,
-30,
-85,
-181,
-255,
-191,
-59,
-128,
-8,
-210,
-155,
-82,
-77,
-232,
-221,
-2,
-210,
-164,
-132,
-26,
-154,
-5,
-164,
-131,
-63,
-224,
-98,
-65,
-4,
-68,
-46,
-8,
-42,
-23,
-84,
-80,
-41,
-94,
-16,
-21,
-17,
-197,
-10,
-22,
-80,
-17,
-21,
-4,
-5,
-65,
-16,
-41,
-42,
-185,
-116,
-19,
-106,
-128,
-80,
-46,
-32,
-33,
-148,
-208,
-18,
-62,
-191,
-63,
-214,
-122,
-115,
-230,
-204,
-217,
-51,
-179,
-103,
-222,
-121,
-223,
-115,
-146,
-123,
-190,
-207,
-115,
-158,
-51,
-101,
-237,
-50,
-243,
-174,
-217,
-123,
-237,
-213,
-182,
-52,
-138,
-81,
-140,
-98,
-20,
-2,
-150,
-3,
-222,
-0,
-54,
-207,
-93,
-255,
-32,
-134,
-247,
-231,
-174,
-111,
-237,
-244,
-203,
-38,
-212,
-61,
-31,
-48,
-149,
-2,
-68,
-232,
-87,
-242,
-91,
-107,
-102,
-174,
-253,
-28,
-184,
-58,
-115,
-190,
-178,
-211,
-172,
-88,
-243,
-57,
-199,
-84,
-220,
-7,
-216,
-17,
-184,
-21,
-120,
-21,
-184,
-23,
-216,
-9,
-56,
-192,
-143,
-103,
-0,
-55,
-1,
-235,
-36,
-180,
-245,
-117,
-224,
-122,
-224,
-244,
-58,
-125,
-244,
-178,
-247,
-0,
-239,
-4,
-222,
-13,
-220,
-85,
-179,
-236,
-55,
-253,
-57,
-190,
-89,
-69,
-59,
-251,
-101,
-132,
-16,
-30,
-151,
-116,
-171,
-164,
-157,
-114,
-52,
-59,
-74,
-186,
-94,
-210,
-118,
-185,
-235,
-59,
-73,
-250,
-123,
-8,
-225,
-137,
-132,
-62,
-237,
-39,
-233,
-113,
-73,
-11,
-248,
-249,
-206,
-126,
-188,
-64,
-230,
-218,
-108,
-132,
-16,
-30,
-145,
-116,
-175,
-164,
-205,
-252,
-129,
-230,
-149,
-180,
-161,
-164,
-21,
-129,
-133,
-156,
-108,
-115,
-73,
-147,
-67,
-8,
-143,
-150,
-53,
-12,
-28,
-9,
-76,
-3,
-206,
-4,
-198,
-74,
-186,
-49,
-161,
-191,
-103,
-75,
-58,
-76,
-210,
-242,
-178,
-103,
-191,
-88,
-210,
-17,
-146,
-118,
-151,
-52,
-78,
-210,
-51,
-146,
-190,
-157,
-80,
-207,
-102,
-33,
-132,
-45,
-37,
-109,
-157,
-64,
-155,
-199,
-204,
-204,
-241,
-172,
-212,
-66,
-192,
-119,
-37,
-45,
-41,
-105,
-13,
-73,
-75,
-251,
-121,
-114,
-225,
-19,
-128,
-137,
-185,
-107,
-15,
-1,
-59,
-3,
-255,
-202,
-93,
-191,
-11,
-248,
-108,
-98,
-189,
-119,
-2,
-251,
-250,
-49,
-64,
-158,
-153,
-98,
-101,
-206,
-1,
-206,
-247,
-227,
-109,
-128,
-75,
-129,
-31,
-117,
-70,
-34,
-224,
-188,
-20,
-14,
-7,
-110,
-241,
-209,
-226,
-76,
-224,
-57,
-224,
-136,
-10,
-122,
-128,
-79,
-100,
-206,
-215,
-205,
-247,
-217,
-71,
-136,
-23,
-18,
-218,
-190,
-223,
-203,
-222,
-93,
-69,
-59,
-34,
-0,
-172,
-159,
-29,
-214,
-129,
-53,
-128,
-71,
-252,
-120,
-42,
-176,
-188,
-31,
-175,
-232,
-15,
-182,
-118,
-66,
-157,
-59,
-1,
-143,
-250,
-87,
-92,
-135,
-1,
-62,
-216,
-121,
-113,
-192,
-89,
-192,
-97,
-192,
-65,
-192,
-185,
-126,
-237,
-110,
-114,
-211,
-82,
-65,
-61,
-165,
-67,
-126,
-132,
-30,
-96,
-219,
-204,
-249,
-88,
-191,
-54,
-54,
-115,
-109,
-115,
-24,
-58,
-117,
-69,
-234,
-186,
-12,
-248,
-53,
-240,
-251,
-58,
-125,
-240,
-178,
-59,
-121,
-187,
-249,
-17,
-185,
-167,
-101,
-59,
-95,
-252,
-193,
-126,
-124,
-100,
-230,
-43,
-252,
-17,
-112,
-144,
-31,
-127,
-28,
-184,
-47,
-177,
-190,
-107,
-128,
-207,
-100,
-206,
-135,
-160,
-160,
-220,
-162,
-192,
-107,
-254,
-255,
-62,
-76,
-46,
-88,
-14,
-120,
-16,
-88,
-204,
-239,
-45,
-146,
-216,
-135,
-228,
-23,
-226,
-116,
-155,
-103,
-206,
-59,
-12,
-176,
-66,
-230,
-90,
-37,
-3,
-0,
-227,
-128,
-151,
-252,
-99,
-121,
-41,
-203,
-64,
-137,
-125,
-238,
-134,
-121,
-26,
-151,
-21,
-112,
-54,
-112,
-177,
-31,
-255,
-1,
-216,
-211,
-143,
-247,
-7,
-46,
-244,
-227,
-75,
-129,
-175,
-37,
-212,
-245,
-110,
-224,
-5,
-96,
-177,
-204,
-53,
-252,
-7,
-121,
-115,
-231,
-175,
-164,
-252,
-77,
-192,
-129,
-192,
-29,
-153,
-107,
-119,
-0,
-7,
-3,
-55,
-212,
-120,
-166,
-228,
-23,
-210,
-34,
-3,
-156,
-14,
-252,
-218,
-143,
-47,
-1,
-78,
-171,
-209,
-223,
-198,
-204,
-211,
-45,
-227,
-9,
-216,
-22,
-19,
-154,
-22,
-0,
-158,
-7,
-22,
-247,
-235,
-111,
-5,
-30,
-199,
-36,
-250,
-231,
-201,
-173,
-22,
-10,
-234,
-250,
-121,
-236,
-139,
-39,
-97,
-10,
-240,
-242,
-39,
-3,
-55,
-0,
-95,
-201,
-92,
-59,
-195,
-25,
-227,
-164,
-196,
-58,
-106,
-189,
-144,
-54,
-24,
-192,
-25,
-251,
-25,
-96,
-15,
-63,
-223,
-195,
-207,
-11,
-153,
-61,
-87,
-190,
-27,
-230,
-105,
-92,
-182,
-83,
-193,
-188,
-206,
-0,
-31,
-7,
-110,
-206,
-221,
-187,
-29,
-27,
-9,
-158,
-162,
-122,
-57,
-53,
-22,
-27,
-166,
-215,
-206,
-126,
-237,
-53,
-25,
-96,
-75,
-167,
-223,
-44,
-115,
-109,
-187,
-252,
-181,
-138,
-58,
-106,
-189,
-144,
-150,
-24,
-224,
-64,
-255,
-72,
-22,
-240,
-243,
-55,
-3,
-211,
-129,
-3,
-19,
-250,
-219,
-152,
-121,
-186,
-101,
-188,
-108,
-69,
-63,
-195,
-164,
-231,
-47,
-230,
-174,
-127,
-205,
-191,
-190,
-31,
-36,
-212,
-113,
-54,
-240,
-219,
-200,
-117,
-72,
-156,
-2,
-186,
-69,
-107,
-47,
-164,
-126,
-187,
-127,
-39,
-142,
-91,
-18,
-202,
-118,
-195,
-60,
-141,
-203,
-230,
-43,
-218,
-219,
-59,
-252,
-222,
-220,
-245,
-9,
-126,
-253,
-3,
-21,
-229,
-23,
-7,
-94,
-4,
-198,
-71,
-238,
-13,
-65,
-173,
-206,
-213,
-64,
-107,
-47,
-164,
-94,
-155,
-239,
-1,
-102,
-97,
-43,
-168,
-236,
-200,
-183,
-154,
-95,
-223,
-176,
-162,
-124,
-55,
-204,
-211,
-184,
-236,
-92,
-137,
-225,
-120,
-33,
-216,
-106,
-233,
-55,
-5,
-247,
-46,
-5,
-126,
-88,
-82,
-182,
-49,
-243,
-116,
-203,
-120,
-115,
-29,
-134,
-227,
-133,
-0,
-75,
-2,
-47,
-3,
-91,
-21,
-220,
-223,
-214,
-239,
-47,
-89,
-112,
-191,
-27,
-230,
-105,
-92,
-118,
-174,
-196,
-156,
-246,
-66,
-186,
-97,
-158,
-110,
-25,
-111,
-174,
-195,
-232,
-11,
-105,
-1,
-116,
-163,
-78,
-180,
-242,
-75,
-1,
-255,
-11,
-252,
-180,
-102,
-185,
-159,
-123,
-185,
-165,
-154,
-180,
-59,
-138,
-150,
-64,
-55,
-234,
-68,
-43,
-127,
-5,
-166,
-195,
-175,
-171,
-139,
-159,
-7,
-51,
-163,
-254,
-161,
-73,
-187,
-163,
-104,
-1,
-116,
-171,
-78,
-156,
-139,
-1,
-44,
-3,
-188,
-14,
-108,
-19,
-185,
-183,
-131,
-223,
-91,
-102,
-56,
-250,
-214,
-4,
-69,
-95,
-231,
-39,
-36,
-93,
-233,
-182,
-246,
-63,
-250,
-121,
-50,
-186,
-153,
-62,
-186,
-157,
-122,
-122,
-141,
-16,
-194,
-83,
-146,
-174,
-146,
-180,
-103,
-228,
-246,
-158,
-146,
-254,
-228,
-52,
-131,
-0,
-44,
-136,
-57,
-121,
-124,
-46,
-114,
-239,
-72,
-191,
-183,
-96,
-228,
-222,
-217,
-152,
-129,
-238,
-62,
-224,
-204,
-204,
-245,
-177,
-152,
-133,
-54,
-201,
-32,
-150,
-12,
-90,
-208,
-158,
-117,
-51,
-125,
-212,
-41,
-235,
-194,
-222,
-143,
-129,
-215,
-114,
-215,
-43,
-95,
-142,
-51,
-217,
-171,
-184,
-173,
-35,
-119,
-239,
-77,
-192,
-211,
-80,
-104,
-169,
-220,
-215,
-229,
-148,
-121,
-50,
-215,
-230,
-245,
-50,
-251,
-148,
-180,
-185,
-30,
-102,
-28,
-219,
-58,
-115,
-109,
-99,
-204,
-79,
-97,
-221,
-130,
-50,
-107,
-250,
-180,
-184,
-46,
-240,
-104,
-230,
-250,
-133,
-192,
-167,
-138,
-218,
-106,
-12,
-186,
-212,
-158,
-117,
-51,
-125,
-212,
-45,
-11,
-252,
-2,
-179,
-77,
-204,
-200,
-93,
-175,
-124,
-57,
-206,
-0,
-55,
-147,
-113,
-254,
-200,
-220,
-219,
-3,
-184,
-177,
-132,
-1,
-22,
-244,
-119,
-180,
-77,
-230,
-218,
-118,
-217,
-247,
-86,
-210,
-238,
-199,
-128,
-39,
-129,
-101,
-157,
-129,
-31,
-6,
-62,
-86,
-81,
-230,
-58,
-103,
-174,
-143,
-248,
-249,
-187,
-48,
-103,
-147,
-55,
-149,
-149,
-107,
-4,
-186,
-212,
-158,
-49,
-12,
-150,
-44,
-96,
-102,
-230,
-56,
-233,
-229,
-248,
-51,
-29,
-79,
-206,
-224,
-229,
-247,
-254,
-0,
-28,
-81,
-196,
-0,
-78,
-243,
-35,
-220,
-57,
-197,
-207,
-207,
-3,
-126,
-148,
-216,
-223,
-95,
-96,
-190,
-130,
-127,
-0,
-126,
-145,
-88,
-102,
-89,
-224,
-223,
-126,
-252,
-39,
-220,
-195,
-170,
-85,
-208,
-189,
-30,
-123,
-88,
-44,
-89,
-57,
-6,
-72,
-122,
-57,
-206,
-0,
-219,
-98,
-243,
-235,
-26,
-153,
-235,
-203,
-3,
-255,
-196,
-220,
-208,
-202,
-24,
-96,
-59,
-124,
-26,
-240,
-191,
-167,
-200,
-120,
-18,
-85,
-180,
-189,
-48,
-54,
-69,
-61,
-69,
-197,
-28,
-142,
-59,
-189,
-2,
-107,
-97,
-158,
-85,
-219,
-99,
-14,
-171,
-1,
-27,
-253,
-94,
-43,
-43,
-95,
-11,
-116,
-169,
-61,
-99,
-152,
-44,
-89,
-29,
-6,
-200,
-188,
-156,
-147,
-128,
-73,
-216,
-240,
-26,
-157,
-10,
-156,
-1,
-182,
-195,
-124,
-14,
-190,
-156,
-185,
-254,
-121,
-224,
-112,
-191,
-87,
-198,
-0,
-99,
-128,
-199,
-156,
-81,
-182,
-246,
-31,
-52,
-105,
-201,
-235,
-31,
-218,
-116,
-108,
-154,
-27,
-178,
-154,
-200,
-209,
-222,
-130,
-9,
-128,
-119,
-2,
-239,
-243,
-231,
-219,
-14,
-88,
-221,
-127,
-175,
-25,
-101,
-229,
-147,
-65,
-11,
-218,
-51,
-134,
-201,
-146,
-5,
-204,
-244,
-47,
-162,
-243,
-114,
-54,
-197,
-28,
-90,
-22,
-3,
-166,
-23,
-148,
-233,
-48,
-192,
-106,
-206,
-40,
-99,
-188,
-142,
-187,
-49,
-107,
-102,
-41,
-3,
-120,
-29,
-103,
-96,
-186,
-142,
-179,
-73,
-116,
-253,
-118,
-198,
-254,
-23,
-240,
-73,
-224,
-88,
-108,
-4,
-90,
-168,
-186,
-164,
-4,
-236,
-7,
-252,
-17,
-152,
-31,
-184,
-26,
-120,
-27,
-240,
-122,
-74,
-217,
-158,
-131,
-97,
-182,
-100,
-117,
-94,
-78,
-238,
-218,
-4,
-224,
-138,
-2,
-122,
-112,
-199,
-20,
-76,
-224,
-219,
-22,
-24,
-143,
-207,
-201,
-137,
-12,
-240,
-14,
-108,
-249,
-54,
-25,
-88,
-191,
-170,
-143,
-94,
-230,
-76,
-224,
-42,
-103,
-182,
-121,
-128,
-127,
-0,
-149,
-46,
-230,
-216,
-202,
-228,
-126,
-44,
-86,
-224,
-28,
-6,
-166,
-202,
-153,
-85,
-101,
-251,
-2,
-134,
-209,
-146,
-149,
-125,
-57,
-153,
-107,
-155,
-2,
-215,
-82,
-108,
-121,
-203,
-50,
-192,
-161,
-216,
-114,
-242,
-2,
-96,
-123,
-191,
-86,
-201,
-0,
-78,
-119,
-59,
-112,
-123,
-21,
-157,
-211,
-110,
-9,
-60,
-75,
-38,
-152,
-5,
-243,
-196,
-126,
-149,
-204,
-210,
-176,
-160,
-236,
-81,
-192,
-5,
-126,
-252,
-47,
-108,
-138,
-155,
-228,
-207,
-49,
-188,
-90,
-83,
-134,
-217,
-146,
-149,
-125,
-57,
-126,
-190,
-13,
-112,
-17,
-176,
-112,
-73,
-153,
-44,
-3,
-44,
-14,
-252,
-219,
-95,
-236,
-24,
-191,
-150,
-196,
-0,
-169,
-0,
-222,
-2,
-60,
-64,
-68,
-166,
-193,
-228,
-144,
-7,
-129,
-183,
-20,
-148,
-93,
-4,
-147,
-55,
-198,
-70,
-238,
-141,
-140,
-17,
-96,
-184,
-16,
-123,
-57,
-206,
-48,
-247,
-101,
-190,
-146,
-141,
-34,
-229,
-102,
-51,
-128,
-159,
-255,
-146,
-140,
-11,
-92,
-219,
-12,
-48,
-226,
-1,
-108,
-229,
-28,
-122,
-47,
-176,
-113,
-230,
-250,
-242,
-152,
-144,
-212,
-174,
-202,
-113,
-20,
-35,
-11,
-152,
-20,
-190,
-13,
-166,
-139,
-191,
-46,
-115,
-253,
-7,
-192,
-145,
-195,
-217,
-183,
-81,
-244,
-1,
-216,
-154,
-244,
-45,
-192,
-66,
-248,
-210,
-9,
-211,
-63,
-223,
-75,
-47,
-84,
-142,
-163,
-24,
-89,
-192,
-140,
-20,
-29,
-6,
-120,
-222,
-175,
-93,
-78,
-137,
-113,
-195,
-105,
-26,
-27,
-100,
-156,
-110,
-39,
-204,
-0,
-116,
-149,
-255,
-93,
-6,
-76,
-232,
-254,
-137,
-134,
-31,
-12,
-198,
-12,
-44,
-170,
-233,
-68,
-42,
-236,
-5,
-5,
-117,
-189,
-189,
-224,
-250,
-82,
-190,
-138,
-200,
-135,
-245,
-111,
-130,
-197,
-101,
-44,
-157,
-218,
-192,
-13,
-153,
-41,
-224,
-111,
-216,
-154,
-248,
-159,
-152,
-150,
-107,
-136,
-108,
-144,
-41,
-215,
-141,
-65,
-230,
-100,
-224,
-123,
-89,
-9,
-31,
-88,
-218,
-175,
-149,
-70,
-254,
-212,
-101,
-28,
-111,
-107,
-50,
-240,
-138,
-255,
-159,
-0,
-124,
-26,
-51,
-204,
-60,
-5,
-156,
-75,
-196,
-28,
-155,
-41,
-191,
-14,
-240,
-83,
-23,
-56,
-159,
-198,
-150,
-157,
-167,
-149,
-49,
-184,
-255,
-240,
-157,
-24,
-136,
-177,
-192,
-7,
-48,
-101,
-213,
-223,
-139,
-218,
-194,
-116,
-254,
-223,
-243,
-118,
-94,
-5,
-166,
-248,
-52,
-252,
-34,
-176,
-92,
-65,
-153,
-139,
-240,
-24,
-206,
-204,
-181,
-115,
-113,
-187,
-74,
-18,
-128,
-205,
-48,
-201,
-249,
-126,
-96,
-139,
-140,
-76,
-16,
-149,
-13,
-34,
-229,
-107,
-25,
-100,
-128,
-93,
-24,
-80,
-186,
-128,
-169,
-70,
-31,
-7,
-142,
-245,
-107,
-223,
-43,
-250,
-65,
-155,
-48,
-14,
-102,
-194,
-125,
-15,
-182,
-228,
-251,
-152,
-127,
-145,
-147,
-176,
-105,
-110,
-37,
-255,
-0,
-162,
-241,
-142,
-192,
-110,
-254,
-110,
-246,
-194,
-109,
-19,
-152,
-99,
-200,
-119,
-252,
-171,
-142,
-46,
-55,
-253,
-185,
-182,
-203,
-93,
-91,
-8,
-91,
-242,
-157,
-16,
-161,
-95,
-10,
-19,
-184,
-127,
-131,
-41,
-153,
-22,
-1,
-54,
-192,
-84,
-228,
-143,
-20,
-49,
-27,
-3,
-150,
-200,
-5,
-253,
-124,
-126,
-44,
-186,
-107,
-151,
-24,
-125,
-37,
-128,
-125,
-112,
-229,
-2,
-17,
-217,
-160,
-160,
-76,
-45,
-131,
-12,
-230,
-50,
-182,
-148,
-31,
-131,
-169,
-53,
-87,
-195,
-194,
-211,
-23,
-244,
-31,
-244,
-178,
-72,
-185,
-44,
-227,
-172,
-4,
-252,
-197,
-31,
-246,
-119,
-126,
-173,
-144,
-113,
-50,
-117,
-204,
-139,
-105,
-24,
-63,
-150,
-185,
-182,
-7,
-240,
-112,
-132,
-118,
-172,
-191,
-252,
-149,
-10,
-234,
-186,
-144,
-140,
-45,
-33,
-119,
-111,
-8,
-3,
-248,
-245,
-207,
-17,
-201,
-250,
-1,
-252,
-183,
-51,
-229,
-152,
-28,
-237,
-3,
-152,
-138,
-250,
-11,
-5,
-237,
-4,
-103,
-170,
-255,
-231,
-231,
-123,
-249,
-199,
-52,
-79,
-140,
-190,
-20,
-152,
-86,
-237,
-94,
-92,
-181,
-73,
-68,
-54,
-40,
-40,
-151,
-55,
-200,
-148,
-90,
-171,
-24,
-156,
-238,
-5,
-224,
-67,
-192,
-113,
-152,
-110,
-188,
-163,
-140,
-185,
-42,
-82,
-46,
-203,
-56,
-191,
-195,
-244,
-241,
-99,
-112,
-61,
-64,
-9,
-227,
-172,
-128,
-133,
-188,
-61,
-236,
-127,
-49,
-188,
-17,
-41,
-247,
-117,
-224,
-56,
-63,
-94,
-13,
-83,
-27,
-79,
-197,
-134,
-230,
-21,
-48,
-245,
-245,
-189,
-145,
-114,
-67,
-144,
-185,
-247,
-65,
-224,
-229,
-72,
-153,
-201,
-157,
-182,
-252,
-124,
-93,
-76,
-167,
-177,
-165,
-191,
-155,
-59,
-242,
-101,
-50,
-180,
-159,
-7,
-174,
-241,
-227,
-203,
-129,
-83,
-139,
-104,
-75,
-1,
-124,
-138,
-140,
-93,
-27,
-147,
-7,
-182,
-198,
-101,
-131,
-146,
-114,
-121,
-131,
-76,
-169,
-181,
-42,
-194,
-0,
-87,
-96,
-115,
-241,
-58,
-153,
-235,
-49,
-6,
-200,
-150,
-123,
-14,
-88,
-61,
-66,
-19,
-43,
-247,
-103,
-204,
-211,
-104,
-17,
-103,
-24,
-176,
-16,
-184,
-172,
-237,
-97,
-136,
-233,
-25,
-251,
-34,
-215,
-246,
-227,
-107,
-128,
-195,
-252,
-248,
-85,
-44,
-98,
-122,
-12,
-240,
-74,
-164,
-92,
-39,
-16,
-118,
-167,
-124,
-221,
-192,
-238,
-192,
-139,
-145,
-50,
-175,
-0,
-123,
-249,
-241,
-188,
-152,
-12,
-118,
-150,
-159,
-239,
-89,
-244,
-46,
-253,
-254,
-114,
-152,
-208,
-183,
-14,
-230,
-151,
-184,
-70,
-17,
-109,
-33,
-252,
-229,
-60,
-202,
-96,
-93,
-245,
-32,
-217,
-160,
-162,
-124,
-178,
-181,
-202,
-127,
-240,
-37,
-253,
-24,
-167,
-61,
-16,
-56,
-207,
-175,
-45,
-69,
-252,
-75,
-206,
-51,
-192,
-106,
-17,
-154,
-24,
-3,
-188,
-4,
-236,
-234,
-199,
-227,
-188,
-205,
-83,
-202,
-158,
-199,
-105,
-95,
-102,
-96,
-110,
-125,
-9,
-120,
-59,
-54,
-26,
-130,
-141,
-150,
-139,
-3,
-79,
-23,
-148,
-133,
-248,
-20,
-240,
-37,
-224,
-214,
-200,
-245,
-87,
-24,
-200,
-199,
-112,
-2,
-54,
-34,
-116,
-204,
-227,
-123,
-17,
-25,
-53,
-114,
-229,
-127,
-135,
-77,
-191,
-133,
-31,
-106,
-207,
-64,
-77,
-107,
-21,
-102,
-219,
-254,
-185,
-31,
-119,
-24,
-32,
-96,
-158,
-50,
-155,
-96,
-115,
-249,
-16,
-199,
-208,
-28,
-227,
-252,
-22,
-243,
-34,
-26,
-195,
-192,
-180,
-80,
-196,
-56,
-147,
-176,
-233,
-226,
-173,
-216,
-84,
-112,
-163,
-51,
-208,
-222,
-206,
-16,
-239,
-5,
-118,
-143,
-148,
-123,
-9,
-88,
-212,
-143,
-31,
-194,
-134,
-227,
-29,
-176,
-17,
-96,
-25,
-44,
-140,
-254,
-226,
-130,
-103,
-28,
-194,
-0,
-94,
-230,
-73,
-224,
-63,
-35,
-244,
-147,
-49,
-47,
-165,
-245,
-48,
-33,
-117,
-211,
-204,
-189,
-227,
-129,
-59,
-99,
-237,
-228,
-222,
-41,
-184,
-235,
-88,
-95,
-65,
-3,
-107,
-21,
-240,
-85,
-44,
-16,
-36,
-43,
-205,
-47,
-133,
-45,
-45,
-79,
-46,
-40,
-147,
-101,
-156,
-149,
-176,
-37,
-224,
-52,
-60,
-137,
-85,
-9,
-227,
-108,
-143,
-205,
-253,
-211,
-129,
-111,
-97,
-67,
-236,
-209,
-126,
-237,
-117,
-108,
-78,
-143,
-249,
-7,
-78,
-196,
-163,
-156,
-177,
-161,
-123,
-138,
-63,
-215,
-4,
-224,
-127,
-48,
-225,
-108,
-229,
-130,
-190,
-130,
-77,
-1,
-11,
-96,
-242,
-194,
-1,
-152,
-176,
-118,
-13,
-145,
-21,
-18,
-230,
-91,
-112,
-15,
-54,
-141,
-158,
-150,
-185,
-62,
-143,
-51,
-71,
-244,
-157,
-100,
-232,
-118,
-114,
-134,
-45,
-52,
-130,
-245,
-4,
-116,
-97,
-173,
-242,
-31,
-244,
-10,
-108,
-202,
-184,
-218,
-143,
-75,
-151,
-47,
-77,
-24,
-167,
-41,
-128,
-255,
-44,
-98,
-224,
-132,
-178,
-89,
-60,
-143,
-45,
-169,
-143,
-2,
-230,
-43,
-160,
-95,
-6,
-147,
-222,
-95,
-198,
-150,
-172,
-11,
-99,
-115,
-250,
-149,
-206,
-116,
-67,
-150,
-129,
-206,
-28,
-11,
-97,
-194,
-232,
-93,
-192,
-25,
-77,
-250,
-58,
-199,
-161,
-9,
-227,
-52,
-108,
-103,
-62,
-255,
-98,
-127,
-69,
-198,
-117,
-219,
-127,
-172,
-86,
-29,
-51,
-177,
-21,
-204,
-115,
-152,
-101,
-242,
-49,
-76,
-168,
-155,
-234,
-35,
-86,
-52,
-84,
-206,
-71,
-150,
-87,
-188,
-220,
-15,
-128,
-249,
-219,
-236,
-147,
-168,
-25,
-218,
-53,
-55,
-194,
-153,
-224,
-211,
-152,
-84,
-62,
-13,
-243,
-29,
-120,
-0,
-23,
-88,
-91,
-110,
-43,
-26,
-31,
-208,
-55,
-144,
-203,
-172,
-73,
-196,
-109,
-122,
-20,
-115,
-15,
-98,
-95,
-247,
-254,
-146,
-54,
-240,
-227,
-219,
-36,
-213,
-138,
-238,
-29,
-197,
-28,
-142,
-58,
-67,
-190,
-207,
-89,
-175,
-145,
-243,
-184,
-193,
-194,
-157,
-94,
-45,
-154,
-183,
-114,
-180,
-141,
-194,
-200,
-71,
-209,
-3,
-48,
-216,
-18,
-213,
-17,
-64,
-190,
-77,
-137,
-73,
-17,
-211,
-174,
-125,
-35,
-119,
-237,
-219,
-20,
-172,
-141,
-35,
-229,
-107,
-133,
-145,
-211,
-48,
-139,
-246,
-40,
-163,
-85,
-128,
-1,
-75,
-212,
-165,
-12,
-88,
-162,
-214,
-243,
-31,
-248,
-62,
-92,
-25,
-18,
-41,
-183,
-11,
-166,
-194,
-237,
-228,
-2,
-126,
-147,
-11,
-73,
-61,
-177,
-233,
-99,
-214,
-183,
-14,
-3,
-36,
-121,
-227,
-122,
-185,
-36,
-70,
-195,
-20,
-66,
-19,
-49,
-69,
-204,
-237,
-84,
-104,
-63,
-115,
-101,
-107,
-51,
-39,
-53,
-82,
-187,
-231,
-202,
-181,
-203,
-208,
-152,
-37,
-234,
-94,
-114,
-22,
-36,
-76,
-203,
-54,
-153,
-98,
-139,
-215,
-60,
-62,
-98,
-236,
-226,
-231,
-187,
-59,
-35,
-69,
-95,
-52,
-109,
-57,
-48,
-244,
-8,
-152,
-54,
-243,
-84,
-96,
-9,
-76,
-115,
-152,
-148,
-19,
-217,
-203,
-214,
-98,
-78,
-224,
-187,
-152,
-86,
-114,
-117,
-76,
-135,
-145,
-156,
-218,
-189,
-238,
-200,
-153,
-82,
-225,
-32,
-75,
-84,
-238,
-222,
-241,
-101,
-28,
-141,
-41,
-102,
-126,
-230,
-199,
-191,
-161,
-192,
-108,
-153,
-161,
-175,
-229,
-192,
-208,
-132,
-105,
-176,
-168,
-160,
-105,
-228,
-220,
-176,
-49,
-83,
-247,
-179,
-37,
-35,
-218,
-11,
-25,
-102,
-222,
-139,
-2,
-61,
-255,
-92,
-7,
-50,
-150,
-168,
-200,
-189,
-82,
-67,
-4,
-102,
-38,
-157,
-142,
-185,
-135,
-205,
-160,
-192,
-118,
-158,
-161,
-175,
-237,
-192,
-80,
-151,
-105,
-252,
-254,
-137,
-152,
-118,
-44,
-100,
-174,
-221,
-70,
-196,
-25,
-35,
-115,
-255,
-39,
-152,
-61,
-98,
-2,
-166,
-149,
-59,
-172,
-236,
-89,
-188,
-76,
-19,
-217,
-169,
-47,
-101,
-146,
-209,
-13,
-3,
-56,
-205,
-95,
-49,
-15,
-153,
-63,
-150,
-209,
-57,
-109,
-109,
-7,
-134,
-134,
-76,
-179,
-136,
-127,
-237,
-239,
-243,
-243,
-157,
-177,
-136,
-227,
-178,
-128,
-145,
-245,
-48,
-211,
-246,
-27,
-192,
-222,
-9,
-207,
-82,
-91,
-118,
-234,
-87,
-153,
-90,
-192,
-116,
-205,
-199,
-23,
-220,
-75,
-177,
-68,
-29,
-236,
-47,
-46,
-150,
-58,
-37,
-70,
-95,
-203,
-129,
-161,
-9,
-211,
-100,
-218,
-185,
-193,
-143,
-255,
-74,
-193,
-52,
-231,
-247,
-223,
-235,
-12,
-115,
-54,
-166,
-233,
-251,
-25,
-3,
-206,
-41,
-135,
-19,
-113,
-200,
-160,
-129,
-236,
-212,
-175,
-50,
-181,
-128,
-37,
-130,
-190,
-47,
-210,
-64,
-146,
-37,
-170,
-65,
-123,
-181,
-29,
-24,
-234,
-50,
-141,
-211,
-45,
-236,
-95,
-253,
-103,
-49,
-169,
-57,
-26,
-126,
-229,
-180,
-119,
-0,
-95,
-242,
-227,
-149,
-24,
-112,
-200,
-92,
-206,
-153,
-237,
-195,
-145,
-50,
-181,
-101,
-167,
-126,
-149,
-169,
-133,
-204,
-16,
-115,
-21,
-230,
-138,
-148,
-181,
-68,
-117,
-63,
-196,
-196,
-219,
-172,
-229,
-192,
-208,
-132,
-105,
-188,
-220,
-113,
-24,
-134,
-216,
-224,
-115,
-116,
-47,
-2,
-187,
-101,
-206,
-87,
-198,
-28,
-100,
-94,
-0,
-190,
-95,
-80,
-166,
-246,
-212,
-217,
-175,
-50,
-41,
-200,
-238,
-26,
-246,
-140,
-164,
-77,
-36,
-77,
-145,
-244,
-39,
-73,
-255,
-150,
-101,
-8,
-123,
-80,
-182,
-251,
-85,
-161,
-67,
-104,
-23,
-248,
-158,
-164,
-237,
-37,
-37,
-165,
-109,
-245,
-157,
-205,
-174,
-148,
-116,
-150,
-108,
-199,
-178,
-201,
-137,
-237,
-116,
-148,
-82,
-67,
-210,
-215,
-231,
-112,
-163,
-164,
-227,
-176,
-101,
-220,
-56,
-73,
-155,
-202,
-118,
-239,
-154,
-79,
-210,
-180,
-196,
-182,
-230,
-40,
-204,
-155,
-61,
-241,
-45,
-224,
-62,
-218,
-199,
-246,
-103,
-74,
-154,
-33,
-233,
-162,
-26,
-101,
-190,
-39,
-233,
-119,
-170,
-215,
-207,
-212,
-32,
-207,
-131,
-36,
-125,
-93,
-198,
-248,
-11,
-73,
-154,
-36,
-233,
-11,
-146,
-110,
-146,
-116,
-45,
-240,
-74,
-8,
-33,
-191,
-130,
-152,
-34,
-41,
-234,
-16,
-226,
-215,
-239,
-143,
-92,
-239,
-87,
-153,
-222,
-131,
-226,
-165,
-73,
-52,
-89,
-34,
-93,
-58,
-48,
-208,
-192,
-235,
-133,
-129,
-93,
-63,
-86,
-173,
-211,
-86,
-98,
-221,
-181,
-101,
-167,
-126,
-149,
-233,
-57,
-40,
-95,
-154,
-60,
-64,
-102,
-179,
-168,
-76,
-153,
-218,
-14,
-12,
-45,
-48,
-77,
-47,
-25,
-160,
-182,
-236,
-212,
-175,
-50,
-61,
-7,
-189,
-94,
-154,
-12,
-212,
-215,
-91,
-175,
-151,
-46,
-145,
-25,
-5,
-31,
-167,
-190,
-82,
-167,
-167,
-101,
-154,
-62,
-80,
-82,
-198,
-110,
-122,
-189,
-52,
-25,
-197,
-240,
-128,
-196,
-140,
-221,
-244,
-104,
-105,
-50,
-138,
-254,
-97,
-222,
-216,
-197,
-16,
-194,
-44,
-73,
-71,
-181,
-80,
-127,
-123,
-73,
-12,
-71,
-209,
-19,
-12,
-50,
-37,
-82,
-223,
-216,
-48,
-69,
-229,
-75,
-147,
-41,
-249,
-139,
-52,
-180,
-210,
-213,
-133,
-11,
-125,
-177,
-168,
-156,
-194,
-220,
-63,
-152,
-47,
-195,
-49,
-152,
-63,
-192,
-75,
-152,
-98,
-232,
-110,
-160,
-141,
-143,
-97,
-100,
-163,
-66,
-162,
-47,
-146,
-76,
-171,
-150,
-38,
-255,
-85,
-208,
-86,
-19,
-43,
-93,
-45,
-230,
-172,
-203,
-0,
-254,
-227,
-95,
-135,
-5,
-101,
-236,
-224,
-140,
-250,
-86,
-224,
-253,
-177,
-122,
-114,
-253,
-122,
-202,
-143,
-151,
-6,
-30,
-47,
-233,
-79,
-7,
-149,
-201,
-34,
-98,
-253,
-199,
-98,
-45,
-175,
-35,
-30,
-195,
-56,
-147,
-248,
-30,
-6,
-105,
-201,
-174,
-104,
-102,
-160,
-40,
-91,
-154,
-220,
-73,
-65,
-6,
-76,
-106,
-90,
-233,
-26,
-50,
-103,
-93,
-6,
-56,
-14,
-75,
-252,
-80,
-107,
-4,
-2,
-118,
-197,
-147,
-81,
-98,
-219,
-202,
-71,
-211,
-220,
-123,
-127,
-146,
-147,
-69,
-228,
-251,
-15,
-124,
-25,
-27,
-153,
-138,
-114,
-4,
-212,
-122,
-222,
-14,
-178,
-83,
-192,
-174,
-146,
-190,
-239,
-243,
-255,
-108,
-132,
-16,
-222,
-144,
-169,
-106,
-135,
-108,
-22,
-25,
-81,
-31,
-79,
-147,
-116,
-151,
-164,
-151,
-36,
-109,
-17,
-66,
-24,
-18,
-1,
-235,
-229,
-158,
-151,
-244,
-223,
-146,
-58,
-43,
-136,
-207,
-74,
-58,
-35,
-132,
-240,
-66,
-65,
-63,
-63,
-43,
-233,
-85,
-73,
-31,
-10,
-33,
-220,
-30,
-66,
-120,
-62,
-132,
-112,
-167,
-108,
-131,
-134,
-55,
-36,
-125,
-166,
-160,
-92,
-29,
-236,
-39,
-233,
-188,
-6,
-42,
-239,
-13,
-36,
-77,
-140,
-28,
-199,
-240,
-122,
-8,
-225,
-149,
-16,
-194,
-148,
-16,
-194,
-111,
-37,
-109,
-37,
-105,
-41,
-73,
-71,
-151,
-53,
-0,
-28,
-42,
-105,
-15,
-73,
-59,
-250,
-187,
-107,
-31,
-180,
-36,
-209,
-99,
-86,
-186,
-137,
-249,
-145,
-36,
-66,
-87,
-199,
-74,
-215,
-196,
-122,
-86,
-138,
-8,
-253,
-12,
-96,
-191,
-148,
-103,
-116,
-250,
-231,
-252,
-111,
-38,
-102,
-44,
-26,
-116,
-92,
-208,
-159,
-58,
-201,
-34,
-240,
-175,
-247,
-3,
-62,
-250,
-69,
-115,
-4,
-37,
-212,
-159,
-60,
-2,
-180,
-133,
-79,
-75,
-90,
-69,
-210,
-37,
-148,
-36,
-67,
-242,
-175,
-253,
-12,
-73,
-95,
-145,
-116,
-122,
-8,
-225,
-165,
-146,
-58,
-223,
-46,
-233,
-161,
-130,
-123,
-15,
-122,
-123,
-49,
-236,
-44,
-105,
-129,
-220,
-223,
-206,
-69,
-93,
-146,
-217,
-38,
-102,
-163,
-140,
-97,
-66,
-8,
-139,
-133,
-16,
-22,
-147,
-244,
-164,
-164,
-181,
-252,
-248,
-127,
-37,
-173,
-238,
-199,
-169,
-184,
-167,
-164,
-255,
-235,
-75,
-250,
-153,
-108,
-116,
-28,
-146,
-189,
-164,
-13,
-100,
-25,
-96,
-138,
-90,
-48,
-54,
-132,
-16,
-238,
-149,
-89,
-248,
-222,
-144,
-84,
-149,
-201,
-58,
-213,
-74,
-215,
-20,
-157,
-33,
-119,
-246,
-95,
-73,
-159,
-30,
-148,
-148,
-207,
-53,
-80,
-198,
-48,
-194,
-118,
-20,
-39,
-132,
-48,
-21,
-75,
-224,
-52,
-203,
-13,
-106,
-117,
-48,
-70,
-210,
-172,
-130,
-123,
-235,
-203,
-166,
-166,
-147,
-128,
-229,
-107,
-214,
-155,
-220,
-120,
-7,
-151,
-73,
-58,
-36,
-63,
-116,
-251,
-249,
-193,
-146,
-46,
-77,
-173,
-52,
-132,
-240,
-247,
-16,
-194,
-110,
-33,
-132,
-170,
-60,
-182,
-169,
-86,
-186,
-41,
-234,
-189,
-37,
-236,
-18,
-73,
-135,
-146,
-145,
-176,
-203,
-24,
-198,
-135,
-249,
-127,
-73,
-90,
-214,
-143,
-39,
-75,
-90,
-174,
-51,
-53,
-212,
-104,
-247,
-157,
-94,
-54,
-134,
-11,
-93,
-86,
-184,
-72,
-210,
-79,
-200,
-172,
-154,
-34,
-152,
-37,
-51,
-91,
-231,
-241,
-38,
-229,
-70,
-182,
-44,
-178,
-12,
-112,
-170,
-19,
-95,
-73,
-70,
-162,
-151,
-116,
-185,
-211,
-69,
-51,
-104,
-245,
-9,
-173,
-49,
-103,
-9,
-206,
-144,
-9,
-175,
-127,
-194,
-178,
-164,
-45,
-138,
-173,
-74,
-162,
-95,
-158,
-15,
-243,
-231,
-72,
-58,
-209,
-143,
-207,
-148,
-116,
-82,
-102,
-106,
-168,
-4,
-102,
-49,
-253,
-152,
-108,
-152,
-47,
-195,
-103,
-36,
-173,
-36,
-233,
-216,
-18,
-154,
-123,
-37,
-189,
-59,
-114,
-125,
-35,
-191,
-151,
-212,
-161,
-254,
-24,
-27,
-6,
-218,
-75,
-178,
-210,
-209,
-204,
-122,
-86,
-91,
-40,
-194,
-188,
-154,
-191,
-137,
-101,
-5,
-155,
-233,
-130,
-225,
-189,
-20,
-236,
-235,
-227,
-237,
-79,
-240,
-227,
-203,
-40,
-217,
-234,
-206,
-251,
-83,
-39,
-89,
-196,
-160,
-254,
-99,
-233,
-239,
-95,
-6,
-54,
-200,
-211,
-250,
-253,
-61,
-48,
-167,
-217,
-3,
-253,
-119,
-124,
-27,
-112,
-144,
-11,
-165,
-251,
-23,
-245,
-107,
-142,
-65,
-191,
-153,
-51,
-177,
-79,
-79,
-116,
-218,
-247,
-227,
-183,
-149,
-208,
-102,
-145,
-146,
-44,
-98,
-8,
-3,
-99,
-241,
-23,
-147,
-41,
-78,
-43,
-255,
-62,
-44,
-132,
-253,
-101,
-103,
-222,
-155,
-129,
-15,
-117,
-243,
-140,
-163,
-24,
-197,
-40,
-70,
-49,
-138,
-185,
-31,
-62,
-231,
-220,
-157,
-159,
-147,
-42,
-132,
-166,
-43,
-124,
-94,
-126,
-210,
-231,
-230,
-239,
-2,
-151,
-39,
-180,
-53,
-98,
-66,
-181,
-105,
-24,
-110,
-62,
-183,
-32,
-175,
-9,
-92,
-84,
-210,
-49,
-53,
-202,
-63,
-41,
-105,
-89,
-73,
-107,
-75,
-90,
-75,
-210,
-91,
-252,
-90,
-21,
-46,
-144,
-45,
-125,
-134,
-4,
-90,
-228,
-65,
-162,
-119,
-82,
-174,
-76,
-157,
-144,
-235,
-236,
-26,
-185,
-72,
-33,
-83,
-214,
-86,
-85,
-184,
-249,
-10,
-152,
-89,
-121,
-205,
-18,
-154,
-206,
-190,
-73,
-235,
-213,
-108,
-187,
-52,
-112,
-21,
-203,
-99,
-124,
-117,
-238,
-218,
-159,
-201,
-236,
-175,
-148,
-189,
-1,
-240,
-31,
-46,
-161,
-142,
-203,
-92,
-47,
-27,
-1,
-30,
-3,
-86,
-201,
-156,
-47,
-82,
-213,
-169,
-186,
-32,
-209,
-59,
-41,
-67,
-223,
-56,
-228,
-58,
-177,
-254,
-90,
-57,
-148,
-128,
-243,
-49,
-251,
-72,
-105,
-194,
-12,
-108,
-207,
-133,
-115,
-203,
-104,
-156,
-110,
-33,
-6,
-194,
-213,
-254,
-234,
-255,
-3,
-17,
-203,
-171,
-255,
-30,
-15,
-2,
-255,
-225,
-231,
-135,
-96,
-206,
-186,
-67,
-173,
-174,
-206,
-0,
-91,
-250,
-131,
-93,
-158,
-185,
-94,
-198,
-0,
-79,
-144,
-73,
-146,
-136,
-173,
-207,
-163,
-241,
-244,
-116,
-107,
-175,
-110,
-25,
-77,
-251,
-131,
-237,
-228,
-185,
-178,
-191,
-167,
-231,
-128,
-35,
-74,
-104,
-215,
-240,
-23,
-62,
-63,
-102,
-30,
-127,
-103,
-9,
-237,
-70,
-216,
-154,
-189,
-106,
-131,
-141,
-19,
-48,
-179,
-245,
-79,
-49,
-31,
-138,
-159,
-98,
-9,
-58,
-190,
-88,
-64,
-191,
-137,
-223,
-127,
-167,
-255,
-31,
-178,
-231,
-67,
-135,
-16,
-108,
-139,
-182,
-133,
-176,
-112,
-168,
-78,
-170,
-215,
-50,
-6,
-248,
-1,
-150,
-174,
-117,
-49,
-255,
-241,
-127,
-82,
-244,
-197,
-121,
-253,
-117,
-236,
-243,
-181,
-126,
-160,
-6,
-244,
-181,
-250,
-147,
-185,
-95,
-39,
-135,
-210,
-175,
-128,
-143,
-250,
-241,
-190,
-68,
-82,
-216,
-230,
-232,
-255,
-9,
-28,
-94,
-65,
-179,
-8,
-182,
-165,
-252,
-49,
-216,
-212,
-114,
-180,
-159,
-23,
-250,
-49,
-96,
-142,
-39,
-51,
-136,
-56,
-232,
-228,
-31,
-38,
-184,
-13,
-255,
-40,
-73,
-103,
-71,
-135,
-138,
-193,
-120,
-171,
-164,
-103,
-100,
-170,
-198,
-251,
-100,
-115,
-104,
-105,
-110,
-128,
-26,
-152,
-39,
-210,
-191,
-54,
-233,
-107,
-193,
-25,
-230,
-110,
-111,
-39,
-123,
-189,
-136,
-193,
-54,
-148,
-244,
-46,
-13,
-132,
-189,
-93,
-36,
-105,
-53,
-96,
-147,
-146,
-102,
-206,
-145,
-52,
-36,
-93,
-109,
-22,
-238,
-15,
-48,
-77,
-246,
-27,
-29,
-44,
-179,
-190,
-78,
-171,
-240,
-99,
-24,
-39,
-233,
-89,
-255,
-63,
-8,
-209,
-23,
-22,
-66,
-248,
-181,
-44,
-69,
-220,
-41,
-42,
-49,
-36,
-132,
-16,
-118,
-9,
-33,
-28,
-18,
-66,
-88,
-38,
-132,
-240,
-182,
-16,
-194,
-193,
-33,
-132,
-29,
-203,
-30,
-96,
-14,
-71,
-29,
-33,
-249,
-84,
-73,
-167,
-116,
-12,
-98,
-238,
-88,
-243,
-21,
-73,
-101,
-177,
-18,
-191,
-144,
-244,
-54,
-42,
-118,
-17,
-149,
-180,
-177,
-164,
-137,
-33,
-132,
-95,
-74,
-186,
-69,
-210,
-123,
-139,
-8,
-49,
-175,
-171,
-237,
-36,
-189,
-71,
-210,
-14,
-120,
-198,
-244,
-24,
-225,
-160,
-33,
-17,
-203,
-160,
-253,
-60,
-182,
-189,
-74,
-215,
-115,
-116,
-131,
-41,
-96,
-36,
-210,
-215,
-18,
-146,
-155,
-0,
-115,
-205,
-251,
-101,
-75,
-117,
-45,
-137,
-201,
-105,
-157,
-233,
-124,
-79,
-63,
-95,
-162,
-67,
-83,
-56,
-100,
-134,
-16,
-30,
-146,
-244,
-85,
-73,
-95,
-106,
-163,
-51,
-115,
-9,
-238,
-151,
-116,
-190,
-164,
-111,
-245,
-176,
-141,
-115,
-37,
-189,
-159,
-130,
-13,
-162,
-106,
-226,
-219,
-146,
-238,
-8,
-33,
-252,
-74,
-146,
-124,
-196,
-184,
-211,
-175,
-75,
-170,
-158,
-51,
-191,
-38,
-11,
-19,
-111,
-3,
-141,
-236,
-213,
-61,
-68,
-147,
-254,
-204,
-39,
-233,
-68,
-73,
-235,
-119,
-190,
-170,
-182,
-17,
-66,
-184,
-95,
-210,
-181,
-50,
-51,
-113,
-183,
-117,
-237,
-29,
-66,
-152,
-144,
-187,
-182,
-67,
-8,
-97,
-246,
-86,
-128,
-217,
-252,
-0,
-33,
-132,
-112,
-117,
-142,
-248,
-245,
-16,
-194,
-58,
-33,
-132,
-50,
-71,
-132,
-84,
-212,
-181,
-87,
-215,
-253,
-129,
-234,
-210,
-55,
-177,
-159,
-215,
-21,
-146,
-155,
-226,
-28,
-73,
-31,
-197,
-115,
-47,
-206,
-21,
-160,
-166,
-189,
-26,
-83,
-209,
-126,
-62,
-114,
-253,
-11,
-46,
-141,
-119,
-75,
-95,
-183,
-63,
-121,
-25,
-233,
-114,
-44,
-151,
-208,
-248,
-54,
-101,
-128,
-185,
-26,
-212,
-176,
-87,
-55,
-248,
-129,
-106,
-59,
-68,
-212,
-236,
-79,
-158,
-1,
-90,
-21,
-146,
-71,
-17,
-65,
-157,
-31,
-168,
-9,
-125,
-205,
-190,
-12,
-89,
-53,
-96,
-46,
-237,
-79,
-14,
-39,
-3,
-120,
-191,
-54,
-175,
-166,
-76,
-171,
-108,
-173,
-252,
-57,
-17,
-71,
-68,
-74,
-208,
-74,
-71,
-70,
-32,
-10,
-24,
-96,
-62,
-204,
-130,
-58,
-231,
-51,
-0,
-176,
-10,
-166,
-99,
-222,
-193,
-207,
-183,
-33,
-183,
-143,
-95,
-134,
-182,
-179,
-207,
-222,
-26,
-222,
-129,
-181,
-41,
-216,
-119,
-111,
-20,
-67,
-129,
-109,
-170,
-149,
-36,
-88,
-99,
-6,
-173,
-168,
-219,
-152,
-223,
-111,
-117,
-4,
-216,
-210,
-153,
-224,
-243,
-254,
-127,
-124,
-5,
-253,
-88,
-239,
-64,
-235,
-169,
-87,
-230,
-102,
-164,
-254,
-248,
-78,
-75,
-217,
-135,
-149,
-101,
-0,
-204,
-225,
-244,
-38,
-114,
-41,
-117,
-235,
-118,
-238,
-24,
-175,
-52,
-154,
-53,
-52,
-71,
-155,
-196,
-0,
-88,
-46,
-225,
-171,
-49,
-227,
-197,
-19,
-152,
-141,
-255,
-255,
-252,
-94,
-68,
-41,
-72,
-101,
-0,
-44,
-136,
-247,
-55,
-192,
-239,
-105,
-178,
-103,
-176,
-87,
-182,
-149,
-127,
-249,
-157,
-72,
-217,
-237,
-43,
-232,
-83,
-25,
-224,
-70,
-44,
-217,
-243,
-50,
-152,
-229,
-234,
-160,
-146,
-135,
-129,
-129,
-125,
-252,
-206,
-1,
-22,
-79,
-232,
-119,
-233,
-48,
-233,
-52,
-75,
-97,
-142,
-34,
-83,
-177,
-56,
-200,
-135,
-40,
-216,
-45,
-188,
-23,
-192,
-220,
-192,
-99,
-136,
-109,
-33,
-123,
-97,
-1,
-237,
-175,
-34,
-180,
-96,
-91,
-204,
-125,
-195,
-191,
-254,
-232,
-182,
-244,
-41,
-29,
-28,
-135,
-205,
-249,
-219,
-248,
-249,
-22,
-126,
-190,
-86,
-73,
-153,
-84,
-6,
-120,
-153,
-34,
-35,
-196,
-96,
-58,
-48,
-223,
-249,
-133,
-49,
-251,
-248,
-157,
-120,
-26,
-250,
-132,
-114,
-101,
-95,
-201,
-34,
-152,
-59,
-245,
-213,
-152,
-235,
-215,
-226,
-254,
-124,
-177,
-212,
-175,
-11,
-3,
-23,
-224,
-210,
-125,
-22,
-17,
-218,
-107,
-129,
-255,
-206,
-93,
-59,
-25,
-207,
-77,
-156,
-187,
-62,
-134,
-220,
-62,
-197,
-254,
-55,
-36,
-225,
-21,
-38,
-92,
-118,
-238,
-131,
-5,
-169,
-188,
-153,
-8,
-147,
-251,
-253,
-142,
-7,
-212,
-16,
-121,
-173,
-22,
-200,
-24,
-57,
-252,
-188,
-40,
-104,
-177,
-115,
-63,
-149,
-1,
-238,
-33,
-205,
-219,
-5,
-6,
-175,
-181,
-247,
-7,
-42,
-85,
-209,
-9,
-12,
-112,
-10,
-230,
-189,
-84,
-24,
-172,
-154,
-161,
-61,
-39,
-247,
-187,
-79,
-194,
-116,
-10,
-147,
-34,
-180,
-91,
-96,
-211,
-90,
-103,
-43,
-219,
-249,
-253,
-163,
-121,
-127,
-69,
-27,
-109,
-203,
-0,
-191,
-194,
-188,
-160,
-174,
-168,
-83,
-119,
-215,
-168,
-193,
-0,
-59,
-99,
-27,
-62,
-92,
-71,
-137,
-61,
-60,
-194,
-0,
-31,
-6,
-162,
-193,
-150,
-212,
-27,
-38,
-239,
-166,
-98,
-19,
-139,
-12,
-237,
-99,
-185,
-250,
-238,
-242,
-235,
-81,
-135,
-81,
-44,
-215,
-241,
-201,
-126,
-124,
-176,
-51,
-123,
-233,
-143,
-64,
-15,
-86,
-1,
-216,
-200,
-245,
-16,
-240,
-233,
-148,
-122,
-91,
-65,
-42,
-3,
-56,
-237,
-234,
-152,
-144,
-50,
-139,
-200,
-208,
-235,
-52,
-48,
-48,
-5,
-108,
-140,
-165,
-145,
-249,
-66,
-1,
-109,
-157,
-97,
-242,
-21,
-96,
-159,
-88,
-61,
-17,
-218,
-153,
-53,
-25,
-96,
-19,
-204,
-71,
-112,
-17,
-108,
-47,
-225,
-131,
-83,
-218,
-105,
-11,
-29,
-6,
-240,
-227,
-205,
-49,
-5,
-216,
-187,
-250,
-213,
-120,
-237,
-101,
-32,
-182,
-15,
-79,
-52,
-214,
-63,
-242,
-53,
-31,
-153,
-88,
-39,
-148,
-15,
-147,
-175,
-144,
-176,
-249,
-131,
-211,
-78,
-175,
-195,
-0,
-126,
-239,
-114,
-76,
-250,
-158,
-74,
-36,
-206,
-175,
-151,
-200,
-50,
-128,
-159,
-127,
-5,
-155,
-182,
-10,
-19,
-110,
-12,
-43,
-176,
-164,
-75,
-209,
-52,
-39,
-254,
-48,
-219,
-249,
-241,
-223,
-129,
-66,
-239,
-155,
-220,
-8,
-112,
-169,
-143,
-26,
-69,
-35,
-192,
-36,
-224,
-115,
-137,
-253,
-251,
-83,
-42,
-3,
-48,
-48,
-250,
-228,
-177,
-66,
-74,
-91,
-35,
-10,
-184,
-85,
-43,
-134,
-46,
-235,
-93,
-10,
-51,
-208,
-44,
-141,
-249,
-200,
-95,
-6,
-252,
-174,
-128,
-54,
-203,
-0,
-187,
-97,
-75,
-209,
-162,
-68,
-83,
-117,
-100,
-128,
-51,
-177,
-249,
-177,
-242,
-235,
-196,
-146,
-80,
-61,
-156,
-194,
-0,
-126,
-61,
-59,
-13,
-237,
-196,
-156,
-170,
-13,
-37,
-190,
-76,
-89,
-180,
-5,
-6,
-88,
-28,
-219,
-170,
-165,
-147,
-71,
-231,
-18,
-10,
-162,
-104,
-115,
-12,
-16,
-48,
-225,
-45,
-233,
-203,
-173,
-232,
-195,
-210,
-152,
-167,
-243,
-223,
-176,
-53,
-243,
-34,
-216,
-178,
-183,
-72,
-22,
-121,
-51,
-176,
-1,
-176,
-97,
-25,
-3,
-208,
-197,
-8,
-224,
-12,
-254,
-40,
-17,
-165,
-77,
-65,
-157,
-253,
-183,
-55,
-116,
-30,
-176,
-143,
-237,
-205,
-102,
-0,
-63,
-255,
-48,
-45,
-37,
-143,
-4,
-150,
-7,
-190,
-143,
-133,
-176,
-205,
-194,
-76,
-185,
-215,
-38,
-148,
-235,
-201,
-8,
-128,
-229,
-58,
-40,
-202,
-163,
-56,
-187,
-174,
-236,
-95,
-74,
-189,
-173,
-2,
-155,
-103,
-135,
-36,
-71,
-192,
-180,
-121,
-127,
-241,
-151,
-217,
-193,
-227,
-100,
-156,
-13,
-71,
-50,
-128,
-139,
-129,
-75,
-18,
-105,
-43,
-133,
-64,
-191,
-63,
-136,
-121,
-43,
-104,
-87,
-199,
-150,
-197,
-149,
-35,
-97,
-66,
-155,
-187,
-96,
-59,
-156,
-206,
-192,
-130,
-86,
-214,
-79,
-233,
-67,
-87,
-192,
-134,
-244,
-147,
-252,
-248,
-68,
-224,
-250,
-158,
-55,
-218,
-34,
-176,
-41,
-33,
-41,
-223,
-94,
-42,
-3,
-212,
-108,
-255,
-44,
-160,
-112,
-151,
-148,
-154,
-12,
-48,
-25,
-155,
-170,
-150,
-193,
-132,
-225,
-222,
-255,
-22,
-206,
-109,
-219,
-250,
-241,
-182,
-68,
-244,
-217,
-125,
-232,
-67,
-22,
-47,
-99,
-243,
-233,
-197,
-84,
-107,
-47,
-255,
-138,
-173,
-48,
-62,
-153,
-216,
-78,
-171,
-12,
-128,
-89,
-236,
-166,
-1,
-91,
-149,
-208,
-68,
-81,
-64,
-247,
-137,
-204,
-249,
-142,
-64,
-81,
-178,
-205,
-40,
-154,
-90,
-228,
-238,
-151,
-244,
-65,
-31,
-242,
-63,
-168,
-226,
-44,
-87,
-131,
-128,
-205,
-233,
-80,
-18,
-35,
-87,
-19,
-157,
-60,
-128,
-111,
-147,
-101,
-50,
-93,
-82,
-210,
-144,
-85,
-64,
-22,
-33,
-132,
-45,
-66,
-8,
-27,
-133,
-16,
-206,
-105,
-169,
-15,
-117,
-177,
-159,
-164,
-199,
-66,
-8,
-215,
-85,
-208,
-197,
-114,
-28,
-198,
-144,
-117,
-96,
-125,
-81,
-182,
-215,
-81,
-111,
-225,
-67,
-206,
-52,
-204,
-106,
-55,
-145,
-4,
-205,
-19,
-176,
-32,
-166,
-217,
-123,
-190,
-136,
-1,
-48,
-189,
-122,
-244,
-47,
-66,
-59,
-100,
-152,
-196,
-36,
-235,
-178,
-132,
-147,
-195,
-14,
-204,
-101,
-173,
-116,
-244,
-169,
-57,
-5,
-100,
-149,
-64,
-155,
-199,
-70,
-138,
-50,
-148,
-186,
-29,
-3,
-99,
-60,
-164,
-105,
-16,
-66,
-8,
-255,
-196,
-214,
-212,
-107,
-132,
-16,
-30,
-76,
-108,
-235,
-51,
-178,
-221,
-184,
-10,
-99,
-223,
-66,
-8,
-141,
-184,
-23,
-83,
-254,
-140,
-149,
-237,
-36,
-86,
-103,
-7,
-178,
-174,
-128,
-57,
-204,
-68,
-87,
-18,
-49,
-87,
-122,
-44,
-50,
-119,
-13,
-73,
-63,
-233,
-109,
-207,
-26,
-130,
-26,
-177,
-239,
-88,
-122,
-179,
-14,
-158,
-164,
-68,
-213,
-138,
-45,
-193,
-158,
-192,
-148,
-66,
-111,
-180,
-49,
-5,
-20,
-76,
-147,
-23,
-208,
-212,
-25,
-162,
-89,
-31,
-138,
-76,
-188,
-209,
-37,
-27,
-233,
-57,
-0,
-250,
-54,
-2,
-228,
-101,
-128,
-253,
-101,
-25,
-175,
-37,
-11,
-14,
-141,
-166,
-112,
-1,
-206,
-145,
-101,
-239,
-92,
-213,
-255,
-206,
-85,
-121,
-34,
-201,
-175,
-74,
-58,
-199,
-179,
-139,
-183,
-105,
-174,
-236,
-204,
-147,
-11,
-75,
-26,
-47,
-11,
-234,
-248,
-122,
-164,
-191,
-27,
-98,
-186,
-250,
-233,
-88,
-130,
-234,
-139,
-40,
-73,
-233,
-150,
-138,
-16,
-194,
-27,
-249,
-84,
-180,
-153,
-148,
-180,
-249,
-62,
-44,
-41,
-105,
-47,
-101,
-194,
-178,
-70,
-28,
-72,
-116,
-211,
-242,
-121,
-121,
-163,
-204,
-249,
-38,
-20,
-164,
-71,
-197,
-52,
-111,
-143,
-227,
-198,
-9,
-231,
-218,
-182,
-70,
-128,
-188,
-12,
-176,
-63,
-240,
-108,
-132,
-246,
-66,
-204,
-81,
-99,
-101,
-108,
-13,
-126,
-45,
-5,
-121,
-253,
-157,
-62,
-201,
-123,
-136,
-30,
-169,
-207,
-135,
-5,
-222,
-239,
-36,
-165,
-2,
-102,
-207,
-62,
-210,
-143,
-23,
-244,
-23,
-28,
-141,
-104,
-5,
-110,
-192,
-44,
-84,
-171,
-250,
-31,
-152,
-255,
-126,
-87,
-201,
-143,
-11,
-24,
-224,
-96,
-224,
-177,
-132,
-178,
-239,
-163,
-216,
-32,
-85,
-199,
-123,
-168,
-214,
-20,
-48,
-162,
-225,
-47,
-52,
-73,
-169,
-224,
-95,
-252,
-173,
-152,
-243,
-196,
-67,
-88,
-166,
-176,
-168,
-22,
-176,
-232,
-11,
-1,
-254,
-210,
-66,
-127,
-59,
-234,
-210,
-69,
-49,
-143,
-230,
-251,
-129,
-51,
-19,
-202,
-126,
-130,
-72,
-184,
-152,
-223,
-75,
-246,
-30,
-154,
-171,
-224,
-47,
-180,
-43,
-165,
-66,
-141,
-118,
-218,
-22,
-2,
-103,
-98,
-185,
-120,
-78,
-166,
-98,
-83,
-73,
-44,
-5,
-206,
-125,
-192,
-199,
-11,
-238,
-39,
-123,
-15,
-205,
-85,
-240,
-23,
-185,
-109,
-230,
-188,
-182,
-68,
-89,
-163,
-157,
-182,
-20,
-65,
-117,
-219,
-158,
-199,
-71,
-182,
-223,
-80,
-224,
-146,
-69,
-13,
-239,
-161,
-134,
-125,
-56,
-44,
-50,
-26,
-198,
-18,
-85,
-64,
-66,
-192,
-7,
-240,
-59,
-76,
-86,
-153,
-138,
-9,
-184,
-93,
-233,
-1,
-94,
-173,
-83,
-184,
-9,
-90,
-10,
-53,
-175,
-13,
-76,
-192,
-253,
-129,
-164,
-197,
-101,
-123,
-239,
-148,
-189,
-168,
-94,
-10,
-113,
-75,
-73,
-186,
-66,
-82,
-214,
-219,
-169,
-82,
-110,
-41,
-66,
-8,
-97,
-182,
-3,
-42,
-240,
-99,
-21,
-107,
-12,
-163,
-152,
-123,
-226,
-207,
-75,
-224,
-95,
-251,
-119,
-100,
-75,
-214,
-9,
-33,
-132,
-178,
-253,
-143,
-166,
-168,
-120,
-11,
-151,
-170,
-118,
-86,
-150,
-229,
-1,
-218,
-82,
-166,
-150,
-30,
-31,
-66,
-184,
-41,
-71,
-182,
-148,
-164,
-7,
-61,
-17,
-68,
-107,
-0,
-54,
-147,
-244,
-33,
-89,
-194,
-206,
-100,
-212,
-182,
-5,
-96,
-82,
-242,
-143,
-128,
-127,
-99,
-10,
-160,
-202,
-8,
-162,
-17,
-128,
-111,
-200,
-244,
-4,
-71,
-200,
-146,
-48,
-117,
-86,
-36,
-177,
-156,
-124,
-127,
-144,
-37,
-103,
-168,
-229,
-219,
-135,
-101,
-50,
-189,
-78,
-54,
-122,
-76,
-144,
-237,
-115,
-116,
-103,
-132,
-116,
-41,
-217,
-222,
-66,
-41,
-216,
-4,
-19,
-204,
-103,
-96,
-249,
-0,
-163,
-242,
-141,
-143,
-110,
-223,
-146,
-244,
-213,
-16,
-194,
-163,
-117,
-250,
-157,
-173,
-100,
-208,
-156,
-83,
-36,
-3,
-0,
-223,
-193,
-44,
-106,
-171,
-57,
-205,
-35,
-192,
-1,
-141,
-26,
-237,
-65,
-255,
-74,
-202,
-198,
-240,
-145,
-8,
-109,
-45,
-239,
-161,
-76,
-185,
-255,
-194,
-54,
-131,
-172,
-218,
-45,
-237,
-50,
-204,
-59,
-234,
-53,
-76,
-63,
-242,
-109,
-34,
-153,
-70,
-188,
-127,
-183,
-97,
-190,
-23,
-107,
-98,
-130,
-235,
-23,
-10,
-234,
-60,
-212,
-239,
-247,
-126,
-87,
-117,
-239,
-244,
-142,
-153,
-243,
-143,
-18,
-89,
-46,
-22,
-9,
-55,
-5,
-117,
-158,
-128,
-229,
-3,
-126,
-26,
-56,
-151,
-226,
-141,
-20,
-187,
-82,
-123,
-166,
-130,
-6,
-222,
-67,
-88,
-46,
-130,
-74,
-247,
-53,
-44,
-115,
-215,
-170,
-216,
-82,
-123,
-107,
-204,
-97,
-245,
-194,
-8,
-29,
-120,
-138,
-87,
-63,
-255,
-52,
-241,
-76,
-39,
-75,
-98,
-163,
-241,
-46,
-169,
-207,
-215,
-21,
-48,
-117,
-234,
-123,
-51,
-231,
-59,
-0,
-67,
-146,
-20,
-166,
-50,
-0,
-176,
-31,
-166,
-88,
-90,
-23,
-88,
-9,
-83,
-28,
-197,
-180,
-110,
-125,
-99,
-128,
-38,
-192,
-252,
-29,
-191,
-136,
-133,
-179,
-189,
-128,
-69,
-233,
-84,
-42,
-187,
-176,
-61,
-25,
-103,
-68,
-174,
-67,
-38,
-95,
-32,
-166,
-188,
-26,
-34,
-164,
-99,
-35,
-114,
-105,
-6,
-210,
-50,
-52,
-241,
-7,
-184,
-94,
-210,
-17,
-62,
-52,
-190,
-93,
-182,
-251,
-103,
-179,
-128,
-68,
-195,
-17,
-146,
-190,
-22,
-66,
-184,
-43,
-132,
-240,
-136,
-76,
-151,
-191,
-103,
-23,
-245,
-13,
-23,
-22,
-146,
-180,
-181,
-164,
-221,
-36,
-173,
-40,
-233,
-101,
-153,
-141,
-164,
-10,
-243,
-73,
-122,
-170,
-224,
-222,
-152,
-220,
-113,
-140,
-225,
-63,
-42,
-105,
-51,
-6,
-150,
-130,
-83,
-233,
-165,
-91,
-186,
-127,
-165,
-87,
-98,
-246,
-128,
-59,
-157,
-235,
-159,
-137,
-208,
-165,
-142,
-0,
-207,
-50,
-20,
-67,
-76,
-208,
-145,
-17,
-96,
-251,
-17,
-54,
-2,
-188,
-64,
-38,
-0,
-22,
-83,
-31,
-199,
-70,
-198,
-227,
-125,
-180,
-91,
-26,
-139,
-198,
-190,
-15,
-56,
-37,
-66,
-7,
-158,
-103,
-216,
-207,
-143,
-161,
-7,
-251,
-25,
-204,
-230,
-48,
-76,
-175,
-125,
-134,
-255,
-32,
-79,
-99,
-33,
-221,
-135,
-228,
-11,
-132,
-16,
-30,
-9,
-33,
-236,
-24,
-66,
-88,
-40,
-132,
-176,
-158,
-164,
-87,
-148,
-186,
-45,
-89,
-113,
-31,
-246,
-209,
-96,
-207,
-151,
-216,
-136,
-242,
-146,
-6,
-123,
-187,
-172,
-17,
-171,
-44,
-195,
-68,
-179,
-48,
-19,
-244,
-55,
-72,
-8,
-49,
-111,
-1,
-119,
-201,
-190,
-252,
-14,
-22,
-146,
-121,
-232,
-228,
-241,
-30,
-217,
-40,
-58,
-85,
-210,
-121,
-146,
-126,
-36,
-41,
-154,
-233,
-91,
-210,
-145,
-152,
-0,
-184,
-150,
-164,
-195,
-212,
-75,
-63,
-2,
-224,
-63,
-157,
-27,
-215,
-198,
-50,
-91,
-19,
-99,
-128,
-72,
-185,
-137,
-192,
-137,
-145,
-235,
-169,
-35,
-192,
-45,
-120,
-112,
-101,
-5,
-221,
-13,
-152,
-6,
-111,
-25,
-76,
-58,
-159,
-28,
-27,
-1,
-188,
-221,
-78,
-124,
-225,
-38,
-152,
-106,
-247,
-231,
-17,
-186,
-113,
-88,
-166,
-243,
-206,
-30,
-192,
-151,
-18,
-217,
-159,
-55,
-50,
-58,
-81,
-208,
-238,
-129,
-152,
-13,
-97,
-75,
-108,
-133,
-116,
-3,
-240,
-157,
-170,
-231,
-42,
-121,
-94,
-128,
-207,
-96,
-246,
-141,
-151,
-177,
-125,
-7,
-122,
-23,
-118,
-134,
-5,
-54,
-30,
-229,
-199,
-215,
-96,
-214,
-176,
-91,
-34,
-116,
-243,
-99,
-238,
-226,
-75,
-98,
-142,
-35,
-83,
-137,
-108,
-221,
-86,
-131,
-1,
-246,
-194,
-156,
-80,
-62,
-4,
-172,
-136,
-229,
-5,
-216,
-45,
-66,
-247,
-78,
-103,
-182,
-87,
-48,
-139,
-229,
-174,
-37,
-12,
-144,
-141,
-45,
-56,
-0,
-152,
-22,
-161,
-187,
-25,
-11,
-169,
-30,
-135,
-229,
-71,
-250,
-5,
-112,
-107,
-132,
-110,
-213,
-220,
-223,
-215,
-40,
-112,
-148,
-193,
-150,
-130,
-79,
-97,
-82,
-249,
-15,
-169,
-200,
-253,
-95,
-6,
-127,
-142,
-118,
-114,
-255,
-36,
-54,
-56,
-29,
-147,
-52,
-183,
-193,
-252,
-214,
-118,
-45,
-120,
-113,
-27,
-97,
-107,
-216,
-255,
-197,
-162,
-124,
-242,
-251,
-237,
-118,
-232,
-146,
-24,
-192,
-105,
-63,
-130,
-133,
-99,
-205,
-116,
-134,
-250,
-84,
-23,
-207,
-145,
-103,
-128,
-168,
-137,
-24,
-155,
-179,
-179,
-50,
-197,
-150,
-84,
-24,
-191,
-48,
-91,
-194,
-20,
-122,
-104,
-43,
-200,
-180,
-149,
-204,
-0,
-152,
-60,
-52,
-209,
-71,
-138,
-169,
-36,
-140,
-168,
-177,
-74,
-166,
-97,
-67,
-231,
-141,
-152,
-37,
-240,
-3,
-68,
-156,
-43,
-106,
-212,
-7,
-67,
-163,
-91,
-74,
-211,
-184,
-180,
-129,
-76,
-187,
-139,
-49,
-32,
-100,
-157,
-29,
-161,
-251,
-33,
-240,
-107,
-204,
-58,
-184,
-16,
-230,
-49,
-84,
-234,
-41,
-12,
-236,
-141,
-41,
-137,
-122,
-174,
-66,
-175,
-201,
-0,
-79,
-98,
-250,
-152,
-69,
-177,
-216,
-198,
-241,
-77,
-26,
-252,
-7,
-22,
-230,
-220,
-217,
-135,
-230,
-104,
-224,
-239,
-181,
-43,
-26,
-168,
-47,
-134,
-82,
-151,
-237,
-54,
-144,
-105,
-107,
-38,
-230,
-171,
-112,
-10,
-241,
-173,
-89,
-231,
-199,
-194,
-179,
-158,
-197,
-134,
-236,
-243,
-168,
-222,
-0,
-234,
-22,
-224,
-179,
-45,
-244,
-177,
-213,
-157,
-202,
-188,
-190,
-243,
-233,
-38,
-132,
-14,
-248,
-148,
-191,
-184,
-253,
-49,
-65,
-240,
-1,
-224,
-208,
-110,
-59,
-215,
-111,
-248,
-51,
-164,
-200,
-30,
-187,
-251,
-151,
-179,
-157,
-63,
-251,
-179,
-148,
-7,
-107,
-116,
-146,
-47,
-44,
-217,
-66,
-31,
-239,
-200,
-48,
-192,
-237,
-45,
-212,
-55,
-30,
-115,
-209,
-159,
-142,
-109,
-47,
-91,
-223,
-153,
-5,
-203,
-171,
-251,
-15,
-127,
-17,
-211,
-128,
-47,
-85,
-125,
-17,
-253,
-4,
-22,
-45,
-124,
-154,
-247,
-237,
-25,
-34,
-137,
-161,
-157,
-46,
-149,
-1,
-38,
-147,
-209,
-239,
-99,
-94,
-66,
-49,
-227,
-77,
-231,
-254,
-111,
-40,
-217,
-129,
-12,
-203,
-104,
-50,
-209,
-153,
-228,
-206,
-70,
-195,
-112,
-67,
-120,
-123,
-7,
-249,
-135,
-123,
-11,
-240,
-219,
-126,
-53,
-12,
-53,
-247,
-186,
-43,
-168,
-99,
-8,
-34,
-116,
-7,
-99,
-235,
-250,
-119,
-97,
-110,
-107,
-79,
-1,
-187,
-23,
-212,
-151,
-194,
-0,
-47,
-98,
-38,
-212,
-206,
-249,
-86,
-68,
-20,
-55,
-126,
-111,
-21,
-159,
-82,
-10,
-179,
-112,
-249,
-87,
-253,
-77,
-204,
-135,
-240,
-43,
-64,
-212,
-220,
-235,
-253,
-107,
-85,
-165,
-141,
-9,
-180,
-59,
-249,
-241,
-102,
-244,
-58,
-56,
-6,
-56,
-28,
-19,
-174,
-240,
-161,
-39,
-105,
-79,
-191,
-130,
-186,
-242,
-14,
-149,
-151,
-17,
-9,
-156,
-196,
-150,
-166,
-95,
-204,
-156,
-159,
-76,
-68,
-7,
-94,
-131,
-1,
-174,
-196,
-214,
-254,
-227,
-176,
-117,
-251,
-31,
-129,
-95,
-23,
-208,
-126,
-11,
-184,
-170,
-162,
-190,
-89,
-157,
-175,
-30,
-19,
-66,
-135,
-232,
-247,
-51,
-253,
-171,
-197,
-0,
-20,
-120,
-92,
-103,
-238,
-159,
-238,
-31,
-196,
-193,
-192,
-73,
-192,
-53,
-101,
-244,
-93,
-193,
-27,
-121,
-209,
-135,
-156,
-21,
-176,
-124,
-193,
-155,
-69,
-232,
-222,
-135,
-101,
-5,
-123,
-17,
-27,
-182,
-47,
-7,
-86,
-175,
-168,
-123,
-107,
-108,
-41,
-51,
-54,
-114,
-111,
-42,
-153,
-204,
-223,
-152,
-222,
-160,
-177,
-39,
-141,
-247,
-253,
-82,
-6,
-166,
-148,
-11,
-137,
-236,
-78,
-234,
-95,
-244,
-139,
-84,
-88,
-219,
-178,
-63,
-44,
-230,
-36,
-251,
-199,
-42,
-58,
-63,
-239,
-154,
-1,
-156,
-102,
-87,
-76,
-249,
-4,
-137,
-249,
-144,
-26,
-1,
-83,
-194,
-156,
-154,
-64,
-247,
-117,
-224,
-8,
-76,
-149,
-185,
-10,
-54,
-135,
-22,
-174,
-42,
-48,
-85,
-244,
-109,
-192,
-87,
-10,
-238,
-191,
-204,
-96,
-159,
-197,
-109,
-129,
-215,
-154,
-61,
-69,
-79,
-60,
-184,
-94,
-0,
-0,
-18,
-40,
-73,
-68,
-65,
-84,
-251,
-200,
-49,
-192,
-115,
-192,
-7,
-170,
-232,
-252,
-188,
-200,
-239,
-98,
-69,
-76,
-178,
-159,
-226,
-101,
-30,
-163,
-64,
-238,
-201,
-149,
-251,
-36,
-53,
-118,
-111,
-205,
-218,
-2,
-82,
-57,
-115,
-13,
-73,
-149,
-203,
-195,
-16,
-194,
-81,
-33,
-132,
-111,
-134,
-16,
-38,
-133,
-16,
-30,
-144,
-237,
-23,
-92,
-54,
-2,
-252,
-135,
-108,
-31,
-194,
-175,
-22,
-220,
-207,
-247,
-101,
-94,
-73,
-175,
-87,
-245,
-99,
-152,
-48,
-70,
-233,
-190,
-121,
-69,
-116,
-157,
-60,
-74,
-239,
-147,
-244,
-188,
-164,
-93,
-36,
-253,
-45,
-79,
-132,
-173,
-253,
-247,
-195,
-54,
-201,
-88,
-92,
-182,
-181,
-221,
-16,
-5,
-94,
-17,
-154,
-40,
-52,
-130,
-226,
-102,
-201,
-40,
-48,
-231,
-142,
-119,
-201,
-12,
-30,
-81,
-243,
-40,
-230,
-17,
-115,
-138,
-164,
-207,
-135,
-16,
-138,
-180,
-113,
-79,
-203,
-28,
-58,
-59,
-88,
-212,
-175,
-141,
-68,
-156,
-45,
-233,
-187,
-192,
-191,
-66,
-8,
-249,
-101,
-94,
-146,
-81,
-75,
-182,
-41,
-247,
-255,
-132,
-16,
-238,
-4,
-8,
-33,
-220,
-86,
-210,
-222,
-161,
-50,
-195,
-82,
-144,
-52,
-81,
-210,
-190,
-181,
-123,
-92,
-99,
-104,
-186,
-139,
-136,
-249,
-178,
-164,
-78,
-48,
-1,
-233,
-28,
-10,
-220,
-165,
-176,
-181,
-235,
-109,
-148,
-44,
-59,
-49,
-161,
-237,
-212,
-204,
-249,
-233,
-84,
-11,
-102,
-125,
-219,
-166,
-62,
-55,
-5,
-4,
-151,
-47,
-254,
-26,
-161,
-75,
-53,
-106,
-77,
-192,
-220,
-237,
-30,
-197,
-150,
-150,
-221,
-229,
-1,
-174,
-243,
-0,
-126,
-94,
-196,
-0,
-31,
-193,
-92,
-164,
-14,
-192,
-92,
-167,
-86,
-195,
-118,
-167,
-140,
-213,
-185,
-152,
-207,
-101,
-31,
-196,
-116,
-253,
-223,
-143,
-208,
-140,
-245,
-249,
-189,
-116,
-183,
-76,
-204,
-104,
-244,
-12,
-166,
-60,
-121,
-47,
-166,
-175,
-56,
-168,
-162,
-204,
-21,
-88,
-58,
-150,
-40,
-99,
-81,
-99,
-107,
-122,
-42,
-182,
-164,
-143,
-188,
-191,
-9,
-192,
-16,
-239,
-99,
-18,
-141,
-90,
-78,
-59,
-47,
-102,
-163,
-152,
-137,
-41,
-121,
-26,
-219,
-72,
-42,
-17,
-121,
-128,
-66,
-135,
-11,
-44,
-140,
-60,
-187,
-12,
-188,
-60,
-70,
-151,
-43,
-179,
-47,
-145,
-120,
-60,
-44,
-173,
-203,
-101,
-164,
-133,
-87,
-127,
-145,
-1,
-69,
-213,
-233,
-116,
-153,
-24,
-153,
-196,
-173,
-233,
-73,
-216,
-146,
-62,
-55,
-2,
-108,
-134,
-105,
-23,
-155,
-121,
-232,
-14,
-173,
-251,
-57,
-10,
-140,
-115,
-173,
-193,
-31,
-32,
-235,
-236,
-121,
-120,
-17,
-3,
-228,
-202,
-36,
-41,
-130,
-176,
-244,
-48,
-49,
-171,
-92,
-20,
-245,
-159,
-96,
-80,
-157,
-149,
-78,
-166,
-109,
-35,
-199,
-0,
-19,
-177,
-81,
-114,
-136,
-215,
-113,
-141,
-250,
-254,
-11,
-27,
-233,
-222,
-234,
-117,
-157,
-69,
-36,
-99,
-121,
-107,
-240,
-7,
-200,
-206,
-77,
-15,
-116,
-243,
-67,
-248,
-215,
-250,
-78,
-44,
-213,
-250,
-54,
-36,
-6,
-110,
-118,
-11,
-18,
-157,
-76,
-157,
-54,
-197,
-27,
-121,
-127,
-76,
-203,
-247,
-146,
-255,
-47,
-220,
-168,
-185,
-77,
-96,
-166,
-246,
-71,
-49,
-211,
-251,
-27,
-254,
-28,
-27,
-20,
-208,
-110,
-129,
-5,
-235,
-118,
-204,
-193,
-73,
-50,
-90,
-190,
-18,
-48,
-109,
-219,
-11,
-192,
-189,
-152,
-121,
-177,
-27,
-6,
-184,
-16,
-211,
-78,
-189,
-234,
-204,
-244,
-101,
-250,
-16,
-54,
-141,
-237,
-154,
-113,
-72,
-230,
-124,
-15,
-224,
-225,
-8,
-93,
-170,
-55,
-242,
-54,
-152,
-60,
-180,
-4,
-182,
-81,
-228,
-255,
-244,
-250,
-25,
-34,
-125,
-168,
-210,
-4,
-62,
-132,
-237,
-243,
-180,
-24,
-150,
-225,
-116,
-124,
-147,
-70,
-160,
-124,
-111,
-251,
-57,
-2,
-164,
-59,
-153,
-38,
-49,
-74,
-174,
-204,
-22,
-68,
-92,
-179,
-107,
-246,
-47,
-41,
-9,
-86,
-174,
-76,
-21,
-3,
-60,
-5,
-28,
-219,
-77,
-191,
-134,
-8,
-129,
-35,
-21,
-84,
-44,
-237,
-48,
-129,
-105,
-111,
-42,
-132,
-202,
-26,
-140,
-50,
-214,
-135,
-227,
-39,
-241,
-189,
-4,
-122,
-241,
-92,
-221,
-0,
-19,
-176,
-103,
-0,
-127,
-198,
-183,
-252,
-105,
-82,
-73,
-45,
-6,
-160,
-98,
-89,
-84,
-179,
-221,
-221,
-72,
-136,
-129,
-115,
-250,
-170,
-165,
-93,
-170,
-147,
-105,
-42,
-163,
-252,
-5,
-243,
-143,
-92,
-15,
-91,
-218,
-165,
-134,
-163,
-245,
-53,
-112,
-5,
-147,
-181,
-78,
-195,
-150,
-151,
-69,
-94,
-198,
-173,
-53,
-86,
-185,
-44,
-170,
-81,
-23,
-152,
-67,
-106,
-101,
-12,
-92,
-98,
-125,
-169,
-78,
-166,
-169,
-140,
-50,
-3,
-247,
-247,
-119,
-134,
-25,
-145,
-12,
-144,
-105,
-247,
-195,
-20,
-152,
-181,
-251,
-221,
-145,
-249,
-177,
-180,
-104,
-51,
-48,
-97,
-235,
-253,
-177,
-23,
-226,
-12,
-144,
-18,
-3,
-55,
-104,
-132,
-42,
-123,
-193,
-36,
-56,
-153,
-214,
-96,
-148,
-251,
-49,
-211,
-243,
-242,
-62,
-26,
-140,
-40,
-6,
-192,
-4,
-191,
-15,
-99,
-182,
-128,
-37,
-48,
-79,
-237,
-59,
-122,
-217,
-96,
-210,
-15,
-129,
-217,
-165,
-31,
-194,
-188,
-84,
-214,
-197,
-252,
-214,
-138,
-24,
-32,
-37,
-6,
-46,
-153,
-1,
-106,
-60,
-75,
-10,
-163,
-124,
-8,
-243,
-25,
-124,
-12,
-83,
-198,
-12,
-73,
-1,
-231,
-116,
-89,
-134,
-159,
-236,
-140,
-92,
-217,
-63,
-204,
-185,
-101,
-136,
-74,
-155,
-193,
-129,
-58,
-207,
-98,
-190,
-141,
-177,
-228,
-147,
-139,
-98,
-102,
-247,
-23,
-48,
-129,
-242,
-58,
-224,
-29,
-169,
-239,
-160,
-54,
-106,
-48,
-192,
-36,
-50,
-91,
-190,
-224,
-169,
-81,
-10,
-234,
-203,
-154,
-121,
-63,
-16,
-123,
-201,
-189,
-96,
-128,
-54,
-17,
-97,
-248,
-127,
-149,
-245,
-15,
-155,
-62,
-47,
-246,
-15,
-99,
-136,
-241,
-134,
-193,
-129,
-58,
-107,
-251,
-113,
-235,
-62,
-154,
-85,
-94,
-176,
-221,
-248,
-4,
-142,
-211,
-224,
-144,
-177,
-178,
-140,
-24,
-43,
-103,
-142,
-87,
-171,
-160,
-29,
-169,
-216,
-87,
-150,
-12,
-243,
-158,
-16,
-194,
-93,
-146,
-138,
-108,
-6,
-203,
-97,
-17,
-67,
-151,
-72,
-250,
-173,
-164,
-117,
-67,
-8,
-67,
-34,
-151,
-36,
-29,
-144,
-169,
-239,
-30,
-89,
-130,
-201,
-131,
-218,
-238,
-244,
-160,
-31,
-152,
-92,
-170,
-88,
-73,
-55,
-118,
-81,
-247,
-171,
-210,
-32,
-179,
-241,
-204,
-18,
-218,
-38,
-49,
-112,
-35,
-45,
-141,
-91,
-42,
-195,
-79,
-150,
-180,
-130,
-164,
-119,
-135,
-16,
-126,
-26,
-203,
-197,
-236,
-88,
-89,
-210,
-3,
-185,
-250,
-74,
-61,
-170,
-154,
-160,
-81,
-170,
-216,
-28,
-138,
-126,
-136,
-71,
-52,
-248,
-203,
-46,
-203,
-187,
-115,
-129,
-164,
-203,
-100,
-182,
-236,
-107,
-20,
-73,
-247,
-170,
-116,
-59,
-122,
-45,
-43,
-95,
-139,
-72,
-101,
-248,
-141,
-100,
-161,
-227,
-119,
-96,
-22,
-213,
-162,
-140,
-34,
-111,
-104,
-112,
-90,
-221,
-222,
-123,
-104,
-167,
-12,
-249,
-46,
-104,
-84,
-26,
-141,
-128,
-207,
-97,
-42,
-229,
-53,
-49,
-147,
-241,
-173,
-37,
-50,
-64,
-74,
-58,
-180,
-36,
-59,
-186,
-211,
-86,
-90,
-249,
-48,
-255,
-132,
-231,
-177,
-37,
-232,
-62,
-152,
-4,
-253,
-229,
-46,
-250,
-119,
-87,
-86,
-136,
-164,
-66,
-149,
-142,
-121,
-55,
-95,
-238,
-178,
-210,
-144,
-20,
-59,
-216,
-166,
-22,
-71,
-103,
-206,
-163,
-129,
-58,
-88,
-112,
-75,
-212,
-70,
-80,
-11,
-36,
-26,
-61,
-82,
-127,
-8,
-76,
-177,
-242,
-83,
-204,
-64,
-113,
-63,
-190,
-45,
-125,
-132,
-46,
-245,
-5,
-39,
-219,
-209,
-83,
-0,
-156,
-138,
-5,
-184,
-238,
-131,
-249,
-213,
-191,
-72,
-36,
-147,
-119,
-141,
-254,
-229,
-25,
-126,
-98,
-74,
-255,
-128,
-77,
-137,
-120,
-241,
-2,
-135,
-248,
-123,
-235,
-8,
-129,
-209,
-64,
-29,
-76,
-11,
-120,
-15,
-150,
-0,
-59,
-26,
-167,
-153,
-4,
-18,
-141,
-30,
-77,
-127,
-8,
-138,
-87,
-11,
-73,
-47,
-56,
-21,
-249,
-250,
-138,
-218,
-109,
-90,
-95,
-9,
-93,
-158,
-225,
-119,
-239,
-178,
-221,
-128,
-237,
-199,
-52,
-141,
-138,
-64,
-29,
-108,
-201,
-184,
-191,
-51,
-242,
-119,
-128,
-101,
-155,
-182,
-219,
-169,
-176,
-107,
-163,
-71,
-164,
-206,
-126,
-41,
-70,
-122,
-193,
-0,
-71,
-210,
-239,
-157,
-185,
-26,
-0,
-120,
-19,
-150,
-243,
-32,
-57,
-197,
-111,
-214,
-43,
-120,
-182,
-209,
-67,
-182,
-11,
-70,
-95,
-247,
-192,
-29,
-225,
-56,
-92,
-210,
-33,
-178,
-93,
-73,
-158,
-144,
-229,
-228,
-27,
-49,
-192,
-100,
-158,
-3,
-36,
-221,
-46,
-233,
-53,
-153,
-160,
-89,
-187,
-146,
-70,
-70,
-143,
-145,
-134,
-30,
-141,
-0,
-61,
-79,
-162,
-221,
-20,
-216,
-74,
-98,
-18,
-230,
-86,
-215,
-60,
-7,
-51,
-13,
-141,
-30,
-253,
-6,
-245,
-157,
-51,
-187,
-74,
-38,
-229,
-245,
-245,
-60,
-137,
-118,
-83,
-96,
-78,
-60,
-155,
-54,
-45,
-159,
-21,
-42,
-30,
-151,
-180,
-49,
-150,
-219,
-174,
-112,
-99,
-167,
-130,
-78,
-52,
-94,
-163,
-250,
-11,
-78,
-205,
-36,
-242,
-93,
-89,
-14,
-222,
-53,
-36,
-45,
-77,
-220,
-10,
-217,
-11,
-125,
-65,
-146,
-60,
-132,
-37,
-153,
-56,
-20,
-216,
-147,
-72,
-242,
-199,
-58,
-72,
-21,
-62,
-67,
-8,
-219,
-68,
-242,
-17,
-55,
-106,
-48,
-201,
-232,
-225,
-180,
-201,
-155,
-75,
-37,
-180,
-155,
-204,
-0,
-137,
-245,
-181,
-173,
-47,
-72,
-158,
-82,
-176,
-112,
-181,
-89,
-152,
-175,
-193,
-184,
-46,
-159,
-35,
-137,
-1,
-134,
-5,
-46,
-9,
-175,
-236,
-12,
-240,
-28,
-112,
-68,
-1,
-221,
-170,
-192,
-245,
-152,
-110,
-225,
-62,
-96,
-255,
-8,
-77,
-7,
-165,
-105,
-221,
-72,
-183,
-142,
-181,
-173,
-47,
-168,
-195,
-0,
-151,
-96,
-145,
-193,
-151,
-23,
-140,
-78,
-117,
-219,
-237,
-139,
-3,
-106,
-109,
-164,
-14,
-249,
-152,
-139,
-210,
-165,
-88,
-36,
-238,
-22,
-192,
-187,
-35,
-52,
-144,
-150,
-214,
-173,
-85,
-235,
-88,
-13,
-134,
-74,
-102,
-128,
-12,
-205,
-130,
-152,
-71,
-111,
-227,
-47,
-216,
-219,
-61,
-154,
-68,
-79,
-169,
-190,
-33,
-245,
-197,
-57,
-237,
-12,
-96,
-231,
-138,
-250,
-96,
-112,
-86,
-175,
-253,
-137,
-103,
-39,
-155,
-157,
-198,
-206,
-207,
-63,
-77,
-119,
-83,
-79,
-219,
-12,
-181,
-16,
-230,
-15,
-240,
-44,
-166,
-8,
-186,
-22,
-248,
-65,
-23,
-245,
-65,
-13,
-79,
-41,
-170,
-125,
-37,
-219,
-201,
-75,
-84,
-231,
-197,
-249,
-67,
-140,
-175,
-168,
-47,
-207,
-0,
-69,
-105,
-221,
-166,
-147,
-9,
-65,
-195,
-28,
-71,
-186,
-201,
-98,
-214,
-54,
-67,
-157,
-137,
-169,
-208,
-215,
-240,
-247,
-114,
-15,
-5,
-89,
-66,
-18,
-235,
-131,
-4,
-79,
-169,
-204,
-253,
-42,
-95,
-201,
-234,
-188,
-68,
-41,
-92,
-82,
-231,
-197,
-213,
-96,
-128,
-148,
-180,
-110,
-211,
-128,
-236,
-246,
-40,
-221,
-166,
-177,
-107,
-155,
-161,
-166,
-228,
-126,
-176,
-131,
-40,
-200,
-18,
-146,
-88,
-31,
-12,
-94,
-126,
-70,
-61,
-165,
-186,
-69,
-158,
-91,
-178,
-38,
-204,
-89,
-5,
-101,
-146,
-236,
-212,
-12,
-172,
-34,
-254,
-140,
-185,
-92,
-149,
-249,
-3,
-252,
-65,
-210,
-51,
-178,
-188,
-185,
-23,
-73,
-138,
-249,
-184,
-223,
-39,
-219,
-242,
-165,
-131,
-85,
-84,
-226,
-56,
-82,
-53,
-36,
-170,
-125,
-115,
-235,
-91,
-101,
-90,
-194,
-14,
-158,
-145,
-45,
-73,
-219,
-66,
-52,
-91,
-56,
-9,
-70,
-188,
-50,
-154,
-65,
-15,
-29,
-66,
-88,
-63,
-132,
-112,
-91,
-8,
-97,
-98,
-8,
-161,
-200,
-175,
-44,
-233,
-197,
-133,
-16,
-58,
-46,
-214,
-219,
-134,
-16,
-230,
-13,
-33,
-148,
-229,
-34,
-216,
-222,
-105,
-198,
-133,
-16,
-78,
-8,
-33,
-196,
-50,
-127,
-156,
-39,
-233,
-176,
-206,
-212,
-35,
-233,
-147,
-178,
-77,
-160,
-138,
-112,
-129,
-164,
-159,
-73,
-42,
-218,
-233,
-35,
-153,
-161,
-18,
-231,
-207,
-71,
-37,
-45,
-151,
-57,
-31,
-39,
-115,
-254,
-232,
-6,
-41,
-158,
-82,
-79,
-200,
-156,
-104,
-86,
-148,
-169,
-240,
-99,
-106,
-234,
-20,
-26,
-137,
-180,
-88,
-185,
-84,
-59,
-245,
-252,
-62,
-140,
-149,
-234,
-165,
-243,
-50,
-64,
-9,
-93,
-178,
-117,
-44,
-5,
-36,
-154,
-91,
-157,
-182,
-114,
-254,
-4,
-190,
-128,
-173,
-96,
-58,
-66,
-219,
-100,
-42,
-194,
-215,
-43,
-250,
-135,
-183,
-187,
-38,
-176,
-22,
-240,
-32,
-240,
-153,
-138,
-50,
-149,
-70,
-188,
-66,
-26,
-210,
-99,
-229,
-82,
-237,
-212,
-251,
-49,
-32,
-20,
-205,
-78,
-182,
-156,
-240,
-236,
-93,
-129,
-244,
-229,
-93,
-219,
-12,
-53,
-63,
-38,
-8,
-62,
-225,
-245,
-157,
-22,
-107,
-183,
-70,
-125,
-175,
-99,
-91,
-249,
-150,
-102,
-11,
-39,
-33,
-114,
-41,
-133,
-70,
-164,
-7,
-85,
-38,
-189,
-56,
-10,
-208,
-232,
-109,
-212,
-0,
-195,
-164,
-47,
-24,
-46,
-144,
-96,
-196,
-75,
-161,
-17,
-137,
-177,
-114,
-35,
-29,
-140,
-112,
-125,
-65,
-219,
-32,
-193,
-136,
-87,
-70,
-147,
-223,
-147,
-38,
-101,
-231,
-142,
-145,
-142,
-182,
-189,
-105,
-251,
-226,
-158,
-221,
-5,
-82,
-140,
-120,
-213,
-52,
-36,
-198,
-202,
-245,
-27,
-62,
-4,
-127,
-25,
-91,
-103,
-191,
-72,
-197,
-14,
-89,
-140,
-112,
-125,
-65,
-219,
-32,
-193,
-136,
-151,
-66,
-35,
-18,
-99,
-229,
-250,
-13,
-224,
-40,
-108,
-101,
-50,
-1,
-75,
-56,
-89,
-149,
-76,
-42,
-105,
-149,
-82,
-163,
-253,
-70,
-12,
-69,
-130,
-169,
-25,
-115,
-72,
-189,
-39,
-161,
-174,
-9,
-254,
-129,
-150,
-230,
-17,
-232,
-26,
-212,
-216,
-185,
-131,
-132,
-240,
-112,
-224,
-91,
-153,
-227,
-111,
-84,
-220,
-31,
-162,
-253,
-243,
-235,
-183,
-147,
-176,
-33,
-99,
-134,
-62,
-121,
-121,
-151,
-88,
-95,
-35,
-134,
-34,
-205,
-212,
-188,
-31,
-80,
-169,
-43,
-192,
-18,
-64,
-156,
-76,
-127,
-54,
-191,
-170,
-6,
-105,
-89,
-179,
-182,
-0,
-206,
-247,
-227,
-205,
-128,
-239,
-69,
-104,
-190,
-207,
-64,
-98,
-165,
-243,
-137,
-120,
-182,
-96,
-75,
-160,
-104,
-218,
-213,
-130,
-190,
-13,
-155,
-190,
-160,
-87,
-240,
-15,
-109,
-124,
-63,
-219,
-236,
-26,
-152,
-143,
-218,
-134,
-249,
-227,
-28,
-205,
-134,
-157,
-57,
-221,
-143,
-127,
-31,
-161,
-121,
-53,
-59,
-4,
-247,
-27,
-77,
-24,
-138,
-244,
-24,
-139,
-13,
-128,
-202,
-116,
-183,
-206,
-0,
-133,
-155,
-89,
-116,
-131,
-70,
-95,
-6,
-105,
-105,
-216,
-230,
-41,
-56,
-46,
-163,
-139,
-169,
-139,
-31,
-80,
-205,
-45,
-209,
-219,
-68,
-8,
-129,
-16,
-194,
-151,
-66,
-8,
-139,
-251,
-223,
-137,
-37,
-241,
-124,
-29,
-164,
-169,
-94,
-165,
-93,
-53,
-120,
-197,
-50,
-8,
-152,
-95,
-193,
-129,
-50,
-27,
-77,
-105,
-254,
-162,
-146,
-58,
-90,
-221,
-158,
-166,
-142,
-198,
-112,
-171,
-204,
-20,
-48,
-123,
-58,
-200,
-209,
-124,
-31,
-216,
-210,
-143,
-207,
-39,
-226,
-64,
-129,
-69,
-20,
-61,
-142,
-185,
-91,
-173,
-74,
-65,
-86,
-210,
-145,
-10,
-10,
-84,
-175,
-192,
-58,
-152,
-215,
-210,
-129,
-37,
-101,
-193,
-164,
-247,
-198,
-35,
-32,
-169,
-219,
-211,
-144,
-184,
-220,
-162,
-70,
-118,
-45,
-50,
-187,
-112,
-17,
-17,
-22,
-169,
-16,
-18,
-253,
-250,
-60,
-152,
-38,
-110,
-42,
-166,
-208,
-24,
-178,
-153,
-196,
-72,
-3,
-105,
-234,
-217,
-75,
-171,
-158,
-5,
-179,
-104,
-30,
-139,
-41,
-233,
-150,
-232,
-93,
-143,
-149,
-190,
-220,
-98,
-4,
-106,
-12,
-201,
-8,
-138,
-20,
-8,
-141,
-62,
-143,
-79,
-194,
-86,
-57,
-189,
-203,
-185,
-171,
-100,
-245,
-236,
-244,
-148,
-121,
-29,
-203,
-23,
-12,
-176,
-69,
-131,
-126,
-108,
-130,
-173,
-253,
-241,
-81,
-180,
-216,
-199,
-144,
-196,
-229,
-22,
-137,
-217,
-181,
-250,
-9,
-127,
-200,
-45,
-242,
-199,
-57,
-154,
-77,
-129,
-5,
-48,
-199,
-147,
-194,
-36,
-74,
-88,
-142,
-223,
-117,
-75,
-238,
-167,
-216,
-223,
-83,
-212,
-179,
-47,
-146,
-152,
-151,
-209,
-127,
-192,
-241,
-41,
-180,
-145,
-178,
-99,
-189,
-124,
-212,
-16,
-151,
-21,
-2,
-87,
-151,
-84,
-232,
-114,
-148,
-193,
-100,
-89,
-86,
-139,
-87,
-178,
-127,
-77,
-58,
-215,
-34,
-158,
-245,
-191,
-252,
-241,
-108,
-132,
-16,
-110,
-10,
-33,
-188,
-44,
-105,
-99,
-21,
-36,
-190,
-192,
-172,
-109,
-71,
-75,
-90,
-172,
-164,
-173,
-20,
-1,
-47,
-69,
-61,
-123,
-147,
-164,
-99,
-48,
-185,
-102,
-107,
-224,
-240,
-146,
-54,
-123,
-15,
-18,
-151,
-91,
-140,
-64,
-141,
-33,
-150,
-24,
-105,
-217,
-252,
-113,
-132,
-110,
-83,
-204,
-89,
-51,
-186,
-247,
-31,
-3,
-123,
-238,
-60,
-133,
-201,
-28,
-165,
-31,
-4,
-197,
-2,
-94,
-138,
-122,
-118,
-101,
-44,
-170,
-231,
-37,
-76,
-183,
-80,
-168,
-134,
-247,
-169,
-235,
-44,
-26,
-200,
-1,
-85,
-35,
-64,
-150,
-240,
-30,
-224,
-184,
-196,
-74,
-187,
-218,
-235,
-151,
-8,
-34,
-52,
-233,
-243,
-87,
-90,
-155,
-219,
-96,
-49,
-244,
-11,
-39,
-244,
-173,
-208,
-157,
-155,
-97,
-200,
-28,
-138,
-233,
-11,
-254,
-66,
-131,
-152,
-196,
-58,
-12,
-208,
-183,
-229,
-150,
-119,
-104,
-208,
-190,
-194,
-5,
-116,
-105,
-157,
-79,
-107,
-243,
-101,
-204,
-148,
-59,
-201,
-255,
-162,
-158,
-74,
-9,
-12,
-80,
-41,
-224,
-141,
-36,
-84,
-189,
-195,
-172,
-226,
-229,
-44,
-153,
-99,
-227,
-143,
-37,
-45,
-33,
-233,
-247,
-254,
-215,
-43,
-188,
-222,
-79,
-217,
-33,
-132,
-208,
-86,
-82,
-169,
-141,
-36,
-237,
-229,
-123,
-249,
-172,
-221,
-82,
-157,
-195,
-134,
-217,
-66,
-96,
-8,
-97,
-86,
-8,
-225,
-216,
-16,
-194,
-10,
-178,
-132,
-77,
-61,
-223,
-233,
-123,
-14,
-69,
-227,
-32,
-218,
-57,
-6,
-192,
-210,
-68,
-182,
-119,
-105,
-177,
-254,
-74,
-25,
-192,
-233,
-42,
-167,
-0,
-90,
-206,
-8,
-134,
-109,
-206,
-176,
-101,
-201,
-253,
-228,
-32,
-218,
-132,
-182,
-160,
-197,
-192,
-216,
-130,
-54,
-234,
-77,
-163,
-192,
-95,
-49,
-19,
-232,
-39,
-11,
-238,
-39,
-101,
-9,
-199,
-76,
-161,
-215,
-3,
-167,
-71,
-238,
-181,
-38,
-3,
-144,
-184,
-239,
-79,
-42,
-48,
-111,
-222,
-51,
-129,
-69,
-128,
-229,
-170,
-75,
-116,
-213,
-86,
-33,
-3,
-84,
-49,
-54,
-166,
-71,
-184,
-25,
-216,
-190,
-164,
-254,
-77,
-48,
-33,
-29,
-103,
-216,
-238,
-130,
-77,
-169,
-145,
-37,
-28,
-183,
-153,
-3,
-255,
-136,
-220,
-75,
-226,
-252,
-218,
-220,
-91,
-94,
-87,
-210,
-22,
-114,
-152,
-13,
-99,
-18,
-230,
-149,
-219,
-120,
-107,
-218,
-196,
-62,
-149,
-49,
-64,
-41,
-99,
-99,
-91,
-218,
-126,
-25,
-75,
-233,
-51,
-242,
-224,
-35,
-197,
-117,
-196,
-13,
-69,
-173,
-48,
-0,
-17,
-148,
-212,
-85,
-26,
-59,
-55,
-28,
-72,
-125,
-15,
-37,
-229,
-199,
-151,
-61,
-115,
-207,
-224,
-29,
-239,
-54,
-244,
-185,
-235,
-41,
-32,
-181,
-158,
-145,
-138,
-34,
-6,
-32,
-81,
-7,
-50,
-34,
-25,
-128,
-52,
-93,
-121,
-229,
-151,
-75,
-194,
-252,
-149,
-242,
-5,
-213,
-25,
-37,
-218,
-0,
-53,
-236,
-239,
-101,
-253,
-175,
-98,
-254,
-12,
-205,
-235,
-192,
-129,
-64,
-163,
-101,
-110,
-62,
-89,
-244,
-78,
-88,
-182,
-203,
-87,
-129,
-235,
-155,
-84,
-168,
-4,
-93,
-121,
-136,
-32,
-66,
-115,
-115,
-8,
-97,
-5,
-191,
-189,
-124,
-8,
-97,
-200,
-198,
-201,
-53,
-176,
-179,
-6,
-187,
-187,
-247,
-18,
-41,
-1,
-182,
-173,
-32,
-132,
-48,
-69,
-210,
-30,
-50,
-29,
-78,
-101,
-36,
-114,
-229,
-71,
-128,
-237,
-85,
-123,
-18,
-182,
-9,
-65,
-97,
-182,
-201,
-178,
-17,
-32,
-71,
-215,
-122,
-194,
-201,
-72,
-63,
-170,
-70,
-146,
-202,
-81,
-194,
-233,
-170,
-178,
-143,
-125,
-17,
-91,
-33,
-188,
-132,
-173,
-148,
-186,
-86,
-2,
-181,
-48,
-2,
-44,
-129,
-153,
-231,
-143,
-37,
-109,
-251,
-219,
-78,
-220,
-226,
-154,
-157,
-107,
-121,
-129,
-104,
-5,
-73,
-215,
-132,
-16,
-166,
-135,
-16,
-158,
-80,
-3,
-208,
-255,
-132,
-147,
-93,
-127,
-221,
-164,
-101,
-31,
-123,
-70,
-22,
-145,
-252,
-14,
-89,
-100,
-241,
-144,
-200,
-228,
-126,
-79,
-55,
-146,
-214,
-145,
-237,
-168,
-126,
-86,
-8,
-225,
-153,
-42,
-226,
-16,
-194,
-164,
-206,
-223,
-144,
-155,
-88,
-98,
-35,
-112,
-75,
-88,
-89,
-69,
-101,
-35,
-0,
-125,
-212,
-149,
-167,
-124,
-221,
-189,
-248,
-81,
-48,
-7,
-214,
-162,
-93,
-77,
-146,
-133,
-210,
-22,
-70,
-128,
-174,
-133,
-192,
-172,
-42,
-120,
-23,
-63,
-220,
-221,
-213,
-193,
-77,
-177,
-145,
-164,
-175,
-135,
-16,
-238,
-84,
-129,
-93,
-29,
-248,
-33,
-112,
-35,
-22,
-199,
-119,
-66,
-228,
-254,
-246,
-126,
-255,
-111,
-180,
-227,
-14,
-93,
-58,
-74,
-52,
-96,
-146,
-247,
-72,
-122,
-168,
-224,
-222,
-235,
-41,
-126,
-18,
-12,
-56,
-210,
-118,
-19,
-101,
-212,
-110,
-144,
-106,
-217,
-151,
-157,
-74,
-71,
-194,
-46,
-91,
-192,
-124,
-254,
-127,
-94,
-226,
-249,
-128,
-110,
-195,
-20,
-29,
-75,
-2,
-255,
-172,
-232,
-71,
-233,
-23,
-87,
-99,
-148,
-72,
-250,
-114,
-125,
-100,
-123,
-30,
-216,
-175,
-97,
-91,
-203,
-96,
-94,
-73,
-39,
-97,
-171,
-155,
-104,
-230,
-175,
-170,
-17,
-0,
-155,
-255,
-191,
-65,
-133,
-207,
-66,
-45,
-164,
-50,
-64,
-69,
-29,
-41,
-206,
-16,
-159,
-192,
-66,
-157,
-174,
-35,
-238,
-80,
-49,
-37,
-118,
-92,
-208,
-223,
-210,
-47,
-183,
-6,
-3,
-164,
-102,
-43,
-189,
-25,
-248,
-97,
-23,
-253,
-153,
-142,
-169,
-113,
-175,
-39,
-18,
-43,
-145,
-161,
-171,
-98,
-128,
-23,
-48,
-231,
-150,
-230,
-249,
-129,
-11,
-30,
-160,
-231,
-217,
-41,
-49,
-149,
-236,
-155,
-253,
-75,
-24,
-178,
-124,
-193,
-166,
-134,
-37,
-48,
-245,
-237,
-109,
-93,
-182,
-85,
-249,
-117,
-215,
-100,
-128,
-153,
-148,
-251,
-18,
-116,
-173,
-152,
-162,
-109,
-29,
-126,
-141,
-134,
-251,
-197,
-0,
-231,
-96,
-6,
-167,
-223,
-19,
-223,
-36,
-114,
-107,
-76,
-6,
-184,
-145,
-76,
-166,
-172,
-134,
-109,
-165,
-142,
-18,
-165,
-52,
-53,
-218,
-234,
-169,
-117,
-175,
-167,
-232,
-23,
-3,
-140,
-52,
-212,
-249,
-114,
-49,
-69,
-217,
-222,
-37,
-245,
-204,
-81,
-12,
-208,
-52,
-52,
-44,
-201,
-178,
-54,
-135,
-33,
-73,
-122,
-87,
-181,
-228,
-61,
-95,
-183,
-83,
-192,
-136,
-7,
-213,
-89,
-41,
-91,
-217,
-89,
-188,
-162,
-15,
-251,
-249,
-124,
-220,
-181,
-16,
-212,
-214,
-151,
-91,
-103,
-42,
-1,
-62,
-6,
-252,
-185,
-219,
-54,
-11,
-234,
-190,
-24,
-184,
-164,
-23,
-117,
-167,
-52,
-222,
-218,
-206,
-226,
-37,
-109,
-28,
-136,
-45,
-55,
-95,
-109,
-145,
-1,
-250,
-102,
-85,
-196,
-18,
-99,
-79,
-163,
-100,
-163,
-7,
-239,
-199,
-195,
-192,
-123,
-234,
-220,
-243,
-251,
-189,
-241,
-232,
-162,
-69,
-87,
-109,
-74,
-60,
-94,
-170,
-166,
-24,
-103,
-176,
-85,
-48,
-75,
-216,
-16,
-6,
-192,
-118,
-61,
-123,
-8,
-243,
-2,
-62,
-51,
-161,
-47,
-201,
-95,
-110,
-27,
-240,
-175,
-191,
-52,
-49,
-68,
-83,
-6,
-160,
-194,
-163,
-171,
-107,
-80,
-189,
-62,
-77,
-181,
-101,
-23,
-122,
-188,
-144,
-232,
-188,
-225,
-109,
-196,
-24,
-96,
-77,
-175,
-127,
-93,
-224,
-209,
-212,
-103,
-235,
-23,
-176,
-192,
-208,
-115,
-170,
-41,
-251,
-136,
-178,
-47,
-50,
-71,
-151,
-106,
-167,
-46,
-165,
-105,
-3,
-69,
-12,
-224,
-247,
-174,
-195,
-242,
-23,
-124,
-164,
-151,
-125,
-104,
-2,
-204,
-234,
-250,
-209,
-4,
-58,
-40,
-214,
-184,
-22,
-222,
-171,
-131,
-236,
-23,
-118,
-128,
-164,
-159,
-43,
-109,
-227,
-230,
-86,
-80,
-244,
-16,
-109,
-60,
-92,
-8,
-97,
-43,
-73,
-235,
-75,
-58,
-173,
-155,
-122,
-98,
-160,
-194,
-233,
-195,
-251,
-191,
-62,
-166,
-210,
-126,
-58,
-82,
-197,
-210,
-50,
-235,
-226,
-176,
-99,
-118,
-96,
-72,
-8,
-97,
-150,
-164,
-163,
-74,
-104,
-231,
-24,
-0,
-43,
-134,
-16,
-30,
-149,
-25,
-163,
-26,
-167,
-108,
-47,
-65,
-138,
-211,
-199,
-143,
-37,
-157,
-44,
-41,
-230,
-21,
-20,
-100,
-73,
-183,
-135,
-29,
-35,
-198,
-65,
-178,
-101,
-252,
-10,
-184,
-79,
-210,
-197,
-138,
-4,
-111,
-96,
-18,
-255,
-195,
-46,
-40,
-78,
-136,
-220,
-47,
-253,
-194,
-19,
-179,
-170,
-255,
-44,
-132,
-240,
-235,
-16,
-66,
-76,
-216,
-251,
-183,
-164,
-158,
-239,
-108,
-78,
-66,
-130,
-173,
-178,
-20,
-238,
-115,
-44,
-66,
-8,
-27,
-87,
-144,
-156,
-39,
-105,
-127,
-73,
-79,
-75,
-186,
-66,
-150,
-218,
-61,
-139,
-54,
-220,
-186,
-162,
-123,
-47,
-59,
-110,
-147,
-57,
-150,
-244,
-26,
-209,
-80,
-249,
-44,
-230,
-74,
-6,
-72,
-192,
-24,
-217,
-143,
-60,
-83,
-17,
-205,
-94,
-8,
-33,
-187,
-55,
-112,
-211,
-31,
-170,
-76,
-155,
-120,
-165,
-164,
-126,
-164,
-154,
-171,
-100,
-128,
-236,
-222,
-193,
-147,
-128,
-189,
-122,
-222,
-165,
-22,
-225,
-14,
-163,
-77,
-172,
-133,
-31,
-151,
-244,
-11,
-73,
-87,
-169,
-32,
-190,
-175,
-45,
-41,
-187,
-0,
-23,
-72,
-90,
-145,
-18,
-115,
-112,
-75,
-72,
-103,
-0,
-89,
-186,
-182,
-170,
-117,
-247,
-38,
-146,
-110,
-240,
-211,
-235,
-138,
-214,
-248,
-35,
-29,
-33,
-132,
-203,
-67,
-8,
-111,
-247,
-29,
-74,
-174,
-168,
-91,
-30,
-184,
-149,
-72,
-196,
-83,
-141,
-246,
-159,
-147,
-116,
-156,
-164,
-83,
-154,
-214,
-145,
-216,
-206,
-86,
-77,
-125,
-59,
-27,
-131,
-26,
-182,
-236,
-94,
-46,
-3,
-187,
-69,
-197,
-26,
-124,
-34,
-112,
-107,
-147,
-178,
-13,
-250,
-176,
-89,
-183,
-245,
-164,
-54,
-54,
-29,
-88,
-186,
-47,
-141,
-205,
-1,
-24,
-78,
-38,
-196,
-92,
-225,
-198,
-99,
-187,
-169,
-22,
-186,
-231,
-183,
-129,
-172,
-16,
-56,
-70,
-115,
-192,
-254,
-0,
-48,
-160,
-167,
-207,
-7,
-148,
-0,
-127,
-146,
-116,
-73,
-8,
-225,
-59,
-125,
-239,
-88,
-187,
-120,
-80,
-210,
-235,
-146,
-142,
-239,
-219,
-16,
-142,
-5,
-60,
-12,
-91,
-74,
-214,
-84,
-96,
-134,
-144,
-29,
-178,
-140,
-144,
-185,
-183,
-9,
-102,
-101,
-91,
-40,
-114,
-111,
-54,
-18,
-219,
-25,
-246,
-105,
-168,
-31,
-200,
-239,
-24,
-18,
-29,
-1,
-24,
-65,
-14,
-32,
-238,
-172,
-17,
-219,
-86,
-78,
-33,
-132,
-155,
-37,
-61,
-37,
-105,
-136,
-199,
-174,
-99,
-130,
-122,
-31,
-26,
-150,
-12,
-103,
-178,
-174,
-77,
-207,
-221,
-48,
-107,
-18,
-3,
-168,
-100,
-15,
-190,
-178,
-47,
-203,
-231,
-178,
-31,
-3,
-209,
-31,
-172,
-71,
-248,
-179,
-236,
-135,
-142,
-225,
-181,
-94,
-230,
-37,
-42,
-250,
-65,
-49,
-155,
-192,
-196,
-94,
-181,
-219,
-13,
-146,
-100,
-128,
-16,
-194,
-78,
-37,
-117,
-148,
-77,
-27,
-231,
-200,
-18,
-77,
-237,
-89,
-191,
-107,
-141,
-113,
-155,
-164,
-227,
-187,
-173,
-36,
-22,
-176,
-218,
-5,
-222,
-144,
-134,
-238,
-250,
-57,
-18,
-208,
-181,
-16,
-24,
-141,
-51,
-27,
-184,
-183,
-143,
-36,
-1,
-63,
-174,
-223,
-181,
-198,
-120,
-70,
-150,
-237,
-108,
-196,
-32,
-132,
-240,
-238,
-58,
-244,
-190,
-196,
-36,
-132,
-176,
-97,
-238,
-250,
-169,
-146,
-246,
-13,
-33,
-188,
-189,
-173,
-190,
-205,
-113,
-171,
-128,
-4,
-228,
-183,
-182,
-157,
-19,
-81,
-212,
-255,
-117,
-36,
-253,
-178,
-205,
-134,
-178,
-230,
-224,
-57,
-253,
-165,
-117,
-176,
-148,
-70,
-136,
-173,
-189,
-10,
-69,
-239,
-188,
-100,
-196,
-120,
-151,
-164,
-99,
-218,
-236,
-195,
-220,
-104,
-14,
-126,
-135,
-76,
-14,
-72,
-134,
-11,
-111,
-255,
-47,
-114,
-125,
-68,
-9,
-111,
-158,
-48,
-163,
-219,
-13,
-169,
-7,
-161,
-47,
-12,
-80,
-177,
-115,
-120,
-219,
-216,
-70,
-102,
-228,
-169,
-131,
-55,
-36,
-197,
-182,
-100,
-107,
-69,
-120,
-115,
-219,
-65,
-97,
-144,
-235,
-112,
-98,
-142,
-51,
-7,
-251,
-50,
-43,
-154,
-116,
-194,
-173,
-107,
-43,
-202,
-150,
-173,
-117,
-240,
-134,
-164,
-151,
-242,
-23,
-235,
-10,
-111,
-37,
-24,
-177,
-211,
-235,
-28,
-199,
-0,
-146,
-94,
-46,
-185,
-247,
-37,
-73,
-159,
-117,
-107,
-91,
-12,
-111,
-2,
-222,
-28,
-209,
-5,
-204,
-82,
-124,
-4,
-104,
-5,
-69,
-140,
-228,
-186,
-147,
-5,
-134,
-115,
-191,
-133,
-57,
-142,
-1,
-202,
-132,
-213,
-16,
-194,
-206,
-21,
-197,
-255,
-216,
-33,
-205,
-93,
-143,
-142,
-0,
-255,
-23,
-48,
-199,
-49,
-64,
-83,
-84,
-172,
-114,
-138,
-100,
-128,
-57,
-2,
-221,
-172,
-224,
-230,
-198,
-85,
-64,
-19,
-204,
-82,
-100,
-4,
-0,
-78,
-165,
-96,
-71,
-180,
-185,
-5,
-255,
-103,
-70,
-128,
-50,
-132,
-16,
-22,
-45,
-184,
-213,
-186,
-226,
-101,
-20,
-35,
-16,
-20,
-196,
-252,
-187,
-103,
-211,
-26,
-53,
-234,
-105,
-197,
-186,
-215,
-79,
-140,
-142,
-0,
-134,
-34,
-141,
-92,
-173,
-108,
-105,
-115,
-145,
-54,
-117,
-20,
-163,
-24,
-197,
-40,
-70,
-49,
-138,
-81,
-140,
-98,
-20,
-163,
-24,
-197,
-40,
-70,
-49,
-138,
-81,
-140,
-98,
-20,
-163,
-24,
-197,
-40,
-70,
-49,
-138,
-81,
-204,
-37,
-248,
-255,
-129,
-51,
-157,
-250,
-111,
-139,
-157,
-153,
-0,
-0,
-0,
-0,
-73,
-69,
-78,
-68,
-174,
-66,
-96,
-130,
-};
-/* clang-format on */
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index 190f2a03d9..7d747e3c9e 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -74,6 +74,10 @@ static const unsigned char dropdown_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x60, 0xf8, 0xc0, 0xcc, 0x0, 0x2, 0x60, 0x16, 0x98, 0x78, 0x67, 0x8, 0x81, 0x6f, 0x4d, 0xde, 0x9a, 0x0, 0x5, 0xde, 0x3a, 0x3d, 0xfc, 0x8f, 0x80, 0xaf, 0xba, 0x18, 0xde, 0x29, 0x2, 0x19, 0xbf, 0x61, 0x2, 0x6f, 0x62, 0x18, 0x3e, 0xb0, 0xbd, 0x97, 0x4, 0x32, 0xff, 0x80, 0xb9, 0xb1, 0x20, 0x93, 0xc0, 0x42, 0x8, 0x2e, 0x54, 0xe8, 0x9d, 0xdc, 0x9b, 0x54, 0x10, 0xb, 0x21, 0xc4, 0x4, 0x63, 0x1, 0x0, 0x86, 0x1f, 0x3b, 0x1e, 0x92, 0x22, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char ellipsis_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x8, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc9, 0x11, 0xce, 0xcc, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x78, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x95, 0xd1, 0x31, 0xa, 0xc2, 0x50, 0x10, 0x4, 0xd0, 0xb7, 0x1f, 0xf, 0x60, 0x67, 0xa, 0xf, 0x12, 0x6f, 0x60, 0xe9, 0x51, 0x5, 0x3d, 0x44, 0xee, 0x61, 0xa1, 0xa5, 0xf6, 0x81, 0xb5, 0xc8, 0x47, 0x82, 0x84, 0x4f, 0xb2, 0xdd, 0xb0, 0x33, 0xb3, 0xb3, 0x4c, 0x40, 0x66, 0xee, 0x71, 0xc2, 0x1, 0x3b, 0xcb, 0x33, 0xe2, 0x85, 0x21, 0x22, 0xde, 0x51, 0x45, 0x97, 0x86, 0x60, 0xc9, 0xe0, 0x5a, 0xea, 0xa5, 0xb5, 0x22, 0x95, 0xdb, 0x97, 0x1a, 0xf, 0x6e, 0xb8, 0xcf, 0x8, 0x2d, 0xdc, 0x95, 0xd9, 0x22, 0xfe, 0x9c, 0x9b, 0x38, 0x32, 0xf3, 0x8c, 0xe3, 0x86, 0xa8, 0xf0, 0x28, 0x18, 0x4c, 0xf, 0xaf, 0x9d, 0x11, 0x43, 0xf0, 0xab, 0xa3, 0x47, 0xa7, 0x5d, 0xc7, 0xd3, 0x54, 0xc7, 0xe7, 0xb, 0xb9, 0xce, 0x1f, 0xc6, 0x2d, 0x99, 0x55, 0xc7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char error_icon_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0xe, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x18, 0x5, 0xa3, 0x0, 0x1, 0x0, 0x2, 0x10, 0x0, 0x1, 0x14, 0xc2, 0xc0, 0x92, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 5647856736..2c5634e6ef 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -505,9 +505,6 @@ void BaseMaterial3D::_update_shader() {
case DIFFUSE_LAMBERT_WRAP:
code += ",diffuse_lambert_wrap";
break;
- case DIFFUSE_OREN_NAYAR:
- code += ",diffuse_oren_nayar";
- break;
case DIFFUSE_TOON:
code += ",diffuse_toon";
break;
@@ -543,6 +540,9 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_DISABLE_DEPTH_TEST]) {
code += ",depth_test_disabled";
}
+ if (flags[FLAG_PARTICLE_TRAILS_MODE]) {
+ code += ",particle_trails";
+ }
if (shading_mode == SHADING_MODE_PER_VERTEX) {
code += ",vertex_lighting";
}
@@ -672,7 +672,7 @@ void BaseMaterial3D::_update_shader() {
code += "uniform sampler2D texture_flowmap : hint_aniso," + texfilter_str + ";\n";
}
if (features[FEATURE_AMBIENT_OCCLUSION]) {
- code += "uniform sampler2D texture_ambient_occlusion : hint_white;\n";
+ code += "uniform sampler2D texture_ambient_occlusion : hint_white, " + texfilter_str + ";\n";
code += "uniform vec4 ao_texture_channel;\n";
code += "uniform float ao_light_affect;\n";
}
@@ -888,7 +888,7 @@ void BaseMaterial3D::_update_shader() {
code += "\t\tfloat current_layer_depth = 0.0;\n";
code += "\t\tvec2 P = view_dir.xy * heightmap_scale;\n";
code += "\t\tvec2 delta = P / num_layers;\n";
- code += "\t\tvec2 ofs = base_uv;\n";
+ code += "\t\tvec2 ofs = base_uv;\n";
if (flags[FLAG_INVERT_HEIGHTMAP]) {
code += "\t\tfloat depth = texture(texture_heightmap, ofs).r;\n";
} else {
@@ -1029,7 +1029,10 @@ void BaseMaterial3D::_update_shader() {
if (features[FEATURE_REFRACTION]) {
if (features[FEATURE_NORMAL_MAPPING]) {
- code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMAL_MAP.x + BINORMAL * NORMAL_MAP.y + NORMAL * NORMAL_MAP.z,NORMAL_MAP_DEPTH) );\n";
+ code += "\tvec3 unpacked_normal = NORMAL_MAP;\n";
+ code += "\tunpacked_normal.xy = unpacked_normal.xy * 2.0 - 1.0;\n";
+ code += "\tunpacked_normal.z = sqrt(max(0.0, 1.0 - dot(unpacked_normal.xy, unpacked_normal.xy)));\n";
+ code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * unpacked_normal.x + BINORMAL * unpacked_normal.y + NORMAL * unpacked_normal.z,NORMAL_MAP_DEPTH) );\n";
} else {
code += "\tvec3 ref_normal = NORMAL;\n";
}
@@ -1597,6 +1600,9 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) {
if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN || p_flag == FLAG_USE_POINT_SIZE) {
notify_property_list_changed();
}
+ if (p_flag == FLAG_PARTICLE_TRAILS_MODE) {
+ update_configuration_warning();
+ }
_queue_shader_change();
}
@@ -1751,7 +1757,8 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
if (orm) {
if (property.name == "shading_mode") {
- property.hint_string = "Unshaded,PerPixel"; //vertex not supported in ORM mode, since no individual roughness.
+ // Vertex not supported in ORM mode, since no individual roughness.
+ property.hint_string = "Unshaded,Per-Pixel";
}
if (property.name.begins_with("roughness") || property.name.begins_with("metallic") || property.name.begins_with("ao_texture")) {
property.usage = 0;
@@ -2177,6 +2184,8 @@ Shader::Mode BaseMaterial3D::get_shader_mode() const {
}
void BaseMaterial3D::_bind_methods() {
+ static_assert(sizeof(MaterialKey) == 16, "MaterialKey should be 16 bytes");
+
ClassDB::bind_method(D_METHOD("set_albedo", "albedo"), &BaseMaterial3D::set_albedo);
ClassDB::bind_method(D_METHOD("get_albedo"), &BaseMaterial3D::get_albedo);
@@ -2376,19 +2385,19 @@ void BaseMaterial3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_distance_fade_min_distance"), &BaseMaterial3D::get_distance_fade_min_distance);
ADD_GROUP("Transparency", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,Alpha Scissor,Alpha Hash,Depth PrePass"), "set_transparency", "get_transparency");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,Alpha Scissor,Alpha Hash,Depth Pre-Pass"), "set_transparency", "get_transparency");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_hash_scale", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_alpha_hash_scale", "get_alpha_hash_scale");
ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_antialiasing_mode", PROPERTY_HINT_ENUM, "Disabled,Alpha Edge Blend,Alpha Edge Clip"), "set_alpha_antialiasing", "get_alpha_antialiasing");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_antialiasing_edge", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_antialiasing_edge", "get_alpha_antialiasing_edge");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul"), "set_blend_mode", "get_blend_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Subtract,Multiply"), "set_blend_mode", "get_blend_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mode", PROPERTY_HINT_ENUM, "Back,Front,Disabled"), "set_cull_mode", "get_cull_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_draw_mode", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never"), "set_depth_draw_mode", "get_depth_draw_mode");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_flag", "get_flag", FLAG_DISABLE_DEPTH_TEST);
ADD_GROUP("Shading", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "shading_mode", PROPERTY_HINT_ENUM, "Unshaded,PerPixel,PerVertex"), "set_shading_mode", "get_shading_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "diffuse_mode", PROPERTY_HINT_ENUM, "Burley,Lambert,Lambert Wrap,Oren Nayar,Toon"), "set_diffuse_mode", "get_diffuse_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shading_mode", PROPERTY_HINT_ENUM, "Unshaded,Per-Pixel,Per-Vertex"), "set_shading_mode", "get_shading_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "diffuse_mode", PROPERTY_HINT_ENUM, "Burley,Lambert,Lambert Wrap,Toon"), "set_diffuse_mode", "get_diffuse_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "specular_mode", PROPERTY_HINT_ENUM, "SchlickGGX,Blinn,Phong,Toon,Disabled"), "set_specular_mode", "get_specular_mode");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "disable_ambient_light"), "set_flag", "get_flag", FLAG_DISABLE_AMBIENT_LIGHT);
@@ -2491,7 +2500,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Detail", "detail_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "detail_enabled"), "set_feature", "get_feature", FEATURE_DETAIL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "detail_mask", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_DETAIL_MASK);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "detail_blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul"), "set_detail_blend_mode", "get_detail_blend_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "detail_blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Subtract,Multiply"), "set_detail_blend_mode", "get_detail_blend_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "detail_uv_layer", PROPERTY_HINT_ENUM, "UV1,UV2"), "set_detail_uv", "get_detail_uv");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "detail_albedo", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_DETAIL_ALBEDO);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "detail_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_DETAIL_NORMAL);
@@ -2511,7 +2520,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv2_world_triplanar"), "set_flag", "get_flag", FLAG_UV2_USE_WORLD_TRIPLANAR);
ADD_GROUP("Sampling", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "texture_repeat"), "set_flag", "get_flag", FLAG_USE_TEXTURE_REPEAT);
ADD_GROUP("Shadows", "");
@@ -2534,6 +2543,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "fixed_size"), "set_flag", "get_flag", FLAG_FIXED_SIZE);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_point_size"), "set_flag", "get_flag", FLAG_USE_POINT_SIZE);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_point_size", "get_point_size");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_particle_trails"), "set_flag", "get_flag", FLAG_PARTICLE_TRAILS_MODE);
ADD_GROUP("Proximity Fade", "proximity_fade_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enable"), "set_proximity_fade", "is_proximity_fade_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_proximity_fade_distance", "get_proximity_fade_distance");
@@ -2635,12 +2645,12 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_USE_TEXTURE_REPEAT);
BIND_ENUM_CONSTANT(FLAG_INVERT_HEIGHTMAP);
BIND_ENUM_CONSTANT(FLAG_SUBSURFACE_MODE_SKIN);
+ BIND_ENUM_CONSTANT(FLAG_PARTICLE_TRAILS_MODE);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(DIFFUSE_BURLEY);
BIND_ENUM_CONSTANT(DIFFUSE_LAMBERT);
BIND_ENUM_CONSTANT(DIFFUSE_LAMBERT_WRAP);
- BIND_ENUM_CONSTANT(DIFFUSE_OREN_NAYAR);
BIND_ENUM_CONSTANT(DIFFUSE_TOON);
BIND_ENUM_CONSTANT(SPECULAR_SCHLICK_GGX);
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 70452a5f74..dc3ecdb5de 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -235,6 +235,7 @@ public:
FLAG_USE_TEXTURE_REPEAT,
FLAG_INVERT_HEIGHTMAP,
FLAG_SUBSURFACE_MODE_SKIN,
+ FLAG_PARTICLE_TRAILS_MODE,
FLAG_MAX
};
@@ -242,7 +243,6 @@ public:
DIFFUSE_BURLEY,
DIFFUSE_LAMBERT,
DIFFUSE_LAMBERT_WRAP,
- DIFFUSE_OREN_NAYAR,
DIFFUSE_TOON,
DIFFUSE_MAX
};
@@ -305,16 +305,15 @@ private:
uint64_t roughness_channel : get_num_bits(TEXTURE_CHANNEL_MAX - 1);
uint64_t emission_op : get_num_bits(EMISSION_OP_MAX - 1);
uint64_t distance_fade : get_num_bits(DISTANCE_FADE_MAX - 1);
-
- // flag bitfield
- uint64_t feature_mask : FEATURE_MAX - 1;
- uint64_t flags : FLAG_MAX - 1;
-
// booleans
uint64_t deep_parallax : 1;
uint64_t grow : 1;
uint64_t proximity_fade : 1;
+ // flag bitfield
+ uint32_t feature_mask;
+ uint32_t flags;
+
MaterialKey() {
memset(this, 0, sizeof(MaterialKey));
}
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index f8e1ce6a61..5e8e77c730 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -579,6 +579,14 @@ Vector<Ref<Shape3D>> Mesh::convex_decompose() const {
return ret;
}
+int Mesh::get_builtin_bind_pose_count() const {
+ return 0;
+}
+
+Transform3D Mesh::get_builtin_bind_pose(int p_index) const {
+ return Transform3D();
+}
+
Mesh::Mesh() {
}
@@ -1394,7 +1402,7 @@ void ArrayMesh::regen_normal_maps() {
}
//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, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache);
+bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, 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;
struct ArrayMeshLightmapSurface {
Ref<Material> material;
@@ -1403,29 +1411,29 @@ struct ArrayMeshLightmapSurface {
uint32_t format = 0;
};
-Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) {
- int *cache_data = nullptr;
- unsigned int cache_size = 0;
- bool use_cache = false; // Don't use cache
- return lightmap_unwrap_cached(cache_data, cache_size, use_cache, p_base_transform, p_texel_size);
+Error ArrayMesh::lightmap_unwrap(const Transform3D &p_base_transform, float p_texel_size) {
+ Vector<uint8_t> null_cache;
+ return lightmap_unwrap_cached(p_base_transform, p_texel_size, null_cache, null_cache, false);
}
-Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size) {
+Error ArrayMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache, bool p_generate_cache) {
ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
- Vector<float> vertices;
- Vector<float> normals;
- Vector<int> indices;
- Vector<float> uv;
- Vector<Pair<int, int>> uv_indices;
+ LocalVector<float> vertices;
+ LocalVector<float> normals;
+ LocalVector<int> indices;
+ LocalVector<float> uv;
+ LocalVector<Pair<int, int>> uv_indices;
Vector<ArrayMeshLightmapSurface> lightmap_surfaces;
// Keep only the scale
- Transform transform = p_base_transform;
- transform.origin = Vector3();
- transform.looking_at(Vector3(1, 0, 0), Vector3(0, 1, 0));
+ Basis basis = p_base_transform.get_basis();
+ Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length());
+
+ Transform3D transform;
+ transform.scale(scale);
Basis normal_basis = transform.basis.inverse().transposed();
@@ -1439,14 +1447,12 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
Array arrays = surface_get_arrays(i);
s.material = surface_get_material(i);
- SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices);
+ SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices, &s.format);
- Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX];
+ PackedVector3Array rvertices = arrays[Mesh::ARRAY_VERTEX];
int vc = rvertices.size();
- const Vector3 *r = rvertices.ptr();
- Vector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL];
- const Vector3 *rn = rnormals.ptr();
+ PackedVector3Array rnormals = arrays[Mesh::ARRAY_NORMAL];
int vertex_ofs = vertices.size() / 3;
@@ -1455,24 +1461,29 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
uv_indices.resize(vertex_ofs + vc);
for (int j = 0; j < vc; j++) {
- Vector3 v = transform.xform(r[j]);
- Vector3 n = normal_basis.xform(rn[j]).normalized();
-
- vertices.write[(j + vertex_ofs) * 3 + 0] = v.x;
- vertices.write[(j + vertex_ofs) * 3 + 1] = v.y;
- vertices.write[(j + vertex_ofs) * 3 + 2] = v.z;
- normals.write[(j + vertex_ofs) * 3 + 0] = n.x;
- normals.write[(j + vertex_ofs) * 3 + 1] = n.y;
- normals.write[(j + vertex_ofs) * 3 + 2] = n.z;
- uv_indices.write[j + vertex_ofs] = Pair<int, int>(i, j);
+ Vector3 v = transform.xform(rvertices[j]);
+ Vector3 n = normal_basis.xform(rnormals[j]).normalized();
+
+ vertices[(j + vertex_ofs) * 3 + 0] = v.x;
+ vertices[(j + vertex_ofs) * 3 + 1] = v.y;
+ vertices[(j + vertex_ofs) * 3 + 2] = v.z;
+ normals[(j + vertex_ofs) * 3 + 0] = n.x;
+ normals[(j + vertex_ofs) * 3 + 1] = n.y;
+ normals[(j + vertex_ofs) * 3 + 2] = n.z;
+ uv_indices[j + vertex_ofs] = Pair<int, int>(i, j);
}
- Vector<int> rindices = arrays[Mesh::ARRAY_INDEX];
+ PackedInt32Array rindices = arrays[Mesh::ARRAY_INDEX];
int ic = rindices.size();
+ float eps = 1.19209290e-7F; // Taken from xatlas.h
if (ic == 0) {
for (int j = 0; j < vc / 3; j++) {
- if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) {
+ Vector3 p0 = transform.xform(rvertices[j * 3 + 0]);
+ Vector3 p1 = transform.xform(rvertices[j * 3 + 1]);
+ Vector3 p2 = transform.xform(rvertices[j * 3 + 2]);
+
+ if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue;
}
@@ -1482,15 +1493,18 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
}
} else {
- const int *ri = rindices.ptr();
-
for (int j = 0; j < ic / 3; j++) {
- if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) {
+ Vector3 p0 = transform.xform(rvertices[rindices[j * 3 + 0]]);
+ Vector3 p1 = transform.xform(rvertices[rindices[j * 3 + 1]]);
+ Vector3 p2 = transform.xform(rvertices[rindices[j * 3 + 2]]);
+
+ if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue;
}
- indices.push_back(vertex_ofs + ri[j * 3 + 0]);
- indices.push_back(vertex_ofs + ri[j * 3 + 1]);
- indices.push_back(vertex_ofs + ri[j * 3 + 2]);
+
+ indices.push_back(vertex_ofs + rindices[j * 3 + 0]);
+ indices.push_back(vertex_ofs + rindices[j * 3 + 1]);
+ indices.push_back(vertex_ofs + rindices[j * 3 + 2]);
}
}
@@ -1499,6 +1513,9 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
//unwrap
+ bool use_cache = p_generate_cache; // Used to request cache generation and to know if cache was used
+ uint8_t *gen_cache;
+ int gen_cache_size;
float *gen_uvs;
int *gen_vertices;
int *gen_indices;
@@ -1507,17 +1524,16 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
int size_x;
int size_y;
- bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y, r_cache_data, r_cache_size, r_used_cache);
+ bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), p_src_cache.ptr(), &use_cache, &gen_cache, &gen_cache_size, &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y);
if (!ok) {
return ERR_CANT_CREATE;
}
- //remove surfaces
clear_surfaces();
//create surfacetools for each surface..
- Vector<Ref<SurfaceTool>> surfaces_tools;
+ LocalVector<Ref<SurfaceTool>> surfaces_tools;
for (int i = 0; i < lightmap_surfaces.size(); i++) {
Ref<SurfaceTool> st;
@@ -1528,11 +1544,12 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
}
print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
+
//go through all indices
for (int i = 0; i < gen_index_count; i += 3) {
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_indices.size(), ERR_BUG);
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_indices.size(), ERR_BUG);
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], (int)uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], (int)uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], (int)uv_indices.size(), ERR_BUG);
ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG);
@@ -1542,48 +1559,53 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_COLOR) {
- surfaces_tools.write[surface]->set_color(v.color);
+ surfaces_tools[surface]->set_color(v.color);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TEX_UV) {
- surfaces_tools.write[surface]->set_uv(v.uv);
+ surfaces_tools[surface]->set_uv(v.uv);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_NORMAL) {
- surfaces_tools.write[surface]->set_normal(v.normal);
+ surfaces_tools[surface]->set_normal(v.normal);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TANGENT) {
Plane t;
t.normal = v.tangent;
t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
- surfaces_tools.write[surface]->set_tangent(t);
+ surfaces_tools[surface]->set_tangent(t);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_BONES) {
- surfaces_tools.write[surface]->set_bones(v.bones);
+ surfaces_tools[surface]->set_bones(v.bones);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) {
- surfaces_tools.write[surface]->set_weights(v.weights);
+ surfaces_tools[surface]->set_weights(v.weights);
}
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
- surfaces_tools.write[surface]->set_uv2(uv2);
+ surfaces_tools[surface]->set_uv2(uv2);
- surfaces_tools.write[surface]->add_vertex(v.vertex);
+ surfaces_tools[surface]->add_vertex(v.vertex);
}
}
//generate surfaces
-
- for (int i = 0; i < surfaces_tools.size(); i++) {
- surfaces_tools.write[i]->index();
- surfaces_tools.write[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), lightmap_surfaces[i].format);
+ for (unsigned int i = 0; i < surfaces_tools.size(); i++) {
+ surfaces_tools[i]->index();
+ surfaces_tools[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), lightmap_surfaces[i].format);
}
set_lightmap_size_hint(Size2(size_x, size_y));
- if (!r_used_cache) {
- //free stuff
- ::free(gen_vertices);
- ::free(gen_indices);
- ::free(gen_uvs);
+ if (gen_cache_size > 0) {
+ r_dst_cache.resize(gen_cache_size);
+ memcpy(r_dst_cache.ptrw(), gen_cache, gen_cache_size);
+ memfree(gen_cache);
+ }
+
+ if (!use_cache) {
+ // Cache was not used, free the buffers
+ memfree(gen_vertices);
+ memfree(gen_indices);
+ memfree(gen_uvs);
}
return OK;
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 9a462d5719..2dfb46782b 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -165,6 +165,9 @@ public:
Vector<Ref<Shape3D>> convex_decompose() const;
+ virtual int get_builtin_bind_pose_count() const;
+ virtual Transform3D get_builtin_bind_pose(int p_index) const;
+
Mesh();
};
@@ -259,8 +262,8 @@ public:
void regen_normal_maps();
- Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05);
- Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform = Transform(), float p_texel_size = 0.05);
+ Error lightmap_unwrap(const Transform3D &p_base_transform = Transform3D(), float p_texel_size = 0.05);
+ Error lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache, bool p_generate_cache = true);
virtual void reload_from_file() override;
diff --git a/scene/resources/mesh_data_tool.h b/scene/resources/mesh_data_tool.h
index f5c8f11437..b0ebfba7ee 100644
--- a/scene/resources/mesh_data_tool.h
+++ b/scene/resources/mesh_data_tool.h
@@ -33,8 +33,8 @@
#include "scene/resources/mesh.h"
-class MeshDataTool : public Reference {
- GDCLASS(MeshDataTool, Reference);
+class MeshDataTool : public RefCounted {
+ GDCLASS(MeshDataTool, RefCounted);
int format = 0;
struct Vertex {
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index ad90481fbd..33c9ca6d1e 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -97,10 +97,10 @@ void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
String name = "item/" + itos(E->key()) + "/";
p_list->push_back(PropertyInfo(Variant::STRING, name + "name"));
p_list->push_back(PropertyInfo(Variant::OBJECT, name + "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, name + "mesh_transform"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + "mesh_transform"));
p_list->push_back(PropertyInfo(Variant::ARRAY, name + "shapes"));
p_list->push_back(PropertyInfo(Variant::OBJECT, name + "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, name + "navmesh_transform"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + "navmesh_transform"));
p_list->push_back(PropertyInfo(Variant::OBJECT, name + "preview", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_HELPER));
}
}
@@ -145,7 +145,7 @@ void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navm
notify_property_list_changed();
}
-void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_transform) {
+void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform3D &p_transform) {
ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].navmesh_transform = p_transform;
notify_change_to_owners();
@@ -180,8 +180,8 @@ Ref<NavigationMesh> MeshLibrary::get_item_navmesh(int p_item) const {
return item_map[p_item].navmesh;
}
-Transform MeshLibrary::get_item_navmesh_transform(int p_item) const {
- ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
+Transform3D MeshLibrary::get_item_navmesh_transform(int p_item) const {
+ ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform3D(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].navmesh_transform;
}
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index 1da624c275..1e8a6bf3ff 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -44,14 +44,14 @@ class MeshLibrary : public Resource {
public:
struct ShapeData {
Ref<Shape3D> shape;
- Transform local_transform;
+ Transform3D local_transform;
};
struct Item {
String name;
Ref<Mesh> mesh;
Vector<ShapeData> shapes;
Ref<Texture2D> preview;
- Transform navmesh_transform;
+ Transform3D navmesh_transform;
Ref<NavigationMesh> navmesh;
};
@@ -73,13 +73,13 @@ public:
void set_item_name(int p_item, const String &p_name);
void set_item_mesh(int p_item, const Ref<Mesh> &p_mesh);
void set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh);
- void set_item_navmesh_transform(int p_item, const Transform &p_transform);
+ void set_item_navmesh_transform(int p_item, const Transform3D &p_transform);
void set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes);
void set_item_preview(int p_item, const Ref<Texture2D> &p_preview);
String get_item_name(int p_item) const;
Ref<Mesh> get_item_mesh(int p_item) const;
Ref<NavigationMesh> get_item_navmesh(int p_item) const;
- Transform get_item_navmesh_transform(int p_item) const;
+ Transform3D get_item_navmesh_transform(int p_item) const;
Vector<ShapeData> get_item_shapes(int p_item) const;
Ref<Texture2D> get_item_preview(int p_item) const;
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index 4991887eb3..dea5c4e7d3 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -50,7 +50,7 @@ void MultiMesh::_set_transform_array(const Vector<Vector3> &p_array) {
const Vector3 *r = xforms.ptr();
for (int i = 0; i < len / 4; i++) {
- Transform t;
+ Transform3D t;
t.basis[0] = r[i * 4 + 0];
t.basis[1] = r[i * 4 + 1];
t.basis[2] = r[i * 4 + 2];
@@ -75,7 +75,7 @@ Vector<Vector3> MultiMesh::_get_transform_array() const {
Vector3 *w = xforms.ptrw();
for (int i = 0; i < instance_count; i++) {
- Transform t = get_instance_transform(i);
+ Transform3D t = get_instance_transform(i);
w[i * 4 + 0] = t.basis[0];
w[i * 4 + 1] = t.basis[1];
w[i * 4 + 2] = t.basis[2];
@@ -236,7 +236,7 @@ int MultiMesh::get_visible_instance_count() const {
return visible_instance_count;
}
-void MultiMesh::set_instance_transform(int p_instance, const Transform &p_transform) {
+void MultiMesh::set_instance_transform(int p_instance, const Transform3D &p_transform) {
RenderingServer::get_singleton()->multimesh_instance_set_transform(multimesh, p_instance, p_transform);
}
@@ -244,7 +244,7 @@ void MultiMesh::set_instance_transform_2d(int p_instance, const Transform2D &p_t
RenderingServer::get_singleton()->multimesh_instance_set_transform_2d(multimesh, p_instance, p_transform);
}
-Transform MultiMesh::get_instance_transform(int p_instance) const {
+Transform3D MultiMesh::get_instance_transform(int p_instance) const {
return RenderingServer::get_singleton()->multimesh_instance_get_transform(multimesh, p_instance);
}
diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h
index ca5c42d47a..2fe0927e6f 100644
--- a/scene/resources/multimesh.h
+++ b/scene/resources/multimesh.h
@@ -92,9 +92,9 @@ public:
void set_visible_instance_count(int p_count);
int get_visible_instance_count() const;
- void set_instance_transform(int p_instance, const Transform &p_transform);
+ void set_instance_transform(int p_instance, const Transform3D &p_transform);
void set_instance_transform_2d(int p_instance, const Transform2D &p_transform);
- Transform get_instance_transform(int p_instance) const;
+ Transform3D get_instance_transform(int p_instance) const;
Transform2D get_instance_transform_2d(int p_instance) const;
void set_instance_color(int p_instance, const Color &p_color);
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 8c12f59a00..0a25bb2ed1 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -92,6 +92,7 @@ uint32_t NavigationMesh::get_collision_mask() const {
}
void NavigationMesh::set_collision_mask_bit(int p_bit, bool p_value) {
+ ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << p_bit;
@@ -102,6 +103,7 @@ void NavigationMesh::set_collision_mask_bit(int p_bit, bool p_value) {
}
bool NavigationMesh::get_collision_mask_bit(int p_bit) const {
+ ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
return get_collision_mask() & (1 << p_bit);
}
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 78a0aeaa9a..e85b933439 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -34,8 +34,8 @@
#include "core/io/resource.h"
#include "scene/main/node.h"
-class SceneState : public Reference {
- GDCLASS(SceneState, Reference);
+class SceneState : public RefCounted {
+ GDCLASS(SceneState, RefCounted);
Vector<StringName> names;
Vector<Variant> variants;
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index bb47eebe9b..60d5566f08 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -615,7 +615,7 @@ void ParticlesMaterial::_update_shader() {
}
// turn particle by rotation in Y
if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) {
- code += " TRANSFORM = TRANSFORM * mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ code += " TRANSFORM = mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
}
//scale by scale
@@ -1316,7 +1316,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
ADD_GROUP("Sub Emitter", "sub_emitter_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,AtEnd,AtCollision"), "set_sub_emitter_mode", "get_sub_emitter_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,At End,At Collision"), "set_sub_emitter_mode", "get_sub_emitter_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_sub_emitter_frequency", "get_sub_emitter_frequency");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity");
@@ -1391,7 +1391,7 @@ ParticlesMaterial::ParticlesMaterial() :
set_sub_emitter_keep_velocity(false);
set_attractor_interaction_enabled(true);
- set_collision_enabled(true);
+ set_collision_enabled(false);
set_collision_bounce(0.0);
set_collision_friction(0.0);
set_collision_use_scale(false);
diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp
index d65b0c8927..31df35aa51 100644
--- a/scene/resources/physics_material.cpp
+++ b/scene/resources/physics_material.cpp
@@ -43,9 +43,9 @@ void PhysicsMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_absorbent", "absorbent"), &PhysicsMaterial::set_absorbent);
ClassDB::bind_method(D_METHOD("is_absorbent"), &PhysicsMaterial::is_absorbent);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_friction", "get_friction");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rough"), "set_rough", "is_rough");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_bounce", "get_bounce");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "absorbent"), "set_absorbent", "is_absorbent");
}
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 1be511e8f1..a745df522b 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -1133,7 +1133,7 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
Vector3 normal_left, normal_right;
normal_left = Vector3(-size.y, size.x * left_to_right, 0.0);
- normal_right = Vector3(size.y, size.x * left_to_right, 0.0);
+ normal_right = Vector3(size.y, size.x * (1.0 - left_to_right), 0.0);
normal_left.normalize();
normal_right.normalize();
@@ -1538,3 +1538,552 @@ void PointMesh::_create_mesh_array(Array &p_arr) const {
PointMesh::PointMesh() {
primitive_type = PRIMITIVE_POINTS;
}
+// TUBE TRAIL
+
+void TubeTrailMesh::set_radius(const float p_radius) {
+ radius = p_radius;
+ _request_update();
+}
+float TubeTrailMesh::get_radius() const {
+ return radius;
+}
+
+void TubeTrailMesh::set_radial_steps(const int p_radial_steps) {
+ ERR_FAIL_COND(p_radial_steps < 3 || p_radial_steps > 128);
+ radial_steps = p_radial_steps;
+ _request_update();
+}
+int TubeTrailMesh::get_radial_steps() const {
+ return radial_steps;
+}
+
+void TubeTrailMesh::set_sections(const int p_sections) {
+ ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
+ sections = p_sections;
+ _request_update();
+}
+int TubeTrailMesh::get_sections() const {
+ return sections;
+}
+
+void TubeTrailMesh::set_section_length(float p_section_length) {
+ section_length = p_section_length;
+ _request_update();
+}
+float TubeTrailMesh::get_section_length() const {
+ return section_length;
+}
+
+void TubeTrailMesh::set_section_rings(const int p_section_rings) {
+ ERR_FAIL_COND(p_section_rings < 1 || p_section_rings > 1024);
+ section_rings = p_section_rings;
+ _request_update();
+}
+int TubeTrailMesh::get_section_rings() const {
+ return section_rings;
+}
+
+void TubeTrailMesh::set_curve(const Ref<Curve> &p_curve) {
+ if (curve == p_curve) {
+ return;
+ }
+ if (curve.is_valid()) {
+ curve->disconnect("changed", callable_mp(this, &TubeTrailMesh::_curve_changed));
+ }
+ curve = p_curve;
+ if (curve.is_valid()) {
+ curve->connect("changed", callable_mp(this, &TubeTrailMesh::_curve_changed));
+ }
+ _request_update();
+}
+Ref<Curve> TubeTrailMesh::get_curve() const {
+ return curve;
+}
+
+void TubeTrailMesh::_curve_changed() {
+ _request_update();
+}
+int TubeTrailMesh::get_builtin_bind_pose_count() const {
+ return sections + 1;
+}
+
+Transform3D TubeTrailMesh::get_builtin_bind_pose(int p_index) const {
+ float depth = section_length * sections;
+
+ Transform3D xform;
+ xform.origin.y = depth / 2.0 - section_length * float(p_index);
+ xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y
+
+ return xform;
+}
+
+void TubeTrailMesh::_create_mesh_array(Array &p_arr) const {
+ PackedVector3Array points;
+ PackedVector3Array normals;
+ PackedFloat32Array tangents;
+ PackedVector2Array uvs;
+ PackedInt32Array bone_indices;
+ PackedFloat32Array bone_weights;
+ PackedInt32Array indices;
+
+ int point = 0;
+
+#define ADD_TANGENT(m_x, m_y, m_z, m_d) \
+ tangents.push_back(m_x); \
+ tangents.push_back(m_y); \
+ tangents.push_back(m_z); \
+ tangents.push_back(m_d);
+
+ int thisrow = 0;
+ int prevrow = 0;
+
+ int total_rings = section_rings * sections;
+ float depth = section_length * sections;
+
+ for (int j = 0; j <= total_rings; j++) {
+ float v = j;
+ v /= total_rings;
+
+ float y = depth * v;
+ y = (depth * 0.5) - y;
+
+ int bone = j / section_rings;
+ float blend = 1.0 - float(j % section_rings) / float(section_rings);
+
+ for (int i = 0; i <= radial_steps; i++) {
+ float u = i;
+ u /= radial_steps;
+
+ float r = radius;
+ if (curve.is_valid() && curve->get_point_count() > 0) {
+ r *= curve->interpolate_baked(v);
+ }
+ float x = sin(u * Math_TAU);
+ float z = cos(u * Math_TAU);
+
+ Vector3 p = Vector3(x * r, y, z * r);
+ points.push_back(p);
+ normals.push_back(Vector3(x, 0, z));
+ ADD_TANGENT(z, 0.0, -x, 1.0)
+ uvs.push_back(Vector2(u, v * 0.5));
+ point++;
+ {
+ bone_indices.push_back(bone);
+ bone_indices.push_back(MIN(sections, bone + 1));
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(blend);
+ bone_weights.push_back(1.0 - blend);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ }
+
+ if (i > 0 && j > 0) {
+ indices.push_back(prevrow + i - 1);
+ indices.push_back(prevrow + i);
+ indices.push_back(thisrow + i - 1);
+
+ indices.push_back(prevrow + i);
+ indices.push_back(thisrow + i);
+ indices.push_back(thisrow + i - 1);
+ }
+ }
+
+ prevrow = thisrow;
+ thisrow = point;
+ }
+
+ // add top
+ float scale_pos = 1.0;
+ if (curve.is_valid() && curve->get_point_count() > 0) {
+ scale_pos = curve->interpolate_baked(0);
+ }
+
+ if (scale_pos > CMP_EPSILON) {
+ float y = depth * 0.5;
+
+ thisrow = point;
+ points.push_back(Vector3(0.0, y, 0));
+ normals.push_back(Vector3(0.0, 1.0, 0.0));
+ ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
+ uvs.push_back(Vector2(0.25, 0.75));
+ point++;
+
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(1.0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+
+ float rm = radius * scale_pos;
+
+ for (int i = 0; i <= radial_steps; i++) {
+ float r = i;
+ r /= radial_steps;
+
+ float x = sin(r * Math_TAU);
+ float z = cos(r * Math_TAU);
+
+ float u = ((x + 1.0) * 0.25);
+ float v = 0.5 + ((z + 1.0) * 0.25);
+
+ Vector3 p = Vector3(x * rm, y, z * rm);
+ points.push_back(p);
+ normals.push_back(Vector3(0.0, 1.0, 0.0));
+ ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
+ uvs.push_back(Vector2(u, v));
+ point++;
+
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(1.0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+
+ if (i > 0) {
+ indices.push_back(thisrow);
+ indices.push_back(point - 1);
+ indices.push_back(point - 2);
+ };
+ };
+ };
+
+ float scale_neg = 1.0;
+ if (curve.is_valid() && curve->get_point_count() > 0) {
+ scale_neg = curve->interpolate_baked(1.0);
+ }
+
+ // add bottom
+ if (scale_neg > CMP_EPSILON) {
+ float y = depth * -0.5;
+
+ thisrow = point;
+ points.push_back(Vector3(0.0, y, 0.0));
+ normals.push_back(Vector3(0.0, -1.0, 0.0));
+ ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
+ uvs.push_back(Vector2(0.75, 0.75));
+ point++;
+
+ bone_indices.push_back(sections);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(1.0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+
+ float rm = radius * scale_neg;
+
+ for (int i = 0; i <= radial_steps; i++) {
+ float r = i;
+ r /= radial_steps;
+
+ float x = sin(r * Math_TAU);
+ float z = cos(r * Math_TAU);
+
+ float u = 0.5 + ((x + 1.0) * 0.25);
+ float v = 1.0 - ((z + 1.0) * 0.25);
+
+ Vector3 p = Vector3(x * rm, y, z * rm);
+ points.push_back(p);
+ normals.push_back(Vector3(0.0, -1.0, 0.0));
+ ADD_TANGENT(1.0, 0.0, 0.0, 1.0)
+ uvs.push_back(Vector2(u, v));
+ point++;
+
+ bone_indices.push_back(sections);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(1.0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+
+ if (i > 0) {
+ indices.push_back(thisrow);
+ indices.push_back(point - 2);
+ indices.push_back(point - 1);
+ };
+ };
+ };
+
+ p_arr[RS::ARRAY_VERTEX] = points;
+ p_arr[RS::ARRAY_NORMAL] = normals;
+ p_arr[RS::ARRAY_TANGENT] = tangents;
+ p_arr[RS::ARRAY_TEX_UV] = uvs;
+ p_arr[RS::ARRAY_BONES] = bone_indices;
+ p_arr[RS::ARRAY_WEIGHTS] = bone_weights;
+ p_arr[RS::ARRAY_INDEX] = indices;
+}
+
+void TubeTrailMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &TubeTrailMesh::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &TubeTrailMesh::get_radius);
+
+ ClassDB::bind_method(D_METHOD("set_radial_steps", "radial_steps"), &TubeTrailMesh::set_radial_steps);
+ ClassDB::bind_method(D_METHOD("get_radial_steps"), &TubeTrailMesh::get_radial_steps);
+
+ ClassDB::bind_method(D_METHOD("set_sections", "sections"), &TubeTrailMesh::set_sections);
+ ClassDB::bind_method(D_METHOD("get_sections"), &TubeTrailMesh::get_sections);
+
+ ClassDB::bind_method(D_METHOD("set_section_length", "section_length"), &TubeTrailMesh::set_section_length);
+ ClassDB::bind_method(D_METHOD("get_section_length"), &TubeTrailMesh::get_section_length);
+
+ ClassDB::bind_method(D_METHOD("set_section_rings", "section_rings"), &TubeTrailMesh::set_section_rings);
+ ClassDB::bind_method(D_METHOD("get_section_rings"), &TubeTrailMesh::get_section_rings);
+
+ ClassDB::bind_method(D_METHOD("set_curve", "curve"), &TubeTrailMesh::set_curve);
+ ClassDB::bind_method(D_METHOD("get_curve"), &TubeTrailMesh::get_curve);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_steps", PROPERTY_HINT_RANGE, "3,128,1"), "set_radial_steps", "get_radial_steps");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_sections", "get_sections");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater"), "set_section_length", "get_section_length");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "section_rings", PROPERTY_HINT_RANGE, "1,128,1"), "set_section_rings", "get_section_rings");
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
+}
+
+TubeTrailMesh::TubeTrailMesh() {
+}
+
+// TUBE TRAIL
+
+void RibbonTrailMesh::set_shape(Shape p_shape) {
+ shape = p_shape;
+ _request_update();
+}
+RibbonTrailMesh::Shape RibbonTrailMesh::get_shape() const {
+ return shape;
+}
+
+void RibbonTrailMesh::set_size(const float p_size) {
+ size = p_size;
+ _request_update();
+}
+float RibbonTrailMesh::get_size() const {
+ return size;
+}
+
+void RibbonTrailMesh::set_sections(const int p_sections) {
+ ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
+ sections = p_sections;
+ _request_update();
+}
+int RibbonTrailMesh::get_sections() const {
+ return sections;
+}
+
+void RibbonTrailMesh::set_section_length(float p_section_length) {
+ section_length = p_section_length;
+ _request_update();
+}
+float RibbonTrailMesh::get_section_length() const {
+ return section_length;
+}
+
+void RibbonTrailMesh::set_section_segments(const int p_section_segments) {
+ ERR_FAIL_COND(p_section_segments < 1 || p_section_segments > 1024);
+ section_segments = p_section_segments;
+ _request_update();
+}
+int RibbonTrailMesh::get_section_segments() const {
+ return section_segments;
+}
+
+void RibbonTrailMesh::set_curve(const Ref<Curve> &p_curve) {
+ if (curve == p_curve) {
+ return;
+ }
+ if (curve.is_valid()) {
+ curve->disconnect("changed", callable_mp(this, &RibbonTrailMesh::_curve_changed));
+ }
+ curve = p_curve;
+ if (curve.is_valid()) {
+ curve->connect("changed", callable_mp(this, &RibbonTrailMesh::_curve_changed));
+ }
+ _request_update();
+}
+Ref<Curve> RibbonTrailMesh::get_curve() const {
+ return curve;
+}
+
+void RibbonTrailMesh::_curve_changed() {
+ _request_update();
+}
+int RibbonTrailMesh::get_builtin_bind_pose_count() const {
+ return sections + 1;
+}
+
+Transform3D RibbonTrailMesh::get_builtin_bind_pose(int p_index) const {
+ float depth = section_length * sections;
+
+ Transform3D xform;
+ xform.origin.y = depth / 2.0 - section_length * float(p_index);
+ xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y
+
+ return xform;
+}
+
+void RibbonTrailMesh::_create_mesh_array(Array &p_arr) const {
+ PackedVector3Array points;
+ PackedVector3Array normals;
+ PackedFloat32Array tangents;
+ PackedVector2Array uvs;
+ PackedInt32Array bone_indices;
+ PackedFloat32Array bone_weights;
+ PackedInt32Array indices;
+
+#define ADD_TANGENT(m_x, m_y, m_z, m_d) \
+ tangents.push_back(m_x); \
+ tangents.push_back(m_y); \
+ tangents.push_back(m_z); \
+ tangents.push_back(m_d);
+
+ int total_segments = section_segments * sections;
+ float depth = section_length * sections;
+
+ for (int j = 0; j <= total_segments; j++) {
+ float v = j;
+ v /= total_segments;
+
+ float y = depth * v;
+ y = (depth * 0.5) - y;
+
+ int bone = j / section_segments;
+ float blend = 1.0 - float(j % section_segments) / float(section_segments);
+
+ float s = size;
+
+ if (curve.is_valid() && curve->get_point_count() > 0) {
+ s *= curve->interpolate_baked(v);
+ }
+
+ points.push_back(Vector3(-s * 0.5, y, 0));
+ points.push_back(Vector3(+s * 0.5, y, 0));
+ if (shape == SHAPE_CROSS) {
+ points.push_back(Vector3(0, y, -s * 0.5));
+ points.push_back(Vector3(0, y, +s * 0.5));
+ }
+
+ normals.push_back(Vector3(0, 0, 1));
+ normals.push_back(Vector3(0, 0, 1));
+ if (shape == SHAPE_CROSS) {
+ normals.push_back(Vector3(1, 0, 0));
+ normals.push_back(Vector3(1, 0, 0));
+ }
+
+ uvs.push_back(Vector2(0, v));
+ uvs.push_back(Vector2(1, v));
+ if (shape == SHAPE_CROSS) {
+ uvs.push_back(Vector2(0, v));
+ uvs.push_back(Vector2(1, v));
+ }
+
+ ADD_TANGENT(0.0, 1.0, 0.0, 1.0)
+ ADD_TANGENT(0.0, 1.0, 0.0, 1.0)
+ if (shape == SHAPE_CROSS) {
+ ADD_TANGENT(0.0, 1.0, 0.0, 1.0)
+ ADD_TANGENT(0.0, 1.0, 0.0, 1.0)
+ }
+
+ for (int i = 0; i < (shape == SHAPE_CROSS ? 4 : 2); i++) {
+ bone_indices.push_back(bone);
+ bone_indices.push_back(MIN(sections, bone + 1));
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(blend);
+ bone_weights.push_back(1.0 - blend);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ }
+
+ if (j > 0) {
+ if (shape == SHAPE_CROSS) {
+ int base = j * 4 - 4;
+ indices.push_back(base + 0);
+ indices.push_back(base + 1);
+ indices.push_back(base + 4);
+
+ indices.push_back(base + 1);
+ indices.push_back(base + 5);
+ indices.push_back(base + 4);
+
+ indices.push_back(base + 2);
+ indices.push_back(base + 3);
+ indices.push_back(base + 6);
+
+ indices.push_back(base + 3);
+ indices.push_back(base + 7);
+ indices.push_back(base + 6);
+ } else {
+ int base = j * 2 - 2;
+ indices.push_back(base + 0);
+ indices.push_back(base + 1);
+ indices.push_back(base + 2);
+
+ indices.push_back(base + 1);
+ indices.push_back(base + 3);
+ indices.push_back(base + 2);
+ }
+ }
+ }
+
+ p_arr[RS::ARRAY_VERTEX] = points;
+ p_arr[RS::ARRAY_NORMAL] = normals;
+ p_arr[RS::ARRAY_TANGENT] = tangents;
+ p_arr[RS::ARRAY_TEX_UV] = uvs;
+ p_arr[RS::ARRAY_BONES] = bone_indices;
+ p_arr[RS::ARRAY_WEIGHTS] = bone_weights;
+ p_arr[RS::ARRAY_INDEX] = indices;
+}
+
+void RibbonTrailMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &RibbonTrailMesh::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &RibbonTrailMesh::get_size);
+
+ ClassDB::bind_method(D_METHOD("set_sections", "sections"), &RibbonTrailMesh::set_sections);
+ ClassDB::bind_method(D_METHOD("get_sections"), &RibbonTrailMesh::get_sections);
+
+ ClassDB::bind_method(D_METHOD("set_section_length", "section_length"), &RibbonTrailMesh::set_section_length);
+ ClassDB::bind_method(D_METHOD("get_section_length"), &RibbonTrailMesh::get_section_length);
+
+ ClassDB::bind_method(D_METHOD("set_section_segments", "section_segments"), &RibbonTrailMesh::set_section_segments);
+ ClassDB::bind_method(D_METHOD("get_section_segments"), &RibbonTrailMesh::get_section_segments);
+
+ ClassDB::bind_method(D_METHOD("set_curve", "curve"), &RibbonTrailMesh::set_curve);
+ ClassDB::bind_method(D_METHOD("get_curve"), &RibbonTrailMesh::get_curve);
+
+ ClassDB::bind_method(D_METHOD("set_shape", "shape"), &RibbonTrailMesh::set_shape);
+ ClassDB::bind_method(D_METHOD("get_shape"), &RibbonTrailMesh::get_shape);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Flat,Cross"), "set_shape", "get_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_sections", "get_sections");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "section_length", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001,or_greater"), "set_section_length", "get_section_length");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "section_segments", PROPERTY_HINT_RANGE, "1,128,1"), "set_section_segments", "get_section_segments");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
+
+ BIND_ENUM_CONSTANT(SHAPE_FLAT)
+ BIND_ENUM_CONSTANT(SHAPE_CROSS)
+}
+
+RibbonTrailMesh::RibbonTrailMesh() {
+}
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 65ecdfc19d..bd6f94921e 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -336,4 +336,98 @@ public:
PointMesh();
};
+class TubeTrailMesh : public PrimitiveMesh {
+ GDCLASS(TubeTrailMesh, PrimitiveMesh);
+
+private:
+ float radius = 1.0;
+ int radial_steps = 8;
+ int sections = 5;
+ float section_length = 0.2;
+ int section_rings = 3;
+
+ Ref<Curve> curve;
+
+ void _curve_changed();
+
+protected:
+ static void _bind_methods();
+ virtual void _create_mesh_array(Array &p_arr) const override;
+
+public:
+ void set_radius(const float p_radius);
+ float get_radius() const;
+
+ void set_radial_steps(const int p_radial_steps);
+ int get_radial_steps() const;
+
+ void set_sections(const int p_sections);
+ int get_sections() const;
+
+ void set_section_length(float p_sectionlength);
+ float get_section_length() const;
+
+ void set_section_rings(const int p_section_rings);
+ int get_section_rings() const;
+
+ void set_curve(const Ref<Curve> &p_curve);
+ Ref<Curve> get_curve() const;
+
+ virtual int get_builtin_bind_pose_count() const override;
+ virtual Transform3D get_builtin_bind_pose(int p_index) const override;
+
+ TubeTrailMesh();
+};
+
+class RibbonTrailMesh : public PrimitiveMesh {
+ GDCLASS(RibbonTrailMesh, PrimitiveMesh);
+
+public:
+ enum Shape {
+ SHAPE_FLAT,
+ SHAPE_CROSS
+ };
+
+private:
+ float size = 1.0;
+ int sections = 5;
+ float section_length = 0.2;
+ int section_segments = 3;
+
+ Shape shape = SHAPE_CROSS;
+
+ Ref<Curve> curve;
+
+ void _curve_changed();
+
+protected:
+ static void _bind_methods();
+ virtual void _create_mesh_array(Array &p_arr) const override;
+
+public:
+ void set_shape(Shape p_shape);
+ Shape get_shape() const;
+
+ void set_size(const float p_size);
+ float get_size() const;
+
+ void set_sections(const int p_sections);
+ int get_sections() const;
+
+ void set_section_length(float p_sectionlength);
+ float get_section_length() const;
+
+ void set_section_segments(const int p_section_segments);
+ int get_section_segments() const;
+
+ void set_curve(const Ref<Curve> &p_curve);
+ Ref<Curve> get_curve() const;
+
+ virtual int get_builtin_bind_pose_count() const override;
+ virtual Transform3D get_builtin_bind_pose(int p_index) const override;
+
+ RibbonTrailMesh();
+};
+
+VARIANT_ENUM_CAST(RibbonTrailMesh::Shape)
#endif
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index f2751b7604..27f0c50a79 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -31,14 +31,14 @@
#include "resource_format_text.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
#include "core/io/resource_format_binary.h"
-#include "core/os/dir_access.h"
#include "core/version.h"
//version 2: changed names for basis, aabb, Vectors, etc.
#define FORMAT_VERSION 2
-#include "core/os/dir_access.h"
+#include "core/io/dir_access.h"
#include "core/version.h"
#define _printerr() ERR_PRINT(String(res_path + ":" + itos(lines) + " - Parse Error: " + error_text).utf8().get_data());
@@ -575,6 +575,7 @@ Error ResourceLoaderText::load() {
int_resources[id] = res; //always assign int resources
if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE);
+ res->set_subindex(id);
}
if (progress && resources_total > 0) {
@@ -978,7 +979,7 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path)
}
wf->store_32(0); //string table size, will not be in use
- size_t ext_res_count_pos = wf->get_position();
+ uint64_t ext_res_count_pos = wf->get_position();
wf->store_32(0); //zero ext resources, still parsing them
@@ -1041,7 +1042,7 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path)
//now, save resources to a separate file, for now
- size_t sub_res_count_pos = wf->get_position();
+ uint64_t sub_res_count_pos = wf->get_position();
wf->store_32(0); //zero sub resources, still parsing them
String temp_file = p_path + ".temp";
@@ -1050,8 +1051,8 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path)
return ERR_CANT_OPEN;
}
- Vector<size_t> local_offsets;
- Vector<size_t> local_pointers_pos;
+ Vector<uint64_t> local_offsets;
+ Vector<uint64_t> local_pointers_pos;
while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
String type;
@@ -1089,7 +1090,7 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path)
wf->store_64(0); //temp local offset
bs_save_unicode_string(wf2, type);
- size_t propcount_ofs = wf2->get_position();
+ uint64_t propcount_ofs = wf2->get_position();
wf2->store_32(0);
int prop_count = 0;
@@ -1159,7 +1160,7 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path)
local_offsets.push_back(wf2->get_position());
bs_save_unicode_string(wf2, "PackedScene");
- size_t propcount_ofs = wf2->get_position();
+ uint64_t propcount_ofs = wf2->get_position();
wf2->store_32(0);
int prop_count = 0;
@@ -1185,7 +1186,7 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path)
wf2->close();
- size_t offset_from = wf->get_position();
+ uint64_t offset_from = wf->get_position();
wf->seek(sub_res_count_pos); //plus one because the saved one
wf->store_32(local_offsets.size());
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index 2dc683415d..f5d9cca859 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -31,9 +31,9 @@
#ifndef RESOURCE_FORMAT_TEXT_H
#define RESOURCE_FORMAT_TEXT_H
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
#include "core/variant/variant_parser.h"
#include "scene/resources/packed_scene.h"
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 77c6199794..cbd44315b7 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -30,7 +30,7 @@
#include "shader.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "scene/scene_string_names.h"
#include "servers/rendering/shader_language.h"
#include "servers/rendering_server.h"
@@ -184,7 +184,7 @@ RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_origi
}
void ResourceFormatLoaderShader::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("shader");
+ p_extensions->push_back("gdshader");
}
bool ResourceFormatLoaderShader::handles_type(const String &p_type) const {
@@ -193,7 +193,7 @@ bool ResourceFormatLoaderShader::handles_type(const String &p_type) const {
String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const {
String el = p_path.get_extension().to_lower();
- if (el == "shader") {
+ if (el == "gdshader") {
return "Shader";
}
return "";
@@ -224,7 +224,7 @@ Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resourc
void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
if (const Shader *shader = Object::cast_to<Shader>(*p_resource)) {
if (shader->is_text_shader()) {
- p_extensions->push_back("shader");
+ p_extensions->push_back("gdshader");
}
}
}
diff --git a/scene/resources/shape_3d.cpp b/scene/resources/shape_3d.cpp
index 5761a405ce..a02a0e5488 100644
--- a/scene/resources/shape_3d.cpp
+++ b/scene/resources/shape_3d.cpp
@@ -35,7 +35,7 @@
#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
-void Shape3D::add_vertices_to_array(Vector<Vector3> &array, const Transform &p_xform) {
+void Shape3D::add_vertices_to_array(Vector<Vector3> &array, const Transform3D &p_xform) {
Vector<Vector3> toadd = get_debug_mesh_lines();
if (toadd.size()) {
@@ -102,6 +102,8 @@ 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);
+ ClassDB::bind_method(D_METHOD("get_debug_mesh"), &Shape3D::get_debug_mesh);
+
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
}
diff --git a/scene/resources/shape_3d.h b/scene/resources/shape_3d.h
index 0644940fd4..b8e529cd3c 100644
--- a/scene/resources/shape_3d.h
+++ b/scene/resources/shape_3d.h
@@ -60,7 +60,7 @@ public:
/// 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);
+ void add_vertices_to_array(Vector<Vector3> &array, const Transform3D &p_xform);
real_t get_margin() const;
void set_margin(real_t p_margin);
diff --git a/scene/resources/skeleton_modification_2d.cpp b/scene/resources/skeleton_modification_2d.cpp
new file mode 100644
index 0000000000..b52a60006a
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d.cpp
@@ -0,0 +1,253 @@
+/*************************************************************************/
+/* skeleton_modification_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_modification_2d.h"
+#include "scene/2d/skeleton_2d.h"
+
+#include "scene/2d/collision_object_2d.h"
+#include "scene/2d/collision_shape_2d.h"
+#include "scene/2d/physical_bone_2d.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif // TOOLS_ENABLED
+
+///////////////////////////////////////
+// Modification2D
+///////////////////////////////////////
+
+void SkeletonModification2D::_execute(float p_delta) {
+ call("_execute", p_delta);
+
+ if (!enabled) {
+ return;
+ }
+}
+
+void SkeletonModification2D::_setup_modification(SkeletonModificationStack2D *p_stack) {
+ stack = p_stack;
+ if (stack) {
+ is_setup = true;
+ } else {
+ WARN_PRINT("Could not setup modification with name " + get_name());
+ }
+
+ call("_setup_modification", p_stack);
+}
+
+void SkeletonModification2D::_draw_editor_gizmo() {
+ call("_draw_editor_gizmo");
+}
+
+void SkeletonModification2D::set_enabled(bool p_enabled) {
+ enabled = p_enabled;
+
+#ifdef TOOLS_ENABLED
+ if (editor_draw_gizmo) {
+ if (stack) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+ }
+#endif // TOOLS_ENABLED
+}
+
+bool SkeletonModification2D::get_enabled() {
+ return enabled;
+}
+
+float SkeletonModification2D::clamp_angle(float p_angle, float p_min_bound, float p_max_bound, bool p_invert) {
+ // Map to the 0 to 360 range (in radians though) instead of the -180 to 180 range.
+ if (p_angle < 0) {
+ p_angle = Math_TAU + p_angle;
+ }
+
+ // Make min and max in the range of 0 to 360 (in radians), and make sure they are in the right order
+ if (p_min_bound < 0) {
+ p_min_bound = Math_TAU + p_min_bound;
+ }
+ if (p_max_bound < 0) {
+ p_max_bound = Math_TAU + p_max_bound;
+ }
+ if (p_min_bound > p_max_bound) {
+ float tmp = p_min_bound;
+ p_min_bound = p_max_bound;
+ p_max_bound = tmp;
+ }
+
+ // Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle.
+ if (p_invert == false) {
+ if (p_angle < p_min_bound || p_angle > p_max_bound) {
+ Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
+ Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
+ Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
+
+ if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
+ p_angle = p_min_bound;
+ } else {
+ p_angle = p_max_bound;
+ }
+ }
+ } else {
+ if (p_angle > p_min_bound && p_angle < p_max_bound) {
+ Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
+ Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
+ Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
+
+ if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
+ p_angle = p_min_bound;
+ } else {
+ p_angle = p_max_bound;
+ }
+ }
+ }
+ return p_angle;
+}
+
+void SkeletonModification2D::editor_draw_angle_constraints(Bone2D *p_operation_bone, float p_min_bound, float p_max_bound,
+ bool p_constraint_enabled, bool p_constraint_in_localspace, bool p_constraint_inverted) {
+ if (!p_operation_bone) {
+ return;
+ }
+
+ Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4);
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
+ }
+#endif // TOOLS_ENABLED
+
+ float arc_angle_min = p_min_bound;
+ float arc_angle_max = p_max_bound;
+ if (arc_angle_min < 0) {
+ arc_angle_min = (Math_PI * 2) + arc_angle_min;
+ }
+ if (arc_angle_max < 0) {
+ arc_angle_max = (Math_PI * 2) + arc_angle_max;
+ }
+ if (arc_angle_min > arc_angle_max) {
+ float tmp = arc_angle_min;
+ arc_angle_min = arc_angle_max;
+ arc_angle_max = tmp;
+ }
+ arc_angle_min += p_operation_bone->get_bone_angle();
+ arc_angle_max += p_operation_bone->get_bone_angle();
+
+ if (p_constraint_enabled) {
+ if (p_constraint_in_localspace) {
+ Node *operation_bone_parent = p_operation_bone->get_parent();
+ Bone2D *operation_bone_parent_bone = Object::cast_to<Bone2D>(operation_bone_parent);
+
+ if (operation_bone_parent_bone) {
+ stack->skeleton->draw_set_transform(
+ stack->skeleton->get_global_transform().affine_inverse().xform(p_operation_bone->get_global_position()),
+ operation_bone_parent_bone->get_global_rotation() - stack->skeleton->get_global_rotation());
+ } else {
+ stack->skeleton->draw_set_transform(stack->skeleton->get_global_transform().affine_inverse().xform(p_operation_bone->get_global_position()));
+ }
+ } else {
+ stack->skeleton->draw_set_transform(stack->skeleton->get_global_transform().affine_inverse().xform(p_operation_bone->get_global_position()));
+ }
+
+ if (p_constraint_inverted) {
+ stack->skeleton->draw_arc(Vector2(0, 0), p_operation_bone->get_length(),
+ arc_angle_min + (Math_PI * 2), arc_angle_max, 32, bone_ik_color, 1.0);
+ } else {
+ stack->skeleton->draw_arc(Vector2(0, 0), p_operation_bone->get_length(),
+ arc_angle_min, arc_angle_max, 32, bone_ik_color, 1.0);
+ }
+ stack->skeleton->draw_line(Vector2(0, 0), Vector2(Math::cos(arc_angle_min), Math::sin(arc_angle_min)) * p_operation_bone->get_length(), bone_ik_color, 1.0);
+ stack->skeleton->draw_line(Vector2(0, 0), Vector2(Math::cos(arc_angle_max), Math::sin(arc_angle_max)) * p_operation_bone->get_length(), bone_ik_color, 1.0);
+
+ } else {
+ stack->skeleton->draw_set_transform(stack->skeleton->get_global_transform().affine_inverse().xform(p_operation_bone->get_global_position()));
+ stack->skeleton->draw_arc(Vector2(0, 0), p_operation_bone->get_length(), 0, Math_PI * 2, 32, bone_ik_color, 1.0);
+ stack->skeleton->draw_line(Vector2(0, 0), Vector2(1, 0) * p_operation_bone->get_length(), bone_ik_color, 1.0);
+ }
+}
+
+Ref<SkeletonModificationStack2D> SkeletonModification2D::get_modification_stack() {
+ return stack;
+}
+
+void SkeletonModification2D::set_is_setup(bool p_setup) {
+ is_setup = p_setup;
+}
+
+bool SkeletonModification2D::get_is_setup() const {
+ return is_setup;
+}
+
+void SkeletonModification2D::set_execution_mode(int p_mode) {
+ execution_mode = p_mode;
+}
+
+int SkeletonModification2D::get_execution_mode() const {
+ return execution_mode;
+}
+
+void SkeletonModification2D::set_editor_draw_gizmo(bool p_draw_gizmo) {
+ editor_draw_gizmo = p_draw_gizmo;
+#ifdef TOOLS_ENABLED
+ if (is_setup) {
+ if (stack) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+ }
+#endif // TOOLS_ENABLED
+}
+
+bool SkeletonModification2D::get_editor_draw_gizmo() const {
+ return editor_draw_gizmo;
+}
+
+void SkeletonModification2D::_bind_methods() {
+ BIND_VMETHOD(MethodInfo("_execute", PropertyInfo(Variant::FLOAT, "delta")));
+ BIND_VMETHOD(MethodInfo("_setup_modification", PropertyInfo(Variant::OBJECT, "modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack2D")));
+ BIND_VMETHOD(MethodInfo("_draw_editor_gizmo"));
+
+ ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModification2D::set_enabled);
+ ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModification2D::get_enabled);
+ ClassDB::bind_method(D_METHOD("get_modification_stack"), &SkeletonModification2D::get_modification_stack);
+ ClassDB::bind_method(D_METHOD("set_is_setup", "is_setup"), &SkeletonModification2D::set_is_setup);
+ ClassDB::bind_method(D_METHOD("get_is_setup"), &SkeletonModification2D::get_is_setup);
+ ClassDB::bind_method(D_METHOD("set_execution_mode", "execution_mode"), &SkeletonModification2D::set_execution_mode);
+ ClassDB::bind_method(D_METHOD("get_execution_mode"), &SkeletonModification2D::get_execution_mode);
+ ClassDB::bind_method(D_METHOD("clamp_angle", "angle", "min", "max", "invert"), &SkeletonModification2D::clamp_angle);
+ ClassDB::bind_method(D_METHOD("set_editor_draw_gizmo", "draw_gizmo"), &SkeletonModification2D::set_editor_draw_gizmo);
+ ClassDB::bind_method(D_METHOD("get_editor_draw_gizmo"), &SkeletonModification2D::get_editor_draw_gizmo);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process, physics_process"), "set_execution_mode", "get_execution_mode");
+}
+
+SkeletonModification2D::SkeletonModification2D() {
+ stack = nullptr;
+ is_setup = false;
+}
diff --git a/scene/resources/skeleton_modification_2d.h b/scene/resources/skeleton_modification_2d.h
new file mode 100644
index 0000000000..18633e55cb
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d.h
@@ -0,0 +1,85 @@
+/*************************************************************************/
+/* skeleton_modification_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETONMODIFICATION2D_H
+#define SKELETONMODIFICATION2D_H
+
+#include "scene/2d/skeleton_2d.h"
+#include "scene/resources/skeleton_modification_stack_2d.h"
+
+///////////////////////////////////////
+// SkeletonModification2D
+///////////////////////////////////////
+
+class SkeletonModificationStack2D;
+class Bone2D;
+
+class SkeletonModification2D : public Resource {
+ GDCLASS(SkeletonModification2D, Resource);
+ friend class Skeleton2D;
+ friend class Bone2D;
+
+protected:
+ static void _bind_methods();
+
+ SkeletonModificationStack2D *stack;
+ int execution_mode = 0; // 0 = process
+
+ bool enabled = true;
+ bool is_setup = false;
+
+ bool _print_execution_error(bool p_condition, String p_message);
+
+public:
+ virtual void _execute(float _delta);
+ virtual void _setup_modification(SkeletonModificationStack2D *p_stack);
+ virtual void _draw_editor_gizmo();
+
+ bool editor_draw_gizmo = false;
+ void set_editor_draw_gizmo(bool p_draw_gizmo);
+ bool get_editor_draw_gizmo() const;
+
+ void set_enabled(bool p_enabled);
+ bool get_enabled();
+
+ Ref<SkeletonModificationStack2D> get_modification_stack();
+ void set_is_setup(bool p_setup);
+ bool get_is_setup() const;
+
+ void set_execution_mode(int p_mode);
+ int get_execution_mode() const;
+
+ float clamp_angle(float p_angle, float p_min_bound, float p_max_bound, bool p_invert_clamp = false);
+ void editor_draw_angle_constraints(Bone2D *p_operation_bone, float p_min_bound, float p_max_bound, bool p_constraint_enabled, bool p_constraint_in_localspace, bool p_constraint_inverted);
+
+ SkeletonModification2D();
+};
+
+#endif // SKELETONMODIFICATION2D_H
diff --git a/scene/resources/skeleton_modification_2d_ccdik.cpp b/scene/resources/skeleton_modification_2d_ccdik.cpp
new file mode 100644
index 0000000000..7ea60e584e
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_ccdik.cpp
@@ -0,0 +1,545 @@
+/*************************************************************************/
+/* skeleton_modification_2d_ccdik.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_modification_2d_ccdik.h"
+#include "scene/2d/skeleton_2d.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif // TOOLS_ENABLED
+
+bool SkeletonModification2DCCDIK::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+ if (path.begins_with("joint_data/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, ccdik_data_chain.size(), false);
+
+ if (what == "bone2d_node") {
+ set_ccdik_joint_bone2d_node(which, p_value);
+ } else if (what == "bone_index") {
+ set_ccdik_joint_bone_index(which, p_value);
+ } else if (what == "rotate_from_joint") {
+ set_ccdik_joint_rotate_from_joint(which, p_value);
+ } else if (what == "enable_constraint") {
+ set_ccdik_joint_enable_constraint(which, p_value);
+ } else if (what == "constraint_angle_min") {
+ set_ccdik_joint_constraint_angle_min(which, Math::deg2rad(float(p_value)));
+ } else if (what == "constraint_angle_max") {
+ set_ccdik_joint_constraint_angle_max(which, Math::deg2rad(float(p_value)));
+ } else if (what == "constraint_angle_invert") {
+ set_ccdik_joint_constraint_angle_invert(which, p_value);
+ } else if (what == "constraint_in_localspace") {
+ set_ccdik_joint_constraint_in_localspace(which, p_value);
+ }
+
+#ifdef TOOLS_ENABLED
+ if (what.begins_with("editor_draw_gizmo")) {
+ set_ccdik_joint_editor_draw_gizmo(which, p_value);
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+ }
+
+#ifdef TOOLS_ENABLED
+ if (path.begins_with("editor/draw_gizmo")) {
+ set_editor_draw_gizmo(p_value);
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+}
+
+bool SkeletonModification2DCCDIK::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path.begins_with("joint_data/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, ccdik_data_chain.size(), false);
+
+ if (what == "bone2d_node") {
+ r_ret = get_ccdik_joint_bone2d_node(which);
+ } else if (what == "bone_index") {
+ r_ret = get_ccdik_joint_bone_index(which);
+ } else if (what == "rotate_from_joint") {
+ r_ret = get_ccdik_joint_rotate_from_joint(which);
+ } else if (what == "enable_constraint") {
+ r_ret = get_ccdik_joint_enable_constraint(which);
+ } else if (what == "constraint_angle_min") {
+ r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_min(which));
+ } else if (what == "constraint_angle_max") {
+ r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_max(which));
+ } else if (what == "constraint_angle_invert") {
+ r_ret = get_ccdik_joint_constraint_angle_invert(which);
+ } else if (what == "constraint_in_localspace") {
+ r_ret = get_ccdik_joint_constraint_in_localspace(which);
+ }
+
+#ifdef TOOLS_ENABLED
+ if (what.begins_with("editor_draw_gizmo")) {
+ r_ret = get_ccdik_joint_editor_draw_gizmo(which);
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+ }
+
+#ifdef TOOLS_ENABLED
+ if (path.begins_with("editor/draw_gizmo")) {
+ r_ret = get_editor_draw_gizmo();
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+}
+
+void SkeletonModification2DCCDIK::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < ccdik_data_chain.size(); i++) {
+ String base_string = "joint_data/" + itos(i) + "/";
+
+ p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "rotate_from_joint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+
+ p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "enable_constraint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ if (ccdik_data_chain[i].enable_constraint) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "constraint_angle_min", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "constraint_angle_max", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "constraint_angle_invert", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "constraint_in_localspace", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "editor_draw_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+#endif // TOOLS_ENABLED
+ }
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "editor/draw_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+#endif // TOOLS_ENABLED
+}
+
+void SkeletonModification2DCCDIK::_execute(float p_delta) {
+ ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
+ "Modification is not setup and therefore cannot execute!");
+ if (!enabled) {
+ return;
+ }
+
+ if (target_node_cache.is_null()) {
+ WARN_PRINT_ONCE("Target cache is out of date. Attempting to update...");
+ update_target_cache();
+ return;
+ }
+ if (tip_node_cache.is_null()) {
+ WARN_PRINT_ONCE("Tip cache is out of date. Attempting to update...");
+ update_tip_cache();
+ return;
+ }
+
+ Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache));
+ if (!target || !target->is_inside_tree()) {
+ ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!");
+ return;
+ }
+
+ Node2D *tip = Object::cast_to<Node2D>(ObjectDB::get_instance(tip_node_cache));
+ if (!tip || !tip->is_inside_tree()) {
+ ERR_PRINT_ONCE("Tip node is not in the scene tree. Cannot execute modification!");
+ return;
+ }
+
+ for (int i = 0; i < ccdik_data_chain.size(); i++) {
+ _execute_ccdik_joint(i, target, tip);
+ }
+}
+
+void SkeletonModification2DCCDIK::_execute_ccdik_joint(int p_joint_idx, Node2D *p_target, Node2D *p_tip) {
+ CCDIK_Joint_Data2D ccdik_data = ccdik_data_chain[p_joint_idx];
+ if (ccdik_data.bone_idx < 0 || ccdik_data.bone_idx > stack->skeleton->get_bone_count()) {
+ ERR_PRINT_ONCE("2D CCDIK joint: bone index not found!");
+ return;
+ }
+
+ Bone2D *operation_bone = stack->skeleton->get_bone(ccdik_data.bone_idx);
+ Transform2D operation_transform = operation_bone->get_global_transform();
+
+ if (ccdik_data.rotate_from_joint) {
+ // To rotate from the joint, simply look at the target!
+ operation_transform.set_rotation(
+ operation_transform.looking_at(p_target->get_global_transform().get_origin()).get_rotation() - operation_bone->get_bone_angle());
+ } else {
+ // How to rotate from the tip: get the difference of rotation needed from the tip to the target, from the perspective of the joint.
+ // Because we are only using the offset, we do not need to account for the bone angle of the Bone2D node.
+ float joint_to_tip = operation_transform.get_origin().angle_to_point(p_tip->get_global_transform().get_origin());
+ float joint_to_target = operation_transform.get_origin().angle_to_point(p_target->get_global_transform().get_origin());
+ operation_transform.set_rotation(
+ operation_transform.get_rotation() + (joint_to_target - joint_to_tip));
+ }
+
+ // Reset scale
+ operation_transform.set_scale(operation_bone->get_global_transform().get_scale());
+
+ // Apply constraints in globalspace:
+ if (ccdik_data.enable_constraint && !ccdik_data.constraint_in_localspace) {
+ operation_transform.set_rotation(clamp_angle(operation_transform.get_rotation(), ccdik_data.constraint_angle_min, ccdik_data.constraint_angle_max, ccdik_data.constraint_angle_invert));
+ }
+
+ // Convert from a global transform to a delta and then apply the delta to the local transform.
+ operation_bone->set_global_transform(operation_transform);
+ operation_transform = operation_bone->get_transform();
+
+ // Apply constraints in localspace:
+ if (ccdik_data.enable_constraint && ccdik_data.constraint_in_localspace) {
+ operation_transform.set_rotation(clamp_angle(operation_transform.get_rotation(), ccdik_data.constraint_angle_min, ccdik_data.constraint_angle_max, ccdik_data.constraint_angle_invert));
+ }
+
+ // Set the local pose override, and to make sure child bones are also updated, set the transform of the bone.
+ stack->skeleton->set_bone_local_pose_override(ccdik_data.bone_idx, operation_transform, stack->strength, true);
+ operation_bone->set_transform(operation_transform);
+ operation_bone->notification(operation_bone->NOTIFICATION_TRANSFORM_CHANGED);
+}
+
+void SkeletonModification2DCCDIK::_setup_modification(SkeletonModificationStack2D *p_stack) {
+ stack = p_stack;
+
+ if (stack != nullptr) {
+ is_setup = true;
+ update_target_cache();
+ update_tip_cache();
+ }
+}
+
+void SkeletonModification2DCCDIK::_draw_editor_gizmo() {
+ if (!enabled || !is_setup) {
+ return;
+ }
+
+ for (int i = 0; i < ccdik_data_chain.size(); i++) {
+ if (!ccdik_data_chain[i].editor_draw_gizmo) {
+ continue;
+ }
+
+ Bone2D *operation_bone = stack->skeleton->get_bone(ccdik_data_chain[i].bone_idx);
+ editor_draw_angle_constraints(operation_bone, ccdik_data_chain[i].constraint_angle_min, ccdik_data_chain[i].constraint_angle_max,
+ ccdik_data_chain[i].enable_constraint, ccdik_data_chain[i].constraint_in_localspace, ccdik_data_chain[i].constraint_angle_invert);
+ }
+}
+
+void SkeletonModification2DCCDIK::update_target_cache() {
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!");
+ return;
+ }
+
+ target_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(target_node)) {
+ Node *node = stack->skeleton->get_node(target_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update target cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update target cache: node is not in the scene tree!");
+ target_node_cache = node->get_instance_id();
+ }
+ }
+ }
+}
+
+void SkeletonModification2DCCDIK::update_tip_cache() {
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update tip cache: modification is not properly setup!");
+ return;
+ }
+
+ tip_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(tip_node)) {
+ Node *node = stack->skeleton->get_node(tip_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update tip cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update tip cache: node is not in the scene tree!");
+ tip_node_cache = node->get_instance_id();
+ }
+ }
+ }
+}
+
+void SkeletonModification2DCCDIK::ccdik_joint_update_bone2d_cache(int p_joint_idx) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "Cannot update bone2d cache: joint index out of range!");
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update CCDIK Bone2D cache: modification is not properly setup!");
+ return;
+ }
+
+ ccdik_data_chain.write[p_joint_idx].bone2d_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(ccdik_data_chain[p_joint_idx].bone2d_node)) {
+ Node *node = stack->skeleton->get_node(ccdik_data_chain[p_joint_idx].bone2d_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update CCDIK joint " + itos(p_joint_idx) + " Bone2D cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update CCDIK joint " + itos(p_joint_idx) + " Bone2D cache: node is not in the scene tree!");
+ ccdik_data_chain.write[p_joint_idx].bone2d_node_cache = node->get_instance_id();
+
+ Bone2D *bone = Object::cast_to<Bone2D>(node);
+ if (bone) {
+ ccdik_data_chain.write[p_joint_idx].bone_idx = bone->get_index_in_skeleton();
+ } else {
+ ERR_FAIL_MSG("CCDIK joint " + itos(p_joint_idx) + " Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
+ }
+ }
+ }
+ }
+}
+
+void SkeletonModification2DCCDIK::set_target_node(const NodePath &p_target_node) {
+ target_node = p_target_node;
+ update_target_cache();
+}
+
+NodePath SkeletonModification2DCCDIK::get_target_node() const {
+ return target_node;
+}
+
+void SkeletonModification2DCCDIK::set_tip_node(const NodePath &p_tip_node) {
+ tip_node = p_tip_node;
+ update_tip_cache();
+}
+
+NodePath SkeletonModification2DCCDIK::get_tip_node() const {
+ return tip_node;
+}
+
+void SkeletonModification2DCCDIK::set_ccdik_data_chain_length(int p_length) {
+ ccdik_data_chain.resize(p_length);
+ notify_property_list_changed();
+}
+
+int SkeletonModification2DCCDIK::get_ccdik_data_chain_length() {
+ return ccdik_data_chain.size();
+}
+
+void SkeletonModification2DCCDIK::set_ccdik_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!");
+ ccdik_data_chain.write[p_joint_idx].bone2d_node = p_target_node;
+ ccdik_joint_update_bone2d_cache(p_joint_idx);
+
+ notify_property_list_changed();
+}
+
+NodePath SkeletonModification2DCCDIK::get_ccdik_joint_bone2d_node(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), NodePath(), "CCDIK joint out of range!");
+ return ccdik_data_chain[p_joint_idx].bone2d_node;
+}
+
+void SkeletonModification2DCCDIK::set_ccdik_joint_bone_index(int p_joint_idx, int p_bone_idx) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCCDIK joint out of range!");
+ ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
+
+ if (is_setup) {
+ if (stack->skeleton) {
+ ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!");
+ ccdik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
+ ccdik_data_chain.write[p_joint_idx].bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id();
+ ccdik_data_chain.write[p_joint_idx].bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx));
+ } else {
+ WARN_PRINT("Cannot verify the CCDIK joint " + itos(p_joint_idx) + " bone index for this modification...");
+ ccdik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
+ }
+ } else {
+ WARN_PRINT("Cannot verify the CCDIK joint " + itos(p_joint_idx) + " bone index for this modification...");
+ ccdik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
+ }
+
+ notify_property_list_changed();
+}
+
+int SkeletonModification2DCCDIK::get_ccdik_joint_bone_index(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), -1, "CCDIK joint out of range!");
+ return ccdik_data_chain[p_joint_idx].bone_idx;
+}
+
+void SkeletonModification2DCCDIK::set_ccdik_joint_rotate_from_joint(int p_joint_idx, bool p_rotate_from_joint) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!");
+ ccdik_data_chain.write[p_joint_idx].rotate_from_joint = p_rotate_from_joint;
+}
+
+bool SkeletonModification2DCCDIK::get_ccdik_joint_rotate_from_joint(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), false, "CCDIK joint out of range!");
+ return ccdik_data_chain[p_joint_idx].rotate_from_joint;
+}
+
+void SkeletonModification2DCCDIK::set_ccdik_joint_enable_constraint(int p_joint_idx, bool p_constraint) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!");
+ ccdik_data_chain.write[p_joint_idx].enable_constraint = p_constraint;
+ notify_property_list_changed();
+
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+bool SkeletonModification2DCCDIK::get_ccdik_joint_enable_constraint(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), false, "CCDIK joint out of range!");
+ return ccdik_data_chain[p_joint_idx].enable_constraint;
+}
+
+void SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_min(int p_joint_idx, float p_angle_min) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!");
+ ccdik_data_chain.write[p_joint_idx].constraint_angle_min = p_angle_min;
+
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+float SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_min(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), 0.0, "CCDIK joint out of range!");
+ return ccdik_data_chain[p_joint_idx].constraint_angle_min;
+}
+
+void SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_max(int p_joint_idx, float p_angle_max) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!");
+ ccdik_data_chain.write[p_joint_idx].constraint_angle_max = p_angle_max;
+
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+float SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_max(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), 0.0, "CCDIK joint out of range!");
+ return ccdik_data_chain[p_joint_idx].constraint_angle_max;
+}
+
+void SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_invert(int p_joint_idx, bool p_invert) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!");
+ ccdik_data_chain.write[p_joint_idx].constraint_angle_invert = p_invert;
+
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+bool SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_invert(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), false, "CCDIK joint out of range!");
+ return ccdik_data_chain[p_joint_idx].constraint_angle_invert;
+}
+
+void SkeletonModification2DCCDIK::set_ccdik_joint_constraint_in_localspace(int p_joint_idx, bool p_constraint_in_localspace) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!");
+ ccdik_data_chain.write[p_joint_idx].constraint_in_localspace = p_constraint_in_localspace;
+
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+bool SkeletonModification2DCCDIK::get_ccdik_joint_constraint_in_localspace(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), false, "CCDIK joint out of range!");
+ return ccdik_data_chain[p_joint_idx].constraint_in_localspace;
+}
+
+void SkeletonModification2DCCDIK::set_ccdik_joint_editor_draw_gizmo(int p_joint_idx, bool p_draw_gizmo) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!");
+ ccdik_data_chain.write[p_joint_idx].editor_draw_gizmo = p_draw_gizmo;
+
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+bool SkeletonModification2DCCDIK::get_ccdik_joint_editor_draw_gizmo(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), false, "CCDIK joint out of range!");
+ return ccdik_data_chain[p_joint_idx].editor_draw_gizmo;
+}
+
+void SkeletonModification2DCCDIK::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DCCDIK::set_target_node);
+ ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DCCDIK::get_target_node);
+ ClassDB::bind_method(D_METHOD("set_tip_node", "tip_nodepath"), &SkeletonModification2DCCDIK::set_tip_node);
+ ClassDB::bind_method(D_METHOD("get_tip_node"), &SkeletonModification2DCCDIK::get_tip_node);
+
+ ClassDB::bind_method(D_METHOD("set_ccdik_data_chain_length", "length"), &SkeletonModification2DCCDIK::set_ccdik_data_chain_length);
+ ClassDB::bind_method(D_METHOD("get_ccdik_data_chain_length"), &SkeletonModification2DCCDIK::get_ccdik_data_chain_length);
+
+ ClassDB::bind_method(D_METHOD("set_ccdik_joint_bone2d_node", "joint_idx", "bone2d_nodepath"), &SkeletonModification2DCCDIK::set_ccdik_joint_bone2d_node);
+ ClassDB::bind_method(D_METHOD("get_ccdik_joint_bone2d_node", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_bone2d_node);
+ ClassDB::bind_method(D_METHOD("set_ccdik_joint_bone_index", "joint_idx", "bone_idx"), &SkeletonModification2DCCDIK::set_ccdik_joint_bone_index);
+ ClassDB::bind_method(D_METHOD("get_ccdik_joint_bone_index", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_bone_index);
+ ClassDB::bind_method(D_METHOD("set_ccdik_joint_rotate_from_joint", "joint_idx", "rotate_from_joint"), &SkeletonModification2DCCDIK::set_ccdik_joint_rotate_from_joint);
+ ClassDB::bind_method(D_METHOD("get_ccdik_joint_rotate_from_joint", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_rotate_from_joint);
+ ClassDB::bind_method(D_METHOD("set_ccdik_joint_enable_constraint", "joint_idx", "enable_constraint"), &SkeletonModification2DCCDIK::set_ccdik_joint_enable_constraint);
+ ClassDB::bind_method(D_METHOD("get_ccdik_joint_enable_constraint", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_enable_constraint);
+ ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_min", "joint_idx", "angle_min"), &SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_min);
+ ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_min", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_min);
+ ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_max", "joint_idx", "angle_max"), &SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_max);
+ ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_max", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_max);
+ ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_invert", "joint_idx", "invert"), &SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_invert);
+ ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_invert", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_invert);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "tip_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_tip_node", "get_tip_node");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "ccdik_data_chain_length", PROPERTY_HINT_RANGE, "0, 100, 1"), "set_ccdik_data_chain_length", "get_ccdik_data_chain_length");
+}
+
+SkeletonModification2DCCDIK::SkeletonModification2DCCDIK() {
+ stack = nullptr;
+ is_setup = false;
+ enabled = true;
+ editor_draw_gizmo = true;
+}
+
+SkeletonModification2DCCDIK::~SkeletonModification2DCCDIK() {
+}
diff --git a/scene/resources/skeleton_modification_2d_ccdik.h b/scene/resources/skeleton_modification_2d_ccdik.h
new file mode 100644
index 0000000000..dc48291f62
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_ccdik.h
@@ -0,0 +1,116 @@
+/*************************************************************************/
+/* skeleton_modification_2d_ccdik.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETONMODIFICATION2DCCDIK_H
+#define SKELETONMODIFICATION2DCCDIK_H
+
+#include "scene/2d/skeleton_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
+
+///////////////////////////////////////
+// SkeletonModification2DCCDIK
+///////////////////////////////////////
+
+class SkeletonModification2DCCDIK : public SkeletonModification2D {
+ GDCLASS(SkeletonModification2DCCDIK, SkeletonModification2D);
+
+private:
+ struct CCDIK_Joint_Data2D {
+ int bone_idx = -1;
+ NodePath bone2d_node;
+ ObjectID bone2d_node_cache;
+ bool rotate_from_joint = false;
+
+ bool enable_constraint = false;
+ float constraint_angle_min = 0;
+ float constraint_angle_max = (2.0 * Math_PI);
+ bool constraint_angle_invert = false;
+ bool constraint_in_localspace = true;
+
+ bool editor_draw_gizmo = true;
+ };
+
+ Vector<CCDIK_Joint_Data2D> ccdik_data_chain;
+
+ NodePath target_node;
+ ObjectID target_node_cache;
+ void update_target_cache();
+
+ NodePath tip_node;
+ ObjectID tip_node_cache;
+ void update_tip_cache();
+
+ void ccdik_joint_update_bone2d_cache(int p_joint_idx);
+ void _execute_ccdik_joint(int p_joint_idx, Node2D *p_target, Node2D *p_tip);
+
+protected:
+ static void _bind_methods();
+ bool _set(const StringName &p_path, const Variant &p_value);
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+public:
+ void _execute(float p_delta) override;
+ void _setup_modification(SkeletonModificationStack2D *p_stack) override;
+ void _draw_editor_gizmo() override;
+
+ void set_target_node(const NodePath &p_target_node);
+ NodePath get_target_node() const;
+ void set_tip_node(const NodePath &p_tip_node);
+ NodePath get_tip_node() const;
+
+ int get_ccdik_data_chain_length();
+ void set_ccdik_data_chain_length(int p_new_length);
+
+ void set_ccdik_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node);
+ NodePath get_ccdik_joint_bone2d_node(int p_joint_idx) const;
+ void set_ccdik_joint_bone_index(int p_joint_idx, int p_bone_idx);
+ int get_ccdik_joint_bone_index(int p_joint_idx) const;
+
+ void set_ccdik_joint_rotate_from_joint(int p_joint_idx, bool p_rotate_from_joint);
+ bool get_ccdik_joint_rotate_from_joint(int p_joint_idx) const;
+ void set_ccdik_joint_enable_constraint(int p_joint_idx, bool p_constraint);
+ bool get_ccdik_joint_enable_constraint(int p_joint_idx) const;
+ void set_ccdik_joint_constraint_angle_min(int p_joint_idx, float p_angle_min);
+ float get_ccdik_joint_constraint_angle_min(int p_joint_idx) const;
+ void set_ccdik_joint_constraint_angle_max(int p_joint_idx, float p_angle_max);
+ float get_ccdik_joint_constraint_angle_max(int p_joint_idx) const;
+ void set_ccdik_joint_constraint_angle_invert(int p_joint_idx, bool p_invert);
+ bool get_ccdik_joint_constraint_angle_invert(int p_joint_idx) const;
+ void set_ccdik_joint_constraint_in_localspace(int p_joint_idx, bool p_constraint_in_localspace);
+ bool get_ccdik_joint_constraint_in_localspace(int p_joint_idx) const;
+ void set_ccdik_joint_editor_draw_gizmo(int p_joint_idx, bool p_draw_gizmo);
+ bool get_ccdik_joint_editor_draw_gizmo(int p_joint_idx) const;
+
+ SkeletonModification2DCCDIK();
+ ~SkeletonModification2DCCDIK();
+};
+
+#endif // SKELETONMODIFICATION2DCCDIK_H
diff --git a/scene/resources/skeleton_modification_2d_fabrik.cpp b/scene/resources/skeleton_modification_2d_fabrik.cpp
new file mode 100644
index 0000000000..aef852f7e4
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_fabrik.cpp
@@ -0,0 +1,444 @@
+/*************************************************************************/
+/* skeleton_modification_2d_fabrik.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_modification_2d_fabrik.h"
+#include "scene/2d/skeleton_2d.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif // TOOLS_ENABLED
+
+bool SkeletonModification2DFABRIK::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+ if (path.begins_with("joint_data/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, fabrik_data_chain.size(), false);
+
+ if (what == "bone2d_node") {
+ set_fabrik_joint_bone2d_node(which, p_value);
+ } else if (what == "bone_index") {
+ set_fabrik_joint_bone_index(which, p_value);
+ } else if (what == "magnet_position") {
+ set_fabrik_joint_magnet_position(which, p_value);
+ } else if (what == "use_target_rotation") {
+ set_fabrik_joint_use_target_rotation(which, p_value);
+ }
+ }
+
+ return true;
+}
+
+bool SkeletonModification2DFABRIK::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path.begins_with("joint_data/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, fabrik_data_chain.size(), false);
+
+ if (what == "bone2d_node") {
+ r_ret = get_fabrik_joint_bone2d_node(which);
+ } else if (what == "bone_index") {
+ r_ret = get_fabrik_joint_bone_index(which);
+ } else if (what == "magnet_position") {
+ r_ret = get_fabrik_joint_magnet_position(which);
+ } else if (what == "use_target_rotation") {
+ r_ret = get_fabrik_joint_use_target_rotation(which);
+ }
+ return true;
+ }
+ return true;
+}
+
+void SkeletonModification2DFABRIK::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < fabrik_data_chain.size(); i++) {
+ String base_string = "joint_data/" + itos(i) + "/";
+
+ p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT));
+
+ if (i > 0) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, base_string + "magnet_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+ if (i == fabrik_data_chain.size() - 1) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_target_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+ }
+}
+
+void SkeletonModification2DFABRIK::_execute(float p_delta) {
+ ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
+ "Modification is not setup and therefore cannot execute!");
+ if (!enabled) {
+ return;
+ }
+
+ if (target_node_cache.is_null()) {
+ WARN_PRINT_ONCE("Target cache is out of date. Attempting to update...");
+ update_target_cache();
+ return;
+ }
+
+ if (fabrik_data_chain.size() <= 1) {
+ ERR_PRINT_ONCE("FABRIK requires at least two joints to operate! Cannot execute modification!");
+ return;
+ }
+
+ Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache));
+ if (!target || !target->is_inside_tree()) {
+ ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!");
+ return;
+ }
+ target_global_pose = target->get_global_transform();
+
+ if (fabrik_data_chain[0].bone2d_node_cache.is_null() && !fabrik_data_chain[0].bone2d_node.is_empty()) {
+ fabrik_joint_update_bone2d_cache(0);
+ WARN_PRINT("Bone2D cache for origin joint is out of date. Updating...");
+ }
+
+ Bone2D *origin_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[0].bone2d_node_cache));
+ if (!origin_bone2d_node || !origin_bone2d_node->is_inside_tree()) {
+ ERR_PRINT_ONCE("Origin joint's Bone2D node is not in the scene tree. Cannot execute modification!");
+ return;
+ }
+
+ origin_global_pose = origin_bone2d_node->get_global_transform();
+
+ if (fabrik_transform_chain.size() != fabrik_data_chain.size()) {
+ fabrik_transform_chain.resize(fabrik_data_chain.size());
+ }
+
+ for (int i = 0; i < fabrik_data_chain.size(); i++) {
+ // Update the transform chain
+ if (fabrik_data_chain[i].bone2d_node_cache.is_null() && !fabrik_data_chain[i].bone2d_node.is_empty()) {
+ WARN_PRINT_ONCE("Bone2D cache for joint " + itos(i) + " is out of date.. Attempting to update...");
+ fabrik_joint_update_bone2d_cache(i);
+ }
+ Bone2D *joint_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[i].bone2d_node_cache));
+ if (!joint_bone2d_node) {
+ ERR_PRINT_ONCE("FABRIK Joint " + itos(i) + " does not have a Bone2D node set! Cannot execute modification!");
+ return;
+ }
+ fabrik_transform_chain.write[i] = joint_bone2d_node->get_global_transform();
+
+ // Apply magnet positions
+ if (i == 0) {
+ continue; // The origin cannot use a magnet position!
+ } else {
+ Transform2D joint_trans = fabrik_transform_chain[i];
+ joint_trans.set_origin(joint_trans.get_origin() + fabrik_data_chain[i].magnet_position);
+ fabrik_transform_chain.write[i] = joint_trans;
+ }
+ }
+
+ Bone2D *final_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[fabrik_data_chain.size() - 1].bone2d_node_cache));
+ float final_bone2d_angle = final_bone2d_node->get_global_transform().get_rotation();
+ if (fabrik_data_chain[fabrik_data_chain.size() - 1].use_target_rotation) {
+ final_bone2d_angle = target_global_pose.get_rotation();
+ }
+ Vector2 final_bone2d_direction = Vector2(Math::cos(final_bone2d_angle), Math::sin(final_bone2d_angle));
+ float final_bone2d_length = final_bone2d_node->get_length() * MIN(final_bone2d_node->get_global_scale().x, final_bone2d_node->get_global_scale().y);
+ float target_distance = (final_bone2d_node->get_global_transform().get_origin() + (final_bone2d_direction * final_bone2d_length)).distance_to(target->get_global_transform().get_origin());
+ chain_iterations = 0;
+
+ while (target_distance > chain_tolarance) {
+ chain_backwards();
+ chain_forwards();
+
+ final_bone2d_angle = final_bone2d_node->get_global_transform().get_rotation();
+ if (fabrik_data_chain[fabrik_data_chain.size() - 1].use_target_rotation) {
+ final_bone2d_angle = target_global_pose.get_rotation();
+ }
+ final_bone2d_direction = Vector2(Math::cos(final_bone2d_angle), Math::sin(final_bone2d_angle));
+ target_distance = (final_bone2d_node->get_global_transform().get_origin() + (final_bone2d_direction * final_bone2d_length)).distance_to(target->get_global_transform().get_origin());
+
+ chain_iterations += 1;
+ if (chain_iterations >= chain_max_iterations) {
+ break;
+ }
+ }
+
+ // Apply all of the saved transforms to the Bone2D nodes
+ for (int i = 0; i < fabrik_data_chain.size(); i++) {
+ Bone2D *joint_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[i].bone2d_node_cache));
+ if (!joint_bone2d_node) {
+ ERR_PRINT_ONCE("FABRIK Joint " + itos(i) + " does not have a Bone2D node set!");
+ continue;
+ }
+ Transform2D chain_trans = fabrik_transform_chain[i];
+
+ // Apply rotation
+ if (i + 1 < fabrik_data_chain.size()) {
+ chain_trans = chain_trans.looking_at(fabrik_transform_chain[i + 1].get_origin());
+ } else {
+ if (fabrik_data_chain[i].use_target_rotation) {
+ chain_trans.set_rotation(target_global_pose.get_rotation());
+ } else {
+ chain_trans = chain_trans.looking_at(target_global_pose.get_origin());
+ }
+ }
+ // Adjust for the bone angle
+ chain_trans.set_rotation(chain_trans.get_rotation() - joint_bone2d_node->get_bone_angle());
+
+ // Reset scale
+ chain_trans.set_scale(joint_bone2d_node->get_global_transform().get_scale());
+
+ // Apply to the bone, and to the override
+ joint_bone2d_node->set_global_transform(chain_trans);
+ stack->skeleton->set_bone_local_pose_override(fabrik_data_chain[i].bone_idx, joint_bone2d_node->get_transform(), stack->strength, true);
+ }
+}
+
+void SkeletonModification2DFABRIK::chain_backwards() {
+ int final_joint_index = fabrik_data_chain.size() - 1;
+ Bone2D *final_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[final_joint_index].bone2d_node_cache));
+ Transform2D final_bone2d_trans = fabrik_transform_chain[final_joint_index];
+
+ // Set the rotation of the tip bone
+ final_bone2d_trans = final_bone2d_trans.looking_at(target_global_pose.get_origin());
+
+ // Set the position of the tip bone
+ float final_bone2d_angle = final_bone2d_trans.get_rotation();
+ if (fabrik_data_chain[final_joint_index].use_target_rotation) {
+ final_bone2d_angle = target_global_pose.get_rotation();
+ }
+ Vector2 final_bone2d_direction = Vector2(Math::cos(final_bone2d_angle), Math::sin(final_bone2d_angle));
+ float final_bone2d_length = final_bone2d_node->get_length() * MIN(final_bone2d_node->get_global_scale().x, final_bone2d_node->get_global_scale().y);
+ final_bone2d_trans.set_origin(target_global_pose.get_origin() - (final_bone2d_direction * final_bone2d_length));
+
+ // Save the transform
+ fabrik_transform_chain.write[final_joint_index] = final_bone2d_trans;
+
+ int i = final_joint_index;
+ while (i >= 1) {
+ Transform2D previous_pose = fabrik_transform_chain[i];
+ i -= 1;
+ Bone2D *current_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[i].bone2d_node_cache));
+ Transform2D current_pose = fabrik_transform_chain[i];
+
+ float current_bone2d_node_length = current_bone2d_node->get_length() * MIN(current_bone2d_node->get_global_scale().x, current_bone2d_node->get_global_scale().y);
+ float length = current_bone2d_node_length / (previous_pose.get_origin() - current_pose.get_origin()).length();
+ Vector2 finish_position = previous_pose.get_origin().lerp(current_pose.get_origin(), length);
+ current_pose.set_origin(finish_position);
+
+ // Save the transform
+ fabrik_transform_chain.write[i] = current_pose;
+ }
+}
+
+void SkeletonModification2DFABRIK::chain_forwards() {
+ Transform2D origin_bone2d_trans = fabrik_transform_chain[0];
+ origin_bone2d_trans.set_origin(origin_global_pose.get_origin());
+ // Save the position
+ fabrik_transform_chain.write[0] = origin_bone2d_trans;
+
+ for (int i = 0; i < fabrik_data_chain.size() - 1; i++) {
+ Bone2D *current_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[i].bone2d_node_cache));
+ Transform2D current_pose = fabrik_transform_chain[i];
+ Transform2D next_pose = fabrik_transform_chain[i + 1];
+
+ float current_bone2d_node_length = current_bone2d_node->get_length() * MIN(current_bone2d_node->get_global_scale().x, current_bone2d_node->get_global_scale().y);
+ float length = current_bone2d_node_length / (current_pose.get_origin() - next_pose.get_origin()).length();
+ Vector2 finish_position = current_pose.get_origin().lerp(next_pose.get_origin(), length);
+ current_pose.set_origin(finish_position);
+
+ // Apply to the bone
+ fabrik_transform_chain.write[i + 1] = current_pose;
+ }
+}
+
+void SkeletonModification2DFABRIK::_setup_modification(SkeletonModificationStack2D *p_stack) {
+ stack = p_stack;
+
+ if (stack != nullptr) {
+ is_setup = true;
+ update_target_cache();
+ }
+}
+
+void SkeletonModification2DFABRIK::update_target_cache() {
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!");
+ return;
+ }
+
+ target_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(target_node)) {
+ Node *node = stack->skeleton->get_node(target_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update target cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update target cache: node is not in scene tree!");
+ target_node_cache = node->get_instance_id();
+ }
+ }
+ }
+}
+
+void SkeletonModification2DFABRIK::fabrik_joint_update_bone2d_cache(int p_joint_idx) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, fabrik_data_chain.size(), "Cannot update bone2d cache: joint index out of range!");
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update FABRIK Bone2D cache: modification is not properly setup!");
+ return;
+ }
+
+ fabrik_data_chain.write[p_joint_idx].bone2d_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(fabrik_data_chain[p_joint_idx].bone2d_node)) {
+ Node *node = stack->skeleton->get_node(fabrik_data_chain[p_joint_idx].bone2d_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update FABRIK joint " + itos(p_joint_idx) + " Bone2D cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update FABRIK joint " + itos(p_joint_idx) + " Bone2D cache: node is not in scene tree!");
+ fabrik_data_chain.write[p_joint_idx].bone2d_node_cache = node->get_instance_id();
+
+ Bone2D *bone = Object::cast_to<Bone2D>(node);
+ if (bone) {
+ fabrik_data_chain.write[p_joint_idx].bone_idx = bone->get_index_in_skeleton();
+ } else {
+ ERR_FAIL_MSG("FABRIK joint " + itos(p_joint_idx) + " Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
+ }
+ }
+ }
+ }
+}
+
+void SkeletonModification2DFABRIK::set_target_node(const NodePath &p_target_node) {
+ target_node = p_target_node;
+ update_target_cache();
+}
+
+NodePath SkeletonModification2DFABRIK::get_target_node() const {
+ return target_node;
+}
+
+void SkeletonModification2DFABRIK::set_fabrik_data_chain_length(int p_length) {
+ fabrik_data_chain.resize(p_length);
+ notify_property_list_changed();
+}
+
+int SkeletonModification2DFABRIK::get_fabrik_data_chain_length() {
+ return fabrik_data_chain.size();
+}
+
+void SkeletonModification2DFABRIK::set_fabrik_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, fabrik_data_chain.size(), "FABRIK joint out of range!");
+ fabrik_data_chain.write[p_joint_idx].bone2d_node = p_target_node;
+ fabrik_joint_update_bone2d_cache(p_joint_idx);
+
+ notify_property_list_changed();
+}
+
+NodePath SkeletonModification2DFABRIK::get_fabrik_joint_bone2d_node(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, fabrik_data_chain.size(), NodePath(), "FABRIK joint out of range!");
+ return fabrik_data_chain[p_joint_idx].bone2d_node;
+}
+
+void SkeletonModification2DFABRIK::set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, fabrik_data_chain.size(), "FABRIK joint out of range!");
+ ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
+
+ if (is_setup) {
+ if (stack->skeleton) {
+ ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!");
+ fabrik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
+ fabrik_data_chain.write[p_joint_idx].bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id();
+ fabrik_data_chain.write[p_joint_idx].bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx));
+ } else {
+ WARN_PRINT("Cannot verify the FABRIK joint " + itos(p_joint_idx) + " bone index for this modification...");
+ fabrik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
+ }
+ } else {
+ WARN_PRINT("Cannot verify the FABRIK joint " + itos(p_joint_idx) + " bone index for this modification...");
+ fabrik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
+ }
+
+ notify_property_list_changed();
+}
+
+int SkeletonModification2DFABRIK::get_fabrik_joint_bone_index(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, fabrik_data_chain.size(), -1, "FABRIK joint out of range!");
+ return fabrik_data_chain[p_joint_idx].bone_idx;
+}
+
+void SkeletonModification2DFABRIK::set_fabrik_joint_magnet_position(int p_joint_idx, Vector2 p_magnet_position) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, fabrik_data_chain.size(), "FABRIK joint out of range!");
+ fabrik_data_chain.write[p_joint_idx].magnet_position = p_magnet_position;
+}
+
+Vector2 SkeletonModification2DFABRIK::get_fabrik_joint_magnet_position(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, fabrik_data_chain.size(), Vector2(), "FABRIK joint out of range!");
+ return fabrik_data_chain[p_joint_idx].magnet_position;
+}
+
+void SkeletonModification2DFABRIK::set_fabrik_joint_use_target_rotation(int p_joint_idx, bool p_use_target_rotation) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, fabrik_data_chain.size(), "FABRIK joint out of range!");
+ fabrik_data_chain.write[p_joint_idx].use_target_rotation = p_use_target_rotation;
+}
+
+bool SkeletonModification2DFABRIK::get_fabrik_joint_use_target_rotation(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, fabrik_data_chain.size(), false, "FABRIK joint out of range!");
+ return fabrik_data_chain[p_joint_idx].use_target_rotation;
+}
+
+void SkeletonModification2DFABRIK::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DFABRIK::set_target_node);
+ ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DFABRIK::get_target_node);
+
+ ClassDB::bind_method(D_METHOD("set_fabrik_data_chain_length", "length"), &SkeletonModification2DFABRIK::set_fabrik_data_chain_length);
+ ClassDB::bind_method(D_METHOD("get_fabrik_data_chain_length"), &SkeletonModification2DFABRIK::get_fabrik_data_chain_length);
+
+ ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone2d_node", "joint_idx", "bone2d_nodepath"), &SkeletonModification2DFABRIK::set_fabrik_joint_bone2d_node);
+ ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone2d_node", "joint_idx"), &SkeletonModification2DFABRIK::get_fabrik_joint_bone2d_node);
+ ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone_index", "joint_idx", "bone_idx"), &SkeletonModification2DFABRIK::set_fabrik_joint_bone_index);
+ ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone_index", "joint_idx"), &SkeletonModification2DFABRIK::get_fabrik_joint_bone_index);
+ ClassDB::bind_method(D_METHOD("set_fabrik_joint_magnet_position", "joint_idx", "magnet_position"), &SkeletonModification2DFABRIK::set_fabrik_joint_magnet_position);
+ ClassDB::bind_method(D_METHOD("get_fabrik_joint_magnet_position", "joint_idx"), &SkeletonModification2DFABRIK::get_fabrik_joint_magnet_position);
+ ClassDB::bind_method(D_METHOD("set_fabrik_joint_use_target_rotation", "joint_idx", "use_target_rotation"), &SkeletonModification2DFABRIK::set_fabrik_joint_use_target_rotation);
+ ClassDB::bind_method(D_METHOD("get_fabrik_joint_use_target_rotation", "joint_idx"), &SkeletonModification2DFABRIK::get_fabrik_joint_use_target_rotation);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fabrik_data_chain_length", PROPERTY_HINT_RANGE, "0, 100, 1"), "set_fabrik_data_chain_length", "get_fabrik_data_chain_length");
+}
+
+SkeletonModification2DFABRIK::SkeletonModification2DFABRIK() {
+ stack = nullptr;
+ is_setup = false;
+ enabled = true;
+ editor_draw_gizmo = false;
+}
+
+SkeletonModification2DFABRIK::~SkeletonModification2DFABRIK() {
+}
diff --git a/scene/resources/skeleton_modification_2d_fabrik.h b/scene/resources/skeleton_modification_2d_fabrik.h
new file mode 100644
index 0000000000..79e0106e26
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_fabrik.h
@@ -0,0 +1,108 @@
+/*************************************************************************/
+/* skeleton_modification_2d_fabrik.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETONMODIFICATION2DFABRIK_H
+#define SKELETONMODIFICATION2DFABRIK_H
+
+#include "scene/2d/skeleton_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
+
+///////////////////////////////////////
+// SkeletonModification2DFABRIK
+///////////////////////////////////////
+
+class SkeletonModification2DFABRIK : public SkeletonModification2D {
+ GDCLASS(SkeletonModification2DFABRIK, SkeletonModification2D);
+
+private:
+ struct FABRIK_Joint_Data2D {
+ int bone_idx = -1;
+ NodePath bone2d_node;
+ ObjectID bone2d_node_cache;
+
+ Vector2 magnet_position = Vector2(0, 0);
+ bool use_target_rotation = false;
+
+ bool editor_draw_gizmo = true;
+ };
+
+ Vector<FABRIK_Joint_Data2D> fabrik_data_chain;
+
+ // Unlike in 3D, we need a vector of Transform2D objects to perform FABRIK.
+ // This is because FABRIK (unlike CCDIK) needs to operate on transforms that are NOT
+ // affected by each other, making the transforms stored in Bone2D unusable, as well as those in Skeleton2D.
+ // For this reason, this modification stores a vector of Transform2Ds used for the calculations, which are then applied at the end.
+ Vector<Transform2D> fabrik_transform_chain;
+
+ NodePath target_node;
+ ObjectID target_node_cache;
+ void update_target_cache();
+
+ float chain_tolarance = 0.01;
+ int chain_max_iterations = 10;
+ int chain_iterations = 0;
+ Transform2D target_global_pose = Transform2D();
+ Transform2D origin_global_pose = Transform2D();
+
+ void fabrik_joint_update_bone2d_cache(int p_joint_idx);
+ void chain_backwards();
+ void chain_forwards();
+
+protected:
+ static void _bind_methods();
+ bool _set(const StringName &p_path, const Variant &p_value);
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+public:
+ void _execute(float p_delta) override;
+ void _setup_modification(SkeletonModificationStack2D *p_stack) override;
+
+ void set_target_node(const NodePath &p_target_node);
+ NodePath get_target_node() const;
+
+ int get_fabrik_data_chain_length();
+ void set_fabrik_data_chain_length(int p_new_length);
+
+ void set_fabrik_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node);
+ NodePath get_fabrik_joint_bone2d_node(int p_joint_idx) const;
+ void set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx);
+ int get_fabrik_joint_bone_index(int p_joint_idx) const;
+
+ void set_fabrik_joint_magnet_position(int p_joint_idx, Vector2 p_magnet_position);
+ Vector2 get_fabrik_joint_magnet_position(int p_joint_idx) const;
+ void set_fabrik_joint_use_target_rotation(int p_joint_idx, bool p_use_target_rotation);
+ bool get_fabrik_joint_use_target_rotation(int p_joint_idx) const;
+
+ SkeletonModification2DFABRIK();
+ ~SkeletonModification2DFABRIK();
+};
+
+#endif // SKELETONMODIFICATION2DFABRIK_H
diff --git a/scene/resources/skeleton_modification_2d_jiggle.cpp b/scene/resources/skeleton_modification_2d_jiggle.cpp
new file mode 100644
index 0000000000..2547083336
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_jiggle.cpp
@@ -0,0 +1,564 @@
+/*************************************************************************/
+/* skeleton_modification_2d_jiggle.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_modification_2d_jiggle.h"
+#include "scene/2d/skeleton_2d.h"
+
+bool SkeletonModification2DJiggle::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+ if (path.begins_with("joint_data/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, jiggle_data_chain.size(), false);
+
+ if (what == "bone2d_node") {
+ set_jiggle_joint_bone2d_node(which, p_value);
+ } else if (what == "bone_index") {
+ set_jiggle_joint_bone_index(which, p_value);
+ } else if (what == "override_defaults") {
+ set_jiggle_joint_override(which, p_value);
+ } else if (what == "stiffness") {
+ set_jiggle_joint_stiffness(which, p_value);
+ } else if (what == "mass") {
+ set_jiggle_joint_mass(which, p_value);
+ } else if (what == "damping") {
+ set_jiggle_joint_damping(which, p_value);
+ } else if (what == "use_gravity") {
+ set_jiggle_joint_use_gravity(which, p_value);
+ } else if (what == "gravity") {
+ set_jiggle_joint_gravity(which, p_value);
+ }
+ return true;
+ } else {
+ if (path == "use_colliders") {
+ set_use_colliders(p_value);
+ } else if (path == "collision_mask") {
+ set_collision_mask(p_value);
+ }
+ }
+ return true;
+}
+
+bool SkeletonModification2DJiggle::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path.begins_with("joint_data/")) {
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+ ERR_FAIL_INDEX_V(which, jiggle_data_chain.size(), false);
+
+ if (what == "bone2d_node") {
+ r_ret = get_jiggle_joint_bone2d_node(which);
+ } else if (what == "bone_index") {
+ r_ret = get_jiggle_joint_bone_index(which);
+ } else if (what == "override_defaults") {
+ r_ret = get_jiggle_joint_override(which);
+ } else if (what == "stiffness") {
+ r_ret = get_jiggle_joint_stiffness(which);
+ } else if (what == "mass") {
+ r_ret = get_jiggle_joint_mass(which);
+ } else if (what == "damping") {
+ r_ret = get_jiggle_joint_damping(which);
+ } else if (what == "use_gravity") {
+ r_ret = get_jiggle_joint_use_gravity(which);
+ } else if (what == "gravity") {
+ r_ret = get_jiggle_joint_gravity(which);
+ }
+ return true;
+ } else {
+ if (path == "use_colliders") {
+ r_ret = get_use_colliders();
+ } else if (path == "collision_mask") {
+ r_ret = get_collision_mask();
+ }
+ }
+ return true;
+}
+
+void SkeletonModification2DJiggle::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "use_colliders", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ if (use_colliders) {
+ p_list->push_back(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS, "", PROPERTY_USAGE_DEFAULT));
+ }
+
+ for (int i = 0; i < jiggle_data_chain.size(); i++) {
+ String base_string = "joint_data/" + itos(i) + "/";
+
+ p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "override_defaults", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+
+ if (jiggle_data_chain[i].override_defaults) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "stiffness", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "mass", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ if (jiggle_data_chain[i].use_gravity) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, base_string + "gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+ }
+ }
+}
+
+void SkeletonModification2DJiggle::_execute(float p_delta) {
+ ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
+ "Modification is not setup and therefore cannot execute!");
+ if (!enabled) {
+ return;
+ }
+ if (target_node_cache.is_null()) {
+ WARN_PRINT_ONCE("Target cache is out of date. Attempting to update...");
+ update_target_cache();
+ return;
+ }
+ Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache));
+ if (!target || !target->is_inside_tree()) {
+ ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!");
+ return;
+ }
+
+ for (int i = 0; i < jiggle_data_chain.size(); i++) {
+ _execute_jiggle_joint(i, target, p_delta);
+ }
+}
+
+void SkeletonModification2DJiggle::_execute_jiggle_joint(int p_joint_idx, Node2D *p_target, float p_delta) {
+ // Adopted from: https://wiki.unity3d.com/index.php/JiggleBone
+ // With modifications by TwistedTwigleg.
+
+ if (jiggle_data_chain[p_joint_idx].bone_idx <= -1 || jiggle_data_chain[p_joint_idx].bone_idx > stack->skeleton->get_bone_count()) {
+ ERR_PRINT_ONCE("Jiggle joint " + itos(p_joint_idx) + " bone index is invalid. Cannot execute modification on joint...");
+ return;
+ }
+
+ if (jiggle_data_chain[p_joint_idx].bone2d_node_cache.is_null() && !jiggle_data_chain[p_joint_idx].bone2d_node.is_empty()) {
+ WARN_PRINT_ONCE("Bone2D cache for joint " + itos(p_joint_idx) + " is out of date. Updating...");
+ jiggle_joint_update_bone2d_cache(p_joint_idx);
+ }
+
+ Bone2D *operation_bone = stack->skeleton->get_bone(jiggle_data_chain[p_joint_idx].bone_idx);
+ if (!operation_bone) {
+ ERR_PRINT_ONCE("Jiggle joint " + itos(p_joint_idx) + " does not have a Bone2D node or it cannot be found!");
+ return;
+ }
+
+ Transform2D operation_bone_trans = operation_bone->get_global_transform();
+ Vector2 target_position = p_target->get_global_transform().get_origin();
+
+ jiggle_data_chain.write[p_joint_idx].force = (target_position - jiggle_data_chain[p_joint_idx].dynamic_position) * jiggle_data_chain[p_joint_idx].stiffness * p_delta;
+
+ if (jiggle_data_chain[p_joint_idx].use_gravity) {
+ jiggle_data_chain.write[p_joint_idx].force += jiggle_data_chain[p_joint_idx].gravity * p_delta;
+ }
+
+ jiggle_data_chain.write[p_joint_idx].acceleration = jiggle_data_chain[p_joint_idx].force / jiggle_data_chain[p_joint_idx].mass;
+ jiggle_data_chain.write[p_joint_idx].velocity += jiggle_data_chain[p_joint_idx].acceleration * (1 - jiggle_data_chain[p_joint_idx].damping);
+
+ jiggle_data_chain.write[p_joint_idx].dynamic_position += jiggle_data_chain[p_joint_idx].velocity + jiggle_data_chain[p_joint_idx].force;
+ jiggle_data_chain.write[p_joint_idx].dynamic_position += operation_bone_trans.get_origin() - jiggle_data_chain[p_joint_idx].last_position;
+ jiggle_data_chain.write[p_joint_idx].last_position = operation_bone_trans.get_origin();
+
+ // Collision detection/response
+ if (use_colliders) {
+ if (execution_mode == SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_physics_process) {
+ Ref<World2D> world_2d = stack->skeleton->get_world_2d();
+ ERR_FAIL_COND(world_2d.is_null());
+ PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());
+ PhysicsDirectSpaceState2D::RayResult ray_result;
+
+ // Add exception support?
+ bool ray_hit = space_state->intersect_ray(operation_bone_trans.get_origin(), jiggle_data_chain[p_joint_idx].dynamic_position,
+ ray_result, Set<RID>(), collision_mask);
+
+ if (ray_hit) {
+ jiggle_data_chain.write[p_joint_idx].dynamic_position = jiggle_data_chain[p_joint_idx].last_noncollision_position;
+ jiggle_data_chain.write[p_joint_idx].acceleration = Vector2(0, 0);
+ jiggle_data_chain.write[p_joint_idx].velocity = Vector2(0, 0);
+ } else {
+ jiggle_data_chain.write[p_joint_idx].last_noncollision_position = jiggle_data_chain[p_joint_idx].dynamic_position;
+ }
+ } else {
+ WARN_PRINT_ONCE("Jiggle 2D modifier: You cannot detect colliders without the stack mode being set to _physics_process!");
+ }
+ }
+
+ // Rotate the bone using the dynamic position!
+ operation_bone_trans = operation_bone_trans.looking_at(jiggle_data_chain[p_joint_idx].dynamic_position);
+ operation_bone_trans.set_rotation(operation_bone_trans.get_rotation() - operation_bone->get_bone_angle());
+
+ // Reset scale
+ operation_bone_trans.set_scale(operation_bone->get_global_transform().get_scale());
+
+ operation_bone->set_global_transform(operation_bone_trans);
+ stack->skeleton->set_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx, operation_bone->get_transform(), stack->strength, true);
+}
+
+void SkeletonModification2DJiggle::_update_jiggle_joint_data() {
+ for (int i = 0; i < jiggle_data_chain.size(); i++) {
+ if (!jiggle_data_chain[i].override_defaults) {
+ set_jiggle_joint_stiffness(i, stiffness);
+ set_jiggle_joint_mass(i, mass);
+ set_jiggle_joint_damping(i, damping);
+ set_jiggle_joint_use_gravity(i, use_gravity);
+ set_jiggle_joint_gravity(i, gravity);
+ }
+ }
+}
+
+void SkeletonModification2DJiggle::_setup_modification(SkeletonModificationStack2D *p_stack) {
+ stack = p_stack;
+
+ if (stack) {
+ is_setup = true;
+
+ if (stack->skeleton) {
+ for (int i = 0; i < jiggle_data_chain.size(); i++) {
+ int bone_idx = jiggle_data_chain[i].bone_idx;
+ if (bone_idx > 0 && bone_idx < stack->skeleton->get_bone_count()) {
+ Bone2D *bone2d_node = stack->skeleton->get_bone(bone_idx);
+ jiggle_data_chain.write[i].dynamic_position = bone2d_node->get_global_transform().get_origin();
+ }
+ }
+ }
+
+ update_target_cache();
+ }
+}
+
+void SkeletonModification2DJiggle::update_target_cache() {
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!");
+ return;
+ }
+
+ target_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(target_node)) {
+ Node *node = stack->skeleton->get_node(target_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update target cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update target cache: node is not in scene tree!");
+ target_node_cache = node->get_instance_id();
+ }
+ }
+ }
+}
+
+void SkeletonModification2DJiggle::jiggle_joint_update_bone2d_cache(int p_joint_idx) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, jiggle_data_chain.size(), "Cannot update bone2d cache: joint index out of range!");
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update Jiggle " + itos(p_joint_idx) + " Bone2D cache: modification is not properly setup!");
+ return;
+ }
+
+ jiggle_data_chain.write[p_joint_idx].bone2d_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(jiggle_data_chain[p_joint_idx].bone2d_node)) {
+ Node *node = stack->skeleton->get_node(jiggle_data_chain[p_joint_idx].bone2d_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update Jiggle joint " + itos(p_joint_idx) + " Bone2D cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update Jiggle joint " + itos(p_joint_idx) + " Bone2D cache: node is not in scene tree!");
+ jiggle_data_chain.write[p_joint_idx].bone2d_node_cache = node->get_instance_id();
+
+ Bone2D *bone = Object::cast_to<Bone2D>(node);
+ if (bone) {
+ jiggle_data_chain.write[p_joint_idx].bone_idx = bone->get_index_in_skeleton();
+ } else {
+ ERR_FAIL_MSG("Jiggle joint " + itos(p_joint_idx) + " Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
+ }
+ }
+ }
+ }
+}
+
+void SkeletonModification2DJiggle::set_target_node(const NodePath &p_target_node) {
+ target_node = p_target_node;
+ update_target_cache();
+}
+
+NodePath SkeletonModification2DJiggle::get_target_node() const {
+ return target_node;
+}
+
+void SkeletonModification2DJiggle::set_stiffness(float p_stiffness) {
+ ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!");
+ stiffness = p_stiffness;
+ _update_jiggle_joint_data();
+}
+
+float SkeletonModification2DJiggle::get_stiffness() const {
+ return stiffness;
+}
+
+void SkeletonModification2DJiggle::set_mass(float p_mass) {
+ ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!");
+ mass = p_mass;
+ _update_jiggle_joint_data();
+}
+
+float SkeletonModification2DJiggle::get_mass() const {
+ return mass;
+}
+
+void SkeletonModification2DJiggle::set_damping(float p_damping) {
+ ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!");
+ ERR_FAIL_COND_MSG(p_damping > 1, "Damping cannot be more than one!");
+ damping = p_damping;
+ _update_jiggle_joint_data();
+}
+
+float SkeletonModification2DJiggle::get_damping() const {
+ return damping;
+}
+
+void SkeletonModification2DJiggle::set_use_gravity(bool p_use_gravity) {
+ use_gravity = p_use_gravity;
+ _update_jiggle_joint_data();
+}
+
+bool SkeletonModification2DJiggle::get_use_gravity() const {
+ return use_gravity;
+}
+
+void SkeletonModification2DJiggle::set_gravity(Vector2 p_gravity) {
+ gravity = p_gravity;
+ _update_jiggle_joint_data();
+}
+
+Vector2 SkeletonModification2DJiggle::get_gravity() const {
+ return gravity;
+}
+
+void SkeletonModification2DJiggle::set_use_colliders(bool p_use_colliders) {
+ use_colliders = p_use_colliders;
+ notify_property_list_changed();
+}
+
+bool SkeletonModification2DJiggle::get_use_colliders() const {
+ return use_colliders;
+}
+
+void SkeletonModification2DJiggle::set_collision_mask(int p_mask) {
+ collision_mask = p_mask;
+}
+
+int SkeletonModification2DJiggle::get_collision_mask() const {
+ return collision_mask;
+}
+
+// Jiggle joint data functions
+int SkeletonModification2DJiggle::get_jiggle_data_chain_length() {
+ return jiggle_data_chain.size();
+}
+
+void SkeletonModification2DJiggle::set_jiggle_data_chain_length(int p_length) {
+ ERR_FAIL_COND(p_length < 0);
+ jiggle_data_chain.resize(p_length);
+ notify_property_list_changed();
+}
+
+void SkeletonModification2DJiggle::set_jiggle_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, jiggle_data_chain.size(), "Jiggle joint out of range!");
+ jiggle_data_chain.write[p_joint_idx].bone2d_node = p_target_node;
+ jiggle_joint_update_bone2d_cache(p_joint_idx);
+
+ notify_property_list_changed();
+}
+
+NodePath SkeletonModification2DJiggle::get_jiggle_joint_bone2d_node(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, jiggle_data_chain.size(), NodePath(), "Jiggle joint out of range!");
+ return jiggle_data_chain[p_joint_idx].bone2d_node;
+}
+
+void SkeletonModification2DJiggle::set_jiggle_joint_bone_index(int p_joint_idx, int p_bone_idx) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, jiggle_data_chain.size(), "Jiggle joint out of range!");
+ ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
+
+ if (is_setup) {
+ if (stack->skeleton) {
+ ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!");
+ jiggle_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
+ jiggle_data_chain.write[p_joint_idx].bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id();
+ jiggle_data_chain.write[p_joint_idx].bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx));
+ } else {
+ WARN_PRINT("Cannot verify the Jiggle joint " + itos(p_joint_idx) + " bone index for this modification...");
+ jiggle_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
+ }
+ } else {
+ WARN_PRINT("Cannot verify the Jiggle joint " + itos(p_joint_idx) + " bone index for this modification...");
+ jiggle_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
+ }
+
+ notify_property_list_changed();
+}
+
+int SkeletonModification2DJiggle::get_jiggle_joint_bone_index(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, jiggle_data_chain.size(), -1, "Jiggle joint out of range!");
+ return jiggle_data_chain[p_joint_idx].bone_idx;
+}
+
+void SkeletonModification2DJiggle::set_jiggle_joint_override(int p_joint_idx, bool p_override) {
+ ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
+ jiggle_data_chain.write[p_joint_idx].override_defaults = p_override;
+ _update_jiggle_joint_data();
+ notify_property_list_changed();
+}
+
+bool SkeletonModification2DJiggle::get_jiggle_joint_override(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), false);
+ return jiggle_data_chain[p_joint_idx].override_defaults;
+}
+
+void SkeletonModification2DJiggle::set_jiggle_joint_stiffness(int p_joint_idx, float p_stiffness) {
+ ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!");
+ ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
+ jiggle_data_chain.write[p_joint_idx].stiffness = p_stiffness;
+}
+
+float SkeletonModification2DJiggle::get_jiggle_joint_stiffness(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), -1);
+ return jiggle_data_chain[p_joint_idx].stiffness;
+}
+
+void SkeletonModification2DJiggle::set_jiggle_joint_mass(int p_joint_idx, float p_mass) {
+ ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!");
+ ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
+ jiggle_data_chain.write[p_joint_idx].mass = p_mass;
+}
+
+float SkeletonModification2DJiggle::get_jiggle_joint_mass(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), -1);
+ return jiggle_data_chain[p_joint_idx].mass;
+}
+
+void SkeletonModification2DJiggle::set_jiggle_joint_damping(int p_joint_idx, float p_damping) {
+ ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!");
+ ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
+ jiggle_data_chain.write[p_joint_idx].damping = p_damping;
+}
+
+float SkeletonModification2DJiggle::get_jiggle_joint_damping(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), -1);
+ return jiggle_data_chain[p_joint_idx].damping;
+}
+
+void SkeletonModification2DJiggle::set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity) {
+ ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
+ jiggle_data_chain.write[p_joint_idx].use_gravity = p_use_gravity;
+ notify_property_list_changed();
+}
+
+bool SkeletonModification2DJiggle::get_jiggle_joint_use_gravity(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), false);
+ return jiggle_data_chain[p_joint_idx].use_gravity;
+}
+
+void SkeletonModification2DJiggle::set_jiggle_joint_gravity(int p_joint_idx, Vector2 p_gravity) {
+ ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
+ jiggle_data_chain.write[p_joint_idx].gravity = p_gravity;
+}
+
+Vector2 SkeletonModification2DJiggle::get_jiggle_joint_gravity(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), Vector2(0, 0));
+ return jiggle_data_chain[p_joint_idx].gravity;
+}
+
+void SkeletonModification2DJiggle::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DJiggle::set_target_node);
+ ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DJiggle::get_target_node);
+
+ ClassDB::bind_method(D_METHOD("set_jiggle_data_chain_length", "length"), &SkeletonModification2DJiggle::set_jiggle_data_chain_length);
+ ClassDB::bind_method(D_METHOD("get_jiggle_data_chain_length"), &SkeletonModification2DJiggle::get_jiggle_data_chain_length);
+
+ ClassDB::bind_method(D_METHOD("set_stiffness", "stiffness"), &SkeletonModification2DJiggle::set_stiffness);
+ ClassDB::bind_method(D_METHOD("get_stiffness"), &SkeletonModification2DJiggle::get_stiffness);
+ ClassDB::bind_method(D_METHOD("set_mass", "mass"), &SkeletonModification2DJiggle::set_mass);
+ ClassDB::bind_method(D_METHOD("get_mass"), &SkeletonModification2DJiggle::get_mass);
+ ClassDB::bind_method(D_METHOD("set_damping", "damping"), &SkeletonModification2DJiggle::set_damping);
+ ClassDB::bind_method(D_METHOD("get_damping"), &SkeletonModification2DJiggle::get_damping);
+ ClassDB::bind_method(D_METHOD("set_use_gravity", "use_gravity"), &SkeletonModification2DJiggle::set_use_gravity);
+ ClassDB::bind_method(D_METHOD("get_use_gravity"), &SkeletonModification2DJiggle::get_use_gravity);
+ ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &SkeletonModification2DJiggle::set_gravity);
+ ClassDB::bind_method(D_METHOD("get_gravity"), &SkeletonModification2DJiggle::get_gravity);
+
+ ClassDB::bind_method(D_METHOD("set_use_colliders", "use_colliders"), &SkeletonModification2DJiggle::set_use_colliders);
+ ClassDB::bind_method(D_METHOD("get_use_colliders"), &SkeletonModification2DJiggle::get_use_colliders);
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SkeletonModification2DJiggle::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &SkeletonModification2DJiggle::get_collision_mask);
+
+ // Jiggle joint data functions
+ ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone2d_node", "joint_idx", "bone2d_node"), &SkeletonModification2DJiggle::set_jiggle_joint_bone2d_node);
+ ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone2d_node", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_bone2d_node);
+ ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone_index", "joint_idx", "bone_idx"), &SkeletonModification2DJiggle::set_jiggle_joint_bone_index);
+ ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone_index", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_bone_index);
+ ClassDB::bind_method(D_METHOD("set_jiggle_joint_override", "joint_idx", "override"), &SkeletonModification2DJiggle::set_jiggle_joint_override);
+ ClassDB::bind_method(D_METHOD("get_jiggle_joint_override", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_override);
+ ClassDB::bind_method(D_METHOD("set_jiggle_joint_stiffness", "joint_idx", "stiffness"), &SkeletonModification2DJiggle::set_jiggle_joint_stiffness);
+ ClassDB::bind_method(D_METHOD("get_jiggle_joint_stiffness", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_stiffness);
+ ClassDB::bind_method(D_METHOD("set_jiggle_joint_mass", "joint_idx", "mass"), &SkeletonModification2DJiggle::set_jiggle_joint_mass);
+ ClassDB::bind_method(D_METHOD("get_jiggle_joint_mass", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_mass);
+ ClassDB::bind_method(D_METHOD("set_jiggle_joint_damping", "joint_idx", "damping"), &SkeletonModification2DJiggle::set_jiggle_joint_damping);
+ ClassDB::bind_method(D_METHOD("get_jiggle_joint_damping", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_damping);
+ ClassDB::bind_method(D_METHOD("set_jiggle_joint_use_gravity", "joint_idx", "use_gravity"), &SkeletonModification2DJiggle::set_jiggle_joint_use_gravity);
+ ClassDB::bind_method(D_METHOD("get_jiggle_joint_use_gravity", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_use_gravity);
+ ClassDB::bind_method(D_METHOD("set_jiggle_joint_gravity", "joint_idx", "gravity"), &SkeletonModification2DJiggle::set_jiggle_joint_gravity);
+ ClassDB::bind_method(D_METHOD("get_jiggle_joint_gravity", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_gravity);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "jiggle_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_jiggle_data_chain_length", "get_jiggle_data_chain_length");
+ ADD_GROUP("Default Joint Settings", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness"), "set_stiffness", "get_stiffness");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass"), "set_mass", "get_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01"), "set_damping", "get_damping");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_gravity"), "set_use_gravity", "get_use_gravity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity"), "set_gravity", "get_gravity");
+ ADD_GROUP("", "");
+}
+
+SkeletonModification2DJiggle::SkeletonModification2DJiggle() {
+ stack = nullptr;
+ is_setup = false;
+ jiggle_data_chain = Vector<Jiggle_Joint_Data2D>();
+ stiffness = 3;
+ mass = 0.75;
+ damping = 0.75;
+ use_gravity = false;
+ gravity = Vector2(0, 6.0);
+ enabled = true;
+ editor_draw_gizmo = false; // Nothing to really show in a gizmo right now.
+}
+
+SkeletonModification2DJiggle::~SkeletonModification2DJiggle() {
+}
diff --git a/scene/resources/skeleton_modification_2d_jiggle.h b/scene/resources/skeleton_modification_2d_jiggle.h
new file mode 100644
index 0000000000..e24038a1db
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_jiggle.h
@@ -0,0 +1,139 @@
+/*************************************************************************/
+/* skeleton_modification_2d_jiggle.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETONMODIFICATION2DJIGGLE_H
+#define SKELETONMODIFICATION2DJIGGLE_H
+
+#include "scene/2d/skeleton_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
+
+///////////////////////////////////////
+// SkeletonModification2DJIGGLE
+///////////////////////////////////////
+
+class SkeletonModification2DJiggle : public SkeletonModification2D {
+ GDCLASS(SkeletonModification2DJiggle, SkeletonModification2D);
+
+private:
+ struct Jiggle_Joint_Data2D {
+ int bone_idx = -1;
+ NodePath bone2d_node;
+ ObjectID bone2d_node_cache;
+
+ bool override_defaults = false;
+ float stiffness = 3;
+ float mass = 0.75;
+ float damping = 0.75;
+ bool use_gravity = false;
+ Vector2 gravity = Vector2(0, 6.0);
+
+ Vector2 force = Vector2(0, 0);
+ Vector2 acceleration = Vector2(0, 0);
+ Vector2 velocity = Vector2(0, 0);
+ Vector2 last_position = Vector2(0, 0);
+ Vector2 dynamic_position = Vector2(0, 0);
+
+ Vector2 last_noncollision_position = Vector2(0, 0);
+ };
+
+ Vector<Jiggle_Joint_Data2D> jiggle_data_chain;
+
+ NodePath target_node;
+ ObjectID target_node_cache;
+ void update_target_cache();
+
+ float stiffness = 3;
+ float mass = 0.75;
+ float damping = 0.75;
+ bool use_gravity = false;
+ Vector2 gravity = Vector2(0, 6);
+
+ bool use_colliders = false;
+ uint32_t collision_mask = 1;
+
+ void jiggle_joint_update_bone2d_cache(int p_joint_idx);
+ void _execute_jiggle_joint(int p_joint_idx, Node2D *p_target, float p_delta);
+ void _update_jiggle_joint_data();
+
+protected:
+ static void _bind_methods();
+ bool _set(const StringName &p_path, const Variant &p_value);
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+public:
+ void _execute(float p_delta) override;
+ void _setup_modification(SkeletonModificationStack2D *p_stack) override;
+
+ void set_target_node(const NodePath &p_target_node);
+ NodePath get_target_node() const;
+
+ void set_stiffness(float p_stiffness);
+ float get_stiffness() const;
+ void set_mass(float p_mass);
+ float get_mass() const;
+ void set_damping(float p_damping);
+ float get_damping() const;
+ void set_use_gravity(bool p_use_gravity);
+ bool get_use_gravity() const;
+ void set_gravity(Vector2 p_gravity);
+ Vector2 get_gravity() const;
+
+ void set_use_colliders(bool p_use_colliders);
+ bool get_use_colliders() const;
+ void set_collision_mask(int p_mask);
+ int get_collision_mask() const;
+
+ int get_jiggle_data_chain_length();
+ void set_jiggle_data_chain_length(int p_new_length);
+
+ void set_jiggle_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node);
+ NodePath get_jiggle_joint_bone2d_node(int p_joint_idx) const;
+ void set_jiggle_joint_bone_index(int p_joint_idx, int p_bone_idx);
+ int get_jiggle_joint_bone_index(int p_joint_idx) const;
+
+ void set_jiggle_joint_override(int p_joint_idx, bool p_override);
+ bool get_jiggle_joint_override(int p_joint_idx) const;
+ void set_jiggle_joint_stiffness(int p_joint_idx, float p_stiffness);
+ float get_jiggle_joint_stiffness(int p_joint_idx) const;
+ void set_jiggle_joint_mass(int p_joint_idx, float p_mass);
+ float get_jiggle_joint_mass(int p_joint_idx) const;
+ void set_jiggle_joint_damping(int p_joint_idx, float p_damping);
+ float get_jiggle_joint_damping(int p_joint_idx) const;
+ void set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity);
+ bool get_jiggle_joint_use_gravity(int p_joint_idx) const;
+ void set_jiggle_joint_gravity(int p_joint_idx, Vector2 p_gravity);
+ Vector2 get_jiggle_joint_gravity(int p_joint_idx) const;
+
+ SkeletonModification2DJiggle();
+ ~SkeletonModification2DJiggle();
+};
+
+#endif // SKELETONMODIFICATION2DJIGGLE_H
diff --git a/scene/resources/skeleton_modification_2d_lookat.cpp b/scene/resources/skeleton_modification_2d_lookat.cpp
new file mode 100644
index 0000000000..fd5c8c7cc2
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_lookat.cpp
@@ -0,0 +1,407 @@
+/*************************************************************************/
+/* skeleton_modification_2d_lookat.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_modification_2d_lookat.h"
+#include "scene/2d/skeleton_2d.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif // TOOLS_ENABLED
+
+bool SkeletonModification2DLookAt::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+ if (path.begins_with("enable_constraint")) {
+ set_enable_constraint(p_value);
+ } else if (path.begins_with("constraint_angle_min")) {
+ set_constraint_angle_min(Math::deg2rad(float(p_value)));
+ } else if (path.begins_with("constraint_angle_max")) {
+ set_constraint_angle_max(Math::deg2rad(float(p_value)));
+ } else if (path.begins_with("constraint_angle_invert")) {
+ set_constraint_angle_invert(p_value);
+ } else if (path.begins_with("constraint_in_localspace")) {
+ set_constraint_in_localspace(p_value);
+ } else if (path.begins_with("additional_rotation")) {
+ set_additional_rotation(Math::deg2rad(float(p_value)));
+ }
+
+#ifdef TOOLS_ENABLED
+ if (path.begins_with("editor/draw_gizmo")) {
+ set_editor_draw_gizmo(p_value);
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+}
+
+bool SkeletonModification2DLookAt::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path.begins_with("enable_constraint")) {
+ r_ret = get_enable_constraint();
+ } else if (path.begins_with("constraint_angle_min")) {
+ r_ret = Math::rad2deg(get_constraint_angle_min());
+ } else if (path.begins_with("constraint_angle_max")) {
+ r_ret = Math::rad2deg(get_constraint_angle_max());
+ } else if (path.begins_with("constraint_angle_invert")) {
+ r_ret = get_constraint_angle_invert();
+ } else if (path.begins_with("constraint_in_localspace")) {
+ r_ret = get_constraint_in_localspace();
+ } else if (path.begins_with("additional_rotation")) {
+ r_ret = Math::rad2deg(get_additional_rotation());
+ }
+
+#ifdef TOOLS_ENABLED
+ if (path.begins_with("editor/draw_gizmo")) {
+ r_ret = get_editor_draw_gizmo();
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+}
+
+void SkeletonModification2DLookAt::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "enable_constraint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ if (enable_constraint) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "constraint_angle_min", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "constraint_angle_max", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "constraint_angle_invert", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "constraint_in_localspace", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "additional_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "editor/draw_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+#endif // TOOLS_ENABLED
+}
+
+void SkeletonModification2DLookAt::_execute(float p_delta) {
+ ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
+ "Modification is not setup and therefore cannot execute!");
+ if (!enabled) {
+ return;
+ }
+
+ if (target_node_cache.is_null()) {
+ WARN_PRINT_ONCE("Target cache is out of date. Attempting to update...");
+ update_target_cache();
+ return;
+ }
+
+ if (bone2d_node_cache.is_null() && !bone2d_node.is_empty()) {
+ update_bone2d_cache();
+ WARN_PRINT_ONCE("Bone2D node cache is out of date. Attempting to update...");
+ return;
+ }
+
+ if (target_node_reference == nullptr) {
+ target_node_reference = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache));
+ }
+ if (!target_node_reference || !target_node_reference->is_inside_tree()) {
+ ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!");
+ return;
+ }
+ if (bone_idx <= -1) {
+ ERR_PRINT_ONCE("Bone index is invalid. Cannot execute modification!");
+ return;
+ }
+
+ Bone2D *operation_bone = stack->skeleton->get_bone(bone_idx);
+ if (operation_bone == nullptr) {
+ ERR_PRINT_ONCE("bone_idx for modification does not point to a valid bone! Cannot execute modification");
+ return;
+ }
+
+ Transform2D operation_transform = operation_bone->get_global_transform();
+ Transform2D target_trans = target_node_reference->get_global_transform();
+
+ // Look at the target!
+ operation_transform = operation_transform.looking_at(target_trans.get_origin());
+ // Apply whatever scale it had prior to looking_at
+ operation_transform.set_scale(operation_bone->get_global_transform().get_scale());
+
+ // Account for the direction the bone faces in:
+ operation_transform.set_rotation(operation_transform.get_rotation() - operation_bone->get_bone_angle());
+
+ // Apply additional rotation
+ operation_transform.set_rotation(operation_transform.get_rotation() + additional_rotation);
+
+ // Apply constraints in globalspace:
+ if (enable_constraint && !constraint_in_localspace) {
+ operation_transform.set_rotation(clamp_angle(operation_transform.get_rotation(), constraint_angle_min, constraint_angle_max, constraint_angle_invert));
+ }
+
+ // Convert from a global transform to a local transform via the Bone2D node
+ operation_bone->set_global_transform(operation_transform);
+ operation_transform = operation_bone->get_transform();
+
+ // Apply constraints in localspace:
+ if (enable_constraint && constraint_in_localspace) {
+ operation_transform.set_rotation(clamp_angle(operation_transform.get_rotation(), constraint_angle_min, constraint_angle_max, constraint_angle_invert));
+ }
+
+ // Set the local pose override, and to make sure child bones are also updated, set the transform of the bone.
+ stack->skeleton->set_bone_local_pose_override(bone_idx, operation_transform, stack->strength, true);
+ operation_bone->set_transform(operation_transform);
+}
+
+void SkeletonModification2DLookAt::_setup_modification(SkeletonModificationStack2D *p_stack) {
+ stack = p_stack;
+
+ if (stack != nullptr) {
+ is_setup = true;
+ update_target_cache();
+ update_bone2d_cache();
+ }
+}
+
+void SkeletonModification2DLookAt::_draw_editor_gizmo() {
+ if (!enabled || !is_setup) {
+ return;
+ }
+
+ Bone2D *operation_bone = stack->skeleton->get_bone(bone_idx);
+ editor_draw_angle_constraints(operation_bone, constraint_angle_min, constraint_angle_max,
+ enable_constraint, constraint_in_localspace, constraint_angle_invert);
+}
+
+void SkeletonModification2DLookAt::update_bone2d_cache() {
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update Bone2D cache: modification is not properly setup!");
+ return;
+ }
+
+ bone2d_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(bone2d_node)) {
+ Node *node = stack->skeleton->get_node(bone2d_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update Bone2D cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update Bone2D cache: node is not in the scene tree!");
+ bone2d_node_cache = node->get_instance_id();
+
+ Bone2D *bone = Object::cast_to<Bone2D>(node);
+ if (bone) {
+ bone_idx = bone->get_index_in_skeleton();
+ } else {
+ ERR_FAIL_MSG("Error Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
+ }
+
+ // Set this to null so we update it
+ target_node_reference = nullptr;
+ }
+ }
+ }
+}
+
+void SkeletonModification2DLookAt::set_bone2d_node(const NodePath &p_target_node) {
+ bone2d_node = p_target_node;
+ update_bone2d_cache();
+}
+
+NodePath SkeletonModification2DLookAt::get_bone2d_node() const {
+ return bone2d_node;
+}
+
+int SkeletonModification2DLookAt::get_bone_index() const {
+ return bone_idx;
+}
+
+void SkeletonModification2DLookAt::set_bone_index(int p_bone_idx) {
+ ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
+
+ if (is_setup) {
+ if (stack->skeleton) {
+ ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!");
+ bone_idx = p_bone_idx;
+ bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id();
+ bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx));
+ } else {
+ WARN_PRINT("Cannot verify the bone index for this modification...");
+ bone_idx = p_bone_idx;
+ }
+ } else {
+ WARN_PRINT("Cannot verify the bone index for this modification...");
+ bone_idx = p_bone_idx;
+ }
+
+ notify_property_list_changed();
+}
+
+void SkeletonModification2DLookAt::update_target_cache() {
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!");
+ return;
+ }
+
+ target_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(target_node)) {
+ Node *node = stack->skeleton->get_node(target_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update target cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update target cache: node is not in the scene tree!");
+ target_node_cache = node->get_instance_id();
+ }
+ }
+ }
+}
+
+void SkeletonModification2DLookAt::set_target_node(const NodePath &p_target_node) {
+ target_node = p_target_node;
+ update_target_cache();
+}
+
+NodePath SkeletonModification2DLookAt::get_target_node() const {
+ return target_node;
+}
+
+float SkeletonModification2DLookAt::get_additional_rotation() const {
+ return additional_rotation;
+}
+
+void SkeletonModification2DLookAt::set_additional_rotation(float p_rotation) {
+ additional_rotation = p_rotation;
+}
+
+void SkeletonModification2DLookAt::set_enable_constraint(bool p_constraint) {
+ enable_constraint = p_constraint;
+ notify_property_list_changed();
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+bool SkeletonModification2DLookAt::get_enable_constraint() const {
+ return enable_constraint;
+}
+
+void SkeletonModification2DLookAt::set_constraint_angle_min(float p_angle_min) {
+ constraint_angle_min = p_angle_min;
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+float SkeletonModification2DLookAt::get_constraint_angle_min() const {
+ return constraint_angle_min;
+}
+
+void SkeletonModification2DLookAt::set_constraint_angle_max(float p_angle_max) {
+ constraint_angle_max = p_angle_max;
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+float SkeletonModification2DLookAt::get_constraint_angle_max() const {
+ return constraint_angle_max;
+}
+
+void SkeletonModification2DLookAt::set_constraint_angle_invert(bool p_invert) {
+ constraint_angle_invert = p_invert;
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+bool SkeletonModification2DLookAt::get_constraint_angle_invert() const {
+ return constraint_angle_invert;
+}
+
+void SkeletonModification2DLookAt::set_constraint_in_localspace(bool p_constraint_in_localspace) {
+ constraint_in_localspace = p_constraint_in_localspace;
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+bool SkeletonModification2DLookAt::get_constraint_in_localspace() const {
+ return constraint_in_localspace;
+}
+
+void SkeletonModification2DLookAt::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_bone2d_node", "bone2d_nodepath"), &SkeletonModification2DLookAt::set_bone2d_node);
+ ClassDB::bind_method(D_METHOD("get_bone2d_node"), &SkeletonModification2DLookAt::get_bone2d_node);
+ ClassDB::bind_method(D_METHOD("set_bone_index", "bone_idx"), &SkeletonModification2DLookAt::set_bone_index);
+ ClassDB::bind_method(D_METHOD("get_bone_index"), &SkeletonModification2DLookAt::get_bone_index);
+
+ ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DLookAt::set_target_node);
+ ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DLookAt::get_target_node);
+
+ ClassDB::bind_method(D_METHOD("set_additional_rotation", "rotation"), &SkeletonModification2DLookAt::set_additional_rotation);
+ ClassDB::bind_method(D_METHOD("get_additional_rotation"), &SkeletonModification2DLookAt::get_additional_rotation);
+
+ ClassDB::bind_method(D_METHOD("set_enable_constraint", "enable_constraint"), &SkeletonModification2DLookAt::set_enable_constraint);
+ ClassDB::bind_method(D_METHOD("get_enable_constraint"), &SkeletonModification2DLookAt::get_enable_constraint);
+ ClassDB::bind_method(D_METHOD("set_constraint_angle_min", "angle_min"), &SkeletonModification2DLookAt::set_constraint_angle_min);
+ ClassDB::bind_method(D_METHOD("get_constraint_angle_min"), &SkeletonModification2DLookAt::get_constraint_angle_min);
+ ClassDB::bind_method(D_METHOD("set_constraint_angle_max", "angle_max"), &SkeletonModification2DLookAt::set_constraint_angle_max);
+ ClassDB::bind_method(D_METHOD("get_constraint_angle_max"), &SkeletonModification2DLookAt::get_constraint_angle_max);
+ ClassDB::bind_method(D_METHOD("set_constraint_angle_invert", "invert"), &SkeletonModification2DLookAt::set_constraint_angle_invert);
+ ClassDB::bind_method(D_METHOD("get_constraint_angle_invert"), &SkeletonModification2DLookAt::get_constraint_angle_invert);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_index"), "set_bone_index", "get_bone_index");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D"), "set_bone2d_node", "get_bone2d_node");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node");
+}
+
+SkeletonModification2DLookAt::SkeletonModification2DLookAt() {
+ stack = nullptr;
+ is_setup = false;
+ bone_idx = -1;
+ additional_rotation = 0;
+ enable_constraint = false;
+ constraint_angle_min = 0;
+ constraint_angle_max = Math_PI * 2;
+ constraint_angle_invert = false;
+ enabled = true;
+
+ editor_draw_gizmo = true;
+}
+
+SkeletonModification2DLookAt::~SkeletonModification2DLookAt() {
+}
diff --git a/scene/resources/skeleton_modification_2d_lookat.h b/scene/resources/skeleton_modification_2d_lookat.h
new file mode 100644
index 0000000000..6aff30b826
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_lookat.h
@@ -0,0 +1,100 @@
+/*************************************************************************/
+/* skeleton_modification_2d_lookat.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETONMODIFICATION2DLOOKAT_H
+#define SKELETONMODIFICATION2DLOOKAT_H
+
+#include "scene/2d/skeleton_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
+
+///////////////////////////////////////
+// SkeletonModification2DLookAt
+///////////////////////////////////////
+
+class SkeletonModification2DLookAt : public SkeletonModification2D {
+ GDCLASS(SkeletonModification2DLookAt, SkeletonModification2D);
+
+private:
+ int bone_idx = -1;
+ NodePath bone2d_node;
+ ObjectID bone2d_node_cache;
+
+ NodePath target_node;
+ ObjectID target_node_cache;
+ Node2D *target_node_reference = nullptr;
+
+ float additional_rotation = 0;
+ bool enable_constraint = false;
+ float constraint_angle_min = 0;
+ float constraint_angle_max = (2.0 * Math_PI);
+ bool constraint_angle_invert = false;
+ bool constraint_in_localspace = true;
+
+ void update_bone2d_cache();
+ void update_target_cache();
+
+protected:
+ static void _bind_methods();
+ bool _set(const StringName &p_path, const Variant &p_value);
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+public:
+ void _execute(float p_delta) override;
+ void _setup_modification(SkeletonModificationStack2D *p_stack) override;
+ void _draw_editor_gizmo() override;
+
+ void set_bone2d_node(const NodePath &p_target_node);
+ NodePath get_bone2d_node() const;
+ void set_bone_index(int p_idx);
+ int get_bone_index() const;
+
+ void set_target_node(const NodePath &p_target_node);
+ NodePath get_target_node() const;
+
+ void set_additional_rotation(float p_rotation);
+ float get_additional_rotation() const;
+
+ void set_enable_constraint(bool p_constraint);
+ bool get_enable_constraint() const;
+ void set_constraint_angle_min(float p_angle_min);
+ float get_constraint_angle_min() const;
+ void set_constraint_angle_max(float p_angle_max);
+ float get_constraint_angle_max() const;
+ void set_constraint_angle_invert(bool p_invert);
+ bool get_constraint_angle_invert() const;
+ void set_constraint_in_localspace(bool p_constraint_in_localspace);
+ bool get_constraint_in_localspace() const;
+
+ SkeletonModification2DLookAt();
+ ~SkeletonModification2DLookAt();
+};
+
+#endif // SKELETONMODIFICATION2DLOOKAT_H
diff --git a/scene/resources/skeleton_modification_2d_physicalbones.cpp b/scene/resources/skeleton_modification_2d_physicalbones.cpp
new file mode 100644
index 0000000000..9dedb93f36
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_physicalbones.cpp
@@ -0,0 +1,297 @@
+/*************************************************************************/
+/* skeleton_modification_2d_physicalbones.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_modification_2d_physicalbones.h"
+#include "scene/2d/physical_bone_2d.h"
+#include "scene/2d/skeleton_2d.h"
+
+bool SkeletonModification2DPhysicalBones::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+#ifdef TOOLS_ENABLED
+ // Exposes a way to fetch the PhysicalBone2D nodes from the Godot editor.
+ if (is_setup) {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (path.begins_with("fetch_bones")) {
+ fetch_physical_bones();
+ notify_property_list_changed();
+ return true;
+ }
+ }
+ }
+#endif //TOOLS_ENABLED
+
+ if (path.begins_with("joint_")) {
+ int which = path.get_slicec('_', 1).to_int();
+ String what = path.get_slicec('_', 2);
+ ERR_FAIL_INDEX_V(which, physical_bone_chain.size(), false);
+
+ if (what == "nodepath") {
+ set_physical_bone_node(which, p_value);
+ }
+ return true;
+ }
+ return true;
+}
+
+bool SkeletonModification2DPhysicalBones::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (path.begins_with("fetch_bones")) {
+ return true; // Do nothing!
+ }
+ }
+#endif //TOOLS_ENABLED
+
+ if (path.begins_with("joint_")) {
+ int which = path.get_slicec('_', 1).to_int();
+ String what = path.get_slicec('_', 2);
+ ERR_FAIL_INDEX_V(which, physical_bone_chain.size(), false);
+
+ if (what == "nodepath") {
+ r_ret = get_physical_bone_node(which);
+ }
+ return true;
+ }
+ return true;
+}
+
+void SkeletonModification2DPhysicalBones::_get_property_list(List<PropertyInfo> *p_list) const {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "fetch_bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+#endif //TOOLS_ENABLED
+
+ for (int i = 0; i < physical_bone_chain.size(); i++) {
+ String base_string = "joint_" + itos(i) + "_";
+
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicalBone2D", PROPERTY_USAGE_DEFAULT));
+ }
+}
+
+void SkeletonModification2DPhysicalBones::_execute(float p_delta) {
+ ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
+ "Modification is not setup and therefore cannot execute!");
+ if (!enabled) {
+ return;
+ }
+
+ if (_simulation_state_dirty) {
+ _update_simulation_state();
+ }
+
+ for (int i = 0; i < physical_bone_chain.size(); i++) {
+ PhysicalBone_Data2D bone_data = physical_bone_chain[i];
+ if (bone_data.physical_bone_node_cache.is_null()) {
+ WARN_PRINT_ONCE("PhysicalBone2D cache " + itos(i) + " is out of date. Attempting to update...");
+ _physical_bone_update_cache(i);
+ continue;
+ }
+
+ PhysicalBone2D *physical_bone = Object::cast_to<PhysicalBone2D>(ObjectDB::get_instance(bone_data.physical_bone_node_cache));
+ if (!physical_bone) {
+ ERR_PRINT_ONCE("PhysicalBone2D not found at index " + itos(i) + "!");
+ return;
+ }
+ if (physical_bone->get_bone2d_index() < 0 || physical_bone->get_bone2d_index() > stack->skeleton->get_bone_count()) {
+ ERR_PRINT_ONCE("PhysicalBone2D at index " + itos(i) + " has invalid Bone2D!");
+ return;
+ }
+ Bone2D *bone_2d = stack->skeleton->get_bone(physical_bone->get_bone2d_index());
+
+ if (physical_bone->get_simulate_physics() && !physical_bone->get_follow_bone_when_simulating()) {
+ bone_2d->set_global_transform(physical_bone->get_global_transform());
+ stack->skeleton->set_bone_local_pose_override(physical_bone->get_bone2d_index(), bone_2d->get_transform(), stack->strength, true);
+ }
+ }
+}
+
+void SkeletonModification2DPhysicalBones::_setup_modification(SkeletonModificationStack2D *p_stack) {
+ stack = p_stack;
+
+ if (stack) {
+ is_setup = true;
+
+ if (stack->skeleton) {
+ for (int i = 0; i < physical_bone_chain.size(); i++) {
+ _physical_bone_update_cache(i);
+ }
+ }
+ }
+}
+
+void SkeletonModification2DPhysicalBones::_physical_bone_update_cache(int p_joint_idx) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, physical_bone_chain.size(), "Cannot update PhysicalBone2D cache: joint index out of range!");
+ if (!is_setup || !stack) {
+ if (!stack) {
+ ERR_PRINT_ONCE("Cannot update PhysicalBone2D cache: modification is not properly setup!");
+ }
+ return;
+ }
+
+ physical_bone_chain.write[p_joint_idx].physical_bone_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(physical_bone_chain[p_joint_idx].physical_bone_node)) {
+ Node *node = stack->skeleton->get_node(physical_bone_chain[p_joint_idx].physical_bone_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update Physical Bone2D " + itos(p_joint_idx) + " cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update Physical Bone2D " + itos(p_joint_idx) + " cache: node is not in scene tree!");
+ physical_bone_chain.write[p_joint_idx].physical_bone_node_cache = node->get_instance_id();
+ }
+ }
+ }
+}
+
+int SkeletonModification2DPhysicalBones::get_physical_bone_chain_length() {
+ return physical_bone_chain.size();
+}
+
+void SkeletonModification2DPhysicalBones::set_physical_bone_chain_length(int p_length) {
+ ERR_FAIL_COND(p_length < 0);
+ physical_bone_chain.resize(p_length);
+ notify_property_list_changed();
+}
+
+void SkeletonModification2DPhysicalBones::fetch_physical_bones() {
+ ERR_FAIL_COND_MSG(!stack, "No modification stack found! Cannot fetch physical bones!");
+ ERR_FAIL_COND_MSG(!stack->skeleton, "No skeleton found! Cannot fetch physical bones!");
+
+ physical_bone_chain.clear();
+
+ List<Node *> node_queue = List<Node *>();
+ node_queue.push_back(stack->skeleton);
+
+ while (node_queue.size() > 0) {
+ Node *node_to_process = node_queue[0];
+ node_queue.pop_front();
+
+ if (node_to_process != nullptr) {
+ PhysicalBone2D *potential_bone = Object::cast_to<PhysicalBone2D>(node_to_process);
+ if (potential_bone) {
+ PhysicalBone_Data2D new_data = PhysicalBone_Data2D();
+ new_data.physical_bone_node = stack->skeleton->get_path_to(potential_bone);
+ new_data.physical_bone_node_cache = potential_bone->get_instance_id();
+ physical_bone_chain.push_back(new_data);
+ }
+ for (int i = 0; i < node_to_process->get_child_count(); i++) {
+ node_queue.push_back(node_to_process->get_child(i));
+ }
+ }
+ }
+}
+
+void SkeletonModification2DPhysicalBones::start_simulation(const TypedArray<StringName> &p_bones) {
+ _simulation_state_dirty = true;
+ _simulation_state_dirty_names = p_bones;
+ _simulation_state_dirty_process = true;
+
+ if (is_setup) {
+ _update_simulation_state();
+ }
+}
+
+void SkeletonModification2DPhysicalBones::stop_simulation(const TypedArray<StringName> &p_bones) {
+ _simulation_state_dirty = true;
+ _simulation_state_dirty_names = p_bones;
+ _simulation_state_dirty_process = false;
+
+ if (is_setup) {
+ _update_simulation_state();
+ }
+}
+
+void SkeletonModification2DPhysicalBones::_update_simulation_state() {
+ if (!_simulation_state_dirty) {
+ return;
+ }
+ _simulation_state_dirty = false;
+
+ if (_simulation_state_dirty_names.size() <= 0) {
+ for (int i = 0; i < physical_bone_chain.size(); i++) {
+ PhysicalBone2D *physical_bone = Object::cast_to<PhysicalBone2D>(stack->skeleton->get_node(physical_bone_chain[i].physical_bone_node));
+ if (!physical_bone) {
+ continue;
+ }
+
+ physical_bone->set_simulate_physics(_simulation_state_dirty_process);
+ }
+ } else {
+ for (int i = 0; i < physical_bone_chain.size(); i++) {
+ PhysicalBone2D *physical_bone = Object::cast_to<PhysicalBone2D>(ObjectDB::get_instance(physical_bone_chain[i].physical_bone_node_cache));
+ if (!physical_bone) {
+ continue;
+ }
+ if (_simulation_state_dirty_names.has(physical_bone->get_name())) {
+ physical_bone->set_simulate_physics(_simulation_state_dirty_process);
+ }
+ }
+ }
+}
+
+void SkeletonModification2DPhysicalBones::set_physical_bone_node(int p_joint_idx, const NodePath &p_nodepath) {
+ ERR_FAIL_INDEX_MSG(p_joint_idx, physical_bone_chain.size(), "Joint index out of range!");
+ physical_bone_chain.write[p_joint_idx].physical_bone_node = p_nodepath;
+ _physical_bone_update_cache(p_joint_idx);
+}
+
+NodePath SkeletonModification2DPhysicalBones::get_physical_bone_node(int p_joint_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_joint_idx, physical_bone_chain.size(), NodePath(), "Joint index out of range!");
+ return physical_bone_chain[p_joint_idx].physical_bone_node;
+}
+
+void SkeletonModification2DPhysicalBones::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_physical_bone_chain_length", "length"), &SkeletonModification2DPhysicalBones::set_physical_bone_chain_length);
+ ClassDB::bind_method(D_METHOD("get_physical_bone_chain_length"), &SkeletonModification2DPhysicalBones::get_physical_bone_chain_length);
+
+ ClassDB::bind_method(D_METHOD("set_physical_bone_node", "joint_idx", "physicalbone2d_node"), &SkeletonModification2DPhysicalBones::set_physical_bone_node);
+ ClassDB::bind_method(D_METHOD("get_physical_bone_node", "joint_idx"), &SkeletonModification2DPhysicalBones::get_physical_bone_node);
+
+ ClassDB::bind_method(D_METHOD("fetch_physical_bones"), &SkeletonModification2DPhysicalBones::fetch_physical_bones);
+ ClassDB::bind_method(D_METHOD("start_simulation", "bones"), &SkeletonModification2DPhysicalBones::start_simulation, DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("stop_simulation", "bones"), &SkeletonModification2DPhysicalBones::stop_simulation, DEFVAL(Array()));
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "physical_bone_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_physical_bone_chain_length", "get_physical_bone_chain_length");
+}
+
+SkeletonModification2DPhysicalBones::SkeletonModification2DPhysicalBones() {
+ stack = nullptr;
+ is_setup = false;
+ physical_bone_chain = Vector<PhysicalBone_Data2D>();
+ enabled = true;
+ editor_draw_gizmo = false; // Nothing to really show in a gizmo right now.
+}
+
+SkeletonModification2DPhysicalBones::~SkeletonModification2DPhysicalBones() {
+}
diff --git a/scene/resources/skeleton_modification_2d_physicalbones.h b/scene/resources/skeleton_modification_2d_physicalbones.h
new file mode 100644
index 0000000000..cdf6a5f570
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_physicalbones.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* skeleton_modification_2d_physicalbones.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETONMODIFICATION2DPHYSICALBONES_H
+#define SKELETONMODIFICATION2DPHYSICALBONES_H
+
+#include "scene/2d/skeleton_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
+
+///////////////////////////////////////
+// SkeletonModification2DJIGGLE
+///////////////////////////////////////
+
+class SkeletonModification2DPhysicalBones : public SkeletonModification2D {
+ GDCLASS(SkeletonModification2DPhysicalBones, SkeletonModification2D);
+
+private:
+ struct PhysicalBone_Data2D {
+ NodePath physical_bone_node;
+ ObjectID physical_bone_node_cache;
+ };
+ Vector<PhysicalBone_Data2D> physical_bone_chain;
+
+ void _physical_bone_update_cache(int p_joint_idx);
+
+ bool _simulation_state_dirty = false;
+ TypedArray<StringName> _simulation_state_dirty_names;
+ bool _simulation_state_dirty_process;
+ void _update_simulation_state();
+
+protected:
+ static void _bind_methods();
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+public:
+ void _execute(float p_delta) override;
+ void _setup_modification(SkeletonModificationStack2D *p_stack) override;
+
+ int get_physical_bone_chain_length();
+ void set_physical_bone_chain_length(int p_new_length);
+
+ void set_physical_bone_node(int p_joint_idx, const NodePath &p_path);
+ NodePath get_physical_bone_node(int p_joint_idx) const;
+
+ void fetch_physical_bones();
+ void start_simulation(const TypedArray<StringName> &p_bones);
+ void stop_simulation(const TypedArray<StringName> &p_bones);
+
+ SkeletonModification2DPhysicalBones();
+ ~SkeletonModification2DPhysicalBones();
+};
+
+#endif // SKELETONMODIFICATION2DPHYSICALBONES_H
diff --git a/scene/resources/skeleton_modification_2d_stackholder.cpp b/scene/resources/skeleton_modification_2d_stackholder.cpp
new file mode 100644
index 0000000000..9436092cd9
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_stackholder.cpp
@@ -0,0 +1,131 @@
+/*************************************************************************/
+/* skeleton_modification_2d_stackholder.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_modification_2d_stackholder.h"
+#include "scene/2d/skeleton_2d.h"
+
+bool SkeletonModification2DStackHolder::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+ if (path == "held_modification_stack") {
+ set_held_modification_stack(p_value);
+ }
+
+#ifdef TOOLS_ENABLED
+ if (path == "editor/draw_gizmo") {
+ set_editor_draw_gizmo(p_value);
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+}
+
+bool SkeletonModification2DStackHolder::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path == "held_modification_stack") {
+ r_ret = get_held_modification_stack();
+ }
+
+#ifdef TOOLS_ENABLED
+ if (path == "editor/draw_gizmo") {
+ r_ret = get_editor_draw_gizmo();
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+}
+
+void SkeletonModification2DStackHolder::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "held_modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "editor/draw_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+#endif // TOOLS_ENABLED
+}
+
+void SkeletonModification2DStackHolder::_execute(float p_delta) {
+ ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
+ "Modification is not setup and therefore cannot execute!");
+
+ if (held_modification_stack.is_valid()) {
+ held_modification_stack->execute(p_delta, execution_mode);
+ }
+}
+
+void SkeletonModification2DStackHolder::_setup_modification(SkeletonModificationStack2D *p_stack) {
+ stack = p_stack;
+
+ if (stack != nullptr) {
+ is_setup = true;
+
+ if (held_modification_stack.is_valid()) {
+ held_modification_stack->set_skeleton(stack->get_skeleton());
+ held_modification_stack->setup();
+ }
+ }
+}
+
+void SkeletonModification2DStackHolder::_draw_editor_gizmo() {
+ if (stack) {
+ if (held_modification_stack.is_valid()) {
+ held_modification_stack->draw_editor_gizmos();
+ }
+ }
+}
+
+void SkeletonModification2DStackHolder::set_held_modification_stack(Ref<SkeletonModificationStack2D> p_held_stack) {
+ held_modification_stack = p_held_stack;
+
+ if (is_setup && held_modification_stack.is_valid()) {
+ held_modification_stack->set_skeleton(stack->get_skeleton());
+ held_modification_stack->setup();
+ }
+}
+
+Ref<SkeletonModificationStack2D> SkeletonModification2DStackHolder::get_held_modification_stack() const {
+ return held_modification_stack;
+}
+
+void SkeletonModification2DStackHolder::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_held_modification_stack", "held_modification_stack"), &SkeletonModification2DStackHolder::set_held_modification_stack);
+ ClassDB::bind_method(D_METHOD("get_held_modification_stack"), &SkeletonModification2DStackHolder::get_held_modification_stack);
+}
+
+SkeletonModification2DStackHolder::SkeletonModification2DStackHolder() {
+ stack = nullptr;
+ is_setup = false;
+ enabled = true;
+}
+
+SkeletonModification2DStackHolder::~SkeletonModification2DStackHolder() {
+}
diff --git a/scene/resources/skeleton_modification_2d_stackholder.h b/scene/resources/skeleton_modification_2d_stackholder.h
new file mode 100644
index 0000000000..9cc38e3942
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_stackholder.h
@@ -0,0 +1,64 @@
+/*************************************************************************/
+/* skeleton_modification_2d_stackholder.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETONMODIFICATION2DSTACKHOLDER_H
+#define SKELETONMODIFICATION2DSTACKHOLDER_H
+
+#include "scene/2d/skeleton_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
+
+///////////////////////////////////////
+// SkeletonModification2DJIGGLE
+///////////////////////////////////////
+
+class SkeletonModification2DStackHolder : public SkeletonModification2D {
+ GDCLASS(SkeletonModification2DStackHolder, SkeletonModification2D);
+
+protected:
+ static void _bind_methods();
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+public:
+ Ref<SkeletonModificationStack2D> held_modification_stack;
+
+ void _execute(float p_delta) override;
+ void _setup_modification(SkeletonModificationStack2D *p_stack) override;
+ void _draw_editor_gizmo() override;
+
+ void set_held_modification_stack(Ref<SkeletonModificationStack2D> p_held_stack);
+ Ref<SkeletonModificationStack2D> get_held_modification_stack() const;
+
+ SkeletonModification2DStackHolder();
+ ~SkeletonModification2DStackHolder();
+};
+
+#endif // SKELETONMODIFICATION2DSTACKHOLDER_H
diff --git a/scene/resources/skeleton_modification_2d_twoboneik.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp
new file mode 100644
index 0000000000..0a91290015
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp
@@ -0,0 +1,481 @@
+/*************************************************************************/
+/* skeleton_modification_2d_twoboneik.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_modification_2d_twoboneik.h"
+#include "scene/2d/skeleton_2d.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif // TOOLS_ENABLED
+
+bool SkeletonModification2DTwoBoneIK::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+ if (path == "joint_one_bone_idx") {
+ set_joint_one_bone_idx(p_value);
+ } else if (path == "joint_one_bone2d_node") {
+ set_joint_one_bone2d_node(p_value);
+ } else if (path == "joint_two_bone_idx") {
+ set_joint_two_bone_idx(p_value);
+ } else if (path == "joint_two_bone2d_node") {
+ set_joint_two_bone2d_node(p_value);
+ }
+
+#ifdef TOOLS_ENABLED
+ if (path.begins_with("editor/draw_gizmo")) {
+ set_editor_draw_gizmo(p_value);
+ } else if (path.begins_with("editor/draw_min_max")) {
+ set_editor_draw_min_max(p_value);
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+}
+
+bool SkeletonModification2DTwoBoneIK::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path == "joint_one_bone_idx") {
+ r_ret = get_joint_one_bone_idx();
+ } else if (path == "joint_one_bone2d_node") {
+ r_ret = get_joint_one_bone2d_node();
+ } else if (path == "joint_two_bone_idx") {
+ r_ret = get_joint_two_bone_idx();
+ } else if (path == "joint_two_bone2d_node") {
+ r_ret = get_joint_two_bone2d_node();
+ }
+
+#ifdef TOOLS_ENABLED
+ if (path.begins_with("editor/draw_gizmo")) {
+ r_ret = get_editor_draw_gizmo();
+ } else if (path.begins_with("editor/draw_min_max")) {
+ r_ret = get_editor_draw_min_max();
+ }
+#endif // TOOLS_ENABLED
+
+ return true;
+}
+
+void SkeletonModification2DTwoBoneIK::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::INT, "joint_one_bone_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, "joint_one_bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT));
+
+ p_list->push_back(PropertyInfo(Variant::INT, "joint_two_bone_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, "joint_two_bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT));
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "editor/draw_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "editor/draw_min_max", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ }
+#endif // TOOLS_ENABLED
+}
+
+void SkeletonModification2DTwoBoneIK::_execute(float p_delta) {
+ ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
+ "Modification is not setup and therefore cannot execute!");
+ if (!enabled) {
+ return;
+ }
+
+ if (target_node_cache.is_null()) {
+ WARN_PRINT_ONCE("Target cache is out of date. Attempting to update...");
+ update_target_cache();
+ return;
+ }
+
+ if (joint_one_bone2d_node_cache.is_null() && !joint_one_bone2d_node.is_empty()) {
+ WARN_PRINT_ONCE("Joint one Bone2D node cache is out of date. Attempting to update...");
+ update_joint_one_bone2d_cache();
+ }
+ if (joint_two_bone2d_node_cache.is_null() && !joint_two_bone2d_node.is_empty()) {
+ WARN_PRINT_ONCE("Joint two Bone2D node cache is out of date. Attempting to update...");
+ update_joint_two_bone2d_cache();
+ }
+
+ Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache));
+ if (!target || !target->is_inside_tree()) {
+ ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!");
+ return;
+ }
+
+ Bone2D *joint_one_bone = stack->skeleton->get_bone(joint_one_bone_idx);
+ if (joint_one_bone == nullptr) {
+ ERR_PRINT_ONCE("Joint one bone_idx does not point to a valid bone! Cannot execute modification!");
+ return;
+ }
+
+ Bone2D *joint_two_bone = stack->skeleton->get_bone(joint_two_bone_idx);
+ if (joint_two_bone == nullptr) {
+ ERR_PRINT_ONCE("Joint two bone_idx does not point to a valid bone! Cannot execute modification!");
+ return;
+ }
+
+ // Adopted from the links below:
+ // http://theorangeduck.com/page/simple-two-joint
+ // https://www.alanzucconi.com/2018/05/02/ik-2d-2/
+ // With modifications by TwistedTwigleg
+ Vector2 target_difference = target->get_global_transform().get_origin() - joint_one_bone->get_global_transform().get_origin();
+ float joint_one_to_target = target_difference.length();
+ float angle_atan = Math::atan2(target_difference.y, target_difference.x);
+
+ float bone_one_length = joint_one_bone->get_length() * MIN(joint_one_bone->get_global_scale().x, joint_one_bone->get_global_scale().y);
+ float bone_two_length = joint_two_bone->get_length() * MIN(joint_two_bone->get_global_scale().x, joint_two_bone->get_global_scale().y);
+ bool override_angles_due_to_out_of_range = false;
+
+ if (joint_one_to_target < target_minimum_distance) {
+ joint_one_to_target = target_minimum_distance;
+ }
+ if (joint_one_to_target > target_maximum_distance && target_maximum_distance > 0.0) {
+ joint_one_to_target = target_maximum_distance;
+ }
+
+ if (bone_one_length + bone_two_length < joint_one_to_target) {
+ override_angles_due_to_out_of_range = true;
+ }
+
+ if (!override_angles_due_to_out_of_range) {
+ float angle_0 = Math::acos(((joint_one_to_target * joint_one_to_target) + (bone_one_length * bone_one_length) - (bone_two_length * bone_two_length)) / (2.0 * joint_one_to_target * bone_one_length));
+ float angle_1 = Math::acos(((bone_two_length * bone_two_length) + (bone_one_length * bone_one_length) - (joint_one_to_target * joint_one_to_target)) / (2.0 * bone_two_length * bone_one_length));
+
+ if (flip_bend_direction) {
+ angle_0 = -angle_0;
+ angle_1 = -angle_1;
+ }
+
+ if (isnan(angle_0) || isnan(angle_1)) {
+ // We cannot solve for this angle! Do nothing to avoid setting the rotation (and scale) to NaN.
+ } else {
+ joint_one_bone->set_global_rotation(angle_atan - angle_0 - joint_one_bone->get_bone_angle());
+ joint_two_bone->set_rotation(-Math_PI - angle_1 - joint_two_bone->get_bone_angle() + joint_one_bone->get_bone_angle());
+ }
+ } else {
+ joint_one_bone->set_global_rotation(angle_atan - joint_one_bone->get_bone_angle());
+ joint_two_bone->set_global_rotation(angle_atan - joint_two_bone->get_bone_angle());
+ }
+
+ stack->skeleton->set_bone_local_pose_override(joint_one_bone_idx, joint_one_bone->get_transform(), stack->strength, true);
+ stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, joint_two_bone->get_transform(), stack->strength, true);
+}
+
+void SkeletonModification2DTwoBoneIK::_setup_modification(SkeletonModificationStack2D *p_stack) {
+ stack = p_stack;
+
+ if (stack) {
+ is_setup = true;
+ update_target_cache();
+ update_joint_one_bone2d_cache();
+ update_joint_two_bone2d_cache();
+ }
+}
+
+void SkeletonModification2DTwoBoneIK::_draw_editor_gizmo() {
+ if (!enabled || !is_setup) {
+ return;
+ }
+
+ Bone2D *operation_bone_one = stack->skeleton->get_bone(joint_one_bone_idx);
+ if (!operation_bone_one) {
+ return;
+ }
+ stack->skeleton->draw_set_transform(
+ stack->skeleton->get_global_transform().affine_inverse().xform(operation_bone_one->get_global_position()),
+ operation_bone_one->get_global_rotation() - stack->skeleton->get_global_rotation());
+
+ Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4);
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
+ }
+#endif // TOOLS_ENABLED
+
+ if (flip_bend_direction) {
+ float angle = -(Math_PI * 0.5) + operation_bone_one->get_bone_angle();
+ stack->skeleton->draw_line(Vector2(0, 0), Vector2(Math::cos(angle), sin(angle)) * (operation_bone_one->get_length() * 0.5), bone_ik_color, 2.0);
+ } else {
+ float angle = (Math_PI * 0.5) + operation_bone_one->get_bone_angle();
+ stack->skeleton->draw_line(Vector2(0, 0), Vector2(Math::cos(angle), sin(angle)) * (operation_bone_one->get_length() * 0.5), bone_ik_color, 2.0);
+ }
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (editor_draw_min_max) {
+ if (target_maximum_distance != 0.0 || target_minimum_distance != 0.0) {
+ Vector2 target_direction = Vector2(0, 1);
+ if (target_node_cache.is_valid()) {
+ stack->skeleton->draw_set_transform(Vector2(0, 0), 0.0);
+ Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache));
+ target_direction = operation_bone_one->get_global_position().direction_to(target->get_global_position());
+ }
+
+ stack->skeleton->draw_circle(target_direction * target_minimum_distance, 8, bone_ik_color);
+ stack->skeleton->draw_circle(target_direction * target_maximum_distance, 8, bone_ik_color);
+ stack->skeleton->draw_line(target_direction * target_minimum_distance, target_direction * target_maximum_distance, bone_ik_color, 2.0);
+ }
+ }
+ }
+#endif // TOOLS_ENABLED
+}
+
+void SkeletonModification2DTwoBoneIK::update_target_cache() {
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!");
+ return;
+ }
+
+ target_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(target_node)) {
+ Node *node = stack->skeleton->get_node(target_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update target cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update target cache: node is not in the scene tree!");
+ target_node_cache = node->get_instance_id();
+ }
+ }
+ }
+}
+
+void SkeletonModification2DTwoBoneIK::update_joint_one_bone2d_cache() {
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update joint one Bone2D cache: modification is not properly setup!");
+ return;
+ }
+
+ joint_one_bone2d_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(joint_one_bone2d_node)) {
+ Node *node = stack->skeleton->get_node(joint_one_bone2d_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update update joint one Bone2D cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update update joint one Bone2D cache: node is not in the scene tree!");
+ joint_one_bone2d_node_cache = node->get_instance_id();
+
+ Bone2D *bone = Object::cast_to<Bone2D>(node);
+ if (bone) {
+ joint_one_bone_idx = bone->get_index_in_skeleton();
+ } else {
+ ERR_FAIL_MSG("update joint one Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
+ }
+ }
+ }
+ }
+}
+
+void SkeletonModification2DTwoBoneIK::update_joint_two_bone2d_cache() {
+ if (!is_setup || !stack) {
+ ERR_PRINT_ONCE("Cannot update joint two Bone2D cache: modification is not properly setup!");
+ return;
+ }
+
+ joint_two_bone2d_node_cache = ObjectID();
+ if (stack->skeleton) {
+ if (stack->skeleton->is_inside_tree()) {
+ if (stack->skeleton->has_node(joint_two_bone2d_node)) {
+ Node *node = stack->skeleton->get_node(joint_two_bone2d_node);
+ ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
+ "Cannot update update joint two Bone2D cache: node is this modification's skeleton or cannot be found!");
+ ERR_FAIL_COND_MSG(!node->is_inside_tree(),
+ "Cannot update update joint two Bone2D cache: node is not in scene tree!");
+ joint_two_bone2d_node_cache = node->get_instance_id();
+
+ Bone2D *bone = Object::cast_to<Bone2D>(node);
+ if (bone) {
+ joint_two_bone_idx = bone->get_index_in_skeleton();
+ } else {
+ ERR_FAIL_MSG("update joint two Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
+ }
+ }
+ }
+ }
+}
+
+void SkeletonModification2DTwoBoneIK::set_target_node(const NodePath &p_target_node) {
+ target_node = p_target_node;
+ update_target_cache();
+}
+
+NodePath SkeletonModification2DTwoBoneIK::get_target_node() const {
+ return target_node;
+}
+
+void SkeletonModification2DTwoBoneIK::set_joint_one_bone2d_node(const NodePath &p_target_node) {
+ joint_one_bone2d_node = p_target_node;
+ update_joint_one_bone2d_cache();
+ notify_property_list_changed();
+}
+
+void SkeletonModification2DTwoBoneIK::set_target_minimum_distance(float p_distance) {
+ ERR_FAIL_COND_MSG(p_distance < 0, "Target minimum distance cannot be less than zero!");
+ target_minimum_distance = p_distance;
+}
+
+float SkeletonModification2DTwoBoneIK::get_target_minimum_distance() const {
+ return target_minimum_distance;
+}
+
+void SkeletonModification2DTwoBoneIK::set_target_maximum_distance(float p_distance) {
+ ERR_FAIL_COND_MSG(p_distance < 0, "Target maximum distance cannot be less than zero!");
+ target_maximum_distance = p_distance;
+}
+
+float SkeletonModification2DTwoBoneIK::get_target_maximum_distance() const {
+ return target_maximum_distance;
+}
+
+void SkeletonModification2DTwoBoneIK::set_flip_bend_direction(bool p_flip_direction) {
+ flip_bend_direction = p_flip_direction;
+
+#ifdef TOOLS_ENABLED
+ if (stack && is_setup) {
+ stack->set_editor_gizmos_dirty(true);
+ }
+#endif // TOOLS_ENABLED
+}
+
+bool SkeletonModification2DTwoBoneIK::get_flip_bend_direction() const {
+ return flip_bend_direction;
+}
+
+NodePath SkeletonModification2DTwoBoneIK::get_joint_one_bone2d_node() const {
+ return joint_one_bone2d_node;
+}
+
+void SkeletonModification2DTwoBoneIK::set_joint_two_bone2d_node(const NodePath &p_target_node) {
+ joint_two_bone2d_node = p_target_node;
+ update_joint_two_bone2d_cache();
+ notify_property_list_changed();
+}
+
+NodePath SkeletonModification2DTwoBoneIK::get_joint_two_bone2d_node() const {
+ return joint_two_bone2d_node;
+}
+
+void SkeletonModification2DTwoBoneIK::set_joint_one_bone_idx(int p_bone_idx) {
+ ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
+
+ if (is_setup) {
+ if (stack->skeleton) {
+ ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!");
+ joint_one_bone_idx = p_bone_idx;
+ joint_one_bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id();
+ joint_one_bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx));
+ } else {
+ WARN_PRINT("TwoBoneIK: Cannot verify the joint bone index for joint one...");
+ joint_one_bone_idx = p_bone_idx;
+ }
+ } else {
+ WARN_PRINT("TwoBoneIK: Cannot verify the joint bone index for joint one...");
+ joint_one_bone_idx = p_bone_idx;
+ }
+
+ notify_property_list_changed();
+}
+
+int SkeletonModification2DTwoBoneIK::get_joint_one_bone_idx() const {
+ return joint_one_bone_idx;
+}
+
+void SkeletonModification2DTwoBoneIK::set_joint_two_bone_idx(int p_bone_idx) {
+ ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
+
+ if (is_setup) {
+ if (stack->skeleton) {
+ ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!");
+ joint_two_bone_idx = p_bone_idx;
+ joint_two_bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id();
+ joint_two_bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx));
+ } else {
+ WARN_PRINT("TwoBoneIK: Cannot verify the joint bone index for joint two...");
+ joint_two_bone_idx = p_bone_idx;
+ }
+ } else {
+ WARN_PRINT("TwoBoneIK: Cannot verify the joint bone index for joint two...");
+ joint_two_bone_idx = p_bone_idx;
+ }
+
+ notify_property_list_changed();
+}
+
+int SkeletonModification2DTwoBoneIK::get_joint_two_bone_idx() const {
+ return joint_two_bone_idx;
+}
+
+#ifdef TOOLS_ENABLED
+void SkeletonModification2DTwoBoneIK::set_editor_draw_min_max(bool p_draw) {
+ editor_draw_min_max = p_draw;
+}
+
+bool SkeletonModification2DTwoBoneIK::get_editor_draw_min_max() const {
+ return editor_draw_min_max;
+}
+#endif // TOOLS_ENABLED
+
+void SkeletonModification2DTwoBoneIK::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DTwoBoneIK::set_target_node);
+ ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DTwoBoneIK::get_target_node);
+
+ ClassDB::bind_method(D_METHOD("set_target_minimum_distance", "minimum_distance"), &SkeletonModification2DTwoBoneIK::set_target_minimum_distance);
+ ClassDB::bind_method(D_METHOD("get_target_minimum_distance"), &SkeletonModification2DTwoBoneIK::get_target_minimum_distance);
+ ClassDB::bind_method(D_METHOD("set_target_maximum_distance", "maximum_distance"), &SkeletonModification2DTwoBoneIK::set_target_maximum_distance);
+ ClassDB::bind_method(D_METHOD("get_target_maximum_distance"), &SkeletonModification2DTwoBoneIK::get_target_maximum_distance);
+ ClassDB::bind_method(D_METHOD("set_flip_bend_direction", "flip_direction"), &SkeletonModification2DTwoBoneIK::set_flip_bend_direction);
+ ClassDB::bind_method(D_METHOD("get_flip_bend_direction"), &SkeletonModification2DTwoBoneIK::get_flip_bend_direction);
+
+ ClassDB::bind_method(D_METHOD("set_joint_one_bone2d_node", "bone2d_node"), &SkeletonModification2DTwoBoneIK::set_joint_one_bone2d_node);
+ ClassDB::bind_method(D_METHOD("get_joint_one_bone2d_node"), &SkeletonModification2DTwoBoneIK::get_joint_one_bone2d_node);
+ ClassDB::bind_method(D_METHOD("set_joint_one_bone_idx", "bone_idx"), &SkeletonModification2DTwoBoneIK::set_joint_one_bone_idx);
+ ClassDB::bind_method(D_METHOD("get_joint_one_bone_idx"), &SkeletonModification2DTwoBoneIK::get_joint_one_bone_idx);
+
+ ClassDB::bind_method(D_METHOD("set_joint_two_bone2d_node", "bone2d_node"), &SkeletonModification2DTwoBoneIK::set_joint_two_bone2d_node);
+ ClassDB::bind_method(D_METHOD("get_joint_two_bone2d_node"), &SkeletonModification2DTwoBoneIK::get_joint_two_bone2d_node);
+ ClassDB::bind_method(D_METHOD("set_joint_two_bone_idx", "bone_idx"), &SkeletonModification2DTwoBoneIK::set_joint_two_bone_idx);
+ ClassDB::bind_method(D_METHOD("get_joint_two_bone_idx"), &SkeletonModification2DTwoBoneIK::get_joint_two_bone_idx);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_minimum_distance", PROPERTY_HINT_RANGE, "0, 100000000, 0.01"), "set_target_minimum_distance", "get_target_minimum_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_maximum_distance", PROPERTY_HINT_NONE, "0, 100000000, 0.01"), "set_target_maximum_distance", "get_target_maximum_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_bend_direction", PROPERTY_HINT_NONE, ""), "set_flip_bend_direction", "get_flip_bend_direction");
+ ADD_GROUP("", "");
+}
+
+SkeletonModification2DTwoBoneIK::SkeletonModification2DTwoBoneIK() {
+ stack = nullptr;
+ is_setup = false;
+ enabled = true;
+ editor_draw_gizmo = true;
+}
+
+SkeletonModification2DTwoBoneIK::~SkeletonModification2DTwoBoneIK() {
+}
diff --git a/scene/resources/skeleton_modification_2d_twoboneik.h b/scene/resources/skeleton_modification_2d_twoboneik.h
new file mode 100644
index 0000000000..c7e545a488
--- /dev/null
+++ b/scene/resources/skeleton_modification_2d_twoboneik.h
@@ -0,0 +1,107 @@
+/*************************************************************************/
+/* skeleton_modification_2d_twoboneik.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETONMODIFICATION2DTWOBONEIK_H
+#define SKELETONMODIFICATION2DTWOBONEIK_H
+
+#include "scene/2d/skeleton_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
+
+///////////////////////////////////////
+// SkeletonModification2DJIGGLE
+///////////////////////////////////////
+
+class SkeletonModification2DTwoBoneIK : public SkeletonModification2D {
+ GDCLASS(SkeletonModification2DTwoBoneIK, SkeletonModification2D);
+
+private:
+ NodePath target_node;
+ ObjectID target_node_cache;
+ float target_minimum_distance = 0;
+ float target_maximum_distance = 0;
+ bool flip_bend_direction = false;
+
+ NodePath joint_one_bone2d_node;
+ ObjectID joint_one_bone2d_node_cache;
+ int joint_one_bone_idx = -1;
+
+ NodePath joint_two_bone2d_node;
+ ObjectID joint_two_bone2d_node_cache;
+ int joint_two_bone_idx = -1;
+
+#ifdef TOOLS_ENABLED
+ bool editor_draw_min_max = false;
+#endif // TOOLS_ENABLED
+
+ void update_target_cache();
+ void update_joint_one_bone2d_cache();
+ void update_joint_two_bone2d_cache();
+
+protected:
+ static void _bind_methods();
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+public:
+ void _execute(float p_delta) override;
+ void _setup_modification(SkeletonModificationStack2D *p_stack) override;
+ void _draw_editor_gizmo() override;
+
+ void set_target_node(const NodePath &p_target_node);
+ NodePath get_target_node() const;
+
+ void set_target_minimum_distance(float p_minimum_distance);
+ float get_target_minimum_distance() const;
+ void set_target_maximum_distance(float p_maximum_distance);
+ float get_target_maximum_distance() const;
+ void set_flip_bend_direction(bool p_flip_direction);
+ bool get_flip_bend_direction() const;
+
+ void set_joint_one_bone2d_node(const NodePath &p_node);
+ NodePath get_joint_one_bone2d_node() const;
+ void set_joint_one_bone_idx(int p_bone_idx);
+ int get_joint_one_bone_idx() const;
+
+ void set_joint_two_bone2d_node(const NodePath &p_node);
+ NodePath get_joint_two_bone2d_node() const;
+ void set_joint_two_bone_idx(int p_bone_idx);
+ int get_joint_two_bone_idx() const;
+
+#ifdef TOOLS_ENABLED
+ void set_editor_draw_min_max(bool p_draw);
+ bool get_editor_draw_min_max() const;
+#endif // TOOLS_ENABLED
+
+ SkeletonModification2DTwoBoneIK();
+ ~SkeletonModification2DTwoBoneIK();
+};
+
+#endif // SKELETONMODIFICATION2DTWOBONEIK_H
diff --git a/scene/resources/skeleton_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp
new file mode 100644
index 0000000000..72c1c330ef
--- /dev/null
+++ b/scene/resources/skeleton_modification_stack_2d.cpp
@@ -0,0 +1,269 @@
+/*************************************************************************/
+/* skeleton_modification_stack_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skeleton_modification_stack_2d.h"
+#include "scene/2d/skeleton_2d.h"
+
+void SkeletonModificationStack2D::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < modifications.size(); i++) {
+ p_list->push_back(
+ PropertyInfo(Variant::OBJECT, "modifications/" + itos(i),
+ PROPERTY_HINT_RESOURCE_TYPE,
+ "SkeletonModification2D",
+ PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+ }
+}
+
+bool SkeletonModificationStack2D::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+ if (path.begins_with("modifications/")) {
+ int mod_idx = path.get_slicec('/', 1).to_int();
+ set_modification(mod_idx, p_value);
+ return true;
+ }
+ return true;
+}
+
+bool SkeletonModificationStack2D::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (path.begins_with("modifications/")) {
+ int mod_idx = path.get_slicec('/', 1).to_int();
+ r_ret = get_modification(mod_idx);
+ return true;
+ }
+ return true;
+}
+
+void SkeletonModificationStack2D::setup() {
+ if (is_setup) {
+ return;
+ }
+
+ if (skeleton != nullptr) {
+ is_setup = true;
+ for (int i = 0; i < modifications.size(); i++) {
+ if (!modifications[i].is_valid()) {
+ continue;
+ }
+ modifications.get(i)->_setup_modification(this);
+ }
+
+#ifdef TOOLS_ENABLED
+ set_editor_gizmos_dirty(true);
+#endif // TOOLS_ENABLED
+
+ } else {
+ WARN_PRINT("Cannot setup SkeletonModificationStack2D: no Skeleton2D set!");
+ }
+}
+
+void SkeletonModificationStack2D::execute(float p_delta, int p_execution_mode) {
+ ERR_FAIL_COND_MSG(!is_setup || skeleton == nullptr || is_queued_for_deletion(),
+ "Modification stack is not properly setup and therefore cannot execute!");
+
+ if (!skeleton->is_inside_tree()) {
+ ERR_PRINT_ONCE("Skeleton is not inside SceneTree! Cannot execute modification!");
+ return;
+ }
+
+ if (!enabled) {
+ return;
+ }
+
+ for (int i = 0; i < modifications.size(); i++) {
+ if (!modifications[i].is_valid()) {
+ continue;
+ }
+
+ if (modifications[i]->get_execution_mode() == p_execution_mode) {
+ modifications.get(i)->_execute(p_delta);
+ }
+ }
+}
+
+void SkeletonModificationStack2D::draw_editor_gizmos() {
+ if (!is_setup) {
+ return;
+ }
+
+ if (editor_gizmo_dirty) {
+ for (int i = 0; i < modifications.size(); i++) {
+ if (!modifications[i].is_valid()) {
+ continue;
+ }
+
+ if (modifications[i]->editor_draw_gizmo) {
+ modifications.get(i)->_draw_editor_gizmo();
+ }
+ }
+ skeleton->draw_set_transform(Vector2(0, 0));
+ editor_gizmo_dirty = false;
+ }
+}
+
+void SkeletonModificationStack2D::set_editor_gizmos_dirty(bool p_dirty) {
+ if (!is_setup) {
+ return;
+ }
+
+ if (!editor_gizmo_dirty && p_dirty) {
+ editor_gizmo_dirty = p_dirty;
+ if (skeleton) {
+ skeleton->update();
+ }
+ } else {
+ editor_gizmo_dirty = p_dirty;
+ }
+}
+
+void SkeletonModificationStack2D::enable_all_modifications(bool p_enabled) {
+ for (int i = 0; i < modifications.size(); i++) {
+ if (!modifications[i].is_valid()) {
+ continue;
+ }
+ modifications.get(i)->set_enabled(p_enabled);
+ }
+}
+
+Ref<SkeletonModification2D> SkeletonModificationStack2D::get_modification(int p_mod_idx) const {
+ ERR_FAIL_INDEX_V(p_mod_idx, modifications.size(), nullptr);
+ return modifications[p_mod_idx];
+}
+
+void SkeletonModificationStack2D::add_modification(Ref<SkeletonModification2D> p_mod) {
+ ERR_FAIL_COND(!p_mod.is_valid());
+
+ p_mod->_setup_modification(this);
+ modifications.push_back(p_mod);
+
+#ifdef TOOLS_ENABLED
+ set_editor_gizmos_dirty(true);
+#endif // TOOLS_ENABLED
+}
+
+void SkeletonModificationStack2D::delete_modification(int p_mod_idx) {
+ ERR_FAIL_INDEX(p_mod_idx, modifications.size());
+ modifications.remove(p_mod_idx);
+
+#ifdef TOOLS_ENABLED
+ set_editor_gizmos_dirty(true);
+#endif // TOOLS_ENABLED
+}
+
+void SkeletonModificationStack2D::set_modification(int p_mod_idx, Ref<SkeletonModification2D> p_mod) {
+ ERR_FAIL_INDEX(p_mod_idx, modifications.size());
+
+ if (p_mod == nullptr) {
+ modifications.insert(p_mod_idx, nullptr);
+ } else {
+ p_mod->_setup_modification(this);
+ modifications.insert(p_mod_idx, p_mod);
+ }
+
+#ifdef TOOLS_ENABLED
+ set_editor_gizmos_dirty(true);
+#endif // TOOLS_ENABLED
+}
+
+void SkeletonModificationStack2D::set_modification_count(int p_count) {
+ modifications.resize(p_count);
+ notify_property_list_changed();
+
+#ifdef TOOLS_ENABLED
+ set_editor_gizmos_dirty(true);
+#endif // TOOLS_ENABLED
+}
+
+int SkeletonModificationStack2D::get_modification_count() const {
+ return modifications.size();
+}
+
+void SkeletonModificationStack2D::set_skeleton(Skeleton2D *p_skeleton) {
+ skeleton = p_skeleton;
+}
+
+Skeleton2D *SkeletonModificationStack2D::get_skeleton() const {
+ return skeleton;
+}
+
+bool SkeletonModificationStack2D::get_is_setup() const {
+ return is_setup;
+}
+
+void SkeletonModificationStack2D::set_enabled(bool p_enabled) {
+ enabled = p_enabled;
+}
+
+bool SkeletonModificationStack2D::get_enabled() const {
+ return enabled;
+}
+
+void SkeletonModificationStack2D::set_strength(float p_strength) {
+ ERR_FAIL_COND_MSG(p_strength < 0, "Strength cannot be less than zero!");
+ ERR_FAIL_COND_MSG(p_strength > 1, "Strength cannot be more than one!");
+ strength = p_strength;
+}
+
+float SkeletonModificationStack2D::get_strength() const {
+ return strength;
+}
+
+void SkeletonModificationStack2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("setup"), &SkeletonModificationStack2D::setup);
+ ClassDB::bind_method(D_METHOD("execute", "delta", "execution_mode"), &SkeletonModificationStack2D::execute);
+
+ ClassDB::bind_method(D_METHOD("enable_all_modifications", "enabled"), &SkeletonModificationStack2D::enable_all_modifications);
+ ClassDB::bind_method(D_METHOD("get_modification", "mod_idx"), &SkeletonModificationStack2D::get_modification);
+ ClassDB::bind_method(D_METHOD("add_modification", "modification"), &SkeletonModificationStack2D::add_modification);
+ ClassDB::bind_method(D_METHOD("delete_modification", "mod_idx"), &SkeletonModificationStack2D::delete_modification);
+ ClassDB::bind_method(D_METHOD("set_modification", "mod_idx", "modification"), &SkeletonModificationStack2D::set_modification);
+
+ ClassDB::bind_method(D_METHOD("set_modification_count"), &SkeletonModificationStack2D::set_modification_count);
+ ClassDB::bind_method(D_METHOD("get_modification_count"), &SkeletonModificationStack2D::get_modification_count);
+
+ ClassDB::bind_method(D_METHOD("get_is_setup"), &SkeletonModificationStack2D::get_is_setup);
+
+ ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModificationStack2D::set_enabled);
+ ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModificationStack2D::get_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_strength", "strength"), &SkeletonModificationStack2D::set_strength);
+ ClassDB::bind_method(D_METHOD("get_strength"), &SkeletonModificationStack2D::get_strength);
+
+ ClassDB::bind_method(D_METHOD("get_skeleton"), &SkeletonModificationStack2D::get_skeleton);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0, 1, 0.001"), "set_strength", "get_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1"), "set_modification_count", "get_modification_count");
+}
+
+SkeletonModificationStack2D::SkeletonModificationStack2D() {
+}
diff --git a/scene/resources/skeleton_modification_stack_2d.h b/scene/resources/skeleton_modification_stack_2d.h
new file mode 100644
index 0000000000..58855701a1
--- /dev/null
+++ b/scene/resources/skeleton_modification_stack_2d.h
@@ -0,0 +1,99 @@
+/*************************************************************************/
+/* skeleton_modification_stack_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKELETONMODIFICATIONSTACK2D_H
+#define SKELETONMODIFICATIONSTACK2D_H
+
+#include "scene/2d/skeleton_2d.h"
+#include "scene/resources/skeleton_modification_2d.h"
+
+///////////////////////////////////////
+// SkeletonModificationStack2D
+///////////////////////////////////////
+
+class Skeleton2D;
+class SkeletonModification2D;
+class Bone2D;
+
+class SkeletonModificationStack2D : public Resource {
+ GDCLASS(SkeletonModificationStack2D, Resource);
+ friend class Skeleton2D;
+ friend class SkeletonModification2D;
+
+protected:
+ static void _bind_methods();
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+
+public:
+ Skeleton2D *skeleton = nullptr;
+ bool is_setup = false;
+ bool enabled = false;
+ float strength = 1.0;
+
+ enum EXECUTION_MODE {
+ execution_mode_process,
+ execution_mode_physics_process
+ };
+
+ Vector<Ref<SkeletonModification2D>> modifications = Vector<Ref<SkeletonModification2D>>();
+
+ void setup();
+ void execute(float p_delta, int p_execution_mode);
+
+ bool editor_gizmo_dirty = false;
+ void draw_editor_gizmos();
+ void set_editor_gizmos_dirty(bool p_dirty);
+
+ void enable_all_modifications(bool p_enable);
+ Ref<SkeletonModification2D> get_modification(int p_mod_idx) const;
+ void add_modification(Ref<SkeletonModification2D> p_mod);
+ void delete_modification(int p_mod_idx);
+ void set_modification(int p_mod_idx, Ref<SkeletonModification2D> p_mod);
+
+ void set_modification_count(int p_count);
+ int get_modification_count() const;
+
+ void set_skeleton(Skeleton2D *p_skeleton);
+ Skeleton2D *get_skeleton() const;
+
+ bool get_is_setup() const;
+
+ void set_enabled(bool p_enabled);
+ bool get_enabled() const;
+
+ void set_strength(float p_strength);
+ float get_strength() const;
+
+ SkeletonModificationStack2D();
+};
+
+#endif // SKELETONMODIFICATION2D_H
diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp
index fee8fdbde2..710612ae05 100644
--- a/scene/resources/skin.cpp
+++ b/scene/resources/skin.cpp
@@ -38,14 +38,14 @@ void Skin::set_bind_count(int p_size) {
emit_changed();
}
-void Skin::add_bind(int p_bone, const Transform &p_pose) {
+void Skin::add_bind(int p_bone, const Transform3D &p_pose) {
uint32_t index = bind_count;
set_bind_count(bind_count + 1);
set_bind_bone(index, p_bone);
set_bind_pose(index, p_pose);
}
-void Skin::add_named_bind(const String &p_name, const Transform &p_pose) {
+void Skin::add_named_bind(const String &p_name, const Transform3D &p_pose) {
uint32_t index = bind_count;
set_bind_count(bind_count + 1);
set_bind_name(index, p_name);
@@ -68,7 +68,7 @@ void Skin::set_bind_bone(int p_index, int p_bone) {
emit_changed();
}
-void Skin::set_bind_pose(int p_index, const Transform &p_pose) {
+void Skin::set_bind_pose(int p_index, const Transform3D &p_pose) {
ERR_FAIL_INDEX(p_index, bind_count);
binds_ptr[p_index].pose = p_pose;
emit_changed();
@@ -134,7 +134,7 @@ void Skin::_get_property_list(List<PropertyInfo> *p_list) const {
for (int i = 0; i < get_bind_count(); i++) {
p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bind/" + itos(i) + "/name"));
p_list->push_back(PropertyInfo(Variant::INT, "bind/" + itos(i) + "/bone", PROPERTY_HINT_RANGE, "0,16384,1,or_greater", get_bind_name(i) != StringName() ? PROPERTY_USAGE_NOEDITOR : PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, "bind/" + itos(i) + "/pose"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, "bind/" + itos(i) + "/pose"));
}
}
diff --git a/scene/resources/skin.h b/scene/resources/skin.h
index f5d64f96aa..6857bf743a 100644
--- a/scene/resources/skin.h
+++ b/scene/resources/skin.h
@@ -39,7 +39,7 @@ class Skin : public Resource {
struct Bind {
int bone = -1;
StringName name;
- Transform pose;
+ Transform3D pose;
};
Vector<Bind> binds;
@@ -59,11 +59,11 @@ public:
void set_bind_count(int p_size);
inline int get_bind_count() const { return bind_count; }
- void add_bind(int p_bone, const Transform &p_pose);
- void add_named_bind(const String &p_name, const Transform &p_pose);
+ void add_bind(int p_bone, const Transform3D &p_pose);
+ void add_named_bind(const String &p_name, const Transform3D &p_pose);
void set_bind_bone(int p_index, int p_bone);
- void set_bind_pose(int p_index, const Transform &p_pose);
+ void set_bind_pose(int p_index, const Transform3D &p_pose);
void set_bind_name(int p_index, const StringName &p_name);
inline int get_bind_bone(int p_index) const {
@@ -80,9 +80,9 @@ public:
return binds_ptr[p_index].name;
}
- inline Transform get_bind_pose(int p_index) const {
+ inline Transform3D get_bind_pose(int p_index) const {
#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(p_index, bind_count, Transform());
+ ERR_FAIL_INDEX_V(p_index, bind_count, Transform3D());
#endif
return binds_ptr[p_index].pose;
}
diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp
index f50ee9c4c8..9d79c22159 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -193,7 +193,6 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() {
code += "uniform float ground_energy = 1.0;\n\n";
code += "uniform float sun_angle_max = 1.74;\n";
code += "uniform float sun_curve : hint_range(0, 1) = 0.05;\n\n";
- code += "const float PI = 3.1415926535897932384626433833;\n\n";
code += "void sky() {\n";
code += "\tfloat v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));\n";
code += "\tfloat c = (1.0 - v_angle / (PI * 0.5));\n";
@@ -499,7 +498,6 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() {
code += "uniform sampler2D night_sky : hint_black;";
- code += "const float PI = 3.141592653589793238462643383279502884197169;\n";
code += "const vec3 UP = vec3( 0.0, 1.0, 0.0 );\n\n";
code += "// Sun constants\n";
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 2159f1bc97..87371224e0 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -121,7 +121,6 @@ void StyleBoxTexture::set_texture(Ref<Texture2D> p_texture) {
} else {
region_rect = Rect2(Point2(), texture->get_size());
}
- emit_signal("texture_changed");
emit_changed();
}
@@ -285,8 +284,6 @@ void StyleBoxTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_v_axis_stretch_mode", "mode"), &StyleBoxTexture::set_v_axis_stretch_mode);
ClassDB::bind_method(D_METHOD("get_v_axis_stretch_mode"), &StyleBoxTexture::get_v_axis_stretch_mode);
- ADD_SIGNAL(MethodInfo("texture_changed"));
-
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
ADD_GROUP("Margin", "margin_");
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 3d3900ecc5..fee9f92ad7 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -35,6 +35,7 @@
SurfaceTool::OptimizeVertexCacheFunc SurfaceTool::optimize_vertex_cache_func = nullptr;
SurfaceTool::SimplifyFunc SurfaceTool::simplify_func = nullptr;
+SurfaceTool::SimplifyWithAttribFunc SurfaceTool::simplify_with_attrib_func = nullptr;
SurfaceTool::SimplifyScaleFunc SurfaceTool::simplify_scale_func = nullptr;
SurfaceTool::SimplifySloppyFunc SurfaceTool::simplify_sloppy_func = nullptr;
@@ -369,13 +370,13 @@ Array SurfaceTool::commit_to_arrays() {
for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
const Vertex &v = vertex_array[idx];
- w[idx + 0] = v.tangent.x;
- w[idx + 1] = v.tangent.y;
- w[idx + 2] = v.tangent.z;
+ w[idx * 4 + 0] = v.tangent.x;
+ w[idx * 4 + 1] = v.tangent.y;
+ w[idx * 4 + 2] = v.tangent.z;
//float d = v.tangent.dot(v.binormal,v.normal);
float d = v.binormal.dot(v.normal.cross(v.tangent));
- w[idx + 3] = d < 0 ? -1 : 1;
+ w[idx * 4 + 3] = d < 0 ? -1 : 1;
}
a[i] = array;
@@ -536,12 +537,16 @@ Array SurfaceTool::commit_to_arrays() {
int count = skin_weights == SKIN_8_WEIGHTS ? 8 : 4;
Vector<int> array;
array.resize(varr_len * count);
+ array.fill(0);
int *w = array.ptrw();
for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
const Vertex &v = vertex_array[idx];
- ERR_CONTINUE(v.bones.size() != count);
+ if (v.bones.size() > count) {
+ ERR_PRINT_ONCE(vformat("Invalid bones size %d vs count %d", v.bones.size(), count));
+ continue;
+ }
for (int j = 0; j < count; j++) {
w[idx * count + j] = v.bones[j];
@@ -556,12 +561,16 @@ Array SurfaceTool::commit_to_arrays() {
int count = skin_weights == SKIN_8_WEIGHTS ? 8 : 4;
array.resize(varr_len * count);
+ array.fill(0.0f);
float *w = array.ptrw();
for (uint32_t idx = 0; idx < vertex_array.size(); idx++) {
const Vertex &v = vertex_array[idx];
- ERR_CONTINUE(v.weights.size() != count);
+ if (v.weights.size() > count) {
+ ERR_PRINT_ONCE(vformat("Invalid weight size %d vs count %d", v.weights.size(), count));
+ continue;
+ }
for (int j = 0; j < count; j++) {
w[idx * count + j] = v.weights[j];
@@ -663,6 +672,8 @@ void SurfaceTool::deindex() {
}
void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, LocalVector<Vertex> *r_vertex, LocalVector<int> *r_index, uint32_t &lformat) {
+ ERR_FAIL_NULL_MSG(p_existing, "First argument in SurfaceTool::_create_list() must be a valid object of type Mesh");
+
Array arr = p_existing->surface_get_arrays(p_surface);
ERR_FAIL_COND(arr.size() != RS::ARRAY_MAX);
_create_list_from_arrays(arr, r_vertex, r_index, lformat);
@@ -824,6 +835,8 @@ void SurfaceTool::create_from_triangle_arrays(const Array &p_arrays) {
}
void SurfaceTool::create_from(const Ref<Mesh> &p_existing, int p_surface) {
+ ERR_FAIL_NULL_MSG(p_existing, "First argument in SurfaceTool::create_from() must be a valid object of type Mesh");
+
clear();
primitive = p_existing->surface_get_primitive_type(p_surface);
_create_list(p_existing, p_surface, &vertex_array, &index_array, format);
@@ -831,6 +844,8 @@ void SurfaceTool::create_from(const Ref<Mesh> &p_existing, int p_surface) {
}
void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String &p_blend_shape_name) {
+ ERR_FAIL_NULL_MSG(p_existing, "First argument in SurfaceTool::create_from_blend_shape() must be a valid object of type Mesh");
+
clear();
primitive = p_existing->surface_get_primitive_type(p_surface);
Array arr = p_existing->surface_get_blend_shape_arrays(p_surface);
@@ -850,7 +865,9 @@ void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_sur
_create_list_from_arrays(arr[shape_idx], &vertex_array, &index_array, format);
}
-void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform) {
+void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform3D &p_xform) {
+ ERR_FAIL_NULL_MSG(p_existing, "First argument in SurfaceTool::append_from() must be a valid object of type Mesh");
+
if (vertex_array.size() == 0) {
primitive = p_existing->surface_get_primitive_type(p_surface);
format = 0;
@@ -1105,7 +1122,7 @@ void SurfaceTool::optimize_indices_for_cache() {
ERR_FAIL_COND(index_array.size() == 0);
LocalVector old_index_array = index_array;
- zeromem(index_array.ptr(), index_array.size() * sizeof(int));
+ memset(index_array.ptr(), 0, index_array.size() * sizeof(int));
optimize_vertex_cache_func((unsigned int *)index_array.ptr(), (unsigned int *)old_index_array.ptr(), old_index_array.size(), vertex_array.size());
}
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index 28addf2245..bde6702759 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -35,8 +35,8 @@
#include "scene/resources/mesh.h"
#include "thirdparty/misc/mikktspace.h"
-class SurfaceTool : public Reference {
- GDCLASS(SurfaceTool, Reference);
+class SurfaceTool : public RefCounted {
+ GDCLASS(SurfaceTool, RefCounted);
public:
struct Vertex {
@@ -78,6 +78,8 @@ public:
static OptimizeVertexCacheFunc optimize_vertex_cache_func;
typedef size_t (*SimplifyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float *r_error);
static SimplifyFunc simplify_func;
+ typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float *result_error, const float *attributes, const float *attribute_weights, size_t attribute_count);
+ static SimplifyWithAttribFunc simplify_with_attrib_func;
typedef float (*SimplifyScaleFunc)(const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
static SimplifyScaleFunc simplify_scale_func;
typedef size_t (*SimplifySloppyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float *out_result_error);
@@ -184,7 +186,7 @@ public:
Array commit_to_arrays();
void create_from(const Ref<Mesh> &p_existing, int p_surface);
void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String &p_blend_shape_name);
- void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform);
+ void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform3D &p_xform);
Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = 0);
SurfaceTool();
diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp
index cf07003720..33bb0a83e9 100644
--- a/scene/resources/text_file.cpp
+++ b/scene/resources/text_file.cpp
@@ -30,7 +30,7 @@
#include "text_file.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
bool TextFile::has_text() const {
return text != "";
@@ -55,10 +55,10 @@ Error TextFile::load_text(const String &p_path) {
ERR_FAIL_COND_V_MSG(err, err, "Cannot open TextFile '" + p_path + "'.");
- int len = f->get_len();
+ uint64_t len = f->get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
- int r = f->get_buffer(w, len);
+ uint64_t r = f->get_buffer(w, len);
f->close();
memdelete(f);
ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index 925867a1f2..f1eff6e84f 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -74,7 +74,7 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextLine::set_flags);
ClassDB::bind_method(D_METHOD("get_flags"), &TextLine::get_flags);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida justification,Word justification,Trim edge spaces after justification,Justification only after last tab"), "set_flags", "get_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida Justify,Word Justify,Trim Edge Spaces After Justify,Justify Only After Last Tab"), "set_flags", "get_flags");
ClassDB::bind_method(D_METHOD("get_objects"), &TextLine::get_objects);
ClassDB::bind_method(D_METHOD("get_object_rect", "key"), &TextLine::get_object_rect);
diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h
index 74d4f2c32c..1b5c1a3123 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -36,8 +36,8 @@
/*************************************************************************/
-class TextLine : public Reference {
- GDCLASS(TextLine, Reference);
+class TextLine : public RefCounted {
+ GDCLASS(TextLine, RefCounted);
RID rid;
int spacing_top = 0;
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 341f5abd80..958c94fe31 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -72,7 +72,7 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextParagraph::set_flags);
ClassDB::bind_method(D_METHOD("get_flags"), &TextParagraph::get_flags);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida justification,Word justification,Trim edge spaces after justification,Justification only after last tab,Break mandatory,Break words,Break graphemes"), "set_flags", "get_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida Justify,Word Justify,Trim Edge Spaces After Justify,Justify Only After Last Tab,Break Mandatory,Break Words,Break Graphemes"), "set_flags", "get_flags");
ClassDB::bind_method(D_METHOD("set_width", "width"), &TextParagraph::set_width);
ClassDB::bind_method(D_METHOD("get_width"), &TextParagraph::get_width);
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index 4396b07130..a34e745090 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -36,8 +36,8 @@
/*************************************************************************/
-class TextParagraph : public Reference {
- GDCLASS(TextParagraph, Reference);
+class TextParagraph : public RefCounted {
+ GDCLASS(TextParagraph, RefCounted);
RID dropcap_rid;
int dropcap_lines = 0;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index b6a2f24b8b..064563d4b5 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -327,7 +327,7 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit
uint32_t mipmaps = f->get_32();
Image::Format format = Image::Format(f->get_32());
- if (data_format == DATA_FORMAT_LOSSLESS || data_format == DATA_FORMAT_LOSSY || data_format == DATA_FORMAT_BASIS_UNIVERSAL) {
+ if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP || data_format == DATA_FORMAT_BASIS_UNIVERSAL) {
//look for a PNG or WEBP file inside
int sw = w;
@@ -335,7 +335,7 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit
//mipmaps need to be read independently, they will be later combined
Vector<Ref<Image>> mipmap_images;
- int total_size = 0;
+ uint64_t total_size = 0;
bool first = true;
@@ -360,10 +360,10 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit
Ref<Image> img;
if (data_format == DATA_FORMAT_BASIS_UNIVERSAL) {
img = Image::basis_universal_unpacker(pv);
- } else if (data_format == DATA_FORMAT_LOSSLESS) {
- img = Image::lossless_unpacker(pv);
+ } else if (data_format == DATA_FORMAT_PNG) {
+ img = Image::png_unpacker(pv);
} else {
- img = Image::lossy_unpacker(pv);
+ img = Image::webp_unpacker(pv);
}
if (img.is_null() || img->is_empty()) {
@@ -410,7 +410,7 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit
Vector<uint8_t> id = mipmap_images[i]->get_data();
int len = id.size();
const uint8_t *r = id.ptr();
- copymem(&wr[ofs], r, len);
+ memcpy(&wr[ofs], r, len);
ofs += len;
}
}
@@ -490,7 +490,7 @@ Image::Format StreamTexture2D::get_format() const {
return format;
}
-Error StreamTexture2D::_load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) {
+Error StreamTexture2D::_load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) {
alpha_cache.unref();
ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER);
@@ -511,8 +511,8 @@ Error StreamTexture2D::_load_data(const String &p_path, int &tw, int &th, int &t
memdelete(f);
ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture file is too new.");
}
- tw_custom = f->get_32();
- th_custom = f->get_32();
+ r_width = f->get_32();
+ r_height = f->get_32();
uint32_t df = f->get_32(); //data format
//skip reserved
@@ -551,7 +551,7 @@ Error StreamTexture2D::_load_data(const String &p_path, int &tw, int &th, int &t
}
Error StreamTexture2D::load(const String &p_path) {
- int lw, lh, lwc, lhc;
+ int lw, lh;
Ref<Image> image;
image.instance();
@@ -560,7 +560,7 @@ Error StreamTexture2D::load(const String &p_path) {
bool request_roughness;
int mipmap_limit;
- Error err = _load_data(p_path, lw, lh, lwc, lhc, image, request_3d, request_normal, request_roughness, mipmap_limit);
+ Error err = _load_data(p_path, lw, lh, image, request_3d, request_normal, request_roughness, mipmap_limit);
if (err) {
return err;
}
@@ -571,12 +571,12 @@ Error StreamTexture2D::load(const String &p_path) {
} else {
texture = RS::get_singleton()->texture_2d_create(image);
}
- if (lwc || lhc) {
- RS::get_singleton()->texture_set_size_override(texture, lwc, lhc);
+ if (lw || lh) {
+ RS::get_singleton()->texture_set_size_override(texture, lw, lh);
}
- w = lwc ? lwc : lw;
- h = lhc ? lhc : lh;
+ w = lw;
+ h = lh;
path_to_file = p_path;
format = image->get_format();
@@ -1405,185 +1405,6 @@ MeshTexture::MeshTexture() {
//////////////////////////////////////////
-int LargeTexture::get_width() const {
- return size.width;
-}
-
-int LargeTexture::get_height() const {
- return size.height;
-}
-
-RID LargeTexture::get_rid() const {
- return RID();
-}
-
-bool LargeTexture::has_alpha() const {
- for (int i = 0; i < pieces.size(); i++) {
- if (pieces[i].texture->has_alpha()) {
- return true;
- }
- }
-
- return false;
-}
-
-int LargeTexture::add_piece(const Point2 &p_offset, const Ref<Texture2D> &p_texture) {
- ERR_FAIL_COND_V(p_texture.is_null(), -1);
- Piece p;
- p.offset = p_offset;
- p.texture = p_texture;
- pieces.push_back(p);
-
- return pieces.size() - 1;
-}
-
-void LargeTexture::set_piece_offset(int p_idx, const Point2 &p_offset) {
- ERR_FAIL_INDEX(p_idx, pieces.size());
- pieces.write[p_idx].offset = p_offset;
-};
-
-void LargeTexture::set_piece_texture(int p_idx, const Ref<Texture2D> &p_texture) {
- ERR_FAIL_COND(p_texture == this);
- ERR_FAIL_COND(p_texture.is_null());
- ERR_FAIL_INDEX(p_idx, pieces.size());
- pieces.write[p_idx].texture = p_texture;
-};
-
-void LargeTexture::set_size(const Size2 &p_size) {
- size = p_size;
-}
-
-void LargeTexture::clear() {
- pieces.clear();
- size = Size2i();
-}
-
-Array LargeTexture::_get_data() const {
- Array arr;
- for (int i = 0; i < pieces.size(); i++) {
- arr.push_back(pieces[i].offset);
- arr.push_back(pieces[i].texture);
- }
- arr.push_back(Size2(size));
- return arr;
-}
-
-void LargeTexture::_set_data(const Array &p_array) {
- ERR_FAIL_COND(p_array.size() < 1);
- ERR_FAIL_COND(!(p_array.size() & 1));
- clear();
- for (int i = 0; i < p_array.size() - 1; i += 2) {
- add_piece(p_array[i], p_array[i + 1]);
- }
- size = Size2(p_array[p_array.size() - 1]);
-}
-
-int LargeTexture::get_piece_count() const {
- return pieces.size();
-}
-
-Vector2 LargeTexture::get_piece_offset(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, pieces.size(), Vector2());
- return pieces[p_idx].offset;
-}
-
-Ref<Texture2D> LargeTexture::get_piece_texture(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, pieces.size(), Ref<Texture2D>());
- return pieces[p_idx].texture;
-}
-
-Ref<Image> LargeTexture::to_image() const {
- Ref<Image> img = memnew(Image(this->get_width(), this->get_height(), false, Image::FORMAT_RGBA8));
- for (int i = 0; i < pieces.size(); i++) {
- Ref<Image> src_img = pieces[i].texture->get_image();
- img->blit_rect(src_img, Rect2(0, 0, src_img->get_width(), src_img->get_height()), pieces[i].offset);
- }
-
- return img;
-}
-
-void LargeTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_piece", "ofs", "texture"), &LargeTexture::add_piece);
- ClassDB::bind_method(D_METHOD("set_piece_offset", "idx", "ofs"), &LargeTexture::set_piece_offset);
- ClassDB::bind_method(D_METHOD("set_piece_texture", "idx", "texture"), &LargeTexture::set_piece_texture);
- ClassDB::bind_method(D_METHOD("set_size", "size"), &LargeTexture::set_size);
- ClassDB::bind_method(D_METHOD("clear"), &LargeTexture::clear);
-
- ClassDB::bind_method(D_METHOD("get_piece_count"), &LargeTexture::get_piece_count);
- ClassDB::bind_method(D_METHOD("get_piece_offset", "idx"), &LargeTexture::get_piece_offset);
- ClassDB::bind_method(D_METHOD("get_piece_texture", "idx"), &LargeTexture::get_piece_texture);
-
- ClassDB::bind_method(D_METHOD("_set_data", "data"), &LargeTexture::_set_data);
- ClassDB::bind_method(D_METHOD("_get_data"), &LargeTexture::_get_data);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
-}
-
-void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
- for (int i = 0; i < pieces.size(); i++) {
- // TODO
- pieces[i].texture->draw(p_canvas_item, pieces[i].offset + p_pos, p_modulate, p_transpose);
- }
-}
-
-void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {
- //tiling not supported for this
- if (size.x == 0 || size.y == 0) {
- return;
- }
-
- Size2 scale = p_rect.size / size;
-
- for (int i = 0; i < pieces.size(); i++) {
- // TODO
- pieces[i].texture->draw_rect(p_canvas_item, Rect2(pieces[i].offset * scale + p_rect.position, pieces[i].texture->get_size() * scale), false, p_modulate, p_transpose);
- }
-}
-
-void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {
- //tiling not supported for this
- if (p_src_rect.size.x == 0 || p_src_rect.size.y == 0) {
- return;
- }
-
- Size2 scale = p_rect.size / p_src_rect.size;
-
- for (int i = 0; i < pieces.size(); i++) {
- // TODO
- Rect2 rect(pieces[i].offset, pieces[i].texture->get_size());
- if (!p_src_rect.intersects(rect)) {
- continue;
- }
- Rect2 local = p_src_rect.intersection(rect);
- Rect2 target = local;
- target.size *= scale;
- target.position = p_rect.position + (p_src_rect.position + rect.position) * scale;
- local.position -= rect.position;
- pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose, false);
- }
-}
-
-bool LargeTexture::is_pixel_opaque(int p_x, int p_y) const {
- for (int i = 0; i < pieces.size(); i++) {
- // TODO
- if (!pieces[i].texture.is_valid()) {
- continue;
- }
-
- Rect2 rect(pieces[i].offset, pieces[i].texture->get_size());
- if (rect.has_point(Point2(p_x, p_y))) {
- return pieces[i].texture->is_pixel_opaque(p_x - rect.position.x, p_y - rect.position.y);
- }
- }
-
- return true;
-}
-
-LargeTexture::LargeTexture() {
-}
-
-///////////////////
-
void CurveTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 16c98f2891..3b1815266d 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -31,10 +31,10 @@
#ifndef TEXTURE_H
#define TEXTURE_H
+#include "core/io/file_access.h"
#include "core/io/resource.h"
#include "core/io/resource_loader.h"
#include "core/math/rect2.h"
-#include "core/os/file_access.h"
#include "core/os/mutex.h"
#include "core/os/rw_lock.h"
#include "core/os/thread_safe.h"
@@ -136,8 +136,8 @@ class StreamTexture2D : public Texture2D {
public:
enum DataFormat {
DATA_FORMAT_IMAGE,
- DATA_FORMAT_LOSSLESS,
- DATA_FORMAT_LOSSY,
+ DATA_FORMAT_PNG,
+ DATA_FORMAT_WEBP,
DATA_FORMAT_BASIS_UNIVERSAL,
};
@@ -146,9 +146,6 @@ public:
};
enum FormatBits {
- FORMAT_MASK_IMAGE_FORMAT = (1 << 20) - 1,
- FORMAT_BIT_LOSSLESS = 1 << 20,
- FORMAT_BIT_LOSSY = 1 << 21,
FORMAT_BIT_STREAM = 1 << 22,
FORMAT_BIT_HAS_MIPMAPS = 1 << 23,
FORMAT_BIT_DETECT_3D = 1 << 24,
@@ -158,7 +155,7 @@ public:
};
private:
- Error _load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit = 0);
+ Error _load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit = 0);
String path_to_file;
mutable RID texture;
Image::Format format = Image::FORMAT_MAX;
@@ -297,51 +294,6 @@ public:
MeshTexture();
};
-class LargeTexture : public Texture2D {
- GDCLASS(LargeTexture, Texture2D);
- RES_BASE_EXTENSION("largetex");
-
-protected:
- struct Piece {
- Point2 offset;
- Ref<Texture2D> texture;
- };
-
- Vector<Piece> pieces;
- Size2i size;
-
- Array _get_data() const;
- void _set_data(const Array &p_array);
- static void _bind_methods();
-
-public:
- virtual int get_width() const override;
- virtual int get_height() const override;
- virtual RID get_rid() const override;
-
- virtual bool has_alpha() const override;
-
- int add_piece(const Point2 &p_offset, const Ref<Texture2D> &p_texture);
- void set_piece_offset(int p_idx, const Point2 &p_offset);
- void set_piece_texture(int p_idx, const Ref<Texture2D> &p_texture);
-
- void set_size(const Size2 &p_size);
- void clear();
-
- int get_piece_count() const;
- Vector2 get_piece_offset(int p_idx) const;
- Ref<Texture2D> get_piece_texture(int p_idx) const;
- Ref<Image> to_image() const;
-
- virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const override;
- virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const override;
-
- bool is_pixel_opaque(int p_x, int p_y) const override;
-
- LargeTexture();
-};
-
class TextureLayered : public Texture {
GDCLASS(TextureLayered, Texture);
@@ -434,8 +386,8 @@ class StreamTextureLayered : public TextureLayered {
public:
enum DataFormat {
DATA_FORMAT_IMAGE,
- DATA_FORMAT_LOSSLESS,
- DATA_FORMAT_LOSSY,
+ DATA_FORMAT_PNG,
+ DATA_FORMAT_WEBP,
DATA_FORMAT_BASIS_UNIVERSAL,
};
@@ -444,9 +396,6 @@ public:
};
enum FormatBits {
- FORMAT_MASK_IMAGE_FORMAT = (1 << 20) - 1,
- FORMAT_BIT_LOSSLESS = 1 << 20,
- FORMAT_BIT_LOSSY = 1 << 21,
FORMAT_BIT_STREAM = 1 << 22,
FORMAT_BIT_HAS_MIPMAPS = 1 << 23,
};
@@ -577,8 +526,8 @@ class StreamTexture3D : public Texture3D {
public:
enum DataFormat {
DATA_FORMAT_IMAGE,
- DATA_FORMAT_LOSSLESS,
- DATA_FORMAT_LOSSY,
+ DATA_FORMAT_PNG,
+ DATA_FORMAT_WEBP,
DATA_FORMAT_BASIS_UNIVERSAL,
};
@@ -587,9 +536,6 @@ public:
};
enum FormatBits {
- FORMAT_MASK_IMAGE_FORMAT = (1 << 20) - 1,
- FORMAT_BIT_LOSSLESS = 1 << 20,
- FORMAT_BIT_LOSSY = 1 << 21,
FORMAT_BIT_STREAM = 1 << 22,
FORMAT_BIT_HAS_MIPMAPS = 1 << 23,
};
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 036d11574c..89ac033207 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -29,18 +29,23 @@
/*************************************************************************/
#include "theme.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/string/print_string.h"
void Theme::_emit_theme_changed() {
+ if (no_change_propagation) {
+ return;
+ }
+
+ notify_property_list_changed();
emit_changed();
}
-Vector<String> Theme::_get_icon_list(const String &p_node_type) const {
+Vector<String> Theme::_get_icon_list(const String &p_theme_type) const {
Vector<String> ilret;
List<StringName> il;
- get_icon_list(p_node_type, &il);
+ get_icon_list(p_theme_type, &il);
ilret.resize(il.size());
int i = 0;
@@ -66,11 +71,11 @@ Vector<String> Theme::_get_icon_type_list() const {
return ilret;
}
-Vector<String> Theme::_get_stylebox_list(const String &p_node_type) const {
+Vector<String> Theme::_get_stylebox_list(const String &p_theme_type) const {
Vector<String> ilret;
List<StringName> il;
- get_stylebox_list(p_node_type, &il);
+ get_stylebox_list(p_theme_type, &il);
ilret.resize(il.size());
int i = 0;
@@ -96,11 +101,11 @@ Vector<String> Theme::_get_stylebox_type_list() const {
return ilret;
}
-Vector<String> Theme::_get_font_list(const String &p_node_type) const {
+Vector<String> Theme::_get_font_list(const String &p_theme_type) const {
Vector<String> ilret;
List<StringName> il;
- get_font_list(p_node_type, &il);
+ get_font_list(p_theme_type, &il);
ilret.resize(il.size());
int i = 0;
@@ -126,11 +131,11 @@ Vector<String> Theme::_get_font_type_list() const {
return ilret;
}
-Vector<String> Theme::_get_font_size_list(const String &p_node_type) const {
+Vector<String> Theme::_get_font_size_list(const String &p_theme_type) const {
Vector<String> ilret;
List<StringName> il;
- get_font_size_list(p_node_type, &il);
+ get_font_size_list(p_theme_type, &il);
ilret.resize(il.size());
int i = 0;
@@ -156,11 +161,11 @@ Vector<String> Theme::_get_font_size_type_list() const {
return ilret;
}
-Vector<String> Theme::_get_color_list(const String &p_node_type) const {
+Vector<String> Theme::_get_color_list(const String &p_theme_type) const {
Vector<String> ilret;
List<StringName> il;
- get_color_list(p_node_type, &il);
+ get_color_list(p_theme_type, &il);
ilret.resize(il.size());
int i = 0;
@@ -186,11 +191,11 @@ Vector<String> Theme::_get_color_type_list() const {
return ilret;
}
-Vector<String> Theme::_get_constant_list(const String &p_node_type) const {
+Vector<String> Theme::_get_constant_list(const String &p_theme_type) const {
Vector<String> ilret;
List<StringName> il;
- get_constant_list(p_node_type, &il);
+ get_constant_list(p_theme_type, &il);
ilret.resize(il.size());
int i = 0;
@@ -216,20 +221,20 @@ Vector<String> Theme::_get_constant_type_list() const {
return ilret;
}
-Vector<String> Theme::_get_theme_item_list(DataType p_data_type, const String &p_node_type) const {
+Vector<String> Theme::_get_theme_item_list(DataType p_data_type, const String &p_theme_type) const {
switch (p_data_type) {
case DATA_TYPE_COLOR:
- return _get_color_list(p_node_type);
+ return _get_color_list(p_theme_type);
case DATA_TYPE_CONSTANT:
- return _get_constant_list(p_node_type);
+ return _get_constant_list(p_theme_type);
case DATA_TYPE_FONT:
- return _get_font_list(p_node_type);
+ return _get_font_list(p_theme_type);
case DATA_TYPE_FONT_SIZE:
- return _get_font_size_list(p_node_type);
+ return _get_font_size_list(p_theme_type);
case DATA_TYPE_ICON:
- return _get_icon_list(p_node_type);
+ return _get_icon_list(p_theme_type);
case DATA_TYPE_STYLEBOX:
- return _get_stylebox_list(p_node_type);
+ return _get_stylebox_list(p_theme_type);
case DATA_TYPE_MAX:
break; // Can't happen, but silences warning.
}
@@ -278,19 +283,19 @@ bool Theme::_set(const StringName &p_name, const Variant &p_value) {
if (sname.find("/") != -1) {
String type = sname.get_slicec('/', 1);
- String node_type = sname.get_slicec('/', 0);
+ String theme_type = sname.get_slicec('/', 0);
String name = sname.get_slicec('/', 2);
if (type == "icons") {
- set_icon(name, node_type, p_value);
+ set_icon(name, theme_type, p_value);
} else if (type == "styles") {
- set_stylebox(name, node_type, p_value);
+ set_stylebox(name, theme_type, p_value);
} else if (type == "fonts") {
- set_font(name, node_type, p_value);
+ set_font(name, theme_type, p_value);
} else if (type == "colors") {
- set_color(name, node_type, p_value);
+ set_color(name, theme_type, p_value);
} else if (type == "constants") {
- set_constant(name, node_type, p_value);
+ set_constant(name, theme_type, p_value);
} else {
return false;
}
@@ -306,31 +311,31 @@ bool Theme::_get(const StringName &p_name, Variant &r_ret) const {
if (sname.find("/") != -1) {
String type = sname.get_slicec('/', 1);
- String node_type = sname.get_slicec('/', 0);
+ String theme_type = sname.get_slicec('/', 0);
String name = sname.get_slicec('/', 2);
if (type == "icons") {
- if (!has_icon(name, node_type)) {
+ if (!has_icon(name, theme_type)) {
r_ret = Ref<Texture2D>();
} else {
- r_ret = get_icon(name, node_type);
+ r_ret = get_icon(name, theme_type);
}
} else if (type == "styles") {
- if (!has_stylebox(name, node_type)) {
+ if (!has_stylebox(name, theme_type)) {
r_ret = Ref<StyleBox>();
} else {
- r_ret = get_stylebox(name, node_type);
+ r_ret = get_stylebox(name, theme_type);
}
} else if (type == "fonts") {
- if (!has_font(name, node_type)) {
+ if (!has_font(name, theme_type)) {
r_ret = Ref<Font>();
} else {
- r_ret = get_font(name, node_type);
+ r_ret = get_font(name, theme_type);
}
} else if (type == "colors") {
- r_ret = get_color(name, node_type);
+ r_ret = get_color(name, theme_type);
} else if (type == "constants") {
- r_ret = get_constant(name, node_type);
+ r_ret = get_constant(name, theme_type);
} else {
return false;
}
@@ -415,8 +420,7 @@ void Theme::set_default_theme_font(const Ref<Font> &p_default_font) {
default_theme_font->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
}
- notify_property_list_changed();
- emit_changed();
+ _emit_theme_changed();
}
Ref<Font> Theme::get_default_theme_font() const {
@@ -430,8 +434,7 @@ void Theme::set_default_theme_font_size(int p_font_size) {
default_theme_font_size = p_font_size;
- notify_property_list_changed();
- emit_changed();
+ _emit_theme_changed();
}
int Theme::get_default_theme_font_size() const {
@@ -477,79 +480,79 @@ void Theme::set_default_font_size(int p_font_size) {
default_font_size = p_font_size;
}
-void Theme::set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon) {
- bool new_value = !icon_map.has(p_node_type) || !icon_map[p_node_type].has(p_name);
-
- if (icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()) {
- icon_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon) {
+ if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) {
+ icon_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
- icon_map[p_node_type][p_name] = p_icon;
+ icon_map[p_theme_type][p_name] = p_icon;
if (p_icon.is_valid()) {
- icon_map[p_node_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
+ icon_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
}
- if (new_value) {
- notify_property_list_changed();
- emit_changed();
- }
+ _emit_theme_changed();
}
-Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_node_type) const {
- if (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()) {
- return icon_map[p_node_type][p_name];
+Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_theme_type) const {
+ if (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) {
+ return icon_map[p_theme_type][p_name];
} else {
return default_icon;
}
}
-bool Theme::has_icon(const StringName &p_name, const StringName &p_node_type) const {
- return (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid());
+bool Theme::has_icon(const StringName &p_name, const StringName &p_theme_type) const {
+ return (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid());
}
-void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!icon_map.has(p_node_type), "Cannot rename the icon '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(icon_map[p_node_type].has(p_name), "Cannot rename the icon '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
- ERR_FAIL_COND_MSG(!icon_map[p_node_type].has(p_old_name), "Cannot rename the icon '" + String(p_old_name) + "' because it does not exist.");
+bool Theme::has_icon_nocheck(const StringName &p_name, const StringName &p_theme_type) const {
+ return (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name));
+}
- icon_map[p_node_type][p_name] = icon_map[p_node_type][p_old_name];
- icon_map[p_node_type].erase(p_old_name);
+void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!icon_map.has(p_theme_type), "Cannot rename the icon '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(icon_map[p_theme_type].has(p_name), "Cannot rename the icon '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!icon_map[p_theme_type].has(p_old_name), "Cannot rename the icon '" + String(p_old_name) + "' because it does not exist.");
- notify_property_list_changed();
- emit_changed();
+ icon_map[p_theme_type][p_name] = icon_map[p_theme_type][p_old_name];
+ icon_map[p_theme_type].erase(p_old_name);
+
+ _emit_theme_changed();
}
-void Theme::clear_icon(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!icon_map.has(p_node_type), "Cannot clear the icon '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(!icon_map[p_node_type].has(p_name), "Cannot clear the icon '" + String(p_name) + "' because it does not exist.");
+void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!icon_map.has(p_theme_type), "Cannot clear the icon '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!icon_map[p_theme_type].has(p_name), "Cannot clear the icon '" + String(p_name) + "' because it does not exist.");
- if (icon_map[p_node_type][p_name].is_valid()) {
- icon_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ if (icon_map[p_theme_type][p_name].is_valid()) {
+ icon_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
- icon_map[p_node_type].erase(p_name);
+ icon_map[p_theme_type].erase(p_name);
- notify_property_list_changed();
- emit_changed();
+ _emit_theme_changed();
}
-void Theme::get_icon_list(StringName p_node_type, List<StringName> *p_list) const {
+void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- if (!icon_map.has(p_node_type)) {
+ if (!icon_map.has(p_theme_type)) {
return;
}
const StringName *key = nullptr;
- while ((key = icon_map[p_node_type].next(key))) {
+ while ((key = icon_map[p_theme_type].next(key))) {
p_list->push_back(*key);
}
}
-void Theme::add_icon_type(const StringName &p_node_type) {
- icon_map[p_node_type] = HashMap<StringName, Ref<Texture2D>>();
+void Theme::add_icon_type(const StringName &p_theme_type) {
+ if (icon_map.has(p_theme_type)) {
+ return;
+ }
+ icon_map[p_theme_type] = HashMap<StringName, Ref<Texture2D>>();
}
void Theme::get_icon_type_list(List<StringName> *p_list) const {
@@ -561,79 +564,79 @@ void Theme::get_icon_type_list(List<StringName> *p_list) const {
}
}
-void Theme::set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style) {
- bool new_value = !style_map.has(p_node_type) || !style_map[p_node_type].has(p_name);
-
- if (style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()) {
- style_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style) {
+ if (style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) {
+ style_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
- style_map[p_node_type][p_name] = p_style;
+ style_map[p_theme_type][p_name] = p_style;
if (p_style.is_valid()) {
- style_map[p_node_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
+ style_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
}
- if (new_value) {
- notify_property_list_changed();
- }
- emit_changed();
+ _emit_theme_changed();
}
-Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_node_type) const {
- if (style_map.has(p_node_type) && style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()) {
- return style_map[p_node_type][p_name];
+Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+ if (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) {
+ return style_map[p_theme_type][p_name];
} else {
return default_style;
}
}
-bool Theme::has_stylebox(const StringName &p_name, const StringName &p_node_type) const {
- return (style_map.has(p_node_type) && style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid());
+bool Theme::has_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+ return (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid());
+}
+
+bool Theme::has_stylebox_nocheck(const StringName &p_name, const StringName &p_theme_type) const {
+ return (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name));
}
-void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!style_map.has(p_node_type), "Cannot rename the stylebox '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(style_map[p_node_type].has(p_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
- ERR_FAIL_COND_MSG(!style_map[p_node_type].has(p_old_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because it does not exist.");
+void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!style_map.has(p_theme_type), "Cannot rename the stylebox '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(style_map[p_theme_type].has(p_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!style_map[p_theme_type].has(p_old_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because it does not exist.");
- style_map[p_node_type][p_name] = style_map[p_node_type][p_old_name];
- style_map[p_node_type].erase(p_old_name);
+ style_map[p_theme_type][p_name] = style_map[p_theme_type][p_old_name];
+ style_map[p_theme_type].erase(p_old_name);
- notify_property_list_changed();
- emit_changed();
+ _emit_theme_changed();
}
-void Theme::clear_stylebox(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!style_map.has(p_node_type), "Cannot clear the stylebox '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(!style_map[p_node_type].has(p_name), "Cannot clear the stylebox '" + String(p_name) + "' because it does not exist.");
+void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!style_map.has(p_theme_type), "Cannot clear the stylebox '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!style_map[p_theme_type].has(p_name), "Cannot clear the stylebox '" + String(p_name) + "' because it does not exist.");
- if (style_map[p_node_type][p_name].is_valid()) {
- style_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ if (style_map[p_theme_type][p_name].is_valid()) {
+ style_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
- style_map[p_node_type].erase(p_name);
+ style_map[p_theme_type].erase(p_name);
- notify_property_list_changed();
- emit_changed();
+ _emit_theme_changed();
}
-void Theme::get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const {
+void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- if (!style_map.has(p_node_type)) {
+ if (!style_map.has(p_theme_type)) {
return;
}
const StringName *key = nullptr;
- while ((key = style_map[p_node_type].next(key))) {
+ while ((key = style_map[p_theme_type].next(key))) {
p_list->push_back(*key);
}
}
-void Theme::add_stylebox_type(const StringName &p_node_type) {
- style_map[p_node_type] = HashMap<StringName, Ref<StyleBox>>();
+void Theme::add_stylebox_type(const StringName &p_theme_type) {
+ if (style_map.has(p_theme_type)) {
+ return;
+ }
+ style_map[p_theme_type] = HashMap<StringName, Ref<StyleBox>>();
}
void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
@@ -645,28 +648,23 @@ void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
}
}
-void Theme::set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font) {
- bool new_value = !font_map.has(p_node_type) || !font_map[p_node_type].has(p_name);
-
- if (font_map[p_node_type][p_name].is_valid()) {
- font_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font) {
+ if (font_map[p_theme_type][p_name].is_valid()) {
+ font_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
- font_map[p_node_type][p_name] = p_font;
+ font_map[p_theme_type][p_name] = p_font;
if (p_font.is_valid()) {
- font_map[p_node_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
+ font_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
}
- if (new_value) {
- notify_property_list_changed();
- emit_changed();
- }
+ _emit_theme_changed();
}
-Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_node_type) const {
- if (font_map.has(p_node_type) && font_map[p_node_type].has(p_name) && font_map[p_node_type][p_name].is_valid()) {
- return font_map[p_node_type][p_name];
+Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_theme_type) const {
+ if (font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) {
+ return font_map[p_theme_type][p_name];
} else if (default_theme_font.is_valid()) {
return default_theme_font;
} else {
@@ -674,51 +672,57 @@ Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_node_typ
}
}
-bool Theme::has_font(const StringName &p_name, const StringName &p_node_type) const {
- return ((font_map.has(p_node_type) && font_map[p_node_type].has(p_name) && font_map[p_node_type][p_name].is_valid()) || default_theme_font.is_valid());
+bool Theme::has_font(const StringName &p_name, const StringName &p_theme_type) const {
+ return ((font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) || default_theme_font.is_valid());
}
-void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!font_map.has(p_node_type), "Cannot rename the font '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(font_map[p_node_type].has(p_name), "Cannot rename the font '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
- ERR_FAIL_COND_MSG(!font_map[p_node_type].has(p_old_name), "Cannot rename the font '" + String(p_old_name) + "' because it does not exist.");
+bool Theme::has_font_nocheck(const StringName &p_name, const StringName &p_theme_type) const {
+ return (font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name));
+}
- font_map[p_node_type][p_name] = font_map[p_node_type][p_old_name];
- font_map[p_node_type].erase(p_old_name);
+void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!font_map.has(p_theme_type), "Cannot rename the font '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(font_map[p_theme_type].has(p_name), "Cannot rename the font '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!font_map[p_theme_type].has(p_old_name), "Cannot rename the font '" + String(p_old_name) + "' because it does not exist.");
- notify_property_list_changed();
- emit_changed();
+ font_map[p_theme_type][p_name] = font_map[p_theme_type][p_old_name];
+ font_map[p_theme_type].erase(p_old_name);
+
+ _emit_theme_changed();
}
-void Theme::clear_font(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!font_map.has(p_node_type), "Cannot clear the font '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(!font_map[p_node_type].has(p_name), "Cannot clear the font '" + String(p_name) + "' because it does not exist.");
+void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!font_map.has(p_theme_type), "Cannot clear the font '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!font_map[p_theme_type].has(p_name), "Cannot clear the font '" + String(p_name) + "' because it does not exist.");
- if (font_map[p_node_type][p_name].is_valid()) {
- font_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ if (font_map[p_theme_type][p_name].is_valid()) {
+ font_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
- font_map[p_node_type].erase(p_name);
- notify_property_list_changed();
- emit_changed();
+ font_map[p_theme_type].erase(p_name);
+
+ _emit_theme_changed();
}
-void Theme::get_font_list(StringName p_node_type, List<StringName> *p_list) const {
+void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- if (!font_map.has(p_node_type)) {
+ if (!font_map.has(p_theme_type)) {
return;
}
const StringName *key = nullptr;
- while ((key = font_map[p_node_type].next(key))) {
+ while ((key = font_map[p_theme_type].next(key))) {
p_list->push_back(*key);
}
}
-void Theme::add_font_type(const StringName &p_node_type) {
- font_map[p_node_type] = HashMap<StringName, Ref<Font>>();
+void Theme::add_font_type(const StringName &p_theme_type) {
+ if (font_map.has(p_theme_type)) {
+ return;
+ }
+ font_map[p_theme_type] = HashMap<StringName, Ref<Font>>();
}
void Theme::get_font_type_list(List<StringName> *p_list) const {
@@ -730,20 +734,15 @@ void Theme::get_font_type_list(List<StringName> *p_list) const {
}
}
-void Theme::set_font_size(const StringName &p_name, const StringName &p_node_type, int p_font_size) {
- bool new_value = !font_size_map.has(p_node_type) || !font_size_map[p_node_type].has(p_name);
-
- font_size_map[p_node_type][p_name] = p_font_size;
+void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size) {
+ font_size_map[p_theme_type][p_name] = p_font_size;
- if (new_value) {
- notify_property_list_changed();
- emit_changed();
- }
+ _emit_theme_changed();
}
-int Theme::get_font_size(const StringName &p_name, const StringName &p_node_type) const {
- if (font_size_map.has(p_node_type) && font_size_map[p_node_type].has(p_name) && (font_size_map[p_node_type][p_name] > 0)) {
- return font_size_map[p_node_type][p_name];
+int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+ if (font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) {
+ return font_size_map[p_theme_type][p_name];
} else if (default_theme_font_size > 0) {
return default_theme_font_size;
} else {
@@ -751,47 +750,53 @@ int Theme::get_font_size(const StringName &p_name, const StringName &p_node_type
}
}
-bool Theme::has_font_size(const StringName &p_name, const StringName &p_node_type) const {
- return ((font_size_map.has(p_node_type) && font_size_map[p_node_type].has(p_name) && (font_size_map[p_node_type][p_name] > 0)) || (default_theme_font_size > 0));
+bool Theme::has_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+ return ((font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) || (default_theme_font_size > 0));
}
-void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!font_size_map.has(p_node_type), "Cannot rename the font size '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(font_size_map[p_node_type].has(p_name), "Cannot rename the font size '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
- ERR_FAIL_COND_MSG(!font_size_map[p_node_type].has(p_old_name), "Cannot rename the font size '" + String(p_old_name) + "' because it does not exist.");
+bool Theme::has_font_size_nocheck(const StringName &p_name, const StringName &p_theme_type) const {
+ return (font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name));
+}
- font_size_map[p_node_type][p_name] = font_size_map[p_node_type][p_old_name];
- font_size_map[p_node_type].erase(p_old_name);
+void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!font_size_map.has(p_theme_type), "Cannot rename the font size '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(font_size_map[p_theme_type].has(p_name), "Cannot rename the font size '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!font_size_map[p_theme_type].has(p_old_name), "Cannot rename the font size '" + String(p_old_name) + "' because it does not exist.");
- notify_property_list_changed();
- emit_changed();
+ font_size_map[p_theme_type][p_name] = font_size_map[p_theme_type][p_old_name];
+ font_size_map[p_theme_type].erase(p_old_name);
+
+ _emit_theme_changed();
}
-void Theme::clear_font_size(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!font_size_map.has(p_node_type), "Cannot clear the font size '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(!font_size_map[p_node_type].has(p_name), "Cannot clear the font size '" + String(p_name) + "' because it does not exist.");
+void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!font_size_map.has(p_theme_type), "Cannot clear the font size '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!font_size_map[p_theme_type].has(p_name), "Cannot clear the font size '" + String(p_name) + "' because it does not exist.");
- font_size_map[p_node_type].erase(p_name);
- notify_property_list_changed();
- emit_changed();
+ font_size_map[p_theme_type].erase(p_name);
+
+ _emit_theme_changed();
}
-void Theme::get_font_size_list(StringName p_node_type, List<StringName> *p_list) const {
+void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- if (!font_size_map.has(p_node_type)) {
+ if (!font_size_map.has(p_theme_type)) {
return;
}
const StringName *key = nullptr;
- while ((key = font_size_map[p_node_type].next(key))) {
+ while ((key = font_size_map[p_theme_type].next(key))) {
p_list->push_back(*key);
}
}
-void Theme::add_font_size_type(const StringName &p_node_type) {
- font_size_map[p_node_type] = HashMap<StringName, int>();
+void Theme::add_font_size_type(const StringName &p_theme_type) {
+ if (font_size_map.has(p_theme_type)) {
+ return;
+ }
+ font_size_map[p_theme_type] = HashMap<StringName, int>();
}
void Theme::get_font_size_type_list(List<StringName> *p_list) const {
@@ -803,66 +808,67 @@ void Theme::get_font_size_type_list(List<StringName> *p_list) const {
}
}
-void Theme::set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color) {
- bool new_value = !color_map.has(p_node_type) || !color_map[p_node_type].has(p_name);
-
- color_map[p_node_type][p_name] = p_color;
+void Theme::set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color) {
+ color_map[p_theme_type][p_name] = p_color;
- if (new_value) {
- notify_property_list_changed();
- emit_changed();
- }
+ _emit_theme_changed();
}
-Color Theme::get_color(const StringName &p_name, const StringName &p_node_type) const {
- if (color_map.has(p_node_type) && color_map[p_node_type].has(p_name)) {
- return color_map[p_node_type][p_name];
+Color Theme::get_color(const StringName &p_name, const StringName &p_theme_type) const {
+ if (color_map.has(p_theme_type) && color_map[p_theme_type].has(p_name)) {
+ return color_map[p_theme_type][p_name];
} else {
return Color();
}
}
-bool Theme::has_color(const StringName &p_name, const StringName &p_node_type) const {
- return (color_map.has(p_node_type) && color_map[p_node_type].has(p_name));
+bool Theme::has_color(const StringName &p_name, const StringName &p_theme_type) const {
+ return (color_map.has(p_theme_type) && color_map[p_theme_type].has(p_name));
}
-void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!color_map.has(p_node_type), "Cannot rename the color '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(color_map[p_node_type].has(p_name), "Cannot rename the color '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
- ERR_FAIL_COND_MSG(!color_map[p_node_type].has(p_old_name), "Cannot rename the color '" + String(p_old_name) + "' because it does not exist.");
+bool Theme::has_color_nocheck(const StringName &p_name, const StringName &p_theme_type) const {
+ return (color_map.has(p_theme_type) && color_map[p_theme_type].has(p_name));
+}
- color_map[p_node_type][p_name] = color_map[p_node_type][p_old_name];
- color_map[p_node_type].erase(p_old_name);
+void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!color_map.has(p_theme_type), "Cannot rename the color '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(color_map[p_theme_type].has(p_name), "Cannot rename the color '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!color_map[p_theme_type].has(p_old_name), "Cannot rename the color '" + String(p_old_name) + "' because it does not exist.");
- notify_property_list_changed();
- emit_changed();
+ color_map[p_theme_type][p_name] = color_map[p_theme_type][p_old_name];
+ color_map[p_theme_type].erase(p_old_name);
+
+ _emit_theme_changed();
}
-void Theme::clear_color(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!color_map.has(p_node_type), "Cannot clear the color '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(!color_map[p_node_type].has(p_name), "Cannot clear the color '" + String(p_name) + "' because it does not exist.");
+void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!color_map.has(p_theme_type), "Cannot clear the color '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!color_map[p_theme_type].has(p_name), "Cannot clear the color '" + String(p_name) + "' because it does not exist.");
- color_map[p_node_type].erase(p_name);
- notify_property_list_changed();
- emit_changed();
+ color_map[p_theme_type].erase(p_name);
+
+ _emit_theme_changed();
}
-void Theme::get_color_list(StringName p_node_type, List<StringName> *p_list) const {
+void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- if (!color_map.has(p_node_type)) {
+ if (!color_map.has(p_theme_type)) {
return;
}
const StringName *key = nullptr;
- while ((key = color_map[p_node_type].next(key))) {
+ while ((key = color_map[p_theme_type].next(key))) {
p_list->push_back(*key);
}
}
-void Theme::add_color_type(const StringName &p_node_type) {
- color_map[p_node_type] = HashMap<StringName, Color>();
+void Theme::add_color_type(const StringName &p_theme_type) {
+ if (color_map.has(p_theme_type)) {
+ return;
+ }
+ color_map[p_theme_type] = HashMap<StringName, Color>();
}
void Theme::get_color_type_list(List<StringName> *p_list) const {
@@ -874,65 +880,67 @@ void Theme::get_color_type_list(List<StringName> *p_list) const {
}
}
-void Theme::set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant) {
- bool new_value = !constant_map.has(p_node_type) || !constant_map[p_node_type].has(p_name);
- constant_map[p_node_type][p_name] = p_constant;
+void Theme::set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant) {
+ constant_map[p_theme_type][p_name] = p_constant;
- if (new_value) {
- notify_property_list_changed();
- emit_changed();
- }
+ _emit_theme_changed();
}
-int Theme::get_constant(const StringName &p_name, const StringName &p_node_type) const {
- if (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name)) {
- return constant_map[p_node_type][p_name];
+int Theme::get_constant(const StringName &p_name, const StringName &p_theme_type) const {
+ if (constant_map.has(p_theme_type) && constant_map[p_theme_type].has(p_name)) {
+ return constant_map[p_theme_type][p_name];
} else {
return 0;
}
}
-bool Theme::has_constant(const StringName &p_name, const StringName &p_node_type) const {
- return (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name));
+bool Theme::has_constant(const StringName &p_name, const StringName &p_theme_type) const {
+ return (constant_map.has(p_theme_type) && constant_map[p_theme_type].has(p_name));
}
-void Theme::rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!constant_map.has(p_node_type), "Cannot rename the constant '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(constant_map[p_node_type].has(p_name), "Cannot rename the constant '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
- ERR_FAIL_COND_MSG(!constant_map[p_node_type].has(p_old_name), "Cannot rename the constant '" + String(p_old_name) + "' because it does not exist.");
+bool Theme::has_constant_nocheck(const StringName &p_name, const StringName &p_theme_type) const {
+ return (constant_map.has(p_theme_type) && constant_map[p_theme_type].has(p_name));
+}
- constant_map[p_node_type][p_name] = constant_map[p_node_type][p_old_name];
- constant_map[p_node_type].erase(p_old_name);
+void Theme::rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!constant_map.has(p_theme_type), "Cannot rename the constant '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(constant_map[p_theme_type].has(p_name), "Cannot rename the constant '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!constant_map[p_theme_type].has(p_old_name), "Cannot rename the constant '" + String(p_old_name) + "' because it does not exist.");
- notify_property_list_changed();
- emit_changed();
+ constant_map[p_theme_type][p_name] = constant_map[p_theme_type][p_old_name];
+ constant_map[p_theme_type].erase(p_old_name);
+
+ _emit_theme_changed();
}
-void Theme::clear_constant(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND_MSG(!constant_map.has(p_node_type), "Cannot clear the constant '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
- ERR_FAIL_COND_MSG(!constant_map[p_node_type].has(p_name), "Cannot clear the constant '" + String(p_name) + "' because it does not exist.");
+void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_type) {
+ ERR_FAIL_COND_MSG(!constant_map.has(p_theme_type), "Cannot clear the constant '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!constant_map[p_theme_type].has(p_name), "Cannot clear the constant '" + String(p_name) + "' because it does not exist.");
- constant_map[p_node_type].erase(p_name);
- notify_property_list_changed();
- emit_changed();
+ constant_map[p_theme_type].erase(p_name);
+
+ _emit_theme_changed();
}
-void Theme::get_constant_list(StringName p_node_type, List<StringName> *p_list) const {
+void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- if (!constant_map.has(p_node_type)) {
+ if (!constant_map.has(p_theme_type)) {
return;
}
const StringName *key = nullptr;
- while ((key = constant_map[p_node_type].next(key))) {
+ while ((key = constant_map[p_theme_type].next(key))) {
p_list->push_back(*key);
}
}
-void Theme::add_constant_type(const StringName &p_node_type) {
- constant_map[p_node_type] = HashMap<StringName, int>();
+void Theme::add_constant_type(const StringName &p_theme_type) {
+ if (constant_map.has(p_theme_type)) {
+ return;
+ }
+ constant_map[p_theme_type] = HashMap<StringName, int>();
}
void Theme::get_constant_type_list(List<StringName> *p_list) const {
@@ -944,63 +952,63 @@ void Theme::get_constant_type_list(List<StringName> *p_list) const {
}
}
-void Theme::set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value) {
+void Theme::set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type, const Variant &p_value) {
switch (p_data_type) {
case DATA_TYPE_COLOR: {
ERR_FAIL_COND_MSG(p_value.get_type() != Variant::COLOR, "Theme item's data type (Color) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
Color color_value = p_value;
- set_color(p_name, p_node_type, color_value);
+ set_color(p_name, p_theme_type, color_value);
} break;
case DATA_TYPE_CONSTANT: {
ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
int constant_value = p_value;
- set_constant(p_name, p_node_type, constant_value);
+ set_constant(p_name, p_theme_type, constant_value);
} break;
case DATA_TYPE_FONT: {
ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
Ref<Font> font_value = Object::cast_to<Font>(p_value.get_validated_object());
- set_font(p_name, p_node_type, font_value);
+ set_font(p_name, p_theme_type, font_value);
} break;
case DATA_TYPE_FONT_SIZE: {
ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
int font_size_value = p_value;
- set_font_size(p_name, p_node_type, font_size_value);
+ set_font_size(p_name, p_theme_type, font_size_value);
} break;
case DATA_TYPE_ICON: {
ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
Ref<Texture2D> icon_value = Object::cast_to<Texture2D>(p_value.get_validated_object());
- set_icon(p_name, p_node_type, icon_value);
+ set_icon(p_name, p_theme_type, icon_value);
} break;
case DATA_TYPE_STYLEBOX: {
ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
Ref<StyleBox> stylebox_value = Object::cast_to<StyleBox>(p_value.get_validated_object());
- set_stylebox(p_name, p_node_type, stylebox_value);
+ set_stylebox(p_name, p_theme_type, stylebox_value);
} break;
case DATA_TYPE_MAX:
break; // Can't happen, but silences warning.
}
}
-Variant Theme::get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const {
+Variant Theme::get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const {
switch (p_data_type) {
case DATA_TYPE_COLOR:
- return get_color(p_name, p_node_type);
+ return get_color(p_name, p_theme_type);
case DATA_TYPE_CONSTANT:
- return get_constant(p_name, p_node_type);
+ return get_constant(p_name, p_theme_type);
case DATA_TYPE_FONT:
- return get_font(p_name, p_node_type);
+ return get_font(p_name, p_theme_type);
case DATA_TYPE_FONT_SIZE:
- return get_font_size(p_name, p_node_type);
+ return get_font_size(p_name, p_theme_type);
case DATA_TYPE_ICON:
- return get_icon(p_name, p_node_type);
+ return get_icon(p_name, p_theme_type);
case DATA_TYPE_STYLEBOX:
- return get_stylebox(p_name, p_node_type);
+ return get_stylebox(p_name, p_theme_type);
case DATA_TYPE_MAX:
break; // Can't happen, but silences warning.
}
@@ -1008,20 +1016,41 @@ Variant Theme::get_theme_item(DataType p_data_type, const StringName &p_name, co
return Variant();
}
-bool Theme::has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const {
+bool Theme::has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return has_color(p_name, p_theme_type);
+ case DATA_TYPE_CONSTANT:
+ return has_constant(p_name, p_theme_type);
+ case DATA_TYPE_FONT:
+ return has_font(p_name, p_theme_type);
+ case DATA_TYPE_FONT_SIZE:
+ return has_font_size(p_name, p_theme_type);
+ case DATA_TYPE_ICON:
+ return has_icon(p_name, p_theme_type);
+ case DATA_TYPE_STYLEBOX:
+ return has_stylebox(p_name, p_theme_type);
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return false;
+}
+
+bool Theme::has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const {
switch (p_data_type) {
case DATA_TYPE_COLOR:
- return has_color(p_name, p_node_type);
+ return has_color_nocheck(p_name, p_theme_type);
case DATA_TYPE_CONSTANT:
- return has_constant(p_name, p_node_type);
+ return has_constant_nocheck(p_name, p_theme_type);
case DATA_TYPE_FONT:
- return has_font(p_name, p_node_type);
+ return has_font_nocheck(p_name, p_theme_type);
case DATA_TYPE_FONT_SIZE:
- return has_font_size(p_name, p_node_type);
+ return has_font_size_nocheck(p_name, p_theme_type);
case DATA_TYPE_ICON:
- return has_icon(p_name, p_node_type);
+ return has_icon_nocheck(p_name, p_theme_type);
case DATA_TYPE_STYLEBOX:
- return has_stylebox(p_name, p_node_type);
+ return has_stylebox_nocheck(p_name, p_theme_type);
case DATA_TYPE_MAX:
break; // Can't happen, but silences warning.
}
@@ -1029,100 +1058,100 @@ bool Theme::has_theme_item(DataType p_data_type, const StringName &p_name, const
return false;
}
-void Theme::rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+void Theme::rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) {
switch (p_data_type) {
case DATA_TYPE_COLOR:
- rename_color(p_old_name, p_name, p_node_type);
+ rename_color(p_old_name, p_name, p_theme_type);
break;
case DATA_TYPE_CONSTANT:
- rename_constant(p_old_name, p_name, p_node_type);
+ rename_constant(p_old_name, p_name, p_theme_type);
break;
case DATA_TYPE_FONT:
- rename_font(p_old_name, p_name, p_node_type);
+ rename_font(p_old_name, p_name, p_theme_type);
break;
case DATA_TYPE_FONT_SIZE:
- rename_font_size(p_old_name, p_name, p_node_type);
+ rename_font_size(p_old_name, p_name, p_theme_type);
break;
case DATA_TYPE_ICON:
- rename_icon(p_old_name, p_name, p_node_type);
+ rename_icon(p_old_name, p_name, p_theme_type);
break;
case DATA_TYPE_STYLEBOX:
- rename_stylebox(p_old_name, p_name, p_node_type);
+ rename_stylebox(p_old_name, p_name, p_theme_type);
break;
case DATA_TYPE_MAX:
break; // Can't happen, but silences warning.
}
}
-void Theme::clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) {
+void Theme::clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) {
switch (p_data_type) {
case DATA_TYPE_COLOR:
- clear_color(p_name, p_node_type);
+ clear_color(p_name, p_theme_type);
break;
case DATA_TYPE_CONSTANT:
- clear_constant(p_name, p_node_type);
+ clear_constant(p_name, p_theme_type);
break;
case DATA_TYPE_FONT:
- clear_font(p_name, p_node_type);
+ clear_font(p_name, p_theme_type);
break;
case DATA_TYPE_FONT_SIZE:
- clear_font_size(p_name, p_node_type);
+ clear_font_size(p_name, p_theme_type);
break;
case DATA_TYPE_ICON:
- clear_icon(p_name, p_node_type);
+ clear_icon(p_name, p_theme_type);
break;
case DATA_TYPE_STYLEBOX:
- clear_stylebox(p_name, p_node_type);
+ clear_stylebox(p_name, p_theme_type);
break;
case DATA_TYPE_MAX:
break; // Can't happen, but silences warning.
}
}
-void Theme::get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const {
+void Theme::get_theme_item_list(DataType p_data_type, StringName p_theme_type, List<StringName> *p_list) const {
switch (p_data_type) {
case DATA_TYPE_COLOR:
- get_color_list(p_node_type, p_list);
+ get_color_list(p_theme_type, p_list);
break;
case DATA_TYPE_CONSTANT:
- get_constant_list(p_node_type, p_list);
+ get_constant_list(p_theme_type, p_list);
break;
case DATA_TYPE_FONT:
- get_font_list(p_node_type, p_list);
+ get_font_list(p_theme_type, p_list);
break;
case DATA_TYPE_FONT_SIZE:
- get_font_size_list(p_node_type, p_list);
+ get_font_size_list(p_theme_type, p_list);
break;
case DATA_TYPE_ICON:
- get_icon_list(p_node_type, p_list);
+ get_icon_list(p_theme_type, p_list);
break;
case DATA_TYPE_STYLEBOX:
- get_stylebox_list(p_node_type, p_list);
+ get_stylebox_list(p_theme_type, p_list);
break;
case DATA_TYPE_MAX:
break; // Can't happen, but silences warning.
}
}
-void Theme::add_theme_item_type(DataType p_data_type, const StringName &p_node_type) {
+void Theme::add_theme_item_type(DataType p_data_type, const StringName &p_theme_type) {
switch (p_data_type) {
case DATA_TYPE_COLOR:
- add_color_type(p_node_type);
+ add_color_type(p_theme_type);
break;
case DATA_TYPE_CONSTANT:
- add_constant_type(p_node_type);
+ add_constant_type(p_theme_type);
break;
case DATA_TYPE_FONT:
- add_font_type(p_node_type);
+ add_font_type(p_theme_type);
break;
case DATA_TYPE_FONT_SIZE:
- add_font_size_type(p_node_type);
+ add_font_size_type(p_theme_type);
break;
case DATA_TYPE_ICON:
- add_icon_type(p_node_type);
+ add_icon_type(p_theme_type);
break;
case DATA_TYPE_STYLEBOX:
- add_stylebox_type(p_node_type);
+ add_stylebox_type(p_theme_type);
break;
case DATA_TYPE_MAX:
break; // Can't happen, but silences warning.
@@ -1154,8 +1183,17 @@ void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_l
}
}
+void Theme::_freeze_change_propagation() {
+ no_change_propagation = true;
+}
+
+void Theme::_unfreeze_and_propagate_changes() {
+ no_change_propagation = false;
+ _emit_theme_changed();
+}
+
void Theme::clear() {
- //these need disconnecting
+ // These items need disconnecting.
{
const StringName *K = nullptr;
while ((K = icon_map.next(K))) {
@@ -1201,8 +1239,7 @@ void Theme::clear() {
color_map.clear();
constant_map.clear();
- notify_property_list_changed();
- emit_changed();
+ _emit_theme_changed();
}
void Theme::copy_default_theme() {
@@ -1216,6 +1253,8 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
return;
}
+ _freeze_change_propagation();
+
// These items need reconnecting, so add them normally.
{
const StringName *K = nullptr;
@@ -1252,8 +1291,7 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
color_map = p_other->color_map;
constant_map = p_other->constant_map;
- notify_property_list_changed();
- emit_changed();
+ _unfreeze_and_propagate_changes();
}
void Theme::get_type_list(List<StringName> *p_list) const {
@@ -1295,56 +1333,66 @@ void Theme::get_type_list(List<StringName> *p_list) const {
}
}
+void Theme::get_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) {
+ ERR_FAIL_NULL(p_list);
+
+ StringName class_name = p_theme_type;
+ while (class_name != StringName()) {
+ p_list->push_back(class_name);
+ class_name = ClassDB::get_parent_class_nocheck(class_name);
+ }
+}
+
void Theme::reset_state() {
clear();
}
void Theme::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_icon", "name", "node_type", "texture"), &Theme::set_icon);
- ClassDB::bind_method(D_METHOD("get_icon", "name", "node_type"), &Theme::get_icon);
- ClassDB::bind_method(D_METHOD("has_icon", "name", "node_type"), &Theme::has_icon);
- ClassDB::bind_method(D_METHOD("rename_icon", "old_name", "name", "node_type"), &Theme::rename_icon);
- ClassDB::bind_method(D_METHOD("clear_icon", "name", "node_type"), &Theme::clear_icon);
- ClassDB::bind_method(D_METHOD("get_icon_list", "node_type"), &Theme::_get_icon_list);
+ ClassDB::bind_method(D_METHOD("set_icon", "name", "theme_type", "texture"), &Theme::set_icon);
+ ClassDB::bind_method(D_METHOD("get_icon", "name", "theme_type"), &Theme::get_icon);
+ ClassDB::bind_method(D_METHOD("has_icon", "name", "theme_type"), &Theme::has_icon);
+ ClassDB::bind_method(D_METHOD("rename_icon", "old_name", "name", "theme_type"), &Theme::rename_icon);
+ ClassDB::bind_method(D_METHOD("clear_icon", "name", "theme_type"), &Theme::clear_icon);
+ ClassDB::bind_method(D_METHOD("get_icon_list", "theme_type"), &Theme::_get_icon_list);
ClassDB::bind_method(D_METHOD("get_icon_type_list"), &Theme::_get_icon_type_list);
- ClassDB::bind_method(D_METHOD("set_stylebox", "name", "node_type", "texture"), &Theme::set_stylebox);
- ClassDB::bind_method(D_METHOD("get_stylebox", "name", "node_type"), &Theme::get_stylebox);
- ClassDB::bind_method(D_METHOD("has_stylebox", "name", "node_type"), &Theme::has_stylebox);
- ClassDB::bind_method(D_METHOD("rename_stylebox", "old_name", "name", "node_type"), &Theme::rename_stylebox);
- ClassDB::bind_method(D_METHOD("clear_stylebox", "name", "node_type"), &Theme::clear_stylebox);
- ClassDB::bind_method(D_METHOD("get_stylebox_list", "node_type"), &Theme::_get_stylebox_list);
+ ClassDB::bind_method(D_METHOD("set_stylebox", "name", "theme_type", "texture"), &Theme::set_stylebox);
+ ClassDB::bind_method(D_METHOD("get_stylebox", "name", "theme_type"), &Theme::get_stylebox);
+ ClassDB::bind_method(D_METHOD("has_stylebox", "name", "theme_type"), &Theme::has_stylebox);
+ ClassDB::bind_method(D_METHOD("rename_stylebox", "old_name", "name", "theme_type"), &Theme::rename_stylebox);
+ ClassDB::bind_method(D_METHOD("clear_stylebox", "name", "theme_type"), &Theme::clear_stylebox);
+ ClassDB::bind_method(D_METHOD("get_stylebox_list", "theme_type"), &Theme::_get_stylebox_list);
ClassDB::bind_method(D_METHOD("get_stylebox_type_list"), &Theme::_get_stylebox_type_list);
- ClassDB::bind_method(D_METHOD("set_font", "name", "node_type", "font"), &Theme::set_font);
- ClassDB::bind_method(D_METHOD("get_font", "name", "node_type"), &Theme::get_font);
- ClassDB::bind_method(D_METHOD("has_font", "name", "node_type"), &Theme::has_font);
- ClassDB::bind_method(D_METHOD("rename_font", "old_name", "name", "node_type"), &Theme::rename_font);
- ClassDB::bind_method(D_METHOD("clear_font", "name", "node_type"), &Theme::clear_font);
- ClassDB::bind_method(D_METHOD("get_font_list", "node_type"), &Theme::_get_font_list);
+ ClassDB::bind_method(D_METHOD("set_font", "name", "theme_type", "font"), &Theme::set_font);
+ ClassDB::bind_method(D_METHOD("get_font", "name", "theme_type"), &Theme::get_font);
+ ClassDB::bind_method(D_METHOD("has_font", "name", "theme_type"), &Theme::has_font);
+ ClassDB::bind_method(D_METHOD("rename_font", "old_name", "name", "theme_type"), &Theme::rename_font);
+ ClassDB::bind_method(D_METHOD("clear_font", "name", "theme_type"), &Theme::clear_font);
+ ClassDB::bind_method(D_METHOD("get_font_list", "theme_type"), &Theme::_get_font_list);
ClassDB::bind_method(D_METHOD("get_font_type_list"), &Theme::_get_font_type_list);
- ClassDB::bind_method(D_METHOD("set_font_size", "name", "node_type", "font_size"), &Theme::set_font_size);
- ClassDB::bind_method(D_METHOD("get_font_size", "name", "node_type"), &Theme::get_font_size);
- ClassDB::bind_method(D_METHOD("has_font_size", "name", "node_type"), &Theme::has_font_size);
- ClassDB::bind_method(D_METHOD("rename_font_size", "old_name", "name", "node_type"), &Theme::rename_font_size);
- ClassDB::bind_method(D_METHOD("clear_font_size", "name", "node_type"), &Theme::clear_font_size);
- ClassDB::bind_method(D_METHOD("get_font_size_list", "node_type"), &Theme::_get_font_size_list);
+ ClassDB::bind_method(D_METHOD("set_font_size", "name", "theme_type", "font_size"), &Theme::set_font_size);
+ ClassDB::bind_method(D_METHOD("get_font_size", "name", "theme_type"), &Theme::get_font_size);
+ ClassDB::bind_method(D_METHOD("has_font_size", "name", "theme_type"), &Theme::has_font_size);
+ ClassDB::bind_method(D_METHOD("rename_font_size", "old_name", "name", "theme_type"), &Theme::rename_font_size);
+ ClassDB::bind_method(D_METHOD("clear_font_size", "name", "theme_type"), &Theme::clear_font_size);
+ ClassDB::bind_method(D_METHOD("get_font_size_list", "theme_type"), &Theme::_get_font_size_list);
ClassDB::bind_method(D_METHOD("get_font_size_type_list"), &Theme::_get_font_size_type_list);
- ClassDB::bind_method(D_METHOD("set_color", "name", "node_type", "color"), &Theme::set_color);
- ClassDB::bind_method(D_METHOD("get_color", "name", "node_type"), &Theme::get_color);
- ClassDB::bind_method(D_METHOD("has_color", "name", "node_type"), &Theme::has_color);
- ClassDB::bind_method(D_METHOD("rename_color", "old_name", "name", "node_type"), &Theme::rename_color);
- ClassDB::bind_method(D_METHOD("clear_color", "name", "node_type"), &Theme::clear_color);
- ClassDB::bind_method(D_METHOD("get_color_list", "node_type"), &Theme::_get_color_list);
+ ClassDB::bind_method(D_METHOD("set_color", "name", "theme_type", "color"), &Theme::set_color);
+ ClassDB::bind_method(D_METHOD("get_color", "name", "theme_type"), &Theme::get_color);
+ ClassDB::bind_method(D_METHOD("has_color", "name", "theme_type"), &Theme::has_color);
+ ClassDB::bind_method(D_METHOD("rename_color", "old_name", "name", "theme_type"), &Theme::rename_color);
+ ClassDB::bind_method(D_METHOD("clear_color", "name", "theme_type"), &Theme::clear_color);
+ ClassDB::bind_method(D_METHOD("get_color_list", "theme_type"), &Theme::_get_color_list);
ClassDB::bind_method(D_METHOD("get_color_type_list"), &Theme::_get_color_type_list);
- ClassDB::bind_method(D_METHOD("set_constant", "name", "node_type", "constant"), &Theme::set_constant);
- ClassDB::bind_method(D_METHOD("get_constant", "name", "node_type"), &Theme::get_constant);
- ClassDB::bind_method(D_METHOD("has_constant", "name", "node_type"), &Theme::has_constant);
- ClassDB::bind_method(D_METHOD("rename_constant", "old_name", "name", "node_type"), &Theme::rename_constant);
- ClassDB::bind_method(D_METHOD("clear_constant", "name", "node_type"), &Theme::clear_constant);
- ClassDB::bind_method(D_METHOD("get_constant_list", "node_type"), &Theme::_get_constant_list);
+ ClassDB::bind_method(D_METHOD("set_constant", "name", "theme_type", "constant"), &Theme::set_constant);
+ ClassDB::bind_method(D_METHOD("get_constant", "name", "theme_type"), &Theme::get_constant);
+ ClassDB::bind_method(D_METHOD("has_constant", "name", "theme_type"), &Theme::has_constant);
+ ClassDB::bind_method(D_METHOD("rename_constant", "old_name", "name", "theme_type"), &Theme::rename_constant);
+ ClassDB::bind_method(D_METHOD("clear_constant", "name", "theme_type"), &Theme::clear_constant);
+ ClassDB::bind_method(D_METHOD("get_constant_list", "theme_type"), &Theme::_get_constant_list);
ClassDB::bind_method(D_METHOD("get_constant_type_list"), &Theme::_get_constant_type_list);
ClassDB::bind_method(D_METHOD("clear"), &Theme::clear);
@@ -1355,12 +1403,12 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_font_size", "font_size"), &Theme::set_default_theme_font_size);
ClassDB::bind_method(D_METHOD("get_default_font_size"), &Theme::get_default_theme_font_size);
- ClassDB::bind_method(D_METHOD("set_theme_item", "data_type", "name", "node_type", "value"), &Theme::set_theme_item);
- ClassDB::bind_method(D_METHOD("get_theme_item", "data_type", "name", "node_type"), &Theme::get_theme_item);
- ClassDB::bind_method(D_METHOD("has_theme_item", "data_type", "name", "node_type"), &Theme::has_theme_item);
- ClassDB::bind_method(D_METHOD("rename_theme_item", "data_type", "old_name", "name", "node_type"), &Theme::rename_theme_item);
- ClassDB::bind_method(D_METHOD("clear_theme_item", "data_type", "name", "node_type"), &Theme::clear_theme_item);
- ClassDB::bind_method(D_METHOD("get_theme_item_list", "data_type", "node_type"), &Theme::_get_theme_item_list);
+ ClassDB::bind_method(D_METHOD("set_theme_item", "data_type", "name", "theme_type", "value"), &Theme::set_theme_item);
+ ClassDB::bind_method(D_METHOD("get_theme_item", "data_type", "name", "theme_type"), &Theme::get_theme_item);
+ ClassDB::bind_method(D_METHOD("has_theme_item", "data_type", "name", "theme_type"), &Theme::has_theme_item);
+ ClassDB::bind_method(D_METHOD("rename_theme_item", "data_type", "old_name", "name", "theme_type"), &Theme::rename_theme_item);
+ ClassDB::bind_method(D_METHOD("clear_theme_item", "data_type", "name", "theme_type"), &Theme::clear_theme_item);
+ ClassDB::bind_method(D_METHOD("get_theme_item_list", "data_type", "theme_type"), &Theme::_get_theme_item_list);
ClassDB::bind_method(D_METHOD("get_theme_item_type_list", "data_type"), &Theme::_get_theme_item_type_list);
ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list);
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index eb918fac69..fe64fd7290 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -41,6 +41,12 @@ class Theme : public Resource {
GDCLASS(Theme, Resource);
RES_BASE_EXTENSION("theme");
+#ifdef TOOLS_ENABLED
+ friend class ThemeItemImportTree;
+ friend class ThemeItemEditorDialog;
+ friend class ThemeTypeEditor;
+#endif
+
public:
enum DataType {
DATA_TYPE_COLOR,
@@ -53,6 +59,8 @@ public:
};
private:
+ bool no_change_propagation = false;
+
void _emit_theme_changed();
HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map;
@@ -62,20 +70,20 @@ private:
HashMap<StringName, HashMap<StringName, Color>> color_map;
HashMap<StringName, HashMap<StringName, int>> constant_map;
- Vector<String> _get_icon_list(const String &p_node_type) const;
+ Vector<String> _get_icon_list(const String &p_theme_type) const;
Vector<String> _get_icon_type_list() const;
- Vector<String> _get_stylebox_list(const String &p_node_type) const;
+ Vector<String> _get_stylebox_list(const String &p_theme_type) const;
Vector<String> _get_stylebox_type_list() const;
- Vector<String> _get_font_list(const String &p_node_type) const;
+ Vector<String> _get_font_list(const String &p_theme_type) const;
Vector<String> _get_font_type_list() const;
- Vector<String> _get_font_size_list(const String &p_node_type) const;
+ Vector<String> _get_font_size_list(const String &p_theme_type) const;
Vector<String> _get_font_size_type_list() const;
- Vector<String> _get_color_list(const String &p_node_type) const;
+ Vector<String> _get_color_list(const String &p_theme_type) const;
Vector<String> _get_color_type_list() const;
- Vector<String> _get_constant_list(const String &p_node_type) const;
+ Vector<String> _get_constant_list(const String &p_theme_type) const;
Vector<String> _get_constant_type_list() const;
- Vector<String> _get_theme_item_list(DataType p_data_type, const String &p_node_type) const;
+ Vector<String> _get_theme_item_list(DataType p_data_type, const String &p_theme_type) const;
Vector<String> _get_theme_item_type_list(DataType p_data_type) const;
Vector<String> _get_type_list() const;
@@ -96,6 +104,9 @@ protected:
static void _bind_methods();
+ void _freeze_change_propagation();
+ void _unfreeze_and_propagate_changes();
+
virtual void reset_state() override;
public:
@@ -116,70 +127,78 @@ public:
void set_default_theme_font_size(int p_font_size);
int get_default_theme_font_size() const;
- void set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon);
- Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_node_type) const;
- bool has_icon(const StringName &p_name, const StringName &p_node_type) const;
- void rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
- void clear_icon(const StringName &p_name, const StringName &p_node_type);
- void get_icon_list(StringName p_node_type, List<StringName> *p_list) const;
- void add_icon_type(const StringName &p_node_type);
+ void set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon);
+ Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_icon(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_icon_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
+ void rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
+ void clear_icon(const StringName &p_name, const StringName &p_theme_type);
+ void get_icon_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void add_icon_type(const StringName &p_theme_type);
void get_icon_type_list(List<StringName> *p_list) const;
- void set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style);
- Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_node_type) const;
- bool has_stylebox(const StringName &p_name, const StringName &p_node_type) const;
- void rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
- void clear_stylebox(const StringName &p_name, const StringName &p_node_type);
- void get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const;
- void add_stylebox_type(const StringName &p_node_type);
+ void set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style);
+ Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_stylebox(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_stylebox_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
+ void rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
+ void clear_stylebox(const StringName &p_name, const StringName &p_theme_type);
+ void get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void add_stylebox_type(const StringName &p_theme_type);
void get_stylebox_type_list(List<StringName> *p_list) const;
- void set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font);
- Ref<Font> get_font(const StringName &p_name, const StringName &p_node_type) const;
- bool has_font(const StringName &p_name, const StringName &p_node_type) const;
- void rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
- void clear_font(const StringName &p_name, const StringName &p_node_type);
- void get_font_list(StringName p_node_type, List<StringName> *p_list) const;
- void add_font_type(const StringName &p_node_type);
+ void set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font);
+ Ref<Font> get_font(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_font(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_font_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
+ void rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
+ void clear_font(const StringName &p_name, const StringName &p_theme_type);
+ void get_font_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void add_font_type(const StringName &p_theme_type);
void get_font_type_list(List<StringName> *p_list) const;
- void set_font_size(const StringName &p_name, const StringName &p_node_type, int p_font_size);
- int get_font_size(const StringName &p_name, const StringName &p_node_type) const;
- bool has_font_size(const StringName &p_name, const StringName &p_node_type) const;
- void rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
- void clear_font_size(const StringName &p_name, const StringName &p_node_type);
- void get_font_size_list(StringName p_node_type, List<StringName> *p_list) const;
- void add_font_size_type(const StringName &p_node_type);
+ void set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size);
+ int get_font_size(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_font_size(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_font_size_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
+ void rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
+ void clear_font_size(const StringName &p_name, const StringName &p_theme_type);
+ void get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void add_font_size_type(const StringName &p_theme_type);
void get_font_size_type_list(List<StringName> *p_list) const;
- void set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color);
- Color get_color(const StringName &p_name, const StringName &p_node_type) const;
- bool has_color(const StringName &p_name, const StringName &p_node_type) const;
- void rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
- void clear_color(const StringName &p_name, const StringName &p_node_type);
- void get_color_list(StringName p_node_type, List<StringName> *p_list) const;
- void add_color_type(const StringName &p_node_type);
+ void set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color);
+ Color get_color(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_color(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_color_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
+ void rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
+ void clear_color(const StringName &p_name, const StringName &p_theme_type);
+ void get_color_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void add_color_type(const StringName &p_theme_type);
void get_color_type_list(List<StringName> *p_list) const;
- void set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant);
- int get_constant(const StringName &p_name, const StringName &p_node_type) const;
- bool has_constant(const StringName &p_name, const StringName &p_node_type) const;
- void rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
- void clear_constant(const StringName &p_name, const StringName &p_node_type);
- void get_constant_list(StringName p_node_type, List<StringName> *p_list) const;
- void add_constant_type(const StringName &p_node_type);
+ void set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant);
+ int get_constant(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_constant(const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_constant_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
+ void rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
+ void clear_constant(const StringName &p_name, const StringName &p_theme_type);
+ void get_constant_list(StringName p_theme_type, List<StringName> *p_list) const;
+ void add_constant_type(const StringName &p_theme_type);
void get_constant_type_list(List<StringName> *p_list) const;
- void set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value);
- Variant get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
- bool has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
- void rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
- void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type);
- void get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const;
- void add_theme_item_type(DataType p_data_type, const StringName &p_node_type);
+ void set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type, const Variant &p_value);
+ Variant get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const;
+ bool has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const;
+ void rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
+ void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type);
+ void get_theme_item_list(DataType p_data_type, StringName p_theme_type, List<StringName> *p_list) const;
+ void add_theme_item_type(DataType p_data_type, const StringName &p_theme_type);
void get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const;
void get_type_list(List<StringName> *p_list) const;
+ static void get_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list);
void copy_default_theme();
void copy_theme(const Ref<Theme> &p_other);
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 84be69d0d6..0d6f3c07f0 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -30,1150 +30,4641 @@
#include "tile_set.h"
-#include "core/config/engine.h"
#include "core/math/geometry_2d.h"
-#include "core/variant/array.h"
+#include "scene/2d/navigation_region_2d.h"
+#include "scene/gui/control.h"
+#include "scene/resources/convex_polygon_shape_2d.h"
+#include "servers/navigation_server_2d.h"
-bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
- String n = p_name;
- int slash = n.find("/");
- if (slash == -1) {
- return false;
- }
- int id = String::to_int(n.get_data(), slash);
-
- if (!tile_map.has(id)) {
- create_tile(id);
- }
- String what = n.substr(slash + 1, n.length());
-
- if (what == "name") {
- tile_set_name(id, p_value);
- } else if (what == "texture") {
- tile_set_texture(id, p_value);
- } else if (what == "tex_offset") {
- tile_set_texture_offset(id, p_value);
- } else if (what == "material") {
- tile_set_material(id, p_value);
- } else if (what == "modulate") {
- tile_set_modulate(id, p_value);
- } else if (what == "region") {
- tile_set_region(id, p_value);
- } else if (what == "tile_mode") {
- tile_set_tile_mode(id, (TileMode)((int)p_value));
- } else if (what == "is_autotile") {
- // backward compatibility for Godot 3.0.x
- // autotile used to be a bool, it's now an enum
- bool is_autotile = p_value;
- if (is_autotile) {
- tile_set_tile_mode(id, AUTO_TILE);
- }
- } else if (what.left(9) == "autotile/") {
- what = what.right(9);
- if (what == "bitmask_mode") {
- autotile_set_bitmask_mode(id, (BitmaskMode)((int)p_value));
- } else if (what == "icon_coordinate") {
- autotile_set_icon_coordinate(id, p_value);
- } else if (what == "tile_size") {
- autotile_set_size(id, p_value);
- } else if (what == "spacing") {
- autotile_set_spacing(id, p_value);
- } else if (what == "bitmask_flags") {
- tile_map[id].autotile_data.flags.clear();
- if (p_value.is_array()) {
- Array p = p_value;
- Vector2 last_coord;
- while (p.size() > 0) {
- if (p[0].get_type() == Variant::VECTOR2) {
- last_coord = p[0];
- } else if (p[0].get_type() == Variant::INT) {
- autotile_set_bitmask(id, last_coord, p[0]);
- }
- p.pop_front();
- }
- }
- } else if (what == "occluder_map") {
- tile_map[id].autotile_data.occluder_map.clear();
- Array p = p_value;
- Vector2 last_coord;
- while (p.size() > 0) {
- if (p[0].get_type() == Variant::VECTOR2) {
- last_coord = p[0];
- } else if (p[0].get_type() == Variant::OBJECT) {
- autotile_set_light_occluder(id, p[0], last_coord);
- }
- p.pop_front();
- }
- } else if (what == "navpoly_map") {
- tile_map[id].autotile_data.navpoly_map.clear();
- Array p = p_value;
- Vector2 last_coord;
- while (p.size() > 0) {
- if (p[0].get_type() == Variant::VECTOR2) {
- last_coord = p[0];
- } else if (p[0].get_type() == Variant::OBJECT) {
- autotile_set_navigation_polygon(id, p[0], last_coord);
- }
- p.pop_front();
- }
- } else if (what == "priority_map") {
- tile_map[id].autotile_data.priority_map.clear();
- Array p = p_value;
- Vector3 val;
- Vector2 v;
- int priority;
- while (p.size() > 0) {
- val = p[0];
- if (val.z > 1) {
- v.x = val.x;
- v.y = val.y;
- priority = (int)val.z;
- tile_map[id].autotile_data.priority_map[v] = priority;
- }
- p.pop_front();
- }
- } else if (what == "z_index_map") {
- tile_map[id].autotile_data.z_index_map.clear();
- Array p = p_value;
- Vector3 val;
- Vector2 v;
- int z_index;
- while (p.size() > 0) {
- val = p[0];
- if (val.z != 0) {
- v.x = val.x;
- v.y = val.y;
- z_index = (int)val.z;
- tile_map[id].autotile_data.z_index_map[v] = z_index;
- }
- p.pop_front();
- }
- }
- } else if (what == "shape") {
- if (tile_get_shape_count(id) > 0) {
- for (int i = 0; i < tile_get_shape_count(id); i++) {
- tile_set_shape(id, i, p_value);
- }
- } else {
- tile_set_shape(id, 0, p_value);
- }
- } else if (what == "shape_offset") {
- if (tile_get_shape_count(id) > 0) {
- for (int i = 0; i < tile_get_shape_count(id); i++) {
- tile_set_shape_offset(id, i, p_value);
- }
- } else {
- tile_set_shape_offset(id, 0, p_value);
- }
- } else if (what == "shape_transform") {
- if (tile_get_shape_count(id) > 0) {
- for (int i = 0; i < tile_get_shape_count(id); i++) {
- tile_set_shape_transform(id, i, p_value);
- }
- } else {
- tile_set_shape_transform(id, 0, p_value);
- }
- } else if (what == "shape_one_way") {
- if (tile_get_shape_count(id) > 0) {
- for (int i = 0; i < tile_get_shape_count(id); i++) {
- tile_set_shape_one_way(id, i, p_value);
- }
- } else {
- tile_set_shape_one_way(id, 0, p_value);
- }
- } else if (what == "shape_one_way_margin") {
- if (tile_get_shape_count(id) > 0) {
- for (int i = 0; i < tile_get_shape_count(id); i++) {
- tile_set_shape_one_way_margin(id, i, p_value);
- }
- } else {
- tile_set_shape_one_way_margin(id, 0, p_value);
- }
- } else if (what == "shapes") {
- _tile_set_shapes(id, p_value);
- } else if (what == "occluder") {
- tile_set_light_occluder(id, p_value);
- } else if (what == "occluder_offset") {
- tile_set_occluder_offset(id, p_value);
- } else if (what == "navigation") {
- tile_set_navigation_polygon(id, p_value);
- } else if (what == "navigation_offset") {
- tile_set_navigation_polygon_offset(id, p_value);
- } else if (what == "z_index") {
- tile_set_z_index(id, p_value);
- } else {
- return false;
- }
+/////////////////////////////// TileSet //////////////////////////////////////
- return true;
+// --- Plugins ---
+Vector<TileSetPlugin *> TileSet::get_tile_set_atlas_plugins() const {
+ return tile_set_plugins_vector;
}
-bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
- String n = p_name;
- int slash = n.find("/");
- if (slash == -1) {
- return false;
+// -- Shape and layout --
+void TileSet::set_tile_shape(TileSet::TileShape p_shape) {
+ tile_shape = p_shape;
+
+ for (Map<int, Ref<TileSetSource>>::Element *E_source = sources.front(); E_source; E_source = E_source->next()) {
+ E_source->get()->notify_tile_data_properties_should_change();
}
- int id = String::to_int(n.get_data(), slash);
-
- ERR_FAIL_COND_V(!tile_map.has(id), false);
-
- String what = n.substr(slash + 1, n.length());
-
- if (what == "name") {
- r_ret = tile_get_name(id);
- } else if (what == "texture") {
- r_ret = tile_get_texture(id);
- } else if (what == "tex_offset") {
- r_ret = tile_get_texture_offset(id);
- } else if (what == "material") {
- r_ret = tile_get_material(id);
- } else if (what == "modulate") {
- r_ret = tile_get_modulate(id);
- } else if (what == "region") {
- r_ret = tile_get_region(id);
- } else if (what == "tile_mode") {
- r_ret = tile_get_tile_mode(id);
- } else if (what.left(9) == "autotile/") {
- what = what.right(9);
- if (what == "bitmask_mode") {
- r_ret = autotile_get_bitmask_mode(id);
- } else if (what == "icon_coordinate") {
- r_ret = autotile_get_icon_coordinate(id);
- } else if (what == "tile_size") {
- r_ret = autotile_get_size(id);
- } else if (what == "spacing") {
- r_ret = autotile_get_spacing(id);
- } else if (what == "bitmask_flags") {
- Array p;
- for (Map<Vector2, uint32_t>::Element *E = tile_map[id].autotile_data.flags.front(); E; E = E->next()) {
- p.push_back(E->key());
- p.push_back(E->value());
- }
- 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()) {
- 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()) {
- p.push_back(E->key());
- p.push_back(E->value());
- }
- r_ret = p;
- } else if (what == "priority_map") {
- Array p;
- Vector3 v;
- for (Map<Vector2, int>::Element *E = tile_map[id].autotile_data.priority_map.front(); E; E = E->next()) {
- if (E->value() > 1) {
- //Don't save default value
- v.x = E->key().x;
- v.y = E->key().y;
- v.z = E->value();
- p.push_back(v);
- }
- }
- r_ret = p;
- } else if (what == "z_index_map") {
- Array p;
- Vector3 v;
- for (Map<Vector2, int>::Element *E = tile_map[id].autotile_data.z_index_map.front(); E; E = E->next()) {
- if (E->value() != 0) {
- //Don't save default value
- v.x = E->key().x;
- v.y = E->key().y;
- v.z = E->value();
- p.push_back(v);
- }
- }
- r_ret = p;
- }
- } else if (what == "shape") {
- r_ret = tile_get_shape(id, 0);
- } else if (what == "shape_offset") {
- r_ret = tile_get_shape_offset(id, 0);
- } else if (what == "shape_transform") {
- r_ret = tile_get_shape_transform(id, 0);
- } else if (what == "shape_one_way") {
- r_ret = tile_get_shape_one_way(id, 0);
- } else if (what == "shape_one_way_margin") {
- r_ret = tile_get_shape_one_way_margin(id, 0);
- } else if (what == "shapes") {
- r_ret = _tile_get_shapes(id);
- } else if (what == "occluder") {
- r_ret = tile_get_light_occluder(id);
- } else if (what == "occluder_offset") {
- r_ret = tile_get_occluder_offset(id);
- } else if (what == "navigation") {
- r_ret = tile_get_navigation_polygon(id);
- } else if (what == "navigation_offset") {
- r_ret = tile_get_navigation_polygon_offset(id);
- } else if (what == "z_index") {
- r_ret = tile_get_z_index(id);
- } else {
- return false;
+
+ emit_changed();
+}
+TileSet::TileShape TileSet::get_tile_shape() const {
+ return tile_shape;
+}
+
+void TileSet::set_tile_layout(TileSet::TileLayout p_layout) {
+ tile_layout = p_layout;
+ emit_changed();
+}
+TileSet::TileLayout TileSet::get_tile_layout() const {
+ return tile_layout;
+}
+
+void TileSet::set_tile_offset_axis(TileSet::TileOffsetAxis p_alignment) {
+ tile_offset_axis = p_alignment;
+
+ for (Map<int, Ref<TileSetSource>>::Element *E_source = sources.front(); E_source; E_source = E_source->next()) {
+ E_source->get()->notify_tile_data_properties_should_change();
}
- return true;
+ emit_changed();
+}
+TileSet::TileOffsetAxis TileSet::get_tile_offset_axis() const {
+ return tile_offset_axis;
}
-void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
- for (Map<int, TileData>::Element *E = tile_map.front(); E; E = E->next()) {
- int id = E->key();
- String pre = itos(id) + "/";
- p_list->push_back(PropertyInfo(Variant::STRING, pre + "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "tex_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::COLOR, pre + "modulate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::RECT2, pre + "region", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE,ATLAS_TILE", PROPERTY_USAGE_NOEDITOR));
- if (tile_get_tile_mode(id) == AUTO_TILE) {
- p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/bitmask_flags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/z_index_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- } else if (tile_get_tile_mode(id) == ATLAS_TILE) {
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/z_index_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
- }
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "occluder_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "navigation_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "navigation", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "shape_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "shape_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_NOEDITOR));
- 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(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1", PROPERTY_USAGE_NOEDITOR));
- }
-}
-
-void TileSet::create_tile(int p_id) {
- ERR_FAIL_COND(tile_map.has(p_id));
- tile_map[p_id] = TileData();
- tile_map[p_id].autotile_data = AutotileData();
- notify_property_list_changed();
+void TileSet::set_tile_size(Size2i p_size) {
+ ERR_FAIL_COND(p_size.x < 1 || p_size.y < 1);
+ tile_size = p_size;
emit_changed();
}
+Size2i TileSet::get_tile_size() const {
+ return tile_size;
+}
-void TileSet::autotile_set_bitmask_mode(int p_id, BitmaskMode p_mode) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].autotile_data.bitmask_mode = p_mode;
- notify_property_list_changed();
+void TileSet::set_tile_skew(Vector2 p_skew) {
emit_changed();
+ tile_skew = p_skew;
+}
+Vector2 TileSet::get_tile_skew() const {
+ return tile_skew;
+}
+
+int TileSet::get_next_source_id() const {
+ return next_source_id;
}
-TileSet::BitmaskMode TileSet::autotile_get_bitmask_mode(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), BITMASK_2X2);
- return tile_map[p_id].autotile_data.bitmask_mode;
+void TileSet::_compute_next_source_id() {
+ while (sources.has(next_source_id)) {
+ next_source_id = (next_source_id + 1) % 1073741824; // 2 ** 30
+ };
}
-void TileSet::tile_set_texture(int p_id, const Ref<Texture2D> &p_texture) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].texture = p_texture;
+// Sources management
+int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source_id_override) {
+ ERR_FAIL_COND_V(!p_tile_set_source.is_valid(), -1);
+ ERR_FAIL_COND_V_MSG(p_atlas_source_id_override >= 0 && (sources.has(p_atlas_source_id_override)), -1, vformat("Cannot create TileSet atlas source. Another atlas source exists with id %d.", p_atlas_source_id_override));
+
+ int new_source_id = p_atlas_source_id_override >= 0 ? p_atlas_source_id_override : next_source_id;
+ sources[new_source_id] = p_tile_set_source;
+ source_ids.append(new_source_id);
+ source_ids.sort();
+ p_tile_set_source->set_tile_set(this);
+ _compute_next_source_id();
+
+ sources[new_source_id]->connect("changed", callable_mp(this, &TileSet::_source_changed));
+
emit_changed();
+
+ return new_source_id;
}
-Ref<Texture2D> TileSet::tile_get_texture(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<Texture2D>());
- return tile_map[p_id].texture;
+void TileSet::remove_source(int p_source_id) {
+ ERR_FAIL_COND_MSG(!sources.has(p_source_id), vformat("Cannot remove TileSet atlas source. No tileset atlas source with id %d.", p_source_id));
+
+ sources[p_source_id]->disconnect("changed", callable_mp(this, &TileSet::_source_changed));
+
+ sources[p_source_id]->set_tile_set(nullptr);
+ sources.erase(p_source_id);
+ source_ids.erase(p_source_id);
+ source_ids.sort();
+
+ emit_changed();
}
-void TileSet::tile_set_material(int p_id, const Ref<ShaderMaterial> &p_material) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].material = p_material;
+void TileSet::set_source_id(int p_source_id, int p_new_source_id) {
+ ERR_FAIL_COND(p_new_source_id < 0);
+ ERR_FAIL_COND_MSG(!sources.has(p_source_id), vformat("Cannot change TileSet atlas source ID. No tileset atlas source with id %d.", p_source_id));
+ if (p_source_id == p_new_source_id) {
+ return;
+ }
+
+ ERR_FAIL_COND_MSG(sources.has(p_new_source_id), vformat("Cannot change TileSet atlas source ID. Another atlas source exists with id %d.", p_new_source_id));
+
+ sources[p_new_source_id] = sources[p_source_id];
+ sources.erase(p_source_id);
+
+ source_ids.erase(p_source_id);
+ source_ids.append(p_new_source_id);
+ source_ids.sort();
+
emit_changed();
}
-Ref<ShaderMaterial> TileSet::tile_get_material(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<ShaderMaterial>());
- return tile_map[p_id].material;
+bool TileSet::has_source(int p_source_id) const {
+ return sources.has(p_source_id);
}
-void TileSet::tile_set_modulate(int p_id, const Color &p_modulate) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].modulate = p_modulate;
+Ref<TileSetSource> TileSet::get_source(int p_source_id) const {
+ ERR_FAIL_COND_V_MSG(!sources.has(p_source_id), nullptr, vformat("No TileSet atlas source with id %d.", p_source_id));
+
+ return sources[p_source_id];
+}
+
+int TileSet::get_source_count() const {
+ return source_ids.size();
+}
+
+int TileSet::get_source_id(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, source_ids.size(), -1);
+ return source_ids[p_index];
+}
+
+// Rendering
+void TileSet::set_uv_clipping(bool p_uv_clipping) {
+ if (uv_clipping == p_uv_clipping) {
+ return;
+ }
+ uv_clipping = p_uv_clipping;
emit_changed();
}
+bool TileSet::is_uv_clipping() const {
+ return uv_clipping;
+};
-Color TileSet::tile_get_modulate(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Color(1, 1, 1));
- return tile_map[p_id].modulate;
+void TileSet::set_y_sorting(bool p_y_sort) {
+ if (y_sorting == p_y_sort) {
+ return;
+ }
+ y_sorting = p_y_sort;
+ emit_changed();
}
+bool TileSet::is_y_sorting() const {
+ return y_sorting;
+};
-void TileSet::tile_set_texture_offset(int p_id, const Vector2 &p_offset) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].offset = p_offset;
+void TileSet::set_occlusion_layers_count(int p_occlusion_layers_count) {
+ ERR_FAIL_COND(p_occlusion_layers_count < 0);
+ if (occlusion_layers.size() == p_occlusion_layers_count) {
+ return;
+ }
+
+ occlusion_layers.resize(p_occlusion_layers_count);
+
+ for (Map<int, Ref<TileSetSource>>::Element *E_source = sources.front(); E_source; E_source = E_source->next()) {
+ E_source->get()->notify_tile_data_properties_should_change();
+ }
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
+int TileSet::get_occlusion_layers_count() const {
+ return occlusion_layers.size();
+};
+
+void TileSet::set_occlusion_layer_light_mask(int p_layer_index, int p_light_mask) {
+ ERR_FAIL_INDEX(p_layer_index, occlusion_layers.size());
+ occlusion_layers.write[p_layer_index].light_mask = p_light_mask;
emit_changed();
}
-Vector2 TileSet::tile_get_texture_offset(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2());
- return tile_map[p_id].offset;
+int TileSet::get_occlusion_layer_light_mask(int p_layer_index) const {
+ ERR_FAIL_INDEX_V(p_layer_index, occlusion_layers.size(), 0);
+ return occlusion_layers[p_layer_index].light_mask;
}
-void TileSet::tile_set_region(int p_id, const Rect2 &p_region) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].region = p_region;
+void TileSet::set_occlusion_layer_sdf_collision(int p_layer_index, int p_sdf_collision) {
+ ERR_FAIL_INDEX(p_layer_index, occlusion_layers.size());
+ occlusion_layers.write[p_layer_index].sdf_collision = p_sdf_collision;
emit_changed();
}
-Rect2 TileSet::tile_get_region(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Rect2());
- return tile_map[p_id].region;
+bool TileSet::get_occlusion_layer_sdf_collision(int p_layer_index) const {
+ ERR_FAIL_INDEX_V(p_layer_index, occlusion_layers.size(), false);
+ return occlusion_layers[p_layer_index].sdf_collision;
+}
+
+void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled, Ref<Texture2D> p_texture) {
+ // TODO: optimize this with 2D meshes when they work again.
+ if (get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) {
+ if (p_filled && p_texture.is_valid()) {
+ p_canvas_item->draw_texture_rect(p_texture, p_region, false, p_color);
+ } else {
+ p_canvas_item->draw_rect(p_region, p_color, p_filled);
+ }
+ } else {
+ float overlap = 0.0;
+ switch (get_tile_shape()) {
+ case TileSet::TILE_SHAPE_ISOMETRIC:
+ overlap = 0.5;
+ break;
+ case TileSet::TILE_SHAPE_HEXAGON:
+ overlap = 0.25;
+ break;
+ case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
+ overlap = 0.0;
+ break;
+ default:
+ break;
+ }
+
+ Vector<Vector2> uvs;
+ uvs.append(Vector2(0.5, 0.0));
+ uvs.append(Vector2(0.0, overlap));
+ uvs.append(Vector2(0.0, 1.0 - overlap));
+ uvs.append(Vector2(0.5, 1.0));
+ uvs.append(Vector2(1.0, 1.0 - overlap));
+ uvs.append(Vector2(1.0, overlap));
+ uvs.append(Vector2(0.5, 0.0));
+ if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
+ for (int i = 0; i < uvs.size(); i++) {
+ uvs.write[i] = Vector2(uvs[i].y, uvs[i].x);
+ }
+ }
+
+ Vector<Vector2> points;
+ for (int i = 0; i < uvs.size(); i++) {
+ points.append(p_region.position + uvs[i] * p_region.size);
+ }
+
+ if (p_filled) {
+ // This does hurt performances a lot. We should use a mesh if possible instead.
+ p_canvas_item->draw_colored_polygon(points, p_color, uvs, p_texture);
+
+ // Should improve performances, but does not work as draw_primitive does not work with textures :/ :
+ /*for (int i = 0; i < 6; i += 3) {
+ Vector<Vector2> quad;
+ quad.append(points[i]);
+ quad.append(points[(i + 1) % points.size()]);
+ quad.append(points[(i + 2) % points.size()]);
+ quad.append(points[(i + 3) % points.size()]);
+
+ Vector<Vector2> uv_quad;
+ uv_quad.append(uvs[i]);
+ uv_quad.append(uvs[(i + 1) % uvs.size()]);
+ uv_quad.append(uvs[(i + 2) % uvs.size()]);
+ uv_quad.append(uvs[(i + 3) % uvs.size()]);
+
+ p_control->draw_primitive(quad, Vector<Color>(), uv_quad, p_texture);
+ }*/
+
+ } else {
+ // This does hurt performances a lot. We should use a mesh if possible instead.
+ // tile_shape_grid->draw_polyline(points, p_color);
+ for (int i = 0; i < points.size() - 1; i++) {
+ p_canvas_item->draw_line(points[i], points[i + 1], p_color);
+ }
+ }
+ }
}
-void TileSet::tile_set_tile_mode(int p_id, TileMode p_tile_mode) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].tile_mode = p_tile_mode;
+// Physics
+void TileSet::set_physics_layers_count(int p_physics_layers_count) {
+ ERR_FAIL_COND(p_physics_layers_count < 0);
+ if (physics_layers.size() == p_physics_layers_count) {
+ return;
+ }
+
+ physics_layers.resize(p_physics_layers_count);
+
+ for (Map<int, Ref<TileSetSource>>::Element *E_source = sources.front(); E_source; E_source = E_source->next()) {
+ E_source->get()->notify_tile_data_properties_should_change();
+ }
+
+ notify_property_list_changed();
emit_changed();
}
-TileSet::TileMode TileSet::tile_get_tile_mode(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), SINGLE_TILE);
- return tile_map[p_id].tile_mode;
+int TileSet::get_physics_layers_count() const {
+ return physics_layers.size();
}
-void TileSet::autotile_set_icon_coordinate(int p_id, Vector2 coord) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].autotile_data.icon_coord = coord;
+void TileSet::set_physics_layer_collision_layer(int p_layer_index, uint32_t p_layer) {
+ ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
+ physics_layers.write[p_layer_index].collision_layer = p_layer;
emit_changed();
}
-Vector2 TileSet::autotile_get_icon_coordinate(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2());
- return tile_map[p_id].autotile_data.icon_coord;
+uint32_t TileSet::get_physics_layer_collision_layer(int p_layer_index) const {
+ ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), 0);
+ return physics_layers[p_layer_index].collision_layer;
}
-void TileSet::autotile_set_spacing(int p_id, int p_spacing) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- ERR_FAIL_COND(p_spacing < 0);
- tile_map[p_id].autotile_data.spacing = p_spacing;
+void TileSet::set_physics_layer_collision_mask(int p_layer_index, uint32_t p_mask) {
+ ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
+ physics_layers.write[p_layer_index].collision_mask = p_mask;
emit_changed();
}
-int TileSet::autotile_get_spacing(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), 0);
- return tile_map[p_id].autotile_data.spacing;
+uint32_t TileSet::get_physics_layer_collision_mask(int p_layer_index) const {
+ ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), 0);
+ return physics_layers[p_layer_index].collision_mask;
}
-void TileSet::autotile_set_size(int p_id, Size2 p_size) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- ERR_FAIL_COND(p_size.x <= 0 || p_size.y <= 0);
- tile_map[p_id].autotile_data.size = p_size;
+void TileSet::set_physics_layer_physics_material(int p_layer_index, Ref<PhysicsMaterial> p_physics_material) {
+ ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
+ physics_layers.write[p_layer_index].physics_material = p_physics_material;
}
-Size2 TileSet::autotile_get_size(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Size2());
- return tile_map[p_id].autotile_data.size;
+Ref<PhysicsMaterial> TileSet::get_physics_layer_physics_material(int p_layer_index) const {
+ ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), Ref<PhysicsMaterial>());
+ return physics_layers[p_layer_index].physics_material;
}
-void TileSet::autotile_clear_bitmask_map(int p_id) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].autotile_data.flags.clear();
+// Terrains
+void TileSet::set_terrain_sets_count(int p_terrains_sets_count) {
+ ERR_FAIL_COND(p_terrains_sets_count < 0);
+
+ terrain_sets.resize(p_terrains_sets_count);
+
+ notify_property_list_changed();
+ emit_changed();
}
-void TileSet::autotile_set_subtile_priority(int p_id, const Vector2 &p_coord, int p_priority) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- ERR_FAIL_COND(p_priority <= 0);
- tile_map[p_id].autotile_data.priority_map[p_coord] = p_priority;
+int TileSet::get_terrain_sets_count() const {
+ return terrain_sets.size();
}
-int TileSet::autotile_get_subtile_priority(int p_id, const Vector2 &p_coord) {
- ERR_FAIL_COND_V(!tile_map.has(p_id), 1);
- if (tile_map[p_id].autotile_data.priority_map.has(p_coord)) {
- return tile_map[p_id].autotile_data.priority_map[p_coord];
+void TileSet::set_terrain_set_mode(int p_terrain_set, TerrainMode p_terrain_mode) {
+ ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
+ terrain_sets.write[p_terrain_set].mode = p_terrain_mode;
+ for (Map<int, Ref<TileSetSource>>::Element *E_source = sources.front(); E_source; E_source = E_source->next()) {
+ E_source->get()->notify_tile_data_properties_should_change();
}
- //When not custom priority set return the default value
- return 1;
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
+TileSet::TerrainMode TileSet::get_terrain_set_mode(int p_terrain_set) const {
+ ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES);
+ return terrain_sets[p_terrain_set].mode;
+}
+
+void TileSet::set_terrains_count(int p_terrain_set, int p_terrains_layers_count) {
+ ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
+ ERR_FAIL_COND(p_terrains_layers_count < 0);
+ if (terrain_sets[p_terrain_set].terrains.size() == p_terrains_layers_count) {
+ return;
+ }
+
+ int old_size = terrain_sets[p_terrain_set].terrains.size();
+ terrain_sets.write[p_terrain_set].terrains.resize(p_terrains_layers_count);
+
+ // Default name and color
+ for (int i = old_size; i < terrain_sets.write[p_terrain_set].terrains.size(); i++) {
+ float hue_rotate = (i * 2 % 16) / 16.0;
+ Color c;
+ c.set_hsv(Math::fmod(float(hue_rotate), float(1.0)), 0.5, 0.5);
+ terrain_sets.write[p_terrain_set].terrains.write[i].color = c;
+ terrain_sets.write[p_terrain_set].terrains.write[i].name = String(vformat("Terrain %d", i));
+ }
+
+ for (Map<int, Ref<TileSetSource>>::Element *E_source = sources.front(); E_source; E_source = E_source->next()) {
+ E_source->get()->notify_tile_data_properties_should_change();
+ }
+
+ notify_property_list_changed();
+ emit_changed();
}
-const Map<Vector2, int> &TileSet::autotile_get_priority_map(int p_id) const {
- static Map<Vector2, int> dummy;
- ERR_FAIL_COND_V(!tile_map.has(p_id), dummy);
- return tile_map[p_id].autotile_data.priority_map;
+int TileSet::get_terrains_count(int p_terrain_set) const {
+ ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), -1);
+ return terrain_sets[p_terrain_set].terrains.size();
}
-void TileSet::autotile_set_z_index(int p_id, const Vector2 &p_coord, int p_z_index) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].autotile_data.z_index_map[p_coord] = p_z_index;
+void TileSet::set_terrain_name(int p_terrain_set, int p_terrain_index, String p_name) {
+ ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
+ ERR_FAIL_INDEX(p_terrain_index, terrain_sets[p_terrain_set].terrains.size());
+ terrain_sets.write[p_terrain_set].terrains.write[p_terrain_index].name = p_name;
emit_changed();
}
-int TileSet::autotile_get_z_index(int p_id, const Vector2 &p_coord) {
- ERR_FAIL_COND_V(!tile_map.has(p_id), 1);
- if (tile_map[p_id].autotile_data.z_index_map.has(p_coord)) {
- return tile_map[p_id].autotile_data.z_index_map[p_coord];
+String TileSet::get_terrain_name(int p_terrain_set, int p_terrain_index) const {
+ ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), String());
+ ERR_FAIL_INDEX_V(p_terrain_index, terrain_sets[p_terrain_set].terrains.size(), String());
+ return terrain_sets[p_terrain_set].terrains[p_terrain_index].name;
+}
+
+void TileSet::set_terrain_color(int p_terrain_set, int p_terrain_index, Color p_color) {
+ ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
+ ERR_FAIL_INDEX(p_terrain_index, terrain_sets[p_terrain_set].terrains.size());
+ if (p_color.a != 1.0) {
+ WARN_PRINT("Terrain color should have alpha == 1.0");
+ p_color.a = 1.0;
}
- //When not custom z index set return the default value
- return 0;
+ terrain_sets.write[p_terrain_set].terrains.write[p_terrain_index].color = p_color;
+ emit_changed();
}
-const Map<Vector2, int> &TileSet::autotile_get_z_index_map(int p_id) const {
- static Map<Vector2, int> dummy;
- ERR_FAIL_COND_V(!tile_map.has(p_id), dummy);
- return tile_map[p_id].autotile_data.z_index_map;
+Color TileSet::get_terrain_color(int p_terrain_set, int p_terrain_index) const {
+ ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), Color());
+ ERR_FAIL_INDEX_V(p_terrain_index, terrain_sets[p_terrain_set].terrains.size(), Color());
+ return terrain_sets[p_terrain_set].terrains[p_terrain_index].color;
}
-void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint32_t p_flag) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- if (p_flag == 0) {
- if (tile_map[p_id].autotile_data.flags.has(p_coord)) {
- tile_map[p_id].autotile_data.flags.erase(p_coord);
+bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
+ if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) {
+ return false;
+ }
+
+ TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
+ if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
+ if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_SIDE) {
+ return true;
+ }
+ }
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
+ if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) {
+ return true;
+ }
+ }
+ } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
+ if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return true;
+ }
+ }
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
+ if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
+ return true;
+ }
}
} else {
- tile_map[p_id].autotile_data.flags[p_coord] = p_flag;
+ if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
+ if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return true;
+ }
+ }
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
+ if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) {
+ return true;
+ }
+ }
+ } else {
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
+ if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
+ return true;
+ }
+ }
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
+ if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
+ p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+// Navigation
+void TileSet::set_navigation_layers_count(int p_navigation_layers_count) {
+ ERR_FAIL_COND(p_navigation_layers_count < 0);
+ if (navigation_layers.size() == p_navigation_layers_count) {
+ return;
}
+
+ navigation_layers.resize(p_navigation_layers_count);
+
+ for (Map<int, Ref<TileSetSource>>::Element *E_source = sources.front(); E_source; E_source = E_source->next()) {
+ E_source->get()->notify_tile_data_properties_should_change();
+ }
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
+int TileSet::get_navigation_layers_count() const {
+ return navigation_layers.size();
+}
+
+void TileSet::set_navigation_layer_layers(int p_layer_index, uint32_t p_layers) {
+ ERR_FAIL_INDEX(p_layer_index, navigation_layers.size());
+ navigation_layers.write[p_layer_index].layers = p_layers;
+ emit_changed();
+}
+
+uint32_t TileSet::get_navigation_layer_layers(int p_layer_index) const {
+ ERR_FAIL_INDEX_V(p_layer_index, navigation_layers.size(), 0);
+ return navigation_layers[p_layer_index].layers;
+}
+
+// Custom data.
+void TileSet::set_custom_data_layers_count(int p_custom_data_layers_count) {
+ ERR_FAIL_COND(p_custom_data_layers_count < 0);
+ if (custom_data_layers.size() == p_custom_data_layers_count) {
+ return;
+ }
+
+ custom_data_layers.resize(p_custom_data_layers_count);
+
+ for (Map<String, int>::Element *E = custom_data_layers_by_name.front(); E; E = E->next()) {
+ if (E->get() >= custom_data_layers.size()) {
+ custom_data_layers_by_name.erase(E);
+ }
+ }
+
+ for (Map<int, Ref<TileSetSource>>::Element *E_source = sources.front(); E_source; E_source = E_source->next()) {
+ E_source->get()->notify_tile_data_properties_should_change();
+ }
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
+int TileSet::get_custom_data_layers_count() const {
+ return custom_data_layers.size();
}
-uint32_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) {
- ERR_FAIL_COND_V(!tile_map.has(p_id), 0);
- if (!tile_map[p_id].autotile_data.flags.has(p_coord)) {
- return 0;
+int TileSet::get_custom_data_layer_by_name(String p_value) const {
+ if (custom_data_layers_by_name.has(p_value)) {
+ return custom_data_layers_by_name[p_value];
+ } else {
+ return -1;
}
- return tile_map[p_id].autotile_data.flags[p_coord];
}
-const Map<Vector2, uint32_t> &TileSet::autotile_get_bitmask_map(int p_id) {
- static Map<Vector2, uint32_t> dummy;
- static Map<Vector2, uint32_t> dummy_atlas;
- ERR_FAIL_COND_V(!tile_map.has(p_id), dummy);
- if (tile_get_tile_mode(p_id) == ATLAS_TILE) {
- dummy_atlas = Map<Vector2, uint32_t>();
- Rect2 region = tile_get_region(p_id);
- Size2 size = autotile_get_size(p_id);
- float spacing = autotile_get_spacing(p_id);
- for (int x = 0; x < (region.size.x / (size.x + spacing)); x++) {
- for (int y = 0; y < (region.size.y / (size.y + spacing)); y++) {
- dummy_atlas.insert(Vector2(x, y), 0);
+void TileSet::set_custom_data_name(int p_layer_id, String p_value) {
+ ERR_FAIL_INDEX(p_layer_id, custom_data_layers.size());
+
+ // Exit if another property has the same name.
+ if (!p_value.is_empty()) {
+ for (int other_layer_id = 0; other_layer_id < get_custom_data_layers_count(); other_layer_id++) {
+ if (other_layer_id != p_layer_id && get_custom_data_name(other_layer_id) == p_value) {
+ ERR_FAIL_MSG(vformat("There is already a custom property named %s", p_value));
}
}
- return dummy_atlas;
+ }
+
+ if (p_value.is_empty() && custom_data_layers_by_name.has(p_value)) {
+ custom_data_layers_by_name.erase(p_value);
} else {
- return tile_map[p_id].autotile_data.flags;
+ custom_data_layers_by_name[p_value] = p_layer_id;
+ }
+
+ custom_data_layers.write[p_layer_id].name = p_value;
+ emit_changed();
+}
+
+String TileSet::get_custom_data_name(int p_layer_id) const {
+ ERR_FAIL_INDEX_V(p_layer_id, custom_data_layers.size(), "");
+ return custom_data_layers[p_layer_id].name;
+}
+
+void TileSet::set_custom_data_type(int p_layer_id, Variant::Type p_value) {
+ ERR_FAIL_INDEX(p_layer_id, custom_data_layers.size());
+ custom_data_layers.write[p_layer_id].type = p_value;
+
+ for (Map<int, Ref<TileSetSource>>::Element *E_source = sources.front(); E_source; E_source = E_source->next()) {
+ E_source->get()->notify_tile_data_properties_should_change();
}
+
+ emit_changed();
}
-Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node, const Vector2 &p_tile_location) {
- 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() != 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) {
- return ret;
+Variant::Type TileSet::get_custom_data_type(int p_layer_id) const {
+ ERR_FAIL_INDEX_V(p_layer_id, custom_data_layers.size(), Variant::NIL);
+ return custom_data_layers[p_layer_id].type;
+}
+
+void TileSet::_source_changed() {
+ emit_changed();
+ notify_property_list_changed();
+}
+
+void TileSet::reset_state() {
+ occlusion_layers.clear();
+ physics_layers.clear();
+ custom_data_layers.clear();
+}
+
+const Vector2i TileSetSource::INVALID_ATLAS_COORDS = Vector2i(-1, -1);
+const int TileSetSource::INVALID_TILE_ALTERNATIVE = -1;
+
+#ifndef DISABLE_DEPRECATED
+void TileSet::compatibility_conversion() {
+ for (Map<int, CompatibilityTileData *>::Element *E = compatibility_data.front(); E; E = E->next()) {
+ CompatibilityTileData *ctd = E->value();
+
+ // Add the texture
+ TileSetAtlasSource *atlas_source = memnew(TileSetAtlasSource);
+ int source_id = add_source(Ref<TileSetSource>(atlas_source));
+
+ atlas_source->set_texture(ctd->texture);
+
+ // Handle each tile as a new source. Not optimal but at least it should stay compatible.
+ switch (ctd->tile_mode) {
+ case 0: // SINGLE_TILE
+ // TODO
+ break;
+ case 1: // AUTO_TILE
+ // TODO
+ break;
+ case 2: // ATLAS_TILE
+ atlas_source->set_margins(ctd->region.get_position());
+ atlas_source->set_separation(Vector2i(ctd->autotile_spacing, ctd->autotile_spacing));
+ atlas_source->set_texture_region_size(ctd->autotile_tile_size);
+
+ Size2i atlas_size = ctd->region.get_size() / (ctd->autotile_tile_size + atlas_source->get_separation());
+ for (int i = 0; i < atlas_size.x; i++) {
+ for (int j = 0; j < atlas_size.y; j++) {
+ Vector2i coords = Vector2i(i, j);
+
+ for (int flags = 0; flags < 8; flags++) {
+ bool flip_h = flags & 1;
+ bool flip_v = flags & 2;
+ bool transpose = flags & 4;
+
+ int alternative_tile = 0;
+ if (!atlas_source->has_tile(coords)) {
+ atlas_source->create_tile(coords);
+ } else {
+ alternative_tile = atlas_source->create_alternative_tile(coords);
+ }
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(coords, alternative_tile));
+
+ tile_data->set_flip_h(flip_h);
+ tile_data->set_flip_v(flip_v);
+ tile_data->set_transpose(transpose);
+ tile_data->tile_set_material(ctd->material);
+ tile_data->set_modulate(ctd->modulate);
+ tile_data->set_z_index(ctd->z_index);
+ if (ctd->autotile_occluder_map.has(coords)) {
+ if (get_occlusion_layers_count() < 1) {
+ set_occlusion_layers_count(1);
+ }
+ tile_data->set_occluder(0, ctd->autotile_occluder_map[coords]);
+ }
+ if (ctd->autotile_navpoly_map.has(coords)) {
+ if (get_navigation_layers_count() < 1) {
+ set_navigation_layers_count(1);
+ }
+ tile_data->set_navigation_polygon(0, ctd->autotile_navpoly_map[coords]);
+ }
+ if (ctd->autotile_priority_map.has(coords)) {
+ tile_data->set_probability(ctd->autotile_priority_map[coords]);
+ }
+ if (ctd->autotile_z_index_map.has(coords)) {
+ tile_data->set_z_index(ctd->autotile_z_index_map[coords]);
+ }
+
+ // Add the shapes.
+ if (ctd->shapes.size() > 0) {
+ if (get_physics_layers_count() < 1) {
+ set_physics_layers_count(1);
+ }
+ }
+ for (int k = 0; k < ctd->shapes.size(); k++) {
+ CompatibilityShapeData csd = ctd->shapes[k];
+ if (csd.autotile_coords == coords) {
+ tile_data->set_collision_shapes_count(0, tile_data->get_collision_shapes_count(0) + 1);
+ int index = tile_data->get_collision_shapes_count(0) - 1;
+ tile_data->set_collision_shape_one_way(0, index, csd.one_way);
+ tile_data->set_collision_shape_one_way_margin(0, index, csd.one_way_margin);
+ tile_data->set_collision_shape_shape(0, index, csd.shape);
+ // Ignores transform for now.
+ }
+ }
+
+ // -- TODO: handle --
+ // Those are offset for the whole atlas, they are likely useless for the atlases, but might make sense for single tiles.
+ // texture offset
+ // occluder_offset
+ // navigation_offset
+
+ // For terrains, ignored for now?
+ // bitmask_mode
+ // bitmask_flags
+ }
+ }
+ }
+ break;
+ }
+
+ // Offset all shapes
+ for (int k = 0; k < ctd->shapes.size(); k++) {
+ Ref<ConvexPolygonShape2D> convex = ctd->shapes[k].shape;
+ if (convex.is_valid()) {
+ Vector<Vector2> points = convex->get_points();
+ for (int i_point = 0; i_point < points.size(); i_point++) {
+ points.write[i_point] = points[i_point] - get_tile_size() / 2;
}
+ convex->set_points(points);
}
}
+
+ // Add the mapping to the map
+ compatibility_source_mapping.insert(E->key(), source_id);
+ }
+
+ // Reset compatibility data
+ for (Map<int, CompatibilityTileData *>::Element *E = compatibility_data.front(); E; E = E->next()) {
+ memdelete(E->get());
}
+ compatibility_data = Map<int, CompatibilityTileData *>();
+}
+#endif // DISABLE_DEPRECATED
+
+bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+
+#ifndef DISABLE_DEPRECATED
+ // TODO: THIS IS HOW WE CHECK IF WE HAVE A DEPRECATED RESOURCE
+ // This should be moved to a dedicated conversion system
+ if (components.size() >= 1 && components[0].is_valid_integer()) {
+ int id = components[0].to_int();
+
+ // Get or create the compatibility object
+ CompatibilityTileData *ctd;
+ Map<int, CompatibilityTileData *>::Element *E = compatibility_data.find(id);
+ if (!E) {
+ ctd = memnew(CompatibilityTileData);
+ compatibility_data.insert(id, ctd);
+ } else {
+ ctd = E->get();
+ }
- List<Vector2> coords;
- List<uint32_t> priorities;
- uint32_t priority_sum = 0;
- uint32_t mask;
- uint16_t mask_;
- uint16_t mask_ignore;
- for (Map<Vector2, uint32_t>::Element *E = tile_map[p_id].autotile_data.flags.front(); E; E = E->next()) {
- mask = E->get();
- if (tile_map[p_id].autotile_data.bitmask_mode == BITMASK_2X2) {
- mask |= (BIND_IGNORE_TOP | BIND_IGNORE_LEFT | BIND_IGNORE_CENTER | BIND_IGNORE_RIGHT | BIND_IGNORE_BOTTOM);
+ if (components.size() < 2) {
+ return false;
}
- mask_ = mask & 0xFFFF;
- mask_ignore = mask >> 16;
+ String what = components[1];
+
+ if (what == "name") {
+ ctd->name = p_value;
+ } else if (what == "texture") {
+ ctd->texture = p_value;
+ } else if (what == "tex_offset") {
+ ctd->tex_offset = p_value;
+ } else if (what == "material") {
+ ctd->material = p_value;
+ } else if (what == "modulate") {
+ ctd->modulate = p_value;
+ } else if (what == "region") {
+ ctd->region = p_value;
+ } else if (what == "tile_mode") {
+ ctd->tile_mode = p_value;
+ } else if (what.left(9) == "autotile") {
+ what = what.substr(9);
+ if (what == "bitmask_mode") {
+ ctd->autotile_bitmask_mode = p_value;
+ } else if (what == "icon_coordinate") {
+ ctd->autotile_icon_coordinate = p_value;
+ } else if (what == "tile_size") {
+ ctd->autotile_tile_size = p_value;
+ } else if (what == "spacing") {
+ ctd->autotile_spacing = p_value;
+ } else if (what == "bitmask_flags") {
+ if (p_value.is_array()) {
+ Array p = p_value;
+ Vector2i last_coord;
+ while (p.size() > 0) {
+ if (p[0].get_type() == Variant::VECTOR2) {
+ last_coord = p[0];
+ } else if (p[0].get_type() == Variant::INT) {
+ ctd->autotile_bitmask_flags.insert(last_coord, p[0]);
+ }
+ p.pop_front();
+ }
+ }
+ } else if (what == "occluder_map") {
+ Array p = p_value;
+ Vector2 last_coord;
+ while (p.size() > 0) {
+ if (p[0].get_type() == Variant::VECTOR2) {
+ last_coord = p[0];
+ } else if (p[0].get_type() == Variant::OBJECT) {
+ ctd->autotile_occluder_map.insert(last_coord, p[0]);
+ }
+ p.pop_front();
+ }
+ } else if (what == "navpoly_map") {
+ Array p = p_value;
+ Vector2 last_coord;
+ while (p.size() > 0) {
+ if (p[0].get_type() == Variant::VECTOR2) {
+ last_coord = p[0];
+ } else if (p[0].get_type() == Variant::OBJECT) {
+ ctd->autotile_navpoly_map.insert(last_coord, p[0]);
+ }
+ p.pop_front();
+ }
+ } else if (what == "priority_map") {
+ Array p = p_value;
+ Vector3 val;
+ Vector2 v;
+ int priority;
+ while (p.size() > 0) {
+ val = p[0];
+ if (val.z > 1) {
+ v.x = val.x;
+ v.y = val.y;
+ priority = (int)val.z;
+ ctd->autotile_priority_map.insert(v, priority);
+ }
+ p.pop_front();
+ }
+ } else if (what == "z_index_map") {
+ Array p = p_value;
+ Vector3 val;
+ Vector2 v;
+ int z_index;
+ while (p.size() > 0) {
+ val = p[0];
+ if (val.z != 0) {
+ v.x = val.x;
+ v.y = val.y;
+ z_index = (int)val.z;
+ ctd->autotile_z_index_map.insert(v, z_index);
+ }
+ p.pop_front();
+ }
+ }
+
+ } else if (what == "shapes") {
+ Array p = p_value;
+ for (int i = 0; i < p.size(); i++) {
+ CompatibilityShapeData csd;
+ Dictionary d = p[i];
+ for (int j = 0; j < d.size(); j++) {
+ String key = d.get_key_at_index(j);
+ if (key == "autotile_coord") {
+ csd.autotile_coords = d[key];
+ } else if (key == "one_way") {
+ csd.one_way = d[key];
+ } else if (key == "one_way_margin") {
+ csd.one_way_margin = d[key];
+ } else if (key == "shape") {
+ csd.shape = d[key];
+ } else if (key == "shape_transform") {
+ csd.transform = d[key];
+ }
+ }
+ ctd->shapes.push_back(csd);
+ }
- if (((mask_ & (~mask_ignore)) == (p_bitmask & (~mask_ignore))) && (((~mask_) | mask_ignore) == ((~p_bitmask) | mask_ignore))) {
- uint32_t priority = autotile_get_subtile_priority(p_id, E->key());
- priority_sum += priority;
- priorities.push_back(priority);
- coords.push_back(E->key());
+ /*
+ // IGNORED FOR NOW, they seem duplicated data compared to the shapes array
+ } else if (what == "shape") {
+ // TODO
+ } else if (what == "shape_offset") {
+ // TODO
+ } else if (what == "shape_transform") {
+ // TODO
+ } else if (what == "shape_one_way") {
+ // TODO
+ } else if (what == "shape_one_way_margin") {
+ // TODO
}
- }
+ // IGNORED FOR NOW, maybe useless ?
+ else if (what == "occluder_offset") {
+ // Not
+ } else if (what == "navigation_offset") {
+ // TODO
+ }
+ */
+
+ } else if (what == "z_index") {
+ ctd->z_index = p_value;
- if (coords.size() == 0) {
- return autotile_get_icon_coordinate(p_id);
+ // TODO: remove the conversion from here, it's not where it should be done
+ compatibility_conversion();
+ } else {
+ return false;
+ }
} else {
- uint32_t picked_value = Math::rand() % priority_sum;
- uint32_t upper_bound;
- uint32_t lower_bound = 0;
- Vector2 result = coords.front()->get();
- List<Vector2>::Element *coords_E = coords.front();
- List<uint32_t>::Element *priorities_E = priorities.front();
- while (priorities_E) {
- upper_bound = lower_bound + priorities_E->get();
- if (lower_bound <= picked_value && picked_value < upper_bound) {
- result = coords_E->get();
- break;
+#endif // DISABLE_DEPRECATED
+
+ // This is now a new property.
+ if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) {
+ // Occlusion layers.
+ int index = components[0].trim_prefix("occlusion_layer_").to_int();
+ ERR_FAIL_COND_V(index < 0, false);
+ if (components[1] == "light_mask") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
+ if (index >= occlusion_layers.size()) {
+ set_occlusion_layers_count(index + 1);
+ }
+ set_occlusion_layer_light_mask(index, p_value);
+ return true;
+ } else if (components[1] == "sdf_collision") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::BOOL, false);
+ if (index >= occlusion_layers.size()) {
+ set_occlusion_layers_count(index + 1);
+ }
+ set_occlusion_layer_sdf_collision(index, p_value);
+ return true;
+ }
+ } else if (components.size() == 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) {
+ // Physics layers.
+ int index = components[0].trim_prefix("physics_layer_").to_int();
+ ERR_FAIL_COND_V(index < 0, false);
+ if (components[1] == "collision_layer") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
+ if (index >= physics_layers.size()) {
+ set_physics_layers_count(index + 1);
+ }
+ set_physics_layer_collision_layer(index, p_value);
+ return true;
+ } else if (components[1] == "collision_mask") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
+ if (index >= physics_layers.size()) {
+ set_physics_layers_count(index + 1);
+ }
+ set_physics_layer_collision_mask(index, p_value);
+ return true;
+ } else if (components[1] == "physics_material") {
+ Ref<PhysicsMaterial> physics_material = p_value;
+ ERR_FAIL_COND_V(!physics_material.is_valid(), false);
+ if (index >= physics_layers.size()) {
+ set_physics_layers_count(index + 1);
+ }
+ set_physics_layer_physics_material(index, physics_material);
+ return true;
+ }
+ } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_integer()) {
+ // Terrains.
+ int terrain_set_index = components[0].trim_prefix("terrain_set_").to_int();
+ ERR_FAIL_COND_V(terrain_set_index < 0, false);
+ if (components[1] == "mode") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
+ if (terrain_set_index >= terrain_sets.size()) {
+ set_terrain_sets_count(terrain_set_index + 1);
+ }
+ set_terrain_set_mode(terrain_set_index, TerrainMode(int(p_value)));
+ } else if (components[1] == "terrains_count") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
+ if (terrain_set_index >= terrain_sets.size()) {
+ set_terrain_sets_count(terrain_set_index + 1);
+ }
+ set_terrains_count(terrain_set_index, p_value);
+ return true;
+ } else if (components.size() >= 3 && components[1].begins_with("terrain_") && components[1].trim_prefix("terrain_").is_valid_integer()) {
+ int terrain_index = components[1].trim_prefix("terrain_").to_int();
+ ERR_FAIL_COND_V(terrain_index < 0, false);
+ if (components[2] == "name") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::STRING, false);
+ if (terrain_set_index >= terrain_sets.size()) {
+ set_terrain_sets_count(terrain_set_index + 1);
+ }
+ if (terrain_index >= terrain_sets[terrain_set_index].terrains.size()) {
+ set_terrains_count(terrain_set_index, terrain_index + 1);
+ }
+ set_terrain_name(terrain_set_index, terrain_index, p_value);
+ return true;
+ } else if (components[2] == "color") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::COLOR, false);
+ if (terrain_set_index >= terrain_sets.size()) {
+ set_terrain_sets_count(terrain_set_index + 1);
+ }
+ if (terrain_index >= terrain_sets[terrain_set_index].terrains.size()) {
+ set_terrains_count(terrain_set_index, terrain_index + 1);
+ }
+ set_terrain_color(terrain_set_index, terrain_index, p_value);
+ return true;
+ }
+ }
+ } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) {
+ // Navigation layers.
+ int index = components[0].trim_prefix("navigation_layer_").to_int();
+ ERR_FAIL_COND_V(index < 0, false);
+ if (components[1] == "layers") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
+ if (index >= navigation_layers.size()) {
+ set_navigation_layers_count(index + 1);
+ }
+ set_navigation_layer_layers(index, p_value);
+ return true;
+ }
+ } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_integer()) {
+ // Custom data layers.
+ int index = components[0].trim_prefix("custom_data_layer_").to_int();
+ ERR_FAIL_COND_V(index < 0, false);
+ if (components[1] == "name") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::STRING, false);
+ if (index >= custom_data_layers.size()) {
+ set_custom_data_layers_count(index + 1);
+ }
+ set_custom_data_name(index, p_value);
+ return true;
+ } else if (components[1] == "type") {
+ ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
+ if (index >= custom_data_layers.size()) {
+ set_custom_data_layers_count(index + 1);
+ }
+ set_custom_data_type(index, Variant::Type(int(p_value)));
+ return true;
+ }
+ } else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_integer()) {
+ // Create source only if it does not exists.
+ int source_id = components[1].to_int();
+
+ if (!has_source(source_id)) {
+ add_source(p_value, source_id);
}
- lower_bound = upper_bound;
- priorities_E = priorities_E->next();
- coords_E = coords_E->next();
+ return true;
}
- return result;
+#ifndef DISABLE_DEPRECATED
}
+#endif // DISABLE_DEPRECATED
+
+ return false;
}
-Vector2 TileSet::atlastile_get_subtile_by_priority(int p_id, const Node *p_tilemap_node, const Vector2 &p_tile_location) {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2());
- //First try to forward selection to script
- 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) {
- return ret;
+bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+
+ if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) {
+ // Occlusion layers.
+ int index = components[0].trim_prefix("occlusion_layer_").to_int();
+ if (index < 0 || index >= occlusion_layers.size()) {
+ return false;
+ }
+ if (components[1] == "light_mask") {
+ r_ret = get_occlusion_layer_light_mask(index);
+ return true;
+ } else if (components[1] == "sdf_collision") {
+ r_ret = get_occlusion_layer_sdf_collision(index);
+ return true;
+ }
+ } else if (components.size() == 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) {
+ // Physics layers.
+ int index = components[0].trim_prefix("physics_layer_").to_int();
+ if (index < 0 || index >= physics_layers.size()) {
+ return false;
+ }
+ if (components[1] == "collision_layer") {
+ r_ret = get_physics_layer_collision_layer(index);
+ return true;
+ } else if (components[1] == "collision_mask") {
+ r_ret = get_physics_layer_collision_mask(index);
+ return true;
+ } else if (components[1] == "physics_material") {
+ r_ret = get_physics_layer_physics_material(index);
+ return true;
+ }
+ } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_integer()) {
+ // Terrains.
+ int terrain_set_index = components[0].trim_prefix("terrain_set_").to_int();
+ if (terrain_set_index < 0 || terrain_set_index >= terrain_sets.size()) {
+ return false;
+ }
+ if (components[1] == "mode") {
+ r_ret = get_terrain_set_mode(terrain_set_index);
+ return true;
+ } else if (components[1] == "terrains_count") {
+ r_ret = get_terrains_count(terrain_set_index);
+ return true;
+ } else if (components.size() >= 3 && components[1].begins_with("terrain_") && components[1].trim_prefix("terrain_").is_valid_integer()) {
+ int terrain_index = components[1].trim_prefix("terrain_").to_int();
+ if (terrain_index < 0 || terrain_index >= terrain_sets[terrain_set_index].terrains.size()) {
+ return false;
+ }
+ if (components[2] == "name") {
+ r_ret = get_terrain_name(terrain_set_index, terrain_index);
+ return true;
+ } else if (components[2] == "color") {
+ r_ret = get_terrain_color(terrain_set_index, terrain_index);
+ return true;
}
}
+ } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) {
+ // navigation layers.
+ int index = components[0].trim_prefix("navigation_layer_").to_int();
+ if (index < 0 || index >= navigation_layers.size()) {
+ return false;
+ }
+ if (components[1] == "layers") {
+ r_ret = get_navigation_layer_layers(index);
+ return true;
+ }
+ } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_integer()) {
+ // Custom data layers.
+ int index = components[0].trim_prefix("custom_data_layer_").to_int();
+ if (index < 0 || index >= custom_data_layers.size()) {
+ return false;
+ }
+ if (components[1] == "name") {
+ r_ret = get_custom_data_name(index);
+ return true;
+ } else if (components[1] == "type") {
+ r_ret = get_custom_data_type(index);
+ return true;
+ }
+ } else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_integer()) {
+ // Atlases data.
+ int source_id = components[1].to_int();
+
+ if (has_source(source_id)) {
+ r_ret = get_source(source_id);
+ return true;
+ } else {
+ return false;
+ }
}
- Vector2 coord = tile_get_region(p_id).size / autotile_get_size(p_id);
+ return false;
+}
- List<Vector2> coords;
- for (int x = 0; x < coord.x; x++) {
- for (int y = 0; y < coord.y; y++) {
- for (int i = 0; i < autotile_get_subtile_priority(p_id, Vector2(x, y)); i++) {
- coords.push_back(Vector2(x, y));
- }
+void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
+ PropertyInfo property_info;
+ // Rendering.
+ p_list->push_back(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+ for (int i = 0; i < occlusion_layers.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("occlusion_layer_%d/light_mask", i), PROPERTY_HINT_LAYERS_2D_RENDER));
+
+ // occlusion_layer_%d/sdf_collision
+ property_info = PropertyInfo(Variant::BOOL, vformat("occlusion_layer_%d/sdf_collision", i));
+ if (occlusion_layers[i].sdf_collision == false) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+
+ // Physics.
+ p_list->push_back(PropertyInfo(Variant::NIL, "Physics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+ for (int i = 0; i < physics_layers.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("physics_layer_%d/collision_layer", i), PROPERTY_HINT_LAYERS_2D_PHYSICS));
+
+ // physics_layer_%d/collision_mask
+ property_info = PropertyInfo(Variant::INT, vformat("physics_layer_%d/collision_mask", i), PROPERTY_HINT_LAYERS_2D_PHYSICS);
+ if (physics_layers[i].collision_mask == 1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+
+ // physics_layer_%d/physics_material
+ property_info = PropertyInfo(Variant::OBJECT, vformat("physics_layer_%d/physics_material", i), PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial");
+ if (!physics_layers[i].physics_material.is_valid()) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+
+ // Terrains.
+ p_list->push_back(PropertyInfo(Variant::NIL, "Terrains", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+ for (int terrain_set_index = 0; terrain_set_index < terrain_sets.size(); terrain_set_index++) {
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("terrain_set_%d/mode", terrain_set_index), PROPERTY_HINT_ENUM, "Match corners and sides,Match corners,Match sides"));
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("terrain_set_%d/terrains_count", terrain_set_index), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+ for (int terrain_index = 0; terrain_index < terrain_sets[terrain_set_index].terrains.size(); terrain_index++) {
+ p_list->push_back(PropertyInfo(Variant::STRING, vformat("terrain_set_%d/terrain_%d/name", terrain_set_index, terrain_index)));
+ p_list->push_back(PropertyInfo(Variant::COLOR, vformat("terrain_set_%d/terrain_%d/color", terrain_set_index, terrain_index)));
+ }
+ }
+
+ // Navigation.
+ p_list->push_back(PropertyInfo(Variant::NIL, "Navigation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+ for (int i = 0; i < navigation_layers.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("navigation_layer_%d/layers", i), PROPERTY_HINT_LAYERS_2D_NAVIGATION));
+ }
+
+ // Custom data.
+ String argt = "Any";
+ for (int i = 1; i < Variant::VARIANT_MAX; i++) {
+ argt += "," + Variant::get_type_name(Variant::Type(i));
+ }
+ p_list->push_back(PropertyInfo(Variant::NIL, "Custom data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+ for (int i = 0; i < custom_data_layers.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::STRING, vformat("custom_data_layer_%d/name", i)));
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("custom_data_layer_%d/type", i), PROPERTY_HINT_ENUM, argt));
+ }
+
+ // Sources.
+ // Note: sources have to be listed in at the end as some TileData rely on the TileSet properties being initialized first.
+ for (Map<int, Ref<TileSetSource>>::Element *E_source = sources.front(); E_source; E_source = E_source->next()) {
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("sources/%d", E_source->key()), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ }
+}
+
+void TileSet::_bind_methods() {
+ // Sources management.
+ ClassDB::bind_method(D_METHOD("get_next_source_id"), &TileSet::get_next_source_id);
+ ClassDB::bind_method(D_METHOD("add_source", "atlas_source_id_override"), &TileSet::add_source, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("remove_source", "source_id"), &TileSet::remove_source);
+ ClassDB::bind_method(D_METHOD("set_source_id", "source_id"), &TileSet::set_source_id);
+ ClassDB::bind_method(D_METHOD("get_source_count"), &TileSet::get_source_count);
+ ClassDB::bind_method(D_METHOD("get_source_id", "index"), &TileSet::get_source_id);
+ ClassDB::bind_method(D_METHOD("has_source", "index"), &TileSet::has_source);
+ ClassDB::bind_method(D_METHOD("get_source", "index"), &TileSet::get_source);
+
+ // Shape and layout.
+ ClassDB::bind_method(D_METHOD("set_tile_shape", "shape"), &TileSet::set_tile_shape);
+ ClassDB::bind_method(D_METHOD("get_tile_shape"), &TileSet::get_tile_shape);
+ ClassDB::bind_method(D_METHOD("set_tile_layout", "layout"), &TileSet::set_tile_layout);
+ ClassDB::bind_method(D_METHOD("get_tile_layout"), &TileSet::get_tile_layout);
+ ClassDB::bind_method(D_METHOD("set_tile_offset_axis", "alignment"), &TileSet::set_tile_offset_axis);
+ ClassDB::bind_method(D_METHOD("get_tile_offset_axis"), &TileSet::get_tile_offset_axis);
+ ClassDB::bind_method(D_METHOD("set_tile_size", "size"), &TileSet::set_tile_size);
+ ClassDB::bind_method(D_METHOD("get_tile_size"), &TileSet::get_tile_size);
+ ClassDB::bind_method(D_METHOD("set_tile_skew", "skew"), &TileSet::set_tile_skew);
+ ClassDB::bind_method(D_METHOD("get_tile_skew"), &TileSet::get_tile_skew);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_shape", PROPERTY_HINT_ENUM, "Square,Isometric,Half-Offset Square,Hexagon"), "set_tile_shape", "get_tile_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_layout", PROPERTY_HINT_ENUM, "Stacked,Stacked Offset,Stairs Right,Stairs Down,Diamond Right,Diamond Down"), "set_tile_layout", "get_tile_layout");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_offset_axis", PROPERTY_HINT_ENUM, "Horizontal Offset,Vertical Offset"), "set_tile_offset_axis", "get_tile_offset_axis");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_size"), "set_tile_size", "get_tile_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_skew"), "set_tile_skew", "get_tile_skew");
+
+ // Rendering.
+ ClassDB::bind_method(D_METHOD("set_uv_clipping", "uv_clipping"), &TileSet::set_uv_clipping);
+ ClassDB::bind_method(D_METHOD("is_uv_clipping"), &TileSet::is_uv_clipping);
+ ClassDB::bind_method(D_METHOD("set_y_sorting", "y_sorting"), &TileSet::set_y_sorting);
+ ClassDB::bind_method(D_METHOD("is_y_sorting"), &TileSet::is_y_sorting);
+
+ ClassDB::bind_method(D_METHOD("set_occlusion_layers_count", "occlusion_layers_count"), &TileSet::set_occlusion_layers_count);
+ ClassDB::bind_method(D_METHOD("get_occlusion_layers_count"), &TileSet::get_occlusion_layers_count);
+ ClassDB::bind_method(D_METHOD("set_occlusion_layer_light_mask", "layer_index", "light_mask"), &TileSet::set_occlusion_layer_light_mask);
+ ClassDB::bind_method(D_METHOD("get_occlusion_layer_light_mask"), &TileSet::get_occlusion_layer_light_mask);
+ ClassDB::bind_method(D_METHOD("set_occlusion_layer_sdf_collision", "layer_index", "sdf_collision"), &TileSet::set_occlusion_layer_sdf_collision);
+ ClassDB::bind_method(D_METHOD("get_occlusion_layer_sdf_collision"), &TileSet::get_occlusion_layer_sdf_collision);
+
+ // Physics
+ ClassDB::bind_method(D_METHOD("set_physics_layers_count", "physics_layers_count"), &TileSet::set_physics_layers_count);
+ ClassDB::bind_method(D_METHOD("get_physics_layers_count"), &TileSet::get_physics_layers_count);
+ ClassDB::bind_method(D_METHOD("set_physics_layer_collision_layer", "layer_index", "layer"), &TileSet::set_physics_layer_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_physics_layer_collision_layer", "layer_index"), &TileSet::get_physics_layer_collision_layer);
+ ClassDB::bind_method(D_METHOD("set_physics_layer_collision_mask", "layer_index", "mask"), &TileSet::set_physics_layer_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_physics_layer_collision_mask", "layer_index"), &TileSet::get_physics_layer_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_physics_layer_physics_material", "layer_index", "physics_material"), &TileSet::set_physics_layer_physics_material);
+ ClassDB::bind_method(D_METHOD("get_physics_layer_physics_material", "layer_index"), &TileSet::get_physics_layer_physics_material);
+
+ // Terrains
+ ClassDB::bind_method(D_METHOD("set_terrain_sets_count", "terrain_sets_count"), &TileSet::set_terrain_sets_count);
+ ClassDB::bind_method(D_METHOD("get_terrain_sets_count"), &TileSet::get_terrain_sets_count);
+ ClassDB::bind_method(D_METHOD("set_terrain_set_mode", "terrain_set", "mode"), &TileSet::set_terrain_set_mode);
+ ClassDB::bind_method(D_METHOD("get_terrain_set_mode", "terrain_set"), &TileSet::get_terrain_set_mode);
+
+ ClassDB::bind_method(D_METHOD("set_terrains_count", "terrain_set", "terrains_count"), &TileSet::set_terrains_count);
+ ClassDB::bind_method(D_METHOD("get_terrains_count", "terrain_set"), &TileSet::get_terrains_count);
+ ClassDB::bind_method(D_METHOD("set_terrain_name", "terrain_set", "terrain_index", "name"), &TileSet::set_terrain_name);
+ ClassDB::bind_method(D_METHOD("get_terrain_name", "terrain_set", "terrain_index"), &TileSet::get_terrain_name);
+ ClassDB::bind_method(D_METHOD("set_terrain_color", "terrain_set", "terrain_index", "color"), &TileSet::set_terrain_color);
+ ClassDB::bind_method(D_METHOD("get_terrain_color", "terrain_set", "terrain_index"), &TileSet::get_terrain_color);
+
+ // Navigation
+ ClassDB::bind_method(D_METHOD("set_navigation_layers_count", "navigation_layers_count"), &TileSet::set_navigation_layers_count);
+ ClassDB::bind_method(D_METHOD("get_navigation_layers_count"), &TileSet::get_navigation_layers_count);
+ ClassDB::bind_method(D_METHOD("set_navigation_layer_layers", "layer_index", "layers"), &TileSet::set_navigation_layer_layers);
+ ClassDB::bind_method(D_METHOD("get_navigation_layer_layers", "layer_index"), &TileSet::get_navigation_layer_layers);
+
+ // Custom data
+ ClassDB::bind_method(D_METHOD("set_custom_data_layers_count", "custom_data_layers_count"), &TileSet::set_custom_data_layers_count);
+ ClassDB::bind_method(D_METHOD("get_custom_data_layers_count"), &TileSet::get_custom_data_layers_count);
+
+ ADD_GROUP("Rendering", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uv_clipping"), "set_uv_clipping", "is_uv_clipping");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "y_sorting"), "set_y_sorting", "is_y_sorting");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "occlusion_layers_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_occlusion_layers_count", "get_occlusion_layers_count");
+
+ ADD_GROUP("Physics", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_layers_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_physics_layers_count", "get_physics_layers_count");
+
+ ADD_GROUP("Terrains", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "terrains_sets_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_terrain_sets_count", "get_terrain_sets_count");
+
+ ADD_GROUP("Navigation", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_navigation_layers_count", "get_navigation_layers_count");
+
+ ADD_GROUP("Custom data", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "custom_data_layers_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_custom_data_layers_count", "get_custom_data_layers_count");
+
+ // -- Enum binding --
+ BIND_ENUM_CONSTANT(TILE_SHAPE_SQUARE);
+ BIND_ENUM_CONSTANT(TILE_SHAPE_ISOMETRIC);
+ BIND_ENUM_CONSTANT(TILE_SHAPE_HALF_OFFSET_SQUARE);
+ BIND_ENUM_CONSTANT(TILE_SHAPE_HEXAGON);
+
+ BIND_ENUM_CONSTANT(TILE_LAYOUT_STACKED);
+ BIND_ENUM_CONSTANT(TILE_LAYOUT_STACKED_OFFSET);
+ BIND_ENUM_CONSTANT(TILE_LAYOUT_STAIRS_RIGHT);
+ BIND_ENUM_CONSTANT(TILE_LAYOUT_STAIRS_DOWN);
+ BIND_ENUM_CONSTANT(TILE_LAYOUT_DIAMOND_RIGHT);
+ BIND_ENUM_CONSTANT(TILE_LAYOUT_DIAMOND_DOWN);
+
+ BIND_ENUM_CONSTANT(TILE_OFFSET_AXIS_HORIZONTAL);
+ BIND_ENUM_CONSTANT(TILE_OFFSET_AXIS_VERTICAL);
+
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_RIGHT_SIDE);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_RIGHT_CORNER);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_LEFT_CORNER);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_CORNER);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER);
+
+ BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_CORNERS_AND_SIDES);
+ BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_CORNERS);
+ BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_SIDES);
+}
+
+TileSet::TileSet() {
+ // Instanciatie and list all plugins.
+ tile_set_plugins_vector.append(memnew(TileSetPluginAtlasRendering));
+ tile_set_plugins_vector.append(memnew(TileSetPluginAtlasPhysics));
+ tile_set_plugins_vector.append(memnew(TileSetPluginAtlasTerrain));
+ tile_set_plugins_vector.append(memnew(TileSetPluginAtlasNavigation));
+ tile_set_plugins_vector.append(memnew(TileSetPluginScenesCollections));
+}
+
+TileSet::~TileSet() {
+#ifndef DISABLE_DEPRECATED
+ for (Map<int, CompatibilityTileData *>::Element *E = compatibility_data.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
+#endif // DISABLE_DEPRECATED
+ while (!source_ids.is_empty()) {
+ remove_source(source_ids[0]);
+ }
+ for (int i = 0; i < tile_set_plugins_vector.size(); i++) {
+ memdelete(tile_set_plugins_vector[i]);
+ }
+}
+
+/////////////////////////////// TileSetSource //////////////////////////////////////
+
+void TileSetSource::set_tile_set(const TileSet *p_tile_set) {
+ tile_set = p_tile_set;
+}
+
+/////////////////////////////// TileSetAtlasSource //////////////////////////////////////
+
+void TileSetAtlasSource::set_tile_set(const TileSet *p_tile_set) {
+ tile_set = p_tile_set;
+
+ // Set the TileSet on all TileData.
+ for (Map<Vector2i, TileAlternativesData>::Element *E_tile = tiles.front(); E_tile; E_tile = E_tile->next()) {
+ for (Map<int, TileData *>::Element *E_alternative = E_tile->get().alternatives.front(); E_alternative; E_alternative = E_alternative->next()) {
+ E_alternative->get()->set_tile_set(tile_set);
+ }
+ }
+}
+
+void TileSetAtlasSource::notify_tile_data_properties_should_change() {
+ // Set the TileSet on all TileData.
+ for (Map<Vector2i, TileAlternativesData>::Element *E_tile = tiles.front(); E_tile; E_tile = E_tile->next()) {
+ for (Map<int, TileData *>::Element *E_alternative = E_tile->get().alternatives.front(); E_alternative; E_alternative = E_alternative->next()) {
+ E_alternative->get()->notify_tile_data_properties_should_change();
}
}
- if (coords.size() == 0) {
- return autotile_get_icon_coordinate(p_id);
+}
+
+void TileSetAtlasSource::reset_state() {
+ // Reset all TileData.
+ for (Map<Vector2i, TileAlternativesData>::Element *E_tile = tiles.front(); E_tile; E_tile = E_tile->next()) {
+ for (Map<int, TileData *>::Element *E_alternative = E_tile->get().alternatives.front(); E_alternative; E_alternative = E_alternative->next()) {
+ E_alternative->get()->reset_state();
+ }
+ }
+}
+
+void TileSetAtlasSource::set_texture(Ref<Texture2D> p_texture) {
+ texture = p_texture;
+
+ emit_changed();
+}
+
+Ref<Texture2D> TileSetAtlasSource::get_texture() const {
+ return texture;
+}
+
+void TileSetAtlasSource::set_margins(Vector2i p_margins) {
+ if (p_margins.x < 0 || p_margins.y < 0) {
+ WARN_PRINT("Atlas source margins should be positive.");
+ margins = Vector2i(MAX(0, p_margins.x), MAX(0, p_margins.y));
} else {
- return coords[Math::random(0, (int)coords.size())];
+ margins = p_margins;
}
+
+ emit_changed();
+}
+Vector2i TileSetAtlasSource::get_margins() const {
+ return margins;
}
-void TileSet::tile_set_name(int p_id, const String &p_name) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].name = p_name;
+void TileSetAtlasSource::set_separation(Vector2i p_separation) {
+ if (p_separation.x < 0 || p_separation.y < 0) {
+ WARN_PRINT("Atlas source separation should be positive.");
+ separation = Vector2i(MAX(0, p_separation.x), MAX(0, p_separation.y));
+ } else {
+ separation = p_separation;
+ }
+
emit_changed();
}
+Vector2i TileSetAtlasSource::get_separation() const {
+ return separation;
+}
+
+void TileSetAtlasSource::set_texture_region_size(Vector2i p_tile_size) {
+ if (p_tile_size.x <= 0 || p_tile_size.y <= 0) {
+ WARN_PRINT("Atlas source tile_size should be strictly positive.");
+ texture_region_size = Vector2i(MAX(1, p_tile_size.x), MAX(1, p_tile_size.y));
+ } else {
+ texture_region_size = p_tile_size;
+ }
-String TileSet::tile_get_name(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), String());
- return tile_map[p_id].name;
+ emit_changed();
+}
+Vector2i TileSetAtlasSource::get_texture_region_size() const {
+ return texture_region_size;
}
-void TileSet::tile_clear_shapes(int p_id) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].shapes_data.clear();
+Vector2i TileSetAtlasSource::get_atlas_grid_size() const {
+ Ref<Texture2D> texture = get_texture();
+ if (!texture.is_valid()) {
+ return Vector2i();
+ }
+
+ ERR_FAIL_COND_V(texture_region_size.x <= 0 || texture_region_size.y <= 0, Vector2i());
+
+ Size2i valid_area = texture->get_size() - margins;
+
+ // Compute the number of valid tiles in the tiles atlas
+ Size2i grid_size = Size2i();
+ if (valid_area.x >= texture_region_size.x && valid_area.y >= texture_region_size.y) {
+ valid_area -= texture_region_size;
+ grid_size = Size2i(1, 1) + valid_area / (texture_region_size + separation);
+ }
+ return grid_size;
}
-void TileSet::tile_add_shape(int p_id, const Ref<Shape2D> &p_shape, const Transform2D &p_transform, bool p_one_way, const Vector2 &p_autotile_coord) {
- ERR_FAIL_COND(!tile_map.has(p_id));
+bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
- ShapeData new_data = ShapeData();
- new_data.shape = p_shape;
- new_data.shape_transform = p_transform;
- new_data.one_way_collision = p_one_way;
- new_data.autotile_coord = p_autotile_coord;
+ // Compute the vector2i if we have coordinates.
+ Vector<String> coords_split = components[0].split(":");
+ Vector2i coords = TileSetSource::INVALID_ATLAS_COORDS;
+ if (coords_split.size() == 2 && coords_split[0].is_valid_integer() && coords_split[1].is_valid_integer()) {
+ coords = Vector2i(coords_split[0].to_int(), coords_split[1].to_int());
+ }
- tile_map[p_id].shapes_data.push_back(new_data);
+ // Properties.
+ if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ // Create the tile if needed.
+ if (!has_tile(coords)) {
+ create_tile(coords);
+ }
+ if (components.size() >= 2) {
+ // Properties.
+ if (components[1] == "size_in_atlas") {
+ move_tile_in_atlas(coords, coords, p_value);
+ } else if (components[1] == "next_alternative_id") {
+ tiles[coords].next_alternative_id = p_value;
+ } else if (components[1].is_valid_integer()) {
+ int alternative_id = components[1].to_int();
+ if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) {
+ // Create the alternative if needed ?
+ if (!has_alternative_tile(coords, alternative_id)) {
+ create_alternative_tile(coords, alternative_id);
+ }
+ if (!tiles[coords].alternatives.has(alternative_id)) {
+ tiles[coords].alternatives[alternative_id] = memnew(TileData);
+ tiles[coords].alternatives[alternative_id]->set_tile_set(tile_set);
+ tiles[coords].alternatives[alternative_id]->set_allow_transform(alternative_id > 0);
+ tiles[coords].alternatives_ids.append(alternative_id);
+ }
+ if (components.size() >= 3) {
+ bool valid;
+ tiles[coords].alternatives[alternative_id]->set(components[2], p_value, &valid);
+ return valid;
+ } else {
+ // Only create the alternative if it did not exist yet.
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
}
-int TileSet::tile_get_shape_count(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), 0);
- return tile_map[p_id].shapes_data.size();
+bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+
+ // Properties.
+ Vector<String> coords_split = components[0].split(":");
+ if (coords_split.size() == 2 && coords_split[0].is_valid_integer() && coords_split[1].is_valid_integer()) {
+ Vector2i coords = Vector2i(coords_split[0].to_int(), coords_split[1].to_int());
+ if (tiles.has(coords)) {
+ if (components.size() >= 2) {
+ // Properties.
+ if (components[1] == "size_in_atlas") {
+ r_ret = tiles[coords].size_in_atlas;
+ return true;
+ } else if (components[1] == "next_alternative_id") {
+ r_ret = tiles[coords].next_alternative_id;
+ return true;
+ } else if (components[1].is_valid_integer()) {
+ int alternative_id = components[1].to_int();
+ if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE && tiles[coords].alternatives.has(alternative_id)) {
+ if (components.size() >= 3) {
+ bool valid;
+ r_ret = tiles[coords].alternatives[alternative_id]->get(components[2], &valid);
+ return valid;
+ } else {
+ // Only to notify the tile alternative exists.
+ r_ret = alternative_id;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
}
-void TileSet::tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_shape) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- ERR_FAIL_COND(p_shape_id < 0);
+void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
+ // Atlases data.
+ PropertyInfo property_info;
+ for (Map<Vector2i, TileAlternativesData>::Element *E_tile = tiles.front(); E_tile; E_tile = E_tile->next()) {
+ List<PropertyInfo> tile_property_list;
+
+ // size_in_atlas
+ property_info = PropertyInfo(Variant::VECTOR2I, "size_in_atlas", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ if (E_tile->get().size_in_atlas == Vector2i(1, 1)) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ tile_property_list.push_back(property_info);
+
+ // next_alternative_id
+ property_info = PropertyInfo(Variant::INT, "next_alternative_id", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ if (E_tile->get().next_alternative_id == 1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ tile_property_list.push_back(property_info);
+
+ for (Map<int, TileData *>::Element *E_alternative = E_tile->get().alternatives.front(); E_alternative; E_alternative = E_alternative->next()) {
+ // Add a dummy property to show the alternative exists.
+ tile_property_list.push_back(PropertyInfo(Variant::INT, vformat("%d", E_alternative->key()), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+
+ // Get the alternative tile's properties and append them to the list of properties.
+ List<PropertyInfo> alternative_property_list;
+ E_alternative->get()->get_property_list(&alternative_property_list);
+ for (List<PropertyInfo>::Element *E_property = alternative_property_list.front(); E_property; E_property = E_property->next()) {
+ property_info = E_property->get();
+ bool valid;
+ Variant default_value = ClassDB::class_get_default_property_value("TileData", property_info.name, &valid);
+ Variant value = E_alternative->get()->get(property_info.name);
+ if (valid && value == default_value) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ property_info.name = vformat("%s/%s", vformat("%d", E_alternative->key()), property_info.name);
+ tile_property_list.push_back(property_info);
+ }
+ }
- if (p_shape_id >= tile_map[p_id].shapes_data.size()) {
- tile_map[p_id].shapes_data.resize(p_shape_id + 1);
+ // Add all alternative.
+ for (List<PropertyInfo>::Element *E_property = tile_property_list.front(); E_property; E_property = E_property->next()) {
+ E_property->get().name = vformat("%s/%s", vformat("%d:%d", E_tile->key().x, E_tile->key().y), E_property->get().name);
+ p_list->push_back(E_property->get());
+ }
}
- tile_map[p_id].shapes_data.write[p_shape_id].shape = p_shape;
- _decompose_convex_shape(p_shape);
- emit_changed();
}
-Ref<Shape2D> TileSet::tile_get_shape(int p_id, int p_shape_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<Shape2D>());
- ERR_FAIL_COND_V(p_shape_id < 0, Ref<Shape2D>());
+void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector2i p_size) {
+ // Create a tile if it does not exists.
+ ERR_FAIL_COND(p_atlas_coords.x < 0 || p_atlas_coords.y < 0);
+ ERR_FAIL_COND(p_size.x <= 0 || p_size.y <= 0);
+ for (int x = 0; x < p_size.x; x++) {
+ for (int y = 0; y < p_size.y; y++) {
+ Vector2i coords = p_atlas_coords + Vector2i(x, y);
+ ERR_FAIL_COND_MSG(tiles.has(coords), vformat("Cannot create tile at position %s with size %s. Already a tile present at %s.", p_atlas_coords, p_size, coords));
+ }
+ }
- if (p_shape_id < tile_map[p_id].shapes_data.size()) {
- return tile_map[p_id].shapes_data[p_shape_id].shape;
+ // Create and resize the tile.
+ tiles.insert(p_atlas_coords, TileSetAtlasSource::TileAlternativesData());
+ tiles_ids.append(p_atlas_coords);
+ tiles_ids.sort();
+
+ tiles[p_atlas_coords].size_in_atlas = p_size;
+ tiles[p_atlas_coords].alternatives[0] = memnew(TileData);
+ tiles[p_atlas_coords].alternatives[0]->set_tile_set(tile_set);
+ tiles[p_atlas_coords].alternatives[0]->set_allow_transform(false);
+ tiles[p_atlas_coords].alternatives[0]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
+ tiles[p_atlas_coords].alternatives[0]->notify_property_list_changed();
+ tiles[p_atlas_coords].alternatives_ids.append(0);
+
+ // Add all covered positions to the mapping cache
+ for (int x = 0; x < p_size.x; x++) {
+ for (int y = 0; y < p_size.y; y++) {
+ Vector2i coords = p_atlas_coords + Vector2i(x, y);
+ _coords_mapping_cache[coords] = p_atlas_coords;
+ }
}
- return Ref<Shape2D>();
+ emit_signal("changed");
}
-void TileSet::tile_set_shape_transform(int p_id, int p_shape_id, const Transform2D &p_offset) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- ERR_FAIL_COND(p_shape_id < 0);
+void TileSetAtlasSource::remove_tile(Vector2i p_atlas_coords) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+
+ // Remove all covered positions from the mapping cache
+ Size2i size = tiles[p_atlas_coords].size_in_atlas;
- if (p_shape_id >= tile_map[p_id].shapes_data.size()) {
- tile_map[p_id].shapes_data.resize(p_shape_id + 1);
+ for (int x = 0; x < size.x; x++) {
+ for (int y = 0; y < size.y; y++) {
+ Vector2i coords = p_atlas_coords + Vector2i(x, y);
+ _coords_mapping_cache.erase(coords);
+ }
}
- tile_map[p_id].shapes_data.write[p_shape_id].shape_transform = p_offset;
- emit_changed();
+
+ // Free tile data.
+ for (Map<int, TileData *>::Element *E_tile_data = tiles[p_atlas_coords].alternatives.front(); E_tile_data; E_tile_data = E_tile_data->next()) {
+ memdelete(E_tile_data->get());
+ }
+
+ // Delete the tile
+ tiles.erase(p_atlas_coords);
+ tiles_ids.erase(p_atlas_coords);
+ tiles_ids.sort();
+
+ emit_signal("changed");
}
-Transform2D TileSet::tile_get_shape_transform(int p_id, int p_shape_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Transform2D());
- ERR_FAIL_COND_V(p_shape_id < 0, Transform2D());
+bool TileSetAtlasSource::has_tile(Vector2i p_atlas_coords) const {
+ return tiles.has(p_atlas_coords);
+}
- if (p_shape_id < tile_map[p_id].shapes_data.size()) {
- return tile_map[p_id].shapes_data[p_shape_id].shape_transform;
+Vector2i TileSetAtlasSource::get_tile_at_coords(Vector2i p_atlas_coords) const {
+ if (!_coords_mapping_cache.has(p_atlas_coords)) {
+ return INVALID_ATLAS_COORDS;
}
- return Transform2D();
+ return _coords_mapping_cache[p_atlas_coords];
}
-void TileSet::tile_set_shape_offset(int p_id, int p_shape_id, const Vector2 &p_offset) {
- Transform2D transform = tile_get_shape_transform(p_id, p_shape_id);
- transform.set_origin(p_offset);
- tile_set_shape_transform(p_id, p_shape_id, transform);
+Vector2i TileSetAtlasSource::get_tile_size_in_atlas(Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(-1, -1), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+
+ return tiles[p_atlas_coords].size_in_atlas;
}
-Vector2 TileSet::tile_get_shape_offset(int p_id, int p_shape_id) const {
- return tile_get_shape_transform(p_id, p_shape_id).get_origin();
+int TileSetAtlasSource::get_tiles_count() const {
+ return tiles_ids.size();
}
-void TileSet::tile_set_shape_one_way(int p_id, int p_shape_id, const bool p_one_way) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- ERR_FAIL_COND(p_shape_id < 0);
+Vector2i TileSetAtlasSource::get_tile_id(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, tiles_ids.size(), TileSetSource::INVALID_ATLAS_COORDS);
+ return tiles_ids[p_index];
+}
- if (p_shape_id >= tile_map[p_id].shapes_data.size()) {
- tile_map[p_id].shapes_data.resize(p_shape_id + 1);
+Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Rect2i(), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+
+ Vector2i size_in_atlas = tiles[p_atlas_coords].size_in_atlas;
+ Vector2 region_size = texture_region_size * size_in_atlas + separation * (size_in_atlas - Vector2i(1, 1));
+
+ Vector2 origin = margins + (p_atlas_coords * (texture_region_size + separation));
+
+ return Rect2(origin, region_size);
+ ;
+}
+
+Vector2i TileSetAtlasSource::get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_COND_V_MSG(!has_alternative_tile(p_atlas_coords, p_alternative_tile), Vector2i(), vformat("TileSetAtlasSource has no alternative tile with id %d at %s.", p_alternative_tile, String(p_atlas_coords)));
+ ERR_FAIL_COND_V(!tile_set, Vector2i());
+
+ Vector2 margin = (get_tile_texture_region(p_atlas_coords).size - tile_set->get_tile_size()) / 2;
+ margin = Vector2i(MAX(0, margin.x), MAX(0, margin.y));
+ Vector2i effective_texture_offset = Object::cast_to<TileData>(get_tile_data(p_atlas_coords, p_alternative_tile))->get_texture_offset();
+ if (ABS(effective_texture_offset.x) > margin.x || ABS(effective_texture_offset.y) > margin.y) {
+ effective_texture_offset.x = CLAMP(effective_texture_offset.x, -margin.x, margin.x);
+ effective_texture_offset.y = CLAMP(effective_texture_offset.y, -margin.y, margin.y);
}
- tile_map[p_id].shapes_data.write[p_shape_id].one_way_collision = p_one_way;
- emit_changed();
+
+ return effective_texture_offset;
+}
+
+bool TileSetAtlasSource::can_move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords, Vector2i p_new_size) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), false, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+
+ Vector2i new_atlas_coords = (p_new_atlas_coords != INVALID_ATLAS_COORDS) ? p_new_atlas_coords : p_atlas_coords;
+ if (new_atlas_coords.x < 0 || new_atlas_coords.y < 0) {
+ return false;
+ }
+
+ Vector2i size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tiles[p_atlas_coords].size_in_atlas;
+ ERR_FAIL_COND_V(size.x <= 0 || size.y <= 0, false);
+
+ Size2i grid_size = get_atlas_grid_size();
+ if (new_atlas_coords.x + size.x > grid_size.x || new_atlas_coords.y + size.y > grid_size.y) {
+ return false;
+ }
+
+ Rect2i new_rect = Rect2i(new_atlas_coords, size);
+ // Check if the new tile can fit in the new rect.
+ for (int x = new_rect.position.x; x < new_rect.get_end().x; x++) {
+ for (int y = new_rect.position.y; y < new_rect.get_end().y; y++) {
+ Vector2i coords = get_tile_at_coords(Vector2i(x, y));
+ if (coords != p_atlas_coords && coords != TileSetSource::INVALID_ATLAS_COORDS) {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
-bool TileSet::tile_get_shape_one_way(int p_id, int p_shape_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), false);
- ERR_FAIL_COND_V(p_shape_id < 0, false);
+void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords, Vector2i p_new_size) {
+ bool can_move = can_move_tile_in_atlas(p_atlas_coords, p_new_atlas_coords, p_new_size);
+ ERR_FAIL_COND_MSG(!can_move, vformat("Cannot move tile at position %s with size %s. Tile already present.", p_new_atlas_coords, p_new_size));
- if (p_shape_id < tile_map[p_id].shapes_data.size()) {
- return tile_map[p_id].shapes_data[p_shape_id].one_way_collision;
+ // Compute the actual new rect from arguments.
+ Vector2i new_atlas_coords = (p_new_atlas_coords != INVALID_ATLAS_COORDS) ? p_new_atlas_coords : p_atlas_coords;
+ Vector2i size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tiles[p_atlas_coords].size_in_atlas;
+
+ if (new_atlas_coords == p_atlas_coords && size == tiles[p_atlas_coords].size_in_atlas) {
+ return;
}
- return false;
+ // Remove all covered positions from the mapping cache.
+ Size2i old_size = tiles[p_atlas_coords].size_in_atlas;
+ for (int x = 0; x < old_size.x; x++) {
+ for (int y = 0; y < old_size.y; y++) {
+ Vector2i coords = p_atlas_coords + Vector2i(x, y);
+ _coords_mapping_cache.erase(coords);
+ }
+ }
+
+ // Move the tile and update its size.
+ if (new_atlas_coords != p_atlas_coords) {
+ tiles[new_atlas_coords] = tiles[p_atlas_coords];
+ tiles.erase(p_atlas_coords);
+
+ tiles_ids.erase(p_atlas_coords);
+ tiles_ids.append(new_atlas_coords);
+ tiles_ids.sort();
+ }
+ tiles[new_atlas_coords].size_in_atlas = size;
+
+ // Add all covered positions to the mapping cache again.
+ for (int x = 0; x < size.x; x++) {
+ for (int y = 0; y < size.y; y++) {
+ Vector2i coords = new_atlas_coords + Vector2i(x, y);
+ _coords_mapping_cache[coords] = new_atlas_coords;
+ }
+ }
+
+ emit_signal("changed");
}
-void TileSet::tile_set_shape_one_way_margin(int p_id, int p_shape_id, float p_margin) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- ERR_FAIL_COND(p_shape_id < 0);
+bool TileSetAtlasSource::has_tiles_outside_texture() {
+ Vector2i grid_size = get_atlas_grid_size();
+ Vector<Vector2i> to_remove;
- if (p_shape_id >= tile_map[p_id].shapes_data.size()) {
- tile_map[p_id].shapes_data.resize(p_shape_id + 1);
+ for (Map<Vector2i, TileSetAtlasSource::TileAlternativesData>::Element *E = tiles.front(); E; E = E->next()) {
+ if (E->key().x >= grid_size.x || E->key().y >= grid_size.y) {
+ return true;
+ }
}
- tile_map[p_id].shapes_data.write[p_shape_id].one_way_collision_margin = p_margin;
- emit_changed();
+
+ return false;
}
-float TileSet::tile_get_shape_one_way_margin(int p_id, int p_shape_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), 0);
- ERR_FAIL_COND_V(p_shape_id < 0, 0);
+void TileSetAtlasSource::clear_tiles_outside_texture() {
+ Vector2i grid_size = get_atlas_grid_size();
+ Vector<Vector2i> to_remove;
+
+ for (Map<Vector2i, TileSetAtlasSource::TileAlternativesData>::Element *E = tiles.front(); E; E = E->next()) {
+ if (E->key().x >= grid_size.x || E->key().y >= grid_size.y) {
+ to_remove.append(E->key());
+ }
+ }
- if (p_shape_id < tile_map[p_id].shapes_data.size()) {
- return tile_map[p_id].shapes_data[p_shape_id].one_way_collision_margin;
+ for (int i = 0; i < to_remove.size(); i++) {
+ remove_tile(to_remove[i]);
}
+}
+
+int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_id_override) {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), -1, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+ ERR_FAIL_COND_V_MSG(p_alternative_id_override >= 0 && tiles[p_atlas_coords].alternatives.has(p_alternative_id_override), -1, vformat("Cannot create alternative tile. Another alternative exists with id %d.", p_alternative_id_override));
- return 0;
+ int new_alternative_id = p_alternative_id_override >= 0 ? p_alternative_id_override : tiles[p_atlas_coords].next_alternative_id;
+
+ tiles[p_atlas_coords].alternatives[new_alternative_id] = memnew(TileData);
+ tiles[p_atlas_coords].alternatives[new_alternative_id]->set_tile_set(tile_set);
+ tiles[p_atlas_coords].alternatives[new_alternative_id]->set_allow_transform(true);
+ tiles[p_atlas_coords].alternatives[new_alternative_id]->notify_property_list_changed();
+ tiles[p_atlas_coords].alternatives_ids.append(new_alternative_id);
+ tiles[p_atlas_coords].alternatives_ids.sort();
+ _compute_next_alternative_id(p_atlas_coords);
+
+ emit_signal("changed");
+
+ return new_alternative_id;
+}
+
+void TileSetAtlasSource::remove_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+ ERR_FAIL_COND_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
+ ERR_FAIL_COND_MSG(p_alternative_tile == 0, "Cannot remove the alternative with id 0, the base tile alternative cannot be removed.");
+
+ memdelete(tiles[p_atlas_coords].alternatives[p_alternative_tile]);
+ tiles[p_atlas_coords].alternatives.erase(p_alternative_tile);
+ tiles[p_atlas_coords].alternatives_ids.erase(p_alternative_tile);
+ tiles[p_atlas_coords].alternatives_ids.sort();
+
+ emit_signal("changed");
+}
+
+void TileSetAtlasSource::set_alternative_tile_id(const Vector2i p_atlas_coords, int p_alternative_tile, int p_new_id) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+ ERR_FAIL_COND_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
+ ERR_FAIL_COND_MSG(p_alternative_tile == 0, "Cannot change the alternative with id 0, the base tile alternative cannot be modified.");
+
+ ERR_FAIL_COND_MSG(tiles[p_atlas_coords].alternatives.has(p_new_id), vformat("TileSetAtlasSource has already an alternative with id %d at %s.", p_new_id, String(p_atlas_coords)));
+
+ tiles[p_atlas_coords].alternatives[p_new_id] = tiles[p_atlas_coords].alternatives[p_alternative_tile];
+ tiles[p_atlas_coords].alternatives_ids.append(p_new_id);
+
+ tiles[p_atlas_coords].alternatives.erase(p_alternative_tile);
+ tiles[p_atlas_coords].alternatives_ids.erase(p_alternative_tile);
+ tiles[p_atlas_coords].alternatives_ids.sort();
+
+ emit_signal("changed");
}
-void TileSet::tile_set_light_occluder(int p_id, const Ref<OccluderPolygon2D> &p_light_occluder) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].occluder = p_light_occluder;
+bool TileSetAtlasSource::has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), false, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
+ return tiles[p_atlas_coords].alternatives.has(p_alternative_tile);
}
-Ref<OccluderPolygon2D> TileSet::tile_get_light_occluder(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<OccluderPolygon2D>());
- return tile_map[p_id].occluder;
+int TileSetAtlasSource::get_next_alternative_tile_id(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), -1, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
+ return tiles[p_atlas_coords].next_alternative_id;
+}
+
+int TileSetAtlasSource::get_alternative_tiles_count(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), -1, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
+ return tiles[p_atlas_coords].alternatives_ids.size();
+}
+
+int TileSetAtlasSource::get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), -1, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
+ ERR_FAIL_INDEX_V(p_index, tiles[p_atlas_coords].alternatives_ids.size(), -1);
+
+ return tiles[p_atlas_coords].alternatives_ids[p_index];
}
-void TileSet::autotile_set_light_occluder(int p_id, const Ref<OccluderPolygon2D> &p_light_occluder, const Vector2 &p_coord) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- if (p_light_occluder.is_null()) {
- if (tile_map[p_id].autotile_data.occluder_map.has(p_coord)) {
- tile_map[p_id].autotile_data.occluder_map.erase(p_coord);
+Object *TileSetAtlasSource::get_tile_data(const Vector2i p_atlas_coords, int p_alternative_tile) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
+ ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
+
+ return tiles[p_atlas_coords].alternatives[p_alternative_tile];
+}
+
+void TileSetAtlasSource::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_texture", "texture"), &TileSetAtlasSource::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &TileSetAtlasSource::get_texture);
+ ClassDB::bind_method(D_METHOD("set_margins", "margins"), &TileSetAtlasSource::set_margins);
+ ClassDB::bind_method(D_METHOD("get_margins"), &TileSetAtlasSource::get_margins);
+ ClassDB::bind_method(D_METHOD("set_separation", "separation"), &TileSetAtlasSource::set_separation);
+ ClassDB::bind_method(D_METHOD("get_separation"), &TileSetAtlasSource::get_separation);
+ ClassDB::bind_method(D_METHOD("set_texture_region_size", "texture_region_size"), &TileSetAtlasSource::set_texture_region_size);
+ ClassDB::bind_method(D_METHOD("get_texture_region_size"), &TileSetAtlasSource::get_texture_region_size);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NOEDITOR), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_margins", "get_margins");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_separation", "get_separation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_texture_region_size", "get_texture_region_size");
+
+ // Base tiles
+ ClassDB::bind_method(D_METHOD("create_tile", "atlas_coords", "size"), &TileSetAtlasSource::create_tile, DEFVAL(Vector2i(1, 1)));
+ ClassDB::bind_method(D_METHOD("remove_tile", "atlas_coords"), &TileSetAtlasSource::remove_tile); // Remove a tile. If p_tile_key.alternative_tile if different from 0, remove the alternative
+ ClassDB::bind_method(D_METHOD("has_tile", "atlas_coords"), &TileSetAtlasSource::has_tile);
+ ClassDB::bind_method(D_METHOD("can_move_tile_in_atlas", "atlas_coords", "new_atlas_coords", "new_size"), &TileSetAtlasSource::can_move_tile_in_atlas, DEFVAL(INVALID_ATLAS_COORDS), DEFVAL(Vector2i(-1, -1)));
+ ClassDB::bind_method(D_METHOD("move_tile_in_atlas", "atlas_coords", "new_atlas_coords", "new_size"), &TileSetAtlasSource::move_tile_in_atlas, DEFVAL(INVALID_ATLAS_COORDS), DEFVAL(Vector2i(-1, -1)));
+ ClassDB::bind_method(D_METHOD("get_tile_size_in_atlas", "atlas_coords"), &TileSetAtlasSource::get_tile_size_in_atlas);
+
+ ClassDB::bind_method(D_METHOD("get_tiles_count"), &TileSetAtlasSource::get_tiles_count);
+ ClassDB::bind_method(D_METHOD("get_tile_id", "index"), &TileSetAtlasSource::get_tile_id);
+
+ ClassDB::bind_method(D_METHOD("get_tile_at_coords", "atlas_coords"), &TileSetAtlasSource::get_tile_at_coords);
+
+ // Alternative tiles
+ ClassDB::bind_method(D_METHOD("create_alternative_tile", "atlas_coords", "alternative_id_override"), &TileSetAtlasSource::create_alternative_tile, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("remove_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetAtlasSource::remove_alternative_tile);
+ ClassDB::bind_method(D_METHOD("set_alternative_tile_id", "atlas_coords", "alternative_tile", "new_id"), &TileSetAtlasSource::set_alternative_tile_id);
+ ClassDB::bind_method(D_METHOD("has_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetAtlasSource::has_alternative_tile);
+ ClassDB::bind_method(D_METHOD("get_next_alternative_tile_id", "atlas_coords"), &TileSetAtlasSource::get_next_alternative_tile_id);
+
+ ClassDB::bind_method(D_METHOD("get_alternative_tiles_count", "atlas_coords"), &TileSetAtlasSource::get_alternative_tiles_count);
+ ClassDB::bind_method(D_METHOD("get_alternative_tile_id", "atlas_coords", "index"), &TileSetAtlasSource::get_alternative_tile_id);
+
+ ClassDB::bind_method(D_METHOD("get_tile_data", "atlas_coords", "index"), &TileSetAtlasSource::get_tile_data);
+
+ // Helpers.
+ ClassDB::bind_method(D_METHOD("get_atlas_grid_size"), &TileSetAtlasSource::get_atlas_grid_size);
+ ClassDB::bind_method(D_METHOD("has_tiles_outside_texture"), &TileSetAtlasSource::has_tiles_outside_texture);
+ ClassDB::bind_method(D_METHOD("clear_tiles_outside_texture"), &TileSetAtlasSource::clear_tiles_outside_texture);
+ ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords"), &TileSetAtlasSource::get_tile_texture_region);
+}
+
+TileSetAtlasSource::~TileSetAtlasSource() {
+ // Free everything needed.
+ for (Map<Vector2i, TileAlternativesData>::Element *E_alternatives = tiles.front(); E_alternatives; E_alternatives = E_alternatives->next()) {
+ for (Map<int, TileData *>::Element *E_tile_data = E_alternatives->get().alternatives.front(); E_tile_data; E_tile_data = E_tile_data->next()) {
+ memdelete(E_tile_data->get());
}
- } else {
- tile_map[p_id].autotile_data.occluder_map[p_coord] = p_light_occluder;
}
}
-Ref<OccluderPolygon2D> TileSet::autotile_get_light_occluder(int p_id, const Vector2 &p_coord) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<OccluderPolygon2D>());
+TileData *TileSetAtlasSource::_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile) {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+ ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
+
+ return tiles[p_atlas_coords].alternatives[p_alternative_tile];
+}
+
+const TileData *TileSetAtlasSource::_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+ ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
+
+ return tiles[p_atlas_coords].alternatives[p_alternative_tile];
+}
+
+void TileSetAtlasSource::_compute_next_alternative_id(const Vector2i p_atlas_coords) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+
+ while (tiles[p_atlas_coords].alternatives.has(tiles[p_atlas_coords].next_alternative_id)) {
+ tiles[p_atlas_coords].next_alternative_id = (tiles[p_atlas_coords].next_alternative_id % 1073741823) + 1; // 2 ** 30
+ };
+}
+
+/////////////////////////////// TileSetScenesCollectionSource //////////////////////////////////////
+
+void TileSetScenesCollectionSource::_compute_next_alternative_id() {
+ while (scenes.has(next_scene_id)) {
+ next_scene_id = (next_scene_id % 1073741823) + 1; // 2 ** 30
+ };
+}
+
+int TileSetScenesCollectionSource::get_tiles_count() const {
+ return 1;
+}
+
+Vector2i TileSetScenesCollectionSource::get_tile_id(int p_tile_index) const {
+ ERR_FAIL_COND_V(p_tile_index != 0, TileSetSource::INVALID_ATLAS_COORDS);
+ return Vector2i();
+}
+
+bool TileSetScenesCollectionSource::has_tile(Vector2i p_atlas_coords) const {
+ return p_atlas_coords == Vector2i();
+}
+
+int TileSetScenesCollectionSource::get_alternative_tiles_count(const Vector2i p_atlas_coords) const {
+ return scenes_ids.size();
+}
+
+int TileSetScenesCollectionSource::get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const {
+ ERR_FAIL_COND_V(p_atlas_coords != Vector2i(), TileSetSource::INVALID_TILE_ALTERNATIVE);
+ ERR_FAIL_INDEX_V(p_index, scenes_ids.size(), TileSetSource::INVALID_TILE_ALTERNATIVE);
+
+ return scenes_ids[p_index];
+}
+
+bool TileSetScenesCollectionSource::has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const {
+ ERR_FAIL_COND_V(p_atlas_coords != Vector2i(), false);
+ return scenes.has(p_alternative_tile);
+}
+
+int TileSetScenesCollectionSource::create_scene_tile(Ref<PackedScene> p_packed_scene, int p_id_override) {
+ ERR_FAIL_COND_V_MSG(p_id_override >= 0 && scenes.has(p_id_override), -1, vformat("Cannot create scene tile. Another scene tile exists with id %d.", p_id_override));
+
+ int new_scene_id = p_id_override >= 0 ? p_id_override : next_scene_id;
+
+ scenes[new_scene_id] = SceneData();
+ scenes_ids.append(new_scene_id);
+ scenes_ids.sort();
+ set_scene_tile_scene(new_scene_id, p_packed_scene);
+ _compute_next_alternative_id();
+
+ emit_signal("changed");
- if (!tile_map[p_id].autotile_data.occluder_map.has(p_coord)) {
- return Ref<OccluderPolygon2D>();
+ return new_scene_id;
+}
+
+void TileSetScenesCollectionSource::set_scene_tile_id(int p_id, int p_new_id) {
+ ERR_FAIL_COND(p_new_id < 0);
+ ERR_FAIL_COND(!has_scene_tile_id(p_id));
+ ERR_FAIL_COND(has_scene_tile_id(p_new_id));
+
+ scenes[p_new_id] = SceneData();
+ scenes[p_new_id] = scenes[p_id];
+ scenes_ids.append(p_new_id);
+ scenes_ids.sort();
+
+ _compute_next_alternative_id();
+
+ scenes.erase(p_id);
+ scenes_ids.erase(p_id);
+
+ emit_signal("changed");
+}
+
+void TileSetScenesCollectionSource::set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene) {
+ ERR_FAIL_COND(!scenes.has(p_id));
+ if (p_packed_scene.is_valid()) {
+ // Make sure we have a root node. Supposed to be at 0 index because find_node_by_path() does not seem to work.
+ ERR_FAIL_COND(!p_packed_scene->get_state().is_valid());
+ ERR_FAIL_COND(p_packed_scene->get_state()->get_node_count() < 1);
+
+ // Check if it extends CanvasItem.
+ String type = p_packed_scene->get_state()->get_node_type(0);
+ bool extends_correct_class = ClassDB::is_parent_class(type, "Control") || ClassDB::is_parent_class(type, "Node2D");
+ ERR_FAIL_COND_MSG(!extends_correct_class, vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Root node should extend Control or Node2D.", p_packed_scene->get_path()));
+
+ scenes[p_id].scene = p_packed_scene;
} else {
- return tile_map[p_id].autotile_data.occluder_map[p_coord];
+ scenes[p_id].scene = Ref<PackedScene>();
}
+ emit_signal("changed");
+}
+
+Ref<PackedScene> TileSetScenesCollectionSource::get_scene_tile_scene(int p_id) const {
+ ERR_FAIL_COND_V(!scenes.has(p_id), Ref<PackedScene>());
+ return scenes[p_id].scene;
+}
+
+void TileSetScenesCollectionSource::set_scene_tile_display_placeholder(int p_id, bool p_display_placeholder) {
+ ERR_FAIL_COND(!scenes.has(p_id));
+
+ scenes[p_id].display_placeholder = p_display_placeholder;
+
+ emit_signal("changed");
}
-void TileSet::tile_set_navigation_polygon_offset(int p_id, const Vector2 &p_offset) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].navigation_polygon_offset = p_offset;
+bool TileSetScenesCollectionSource::get_scene_tile_display_placeholder(int p_id) const {
+ ERR_FAIL_COND_V(!scenes.has(p_id), false);
+ return scenes[p_id].display_placeholder;
}
-Vector2 TileSet::tile_get_navigation_polygon_offset(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2());
- return tile_map[p_id].navigation_polygon_offset;
+void TileSetScenesCollectionSource::remove_scene_tile(int p_id) {
+ ERR_FAIL_COND(!scenes.has(p_id));
+
+ scenes.erase(p_id);
+ scenes_ids.erase(p_id);
+ emit_signal("changed");
}
-void TileSet::tile_set_navigation_polygon(int p_id, const Ref<NavigationPolygon> &p_navigation_polygon) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].navigation_polygon = p_navigation_polygon;
+int TileSetScenesCollectionSource::get_next_scene_tile_id() const {
+ return next_scene_id;
}
-Ref<NavigationPolygon> TileSet::tile_get_navigation_polygon(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<NavigationPolygon>());
- return tile_map[p_id].navigation_polygon;
+bool TileSetScenesCollectionSource::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+
+ if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_integer()) {
+ int scene_id = components[1].to_int();
+ if (components.size() >= 3 && components[2] == "scene") {
+ if (has_scene_tile_id(scene_id)) {
+ set_scene_tile_scene(scene_id, p_value);
+ } else {
+ create_scene_tile(p_value, scene_id);
+ }
+ return true;
+ } else if (components.size() >= 3 && components[2] == "display_placeholder") {
+ if (!has_scene_tile_id(scene_id)) {
+ create_scene_tile(p_value, scene_id);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
}
-const Map<Vector2, Ref<OccluderPolygon2D>> &TileSet::autotile_get_light_oclusion_map(int p_id) const {
- 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;
+bool TileSetScenesCollectionSource::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+
+ if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_integer() && scenes.has(components[1].to_int())) {
+ if (components.size() >= 3 && components[2] == "scene") {
+ r_ret = scenes[components[1].to_int()].scene;
+ return true;
+ } else if (components.size() >= 3 && components[2] == "display_placeholder") {
+ r_ret = scenes[components[1].to_int()].scene;
+ return true;
+ }
+ }
+
+ return false;
}
-void TileSet::autotile_set_navigation_polygon(int p_id, const Ref<NavigationPolygon> &p_navigation_polygon, const Vector2 &p_coord) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- if (p_navigation_polygon.is_null()) {
- if (tile_map[p_id].autotile_data.navpoly_map.has(p_coord)) {
- tile_map[p_id].autotile_data.navpoly_map.erase(p_coord);
+void TileSetScenesCollectionSource::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < scenes_ids.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("scenes/%d/scene", scenes_ids[i]), PROPERTY_HINT_RESOURCE_TYPE, "TileSetScenesCollectionSource"));
+
+ PropertyInfo property_info = PropertyInfo(Variant::BOOL, vformat("scenes/%d/display_placeholder", scenes_ids[i]));
+ if (scenes[scenes_ids[i]].display_placeholder == false) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
- } else {
- tile_map[p_id].autotile_data.navpoly_map[p_coord] = p_navigation_polygon;
+ p_list->push_back(property_info);
}
}
-Ref<NavigationPolygon> TileSet::autotile_get_navigation_polygon(int p_id, const Vector2 &p_coord) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Ref<NavigationPolygon>());
- if (!tile_map[p_id].autotile_data.navpoly_map.has(p_coord)) {
- return Ref<NavigationPolygon>();
- } else {
- return tile_map[p_id].autotile_data.navpoly_map[p_coord];
+void TileSetScenesCollectionSource::_bind_methods() {
+ // Base tiles
+ ClassDB::bind_method(D_METHOD("get_tiles_count"), &TileSetScenesCollectionSource::get_tiles_count);
+ ClassDB::bind_method(D_METHOD("get_tile_id", "index"), &TileSetScenesCollectionSource::get_tile_id);
+ ClassDB::bind_method(D_METHOD("has_tile", "atlas_coords"), &TileSetScenesCollectionSource::has_tile);
+
+ // Alternative tiles
+ ClassDB::bind_method(D_METHOD("get_alternative_tiles_count", "atlas_coords"), &TileSetScenesCollectionSource::get_alternative_tiles_count);
+ ClassDB::bind_method(D_METHOD("get_alternative_tile_id", "atlas_coords", "index"), &TileSetScenesCollectionSource::get_alternative_tile_id);
+ ClassDB::bind_method(D_METHOD("has_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetScenesCollectionSource::has_alternative_tile);
+
+ ClassDB::bind_method(D_METHOD("get_scene_tiles_count"), &TileSetScenesCollectionSource::get_scene_tiles_count);
+ ClassDB::bind_method(D_METHOD("get_scene_tile_id", "index"), &TileSetScenesCollectionSource::get_scene_tile_id);
+ ClassDB::bind_method(D_METHOD("has_scene_tile_id", "id"), &TileSetScenesCollectionSource::has_scene_tile_id);
+ ClassDB::bind_method(D_METHOD("create_scene_tile", "packed_scene", "id_override"), &TileSetScenesCollectionSource::create_scene_tile, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("set_scene_tile_id", "id", "new_id"), &TileSetScenesCollectionSource::set_scene_tile_id);
+ ClassDB::bind_method(D_METHOD("set_scene_tile_scene", "id", "packed_scene"), &TileSetScenesCollectionSource::set_scene_tile_scene);
+ ClassDB::bind_method(D_METHOD("get_scene_tile_scene", "id"), &TileSetScenesCollectionSource::get_scene_tile_scene);
+ ClassDB::bind_method(D_METHOD("set_scene_tile_display_placeholder", "id", "display_placeholder"), &TileSetScenesCollectionSource::set_scene_tile_display_placeholder);
+ ClassDB::bind_method(D_METHOD("get_scene_tile_display_placeholder", "id"), &TileSetScenesCollectionSource::get_scene_tile_display_placeholder);
+ ClassDB::bind_method(D_METHOD("remove_scene_tile", "id"), &TileSetScenesCollectionSource::remove_scene_tile);
+ ClassDB::bind_method(D_METHOD("get_next_scene_tile_id"), &TileSetScenesCollectionSource::get_next_scene_tile_id);
+}
+
+/////////////////////////////// TileData //////////////////////////////////////
+
+void TileData::set_tile_set(const TileSet *p_tile_set) {
+ tile_set = p_tile_set;
+ if (tile_set) {
+ occluders.resize(tile_set->get_occlusion_layers_count());
+ physics.resize(tile_set->get_physics_layers_count());
+ navigation.resize(tile_set->get_navigation_layers_count());
+ custom_data.resize(tile_set->get_custom_data_layers_count());
}
+ notify_property_list_changed();
+}
+
+void TileData::notify_tile_data_properties_should_change() {
+ occluders.resize(tile_set->get_occlusion_layers_count());
+ physics.resize(tile_set->get_physics_layers_count());
+ for (int bit_index = 0; bit_index < 16; bit_index++) {
+ if (terrain_set < 0 || terrain_peering_bits[bit_index] >= tile_set->get_terrains_count(terrain_set)) {
+ terrain_peering_bits[bit_index] = -1;
+ }
+ }
+ navigation.resize(tile_set->get_navigation_layers_count());
+
+ // Convert custom data to the new type.
+ custom_data.resize(tile_set->get_custom_data_layers_count());
+ for (int i = 0; i < custom_data.size(); i++) {
+ if (custom_data[i].get_type() != tile_set->get_custom_data_type(i)) {
+ Variant new_val;
+ Callable::CallError error;
+ if (Variant::can_convert(custom_data[i].get_type(), tile_set->get_custom_data_type(i))) {
+ const Variant *args[] = { &custom_data[i] };
+ Variant::construct(tile_set->get_custom_data_type(i), new_val, args, 1, error);
+ } else {
+ Variant::construct(tile_set->get_custom_data_type(i), new_val, nullptr, 0, error);
+ }
+ custom_data.write[i] = new_val;
+ }
+ }
+
+ notify_property_list_changed();
+ emit_signal("changed");
+}
+
+void TileData::reset_state() {
+ occluders.clear();
+ physics.clear();
+ navigation.clear();
+ custom_data.clear();
+}
+
+void TileData::set_allow_transform(bool p_allow_transform) {
+ allow_transform = p_allow_transform;
+}
+
+bool TileData::is_allowing_transform() const {
+ return allow_transform;
+}
+
+// Rendering
+void TileData::set_flip_h(bool p_flip_h) {
+ ERR_FAIL_COND_MSG(!allow_transform && p_flip_h, "Transform is only allowed for alternative tiles (with its alternative_id != 0)");
+ flip_h = p_flip_h;
+ emit_signal("changed");
+}
+bool TileData::get_flip_h() const {
+ return flip_h;
+}
+
+void TileData::set_flip_v(bool p_flip_v) {
+ ERR_FAIL_COND_MSG(!allow_transform && p_flip_v, "Transform is only allowed for alternative tiles (with its alternative_id != 0)");
+ flip_v = p_flip_v;
+ emit_signal("changed");
+}
+
+bool TileData::get_flip_v() const {
+ return flip_v;
+}
+
+void TileData::set_transpose(bool p_transpose) {
+ ERR_FAIL_COND_MSG(!allow_transform && p_transpose, "Transform is only allowed for alternative tiles (with its alternative_id != 0)");
+ transpose = p_transpose;
+ emit_signal("changed");
+}
+bool TileData::get_transpose() const {
+ return transpose;
+}
+
+void TileData::set_texture_offset(Vector2i p_texture_offset) {
+ tex_offset = p_texture_offset;
+ emit_signal("changed");
+}
+
+Vector2i TileData::get_texture_offset() const {
+ return tex_offset;
+}
+
+void TileData::tile_set_material(Ref<ShaderMaterial> p_material) {
+ material = p_material;
+ emit_signal("changed");
+}
+Ref<ShaderMaterial> TileData::tile_get_material() const {
+ return material;
+}
+
+void TileData::set_modulate(Color p_modulate) {
+ modulate = p_modulate;
+ emit_signal("changed");
+}
+Color TileData::get_modulate() const {
+ return modulate;
+}
+
+void TileData::set_z_index(int p_z_index) {
+ z_index = p_z_index;
+ emit_signal("changed");
+}
+int TileData::get_z_index() const {
+ return z_index;
+}
+
+void TileData::set_y_sort_origin(int p_y_sort_origin) {
+ y_sort_origin = p_y_sort_origin;
+ emit_signal("changed");
+}
+int TileData::get_y_sort_origin() const {
+ return y_sort_origin;
+}
+
+void TileData::set_occluder(int p_layer_id, Ref<OccluderPolygon2D> p_occluder_polygon) {
+ ERR_FAIL_INDEX(p_layer_id, occluders.size());
+ occluders.write[p_layer_id] = p_occluder_polygon;
+ emit_signal("changed");
+}
+
+Ref<OccluderPolygon2D> TileData::get_occluder(int p_layer_id) const {
+ ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), Ref<OccluderPolygon2D>());
+ return occluders[p_layer_id];
+}
+
+// Physics
+int TileData::get_collision_shapes_count(int p_layer_id) const {
+ ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0);
+ return physics[p_layer_id].shapes.size();
+}
+
+void TileData::set_collision_shapes_count(int p_layer_id, int p_shapes_count) {
+ ERR_FAIL_INDEX(p_layer_id, physics.size());
+ ERR_FAIL_COND(p_shapes_count < 0);
+ physics.write[p_layer_id].shapes.resize(p_shapes_count);
+ notify_property_list_changed();
+ emit_signal("changed");
+}
+
+void TileData::add_collision_shape(int p_layer_id) {
+ ERR_FAIL_INDEX(p_layer_id, physics.size());
+ physics.write[p_layer_id].shapes.push_back(PhysicsLayerTileData::ShapeTileData());
+ emit_signal("changed");
+}
+
+void TileData::remove_collision_shape(int p_layer_id, int p_shape_index) {
+ ERR_FAIL_INDEX(p_layer_id, physics.size());
+ ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size());
+ physics.write[p_layer_id].shapes.remove(p_shape_index);
+ emit_signal("changed");
+}
+
+void TileData::set_collision_shape_shape(int p_layer_id, int p_shape_index, Ref<Shape2D> p_shape) {
+ ERR_FAIL_INDEX(p_layer_id, physics.size());
+ ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size());
+ physics.write[p_layer_id].shapes.write[p_shape_index].shape = p_shape;
+ emit_signal("changed");
+}
+
+Ref<Shape2D> TileData::get_collision_shape_shape(int p_layer_id, int p_shape_index) const {
+ ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Ref<Shape2D>());
+ ERR_FAIL_INDEX_V(p_shape_index, physics[p_layer_id].shapes.size(), Ref<Shape2D>());
+ return physics[p_layer_id].shapes[p_shape_index].shape;
+}
+
+void TileData::set_collision_shape_one_way(int p_layer_id, int p_shape_index, bool p_one_way) {
+ ERR_FAIL_INDEX(p_layer_id, physics.size());
+ ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size());
+ physics.write[p_layer_id].shapes.write[p_shape_index].one_way = p_one_way;
+ emit_signal("changed");
}
-const Map<Vector2, Ref<NavigationPolygon>> &TileSet::autotile_get_navigation_map(int p_id) const {
- 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;
+bool TileData::is_collision_shape_one_way(int p_layer_id, int p_shape_index) const {
+ ERR_FAIL_INDEX_V(p_layer_id, physics.size(), false);
+ ERR_FAIL_INDEX_V(p_shape_index, physics[p_layer_id].shapes.size(), false);
+ return physics[p_layer_id].shapes[p_shape_index].one_way;
}
-void TileSet::tile_set_occluder_offset(int p_id, const Vector2 &p_offset) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].occluder_offset = p_offset;
+void TileData::set_collision_shape_one_way_margin(int p_layer_id, int p_shape_index, float p_one_way_margin) {
+ ERR_FAIL_INDEX(p_layer_id, physics.size());
+ ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size());
+ physics.write[p_layer_id].shapes.write[p_shape_index].one_way_margin = p_one_way_margin;
+ emit_signal("changed");
}
-Vector2 TileSet::tile_get_occluder_offset(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2());
- return tile_map[p_id].occluder_offset;
+float TileData::get_collision_shape_one_way_margin(int p_layer_id, int p_shape_index) const {
+ ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0.0);
+ ERR_FAIL_INDEX_V(p_shape_index, physics[p_layer_id].shapes.size(), 0.0);
+ return physics[p_layer_id].shapes[p_shape_index].one_way_margin;
}
-void TileSet::tile_set_shapes(int p_id, const Vector<ShapeData> &p_shapes) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].shapes_data = p_shapes;
- for (int i = 0; i < p_shapes.size(); i++) {
- _decompose_convex_shape(p_shapes[i].shape);
+// Terrain
+void TileData::set_terrain_set(int p_terrain_set) {
+ ERR_FAIL_COND(p_terrain_set < -1);
+ if (tile_set) {
+ ERR_FAIL_COND(p_terrain_set >= tile_set->get_terrain_sets_count());
}
- emit_changed();
+ terrain_set = p_terrain_set;
+ notify_property_list_changed();
+ emit_signal("changed");
}
-Vector<TileSet::ShapeData> TileSet::tile_get_shapes(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Vector<ShapeData>());
+int TileData::get_terrain_set() const {
+ return terrain_set;
+}
- return tile_map[p_id].shapes_data;
+void TileData::set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
+ ERR_FAIL_INDEX(p_peering_bit, TileSet::CELL_NEIGHBOR_MAX);
+ ERR_FAIL_COND(p_terrain_index < -1);
+ if (tile_set) {
+ ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set));
+ ERR_FAIL_COND(!is_valid_peering_bit_terrain(p_peering_bit));
+ }
+ terrain_peering_bits[p_peering_bit] = p_terrain_index;
+ emit_signal("changed");
}
-int TileSet::tile_get_z_index(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), 0);
- return tile_map[p_id].z_index;
+int TileData::get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const {
+ ERR_FAIL_INDEX_V(p_peering_bit, TileSet::CELL_NEIGHBOR_MAX, -1);
+ return terrain_peering_bits[p_peering_bit];
}
-void TileSet::tile_set_z_index(int p_id, int p_z_index) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].z_index = p_z_index;
- emit_changed();
+bool TileData::is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const {
+ ERR_FAIL_COND_V(!tile_set, false);
+
+ return tile_set->is_valid_peering_bit_terrain(terrain_set, p_peering_bit);
}
-void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- Vector<ShapeData> shapes_data;
- Transform2D default_transform = tile_get_shape_transform(p_id, 0);
- bool default_one_way = tile_get_shape_one_way(p_id, 0);
- Vector2 default_autotile_coord = Vector2();
- for (int i = 0; i < p_shapes.size(); i++) {
- ShapeData s = ShapeData();
+// Navigation
+void TileData::set_navigation_polygon(int p_layer_id, Ref<NavigationPolygon> p_navigation_polygon) {
+ ERR_FAIL_INDEX(p_layer_id, navigation.size());
+ navigation.write[p_layer_id] = p_navigation_polygon;
+ emit_signal("changed");
+}
- if (p_shapes[i].get_type() == Variant::OBJECT) {
- Ref<Shape2D> shape = p_shapes[i];
- if (shape.is_null()) {
- continue;
+Ref<NavigationPolygon> TileData::get_navigation_polygon(int p_layer_id) const {
+ ERR_FAIL_INDEX_V(p_layer_id, navigation.size(), Ref<NavigationPolygon>());
+ return navigation[p_layer_id];
+}
+
+// Misc
+void TileData::set_probability(float p_probability) {
+ ERR_FAIL_COND(p_probability <= 0.0);
+ probability = p_probability;
+ emit_signal("changed");
+}
+float TileData::get_probability() const {
+ return probability;
+}
+
+// Custom data
+void TileData::set_custom_data(String p_layer_name, Variant p_value) {
+ ERR_FAIL_COND(!tile_set);
+ int p_layer_id = tile_set->get_custom_data_layer_by_name(p_layer_name);
+ ERR_FAIL_COND_MSG(p_layer_id < 0, vformat("TileSet has no layer with name: %s", p_layer_name));
+ set_custom_data_by_layer_id(p_layer_id, p_value);
+}
+
+Variant TileData::get_custom_data(String p_layer_name) const {
+ ERR_FAIL_COND_V(!tile_set, Variant());
+ int p_layer_id = tile_set->get_custom_data_layer_by_name(p_layer_name);
+ ERR_FAIL_COND_V_MSG(p_layer_id < 0, Variant(), vformat("TileSet has no layer with name: %s", p_layer_name));
+ return get_custom_data_by_layer_id(p_layer_id);
+}
+
+void TileData::set_custom_data_by_layer_id(int p_layer_id, Variant p_value) {
+ ERR_FAIL_INDEX(p_layer_id, custom_data.size());
+ custom_data.write[p_layer_id] = p_value;
+ emit_signal("changed");
+}
+
+Variant TileData::get_custom_data_by_layer_id(int p_layer_id) const {
+ ERR_FAIL_INDEX_V(p_layer_id, custom_data.size(), Variant());
+ return custom_data[p_layer_id];
+}
+
+bool TileData::_set(const StringName &p_name, const Variant &p_value) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+
+ if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) {
+ // Occlusion layers.
+ int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+ if (components[1] == "polygon") {
+ Ref<OccluderPolygon2D> polygon = p_value;
+ if (!polygon.is_valid()) {
+ return false;
}
- s.shape = shape;
- s.shape_transform = default_transform;
- s.one_way_collision = default_one_way;
- s.autotile_coord = default_autotile_coord;
- } else if (p_shapes[i].get_type() == Variant::DICTIONARY) {
- Dictionary d = p_shapes[i];
+ if (layer_index >= occluders.size()) {
+ if (tile_set) {
+ return false;
+ } else {
+ occluders.resize(layer_index + 1);
+ }
+ }
+ set_occluder(layer_index, polygon);
+ return true;
+ }
+ } else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) {
+ // Physics layers.
+ int layer_index = components[0].trim_prefix("physics_layer_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+ if (components.size() == 2 && components[1] == "shapes_count") {
+ if (p_value.get_type() != Variant::INT) {
+ return false;
+ }
- if (d.has("shape") && d["shape"].get_type() == Variant::OBJECT) {
- s.shape = d["shape"];
- _decompose_convex_shape(s.shape);
- } else {
- continue;
+ if (layer_index >= physics.size()) {
+ if (tile_set) {
+ return false;
+ } else {
+ physics.resize(layer_index + 1);
+ }
}
+ set_collision_shapes_count(layer_index, p_value);
+ return true;
+ } else if (components.size() == 3 && components[1].begins_with("shape_") && components[1].trim_prefix("shape_").is_valid_integer()) {
+ int shape_index = components[1].trim_prefix("shape_").to_int();
+ ERR_FAIL_COND_V(shape_index < 0, false);
+
+ if (components[2] == "shape" || components[2] == "one_way" || components[2] == "one_way_margin") {
+ if (layer_index >= physics.size()) {
+ if (tile_set) {
+ return false;
+ } else {
+ physics.resize(layer_index + 1);
+ }
+ }
- if (d.has("shape_transform") && d["shape_transform"].get_type() == Variant::TRANSFORM2D) {
- s.shape_transform = d["shape_transform"];
- } else if (d.has("shape_offset") && d["shape_offset"].get_type() == Variant::VECTOR2) {
- s.shape_transform = Transform2D(0, (Vector2)d["shape_offset"]);
- } else {
- s.shape_transform = default_transform;
+ if (shape_index >= physics[layer_index].shapes.size()) {
+ physics.write[layer_index].shapes.resize(shape_index + 1);
+ }
+ }
+ if (components[2] == "shape") {
+ Ref<Shape2D> shape = p_value;
+ set_collision_shape_shape(layer_index, shape_index, shape);
+ return true;
+ } else if (components[2] == "one_way") {
+ set_collision_shape_one_way(layer_index, shape_index, p_value);
+ return true;
+ } else if (components[2] == "one_way_margin") {
+ set_collision_shape_one_way_margin(layer_index, shape_index, p_value);
+ return true;
+ }
+ }
+ } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) {
+ // Navigation layers.
+ int layer_index = components[0].trim_prefix("navigation_layer_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+ if (components[1] == "polygon") {
+ Ref<NavigationPolygon> polygon = p_value;
+ if (!polygon.is_valid()) {
+ return false;
}
- if (d.has("one_way") && d["one_way"].get_type() == Variant::BOOL) {
- s.one_way_collision = d["one_way"];
+ if (layer_index >= navigation.size()) {
+ if (tile_set) {
+ return false;
+ } else {
+ navigation.resize(layer_index + 1);
+ }
+ }
+ set_navigation_polygon(layer_index, polygon);
+ return true;
+ }
+ } else if (components.size() == 2 && components[0] == "terrains_peering_bit") {
+ // Terrains.
+ if (components[1] == "right_side") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, p_value);
+ } else if (components[1] == "right_corner") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER, p_value);
+ } else if (components[1] == "bottom_right_side") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, p_value);
+ } else if (components[1] == "bottom_right_corner") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, p_value);
+ } else if (components[1] == "bottom_side") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, p_value);
+ } else if (components[1] == "bottom_corner") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER, p_value);
+ } else if (components[1] == "bottom_left_side") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, p_value);
+ } else if (components[1] == "bottom_left_corner") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, p_value);
+ } else if (components[1] == "left_side") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE, p_value);
+ } else if (components[1] == "left_corner") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER, p_value);
+ } else if (components[1] == "top_left_side") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, p_value);
+ } else if (components[1] == "top_left_corner") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, p_value);
+ } else if (components[1] == "top_side") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE, p_value);
+ } else if (components[1] == "top_corner") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER, p_value);
+ } else if (components[1] == "top_right_side") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, p_value);
+ } else if (components[1] == "top_right_corner") {
+ set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, p_value);
+ } else {
+ return false;
+ }
+ return true;
+ } else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_integer()) {
+ // Custom data layers.
+ int layer_index = components[0].trim_prefix("custom_data_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+
+ if (layer_index >= custom_data.size()) {
+ if (tile_set) {
+ return false;
} else {
- s.one_way_collision = default_one_way;
+ custom_data.resize(layer_index + 1);
}
+ }
+ set_custom_data_by_layer_id(layer_index, p_value);
- if (d.has("one_way_margin") && d["one_way_margin"].is_num()) {
- s.one_way_collision_margin = d["one_way_margin"];
+ return true;
+ }
+
+ return false;
+}
+
+bool TileData::_get(const StringName &p_name, Variant &r_ret) const {
+ Vector<String> components = String(p_name).split("/", true, 2);
+
+ if (tile_set) {
+ if (components.size() == 2 && components[0].begins_with("occlusion_layer") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) {
+ // Occlusion layers.
+ int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+ if (layer_index >= occluders.size()) {
+ return false;
+ }
+ if (components[1] == "polygon") {
+ r_ret = get_occluder(layer_index);
+ return true;
+ }
+ } else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) {
+ // Physics layers.
+ int layer_index = components[0].trim_prefix("physics_layer_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+ if (layer_index >= physics.size()) {
+ return false;
+ }
+ if (components.size() == 2 && components[1] == "shapes_count") {
+ r_ret = get_collision_shapes_count(layer_index);
+ return true;
+ } else if (components.size() == 3 && components[1].begins_with("shape_") && components[1].trim_prefix("shape_").is_valid_integer()) {
+ int shape_index = components[1].trim_prefix("shape_").to_int();
+ ERR_FAIL_COND_V(shape_index < 0, false);
+ if (shape_index >= physics[layer_index].shapes.size()) {
+ return false;
+ }
+ if (components[2] == "shape") {
+ r_ret = get_collision_shape_shape(layer_index, shape_index);
+ return true;
+ } else if (components[2] == "one_way") {
+ r_ret = is_collision_shape_one_way(layer_index, shape_index);
+ return true;
+ } else if (components[2] == "one_way_margin") {
+ r_ret = get_collision_shape_one_way_margin(layer_index, shape_index);
+ return true;
+ }
+ }
+ } else if (components.size() == 2 && components[0] == "terrains_peering_bit") {
+ // Terrains.
+ if (components[1] == "right_side") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_RIGHT_SIDE];
+ } else if (components[1] == "right_corner") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_RIGHT_CORNER];
+ } else if (components[1] == "bottom_right_side") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE];
+ } else if (components[1] == "bottom_right_corner") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER];
+ } else if (components[1] == "bottom_side") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_SIDE];
+ } else if (components[1] == "bottom_corner") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_CORNER];
+ } else if (components[1] == "bottom_left_side") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE];
+ } else if (components[1] == "bottom_left_corner") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER];
+ } else if (components[1] == "left_side") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_LEFT_SIDE];
+ } else if (components[1] == "left_corner") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_LEFT_CORNER];
+ } else if (components[1] == "top_left_side") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE];
+ } else if (components[1] == "top_left_corner") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER];
+ } else if (components[1] == "top_side") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_SIDE];
+ } else if (components[1] == "top_corner") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_CORNER];
+ } else if (components[1] == "top_right_side") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE];
+ } else if (components[1] == "top_right_corner") {
+ r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER];
} else {
- s.one_way_collision_margin = 1.0;
+ return false;
+ }
+ return true;
+ } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) {
+ // Occlusion layers.
+ int layer_index = components[0].trim_prefix("navigation_layer_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+ if (layer_index >= navigation.size()) {
+ return false;
+ }
+ if (components[1] == "polygon") {
+ r_ret = get_navigation_polygon(layer_index);
+ return true;
+ }
+ } else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_integer()) {
+ // Custom data layers.
+ int layer_index = components[0].trim_prefix("custom_data_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+ if (layer_index >= custom_data.size()) {
+ return false;
}
+ r_ret = get_custom_data_by_layer_id(layer_index);
+ return true;
+ }
+ }
- if (d.has("autotile_coord") && d["autotile_coord"].get_type() == Variant::VECTOR2) {
- s.autotile_coord = d["autotile_coord"];
- } else {
- s.autotile_coord = default_autotile_coord;
+ return false;
+}
+
+void TileData::_get_property_list(List<PropertyInfo> *p_list) const {
+ PropertyInfo property_info;
+ // Add the groups manually.
+ if (tile_set) {
+ // Occlusion layers.
+ p_list->push_back(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+ for (int i = 0; i < occluders.size(); i++) {
+ // occlusion_layer_%d/polygon
+ property_info = PropertyInfo(Variant::OBJECT, vformat("occlusion_layer_%d/polygon", i), PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D", PROPERTY_USAGE_DEFAULT);
+ if (!occluders[i].is_valid()) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
+ p_list->push_back(property_info);
+ }
- } else {
- ERR_CONTINUE_MSG(true, "Expected an array of objects or dictionaries for tile_set_shapes.");
+ // Physics layers.
+ p_list->push_back(PropertyInfo(Variant::NIL, "Physics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+ for (int i = 0; i < physics.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("physics_layer_%d/shapes_count", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+
+ for (int j = 0; j < physics[i].shapes.size(); j++) {
+ // physics_layer_%d/shapes_count
+ property_info = PropertyInfo(Variant::OBJECT, vformat("physics_layer_%d/shape_%d/shape", i, j), PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_DEFAULT);
+ if (!physics[i].shapes[j].shape.is_valid()) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+
+ // physics_layer_%d/shape_%d/one_way
+ property_info = PropertyInfo(Variant::BOOL, vformat("physics_layer_%d/shape_%d/one_way", i, j));
+ if (physics[i].shapes[j].one_way == false) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+
+ // physics_layer_%d/shape_%d/one_way_margin
+ property_info = PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/shape_%d/one_way_margin", i, j));
+ if (physics[i].shapes[j].one_way_margin == 1.0) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ }
+
+ // Terrain data
+ if (terrain_set >= 0) {
+ p_list->push_back(PropertyInfo(Variant::NIL, "Terrains", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/right_side");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/right_corner");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_right_side");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_right_corner");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_side");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_corner");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_left_side");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_left_corner");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/left_side");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/left_corner");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_left_side");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_left_corner");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_side");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_corner");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_right_side");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+ if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER)) {
+ property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_right_corner");
+ if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) == -1) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
}
- shapes_data.push_back(s);
+ // Navigation layers.
+ p_list->push_back(PropertyInfo(Variant::NIL, "Navigation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+ for (int i = 0; i < navigation.size(); i++) {
+ property_info = PropertyInfo(Variant::OBJECT, vformat("navigation_layer_%d/polygon", i), PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon", PROPERTY_USAGE_DEFAULT);
+ if (!navigation[i].is_valid()) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
+
+ // Custom data layers.
+ p_list->push_back(PropertyInfo(Variant::NIL, "Custom data", PROPERTY_HINT_NONE, "custom_data_", PROPERTY_USAGE_GROUP));
+ for (int i = 0; i < custom_data.size(); i++) {
+ Variant default_val;
+ Callable::CallError error;
+ Variant::construct(custom_data[i].get_type(), default_val, nullptr, 0, error);
+ property_info = PropertyInfo(tile_set->get_custom_data_type(i), vformat("custom_data_%d", i), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
+ if (custom_data[i] == default_val) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ p_list->push_back(property_info);
+ }
}
+}
- tile_map[p_id].shapes_data = shapes_data;
- emit_changed();
+void TileData::_bind_methods() {
+ // Rendering.
+ ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &TileData::set_flip_h);
+ ClassDB::bind_method(D_METHOD("get_flip_h"), &TileData::get_flip_h);
+ ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &TileData::set_flip_v);
+ ClassDB::bind_method(D_METHOD("get_flip_v"), &TileData::get_flip_v);
+ ClassDB::bind_method(D_METHOD("set_transpose", "transpose"), &TileData::set_transpose);
+ ClassDB::bind_method(D_METHOD("get_transpose"), &TileData::get_transpose);
+ ClassDB::bind_method(D_METHOD("tile_set_material", "material"), &TileData::tile_set_material);
+ ClassDB::bind_method(D_METHOD("tile_get_material"), &TileData::tile_get_material);
+ ClassDB::bind_method(D_METHOD("set_texture_offset", "texture_offset"), &TileData::set_texture_offset);
+ ClassDB::bind_method(D_METHOD("get_texture_offset"), &TileData::get_texture_offset);
+ ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &TileData::set_modulate);
+ ClassDB::bind_method(D_METHOD("get_modulate"), &TileData::get_modulate);
+ ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &TileData::set_z_index);
+ ClassDB::bind_method(D_METHOD("get_z_index"), &TileData::get_z_index);
+ ClassDB::bind_method(D_METHOD("set_y_sort_origin", "y_sort_origin"), &TileData::set_y_sort_origin);
+ ClassDB::bind_method(D_METHOD("get_y_sort_origin"), &TileData::get_y_sort_origin);
+
+ ClassDB::bind_method(D_METHOD("set_occluder", "layer_id", "occluder_polygon"), &TileData::set_occluder);
+ ClassDB::bind_method(D_METHOD("get_occluder", "layer_id"), &TileData::get_occluder);
+
+ // Physics.
+ ClassDB::bind_method(D_METHOD("get_collision_shapes_count", "layer_id"), &TileData::get_collision_shapes_count);
+ ClassDB::bind_method(D_METHOD("set_collision_shapes_count", "layer_id", "shapes_count"), &TileData::set_collision_shapes_count);
+ ClassDB::bind_method(D_METHOD("add_collision_shape", "layer_id"), &TileData::add_collision_shape);
+ ClassDB::bind_method(D_METHOD("remove_collision_shape", "layer_id", "shape_index"), &TileData::remove_collision_shape);
+ ClassDB::bind_method(D_METHOD("set_collision_shape_shape", "layer_id", "shape_index", "shape"), &TileData::set_collision_shape_shape);
+ ClassDB::bind_method(D_METHOD("get_collision_shape_shape", "layer_id", "shape_index"), &TileData::get_collision_shape_shape);
+ ClassDB::bind_method(D_METHOD("set_collision_shape_one_way", "layer_id", "shape_index", "one_way"), &TileData::set_collision_shape_one_way);
+ ClassDB::bind_method(D_METHOD("is_collision_shape_one_way", "layer_id", "shape_index"), &TileData::is_collision_shape_one_way);
+ ClassDB::bind_method(D_METHOD("set_collision_shape_one_way_margin", "layer_id", "shape_index", "one_way_margin"), &TileData::set_collision_shape_one_way_margin);
+ ClassDB::bind_method(D_METHOD("get_collision_shape_one_way_margin", "layer_id", "shape_index"), &TileData::get_collision_shape_one_way_margin);
+
+ // Terrain
+ ClassDB::bind_method(D_METHOD("set_terrain_set", "terrain_set"), &TileData::set_terrain_set);
+ ClassDB::bind_method(D_METHOD("get_terrain_set"), &TileData::get_terrain_set);
+ ClassDB::bind_method(D_METHOD("set_peering_bit_terrain", "peering_bit", "terrain"), &TileData::set_peering_bit_terrain);
+ ClassDB::bind_method(D_METHOD("get_peering_bit_terrain", "peering_bit"), &TileData::get_peering_bit_terrain);
+
+ // Navigation
+ ClassDB::bind_method(D_METHOD("set_navigation_polygon", "layer_id", "navigation_polygon"), &TileData::set_navigation_polygon);
+ ClassDB::bind_method(D_METHOD("get_navigation_polygon", "layer_id"), &TileData::get_navigation_polygon);
+
+ // Misc.
+ ClassDB::bind_method(D_METHOD("set_probability", "probability"), &TileData::set_probability);
+ ClassDB::bind_method(D_METHOD("get_probability"), &TileData::get_probability);
+
+ // Custom data.
+ ClassDB::bind_method(D_METHOD("set_custom_data", "layer_name", "value"), &TileData::set_custom_data);
+ ClassDB::bind_method(D_METHOD("get_custom_data", "layer_name"), &TileData::get_custom_data);
+ ClassDB::bind_method(D_METHOD("set_custom_data_by_layer_id", "layer_id", "value"), &TileData::set_custom_data_by_layer_id);
+ ClassDB::bind_method(D_METHOD("get_custom_data_by_layer_id", "layer_id"), &TileData::get_custom_data_by_layer_id);
+
+ ADD_GROUP("Rendering", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "get_flip_h");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "get_flip_v");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transpose"), "set_transpose", "get_transpose");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_offset"), "set_texture_offset", "get_texture_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index"), "set_z_index", "get_z_index");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "y_sort_origin"), "set_y_sort_origin", "get_y_sort_origin");
+
+ ADD_GROUP("Terrains", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain_set"), "set_terrain_set", "get_terrain_set");
+
+ ADD_GROUP("Miscellaneous", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "probability"), "set_probability", "get_probability");
+
+ ADD_SIGNAL(MethodInfo("changed"));
}
-Array TileSet::_tile_get_shapes(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), Array());
- Array arr;
+/////////////////////////////// TileSetPluginAtlasTerrain //////////////////////////////////////
+
+// --- PLUGINS ---
+void TileSetPluginAtlasTerrain::_draw_square_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) {
+ Rect2 bit_rect;
+ bit_rect.size = Vector2(p_size) / 3;
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
+ bit_rect.position = Vector2(1, -1);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ bit_rect.position = Vector2(1, 1);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
+ bit_rect.position = Vector2(-1, 1);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ bit_rect.position = Vector2(-3, 1);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
+ bit_rect.position = Vector2(-3, -1);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ bit_rect.position = Vector2(-3, -3);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_SIDE:
+ bit_rect.position = Vector2(-1, -3);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ bit_rect.position = Vector2(1, -3);
+ break;
+ default:
+ break;
+ }
+ bit_rect.position *= Vector2(p_size) / 6.0;
+ p_canvas_item->draw_rect(bit_rect, p_color);
+}
- Vector<ShapeData> data = tile_map[p_id].shapes_data;
- for (int i = 0; i < data.size(); i++) {
- Dictionary shape_data;
- shape_data["shape"] = data[i].shape;
- shape_data["shape_transform"] = data[i].shape_transform;
- shape_data["one_way"] = data[i].one_way_collision;
- shape_data["one_way_margin"] = data[i].one_way_collision_margin;
- shape_data["autotile_coord"] = data[i].autotile_coord;
- arr.push_back(shape_data);
+void TileSetPluginAtlasTerrain::_draw_square_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) {
+ PackedColorArray color_array;
+ color_array.push_back(p_color);
+
+ Vector2 unit = Vector2(p_size) / 6.0;
+ PackedVector2Array polygon;
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ polygon.push_back(Vector2(0, 3) * unit);
+ polygon.push_back(Vector2(3, 3) * unit);
+ polygon.push_back(Vector2(3, 0) * unit);
+ polygon.push_back(Vector2(1, 0) * unit);
+ polygon.push_back(Vector2(1, 1) * unit);
+ polygon.push_back(Vector2(0, 1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ polygon.push_back(Vector2(0, 3) * unit);
+ polygon.push_back(Vector2(-3, 3) * unit);
+ polygon.push_back(Vector2(-3, 0) * unit);
+ polygon.push_back(Vector2(-1, 0) * unit);
+ polygon.push_back(Vector2(-1, 1) * unit);
+ polygon.push_back(Vector2(0, 1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ polygon.push_back(Vector2(0, -3) * unit);
+ polygon.push_back(Vector2(-3, -3) * unit);
+ polygon.push_back(Vector2(-3, 0) * unit);
+ polygon.push_back(Vector2(-1, 0) * unit);
+ polygon.push_back(Vector2(-1, -1) * unit);
+ polygon.push_back(Vector2(0, -1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ polygon.push_back(Vector2(0, -3) * unit);
+ polygon.push_back(Vector2(3, -3) * unit);
+ polygon.push_back(Vector2(3, 0) * unit);
+ polygon.push_back(Vector2(1, 0) * unit);
+ polygon.push_back(Vector2(1, -1) * unit);
+ polygon.push_back(Vector2(0, -1) * unit);
+ break;
+ default:
+ break;
}
+ if (!polygon.is_empty()) {
+ p_canvas_item->draw_polygon(polygon, color_array);
+ }
+}
- return arr;
+void TileSetPluginAtlasTerrain::_draw_square_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) {
+ PackedColorArray color_array;
+ color_array.push_back(p_color);
+
+ Vector2 unit = Vector2(p_size) / 6.0;
+ PackedVector2Array polygon;
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
+ polygon.push_back(Vector2(1, -1) * unit);
+ polygon.push_back(Vector2(3, -3) * unit);
+ polygon.push_back(Vector2(3, 3) * unit);
+ polygon.push_back(Vector2(1, 1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
+ polygon.push_back(Vector2(-1, 1) * unit);
+ polygon.push_back(Vector2(-3, 3) * unit);
+ polygon.push_back(Vector2(3, 3) * unit);
+ polygon.push_back(Vector2(1, 1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
+ polygon.push_back(Vector2(-1, -1) * unit);
+ polygon.push_back(Vector2(-3, -3) * unit);
+ polygon.push_back(Vector2(-3, 3) * unit);
+ polygon.push_back(Vector2(-1, 1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_SIDE:
+ polygon.push_back(Vector2(-1, -1) * unit);
+ polygon.push_back(Vector2(-3, -3) * unit);
+ polygon.push_back(Vector2(3, -3) * unit);
+ polygon.push_back(Vector2(1, -1) * unit);
+ break;
+ default:
+ break;
+ }
+ if (!polygon.is_empty()) {
+ p_canvas_item->draw_polygon(polygon, color_array);
+ }
}
-Array TileSet::_get_tiles_ids() const {
- Array arr;
+void TileSetPluginAtlasTerrain::_draw_isometric_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) {
+ PackedColorArray color_array;
+ color_array.push_back(p_color);
+
+ Vector2 unit = Vector2(p_size) / 6.0;
+ PackedVector2Array polygon;
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
+ polygon.push_back(Vector2(1, 0) * unit);
+ polygon.push_back(Vector2(2, -1) * unit);
+ polygon.push_back(Vector2(3, 0) * unit);
+ polygon.push_back(Vector2(2, 1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ polygon.push_back(Vector2(0, 1) * unit);
+ polygon.push_back(Vector2(1, 2) * unit);
+ polygon.push_back(Vector2(2, 1) * unit);
+ polygon.push_back(Vector2(1, 0) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
+ polygon.push_back(Vector2(0, 1) * unit);
+ polygon.push_back(Vector2(-1, 2) * unit);
+ polygon.push_back(Vector2(0, 3) * unit);
+ polygon.push_back(Vector2(1, 2) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ polygon.push_back(Vector2(0, 1) * unit);
+ polygon.push_back(Vector2(-1, 2) * unit);
+ polygon.push_back(Vector2(-2, 1) * unit);
+ polygon.push_back(Vector2(-1, 0) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
+ polygon.push_back(Vector2(-1, 0) * unit);
+ polygon.push_back(Vector2(-2, -1) * unit);
+ polygon.push_back(Vector2(-3, 0) * unit);
+ polygon.push_back(Vector2(-2, 1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ polygon.push_back(Vector2(0, -1) * unit);
+ polygon.push_back(Vector2(-1, -2) * unit);
+ polygon.push_back(Vector2(-2, -1) * unit);
+ polygon.push_back(Vector2(-1, 0) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_CORNER:
+ polygon.push_back(Vector2(0, -1) * unit);
+ polygon.push_back(Vector2(-1, -2) * unit);
+ polygon.push_back(Vector2(0, -3) * unit);
+ polygon.push_back(Vector2(1, -2) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ polygon.push_back(Vector2(0, -1) * unit);
+ polygon.push_back(Vector2(1, -2) * unit);
+ polygon.push_back(Vector2(2, -1) * unit);
+ polygon.push_back(Vector2(1, 0) * unit);
+ break;
+ default:
+ break;
+ }
+ if (!polygon.is_empty()) {
+ p_canvas_item->draw_polygon(polygon, color_array);
+ }
+}
- for (Map<int, TileData>::Element *E = tile_map.front(); E; E = E->next()) {
- arr.push_back(E->key());
+void TileSetPluginAtlasTerrain::_draw_isometric_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) {
+ PackedColorArray color_array;
+ color_array.push_back(p_color);
+
+ Vector2 unit = Vector2(p_size) / 6.0;
+ PackedVector2Array polygon;
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
+ polygon.push_back(Vector2(0.5, -0.5) * unit);
+ polygon.push_back(Vector2(1.5, -1.5) * unit);
+ polygon.push_back(Vector2(3, 0) * unit);
+ polygon.push_back(Vector2(1.5, 1.5) * unit);
+ polygon.push_back(Vector2(0.5, 0.5) * unit);
+ polygon.push_back(Vector2(1, 0) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
+ polygon.push_back(Vector2(-0.5, 0.5) * unit);
+ polygon.push_back(Vector2(-1.5, 1.5) * unit);
+ polygon.push_back(Vector2(0, 3) * unit);
+ polygon.push_back(Vector2(1.5, 1.5) * unit);
+ polygon.push_back(Vector2(0.5, 0.5) * unit);
+ polygon.push_back(Vector2(0, 1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
+ polygon.push_back(Vector2(-0.5, -0.5) * unit);
+ polygon.push_back(Vector2(-1.5, -1.5) * unit);
+ polygon.push_back(Vector2(-3, 0) * unit);
+ polygon.push_back(Vector2(-1.5, 1.5) * unit);
+ polygon.push_back(Vector2(-0.5, 0.5) * unit);
+ polygon.push_back(Vector2(-1, 0) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_CORNER:
+ polygon.push_back(Vector2(-0.5, -0.5) * unit);
+ polygon.push_back(Vector2(-1.5, -1.5) * unit);
+ polygon.push_back(Vector2(0, -3) * unit);
+ polygon.push_back(Vector2(1.5, -1.5) * unit);
+ polygon.push_back(Vector2(0.5, -0.5) * unit);
+ polygon.push_back(Vector2(0, -1) * unit);
+ break;
+ default:
+ break;
+ }
+ if (!polygon.is_empty()) {
+ p_canvas_item->draw_polygon(polygon, color_array);
}
+}
- return arr;
+void TileSetPluginAtlasTerrain::_draw_isometric_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) {
+ PackedColorArray color_array;
+ color_array.push_back(p_color);
+
+ Vector2 unit = Vector2(p_size) / 6.0;
+ PackedVector2Array polygon;
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ polygon.push_back(Vector2(1, 0) * unit);
+ polygon.push_back(Vector2(3, 0) * unit);
+ polygon.push_back(Vector2(0, 3) * unit);
+ polygon.push_back(Vector2(0, 1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ polygon.push_back(Vector2(-1, 0) * unit);
+ polygon.push_back(Vector2(-3, 0) * unit);
+ polygon.push_back(Vector2(0, 3) * unit);
+ polygon.push_back(Vector2(0, 1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ polygon.push_back(Vector2(-1, 0) * unit);
+ polygon.push_back(Vector2(-3, 0) * unit);
+ polygon.push_back(Vector2(0, -3) * unit);
+ polygon.push_back(Vector2(0, -1) * unit);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ polygon.push_back(Vector2(1, 0) * unit);
+ polygon.push_back(Vector2(3, 0) * unit);
+ polygon.push_back(Vector2(0, -3) * unit);
+ polygon.push_back(Vector2(0, -1) * unit);
+ break;
+ default:
+ break;
+ }
+ if (!polygon.is_empty()) {
+ p_canvas_item->draw_polygon(polygon, color_array);
+ }
}
-void TileSet::_decompose_convex_shape(Ref<Shape2D> p_shape) {
- if (Engine::get_singleton()->is_editor_hint()) {
- return;
+void TileSetPluginAtlasTerrain::_draw_half_offset_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+ PackedColorArray color_array;
+ color_array.push_back(p_color);
+
+ PackedVector2Array point_list;
+ point_list.push_back(Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0));
+ point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)));
+ point_list.push_back(Vector2(1, 3.0 - p_overlap * 2.0));
+ point_list.push_back(Vector2(0, 3));
+ point_list.push_back(Vector2(-1, 3.0 - p_overlap * 2.0));
+ point_list.push_back(Vector2(-2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)));
+ point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(-3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0));
+ point_list.push_back(Vector2(-3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0));
+ point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(-2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)));
+ point_list.push_back(Vector2(-1, -(3.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(0, -3));
+ point_list.push_back(Vector2(1, -(3.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)));
+ point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0));
+
+ Vector2 unit = Vector2(p_size) / 6.0;
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
+
+ PackedVector2Array polygon;
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
+ polygon.push_back(point_list[17]);
+ polygon.push_back(point_list[0]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ polygon.push_back(point_list[0]);
+ polygon.push_back(point_list[1]);
+ polygon.push_back(point_list[2]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ polygon.push_back(point_list[2]);
+ polygon.push_back(point_list[3]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
+ polygon.push_back(point_list[3]);
+ polygon.push_back(point_list[4]);
+ polygon.push_back(point_list[5]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ polygon.push_back(point_list[5]);
+ polygon.push_back(point_list[6]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ polygon.push_back(point_list[6]);
+ polygon.push_back(point_list[7]);
+ polygon.push_back(point_list[8]);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
+ polygon.push_back(point_list[8]);
+ polygon.push_back(point_list[9]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ polygon.push_back(point_list[9]);
+ polygon.push_back(point_list[10]);
+ polygon.push_back(point_list[11]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ polygon.push_back(point_list[11]);
+ polygon.push_back(point_list[12]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_CORNER:
+ polygon.push_back(point_list[12]);
+ polygon.push_back(point_list[13]);
+ polygon.push_back(point_list[14]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ polygon.push_back(point_list[14]);
+ polygon.push_back(point_list[15]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ polygon.push_back(point_list[15]);
+ polygon.push_back(point_list[16]);
+ polygon.push_back(point_list[17]);
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
+ }
+ }
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
+ polygon.push_back(point_list[3]);
+ polygon.push_back(point_list[4]);
+ polygon.push_back(point_list[5]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ polygon.push_back(point_list[2]);
+ polygon.push_back(point_list[3]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ polygon.push_back(point_list[0]);
+ polygon.push_back(point_list[1]);
+ polygon.push_back(point_list[2]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
+ polygon.push_back(point_list[17]);
+ polygon.push_back(point_list[0]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ polygon.push_back(point_list[15]);
+ polygon.push_back(point_list[16]);
+ polygon.push_back(point_list[17]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ polygon.push_back(point_list[14]);
+ polygon.push_back(point_list[15]);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
+ polygon.push_back(point_list[12]);
+ polygon.push_back(point_list[13]);
+ polygon.push_back(point_list[14]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ polygon.push_back(point_list[11]);
+ polygon.push_back(point_list[12]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ polygon.push_back(point_list[9]);
+ polygon.push_back(point_list[10]);
+ polygon.push_back(point_list[11]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_SIDE:
+ polygon.push_back(point_list[8]);
+ polygon.push_back(point_list[9]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ polygon.push_back(point_list[6]);
+ polygon.push_back(point_list[7]);
+ polygon.push_back(point_list[8]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ polygon.push_back(point_list[5]);
+ polygon.push_back(point_list[6]);
+ break;
+ default:
+ break;
+ }
+ }
+
+ int half_polygon_size = polygon.size();
+ for (int i = 0; i < half_polygon_size; i++) {
+ polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0);
+ }
+
+ if (!polygon.is_empty()) {
+ p_canvas_item->draw_polygon(polygon, color_array);
+ }
+}
+
+void TileSetPluginAtlasTerrain::_draw_half_offset_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+ PackedColorArray color_array;
+ color_array.push_back(p_color);
+
+ PackedVector2Array point_list;
+ point_list.push_back(Vector2(3, 0));
+ point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0));
+ point_list.push_back(Vector2(0, 3));
+ point_list.push_back(Vector2(-1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0));
+ point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(-3, 0));
+ point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(-1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0));
+ point_list.push_back(Vector2(0, -3));
+ point_list.push_back(Vector2(1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0));
+ point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0)));
+
+ Vector2 unit = Vector2(p_size) / 6.0;
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
+
+ PackedVector2Array polygon;
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ polygon.push_back(point_list[0]);
+ polygon.push_back(point_list[1]);
+ polygon.push_back(point_list[2]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
+ polygon.push_back(point_list[2]);
+ polygon.push_back(point_list[3]);
+ polygon.push_back(point_list[4]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ polygon.push_back(point_list[4]);
+ polygon.push_back(point_list[5]);
+ polygon.push_back(point_list[6]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ polygon.push_back(point_list[6]);
+ polygon.push_back(point_list[7]);
+ polygon.push_back(point_list[8]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_CORNER:
+ polygon.push_back(point_list[8]);
+ polygon.push_back(point_list[9]);
+ polygon.push_back(point_list[10]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ polygon.push_back(point_list[10]);
+ polygon.push_back(point_list[11]);
+ polygon.push_back(point_list[0]);
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
+ }
+ }
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
+ polygon.push_back(point_list[2]);
+ polygon.push_back(point_list[3]);
+ polygon.push_back(point_list[4]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
+ polygon.push_back(point_list[0]);
+ polygon.push_back(point_list[1]);
+ polygon.push_back(point_list[2]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
+ polygon.push_back(point_list[10]);
+ polygon.push_back(point_list[11]);
+ polygon.push_back(point_list[0]);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
+ polygon.push_back(point_list[8]);
+ polygon.push_back(point_list[9]);
+ polygon.push_back(point_list[10]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
+ polygon.push_back(point_list[6]);
+ polygon.push_back(point_list[7]);
+ polygon.push_back(point_list[8]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
+ polygon.push_back(point_list[4]);
+ polygon.push_back(point_list[5]);
+ polygon.push_back(point_list[6]);
+ break;
+ default:
+ break;
+ }
+ }
+
+ int half_polygon_size = polygon.size();
+ for (int i = 0; i < half_polygon_size; i++) {
+ polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0);
+ }
+
+ if (!polygon.is_empty()) {
+ p_canvas_item->draw_polygon(polygon, color_array);
+ }
+}
+
+void TileSetPluginAtlasTerrain::_draw_half_offset_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
+ PackedColorArray color_array;
+ color_array.push_back(p_color);
+
+ PackedVector2Array point_list;
+ point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(0, 3));
+ point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0)));
+ point_list.push_back(Vector2(0, -3));
+ point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0)));
+
+ Vector2 unit = Vector2(p_size) / 6.0;
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = point_list[i] * unit;
+ }
+
+ PackedVector2Array polygon;
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
+ polygon.push_back(point_list[5]);
+ polygon.push_back(point_list[0]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ polygon.push_back(point_list[0]);
+ polygon.push_back(point_list[1]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ polygon.push_back(point_list[1]);
+ polygon.push_back(point_list[2]);
+ break;
+ case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
+ polygon.push_back(point_list[2]);
+ polygon.push_back(point_list[3]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ polygon.push_back(point_list[3]);
+ polygon.push_back(point_list[4]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ polygon.push_back(point_list[4]);
+ polygon.push_back(point_list[5]);
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
+ for (int i = 0; i < point_list.size(); i++) {
+ point_list.write[i] = Vector2(point_list[i].y, point_list[i].x);
+ }
+ }
+ switch (p_bit) {
+ case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
+ polygon.push_back(point_list[0]);
+ polygon.push_back(point_list[1]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
+ polygon.push_back(point_list[5]);
+ polygon.push_back(point_list[0]);
+ break;
+ case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
+ polygon.push_back(point_list[4]);
+ polygon.push_back(point_list[5]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
+ polygon.push_back(point_list[3]);
+ polygon.push_back(point_list[4]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_SIDE:
+ polygon.push_back(point_list[2]);
+ polygon.push_back(point_list[3]);
+ break;
+ case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
+ polygon.push_back(point_list[1]);
+ polygon.push_back(point_list[2]);
+ break;
+ default:
+ break;
+ }
+ }
+
+ int half_polygon_size = polygon.size();
+ for (int i = 0; i < half_polygon_size; i++) {
+ polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0);
+ }
+
+ if (!polygon.is_empty()) {
+ p_canvas_item->draw_polygon(polygon, color_array);
+ }
+}
+
+#define TERRAIN_ALPHA 0.8
+
+#define DRAW_TERRAIN_BIT(f, bit) \
+ { \
+ int terrain_id = p_tile_data->get_peering_bit_terrain((bit)); \
+ if (terrain_id >= 0) { \
+ Color color = p_tile_set->get_terrain_color(terrain_set, terrain_id); \
+ color.a = TERRAIN_ALPHA; \
+ f(p_canvas_item, color, size, (bit)); \
+ } \
}
- Ref<ConvexPolygonShape2D> convex = p_shape;
- if (!convex.is_valid()) {
+
+#define DRAW_HALF_OFFSET_TERRAIN_BIT(f, bit, overlap, half_offset_axis) \
+ { \
+ int terrain_id = p_tile_data->get_peering_bit_terrain((bit)); \
+ if (terrain_id >= 0) { \
+ Color color = p_tile_set->get_terrain_color(terrain_set, terrain_id); \
+ color.a = TERRAIN_ALPHA; \
+ f(p_canvas_item, color, size, (bit), overlap, half_offset_axis); \
+ } \
+ }
+
+void TileSetPluginAtlasTerrain::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, const TileData *p_tile_data) {
+ ERR_FAIL_COND(!p_tile_set);
+ ERR_FAIL_COND(!p_tile_data);
+
+ int terrain_set = p_tile_data->get_terrain_set();
+ if (terrain_set < 0) {
return;
}
- Vector<Vector<Vector2>> decomp = Geometry2D::decompose_polygon_in_convex(convex->get_points());
- if (decomp.size() > 1) {
- Array sub_shapes;
- for (int i = 0; i < decomp.size(); i++) {
- Ref<ConvexPolygonShape2D> _convex = memnew(ConvexPolygonShape2D);
- _convex->set_points(decomp[i]);
- sub_shapes.append(_convex);
+ TileSet::TerrainMode terrain_mode = p_tile_set->get_terrain_set_mode(terrain_set);
+
+ TileSet::TileShape shape = p_tile_set->get_tile_shape();
+ Vector2i size = p_tile_set->get_tile_size();
+
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
+ if (shape == TileSet::TILE_SHAPE_SQUARE) {
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
+ DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE);
+ DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER);
+ DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE);
+ DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER);
+ DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER);
+ DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER);
+ } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
+ DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER);
+ DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER);
+ DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER);
+ DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER);
+ } else { // TileData::TERRAIN_MODE_MATCH_SIDES
+ DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE);
+ DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE);
+ DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE);
+ DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE);
+ }
+ } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER);
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE);
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER);
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER);
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER);
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
+ } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER);
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER);
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER);
+ DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER);
+ } else { // TileData::TERRAIN_MODE_MATCH_SIDES
+ DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE);
+ DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
+ DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE);
+ DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE);
}
- convex->set_meta("decomposed", sub_shapes);
} else {
- convex->set_meta("decomposed", Variant());
+ TileSet::TileOffsetAxis offset_axis = p_tile_set->get_tile_offset_axis();
+ float overlap = 0.0;
+ switch (p_tile_set->get_tile_shape()) {
+ case TileSet::TILE_SHAPE_HEXAGON:
+ overlap = 0.25;
+ break;
+ case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
+ overlap = 0.0;
+ break;
+ default:
+ break;
+ }
+ if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
+ if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis);
+ } else {
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis);
+ }
+ } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
+ if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis);
+ } else {
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis);
+ }
+ } else { // TileData::TERRAIN_MODE_MATCH_SIDES
+ if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis);
+ } else {
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE, overlap, offset_axis);
+ DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis);
+ }
+ }
}
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
}
-void TileSet::get_tile_list(List<int> *p_tiles) const {
- for (Map<int, TileData>::Element *E = tile_map.front(); E; E = E->next()) {
- p_tiles->push_back(E->key());
+/////////////////////////////// TileSetPluginAtlasRendering //////////////////////////////////////
+
+void TileSetPluginAtlasRendering::tilemap_notification(TileMap *p_tile_map, int p_what) {
+ switch (p_what) {
+ case CanvasItem::NOTIFICATION_VISIBILITY_CHANGED: {
+ bool visible = p_tile_map->is_visible_in_tree();
+ for (Map<Vector2i, TileMapQuadrant>::Element *E_quadrant = p_tile_map->get_quadrant_map().front(); E_quadrant; E_quadrant = E_quadrant->next()) {
+ TileMapQuadrant &q = E_quadrant->get();
+
+ // Update occluders transform.
+ for (Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator>::Element *E_cell = q.world_to_map.front(); E_cell; E_cell = E_cell->next()) {
+ Transform2D xform;
+ xform.set_origin(E_cell->key());
+ for (List<RID>::Element *E_occluder_id = q.occluders.front(); E_occluder_id; E_occluder_id = E_occluder_id->next()) {
+ RS::get_singleton()->canvas_light_occluder_set_enabled(E_occluder_id->get(), visible);
+ }
+ }
+ }
+ } break;
+ case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: {
+ if (!p_tile_map->is_inside_tree()) {
+ return;
+ }
+
+ for (Map<Vector2i, TileMapQuadrant>::Element *E_quadrant = p_tile_map->get_quadrant_map().front(); E_quadrant; E_quadrant = E_quadrant->next()) {
+ TileMapQuadrant &q = E_quadrant->get();
+
+ // Update occluders transform.
+ for (Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator>::Element *E_cell = q.world_to_map.front(); E_cell; E_cell = E_cell->next()) {
+ Transform2D xform;
+ xform.set_origin(E_cell->key());
+ for (List<RID>::Element *E_occluder_id = q.occluders.front(); E_occluder_id; E_occluder_id = E_occluder_id->next()) {
+ RS::get_singleton()->canvas_light_occluder_set_transform(E_occluder_id->get(), p_tile_map->get_global_transform() * xform);
+ }
+ }
+ }
+ } break;
+ case CanvasItem::NOTIFICATION_DRAW: {
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ if (tile_set.is_valid() || p_tile_map->is_y_sort_enabled()) {
+ RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(p_tile_map->get_canvas_item(), tile_set->is_y_sorting() || p_tile_map->is_y_sort_enabled());
+ }
+ } break;
}
}
-bool TileSet::has_tile(int p_id) const {
- return tile_map.has(p_id);
+void TileSetPluginAtlasRendering::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation) {
+ ERR_FAIL_COND(!p_tile_set.is_valid());
+ ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id));
+ ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords));
+ ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_alternative_tile(p_atlas_coords, p_alternative_tile));
+
+ TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get the texture.
+ Ref<Texture2D> tex = atlas_source->get_texture();
+ if (!tex.is_valid()) {
+ return;
+ }
+
+ // Check if we are in the texture, return otherwise.
+ Vector2i grid_size = atlas_source->get_atlas_grid_size();
+ if (p_atlas_coords.x >= grid_size.x || p_atlas_coords.y >= grid_size.y) {
+ return;
+ }
+
+ // Get tile data.
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile));
+
+ // Compute the offset
+ Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords);
+ Vector2i tile_offset = atlas_source->get_tile_effective_texture_offset(p_atlas_coords, p_alternative_tile);
+
+ // Compute the destination rectangle in the CanvasItem.
+ Rect2 dest_rect;
+ dest_rect.size = source_rect.size;
+ dest_rect.size.x += fp_adjust;
+ dest_rect.size.y += fp_adjust;
+
+ bool transpose = tile_data->get_transpose();
+ if (transpose) {
+ dest_rect.position = (p_position - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
+ } else {
+ dest_rect.position = (p_position - dest_rect.size / 2 - tile_offset);
+ }
+
+ if (tile_data->get_flip_h()) {
+ dest_rect.size.x = -dest_rect.size.x;
+ }
+
+ if (tile_data->get_flip_v()) {
+ dest_rect.size.y = -dest_rect.size.y;
+ }
+
+ // Get the tile modulation.
+ Color modulate = tile_data->get_modulate();
+ modulate = Color(modulate.r * p_modulation.r, modulate.g * p_modulation.g, modulate.b * p_modulation.b, modulate.a * p_modulation.a);
+
+ // Draw the tile.
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ }
}
-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() != 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) {
- return ret;
+void TileSetPluginAtlasRendering::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+ ERR_FAIL_COND(!p_tile_map);
+ ERR_FAIL_COND(!p_tile_map->is_inside_tree());
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ bool visible = p_tile_map->is_visible_in_tree();
+
+ SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
+ while (q_list_element) {
+ TileMapQuadrant &q = *q_list_element->self();
+
+ RenderingServer *rs = RenderingServer::get_singleton();
+
+ // Free the canvas items.
+ for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
+ rs->free(E->get());
+ }
+ q.canvas_items.clear();
+
+ // Free the occluders.
+ for (List<RID>::Element *E = q.occluders.front(); E; E = E->next()) {
+ rs->free(E->get());
+ }
+ q.occluders.clear();
+
+ // Those allow to group cell per material or z-index.
+ Ref<ShaderMaterial> prev_material;
+ int prev_z_index = 0;
+ RID prev_canvas_item;
+
+ // Iterate over the cells of the quadrant.
+ for (Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator>::Element *E_cell = q.world_to_map.front(); E_cell; E_cell = E_cell->next()) {
+ TileMapCell c = p_tile_map->get_cell(E_cell->value());
+
+ TileSetSource *source;
+ if (tile_set->has_source(c.source_id)) {
+ source = *tile_set->get_source(c.source_id);
+
+ if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
+ continue;
+ }
+
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get the tile data.
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+ Ref<ShaderMaterial> mat = tile_data->tile_get_material();
+ int z_index = tile_data->get_z_index();
+
+ // Quandrant pos.
+ Vector2 position = p_tile_map->map_to_world(q.coords * p_tile_map->get_effective_quadrant_size());
+ if (tile_set->is_y_sorting()) {
+ // When Y-sorting, the quandrant size is sure to be 1, we can thus offset the CanvasItem.
+ position.y += tile_data->get_y_sort_origin();
+ }
+
+ // --- CanvasItems ---
+ // Create two canvas items, for rendering and debug.
+ RID canvas_item;
+
+ // Check if the material or the z_index changed.
+ if (prev_canvas_item == RID() || prev_material != mat || prev_z_index != z_index) {
+ // If so, create a new CanvasItem.
+ canvas_item = rs->canvas_item_create();
+ if (mat.is_valid()) {
+ rs->canvas_item_set_material(canvas_item, mat->get_rid());
+ }
+ rs->canvas_item_set_parent(canvas_item, p_tile_map->get_canvas_item());
+ rs->canvas_item_set_use_parent_material(canvas_item, p_tile_map->get_use_parent_material() || p_tile_map->get_material().is_valid());
+
+ Transform2D xform;
+ xform.set_origin(position);
+ rs->canvas_item_set_transform(canvas_item, xform);
+
+ rs->canvas_item_set_light_mask(canvas_item, p_tile_map->get_light_mask());
+ rs->canvas_item_set_z_index(canvas_item, z_index);
+
+ rs->canvas_item_set_default_texture_filter(canvas_item, RS::CanvasItemTextureFilter(p_tile_map->CanvasItem::get_texture_filter()));
+ rs->canvas_item_set_default_texture_repeat(canvas_item, RS::CanvasItemTextureRepeat(p_tile_map->CanvasItem::get_texture_repeat()));
+
+ q.canvas_items.push_back(canvas_item);
+
+ prev_canvas_item = canvas_item;
+ prev_material = mat;
+ prev_z_index = z_index;
+
+ } else {
+ // Keep the same canvas_item to draw on.
+ canvas_item = prev_canvas_item;
+ }
+
+ // Drawing the tile in the canvas item.
+ draw_tile(canvas_item, E_cell->key() - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, p_tile_map->get_self_modulate());
+
+ // --- Occluders ---
+ for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
+ Transform2D xform;
+ xform.set_origin(E_cell->key());
+ if (tile_data->get_occluder(i).is_valid()) {
+ RID occluder_id = rs->canvas_light_occluder_create();
+ rs->canvas_light_occluder_set_enabled(occluder_id, visible);
+ rs->canvas_light_occluder_set_transform(occluder_id, p_tile_map->get_global_transform() * xform);
+ rs->canvas_light_occluder_set_polygon(occluder_id, tile_data->get_occluder(i)->get_rid());
+ rs->canvas_light_occluder_attach_to_canvas(occluder_id, p_tile_map->get_canvas());
+ rs->canvas_light_occluder_set_light_mask(occluder_id, tile_set->get_occlusion_layer_light_mask(i));
+ q.occluders.push_back(occluder_id);
+ }
+ }
+ }
}
}
+
+ quadrant_order_dirty = true;
+ q_list_element = q_list_element->next();
+ }
+
+ // Reset the drawing indices
+ if (quadrant_order_dirty) {
+ int index = -(int64_t)0x80000000; //always must be drawn below children.
+
+ // Sort the quadrants coords per world coordinates
+ Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> world_to_map;
+ Map<Vector2i, TileMapQuadrant> quadrant_map = p_tile_map->get_quadrant_map();
+ for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
+ world_to_map[p_tile_map->map_to_world(E->key())] = E->key();
+ }
+
+ // Sort the quadrants
+ for (Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator>::Element *E = world_to_map.front(); E; E = E->next()) {
+ TileMapQuadrant &q = quadrant_map[E->value()];
+ for (List<RID>::Element *F = q.canvas_items.front(); F; F = F->next()) {
+ RS::get_singleton()->canvas_item_set_draw_index(F->get(), index++);
+ }
+ }
+
+ quadrant_order_dirty = false;
}
- return false;
}
-void TileSet::remove_tile(int p_id) {
- ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map.erase(p_id);
- notify_property_list_changed();
- emit_changed();
+void TileSetPluginAtlasRendering::create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ quadrant_order_dirty = true;
}
-int TileSet::get_last_unused_tile_id() const {
- if (tile_map.size()) {
- return tile_map.back()->key() + 1;
- } else {
- return 0;
+void TileSetPluginAtlasRendering::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
+ // Free the canvas items.
+ for (List<RID>::Element *E = p_quadrant->canvas_items.front(); E; E = E->next()) {
+ RenderingServer::get_singleton()->free(E->get());
}
+ p_quadrant->canvas_items.clear();
+
+ // Free the occluders.
+ for (List<RID>::Element *E = p_quadrant->occluders.front(); E; E = E->next()) {
+ RenderingServer::get_singleton()->free(E->get());
+ }
+ p_quadrant->occluders.clear();
}
-int TileSet::find_tile_by_name(const String &p_name) const {
- for (Map<int, TileData>::Element *E = tile_map.front(); E; E = E->next()) {
- if (p_name == E->get().name) {
- return E->key();
+void TileSetPluginAtlasRendering::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+
+ // Draw a placeholder for scenes needing one.
+ RenderingServer *rs = RenderingServer::get_singleton();
+ Vector2 quadrant_pos = p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size());
+ for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
+ const TileMapCell &c = p_tile_map->get_cell(E_cell->get());
+
+ TileSetSource *source;
+ if (tile_set->has_source(c.source_id)) {
+ source = *tile_set->get_source(c.source_id);
+
+ if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
+ continue;
+ }
+
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ Vector2i grid_size = atlas_source->get_atlas_grid_size();
+ if (!atlas_source->get_texture().is_valid() || c.get_atlas_coords().x >= grid_size.x || c.get_atlas_coords().y >= grid_size.y) {
+ // Generate a random color from the hashed values of the tiles.
+ Array to_hash;
+ to_hash.push_back(c.source_id);
+ to_hash.push_back(c.get_atlas_coords());
+ to_hash.push_back(c.alternative_tile);
+ uint32_t hash = RandomPCG(to_hash.hash()).rand();
+
+ Color color;
+ color = color.from_hsv(
+ (float)((hash >> 24) & 0xFF) / 256.0,
+ Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
+ Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
+ 0.8);
+
+ // Draw a placeholder tile.
+ Transform2D xform;
+ xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
+ }
+ }
}
}
- return -1;
}
-void TileSet::reset_state() {
- clear();
+/////////////////////////////// TileSetPluginAtlasPhysics //////////////////////////////////////
+
+void TileSetPluginAtlasPhysics::tilemap_notification(TileMap *p_tile_map, int p_what) {
+ switch (p_what) {
+ case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: {
+ // Update the bodies transforms.
+ if (p_tile_map->is_inside_tree()) {
+ Map<Vector2i, TileMapQuadrant> quadrant_map = p_tile_map->get_quadrant_map();
+ Transform2D global_transform = p_tile_map->get_global_transform();
+
+ for (Map<Vector2i, TileMapQuadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
+ TileMapQuadrant &q = E->get();
+
+ Transform2D xform;
+ xform.set_origin(p_tile_map->map_to_world(E->key() * p_tile_map->get_effective_quadrant_size()));
+ xform = global_transform * xform;
+
+ for (int body_index = 0; body_index < q.bodies.size(); body_index++) {
+ PhysicsServer2D::get_singleton()->body_set_state(q.bodies[body_index], PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
+ }
+ }
+ }
+ } break;
+ }
}
-void TileSet::clear() {
- tile_map.clear();
- notify_property_list_changed();
- emit_changed();
+void TileSetPluginAtlasPhysics::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+ ERR_FAIL_COND(!p_tile_map);
+ ERR_FAIL_COND(!p_tile_map->is_inside_tree());
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ Transform2D global_transform = p_tile_map->get_global_transform();
+ PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
+
+ SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
+ while (q_list_element) {
+ TileMapQuadrant &q = *q_list_element->self();
+
+ Vector2 quadrant_pos = p_tile_map->map_to_world(q.coords * p_tile_map->get_effective_quadrant_size());
+
+ // Clear shapes.
+ for (int body_index = 0; body_index < q.bodies.size(); body_index++) {
+ ps->body_clear_shapes(q.bodies[body_index]);
+
+ // Position the bodies.
+ Transform2D xform;
+ xform.set_origin(quadrant_pos);
+ xform = global_transform * xform;
+ ps->body_set_state(q.bodies[body_index], PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
+ }
+
+ for (Set<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) {
+ TileMapCell c = p_tile_map->get_cell(E_cell->get());
+
+ TileSetSource *source;
+ if (tile_set->has_source(c.source_id)) {
+ source = *tile_set->get_source(c.source_id);
+
+ if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
+ continue;
+ }
+
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+
+ for (int body_index = 0; body_index < q.bodies.size(); body_index++) {
+ // Add the shapes again.
+ for (int shape_index = 0; shape_index < tile_data->get_collision_shapes_count(body_index); shape_index++) {
+ bool one_way_collision = tile_data->is_collision_shape_one_way(body_index, shape_index);
+ float one_way_collision_margin = tile_data->get_collision_shape_one_way_margin(body_index, shape_index);
+ Ref<Shape2D> shape = tile_data->get_collision_shape_shape(body_index, shape_index);
+ if (shape.is_valid()) {
+ Transform2D xform = Transform2D();
+ xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos);
+
+ // Add decomposed convex shapes.
+ ps->body_add_shape(q.bodies[body_index], shape->get_rid(), xform);
+ ps->body_set_shape_metadata(q.bodies[body_index], shape_index, E_cell->get());
+ ps->body_set_shape_as_one_way_collision(q.bodies[body_index], shape_index, one_way_collision, one_way_collision_margin);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ q_list_element = q_list_element->next();
+ }
}
-void TileSet::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_tile", "id"), &TileSet::create_tile);
- ClassDB::bind_method(D_METHOD("autotile_clear_bitmask_map", "id"), &TileSet::autotile_clear_bitmask_map);
- ClassDB::bind_method(D_METHOD("autotile_set_icon_coordinate", "id", "coord"), &TileSet::autotile_set_icon_coordinate);
- ClassDB::bind_method(D_METHOD("autotile_get_icon_coordinate", "id"), &TileSet::autotile_get_icon_coordinate);
- ClassDB::bind_method(D_METHOD("autotile_set_subtile_priority", "id", "coord", "priority"), &TileSet::autotile_set_subtile_priority);
- ClassDB::bind_method(D_METHOD("autotile_get_subtile_priority", "id", "coord"), &TileSet::autotile_get_subtile_priority);
- ClassDB::bind_method(D_METHOD("autotile_set_z_index", "id", "coord", "z_index"), &TileSet::autotile_set_z_index);
- ClassDB::bind_method(D_METHOD("autotile_get_z_index", "id", "coord"), &TileSet::autotile_get_z_index);
- ClassDB::bind_method(D_METHOD("autotile_set_light_occluder", "id", "light_occluder", "coord"), &TileSet::autotile_set_light_occluder);
- ClassDB::bind_method(D_METHOD("autotile_get_light_occluder", "id", "coord"), &TileSet::autotile_get_light_occluder);
- ClassDB::bind_method(D_METHOD("autotile_set_navigation_polygon", "id", "navigation_polygon", "coord"), &TileSet::autotile_set_navigation_polygon);
- ClassDB::bind_method(D_METHOD("autotile_get_navigation_polygon", "id", "coord"), &TileSet::autotile_get_navigation_polygon);
- ClassDB::bind_method(D_METHOD("autotile_set_bitmask", "id", "bitmask", "flag"), &TileSet::autotile_set_bitmask);
- ClassDB::bind_method(D_METHOD("autotile_get_bitmask", "id", "coord"), &TileSet::autotile_get_bitmask);
- ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "id", "mode"), &TileSet::autotile_set_bitmask_mode);
- ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode", "id"), &TileSet::autotile_get_bitmask_mode);
- ClassDB::bind_method(D_METHOD("autotile_set_spacing", "id", "spacing"), &TileSet::autotile_set_spacing);
- ClassDB::bind_method(D_METHOD("autotile_get_spacing", "id"), &TileSet::autotile_get_spacing);
- ClassDB::bind_method(D_METHOD("autotile_set_size", "id", "size"), &TileSet::autotile_set_size);
- ClassDB::bind_method(D_METHOD("autotile_get_size", "id"), &TileSet::autotile_get_size);
- ClassDB::bind_method(D_METHOD("tile_set_name", "id", "name"), &TileSet::tile_set_name);
- ClassDB::bind_method(D_METHOD("tile_get_name", "id"), &TileSet::tile_get_name);
- ClassDB::bind_method(D_METHOD("tile_set_texture", "id", "texture"), &TileSet::tile_set_texture);
- ClassDB::bind_method(D_METHOD("tile_get_texture", "id"), &TileSet::tile_get_texture);
- ClassDB::bind_method(D_METHOD("tile_set_material", "id", "material"), &TileSet::tile_set_material);
- ClassDB::bind_method(D_METHOD("tile_get_material", "id"), &TileSet::tile_get_material);
- ClassDB::bind_method(D_METHOD("tile_set_modulate", "id", "color"), &TileSet::tile_set_modulate);
- ClassDB::bind_method(D_METHOD("tile_get_modulate", "id"), &TileSet::tile_get_modulate);
- ClassDB::bind_method(D_METHOD("tile_set_texture_offset", "id", "texture_offset"), &TileSet::tile_set_texture_offset);
- ClassDB::bind_method(D_METHOD("tile_get_texture_offset", "id"), &TileSet::tile_get_texture_offset);
- ClassDB::bind_method(D_METHOD("tile_set_region", "id", "region"), &TileSet::tile_set_region);
- ClassDB::bind_method(D_METHOD("tile_get_region", "id"), &TileSet::tile_get_region);
- ClassDB::bind_method(D_METHOD("tile_set_shape", "id", "shape_id", "shape"), &TileSet::tile_set_shape);
- ClassDB::bind_method(D_METHOD("tile_get_shape", "id", "shape_id"), &TileSet::tile_get_shape);
- ClassDB::bind_method(D_METHOD("tile_set_shape_offset", "id", "shape_id", "shape_offset"), &TileSet::tile_set_shape_offset);
- ClassDB::bind_method(D_METHOD("tile_get_shape_offset", "id", "shape_id"), &TileSet::tile_get_shape_offset);
- ClassDB::bind_method(D_METHOD("tile_set_shape_transform", "id", "shape_id", "shape_transform"), &TileSet::tile_set_shape_transform);
- ClassDB::bind_method(D_METHOD("tile_get_shape_transform", "id", "shape_id"), &TileSet::tile_get_shape_transform);
- ClassDB::bind_method(D_METHOD("tile_set_shape_one_way", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way);
- ClassDB::bind_method(D_METHOD("tile_get_shape_one_way", "id", "shape_id"), &TileSet::tile_get_shape_one_way);
- ClassDB::bind_method(D_METHOD("tile_set_shape_one_way_margin", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way_margin);
- ClassDB::bind_method(D_METHOD("tile_get_shape_one_way_margin", "id", "shape_id"), &TileSet::tile_get_shape_one_way_margin);
- ClassDB::bind_method(D_METHOD("tile_add_shape", "id", "shape", "shape_transform", "one_way", "autotile_coord"), &TileSet::tile_add_shape, DEFVAL(false), DEFVAL(Vector2()));
- ClassDB::bind_method(D_METHOD("tile_get_shape_count", "id"), &TileSet::tile_get_shape_count);
- ClassDB::bind_method(D_METHOD("tile_set_shapes", "id", "shapes"), &TileSet::_tile_set_shapes);
- ClassDB::bind_method(D_METHOD("tile_get_shapes", "id"), &TileSet::_tile_get_shapes);
- ClassDB::bind_method(D_METHOD("tile_set_tile_mode", "id", "tilemode"), &TileSet::tile_set_tile_mode);
- ClassDB::bind_method(D_METHOD("tile_get_tile_mode", "id"), &TileSet::tile_get_tile_mode);
- ClassDB::bind_method(D_METHOD("tile_set_navigation_polygon", "id", "navigation_polygon"), &TileSet::tile_set_navigation_polygon);
- ClassDB::bind_method(D_METHOD("tile_get_navigation_polygon", "id"), &TileSet::tile_get_navigation_polygon);
- ClassDB::bind_method(D_METHOD("tile_set_navigation_polygon_offset", "id", "navigation_polygon_offset"), &TileSet::tile_set_navigation_polygon_offset);
- ClassDB::bind_method(D_METHOD("tile_get_navigation_polygon_offset", "id"), &TileSet::tile_get_navigation_polygon_offset);
- ClassDB::bind_method(D_METHOD("tile_set_light_occluder", "id", "light_occluder"), &TileSet::tile_set_light_occluder);
- ClassDB::bind_method(D_METHOD("tile_get_light_occluder", "id"), &TileSet::tile_get_light_occluder);
- ClassDB::bind_method(D_METHOD("tile_set_occluder_offset", "id", "occluder_offset"), &TileSet::tile_set_occluder_offset);
- ClassDB::bind_method(D_METHOD("tile_get_occluder_offset", "id"), &TileSet::tile_get_occluder_offset);
- ClassDB::bind_method(D_METHOD("tile_set_z_index", "id", "z_index"), &TileSet::tile_set_z_index);
- ClassDB::bind_method(D_METHOD("tile_get_z_index", "id"), &TileSet::tile_get_z_index);
-
- ClassDB::bind_method(D_METHOD("remove_tile", "id"), &TileSet::remove_tile);
- ClassDB::bind_method(D_METHOD("clear"), &TileSet::clear);
- ClassDB::bind_method(D_METHOD("get_last_unused_tile_id"), &TileSet::get_last_unused_tile_id);
- ClassDB::bind_method(D_METHOD("find_tile_by_name", "name"), &TileSet::find_tile_by_name);
- ClassDB::bind_method(D_METHOD("get_tiles_ids"), &TileSet::_get_tiles_ids);
-
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_tile_bound", PropertyInfo(Variant::INT, "drawn_id"), PropertyInfo(Variant::INT, "neighbor_id")));
- BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_subtile_selection", PropertyInfo(Variant::INT, "autotile_id"), PropertyInfo(Variant::INT, "bitmask"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location")));
- BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_atlas_subtile_selection", PropertyInfo(Variant::INT, "atlastile_id"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location")));
-
- BIND_ENUM_CONSTANT(BITMASK_2X2);
- BIND_ENUM_CONSTANT(BITMASK_3X3_MINIMAL);
- BIND_ENUM_CONSTANT(BITMASK_3X3);
-
- BIND_ENUM_CONSTANT(BIND_TOPLEFT);
- BIND_ENUM_CONSTANT(BIND_TOP);
- BIND_ENUM_CONSTANT(BIND_TOPRIGHT);
- BIND_ENUM_CONSTANT(BIND_LEFT);
- BIND_ENUM_CONSTANT(BIND_CENTER);
- BIND_ENUM_CONSTANT(BIND_RIGHT);
- BIND_ENUM_CONSTANT(BIND_BOTTOMLEFT);
- BIND_ENUM_CONSTANT(BIND_BOTTOM);
- BIND_ENUM_CONSTANT(BIND_BOTTOMRIGHT);
-
- BIND_ENUM_CONSTANT(SINGLE_TILE);
- BIND_ENUM_CONSTANT(AUTO_TILE);
- BIND_ENUM_CONSTANT(ATLAS_TILE);
+void TileSetPluginAtlasPhysics::create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ //Get the TileMap's gobla transform.
+ Transform2D global_transform;
+ if (p_tile_map->is_inside_tree()) {
+ global_transform = p_tile_map->get_global_transform();
+ }
+
+ // Clear all bodies.
+ p_quadrant->bodies.clear();
+
+ // Create the body and set its parameters.
+ for (int layer_index = 0; layer_index < tile_set->get_physics_layers_count(); layer_index++) {
+ RID body = PhysicsServer2D::get_singleton()->body_create();
+ PhysicsServer2D::get_singleton()->body_set_mode(body, PhysicsServer2D::BODY_MODE_STATIC);
+
+ PhysicsServer2D::get_singleton()->body_attach_object_instance_id(body, p_tile_map->get_instance_id());
+ PhysicsServer2D::get_singleton()->body_set_collision_layer(body, tile_set->get_physics_layer_collision_layer(layer_index));
+ PhysicsServer2D::get_singleton()->body_set_collision_mask(body, tile_set->get_physics_layer_collision_mask(layer_index));
+
+ Ref<PhysicsMaterial> physics_material = tile_set->get_physics_layer_physics_material(layer_index);
+ if (!physics_material.is_valid()) {
+ PhysicsServer2D::get_singleton()->body_set_param(body, PhysicsServer2D::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer2D::get_singleton()->body_set_param(body, PhysicsServer2D::BODY_PARAM_FRICTION, 1);
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_param(body, PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material->computed_bounce());
+ PhysicsServer2D::get_singleton()->body_set_param(body, PhysicsServer2D::BODY_PARAM_FRICTION, physics_material->computed_friction());
+ }
+
+ if (p_tile_map->is_inside_tree()) {
+ RID space = p_tile_map->get_world_2d()->get_space();
+ PhysicsServer2D::get_singleton()->body_set_space(body, space);
+
+ Transform2D xform;
+ xform.set_origin(p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size()));
+ xform = global_transform * xform;
+ PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
+ }
+
+ p_quadrant->bodies.push_back(body);
+ }
}
-TileSet::TileSet() {
+void TileSetPluginAtlasPhysics::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
+ // Remove a quadrant.
+ for (int body_index = 0; body_index < p_quadrant->bodies.size(); body_index++) {
+ PhysicsServer2D::get_singleton()->free(p_quadrant->bodies[body_index]);
+ }
+ p_quadrant->bodies.clear();
+}
+
+void TileSetPluginAtlasPhysics::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
+ // Draw the debug collision shapes.
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ if (!p_tile_map->get_tree()) {
+ return;
+ }
+
+ bool show_collision = false;
+ switch (p_tile_map->get_collision_visibility_mode()) {
+ case TileMap::VISIBILITY_MODE_DEFAULT:
+ show_collision = !Engine::get_singleton()->is_editor_hint() && (p_tile_map->get_tree() && p_tile_map->get_tree()->is_debugging_navigation_hint());
+ break;
+ case TileMap::VISIBILITY_MODE_FORCE_HIDE:
+ show_collision = false;
+ break;
+ case TileMap::VISIBILITY_MODE_FORCE_SHOW:
+ show_collision = true;
+ break;
+ }
+ if (!show_collision) {
+ return;
+ }
+
+ RenderingServer *rs = RenderingServer::get_singleton();
+
+ Vector2 quadrant_pos = p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size());
+
+ Color debug_collision_color = p_tile_map->get_tree()->get_debug_collisions_color();
+ for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
+ TileMapCell c = p_tile_map->get_cell(E_cell->get());
+
+ Transform2D xform;
+ xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+
+ if (tile_set->has_source(c.source_id)) {
+ TileSetSource *source = *tile_set->get_source(c.source_id);
+
+ if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
+ continue;
+ }
+
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+
+ for (int body_index = 0; body_index < p_quadrant->bodies.size(); body_index++) {
+ for (int shape_index = 0; shape_index < tile_data->get_collision_shapes_count(body_index); shape_index++) {
+ // Draw the debug shape.
+ Ref<Shape2D> shape = tile_data->get_collision_shape_shape(body_index, shape_index);
+ if (shape.is_valid()) {
+ shape->draw(p_quadrant->debug_canvas_item, debug_collision_color);
+ }
+ }
+ }
+ }
+ }
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, Transform2D());
+ }
+};
+
+/////////////////////////////// TileSetPluginAtlasNavigation //////////////////////////////////////
+
+void TileSetPluginAtlasNavigation::tilemap_notification(TileMap *p_tile_map, int p_what) {
+ switch (p_what) {
+ case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: {
+ if (p_tile_map->is_inside_tree()) {
+ Map<Vector2i, TileMapQuadrant> quadrant_map = p_tile_map->get_quadrant_map();
+ Transform2D tilemap_xform = p_tile_map->get_global_transform();
+ for (Map<Vector2i, TileMapQuadrant>::Element *E_quadrant = quadrant_map.front(); E_quadrant; E_quadrant = E_quadrant->next()) {
+ TileMapQuadrant &q = E_quadrant->get();
+ for (Map<Vector2i, Vector<RID>>::Element *E_region = q.navigation_regions.front(); E_region; E_region = E_region->next()) {
+ for (int layer_index = 0; layer_index < E_region->get().size(); layer_index++) {
+ RID region = E_region->get()[layer_index];
+ if (!region.is_valid()) {
+ continue;
+ }
+ Transform2D tile_transform;
+ tile_transform.set_origin(p_tile_map->map_to_world(E_region->key()));
+ NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
+ }
+ }
+ }
+ }
+ } break;
+ }
+}
+
+void TileSetPluginAtlasNavigation::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+ ERR_FAIL_COND(!p_tile_map);
+ ERR_FAIL_COND(!p_tile_map->is_inside_tree());
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ // Get colors for debug.
+ SceneTree *st = SceneTree::get_singleton();
+ Color debug_navigation_color;
+ bool debug_navigation = st && st->is_debugging_navigation_hint();
+ if (debug_navigation) {
+ debug_navigation_color = st->get_debug_navigation_color();
+ }
+
+ Transform2D tilemap_xform = p_tile_map->get_global_transform();
+ SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
+ while (q_list_element) {
+ TileMapQuadrant &q = *q_list_element->self();
+
+ // Clear navigation shapes in the quadrant.
+ for (Map<Vector2i, Vector<RID>>::Element *E = q.navigation_regions.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().size(); i++) {
+ RID region = E->get()[i];
+ if (!region.is_valid()) {
+ continue;
+ }
+ NavigationServer2D::get_singleton()->region_set_map(region, RID());
+ }
+ }
+ q.navigation_regions.clear();
+
+ // Get the navigation polygons and create regions.
+ for (Set<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) {
+ TileMapCell c = p_tile_map->get_cell(E_cell->get());
+
+ TileSetSource *source;
+ if (tile_set->has_source(c.source_id)) {
+ source = *tile_set->get_source(c.source_id);
+
+ if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
+ continue;
+ }
+
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+ q.navigation_regions[E_cell->get()].resize(tile_set->get_navigation_layers_count());
+
+ for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
+ Ref<NavigationPolygon> navpoly;
+ navpoly = tile_data->get_navigation_polygon(layer_index);
+
+ if (navpoly.is_valid()) {
+ Transform2D tile_transform;
+ tile_transform.set_origin(p_tile_map->map_to_world(E_cell->get()));
+
+ RID region = NavigationServer2D::get_singleton()->region_create();
+ NavigationServer2D::get_singleton()->region_set_map(region, p_tile_map->get_world_2d()->get_navigation_map());
+ NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
+ NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly);
+ q.navigation_regions[E_cell->get()].write[layer_index] = region;
+ }
+ }
+ }
+ }
+ }
+
+ q_list_element = q_list_element->next();
+ }
+}
+
+void TileSetPluginAtlasNavigation::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
+ // Clear navigation shapes in the quadrant.
+ for (Map<Vector2i, Vector<RID>>::Element *E = p_quadrant->navigation_regions.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().size(); i++) {
+ RID region = E->get()[i];
+ if (!region.is_valid()) {
+ continue;
+ }
+ NavigationServer2D::get_singleton()->free(region);
+ }
+ }
+ p_quadrant->navigation_regions.clear();
+}
+
+void TileSetPluginAtlasNavigation::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
+ // Draw the debug collision shapes.
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ if (!p_tile_map->get_tree()) {
+ return;
+ }
+
+ bool show_navigation = false;
+ switch (p_tile_map->get_navigation_visibility_mode()) {
+ case TileMap::VISIBILITY_MODE_DEFAULT:
+ show_navigation = !Engine::get_singleton()->is_editor_hint() && (p_tile_map->get_tree() && p_tile_map->get_tree()->is_debugging_navigation_hint());
+ break;
+ case TileMap::VISIBILITY_MODE_FORCE_HIDE:
+ show_navigation = false;
+ break;
+ case TileMap::VISIBILITY_MODE_FORCE_SHOW:
+ show_navigation = true;
+ break;
+ }
+ if (!show_navigation) {
+ return;
+ }
+
+ RenderingServer *rs = RenderingServer::get_singleton();
+
+ Color color = p_tile_map->get_tree()->get_debug_navigation_color();
+ RandomPCG rand;
+
+ Vector2 quadrant_pos = p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size());
+
+ for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
+ TileMapCell c = p_tile_map->get_cell(E_cell->get());
+
+ TileSetSource *source;
+ if (tile_set->has_source(c.source_id)) {
+ source = *tile_set->get_source(c.source_id);
+
+ if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
+ continue;
+ }
+
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
+
+ Transform2D xform;
+ xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+
+ for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
+ Ref<NavigationPolygon> navpoly = tile_data->get_navigation_polygon(layer_index);
+ if (navpoly.is_valid()) {
+ PackedVector2Array navigation_polygon_vertices = navpoly->get_vertices();
+
+ for (int i = 0; i < navpoly->get_polygon_count(); i++) {
+ // An array of vertices for this polygon.
+ Vector<int> polygon = navpoly->get_polygon(i);
+ Vector<Vector2> vertices;
+ vertices.resize(polygon.size());
+ for (int j = 0; j < polygon.size(); j++) {
+ ERR_FAIL_INDEX(polygon[j], navigation_polygon_vertices.size());
+ vertices.write[j] = navigation_polygon_vertices[polygon[j]];
+ }
+
+ // Generate the polygon color, slightly randomly modified from the settings one.
+ Color random_variation_color;
+ random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1);
+ random_variation_color.a = color.a;
+ Vector<Color> colors;
+ colors.push_back(random_variation_color);
+
+ rs->canvas_item_add_polygon(p_quadrant->debug_canvas_item, vertices, colors);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/////////////////////////////// TileSetPluginScenesCollections //////////////////////////////////////
+
+void TileSetPluginScenesCollections::update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
+ while (q_list_element) {
+ TileMapQuadrant &q = *q_list_element->self();
+
+ // Clear the scenes.
+ for (Map<Vector2i, String>::Element *E = q.scenes.front(); E; E = E->next()) {
+ Node *node = p_tile_map->get_node(E->get());
+ if (node) {
+ node->queue_delete();
+ }
+ }
+
+ q.scenes.clear();
+
+ // Recreate the scenes.
+ for (Set<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) {
+ const TileMapCell &c = p_tile_map->get_cell(E_cell->get());
+
+ TileSetSource *source;
+ if (tile_set->has_source(c.source_id)) {
+ source = *tile_set->get_source(c.source_id);
+
+ if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
+ continue;
+ }
+
+ TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
+ if (scenes_collection_source) {
+ Ref<PackedScene> packed_scene = scenes_collection_source->get_scene_tile_scene(c.alternative_tile);
+ if (packed_scene.is_valid()) {
+ Node *scene = packed_scene->instance();
+ p_tile_map->add_child(scene);
+ Control *scene_as_control = Object::cast_to<Control>(scene);
+ Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene);
+ if (scene_as_control) {
+ scene_as_control->set_position(p_tile_map->map_to_world(E_cell->get()) + scene_as_control->get_position());
+ } else if (scene_as_node2d) {
+ Transform2D xform;
+ xform.set_origin(p_tile_map->map_to_world(E_cell->get()));
+ scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform());
+ }
+ q.scenes[E_cell->get()] = scene->get_name();
+ }
+ }
+ }
+ }
+
+ q_list_element = q_list_element->next();
+ }
+}
+
+void TileSetPluginScenesCollections::cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
+ // Clear the scenes.
+ for (Map<Vector2i, String>::Element *E = p_quadrant->scenes.front(); E; E = E->next()) {
+ Node *node = p_tile_map->get_node(E->get());
+ if (node) {
+ node->queue_delete();
+ }
+ }
+
+ p_quadrant->scenes.clear();
+}
+
+void TileSetPluginScenesCollections::draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) {
+ Ref<TileSet> tile_set = p_tile_map->get_tileset();
+ ERR_FAIL_COND(!tile_set.is_valid());
+
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+
+ // Draw a placeholder for scenes needing one.
+ RenderingServer *rs = RenderingServer::get_singleton();
+ Vector2 quadrant_pos = p_tile_map->map_to_world(p_quadrant->coords * p_tile_map->get_effective_quadrant_size());
+ for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
+ const TileMapCell &c = p_tile_map->get_cell(E_cell->get());
+
+ TileSetSource *source;
+ if (tile_set->has_source(c.source_id)) {
+ source = *tile_set->get_source(c.source_id);
+
+ if (!source->has_tile(c.get_atlas_coords()) || !source->has_alternative_tile(c.get_atlas_coords(), c.alternative_tile)) {
+ continue;
+ }
+
+ TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
+ if (scenes_collection_source) {
+ if (!scenes_collection_source->get_scene_tile_scene(c.alternative_tile).is_valid() || scenes_collection_source->get_scene_tile_display_placeholder(c.alternative_tile)) {
+ // Generate a random color from the hashed values of the tiles.
+ Array to_hash;
+ to_hash.push_back(c.source_id);
+ to_hash.push_back(c.alternative_tile);
+ uint32_t hash = RandomPCG(to_hash.hash()).rand();
+
+ Color color;
+ color = color.from_hsv(
+ (float)((hash >> 24) & 0xFF) / 256.0,
+ Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0),
+ Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0),
+ 0.8);
+
+ // Draw a placeholder tile.
+ Transform2D xform;
+ xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
+ }
+ }
+ }
+ }
}
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 0a8721f35b..6cf4198f30 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -32,226 +32,668 @@
#define TILE_SET_H
#include "core/io/resource.h"
-#include "core/variant/array.h"
+#include "core/object/object.h"
#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/navigation_region_2d.h"
+#include "scene/main/canvas_item.h"
#include "scene/resources/convex_polygon_shape_2d.h"
+#include "scene/resources/packed_scene.h"
+#include "scene/resources/physics_material.h"
+#include "scene/resources/shape_2d.h"
+
+#ifndef DISABLE_DEPRECATED
+#include "scene/2d/light_occluder_2d.h"
+#include "scene/2d/navigation_region_2d.h"
+#include "scene/resources/shader.h"
#include "scene/resources/shape_2d.h"
#include "scene/resources/texture.h"
+#endif
+
+class TileMap;
+struct TileMapQuadrant;
+class TileSetSource;
+class TileSetAtlasSource;
+class TileData;
+
+// Forward-declare the plugins.
+class TileSetPlugin;
+class TileSetPluginAtlasRendering;
+class TileSetPluginAtlasPhysics;
+class TileSetPluginAtlasNavigation;
+class TileSetPluginAtlasTerrain;
class TileSet : public Resource {
GDCLASS(TileSet, Resource);
-public:
- struct ShapeData {
+#ifndef DISABLE_DEPRECATED
+private:
+ struct CompatibilityShapeData {
+ Vector2i autotile_coords;
+ bool one_way;
+ float one_way_margin;
Ref<Shape2D> shape;
- Transform2D shape_transform;
- Vector2 autotile_coord;
- bool one_way_collision = false;
- float one_way_collision_margin = 1.0;
+ Transform2D transform;
+ };
- ShapeData() {}
+ struct CompatibilityTileData {
+ String name;
+ Ref<Texture2D> texture;
+ Vector2 tex_offset;
+ Ref<ShaderMaterial> material;
+ Rect2 region;
+ int tile_mode;
+ Color modulate;
+
+ // Atlas or autotiles data
+ int autotile_bitmask_mode;
+ Vector2 autotile_icon_coordinate;
+ Size2i autotile_tile_size = Size2i(16, 16);
+
+ int autotile_spacing;
+ Map<Vector2i, int> autotile_bitmask_flags;
+ Map<Vector2i, Ref<OccluderPolygon2D>> autotile_occluder_map;
+ Map<Vector2i, Ref<NavigationPolygon>> autotile_navpoly_map;
+ Map<Vector2i, int> autotile_priority_map;
+ Map<Vector2i, int> autotile_z_index_map;
+
+ Vector<CompatibilityShapeData> shapes;
+ Ref<OccluderPolygon2D> occluder;
+ Vector2 occluder_offset;
+ Ref<NavigationPolygon> navigation;
+ Vector2 navigation_offset;
+ int z_index;
};
- enum BitmaskMode {
- BITMASK_2X2,
- BITMASK_3X3_MINIMAL,
- BITMASK_3X3
+ Map<int, CompatibilityTileData *> compatibility_data = Map<int, CompatibilityTileData *>();
+ Map<int, int> compatibility_source_mapping = Map<int, int>();
+
+private:
+ void compatibility_conversion();
+
+public:
+ int compatibility_get_source_for_tile_id(int p_old_source) {
+ return compatibility_source_mapping[p_old_source];
};
- enum AutotileBindings {
- BIND_TOPLEFT = 1,
- BIND_TOP = 2,
- BIND_TOPRIGHT = 4,
- BIND_LEFT = 8,
- BIND_CENTER = 16,
- BIND_RIGHT = 32,
- BIND_BOTTOMLEFT = 64,
- BIND_BOTTOM = 128,
- BIND_BOTTOMRIGHT = 256,
-
- BIND_IGNORE_TOPLEFT = 1 << 16,
- BIND_IGNORE_TOP = 1 << 17,
- BIND_IGNORE_TOPRIGHT = 1 << 18,
- BIND_IGNORE_LEFT = 1 << 19,
- BIND_IGNORE_CENTER = 1 << 20,
- BIND_IGNORE_RIGHT = 1 << 21,
- BIND_IGNORE_BOTTOMLEFT = 1 << 22,
- BIND_IGNORE_BOTTOM = 1 << 23,
- BIND_IGNORE_BOTTOMRIGHT = 1 << 24
+#endif // DISABLE_DEPRECATED
+
+public:
+ enum CellNeighbor {
+ CELL_NEIGHBOR_RIGHT_SIDE = 0,
+ CELL_NEIGHBOR_RIGHT_CORNER,
+ CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE,
+ CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER,
+ CELL_NEIGHBOR_BOTTOM_SIDE,
+ CELL_NEIGHBOR_BOTTOM_CORNER,
+ CELL_NEIGHBOR_BOTTOM_LEFT_SIDE,
+ CELL_NEIGHBOR_BOTTOM_LEFT_CORNER,
+ CELL_NEIGHBOR_LEFT_SIDE,
+ CELL_NEIGHBOR_LEFT_CORNER,
+ CELL_NEIGHBOR_TOP_LEFT_SIDE,
+ CELL_NEIGHBOR_TOP_LEFT_CORNER,
+ CELL_NEIGHBOR_TOP_SIDE,
+ CELL_NEIGHBOR_TOP_CORNER,
+ CELL_NEIGHBOR_TOP_RIGHT_SIDE,
+ CELL_NEIGHBOR_TOP_RIGHT_CORNER,
+ CELL_NEIGHBOR_MAX,
};
- enum TileMode {
- SINGLE_TILE,
- AUTO_TILE,
- ATLAS_TILE
+ enum TerrainMode {
+ TERRAIN_MODE_MATCH_CORNERS_AND_SIDES = 0,
+ TERRAIN_MODE_MATCH_CORNERS,
+ TERRAIN_MODE_MATCH_SIDES,
};
- struct AutotileData {
- BitmaskMode bitmask_mode = BITMASK_2X2;
- // Default size to prevent invalid value
- Size2 size = Size2(64, 64);
- Vector2 icon_coord = Vector2(0, 0);
- int spacing = 0;
- Map<Vector2, uint32_t> flags;
- Map<Vector2, Ref<OccluderPolygon2D>> occluder_map;
- Map<Vector2, Ref<NavigationPolygon>> navpoly_map;
- Map<Vector2, int> priority_map;
- Map<Vector2, int> z_index_map;
-
- explicit AutotileData() {}
+ enum TileShape {
+ TILE_SHAPE_SQUARE,
+ TILE_SHAPE_ISOMETRIC,
+ TILE_SHAPE_HALF_OFFSET_SQUARE,
+ TILE_SHAPE_HEXAGON,
};
-private:
- struct TileData {
- String name;
- Ref<Texture2D> texture;
- Vector2 offset;
- Rect2i region;
- Vector<ShapeData> shapes_data;
- Vector2 occluder_offset;
- Ref<OccluderPolygon2D> occluder;
- Vector2 navigation_polygon_offset;
- Ref<NavigationPolygon> navigation_polygon;
- Ref<ShaderMaterial> material;
- TileMode tile_mode = SINGLE_TILE;
- // Default modulate for back-compat
- Color modulate = Color(1, 1, 1);
- AutotileData autotile_data;
- int z_index = 0;
+ enum TileLayout {
+ TILE_LAYOUT_STACKED,
+ TILE_LAYOUT_STACKED_OFFSET,
+ TILE_LAYOUT_STAIRS_RIGHT,
+ TILE_LAYOUT_STAIRS_DOWN,
+ TILE_LAYOUT_DIAMOND_RIGHT,
+ TILE_LAYOUT_DIAMOND_DOWN,
+ };
- explicit TileData() {}
+ enum TileOffsetAxis {
+ TILE_OFFSET_AXIS_HORIZONTAL,
+ TILE_OFFSET_AXIS_VERTICAL,
};
- Map<int, TileData> tile_map;
+public:
+ struct PackedSceneSource {
+ Ref<PackedScene> scene;
+ Vector2 offset;
+ };
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 _tile_set_shapes(int p_id, const Array &p_shapes);
- Array _tile_get_shapes(int p_id) const;
- Array _get_tiles_ids() const;
- void _decompose_convex_shape(Ref<Shape2D> p_shape);
+private:
+ // --- TileSet data ---
+ // Basic shape and layout.
+ TileShape tile_shape = TILE_SHAPE_SQUARE;
+ TileLayout tile_layout = TILE_LAYOUT_STACKED;
+ TileOffsetAxis tile_offset_axis = TILE_OFFSET_AXIS_HORIZONTAL;
+ Size2i tile_size = Size2i(16, 16); //Size2(64, 64);
+ Vector2 tile_skew = Vector2(0, 0);
+
+ // Rendering.
+ bool y_sorting = false;
+ bool uv_clipping = false;
+ struct OcclusionLayer {
+ uint32_t light_mask = 1;
+ bool sdf_collision = false;
+ };
+ Vector<OcclusionLayer> occlusion_layers;
+
+ // Physics
+ struct PhysicsLayer {
+ uint32_t collision_layer = 1;
+ uint32_t collision_mask = 1;
+ Ref<PhysicsMaterial> physics_material;
+ };
+ Vector<PhysicsLayer> physics_layers;
+
+ // Terrains
+ struct Terrain {
+ String name;
+ Color color;
+ };
+ struct TerrainSet {
+ TerrainMode mode = TERRAIN_MODE_MATCH_CORNERS_AND_SIDES;
+ Vector<Terrain> terrains;
+ };
+ Vector<TerrainSet> terrain_sets;
+
+ // Navigation
+ struct Navigationlayer {
+ uint32_t layers = 1;
+ };
+ Vector<Navigationlayer> navigation_layers;
+
+ // CustomData
+ struct CustomDataLayer {
+ String name;
+ Variant::Type type = Variant::NIL;
+ };
+ Vector<CustomDataLayer> custom_data_layers;
+ Map<String, int> custom_data_layers_by_name;
+
+ // Per Atlas source data.
+ Map<int, Ref<TileSetSource>> sources;
+ Vector<int> source_ids;
+ int next_source_id = 0;
+ // ---------------------
+
+ // Plugins themselves.
+ Vector<TileSetPlugin *> tile_set_plugins_vector;
+
+ void _compute_next_source_id();
+ void _source_changed();
+
+protected:
static void _bind_methods();
+public:
+ // --- Plugins ---
+ Vector<TileSetPlugin *> get_tile_set_atlas_plugins() const;
+
+ // --- Accessors for TileSet data ---
+
+ // -- Shape and layout --
+ void set_tile_shape(TileShape p_shape);
+ TileShape get_tile_shape() const;
+ void set_tile_layout(TileLayout p_layout);
+ TileLayout get_tile_layout() const;
+ void set_tile_offset_axis(TileOffsetAxis p_alignment);
+ TileOffsetAxis get_tile_offset_axis() const;
+ void set_tile_size(Size2i p_size);
+ Size2i get_tile_size() const;
+ void set_tile_skew(Vector2 p_skew);
+ Vector2 get_tile_skew() const;
+
+ // -- Sources management --
+ int get_next_source_id() const;
+ int get_source_count() const;
+ int get_source_id(int p_index) const;
+ int add_source(Ref<TileSetSource> p_tile_set_source, int p_source_id_override = -1);
+ void set_source_id(int p_source_id, int p_new_id);
+ void remove_source(int p_source_id);
+ bool has_source(int p_source_id) const;
+ Ref<TileSetSource> get_source(int p_source_id) const;
+
+ // Rendering
+ void set_y_sorting(bool p_y_sort);
+ bool is_y_sorting() const;
+
+ void set_uv_clipping(bool p_uv_clipping);
+ bool is_uv_clipping() const;
+
+ void set_occlusion_layers_count(int p_occlusion_layers_count);
+ int get_occlusion_layers_count() const;
+ void set_occlusion_layer_light_mask(int p_layer_index, int p_light_mask);
+ int get_occlusion_layer_light_mask(int p_layer_index) const;
+ void set_occlusion_layer_sdf_collision(int p_layer_index, int p_sdf_collision);
+ bool get_occlusion_layer_sdf_collision(int p_layer_index) const;
+
+ // Physics
+ void set_physics_layers_count(int p_physics_layers_count);
+ int get_physics_layers_count() const;
+ void set_physics_layer_collision_layer(int p_layer_index, uint32_t p_layer);
+ uint32_t get_physics_layer_collision_layer(int p_layer_index) const;
+ void set_physics_layer_collision_mask(int p_layer_index, uint32_t p_mask);
+ uint32_t get_physics_layer_collision_mask(int p_layer_index) const;
+ void set_physics_layer_physics_material(int p_layer_index, Ref<PhysicsMaterial> p_physics_material);
+ Ref<PhysicsMaterial> get_physics_layer_physics_material(int p_layer_index) const;
+
+ // Terrains
+ void set_terrain_sets_count(int p_terrains_sets_count);
+ int get_terrain_sets_count() const;
+ void set_terrain_set_mode(int p_terrain_set, TerrainMode p_terrain_mode);
+ TerrainMode get_terrain_set_mode(int p_terrain_set) const;
+ void set_terrains_count(int p_terrain_set, int p_terrains_count);
+ int get_terrains_count(int p_terrain_set) const;
+ void set_terrain_name(int p_terrain_set, int p_terrain_index, String p_name);
+ String get_terrain_name(int p_terrain_set, int p_terrain_index) const;
+ void set_terrain_color(int p_terrain_set, int p_terrain_index, Color p_color);
+ Color get_terrain_color(int p_terrain_set, int p_terrain_index) const;
+ bool is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const;
+
+ // Navigation
+ void set_navigation_layers_count(int p_navigation_layers_count);
+ int get_navigation_layers_count() const;
+ void set_navigation_layer_layers(int p_layer_index, uint32_t p_layers);
+ uint32_t get_navigation_layer_layers(int p_layer_index) const;
+
+ // Custom data
+ void set_custom_data_layers_count(int p_custom_data_layers_count);
+ int get_custom_data_layers_count() const;
+ int get_custom_data_layer_by_name(String p_value) const;
+ void set_custom_data_name(int p_layer_id, String p_value);
+ String get_custom_data_name(int p_layer_id) const;
+ void set_custom_data_type(int p_layer_id, Variant::Type p_value);
+ Variant::Type get_custom_data_type(int p_layer_id) const;
+
+ // Helpers
+ void draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>());
+
virtual void reset_state() override;
+ TileSet();
+ ~TileSet();
+};
+
+class TileSetSource : public Resource {
+ GDCLASS(TileSetSource, Resource);
+
+protected:
+ const TileSet *tile_set = nullptr;
+
+public:
+ static const Vector2i INVALID_ATLAS_COORDS; // Vector2i(-1, -1);
+ static const int INVALID_TILE_ALTERNATIVE; // -1;
+
+ // Not exposed.
+ virtual void set_tile_set(const TileSet *p_tile_set);
+ virtual void notify_tile_data_properties_should_change(){};
+ virtual void reset_state() override{};
+
+ // Tiles.
+ virtual int get_tiles_count() const = 0;
+ virtual Vector2i get_tile_id(int tile_index) const = 0;
+ virtual bool has_tile(Vector2i p_atlas_coords) const = 0;
+
+ // Alternative tiles.
+ virtual int get_alternative_tiles_count(const Vector2i p_atlas_coords) const = 0;
+ virtual int get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const = 0;
+ virtual bool has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const = 0;
+};
+
+class TileSetAtlasSource : public TileSetSource {
+ GDCLASS(TileSetAtlasSource, TileSetSource);
+
public:
- void create_tile(int p_id);
+ struct TileAlternativesData {
+ Vector2i size_in_atlas = Vector2i(1, 1);
+ Vector2i texture_offset;
+ Map<int, TileData *> alternatives;
+ Vector<int> alternatives_ids;
+ int next_alternative_id = 1;
+ };
- void autotile_set_bitmask_mode(int p_id, BitmaskMode p_mode);
- BitmaskMode autotile_get_bitmask_mode(int p_id) const;
+private:
+ Ref<Texture2D> texture;
+ Vector2i margins;
+ Vector2i separation;
+ Size2i texture_region_size = Size2i(16, 16);
- void tile_set_name(int p_id, const String &p_name);
- String tile_get_name(int p_id) const;
+ Map<Vector2i, TileAlternativesData> tiles;
+ Vector<Vector2i> tiles_ids;
+ Map<Vector2i, Vector2i> _coords_mapping_cache; // Maps any coordinate to the including tile
- void tile_set_texture(int p_id, const Ref<Texture2D> &p_texture);
- Ref<Texture2D> tile_get_texture(int p_id) const;
+ TileData *_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile);
+ const TileData *_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile) const;
- void tile_set_texture_offset(int p_id, const Vector2 &p_offset);
- Vector2 tile_get_texture_offset(int p_id) const;
+ void _compute_next_alternative_id(const Vector2i p_atlas_coords);
- void tile_set_region(int p_id, const Rect2 &p_region);
- Rect2 tile_get_region(int p_id) const;
+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 tile_set_tile_mode(int p_id, TileMode p_tile_mode);
- TileMode tile_get_tile_mode(int p_id) const;
+ static void _bind_methods();
- void autotile_set_icon_coordinate(int p_id, Vector2 coord);
- Vector2 autotile_get_icon_coordinate(int p_id) const;
+public:
+ // Not exposed.
+ virtual void set_tile_set(const TileSet *p_tile_set) override;
+ virtual void notify_tile_data_properties_should_change() override;
+ virtual void reset_state() override;
+
+ // Base properties.
+ void set_texture(Ref<Texture2D> p_texture);
+ Ref<Texture2D> get_texture() const;
+ void set_margins(Vector2i p_margins);
+ Vector2i get_margins() const;
+ void set_separation(Vector2i p_separation);
+ Vector2i get_separation() const;
+ void set_texture_region_size(Vector2i p_tile_size);
+ Vector2i get_texture_region_size() const;
+
+ // Base tiles.
+ void create_tile(const Vector2i p_atlas_coords, const Vector2i p_size = Vector2i(1, 1)); // Create a tile if it does not exists, or add alternative tile if it does.
+ void remove_tile(Vector2i p_atlas_coords); // Remove a tile. If p_tile_key.alternative_tile if different from 0, remove the alternative
+ virtual bool has_tile(Vector2i p_atlas_coords) const override;
+ bool can_move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords = INVALID_ATLAS_COORDS, Vector2i p_new_size = Vector2i(-1, -1)) const;
+ void move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords = INVALID_ATLAS_COORDS, Vector2i p_new_size = Vector2i(-1, -1));
+ Vector2i get_tile_size_in_atlas(Vector2i p_atlas_coords) const;
+
+ virtual int get_tiles_count() const override;
+ virtual Vector2i get_tile_id(int p_index) const override;
+
+ Vector2i get_tile_at_coords(Vector2i p_atlas_coords) const;
+
+ // Alternative tiles.
+ int create_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_id_override = -1);
+ void remove_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile);
+ void set_alternative_tile_id(const Vector2i p_atlas_coords, int p_alternative_tile, int p_new_id);
+ virtual bool has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const override;
+ int get_next_alternative_tile_id(const Vector2i p_atlas_coords) const;
+
+ virtual int get_alternative_tiles_count(const Vector2i p_atlas_coords) const override;
+ virtual int get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const override;
+
+ // Get data associated to a tile.
+ Object *get_tile_data(const Vector2i p_atlas_coords, int p_alternative_tile) const;
+
+ // Helpers.
+ Vector2i get_atlas_grid_size() const;
+ bool has_tiles_outside_texture();
+ void clear_tiles_outside_texture();
+ Rect2i get_tile_texture_region(Vector2i p_atlas_coords) const;
+ Vector2i get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const;
+
+ ~TileSetAtlasSource();
+};
+
+class TileSetScenesCollectionSource : public TileSetSource {
+ GDCLASS(TileSetScenesCollectionSource, TileSetSource);
+
+private:
+ struct SceneData {
+ Ref<PackedScene> scene;
+ bool display_placeholder = false;
+ };
+ Vector<int> scenes_ids;
+ Map<int, SceneData> scenes;
+ int next_scene_id = 1;
+
+ void _compute_next_alternative_id();
+
+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 autotile_set_spacing(int p_id, int p_spacing);
- int autotile_get_spacing(int p_id) const;
+ static void _bind_methods();
- void autotile_set_size(int p_id, Size2 p_size);
- Size2 autotile_get_size(int p_id) const;
+public:
+ // Tiles.
+ int get_tiles_count() const override;
+ Vector2i get_tile_id(int p_tile_index) const override;
+ bool has_tile(Vector2i p_atlas_coords) const override;
+
+ // Alternative tiles.
+ int get_alternative_tiles_count(const Vector2i p_atlas_coords) const override;
+ int get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const override;
+ bool has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const override;
+
+ // Scenes sccessors. Lot are similar to "Alternative tiles".
+ int get_scene_tiles_count() { return get_alternative_tiles_count(Vector2i()); }
+ int get_scene_tile_id(int p_index) { return get_alternative_tile_id(Vector2i(), p_index); };
+ bool has_scene_tile_id(int p_id) { return has_alternative_tile(Vector2i(), p_id); };
+ int create_scene_tile(Ref<PackedScene> p_packed_scene = Ref<PackedScene>(), int p_id_override = -1);
+ void set_scene_tile_id(int p_id, int p_new_id);
+ void set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene);
+ Ref<PackedScene> get_scene_tile_scene(int p_id) const;
+ void set_scene_tile_display_placeholder(int p_id, bool p_packed_scene);
+ bool get_scene_tile_display_placeholder(int p_id) const;
+ void remove_scene_tile(int p_id);
+ int get_next_scene_tile_id() const;
+};
- void autotile_clear_bitmask_map(int p_id);
- void autotile_set_subtile_priority(int p_id, const Vector2 &p_coord, int p_priority);
- int autotile_get_subtile_priority(int p_id, const Vector2 &p_coord);
- const Map<Vector2, int> &autotile_get_priority_map(int p_id) const;
+class TileData : public Object {
+ GDCLASS(TileData, Object);
- void autotile_set_z_index(int p_id, const Vector2 &p_coord, int p_z_index);
- int autotile_get_z_index(int p_id, const Vector2 &p_coord);
- const Map<Vector2, int> &autotile_get_z_index_map(int p_id) const;
+private:
+ const TileSet *tile_set = nullptr;
+ bool allow_transform = true;
+
+ // Rendering
+ bool flip_h = false;
+ bool flip_v = false;
+ bool transpose = false;
+ Vector2i tex_offset = Vector2i();
+ Ref<ShaderMaterial> material = Ref<ShaderMaterial>();
+ Color modulate = Color(1.0, 1.0, 1.0, 1.0);
+ int z_index = 0;
+ int y_sort_origin = 0;
+ Vector<Ref<OccluderPolygon2D>> occluders;
+
+ // Physics
+ struct PhysicsLayerTileData {
+ struct ShapeTileData {
+ Ref<Shape2D> shape = Ref<Shape2D>();
+ bool one_way = false;
+ float one_way_margin = 1.0;
+ };
+
+ Vector<ShapeTileData> shapes;
+ };
+ Vector<PhysicsLayerTileData> physics;
+ // TODO add support for areas.
- 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 = 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());
+ // Terrain
+ int terrain_set = -1;
+ int terrain_peering_bits[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
- 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;
+ // Navigation
+ Vector<Ref<NavigationPolygon>> navigation;
- void tile_set_shape_transform(int p_id, int p_shape_id, const Transform2D &p_offset);
- Transform2D tile_get_shape_transform(int p_id, int p_shape_id) const;
+ // Misc
+ double probability = 1.0;
- void tile_set_shape_offset(int p_id, int p_shape_id, const Vector2 &p_offset);
- Vector2 tile_get_shape_offset(int p_id, int p_shape_id) const;
+ // Custom data
+ Vector<Variant> custom_data;
- void tile_set_shape_one_way(int p_id, int p_shape_id, bool p_one_way);
- bool tile_get_shape_one_way(int p_id, int p_shape_id) const;
+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;
+ static void _bind_methods();
- void tile_set_shape_one_way_margin(int p_id, int p_shape_id, float p_margin);
- float tile_get_shape_one_way_margin(int p_id, int p_shape_id) const;
+public:
+ // Not exposed.
+ void set_tile_set(const TileSet *p_tile_set);
+ void notify_tile_data_properties_should_change();
+ void reset_state();
+ void set_allow_transform(bool p_allow_transform);
+ bool is_allowing_transform() const;
+
+ // Rendering
+ void set_flip_h(bool p_flip_h);
+ bool get_flip_h() const;
+ void set_flip_v(bool p_flip_v);
+ bool get_flip_v() const;
+ void set_transpose(bool p_transpose);
+ bool get_transpose() const;
+
+ void set_texture_offset(Vector2i p_texture_offset);
+ Vector2i get_texture_offset() const;
+ void tile_set_material(Ref<ShaderMaterial> p_material);
+ Ref<ShaderMaterial> tile_get_material() const;
+ void set_modulate(Color p_modulate);
+ Color get_modulate() const;
+ void set_z_index(int p_z_index);
+ int get_z_index() const;
+ void set_y_sort_origin(int p_y_sort_origin);
+ int get_y_sort_origin() const;
+
+ void set_occluder(int p_layer_id, Ref<OccluderPolygon2D> p_occluder_polygon);
+ Ref<OccluderPolygon2D> get_occluder(int p_layer_id) const;
+
+ // Physics
+ int get_collision_shapes_count(int p_layer_id) const;
+ void set_collision_shapes_count(int p_layer_id, int p_shapes_count);
+ void add_collision_shape(int p_layer_id);
+ void remove_collision_shape(int p_layer_id, int p_shape_index);
+ void set_collision_shape_shape(int p_layer_id, int p_shape_index, Ref<Shape2D> p_shape);
+ Ref<Shape2D> get_collision_shape_shape(int p_layer_id, int p_shape_index) const;
+ void set_collision_shape_one_way(int p_layer_id, int p_shape_index, bool p_one_way);
+ bool is_collision_shape_one_way(int p_layer_id, int p_shape_index) const;
+ void set_collision_shape_one_way_margin(int p_layer_id, int p_shape_index, float p_one_way_margin);
+ float get_collision_shape_one_way_margin(int p_layer_id, int p_shape_index) const;
+
+ // Terrain
+ void set_terrain_set(int p_terrain_id);
+ int get_terrain_set() const;
+ void set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_id);
+ int get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const;
+ bool is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const;
+
+ // Navigation
+ void set_navigation_polygon(int p_layer_id, Ref<NavigationPolygon> p_navigation_polygon);
+ Ref<NavigationPolygon> get_navigation_polygon(int p_layer_id) const;
+
+ // Misc
+ void set_probability(float p_probability);
+ float get_probability() const;
+
+ // Custom data.
+ void set_custom_data(String p_layer_name, Variant p_value);
+ Variant get_custom_data(String p_layer_name) const;
+ void set_custom_data_by_layer_id(int p_layer_id, Variant p_value);
+ Variant get_custom_data_by_layer_id(int p_layer_id) const;
+};
- void tile_clear_shapes(int p_id);
- void tile_add_shape(int p_id, const Ref<Shape2D> &p_shape, const Transform2D &p_transform, bool p_one_way = false, const Vector2 &p_autotile_coord = Vector2());
- int tile_get_shape_count(int p_id) const;
+#include "scene/2d/tile_map.h"
- void tile_set_shapes(int p_id, const Vector<ShapeData> &p_shapes);
- Vector<ShapeData> tile_get_shapes(int p_id) const;
+class TileSetPlugin : public Object {
+ GDCLASS(TileSetPlugin, Object);
- void tile_set_material(int p_id, const Ref<ShaderMaterial> &p_material);
- Ref<ShaderMaterial> tile_get_material(int p_id) const;
+public:
+ // Tilemap updates.
+ virtual void tilemap_notification(TileMap *p_tile_map, int p_what){};
+ virtual void update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list){};
+ virtual void create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant){};
+ virtual void cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant){};
- void tile_set_modulate(int p_id, const Color &p_modulate);
- Color tile_get_modulate(int p_id) const;
+ virtual void draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant){};
+};
- void tile_set_occluder_offset(int p_id, const Vector2 &p_offset);
- Vector2 tile_get_occluder_offset(int p_id) const;
+class TileSetPluginAtlasRendering : public TileSetPlugin {
+ GDCLASS(TileSetPluginAtlasRendering, TileSetPlugin);
- void tile_set_light_occluder(int p_id, const Ref<OccluderPolygon2D> &p_light_occluder);
- Ref<OccluderPolygon2D> tile_get_light_occluder(int p_id) const;
+private:
+ static constexpr float fp_adjust = 0.00001;
+ bool quadrant_order_dirty = false;
- 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;
+public:
+ // Tilemap updates
+ virtual void tilemap_notification(TileMap *p_tile_map, int p_what) override;
+ virtual void update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) override;
+ virtual void create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override;
+ virtual void cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override;
+ virtual void draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override;
+
+ // Other.
+ static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0));
+};
- void tile_set_navigation_polygon_offset(int p_id, const Vector2 &p_offset);
- Vector2 tile_get_navigation_polygon_offset(int p_id) const;
+class TileSetPluginAtlasTerrain : public TileSetPlugin {
+ GDCLASS(TileSetPluginAtlasTerrain, TileSetPlugin);
- void tile_set_navigation_polygon(int p_id, const Ref<NavigationPolygon> &p_navigation_polygon);
- Ref<NavigationPolygon> tile_get_navigation_polygon(int p_id) const;
+private:
+ static void _draw_square_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit);
+ static void _draw_square_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit);
+ static void _draw_square_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit);
- 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;
+ static void _draw_isometric_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit);
+ static void _draw_isometric_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit);
+ static void _draw_isometric_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit);
- void tile_set_z_index(int p_id, int p_z_index);
- int tile_get_z_index(int p_id) const;
+ static void _draw_half_offset_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
+ static void _draw_half_offset_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
+ static void _draw_half_offset_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis);
- void remove_tile(int p_id);
+public:
+ static void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, const TileData *p_tile_data);
+};
- bool has_tile(int p_id) const;
+class TileSetPluginAtlasPhysics : public TileSetPlugin {
+ GDCLASS(TileSetPluginAtlasPhysics, TileSetPlugin);
- bool is_tile_bound(int p_drawn_id, int p_neighbor_id);
+public:
+ // Tilemap updates
+ virtual void tilemap_notification(TileMap *p_tile_map, int p_what) override;
+ virtual void update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) override;
+ virtual void create_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override;
+ virtual void cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override;
+ virtual void draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override;
+};
- int find_tile_by_name(const String &p_name) const;
- void get_tile_list(List<int> *p_tiles) const;
+class TileSetPluginAtlasNavigation : public TileSetPlugin {
+ GDCLASS(TileSetPluginAtlasNavigation, TileSetPlugin);
- void clear();
+public:
+ // Tilemap updates
+ virtual void tilemap_notification(TileMap *p_tile_map, int p_what) override;
+ virtual void update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) override;
+ virtual void cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override;
+ virtual void draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override;
+};
- int get_last_unused_tile_id() const;
+class TileSetPluginScenesCollections : public TileSetPlugin {
+ GDCLASS(TileSetPluginScenesCollections, TileSetPlugin);
- TileSet();
+public:
+ // Tilemap updates
+ virtual void update_dirty_quadrants(TileMap *p_tile_map, SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) override;
+ virtual void cleanup_quadrant(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override;
+ virtual void draw_quadrant_debug(TileMap *p_tile_map, TileMapQuadrant *p_quadrant) override;
};
-VARIANT_ENUM_CAST(TileSet::AutotileBindings);
-VARIANT_ENUM_CAST(TileSet::BitmaskMode);
-VARIANT_ENUM_CAST(TileSet::TileMode);
+VARIANT_ENUM_CAST(TileSet::CellNeighbor);
+VARIANT_ENUM_CAST(TileSet::TerrainMode);
+VARIANT_ENUM_CAST(TileSet::TileShape);
+VARIANT_ENUM_CAST(TileSet::TileLayout);
+VARIANT_ENUM_CAST(TileSet::TileOffsetAxis);
#endif // TILE_SET_H
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index d09cf4b971..5759948fe6 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -33,6 +33,7 @@
#include "core/templates/vmap.h"
#include "servers/rendering/shader_types.h"
#include "visual_shader_nodes.h"
+#include "visual_shader_particle_nodes.h"
#include "visual_shader_sdf_nodes.h"
bool VisualShaderNode::is_simple_decl() const {
@@ -60,6 +61,20 @@ Variant VisualShaderNode::get_input_port_default_value(int p_port) const {
return Variant();
}
+void VisualShaderNode::remove_input_port_default_value(int p_port) {
+ if (default_input_values.has(p_port)) {
+ default_input_values.erase(p_port);
+ emit_changed();
+ }
+}
+
+void VisualShaderNode::clear_default_input_values() {
+ if (!default_input_values.is_empty()) {
+ default_input_values.clear();
+ emit_changed();
+ }
+}
+
bool VisualShaderNode::is_port_separator(int p_index) const {
return false;
}
@@ -94,6 +109,52 @@ bool VisualShaderNode::is_generate_input_var(int p_port) const {
return true;
}
+bool VisualShaderNode::is_output_port_expandable(int p_port) const {
+ return false;
+}
+
+void VisualShaderNode::_set_output_ports_expanded(const Array &p_values) {
+ for (int i = 0; i < p_values.size(); i++) {
+ expanded_output_ports[p_values[i]] = true;
+ }
+ emit_changed();
+}
+
+Array VisualShaderNode::_get_output_ports_expanded() const {
+ Array arr;
+ for (int i = 0; i < get_output_port_count(); i++) {
+ if (_is_output_port_expanded(i)) {
+ arr.push_back(i);
+ }
+ }
+ return arr;
+}
+
+void VisualShaderNode::_set_output_port_expanded(int p_port, bool p_expanded) {
+ expanded_output_ports[p_port] = p_expanded;
+ emit_changed();
+}
+
+bool VisualShaderNode::_is_output_port_expanded(int p_port) const {
+ if (expanded_output_ports.has(p_port)) {
+ return expanded_output_ports[p_port];
+ }
+ return false;
+}
+
+int VisualShaderNode::get_expanded_output_port_count() const {
+ int count = get_output_port_count();
+ int count2 = count;
+ for (int i = 0; i < count; i++) {
+ if (is_output_port_expandable(i) && _is_output_port_expanded(i)) {
+ if (get_output_port_type(i) == PORT_TYPE_VECTOR) {
+ count2 += 3;
+ }
+ }
+ }
+ return count2;
+}
+
bool VisualShaderNode::is_code_generated() const {
return true;
}
@@ -106,6 +167,14 @@ bool VisualShaderNode::is_use_prop_slots() const {
return false;
}
+bool VisualShaderNode::is_disabled() const {
+ return disabled;
+}
+
+void VisualShaderNode::set_disabled(bool p_disabled) {
+ disabled = p_disabled;
+}
+
Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
return Vector<VisualShader::DefaultTextureParam>();
}
@@ -157,14 +226,24 @@ void VisualShaderNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_output_port_for_preview", "port"), &VisualShaderNode::set_output_port_for_preview);
ClassDB::bind_method(D_METHOD("get_output_port_for_preview"), &VisualShaderNode::get_output_port_for_preview);
+ ClassDB::bind_method(D_METHOD("_set_output_port_expanded", "port"), &VisualShaderNode::_set_output_port_expanded);
+ ClassDB::bind_method(D_METHOD("_is_output_port_expanded"), &VisualShaderNode::_is_output_port_expanded);
+
+ ClassDB::bind_method(D_METHOD("_set_output_ports_expanded", "values"), &VisualShaderNode::_set_output_ports_expanded);
+ ClassDB::bind_method(D_METHOD("_get_output_ports_expanded"), &VisualShaderNode::_get_output_ports_expanded);
+
ClassDB::bind_method(D_METHOD("set_input_port_default_value", "port", "value"), &VisualShaderNode::set_input_port_default_value);
ClassDB::bind_method(D_METHOD("get_input_port_default_value", "port"), &VisualShaderNode::get_input_port_default_value);
+ ClassDB::bind_method(D_METHOD("remove_input_port_default_value", "port"), &VisualShaderNode::remove_input_port_default_value);
+ ClassDB::bind_method(D_METHOD("clear_default_input_values"), &VisualShaderNode::clear_default_input_values);
+
ClassDB::bind_method(D_METHOD("set_default_input_values", "values"), &VisualShaderNode::set_default_input_values);
ClassDB::bind_method(D_METHOD("get_default_input_values"), &VisualShaderNode::get_default_input_values);
ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_default_input_values", "get_default_input_values");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "expanded_output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_output_ports_expanded", "_get_output_ports_expanded");
ADD_SIGNAL(MethodInfo("editor_refresh_request"));
BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR);
@@ -300,6 +379,42 @@ String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, Vis
return "";
}
+void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value) {
+ if (!is_initialized) {
+ VisualShaderNode::set_input_port_default_value(p_port, p_value);
+ }
+}
+
+void VisualShaderNodeCustom::set_default_input_values(const Array &p_values) {
+ if (!is_initialized) {
+ VisualShaderNode::set_default_input_values(p_values);
+ }
+}
+
+void VisualShaderNodeCustom::remove_input_port_default_value(int p_port) {
+ if (!is_initialized) {
+ VisualShaderNode::remove_input_port_default_value(p_port);
+ }
+}
+
+void VisualShaderNodeCustom::clear_default_input_values() {
+ if (!is_initialized) {
+ VisualShaderNode::clear_default_input_values();
+ }
+}
+
+void VisualShaderNodeCustom::_set_input_port_default_value(int p_port, const Variant &p_value) {
+ VisualShaderNode::set_input_port_default_value(p_port, p_value);
+}
+
+bool VisualShaderNodeCustom::_is_initialized() {
+ return is_initialized;
+}
+
+void VisualShaderNodeCustom::_set_initialized(bool p_enabled) {
+ is_initialized = p_enabled;
+}
+
void VisualShaderNodeCustom::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_name"));
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_description"));
@@ -314,6 +429,12 @@ void VisualShaderNodeCustom::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_code", PropertyInfo(Variant::ARRAY, "input_vars"), PropertyInfo(Variant::ARRAY, "output_vars"), PropertyInfo(Variant::INT, "mode"), PropertyInfo(Variant::INT, "type")));
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_global_code", PropertyInfo(Variant::INT, "mode")));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_highend"));
+
+ ClassDB::bind_method(D_METHOD("_set_initialized", "enabled"), &VisualShaderNodeCustom::_set_initialized);
+ ClassDB::bind_method(D_METHOD("_is_initialized"), &VisualShaderNodeCustom::_is_initialized);
+ ClassDB::bind_method(D_METHOD("_set_input_port_default_value", "port", "value"), &VisualShaderNodeCustom::_set_input_port_default_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "initialized", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_initialized", "_is_initialized");
}
VisualShaderNodeCustom::VisualShaderNodeCustom() {
@@ -546,7 +667,7 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po
return false;
}
- if (p_from_port < 0 || p_from_port >= g->nodes[p_from_node].node->get_output_port_count()) {
+ if (p_from_port < 0 || p_from_port >= g->nodes[p_from_node].node->get_expanded_output_port_count()) {
return false;
}
@@ -587,7 +708,7 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from
Graph *g = &graph[p_type];
ERR_FAIL_COND(!g->nodes.has(p_from_node));
- ERR_FAIL_INDEX(p_from_port, g->nodes[p_from_node].node->get_output_port_count());
+ ERR_FAIL_INDEX(p_from_port, g->nodes[p_from_node].node->get_expanded_output_port_count());
ERR_FAIL_COND(!g->nodes.has(p_to_node));
ERR_FAIL_INDEX(p_to_port, g->nodes[p_to_node].node->get_input_port_count());
@@ -609,7 +730,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
Graph *g = &graph[p_type];
ERR_FAIL_COND_V(!g->nodes.has(p_from_node), ERR_INVALID_PARAMETER);
- ERR_FAIL_INDEX_V(p_from_port, g->nodes[p_from_node].node->get_output_port_count(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_INDEX_V(p_from_port, g->nodes[p_from_node].node->get_expanded_output_port_count(), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(!g->nodes.has(p_to_node), ERR_INVALID_PARAMETER);
ERR_FAIL_INDEX_V(p_to_port, g->nodes[p_to_node].node->get_input_port_count(), ERR_INVALID_PARAMETER);
@@ -760,7 +881,7 @@ bool VisualShader::is_text_shader() const {
String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &default_tex_params) const {
Ref<VisualShaderNode> node = get_node(p_type, p_node);
ERR_FAIL_COND_V(!node.is_valid(), String());
- ERR_FAIL_COND_V(p_port < 0 || p_port >= node->get_output_port_count(), String());
+ ERR_FAIL_COND_V(p_port < 0 || p_port >= node->get_expanded_output_port_count(), String());
ERR_FAIL_COND_V(node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_TRANSFORM, String());
StringBuilder global_code;
@@ -959,9 +1080,11 @@ static const char *type_string[VisualShader::TYPE_MAX] = {
"vertex",
"fragment",
"light",
- "emit",
+ "start",
"process",
- "end",
+ "collide",
+ "start_custom",
+ "process_custom",
"sky",
};
@@ -1177,6 +1300,12 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBuilder &global_code_per_node, Map<Type, StringBuilder> &global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const {
const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node;
+ if (vsnode->is_disabled()) {
+ code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
+ code += "\t// Node is disabled and code is not generated.\n";
+ return OK;
+ }
+
//check inputs recursively first
int input_count = vsnode->get_input_port_count();
for (int i = 0; i < input_count; i++) {
@@ -1231,7 +1360,8 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
return OK;
}
- code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
+ String node_name = "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
+ String node_code;
Vector<String> input_vars;
input_vars.resize(vsnode->get_input_port_count());
@@ -1245,6 +1375,11 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
if (input_connections.has(ck)) {
//connected to something, use that output
int from_node = input_connections[ck]->get().from_node;
+
+ if (graph[type].nodes[from_node].node->is_disabled()) {
+ continue;
+ }
+
int from_port = input_connections[ck]->get().from_port;
VisualShaderNode::PortType in_type = vsnode->get_input_port_type(i);
@@ -1297,21 +1432,21 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
if (defval.get_type() == Variant::FLOAT) {
float val = defval;
inputs[i] = "n_in" + itos(node) + "p" + itos(i);
- code += "\tfloat " + inputs[i] + " = " + vformat("%.5f", val) + ";\n";
+ node_code += "\tfloat " + inputs[i] + " = " + vformat("%.5f", val) + ";\n";
} else if (defval.get_type() == Variant::INT) {
int val = defval;
inputs[i] = "n_in" + itos(node) + "p" + itos(i);
- code += "\tint " + inputs[i] + " = " + itos(val) + ";\n";
+ node_code += "\tint " + inputs[i] + " = " + itos(val) + ";\n";
} else if (defval.get_type() == Variant::BOOL) {
bool val = defval;
inputs[i] = "n_in" + itos(node) + "p" + itos(i);
- code += "\tbool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n";
+ node_code += "\tbool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n";
} else if (defval.get_type() == Variant::VECTOR3) {
Vector3 val = defval;
inputs[i] = "n_in" + itos(node) + "p" + itos(i);
- code += "\tvec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z);
- } else if (defval.get_type() == Variant::TRANSFORM) {
- Transform val = defval;
+ node_code += "\tvec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z);
+ } else if (defval.get_type() == Variant::TRANSFORM3D) {
+ Transform3D val = defval;
val.basis.transpose();
inputs[i] = "n_in" + itos(node) + "p" + itos(i);
Array values;
@@ -1324,7 +1459,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
values.push_back(val.origin.y);
values.push_back(val.origin.z);
bool err = false;
- code += "\tmat4 " + inputs[i] + " = " + String("mat4(vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 1.0));\n").sprintf(values, &err);
+ node_code += "\tmat4 " + inputs[i] + " = " + String("mat4(vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 1.0));\n").sprintf(values, &err);
} else {
//will go empty, node is expected to know what it is doing at this point and handle it
}
@@ -1332,13 +1467,30 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
}
int output_count = vsnode->get_output_port_count();
+ int initial_output_count = output_count;
+
+ Map<int, bool> expanded_output_ports;
+
+ for (int i = 0; i < initial_output_count; i++) {
+ bool expanded = false;
+
+ if (vsnode->is_output_port_expandable(i) && vsnode->_is_output_port_expanded(i)) {
+ expanded = true;
+
+ if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) {
+ output_count += 3;
+ }
+ }
+ expanded_output_ports.insert(i, expanded);
+ }
+
Vector<String> output_vars;
- output_vars.resize(vsnode->get_output_port_count());
+ output_vars.resize(output_count);
String *outputs = output_vars.ptrw();
if (vsnode->is_simple_decl()) { // less code to generate for some simple_decl nodes
- for (int i = 0; i < output_count; i++) {
- String var_name = "n_out" + itos(node) + "p" + itos(i);
+ for (int i = 0, j = 0; i < initial_output_count; i++, j++) {
+ String var_name = "n_out" + itos(node) + "p" + itos(j);
switch (vsnode->get_output_port_type(i)) {
case VisualShaderNode::PORT_TYPE_SCALAR:
outputs[i] = "float " + var_name;
@@ -1358,34 +1510,88 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
default: {
}
}
+ if (expanded_output_ports[i]) {
+ if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) {
+ j += 3;
+ }
+ }
}
} else {
- for (int i = 0; i < output_count; i++) {
- outputs[i] = "n_out" + itos(node) + "p" + itos(i);
+ for (int i = 0, j = 0; i < initial_output_count; i++, j++) {
+ outputs[i] = "n_out" + itos(node) + "p" + itos(j);
switch (vsnode->get_output_port_type(i)) {
case VisualShaderNode::PORT_TYPE_SCALAR:
- code += String() + "\tfloat " + outputs[i] + ";\n";
+ code += "\tfloat " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_SCALAR_INT:
- code += String() + "\tint " + outputs[i] + ";\n";
+ code += "\tint " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_VECTOR:
- code += String() + "\tvec3 " + outputs[i] + ";\n";
+ code += "\tvec3 " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_BOOLEAN:
- code += String() + "\tbool " + outputs[i] + ";\n";
+ code += "\tbool " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_TRANSFORM:
- code += String() + "\tmat4 " + outputs[i] + ";\n";
+ code += "\tmat4 " + outputs[i] + ";\n";
break;
default: {
}
}
+ if (expanded_output_ports[i]) {
+ if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) {
+ j += 3;
+ }
+ }
}
}
- code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview);
+ node_code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview);
+ if (node_code != String()) {
+ code += node_name;
+ code += node_code;
+ code += "\n";
+ }
+
+ for (int i = 0; i < output_count; i++) {
+ bool new_line_inserted = false;
+ if (expanded_output_ports[i]) {
+ if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) {
+ if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
+ if (!new_line_inserted) {
+ code += "\n";
+ new_line_inserted = true;
+ }
+ String r = "n_out" + itos(node) + "p" + itos(i + 1);
+ code += "\tfloat " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n";
+ outputs[i + 1] = r;
+ }
+
+ if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
+ if (!new_line_inserted) {
+ code += "\n";
+ new_line_inserted = true;
+ }
+ String g = "n_out" + itos(node) + "p" + itos(i + 2);
+ code += "\tfloat " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n";
+ outputs[i + 2] = g;
+ }
+
+ if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
+ if (!new_line_inserted) {
+ code += "\n";
+ new_line_inserted = true;
+ }
+ String b = "n_out" + itos(node) + "p" + itos(i + 3);
+ code += "\tfloat " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n";
+ outputs[i + 3] = b;
+ }
+
+ i += 3;
+ }
+ }
+ }
code += "\n"; //
processed.insert(node);
@@ -1396,7 +1602,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
bool VisualShader::has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const {
if (!ShaderTypes::get_singleton()->get_functions(p_mode).has(p_func_name)) {
if (p_mode == RenderingServer::ShaderMode::SHADER_PARTICLES) {
- if (p_func_name == "emit" || p_func_name == "process" || p_func_name == "end") {
+ if (p_func_name == "start_custom" || p_func_name == "process_custom" || p_func_name == "collide") {
return true;
}
}
@@ -1477,11 +1683,12 @@ void VisualShader::_update_shader() const {
global_code += "render_mode " + render_mode + ";\n\n";
}
- static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "emit", "process", "end", "sky" };
+ static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky" };
String global_expressions;
Set<String> used_uniform_names;
List<VisualShaderNodeUniform *> uniforms;
+ Map<int, List<int>> emitters;
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
@@ -1506,6 +1713,19 @@ void VisualShader::_update_shader() const {
if (uniform.is_valid()) {
uniforms.push_back(uniform.ptr());
}
+ Ref<VisualShaderNodeParticleEmit> emit_particle = Object::cast_to<VisualShaderNodeParticleEmit>(E->get().node.ptr());
+ if (emit_particle.is_valid()) {
+ if (!emitters.has(i)) {
+ emitters.insert(i, List<int>());
+ }
+
+ for (Map<int, Node>::Element *M = graph[i].nodes.front(); M; M = M->next()) {
+ if (M->get().node == emit_particle.ptr()) {
+ emitters[i].push_back(M->key());
+ break;
+ }
+ }
+ }
}
}
@@ -1554,6 +1774,13 @@ void VisualShader::_update_shader() const {
Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes);
ERR_FAIL_COND(err != OK);
+ if (emitters.has(i)) {
+ for (List<int>::Element *E = emitters[i].front(); E; E = E->next()) {
+ err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, E->get(), processed, false, classes);
+ ERR_FAIL_COND(err != OK);
+ }
+ }
+
if (shader_mode == Shader::MODE_PARTICLES) {
code_map.insert(i, func_code);
} else {
@@ -1562,19 +1789,130 @@ void VisualShader::_update_shader() const {
}
}
+ String global_compute_code;
+
if (shader_mode == Shader::MODE_PARTICLES) {
- code += "\nvoid compute() {\n";
- code += "\tif (RESTART) {\n";
- code += code_map[TYPE_EMIT];
- code += "\t} else {\n";
- code += code_map[TYPE_PROCESS];
+ bool has_start = !code_map[TYPE_START].is_empty();
+ bool has_start_custom = !code_map[TYPE_START_CUSTOM].is_empty();
+ bool has_process = !code_map[TYPE_PROCESS].is_empty();
+ bool has_process_custom = !code_map[TYPE_PROCESS_CUSTOM].is_empty();
+ bool has_collide = !code_map[TYPE_COLLIDE].is_empty();
+
+ code += "void start() {\n";
+ if (has_start || has_start_custom) {
+ code += "\tuint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
+ code += "\tvec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n";
+ code += "\tfloat __radians;\n";
+ code += "\tvec3 __vec3_buff1;\n";
+ code += "\tvec3 __vec3_buff2;\n";
+ code += "\tfloat __scalar_buff1;\n";
+ code += "\tfloat __scalar_buff2;\n";
+ code += "\tvec3 __ndiff = normalize(__diff);\n\n";
+ }
+ if (has_start) {
+ code += "\t{\n";
+ code += code_map[TYPE_START].replace("\n\t", "\n\t\t");
+ code += "\t}\n";
+ if (has_start_custom) {
+ code += "\t\n";
+ }
+ }
+ if (has_start_custom) {
+ code += "\t{\n";
+ code += code_map[TYPE_START_CUSTOM].replace("\n\t", "\n\t\t");
+ code += "\t}\n";
+ }
+ code += "}\n\n";
+ code += "void process() {\n";
+ if (has_process || has_process_custom || has_collide) {
+ code += "\tuint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
+ code += "\tvec3 __vec3_buff1;\n";
+ code += "\tvec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n";
+ code += "\tvec3 __ndiff = normalize(__diff);\n\n";
+ }
+ code += "\t{\n";
+ String tab = "\t";
+ if (has_collide) {
+ code += "\t\tif (COLLIDED) {\n\n";
+ code += code_map[TYPE_COLLIDE].replace("\n\t", "\n\t\t\t");
+ if (has_process) {
+ code += "\t\t} else {\n\n";
+ tab += "\t";
+ }
+ }
+ if (has_process) {
+ code += code_map[TYPE_PROCESS].replace("\n\t", "\n\t" + tab);
+ }
+ if (has_collide) {
+ code += "\t\t}\n";
+ }
code += "\t}\n";
- code += "}\n";
+
+ if (has_process_custom) {
+ code += "\t{\n\n";
+ code += code_map[TYPE_PROCESS_CUSTOM].replace("\n\t", "\n\t\t");
+ code += "\t}\n";
+ }
+
+ code += "}\n\n";
+
+ global_compute_code += "float __rand_from_seed(inout uint seed) {\n";
+ global_compute_code += "\tint k;\n";
+ global_compute_code += "\tint s = int(seed);\n";
+ global_compute_code += "\tif (s == 0)\n";
+ global_compute_code += "\ts = 305420679;\n";
+ global_compute_code += "\tk = s / 127773;\n";
+ global_compute_code += "\ts = 16807 * (s - k * 127773) - 2836 * k;\n";
+ global_compute_code += "\tif (s < 0)\n";
+ global_compute_code += "\t\ts += 2147483647;\n";
+ global_compute_code += "\tseed = uint(s);\n";
+ global_compute_code += "\treturn float(seed % uint(65536)) / 65535.0;\n";
+ global_compute_code += "}\n\n";
+
+ global_compute_code += "float __rand_from_seed_m1_p1(inout uint seed) {\n";
+ global_compute_code += "\treturn __rand_from_seed(seed) * 2.0 - 1.0;\n";
+ global_compute_code += "}\n\n";
+
+ global_compute_code += "float __randf_range(inout uint seed, float from, float to) {\n";
+ global_compute_code += "\treturn __rand_from_seed(seed) * (to - from) + from;\n";
+ global_compute_code += "}\n\n";
+
+ global_compute_code += "vec3 __randv_range(inout uint seed, vec3 from, vec3 to) {\n";
+ global_compute_code += "\treturn vec3(__randf_range(seed, from.x, to.x), __randf_range(seed, from.y, to.y), __randf_range(seed, from.z, to.z));\n";
+ global_compute_code += "}\n\n";
+
+ global_compute_code += "uint __hash(uint x) {\n";
+ global_compute_code += "\tx = ((x >> uint(16)) ^ x) * uint(73244475);\n";
+ global_compute_code += "\tx = ((x >> uint(16)) ^ x) * uint(73244475);\n";
+ global_compute_code += "\tx = (x >> uint(16)) ^ x;\n";
+ global_compute_code += "\treturn x;\n";
+ global_compute_code += "}\n\n";
+
+ global_compute_code += "mat3 __build_rotation_mat3(vec3 axis, float angle) {\n";
+ global_compute_code += "\taxis = normalize(axis);\n";
+ global_compute_code += "\tfloat s = sin(angle);\n";
+ global_compute_code += "\tfloat c = cos(angle);\n";
+ global_compute_code += "\tfloat oc = 1.0 - c;\n";
+ global_compute_code += "\treturn mat3(vec3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s), vec3(oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s), vec3(oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c));\n";
+ global_compute_code += "}\n\n";
+
+ global_compute_code += "mat4 __build_rotation_mat4(vec3 axis, float angle) {\n";
+ global_compute_code += "\taxis = normalize(axis);\n";
+ global_compute_code += "\tfloat s = sin(angle);\n";
+ global_compute_code += "\tfloat c = cos(angle);\n";
+ global_compute_code += "\tfloat oc = 1.0 - c;\n";
+ global_compute_code += "\treturn mat4(vec4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0), vec4(oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0), vec4(oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0), vec4(0, 0, 0, 1));\n";
+ global_compute_code += "}\n\n";
+
+ global_compute_code += "vec3 __get_random_unit_vec3(inout uint seed) {\n";
+ global_compute_code += "\treturn normalize(vec3(__rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed)));\n";
+ global_compute_code += "}\n\n";
}
//set code secretly
global_code += "\n\n";
String final_code = global_code;
+ final_code += global_compute_code;
final_code += global_code_per_node;
final_code += global_expressions;
String tcode = code;
@@ -1665,9 +2003,11 @@ void VisualShader::_bind_methods() {
BIND_ENUM_CONSTANT(TYPE_VERTEX);
BIND_ENUM_CONSTANT(TYPE_FRAGMENT);
BIND_ENUM_CONSTANT(TYPE_LIGHT);
- BIND_ENUM_CONSTANT(TYPE_EMIT);
+ BIND_ENUM_CONSTANT(TYPE_START);
BIND_ENUM_CONSTANT(TYPE_PROCESS);
- BIND_ENUM_CONSTANT(TYPE_END);
+ BIND_ENUM_CONSTANT(TYPE_COLLIDE);
+ BIND_ENUM_CONSTANT(TYPE_START_CUSTOM);
+ BIND_ENUM_CONSTANT(TYPE_PROCESS_CUSTOM);
BIND_ENUM_CONSTANT(TYPE_SKY);
BIND_ENUM_CONSTANT(TYPE_MAX);
@@ -1678,11 +2018,20 @@ void VisualShader::_bind_methods() {
VisualShader::VisualShader() {
dirty.set();
for (int i = 0; i < TYPE_MAX; i++) {
- Ref<VisualShaderNodeOutput> output;
- output.instance();
- output->shader_type = Type(i);
- output->shader_mode = shader_mode;
- graph[i].nodes[NODE_ID_OUTPUT].node = output;
+ if (i > (int)TYPE_LIGHT && i < (int)TYPE_SKY) {
+ Ref<VisualShaderNodeParticleOutput> output;
+ output.instance();
+ output->shader_type = Type(i);
+ output->shader_mode = shader_mode;
+ graph[i].nodes[NODE_ID_OUTPUT].node = output;
+ } else {
+ Ref<VisualShaderNodeOutput> output;
+ output.instance();
+ output->shader_type = Type(i);
+ output->shader_mode = shader_mode;
+ graph[i].nodes[NODE_ID_OUTPUT].node = output;
+ }
+
graph[i].nodes[NODE_ID_OUTPUT].position = Vector2(400, 150);
}
}
@@ -1811,27 +2160,45 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular_shininess", "SPECULAR_SHININESS.rgb" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "specular_shininess_alpha", "SPECULAR_SHININESS.a" },
- // Particles, Emit
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ // Particles, Start
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+
+ // Particles, Start (Custom)
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
// Particles, Process
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
@@ -1841,20 +2208,39 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
- // Particles, End
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ // Particles, Process (Custom)
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+
+ // Particles, Collide
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "collision_depth", "COLLISION_DEPTH" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "collision_normal", "COLLISION_NORMAL" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
// Sky, Sky
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" },
@@ -1930,11 +2316,13 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
- // Particles, Vertex
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" },
- { 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" },
+
+ // Particles
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
@@ -2382,6 +2770,8 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_view_matrix", "MODELVIEW_MATRIX" },
+
// Spatial, Fragment
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" },
@@ -2425,30 +2815,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
// Canvas Item, Light
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" },
- // Particles, Emit
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
- // Particles, Process
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
- // Particles, End
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
+
// Sky, Sky
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" },
{ Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
@@ -2521,9 +2888,13 @@ String VisualShaderNodeOutput::get_output_port_name(int p_port) const {
}
bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
+ if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_VERTEX) {
+ String name = get_input_port_name(p_index);
+ return bool(name == "Model View Matrix");
+ }
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) {
String name = get_input_port_name(p_index);
- return (name == "Normal" || name == "Rim" || name == "Alpha Scissor Threshold");
+ return bool(name == "Normal" || name == "Rim" || name == "Alpha Scissor Threshold");
}
return false;
}
@@ -3118,11 +3489,11 @@ int VisualShaderNodeGroupBase::get_free_output_port_id() const {
return output_ports.size();
}
-void VisualShaderNodeGroupBase::set_control(Control *p_control, int p_index) {
+void VisualShaderNodeGroupBase::set_ctrl_pressed(Control *p_control, int p_index) {
controls[p_index] = p_control;
}
-Control *VisualShaderNodeGroupBase::get_control(int p_index) {
+Control *VisualShaderNodeGroupBase::is_ctrl_pressed(int p_index) {
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 e2e1b473ed..53b165fe0f 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -51,9 +51,11 @@ public:
TYPE_VERTEX,
TYPE_FRAGMENT,
TYPE_LIGHT,
- TYPE_EMIT,
+ TYPE_START,
TYPE_PROCESS,
- TYPE_END,
+ TYPE_COLLIDE,
+ TYPE_START_CUSTOM,
+ TYPE_PROCESS_CUSTOM,
TYPE_SKY,
TYPE_MAX
};
@@ -199,9 +201,12 @@ class VisualShaderNode : public Resource {
Map<int, Variant> default_input_values;
Map<int, bool> connected_input_ports;
Map<int, int> connected_output_ports;
+ Map<int, bool> expanded_output_ports;
protected:
bool simple_decl = true;
+ bool disabled = false;
+
static void _bind_methods();
public:
@@ -223,10 +228,12 @@ public:
virtual PortType get_input_port_type(int p_port) const = 0;
virtual String get_input_port_name(int p_port) const = 0;
- void set_input_port_default_value(int p_port, const Variant &p_value);
+ virtual void set_input_port_default_value(int p_port, const Variant &p_value);
Variant get_input_port_default_value(int p_port) const; // if NIL (default if node does not set anything) is returned, it means no default value is wanted if disconnected, thus no input var must be supplied (empty string will be supplied)
Array get_default_input_values() const;
- void set_default_input_values(const Array &p_values);
+ virtual void set_default_input_values(const Array &p_values);
+ virtual void remove_input_port_default_value(int p_port);
+ virtual void clear_default_input_values();
virtual int get_output_port_count() const = 0;
virtual PortType get_output_port_type(int p_port) const = 0;
@@ -245,17 +252,28 @@ public:
void set_input_port_connected(int p_port, bool p_connected);
virtual bool is_generate_input_var(int p_port) const;
+ virtual bool is_output_port_expandable(int p_port) const;
+ void _set_output_ports_expanded(const Array &p_data);
+ Array _get_output_ports_expanded() const;
+ void _set_output_port_expanded(int p_port, bool p_expanded);
+ bool _is_output_port_expanded(int p_port) const;
+ int get_expanded_output_port_count() const;
+
virtual bool is_code_generated() const;
virtual bool is_show_prop_names() const;
virtual bool is_use_prop_slots() const;
+ bool is_disabled() const;
+ void set_disabled(bool p_disabled = true);
+
virtual Vector<StringName> get_editable_properties() const;
virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const = 0; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ // If no output is connected, the output var passed will be empty. If no input is connected and input is NIL, the input var passed will be empty.
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const = 0;
virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const;
@@ -272,6 +290,7 @@ class VisualShaderNodeCustom : public VisualShaderNode {
int type = 0;
};
+ bool is_initialized = false;
List<Port> input_ports;
List<Port> output_ports;
@@ -288,7 +307,14 @@ protected:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual void set_input_port_default_value(int p_port, const Variant &p_value) override;
+ virtual void set_default_input_values(const Array &p_values) override;
+ virtual void remove_input_port_default_value(int p_port) override;
+ virtual void clear_default_input_values() override;
+
protected:
+ void _set_input_port_default_value(int p_port, const Variant &p_value);
+
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
@@ -297,6 +323,9 @@ protected:
public:
VisualShaderNodeCustom();
void update_ports();
+
+ bool _is_initialized();
+ void _set_initialized(bool p_enabled);
};
/////
@@ -601,8 +630,8 @@ public:
int get_free_input_port_id() const;
int get_free_output_port_id() const;
- void set_control(Control *p_control, int p_index);
- Control *get_control(int p_index);
+ void set_ctrl_pressed(Control *p_control, int p_index);
+ Control *is_ctrl_pressed(int p_index);
void set_editable(bool p_enabled);
bool is_editable() const;
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 7943b95177..d3b094de31 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -242,6 +242,13 @@ String VisualShaderNodeColorConstant::get_output_port_name(int p_port) const {
return p_port == 0 ? "" : "alpha"; //no output port means the editor will be used as port
}
+bool VisualShaderNodeColorConstant::is_output_port_expandable(int p_port) const {
+ if (p_port == 0) {
+ return true;
+ }
+ return false;
+}
+
String VisualShaderNodeColorConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
code += "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f, %.6f, %.6f)", constant.r, constant.g, constant.b) + ";\n";
@@ -334,10 +341,10 @@ void VisualShaderNodeVec3Constant::_bind_methods() {
VisualShaderNodeVec3Constant::VisualShaderNodeVec3Constant() {
}
-////////////// Transform
+////////////// Transform3D
String VisualShaderNodeTransformConstant::get_caption() const {
- return "Transform";
+ return "Transform3D";
}
int VisualShaderNodeTransformConstant::get_input_port_count() const {
@@ -365,7 +372,7 @@ String VisualShaderNodeTransformConstant::get_output_port_name(int p_port) const
}
String VisualShaderNodeTransformConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- Transform t = constant;
+ Transform3D t = constant;
t.basis.transpose();
String code = "\t" + p_output_vars[0] + " = mat4(";
@@ -376,12 +383,12 @@ String VisualShaderNodeTransformConstant::generate_code(Shader::Mode p_mode, Vis
return code;
}
-void VisualShaderNodeTransformConstant::set_constant(Transform p_value) {
+void VisualShaderNodeTransformConstant::set_constant(Transform3D p_value) {
constant = p_value;
emit_changed();
}
-Transform VisualShaderNodeTransformConstant::get_constant() const {
+Transform3D VisualShaderNodeTransformConstant::get_constant() const {
return constant;
}
@@ -395,7 +402,7 @@ void VisualShaderNodeTransformConstant::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeTransformConstant::set_constant);
ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeTransformConstant::get_constant);
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "constant"), "set_constant", "get_constant");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "constant"), "set_constant", "get_constant");
}
VisualShaderNodeTransformConstant::VisualShaderNodeTransformConstant() {
@@ -455,6 +462,13 @@ String VisualShaderNodeTexture::get_output_port_name(int p_port) const {
return p_port == 0 ? "rgb" : "alpha";
}
+bool VisualShaderNodeTexture::is_output_port_expandable(int p_port) const {
+ if (p_port == 0) {
+ return true;
+ }
+ return false;
+}
+
String VisualShaderNodeTexture::get_input_port_default_hint(int p_port) const {
if (p_port == 0) {
return "default";
@@ -775,7 +789,7 @@ void VisualShaderNodeTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort"), "set_source", "get_source");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap"), "set_texture_type", "get_texture_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map"), "set_texture_type", "get_texture_type");
BIND_ENUM_CONSTANT(SOURCE_TEXTURE);
BIND_ENUM_CONSTANT(SOURCE_SCREEN);
@@ -846,7 +860,7 @@ String VisualShaderNodeCurveTexture::generate_code(Shader::Mode p_mode, VisualSh
}
String id = make_unique_id(p_type, p_id, "curve");
String code;
- code += "\t" + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ", 0.0)).r;\n";
+ code += "\t" + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ")).r;\n";
return code;
}
@@ -917,6 +931,13 @@ String VisualShaderNodeSample3D::get_output_port_name(int p_port) const {
return p_port == 0 ? "rgb" : "alpha";
}
+bool VisualShaderNodeSample3D::is_output_port_expandable(int p_port) const {
+ if (p_port == 0) {
+ return true;
+ }
+ return false;
+}
+
String VisualShaderNodeSample3D::get_input_port_default_hint(int p_port) const {
if (p_port == 0) {
return "default";
@@ -1168,6 +1189,13 @@ String VisualShaderNodeCubemap::get_output_port_name(int p_port) const {
return p_port == 0 ? "rgb" : "alpha";
}
+bool VisualShaderNodeCubemap::is_output_port_expandable(int p_port) const {
+ if (p_port == 0) {
+ return true;
+ }
+ return false;
+}
+
Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCubemap::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
VisualShader::DefaultTextureParam dtp;
dtp.name = make_unique_id(p_type, p_id, "cube");
@@ -1308,7 +1336,7 @@ void VisualShaderNodeCubemap::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,SamplerPort"), "set_source", "get_source");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "cube_map", PROPERTY_HINT_RESOURCE_TYPE, "Cubemap"), "set_cube_map", "get_cube_map");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap"), "set_texture_type", "get_texture_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map"), "set_texture_type", "get_texture_type");
BIND_ENUM_CONSTANT(SOURCE_TEXTURE);
BIND_ENUM_CONSTANT(SOURCE_PORT);
@@ -1409,7 +1437,7 @@ void VisualShaderNodeFloatOp::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeFloatOp::set_operator);
ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeFloatOp::get_operator);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Atan2,Step"), "set_operator", "get_operator");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Subtract,Multiply,Divide,Remainder,Power,Max,Min,ATan2,Step"), "set_operator", "get_operator");
BIND_ENUM_CONSTANT(OP_ADD);
BIND_ENUM_CONSTANT(OP_SUB);
@@ -1506,7 +1534,7 @@ void VisualShaderNodeIntOp::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeIntOp::set_operator);
ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeIntOp::get_operator);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Max,Min"), "set_operator", "get_operator");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Subtract,Multiply,Divide,Remainder,Max,Min"), "set_operator", "get_operator");
BIND_ENUM_CONSTANT(OP_ADD);
BIND_ENUM_CONSTANT(OP_SUB);
@@ -1615,7 +1643,7 @@ void VisualShaderNodeVectorOp::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeVectorOp::set_operator);
ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeVectorOp::get_operator);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Cross,Atan2,Reflect,Step"), "set_operator", "get_operator");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Subtract,Multiply,Divide,Remainder,Power,Max,Min,Cross,ATan2,Reflect,Step"), "set_operator", "get_operator");
BIND_ENUM_CONSTANT(OP_ADD);
BIND_ENUM_CONSTANT(OP_SUB);
@@ -1785,7 +1813,7 @@ void VisualShaderNodeColorOp::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeColorOp::set_operator);
ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeColorOp::get_operator);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Screen,Difference,Darken,Lighten,Overlay,Dodge,Burn,SoftLight,HardLight"), "set_operator", "get_operator");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Screen,Difference,Darken,Lighten,Overlay,Dodge,Burn,Soft Light,Hard Light"), "set_operator", "get_operator");
BIND_ENUM_CONSTANT(OP_SCREEN);
BIND_ENUM_CONSTANT(OP_DIFFERENCE);
@@ -1873,8 +1901,8 @@ void VisualShaderNodeTransformMult::_bind_methods() {
}
VisualShaderNodeTransformMult::VisualShaderNodeTransformMult() {
- set_input_port_default_value(0, Transform());
- set_input_port_default_value(1, Transform());
+ set_input_port_default_value(0, Transform3D());
+ set_input_port_default_value(1, Transform3D());
}
////////////// TransformVec Mult
@@ -1947,7 +1975,7 @@ void VisualShaderNodeTransformVecMult::_bind_methods() {
}
VisualShaderNodeTransformVecMult::VisualShaderNodeTransformVecMult() {
- set_input_port_default_value(0, Transform());
+ set_input_port_default_value(0, Transform3D());
set_input_port_default_value(1, Vector3());
}
@@ -2468,7 +2496,144 @@ void VisualShaderNodeTransformFunc::_bind_methods() {
}
VisualShaderNodeTransformFunc::VisualShaderNodeTransformFunc() {
- set_input_port_default_value(0, Transform());
+ set_input_port_default_value(0, Transform3D());
+}
+
+////////////// UV Func
+
+String VisualShaderNodeUVFunc::get_caption() const {
+ return "UVFunc";
+}
+
+int VisualShaderNodeUVFunc::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeUVFunc::PortType VisualShaderNodeUVFunc::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ [[fallthrough]]; // uv
+ case 1:
+ return PORT_TYPE_VECTOR; // scale
+ case 2:
+ return PORT_TYPE_VECTOR; // offset & pivot
+ default:
+ break;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeUVFunc::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "uv";
+ case 1:
+ return "scale";
+ case 2:
+ switch (func) {
+ case FUNC_PANNING:
+ return "offset";
+ case FUNC_SCALING:
+ return "pivot";
+ case FUNC_MAX:
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return "";
+}
+
+String VisualShaderNodeUVFunc::get_input_port_default_hint(int p_port) const {
+ if (p_port == 0) {
+ return "UV";
+ }
+ return "";
+}
+
+int VisualShaderNodeUVFunc::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeUVFunc::PortType VisualShaderNodeUVFunc::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeUVFunc::get_output_port_name(int p_port) const {
+ return "uv";
+}
+
+bool VisualShaderNodeUVFunc::is_show_prop_names() const {
+ return true;
+}
+
+String VisualShaderNodeUVFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ String uv;
+ if (p_input_vars[0].is_empty()) {
+ uv = "vec3(UV.xy, 0.0)";
+ } else {
+ uv = vformat("%s", p_input_vars[0]);
+ }
+ String scale = vformat("%s", p_input_vars[1]);
+ String offset_pivot = vformat("%s", p_input_vars[2]);
+
+ switch (func) {
+ case FUNC_PANNING: {
+ code += vformat("\t%s = fma(%s, %s, %s);\n", p_output_vars[0], offset_pivot, scale, uv);
+ } break;
+ case FUNC_SCALING: {
+ code += vformat("\t%s = fma((%s - %s), %s, %s);\n", p_output_vars[0], uv, offset_pivot, scale, offset_pivot);
+ } break;
+ case FUNC_MAX:
+ break;
+ }
+ return code;
+}
+
+void VisualShaderNodeUVFunc::set_function(VisualShaderNodeUVFunc::Function p_func) {
+ ERR_FAIL_INDEX(int(p_func), FUNC_MAX);
+ if (func == p_func) {
+ return;
+ }
+ func = p_func;
+
+ if (p_func == FUNC_PANNING) {
+ set_input_port_default_value(2, Vector3()); // offset
+ } else { // FUNC_SCALING
+ set_input_port_default_value(2, Vector3(0.5, 0.5, 0.0)); // pivot
+ }
+ emit_changed();
+}
+
+VisualShaderNodeUVFunc::Function VisualShaderNodeUVFunc::get_function() const {
+ return func;
+}
+
+Vector<StringName> VisualShaderNodeUVFunc::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("function");
+ return props;
+}
+
+void VisualShaderNodeUVFunc::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeUVFunc::set_function);
+ ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeUVFunc::get_function);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Panning,Scaling"), "set_function", "get_function");
+
+ BIND_ENUM_CONSTANT(FUNC_PANNING);
+ BIND_ENUM_CONSTANT(FUNC_SCALING);
+ BIND_ENUM_CONSTANT(FUNC_MAX);
+}
+
+VisualShaderNodeUVFunc::VisualShaderNodeUVFunc() {
+ set_input_port_default_value(1, Vector3(1.0, 1.0, 0.0)); // scale
+ set_input_port_default_value(2, Vector3()); // offset
}
////////////// Dot Product
@@ -2583,7 +2748,7 @@ String VisualShaderNodeDeterminant::generate_code(Shader::Mode p_mode, VisualSha
}
VisualShaderNodeDeterminant::VisualShaderNodeDeterminant() {
- set_input_port_default_value(0, Transform());
+ set_input_port_default_value(0, Transform3D());
}
////////////// Scalar Derivative Function
@@ -3594,7 +3759,7 @@ String VisualShaderNodeTransformDecompose::generate_code(Shader::Mode p_mode, Vi
}
VisualShaderNodeTransformDecompose::VisualShaderNodeTransformDecompose() {
- set_input_port_default_value(0, Transform());
+ set_input_port_default_value(0, Transform3D());
}
////////////// Float Uniform
@@ -3899,7 +4064,7 @@ void VisualShaderNodeIntUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeIntUniform::set_default_value);
ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeIntUniform::get_default_value);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range + Step"), "set_hint", "get_hint");
ADD_PROPERTY(PropertyInfo(Variant::INT, "min"), "set_min", "get_min");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max"), "set_max", "get_max");
ADD_PROPERTY(PropertyInfo(Variant::INT, "step"), "set_step", "get_step");
@@ -4280,12 +4445,12 @@ bool VisualShaderNodeTransformUniform::is_default_value_enabled() const {
return default_value_enabled;
}
-void VisualShaderNodeTransformUniform::set_default_value(const Transform &p_value) {
+void VisualShaderNodeTransformUniform::set_default_value(const Transform3D &p_value) {
default_value = p_value;
emit_changed();
}
-Transform VisualShaderNodeTransformUniform::get_default_value() const {
+Transform3D VisualShaderNodeTransformUniform::get_default_value() const {
return default_value;
}
@@ -4314,7 +4479,7 @@ void VisualShaderNodeTransformUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformUniform::get_default_value);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "default_value"), "set_default_value", "get_default_value");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "default_value"), "set_default_value", "get_default_value");
}
bool VisualShaderNodeTransformUniform::is_show_prop_names() const {
@@ -4487,7 +4652,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureUniform::set_color_default);
ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureUniform::get_color_default);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap,Aniso"), "set_texture_type", "get_texture_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map,Anisotropic"), "set_texture_type", "get_texture_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White Default,Black Default"), "set_color_default", "get_color_default");
BIND_ENUM_CONSTANT(TYPE_DATA);
@@ -4997,8 +5162,8 @@ void VisualShaderNodeSwitch::set_op_type(OpType p_op_type) {
set_input_port_default_value(2, false);
break;
case OP_TYPE_TRANSFORM:
- set_input_port_default_value(1, Transform());
- set_input_port_default_value(2, Transform());
+ set_input_port_default_value(1, Transform3D());
+ set_input_port_default_value(2, Transform3D());
break;
default:
break;
@@ -5377,8 +5542,8 @@ void VisualShaderNodeCompare::set_comparison_type(ComparisonType p_type) {
simple_decl = true;
break;
case CTYPE_TRANSFORM:
- set_input_port_default_value(0, Transform());
- set_input_port_default_value(1, Transform());
+ set_input_port_default_value(0, Transform3D());
+ set_input_port_default_value(1, Transform3D());
simple_decl = true;
break;
}
@@ -5551,3 +5716,127 @@ VisualShaderNodeMultiplyAdd::VisualShaderNodeMultiplyAdd() {
set_input_port_default_value(1, 0.0);
set_input_port_default_value(2, 0.0);
}
+
+////////////// Billboard
+
+String VisualShaderNodeBillboard::get_caption() const {
+ return "GetBillboardMatrix";
+}
+
+int VisualShaderNodeBillboard::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeBillboard::PortType VisualShaderNodeBillboard::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeBillboard::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeBillboard::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeBillboard::PortType VisualShaderNodeBillboard::get_output_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+
+String VisualShaderNodeBillboard::get_output_port_name(int p_port) const {
+ return "model_view_matrix";
+}
+
+String VisualShaderNodeBillboard::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ switch (billboard_type) {
+ case BILLBOARD_TYPE_ENABLED:
+ code += "\t{\n";
+ code += "\t\tmat4 __mvm = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0], CAMERA_MATRIX[1], CAMERA_MATRIX[2], WORLD_MATRIX[3]);\n";
+ if (keep_scale) {
+ code += "\t\t__mvm = __mvm * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ }
+ code += "\t\t" + p_output_vars[0] + " = __mvm;\n";
+ code += "\t}\n";
+ break;
+ case BILLBOARD_TYPE_FIXED_Y:
+ code += "\t{\n";
+ code += "\t\tmat4 __mvm = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0], WORLD_MATRIX[1], vec4(normalize(cross(CAMERA_MATRIX[0].xyz, WORLD_MATRIX[1].xyz)), 0.0), WORLD_MATRIX[3]);\n";
+ if (keep_scale) {
+ code += "\t\t__mvm = __mvm * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ } else {
+ code += "\t\t__mvm = __mvm * mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0 / length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ }
+ code += "\t\t" + p_output_vars[0] + " = __mvm;\n";
+ code += "\t}\n";
+ break;
+ case BILLBOARD_TYPE_PARTICLES:
+ code += "\t{\n";
+ code += "\t\tmat4 __wm = mat4(normalize(CAMERA_MATRIX[0]) * length(WORLD_MATRIX[0]), normalize(CAMERA_MATRIX[1]) * length(WORLD_MATRIX[0]), normalize(CAMERA_MATRIX[2]) * length(WORLD_MATRIX[2]), WORLD_MATRIX[3]);\n";
+ code += "\t\t__wm = __wm * mat4(vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ code += "\t\t" + p_output_vars[0] + " = INV_CAMERA_MATRIX * __wm;\n";
+ code += "\t}\n";
+ break;
+ default:
+ code += "\t" + p_output_vars[0] + " = mat4(1.0);\n";
+ break;
+ }
+
+ return code;
+}
+
+bool VisualShaderNodeBillboard::is_show_prop_names() const {
+ return true;
+}
+
+void VisualShaderNodeBillboard::set_billboard_type(BillboardType p_billboard_type) {
+ ERR_FAIL_INDEX((int)p_billboard_type, BILLBOARD_TYPE_MAX);
+ billboard_type = p_billboard_type;
+ simple_decl = bool(billboard_type == BILLBOARD_TYPE_DISABLED);
+ set_disabled(simple_decl);
+ emit_changed();
+}
+
+VisualShaderNodeBillboard::BillboardType VisualShaderNodeBillboard::get_billboard_type() const {
+ return billboard_type;
+}
+
+void VisualShaderNodeBillboard::set_keep_scale_enabled(bool p_enabled) {
+ keep_scale = p_enabled;
+ emit_changed();
+}
+
+bool VisualShaderNodeBillboard::is_keep_scale_enabled() const {
+ return keep_scale;
+}
+
+Vector<StringName> VisualShaderNodeBillboard::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("billboard_type");
+ if (billboard_type == BILLBOARD_TYPE_ENABLED || billboard_type == BILLBOARD_TYPE_FIXED_Y) {
+ props.push_back("keep_scale");
+ }
+ return props;
+}
+
+void VisualShaderNodeBillboard::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_billboard_type", "billboard_type"), &VisualShaderNodeBillboard::set_billboard_type);
+ ClassDB::bind_method(D_METHOD("get_billboard_type"), &VisualShaderNodeBillboard::get_billboard_type);
+
+ ClassDB::bind_method(D_METHOD("set_keep_scale_enabled", "enabled"), &VisualShaderNodeBillboard::set_keep_scale_enabled);
+ ClassDB::bind_method(D_METHOD("is_keep_scale_enabled"), &VisualShaderNodeBillboard::is_keep_scale_enabled);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "billboard_type", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard,Particles"), "set_billboard_type", "get_billboard_type");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_scale"), "set_keep_scale_enabled", "is_keep_scale_enabled");
+
+ BIND_ENUM_CONSTANT(BILLBOARD_TYPE_DISABLED);
+ BIND_ENUM_CONSTANT(BILLBOARD_TYPE_ENABLED);
+ BIND_ENUM_CONSTANT(BILLBOARD_TYPE_FIXED_Y);
+ BIND_ENUM_CONSTANT(BILLBOARD_TYPE_PARTICLES);
+ BIND_ENUM_CONSTANT(BILLBOARD_TYPE_MAX);
+}
+
+VisualShaderNodeBillboard::VisualShaderNodeBillboard() {
+ simple_decl = false;
+}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 594a494cf1..5b44e9f776 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -74,7 +74,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_constant(float p_value);
float get_constant() const;
@@ -104,7 +104,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_constant(int p_value);
int get_constant() const;
@@ -134,7 +134,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_constant(bool p_value);
bool get_constant() const;
@@ -163,8 +163,9 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool is_output_port_expandable(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_constant(Color p_value);
Color get_constant() const;
@@ -194,7 +195,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_constant(Vector3 p_value);
Vector3 get_constant() const;
@@ -208,7 +209,7 @@ public:
class VisualShaderNodeTransformConstant : public VisualShaderNodeConstant {
GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNodeConstant);
- Transform constant;
+ Transform3D constant;
protected:
static void _bind_methods();
@@ -224,10 +225,10 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
- void set_constant(Transform p_value);
- Transform get_constant() const;
+ void set_constant(Transform3D p_value);
+ Transform3D get_constant() const;
virtual Vector<StringName> get_editable_properties() const override;
@@ -275,12 +276,13 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool is_output_port_expandable(int p_port) const override;
virtual String get_input_port_default_hint(int p_port) const override;
virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_source(Source p_source);
Source get_source() const;
@@ -323,7 +325,7 @@ public:
virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_texture(Ref<CurveTexture> p_value);
Ref<CurveTexture> get_texture() const;
@@ -359,8 +361,9 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool is_output_port_expandable(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_source(Source p_source);
Source get_source() const;
@@ -452,10 +455,11 @@ public:
virtual int get_output_port_count() const override;
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
+ virtual bool is_output_port_expandable(int p_port) const override;
virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_source(Source p_source);
Source get_source() const;
@@ -512,7 +516,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_operator(Operator p_op);
Operator get_operator() const;
@@ -554,7 +558,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_operator(Operator p_op);
Operator get_operator() const;
@@ -601,7 +605,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_operator(Operator p_op);
Operator get_operator() const;
@@ -647,7 +651,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_operator(Operator p_op);
Operator get_operator() const;
@@ -690,7 +694,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_operator(Operator p_op);
Operator get_operator() const;
@@ -733,7 +737,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_operator(Operator p_op);
Operator get_operator() const;
@@ -804,7 +808,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_function(Function p_func);
Function get_function() const;
@@ -846,7 +850,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_function(Function p_func);
Function get_function() const;
@@ -920,7 +924,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_function(Function p_func);
Function get_function() const;
@@ -961,7 +965,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_function(Function p_func);
Function get_function() const;
@@ -1002,7 +1006,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_function(Function p_func);
Function get_function() const;
@@ -1015,6 +1019,51 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeTransformFunc::Function)
///////////////////////////////////////
+/// UV FUNC
+///////////////////////////////////////
+
+class VisualShaderNodeUVFunc : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeUVFunc, VisualShaderNode);
+
+public:
+ enum Function {
+ FUNC_PANNING,
+ FUNC_SCALING,
+ FUNC_MAX,
+ };
+
+protected:
+ Function func = FUNC_PANNING;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+ virtual String get_input_port_default_hint(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual bool is_show_prop_names() const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ void set_function(Function p_op);
+ Function get_function() const;
+
+ virtual Vector<StringName> get_editable_properties() const override;
+
+ VisualShaderNodeUVFunc();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeUVFunc::Function)
+
+///////////////////////////////////////
/// DOT
///////////////////////////////////////
@@ -1032,7 +1081,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeDotProduct();
};
@@ -1055,7 +1104,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeVectorLen();
};
@@ -1078,7 +1127,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeDeterminant();
};
@@ -1118,7 +1167,7 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeClamp();
};
@@ -1155,7 +1204,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_function(Function p_func);
Function get_function() const;
@@ -1195,7 +1244,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_function(Function p_func);
Function get_function() const;
@@ -1225,7 +1274,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeFaceForward();
};
@@ -1248,7 +1297,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeOuterProduct();
};
@@ -1288,7 +1337,7 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeStep();
};
@@ -1330,7 +1379,7 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeSmoothStep();
};
@@ -1355,7 +1404,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeVectorDistance();
};
@@ -1378,7 +1427,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeVectorRefract();
};
@@ -1418,7 +1467,7 @@ public:
virtual Vector<StringName> get_editable_properties() const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeMix();
};
@@ -1443,7 +1492,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeVectorCompose();
};
@@ -1464,7 +1513,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeTransformCompose();
};
@@ -1487,7 +1536,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeVectorDecompose();
};
@@ -1508,7 +1557,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeTransformDecompose();
};
@@ -1550,7 +1599,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual bool is_show_prop_names() const override;
virtual bool is_use_prop_slots() const override;
@@ -1616,7 +1665,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual bool is_show_prop_names() const override;
virtual bool is_use_prop_slots() const override;
@@ -1673,7 +1722,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual bool is_show_prop_names() const override;
virtual bool is_use_prop_slots() const override;
@@ -1716,7 +1765,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual bool is_show_prop_names() const override;
@@ -1758,7 +1807,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual bool is_show_prop_names() const override;
virtual bool is_use_prop_slots() const override;
@@ -1784,7 +1833,7 @@ class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform {
private:
bool default_value_enabled = false;
- Transform default_value = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0);
+ Transform3D default_value = Transform3D(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0);
protected:
static void _bind_methods();
@@ -1801,7 +1850,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual bool is_show_prop_names() const override;
virtual bool is_use_prop_slots() const override;
@@ -1809,8 +1858,8 @@ public:
void set_default_value_enabled(bool p_enabled);
bool is_default_value_enabled() const;
- void set_default_value(const Transform &p_value);
- Transform get_default_value() const;
+ void set_default_value(const Transform3D &p_value);
+ Transform3D get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
bool is_convertible_to_constant() const override;
@@ -1858,7 +1907,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
virtual bool is_code_generated() const override;
@@ -1895,7 +1944,7 @@ public:
virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeTextureUniformTriplanar();
};
@@ -1918,7 +1967,7 @@ public:
virtual String get_input_port_default_hint(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeTexture2DArrayUniform();
};
@@ -1941,7 +1990,7 @@ public:
virtual String get_input_port_default_hint(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeTexture3DUniform();
};
@@ -1964,7 +2013,7 @@ public:
virtual String get_input_port_default_hint(int p_port) const override;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeCubemapUniform();
};
@@ -2092,7 +2141,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_function(Function p_func);
Function get_function() const;
@@ -2153,7 +2202,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_comparison_type(ComparisonType p_type);
ComparisonType get_comparison_type() const;
@@ -2201,7 +2250,7 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
void set_op_type(OpType p_type);
OpType get_op_type() const;
@@ -2213,4 +2262,51 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeMultiplyAdd::OpType)
+class VisualShaderNodeBillboard : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeBillboard, VisualShaderNode);
+
+public:
+ enum BillboardType {
+ BILLBOARD_TYPE_DISABLED,
+ BILLBOARD_TYPE_ENABLED,
+ BILLBOARD_TYPE_FIXED_Y,
+ BILLBOARD_TYPE_PARTICLES,
+ BILLBOARD_TYPE_MAX,
+ };
+
+protected:
+ BillboardType billboard_type = BILLBOARD_TYPE_ENABLED;
+ bool keep_scale = false;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ virtual bool is_show_prop_names() const override;
+
+ void set_billboard_type(BillboardType p_billboard_type);
+ BillboardType get_billboard_type() const;
+
+ void set_keep_scale_enabled(bool p_enabled);
+ bool is_keep_scale_enabled() const;
+
+ virtual Vector<StringName> get_editable_properties() const override;
+
+ VisualShaderNodeBillboard();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeBillboard::BillboardType)
+
#endif // VISUAL_SHADER_NODES_H
diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp
new file mode 100644
index 0000000000..29d583a82a
--- /dev/null
+++ b/scene/resources/visual_shader_particle_nodes.cpp
@@ -0,0 +1,1025 @@
+/*************************************************************************/
+/* visual_shader_particle_nodes.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "visual_shader_particle_nodes.h"
+
+// VisualShaderNodeParticleEmitter
+
+int VisualShaderNodeParticleEmitter::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeParticleEmitter::PortType VisualShaderNodeParticleEmitter::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeParticleEmitter::get_output_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "position";
+ }
+ return String();
+}
+
+VisualShaderNodeParticleEmitter::VisualShaderNodeParticleEmitter() {
+}
+
+// VisualShaderNodeParticleSphereEmitter
+
+String VisualShaderNodeParticleSphereEmitter::get_caption() const {
+ return "SphereEmitter";
+}
+
+int VisualShaderNodeParticleSphereEmitter::get_input_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeParticleSphereEmitter::PortType VisualShaderNodeParticleSphereEmitter::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeParticleSphereEmitter::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "radius";
+ } else if (p_port == 1) {
+ return "inner_radius";
+ }
+ return String();
+}
+
+String VisualShaderNodeParticleSphereEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code;
+ code += "vec3 __get_random_point_in_sphere(inout uint seed, float radius, float inner_radius) {\n";
+ code += "\treturn __get_random_unit_vec3(seed) * __randf_range(seed, inner_radius, radius);\n";
+ code += "}\n\n";
+ return code;
+}
+
+String VisualShaderNodeParticleSphereEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ code += "\t" + p_output_vars[0] + " = __get_random_point_in_sphere(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ", " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n";
+ return code;
+}
+
+VisualShaderNodeParticleSphereEmitter::VisualShaderNodeParticleSphereEmitter() {
+ set_input_port_default_value(0, 10.0);
+ set_input_port_default_value(1, 0.0);
+}
+
+// VisualShaderNodeParticleBoxEmitter
+
+String VisualShaderNodeParticleBoxEmitter::get_caption() const {
+ return "BoxEmitter";
+}
+
+int VisualShaderNodeParticleBoxEmitter::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleBoxEmitter::get_input_port_type(int p_port) const {
+ if (p_port == 0) {
+ return PORT_TYPE_VECTOR;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeParticleBoxEmitter::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "extents";
+ }
+ return String();
+}
+
+String VisualShaderNodeParticleBoxEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code;
+ code += "vec3 __get_random_point_in_box(inout uint seed, vec3 extents) {\n";
+ code += "\tvec3 half_extents = extents / 2.0;\n";
+ code += "\treturn vec3(__randf_range(seed, -half_extents.x, half_extents.x), __randf_range(seed, -half_extents.y, half_extents.y), __randf_range(seed, -half_extents.z, half_extents.z));\n";
+ code += "}\n\n";
+ return code;
+}
+
+String VisualShaderNodeParticleBoxEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ code += "\t" + p_output_vars[0] + " = __get_random_point_in_box(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ");\n";
+ return code;
+}
+
+VisualShaderNodeParticleBoxEmitter::VisualShaderNodeParticleBoxEmitter() {
+ set_input_port_default_value(0, Vector3(1.0, 1.0, 1.0));
+}
+
+// VisualShaderNodeParticleRingEmitter
+
+String VisualShaderNodeParticleRingEmitter::get_caption() const {
+ return "RingEmitter";
+}
+
+int VisualShaderNodeParticleRingEmitter::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeParticleRingEmitter::PortType VisualShaderNodeParticleRingEmitter::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeParticleRingEmitter::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "radius";
+ } else if (p_port == 1) {
+ return "inner_radius";
+ } else if (p_port == 2) {
+ return "height";
+ }
+ return String();
+}
+
+String VisualShaderNodeParticleRingEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code;
+ code += "vec3 __get_random_point_on_ring(inout uint seed, float radius, float inner_radius, float height) {\n";
+ code += "\tfloat angle = __rand_from_seed(seed) * PI * 2.0;\n";
+ code += "\tvec2 ring = vec2(sin(angle), cos(angle)) * __randf_range(seed, inner_radius, radius);\n";
+ code += "\treturn vec3(ring.x, __randf_range(seed, min(0.0, height), max(0.0, height)), ring.y);\n";
+ code += "}\n\n";
+ return code;
+}
+
+String VisualShaderNodeParticleRingEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ code = "\t" + p_output_vars[0] + " = __get_random_point_on_ring(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ", " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ", " + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ");\n";
+ return code;
+}
+
+VisualShaderNodeParticleRingEmitter::VisualShaderNodeParticleRingEmitter() {
+ set_input_port_default_value(0, 10.0);
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 0.0);
+}
+
+// VisualShaderNodeParticleMultiplyByAxisAngle
+
+void VisualShaderNodeParticleMultiplyByAxisAngle::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_degrees_mode", "enabled"), &VisualShaderNodeParticleMultiplyByAxisAngle::set_degrees_mode);
+ ClassDB::bind_method(D_METHOD("is_degrees_mode"), &VisualShaderNodeParticleMultiplyByAxisAngle::is_degrees_mode);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "degrees_mode"), "set_degrees_mode", "is_degrees_mode");
+}
+
+String VisualShaderNodeParticleMultiplyByAxisAngle::get_caption() const {
+ return "MultiplyByAxisAngle";
+}
+
+int VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeParticleMultiplyByAxisAngle::PortType VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_type(int p_port) const {
+ if (p_port == 0 || p_port == 1) { // position, rotation_axis
+ return PORT_TYPE_VECTOR;
+ }
+ return PORT_TYPE_SCALAR; // angle (degrees/radians)
+}
+
+String VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "position";
+ }
+ if (p_port == 1) {
+ return "axis";
+ }
+ if (p_port == 2) {
+ if (degrees_mode) {
+ return "angle (degrees)";
+ } else {
+ return "angle (radians)";
+ }
+ }
+ return String();
+}
+
+bool VisualShaderNodeParticleMultiplyByAxisAngle::is_show_prop_names() const {
+ return true;
+}
+
+int VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeParticleMultiplyByAxisAngle::PortType VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_name(int p_port) const {
+ return "position";
+}
+
+String VisualShaderNodeParticleMultiplyByAxisAngle::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ if (degrees_mode) {
+ code += "\t" + p_output_vars[0] + " = __build_rotation_mat3(" + (p_input_vars[1].is_empty() ? ("vec3" + (String)get_input_port_default_value(1)) : p_input_vars[1]) + ", radians(" + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ")) * " + (p_input_vars[0].is_empty() ? "vec3(0.0)" : p_input_vars[0]) + ";\n";
+ } else {
+ code += "\t" + p_output_vars[0] + " = __build_rotation_mat3(" + (p_input_vars[1].is_empty() ? ("vec3" + (String)get_input_port_default_value(1)) : p_input_vars[1]) + ", " + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ") * " + (p_input_vars[0].is_empty() ? "vec3(0.0)" : p_input_vars[0]) + ";\n";
+ }
+ return code;
+}
+
+void VisualShaderNodeParticleMultiplyByAxisAngle::set_degrees_mode(bool p_enabled) {
+ degrees_mode = p_enabled;
+ emit_changed();
+}
+
+bool VisualShaderNodeParticleMultiplyByAxisAngle::is_degrees_mode() const {
+ return degrees_mode;
+}
+
+Vector<StringName> VisualShaderNodeParticleMultiplyByAxisAngle::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("degrees_mode");
+ props.push_back("axis_amount");
+ return props;
+}
+
+VisualShaderNodeParticleMultiplyByAxisAngle::VisualShaderNodeParticleMultiplyByAxisAngle() {
+ set_input_port_default_value(1, Vector3(1, 0, 0));
+ set_input_port_default_value(2, 0.0);
+}
+
+// VisualShaderNodeParticleConeVelocity
+
+String VisualShaderNodeParticleConeVelocity::get_caption() const {
+ return "ConeVelocity";
+}
+
+int VisualShaderNodeParticleConeVelocity::get_input_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeParticleConeVelocity::PortType VisualShaderNodeParticleConeVelocity::get_input_port_type(int p_port) const {
+ if (p_port == 0) {
+ return PORT_TYPE_VECTOR;
+ } else if (p_port == 1) {
+ return PORT_TYPE_SCALAR;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeParticleConeVelocity::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "direction";
+ } else if (p_port == 1) {
+ return "spread(degrees)";
+ }
+ return String();
+}
+
+int VisualShaderNodeParticleConeVelocity::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeParticleConeVelocity::PortType VisualShaderNodeParticleConeVelocity::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeParticleConeVelocity::get_output_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "velocity";
+ }
+ return String();
+}
+
+String VisualShaderNodeParticleConeVelocity::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ code += "\t__radians = radians(" + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n";
+ code += "\t__scalar_buff1 = __rand_from_seed_m1_p1(__seed) * __radians;\n";
+ code += "\t__scalar_buff2 = __rand_from_seed_m1_p1(__seed) * __radians;\n";
+ code += "\t__vec3_buff1 = " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + ";\n";
+ code += "\t__scalar_buff1 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.x, __vec3_buff1.z) : sign(__vec3_buff1.x) * (PI / 2.0);\n";
+ code += "\t__scalar_buff2 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.z)) : (__vec3_buff1.x != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.x)) : sign(__vec3_buff1.y) * (PI / 2.0));\n";
+ code += "\t__vec3_buff1 = vec3(sin(__scalar_buff1), 0.0, cos(__scalar_buff1));\n";
+ code += "\t__vec3_buff2 = vec3(0.0, sin(__scalar_buff2), cos(__scalar_buff2));\n";
+ code += "\t__vec3_buff2.z = __vec3_buff2.z / max(0.0001, sqrt(abs(__vec3_buff2.z)));\n";
+ code += "\t" + p_output_vars[0] + " = normalize(vec3(__vec3_buff1.x * __vec3_buff2.z, __vec3_buff2.y, __vec3_buff1.z * __vec3_buff2.z));\n";
+ return code;
+}
+
+VisualShaderNodeParticleConeVelocity::VisualShaderNodeParticleConeVelocity() {
+ set_input_port_default_value(0, Vector3(1, 0, 0));
+ set_input_port_default_value(1, 45.0);
+}
+
+// VisualShaderNodeParticleRandomness
+
+void VisualShaderNodeParticleRandomness::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeParticleRandomness::set_op_type);
+ ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeParticleRandomness::get_op_type);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector"), "set_op_type", "get_op_type");
+
+ BIND_ENUM_CONSTANT(OP_TYPE_SCALAR);
+ BIND_ENUM_CONSTANT(OP_TYPE_VECTOR);
+ BIND_ENUM_CONSTANT(OP_TYPE_MAX);
+}
+
+Vector<StringName> VisualShaderNodeParticleRandomness::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("op_type");
+ return props;
+}
+
+String VisualShaderNodeParticleRandomness::get_caption() const {
+ return "ParticleRandomness";
+}
+
+int VisualShaderNodeParticleRandomness::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeParticleRandomness::PortType VisualShaderNodeParticleRandomness::get_output_port_type(int p_port) const {
+ if (op_type == OP_TYPE_VECTOR) {
+ return PORT_TYPE_VECTOR;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeParticleRandomness::get_output_port_name(int p_port) const {
+ return "random";
+}
+
+int VisualShaderNodeParticleRandomness::get_input_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeParticleRandomness::PortType VisualShaderNodeParticleRandomness::get_input_port_type(int p_port) const {
+ if (op_type == OP_TYPE_VECTOR) {
+ return PORT_TYPE_VECTOR;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeParticleRandomness::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "min";
+ } else if (p_port == 1) {
+ return "max";
+ }
+ return String();
+}
+
+String VisualShaderNodeParticleRandomness::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ if (op_type == OP_TYPE_SCALAR) {
+ code += vformat("\t%s = __randf_range(__seed, %s, %s);\n", p_output_vars[0], p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0], p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]);
+ } else if (op_type == OP_TYPE_VECTOR) {
+ code += vformat("\t%s = __randv_range(__seed, %s, %s);\n", p_output_vars[0], p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0], p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]);
+ }
+ return code;
+}
+
+void VisualShaderNodeParticleRandomness::set_op_type(OpType p_op_type) {
+ ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX);
+ if (p_op_type != op_type) {
+ if (p_op_type == OP_TYPE_SCALAR) {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 1.0);
+ } else {
+ set_input_port_default_value(0, Vector3(-1.0, -1.0, -1.0));
+ set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0));
+ }
+ }
+ op_type = p_op_type;
+ emit_changed();
+}
+
+VisualShaderNodeParticleRandomness::OpType VisualShaderNodeParticleRandomness::get_op_type() const {
+ return op_type;
+}
+
+VisualShaderNodeParticleRandomness::VisualShaderNodeParticleRandomness() {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 1.0);
+}
+
+// VisualShaderNodeParticleAccelerator
+
+void VisualShaderNodeParticleAccelerator::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mode", "mode"), &VisualShaderNodeParticleAccelerator::set_mode);
+ ClassDB::bind_method(D_METHOD("get_mode"), &VisualShaderNodeParticleAccelerator::get_mode);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Linear,Radial,Tangential"), "set_mode", "get_mode");
+
+ BIND_ENUM_CONSTANT(MODE_LINEAR);
+ BIND_ENUM_CONSTANT(MODE_RADIAL)
+ BIND_ENUM_CONSTANT(MODE_TANGENTIAL);
+ BIND_ENUM_CONSTANT(MODE_MAX);
+}
+
+Vector<StringName> VisualShaderNodeParticleAccelerator::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("mode");
+ return props;
+}
+
+String VisualShaderNodeParticleAccelerator::get_caption() const {
+ return "ParticleAccelerator";
+}
+
+int VisualShaderNodeParticleAccelerator::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeParticleAccelerator::PortType VisualShaderNodeParticleAccelerator::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeParticleAccelerator::get_output_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeParticleAccelerator::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeParticleAccelerator::PortType VisualShaderNodeParticleAccelerator::get_input_port_type(int p_port) const {
+ if (p_port == 0) {
+ return PORT_TYPE_VECTOR;
+ } else if (p_port == 1) {
+ return PORT_TYPE_SCALAR;
+ } else if (p_port == 2) {
+ return PORT_TYPE_VECTOR;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeParticleAccelerator::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "amount";
+ } else if (p_port == 1) {
+ return "randomness";
+ } else if (p_port == 2) {
+ return "axis";
+ }
+ return String();
+}
+
+String VisualShaderNodeParticleAccelerator::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ switch (mode) {
+ case MODE_LINEAR:
+ code += "\t" + p_output_vars[0] + " = length(VELOCITY) > 0.0 ? " + "normalize(VELOCITY) * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n";
+ break;
+ case MODE_RADIAL:
+ code += "\t" + p_output_vars[0] + " = length(__diff) > 0.0 ? __ndiff * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n";
+ break;
+ case MODE_TANGENTIAL:
+ code += "\t__vec3_buff1 = cross(__ndiff, normalize(" + (p_input_vars[2].is_empty() ? "vec3" + (String)get_input_port_default_value(2) : p_input_vars[2]) + "));\n";
+ code += "\t" + p_output_vars[0] + " = length(__vec3_buff1) > 0.0 ? normalize(__vec3_buff1) * (" + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ")) : vec3(0.0);\n";
+ break;
+ case MODE_MAX:
+ break;
+ default:
+ break;
+ }
+
+ return code;
+}
+
+void VisualShaderNodeParticleAccelerator::set_mode(Mode p_mode) {
+ mode = p_mode;
+ emit_changed();
+}
+
+VisualShaderNodeParticleAccelerator::Mode VisualShaderNodeParticleAccelerator::get_mode() const {
+ return mode;
+}
+
+VisualShaderNodeParticleAccelerator::VisualShaderNodeParticleAccelerator() {
+ set_input_port_default_value(0, Vector3(1, 1, 1));
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, Vector3(0, -9.8, 0));
+}
+
+// VisualShaderNodeParticleOutput
+
+String VisualShaderNodeParticleOutput::get_caption() const {
+ if (shader_type == VisualShader::TYPE_START) {
+ return "StartOutput";
+ } else if (shader_type == VisualShader::TYPE_PROCESS) {
+ return "ProcessOutput";
+ } else if (shader_type == VisualShader::TYPE_COLLIDE) {
+ return "CollideOutput";
+ } else if (shader_type == VisualShader::TYPE_START_CUSTOM) {
+ return "CustomStartOutput";
+ } else if (shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ return "CustomProcessOutput";
+ }
+ return String();
+}
+
+int VisualShaderNodeParticleOutput::get_input_port_count() const {
+ if (shader_type == VisualShader::TYPE_START) {
+ return 8;
+ } else if (shader_type == VisualShader::TYPE_COLLIDE) {
+ return 5;
+ } else if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ return 6;
+ } else { // TYPE_PROCESS
+ return 7;
+ }
+ return 0;
+}
+
+VisualShaderNodeParticleOutput::PortType VisualShaderNodeParticleOutput::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ return PORT_TYPE_VECTOR; // custom.rgb
+ }
+ return PORT_TYPE_BOOLEAN; // active
+ case 1:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ break; // custom.a (scalar)
+ }
+ return PORT_TYPE_VECTOR; // velocity
+ case 2:
+ return PORT_TYPE_VECTOR; // color & velocity
+ case 3:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ return PORT_TYPE_VECTOR; // color
+ }
+ break; // alpha (scalar)
+ case 4:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ break; // alpha
+ }
+ if (shader_type == VisualShader::TYPE_PROCESS) {
+ break; // scale
+ }
+ if (shader_type == VisualShader::TYPE_COLLIDE) {
+ return PORT_TYPE_TRANSFORM; // transform
+ }
+ return PORT_TYPE_VECTOR; // position
+ case 5:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ return PORT_TYPE_TRANSFORM; // transform
+ }
+ if (shader_type == VisualShader::TYPE_PROCESS) {
+ return PORT_TYPE_VECTOR; // rotation_axis
+ }
+ break; // scale (scalar)
+ case 6:
+ if (shader_type == VisualShader::TYPE_START) {
+ return PORT_TYPE_VECTOR; // rotation_axis
+ }
+ break;
+ case 7:
+ break; // angle (scalar)
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeParticleOutput::get_input_port_name(int p_port) const {
+ String port_name;
+ switch (p_port) {
+ case 0:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ port_name = "custom";
+ break;
+ }
+ port_name = "active";
+ break;
+ case 1:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ port_name = "custom_alpha";
+ break;
+ }
+ port_name = "velocity";
+ break;
+ case 2:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ port_name = "velocity";
+ break;
+ }
+ port_name = "color";
+ break;
+ case 3:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ port_name = "color";
+ break;
+ }
+ port_name = "alpha";
+ break;
+ case 4:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ port_name = "alpha";
+ break;
+ }
+ if (shader_type == VisualShader::TYPE_PROCESS) {
+ port_name = "scale";
+ break;
+ }
+ if (shader_type == VisualShader::TYPE_COLLIDE) {
+ port_name = "transform";
+ break;
+ }
+ port_name = "position";
+ break;
+ case 5:
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ port_name = "transform";
+ break;
+ }
+ if (shader_type == VisualShader::TYPE_PROCESS) {
+ port_name = "rotation_axis";
+ break;
+ }
+ port_name = "scale";
+ break;
+ case 6:
+ if (shader_type == VisualShader::TYPE_PROCESS) {
+ port_name = "angle_in_radians";
+ break;
+ }
+ port_name = "rotation_axis";
+ break;
+ case 7:
+ port_name = "angle_in_radians";
+ break;
+ default:
+ break;
+ }
+ if (!port_name.is_empty()) {
+ return port_name.capitalize();
+ }
+ return String();
+}
+
+bool VisualShaderNodeParticleOutput::is_port_separator(int p_index) const {
+ if (shader_type == VisualShader::TYPE_START || shader_type == VisualShader::TYPE_PROCESS) {
+ String name = get_input_port_name(p_index);
+ return bool(name == "Scale");
+ }
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ String name = get_input_port_name(p_index);
+ return bool(name == "Velocity");
+ }
+ return false;
+}
+
+String VisualShaderNodeParticleOutput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ String tab = "\t";
+
+ if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
+ if (!p_input_vars[0].is_empty()) { // custom.rgb
+ code += tab + "CUSTOM.rgb = " + p_input_vars[0] + ";\n";
+ }
+ if (!p_input_vars[1].is_empty()) { // custom.a
+ code += tab + "CUSTOM.a = " + p_input_vars[1] + ";\n";
+ }
+ if (!p_input_vars[2].is_empty()) { // velocity
+ code += tab + "VELOCITY = " + p_input_vars[2] + ";\n";
+ }
+ if (!p_input_vars[3].is_empty()) { // color.rgb
+ code += tab + "COLOR.rgb = " + p_input_vars[3] + ";\n";
+ }
+ if (!p_input_vars[4].is_empty()) { // color.a
+ code += tab + "COLOR.a = " + p_input_vars[4] + ";\n";
+ }
+ if (!p_input_vars[5].is_empty()) { // transform
+ code += tab + "TRANSFORM = " + p_input_vars[5] + ";\n";
+ }
+ } else {
+ if (!p_input_vars[0].is_empty()) { // active (begin)
+ code += tab + "ACTIVE = " + p_input_vars[0] + ";\n";
+ code += tab + "if(ACTIVE) {\n";
+ tab += "\t";
+ }
+ if (!p_input_vars[1].is_empty()) { // velocity
+ code += tab + "VELOCITY = " + p_input_vars[1] + ";\n";
+ }
+ if (!p_input_vars[2].is_empty()) { // color
+ code += tab + "COLOR.rgb = " + p_input_vars[2] + ";\n";
+ }
+ if (!p_input_vars[3].is_empty()) { // alpha
+ code += tab + "COLOR.a = " + p_input_vars[3] + ";\n";
+ }
+
+ // position
+ if (shader_type == VisualShader::TYPE_START) {
+ code += tab + "if (RESTART_POSITION) {\n";
+ if (!p_input_vars[4].is_empty()) {
+ code += tab + "\tTRANSFORM = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(" + p_input_vars[4] + ", 1.0));\n";
+ } else {
+ code += tab + "\tTRANSFORM = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ }
+ code += tab + "\tif (RESTART_VELOCITY) {\n";
+ code += tab + "\t\tVELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
+ code += tab + "\t}\n";
+ code += tab + "\tTRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
+ code += tab + "}\n";
+ } else if (shader_type == VisualShader::TYPE_COLLIDE) { // position
+ if (!p_input_vars[4].is_empty()) {
+ code += tab + "TRANSFORM = " + p_input_vars[4] + ";\n";
+ }
+ }
+
+ if (shader_type == VisualShader::TYPE_START || shader_type == VisualShader::TYPE_PROCESS) {
+ int scale = 5;
+ int rotation_axis = 6;
+ int rotation = 7;
+ if (shader_type == VisualShader::TYPE_PROCESS) {
+ scale = 4;
+ rotation_axis = 5;
+ rotation = 6;
+ }
+ String op;
+ if (shader_type == VisualShader::TYPE_START) {
+ op = "*=";
+ } else {
+ op = "=";
+ }
+
+ if (!p_input_vars[rotation].is_empty()) { // rotation_axis & angle_in_radians
+ String axis;
+ if (p_input_vars[rotation_axis].is_empty()) {
+ axis = "vec3(0, 1, 0)";
+ } else {
+ axis = p_input_vars[rotation_axis];
+ }
+ code += tab + "TRANSFORM " + op + " __build_rotation_mat4(" + axis + ", " + p_input_vars[rotation] + ");\n";
+ }
+ if (!p_input_vars[scale].is_empty()) { // scale
+ code += tab + "TRANSFORM " + op + " mat4(vec4(" + p_input_vars[scale] + ", 0, 0, 0), vec4(0, " + p_input_vars[scale] + ", 0, 0), vec4(0, 0, " + p_input_vars[scale] + ", 0), vec4(0, 0, 0, 1));\n";
+ }
+ }
+ if (!p_input_vars[0].is_empty()) { // active (end)
+ code += "\t}\n";
+ }
+ }
+ return code;
+}
+
+VisualShaderNodeParticleOutput::VisualShaderNodeParticleOutput() {
+}
+
+// EmitParticle
+
+Vector<StringName> VisualShaderNodeParticleEmit::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("flags");
+ return props;
+}
+
+void VisualShaderNodeParticleEmit::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_flags", "flags"), &VisualShaderNodeParticleEmit::set_flags);
+ ClassDB::bind_method(D_METHOD("get_flags"), &VisualShaderNodeParticleEmit::get_flags);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Position,RotScale,Velocity,Color,Custom"), "set_flags", "get_flags");
+
+ BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_ROT_SCALE);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_VELOCITY);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_COLOR);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM);
+}
+
+String VisualShaderNodeParticleEmit::get_caption() const {
+ return "EmitParticle";
+}
+
+int VisualShaderNodeParticleEmit::get_input_port_count() const {
+ return 7;
+}
+
+VisualShaderNodeParticleEmit::PortType VisualShaderNodeParticleEmit::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_BOOLEAN;
+ case 1:
+ return PORT_TYPE_TRANSFORM;
+ case 2:
+ return PORT_TYPE_VECTOR;
+ case 3:
+ return PORT_TYPE_VECTOR;
+ case 4:
+ return PORT_TYPE_SCALAR;
+ case 5:
+ return PORT_TYPE_VECTOR;
+ case 6:
+ return PORT_TYPE_SCALAR;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeParticleEmit::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "condition";
+ case 1:
+ return "transform";
+ case 2:
+ return "velocity";
+ case 3:
+ return "color";
+ case 4:
+ return "alpha";
+ case 5:
+ return "custom";
+ case 6:
+ return "custom_alpha";
+ }
+ return String();
+}
+
+int VisualShaderNodeParticleEmit::get_output_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeParticleEmit::PortType VisualShaderNodeParticleEmit::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeParticleEmit::get_output_port_name(int p_port) const {
+ return String();
+}
+
+void VisualShaderNodeParticleEmit::add_flag(EmitFlags p_flag) {
+ flags |= p_flag;
+ emit_changed();
+}
+
+bool VisualShaderNodeParticleEmit::has_flag(EmitFlags p_flag) const {
+ return flags & p_flag;
+}
+
+void VisualShaderNodeParticleEmit::set_flags(EmitFlags p_flags) {
+ flags = (int)p_flags;
+ emit_changed();
+}
+
+VisualShaderNodeParticleEmit::EmitFlags VisualShaderNodeParticleEmit::get_flags() const {
+ return EmitFlags(flags);
+}
+
+bool VisualShaderNodeParticleEmit::is_show_prop_names() const {
+ return true;
+}
+
+bool VisualShaderNodeParticleEmit::is_generate_input_var(int p_port) const {
+ if (p_port == 0) {
+ if (!is_input_port_connected(0)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+String VisualShaderNodeParticleEmit::get_input_port_default_hint(int p_port) const {
+ switch (p_port) {
+ case 1:
+ return "default";
+ case 2:
+ return "default";
+ case 3:
+ return "default";
+ case 4:
+ return "default";
+ case 5:
+ return "default";
+ case 6:
+ return "default";
+ }
+ return String();
+}
+
+String VisualShaderNodeParticleEmit::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ String tab;
+ bool default_condition = false;
+
+ if (!is_input_port_connected(0)) {
+ default_condition = true;
+ if (get_input_port_default_value(0)) {
+ tab = "\t";
+ } else {
+ return code;
+ }
+ } else {
+ tab = "\t\t";
+ }
+
+ String transform;
+ if (p_input_vars[1].is_empty()) {
+ transform = "TRANSFORM";
+ } else {
+ transform = p_input_vars[1];
+ }
+
+ String velocity;
+ if (p_input_vars[2].is_empty()) {
+ velocity = "VELOCITY";
+ } else {
+ velocity = p_input_vars[2];
+ }
+
+ String color;
+ if (p_input_vars[3].is_empty()) {
+ color = "COLOR.rgb";
+ } else {
+ color = p_input_vars[3];
+ }
+
+ String alpha;
+ if (p_input_vars[4].is_empty()) {
+ alpha = "COLOR.a";
+ } else {
+ alpha = p_input_vars[4];
+ }
+
+ String custom;
+ if (p_input_vars[5].is_empty()) {
+ custom = "CUSTOM.rgb";
+ } else {
+ custom = p_input_vars[5];
+ }
+
+ String custom_alpha;
+ if (p_input_vars[6].is_empty()) {
+ custom_alpha = "CUSTOM.a";
+ } else {
+ custom_alpha = p_input_vars[6];
+ }
+
+ List<String> flags_arr;
+
+ if (has_flag(EmitFlags::EMIT_FLAG_POSITION)) {
+ flags_arr.push_back("FLAG_EMIT_POSITION");
+ }
+ if (has_flag(EmitFlags::EMIT_FLAG_ROT_SCALE)) {
+ flags_arr.push_back("FLAG_EMIT_ROT_SCALE");
+ }
+ if (has_flag(EmitFlags::EMIT_FLAG_VELOCITY)) {
+ flags_arr.push_back("FLAG_EMIT_VELOCITY");
+ }
+ if (has_flag(EmitFlags::EMIT_FLAG_COLOR)) {
+ flags_arr.push_back("FLAG_EMIT_COLOR");
+ }
+ if (has_flag(EmitFlags::EMIT_FLAG_CUSTOM)) {
+ flags_arr.push_back("FLAG_EMIT_CUSTOM");
+ }
+
+ String flags;
+
+ for (int i = 0; i < flags_arr.size(); i++) {
+ if (i > 0) {
+ flags += "|";
+ }
+ flags += flags_arr[i];
+ }
+
+ if (flags.is_empty()) {
+ flags = "uint(0)";
+ }
+
+ if (!default_condition) {
+ code += "\tif (" + p_input_vars[0] + ") {\n";
+ }
+
+ code += tab + "emit_subparticle(" + transform + ", " + velocity + ", vec4(" + color + ", " + alpha + "), vec4(" + custom + ", " + custom_alpha + "), " + flags + ");\n";
+
+ if (!default_condition) {
+ code += "\t}\n";
+ }
+
+ return code;
+}
+
+VisualShaderNodeParticleEmit::VisualShaderNodeParticleEmit() {
+ set_input_port_default_value(0, true);
+}
diff --git a/scene/resources/visual_shader_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h
new file mode 100644
index 0000000000..ecd187a885
--- /dev/null
+++ b/scene/resources/visual_shader_particle_nodes.h
@@ -0,0 +1,285 @@
+/*************************************************************************/
+/* visual_shader_particle_nodes.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef VISUAL_SHADER_PARTICLE_NODES_H
+#define VISUAL_SHADER_PARTICLE_NODES_H
+
+#include "scene/resources/visual_shader.h"
+
+// Emit nodes
+
+class VisualShaderNodeParticleEmitter : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeParticleEmitter, VisualShaderNode);
+
+public:
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ VisualShaderNodeParticleEmitter();
+};
+
+class VisualShaderNodeParticleSphereEmitter : public VisualShaderNodeParticleEmitter {
+ GDCLASS(VisualShaderNodeParticleSphereEmitter, VisualShaderNodeParticleEmitter);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeParticleSphereEmitter();
+};
+
+class VisualShaderNodeParticleBoxEmitter : public VisualShaderNodeParticleEmitter {
+ GDCLASS(VisualShaderNodeParticleBoxEmitter, VisualShaderNodeParticleEmitter);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeParticleBoxEmitter();
+};
+
+class VisualShaderNodeParticleRingEmitter : public VisualShaderNodeParticleEmitter {
+ GDCLASS(VisualShaderNodeParticleRingEmitter, VisualShaderNodeParticleEmitter);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeParticleRingEmitter();
+};
+
+class VisualShaderNodeParticleMultiplyByAxisAngle : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeParticleMultiplyByAxisAngle, VisualShaderNode);
+ bool degrees_mode = true;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+ virtual bool is_show_prop_names() const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ void set_degrees_mode(bool p_enabled);
+ bool is_degrees_mode() const;
+ Vector<StringName> get_editable_properties() const override;
+
+ VisualShaderNodeParticleMultiplyByAxisAngle();
+};
+
+class VisualShaderNodeParticleConeVelocity : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeParticleConeVelocity, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeParticleConeVelocity();
+};
+
+class VisualShaderNodeParticleRandomness : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeParticleRandomness, VisualShaderNode);
+
+public:
+ enum OpType {
+ OP_TYPE_SCALAR,
+ OP_TYPE_VECTOR,
+ OP_TYPE_MAX,
+ };
+
+private:
+ OpType op_type = OP_TYPE_SCALAR;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Vector<StringName> get_editable_properties() const override;
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ void set_op_type(OpType p_type);
+ OpType get_op_type() const;
+
+ VisualShaderNodeParticleRandomness();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeParticleRandomness::OpType)
+
+// Process nodes
+
+class VisualShaderNodeParticleAccelerator : public VisualShaderNodeOutput {
+ GDCLASS(VisualShaderNodeParticleAccelerator, VisualShaderNodeOutput);
+
+public:
+ enum Mode {
+ MODE_LINEAR,
+ MODE_RADIAL,
+ MODE_TANGENTIAL,
+ MODE_MAX,
+ };
+
+private:
+ Mode mode = MODE_LINEAR;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Vector<StringName> get_editable_properties() const override;
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ void set_mode(Mode p_mode);
+ Mode get_mode() const;
+
+ VisualShaderNodeParticleAccelerator();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeParticleAccelerator::Mode)
+
+// Common nodes
+
+class VisualShaderNodeParticleOutput : public VisualShaderNodeOutput {
+ GDCLASS(VisualShaderNodeParticleOutput, VisualShaderNodeOutput);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+ virtual bool is_port_separator(int p_index) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeParticleOutput();
+};
+
+class VisualShaderNodeParticleEmit : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeParticleEmit, VisualShaderNode);
+
+public:
+ enum EmitFlags {
+ EMIT_FLAG_POSITION = 1,
+ EMIT_FLAG_ROT_SCALE = 2,
+ EMIT_FLAG_VELOCITY = 4,
+ EMIT_FLAG_COLOR = 8,
+ EMIT_FLAG_CUSTOM = 16,
+ };
+
+protected:
+ int flags = EMIT_FLAG_POSITION | EMIT_FLAG_ROT_SCALE | EMIT_FLAG_VELOCITY | EMIT_FLAG_COLOR | EMIT_FLAG_CUSTOM;
+ static void _bind_methods();
+
+public:
+ Vector<StringName> get_editable_properties() const override;
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ void add_flag(EmitFlags p_flag);
+ bool has_flag(EmitFlags p_flag) const;
+
+ void set_flags(EmitFlags p_flags);
+ EmitFlags get_flags() const;
+
+ virtual bool is_show_prop_names() const override;
+ virtual bool is_generate_input_var(int p_port) const override;
+ virtual String get_input_port_default_hint(int p_port) const override;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeParticleEmit();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeParticleEmit::EmitFlags)
+
+#endif
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index ccdc5bebd0..9a7a47f884 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -38,284 +38,6 @@
#include "servers/physics_server_2d.h"
#include "servers/rendering_server.h"
-struct SpatialIndexer2D {
- struct CellRef {
- int ref = 0;
-
- _FORCE_INLINE_ int inc() {
- ref++;
- return ref;
- }
- _FORCE_INLINE_ int dec() {
- ref--;
- return ref;
- }
- };
-
- struct CellKey {
- union {
- struct {
- int32_t x;
- int32_t y;
- };
- uint64_t key = 0;
- };
-
- bool operator==(const CellKey &p_key) const { return key == p_key.key; }
- _FORCE_INLINE_ bool operator<(const CellKey &p_key) const {
- return key < p_key.key;
- }
- };
-
- struct CellData {
- Map<VisibilityNotifier2D *, CellRef> notifiers;
- };
-
- Map<CellKey, CellData> cells;
- int cell_size;
-
- Map<VisibilityNotifier2D *, Rect2> notifiers;
-
- struct ViewportData {
- Map<VisibilityNotifier2D *, uint64_t> notifiers;
- Rect2 rect;
- };
-
- Map<Viewport *, ViewportData> viewports;
-
- bool changed = false;
-
- uint64_t pass = 0;
-
- void _notifier_update_cells(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect, bool p_add) {
- Point2i begin = p_rect.position;
- begin /= cell_size;
- Point2i end = p_rect.position + p_rect.size;
- end /= cell_size;
- for (int i = begin.x; i <= end.x; i++) {
- for (int j = begin.y; j <= end.y; j++) {
- CellKey ck;
- ck.x = i;
- ck.y = j;
- Map<CellKey, CellData>::Element *E = cells.find(ck);
-
- if (p_add) {
- if (!E) {
- E = cells.insert(ck, CellData());
- }
- E->get().notifiers[p_notifier].inc();
- } else {
- ERR_CONTINUE(!E);
- if (E->get().notifiers[p_notifier].dec() == 0) {
- E->get().notifiers.erase(p_notifier);
- if (E->get().notifiers.is_empty()) {
- cells.erase(E);
- }
- }
- }
- }
- }
- }
-
- void _notifier_add(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) {
- ERR_FAIL_COND(notifiers.has(p_notifier));
- notifiers[p_notifier] = p_rect;
- _notifier_update_cells(p_notifier, p_rect, true);
- changed = true;
- }
-
- void _notifier_update(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) {
- Map<VisibilityNotifier2D *, Rect2>::Element *E = notifiers.find(p_notifier);
- ERR_FAIL_COND(!E);
- if (E->get() == p_rect) {
- return;
- }
-
- _notifier_update_cells(p_notifier, p_rect, true);
- _notifier_update_cells(p_notifier, E->get(), false);
- E->get() = p_rect;
- changed = true;
- }
-
- void _notifier_remove(VisibilityNotifier2D *p_notifier) {
- Map<VisibilityNotifier2D *, Rect2>::Element *E = notifiers.find(p_notifier);
- ERR_FAIL_COND(!E);
- _notifier_update_cells(p_notifier, E->get(), false);
- notifiers.erase(p_notifier);
-
- List<Viewport *> removed;
- for (Map<Viewport *, ViewportData>::Element *F = viewports.front(); F; F = F->next()) {
- Map<VisibilityNotifier2D *, uint64_t>::Element *G = F->get().notifiers.find(p_notifier);
-
- if (G) {
- F->get().notifiers.erase(G);
- removed.push_back(F->key());
- }
- }
-
- while (!removed.is_empty()) {
- p_notifier->_exit_viewport(removed.front()->get());
- removed.pop_front();
- }
-
- changed = true;
- }
-
- void _add_viewport(Viewport *p_viewport, const Rect2 &p_rect) {
- ERR_FAIL_COND(viewports.has(p_viewport));
- ViewportData vd;
- vd.rect = p_rect;
- viewports[p_viewport] = vd;
- changed = true;
- }
-
- void _update_viewport(Viewport *p_viewport, const Rect2 &p_rect) {
- Map<Viewport *, ViewportData>::Element *E = viewports.find(p_viewport);
- ERR_FAIL_COND(!E);
- if (E->get().rect == p_rect) {
- return;
- }
- E->get().rect = p_rect;
- changed = true;
- }
-
- void _remove_viewport(Viewport *p_viewport) {
- ERR_FAIL_COND(!viewports.has(p_viewport));
- List<VisibilityNotifier2D *> removed;
- for (Map<VisibilityNotifier2D *, uint64_t>::Element *E = viewports[p_viewport].notifiers.front(); E; E = E->next()) {
- removed.push_back(E->key());
- }
-
- while (!removed.is_empty()) {
- removed.front()->get()->_exit_viewport(p_viewport);
- removed.pop_front();
- }
-
- viewports.erase(p_viewport);
- }
-
- void _update() {
- if (!changed) {
- return;
- }
-
- for (Map<Viewport *, ViewportData>::Element *E = viewports.front(); E; E = E->next()) {
- Point2i begin = E->get().rect.position;
- begin /= cell_size;
- Point2i end = E->get().rect.position + E->get().rect.size;
- end /= cell_size;
- pass++;
- List<VisibilityNotifier2D *> added;
- List<VisibilityNotifier2D *> removed;
-
- uint64_t visible_cells = (uint64_t)(end.x - begin.x) * (uint64_t)(end.y - begin.y);
-
- if (visible_cells > 10000) {
- //well you zoomed out a lot, it's your problem. To avoid freezing in the for loops below, we'll manually check cell by cell
-
- for (Map<CellKey, CellData>::Element *F = cells.front(); F; F = F->next()) {
- const CellKey &ck = F->key();
-
- if (ck.x < begin.x || ck.x > end.x) {
- continue;
- }
- if (ck.y < begin.y || ck.y > end.y) {
- continue;
- }
-
- //notifiers in cell
- for (Map<VisibilityNotifier2D *, CellRef>::Element *G = F->get().notifiers.front(); G; G = G->next()) {
- Map<VisibilityNotifier2D *, uint64_t>::Element *H = E->get().notifiers.find(G->key());
- if (!H) {
- H = E->get().notifiers.insert(G->key(), pass);
- added.push_back(G->key());
- } else {
- H->get() = pass;
- }
- }
- }
-
- } else {
- //check cells in grid fashion
- for (int i = begin.x; i <= end.x; i++) {
- for (int j = begin.y; j <= end.y; j++) {
- CellKey ck;
- ck.x = i;
- ck.y = j;
-
- Map<CellKey, CellData>::Element *F = cells.find(ck);
- if (!F) {
- continue;
- }
-
- //notifiers in cell
- for (Map<VisibilityNotifier2D *, CellRef>::Element *G = F->get().notifiers.front(); G; G = G->next()) {
- Map<VisibilityNotifier2D *, uint64_t>::Element *H = E->get().notifiers.find(G->key());
- if (!H) {
- H = E->get().notifiers.insert(G->key(), pass);
- added.push_back(G->key());
- } else {
- H->get() = pass;
- }
- }
- }
- }
- }
-
- for (Map<VisibilityNotifier2D *, uint64_t>::Element *F = E->get().notifiers.front(); F; F = F->next()) {
- if (F->get() != pass) {
- removed.push_back(F->key());
- }
- }
-
- while (!added.is_empty()) {
- added.front()->get()->_enter_viewport(E->key());
- added.pop_front();
- }
-
- while (!removed.is_empty()) {
- E->get().notifiers.erase(removed.front()->get());
- removed.front()->get()->_exit_viewport(E->key());
- removed.pop_front();
- }
- }
-
- changed = false;
- }
-
- SpatialIndexer2D() {
- cell_size = GLOBAL_DEF("world/2d/cell_size", 100);
- }
-};
-
-void World2D::_register_viewport(Viewport *p_viewport, const Rect2 &p_rect) {
- indexer->_add_viewport(p_viewport, p_rect);
-}
-
-void World2D::_update_viewport(Viewport *p_viewport, const Rect2 &p_rect) {
- indexer->_update_viewport(p_viewport, p_rect);
-}
-
-void World2D::_remove_viewport(Viewport *p_viewport) {
- indexer->_remove_viewport(p_viewport);
-}
-
-void World2D::_register_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) {
- indexer->_notifier_add(p_notifier, p_rect);
-}
-
-void World2D::_update_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) {
- indexer->_notifier_update(p_notifier, p_rect);
-}
-
-void World2D::_remove_notifier(VisibilityNotifier2D *p_notifier) {
- indexer->_notifier_remove(p_notifier);
-}
-
-void World2D::_update() {
- indexer->_update();
-}
-
RID World2D::get_canvas() const {
return canvas;
}
@@ -328,12 +50,6 @@ RID World2D::get_navigation_map() const {
return navigation_map;
}
-void World2D::get_viewport_list(List<Viewport *> *r_viewports) {
- for (Map<Viewport *, SpatialIndexer2D::ViewportData>::Element *E = indexer->viewports.front(); E; E = E->next()) {
- r_viewports->push_back(E->key());
- }
-}
-
void World2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_canvas"), &World2D::get_canvas);
ClassDB::bind_method(D_METHOD("get_space"), &World2D::get_space);
@@ -357,7 +73,7 @@ World2D::World2D() {
// Create and configure space2D to be more friendly with pixels than meters
space = PhysicsServer2D::get_singleton()->space_create();
PhysicsServer2D::get_singleton()->space_set_active(space, true);
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/2d/default_gravity", 98));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/2d/default_gravity", 980.0));
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"));
@@ -369,13 +85,10 @@ World2D::World2D() {
NavigationServer2D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 10));
NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 5));
-
- indexer = memnew(SpatialIndexer2D);
}
World2D::~World2D() {
RenderingServer::get_singleton()->free(canvas);
PhysicsServer2D::get_singleton()->free(space);
NavigationServer2D::get_singleton()->free(navigation_map);
- memdelete(indexer);
}
diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h
index 38abf3d7ad..e31ac22351 100644
--- a/scene/resources/world_2d.h
+++ b/scene/resources/world_2d.h
@@ -46,23 +46,15 @@ class World2D : public Resource {
RID space;
RID navigation_map;
- SpatialIndexer2D *indexer;
+ Set<Viewport *> viewports;
protected:
static void _bind_methods();
friend class Viewport;
- friend class VisibilityNotifier2D;
- void _register_viewport(Viewport *p_viewport, const Rect2 &p_rect);
- void _update_viewport(Viewport *p_viewport, const Rect2 &p_rect);
+ void _register_viewport(Viewport *p_viewport);
void _remove_viewport(Viewport *p_viewport);
- void _register_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect);
- void _update_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect);
- void _remove_notifier(VisibilityNotifier2D *p_notifier);
-
- void _update();
-
public:
RID get_canvas() const;
RID get_space() const;
@@ -70,7 +62,7 @@ public:
PhysicsDirectSpaceState2D *get_direct_space_state();
- void get_viewport_list(List<Viewport *> *r_viewports);
+ _FORCE_INLINE_ const Set<Viewport *> &get_viewports() { return viewports; }
World2D();
~World2D();
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index f067771d58..a85bd8fdba 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -37,206 +37,15 @@
#include "scene/scene_string_names.h"
#include "servers/navigation_server_3d.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.is_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.is_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.is_empty()) {
- added.front()->get()->_enter_camera(E->key());
- added.pop_front();
- }
-
- while (!removed.is_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);
+ cameras.insert(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);
+ cameras.erase(p_camera);
#endif
}
@@ -307,12 +116,6 @@ 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_navigation_map"), &World3D::get_navigation_map);
@@ -321,7 +124,7 @@ void World3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_environment"), &World3D::get_environment);
ClassDB::bind_method(D_METHOD("set_fallback_environment", "env"), &World3D::set_fallback_environment);
ClassDB::bind_method(D_METHOD("get_fallback_environment"), &World3D::get_fallback_environment);
- ClassDB::bind_method(D_METHOD("set_camera_effects", "env"), &World3D::set_camera_effects);
+ ClassDB::bind_method(D_METHOD("set_camera_effects", "effects"), &World3D::set_camera_effects);
ClassDB::bind_method(D_METHOD("get_camera_effects"), &World3D::get_camera_effects);
ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World3D::get_direct_space_state);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
@@ -349,20 +152,10 @@ World3D::World3D() {
NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.3));
NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.3));
-
-#ifdef _3D_DISABLED
- indexer = nullptr;
-#else
- indexer = memnew(SpatialIndexer);
-#endif
}
World3D::~World3D() {
PhysicsServer3D::get_singleton()->free(space);
RenderingServer::get_singleton()->free(scenario);
NavigationServer3D::get_singleton()->free(navigation_map);
-
-#ifndef _3D_DISABLED
- memdelete(indexer);
-#endif
}
diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h
index 4e2717a2bb..da5ed486b0 100644
--- a/scene/resources/world_3d.h
+++ b/scene/resources/world_3d.h
@@ -48,27 +48,21 @@ private:
RID space;
RID navigation_map;
RID scenario;
- SpatialIndexer *indexer;
+
Ref<Environment> environment;
Ref<Environment> fallback_environment;
Ref<CameraEffects> camera_effects;
+ Set<Camera3D *> cameras;
+
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_navigation_map() const;
@@ -83,7 +77,7 @@ public:
void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
Ref<CameraEffects> get_camera_effects() const;
- void get_camera_list(List<Camera3D *> *r_cameras);
+ _FORCE_INLINE_ const Set<Camera3D *> &get_cameras() const { return cameras; }
PhysicsDirectSpaceState3D *get_direct_space_state();
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 7575ccd5c3..8acab79c9e 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -155,13 +155,13 @@ SceneStringNames::SceneStringNames() {
area_entered = StaticCString::create("area_entered");
area_exited = StaticCString::create("area_exited");
- has_point = StaticCString::create("has_point");
+ _has_point = StaticCString::create("_has_point");
line_separation = StaticCString::create("line_separation");
- get_drag_data = StaticCString::create("get_drag_data");
- drop_data = StaticCString::create("drop_data");
- can_drop_data = StaticCString::create("can_drop_data");
+ _get_drag_data = StaticCString::create("_get_drag_data");
+ _drop_data = StaticCString::create("_drop_data");
+ _can_drop_data = StaticCString::create("_can_drop_data");
_im_update = StaticCString::create("_im_update"); // Sprite3D
@@ -175,6 +175,7 @@ SceneStringNames::SceneStringNames() {
_toggled = StaticCString::create("_toggled");
frame_changed = StaticCString::create("frame_changed");
+ texture_changed = StaticCString::create("texture_changed");
playback_speed = StaticCString::create("playback/speed");
playback_active = StaticCString::create("playback/active");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index a5b489eddc..0c528a45f7 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -138,10 +138,10 @@ public:
StringName grouped;
StringName ungrouped;
- StringName has_point;
- StringName get_drag_data;
- StringName can_drop_data;
- StringName drop_data;
+ StringName _has_point;
+ StringName _get_drag_data;
+ StringName _can_drop_data;
+ StringName _drop_data;
StringName screen_entered;
StringName screen_exited;
@@ -184,6 +184,7 @@ public:
StringName _mouse_exit;
StringName frame_changed;
+ StringName texture_changed;
StringName playback_speed;
StringName playback_active;
diff --git a/servers/audio/audio_effect.h b/servers/audio/audio_effect.h
index 4556db9b93..5d14f03199 100644
--- a/servers/audio/audio_effect.h
+++ b/servers/audio/audio_effect.h
@@ -34,8 +34,8 @@
#include "core/io/resource.h"
#include "core/math/audio_frame.h"
-class AudioEffectInstance : public Reference {
- GDCLASS(AudioEffectInstance, Reference);
+class AudioEffectInstance : public RefCounted {
+ GDCLASS(AudioEffectInstance, RefCounted);
public:
virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) = 0;
diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h
index 93566783be..0d426f99b2 100644
--- a/servers/audio/audio_stream.h
+++ b/servers/audio/audio_stream.h
@@ -36,8 +36,8 @@
#include "servers/audio/audio_filter_sw.h"
#include "servers/audio_server.h"
-class AudioStreamPlayback : public Reference {
- GDCLASS(AudioStreamPlayback, Reference);
+class AudioStreamPlayback : public RefCounted {
+ GDCLASS(AudioStreamPlayback, RefCounted);
public:
virtual void start(float p_from_pos = 0.0) = 0;
diff --git a/servers/audio/effects/audio_effect_capture.h b/servers/audio/effects/audio_effect_capture.h
index 81d4ed6b0f..82686d5b4c 100644
--- a/servers/audio/effects/audio_effect_capture.h
+++ b/servers/audio/effects/audio_effect_capture.h
@@ -33,7 +33,7 @@
#include "core/config/engine.h"
#include "core/math/audio_frame.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/templates/vector.h"
#include "servers/audio/audio_effect.h"
#include "servers/audio_server.h"
diff --git a/servers/audio/effects/audio_effect_distortion.cpp b/servers/audio/effects/audio_effect_distortion.cpp
index 06d51776a3..5c076ca3fe 100644
--- a/servers/audio/effects/audio_effect_distortion.cpp
+++ b/servers/audio/effects/audio_effect_distortion.cpp
@@ -159,7 +159,7 @@ void AudioEffectDistortion::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_post_gain", "post_gain"), &AudioEffectDistortion::set_post_gain);
ClassDB::bind_method(D_METHOD("get_post_gain"), &AudioEffectDistortion::get_post_gain);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Clip,ATan,LoFi,Overdrive,WaveShape"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Clip,ATan,LoFi,Overdrive,Wave Shape"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pre_gain", PROPERTY_HINT_RANGE, "-60,60,0.01"), "set_pre_gain", "get_pre_gain");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "keep_hf_hz", PROPERTY_HINT_RANGE, "1,20500,1"), "set_keep_hf_hz", "get_keep_hf_hz");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drive", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drive", "get_drive");
diff --git a/servers/audio/effects/audio_effect_pitch_shift.cpp b/servers/audio/effects/audio_effect_pitch_shift.cpp
index 2123fe8548..7b0151b9c1 100644
--- a/servers/audio/effects/audio_effect_pitch_shift.cpp
+++ b/servers/audio/effects/audio_effect_pitch_shift.cpp
@@ -326,12 +326,12 @@ int AudioEffectPitchShift::get_oversampling() const {
return oversampling;
}
-void AudioEffectPitchShift::set_fft_size(FFT_Size p_fft_size) {
+void AudioEffectPitchShift::set_fft_size(FFTSize p_fft_size) {
ERR_FAIL_INDEX(p_fft_size, FFT_SIZE_MAX);
fft_size = p_fft_size;
}
-AudioEffectPitchShift::FFT_Size AudioEffectPitchShift::get_fft_size() const {
+AudioEffectPitchShift::FFTSize AudioEffectPitchShift::get_fft_size() const {
return fft_size;
}
diff --git a/servers/audio/effects/audio_effect_pitch_shift.h b/servers/audio/effects/audio_effect_pitch_shift.h
index 18a9c33968..669943fa43 100644
--- a/servers/audio/effects/audio_effect_pitch_shift.h
+++ b/servers/audio/effects/audio_effect_pitch_shift.h
@@ -89,7 +89,7 @@ class AudioEffectPitchShift : public AudioEffect {
public:
friend class AudioEffectPitchShiftInstance;
- enum FFT_Size {
+ enum FFTSize {
FFT_SIZE_256,
FFT_SIZE_512,
FFT_SIZE_1024,
@@ -100,7 +100,7 @@ public:
float pitch_scale;
int oversampling;
- FFT_Size fft_size;
+ FFTSize fft_size;
float wet;
float dry;
bool filter;
@@ -117,12 +117,12 @@ public:
void set_oversampling(int p_oversampling);
int get_oversampling() const;
- void set_fft_size(FFT_Size);
- FFT_Size get_fft_size() const;
+ void set_fft_size(FFTSize);
+ FFTSize get_fft_size() const;
AudioEffectPitchShift();
};
-VARIANT_ENUM_CAST(AudioEffectPitchShift::FFT_Size);
+VARIANT_ENUM_CAST(AudioEffectPitchShift::FFTSize);
#endif // AUDIO_EFFECT_PITCH_SHIFT_H
diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h
index b97ec43946..8f56e227e0 100644
--- a/servers/audio/effects/audio_effect_record.h
+++ b/servers/audio/effects/audio_effect_record.h
@@ -31,8 +31,8 @@
#ifndef AUDIOEFFECTRECORD_H
#define AUDIOEFFECTRECORD_H
+#include "core/io/file_access.h"
#include "core/io/marshalls.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/os/thread.h"
#include "editor/import/resource_importer_wav.h"
diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp
index 3f7ab74a74..44b7f64d52 100644
--- a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp
+++ b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp
@@ -245,12 +245,12 @@ float AudioEffectSpectrumAnalyzer::get_tap_back_pos() const {
return tapback_pos;
}
-void AudioEffectSpectrumAnalyzer::set_fft_size(FFT_Size p_fft_size) {
+void AudioEffectSpectrumAnalyzer::set_fft_size(FFTSize p_fft_size) {
ERR_FAIL_INDEX(p_fft_size, FFT_SIZE_MAX);
fft_size = p_fft_size;
}
-AudioEffectSpectrumAnalyzer::FFT_Size AudioEffectSpectrumAnalyzer::get_fft_size() const {
+AudioEffectSpectrumAnalyzer::FFTSize AudioEffectSpectrumAnalyzer::get_fft_size() const {
return fft_size;
}
diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.h b/servers/audio/effects/audio_effect_spectrum_analyzer.h
index fba276e2bb..fc275446f0 100644
--- a/servers/audio/effects/audio_effect_spectrum_analyzer.h
+++ b/servers/audio/effects/audio_effect_spectrum_analyzer.h
@@ -71,7 +71,7 @@ class AudioEffectSpectrumAnalyzer : public AudioEffect {
GDCLASS(AudioEffectSpectrumAnalyzer, AudioEffect);
public:
- enum FFT_Size {
+ enum FFTSize {
FFT_SIZE_256,
FFT_SIZE_512,
FFT_SIZE_1024,
@@ -84,7 +84,7 @@ public:
friend class AudioEffectSpectrumAnalyzerInstance;
float buffer_length;
float tapback_pos;
- FFT_Size fft_size;
+ FFTSize fft_size;
protected:
static void _bind_methods();
@@ -96,12 +96,12 @@ public:
void set_tap_back_pos(float p_seconds);
float get_tap_back_pos() const;
- void set_fft_size(FFT_Size);
- FFT_Size get_fft_size() const;
+ void set_fft_size(FFTSize);
+ FFTSize get_fft_size() const;
AudioEffectSpectrumAnalyzer();
};
-VARIANT_ENUM_CAST(AudioEffectSpectrumAnalyzer::FFT_Size);
+VARIANT_ENUM_CAST(AudioEffectSpectrumAnalyzer::FFTSize);
#endif // AUDIO_EFFECT_SPECTRUM_ANALYZER_H
diff --git a/servers/audio/effects/reverb.cpp b/servers/audio/effects/reverb.cpp
index 7df2f99f67..1d97de5205 100644
--- a/servers/audio/effects/reverb.cpp
+++ b/servers/audio/effects/reverb.cpp
@@ -290,7 +290,7 @@ void Reverb::update_parameters() {
c.feedback = (room_offset + room_scale);
}
- float auxdmp = params.damp / 2.0 + 0.5; //only half the range (0.5 .. 1.0 is enough)
+ float auxdmp = params.damp / 2.0 + 0.5; //only half the range (0.5 .. 1.0 is enough)
auxdmp *= auxdmp;
c.damp = expf(-Math_TAU * auxdmp * 10000 / params.mix_rate); // 0 .. 10khz
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 138cb6e1f8..acfdfa783a 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -32,8 +32,8 @@
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
+#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
-#include "core/os/file_access.h"
#include "core/os/os.h"
#include "scene/resources/audio_stream_sample.h"
#include "servers/audio/audio_driver_dummy.h"
@@ -246,6 +246,7 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) {
init_channels_and_buffers();
}
+ ERR_FAIL_COND_MSG(buses.is_empty() && todo, "AudioServer bus count is less than 1.");
while (todo) {
if (to_mix == 0) {
_mix_step();
@@ -1163,6 +1164,9 @@ void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) {
Bus::Effect bfx;
bfx.effect = fx;
bfx.enabled = p_bus_layout->buses[i].effects[j].enabled;
+#if DEBUG_ENABLED
+ bfx.prof_time = 0;
+#endif
bus->effects.push_back(bfx);
}
}
diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h
index eb4ef155bc..fac7ae1b2d 100644
--- a/servers/camera/camera_feed.h
+++ b/servers/camera/camera_feed.h
@@ -43,8 +43,8 @@
camera feeds that can be used as the background for our environment.
**/
-class CameraFeed : public Reference {
- GDCLASS(CameraFeed, Reference);
+class CameraFeed : public RefCounted {
+ GDCLASS(CameraFeed, RefCounted);
public:
enum FeedDataType {
diff --git a/servers/camera_server.h b/servers/camera_server.h
index 97aa8f74ba..7390129df9 100644
--- a/servers/camera_server.h
+++ b/servers/camera_server.h
@@ -32,7 +32,7 @@
#define CAMERA_SERVER_H
#include "core/object/class_db.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/os/thread_safe.h"
#include "core/templates/rid.h"
#include "core/variant/variant.h"
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 2fa333cc05..ded4b849ef 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -32,14 +32,18 @@
#include "core/input/input.h"
#include "scene/resources/texture.h"
+#include "servers/display_server_headless.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;
+DisplayServer::DisplayServerCreate DisplayServer::server_create_functions[DisplayServer::MAX_SERVERS] = {
+ { "headless", &DisplayServerHeadless::create_func, &DisplayServerHeadless::get_rendering_drivers_func }
+};
+
+int DisplayServer::server_create_count = 1;
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.");
@@ -253,27 +257,6 @@ bool DisplayServer::get_swap_cancel_ok() {
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;
@@ -477,12 +460,6 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("enable_for_stealing_focus", "process_id"), &DisplayServer::enable_for_stealing_focus);
- ClassDB::bind_method(D_METHOD("native_video_play", "path", "volume", "audio_track", "subtitle_track", "screen"), &DisplayServer::native_video_play);
- ClassDB::bind_method(D_METHOD("native_video_is_playing"), &DisplayServer::native_video_is_playing);
- ClassDB::bind_method(D_METHOD("native_video_stop"), &DisplayServer::native_video_stop);
- ClassDB::bind_method(D_METHOD("native_video_pause"), &DisplayServer::native_video_pause);
- 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);
@@ -518,7 +495,6 @@ void DisplayServer::_bind_methods() {
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);
@@ -533,6 +509,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
+ BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED_HIDDEN);
BIND_CONSTANT(SCREEN_OF_MAIN_WINDOW);
BIND_CONSTANT(MAIN_WINDOW_ID);
@@ -588,9 +565,11 @@ void DisplayServer::_bind_methods() {
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;
+ // Headless display server is always last
+ server_create_functions[server_create_count] = server_create_functions[server_create_count - 1];
+ server_create_functions[server_create_count - 1].name = p_name;
+ server_create_functions[server_create_count - 1].create_function = p_function;
+ server_create_functions[server_create_count - 1].get_rendering_drivers_function = p_get_drivers;
server_create_count++;
}
diff --git a/servers/display_server.h b/servers/display_server.h
index 3aab572120..b8201f6fd5 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -97,7 +97,6 @@ public:
FEATURE_VIRTUAL_KEYBOARD,
FEATURE_CURSOR_SHAPE,
FEATURE_CUSTOM_CURSOR_SHAPE,
- FEATURE_NATIVE_VIDEO,
FEATURE_NATIVE_DIALOG,
FEATURE_CONSOLE_WINDOW,
FEATURE_IME,
@@ -143,7 +142,8 @@ public:
MOUSE_MODE_VISIBLE,
MOUSE_MODE_HIDDEN,
MOUSE_MODE_CAPTURED,
- MOUSE_MODE_CONFINED
+ MOUSE_MODE_CONFINED,
+ MOUSE_MODE_CONFINED_HIDDEN,
};
virtual void mouse_set_mode(MouseMode p_mode);
@@ -176,6 +176,9 @@ public:
return scale;
}
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+
+ // Keep the ScreenOrientation enum values in sync with the `display/window/handheld/orientation`
+ // project setting hint.
enum ScreenOrientation {
SCREEN_LANDSCAPE,
SCREEN_PORTRAIT,
@@ -324,13 +327,6 @@ public:
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);
diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h
new file mode 100644
index 0000000000..8b386c8d9c
--- /dev/null
+++ b/servers/display_server_headless.h
@@ -0,0 +1,127 @@
+/*************************************************************************/
+/* display_server_headless.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef DISPLAY_SERVER_HEADLESS_H
+#define DISPLAY_SERVER_HEADLESS_H
+
+#include "servers/display_server.h"
+
+#include "servers/rendering/rasterizer_dummy.h"
+
+class DisplayServerHeadless : public DisplayServer {
+private:
+ friend class DisplayServer;
+
+ static Vector<String> get_rendering_drivers_func() {
+ Vector<String> drivers;
+ drivers.push_back("dummy");
+ return drivers;
+ }
+
+ static DisplayServer *create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+ r_error = OK;
+ RasterizerDummy::make_current();
+ return memnew(DisplayServerHeadless());
+ }
+
+public:
+ bool has_feature(Feature p_feature) const override { return false; }
+ String get_name() const override { return "headless"; }
+
+ void alert(const String &p_alert, const String &p_title = "ALERT!") override {}
+
+ int get_screen_count() const override { return 0; }
+ Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Point2i(); }
+ Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Size2i(); }
+ Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Rect2i(); }
+ int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return 96; /* 0 might cause issues */ }
+ float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return 1; }
+ float screen_get_max_scale() const override { return 1; }
+
+ Vector<DisplayServer::WindowID> get_window_list() const override { return Vector<DisplayServer::WindowID>(); }
+
+ WindowID get_window_at_screen_position(const Point2i &p_position) const override { return -1; }
+
+ void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override {}
+ ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override { return ObjectID(); }
+
+ void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {}
+
+ void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {}
+ void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {}
+ void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {}
+ void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override {}
+
+ void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override {}
+
+ void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID) override {}
+
+ int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override { return -1; }
+ void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override {}
+
+ Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const override { return Point2i(); }
+ void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override {}
+
+ void window_set_transient(WindowID p_window, WindowID p_parent) override {}
+
+ void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override {}
+ Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override { return Size2i(); }
+
+ void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override {}
+ Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const override { return Size2i(); };
+
+ void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override {}
+ Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const override { return Size2i(); }
+ Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const override { return Size2i(); }
+
+ void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) override {}
+ WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const override { return WINDOW_MODE_MINIMIZED; }
+
+ bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const override { return false; }
+
+ void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) override {}
+ virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const override { return false; }
+
+ void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override {}
+ void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override {}
+
+ bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override { return false; }
+
+ bool can_any_window_draw() const override { return false; }
+
+ void process_events() override {}
+
+ void set_icon(const Ref<Image> &p_icon) override {}
+
+ DisplayServerHeadless() {}
+ ~DisplayServerHeadless() {}
+};
+
+#endif // DISPLAY_SERVER_HEADLESS_H
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index 9e32bc209b..ef2635c188 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "servers/navigation_server_2d.h"
-#include "core/math/transform.h"
#include "core/math/transform_2d.h"
+#include "core/math/transform_3d.h"
#include "servers/navigation_server_3d.h"
/**
@@ -129,12 +129,12 @@ static Vector<Vector2> vector_v3_to_v2(const Vector<Vector3> &d) {
return nd;
}
-static Transform trf2_to_trf3(const Transform2D &d) {
+static Transform3D trf2_to_trf3(const Transform2D &d) {
Vector3 o(v2_to_v3(d.get_origin()));
Basis b;
b.rotate(Vector3(0, -1, 0), d.get_rotation());
b.scale(v2_to_v3(d.get_scale()));
- return Transform(b, o);
+ return Transform3D(b, o);
}
static Object *obj_to_obj(Object *d) {
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index 420f9c9c18..3aef693ac8 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -106,7 +106,7 @@ public:
virtual uint32_t region_get_layers(RID p_region) const = 0;
/// Set the global transformation of this region.
- virtual void region_set_transform(RID p_region, Transform p_transform) const = 0;
+ virtual void region_set_transform(RID p_region, Transform3D 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;
diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp
index 21ad57e344..eb9fc0e800 100644
--- a/servers/physics_2d/area_pair_2d_sw.cpp
+++ b/servers/physics_2d/area_pair_2d_sw.cpp
@@ -40,31 +40,48 @@ bool AreaPair2DSW::setup(real_t p_step) {
result = true;
}
+ process_collision = false;
if (result != colliding) {
- if (result) {
- 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() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
- body->remove_area(area);
- }
- if (area->has_monitor_callback()) {
- area->remove_body_from_query(body, body_shape, area_shape);
- }
+ if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ process_collision = true;
+ } else if (area->has_monitor_callback()) {
+ process_collision = true;
}
colliding = result;
}
- return false; //never do any post solving
+ return process_collision;
+}
+
+bool AreaPair2DSW::pre_solve(real_t p_step) {
+ if (!process_collision) {
+ return false;
+ }
+
+ if (colliding) {
+ 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() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ body->remove_area(area);
+ }
+
+ if (area->has_monitor_callback()) {
+ area->remove_body_from_query(body, body_shape, area_shape);
+ }
+ }
+
+ return false; // Never do any post solving.
}
void AreaPair2DSW::solve(real_t p_step) {
+ // Nothing to do.
}
AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, int p_area_shape) {
@@ -72,7 +89,6 @@ AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area,
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() == PhysicsServer2D::BODY_MODE_KINEMATIC) { //need to be active to process pair
@@ -103,33 +119,48 @@ bool Area2Pair2DSW::setup(real_t p_step) {
result = true;
}
+ process_collision = false;
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);
- }
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ process_collision = true;
+ } else if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ process_collision = true;
}
colliding = result;
}
- return false; //never do any post solving
+ return process_collision;
+}
+
+bool Area2Pair2DSW::pre_solve(real_t p_step) {
+ if (!process_collision) {
+ return false;
+ }
+
+ if (colliding) {
+ 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);
+ }
+ }
+
+ return false; // Never do any post solving.
}
void Area2Pair2DSW::solve(real_t p_step) {
+ // Nothing to do.
}
Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area_b, int p_shape_b) {
@@ -137,7 +168,6 @@ Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area
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);
}
diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/area_pair_2d_sw.h
index 4015aad5d1..4632a307d9 100644
--- a/servers/physics_2d/area_pair_2d_sw.h
+++ b/servers/physics_2d/area_pair_2d_sw.h
@@ -36,30 +36,34 @@
#include "constraint_2d_sw.h"
class AreaPair2DSW : public Constraint2DSW {
- Body2DSW *body;
- Area2DSW *area;
- int body_shape;
- int area_shape;
- bool colliding;
+ Body2DSW *body = nullptr;
+ Area2DSW *area = nullptr;
+ int body_shape = 0;
+ int area_shape = 0;
+ bool colliding = false;
+ bool process_collision = false;
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, int p_area_shape);
~AreaPair2DSW();
};
class Area2Pair2DSW : public Constraint2DSW {
- Area2DSW *area_a;
- Area2DSW *area_b;
- int shape_a;
- int shape_b;
- bool colliding;
+ Area2DSW *area_a = nullptr;
+ Area2DSW *area_b = nullptr;
+ int shape_a = 0;
+ int shape_b = 0;
+ bool colliding = false;
+ bool process_collision = false;
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area_b, int p_shape_b);
~Area2Pair2DSW();
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index 0a91931354..6f244deb1e 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -43,7 +43,7 @@ void Body2DSW::update_inertias() {
//update shapes and motions
switch (mode) {
- case PhysicsServer2D::BODY_MODE_RIGID: {
+ case PhysicsServer2D::BODY_MODE_DYNAMIC: {
if (user_inertia) {
_inv_inertia = inertia > 0 ? (1.0 / inertia) : 0;
break;
@@ -87,7 +87,7 @@ void Body2DSW::update_inertias() {
_inv_inertia = 0;
_inv_mass = 0;
} break;
- case PhysicsServer2D::BODY_MODE_CHARACTER: {
+ case PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED: {
_inv_inertia = 0;
_inv_mass = 1.0 / mass;
@@ -104,31 +104,17 @@ void Body2DSW::set_active(bool p_active) {
}
active = p_active;
- if (!p_active) {
- if (get_space()) {
- get_space()->body_remove_from_active_list(&active_list);
- }
- } else {
+
+ if (active) {
if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
- return; //static bodies can't become active
- }
- if (get_space()) {
+ // Static bodies can't be active.
+ active = false;
+ } else 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);
- }
+ } else if (get_space()) {
+ get_space()->body_remove_from_active_list(&active_list);
}
-*/
}
void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) {
@@ -218,14 +204,14 @@ void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) {
first_time_kinematic = true;
}
} break;
- case PhysicsServer2D::BODY_MODE_RIGID: {
+ case PhysicsServer2D::BODY_MODE_DYNAMIC: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_inv_inertia = inertia > 0 ? (1.0 / inertia) : 0;
_set_static(false);
set_active(true);
} break;
- case PhysicsServer2D::BODY_MODE_CHARACTER: {
+ case PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_inv_inertia = 0;
_set_static(false);
@@ -233,7 +219,7 @@ void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) {
angular_velocity = 0;
} break;
}
- if (p_mode == PhysicsServer2D::BODY_MODE_RIGID && _inv_inertia == 0) {
+ if (p_mode == PhysicsServer2D::BODY_MODE_DYNAMIC && _inv_inertia == 0) {
_update_inertia();
}
/*
@@ -281,25 +267,16 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va
} break;
case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: {
- /*
- if (mode==PhysicsServer2D::BODY_MODE_STATIC)
- break;
- */
linear_velocity = p_variant;
wakeup();
} break;
case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: {
- /*
- if (mode!=PhysicsServer2D::BODY_MODE_RIGID)
- break;
- */
angular_velocity = p_variant;
wakeup();
} break;
case PhysicsServer2D::BODY_STATE_SLEEPING: {
- //?
if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
break;
}
@@ -318,7 +295,7 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va
} break;
case PhysicsServer2D::BODY_STATE_CAN_SLEEP: {
can_sleep = p_variant;
- if (mode == PhysicsServer2D::BODY_MODE_RIGID && !active && !can_sleep) {
+ if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC && !active && !can_sleep) {
set_active(true);
}
@@ -370,13 +347,6 @@ void Body2DSW::set_space(Space2DSW *p_space) {
if (active) {
get_space()->body_add_to_active_list(&active_list);
}
- /*
- _update_queries();
- if (is_active()) {
- active=false;
- set_active(true);
- }
- */
}
first_integration = false;
@@ -572,7 +542,7 @@ void Body2DSW::wakeup_neighbours() {
continue;
}
Body2DSW *b = n[i];
- if (b->mode != PhysicsServer2D::BODY_MODE_RIGID) {
+ if (b->mode != PhysicsServer2D::BODY_MODE_DYNAMIC) {
continue;
}
@@ -591,16 +561,17 @@ void Body2DSW::call_queries() {
Variant v = dbs;
const Variant *vp[2] = { &v, &fi_callback->callback_udata };
- Object *obj = ObjectDB::get_instance(fi_callback->id);
+ Object *obj = fi_callback->callable.get_object();
if (!obj) {
- set_force_integration_callback(ObjectID(), StringName());
+ set_force_integration_callback(Callable());
} else {
Callable::CallError ce;
+ Variant rv;
if (fi_callback->callback_udata.get_type() != Variant::NIL) {
- obj->call(fi_callback->method, vp, 2, ce);
+ fi_callback->callable.call(vp, 2, rv, ce);
} else {
- obj->call(fi_callback->method, vp, 1, ce);
+ fi_callback->callable.call(vp, 1, rv, ce);
}
}
}
@@ -608,9 +579,7 @@ void Body2DSW::call_queries() {
bool Body2DSW::sleep_test(real_t p_step) {
if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- return true; //
- } else if (mode == PhysicsServer2D::BODY_MODE_CHARACTER) {
- return !active; // characters and kinematic bodies don't sleep unless asked to sleep
+ return true;
} else if (!can_sleep) {
return false;
}
@@ -625,16 +594,15 @@ bool Body2DSW::sleep_test(real_t p_step) {
}
}
-void Body2DSW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+void Body2DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
if (fi_callback) {
memdelete(fi_callback);
fi_callback = nullptr;
}
- if (p_id.is_valid()) {
+ if (p_callable.get_object()) {
fi_callback = memnew(ForceIntegrationCallback);
- fi_callback->id = p_id;
- fi_callback->method = p_method;
+ fi_callback->callable = p_callable;
fi_callback->callback_udata = p_udata;
}
}
@@ -644,7 +612,7 @@ Body2DSW::Body2DSW() :
active_list(this),
inertia_update_list(this),
direct_state_query_list(this) {
- mode = PhysicsServer2D::BODY_MODE_RIGID;
+ mode = PhysicsServer2D::BODY_MODE_DYNAMIC;
active = true;
angular_velocity = 0;
biased_angular_velocity = 0;
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index 7ea4ac697c..b4a95651cb 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -117,8 +117,7 @@ class Body2DSW : public CollisionObject2DSW {
int contact_count;
struct ForceIntegrationCallback {
- ObjectID id;
- StringName method;
+ Callable callable;
Variant callback_udata;
};
@@ -131,7 +130,7 @@ class Body2DSW : public CollisionObject2DSW {
friend class PhysicsDirectBodyState2DSW; // i give up, too many functions to expose
public:
- void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
_FORCE_INLINE_ void add_area(Area2DSW *p_area) {
int index = areas.find(AreaCMP(p_area));
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index da70ac7d4b..ff31825b83 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -87,10 +87,13 @@ void BodyPair2DSW::_contact_added_callback(const Vector2 &p_point_A, const Vecto
int least_deep = -1;
real_t min_depth = 1e10;
+ const Transform2D &transform_A = A->get_transform();
+ const Transform2D &transform_B = B->get_transform();
+
for (int i = 0; i <= contact_count; i++) {
Contact &c = (i == contact_count) ? contact : contacts[i];
- Vector2 global_A = A->get_transform().basis_xform(c.local_A);
- Vector2 global_B = B->get_transform().basis_xform(c.local_B) + offset_B;
+ Vector2 global_A = transform_A.basis_xform(c.local_A);
+ Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B;
Vector2 axis = global_A - global_B;
real_t depth = axis.dot(c.normal);
@@ -124,6 +127,9 @@ void BodyPair2DSW::_validate_contacts() {
real_t max_separation = space->get_contact_max_separation();
real_t max_separation2 = max_separation * max_separation;
+ const Transform2D &transform_A = A->get_transform();
+ const Transform2D &transform_B = B->get_transform();
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
@@ -134,8 +140,8 @@ void BodyPair2DSW::_validate_contacts() {
} else {
c.reused = false;
- Vector2 global_A = A->get_transform().basis_xform(c.local_A);
- Vector2 global_B = B->get_transform().basis_xform(c.local_B) + offset_B;
+ Vector2 global_A = transform_A.basis_xform(c.local_A);
+ Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B;
Vector2 axis = global_A - global_B;
real_t depth = axis.dot(c.normal);
@@ -220,14 +226,16 @@ real_t combine_friction(Body2DSW *A, Body2DSW *B) {
}
bool BodyPair2DSW::setup(real_t p_step) {
- //cannot collide
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
- bool report_contacts_only = false;
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ report_contacts_only = false;
+ if (!dynamic_A && !dynamic_B) {
if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
report_contacts_only = true;
} else {
@@ -246,12 +254,12 @@ bool BodyPair2DSW::setup(real_t p_step) {
_validate_contacts();
- Vector2 offset_A = A->get_transform().get_origin();
+ const Vector2 &offset_A = A->get_transform().get_origin();
Transform2D xform_Au = A->get_transform().untranslated();
Transform2D xform_A = xform_Au * A->get_shape_transform(shape_A);
Transform2D xform_Bu = B->get_transform();
- xform_Bu.elements[2] -= A->get_transform().get_origin();
+ xform_Bu.elements[2] -= offset_A;
Transform2D xform_B = xform_Bu * B->get_shape_transform(shape_B);
Shape2DSW *shape_A_ptr = A->get_shape(shape_A);
@@ -272,13 +280,13 @@ bool BodyPair2DSW::setup(real_t p_step) {
if (!collided) {
//test ccd (currently just a raycast)
- if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && dynamic_A) {
if (_test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B)) {
collided = true;
}
}
- if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && dynamic_B) {
if (_test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A, true)) {
collided = true;
}
@@ -338,9 +346,21 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
}
+ return true;
+}
+
+bool BodyPair2DSW::pre_solve(real_t p_step) {
+ if (!collided || oneway_disabled) {
+ return false;
+ }
+
real_t max_penetration = space->get_contact_max_allowed_penetration();
real_t bias = 0.3;
+
+ Shape2DSW *shape_A_ptr = A->get_shape(shape_A);
+ Shape2DSW *shape_B_ptr = B->get_shape(shape_B);
+
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();
@@ -351,21 +371,23 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
}
- cc = 0;
-
real_t inv_dt = 1.0 / p_step;
bool do_process = false;
+ const Vector2 &offset_A = A->get_transform().get_origin();
+ const Transform2D &transform_A = A->get_transform();
+ const Transform2D &transform_B = B->get_transform();
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
-
c.active = false;
- Vector2 global_A = xform_Au.xform(c.local_A);
- Vector2 global_B = xform_Bu.xform(c.local_B);
+ Vector2 global_A = transform_A.basis_xform(c.local_A);
+ Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B;
- real_t depth = c.normal.dot(global_A - global_B);
+ Vector2 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
if (depth <= 0 || !c.reused) {
continue;
@@ -396,8 +418,6 @@ bool BodyPair2DSW::setup(real_t p_step) {
continue;
}
- c.active = true;
-
// Precompute normal mass, tangent mass, and bias.
real_t rnA = c.rA.dot(c.normal);
real_t rnB = c.rB.dot(c.normal);
@@ -421,8 +441,12 @@ bool BodyPair2DSW::setup(real_t p_step) {
// Apply normal + friction impulse
Vector2 P = c.acc_normal_impulse * c.normal + c.acc_tangent_impulse * tangent;
- A->apply_impulse(-P, c.rA);
- B->apply_impulse(P, c.rB);
+ if (dynamic_A) {
+ A->apply_impulse(-P, c.rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(P, c.rB);
+ }
}
#endif
@@ -434,6 +458,7 @@ bool BodyPair2DSW::setup(real_t p_step) {
c.bounce = c.bounce * dv.dot(c.normal);
}
+ c.active = true;
do_process = true;
}
@@ -441,13 +466,12 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
void BodyPair2DSW::solve(real_t p_step) {
- if (!collided) {
+ if (!collided || oneway_disabled) {
return;
}
for (int i = 0; i < contact_count; ++i) {
Contact &c = contacts[i];
- cc++;
if (!c.active) {
continue;
@@ -474,8 +498,12 @@ void BodyPair2DSW::solve(real_t p_step) {
Vector2 jb = c.normal * (c.acc_bias_impulse - jbnOld);
- A->apply_bias_impulse(-jb, c.rA);
- B->apply_bias_impulse(jb, c.rB);
+ if (dynamic_A) {
+ A->apply_bias_impulse(-jb, c.rA);
+ }
+ if (dynamic_B) {
+ B->apply_bias_impulse(jb, c.rB);
+ }
real_t jn = -(c.bounce + vn) * c.mass_normal;
real_t jnOld = c.acc_normal_impulse;
@@ -490,8 +518,12 @@ void BodyPair2DSW::solve(real_t p_step) {
Vector2 j = c.normal * (c.acc_normal_impulse - jnOld) + tangent * (c.acc_tangent_impulse - jtOld);
- A->apply_impulse(-j, c.rA);
- B->apply_impulse(j, c.rB);
+ if (dynamic_A) {
+ A->apply_impulse(-j, c.rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, c.rB);
+ }
}
}
@@ -504,9 +536,6 @@ BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_sh
space = A->get_space();
A->add_constraint(this, 0);
B->add_constraint(this, 1);
- contact_count = 0;
- collided = false;
- oneway_disabled = false;
}
BodyPair2DSW::~BodyPair2DSW() {
diff --git a/servers/physics_2d/body_pair_2d_sw.h b/servers/physics_2d/body_pair_2d_sw.h
index 31ab9b9017..4b42b44c92 100644
--- a/servers/physics_2d/body_pair_2d_sw.h
+++ b/servers/physics_2d/body_pair_2d_sw.h
@@ -44,13 +44,16 @@ class BodyPair2DSW : public Constraint2DSW {
Body2DSW *B;
};
- Body2DSW *_arr[2];
+ Body2DSW *_arr[2] = { nullptr, nullptr };
};
- int shape_A;
- int shape_B;
+ int shape_A = 0;
+ int shape_B = 0;
- Space2DSW *space;
+ bool dynamic_A = false;
+ bool dynamic_B = false;
+
+ Space2DSW *space = nullptr;
struct Contact {
Vector2 position;
@@ -73,10 +76,10 @@ class BodyPair2DSW : public Constraint2DSW {
Vector2 sep_axis;
Contact contacts[MAX_CONTACTS];
- int contact_count;
- bool collided;
- bool oneway_disabled;
- int cc;
+ int contact_count = 0;
+ bool collided = false;
+ bool oneway_disabled = false;
+ bool report_contacts_only = false;
bool _test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const Transform2D &p_xform_A, Body2DSW *p_B, int p_shape_B, const Transform2D &p_xform_B, bool p_swap_result = false);
void _validate_contacts();
@@ -84,8 +87,9 @@ class BodyPair2DSW : public Constraint2DSW {
_FORCE_INLINE_ void _contact_added_callback(const Vector2 &p_point_A, const Vector2 &p_point_B);
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_shape_B);
~BodyPair2DSW();
diff --git a/servers/physics_2d/broad_phase_2d_basic.cpp b/servers/physics_2d/broad_phase_2d_basic.cpp
deleted file mode 100644
index 17424629a9..0000000000
--- a/servers/physics_2d/broad_phase_2d_basic.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*************************************************************************/
-/* broad_phase_2d_basic.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "broad_phase_2d_basic.h"
-
-BroadPhase2DBasic::ID BroadPhase2DBasic::create(CollisionObject2DSW *p_object_, int p_subindex) {
- current++;
-
- Element e;
- e.owner = p_object_;
- e._static = false;
- e.subindex = p_subindex;
-
- element_map[current] = e;
- return current;
-}
-
-void BroadPhase2DBasic::move(ID p_id, const Rect2 &p_aabb) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
- E->get().aabb = p_aabb;
-}
-
-void BroadPhase2DBasic::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 BroadPhase2DBasic::remove(ID p_id) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
- element_map.erase(E);
-}
-
-CollisionObject2DSW *BroadPhase2DBasic::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 BroadPhase2DBasic::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 BroadPhase2DBasic::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 BroadPhase2DBasic::cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **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 Rect2 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 BroadPhase2DBasic::cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **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 Rect2 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 BroadPhase2DBasic::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
- pair_userdata = p_userdata;
- pair_callback = p_pair_callback;
-}
-
-void BroadPhase2DBasic::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
- unpair_userdata = p_userdata;
- unpair_callback = p_unpair_callback;
-}
-
-void BroadPhase2DBasic::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);
- if (data) {
- pair_map.insert(key, data);
- }
- }
- }
- }
- }
-}
-
-BroadPhase2DSW *BroadPhase2DBasic::_create() {
- return memnew(BroadPhase2DBasic);
-}
-
-BroadPhase2DBasic::BroadPhase2DBasic() {
- current = 1;
- unpair_callback = nullptr;
- unpair_userdata = nullptr;
- pair_callback = nullptr;
- pair_userdata = nullptr;
-}
diff --git a/servers/physics_2d/broad_phase_2d_bvh.cpp b/servers/physics_2d/broad_phase_2d_bvh.cpp
new file mode 100644
index 0000000000..5f53f4a012
--- /dev/null
+++ b/servers/physics_2d/broad_phase_2d_bvh.cpp
@@ -0,0 +1,116 @@
+/*************************************************************************/
+/* broad_phase_2d_bvh.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "broad_phase_2d_bvh.h"
+#include "collision_object_2d_sw.h"
+
+BroadPhase2DSW::ID BroadPhase2DBVH::create(CollisionObject2DSW *p_object, int p_subindex, const Rect2 &p_aabb, bool p_static) {
+ ID oid = bvh.create(p_object, true, p_aabb, p_subindex, !p_static, 1 << p_object->get_type(), p_static ? 0 : 0xFFFFF); // Pair everything, don't care?
+ return oid + 1;
+}
+
+void BroadPhase2DBVH::move(ID p_id, const Rect2 &p_aabb) {
+ bvh.move(p_id - 1, p_aabb);
+}
+
+void BroadPhase2DBVH::set_static(ID p_id, bool p_static) {
+ CollisionObject2DSW *it = bvh.get(p_id - 1);
+ bvh.set_pairable(p_id - 1, !p_static, 1 << it->get_type(), p_static ? 0 : 0xFFFFF, false); // Pair everything, don't care?
+}
+
+void BroadPhase2DBVH::remove(ID p_id) {
+ bvh.erase(p_id - 1);
+}
+
+CollisionObject2DSW *BroadPhase2DBVH::get_object(ID p_id) const {
+ CollisionObject2DSW *it = bvh.get(p_id - 1);
+ ERR_FAIL_COND_V(!it, nullptr);
+ return it;
+}
+
+bool BroadPhase2DBVH::is_static(ID p_id) const {
+ return !bvh.is_pairable(p_id - 1);
+}
+
+int BroadPhase2DBVH::get_subindex(ID p_id) const {
+ return bvh.get_subindex(p_id - 1);
+}
+
+int BroadPhase2DBVH::cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) {
+ return bvh.cull_segment(p_from, p_to, p_results, p_max_results, p_result_indices);
+}
+
+int BroadPhase2DBVH::cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) {
+ return bvh.cull_aabb(p_aabb, p_results, p_max_results, p_result_indices);
+}
+
+void *BroadPhase2DBVH::_pair_callback(void *self, uint32_t p_A, CollisionObject2DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject2DSW *p_object_B, int subindex_B) {
+ BroadPhase2DBVH *bpo = (BroadPhase2DBVH *)(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 BroadPhase2DBVH::_unpair_callback(void *self, uint32_t p_A, CollisionObject2DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject2DSW *p_object_B, int subindex_B, void *pairdata) {
+ BroadPhase2DBVH *bpo = (BroadPhase2DBVH *)(self);
+ if (!bpo->unpair_callback) {
+ return;
+ }
+
+ bpo->unpair_callback(p_object_A, subindex_A, p_object_B, subindex_B, pairdata, bpo->unpair_userdata);
+}
+
+void BroadPhase2DBVH::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
+ pair_callback = p_pair_callback;
+ pair_userdata = p_userdata;
+}
+
+void BroadPhase2DBVH::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
+ unpair_callback = p_unpair_callback;
+ unpair_userdata = p_userdata;
+}
+
+void BroadPhase2DBVH::update() {
+ bvh.update();
+}
+
+BroadPhase2DSW *BroadPhase2DBVH::_create() {
+ return memnew(BroadPhase2DBVH);
+}
+
+BroadPhase2DBVH::BroadPhase2DBVH() {
+ bvh.set_pair_callback(_pair_callback, this);
+ bvh.set_unpair_callback(_unpair_callback, this);
+ pair_callback = nullptr;
+ pair_userdata = nullptr;
+ unpair_userdata = nullptr;
+}
diff --git a/servers/physics_2d/broad_phase_2d_basic.h b/servers/physics_2d/broad_phase_2d_bvh.h
index ca1db360fb..6c11d2561b 100644
--- a/servers/physics_2d/broad_phase_2d_basic.h
+++ b/servers/physics_2d/broad_phase_2d_bvh.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* broad_phase_2d_basic.h */
+/* broad_phase_2d_bvh.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,49 +28,19 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BROAD_PHASE_2D_BASIC_H
-#define BROAD_PHASE_2D_BASIC_H
+#ifndef BROAD_PHASE_2D_BVH_H
+#define BROAD_PHASE_2D_BVH_H
-#include "core/templates/map.h"
-#include "space_2d_sw.h"
-class BroadPhase2DBasic : public BroadPhase2DSW {
- struct Element {
- CollisionObject2DSW *owner;
- bool _static;
- Rect2 aabb;
- int subindex;
- };
+#include "broad_phase_2d_sw.h"
+#include "core/math/bvh.h"
+#include "core/math/rect2.h"
+#include "core/math/vector2.h"
- Map<ID, Element> element_map;
+class BroadPhase2DBVH : public BroadPhase2DSW {
+ BVH_Manager<CollisionObject2DSW, true, 128, Rect2, Vector2> bvh;
- 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;
+ static void *_pair_callback(void *, uint32_t, CollisionObject2DSW *, int, uint32_t, CollisionObject2DSW *, int);
+ static void _unpair_callback(void *, uint32_t, CollisionObject2DSW *, int, uint32_t, CollisionObject2DSW *, int, void *);
PairCallback pair_callback;
void *pair_userdata;
@@ -79,7 +49,7 @@ class BroadPhase2DBasic : public BroadPhase2DSW {
public:
// 0 is an invalid ID
- virtual ID create(CollisionObject2DSW *p_object_, int p_subindex = 0);
+ virtual ID create(CollisionObject2DSW *p_object, int p_subindex = 0, const Rect2 &p_aabb = Rect2(), bool p_static = false);
virtual void move(ID p_id, const Rect2 &p_aabb);
virtual void set_static(ID p_id, bool p_static);
virtual void remove(ID p_id);
@@ -97,7 +67,7 @@ public:
virtual void update();
static BroadPhase2DSW *_create();
- BroadPhase2DBasic();
+ BroadPhase2DBVH();
};
-#endif // BROAD_PHASE_2D_BASIC_H
+#endif // BROAD_PHASE_2D_BVH_H
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
deleted file mode 100644
index 35447c5389..0000000000
--- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp
+++ /dev/null
@@ -1,738 +0,0 @@
-/*************************************************************************/
-/* broad_phase_2d_hash_grid.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "broad_phase_2d_hash_grid.h"
-#include "collision_object_2d_sw.h"
-#include "core/config/project_settings.h"
-
-#define LARGE_ELEMENT_FI 1.01239812
-
-void BroadPhase2DHashGrid::_pair_attempt(Element *p_elem, Element *p_with) {
- if (p_elem->owner == p_with->owner) {
- return;
- }
- if (!_test_collision_mask(p_elem->collision_mask, p_elem->collision_layer, p_with->collision_mask, p_with->collision_layer)) {
- return;
- }
- Map<Element *, PairData *>::Element *E = p_elem->paired.find(p_with);
-
- ERR_FAIL_COND(p_elem->_static && p_with->_static);
-
- if (!E) {
- PairData *pd = memnew(PairData);
- p_elem->paired[p_with] = pd;
- p_with->paired[p_elem] = pd;
- } else {
- E->get()->rc++;
- }
-}
-
-void BroadPhase2DHashGrid::_unpair_attempt(Element *p_elem, Element *p_with) {
- if (p_elem->owner == p_with->owner) {
- return;
- }
- if (!_test_collision_mask(p_elem->collision_mask, p_elem->collision_layer, p_with->collision_mask, p_with->collision_layer)) {
- return;
- }
- Map<Element *, PairData *>::Element *E = p_elem->paired.find(p_with);
-
- ERR_FAIL_COND(!E); //this should really be paired..
-
- E->get()->rc--;
-
- if (E->get()->rc == 0) {
- if (E->get()->colliding) {
- //uncollide
- if (unpair_callback) {
- unpair_callback(p_elem->owner, p_elem->subindex, p_with->owner, p_with->subindex, E->get()->ud, unpair_userdata);
- }
- }
-
- memdelete(E->get());
- p_elem->paired.erase(E);
- p_with->paired.erase(p_elem);
- }
-}
-
-void BroadPhase2DHashGrid::_check_motion(Element *p_elem) {
- for (Map<Element *, PairData *>::Element *E = p_elem->paired.front(); E; E = E->next()) {
- bool physical_collision = p_elem->aabb.intersects(E->key()->aabb);
- bool logical_collision = p_elem->owner->test_collision_mask(E->key()->owner);
-
- if (physical_collision && logical_collision) {
- if (!E->get()->colliding && pair_callback) {
- E->get()->ud = pair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, pair_userdata);
- }
- E->get()->colliding = true;
- } else { // No collision
- if (E->get()->colliding && unpair_callback) {
- unpair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, E->get()->ud, unpair_userdata);
- E->get()->ud = nullptr;
- }
- E->get()->colliding = false;
- }
- }
-}
-
-void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_enter) {
- Vector2 sz = (p_rect.size / cell_size * LARGE_ELEMENT_FI); //use magic number to avoid floating point issues
- if (sz.width * sz.height > large_object_min_surface) {
- //large object, do not use grid, must check against all elements
- for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
- if (E->key() == p_elem->self) {
- continue; // do not pair against itself
- }
- if (E->get()._static && p_static) {
- continue;
- }
-
- _pair_attempt(p_elem, &E->get());
- }
-
- large_elements[p_elem].inc();
- return;
- }
-
- Point2i from = (p_rect.position / cell_size).floor();
- Point2i to = ((p_rect.position + p_rect.size) / cell_size).floor();
-
- for (int i = from.x; i <= to.x; i++) {
- for (int j = from.y; j <= to.y; j++) {
- PosKey pk;
- pk.x = i;
- pk.y = j;
-
- uint32_t idx = pk.hash() % hash_table_size;
- PosBin *pb = hash_table[idx];
-
- while (pb) {
- if (pb->key == pk) {
- break;
- }
-
- pb = pb->next;
- }
-
- bool entered = p_force_enter;
-
- if (!pb) {
- //does not exist, create!
- pb = memnew(PosBin);
- pb->key = pk;
- pb->next = hash_table[idx];
- hash_table[idx] = pb;
- }
-
- if (p_static) {
- if (pb->static_object_set[p_elem].inc() == 1) {
- entered = true;
- }
- } else {
- if (pb->object_set[p_elem].inc() == 1) {
- entered = true;
- }
- }
-
- if (entered) {
- for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) {
- _pair_attempt(p_elem, E->key());
- }
-
- if (!p_static) {
- for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) {
- _pair_attempt(p_elem, E->key());
- }
- }
- }
- }
- }
-
- //pair separatedly with large elements
-
- for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) {
- if (E->key() == p_elem) {
- continue; // do not pair against itself
- }
- if (E->key()->_static && p_static) {
- continue;
- }
- _pair_attempt(E->key(), p_elem);
- }
-}
-
-void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_exit) {
- Vector2 sz = (p_rect.size / cell_size * LARGE_ELEMENT_FI);
- if (sz.width * sz.height > large_object_min_surface) {
- //unpair all elements, instead of checking all, just check what is already paired, so we at least save from checking static vs static
- Map<Element *, PairData *>::Element *E = p_elem->paired.front();
- while (E) {
- Map<Element *, PairData *>::Element *next = E->next();
- _unpair_attempt(p_elem, E->key());
- E = next;
- }
-
- if (large_elements[p_elem].dec() == 0) {
- large_elements.erase(p_elem);
- }
- return;
- }
-
- Point2i from = (p_rect.position / cell_size).floor();
- Point2i to = ((p_rect.position + p_rect.size) / cell_size).floor();
-
- for (int i = from.x; i <= to.x; i++) {
- for (int j = from.y; j <= to.y; j++) {
- PosKey pk;
- pk.x = i;
- pk.y = j;
-
- uint32_t idx = pk.hash() % hash_table_size;
- PosBin *pb = hash_table[idx];
-
- while (pb) {
- if (pb->key == pk) {
- break;
- }
-
- pb = pb->next;
- }
-
- ERR_CONTINUE(!pb); //should exist!!
-
- bool exited = p_force_exit;
-
- if (p_static) {
- if (pb->static_object_set[p_elem].dec() == 0) {
- pb->static_object_set.erase(p_elem);
- exited = true;
- }
- } else {
- if (pb->object_set[p_elem].dec() == 0) {
- pb->object_set.erase(p_elem);
- exited = true;
- }
- }
-
- if (exited) {
- for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) {
- _unpair_attempt(p_elem, E->key());
- }
-
- if (!p_static) {
- for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) {
- _unpair_attempt(p_elem, E->key());
- }
- }
- }
-
- if (pb->object_set.is_empty() && pb->static_object_set.is_empty()) {
- if (hash_table[idx] == pb) {
- hash_table[idx] = pb->next;
- } else {
- PosBin *px = hash_table[idx];
-
- while (px) {
- if (px->next == pb) {
- px->next = pb->next;
- break;
- }
-
- px = px->next;
- }
-
- ERR_CONTINUE(!px);
- }
-
- memdelete(pb);
- }
- }
- }
-
- for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) {
- if (E->key() == p_elem) {
- continue; // do not pair against itself
- }
- if (E->key()->_static && p_static) {
- continue;
- }
-
- //unpair from large elements
- _unpair_attempt(p_elem, E->key());
- }
-}
-
-BroadPhase2DHashGrid::ID BroadPhase2DHashGrid::create(CollisionObject2DSW *p_object, int p_subindex) {
- current++;
-
- Element e;
- e.owner = p_object;
- e._static = false;
- e.collision_mask = p_object->get_collision_mask();
- e.collision_layer = p_object->get_collision_layer();
- e.subindex = p_subindex;
- e.self = current;
- e.pass = 0;
-
- element_map[current] = e;
- return current;
-}
-
-void BroadPhase2DHashGrid::move(ID p_id, const Rect2 &p_aabb) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
-
- Element &e = E->get();
- bool layer_changed = e.collision_mask != e.owner->get_collision_mask() || e.collision_layer != e.owner->get_collision_layer();
-
- if (p_aabb != e.aabb || layer_changed) {
- uint32_t old_mask = e.collision_mask;
- uint32_t old_layer = e.collision_layer;
- if (p_aabb != Rect2()) {
- e.collision_mask = e.owner->get_collision_mask();
- e.collision_layer = e.owner->get_collision_layer();
-
- _enter_grid(&e, p_aabb, e._static, layer_changed);
- }
- if (e.aabb != Rect2()) {
- // Need _exit_grid to remove from cells based on the old layer values.
- e.collision_mask = old_mask;
- e.collision_layer = old_layer;
-
- _exit_grid(&e, e.aabb, e._static, layer_changed);
-
- e.collision_mask = e.owner->get_collision_mask();
- e.collision_layer = e.owner->get_collision_layer();
- }
- e.aabb = p_aabb;
- }
-
- _check_motion(&e);
-}
-
-void BroadPhase2DHashGrid::set_static(ID p_id, bool p_static) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
-
- Element &e = E->get();
-
- if (e._static == p_static) {
- return;
- }
-
- if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static, false);
- }
-
- e._static = p_static;
-
- if (e.aabb != Rect2()) {
- _enter_grid(&e, e.aabb, e._static, false);
- _check_motion(&e);
- }
-}
-
-void BroadPhase2DHashGrid::remove(ID p_id) {
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
-
- Element &e = E->get();
-
- if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static, false);
- }
-
- element_map.erase(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, nullptr);
- return E->get().owner;
-}
-
-bool BroadPhase2DHashGrid::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 BroadPhase2DHashGrid::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;
-}
-
-template <bool use_aabb, bool use_segment>
-void BroadPhase2DHashGrid::_cull(const Point2i p_cell, const Rect2 &p_aabb, const Point2 &p_from, const Point2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices, int &index) {
- PosKey pk;
- pk.x = p_cell.x;
- pk.y = p_cell.y;
-
- uint32_t idx = pk.hash() % hash_table_size;
- PosBin *pb = hash_table[idx];
-
- while (pb) {
- if (pb->key == pk) {
- break;
- }
-
- pb = pb->next;
- }
-
- if (!pb) {
- return;
- }
-
- for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) {
- if (index >= p_max_results) {
- break;
- }
- if (E->key()->pass == pass) {
- continue;
- }
-
- E->key()->pass = pass;
-
- if (use_aabb && !p_aabb.intersects(E->key()->aabb)) {
- continue;
- }
-
- if (use_segment && !E->key()->aabb.intersects_segment(p_from, p_to)) {
- continue;
- }
-
- p_results[index] = E->key()->owner;
- p_result_indices[index] = E->key()->subindex;
- index++;
- }
-
- for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) {
- if (index >= p_max_results) {
- break;
- }
- if (E->key()->pass == pass) {
- continue;
- }
-
- if (use_aabb && !p_aabb.intersects(E->key()->aabb)) {
- continue;
- }
-
- if (use_segment && !E->key()->aabb.intersects_segment(p_from, p_to)) {
- continue;
- }
-
- E->key()->pass = pass;
- p_results[index] = E->key()->owner;
- p_result_indices[index] = E->key()->subindex;
- index++;
- }
-}
-
-int BroadPhase2DHashGrid::cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) {
- pass++;
-
- Vector2 dir = (p_to - p_from);
- if (dir == Vector2()) {
- return 0;
- }
- //avoid divisions by zero
- dir.normalize();
- if (dir.x == 0.0) {
- dir.x = 0.000001;
- }
- if (dir.y == 0.0) {
- dir.y = 0.000001;
- }
- Vector2 delta = dir.abs();
-
- delta.x = cell_size / delta.x;
- delta.y = cell_size / delta.y;
-
- Point2i pos = (p_from / cell_size).floor();
- Point2i end = (p_to / cell_size).floor();
-
- Point2i step = Vector2(SGN(dir.x), SGN(dir.y));
-
- Vector2 max;
-
- if (dir.x < 0) {
- max.x = (Math::floor((double)pos.x) * cell_size - p_from.x) / dir.x;
- } else {
- max.x = (Math::floor((double)pos.x + 1) * cell_size - p_from.x) / dir.x;
- }
-
- if (dir.y < 0) {
- max.y = (Math::floor((double)pos.y) * cell_size - p_from.y) / dir.y;
- } else {
- max.y = (Math::floor((double)pos.y + 1) * cell_size - p_from.y) / dir.y;
- }
-
- int cullcount = 0;
- _cull<false, true>(pos, Rect2(), p_from, p_to, p_results, p_max_results, p_result_indices, cullcount);
-
- bool reached_x = false;
- bool reached_y = false;
-
- while (true) {
- if (max.x < max.y) {
- max.x += delta.x;
- pos.x += step.x;
- } else {
- max.y += delta.y;
- pos.y += step.y;
- }
-
- if (step.x > 0) {
- if (pos.x >= end.x) {
- reached_x = true;
- }
- } else if (pos.x <= end.x) {
- reached_x = true;
- }
-
- if (step.y > 0) {
- if (pos.y >= end.y) {
- reached_y = true;
- }
- } else if (pos.y <= end.y) {
- reached_y = true;
- }
-
- _cull<false, true>(pos, Rect2(), p_from, p_to, p_results, p_max_results, p_result_indices, cullcount);
-
- if (reached_x && reached_y) {
- break;
- }
- }
-
- for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) {
- if (cullcount >= p_max_results) {
- break;
- }
- if (E->key()->pass == pass) {
- continue;
- }
-
- E->key()->pass = pass;
-
- /*
- if (use_aabb && !p_aabb.intersects(E->key()->aabb))
- continue;
- */
-
- if (!E->key()->aabb.intersects_segment(p_from, p_to)) {
- continue;
- }
-
- p_results[cullcount] = E->key()->owner;
- p_result_indices[cullcount] = E->key()->subindex;
- cullcount++;
- }
-
- return cullcount;
-}
-
-int BroadPhase2DHashGrid::cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) {
- pass++;
-
- Point2i from = (p_aabb.position / cell_size).floor();
- Point2i to = ((p_aabb.position + p_aabb.size) / cell_size).floor();
- int cullcount = 0;
-
- for (int i = from.x; i <= to.x; i++) {
- for (int j = from.y; j <= to.y; j++) {
- _cull<true, false>(Point2i(i, j), p_aabb, Point2(), Point2(), p_results, p_max_results, p_result_indices, cullcount);
- }
- }
-
- for (Map<Element *, RC>::Element *E = large_elements.front(); E; E = E->next()) {
- if (cullcount >= p_max_results) {
- break;
- }
- if (E->key()->pass == pass) {
- continue;
- }
-
- E->key()->pass = pass;
-
- if (!p_aabb.intersects(E->key()->aabb)) {
- continue;
- }
-
- /*
- if (!E->key()->aabb.intersects_segment(p_from,p_to))
- continue;
- */
-
- p_results[cullcount] = E->key()->owner;
- p_result_indices[cullcount] = E->key()->subindex;
- cullcount++;
- }
- return cullcount;
-}
-
-void BroadPhase2DHashGrid::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
- pair_callback = p_pair_callback;
- pair_userdata = p_userdata;
-}
-
-void BroadPhase2DHashGrid::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
- unpair_callback = p_unpair_callback;
- unpair_userdata = p_userdata;
-}
-
-void BroadPhase2DHashGrid::update() {
-}
-
-BroadPhase2DSW *BroadPhase2DHashGrid::_create() {
- return memnew(BroadPhase2DHashGrid);
-}
-
-BroadPhase2DHashGrid::BroadPhase2DHashGrid() {
- hash_table_size = GLOBAL_DEF("physics/2d/bp_hash_table_size", 4096);
- ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/bp_hash_table_size", PropertyInfo(Variant::INT, "physics/2d/bp_hash_table_size", PROPERTY_HINT_RANGE, "0,8192,1,or_greater"));
- hash_table_size = Math::larger_prime(hash_table_size);
- hash_table = memnew_arr(PosBin *, hash_table_size);
-
- cell_size = GLOBAL_DEF("physics/2d/cell_size", 128);
- ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/cell_size", PropertyInfo(Variant::INT, "physics/2d/cell_size", PROPERTY_HINT_RANGE, "0,512,1,or_greater"));
-
- large_object_min_surface = GLOBAL_DEF("physics/2d/large_object_surface_threshold_in_cells", 512);
- 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] = nullptr;
- }
- pass = 1;
-
- current = 0;
-}
-
-BroadPhase2DHashGrid::~BroadPhase2DHashGrid() {
- for (uint32_t i = 0; i < hash_table_size; i++) {
- while (hash_table[i]) {
- PosBin *pb = hash_table[i];
- hash_table[i] = pb->next;
- memdelete(pb);
- }
- }
-
- memdelete_arr(hash_table);
-}
-
-/* 3D version of voxel traversal:
-
-public IEnumerable<Point3D> GetCellsOnRay(Ray ray, int maxDepth)
-{
- // Implementation is based on:
- // "A Fast Voxel Traversal Algorithm for Ray Tracing"
- // John Amanatides, Andrew Woo
- // http://www.cse.yorku.ca/~amana/research/grid.pdf
- // https://web.archive.org/web/20100616193049/http://www.devmaster.net/articles/raytracing_series/A%20faster%20voxel%20traversal%20algorithm%20for%20ray%20tracing.pdf
-
- // NOTES:
- // * This code assumes that the ray's position and direction are in 'cell coordinates', which means
- // that one unit equals one cell in all directions.
- // * When the ray doesn't start within the voxel grid, calculate the first position at which the
- // ray could enter the grid. If it never enters the grid, there is nothing more to do here.
- // * Also, it is important to test when the ray exits the voxel grid when the grid isn't infinite.
- // * The Point3D structure is a simple structure having three integer fields (X, Y and Z).
-
- // The cell in which the ray starts.
- Point3D start = GetCellAt(ray.Position); // Rounds the position's X, Y and Z down to the nearest integer values.
- int x = start.X;
- int y = start.Y;
- int z = start.Z;
-
- // Determine which way we go.
- int stepX = Math.Sign(ray.Direction.X);
- int stepY = Math.Sign(ray.Direction.Y);
- int stepZ = Math.Sign(ray.Direction.Z);
-
- // Calculate cell boundaries. When the step (i.e. direction sign) is positive,
- // the next boundary is AFTER our current position, meaning that we have to add 1.
- // Otherwise, it is BEFORE our current position, in which case we add nothing.
- Point3D cellBoundary = new Point3D(
- x + (stepX > 0 ? 1 : 0),
- y + (stepY > 0 ? 1 : 0),
- z + (stepZ > 0 ? 1 : 0));
-
- // NOTE: For the following calculations, the result will be Single.PositiveInfinity
- // when ray.Direction.X, Y or Z equals zero, which is OK. However, when the left-hand
- // value of the division also equals zero, the result is Single.NaN, which is not OK.
-
- // Determine how far we can travel along the ray before we hit a voxel boundary.
- Vector3 tMax = new Vector3(
- (cellBoundary.X - ray.Position.X) / ray.Direction.X, // Boundary is a plane on the YZ axis.
- (cellBoundary.Y - ray.Position.Y) / ray.Direction.Y, // Boundary is a plane on the XZ axis.
- (cellBoundary.Z - ray.Position.Z) / ray.Direction.Z); // Boundary is a plane on the XY axis.
- if (Single.IsNaN(tMax.X)) tMax.X = Single.PositiveInfinity;
- if (Single.IsNaN(tMax.Y)) tMax.Y = Single.PositiveInfinity;
- if (Single.IsNaN(tMax.Z)) tMax.Z = Single.PositiveInfinity;
-
- // Determine how far we must travel along the ray before we have crossed a gridcell.
- Vector3 tDelta = new Vector3(
- stepX / ray.Direction.X, // Crossing the width of a cell.
- stepY / ray.Direction.Y, // Crossing the height of a cell.
- stepZ / ray.Direction.Z); // Crossing the depth of a cell.
- if (Single.IsNaN(tDelta.X)) tDelta.X = Single.PositiveInfinity;
- if (Single.IsNaN(tDelta.Y)) tDelta.Y = Single.PositiveInfinity;
- if (Single.IsNaN(tDelta.Z)) tDelta.Z = Single.PositiveInfinity;
-
- // For each step, determine which distance to the next voxel boundary is lowest (i.e.
- // which voxel boundary is nearest) and walk that way.
- for (int i = 0; i < maxDepth; i++)
- {
- // Return it.
- yield return new Point3D(x, y, z);
-
- // Do the next step.
- if (tMax.X < tMax.Y && tMax.X < tMax.Z)
- {
- // tMax.X is the lowest, an YZ cell boundary plane is nearest.
- x += stepX;
- tMax.X += tDelta.X;
- }
- else if (tMax.Y < tMax.Z)
- {
- // tMax.Y is the lowest, an XZ cell boundary plane is nearest.
- y += stepY;
- tMax.Y += tDelta.Y;
- }
- else
- {
- // tMax.Z is the lowest, an XY cell boundary plane is nearest.
- z += stepZ;
- tMax.Z += tDelta.Z;
- }
- }
-
- */
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.h b/servers/physics_2d/broad_phase_2d_hash_grid.h
deleted file mode 100644
index bb7c03b989..0000000000
--- a/servers/physics_2d/broad_phase_2d_hash_grid.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/*************************************************************************/
-/* broad_phase_2d_hash_grid.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef BROAD_PHASE_2D_HASH_GRID_H
-#define BROAD_PHASE_2D_HASH_GRID_H
-
-#include "broad_phase_2d_sw.h"
-#include "core/templates/map.h"
-
-class BroadPhase2DHashGrid : public BroadPhase2DSW {
- struct PairData {
- bool colliding;
- int rc;
- void *ud;
- PairData() {
- colliding = false;
- rc = 1;
- ud = nullptr;
- }
- };
-
- struct Element {
- ID self;
- CollisionObject2DSW *owner;
- bool _static;
- Rect2 aabb;
- // Owner's collision_mask/layer, used to detect changes in layers.
- uint32_t collision_mask;
- uint32_t collision_layer;
- int subindex;
- uint64_t pass;
- Map<Element *, PairData *> paired;
- };
-
- struct RC {
- int ref;
-
- _FORCE_INLINE_ int inc() {
- ref++;
- return ref;
- }
- _FORCE_INLINE_ int dec() {
- ref--;
- return ref;
- }
-
- _FORCE_INLINE_ RC() {
- ref = 0;
- }
- };
-
- Map<ID, Element> element_map;
- Map<Element *, RC> large_elements;
-
- ID current;
-
- uint64_t pass;
-
- 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, PairData> pair_map;
-
- int cell_size;
- int large_object_min_surface;
-
- PairCallback pair_callback;
- void *pair_userdata;
- UnpairCallback unpair_callback;
- void *unpair_userdata;
-
- static _FORCE_INLINE_ bool _test_collision_mask(uint32_t p_mask1, uint32_t p_layer1, uint32_t p_mask2, uint32_t p_layer2) {
- return p_mask1 & p_layer2 || p_mask2 & p_layer1;
- }
-
- void _enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_enter);
- void _exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_exit);
- template <bool use_aabb, bool use_segment>
- _FORCE_INLINE_ void _cull(const Point2i p_cell, const Rect2 &p_aabb, const Point2 &p_from, const Point2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices, int &index);
-
- struct PosKey {
- union {
- struct {
- int32_t x;
- int32_t y;
- };
- uint64_t key;
- };
-
- _FORCE_INLINE_ uint32_t hash() const {
- uint64_t k = key;
- k = (~k) + (k << 18); // k = (k << 18) - k - 1;
- k = k ^ (k >> 31);
- k = k * 21; // k = (k + (k << 2)) + (k << 4);
- k = k ^ (k >> 11);
- k = k + (k << 6);
- k = k ^ (k >> 22);
- return k;
- }
-
- bool operator==(const PosKey &p_key) const { return key == p_key.key; }
- _FORCE_INLINE_ bool operator<(const PosKey &p_key) const {
- return key < p_key.key;
- }
- };
-
- struct PosBin {
- PosKey key;
- Map<Element *, RC> object_set;
- Map<Element *, RC> static_object_set;
- PosBin *next;
- };
-
- uint32_t hash_table_size;
- PosBin **hash_table;
-
- void _pair_attempt(Element *p_elem, Element *p_with);
- void _unpair_attempt(Element *p_elem, Element *p_with);
- void _check_motion(Element *p_elem);
-
-public:
- virtual ID create(CollisionObject2DSW *p_object, int p_subindex = 0);
- virtual void move(ID p_id, const Rect2 &p_aabb);
- virtual void set_static(ID p_id, bool p_static);
- virtual void remove(ID p_id);
-
- virtual CollisionObject2DSW *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_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);
-
- virtual void update();
-
- static BroadPhase2DSW *_create();
-
- BroadPhase2DHashGrid();
- ~BroadPhase2DHashGrid();
-};
-
-#endif // BROAD_PHASE_2D_HASH_GRID_H
diff --git a/servers/physics_2d/broad_phase_2d_sw.h b/servers/physics_2d/broad_phase_2d_sw.h
index d17ee6e2d6..0f82f06b9c 100644
--- a/servers/physics_2d/broad_phase_2d_sw.h
+++ b/servers/physics_2d/broad_phase_2d_sw.h
@@ -48,7 +48,7 @@ public:
typedef void (*UnpairCallback)(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_data, void *p_userdata);
// 0 is an invalid ID
- virtual ID create(CollisionObject2DSW *p_object_, int p_subindex = 0) = 0;
+ virtual ID create(CollisionObject2DSW *p_object_, int p_subindex = 0, const Rect2 &p_aabb = Rect2(), bool p_static = false) = 0;
virtual void move(ID p_id, const Rect2 &p_aabb) = 0;
virtual void set_static(ID p_id, bool p_static) = 0;
virtual void remove(ID p_id) = 0;
diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp
index 7a2f312263..fa87dc1f3f 100644
--- a/servers/physics_2d/collision_object_2d_sw.cpp
+++ b/servers/physics_2d/collision_object_2d_sw.cpp
@@ -182,19 +182,19 @@ void CollisionObject2DSW::_update_shapes() {
continue;
}
- 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..
Rect2 shape_aabb = s.shape->get_aabb();
Transform2D xform = transform * s.xform;
shape_aabb = xform.xform(shape_aabb);
+ shape_aabb.grow_by((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05);
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);
- space->get_broadphase()->move(s.bpid, s.aabb_cache);
+ if (s.bpid == 0) {
+ s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static);
+ space->get_broadphase()->set_static(s.bpid, _static);
+ }
+
+ space->get_broadphase()->move(s.bpid, shape_aabb);
}
}
@@ -209,11 +209,6 @@ void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) {
continue;
}
- 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..
Rect2 shape_aabb = s.shape->get_aabb();
Transform2D xform = transform * s.xform;
@@ -221,6 +216,11 @@ void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) {
shape_aabb = shape_aabb.merge(Rect2(shape_aabb.position + p_motion, shape_aabb.size)); //use motion
s.aabb_cache = shape_aabb;
+ if (s.bpid == 0) {
+ s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static);
+ space->get_broadphase()->set_static(s.bpid, _static);
+ }
+
space->get_broadphase()->move(s.bpid, shape_aabb);
}
}
diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h
index 2db3961f41..c395e59694 100644
--- a/servers/physics_2d/collision_object_2d_sw.h
+++ b/servers/physics_2d/collision_object_2d_sw.h
@@ -143,8 +143,8 @@ public:
return shapes[p_index].metadata;
}
- _FORCE_INLINE_ Transform2D get_transform() const { return transform; }
- _FORCE_INLINE_ Transform2D get_inv_transform() const { return inv_transform; }
+ _FORCE_INLINE_ const Transform2D &get_transform() const { return transform; }
+ _FORCE_INLINE_ const Transform2D &get_inv_transform() const { return inv_transform; }
_FORCE_INLINE_ Space2DSW *get_space() const { return space; }
void set_shape_as_disabled(int p_idx, bool p_disabled);
diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h
index b724deb48e..5e8dfbe570 100644
--- a/servers/physics_2d/constraint_2d_sw.h
+++ b/servers/physics_2d/constraint_2d_sw.h
@@ -63,6 +63,7 @@ public:
_FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; }
virtual bool setup(real_t p_step) = 0;
+ virtual bool pre_solve(real_t p_step) = 0;
virtual void solve(real_t p_step) = 0;
virtual ~Constraint2DSW() {}
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index 20d4b9aa1a..5a0a628fbc 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/joints_2d_sw.cpp
@@ -97,7 +97,10 @@ normal_relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB, Vecto
}
bool PinJoint2DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -148,12 +151,6 @@ bool PinJoint2DSW::setup(real_t p_step) {
bias = delta * -(get_bias() == 0 ? space->get_constraint_bias() : get_bias()) * (1.0 / p_step);
- // apply accumulated impulse
- A->apply_impulse(-P, rA);
- if (B) {
- B->apply_impulse(P, rB);
- }
-
return true;
}
@@ -161,6 +158,18 @@ inline Vector2 custom_cross(const Vector2 &p_vec, real_t p_other) {
return Vector2(p_other * p_vec.y, -p_other * p_vec.x);
}
+bool PinJoint2DSW::pre_solve(real_t p_step) {
+ // Apply accumulated impulse.
+ if (dynamic_A) {
+ A->apply_impulse(-P, rA);
+ }
+ if (B && dynamic_B) {
+ B->apply_impulse(P, rB);
+ }
+
+ return true;
+}
+
void PinJoint2DSW::solve(real_t p_step) {
// compute relative velocity
Vector2 vA = A->get_linear_velocity() - custom_cross(rA, A->get_angular_velocity());
@@ -174,8 +183,10 @@ void PinJoint2DSW::solve(real_t p_step) {
Vector2 impulse = M.basis_xform(bias - rel_vel - Vector2(softness, softness) * P);
- A->apply_impulse(-impulse, rA);
- if (B) {
+ if (dynamic_A) {
+ A->apply_impulse(-impulse, rA);
+ }
+ if (B && dynamic_B) {
B->apply_impulse(impulse, rB);
}
@@ -262,14 +273,19 @@ mult_k(const Vector2 &vr, const Vector2 &k1, const Vector2 &k2) {
}
bool GrooveJoint2DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
+ Space2DSW *space = A->get_space();
+ ERR_FAIL_COND_V(!space, false);
+
// calculate endpoints in worldspace
Vector2 ta = A->get_transform().xform(A_groove_1);
Vector2 tb = A->get_transform().xform(A_groove_2);
- Space2DSW *space = A->get_space();
// calculate axis
Vector2 n = -(tb - ta).orthogonal().normalized();
@@ -306,16 +322,24 @@ bool GrooveJoint2DSW::setup(real_t p_step) {
Vector2 delta = (B->get_transform().get_origin() + rB) - (A->get_transform().get_origin() + rA);
real_t _b = get_bias();
- gbias = (delta * -(_b == 0 ? space->get_constraint_bias() : _b) * (1.0 / p_step)).clamped(get_max_bias());
-
- // apply accumulated impulse
- A->apply_impulse(-jn_acc, rA);
- B->apply_impulse(jn_acc, rB);
+ gbias = (delta * -(_b == 0 ? space->get_constraint_bias() : _b) * (1.0 / p_step)).limit_length(get_max_bias());
correct = true;
return true;
}
+bool GrooveJoint2DSW::pre_solve(real_t p_step) {
+ // Apply accumulated impulse.
+ if (dynamic_A) {
+ A->apply_impulse(-jn_acc, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(jn_acc, rB);
+ }
+
+ return true;
+}
+
void GrooveJoint2DSW::solve(real_t p_step) {
// compute impulse
Vector2 vr = relative_velocity(A, B, rA, rB);
@@ -324,12 +348,16 @@ void GrooveJoint2DSW::solve(real_t p_step) {
Vector2 jOld = jn_acc;
j += jOld;
- jn_acc = (((clamp * j.cross(xf_normal)) > 0) ? j : j.project(xf_normal)).clamped(jn_max);
+ jn_acc = (((clamp * j.cross(xf_normal)) > 0) ? j : j.project(xf_normal)).limit_length(jn_max);
j = jn_acc - jOld;
- A->apply_impulse(-j, rA);
- B->apply_impulse(j, rB);
+ if (dynamic_A) {
+ A->apply_impulse(-j, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, rB);
+ }
}
GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b) :
@@ -351,7 +379,10 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_
//////////////////////////////////////////////
bool DampedSpringJoint2DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -373,12 +404,21 @@ bool DampedSpringJoint2DSW::setup(real_t p_step) {
target_vrn = 0.0f;
v_coef = 1.0f - Math::exp(-damping * (p_step)*k);
- // apply spring force
+ // Calculate spring force.
real_t f_spring = (rest_length - dist) * stiffness;
- Vector2 j = n * f_spring * (p_step);
+ j = n * f_spring * (p_step);
- A->apply_impulse(-j, rA);
- B->apply_impulse(j, rB);
+ return true;
+}
+
+bool DampedSpringJoint2DSW::pre_solve(real_t p_step) {
+ // Apply spring force.
+ if (dynamic_A) {
+ A->apply_impulse(-j, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, rB);
+ }
return true;
}
@@ -393,8 +433,12 @@ void DampedSpringJoint2DSW::solve(real_t p_step) {
target_vrn = vrn + v_damp;
Vector2 j = n * v_damp * n_mass;
- A->apply_impulse(-j, rA);
- B->apply_impulse(j, rB);
+ if (dynamic_A) {
+ A->apply_impulse(-j, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, rB);
+ }
}
void DampedSpringJoint2DSW::set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value) {
diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/joints_2d_sw.h
index 628de972ae..ccc5c585a0 100644
--- a/servers/physics_2d/joints_2d_sw.h
+++ b/servers/physics_2d/joints_2d_sw.h
@@ -39,6 +39,10 @@ class Joint2DSW : public Constraint2DSW {
real_t bias;
real_t max_bias;
+protected:
+ bool dynamic_A = false;
+ bool dynamic_B = false;
+
public:
_FORCE_INLINE_ void set_max_force(real_t p_force) { max_force = p_force; }
_FORCE_INLINE_ real_t get_max_force() const { return max_force; }
@@ -49,8 +53,9 @@ 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 bool setup(real_t p_step) { return false; }
- virtual void solve(real_t p_step) {}
+ virtual bool setup(real_t p_step) override { return false; }
+ virtual bool pre_solve(real_t p_step) override { return false; }
+ virtual void solve(real_t p_step) override {}
void copy_settings_from(Joint2DSW *p_joint);
@@ -90,10 +95,11 @@ class PinJoint2DSW : public Joint2DSW {
real_t softness;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_PIN; }
+ virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_PIN; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
void set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value);
real_t get_param(PhysicsServer2D::PinJointParam p_param) const;
@@ -126,10 +132,11 @@ class GrooveJoint2DSW : public Joint2DSW {
bool correct;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_GROOVE; }
+ virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_GROOVE; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b);
};
@@ -153,15 +160,17 @@ class DampedSpringJoint2DSW : public Joint2DSW {
Vector2 rA, rB;
Vector2 n;
+ Vector2 j;
real_t n_mass;
real_t target_vrn;
real_t v_coef;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; }
+ virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
void set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value);
real_t get_param(PhysicsServer2D::DampedSpringParam p_param) const;
diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp
index 1040437ca7..1c2dca0259 100644
--- a/servers/physics_2d/physics_server_2d_sw.cpp
+++ b/servers/physics_2d/physics_server_2d_sw.cpp
@@ -30,8 +30,7 @@
#include "physics_server_2d_sw.h"
-#include "broad_phase_2d_basic.h"
-#include "broad_phase_2d_hash_grid.h"
+#include "broad_phase_2d_bvh.h"
#include "collision_solver_2d_sw.h"
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
@@ -927,10 +926,10 @@ int PhysicsServer2DSW::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
-void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
+void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
+ body->set_force_integration_callback(p_callable, p_udata);
}
bool PhysicsServer2DSW::body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) {
@@ -1238,6 +1237,10 @@ void PhysicsServer2DSW::set_active(bool p_active) {
active = p_active;
};
+void PhysicsServer2DSW::set_collision_iterations(int p_iterations) {
+ iterations = p_iterations;
+};
+
void PhysicsServer2DSW::init() {
doing_sync = false;
last_step = 0.001;
@@ -1356,8 +1359,7 @@ PhysicsServer2DSW *PhysicsServer2DSW::singletonsw = nullptr;
PhysicsServer2DSW::PhysicsServer2DSW(bool p_using_threads) {
singletonsw = this;
- BroadPhase2DSW::create_func = BroadPhase2DHashGrid::_create;
- //BroadPhase2DSW::create_func=BroadPhase2DBasic::_create;
+ BroadPhase2DSW::create_func = BroadPhase2DBVH::_create;
active = true;
island_count = 0;
diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h
index 65c5df0fce..5002bf5fc8 100644
--- a/servers/physics_2d/physics_server_2d_sw.h
+++ b/servers/physics_2d/physics_server_2d_sw.h
@@ -242,13 +242,13 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override;
virtual void body_set_pickable(RID p_body, bool p_pickable) override;
- 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) override;
- 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, real_t p_margin = 0.001) override;
+ 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.08, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
+ 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, real_t p_margin = 0.08) override;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override;
@@ -288,6 +288,8 @@ public:
virtual void end_sync() override;
virtual void finish() override;
+ virtual void set_collision_iterations(int p_iterations) override;
+
virtual bool is_flushing_queries() const override { return flushing_queries; }
int get_process_info(ProcessInfo p_info) override;
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.cpp b/servers/physics_2d/physics_server_2d_wrap_mt.cpp
index 790c87cc44..930b19c2cb 100644
--- a/servers/physics_2d/physics_server_2d_wrap_mt.cpp
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.cpp
@@ -56,7 +56,7 @@ void PhysicsServer2DWrapMT::thread_loop() {
step_thread_up.set();
while (!exit.is_set()) {
// flush commands one by one, until exit is requested
- command_queue.wait_and_flush_one();
+ command_queue.wait_and_flush();
}
command_queue.flush_all(); // flush all
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h
index 3577f706de..c776641699 100644
--- a/servers/physics_2d/physics_server_2d_wrap_mt.h
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.h
@@ -245,7 +245,7 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
- FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, const Variant &);
+ FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
return physics_2d_server->body_collide_shape(p_body, p_body_shape, p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count);
@@ -303,6 +303,7 @@ public:
FUNC1(free, RID);
FUNC1(set_active, bool);
+ FUNC1(set_collision_iterations, int);
virtual void init() override;
virtual void step(real_t p_step) override;
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 4f12248c3e..1380e57b57 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -827,7 +827,7 @@ 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() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) {
+ if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_DYNAMIC) {
//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
@@ -1109,7 +1109,7 @@ 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() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) {
+ if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_DYNAMIC) {
//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
diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp
index 406d750776..b8cb4cddc5 100644
--- a/servers/physics_2d/step_2d_sw.cpp
+++ b/servers/physics_2d/step_2d_sw.cpp
@@ -29,45 +29,59 @@
/*************************************************************************/
#include "step_2d_sw.h"
+
#include "core/os/os.h"
#define BODY_ISLAND_COUNT_RESERVE 128
#define BODY_ISLAND_SIZE_RESERVE 512
#define ISLAND_COUNT_RESERVE 128
#define ISLAND_SIZE_RESERVE 512
+#define CONSTRAINT_COUNT_RESERVE 1024
void Step2DSW::_populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island) {
p_body->set_island_step(_step);
- p_body_island.push_back(p_body);
- // Faster with reversed iterations.
- for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().back(); E; E = E->prev()) {
- Constraint2DSW *c = (Constraint2DSW *)E->get().first;
- if (c->get_island_step() == _step) {
- continue; //already processed
+ if (p_body->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ // Only dynamic bodies are tested for activation.
+ p_body_island.push_back(p_body);
+ }
+
+ for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().front(); E; E = E->next()) {
+ Constraint2DSW *constraint = (Constraint2DSW *)E->get().first;
+ if (constraint->get_island_step() == _step) {
+ continue; // Already processed.
}
- c->set_island_step(_step);
- p_constraint_island.push_back(c);
+ constraint->set_island_step(_step);
+ p_constraint_island.push_back(constraint);
+ all_constraints.push_back(constraint);
- for (int i = 0; i < c->get_body_count(); i++) {
+ for (int i = 0; i < constraint->get_body_count(); i++) {
if (i == E->get().second) {
continue;
}
- Body2DSW *b = c->get_body_ptr()[i];
- if (b->get_island_step() == _step || b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- continue; //no go
+ Body2DSW *other_body = constraint->get_body_ptr()[i];
+ if (other_body->get_island_step() == _step) {
+ continue; // Already processed.
+ }
+ if (other_body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC) {
+ continue; // Static bodies don't connect islands.
}
- _populate_island(c->get_body_ptr()[i], p_body_island, p_constraint_island);
+ _populate_island(other_body, p_body_island, p_constraint_island);
}
}
}
-void Step2DSW::_setup_island(LocalVector<Constraint2DSW *> &p_constraint_island, real_t p_delta) {
+void Step2DSW::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) {
+ Constraint2DSW *constraint = all_constraints[p_constraint_index];
+ constraint->setup(delta);
+}
+
+void Step2DSW::_pre_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island) const {
uint32_t constraint_count = p_constraint_island.size();
uint32_t valid_constraint_count = 0;
for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
Constraint2DSW *constraint = p_constraint_island[constraint_index];
- if (p_constraint_island[constraint_index]->setup(p_delta)) {
+ if (p_constraint_island[constraint_index]->pre_solve(delta)) {
// Keep this constraint for solving.
p_constraint_island[valid_constraint_count++] = constraint;
}
@@ -75,27 +89,25 @@ void Step2DSW::_setup_island(LocalVector<Constraint2DSW *> &p_constraint_island,
p_constraint_island.resize(valid_constraint_count);
}
-void Step2DSW::_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island, int p_iterations, real_t p_delta) {
- for (int i = 0; i < p_iterations; i++) {
- uint32_t constraint_count = p_constraint_island.size();
+void Step2DSW::_solve_island(uint32_t p_island_index, void *p_userdata) const {
+ const LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[p_island_index];
+
+ for (int i = 0; i < iterations; i++) {
+ uint32_t constraint_count = constraint_island.size();
for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
- p_constraint_island[constraint_index]->solve(p_delta);
+ constraint_island[constraint_index]->solve(delta);
}
}
}
-void Step2DSW::_check_suspend(const LocalVector<Body2DSW *> &p_body_island, real_t p_delta) {
+void Step2DSW::_check_suspend(LocalVector<Body2DSW *> &p_body_island) const {
bool can_sleep = true;
uint32_t body_count = p_body_island.size();
for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
Body2DSW *body = p_body_island[body_index];
- if (body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- continue; // Ignore for static.
- }
-
- if (!body->sleep_test(p_delta)) {
+ if (!body->sleep_test(delta)) {
can_sleep = false;
}
}
@@ -104,10 +116,6 @@ void Step2DSW::_check_suspend(const LocalVector<Body2DSW *> &p_body_island, real
for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
Body2DSW *body = p_body_island[body_index];
- if (body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- continue; // Ignore for static.
- }
-
bool active = body->is_active();
if (active == can_sleep) {
@@ -121,6 +129,9 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
p_space->setup(); //update inertias, etc
+ iterations = p_iterations;
+ delta = p_delta;
+
const SelfList<Body2DSW>::List *body_list = &p_space->get_active_body_list();
/* INTEGRATE FORCES */
@@ -145,12 +156,39 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
profile_begtime = profile_endtime;
}
- /* GENERATE CONSTRAINT ISLANDS */
+ /* GENERATE CONSTRAINT ISLANDS FOR MOVING AREAS */
+
+ uint32_t island_count = 0;
+
+ const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list();
+
+ while (aml.first()) {
+ for (const Set<Constraint2DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) {
+ Constraint2DSW *constraint = E->get();
+ if (constraint->get_island_step() == _step) {
+ continue;
+ }
+ constraint->set_island_step(_step);
+
+ // Each constraint can be on a separate island for areas as there's no solving phase.
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+
+ all_constraints.push_back(constraint);
+ constraint_island.push_back(constraint);
+ }
+ p_space->area_remove_from_moved_list((SelfList<Area2DSW> *)aml.first()); //faster to remove here
+ }
+
+ /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */
b = body_list->first();
uint32_t body_island_count = 0;
- uint32_t island_count = 0;
while (b) {
Body2DSW *body = b->self();
@@ -174,7 +212,9 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
_populate_island(body, body_island, constraint_island);
- body_islands.push_back(body_island);
+ if (body_island.is_empty()) {
+ --body_island_count;
+ }
if (constraint_island.is_empty()) {
--island_count;
@@ -185,37 +225,16 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
p_space->set_island_count((int)island_count);
- const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list();
-
- while (aml.first()) {
- for (const Set<Constraint2DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) {
- Constraint2DSW *c = E->get();
- if (c->get_island_step() == _step) {
- continue;
- }
- c->set_island_step(_step);
- ++island_count;
- if (constraint_islands.size() < island_count) {
- constraint_islands.resize(island_count);
- }
- LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1];
- constraint_island.clear();
- constraint_island.push_back(c);
- }
- p_space->area_remove_from_moved_list((SelfList<Area2DSW> *)aml.first()); //faster to remove here
- }
-
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);
profile_begtime = profile_endtime;
}
- /* SETUP CONSTRAINT ISLANDS */
+ /* SETUP CONSTRAINTS / PROCESS COLLISIONS */
- for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
- _setup_island(constraint_islands[island_index], p_delta);
- }
+ uint32_t total_contraint_count = all_constraints.size();
+ work_pool.do_work(total_contraint_count, this, &Step2DSW::_setup_contraint, nullptr);
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
@@ -223,10 +242,21 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
profile_begtime = profile_endtime;
}
- /* SOLVE CONSTRAINT ISLANDS */
+ /* PRE-SOLVE CONSTRAINT ISLANDS */
+ // Warning: This doesn't run on threads, because it involves thread-unsafe processing.
for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
- _solve_island(constraint_islands[island_index], p_iterations, p_delta);
+ _pre_solve_island(constraint_islands[island_index]);
+ }
+
+ /* SOLVE CONSTRAINT ISLANDS */
+
+ // Warning: _solve_island modifies the constraint islands for optimization purpose,
+ // their content is not reliable after these calls and shouldn't be used anymore.
+ if (island_count > 1) {
+ work_pool.do_work(island_count, this, &Step2DSW::_solve_island, nullptr);
+ } else if (island_count > 0) {
+ _solve_island(0);
}
{ //profile
@@ -247,7 +277,7 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* SLEEP / WAKE UP ISLANDS */
for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {
- _check_suspend(body_islands[island_index], p_delta);
+ _check_suspend(body_islands[island_index]);
}
{ //profile
@@ -256,6 +286,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
//profile_begtime=profile_endtime;
}
+ all_constraints.clear();
+
p_space->update();
p_space->unlock();
_step++;
@@ -266,4 +298,11 @@ Step2DSW::Step2DSW() {
body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);
constraint_islands.reserve(ISLAND_COUNT_RESERVE);
+ all_constraints.reserve(CONSTRAINT_COUNT_RESERVE);
+
+ work_pool.init();
+}
+
+Step2DSW::~Step2DSW() {
+ work_pool.finish();
}
diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/step_2d_sw.h
index 5af4a36f52..c51fd73a79 100644
--- a/servers/physics_2d/step_2d_sw.h
+++ b/servers/physics_2d/step_2d_sw.h
@@ -34,21 +34,30 @@
#include "space_2d_sw.h"
#include "core/templates/local_vector.h"
+#include "core/templates/thread_work_pool.h"
class Step2DSW {
uint64_t _step;
+ int iterations = 0;
+ real_t delta = 0.0;
+
+ ThreadWorkPool work_pool;
+
LocalVector<LocalVector<Body2DSW *>> body_islands;
LocalVector<LocalVector<Constraint2DSW *>> constraint_islands;
+ LocalVector<Constraint2DSW *> all_constraints;
void _populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island);
- void _setup_island(LocalVector<Constraint2DSW *> &p_constraint_island, real_t p_delta);
- void _solve_island(LocalVector<Constraint2DSW *> &p_constraint_island, int p_iterations, real_t p_delta);
- void _check_suspend(const LocalVector<Body2DSW *> &p_body_island, real_t p_delta);
+ void _setup_contraint(uint32_t p_constraint_index, void *p_userdata = nullptr);
+ void _pre_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island) const;
+ void _solve_island(uint32_t p_island_index, void *p_userdata = nullptr) const;
+ void _check_suspend(LocalVector<Body2DSW *> &p_body_island) const;
public:
void step(Space2DSW *p_space, real_t p_delta, int p_iterations);
Step2DSW();
+ ~Step2DSW();
};
#endif // STEP_2D_SW_H
diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp
index bb4e0ed752..a9f5c4aec3 100644
--- a/servers/physics_3d/area_3d_sw.cpp
+++ b/servers/physics_3d/area_3d_sw.cpp
@@ -52,7 +52,7 @@ void Area3DSW::_shapes_changed() {
}
}
-void Area3DSW::set_transform(const Transform &p_transform) {
+void Area3DSW::set_transform(const Transform3D &p_transform) {
if (!moved_list.in_list() && get_space()) {
get_space()->area_add_to_moved_list(&moved_list);
}
diff --git a/servers/physics_3d/area_3d_sw.h b/servers/physics_3d/area_3d_sw.h
index 8a0a1e963b..12f7545c08 100644
--- a/servers/physics_3d/area_3d_sw.h
+++ b/servers/physics_3d/area_3d_sw.h
@@ -156,7 +156,7 @@ public:
void set_monitorable(bool p_monitorable);
_FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
- void set_transform(const Transform &p_transform);
+ void set_transform(const Transform3D &p_transform);
void set_space(Space3DSW *p_space);
diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp
index 4de5f1ba47..2073df7dee 100644
--- a/servers/physics_3d/area_pair_3d_sw.cpp
+++ b/servers/physics_3d/area_pair_3d_sw.cpp
@@ -40,31 +40,48 @@ bool AreaPair3DSW::setup(real_t p_step) {
result = true;
}
+ process_collision = false;
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);
- }
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
+ process_collision = true;
+ } else if (area->has_monitor_callback()) {
+ process_collision = true;
}
colliding = result;
}
- return false; //never do any post solving
+ return process_collision;
+}
+
+bool AreaPair3DSW::pre_solve(real_t p_step) {
+ if (!process_collision) {
+ return false;
+ }
+
+ if (colliding) {
+ 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);
+ }
+ }
+
+ return false; // Never do any post solving.
}
void AreaPair3DSW::solve(real_t p_step) {
+ // Nothing to do.
}
AreaPair3DSW::AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, int p_area_shape) {
@@ -72,7 +89,6 @@ AreaPair3DSW::AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area,
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) {
@@ -103,33 +119,48 @@ bool Area2Pair3DSW::setup(real_t p_step) {
result = true;
}
+ process_collision = false;
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);
- }
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ process_collision = true;
+ } else if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ process_collision = true;
}
colliding = result;
}
- return false; //never do any post solving
+ return process_collision;
+}
+
+bool Area2Pair3DSW::pre_solve(real_t p_step) {
+ if (!process_collision) {
+ return false;
+ }
+
+ if (colliding) {
+ 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);
+ }
+ }
+
+ return false; // Never do any post solving.
}
void Area2Pair3DSW::solve(real_t p_step) {
+ // Nothing to do.
}
Area2Pair3DSW::Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area_b, int p_shape_b) {
@@ -137,7 +168,6 @@ Area2Pair3DSW::Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area
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);
}
diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h
index fbdaa25cbb..596d893082 100644
--- a/servers/physics_3d/area_pair_3d_sw.h
+++ b/servers/physics_3d/area_pair_3d_sw.h
@@ -40,11 +40,13 @@ class AreaPair3DSW : public Constraint3DSW {
Area3DSW *area;
int body_shape;
int area_shape;
- bool colliding;
+ bool colliding = false;
+ bool process_collision = false;
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, int p_area_shape);
~AreaPair3DSW();
@@ -55,11 +57,13 @@ class Area2Pair3DSW : public Constraint3DSW {
Area3DSW *area_b;
int shape_a;
int shape_b;
- bool colliding;
+ bool colliding = false;
+ bool process_collision = false;
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area_b, int p_shape_b);
~Area2Pair3DSW();
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index cc414b7f30..ea6064cb4c 100644
--- a/servers/physics_3d/body_3d_sw.cpp
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -54,7 +54,7 @@ void Body3DSW::update_inertias() {
// Update shapes and motions.
switch (mode) {
- case PhysicsServer3D::BODY_MODE_RIGID: {
+ case PhysicsServer3D::BODY_MODE_DYNAMIC: {
// Update tensor for all shapes, not the best way but should be somehow OK. (inspired from bullet)
real_t total_area = 0;
@@ -65,16 +65,18 @@ void Body3DSW::update_inertias() {
// 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);
+ if (total_area != 0.0) {
+ for (int i = 0; i < get_shape_count(); i++) {
+ real_t area = get_shape_area(i);
- real_t mass = area * this->mass / total_area;
+ 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;
- }
+ // 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;
+ center_of_mass_local /= mass;
+ }
// Recompute the inertia tensor.
Basis inertia_tensor;
@@ -86,16 +88,19 @@ void Body3DSW::update_inertias() {
continue;
}
+ real_t area = get_shape_area(i);
+ if (area == 0.0) {
+ continue;
+ }
+
inertia_set = true;
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);
+ Transform3D 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!
@@ -127,7 +132,7 @@ void Body3DSW::update_inertias() {
_inv_inertia_tensor.set_zero();
_inv_mass = 0;
} break;
- case PhysicsServer3D::BODY_MODE_CHARACTER: {
+ case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: {
_inv_inertia_tensor.set_zero();
_inv_mass = 1.0 / mass;
@@ -145,31 +150,17 @@ void Body3DSW::set_active(bool p_active) {
}
active = p_active;
- if (!p_active) {
- if (get_space()) {
- get_space()->body_remove_from_active_list(&active_list);
- }
- } else {
+
+ if (active) {
if (mode == PhysicsServer3D::BODY_MODE_STATIC) {
- return; //static bodies can't become active
- }
- if (get_space()) {
+ // Static bodies can't be active.
+ active = false;
+ } else 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);
- }
+ } else if (get_space()) {
+ get_space()->body_remove_from_active_list(&active_list);
}
-*/
}
void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) {
@@ -248,13 +239,13 @@ void Body3DSW::set_mode(PhysicsServer3D::BodyMode p_mode) {
}
} break;
- case PhysicsServer3D::BODY_MODE_RIGID: {
+ case PhysicsServer3D::BODY_MODE_DYNAMIC: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_set_static(false);
set_active(true);
} break;
- case PhysicsServer3D::BODY_MODE_CHARACTER: {
+ case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_set_static(false);
set_active(true);
@@ -295,7 +286,7 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va
_set_inv_transform(get_transform().affine_inverse());
wakeup_neighbours();
} else {
- Transform t = p_variant;
+ Transform3D t = p_variant;
t.orthonormalize();
new_transform = get_transform(); //used as old to compute motion
if (new_transform == t) {
@@ -308,24 +299,15 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va
} 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;
}
@@ -342,7 +324,7 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va
} break;
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
can_sleep = p_variant;
- if (mode == PhysicsServer3D::BODY_MODE_RIGID && !active && !can_sleep) {
+ if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC && !active && !can_sleep) {
set_active(true);
}
@@ -392,13 +374,6 @@ void Body3DSW::set_space(Space3DSW *p_space) {
if (active) {
get_space()->body_add_to_active_list(&active_list);
}
- /*
- _update_queries();
- if (is_active()) {
- active=false;
- set_active(true);
- }
- */
}
first_integration = true;
@@ -601,7 +576,7 @@ void Body3DSW::integrate_velocities(real_t p_step) {
Vector3 total_angular_velocity = angular_velocity + biased_angular_velocity;
real_t ang_vel = total_angular_velocity.length();
- Transform transform = get_transform();
+ Transform3D transform = get_transform();
if (ang_vel != 0.0) {
Vector3 ang_vel_axis = total_angular_velocity / ang_vel;
@@ -633,8 +608,8 @@ void Body3DSW::integrate_velocities(real_t p_step) {
}
/*
-void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) {
- Transform inv_xform = p_xform.affine_inverse();
+void BodySW::simulate_motion(const Transform3D& p_xform,real_t p_step) {
+ Transform3D inv_xform = p_xform.affine_inverse();
if (!get_space()) {
_set_transform(p_xform);
_set_inv_transform(inv_xform);
@@ -675,7 +650,7 @@ void Body3DSW::wakeup_neighbours() {
continue;
}
Body3DSW *b = n[i];
- if (b->mode != PhysicsServer3D::BODY_MODE_RIGID) {
+ if (b->mode != PhysicsServer3D::BODY_MODE_DYNAMIC) {
continue;
}
@@ -693,24 +668,23 @@ void Body3DSW::call_queries() {
Variant v = dbs;
- Object *obj = ObjectDB::get_instance(fi_callback->id);
+ Object *obj = fi_callback->callable.get_object();
if (!obj) {
- set_force_integration_callback(ObjectID(), StringName());
+ set_force_integration_callback(Callable());
} else {
const Variant *vp[2] = { &v, &fi_callback->udata };
Callable::CallError ce;
int argc = (fi_callback->udata.get_type() == Variant::NIL) ? 1 : 2;
- obj->call(fi_callback->method, vp, argc, ce);
+ Variant rv;
+ fi_callback->callable.call(vp, argc, rv, ce);
}
}
}
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
+ return true;
} else if (!can_sleep) {
return false;
}
@@ -725,36 +699,29 @@ bool Body3DSW::sleep_test(real_t p_step) {
}
}
-void Body3DSW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+void Body3DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
if (fi_callback) {
memdelete(fi_callback);
fi_callback = nullptr;
}
- if (p_id.is_valid()) {
+ if (p_callable.get_object()) {
fi_callback = memnew(ForceIntegrationCallback);
- fi_callback->id = p_id;
- fi_callback->method = p_method;
+ fi_callback->callable = p_callable;
fi_callback->udata = p_udata;
}
}
-void Body3DSW::set_kinematic_margin(real_t p_margin) {
- kinematic_safe_margin = p_margin;
-}
-
Body3DSW::Body3DSW() :
CollisionObject3DSW(TYPE_BODY),
active_list(this),
inertia_update_list(this),
direct_state_query_list(this) {
- mode = PhysicsServer3D::BODY_MODE_RIGID;
+ mode = PhysicsServer3D::BODY_MODE_DYNAMIC;
active = true;
mass = 1;
- kinematic_safe_margin = 0.001;
- //_inv_inertia=Transform();
_inv_mass = 1;
bounce = 0;
friction = 1;
diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h
index 5790f43019..0fa31c5037 100644
--- a/servers/physics_3d/body_3d_sw.h
+++ b/servers/physics_3d/body_3d_sw.h
@@ -55,7 +55,6 @@ class Body3DSW : public CollisionObject3DSW {
uint16_t locked_axis = 0;
- real_t kinematic_safe_margin;
real_t _inv_mass;
Vector3 _inv_inertia; // Relative to the principal axes of inertia
@@ -93,7 +92,7 @@ class Body3DSW : public CollisionObject3DSW {
bool first_time_kinematic;
void _update_inertia();
virtual void _shapes_changed();
- Transform new_transform;
+ Transform3D new_transform;
Map<Constraint3DSW *, int> constraint_map;
@@ -127,8 +126,7 @@ class Body3DSW : public CollisionObject3DSW {
int contact_count;
struct ForceIntegrationCallback {
- ObjectID id;
- StringName method;
+ Callable callable;
Variant udata;
};
@@ -143,10 +141,7 @@ class Body3DSW : public CollisionObject3DSW {
friend class PhysicsDirectBodyState3DSW; // i give up, too many functions to expose
public:
- void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
-
- void set_kinematic_margin(real_t p_margin);
- _FORCE_INLINE_ real_t get_kinematic_margin() { return kinematic_safe_margin; }
+ void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
_FORCE_INLINE_ void add_area(Area3DSW *p_area) {
int index = areas.find(AreaCMP(p_area));
@@ -312,7 +307,7 @@ public:
return p_axis.dot(_inv_inertia_tensor.xform_inv(p_axis));
}
- //void simulate_motion(const Transform& p_xform,real_t p_step);
+ //void simulate_motion(const Transform3D& p_xform,real_t p_step);
void call_queries();
void wakeup_neighbours();
@@ -391,8 +386,8 @@ public:
virtual void set_angular_velocity(const Vector3 &p_velocity) override { body->set_angular_velocity(p_velocity); }
virtual Vector3 get_angular_velocity() const override { return body->get_angular_velocity(); }
- virtual void set_transform(const Transform &p_transform) override { body->set_state(PhysicsServer3D::BODY_STATE_TRANSFORM, p_transform); }
- virtual Transform get_transform() const override { return body->get_transform(); }
+ virtual void set_transform(const Transform3D &p_transform) override { body->set_state(PhysicsServer3D::BODY_STATE_TRANSFORM, p_transform); }
+ virtual Transform3D get_transform() const override { return body->get_transform(); }
virtual void add_central_force(const Vector3 &p_force) override { body->add_central_force(p_force); }
virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override {
diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp
index 28c854466f..aed4815c5e 100644
--- a/servers/physics_3d/body_pair_3d_sw.cpp
+++ b/servers/physics_3d/body_pair_3d_sw.cpp
@@ -161,7 +161,7 @@ void BodyPair3DSW::validate_contacts() {
}
}
-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) {
+bool BodyPair3DSW::_test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform3D &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform3D &p_xform_B) {
Vector3 motion = p_A->get_linear_velocity() * p_step;
real_t mlen = motion.length();
if (mlen < CMP_EPSILON) {
@@ -184,7 +184,7 @@ bool BodyPair3DSW::_test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const
Vector3 from = p_xform_A.xform(s);
Vector3 to = from + motion;
- Transform from_inv = p_xform_B.affine_inverse();
+ Transform3D 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);
@@ -212,14 +212,16 @@ real_t combine_friction(Body3DSW *A, Body3DSW *B) {
}
bool BodyPair3DSW::setup(real_t p_step) {
- //cannot collide
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
- bool report_contacts_only = false;
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ report_contacts_only = false;
+ if (!dynamic_A && !dynamic_B) {
if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
report_contacts_only = true;
} else {
@@ -237,38 +239,48 @@ bool BodyPair3DSW::setup(real_t p_step) {
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);
+ const Vector3 &offset_A = A->get_transform().get_origin();
+ Transform3D xform_Au = Transform3D(A->get_transform().basis, Vector3());
+ Transform3D xform_A = xform_Au * A->get_shape_transform(shape_A);
- Transform xform_Bu = B->get_transform();
+ Transform3D xform_Bu = B->get_transform();
xform_Bu.origin -= offset_A;
- Transform xform_B = xform_Bu * B->get_shape_transform(shape_B);
+ Transform3D 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;
+ collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
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) {
+ if (A->is_continuous_collision_detection_enabled() && dynamic_A && !dynamic_B) {
_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) {
+ if (B->is_continuous_collision_detection_enabled() && dynamic_B && !dynamic_A) {
_test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A);
}
return false;
}
+ return true;
+}
+
+bool BodyPair3DSW::pre_solve(real_t p_step) {
+ if (!collided) {
+ return false;
+ }
+
real_t max_penetration = space->get_contact_max_allowed_penetration();
real_t bias = (real_t)0.3;
+ Shape3DSW *shape_A_ptr = A->get_shape(shape_A);
+ Shape3DSW *shape_B_ptr = B->get_shape(shape_B);
+
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();
@@ -283,22 +295,26 @@ bool BodyPair3DSW::setup(real_t p_step) {
bool do_process = false;
+ const Basis &basis_A = A->get_transform().basis;
+ const Basis &basis_B = B->get_transform().basis;
+
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);
+ Vector3 global_A = basis_A.xform(c.local_A);
+ Vector3 global_B = basis_B.xform(c.local_B) + offset_B;
- real_t depth = c.normal.dot(global_A - global_B);
+ Vector3 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
if (depth <= 0) {
continue;
}
#ifdef DEBUG_ENABLED
-
if (space->is_debugging_contacts()) {
+ const Vector3 &offset_A = A->get_transform().get_origin();
space->add_debug_contact(global_A + offset_A);
space->add_debug_contact(global_B + offset_A);
}
@@ -338,8 +354,12 @@ bool BodyPair3DSW::setup(real_t p_step) {
c.depth = depth;
Vector3 j_vec = c.normal * c.acc_normal_impulse + c.acc_tangent_impulse;
- A->apply_impulse(-j_vec, c.rA + A->get_center_of_mass());
- B->apply_impulse(j_vec, c.rB + B->get_center_of_mass());
+ if (dynamic_A) {
+ A->apply_impulse(-j_vec, c.rA + A->get_center_of_mass());
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j_vec, c.rB + B->get_center_of_mass());
+ }
c.acc_bias_impulse = 0;
c.acc_bias_impulse_center_of_mass = 0;
@@ -361,6 +381,8 @@ void BodyPair3DSW::solve(real_t p_step) {
return;
}
+ const real_t max_bias_av = MAX_BIAS_ROTATION / p_step;
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
if (!c.active) {
@@ -384,8 +406,12 @@ void BodyPair3DSW::solve(real_t p_step) {
Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld);
- A->apply_bias_impulse(-jb, c.rA + A->get_center_of_mass(), MAX_BIAS_ROTATION / p_step);
- B->apply_bias_impulse(jb, c.rB + B->get_center_of_mass(), MAX_BIAS_ROTATION / p_step);
+ if (dynamic_A) {
+ A->apply_bias_impulse(-jb, c.rA + A->get_center_of_mass(), max_bias_av);
+ }
+ if (dynamic_B) {
+ B->apply_bias_impulse(jb, c.rB + B->get_center_of_mass(), max_bias_av);
+ }
crbA = A->get_biased_angular_velocity().cross(c.rA);
crbB = B->get_biased_angular_velocity().cross(c.rB);
@@ -400,8 +426,12 @@ void BodyPair3DSW::solve(real_t p_step) {
Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com);
- A->apply_bias_impulse(-jb_com, A->get_center_of_mass(), 0.0f);
- B->apply_bias_impulse(jb_com, B->get_center_of_mass(), 0.0f);
+ if (dynamic_A) {
+ A->apply_bias_impulse(-jb_com, A->get_center_of_mass(), 0.0f);
+ }
+ if (dynamic_B) {
+ B->apply_bias_impulse(jb_com, B->get_center_of_mass(), 0.0f);
+ }
}
c.active = true;
@@ -421,8 +451,12 @@ void BodyPair3DSW::solve(real_t p_step) {
Vector3 j = c.normal * (c.acc_normal_impulse - jnOld);
- A->apply_impulse(-j, c.rA + A->get_center_of_mass());
- B->apply_impulse(j, c.rB + B->get_center_of_mass());
+ if (dynamic_A) {
+ A->apply_impulse(-j, c.rA + A->get_center_of_mass());
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, c.rB + B->get_center_of_mass());
+ }
c.active = true;
}
@@ -464,8 +498,12 @@ void BodyPair3DSW::solve(real_t p_step) {
jt = c.acc_tangent_impulse - jtOld;
- A->apply_impulse(-jt, c.rA + A->get_center_of_mass());
- B->apply_impulse(jt, c.rB + B->get_center_of_mass());
+ if (dynamic_A) {
+ A->apply_impulse(-jt, c.rA + A->get_center_of_mass());
+ }
+ if (dynamic_B) {
+ B->apply_impulse(jt, c.rB + B->get_center_of_mass());
+ }
c.active = true;
}
@@ -481,8 +519,6 @@ BodyPair3DSW::BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_sh
space = A->get_space();
A->add_constraint(this, 0);
B->add_constraint(this, 1);
- contact_count = 0;
- collided = false;
}
BodyPair3DSW::~BodyPair3DSW() {
@@ -535,7 +571,7 @@ void BodySoftBodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int
void BodySoftBodyPair3DSW::validate_contacts() {
// Make sure to erase contacts that are no longer valid.
- const Transform &transform_A = body->get_transform();
+ const Transform3D &transform_A = body->get_transform();
real_t contact_max_separation = space->get_contact_max_separation();
@@ -564,6 +600,8 @@ void BodySoftBodyPair3DSW::validate_contacts() {
}
bool BodySoftBodyPair3DSW::setup(real_t p_step) {
+ body_dynamic = (body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
if (!body->test_collision_mask(soft_body) || body->has_exception(soft_body->get_self()) || soft_body->has_exception(body->get_self())) {
collided = false;
return false;
@@ -574,23 +612,33 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
return false;
}
- const Transform &xform_Au = body->get_transform();
- Transform xform_A = xform_Au * body->get_shape_transform(body_shape);
+ const Transform3D &xform_Au = body->get_transform();
+ Transform3D xform_A = xform_Au * body->get_shape_transform(body_shape);
- Transform xform_Bu = soft_body->get_transform();
- Transform xform_B = xform_Bu * soft_body->get_shape_transform(0);
+ Transform3D xform_Bu = soft_body->get_transform();
+ Transform3D xform_B = xform_Bu * soft_body->get_shape_transform(0);
validate_contacts();
Shape3DSW *shape_A_ptr = body->get_shape(body_shape);
Shape3DSW *shape_B_ptr = soft_body->get_shape(0);
- bool collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
- this->collided = collided;
+ collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
+
+ return collided;
+}
+
+bool BodySoftBodyPair3DSW::pre_solve(real_t p_step) {
+ if (!collided) {
+ return false;
+ }
real_t max_penetration = space->get_contact_max_allowed_penetration();
real_t bias = (real_t)0.3;
+
+ Shape3DSW *shape_A_ptr = body->get_shape(body_shape);
+
if (shape_A_ptr->get_custom_bias()) {
bias = shape_A_ptr->get_custom_bias();
}
@@ -599,6 +647,8 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
bool do_process = false;
+ const Transform3D &transform_A = body->get_transform();
+
uint32_t contact_count = contacts.size();
for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
Contact &c = contacts[contact_index];
@@ -609,10 +659,10 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
continue;
}
- Vector3 global_A = xform_Au.xform(c.local_A);
+ Vector3 global_A = transform_A.xform(c.local_A);
Vector3 global_B = soft_body->get_node_position(c.index_B) + c.local_B;
-
- real_t depth = c.normal.dot(global_A - global_B);
+ Vector3 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
if (depth <= 0) {
continue;
@@ -629,7 +679,7 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
}
#endif
- c.rA = global_A - xform_Au.origin - body->get_center_of_mass();
+ c.rA = global_A - transform_A.origin - body->get_center_of_mass();
c.rB = global_B;
if (body->can_report_contacts()) {
@@ -637,7 +687,7 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
body->add_contact(global_A, -c.normal, depth, body_shape, global_B, 0, soft_body->get_instance_id(), soft_body->get_self(), crA);
}
- if (body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ if (body_dynamic) {
body->set_active(true);
}
@@ -651,7 +701,9 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
c.depth = depth;
Vector3 j_vec = c.normal * c.acc_normal_impulse + c.acc_tangent_impulse;
- body->apply_impulse(-j_vec, c.rA + body->get_center_of_mass());
+ if (body_dynamic) {
+ body->apply_impulse(-j_vec, c.rA + body->get_center_of_mass());
+ }
soft_body->apply_node_impulse(c.index_B, j_vec);
c.acc_bias_impulse = 0;
c.acc_bias_impulse_center_of_mass = 0;
@@ -675,6 +727,8 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
return;
}
+ const real_t max_bias_av = MAX_BIAS_ROTATION / p_step;
+
uint32_t contact_count = contacts.size();
for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
Contact &c = contacts[contact_index];
@@ -697,7 +751,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld);
- body->apply_bias_impulse(-jb, c.rA + body->get_center_of_mass(), MAX_BIAS_ROTATION / p_step);
+ if (body_dynamic) {
+ body->apply_bias_impulse(-jb, c.rA + body->get_center_of_mass(), max_bias_av);
+ }
soft_body->apply_node_bias_impulse(c.index_B, jb);
crbA = body->get_biased_angular_velocity().cross(c.rA);
@@ -712,7 +768,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com);
- body->apply_bias_impulse(-jb_com, body->get_center_of_mass(), 0.0f);
+ if (body_dynamic) {
+ body->apply_bias_impulse(-jb_com, body->get_center_of_mass(), 0.0f);
+ }
soft_body->apply_node_bias_impulse(c.index_B, jb_com);
}
@@ -732,7 +790,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
Vector3 j = c.normal * (c.acc_normal_impulse - jnOld);
- body->apply_impulse(-j, c.rA + body->get_center_of_mass());
+ if (body_dynamic) {
+ body->apply_impulse(-j, c.rA + body->get_center_of_mass());
+ }
soft_body->apply_node_impulse(c.index_B, j);
c.active = true;
@@ -773,7 +833,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
jt = c.acc_tangent_impulse - jtOld;
- body->apply_impulse(-jt, c.rA + body->get_center_of_mass());
+ if (body_dynamic) {
+ body->apply_impulse(-jt, c.rA + body->get_center_of_mass());
+ }
soft_body->apply_node_impulse(c.index_B, jt);
c.active = true;
@@ -781,7 +843,8 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
}
}
-BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B) {
+BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B) :
+ BodyContact3DSW(&body, 1) {
body = p_A;
soft_body = p_B;
body_shape = p_shape_A;
diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/body_pair_3d_sw.h
index 74dddfa6aa..976982d1f1 100644
--- a/servers/physics_3d/body_pair_3d_sw.h
+++ b/servers/physics_3d/body_pair_3d_sw.h
@@ -57,9 +57,9 @@ protected:
};
Vector3 sep_axis;
- bool collided;
+ bool collided = false;
- Space3DSW *space;
+ Space3DSW *space = nullptr;
BodyContact3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) :
Constraint3DSW(p_body_ptr, p_body_count) {
@@ -77,37 +77,45 @@ class BodyPair3DSW : public BodyContact3DSW {
Body3DSW *B;
};
- Body3DSW *_arr[2];
+ Body3DSW *_arr[2] = { nullptr, nullptr };
};
- int shape_A;
- int shape_B;
+ int shape_A = 0;
+ int shape_B = 0;
+
+ bool dynamic_A = false;
+ bool dynamic_B = false;
+
+ bool report_contacts_only = false;
Vector3 offset_B; //use local A coordinates to avoid numerical issues on collision detection
Contact contacts[MAX_CONTACTS];
- int contact_count;
+ int contact_count = 0;
static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B);
void validate_contacts();
- bool _test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform &p_xform_B);
+ bool _test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform3D &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform3D &p_xform_B);
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_shape_B);
~BodyPair3DSW();
};
class BodySoftBodyPair3DSW : public BodyContact3DSW {
- Body3DSW *body;
- SoftBody3DSW *soft_body;
+ Body3DSW *body = nullptr;
+ SoftBody3DSW *soft_body = nullptr;
- int body_shape;
+ int body_shape = 0;
+
+ bool body_dynamic = false;
LocalVector<Contact> contacts;
@@ -118,8 +126,12 @@ class BodySoftBodyPair3DSW : public BodyContact3DSW {
void validate_contacts();
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
+
+ virtual SoftBody3DSW *get_soft_body_ptr(int p_index) const override { return soft_body; }
+ virtual int get_soft_body_count() const override { return 1; }
BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B);
~BodySoftBodyPair3DSW();
diff --git a/servers/physics_3d/broad_phase_3d_basic.cpp b/servers/physics_3d/broad_phase_3d_basic.cpp
deleted file mode 100644
index b41c2530da..0000000000
--- a/servers/physics_3d/broad_phase_3d_basic.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/*************************************************************************/
-/* broad_phase_3d_basic.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "broad_phase_3d_basic.h"
-#include "core/string/print_string.h"
-#include "core/templates/list.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);
- if (data) {
- 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_octree.cpp b/servers/physics_3d/broad_phase_3d_bvh.cpp
index 11324fa4e4..f9f64f786d 100644
--- a/servers/physics_3d/broad_phase_octree.cpp
+++ b/servers/physics_3d/broad_phase_3d_bvh.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* broad_phase_octree.cpp */
+/* broad_phase_3d_bvh.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,55 +28,55 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "broad_phase_octree.h"
+#include "broad_phase_3d_bvh.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;
+BroadPhase3DBVH::ID BroadPhase3DBVH::create(CollisionObject3DSW *p_object, int p_subindex, const AABB &p_aabb, bool p_static) {
+ ID oid = bvh.create(p_object, true, p_aabb, p_subindex, !p_static, 1 << p_object->get_type(), p_static ? 0 : 0xFFFFF); // Pair everything, don't care?
+ return oid + 1;
}
-void BroadPhaseOctree::move(ID p_id, const AABB &p_aabb) {
- octree.move(p_id, p_aabb);
+void BroadPhase3DBVH::move(ID p_id, const AABB &p_aabb) {
+ bvh.move(p_id - 1, 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 BroadPhase3DBVH::set_static(ID p_id, bool p_static) {
+ CollisionObject3DSW *it = bvh.get(p_id - 1);
+ bvh.set_pairable(p_id - 1, !p_static, 1 << it->get_type(), p_static ? 0 : 0xFFFFF, false); // Pair everything, don't care?
}
-void BroadPhaseOctree::remove(ID p_id) {
- octree.erase(p_id);
+void BroadPhase3DBVH::remove(ID p_id) {
+ bvh.erase(p_id - 1);
}
-CollisionObject3DSW *BroadPhaseOctree::get_object(ID p_id) const {
- CollisionObject3DSW *it = octree.get(p_id);
+CollisionObject3DSW *BroadPhase3DBVH::get_object(ID p_id) const {
+ CollisionObject3DSW *it = bvh.get(p_id - 1);
ERR_FAIL_COND_V(!it, nullptr);
return it;
}
-bool BroadPhaseOctree::is_static(ID p_id) const {
- return !octree.is_pairable(p_id);
+bool BroadPhase3DBVH::is_static(ID p_id) const {
+ return !bvh.is_pairable(p_id - 1);
}
-int BroadPhaseOctree::get_subindex(ID p_id) const {
- return octree.get_subindex(p_id);
+int BroadPhase3DBVH::get_subindex(ID p_id) const {
+ return bvh.get_subindex(p_id - 1);
}
-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 BroadPhase3DBVH::cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) {
+ return bvh.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 BroadPhase3DBVH::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) {
+ return bvh.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);
+int BroadPhase3DBVH::cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) {
+ return bvh.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);
+void *BroadPhase3DBVH::_pair_callback(void *self, uint32_t p_A, CollisionObject3DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject3DSW *p_object_B, int subindex_B) {
+ BroadPhase3DBVH *bpo = (BroadPhase3DBVH *)(self);
if (!bpo->pair_callback) {
return nullptr;
}
@@ -84,8 +84,8 @@ void *BroadPhaseOctree::_pair_callback(void *self, OctreeElementID p_A, Collisio
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);
+void BroadPhase3DBVH::_unpair_callback(void *self, uint32_t p_A, CollisionObject3DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject3DSW *p_object_B, int subindex_B, void *pairdata) {
+ BroadPhase3DBVH *bpo = (BroadPhase3DBVH *)(self);
if (!bpo->unpair_callback) {
return;
}
@@ -93,27 +93,27 @@ void BroadPhaseOctree::_unpair_callback(void *self, OctreeElementID p_A, Collisi
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) {
+void BroadPhase3DBVH::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) {
+void BroadPhase3DBVH::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
unpair_callback = p_unpair_callback;
unpair_userdata = p_userdata;
}
-void BroadPhaseOctree::update() {
- // does.. not?
+void BroadPhase3DBVH::update() {
+ bvh.update();
}
-BroadPhase3DSW *BroadPhaseOctree::_create() {
- return memnew(BroadPhaseOctree);
+BroadPhase3DSW *BroadPhase3DBVH::_create() {
+ return memnew(BroadPhase3DBVH);
}
-BroadPhaseOctree::BroadPhaseOctree() {
- octree.set_pair_callback(_pair_callback, this);
- octree.set_unpair_callback(_unpair_callback, this);
+BroadPhase3DBVH::BroadPhase3DBVH() {
+ bvh.set_pair_callback(_pair_callback, this);
+ bvh.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_3d_bvh.h
index ee681dda96..30b8b7f2aa 100644
--- a/servers/physics_3d/broad_phase_octree.h
+++ b/servers/physics_3d/broad_phase_3d_bvh.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* broad_phase_octree.h */
+/* broad_phase_3d_bvh.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,17 +28,17 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef BROAD_PHASE_OCTREE_H
-#define BROAD_PHASE_OCTREE_H
+#ifndef BROAD_PHASE_3D_BVH_H
+#define BROAD_PHASE_3D_BVH_H
#include "broad_phase_3d_sw.h"
-#include "core/math/octree.h"
+#include "core/math/bvh.h"
-class BroadPhaseOctree : public BroadPhase3DSW {
- Octree<CollisionObject3DSW, true> octree;
+class BroadPhase3DBVH : public BroadPhase3DSW {
+ BVH_Manager<CollisionObject3DSW, true, 128> bvh;
- static void *_pair_callback(void *, OctreeElementID, CollisionObject3DSW *, int, OctreeElementID, CollisionObject3DSW *, int);
- static void _unpair_callback(void *, OctreeElementID, CollisionObject3DSW *, int, OctreeElementID, CollisionObject3DSW *, int, void *);
+ static void *_pair_callback(void *, uint32_t, CollisionObject3DSW *, int, uint32_t, CollisionObject3DSW *, int);
+ static void _unpair_callback(void *, uint32_t, CollisionObject3DSW *, int, uint32_t, CollisionObject3DSW *, int, void *);
PairCallback pair_callback;
void *pair_userdata;
@@ -47,7 +47,7 @@ class BroadPhaseOctree : public BroadPhase3DSW {
public:
// 0 is an invalid ID
- virtual ID create(CollisionObject3DSW *p_object, int p_subindex = 0);
+ virtual ID create(CollisionObject3DSW *p_object, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false);
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);
@@ -66,7 +66,7 @@ public:
virtual void update();
static BroadPhase3DSW *_create();
- BroadPhaseOctree();
+ BroadPhase3DBVH();
};
-#endif // BROAD_PHASE_OCTREE_H
+#endif // BROAD_PHASE_3D_BVH_H
diff --git a/servers/physics_3d/broad_phase_3d_sw.h b/servers/physics_3d/broad_phase_3d_sw.h
index 283c087b96..98313cb216 100644
--- a/servers/physics_3d/broad_phase_3d_sw.h
+++ b/servers/physics_3d/broad_phase_3d_sw.h
@@ -48,7 +48,7 @@ public:
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 ID create(CollisionObject3DSW *p_object_, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false) = 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;
diff --git a/servers/physics_3d/collision_object_3d_sw.cpp b/servers/physics_3d/collision_object_3d_sw.cpp
index 293a7e6606..51e2432071 100644
--- a/servers/physics_3d/collision_object_3d_sw.cpp
+++ b/servers/physics_3d/collision_object_3d_sw.cpp
@@ -32,7 +32,7 @@
#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) {
+void CollisionObject3DSW::add_shape(Shape3DSW *p_shape, const Transform3D &p_transform, bool p_disabled) {
Shape s;
s.shape = p_shape;
s.xform = p_transform;
@@ -62,7 +62,7 @@ void CollisionObject3DSW::set_shape(int p_index, Shape3DSW *p_shape) {
//_shapes_changed();
}
-void CollisionObject3DSW::set_shape_transform(int p_index, const Transform &p_transform) {
+void CollisionObject3DSW::set_shape_transform(int p_index, const Transform3D &p_transform) {
ERR_FAIL_INDEX(p_index, shapes.size());
shapes.write[p_index].xform = p_transform;
@@ -146,22 +146,23 @@ void CollisionObject3DSW::_update_shapes() {
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;
+ Transform3D xform = transform * s.xform;
shape_aabb = xform.xform(shape_aabb);
+ shape_aabb.grow_by((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05);
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);
+ if (s.bpid == 0) {
+ s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static);
+ space->get_broadphase()->set_static(s.bpid, _static);
+ }
+
+ space->get_broadphase()->move(s.bpid, shape_aabb);
}
}
@@ -172,18 +173,19 @@ void CollisionObject3DSW::_update_shapes_with_motion(const Vector3 &p_motion) {
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;
+ Transform3D 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
+ shape_aabb.merge_with(AABB(shape_aabb.position + p_motion, shape_aabb.size)); //use motion
s.aabb_cache = shape_aabb;
+ if (s.bpid == 0) {
+ s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static);
+ space->get_broadphase()->set_static(s.bpid, _static);
+ }
+
space->get_broadphase()->move(s.bpid, shape_aabb);
}
}
diff --git a/servers/physics_3d/collision_object_3d_sw.h b/servers/physics_3d/collision_object_3d_sw.h
index 85221b7746..5505fec3da 100644
--- a/servers/physics_3d/collision_object_3d_sw.h
+++ b/servers/physics_3d/collision_object_3d_sw.h
@@ -60,8 +60,8 @@ private:
uint32_t collision_mask;
struct Shape {
- Transform xform;
- Transform xform_inv;
+ Transform3D xform;
+ Transform3D xform_inv;
BroadPhase3DSW::ID bpid;
AABB aabb_cache; //for rayqueries
real_t area_cache;
@@ -73,8 +73,8 @@ private:
Vector<Shape> shapes;
Space3DSW *space;
- Transform transform;
- Transform inv_transform;
+ Transform3D transform;
+ Transform3D inv_transform;
bool _static;
SelfList<CollisionObject3DSW> pending_shape_update_list;
@@ -85,7 +85,7 @@ 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) {
+ _FORCE_INLINE_ void _set_transform(const Transform3D &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).");
@@ -96,7 +96,7 @@ protected:
_update_shapes();
}
}
- _FORCE_INLINE_ void _set_inv_transform(const Transform &p_transform) { inv_transform = p_transform; }
+ _FORCE_INLINE_ void _set_inv_transform(const Transform3D &p_transform) { inv_transform = p_transform; }
void _set_static(bool p_static);
virtual void _shapes_changed() = 0;
@@ -116,22 +116,22 @@ public:
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 add_shape(Shape3DSW *p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false);
void set_shape(int p_index, Shape3DSW *p_shape);
- void set_shape_transform(int p_index, const Transform &p_transform);
+ void set_shape_transform(int p_index, const Transform3D &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 Transform3D &get_shape_transform(int p_index) const { return shapes[p_index].xform; }
+ _FORCE_INLINE_ const Transform3D &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_ const Transform &get_transform() const { return transform; }
- _FORCE_INLINE_ const Transform &get_inv_transform() const { return inv_transform; }
+ _FORCE_INLINE_ const Transform3D &get_transform() const { return transform; }
+ _FORCE_INLINE_ const Transform3D &get_inv_transform() const { return inv_transform; }
_FORCE_INLINE_ Space3DSW *get_space() const { return space; }
_FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; }
diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp
index 9d5448dbfa..b362f1ff17 100644
--- a/servers/physics_3d/collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/collision_solver_3d_sat.cpp
@@ -608,8 +608,8 @@ 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;
+ const Transform3D *transform_A;
+ const Transform3D *transform_B;
real_t best_depth;
Vector3 best_axis;
_CollectorCallback *callback;
@@ -690,7 +690,7 @@ public:
Vector3 axis = (p_point_B - p_point_A);
real_t depth = axis.length();
- // Filter out bogus directions with a treshold and re-testing axis.
+ // Filter out bogus directions with a threshold and re-testing axis.
if (separator->best_depth - depth > 0.001) {
separator->test_axis(axis / depth);
}
@@ -750,7 +750,7 @@ public:
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) {
+ _FORCE_INLINE_ SeparatorAxisTest(const ShapeA *p_shape_A, const Transform3D &p_transform_A, const ShapeB *p_shape_B, const Transform3D &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;
@@ -764,10 +764,10 @@ public:
/****** SAT TESTS *******/
-typedef void (*CollisionFunc)(const Shape3DSW *, const Transform &, const Shape3DSW *, const Transform &, _CollectorCallback *p_callback, real_t, real_t);
+typedef void (*CollisionFunc)(const Shape3DSW *, const Transform3D &, const Shape3DSW *, const Transform3D &, _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) {
+static void _collision_sphere_sphere(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -787,7 +787,7 @@ static void _collision_sphere_sphere(const Shape3DSW *p_a, const Transform &p_tr
}
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) {
+static void _collision_sphere_box(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -838,7 +838,7 @@ static void _collision_sphere_box(const Shape3DSW *p_a, const Transform &p_trans
}
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) {
+static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -880,7 +880,7 @@ static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform &p_t
}
template <bool withMargin>
-static void _collision_sphere_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+static void _collision_sphere_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a);
const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b);
@@ -939,7 +939,7 @@ static void _collision_sphere_cylinder(const Shape3DSW *p_a, const Transform &p_
}
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) {
+static void _collision_sphere_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -999,7 +999,7 @@ static void _collision_sphere_convex_polygon(const Shape3DSW *p_a, const Transfo
}
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) {
+static void _collision_sphere_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -1044,7 +1044,7 @@ static void _collision_sphere_face(const Shape3DSW *p_a, const Transform &p_tran
}
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) {
+static void _collision_box_box(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -1142,7 +1142,7 @@ static void _collision_box_box(const Shape3DSW *p_a, const Transform &p_transfor
}
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) {
+static void _collision_box_capsule(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -1240,7 +1240,7 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran
}
template <bool withMargin>
-static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a);
const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b);
@@ -1353,7 +1353,7 @@ static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform &p_tra
}
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) {
+static void _collision_box_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -1468,7 +1468,7 @@ static void _collision_box_convex_polygon(const Shape3DSW *p_a, const Transform
}
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) {
+static void _collision_box_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -1591,7 +1591,7 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
}
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) {
+static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -1655,7 +1655,7 @@ static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform &p_
}
template <bool withMargin>
-static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a);
const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b);
@@ -1717,7 +1717,7 @@ static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform &p
}
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) {
+static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -1781,7 +1781,7 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf
}
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) {
+static void _collision_capsule_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -1855,7 +1855,7 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
}
template <bool withMargin>
-static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
+static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a);
const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b);
@@ -1909,7 +1909,7 @@ static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform &
}
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) {
+static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a);
const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b);
@@ -1926,7 +1926,7 @@ static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Trans
}
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) {
+static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a);
const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b);
@@ -2031,7 +2031,7 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
}
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) {
+static void _collision_convex_polygon_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -2140,7 +2140,7 @@ static void _collision_convex_polygon_convex_polygon(const Shape3DSW *p_a, const
}
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) {
+static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &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);
@@ -2258,7 +2258,7 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
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) {
+bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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);
@@ -2358,8 +2358,8 @@ bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_tr
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;
+ const Transform3D *transform_A = &p_transform_A;
+ const Transform3D *transform_B = &p_transform_B;
real_t margin_A = p_margin_a;
real_t margin_B = p_margin_b;
diff --git a/servers/physics_3d/collision_solver_3d_sat.h b/servers/physics_3d/collision_solver_3d_sat.h
index 97454c0b4a..e50da7b101 100644
--- a/servers/physics_3d/collision_solver_3d_sat.h
+++ b/servers/physics_3d/collision_solver_3d_sat.h
@@ -33,6 +33,6 @@
#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);
+bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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
index f655c4626c..67330d497e 100644
--- a/servers/physics_3d/collision_solver_3d_sw.cpp
+++ b/servers/physics_3d/collision_solver_3d_sw.cpp
@@ -37,7 +37,7 @@
#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) {
+bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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;
@@ -89,14 +89,14 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T
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) {
+bool CollisionSolver3DSW::solve_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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();
+ Transform3D ai = p_transform_B.affine_inverse();
from = ai.xform(from);
to = ai.xform(to);
@@ -146,8 +146,8 @@ struct _SoftBodyQueryInfo {
SoftBody3DSW *soft_body = nullptr;
const Shape3DSW *shape_A = nullptr;
const Shape3DSW *shape_B = nullptr;
- Transform transform_A;
- Transform node_transform;
+ Transform3D transform_A;
+ Transform3D node_transform;
_SoftBodyContactCollisionInfo contact_info;
#ifdef DEBUG_ENABLED
int node_query_count = 0;
@@ -160,7 +160,7 @@ bool CollisionSolver3DSW::soft_body_query_callback(uint32_t p_node_index, void *
Vector3 node_position = query_cinfo.soft_body->get_node_position(p_node_index);
- Transform transform_B;
+ Transform3D transform_B;
transform_B.origin = query_cinfo.node_transform.xform(node_position);
query_cinfo.contact_info.node_index = p_node_index;
@@ -201,11 +201,11 @@ void CollisionSolver3DSW::soft_body_concave_callback(void *p_userdata, Shape3DSW
#endif
}
-bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
+bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
const SoftBodyShape3DSW *soft_body_shape_B = static_cast<const SoftBodyShape3DSW *>(p_shape_B);
SoftBody3DSW *soft_body = soft_body_shape_B->get_soft_body();
- const Transform &world_to_local = soft_body->get_inv_transform();
+ const Transform3D &world_to_local = soft_body->get_inv_transform();
const real_t collision_margin = soft_body->get_collision_margin();
@@ -257,9 +257,9 @@ bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Tran
}
struct _ConcaveCollisionInfo {
- const Transform *transform_A;
+ const Transform3D *transform_A;
const Shape3DSW *shape_A;
- const Transform *transform_B;
+ const Transform3D *transform_B;
CollisionSolver3DSW::CallbackResult result_callback;
void *userdata;
bool swap_result;
@@ -285,7 +285,7 @@ void CollisionSolver3DSW::concave_callback(void *p_userdata, Shape3DSW *p_convex
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) {
+bool CollisionSolver3DSW::solve_concave(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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;
@@ -302,7 +302,7 @@ bool CollisionSolver3DSW::solve_concave(const Shape3DSW *p_shape_A, const Transf
cinfo.aabb_tests = 0;
- Transform rel_transform = p_transform_A;
+ Transform3D rel_transform = p_transform_A;
rel_transform.origin -= p_transform_B.origin;
//quickly compute a local AABB
@@ -329,7 +329,7 @@ bool CollisionSolver3DSW::solve_concave(const Shape3DSW *p_shape_A, const Transf
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) {
+bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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();
@@ -421,7 +421,7 @@ void CollisionSolver3DSW::concave_distance_callback(void *p_userdata, Shape3DSW
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) {
+bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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;
@@ -473,7 +473,7 @@ bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const
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) {
+bool CollisionSolver3DSW::solve_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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;
}
@@ -504,7 +504,7 @@ bool CollisionSolver3DSW::solve_distance(const Shape3DSW *p_shape_A, const Trans
cinfo.aabb_tests = 0;
cinfo.tested = false;
- Transform rel_transform = p_transform_A;
+ Transform3D rel_transform = p_transform_A;
rel_transform.origin -= p_transform_B.origin;
//quickly compute a local AABB
diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/collision_solver_3d_sw.h
index 34ac2c6d3f..a5dd7d48eb 100644
--- a/servers/physics_3d/collision_solver_3d_sw.h
+++ b/servers/physics_3d/collision_solver_3d_sw.h
@@ -42,16 +42,16 @@ private:
static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
static void soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex);
static void concave_callback(void *p_userdata, Shape3DSW *p_convex);
- static bool solve_static_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
- static bool solve_ray(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
- static bool solve_soft_body(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
- static bool solve_concave(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0);
+ static bool solve_static_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_soft_body(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_concave(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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);
+ static bool solve_distance_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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);
+ static bool solve_static(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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 Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &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
index 16a31e167d..7b44726ef5 100644
--- a/servers/physics_3d/constraint_3d_sw.h
+++ b/servers/physics_3d/constraint_3d_sw.h
@@ -31,7 +31,8 @@
#ifndef CONSTRAINT_SW_H
#define CONSTRAINT_SW_H
-#include "body_3d_sw.h"
+class Body3DSW;
+class SoftBody3DSW;
class Constraint3DSW {
Body3DSW **_body_ptr;
@@ -61,6 +62,9 @@ public:
_FORCE_INLINE_ Body3DSW **get_body_ptr() const { return _body_ptr; }
_FORCE_INLINE_ int get_body_count() const { return _body_count; }
+ virtual SoftBody3DSW *get_soft_body_ptr(int p_index) const { return nullptr; }
+ virtual int get_soft_body_count() const { return 0; }
+
_FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; }
_FORCE_INLINE_ int get_priority() const { return priority; }
@@ -68,6 +72,7 @@ public:
_FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; }
virtual bool setup(real_t p_step) = 0;
+ virtual bool pre_solve(real_t p_step) = 0;
virtual void solve(real_t p_step) = 0;
virtual ~Constraint3DSW() {}
diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp
index 1a8c7f704f..2df991563d 100644
--- a/servers/physics_3d/gjk_epa.cpp
+++ b/servers/physics_3d/gjk_epa.cpp
@@ -107,16 +107,16 @@ typedef unsigned char U1;
struct MinkowskiDiff {
const Shape3DSW* m_shapes[2];
- Transform transform_A;
- Transform transform_B;
+ Transform3D transform_A;
+ Transform3D transform_B;
real_t margin_A = 0.0;
real_t margin_B = 0.0;
Vector3 (*get_support)(const Shape3DSW*, const Vector3&, real_t);
- void Initialize(const Shape3DSW* shape0, const Transform& wtrs0, const real_t margin0,
- const Shape3DSW* shape1, const Transform& wtrs1, const real_t margin1) {
+ void Initialize(const Shape3DSW* shape0, const Transform3D& wtrs0, const real_t margin0,
+ const Shape3DSW* shape1, const Transform3D& wtrs1, const real_t margin1) {
m_shapes[0] = shape0;
m_shapes[1] = shape1;
transform_A = wtrs0;
@@ -862,8 +862,8 @@ struct GJK
};
//
- static void Initialize( const Shape3DSW* shape0, const Transform& wtrs0, real_t margin0,
- const Shape3DSW* shape1, const Transform& wtrs1, real_t margin1,
+ static void Initialize( const Shape3DSW* shape0, const Transform3D& wtrs0, real_t margin0,
+ const Shape3DSW* shape1, const Transform3D& wtrs1, real_t margin1,
sResults& results,
tShape& shape)
{
@@ -885,10 +885,10 @@ struct GJK
//
bool Distance( const Shape3DSW* shape0,
- const Transform& wtrs0,
+ const Transform3D& wtrs0,
real_t margin0,
const Shape3DSW* shape1,
- const Transform& wtrs1,
+ const Transform3D& wtrs1,
real_t margin1,
const Vector3& guess,
sResults& results)
@@ -926,10 +926,10 @@ bool Distance( const Shape3DSW* shape0,
//
bool Penetration( const Shape3DSW* shape0,
- const Transform& wtrs0,
+ const Transform3D& wtrs0,
real_t margin0,
const Shape3DSW* shape1,
- const Transform& wtrs1,
+ const Transform3D& wtrs1,
real_t margin1,
const Vector3& guess,
sResults& results
@@ -993,7 +993,7 @@ bool Penetration( const Shape3DSW* shape0,
/* 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) {
+bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B) {
GjkEpa2::sResults res;
if (GjkEpa2::Distance(p_shape_A, p_transform_A, 0.0, p_shape_B, p_transform_B, 0.0, p_transform_B.origin - p_transform_A.origin, res)) {
@@ -1005,7 +1005,7 @@ bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_t
return false;
}
-bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, real_t p_margin_A, real_t p_margin_B) {
+bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, real_t p_margin_A, real_t p_margin_B) {
GjkEpa2::sResults res;
if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_margin_A, p_shape_B, p_transform_B, p_margin_B, p_transform_B.origin - p_transform_A.origin, res)) {
diff --git a/servers/physics_3d/gjk_epa.h b/servers/physics_3d/gjk_epa.h
index a7e2e1719e..69e85d2bc0 100644
--- a/servers/physics_3d/gjk_epa.h
+++ b/servers/physics_3d/gjk_epa.h
@@ -34,7 +34,7 @@
#include "collision_solver_3d_sw.h"
#include "shape_3d_sw.h"
-bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, real_t p_margin_A = 0.0, real_t p_margin_B = 0.0);
-bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B);
+bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, real_t p_margin_A = 0.0, real_t p_margin_B = 0.0);
+bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B);
#endif
diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
index 167f797bfe..7315e9c709 100644
--- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
@@ -84,7 +84,7 @@ static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) {
return (y < 0.0f) ? -angle : angle;
}
-ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &rbAFrame, const Transform &rbBFrame) :
+ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame) :
Joint3DSW(_arr, 2) {
A = rbA;
B = rbB;
@@ -109,7 +109,10 @@ ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Trans
}
bool ConeTwistJoint3DSW::setup(real_t p_timestep) {
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -208,7 +211,7 @@ bool ConeTwistJoint3DSW::setup(real_t p_timestep) {
// 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);
+ Quaternion rotationArc = Quaternion(b2Axis1, b1Axis1);
Vector3 TwistRef = rotationArc.xform(b2Axis22);
real_t twist = atan2fast(TwistRef.dot(b1Axis3), TwistRef.dot(b1Axis2));
@@ -265,8 +268,12 @@ void ConeTwistJoint3DSW::solve(real_t p_timestep) {
real_t impulse = depth * tau / p_timestep * jacDiagABInv - rel_vel * jacDiagABInv;
m_appliedImpulse += impulse;
Vector3 impulse_vector = normal * impulse;
- A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
- B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ if (dynamic_A) {
+ A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ }
}
}
@@ -287,8 +294,12 @@ void ConeTwistJoint3DSW::solve(real_t p_timestep) {
Vector3 impulse = m_swingAxis * impulseMag;
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
+ if (dynamic_A) {
+ A->apply_torque_impulse(impulse);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-impulse);
+ }
}
// solve twist limit
@@ -303,8 +314,12 @@ void ConeTwistJoint3DSW::solve(real_t p_timestep) {
Vector3 impulse = m_twistAxis * impulseMag;
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
+ if (dynamic_A) {
+ A->apply_torque_impulse(impulse);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-impulse);
+ }
}
}
}
diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
index 4e4d4e7f0c..608847352c 100644
--- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
+++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
@@ -73,8 +73,8 @@ public:
JacobianEntry3DSW m_jac[3]; //3 orthogonal linear constraints
real_t m_appliedImpulse;
- Transform m_rbAFrame;
- Transform m_rbBFrame;
+ Transform3D m_rbAFrame;
+ Transform3D m_rbBFrame;
real_t m_limitSoftness;
real_t m_biasFactor;
@@ -102,12 +102,12 @@ public:
bool m_solveSwingLimit;
public:
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_CONE_TWIST; }
+ virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_CONE_TWIST; }
- virtual bool setup(real_t p_timestep);
- virtual void solve(real_t p_timestep);
+ virtual bool setup(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
- ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &rbAFrame, const Transform &rbBFrame);
+ ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame);
void setAngularOnly(bool angularOnly) {
m_angularOnly = angularOnly;
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
index a86e8b4e76..56aba24b42 100644
--- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
@@ -82,7 +82,7 @@ int G6DOFRotationalLimitMotor3DSW::testLimitValue(real_t test_value) {
real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits(
real_t timeStep, Vector3 &axis, real_t jacDiagABInv,
- Body3DSW *body0, Body3DSW *body1) {
+ Body3DSW *body0, Body3DSW *body1, bool p_body0_dynamic, bool p_body1_dynamic) {
if (!needApplyTorques()) {
return 0.0f;
}
@@ -138,8 +138,10 @@ real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits(
Vector3 motorImp = clippedMotorImpulse * axis;
- body0->apply_torque_impulse(motorImp);
- if (body1) {
+ if (p_body0_dynamic) {
+ body0->apply_torque_impulse(motorImp);
+ }
+ if (body1 && p_body1_dynamic) {
body1->apply_torque_impulse(-motorImp);
}
@@ -154,6 +156,7 @@ real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis(
real_t jacDiagABInv,
Body3DSW *body1, const Vector3 &pointInA,
Body3DSW *body2, const Vector3 &pointInB,
+ bool p_body1_dynamic, bool p_body2_dynamic,
int limit_index,
const Vector3 &axis_normal_on_a,
const Vector3 &anchorPos) {
@@ -205,14 +208,18 @@ real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis(
normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
Vector3 impulse_vector = axis_normal_on_a * normalImpulse;
- body1->apply_impulse(impulse_vector, rel_pos1);
- body2->apply_impulse(-impulse_vector, rel_pos2);
+ if (p_body1_dynamic) {
+ body1->apply_impulse(impulse_vector, rel_pos1);
+ }
+ if (p_body2_dynamic) {
+ body2->apply_impulse(-impulse_vector, rel_pos2);
+ }
return normalImpulse;
}
//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
-Generic6DOFJoint3DSW::Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA) :
+Generic6DOFJoint3DSW::Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB, bool useLinearReferenceFrameA) :
Joint3DSW(_arr, 2),
m_frameInA(frameInA),
m_frameInB(frameInB),
@@ -303,7 +310,10 @@ bool Generic6DOFJoint3DSW::testAngularLimitMotor(int axis_index) {
}
bool Generic6DOFJoint3DSW::setup(real_t p_timestep) {
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -384,6 +394,7 @@ void Generic6DOFJoint3DSW::solve(real_t p_timestep) {
jacDiagABInv,
A, pointInA,
B, pointInB,
+ dynamic_A, dynamic_B,
i, linear_axis, m_AnchorPos);
}
}
@@ -398,7 +409,7 @@ void Generic6DOFJoint3DSW::solve(real_t p_timestep) {
angularJacDiagABInv = real_t(1.) / m_jacAng[i].getDiagonal();
- m_angularLimits[i].solveAngularLimits(m_timeStep, angular_axis, angularJacDiagABInv, A, B);
+ m_angularLimits[i].solveAngularLimits(m_timeStep, angular_axis, angularJacDiagABInv, A, B, dynamic_A, dynamic_B);
}
}
}
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
index d61a033231..d46437e782 100644
--- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
@@ -81,7 +81,7 @@ public:
//! temp_variables
//!@{
- real_t m_currentLimitError; //! How much is violated this limit
+ 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;
//!@}
@@ -113,14 +113,14 @@ public:
return (m_enableMotor || m_currentLimit != 0);
}
- //! calculates error
+ //! 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);
+ real_t solveAngularLimits(real_t timeStep, Vector3 &axis, real_t jacDiagABInv, Body3DSW *body0, Body3DSW *body1, bool p_body0_dynamic, bool p_body1_dynamic);
};
class G6DOFTranslationalLimitMotor3DSW {
@@ -166,6 +166,7 @@ public:
real_t jacDiagABInv,
Body3DSW *body1, const Vector3 &pointInA,
Body3DSW *body2, const Vector3 &pointInB,
+ bool p_body1_dynamic, bool p_body2_dynamic,
int limit_index,
const Vector3 &axis_normal_on_a,
const Vector3 &anchorPos);
@@ -184,8 +185,8 @@ protected:
//! relative_frames
//!@{
- Transform m_frameInA; //!< the constraint space w.r.t body A
- Transform m_frameInB; //!< the constraint space w.r.t body B
+ Transform3D m_frameInA; //!< the constraint space w.r.t body A
+ Transform3D m_frameInB; //!< the constraint space w.r.t body B
//!@}
//! Jacobians
@@ -208,8 +209,8 @@ protected:
//! temporal variables
//!@{
real_t m_timeStep;
- Transform m_calculatedTransformA;
- Transform m_calculatedTransformB;
+ Transform3D m_calculatedTransformA;
+ Transform3D m_calculatedTransformB;
Vector3 m_calculatedAxisAngleDiff;
Vector3 m_calculatedAxis[3];
@@ -232,12 +233,12 @@ protected:
void calculateAngleInfo();
public:
- Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA);
+ Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB, bool useLinearReferenceFrameA);
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_6DOF; }
+ virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_6DOF; }
- virtual bool setup(real_t p_timestep);
- virtual void solve(real_t p_timestep);
+ virtual bool setup(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
//! Calcs global transform of the offsets
/*!
@@ -250,7 +251,7 @@ public:
/*!
\sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo.
*/
- const Transform &getCalculatedTransformA() const {
+ const Transform3D &getCalculatedTransformA() const {
return m_calculatedTransformA;
}
@@ -258,23 +259,23 @@ public:
/*!
\sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo.
*/
- const Transform &getCalculatedTransformB() const {
+ const Transform3D &getCalculatedTransformB() const {
return m_calculatedTransformB;
}
- const Transform &getFrameOffsetA() const {
+ const Transform3D &getFrameOffsetA() const {
return m_frameInA;
}
- const Transform &getFrameOffsetB() const {
+ const Transform3D &getFrameOffsetB() const {
return m_frameInB;
}
- Transform &getFrameOffsetA() {
+ Transform3D &getFrameOffsetA() {
return m_frameInA;
}
- Transform &getFrameOffsetB() {
+ Transform3D &getFrameOffsetB() {
return m_frameInB;
}
@@ -326,7 +327,7 @@ public:
return &m_angularLimits[index];
}
- //! Retrieves the limit informacion
+ //! Retrieves the limit informacion
G6DOFTranslationalLimitMotor3DSW *getTranslationalLimitMotor() {
return &m_linearLimits;
}
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
index 90b82f4680..b928f18231 100644
--- a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
@@ -67,7 +67,7 @@ static void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) {
}
}
-HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameA, const Transform &frameB) :
+HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameA, const Transform3D &frameB) :
Joint3DSW(_arr, 2) {
A = rbA;
B = rbB;
@@ -126,7 +126,7 @@ HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivo
rbAxisA1.y, rbAxisA2.y, axisInA.y,
rbAxisA1.z, rbAxisA2.z, axisInA.z);
- Quat rotationArc = Quat(axisInA, axisInB);
+ Quaternion rotationArc = Quaternion(axisInA, axisInB);
Vector3 rbAxisB1 = rotationArc.xform(rbAxisA1);
Vector3 rbAxisB2 = axisInB.cross(rbAxisB1);
@@ -155,7 +155,10 @@ HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivo
}
bool HingeJoint3DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -279,8 +282,12 @@ void HingeJoint3DSW::solve(real_t p_step) {
real_t impulse = depth * tau / p_step * jacDiagABInv - rel_vel * jacDiagABInv;
m_appliedImpulse += impulse;
Vector3 impulse_vector = normal * impulse;
- A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
- B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ if (dynamic_A) {
+ A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ }
}
}
@@ -322,8 +329,12 @@ void HingeJoint3DSW::solve(real_t p_step) {
angularError *= (real_t(1.) / denom2) * relaxation;
}
- A->apply_torque_impulse(-velrelOrthog + angularError);
- B->apply_torque_impulse(velrelOrthog - angularError);
+ if (dynamic_A) {
+ A->apply_torque_impulse(-velrelOrthog + angularError);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(velrelOrthog - angularError);
+ }
// solve limit
if (m_solveLimit) {
@@ -337,8 +348,12 @@ void HingeJoint3DSW::solve(real_t p_step) {
impulseMag = m_accLimitImpulse - temp;
Vector3 impulse = axisA * impulseMag * m_limitSign;
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
+ if (dynamic_A) {
+ A->apply_torque_impulse(impulse);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-impulse);
+ }
}
}
@@ -359,8 +374,12 @@ void HingeJoint3DSW::solve(real_t p_step) {
clippedMotorImpulse = clippedMotorImpulse < -m_maxMotorImpulse ? -m_maxMotorImpulse : clippedMotorImpulse;
Vector3 motorImp = clippedMotorImpulse * axisA;
- A->apply_torque_impulse(motorImp + angularLimit);
- B->apply_torque_impulse(-motorImp - angularLimit);
+ if (dynamic_A) {
+ A->apply_torque_impulse(motorImp + angularLimit);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-motorImp - angularLimit);
+ }
}
}
}
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.h b/servers/physics_3d/joints/hinge_joint_3d_sw.h
index b6117aa0bc..22eb2f4660 100644
--- a/servers/physics_3d/joints/hinge_joint_3d_sw.h
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.h
@@ -66,8 +66,8 @@ class HingeJoint3DSW : public Joint3DSW {
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;
+ Transform3D m_rbAFrame; // constraint axii. Assumes z is hinge axis.
+ Transform3D m_rbBFrame;
real_t m_motorTargetVelocity;
real_t m_maxMotorImpulse;
@@ -96,10 +96,10 @@ class HingeJoint3DSW : public Joint3DSW {
real_t m_appliedImpulse;
public:
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_HINGE; }
+ virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_HINGE; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
real_t get_hinge_angle();
@@ -109,7 +109,7 @@ public:
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 Transform3D &frameA, const Transform3D &frameB);
HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB);
};
diff --git a/servers/physics_3d/joints/jacobian_entry_3d_sw.h b/servers/physics_3d/joints/jacobian_entry_3d_sw.h
index 2829a5caf7..6afa70c816 100644
--- a/servers/physics_3d/joints/jacobian_entry_3d_sw.h
+++ b/servers/physics_3d/joints/jacobian_entry_3d_sw.h
@@ -50,7 +50,7 @@ subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
class JacobianEntry3DSW {
public:
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.cpp b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
index 75d87992d1..8eb84d1c2f 100644
--- a/servers/physics_3d/joints/pin_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
@@ -50,7 +50,10 @@ subject to the following restrictions:
#include "pin_joint_3d_sw.h"
bool PinJoint3DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -123,8 +126,12 @@ void PinJoint3DSW::solve(real_t p_step) {
m_appliedImpulse += impulse;
Vector3 impulse_vector = normal * impulse;
- A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
- B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ if (dynamic_A) {
+ A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ }
normal[i] = 0;
}
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.h b/servers/physics_3d/joints/pin_joint_3d_sw.h
index 1875983527..3d91452850 100644
--- a/servers/physics_3d/joints/pin_joint_3d_sw.h
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.h
@@ -74,10 +74,10 @@ class PinJoint3DSW : public Joint3DSW {
Vector3 m_pivotInB;
public:
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_PIN; }
+ virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_PIN; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
void set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value);
real_t get_param(PhysicsServer3D::PinJointParam p_param) const;
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
index 2e1ee8e770..db9bdb2986 100644
--- a/servers/physics_3d/joints/slider_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
@@ -111,7 +111,7 @@ void SliderJoint3DSW::initParams() {
//-----------------------------------------------------------------------------
-SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB) :
+SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB) :
Joint3DSW(_arr, 2),
m_frameInA(frameInA),
m_frameInB(frameInB) {
@@ -127,7 +127,10 @@ SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &
//-----------------------------------------------------------------------------
bool SliderJoint3DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -200,8 +203,12 @@ void SliderJoint3DSW::solve(real_t p_step) {
// 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(impulse_vector, m_relPosA);
- B->apply_impulse(-impulse_vector, m_relPosB);
+ if (dynamic_A) {
+ A->apply_impulse(impulse_vector, m_relPosA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(-impulse_vector, m_relPosB);
+ }
if (m_poweredLinMotor && (!i)) { // apply linear motor
if (m_accumulatedLinMotorImpulse < m_maxLinMotorForce) {
real_t desiredMotorVel = m_targetLinMotorVelocity;
@@ -221,8 +228,12 @@ void SliderJoint3DSW::solve(real_t p_step) {
m_accumulatedLinMotorImpulse = new_acc;
// apply clamped impulse
impulse_vector = normal * normalImpulse;
- A->apply_impulse(impulse_vector, m_relPosA);
- B->apply_impulse(-impulse_vector, m_relPosB);
+ if (dynamic_A) {
+ A->apply_impulse(impulse_vector, m_relPosA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(-impulse_vector, m_relPosB);
+ }
}
}
}
@@ -256,8 +267,12 @@ void SliderJoint3DSW::solve(real_t p_step) {
angularError *= (real_t(1.) / denom2) * m_restitutionOrthoAng * m_softnessOrthoAng;
}
// apply impulse
- A->apply_torque_impulse(-velrelOrthog + angularError);
- B->apply_torque_impulse(velrelOrthog - angularError);
+ if (dynamic_A) {
+ A->apply_torque_impulse(-velrelOrthog + angularError);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(velrelOrthog - angularError);
+ }
real_t impulseMag;
//solve angular limits
if (m_solveAngLim) {
@@ -268,8 +283,12 @@ void SliderJoint3DSW::solve(real_t p_step) {
impulseMag *= m_kAngle * m_softnessDirAng;
}
Vector3 impulse = axisA * impulseMag;
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
+ if (dynamic_A) {
+ A->apply_torque_impulse(impulse);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-impulse);
+ }
//apply angular motor
if (m_poweredAngMotor) {
if (m_accumulatedAngMotorImpulse < m_maxAngMotorForce) {
@@ -294,8 +313,12 @@ void SliderJoint3DSW::solve(real_t p_step) {
m_accumulatedAngMotorImpulse = new_acc;
// apply clamped impulse
Vector3 motorImp = angImpulse * axisA;
- A->apply_torque_impulse(motorImp);
- B->apply_torque_impulse(-motorImp);
+ if (dynamic_A) {
+ A->apply_torque_impulse(motorImp);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-motorImp);
+ }
}
}
} // SliderJointSW::solveConstraint()
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.h b/servers/physics_3d/joints/slider_joint_3d_sw.h
index f52f6ace27..f357bbd67a 100644
--- a/servers/physics_3d/joints/slider_joint_3d_sw.h
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.h
@@ -76,8 +76,8 @@ protected:
Body3DSW *_arr[2];
};
- Transform m_frameInA;
- Transform m_frameInB;
+ Transform3D m_frameInA;
+ Transform3D m_frameInB;
// linear limits
real_t m_lowerLinLimit;
@@ -120,8 +120,8 @@ protected:
JacobianEntry3DSW m_jacAng[3];
real_t m_timeStep;
- Transform m_calculatedTransformA;
- Transform m_calculatedTransformB;
+ Transform3D m_calculatedTransformA;
+ Transform3D m_calculatedTransformB;
Vector3 m_sliderAxis;
Vector3 m_realPivotAInW;
@@ -152,19 +152,19 @@ protected:
public:
// constructors
- SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB);
+ SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &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; }
+ const Transform3D &getCalculatedTransformA() const { return m_calculatedTransformA; }
+ const Transform3D &getCalculatedTransformB() const { return m_calculatedTransformB; }
+ const Transform3D &getFrameOffsetA() const { return m_frameInA; }
+ const Transform3D &getFrameOffsetB() const { return m_frameInB; }
+ Transform3D &getFrameOffsetA() { return m_frameInA; }
+ Transform3D &getFrameOffsetB() { return m_frameInB; }
real_t getLowerLinLimit() { return m_lowerLinLimit; }
void setLowerLinLimit(real_t lowerLimit) { m_lowerLinLimit = lowerLimit; }
real_t getUpperLinLimit() { return m_upperLinLimit; }
@@ -240,10 +240,10 @@ public:
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 bool setup(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_SLIDER; }
+ virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_SLIDER; }
};
#endif // SLIDER_JOINT_SW_H
diff --git a/servers/physics_3d/joints_3d_sw.h b/servers/physics_3d/joints_3d_sw.h
index 225a71aca9..e2514674ea 100644
--- a/servers/physics_3d/joints_3d_sw.h
+++ b/servers/physics_3d/joints_3d_sw.h
@@ -35,9 +35,14 @@
#include "constraint_3d_sw.h"
class Joint3DSW : public Constraint3DSW {
+protected:
+ bool dynamic_A = false;
+ bool dynamic_B = false;
+
public:
- virtual bool setup(real_t p_step) { return false; }
- virtual void solve(real_t p_step) {}
+ virtual bool setup(real_t p_step) override { return false; }
+ virtual bool pre_solve(real_t p_step) override { return true; }
+ virtual void solve(real_t p_step) override {}
void copy_settings_from(Joint3DSW *p_joint) {
set_self(p_joint->get_self());
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index 3d0063b0fa..7a95a8abc8 100644
--- a/servers/physics_3d/physics_server_3d_sw.cpp
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -30,8 +30,7 @@
#include "physics_server_3d_sw.h"
-#include "broad_phase_3d_basic.h"
-#include "broad_phase_octree.h"
+#include "broad_phase_3d_bvh.h"
#include "core/debugger/engine_debugger.h"
#include "core/os/os.h"
#include "joints/cone_twist_joint_3d_sw.h"
@@ -263,7 +262,7 @@ PhysicsServer3D::AreaSpaceOverrideMode PhysicsServer3DSW::area_get_space_overrid
return area->get_space_override_mode();
}
-void PhysicsServer3DSW::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) {
+void PhysicsServer3DSW::area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform, bool p_disabled) {
Area3DSW *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
@@ -284,7 +283,7 @@ void PhysicsServer3DSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape)
area->set_shape(p_shape_idx, shape);
}
-void PhysicsServer3DSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) {
+void PhysicsServer3DSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) {
Area3DSW *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
@@ -308,9 +307,9 @@ RID PhysicsServer3DSW::area_get_shape(RID p_area, int p_shape_idx) const {
return shape->get_self();
}
-Transform PhysicsServer3DSW::area_get_shape_transform(RID p_area, int p_shape_idx) const {
+Transform3D 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());
+ ERR_FAIL_COND_V(!area, Transform3D());
return area->get_shape_transform(p_shape_idx);
}
@@ -369,7 +368,7 @@ void PhysicsServer3DSW::area_set_param(RID p_area, AreaParameter p_param, const
area->set_param(p_param, p_value);
};
-void PhysicsServer3DSW::area_set_transform(RID p_area, const Transform &p_transform) {
+void PhysicsServer3DSW::area_set_transform(RID p_area, const Transform3D &p_transform) {
Area3DSW *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_transform(p_transform);
@@ -386,9 +385,9 @@ Variant PhysicsServer3DSW::area_get_param(RID p_area, AreaParameter p_param) con
return area->get_param(p_param);
};
-Transform PhysicsServer3DSW::area_get_transform(RID p_area) const {
+Transform3D PhysicsServer3DSW::area_get_transform(RID p_area) const {
Area3DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Transform());
+ ERR_FAIL_COND_V(!area, Transform3D());
return area->get_transform();
};
@@ -488,7 +487,7 @@ PhysicsServer3D::BodyMode PhysicsServer3DSW::body_get_mode(RID p_body) const {
return body->get_mode();
};
-void PhysicsServer3DSW::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) {
+void PhysicsServer3DSW::body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform, bool p_disabled) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -508,8 +507,7 @@ void PhysicsServer3DSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape)
body->set_shape(p_shape_idx, shape);
}
-
-void PhysicsServer3DSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) {
+void PhysicsServer3DSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -542,9 +540,9 @@ void PhysicsServer3DSW::body_set_shape_disabled(RID p_body, int p_shape_idx, boo
body->set_shape_as_disabled(p_shape_idx, p_disabled);
}
-Transform PhysicsServer3DSW::body_get_shape_transform(RID p_body, int p_shape_idx) const {
+Transform3D 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());
+ ERR_FAIL_COND_V(!body, Transform3D());
return body->get_shape_transform(p_shape_idx);
}
@@ -658,19 +656,6 @@ real_t PhysicsServer3DSW::body_get_param(RID p_body, BodyParameter p_param) cons
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);
@@ -857,10 +842,10 @@ int PhysicsServer3DSW::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
-void PhysicsServer3DSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
+void PhysicsServer3DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
+ body->set_force_integration_callback(p_callable, p_udata);
}
void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) {
@@ -869,7 +854,7 @@ void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) {
body->set_ray_pickable(p_enable);
}
-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) {
+bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, 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);
@@ -877,10 +862,10 @@ bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform &p_from, co
_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);
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_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, real_t p_margin) {
+int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
@@ -1011,7 +996,7 @@ Variant PhysicsServer3DSW::soft_body_get_state(RID p_body, BodyState p_state) co
return soft_body->get_state(p_state);
}
-void PhysicsServer3DSW::soft_body_set_transform(RID p_body, const Transform &p_transform) {
+void PhysicsServer3DSW::soft_body_set_transform(RID p_body, const Transform3D &p_transform) {
SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!soft_body);
@@ -1254,7 +1239,7 @@ Vector3 PhysicsServer3DSW::pin_joint_get_local_b(RID p_joint) const {
return pin_joint->get_position_b();
}
-void PhysicsServer3DSW::joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) {
+void PhysicsServer3DSW::joint_make_hinge(RID p_joint, RID p_body_A, const Transform3D &p_frame_A, RID p_body_B, const Transform3D &p_frame_B) {
Body3DSW *body_A = body_owner.getornull(p_body_A);
ERR_FAIL_COND(!body_A);
@@ -1379,7 +1364,7 @@ PhysicsServer3DSW::JointType PhysicsServer3DSW::joint_get_type(RID p_joint) cons
return joint->get_type();
}
-void PhysicsServer3DSW::joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+void PhysicsServer3DSW::joint_make_slider(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) {
Body3DSW *body_A = body_owner.getornull(p_body_A);
ERR_FAIL_COND(!body_A);
@@ -1419,7 +1404,7 @@ real_t PhysicsServer3DSW::slider_joint_get_param(RID p_joint, SliderJointParam p
return slider_joint->get_param(p_param);
}
-void PhysicsServer3DSW::joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+void PhysicsServer3DSW::joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) {
Body3DSW *body_A = body_owner.getornull(p_body_A);
ERR_FAIL_COND(!body_A);
@@ -1459,7 +1444,7 @@ real_t PhysicsServer3DSW::cone_twist_joint_get_param(RID p_joint, ConeTwistJoint
return cone_twist_joint->get_param(p_param);
}
-void PhysicsServer3DSW::joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+void PhysicsServer3DSW::joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) {
Body3DSW *body_A = body_owner.getornull(p_body_A);
ERR_FAIL_COND(!body_A);
@@ -1755,7 +1740,8 @@ void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A,
PhysicsServer3DSW *PhysicsServer3DSW::singletonsw = nullptr;
PhysicsServer3DSW::PhysicsServer3DSW(bool p_using_threads) {
singletonsw = this;
- BroadPhase3DSW::create_func = BroadPhaseOctree::_create;
+ BroadPhase3DSW::create_func = BroadPhase3DBVH::_create;
+
island_count = 0;
active_objects = 0;
collision_pairs = 0;
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
index f92652bfad..57b6385758 100644
--- a/servers/physics_3d/physics_server_3d_sw.h
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -130,13 +130,13 @@ public:
virtual void area_set_space(RID p_area, RID p_space) override;
virtual RID area_get_space(RID p_area) const override;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) override;
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override;
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) override;
- virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) override;
+ virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) override;
virtual int area_get_shape_count(RID p_area) const override;
virtual RID area_get_shape(RID p_area, int p_shape_idx) const override;
- virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const override;
+ virtual Transform3D area_get_shape_transform(RID p_area, int p_shape_idx) const override;
virtual void area_remove_shape(RID p_area, int p_shape_idx) override;
virtual void area_clear_shapes(RID p_area) override;
@@ -147,10 +147,10 @@ public:
virtual ObjectID area_get_object_instance_id(RID p_area) const override;
virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) override;
- virtual void area_set_transform(RID p_area, const Transform &p_transform) override;
+ virtual void area_set_transform(RID p_area, const Transform3D &p_transform) override;
virtual Variant area_get_param(RID p_area, AreaParameter p_param) const override;
- virtual Transform area_get_transform(RID p_area) const override;
+ virtual Transform3D area_get_transform(RID p_area) const override;
virtual void area_set_ray_pickable(RID p_area, bool p_enable) override;
@@ -173,13 +173,13 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode) override;
virtual BodyMode body_get_mode(RID p_body) const override;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) override;
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override;
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) override;
- virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) override;
+ virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) override;
virtual int body_get_shape_count(RID p_body) const override;
virtual RID body_get_shape(RID p_body, int p_shape_idx) const override;
- virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const override;
+ virtual Transform3D body_get_shape_transform(RID p_body, int p_shape_idx) const override;
virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) override;
@@ -204,9 +204,6 @@ public:
virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override;
virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override;
- virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) override;
- virtual real_t body_get_kinematic_safe_margin(RID p_body) const override;
-
virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override;
virtual Variant body_get_state(RID p_body, BodyState p_state) const override;
@@ -241,12 +238,12 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) override;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
- virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
+ virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
+ virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
@@ -273,7 +270,7 @@ public:
virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override;
virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override;
- virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override;
+ virtual void soft_body_set_transform(RID p_body, const Transform3D &p_transform) override;
virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override;
@@ -323,7 +320,7 @@ public:
virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) override;
virtual Vector3 pin_joint_get_local_b(RID p_joint) const override;
- virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) override;
+ virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform3D &p_frame_A, RID p_body_B, const Transform3D &p_frame_B) override;
virtual void joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override;
virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) override;
@@ -332,17 +329,17 @@ public:
virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) override;
virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const override;
- virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A
+ virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; //reference frame is A
virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) override;
virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override;
- virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A
+ virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; //reference frame is A
virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) override;
virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override;
- virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A
+ virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; //reference frame is A
virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value) override;
virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) const override;
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.cpp b/servers/physics_3d/physics_server_3d_wrap_mt.cpp
index f73f67a756..0a89c1a9c9 100644
--- a/servers/physics_3d/physics_server_3d_wrap_mt.cpp
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.cpp
@@ -56,7 +56,7 @@ void PhysicsServer3DWrapMT::thread_loop() {
step_thread_up = true;
while (!exit) {
// flush commands one by one, until exit is requested
- command_queue.wait_and_flush_one();
+ command_queue.wait_and_flush();
}
command_queue.flush_all(); // flush all
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h
index 49ae60db92..bda2e30dd1 100644
--- a/servers/physics_3d/physics_server_3d_wrap_mt.h
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.h
@@ -142,14 +142,14 @@ public:
FUNC2(area_set_space_override_mode, RID, AreaSpaceOverrideMode);
FUNC1RC(AreaSpaceOverrideMode, area_get_space_override_mode, RID);
- FUNC4(area_add_shape, RID, RID, const Transform &, bool);
+ FUNC4(area_add_shape, RID, RID, const Transform3D &, bool);
FUNC3(area_set_shape, RID, int, RID);
- FUNC3(area_set_shape_transform, RID, int, const Transform &);
+ FUNC3(area_set_shape_transform, RID, int, const Transform3D &);
FUNC3(area_set_shape_disabled, RID, int, bool);
FUNC1RC(int, area_get_shape_count, RID);
FUNC2RC(RID, area_get_shape, RID, int);
- FUNC2RC(Transform, area_get_shape_transform, RID, int);
+ FUNC2RC(Transform3D, area_get_shape_transform, RID, int);
FUNC2(area_remove_shape, RID, int);
FUNC1(area_clear_shapes, RID);
@@ -157,10 +157,10 @@ public:
FUNC1RC(ObjectID, area_get_object_instance_id, RID);
FUNC3(area_set_param, RID, AreaParameter, const Variant &);
- FUNC2(area_set_transform, RID, const Transform &);
+ FUNC2(area_set_transform, RID, const Transform3D &);
FUNC2RC(Variant, area_get_param, RID, AreaParameter);
- FUNC1RC(Transform, area_get_transform, RID);
+ FUNC1RC(Transform3D, area_get_transform, RID);
FUNC2(area_set_collision_mask, RID, uint32_t);
FUNC2(area_set_collision_layer, RID, uint32_t);
@@ -182,12 +182,12 @@ public:
FUNC2(body_set_mode, RID, BodyMode);
FUNC1RC(BodyMode, body_get_mode, RID);
- FUNC4(body_add_shape, RID, RID, const Transform &, bool);
+ FUNC4(body_add_shape, RID, RID, const Transform3D &, bool);
FUNC3(body_set_shape, RID, int, RID);
- FUNC3(body_set_shape_transform, RID, int, const Transform &);
+ FUNC3(body_set_shape_transform, RID, int, const Transform3D &);
FUNC1RC(int, body_get_shape_count, RID);
- FUNC2RC(Transform, body_get_shape_transform, RID, int);
+ FUNC2RC(Transform3D, body_get_shape_transform, RID, int);
FUNC2RC(RID, body_get_shape, RID, int);
FUNC3(body_set_shape_disabled, RID, int, bool);
@@ -213,9 +213,6 @@ public:
FUNC3(body_set_param, RID, BodyParameter, real_t);
FUNC2RC(real_t, body_get_param, RID, BodyParameter);
- FUNC2(body_set_kinematic_safe_margin, RID, real_t);
- FUNC1RC(real_t, body_get_kinematic_safe_margin, RID);
-
FUNC3(body_set_state, RID, BodyState, const Variant &);
FUNC2RC(Variant, body_get_state, RID, BodyState);
@@ -249,16 +246,16 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
- FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, const Variant &);
+ FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
FUNC2(body_set_ray_pickable, RID, bool);
- bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override {
+ bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
- return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes);
+ return physics_3d_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 Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override {
+ int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
return physics_3d_server->body_test_ray_separation(p_body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
}
@@ -293,7 +290,7 @@ public:
FUNC3(soft_body_set_state, RID, BodyState, const Variant &);
FUNC2RC(Variant, soft_body_get_state, RID, BodyState);
- FUNC2(soft_body_set_transform, RID, const Transform &);
+ FUNC2(soft_body_set_transform, RID, const Transform3D &);
FUNC2(soft_body_set_simulation_precision, RID, int);
FUNC1RC(int, soft_body_get_simulation_precision, RID);
@@ -341,7 +338,7 @@ public:
FUNC2(pin_joint_set_local_b, RID, const Vector3 &)
FUNC1RC(Vector3, pin_joint_get_local_b, RID)
- FUNC5(joint_make_hinge, RID, RID, const Transform &, RID, const Transform &)
+ FUNC5(joint_make_hinge, RID, RID, const Transform3D &, RID, const Transform3D &)
FUNC7(joint_make_hinge_simple, RID, RID, const Vector3 &, const Vector3 &, RID, const Vector3 &, const Vector3 &)
FUNC3(hinge_joint_set_param, RID, HingeJointParam, real_t)
@@ -350,17 +347,17 @@ public:
FUNC3(hinge_joint_set_flag, RID, HingeJointFlag, bool)
FUNC2RC(bool, hinge_joint_get_flag, RID, HingeJointFlag)
- FUNC5(joint_make_slider, RID, RID, const Transform &, RID, const Transform &)
+ FUNC5(joint_make_slider, RID, RID, const Transform3D &, RID, const Transform3D &)
FUNC3(slider_joint_set_param, RID, SliderJointParam, real_t)
FUNC2RC(real_t, slider_joint_get_param, RID, SliderJointParam)
- FUNC5(joint_make_cone_twist, RID, RID, const Transform &, RID, const Transform &)
+ FUNC5(joint_make_cone_twist, RID, RID, const Transform3D &, RID, const Transform3D &)
FUNC3(cone_twist_joint_set_param, RID, ConeTwistJointParam, real_t)
FUNC2RC(real_t, cone_twist_joint_get_param, RID, ConeTwistJointParam)
- FUNC5(joint_make_generic_6dof, RID, RID, const Transform &, RID, const Transform &)
+ FUNC5(joint_make_generic_6dof, RID, RID, const Transform3D &, RID, const Transform3D &)
FUNC4(generic_6dof_joint_set_param, RID, Vector3::Axis, G6DOFJointAxisParam, real_t)
FUNC3RC(real_t, generic_6dof_joint_get_param, RID, Vector3::Axis, G6DOFJointAxisParam)
diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp
index ccd37ca742..2ffab0c923 100644
--- a/servers/physics_3d/shape_3d_sw.cpp
+++ b/servers/physics_3d/shape_3d_sw.cpp
@@ -31,8 +31,8 @@
#include "shape_3d_sw.h"
#include "core/io/image.h"
+#include "core/math/convex_hull.h"
#include "core/math/geometry_3d.h"
-#include "core/math/quick_hull.h"
#include "core/templates/sort_array.h"
// HeightMapShape3DSW is based on Bullet btHeightfieldTerrainShape.
@@ -114,7 +114,7 @@ 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 {
+void PlaneShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
// gibberish, a plane is infinity
r_min = -1e7;
r_max = 1e7;
@@ -174,7 +174,7 @@ 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 {
+void RayShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &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;
@@ -255,7 +255,7 @@ 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 {
+void SphereShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &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
@@ -317,7 +317,7 @@ SphereShape3DSW::SphereShape3DSW() {
/********** BOX *************/
-void BoxShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+void BoxShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &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);
@@ -507,7 +507,7 @@ BoxShape3DSW::BoxShape3DSW() {
/********** CAPSULE *************/
-void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &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.y > 0) ? height : -height;
@@ -674,7 +674,7 @@ CapsuleShape3DSW::CapsuleShape3DSW() {
/********** CYLINDER *************/
-void CylinderShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+void CylinderShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
Vector3 cylinder_axis = p_transform.basis.get_axis(1).normalized();
real_t axis_dot = cylinder_axis.dot(p_normal);
@@ -854,7 +854,7 @@ CylinderShape3DSW::CylinderShape3DSW() {
/********** CONVEX POLYGON *************/
-void ConvexPolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+void ConvexPolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
int vertex_count = mesh.vertices.size();
if (vertex_count == 0) {
return;
@@ -1089,9 +1089,9 @@ Vector3 ConvexPolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const {
}
void ConvexPolygonShape3DSW::_setup(const Vector<Vector3> &p_vertices) {
- Error err = QuickHull::build(p_vertices, mesh);
+ Error err = ConvexHullComputer::convex_hull(p_vertices, mesh);
if (err != OK) {
- ERR_PRINT("Failed to build QuickHull");
+ ERR_PRINT("Failed to build convex hull");
}
AABB _aabb;
@@ -1120,7 +1120,7 @@ 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 {
+void FaceShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &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);
@@ -1250,7 +1250,7 @@ Vector<Vector3> ConcavePolygonShape3DSW::get_faces() const {
return rfaces;
}
-void ConcavePolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+void ConcavePolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
int count = vertices.size();
if (count == 0) {
r_min = 0;
@@ -1647,7 +1647,7 @@ int HeightMapShape3DSW::get_depth() const {
return depth;
}
-void HeightMapShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+void HeightMapShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &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);
}
diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h
index 4d2b6ffbed..bc8bd3e695 100644
--- a/servers/physics_3d/shape_3d_sw.h
+++ b/servers/physics_3d/shape_3d_sw.h
@@ -86,7 +86,7 @@ public:
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 void project_range(const Vector3 &p_normal, const Transform3D &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, FeatureType &r_type) const = 0;
virtual Vector3 get_closest_point_to(const Vector3 &p_point) const = 0;
@@ -130,7 +130,7 @@ public:
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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
@@ -157,7 +157,7 @@ public:
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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
@@ -185,7 +185,7 @@ public:
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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
@@ -210,7 +210,7 @@ public:
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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
@@ -239,7 +239,7 @@ public:
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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
@@ -268,7 +268,7 @@ public:
virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CYLINDER; }
- virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const;
+ virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
@@ -293,7 +293,7 @@ public:
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 void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
virtual Vector3 get_support(const Vector3 &p_normal) const;
virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
@@ -371,7 +371,7 @@ public:
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 void project_range(const Vector3 &p_normal, const Transform3D &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;
@@ -415,7 +415,7 @@ public:
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 void project_range(const Vector3 &p_normal, const Transform3D &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;
@@ -441,7 +441,7 @@ struct FaceShape3DSW : public Shape3DSW {
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;
+ void project_range(const Vector3 &p_normal, const Transform3D &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, FeatureType &r_type) const;
bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
@@ -462,11 +462,11 @@ struct MotionShape3DSW : public Shape3DSW {
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 {
+ void project_range(const Vector3 &p_normal, const Transform3D &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;
+ Transform3D ofsb = p_transform;
ofsb.origin += cast;
shape->project_range(p_normal, p_transform, mina, maxa);
shape->project_range(p_normal, ofsb, minb, maxb);
diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp
index f63a470cbe..63a0fe11ba 100644
--- a/servers/physics_3d/soft_body_3d_sw.cpp
+++ b/servers/physics_3d/soft_body_3d_sw.cpp
@@ -289,7 +289,7 @@ void SoftBody3DSW::update_link_constants() {
}
}
-void SoftBody3DSW::apply_nodes_transform(const Transform &p_transform) {
+void SoftBody3DSW::apply_nodes_transform(const Transform3D &p_transform) {
if (soft_mesh.is_null()) {
return;
}
@@ -684,7 +684,7 @@ void SoftBody3DSW::generate_bending_constraints(int p_distance) {
//
// This function takes in a list of interdependent Links and tries
// to maximize the distance between calculation
-// of dependent links. This increases the amount of parallelism that can
+// of dependent links. This increases the amount of parallelism that can
// be exploited by out-of-order instruction processors with large but
// (inevitably) finite instruction windows.
//
diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/soft_body_3d_sw.h
index 6c0451ff45..ac8bcbf0b9 100644
--- a/servers/physics_3d/soft_body_3d_sw.h
+++ b/servers/physics_3d/soft_body_3d_sw.h
@@ -106,6 +106,8 @@ class SoftBody3DSW : public CollisionObject3DSW {
VSet<RID> exceptions;
+ uint64_t island_step = 0;
+
public:
SoftBody3DSW();
@@ -124,6 +126,9 @@ public:
_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; }
+
virtual void set_space(Space3DSW *p_space);
void set_mesh(const Ref<Mesh> &p_mesh);
@@ -196,7 +201,7 @@ private:
void reset_link_rest_lengths();
void update_link_constants();
- void apply_nodes_transform(const Transform &p_transform);
+ void apply_nodes_transform(const Transform3D &p_transform);
void add_velocity(const Vector3 &p_velocity);
@@ -226,7 +231,7 @@ public:
SoftBody3DSW *get_soft_body() const { return soft_body; }
virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_SOFT_BODY; }
- virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { r_min = r_max = 0.0; }
+ virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { r_min = r_max = 0.0; }
virtual Vector3 get_support(const Vector3 &p_normal) const { return Vector3(); }
virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; }
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
index 2df824b320..c1e09c9a22 100644
--- a/servers/physics_3d/space_3d_sw.cpp
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -59,7 +59,7 @@ int PhysicsDirectSpaceState3DSW::intersect_point(const Vector3 &p_point, ShapeRe
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();
+ //Transform3D ai = p_xform.affine_inverse();
for (int i = 0; i < amount; i++) {
if (cc >= p_result_max) {
@@ -79,7 +79,7 @@ int PhysicsDirectSpaceState3DSW::intersect_point(const Vector3 &p_point, ShapeRe
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);
+ Transform3D 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))) {
@@ -136,7 +136,7 @@ bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vec
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();
+ Transform3D 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);
@@ -146,7 +146,7 @@ bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vec
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);
+ Transform3D 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);
@@ -180,7 +180,7 @@ bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vec
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) {
+int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Transform3D &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;
}
@@ -194,7 +194,7 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans
int cc = 0;
- //Transform ai = p_xform.affine_inverse();
+ //Transform3D ai = p_xform.affine_inverse();
for (int i = 0; i < amount; i++) {
if (cc >= p_result_max) {
@@ -239,7 +239,7 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans
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) {
+bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transform3D &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 = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, false);
@@ -252,7 +252,7 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor
real_t best_safe = 1;
real_t best_unsafe = 1;
- Transform xform_inv = p_xform.affine_inverse();
+ Transform3D xform_inv = p_xform.affine_inverse();
MotionShape3DSW mshape;
mshape.shape = shape;
mshape.motion = xform_inv.basis.xform(p_motion);
@@ -280,7 +280,7 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor
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);
+ Transform3D 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;
@@ -348,7 +348,7 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor
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) {
+bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform3D &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 false;
}
@@ -432,7 +432,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect
rd->best_local_shape = rd->local_shape;
}
-bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform3D &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 = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, 0);
@@ -512,7 +512,7 @@ Vector3 PhysicsDirectSpaceState3DSW::get_closest_point_to_object_volume(RID p_ob
continue;
}
- Transform shape_xform = obj->get_transform() * obj->get_shape_transform(i);
+ Transform3D 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));
@@ -573,7 +573,7 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) {
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) {
+int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform3D &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;
@@ -598,7 +598,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra
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;
+ Transform3D body_transform = p_transform;
for (int i = 0; i < p_result_max; i++) {
//reset results
@@ -636,7 +636,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra
continue;
}
- Transform body_shape_xform = body_transform * p_body->get_shape_transform(j);
+ Transform3D 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];
@@ -724,7 +724,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra
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) {
+bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &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
@@ -768,7 +768,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
real_t motion_length = p_motion.length();
Vector3 motion_normal = p_motion / motion_length;
- Transform body_transform = p_from;
+ Transform3D body_transform = p_from;
bool recovered = false;
@@ -797,7 +797,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
continue;
}
- Transform body_shape_xform = body_transform * p_body->get_shape_transform(j);
+ Transform3D 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;
@@ -807,6 +807,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
const CollisionObject3DSW *col_obj = intersection_query_results[i];
int shape_idx = intersection_query_subindex_results[i];
+ 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;
+ }
+ }
+
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;
}
@@ -868,14 +875,14 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
continue;
}
- Transform body_shape_xform = body_transform * p_body->get_shape_transform(j);
+ Transform3D 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();
+ Transform3D 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);
@@ -889,11 +896,18 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
const CollisionObject3DSW *col_obj = intersection_query_results[i];
int shape_idx = intersection_query_subindex_results[i];
+ 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;
+ }
+ }
+
//test initial overlap, does it collide if going all the way?
Vector3 point_A, point_B;
Vector3 sep_axis = motion_normal;
- Transform col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+ Transform3D 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;
@@ -960,7 +974,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
}
//it collided, let's get the rest info in unsafe advance
- Transform ugt = body_transform;
+ Transform3D ugt = body_transform;
ugt.origin += p_motion * unsafe;
_RestCallbackData rcd;
@@ -979,7 +993,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
continue;
}
- Transform body_shape_xform = ugt * p_body->get_shape_transform(j);
+ Transform3D body_shape_xform = ugt * 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) {
@@ -994,6 +1008,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons
const CollisionObject3DSW *col_obj = intersection_query_results[i];
int shape_idx = intersection_query_subindex_results[i];
+ 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;
+ }
+ }
+
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);
diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h
index 3a8f452e54..18e93c90cc 100644
--- a/servers/physics_3d/space_3d_sw.h
+++ b/servers/physics_3d/space_3d_sw.h
@@ -50,10 +50,10 @@ 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) override;
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) override;
- 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) override;
- 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) override;
- 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) override;
- 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) override;
+ virtual int intersect_shape(const RID &p_shape, const Transform3D &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) override;
+ virtual bool cast_motion(const RID &p_shape, const Transform3D &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) override;
+ virtual bool collide_shape(RID p_shape, const Transform3D &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) override;
+ virtual bool rest_info(RID p_shape, const Transform3D &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) override;
virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override;
PhysicsDirectSpaceState3DSW();
@@ -203,8 +203,8 @@ public:
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);
+ int test_body_ray_separation(Body3DSW *p_body, const Transform3D &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 Transform3D &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();
diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/step_3d_sw.cpp
index 06f3227eab..ba18bac611 100644
--- a/servers/physics_3d/step_3d_sw.cpp
+++ b/servers/physics_3d/step_3d_sw.cpp
@@ -37,39 +37,90 @@
#define BODY_ISLAND_SIZE_RESERVE 512
#define ISLAND_COUNT_RESERVE 128
#define ISLAND_SIZE_RESERVE 512
+#define CONSTRAINT_COUNT_RESERVE 1024
void Step3DSW::_populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island) {
p_body->set_island_step(_step);
- p_body_island.push_back(p_body);
- // Faster with reversed iterations.
- for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().back(); E; E = E->prev()) {
- Constraint3DSW *c = (Constraint3DSW *)E->key();
- if (c->get_island_step() == _step) {
- continue; //already processed
+ if (p_body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ // Only dynamic bodies are tested for activation.
+ p_body_island.push_back(p_body);
+ }
+
+ for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) {
+ Constraint3DSW *constraint = (Constraint3DSW *)E->key();
+ if (constraint->get_island_step() == _step) {
+ continue; // Already processed.
}
- c->set_island_step(_step);
- p_constraint_island.push_back(c);
+ constraint->set_island_step(_step);
+ p_constraint_island.push_back(constraint);
+
+ all_constraints.push_back(constraint);
- for (int i = 0; i < c->get_body_count(); i++) {
+ // Find connected rigid bodies.
+ for (int i = 0; i < constraint->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
+ Body3DSW *other_body = constraint->get_body_ptr()[i];
+ if (other_body->get_island_step() == _step) {
+ continue; // Already processed.
+ }
+ if (other_body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC) {
+ continue; // Static bodies don't connect islands.
+ }
+ _populate_island(other_body, p_body_island, p_constraint_island);
+ }
+
+ // Find connected soft bodies.
+ for (int i = 0; i < constraint->get_soft_body_count(); i++) {
+ SoftBody3DSW *soft_body = constraint->get_soft_body_ptr(i);
+ if (soft_body->get_island_step() == _step) {
+ continue; // Already processed.
}
- _populate_island(c->get_body_ptr()[i], p_body_island, p_constraint_island);
+ _populate_island_soft_body(soft_body, p_body_island, p_constraint_island);
}
}
}
-void Step3DSW::_setup_island(LocalVector<Constraint3DSW *> &p_constraint_island, real_t p_delta) {
+void Step3DSW::_populate_island_soft_body(SoftBody3DSW *p_soft_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island) {
+ p_soft_body->set_island_step(_step);
+
+ for (Set<Constraint3DSW *>::Element *E = p_soft_body->get_constraints().front(); E; E = E->next()) {
+ Constraint3DSW *constraint = (Constraint3DSW *)E->get();
+ if (constraint->get_island_step() == _step) {
+ continue; // Already processed.
+ }
+ constraint->set_island_step(_step);
+ p_constraint_island.push_back(constraint);
+
+ all_constraints.push_back(constraint);
+
+ // Find connected rigid bodies.
+ for (int i = 0; i < constraint->get_body_count(); i++) {
+ Body3DSW *body = constraint->get_body_ptr()[i];
+ if (body->get_island_step() == _step) {
+ continue; // Already processed.
+ }
+ if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC) {
+ continue; // Static bodies don't connect islands.
+ }
+ _populate_island(body, p_body_island, p_constraint_island);
+ }
+ }
+}
+
+void Step3DSW::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) {
+ Constraint3DSW *constraint = all_constraints[p_constraint_index];
+ constraint->setup(delta);
+}
+
+void Step3DSW::_pre_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island) const {
uint32_t constraint_count = p_constraint_island.size();
uint32_t valid_constraint_count = 0;
for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
Constraint3DSW *constraint = p_constraint_island[constraint_index];
- if (p_constraint_island[constraint_index]->setup(p_delta)) {
+ if (p_constraint_island[constraint_index]->pre_solve(delta)) {
// Keep this constraint for solving.
p_constraint_island[valid_constraint_count++] = constraint;
}
@@ -77,15 +128,17 @@ void Step3DSW::_setup_island(LocalVector<Constraint3DSW *> &p_constraint_island,
p_constraint_island.resize(valid_constraint_count);
}
-void Step3DSW::_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island, int p_iterations, real_t p_delta) {
+void Step3DSW::_solve_island(uint32_t p_island_index, void *p_userdata) {
+ LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[p_island_index];
+
int current_priority = 1;
- uint32_t constraint_count = p_constraint_island.size();
+ uint32_t constraint_count = constraint_island.size();
while (constraint_count > 0) {
- for (int i = 0; i < p_iterations; i++) {
+ for (int i = 0; i < iterations; i++) {
// Go through all iterations.
for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
- p_constraint_island[constraint_index]->solve(p_delta);
+ constraint_island[constraint_index]->solve(delta);
}
}
@@ -93,28 +146,24 @@ void Step3DSW::_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island,
uint32_t priority_constraint_count = 0;
++current_priority;
for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
- Constraint3DSW *constraint = p_constraint_island[constraint_index];
+ Constraint3DSW *constraint = constraint_island[constraint_index];
if (constraint->get_priority() >= current_priority) {
// Keep this constraint for the next iteration.
- p_constraint_island[priority_constraint_count++] = constraint;
+ constraint_island[priority_constraint_count++] = constraint;
}
}
constraint_count = priority_constraint_count;
}
}
-void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island, real_t p_delta) {
+void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island) const {
bool can_sleep = true;
uint32_t body_count = p_body_island.size();
for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
Body3DSW *body = p_body_island[body_index];
- if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
- continue; // Ignore for static.
- }
-
- if (!body->sleep_test(p_delta)) {
+ if (!body->sleep_test(delta)) {
can_sleep = false;
}
}
@@ -123,10 +172,6 @@ void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island, real
for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
Body3DSW *body = p_body_island[body_index];
- if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
- continue; // Ignore for static.
- }
-
bool active = body->is_active();
if (active == can_sleep) {
@@ -140,6 +185,9 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
p_space->setup(); //update inertias, etc
+ iterations = p_iterations;
+ delta = p_delta;
+
const SelfList<Body3DSW>::List *body_list = &p_space->get_active_body_list();
const SelfList<SoftBody3DSW>::List *soft_body_list = &p_space->get_active_soft_body_list();
@@ -175,12 +223,39 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
profile_begtime = profile_endtime;
}
- /* GENERATE CONSTRAINT ISLANDS */
+ /* GENERATE CONSTRAINT ISLANDS FOR MOVING AREAS */
+
+ uint32_t island_count = 0;
+
+ 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 *constraint = E->get();
+ if (constraint->get_island_step() == _step) {
+ continue;
+ }
+ constraint->set_island_step(_step);
+
+ // Each constraint can be on a separate island for areas as there's no solving phase.
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+
+ all_constraints.push_back(constraint);
+ constraint_island.push_back(constraint);
+ }
+ p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here
+ }
+
+ /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */
b = body_list->first();
uint32_t body_island_count = 0;
- uint32_t island_count = 0;
while (b) {
Body3DSW *body = b->self();
@@ -204,7 +279,9 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
_populate_island(body, body_island, constraint_island);
- body_islands.push_back(body_island);
+ if (body_island.is_empty()) {
+ --body_island_count;
+ }
if (constraint_island.is_empty()) {
--island_count;
@@ -213,58 +290,54 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
b = b->next();
}
- p_space->set_island_count((int)island_count);
+ /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE SOFT BODIES */
- const SelfList<Area3DSW>::List &aml = p_space->get_moved_area_list();
+ sb = soft_body_list->first();
+ while (sb) {
+ SoftBody3DSW *soft_body = sb->self();
- 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;
+ if (soft_body->get_island_step() != _step) {
+ ++body_island_count;
+ if (body_islands.size() < body_island_count) {
+ body_islands.resize(body_island_count);
}
- c->set_island_step(_step);
+ LocalVector<Body3DSW *> &body_island = body_islands[body_island_count - 1];
+ body_island.clear();
+ body_island.reserve(BODY_ISLAND_SIZE_RESERVE);
+
++island_count;
if (constraint_islands.size() < island_count) {
constraint_islands.resize(island_count);
}
LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
constraint_island.clear();
- constraint_island.push_back(c);
- }
- p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here
- }
+ constraint_island.reserve(ISLAND_SIZE_RESERVE);
- sb = soft_body_list->first();
- while (sb) {
- for (const Set<Constraint3DSW *>::Element *E = sb->self()->get_constraints().front(); E; E = E->next()) {
- Constraint3DSW *c = E->get();
- if (c->get_island_step() == _step) {
- continue;
+ _populate_island_soft_body(soft_body, body_island, constraint_island);
+
+ if (body_island.is_empty()) {
+ --body_island_count;
}
- c->set_island_step(_step);
- ++island_count;
- if (constraint_islands.size() < island_count) {
- constraint_islands.resize(island_count);
+
+ if (constraint_island.is_empty()) {
+ --island_count;
}
- LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
- constraint_island.clear();
- constraint_island.push_back(c);
}
sb = sb->next();
}
+ p_space->set_island_count((int)island_count);
+
{ //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 */
+ /* SETUP CONSTRAINTS / PROCESS COLLISIONS */
- for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
- _setup_island(constraint_islands[island_index], p_delta);
- }
+ uint32_t total_contraint_count = all_constraints.size();
+ work_pool.do_work(total_contraint_count, this, &Step3DSW::_setup_contraint, nullptr);
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
@@ -272,12 +345,21 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
profile_begtime = profile_endtime;
}
- /* SOLVE CONSTRAINT ISLANDS */
+ /* PRE-SOLVE CONSTRAINT ISLANDS */
+ // Warning: This doesn't run on threads, because it involves thread-unsafe processing.
for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
- // Warning: _solve_island modifies the constraint islands for optimization purpose,
- // their content is not reliable after these calls and shouldn't be used anymore.
- _solve_island(constraint_islands[island_index], p_iterations, p_delta);
+ _pre_solve_island(constraint_islands[island_index]);
+ }
+
+ /* SOLVE CONSTRAINT ISLANDS */
+
+ // Warning: _solve_island modifies the constraint islands for optimization purpose,
+ // their content is not reliable after these calls and shouldn't be used anymore.
+ if (island_count > 1) {
+ work_pool.do_work(island_count, this, &Step3DSW::_solve_island, nullptr);
+ } else if (island_count > 0) {
+ _solve_island(0);
}
{ //profile
@@ -298,7 +380,7 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
/* SLEEP / WAKE UP ISLANDS */
for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {
- _check_suspend(body_islands[island_index], p_delta);
+ _check_suspend(body_islands[island_index]);
}
/* UPDATE SOFT BODY CONSTRAINTS */
@@ -315,6 +397,8 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
profile_begtime = profile_endtime;
}
+ all_constraints.clear();
+
p_space->update();
p_space->unlock();
_step++;
@@ -325,4 +409,11 @@ Step3DSW::Step3DSW() {
body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);
constraint_islands.reserve(ISLAND_COUNT_RESERVE);
+ all_constraints.reserve(CONSTRAINT_COUNT_RESERVE);
+
+ work_pool.init();
+}
+
+Step3DSW::~Step3DSW() {
+ work_pool.finish();
}
diff --git a/servers/physics_3d/step_3d_sw.h b/servers/physics_3d/step_3d_sw.h
index f406c35c3a..9c60004b24 100644
--- a/servers/physics_3d/step_3d_sw.h
+++ b/servers/physics_3d/step_3d_sw.h
@@ -34,21 +34,31 @@
#include "space_3d_sw.h"
#include "core/templates/local_vector.h"
+#include "core/templates/thread_work_pool.h"
class Step3DSW {
uint64_t _step;
+ int iterations = 0;
+ real_t delta = 0.0;
+
+ ThreadWorkPool work_pool;
+
LocalVector<LocalVector<Body3DSW *>> body_islands;
LocalVector<LocalVector<Constraint3DSW *>> constraint_islands;
+ LocalVector<Constraint3DSW *> all_constraints;
void _populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island);
- void _setup_island(LocalVector<Constraint3DSW *> &p_constraint_island, real_t p_delta);
- void _solve_island(LocalVector<Constraint3DSW *> &p_constraint_island, int p_iterations, real_t p_delta);
- void _check_suspend(const LocalVector<Body3DSW *> &p_body_island, real_t p_delta);
+ void _populate_island_soft_body(SoftBody3DSW *p_soft_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island);
+ void _setup_contraint(uint32_t p_constraint_index, void *p_userdata = nullptr);
+ void _pre_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island) const;
+ void _solve_island(uint32_t p_island_index, void *p_userdata = nullptr);
+ void _check_suspend(const LocalVector<Body3DSW *> &p_body_island) const;
public:
void step(Space3DSW *p_space, real_t p_delta, int p_iterations);
Step3DSW();
+ ~Step3DSW();
};
#endif // STEP__SW_H
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index 83ebc0c55b..faab4f43b8 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -176,11 +176,11 @@ real_t PhysicsShapeQueryParameters2D::get_margin() const {
return margin;
}
-void PhysicsShapeQueryParameters2D::set_collision_mask(int p_collision_mask) {
+void PhysicsShapeQueryParameters2D::set_collision_mask(uint32_t p_collision_mask) {
collision_mask = p_collision_mask;
}
-int PhysicsShapeQueryParameters2D::get_collision_mask() const {
+uint32_t PhysicsShapeQueryParameters2D::get_collision_mask() const {
return collision_mask;
}
@@ -509,12 +509,6 @@ void PhysicsTestMotionResult2D::_bind_methods() {
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, real_t p_margin, const Ref<PhysicsTestMotionResult2D> &p_result) {
@@ -647,7 +641,7 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &PhysicsServer2D::body_set_omit_force_integration);
ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &PhysicsServer2D::body_is_omitting_force_integration);
- ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result"), &PhysicsServer2D::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant()));
@@ -675,6 +669,8 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_active", "active"), &PhysicsServer2D::set_active);
+ ClassDB::bind_method(D_METHOD("set_collision_iterations", "iterations"), &PhysicsServer2D::set_collision_iterations);
+
ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &PhysicsServer2D::get_process_info);
BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_RECYCLE_RADIUS);
@@ -713,8 +709,8 @@ void PhysicsServer2D::_bind_methods() {
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_MODE_DYNAMIC);
+ BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LOCKED);
BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE);
BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index 28f22ce06b..df39d6ae50 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -33,7 +33,7 @@
#include "core/io/resource.h"
#include "core/object/class_db.h"
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
class PhysicsDirectSpaceState2D;
@@ -95,8 +95,8 @@ public:
class PhysicsShapeQueryResult2D;
//used for script
-class PhysicsShapeQueryParameters2D : public Reference {
- GDCLASS(PhysicsShapeQueryParameters2D, Reference);
+class PhysicsShapeQueryParameters2D : public RefCounted {
+ GDCLASS(PhysicsShapeQueryParameters2D, RefCounted);
friend class PhysicsDirectSpaceState2D;
RES shape_ref;
@@ -128,8 +128,8 @@ public:
void set_margin(real_t p_margin);
real_t get_margin() const;
- void set_collision_mask(int p_collision_mask);
- int get_collision_mask() const;
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
void set_collide_with_bodies(bool p_enable);
bool is_collide_with_bodies_enabled() const;
@@ -164,8 +164,8 @@ public:
Vector2 normal;
RID rid;
ObjectID collider_id;
- Object *collider;
- int shape;
+ Object *collider = nullptr;
+ int shape = 0;
Variant metadata;
};
@@ -174,8 +174,8 @@ public:
struct ShapeResult {
RID rid;
ObjectID collider_id;
- Object *collider;
- int shape;
+ Object *collider = nullptr;
+ int shape = 0;
Variant metadata;
};
@@ -193,7 +193,7 @@ public:
Vector2 normal;
RID rid;
ObjectID collider_id;
- int shape;
+ int shape = 0;
Vector2 linear_velocity; //velocity at contact point
Variant metadata;
};
@@ -203,8 +203,8 @@ public:
PhysicsDirectSpaceState2D();
};
-class PhysicsShapeQueryResult2D : public Reference {
- GDCLASS(PhysicsShapeQueryResult2D, Reference);
+class PhysicsShapeQueryResult2D : public RefCounted {
+ GDCLASS(PhysicsShapeQueryResult2D, RefCounted);
Vector<PhysicsDirectSpaceState2D::ShapeResult> result;
@@ -370,8 +370,8 @@ public:
enum BodyMode {
BODY_MODE_STATIC,
BODY_MODE_KINEMATIC,
- BODY_MODE_RIGID,
- BODY_MODE_CHARACTER
+ BODY_MODE_DYNAMIC,
+ BODY_MODE_DYNAMIC_LOCKED,
};
virtual RID body_create() = 0;
@@ -477,7 +477,7 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) = 0;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) = 0;
@@ -493,17 +493,11 @@ public:
Vector2 collision_point;
Vector2 collision_normal;
Vector2 collider_velocity;
- int collision_local_shape;
+ int collision_local_shape = 0;
ObjectID collider_id;
RID collider;
- int collider_shape;
+ int collider_shape = 0;
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, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0;
@@ -589,6 +583,8 @@ public:
virtual bool is_flushing_queries() const = 0;
+ virtual void set_collision_iterations(int iterations) = 0;
+
enum ProcessInfo {
INFO_ACTIVE_OBJECTS,
INFO_COLLISION_PAIRS,
@@ -601,11 +597,10 @@ public:
~PhysicsServer2D();
};
-class PhysicsTestMotionResult2D : public Reference {
- GDCLASS(PhysicsTestMotionResult2D, Reference);
+class PhysicsTestMotionResult2D : public RefCounted {
+ GDCLASS(PhysicsTestMotionResult2D, RefCounted);
PhysicsServer2D::MotionResult result;
- bool colliding;
friend class PhysicsServer2D;
protected:
@@ -614,7 +609,6 @@ protected:
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;
@@ -625,8 +619,6 @@ public:
RID get_collider_rid() const;
Object *get_collider() const;
int get_collider_shape() const;
-
- PhysicsTestMotionResult2D();
};
typedef PhysicsServer2D *(*CreatePhysicsServer2DCallback)();
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index 586845de99..1634169e8a 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -128,7 +128,7 @@ void PhysicsDirectBodyState3D::_bind_methods() {
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::TRANSFORM, "transform"), "set_transform", "get_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform"), "set_transform", "get_transform");
}
PhysicsDirectBodyState3D::PhysicsDirectBodyState3D() {}
@@ -156,11 +156,11 @@ RID PhysicsShapeQueryParameters3D::get_shape_rid() const {
return shape;
}
-void PhysicsShapeQueryParameters3D::set_transform(const Transform &p_transform) {
+void PhysicsShapeQueryParameters3D::set_transform(const Transform3D &p_transform) {
transform = p_transform;
}
-Transform PhysicsShapeQueryParameters3D::get_transform() const {
+Transform3D PhysicsShapeQueryParameters3D::get_transform() const {
return transform;
}
@@ -172,11 +172,11 @@ real_t PhysicsShapeQueryParameters3D::get_margin() const {
return margin;
}
-void PhysicsShapeQueryParameters3D::set_collision_mask(int p_collision_mask) {
+void PhysicsShapeQueryParameters3D::set_collision_mask(uint32_t p_collision_mask) {
collision_mask = p_collision_mask;
}
-int PhysicsShapeQueryParameters3D::get_collision_mask() const {
+uint32_t PhysicsShapeQueryParameters3D::get_collision_mask() const {
return collision_mask;
}
@@ -242,7 +242,7 @@ void PhysicsShapeQueryParameters3D::_bind_methods() {
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, "Shape3D"), "set_shape", "get_shape");
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::TRANSFORM3D, "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");
}
@@ -458,7 +458,7 @@ void PhysicsServer3D::_bind_methods() {
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_add_shape", "area", "shape", "transform", "disabled"), &PhysicsServer3D::area_add_shape, DEFVAL(Transform3D()), 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);
@@ -502,7 +502,7 @@ void PhysicsServer3D::_bind_methods() {
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_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer3D::body_add_shape, DEFVAL(Transform3D()), 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);
@@ -523,9 +523,6 @@ void PhysicsServer3D::_bind_methods() {
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);
@@ -550,7 +547,7 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &PhysicsServer3D::body_set_omit_force_integration);
ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &PhysicsServer3D::body_is_omitting_force_integration);
- ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &PhysicsServer3D::body_set_force_integration_callback, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer3D::body_set_force_integration_callback, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable);
@@ -717,8 +714,8 @@ void PhysicsServer3D::_bind_methods() {
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_MODE_DYNAMIC);
+ BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LOCKED);
BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE);
BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 69f5c1c0ad..d9b805de87 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -59,8 +59,8 @@ public:
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 set_transform(const Transform3D &p_transform) = 0;
+ virtual Transform3D 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_position = Vector3()) = 0;
@@ -96,13 +96,13 @@ public:
class PhysicsShapeQueryResult3D;
-class PhysicsShapeQueryParameters3D : public Reference {
- GDCLASS(PhysicsShapeQueryParameters3D, Reference);
+class PhysicsShapeQueryParameters3D : public RefCounted {
+ GDCLASS(PhysicsShapeQueryParameters3D, RefCounted);
friend class PhysicsDirectSpaceState3D;
RES shape_ref;
RID shape;
- Transform transform;
+ Transform3D transform;
real_t margin;
Set<RID> exclude;
uint32_t collision_mask;
@@ -119,14 +119,14 @@ public:
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_transform(const Transform3D &p_transform);
+ Transform3D get_transform() const;
void set_margin(real_t p_margin);
real_t get_margin() const;
- void set_collision_mask(int p_collision_mask);
- int get_collision_mask() const;
+ void set_collision_mask(uint32_t p_collision_mask);
+ uint32_t get_collision_mask() const;
void set_exclude(const Vector<RID> &p_exclude);
Vector<RID> get_exclude() const;
@@ -157,8 +157,8 @@ public:
struct ShapeResult {
RID rid;
ObjectID collider_id;
- Object *collider;
- int shape;
+ Object *collider = nullptr;
+ int shape = 0;
};
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;
@@ -168,36 +168,36 @@ public:
Vector3 normal;
RID rid;
ObjectID collider_id;
- Object *collider;
- int shape;
+ Object *collider = nullptr;
+ int shape = 0;
};
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, 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) = 0;
+ virtual int intersect_shape(const RID &p_shape, const Transform3D &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) = 0;
struct ShapeRestInfo {
Vector3 point;
Vector3 normal;
RID rid;
ObjectID collider_id;
- int shape;
+ int shape = 0;
Vector3 linear_velocity; //velocity at contact point
};
- 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) = 0;
+ virtual bool cast_motion(const RID &p_shape, const Transform3D &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) = 0;
- 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) = 0;
+ virtual bool collide_shape(RID p_shape, const Transform3D &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) = 0;
- 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) = 0;
+ virtual bool rest_info(RID p_shape, const Transform3D &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) = 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);
+class PhysicsShapeQueryResult3D : public RefCounted {
+ GDCLASS(PhysicsShapeQueryResult3D, RefCounted);
Vector<PhysicsDirectSpaceState3D::ShapeResult> result;
@@ -335,13 +335,13 @@ public:
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_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform = Transform3D(), 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 void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &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 Transform3D 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;
@@ -352,10 +352,10 @@ public:
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 void area_set_transform(RID p_area, const Transform3D &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 Transform3D 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;
@@ -374,8 +374,8 @@ public:
enum BodyMode {
BODY_MODE_STATIC,
BODY_MODE_KINEMATIC,
- BODY_MODE_RIGID,
- BODY_MODE_CHARACTER
+ BODY_MODE_DYNAMIC,
+ BODY_MODE_DYNAMIC_LOCKED,
};
virtual RID body_create() = 0;
@@ -386,13 +386,13 @@ public:
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_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform = Transform3D(), 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 void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &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 Transform3D 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;
@@ -428,9 +428,6 @@ public:
virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) = 0;
virtual real_t 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,
@@ -486,7 +483,7 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) = 0;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) = 0;
@@ -500,19 +497,14 @@ public:
Vector3 collision_point;
Vector3 collision_normal;
Vector3 collider_velocity;
- int collision_local_shape;
+ int collision_local_shape = 0;
ObjectID collider_id;
RID collider;
- int collider_shape;
+ int collider_shape = 0;
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;
+ virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0;
struct SeparationResult {
real_t collision_depth;
@@ -526,7 +518,7 @@ public:
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, real_t p_margin = 0.001) = 0;
+ virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) = 0;
/* SOFT BODY */
@@ -554,7 +546,7 @@ public:
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 void soft_body_set_transform(RID p_body, const Transform3D &p_transform) = 0;
virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) = 0;
@@ -642,7 +634,7 @@ public:
HINGE_JOINT_FLAG_MAX
};
- virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) = 0;
+ virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform3D &p_hinge_A, RID p_body_B, const Transform3D &p_hinge_B) = 0;
virtual void joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) = 0;
virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) = 0;
@@ -679,7 +671,7 @@ public:
};
- virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A
+ virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) = 0; //reference frame is A
virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) = 0;
virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const = 0;
@@ -693,7 +685,7 @@ public:
CONE_TWIST_MAX
};
- virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A
+ virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) = 0; //reference frame is A
virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) = 0;
virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const = 0;
@@ -734,7 +726,7 @@ public:
G6DOF_JOINT_FLAG_MAX
};
- virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A
+ virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) = 0; //reference frame is A
virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value) = 0;
virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) const = 0;
diff --git a/drivers/dummy/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h
index 9d6be1a802..d4c25b6253 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/servers/rendering/rasterizer_dummy.h
@@ -45,7 +45,7 @@ public:
void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override {}
void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) override {}
void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override {}
- void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override {}
+ void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override {}
void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override {}
void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override {}
void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override {}
@@ -59,7 +59,7 @@ public:
void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override {}
void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {}
void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override {}
- void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) override {}
+ void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override {}
void geometry_instance_free(GeometryInstance *p_geometry_instance) override {}
@@ -145,9 +145,9 @@ public:
void directional_shadow_quality_set(RS::ShadowQuality p_quality) override {}
RID light_instance_create(RID p_light) override { return RID(); }
- void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) override {}
+ void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override {}
void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {}
- 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()) override {}
+ void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &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()) override {}
void light_instance_mark_visible(RID p_light_instance) override {}
RID reflection_atlas_create() override { return RID(); }
@@ -155,7 +155,7 @@ public:
void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {}
RID reflection_probe_instance_create(RID p_probe) override { return RID(); }
- void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) override {}
+ void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override {}
void reflection_probe_release_atlas_index(RID p_instance) override {}
bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; }
bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; }
@@ -163,28 +163,28 @@ public:
bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; }
RID decal_instance_create(RID p_decal) override { return RID(); }
- void decal_instance_set_transform(RID p_decal, const Transform &p_transform) override {}
+ void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
RID lightmap_instance_create(RID p_lightmap) override { return RID(); }
- void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) override {}
+ void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override {}
- RID gi_probe_instance_create(RID p_gi_probe) override { return RID(); }
- void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) override {}
- bool gi_probe_needs_update(RID p_probe) const override { return false; }
- void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects) override {}
+ RID voxel_gi_instance_create(RID p_voxel_gi) override { return RID(); }
+ void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override {}
+ bool voxel_gi_needs_update(RID p_probe) const override { return false; }
+ void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects) override {}
- void gi_probe_set_quality(RS::GIProbeQuality) override {}
+ void voxel_gi_set_quality(RS::VoxelGIQuality) override {}
- void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) override {}
- void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {}
- void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {}
+ void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) override {}
+ void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {}
+ void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {}
void set_scene_pass(uint64_t p_pass) override {}
void set_time(double p_time, double p_step) override {}
void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override {}
RID render_buffers_create() override { return RID(); }
- void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) override {}
+ void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override {}
void gi_set_use_half_resolution(bool p_enable) override {}
void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override {}
@@ -199,8 +199,6 @@ public:
void update() override {}
void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override {}
- bool is_low_end() const override { return true; }
-
RasterizerSceneDummy() {}
~RasterizerSceneDummy() {}
};
@@ -349,7 +347,7 @@ public:
int multimesh_get_instance_count(RID p_multimesh) const override { return 0; }
void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {}
- void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) override {}
+ void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override {}
void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override {}
void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {}
void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {}
@@ -357,7 +355,7 @@ public:
RID multimesh_get_mesh(RID p_multimesh) const override { return RID(); }
AABB multimesh_get_aabb(RID p_multimesh) const override { return AABB(); }
- Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform(); }
+ Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform3D(); }
Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override { return Transform2D(); }
Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
@@ -391,8 +389,8 @@ public:
void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override {}
void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override {}
int skeleton_get_bone_count(RID p_skeleton) const override { return 0; }
- void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) override {}
- Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override { return Transform(); }
+ void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override {}
+ Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override { return Transform3D(); }
void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override {}
Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override { return Transform2D(); }
@@ -484,52 +482,52 @@ public:
AABB decal_get_aabb(RID p_decal) const override { return AABB(); }
- /* GI PROBE API */
+ /* VOXEL GI API */
- RID gi_probe_allocate() override { return RID(); }
- void gi_probe_initialize(RID p_rid) override {}
- void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) override {}
+ RID voxel_gi_allocate() override { return RID(); }
+ void voxel_gi_initialize(RID p_rid) override {}
+ void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) override {}
- AABB gi_probe_get_bounds(RID p_gi_probe) const override { return AABB(); }
- Vector3i gi_probe_get_octree_size(RID p_gi_probe) const override { return Vector3i(); }
- Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const override { return Vector<uint8_t>(); }
- Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const override { return Vector<uint8_t>(); }
- Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const override { return Vector<uint8_t>(); }
+ AABB voxel_gi_get_bounds(RID p_voxel_gi) const override { return AABB(); }
+ Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override { return Vector3i(); }
+ Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const override { return Vector<uint8_t>(); }
+ Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const override { return Vector<uint8_t>(); }
+ Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const override { return Vector<uint8_t>(); }
- Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const override { return Vector<int>(); }
- Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const override { return Transform(); }
+ Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const override { return Vector<int>(); }
+ Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override { return Transform3D(); }
- void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) override {}
- float gi_probe_get_dynamic_range(RID p_gi_probe) const override { return 0; }
+ void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override {}
+ float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override { return 0; }
- void gi_probe_set_propagation(RID p_gi_probe, float p_range) override {}
- float gi_probe_get_propagation(RID p_gi_probe) const override { return 0; }
+ void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override {}
+ float voxel_gi_get_propagation(RID p_voxel_gi) const override { return 0; }
- void gi_probe_set_energy(RID p_gi_probe, float p_range) override {}
- float gi_probe_get_energy(RID p_gi_probe) const override { return 0.0; }
+ void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override {}
+ float voxel_gi_get_energy(RID p_voxel_gi) const override { return 0.0; }
- void gi_probe_set_ao(RID p_gi_probe, float p_ao) override {}
- float gi_probe_get_ao(RID p_gi_probe) const override { return 0; }
+ void voxel_gi_set_ao(RID p_voxel_gi, float p_ao) override {}
+ float voxel_gi_get_ao(RID p_voxel_gi) const override { return 0; }
- void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) override {}
- float gi_probe_get_ao_size(RID p_gi_probe) const override { return 0; }
+ void voxel_gi_set_ao_size(RID p_voxel_gi, float p_strength) override {}
+ float voxel_gi_get_ao_size(RID p_voxel_gi) const override { return 0; }
- void gi_probe_set_bias(RID p_gi_probe, float p_range) override {}
- float gi_probe_get_bias(RID p_gi_probe) const override { return 0.0; }
+ void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override {}
+ float voxel_gi_get_bias(RID p_voxel_gi) const override { return 0.0; }
- void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) override {}
- float gi_probe_get_normal_bias(RID p_gi_probe) const override { return 0.0; }
+ void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override {}
+ float voxel_gi_get_normal_bias(RID p_voxel_gi) const override { return 0.0; }
- void gi_probe_set_interior(RID p_gi_probe, bool p_enable) override {}
- bool gi_probe_is_interior(RID p_gi_probe) const override { return false; }
+ void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override {}
+ bool voxel_gi_is_interior(RID p_voxel_gi) const override { return false; }
- void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) override {}
- bool gi_probe_is_using_two_bounces(RID p_gi_probe) const override { return false; }
+ void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override {}
+ bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override { return false; }
- void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) override {}
- float gi_probe_get_anisotropy_strength(RID p_gi_probe) const override { return 0; }
+ void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) override {}
+ float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const override { return 0; }
- uint32_t gi_probe_get_version(RID p_gi_probe) override { return 0; }
+ uint32_t voxel_gi_get_version(RID p_voxel_gi) override { return 0; }
/* LIGHTMAP CAPTURE */
RID lightmap_allocate() override { return RID(); }
@@ -548,11 +546,16 @@ public:
void lightmap_set_probe_capture_update_speed(float p_speed) override {}
float lightmap_get_probe_capture_update_speed() const override { return 0; }
+ /* OCCLUDER */
+
+ void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {}
+
/* PARTICLES */
RID particles_allocate() override { return RID(); }
void particles_initialize(RID p_rid) override {}
- void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override {}
+ void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override {}
+ void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override {}
void particles_set_emitting(RID p_particles, bool p_emitting) override {}
void particles_set_amount(RID p_particles, int p_amount) override {}
void particles_set_lifetime(RID p_particles, float p_lifetime) override {}
@@ -565,10 +568,17 @@ public:
void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override {}
void particles_set_process_material(RID p_particles, RID p_material) override {}
void particles_set_fixed_fps(RID p_particles, int p_fps) override {}
+ void particles_set_interpolate(RID p_particles, bool p_enable) override {}
void particles_set_fractional_delta(RID p_particles, bool p_enable) override {}
void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) override {}
- void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) override {}
+ void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) override {}
void particles_set_collision_base_size(RID p_particles, float p_size) override {}
+
+ void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override {}
+
+ void particles_set_trails(RID p_particles, bool p_enable, float p_length) override {}
+ void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) override {}
+
void particles_restart(RID p_particles) override {}
void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) override {}
@@ -580,7 +590,7 @@ public:
AABB particles_get_current_aabb(RID p_particles) override { return AABB(); }
AABB particles_get_aabb(RID p_particles) const override { return AABB(); }
- void particles_set_emission_transform(RID p_particles, const Transform &p_transform) override {}
+ void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override {}
bool particles_get_emitting(RID p_particles) override { return false; }
int particles_get_draw_passes(RID p_particles) const override { return 0; }
@@ -589,6 +599,8 @@ public:
void particles_add_collision(RID p_particles, RID p_instance) override {}
void particles_remove_collision(RID p_particles, RID p_instance) override {}
+ void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) override {}
+
void update_particles() override {}
/* PARTICLES COLLISION */
@@ -609,9 +621,18 @@ public:
bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; }
RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override { return RID(); }
- RID particles_collision_instance_create(RID p_collision) override { return RID(); };
- void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) override{};
- void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override{};
+ RID particles_collision_instance_create(RID p_collision) override { return RID(); }
+ void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override {}
+ void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override {}
+
+ /* VISIBILITY NOTIFIER */
+ virtual RID visibility_notifier_allocate() override { return RID(); }
+ virtual void visibility_notifier_initialize(RID p_notifier) override {}
+ virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) override {}
+ virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) override {}
+
+ virtual AABB visibility_notifier_get_aabb(RID p_notifier) const override { return AABB(); }
+ virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) override {}
/* GLOBAL VARIABLES */
@@ -637,7 +658,7 @@ public:
RID render_target_create() override { return RID(); }
void render_target_set_position(RID p_render_target, int p_x, int p_y) override {}
- void render_target_set_size(RID p_render_target, int p_width, int p_height) override {}
+ void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override {}
RID render_target_get_texture(RID p_render_target) override { return RID(); }
void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override {}
void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override {}
@@ -652,6 +673,7 @@ public:
void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override {}
Rect2i render_target_get_sdf_rect(RID p_render_target) const override { return Rect2i(); }
+ void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override {}
RS::InstanceType get_base_type(RID p_rid) const override { return RS::INSTANCE_NONE; }
bool free(RID p_rid) override {
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 7f3fc2f8f4..5703737252 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -44,10 +44,10 @@ void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas
memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::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);
+ _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, true);
}
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);
+ _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true);
}
RendererCanvasRender::Item *list = nullptr;
@@ -104,98 +104,7 @@ void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_PtrOwner<Rende
} while (ysort_owner && ysort_owner->sort_y);
}
-void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::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 = ci->xform;
- if (snapping_2d_transforms_to_pixel) {
- xform.elements[2] = xform.elements[2].floor();
- }
- xform = p_transform * 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.intersection(global_rect);
- } else {
- ci->final_clip_rect = global_rect;
- }
- ci->final_clip_rect.position = ci->final_clip_rect.position.round();
- ci->final_clip_rect.size = ci->final_clip_rect.size.round();
- ci->final_clip_owner = ci;
-
- } else {
- 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;
- }
-
- RendererCanvasRender::Item *canvas_group_from = nullptr;
- bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
- if (use_canvas_group) {
- int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
- canvas_group_from = z_last_list[zidx];
- }
-
- for (int i = 0; i < child_item_count; i++) {
- if ((!child_items[i]->behind && !use_canvas_group) || (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 RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform) {
if (ci->copy_back_buffer) {
ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
}
@@ -229,7 +138,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
// We have two choices now, if user has drawn something, we must assume users wants to draw the "mask", so compute the size based on this.
// If nothing has been drawn, we just take it over and draw it ourselves.
if (ci->canvas_group->fit_empty && (ci->commands == nullptr ||
- (ci->commands->next == nullptr && ci->commands->type == Item::Command::TYPE_RECT && (static_cast<Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) {
+ (ci->commands->next == nullptr && ci->commands->type == RendererCanvasCull::Item::Command::TYPE_RECT && (static_cast<RendererCanvasCull::Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) {
// No commands, or sole command is the one used to draw, so we (re)create the draw command.
ci->clear();
@@ -264,42 +173,163 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
}
}
- if (ci->update_when_visible) {
- RenderingServerDefault::redraw_request();
+ if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
+ //something to draw?
+
+ if (ci->update_when_visible) {
+ RenderingServerDefault::redraw_request();
+ }
+
+ if (ci->commands != nullptr) {
+ 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;
+ }
+
+ if (ci->visibility_notifier) {
+ if (!ci->visibility_notifier->visible_element.in_list()) {
+ visibility_notifier_list.add(&ci->visibility_notifier->visible_element);
+ ci->visibility_notifier->just_visible = true;
+ }
+
+ ci->visibility_notifier->visible_in_frame = RSG::rasterizer->get_frame_number();
+ }
}
+}
- 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;
+void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort) {
+ Item *ci = p_canvas_item;
- int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
+ if (!ci->visible) {
+ return;
+ }
- if (z_last_list[zidx]) {
- z_last_list[zidx]->next = ci;
- z_last_list[zidx] = ci;
+ if (ci->children_order_dirty) {
+ ci->child_items.sort_custom<ItemIndexSort>();
+ ci->children_order_dirty = false;
+ }
- } else {
- z_list[zidx] = ci;
- z_last_list[zidx] = ci;
+ Rect2 rect = ci->get_rect();
+
+ if (ci->visibility_notifier) {
+ if (ci->visibility_notifier->area.size != Vector2()) {
+ rect = rect.merge(ci->visibility_notifier->area);
}
+ }
+
+ Transform2D xform = ci->xform;
+ if (snapping_2d_transforms_to_pixel) {
+ xform.elements[2] = xform.elements[2].floor();
+ }
+ xform = p_transform * xform;
+
+ Rect2 global_rect = xform.xform(rect);
+ global_rect.position += p_clip_rect.position;
- ci->z_final = p_z;
+ if (ci->use_parent_material && p_material_owner) {
+ ci->material_owner = p_material_owner;
+ } else {
+ p_material_owner = ci;
+ ci->material_owner = nullptr;
+ }
- ci->next = 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;
}
- for (int i = 0; i < child_item_count; i++) {
- if (child_items[i]->behind || use_canvas_group || (ci->sort_y && child_items[i]->sort_y)) {
- continue;
+ 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.intersection(global_rect);
+ } else {
+ ci->final_clip_rect = global_rect;
}
- 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);
+ ci->final_clip_rect.position = ci->final_clip_rect.position.round();
+ ci->final_clip_rect.size = ci->final_clip_rect.size.round();
+ ci->final_clip_owner = ci;
+
+ } else {
+ ci->final_clip_owner = p_canvas_clip;
+ }
+
+ 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;
+ }
+
+ if (ci->sort_y) {
+ if (allow_y_sort) {
+ 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 + 1;
+ child_items = (Item **)alloca(child_item_count * sizeof(Item *));
+
+ child_items[0] = ci;
+ int i = 1;
+ _collect_ysort_children(ci, Transform2D(), p_material_owner, child_items, i);
+ ci->ysort_xform = ci->xform.affine_inverse();
+
+ SortArray<Item *, ItemPtrSort> sorter;
+ sorter.sort(child_items, child_item_count);
+
+ for (i = 0; i < child_item_count; i++) {
+ _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, false);
+ }
} 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);
+ RendererCanvasRender::Item *canvas_group_from = nullptr;
+ bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
+ if (use_canvas_group) {
+ int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
+ canvas_group_from = z_last_list[zidx];
+ }
+
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
+ }
+ } else {
+ RendererCanvasRender::Item *canvas_group_from = nullptr;
+ bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
+ if (use_canvas_group) {
+ int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
+ canvas_group_from = z_last_list[zidx];
+ }
+
+ for (int i = 0; i < child_item_count; i++) {
+ if (!child_items[i]->behind && !use_canvas_group) {
+ continue;
+ }
+ _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, true);
+ }
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
+ for (int i = 0; i < child_item_count; i++) {
+ if (child_items[i]->behind || use_canvas_group) {
+ continue;
+ }
+ _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, true);
}
}
}
@@ -923,10 +953,15 @@ void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transfo
void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
+ ERR_FAIL_COND(!p_mesh.is_valid());
Item::CommandMesh *m = canvas_item->alloc_command<Item::CommandMesh>();
ERR_FAIL_COND(!m);
m->mesh = p_mesh;
+ if (canvas_item->skeleton.is_valid()) {
+ m->mesh_instance = RSG::storage->mesh_instance_create(p_mesh);
+ RSG::storage->mesh_instance_set_skeleton(m->mesh_instance, canvas_item->skeleton);
+ }
m->texture = p_texture;
@@ -996,8 +1031,30 @@ void RendererCanvasCull::canvas_item_set_z_as_relative_to_parent(RID p_item, boo
void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
-
+ if (canvas_item->skeleton == p_skeleton) {
+ return;
+ }
canvas_item->skeleton = p_skeleton;
+
+ Item::Command *c = canvas_item->commands;
+
+ while (c) {
+ if (c->type == Item::Command::TYPE_MESH) {
+ Item::CommandMesh *cm = static_cast<Item::CommandMesh *>(c);
+ if (canvas_item->skeleton.is_valid()) {
+ if (cm->mesh_instance.is_null()) {
+ cm->mesh_instance = RSG::storage->mesh_instance_create(cm->mesh);
+ }
+ RSG::storage->mesh_instance_set_skeleton(cm->mesh_instance, canvas_item->skeleton);
+ } else {
+ if (cm->mesh_instance.is_valid()) {
+ RSG::storage->free(cm->mesh_instance);
+ cm->mesh_instance = RID();
+ }
+ }
+ }
+ c = c->next;
+ }
}
void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) {
@@ -1057,6 +1114,26 @@ void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_
canvas_item->use_parent_material = p_enable;
}
+void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable) {
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ if (p_enable) {
+ if (!canvas_item->visibility_notifier) {
+ canvas_item->visibility_notifier = visibility_notifier_allocator.alloc();
+ }
+ canvas_item->visibility_notifier->area = p_area;
+ canvas_item->visibility_notifier->enter_callable = p_enter_callable;
+ canvas_item->visibility_notifier->exit_callable = p_exit_callable;
+
+ } else {
+ if (canvas_item->visibility_notifier) {
+ visibility_notifier_allocator.free(canvas_item->visibility_notifier);
+ canvas_item->visibility_notifier = nullptr;
+ }
+ }
+}
+
void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
@@ -1439,6 +1516,44 @@ void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS::
ci->texture_repeat = p_repeat;
}
+void RendererCanvasCull::update_visibility_notifiers() {
+ SelfList<Item::VisibilityNotifierData> *E = visibility_notifier_list.first();
+ while (E) {
+ SelfList<Item::VisibilityNotifierData> *N = E->next();
+
+ Item::VisibilityNotifierData *visibility_notifier = E->self();
+ if (visibility_notifier->just_visible) {
+ visibility_notifier->just_visible = false;
+
+ if (!visibility_notifier->enter_callable.is_null()) {
+ if (RSG::threaded) {
+ visibility_notifier->enter_callable.call_deferred(nullptr, 0);
+ } else {
+ Callable::CallError ce;
+ Variant ret;
+ visibility_notifier->enter_callable.call(nullptr, 0, ret, ce);
+ }
+ }
+ } else {
+ if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) {
+ visibility_notifier_list.remove(E);
+
+ if (!visibility_notifier->exit_callable.is_null()) {
+ if (RSG::threaded) {
+ visibility_notifier->exit_callable.call_deferred(nullptr, 0);
+ } else {
+ Callable::CallError ce;
+ Variant ret;
+ visibility_notifier->exit_callable.call(nullptr, 0, ret, ce);
+ }
+ }
+ }
+ }
+
+ E = N;
+ }
+}
+
bool RendererCanvasCull::free(RID p_rid) {
if (canvas_owner.owns(p_rid)) {
Canvas *canvas = canvas_owner.getornull(p_rid);
@@ -1493,6 +1608,10 @@ bool RendererCanvasCull::free(RID p_rid) {
canvas_item->child_items[i]->parent = RID();
}
+ if (canvas_item->visibility_notifier != nullptr) {
+ visibility_notifier_allocator.free(canvas_item->visibility_notifier);
+ }
+
/*
if (canvas_item->material) {
canvas_item->material->owners.erase(canvas_item);
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index b71f8e5a9a..661216cad3 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -31,6 +31,7 @@
#ifndef RENDERING_SERVER_CANVAS_CULL_H
#define RENDERING_SERVER_CANVAS_CULL_H
+#include "core/templates/paged_allocator.h"
#include "renderer_compositor.h"
#include "renderer_viewport.h"
@@ -55,6 +56,20 @@ public:
Vector<Item *> child_items;
+ struct VisibilityNotifierData {
+ Rect2 area;
+ Callable enter_callable;
+ Callable exit_callable;
+ bool just_visible = false;
+ uint64_t visible_in_frame = 0;
+ SelfList<VisibilityNotifierData> visible_element;
+ VisibilityNotifierData() :
+ visible_element(this) {
+ }
+ };
+
+ VisibilityNotifierData *visibility_notifier = nullptr;
+
Item() {
children_order_dirty = true;
E = nullptr;
@@ -156,9 +171,14 @@ public:
bool sdf_used = false;
bool snapping_2d_transforms_to_pixel = false;
+ PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator;
+ SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list;
+
+ _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform);
+
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, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
- void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner);
+ void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort);
RendererCanvasRender::Item **z_list;
RendererCanvasRender::Item **z_last_list;
@@ -224,6 +244,8 @@ public:
void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
+ void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable);
+
void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false);
RID canvas_light_allocate();
@@ -283,6 +305,8 @@ public:
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 update_visibility_notifiers();
+
bool free(RID p_rid);
RendererCanvasCull();
~RendererCanvasCull();
diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h
index f08986b021..0266e137c0 100644
--- a/servers/rendering/renderer_canvas_render.h
+++ b/servers/rendering/renderer_canvas_render.h
@@ -246,10 +246,16 @@ public:
RID mesh;
Transform2D transform;
Color modulate;
+ RID mesh_instance;
RID texture;
CommandMesh() { type = TYPE_MESH; }
+ ~CommandMesh() {
+ if (mesh_instance.is_valid()) {
+ RendererStorage::base_singleton->free(mesh_instance);
+ }
+ }
};
struct CommandMultiMesh : public Command {
@@ -262,7 +268,6 @@ public:
struct CommandParticles : public Command {
RID particles;
-
RID texture;
CommandParticles() { type = TYPE_PARTICLES; }
@@ -415,7 +420,6 @@ public:
if (found_xform) {
r = xf.xform(r);
- found_xform = false;
}
if (first) {
diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp
index 8861522d34..80c4625261 100644
--- a/servers/rendering/renderer_compositor.cpp
+++ b/servers/rendering/renderer_compositor.cpp
@@ -30,6 +30,7 @@
#include "renderer_compositor.h"
+#include "core/config/project_settings.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -39,4 +40,12 @@ RendererCompositor *RendererCompositor::create() {
return _create_func();
}
+bool RendererCompositor::is_xr_enabled() const {
+ return xr_enabled;
+}
+
+RendererCompositor::RendererCompositor() {
+ xr_enabled = GLOBAL_GET("rendering/xr/enabled");
+}
+
RendererCanvasRender *RendererCanvasRender::singleton = nullptr;
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index 919ae2c6da..eabdebf4b3 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -40,7 +40,31 @@
#include "servers/rendering/renderer_storage.h"
#include "servers/rendering_server.h"
+struct BlitToScreen {
+ RID render_target;
+ Rect2i rect;
+
+ struct {
+ bool use_layer = false;
+ uint32_t layer = 0;
+ } multi_view;
+
+ struct {
+ //lens distorted parameters for VR
+ bool apply = false;
+ Vector2 eye_center;
+ float k1 = 0.0;
+ float k2 = 0.0;
+
+ float upscale = 1.0;
+ float aspect_ratio = 1.0;
+ } lens_distortion;
+};
+
class RendererCompositor {
+private:
+ bool xr_enabled = false;
+
protected:
static RendererCompositor *(*_create_func)();
@@ -56,12 +80,6 @@ public:
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;
@@ -71,7 +89,9 @@ public:
virtual float get_frame_delta_time() const = 0;
virtual bool is_low_end() const = 0;
+ virtual bool is_xr_enabled() const;
+ RendererCompositor();
virtual ~RendererCompositor() {}
};
diff --git a/servers/rendering/renderer_rd/SCsub b/servers/rendering/renderer_rd/SCsub
index 9c95f538ac..64e613ab91 100644
--- a/servers/rendering/renderer_rd/SCsub
+++ b/servers/rendering/renderer_rd/SCsub
@@ -5,4 +5,5 @@ Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
SConscript("forward_clustered/SCsub")
+SConscript("forward_mobile/SCsub")
SConscript("shaders/SCsub")
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
index 0fdd864d47..b952ecbff0 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
@@ -86,13 +86,13 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
Vector<uint8_t> vertex_data;
vertex_data.resize(sizeof(float) * icosphere_vertex_count * 3);
- copymem(vertex_data.ptrw(), icosphere_vertices, vertex_data.size());
+ memcpy(vertex_data.ptrw(), icosphere_vertices, vertex_data.size());
sphere_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
index_data.resize(sizeof(uint32_t) * icosphere_triangle_count * 3);
- copymem(index_data.ptrw(), icosphere_triangle_indices, index_data.size());
+ memcpy(index_data.ptrw(), icosphere_triangle_indices, index_data.size());
sphere_index_buffer = RD::get_singleton()->index_buffer_create(icosphere_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data);
@@ -130,13 +130,13 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
Vector<uint8_t> vertex_data;
vertex_data.resize(sizeof(float) * cone_vertex_count * 3);
- copymem(vertex_data.ptrw(), cone_vertices, vertex_data.size());
+ memcpy(vertex_data.ptrw(), cone_vertices, vertex_data.size());
cone_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
index_data.resize(sizeof(uint32_t) * cone_triangle_count * 3);
- copymem(index_data.ptrw(), cone_triangle_indices, index_data.size());
+ memcpy(index_data.ptrw(), cone_triangle_indices, index_data.size());
cone_index_buffer = RD::get_singleton()->index_buffer_create(cone_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data);
@@ -184,13 +184,13 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() {
Vector<uint8_t> vertex_data;
vertex_data.resize(sizeof(float) * box_vertex_count * 3);
- copymem(vertex_data.ptrw(), box_vertices, vertex_data.size());
+ memcpy(vertex_data.ptrw(), box_vertices, vertex_data.size());
box_vertex_buffer = RD::get_singleton()->vertex_buffer_create(vertex_data.size(), vertex_data);
Vector<uint8_t> index_data;
index_data.resize(sizeof(uint32_t) * box_triangle_count * 3);
- copymem(index_data.ptrw(), box_triangle_indices, index_data.size());
+ memcpy(index_data.ptrw(), box_triangle_indices, index_data.size());
box_index_buffer = RD::get_singleton()->index_buffer_create(box_triangle_count * 3, RD::INDEX_BUFFER_FORMAT_UINT32, index_data);
@@ -374,7 +374,7 @@ void ClusterBuilderRD::setup(Size2i p_screen_size, uint32_t p_max_elements, RID
}
}
-void ClusterBuilderRD::begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y) {
+void ClusterBuilderRD::begin(const Transform3D &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y) {
view_xform = p_view_transform.affine_inverse();
projection = p_cam_projection;
z_near = projection.get_z_near();
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h
index dc1707b534..ebb81abdad 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.h
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.h
@@ -167,7 +167,7 @@ private:
uint32_t render_element_count = 0;
uint32_t render_element_max = 0;
- Transform view_xform;
+ Transform3D view_xform;
CameraMatrix adjusted_projection;
CameraMatrix projection;
float z_far = 0;
@@ -220,9 +220,9 @@ private:
public:
void setup(Size2i p_screen_size, uint32_t p_max_elements, RID p_depth_buffer, RID p_depth_buffer_sampler, RID p_color_buffer);
- void begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y);
+ void begin(const Transform3D &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y);
- _FORCE_INLINE_ void add_light(LightType p_type, const Transform &p_transform, float p_radius, float p_spot_aperture) {
+ _FORCE_INLINE_ void add_light(LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) {
if (p_type == LIGHT_TYPE_OMNI && cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT] == max_elements_by_type) {
return; //max number elements reached
}
@@ -232,7 +232,7 @@ public:
RenderElementData &e = render_elements[render_element_count];
- Transform xform = view_xform * p_transform;
+ Transform3D xform = view_xform * p_transform;
float radius = xform.basis.get_uniform_scale();
if (radius > 0.98 || radius < 1.02) {
@@ -317,7 +317,7 @@ public:
render_element_count++;
}
- _FORCE_INLINE_ void add_box(BoxType p_box_type, const Transform &p_transform, const Vector3 &p_half_extents) {
+ _FORCE_INLINE_ void add_box(BoxType p_box_type, const Transform3D &p_transform, const Vector3 &p_half_extents) {
if (p_box_type == BOX_TYPE_DECAL && cluster_count_by_type[ELEMENT_TYPE_DECAL] == max_elements_by_type) {
return; //max number elements reached
}
@@ -326,7 +326,7 @@ public:
}
RenderElementData &e = render_elements[render_element_count];
- Transform xform = view_xform * p_transform;
+ Transform3D xform = view_xform * p_transform;
//extract scale and scale the matrix by it, makes things simpler
Vector3 scale = p_half_extents;
diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp
index bc304aedd8..4fd5520e56 100644
--- a/servers/rendering/renderer_rd/effects_rd.cpp
+++ b/servers/rendering/renderer_rd/effects_rd.cpp
@@ -34,6 +34,7 @@
#include "core/math/math_defs.h"
#include "core/os/os.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "thirdparty/misc/cubemap_coeffs.h"
static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) {
@@ -226,7 +227,7 @@ RID EffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_te
}
void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) {
- zeromem(&copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
+ memset(&copy_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant));
copy_to_fb.push_constant.use_section = true;
copy_to_fb.push_constant.section[0] = p_uv_rect.position.x;
@@ -247,7 +248,7 @@ void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer
}
void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary) {
- zeromem(&copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
+ memset(&copy_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant));
if (p_flip_y) {
copy_to_fb.push_constant.flip_y = true;
@@ -275,7 +276,7 @@ void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer,
}
void EffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
if (p_flip_y) {
copy.push_constant.flags |= COPY_FLAG_FLIP_Y;
}
@@ -309,7 +310,7 @@ void EffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const
}
void EffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
copy.push_constant.section[0] = 0;
copy.push_constant.section[1] = 0;
@@ -329,7 +330,7 @@ void EffectsRD::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama,
}
void EffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
if (p_flip_y) {
copy.push_constant.flags |= COPY_FLAG_FLIP_Y;
}
@@ -353,7 +354,7 @@ void EffectsRD::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_
}
void EffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
if (p_flip_y) {
copy.push_constant.flags |= COPY_FLAG_FLIP_Y;
}
@@ -375,7 +376,7 @@ void EffectsRD::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture,
}
void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
copy.push_constant.section[0] = 0;
copy.push_constant.section[1] = 0;
@@ -397,7 +398,7 @@ void EffectsRD::set_color(RID p_dest_texture, const Color &p_color, const Rect2i
}
void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
uint32_t base_flags = 0;
copy.push_constant.section[0] = p_region.position.x;
@@ -430,7 +431,7 @@ void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back
}
void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW;
uint32_t base_flags = 0;
@@ -657,7 +658,7 @@ void EffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_bas
}
void EffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) {
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
copy.push_constant.section[0] = 0;
copy.push_constant.section[1] = 0;
@@ -694,7 +695,7 @@ void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffe
}
void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) {
- zeromem(&tonemap.push_constant, sizeof(TonemapPushConstant));
+ memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant));
tonemap.push_constant.use_bcs = p_settings.use_bcs;
tonemap.push_constant.bcs[0] = p_settings.brightness;
@@ -732,6 +733,11 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone
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;
+ if (p_settings.view_count > 1) {
+ // Use MULTIVIEW versions
+ mode += 4;
+ }
+
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);
@@ -934,10 +940,10 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass) {
- RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, ssao.gather_uniform_set, 0);
+void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) {
+ RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0);
if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) {
- RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, ssao.importance_map_uniform_set, 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1);
}
for (int i = 0; i < 4; i++) {
@@ -960,7 +966,7 @@ void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID>
RD::get_singleton()->compute_list_add_barrier(p_compute_list);
}
-void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &p_depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets) {
+void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &p_depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set) {
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->draw_command_begin_label("SSAO");
/* FIRST PASS */
@@ -990,7 +996,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
u.ids.push_back(p_depth_mipmaps[3]);
uniforms.push_back(u);
}
- ssao.downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, 2), 2);
+ r_downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, 2), 2);
}
float depth_linearize_mul = -p_projection.matrix[3][2];
@@ -1025,7 +1031,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_depth_mipmaps[0]), 1);
if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssao.downsample_uniform_set, 2);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, r_downsample_uniform_set, 2);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.downsample_push_constant, sizeof(SSAODownsamplePushConstant));
@@ -1109,7 +1115,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
u.ids.push_back(ssao.gather_constants_buffer);
uniforms.push_back(u);
}
- ssao.gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0), 0);
+ r_gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0), 0);
}
if (p_invalidate_uniform_sets) {
@@ -1136,7 +1142,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
u.ids.push_back(ssao.importance_map_load_counter);
uniforms.push_back(u);
}
- ssao.importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 2), 1);
+ r_importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 2), 1);
}
if (p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) {
@@ -1147,7 +1153,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
ssao.importance_map_push_constant.power = p_settings.power;
//base pass
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_BASE]);
- gather_ssao(compute_list, p_ao_pong_slices, p_settings, true);
+ gather_ssao(compute_list, p_ao_pong_slices, p_settings, true, r_gather_uniform_set, RID());
//generate importance map
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GENERATE_IMPORTANCE_MAP]);
@@ -1178,7 +1184,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER]);
}
- gather_ssao(compute_list, p_ao_slices, p_settings, false);
+ gather_ssao(compute_list, p_ao_slices, p_settings, false, r_gather_uniform_set, r_importance_map_uniform_set);
RD::get_singleton()->draw_command_end_label(); // Gather SSAO
}
@@ -1294,7 +1300,7 @@ void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size
}
void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
- zeromem(&roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
+ memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
roughness.push_constant.roughness = p_roughness;
@@ -1365,15 +1371,18 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap,
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {
+void EffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const CameraMatrix *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {
SkyPushConstant sky_push_constant;
- zeromem(&sky_push_constant, sizeof(SkyPushConstant));
+ memset(&sky_push_constant, 0, sizeof(SkyPushConstant));
- sky_push_constant.proj[0] = p_camera.matrix[2][0];
- sky_push_constant.proj[1] = p_camera.matrix[0][0];
- sky_push_constant.proj[2] = p_camera.matrix[2][1];
- sky_push_constant.proj[3] = p_camera.matrix[1][1];
+ for (uint32_t v = 0; v < p_view_count; v++) {
+ // We only need key components of our projection matrix
+ sky_push_constant.projections[v][0] = p_projections[v].matrix[2][0];
+ sky_push_constant.projections[v][1] = p_projections[v].matrix[0][0];
+ sky_push_constant.projections[v][2] = p_projections[v].matrix[2][1];
+ sky_push_constant.projections[v][3] = p_projections[v].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;
@@ -1401,19 +1410,19 @@ void EffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_
RD::get_singleton()->draw_list_draw(draw_list, true);
}
-void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) {
+void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) {
ResolvePushConstant push_constant;
push_constant.screen_size[0] = p_screen_size.x;
push_constant.screen_size[1] = p_screen_size.y;
push_constant.samples = p_samples;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[p_source_giprobe.is_valid() ? RESOLVE_MODE_GI_GIPROBE : RESOLVE_MODE_GI]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[p_source_voxel_gi.is_valid() ? RESOLVE_MODE_GI_VOXEL_GI : RESOLVE_MODE_GI]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_pair(p_source_depth, p_source_normal_roughness), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_dest_depth, p_dest_normal_roughness), 1);
- if (p_source_giprobe.is_valid()) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_giprobe), 2);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_giprobe), 3);
+ if (p_source_voxel_gi.is_valid()) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_voxel_gi), 2);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_voxel_gi), 3);
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ResolvePushConstant));
@@ -1510,7 +1519,7 @@ EffectsRD::EffectsRD() {
copy_modes.push_back("\n#define MODE_CUBEMAP_ARRAY_TO_PANORAMA\n");
copy.shader.initialize(copy_modes);
- zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ memset(&copy.push_constant, 0, sizeof(CopyPushConstant));
copy.shader_version = copy.shader.version_create();
for (int i = 0; i < COPY_MODE_MAX; i++) {
@@ -1553,12 +1562,29 @@ EffectsRD::EffectsRD() {
tonemap_modes.push_back("\n#define USE_1D_LUT\n");
tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
+ // multiview versions of our shaders
+ tonemap_modes.push_back("\n#define MULTIVIEW\n");
+ tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n");
+ tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_1D_LUT\n");
+ tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n");
+
tonemap.shader.initialize(tonemap_modes);
+ if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_NORMAL_MULTIVIEW, false);
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false);
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false);
+ tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, false);
+ }
+
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);
+ if (tonemap.shader.is_variant_enabled(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);
+ } else {
+ tonemap.pipelines[i].clear();
+ }
}
}
@@ -1907,7 +1933,7 @@ EffectsRD::EffectsRD() {
{
Vector<String> resolve_modes;
resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n");
- resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define GIPROBE_RESOLVE\n");
+ resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define VOXEL_GI_RESOLVE\n");
resolve.shader.initialize(resolve_modes);
diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h
index 1ba25e301b..8b31ffbbd0 100644
--- a/servers/rendering/renderer_rd/effects_rd.h
+++ b/servers/rendering/renderer_rd/effects_rd.h
@@ -55,6 +55,7 @@
#include "servers/rendering/renderer_rd/shaders/ssao_interleave.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/tonemap.glsl.gen.h"
+#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
@@ -170,6 +171,12 @@ class EffectsRD {
TONEMAP_MODE_BICUBIC_GLOW_FILTER,
TONEMAP_MODE_1D_LUT,
TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT,
+
+ TONEMAP_MODE_NORMAL_MULTIVIEW,
+ TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW,
+ TONEMAP_MODE_1D_LUT_MULTIVIEW,
+ TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW,
+
TONEMAP_MODE_MAX
};
@@ -378,12 +385,10 @@ class EffectsRD {
SSAODownsamplePushConstant downsample_push_constant;
SsaoDownsampleShaderRD downsample_shader;
RID downsample_shader_version;
- RID downsample_uniform_set;
SSAOGatherPushConstant gather_push_constant;
SsaoShaderRD gather_shader;
RID gather_shader_version;
- RID gather_uniform_set;
RID gather_constants_buffer;
bool gather_initialized = false;
@@ -391,7 +396,6 @@ class EffectsRD {
SsaoImportanceMapShaderRD importance_map_shader;
RID importance_map_shader_version;
RID importance_map_load_counter;
- RID importance_map_uniform_set;
RID counter_uniform_set;
SSAOBlurPushConstant blur_push_constant;
@@ -453,12 +457,12 @@ class EffectsRD {
} filter;
struct SkyPushConstant {
- float orientation[12];
- float proj[4];
- float position[3];
- float multiplier;
- float time;
- float pad[3];
+ float orientation[12]; // 48 - 48
+ float projections[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 64, if we ever need more then 3 we should consider adding this to a set.
+ float position[3]; // 12 - 92
+ float multiplier; // 4 - 96
+ float time; // 4 - 100
+ float pad[3]; // 12 - 112
};
enum SpecularMergeMode {
@@ -585,7 +589,7 @@ class EffectsRD {
enum ResolveMode {
RESOLVE_MODE_GI,
- RESOLVE_MODE_GI_GIPROBE,
+ RESOLVE_MODE_GI_VOXEL_GI,
RESOLVE_MODE_MAX
};
@@ -714,6 +718,7 @@ public:
bool use_fxaa = false;
bool use_debanding = false;
Vector2i texture_size;
+ uint32_t view_count = 1;
};
struct SSAOSettings {
@@ -738,19 +743,19 @@ public:
void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings);
- void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass);
- void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets);
+ void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set);
+ void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set);
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_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position);
+ void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const CameraMatrix *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position);
void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, 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);
- void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+ void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
void sort_buffer(RID p_uniform_set, int p_size);
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 9be0dc0d15..1653453c5c 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -93,8 +93,8 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_specular()
}
}
-void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_giprobe() {
- if (!giprobe_buffer.is_valid()) {
+void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_voxelgi() {
+ if (!voxelgi_buffer.is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8G8_UINT;
tf.width = width;
@@ -105,41 +105,41 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_giprobe()
RD::TextureFormat tf_aa = tf;
tf_aa.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
tf_aa.samples = texture_samples;
- giprobe_buffer_msaa = RD::get_singleton()->texture_create(tf_aa, RD::TextureView());
+ voxelgi_buffer_msaa = RD::get_singleton()->texture_create(tf_aa, RD::TextureView());
} else {
tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
}
tf.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT;
- giprobe_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ voxelgi_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
Vector<RID> fb;
if (msaa != RS::VIEWPORT_MSAA_DISABLED) {
fb.push_back(depth_msaa);
fb.push_back(normal_roughness_buffer_msaa);
- fb.push_back(giprobe_buffer_msaa);
+ fb.push_back(voxelgi_buffer_msaa);
} else {
fb.push_back(depth);
fb.push_back(normal_roughness_buffer);
- fb.push_back(giprobe_buffer);
+ fb.push_back(voxelgi_buffer);
}
- depth_normal_roughness_giprobe_fb = RD::get_singleton()->framebuffer_create(fb);
+ depth_normal_roughness_voxelgi_fb = RD::get_singleton()->framebuffer_create(fb);
}
}
void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
- if (giprobe_buffer != RID()) {
- RD::get_singleton()->free(giprobe_buffer);
- giprobe_buffer = RID();
+ if (voxelgi_buffer != RID()) {
+ RD::get_singleton()->free(voxelgi_buffer);
+ voxelgi_buffer = RID();
- if (giprobe_buffer_msaa.is_valid()) {
- RD::get_singleton()->free(giprobe_buffer_msaa);
- giprobe_buffer_msaa = RID();
+ if (voxelgi_buffer_msaa.is_valid()) {
+ RD::get_singleton()->free(voxelgi_buffer_msaa);
+ voxelgi_buffer_msaa = RID();
}
- depth_normal_roughness_giprobe_fb = RID();
+ depth_normal_roughness_voxelgi_fb = RID();
}
if (color_msaa.is_valid()) {
@@ -183,9 +183,11 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
}
}
-void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) {
+void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
clear();
+ ERR_FAIL_COND_MSG(p_view_count != 1, "Multiple views is currently not supported in this renderer, please use the mobile renderer for VR support");
+
msaa = p_msaa;
width = p_width;
@@ -284,8 +286,6 @@ void RenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferData
fb.push_back(rb->normal_roughness_buffer_msaa);
rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb);
}
-
- _render_buffers_clear_uniform_set(rb);
}
RendererSceneRenderRD::RenderBufferData *RenderForwardClustered::_create_render_buffer_data() {
@@ -400,8 +400,8 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
} break;
- case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: {
- shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE;
+ case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: {
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI;
} break;
case PASS_MODE_DEPTH_MATERIAL: {
shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
@@ -466,6 +466,10 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant));
uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : element_info.repeat;
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) {
+ instance_count /= surf->owner->trail_steps;
+ }
+
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
i += element_info.repeat - 1; //skip equal elements
}
@@ -496,8 +500,8 @@ void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_lis
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
_render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
} break;
- case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: {
- _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: {
+ _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
} break;
case PASS_MODE_DEPTH_MATERIAL: {
_render_list_template<PASS_MODE_DEPTH_MATERIAL>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
@@ -534,21 +538,21 @@ void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_p
}
}
-void RenderForwardClustered::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
- //CameraMatrix projection = p_cam_projection;
+void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
+ //CameraMatrix projection = p_render_data->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;
+ CameraMatrix projection = correction * p_render_data->cam_projection;
//store camera into ubo
RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix);
RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
- RendererStorageRD::store_transform(p_cam_transform, scene_state.ubo.camera_matrix);
- RendererStorageRD::store_transform(p_cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix);
+ RendererStorageRD::store_transform(p_render_data->cam_transform, scene_state.ubo.camera_matrix);
+ RendererStorageRD::store_transform(p_render_data->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.z_far = p_render_data->z_far;
+ scene_state.ubo.z_near = p_render_data->z_near;
scene_state.ubo.pancake_shadows = p_pancake_shadows;
@@ -566,17 +570,17 @@ void RenderForwardClustered::_setup_environment(RID p_environment, RID p_render_
scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
- scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_cluster_size);
- scene_state.ubo.max_cluster_element_count_div_32 = p_max_cluster_elements / 32;
+ scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_render_data->cluster_size);
+ scene_state.ubo.max_cluster_element_count_div_32 = p_render_data->cluster_max_elements / 32;
{
- uint32_t cluster_screen_width = (p_screen_size.width - 1) / p_cluster_size + 1;
- uint32_t cluster_screen_height = (p_screen_size.height - 1) / p_cluster_size + 1;
+ uint32_t cluster_screen_width = (p_screen_size.width - 1) / p_render_data->cluster_size + 1;
+ uint32_t cluster_screen_height = (p_screen_size.height - 1) / p_render_data->cluster_size + 1;
scene_state.ubo.cluster_type_size = cluster_screen_width * cluster_screen_height * (scene_state.ubo.max_cluster_element_count_div_32 + 32);
scene_state.ubo.cluster_width = cluster_screen_width;
}
- if (p_shadow_atlas.is_valid()) {
- Vector2 sas = shadow_atlas_get_size(p_shadow_atlas);
+ if (p_render_data->shadow_atlas.is_valid()) {
+ Vector2 sas = shadow_atlas_get_size(p_render_data->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;
}
@@ -592,22 +596,22 @@ void RenderForwardClustered::_setup_environment(RID p_environment, RID p_render_
scene_state.ubo.volumetric_fog_enabled = false;
scene_state.ubo.fog_enabled = false;
- if (p_render_buffers.is_valid()) {
- RenderBufferDataForwardClustered *render_buffers = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
+ if (p_render_data->render_buffers.is_valid()) {
+ RenderBufferDataForwardClustered *render_buffers = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_data->render_buffers);
if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) {
scene_state.ubo.gi_upscale_for_msaa = true;
}
- if (render_buffers_has_volumetric_fog(p_render_buffers)) {
+ if (render_buffers_has_volumetric_fog(p_render_data->render_buffers)) {
scene_state.ubo.volumetric_fog_enabled = true;
- float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers);
+ float fog_end = render_buffers_get_volumetric_fog_end(p_render_data->render_buffers);
if (fog_end > 0.0) {
scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
} else {
scene_state.ubo.volumetric_fog_inv_length = 1.0;
}
- float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+ float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_data->render_buffers); //reverse lookup
if (fog_detail_spread > 0.0) {
scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
} else {
@@ -616,26 +620,26 @@ void RenderForwardClustered::_setup_environment(RID p_environment, RID p_render_
}
}
#if 0
- if (p_render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_buffers)) {
- scene_state.ubo.sdfgi_cascade_count = render_buffers_get_sdfgi_cascade_count(p_render_buffers);
- scene_state.ubo.sdfgi_probe_axis_size = render_buffers_get_sdfgi_cascade_probe_count(p_render_buffers);
+ if (p_render_data->render_buffers.is_valid() && render_buffers_is_sdfgi_enabled(p_render_data->render_buffers)) {
+ scene_state.ubo.sdfgi_cascade_count = render_buffers_get_sdfgi_cascade_count(p_render_data->render_buffers);
+ scene_state.ubo.sdfgi_probe_axis_size = render_buffers_get_sdfgi_cascade_probe_count(p_render_data->render_buffers);
scene_state.ubo.sdfgi_cascade_probe_size[0] = scene_state.ubo.sdfgi_probe_axis_size - 1; //float version for performance
scene_state.ubo.sdfgi_cascade_probe_size[1] = scene_state.ubo.sdfgi_probe_axis_size - 1;
scene_state.ubo.sdfgi_cascade_probe_size[2] = scene_state.ubo.sdfgi_probe_axis_size - 1;
- float csize = render_buffers_get_sdfgi_cascade_size(p_render_buffers);
+ float csize = render_buffers_get_sdfgi_cascade_size(p_render_data->render_buffers);
scene_state.ubo.sdfgi_probe_to_uvw = 1.0 / float(scene_state.ubo.sdfgi_cascade_probe_size[0]);
float occ_bias = 0.0;
scene_state.ubo.sdfgi_occlusion_bias = occ_bias / csize;
- scene_state.ubo.sdfgi_use_occlusion = render_buffers_is_sdfgi_using_occlusion(p_render_buffers);
- scene_state.ubo.sdfgi_energy = render_buffers_get_sdfgi_energy(p_render_buffers);
+ scene_state.ubo.sdfgi_use_occlusion = render_buffers_is_sdfgi_using_occlusion(p_render_data->render_buffers);
+ scene_state.ubo.sdfgi_energy = render_buffers_get_sdfgi_energy(p_render_data->render_buffers);
float cascade_voxel_size = (csize / scene_state.ubo.sdfgi_cascade_probe_size[0]);
float occlusion_clamp = (cascade_voxel_size - 0.5) / cascade_voxel_size;
scene_state.ubo.sdfgi_occlusion_clamp[0] = occlusion_clamp;
scene_state.ubo.sdfgi_occlusion_clamp[1] = occlusion_clamp;
scene_state.ubo.sdfgi_occlusion_clamp[2] = occlusion_clamp;
- scene_state.ubo.sdfgi_normal_bias = (render_buffers_get_sdfgi_normal_bias(p_render_buffers) / csize) * scene_state.ubo.sdfgi_cascade_probe_size[0];
+ scene_state.ubo.sdfgi_normal_bias = (render_buffers_get_sdfgi_normal_bias(p_render_data->render_buffers) / csize) * scene_state.ubo.sdfgi_cascade_probe_size[0];
//vec2 tex_pixel_size = 1.0 / vec2(ivec2( (OCT_SIZE+2) * params.probe_axis_size * params.probe_axis_size, (OCT_SIZE+2) * params.probe_axis_size ) );
//vec3 probe_uv_offset = (ivec3(OCT_SIZE+2,OCT_SIZE+2,(OCT_SIZE+2) * params.probe_axis_size)) * tex_pixel_size.xyx;
@@ -656,14 +660,14 @@ void RenderForwardClustered::_setup_environment(RID p_environment, RID p_render_
for (uint32_t i = 0; i < scene_state.ubo.sdfgi_cascade_count; i++) {
SceneState::UBO::SDFGICascade &c = scene_state.ubo.sdfgi_cascades[i];
- Vector3 pos = render_buffers_get_sdfgi_cascade_offset(p_render_buffers, i);
- pos -= p_cam_transform.origin; //make pos local to camera, to reduce numerical error
+ Vector3 pos = render_buffers_get_sdfgi_cascade_offset(p_render_data->render_buffers, i);
+ pos -= p_render_data->cam_transform.origin; //make pos local to camera, to reduce numerical error
c.position[0] = pos.x;
c.position[1] = pos.y;
c.position[2] = pos.z;
- c.to_probe = 1.0 / render_buffers_get_sdfgi_cascade_probe_size(p_render_buffers, i);
+ c.to_probe = 1.0 / render_buffers_get_sdfgi_cascade_probe_size(p_render_data->render_buffers, i);
- Vector3i probe_ofs = render_buffers_get_sdfgi_cascade_probe_offset(p_render_buffers, i);
+ Vector3i probe_ofs = render_buffers_get_sdfgi_cascade_probe_offset(p_render_data->render_buffers, i);
c.probe_world_offset[0] = probe_ofs.x;
c.probe_world_offset[1] = probe_ofs.y;
c.probe_world_offset[2] = probe_ofs.z;
@@ -680,18 +684,18 @@ void RenderForwardClustered::_setup_environment(RID p_environment, RID p_render_
scene_state.ubo.use_reflection_cubemap = false;
scene_state.ubo.ssao_enabled = false;
- } else if (is_environment(p_environment)) {
- RS::EnvironmentBG env_bg = environment_get_background(p_environment);
- RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_environment);
+ } else if (is_environment(p_render_data->environment)) {
+ RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
+ RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
- float bg_energy = environment_get_bg_energy(p_environment);
+ float bg_energy = environment_get_bg_energy(p_render_data->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);
+ scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->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 = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
color = color.to_linear();
scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
@@ -700,15 +704,15 @@ void RenderForwardClustered::_setup_environment(RID p_environment, RID p_render_
scene_state.ubo.use_ambient_light = true;
scene_state.ubo.use_ambient_cubemap = false;
} else {
- float energy = environment_get_ambient_light_energy(p_environment);
- Color color = environment_get_ambient_light_color(p_environment);
+ float energy = environment_get_ambient_light_energy(p_render_data->environment);
+ Color color = environment_get_ambient_light_color(p_render_data->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;
+ Basis sky_transform = environment_get_sky_orientation(p_render_data->environment);
+ sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
RendererStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
@@ -716,43 +720,43 @@ void RenderForwardClustered::_setup_environment(RID p_environment, RID p_render_
}
//specular
- RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_environment);
+ RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->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);
+ scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_is_ssao_enabled(p_render_data->environment);
+ scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_render_data->environment);
+ scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_render_data->environment);
- Color ao_color = environment_get_ao_color(p_environment).to_linear();
+ Color ao_color = environment_get_ao_color(p_render_data->environment).to_linear();
scene_state.ubo.ao_color[0] = ao_color.r;
scene_state.ubo.ao_color[1] = ao_color.g;
scene_state.ubo.ao_color[2] = ao_color.b;
scene_state.ubo.ao_color[3] = ao_color.a;
- scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment);
- scene_state.ubo.fog_density = environment_get_fog_density(p_environment);
- scene_state.ubo.fog_height = environment_get_fog_height(p_environment);
- scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_environment);
+ scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_render_data->environment);
+ scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment);
+ scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment);
+ scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
if (scene_state.ubo.fog_height_density >= 0.0001) {
scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density;
}
- scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment);
+ scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
- Color fog_color = environment_get_fog_light_color(p_environment).to_linear();
- float fog_energy = environment_get_fog_light_energy(p_environment);
+ Color fog_color = environment_get_fog_light_color(p_render_data->environment).to_linear();
+ float fog_energy = environment_get_fog_light_energy(p_render_data->environment);
scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
- scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment);
+ scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment);
} else {
- if (p_reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
+ if (p_render_data->reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
scene_state.ubo.use_ambient_light = false;
} else {
scene_state.ubo.use_ambient_light = true;
@@ -815,7 +819,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, u
if (inst->store_transform_cache) {
RendererStorageRD::store_transform(inst->transform, instance_data.transform);
} else {
- RendererStorageRD::store_transform(Transform(), instance_data.transform);
+ RendererStorageRD::store_transform(Transform3D(), instance_data.transform);
}
instance_data.flags = inst->flags_cache;
@@ -865,7 +869,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, u
}
}
-void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_append) {
+void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) {
if (p_render_list == RENDER_LIST_OPAQUE) {
scene_state.used_sss = false;
scene_state.used_screen_texture = false;
@@ -874,9 +878,9 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
}
uint32_t lightmap_captures_used = 0;
- Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(Vector3::AXIS_Z));
- near_plane.d += p_cam_projection.get_z_near();
- float z_max = p_cam_projection.get_z_far() - p_cam_projection.get_z_near();
+ Plane near_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z));
+ near_plane.d += p_render_data->cam_projection.get_z_near();
+ float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near();
RenderList *rl = &render_list[p_render_list];
_update_dirty_geometry_instances();
@@ -890,8 +894,8 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
//fill list
- for (int i = 0; i < (int)p_instances.size(); i++) {
- GeometryInstanceForwardClustered *inst = static_cast<GeometryInstanceForwardClustered *>(p_instances[i]);
+ for (int i = 0; i < (int)p_render_data->instances->size(); i++) {
+ GeometryInstanceForwardClustered *inst = static_cast<GeometryInstanceForwardClustered *>((*p_render_data->instances)[i]);
Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal);
inst->depth = near_plane.distance_to(support_min);
@@ -946,14 +950,14 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS;
}
- if (inst->gi_probes[0].is_valid()) {
+ if (inst->voxel_gi_instances[0].is_valid()) {
uint32_t probe0_index = 0xFFFF;
uint32_t probe1_index = 0xFFFF;
- for (uint32_t j = 0; j < scene_state.giprobes_used; j++) {
- if (scene_state.giprobe_ids[j] == inst->gi_probes[0]) {
+ for (uint32_t j = 0; j < scene_state.voxelgis_used; j++) {
+ if (scene_state.voxelgi_ids[j] == inst->voxel_gi_instances[0]) {
probe0_index = j;
- } else if (scene_state.giprobe_ids[j] == inst->gi_probes[1]) {
+ } else if (scene_state.voxelgi_ids[j] == inst->voxel_gi_instances[1]) {
probe1_index = j;
}
}
@@ -964,7 +968,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
}
inst->gi_offset_cache = probe0_index | (probe1_index << 16);
- flags |= INSTANCE_DATA_FLAG_USE_GIPROBE;
+ flags |= INSTANCE_DATA_FLAG_USE_VOXEL_GI;
uses_gi = true;
} else {
if (p_using_sdfgi && inst->can_sdfgi) {
@@ -985,13 +989,13 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
// LOD
- if (p_screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) {
+ if (p_render_data->screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) {
//lod
- Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_lod_plane.normal);
- Vector3 lod_support_max = inst->transformed_aabb.get_support(p_lod_plane.normal);
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
- float distance_min = p_lod_plane.distance_to(lod_support_min);
- float distance_max = p_lod_plane.distance_to(lod_support_max);
+ float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min);
+ float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max);
float distance = 0.0;
@@ -1004,7 +1008,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
distance = -distance_max;
}
- surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_lod_distance_multiplier, p_screen_lod_threshold);
+ surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
} else {
surf->sort.lod_index = 0;
}
@@ -1059,14 +1063,14 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
}
}
-void RenderForwardClustered::_setup_giprobes(const PagedArray<RID> &p_giprobes) {
- scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES));
- for (uint32_t i = 0; i < scene_state.giprobes_used; i++) {
- scene_state.giprobe_ids[i] = p_giprobes[i];
+void RenderForwardClustered::_setup_voxelgis(const PagedArray<RID> &p_voxelgis) {
+ scene_state.voxelgis_used = MIN(p_voxelgis.size(), uint32_t(MAX_VOXEL_GI_INSTANCESS));
+ for (uint32_t i = 0; i < scene_state.voxelgis_used; i++) {
+ scene_state.voxelgi_ids[i] = p_voxelgis[i];
}
}
-void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) {
+void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
scene_state.lightmaps_used = 0;
for (int i = 0; i < (int)p_lightmaps.size(); i++) {
if (i >= (int)scene_state.max_lightmaps) {
@@ -1088,28 +1092,23 @@ void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps
}
}
-void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) {
+void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
+ ERR_FAIL_COND_MSG(p_render_data->view_count != 1, "Multiview is currently not supported in the clustered renderer. Please use the mobile renderer for VR.");
+
RenderBufferDataForwardClustered *render_buffer = nullptr;
- if (p_render_buffer.is_valid()) {
- render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffer);
+ if (p_render_data->render_buffers.is_valid()) {
+ render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_data->render_buffers);
}
- RendererSceneEnvironmentRD *env = get_environment(p_environment);
+ RendererSceneEnvironmentRD *env = get_environment(p_render_data->environment);
//first of all, make a new render pass
//fill up ubo
RENDER_TIMESTAMP("Setup 3D Scene");
- float lod_distance_multiplier = p_cam_projection.get_lod_multiplier();
- Plane lod_camera_plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z));
-
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
- p_screen_lod_threshold = 0.0;
- }
-
//scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size;
- Vector2 vp_he = p_cam_projection.get_viewport_half_extents();
+ Vector2 vp_he = p_render_data->cam_projection.get_viewport_half_extents();
scene_state.ubo.viewport_size[0] = vp_he.x;
scene_state.ubo.viewport_size[1] = vp_he.y;
scene_state.ubo.directional_light_count = 0;
@@ -1125,7 +1124,7 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
bool using_separate_specular = false;
bool using_ssr = false;
bool using_sdfgi = false;
- bool using_giprobe = false;
+ bool using_voxelgi = false;
bool reverse_cull = false;
if (render_buffer) {
@@ -1134,29 +1133,29 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
opaque_framebuffer = render_buffer->color_fb;
- if (p_gi_probes.size() > 0) {
- using_giprobe = true;
+ if (p_render_data->voxel_gi_instances->size() > 0) {
+ using_voxelgi = true;
}
- if (!p_environment.is_valid() && using_giprobe) {
- depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE;
+ if (!p_render_data->environment.is_valid() && using_voxelgi) {
+ depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI;
- } else if (p_environment.is_valid() && (environment_is_ssr_enabled(p_environment) || environment_is_sdfgi_enabled(p_environment) || using_giprobe)) {
- if (environment_is_sdfgi_enabled(p_environment)) {
- depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also giprobe
+ } else if (p_render_data->environment.is_valid() && (environment_is_ssr_enabled(p_render_data->environment) || environment_is_sdfgi_enabled(p_render_data->environment) || using_voxelgi)) {
+ if (environment_is_sdfgi_enabled(p_render_data->environment)) {
+ depth_pass_mode = using_voxelgi ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also voxelgi
using_sdfgi = true;
} else {
- depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS;
+ depth_pass_mode = using_voxelgi ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI : PASS_MODE_DEPTH_NORMAL_ROUGHNESS;
}
- if (environment_is_ssr_enabled(p_environment)) {
+ if (environment_is_ssr_enabled(p_render_data->environment)) {
render_buffer->ensure_specular();
using_separate_specular = true;
using_ssr = true;
opaque_specular_framebuffer = render_buffer->color_specular_fb;
}
- } else if (p_environment.is_valid() && (environment_is_ssao_enabled(p_environment) || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) {
+ } else if (p_render_data->environment.is_valid() && (environment_is_ssao_enabled(p_render_data->environment) || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) {
depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS;
}
@@ -1169,10 +1168,10 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
depth_framebuffer = render_buffer->depth_normal_roughness_fb;
depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
} break;
- case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: {
+ case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: {
_allocate_normal_roughness_texture(render_buffer);
- render_buffer->ensure_giprobe();
- depth_framebuffer = render_buffer->depth_normal_roughness_giprobe_fb;
+ render_buffer->ensure_voxelgi();
+ depth_framebuffer = render_buffer->depth_normal_roughness_voxelgi_fb;
depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
depth_pass_clear.push_back(Color(0, 0, 0, 0));
} break;
@@ -1181,17 +1180,18 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
}
alpha_framebuffer = opaque_framebuffer;
- } else if (p_reflection_probe.is_valid()) {
- uint32_t resolution = reflection_probe_instance_get_resolution(p_reflection_probe);
+ } else if (p_render_data->reflection_probe.is_valid()) {
+ uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
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);
+ opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+ depth_framebuffer = reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->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
+ if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ p_render_data->environment = RID(); //no environment on interiors
+ env = nullptr;
}
reverse_cull = true; // for some reason our views are inverted
@@ -1201,13 +1201,13 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
RD::get_singleton()->draw_command_begin_label("Render Setup");
- _setup_lightmaps(p_lightmaps, p_cam_transform);
- _setup_giprobes(p_gi_probes);
- _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, 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);
+ _setup_lightmaps(*p_render_data->lightmaps, p_render_data->cam_transform);
+ _setup_voxelgis(*p_render_data->voxel_gi_instances);
+ _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
- _fill_render_list(RENDER_LIST_OPAQUE, p_instances, PASS_MODE_COLOR, p_cam_projection, p_cam_transform, using_sdfgi, using_sdfgi || using_giprobe, lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_voxelgi);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
render_list[RENDER_LIST_ALPHA].sort_by_depth();
_fill_instance_data(RENDER_LIST_OPAQUE);
@@ -1232,26 +1232,26 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
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);
+ } else if (is_environment(p_render_data->environment)) {
+ RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment);
+ float bg_energy = environment_get_bg_energy(p_render_data->environment);
switch (bg_mode) {
case RS::ENV_BG_CLEAR_COLOR: {
clear_color = p_default_bg_color;
clear_color.r *= bg_energy;
clear_color.g *= bg_energy;
clear_color.b *= bg_energy;
- if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
+ if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) {
draw_sky_fog_only = true;
storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
}
} break;
case RS::ENV_BG_COLOR: {
- clear_color = environment_get_bg_color(p_environment);
+ clear_color = environment_get_bg_color(p_render_data->environment);
clear_color.r *= bg_energy;
clear_color.g *= bg_energy;
clear_color.b *= bg_energy;
- if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
+ if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) {
draw_sky_fog_only = true;
storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
}
@@ -1271,21 +1271,21 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
}
}
// setup sky if used for ambient, reflections, or background
- if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+ if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
RENDER_TIMESTAMP("Setup Sky");
RD::get_singleton()->draw_command_begin_label("Setup Sky");
- CameraMatrix projection = p_cam_projection;
- if (p_reflection_probe.is_valid()) {
+ CameraMatrix projection = p_render_data->cam_projection;
+ if (p_render_data->reflection_probe.is_valid()) {
CameraMatrix correction;
correction.set_depth_correction(true);
- projection = correction * p_cam_projection;
+ projection = correction * p_render_data->cam_projection;
}
- sky.setup(env, p_render_buffer, projection, p_cam_transform, screen_size, this);
+ sky.setup(env, p_render_data->render_buffers, projection, p_render_data->cam_transform, screen_size, this);
RID sky_rid = env->sky;
if (sky_rid.is_valid()) {
- sky.update(env, projection, p_cam_transform, time);
+ sky.update(env, projection, p_render_data->cam_transform, time);
radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
@@ -1297,15 +1297,15 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
clear_color = p_default_bg_color;
}
- bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION;
+ bool debug_voxelgis = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION;
bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES;
bool depth_pre_pass = depth_framebuffer.is_valid();
- bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment);
+ bool using_ssao = depth_pre_pass && p_render_data->render_buffers.is_valid() && p_render_data->environment.is_valid() && environment_is_ssao_enabled(p_render_data->environment);
bool continue_depth = false;
if (depth_pre_pass) { //depth pre pass
- bool needs_pre_resolve = _needs_post_prepass_render(using_sdfgi || using_giprobe);
+ bool needs_pre_resolve = _needs_post_prepass_render(p_render_data, using_sdfgi || using_voxelgi);
if (needs_pre_resolve) {
RENDER_TIMESTAMP("GI + Render Depth Pre-Pass (parallel)");
} else {
@@ -1316,32 +1316,32 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
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);
RD::get_singleton()->draw_list_end();
//start compute processes here, so they run at the same time as depth pre-pass
- _post_prepass_render(using_sdfgi || using_giprobe);
+ _post_prepass_render(p_render_data, using_sdfgi || using_voxelgi);
}
RD::get_singleton()->draw_command_begin_label("Render Depth Pre-Pass");
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID());
- bool finish_depth = using_ssao || using_sdfgi || using_giprobe;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ bool finish_depth = using_ssao || using_sdfgi || using_voxelgi;
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
_render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
RD::get_singleton()->draw_command_end_label();
if (needs_pre_resolve) {
- _pre_resolve_render(using_sdfgi || using_giprobe);
+ _pre_resolve_render(p_render_data, using_sdfgi || using_voxelgi);
}
if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
RENDER_TIMESTAMP("Resolve Depth Pre-Pass");
RD::get_singleton()->draw_command_begin_label("Resolve Depth Pre-Pass");
- if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) {
+ if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI) {
if (needs_pre_resolve) {
RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, RD::BARRIER_MASK_COMPUTE);
}
static int texture_samples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 };
- storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_giprobe ? render_buffer->giprobe_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_giprobe ? render_buffer->giprobe_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]);
+ storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_voxelgi ? render_buffer->voxelgi_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_voxelgi ? render_buffer->voxelgi_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]);
} else if (finish_depth) {
RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth);
}
@@ -1351,24 +1351,24 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
continue_depth = !finish_depth;
}
- _pre_opaque_render(using_ssao, using_sdfgi || using_giprobe, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->giprobe_buffer : RID());
+ _pre_opaque_render(p_render_data, using_ssao, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->voxelgi_buffer : RID());
RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
- scene_state.ubo.directional_light_count = _get_render_state_directional_light_count();
+ scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
- _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, 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());
+ _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
RENDER_TIMESTAMP("Render Opaque Pass");
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true);
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss;
bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
{
- bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);
- bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);
+ bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes);
+ bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes);
//regular forward for now
Vector<Color> c;
@@ -1382,7 +1382,7 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
}
RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
_render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
if (will_continue_color && using_separate_specular) {
// close the specular framebuffer, as it's no longer used
@@ -1393,34 +1393,34 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
RD::get_singleton()->draw_command_end_label();
- if (debug_giprobes) {
- //debug giprobes
+ if (debug_voxelgis) {
+ //debug voxelgis
bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
CameraMatrix dc;
dc.set_depth_correction(true);
- CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse());
+ CameraMatrix cm = (dc * p_render_data->cam_projection) * CameraMatrix(p_render_data->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);
- RD::get_singleton()->draw_command_begin_label("Debug GIProbes");
- for (int i = 0; i < (int)p_gi_probes.size(); i++) {
- gi.debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0);
+ RD::get_singleton()->draw_command_begin_label("Debug VoxelGIs");
+ for (int i = 0; i < (int)p_render_data->voxel_gi_instances->size(); i++) {
+ gi.debug_voxel_gi((*p_render_data->voxel_gi_instances)[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION, 1.0);
}
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->draw_list_end();
}
if (debug_sdfgi_probes) {
- //debug giprobes
+ //debug voxelgis
bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
CameraMatrix dc;
dc.set_depth_correction(true);
- CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse());
+ CameraMatrix cm = (dc * p_render_data->cam_projection) * CameraMatrix(p_render_data->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);
RD::get_singleton()->draw_command_begin_label("Debug SDFGI");
- _debug_sdfgi_probes(p_render_buffer, draw_list, opaque_framebuffer, cm);
+ _debug_sdfgi_probes(p_render_data->render_buffers, draw_list, opaque_framebuffer, cm);
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->draw_list_end();
}
@@ -1428,14 +1428,14 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
if (draw_sky || draw_sky_fog_only) {
RENDER_TIMESTAMP("Render Sky");
- CameraMatrix projection = p_cam_projection;
- if (p_reflection_probe.is_valid()) {
+ CameraMatrix projection = p_render_data->cam_projection;
+ if (p_render_data->reflection_probe.is_valid()) {
CameraMatrix correction;
correction.set_depth_correction(true);
- projection = correction * p_cam_projection;
+ projection = correction * p_render_data->cam_projection;
}
RD::get_singleton()->draw_command_begin_label("Draw Sky");
- sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_cam_transform, time);
+ sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, 1, &projection, p_render_data->cam_transform, time);
RD::get_singleton()->draw_command_end_label();
}
@@ -1454,14 +1454,14 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
if (using_sss) {
RENDER_TIMESTAMP("Sub Surface Scattering");
RD::get_singleton()->draw_command_begin_label("Process Sub Surface Scattering");
- _process_sss(p_render_buffer, p_cam_projection);
+ _process_sss(p_render_data->render_buffers, p_render_data->cam_projection);
RD::get_singleton()->draw_command_end_label();
}
if (using_ssr) {
RENDER_TIMESTAMP("Screen Space Reflection");
RD::get_singleton()->draw_command_begin_label("Process Screen Space Reflections");
- _process_ssr(p_render_buffer, render_buffer->color_fb, render_buffer->normal_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);
+ _process_ssr(p_render_data->render_buffers, render_buffer->color_fb, render_buffer->normal_roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_render_data->environment, p_render_data->cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED);
RD::get_singleton()->draw_command_end_label();
} else {
//just mix specular back
@@ -1474,12 +1474,12 @@ void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform
RD::get_singleton()->draw_command_begin_label("Render Transparent Pass");
- rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_cluster_buffer, p_gi_probes, p_lightmaps, true);
+ rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
- _setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_size, p_cluster_size, p_max_cluster_elements, 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);
+ _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
{
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
_render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
}
@@ -1502,23 +1502,37 @@ void RenderForwardClustered::_render_shadow_begin() {
render_list[RENDER_LIST_SECONDARY].clear();
scene_state.instance_data[RENDER_LIST_SECONDARY].clear();
}
-void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) {
+
+void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) {
uint32_t shadow_pass_index = scene_state.shadow_passes.size();
SceneState::ShadowPass shadow_pass;
+ RenderDataRD render_data;
+ render_data.cam_projection = p_projection;
+ render_data.cam_transform = p_transform;
+ render_data.z_far = p_zfar;
+ render_data.z_near = 0.0;
+ render_data.cluster_size = 1;
+ render_data.cluster_max_elements = 32;
+ render_data.instances = &p_instances;
+ render_data.lod_camera_plane = p_camera_plane;
+ render_data.lod_distance_multiplier = p_lod_distance_multiplier;
+
scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
- _setup_environment(RID(), RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), !p_flip_y, Color(), 0, p_zfar, false, p_use_pancake, shadow_pass_index);
+ _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
- p_screen_lod_threshold = 0.0;
+ render_data.screen_lod_threshold = 0.0;
+ } else {
+ render_data.screen_lod_threshold = p_screen_lod_threshold;
}
PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size();
- _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_projection, p_transform, false, false, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, true);
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, false, false, true);
uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
_fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false);
@@ -1537,8 +1551,8 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete
shadow_pass.camera_plane = p_camera_plane;
- shadow_pass.screen_lod_threshold = p_screen_lod_threshold;
- shadow_pass.lod_distance_multiplier = p_lod_distance_multiplier;
+ shadow_pass.screen_lod_threshold = render_data.screen_lod_threshold;
+ shadow_pass.lod_distance_multiplier = render_data.lod_distance_multiplier;
shadow_pass.framebuffer = p_framebuffer;
shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE);
@@ -1556,7 +1570,7 @@ void RenderForwardClustered::_render_shadow_process() {
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
//render passes need to be configured after instance buffer is done, since they need the latest version
SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
- shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>(), false, i);
+ shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), false, i);
}
RD::get_singleton()->draw_command_end_label();
@@ -1576,23 +1590,32 @@ void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) {
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
+void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
RENDER_TIMESTAMP("Setup Render Collider Heightfield");
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
+ RenderDataRD render_data;
+ render_data.cam_projection = p_cam_projection;
+ render_data.cam_transform = p_cam_transform;
+ render_data.z_near = 0.0;
+ render_data.z_far = p_cam_projection.get_z_far();
+ render_data.cluster_size = 1;
+ render_data.cluster_max_elements = 32;
+ render_data.instances = &p_instances;
+
_update_render_base_uniform_set();
scene_state.ubo.dual_paraboloid_side = 0;
- _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false);
+ _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
PassMode pass_mode = PASS_MODE_SHADOW;
- _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform);
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
RENDER_TIMESTAMP("Render Collider Heightfield");
@@ -1604,24 +1627,31 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardClustered::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
RENDER_TIMESTAMP("Setup Rendering Material");
RD::get_singleton()->draw_command_begin_label("Render Material");
+ RenderDataRD render_data;
+ render_data.cam_projection = p_cam_projection;
+ render_data.cam_transform = p_cam_transform;
+ render_data.cluster_size = 1;
+ render_data.cluster_max_elements = 32;
+ render_data.instances = &p_instances;
+
_update_render_base_uniform_set();
scene_state.ubo.dual_paraboloid_side = 0;
scene_state.ubo.material_uv2_mode = false;
- _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0);
+ _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
- _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, p_cam_projection, p_cam_transform);
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
RENDER_TIMESTAMP("Render Material");
@@ -1647,19 +1677,24 @@ void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p
RD::get_singleton()->draw_command_begin_label("Render UV2");
+ RenderDataRD render_data;
+ render_data.cluster_size = 1;
+ render_data.cluster_max_elements = 32;
+ render_data.instances = &p_instances;
+
_update_render_base_uniform_set();
scene_state.ubo.dual_paraboloid_side = 0;
scene_state.ubo.material_uv2_mode = true;
- _setup_environment(RID(), RID(), CameraMatrix(), Transform(), RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0);
+ _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
- _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform());
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
- RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>());
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
RENDER_TIMESTAMP("Render Material");
@@ -1696,6 +1731,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative
}
render_list_params.uv_offset = Vector2();
+ render_list_params.force_wireframe = false;
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles
RD::get_singleton()->draw_list_end();
@@ -1709,13 +1745,18 @@ void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i
RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel");
+ RenderDataRD render_data;
+ render_data.cluster_size = 1;
+ render_data.cluster_max_elements = 32;
+ render_data.instances = &p_instances;
+
_update_render_base_uniform_set();
RenderBufferDataForwardClustered *render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
ERR_FAIL_COND(!render_buffer);
PassMode pass_mode = PASS_MODE_SDF;
- _fill_render_list(RENDER_LIST_SECONDARY, p_instances, pass_mode, CameraMatrix(), Transform());
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
render_list[RENDER_LIST_SECONDARY].sort_by_key();
_fill_instance_data(RENDER_LIST_SECONDARY);
@@ -1747,28 +1788,26 @@ void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i
fb_size.x = p_size[right_axis];
fb_size.y = p_size[up_axis];
- Transform cam_xform;
- cam_xform.origin = center + axis * half_extents;
- cam_xform.basis.set_axis(0, right);
- cam_xform.basis.set_axis(1, up);
- cam_xform.basis.set_axis(2, axis);
+ render_data.cam_transform.origin = center + axis * half_extents;
+ render_data.cam_transform.basis.set_axis(0, right);
+ render_data.cam_transform.basis.set_axis(1, up);
+ render_data.cam_transform.basis.set_axis(2, axis);
- //print_line("pass: " + itos(i) + " xform " + cam_xform);
+ //print_line("pass: " + itos(i) + " xform " + render_data.cam_transform);
float h_size = half_extents[right_axis];
float v_size = half_extents[up_axis];
float d_size = half_extents[i] * 2.0;
- CameraMatrix camera_proj;
- camera_proj.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size);
+ render_data.cam_projection.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size);
//print_line("pass: " + itos(i) + " cam hsize: " + rtos(h_size) + " vsize: " + rtos(v_size) + " dsize " + rtos(d_size));
- Transform to_bounds;
+ Transform3D to_bounds;
to_bounds.origin = p_bounds.position;
to_bounds.basis.scale(p_bounds.size);
- RendererStorageRD::store_transform(to_bounds.affine_inverse() * cam_xform, scene_state.ubo.sdf_to_bounds);
+ RendererStorageRD::store_transform(to_bounds.affine_inverse() * render_data.cam_transform, scene_state.ubo.sdf_to_bounds);
- _setup_environment(RID(), RID(), camera_proj, cam_xform, RID(), true, Vector2(1, 1), 1, 32, RID(), false, Color(), 0, 0);
+ _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture);
@@ -1918,13 +1957,13 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
}
}
-RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas, int p_index) {
+RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) {
//there should always be enough uniform buffers for render passes, otherwise bugs
ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID());
RenderBufferDataForwardClustered *rb = nullptr;
- if (p_render_buffers.is_valid()) {
- rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
+ if (p_render_data && p_render_data->render_buffers.is_valid()) {
+ rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_data->render_buffers);
}
//default render buffer and scene state uniform set
@@ -1964,7 +2003,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
- RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID();
+ RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
RD::Uniform u;
u.binding = 3;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
@@ -1981,8 +2020,8 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture;
- if (p_shadow_atlas.is_valid()) {
- texture = shadow_atlas_get_texture(p_shadow_atlas);
+ if (p_render_data && p_render_data->shadow_atlas.is_valid()) {
+ texture = shadow_atlas_get_texture(p_render_data->shadow_atlas);
}
if (!texture.is_valid()) {
texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
@@ -2008,8 +2047,8 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.ids.resize(scene_state.max_lightmaps);
RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
- if (i < p_lightmaps.size()) {
- RID base = lightmap_instance_get_lightmap(p_lightmaps[i]);
+ if (p_render_data && i < p_render_data->lightmaps->size()) {
+ RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
RID texture = storage->lightmap_get_texture(base);
RID rd_texture = storage->texture_get_rd_texture(texture);
u.ids.write[i] = rd_texture;
@@ -2024,11 +2063,11 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.resize(MAX_GI_PROBES);
+ u.ids.resize(MAX_VOXEL_GI_INSTANCESS);
RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- for (int i = 0; i < MAX_GI_PROBES; i++) {
- if (i < (int)p_gi_probes.size()) {
- RID tex = gi.gi_probe_instance_get_texture(p_gi_probes[i]);
+ for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
+ if (p_render_data && i < (int)p_render_data->voxel_gi_instances->size()) {
+ RID tex = gi.voxel_gi_instance_get_texture((*p_render_data->voxel_gi_instances)[i]);
if (!tex.is_valid()) {
tex = default_tex;
}
@@ -2045,7 +2084,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : scene_shader.default_vec4_xform_buffer;
+ RID cb = (p_render_data && p_render_data->cluster_buffer.is_valid()) ? p_render_data->cluster_buffer : scene_shader.default_vec4_xform_buffer;
u.ids.push_back(cb);
uniforms.push_back(u);
}
@@ -2062,7 +2101,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_buffers) : RID();
+ RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_data->render_buffers) : RID();
RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
u.ids.push_back(texture);
uniforms.push_back(u);
@@ -2082,7 +2121,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 12;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID aot = rb ? render_buffers_get_ao_texture(p_render_buffers) : RID();
+ RID aot = rb ? render_buffers_get_ao_texture(p_render_data->render_buffers) : RID();
RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
u.ids.push_back(texture);
uniforms.push_back(u);
@@ -2092,7 +2131,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID ambient_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_ambient_texture(p_render_buffers) : RID();
+ RID ambient_buffer = rb ? render_buffers_get_gi_ambient_texture(p_render_data->render_buffers) : RID();
RID texture = ambient_buffer.is_valid() ? ambient_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
u.ids.push_back(texture);
uniforms.push_back(u);
@@ -2102,7 +2141,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 14;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID reflection_buffer = p_render_buffers.is_valid() ? render_buffers_get_gi_reflection_texture(p_render_buffers) : RID();
+ RID reflection_buffer = rb ? render_buffers_get_gi_reflection_texture(p_render_data->render_buffers) : RID();
RID texture = reflection_buffer.is_valid() ? reflection_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
u.ids.push_back(texture);
uniforms.push_back(u);
@@ -2112,8 +2151,8 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 15;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID t;
- if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) {
- t = render_buffers_get_sdfgi_irradiance_probes(p_render_buffers);
+ if (rb && render_buffers_is_sdfgi_enabled(p_render_data->render_buffers)) {
+ t = render_buffers_get_sdfgi_irradiance_probes(p_render_data->render_buffers);
} else {
t = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
}
@@ -2124,8 +2163,8 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 16;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) {
- u.ids.push_back(render_buffers_get_sdfgi_occlusion_texture(p_render_buffers));
+ if (rb && render_buffers_is_sdfgi_enabled(p_render_data->render_buffers)) {
+ u.ids.push_back(render_buffers_get_sdfgi_occlusion_texture(p_render_data->render_buffers));
} else {
u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE));
}
@@ -2135,7 +2174,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 17;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_buffers) : render_buffers_get_default_gi_probe_buffer());
+ u.ids.push_back(rb ? render_buffers_get_voxel_gi_buffer(p_render_data->render_buffers) : render_buffers_get_default_voxel_gi_buffer());
uniforms.push_back(u);
}
{
@@ -2143,8 +2182,8 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 18;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID vfog = RID();
- if (rb && render_buffers_has_volumetric_fog(p_render_buffers)) {
- vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers);
+ if (rb && render_buffers_has_volumetric_fog(p_render_data->render_buffers)) {
+ vfog = render_buffers_get_volumetric_fog_texture(p_render_data->render_buffers);
if (vfog.is_null()) {
vfog = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
}
@@ -2244,13 +2283,13 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
}
{
- // No GIProbes
+ // No VoxelGIs
RD::Uniform u;
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.resize(MAX_GI_PROBES);
+ u.ids.resize(MAX_VOXEL_GI_INSTANCESS);
RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- for (int i = 0; i < MAX_GI_PROBES; i++) {
+ for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
u.ids.write[i] = default_tex;
}
@@ -2301,15 +2340,6 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
return sdfgi_pass_uniform_set;
}
-void RenderForwardClustered::_render_buffers_clear_uniform_set(RenderBufferDataForwardClustered *rb) {
-}
-
-void RenderForwardClustered::_render_buffers_uniform_set_changed(RID p_render_buffers) {
- RenderBufferDataForwardClustered *rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
-
- _render_buffers_clear_uniform_set(rb);
-}
-
RID RenderForwardClustered::_render_buffers_get_normal_texture(RID p_render_buffers) {
RenderBufferDataForwardClustered *rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
@@ -2379,9 +2409,13 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
}
+ if (p_material->shader_data->uses_particle_trails) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS;
+ }
+
SceneShaderForwardClustered::MaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
- if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
material_shadow = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D);
@@ -2550,7 +2584,7 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
}
}
- ginstance->instance_count = storage->particles_get_amount(ginstance->data->base);
+ ginstance->instance_count = storage->particles_get_amount(ginstance->data->base, ginstance->trail_steps);
} break;
@@ -2564,42 +2598,26 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
- uint32_t stride;
if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
- stride = 2;
- } else {
- stride = 3;
}
if (storage->multimesh_uses_colors(ginstance->data->base)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
- stride += 1;
}
if (storage->multimesh_uses_custom_data(ginstance->data->base)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
- stride += 1;
}
- ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT);
ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
} else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
- uint32_t stride;
- if (false) { // 2D particles
- ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
- stride = 2;
- } else {
- stride = 3;
- }
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
- stride += 1;
-
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
- stride += 1;
- ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT);
+ //for particles, stride is the trail size
+ ginstance->base_flags |= (ginstance->trail_steps << INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT);
if (!storage->particles_is_using_local_coords(ginstance->data->base)) {
store_transform = false;
@@ -2608,7 +2626,6 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
if (storage->skeleton_is_valid(ginstance->data->skeleton)) {
- ginstance->base_flags |= INSTANCE_DATA_FLAG_SKELETON;
ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
if (ginstance->data->dirty_dependencies) {
storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
@@ -2620,7 +2637,7 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome
ginstance->can_sdfgi = false;
if (!lightmap_instance_is_valid(ginstance->lightmap_instance)) {
- if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) {
+ if (ginstance->voxel_gi_instances[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) {
ginstance->can_sdfgi = true;
}
}
@@ -2643,6 +2660,7 @@ void RenderForwardClustered::_geometry_instance_dependency_changed(RendererStora
switch (p_notification) {
case RendererStorage::DEPENDENCY_CHANGED_MATERIAL:
case RendererStorage::DEPENDENCY_CHANGED_MESH:
+ case RendererStorage::DEPENDENCY_CHANGED_PARTICLES:
case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH:
case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: {
static_cast<RenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
@@ -2706,7 +2724,7 @@ void RenderForwardClustered::geometry_instance_set_mesh_instance(GeometryInstanc
ginstance->mesh_instance = p_mesh_instance;
_geometry_instance_mark_dirty(ginstance);
}
-void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
+void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->transform = p_transform;
@@ -2756,7 +2774,7 @@ void RenderForwardClustered::geometry_instance_set_lightmap_capture(GeometryInst
ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc();
}
- copymem(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9);
+ memcpy(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9);
} else {
if (ginstance->lightmap_sh != nullptr) {
geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
@@ -2802,7 +2820,7 @@ void RenderForwardClustered::geometry_instance_free(GeometryInstance *p_geometry
}
uint32_t RenderForwardClustered::geometry_instance_get_pair_mask() {
- return (1 << RS::INSTANCE_GI_PROBE);
+ return (1 << RS::INSTANCE_VOXEL_GI);
}
void RenderForwardClustered::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
}
@@ -2811,30 +2829,31 @@ void RenderForwardClustered::geometry_instance_pair_reflection_probe_instances(G
void RenderForwardClustered::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
}
-Transform RenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) {
+Transform3D RenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance);
- ERR_FAIL_COND_V(!ginstance, Transform());
+ ERR_FAIL_COND_V(!ginstance, Transform3D());
return ginstance->transform;
}
+
AABB RenderForwardClustered::geometry_instance_get_aabb(GeometryInstance *p_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance);
ERR_FAIL_COND_V(!ginstance, AABB());
return ginstance->data->aabb;
}
-void RenderForwardClustered::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) {
+void RenderForwardClustered::geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
- if (p_gi_probe_instance_count > 0) {
- ginstance->gi_probes[0] = p_gi_probe_instances[0];
+ if (p_voxel_gi_instance_count > 0) {
+ ginstance->voxel_gi_instances[0] = p_voxel_gi_instances[0];
} else {
- ginstance->gi_probes[0] = RID();
+ ginstance->voxel_gi_instances[0] = RID();
}
- if (p_gi_probe_instance_count > 1) {
- ginstance->gi_probes[1] = p_gi_probe_instances[1];
+ if (p_voxel_gi_instance_count > 1) {
+ ginstance->voxel_gi_instances[1] = p_voxel_gi_instances[1];
} else {
- ginstance->gi_probes[1] = RID();
+ ginstance->voxel_gi_instances[1] = RID();
}
}
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 72e84a6f24..579c8de05e 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -52,9 +52,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
enum {
SDFGI_MAX_CASCADES = 8,
- MAX_GI_PROBES = 8,
+ MAX_VOXEL_GI_INSTANCESS = 8,
MAX_LIGHTMAPS = 8,
- MAX_GI_PROBES_PER_INSTANCE = 2,
+ MAX_VOXEL_GI_INSTANCESS_PER_INSTANCE = 2,
INSTANCE_DATA_BUFFER_MIN_SIZE = 4096
};
@@ -79,7 +79,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID depth;
RID specular;
RID normal_roughness_buffer;
- RID giprobe_buffer;
+ RID voxelgi_buffer;
RS::ViewportMSAA msaa;
RD::TextureSamples texture_samples;
@@ -89,11 +89,11 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID specular_msaa;
RID normal_roughness_buffer_msaa;
RID roughness_buffer_msaa;
- RID giprobe_buffer_msaa;
+ RID voxelgi_buffer_msaa;
RID depth_fb;
RID depth_normal_roughness_fb;
- RID depth_normal_roughness_giprobe_fb;
+ RID depth_normal_roughness_voxelgi_fb;
RID color_fb;
RID color_specular_fb;
RID specular_only_fb;
@@ -101,9 +101,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID render_sdfgi_uniform_set;
void ensure_specular();
- void ensure_giprobe();
+ void ensure_voxelgi();
void clear();
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa);
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
~RenderBufferDataForwardClustered();
};
@@ -118,13 +118,11 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
virtual void _base_uniforms_changed();
- void _render_buffers_clear_uniform_set(RenderBufferDataForwardClustered *rb);
- virtual void _render_buffers_uniform_set_changed(RID p_render_buffers);
virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
void _update_render_base_uniform_set();
RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture);
- RID _setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas = false, int p_index = 0);
+ RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
enum PassMode {
PASS_MODE_COLOR,
@@ -134,7 +132,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
PASS_MODE_SHADOW_DP,
PASS_MODE_DEPTH,
PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
- PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE,
+ PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI,
PASS_MODE_DEPTH_MATERIAL,
PASS_MODE_SDF,
};
@@ -191,21 +189,21 @@ class RenderForwardClustered : public RendererSceneRenderRD {
INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
- INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15,
- INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16,
- INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7,
- INSTANCE_DATA_FLAG_SKELETON = 1 << 19,
+ INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16,
+ INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF,
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 24,
};
struct SceneState {
+ // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
struct UBO {
float projection_matrix[16];
float inv_projection_matrix[16];
-
float camera_matrix[16];
float inv_camera_matrix[16];
@@ -319,8 +317,8 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t max_lightmap_captures;
RID lightmap_capture_buffer;
- RID giprobe_ids[MAX_GI_PROBES];
- uint32_t giprobes_used = 0;
+ RID voxelgi_ids[MAX_VOXEL_GI_INSTANCESS];
+ uint32_t voxelgis_used = 0;
bool used_screen_texture = false;
bool used_normal_texture = false;
@@ -350,9 +348,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
static RenderForwardClustered *singleton;
- void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
- void _setup_giprobes(const PagedArray<RID> &p_giprobes);
- void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform);
+ void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
+ void _setup_voxelgis(const PagedArray<RID> &p_voxelgis);
+ void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
struct RenderElementInfo {
uint32_t repeat : 22;
@@ -374,7 +372,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
void _update_instance_data_buffer(RenderListType p_render_list);
void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
- void _fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, const Plane &p_lod_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, bool p_append = false);
+ void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, bool p_append = false);
Map<Size2i, RID> sdfgi_framebuffer_size_cache;
@@ -398,6 +396,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
FLAG_USES_DEPTH_TEXTURE = 8192,
FLAG_USES_NORMAL_TEXTURE = 16384,
FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768,
+ FLAG_USES_PARTICLE_TRAILS = 65536,
};
union {
@@ -453,12 +452,13 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t layer_mask = 1;
RID transforms_uniform_set;
uint32_t instance_count = 0;
+ uint32_t trail_steps = 1;
RID mesh_instance;
bool can_sdfgi = false;
//used during setup
uint32_t base_flags = 0;
- Transform transform;
- RID gi_probes[MAX_GI_PROBES_PER_INSTANCE];
+ Transform3D transform;
+ RID voxel_gi_instances[MAX_VOXEL_GI_INSTANCESS_PER_INSTANCE];
RID lightmap_instance;
GeometryInstanceLightmapSH *lightmap_sh = nullptr;
GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
@@ -565,17 +565,17 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RenderList render_list[RENDER_LIST_MAX];
protected:
- virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_lod_threshold);
+ virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color);
virtual void _render_shadow_begin();
- virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true);
+ virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true);
virtual void _render_shadow_process();
virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL);
- virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
+ virtual void _render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture);
- virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances);
+ virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances);
public:
virtual GeometryInstance *geometry_instance_create(RID p_base);
@@ -583,7 +583,7 @@ public:
virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override);
virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials);
virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance);
- virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb);
+ virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb);
virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask);
virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias);
virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable);
@@ -593,7 +593,7 @@ public:
virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset);
virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable);
- virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance);
+ virtual Transform3D geometry_instance_get_transform(GeometryInstance *p_instance);
virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance);
virtual void geometry_instance_free(GeometryInstance *p_geometry_instance);
@@ -602,7 +602,7 @@ public:
virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count);
virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count);
virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count);
- virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count);
+ virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count);
virtual bool free(RID p_rid);
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 15982b4b29..f125931df8 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -30,6 +30,7 @@
#include "scene_shader_forward_clustered.h"
#include "core/config/project_settings.h"
+#include "core/math/math_defs.h"
#include "render_forward_clustered.h"
using namespace RendererSceneRenderImplementation;
@@ -73,6 +74,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
uses_time = false;
writes_modelview_or_projection = false;
uses_world_coordinates = false;
+ uses_particle_trails = false;
int depth_drawi = DEPTH_DRAW_OPAQUE;
@@ -101,6 +103,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
actions.render_mode_flags["unshaded"] = &unshaded;
actions.render_mode_flags["wireframe"] = &wireframe;
+ actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
@@ -144,12 +147,17 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
for (int i = 0; i < gen_code.defines.size(); i++) {
print_line(gen_code.defines[i]);
}
+
+ Map<String, String>::Element * el = gen_code.code.front();
+ while (el) {
+ print_line("\n**code " + el->key() + ":\n" + el->value());
+
+ el = el->next();
+ }
+
print_line("\n**uniforms:\n" + gen_code.uniforms);
- print_line("\n**vertex_globals:\n" + gen_code.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);
+ print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX]);
+ print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT]);
#endif
shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version));
@@ -303,7 +311,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
//none, leave empty
} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
blend_state = blend_state_depth_normal_roughness;
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) {
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI) {
blend_state = blend_state_depth_normal_roughness_giprobe;
} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
@@ -552,30 +560,19 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
{
Vector<String> shader_versions;
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n");
- shader_versions.push_back("");
- shader_versions.push_back("\n#define USE_FORWARD_GI\n");
- shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
- shader_versions.push_back("\n#define USE_LIGHTMAP\n");
- shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n");
- shader.initialize(shader_versions, p_defines);
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_DEPTH_PASS
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_DEPTH_PASS_DP
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n"); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n"); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n"); // SHADER_VERSION_DEPTH_PASS_WITH_SDF
+ shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS
+ shader_versions.push_back("\n#define USE_FORWARD_GI\n"); // SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI
+ shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); // SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR
+ shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS
+ shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR
- /*
- if (p_is_low_end) {
- //disable the high end versions
- shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false);
- shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false);
- shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false);
- shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false);
- shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false);
- shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false);
- }
- */
+ shader.initialize(shader_versions, p_defines);
}
storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
@@ -613,6 +610,9 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
//builtins
actions.renames["TIME"] = "scene_data.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
@@ -657,6 +657,11 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.renames["CUSTOM2"] = "custom2_attrib";
actions.renames["CUSTOM3"] = "custom3_attrib";
+ // not implemented but need these just in case code is in the shaders
+ actions.renames["VIEW_INDEX"] = "0";
+ actions.renames["VIEW_MONO_LEFT"] = "0";
+ actions.renames["VIEW_RIGHT"] = "1";
+
//for light
actions.renames["VIEW"] = "view";
actions.renames["LIGHT_COLOR"] = "light_color";
@@ -714,6 +719,7 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
+ actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n";
bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
@@ -721,7 +727,6 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
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";
@@ -753,7 +758,7 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
actions.global_buffer_array_variable = "global_variables.data";
- actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
+ actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs";
compiler.initialize(actions);
}
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index 953a5291c8..8add9f8095 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -48,7 +48,7 @@ public:
SHADER_VERSION_DEPTH_PASS,
SHADER_VERSION_DEPTH_PASS_DP,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
- SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE,
+ SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI,
SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
SHADER_VERSION_DEPTH_PASS_WITH_SDF,
SHADER_VERSION_COLOR_PASS,
@@ -56,6 +56,7 @@ public:
SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
SHADER_VERSION_LIGHTMAP_COLOR_PASS,
SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR,
+
SHADER_VERSION_MAX
};
@@ -126,6 +127,7 @@ public:
bool uses_discard;
bool uses_roughness;
bool uses_normal;
+ bool uses_particle_trails;
bool unshaded;
bool uses_vertex;
diff --git a/servers/rendering/renderer_rd/forward_mobile/SCsub b/servers/rendering/renderer_rd/forward_mobile/SCsub
new file mode 100644
index 0000000000..86681f9c74
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_mobile/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
new file mode 100644
index 0000000000..ae09d215ff
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -0,0 +1,2154 @@
+/*************************************************************************/
+/* render_forward_mobile.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "render_forward_mobile.h"
+#include "core/config/project_settings.h"
+#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/rendering_server_default.h"
+
+using namespace RendererSceneRenderImplementation;
+
+/* Render buffer */
+
+void RenderForwardMobile::RenderBufferDataForwardMobile::clear() {
+ if (color_msaa.is_valid()) {
+ RD::get_singleton()->free(color_msaa);
+ color_msaa = RID();
+ }
+
+ if (depth_msaa.is_valid()) {
+ RD::get_singleton()->free(depth_msaa);
+ depth_msaa = RID();
+ }
+
+ color = RID();
+ depth = RID();
+ color_fb = RID();
+}
+
+void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) {
+ clear();
+
+ msaa = p_msaa;
+
+ width = p_width;
+ height = p_height;
+ view_count = p_view_count;
+
+ color = p_color_buffer;
+ depth = p_depth_buffer;
+
+ // re-introduce setting up msaa? For now we ignore this...
+
+ if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) {
+ Vector<RID> fb;
+ fb.push_back(p_color_buffer);
+ fb.push_back(depth);
+
+ color_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
+ } else {
+ RD::TextureFormat tf;
+ if (view_count > 1) {
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ } else {
+ tf.texture_type = RD::TEXTURE_TYPE_2D;
+ }
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = p_width;
+ tf.height = p_height;
+ tf.array_layers = view_count; // create a layer for every view
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
+ RD::TEXTURE_SAMPLES_1,
+ RD::TEXTURE_SAMPLES_2,
+ RD::TEXTURE_SAMPLES_4,
+ RD::TEXTURE_SAMPLES_8,
+ RD::TEXTURE_SAMPLES_16
+ };
+
+ texture_samples = ts[p_msaa];
+ tf.samples = texture_samples;
+
+ color_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+ tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ depth_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ {
+ Vector<RID> fb;
+ fb.push_back(color_msaa);
+ fb.push_back(depth_msaa);
+
+ color_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count);
+ }
+ }
+}
+
+RenderForwardMobile::RenderBufferDataForwardMobile::~RenderBufferDataForwardMobile() {
+ clear();
+}
+
+RendererSceneRenderRD::RenderBufferData *RenderForwardMobile::_create_render_buffer_data() {
+ return memnew(RenderBufferDataForwardMobile);
+}
+
+bool RenderForwardMobile::free(RID p_rid) {
+ if (RendererSceneRenderRD::free(p_rid)) {
+ return true;
+ }
+ return false;
+}
+
+/* Render functions */
+
+RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) {
+ //there should always be enough uniform buffers for render passes, otherwise bugs
+ ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID());
+
+ RenderBufferDataForwardMobile *rb = nullptr;
+ if (p_render_data && p_render_data->render_buffers.is_valid()) {
+ rb = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_data->render_buffers);
+ }
+
+ // default render buffer and scene state uniform set
+ // loaded into set 1
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.uniform_buffers[p_index]);
+ uniforms.push_back(u);
+ }
+
+ {
+ RID radiance_texture;
+ if (p_radiance_texture.is_valid()) {
+ radiance_texture = p_radiance_texture;
+ } else {
+ radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
+ }
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(radiance_texture);
+ uniforms.push_back(u);
+ }
+
+ {
+ RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ if (ref_texture.is_valid()) {
+ u.ids.push_back(ref_texture);
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK));
+ }
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture;
+ if (p_render_data && p_render_data->shadow_atlas.is_valid()) {
+ texture = shadow_atlas_get_texture(p_render_data->shadow_atlas);
+ }
+ if (!texture.is_valid()) {
+ texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ }
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) {
+ u.ids.push_back(directional_shadow_get_texture());
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ }
+ uniforms.push_back(u);
+ }
+
+ /* we have limited ability to keep textures like this so we're moving this to a set we change before drawing geometry and just pushing the needed texture in */
+ {
+ RD::Uniform u;
+ u.binding = 6;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.resize(scene_state.max_lightmaps);
+ RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
+ if (p_render_data && i < p_render_data->lightmaps->size()) {
+ RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
+ RID texture = storage->lightmap_get_texture(base);
+ RID rd_texture = storage->texture_get_rd_texture(texture);
+ u.ids.write[i] = rd_texture;
+ } else {
+ u.ids.write[i] = default_tex;
+ }
+ }
+
+ uniforms.push_back(u);
+ }
+
+ /*
+ {
+ RD::Uniform u;
+ u.binding = 7;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.resize(MAX_VOXEL_GI_INSTANCESS);
+ RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
+ if (i < (int)p_voxel_gi_instances.size()) {
+ RID tex = gi.voxel_gi_instance_get_texture(p_voxel_gi_instances[i]);
+ if (!tex.is_valid()) {
+ tex = default_tex;
+ }
+ u.ids.write[i] = tex;
+ } else {
+ u.ids.write[i] = default_tex;
+ }
+ }
+
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer;
+ u.ids.push_back(cb);
+ uniforms.push_back(u);
+ }
+ */
+
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_data->render_buffers) : RID();
+ RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+
+ if (p_index >= (int)render_pass_uniform_sets.size()) {
+ render_pass_uniform_sets.resize(p_index + 1);
+ }
+
+ if (render_pass_uniform_sets[p_index].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[p_index])) {
+ RD::get_singleton()->free(render_pass_uniform_sets[p_index]);
+ }
+
+ render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET);
+ return render_pass_uniform_sets[p_index];
+}
+
+void RenderForwardMobile::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
+ // This probably needs to change...
+ scene_state.lightmaps_used = 0;
+ for (int i = 0; i < (int)p_lightmaps.size(); i++) {
+ if (i >= (int)scene_state.max_lightmaps) {
+ break;
+ }
+
+ RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]);
+
+ Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
+ to_lm = to_lm.inverse().transposed(); //will transform normals
+ RendererStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
+ scene_state.lightmap_ids[i] = p_lightmaps[i];
+ scene_state.lightmap_has_sh[i] = storage->lightmap_uses_spherical_harmonics(lightmap);
+
+ scene_state.lightmaps_used++;
+ }
+ if (scene_state.lightmaps_used > 0) {
+ RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, RD::BARRIER_MASK_RASTER);
+ }
+}
+
+void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
+ RenderBufferDataForwardMobile *render_buffer = nullptr;
+ if (p_render_data->render_buffers.is_valid()) {
+ render_buffer = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_data->render_buffers);
+ }
+ RendererSceneEnvironmentRD *env = get_environment(p_render_data->environment);
+
+ RENDER_TIMESTAMP("Setup 3D Scene");
+
+ Vector2 vp_he = p_render_data->cam_projection.get_viewport_half_extents();
+ scene_state.ubo.viewport_size[0] = vp_he.x;
+ scene_state.ubo.viewport_size[1] = vp_he.y;
+ scene_state.ubo.directional_light_count = 0;
+
+ Size2i screen_size;
+ RID opaque_framebuffer;
+ RID alpha_framebuffer;
+ bool reverse_cull = false;
+
+ // I don't think we support either of these in our mobile renderer so probably should phase them out
+ bool using_ssr = false;
+ bool using_sss = false;
+
+ if (render_buffer) {
+ // setup rendering to render buffer
+ screen_size.x = render_buffer->width;
+ screen_size.y = render_buffer->height;
+
+ opaque_framebuffer = render_buffer->color_fb;
+ alpha_framebuffer = opaque_framebuffer;
+ } else if (p_render_data->reflection_probe.is_valid()) {
+ uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
+ screen_size.x = resolution;
+ screen_size.y = resolution;
+
+ opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+ alpha_framebuffer = opaque_framebuffer;
+
+ if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ p_render_data->environment = RID(); //no environment on interiors
+ env = nullptr;
+ }
+
+ reverse_cull = true;
+ } else {
+ ERR_FAIL(); //bug?
+ }
+
+ RD::get_singleton()->draw_command_begin_label("Render Setup");
+
+ _setup_lightmaps(*p_render_data->lightmaps, p_render_data->cam_transform);
+ _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
+
+ _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
+
+ _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
+ render_list[RENDER_LIST_OPAQUE].sort_by_key();
+ render_list[RENDER_LIST_ALPHA].sort_by_depth();
+
+ // we no longer use this...
+ _fill_instance_data(RENDER_LIST_OPAQUE);
+ _fill_instance_data(RENDER_LIST_ALPHA);
+
+ RD::get_singleton()->draw_command_end_label();
+
+ // note, no depth prepass here!
+
+ // setup environment
+ RID radiance_texture;
+ bool draw_sky = false;
+ bool draw_sky_fog_only = false;
+
+ Color clear_color = p_default_bg_color;
+ bool keep_color = false;
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
+ clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
+ } else if (is_environment(p_render_data->environment)) {
+ RS::EnvironmentBG bg_mode = environment_get_background(p_render_data->environment);
+ float bg_energy = environment_get_bg_energy(p_render_data->environment);
+ switch (bg_mode) {
+ case RS::ENV_BG_CLEAR_COLOR: {
+ clear_color = p_default_bg_color;
+ clear_color.r *= bg_energy;
+ clear_color.g *= bg_energy;
+ clear_color.b *= bg_energy;
+ /*
+ if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) {
+ draw_sky_fog_only = true;
+ storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ }
+ */
+ } break;
+ case RS::ENV_BG_COLOR: {
+ clear_color = environment_get_bg_color(p_render_data->environment);
+ clear_color.r *= bg_energy;
+ clear_color.g *= bg_energy;
+ clear_color.b *= bg_energy;
+ /*
+ if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) {
+ draw_sky_fog_only = true;
+ storage->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+ }
+ */
+ } break;
+ case RS::ENV_BG_SKY: {
+ draw_sky = true;
+ } break;
+ case RS::ENV_BG_CANVAS: {
+ keep_color = true;
+ } break;
+ case RS::ENV_BG_KEEP: {
+ keep_color = true;
+ } break;
+ case RS::ENV_BG_CAMERA_FEED: {
+ } break;
+ default: {
+ }
+ }
+ // setup sky if used for ambient, reflections, or background
+ if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+ RENDER_TIMESTAMP("Setup Sky");
+ RD::get_singleton()->draw_command_begin_label("Setup Sky");
+ CameraMatrix projection = p_render_data->cam_projection;
+ if (p_render_data->reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ projection = correction * p_render_data->cam_projection;
+ }
+
+ sky.setup(env, p_render_data->render_buffers, projection, p_render_data->cam_transform, screen_size, this);
+
+ RID sky_rid = env->sky;
+ if (sky_rid.is_valid()) {
+ sky.update(env, projection, p_render_data->cam_transform, time);
+ radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
+ } else {
+ // do not try to draw sky if invalid
+ draw_sky = false;
+ }
+ RD::get_singleton()->draw_command_end_label();
+ }
+ } else {
+ clear_color = p_default_bg_color;
+ }
+
+ // opaque pass
+
+ // !BAS! Look into this, seems most of the code in here related to clustered only, may want to move this code into ForwardClustered/RenderForwardMobile before calling it from here
+ // does trigger shadow map rendering so kinda important
+ _pre_opaque_render(p_render_data, false, false, RID(), RID());
+
+ RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
+
+ scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
+
+ _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
+
+ RENDER_TIMESTAMP("Render Opaque Pass");
+
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
+
+ bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss;
+ bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
+
+ {
+ bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
+ bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
+
+ // regular forward for now
+ Vector<Color> c;
+ c.push_back(clear_color.to_linear());
+
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ _render_list_with_threads(&render_list_params, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+
+ if (draw_sky || draw_sky_fog_only) {
+ RENDER_TIMESTAMP("Render Sky");
+
+ RD::get_singleton()->draw_command_begin_label("Draw Sky");
+
+ if (p_render_data->reflection_probe.is_valid()) {
+ CameraMatrix correction;
+ correction.set_depth_correction(true);
+ CameraMatrix projection = correction * p_render_data->cam_projection;
+ sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, 1, &projection, p_render_data->cam_transform, time);
+ } else {
+ sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time);
+ }
+ RD::get_singleton()->draw_command_end_label();
+ }
+
+ if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color);
+ /*
+ if (using_separate_specular) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular);
+ }
+ */
+ }
+
+ if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth);
+ }
+
+ // transparent pass
+ RENDER_TIMESTAMP("Render Transparent Pass");
+
+ RD::get_singleton()->draw_command_begin_label("Render Transparent Pass");
+
+ rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true);
+
+ _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
+
+ {
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count);
+ _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+
+ RD::get_singleton()->draw_command_begin_label("Resolve");
+
+ if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+/* these are being called from RendererSceneRenderRD::_pre_opaque_render */
+
+void RenderForwardMobile::_render_shadow_begin() {
+ scene_state.shadow_passes.clear();
+ RD::get_singleton()->draw_command_begin_label("Shadow Setup");
+ _update_render_base_uniform_set();
+
+ render_list[RENDER_LIST_SECONDARY].clear();
+}
+
+void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) {
+ uint32_t shadow_pass_index = scene_state.shadow_passes.size();
+
+ SceneState::ShadowPass shadow_pass;
+
+ RenderDataRD render_data;
+ render_data.cam_projection = p_projection;
+ render_data.cam_transform = p_transform;
+ render_data.view_projection[0] = p_projection;
+ render_data.z_near = 0.0;
+ render_data.z_far = p_zfar;
+ render_data.instances = &p_instances;
+ render_data.lod_camera_plane = p_camera_plane;
+ render_data.lod_distance_multiplier = p_lod_distance_multiplier;
+
+ scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
+
+ _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
+ render_data.screen_lod_threshold = 0.0;
+ } else {
+ render_data.screen_lod_threshold = p_screen_lod_threshold;
+ }
+
+ PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
+
+ uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size();
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, true);
+ uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
+ render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
+ _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false);
+
+ {
+ //regular forward for now
+ bool flip_cull = p_use_dp_flip;
+ if (p_flip_y) {
+ flip_cull = !flip_cull;
+ }
+
+ shadow_pass.element_from = render_list_from;
+ shadow_pass.element_count = render_list_size;
+ shadow_pass.flip_cull = flip_cull;
+ shadow_pass.pass_mode = pass_mode;
+
+ shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete
+ shadow_pass.camera_plane = p_camera_plane;
+ shadow_pass.screen_lod_threshold = render_data.screen_lod_threshold;
+ shadow_pass.lod_distance_multiplier = render_data.lod_distance_multiplier;
+
+ shadow_pass.framebuffer = p_framebuffer;
+ shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE);
+ shadow_pass.final_depth_action = p_end ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE;
+ shadow_pass.rect = p_rect;
+
+ scene_state.shadow_passes.push_back(shadow_pass);
+ }
+}
+
+void RenderForwardMobile::_render_shadow_process() {
+ //render shadows one after the other, so this can be done un-barriered and the driver can optimize (as well as allow us to run compute at the same time)
+
+ for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
+ //render passes need to be configured after instance buffer is done, since they need the latest version
+ SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
+ shadow_pass.rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID(), false, i);
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) {
+ RD::get_singleton()->draw_command_begin_label("Shadow Render");
+
+ for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
+ SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
+ RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
+ _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
+ }
+
+ if (p_barrier != RD::BARRIER_MASK_NO_BARRIER) {
+ RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, p_barrier);
+ }
+ RD::get_singleton()->draw_command_end_label();
+}
+
+/* */
+
+void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+ RENDER_TIMESTAMP("Setup Rendering Material");
+
+ RD::get_singleton()->draw_command_begin_label("Render Material");
+
+ _update_render_base_uniform_set();
+
+ scene_state.ubo.dual_paraboloid_side = 0;
+ scene_state.ubo.material_uv2_mode = false;
+
+ RenderDataRD render_data;
+ render_data.cam_projection = p_cam_projection;
+ render_data.cam_transform = p_cam_transform;
+ render_data.view_projection[0] = p_cam_projection;
+ render_data.instances = &p_instances;
+
+ _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+
+ PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
+ render_list[RENDER_LIST_SECONDARY].sort_by_key();
+ _fill_instance_data(RENDER_LIST_SECONDARY);
+
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
+
+ RENDER_TIMESTAMP("Render Material");
+
+ {
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set);
+ //regular forward for now
+ Vector<Color> clear;
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RenderForwardMobile::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+ RENDER_TIMESTAMP("Setup Rendering UV2");
+
+ RD::get_singleton()->draw_command_begin_label("Render UV2");
+
+ _update_render_base_uniform_set();
+
+ scene_state.ubo.dual_paraboloid_side = 0;
+ scene_state.ubo.material_uv2_mode = true;
+
+ RenderDataRD render_data;
+ render_data.instances = &p_instances;
+
+ _setup_environment(&render_data, true, Vector2(1, 1), false, Color());
+
+ PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
+ render_list[RENDER_LIST_SECONDARY].sort_by_key();
+ _fill_instance_data(RENDER_LIST_SECONDARY);
+
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
+
+ RENDER_TIMESTAMP("Render Material");
+
+ {
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true);
+ //regular forward for now
+ Vector<Color> clear;
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ clear.push_back(Color(0, 0, 0, 0));
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region);
+
+ const int uv_offset_count = 9;
+ static const Vector2 uv_offsets[uv_offset_count] = {
+ Vector2(-1, 1),
+ Vector2(1, 1),
+ Vector2(1, -1),
+ Vector2(-1, -1),
+ Vector2(-1, 0),
+ Vector2(1, 0),
+ Vector2(0, -1),
+ Vector2(0, 1),
+ Vector2(0, 0),
+
+ };
+
+ for (int i = 0; i < uv_offset_count; i++) {
+ Vector2 ofs = uv_offsets[i];
+ ofs.x /= p_region.size.width;
+ ofs.y /= p_region.size.height;
+ render_list_params.uv_offset = ofs;
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative
+ }
+ render_list_params.uv_offset = Vector2();
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles
+
+ RD::get_singleton()->draw_list_end();
+ }
+
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RenderForwardMobile::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) {
+ // we don't do GI in low end..
+}
+
+void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
+ RENDER_TIMESTAMP("Setup Render Collider Heightfield");
+
+ RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
+
+ _update_render_base_uniform_set();
+ scene_state.ubo.dual_paraboloid_side = 0;
+
+ RenderDataRD render_data;
+ render_data.cam_projection = p_cam_projection;
+ render_data.cam_transform = p_cam_transform;
+ render_data.view_projection[0] = p_cam_projection;
+ render_data.z_near = 0.0;
+ render_data.z_far = p_cam_projection.get_z_far();
+ render_data.instances = &p_instances;
+
+ _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
+
+ PassMode pass_mode = PASS_MODE_SHADOW;
+
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode);
+ render_list[RENDER_LIST_SECONDARY].sort_by_key();
+ _fill_instance_data(RENDER_LIST_SECONDARY);
+
+ RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID());
+
+ RENDER_TIMESTAMP("Render Collider Heightfield");
+
+ {
+ //regular forward for now
+ RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set);
+ _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ);
+ }
+ RD::get_singleton()->draw_command_end_label();
+}
+
+void RenderForwardMobile::_base_uniforms_changed() {
+ if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+ RD::get_singleton()->free(render_base_uniform_set);
+ }
+ render_base_uniform_set = RID();
+}
+
+void RenderForwardMobile::_update_render_base_uniform_set() {
+ if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) {
+ if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+ RD::get_singleton()->free(render_base_uniform_set);
+ }
+
+ // This is all loaded into set 0
+
+ lightmap_texture_array_version = storage->lightmap_array_get_version();
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 1;
+ u.ids.resize(12);
+ RID *ids_ptr = u.ids.ptrw();
+ ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(scene_shader.shadow_sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(get_omni_light_buffer());
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(get_spot_light_buffer());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(get_reflection_probe_buffer());
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 6;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(get_directional_light_buffer());
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 7;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(scene_state.lightmap_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(scene_state.lightmap_capture_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID decal_atlas = storage->decal_atlas_get_texture();
+ u.ids.push_back(decal_atlas);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID decal_atlas = storage->decal_atlas_get_texture_srgb();
+ u.ids.push_back(decal_atlas);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 11;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(get_decal_buffer());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 12;
+ u.ids.push_back(storage->global_variables_get_storage_buffer());
+ uniforms.push_back(u);
+ }
+
+ render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
+ }
+}
+
+RID RenderForwardMobile::_render_buffers_get_normal_texture(RID p_render_buffers) {
+ // RenderBufferDataForwardMobile *rb = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_buffers);
+
+ // We don't have this. This is for debugging
+ // return rb->normal_roughness_buffer;
+ return RID();
+}
+
+void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append) {
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ scene_state.used_sss = false;
+ scene_state.used_screen_texture = false;
+ scene_state.used_normal_texture = false;
+ scene_state.used_depth_texture = false;
+ }
+ uint32_t lightmap_captures_used = 0;
+
+ Plane near_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z));
+ near_plane.d += p_render_data->cam_projection.get_z_near();
+ float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near();
+
+ RenderList *rl = &render_list[p_render_list];
+
+ // Parse any updates on our geometry, updates surface caches and such
+ _update_dirty_geometry_instances();
+
+ if (!p_append) {
+ rl->clear();
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ render_list[RENDER_LIST_ALPHA].clear(); //opaque fills alpha too
+ }
+ }
+
+ //fill list
+
+ for (int i = 0; i < (int)p_render_data->instances->size(); i++) {
+ GeometryInstanceForwardMobile *inst = static_cast<GeometryInstanceForwardMobile *>((*p_render_data->instances)[i]);
+
+ Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal);
+ inst->depth = near_plane.distance_to(support_min);
+ uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15);
+
+ uint32_t flags = inst->base_flags; //fill flags if appropriate
+
+ bool uses_lightmap = false;
+ // bool uses_gi = false;
+
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ if (inst->lightmap_instance.is_valid()) {
+ int32_t lightmap_cull_index = -1;
+ for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) {
+ if (scene_state.lightmap_ids[j] == inst->lightmap_instance) {
+ lightmap_cull_index = j;
+ break;
+ }
+ }
+ if (lightmap_cull_index >= 0) {
+ inst->gi_offset_cache = inst->lightmap_slice_index << 16;
+ inst->gi_offset_cache |= lightmap_cull_index;
+ flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP;
+ if (scene_state.lightmap_has_sh[lightmap_cull_index]) {
+ flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP;
+ }
+ uses_lightmap = true;
+ } else {
+ inst->gi_offset_cache = 0xFFFFFFFF;
+ }
+
+ } else if (inst->lightmap_sh) {
+ if (lightmap_captures_used < scene_state.max_lightmap_captures) {
+ const Color *src_capture = inst->lightmap_sh->sh;
+ LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used];
+ for (int j = 0; j < 9; j++) {
+ lcd.sh[j * 4 + 0] = src_capture[j].r;
+ lcd.sh[j * 4 + 1] = src_capture[j].g;
+ lcd.sh[j * 4 + 2] = src_capture[j].b;
+ lcd.sh[j * 4 + 3] = src_capture[j].a;
+ }
+ flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE;
+ inst->gi_offset_cache = lightmap_captures_used;
+ lightmap_captures_used++;
+ uses_lightmap = true;
+ }
+ }
+ }
+ inst->flags_cache = flags;
+
+ GeometryInstanceSurfaceDataCache *surf = inst->surface_caches;
+
+ while (surf) {
+ surf->sort.uses_lightmap = 0;
+
+ // LOD
+
+ if (p_render_data->screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(surf->surface)) {
+ //lod
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
+
+ float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min);
+ float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max);
+
+ float distance = 0.0;
+
+ if (distance_min * distance_max < 0.0) {
+ //crossing plane
+ distance = 0.0;
+ } else if (distance_min >= 0.0) {
+ distance = distance_min;
+ } else if (distance_max <= 0.0) {
+ distance = -distance_max;
+ }
+
+ surf->lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold);
+ } else {
+ surf->lod_index = 0;
+ }
+
+ // ADD Element
+ if (p_pass_mode == PASS_MODE_COLOR) {
+ if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
+ rl->add_element(surf);
+ }
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) {
+ render_list[RENDER_LIST_ALPHA].add_element(surf);
+ // if (uses_gi) {
+ // surf->sort.uses_forward_gi = 1;
+ // }
+ }
+
+ if (uses_lightmap) {
+ surf->sort.uses_lightmap = 1; // This needs to become our lightmap index but we'll do that in a separate PR.
+ }
+
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) {
+ scene_state.used_sss = true;
+ }
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) {
+ scene_state.used_screen_texture = true;
+ }
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE) {
+ scene_state.used_normal_texture = true;
+ }
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) {
+ scene_state.used_depth_texture = true;
+ }
+
+ } else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) {
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) {
+ rl->add_element(surf);
+ }
+ } else {
+ if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) {
+ rl->add_element(surf);
+ }
+ }
+
+ surf->sort.depth_layer = depth_layer;
+
+ surf = surf->next;
+ }
+ }
+}
+
+void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
+ //!BAS! need to go through this and find out what we don't need anymore
+
+ // This populates our UBO with main scene data that is pushed into set 1
+
+ //CameraMatrix projection = p_render_data->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_render_data->cam_projection;
+
+ //store camera into ubo
+ RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix);
+ RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
+ RendererStorageRD::store_transform(p_render_data->cam_transform, scene_state.ubo.camera_matrix);
+ RendererStorageRD::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix);
+
+ for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ projection = correction * p_render_data->view_projection[v];
+ RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix_view[v]);
+ RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix_view[v]);
+ }
+
+ scene_state.ubo.z_far = p_render_data->z_far;
+ scene_state.ubo.z_near = p_render_data->z_near;
+
+ scene_state.ubo.pancake_shadows = p_pancake_shadows;
+
+ RendererStorageRD::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel);
+ RendererStorageRD::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel);
+ RendererStorageRD::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
+ RendererStorageRD::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);
+
+ scene_state.ubo.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get();
+ scene_state.ubo.directional_soft_shadow_samples = directional_soft_shadow_samples_get();
+ scene_state.ubo.penumbra_shadow_samples = penumbra_shadow_samples_get();
+ scene_state.ubo.soft_shadow_samples = soft_shadow_samples_get();
+
+ Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
+ scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
+ scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
+
+ if (p_render_data->shadow_atlas.is_valid()) {
+ Vector2 sas = shadow_atlas_get_size(p_render_data->shadow_atlas);
+ scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x;
+ scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y;
+ }
+ {
+ Vector2 dss = directional_shadow_get_size();
+ scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x;
+ scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y;
+ }
+
+ //time global variables
+ scene_state.ubo.time = time;
+
+ /*
+ scene_state.ubo.gi_upscale_for_msaa = false;
+ scene_state.ubo.volumetric_fog_enabled = false;
+ scene_state.ubo.fog_enabled = false;
+
+ if (p_render_data->render_buffers.is_valid()) {
+ RenderBufferDataForwardMobile *render_buffers = (RenderBufferDataForwardMobile *)render_buffers_get_data(p_render_data->render_buffers);
+ if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ scene_state.ubo.gi_upscale_for_msaa = true;
+ }
+
+ if (render_buffers_has_volumetric_fog(p_render_data->render_buffers)) {
+ scene_state.ubo.volumetric_fog_enabled = true;
+ float fog_end = render_buffers_get_volumetric_fog_end(p_render_data->render_buffers);
+ if (fog_end > 0.0) {
+ scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+ } else {
+ scene_state.ubo.volumetric_fog_inv_length = 1.0;
+ }
+
+ float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_data->render_buffers); //reverse lookup
+ if (fog_detail_spread > 0.0) {
+ scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+ } else {
+ scene_state.ubo.volumetric_fog_detail_spread = 1.0;
+ }
+ }
+ }
+
+ */
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
+ scene_state.ubo.use_ambient_light = true;
+ scene_state.ubo.ambient_light_color_energy[0] = 1;
+ scene_state.ubo.ambient_light_color_energy[1] = 1;
+ scene_state.ubo.ambient_light_color_energy[2] = 1;
+ scene_state.ubo.ambient_light_color_energy[3] = 1.0;
+ scene_state.ubo.use_ambient_cubemap = false;
+ scene_state.ubo.use_reflection_cubemap = false;
+ scene_state.ubo.ssao_enabled = false;
+
+ } else if (is_environment(p_render_data->environment)) {
+ RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
+ RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
+
+ float bg_energy = environment_get_bg_energy(p_render_data->environment);
+ scene_state.ubo.ambient_light_color_energy[3] = bg_energy;
+
+ scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->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_render_data->environment);
+ color = color.to_linear();
+
+ scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy;
+ scene_state.ubo.use_ambient_light = true;
+ scene_state.ubo.use_ambient_cubemap = false;
+ } else {
+ float energy = environment_get_ambient_light_energy(p_render_data->environment);
+ Color color = environment_get_ambient_light_color(p_render_data->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_render_data->environment);
+ sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
+ RendererStorageRD::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
+
+ scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
+ scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
+ }
+
+ //specular
+ RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->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_render_data->environment);
+ scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_render_data->environment);
+ scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_render_data->environment);
+
+ Color ao_color = environment_get_ao_color(p_render_data->environment).to_linear();
+ scene_state.ubo.ao_color[0] = ao_color.r;
+ scene_state.ubo.ao_color[1] = ao_color.g;
+ scene_state.ubo.ao_color[2] = ao_color.b;
+ scene_state.ubo.ao_color[3] = ao_color.a;
+
+ scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_render_data->environment);
+ scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment);
+ scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment);
+ scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
+ if (scene_state.ubo.fog_height_density >= 0.0001) {
+ scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density;
+ }
+ scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
+
+ Color fog_color = environment_get_fog_light_color(p_render_data->environment).to_linear();
+ float fog_energy = environment_get_fog_light_energy(p_render_data->environment);
+
+ scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
+
+ scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment);
+
+ } else {
+ if (p_render_data->reflection_probe.is_valid() && storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ scene_state.ubo.use_ambient_light = false;
+ } else {
+ scene_state.ubo.use_ambient_light = true;
+ Color clear_color = p_default_bg_color;
+ clear_color = clear_color.to_linear();
+ scene_state.ubo.ambient_light_color_energy[0] = clear_color.r;
+ scene_state.ubo.ambient_light_color_energy[1] = clear_color.g;
+ scene_state.ubo.ambient_light_color_energy[2] = clear_color.b;
+ scene_state.ubo.ambient_light_color_energy[3] = 1.0;
+ }
+
+ scene_state.ubo.use_ambient_cubemap = false;
+ scene_state.ubo.use_reflection_cubemap = false;
+ scene_state.ubo.ssao_enabled = false;
+ }
+
+ scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active();
+ scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount();
+ scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit();
+
+ if (p_index >= (int)scene_state.uniform_buffers.size()) {
+ uint32_t from = scene_state.uniform_buffers.size();
+ scene_state.uniform_buffers.resize(p_index + 1);
+ render_pass_uniform_sets.resize(p_index + 1);
+ for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) {
+ scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO));
+ }
+ }
+ RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
+}
+
+void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
+ // !BAS! Rename this to make clear this is not the same as with the forward renderer and remove p_update_buffer?
+
+ RenderList *rl = &render_list[p_render_list];
+ uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
+
+ rl->element_info.resize(p_offset + element_total);
+
+ for (uint32_t i = 0; i < element_total; i++) {
+ GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset];
+ RenderElementInfo &element_info = rl->element_info[p_offset + i];
+
+ element_info.lod_index = surface->lod_index;
+ element_info.uses_lightmap = surface->sort.uses_lightmap;
+ }
+}
+
+/// RENDERING ///
+
+void RenderForwardMobile::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
+ //use template for faster performance (pass mode comparisons are inlined)
+
+ switch (p_params->pass_mode) {
+ case PASS_MODE_COLOR: {
+ _render_list_template<PASS_MODE_COLOR>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ } break;
+ case PASS_MODE_COLOR_TRANSPARENT: {
+ _render_list_template<PASS_MODE_COLOR_TRANSPARENT>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ } break;
+ case PASS_MODE_SHADOW: {
+ _render_list_template<PASS_MODE_SHADOW>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ } break;
+ case PASS_MODE_SHADOW_DP: {
+ _render_list_template<PASS_MODE_SHADOW_DP>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ } break;
+ case PASS_MODE_DEPTH_MATERIAL: {
+ _render_list_template<PASS_MODE_DEPTH_MATERIAL>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element);
+ } break;
+ }
+}
+
+void RenderForwardMobile::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) {
+ uint32_t render_total = p_params->element_count;
+ uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
+ uint32_t render_from = p_thread * render_total / total_threads;
+ uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads);
+ _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to);
+}
+
+void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
+ RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer);
+ p_params->framebuffer_format = fb_format;
+
+ if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time
+ //multi threaded
+ thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
+ RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, p_params);
+ RD::get_singleton()->draw_list_end(p_params->barrier);
+ } else {
+ //single threaded
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
+ _render_list(draw_list, fb_format, p_params, 0, p_params->element_count);
+ RD::get_singleton()->draw_list_end(p_params->barrier);
+ }
+}
+
+template <RenderForwardMobile::PassMode p_pass_mode>
+void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
+ RD::DrawListID draw_list = p_draw_list;
+ RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
+
+ //global scope bindings
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, scene_shader.default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET);
+
+ RID prev_material_uniform_set;
+
+ RID prev_vertex_array_rd;
+ RID prev_index_array_rd;
+ RID prev_pipeline_rd;
+ RID prev_xforms_uniform_set;
+
+ bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP);
+
+ for (uint32_t i = p_from_element; i < p_to_element; i++) {
+ const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i];
+ const RenderElementInfo &element_info = p_params->element_info[i];
+ const GeometryInstanceForwardMobile *inst = surf->owner;
+
+ // GeometryInstanceForwardMobile::PushConstant push_constant = inst->push_constant;
+ GeometryInstanceForwardMobile::PushConstant push_constant;
+
+ if (inst->store_transform_cache) {
+ RendererStorageRD::store_transform(inst->transform, push_constant.transform);
+ } else {
+ RendererStorageRD::store_transform(Transform3D(), push_constant.transform);
+ }
+
+ push_constant.flags = inst->flags_cache;
+ push_constant.gi_offset = inst->gi_offset_cache;
+ push_constant.layer_mask = inst->layer_mask;
+ push_constant.instance_uniforms_ofs = uint32_t(inst->shader_parameters_offset);
+
+ if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) {
+ // abuse lightmap_uv_scale[0] here, should not be needed here
+ push_constant.lightmap_uv_scale[0] = p_params->uv_offset.x;
+ push_constant.lightmap_uv_scale[1] = p_params->uv_offset.y;
+ } else {
+ push_constant.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x;
+ push_constant.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y;
+ push_constant.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
+ push_constant.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y;
+ };
+
+ _fill_instance_indices(inst->omni_lights, inst->omni_light_count, push_constant.omni_lights, inst->spot_lights, inst->spot_light_count, push_constant.spot_lights, inst->reflection_probes, inst->reflection_probe_count, push_constant.reflection_probes, inst->decals, inst->decals_count, push_constant.decals, push_constant.layer_mask);
+
+ RID material_uniform_set;
+ SceneShaderForwardMobile::ShaderData *shader;
+ void *mesh_surface;
+
+ if (shadow_pass) {
+ material_uniform_set = surf->material_uniform_set_shadow;
+ shader = surf->shader_shadow;
+ mesh_surface = surf->surface_shadow;
+
+ } else {
+ material_uniform_set = surf->material_uniform_set;
+ shader = surf->shader;
+ mesh_surface = surf->surface;
+ }
+
+ if (!mesh_surface) {
+ continue;
+ }
+
+ //find cull variant
+ SceneShaderForwardMobile::ShaderData::CullVariant cull_variant;
+
+ if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
+ cull_variant = SceneShaderForwardMobile::ShaderData::CULL_VARIANT_DOUBLE_SIDED;
+ } else {
+ bool mirror = surf->owner->mirror;
+ if (p_params->reverse_cull) {
+ mirror = !mirror;
+ }
+ cull_variant = mirror ? SceneShaderForwardMobile::ShaderData::CULL_VARIANT_REVERSED : SceneShaderForwardMobile::ShaderData::CULL_VARIANT_NORMAL;
+ }
+
+ RS::PrimitiveType primitive = surf->primitive;
+ RID xforms_uniform_set = surf->owner->transforms_uniform_set;
+
+ SceneShaderForwardMobile::ShaderVersion shader_version = SceneShaderForwardMobile::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
+
+ switch (p_params->pass_mode) {
+ case PASS_MODE_COLOR:
+ case PASS_MODE_COLOR_TRANSPARENT: {
+ if (element_info.uses_lightmap) {
+ shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
+ } else {
+ shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS;
+ }
+ } break;
+ case PASS_MODE_SHADOW: {
+ shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS;
+ } break;
+ case PASS_MODE_SHADOW_DP: {
+ ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for shadow DP pass");
+ shader_version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_DP;
+ } break;
+ case PASS_MODE_DEPTH_MATERIAL: {
+ ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for material pass");
+ shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
+ } break;
+ }
+
+ PipelineCacheRD *pipeline = nullptr;
+
+ pipeline = &shader->pipelines[cull_variant][primitive][shader_version];
+
+ RD::VertexFormatID vertex_format = -1;
+ RID vertex_array_rd;
+ RID index_array_rd;
+
+ //skeleton and blend shape
+ if (surf->owner->mesh_instance.is_valid()) {
+ storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+ } else {
+ storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
+ }
+
+ index_array_rd = storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
+
+ if (prev_vertex_array_rd != vertex_array_rd) {
+ RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd);
+ prev_vertex_array_rd = vertex_array_rd;
+ }
+
+ if (prev_index_array_rd != index_array_rd) {
+ if (index_array_rd.is_valid()) {
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array_rd);
+ }
+ prev_index_array_rd = index_array_rd;
+ }
+
+ RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe);
+
+ if (pipeline_rd != prev_pipeline_rd) {
+ // checking with prev shader does not make so much sense, as
+ // the pipeline may still be different.
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd);
+ prev_pipeline_rd = pipeline_rd;
+ }
+
+ if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, TRANSFORMS_UNIFORM_SET);
+ prev_xforms_uniform_set = xforms_uniform_set;
+ }
+
+ if (material_uniform_set != prev_material_uniform_set) {
+ //update uniform set
+ if (material_uniform_set.is_valid()) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
+ }
+
+ prev_material_uniform_set = material_uniform_set;
+ }
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(GeometryInstanceForwardMobile::PushConstant));
+
+ uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : 1;
+ if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) {
+ instance_count /= surf->owner->trail_steps;
+ }
+
+ RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
+ }
+}
+
+/* Geometry instance */
+
+RendererSceneRender::GeometryInstance *RenderForwardMobile::geometry_instance_create(RID p_base) {
+ RS::InstanceType type = storage->get_base_type(p_base);
+ ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr);
+
+ GeometryInstanceForwardMobile *ginstance = geometry_instance_alloc.alloc();
+ ginstance->data = memnew(GeometryInstanceForwardMobile::Data);
+
+ ginstance->data->base = p_base;
+ ginstance->data->base_type = type;
+
+ _geometry_instance_mark_dirty(ginstance);
+
+ return ginstance;
+}
+
+void RenderForwardMobile::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->skeleton = p_skeleton;
+
+ _geometry_instance_mark_dirty(ginstance);
+ ginstance->data->dirty_dependencies = true;
+}
+
+void RenderForwardMobile::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->material_override = p_override;
+
+ _geometry_instance_mark_dirty(ginstance);
+ ginstance->data->dirty_dependencies = true;
+}
+
+void RenderForwardMobile::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->surface_materials = p_materials;
+
+ _geometry_instance_mark_dirty(ginstance);
+ ginstance->data->dirty_dependencies = true;
+}
+
+void RenderForwardMobile::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->mesh_instance = p_mesh_instance;
+
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->transform = p_transform;
+ ginstance->mirror = p_transform.basis.determinant() < 0;
+ ginstance->data->aabb = p_aabb;
+ ginstance->transformed_aabb = p_transformed_aabb;
+
+ Vector3 model_scale_vec = p_transform.basis.get_scale_abs();
+ // handle non uniform scale here
+
+ float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z));
+ float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z));
+ ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9;
+
+ ginstance->lod_model_scale = max_scale;
+}
+
+void RenderForwardMobile::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->layer_mask = p_layer_mask;
+}
+
+void RenderForwardMobile::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->lod_bias = p_lod_bias;
+}
+
+void RenderForwardMobile::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->use_baked_light = p_enable;
+
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) {
+ // !BAS! do we support this in mobile?
+ // GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ // ERR_FAIL_COND(!ginstance);
+ // ginstance->data->use_dynamic_gi = p_enable;
+ // _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->lightmap_instance = p_lightmap_instance;
+ ginstance->lightmap_uv_scale = p_lightmap_uv_scale;
+ ginstance->lightmap_slice_index = p_lightmap_slice_index;
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ if (p_sh9) {
+ if (ginstance->lightmap_sh == nullptr) {
+ ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc();
+ }
+
+ memcpy(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9);
+ } else {
+ if (ginstance->lightmap_sh != nullptr) {
+ geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
+ ginstance->lightmap_sh = nullptr;
+ }
+ }
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->shader_parameters_offset = p_offset;
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+void RenderForwardMobile::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->data->cast_double_sided_shadows = p_enable;
+ _geometry_instance_mark_dirty(ginstance);
+}
+
+Transform3D RenderForwardMobile::geometry_instance_get_transform(GeometryInstance *p_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_instance);
+ ERR_FAIL_COND_V(!ginstance, Transform3D());
+ return ginstance->transform;
+}
+
+AABB RenderForwardMobile::geometry_instance_get_aabb(GeometryInstance *p_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_instance);
+ ERR_FAIL_COND_V(!ginstance, AABB());
+ return ginstance->data->aabb;
+}
+
+void RenderForwardMobile::geometry_instance_free(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ if (ginstance->lightmap_sh != nullptr) {
+ geometry_instance_lightmap_sh.free(ginstance->lightmap_sh);
+ }
+ GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches;
+ while (surf) {
+ GeometryInstanceSurfaceDataCache *next = surf->next;
+ geometry_instance_surface_alloc.free(surf);
+ surf = next;
+ }
+ memdelete(ginstance->data);
+ geometry_instance_alloc.free(ginstance);
+}
+
+uint32_t RenderForwardMobile::geometry_instance_get_pair_mask() {
+ return ((1 << RS::INSTANCE_LIGHT) + (1 << RS::INSTANCE_REFLECTION_PROBE) + (1 << RS::INSTANCE_DECAL));
+}
+
+void RenderForwardMobile::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->omni_light_count = 0;
+ ginstance->spot_light_count = 0;
+
+ for (uint32_t i = 0; i < p_light_instance_count; i++) {
+ RS::LightType type = light_instance_get_type(p_light_instances[i]);
+ switch (type) {
+ case RS::LIGHT_OMNI: {
+ if (ginstance->omni_light_count < (uint32_t)MAX_RDL_CULL) {
+ ginstance->omni_lights[ginstance->omni_light_count] = p_light_instances[i];
+ ginstance->omni_light_count++;
+ }
+ } break;
+ case RS::LIGHT_SPOT: {
+ if (ginstance->spot_light_count < (uint32_t)MAX_RDL_CULL) {
+ ginstance->spot_lights[ginstance->spot_light_count] = p_light_instances[i];
+ ginstance->spot_light_count++;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+}
+
+void RenderForwardMobile::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->reflection_probe_count = p_reflection_probe_instance_count < (uint32_t)MAX_RDL_CULL ? p_reflection_probe_instance_count : (uint32_t)MAX_RDL_CULL;
+ for (uint32_t i = 0; i < ginstance->reflection_probe_count; i++) {
+ ginstance->reflection_probes[i] = p_reflection_probe_instances[i];
+ }
+}
+
+void RenderForwardMobile::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->decals_count = p_decal_instance_count < (uint32_t)MAX_RDL_CULL ? p_decal_instance_count : (uint32_t)MAX_RDL_CULL;
+ for (uint32_t i = 0; i < ginstance->decals_count; i++) {
+ ginstance->decals[i] = p_decal_instances[i];
+ }
+}
+
+void RenderForwardMobile::geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) {
+ // We do not have this here!
+}
+
+void RenderForwardMobile::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+ if (ginstance->dirty_list_element.in_list()) {
+ return;
+ }
+
+ //clear surface caches
+ GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches;
+
+ while (surf) {
+ GeometryInstanceSurfaceDataCache *next = surf->next;
+ geometry_instance_surface_alloc.free(surf);
+ surf = next;
+ }
+
+ ginstance->surface_caches = nullptr;
+
+ geometry_instance_dirty_list.add(&ginstance->dirty_list_element);
+}
+
+void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
+ bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
+ bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha);
+ bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
+ bool has_alpha = has_base_alpha || has_blend_alpha;
+
+ uint32_t flags = 0;
+
+ if (p_material->shader_data->uses_sss) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING;
+ }
+
+ if (p_material->shader_data->uses_screen_texture) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE;
+ }
+
+ if (p_material->shader_data->uses_depth_texture) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE;
+ }
+
+ if (p_material->shader_data->uses_normal_texture) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE;
+ }
+
+ if (ginstance->data->cast_double_sided_shadows) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS;
+ }
+
+ if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED) {
+ //material is only meant for alpha pass
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA;
+ if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED)) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH;
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
+ }
+ } else {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE;
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH;
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
+ }
+
+ if (p_material->shader_data->uses_particle_trails) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS;
+ }
+
+ SceneShaderForwardMobile::MaterialData *material_shadow = nullptr;
+ void *surface_shadow = nullptr;
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
+ flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
+ material_shadow = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D);
+
+ RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh);
+
+ if (shadow_mesh.is_valid()) {
+ surface_shadow = storage->mesh_get_surface(shadow_mesh, p_surface);
+ }
+
+ } else {
+ material_shadow = p_material;
+ }
+
+ GeometryInstanceSurfaceDataCache *sdcache = geometry_instance_surface_alloc.alloc();
+
+ sdcache->flags = flags;
+
+ sdcache->shader = p_material->shader_data;
+ sdcache->material_uniform_set = p_material->uniform_set;
+ sdcache->surface = storage->mesh_get_surface(p_mesh, p_surface);
+ sdcache->primitive = storage->mesh_surface_get_primitive(sdcache->surface);
+ sdcache->surface_index = p_surface;
+
+ if (ginstance->data->dirty_dependencies) {
+ storage->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker);
+ }
+
+ //shadow
+ sdcache->shader_shadow = material_shadow->shader_data;
+ sdcache->material_uniform_set_shadow = material_shadow->uniform_set;
+
+ sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface;
+
+ sdcache->owner = ginstance;
+
+ sdcache->next = ginstance->surface_caches;
+ ginstance->surface_caches = sdcache;
+
+ //sortkey
+
+ sdcache->sort.sort_key1 = 0;
+ sdcache->sort.sort_key2 = 0;
+
+ sdcache->sort.surface_index = p_surface;
+ sdcache->sort.material_id_low = p_material_id & 0x0000FFFF;
+ sdcache->sort.material_id_hi = p_material_id >> 16;
+ sdcache->sort.shader_id = p_shader_id;
+ sdcache->sort.geometry_id = p_mesh.get_local_index();
+ // sdcache->sort.uses_forward_gi = ginstance->can_sdfgi;
+ sdcache->sort.priority = p_material->priority;
+}
+
+void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
+ RID m_src;
+
+ m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material;
+
+ SceneShaderForwardMobile::MaterialData *material = nullptr;
+
+ if (m_src.is_valid()) {
+ material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (material) {
+ if (ginstance->data->dirty_dependencies) {
+ storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
+ }
+ } else {
+ material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D);
+ m_src = scene_shader.default_material;
+ }
+
+ ERR_FAIL_COND(!material);
+
+ _geometry_instance_add_surface_with_material(ginstance, p_surface, material, m_src.get_local_index(), storage->material_get_shader_id(m_src), p_mesh);
+
+ while (material->next_pass.is_valid()) {
+ RID next_pass = material->next_pass;
+ material = (SceneShaderForwardMobile::MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D);
+ if (!material || !material->shader_data->valid) {
+ break;
+ }
+ if (ginstance->data->dirty_dependencies) {
+ storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker);
+ }
+ _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh);
+ }
+}
+
+void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance);
+
+ if (ginstance->data->dirty_dependencies) {
+ ginstance->data->dependency_tracker.update_begin();
+ }
+
+ //add geometry for drawing
+ switch (ginstance->data->base_type) {
+ case RS::INSTANCE_MESH: {
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+ RID mesh = ginstance->data->base;
+
+ materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (materials) {
+ //if no materials, no surfaces.
+ const RID *inst_materials = ginstance->data->surface_materials.ptr();
+ uint32_t surf_mat_count = ginstance->data->surface_materials.size();
+
+ for (uint32_t j = 0; j < surface_count; j++) {
+ RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j];
+ _geometry_instance_add_surface(ginstance, j, material, mesh);
+ }
+ }
+
+ ginstance->instance_count = 1;
+
+ } break;
+
+ case RS::INSTANCE_MULTIMESH: {
+ RID mesh = storage->multimesh_get_mesh(ginstance->data->base);
+ if (mesh.is_valid()) {
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+
+ materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (materials) {
+ for (uint32_t j = 0; j < surface_count; j++) {
+ _geometry_instance_add_surface(ginstance, j, materials[j], mesh);
+ }
+ }
+
+ ginstance->instance_count = storage->multimesh_get_instances_to_draw(ginstance->data->base);
+ }
+
+ } break;
+#if 0
+ case RS::INSTANCE_IMMEDIATE: {
+ RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base);
+ ERR_CONTINUE(!immediate);
+
+ _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass);
+
+ } break;
+#endif
+ case RS::INSTANCE_PARTICLES: {
+ int draw_passes = storage->particles_get_draw_passes(ginstance->data->base);
+
+ for (int j = 0; j < draw_passes; j++) {
+ RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j);
+ if (!mesh.is_valid()) {
+ continue;
+ }
+
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+
+ materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (materials) {
+ for (uint32_t k = 0; k < surface_count; k++) {
+ _geometry_instance_add_surface(ginstance, k, materials[k], mesh);
+ }
+ }
+ }
+
+ ginstance->instance_count = storage->particles_get_amount(ginstance->data->base, ginstance->trail_steps);
+
+ } break;
+
+ default: {
+ }
+ }
+
+ //Fill push constant
+
+ bool store_transform = true;
+
+ if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
+ if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
+ }
+ if (storage->multimesh_uses_colors(ginstance->data->base)) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
+ }
+ if (storage->multimesh_uses_custom_data(ginstance->data->base)) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
+ }
+
+ ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+
+ } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
+ if (false) { // 2D particles
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
+ }
+
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
+
+ //for particles, stride is the trail size
+ ginstance->base_flags |= (ginstance->trail_steps << INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT);
+
+ if (!storage->particles_is_using_local_coords(ginstance->data->base)) {
+ store_transform = false;
+ }
+ ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+
+ } else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
+ if (storage->skeleton_is_valid(ginstance->data->skeleton)) {
+ ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ if (ginstance->data->dirty_dependencies) {
+ storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
+ }
+ }
+ }
+
+ ginstance->store_transform_cache = store_transform;
+
+ if (ginstance->data->dirty_dependencies) {
+ ginstance->data->dependency_tracker.update_end();
+ ginstance->data->dirty_dependencies = false;
+ }
+
+ ginstance->dirty_list_element.remove_from_list();
+}
+
+void RenderForwardMobile::_update_dirty_geometry_instances() {
+ while (geometry_instance_dirty_list.first()) {
+ _geometry_instance_update(geometry_instance_dirty_list.first()->self());
+ }
+}
+
+void RenderForwardMobile::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) {
+ switch (p_notification) {
+ case RendererStorage::DEPENDENCY_CHANGED_MATERIAL:
+ case RendererStorage::DEPENDENCY_CHANGED_MESH:
+ case RendererStorage::DEPENDENCY_CHANGED_PARTICLES:
+ case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH:
+ case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: {
+ static_cast<RenderForwardMobile *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+ } break;
+ case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
+ GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_tracker->userdata);
+ if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
+ ginstance->instance_count = static_cast<RenderForwardMobile *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base);
+ }
+ } break;
+ default: {
+ //rest of notifications of no interest
+ } break;
+ }
+}
+void RenderForwardMobile::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) {
+ static_cast<RenderForwardMobile *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+}
+
+/* misc */
+
+bool RenderForwardMobile::is_dynamic_gi_supported() const {
+ return false;
+}
+
+bool RenderForwardMobile::is_clustered_enabled() const {
+ return false;
+}
+
+bool RenderForwardMobile::is_volumetric_supported() const {
+ return false;
+}
+
+uint32_t RenderForwardMobile::get_max_elements() const {
+ return 256;
+}
+
+RenderForwardMobile *RenderForwardMobile::singleton = nullptr;
+
+RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) :
+ RendererSceneRenderRD(p_storage) {
+ singleton = this;
+
+ String defines;
+
+ defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n";
+ if (is_using_radiance_cubemap_array()) {
+ defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
+ }
+ // defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n";
+ defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(get_max_directional_lights()) + "\n";
+
+ {
+ //lightmaps
+ scene_state.max_lightmaps = 2;
+ defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n";
+ defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n";
+
+ scene_state.lightmap_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapData) * scene_state.max_lightmaps);
+ }
+ {
+ //captures
+ scene_state.max_lightmap_captures = 2048;
+ scene_state.lightmap_captures = memnew_arr(LightmapCaptureData, scene_state.max_lightmap_captures);
+ scene_state.lightmap_capture_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapCaptureData) * scene_state.max_lightmap_captures);
+ }
+ {
+ defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n";
+ }
+
+ scene_shader.init(p_storage, defines);
+
+ // !BAS! maybe we need a mobile version of this setting?
+ render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
+}
+
+RenderForwardMobile::~RenderForwardMobile() {
+ directional_shadow_atlas_set_size(0);
+
+ //clear base uniform set if still valid
+ for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) {
+ if (render_pass_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_sets[i])) {
+ RD::get_singleton()->free(render_pass_uniform_sets[i]);
+ }
+ }
+
+ {
+ for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) {
+ RD::get_singleton()->free(scene_state.uniform_buffers[i]);
+ }
+ RD::get_singleton()->free(scene_state.lightmap_buffer);
+ RD::get_singleton()->free(scene_state.lightmap_capture_buffer);
+ memdelete_arr(scene_state.lightmap_captures);
+ }
+}
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
new file mode 100644
index 0000000000..99cbd45b10
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -0,0 +1,608 @@
+/*************************************************************************/
+/* render_forward_mobile.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_MOBILE_H
+#define RENDERING_SERVER_SCENE_RENDER_FORWARD_MOBILE_H
+
+#include "core/templates/paged_allocator.h"
+#include "servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h"
+#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+
+namespace RendererSceneRenderImplementation {
+
+class RenderForwardMobile : public RendererSceneRenderRD {
+ friend SceneShaderForwardMobile;
+
+protected:
+ /* Scene Shader */
+
+ enum {
+ SCENE_UNIFORM_SET = 0,
+ RENDER_PASS_UNIFORM_SET = 1,
+ TRANSFORMS_UNIFORM_SET = 2,
+ MATERIAL_UNIFORM_SET = 3
+ };
+
+ enum {
+ MAX_LIGHTMAPS = 8,
+ MAX_RDL_CULL = 8, // maximum number of reflection probes, decals or lights we can cull per geometry instance
+ INSTANCE_DATA_BUFFER_MIN_SIZE = 4096
+ };
+
+ enum RenderListType {
+ RENDER_LIST_OPAQUE, //used for opaque objects
+ RENDER_LIST_ALPHA, //used for transparent objects
+ RENDER_LIST_SECONDARY, //used for shadows and other objects
+ RENDER_LIST_MAX
+ };
+
+ /* Scene Shader */
+
+ SceneShaderForwardMobile scene_shader;
+
+ /* Render Buffer */
+
+ struct RenderBufferDataForwardMobile : public RenderBufferData {
+ RID color;
+ RID depth;
+ // RID normal_roughness_buffer;
+
+ RS::ViewportMSAA msaa;
+ RD::TextureSamples texture_samples;
+
+ RID color_msaa;
+ RID depth_msaa;
+ // RID normal_roughness_buffer_msaa;
+
+ RID color_fb;
+ int width, height;
+ uint32_t view_count;
+
+ void clear();
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count);
+
+ ~RenderBufferDataForwardMobile();
+ };
+
+ virtual RenderBufferData *_create_render_buffer_data();
+
+ /* Rendering */
+
+ enum PassMode {
+ PASS_MODE_COLOR,
+ // PASS_MODE_COLOR_SPECULAR,
+ PASS_MODE_COLOR_TRANSPARENT,
+ PASS_MODE_SHADOW,
+ PASS_MODE_SHADOW_DP,
+ // PASS_MODE_DEPTH,
+ // PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
+ // PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI,
+ PASS_MODE_DEPTH_MATERIAL,
+ // PASS_MODE_SDF,
+ };
+
+ struct GeometryInstanceForwardMobile;
+ struct GeometryInstanceSurfaceDataCache;
+ struct RenderElementInfo;
+
+ struct RenderListParameters {
+ GeometryInstanceSurfaceDataCache **elements = nullptr;
+ RenderElementInfo *element_info = nullptr;
+ int element_count = 0;
+ bool reverse_cull = false;
+ PassMode pass_mode = PASS_MODE_COLOR;
+ // bool no_gi = false;
+ uint32_t view_count = 1;
+ RID render_pass_uniform_set;
+ bool force_wireframe = false;
+ Vector2 uv_offset;
+ Plane lod_plane;
+ float lod_distance_multiplier = 0.0;
+ float screen_lod_threshold = 0.0;
+ RD::FramebufferFormatID framebuffer_format = 0;
+ uint32_t element_offset = 0;
+ uint32_t barrier = RD::BARRIER_MASK_ALL;
+
+ RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
+ elements = p_elements;
+ element_info = p_element_info;
+ element_count = p_element_count;
+ reverse_cull = p_reverse_cull;
+ pass_mode = p_pass_mode;
+ // no_gi = p_no_gi;
+ view_count = p_view_count;
+ render_pass_uniform_set = p_render_pass_uniform_set;
+ force_wireframe = p_force_wireframe;
+ uv_offset = p_uv_offset;
+ lod_plane = p_lod_plane;
+ lod_distance_multiplier = p_lod_distance_multiplier;
+ screen_lod_threshold = p_screen_lod_threshold;
+ element_offset = p_element_offset;
+ barrier = p_barrier;
+ }
+ };
+
+ RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
+ virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color);
+
+ virtual void _render_shadow_begin();
+ virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true);
+ virtual void _render_shadow_process();
+ virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+
+ virtual void _render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
+ virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
+ virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture);
+ virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances);
+
+ uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
+
+ virtual void _base_uniforms_changed();
+ void _update_render_base_uniform_set();
+ virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
+
+ void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
+ void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
+ // void _update_instance_data_buffer(RenderListType p_render_list);
+
+ static RenderForwardMobile *singleton;
+
+ void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
+ void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
+
+ RID render_base_uniform_set;
+ LocalVector<RID> render_pass_uniform_sets;
+
+ /* Light map */
+
+ struct LightmapData {
+ float normal_xform[12];
+ };
+
+ struct LightmapCaptureData {
+ float sh[9 * 4];
+ };
+
+ /* Scene state */
+
+ struct SceneState {
+ // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
+ struct UBO {
+ float projection_matrix[16];
+ float inv_projection_matrix[16];
+ float camera_matrix[16];
+ float inv_camera_matrix[16];
+
+ float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+ float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+
+ float viewport_size[2];
+ float screen_pixel_size[2];
+
+ float directional_penumbra_shadow_kernel[128]; //32 vec4s
+ float directional_soft_shadow_kernel[128];
+ float penumbra_shadow_kernel[128];
+ float soft_shadow_kernel[128];
+
+ uint32_t directional_penumbra_shadow_samples;
+ uint32_t directional_soft_shadow_samples;
+ uint32_t penumbra_shadow_samples;
+ uint32_t soft_shadow_samples;
+
+ float ambient_light_color_energy[4];
+
+ float ambient_color_sky_mix;
+ uint32_t use_ambient_light;
+ uint32_t use_ambient_cubemap;
+ uint32_t use_reflection_cubemap;
+
+ float radiance_inverse_xform[12];
+
+ float shadow_atlas_pixel_size[2];
+ float directional_shadow_pixel_size[2];
+
+ uint32_t directional_light_count;
+ float dual_paraboloid_side;
+ float z_far;
+ float z_near;
+
+ uint32_t ssao_enabled;
+ float ssao_light_affect;
+ float ssao_ao_affect;
+ uint32_t roughness_limiter_enabled;
+
+ float roughness_limiter_amount;
+ float roughness_limiter_limit;
+ uint32_t roughness_limiter_pad[2];
+
+ float ao_color[4];
+
+ // Fog
+ uint32_t fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+
+ float fog_aerial_perspective;
+ uint32_t material_uv2_mode;
+
+ float time;
+ float reflection_multiplier;
+
+ uint32_t pancake_shadows;
+ uint32_t pad1;
+ uint32_t pad2;
+ uint32_t pad3;
+ };
+
+ UBO ubo;
+
+ LocalVector<RID> uniform_buffers;
+
+ // !BAS! We need to change lightmaps, we're not going to do this with a buffer but pushing the used lightmap in
+ LightmapData lightmaps[MAX_LIGHTMAPS];
+ RID lightmap_ids[MAX_LIGHTMAPS];
+ bool lightmap_has_sh[MAX_LIGHTMAPS];
+ uint32_t lightmaps_used = 0;
+ uint32_t max_lightmaps;
+ RID lightmap_buffer;
+
+ LightmapCaptureData *lightmap_captures;
+ uint32_t max_lightmap_captures;
+ RID lightmap_capture_buffer;
+
+ bool used_screen_texture = false;
+ bool used_normal_texture = false;
+ bool used_depth_texture = false;
+ bool used_sss = false;
+
+ struct ShadowPass {
+ uint32_t element_from;
+ uint32_t element_count;
+ bool flip_cull;
+ PassMode pass_mode;
+
+ RID rp_uniform_set;
+ Plane camera_plane;
+ float lod_distance_multiplier;
+ float screen_lod_threshold;
+
+ RID framebuffer;
+ RD::InitialAction initial_depth_action;
+ RD::FinalAction final_depth_action;
+ Rect2i rect;
+ };
+
+ LocalVector<ShadowPass> shadow_passes;
+ } scene_state;
+
+ /* Render List */
+
+ // !BAS! Render list can probably be reused between clustered and mobile?
+ struct RenderList {
+ LocalVector<GeometryInstanceSurfaceDataCache *> elements;
+ LocalVector<RenderElementInfo> element_info;
+
+ void clear() {
+ elements.clear();
+ element_info.clear();
+ }
+
+ //should eventually be replaced by radix
+
+ struct SortByKey {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
+ return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2);
+ }
+ };
+
+ void sort_by_key() {
+ SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ void sort_by_key_range(uint32_t p_from, uint32_t p_size) {
+ SortArray<GeometryInstanceSurfaceDataCache *, SortByKey> sorter;
+ sorter.sort(elements.ptr() + p_from, p_size);
+ }
+
+ struct SortByDepth {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
+ return (A->owner->depth < B->owner->depth);
+ }
+ };
+
+ void sort_by_depth() { //used for shadows
+
+ SortArray<GeometryInstanceSurfaceDataCache *, SortByDepth> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ struct SortByReverseDepthAndPriority {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const {
+ return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority);
+ }
+ };
+
+ void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha
+
+ SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ _FORCE_INLINE_ void add_element(GeometryInstanceSurfaceDataCache *p_element) {
+ elements.push_back(p_element);
+ }
+ };
+
+ struct RenderElementInfo {
+ uint32_t uses_lightmap : 1;
+ uint32_t lod_index : 8;
+ uint32_t reserved : 23;
+ };
+
+ template <PassMode p_pass_mode>
+ _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
+
+ void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
+
+ LocalVector<RD::DrawListID> thread_draw_lists;
+ void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params);
+ void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
+
+ uint32_t render_list_thread_threshold = 500;
+
+ RenderList render_list[RENDER_LIST_MAX];
+
+ /* Geometry instance */
+
+ // check which ones of these apply, probably all except GI and SDFGI
+ enum {
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
+ INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
+ INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
+ INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
+ INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
+ INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15,
+ INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16,
+ INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF,
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 24,
+ };
+
+ struct GeometryInstanceLightmapSH {
+ Color sh[9];
+ };
+
+ // Cached data for drawing surfaces
+ struct GeometryInstanceSurfaceDataCache {
+ enum {
+ FLAG_PASS_DEPTH = 1,
+ FLAG_PASS_OPAQUE = 2,
+ FLAG_PASS_ALPHA = 4,
+ FLAG_PASS_SHADOW = 8,
+ FLAG_USES_SHARED_SHADOW_MATERIAL = 128,
+ FLAG_USES_SUBSURFACE_SCATTERING = 2048,
+ FLAG_USES_SCREEN_TEXTURE = 4096,
+ FLAG_USES_DEPTH_TEXTURE = 8192,
+ FLAG_USES_NORMAL_TEXTURE = 16384,
+ FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768,
+ FLAG_USES_PARTICLE_TRAILS = 65536,
+ };
+
+ union {
+ struct {
+ // !BAS! CHECK BITS!!!
+
+ uint64_t surface_index : 10;
+ uint64_t geometry_id : 32;
+ uint64_t material_id_low : 16;
+
+ uint64_t material_id_hi : 16;
+ uint64_t shader_id : 32;
+ uint64_t uses_lightmap : 4; // sort by lightmap id here, not whether its yes/no (is 4 bits enough?)
+ uint64_t depth_layer : 4;
+ uint64_t priority : 8;
+
+ // uint64_t lod_index : 8; // no need to sort on LOD
+ // uint64_t uses_forward_gi : 1; // no GI here, remove
+ };
+ struct {
+ uint64_t sort_key1;
+ uint64_t sort_key2;
+ };
+ } sort;
+
+ RS::PrimitiveType primitive = RS::PRIMITIVE_MAX;
+ uint32_t flags = 0;
+ uint32_t surface_index = 0;
+ uint32_t lod_index = 0;
+
+ void *surface = nullptr;
+ RID material_uniform_set;
+ SceneShaderForwardMobile::ShaderData *shader = nullptr;
+
+ void *surface_shadow = nullptr;
+ RID material_uniform_set_shadow;
+ SceneShaderForwardMobile::ShaderData *shader_shadow = nullptr;
+
+ GeometryInstanceSurfaceDataCache *next = nullptr;
+ GeometryInstanceForwardMobile *owner = nullptr;
+ };
+
+ // !BAS! GeometryInstanceForwardClustered and GeometryInstanceForwardMobile will likely have a lot of overlap
+ // may need to think about making this its own class like GeometryInstanceRD?
+
+ struct GeometryInstanceForwardMobile : public GeometryInstance {
+ // setup
+ uint32_t base_flags = 0;
+ uint32_t flags_cache = 0;
+
+ // this structure maps to our push constant in our shader and is populated right before our draw call
+ struct PushConstant {
+ float transform[16];
+ uint32_t flags;
+ uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables
+ uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index)
+ uint32_t layer_mask = 1;
+ float lightmap_uv_scale[4]; // doubles as uv_offset when needed
+ uint32_t reflection_probes[2]; // packed reflection probes
+ uint32_t omni_lights[2]; // packed omni lights
+ uint32_t spot_lights[2]; // packed spot lights
+ uint32_t decals[2]; // packed spot lights
+ };
+
+ // PushConstant push_constant; // we populate this from our instance data
+
+ //used during rendering
+ uint32_t layer_mask = 1;
+ RID transforms_uniform_set;
+ float depth = 0;
+ bool mirror = false;
+ Transform3D transform;
+ bool store_transform_cache = true; // if true we copy our transform into our PushConstant, if false we use our transforms UBO and clear our PushConstants transform
+ bool non_uniform_scale = false;
+ AABB transformed_aabb; //needed for LOD
+ float lod_bias = 0.0;
+ float lod_model_scale = 1.0;
+ int32_t shader_parameters_offset = -1;
+ uint32_t instance_count = 0;
+ uint32_t trail_steps = 1;
+ RID mesh_instance;
+
+ // lightmap
+ uint32_t gi_offset_cache = 0; // !BAS! Should rename this to lightmap_offset_cache, in forward clustered this was shared between gi and lightmap
+ uint32_t lightmap_slice_index;
+ Rect2 lightmap_uv_scale;
+ RID lightmap_instance;
+ GeometryInstanceLightmapSH *lightmap_sh = nullptr;
+
+ // culled light info
+ uint32_t reflection_probe_count;
+ RID reflection_probes[MAX_RDL_CULL];
+ uint32_t omni_light_count;
+ RID omni_lights[MAX_RDL_CULL];
+ uint32_t spot_light_count;
+ RID spot_lights[MAX_RDL_CULL];
+ uint32_t decals_count;
+ RID decals[MAX_RDL_CULL];
+
+ GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
+
+ // do we use this?
+ SelfList<GeometryInstanceForwardMobile> dirty_list_element;
+
+ struct Data {
+ //data used less often goes into regular heap
+ RID base;
+ RS::InstanceType base_type;
+
+ RID skeleton;
+ Vector<RID> surface_materials;
+ RID material_override;
+ AABB aabb;
+
+ bool use_baked_light = false;
+ bool cast_double_sided_shadows = false;
+ // bool mirror = false; // !BAS! Does not seem used, we already have this in the main struct
+
+ bool dirty_dependencies = false;
+
+ RendererStorage::DependencyTracker dependency_tracker;
+ };
+
+ Data *data = nullptr;
+
+ GeometryInstanceForwardMobile() :
+ dirty_list_element(this) {}
+ };
+
+public:
+ static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker);
+ static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker);
+
+ SelfList<GeometryInstanceForwardMobile>::List geometry_instance_dirty_list;
+
+ PagedAllocator<GeometryInstanceForwardMobile> geometry_instance_alloc;
+ PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
+ PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
+
+ void _geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
+ void _geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
+ void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance);
+ void _geometry_instance_update(GeometryInstance *p_geometry_instance);
+ void _update_dirty_geometry_instances();
+
+ virtual GeometryInstance *geometry_instance_create(RID p_base);
+ virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton);
+ virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override);
+ virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials);
+ virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance);
+ virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb);
+ virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask);
+ virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias);
+ virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable);
+ virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable);
+ virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index);
+ virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9);
+ virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset);
+ virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable);
+
+ virtual Transform3D geometry_instance_get_transform(GeometryInstance *p_instance);
+ virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance);
+
+ virtual void geometry_instance_free(GeometryInstance *p_geometry_instance);
+
+ virtual uint32_t geometry_instance_get_pair_mask();
+ virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count);
+ virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count);
+ virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count);
+ virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count);
+
+ virtual bool free(RID p_rid);
+
+ virtual bool is_dynamic_gi_supported() const;
+ virtual bool is_clustered_enabled() const;
+ virtual bool is_volumetric_supported() const;
+ virtual uint32_t get_max_elements() const;
+
+ RenderForwardMobile(RendererStorageRD *p_storage);
+ ~RenderForwardMobile();
+};
+} // namespace RendererSceneRenderImplementation
+#endif // !RENDERING_SERVER_SCENE_RENDER_FORWARD_MOBILE_H
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
new file mode 100644
index 0000000000..b5fb9fbc62
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -0,0 +1,812 @@
+/*************************************************************************/
+/* scene_shader_forward_mobile.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "scene_shader_forward_mobile.h"
+#include "core/config/project_settings.h"
+#include "core/math/math_defs.h"
+#include "render_forward_mobile.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
+
+using namespace RendererSceneRenderImplementation;
+
+/* ShaderData */
+
+void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+ uses_screen_texture = false;
+
+ if (code == String()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompilerRD::GeneratedCode gen_code;
+
+ int blend_mode = BLEND_MODE_MIX;
+ int depth_testi = DEPTH_TEST_ENABLED;
+ int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
+ int cull = CULL_BACK;
+
+ uses_point_size = false;
+ uses_alpha = false;
+ uses_blend_alpha = false;
+ uses_depth_pre_pass = false;
+ uses_discard = false;
+ uses_roughness = false;
+ uses_normal = false;
+ bool wireframe = false;
+
+ unshaded = false;
+ uses_vertex = false;
+ uses_sss = false;
+ uses_transmittance = false;
+ uses_screen_texture = false;
+ uses_depth_texture = false;
+ uses_normal_texture = false;
+ uses_time = false;
+ writes_modelview_or_projection = false;
+ uses_world_coordinates = false;
+ uses_particle_trails = false;
+
+ int depth_drawi = DEPTH_DRAW_OPAQUE;
+
+ ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["vertex"] = ShaderCompilerRD::STAGE_VERTEX;
+ actions.entry_point_stages["fragment"] = ShaderCompilerRD::STAGE_FRAGMENT;
+ actions.entry_point_stages["light"] = ShaderCompilerRD::STAGE_FRAGMENT;
+
+ actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
+ actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
+ actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
+ actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
+
+ actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
+ actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
+
+ actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
+ actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
+ actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
+
+ actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
+
+ actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED);
+ actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT);
+ actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK);
+
+ actions.render_mode_flags["unshaded"] = &unshaded;
+ actions.render_mode_flags["wireframe"] = &wireframe;
+ actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
+
+ actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
+ actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
+
+ // actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
+ // actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
+
+ actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+ actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
+ actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture;
+ actions.usage_flag_pointers["DISCARD"] = &uses_discard;
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+ actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
+ actions.usage_flag_pointers["NORMAL"] = &uses_normal;
+ actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal;
+
+ actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
+ actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
+
+ actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["VERTEX"] = &uses_vertex;
+
+ actions.uniforms = &uniforms;
+
+ SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
+
+ Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
+
+ ERR_FAIL_COND(err != OK);
+
+ if (version.is_null()) {
+ version = shader_singleton->shader.version_create();
+ }
+
+ depth_draw = DepthDraw(depth_drawi);
+ depth_test = DepthTest(depth_testi);
+
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+
+ Map<String, String>::Element * el = gen_code.code.front();
+ while (el) {
+ print_line("\n**code " + el->key() + ":\n" + el->value());
+
+ el = el->next();
+ }
+
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX]);
+ print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT]);
+#endif
+
+ shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines);
+ ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ //blend modes
+
+ // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
+ if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
+ blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
+ }
+
+ RD::PipelineColorBlendState::Attachment blend_attachment;
+
+ switch (blend_mode) {
+ case BLEND_MODE_MIX: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ } break;
+ case BLEND_MODE_ADD: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ uses_blend_alpha = true; //force alpha used because of blend
+
+ } break;
+ case BLEND_MODE_SUB: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
+ blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ uses_blend_alpha = true; //force alpha used because of blend
+
+ } break;
+ case BLEND_MODE_MUL: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+ uses_blend_alpha = true; //force alpha used because of blend
+ } break;
+ case BLEND_MODE_ALPHA_TO_COVERAGE: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+ }
+ }
+
+ RD::PipelineColorBlendState blend_state_blend;
+ blend_state_blend.attachments.push_back(blend_attachment);
+ RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1);
+ RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2);
+ RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
+ RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
+
+ //update pipelines
+
+ RD::PipelineDepthStencilState depth_stencil_state;
+
+ if (depth_test != DEPTH_TEST_DISABLED) {
+ depth_stencil_state.enable_depth_test = true;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
+ }
+
+ for (int i = 0; i < CULL_VARIANT_MAX; i++) {
+ RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
+ };
+
+ RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull];
+
+ for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
+ RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
+ RD::RENDER_PRIMITIVE_POINTS,
+ RD::RENDER_PRIMITIVE_LINES,
+ RD::RENDER_PRIMITIVE_LINESTRIPS,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
+ };
+
+ RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
+
+ for (int k = 0; k < SHADER_VERSION_MAX; k++) {
+ if (!static_cast<SceneShaderForwardMobile *>(singleton)->shader.is_variant_enabled(k)) {
+ continue;
+ }
+ RD::PipelineRasterizationState raster_state;
+ raster_state.cull_mode = cull_mode_rd;
+ raster_state.wireframe = wireframe;
+
+ RD::PipelineColorBlendState blend_state;
+ RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
+ RD::PipelineMultisampleState multisample_state;
+
+ if (uses_alpha || uses_blend_alpha) {
+ // only allow these flags to go through if we have some form of msaa
+ if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
+ multisample_state.enable_alpha_to_coverage = true;
+ } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
+ multisample_state.enable_alpha_to_coverage = true;
+ multisample_state.enable_alpha_to_one = true;
+ }
+
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_MULTIVIEW || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) {
+ blend_state = blend_state_blend;
+ if (depth_draw == DEPTH_DRAW_OPAQUE) {
+ depth_stencil.enable_depth_write = false; //alpha does not draw depth
+ }
+ } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || k == SHADER_VERSION_SHADOW_PASS_DP) {
+ //none, blend state contains nothing
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else {
+ pipelines[i][j][k].clear();
+ continue; // do not use this version (will error if using it is attempted)
+ }
+ } else {
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_MULTIVIEW || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) {
+ blend_state = blend_state_opaque;
+ } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || k == SHADER_VERSION_SHADOW_PASS_DP) {
+ //none, leave empty
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else {
+ // ???
+ }
+ }
+
+ RID shader_variant = shader_singleton->shader.version_get_shader(version, k);
+ pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
+ }
+ }
+ }
+
+ valid = true;
+}
+
+void SceneShaderForwardMobile::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+ if (!p_texture.is_valid()) {
+ default_texture_params.erase(p_name);
+ } else {
+ default_texture_params[p_name] = p_texture;
+ }
+}
+
+void SceneShaderForwardMobile::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+ Map<int, StringName> order;
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+
+ if (E->get().texture_order >= 0) {
+ order[E->get().texture_order + 100000] = E->key();
+ } else {
+ order[E->get().order] = E->key();
+ }
+ }
+
+ for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
+ pi.name = E->get();
+ p_param_list->push_back(pi);
+ }
+}
+
+void SceneShaderForwardMobile::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E->get());
+ p.info.name = E->key(); //supply name
+ p.index = E->get().instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool SceneShaderForwardMobile::ShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool SceneShaderForwardMobile::ShaderData::is_animated() const {
+ return false;
+}
+
+bool SceneShaderForwardMobile::ShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant SceneShaderForwardMobile::ShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const {
+ SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
+
+ return shader_singleton->shader.version_get_native_source_code(version);
+}
+
+SceneShaderForwardMobile::ShaderData::ShaderData() {
+ valid = false;
+ uses_screen_texture = false;
+}
+
+SceneShaderForwardMobile::ShaderData::~ShaderData() {
+ SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
+ ERR_FAIL_COND(!shader_singleton);
+ //pipeline variants will clear themselves if shader is gone
+ if (version.is_valid()) {
+ shader_singleton->shader.version_free(version);
+ }
+}
+
+RendererStorageRD::ShaderData *SceneShaderForwardMobile::_create_shader_func() {
+ ShaderData *shader_data = memnew(ShaderData);
+ return shader_data;
+}
+
+void SceneShaderForwardMobile::MaterialData::set_render_priority(int p_priority) {
+ priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
+}
+
+void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) {
+ next_pass = p_pass;
+}
+
+void SceneShaderForwardMobile::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
+
+ if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
+ p_uniform_dirty = true;
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ uniform_buffer = RID();
+ }
+
+ ubo_data.resize(shader_data->ubo_size);
+ if (ubo_data.size()) {
+ uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
+ memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
+ }
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ //check whether buffer changed
+ if (p_uniform_dirty && ubo_data.size()) {
+ update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER);
+ }
+
+ uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
+
+ if ((uint32_t)texture_cache.size() != tex_uniform_count) {
+ texture_cache.resize(tex_uniform_count);
+ p_textures_dirty = true;
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ if (p_textures_dirty && tex_uniform_count) {
+ update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
+ }
+
+ if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
+ // This material does not require an uniform set, so don't create it.
+ return;
+ }
+
+ if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ //no reason to update uniform set, only UBO (or nothing) was needed to update
+ return;
+ }
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ if (shader_data->ubo_size) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ const RID *textures = texture_cache.ptrw();
+ for (uint32_t i = 0; i < tex_uniform_count; i++) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1 + i;
+ u.ids.push_back(textures[i]);
+ uniforms.push_back(u);
+ }
+ }
+
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET);
+}
+
+SceneShaderForwardMobile::MaterialData::~MaterialData() {
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ }
+
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ }
+}
+
+RendererStorageRD::MaterialData *SceneShaderForwardMobile::_create_material_func(ShaderData *p_shader) {
+ MaterialData *material_data = memnew(MaterialData);
+ material_data->shader_data = p_shader;
+ material_data->last_frame = false;
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+/* Scene Shader */
+
+SceneShaderForwardMobile *SceneShaderForwardMobile::singleton = nullptr;
+
+SceneShaderForwardMobile::SceneShaderForwardMobile() {
+ // there should be only one of these, contained within our RenderForwardMobile singleton.
+ singleton = this;
+}
+
+void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p_defines) {
+ storage = p_storage;
+
+ /* SCENE SHADER */
+
+ {
+ Vector<String> shader_versions;
+ shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS
+ shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here...
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_SHADOW_PASS_DP
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL
+
+ // multiview versions of our shaders
+ shader_versions.push_back("\n#define USE_MULTIVIEW\n"); // SHADER_VERSION_COLOR_PASS_MULTIVIEW
+ shader_versions.push_back("\n#define USE_MULTIVIEW\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW
+ shader_versions.push_back("\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS_MULTIVIEW
+
+ shader.initialize(shader_versions, p_defines);
+
+ if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_MULTIVIEW, false);
+ shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW, false);
+ shader.set_variant_enabled(SHADER_VERSION_SHADOW_PASS_MULTIVIEW, false);
+ }
+ }
+
+ storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
+ storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs);
+
+ {
+ //shader compiler
+ ShaderCompilerRD::DefaultIdentifierActions actions;
+
+ actions.renames["WORLD_MATRIX"] = "world_matrix";
+ actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix";
+ actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix";
+ actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix";
+ actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
+ actions.renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
+ actions.renames["MODELVIEW_MATRIX"] = "modelview";
+ actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
+
+ actions.renames["VERTEX"] = "vertex";
+ actions.renames["NORMAL"] = "normal";
+ actions.renames["TANGENT"] = "tangent";
+ actions.renames["BINORMAL"] = "binormal";
+ actions.renames["POSITION"] = "position";
+ actions.renames["UV"] = "uv_interp";
+ actions.renames["UV2"] = "uv2_interp";
+ actions.renames["COLOR"] = "color_interp";
+ actions.renames["POINT_SIZE"] = "gl_PointSize";
+ actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
+
+ actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
+ actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
+ actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
+ actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
+
+ //builtins
+
+ actions.renames["TIME"] = "scene_data.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
+ actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
+
+ actions.renames["FRAGCOORD"] = "gl_FragCoord";
+ actions.renames["FRONT_FACING"] = "gl_FrontFacing";
+ actions.renames["NORMAL_MAP"] = "normal_map";
+ actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
+ actions.renames["ALBEDO"] = "albedo";
+ actions.renames["ALPHA"] = "alpha";
+ actions.renames["METALLIC"] = "metallic";
+ actions.renames["SPECULAR"] = "specular";
+ actions.renames["ROUGHNESS"] = "roughness";
+ actions.renames["RIM"] = "rim";
+ actions.renames["RIM_TINT"] = "rim_tint";
+ actions.renames["CLEARCOAT"] = "clearcoat";
+ actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
+ actions.renames["ANISOTROPY"] = "anisotropy";
+ actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
+ actions.renames["SSS_STRENGTH"] = "sss_strength";
+ actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
+ actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
+ actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve";
+ actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
+ actions.renames["BACKLIGHT"] = "backlight";
+ actions.renames["AO"] = "ao";
+ actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
+ actions.renames["EMISSION"] = "emission";
+ actions.renames["POINT_COORD"] = "gl_PointCoord";
+ actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
+ actions.renames["SCREEN_UV"] = "screen_uv";
+ actions.renames["SCREEN_TEXTURE"] = "color_buffer";
+ actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
+ actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
+ actions.renames["DEPTH"] = "gl_FragDepth";
+ actions.renames["OUTPUT_IS_SRGB"] = "true";
+ actions.renames["FOG"] = "custom_fog";
+ actions.renames["RADIANCE"] = "custom_radiance";
+ actions.renames["IRRADIANCE"] = "custom_irradiance";
+ actions.renames["BONE_INDICES"] = "bone_attrib";
+ actions.renames["BONE_WEIGHTS"] = "weight_attrib";
+ actions.renames["CUSTOM0"] = "custom0_attrib";
+ actions.renames["CUSTOM1"] = "custom1_attrib";
+ actions.renames["CUSTOM2"] = "custom2_attrib";
+ actions.renames["CUSTOM3"] = "custom3_attrib";
+
+ actions.renames["VIEW_INDEX"] = "ViewIndex";
+ actions.renames["VIEW_MONO_LEFT"] = "0";
+ actions.renames["VIEW_RIGHT"] = "1";
+
+ //for light
+ actions.renames["VIEW"] = "view";
+ actions.renames["LIGHT_COLOR"] = "light_color";
+ actions.renames["LIGHT"] = "light";
+ actions.renames["ATTENUATION"] = "attenuation";
+ actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation";
+ actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
+ actions.renames["SPECULAR_LIGHT"] = "specular_light";
+
+ actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+ actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n";
+ actions.usage_defines["BINORMAL"] = "@TANGENT";
+ actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";
+ actions.usage_defines["RIM_TINT"] = "@RIM";
+ actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n";
+ actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
+ actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";
+ actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
+ actions.usage_defines["AO"] = "#define AO_USED\n";
+ actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
+ actions.usage_defines["UV"] = "#define UV_USED\n";
+ actions.usage_defines["UV2"] = "#define UV2_USED\n";
+ actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
+ actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
+ actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
+ actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
+ actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
+ actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
+ actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
+ actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
+ actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
+ actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
+ actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+
+ actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
+ actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
+ actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
+ actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
+
+ actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
+ actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
+ actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
+ actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+
+ actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+ actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+
+ actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
+ actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
+ actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
+
+ actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+ actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
+ actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
+ actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
+ actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n";
+
+ bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
+ if (!force_lambert) {
+ actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
+ }
+
+ actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
+ actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
+
+ actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
+
+ bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx");
+ if (!force_blinn) {
+ actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
+ } else {
+ actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
+ }
+
+ actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
+ actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
+ actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
+ actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
+ actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+ actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
+ actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
+ actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+
+ actions.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 1;
+ actions.texture_layout_set = RenderForwardMobile::MATERIAL_UNIFORM_SET;
+ actions.base_uniform_string = "material.";
+ actions.base_varying_index = 10;
+
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+ actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+ actions.global_buffer_array_variable = "global_variables.data";
+ actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
+
+ compiler.initialize(actions);
+ }
+
+ {
+ //default material and shader
+ default_shader = storage->shader_allocate();
+ storage->shader_initialize(default_shader);
+ storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n");
+ default_material = storage->material_allocate();
+ storage->material_initialize(default_material);
+ storage->material_set_shader(default_material, default_shader);
+
+ MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
+ default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
+ }
+
+ {
+ overdraw_material_shader = storage->shader_allocate();
+ storage->shader_initialize(overdraw_material_shader);
+ storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }");
+ overdraw_material = storage->material_allocate();
+ storage->material_initialize(overdraw_material);
+ storage->material_set_shader(overdraw_material, overdraw_material_shader);
+
+ wireframe_material_shader = storage->shader_allocate();
+ storage->shader_initialize(wireframe_material_shader);
+ storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }");
+ wireframe_material = storage->material_allocate();
+ storage->material_initialize(wireframe_material);
+ storage->material_set_shader(wireframe_material, wireframe_material_shader);
+ }
+
+ {
+ default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(default_vec4_xform_buffer);
+ u.binding = 0;
+ uniforms.push_back(u);
+
+ default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RenderForwardMobile::TRANSFORMS_UNIFORM_SET);
+ }
+ {
+ RD::SamplerState sampler;
+ sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.enable_compare = true;
+ sampler.compare_op = RD::COMPARE_OP_LESS;
+ shadow_sampler = RD::get_singleton()->sampler_create(sampler);
+ }
+}
+
+SceneShaderForwardMobile::~SceneShaderForwardMobile() {
+ RD::get_singleton()->free(default_vec4_xform_buffer);
+ RD::get_singleton()->free(shadow_sampler);
+
+ storage->free(wireframe_material_shader);
+ storage->free(overdraw_material_shader);
+ storage->free(default_shader);
+
+ storage->free(wireframe_material);
+ storage->free(overdraw_material);
+ storage->free(default_material);
+}
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
new file mode 100644
index 0000000000..f4f6ceeb1d
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -0,0 +1,208 @@
+/*************************************************************************/
+/* scene_shader_forward_mobile.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RSSR_SCENE_SHADER_FM_H
+#define RSSR_SCENE_SHADER_FM_H
+
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl.gen.h"
+
+namespace RendererSceneRenderImplementation {
+
+class SceneShaderForwardMobile {
+private:
+ static SceneShaderForwardMobile *singleton;
+ RendererStorageRD *storage;
+
+public:
+ enum ShaderVersion {
+ SHADER_VERSION_COLOR_PASS,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS,
+ SHADER_VERSION_SHADOW_PASS,
+ SHADER_VERSION_SHADOW_PASS_DP,
+ SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
+
+ SHADER_VERSION_COLOR_PASS_MULTIVIEW,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW,
+ SHADER_VERSION_SHADOW_PASS_MULTIVIEW,
+
+ SHADER_VERSION_MAX
+ };
+
+ struct ShaderData : public RendererStorageRD::ShaderData {
+ enum BlendMode { //used internally
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_ALPHA_TO_COVERAGE
+ };
+
+ enum DepthDraw {
+ DEPTH_DRAW_DISABLED,
+ DEPTH_DRAW_OPAQUE,
+ DEPTH_DRAW_ALWAYS
+ };
+
+ enum DepthTest {
+ DEPTH_TEST_DISABLED,
+ DEPTH_TEST_ENABLED
+ };
+
+ enum Cull {
+ CULL_DISABLED,
+ CULL_FRONT,
+ CULL_BACK
+ };
+
+ enum CullVariant {
+ CULL_VARIANT_NORMAL,
+ CULL_VARIANT_REVERSED,
+ CULL_VARIANT_DOUBLE_SIDED,
+ CULL_VARIANT_MAX
+
+ };
+
+ enum AlphaAntiAliasing {
+ ALPHA_ANTIALIASING_OFF,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
+ };
+
+ bool valid;
+ RID version;
+ uint32_t vertex_input_mask;
+ PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
+
+ String path;
+
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String code;
+ Map<StringName, RID> default_texture_params;
+
+ DepthDraw depth_draw;
+ DepthTest depth_test;
+
+ bool uses_point_size;
+ bool uses_alpha;
+ bool uses_blend_alpha;
+ bool uses_alpha_clip;
+ bool uses_depth_pre_pass;
+ bool uses_discard;
+ bool uses_roughness;
+ bool uses_normal;
+ bool uses_particle_trails;
+
+ bool unshaded;
+ bool uses_vertex;
+ bool uses_sss;
+ bool uses_transmittance;
+ bool uses_screen_texture;
+ bool uses_depth_texture;
+ bool uses_normal_texture;
+ bool uses_time;
+ bool writes_modelview_or_projection;
+ bool uses_world_coordinates;
+
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
+
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+
+ ShaderData();
+ virtual ~ShaderData();
+ };
+
+ RendererStorageRD::ShaderData *_create_shader_func();
+ static RendererStorageRD::ShaderData *_create_shader_funcs() {
+ return static_cast<SceneShaderForwardMobile *>(singleton)->_create_shader_func();
+ }
+
+ struct MaterialData : public RendererStorageRD::MaterialData {
+ uint64_t last_frame;
+ ShaderData *shader_data;
+ RID uniform_buffer;
+ RID uniform_set;
+ Vector<RID> texture_cache;
+ Vector<uint8_t> ubo_data;
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+ RID next_pass;
+ uint8_t priority;
+ virtual void set_render_priority(int p_priority);
+ virtual void set_next_pass(RID p_pass);
+ virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual ~MaterialData();
+ };
+
+ RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
+ static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
+ return static_cast<SceneShaderForwardMobile *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
+ }
+
+ SceneForwardMobileShaderRD shader;
+ ShaderCompilerRD compiler;
+
+ RID default_shader;
+ RID default_material;
+ RID overdraw_material_shader;
+ RID overdraw_material;
+ RID wireframe_material_shader;
+ RID wireframe_material;
+ RID default_shader_rd;
+
+ RID default_vec4_xform_buffer;
+ RID default_vec4_xform_uniform_set;
+
+ RID shadow_sampler;
+
+ SceneShaderForwardMobile();
+ ~SceneShaderForwardMobile();
+
+ void init(RendererStorageRD *p_storage, const String p_defines);
+};
+
+} // namespace RendererSceneRenderImplementation
+#endif // !RSSR_SCENE_SHADER_FM_H
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 3c76c91a67..9d325fe69b 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -31,8 +31,10 @@
#include "renderer_canvas_render_rd.h"
#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
+#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
#include "renderer_compositor_rd.h"
+#include "servers/rendering/rendering_server_default.h"
void RendererCanvasRenderRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
p_mat4[0] = p_transform.elements[0][0];
@@ -74,7 +76,7 @@ void RendererCanvasRenderRD::_update_transform_2d_to_mat2x3(const Transform2D &p
p_mat2x3[5] = p_transform.elements[2][1];
}
-void RendererCanvasRenderRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) {
+void RendererCanvasRenderRD::_update_transform_to_mat4(const Transform3D &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];
@@ -304,7 +306,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
index_buffer.resize(p_indices.size() * sizeof(int32_t));
{
uint8_t *w = index_buffer.ptrw();
- copymem(w, p_indices.ptr(), sizeof(int32_t) * p_indices.size());
+ memcpy(w, p_indices.ptr(), sizeof(int32_t) * p_indices.size());
}
pb.index_buffer = RD::get_singleton()->index_buffer_create(p_indices.size(), RD::INDEX_BUFFER_FORMAT_UINT32, index_buffer);
pb.indices = RD::get_singleton()->index_array_create(pb.index_buffer, 0, p_indices.size());
@@ -390,7 +392,7 @@ void RendererCanvasRenderRD::_bind_canvas_texture(RD::DrawListID p_draw_list, RI
r_last_texture = p_texture;
}
-void RendererCanvasRenderRD::_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) {
+void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, 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
RS::CanvasItemTextureFilter current_filter = default_filter;
@@ -705,286 +707,158 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
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);
+ RID mesh;
+ RID mesh_instance;
+ RID texture;
+ Color modulate(1, 1, 1, 1);
+ float world_backup[6];
+ int instance_count = 1;
+
+ for (int j = 0; j < 6; j++) {
+ world_backup[j] = push_constant.world[j];
}
- 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);
+ if (c->type == Item::Command::TYPE_MESH) {
+ const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
+ mesh = m->mesh;
+ mesh_instance = m->mesh_instance;
+ texture = m->texture;
+ modulate = m->modulate;
+ _update_transform_2d_to_mat2x3(base_transform * m->transform, push_constant.world);
+ } else if (c->type == Item::Command::TYPE_MULTIMESH) {
+ const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
+ RID multimesh = mm->multimesh;
+ mesh = storage->multimesh_get_mesh(multimesh);
+ texture = mm->texture;
+
+ if (storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
+ break;
}
- }
- 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);
+ instance_count = storage->multimesh_get_instances_to_draw(multimesh);
- if (!mesh_data)
- break;
+ RID uniform_set = storage->multimesh_get_2d_uniform_set(multimesh, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET);
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET);
+ push_constant.flags |= 1; //multimesh, trails disabled
+ if (storage->multimesh_uses_colors(multimesh)) {
+ push_constant.flags |= FLAGS_INSTANCING_HAS_COLORS;
+ }
+ if (storage->multimesh_uses_custom_data(multimesh)) {
+ push_constant.flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
+ }
+ } else if (c->type == Item::Command::TYPE_PARTICLES) {
+ const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
+ ERR_BREAK(storage->particles_get_mode(pt->particles) != RS::PARTICLES_MODE_2D);
+ storage->particles_request_process(pt->particles);
- RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map);
+ if (storage->particles_is_inactive(pt->particles)) {
+ break;
+ }
- 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);
+ RenderingServerDefault::redraw_request(); // active particles means redraw request
- if (texture) {
- Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
- state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
- }
+ bool local_coords = true;
+ int dpc = storage->particles_get_draw_passes(pt->particles);
+ if (dpc == 0) {
+ break; //nothing to draw
+ }
+ uint32_t divisor = 1;
+ instance_count = storage->particles_get_amount(pt->particles, divisor);
- int amount = MIN(multi_mesh->size, multi_mesh->visible_instances);
+ RID uniform_set = storage->particles_get_instance_buffer_uniform_set(pt->particles, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET);
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET);
- if (amount == -1) {
- amount = multi_mesh->size;
- }
+ push_constant.flags |= divisor;
+ instance_count /= divisor;
- 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);
+ push_constant.flags |= FLAGS_INSTANCING_HAS_COLORS;
+ push_constant.flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
- glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer
+ mesh = storage->particles_get_draw_pass_mesh(pt->particles, 0); //higher ones are ignored
+ texture = pt->texture;
- 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);
+ if (storage->particles_has_collision(pt->particles) && storage->render_target_is_sdf_enabled(p_render_target)) {
+ //pass collision information
+ Transform2D xform;
+ if (local_coords) {
+ xform = p_item->final_transform;
+ } else {
+ xform = p_canvas_transform_inverse;
+ }
- int color_ofs;
+ RID sdf_texture = storage->render_target_get_sdf_texture(p_render_target);
- 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;
- }
+ Rect2 to_screen;
+ {
+ Rect2 sdf_rect = storage->render_target_get_sdf_rect(p_render_target);
- 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;
- }
+ to_screen.size = Vector2(1.0 / sdf_rect.size.width, 1.0 / sdf_rect.size.height);
+ to_screen.position = -sdf_rect.position * to_screen.size;
+ }
- 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);
+ storage->particles_set_canvas_sdf_collision(pt->particles, true, xform, to_screen, sdf_texture);
} else {
- glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount);
+ storage->particles_set_canvas_sdf_collision(pt->particles, false, Transform2D(), Rect2(), RID());
}
+ }
- glBindVertexArray(0);
+ if (mesh.is_null()) {
+ break;
}
- 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);
+ _bind_canvas_texture(p_draw_list, texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);
- } break;
- case Item::Command::TYPE_PARTICLES: {
- Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c);
+ uint32_t surf_count = storage->mesh_get_surface_count(mesh);
+ 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 };
- RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles);
- if (!particles)
- break;
-
- if (particles->inactive && !particles->emitting)
- break;
+ push_constant.modulation[0] = base_color.r * modulate.r;
+ push_constant.modulation[1] = base_color.g * modulate.g;
+ push_constant.modulation[2] = base_color.b * modulate.b;
+ push_constant.modulation[3] = base_color.a * modulate.a;
- glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white
+ 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;
+ }
- RenderingServerDefault::redraw_request();
+ for (uint32_t j = 0; j < surf_count; j++) {
+ void *surface = storage->mesh_get_surface(mesh, j);
- storage->particles_request_process(particles_cmd->particles);
- //enable instancing
+ RS::PrimitiveType primitive = storage->mesh_surface_get_primitive(surface);
+ ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
- 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);
+ uint32_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask();
- RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map);
+ RID vertex_array;
+ RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID;
- 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 (mesh_instance.is_valid()) {
+ storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array, vertex_format);
+ } else {
+ storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array, vertex_format);
+ }
- 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();
+ RID pipeline = pipeline_variants->variants[light_mode][variant[primitive]].get_render_pipeline(vertex_format, p_framebuffer_format);
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
- state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf);
- }
+ RID index_array = storage->mesh_surface_get_index_array(surface, 0);
- 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 (index_array.is_valid()) {
+ RD::get_singleton()->draw_list_bind_index_array(p_draw_list, index_array);
}
- 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);
- }
- }
+ RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, vertex_array);
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
- glBindVertexArray(0);
+ RD::get_singleton()->draw_list_draw(p_draw_list, index_array.is_valid(), instance_count);
+ }
- 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);
+ for (int j = 0; j < 6; j++) {
+ push_constant.world[j] = world_backup[j];
+ }
} 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);
@@ -1210,7 +1084,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
}
}
- _render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
+ _render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
prev_material = material;
}
@@ -1376,7 +1250,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
Size2i ssize = storage->render_target_get_size(p_to_render_target);
- Transform screen_transform;
+ Transform3D 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);
@@ -1437,6 +1311,9 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
Item *canvas_group_owner = nullptr;
+ bool update_skeletons = false;
+ bool time_used = false;
+
while (ci) {
if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
backbuffer_copy = true;
@@ -1461,6 +1338,9 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
if (md->shader_data->uses_sdf) {
r_sdf_used = true;
}
+ if (md->shader_data->uses_time) {
+ time_used = true;
+ }
if (md->last_frame != RendererCompositorRD::singleton->get_frame_number()) {
md->last_frame = RendererCompositorRD::singleton->get_frame_number();
if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) {
@@ -1472,9 +1352,27 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
}
}
+ if (ci->skeleton.is_valid()) {
+ const Item::Command *c = ci->commands;
+
+ while (c) {
+ if (c->type == Item::Command::TYPE_MESH) {
+ const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c);
+ if (cm->mesh_instance.is_valid()) {
+ storage->mesh_instance_check_for_update(cm->mesh_instance);
+ update_skeletons = true;
+ }
+ }
+ }
+ }
+
if (ci->canvas_group_owner != nullptr) {
if (canvas_group_owner == nullptr) {
//Canvas group begins here, render until before this item
+ if (update_skeletons) {
+ storage->update_mesh_instances();
+ update_skeletons = false;
+ }
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
item_count = 0;
@@ -1494,6 +1392,11 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
}
if (ci == canvas_group_owner) {
+ if (update_skeletons) {
+ storage->update_mesh_instances();
+ update_skeletons = false;
+ }
+
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true);
item_count = 0;
@@ -1506,6 +1409,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
if (backbuffer_copy) {
//render anything pending, including clearing if no items
+ if (update_skeletons) {
+ storage->update_mesh_instances();
+ update_skeletons = false;
+ }
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
item_count = 0;
@@ -1518,6 +1425,11 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
items[item_count++] = ci;
if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
+ if (update_skeletons) {
+ storage->update_mesh_instances();
+ update_skeletons = false;
+ }
+
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
//then reset
item_count = 0;
@@ -1525,6 +1437,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
ci = ci->next;
}
+
+ if (time_used) {
+ RenderingServerDefault::redraw_request();
+ }
}
RID RendererCanvasRenderRD::light_create() {
@@ -1623,7 +1539,7 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index,
}
Vector3 cam_target = Basis(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
- projection = projection * CameraMatrix(Transform().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
+ projection = projection * CameraMatrix(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
ShadowRenderPushConstant push_constant;
for (int y = 0; y < 4; y++) {
@@ -1701,7 +1617,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh
CameraMatrix projection;
projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance);
- projection = projection * CameraMatrix(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse());
+ projection = projection * CameraMatrix(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse());
ShadowRenderPushConstant push_constant;
for (int y = 0; y < 4; y++) {
@@ -2001,6 +1917,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
uniforms.clear();
uses_screen_texture = false;
uses_sdf = false;
+ uses_time = false;
if (code == String()) {
return; //just invalid, but no error
@@ -2025,6 +1942,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
+ actions.usage_flag_pointers["TIME"] = &uses_time;
actions.uniforms = &uniforms;
@@ -2491,6 +2409,9 @@ RendererCanvasRenderRD::RendererCanvasRenderRD(RendererStorageRD *p_storage) {
actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform";
actions.renames["SCREEN_MATRIX"] = "canvas_data.screen_transform";
actions.renames["TIME"] = "canvas_data.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
actions.renames["AT_LIGHT_PASS"] = "false";
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index cb947d7180..8c1376e2dc 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -67,12 +67,10 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
};
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_INSTANCING_MASK = 0x7F,
+ FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
+ FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
FLAGS_CLIP_RECT_UV = (1 << 9),
FLAGS_TRANSPOSE_RECT = (1 << 10),
@@ -178,6 +176,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
bool uses_screen_texture = false;
bool uses_sdf = false;
+ bool uses_time = false;
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
@@ -427,14 +426,14 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer);
inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size); //recursive, so regular inline used instead.
- 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_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, 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, bool p_to_backbuffer = false);
_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_transform_to_mat4(const Transform3D &p_transform, float *p_mat4);
void _update_shadow_atlas();
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index 2247b841c9..f9ac7c8fa3 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -31,6 +31,7 @@
#include "renderer_compositor_rd.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
void RendererCompositorRD::prepare_for_blitting_render_targets() {
RD::get_singleton()->prepare_screen_for_drawing();
@@ -44,32 +45,40 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID
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.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
u.binding = 0;
- u.ids.push_back(copy_viewports_sampler);
+ u.ids.push_back(blit.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);
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, blit.shader.version_get_shader(blit.shader_version, BLIT_MODE_NORMAL), 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);
+ BlitMode mode = p_render_targets[i].lens_distortion.apply ? BLIT_MODE_LENS : p_render_targets[i].multi_view.use_layer ? BLIT_MODE_USE_LAYER :
+ BLIT_MODE_NORMAL;
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blit.pipelines[mode]);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.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));
+ blit.push_constant.rect[0] = p_render_targets[i].rect.position.x / screen_size.width;
+ blit.push_constant.rect[1] = p_render_targets[i].rect.position.y / screen_size.height;
+ blit.push_constant.rect[2] = p_render_targets[i].rect.size.width / screen_size.width;
+ blit.push_constant.rect[3] = p_render_targets[i].rect.size.height / screen_size.height;
+ blit.push_constant.layer = p_render_targets[i].multi_view.layer;
+ blit.push_constant.eye_center[0] = p_render_targets[i].lens_distortion.eye_center.x;
+ blit.push_constant.eye_center[1] = p_render_targets[i].lens_distortion.eye_center.y;
+ blit.push_constant.k1 = p_render_targets[i].lens_distortion.k1;
+ blit.push_constant.k2 = p_render_targets[i].lens_distortion.k2;
+ blit.push_constant.upscale = p_render_targets[i].lens_distortion.upscale;
+ blit.push_constant.aspect_ratio = p_render_targets[i].lens_distortion.aspect_ratio;
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant));
RD::get_singleton()->draw_list_draw(draw_list, true);
}
@@ -96,40 +105,22 @@ void RendererCompositorRD::end_frame(bool p_swap_buffers) {
}
void RendererCompositorRD::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);
+ {
+ // Initialize blit
+ Vector<String> blit_modes;
+ blit_modes.push_back("\n");
+ blit_modes.push_back("\n#define USE_LAYER\n");
+ blit_modes.push_back("\n#define USE_LAYER\n#define APPLY_LENS_DISTORTION\n");
+
+ blit.shader.initialize(blit_modes);
+
+ blit.shader_version = blit.shader.version_create();
+
+ for (int i = 0; i < BLIT_MODE_MAX; i++) {
+ blit.pipelines[i] = RD::get_singleton()->render_pipeline_create(blit.shader.version_get_shader(blit.shader_version, i), 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);
}
- }
- { //create index array for copy shader
+ //create index array for copy shader
Vector<uint8_t> pv;
pv.resize(6 * 4);
{
@@ -142,15 +133,10 @@ void RendererCompositorRD::initialize() {
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);
- }
+ blit.index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
+ blit.array = RD::get_singleton()->index_array_create(blit.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());
+ blit.sampler = RD::get_singleton()->sampler_create(RD::SamplerState());
}
}
@@ -162,18 +148,68 @@ void RendererCompositorRD::finalize() {
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);
+ blit.shader.version_free(blit.shader_version);
+ RD::get_singleton()->free(blit.index_buffer);
+ RD::get_singleton()->free(blit.sampler);
}
RendererCompositorRD *RendererCompositorRD::singleton = nullptr;
RendererCompositorRD::RendererCompositorRD() {
+ {
+ String shader_cache_dir = Engine::get_singleton()->get_shader_cache_path();
+ if (shader_cache_dir == String()) {
+ shader_cache_dir = "user://";
+ }
+ DirAccessRef da = DirAccess::open(shader_cache_dir);
+ if (!da) {
+ ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
+ } else {
+ Error err = da->change_dir("shader_cache");
+ if (err != OK) {
+ err = da->make_dir("shader_cache");
+ }
+ if (err != OK) {
+ ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
+ } else {
+ shader_cache_dir = shader_cache_dir.plus_file("shader_cache");
+
+ bool shader_cache_enabled = GLOBAL_GET("rendering/shader_compiler/shader_cache/enabled");
+ if (!Engine::get_singleton()->is_editor_hint() && !shader_cache_enabled) {
+ shader_cache_dir = String(); //disable only if not editor
+ }
+
+ if (shader_cache_dir != String()) {
+ bool compress = GLOBAL_GET("rendering/shader_compiler/shader_cache/compress");
+ bool use_zstd = GLOBAL_GET("rendering/shader_compiler/shader_cache/use_zstd_compression");
+ bool strip_debug = GLOBAL_GET("rendering/shader_compiler/shader_cache/strip_debug");
+
+ ShaderRD::set_shader_cache_dir(shader_cache_dir);
+ ShaderRD::set_shader_cache_save_compressed(compress);
+ ShaderRD::set_shader_cache_save_compressed_zstd(use_zstd);
+ ShaderRD::set_shader_cache_save_debug(!strip_debug);
+ }
+ }
+ }
+ }
+
singleton = this;
time = 0;
storage = memnew(RendererStorageRD);
canvas = memnew(RendererCanvasRenderRD(storage));
- scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
+
+ uint32_t back_end = GLOBAL_GET("rendering/vulkan/rendering/back_end");
+ uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
+
+ if (back_end == 1 || textures_per_stage < 48) {
+ scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile(storage));
+ } else { // back_end == 0
+ // default to our high end renderer
+ scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
+ }
+}
+
+RendererCompositorRD::~RendererCompositorRD() {
+ ShaderRD::set_shader_cache_dir(String());
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 5b5f3ad0cb..7a78322051 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -35,8 +35,10 @@
#include "core/templates/thread_work_pool.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h"
+#include "servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h"
#include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/shaders/blit.glsl.gen.h"
class RendererCompositorRD : public RendererCompositor {
protected:
@@ -44,11 +46,35 @@ protected:
RendererStorageRD *storage;
RendererSceneRenderRD *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;
+ enum BlitMode {
+ BLIT_MODE_NORMAL,
+ BLIT_MODE_USE_LAYER,
+ BLIT_MODE_LENS,
+ BLIT_MODE_MAX
+ };
+
+ struct BlitPushConstant {
+ float rect[4];
+
+ float eye_center[2];
+ float k1;
+ float k2;
+
+ float upscale;
+ float aspect_ratio;
+ uint32_t layer;
+ uint32_t pad1;
+ };
+
+ struct Blit {
+ BlitPushConstant push_constant;
+ BlitShaderRD shader;
+ RID shader_version;
+ RID pipelines[BLIT_MODE_MAX];
+ RID index_buffer;
+ RID array;
+ RID sampler;
+ } blit;
Map<RID, RID> render_target_descriptors;
@@ -92,6 +118,6 @@ public:
static RendererCompositorRD *singleton;
RendererCompositorRD();
- ~RendererCompositorRD() {}
+ ~RendererCompositorRD();
};
#endif // RASTERIZER_RD_H
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
index 3856f38457..43a4058ab6 100644
--- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
@@ -1099,7 +1099,7 @@ void RendererSceneGIRD::SDFGI::update_cascades() {
RD::get_singleton()->buffer_update(cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE);
}
-void RendererSceneGIRD::SDFGI::debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture) {
+void RendererSceneGIRD::SDFGI::debug_draw(const CameraMatrix &p_projection, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture) {
if (!debug_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(debug_uniform_set)) {
Vector<RD::Uniform> uniforms;
{
@@ -1367,7 +1367,7 @@ void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_fr
}
}
-void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, RendererSceneRenderRD *p_scene_render) {
+void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render) {
/* Update general SDFGI Buffer */
SDFGIData sdfgi_data;
@@ -1564,7 +1564,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region,
//clear dispatch indirect data
SDFGIShader::PreprocessPushConstant push_constant;
- zeromem(&push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
+ memset(&push_constant, 0, sizeof(SDFGIShader::PreprocessPushConstant));
RENDER_TIMESTAMP("Scroll SDF");
@@ -2012,10 +2012,10 @@ void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32
}
////////////////////////////////////////////////////////////////////////////////
-// GIProbeInstance
+// VoxelGIInstance
-void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
- uint32_t data_version = storage->gi_probe_get_data_version(probe);
+void RendererSceneGIRD::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+ uint32_t data_version = storage->voxel_gi_get_data_version(probe);
// (RE)CREATE IF NEEDED
@@ -2034,11 +2034,11 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
dynamic_maps.clear();
- Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+ Vector3i octree_size = storage->voxel_gi_get_octree_size(probe);
if (octree_size != Vector3i()) {
//can create a 3D texture
- Vector<int> levels = storage->gi_probe_get_level_counts(probe);
+ Vector<int> levels = storage->voxel_gi_get_level_counts(probe);
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
@@ -2064,7 +2064,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
}
for (int i = 0; i < levels.size(); i++) {
- GIProbeInstance::Mipmap mipmap;
+ VoxelGIInstance::Mipmap mipmap;
mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture, 0, i, RD::TEXTURE_SLICE_3D);
mipmap.level = levels.size() - i - 1;
mipmap.cell_offset = 0;
@@ -2078,14 +2078,14 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
- u.ids.push_back(storage->gi_probe_get_octree_buffer(probe));
+ u.ids.push_back(storage->voxel_gi_get_octree_buffer(probe));
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
- u.ids.push_back(storage->gi_probe_get_data_buffer(probe));
+ u.ids.push_back(storage->voxel_gi_get_data_buffer(probe));
uniforms.push_back(u);
}
@@ -2100,7 +2100,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ u.ids.push_back(storage->voxel_gi_get_sdf_texture(probe));
uniforms.push_back(u);
}
{
@@ -2118,11 +2118,11 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 3;
- u.ids.push_back(gi->gi_probe_lights_uniform);
+ u.ids.push_back(gi->voxel_gi_lights_uniform);
copy_uniforms.push_back(u);
}
- mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0);
+ mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT], 0);
copy_uniforms = uniforms; //restore
@@ -2133,9 +2133,9 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
u.ids.push_back(texture);
copy_uniforms.push_back(u);
}
- mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0);
+ mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0);
} else {
- mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0);
+ mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP], 0);
}
}
@@ -2147,7 +2147,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
uniforms.push_back(u);
}
- mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0);
+ mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE], 0);
mipmaps.push_back(mipmap);
}
@@ -2158,7 +2158,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
int mipmap_index = 0;
while (mipmap_index < mipmaps.size()) {
- GIProbeInstance::DynamicMap dmap;
+ VoxelGIInstance::DynamicMap dmap;
if (oversample > 0) {
dmap.size = dynamic_map_size * (1 << oversample);
@@ -2217,7 +2217,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 3;
- u.ids.push_back(gi->gi_probe_lights_uniform);
+ u.ids.push_back(gi->voxel_gi_lights_uniform);
uniforms.push_back(u);
}
@@ -2253,7 +2253,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ u.ids.push_back(storage->voxel_gi_get_sdf_texture(probe));
uniforms.push_back(u);
}
{
@@ -2278,7 +2278,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
uniforms.push_back(u);
}
- dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
+ dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0);
}
} else {
bool plot = dmap.mipmap >= 0;
@@ -2322,7 +2322,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9;
- u.ids.push_back(storage->gi_probe_get_sdf_texture(probe));
+ u.ids.push_back(storage->voxel_gi_get_sdf_texture(probe));
uniforms.push_back(u);
}
{
@@ -2345,7 +2345,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
dmap.uniform_set = RD::get_singleton()->uniform_set_create(
uniforms,
- gi->giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)],
+ gi->voxel_gi_lighting_shader_version_shaders[(write && plot) ? VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)],
0);
}
@@ -2370,15 +2370,15 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
uint32_t light_count = 0;
if (p_update_light_instances || p_dynamic_objects.size() > 0) {
- light_count = MIN(gi->gi_probe_max_lights, (uint32_t)p_light_instances.size());
+ light_count = MIN(gi->voxel_gi_max_lights, (uint32_t)p_light_instances.size());
{
- Transform to_cell = storage->gi_probe_get_to_cell_xform(probe);
- Transform to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse();
+ Transform3D to_cell = storage->voxel_gi_get_to_cell_xform(probe);
+ Transform3D to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse();
//update lights
for (uint32_t i = 0; i < light_count; i++) {
- GIProbeLight &l = gi->gi_probe_lights[i];
+ VoxelGILight &l = gi->voxel_gi_lights[i];
RID light_instance = p_light_instances[i];
RID light = p_scene_render->light_instance_get_base_light(light_instance);
@@ -2399,7 +2399,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
- Transform xform = p_scene_render->light_instance_get_base_transform(light_instance);
+ Transform3D xform = p_scene_render->light_instance_get_base_transform(light_instance);
Vector3 pos = to_probe_xform.xform(xform.origin);
Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized();
@@ -2415,7 +2415,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
l.has_shadow = storage->light_has_shadow(light);
}
- RD::get_singleton()->buffer_update(gi->gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi->gi_probe_lights);
+ RD::get_singleton()->buffer_update(gi->voxel_gi_lights_uniform, 0, sizeof(VoxelGILight) * light_count, gi->voxel_gi_lights);
}
}
@@ -2424,17 +2424,17 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
if (mipmaps.size()) {
//can update mipmaps
- Vector3i probe_size = storage->gi_probe_get_octree_size(probe);
+ Vector3i probe_size = storage->voxel_gi_get_octree_size(probe);
- GIProbePushConstant push_constant;
+ VoxelGIPushConstant push_constant;
push_constant.limits[0] = probe_size.x;
push_constant.limits[1] = probe_size.y;
push_constant.limits[2] = probe_size.z;
push_constant.stack_size = mipmaps.size();
push_constant.emission_scale = 1.0;
- push_constant.propagation = storage->gi_probe_get_propagation(probe);
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.propagation = storage->voxel_gi_get_propagation(probe);
+ push_constant.dynamic_range = storage->voxel_gi_get_dynamic_range(probe);
push_constant.light_count = light_count;
push_constant.aniso_strength = 0;
@@ -2446,7 +2446,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
int passes;
if (p_update_light_instances) {
- passes = storage->gi_probe_is_using_two_bounces(probe) ? 2 : 1;
+ passes = storage->voxel_gi_is_using_two_bounces(probe) ? 2 : 1;
} else {
passes = 1; //only re-blitting is necessary
}
@@ -2457,9 +2457,9 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
if (p_update_light_instances) {
for (int i = 0; i < mipmaps.size(); i++) {
if (i == 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[pass == 0 ? VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT : VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
} else if (i == 1) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP]);
}
if (pass == 1 || i > 0) {
@@ -2477,7 +2477,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1;
while (wg_todo) {
int wg_count = MIN(wg_todo, wg_limit_x);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
wg_todo -= wg_count;
push_constant.cell_offset += wg_count * wg_size;
@@ -2487,7 +2487,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
}
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE]);
for (int i = 0; i < mipmaps.size(); i++) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].write_uniform_set, 0);
@@ -2498,7 +2498,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1;
while (wg_todo) {
int wg_count = MIN(wg_todo, wg_limit_x);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant));
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1);
wg_todo -= wg_count;
push_constant.cell_offset += wg_count * wg_size;
@@ -2513,15 +2513,15 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
has_dynamic_object_data = false; //clear until dynamic object data is used again
if (p_dynamic_objects.size() && dynamic_maps.size()) {
- Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+ Vector3i octree_size = storage->voxel_gi_get_octree_size(probe);
int multiplier = dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z);
- Transform oversample_scale;
+ Transform3D oversample_scale;
oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier));
- Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(probe);
- Transform to_world_xform = transform * to_cell.affine_inverse();
- Transform to_probe_xform = to_world_xform.affine_inverse();
+ Transform3D to_cell = oversample_scale * storage->voxel_gi_get_to_cell_xform(probe);
+ Transform3D to_world_xform = transform * to_cell.affine_inverse();
+ Transform3D to_probe_xform = to_world_xform.affine_inverse();
AABB probe_aabb(Vector3(), octree_size);
@@ -2529,7 +2529,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
for (int i = 0; i < (int)p_dynamic_objects.size(); i++) {
RendererSceneRender::GeometryInstance *instance = p_dynamic_objects[i];
- //transform aabb to giprobe
+ //transform aabb to voxel_gi
AABB aabb = (to_probe_xform * p_scene_render->geometry_instance_get_transform(instance)).xform(p_scene_render->geometry_instance_get_aabb(instance));
//this needs to wrap to grid resolution to avoid jitter
@@ -2576,7 +2576,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
Vector3 up_dir = render_up[j];
Vector3 center = aabb.position + aabb.size * 0.5;
- Transform xform;
+ Transform3D xform;
xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir);
Vector3 x_dir = xform.basis.get_axis(0).abs();
@@ -2601,8 +2601,8 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size));
- GIProbeDynamicPushConstant push_constant;
- zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant));
+ VoxelGIDynamicPushConstant push_constant;
+ memset(&push_constant, 0, sizeof(VoxelGIDynamicPushConstant));
push_constant.limits[0] = octree_size.x;
push_constant.limits[1] = octree_size.y;
push_constant.limits[2] = octree_size.z;
@@ -2619,7 +2619,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
push_constant.z_base = xform.origin[z_axis];
push_constant.z_sign = (z_flip ? -1.0 : 1.0);
push_constant.pos_multiplier = float(1.0) / multiplier;
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.dynamic_range = storage->voxel_gi_get_dynamic_range(probe);
push_constant.flip_x = x_flip;
push_constant.flip_y = y_flip;
push_constant.rect_pos[0] = rect.position[0];
@@ -2631,16 +2631,16 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
push_constant.prev_rect_size[0] = 0;
push_constant.prev_rect_size[1] = 0;
push_constant.on_mipmap = false;
- push_constant.propagation = storage->gi_probe_get_propagation(probe);
+ push_constant.propagation = storage->voxel_gi_get_propagation(probe);
push_constant.pad[0] = 0;
push_constant.pad[1] = 0;
push_constant.pad[2] = 0;
//process lighting
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[0].uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIDynamicPushConstant));
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);
@@ -2695,14 +2695,14 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
RD::get_singleton()->compute_list_add_barrier(compute_list);
if (dynamic_maps[k].mipmap < 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
} else if (k < dynamic_maps.size() - 1) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
} else {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
}
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[k].uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant));
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIDynamicPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1);
}
@@ -2713,22 +2713,22 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c
has_dynamic_object_data = true; //clear until dynamic object data is used again
}
- last_probe_version = storage->gi_probe_get_version(probe);
+ last_probe_version = storage->voxel_gi_get_version(probe);
}
-void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
+void RendererSceneGIRD::VoxelGIInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
if (mipmaps.size() == 0) {
return;
}
- CameraMatrix cam_transform = (p_camera_with_transform * CameraMatrix(transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(probe).affine_inverse());
+ CameraMatrix cam_transform = (p_camera_with_transform * CameraMatrix(transform)) * CameraMatrix(storage->voxel_gi_get_to_cell_xform(probe).affine_inverse());
int level = 0;
- Vector3i octree_size = storage->gi_probe_get_octree_size(probe);
+ Vector3i octree_size = storage->voxel_gi_get_octree_size(probe);
- GIProbeDebugPushConstant push_constant;
+ VoxelGIDebugPushConstant push_constant;
push_constant.alpha = p_alpha;
- push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe);
+ push_constant.dynamic_range = storage->voxel_gi_get_dynamic_range(probe);
push_constant.cell_offset = mipmaps[level].cell_offset;
push_constant.level = level;
@@ -2743,15 +2743,15 @@ void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p
}
}
- if (gi->giprobe_debug_uniform_set.is_valid()) {
- RD::get_singleton()->free(gi->giprobe_debug_uniform_set);
+ if (gi->voxel_gi_debug_uniform_set.is_valid()) {
+ RD::get_singleton()->free(gi->voxel_gi_debug_uniform_set);
}
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
- u.ids.push_back(storage->gi_probe_get_data_buffer(probe));
+ u.ids.push_back(storage->voxel_gi_get_data_buffer(probe));
uniforms.push_back(u);
}
{
@@ -2776,19 +2776,19 @@ void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p
cell_count = mipmaps[level].cell_count;
}
- gi->giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_debug_shader_version_shaders[0], 0);
+ gi->voxel_gi_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->voxel_gi_debug_shader_version_shaders[0], 0);
- int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR;
+ int voxel_gi_debug_pipeline = VOXEL_GI_DEBUG_COLOR;
if (p_emission) {
- giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION;
+ voxel_gi_debug_pipeline = VOXEL_GI_DEBUG_EMISSION;
} else if (p_lighting) {
- giprobe_debug_pipeline = has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT;
+ voxel_gi_debug_pipeline = has_dynamic_object_data ? VOXEL_GI_DEBUG_LIGHT_FULL : VOXEL_GI_DEBUG_LIGHT;
}
RD::get_singleton()->draw_list_bind_render_pipeline(
p_draw_list,
- gi->giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, gi->giprobe_debug_uniform_set, 0);
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant));
+ gi->voxel_gi_debug_shader_version_pipelines[voxel_gi_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, gi->voxel_gi_debug_uniform_set, 0);
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(VoxelGIDebugPushConstant));
RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36);
}
@@ -2812,13 +2812,13 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
{
//kinda complicated to compute the amount of slots, we try to use as many as we can
- gi_probe_max_lights = 32;
+ voxel_gi_max_lights = 32;
- gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights);
- gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight));
- gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")), 0, 1));
+ voxel_gi_lights = memnew_arr(VoxelGILight, voxel_gi_max_lights);
+ voxel_gi_lights_uniform = RD::get_singleton()->uniform_buffer_create(voxel_gi_max_lights * sizeof(VoxelGILight));
+ voxel_gi_quality = RS::VoxelGIQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/voxel_gi/quality")), 0, 1));
- String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n";
+ String defines = "\n#define MAX_LIGHTS " + itos(voxel_gi_max_lights) + "\n";
Vector<String> versions;
versions.push_back("\n#define MODE_COMPUTE_LIGHT\n");
@@ -2830,11 +2830,11 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
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]);
+ voxel_gi_shader.initialize(versions, defines);
+ voxel_gi_lighting_shader_version = voxel_gi_shader.version_create();
+ for (int i = 0; i < VOXEL_GI_SHADER_VERSION_MAX; i++) {
+ voxel_gi_lighting_shader_version_shaders[i] = voxel_gi_shader.version_get_shader(voxel_gi_lighting_shader_version, i);
+ voxel_gi_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(voxel_gi_lighting_shader_version_shaders[i]);
}
}
@@ -2846,10 +2846,10 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
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);
+ voxel_gi_debug_shader.initialize(versions, defines);
+ voxel_gi_debug_shader_version = voxel_gi_debug_shader.version_create();
+ for (int i = 0; i < VOXEL_GI_DEBUG_MAX; i++) {
+ voxel_gi_debug_shader_version_shaders[i] = voxel_gi_debug_shader.version_get_shader(voxel_gi_debug_shader_version, i);
RD::PipelineRasterizationState rs;
rs.cull_mode = RD::POLYGON_CULL_FRONT;
@@ -2858,7 +2858,7 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
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);
+ voxel_gi_debug_shader_version_pipelines[i].setup(voxel_gi_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
}
}
@@ -2944,12 +2944,12 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
//calculate tables
String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
Vector<String> gi_modes;
- gi_modes.push_back("\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define USE_VOXEL_GI_INSTANCES\n");
gi_modes.push_back("\n#define USE_SDFGI\n");
- gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
- gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n");
+ gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_VOXEL_GI_INSTANCES\n");
gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n");
- gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n");
+ gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n");
shader.initialize(gi_modes, defines);
shader_version = shader.version_create();
@@ -2991,17 +2991,17 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
}
}
}
- default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * MAX_GIPROBES);
+ default_voxel_gi_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(VoxelGIData) * MAX_VOXEL_GI_INSTANCES);
half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution");
}
void RendererSceneGIRD::free() {
- RD::get_singleton()->free(default_giprobe_buffer);
- RD::get_singleton()->free(gi_probe_lights_uniform);
+ RD::get_singleton()->free(default_voxel_gi_buffer);
+ RD::get_singleton()->free(voxel_gi_lights_uniform);
RD::get_singleton()->free(sdfgi_ubo);
- giprobe_debug_shader.version_free(giprobe_debug_shader_version);
- giprobe_shader.version_free(giprobe_lighting_shader_version);
+ voxel_gi_debug_shader.version_free(voxel_gi_debug_shader_version);
+ voxel_gi_shader.version_free(voxel_gi_lighting_shader_version);
shader.version_free(shader_version);
sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader);
sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader);
@@ -3009,7 +3009,7 @@ void RendererSceneGIRD::free() {
sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);
sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader);
- memdelete_arr(gi_probe_lights);
+ memdelete_arr(voxel_gi_lights);
}
RendererSceneGIRD::SDFGI *RendererSceneGIRD::create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size) {
@@ -3020,36 +3020,36 @@ RendererSceneGIRD::SDFGI *RendererSceneGIRD::create_sdfgi(RendererSceneEnvironme
return sdfgi;
}
-void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render) {
- r_gi_probes_used = 0;
+void RendererSceneGIRD::setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render) {
+ r_voxel_gi_instances_used = 0;
// feels a little dirty to use our container this way but....
RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(rb == nullptr);
- RID gi_probe_buffer = p_scene_render->render_buffers_get_gi_probe_buffer(p_render_buffers);
+ RID voxel_gi_buffer = p_scene_render->render_buffers_get_voxel_gi_buffer(p_render_buffers);
- RD::get_singleton()->draw_command_begin_label("GIProbes Setup");
+ RD::get_singleton()->draw_command_begin_label("VoxelGIs Setup");
- GIProbeData gi_probe_data[MAX_GIPROBES];
+ VoxelGIData voxel_gi_data[MAX_VOXEL_GI_INSTANCES];
- bool giprobes_changed = false;
+ bool voxel_gi_instances_changed = false;
- Transform to_camera;
+ Transform3D to_camera;
to_camera.origin = p_transform.origin; //only translation, make local
- for (int i = 0; i < MAX_GIPROBES; i++) {
+ for (int i = 0; i < MAX_VOXEL_GI_INSTANCES; i++) {
RID texture;
- if (i < (int)p_gi_probes.size()) {
- GIProbeInstance *gipi = get_probe_instance(p_gi_probes[i]);
+ if (i < (int)p_voxel_gi_instances.size()) {
+ VoxelGIInstance *gipi = get_probe_instance(p_voxel_gi_instances[i]);
if (gipi) {
texture = gipi->texture;
- GIProbeData &gipd = gi_probe_data[i];
+ VoxelGIData &gipd = voxel_gi_data[i];
RID base_probe = gipi->probe;
- Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
+ Transform3D to_cell = storage->voxel_gi_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera;
gipd.xform[0] = to_cell.basis.elements[0][0];
gipd.xform[1] = to_cell.basis.elements[1][0];
@@ -3068,36 +3068,36 @@ void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_
gipd.xform[14] = to_cell.origin.z;
gipd.xform[15] = 1;
- Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
+ Vector3 bounds = storage->voxel_gi_get_octree_size(base_probe);
gipd.bounds[0] = bounds.x;
gipd.bounds[1] = bounds.y;
gipd.bounds[2] = bounds.z;
- gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
- gipd.bias = storage->gi_probe_get_bias(base_probe);
- gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
- gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe);
+ gipd.dynamic_range = storage->voxel_gi_get_dynamic_range(base_probe) * storage->voxel_gi_get_energy(base_probe);
+ gipd.bias = storage->voxel_gi_get_bias(base_probe);
+ gipd.normal_bias = storage->voxel_gi_get_normal_bias(base_probe);
+ gipd.blend_ambient = !storage->voxel_gi_is_interior(base_probe);
gipd.anisotropy_strength = 0;
- gipd.ao = storage->gi_probe_get_ao(base_probe);
- gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
+ gipd.ao = storage->voxel_gi_get_ao(base_probe);
+ gipd.ao_size = Math::pow(storage->voxel_gi_get_ao_size(base_probe), 4.0f);
gipd.mipmaps = gipi->mipmaps.size();
}
- r_gi_probes_used++;
+ r_voxel_gi_instances_used++;
}
if (texture == RID()) {
texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
}
- if (texture != rb->gi.giprobe_textures[i]) {
- giprobes_changed = true;
- rb->gi.giprobe_textures[i] = texture;
+ if (texture != rb->gi.voxel_gi_textures[i]) {
+ voxel_gi_instances_changed = true;
+ rb->gi.voxel_gi_textures[i] = texture;
}
}
- if (giprobes_changed) {
+ if (voxel_gi_instances_changed) {
if (RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) {
RD::get_singleton()->free(rb->gi.uniform_set);
}
@@ -3112,14 +3112,14 @@ void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_
}
}
- if (p_gi_probes.size() > 0) {
- RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GIProbeData) * MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, RD::BARRIER_MASK_COMPUTE);
+ if (p_voxel_gi_instances.size() > 0) {
+ RD::get_singleton()->buffer_update(voxel_gi_buffer, 0, sizeof(VoxelGIData) * MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()), voxel_gi_data, RD::BARRIER_MASK_COMPUTE);
}
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render) {
+void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render) {
RD::get_singleton()->draw_command_begin_label("GI Render");
RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers);
@@ -3144,8 +3144,6 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
rb->reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
rb->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
rb->gi.using_half_size_gi = half_resolution;
-
- p_scene_render->_render_buffers_uniform_set_changed(p_render_buffers);
}
PushConstant push_constant;
@@ -3159,11 +3157,11 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]);
push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
- push_constant.max_giprobes = MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size());
- push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH;
+ push_constant.max_voxel_gi_instances = MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size());
+ push_constant.high_quality_vct = voxel_gi_quality == RS::VOXEL_GI_QUALITY_HIGH;
bool use_sdfgi = rb->sdfgi != nullptr;
- bool use_giprobes = push_constant.max_giprobes > 0;
+ bool use_voxel_gi_instances = push_constant.max_voxel_gi_instances > 0;
if (env) {
push_constant.ao_color[0] = env->ao_color.r;
@@ -3313,7 +3311,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 14;
- RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ RID buffer = p_voxel_gi_buffer.is_valid() ? p_voxel_gi_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK);
u.ids.push_back(buffer);
uniforms.push_back(u);
}
@@ -3328,15 +3326,15 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 16;
- u.ids.push_back(rb->gi.giprobe_buffer);
+ u.ids.push_back(rb->gi.voxel_gi_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 17;
- for (int i = 0; i < MAX_GIPROBES; i++) {
- u.ids.push_back(rb->gi.giprobe_textures[i]);
+ for (int i = 0; i < MAX_VOXEL_GI_INSTANCES; i++) {
+ u.ids.push_back(rb->gi.voxel_gi_textures[i]);
}
uniforms.push_back(u);
}
@@ -3347,9 +3345,9 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
Mode mode;
if (rb->gi.using_half_size_gi) {
- mode = (use_sdfgi && use_giprobes) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_GIPROBE);
+ mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_VOXEL_GI);
} else {
- mode = (use_sdfgi && use_giprobes) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_GIPROBE);
+ mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_VOXEL_GI);
}
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[mode]);
@@ -3366,39 +3364,39 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
RD::get_singleton()->draw_command_end_label();
}
-RID RendererSceneGIRD::gi_probe_instance_create(RID p_base) {
- GIProbeInstance gi_probe;
- gi_probe.gi = this;
- gi_probe.storage = storage;
- gi_probe.probe = p_base;
- RID rid = gi_probe_instance_owner.make_rid(gi_probe);
+RID RendererSceneGIRD::voxel_gi_instance_create(RID p_base) {
+ VoxelGIInstance voxel_gi;
+ voxel_gi.gi = this;
+ voxel_gi.storage = storage;
+ voxel_gi.probe = p_base;
+ RID rid = voxel_gi_instance_owner.make_rid(voxel_gi);
return rid;
}
-void RendererSceneGIRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
- GIProbeInstance *gi_probe = get_probe_instance(p_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererSceneGIRD::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) {
+ VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->transform = p_xform;
+ voxel_gi->transform = p_xform;
}
-bool RendererSceneGIRD::gi_probe_needs_update(RID p_probe) const {
- GIProbeInstance *gi_probe = get_probe_instance(p_probe);
- ERR_FAIL_COND_V(!gi_probe, false);
+bool RendererSceneGIRD::voxel_gi_needs_update(RID p_probe) const {
+ VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ ERR_FAIL_COND_V(!voxel_gi, false);
- return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
+ return voxel_gi->last_probe_version != storage->voxel_gi_get_version(voxel_gi->probe);
}
-void RendererSceneGIRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
- GIProbeInstance *gi_probe = get_probe_instance(p_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererSceneGIRD::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+ VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render);
+ voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render);
}
-void RendererSceneGIRD::debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererSceneGIRD::debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
+ VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha);
+ voxel_gi->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha);
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
index df20011b23..45fc7b3951 100644
--- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
@@ -38,26 +38,27 @@
#include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
#include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/voxel_gi.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
-// Forward declare RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound
+// Forward declare RenderDataRD and RendererSceneRenderRD so we can pass it into some of our methods, these classes are pretty tightly bound
+struct RenderDataRD;
class RendererSceneRenderRD;
class RendererSceneGIRD {
private:
RendererStorageRD *storage;
- /* GIPROBE INSTANCE */
+ /* VOXEL_GI INSTANCE */
- struct GIProbeLight {
+ struct VoxelGILight {
uint32_t type;
float energy;
float radius;
@@ -73,7 +74,7 @@ private:
uint32_t has_shadow;
};
- struct GIProbePushConstant {
+ struct VoxelGIPushConstant {
int32_t limits[3];
uint32_t stack_size;
@@ -88,7 +89,7 @@ private:
uint32_t pad;
};
- struct GIProbeDynamicPushConstant {
+ struct VoxelGIDynamicPushConstant {
int32_t limits[3];
uint32_t light_count;
int32_t x_dir[3];
@@ -109,36 +110,36 @@ private:
float pad[3];
};
- GIProbeLight *gi_probe_lights;
- uint32_t gi_probe_max_lights;
- RID gi_probe_lights_uniform;
+ VoxelGILight *voxel_gi_lights;
+ uint32_t voxel_gi_max_lights;
+ RID voxel_gi_lights_uniform;
enum {
- GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT,
- GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
- GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP,
- GI_PROBE_SHADER_VERSION_WRITE_TEXTURE,
- GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
- GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
- GI_PROBE_SHADER_VERSION_MAX
+ VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT,
+ VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE,
+ VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP,
+ VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE,
+ VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING,
+ VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE,
+ VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT,
+ VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT,
+ VOXEL_GI_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];
+ VoxelGiShaderRD voxel_gi_shader;
+ RID voxel_gi_lighting_shader_version;
+ RID voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_MAX];
+ RID voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_MAX];
enum {
- GI_PROBE_DEBUG_COLOR,
- GI_PROBE_DEBUG_LIGHT,
- GI_PROBE_DEBUG_EMISSION,
- GI_PROBE_DEBUG_LIGHT_FULL,
- GI_PROBE_DEBUG_MAX
+ VOXEL_GI_DEBUG_COLOR,
+ VOXEL_GI_DEBUG_LIGHT,
+ VOXEL_GI_DEBUG_EMISSION,
+ VOXEL_GI_DEBUG_LIGHT_FULL,
+ VOXEL_GI_DEBUG_MAX
};
- struct GIProbeDebugPushConstant {
+ struct VoxelGIDebugPushConstant {
float projection[16];
uint32_t cell_offset;
float dynamic_range;
@@ -148,11 +149,11 @@ private:
uint32_t pad;
};
- GiprobeDebugShaderRD giprobe_debug_shader;
- RID giprobe_debug_shader_version;
- RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX];
- PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX];
- RID giprobe_debug_uniform_set;
+ VoxelGiDebugShaderRD voxel_gi_debug_shader;
+ RID voxel_gi_debug_shader_version;
+ RID voxel_gi_debug_shader_version_shaders[VOXEL_GI_DEBUG_MAX];
+ PipelineCacheRD voxel_gi_debug_shader_version_pipelines[VOXEL_GI_DEBUG_MAX];
+ RID voxel_gi_debug_uniform_set;
/* SDFGI */
@@ -325,11 +326,11 @@ private:
} sdfgi_shader;
public:
- /* GIPROBE INSTANCE */
+ /* VOXEL_GI INSTANCE */
- //@TODO GIProbeInstance is still directly used in the render code, we'll address this when we refactor the render code itself.
+ //@TODO VoxelGIInstance is still directly used in the render code, we'll address this when we refactor the render code itself.
- struct GIProbeInstance {
+ struct VoxelGIInstance {
// access to our containers
RendererStorageRD *storage;
RendererSceneGIRD *gi;
@@ -373,25 +374,25 @@ public:
bool has_dynamic_object_data = false;
- Transform transform;
+ Transform3D transform;
void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
};
- mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner;
+ mutable RID_Owner<VoxelGIInstance> voxel_gi_instance_owner;
- _FORCE_INLINE_ GIProbeInstance *get_probe_instance(RID p_probe) const {
- return gi_probe_instance_owner.getornull(p_probe);
+ _FORCE_INLINE_ VoxelGIInstance *get_probe_instance(RID p_probe) const {
+ return voxel_gi_instance_owner.getornull(p_probe);
};
- _FORCE_INLINE_ RID gi_probe_instance_get_texture(RID p_probe) {
- GIProbeInstance *gi_probe = get_probe_instance(p_probe);
- ERR_FAIL_COND_V(!gi_probe, RID());
- return gi_probe->texture;
+ _FORCE_INLINE_ RID voxel_gi_instance_get_texture(RID p_probe) {
+ VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
+ ERR_FAIL_COND_V(!voxel_gi, RID());
+ return voxel_gi->texture;
};
- RS::GIProbeQuality gi_probe_quality = RS::GI_PROBE_QUALITY_HIGH;
+ RS::VoxelGIQuality voxel_gi_quality = RS::VOXEL_GI_QUALITY_HIGH;
/* SDFGI */
@@ -526,10 +527,10 @@ public:
int get_pending_region_data(int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const;
void update_cascades();
- void debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture);
+ void debug_draw(const CameraMatrix &p_projection, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture);
void debug_probes(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform);
- void pre_process_gi(const Transform &p_transform, RendererSceneRenderRD *p_scene_render);
+ void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render);
void render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render);
void render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render);
};
@@ -550,13 +551,13 @@ public:
/* GI */
enum {
- MAX_GIPROBES = 8
+ MAX_VOXEL_GI_INSTANCES = 8
};
// Struct for use in render buffer
struct RenderBuffersGI {
- RID giprobe_textures[MAX_GIPROBES];
- RID giprobe_buffer;
+ RID voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
+ RID voxel_gi_buffer;
RID full_buffer;
RID full_dispatch;
@@ -600,7 +601,7 @@ public:
ProbeCascadeData cascades[SDFGI::MAX_CASCADES];
};
- struct GIProbeData {
+ struct VoxelGIData {
float xform[16];
float bounds[3];
float dynamic_range;
@@ -623,7 +624,7 @@ public:
float proj_info[4];
float ao_color[3];
- uint32_t max_giprobes;
+ uint32_t max_voxel_gi_instances;
uint32_t high_quality_vct;
uint32_t orthogonal;
@@ -634,16 +635,16 @@ public:
RID sdfgi_ubo;
enum Mode {
- MODE_GIPROBE,
+ MODE_VOXEL_GI,
MODE_SDFGI,
MODE_COMBINED,
- MODE_HALF_RES_GIPROBE,
+ MODE_HALF_RES_VOXEL_GI,
MODE_HALF_RES_SDFGI,
MODE_HALF_RES_COMBINED,
MODE_MAX
};
- RID default_giprobe_buffer;
+ RID default_voxel_gi_buffer;
bool half_resolution = false;
GiShaderRD shader;
@@ -658,14 +659,14 @@ public:
SDFGI *create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size);
- void setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render);
- void process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render);
+ void setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render);
+ void process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render);
- RID gi_probe_instance_create(RID p_base);
- void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
- bool gi_probe_needs_update(RID p_probe) const;
- void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
- void debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
+ RID voxel_gi_instance_create(RID p_base);
+ void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform);
+ bool voxel_gi_needs_update(RID p_probe) const;
+ void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
+ void debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
};
#endif /* !RENDERING_SERVER_SCENE_GI_RD_H */
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index a98f67f163..be98fb42c0 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -58,8 +58,6 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment
rb->sdfgi->erase();
memdelete(rb->sdfgi);
rb->sdfgi = nullptr;
-
- _render_buffers_uniform_set_changed(p_render_buffers);
}
return;
}
@@ -78,8 +76,6 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment
if (sdfgi == nullptr) {
// re-create
rb->sdfgi = gi.create_sdfgi(env, p_world_position, requested_history_size);
-
- _render_buffers_uniform_set_changed(p_render_buffers);
} else {
//check for updates
rb->sdfgi->update(env, p_world_position);
@@ -574,7 +570,7 @@ RID RendererSceneRenderRD::reflection_probe_instance_create(RID p_probe) {
return reflection_probe_instance_owner.make_rid(rpi);
}
-void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) {
+void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
ERR_FAIL_COND(!rpi);
@@ -1237,7 +1233,7 @@ RID RendererSceneRenderRD::light_instance_create(RID p_light) {
return li;
}
-void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) {
+void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
ERR_FAIL_COND(!light_instance);
@@ -1251,7 +1247,7 @@ void RendererSceneRenderRD::light_instance_set_aabb(RID p_light_instance, const
light_instance->aabb = p_aabb;
}
-void RendererSceneRenderRD::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) {
+void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &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);
@@ -1309,7 +1305,7 @@ RID RendererSceneRenderRD::decal_instance_create(RID p_decal) {
return decal_instance_owner.make_rid(di);
}
-void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform &p_transform) {
+void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) {
DecalInstance *di = decal_instance_owner.getornull(p_decal);
ERR_FAIL_COND(!di);
di->transform = p_transform;
@@ -1322,7 +1318,7 @@ RID RendererSceneRenderRD::lightmap_instance_create(RID p_lightmap) {
li.lightmap = p_lightmap;
return lightmap_instance_owner.make_rid(li);
}
-void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) {
+void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap);
ERR_FAIL_COND(!li);
li->transform = p_transform;
@@ -1330,28 +1326,28 @@ void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, cons
/////////////////////////////////
-RID RendererSceneRenderRD::gi_probe_instance_create(RID p_base) {
- return gi.gi_probe_instance_create(p_base);
+RID RendererSceneRenderRD::voxel_gi_instance_create(RID p_base) {
+ return gi.voxel_gi_instance_create(p_base);
}
-void RendererSceneRenderRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
- gi.gi_probe_instance_set_transform_to_data(p_probe, p_xform);
+void RendererSceneRenderRD::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) {
+ gi.voxel_gi_instance_set_transform_to_data(p_probe, p_xform);
}
-bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const {
+bool RendererSceneRenderRD::voxel_gi_needs_update(RID p_probe) const {
if (!is_dynamic_gi_supported()) {
return false;
}
- return gi.gi_probe_needs_update(p_probe);
+ return gi.voxel_gi_needs_update(p_probe);
}
-void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) {
+void RendererSceneRenderRD::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) {
if (!is_dynamic_gi_supported()) {
return;
}
- gi.gi_probe_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this);
+ gi.voxel_gi_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this);
}
void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) {
@@ -1533,7 +1529,6 @@ void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatri
if (rb->blur[0].texture.is_null()) {
_allocate_blur_textures(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
}
storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality);
@@ -1585,7 +1580,6 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
if (rb->blur[0].texture.is_null()) {
_allocate_blur_textures(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
}
storage->get_effects()->screen_space_reflection(rb->texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->width / 2, rb->height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection);
@@ -1711,7 +1705,6 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
rb->ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->ssao.ao_final, "SSAO Final");
- _render_buffers_uniform_set_changed(p_render_buffers);
}
ssao_using_half_size = ssao_half_size;
uniform_sets_are_invalid = true;
@@ -1735,33 +1728,31 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
settings.half_screen_size = Size2i(buffer_width, buffer_height);
settings.quarter_screen_size = Size2i(half_width, half_height);
- storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid);
+ storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid, rb->ssao.downsample_uniform_set, rb->ssao.gather_uniform_set, rb->ssao.importance_map_uniform_set);
}
-void RendererSceneRenderRD::_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);
+void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data) {
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
ERR_FAIL_COND(!rb);
- RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment);
//glow (if enabled)
- CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
+ CameraEffects *camfx = camera_effects_owner.getornull(p_render_data->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());
+ 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_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal);
}
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;
@@ -1782,7 +1773,6 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende
if (rb->blur[1].texture.is_null()) {
_allocate_blur_textures(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
}
for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) {
@@ -1867,13 +1857,15 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(RID p_rende
}
}
+ tonemap.view_count = p_render_data->view_count;
+
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 RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas) {
+void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
EffectsRD *effects = storage->get_effects();
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
@@ -1932,6 +1924,13 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID
RID reflection_texture = rb->reflection_buffer;
effects->copy_to_fb_rect(ambient_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture);
}
+
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS) {
+ if (p_occlusion_buffer.is_valid()) {
+ Size2 rtsize = storage->render_target_get_size(rb->render_target);
+ effects->copy_to_fb_rect(storage->texture_get_rd_texture(p_occlusion_buffer), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize), true, false);
+ }
+ }
}
void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) {
@@ -1962,17 +1961,17 @@ RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) {
return rb->ssao.ao_final;
}
-RID RendererSceneRenderRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) {
+RID RendererSceneRenderRD::render_buffers_get_voxel_gi_buffer(RID p_render_buffers) {
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND_V(!rb, RID());
- if (rb->gi.giprobe_buffer.is_null()) {
- rb->gi.giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererSceneGIRD::GIProbeData) * RendererSceneGIRD::MAX_GIPROBES);
+ if (rb->gi.voxel_gi_buffer.is_null()) {
+ rb->gi.voxel_gi_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererSceneGIRD::VoxelGIData) * RendererSceneGIRD::MAX_VOXEL_GI_INSTANCES);
}
- return rb->gi.giprobe_buffer;
+ return rb->gi.voxel_gi_buffer;
}
-RID RendererSceneRenderRD::render_buffers_get_default_gi_probe_buffer() {
- return gi.default_giprobe_buffer;
+RID RendererSceneRenderRD::render_buffers_get_default_voxel_gi_buffer() {
+ return gi.default_voxel_gi_buffer;
}
RID RendererSceneRenderRD::render_buffers_get_gi_ambient_texture(RID p_render_buffers) {
@@ -2115,7 +2114,9 @@ float RendererSceneRenderRD::render_buffers_get_volumetric_fog_detail_spread(RID
return rb->volumetric_fog->spread;
}
-void RendererSceneRenderRD::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, bool p_use_debanding) {
+void RendererSceneRenderRD::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, bool p_use_debanding, uint32_t p_view_count) {
+ ERR_FAIL_COND_MSG(p_view_count == 0, "Must have atleast 1 view");
+
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
rb->width = p_width;
rb->height = p_height;
@@ -2123,6 +2124,7 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
rb->msaa = p_msaa;
rb->screen_space_aa = p_screen_space_aa;
rb->use_debanding = p_use_debanding;
+ rb->view_count = p_view_count;
if (is_clustered_enabled()) {
if (rb->cluster_builder == nullptr) {
@@ -2135,9 +2137,13 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
{
RD::TextureFormat tf;
+ if (rb->view_count > 1) {
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ }
tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
tf.width = rb->width;
tf.height = rb->height;
+ tf.array_layers = rb->view_count; // create a layer for every view
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 | RD::TEXTURE_USAGE_STORAGE_BIT;
@@ -2150,6 +2156,9 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
{
RD::TextureFormat tf;
+ if (rb->view_count > 1) {
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ }
if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) {
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;
} else {
@@ -2159,6 +2168,7 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
tf.width = p_width;
tf.height = p_height;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
+ tf.array_layers = rb->view_count; // create a layer for every view
if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
@@ -2169,8 +2179,7 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
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);
+ rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa, p_view_count);
if (is_clustered_enabled()) {
rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
@@ -2288,7 +2297,7 @@ RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_g
return rb->data;
}
-void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment) {
+void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment) {
cluster.reflection_count = 0;
for (uint32_t i = 0; i < (uint32_t)p_reflections.size(); i++) {
@@ -2322,6 +2331,8 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
Vector3 extents = storage->reflection_probe_get_extents(base_probe);
+ rpi->cull_mask = storage->reflection_probe_get_cull_mask(base_probe);
+
reflection_ubo.box_extents[0] = extents.x;
reflection_ubo.box_extents[1] = extents.y;
reflection_ubo.box_extents[2] = extents.z;
@@ -2346,11 +2357,13 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy;
reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy;
- Transform transform = rpi->transform;
- Transform proj = (p_camera_inverse_transform * transform).inverse();
+ Transform3D transform = rpi->transform;
+ Transform3D proj = (p_camera_inverse_transform * transform).inverse();
RendererStorageRD::store_transform(proj, reflection_ubo.local_matrix);
- current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, transform, extents);
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, transform, extents);
+ }
rpi->last_pass = RSG::rasterizer->get_frame_number();
}
@@ -2360,8 +2373,8 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
}
}
-void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) {
- Transform inverse_transform = p_camera_transform.affine_inverse();
+void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) {
+ Transform3D inverse_transform = p_camera_transform.affine_inverse();
r_directional_light_count = 0;
r_positional_light_count = 0;
@@ -2387,7 +2400,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
// Copy to SkyDirectionalLightData
if (r_directional_light_count < sky.sky_scene_state.max_directional_lights) {
RendererSceneSkyRD::SkyDirectionalLightData &sky_light_data = sky.sky_scene_state.directional_lights[r_directional_light_count];
- Transform light_transform = li->transform;
+ Transform3D light_transform = li->transform;
Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
sky_light_data.direction[0] = world_direction.x;
@@ -2423,7 +2436,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
Cluster::DirectionalLightData &light_data = cluster.directional_lights[r_directional_light_count];
- Transform light_transform = li->transform;
+ Transform3D light_transform = li->transform;
Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
@@ -2513,7 +2526,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
CameraMatrix rectm;
rectm.set_light_atlas_rect(atlas_rect);
- Transform modelview = (inverse_transform * li->shadow_transform[j].transform).inverse();
+ Transform3D modelview = (inverse_transform * li->shadow_transform[j].transform).inverse();
CameraMatrix shadow_mtx = rectm * bias * matrix * modelview;
light_data.shadow_split_offsets[j] = split;
@@ -2554,6 +2567,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
light_data.softshadow_angle = angular_diameter;
+ light_data.bake_mode = storage->light_get_bake_mode(base);
if (angular_diameter <= 0.0) {
light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF
@@ -2608,7 +2622,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
LightInstance *li = (i < cluster.omni_light_count) ? cluster.omni_light_sort[index].instance : cluster.spot_light_sort[index].instance;
RID base = li->light;
- Transform light_transform = li->transform;
+ Transform3D light_transform = li->transform;
float sign = storage->light_is_negative(base) ? -1 : 1;
Color linear_col = storage->light_get_color(base).to_linear();
@@ -2621,6 +2635,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.color[1] = linear_col.g * energy;
light_data.color[2] = linear_col.b * energy;
light_data.specular_amount = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0;
+ light_data.bake_mode = storage->light_get_bake_mode(base);
float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
light_data.inv_radius = 1.0 / radius;
@@ -2707,7 +2722,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
if (type == RS::LIGHT_OMNI) {
light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another
- Transform proj = (inverse_transform * light_transform).inverse();
+ Transform3D proj = (inverse_transform * light_transform).inverse();
RendererStorageRD::store_transform(proj, light_data.shadow_matrix);
@@ -2719,7 +2734,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
}
} else if (type == RS::LIGHT_SPOT) {
- Transform modelview = (inverse_transform * light_transform).inverse();
+ Transform3D modelview = (inverse_transform * light_transform).inverse();
CameraMatrix bias;
bias.set_light_bias();
@@ -2740,8 +2755,11 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
}
li->light_index = index;
+ li->cull_mask = storage->light_get_cull_mask(base);
- current_cluster_builder->add_light(type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_light(type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);
+ }
r_positional_light_count++;
}
@@ -2760,8 +2778,8 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
}
}
-void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform) {
- Transform uv_xform;
+void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) {
+ Transform3D uv_xform;
uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0));
uv_xform.origin = Vector3(-1.0, 0.0, -1.0);
@@ -2780,7 +2798,7 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
}
RID decal = di->decal;
- Transform xform = di->transform;
+ Transform3D xform = di->transform;
real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
@@ -2809,7 +2827,10 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
DecalInstance *di = cluster.decal_sort[i].instance;
RID decal = di->decal;
- Transform xform = di->transform;
+ di->render_index = i;
+ di->cull_mask = storage->decal_get_cull_mask(decal);
+
+ Transform3D xform = di->transform;
float fade = 1.0;
if (storage->decal_is_distance_fade_enabled(decal)) {
@@ -2826,9 +2847,9 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
Vector3 decal_extents = storage->decal_get_extents(decal);
- Transform scale_xform;
+ Transform3D scale_xform;
scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z));
- Transform to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse();
+ Transform3D to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse();
RendererStorageRD::store_transform(to_decal_xform, dd.xform);
Vector3 normal = xform.basis.get_axis(Vector3::AXIS_Y).normalized();
@@ -2913,7 +2934,9 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
dd.upper_fade = storage->decal_get_upper_fade(decal);
dd.lower_fade = storage->decal_get_lower_fade(decal);
- current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, xform, decal_extents);
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, xform, decal_extents);
+ }
}
if (cluster.decal_count > 0) {
@@ -2921,6 +2944,116 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const
}
}
+void RendererSceneRenderRD::_fill_instance_indices(const RID *p_omni_light_instances, uint32_t p_omni_light_instance_count, uint32_t *p_omni_light_indices, const RID *p_spot_light_instances, uint32_t p_spot_light_instance_count, uint32_t *p_spot_light_indices, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count, uint32_t *p_reflection_probe_indices, const RID *p_decal_instances, uint32_t p_decal_instance_count, uint32_t *p_decal_instance_indices, uint32_t p_layer_mask, uint32_t p_max_dst_words) {
+ // first zero out our indices
+ for (uint32_t i = 0; i < p_max_dst_words; i++) {
+ p_omni_light_indices[i] = 0;
+ p_spot_light_indices[i] = 0;
+ p_reflection_probe_indices[i] = 0;
+ p_decal_instance_indices[i] = 0;
+ }
+
+ {
+ // process omni lights
+ uint32_t dword = 0;
+ uint32_t shift = 0;
+
+ for (uint32_t i = 0; i < p_omni_light_instance_count && dword < p_max_dst_words; i++) {
+ LightInstance *li = light_instance_owner.getornull(p_omni_light_instances[i]);
+
+ if ((li->cull_mask & p_layer_mask) && (li->light_index < 255)) {
+ p_omni_light_indices[dword] += li->light_index << shift;
+ if (shift == 24) {
+ dword++;
+ shift = 0;
+ } else {
+ shift += 8;
+ }
+ }
+ }
+
+ if (dword < 2) {
+ // put in ending mark
+ p_omni_light_indices[dword] += 0xFF << shift;
+ }
+ }
+
+ {
+ // process spot lights
+ uint32_t dword = 0;
+ uint32_t shift = 0;
+
+ for (uint32_t i = 0; i < p_spot_light_instance_count && dword < p_max_dst_words; i++) {
+ LightInstance *li = light_instance_owner.getornull(p_spot_light_instances[i]);
+
+ if ((li->cull_mask & p_layer_mask) && (li->light_index < 255)) {
+ p_spot_light_indices[dword] += li->light_index << shift;
+ if (shift == 24) {
+ dword++;
+ shift = 0;
+ } else {
+ shift += 8;
+ }
+ }
+ }
+
+ if (dword < 2) {
+ // put in ending mark
+ p_spot_light_indices[dword] += 0xFF << shift;
+ }
+ }
+
+ {
+ // process reflection probes
+ uint32_t dword = 0;
+ uint32_t shift = 0;
+
+ for (uint32_t i = 0; i < p_reflection_probe_instance_count && dword < p_max_dst_words; i++) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe_instances[i]);
+
+ if ((rpi->cull_mask & p_layer_mask) && (rpi->render_index < 255)) {
+ p_reflection_probe_indices[dword] += rpi->render_index << shift;
+ if (shift == 24) {
+ dword++;
+ shift = 0;
+ } else {
+ shift += 8;
+ }
+ }
+ }
+
+ if (dword < 2) {
+ // put in ending mark
+ p_reflection_probe_indices[dword] += 0xFF << shift;
+ }
+ }
+
+ {
+ // process decals
+ uint32_t dword = 0;
+ uint32_t shift = 0;
+
+ for (uint32_t i = 0; i < p_decal_instance_count && dword < p_max_dst_words; i++) {
+ DecalInstance *decal = decal_instance_owner.getornull(p_decal_instances[i]);
+
+ if ((decal->cull_mask & p_layer_mask) && (decal->render_index < 255)) {
+ p_decal_instance_indices[dword] += decal->render_index << shift;
+ if (shift == 24) {
+ dword++;
+ shift = 0;
+ } else {
+ shift += 8;
+ }
+ }
+ }
+
+ if (dword < 2) {
+ // put in ending mark
+ p_decal_instance_indices[dword] += 0xFF << shift;
+ }
+ }
+}
+
void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
ERR_FAIL_COND(!rb->volumetric_fog);
@@ -2946,7 +3079,7 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
rb->volumetric_fog = nullptr;
}
-void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) {
+void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count) {
ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
@@ -2960,7 +3093,6 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
//validate
if (!env || !env->volumetric_fog_enabled || rb->volumetric_fog->width != target_width || rb->volumetric_fog->height != target_height || rb->volumetric_fog->depth != volumetric_fog_depth) {
_volumetric_fog_erase(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
}
}
@@ -2996,7 +3128,6 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
- _render_buffers_uniform_set_changed(p_render_buffers);
Vector<RD::Uniform> uniforms;
{
@@ -3110,7 +3241,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 11;
- u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers));
+ u.ids.push_back(render_buffers_get_voxel_gi_buffer(p_render_buffers));
uniforms.push_back(u);
}
@@ -3118,8 +3249,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 12;
- for (int i = 0; i < RendererSceneGIRD::MAX_GIPROBES; i++) {
- u.ids.push_back(rb->gi.giprobe_textures[i]);
+ for (int i = 0; i < RendererSceneGIRD::MAX_VOXEL_GI_INSTANCES; i++) {
+ u.ids.push_back(rb->gi.voxel_gi_textures[i]);
}
uniforms.push_back(u);
}
@@ -3244,10 +3375,10 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
params.cam_rotation[10] = p_cam_transform.basis[2][2];
params.cam_rotation[11] = 0;
params.filter_axis = 0;
- params.max_gi_probes = env->volumetric_fog_gi_inject > 0.001 ? p_gi_probe_count : 0;
+ params.max_voxel_gi_instances = env->volumetric_fog_gi_inject > 0.001 ? p_voxel_gi_count : 0;
params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES;
- Transform to_prev_cam_view = rb->volumetric_fog->prev_cam_transform.affine_inverse() * p_cam_transform;
+ Transform3D to_prev_cam_view = rb->volumetric_fog->prev_cam_transform.affine_inverse() * p_cam_transform;
storage->store_transform(to_prev_cam_view, params.to_prev_view);
params.use_temporal_reprojection = env->volumetric_fog_temporal_reprojection;
@@ -3341,13 +3472,9 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
rb->volumetric_fog->prev_cam_transform = p_cam_transform;
}
-uint32_t RendererSceneRenderRD::_get_render_state_directional_light_count() const {
- return render_state.directional_light_count;
-}
-
-bool RendererSceneRenderRD::_needs_post_prepass_render(bool p_use_gi) {
- if (render_state.render_buffers.is_valid()) {
- RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers);
+bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) {
+ if (p_render_data->render_buffers.is_valid()) {
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
if (rb->sdfgi != nullptr) {
return true;
}
@@ -3355,48 +3482,46 @@ bool RendererSceneRenderRD::_needs_post_prepass_render(bool p_use_gi) {
return false;
}
-void RendererSceneRenderRD::_post_prepass_render(bool p_use_gi) {
- if (render_state.render_buffers.is_valid()) {
+void RendererSceneRenderRD::_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) {
+ if (p_render_data->render_buffers.is_valid()) {
if (p_use_gi) {
- RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers);
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
ERR_FAIL_COND(rb == nullptr);
if (rb->sdfgi == nullptr) {
return;
}
- RendererSceneEnvironmentRD *env = environment_owner.getornull(render_state.environment);
+ RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment);
rb->sdfgi->update_probes(env, sky.sky_owner.getornull(env->sky));
}
}
}
-void RendererSceneRenderRD::_pre_resolve_render(bool p_use_gi) {
- if (render_state.render_buffers.is_valid()) {
+void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi) {
+ if (p_render_data->render_buffers.is_valid()) {
if (p_use_gi) {
RD::get_singleton()->compute_list_end();
}
}
}
-void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer) {
+void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer) {
// Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time
- if (render_state.render_buffers.is_valid() && p_use_gi) {
- RenderBuffers *rb = render_buffers_owner.getornull(render_state.render_buffers);
+ if (p_render_data->render_buffers.is_valid() && p_use_gi) {
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers);
ERR_FAIL_COND(rb == nullptr);
- if (rb->sdfgi == nullptr) {
- return;
+ if (rb->sdfgi != nullptr) {
+ rb->sdfgi->store_probes();
}
-
- rb->sdfgi->store_probes();
}
render_state.cube_shadows.clear();
render_state.shadows.clear();
render_state.directional_shadows.clear();
- Plane camera_plane(render_state.cam_transform.origin, -render_state.cam_transform.basis.get_axis(Vector3::AXIS_Z));
- float lod_distance_multiplier = render_state.cam_projection.get_lod_multiplier();
+ Plane camera_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z));
+ float lod_distance_multiplier = p_render_data->cam_projection.get_lod_multiplier();
{
for (int i = 0; i < render_state.render_shadow_count; i++) {
@@ -3413,7 +3538,7 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
//cube shadows are rendered in their own way
for (uint32_t i = 0; i < render_state.cube_shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, render_state.shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, render_state.screen_lod_threshold, true, true, true);
+ _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, true, true, true);
}
if (render_state.directional_shadows.size()) {
@@ -3427,7 +3552,7 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
// Render GI
bool render_shadows = render_state.directional_shadows.size() || render_state.shadows.size();
- bool render_gi = render_state.render_buffers.is_valid() && p_use_gi;
+ bool render_gi = p_render_data->render_buffers.is_valid() && p_use_gi;
if (render_shadows && render_gi) {
RENDER_TIMESTAMP("Render GI + Render Shadows (parallel)");
@@ -3443,11 +3568,11 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
//render directional shadows
for (uint32_t i = 0; i < render_state.directional_shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, render_state.shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, render_state.screen_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false);
+ _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false);
}
//render positional shadows
for (uint32_t i = 0; i < render_state.shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, render_state.shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, render_state.screen_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true);
+ _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true);
}
_render_shadow_process();
@@ -3455,7 +3580,7 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
//start GI
if (render_gi) {
- gi.process_gi(render_state.render_buffers, p_normal_roughness_buffer, p_gi_probe_buffer, render_state.environment, render_state.cam_projection, render_state.cam_transform, *render_state.gi_probes, this);
+ gi.process_gi(p_render_data->render_buffers, p_normal_roughness_buffer, p_voxel_gi_buffer, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, *p_render_data->voxel_gi_instances, this);
}
//Do shadow rendering (in parallel with GI)
@@ -3467,9 +3592,9 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier
}
- if (render_state.render_buffers.is_valid()) {
+ if (p_render_data->render_buffers.is_valid()) {
if (p_use_ssao) {
- _process_ssao(render_state.render_buffers, render_state.environment, p_normal_roughness_buffer, render_state.cam_projection);
+ _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_buffer, p_render_data->cam_projection);
}
}
@@ -3477,32 +3602,32 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL);
if (current_cluster_builder) {
- current_cluster_builder->begin(render_state.cam_transform, render_state.cam_projection, !render_state.reflection_probe.is_valid());
+ current_cluster_builder->begin(p_render_data->cam_transform, p_render_data->cam_projection, !p_render_data->reflection_probe.is_valid());
}
bool using_shadows = true;
- if (render_state.reflection_probe.is_valid()) {
- if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(render_state.reflection_probe))) {
+ if (p_render_data->reflection_probe.is_valid()) {
+ if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
using_shadows = false;
}
} else {
//do not render reflections when rendering a reflection probe
- _setup_reflections(*render_state.reflection_probes, render_state.cam_transform.affine_inverse(), render_state.environment);
+ _setup_reflections(*p_render_data->reflection_probes, p_render_data->cam_transform.affine_inverse(), p_render_data->environment);
}
uint32_t directional_light_count = 0;
uint32_t positional_light_count = 0;
- _setup_lights(*render_state.lights, render_state.cam_transform, render_state.shadow_atlas, using_shadows, directional_light_count, positional_light_count);
- _setup_decals(*render_state.decals, render_state.cam_transform.affine_inverse());
+ _setup_lights(*p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count);
+ _setup_decals(*p_render_data->decals, p_render_data->cam_transform.affine_inverse());
- render_state.directional_light_count = directional_light_count;
+ p_render_data->directional_light_count = directional_light_count;
if (current_cluster_builder) {
current_cluster_builder->bake_cluster();
}
- if (render_state.render_buffers.is_valid()) {
+ if (p_render_data->render_buffers.is_valid()) {
bool directional_shadows = false;
for (uint32_t i = 0; i < directional_light_count; i++) {
if (cluster.directional_lights[i].shadow_enabled) {
@@ -3511,38 +3636,60 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
}
}
if (is_volumetric_supported()) {
- _update_volumetric_fog(render_state.render_buffers, render_state.environment, render_state.cam_projection, render_state.cam_transform, render_state.shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count);
+ _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count);
}
}
}
-void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data) {
+void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data) {
// getting this here now so we can direct call a bunch of things more easily
RenderBuffers *rb = nullptr;
if (p_render_buffers.is_valid()) {
rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb); // !BAS! Do we fail here or skip the parts that won't work. can't really see a case why we would be rendering without buffers....
+ ERR_FAIL_COND(!rb);
}
//assign render data
+ RenderDataRD render_data;
{
- render_state.render_buffers = p_render_buffers;
- render_state.cam_transform = p_cam_transform;
- render_state.cam_projection = p_cam_projection;
- render_state.cam_ortogonal = p_cam_projection.is_orthogonal();
- render_state.instances = &p_instances;
- render_state.lights = &p_lights;
- render_state.reflection_probes = &p_reflection_probes;
- render_state.gi_probes = &p_gi_probes;
- render_state.decals = &p_decals;
- render_state.lightmaps = &p_lightmaps;
- render_state.environment = p_environment;
- render_state.camera_effects = p_camera_effects;
- render_state.shadow_atlas = p_shadow_atlas;
- render_state.reflection_atlas = p_reflection_atlas;
- render_state.reflection_probe = p_reflection_probe;
- render_state.reflection_probe_pass = p_reflection_probe_pass;
- render_state.screen_lod_threshold = p_screen_lod_threshold;
+ render_data.render_buffers = p_render_buffers;
+
+ // Our first camera is used by default
+ render_data.cam_transform = p_camera_data->main_transform;
+ render_data.cam_projection = p_camera_data->main_projection;
+ render_data.view_projection[0] = p_camera_data->main_projection;
+ render_data.cam_ortogonal = p_camera_data->is_ortogonal;
+
+ render_data.view_count = p_camera_data->view_count;
+ for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
+ render_data.view_projection[v] = p_camera_data->view_projection[v];
+ }
+
+ render_data.z_near = p_camera_data->main_projection.get_z_near();
+ render_data.z_far = p_camera_data->main_projection.get_z_far();
+
+ render_data.instances = &p_instances;
+ render_data.lights = &p_lights;
+ render_data.reflection_probes = &p_reflection_probes;
+ render_data.voxel_gi_instances = &p_voxel_gi_instances;
+ render_data.decals = &p_decals;
+ render_data.lightmaps = &p_lightmaps;
+ render_data.environment = p_environment;
+ render_data.camera_effects = p_camera_effects;
+ render_data.shadow_atlas = p_shadow_atlas;
+ render_data.reflection_atlas = p_reflection_atlas;
+ render_data.reflection_probe = p_reflection_probe;
+ render_data.reflection_probe_pass = p_reflection_probe_pass;
+
+ // this should be the same for all cameras..
+ render_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier();
+ render_data.lod_camera_plane = Plane(p_camera_data->main_transform.get_origin(), -p_camera_data->main_transform.basis.get_axis(Vector3::AXIS_Z));
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
+ render_data.screen_lod_threshold = 0.0;
+ } else {
+ render_data.screen_lod_threshold = p_screen_lod_threshold;
+ }
render_state.render_shadows = p_render_shadows;
render_state.render_shadow_count = p_render_shadow_count;
@@ -3554,9 +3701,9 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
PagedArray<RID> empty;
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
- render_state.lights = &empty;
- render_state.reflection_probes = &empty;
- render_state.gi_probes = &empty;
+ render_data.lights = &empty;
+ render_data.reflection_probes = &empty;
+ render_data.voxel_gi_instances = &empty;
}
//sdfgi first
@@ -3576,19 +3723,21 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
clear_color = storage->get_default_clear_color();
}
- //assign render indices to giprobes
- for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) {
- RendererSceneGIRD::GIProbeInstance *giprobe_inst = gi.gi_probe_instance_owner.getornull(p_gi_probes[i]);
- if (giprobe_inst) {
- giprobe_inst->render_index = i;
+ //assign render indices to voxel_gi_instances
+ if (is_dynamic_gi_supported()) {
+ for (uint32_t i = 0; i < (uint32_t)p_voxel_gi_instances.size(); i++) {
+ RendererSceneGIRD::VoxelGIInstance *voxel_gi_inst = gi.voxel_gi_instance_owner.getornull(p_voxel_gi_instances[i]);
+ if (voxel_gi_inst) {
+ voxel_gi_inst->render_index = i;
+ }
}
}
- if (render_buffers_owner.owns(render_state.render_buffers)) {
- // render_state.render_buffers == p_render_buffers so we can use our already retrieved rb
+ if (render_buffers_owner.owns(render_data.render_buffers)) {
+ // render_data.render_buffers == p_render_buffers so we can use our already retrieved rb
current_cluster_builder = rb->cluster_builder;
- } else if (reflection_probe_instance_owner.owns(render_state.reflection_probe)) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_state.reflection_probe);
+ } else if (reflection_probe_instance_owner.owns(render_data.reflection_probe)) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_data.reflection_probe);
ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas);
if (!ra) {
ERR_PRINT("reflection probe has no reflection atlas! Bug?");
@@ -3601,22 +3750,29 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
current_cluster_builder = nullptr;
}
- if (rb != nullptr && rb->sdfgi != nullptr) {
- rb->sdfgi->update_cascades();
-
- rb->sdfgi->pre_process_gi(p_cam_transform, this);
- }
+ render_state.voxel_gi_count = 0;
- render_state.gi_probe_count = 0;
- if (rb != nullptr && rb->sdfgi != nullptr) {
- gi.setup_giprobes(render_state.render_buffers, render_state.cam_transform, *render_state.gi_probes, render_state.gi_probe_count, this);
+ if (rb != nullptr) {
+ if (rb->sdfgi) {
+ rb->sdfgi->update_cascades();
+ rb->sdfgi->pre_process_gi(render_data.cam_transform, &render_data, this);
+ rb->sdfgi->update_light();
+ }
- rb->sdfgi->update_light();
+ if (p_voxel_gi_instances.size()) {
+ gi.setup_voxel_gi_instances(render_data.render_buffers, render_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this);
+ }
}
render_state.depth_prepass_used = false;
//calls _pre_opaque_render between depth pre-pass and opaque pass
- _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, *render_state.gi_probes, p_lightmaps, p_environment, current_cluster_builder->get_cluster_buffer(), current_cluster_builder->get_cluster_size(), current_cluster_builder->get_max_cluster_elements(), p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color, p_screen_lod_threshold);
+ if (current_cluster_builder != nullptr) {
+ render_data.cluster_buffer = current_cluster_builder->get_cluster_buffer();
+ render_data.cluster_size = current_cluster_builder->get_cluster_size();
+ render_data.cluster_max_elements = current_cluster_builder->get_max_cluster_elements();
+ }
+
+ _render_scene(&render_data, clear_color);
if (p_render_buffers.is_valid()) {
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
@@ -3637,15 +3793,17 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
default: {
}
}
- current_cluster_builder->debug(elem_type);
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->debug(elem_type);
+ }
}
RENDER_TIMESTAMP("Tonemap");
- _render_buffers_post_process_and_tonemap(p_render_buffers, p_environment, p_camera_effects, p_cam_projection);
- _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas);
+ _render_buffers_post_process_and_tonemap(&render_data);
+ _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) {
- rb->sdfgi->debug_draw(p_cam_projection, p_cam_transform, rb->width, rb->height, rb->render_target, rb->texture);
+ rb->sdfgi->debug_draw(render_data.cam_projection, render_data.cam_transform, rb->width, rb->height, rb->render_target, rb->texture);
}
}
}
@@ -3671,7 +3829,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
bool flip_y = false;
CameraMatrix light_projection;
- Transform light_transform;
+ Transform3D light_transform;
if (storage->light_get_type(light_instance->light) == RS::LIGHT_DIRECTIONAL) {
//set pssm stuff
@@ -3821,11 +3979,11 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
}
}
-void RendererSceneRenderRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RendererSceneRenderRD::render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
_render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, p_framebuffer, p_region);
}
-void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) {
+void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) {
ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider));
Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale();
CameraMatrix cm;
@@ -3834,7 +3992,7 @@ void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider,
Vector3 cam_pos = p_transform.origin;
cam_pos.y += extents.y;
- Transform cam_xform;
+ Transform3D cam_xform;
cam_xform.set_look_at(cam_pos, cam_pos - p_transform.basis.get_axis(Vector3::AXIS_Y), -p_transform.basis.get_axis(Vector3::AXIS_Z).normalized());
RID fb = storage->particles_collision_get_heightfield_framebuffer(p_collider);
@@ -3881,19 +4039,19 @@ bool RendererSceneRenderRD::free(RID p_rid) {
decal_instance_owner.free(p_rid);
} else if (lightmap_instance_owner.owns(p_rid)) {
lightmap_instance_owner.free(p_rid);
- } else if (gi.gi_probe_instance_owner.owns(p_rid)) {
- RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_rid);
- if (gi_probe->texture.is_valid()) {
- RD::get_singleton()->free(gi_probe->texture);
- RD::get_singleton()->free(gi_probe->write_buffer);
+ } else if (gi.voxel_gi_instance_owner.owns(p_rid)) {
+ RendererSceneGIRD::VoxelGIInstance *voxel_gi = gi.voxel_gi_instance_owner.getornull(p_rid);
+ if (voxel_gi->texture.is_valid()) {
+ RD::get_singleton()->free(voxel_gi->texture);
+ RD::get_singleton()->free(voxel_gi->write_buffer);
}
- 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);
+ for (int i = 0; i < voxel_gi->dynamic_maps.size(); i++) {
+ RD::get_singleton()->free(voxel_gi->dynamic_maps[i].texture);
+ RD::get_singleton()->free(voxel_gi->dynamic_maps[i].depth);
}
- gi.gi_probe_instance_owner.free(p_rid);
+ gi.voxel_gi_instance_owner.free(p_rid);
} else if (sky.sky_owner.owns(p_rid)) {
sky.update_dirty_skys();
sky.free_sky(p_rid);
@@ -4098,8 +4256,12 @@ bool RendererSceneRenderRD::is_volumetric_supported() const {
return true;
}
+uint32_t RendererSceneRenderRD::get_max_elements() const {
+ return GLOBAL_GET("rendering/limits/cluster_builder/max_clustered_elements");
+}
+
RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
- max_cluster_elements = GLOBAL_GET("rendering/limits/cluster_builder/max_clustered_elements");
+ max_cluster_elements = get_max_elements();
storage = p_storage;
singleton = this;
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 4bf0818206..9a793e42c5 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -43,6 +43,44 @@
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
+struct RenderDataRD {
+ RID render_buffers = RID();
+
+ Transform3D cam_transform = Transform3D();
+ CameraMatrix cam_projection = CameraMatrix();
+ bool cam_ortogonal = false;
+
+ // For stereo rendering
+ uint32_t view_count = 1;
+ CameraMatrix view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
+
+ float z_near = 0.0;
+ float z_far = 0.0;
+
+ const PagedArray<RendererSceneRender::GeometryInstance *> *instances = nullptr;
+ const PagedArray<RID> *lights = nullptr;
+ const PagedArray<RID> *reflection_probes = nullptr;
+ const PagedArray<RID> *voxel_gi_instances = nullptr;
+ const PagedArray<RID> *decals = nullptr;
+ const PagedArray<RID> *lightmaps = nullptr;
+ RID environment = RID();
+ RID camera_effects = RID();
+ RID shadow_atlas = RID();
+ RID reflection_atlas = RID();
+ RID reflection_probe = RID();
+ int reflection_probe_pass = 0;
+
+ float lod_distance_multiplier = 0.0;
+ Plane lod_camera_plane = Plane();
+ float screen_lod_threshold = 0.0;
+
+ RID cluster_buffer = RID();
+ uint32_t cluster_size = 0;
+ uint32_t cluster_max_elements = 0;
+
+ uint32_t directional_light_count = 0;
+};
+
class RendererSceneRenderRD : public RendererSceneRender {
friend RendererSceneSkyRD;
friend RendererSceneGIRD;
@@ -53,45 +91,43 @@ protected:
double time_step = 0;
struct RenderBufferData {
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) = 0;
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) = 0;
virtual ~RenderBufferData() {}
};
virtual RenderBufferData *_create_render_buffer_data() = 0;
- void _setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count);
- void _setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform);
- void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment);
+ void _setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count);
+ void _setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform);
+ void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment);
- virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_cluster_max_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color, float p_screen_lod_threshold) = 0;
+ virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0;
virtual void _render_shadow_begin() = 0;
- virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true) = 0;
+ virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true) = 0;
virtual void _render_shadow_process() = 0;
virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) = 0;
- virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
+ virtual void _render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0;
- virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0;
+ virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0;
void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform);
RenderBufferData *render_buffers_get_data(RID p_render_buffers);
virtual void _base_uniforms_changed() = 0;
- virtual void _render_buffers_uniform_set_changed(RID p_render_buffers) = 0;
virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) = 0;
void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection);
void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive);
void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera);
- bool _needs_post_prepass_render(bool p_use_gi);
- void _post_prepass_render(bool p_use_gi);
- void _pre_resolve_render(bool p_use_gi);
+ bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
+ void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
+ void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi);
- void _pre_opaque_render(bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer);
- uint32_t _get_render_state_directional_light_count() const;
+ void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer);
// needed for a single argument calls (material and uv2)
PagedArrayPool<GeometryInstance *> cull_argument_pool;
@@ -150,8 +186,9 @@ private:
uint32_t render_step = 0;
uint64_t last_pass = 0;
uint32_t render_index = 0;
+ uint32_t cull_mask = 0;
- Transform transform;
+ Transform3D transform;
};
mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
@@ -160,7 +197,9 @@ private:
struct DecalInstance {
RID decal;
- Transform transform;
+ Transform3D transform;
+ uint32_t render_index;
+ uint32_t cull_mask;
};
mutable RID_Owner<DecalInstance> decal_instance_owner;
@@ -169,7 +208,7 @@ private:
struct LightmapInstance {
RID lightmap;
- Transform transform;
+ Transform3D transform;
};
mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
@@ -277,7 +316,7 @@ private:
struct LightInstance {
struct ShadowTransform {
CameraMatrix camera;
- Transform transform;
+ Transform3D transform;
float farplane;
float split;
float bias_scale;
@@ -294,7 +333,7 @@ private:
AABB aabb;
RID self;
RID light;
- Transform transform;
+ Transform3D transform;
Vector3 light_vector;
Vector3 spot_vector;
@@ -305,6 +344,7 @@ private:
uint64_t last_scene_shadow_pass = 0;
uint64_t last_pass = 0;
uint32_t light_index = 0;
+ uint32_t cull_mask = 0;
uint32_t light_directional_index = 0;
uint32_t current_shadow_atlas_key = 0;
@@ -375,6 +415,7 @@ private:
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
bool use_debanding = false;
+ uint32_t view_count = 1;
RID render_target;
@@ -418,6 +459,10 @@ private:
Vector<RID> ao_pong_slices;
RID ao_final;
RID importance_map[2];
+
+ RID downsample_uniform_set;
+ RID gather_uniform_set;
+ RID importance_map_uniform_set;
} ssao;
struct SSR {
@@ -441,14 +486,16 @@ private:
void _allocate_blur_textures(RenderBuffers *rb);
void _allocate_luminance_textures(RenderBuffers *rb);
- void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas);
- void _render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection);
+ void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
+ void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
/* Cluster */
struct Cluster {
/* Scene State UBO */
+ // !BAS! Most data here is not just used by our clustering logic but also by other lighting implementations. Maybe rename this struct to something more appropriate
+
enum {
REFLECTION_AMBIENT_DISABLED = 0,
REFLECTION_AMBIENT_ENVIRONMENT = 1,
@@ -492,7 +539,7 @@ private:
float soft_shadow_scale;
uint32_t mask;
float shadow_volumetric_fog_fade;
- uint32_t pad;
+ uint32_t bake_mode;
float projector_rect[4];
};
@@ -509,7 +556,8 @@ private:
uint32_t shadow_enabled;
float fade_from;
float fade_to;
- uint32_t pad[3];
+ uint32_t pad[2];
+ uint32_t bake_mode;
float shadow_volumetric_fog_fade;
float shadow_bias[4];
float shadow_normal_bias[4];
@@ -586,38 +634,19 @@ private:
} cluster;
struct RenderState {
- RID render_buffers;
- Transform cam_transform;
- CameraMatrix cam_projection;
- bool cam_ortogonal = false;
- const PagedArray<GeometryInstance *> *instances = nullptr;
- const PagedArray<RID> *lights = nullptr;
- const PagedArray<RID> *reflection_probes = nullptr;
- const PagedArray<RID> *gi_probes = nullptr;
- const PagedArray<RID> *decals = nullptr;
- const PagedArray<RID> *lightmaps = nullptr;
- RID environment;
- RID camera_effects;
- RID shadow_atlas;
- RID reflection_atlas;
- RID reflection_probe;
- int reflection_probe_pass = 0;
- float screen_lod_threshold = 0.0;
-
- const RenderShadowData *render_shadows = nullptr;
+ const RendererSceneRender::RenderShadowData *render_shadows = nullptr;
int render_shadow_count = 0;
- const RenderSDFGIData *render_sdfgi_regions = nullptr;
+ const RendererSceneRender::RenderSDFGIData *render_sdfgi_regions = nullptr;
int render_sdfgi_region_count = 0;
- const RenderSDFGIUpdateData *sdfgi_update_data = nullptr;
+ const RendererSceneRender::RenderSDFGIUpdateData *sdfgi_update_data = nullptr;
- uint32_t directional_light_count = 0;
- uint32_t gi_probe_count = 0;
+ uint32_t voxel_gi_count = 0;
LocalVector<int> cube_shadows;
LocalVector<int> shadows;
LocalVector<int> directional_shadows;
- bool depth_prepass_used;
+ bool depth_prepass_used; // this does not seem used anywhere...
} render_state;
struct VolumetricFog {
@@ -643,7 +672,7 @@ private:
int last_shadow_filter = -1;
- Transform prev_cam_transform;
+ Transform3D prev_cam_transform;
};
enum {
@@ -672,7 +701,7 @@ private:
float detail_spread;
float gi_inject;
- uint32_t max_gi_probes;
+ uint32_t max_voxel_gi_instances;
uint32_t cluster_type_size;
float screen_size[2];
@@ -701,7 +730,7 @@ private:
bool volumetric_fog_filter_active = true;
void _volumetric_fog_erase(RenderBuffers *rb);
- void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count);
+ void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count);
RID shadow_sampler;
@@ -720,7 +749,7 @@ private:
void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true);
public:
- virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance) = 0;
+ virtual Transform3D geometry_instance_get_transform(GeometryInstance *p_instance) = 0;
virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) = 0;
/* SHADOW ATLAS API */
@@ -858,9 +887,9 @@ public:
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_transform(RID p_light_instance, const Transform3D &p_transform);
void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb);
- 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_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &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) {
@@ -868,7 +897,7 @@ public:
return li->light;
}
- _FORCE_INLINE_ Transform light_instance_get_base_transform(RID p_light_instance) {
+ _FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) {
LightInstance *li = light_instance_owner.getornull(p_light_instance);
return li->transform;
}
@@ -925,7 +954,7 @@ public:
return float(1.0) / shadow_size;
}
- _FORCE_INLINE_ Transform
+ _FORCE_INLINE_ Transform3D
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;
@@ -999,7 +1028,7 @@ public:
}
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_instance_set_transform(RID p_instance, const Transform3D &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);
@@ -1043,9 +1072,9 @@ public:
return rpi->last_pass;
}
- _FORCE_INLINE_ Transform reflection_probe_instance_get_transform(RID p_instance) {
+ _FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, Transform());
+ ERR_FAIL_COND_V(!rpi, Transform3D());
return rpi->transform;
}
@@ -1058,20 +1087,20 @@ public:
}
virtual RID decal_instance_create(RID p_decal);
- virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform);
+ virtual void decal_instance_set_transform(RID p_decal, const Transform3D &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 {
+ _FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal) const {
DecalInstance *decal = decal_instance_owner.getornull(p_decal);
return decal->transform;
}
virtual RID lightmap_instance_create(RID p_lightmap);
- virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform);
+ virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform);
_FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) {
return lightmap_instance_owner.getornull(p_lightmap_instance) != nullptr;
}
@@ -1080,29 +1109,31 @@ public:
LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance);
return li->lightmap;
}
- _FORCE_INLINE_ Transform lightmap_instance_get_transform(RID p_lightmap_instance) {
+ _FORCE_INLINE_ Transform3D lightmap_instance_get_transform(RID p_lightmap_instance) {
LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance);
return li->transform;
}
+ void _fill_instance_indices(const RID *p_omni_light_instances, uint32_t p_omni_light_instance_count, uint32_t *p_omni_light_indices, const RID *p_spot_light_instances, uint32_t p_spot_light_instance_count, uint32_t *p_spot_light_indices, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count, uint32_t *p_reflection_probe_indices, const RID *p_decal_instances, uint32_t p_decal_instance_count, uint32_t *p_decal_instance_indices, uint32_t p_layer_mask, uint32_t p_max_dst_words = 2);
+
/* gi light probes */
- RID gi_probe_instance_create(RID p_base);
- void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
- bool gi_probe_needs_update(RID p_probe) const;
- void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects);
- void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi.gi_probe_quality = p_quality; }
+ RID voxel_gi_instance_create(RID p_base);
+ void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform);
+ bool voxel_gi_needs_update(RID p_probe) const;
+ void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects);
+ void voxel_gi_set_quality(RS::VoxelGIQuality p_quality) { gi.voxel_gi_quality = p_quality; }
/* render buffers */
RID render_buffers_create();
- void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding);
+ void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count);
void gi_set_use_half_resolution(bool p_enable);
RID render_buffers_get_ao_texture(RID p_render_buffers);
RID render_buffers_get_back_buffer_texture(RID p_render_buffers);
- RID render_buffers_get_gi_probe_buffer(RID p_render_buffers);
- RID render_buffers_get_default_gi_probe_buffer();
+ RID render_buffers_get_voxel_gi_buffer(RID p_render_buffers);
+ RID render_buffers_get_default_voxel_gi_buffer();
RID render_buffers_get_gi_ambient_texture(RID p_render_buffers);
RID render_buffers_get_gi_reflection_texture(RID p_render_buffers);
@@ -1125,11 +1156,11 @@ public:
float render_buffers_get_volumetric_fog_end(RID p_render_buffers);
float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers);
- void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr);
+ void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr);
- void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
+ void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region);
- void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances);
+ void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances);
virtual void set_scene_pass(uint64_t p_pass) {
scene_pass = p_pass;
@@ -1192,6 +1223,7 @@ public:
virtual bool is_dynamic_gi_supported() const;
virtual bool is_clustered_enabled() const;
virtual bool is_volumetric_supported() const;
+ virtual uint32_t get_max_elements() const;
RendererSceneRenderRD(RendererStorageRD *p_storage);
~RendererSceneRenderRD();
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
index 54c6e81110..1aa01dd16e 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
@@ -30,7 +30,9 @@
#include "renderer_scene_sky_rd.h"
#include "core/config/project_settings.h"
+#include "core/math/math_defs.h"
#include "renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/rendering_server_default.h"
////////////////////////////////////////////////////////////////////////////////
@@ -125,8 +127,12 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) {
depth_stencil_state.enable_depth_test = true;
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
- RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i);
- pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
+ if (scene_singleton->sky.sky_shader.shader.is_variant_enabled(i)) {
+ RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i);
+ pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
+ } else {
+ pipelines[i].clear();
+ }
}
valid = true;
@@ -693,7 +699,18 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
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_modes.push_back("\n#define USE_MULTIVIEW\n"); // Full size multiview
+ sky_modes.push_back("\n#define USE_HALF_RES_PASS\n#define USE_MULTIVIEW\n"); // Half Res multiview
+ sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n#define USE_MULTIVIEW\n"); // Quarter res multiview
+
sky_shader.shader.initialize(sky_modes, defines);
+
+ if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ sky_shader.shader.set_variant_enabled(SKY_VERSION_BACKGROUND_MULTIVIEW, false);
+ sky_shader.shader.set_variant_enabled(SKY_VERSION_HALF_RES_MULTIVIEW, false);
+ sky_shader.shader.set_variant_enabled(SKY_VERSION_QUARTER_RES_MULTIVIEW, false);
+ }
}
// register our shader funds
@@ -710,6 +727,9 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
actions.renames["SKY_COORDS"] = "panorama_coords";
actions.renames["SCREEN_UV"] = "uv";
actions.renames["TIME"] = "params.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
actions.renames["HALF_RES_COLOR"] = "half_res_color";
actions.renames["QUARTER_RES_COLOR"] = "quarter_res_color";
actions.renames["RADIANCE"] = "radiance";
@@ -874,7 +894,7 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
}
}
-void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
+void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
ERR_FAIL_COND(!p_env); // I guess without an environment we also can't have a sky...
SkyMaterialData *material = nullptr;
@@ -1044,7 +1064,7 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b
RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo);
}
-void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) {
+void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform, double p_time) {
ERR_FAIL_COND(!p_env);
Sky *sky = get_sky(p_env->sky);
@@ -1131,12 +1151,12 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
RD::DrawListID cubemap_draw_list;
for (int i = 0; i < 6; i++) {
- Transform local_view;
+ Transform3D local_view;
local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
}
@@ -1149,12 +1169,12 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
RD::DrawListID cubemap_draw_list;
for (int i = 0; i < 6; i++) {
- Transform local_view;
+ Transform3D local_view;
local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
}
@@ -1163,12 +1183,12 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP];
for (int i = 0; i < 6; i++) {
- Transform local_view;
+ Transform3D local_view;
local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd);
cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
@@ -1209,9 +1229,12 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
}
}
-void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) {
+void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time) {
ERR_FAIL_COND(!p_env);
+ ERR_FAIL_COND(p_view_count == 0);
+ ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
+
Sky *sky = get_sky(p_env->sky);
ERR_FAIL_COND(!sky);
@@ -1253,24 +1276,28 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont
float multiplier = p_env->bg_energy;
float custom_fov = p_env->sky_custom_fov;
+
// Camera
CameraMatrix camera;
+ uint32_t view_count = p_view_count;
+ const CameraMatrix *projections = p_projections;
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();
+ // With custom fov we don't support stereo...
+ float near_plane = p_projections[0].get_z_near();
+ float far_plane = p_projections[0].get_z_far();
+ float aspect = p_projections[0].get_aspect();
camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
- } else {
- camera = p_projection;
+ view_count = 1;
+ projections = &camera;
}
sky_transform = p_transform.basis * sky_transform;
if (shader_data->uses_quarter_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES];
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
@@ -1278,12 +1305,12 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, p_time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(draw_list, p_time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
if (shader_data->uses_half_res) {
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES];
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
@@ -1291,11 +1318,11 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont
clear_colors.push_back(Color(0.0, 0.0, 0.0));
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
- storage->get_effects()->render_sky(draw_list, p_time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(draw_list, p_time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
- PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND];
+ PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
RID texture_uniform_set;
if (sky) {
@@ -1305,7 +1332,7 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont
}
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- storage->get_effects()->render_sky(draw_list, p_time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ storage->get_effects()->render_sky(draw_list, p_time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin);
RD::get_singleton()->draw_list_end();
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
index 73390a586b..200902bff2 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h
@@ -72,6 +72,11 @@ public:
SKY_VERSION_CUBEMAP,
SKY_VERSION_CUBEMAP_HALF_RES,
SKY_VERSION_CUBEMAP_QUARTER_RES,
+
+ SKY_VERSION_BACKGROUND_MULTIVIEW,
+ SKY_VERSION_HALF_RES_MULTIVIEW,
+ SKY_VERSION_QUARTER_RES_MULTIVIEW,
+
SKY_VERSION_MAX
};
@@ -268,9 +273,9 @@ public:
void init(RendererStorageRD *p_storage);
- void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
- void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time);
- void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time);
+ void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
+ void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform, double p_time);
+ void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time);
void invalidate_sky(Sky *p_sky);
void update_dirty_skys();
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 189c5782f4..246b5f0e4c 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -33,6 +33,7 @@
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
+#include "core/math/math_defs.h"
#include "renderer_compositor_rd.h"
#include "servers/rendering/shader_language.h"
@@ -756,7 +757,7 @@ void RendererStorageRD::texture_3d_initialize(RID p_texture, Image::Format p_for
for (int i = 0; i < p_data.size(); i++) {
uint32_t s = images[i]->get_data().size();
- copymem(&all_data.write[offset], images[i]->get_data().ptr(), s);
+ memcpy(&all_data.write[offset], images[i]->get_data().ptr(), s);
{
Texture::BufferSlice3D slice;
slice.size.width = images[i]->get_width();
@@ -919,7 +920,7 @@ void RendererStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image>
for (int i = 0; i < p_data.size(); i++) {
uint32_t s = images[i]->get_data().size();
- copymem(&all_data.write[offset], images[i]->get_data().ptr(), s);
+ memcpy(&all_data.write[offset], images[i]->get_data().ptr(), s);
offset += s;
}
}
@@ -1439,8 +1440,10 @@ void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) {
material->shader_type = new_type;
}
- for (Map<StringName, RID>::Element *E = shader->default_texture_parameter.front(); E; E = E->next()) {
- shader->data->set_default_texture_param(E->key(), E->get());
+ if (shader->data) {
+ for (Map<StringName, RID>::Element *E = shader->default_texture_parameter.front(); E; E = E->next()) {
+ shader->data->set_default_texture_param(E->key(), E->get());
+ }
}
}
@@ -1877,8 +1880,8 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
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;
+ } else if (value.get_type() == Variant::QUATERNION) {
+ Quaternion v = value;
gui[0] = v.x;
gui[1] = v.y;
@@ -1925,7 +1928,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
gui[11] = 0;
} break;
case ShaderLanguage::TYPE_MAT4: {
- Transform v = value;
+ Transform3D v = value;
float *gui = (float *)data;
gui[0] = v.basis.elements[0][0];
@@ -2108,13 +2111,13 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
case ShaderLanguage::TYPE_INT:
case ShaderLanguage::TYPE_UINT:
case ShaderLanguage::TYPE_FLOAT: {
- zeromem(data, 4);
+ memset(data, 0, 4);
} break;
case ShaderLanguage::TYPE_BVEC2:
case ShaderLanguage::TYPE_IVEC2:
case ShaderLanguage::TYPE_UVEC2:
case ShaderLanguage::TYPE_VEC2: {
- zeromem(data, 8);
+ memset(data, 0, 8);
} break;
case ShaderLanguage::TYPE_BVEC3:
case ShaderLanguage::TYPE_IVEC3:
@@ -2124,16 +2127,16 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
case ShaderLanguage::TYPE_IVEC4:
case ShaderLanguage::TYPE_UVEC4:
case ShaderLanguage::TYPE_VEC4: {
- zeromem(data, 16);
+ memset(data, 0, 16);
} break;
case ShaderLanguage::TYPE_MAT2: {
- zeromem(data, 32);
+ memset(data, 0, 32);
} break;
case ShaderLanguage::TYPE_MAT3: {
- zeromem(data, 48);
+ memset(data, 0, 48);
} break;
case ShaderLanguage::TYPE_MAT4: {
- zeromem(data, 64);
+ memset(data, 0, 64);
} break;
default: {
@@ -2775,7 +2778,7 @@ AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
const float *dataptr = baseptr + j * 8;
- Transform mtx;
+ Transform3D mtx;
mtx.basis.elements[0].x = dataptr[0];
mtx.basis.elements[1].x = dataptr[1];
@@ -2802,7 +2805,7 @@ AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
const float *dataptr = baseptr + j * 12;
- Transform mtx;
+ Transform3D mtx;
mtx.basis.elements[0][0] = dataptr[0];
mtx.basis.elements[0][1] = dataptr[1];
@@ -3412,10 +3415,10 @@ void RendererStorageRD::_multimesh_make_local(MultiMesh *multimesh) const {
Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
{
const uint8_t *r = buffer.ptr();
- copymem(w, r, buffer.size());
+ memcpy(w, r, buffer.size());
}
} else {
- zeromem(w, multimesh->instances * multimesh->stride_cache * sizeof(float));
+ memset(w, 0, multimesh->instances * multimesh->stride_cache * sizeof(float));
}
}
uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
@@ -3477,7 +3480,7 @@ void RendererStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const fl
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;
+ Transform3D t;
if (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_3D) {
t.basis.elements[0][0] = data[0];
@@ -3513,7 +3516,7 @@ void RendererStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const fl
multimesh->aabb = aabb;
}
-void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) {
+void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
@@ -3620,15 +3623,15 @@ RID RendererStorageRD::multimesh_get_mesh(RID p_multimesh) const {
return multimesh->mesh;
}
-Transform RendererStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
+Transform3D RendererStorageRD::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());
+ ERR_FAIL_COND_V(!multimesh, Transform3D());
+ ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform3D());
+ ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform3D());
_multimesh_make_local(multimesh);
- Transform t;
+ Transform3D t;
{
const float *r = multimesh->data_cache.ptr();
@@ -3771,7 +3774,7 @@ Vector<float> RendererStorageRD::multimesh_get_buffer(RID p_multimesh) const {
{
float *w = ret.ptrw();
const uint8_t *r = buffer.ptr();
- copymem(w, r, buffer.size());
+ memcpy(w, r, buffer.size());
}
return ret;
@@ -3822,7 +3825,7 @@ void RendererStorageRD::_update_dirty_multimeshes() {
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 visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
@@ -3873,6 +3876,18 @@ void RendererStorageRD::particles_initialize(RID p_rid) {
particles_owner.initialize_rid(p_rid, Particles());
}
+void RendererStorageRD::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ if (particles->mode == p_mode) {
+ return;
+ }
+
+ _particles_free_data(particles);
+
+ particles->mode = p_mode;
+}
+
void RendererStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
@@ -3888,22 +3903,37 @@ bool RendererStorageRD::particles_get_emitting(RID p_particles) {
}
void RendererStorageRD::_particles_free_data(Particles *particles) {
- if (!particles->particle_buffer.is_valid()) {
- return;
+ if (particles->particle_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->particle_buffer);
+ particles->particle_buffer = RID();
+ RD::get_singleton()->free(particles->particle_instance_buffer);
+ particles->particle_instance_buffer = RID();
+ }
+
+ if (particles->frame_params_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->frame_params_buffer);
+ particles->frame_params_buffer = RID();
}
- RD::get_singleton()->free(particles->particle_buffer);
- RD::get_singleton()->free(particles->frame_params_buffer);
- RD::get_singleton()->free(particles->particle_instance_buffer);
particles->particles_transforms_buffer_uniform_set = RID();
- particles->particle_buffer = RID();
+ if (RD::get_singleton()->uniform_set_is_valid(particles->trail_bind_pose_uniform_set)) {
+ RD::get_singleton()->free(particles->trail_bind_pose_uniform_set);
+ }
+ particles->trail_bind_pose_uniform_set = RID();
+
+ if (particles->trail_bind_pose_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->trail_bind_pose_buffer);
+ particles->trail_bind_pose_buffer = RID();
+ }
if (RD::get_singleton()->uniform_set_is_valid(particles->collision_textures_uniform_set)) {
RD::get_singleton()->free(particles->collision_textures_uniform_set);
}
+ particles->collision_textures_uniform_set = RID();
if (particles->particles_sort_buffer.is_valid()) {
RD::get_singleton()->free(particles->particles_sort_buffer);
particles->particles_sort_buffer = RID();
+ particles->particles_sort_uniform_set = RID();
}
if (particles->emission_buffer != nullptr) {
@@ -3912,6 +3942,12 @@ void RendererStorageRD::_particles_free_data(Particles *particles) {
RD::get_singleton()->free(particles->emission_storage_buffer);
particles->emission_storage_buffer = RID();
}
+
+ if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) {
+ //will need to be re-created
+ RD::get_singleton()->free(particles->particles_material_uniform_set);
+ }
+ particles->particles_material_uniform_set = RID();
}
void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) {
@@ -3926,38 +3962,12 @@ void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) {
particles->amount = p_amount;
- if (particles->amount > 0) {
- particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * p_amount);
- particles->frame_params_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticlesFrameParams) * 1);
- particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (3 + 1 + 1) * p_amount);
- //needs to clear it
-
- {
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 1;
- u.ids.push_back(particles->particle_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 2;
- u.ids.push_back(particles->particle_instance_buffer);
- uniforms.push_back(u);
- }
-
- particles->particles_copy_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 0);
- }
- }
-
particles->prev_ticks = 0;
particles->phase = 0;
particles->prev_phase = 0;
particles->clear = true;
+
+ particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
}
void RendererStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) {
@@ -4013,6 +4023,22 @@ void RendererStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) {
ERR_FAIL_COND(!particles);
particles->fixed_fps = p_fps;
+
+ _particles_free_data(particles);
+
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+
+ particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
+}
+
+void RendererStorageRD::particles_set_interpolate(RID p_particles, bool p_enable) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->interpolate = p_enable;
}
void RendererStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) {
@@ -4022,6 +4048,42 @@ void RendererStorageRD::particles_set_fractional_delta(RID p_particles, bool p_e
particles->fractional_delta = p_enable;
}
+void RendererStorageRD::particles_set_trails(RID p_particles, bool p_enable, float p_length) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ ERR_FAIL_COND(p_length < 0.1);
+ p_length = MIN(10.0, p_length);
+
+ particles->trails_enabled = p_enable;
+ particles->trail_length = p_length;
+
+ _particles_free_data(particles);
+
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+
+ particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
+}
+
+void RendererStorageRD::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ if (particles->trail_bind_pose_buffer.is_valid() && particles->trail_bind_poses.size() != p_bind_poses.size()) {
+ _particles_free_data(particles);
+
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+ }
+ particles->trail_bind_poses = p_bind_poses;
+ particles->trail_bind_poses_dirty = true;
+
+ particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES);
+}
+
void RendererStorageRD::particles_set_collision_base_size(RID p_particles, float p_size) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
@@ -4029,6 +4091,13 @@ void RendererStorageRD::particles_set_collision_base_size(RID p_particles, float
particles->collision_base_size = p_size;
}
+void RendererStorageRD::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->transform_align = p_transform_align;
+}
+
void RendererStorageRD::particles_set_process_material(RID p_particles, RID p_material) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
@@ -4068,7 +4137,7 @@ void RendererStorageRD::_particles_allocate_emission_buffer(Particles *particles
ERR_FAIL_COND(particles->emission_buffer != nullptr);
particles->emission_buffer_data.resize(sizeof(ParticleEmissionBuffer::Data) * particles->amount + sizeof(uint32_t) * 4);
- zeromem(particles->emission_buffer_data.ptrw(), particles->emission_buffer_data.size());
+ memset(particles->emission_buffer_data.ptrw(), 0, particles->emission_buffer_data.size());
particles->emission_buffer = (ParticleEmissionBuffer *)particles->emission_buffer_data.ptrw();
particles->emission_buffer->particle_max = particles->amount;
@@ -4094,7 +4163,7 @@ void RendererStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitt
}
}
-void RendererStorageRD::particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
+void RendererStorageRD::particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
ERR_FAIL_COND(particles->amount == 0);
@@ -4152,18 +4221,24 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) {
const Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND_V(!particles, AABB());
+ int total_amount = particles->amount;
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ total_amount *= particles->trail_bind_poses.size();
+ }
+
Vector<ParticleData> data;
- data.resize(particles->amount);
+ data.resize(total_amount);
Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(particles->particle_buffer);
- Transform inv = particles->emission_transform.affine_inverse();
+ Transform3D inv = particles->emission_transform.affine_inverse();
AABB aabb;
if (buffer.size()) {
bool first = true;
+
const ParticleData *particle_data = (const ParticleData *)data.ptr();
- for (int i = 0; i < particles->amount; i++) {
+ for (int i = 0; i < total_amount; i++) {
if (particle_data[i].active) {
Vector3 pos = Vector3(particle_data[i].xform[12], particle_data[i].xform[13], particle_data[i].xform[14]);
if (!particles->use_local_coords) {
@@ -4199,7 +4274,7 @@ AABB RendererStorageRD::particles_get_aabb(RID p_particles) const {
return particles->custom_aabb;
}
-void RendererStorageRD::particles_set_emission_transform(RID p_particles, const Transform &p_transform) {
+void RendererStorageRD::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
@@ -4224,17 +4299,24 @@ RID RendererStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass)
void RendererStorageRD::particles_add_collision(RID p_particles, RID p_particles_collision_instance) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
-
particles->collisions.insert(p_particles_collision_instance);
}
void RendererStorageRD::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
-
particles->collisions.erase(p_particles_collision_instance);
}
+void RendererStorageRD::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->has_sdf_collision = p_enable;
+ particles->sdf_collision_transform = p_xform;
+ particles->sdf_collision_to_screen = p_to_screen;
+ particles->sdf_collision_texture = p_texture;
+}
+
void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta) {
if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) {
Vector<RD::Uniform> uniforms;
@@ -4286,7 +4368,12 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
float new_phase = Math::fmod((float)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, (float)1.0);
- ParticlesFrameParams &frame_params = p_particles->frame_params;
+ //move back history (if there is any)
+ for (uint32_t i = p_particles->frame_history.size() - 1; i > 0; i--) {
+ p_particles->frame_history[i] = p_particles->frame_history[i - 1];
+ }
+ //update current frame
+ ParticlesFrameParams &frame_params = p_particles->frame_history[0];
if (p_particles->clear) {
p_particles->cycle_number = 0;
@@ -4311,12 +4398,16 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
frame_params.randomness = p_particles->randomness;
if (p_particles->use_local_coords) {
- store_transform(Transform(), frame_params.emission_transform);
+ store_transform(Transform3D(), frame_params.emission_transform);
} else {
store_transform(p_particles->emission_transform, frame_params.emission_transform);
}
frame_params.cycle = p_particles->cycle_number;
+ frame_params.frame = p_particles->frame_counter++;
+ frame_params.pad0 = 0;
+ frame_params.pad1 = 0;
+ frame_params.pad2 = 0;
{ //collision and attractors
@@ -4327,10 +4418,54 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
RID collision_3d_textures[ParticlesFrameParams::MAX_3D_TEXTURES];
RID collision_heightmap_texture;
- Transform to_particles;
+ Transform3D to_particles;
if (p_particles->use_local_coords) {
to_particles = p_particles->emission_transform.affine_inverse();
}
+
+ if (p_particles->has_sdf_collision && RD::get_singleton()->texture_is_valid(p_particles->sdf_collision_texture)) {
+ //2D collision
+
+ Transform2D xform = p_particles->sdf_collision_transform; //will use dotproduct manually so invert beforehand
+ Transform2D revert = xform.affine_inverse();
+ frame_params.collider_count = 1;
+ frame_params.colliders[0].transform[0] = xform.elements[0][0];
+ frame_params.colliders[0].transform[1] = xform.elements[0][1];
+ frame_params.colliders[0].transform[2] = 0;
+ frame_params.colliders[0].transform[3] = xform.elements[2][0];
+
+ frame_params.colliders[0].transform[4] = xform.elements[1][0];
+ frame_params.colliders[0].transform[5] = xform.elements[1][1];
+ frame_params.colliders[0].transform[6] = 0;
+ frame_params.colliders[0].transform[7] = xform.elements[2][1];
+
+ frame_params.colliders[0].transform[8] = revert.elements[0][0];
+ frame_params.colliders[0].transform[9] = revert.elements[0][1];
+ frame_params.colliders[0].transform[10] = 0;
+ frame_params.colliders[0].transform[11] = revert.elements[2][0];
+
+ frame_params.colliders[0].transform[12] = revert.elements[1][0];
+ frame_params.colliders[0].transform[13] = revert.elements[1][1];
+ frame_params.colliders[0].transform[14] = 0;
+ frame_params.colliders[0].transform[15] = revert.elements[2][1];
+
+ frame_params.colliders[0].extents[0] = p_particles->sdf_collision_to_screen.size.x;
+ frame_params.colliders[0].extents[1] = p_particles->sdf_collision_to_screen.size.y;
+ frame_params.colliders[0].extents[2] = p_particles->sdf_collision_to_screen.position.x;
+ frame_params.colliders[0].scale = p_particles->sdf_collision_to_screen.position.y;
+ frame_params.colliders[0].texture_index = 0;
+ frame_params.colliders[0].type = ParticlesFrameParams::COLLISION_TYPE_2D_SDF;
+
+ collision_heightmap_texture = p_particles->sdf_collision_texture;
+
+ //replace in all other history frames where used because parameters are no longer valid if screen moves
+ for (uint32_t i = 1; i < p_particles->frame_history.size(); i++) {
+ if (p_particles->frame_history[i].collider_count > 0 && p_particles->frame_history[i].colliders[0].type == ParticlesFrameParams::COLLISION_TYPE_2D_SDF) {
+ p_particles->frame_history[i].colliders[0] = frame_params.colliders[0];
+ }
+ }
+ }
+
uint32_t collision_3d_textures_used = 0;
for (const Set<RID>::Element *E = p_particles->collisions.front(); E; E = E->next()) {
ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(E->get());
@@ -4340,7 +4475,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
ParticlesCollision *pc = particles_collision_owner.getornull(pci->collision);
ERR_CONTINUE(!pc);
- Transform to_collider = pci->transform;
+ Transform3D to_collider = pci->transform;
if (p_particles->use_local_coords) {
to_collider = to_particles * to_collider;
}
@@ -4515,12 +4650,18 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
ParticlesShader::PushConstant push_constant;
+ int process_amount = p_particles->amount;
+
+ if (p_particles->trails_enabled && p_particles->trail_bind_poses.size() > 1) {
+ process_amount *= p_particles->trail_bind_poses.size();
+ }
push_constant.clear = p_particles->clear;
push_constant.total_particles = p_particles->amount;
push_constant.lifetime = p_particles->lifetime;
- push_constant.trail_size = 1;
+ push_constant.trail_size = p_particles->trail_params.size();
push_constant.use_fractional_delta = p_particles->fractional_delta;
push_constant.sub_emitter_mode = !p_particles->emitting && p_particles->emission_buffer && (p_particles->emission_buffer->particle_count > 0 || p_particles->force_sub_emit);
+ push_constant.trail_pass = false;
p_particles->force_sub_emit = false; //reset
@@ -4553,7 +4694,17 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
p_particles->clear = false;
- RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams), &frame_params);
+ if (p_particles->trail_params.size() > 1) {
+ //fill the trail params
+ for (uint32_t i = 0; i < p_particles->trail_params.size(); i++) {
+ uint32_t src_idx = i * p_particles->frame_history.size() / p_particles->trail_params.size();
+ p_particles->trail_params[i] = p_particles->frame_history[src_idx];
+ }
+ } else {
+ p_particles->trail_params[0] = p_particles->frame_history[0];
+ }
+
+ RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams) * p_particles->trail_params.size(), p_particles->trail_params.ptr());
ParticlesMaterialData *m = (ParticlesMaterialData *)material_get_data(p_particles->process_material, SHADER_TYPE_PARTICLES);
if (!m) {
@@ -4562,6 +4713,8 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
ERR_FAIL_COND(!m);
+ p_particles->has_collision_cache = m->shader_data->uses_collision;
+
//todo should maybe compute all particle systems together?
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, m->shader_data->pipeline);
@@ -4575,27 +4728,45 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_particles->amount, 1, 1);
+ if (p_particles->trails_enabled && p_particles->trail_bind_poses.size() > 1) {
+ //trails requires two passes in order to catch particle starts
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, process_amount / p_particles->trail_bind_poses.size(), 1, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ push_constant.trail_pass = true;
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant));
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, process_amount - p_particles->amount, 1, 1);
+ } else {
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, process_amount, 1, 1);
+ }
RD::get_singleton()->compute_list_end();
}
-void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis) {
+void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
- if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH) {
- return; //uninteresting for other modes
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
+ return;
+ }
+
+ if (particles->particle_buffer.is_null()) {
+ return; //particles have not processed yet
}
+ bool do_sort = particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH;
+
//copy to sort buffer
- if (particles->particles_sort_buffer == RID()) {
+ if (do_sort && particles->particles_sort_buffer == RID()) {
uint32_t size = particles->amount;
if (size & 1) {
size++; //make multiple of 16
}
size *= sizeof(float) * 2;
particles->particles_sort_buffer = RD::get_singleton()->storage_buffer_create(size);
+
{
Vector<RD::Uniform> uniforms;
@@ -4611,41 +4782,114 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &
}
}
+ ParticlesShader::CopyPushConstant copy_push_constant;
+
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ int fixed_fps = 60.0;
+ if (particles->fixed_fps > 0) {
+ fixed_fps = particles->fixed_fps;
+ }
+
+ copy_push_constant.trail_size = particles->trail_bind_poses.size();
+ copy_push_constant.trail_total = particles->frame_history.size();
+ copy_push_constant.frame_delta = 1.0 / fixed_fps;
+ } else {
+ copy_push_constant.trail_size = 1;
+ copy_push_constant.trail_total = 1;
+ copy_push_constant.frame_delta = 0.0;
+ }
+
+ copy_push_constant.order_by_lifetime = (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME);
+ copy_push_constant.lifetime_split = MIN(particles->amount * particles->phase, particles->amount - 1);
+ copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME;
+
+ copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0;
+ copy_push_constant.total_particles = particles->amount;
+
Vector3 axis = -p_axis; // cameras look to z negative
if (particles->use_local_coords) {
axis = particles->emission_transform.basis.xform_inv(axis).normalized();
}
- ParticlesShader::CopyPushConstant copy_push_constant;
- copy_push_constant.total_particles = particles->amount;
copy_push_constant.sort_direction[0] = axis.x;
copy_push_constant.sort_direction[1] = axis.y;
copy_push_constant.sort_direction[2] = axis.z;
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
+ copy_push_constant.align_up[0] = p_up_axis.x;
+ copy_push_constant.align_up[1] = p_up_axis.y;
+ copy_push_constant.align_up[2] = p_up_axis.z;
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
+ copy_push_constant.align_mode = particles->transform_align;
- RD::get_singleton()->compute_list_end();
+ if (do_sort) {
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
+
+ RD::get_singleton()->compute_list_end();
+ effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount);
+ }
- effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount);
+ copy_push_constant.total_particles *= copy_push_constant.total_particles;
- compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER]);
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[do_sort ? ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER : (particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES)]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
+ if (do_sort) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
+ }
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2);
+
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, copy_push_constant.total_particles, 1, 1);
RD::get_singleton()->compute_list_end();
}
+void RendererStorageRD::_particles_update_buffers(Particles *particles) {
+ if (particles->amount > 0 && particles->particle_buffer.is_null()) {
+ int total_amount = particles->amount;
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ total_amount *= particles->trail_bind_poses.size();
+ }
+
+ uint32_t xform_size = particles->mode == RS::PARTICLES_MODE_2D ? 2 : 3;
+
+ particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * total_amount);
+
+ particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (xform_size + 1 + 1) * total_amount);
+ //needs to clear it
+
+ {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(particles->particle_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(particles->particle_instance_buffer);
+ uniforms.push_back(u);
+ }
+
+ particles->particles_copy_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 0);
+ }
+ }
+}
void RendererStorageRD::update_particles() {
while (particle_update_list) {
//use transform feedback to process particles
@@ -4657,6 +4901,8 @@ void RendererStorageRD::update_particles() {
particles->update_list = nullptr;
particles->dirty = false;
+ _particles_update_buffers(particles);
+
if (particles->restart_request) {
particles->prev_ticks = 0;
particles->phase = 0;
@@ -4688,12 +4934,81 @@ void RendererStorageRD::update_particles() {
}
}
+#ifndef _MSC_VER
+#warning Should use display refresh rate for all this
+#endif
+
+ float screen_hz = 60;
+
+ int fixed_fps = 0;
+ if (particles->fixed_fps > 0) {
+ fixed_fps = particles->fixed_fps;
+ } else if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ fixed_fps = screen_hz;
+ }
+ {
+ //update trails
+ int history_size = 1;
+ int trail_steps = 1;
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ history_size = MAX(1, int(particles->trail_length * fixed_fps));
+ trail_steps = particles->trail_bind_poses.size();
+ }
+
+ if (uint32_t(history_size) != particles->frame_history.size()) {
+ particles->frame_history.resize(history_size);
+ memset(particles->frame_history.ptr(), 0, sizeof(ParticlesFrameParams) * history_size);
+ }
+
+ if (uint32_t(trail_steps) != particles->trail_params.size() || particles->frame_params_buffer.is_null()) {
+ particles->trail_params.resize(trail_steps);
+ if (particles->frame_params_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->frame_params_buffer);
+ }
+ particles->frame_params_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticlesFrameParams) * trail_steps);
+ }
+
+ if (particles->trail_bind_poses.size() > 1 && particles->trail_bind_pose_buffer.is_null()) {
+ particles->trail_bind_pose_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 16 * particles->trail_bind_poses.size());
+ particles->trail_bind_poses_dirty = true;
+ }
+
+ if (particles->trail_bind_pose_uniform_set.is_null()) {
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ if (particles->trail_bind_pose_buffer.is_valid()) {
+ u.ids.push_back(particles->trail_bind_pose_buffer);
+ } else {
+ u.ids.push_back(default_rd_storage_buffer);
+ }
+ uniforms.push_back(u);
+ }
+
+ particles->trail_bind_pose_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 2);
+ }
+
+ if (particles->trail_bind_pose_buffer.is_valid() && particles->trail_bind_poses_dirty) {
+ if (particles_shader.pose_update_buffer.size() < uint32_t(particles->trail_bind_poses.size()) * 16) {
+ particles_shader.pose_update_buffer.resize(particles->trail_bind_poses.size() * 16);
+ }
+
+ for (int i = 0; i < particles->trail_bind_poses.size(); i++) {
+ store_transform(particles->trail_bind_poses[i], &particles_shader.pose_update_buffer[i * 16]);
+ }
+
+ RD::get_singleton()->buffer_update(particles->trail_bind_pose_buffer, 0, particles->trail_bind_poses.size() * 16 * sizeof(float), particles_shader.pose_update_buffer.ptr());
+ }
+ }
+
bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0;
if (particles->clear && particles->pre_process_time > 0.0) {
float frame_time;
- if (particles->fixed_fps > 0) {
- frame_time = 1.0 / particles->fixed_fps;
+ if (fixed_fps > 0) {
+ frame_time = 1.0 / fixed_fps;
} else {
frame_time = 1.0 / 30.0;
}
@@ -4706,14 +5021,14 @@ void RendererStorageRD::update_particles() {
}
}
- if (particles->fixed_fps > 0) {
+ if (fixed_fps > 0) {
float frame_time;
float decr;
if (zero_time_scale) {
frame_time = 0.0;
- decr = 1.0 / particles->fixed_fps;
+ decr = 1.0 / fixed_fps;
} else {
- frame_time = 1.0 / particles->fixed_fps;
+ frame_time = 1.0 / fixed_fps;
decr = frame_time;
}
float delta = RendererCompositorRD::singleton->get_frame_delta_time();
@@ -4741,16 +5056,43 @@ void RendererStorageRD::update_particles() {
//copy particles to instance buffer
- if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH) {
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
+ //does not need view dependent operation, do copy here
ParticlesShader::CopyPushConstant copy_push_constant;
- copy_push_constant.total_particles = particles->amount;
+
+ int total_amount = particles->amount;
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ total_amount *= particles->trail_bind_poses.size();
+ }
+
+ copy_push_constant.total_particles = total_amount;
+ copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0;
+ copy_push_constant.align_mode = particles->transform_align;
+ copy_push_constant.align_up[0] = 0;
+ copy_push_constant.align_up[1] = 0;
+ copy_push_constant.align_up[2] = 0;
+
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ copy_push_constant.trail_size = particles->trail_bind_poses.size();
+ copy_push_constant.trail_total = particles->frame_history.size();
+ copy_push_constant.frame_delta = 1.0 / fixed_fps;
+ } else {
+ copy_push_constant.trail_size = 1;
+ copy_push_constant.trail_total = 1;
+ copy_push_constant.frame_delta = 0.0;
+ }
+
+ copy_push_constant.order_by_lifetime = (particles->draw_order == RS::PARTICLES_DRAW_ORDER_LIFETIME || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME);
+ copy_push_constant.lifetime_split = MIN(particles->amount * particles->phase, particles->amount - 1);
+ copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES]);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, total_amount, 1, 1);
RD::get_singleton()->compute_list_end();
}
@@ -4774,6 +5116,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
valid = false;
ubo_size = 0;
uniforms.clear();
+ uses_collision = false;
if (code == String()) {
return; //just invalid, but no error
@@ -4793,6 +5136,8 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
actions.usage_flag_pointers["TIME"] = &uses_time;
*/
+ actions.usage_flag_pointers["COLLIDED"] = &uses_collision;
+
actions.uniforms = &uniforms;
Error err = base_singleton->particles_shader.compiler.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code);
@@ -5179,7 +5524,7 @@ RID RendererStorageRD::particles_collision_instance_create(RID p_collision) {
pci.collision = p_collision;
return particles_collision_instance_owner.make_rid(pci);
}
-void RendererStorageRD::particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) {
+void RendererStorageRD::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) {
ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance);
ERR_FAIL_COND(!pci);
pci->transform = p_transform;
@@ -5190,6 +5535,59 @@ void RendererStorageRD::particles_collision_instance_set_active(RID p_collision_
pci->active = p_active;
}
+/* VISIBILITY NOTIFIER */
+
+RID RendererStorageRD::visibility_notifier_allocate() {
+ return visibility_notifier_owner.allocate_rid();
+}
+void RendererStorageRD::visibility_notifier_initialize(RID p_notifier) {
+ visibility_notifier_owner.initialize_rid(p_notifier, VisibilityNotifier());
+}
+void RendererStorageRD::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) {
+ VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier);
+ ERR_FAIL_COND(!vn);
+ vn->aabb = p_aabb;
+ vn->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
+}
+void RendererStorageRD::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) {
+ VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier);
+ ERR_FAIL_COND(!vn);
+ vn->enter_callback = p_enter_callbable;
+ vn->exit_callback = p_exit_callable;
+}
+
+AABB RendererStorageRD::visibility_notifier_get_aabb(RID p_notifier) const {
+ const VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier);
+ ERR_FAIL_COND_V(!vn, AABB());
+ return vn->aabb;
+}
+void RendererStorageRD::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) {
+ VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier);
+ ERR_FAIL_COND(!vn);
+
+ if (p_enter) {
+ if (!vn->enter_callback.is_null()) {
+ if (p_deferred) {
+ vn->enter_callback.call_deferred(nullptr, 0);
+ } else {
+ Variant r;
+ Callable::CallError ce;
+ vn->enter_callback.call(nullptr, 0, r, ce);
+ }
+ }
+ } else {
+ if (!vn->exit_callback.is_null()) {
+ if (p_deferred) {
+ vn->exit_callback.call_deferred(nullptr, 0);
+ } else {
+ Variant r;
+ Callable::CallError ce;
+ vn->exit_callback.call(nullptr, 0, r, ce);
+ }
+ }
+ }
+}
+
/* SKELETON API */
RID RendererStorageRD::skeleton_allocate() {
@@ -5230,7 +5628,7 @@ void RendererStorageRD::skeleton_allocate_data(RID p_skeleton, int p_bones, bool
if (skeleton->size) {
skeleton->data.resize(skeleton->size * (skeleton->use_2d ? 8 : 12));
skeleton->buffer = RD::get_singleton()->storage_buffer_create(skeleton->data.size() * sizeof(float));
- zeromem(skeleton->data.ptrw(), skeleton->data.size() * sizeof(float));
+ memset(skeleton->data.ptrw(), 0, skeleton->data.size() * sizeof(float));
_skeleton_make_dirty(skeleton);
@@ -5257,7 +5655,7 @@ int RendererStorageRD::skeleton_get_bone_count(RID p_skeleton) const {
return skeleton->size;
}
-void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) {
+void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) {
Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
ERR_FAIL_COND(!skeleton);
@@ -5282,16 +5680,16 @@ void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone,
_skeleton_make_dirty(skeleton);
}
-Transform RendererStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
+Transform3D RendererStorageRD::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());
+ ERR_FAIL_COND_V(!skeleton, Transform3D());
+ ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform3D());
+ ERR_FAIL_COND_V(skeleton->use_2d, Transform3D());
const float *dataptr = skeleton->data.ptr() + p_bone * 12;
- Transform t;
+ Transform3D t;
t.basis.elements[0][0] = dataptr[0];
t.basis.elements[0][1] = dataptr[1];
@@ -5981,36 +6379,36 @@ AABB RendererStorageRD::decal_get_aabb(RID p_decal) const {
return AABB(-decal->extents, decal->extents * 2.0);
}
-RID RendererStorageRD::gi_probe_allocate() {
- return gi_probe_owner.allocate_rid();
+RID RendererStorageRD::voxel_gi_allocate() {
+ return voxel_gi_owner.allocate_rid();
}
-void RendererStorageRD::gi_probe_initialize(RID p_gi_probe) {
- gi_probe_owner.initialize_rid(p_gi_probe, GIProbe());
+void RendererStorageRD::voxel_gi_initialize(RID p_voxel_gi) {
+ voxel_gi_owner.initialize_rid(p_voxel_gi, VoxelGI());
}
-void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
+void RendererStorageRD::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &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) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- 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);
+ if (voxel_gi->octree_buffer.is_valid()) {
+ RD::get_singleton()->free(voxel_gi->octree_buffer);
+ RD::get_singleton()->free(voxel_gi->data_buffer);
+ if (voxel_gi->sdf_texture.is_valid()) {
+ RD::get_singleton()->free(voxel_gi->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;
+ voxel_gi->sdf_texture = RID();
+ voxel_gi->octree_buffer = RID();
+ voxel_gi->data_buffer = RID();
+ voxel_gi->octree_buffer_size = 0;
+ voxel_gi->data_buffer_size = 0;
+ voxel_gi->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;
+ voxel_gi->to_cell_xform = p_to_cell_xform;
+ voxel_gi->bounds = p_aabb;
+ voxel_gi->octree_size = p_octree_size;
+ voxel_gi->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
@@ -6019,42 +6417,42 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &
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();
+ voxel_gi->cell_count = cell_count;
+ voxel_gi->octree_buffer = RD::get_singleton()->storage_buffer_create(p_octree_cells.size(), p_octree_cells);
+ voxel_gi->octree_buffer_size = p_octree_cells.size();
+ voxel_gi->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells);
+ voxel_gi->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.width = voxel_gi->octree_size.x;
+ tf.height = voxel_gi->octree_size.y;
+ tf.depth = voxel_gi->octree_size.z;
tf.texture_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);
+ voxel_gi->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.width = voxel_gi->octree_size.x;
+ tf.height = voxel_gi->octree_size.y;
+ tf.depth = voxel_gi->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());
+ voxel_gi->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);
+ shared_tex = RD::get_singleton()->texture_create_shared(tv, voxel_gi->sdf_texture);
}
//update SDF texture
Vector<RD::Uniform> uniforms;
@@ -6062,14 +6460,14 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 1;
- u.ids.push_back(gi_probe->octree_buffer);
+ u.ids.push_back(voxel_gi->octree_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 2;
- u.ids.push_back(gi_probe->data_buffer);
+ u.ids.push_back(voxel_gi->data_buffer);
uniforms.push_back(u);
}
{
@@ -6080,24 +6478,24 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &
uniforms.push_back(u);
}
- RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_sdf_shader_version_shader, 0);
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, voxel_gi_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];
+ for (int i = 0; i < voxel_gi->level_counts.size() - 1; i++) {
+ push_constant[0] += voxel_gi->level_counts[i];
}
- push_constant[1] = push_constant[0] + gi_probe->level_counts[gi_probe->level_counts.size() - 1];
+ push_constant[1] = push_constant[0] + voxel_gi->level_counts[voxel_gi->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_compute_pipeline(compute_list, voxel_gi_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_dispatch(compute_list, voxel_gi->octree_size.x / 4, voxel_gi->octree_size.y / 4, voxel_gi->octree_size.z / 4);
RD::get_singleton()->compute_list_end();
}
@@ -6107,232 +6505,232 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &
#endif
}
- gi_probe->version++;
- gi_probe->data_version++;
+ voxel_gi->version++;
+ voxel_gi->data_version++;
- gi_probe->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
+ voxel_gi->dependency.changed_notify(DEPENDENCY_CHANGED_AABB);
}
-AABB RendererStorageRD::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());
+AABB RendererStorageRD::voxel_gi_get_bounds(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, AABB());
- return gi_probe->bounds;
+ return voxel_gi->bounds;
}
-Vector3i RendererStorageRD::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;
+Vector3i RendererStorageRD::voxel_gi_get_octree_size(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Vector3i());
+ return voxel_gi->octree_size;
}
-Vector<uint8_t> RendererStorageRD::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>());
+Vector<uint8_t> RendererStorageRD::voxel_gi_get_octree_cells(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>());
- if (gi_probe->octree_buffer.is_valid()) {
- return RD::get_singleton()->buffer_get_data(gi_probe->octree_buffer);
+ if (voxel_gi->octree_buffer.is_valid()) {
+ return RD::get_singleton()->buffer_get_data(voxel_gi->octree_buffer);
}
return Vector<uint8_t>();
}
-Vector<uint8_t> RendererStorageRD::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>());
+Vector<uint8_t> RendererStorageRD::voxel_gi_get_data_cells(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>());
- if (gi_probe->data_buffer.is_valid()) {
- return RD::get_singleton()->buffer_get_data(gi_probe->data_buffer);
+ if (voxel_gi->data_buffer.is_valid()) {
+ return RD::get_singleton()->buffer_get_data(voxel_gi->data_buffer);
}
return Vector<uint8_t>();
}
-Vector<uint8_t> RendererStorageRD::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>());
+Vector<uint8_t> RendererStorageRD::voxel_gi_get_distance_field(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>());
- if (gi_probe->data_buffer.is_valid()) {
- return RD::get_singleton()->texture_get_data(gi_probe->sdf_texture, 0);
+ if (voxel_gi->data_buffer.is_valid()) {
+ return RD::get_singleton()->texture_get_data(voxel_gi->sdf_texture, 0);
}
return Vector<uint8_t>();
}
-Vector<int> RendererStorageRD::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>());
+Vector<int> RendererStorageRD::voxel_gi_get_level_counts(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Vector<int>());
- return gi_probe->level_counts;
+ return voxel_gi->level_counts;
}
-Transform RendererStorageRD::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());
+Transform3D RendererStorageRD::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, Transform3D());
- return gi_probe->to_cell_xform;
+ return voxel_gi->to_cell_xform;
}
-void RendererStorageRD::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);
+void RendererStorageRD::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->dynamic_range = p_range;
- gi_probe->version++;
+ voxel_gi->dynamic_range = p_range;
+ voxel_gi->version++;
}
-float RendererStorageRD::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);
+float RendererStorageRD::voxel_gi_get_dynamic_range(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
- return gi_probe->dynamic_range;
+ return voxel_gi->dynamic_range;
}
-void RendererStorageRD::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);
+void RendererStorageRD::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->propagation = p_range;
- gi_probe->version++;
+ voxel_gi->propagation = p_range;
+ voxel_gi->version++;
}
-float RendererStorageRD::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;
+float RendererStorageRD::voxel_gi_get_propagation(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->propagation;
}
-void RendererStorageRD::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);
+void RendererStorageRD::voxel_gi_set_energy(RID p_voxel_gi, float p_energy) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->energy = p_energy;
+ voxel_gi->energy = p_energy;
}
-float RendererStorageRD::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;
+float RendererStorageRD::voxel_gi_get_energy(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->energy;
}
-void RendererStorageRD::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);
+void RendererStorageRD::voxel_gi_set_ao(RID p_voxel_gi, float p_ao) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->ao = p_ao;
+ voxel_gi->ao = p_ao;
}
-float RendererStorageRD::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;
+float RendererStorageRD::voxel_gi_get_ao(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->ao;
}
-void RendererStorageRD::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);
+void RendererStorageRD::voxel_gi_set_ao_size(RID p_voxel_gi, float p_strength) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->ao_size = p_strength;
+ voxel_gi->ao_size = p_strength;
}
-float RendererStorageRD::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;
+float RendererStorageRD::voxel_gi_get_ao_size(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->ao_size;
}
-void RendererStorageRD::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);
+void RendererStorageRD::voxel_gi_set_bias(RID p_voxel_gi, float p_bias) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->bias = p_bias;
+ voxel_gi->bias = p_bias;
}
-float RendererStorageRD::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;
+float RendererStorageRD::voxel_gi_get_bias(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->bias;
}
-void RendererStorageRD::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);
+void RendererStorageRD::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_normal_bias) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->normal_bias = p_normal_bias;
+ voxel_gi->normal_bias = p_normal_bias;
}
-float RendererStorageRD::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;
+float RendererStorageRD::voxel_gi_get_normal_bias(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->normal_bias;
}
-void RendererStorageRD::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);
+void RendererStorageRD::voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->anisotropy_strength = p_strength;
+ voxel_gi->anisotropy_strength = p_strength;
}
-float RendererStorageRD::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;
+float RendererStorageRD::voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->anisotropy_strength;
}
-void RendererStorageRD::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);
+void RendererStorageRD::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->interior = p_enable;
+ voxel_gi->interior = p_enable;
}
-void RendererStorageRD::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);
+void RendererStorageRD::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND(!voxel_gi);
- gi_probe->use_two_bounces = p_enable;
- gi_probe->version++;
+ voxel_gi->use_two_bounces = p_enable;
+ voxel_gi->version++;
}
-bool RendererStorageRD::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 RendererStorageRD::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, false);
+ return voxel_gi->use_two_bounces;
}
-bool RendererStorageRD::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;
+bool RendererStorageRD::voxel_gi_is_interior(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->interior;
}
-uint32_t RendererStorageRD::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 RendererStorageRD::voxel_gi_get_version(RID p_voxel_gi) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->version;
}
-uint32_t RendererStorageRD::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;
+uint32_t RendererStorageRD::voxel_gi_get_data_version(RID p_voxel_gi) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, 0);
+ return voxel_gi->data_version;
}
-RID RendererStorageRD::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 RendererStorageRD::voxel_gi_get_octree_buffer(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, RID());
+ return voxel_gi->octree_buffer;
}
-RID RendererStorageRD::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 RendererStorageRD::voxel_gi_get_data_buffer(RID p_voxel_gi) const {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, RID());
+ return voxel_gi->data_buffer;
}
-RID RendererStorageRD::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());
+RID RendererStorageRD::voxel_gi_get_sdf_texture(RID p_voxel_gi) {
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi);
+ ERR_FAIL_COND_V(!voxel_gi, RID());
- return gi_probe->sdf_texture;
+ return voxel_gi->sdf_texture;
}
/* LIGHTMAP API */
@@ -6568,9 +6966,13 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) {
rd_format.width = rt->size.width;
rd_format.height = rt->size.height;
rd_format.depth = 1;
- rd_format.array_layers = 1;
+ rd_format.array_layers = rt->view_count; // for stereo we create two (or more) layers, need to see if we can make fallback work like this too if we don't have multiview
rd_format.mipmaps = 1;
- rd_format.texture_type = RD::TEXTURE_TYPE_2D;
+ if (rd_format.array_layers > 1) { // why are we not using rt->texture_type ??
+ rd_format.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ } else {
+ rd_format.texture_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);
@@ -6582,7 +6984,7 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) {
Vector<RID> fb_textures;
fb_textures.push_back(rt->color);
- rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures);
+ rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures, RenderingDevice::INVALID_ID, rt->view_count);
if (rt->framebuffer.is_null()) {
_clear_render_target(rt);
ERR_FAIL_COND(rt->framebuffer.is_null());
@@ -6696,12 +7098,15 @@ void RendererStorageRD::render_target_set_position(RID p_render_target, int p_x,
//unused for this render target
}
-void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) {
+void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) {
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);
+ if (rt->size.x != p_width || rt->size.y != p_height || rt->view_count != p_view_count) {
+ rt->size.x = p_width;
+ rt->size.y = p_height;
+ rt->view_count = p_view_count;
+ _update_render_target(rt);
+ }
}
RID RendererStorageRD::render_target_get_texture(RID p_render_target) {
@@ -6858,6 +7263,20 @@ Rect2i RendererStorageRD::render_target_get_sdf_rect(RID p_render_target) const
return _render_target_get_sdf_rect(rt);
}
+void RendererStorageRD::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ rt->sdf_enabled = p_enabled;
+}
+
+bool RendererStorageRD::render_target_is_sdf_enabled(RID p_render_target) const {
+ const RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+
+ return rt->sdf_enabled;
+}
+
RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
@@ -6872,7 +7291,7 @@ RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) {
Vector<uint8_t> pv;
pv.resize(16 * 4);
- zeromem(pv.ptrw(), 16 * 4);
+ memset(pv.ptrw(), 0, 16 * 4);
Vector<Vector<uint8_t>> vpv;
rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
@@ -6925,7 +7344,7 @@ void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) {
rt->process_size.x = MAX(rt->process_size.x, 1);
rt->process_size.y = MAX(rt->process_size.y, 1);
- tformat.format = RD::DATA_FORMAT_R16G16_UINT;
+ tformat.format = RD::DATA_FORMAT_R16G16_SINT;
tformat.width = rt->process_size.width;
tformat.height = rt->process_size.height;
tformat.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
@@ -6933,7 +7352,7 @@ void RendererStorageRD::_render_target_allocate_sdf(RenderTarget *rt) {
rt->sdf_buffer_process[0] = RD::get_singleton()->texture_create(tformat, RD::TextureView());
rt->sdf_buffer_process[1] = RD::get_singleton()->texture_create(tformat, RD::TextureView());
- tformat.format = RD::DATA_FORMAT_R16_UNORM;
+ tformat.format = RD::DATA_FORMAT_R16_SNORM;
tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
rt->sdf_buffer_read = RD::get_singleton()->texture_create(tformat, RD::TextureView());
@@ -7209,8 +7628,8 @@ void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_
} else if (decal_owner.owns(p_base)) {
Decal *decal = decal_owner.getornull(p_base);
p_instance->update_dependency(&decal->dependency);
- } else if (gi_probe_owner.owns(p_base)) {
- GIProbe *gip = gi_probe_owner.getornull(p_base);
+ } else if (voxel_gi_owner.owns(p_base)) {
+ VoxelGI *gip = voxel_gi_owner.getornull(p_base);
p_instance->update_dependency(&gip->dependency);
} else if (lightmap_owner.owns(p_base)) {
Lightmap *lm = lightmap_owner.getornull(p_base);
@@ -7224,6 +7643,9 @@ void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_
} else if (particles_collision_owner.owns(p_base)) {
ParticlesCollision *pc = particles_collision_owner.getornull(p_base);
p_instance->update_dependency(&pc->dependency);
+ } else if (visibility_notifier_owner.owns(p_base)) {
+ VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_base);
+ p_instance->update_dependency(&vn->dependency);
}
}
@@ -7247,8 +7669,8 @@ RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const {
if (decal_owner.owns(p_rid)) {
return RS::INSTANCE_DECAL;
}
- if (gi_probe_owner.owns(p_rid)) {
- return RS::INSTANCE_GI_PROBE;
+ if (voxel_gi_owner.owns(p_rid)) {
+ return RS::INSTANCE_VOXEL_GI;
}
if (light_owner.owns(p_rid)) {
return RS::INSTANCE_LIGHT;
@@ -7262,6 +7684,9 @@ RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const {
if (particles_collision_owner.owns(p_rid)) {
return RS::INSTANCE_PARTICLES_COLLISION;
}
+ if (visibility_notifier_owner.owns(p_rid)) {
+ return RS::INSTANCE_VISIBLITY_NOTIFIER;
+ }
return RS::INSTANCE_NONE;
}
@@ -7359,7 +7784,7 @@ void RendererStorageRD::_update_decal_atlas() {
v_offsetsv.resize(base_size);
int *v_offsets = v_offsetsv.ptrw();
- zeromem(v_offsets, sizeof(int) * base_size);
+ memset(v_offsets, 0, sizeof(int) * base_size);
int max_height = 0;
@@ -7772,7 +8197,7 @@ void RendererStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS::Gl
} break;
case RS::GLOBAL_VAR_TYPE_TRANSFORM: {
GlobalVariables::Value *bv = &global_variables.buffer_values[p_index];
- Transform v = p_value;
+ Transform3D v = p_value;
bv[0].x = v.basis.elements[0][0];
bv[0].y = v.basis.elements[1][0];
bv[0].z = v.basis.elements[2][0];
@@ -7923,7 +8348,6 @@ void RendererStorageRD::global_variable_set_override(const StringName &p_name, c
_global_variable_mark_buffer_dirty(gv.buffer_index, gv.buffer_elements);
} else {
//texture
- //texture
for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) {
Material *material = material_owner.getornull(E->get());
ERR_CONTINUE(!material);
@@ -8116,7 +8540,7 @@ void RendererStorageRD::_update_global_variables() {
if (total_regions / global_variables.buffer_dirty_region_count <= 4) {
// 25% of regions dirty, just update all buffer
RD::get_singleton()->buffer_update(global_variables.buffer, 0, sizeof(GlobalVariables::Value) * global_variables.buffer_size, global_variables.buffer_values);
- zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * total_regions);
+ memset(global_variables.buffer_dirty_regions, 0, sizeof(bool) * total_regions);
} else {
uint32_t region_byte_size = sizeof(GlobalVariables::Value) * GlobalVariables::BUFFER_DIRTY_REGION_SIZE;
@@ -8196,6 +8620,7 @@ bool RendererStorageRD::free(RID p_rid) {
if (texture_owner.owns(p_rid)) {
Texture *t = texture_owner.getornull(p_rid);
+ ERR_FAIL_COND_V(!t, false);
ERR_FAIL_COND_V(t->is_render_target, false);
if (RD::get_singleton()->texture_is_valid(t->rd_texture_srgb)) {
@@ -8306,11 +8731,11 @@ bool RendererStorageRD::free(RID p_rid) {
}
decal->dependency.deleted_notify(p_rid);
decal_owner.free(p_rid);
- } else if (gi_probe_owner.owns(p_rid)) {
- gi_probe_allocate_data(p_rid, Transform(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate
- GIProbe *gi_probe = gi_probe_owner.getornull(p_rid);
- gi_probe->dependency.deleted_notify(p_rid);
- gi_probe_owner.free(p_rid);
+ } else if (voxel_gi_owner.owns(p_rid)) {
+ voxel_gi_allocate_data(p_rid, Transform3D(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate
+ VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_rid);
+ voxel_gi->dependency.deleted_notify(p_rid);
+ voxel_gi_owner.free(p_rid);
} else if (lightmap_owner.owns(p_rid)) {
lightmap_set_textures(p_rid, RID(), false);
Lightmap *lightmap = lightmap_owner.getornull(p_rid);
@@ -8325,9 +8750,10 @@ bool RendererStorageRD::free(RID p_rid) {
light_owner.free(p_rid);
} else if (particles_owner.owns(p_rid)) {
+ update_particles();
Particles *particles = particles_owner.getornull(p_rid);
- _particles_free_data(particles);
particles->dependency.deleted_notify(p_rid);
+ _particles_free_data(particles);
particles_owner.free(p_rid);
} else if (particles_collision_owner.owns(p_rid)) {
ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_rid);
@@ -8337,6 +8763,10 @@ bool RendererStorageRD::free(RID p_rid) {
}
particles_collision->dependency.deleted_notify(p_rid);
particles_collision_owner.free(p_rid);
+ } else if (visibility_notifier_owner.owns(p_rid)) {
+ VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_rid);
+ vn->dependency.deleted_notify(p_rid);
+ visibility_notifier_owner.free(p_rid);
} else if (particles_collision_instance_owner.owns(p_rid)) {
particles_collision_instance_owner.free(p_rid);
} else if (render_target_owner.owns(p_rid)) {
@@ -8404,10 +8834,10 @@ RendererStorageRD::RendererStorageRD() {
global_variables.buffer_size = GLOBAL_GET("rendering/limits/global_shader_variables/buffer_size");
global_variables.buffer_size = MAX(4096, global_variables.buffer_size);
global_variables.buffer_values = memnew_arr(GlobalVariables::Value, global_variables.buffer_size);
- zeromem(global_variables.buffer_values, sizeof(GlobalVariables::Value) * global_variables.buffer_size);
+ memset(global_variables.buffer_values, 0, sizeof(GlobalVariables::Value) * global_variables.buffer_size);
global_variables.buffer_usage = memnew_arr(GlobalVariables::ValueUsage, global_variables.buffer_size);
global_variables.buffer_dirty_regions = memnew_arr(bool, global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
- zeromem(global_variables.buffer_dirty_regions, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
+ memset(global_variables.buffer_dirty_regions, 0, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE);
global_variables.buffer = RD::get_singleton()->storage_buffer_create(sizeof(GlobalVariables::Value) * global_variables.buffer_size);
material_update_list = nullptr;
@@ -8824,10 +9254,10 @@ RendererStorageRD::RendererStorageRD() {
{
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_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);
+ voxel_gi_sdf_shader.initialize(sdf_versions);
+ voxel_gi_sdf_shader_version = voxel_gi_sdf_shader.version_create();
+ voxel_gi_sdf_shader_version_shader = voxel_gi_sdf_shader.version_get_shader(voxel_gi_sdf_shader_version, 0);
+ voxel_gi_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(voxel_gi_sdf_shader_version_shader);
}
using_lightmap_array = true; // high end
@@ -8864,14 +9294,17 @@ RendererStorageRD::RendererStorageRD() {
actions.renames["COLOR"] = "PARTICLE.color";
actions.renames["VELOCITY"] = "PARTICLE.velocity";
//actions.renames["MASS"] = "mass"; ?
- actions.renames["ACTIVE"] = "PARTICLE.is_active";
+ actions.renames["ACTIVE"] = "particle_active";
actions.renames["RESTART"] = "restart";
actions.renames["CUSTOM"] = "PARTICLE.custom";
actions.renames["TRANSFORM"] = "PARTICLE.xform";
actions.renames["TIME"] = "FRAME.time";
+ actions.renames["PI"] = _MKSTR(Math_PI);
+ actions.renames["TAU"] = _MKSTR(Math_TAU);
+ actions.renames["E"] = _MKSTR(Math_E);
actions.renames["LIFETIME"] = "params.lifetime";
actions.renames["DELTA"] = "local_delta";
- actions.renames["NUMBER"] = "particle";
+ actions.renames["NUMBER"] = "particle_number";
actions.renames["INDEX"] = "index";
//actions.renames["GRAVITY"] = "current_gravity";
actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform";
@@ -8961,6 +9394,7 @@ RendererStorageRD::RendererStorageRD() {
{
Vector<String> copy_modes;
copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n");
+ copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define MODE_2D\n");
copy_modes.push_back("\n#define MODE_FILL_SORT_BUFFER\n#define USE_SORT_BUFFER\n");
copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define USE_SORT_BUFFER\n");
@@ -9039,7 +9473,7 @@ RendererStorageRD::~RendererStorageRD() {
RD::get_singleton()->free(mesh_default_rd_buffers[i]);
}
- giprobe_sdf_shader.version_free(giprobe_sdf_shader_version);
+ voxel_gi_sdf_shader.version_free(voxel_gi_sdf_shader_version);
particles_shader.copy_shader.version_free(particles_shader.copy_shader_version);
rt_sdf.shader.version_free(rt_sdf.shader_version);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index 6405bb75b0..ab470cb3a6 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -38,15 +38,15 @@
#include "servers/rendering/renderer_rd/effects_rd.h"
#include "servers/rendering/renderer_rd/shader_compiler_rd.h"
#include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/particles.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/particles_copy.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/skeleton.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
class RendererStorageRD : public RendererStorage {
public:
- static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) {
+ static _FORCE_INLINE_ void store_transform(const Transform3D &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];
@@ -95,7 +95,7 @@ public:
p_array[11] = 0;
}
- static _FORCE_INLINE_ void store_transform_transposed_3x4(const Transform &p_mtx, float *p_array) {
+ static _FORCE_INLINE_ void store_transform_transposed_3x4(const Transform3D &p_mtx, float *p_array) {
p_array[0] = p_mtx.basis.elements[0][0];
p_array[1] = p_mtx.basis.elements[0][1];
p_array[2] = p_mtx.basis.elements[0][2];
@@ -580,6 +580,7 @@ private:
RID buffer; //storage buffer
RID uniform_set_3d;
+ RID uniform_set_2d;
bool dirty = false;
MultiMesh *dirty_list = nullptr;
@@ -637,7 +638,9 @@ private:
COLLISION_TYPE_SPHERE,
COLLISION_TYPE_BOX,
COLLISION_TYPE_SDF,
- COLLISION_TYPE_HEIGHT_FIELD
+ COLLISION_TYPE_HEIGHT_FIELD,
+ COLLISION_TYPE_2D_SDF,
+
};
struct Collider {
@@ -660,6 +663,11 @@ private:
float time;
float delta;
+ uint32_t frame;
+ uint32_t pad0;
+ uint32_t pad1;
+ uint32_t pad2;
+
uint32_t random_seed;
uint32_t attractor_count;
uint32_t collider_count;
@@ -691,6 +699,7 @@ private:
};
struct Particles {
+ RS::ParticlesMode mode = RS::PARTICLES_MODE_3D;
bool inactive = true;
float inactive_time = 0.0;
bool emitting = false;
@@ -703,11 +712,24 @@ private:
bool restart_request = false;
AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
bool use_local_coords = true;
+ bool has_collision_cache = false;
+
+ bool has_sdf_collision = false;
+ Transform2D sdf_collision_transform;
+ Rect2 sdf_collision_to_screen;
+ RID sdf_collision_texture;
+
RID process_material;
+ uint32_t frame_counter = 0;
+ RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED;
RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX;
Vector<RID> draw_passes;
+ Vector<Transform3D> trail_bind_poses;
+ bool trail_bind_poses_dirty = false;
+ RID trail_bind_pose_buffer;
+ RID trail_bind_pose_uniform_set;
RID particle_buffer;
RID particle_instance_buffer;
@@ -739,7 +761,8 @@ private:
float speed_scale = 1.0;
- int fixed_fps = 0;
+ int fixed_fps = 30;
+ bool interpolate = true;
bool fractional_delta = false;
float frame_remainder = 0;
float collision_base_size = 0.01;
@@ -748,7 +771,7 @@ private:
bool force_sub_emit = false;
- Transform emission_transform;
+ Transform3D emission_transform;
Vector<uint8_t> emission_buffer_data;
@@ -759,12 +782,19 @@ private:
Dependency dependency;
- ParticlesFrameParams frame_params;
+ float trail_length = 1.0;
+ bool trails_enabled = false;
+ LocalVector<ParticlesFrameParams> frame_history;
+ LocalVector<ParticlesFrameParams> trail_params;
+
+ Particles() {
+ }
};
void _particles_process(Particles *p_particles, float p_delta);
void _particles_allocate_emission_buffer(Particles *particles);
void _particles_free_data(Particles *particles);
+ void _particles_update_buffers(Particles *particles);
struct ParticlesShader {
struct PushConstant {
@@ -776,7 +806,7 @@ private:
uint32_t use_fractional_delta;
uint32_t sub_emitter_mode;
uint32_t can_emit;
- uint32_t pad;
+ uint32_t trail_pass;
};
ParticlesShaderRD shader;
@@ -791,10 +821,24 @@ private:
struct CopyPushConstant {
float sort_direction[3];
uint32_t total_particles;
+
+ uint32_t trail_size;
+ uint32_t trail_total;
+ float frame_delta;
+ float frame_remainder;
+
+ float align_up[3];
+ uint32_t align_mode;
+
+ uint32_t order_by_lifetime;
+ uint32_t lifetime_split;
+ uint32_t lifetime_reverse;
+ uint32_t pad;
};
enum {
COPY_MODE_FILL_INSTANCES,
+ COPY_MODE_FILL_INSTANCES_2D,
COPY_MODE_FILL_SORT_BUFFER,
COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER,
COPY_MODE_MAX,
@@ -804,6 +848,8 @@ private:
RID copy_shader_version;
RID copy_pipelines[COPY_MODE_MAX];
+ LocalVector<float> pose_update_buffer;
+
} particles_shader;
Particles *particle_update_list = nullptr;
@@ -811,6 +857,7 @@ private:
struct ParticlesShaderData : public ShaderData {
bool valid;
RID version;
+ bool uses_collision = false;
//PipelineCacheRD pipelines[SKY_VERSION_MAX];
Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
@@ -894,12 +941,23 @@ private:
struct ParticlesCollisionInstance {
RID collision;
- Transform transform;
+ Transform3D transform;
bool active = false;
};
mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner;
+ /* visibility_notifier */
+
+ struct VisibilityNotifier {
+ AABB aabb;
+ Callable enter_callback;
+ Callable exit_callback;
+ Dependency dependency;
+ };
+
+ mutable RID_Owner<VisibilityNotifier> visibility_notifier_owner;
+
/* Skeleton */
struct Skeleton {
@@ -998,9 +1056,9 @@ private:
mutable RID_Owner<Decal, true> decal_owner;
- /* GI PROBE */
+ /* VOXEL GI */
- struct GIProbe {
+ struct VoxelGI {
RID octree_buffer;
RID data_buffer;
RID sdf_texture;
@@ -1012,7 +1070,7 @@ private:
int cell_count = 0;
- Transform to_cell_xform;
+ Transform3D to_cell_xform;
AABB bounds;
Vector3i octree_size;
@@ -1034,12 +1092,12 @@ private:
Dependency dependency;
};
- GiprobeSdfShaderRD giprobe_sdf_shader;
- RID giprobe_sdf_shader_version;
- RID giprobe_sdf_shader_version_shader;
- RID giprobe_sdf_shader_pipeline;
+ VoxelGiSdfShaderRD voxel_gi_sdf_shader;
+ RID voxel_gi_sdf_shader_version;
+ RID voxel_gi_sdf_shader_version_shader;
+ RID voxel_gi_sdf_shader_pipeline;
- mutable RID_Owner<GIProbe, true> gi_probe_owner;
+ mutable RID_Owner<VoxelGI, true> voxel_gi_owner;
/* REFLECTION PROBE */
@@ -1078,6 +1136,7 @@ private:
struct RenderTarget {
Size2i size;
+ uint32_t view_count;
RID framebuffer;
RID color;
@@ -1088,6 +1147,8 @@ private:
bool flags[RENDER_TARGET_FLAG_MAX];
+ bool sdf_enabled = false;
+
RID backbuffer; //used for effects
RID backbuffer_fb;
RID backbuffer_mipmap0;
@@ -1612,14 +1673,14 @@ public:
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(RID p_multimesh, int p_index, const Transform3D &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;
+ Transform3D 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;
@@ -1670,6 +1731,21 @@ public:
return multimesh->uniform_set_3d;
}
+ _FORCE_INLINE_ RID multimesh_get_2d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ if (!multimesh->uniform_set_2d.is_valid()) {
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(multimesh->buffer);
+ uniforms.push_back(u);
+ multimesh->uniform_set_2d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
+ }
+
+ return multimesh->uniform_set_2d;
+ }
+
/* IMMEDIATE API */
RID immediate_allocate() { return RID(); }
@@ -1695,10 +1771,10 @@ public:
void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false);
void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform);
- void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform);
+ void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform3D &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(RID p_skeleton, int p_bone, const Transform3D &p_transform);
+ Transform3D 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;
@@ -1955,59 +2031,59 @@ public:
virtual AABB decal_get_aabb(RID p_decal) const;
- /* GI PROBE API */
+ /* VOXEL GI API */
- RID gi_probe_allocate();
- void gi_probe_initialize(RID p_gi_probe);
+ RID voxel_gi_allocate();
+ void voxel_gi_initialize(RID p_voxel_gi);
- void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts);
+ void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &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;
+ AABB voxel_gi_get_bounds(RID p_voxel_gi) const;
+ Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const;
+ Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const;
+ Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const;
+ Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) 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;
+ Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const;
+ Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) 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 voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range);
+ float voxel_gi_get_dynamic_range(RID p_voxel_gi) const;
- void gi_probe_set_propagation(RID p_gi_probe, float p_range);
- float gi_probe_get_propagation(RID p_gi_probe) const;
+ void voxel_gi_set_propagation(RID p_voxel_gi, float p_range);
+ float voxel_gi_get_propagation(RID p_voxel_gi) const;
- void gi_probe_set_energy(RID p_gi_probe, float p_energy);
- float gi_probe_get_energy(RID p_gi_probe) const;
+ void voxel_gi_set_energy(RID p_voxel_gi, float p_energy);
+ float voxel_gi_get_energy(RID p_voxel_gi) const;
- void gi_probe_set_ao(RID p_gi_probe, float p_ao);
- float gi_probe_get_ao(RID p_gi_probe) const;
+ void voxel_gi_set_ao(RID p_voxel_gi, float p_ao);
+ float voxel_gi_get_ao(RID p_voxel_gi) 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 voxel_gi_set_ao_size(RID p_voxel_gi, float p_strength);
+ float voxel_gi_get_ao_size(RID p_voxel_gi) const;
- void gi_probe_set_bias(RID p_gi_probe, float p_bias);
- float gi_probe_get_bias(RID p_gi_probe) const;
+ void voxel_gi_set_bias(RID p_voxel_gi, float p_bias);
+ float voxel_gi_get_bias(RID p_voxel_gi) 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 voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range);
+ float voxel_gi_get_normal_bias(RID p_voxel_gi) const;
- void gi_probe_set_interior(RID p_gi_probe, bool p_enable);
- bool gi_probe_is_interior(RID p_gi_probe) const;
+ void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable);
+ bool voxel_gi_is_interior(RID p_voxel_gi) 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 voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable);
+ bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) 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;
+ void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength);
+ float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const;
- uint32_t gi_probe_get_version(RID p_probe);
- uint32_t gi_probe_get_data_version(RID p_probe);
+ uint32_t voxel_gi_get_version(RID p_probe);
+ uint32_t voxel_gi_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 voxel_gi_get_octree_buffer(RID p_voxel_gi) const;
+ RID voxel_gi_get_data_buffer(RID p_voxel_gi) const;
- RID gi_probe_get_sdf_texture(RID p_gi_probe);
+ RID voxel_gi_get_sdf_texture(RID p_voxel_gi);
/* LIGHTMAP CAPTURE */
@@ -2064,6 +2140,7 @@ public:
RID particles_allocate();
void particles_initialize(RID p_particles_collision);
+ void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode);
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);
@@ -2076,10 +2153,17 @@ public:
void particles_set_use_local_coordinates(RID p_particles, bool p_enable);
void particles_set_process_material(RID p_particles, RID p_material);
void particles_set_fixed_fps(RID p_particles, int p_fps);
+ void particles_set_interpolate(RID p_particles, bool p_enable);
void particles_set_fractional_delta(RID p_particles, bool p_enable);
void particles_set_collision_base_size(RID p_particles, float p_size);
+ void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align);
+
+ void particles_set_trails(RID p_particles, bool p_enable, float p_length);
+ void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses);
+
void particles_restart(RID p_particles);
- void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
+ void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
+
void particles_set_subemitter(RID p_particles, RID p_subemitter_particles);
void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order);
@@ -2091,21 +2175,40 @@ public:
AABB particles_get_current_aabb(RID p_particles);
AABB particles_get_aabb(RID p_particles) const;
- void particles_set_emission_transform(RID p_particles, const Transform &p_transform);
+ void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform);
bool particles_get_emitting(RID p_particles);
int particles_get_draw_passes(RID p_particles) const;
RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const;
- void particles_set_view_axis(RID p_particles, const Vector3 &p_axis);
+ void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis);
virtual bool particles_is_inactive(RID p_particles) const;
- _FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles) {
+ _FORCE_INLINE_ RS::ParticlesMode particles_get_mode(RID p_particles) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, RS::PARTICLES_MODE_2D);
+ return particles->mode;
+ }
+
+ _FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles, uint32_t &r_trail_divisor) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, 0);
+
+ if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
+ r_trail_divisor = particles->trail_bind_poses.size();
+ } else {
+ r_trail_divisor = 1;
+ }
+
+ return particles->amount * r_trail_divisor;
+ }
+
+ _FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND_V(!particles, 0);
- return particles->amount;
+ return particles->has_collision_cache;
}
_FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) {
@@ -2119,6 +2222,8 @@ public:
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND_V(!particles, RID());
if (particles->particles_transforms_buffer_uniform_set.is_null()) {
+ _particles_update_buffers(particles);
+
Vector<RD::Uniform> uniforms;
{
@@ -2137,6 +2242,7 @@ public:
virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance);
virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance);
+ virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture);
/* PARTICLES COLLISION */
@@ -2158,9 +2264,17 @@ public:
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const;
RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
+ virtual RID visibility_notifier_allocate();
+ virtual void visibility_notifier_initialize(RID p_notifier);
+ virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb);
+ virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable);
+
+ virtual AABB visibility_notifier_get_aabb(RID p_notifier) const;
+ virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred);
+
//used from 2D and 3D
virtual RID particles_collision_instance_create(RID p_collision);
- virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform);
+ virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform);
virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active);
/* GLOBAL VARIABLES API */
@@ -2188,7 +2302,7 @@ public:
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);
+ void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count);
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);
@@ -2211,6 +2325,8 @@ public:
RID render_target_get_sdf_framebuffer(RID p_render_target);
void render_target_sdf_process(RID p_render_target);
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const;
+ void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled);
+ bool render_target_is_sdf_enabled(RID p_render_target) const;
Size2 render_target_get_size(RID p_render_target);
RID render_target_get_rd_framebuffer(RID p_render_target);
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
index 24ac85bb35..b347197289 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
@@ -369,17 +369,24 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S
ERR_FAIL_COND(fidx == -1);
+ Vector<StringName> uses_functions;
+
for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) {
- if (added.has(E->get())) {
+ uses_functions.push_back(E->get());
+ }
+ uses_functions.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced
+
+ for (int k = 0; k < uses_functions.size(); k++) {
+ if (added.has(uses_functions[k])) {
continue; //was added already
}
- _dump_function_deps(p_node, E->get(), p_func_code, r_to_add, added);
+ _dump_function_deps(p_node, uses_functions[k], 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()) {
+ if (p_node->functions[i].name == uses_functions[k]) {
fnode = p_node->functions[i].function;
break;
}
@@ -391,10 +398,21 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S
String header;
if (fnode->return_type == SL::TYPE_STRUCT) {
- header = _mkid(fnode->return_struct_name) + " " + _mkid(fnode->name) + "(";
+ header = _mkid(fnode->return_struct_name);
} else {
- header = _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "(";
+ header = _typestr(fnode->return_type);
}
+
+ if (fnode->return_array_size > 0) {
+ header += "[";
+ header += itos(fnode->return_array_size);
+ header += "]";
+ }
+
+ header += " ";
+ header += _mkid(fnode->name);
+ header += "(";
+
for (int i = 0; i < fnode->arguments.size(); i++) {
if (i > 0) {
header += ", ";
@@ -407,13 +425,18 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S
} else {
header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name);
}
+ if (fnode->arguments[i].array_size > 0) {
+ header += "[";
+ header += itos(fnode->arguments[i].array_size);
+ header += "]";
+ }
}
header += ")\n";
r_to_add += header;
- r_to_add += p_func_code[E->get()];
+ r_to_add += p_func_code[uses_functions[k]];
- added.insert(E->get());
+ added.insert(uses_functions[k]);
}
}
@@ -565,63 +588,74 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
uniform_defines.resize(max_uniforms);
bool uses_uniforms = false;
+ Vector<StringName> uniform_names;
+
for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
+ uniform_names.push_back(E->key());
+ }
+
+ uniform_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced
+
+ for (int k = 0; k < uniform_names.size(); k++) {
+ StringName uniform_name = uniform_names[k];
+ const SL::ShaderNode::Uniform &uniform = pnode->uniforms[uniform_name];
+
String ucode;
- if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ if (uniform.scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
//insert, but don't generate any code.
- p_actions.uniforms->insert(E->key(), E->get());
+ p_actions.uniforms->insert(uniform_name, uniform);
continue; //instances are indexed directly, dont need index uniforms
}
- 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 ";
+ if (SL::is_sampler_type(uniform.type)) {
+ ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_order) + ") uniform ";
}
- bool is_buffer_global = !SL::is_sampler_type(E->get().type) && E->get().scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
+ bool is_buffer_global = !SL::is_sampler_type(uniform.type) && uniform.scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
if (is_buffer_global) {
//this is an integer to index the global table
ucode += _typestr(ShaderLanguage::TYPE_UINT);
} else {
- ucode += _prestr(E->get().precision);
- ucode += _typestr(E->get().type);
+ ucode += _prestr(uniform.precision);
+ ucode += _typestr(uniform.type);
}
- ucode += " " + _mkid(E->key());
+ ucode += " " + _mkid(uniform_name);
ucode += ";\n";
- if (SL::is_sampler_type(E->get().type)) {
+ if (SL::is_sampler_type(uniform.type)) {
for (int j = 0; j < STAGE_MAX; j++) {
r_gen_code.stage_globals[j] += 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;
- texture.global = E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;
+ texture.name = uniform_name;
+ texture.hint = uniform.hint;
+ texture.type = uniform.type;
+ texture.filter = uniform.filter;
+ texture.repeat = uniform.repeat;
+ texture.global = uniform.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;
if (texture.global) {
r_gen_code.uses_global_textures = true;
}
- r_gen_code.texture_uniforms.write[E->get().texture_order] = texture;
+ r_gen_code.texture_uniforms.write[uniform.texture_order] = texture;
} else {
if (!uses_uniforms) {
uses_uniforms = true;
}
- uniform_defines.write[E->get().order] = ucode;
+ uniform_defines.write[uniform.order] = ucode;
if (is_buffer_global) {
//globals are indices into the global table
- uniform_sizes.write[E->get().order] = _get_datatype_size(ShaderLanguage::TYPE_UINT);
- uniform_alignments.write[E->get().order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
+ uniform_sizes.write[uniform.order] = _get_datatype_size(ShaderLanguage::TYPE_UINT);
+ uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
} else {
- uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
- uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
+ uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type);
+ uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type);
}
}
- p_actions.uniforms->insert(E->key(), E->get());
+ p_actions.uniforms->insert(uniform_name, uniform);
}
for (int i = 0; i < max_uniforms; i++) {
@@ -688,21 +722,32 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
List<Pair<StringName, SL::ShaderNode::Varying>> var_frag_to_light;
+ Vector<StringName> varying_names;
+
for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) {
- if (E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) {
- var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(E->key(), E->get()));
- fragment_varyings.insert(E->key());
+ varying_names.push_back(E->key());
+ }
+
+ varying_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced
+
+ for (int k = 0; k < varying_names.size(); k++) {
+ StringName varying_name = varying_names[k];
+ const SL::ShaderNode::Varying &varying = pnode->varyings[varying_name];
+
+ if (varying.stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || varying.stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) {
+ var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(varying_name, varying));
+ fragment_varyings.insert(varying_name);
continue;
}
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) {
+ String interp_mode = _interpstr(varying.interpolation);
+ vcode += _prestr(varying.precision);
+ vcode += _typestr(varying.type);
+ vcode += " " + _mkid(varying_name);
+ if (varying.array_size > 0) {
vcode += "[";
- vcode += itos(E->get().array_size);
+ vcode += itos(varying.array_size);
vcode += "]";
}
vcode += ";\n";
@@ -959,25 +1004,30 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
declaration += itos(adnode->declarations[i].size);
}
declaration += "]";
- int sz = adnode->declarations[i].initializer.size();
- if (sz > 0) {
+ if (adnode->declarations[i].single_expression) {
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 += _dump_node_code(adnode->declarations[i].initializer[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ } else {
+ 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 += ")";
}
- declaration += ")";
}
}
@@ -988,7 +1038,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
bool use_fragment_varying = false;
if (!(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) {
- if (anode->assign_expression != nullptr) {
+ if (anode->assign_expression != nullptr && shader->varyings.has(anode->name)) {
use_fragment_varying = true;
} else {
if (p_assigning) {
@@ -1280,6 +1330,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
} else if (mnode->assign_expression != nullptr) {
code += "=";
code += _dump_node_code(mnode->assign_expression, p_level, r_gen_code, p_actions, p_default_actions, true, false);
+ } else if (mnode->call_expression != nullptr) {
+ code += ".";
+ code += _dump_node_code(mnode->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning, false);
}
} break;
}
@@ -1451,7 +1504,6 @@ ShaderCompilerRD::ShaderCompilerRD() {
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";
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index f7242a2b17..27305cc938 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -30,8 +30,12 @@
#include "shader_rd.h"
+#include "core/io/compression.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "renderer_compositor_rd.h"
#include "servers/rendering/rendering_device.h"
+#include "thirdparty/misc/smolv.h"
void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
Vector<String> lines = String(p_code).split("\n");
@@ -97,6 +101,7 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) {
name = p_name;
+
if (p_compute_code) {
_add_stage(p_compute_code, STAGE_TYPE_COMPUTE);
is_compute = true;
@@ -109,6 +114,18 @@ void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, con
_add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT);
}
}
+
+ StringBuilder tohash;
+ tohash.append("[VersionKey]");
+ tohash.append(RenderingDevice::get_singleton()->shader_get_cache_key());
+ tohash.append("[Vertex]");
+ tohash.append(p_vertex_code ? p_vertex_code : "");
+ tohash.append("[Fragment]");
+ tohash.append(p_fragment_code ? p_fragment_code : "");
+ tohash.append("[Compute]");
+ tohash.append(p_compute_code ? p_compute_code : "");
+
+ base_sha256 = tohash.as_string().sha256_text();
}
RID ShaderRD::version_create() {
@@ -131,6 +148,9 @@ void ShaderRD::_clear_version(Version *p_version) {
}
memdelete_arr(p_version->variants);
+ if (p_version->variant_stages) {
+ memdelete_arr(p_version->variant_stages);
+ }
p_version->variants = nullptr;
}
}
@@ -183,7 +203,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
return; //variant is disabled, return
}
- Vector<RD::ShaderStageData> stages;
+ Vector<RD::ShaderStageData> &stages = p_version->variant_stages[p_variant];
String error;
String current_source;
@@ -313,6 +333,197 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio
return source_code;
}
+String ShaderRD::_version_get_sha1(Version *p_version) const {
+ StringBuilder hash_build;
+
+ hash_build.append("[uniforms]");
+ hash_build.append(p_version->uniforms.get_data());
+ hash_build.append("[vertex_globals]");
+ hash_build.append(p_version->vertex_globals.get_data());
+ hash_build.append("[fragment_globals]");
+ hash_build.append(p_version->fragment_globals.get_data());
+ hash_build.append("[compute_globals]");
+ hash_build.append(p_version->compute_globals.get_data());
+
+ Vector<StringName> code_sections;
+ for (Map<StringName, CharString>::Element *E = p_version->code_sections.front(); E; E = E->next()) {
+ code_sections.push_back(E->key());
+ }
+ code_sections.sort_custom<StringName::AlphCompare>();
+
+ for (int i = 0; i < code_sections.size(); i++) {
+ hash_build.append(String("[code:") + String(code_sections[i]) + "]");
+ hash_build.append(p_version->code_sections[code_sections[i]].get_data());
+ }
+ for (int i = 0; i < p_version->custom_defines.size(); i++) {
+ hash_build.append("[custom_defines:" + itos(i) + "]");
+ hash_build.append(p_version->custom_defines[i].get_data());
+ }
+
+ return hash_build.as_string().sha1_text();
+}
+
+static const char *shader_file_header = "GDSC";
+static const uint32_t cache_file_version = 1;
+
+bool ShaderRD::_load_from_cache(Version *p_version) {
+ String sha1 = _version_get_sha1(p_version);
+ String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+
+ uint64_t time_from = OS::get_singleton()->get_ticks_usec();
+
+ FileAccessRef f = FileAccess::open(path, FileAccess::READ);
+ if (!f) {
+ return false;
+ }
+
+ char header[5] = { 0, 0, 0, 0, 0 };
+ f->get_buffer((uint8_t *)header, 4);
+ ERR_FAIL_COND_V(header != String(shader_file_header), false);
+
+ uint32_t file_version = f->get_32();
+ if (file_version != cache_file_version) {
+ return false; // wrong version
+ }
+
+ uint32_t variant_count = f->get_32();
+
+ ERR_FAIL_COND_V(variant_count != (uint32_t)variant_defines.size(), false); //should not happen but check
+
+ bool success = true;
+ for (uint32_t i = 0; i < variant_count; i++) {
+ uint32_t stage_count = f->get_32();
+ p_version->variant_stages[i].resize(stage_count);
+ for (uint32_t j = 0; j < stage_count; j++) {
+ p_version->variant_stages[i].write[j].shader_stage = RD::ShaderStage(f->get_32());
+
+ int compression = f->get_32();
+ uint32_t length = f->get_32();
+
+ if (compression == 0) {
+ Vector<uint8_t> data;
+ data.resize(length);
+
+ f->get_buffer(data.ptrw(), length);
+
+ p_version->variant_stages[i].write[j].spir_v = data;
+ } else {
+ Vector<uint8_t> data;
+
+ if (compression == 2) {
+ //zstd
+ int smol_length = f->get_32();
+ Vector<uint8_t> zstd_data;
+
+ zstd_data.resize(smol_length);
+ f->get_buffer(zstd_data.ptrw(), smol_length);
+
+ data.resize(length);
+ Compression::decompress(data.ptrw(), data.size(), zstd_data.ptr(), zstd_data.size(), Compression::MODE_ZSTD);
+
+ } else {
+ data.resize(length);
+ f->get_buffer(data.ptrw(), length);
+ }
+
+ Vector<uint8_t> spirv;
+ uint32_t spirv_size = smolv::GetDecodedBufferSize(data.ptr(), data.size());
+ spirv.resize(spirv_size);
+ if (!smolv::Decode(data.ptr(), data.size(), spirv.ptrw(), spirv_size)) {
+ ERR_PRINT("Malformed smolv input uncompressing shader " + name + ", variant #" + itos(i) + " stage :" + itos(j));
+ success = false;
+ break;
+ }
+ p_version->variant_stages[i].write[j].spir_v = spirv;
+ }
+ }
+ }
+
+ if (!success) {
+ for (uint32_t i = 0; i < variant_count; i++) {
+ p_version->variant_stages[i].resize(0);
+ }
+ return false;
+ }
+
+ float time_ms = double(OS::get_singleton()->get_ticks_usec() - time_from) / 1000.0;
+
+ print_verbose("Shader cache load success '" + path + "' " + rtos(time_ms) + "ms.");
+
+ for (uint32_t i = 0; i < variant_count; i++) {
+ RID shader = RD::get_singleton()->shader_create(p_version->variant_stages[i]);
+ {
+ MutexLock lock(variant_set_mutex);
+ p_version->variants[i] = shader;
+ }
+ }
+
+ memdelete_arr(p_version->variant_stages); //clear stages
+ p_version->variant_stages = nullptr;
+ p_version->valid = true;
+ return true;
+}
+
+void ShaderRD::_save_to_cache(Version *p_version) {
+ String sha1 = _version_get_sha1(p_version);
+ String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+
+ FileAccessRef f = FileAccess::open(path, FileAccess::WRITE);
+ ERR_FAIL_COND(!f);
+ f->store_buffer((const uint8_t *)shader_file_header, 4);
+ f->store_32(cache_file_version); //file version
+ uint32_t variant_count = variant_defines.size();
+ f->store_32(variant_count); //variant count
+
+ for (uint32_t i = 0; i < variant_count; i++) {
+ f->store_32(p_version->variant_stages[i].size()); //stage count
+ for (int j = 0; j < p_version->variant_stages[i].size(); j++) {
+ f->store_32(p_version->variant_stages[i][j].shader_stage); //stage count
+ Vector<uint8_t> spirv = p_version->variant_stages[i][j].spir_v;
+
+ bool save_uncompressed = true;
+ if (shader_cache_save_compressed) {
+ smolv::ByteArray smolv;
+ bool strip_debug = !shader_cache_save_debug;
+ if (!smolv::Encode(spirv.ptr(), spirv.size(), smolv, strip_debug ? smolv::kEncodeFlagStripDebugInfo : 0)) {
+ ERR_PRINT("Error compressing shader " + name + ", variant #" + itos(i) + " stage :" + itos(i));
+ } else {
+ bool compress_zstd = shader_cache_save_compressed_zstd;
+
+ if (compress_zstd) {
+ Vector<uint8_t> zstd;
+ zstd.resize(Compression::get_max_compressed_buffer_size(smolv.size(), Compression::MODE_ZSTD));
+ int dst_size = Compression::compress(zstd.ptrw(), &smolv[0], smolv.size(), Compression::MODE_ZSTD);
+ if (dst_size >= 0 && (uint32_t)dst_size < smolv.size()) {
+ f->store_32(2); //compressed zstd
+ f->store_32(smolv.size()); //size of smolv buffer
+ f->store_32(dst_size); //size of smolv buffer
+ f->store_buffer(zstd.ptr(), dst_size); //smolv buffer
+ } else {
+ compress_zstd = false;
+ }
+ }
+
+ if (!compress_zstd) {
+ f->store_32(1); //compressed
+ f->store_32(smolv.size()); //size of smolv buffer
+ f->store_buffer(&smolv[0], smolv.size()); //smolv buffer
+ }
+ save_uncompressed = false;
+ }
+ }
+
+ if (save_uncompressed) {
+ f->store_32(0); //uncompressed
+ f->store_32(spirv.size()); //stage count
+ f->store_buffer(spirv.ptr(), spirv.size()); //stage count
+ }
+ }
+ }
+
+ f->close();
+}
+
void ShaderRD::_compile_version(Version *p_version) {
_clear_version(p_version);
@@ -320,6 +531,15 @@ void ShaderRD::_compile_version(Version *p_version) {
p_version->dirty = false;
p_version->variants = memnew_arr(RID, variant_defines.size());
+ typedef Vector<RD::ShaderStageData> ShaderStageArray;
+ p_version->variant_stages = memnew_arr(ShaderStageArray, variant_defines.size());
+
+ if (shader_cache_dir_valid) {
+ if (_load_from_cache(p_version)) {
+ return;
+ }
+ }
+
#if 1
RendererThreadPool::singleton->thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version);
@@ -351,10 +571,20 @@ void ShaderRD::_compile_version(Version *p_version) {
}
}
memdelete_arr(p_version->variants);
+ if (p_version->variant_stages) {
+ memdelete_arr(p_version->variant_stages);
+ }
p_version->variants = nullptr;
+ p_version->variant_stages = nullptr;
return;
+ } else if (shader_cache_dir_valid) {
+ //save shader cache
+ _save_to_cache(p_version);
}
+ memdelete_arr(p_version->variant_stages); //clear stages
+ p_version->variant_stages = nullptr;
+
p_version->valid = true;
}
@@ -443,6 +673,8 @@ bool ShaderRD::is_variant_enabled(int p_variant) const {
return variants_enabled[p_variant];
}
+bool ShaderRD::shader_cache_cleanup_on_start = false;
+
ShaderRD::ShaderRD() {
// Do not feel forced to use this, in most cases it makes little to no difference.
bool use_32_threads = false;
@@ -469,8 +701,64 @@ void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String
variant_defines.push_back(p_variant_defines[i].utf8());
variants_enabled.push_back(true);
}
+
+ if (shader_cache_dir != String()) {
+ StringBuilder hash_build;
+
+ hash_build.append("[base_hash]");
+ hash_build.append(base_sha256);
+ hash_build.append("[general_defines]");
+ hash_build.append(general_defines.get_data());
+ for (int i = 0; i < variant_defines.size(); i++) {
+ hash_build.append("[variant_defines:" + itos(i) + "]");
+ hash_build.append(variant_defines[i].get_data());
+ }
+
+ base_sha256 = hash_build.as_string().sha256_text();
+
+ DirAccessRef d = DirAccess::open(shader_cache_dir);
+ ERR_FAIL_COND(!d);
+ if (d->change_dir(name) != OK) {
+ Error err = d->make_dir(name);
+ ERR_FAIL_COND(err != OK);
+ d->change_dir(name);
+ }
+
+ //erase other versions?
+ if (shader_cache_cleanup_on_start) {
+ }
+ //
+ if (d->change_dir(base_sha256) != OK) {
+ Error err = d->make_dir(base_sha256);
+ ERR_FAIL_COND(err != OK);
+ }
+ shader_cache_dir_valid = true;
+
+ print_verbose("Shader '" + name + "' SHA256: " + base_sha256);
+ }
+}
+
+void ShaderRD::set_shader_cache_dir(const String &p_dir) {
+ shader_cache_dir = p_dir;
+}
+
+void ShaderRD::set_shader_cache_save_compressed(bool p_enable) {
+ shader_cache_save_compressed = p_enable;
}
+void ShaderRD::set_shader_cache_save_compressed_zstd(bool p_enable) {
+ shader_cache_save_compressed_zstd = p_enable;
+}
+
+void ShaderRD::set_shader_cache_save_debug(bool p_enable) {
+ shader_cache_save_debug = p_enable;
+}
+
+String ShaderRD::shader_cache_dir;
+bool ShaderRD::shader_cache_save_compressed = true;
+bool ShaderRD::shader_cache_save_compressed_zstd = true;
+bool ShaderRD::shader_cache_save_debug = true;
+
ShaderRD::~ShaderRD() {
List<RID> remaining;
version_owner.get_owned_list(&remaining);
diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h
index f20d539621..9a68e02007 100644
--- a/servers/rendering/renderer_rd/shader_rd.h
+++ b/servers/rendering/renderer_rd/shader_rd.h
@@ -59,7 +59,8 @@ class ShaderRD {
Map<StringName, CharString> code_sections;
Vector<CharString> custom_defines;
- RID *variants; //same size as version defines
+ Vector<RD::ShaderStageData> *variant_stages = nullptr;
+ RID *variants = nullptr; //same size as version defines
bool valid;
bool dirty;
@@ -96,10 +97,19 @@ class ShaderRD {
bool is_compute = false;
- const char *name;
+ String name;
CharString base_compute_defines;
+ String base_sha256;
+
+ static String shader_cache_dir;
+ static bool shader_cache_cleanup_on_start;
+ static bool shader_cache_save_compressed;
+ static bool shader_cache_save_compressed_zstd;
+ static bool shader_cache_save_debug;
+ bool shader_cache_dir_valid = false;
+
enum StageType {
STAGE_TYPE_VERTEX,
STAGE_TYPE_FRAGMENT,
@@ -113,6 +123,10 @@ class ShaderRD {
void _add_stage(const char *p_code, StageType p_stage_type);
+ String _version_get_sha1(Version *p_version) const;
+ bool _load_from_cache(Version *p_version);
+ void _save_to_cache(Version *p_version);
+
protected:
ShaderRD();
void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name);
@@ -148,6 +162,11 @@ public:
void set_variant_enabled(int p_variant, bool p_enabled);
bool is_variant_enabled(int p_variant) const;
+ static void set_shader_cache_dir(const String &p_dir);
+ static void set_shader_cache_save_compressed(bool p_enable);
+ static void set_shader_cache_save_compressed_zstd(bool p_enable);
+ static void set_shader_cache_save_debug(bool p_enable);
+
RS::ShaderNativeSourceCode version_get_native_source_code(RID p_version);
void initialize(const Vector<String> &p_variant_defines, const String &p_general_defines = "");
diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl
new file mode 100644
index 0000000000..967da1e6e4
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/blit.glsl
@@ -0,0 +1,95 @@
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, binding = 0, std140) uniform Pos {
+ vec4 dst_rect;
+
+ vec2 eye_center;
+ float k1;
+ float k2;
+
+ float upscale;
+ float aspect_ratio;
+ uint layer;
+ uint pad1;
+}
+data;
+
+layout(location = 0) out vec2 uv;
+
+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 = base_arr[gl_VertexIndex];
+ vec2 vtx = data.dst_rect.xy + uv * data.dst_rect.zw;
+ gl_Position = vec4(vtx * 2.0 - 1.0, 0.0, 1.0);
+}
+
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, binding = 0, std140) uniform Pos {
+ vec4 dst_rect;
+
+ vec2 eye_center;
+ float k1;
+ float k2;
+
+ float upscale;
+ float aspect_ratio;
+ uint layer;
+ uint pad1;
+}
+data;
+
+layout(location = 0) in vec2 uv;
+
+layout(location = 0) out vec4 color;
+
+#ifdef USE_LAYER
+layout(binding = 0) uniform sampler2DArray src_rt;
+#else
+layout(binding = 0) uniform sampler2D src_rt;
+#endif
+
+void main() {
+#ifdef APPLY_LENS_DISTORTION
+ vec2 coords = uv * 2.0 - 1.0;
+ vec2 offset = coords - data.eye_center;
+
+ // take aspect ratio into account
+ offset.y /= data.aspect_ratio;
+
+ // distort
+ vec2 offset_sq = offset * offset;
+ float radius_sq = offset_sq.x + offset_sq.y;
+ float radius_s4 = radius_sq * radius_sq;
+ float distortion_scale = 1.0 + (data.k1 * radius_sq) + (data.k2 * radius_s4);
+ offset *= distortion_scale;
+
+ // reapply aspect ratio
+ offset.y *= data.aspect_ratio;
+
+ // add our eye center back in
+ coords = offset + data.eye_center;
+ coords /= data.upscale;
+
+ // and check our color
+ if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) {
+ color = vec4(0.0, 0.0, 0.0, 1.0);
+ } else {
+ // layer is always used here
+ coords = (coords + vec2(1.0)) / vec2(2.0);
+ color = texture(src_rt, vec3(coords, data.layer));
+ }
+#elif defined(USE_LAYER)
+ color = texture(src_rt, vec3(uv, data.layer));
+#else
+ color = texture(src_rt, uv);
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 8b97ec119f..2186bd174b 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -84,40 +84,82 @@ void main() {
mat4 world_matrix = mat4(vec4(draw_data.world_x, 0.0, 0.0), vec4(draw_data.world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data.world_ofs, 0.0, 1.0));
-#if 0
- if (draw_data.flags & FLAGS_INSTANCING_ENABLED) {
- uint offset = draw_data.flags & FLAGS_INSTANCING_STRIDE_MASK;
- offset *= gl_InstanceIndex;
- mat4 instance_xform = mat4(
- vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), 0.0, texelFetch(instancing_buffer, offset + 3)),
- vec4(texelFetch(instancing_buffer, offset + 4), texelFetch(instancing_buffer, offset + 5), 0.0, texelFetch(instancing_buffer, offset + 7)),
- vec4(0.0, 0.0, 1.0, 0.0),
- vec4(0.0, 0.0, 0.0, 1.0));
- offset += 8;
- if (draw_data.flags & FLAGS_INSTANCING_HAS_COLORS) {
- vec4 instance_color;
- if (draw_data.flags & FLAGS_INSTANCING_COLOR_8_BIT) {
- uint bits = floatBitsToUint(texelFetch(instancing_buffer, offset));
- instance_color = unpackUnorm4x8(bits);
- offset += 1;
- } else {
- instance_color = vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), texelFetch(instancing_buffer, offset + 2), texelFetch(instancing_buffer, offset + 3));
- offset += 4;
- }
+#define FLAGS_INSTANCING_MASK 0x7F
+#define FLAGS_INSTANCING_HAS_COLORS (1 << 7)
+#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 8)
+
+ uint instancing = draw_data.flags & FLAGS_INSTANCING_MASK;
+
+#ifdef USE_ATTRIBUTES
+
+ if (instancing > 1) {
+ // trails
- color *= instance_color;
+ uint stride = 2 + 1 + 1; //particles always uses this format
+
+ uint trail_size = instancing;
+
+ uint offset = trail_size * stride * gl_InstanceIndex;
+
+ vec4 pcolor;
+ vec2 new_vertex;
+ {
+ uint boffset = offset + bone_attrib.x * stride;
+ new_vertex = (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.x;
+ pcolor = transforms.data[boffset + 2] * weight_attrib.x;
}
- if (draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA) {
- if (draw_data.flags & FLAGS_INSTANCING_CUSTOM_DATA_8_BIT) {
- uint bits = floatBitsToUint(texelFetch(instancing_buffer, offset));
- instance_custom = unpackUnorm4x8(bits);
- } else {
- instance_custom = vec4(texelFetch(instancing_buffer, offset + 0), texelFetch(instancing_buffer, offset + 1), texelFetch(instancing_buffer, offset + 2), texelFetch(instancing_buffer, offset + 3));
+ if (weight_attrib.y > 0.001) {
+ uint boffset = offset + bone_attrib.y * stride;
+ new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.y;
+ pcolor += transforms.data[boffset + 2] * weight_attrib.y;
+ }
+ if (weight_attrib.z > 0.001) {
+ uint boffset = offset + bone_attrib.z * stride;
+ new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.z;
+ pcolor += transforms.data[boffset + 2] * weight_attrib.z;
+ }
+ if (weight_attrib.w > 0.001) {
+ uint boffset = offset + bone_attrib.w * stride;
+ new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.w;
+ pcolor += transforms.data[boffset + 2] * weight_attrib.w;
+ }
+
+ instance_custom = transforms.data[offset + 3];
+
+ vertex = new_vertex;
+ color *= pcolor;
+
+ } else
+#endif // USE_ATTRIBUTES
+
+ if (instancing == 1) {
+ uint stride = 2;
+ {
+ if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
+ stride += 1;
+ }
+ if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+ stride += 1;
}
}
- }
-#endif
+ uint offset = stride * gl_InstanceIndex;
+
+ mat4 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;
+
+ if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
+ color *= transforms.data[offset];
+ offset += 1;
+ }
+
+ if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+ instance_custom = transforms.data[offset];
+ }
+
+ matrix = transpose(matrix);
+ world_matrix = world_matrix * matrix;
+ }
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
if (bool(draw_data.flags & FLAGS_USING_PARTICLES)) {
@@ -239,7 +281,7 @@ vec2 screen_uv_to_sdf(vec2 p_uv) {
float texture_sdf(vec2 p_sdf) {
vec2 uv = p_sdf * canvas_data.sdf_to_tex.xy + canvas_data.sdf_to_tex.zw;
float d = texture(sampler2D(sdf_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv).r;
- d = d * SDF_MAX_LENGTH - 1.0;
+ d *= SDF_MAX_LENGTH;
return d * canvas_data.tex_to_sdf;
}
diff --git a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
index 65a554e839..2bdfbabfcf 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
@@ -7,7 +7,7 @@
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(r8, set = 0, binding = 1) uniform restrict readonly image2D src_pixels;
-layout(r16, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf;
+layout(r16_snorm, set = 0, binding = 2) uniform restrict writeonly image2D dst_sdf;
layout(rg16i, set = 0, binding = 3) uniform restrict readonly iimage2D src_process;
layout(rg16i, set = 0, binding = 4) uniform restrict writeonly iimage2D dst_process;
@@ -32,7 +32,7 @@ void main() {
#ifdef MODE_LOAD
bool solid = imageLoad(src_pixels, pos).r > 0.5;
- imageStore(dst_process, pos, solid ? ivec4(pos, 0, 0) : ivec4(ivec2(32767), 0, 0));
+ imageStore(dst_process, pos, solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0));
#endif
#ifdef MODE_LOAD_SHRINK
@@ -43,6 +43,8 @@ void main() {
ivec2 rel = ivec2(32767);
float d = 1e20;
+ int found = 0;
+ int solid_found = 0;
for (int i = 0; i < s; i++) {
for (int j = 0; j < s; j++) {
ivec2 src_pos = base + ivec2(i, j);
@@ -56,10 +58,17 @@ void main() {
d = dist;
rel = src_pos;
}
+ solid_found++;
}
+ found++;
}
}
+ if (solid_found == found) {
+ //mark solid only if all are solid
+ rel = ivec2(-32767);
+ }
+
imageStore(dst_process, pos, ivec4(rel, 0, 0));
#endif
@@ -70,6 +79,12 @@ void main() {
ivec2 rel = imageLoad(src_process, pos).xy;
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
if (center != rel) {
//only process if it does not point to itself
const int ofs_table_size = 8;
@@ -92,6 +107,15 @@ void main() {
continue;
}
ivec2 src_rel = imageLoad(src_process, src_pos).xy;
+ bool src_solid = src_rel.x < 0;
+ if (src_solid) {
+ src_rel = -src_rel - ivec2(1);
+ }
+
+ if (src_solid != solid) {
+ src_rel = ivec2(src_pos << params.shift); //point to itself if of different type
+ }
+
float src_dist = length(vec2(src_rel - center));
if (src_dist < dist) {
dist = src_dist;
@@ -100,18 +124,31 @@ void main() {
}
}
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
imageStore(dst_process, pos, ivec4(rel, 0, 0));
#endif
#ifdef MODE_STORE
ivec2 rel = imageLoad(src_process, pos).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
float d = length(vec2(rel - pos));
- if (d > 0.01) {
- d += 1.0; //make it signed
+
+ if (solid) {
+ d = -d;
}
+
d /= SDF_MAX_LENGTH;
- d = clamp(d, 0.0, 1.0);
+ d = clamp(d, -1.0, 1.0);
imageStore(dst_sdf, pos, vec4(d));
#endif
@@ -122,13 +159,20 @@ void main() {
ivec2 center = base + ivec2(params.shift);
ivec2 rel = imageLoad(src_process, pos).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
float d = length(vec2(rel - center));
- if (d > 0.01) {
- d += 1.0; //make it signed
+ if (solid) {
+ d = -d;
}
d /= SDF_MAX_LENGTH;
- d = clamp(d, 0.0, 1.0);
+ d = clamp(d, -1.0, 1.0);
imageStore(dst_sdf, pos, vec4(d));
#endif
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index cf7678ea31..451f9b0089 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -5,12 +5,10 @@
#define SDF_MAX_LENGTH 16384.0
-#define FLAGS_INSTANCING_STRIDE_MASK 0xF
-#define FLAGS_INSTANCING_ENABLED (1 << 4)
-#define FLAGS_INSTANCING_HAS_COLORS (1 << 5)
-#define FLAGS_INSTANCING_COLOR_8BIT (1 << 6)
-#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 7)
-#define FLAGS_INSTANCING_CUSTOM_DATA_8_BIT (1 << 8)
+//1 means enabled, 2+ means trails in use
+#define FLAGS_INSTANCING_MASK 0x7F
+#define FLAGS_INSTANCING_HAS_COLORS (1 << 7)
+#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 8)
#define FLAGS_CLIP_RECT_UV (1 << 9)
#define FLAGS_TRANSPOSE_RECT (1 << 10)
diff --git a/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl b/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl
index 3a4bf4da07..8e616ebe1f 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_data_inc.glsl
@@ -1,105 +1,3 @@
-
#define CLUSTER_COUNTER_SHIFT 20
#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1)
#define CLUSTER_COUNTER_MASK 0xfff
-
-struct LightData { //this structure needs to be as packed as possible
- vec3 position;
- float inv_radius;
-
- vec3 direction;
- float size;
-
- vec3 color;
- float attenuation;
-
- float cone_attenuation;
- float cone_angle;
- float specular_amount;
- bool shadow_enabled;
-
- vec4 atlas_rect; // rect in the shadow atlas
- mat4 shadow_matrix;
- float shadow_bias;
- float shadow_normal_bias;
- float transmittance_bias;
- float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
- float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
- uint mask;
- float shadow_volumetric_fog_fade;
- uint pad;
- vec4 projector_rect; //projector rect in srgb decal atlas
-};
-
-#define REFLECTION_AMBIENT_DISABLED 0
-#define REFLECTION_AMBIENT_ENVIRONMENT 1
-#define REFLECTION_AMBIENT_COLOR 2
-
-struct ReflectionData {
- vec3 box_extents;
- float index;
- vec3 box_offset;
- uint mask;
- vec3 ambient; // ambient color
- float intensity;
- bool exterior;
- bool box_project;
- uint ambient_mode;
- uint pad;
- //0-8 is intensity,8-9 is ambient, mode
- mat4 local_matrix; // up to here for spot and omni, rest is for directional
- // notes: for ambientblend, use distance to edge to blend between already existing global environment
-};
-
-struct DirectionalLightData {
- vec3 direction;
- float energy;
- vec3 color;
- float size;
- float specular;
- uint mask;
- float softshadow_angle;
- float soft_shadow_scale;
- bool blend_splits;
- bool shadow_enabled;
- float fade_from;
- float fade_to;
- uvec3 pad;
- float shadow_volumetric_fog_fade;
- vec4 shadow_bias;
- vec4 shadow_normal_bias;
- vec4 shadow_transmittance_bias;
- vec4 shadow_z_range;
- vec4 shadow_range_begin;
- vec4 shadow_split_offsets;
- mat4 shadow_matrix1;
- mat4 shadow_matrix2;
- mat4 shadow_matrix3;
- mat4 shadow_matrix4;
- vec4 shadow_color1;
- vec4 shadow_color2;
- vec4 shadow_color3;
- vec4 shadow_color4;
- vec2 uv_scale1;
- vec2 uv_scale2;
- vec2 uv_scale3;
- vec2 uv_scale4;
-};
-
-struct DecalData {
- mat4 xform; //to decal transform
- vec3 inv_extents;
- float albedo_mix;
- vec4 albedo_rect;
- vec4 normal_rect;
- vec4 orm_rect;
- vec4 emission_rect;
- vec4 modulate;
- float emission_energy;
- uint mask;
- float upper_fade;
- float lower_fade;
- mat3x4 normal_xform;
- vec3 normal;
- float normal_fade;
-};
diff --git a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
new file mode 100644
index 0000000000..ccaad13311
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
@@ -0,0 +1,18 @@
+
+struct DecalData {
+ mat4 xform; //to decal transform
+ vec3 inv_extents;
+ float albedo_mix;
+ vec4 albedo_rect;
+ vec4 normal_rect;
+ vec4 orm_rect;
+ vec4 emission_rect;
+ vec4 modulate;
+ float emission_energy;
+ uint mask;
+ float upper_fade;
+ float lower_fade;
+ mat3x4 normal_xform;
+ vec3 normal;
+ float normal_fade;
+};
diff --git a/servers/rendering/renderer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl
index bfd5c4c88d..3977f4efa0 100644
--- a/servers/rendering/renderer_rd/shaders/gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/gi.glsl
@@ -35,7 +35,7 @@ layout(set = 0, binding = 11) uniform texture2DArray lightprobe_texture;
layout(set = 0, binding = 12) uniform texture2D depth_buffer;
layout(set = 0, binding = 13) uniform texture2D normal_roughness_buffer;
-layout(set = 0, binding = 14) uniform utexture2D giprobe_buffer;
+layout(set = 0, binding = 14) uniform utexture2D voxel_gi_buffer;
layout(set = 0, binding = 15, std140) uniform SDFGI {
vec3 grid_size;
@@ -65,9 +65,9 @@ layout(set = 0, binding = 15, std140) uniform SDFGI {
}
sdfgi;
-#define MAX_GI_PROBES 8
+#define MAX_VOXEL_GI_INSTANCES 8
-struct GIProbeData {
+struct VoxelGIData {
mat4 xform;
vec3 bounds;
float dynamic_range;
@@ -83,12 +83,12 @@ struct GIProbeData {
uint mipmaps;
};
-layout(set = 0, binding = 16, std140) uniform GIProbes {
- GIProbeData data[MAX_GI_PROBES];
+layout(set = 0, binding = 16, std140) uniform VoxelGIs {
+ VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
-gi_probes;
+voxel_gi_instances;
-layout(set = 0, binding = 17) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
+layout(set = 0, binding = 17) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
layout(push_constant, binding = 0, std430) uniform Params {
ivec2 screen_size;
@@ -98,7 +98,7 @@ layout(push_constant, binding = 0, std430) uniform Params {
vec4 proj_info;
vec3 ao_color;
- uint max_giprobes;
+ uint max_voxel_gi_instances;
bool high_quality_vct;
bool orthogonal;
@@ -155,7 +155,7 @@ vec3 reconstruct_position(ivec2 screen_pos) {
return pos;
}
-void sdfgi_probe_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, float roughness, out vec3 diffuse_light, out vec3 specular_light) {
+void sdfvoxel_gi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, float roughness, out vec3 diffuse_light, out vec3 specular_light) {
cascade_pos += cam_normal * sdfgi.normal_bias;
vec3 base_pos = floor(cascade_pos);
@@ -293,7 +293,7 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o
float blend;
vec3 diffuse, specular;
- sdfgi_probe_process(cascade, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse, specular);
+ sdfvoxel_gi_process(cascade, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse, specular);
{
//process blend
@@ -323,7 +323,7 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o
} else {
vec3 diffuse2, specular2;
cascade_pos = (cam_pos - sdfgi.cascades[cascade + 1].position) * sdfgi.cascades[cascade + 1].to_probe;
- sdfgi_probe_process(cascade + 1, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse2, specular2);
+ sdfvoxel_gi_process(cascade + 1, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse2, specular2);
diffuse = mix(diffuse, diffuse2, blend);
specular = mix(specular, specular2, blend);
}
@@ -494,26 +494,26 @@ vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3
return color;
}
-void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, inout vec4 out_spec, inout vec4 out_diff, inout float out_blend) {
- 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);
+void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, inout vec4 out_spec, inout vec4 out_diff, inout float out_blend) {
+ position = (voxel_gi_instances.data[index].xform * vec4(position, 1.0)).xyz;
+ ref_vec = normalize((voxel_gi_instances.data[index].xform * vec4(ref_vec, 0.0)).xyz);
+ normal = normalize((voxel_gi_instances.data[index].xform * vec4(normal, 0.0)).xyz);
- position += normal * gi_probes.data[index].normal_bias;
+ position += normal * voxel_gi_instances.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))))) {
+ if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, voxel_gi_instances.data[index].bounds))))) {
return;
}
- mat3 dir_xform = mat3(gi_probes.data[index].xform) * normal_xform;
+ mat3 dir_xform = mat3(voxel_gi_instances.data[index].xform) * normal_xform;
- vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0);
+ vec3 blendv = abs(position / voxel_gi_instances.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;
+ float max_distance = length(voxel_gi_instances.data[index].bounds);
+ vec3 cell_size = 1.0 / voxel_gi_instances.data[index].bounds;
//irradiance
@@ -534,7 +534,7 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
for (uint i = 0; i < cone_dir_count; i++) {
vec3 dir = normalize(dir_xform * cone_dirs[i]);
- light += cone_weights[i] * voxel_cone_trace(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+ light += cone_weights[i] * voxel_cone_trace(voxel_gi_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, voxel_gi_instances.data[index].bias);
}
} else {
const uint cone_dir_count = 4;
@@ -547,42 +547,42 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3
float cone_weights[cone_dir_count] = float[](0.25, 0.25, 0.25, 0.25);
for (int i = 0; i < cone_dir_count; i++) {
vec3 dir = normalize(dir_xform * cone_dirs[i]);
- light += cone_weights[i] * voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, max_distance, gi_probes.data[index].bias);
+ light += cone_weights[i] * voxel_cone_trace_45_degrees(voxel_gi_textures[index], cell_size, position, dir, max_distance, voxel_gi_instances.data[index].bias);
}
}
- if (gi_probes.data[index].ambient_occlusion > 0.001) {
- float size = 1.0 + gi_probes.data[index].ambient_occlusion_size * 7.0;
+ if (voxel_gi_instances.data[index].ambient_occlusion > 0.001) {
+ float size = 1.0 + voxel_gi_instances.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[index], linear_sampler_with_mipmaps), ofs, i - 1.0).a * i;
+ ao += textureLod(sampler3D(voxel_gi_textures[index], linear_sampler_with_mipmaps), 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[index], linear_sampler_with_mipmaps), ofs, taps).a * (taps + 1.0) * blend;
+ ao += textureLod(sampler3D(voxel_gi_textures[index], linear_sampler_with_mipmaps), ofs, taps).a * (taps + 1.0) * blend;
}
ao = 1.0 - min(1.0, ao);
- light.rgb = mix(params.ao_color, light.rgb, mix(1.0, ao, gi_probes.data[index].ambient_occlusion));
+ light.rgb = mix(params.ao_color, light.rgb, mix(1.0, ao, voxel_gi_instances.data[index].ambient_occlusion));
}
- light.rgb *= gi_probes.data[index].dynamic_range;
- if (!gi_probes.data[index].blend_ambient) {
+ light.rgb *= voxel_gi_instances.data[index].dynamic_range;
+ if (!voxel_gi_instances.data[index].blend_ambient) {
light.a = 1.0;
}
out_diff += light * blend;
//radiance
- vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias);
- irr_light.rgb *= gi_probes.data[index].dynamic_range;
- if (!gi_probes.data[index].blend_ambient) {
+ vec4 irr_light = voxel_cone_trace(voxel_gi_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, voxel_gi_instances.data[index].bias);
+ irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range;
+ if (!voxel_gi_instances.data[index].blend_ambient) {
irr_light.a = 1.0;
}
@@ -614,9 +614,9 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref
sdfgi_process(vertex, normal, reflection, roughness, ambient_light, reflection_light);
#endif
-#ifdef USE_GIPROBES
+#ifdef USE_VOXEL_GI_INSTANCES
{
- uvec2 giprobe_tex = texelFetch(usampler2D(giprobe_buffer, linear_sampler), pos, 0).rg;
+ uvec2 voxel_gi_tex = texelFetch(usampler2D(voxel_gi_buffer, linear_sampler), pos, 0).rg;
roughness *= roughness;
//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);
@@ -628,9 +628,9 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref
vec4 spec_accum = vec4(0.0);
float blend_accum = 0.0;
- for (uint i = 0; i < params.max_giprobes; i++) {
- if (any(equal(uvec2(i), giprobe_tex))) {
- gi_probe_compute(i, vertex, normal, reflection, normal_mat, roughness, spec_accum, amb_accum, blend_accum);
+ for (uint i = 0; i < params.max_voxel_gi_instances; i++) {
+ if (any(equal(uvec2(i), voxel_gi_tex))) {
+ voxel_gi_compute(i, vertex, normal, reflection, normal_mat, roughness, spec_accum, amb_accum, blend_accum);
}
}
if (blend_accum > 0.0) {
diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
new file mode 100644
index 0000000000..2fce258cff
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
@@ -0,0 +1,87 @@
+#define LIGHT_BAKE_DISABLED 0
+#define LIGHT_BAKE_DYNAMIC 1
+#define LIGHT_BAKE_STATIC 2
+
+struct LightData { //this structure needs to be as packed as possible
+ vec3 position;
+ float inv_radius;
+
+ vec3 direction;
+ float size;
+
+ vec3 color;
+ float attenuation;
+
+ float cone_attenuation;
+ float cone_angle;
+ float specular_amount;
+ bool shadow_enabled;
+
+ vec4 atlas_rect; // rect in the shadow atlas
+ mat4 shadow_matrix;
+ float shadow_bias;
+ float shadow_normal_bias;
+ float transmittance_bias;
+ float soft_shadow_size; // for spot, it's the size in uv coordinates of the light, for omni it's the span angle
+ float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
+ uint mask;
+ float shadow_volumetric_fog_fade;
+ uint bake_mode;
+ vec4 projector_rect; //projector rect in srgb decal atlas
+};
+
+#define REFLECTION_AMBIENT_DISABLED 0
+#define REFLECTION_AMBIENT_ENVIRONMENT 1
+#define REFLECTION_AMBIENT_COLOR 2
+
+struct ReflectionData {
+ vec3 box_extents;
+ float index;
+ vec3 box_offset;
+ uint mask;
+ vec3 ambient; // ambient color
+ float intensity;
+ bool exterior;
+ bool box_project;
+ uint ambient_mode;
+ uint pad;
+ //0-8 is intensity,8-9 is ambient, mode
+ mat4 local_matrix; // up to here for spot and omni, rest is for directional
+ // notes: for ambientblend, use distance to edge to blend between already existing global environment
+};
+
+struct DirectionalLightData {
+ vec3 direction;
+ float energy;
+ vec3 color;
+ float size;
+ float specular;
+ uint mask;
+ float softshadow_angle;
+ float soft_shadow_scale;
+ bool blend_splits;
+ bool shadow_enabled;
+ float fade_from;
+ float fade_to;
+ uvec2 pad;
+ uint bake_mode;
+ float shadow_volumetric_fog_fade;
+ vec4 shadow_bias;
+ vec4 shadow_normal_bias;
+ vec4 shadow_transmittance_bias;
+ vec4 shadow_z_range;
+ vec4 shadow_range_begin;
+ vec4 shadow_split_offsets;
+ mat4 shadow_matrix1;
+ mat4 shadow_matrix2;
+ mat4 shadow_matrix3;
+ mat4 shadow_matrix4;
+ vec4 shadow_color1;
+ vec4 shadow_color2;
+ vec4 shadow_color3;
+ vec4 shadow_color4;
+ vec2 uv_scale1;
+ vec2 uv_scale2;
+ vec2 uv_scale3;
+ vec2 uv_scale4;
+};
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index 3712220dc4..9f8410fd8a 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -19,6 +19,8 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
+#define SDF_MAX_LENGTH 16384.0
+
/* SET 0: GLOBAL DATA */
layout(set = 0, binding = 1) uniform sampler material_samplers[12];
@@ -54,6 +56,7 @@ struct Attractor {
#define COLLIDER_TYPE_BOX 1
#define COLLIDER_TYPE_SDF 2
#define COLLIDER_TYPE_HEIGHT_FIELD 3
+#define COLLIDER_TYPE_2D_SDF 4
struct Collider {
mat4 transform;
@@ -76,6 +79,11 @@ struct FrameParams {
float time;
float delta;
+ uint frame;
+ uint pad0;
+ uint pad1;
+ uint pad2;
+
uint random_seed;
uint attractor_count;
uint collider_count;
@@ -92,10 +100,16 @@ layout(set = 1, binding = 0, std430) restrict buffer FrameHistory {
}
frame_history;
+#define PARTICLE_FLAG_ACTIVE uint(1)
+#define PARTICLE_FLAG_STARTED uint(2)
+#define PARTICLE_FLAG_TRAILED uint(4)
+#define PARTICLE_FRAME_MASK uint(0xFFFF)
+#define PARTICLE_FRAME_SHIFT uint(16)
+
struct ParticleData {
mat4 xform;
vec3 velocity;
- bool is_active;
+ uint flags;
vec4 color;
vec4 custom;
};
@@ -162,7 +176,7 @@ layout(push_constant, binding = 0, std430) uniform Params {
bool use_fractional_delta;
bool sub_emitter_mode;
bool can_emit;
- uint pad;
+ bool trail_pass;
}
params;
@@ -201,6 +215,14 @@ bool emit_subparticle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom
void main() {
uint particle = gl_GlobalInvocationID.x;
+ if (params.trail_size > 1) {
+ if (params.trail_pass) {
+ particle += (particle / (params.trail_size - 1)) + 1;
+ } else {
+ particle *= params.trail_size;
+ }
+ }
+
if (particle >= params.total_particles * params.trail_size) {
return; //discard
}
@@ -229,7 +251,7 @@ void main() {
PARTICLE.color = vec4(1.0);
PARTICLE.custom = vec4(0.0);
PARTICLE.velocity = vec3(0.0);
- PARTICLE.is_active = false;
+ PARTICLE.flags = 0;
PARTICLE.xform = mat4(
vec4(1.0, 0.0, 0.0, 0.0),
vec4(0.0, 1.0, 0.0, 0.0),
@@ -237,6 +259,29 @@ void main() {
vec4(0.0, 0.0, 0.0, 1.0));
}
+ //clear started flag if set
+
+ if (params.trail_pass) {
+ //trail started
+ uint src_idx = index * params.trail_size;
+ if (bool(particles.data[src_idx].flags & PARTICLE_FLAG_STARTED)) {
+ //save start conditions for trails
+ PARTICLE.color = particles.data[src_idx].color;
+ PARTICLE.custom = particles.data[src_idx].custom;
+ PARTICLE.velocity = particles.data[src_idx].velocity;
+ PARTICLE.flags = PARTICLE_FLAG_TRAILED | ((frame_history.data[0].frame & PARTICLE_FRAME_MASK) << PARTICLE_FRAME_SHIFT); //mark it as trailed, save in which frame it will start
+ PARTICLE.xform = particles.data[src_idx].xform;
+ }
+
+ if (bool(PARTICLE.flags & PARTICLE_FLAG_TRAILED) && ((PARTICLE.flags >> PARTICLE_FRAME_SHIFT) == (FRAME.frame & PARTICLE_FRAME_MASK))) { //check this is trailed and see if it should start now
+ // we just assume that this is the first frame of the particle, the rest is deterministic
+ PARTICLE.flags = PARTICLE_FLAG_ACTIVE | (particles.data[src_idx].flags & (PARTICLE_FRAME_MASK << PARTICLE_FRAME_SHIFT));
+ return; //- this appears like it should be correct, but it seems not to be.. wonder why.
+ }
+ } else {
+ PARTICLE.flags &= ~PARTICLE_FLAG_STARTED;
+ }
+
bool collided = false;
vec3 collision_normal = vec3(0.0);
float collision_depth = 0.0;
@@ -245,19 +290,17 @@ void main() {
#if !defined(DISABLE_VELOCITY)
- if (PARTICLE.is_active) {
+ if (bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE)) {
PARTICLE.xform[3].xyz += PARTICLE.velocity * local_delta;
}
#endif
- /* Process physics if active */
-
- if (params.sub_emitter_mode) {
- if (!PARTICLE.is_active) {
+ if (!params.trail_pass && params.sub_emitter_mode) {
+ if (!bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE)) {
int src_index = atomicAdd(src_particles.particle_count, -1) - 1;
if (src_index >= 0) {
- PARTICLE.is_active = true;
+ PARTICLE.flags = (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (FRAME.cycle << PARTICLE_FRAME_SHIFT));
restart = true;
if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) {
@@ -339,16 +382,12 @@ void main() {
}
}
- uint current_cycle = FRAME.cycle;
-
- if (FRAME.system_phase < restart_phase) {
- current_cycle -= uint(1);
+ if (params.trail_pass) {
+ restart = false;
}
- uint particle_number = current_cycle * uint(params.total_particles) + particle;
-
if (restart) {
- PARTICLE.is_active = FRAME.emitting;
+ PARTICLE.flags = FRAME.emitting ? (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (FRAME.cycle << PARTICLE_FRAME_SHIFT)) : 0;
restart_position = true;
restart_rotation_scale = true;
restart_velocity = true;
@@ -357,11 +396,15 @@ void main() {
}
}
- if (restart && PARTICLE.is_active) {
+ bool particle_active = bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE);
+
+ uint particle_number = (PARTICLE.flags >> PARTICLE_FRAME_SHIFT) * uint(params.total_particles) + index;
+
+ if (restart && particle_active) {
#CODE : START
}
- if (PARTICLE.is_active) {
+ if (particle_active) {
for (uint i = 0; i < FRAME.attractor_count; i++) {
vec3 dir;
float amount;
@@ -412,134 +455,178 @@ void main() {
#endif
- for (uint i = 0; i < FRAME.collider_count; i++) {
- vec3 normal;
- float depth;
- bool col = false;
+ if (FRAME.collider_count == 1 && FRAME.colliders[0].type == COLLIDER_TYPE_2D_SDF) {
+ //2D collision
- vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz;
- vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform);
+ vec2 pos = PARTICLE.xform[3].xy;
+ vec4 to_sdf_x = FRAME.colliders[0].transform[0];
+ vec4 to_sdf_y = FRAME.colliders[0].transform[1];
+ vec2 sdf_pos = vec2(dot(vec4(pos, 0, 1), to_sdf_x), dot(vec4(pos, 0, 1), to_sdf_y));
- switch (FRAME.colliders[i].type) {
- case COLLIDER_TYPE_SPHERE: {
- float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x);
+ vec4 sdf_to_screen = vec4(FRAME.colliders[0].extents, FRAME.colliders[0].scale);
- if (d < 0.0) {
- col = true;
- depth = -d;
- normal = normalize(rel_vec);
- }
+ vec2 uv_pos = sdf_pos * sdf_to_screen.xy + sdf_to_screen.zw;
- } break;
- case COLLIDER_TYPE_BOX: {
- vec3 abs_pos = abs(local_pos);
- vec3 sgn_pos = sign(local_pos);
+ if (all(greaterThan(uv_pos, vec2(0.0))) && all(lessThan(uv_pos, vec2(1.0)))) {
+ vec2 pos2 = pos + vec2(0, particle_size);
+ vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y));
+ float sdf_particle_size = distance(sdf_pos, sdf_pos2);
+
+ float d = texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos).r * SDF_MAX_LENGTH;
+
+ d -= sdf_particle_size;
+
+ if (d < 0.0) {
+ const float EPSILON = 0.001;
+ vec2 n = normalize(vec2(
+ texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(EPSILON, 0.0)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(EPSILON, 0.0)).r,
+ texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos + vec2(0.0, EPSILON)).r - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uv_pos - vec2(0.0, EPSILON)).r));
+
+ collided = true;
+ sdf_pos2 = sdf_pos + n * d;
+ pos2 = vec2(dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[2]), dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[3]));
+
+ n = pos - pos2;
+
+ collision_normal = normalize(vec3(n, 0.0));
+ collision_depth = length(n);
+ }
+ }
+
+ } else {
+ for (uint i = 0; i < FRAME.collider_count; i++) {
+ vec3 normal;
+ float depth;
+ bool col = false;
- if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) {
- //point outside box
+ vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz;
+ vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform);
- vec3 closest = min(abs_pos, FRAME.colliders[i].extents);
- vec3 rel = abs_pos - closest;
- depth = length(rel) - particle_size;
- if (depth < 0.0) {
+ switch (FRAME.colliders[i].type) {
+ case COLLIDER_TYPE_SPHERE: {
+ float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x);
+
+ if (d < 0.0) {
col = true;
- normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos);
- depth = -depth;
+ depth = -d;
+ normal = normalize(rel_vec);
}
- } else {
- //point inside box
- vec3 axis_len = FRAME.colliders[i].extents - abs_pos;
- // there has to be a faster way to do this?
- if (all(lessThan(axis_len.xx, axis_len.yz))) {
- normal = vec3(1, 0, 0);
- } else if (all(lessThan(axis_len.yy, axis_len.xz))) {
- normal = vec3(0, 1, 0);
+
+ } break;
+ case COLLIDER_TYPE_BOX: {
+ vec3 abs_pos = abs(local_pos);
+ vec3 sgn_pos = sign(local_pos);
+
+ if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) {
+ //point outside box
+
+ vec3 closest = min(abs_pos, FRAME.colliders[i].extents);
+ vec3 rel = abs_pos - closest;
+ depth = length(rel) - particle_size;
+ if (depth < 0.0) {
+ col = true;
+ normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos);
+ depth = -depth;
+ }
} else {
- normal = vec3(0, 0, 1);
+ //point inside box
+ vec3 axis_len = FRAME.colliders[i].extents - abs_pos;
+ // there has to be a faster way to do this?
+ if (all(lessThan(axis_len.xx, axis_len.yz))) {
+ normal = vec3(1, 0, 0);
+ } else if (all(lessThan(axis_len.yy, axis_len.xz))) {
+ normal = vec3(0, 1, 0);
+ } else {
+ normal = vec3(0, 0, 1);
+ }
+
+ col = true;
+ depth = dot(normal * axis_len, vec3(1)) + particle_size;
+ normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos);
}
- col = true;
- depth = dot(normal * axis_len, vec3(1)) + particle_size;
- normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos);
- }
+ } break;
+ case COLLIDER_TYPE_SDF: {
+ vec3 apos = abs(local_pos);
+ float extra_dist = 0.0;
+ if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside
+ vec3 mpos = min(apos, FRAME.colliders[i].extents);
+ extra_dist = distance(mpos, apos);
+ }
- } break;
- case COLLIDER_TYPE_SDF: {
- vec3 apos = abs(local_pos);
- float extra_dist = 0.0;
- if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside
- vec3 mpos = min(apos, FRAME.colliders[i].extents);
- extra_dist = distance(mpos, apos);
- }
+ if (extra_dist > particle_size) {
+ continue;
+ }
- if (extra_dist > particle_size) {
- continue;
- }
+ vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5;
+ float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r;
+ s *= FRAME.colliders[i].scale;
+ s += extra_dist;
+ if (s < particle_size) {
+ col = true;
+ depth = particle_size - s;
+ const float EPSILON = 0.001;
+ normal = mat3(FRAME.colliders[i].transform) *
+ normalize(
+ vec3(
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
+ texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
+ }
- vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5;
- float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).r;
- s *= FRAME.colliders[i].scale;
- s += extra_dist;
- if (s < particle_size) {
- col = true;
- depth = particle_size - s;
- const float EPSILON = 0.001;
- normal = mat3(FRAME.colliders[i].transform) *
- normalize(
- vec3(
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
- }
+ } break;
+ case COLLIDER_TYPE_HEIGHT_FIELD: {
+ vec3 local_pos_bottom = local_pos;
+ local_pos_bottom.y -= particle_size;
- } break;
- case COLLIDER_TYPE_HEIGHT_FIELD: {
- vec3 local_pos_bottom = local_pos;
- local_pos_bottom.y -= particle_size;
+ if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) {
+ continue;
+ }
+ const float DELTA = 1.0 / 8192.0;
- if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) {
- continue;
- }
+ vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
- const float DELTA = 1.0 / 8192.0;
+ float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
- vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
+ if (y > uvw_pos.y) {
+ //inside heightfield
- float y = 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz).r;
+ vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- if (y > uvw_pos.y) {
- //inside heightfield
+ normal = normalize(cross(pos1 - pos2, pos1 - pos3));
+ float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
- vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- vec3 pos2 = (vec3(uvw_pos.x + DELTA, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- vec3 pos3 = (vec3(uvw_pos.x, 1.0 - texture(sampler2D(height_field_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
+ col = true;
+ depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
+ }
- normal = normalize(cross(pos1 - pos2, pos1 - pos3));
- float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
+ } break;
+ }
- col = true;
- depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
+ if (col) {
+ if (!collided) {
+ collided = true;
+ collision_normal = normal;
+ collision_depth = depth;
+ } else {
+ vec3 c = collision_normal * collision_depth;
+ c += normal * max(0.0, depth - dot(normal, c));
+ collision_normal = normalize(c);
+ collision_depth = length(c);
}
-
- } break;
- }
-
- if (col) {
- if (!collided) {
- collided = true;
- collision_normal = normal;
- collision_depth = depth;
- } else {
- vec3 c = collision_normal * collision_depth;
- c += normal * max(0.0, depth - dot(normal, c));
- collision_normal = normalize(c);
- collision_depth = length(c);
}
}
}
}
- if (PARTICLE.is_active) {
+ if (particle_active) {
#CODE : PROCESS
}
+
+ PARTICLE.flags &= ~PARTICLE_FLAG_ACTIVE;
+ if (particle_active) {
+ PARTICLE.flags |= PARTICLE_FLAG_ACTIVE;
+ }
}
diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
index 80adb49619..4dceeea995 100644
--- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
@@ -6,10 +6,14 @@
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+#define PARTICLE_FLAG_ACTIVE uint(1)
+#define PARTICLE_FLAG_STARTED uint(2)
+#define PARTICLE_FLAG_TRAILED uint(4)
+
struct ParticleData {
mat4 xform;
vec3 velocity;
- bool is_active;
+ uint flags;
vec4 color;
vec4 custom;
};
@@ -33,12 +37,35 @@ sort_buffer;
#endif // USE_SORT_BUFFER
+layout(set = 2, binding = 0, std430) restrict readonly buffer TrailBindPoses {
+ mat4 data[];
+}
+trail_bind_poses;
+
layout(push_constant, binding = 0, std430) uniform Params {
vec3 sort_direction;
uint total_particles;
+
+ uint trail_size;
+ uint trail_total;
+ float frame_delta;
+ float frame_remainder;
+
+ vec3 align_up;
+ uint align_mode;
+
+ bool order_by_lifetime;
+ uint lifetime_split;
+ bool lifetime_reverse;
+ uint pad;
}
params;
+#define TRANSFORM_ALIGN_DISABLED 0
+#define TRANSFORM_ALIGN_Z_BILLBOARD 1
+#define TRANSFORM_ALIGN_Y_TO_VELOCITY 2
+#define TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY 3
+
void main() {
#ifdef MODE_FILL_SORT_BUFFER
@@ -47,36 +74,152 @@ void main() {
return; //discard
}
- sort_buffer.data[particle].x = dot(params.sort_direction, particles.data[particle].xform[3].xyz);
+ uint src_particle = particle;
+ if (params.trail_size > 1) {
+ src_particle = src_particle * params.trail_size + params.trail_size / 2; //use trail center for sorting
+ }
+ sort_buffer.data[particle].x = dot(params.sort_direction, particles.data[src_particle].xform[3].xyz);
sort_buffer.data[particle].y = float(particle);
#endif
#ifdef MODE_FILL_INSTANCES
uint particle = gl_GlobalInvocationID.x;
- uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom
if (particle >= params.total_particles) {
return; //discard
}
#ifdef USE_SORT_BUFFER
- particle = uint(sort_buffer.data[particle].y); //use index from sort buffer
-#endif
+
+ if (params.trail_size > 1) {
+ particle = uint(sort_buffer.data[particle / params.trail_size].y) + (particle % params.trail_size);
+ } else {
+ particle = uint(sort_buffer.data[particle].y); //use index from sort buffer
+ }
+#else
+ if (params.order_by_lifetime) {
+ if (params.trail_size > 1) {
+ uint limit = (params.total_particles / params.trail_size) - params.lifetime_split;
+
+ uint base_index = particle / params.trail_size;
+ uint base_offset = particle % params.trail_size;
+
+ if (params.lifetime_reverse) {
+ base_index = (params.total_particles / params.trail_size) - base_index - 1;
+ }
+
+ if (base_index < limit) {
+ base_index = params.lifetime_split + base_index;
+ } else {
+ base_index -= limit;
+ }
+
+ particle = base_index * params.trail_size + base_offset;
+
+ } else {
+ uint limit = params.total_particles - params.lifetime_split;
+
+ if (params.lifetime_reverse) {
+ particle = params.total_particles - particle - 1;
+ }
+
+ if (particle < limit) {
+ particle = params.lifetime_split + particle;
+ } else {
+ particle -= limit;
+ }
+ }
+ }
+#endif // USE_SORT_BUFFER
mat4 txform;
- if (particles.data[particle].is_active) {
- txform = transpose(particles.data[particle].xform);
+ if (bool(particles.data[particle].flags & PARTICLE_FLAG_ACTIVE) || bool(particles.data[particle].flags & PARTICLE_FLAG_TRAILED)) {
+ txform = particles.data[particle].xform;
+ if (params.trail_size > 1) {
+ // since the steps dont fit precisely in the history frames, must do a tiny bit of
+ // interpolation to get them close to their intended location.
+ uint part_ofs = particle % params.trail_size;
+ float natural_ofs = fract((float(part_ofs) / float(params.trail_size)) * float(params.trail_total)) * params.frame_delta;
+
+ txform[3].xyz -= particles.data[particle].velocity * natural_ofs;
+ }
+
+ switch (params.align_mode) {
+ case TRANSFORM_ALIGN_DISABLED: {
+ } break; //nothing
+ case TRANSFORM_ALIGN_Z_BILLBOARD: {
+ mat3 local = mat3(normalize(cross(params.align_up, params.sort_direction)), params.align_up, params.sort_direction);
+ local = local * mat3(txform);
+ txform[0].xyz = local[0];
+ txform[1].xyz = local[1];
+ txform[2].xyz = local[2];
+
+ } break;
+ case TRANSFORM_ALIGN_Y_TO_VELOCITY: {
+ vec3 v = particles.data[particle].velocity;
+ float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
+ if (length(v) > 0.0) {
+ txform[1].xyz = normalize(v);
+ } else {
+ txform[1].xyz = normalize(txform[1].xyz);
+ }
+
+ txform[0].xyz = normalize(cross(txform[1].xyz, txform[2].xyz));
+ txform[2].xyz = vec3(0.0, 0.0, 1.0) * s;
+ txform[0].xyz *= s;
+ txform[1].xyz *= s;
+ } break;
+ case TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY: {
+ vec3 v = particles.data[particle].velocity;
+ vec3 sv = v - params.sort_direction * dot(params.sort_direction, v); //screen velocity
+ float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0;
+
+ if (length(sv) == 0) {
+ sv = params.align_up;
+ }
+
+ sv = normalize(sv);
+
+ txform[0].xyz = normalize(cross(sv, params.sort_direction)) * s;
+ txform[1].xyz = sv * s;
+ txform[2].xyz = params.sort_direction * s;
+
+ } break;
+ }
+
+ txform[3].xyz += particles.data[particle].velocity * params.frame_remainder;
+
+ if (params.trail_size > 1) {
+ uint part_ofs = particle % params.trail_size;
+ txform = txform * trail_bind_poses.data[part_ofs];
+ }
+
+ txform = transpose(txform);
} else {
txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible
}
+#ifdef MODE_2D
+
+ uint write_offset = gl_GlobalInvocationID.x * (2 + 1 + 1); //xform + color + custom
+
+ instances.data[write_offset + 0] = txform[0];
+ instances.data[write_offset + 1] = txform[1];
+ instances.data[write_offset + 2] = particles.data[particle].color;
+ instances.data[write_offset + 3] = particles.data[particle].custom;
+
+#else
+
+ uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom
+
instances.data[write_offset + 0] = txform[0];
instances.data[write_offset + 1] = txform[1];
instances.data[write_offset + 2] = txform[2];
instances.data[write_offset + 3] = particles.data[particle].color;
instances.data[write_offset + 4] = particles.data[particle].custom;
+#endif //MODE_2D
#endif
}
diff --git a/servers/rendering/renderer_rd/shaders/resolve.glsl b/servers/rendering/renderer_rd/shaders/resolve.glsl
index 2286a26485..a4610e081c 100644
--- a/servers/rendering/renderer_rd/shaders/resolve.glsl
+++ b/servers/rendering/renderer_rd/shaders/resolve.glsl
@@ -13,9 +13,9 @@ layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness;
layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth;
layout(rgba8, set = 1, binding = 1) uniform restrict writeonly image2D dest_normal_roughness;
-#ifdef GIPROBE_RESOLVE
-layout(set = 2, binding = 0) uniform usampler2DMS source_giprobe;
-layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_giprobe;
+#ifdef VOXEL_GI_RESOLVE
+layout(set = 2, binding = 0) uniform usampler2DMS source_voxel_gi;
+layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_voxel_gi;
#endif
#endif
@@ -38,8 +38,8 @@ void main() {
float best_depth = 1e20;
vec4 best_normal_roughness = vec4(0.0);
-#ifdef GIPROBE_RESOLVE
- uvec2 best_giprobe;
+#ifdef VOXEL_GI_RESOLVE
+ uvec2 best_voxel_gi;
#endif
#if 0
@@ -50,8 +50,8 @@ void main() {
best_depth = depth;
best_normal_roughness = texelFetch(source_normal_roughness,pos,i);
-#ifdef GIPROBE_RESOLVE
- best_giprobe = texelFetch(source_giprobe,pos,i).rg;
+#ifdef VOXEL_GI_RESOLVE
+ best_voxel_gi = texelFetch(source_voxel_gi,pos,i).rg;
#endif
}
}
@@ -204,16 +204,16 @@ void main() {
#endif
best_depth = texelFetch(source_depth, pos, best_index).r;
best_normal_roughness = texelFetch(source_normal_roughness, pos, best_index);
-#ifdef GIPROBE_RESOLVE
- best_giprobe = texelFetch(source_giprobe, pos, best_index).rg;
+#ifdef VOXEL_GI_RESOLVE
+ best_voxel_gi = texelFetch(source_voxel_gi, pos, best_index).rg;
#endif
#endif
imageStore(dest_depth, pos, vec4(best_depth));
imageStore(dest_normal_roughness, pos, vec4(best_normal_roughness));
-#ifdef GIPROBE_RESOLVE
- imageStore(dest_giprobe, pos, uvec4(best_giprobe, 0, 0));
+#ifdef VOXEL_GI_RESOLVE
+ imageStore(dest_voxel_gi, pos, uvec4(best_voxel_gi, 0, 0));
#endif
#endif
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl
new file mode 100644
index 0000000000..99714b4504
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl
@@ -0,0 +1,58 @@
+#ifdef ALPHA_HASH_USED
+
+float hash_2d(vec2 p) {
+ return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) *
+ (0.1 + abs(sin(13.0 * p.y + p.x))));
+}
+
+float hash_3d(vec3 p) {
+ return hash_2d(vec2(hash_2d(p.xy), p.z));
+}
+
+float compute_alpha_hash_threshold(vec3 pos, float hash_scale) {
+ vec3 dx = dFdx(pos);
+ vec3 dy = dFdx(pos);
+ float delta_max_sqr = max(length(dx), length(dy));
+ float pix_scale = 1.0 / (hash_scale * delta_max_sqr);
+
+ vec2 pix_scales =
+ vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale))));
+
+ vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)),
+ hash_3d(floor(pix_scales.y * pos.xyz)));
+
+ float lerp_factor = fract(log2(pix_scale));
+
+ float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y;
+
+ float min_lerp = min(lerp_factor, 1.0 - lerp_factor);
+
+ vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)),
+ (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp),
+ 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) /
+ (2.0 * min_lerp * (1.0 - min_lerp))));
+
+ float alpha_hash_threshold =
+ (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z;
+
+ return clamp(alpha_hash_threshold, 0.0, 1.0);
+}
+
+#endif // ALPHA_HASH_USED
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+
+float calc_mip_level(vec2 texture_coord) {
+ vec2 dx = dFdx(texture_coord);
+ vec2 dy = dFdy(texture_coord);
+ float delta_max_sqr = max(dot(dx, dx), dot(dy, dy));
+ return max(0.0, 0.5 * log2(delta_max_sqr));
+}
+
+float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) {
+ input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number
+ input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5;
+ return clamp(input_alpha, 0.0, 1.0);
+}
+
+#endif // ALPHA_ANTIALIASING_USED
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index fce17c47e8..8538030263 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -48,11 +48,11 @@ layout(location = 8) in vec4 custom2_attrib;
layout(location = 9) in vec4 custom3_attrib;
#endif
-#if defined(BONES_USED)
+#if defined(BONES_USED) || defined(USE_PARTICLE_TRAILS)
layout(location = 10) in uvec4 bone_attrib;
#endif
-#if defined(WEIGHTS_USED)
+#if defined(WEIGHTS_USED) || defined(USE_PARTICLE_TRAILS)
layout(location = 11) in vec4 weight_attrib;
#endif
@@ -89,8 +89,6 @@ layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms
} material;
#endif
-invariant gl_Position;
-
#ifdef MODE_DUAL_PARABOLOID
layout(location = 8) out float dp_clip;
@@ -99,6 +97,8 @@ layout(location = 8) out float dp_clip;
layout(location = 9) out flat uint instance_index;
+invariant gl_Position;
+
#GLOBALS
void main() {
@@ -125,10 +125,72 @@ void main() {
if (is_multimesh) {
//multimesh, instances are for it
- uint offset = (instances.data[instance_index].flags >> INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT) & INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK;
- offset *= gl_InstanceIndex;
mat4 matrix;
+
+#ifdef USE_PARTICLE_TRAILS
+ uint trail_size = (instances.data[instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK;
+ uint stride = 3 + 1 + 1; //particles always uses this format
+
+ uint offset = trail_size * stride * gl_InstanceIndex;
+
+#ifdef COLOR_USED
+ vec4 pcolor;
+#endif
+ {
+ uint boffset = offset + bone_attrib.x * stride;
+ matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x;
+#ifdef COLOR_USED
+ pcolor = transforms.data[boffset + 3] * weight_attrib.x;
+#endif
+ }
+ if (weight_attrib.y > 0.001) {
+ uint boffset = offset + bone_attrib.y * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.y;
+#endif
+ }
+ if (weight_attrib.z > 0.001) {
+ uint boffset = offset + bone_attrib.z * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.z;
+#endif
+ }
+ if (weight_attrib.w > 0.001) {
+ uint boffset = offset + bone_attrib.w * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.w;
+#endif
+ }
+
+ instance_custom = transforms.data[offset + 4];
+
+#ifdef COLOR_USED
+ color_interp *= pcolor;
+#endif
+
+#else
+ uint stride = 0;
+ {
+ //TODO implement a small lookup table for the stride
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ stride += 2;
+ } else {
+ stride += 3;
+ }
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+ stride += 1;
+ }
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ stride += 1;
+ }
+ }
+
+ uint offset = stride * gl_InstanceIndex;
+
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
offset += 2;
@@ -148,6 +210,7 @@ void main() {
instance_custom = transforms.data[offset];
}
+#endif
//transpose
matrix = transpose(matrix);
world_matrix = world_matrix * matrix;
@@ -165,32 +228,6 @@ void main() {
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
-#if 0
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) {
- //multimesh, instances are for it
-
- uvec2 bones_01 = uvec2(bone_attrib.x & 0xFFFF, bone_attrib.x >> 16) * 3;
- uvec2 bones_23 = uvec2(bone_attrib.y & 0xFFFF, bone_attrib.y >> 16) * 3;
- vec2 weights_01 = unpackUnorm2x16(bone_attrib.z);
- vec2 weights_23 = unpackUnorm2x16(bone_attrib.w);
-
- mat4 m = mat4(transforms.data[bones_01.x], transforms.data[bones_01.x + 1], transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x;
- m += mat4(transforms.data[bones_01.y], transforms.data[bones_01.y + 1], transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y;
- m += mat4(transforms.data[bones_23.x], transforms.data[bones_23.x + 1], transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x;
- m += mat4(transforms.data[bones_23.y], transforms.data[bones_23.y + 1], transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y;
-
- //reverse order because its transposed
- vertex = (vec4(vertex, 1.0) * m).xyz;
- normal = (vec4(normal, 0.0) * m).xyz;
-
-#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-
- tangent = (vec4(tangent, 0.0) * m).xyz;
- binormal = (vec4(binormal, 0.0) * m).xyz;
-#endif
- }
-#endif
-
#ifdef UV_USED
uv_interp = uv_attrib;
#endif
@@ -384,13 +421,13 @@ layout(location = 2) out vec4 orm_output_buffer;
layout(location = 3) out vec4 emission_output_buffer;
layout(location = 4) out float depth_output_buffer;
-#endif
+#endif // MODE_RENDER_MATERIAL
#ifdef MODE_RENDER_NORMAL_ROUGHNESS
layout(location = 0) out vec4 normal_roughness_output_buffer;
-#ifdef MODE_RENDER_GIPROBE
-layout(location = 1) out uvec2 giprobe_buffer;
+#ifdef MODE_RENDER_VOXEL_GI
+layout(location = 1) out uvec2 voxel_gi_buffer;
#endif
#endif //MODE_RENDER_NORMAL
@@ -403,1315 +440,19 @@ layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface sc
#else
layout(location = 0) out vec4 frag_color;
-#endif
+#endif // MODE_MULTIPLE_RENDER_TARGETS
#endif // RENDER DEPTH
-#ifdef ALPHA_HASH_USED
-
-float hash_2d(vec2 p) {
- return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) *
- (0.1 + abs(sin(13.0 * p.y + p.x))));
-}
-
-float hash_3d(vec3 p) {
- return hash_2d(vec2(hash_2d(p.xy), p.z));
-}
-
-float compute_alpha_hash_threshold(vec3 pos, float hash_scale) {
- vec3 dx = dFdx(pos);
- vec3 dy = dFdx(pos);
- float delta_max_sqr = max(length(dx), length(dy));
- float pix_scale = 1.0 / (hash_scale * delta_max_sqr);
-
- vec2 pix_scales =
- vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale))));
-
- vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)),
- hash_3d(floor(pix_scales.y * pos.xyz)));
-
- float lerp_factor = fract(log2(pix_scale));
-
- float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y;
-
- float min_lerp = min(lerp_factor, 1.0 - lerp_factor);
-
- vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)),
- (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp),
- 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) /
- (2.0 * min_lerp * (1.0 - min_lerp))));
-
- float alpha_hash_threshold =
- (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z;
-
- return clamp(alpha_hash_threshold, 0.0, 1.0);
-}
-
-#endif // ALPHA_HASH_USED
-
-#ifdef ALPHA_ANTIALIASING_EDGE_USED
-
-float calc_mip_level(vec2 texture_coord) {
- vec2 dx = dFdx(texture_coord);
- vec2 dy = dFdy(texture_coord);
- float delta_max_sqr = max(dot(dx, dx), dot(dy, dy));
- return max(0.0, 0.5 * log2(delta_max_sqr));
-}
-
-float compute_alpha_antialiasing_edge(float input_alpha, vec2 texture_coord, float alpha_edge) {
- input_alpha *= 1.0 + max(0, calc_mip_level(texture_coord)) * 0.25; // 0.25 mip scale, magic number
- input_alpha = (input_alpha - alpha_edge) / max(fwidth(input_alpha), 0.0001) + 0.5;
- return clamp(input_alpha, 0.0, 1.0);
-}
-
-#endif // ALPHA_ANTIALIASING_USED
-
-// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V.
-// We're dividing this factor off because the overall term we'll end up looks like
-// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012):
-//
-// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V)
-//
-// We're basically regouping this as
-//
-// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)]
-//
-// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V.
-//
-// The contents of the D and G (G1) functions (GGX) are taken from
-// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014).
-// Eqns 71-72 and 85-86 (see also Eqns 43 and 80).
+#include "scene_forward_aa_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-float G_GGX_2cos(float cos_theta_m, float alpha) {
- // Schlick's approximation
- // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994)
- // Eq. (19), although see Heitz (2014) the about the problems with his derivation.
- // It nevertheless approximates GGX well with k = alpha/2.
- float k = 0.5 * alpha;
- return 0.5 / (cos_theta_m * (1.0 - k) + k);
-
- // float cos2 = cos_theta_m * cos_theta_m;
- // float sin2 = (1.0 - cos2);
- // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2));
-}
-
-float D_GGX(float cos_theta_m, float alpha) {
- float alpha2 = alpha * alpha;
- float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m;
- return alpha2 / (M_PI * d * d);
-}
-
-float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
- float cos2 = cos_theta_m * cos_theta_m;
- float sin2 = (1.0 - cos2);
- float s_x = alpha_x * cos_phi;
- float s_y = alpha_y * sin_phi;
- return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001);
-}
-
-float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
- float cos2 = cos_theta_m * cos_theta_m;
- float sin2 = (1.0 - cos2);
- float r_x = cos_phi / alpha_x;
- float r_y = sin_phi / alpha_y;
- float d = cos2 + sin2 * (r_x * r_x + r_y * r_y);
- return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001);
-}
-
-float SchlickFresnel(float u) {
- float m = 1.0 - u;
- float m2 = m * m;
- return m2 * m2 * m; // pow(m,5)
-}
-
-float GTR1(float NdotH, float a) {
- if (a >= 1.0)
- return 1.0 / M_PI;
- float a2 = a * a;
- float t = 1.0 + (a2 - 1.0) * NdotH * NdotH;
- return (a2 - 1.0) / (M_PI * log(a2) * t);
-}
-
-vec3 F0(float metallic, float specular, vec3 albedo) {
- float dielectric = 0.16 * specular * specular;
- // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials;
- // see https://google.github.io/filament/Filament.md.html
- return mix(vec3(dielectric), albedo, vec3(metallic));
-}
-
-void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount,
-#ifdef LIGHT_BACKLIGHT_USED
- vec3 backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- vec4 transmittance_color,
- float transmittance_depth,
- float transmittance_curve,
- float transmittance_boost,
- float transmittance_z,
-#endif
-#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- float clearcoat, float clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- vec3 B, vec3 T, float anisotropy,
-#endif
-#ifdef USE_SOFT_SHADOWS
- float A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
- inout vec3 diffuse_light, inout vec3 specular_light) {
-
-#if defined(LIGHT_CODE_USED)
- // light is written by the light shader
-
- vec3 normal = N;
- vec3 light = L;
- vec3 view = V;
-
-#CODE : LIGHT
-
-#else
-
-#ifdef USE_SOFT_SHADOWS
- float NdotL = min(A + dot(N, L), 1.0);
-#else
- float NdotL = dot(N, L);
-#endif
- float cNdotL = max(NdotL, 0.0); // clamped NdotL
- float NdotV = dot(N, V);
- float cNdotV = max(NdotV, 0.0);
-
-#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
- vec3 H = normalize(V + L);
-#endif
-
-#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-#ifdef USE_SOFT_SHADOWS
- float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
-#else
- float cNdotH = clamp(dot(N, H), 0.0, 1.0);
-#endif
-#endif
-
-#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-#ifdef USE_SOFT_SHADOWS
- float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
-#else
- float cLdotH = clamp(dot(L, H), 0.0, 1.0);
-#endif
-#endif
-
- float metallic = unpackUnorm4x8(orms).z;
- if (metallic < 1.0) {
- float roughness = unpackUnorm4x8(orms).y;
-
-#if defined(DIFFUSE_OREN_NAYAR)
- vec3 diffuse_brdf_NL;
-#else
- float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
-#endif
-
-#if defined(DIFFUSE_LAMBERT_WRAP)
- // energy conserving lambert wrap shader
- diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness)));
-#elif defined(DIFFUSE_TOON)
-
- diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL);
-
-#elif defined(DIFFUSE_BURLEY)
-
- {
- float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5;
- float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV);
- float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL);
- diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL;
- /*
- float energyBias = mix(roughness, 0.0, 0.5);
- float energyFactor = mix(roughness, 1.0, 1.0 / 1.51);
- float fd90 = energyBias + 2.0 * VoH * VoH * roughness;
- float f0 = 1.0;
- float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0);
- float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0);
-
- diffuse_brdf_NL = lightScatter * viewScatter * energyFactor;
- */
- }
-#else
- // lambert
- diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
-#endif
-
- diffuse_light += light_color * diffuse_brdf_NL * attenuation;
-
-#if defined(LIGHT_BACKLIGHT_USED)
- diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation;
-#endif
-
-#if defined(LIGHT_RIM_USED)
- float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
- diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color;
-#endif
-
-#ifdef LIGHT_TRANSMITTANCE_USED
-
-#ifdef SSS_MODE_SKIN
-
- {
- float scale = 8.25 / transmittance_depth;
- float d = scale * abs(transmittance_z);
- float dd = -d * d;
- vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
- vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
- vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
- vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
- vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
- vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
-
- diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
- }
-#else
-
- if (transmittance_depth > 0.0) {
- float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0);
-
- fade = pow(max(0.0, 1.0 - fade), transmittance_curve);
- fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0);
-
- diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade;
- }
-
-#endif //SSS_MODE_SKIN
-
-#endif //LIGHT_TRANSMITTANCE_USED
- }
-
- float roughness = unpackUnorm4x8(orms).y;
- if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
-
- // D
-
-#if defined(SPECULAR_BLINN)
-
- //normalized blinn
- float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
- float blinn = pow(cNdotH, shininess) * cNdotL;
- blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float intensity = blinn;
-
- specular_light += light_color * intensity * attenuation * specular_amount;
-
-#elif defined(SPECULAR_PHONG)
-
- vec3 R = normalize(-reflect(L, N));
- float cRdotV = clamp(A + dot(R, V), 0.0, 1.0);
- float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
- float phong = pow(cRdotV, shininess);
- phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
- float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75);
-
- specular_light += light_color * intensity * attenuation * specular_amount;
-
-#elif defined(SPECULAR_TOON)
-
- vec3 R = normalize(-reflect(L, N));
- float RdotV = dot(R, V);
- float mid = 1.0 - roughness;
- mid *= mid;
- float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid;
- diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection
-
-#elif defined(SPECULAR_DISABLED)
- // none..
-
-#elif defined(SPECULAR_SCHLICK_GGX)
- // shlick+ggx as default
-
-#if defined(LIGHT_ANISOTROPY_USED)
-
- float alpha_ggx = roughness * roughness;
- float aspect = sqrt(1.0 - anisotropy * 0.9);
- float ax = alpha_ggx / aspect;
- float ay = alpha_ggx * aspect;
- float XdotH = dot(T, H);
- float YdotH = dot(B, H);
- float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH);
- float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH);
-
-#else
- float alpha_ggx = roughness * roughness;
- float D = D_GGX(cNdotH, alpha_ggx);
- float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx);
-#endif
- // F
- float cLdotH5 = SchlickFresnel(cLdotH);
- vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0);
-
- vec3 specular_brdf_NL = cNdotL * D * F * G;
-
- specular_light += specular_brdf_NL * light_color * attenuation * specular_amount;
-#endif
-
-#if defined(LIGHT_CLEARCOAT_USED)
-
-#if !defined(SPECULAR_SCHLICK_GGX)
- float cLdotH5 = SchlickFresnel(cLdotH);
-#endif
- float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss));
- float Fr = mix(.04, 1.0, cLdotH5);
- float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25);
-
- float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL;
-
- specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount;
-#endif
- }
-
-#ifdef USE_SHADOW_TO_OPACITY
- alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0));
-#endif
-
-#endif //defined(LIGHT_CODE_USED)
-}
-
-#ifndef USE_NO_SHADOWS
-
-// Interleaved Gradient Noise
-// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
-float quick_hash(vec2 pos) {
- const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
- return fract(magic.z * fract(dot(pos, magic.xy)));
-}
-
-float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
- vec2 pos = coord.xy;
- float depth = coord.z;
-
- //if only one sample is taken, take it from the center
- if (scene_data.directional_soft_shadow_samples == 1) {
- return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
- }
-
- mat2 disk_rotation;
- {
- float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
- float sr = sin(r);
- float cr = cos(r);
- disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
- }
-
- float avg = 0.0;
-
- for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) {
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0));
- }
-
- return avg * (1.0 / float(scene_data.directional_soft_shadow_samples));
-}
-
-float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
- vec2 pos = coord.xy;
- float depth = coord.z;
-
- //if only one sample is taken, take it from the center
- if (scene_data.soft_shadow_samples == 1) {
- return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
- }
-
- mat2 disk_rotation;
- {
- float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
- float sr = sin(r);
- float cr = cos(r);
- disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
- }
-
- float avg = 0.0;
-
- for (uint i = 0; i < scene_data.soft_shadow_samples; i++) {
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0));
- }
-
- return avg * (1.0 / float(scene_data.soft_shadow_samples));
-}
-
-float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) {
- //find blocker
- float blocker_count = 0.0;
- float blocker_average = 0.0;
-
- mat2 disk_rotation;
- {
- float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
- float sr = sin(r);
- float cr = cos(r);
- disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
- }
-
- for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
- vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
- float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
- if (d < pssm_coord.z) {
- blocker_average += d;
- blocker_count += 1.0;
- }
- }
-
- if (blocker_count > 0.0) {
- //blockers found, do soft shadow
- blocker_average /= blocker_count;
- float penumbra = (pssm_coord.z - blocker_average) / blocker_average;
- tex_scale *= penumbra;
-
- float s = 0.0;
- for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
- vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
- s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0));
- }
-
- return s / float(scene_data.directional_penumbra_shadow_samples);
-
- } else {
- //no blockers found, so no shadow
- return 1.0;
- }
-}
-
-#endif //USE_NO_SHADOWS
-
-float get_omni_attenuation(float distance, float inv_range, float decay) {
- float nd = distance * inv_range;
- nd *= nd;
- nd *= nd; // nd^4
- nd = max(1.0 - nd, 0.0);
- nd *= nd; // nd^2
- return nd * pow(max(distance, 0.0001), -decay);
-}
-
-float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
-#ifndef USE_NO_SHADOWS
- if (omni_lights.data[idx].shadow_enabled) {
- // there is a shadowmap
-
- vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
-
- vec4 v = vec4(vertex, 1.0);
-
- vec4 splane = (omni_lights.data[idx].shadow_matrix * v);
- float shadow_len = length(splane.xyz); //need to remember shadow len from here
-
- {
- vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius;
- nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp))));
- v.xyz += nofs;
- splane = (omni_lights.data[idx].shadow_matrix * v);
- }
-
- float shadow;
-
-#ifdef USE_SOFT_SHADOWS
- if (omni_lights.data[idx].soft_shadow_size > 0.0) {
- //soft shadow
-
- //find blocker
-
- float blocker_count = 0.0;
- float blocker_average = 0.0;
-
- mat2 disk_rotation;
- {
- float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
- float sr = sin(r);
- float cr = cos(r);
- disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
- }
-
- vec3 normal = normalize(splane.xyz);
- vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
- vec3 tangent = normalize(cross(v0, normal));
- vec3 bitangent = normalize(cross(tangent, normal));
- float z_norm = shadow_len * omni_lights.data[idx].inv_radius;
-
- tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
- bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
-
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
- vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
-
- vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
-
- pos = normalize(pos);
- vec4 uv_rect = omni_lights.data[idx].atlas_rect;
-
- if (pos.z >= 0.0) {
- pos.z += 1.0;
- uv_rect.y += uv_rect.w;
- } else {
- pos.z = 1.0 - pos.z;
- }
-
- pos.xy /= pos.z;
-
- pos.xy = pos.xy * 0.5 + 0.5;
- pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
-
- float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r;
- if (d < z_norm) {
- blocker_average += d;
- blocker_count += 1.0;
- }
- }
-
- if (blocker_count > 0.0) {
- //blockers found, do soft shadow
- blocker_average /= blocker_count;
- float penumbra = (z_norm - blocker_average) / blocker_average;
- tangent *= penumbra;
- bitangent *= penumbra;
-
- z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias;
-
- shadow = 0.0;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
- vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
- vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
-
- pos = normalize(pos);
- vec4 uv_rect = omni_lights.data[idx].atlas_rect;
-
- if (pos.z >= 0.0) {
- pos.z += 1.0;
- uv_rect.y += uv_rect.w;
- } else {
- pos.z = 1.0 - pos.z;
- }
-
- pos.xy /= pos.z;
-
- pos.xy = pos.xy * 0.5 + 0.5;
- pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
- shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0));
- }
-
- shadow /= float(scene_data.penumbra_shadow_samples);
-
- } else {
- //no blockers found, so no shadow
- shadow = 1.0;
- }
- } else {
-#endif
- splane.xyz = normalize(splane.xyz);
- vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
-
- if (splane.z >= 0.0) {
- splane.z += 1.0;
-
- clamp_rect.y += clamp_rect.w;
-
- } else {
- splane.z = 1.0 - splane.z;
- }
-
- splane.xy /= splane.z;
-
- splane.xy = splane.xy * 0.5 + 0.5;
- splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius;
- splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
- splane.w = 1.0; //needed? i think it should be 1 already
- shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
-#ifdef USE_SOFT_SHADOWS
- }
-#endif
-
- return shadow;
- }
-#endif
-
- return 1.0;
-}
-
-void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
-#ifdef LIGHT_BACKLIGHT_USED
- vec3 backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- vec4 transmittance_color,
- float transmittance_depth,
- float transmittance_curve,
- float transmittance_boost,
-#endif
-#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- float clearcoat, float clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- vec3 binormal, vec3 tangent, float anisotropy,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
- inout vec3 diffuse_light, inout vec3 specular_light) {
- vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
- float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation);
- float light_attenuation = omni_attenuation;
- vec3 color = omni_lights.data[idx].color;
-
-#ifdef USE_SOFT_SHADOWS
- float size_A = 0.0;
-
- if (omni_lights.data[idx].size > 0.0) {
- float t = omni_lights.data[idx].size / max(0.001, light_length);
- size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
- }
-#endif
-
-#ifdef LIGHT_TRANSMITTANCE_USED
- float transmittance_z = transmittance_depth; //no transmittance by default
- transmittance_color.a *= light_attenuation;
- {
- vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
-
- //redo shadowmapping, but shrink the model a bit to avoid arctifacts
- vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0));
-
- shadow_len = length(splane.xyz);
- splane = normalize(splane.xyz);
-
- if (splane.z >= 0.0) {
- splane.z += 1.0;
-
- } else {
- splane.z = 1.0 - splane.z;
- }
-
- splane.xy /= splane.z;
- splane.xy = splane.xy * 0.5 + 0.5;
- splane.z = shadow_len * omni_lights.data[idx].inv_radius;
- splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
- splane.w = 1.0; //needed? i think it should be 1 already
-
- float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
- transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius;
- }
-#endif
-
-#if 0
-
- if (omni_lights.data[idx].projector_rect != vec4(0.0)) {
- vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
- local_v = normalize(local_v);
-
- vec4 atlas_rect = omni_lights.data[idx].projector_rect;
-
- if (local_v.z >= 0.0) {
- local_v.z += 1.0;
- atlas_rect.y += atlas_rect.w;
-
- } else {
- local_v.z = 1.0 - local_v.z;
- }
-
- local_v.xy /= local_v.z;
- local_v.xy = local_v.xy * 0.5 + 0.5;
- vec2 proj_uv = local_v.xy * atlas_rect.zw;
-
- vec2 proj_uv_ddx;
- vec2 proj_uv_ddy;
- {
- vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
- local_v_ddx = normalize(local_v_ddx);
-
- if (local_v_ddx.z >= 0.0) {
- local_v_ddx.z += 1.0;
- } else {
- local_v_ddx.z = 1.0 - local_v_ddx.z;
- }
-
- local_v_ddx.xy /= local_v_ddx.z;
- local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
-
- proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
-
- vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
- local_v_ddy = normalize(local_v_ddy);
-
- if (local_v_ddy.z >= 0.0) {
- local_v_ddy.z += 1.0;
- } else {
- local_v_ddy.z = 1.0 - local_v_ddy.z;
- }
-
- local_v_ddy.xy /= local_v_ddy.z;
- local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
-
- proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
- }
-
- vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
- no_shadow = mix(no_shadow, proj.rgb, proj.a);
- }
-#endif
-
- light_attenuation *= shadow;
-
- light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount,
-#ifdef LIGHT_BACKLIGHT_USED
- backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_curve,
- transmittance_boost,
- transmittance_z,
-#endif
-#ifdef LIGHT_RIM_USED
- rim * omni_attenuation, rim_tint, rim_color,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- binormal, tangent, anisotropy,
-#endif
-#ifdef USE_SOFT_SHADOWS
- size_A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light,
- specular_light);
-}
-
-float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
-#ifndef USE_NO_SHADOWS
- if (spot_lights.data[idx].shadow_enabled) {
- vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
- vec3 spot_dir = spot_lights.data[idx].direction;
- //there is a shadowmap
- vec4 v = vec4(vertex, 1.0);
-
- v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias;
-
- float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius;
-
- float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map
- vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale;
- normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z
- v.xyz += normal_bias;
-
- //adjust with bias
- z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius;
-
- float shadow;
-
- vec4 splane = (spot_lights.data[idx].shadow_matrix * v);
- splane /= splane.w;
-
-#ifdef USE_SOFT_SHADOWS
- if (spot_lights.data[idx].soft_shadow_size > 0.0) {
- //soft shadow
-
- //find blocker
-
- vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
-
- float blocker_count = 0.0;
- float blocker_average = 0.0;
-
- mat2 disk_rotation;
- {
- float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
- float sr = sin(r);
- float cr = cos(r);
- disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
- }
-
- float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale;
- vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
- vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
- suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
- float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
- if (d < z_norm) {
- blocker_average += d;
- blocker_count += 1.0;
- }
- }
-
- if (blocker_count > 0.0) {
- //blockers found, do soft shadow
- blocker_average /= blocker_count;
- float penumbra = (z_norm - blocker_average) / blocker_average;
- uv_size *= penumbra;
-
- shadow = 0.0;
- for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
- vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
- suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
- shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
- }
-
- shadow /= float(scene_data.penumbra_shadow_samples);
-
- } else {
- //no blockers found, so no shadow
- shadow = 1.0;
- }
-
- } else {
-#endif
- //hard shadow
- vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0);
-
- shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
-#ifdef USE_SOFT_SHADOWS
- }
-#endif
-
- return shadow;
- }
-
-#endif //USE_NO_SHADOWS
-
- return 1.0;
-}
-
-void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
-#ifdef LIGHT_BACKLIGHT_USED
- vec3 backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- vec4 transmittance_color,
- float transmittance_depth,
- float transmittance_curve,
- float transmittance_boost,
-#endif
-#ifdef LIGHT_RIM_USED
- float rim, float rim_tint, vec3 rim_color,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- float clearcoat, float clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- vec3 binormal, vec3 tangent, float anisotropy,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- inout float alpha,
-#endif
- inout vec3 diffuse_light,
- inout vec3 specular_light) {
- vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
- float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation);
- vec3 spot_dir = spot_lights.data[idx].direction;
- float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[idx].cone_angle);
- float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[idx].cone_angle));
- spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation);
- float light_attenuation = spot_attenuation;
- vec3 color = spot_lights.data[idx].color;
- float specular_amount = spot_lights.data[idx].specular_amount;
-
-#ifdef USE_SOFT_SHADOWS
- float size_A = 0.0;
-
- if (spot_lights.data[idx].size > 0.0) {
- float t = spot_lights.data[idx].size / max(0.001, light_length);
- size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
- }
-#endif
-
- /*
- if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) {
- //use projector texture
- }
- */
-
-#ifdef LIGHT_TRANSMITTANCE_USED
- float transmittance_z = transmittance_depth;
- transmittance_color.a *= light_attenuation;
- {
- splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0));
- splane /= splane.w;
- splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
-
- float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
- //reconstruct depth
- shadow_z /= spot_lights.data[idx].inv_radius;
- //distance to light plane
- float z = dot(spot_dir, -light_rel_vec);
- transmittance_z = z - shadow_z;
- }
-#endif //LIGHT_TRANSMITTANCE_USED
-
- light_attenuation *= shadow;
-
- light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount,
-#ifdef LIGHT_BACKLIGHT_USED
- backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
- transmittance_color,
- transmittance_depth,
- transmittance_curve,
- transmittance_boost,
- transmittance_z,
-#endif
-#ifdef LIGHT_RIM_USED
- rim * spot_attenuation, rim_tint, rim_color,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- binormal, tangent, anisotropy,
-#endif
-#ifdef USE_SOFT_SHADOW
- size_A,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light, specular_light);
-}
-
-void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughness, vec3 ambient_light, vec3 specular_light, inout vec4 ambient_accum, inout vec4 reflection_accum) {
- vec3 box_extents = reflections.data[ref_index].box_extents;
- vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz;
-
- if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box
- return;
- }
-
- vec3 ref_vec = normalize(reflect(vertex, normal));
-
- vec3 inner_pos = abs(local_pos / box_extents);
- float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
- //make blend more rounded
- blend = mix(length(inner_pos), blend, blend);
- blend *= blend;
- blend = max(0.0, 1.0 - blend);
-
- if (reflections.data[ref_index].intensity > 0.0) { // compute reflection
-
- vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz;
-
- if (reflections.data[ref_index].box_project) { //box project
-
- vec3 nrdir = normalize(local_ref_vec);
- vec3 rbmax = (box_extents - local_pos) / nrdir;
- vec3 rbmin = (-box_extents - local_pos) / nrdir;
-
- vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0)));
-
- float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
- vec3 posonbox = local_pos + nrdir * fa;
- local_ref_vec = posonbox - reflections.data[ref_index].box_offset;
- }
-
- vec4 reflection;
-
- reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb;
-
- if (reflections.data[ref_index].exterior) {
- reflection.rgb = mix(specular_light, reflection.rgb, blend);
- }
-
- reflection.rgb *= reflections.data[ref_index].intensity; //intensity
- reflection.a = blend;
- reflection.rgb *= reflection.a;
-
- reflection_accum += reflection;
- }
-
- switch (reflections.data[ref_index].ambient_mode) {
- case REFLECTION_AMBIENT_DISABLED: {
- //do nothing
- } break;
- case REFLECTION_AMBIENT_ENVIRONMENT: {
- //do nothing
- vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz;
-
- vec4 ambient_out;
-
- ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb;
- ambient_out.a = blend;
- if (reflections.data[ref_index].exterior) {
- ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
- }
-
- ambient_out.rgb *= ambient_out.a;
- ambient_accum += ambient_out;
- } break;
- case REFLECTION_AMBIENT_COLOR: {
- vec4 ambient_out;
- ambient_out.a = blend;
- ambient_out.rgb = reflections.data[ref_index].ambient;
- if (reflections.data[ref_index].exterior) {
- ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
- }
- ambient_out.rgb *= ambient_out.a;
- ambient_accum += ambient_out;
- } break;
- }
-}
+#include "scene_forward_lights_inc.glsl"
#ifdef USE_FORWARD_GI
-//standard voxel cone trace
-vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
- float dist = p_bias;
- vec4 color = vec4(0.0);
-
- while (dist < max_distance && color.a < 0.95) {
- float diameter = max(1.0, 2.0 * tan_half_angle * dist);
- vec3 uvw_pos = (pos + dist * direction) * cell_size;
- float half_diameter = diameter * 0.5;
- //check if outside, then break
- if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + half_diameter * cell_size)))) {
- break;
- }
- vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter));
- float a = (1.0 - color.a);
- color += a * scolor;
- dist += half_diameter;
- }
-
- return color;
-}
-
-vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
- float dist = p_bias;
- vec4 color = vec4(0.0);
- float radius = max(0.5, tan_half_angle * dist);
- float lod_level = log2(radius * 2.0);
-
- while (dist < max_distance && color.a < 0.95) {
- vec3 uvw_pos = (pos + dist * direction) * cell_size;
-
- //check if outside, then break
- if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + radius * cell_size)))) {
- break;
- }
- vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level);
- lod_level += 1.0;
-
- float a = (1.0 - color.a);
- scolor *= a;
- color += scolor;
- dist += radius;
- radius = max(0.5, tan_half_angle * dist);
- }
-
- return color;
-}
-
-void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) {
- position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz;
- ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz);
- normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz);
-
- position += normal * gi_probes.data[index].normal_bias;
-
- //this causes corrupted pixels, i have no idea why..
- if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) {
- return;
- }
-
- vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0);
- float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0);
- //float blend=1.0;
-
- float max_distance = length(gi_probes.data[index].bounds);
- vec3 cell_size = 1.0 / gi_probes.data[index].bounds;
-
- //radiance
-
-#define MAX_CONE_DIRS 4
-
- vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
- vec3(0.707107, 0.0, 0.707107),
- vec3(0.0, 0.707107, 0.707107),
- vec3(-0.707107, 0.0, 0.707107),
- vec3(0.0, -0.707107, 0.707107));
-
- float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
- float cone_angle_tan = 0.98269;
-
- vec3 light = vec3(0.0);
-
- for (int i = 0; i < MAX_CONE_DIRS; i++) {
- vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz);
-
- vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
-
- if (gi_probes.data[index].blend_ambient) {
- cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95));
- }
-
- light += cone_weights[i] * cone_light.rgb;
- }
-
- light *= gi_probes.data[index].dynamic_range;
- out_diff += vec4(light * blend, blend);
-
- //irradiance
- vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias);
- if (gi_probes.data[index].blend_ambient) {
- irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95));
- }
- irr_light.rgb *= gi_probes.data[index].dynamic_range;
- //irr_light=vec3(0.0);
-
- out_spec += vec4(irr_light.rgb * blend, blend);
-}
-
-vec2 octahedron_wrap(vec2 v) {
- vec2 signVal;
- signVal.x = v.x >= 0.0 ? 1.0 : -1.0;
- signVal.y = v.y >= 0.0 ? 1.0 : -1.0;
- return (1.0 - abs(v.yx)) * signVal;
-}
-
-vec2 octahedron_encode(vec3 n) {
- // https://twitter.com/Stubbesaurus/status/937994790553227264
- n /= (abs(n.x) + abs(n.y) + abs(n.z));
- n.xy = n.z >= 0.0 ? n.xy : octahedron_wrap(n.xy);
- n.xy = n.xy * 0.5 + 0.5;
- return n.xy;
-}
-
-void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, bool use_specular, float roughness, out vec3 diffuse_light, out vec3 specular_light, out float blend) {
- cascade_pos += cam_normal * sdfgi.normal_bias;
-
- vec3 base_pos = floor(cascade_pos);
- //cascade_pos += mix(vec3(0.0),vec3(0.01),lessThan(abs(cascade_pos-base_pos),vec3(0.01))) * cam_normal;
- ivec3 probe_base_pos = ivec3(base_pos);
-
- vec4 diffuse_accum = vec4(0.0);
- vec3 specular_accum;
-
- ivec3 tex_pos = ivec3(probe_base_pos.xy, int(cascade));
- tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
- tex_pos.xy = tex_pos.xy * (SDFGI_OCT_SIZE + 2) + ivec2(1);
-
- vec3 diffuse_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size;
-
- vec3 specular_posf;
-
- if (use_specular) {
- specular_accum = vec3(0.0);
- specular_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_specular_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size;
- }
-
- vec4 light_accum = vec4(0.0);
- float weight_accum = 0.0;
-
- for (uint j = 0; j < 8; j++) {
- ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
- ivec3 probe_posi = probe_base_pos;
- probe_posi += offset;
-
- // Compute weight
-
- vec3 probe_pos = vec3(probe_posi);
- vec3 probe_to_pos = cascade_pos - probe_pos;
- vec3 probe_dir = normalize(-probe_to_pos);
-
- vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
- float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(cam_normal, probe_dir));
-
- // Compute lightprobe occlusion
-
- if (sdfgi.use_occlusion) {
- ivec3 occ_indexv = abs((sdfgi.cascades[cascade].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
- vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
-
- vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
- occ_pos.z += float(cascade);
- if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
- occ_pos.x += 1.0;
- }
-
- occ_pos *= sdfgi.occlusion_renormalize;
- float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, material_samplers[SAMPLER_LINEAR_CLAMP]), occ_pos, 0.0), occ_mask);
-
- weight *= max(occlusion, 0.01);
- }
-
- // Compute lightprobe texture position
-
- vec3 diffuse;
- vec3 pos_uvw = diffuse_posf;
- pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy;
- pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z;
- diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb;
-
- diffuse_accum += vec4(diffuse * weight, weight);
-
- if (use_specular) {
- vec3 specular = vec3(0.0);
- vec3 pos_uvw = specular_posf;
- pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy;
- pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z;
- if (roughness < 0.99) {
- specular = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw + vec3(0, 0, float(sdfgi.max_cascades)), 0.0).rgb;
- }
- if (roughness > 0.5) {
- specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0);
- }
-
- specular_accum += specular * weight;
- }
- }
-
- if (diffuse_accum.a > 0.0) {
- diffuse_accum.rgb /= diffuse_accum.a;
- }
-
- diffuse_light = diffuse_accum.rgb;
-
- if (use_specular) {
- if (diffuse_accum.a > 0.0) {
- specular_accum /= diffuse_accum.a;
- }
-
- specular_light = specular_accum;
- }
-
- {
- //process blend
- float blend_from = (float(sdfgi.probe_axis_size - 1) / 2.0) - 2.5;
- float blend_to = blend_from + 2.0;
-
- vec3 inner_pos = cam_pos * sdfgi.cascades[cascade].to_probe;
-
- float len = length(inner_pos);
-
- inner_pos = abs(normalize(inner_pos));
- len *= max(inner_pos.x, max(inner_pos.y, inner_pos.z));
-
- if (len >= blend_from) {
- blend = smoothstep(blend_from, blend_to, len);
- } else {
- blend = 0.0;
- }
- }
-}
+#include "scene_forward_gi_inc.glsl"
#endif //USE_FORWARD_GI
@@ -1792,26 +533,6 @@ uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) {
return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width);
}
-float blur_shadow(float shadow) {
- return shadow;
-#if 0
- //disabling for now, will investigate later
- float interp_shadow = shadow;
- if (gl_HelperInvocation) {
- interp_shadow = -4.0; // technically anything below -4 will do but just to make sure
- }
-
- uvec2 fc2 = uvec2(gl_FragCoord.xy);
- interp_shadow -= dFdx(interp_shadow) * (float(fc2.x & 1) - 0.5);
- interp_shadow -= dFdy(interp_shadow) * (float(fc2.y & 1) - 0.5);
-
- if (interp_shadow >= 0.0) {
- shadow = interp_shadow;
- }
- return shadow;
-#endif
-}
-
#endif //!MODE_RENDER DEPTH
void main() {
@@ -1941,7 +662,7 @@ void main() {
#endif
#ifdef ALPHA_ANTIALIASING_EDGE_USED
-// If alpha scissor is used, we must further the edge threshold, otherwise we wont get any edge feather
+// If alpha scissor is used, we must further the edge threshold, otherwise we won't get any edge feather
#ifdef ALPHA_SCISSOR_USED
alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0);
#endif
@@ -2129,7 +850,7 @@ void main() {
if (scene_data.roughness_limiter_enabled) {
//http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
float roughness2 = roughness * roughness;
- vec3 dndu = dFdx(normal), dndv = dFdx(normal);
+ vec3 dndu = dFdx(normal), dndv = dFdy(normal);
float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv));
float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect
float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2);
@@ -2183,7 +904,7 @@ void main() {
}
#endif // USE_LIGHTMAP
#if defined(CUSTOM_IRRADIANCE_USED)
- ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a);
+ ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a);
#endif
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -2321,7 +1042,7 @@ void main() {
}
}
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
vec3 ref_vec = normalize(reflect(normalize(vertex), normal));
@@ -2333,12 +1054,12 @@ void main() {
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);
+ voxel_gi_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);
+ voxel_gi_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
}
if (amb_accum.a > 0.0) {
@@ -2506,6 +1227,10 @@ void main() {
continue; //not masked
}
+ if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
+
float shadow = 1.0;
#ifdef USE_SOFT_SHADOWS
@@ -2955,6 +1680,10 @@ void main() {
continue; //not masked
}
+ if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
+
float shadow = light_process_omni_shadow(light_index, vertex, view);
shadow = blur_shadow(shadow);
@@ -3028,6 +1757,10 @@ void main() {
continue; //not masked
}
+ if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
+
float shadow = light_process_spot_shadow(light_index, vertex, view);
shadow = blur_shadow(shadow);
@@ -3196,15 +1929,15 @@ void main() {
#ifdef MODE_RENDER_NORMAL_ROUGHNESS
normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness);
-#ifdef MODE_RENDER_GIPROBE
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes
+#ifdef MODE_RENDER_VOXEL_GI
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
uint index2 = instances.data[instance_index].gi_offset >> 16;
- giprobe_buffer.x = index1 & 0xFF;
- giprobe_buffer.y = index2 & 0xFF;
+ voxel_gi_buffer.x = index1 & 0xFF;
+ voxel_gi_buffer.y = index2 & 0xFF;
} else {
- giprobe_buffer.x = 0xFF;
- giprobe_buffer.y = 0xFF;
+ voxel_gi_buffer.x = 0xFF;
+ voxel_gi_buffer.y = 0xFF;
}
#endif
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
index 48e331714d..e64e52623e 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
@@ -1,7 +1,7 @@
#define M_PI 3.14159265359
#define ROUGHNESS_MAX_LOD 5
-#define MAX_GI_PROBES 8
+#define MAX_VOXEL_GI_INSTANCES 8
#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
@@ -13,8 +13,9 @@
#endif
#include "cluster_data_inc.glsl"
+#include "decal_data_inc.glsl"
-#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_GIPROBE) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED)
+#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED)
#ifndef NORMAL_USED
#define NORMAL_USED
#endif
@@ -28,7 +29,11 @@ layout(push_constant, binding = 0, std430) uniform DrawCall {
}
draw_call;
-/* Set 0 Scene data that never changes, ever */
+#define SDFGI_MAX_CASCADES 8
+
+/* Set 0: Base Pass (never changes) */
+
+#include "light_data_inc.glsl"
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
@@ -43,10 +48,6 @@ draw_call;
#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
-#define SDFGI_MAX_CASCADES 8
-
-/* Set 1: Base Pass (never changes) */
-
layout(set = 0, binding = 1) uniform sampler material_samplers[12];
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
@@ -56,17 +57,16 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler;
#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8)
#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9)
#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10)
-#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11)
+#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 11)
#define INSTANCE_FLAGS_MULTIMESH (1 << 12)
#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13)
#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14)
#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15)
-#define INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT 16
+#define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16
//3 bits of stride
-#define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7
+#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
-#define INSTANCE_FLAGS_SKELETON (1 << 19)
-#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 20)
+#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24)
layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
LightData data[];
@@ -122,7 +122,7 @@ layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableDat
}
global_variables;
-struct SDFGIProbeCascadeData {
+struct SDFVoxelGICascadeData {
vec3 position;
float to_probe;
ivec3 probe_world_offset;
@@ -153,11 +153,11 @@ layout(set = 0, binding = 13, std140) uniform SDFGI {
vec3 cascade_probe_size;
uint pad5;
- SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES];
+ SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES];
}
sdfgi;
-/* Set 2: Render Pass (changes per render pass) */
+/* Set 1: Render Pass (changes per render pass) */
layout(set = 1, binding = 0, std140) uniform SceneData {
mat4 projection_matrix;
@@ -241,7 +241,6 @@ layout(set = 1, binding = 0, std140) uniform SceneData {
bool pancake_shadows;
}
-
scene_data;
struct InstanceData {
@@ -276,7 +275,7 @@ layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
-layout(set = 1, binding = 7) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
+layout(set = 1, binding = 7) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer {
uint data[];
@@ -307,7 +306,7 @@ layout(set = 1, binding = 14) uniform texture2D reflection_buffer;
layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture;
layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades;
-struct GIProbeData {
+struct VoxelGIData {
mat4 xform;
vec3 bounds;
float dynamic_range;
@@ -323,10 +322,10 @@ struct GIProbeData {
uint mipmaps;
};
-layout(set = 1, binding = 17, std140) uniform GIProbes {
- GIProbeData data[MAX_GI_PROBES];
+layout(set = 1, binding = 17, std140) uniform VoxelGIs {
+ VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
-gi_probes;
+voxel_gi_instances;
layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
new file mode 100644
index 0000000000..c88bd0a14b
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl
@@ -0,0 +1,242 @@
+// Functions related to gi/sdfgi for our forward renderer
+
+//standard voxel cone trace
+vec4 voxel_cone_trace(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+ float dist = p_bias;
+ vec4 color = vec4(0.0);
+
+ while (dist < max_distance && color.a < 0.95) {
+ float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+ vec3 uvw_pos = (pos + dist * direction) * cell_size;
+ float half_diameter = diameter * 0.5;
+ //check if outside, then break
+ if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + half_diameter * cell_size)))) {
+ break;
+ }
+ vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2(diameter));
+ float a = (1.0 - color.a);
+ color += a * scolor;
+ dist += half_diameter;
+ }
+
+ return color;
+}
+
+vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
+ float dist = p_bias;
+ vec4 color = vec4(0.0);
+ float radius = max(0.5, tan_half_angle * dist);
+ float lod_level = log2(radius * 2.0);
+
+ while (dist < max_distance && color.a < 0.95) {
+ vec3 uvw_pos = (pos + dist * direction) * cell_size;
+
+ //check if outside, then break
+ if (any(greaterThan(abs(uvw_pos - 0.5), vec3(0.5f + radius * cell_size)))) {
+ break;
+ }
+ vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level);
+ lod_level += 1.0;
+
+ float a = (1.0 - color.a);
+ scolor *= a;
+ color += scolor;
+ dist += radius;
+ radius = max(0.5, tan_half_angle * dist);
+ }
+
+ return color;
+}
+
+void voxel_gi_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 = (voxel_gi_instances.data[index].xform * vec4(position, 1.0)).xyz;
+ ref_vec = normalize((voxel_gi_instances.data[index].xform * vec4(ref_vec, 0.0)).xyz);
+ normal = normalize((voxel_gi_instances.data[index].xform * vec4(normal, 0.0)).xyz);
+
+ position += normal * voxel_gi_instances.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, voxel_gi_instances.data[index].bounds))))) {
+ return;
+ }
+
+ vec3 blendv = abs(position / voxel_gi_instances.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(voxel_gi_instances.data[index].bounds);
+ vec3 cell_size = 1.0 / voxel_gi_instances.data[index].bounds;
+
+ //radiance
+
+#define MAX_CONE_DIRS 4
+
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
+ vec3(0.707107, 0.0, 0.707107),
+ vec3(0.0, 0.707107, 0.707107),
+ vec3(-0.707107, 0.0, 0.707107),
+ vec3(0.0, -0.707107, 0.707107));
+
+ float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
+ float cone_angle_tan = 0.98269;
+
+ vec3 light = vec3(0.0);
+
+ for (int i = 0; i < MAX_CONE_DIRS; i++) {
+ vec3 dir = normalize((voxel_gi_instances.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz);
+
+ vec4 cone_light = voxel_cone_trace_45_degrees(voxel_gi_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, voxel_gi_instances.data[index].bias);
+
+ if (voxel_gi_instances.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 *= voxel_gi_instances.data[index].dynamic_range;
+ out_diff += vec4(light * blend, blend);
+
+ //irradiance
+ vec4 irr_light = voxel_cone_trace(voxel_gi_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, voxel_gi_instances.data[index].bias);
+ if (voxel_gi_instances.data[index].blend_ambient) {
+ irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95));
+ }
+ irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range;
+ //irr_light=vec3(0.0);
+
+ out_spec += vec4(irr_light.rgb * blend, blend);
+}
+
+vec2 octahedron_wrap(vec2 v) {
+ vec2 signVal;
+ signVal.x = v.x >= 0.0 ? 1.0 : -1.0;
+ signVal.y = v.y >= 0.0 ? 1.0 : -1.0;
+ return (1.0 - abs(v.yx)) * signVal;
+}
+
+vec2 octahedron_encode(vec3 n) {
+ // https://twitter.com/Stubbesaurus/status/937994790553227264
+ n /= (abs(n.x) + abs(n.y) + abs(n.z));
+ n.xy = n.z >= 0.0 ? n.xy : octahedron_wrap(n.xy);
+ n.xy = n.xy * 0.5 + 0.5;
+ return n.xy;
+}
+
+void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, bool use_specular, float roughness, out vec3 diffuse_light, out vec3 specular_light, out float blend) {
+ cascade_pos += cam_normal * sdfgi.normal_bias;
+
+ vec3 base_pos = floor(cascade_pos);
+ //cascade_pos += mix(vec3(0.0),vec3(0.01),lessThan(abs(cascade_pos-base_pos),vec3(0.01))) * cam_normal;
+ ivec3 probe_base_pos = ivec3(base_pos);
+
+ vec4 diffuse_accum = vec4(0.0);
+ vec3 specular_accum;
+
+ ivec3 tex_pos = ivec3(probe_base_pos.xy, int(cascade));
+ tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size;
+ tex_pos.xy = tex_pos.xy * (SDFGI_OCT_SIZE + 2) + ivec2(1);
+
+ vec3 diffuse_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size;
+
+ vec3 specular_posf;
+
+ if (use_specular) {
+ specular_accum = vec3(0.0);
+ specular_posf = (vec3(tex_pos) + vec3(octahedron_encode(cam_specular_normal) * float(SDFGI_OCT_SIZE), 0.0)) * sdfgi.lightprobe_tex_pixel_size;
+ }
+
+ vec4 light_accum = vec4(0.0);
+ float weight_accum = 0.0;
+
+ for (uint j = 0; j < 8; j++) {
+ ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1);
+ ivec3 probe_posi = probe_base_pos;
+ probe_posi += offset;
+
+ // Compute weight
+
+ vec3 probe_pos = vec3(probe_posi);
+ vec3 probe_to_pos = cascade_pos - probe_pos;
+ vec3 probe_dir = normalize(-probe_to_pos);
+
+ vec3 trilinear = vec3(1.0) - abs(probe_to_pos);
+ float weight = trilinear.x * trilinear.y * trilinear.z * max(0.005, dot(cam_normal, probe_dir));
+
+ // Compute lightprobe occlusion
+
+ if (sdfgi.use_occlusion) {
+ ivec3 occ_indexv = abs((sdfgi.cascades[cascade].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4);
+ vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3)));
+
+ vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw;
+ occ_pos.z += float(cascade);
+ if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures
+ occ_pos.x += 1.0;
+ }
+
+ occ_pos *= sdfgi.occlusion_renormalize;
+ float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_cascades, material_samplers[SAMPLER_LINEAR_CLAMP]), occ_pos, 0.0), occ_mask);
+
+ weight *= max(occlusion, 0.01);
+ }
+
+ // Compute lightprobe texture position
+
+ vec3 diffuse;
+ vec3 pos_uvw = diffuse_posf;
+ pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy;
+ pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z;
+ diffuse = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb;
+
+ diffuse_accum += vec4(diffuse * weight, weight);
+
+ if (use_specular) {
+ vec3 specular = vec3(0.0);
+ vec3 pos_uvw = specular_posf;
+ pos_uvw.xy += vec2(offset.xy) * sdfgi.lightprobe_uv_offset.xy;
+ pos_uvw.x += float(offset.z) * sdfgi.lightprobe_uv_offset.z;
+ if (roughness < 0.99) {
+ specular = textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw + vec3(0, 0, float(sdfgi.max_cascades)), 0.0).rgb;
+ }
+ if (roughness > 0.5) {
+ specular = mix(specular, textureLod(sampler2DArray(sdfgi_lightprobe_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), pos_uvw, 0.0).rgb, (roughness - 0.5) * 2.0);
+ }
+
+ specular_accum += specular * weight;
+ }
+ }
+
+ if (diffuse_accum.a > 0.0) {
+ diffuse_accum.rgb /= diffuse_accum.a;
+ }
+
+ diffuse_light = diffuse_accum.rgb;
+
+ if (use_specular) {
+ if (diffuse_accum.a > 0.0) {
+ specular_accum /= diffuse_accum.a;
+ }
+
+ specular_light = specular_accum;
+ }
+
+ {
+ //process blend
+ float blend_from = (float(sdfgi.probe_axis_size - 1) / 2.0) - 2.5;
+ float blend_to = blend_from + 2.0;
+
+ vec3 inner_pos = cam_pos * sdfgi.cascades[cascade].to_probe;
+
+ float len = length(inner_pos);
+
+ inner_pos = abs(normalize(inner_pos));
+ len *= max(inner_pos.x, max(inner_pos.y, inner_pos.z));
+
+ if (len >= blend_from) {
+ blend = smoothstep(blend_from, blend_to, len);
+ } else {
+ blend = 0.0;
+ }
+ }
+}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
new file mode 100644
index 0000000000..709ea45b88
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -0,0 +1,1022 @@
+// Functions related to lighting
+
+// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V.
+// We're dividing this factor off because the overall term we'll end up looks like
+// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012):
+//
+// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V)
+//
+// We're basically regouping this as
+//
+// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)]
+//
+// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V.
+//
+// The contents of the D and G (G1) functions (GGX) are taken from
+// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014).
+// Eqns 71-72 and 85-86 (see also Eqns 43 and 80).
+
+float G_GGX_2cos(float cos_theta_m, float alpha) {
+ // Schlick's approximation
+ // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994)
+ // Eq. (19), although see Heitz (2014) the about the problems with his derivation.
+ // It nevertheless approximates GGX well with k = alpha/2.
+ float k = 0.5 * alpha;
+ return 0.5 / (cos_theta_m * (1.0 - k) + k);
+
+ // float cos2 = cos_theta_m * cos_theta_m;
+ // float sin2 = (1.0 - cos2);
+ // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2));
+}
+
+float D_GGX(float cos_theta_m, float alpha) {
+ float alpha2 = alpha * alpha;
+ float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m;
+ return alpha2 / (M_PI * d * d);
+}
+
+float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
+ float cos2 = cos_theta_m * cos_theta_m;
+ float sin2 = (1.0 - cos2);
+ float s_x = alpha_x * cos_phi;
+ float s_y = alpha_y * sin_phi;
+ return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001);
+}
+
+float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
+ float cos2 = cos_theta_m * cos_theta_m;
+ float sin2 = (1.0 - cos2);
+ float r_x = cos_phi / alpha_x;
+ float r_y = sin_phi / alpha_y;
+ float d = cos2 + sin2 * (r_x * r_x + r_y * r_y);
+ return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001);
+}
+
+float SchlickFresnel(float u) {
+ float m = 1.0 - u;
+ float m2 = m * m;
+ return m2 * m2 * m; // pow(m,5)
+}
+
+float GTR1(float NdotH, float a) {
+ if (a >= 1.0)
+ return 1.0 / M_PI;
+ float a2 = a * a;
+ float t = 1.0 + (a2 - 1.0) * NdotH * NdotH;
+ return (a2 - 1.0) / (M_PI * log(a2) * t);
+}
+
+vec3 F0(float metallic, float specular, vec3 albedo) {
+ float dielectric = 0.16 * specular * specular;
+ // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials;
+ // see https://google.github.io/filament/Filament.md.html
+ return mix(vec3(dielectric), albedo, vec3(metallic));
+}
+
+void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+ vec4 transmittance_color,
+ float transmittance_depth,
+ float transmittance_curve,
+ float transmittance_boost,
+ float transmittance_z,
+#endif
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint, vec3 rim_color,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 B, vec3 T, float anisotropy,
+#endif
+#ifdef USE_SOFT_SHADOWS
+ float A,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ inout float alpha,
+#endif
+ inout vec3 diffuse_light, inout vec3 specular_light) {
+
+#if defined(LIGHT_CODE_USED)
+ // light is written by the light shader
+
+ vec3 normal = N;
+ vec3 light = L;
+ vec3 view = V;
+
+#CODE : LIGHT
+
+#else
+
+#ifdef USE_SOFT_SHADOWS
+ float NdotL = min(A + dot(N, L), 1.0);
+#else
+ float NdotL = dot(N, L);
+#endif
+ float cNdotL = max(NdotL, 0.0); // clamped NdotL
+ float NdotV = dot(N, V);
+ float cNdotV = max(NdotV, 0.0);
+
+#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
+ vec3 H = normalize(V + L);
+#endif
+
+#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
+#ifdef USE_SOFT_SHADOWS
+ float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
+#else
+ float cNdotH = clamp(dot(N, H), 0.0, 1.0);
+#endif
+#endif
+
+#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
+#ifdef USE_SOFT_SHADOWS
+ float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
+#else
+ float cLdotH = clamp(dot(L, H), 0.0, 1.0);
+#endif
+#endif
+
+ float metallic = unpackUnorm4x8(orms).z;
+ if (metallic < 1.0) {
+ float roughness = unpackUnorm4x8(orms).y;
+ float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
+
+#if defined(DIFFUSE_LAMBERT_WRAP)
+ // energy conserving lambert wrap shader
+ diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness)));
+#elif defined(DIFFUSE_TOON)
+
+ diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL);
+
+#elif defined(DIFFUSE_BURLEY)
+
+ {
+ float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5;
+ float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV);
+ float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL);
+ diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL;
+ /*
+ float energyBias = mix(roughness, 0.0, 0.5);
+ float energyFactor = mix(roughness, 1.0, 1.0 / 1.51);
+ float fd90 = energyBias + 2.0 * VoH * VoH * roughness;
+ float f0 = 1.0;
+ float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0);
+ float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0);
+
+ diffuse_brdf_NL = lightScatter * viewScatter * energyFactor;
+ */
+ }
+#else
+ // lambert
+ diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
+#endif
+
+ diffuse_light += light_color * diffuse_brdf_NL * attenuation;
+
+#if defined(LIGHT_BACKLIGHT_USED)
+ diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation;
+#endif
+
+#if defined(LIGHT_RIM_USED)
+ float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
+ diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color;
+#endif
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+
+#ifdef SSS_MODE_SKIN
+
+ {
+ float scale = 8.25 / transmittance_depth;
+ float d = scale * abs(transmittance_z);
+ float dd = -d * d;
+ vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
+ vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
+ vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
+ vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
+ vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
+ vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
+
+ diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
+ }
+#else
+
+ if (transmittance_depth > 0.0) {
+ float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0);
+
+ fade = pow(max(0.0, 1.0 - fade), transmittance_curve);
+ fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0);
+
+ diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade;
+ }
+
+#endif //SSS_MODE_SKIN
+
+#endif //LIGHT_TRANSMITTANCE_USED
+ }
+
+ float roughness = unpackUnorm4x8(orms).y;
+ if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
+
+ // D
+
+#if defined(SPECULAR_BLINN)
+
+ //normalized blinn
+ float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
+ float blinn = pow(cNdotH, shininess) * cNdotL;
+ blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
+ float intensity = blinn;
+
+ specular_light += light_color * intensity * attenuation * specular_amount;
+
+#elif defined(SPECULAR_PHONG)
+
+ vec3 R = normalize(-reflect(L, N));
+#ifdef USE_SOFT_SHADOWS
+ float cRdotV = clamp(A + dot(R, V), 0.0, 1.0);
+#else
+ float cRdotV = clamp(dot(R, V), 0.0, 1.0);
+#endif
+ float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
+ float phong = pow(cRdotV, shininess);
+ phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
+ float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75);
+
+ specular_light += light_color * intensity * attenuation * specular_amount;
+
+#elif defined(SPECULAR_TOON)
+
+ vec3 R = normalize(-reflect(L, N));
+ float RdotV = dot(R, V);
+ float mid = 1.0 - roughness;
+ mid *= mid;
+ float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid;
+ diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection
+
+#elif defined(SPECULAR_DISABLED)
+ // none..
+
+#elif defined(SPECULAR_SCHLICK_GGX)
+ // shlick+ggx as default
+
+#if defined(LIGHT_ANISOTROPY_USED)
+
+ float alpha_ggx = roughness * roughness;
+ float aspect = sqrt(1.0 - anisotropy * 0.9);
+ float ax = alpha_ggx / aspect;
+ float ay = alpha_ggx * aspect;
+ float XdotH = dot(T, H);
+ float YdotH = dot(B, H);
+ float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH);
+ float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH);
+
+#else
+ float alpha_ggx = roughness * roughness;
+ float D = D_GGX(cNdotH, alpha_ggx);
+ float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx);
+#endif
+ // F
+ float cLdotH5 = SchlickFresnel(cLdotH);
+ vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0);
+
+ vec3 specular_brdf_NL = cNdotL * D * F * G;
+
+ specular_light += specular_brdf_NL * light_color * attenuation * specular_amount;
+#endif
+
+#if defined(LIGHT_CLEARCOAT_USED)
+
+#if !defined(SPECULAR_SCHLICK_GGX)
+ float cLdotH5 = SchlickFresnel(cLdotH);
+#endif
+ float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss));
+ float Fr = mix(.04, 1.0, cLdotH5);
+ float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25);
+
+ float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL;
+
+ specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount;
+#endif
+ }
+
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0));
+#endif
+
+#endif //defined(LIGHT_CODE_USED)
+}
+
+#ifndef USE_NO_SHADOWS
+
+// Interleaved Gradient Noise
+// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+float quick_hash(vec2 pos) {
+ const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
+ return fract(magic.z * fract(dot(pos, magic.xy)));
+}
+
+float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
+ vec2 pos = coord.xy;
+ float depth = coord.z;
+
+ //if only one sample is taken, take it from the center
+ if (scene_data.directional_soft_shadow_samples == 1) {
+ return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
+ }
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ float avg = 0.0;
+
+ for (uint i = 0; i < scene_data.directional_soft_shadow_samples; i++) {
+ avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.directional_soft_shadow_kernel[i].xy), depth, 1.0));
+ }
+
+ return avg * (1.0 / float(scene_data.directional_soft_shadow_samples));
+}
+
+float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
+ vec2 pos = coord.xy;
+ float depth = coord.z;
+
+ //if only one sample is taken, take it from the center
+ if (scene_data.soft_shadow_samples == 1) {
+ return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
+ }
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ float avg = 0.0;
+
+ for (uint i = 0; i < scene_data.soft_shadow_samples; i++) {
+ avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data.soft_shadow_kernel[i].xy), depth, 1.0));
+ }
+
+ return avg * (1.0 / float(scene_data.soft_shadow_samples));
+}
+
+float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale) {
+ //find blocker
+ float blocker_count = 0.0;
+ float blocker_average = 0.0;
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
+ vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
+ float d = textureLod(sampler2D(shadow, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
+ if (d < pssm_coord.z) {
+ blocker_average += d;
+ blocker_count += 1.0;
+ }
+ }
+
+ if (blocker_count > 0.0) {
+ //blockers found, do soft shadow
+ blocker_average /= blocker_count;
+ float penumbra = (pssm_coord.z - blocker_average) / blocker_average;
+ tex_scale *= penumbra;
+
+ float s = 0.0;
+ for (uint i = 0; i < scene_data.directional_penumbra_shadow_samples; i++) {
+ vec2 suv = pssm_coord.xy + (disk_rotation * scene_data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
+ s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0));
+ }
+
+ return s / float(scene_data.directional_penumbra_shadow_samples);
+
+ } else {
+ //no blockers found, so no shadow
+ return 1.0;
+ }
+}
+
+#endif //USE_NO_SHADOWS
+
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+ float nd = distance * inv_range;
+ nd *= nd;
+ nd *= nd; // nd^4
+ nd = max(1.0 - nd, 0.0);
+ nd *= nd; // nd^2
+ return nd * pow(max(distance, 0.0001), -decay);
+}
+
+float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
+#ifndef USE_NO_SHADOWS
+ if (omni_lights.data[idx].shadow_enabled) {
+ // there is a shadowmap
+
+ vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+
+ vec4 v = vec4(vertex, 1.0);
+
+ vec4 splane = (omni_lights.data[idx].shadow_matrix * v);
+ float shadow_len = length(splane.xyz); //need to remember shadow len from here
+
+ {
+ vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius;
+ nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp))));
+ v.xyz += nofs;
+ splane = (omni_lights.data[idx].shadow_matrix * v);
+ }
+
+ float shadow;
+
+#ifdef USE_SOFT_SHADOWS
+ if (omni_lights.data[idx].soft_shadow_size > 0.0) {
+ //soft shadow
+
+ //find blocker
+
+ float blocker_count = 0.0;
+ float blocker_average = 0.0;
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ vec3 normal = normalize(splane.xyz);
+ vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
+ vec3 tangent = normalize(cross(v0, normal));
+ vec3 bitangent = normalize(cross(tangent, normal));
+ float z_norm = shadow_len * omni_lights.data[idx].inv_radius;
+
+ tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
+ bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
+
+ for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
+
+ vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
+
+ pos = normalize(pos);
+ vec4 uv_rect = omni_lights.data[idx].atlas_rect;
+
+ if (pos.z >= 0.0) {
+ pos.z += 1.0;
+ uv_rect.y += uv_rect.w;
+ } else {
+ pos.z = 1.0 - pos.z;
+ }
+
+ pos.xy /= pos.z;
+
+ pos.xy = pos.xy * 0.5 + 0.5;
+ pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
+
+ float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), pos.xy, 0.0).r;
+ if (d < z_norm) {
+ blocker_average += d;
+ blocker_count += 1.0;
+ }
+ }
+
+ if (blocker_count > 0.0) {
+ //blockers found, do soft shadow
+ blocker_average /= blocker_count;
+ float penumbra = (z_norm - blocker_average) / blocker_average;
+ tangent *= penumbra;
+ bitangent *= penumbra;
+
+ z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias;
+
+ shadow = 0.0;
+ for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ vec2 disk = disk_rotation * scene_data.penumbra_shadow_kernel[i].xy;
+ vec3 pos = splane.xyz + tangent * disk.x + bitangent * disk.y;
+
+ pos = normalize(pos);
+ vec4 uv_rect = omni_lights.data[idx].atlas_rect;
+
+ if (pos.z >= 0.0) {
+ pos.z += 1.0;
+ uv_rect.y += uv_rect.w;
+ } else {
+ pos.z = 1.0 - pos.z;
+ }
+
+ pos.xy /= pos.z;
+
+ pos.xy = pos.xy * 0.5 + 0.5;
+ pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
+ shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0));
+ }
+
+ shadow /= float(scene_data.penumbra_shadow_samples);
+
+ } else {
+ //no blockers found, so no shadow
+ shadow = 1.0;
+ }
+ } else {
+#endif
+ splane.xyz = normalize(splane.xyz);
+ vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
+
+ if (splane.z >= 0.0) {
+ splane.z += 1.0;
+
+ clamp_rect.y += clamp_rect.w;
+
+ } else {
+ splane.z = 1.0 - splane.z;
+ }
+
+ splane.xy /= splane.z;
+
+ splane.xy = splane.xy * 0.5 + 0.5;
+ splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius;
+ splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
+ splane.w = 1.0; //needed? i think it should be 1 already
+ shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
+#ifdef USE_SOFT_SHADOWS
+ }
+#endif
+
+ return shadow;
+ }
+#endif
+
+ return 1.0;
+}
+
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+ vec4 transmittance_color,
+ float transmittance_depth,
+ float transmittance_curve,
+ float transmittance_boost,
+#endif
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint, vec3 rim_color,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 binormal, vec3 tangent, float anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ inout float alpha,
+#endif
+ inout vec3 diffuse_light, inout vec3 specular_light) {
+ vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation);
+ float light_attenuation = omni_attenuation;
+ vec3 color = omni_lights.data[idx].color;
+
+#ifdef USE_SOFT_SHADOWS
+ float size_A = 0.0;
+
+ if (omni_lights.data[idx].size > 0.0) {
+ float t = omni_lights.data[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ }
+#endif
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+ float transmittance_z = transmittance_depth; //no transmittance by default
+ transmittance_color.a *= light_attenuation;
+ {
+ vec4 clamp_rect = omni_lights.data[idx].atlas_rect;
+
+ //redo shadowmapping, but shrink the model a bit to avoid arctifacts
+ vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0));
+
+ shadow_len = length(splane.xyz);
+ splane = normalize(splane.xyz);
+
+ if (splane.z >= 0.0) {
+ splane.z += 1.0;
+
+ } else {
+ splane.z = 1.0 - splane.z;
+ }
+
+ splane.xy /= splane.z;
+ splane.xy = splane.xy * 0.5 + 0.5;
+ splane.z = shadow_len * omni_lights.data[idx].inv_radius;
+ splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
+ splane.w = 1.0; //needed? i think it should be 1 already
+
+ float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
+ transmittance_z = (splane.z - shadow_z) / omni_lights.data[idx].inv_radius;
+ }
+#endif
+
+#if 0
+
+ if (omni_lights.data[idx].projector_rect != vec4(0.0)) {
+ vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
+ local_v = normalize(local_v);
+
+ vec4 atlas_rect = omni_lights.data[idx].projector_rect;
+
+ if (local_v.z >= 0.0) {
+ local_v.z += 1.0;
+ atlas_rect.y += atlas_rect.w;
+
+ } else {
+ local_v.z = 1.0 - local_v.z;
+ }
+
+ local_v.xy /= local_v.z;
+ local_v.xy = local_v.xy * 0.5 + 0.5;
+ vec2 proj_uv = local_v.xy * atlas_rect.zw;
+
+ vec2 proj_uv_ddx;
+ vec2 proj_uv_ddy;
+ {
+ vec3 local_v_ddx = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
+ local_v_ddx = normalize(local_v_ddx);
+
+ if (local_v_ddx.z >= 0.0) {
+ local_v_ddx.z += 1.0;
+ } else {
+ local_v_ddx.z = 1.0 - local_v_ddx.z;
+ }
+
+ local_v_ddx.xy /= local_v_ddx.z;
+ local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
+
+ proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
+
+ vec3 local_v_ddy = (omni_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
+ local_v_ddy = normalize(local_v_ddy);
+
+ if (local_v_ddy.z >= 0.0) {
+ local_v_ddy.z += 1.0;
+ } else {
+ local_v_ddy.z = 1.0 - local_v_ddy.z;
+ }
+
+ local_v_ddy.xy /= local_v_ddy.z;
+ local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
+
+ proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
+ }
+
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ no_shadow = mix(no_shadow, proj.rgb, proj.a);
+ }
+#endif
+
+ light_attenuation *= shadow;
+
+ light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+ transmittance_color,
+ transmittance_depth,
+ transmittance_curve,
+ transmittance_boost,
+ transmittance_z,
+#endif
+#ifdef LIGHT_RIM_USED
+ rim * omni_attenuation, rim_tint, rim_color,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+#ifdef USE_SOFT_SHADOWS
+ size_A,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light,
+ specular_light);
+}
+
+float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
+#ifndef USE_NO_SHADOWS
+ if (spot_lights.data[idx].shadow_enabled) {
+ vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ vec3 spot_dir = spot_lights.data[idx].direction;
+ //there is a shadowmap
+ vec4 v = vec4(vertex, 1.0);
+
+ v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias;
+
+ float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius;
+
+ float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map
+ vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale;
+ normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z
+ v.xyz += normal_bias;
+
+ //adjust with bias
+ z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius;
+
+ float shadow;
+
+ vec4 splane = (spot_lights.data[idx].shadow_matrix * v);
+ splane /= splane.w;
+
+#ifdef USE_SOFT_SHADOWS
+ if (spot_lights.data[idx].soft_shadow_size > 0.0) {
+ //soft shadow
+
+ //find blocker
+
+ vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
+
+ float blocker_count = 0.0;
+ float blocker_average = 0.0;
+
+ mat2 disk_rotation;
+ {
+ float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
+ float sr = sin(r);
+ float cr = cos(r);
+ disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ }
+
+ float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale;
+ vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw;
+ for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
+ suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
+ float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
+ if (d < z_norm) {
+ blocker_average += d;
+ blocker_count += 1.0;
+ }
+ }
+
+ if (blocker_count > 0.0) {
+ //blockers found, do soft shadow
+ blocker_average /= blocker_count;
+ float penumbra = (z_norm - blocker_average) / blocker_average;
+ uv_size *= penumbra;
+
+ shadow = 0.0;
+ for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
+ vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
+ suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
+ shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
+ }
+
+ shadow /= float(scene_data.penumbra_shadow_samples);
+
+ } else {
+ //no blockers found, so no shadow
+ shadow = 1.0;
+ }
+
+ } else {
+#endif
+ //hard shadow
+ vec4 shadow_uv = vec4(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z, 1.0);
+
+ shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
+#ifdef USE_SOFT_SHADOWS
+ }
+#endif
+
+ return shadow;
+ }
+
+#endif //USE_NO_SHADOWS
+
+ return 1.0;
+}
+
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+ vec4 transmittance_color,
+ float transmittance_depth,
+ float transmittance_curve,
+ float transmittance_boost,
+#endif
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint, vec3 rim_color,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 binormal, vec3 tangent, float anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ inout float alpha,
+#endif
+ inout vec3 diffuse_light,
+ inout vec3 specular_light) {
+ vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation);
+ vec3 spot_dir = spot_lights.data[idx].direction;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[idx].cone_angle);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[idx].cone_angle));
+ spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation);
+ float light_attenuation = spot_attenuation;
+ vec3 color = spot_lights.data[idx].color;
+ float specular_amount = spot_lights.data[idx].specular_amount;
+
+#ifdef USE_SOFT_SHADOWS
+ float size_A = 0.0;
+
+ if (spot_lights.data[idx].size > 0.0) {
+ float t = spot_lights.data[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ }
+#endif
+
+ /*
+ if (spot_lights.data[idx].atlas_rect!=vec4(0.0)) {
+ //use projector texture
+ }
+ */
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+ float transmittance_z = transmittance_depth;
+ transmittance_color.a *= light_attenuation;
+ {
+ splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0));
+ splane /= splane.w;
+ splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
+
+ float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
+ //reconstruct depth
+ shadow_z /= spot_lights.data[idx].inv_radius;
+ //distance to light plane
+ float z = dot(spot_dir, -light_rel_vec);
+ transmittance_z = z - shadow_z;
+ }
+#endif //LIGHT_TRANSMITTANCE_USED
+
+ light_attenuation *= shadow;
+
+ light_compute(normal, normalize(light_rel_vec), eye_vec, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+ transmittance_color,
+ transmittance_depth,
+ transmittance_curve,
+ transmittance_boost,
+ transmittance_z,
+#endif
+#ifdef LIGHT_RIM_USED
+ rim * spot_attenuation, rim_tint, rim_color,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+#ifdef USE_SOFT_SHADOW
+ size_A,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light, specular_light);
+}
+
+void reflection_process(uint ref_index, vec3 vertex, vec3 normal, float roughness, vec3 ambient_light, vec3 specular_light, inout vec4 ambient_accum, inout vec4 reflection_accum) {
+ vec3 box_extents = reflections.data[ref_index].box_extents;
+ vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz;
+
+ if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box
+ return;
+ }
+
+ vec3 ref_vec = normalize(reflect(vertex, normal));
+
+ vec3 inner_pos = abs(local_pos / box_extents);
+ float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
+ //make blend more rounded
+ blend = mix(length(inner_pos), blend, blend);
+ blend *= blend;
+ blend = max(0.0, 1.0 - blend);
+
+ if (reflections.data[ref_index].intensity > 0.0) { // compute reflection
+
+ vec3 local_ref_vec = (reflections.data[ref_index].local_matrix * vec4(ref_vec, 0.0)).xyz;
+
+ if (reflections.data[ref_index].box_project) { //box project
+
+ vec3 nrdir = normalize(local_ref_vec);
+ vec3 rbmax = (box_extents - local_pos) / nrdir;
+ vec3 rbmin = (-box_extents - local_pos) / nrdir;
+
+ vec3 rbminmax = mix(rbmin, rbmax, greaterThan(nrdir, vec3(0.0, 0.0, 0.0)));
+
+ float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
+ vec3 posonbox = local_pos + nrdir * fa;
+ local_ref_vec = posonbox - reflections.data[ref_index].box_offset;
+ }
+
+ vec4 reflection;
+
+ reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_ref_vec, reflections.data[ref_index].index), roughness * MAX_ROUGHNESS_LOD).rgb;
+
+ if (reflections.data[ref_index].exterior) {
+ reflection.rgb = mix(specular_light, reflection.rgb, blend);
+ }
+
+ reflection.rgb *= reflections.data[ref_index].intensity; //intensity
+ reflection.a = blend;
+ reflection.rgb *= reflection.a;
+
+ reflection_accum += reflection;
+ }
+
+ switch (reflections.data[ref_index].ambient_mode) {
+ case REFLECTION_AMBIENT_DISABLED: {
+ //do nothing
+ } break;
+ case REFLECTION_AMBIENT_ENVIRONMENT: {
+ //do nothing
+ vec3 local_amb_vec = (reflections.data[ref_index].local_matrix * vec4(normal, 0.0)).xyz;
+
+ vec4 ambient_out;
+
+ ambient_out.rgb = textureLod(samplerCubeArray(reflection_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(local_amb_vec, reflections.data[ref_index].index), MAX_ROUGHNESS_LOD).rgb;
+ ambient_out.a = blend;
+ if (reflections.data[ref_index].exterior) {
+ ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
+ }
+
+ ambient_out.rgb *= ambient_out.a;
+ ambient_accum += ambient_out;
+ } break;
+ case REFLECTION_AMBIENT_COLOR: {
+ vec4 ambient_out;
+ ambient_out.a = blend;
+ ambient_out.rgb = reflections.data[ref_index].ambient;
+ if (reflections.data[ref_index].exterior) {
+ ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
+ }
+ ambient_out.rgb *= ambient_out.a;
+ ambient_accum += ambient_out;
+ } break;
+ }
+}
+
+float blur_shadow(float shadow) {
+ return shadow;
+#if 0
+ //disabling for now, will investigate later
+ float interp_shadow = shadow;
+ if (gl_HelperInvocation) {
+ interp_shadow = -4.0; // technically anything below -4 will do but just to make sure
+ }
+
+ uvec2 fc2 = uvec2(gl_FragCoord.xy);
+ interp_shadow -= dFdx(interp_shadow) * (float(fc2.x & 1) - 0.5);
+ interp_shadow -= dFdy(interp_shadow) * (float(fc2.y & 1) - 0.5);
+
+ if (interp_shadow >= 0.0) {
+ shadow = interp_shadow;
+ }
+ return shadow;
+#endif
+}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
new file mode 100644
index 0000000000..aa8a0b96c5
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
@@ -0,0 +1,1510 @@
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+/* Include our forward mobile UBOs definitions etc. */
+#include "scene_forward_mobile_inc.glsl"
+
+/* INPUT ATTRIBS */
+
+layout(location = 0) in vec3 vertex_attrib;
+
+//only for pure render depth when normal is not used
+
+#ifdef NORMAL_USED
+layout(location = 1) in vec3 normal_attrib;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+layout(location = 2) in vec4 tangent_attrib;
+#endif
+
+#if defined(COLOR_USED)
+layout(location = 3) in vec4 color_attrib;
+#endif
+
+#ifdef UV_USED
+layout(location = 4) in vec2 uv_attrib;
+#endif
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL)
+layout(location = 5) in vec2 uv2_attrib;
+#endif // MODE_RENDER_MATERIAL
+
+#if defined(CUSTOM0_USED)
+layout(location = 6) in vec4 custom0_attrib;
+#endif
+
+#if defined(CUSTOM1_USED)
+layout(location = 7) in vec4 custom1_attrib;
+#endif
+
+#if defined(CUSTOM2_USED)
+layout(location = 8) in vec4 custom2_attrib;
+#endif
+
+#if defined(CUSTOM3_USED)
+layout(location = 9) in vec4 custom3_attrib;
+#endif
+
+#if defined(BONES_USED) || defined(USE_PARTICLE_TRAILS)
+layout(location = 10) in uvec4 bone_attrib;
+#endif
+
+#if defined(WEIGHTS_USED) || defined(USE_PARTICLE_TRAILS)
+layout(location = 11) in vec4 weight_attrib;
+#endif
+
+/* Varyings */
+
+layout(location = 0) out vec3 vertex_interp;
+
+#ifdef NORMAL_USED
+layout(location = 1) out vec3 normal_interp;
+#endif
+
+#if defined(COLOR_USED)
+layout(location = 2) out vec4 color_interp;
+#endif
+
+#ifdef UV_USED
+layout(location = 3) out vec2 uv_interp;
+#endif
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+layout(location = 4) out vec2 uv2_interp;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+layout(location = 5) out vec3 tangent_interp;
+layout(location = 6) out vec3 binormal_interp;
+#endif
+
+#ifdef MATERIAL_UNIFORMS_USED
+layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{
+
+#MATERIAL_UNIFORMS
+
+} material;
+#endif
+
+#ifdef MODE_DUAL_PARABOLOID
+
+layout(location = 8) out float dp_clip;
+
+#endif
+
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#define ViewIndex gl_ViewIndex
+#else
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
+#endif
+#else
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
+
+invariant gl_Position;
+
+#GLOBALS
+
+void main() {
+ vec4 instance_custom = vec4(0.0);
+#if defined(COLOR_USED)
+ color_interp = color_attrib;
+#endif
+
+ bool is_multimesh = bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH);
+
+ mat4 world_matrix = draw_call.transform;
+
+ mat3 world_normal_matrix;
+ if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) {
+ world_normal_matrix = inverse(mat3(world_matrix));
+ } else {
+ world_normal_matrix = mat3(world_matrix);
+ }
+
+ if (is_multimesh) {
+ //multimesh, instances are for it
+
+ mat4 matrix;
+
+#ifdef USE_PARTICLE_TRAILS
+ uint trail_size = (draw_call.flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK;
+ uint stride = 3 + 1 + 1; //particles always uses this format
+
+ uint offset = trail_size * stride * gl_InstanceIndex;
+
+#ifdef COLOR_USED
+ vec4 pcolor;
+#endif
+ {
+ uint boffset = offset + bone_attrib.x * stride;
+ matrix = mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.x;
+#ifdef COLOR_USED
+ pcolor = transforms.data[boffset + 3] * weight_attrib.x;
+#endif
+ }
+ if (weight_attrib.y > 0.001) {
+ uint boffset = offset + bone_attrib.y * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.y;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.y;
+#endif
+ }
+ if (weight_attrib.z > 0.001) {
+ uint boffset = offset + bone_attrib.z * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.z;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.z;
+#endif
+ }
+ if (weight_attrib.w > 0.001) {
+ uint boffset = offset + bone_attrib.w * stride;
+ matrix += mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], transforms.data[boffset + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weight_attrib.w;
+#ifdef COLOR_USED
+ pcolor += transforms.data[boffset + 3] * weight_attrib.w;
+#endif
+ }
+
+ instance_custom = transforms.data[offset + 4];
+
+#ifdef COLOR_USED
+ color_interp *= pcolor;
+#endif
+
+#else
+ uint stride = 0;
+ {
+ //TODO implement a small lookup table for the stride
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ stride += 2;
+ } else {
+ stride += 3;
+ }
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+ stride += 1;
+ }
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ stride += 1;
+ }
+ }
+
+ uint offset = stride * gl_InstanceIndex;
+
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
+ matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
+ offset += 2;
+ } else {
+ matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], transforms.data[offset + 2], vec4(0.0, 0.0, 0.0, 1.0));
+ offset += 3;
+ }
+
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+#ifdef COLOR_USED
+ color_interp *= transforms.data[offset];
+#endif
+ offset += 1;
+ }
+
+ if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ instance_custom = transforms.data[offset];
+ }
+
+#endif
+ //transpose
+ matrix = transpose(matrix);
+ world_matrix = world_matrix * matrix;
+ world_normal_matrix = world_normal_matrix * mat3(matrix);
+ }
+
+ vec3 vertex = vertex_attrib;
+#ifdef NORMAL_USED
+ vec3 normal = normal_attrib * 2.0 - 1.0;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
+ float binormalf = tangent_attrib.a * 2.0 - 1.0;
+ vec3 binormal = normalize(cross(normal, tangent) * binormalf);
+#endif
+
+#ifdef UV_USED
+ uv_interp = uv_attrib;
+#endif
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ uv2_interp = uv2_attrib;
+#endif
+
+#ifdef OVERRIDE_POSITION
+ vec4 position;
+#endif
+
+#ifdef USE_MULTIVIEW
+ mat4 projection_matrix = scene_data.projection_matrix_view[ViewIndex];
+ mat4 inv_projection_matrix = scene_data.inv_projection_matrix_view[ViewIndex];
+#else
+ mat4 projection_matrix = scene_data.projection_matrix;
+ mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
+#endif //USE_MULTIVIEW
+
+//using world coordinates
+#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
+
+ vertex = (world_matrix * vec4(vertex, 1.0)).xyz;
+
+ normal = world_normal_matrix * normal;
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+
+ tangent = world_normal_matrix * tangent;
+ binormal = world_normal_matrix * binormal;
+
+#endif
+#endif
+
+ float roughness = 1.0;
+
+ mat4 modelview = scene_data.inv_camera_matrix * world_matrix;
+ mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * world_normal_matrix;
+
+ {
+#CODE : VERTEX
+ }
+
+ /* output */
+
+// using local coordinates (default)
+#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
+
+ vertex = (modelview * vec4(vertex, 1.0)).xyz;
+#ifdef NORMAL_USED
+ normal = modelview_normal * normal;
+#endif
+
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+
+ binormal = modelview_normal * binormal;
+ tangent = modelview_normal * tangent;
+#endif
+
+//using world coordinates
+#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
+
+ vertex = (scene_data.inv_camera_matrix * vec4(vertex, 1.0)).xyz;
+ normal = mat3(scene_data.inverse_normal_matrix) * normal;
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+
+ binormal = mat3(scene_data.camera_inverse_binormal_matrix) * binormal;
+ tangent = mat3(scene_data.camera_inverse_tangent_matrix) * tangent;
+#endif
+#endif
+
+ vertex_interp = vertex;
+#ifdef NORMAL_USED
+ normal_interp = normal;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ tangent_interp = tangent;
+ binormal_interp = binormal;
+#endif
+
+#ifdef MODE_RENDER_DEPTH
+
+#ifdef MODE_DUAL_PARABOLOID
+
+ vertex_interp.z *= scene_data.dual_paraboloid_side;
+
+ dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias
+
+ //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges
+
+ vec3 vtx = vertex_interp;
+ float distance = length(vtx);
+ vtx = normalize(vtx);
+ vtx.xy /= 1.0 - vtx.z;
+ vtx.z = (distance / scene_data.z_far);
+ vtx.z = vtx.z * 2.0 - 1.0;
+ vertex_interp = vtx;
+
+#endif
+
+#endif //MODE_RENDER_DEPTH
+
+#ifdef OVERRIDE_POSITION
+ gl_Position = position;
+#else
+ gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
+#endif // OVERRIDE_POSITION
+
+#ifdef MODE_RENDER_DEPTH
+ if (scene_data.pancake_shadows) {
+ if (gl_Position.z <= 0.00001) {
+ gl_Position.z = 0.00001;
+ }
+ }
+#endif // MODE_RENDER_DEPTH
+#ifdef MODE_RENDER_MATERIAL
+ if (scene_data.material_uv2_mode) {
+ vec2 uv_offset = draw_call.lightmap_uv_scale.xy; // we are abusing lightmap_uv_scale here, we shouldn't have a lightmap during a depth pass...
+ gl_Position.xy = (uv2_attrib.xy + uv_offset) * 2.0 - 1.0;
+ gl_Position.z = 0.00001;
+ gl_Position.w = 1.0;
+ }
+#endif // MODE_RENDER_MATERIAL
+}
+
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+/* Include our forward mobile UBOs definitions etc. */
+#include "scene_forward_mobile_inc.glsl"
+
+/* Varyings */
+
+layout(location = 0) in vec3 vertex_interp;
+
+#ifdef NORMAL_USED
+layout(location = 1) in vec3 normal_interp;
+#endif
+
+#if defined(COLOR_USED)
+layout(location = 2) in vec4 color_interp;
+#endif
+
+#ifdef UV_USED
+layout(location = 3) in vec2 uv_interp;
+#endif
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+layout(location = 4) in vec2 uv2_interp;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+layout(location = 5) in vec3 tangent_interp;
+layout(location = 6) in vec3 binormal_interp;
+#endif
+
+#ifdef MODE_DUAL_PARABOLOID
+
+layout(location = 8) in float dp_clip;
+
+#endif
+
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#define ViewIndex gl_ViewIndex
+#else
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
+#endif
+#else
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
+
+//defines to keep compatibility with vertex
+
+#define world_matrix draw_call.transform
+#ifdef USE_MULTIVIEW
+#define projection_matrix scene_data.projection_matrix_view[ViewIndex]
+#else
+#define projection_matrix scene_data.projection_matrix
+#endif
+
+#if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE)
+//both required for transmittance to be enabled
+#define LIGHT_TRANSMITTANCE_USED
+#endif
+
+#ifdef MATERIAL_UNIFORMS_USED
+layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{
+
+#MATERIAL_UNIFORMS
+
+} material;
+#endif
+
+#GLOBALS
+
+/* clang-format on */
+
+#ifdef MODE_RENDER_DEPTH
+
+#ifdef MODE_RENDER_MATERIAL
+
+layout(location = 0) out vec4 albedo_output_buffer;
+layout(location = 1) out vec4 normal_output_buffer;
+layout(location = 2) out vec4 orm_output_buffer;
+layout(location = 3) out vec4 emission_output_buffer;
+layout(location = 4) out float depth_output_buffer;
+
+#endif // MODE_RENDER_MATERIAL
+
+#else // RENDER DEPTH
+
+#ifdef MODE_MULTIPLE_RENDER_TARGETS
+
+layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness
+layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter)
+#else
+
+layout(location = 0) out vec4 frag_color;
+#endif // MODE_MULTIPLE_RENDER_TARGETS
+
+#endif // RENDER DEPTH
+
+#include "scene_forward_aa_inc.glsl"
+
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+#include "scene_forward_lights_inc.glsl"
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+#ifndef MODE_RENDER_DEPTH
+
+/*
+ Only supporting normal fog here.
+*/
+
+vec4 fog_process(vec3 vertex) {
+ vec3 fog_color = scene_data.fog_light_color;
+
+ if (scene_data.fog_aerial_perspective > 0.0) {
+ vec3 sky_fog_color = vec3(0.0);
+ vec3 cube_view = scene_data.radiance_inverse_xform * vertex;
+ // mip_level always reads from the second mipmap and higher so the fog is always slightly blurred
+ float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near));
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+ float lod, blend;
+ blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod);
+ sky_fog_color = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod)).rgb;
+ sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod + 1)).rgb, blend);
+#else
+ sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb;
+#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective);
+ }
+
+ if (scene_data.fog_sun_scatter > 0.001) {
+ vec4 sun_scatter = vec4(0.0);
+ float sun_total = 0.0;
+ vec3 view = normalize(vertex);
+
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
+ vec3 light_color = directional_lights.data[i].color * directional_lights.data[i].energy;
+ float light_amount = pow(max(dot(view, directional_lights.data[i].direction), 0.0), 8.0);
+ fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
+ }
+ }
+
+ float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density));
+
+ if (abs(scene_data.fog_height_density) > 0.001) {
+ float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y;
+
+ float y_dist = scene_data.fog_height - y;
+
+ float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0);
+
+ fog_amount = max(vfog_amount, fog_amount);
+ }
+
+ return vec4(fog_color, fog_amount);
+}
+
+#endif //!MODE_RENDER DEPTH
+
+void main() {
+#ifdef MODE_DUAL_PARABOLOID
+
+ if (dp_clip > 0.0)
+ discard;
+#endif
+
+ //lay out everything, whathever is unused is optimized away anyway
+ vec3 vertex = vertex_interp;
+ vec3 view = -normalize(vertex_interp);
+ vec3 albedo = vec3(1.0);
+ vec3 backlight = vec3(0.0);
+ vec4 transmittance_color = vec4(0.0);
+ float transmittance_depth = 0.0;
+ float transmittance_curve = 1.0;
+ float transmittance_boost = 0.0;
+ float metallic = 0.0;
+ float specular = 0.5;
+ vec3 emission = vec3(0.0);
+ float roughness = 1.0;
+ float rim = 0.0;
+ float rim_tint = 0.0;
+ float clearcoat = 0.0;
+ float clearcoat_gloss = 0.0;
+ float anisotropy = 0.0;
+ vec2 anisotropy_flow = vec2(1.0, 0.0);
+ vec4 fog = vec4(0.0);
+#if defined(CUSTOM_RADIANCE_USED)
+ vec4 custom_radiance = vec4(0.0);
+#endif
+#if defined(CUSTOM_IRRADIANCE_USED)
+ vec4 custom_irradiance = vec4(0.0);
+#endif
+
+ float ao = 1.0;
+ float ao_light_affect = 0.0;
+
+ float alpha = 1.0;
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ vec3 binormal = normalize(binormal_interp);
+ vec3 tangent = normalize(tangent_interp);
+#else
+ vec3 binormal = vec3(0.0);
+ vec3 tangent = vec3(0.0);
+#endif
+
+#ifdef NORMAL_USED
+ vec3 normal = normalize(normal_interp);
+
+#if defined(DO_SIDE_CHECK)
+ if (!gl_FrontFacing) {
+ normal = -normal;
+ }
+#endif
+
+#endif //NORMAL_USED
+
+#ifdef UV_USED
+ vec2 uv = uv_interp;
+#endif
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ vec2 uv2 = uv2_interp;
+#endif
+
+#if defined(COLOR_USED)
+ vec4 color = color_interp;
+#endif
+
+#if defined(NORMAL_MAP_USED)
+
+ vec3 normal_map = vec3(0.5);
+#endif
+
+ float normal_map_depth = 1.0;
+
+ vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size + scene_data.screen_pixel_size * 0.5; //account for center
+
+ float sss_strength = 0.0;
+
+#ifdef ALPHA_SCISSOR_USED
+ float alpha_scissor_threshold = 1.0;
+#endif // ALPHA_SCISSOR_USED
+
+#ifdef ALPHA_HASH_USED
+ float alpha_hash_scale = 1.0;
+#endif // ALPHA_HASH_USED
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+ float alpha_antialiasing_edge = 0.0;
+ vec2 alpha_texture_coordinate = vec2(0.0, 0.0);
+#endif // ALPHA_ANTIALIASING_EDGE_USED
+
+ {
+#CODE : FRAGMENT
+ }
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+#ifdef SSS_MODE_SKIN
+ transmittance_color.a = sss_strength;
+#else
+ transmittance_color.a *= sss_strength;
+#endif
+#endif
+
+#ifndef USE_SHADOW_TO_OPACITY
+
+#ifdef ALPHA_SCISSOR_USED
+ if (alpha < alpha_scissor_threshold) {
+ discard;
+ }
+#endif // ALPHA_SCISSOR_USED
+
+// alpha hash can be used in unison with alpha antialiasing
+#ifdef ALPHA_HASH_USED
+ if (alpha < compute_alpha_hash_threshold(vertex, alpha_hash_scale)) {
+ discard;
+ }
+#endif // ALPHA_HASH_USED
+
+// If we are not edge antialiasing, we need to remove the output alpha channel from scissor and hash
+#if (defined(ALPHA_SCISSOR_USED) || defined(ALPHA_HASH_USED)) && !defined(ALPHA_ANTIALIASING_EDGE_USED)
+ alpha = 1.0;
+#endif
+
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+// If alpha scissor is used, we must further the edge threshold, otherwise we won't get any edge feather
+#ifdef ALPHA_SCISSOR_USED
+ alpha_antialiasing_edge = clamp(alpha_scissor_threshold + alpha_antialiasing_edge, 0.0, 1.0);
+#endif
+ alpha = compute_alpha_antialiasing_edge(alpha, alpha_texture_coordinate, alpha_antialiasing_edge);
+#endif // ALPHA_ANTIALIASING_EDGE_USED
+
+#ifdef USE_OPAQUE_PREPASS
+ if (alpha < opaque_prepass_threshold) {
+ discard;
+ }
+#endif // USE_OPAQUE_PREPASS
+
+#endif // !USE_SHADOW_TO_OPACITY
+
+#ifdef NORMAL_MAP_USED
+
+ normal_map.xy = normal_map.xy * 2.0 - 1.0;
+ normal_map.z = sqrt(max(0.0, 1.0 - dot(normal_map.xy, normal_map.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
+
+ normal = normalize(mix(normal, tangent * normal_map.x + binormal * normal_map.y + normal * normal_map.z, normal_map_depth));
+
+#endif
+
+#ifdef LIGHT_ANISOTROPY_USED
+
+ if (anisotropy > 0.01) {
+ //rotation matrix
+ mat3 rot = mat3(tangent, binormal, normal);
+ //make local to space
+ tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0));
+ binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0));
+ }
+
+#endif
+
+#ifdef ENABLE_CLIP_ALPHA
+ if (albedo.a < 0.99) {
+ //used for doublepass and shadowmapping
+ discard;
+ }
+#endif
+
+ /////////////////////// FOG //////////////////////
+#ifndef MODE_RENDER_DEPTH
+
+#ifndef CUSTOM_FOG_USED
+ // fog must be processed as early as possible and then packed.
+ // to maximize VGPR usage
+ // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
+
+ if (scene_data.fog_enabled) {
+ fog = fog_process(vertex);
+ }
+
+#endif //!CUSTOM_FOG_USED
+
+ uint fog_rg = packHalf2x16(fog.rg);
+ uint fog_ba = packHalf2x16(fog.ba);
+
+#endif //!MODE_RENDER_DEPTH
+
+ /////////////////////// DECALS ////////////////////////////////
+
+#ifndef MODE_RENDER_DEPTH
+
+ vec3 vertex_ddx = dFdx(vertex);
+ vec3 vertex_ddy = dFdy(vertex);
+
+ { //Decals
+ // must implement
+
+ uint decal_indices = draw_call.decals.x;
+ for (uint i = 0; i < 8; i++) {
+ uint decal_index = decal_indices & 0xFF;
+ if (i == 4) {
+ decal_indices = draw_call.decals.y;
+ } else {
+ decal_indices = decal_indices >> 8;
+ }
+
+ if (decal_index == 0xFF) {
+ break;
+ }
+
+ vec3 uv_local = (decals.data[decal_index].xform * vec4(vertex, 1.0)).xyz;
+ if (any(lessThan(uv_local, vec3(0.0, -1.0, 0.0))) || any(greaterThan(uv_local, vec3(1.0)))) {
+ continue; //out of decal
+ }
+
+ //we need ddx/ddy for mipmaps, so simulate them
+ vec2 ddx = (decals.data[decal_index].xform * vec4(vertex_ddx, 0.0)).xz;
+ vec2 ddy = (decals.data[decal_index].xform * vec4(vertex_ddy, 0.0)).xz;
+
+ float fade = pow(1.0 - (uv_local.y > 0.0 ? uv_local.y : -uv_local.y), uv_local.y > 0.0 ? decals.data[decal_index].upper_fade : decals.data[decal_index].lower_fade);
+
+ if (decals.data[decal_index].normal_fade > 0.0) {
+ fade *= smoothstep(decals.data[decal_index].normal_fade, 1.0, dot(normal_interp, decals.data[decal_index].normal) * 0.5 + 0.5);
+ }
+
+ if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
+ //has albedo
+ vec4 decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
+ decal_albedo *= decals.data[decal_index].modulate;
+ decal_albedo.a *= fade;
+ albedo = mix(albedo, decal_albedo.rgb, decal_albedo.a * decals.data[decal_index].albedo_mix);
+
+ if (decals.data[decal_index].normal_rect != vec4(0.0)) {
+ vec3 decal_normal = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
+ decal_normal.xy = decal_normal.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); //users prefer flipped y normal maps in most authoring software
+ decal_normal.z = sqrt(max(0.0, 1.0 - dot(decal_normal.xy, decal_normal.xy)));
+ //convert to view space, use xzy because y is up
+ decal_normal = (decals.data[decal_index].normal_xform * decal_normal.xzy).xyz;
+
+ normal = normalize(mix(normal, decal_normal, decal_albedo.a));
+ }
+
+ if (decals.data[decal_index].orm_rect != vec4(0.0)) {
+ vec3 decal_orm = textureGrad(sampler2D(decal_atlas, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
+ ao = mix(ao, decal_orm.r, decal_albedo.a);
+ roughness = mix(roughness, decal_orm.g, decal_albedo.a);
+ metallic = mix(metallic, decal_orm.b, decal_albedo.a);
+ }
+ }
+
+ if (decals.data[decal_index].emission_rect != vec4(0.0)) {
+ //emission is additive, so its independent from albedo
+ emission += textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
+ }
+ }
+ } //Decals
+#endif //!MODE_RENDER_DEPTH
+
+ /////////////////////// LIGHTING //////////////////////////////
+
+#ifdef NORMAL_USED
+ if (scene_data.roughness_limiter_enabled) {
+ //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
+ float roughness2 = roughness * roughness;
+ vec3 dndu = dFdx(normal), dndv = dFdy(normal);
+ float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv));
+ float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect
+ float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2);
+ roughness = sqrt(filteredRoughness2);
+ }
+#endif // NORMAL_USED
+ //apply energy conservation
+
+ vec3 specular_light = vec3(0.0, 0.0, 0.0);
+ vec3 diffuse_light = vec3(0.0, 0.0, 0.0);
+ vec3 ambient_light = vec3(0.0, 0.0, 0.0);
+
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+ if (scene_data.use_reflection_cubemap) {
+ vec3 ref_vec = reflect(-view, normal);
+ ref_vec = scene_data.radiance_inverse_xform * ref_vec;
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+
+ float lod, blend;
+ blend = modf(roughness * MAX_ROUGHNESS_LOD, lod);
+ specular_light = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod)).rgb;
+ specular_light = mix(specular_light, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ref_vec, lod + 1)).rgb, blend);
+
+#else // USE_RADIANCE_CUBEMAP_ARRAY
+ specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb;
+
+#endif //USE_RADIANCE_CUBEMAP_ARRAY
+ specular_light *= scene_data.ambient_light_color_energy.a;
+ }
+
+#if defined(CUSTOM_RADIANCE_USED)
+ specular_light = mix(specular_light, custom_radiance.rgb, custom_radiance.a);
+#endif // CUSTOM_RADIANCE_USED
+
+#ifndef USE_LIGHTMAP
+ //lightmap overrides everything
+ if (scene_data.use_ambient_light) {
+ ambient_light = scene_data.ambient_light_color_energy.rgb;
+
+ if (scene_data.use_ambient_cubemap) {
+ vec3 ambient_dir = scene_data.radiance_inverse_xform * normal;
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+ vec3 cubemap_ambient = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(ambient_dir, MAX_ROUGHNESS_LOD)).rgb;
+#else
+ vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
+#endif //USE_RADIANCE_CUBEMAP_ARRAY
+
+ ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
+ }
+ }
+#endif // !USE_LIGHTMAP
+
+#if defined(CUSTOM_IRRADIANCE_USED)
+ ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a);
+#endif // CUSTOM_IRRADIANCE_USED
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+ //radiance
+
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+#ifdef USE_LIGHTMAP
+
+ //lightmap
+ if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture
+ uint index = draw_call.gi_offset;
+
+ vec3 wnormal = mat3(scene_data.camera_matrix) * normal;
+ const float c1 = 0.429043;
+ const float c2 = 0.511664;
+ const float c3 = 0.743125;
+ const float c4 = 0.886227;
+ const float c5 = 0.247708;
+ ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) +
+ c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z +
+ c4 * lightmap_captures.data[index].sh[0].rgb -
+ c5 * lightmap_captures.data[index].sh[6].rgb +
+ 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y +
+ 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z +
+ 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z +
+ 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x +
+ 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y +
+ 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z);
+
+ } else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
+ bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
+ uint ofs = draw_call.gi_offset & 0xFFFF;
+ vec3 uvw;
+ uvw.xy = uv2 * draw_call.lightmap_uv_scale.zw + draw_call.lightmap_uv_scale.xy;
+ uvw.z = float((draw_call.gi_offset >> 16) & 0xFFFF);
+
+ if (uses_sh) {
+ uvw.z *= 4.0; //SH textures use 4 times more data
+ vec3 lm_light_l0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 0.0), 0.0).rgb;
+ vec3 lm_light_l1n1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 1.0), 0.0).rgb;
+ vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
+ vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
+
+ uint idx = draw_call.gi_offset >> 20;
+ vec3 n = normalize(lightmaps.data[idx].normal_xform * normal);
+
+ ambient_light += lm_light_l0 * 0.282095f;
+ ambient_light += lm_light_l1n1 * 0.32573 * n.y;
+ ambient_light += lm_light_l1_0 * 0.32573 * n.z;
+ ambient_light += lm_light_l1p1 * 0.32573 * n.x;
+ if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick
+ vec3 r = reflect(normalize(-vertex), normal);
+ specular_light += lm_light_l1n1 * 0.32573 * r.y;
+ specular_light += lm_light_l1_0 * 0.32573 * r.z;
+ specular_light += lm_light_l1p1 * 0.32573 * r.x;
+ }
+
+ } else {
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw, 0.0).rgb;
+ }
+ }
+
+ // No GI nor non low end mode...
+
+#endif // USE_LIGHTMAP
+
+ // skipping ssao, do we remove ssao totally?
+
+ { //Reflection probes
+ vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
+ vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
+
+ uint reflection_indices = draw_call.reflection_probes.x;
+ for (uint i = 0; i < 8; i++) {
+ uint reflection_index = reflection_indices & 0xFF;
+ if (i == 4) {
+ reflection_indices = draw_call.reflection_probes.y;
+ } else {
+ reflection_indices = reflection_indices >> 8;
+ }
+
+ if (reflection_index == 0xFF) {
+ break;
+ }
+
+ reflection_process(reflection_index, vertex, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum);
+ }
+
+ if (reflection_accum.a > 0.0) {
+ specular_light = reflection_accum.rgb / reflection_accum.a;
+ }
+ } //Reflection probes
+
+ // finalize ambient light here
+ ambient_light *= albedo.rgb;
+ ambient_light *= ao;
+
+ // convert ao to direct light ao
+ ao = mix(1.0, ao, ao_light_affect);
+
+ //this saves some VGPRs
+ vec3 f0 = F0(metallic, specular, albedo);
+
+ {
+#if defined(DIFFUSE_TOON)
+ //simplify for toon, as
+ specular_light *= specular * metallic * albedo * 2.0;
+#else
+
+ // scales the specular reflections, needs to be be computed before lighting happens,
+ // but after environment, GI, and reflection probes are added
+ // Environment brdf approximation (Lazarov 2013)
+ // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
+ const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
+ vec4 r = roughness * c0 + c1;
+ float ndotv = clamp(dot(normal, view), 0.0, 1.0);
+ float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
+ vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
+
+ specular_light *= env.x * f0 + env.y;
+#endif
+ }
+
+#endif // !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+#if !defined(MODE_RENDER_DEPTH)
+ //this saves some VGPRs
+ uint orms = packUnorm4x8(vec4(ao, roughness, metallic, specular));
+#endif
+
+// LIGHTING
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+ { //directional light
+
+ // Do shadow and lighting in two passes to reduce register pressure
+ uint shadow0 = 0;
+ uint shadow1 = 0;
+
+ for (uint i = 0; i < 8; i++) {
+ if (i >= scene_data.directional_light_count) {
+ break;
+ }
+
+ if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) {
+ continue; //not masked
+ }
+
+ float shadow = 1.0;
+
+ // Directional light shadow code is basically the same as forward clustered at this point in time minus `LIGHT_TRANSMITTANCE_USED` support.
+ // Not sure if there is a reason to change this seeing directional lights are part of our global data
+ // Should think about whether we may want to move this code into an include file or function??
+
+#ifdef USE_SOFT_SHADOWS
+ //version with soft shadows, more expensive
+ if (directional_lights.data[i].shadow_enabled) {
+ float depth_z = -vertex.z;
+
+ vec4 pssm_coord;
+ vec3 shadow_color = vec3(0.0);
+ vec3 light_dir = directional_lights.data[i].direction;
+
+#define BIAS_FUNC(m_var, m_idx) \
+ m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
+ vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \
+ normal_bias -= light_dir * dot(light_dir, normal_bias); \
+ m_var.xyz += normal_bias;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 0)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.x;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ shadow_color = directional_lights.data[i].shadow_color1.rgb;
+
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 1)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.y;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ shadow_color = directional_lights.data[i].shadow_color2.rgb;
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 2)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.z;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ shadow_color = directional_lights.data[i].shadow_color3.rgb;
+
+ } else {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 3)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.w;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
+ shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ shadow_color = directional_lights.data[i].shadow_color4.rgb;
+ }
+
+ if (directional_lights.data[i].blend_splits) {
+ vec3 shadow_color_blend = vec3(0.0);
+ float pssm_blend;
+ float shadow2;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 1)
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.y;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius;
+ shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ shadow_color_blend = directional_lights.data[i].shadow_color2.rgb;
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 2)
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_coord /= pssm_coord.w;
+
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.z;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius;
+ shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+
+ shadow_color_blend = directional_lights.data[i].shadow_color3.rgb;
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 3)
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_coord /= pssm_coord.w;
+ if (directional_lights.data[i].softshadow_angle > 0) {
+ float range_pos = dot(directional_lights.data[i].direction, v.xyz);
+ float range_begin = directional_lights.data[i].shadow_range_begin.w;
+ float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle;
+ vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius;
+ shadow2 = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale);
+ } else {
+ shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ }
+
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ shadow_color_blend = directional_lights.data[i].shadow_color4.rgb;
+ } else {
+ pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ }
+
+ pssm_blend = sqrt(pssm_blend);
+
+ shadow = mix(shadow, shadow2, pssm_blend);
+ shadow_color = mix(shadow_color, shadow_color_blend, pssm_blend);
+ }
+
+ shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
+
+#undef BIAS_FUNC
+ }
+#else
+ // Soft shadow disabled version
+
+ if (directional_lights.data[i].shadow_enabled) {
+ float depth_z = -vertex.z;
+
+ vec4 pssm_coord;
+ vec3 light_dir = directional_lights.data[i].direction;
+ vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
+
+#define BIAS_FUNC(m_var, m_idx) \
+ m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \
+ vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \
+ normal_bias -= light_dir * dot(light_dir, normal_bias); \
+ m_var.xyz += normal_bias;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 0)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * v);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 1)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 2)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+
+ } else {
+ vec4 v = vec4(vertex, 1.0);
+
+ BIAS_FUNC(v, 3)
+
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ }
+
+ pssm_coord /= pssm_coord.w;
+
+ shadow = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+
+ if (directional_lights.data[i].blend_splits) {
+ float pssm_blend;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 1)
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * v);
+ pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 2)
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * v);
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ vec4 v = vec4(vertex, 1.0);
+ BIAS_FUNC(v, 3)
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * v);
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ } else {
+ pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ }
+
+ pssm_coord /= pssm_coord.w;
+
+ float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord);
+ shadow = mix(shadow, shadow2, pssm_blend);
+ }
+
+ shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance
+
+#undef BIAS_FUNC
+ }
+#endif
+
+ if (i < 4) {
+ shadow0 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << (i * 8);
+ } else {
+ shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8);
+ }
+ }
+
+ for (uint i = 0; i < 8; i++) {
+ if (i >= scene_data.directional_light_count) {
+ break;
+ }
+
+ if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) {
+ continue; //not masked
+ }
+
+ // We're not doing light transmittence
+
+ float shadow = 1.0;
+
+ if (i < 4) {
+ shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0;
+ } else {
+ shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
+ }
+
+ blur_shadow(shadow);
+
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+/* not supported here
+#ifdef LIGHT_TRANSMITTANCE_USED
+ transmittance_color,
+ transmittance_depth,
+ transmittance_curve,
+ transmittance_boost,
+ transmittance_z,
+#endif
+*/
+#ifdef LIGHT_RIM_USED
+ rim, rim_tint, albedo,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+#ifdef USE_SOFT_SHADOW
+ directional_lights.data[i].size,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light,
+ specular_light);
+ }
+ } //directional light
+
+ { //omni lights
+ uint light_indices = draw_call.omni_lights.x;
+ for (uint i = 0; i < 8; i++) {
+ uint light_index = light_indices & 0xFF;
+ if (i == 4) {
+ light_indices = draw_call.omni_lights.y;
+ } else {
+ light_indices = light_indices >> 8;
+ }
+
+ if (light_index == 0xFF) {
+ break;
+ }
+
+ float shadow = light_process_omni_shadow(light_index, vertex, view);
+
+ shadow = blur_shadow(shadow);
+
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+/*
+#ifdef LIGHT_TRANSMITTANCE_USED
+ transmittance_color,
+ transmittance_depth,
+ transmittance_curve,
+ transmittance_boost,
+#endif
+*/
+#ifdef LIGHT_RIM_USED
+ rim,
+ rim_tint,
+ albedo,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ tangent, binormal, anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light, specular_light);
+ }
+ } //omni lights
+
+ { //spot lights
+
+ uint light_indices = draw_call.spot_lights.x;
+ for (uint i = 0; i < 8; i++) {
+ uint light_index = light_indices & 0xFF;
+ if (i == 4) {
+ light_indices = draw_call.spot_lights.y;
+ } else {
+ light_indices = light_indices >> 8;
+ }
+
+ if (light_index == 0xFF) {
+ break;
+ }
+
+ float shadow = light_process_spot_shadow(light_index, vertex, view);
+
+ shadow = blur_shadow(shadow);
+
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+/*
+#ifdef LIGHT_TRANSMITTANCE_USED
+ transmittance_color,
+ transmittance_depth,
+ transmittance_curve,
+ transmittance_boost,
+#endif
+*/
+#ifdef LIGHT_RIM_USED
+ rim,
+ rim_tint,
+ albedo,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ tangent, binormal, anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light, specular_light);
+ }
+ } //spot lights
+
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
+
+#if defined(ALPHA_SCISSOR_USED)
+ if (alpha < alpha_scissor) {
+ discard;
+ }
+#endif // ALPHA_SCISSOR_USED
+
+#ifdef USE_OPAQUE_PREPASS
+
+ if (alpha < opaque_prepass_threshold) {
+ discard;
+ }
+
+#endif // USE_OPAQUE_PREPASS
+
+#endif // USE_SHADOW_TO_OPACITY
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+#ifdef MODE_RENDER_DEPTH
+
+#ifdef MODE_RENDER_MATERIAL
+
+ albedo_output_buffer.rgb = albedo;
+ albedo_output_buffer.a = alpha;
+
+ normal_output_buffer.rgb = normal * 0.5 + 0.5;
+ normal_output_buffer.a = 0.0;
+ depth_output_buffer.r = -vertex.z;
+
+ orm_output_buffer.r = ao;
+ orm_output_buffer.g = roughness;
+ orm_output_buffer.b = metallic;
+ orm_output_buffer.a = sss_strength;
+
+ emission_output_buffer.rgb = emission;
+ emission_output_buffer.a = 0.0;
+#endif // MODE_RENDER_MATERIAL
+
+#else // MODE_RENDER_DEPTH
+
+ // multiply by albedo
+ diffuse_light *= albedo; // ambient must be multiplied by albedo at the end
+
+ // apply direct light AO
+ ao = unpackUnorm4x8(orms).x;
+ specular_light *= ao;
+ diffuse_light *= ao;
+
+ // apply metallic
+ metallic = unpackUnorm4x8(orms).z;
+ diffuse_light *= 1.0 - metallic;
+ ambient_light *= 1.0 - metallic;
+
+ //restore fog
+ fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba));
+
+#ifdef MODE_MULTIPLE_RENDER_TARGETS
+
+#ifdef MODE_UNSHADED
+ diffuse_buffer = vec4(albedo.rgb, 0.0);
+ specular_buffer = vec4(0.0);
+
+#else // MODE_UNSHADED
+
+#ifdef SSS_MODE_SKIN
+ sss_strength = -sss_strength;
+#endif // SSS_MODE_SKIN
+ diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength);
+ specular_buffer = vec4(specular_light, metallic);
+#endif // MODE_UNSHADED
+
+ diffuse_buffer.rgb = mix(diffuse_buffer.rgb, fog.rgb, fog.a);
+ specular_buffer.rgb = mix(specular_buffer.rgb, vec3(0.0), fog.a);
+
+#else //MODE_MULTIPLE_RENDER_TARGETS
+
+#ifdef MODE_UNSHADED
+ frag_color = vec4(albedo, alpha);
+#else // MODE_UNSHADED
+ frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha);
+ //frag_color = vec4(1.0);
+#endif // MODE_UNSHADED
+
+ // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
+ frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+
+#endif //MODE_MULTIPLE_RENDER_TARGETS
+
+#endif //MODE_RENDER_DEPTH
+}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
new file mode 100644
index 0000000000..7fcd84695d
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
@@ -0,0 +1,228 @@
+#define M_PI 3.14159265359
+#define MAX_VIEWS 2
+
+#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview)
+#extension GL_EXT_multiview : enable
+#endif
+
+#include "decal_data_inc.glsl"
+
+#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED)
+#ifndef NORMAL_USED
+#define NORMAL_USED
+#endif
+#endif
+
+/* don't exceed 128 bytes!! */
+/* put instance data into our push content, not a array */
+layout(push_constant, binding = 0, std430) uniform DrawCall {
+ mat4 transform; // 64 - 64
+ uint flags; // 04 - 68
+ uint instance_uniforms_ofs; //base offset in global buffer for instance variables // 04 - 72
+ uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) // 04 - 76
+ uint layer_mask; // 04 - 80
+ vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed
+
+ uvec2 reflection_probes; // 08 - 104
+ uvec2 omni_lights; // 08 - 112
+ uvec2 spot_lights; // 08 - 120
+ uvec2 decals; // 08 - 128
+}
+draw_call;
+
+/* Set 0: Base Pass (never changes) */
+
+#include "light_data_inc.glsl"
+
+#define SAMPLER_NEAREST_CLAMP 0
+#define SAMPLER_LINEAR_CLAMP 1
+#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
+#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
+#define SAMPLER_NEAREST_REPEAT 6
+#define SAMPLER_LINEAR_REPEAT 7
+#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
+#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
+
+layout(set = 0, binding = 1) uniform sampler material_samplers[12];
+
+layout(set = 0, binding = 2) uniform sampler shadow_sampler;
+
+#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6)
+#define INSTANCE_FLAGS_USE_SDFGI (1 << 7)
+#define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8)
+#define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9)
+#define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10)
+#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 11)
+#define INSTANCE_FLAGS_MULTIMESH (1 << 12)
+#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13)
+#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14)
+#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15)
+#define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16
+//3 bits of stride
+#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
+
+#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24)
+
+layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
+ LightData data[];
+}
+omni_lights;
+
+layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
+ LightData data[];
+}
+spot_lights;
+
+layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
+ ReflectionData data[];
+}
+reflections;
+
+layout(set = 0, binding = 6, std140) uniform DirectionalLights {
+ DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+directional_lights;
+
+#define LIGHTMAP_FLAG_USE_DIRECTION 1
+#define LIGHTMAP_FLAG_USE_SPECULAR_DIRECTION 2
+
+struct Lightmap {
+ mat3 normal_xform;
+};
+
+layout(set = 0, binding = 7, std140) restrict readonly buffer Lightmaps {
+ Lightmap data[];
+}
+lightmaps;
+
+struct LightmapCapture {
+ vec4 sh[9];
+};
+
+layout(set = 0, binding = 8, std140) restrict readonly buffer LightmapCaptures {
+ LightmapCapture data[];
+}
+lightmap_captures;
+
+layout(set = 0, binding = 9) uniform texture2D decal_atlas;
+layout(set = 0, binding = 10) uniform texture2D decal_atlas_srgb;
+
+layout(set = 0, binding = 11, std430) restrict readonly buffer Decals {
+ DecalData data[];
+}
+decals;
+
+layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableData {
+ vec4 data[];
+}
+global_variables;
+
+/* Set 1: Render Pass (changes per render pass) */
+
+layout(set = 1, binding = 0, std140) uniform SceneData {
+ mat4 projection_matrix;
+ mat4 inv_projection_matrix;
+ mat4 camera_matrix;
+ mat4 inv_camera_matrix;
+
+ // only used for multiview
+ mat4 projection_matrix_view[MAX_VIEWS];
+ mat4 inv_projection_matrix_view[MAX_VIEWS];
+
+ vec2 viewport_size;
+ vec2 screen_pixel_size;
+
+ //use vec4s because std140 doesnt play nice with vec2s, z and w are wasted
+ vec4 directional_penumbra_shadow_kernel[32];
+ vec4 directional_soft_shadow_kernel[32];
+ vec4 penumbra_shadow_kernel[32];
+ vec4 soft_shadow_kernel[32];
+
+ uint directional_penumbra_shadow_samples;
+ uint directional_soft_shadow_samples;
+ uint penumbra_shadow_samples;
+ uint soft_shadow_samples;
+
+ vec4 ambient_light_color_energy;
+
+ float ambient_color_sky_mix;
+ bool use_ambient_light;
+ bool use_ambient_cubemap;
+ bool use_reflection_cubemap;
+
+ mat3 radiance_inverse_xform;
+
+ vec2 shadow_atlas_pixel_size;
+ vec2 directional_shadow_pixel_size;
+
+ uint directional_light_count;
+ float dual_paraboloid_side;
+ float z_far;
+ float z_near;
+
+ bool ssao_enabled;
+ float ssao_light_affect;
+ float ssao_ao_affect;
+ bool roughness_limiter_enabled;
+
+ float roughness_limiter_amount;
+ float roughness_limiter_limit;
+ uvec2 roughness_limiter_pad;
+
+ vec4 ao_color;
+
+ bool fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
+
+ vec3 fog_light_color;
+ float fog_sun_scatter;
+
+ float fog_aerial_perspective;
+ bool material_uv2_mode;
+
+ float time;
+ float reflection_multiplier; // one normally, zero when rendering reflections
+
+ bool pancake_shadows;
+ uint pad1;
+ uint pad2;
+ uint pad3;
+}
+scene_data;
+
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+
+layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap;
+
+#else
+
+layout(set = 1, binding = 2) uniform textureCube radiance_cubemap;
+
+#endif
+
+layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas;
+
+layout(set = 1, binding = 4) uniform texture2D shadow_atlas;
+
+layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
+
+// this needs to change to providing just the lightmap we're using..
+layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
+
+layout(set = 1, binding = 9) uniform texture2D depth_buffer;
+layout(set = 1, binding = 10) uniform texture2D color_buffer;
+
+/* Set 2 Skeleton & Instancing (can change per item) */
+
+layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms {
+ vec4 data[];
+}
+transforms;
+
+/* Set 3 User Material */
diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl
index 669ffc961d..b831005256 100644
--- a/servers/rendering/renderer_rd/shaders/skeleton.glsl
+++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl
@@ -74,6 +74,53 @@ void main() {
#ifdef MODE_2D
vec2 vertex = uintBitsToFloat(uvec2(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1]));
+
+ if (params.has_blend_shape) {
+ float blend_total = 0.0;
+ vec2 blend_vertex = vec2(0.0);
+
+ for (uint i = 0; i < params.blend_shape_count; i++) {
+ float w = blend_shape_weights.data[i];
+ if (abs(w) > 0.0001) {
+ uint base_offset = (params.vertex_count * i + index) * params.vertex_stride;
+
+ blend_vertex += uintBitsToFloat(uvec2(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1])) * w;
+
+ base_offset += 2;
+
+ blend_total += w;
+ }
+ }
+
+ if (params.normalized_blend_shapes) {
+ vertex = (1.0 - blend_total) * vertex;
+ }
+
+ vertex += blend_vertex;
+ }
+
+ if (params.has_skeleton) {
+ uint skin_offset = params.skin_stride * index;
+
+ uvec2 bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]);
+ uvec2 bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset
+ uvec2 bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3;
+
+ skin_offset += params.skin_weight_offset;
+
+ uvec2 weights = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]);
+
+ vec2 weights_01 = unpackUnorm2x16(weights.x);
+ vec2 weights_23 = unpackUnorm2x16(weights.y);
+
+ mat4 m = mat4(bone_transforms.data[bones_01.x], bone_transforms.data[bones_01.x + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x;
+ m += mat4(bone_transforms.data[bones_01.y], bone_transforms.data[bones_01.y + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y;
+ m += mat4(bone_transforms.data[bones_23.x], bone_transforms.data[bones_23.x + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x;
+ m += mat4(bone_transforms.data[bones_23.y], bone_transforms.data[bones_23.y + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y;
+
+ //reverse order because its transposed
+ vertex = (vec4(vertex, 0.0, 1.0) * m).xy;
+ }
#else
vec3 vertex;
vec3 normal;
diff --git a/servers/rendering/renderer_rd/shaders/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl
index 9924da37d5..41c6325bc5 100644
--- a/servers/rendering/renderer_rd/shaders/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/sky.glsl
@@ -4,11 +4,17 @@
#VERSION_DEFINES
+#define MAX_VIEWS 2
+
+#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview)
+#extension GL_EXT_multiview : enable
+#endif
+
layout(location = 0) out vec2 uv_interp;
layout(push_constant, binding = 1, std430) uniform Params {
mat3 orientation;
- vec4 proj;
+ vec4 projections[MAX_VIEWS];
vec4 position_multiplier;
float time;
}
@@ -26,15 +32,29 @@ void main() {
#VERSION_DEFINES
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#extension GL_EXT_multiview : enable
+#define ViewIndex gl_ViewIndex
+#else // has_VK_KHR_multiview
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
+#endif // has_VK_KHR_multiview
+#else // USE_MULTIVIEW
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
+
#define M_PI 3.14159265359
+#define MAX_VIEWS 2
layout(location = 0) in vec2 uv_interp;
layout(push_constant, binding = 1, std430) uniform Params {
mat3 orientation;
- vec4 proj;
+ vec4 projections[MAX_VIEWS];
vec4 position_multiplier;
- float time; //TODO consider adding vec2 screen res, and float radiance size
+ float time;
}
params;
@@ -85,7 +105,6 @@ struct DirectionalLightData {
layout(set = 0, binding = 3, std140) uniform DirectionalLights {
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
-
directional_lights;
#ifdef MATERIAL_UNIFORMS_USED
@@ -154,8 +173,8 @@ vec4 fog_process(vec3 view, vec3 sky_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.x = (cube_normal.z * (-uv_interp.x - params.projections[ViewIndex].x)) / params.projections[ViewIndex].y;
+ cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projections[ViewIndex].z)) / params.projections[ViewIndex].w;
cube_normal = mat3(params.orientation) * cube_normal;
cube_normal.z = -cube_normal.z;
cube_normal = normalize(cube_normal);
diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl
index 86b4da6b08..23f83b3b9c 100644
--- a/servers/rendering/renderer_rd/shaders/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl
@@ -4,6 +4,12 @@
#VERSION_DEFINES
+#ifdef MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#extension GL_EXT_multiview : enable
+#endif
+#endif
+
layout(location = 0) out vec2 uv_interp;
void main() {
@@ -18,9 +24,22 @@ void main() {
#VERSION_DEFINES
+#ifdef MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#extension GL_EXT_multiview : enable
+#define ViewIndex gl_ViewIndex
+#else // has_VK_KHR_multiview
+#define ViewIndex 0
+#endif // has_VK_KHR_multiview
+#endif //MULTIVIEW
+
layout(location = 0) in vec2 uv_interp;
+#ifdef MULTIVIEW
+layout(set = 0, binding = 0) uniform sampler2DArray source_color;
+#else
layout(set = 0, binding = 0) uniform sampler2D source_color;
+#endif
layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
layout(set = 2, binding = 0) uniform sampler2D source_glow;
#ifdef USE_1D_LUT
@@ -277,10 +296,17 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
const float FXAA_REDUCE_MUL = (1.0 / 8.0);
const float FXAA_SPAN_MAX = 8.0;
+#ifdef MULTIVIEW
+ vec3 rgbNW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure;
+ vec3 rgbNE = textureLod(source_color, vec3(uv_interp + vec2(1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure;
+ vec3 rgbSW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure;
+ vec3 rgbSE = textureLod(source_color, vec3(uv_interp + vec2(1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure;
+#else
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;
+#endif
vec3 rgbM = color;
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
@@ -305,8 +331,13 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
dir * rcpDirMin)) *
params.pixel_size;
+#ifdef MULTIVIEW
+ vec3 rgbA = 0.5 * exposure * (textureLod(source_color, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz);
+ vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz);
+#else
vec3 rgbA = 0.5 * exposure * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz);
vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz);
+#endif
float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
@@ -329,7 +360,11 @@ vec3 screen_space_dither(vec2 frag_coord) {
}
void main() {
+#ifdef MULTIVIEW
+ vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb;
+#else
vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb;
+#endif
// Exposure
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
index cace607667..f2010222e5 100644
--- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
@@ -26,6 +26,7 @@ layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
#endif
#include "cluster_data_inc.glsl"
+#include "light_data_inc.glsl"
#define M_PI 3.14159265359
@@ -71,9 +72,9 @@ layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_ma
layout(set = 0, binding = 10) uniform sampler shadow_sampler;
-#define MAX_GI_PROBES 8
+#define MAX_VOXEL_GI_INSTANCES 8
-struct GIProbeData {
+struct VoxelGIData {
mat4 xform;
vec3 bounds;
float dynamic_range;
@@ -89,12 +90,12 @@ struct GIProbeData {
uint mipmaps;
};
-layout(set = 0, binding = 11, std140) uniform GIProbes {
- GIProbeData data[MAX_GI_PROBES];
+layout(set = 0, binding = 11, std140) uniform VoxelGIs {
+ VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
-gi_probes;
+voxel_gi_instances;
-layout(set = 0, binding = 12) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
+layout(set = 0, binding = 12) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps;
@@ -103,7 +104,7 @@ layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps;
// SDFGI Integration on set 1
#define SDFGI_MAX_CASCADES 8
-struct SDFGIProbeCascadeData {
+struct SDFVoxelGICascadeData {
vec3 position;
float to_probe;
ivec3 probe_world_offset;
@@ -134,7 +135,7 @@ layout(set = 1, binding = 0, std140) uniform SDFGI {
vec3 cascade_probe_size;
uint pad5;
- SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES];
+ SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES];
}
sdfgi;
@@ -161,7 +162,7 @@ layout(set = 0, binding = 14, std140) uniform Params {
float detail_spread;
float gi_inject;
- uint max_gi_probes;
+ uint max_voxel_gi_instances;
uint cluster_type_size;
vec2 screen_size;
@@ -532,21 +533,21 @@ void main() {
vec3 world_pos = mat3(params.cam_rotation) * view_pos;
- for (uint i = 0; i < params.max_gi_probes; i++) {
- vec3 position = (gi_probes.data[i].xform * vec4(world_pos, 1.0)).xyz;
+ for (uint i = 0; i < params.max_voxel_gi_instances; i++) {
+ vec3 position = (voxel_gi_instances.data[i].xform * vec4(world_pos, 1.0)).xyz;
//this causes corrupted pixels, i have no idea why..
- if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, gi_probes.data[i].bounds))))) {
- position /= gi_probes.data[i].bounds;
+ if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, voxel_gi_instances.data[i].bounds))))) {
+ position /= voxel_gi_instances.data[i].bounds;
vec4 light = vec4(0.0);
- for (uint j = 0; j < gi_probes.data[i].mipmaps; j++) {
- vec4 slight = textureLod(sampler3D(gi_probe_textures[i], linear_sampler_with_mipmaps), position, float(j));
+ for (uint j = 0; j < voxel_gi_instances.data[i].mipmaps; j++) {
+ vec4 slight = textureLod(sampler3D(voxel_gi_textures[i], linear_sampler_with_mipmaps), position, float(j));
float a = (1.0 - light.a);
light += a * slight;
}
- light.rgb *= gi_probes.data[i].dynamic_range * params.gi_inject;
+ light.rgb *= voxel_gi_instances.data[i].dynamic_range * params.gi_inject;
total_light += light.rgb;
}
diff --git a/servers/rendering/renderer_rd/shaders/giprobe.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl
index 49a493cdc7..49a493cdc7 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe.glsl
+++ b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl
index 7d4d72967a..7d4d72967a 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl
index e20b3f680d..e20b3f680d 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl
diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h
index 551d4f4240..d71425f465 100644
--- a/servers/rendering/renderer_scene.h
+++ b/servers/rendering/renderer_scene.h
@@ -42,13 +42,17 @@ public:
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_transform(RID p_camera, const Transform3D &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_fx) = 0;
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0;
virtual bool is_camera(RID p_camera) const = 0;
+ virtual RID occluder_allocate() = 0;
+ virtual void occluder_initialize(RID p_occluder) = 0;
+ virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) = 0;
+
virtual RID scenario_allocate() = 0;
virtual void scenario_initialize(RID p_rid) = 0;
@@ -59,6 +63,8 @@ public:
virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) = 0;
virtual bool is_scenario(RID p_scenario) const = 0;
virtual RID scenario_get_environment(RID p_scenario) = 0;
+ virtual void scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport) = 0;
+ virtual void scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport) = 0;
virtual RID instance_allocate() = 0;
virtual void instance_initialize(RID p_rid) = 0;
@@ -66,7 +72,7 @@ public:
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_set_transform(RID p_instance, const Transform3D &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_override_material(RID p_instance, int p_surface, RID p_material) = 0;
@@ -78,6 +84,7 @@ public:
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;
+ virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0;
// don't use these in a game!
virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0;
@@ -88,8 +95,7 @@ public:
virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::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;
+ virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0;
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) = 0;
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0;
@@ -185,23 +191,23 @@ public:
virtual RID render_buffers_create() = 0;
- virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0;
+ virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0;
virtual void gi_set_use_half_resolution(bool p_enable) = 0;
virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0;
virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0;
- virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0;
+ virtual void voxel_gi_set_quality(RS::VoxelGIQuality) = 0;
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0;
virtual void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) = 0;
- virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0;
- virtual void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0;
+ virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface) = 0;
virtual void update() = 0;
virtual void render_probes() = 0;
+ virtual void update_visibility_notifiers() = 0;
virtual bool free(RID p_rid) = 0;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index c7caf71fcc..60c7dbf3b7 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -74,7 +74,7 @@ void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p
camera->zfar = p_z_far;
}
-void RendererSceneCull::camera_set_transform(RID p_camera, const Transform &p_transform) {
+void RendererSceneCull::camera_set_transform(RID p_camera, const Transform3D &p_transform) {
Camera *camera = camera_owner.getornull(p_camera);
ERR_FAIL_COND(!camera);
camera->transform = p_transform.orthonormalized();
@@ -109,6 +109,20 @@ bool RendererSceneCull::is_camera(RID p_camera) const {
return camera_owner.owns(p_camera);
}
+/* OCCLUDER API */
+
+RID RendererSceneCull::occluder_allocate() {
+ return RendererSceneOcclusionCull::get_singleton()->occluder_allocate();
+}
+
+void RendererSceneCull::occluder_initialize(RID p_rid) {
+ RendererSceneOcclusionCull::get_singleton()->occluder_initialize(p_rid);
+}
+
+void RendererSceneCull::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {
+ RendererSceneOcclusionCull::get_singleton()->occluder_set_mesh(p_occluder, p_vertices, p_indices);
+}
+
/* SCENARIO API */
void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
@@ -176,26 +190,26 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture
}
- } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
+ } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_VOXEL_GI) && B->base_type == RS::INSTANCE_VOXEL_GI && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
- geom->gi_probes.insert(B);
+ geom->voxel_gi_instances.insert(B);
if (A->dynamic_gi) {
- gi_probe->dynamic_geometries.insert(A);
+ voxel_gi->dynamic_geometries.insert(A);
} else {
- gi_probe->geometries.insert(A);
+ voxel_gi->geometries.insert(A);
}
if (A->scenario && A->array_index >= 0) {
InstanceData &idata = A->scenario->instance_data[A->array_index];
- idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY;
+ idata.flags |= InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY;
}
- } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
- gi_probe->lights.insert(A);
+ } else if (B->base_type == RS::INSTANCE_VOXEL_GI && A->base_type == RS::INSTANCE_LIGHT) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data);
+ voxel_gi->lights.insert(A);
} else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data);
RSG::storage->particles_add_collision(A->base, collision->instance);
@@ -267,25 +281,25 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture
}
- } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
+ } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_VOXEL_GI) && B->base_type == RS::INSTANCE_VOXEL_GI && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
- geom->gi_probes.erase(B);
+ geom->voxel_gi_instances.erase(B);
if (A->dynamic_gi) {
- gi_probe->dynamic_geometries.erase(A);
+ voxel_gi->dynamic_geometries.erase(A);
} else {
- gi_probe->geometries.erase(A);
+ voxel_gi->geometries.erase(A);
}
if (A->scenario && A->array_index >= 0) {
InstanceData &idata = A->scenario->instance_data[A->array_index];
- idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY;
+ idata.flags |= InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY;
}
- } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
- gi_probe->lights.erase(A);
+ } else if (B->base_type == RS::INSTANCE_VOXEL_GI && A->base_type == RS::INSTANCE_LIGHT) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data);
+ voxel_gi->lights.erase(A);
} else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data);
RSG::storage->particles_remove_collision(A->base, collision->instance);
@@ -309,6 +323,9 @@ void RendererSceneCull::scenario_initialize(RID p_rid) {
scenario->instance_aabbs.set_page_pool(&instance_aabb_page_pool);
scenario->instance_data.set_page_pool(&instance_data_page_pool);
+ scenario->instance_visibility.set_page_pool(&instance_visibility_data_page_pool);
+
+ RendererSceneOcclusionCull::get_singleton()->add_scenario(p_rid);
scenario_owner.initialize_rid(p_rid, scenario);
}
@@ -353,6 +370,37 @@ RID RendererSceneCull::scenario_get_environment(RID p_scenario) {
return scenario->environment;
}
+void RendererSceneCull::scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport) {
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ if (!scenario->viewport_visibility_masks.has(p_viewport)) {
+ return;
+ }
+
+ uint64_t mask = scenario->viewport_visibility_masks[p_viewport];
+ scenario->used_viewport_visibility_bits &= ~mask;
+ scenario->viewport_visibility_masks.erase(p_viewport);
+}
+
+void RendererSceneCull::scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport) {
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ ERR_FAIL_COND(scenario->viewport_visibility_masks.has(p_viewport));
+
+ uint64_t new_mask = 1;
+ while (new_mask & scenario->used_viewport_visibility_bits) {
+ new_mask <<= 1;
+ }
+
+ if (new_mask == 0) {
+ ERR_PRINT("Only 64 viewports per scenario allowed when using visibility ranges.");
+ new_mask = ((uint64_t)1) << 63;
+ }
+
+ scenario->viewport_visibility_masks[p_viewport] = new_mask;
+ scenario->used_viewport_visibility_bits |= new_mask;
+}
+
/* INSTANCING API */
void RendererSceneCull::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) {
@@ -458,6 +506,9 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data);
RSG::storage->free(collision->instance);
} break;
+ case RS::INSTANCE_VISIBLITY_NOTIFIER: {
+ //none
+ } break;
case RS::INSTANCE_REFLECTION_PROBE: {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
scene_render->free(reflection_probe->instance);
@@ -478,25 +529,30 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
}
scene_render->free(lightmap_data->instance);
} break;
- case RS::INSTANCE_GI_PROBE: {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
+ case RS::INSTANCE_VOXEL_GI: {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data);
#ifdef DEBUG_ENABLED
- if (gi_probe->geometries.size()) {
- ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe.");
+ if (voxel_gi->geometries.size()) {
+ ERR_PRINT("BUG, indexing did not unpair geometries from VoxelGI.");
}
#endif
#ifdef DEBUG_ENABLED
- if (gi_probe->lights.size()) {
- ERR_PRINT("BUG, indexing did not unpair lights from GIProbe.");
+ if (voxel_gi->lights.size()) {
+ ERR_PRINT("BUG, indexing did not unpair lights from VoxelGI.");
}
#endif
- if (gi_probe->update_element.in_list()) {
- gi_probe_update_list.remove(&gi_probe->update_element);
+ if (voxel_gi->update_element.in_list()) {
+ voxel_gi_update_list.remove(&voxel_gi->update_element);
}
- scene_render->free(gi_probe->probe_instance);
+ scene_render->free(voxel_gi->probe_instance);
} break;
+ case RS::INSTANCE_OCCLUDER: {
+ if (scenario && instance->visible) {
+ RendererSceneOcclusionCull::get_singleton()->scenario_remove_instance(instance->scenario->self, p_instance);
+ }
+ } break;
default: {
}
}
@@ -514,6 +570,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
if (p_base.is_valid()) {
instance->base_type = RSG::storage->get_base_type(p_base);
+
+ if (instance->base_type == RS::INSTANCE_NONE && RendererSceneOcclusionCull::get_singleton()->is_occluder(p_base)) {
+ instance->base_type = RS::INSTANCE_OCCLUDER;
+ }
+
ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE);
switch (instance->base_type) {
@@ -557,6 +618,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
RSG::storage->particles_collision_instance_set_active(collision->instance, instance->visible);
instance->base_data = collision;
} break;
+ case RS::INSTANCE_VISIBLITY_NOTIFIER: {
+ InstanceVisibilityNotifierData *vnd = memnew(InstanceVisibilityNotifierData);
+ vnd->base = p_base;
+ instance->base_data = vnd;
+ } break;
case RS::INSTANCE_REFLECTION_PROBE: {
InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData);
reflection_probe->owner = instance;
@@ -576,18 +642,23 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
instance->base_data = lightmap_data;
lightmap_data->instance = scene_render->lightmap_instance_create(p_base);
} break;
- case RS::INSTANCE_GI_PROBE: {
- InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData);
- instance->base_data = gi_probe;
- gi_probe->owner = instance;
+ case RS::INSTANCE_VOXEL_GI: {
+ InstanceVoxelGIData *voxel_gi = memnew(InstanceVoxelGIData);
+ instance->base_data = voxel_gi;
+ voxel_gi->owner = instance;
- if (scenario && !gi_probe->update_element.in_list()) {
- gi_probe_update_list.add(&gi_probe->update_element);
+ if (scenario && !voxel_gi->update_element.in_list()) {
+ voxel_gi_update_list.add(&voxel_gi->update_element);
}
- gi_probe->probe_instance = scene_render->gi_probe_instance_create(p_base);
+ voxel_gi->probe_instance = scene_render->voxel_gi_instance_create(p_base);
} break;
+ case RS::INSTANCE_OCCLUDER: {
+ if (scenario) {
+ RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(scenario->self, p_instance, p_base, instance->transform, instance->visible);
+ }
+ } break;
default: {
}
}
@@ -637,22 +708,27 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
case RS::INSTANCE_PARTICLES_COLLISION: {
heightfield_particle_colliders_update_list.erase(instance);
} break;
- case RS::INSTANCE_GI_PROBE: {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
+ case RS::INSTANCE_VOXEL_GI: {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data);
#ifdef DEBUG_ENABLED
- if (gi_probe->geometries.size()) {
- ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe.");
+ if (voxel_gi->geometries.size()) {
+ ERR_PRINT("BUG, indexing did not unpair geometries from VoxelGI.");
}
#endif
#ifdef DEBUG_ENABLED
- if (gi_probe->lights.size()) {
- ERR_PRINT("BUG, indexing did not unpair lights from GIProbe.");
+ if (voxel_gi->lights.size()) {
+ ERR_PRINT("BUG, indexing did not unpair lights from VoxelGI.");
}
#endif
- if (gi_probe->update_element.in_list()) {
- gi_probe_update_list.remove(&gi_probe->update_element);
+ if (voxel_gi->update_element.in_list()) {
+ voxel_gi_update_list.remove(&voxel_gi->update_element);
+ }
+ } break;
+ case RS::INSTANCE_OCCLUDER: {
+ if (instance->visible) {
+ RendererSceneOcclusionCull::get_singleton()->scenario_remove_instance(instance->scenario->self, p_instance);
}
} break;
default: {
@@ -678,12 +754,15 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
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);
+ case RS::INSTANCE_VOXEL_GI: {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data);
+ if (!voxel_gi->update_element.in_list()) {
+ voxel_gi_update_list.add(&voxel_gi->update_element);
}
} break;
+ case RS::INSTANCE_OCCLUDER: {
+ RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(scenario->self, p_instance, instance->base, instance->transform, instance->visible);
+ } break;
default: {
}
}
@@ -707,7 +786,7 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask)
}
}
-void RendererSceneCull::instance_set_transform(RID p_instance, const Transform &p_transform) {
+void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D &p_transform) {
Instance *instance = instance_owner.getornull(p_instance);
ERR_FAIL_COND(!instance);
@@ -801,6 +880,12 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data);
RSG::storage->particles_collision_instance_set_active(collision->instance, p_visible);
}
+
+ if (instance->base_type == RS::INSTANCE_OCCLUDER) {
+ if (instance->scenario) {
+ RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(instance->scenario->self, p_instance, instance->base, instance->transform, p_visible);
+ }
+ }
}
inline bool is_geometry_instance(RenderingServer::InstanceType p_type) {
@@ -998,6 +1083,18 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF
}
} break;
+ case RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING: {
+ instance->ignore_occlusion_culling = p_enabled;
+
+ if (instance->scenario && instance->array_index >= 0) {
+ InstanceData &idata = instance->scenario->instance_data[instance->array_index];
+ if (instance->ignore_occlusion_culling) {
+ idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING;
+ } else {
+ idata.flags &= ~uint32_t(InstanceData::FLAG_IGNORE_OCCLUSION_CULLING);
+ }
+ }
+ } break;
default: {
}
}
@@ -1046,10 +1143,142 @@ void RendererSceneCull::instance_geometry_set_material_override(RID p_instance,
}
}
-void RendererSceneCull::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {
+void RendererSceneCull::instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ instance->visibility_range_begin = p_min;
+ instance->visibility_range_end = p_max;
+ instance->visibility_range_begin_margin = p_min_margin;
+ instance->visibility_range_end_margin = p_max_margin;
+
+ _update_instance_visibility_dependencies(instance);
+
+ if (instance->scenario && instance->visibility_index != -1) {
+ InstanceVisibilityData &vd = instance->scenario->instance_visibility[instance->visibility_index];
+ vd.range_begin = instance->visibility_range_begin;
+ vd.range_end = instance->visibility_range_end;
+ vd.range_begin_margin = instance->visibility_range_begin_margin;
+ vd.range_end_margin = instance->visibility_range_end_margin;
+ }
+}
+
+void RendererSceneCull::instance_set_visibility_parent(RID p_instance, RID p_parent_instance) {
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ Instance *old_parent = instance->visibility_parent;
+ if (old_parent) {
+ if ((1 << old_parent->base_type) & RS::INSTANCE_GEOMETRY_MASK && old_parent->base_data) {
+ InstanceGeometryData *old_parent_geom = static_cast<InstanceGeometryData *>(old_parent->base_data);
+ old_parent_geom->visibility_dependencies.erase(instance);
+ _update_instance_visibility_depth(old_parent);
+ }
+ instance->visibility_parent = nullptr;
+ }
+
+ Instance *parent = instance_owner.getornull(p_parent_instance);
+ ERR_FAIL_COND(p_parent_instance.is_valid() && !parent);
+
+ if (parent) {
+ if ((1 << parent->base_type) & RS::INSTANCE_GEOMETRY_MASK && parent->base_data) {
+ InstanceGeometryData *parent_geom = static_cast<InstanceGeometryData *>(parent->base_data);
+ parent_geom->visibility_dependencies.insert(instance);
+ _update_instance_visibility_depth(parent);
+ }
+ instance->visibility_parent = parent;
+ }
+
+ _update_instance_visibility_dependencies(instance);
+}
+
+void RendererSceneCull::_update_instance_visibility_depth(Instance *p_instance) {
+ bool cycle_detected = false;
+ Set<Instance *> traversed_nodes;
+
+ {
+ Instance *instance = p_instance;
+ while (instance && ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) && instance->base_data) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ if (!geom->visibility_dependencies.is_empty()) {
+ uint32_t depth = 0;
+ for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) {
+ if (((1 << E->get()->base_type) & RS::INSTANCE_GEOMETRY_MASK) == 0 || !E->get()->base_data) {
+ continue;
+ }
+ InstanceGeometryData *child_geom = static_cast<InstanceGeometryData *>(E->get()->base_data);
+ depth = MAX(depth, child_geom->visibility_dependencies_depth);
+ }
+ geom->visibility_dependencies_depth = depth + 1;
+ } else {
+ geom->visibility_dependencies_depth = 0;
+ }
+
+ if (instance->scenario && instance->visibility_index != -1) {
+ instance->scenario->instance_visibility.move(instance->visibility_index, geom->visibility_dependencies_depth);
+ }
+
+ traversed_nodes.insert(instance);
+
+ instance = instance->visibility_parent;
+ if (traversed_nodes.has(instance)) {
+ cycle_detected = true;
+ break;
+ }
+ }
+ }
+
+ if (cycle_detected) {
+ ERR_PRINT("Cycle detected in the visibility dependecies tree.");
+ for (Set<Instance *>::Element *E = traversed_nodes.front(); E; E = E->next()) {
+ Instance *instance = E->get();
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
+ geom->visibility_dependencies_depth = 0;
+ if (instance->scenario && instance->visibility_index != -1) {
+ instance->scenario->instance_visibility.move(instance->visibility_index, geom->visibility_dependencies_depth);
+ }
+ }
+ }
}
-void RendererSceneCull::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) {
+void RendererSceneCull::_update_instance_visibility_dependencies(Instance *p_instance) {
+ bool is_geometry_instance = ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) && p_instance->base_data;
+ bool has_visibility_range = p_instance->visibility_range_begin > 0.0 || p_instance->visibility_range_end > 0.0;
+ bool needs_visibility_cull = has_visibility_range && is_geometry_instance && p_instance->array_index != -1;
+
+ if (!needs_visibility_cull && p_instance->visibility_index != -1) {
+ p_instance->scenario->instance_visibility.remove(p_instance->visibility_index);
+ p_instance->visibility_index = -1;
+ } else if (needs_visibility_cull && p_instance->visibility_index == -1) {
+ InstanceVisibilityData vd;
+ vd.instance = p_instance;
+ vd.range_begin = p_instance->visibility_range_begin;
+ vd.range_end = p_instance->visibility_range_end;
+ vd.range_begin_margin = p_instance->visibility_range_begin_margin;
+ vd.range_end_margin = p_instance->visibility_range_end_margin;
+ vd.position = p_instance->transformed_aabb.get_position() + p_instance->transformed_aabb.get_size() / 2.0f;
+ vd.array_index = p_instance->array_index;
+
+ InstanceGeometryData *geom_data = static_cast<InstanceGeometryData *>(p_instance->base_data);
+ p_instance->scenario->instance_visibility.insert(vd, geom_data->visibility_dependencies_depth);
+ }
+
+ if (p_instance->scenario && p_instance->array_index != -1) {
+ p_instance->scenario->instance_data[p_instance->array_index].visibility_index = p_instance->visibility_index;
+
+ InstanceGeometryData *geom_data = static_cast<InstanceGeometryData *>(p_instance->base_data);
+ if ((has_visibility_range || p_instance->visibility_parent) && (p_instance->visibility_index == -1 || (geom_data && geom_data->visibility_dependencies_depth == 0))) {
+ p_instance->scenario->instance_data[p_instance->array_index].flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK;
+ } else {
+ p_instance->scenario->instance_data[p_instance->array_index].flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK;
+ }
+
+ if (p_instance->visibility_parent) {
+ p_instance->scenario->instance_data[p_instance->array_index].parent_array_index = p_instance->visibility_parent->array_index;
+ } else {
+ p_instance->scenario->instance_data[p_instance->array_index].parent_array_index = -1;
+ }
+ }
}
void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) {
@@ -1196,10 +1425,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
InstanceLightmapData *lightmap = static_cast<InstanceLightmapData *>(p_instance->base_data);
scene_render->lightmap_instance_set_transform(lightmap->instance, p_instance->transform);
- } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data);
+ } else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(p_instance->base_data);
- scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform);
+ scene_render->voxel_gi_instance_set_transform_to_data(voxel_gi->probe_instance, p_instance->transform);
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
RSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform);
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) {
@@ -1210,6 +1439,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
heightfield_particle_colliders_update_list.insert(p_instance);
}
RSG::storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform);
+ } else if (p_instance->base_type == RS::INSTANCE_OCCLUDER) {
+ if (p_instance->scenario) {
+ RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(p_instance->scenario->self, p_instance->self, p_instance->base, p_instance->transform, p_instance->visible);
+ }
}
if (p_instance->aabb.has_no_surface()) {
@@ -1291,12 +1524,23 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
idata.layer_mask = p_instance->layer_mask;
idata.flags = p_instance->base_type; //changing it means de-indexing, so this never needs to be changed later
idata.base_rid = p_instance->base;
+ idata.parent_array_index = p_instance->visibility_parent ? p_instance->visibility_parent->array_index : -1;
+ idata.visibility_index = p_instance->visibility_index;
+
switch (p_instance->base_type) {
case RS::INSTANCE_MESH:
case RS::INSTANCE_MULTIMESH:
case RS::INSTANCE_IMMEDIATE:
case RS::INSTANCE_PARTICLES: {
- idata.instance_geometry = static_cast<InstanceGeometryData *>(p_instance->base_data)->geometry_instance;
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
+ idata.instance_geometry = geom->geometry_instance;
+
+ for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) {
+ Instance *dep_instance = E->get();
+ if (dep_instance->array_index != -1) {
+ dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = p_instance->array_index;
+ }
+ }
} break;
case RS::INSTANCE_LIGHT: {
idata.instance_data_rid = static_cast<InstanceLightData *>(p_instance->base_data)->instance.get_id();
@@ -1310,8 +1554,11 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
case RS::INSTANCE_LIGHTMAP: {
idata.instance_data_rid = static_cast<InstanceLightmapData *>(p_instance->base_data)->instance.get_id();
} break;
- case RS::INSTANCE_GI_PROBE: {
- idata.instance_data_rid = static_cast<InstanceGIProbeData *>(p_instance->base_data)->probe_instance.get_id();
+ case RS::INSTANCE_VOXEL_GI: {
+ idata.instance_data_rid = static_cast<InstanceVoxelGIData *>(p_instance->base_data)->probe_instance.get_id();
+ } break;
+ case RS::INSTANCE_VISIBLITY_NOTIFIER: {
+ idata.visibility_notifier = static_cast<InstanceVisibilityNotifierData *>(p_instance->base_data);
} break;
default: {
}
@@ -1337,9 +1584,13 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
if (p_instance->mesh_instance.is_valid()) {
idata.flags |= InstanceData::FLAG_USES_MESH_INSTANCE;
}
+ if (p_instance->ignore_occlusion_culling) {
+ idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING;
+ }
p_instance->scenario->instance_data.push_back(idata);
p_instance->scenario->instance_aabbs.push_back(InstanceBounds(p_instance->transformed_aabb));
+ _update_instance_visibility_dependencies(p_instance);
} else {
if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].update(p_instance->indexer_id, bvh_aabb);
@@ -1349,6 +1600,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
p_instance->scenario->instance_aabbs[p_instance->array_index] = InstanceBounds(p_instance->transformed_aabb);
}
+ if (p_instance->visibility_index != -1) {
+ p_instance->scenario->instance_visibility[p_instance->visibility_index].position = p_instance->transformed_aabb.get_position() + p_instance->transformed_aabb.get_size() / 2.0f;
+ }
+
//move instance and repair
pair_pass++;
@@ -1361,8 +1616,11 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
pair.pair_mask |= 1 << RS::INSTANCE_LIGHT;
- pair.pair_mask |= 1 << RS::INSTANCE_GI_PROBE;
+ pair.pair_mask |= 1 << RS::INSTANCE_VOXEL_GI;
pair.pair_mask |= 1 << RS::INSTANCE_LIGHTMAP;
+ if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
+ pair.pair_mask |= 1 << RS::INSTANCE_PARTICLES_COLLISION;
+ }
pair.pair_mask |= geometry_instance_pair_mask;
@@ -1372,7 +1630,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
if (RSG::storage->light_get_bake_mode(p_instance->base) == RS::LIGHT_BAKE_DYNAMIC) {
- pair.pair_mask |= (1 << RS::INSTANCE_GI_PROBE);
+ pair.pair_mask |= (1 << RS::INSTANCE_VOXEL_GI);
pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES];
}
} else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) {
@@ -1384,7 +1642,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) {
pair.pair_mask = (1 << RS::INSTANCE_PARTICLES);
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
- } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) {
+ } else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) {
//lights and geometries
pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT);
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
@@ -1419,9 +1677,24 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) {
//replace this by last
int32_t swap_with_index = p_instance->scenario->instance_data.size() - 1;
if (swap_with_index != p_instance->array_index) {
- p_instance->scenario->instance_data[swap_with_index].instance->array_index = p_instance->array_index; //swap
+ Instance *swapped_instance = p_instance->scenario->instance_data[swap_with_index].instance;
+ swapped_instance->array_index = p_instance->array_index; //swap
p_instance->scenario->instance_data[p_instance->array_index] = p_instance->scenario->instance_data[swap_with_index];
p_instance->scenario->instance_aabbs[p_instance->array_index] = p_instance->scenario->instance_aabbs[swap_with_index];
+
+ if (swapped_instance->visibility_index != -1) {
+ swapped_instance->scenario->instance_visibility[swapped_instance->visibility_index].array_index = swapped_instance->array_index;
+ }
+
+ if ((1 << swapped_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(swapped_instance->base_data);
+ for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) {
+ Instance *dep_instance = E->get();
+ if (dep_instance != p_instance && dep_instance->array_index != -1) {
+ dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = swapped_instance->array_index;
+ }
+ }
+ }
}
// pop last
@@ -1437,8 +1710,17 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) {
scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, nullptr, 0);
scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, nullptr, 0);
scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, nullptr, 0);
- scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, nullptr, 0);
+ scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, nullptr, 0);
+
+ for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) {
+ Instance *dep_instance = E->get();
+ if (dep_instance->array_index != -1) {
+ dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = -1;
+ }
+ }
}
+
+ _update_instance_visibility_dependencies(p_instance);
}
void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
@@ -1487,6 +1769,9 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base);
} break;
+ case RenderingServer::INSTANCE_VISIBLITY_NOTIFIER: {
+ new_aabb = RSG::storage->visibility_notifier_get_aabb(p_instance->base);
+ } break;
case RenderingServer::INSTANCE_LIGHT: {
new_aabb = RSG::storage->light_get_aabb(p_instance->base);
@@ -1499,8 +1784,8 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
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);
+ case RenderingServer::INSTANCE_VOXEL_GI: {
+ new_aabb = RSG::storage->voxel_gi_get_bounds(p_instance->base);
} break;
case RenderingServer::INSTANCE_LIGHTMAP: {
@@ -1538,7 +1823,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
continue; //we are inside, ignore exteriors
}
- Transform to_bounds = lightmap->transform.affine_inverse();
+ Transform3D to_bounds = lightmap->transform.affine_inverse();
Vector3 center = p_instance->transform.xform(p_instance->aabb.position + p_instance->aabb.size * 0.5); //use aabb center
Vector3 lm_pos = to_bounds.xform(center);
@@ -1599,10 +1884,10 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, p_instance->lightmap_sh.ptr());
}
-void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) {
+void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) {
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
- Transform light_transform = p_instance->transform;
+ Transform3D light_transform = p_instance->transform;
light_transform.orthonormalize(); //scale does not count on lights
real_t max_distance = p_cam_projection.get_z_far();
@@ -1678,7 +1963,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
// obtain the light frustum ranges (given endpoints)
- Transform transform = light_transform; //discard scale and stabilize light
+ Transform3D 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();
@@ -1877,7 +2162,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam));
- Transform ortho_transform;
+ Transform3D 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;
@@ -1894,10 +2179,10 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
}
}
-bool RendererSceneCull::_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, float p_screen_lod_threshold) {
+bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_lod_threshold) {
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
- Transform light_transform = p_instance->transform;
+ Transform3D light_transform = p_instance->transform;
light_transform.orthonormalize(); //scale does not count on lights
bool animated_material_found = false;
@@ -2004,7 +2289,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
Vector3(0, -1, 0)
};
- Transform xform = light_transform * Transform().looking_at(view_normals[i], view_up[i]);
+ Transform3D xform = light_transform * Transform3D().looking_at(view_normals[i], view_up[i]);
Vector<Plane> planes = cm.get_projection_planes(xform);
@@ -2119,150 +2404,159 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
return animated_material_found;
}
-void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) {
-// render to mono camera
+void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface) {
#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;
+ RendererSceneRender::CameraData camera_data;
+
+ // Setup Camera(s)
+ if (p_xr_interface.is_null()) {
+ // Normal camera
+ Transform3D transform = camera->transform;
+ CameraMatrix projection;
+ bool vaspect = camera->vaspect;
+ bool is_ortogonal = false;
+
+ switch (camera->type) {
+ case Camera::ORTHOGONAL: {
+ projection.set_orthogonal(
+ camera->size,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect);
+ is_ortogonal = true;
+ } break;
+ case Camera::PERSPECTIVE: {
+ projection.set_perspective(
+ camera->fov,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect);
- } 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;
+ } break;
+ case Camera::FRUSTUM: {
+ projection.set_frustum(
+ camera->size,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->offset,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect);
+ } break;
+ }
+
+ camera_data.set_camera(transform, projection, is_ortogonal, vaspect);
+ } else {
+ // Setup our camera for our XR interface.
+ // We can support multiple views here each with their own camera
+ Transform3D transforms[RendererSceneRender::MAX_RENDER_VIEWS];
+ CameraMatrix projections[RendererSceneRender::MAX_RENDER_VIEWS];
+
+ uint32_t view_count = p_xr_interface->get_view_count();
+ ERR_FAIL_COND_MSG(view_count > RendererSceneRender::MAX_RENDER_VIEWS, "Requested view count is not supported");
+
+ float aspect = p_viewport_size.width / (float)p_viewport_size.height;
+
+ Transform3D world_origin = XRServer::get_singleton()->get_world_origin();
+
+ // We ignore our camera position, it will have been positioned with a slightly old tracking position.
+ // Instead we take our origin point and have our XR interface add fresh tracking data! Whoohoo!
+ for (uint32_t v = 0; v < view_count; v++) {
+ transforms[v] = p_xr_interface->get_transform_for_view(v, world_origin);
+ projections[v] = p_xr_interface->get_projection_for_view(v, aspect, camera->znear, camera->zfar);
+ }
+
+ if (view_count == 1) {
+ camera_data.set_camera(transforms[0], projections[0], false, camera->vaspect);
+ } else if (view_count == 2) {
+ camera_data.set_multiview_camera(view_count, transforms, projections, false, camera->vaspect);
+ } else {
+ // this won't be called (see fail check above) but keeping this comment to indicate we may support more then 2 views in the future...
+ }
}
RID environment = _render_get_environment(p_camera, p_scenario);
- _render_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold);
+ RENDER_TIMESTAMP("Update occlusion buffer")
+ // For now just cull on the first camera
+ RendererSceneOcclusionCull::get_singleton()->buffer_update(p_viewport, camera_data.main_transform, camera_data.main_projection, camera_data.is_ortogonal, RendererThreadPool::singleton->thread_work_pool);
+
+ _render_scene(&camera_data, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_viewport, p_shadow_atlas, RID(), -1, p_screen_lod_threshold);
#endif
}
-void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) {
- // render for AR/VR interface
-#if 0
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
+void RendererSceneCull::_visibility_cull_threaded(uint32_t p_thread, VisibilityCullData *cull_data) {
+ uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
+ uint32_t bin_from = p_thread * cull_data->cull_count / total_threads;
+ uint32_t bin_to = (p_thread + 1 == total_threads) ? cull_data->cull_count : ((p_thread + 1) * cull_data->cull_count / total_threads);
- /* 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);
+ _visibility_cull(*cull_data, cull_data->cull_offset + bin_from, cull_data->cull_offset + bin_to);
+}
- // 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);
+void RendererSceneCull::_visibility_cull(const VisibilityCullData &cull_data, uint64_t p_from, uint64_t p_to) {
+ Scenario *scenario = cull_data.scenario;
+ for (unsigned int i = p_from; i < p_to; i++) {
+ InstanceVisibilityData &vd = scenario->instance_visibility[i];
+ InstanceData &idata = scenario->instance_data[vd.array_index];
- RID environment = _render_get_environment(p_camera, p_scenario);
+ if (idata.parent_array_index >= 0) {
+ uint32_t parent_flags = scenario->instance_data[idata.parent_array_index].flags;
+ if ((parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN) || (parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE) == 0) {
+ idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
+ continue;
+ }
+ }
- // 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, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold);
- } else if (p_eye == XRInterface::EYE_MONO) {
- // For mono render, prepare as per usual
- _prepare_scene(cam_transform, camera_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold);
- }
-
- // And render our scene...
- _render_scene(p_render_buffers, cam_transform, camera_matrix, false, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold);
-#endif
-};
+ int range_check = _visibility_range_check(vd, cull_data.camera_position, cull_data.viewport_mask);
+
+ if (range_check == -1) {
+ idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
+ } else if (range_check == 1) {
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
+ idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
+ } else {
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
+ idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
+ }
+ }
+}
-void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data) {
+int RendererSceneCull::_visibility_range_check(InstanceVisibilityData &r_vis_data, const Vector3 &p_camera_pos, uint64_t p_viewport_mask) {
+ float dist = p_camera_pos.distance_to(r_vis_data.position);
+
+ bool in_range_last_frame = p_viewport_mask & r_vis_data.viewport_state;
+ float begin_offset = in_range_last_frame ? -r_vis_data.range_begin_margin : r_vis_data.range_begin_margin;
+ float end_offset = in_range_last_frame ? r_vis_data.range_end_margin : -r_vis_data.range_end_margin;
+
+ if (r_vis_data.range_end > 0.0f && dist > r_vis_data.range_end + end_offset) {
+ r_vis_data.viewport_state &= ~p_viewport_mask;
+ return -1;
+ } else if (r_vis_data.range_begin > 0.0f && dist < r_vis_data.range_begin + begin_offset) {
+ r_vis_data.viewport_state &= ~p_viewport_mask;
+ return 1;
+ } else {
+ r_vis_data.viewport_state |= p_viewport_mask;
+ return 0;
+ }
+}
+
+void RendererSceneCull::_scene_cull_threaded(uint32_t p_thread, CullData *cull_data) {
uint32_t cull_total = cull_data->scenario->instance_data.size();
uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
uint32_t cull_from = p_thread * cull_total / total_threads;
uint32_t cull_to = (p_thread + 1 == total_threads) ? cull_total : ((p_thread + 1) * cull_total / total_threads);
- _frustum_cull(*cull_data, frustum_cull_result_threads[p_thread], cull_from, cull_to);
+ _scene_cull(*cull_data, scene_cull_result_threads[p_thread], cull_from, cull_to);
}
-void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) {
+void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to) {
uint64_t frame_number = RSG::rasterizer->get_frame_number();
float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time();
@@ -2271,178 +2565,207 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes
RID instance_pair_buffer[MAX_INSTANCE_PAIRS];
+ Transform3D inv_cam_transform = cull_data.cam_transform.inverse();
+ float z_near = cull_data.camera_matrix->get_z_near();
+
for (uint64_t i = p_from; i < p_to; i++) {
bool mesh_visible = false;
- if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum)) {
- InstanceData &idata = cull_data.scenario->instance_data[i];
- uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
-
- if ((cull_data.visible_layers & idata.layer_mask) == 0) {
- //failure
- } else if (base_type == RS::INSTANCE_LIGHT) {
- cull_result.lights.push_back(idata.instance);
- cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid));
- if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) {
- scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later
- }
+ InstanceData &idata = cull_data.scenario->instance_data[i];
+ uint32_t visibility_flags = idata.flags & (InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE | InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN);
+ int32_t visibility_check = -1;
- } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) {
- if (cull_data.render_reflection_probe != idata.instance) {
- //avoid entering The Matrix
+#define HIDDEN_BY_VISIBILITY_CHECKS (visibility_flags == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE || visibility_flags == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN)
+#define LAYER_CHECK (cull_data.visible_layers & idata.layer_mask)
+#define IN_FRUSTUM(f) (cull_data.scenario->instance_aabbs[i].in_frustum(f))
+#define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_cull_data->viewport_mask) == 0)
+#define VIS_PARENT_CHECK ((idata.parent_array_index == -1) || ((cull_data.scenario->instance_data[idata.parent_array_index].flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK) == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE))
+#define VIS_CHECK (visibility_check < 0 ? (visibility_check = (visibility_flags != InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK || (VIS_RANGE_CHECK && VIS_PARENT_CHECK))) : visibility_check)
+#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near))
- if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) {
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data);
- cull_data.cull->lock.lock();
- if (!reflection_probe->update_list.in_list()) {
- reflection_probe->render_step = 0;
- reflection_probe_render_list.add_last(&reflection_probe->update_list);
- }
- cull_data.cull->lock.unlock();
-
- idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY);
+ if (!HIDDEN_BY_VISIBILITY_CHECKS) {
+ if (LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) {
+ uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
+ if (base_type == RS::INSTANCE_LIGHT) {
+ cull_result.lights.push_back(idata.instance);
+ cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid));
+ if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) {
+ scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later
}
- if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) {
- cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid));
- }
- }
- } else if (base_type == RS::INSTANCE_DECAL) {
- cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid));
-
- } else if (base_type == RS::INSTANCE_GI_PROBE) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(idata.instance->base_data);
- cull_data.cull->lock.lock();
- if (!gi_probe->update_element.in_list()) {
- gi_probe_update_list.add(&gi_probe->update_element);
- }
- cull_data.cull->lock.unlock();
- cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid));
+ } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) {
+ if (cull_data.render_reflection_probe != idata.instance) {
+ //avoid entering The Matrix
- } else if (base_type == RS::INSTANCE_LIGHTMAP) {
- cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid));
- } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) {
- bool keep = true;
+ if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) {
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data);
+ cull_data.cull->lock.lock();
+ if (!reflection_probe->update_list.in_list()) {
+ reflection_probe->render_step = 0;
+ reflection_probe_render_list.add_last(&reflection_probe->update_list);
+ }
+ cull_data.cull->lock.unlock();
- if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) {
- RenderingServerDefault::redraw_request();
- }
+ idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY);
+ }
- if (base_type == RS::INSTANCE_MESH) {
- mesh_visible = true;
- } else if (base_type == RS::INSTANCE_PARTICLES) {
- //particles visible? process them
- if (RSG::storage->particles_is_inactive(idata.base_rid)) {
- //but if nothing is going on, don't do it.
- keep = false;
- } else {
- cull_data.cull->lock.lock();
- RSG::storage->particles_request_process(idata.base_rid);
- cull_data.cull->lock.unlock();
- RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized());
- //particles visible? request redraw
- RenderingServerDefault::redraw_request();
+ if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) {
+ cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid));
+ }
}
- }
+ } else if (base_type == RS::INSTANCE_DECAL) {
+ cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid));
+
+ } else if (base_type == RS::INSTANCE_VOXEL_GI) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(idata.instance->base_data);
+ cull_data.cull->lock.lock();
+ if (!voxel_gi->update_element.in_list()) {
+ voxel_gi_update_list.add(&voxel_gi->update_element);
+ }
+ cull_data.cull->lock.unlock();
+ cull_result.voxel_gi_instances.push_back(RID::from_uint64(idata.instance_data_rid));
+
+ } else if (base_type == RS::INSTANCE_LIGHTMAP) {
+ cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid));
+ } else if (base_type == RS::INSTANCE_VISIBLITY_NOTIFIER) {
+ InstanceVisibilityNotifierData *vnd = idata.visibility_notifier;
+ if (!vnd->list_element.in_list()) {
+ visible_notifier_list_lock.lock();
+ visible_notifier_list.add(&vnd->list_element);
+ visible_notifier_list_lock.unlock();
+ vnd->just_visible = true;
+ }
+ vnd->visible_in_frame = RSG::rasterizer->get_frame_number();
+ } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) {
+ bool keep = true;
- if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) {
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- uint32_t idx = 0;
+ if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) {
+ RenderingServerDefault::redraw_request();
+ }
- for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) {
- InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
- instance_pair_buffer[idx++] = light->instance;
- if (idx == MAX_INSTANCE_PAIRS) {
- break;
+ if (base_type == RS::INSTANCE_MESH) {
+ mesh_visible = true;
+ } else if (base_type == RS::INSTANCE_PARTICLES) {
+ //particles visible? process them
+ if (RSG::storage->particles_is_inactive(idata.base_rid)) {
+ //but if nothing is going on, don't do it.
+ keep = false;
+ } else {
+ cull_data.cull->lock.lock();
+ RSG::storage->particles_request_process(idata.base_rid);
+ cull_data.cull->lock.unlock();
+ RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized(), cull_data.cam_transform.basis.get_axis(1).normalized());
+ //particles visible? request redraw
+ RenderingServerDefault::redraw_request();
}
}
- scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx);
- idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY);
- }
+ if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ uint32_t idx = 0;
+
+ for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) {
+ InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
+ instance_pair_buffer[idx++] = light->instance;
+ if (idx == MAX_INSTANCE_PAIRS) {
+ break;
+ }
+ }
+
+ scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY);
+ }
- if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) {
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- uint32_t idx = 0;
+ if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ uint32_t idx = 0;
- for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) {
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);
+ for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) {
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);
- instance_pair_buffer[idx++] = reflection_probe->instance;
- if (idx == MAX_INSTANCE_PAIRS) {
- break;
+ instance_pair_buffer[idx++] = reflection_probe->instance;
+ if (idx == MAX_INSTANCE_PAIRS) {
+ break;
+ }
}
+
+ scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY);
}
- scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx);
- idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY);
- }
+ if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ uint32_t idx = 0;
- if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) {
- //InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- //todo for GLES3
- idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY);
- /*for (Set<Instance *>::Element *E = geom->dec.front(); E; E = E->next()) {
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);
+ for (Set<Instance *>::Element *E = geom->decals.front(); E; E = E->next()) {
+ InstanceDecalData *decal = static_cast<InstanceDecalData *>(E->get()->base_data);
- instance_pair_buffer[idx++] = reflection_probe->instance;
- if (idx==MAX_INSTANCE_PAIRS) {
- break;
+ instance_pair_buffer[idx++] = decal->instance;
+ if (idx == MAX_INSTANCE_PAIRS) {
+ break;
+ }
+ }
+ scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY);
}
- }*/
- //scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, light_instances, idx);
- }
- if (idata.flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY) {
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- uint32_t idx = 0;
- for (Set<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) {
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data);
+ if (idata.flags & InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ uint32_t idx = 0;
+ for (Set<Instance *>::Element *E = geom->voxel_gi_instances.front(); E; E = E->next()) {
+ InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(E->get()->base_data);
- instance_pair_buffer[idx++] = gi_probe->probe_instance;
- if (idx == MAX_INSTANCE_PAIRS) {
- break;
+ instance_pair_buffer[idx++] = voxel_gi->probe_instance;
+ if (idx == MAX_INSTANCE_PAIRS) {
+ break;
+ }
}
- }
- scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx);
- idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY);
- }
+ scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY);
+ }
- if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) {
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
- Color *sh = idata.instance->lightmap_sh.ptrw();
- const Color *target_sh = idata.instance->lightmap_target_sh.ptr();
- for (uint32_t j = 0; j < 9; j++) {
- sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed));
+ if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) {
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
+ Color *sh = idata.instance->lightmap_sh.ptrw();
+ const Color *target_sh = idata.instance->lightmap_target_sh.ptr();
+ for (uint32_t j = 0; j < 9; j++) {
+ sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed));
+ }
+ scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh);
+ idata.instance->last_frame_pass = frame_number;
}
- scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh);
- idata.instance->last_frame_pass = frame_number;
- }
- if (keep) {
- cull_result.geometry_instances.push_back(idata.instance_geometry);
+ if (keep) {
+ cull_result.geometry_instances.push_back(idata.instance_geometry);
+ }
}
}
- }
- for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) {
- for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) {
- if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->shadows[j].cascades[k].frustum)) {
- InstanceData &idata = cull_data.scenario->instance_data[i];
- uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
+ for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) {
+ for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) {
+ if (IN_FRUSTUM(cull_data.cull->shadows[j].cascades[k].frustum) && VIS_CHECK) {
+ uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
- if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) {
- cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry);
- mesh_visible = true;
+ if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) {
+ cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry);
+ mesh_visible = true;
+ }
}
}
}
}
+#undef HIDDEN_BY_VISIBILITY_CHECKS
+#undef LAYER_CHECK
+#undef IN_FRUSTUM
+#undef VIS_RANGE_CHECK
+#undef VIS_PARENT_CHECK
+#undef VIS_CHECK
+#undef OCCLUSION_CULLED
+
for (uint32_t j = 0; j < cull_data.cull->sdfgi.region_count; j++) {
if (cull_data.scenario->instance_aabbs[i].in_aabb(cull_data.cull->sdfgi.region_aabb[j])) {
- InstanceData &idata = cull_data.scenario->instance_data[i];
uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
if (base_type == RS::INSTANCE_LIGHT) {
@@ -2469,11 +2792,7 @@ void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullRes
}
}
-void RendererSceneCull::_render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows) {
- // 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
-
+void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows) {
Instance *render_reflection_probe = instance_owner.getornull(p_reflection_probe); //if null, not rendering to it
Scenario *scenario = scenario_owner.getornull(p_scenario);
@@ -2484,16 +2803,44 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
if (p_render_buffers.is_valid()) {
//no rendering code here, this is only to set up what needs to be done, request regions, etc.
- scene_render->sdfgi_update(p_render_buffers, p_environment, p_cam_transform.origin); //update conditions for SDFGI (whether its used or not)
+ scene_render->sdfgi_update(p_render_buffers, p_environment, p_camera_data->main_transform.origin); //update conditions for SDFGI (whether its used or not)
+ }
+
+ RENDER_TIMESTAMP("Visibility Dependencies");
+
+ VisibilityCullData visibility_cull_data;
+ if (scenario->instance_visibility.get_bin_count() > 0) {
+ if (!scenario->viewport_visibility_masks.has(p_viewport)) {
+ scenario_add_viewport_visibility_mask(scenario->self, p_viewport);
+ }
+
+ visibility_cull_data.scenario = scenario;
+ visibility_cull_data.viewport_mask = scenario->viewport_visibility_masks[p_viewport];
+ visibility_cull_data.camera_position = p_camera_data->main_transform.origin;
+
+ for (int i = scenario->instance_visibility.get_bin_count() - 1; i > 0; i--) { // We skip bin 0
+ visibility_cull_data.cull_offset = scenario->instance_visibility.get_bin_start(i);
+ visibility_cull_data.cull_count = scenario->instance_visibility.get_bin_size(i);
+
+ if (visibility_cull_data.cull_count == 0) {
+ continue;
+ }
+
+ if (visibility_cull_data.cull_count > thread_cull_threshold) {
+ RendererThreadPool::singleton->thread_work_pool.do_work(RendererThreadPool::singleton->thread_work_pool.get_thread_count(), this, &RendererSceneCull::_visibility_cull_threaded, &visibility_cull_data);
+ } else {
+ _visibility_cull(visibility_cull_data, visibility_cull_data.cull_offset, visibility_cull_data.cull_offset + visibility_cull_data.cull_count);
+ }
+ }
}
- RENDER_TIMESTAMP("Frustum Culling");
+ RENDER_TIMESTAMP("Culling");
- //rasterizer->set_camera(camera->transform, camera_matrix,ortho);
+ //rasterizer->set_camera(p_camera_data->main_transform, p_camera_data.main_projection, p_camera_data.is_ortogonal);
- Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform);
+ Vector<Plane> planes = p_camera_data->main_projection.get_projection_planes(p_camera_data->main_transform);
- Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized());
+ Plane near_plane(p_camera_data->main_transform.origin, -p_camera_data->main_transform.basis.get_axis(2).normalized());
/* STEP 2 - CULL */
@@ -2531,7 +2878,7 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
scene_render->set_directional_shadow_count(lights_with_shadow.size());
for (int i = 0; i < lights_with_shadow.size(); i++) {
- _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect);
+ _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_ortogonal, p_camera_data->vaspect);
}
}
@@ -2560,40 +2907,42 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
}
}
- frustum_cull_result.clear();
+ scene_cull_result.clear();
{
uint64_t cull_from = 0;
uint64_t cull_to = scenario->instance_data.size();
- FrustumCullData cull_data;
+ CullData cull_data;
//prepare for eventual thread usage
cull_data.cull = &cull;
cull_data.scenario = scenario;
cull_data.shadow_atlas = p_shadow_atlas;
- cull_data.cam_transform = p_cam_transform;
+ cull_data.cam_transform = p_camera_data->main_transform;
cull_data.visible_layers = p_visible_layers;
cull_data.render_reflection_probe = render_reflection_probe;
+ cull_data.occlusion_buffer = RendererSceneOcclusionCull::get_singleton()->buffer_get_ptr(p_viewport);
+ cull_data.camera_matrix = &p_camera_data->main_projection;
//#define DEBUG_CULL_TIME
#ifdef DEBUG_CULL_TIME
uint64_t time_from = OS::get_singleton()->get_ticks_usec();
#endif
if (cull_to > thread_cull_threshold) {
//multiple threads
- for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
- frustum_cull_result_threads[i].clear();
+ for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
+ scene_cull_result_threads[i].clear();
}
- RendererThreadPool::singleton->thread_work_pool.do_work(frustum_cull_result_threads.size(), this, &RendererSceneCull::_frustum_cull_threaded, &cull_data);
+ RendererThreadPool::singleton->thread_work_pool.do_work(scene_cull_result_threads.size(), this, &RendererSceneCull::_scene_cull_threaded, &cull_data);
- for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
- frustum_cull_result.append_from(frustum_cull_result_threads[i]);
+ for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
+ scene_cull_result.append_from(scene_cull_result_threads[i]);
}
} else {
//single threaded
- _frustum_cull(cull_data, frustum_cull_result, cull_from, cull_to);
+ _scene_cull(cull_data, scene_cull_result, cull_from, cull_to);
}
#ifdef DEBUG_CULL_TIME
@@ -2604,9 +2953,9 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
print_line("time taken: " + rtos(time_avg / time_count));
#endif
- if (frustum_cull_result.mesh_instances.size()) {
- for (uint64_t i = 0; i < frustum_cull_result.mesh_instances.size(); i++) {
- RSG::storage->mesh_instance_check_for_update(frustum_cull_result.mesh_instances[i]);
+ if (scene_cull_result.mesh_instances.size()) {
+ for (uint64_t i = 0; i < scene_cull_result.mesh_instances.size(); i++) {
+ RSG::storage->mesh_instance_check_for_update(scene_cull_result.mesh_instances[i]);
}
RSG::storage->update_mesh_instances();
}
@@ -2630,14 +2979,14 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
}
render_shadow_data[max_shadows_used].light = cull.shadows[i].light_instance;
render_shadow_data[max_shadows_used].pass = j;
- render_shadow_data[max_shadows_used].instances.merge_unordered(frustum_cull_result.directional_shadows[i].cascade_geometry_instances[j]);
+ render_shadow_data[max_shadows_used].instances.merge_unordered(scene_cull_result.directional_shadows[i].cascade_geometry_instances[j]);
max_shadows_used++;
}
}
// Positional Shadowss
- for (uint32_t i = 0; i < (uint32_t)frustum_cull_result.lights.size(); i++) {
- Instance *ins = frustum_cull_result.lights[i];
+ for (uint32_t i = 0; i < (uint32_t)scene_cull_result.lights.size(); i++) {
+ Instance *ins = scene_cull_result.lights[i];
if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base)) {
continue;
@@ -2649,12 +2998,12 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
{ //compute coverage
- Transform cam_xf = p_cam_transform;
- float zn = p_cam_projection.get_z_near();
+ Transform3D cam_xf = p_camera_data->main_transform;
+ float zn = p_camera_data->main_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();
+ Vector2 vp_half_extents = p_camera_data->main_projection.get_viewport_half_extents();
switch (RSG::storage->light_get_type(ins->base)) {
case RS::LIGHT_OMNI: {
@@ -2666,7 +3015,7 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
ins->transform.origin + cam_xf.basis.get_axis(0) * radius
};
- if (!p_cam_orthogonal) {
+ if (!p_camera_data->is_ortogonal) {
//if using perspetive, map them to near plane
for (int j = 0; j < 2; j++) {
if (p.distance_to(points[j]) < 0) {
@@ -2694,7 +3043,7 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
base + cam_xf.basis.get_axis(0) * w
};
- if (!p_cam_orthogonal) {
+ if (!p_camera_data->is_ortogonal) {
//if using perspetive, map them to near plane
for (int j = 0; j < 2; j++) {
if (p.distance_to(points[j]) < 0) {
@@ -2725,7 +3074,7 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) {
//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, p_screen_lod_threshold);
+ light->shadow_dirty = _light_instance_update_shadow(ins, p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_ortogonal, p_camera_data->vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold);
RENDER_TIMESTAMP("<Rendering Light " + itos(i));
} else {
light->shadow_dirty = redraw;
@@ -2741,13 +3090,13 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
if (cull.sdfgi.region_count > 0) {
//update regions
for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) {
- render_sdfgi_data[i].instances.merge_unordered(frustum_cull_result.sdfgi_region_geometry_instances[i]);
+ render_sdfgi_data[i].instances.merge_unordered(scene_cull_result.sdfgi_region_geometry_instances[i]);
render_sdfgi_data[i].region = i;
}
//check if static lights were culled
bool static_lights_culled = false;
for (uint32_t i = 0; i < cull.sdfgi.cascade_light_count; i++) {
- if (frustum_cull_result.sdfgi_cascade_lights[i].size()) {
+ if (scene_cull_result.sdfgi_cascade_lights[i].size()) {
static_lights_culled = true;
break;
}
@@ -2756,7 +3105,7 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
if (static_lights_culled) {
sdfgi_update_data.static_cascade_count = cull.sdfgi.cascade_light_count;
sdfgi_update_data.static_cascade_indices = cull.sdfgi.cascade_light_index;
- sdfgi_update_data.static_positional_lights = frustum_cull_result.sdfgi_cascade_lights;
+ sdfgi_update_data.static_positional_lights = scene_cull_result.sdfgi_cascade_lights;
sdfgi_update_data.update_static = true;
}
}
@@ -2770,7 +3119,7 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
//append the directional lights to the lights culled
for (int i = 0; i < directional_lights.size(); i++) {
- frustum_cull_result.light_instances.push_back(directional_lights[i]);
+ scene_cull_result.light_instances.push_back(directional_lights[i]);
}
RID camera_effects;
@@ -2781,8 +3130,13 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
}
/* PROCESS GEOMETRY AND DRAW SCENE */
+ RID occluders_tex;
+ if (p_viewport.is_valid()) {
+ occluders_tex = RSG::viewport->viewport_get_occluder_debug_texture(p_viewport);
+ }
+
RENDER_TIMESTAMP("Render Scene ");
- scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.gi_probes, frustum_cull_result.decals, frustum_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data);
+ scene_render->render_scene(p_render_buffers, p_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data);
for (uint32_t i = 0; i < max_shadows_used; i++) {
render_shadow_data[i].instances.clear();
@@ -2793,7 +3147,7 @@ void RendererSceneCull::_render_scene(const Transform p_cam_transform, const Cam
render_sdfgi_data[i].instances.clear();
}
- // virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold,const RenderShadowData *p_render_shadows,int p_render_shadow_count,const RenderSDFGIData *p_render_sdfgi_regions,int p_render_sdfgi_region_count,const RenderSDFGIStaticLightData *p_render_sdfgi_static_lights=nullptr) = 0;
+ // virtual void render_scene(RID p_render_buffers, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold,const RenderShadowData *p_render_shadows,int p_render_shadow_count,const RenderSDFGIData *p_render_sdfgi_regions,int p_render_sdfgi_region_count,const RenderSDFGIStaticLightData *p_render_sdfgi_static_lights=nullptr) = 0;
}
RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) {
@@ -2829,7 +3183,11 @@ void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario,
environment = scenario->fallback_environment;
}
RENDER_TIMESTAMP("Render Empty Scene ");
- scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr);
+
+ RendererSceneRender::CameraData camera_data;
+ camera_data.set_camera(Transform3D(), CameraMatrix(), true, false);
+
+ scene_render->render_scene(p_render_buffers, &camera_data, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr);
#endif
}
@@ -2879,10 +3237,10 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
CameraMatrix cm;
cm.set_perspective(90, 1, 0.01, max_distance);
- Transform local_view;
+ Transform3D 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;
+ Transform3D xform = p_instance->transform * local_view;
RID shadow_atlas;
@@ -2899,7 +3257,10 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
}
RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step));
- _render_scene(xform, cm, false, false, RID(), environment, RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows);
+ RendererSceneRender::CameraData camera_data;
+ camera_data.set_camera(xform, cm, false, false);
+
+ _render_scene(&camera_data, RID(), environment, RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows);
} else {
//do roughness postprocess step until it believes it's done
@@ -2951,18 +3312,18 @@ void RendererSceneCull::render_probes() {
ref_probe = next;
}
- /* GI PROBES */
+ /* VOXEL GIS */
- SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first();
+ SelfList<InstanceVoxelGIData> *voxel_gi = voxel_gi_update_list.first();
- if (gi_probe) {
+ if (voxel_gi) {
RENDER_TIMESTAMP("Render GI Probes");
}
- while (gi_probe) {
- SelfList<InstanceGIProbeData> *next = gi_probe->next();
+ while (voxel_gi) {
+ SelfList<InstanceVoxelGIData> *next = voxel_gi->next();
- InstanceGIProbeData *probe = gi_probe->self();
+ InstanceVoxelGIData *probe = voxel_gi->self();
//Instance *instance_probe = probe->owner;
//check if probe must be setup, but don't do if on the lighting thread
@@ -2971,7 +3332,7 @@ void RendererSceneCull::render_probes() {
int cache_count = 0;
{
int light_cache_size = probe->light_cache.size();
- const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr();
+ const InstanceVoxelGIData::LightCache *caches = probe->light_cache.ptr();
const RID *instance_caches = probe->light_instances.ptr();
int idx = 0; //must count visible lights
@@ -2986,7 +3347,7 @@ void RendererSceneCull::render_probes() {
} else if (idx >= light_cache_size) {
cache_dirty = true;
} else {
- const InstanceGIProbeData::LightCache *cache = &caches[idx];
+ const InstanceVoxelGIData::LightCache *cache = &caches[idx];
if (
instance_caches[idx] != instance_light->instance ||
@@ -3018,7 +3379,7 @@ void RendererSceneCull::render_probes() {
} else if (idx >= light_cache_size) {
cache_dirty = true;
} else {
- const InstanceGIProbeData::LightCache *cache = &caches[idx];
+ const InstanceVoxelGIData::LightCache *cache = &caches[idx];
if (
instance_caches[idx] != instance_light->instance ||
@@ -3047,14 +3408,14 @@ void RendererSceneCull::render_probes() {
cache_count = idx;
}
- bool update_lights = scene_render->gi_probe_needs_update(probe->probe_instance);
+ bool update_lights = scene_render->voxel_gi_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();
+ InstanceVoxelGIData::LightCache *caches = probe->light_cache.ptrw();
RID *instance_caches = probe->light_instances.ptrw();
int idx = 0; //must count visible lights
@@ -3065,7 +3426,7 @@ void RendererSceneCull::render_probes() {
continue;
}
- InstanceGIProbeData::LightCache *cache = &caches[idx];
+ InstanceVoxelGIData::LightCache *cache = &caches[idx];
instance_caches[idx] = instance_light->instance;
cache->has_shadow = RSG::storage->light_has_shadow(instance->base);
@@ -3088,7 +3449,7 @@ void RendererSceneCull::render_probes() {
continue;
}
- InstanceGIProbeData::LightCache *cache = &caches[idx];
+ InstanceVoxelGIData::LightCache *cache = &caches[idx];
instance_caches[idx] = instance_light->instance;
cache->has_shadow = RSG::storage->light_has_shadow(instance->base);
@@ -3110,7 +3471,7 @@ void RendererSceneCull::render_probes() {
update_lights = true;
}
- frustum_cull_result.geometry_instances.clear();
+ scene_cull_result.geometry_instances.clear();
RID instance_pair_buffer[MAX_INSTANCE_PAIRS];
@@ -3121,30 +3482,30 @@ void RendererSceneCull::render_probes() {
}
InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data;
- if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY)) {
+ if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY)) {
uint32_t idx = 0;
- for (Set<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) {
- InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data);
+ for (Set<Instance *>::Element *F = geom->voxel_gi_instances.front(); F; F = F->next()) {
+ InstanceVoxelGIData *voxel_gi2 = static_cast<InstanceVoxelGIData *>(F->get()->base_data);
- instance_pair_buffer[idx++] = gi_probe2->probe_instance;
+ instance_pair_buffer[idx++] = voxel_gi2->probe_instance;
if (idx == MAX_INSTANCE_PAIRS) {
break;
}
}
- scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx);
+ scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, instance_pair_buffer, idx);
- ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY);
+ ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY);
}
- frustum_cull_result.geometry_instances.push_back(geom->geometry_instance);
+ scene_cull_result.geometry_instances.push_back(geom->geometry_instance);
}
- scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, frustum_cull_result.geometry_instances);
+ scene_render->voxel_gi_update(probe->probe_instance, update_lights, probe->light_instances, scene_cull_result.geometry_instances);
- gi_probe_update_list.remove(gi_probe);
+ voxel_gi_update_list.remove(voxel_gi);
- gi_probe = next;
+ voxel_gi = next;
}
}
@@ -3155,7 +3516,7 @@ void RendererSceneCull::render_particle_colliders() {
if (hfpc->scenario && hfpc->base_type == RS::INSTANCE_PARTICLES_COLLISION && RSG::storage->particles_collision_is_heightfield(hfpc->base)) {
//update heightfield
instance_cull_result.clear();
- frustum_cull_result.geometry_instances.clear();
+ scene_cull_result.geometry_instances.clear();
struct CullAABB {
PagedArray<Instance *> *result;
@@ -3177,10 +3538,10 @@ void RendererSceneCull::render_particle_colliders() {
continue;
}
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
- frustum_cull_result.geometry_instances.push_back(geom->geometry_instance);
+ scene_cull_result.geometry_instances.push_back(geom->geometry_instance);
}
- scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, frustum_cull_result.geometry_instances);
+ scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, scene_cull_result.geometry_instances);
}
heightfield_particle_colliders_update_list.erase(heightfield_particle_colliders_update_list.front());
}
@@ -3469,12 +3830,16 @@ bool RendererSceneCull::free(RID p_rid) {
}
scenario->instance_aabbs.reset();
scenario->instance_data.reset();
+ scenario->instance_visibility.reset();
scene_render->free(scenario->reflection_probe_shadow_atlas);
scene_render->free(scenario->reflection_atlas);
scenario_owner.free(p_rid);
+ RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid);
memdelete(scenario);
+ } else if (RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) {
+ RendererSceneOcclusionCull::get_singleton()->free_occluder(p_rid);
} else if (instance_owner.owns(p_rid)) {
// delete the instance
@@ -3507,6 +3872,28 @@ TypedArray<Image> RendererSceneCull::bake_render_uv2(RID p_base, const Vector<RI
return scene_render->bake_render_uv2(p_base, p_material_overrides, p_image_size);
}
+void RendererSceneCull::update_visibility_notifiers() {
+ SelfList<InstanceVisibilityNotifierData> *E = visible_notifier_list.first();
+ while (E) {
+ SelfList<InstanceVisibilityNotifierData> *N = E->next();
+
+ InstanceVisibilityNotifierData *visibility_notifier = E->self();
+ if (visibility_notifier->just_visible) {
+ visibility_notifier->just_visible = false;
+
+ RSG::storage->visibility_notifier_call(visibility_notifier->base, true, RSG::threaded);
+ } else {
+ if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) {
+ visible_notifier_list.remove(E);
+
+ RSG::storage->visibility_notifier_call(visibility_notifier->base, false, RSG::threaded);
+ }
+ }
+
+ E = N;
+ }
+}
+
/*******************************/
/* Passthrough to Scene Render */
/*******************************/
@@ -3534,15 +3921,17 @@ RendererSceneCull::RendererSceneCull() {
render_sdfgi_data[i].instances.set_page_pool(&geometry_instance_cull_page_pool);
}
- frustum_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
- frustum_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
- for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
- frustum_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
+ scene_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
+ scene_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
+ for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
+ scene_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
}
indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame");
thread_cull_threshold = GLOBAL_GET("rendering/limits/spatial_indexer/threaded_cull_minimum_instances");
thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)RendererThreadPool::singleton->thread_work_pool.get_thread_count()); //make sure there is at least one thread per CPU
+
+ dummy_occlusion_culling = memnew(RendererSceneOcclusionCull);
}
RendererSceneCull::~RendererSceneCull() {
@@ -3556,9 +3945,13 @@ RendererSceneCull::~RendererSceneCull() {
render_sdfgi_data[i].instances.reset();
}
- frustum_cull_result.reset();
- for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
- frustum_cull_result_threads[i].reset();
+ scene_cull_result.reset();
+ for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
+ scene_cull_result_threads[i].reset();
+ }
+ scene_cull_result_threads.clear();
+
+ if (dummy_occlusion_culling) {
+ memdelete(dummy_occlusion_culling);
}
- frustum_cull_result_threads.clear();
}
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index d7d59665ec..d9466d8b04 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -31,6 +31,7 @@
#ifndef RENDERING_SERVER_SCENE_CULL_H
#define RENDERING_SERVER_SCENE_CULL_H
+#include "core/templates/bin_sorted_array.h"
#include "core/templates/pass_func.h"
#include "servers/rendering/renderer_compositor.h"
@@ -45,8 +46,10 @@
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
#include "servers/rendering/renderer_scene.h"
+#include "servers/rendering/renderer_scene_occlusion_cull.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/xr/xr_interface.h"
+
class RendererSceneCull : public RendererScene {
public:
RendererSceneRender *scene_render;
@@ -80,7 +83,7 @@ public:
RID env;
RID effects;
- Transform transform;
+ Transform3D transform;
Camera() {
visible_layers = 0xFFFFFFFF;
@@ -102,13 +105,23 @@ public:
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_transform(RID p_camera, const Transform3D &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);
virtual bool is_camera(RID p_camera) const;
+ /* OCCLUDER API */
+
+ virtual RID occluder_allocate();
+ virtual void occluder_initialize(RID p_occluder);
+ virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices);
+
+ /* VISIBILITY NOTIFIER API */
+
+ RendererSceneOcclusionCull *dummy_occlusion_culling;
+
/* SCENARIO API */
struct Instance;
@@ -232,6 +245,8 @@ public:
}
};
+ struct InstanceVisibilityNotifierData;
+
struct InstanceData {
// Store instance pointer as well as common instance processing information,
// to make processing more cache friendly.
@@ -243,11 +258,15 @@ public:
FLAG_GEOM_LIGHTING_DIRTY = (1 << 11),
FLAG_GEOM_REFLECTION_DIRTY = (1 << 12),
FLAG_GEOM_DECAL_DIRTY = (1 << 13),
- FLAG_GEOM_GI_PROBE_DIRTY = (1 << 14),
+ FLAG_GEOM_VOXEL_GI_DIRTY = (1 << 14),
FLAG_LIGHTMAP_CAPTURE = (1 << 15),
FLAG_USES_BAKED_LIGHT = (1 << 16),
FLAG_USES_MESH_INSTANCE = (1 << 17),
FLAG_REFLECTION_PROBE_DIRTY = (1 << 18),
+ FLAG_IGNORE_OCCLUSION_CULLING = (1 << 19),
+ FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK = (3 << 20), // 2 bits, overlaps with the other vis. dependency flags
+ FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE = (1 << 20),
+ FLAG_VISIBILITY_DEPENDENCY_HIDDEN = (1 << 21),
};
uint32_t flags = 0;
@@ -256,12 +275,36 @@ public:
union {
uint64_t instance_data_rid;
RendererSceneRender::GeometryInstance *instance_geometry;
+ InstanceVisibilityNotifierData *visibility_notifier;
};
Instance *instance = nullptr;
+ int32_t parent_array_index = -1;
+ int32_t visibility_index = -1;
+ };
+
+ struct InstanceVisibilityData {
+ uint64_t viewport_state = 0;
+ int32_t array_index = -1;
+ Vector3 position;
+ Instance *instance = nullptr;
+ float range_begin = 0.0f;
+ float range_end = 0.0f;
+ float range_begin_margin = 0.0f;
+ float range_end_margin = 0.0f;
+ };
+
+ class VisibilityArray : public BinSortedArray<InstanceVisibilityData> {
+ _FORCE_INLINE_ virtual void _update_idx(InstanceVisibilityData &r_element, uint64_t p_idx) {
+ r_element.instance->visibility_index = p_idx;
+ if (r_element.instance->scenario && r_element.instance->array_index != -1) {
+ r_element.instance->scenario->instance_data[r_element.instance->array_index].visibility_index = p_idx;
+ }
+ }
};
PagedArrayPool<InstanceBounds> instance_aabb_page_pool;
PagedArrayPool<InstanceData> instance_data_page_pool;
+ PagedArrayPool<InstanceVisibilityData> instance_visibility_data_page_pool;
struct Scenario {
enum IndexerType {
@@ -281,6 +324,8 @@ public:
RID camera_effects;
RID reflection_probe_shadow_atlas;
RID reflection_atlas;
+ uint64_t used_viewport_visibility_bits;
+ Map<RID, uint64_t> viewport_visibility_masks;
SelfList<Instance>::List instances;
@@ -288,11 +333,13 @@ public:
PagedArray<InstanceBounds> instance_aabbs;
PagedArray<InstanceData> instance_data;
+ VisibilityArray instance_visibility;
Scenario() {
indexers[INDEXER_GEOMETRY].set_index(INDEXER_GEOMETRY);
indexers[INDEXER_VOLUMES].set_index(INDEXER_VOLUMES);
debug = RS::SCENARIO_DEBUG_DISABLED;
+ used_viewport_visibility_bits = 0;
}
};
@@ -315,6 +362,8 @@ public:
virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count);
virtual bool is_scenario(RID p_scenario) const;
virtual RID scenario_get_environment(RID p_scenario);
+ virtual void scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport);
+ virtual void scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport);
/* INSTANCING API */
@@ -342,10 +391,12 @@ public:
RID mesh_instance; //only used for meshes and when skeleton/blendshapes exist
- Transform transform;
+ Transform3D transform;
float lod_bias;
+ bool ignore_occlusion_culling;
+
Vector<RID> materials;
RS::ShadowCastingSetting cast_shadows;
@@ -386,6 +437,12 @@ public:
//scenario stuff
DynamicBVH::ID indexer_id;
int32_t array_index;
+ int32_t visibility_index = -1;
+ float visibility_range_begin;
+ float visibility_range_end;
+ float visibility_range_begin_margin;
+ float visibility_range_end_margin;
+ Instance *visibility_parent = nullptr;
Scenario *scenario;
SelfList<Instance> scenario_item;
@@ -399,12 +456,6 @@ public:
float extra_margin;
ObjectID object_id;
- float lod_begin;
- float lod_end;
- float lod_begin_hysteresis;
- float lod_end_hysteresis;
- RID lod_instance;
-
Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior
uint64_t last_frame_pass;
@@ -430,6 +481,7 @@ public:
singleton->_instance_queue_update(instance, false, true);
} break;
case RendererStorage::DEPENDENCY_CHANGED_MESH:
+ case RendererStorage::DEPENDENCY_CHANGED_PARTICLES:
case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH:
case RendererStorage::DEPENDENCY_CHANGED_DECAL:
case RendererStorage::DEPENDENCY_CHANGED_LIGHT:
@@ -470,6 +522,7 @@ public:
lightmap = nullptr;
lightmap_cull_index = 0;
lod_bias = 1.0;
+ ignore_occlusion_culling = false;
scenario = nullptr;
@@ -480,10 +533,10 @@ public:
visible = true;
- lod_begin = 0;
- lod_end = 0;
- lod_begin_hysteresis = 0;
- lod_end_hysteresis = 0;
+ visibility_range_begin = 0;
+ visibility_range_end = 0;
+ visibility_range_begin_margin = 0;
+ visibility_range_end_margin = 0;
last_frame_pass = 0;
version = 1;
@@ -520,8 +573,10 @@ public:
Set<Instance *> decals;
Set<Instance *> reflection_probes;
- Set<Instance *> gi_probes;
+ Set<Instance *> voxel_gi_instances;
Set<Instance *> lightmap_captures;
+ Set<Instance *> visibility_dependencies;
+ uint32_t visibility_dependencies_depth = 0;
InstanceGeometryData() {
can_cast_shadows = true;
@@ -561,6 +616,18 @@ public:
RID instance;
};
+ struct InstanceVisibilityNotifierData : public InstanceBaseData {
+ bool just_visible = false;
+ uint64_t visible_in_frame = 0;
+ RID base;
+ SelfList<InstanceVisibilityNotifierData> list_element;
+ InstanceVisibilityNotifierData() :
+ list_element(this) {}
+ };
+
+ SpinLock visible_notifier_list_lock;
+ SelfList<InstanceVisibilityNotifierData>::List visible_notifier_list;
+
struct InstanceLightData : public InstanceBaseData {
RID instance;
uint64_t last_version;
@@ -584,7 +651,7 @@ public:
}
};
- struct InstanceGIProbeData : public InstanceBaseData {
+ struct InstanceVoxelGIData : public InstanceBaseData {
Instance *owner;
Set<Instance *> geometries;
@@ -594,7 +661,7 @@ public:
struct LightCache {
RS::LightType type;
- Transform transform;
+ Transform3D transform;
Color color;
float energy;
float bake_energy;
@@ -614,16 +681,16 @@ public:
bool invalid;
uint32_t base_version;
- SelfList<InstanceGIProbeData> update_element;
+ SelfList<InstanceVoxelGIData> update_element;
- InstanceGIProbeData() :
+ InstanceVoxelGIData() :
update_element(this) {
invalid = true;
base_version = 0;
}
};
- SelfList<InstanceGIProbeData>::List gi_probe_update_list;
+ SelfList<InstanceVoxelGIData>::List voxel_gi_update_list;
struct InstanceLightmapData : public InstanceBaseData {
RID instance;
@@ -647,6 +714,7 @@ public:
_FORCE_INLINE_ bool operator()(void *p_data) {
Instance *p_instance = (Instance *)p_data;
+
if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type))) {
//test is more coarse in indexer
p_instance->pair_check = pair_pass;
@@ -701,14 +769,14 @@ public:
PagedArray<Instance *> instance_cull_result;
PagedArray<Instance *> instance_shadow_cull_result;
- struct FrustumCullResult {
+ struct InstanceCullResult {
PagedArray<RendererSceneRender::GeometryInstance *> geometry_instances;
PagedArray<Instance *> lights;
PagedArray<RID> light_instances;
PagedArray<RID> lightmaps;
PagedArray<RID> reflections;
PagedArray<RID> decals;
- PagedArray<RID> gi_probes;
+ PagedArray<RID> voxel_gi_instances;
PagedArray<RID> mesh_instances;
struct DirectionalShadow {
@@ -725,7 +793,7 @@ public:
lightmaps.clear();
reflections.clear();
decals.clear();
- gi_probes.clear();
+ voxel_gi_instances.clear();
mesh_instances.clear();
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
@@ -749,7 +817,7 @@ public:
lightmaps.reset();
reflections.reset();
decals.reset();
- gi_probes.reset();
+ voxel_gi_instances.reset();
mesh_instances.reset();
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
@@ -766,14 +834,14 @@ public:
}
}
- void append_from(FrustumCullResult &p_cull_result) {
+ void append_from(InstanceCullResult &p_cull_result) {
geometry_instances.merge_unordered(p_cull_result.geometry_instances);
lights.merge_unordered(p_cull_result.lights);
light_instances.merge_unordered(p_cull_result.light_instances);
lightmaps.merge_unordered(p_cull_result.lightmaps);
reflections.merge_unordered(p_cull_result.reflections);
decals.merge_unordered(p_cull_result.decals);
- gi_probes.merge_unordered(p_cull_result.gi_probes);
+ voxel_gi_instances.merge_unordered(p_cull_result.voxel_gi_instances);
mesh_instances.merge_unordered(p_cull_result.mesh_instances);
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
@@ -798,7 +866,7 @@ public:
lightmaps.set_page_pool(p_rid_pool);
reflections.set_page_pool(p_rid_pool);
decals.set_page_pool(p_rid_pool);
- gi_probes.set_page_pool(p_rid_pool);
+ voxel_gi_instances.set_page_pool(p_rid_pool);
mesh_instances.set_page_pool(p_rid_pool);
for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) {
for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) {
@@ -816,8 +884,8 @@ public:
}
};
- FrustumCullResult frustum_cull_result;
- LocalVector<FrustumCullResult> frustum_cull_result_threads;
+ InstanceCullResult scene_cull_result;
+ LocalVector<InstanceCullResult> scene_cull_result_threads;
RendererSceneRender::RenderShadowData render_shadow_data[MAX_UPDATE_SHADOWS];
uint32_t max_shadows_used = 0;
@@ -829,7 +897,7 @@ public:
RID_PtrOwner<Instance, true> instance_owner;
- uint32_t geometry_instance_pair_mask; // used in traditional forward, unnecesary on clustered
+ uint32_t geometry_instance_pair_mask; // used in traditional forward, unnecessary on clustered
virtual RID instance_allocate();
virtual void instance_initialize(RID p_rid);
@@ -837,7 +905,7 @@ public:
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_set_transform(RID p_instance, const Transform3D &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_override_material(RID p_instance, int p_surface, RID p_material);
@@ -850,6 +918,11 @@ public:
virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin);
+ virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance);
+
+ void _update_instance_visibility_depth(Instance *p_instance);
+ void _update_instance_visibility_dependencies(Instance *p_instance);
+
// 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;
@@ -859,8 +932,8 @@ public:
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);
+ virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin);
+
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index);
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias);
@@ -877,9 +950,9 @@ public:
_FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance);
void _unpair_instance(Instance *p_instance);
- void _light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect);
+ void _light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect);
- _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, float p_scren_lod_threshold);
+ _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_scren_lod_threshold);
RID _render_get_environment(RID p_camera, RID p_scenario);
@@ -890,7 +963,7 @@ public:
Frustum frustum;
CameraMatrix projection;
- Transform transform;
+ Transform3D transform;
real_t zfar;
real_t split;
real_t shadow_texel_size;
@@ -921,24 +994,39 @@ public:
Frustum frustum;
} cull;
- struct FrustumCullData {
+ struct VisibilityCullData {
+ uint64_t viewport_mask;
+ Scenario *scenario;
+ Vector3 camera_position;
+ uint32_t cull_offset;
+ uint32_t cull_count;
+ };
+
+ void _visibility_cull_threaded(uint32_t p_thread, VisibilityCullData *cull_data);
+ void _visibility_cull(const VisibilityCullData &cull_data, uint64_t p_from, uint64_t p_to);
+ _FORCE_INLINE_ void _visibility_cull(const VisibilityCullData &cull_data, uint64_t p_idx);
+ _FORCE_INLINE_ int _visibility_range_check(InstanceVisibilityData &r_vis_data, const Vector3 &p_camera_pos, uint64_t p_viewport_mask);
+
+ struct CullData {
Cull *cull;
Scenario *scenario;
RID shadow_atlas;
- Transform cam_transform;
+ Transform3D cam_transform;
uint32_t visible_layers;
Instance *render_reflection_probe;
+ const RendererSceneOcclusionCull::HZBuffer *occlusion_buffer;
+ const CameraMatrix *camera_matrix;
+ const VisibilityCullData *visibility_cull_data;
};
- void _frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data);
- void _frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to);
+ void _scene_cull_threaded(uint32_t p_thread, CullData *cull_data);
+ void _scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to);
bool _render_reflection_probe_step(Instance *p_instance, int p_step);
- void _render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true);
+ void _render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true);
void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas);
- void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas);
- void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas);
+ void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface);
void update_dirty_instances();
void render_particle_colliders();
@@ -957,7 +1045,7 @@ public:
#define PASSBASE scene_render
PASS2(directional_shadow_atlas_set_size, int, bool)
- PASS1(gi_probe_set_quality, RS::GIProbeQuality)
+ PASS1(voxel_gi_set_quality, RS::VoxelGIQuality)
/* SKY API */
@@ -1036,7 +1124,7 @@ public:
/* Render Buffers */
PASS0R(RID, render_buffers_create)
- PASS7(render_buffers_configure, RID, RID, int, int, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool)
+ PASS8(render_buffers_configure, RID, RID, int, int, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, uint32_t)
PASS1(gi_set_use_half_resolution, bool)
/* Shadow Atlas */
@@ -1052,6 +1140,8 @@ public:
void set_scene_render(RendererSceneRender *p_scene_render);
+ virtual void update_visibility_notifiers();
+
RendererSceneCull();
virtual ~RendererSceneCull();
};
diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp
new file mode 100644
index 0000000000..c491ccbe7a
--- /dev/null
+++ b/servers/rendering/renderer_scene_occlusion_cull.cpp
@@ -0,0 +1,192 @@
+/*************************************************************************/
+/* renderer_scene_occlusion_cull.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "renderer_scene_occlusion_cull.h"
+
+RendererSceneOcclusionCull *RendererSceneOcclusionCull::singleton = nullptr;
+
+const Vector3 RendererSceneOcclusionCull::HZBuffer::corners[8] = {
+ Vector3(0, 0, 0),
+ Vector3(0, 0, 1),
+ Vector3(0, 1, 0),
+ Vector3(0, 1, 1),
+ Vector3(1, 0, 0),
+ Vector3(1, 0, 1),
+ Vector3(1, 1, 0),
+ Vector3(1, 1, 1)
+};
+
+bool RendererSceneOcclusionCull::HZBuffer::is_empty() const {
+ return sizes.is_empty();
+}
+
+void RendererSceneOcclusionCull::HZBuffer::clear() {
+ if (sizes.is_empty()) {
+ return; // Already cleared
+ }
+
+ data.clear();
+ sizes.clear();
+ mips.clear();
+
+ debug_data.clear();
+ if (debug_image.is_valid()) {
+ debug_image.unref();
+ }
+ RS::get_singleton()->free(debug_texture);
+}
+
+void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) {
+ if (p_size == Size2i()) {
+ clear();
+ return;
+ }
+
+ if (!sizes.is_empty() && p_size == sizes[0]) {
+ return; // Size didn't change
+ }
+
+ int mip_count = 0;
+ int data_size = 0;
+ int w = p_size.x;
+ int h = p_size.y;
+
+ while (true) {
+ data_size += h * w;
+
+ w = MAX(1, w >> 1);
+ h = MAX(1, h >> 1);
+
+ mip_count++;
+
+ if (w == 1U && h == 1U) {
+ data_size += 1U;
+ mip_count++;
+ break;
+ }
+ }
+
+ data.resize(data_size);
+ mips.resize(mip_count);
+ sizes.resize(mip_count);
+
+ w = p_size.x;
+ h = p_size.y;
+ float *ptr = data.ptr();
+
+ for (int i = 0; i < mip_count; i++) {
+ sizes[i] = Size2i(w, h);
+ mips[i] = ptr;
+
+ ptr = &ptr[w * h];
+ w = MAX(1, w >> 1);
+ h = MAX(1, h >> 1);
+ }
+
+ for (int i = 0; i < data_size; i++) {
+ data[i] = FLT_MAX;
+ }
+
+ debug_data.resize(sizes[0].x * sizes[0].y);
+ if (debug_texture.is_valid()) {
+ RS::get_singleton()->free(debug_texture);
+ debug_texture = RID();
+ }
+}
+
+void RendererSceneOcclusionCull::HZBuffer::update_mips() {
+ if (sizes.is_empty()) {
+ return;
+ }
+
+ for (uint32_t mip = 1; mip < mips.size(); mip++) {
+ for (int y = 0; y < sizes[mip].y; y++) {
+ for (int x = 0; x < sizes[mip].x; x++) {
+ int prev_x = x * 2;
+ int prev_y = y * 2;
+
+ int prev_w = sizes[mip - 1].width;
+ int prev_h = sizes[mip - 1].height;
+
+ bool odd_w = (prev_w % 2) != 0;
+ bool odd_h = (prev_h % 2) != 0;
+
+#define CHECK_OFFSET(xx, yy) max_depth = MAX(max_depth, mips[mip - 1][MIN(prev_h - 1, prev_y + (yy)) * prev_w + MIN(prev_w - 1, prev_x + (xx))])
+
+ float max_depth = mips[mip - 1][prev_y * sizes[mip - 1].x + prev_x];
+ CHECK_OFFSET(0, 1);
+ CHECK_OFFSET(1, 0);
+ CHECK_OFFSET(1, 1);
+
+ if (odd_w) {
+ CHECK_OFFSET(2, 0);
+ CHECK_OFFSET(2, 1);
+ }
+
+ if (odd_h) {
+ CHECK_OFFSET(0, 2);
+ CHECK_OFFSET(1, 2);
+ }
+
+ if (odd_w && odd_h) {
+ CHECK_OFFSET(2, 2);
+ }
+
+ mips[mip][y * sizes[mip].x + x] = max_depth;
+#undef CHECK_OFFSET
+ }
+ }
+ }
+}
+
+RID RendererSceneOcclusionCull::HZBuffer::get_debug_texture() {
+ if (sizes.is_empty() || sizes[0] == Size2i()) {
+ return RID();
+ }
+
+ if (debug_image.is_null()) {
+ debug_image.instance();
+ }
+
+ unsigned char *ptrw = debug_data.ptrw();
+ for (int i = 0; i < debug_data.size(); i++) {
+ ptrw[i] = MIN(mips[0][i] / debug_tex_range, 1.0) * 255;
+ }
+
+ debug_image->create(sizes[0].x, sizes[0].y, false, Image::FORMAT_L8, debug_data);
+
+ if (debug_texture.is_null()) {
+ debug_texture = RS::get_singleton()->texture_2d_create(debug_image);
+ } else {
+ RenderingServer::get_singleton()->texture_2d_update_immediate(debug_texture, debug_image);
+ }
+
+ return debug_texture;
+}
diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h
new file mode 100644
index 0000000000..1d0f53c0bf
--- /dev/null
+++ b/servers/rendering/renderer_scene_occlusion_cull.h
@@ -0,0 +1,201 @@
+/*************************************************************************/
+/* renderer_scene_occlusion_cull.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RENDERER_SCENE_OCCLUSION_CULL_H
+#define RENDERER_SCENE_OCCLUSION_CULL_H
+
+#include "core/math/camera_matrix.h"
+#include "core/templates/local_vector.h"
+#include "servers/rendering_server.h"
+
+class RendererSceneOcclusionCull {
+protected:
+ static RendererSceneOcclusionCull *singleton;
+
+public:
+ class HZBuffer {
+ protected:
+ static const Vector3 corners[8];
+
+ LocalVector<float> data;
+ LocalVector<Size2i> sizes;
+ LocalVector<float *> mips;
+
+ RID debug_texture;
+ Ref<Image> debug_image;
+ PackedByteArray debug_data;
+ float debug_tex_range = 0.0f;
+
+ public:
+ bool is_empty() const;
+ virtual void clear();
+ virtual void resize(const Size2i &p_size);
+
+ void update_mips();
+
+ _FORCE_INLINE_ bool is_occluded(const float p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const CameraMatrix &p_cam_projection, float p_near) const {
+ if (is_empty()) {
+ return false;
+ }
+
+ Vector3 closest_point = Vector3(CLAMP(p_cam_position.x, p_bounds[0], p_bounds[3]), CLAMP(p_cam_position.y, p_bounds[1], p_bounds[4]), CLAMP(p_cam_position.z, p_bounds[2], p_bounds[5]));
+
+ if (closest_point == p_cam_position) {
+ return false;
+ }
+
+ Vector3 closest_point_view = p_cam_inv_transform.xform(closest_point);
+ if (closest_point_view.z > -p_near) {
+ return false;
+ }
+
+ float min_depth;
+ if (p_cam_projection.is_orthogonal()) {
+ min_depth = (-closest_point_view.z) - p_near;
+ } else {
+ float r = -p_near / closest_point_view.z;
+ Vector3 closest_point_proj = Vector3(closest_point_view.x * r, closest_point_view.y * r, -p_near);
+ min_depth = closest_point_proj.distance_to(closest_point_view);
+ }
+
+ Vector2 rect_min = Vector2(FLT_MAX, FLT_MAX);
+ Vector2 rect_max = Vector2(FLT_MIN, FLT_MIN);
+
+ for (int j = 0; j < 8; j++) {
+ Vector3 c = RendererSceneOcclusionCull::HZBuffer::corners[j];
+ Vector3 nc = Vector3(1, 1, 1) - c;
+ Vector3 corner = Vector3(p_bounds[0] * c.x + p_bounds[3] * nc.x, p_bounds[1] * c.y + p_bounds[4] * nc.y, p_bounds[2] * c.z + p_bounds[5] * nc.z);
+ Vector3 view = p_cam_inv_transform.xform(corner);
+
+ Vector3 projected = p_cam_projection.xform(view);
+ Vector2 normalized = Vector2(projected.x * 0.5f + 0.5f, projected.y * 0.5f + 0.5f);
+ rect_min = rect_min.min(normalized);
+ rect_max = rect_max.max(normalized);
+ }
+
+ rect_max = rect_max.min(Vector2(1, 1));
+ rect_min = rect_min.max(Vector2(0, 0));
+
+ int mip_count = mips.size();
+
+ Vector2 screen_diagonal = (rect_max - rect_min) * sizes[0];
+ float size = MAX(screen_diagonal.x, screen_diagonal.y);
+ float l = Math::ceil(Math::log2(size));
+ int lod = CLAMP(l, 0, mip_count - 1);
+
+ const int max_samples = 512;
+ int sample_count = 0;
+ bool visible = true;
+
+ for (; lod >= 0; lod--) {
+ int w = sizes[lod].x;
+ int h = sizes[lod].y;
+
+ int minx = CLAMP(rect_min.x * w - 1, 0, w - 1);
+ int maxx = CLAMP(rect_max.x * w + 1, 0, w - 1);
+
+ int miny = CLAMP(rect_min.y * h - 1, 0, h - 1);
+ int maxy = CLAMP(rect_max.y * h + 1, 0, h - 1);
+
+ sample_count += (maxx - minx + 1) * (maxy - miny + 1);
+
+ if (sample_count > max_samples) {
+ return false;
+ }
+
+ visible = false;
+ for (int y = miny; y <= maxy; y++) {
+ for (int x = minx; x <= maxx; x++) {
+ float depth = mips[lod][y * w + x];
+ if (depth > min_depth) {
+ visible = true;
+ break;
+ }
+ }
+ if (visible) {
+ break;
+ }
+ }
+
+ if (!visible) {
+ return true;
+ }
+ }
+
+ return !visible;
+ }
+
+ RID get_debug_texture();
+
+ virtual ~HZBuffer(){};
+ };
+
+ static RendererSceneOcclusionCull *get_singleton() { return singleton; }
+
+ void _print_warining() {
+ WARN_PRINT_ONCE("Occlusion culling is disabled at build time.");
+ }
+
+ virtual bool is_occluder(RID p_rid) { return false; }
+ virtual RID occluder_allocate() { return RID(); }
+ virtual void occluder_initialize(RID p_occluder) {}
+ virtual void free_occluder(RID p_occluder) { _print_warining(); }
+ virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) { _print_warining(); }
+
+ virtual void add_scenario(RID p_scenario) {}
+ virtual void remove_scenario(RID p_scenario) {}
+ virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform3D &p_xform, bool p_enabled) { _print_warining(); }
+ virtual void scenario_remove_instance(RID p_scenario, RID p_instance) { _print_warining(); }
+
+ virtual void add_buffer(RID p_buffer) { _print_warining(); }
+ virtual void remove_buffer(RID p_buffer) { _print_warining(); }
+ virtual HZBuffer *buffer_get_ptr(RID p_buffer) {
+ return nullptr;
+ }
+ virtual void buffer_set_scenario(RID p_buffer, RID p_scenario) { _print_warining(); }
+ virtual void buffer_set_size(RID p_buffer, const Vector2i &p_size) { _print_warining(); }
+ virtual void buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) {}
+ virtual RID buffer_get_debug_texture(RID p_buffer) {
+ _print_warining();
+ return RID();
+ }
+
+ virtual void set_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) {}
+
+ RendererSceneOcclusionCull() {
+ singleton = this;
+ };
+
+ virtual ~RendererSceneOcclusionCull() {
+ singleton = nullptr;
+ };
+};
+
+#endif //RENDERER_SCENE_OCCLUSION_CULL_H
diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp
index f27bdc6798..3aa97f4084 100644
--- a/servers/rendering/renderer_scene_render.cpp
+++ b/servers/rendering/renderer_scene_render.cpp
@@ -29,3 +29,153 @@
/*************************************************************************/
#include "renderer_scene_render.h"
+
+void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, const CameraMatrix p_projection, bool p_is_ortogonal, bool p_vaspect) {
+ view_count = 1;
+ is_ortogonal = p_is_ortogonal;
+ vaspect = p_vaspect;
+
+ main_transform = p_transform;
+ main_projection = p_projection;
+
+ view_offset[0] = Transform3D();
+ view_projection[0] = p_projection;
+}
+
+void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const CameraMatrix *p_projections, bool p_is_ortogonal, bool p_vaspect) {
+ ERR_FAIL_COND_MSG(p_view_count != 2, "Incorrect view count for stereoscopic view");
+
+ view_count = p_view_count;
+ is_ortogonal = p_is_ortogonal;
+ vaspect = p_vaspect;
+ Vector<Plane> planes[2];
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Figure out our center transform
+
+ // 1. obtain our planes
+ for (uint32_t v = 0; v < view_count; v++) {
+ planes[v] = p_projections[v].get_projection_planes(p_transforms[v]);
+ }
+
+ // 2. average and normalize plane normals to obtain z vector, cross them to obtain y vector, and from there the x vector for combined camera basis.
+ Vector3 n0 = planes[0][CameraMatrix::PLANE_LEFT].normal;
+ Vector3 n1 = planes[1][CameraMatrix::PLANE_RIGHT].normal;
+ Vector3 z = (n0 + n1).normalized();
+ Vector3 y = n0.cross(n1).normalized();
+ Vector3 x = y.cross(z).normalized();
+ y = z.cross(x).normalized();
+ main_transform.basis.set(x, y, z);
+
+ // 3. create a horizon plane with one of the eyes and the up vector as normal.
+ Plane horizon(p_transforms[0].origin, y);
+
+ // 4. Intersect horizon, left and right to obtain the combined camera origin.
+ ERR_FAIL_COND_MSG(
+ !horizon.intersect_3(planes[0][CameraMatrix::PLANE_LEFT], planes[1][CameraMatrix::PLANE_RIGHT], &main_transform.origin), "Can't determine camera origin");
+
+ // handy to have the inverse of the transform we just build
+ Transform3D main_transform_inv = main_transform.inverse();
+
+ // 5. figure out far plane, this could use some improvement, we may have our far plane too close like this, not sure if this matters
+ Vector3 far_center = (planes[0][CameraMatrix::PLANE_FAR].center() + planes[1][CameraMatrix::PLANE_FAR].center()) * 0.5;
+ Plane far(far_center, -z);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Figure out our top/bottom planes
+
+ // 6. Intersect far and left planes with top planes from both eyes, save the point with highest y as top_left.
+ Vector3 top_left, other;
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[0][CameraMatrix::PLANE_LEFT], planes[0][CameraMatrix::PLANE_TOP], &top_left), "Can't determine left camera far/left/top vector");
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[1][CameraMatrix::PLANE_LEFT], planes[1][CameraMatrix::PLANE_TOP], &other), "Can't determine right camera far/left/top vector");
+ if (y.dot(top_left) < y.dot(other)) {
+ top_left = other;
+ }
+
+ // 7. Intersect far and left planes with bottom planes from both eyes, save the point with lowest y as bottom_left.
+ Vector3 bottom_left;
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[0][CameraMatrix::PLANE_LEFT], planes[0][CameraMatrix::PLANE_BOTTOM], &bottom_left), "Can't determine left camera far/left/bottom vector");
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[1][CameraMatrix::PLANE_LEFT], planes[1][CameraMatrix::PLANE_BOTTOM], &other), "Can't determine right camera far/left/bottom vector");
+ if (y.dot(other) < y.dot(bottom_left)) {
+ bottom_left = other;
+ }
+
+ // 8. Intersect far and right planes with top planes from both eyes, save the point with highest y as top_right.
+ Vector3 top_right;
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[0][CameraMatrix::PLANE_RIGHT], planes[0][CameraMatrix::PLANE_TOP], &top_right), "Can't determine left camera far/right/top vector");
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[1][CameraMatrix::PLANE_RIGHT], planes[1][CameraMatrix::PLANE_TOP], &other), "Can't determine right camera far/right/top vector");
+ if (y.dot(top_right) < y.dot(other)) {
+ top_right = other;
+ }
+
+ // 9. Intersect far and right planes with bottom planes from both eyes, save the point with lowest y as bottom_right.
+ Vector3 bottom_right;
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[0][CameraMatrix::PLANE_RIGHT], planes[0][CameraMatrix::PLANE_BOTTOM], &bottom_right), "Can't determine left camera far/right/bottom vector");
+ ERR_FAIL_COND_MSG(
+ !far.intersect_3(planes[1][CameraMatrix::PLANE_RIGHT], planes[1][CameraMatrix::PLANE_BOTTOM], &other), "Can't determine right camera far/right/bottom vector");
+ if (y.dot(other) < y.dot(bottom_right)) {
+ bottom_right = other;
+ }
+
+ // 10. Create top plane with these points: camera origin, top_left, top_right
+ Plane top(main_transform.origin, top_left, top_right);
+
+ // 11. Create bottom plane with these points: camera origin, bottom_left, bottom_right
+ Plane bottom(main_transform.origin, bottom_left, bottom_right);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Figure out our near plane points
+
+ // 12. Create a near plane using -camera z and the eye further along in that axis.
+ Plane near;
+ Vector3 neg_z = -z;
+ if (neg_z.dot(p_transforms[1].origin) < neg_z.dot(p_transforms[0].origin)) {
+ near = Plane(p_transforms[0].origin, neg_z);
+ } else {
+ near = Plane(p_transforms[1].origin, neg_z);
+ }
+
+ // 13. Intersect near plane with bottm/left planes, to obtain min_vec then top/right to obtain max_vec
+ Vector3 min_vec;
+ ERR_FAIL_COND_MSG(
+ !near.intersect_3(bottom, planes[0][CameraMatrix::PLANE_LEFT], &min_vec), "Can't determine left camera near/left/bottom vector");
+ ERR_FAIL_COND_MSG(
+ !near.intersect_3(bottom, planes[1][CameraMatrix::PLANE_LEFT], &other), "Can't determine right camera near/left/bottom vector");
+ if (x.dot(other) < x.dot(min_vec)) {
+ min_vec = other;
+ }
+
+ Vector3 max_vec;
+ ERR_FAIL_COND_MSG(
+ !near.intersect_3(top, planes[0][CameraMatrix::PLANE_RIGHT], &max_vec), "Can't determine left camera near/right/top vector");
+ ERR_FAIL_COND_MSG(
+ !near.intersect_3(top, planes[1][CameraMatrix::PLANE_RIGHT], &other), "Can't determine right camera near/right/top vector");
+ if (x.dot(max_vec) < x.dot(other)) {
+ max_vec = other;
+ }
+
+ // 14. transform these points by the inverse camera to obtain local_min_vec and local_max_vec
+ Vector3 local_min_vec = main_transform_inv.xform(min_vec);
+ Vector3 local_max_vec = main_transform_inv.xform(max_vec);
+
+ // 15. get x and y from these to obtain left, top, right bottom for the frustum. Get the distance from near plane to camera origin to obtain near, and the distance from the far plane to the camer origin to obtain far.
+ float z_near = -near.distance_to(main_transform.origin);
+ float z_far = -far.distance_to(main_transform.origin);
+
+ // 16. Use this to build the combined camera matrix.
+ main_projection.set_frustum(local_min_vec.x, local_max_vec.x, local_min_vec.y, local_max_vec.y, z_near, z_far);
+
+ /////////////////////////////////////////////////////////////////////////////
+ // 3. Copy our view data
+ for (uint32_t v = 0; v < view_count; v++) {
+ view_offset[v] = p_transforms[v] * main_transform_inv;
+ view_projection[v] = p_projections[v] * CameraMatrix(view_offset[v]);
+ }
+}
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 9ca9574f6f..3682122dd3 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -39,7 +39,8 @@ class RendererSceneRender {
public:
enum {
MAX_DIRECTIONAL_LIGHTS = 8,
- MAX_DIRECTIONAL_LIGHT_CASCADES = 4
+ MAX_DIRECTIONAL_LIGHT_CASCADES = 4,
+ MAX_RENDER_VIEWS = 2
};
struct GeometryInstance {
@@ -51,7 +52,7 @@ public:
virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) = 0;
virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) = 0;
virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) = 0;
- virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0;
+ virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0;
virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) = 0;
virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) = 0;
virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) = 0;
@@ -65,7 +66,7 @@ public:
virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) = 0;
virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0;
virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0;
- virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) = 0;
+ virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) = 0;
virtual void geometry_instance_free(GeometryInstance *p_geometry_instance) = 0;
@@ -161,9 +162,9 @@ public:
virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0;
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_transform(RID p_light_instance, const Transform3D &p_transform) = 0;
virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 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_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &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;
@@ -174,7 +175,7 @@ public:
virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 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_instance_set_transform(RID p_instance, const Transform3D &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;
@@ -182,17 +183,17 @@ public:
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 void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) = 0;
virtual RID lightmap_instance_create(RID p_lightmap) = 0;
- virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) = 0;
+ virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &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, const PagedArray<GeometryInstance *> &p_dynamic_objects) = 0;
+ virtual RID voxel_gi_instance_create(RID p_voxel_gi) = 0;
+ virtual void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) = 0;
+ virtual bool voxel_gi_needs_update(RID p_probe) const = 0;
+ virtual void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) = 0;
- virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0;
+ virtual void voxel_gi_set_quality(RS::VoxelGIQuality) = 0;
struct RenderShadowData {
RID light;
@@ -216,17 +217,34 @@ public:
uint32_t positional_light_count;
};
- virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) = 0;
+ struct CameraData {
+ // flags
+ uint32_t view_count;
+ bool is_ortogonal;
+ bool vaspect;
- virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
- virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0;
+ // Main/center projection
+ Transform3D main_transform;
+ CameraMatrix main_projection;
+
+ Transform3D view_offset[RendererSceneRender::MAX_RENDER_VIEWS];
+ CameraMatrix view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
+
+ void set_camera(const Transform3D p_transform, const CameraMatrix p_projection, bool p_is_ortogonal, bool p_vaspect);
+ void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const CameraMatrix *p_projections, bool p_is_ortogonal, bool p_vaspect);
+ };
+
+ virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) = 0;
+
+ virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
+ virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 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, bool p_use_debanding) = 0;
+ virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0;
virtual void gi_set_use_half_resolution(bool p_enable) = 0;
virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0;
diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h
index 22cf6acb19..f22c582f48 100644
--- a/servers/rendering/renderer_storage.h
+++ b/servers/rendering/renderer_storage.h
@@ -43,6 +43,7 @@ public:
DEPENDENCY_CHANGED_MESH,
DEPENDENCY_CHANGED_MULTIMESH,
DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES,
+ DEPENDENCY_CHANGED_PARTICLES,
DEPENDENCY_CHANGED_DECAL,
DEPENDENCY_CHANGED_SKELETON_DATA,
DEPENDENCY_CHANGED_SKELETON_BONES,
@@ -267,14 +268,14 @@ public:
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(RID p_multimesh, int p_index, const Transform3D &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 Transform3D 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;
@@ -312,8 +313,8 @@ public:
virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0;
virtual int skeleton_get_bone_count(RID p_skeleton) const = 0;
- virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0;
- virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0;
+ virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) = 0;
+ virtual Transform3D 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;
@@ -412,53 +413,53 @@ public:
virtual AABB decal_get_aabb(RID p_decal) const = 0;
- /* GI PROBE API */
+ /* VOXEL GI API */
- virtual RID gi_probe_allocate() = 0;
- virtual void gi_probe_initialize(RID p_rid) = 0;
+ virtual RID voxel_gi_allocate() = 0;
+ virtual void voxel_gi_initialize(RID p_rid) = 0;
- virtual void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0;
+ virtual void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &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 AABB voxel_gi_get_bounds(RID p_voxel_gi) const = 0;
+ virtual Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const = 0;
+ virtual Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const = 0;
+ virtual Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const = 0;
+ virtual Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) 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 Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const = 0;
+ virtual Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) 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 voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) = 0;
+ virtual float voxel_gi_get_dynamic_range(RID p_voxel_gi) 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 voxel_gi_set_propagation(RID p_voxel_gi, float p_range) = 0;
+ virtual float voxel_gi_get_propagation(RID p_voxel_gi) 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 voxel_gi_set_energy(RID p_voxel_gi, float p_energy) = 0;
+ virtual float voxel_gi_get_energy(RID p_voxel_gi) 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 voxel_gi_set_ao(RID p_voxel_gi, float p_ao) = 0;
+ virtual float voxel_gi_get_ao(RID p_voxel_gi) 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 voxel_gi_set_ao_size(RID p_voxel_gi, float p_strength) = 0;
+ virtual float voxel_gi_get_ao_size(RID p_voxel_gi) 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 voxel_gi_set_bias(RID p_voxel_gi, float p_bias) = 0;
+ virtual float voxel_gi_get_bias(RID p_voxel_gi) 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 voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) = 0;
+ virtual float voxel_gi_get_normal_bias(RID p_voxel_gi) 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 voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) = 0;
+ virtual bool voxel_gi_is_interior(RID p_voxel_gi) 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 voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) = 0;
+ virtual bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) 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 void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) = 0;
+ virtual float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const = 0;
- virtual uint32_t gi_probe_get_version(RID p_probe) = 0;
+ virtual uint32_t voxel_gi_get_version(RID p_probe) = 0;
/* LIGHTMAP */
@@ -483,6 +484,7 @@ public:
virtual RID particles_allocate() = 0;
virtual void particles_initialize(RID p_rid) = 0;
+ virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) = 0;
virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
virtual bool particles_get_emitting(RID p_particles) = 0;
@@ -498,10 +500,17 @@ public:
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0;
virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
+ virtual void particles_set_interpolate(RID p_particles, bool p_enable) = 0;
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0;
+
+ virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) = 0;
+
+ virtual void particles_set_trails(RID p_particles, bool p_enable, float p_length) = 0;
+ virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) = 0;
+
virtual void particles_restart(RID p_particles) = 0;
- virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0;
+ virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0;
virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0;
virtual bool particles_is_inactive(RID p_particles) const = 0;
@@ -515,16 +524,18 @@ public:
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 void particles_set_emission_transform(RID p_particles, const Transform3D &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;
- virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) = 0;
+ virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) = 0;
virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) = 0;
virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) = 0;
+ virtual void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) = 0;
+
virtual void update_particles() = 0;
/* PARTICLES COLLISION */
@@ -546,9 +557,17 @@ public:
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0;
virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0;
+ virtual RID visibility_notifier_allocate() = 0;
+ virtual void visibility_notifier_initialize(RID p_notifier) = 0;
+ virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) = 0;
+ virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0;
+
+ virtual AABB visibility_notifier_get_aabb(RID p_notifier) const = 0;
+ virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) = 0;
+
//used from 2D and 3D
virtual RID particles_collision_instance_create(RID p_collision) = 0;
- virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) = 0;
+ virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) = 0;
virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) = 0;
/* GLOBAL VARIABLES */
@@ -579,7 +598,7 @@ public:
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 void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) = 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;
@@ -594,6 +613,7 @@ public:
virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) = 0;
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const = 0;
+ virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) = 0;
virtual RS::InstanceType get_base_type(RID p_rid) const = 0;
virtual bool free(RID p_rid) = 0;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index a5d5033c18..34bdb15c62 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -71,24 +71,36 @@ static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport,
return xf;
}
-void RendererViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) {
+void RendererViewport::_draw_3d(Viewport *p_viewport) {
RENDER_TIMESTAMP(">Begin Rendering 3D Scene");
Ref<XRInterface> xr_interface;
- if (XRServer::get_singleton() != nullptr) {
+ if (p_viewport->use_xr && XRServer::get_singleton() != nullptr) {
xr_interface = XRServer::get_singleton()->get_primary_interface();
}
- float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width);
- if (p_viewport->use_xr && xr_interface.is_valid()) {
- RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas);
- } else {
- RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas);
+ if (p_viewport->use_occlusion_culling) {
+ if (p_viewport->occlusion_buffer_dirty) {
+ float aspect = p_viewport->size.aspect();
+ int max_size = occlusion_rays_per_thread * RendererThreadPool::singleton->thread_work_pool.get_thread_count();
+
+ int viewport_size = p_viewport->size.width * p_viewport->size.height;
+ max_size = CLAMP(max_size, viewport_size / (32 * 32), viewport_size / (2 * 2)); // At least one depth pixel for every 16x16 region. At most one depth pixel for every 2x2 region.
+
+ float height = Math::sqrt(max_size / aspect);
+ Size2i new_size = Size2i(height * aspect, height);
+ RendererSceneOcclusionCull::get_singleton()->buffer_set_size(p_viewport->self, new_size);
+ p_viewport->occlusion_buffer_dirty = false;
+ }
}
+
+ float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width);
+ RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas, xr_interface);
+
RENDER_TIMESTAMP("<End Rendering 3D Scene");
}
-void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) {
+void RendererViewport::_draw_viewport(Viewport *p_viewport, uint32_t p_view_count) {
if (p_viewport->measure_render_time) {
String rt_id = "vp_begin_" + itos(p_viewport->self.get_id());
RSG::storage->capture_timestamp(rt_id);
@@ -124,13 +136,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
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_buffers_create();
- RSG::scene->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, p_viewport->use_debanding);
+ RSG::scene->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, p_viewport->use_debanding, p_view_count);
}
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);
+ _draw_3d(p_viewport);
}
if (!p_viewport->hide_canvas) {
@@ -171,8 +183,11 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
}
RSG::canvas_render->render_sdf(p_viewport->render_target, occluders);
+ RSG::storage->render_target_mark_sdf_enabled(p_viewport->render_target, true);
p_viewport->sdf_active = false; // if used, gets set active again
+ } else {
+ RSG::storage->render_target_mark_sdf_enabled(p_viewport->render_target, false);
}
Rect2 shadow_rect;
@@ -307,7 +322,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
Vector2 point = clip_rect.position + clip_rect.size * signs[j];
if (sign_cmp == light_dir_sign) {
- //both point in same direction, plot offseted
+ //both point in same direction, plot offsetted
points[point_count++] = point + light_dir * cull_distance;
} else if (sign_cmp.x == light_dir_sign.x || sign_cmp.y == light_dir_sign.y) {
int next_j = (j + 1) % 4;
@@ -374,7 +389,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
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);
+ _draw_3d(p_viewport);
}
scenario_draw_canvas_bg = false;
}
@@ -415,7 +430,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
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);
+ _draw_3d(p_viewport);
}
scenario_draw_canvas_bg = false;
@@ -426,7 +441,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_
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);
+ _draw_3d(p_viewport);
}
}
}
@@ -463,7 +478,7 @@ void RendererViewport::draw_viewports() {
//sort viewports
active_viewports.sort_custom<ViewportSort>();
- Map<DisplayServer::WindowID, Vector<RendererCompositor::BlitToScreen>> blit_to_screen_list;
+ Map<DisplayServer::WindowID, Vector<BlitToScreen>> blit_to_screen_list;
//draw viewports
RENDER_TIMESTAMP(">Render Viewports");
@@ -517,52 +532,54 @@ void RendererViewport::draw_viewports() {
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
+ // override our size, make sure it matches our required size and is created as a stereo target
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;
+ uint32_t view_count = xr_interface->get_view_count();
+ RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count);
- // 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));
+ // check for an external texture destination (disabled for now, not yet supported)
+ // RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono));
+ RSG::storage->render_target_set_external_texture(vp->render_target, 0);
- // set our render target as current
- RSG::rasterizer->set_current_render_target(vp->render_target);
+ // render...
+ RSG::scene->set_debug_draw_mode(vp->debug_draw);
+ RSG::storage->render_info_begin_capture();
- // and draw left eye/mono
- _draw_viewport(vp, leftOrMono);
- xr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect);
+ // and draw viewport
+ _draw_viewport(vp, view_count);
- // 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));
+ // measure
+ 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);
- // commit for eye may have changed the render target
- RSG::rasterizer->set_current_render_target(vp->render_target);
+ // commit our eyes
+ Vector<BlitToScreen> blits = xr_interface->commit_views(vp->render_target, vp->viewport_to_screen_rect);
+ if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && blits.size() > 0) {
+ if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
+ blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
+ }
- _draw_viewport(vp, XRInterface::EYE_RIGHT);
- xr_interface->commit_for_eye(XRInterface::EYE_RIGHT, vp->render_target, vp->viewport_to_screen_rect);
+ for (int b = 0; b < blits.size(); b++) {
+ blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
+ }
}
// 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->set_debug_draw_mode(vp->debug_draw);
RSG::storage->render_info_begin_capture();
// render standard mono camera
- _draw_viewport(vp);
+ _draw_viewport(vp, 1);
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);
@@ -574,7 +591,7 @@ void RendererViewport::draw_viewports() {
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
- RendererCompositor::BlitToScreen blit;
+ BlitToScreen blit;
blit.render_target = vp->render_target;
if (vp->viewport_to_screen_rect != Rect2()) {
blit.rect = vp->viewport_to_screen_rect;
@@ -584,7 +601,7 @@ void RendererViewport::draw_viewports() {
}
if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
- blit_to_screen_list[vp->viewport_to_screen] = Vector<RendererCompositor::BlitToScreen>();
+ blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
}
blit_to_screen_list[vp->viewport_to_screen].push_back(blit);
@@ -603,7 +620,7 @@ void RendererViewport::draw_viewports() {
//this needs to be called to make screen swapping more efficient
RSG::rasterizer->prepare_for_blitting_render_targets();
- for (Map<int, Vector<RendererCompositor::BlitToScreen>>::Element *E = blit_to_screen_list.front(); E; E = E->next()) {
+ for (Map<int, Vector<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());
}
}
@@ -628,7 +645,29 @@ void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
Viewport *viewport = viewport_owner.getornull(p_viewport);
ERR_FAIL_COND(!viewport);
+ if (viewport->use_xr == p_use_xr) {
+ return;
+ }
+
viewport->use_xr = p_use_xr;
+ if (viewport->render_buffers.is_valid()) {
+ RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding, viewport->get_view_count());
+ }
+}
+
+uint32_t RendererViewport::Viewport::get_view_count() {
+ uint32_t view_count = 1;
+
+ if (use_xr && XRServer::get_singleton() != nullptr) {
+ Ref<XRInterface> xr_interface;
+
+ xr_interface = XRServer::get_singleton()->get_primary_interface();
+ if (xr_interface.is_valid()) {
+ view_count = xr_interface->get_view_count();
+ }
+ }
+
+ return view_count;
}
void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) {
@@ -638,15 +677,18 @@ void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_heig
ERR_FAIL_COND(!viewport);
viewport->size = Size2(p_width, p_height);
- RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height);
+ uint32_t view_count = viewport->get_view_count();
+ RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height, view_count);
if (viewport->render_buffers.is_valid()) {
if (p_width == 0 || p_height == 0) {
RSG::scene->free(viewport->render_buffers);
viewport->render_buffers = RID();
} else {
- RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding);
+ RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding, view_count);
}
}
+
+ viewport->occlusion_buffer_dirty = true;
}
void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
@@ -655,6 +697,7 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
if (p_active) {
ERR_FAIL_COND(active_viewports.find(viewport) != -1); //already active
+ viewport->occlusion_buffer_dirty = true;
active_viewports.push_back(viewport);
} else {
active_viewports.erase(viewport);
@@ -683,7 +726,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
// 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_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->get_view_count());
RSG::storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y);
}
@@ -693,7 +736,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
// 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);
+ RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
}
viewport->viewport_to_screen_rect = Rect2();
@@ -712,7 +755,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
// 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_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
}
RSG::storage->render_target_set_flag(viewport->render_target, RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable);
@@ -720,7 +763,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
// 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_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->get_view_count());
RSG::storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y);
}
}
@@ -739,6 +782,16 @@ RID RendererViewport::viewport_get_texture(RID p_viewport) const {
return RSG::storage->render_target_get_texture(viewport->render_target);
}
+RID RendererViewport::viewport_get_occluder_debug_texture(RID p_viewport) const {
+ const Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND_V(!viewport, RID());
+
+ if (viewport->use_occlusion_culling && viewport->debug_draw == RenderingServer::VIEWPORT_DEBUG_DRAW_OCCLUDERS) {
+ return RendererSceneOcclusionCull::get_singleton()->buffer_get_debug_texture(p_viewport);
+ }
+ return RID();
+}
+
void RendererViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) {
Viewport *viewport = viewport_owner.getornull(p_viewport);
ERR_FAIL_COND(!viewport);
@@ -771,7 +824,14 @@ void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) {
Viewport *viewport = viewport_owner.getornull(p_viewport);
ERR_FAIL_COND(!viewport);
+ if (viewport->scenario.is_valid()) {
+ RSG::scene->scenario_remove_viewport_visibility_mask(viewport->scenario, p_viewport);
+ }
+
viewport->scenario = p_scenario;
+ if (viewport->use_occlusion_culling) {
+ RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, p_scenario);
+ }
}
void RendererViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) {
@@ -858,7 +918,7 @@ void RendererViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa
}
viewport->msaa = p_msaa;
if (viewport->render_buffers.is_valid()) {
- RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa, viewport->use_debanding);
+ RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa, viewport->use_debanding, viewport->get_view_count());
}
}
@@ -871,7 +931,7 @@ void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::Viewport
}
viewport->screen_space_aa = p_mode;
if (viewport->render_buffers.is_valid()) {
- RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode, viewport->use_debanding);
+ RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode, viewport->use_debanding, viewport->get_view_count());
}
}
@@ -884,10 +944,45 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb
}
viewport->use_debanding = p_use_debanding;
if (viewport->render_buffers.is_valid()) {
- RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, p_use_debanding);
+ RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, p_use_debanding, viewport->get_view_count());
}
}
+void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) {
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ if (viewport->use_occlusion_culling == p_use_occlusion_culling) {
+ return;
+ }
+ viewport->use_occlusion_culling = p_use_occlusion_culling;
+
+ if (viewport->use_occlusion_culling) {
+ RendererSceneOcclusionCull::get_singleton()->add_buffer(p_viewport);
+ RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, viewport->scenario);
+ } else {
+ RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_viewport);
+ }
+
+ viewport->occlusion_buffer_dirty = true;
+}
+
+void RendererViewport::viewport_set_occlusion_rays_per_thread(int p_rays_per_thread) {
+ if (occlusion_rays_per_thread == p_rays_per_thread) {
+ return;
+ }
+
+ occlusion_rays_per_thread = p_rays_per_thread;
+
+ for (int i = 0; i < active_viewports.size(); i++) {
+ active_viewports[i]->occlusion_buffer_dirty = true;
+ }
+}
+
+void RendererViewport::viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) {
+ RendererSceneOcclusionCull::get_singleton()->set_build_quality(p_quality);
+}
+
void RendererViewport::viewport_set_lod_threshold(RID p_viewport, float p_pixels) {
Viewport *viewport = viewport_owner.getornull(p_viewport);
ERR_FAIL_COND(!viewport);
@@ -985,6 +1080,10 @@ bool RendererViewport::free(RID p_rid) {
viewport_set_scenario(p_rid, RID());
active_viewports.erase(viewport);
+ if (viewport->use_occlusion_culling) {
+ RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_rid);
+ }
+
viewport_owner.free(p_rid);
memdelete(viewport);
@@ -1026,4 +1125,5 @@ void RendererViewport::call_set_use_vsync(bool p_enable) {
}
RendererViewport::RendererViewport() {
+ occlusion_rays_per_thread = GLOBAL_GET("rendering/occlusion_culling/occlusion_rays_per_thread");
}
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index f5ed543e8d..ffda9ad8f0 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -31,9 +31,9 @@
#ifndef VISUALSERVERVIEWPORT_H
#define VISUALSERVERVIEWPORT_H
+#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
-#include "renderer_compositor.h"
#include "servers/rendering_server.h"
#include "servers/xr/xr_interface.h"
@@ -61,6 +61,9 @@ public:
RS::ViewportScreenSpaceAA screen_space_aa;
bool use_debanding;
+ bool use_occlusion_culling;
+ bool occlusion_buffer_dirty;
+
DisplayServer::WindowID viewport_to_screen;
Rect2 viewport_to_screen_rect;
bool viewport_render_direct_to_screen;
@@ -143,6 +146,8 @@ public:
msaa = RS::VIEWPORT_MSAA_DISABLED;
screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
use_debanding = false;
+ use_occlusion_culling = false;
+ occlusion_buffer_dirty = true;
snap_2d_transforms_to_pixel = false;
snap_2d_vertices_to_pixel = false;
@@ -159,6 +164,8 @@ public:
time_gpu_begin = 0;
time_gpu_end = 0;
}
+
+ uint32_t get_view_count();
};
HashMap<String, RID> timestamp_vp_map;
@@ -182,8 +189,12 @@ public:
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);
+ void _draw_3d(Viewport *p_viewport);
+ void _draw_viewport(Viewport *p_viewport, uint32_t p_view_count = 1);
+
+ int occlusion_rays_per_thread = 512;
+
+ void _resize_occlusion_culling_buffer(const Size2i &p_size);
public:
RID viewport_allocate();
@@ -204,6 +215,7 @@ public:
void viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode);
RID viewport_get_texture(RID p_viewport) const;
+ RID viewport_get_occluder_debug_texture(RID p_viewport) const;
void viewport_set_hide_scenario(RID p_viewport, bool p_hide);
void viewport_set_hide_canvas(RID p_viewport, bool p_hide);
@@ -225,7 +237,9 @@ public:
void viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa);
void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode);
void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding);
-
+ void viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling);
+ void viewport_set_occlusion_rays_per_thread(int p_rays_per_thread);
+ void viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality);
void viewport_set_lod_threshold(RID p_viewport, float p_pixels);
virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info);
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index e6ad001807..056cec4c1f 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -40,6 +40,7 @@ RenderingDevice *RenderingDevice::get_singleton() {
RenderingDevice::ShaderCompileFunction RenderingDevice::compile_function = nullptr;
RenderingDevice::ShaderCacheFunction RenderingDevice::cache_function = nullptr;
+RenderingDevice::ShaderGetCacheKeyFunction RenderingDevice::get_cache_key_function = nullptr;
void RenderingDevice::shader_set_compile_function(ShaderCompileFunction p_function) {
compile_function = p_function;
@@ -49,6 +50,10 @@ void RenderingDevice::shader_set_cache_function(ShaderCacheFunction p_function)
cache_function = p_function;
}
+void RenderingDevice::shader_set_get_cache_key_function(ShaderGetCacheKeyFunction p_function) {
+ get_cache_key_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);
@@ -62,6 +67,13 @@ Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage,
return compile_function(p_stage, p_source_code, p_language, r_error, &device_capabilities);
}
+String RenderingDevice::shader_get_cache_key() const {
+ if (get_cache_key_function) {
+ return get_cache_key_function(&device_capabilities);
+ }
+ return String();
+}
+
RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) {
ERR_FAIL_COND_V(p_format.is_null(), RID());
ERR_FAIL_COND_V(p_view.is_null(), RID());
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 2de0549e8d..c13dc01dd7 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -93,18 +93,24 @@ public:
DeviceFamily device_family = DEVICE_UNKNOWN;
uint32_t version_major = 1.0;
uint32_t version_minor = 0.0;
+
// subgroup capabilities
uint32_t subgroup_size = 0;
uint32_t subgroup_in_shaders = 0; // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc.
uint32_t subgroup_operations = 0; // Set flags, using SubgroupOperations
+
+ // features
+ bool supports_multiview = false; // If true this device supports multiview options
};
+ typedef String (*ShaderGetCacheKeyFunction)(const Capabilities *p_capabilities);
typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities);
typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
private:
static ShaderCompileFunction compile_function;
static ShaderCacheFunction cache_function;
+ static ShaderGetCacheKeyFunction get_cache_key_function;
static RenderingDevice *singleton;
@@ -510,11 +516,11 @@ public:
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 FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1) = 0;
virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1) = 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 RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0;
virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID) = 0;
virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0;
@@ -631,9 +637,11 @@ public:
const Capabilities *get_device_capabilities() const { return &device_capabilities; };
virtual Vector<uint8_t> shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true);
+ virtual String shader_get_cache_key() const;
static void shader_set_compile_function(ShaderCompileFunction p_function);
static void shader_set_cache_function(ShaderCacheFunction p_function);
+ static void shader_set_get_cache_key_function(ShaderGetCacheKeyFunction p_function);
struct ShaderStageData {
ShaderStage shader_stage;
@@ -978,7 +986,7 @@ public:
enum InitialAction {
INITIAL_ACTION_CLEAR, //start rendering and clear the whole framebuffer (region or not) (supply params)
INITIAL_ACTION_CLEAR_REGION, //start rendering and clear the framebuffer in the specified region (supply params)
- INITIAL_ACTION_CLEAR_REGION_CONTINUE, //countinue rendering and clear the framebuffer in the specified region (supply params)
+ INITIAL_ACTION_CLEAR_REGION_CONTINUE, //continue rendering and clear the framebuffer in the specified region (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)
diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h
index e43c3669b5..912674e309 100644
--- a/servers/rendering/rendering_device_binds.h
+++ b/servers/rendering/rendering_device_binds.h
@@ -51,8 +51,8 @@
ClassDB::bind_method(D_METHOD("get_" _MKSTR(m_sub) "_" _MKSTR(m_member)), &m_class::get_##m_sub##_##m_member); \
ADD_PROPERTY(PropertyInfo(m_variant_type, _MKSTR(m_sub) "_" _MKSTR(m_member)), "set_" _MKSTR(m_sub) "_" _MKSTR(m_member), "get_" _MKSTR(m_sub) "_" _MKSTR(m_member))
-class RDTextureFormat : public Reference {
- GDCLASS(RDTextureFormat, Reference)
+class RDTextureFormat : public RefCounted {
+ GDCLASS(RDTextureFormat, RefCounted)
friend class RenderingDevice;
RD::TextureFormat base;
@@ -87,8 +87,8 @@ protected:
}
};
-class RDTextureView : public Reference {
- GDCLASS(RDTextureView, Reference)
+class RDTextureView : public RefCounted {
+ GDCLASS(RDTextureView, RefCounted)
friend class RenderingDevice;
@@ -110,8 +110,8 @@ protected:
}
};
-class RDAttachmentFormat : public Reference {
- GDCLASS(RDAttachmentFormat, Reference)
+class RDAttachmentFormat : public RefCounted {
+ GDCLASS(RDAttachmentFormat, RefCounted)
friend class RenderingDevice;
RD::AttachmentFormat base;
@@ -128,8 +128,8 @@ protected:
}
};
-class RDSamplerState : public Reference {
- GDCLASS(RDSamplerState, Reference)
+class RDSamplerState : public RefCounted {
+ GDCLASS(RDSamplerState, RefCounted)
friend class RenderingDevice;
RD::SamplerState base;
@@ -171,8 +171,8 @@ protected:
}
};
-class RDVertexAttribute : public Reference {
- GDCLASS(RDVertexAttribute, Reference)
+class RDVertexAttribute : public RefCounted {
+ GDCLASS(RDVertexAttribute, RefCounted)
friend class RenderingDevice;
RD::VertexAttribute base;
@@ -192,8 +192,8 @@ protected:
RD_BIND(Variant::INT, RDVertexAttribute, frequency);
}
};
-class RDShaderSource : public Reference {
- GDCLASS(RDShaderSource, Reference)
+class RDShaderSource : public RefCounted {
+ GDCLASS(RDShaderSource, RefCounted)
String source[RD::SHADER_STAGE_MAX];
RD::ShaderLanguage language = RD::SHADER_LANGUAGE_GLSL;
@@ -386,8 +386,8 @@ protected:
}
};
-class RDUniform : public Reference {
- GDCLASS(RDUniform, Reference)
+class RDUniform : public RefCounted {
+ GDCLASS(RDUniform, RefCounted)
friend class RenderingDevice;
RD::Uniform base;
@@ -424,8 +424,8 @@ protected:
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_ids", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_ids", "get_ids");
}
};
-class RDPipelineRasterizationState : public Reference {
- GDCLASS(RDPipelineRasterizationState, Reference)
+class RDPipelineRasterizationState : public RefCounted {
+ GDCLASS(RDPipelineRasterizationState, RefCounted)
friend class RenderingDevice;
RD::PipelineRasterizationState base;
@@ -459,8 +459,8 @@ protected:
}
};
-class RDPipelineMultisampleState : public Reference {
- GDCLASS(RDPipelineMultisampleState, Reference)
+class RDPipelineMultisampleState : public RefCounted {
+ GDCLASS(RDPipelineMultisampleState, RefCounted)
friend class RenderingDevice;
RD::PipelineMultisampleState base;
@@ -490,8 +490,8 @@ protected:
}
};
-class RDPipelineDepthStencilState : public Reference {
- GDCLASS(RDPipelineDepthStencilState, Reference)
+class RDPipelineDepthStencilState : public RefCounted {
+ GDCLASS(RDPipelineDepthStencilState, RefCounted)
friend class RenderingDevice;
RD::PipelineDepthStencilState base;
@@ -549,8 +549,8 @@ protected:
}
};
-class RDPipelineColorBlendStateAttachment : public Reference {
- GDCLASS(RDPipelineColorBlendStateAttachment, Reference)
+class RDPipelineColorBlendStateAttachment : public RefCounted {
+ GDCLASS(RDPipelineColorBlendStateAttachment, RefCounted)
friend class RenderingDevice;
RD::PipelineColorBlendState::Attachment base;
@@ -594,8 +594,8 @@ protected:
}
};
-class RDPipelineColorBlendState : public Reference {
- GDCLASS(RDPipelineColorBlendState, Reference)
+class RDPipelineColorBlendState : public RefCounted {
+ GDCLASS(RDPipelineColorBlendState, RefCounted)
friend class RenderingDevice;
RD::PipelineColorBlendState base;
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index c6fe6a07e0..629d212b69 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -117,6 +117,9 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
_draw_margins();
RSG::rasterizer->end_frame(p_swap_buffers);
+ RSG::canvas->update_visibility_notifiers();
+ RSG::scene->update_visibility_notifiers();
+
while (frame_drawn_callbacks.front()) {
Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object);
if (obj) {
@@ -358,7 +361,7 @@ void RenderingServerDefault::_thread_loop() {
draw_thread_up.set();
while (!exit.is_set()) {
// flush commands one by one, until exit is requested
- command_queue.wait_and_flush_one();
+ command_queue.wait_and_flush();
}
command_queue.flush_all(); // flush all
@@ -396,6 +399,7 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) :
server_thread = 0;
}
+ RSG::threaded = p_create_thread;
RSG::canvas = memnew(RendererCanvasCull);
RSG::viewport = memnew(RendererViewport);
RendererSceneCull *sr = memnew(RendererSceneCull);
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 683a22fd9a..9404374287 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -314,7 +314,7 @@ public:
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, RID, int, const Transform3D &)
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 &)
@@ -322,7 +322,7 @@ public:
FUNC1RC(RID, multimesh_get_mesh, RID)
FUNC1RC(AABB, multimesh_get_aabb, RID)
- FUNC2RC(Transform, multimesh_instance_get_transform, RID, int)
+ FUNC2RC(Transform3D, 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)
@@ -353,8 +353,8 @@ public:
FUNCRIDSPLIT(skeleton)
FUNC3(skeleton_allocate_data, RID, int, bool)
FUNC1RC(int, skeleton_get_bone_count, RID)
- FUNC3(skeleton_bone_set_transform, RID, int, const Transform &)
- FUNC2RC(Transform, skeleton_bone_get_transform, RID, int)
+ FUNC3(skeleton_bone_set_transform, RID, int, const Transform3D &)
+ FUNC2RC(Transform3D, 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 &)
@@ -418,47 +418,47 @@ public:
/* BAKED LIGHT API */
- FUNCRIDSPLIT(gi_probe)
+ FUNCRIDSPLIT(voxel_gi)
- FUNC8(gi_probe_allocate_data, RID, const Transform &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &)
+ FUNC8(voxel_gi_allocate_data, RID, const Transform3D &, 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)
+ FUNC1RC(AABB, voxel_gi_get_bounds, RID)
+ FUNC1RC(Vector3i, voxel_gi_get_octree_size, RID)
+ FUNC1RC(Vector<uint8_t>, voxel_gi_get_octree_cells, RID)
+ FUNC1RC(Vector<uint8_t>, voxel_gi_get_data_cells, RID)
+ FUNC1RC(Vector<uint8_t>, voxel_gi_get_distance_field, RID)
+ FUNC1RC(Vector<int>, voxel_gi_get_level_counts, RID)
+ FUNC1RC(Transform3D, voxel_gi_get_to_cell_xform, RID)
- FUNC2(gi_probe_set_dynamic_range, RID, float)
- FUNC1RC(float, gi_probe_get_dynamic_range, RID)
+ FUNC2(voxel_gi_set_dynamic_range, RID, float)
+ FUNC1RC(float, voxel_gi_get_dynamic_range, RID)
- FUNC2(gi_probe_set_propagation, RID, float)
- FUNC1RC(float, gi_probe_get_propagation, RID)
+ FUNC2(voxel_gi_set_propagation, RID, float)
+ FUNC1RC(float, voxel_gi_get_propagation, RID)
- FUNC2(gi_probe_set_energy, RID, float)
- FUNC1RC(float, gi_probe_get_energy, RID)
+ FUNC2(voxel_gi_set_energy, RID, float)
+ FUNC1RC(float, voxel_gi_get_energy, RID)
- FUNC2(gi_probe_set_ao, RID, float)
- FUNC1RC(float, gi_probe_get_ao, RID)
+ FUNC2(voxel_gi_set_ao, RID, float)
+ FUNC1RC(float, voxel_gi_get_ao, RID)
- FUNC2(gi_probe_set_ao_size, RID, float)
- FUNC1RC(float, gi_probe_get_ao_size, RID)
+ FUNC2(voxel_gi_set_ao_size, RID, float)
+ FUNC1RC(float, voxel_gi_get_ao_size, RID)
- FUNC2(gi_probe_set_bias, RID, float)
- FUNC1RC(float, gi_probe_get_bias, RID)
+ FUNC2(voxel_gi_set_bias, RID, float)
+ FUNC1RC(float, voxel_gi_get_bias, RID)
- FUNC2(gi_probe_set_normal_bias, RID, float)
- FUNC1RC(float, gi_probe_get_normal_bias, RID)
+ FUNC2(voxel_gi_set_normal_bias, RID, float)
+ FUNC1RC(float, voxel_gi_get_normal_bias, RID)
- FUNC2(gi_probe_set_interior, RID, bool)
- FUNC1RC(bool, gi_probe_is_interior, RID)
+ FUNC2(voxel_gi_set_interior, RID, bool)
+ FUNC1RC(bool, voxel_gi_is_interior, RID)
- FUNC2(gi_probe_set_use_two_bounces, RID, bool)
- FUNC1RC(bool, gi_probe_is_using_two_bounces, RID)
+ FUNC2(voxel_gi_set_use_two_bounces, RID, bool)
+ FUNC1RC(bool, voxel_gi_is_using_two_bounces, RID)
- FUNC2(gi_probe_set_anisotropy_strength, RID, float)
- FUNC1RC(float, gi_probe_get_anisotropy_strength, RID)
+ FUNC2(voxel_gi_set_anisotropy_strength, RID, float)
+ FUNC1RC(float, voxel_gi_get_anisotropy_strength, RID)
/* LIGHTMAP */
@@ -478,6 +478,7 @@ public:
FUNCRIDSPLIT(particles)
+ FUNC2(particles_set_mode, RID, ParticlesMode)
FUNC2(particles_set_emitting, RID, bool)
FUNC1R(bool, particles_get_emitting, RID)
FUNC2(particles_set_amount, RID, int)
@@ -491,21 +492,27 @@ public:
FUNC2(particles_set_use_local_coordinates, RID, bool)
FUNC2(particles_set_process_material, RID, RID)
FUNC2(particles_set_fixed_fps, RID, int)
+ FUNC2(particles_set_interpolate, RID, bool)
FUNC2(particles_set_fractional_delta, RID, bool)
FUNC1R(bool, particles_is_inactive, RID)
+ FUNC3(particles_set_trails, RID, bool, float)
+ FUNC2(particles_set_trail_bind_poses, RID, const Vector<Transform3D> &)
+
FUNC1(particles_request_process, RID)
FUNC1(particles_restart, RID)
- FUNC6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t)
+ FUNC6(particles_emit, RID, const Transform3D &, const Vector3 &, const Color &, const Color &, uint32_t)
FUNC2(particles_set_subemitter, RID, RID)
FUNC2(particles_set_collision_base_size, RID, float)
+ FUNC2(particles_set_transform_align, RID, RS::ParticlesTransformAlign)
+
FUNC2(particles_set_draw_order, RID, RS::ParticlesDrawOrder)
FUNC2(particles_set_draw_passes, RID, int)
FUNC3(particles_set_draw_pass_mesh, RID, int, RID)
FUNC1R(AABB, particles_get_current_aabb, RID)
- FUNC2(particles_set_emission_transform, RID, const Transform &)
+ FUNC2(particles_set_emission_transform, RID, const Transform3D &)
/* PARTICLES COLLISION */
@@ -522,6 +529,12 @@ public:
FUNC1(particles_collision_height_field_update, RID)
FUNC2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution)
+ /* VISIBILITY_NOTIFIER */
+
+ FUNCRIDSPLIT(visibility_notifier)
+ FUNC2(visibility_notifier_set_aabb, RID, const AABB &)
+ FUNC3(visibility_notifier_set_callbacks, RID, const Callable &, const Callable &)
+
#undef server_name
#undef ServerName
//from now on, calls forwarded to this singleton
@@ -534,12 +547,16 @@ public:
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_transform, RID, const Transform3D &)
FUNC2(camera_set_cull_mask, RID, uint32_t)
FUNC2(camera_set_environment, RID, RID)
FUNC2(camera_set_camera_effects, RID, RID)
FUNC2(camera_set_use_vertical_aspect, RID, bool)
+ /* OCCLUDER */
+ FUNCRIDSPLIT(occluder)
+ FUNC3(occluder_set_mesh, RID, const PackedVector3Array &, const PackedInt32Array &)
+
#undef server_name
#undef ServerName
//from now on, calls forwarded to this singleton
@@ -590,6 +607,9 @@ public:
FUNC2(viewport_set_msaa, RID, ViewportMSAA)
FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
FUNC2(viewport_set_use_debanding, RID, bool)
+ FUNC2(viewport_set_use_occlusion_culling, RID, bool)
+ FUNC1(viewport_set_occlusion_rays_per_thread, int)
+ FUNC1(viewport_set_occlusion_culling_build_quality, ViewportOcclusionCullingBuildQuality)
FUNC2(viewport_set_lod_threshold, RID, float)
FUNC2R(int, viewport_get_render_info, RID, ViewportRenderInfo)
@@ -610,7 +630,7 @@ public:
#define server_name RSG::scene
FUNC2(directional_shadow_atlas_set_size, int, bool)
- FUNC1(gi_probe_set_quality, GIProbeQuality)
+ FUNC1(voxel_gi_set_quality, VoxelGIQuality)
/* SKY API */
@@ -700,7 +720,7 @@ public:
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_set_transform, RID, const Transform3D &)
FUNC2(instance_attach_object_instance_id, RID, ObjectID)
FUNC3(instance_set_blend_shape_weight, RID, int, float)
FUNC3(instance_set_surface_override_material, RID, int, RID)
@@ -712,6 +732,7 @@ public:
FUNC2(instance_set_exterior, RID, bool)
FUNC2(instance_set_extra_visibility_margin, RID, real_t)
+ FUNC2(instance_set_visibility_parent, RID, RID)
// don't use these in a game!
FUNC2RC(Vector<ObjectID>, instances_cull_aabb, const AABB &, RID)
@@ -722,8 +743,7 @@ public:
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)
+ FUNC5(instance_geometry_set_visibility_range, RID, float, float, float, float)
FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int)
FUNC2(instance_geometry_set_lod_bias, RID, float)
@@ -806,6 +826,8 @@ public:
FUNC2(canvas_item_set_use_parent_material, RID, bool)
+ FUNC5(canvas_item_set_visibility_notifier, RID, bool, const Rect2 &, const Callable &, const Callable &)
+
FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
FUNCRIDSPLIT(canvas_light)
diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp
index c0d9988e85..2dda506bac 100644
--- a/servers/rendering/rendering_server_globals.cpp
+++ b/servers/rendering/rendering_server_globals.cpp
@@ -30,6 +30,8 @@
#include "rendering_server_globals.h"
+bool RenderingServerGlobals::threaded = false;
+
RendererStorage *RenderingServerGlobals::storage = nullptr;
RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr;
RendererCompositor *RenderingServerGlobals::rasterizer = nullptr;
diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h
index a28a0f5180..63755e6125 100644
--- a/servers/rendering/rendering_server_globals.h
+++ b/servers/rendering/rendering_server_globals.h
@@ -41,6 +41,8 @@ class RendererScene;
class RenderingServerGlobals {
public:
+ static bool threaded;
+
static RendererStorage *storage;
static RendererCanvasRender *canvas_render;
static RendererCompositor *rasterizer;
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index f5228f9747..8ed774f8e7 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -33,6 +33,8 @@
#include "core/string/print_string.h"
#include "servers/rendering_server.h"
+#define HAS_WARNING(flag) (warning_flags & flag)
+
static bool _is_text_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
@@ -901,6 +903,8 @@ bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) {
void ShaderLanguage::clear() {
current_function = StringName();
+ last_name = StringName();
+ last_type = IDENTIFIER_MAX;
completion_type = COMPLETION_NONE;
completion_block = nullptr;
@@ -908,12 +912,22 @@ void ShaderLanguage::clear() {
completion_class = SubClassTag::TAG_GLOBAL;
completion_struct = StringName();
+#ifdef DEBUG_ENABLED
+ used_constants.clear();
+ used_varyings.clear();
+ used_uniforms.clear();
+ used_functions.clear();
+ used_structs.clear();
+ warnings.clear();
+#endif // DEBUG_ENABLED
+
error_line = 0;
tk_line = 1;
char_idx = 0;
error_set = false;
error_str = "";
last_const = false;
+ pass_array = false;
while (nodes) {
Node *n = nodes;
nodes = nodes->next;
@@ -921,6 +935,35 @@ void ShaderLanguage::clear() {
}
}
+#ifdef DEBUG_ENABLED
+void ShaderLanguage::_parse_used_identifier(const StringName &p_identifier, IdentifierType p_type) {
+ switch (p_type) {
+ case IdentifierType::IDENTIFIER_CONSTANT:
+ if (HAS_WARNING(ShaderWarning::UNUSED_CONSTANT_FLAG) && used_constants.has(p_identifier)) {
+ used_constants[p_identifier].used = true;
+ }
+ break;
+ case IdentifierType::IDENTIFIER_VARYING:
+ if (HAS_WARNING(ShaderWarning::UNUSED_VARYING_FLAG) && used_varyings.has(p_identifier)) {
+ used_varyings[p_identifier].used = true;
+ }
+ break;
+ case IdentifierType::IDENTIFIER_UNIFORM:
+ if (HAS_WARNING(ShaderWarning::UNUSED_UNIFORM_FLAG) && used_uniforms.has(p_identifier)) {
+ used_uniforms[p_identifier].used = true;
+ }
+ break;
+ case IdentifierType::IDENTIFIER_FUNCTION:
+ if (HAS_WARNING(ShaderWarning::UNUSED_FUNCTION_FLAG) && used_functions.has(p_identifier)) {
+ used_functions[p_identifier].used = true;
+ }
+ break;
+ default:
+ break;
+ }
+}
+#endif // DEBUG_ENABLED
+
bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name, ConstantNode::Value *r_constant_value) {
if (p_function_info.built_ins.has(p_identifier)) {
if (r_data_type) {
@@ -932,7 +975,6 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_type) {
*r_type = IDENTIFIER_BUILTIN_VAR;
}
-
return true;
}
@@ -946,7 +988,6 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_type) {
*r_type = IDENTIFIER_FUNCTION;
}
-
return true;
}
@@ -963,16 +1004,15 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
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;
}
if (r_constant_value) {
*r_constant_value = p_block->variables[p_identifier].value;
}
-
+ if (r_type) {
+ *r_type = IDENTIFIER_LOCAL_VAR;
+ }
return true;
}
@@ -994,15 +1034,18 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
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;
}
+ if (r_array_size) {
+ *r_array_size = function->arguments[i].array_size;
+ }
if (r_is_const) {
*r_is_const = function->arguments[i].is_const;
}
+ if (r_type) {
+ *r_type = IDENTIFIER_FUNCTION_ARGUMENT;
+ }
return true;
}
}
@@ -1041,9 +1084,6 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_array_size) {
*r_array_size = shader->constants[p_identifier].array_size;
}
- if (r_type) {
- *r_type = IDENTIFIER_CONSTANT;
- }
if (r_struct_name) {
*r_struct_name = shader->constants[p_identifier].type_str;
}
@@ -1052,6 +1092,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
*r_constant_value = shader->constants[p_identifier].initializer->values[0];
}
}
+ if (r_type) {
+ *r_type = IDENTIFIER_CONSTANT;
+ }
return true;
}
@@ -1064,6 +1107,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_data_type) {
*r_data_type = shader->functions[i].function->return_type;
}
+ if (r_array_size) {
+ *r_array_size = shader->functions[i].function->return_array_size;
+ }
if (r_type) {
*r_type = IDENTIFIER_FUNCTION;
}
@@ -1074,13 +1120,18 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
return false;
}
-bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type) {
+bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type, int *r_ret_size) {
bool valid = false;
DataType ret_type = TYPE_VOID;
+ int ret_size = 0;
switch (p_op->op) {
case OP_EQUAL:
case OP_NOT_EQUAL: {
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
valid = na == nb;
@@ -1090,6 +1141,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
case OP_LESS_EQUAL:
case OP_GREATER:
case OP_GREATER_EQUAL: {
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1099,6 +1154,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
} break;
case OP_AND:
case OP_OR: {
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1107,6 +1166,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
} break;
case OP_NOT: {
+ if (!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
valid = na == TYPE_BOOL;
ret_type = TYPE_BOOL;
@@ -1117,6 +1180,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
case OP_POST_INCREMENT:
case OP_POST_DECREMENT:
case OP_NEGATE: {
+ if (!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
valid = na > TYPE_BOOL && na < TYPE_MAT2;
ret_type = na;
@@ -1125,6 +1192,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
case OP_SUB:
case OP_MUL:
case OP_DIV: {
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1193,6 +1264,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
* component-wise.
*/
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1245,6 +1320,10 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
case OP_ASSIGN_SHIFT_RIGHT:
case OP_SHIFT_LEFT:
case OP_SHIFT_RIGHT: {
+ if ((!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) || (!p_op->arguments[1]->is_indexed() && p_op->arguments[1]->get_array_size() > 0)) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1293,6 +1372,18 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
}
} break;
case OP_ASSIGN: {
+ int sa = 0;
+ int sb = 0;
+ if (!p_op->arguments[0]->is_indexed()) {
+ sa = p_op->arguments[0]->get_array_size();
+ }
+ if (!p_op->arguments[1]->is_indexed()) {
+ sb = p_op->arguments[1]->get_array_size();
+ }
+ if (sa != sb) {
+ break; // don't accept arrays if their sizes are not equal
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
if (na == TYPE_STRUCT || nb == TYPE_STRUCT) {
@@ -1301,11 +1392,24 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
valid = na == nb;
}
ret_type = na;
+ ret_size = sa;
} break;
case OP_ASSIGN_ADD:
case OP_ASSIGN_SUB:
case OP_ASSIGN_MUL:
case OP_ASSIGN_DIV: {
+ int sa = 0;
+ int sb = 0;
+ if (!p_op->arguments[0]->is_indexed()) {
+ sa = p_op->arguments[0]->get_array_size();
+ }
+ if (!p_op->arguments[1]->is_indexed()) {
+ sb = p_op->arguments[1]->get_array_size();
+ }
+ if (sa > 0 || sb > 0) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1373,6 +1477,18 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
* must match.
*/
+ int sa = 0;
+ int sb = 0;
+ if (!p_op->arguments[0]->is_indexed()) {
+ sa = p_op->arguments[0]->get_array_size();
+ }
+ if (!p_op->arguments[1]->is_indexed()) {
+ sb = p_op->arguments[1]->get_array_size();
+ }
+ if (sa > 0 || sb > 0) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype();
@@ -1427,17 +1543,34 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
}
} break;
case OP_BIT_INVERT: { //unaries
+ if (!p_op->arguments[0]->is_indexed() && p_op->arguments[0]->get_array_size() > 0) {
+ break; // don't accept arrays
+ }
+
DataType na = p_op->arguments[0]->get_datatype();
valid = na >= TYPE_INT && na < TYPE_FLOAT;
ret_type = na;
} break;
case OP_SELECT_IF: {
+ int sa = 0;
+ int sb = 0;
+ if (!p_op->arguments[1]->is_indexed()) {
+ sa = p_op->arguments[1]->get_array_size();
+ }
+ if (!p_op->arguments[2]->is_indexed()) {
+ sb = p_op->arguments[2]->get_array_size();
+ }
+ if (sa != sb) {
+ break; // don't accept arrays if their sizes are not equal
+ }
+
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;
+ ret_size = sa;
} break;
default: {
ERR_FAIL_V(false);
@@ -1447,6 +1580,9 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
if (r_ret_type) {
*r_ret_type = ret_type;
}
+ if (r_ret_size) {
+ *r_ret_size = ret_size;
+ }
return valid;
}
@@ -2182,6 +2318,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
Vector<DataType> args;
Vector<StringName> args2;
+ Vector<int> args3;
ERR_FAIL_COND_V(p_func->arguments[0]->type != Node::TYPE_VARIABLE, false);
@@ -2190,6 +2327,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
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());
+ args3.push_back(p_func->arguments[i]->get_array_size());
}
int argcount = args.size();
@@ -2457,6 +2595,11 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
} else {
func_arg_name = get_datatype_name(pfunc->arguments[j].type);
}
+ if (pfunc->arguments[j].array_size > 0) {
+ func_arg_name += "[";
+ func_arg_name += itos(pfunc->arguments[j].array_size);
+ func_arg_name += "]";
+ }
arg_list += func_arg_name;
}
}
@@ -2469,21 +2612,32 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
bool fail = false;
for (int j = 0; j < args.size(); j++) {
- 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)) {
+ if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && args3[j] == 0 && 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 || (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str)) {
+ } else if (args[j] != pfunc->arguments[j].type || (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str) || args3[j] != pfunc->arguments[j].array_size) {
String func_arg_name;
if (pfunc->arguments[j].type == TYPE_STRUCT) {
func_arg_name = pfunc->arguments[j].type_str;
} else {
func_arg_name = get_datatype_name(pfunc->arguments[j].type);
}
+ if (pfunc->arguments[j].array_size > 0) {
+ func_arg_name += "[";
+ func_arg_name += itos(pfunc->arguments[j].array_size);
+ func_arg_name += "]";
+ }
String arg_name;
if (args[j] == TYPE_STRUCT) {
arg_name = args2[j];
} else {
arg_name = get_datatype_name(args[j]);
}
+ if (args3[j] > 0) {
+ arg_name += "[";
+ arg_name += itos(args3[j]);
+ arg_name += "]";
+ }
+
_set_error(vformat("Invalid argument for \"%s(%s)\" function: argument %s should be %s but is %s.", String(name), arg_list, j + 1, func_arg_name, arg_name));
fail = true;
break;
@@ -2529,16 +2683,45 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
return false;
}
-bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) const {
- if (a->get_datatype() != b->get_datatype()) {
- return false;
+bool ShaderLanguage::_compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b) {
+ bool result = true;
+
+ if (p_datatype_a == TYPE_STRUCT || p_datatype_b == TYPE_STRUCT) {
+ if (p_datatype_name_a != p_datatype_name_b) {
+ result = false;
+ }
+ } else {
+ if (p_datatype_a != p_datatype_b) {
+ result = false;
+ }
}
- if (a->get_datatype() == TYPE_STRUCT || b->get_datatype() == TYPE_STRUCT) {
- if (a->get_datatype_name() != b->get_datatype_name()) {
- return false;
+
+ if (p_array_size_a != p_array_size_b) {
+ result = false;
+ }
+
+ if (!result) {
+ String type_name = p_datatype_a == TYPE_STRUCT ? p_datatype_name_a : get_datatype_name(p_datatype_a);
+ if (p_array_size_a > 0) {
+ type_name += "[";
+ type_name += itos(p_array_size_a);
+ type_name += "]";
}
+
+ String type_name2 = p_datatype_b == TYPE_STRUCT ? p_datatype_name_b : get_datatype_name(p_datatype_b);
+ if (p_array_size_b > 0) {
+ type_name2 += "[";
+ type_name2 += itos(p_array_size_b);
+ type_name2 += "]";
+ }
+
+ _set_error("Invalid assignment of '" + type_name2 + "' to '" + type_name + "'");
}
- return true;
+ return result;
+}
+
+bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) {
+ return _compare_datatypes(a->get_datatype(), a->get_datatype_name(), a->get_array_size(), b->get_datatype(), b->get_datatype_name(), b->get_array_size());
}
bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg) {
@@ -2758,7 +2941,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
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));
+ Transform3D t = Transform3D(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real));
value = Variant(t);
break;
}
@@ -2857,7 +3040,7 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
pi.type = Variant::BASIS;
break;
case ShaderLanguage::TYPE_MAT4:
- pi.type = Variant::TRANSFORM;
+ pi.type = Variant::TRANSFORM3D;
break;
case ShaderLanguage::TYPE_SAMPLER2D:
case ShaderLanguage::TYPE_ISAMPLER2D:
@@ -2969,6 +3152,20 @@ void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
}
}
+bool ShaderLanguage::is_control_flow_keyword(String p_keyword) {
+ return p_keyword == "break" ||
+ p_keyword == "case" ||
+ p_keyword == "continue" ||
+ p_keyword == "default" ||
+ p_keyword == "do" ||
+ p_keyword == "else" ||
+ p_keyword == "for" ||
+ p_keyword == "if" ||
+ p_keyword == "return" ||
+ p_keyword == "switch" ||
+ p_keyword == "while";
+}
+
void ShaderLanguage::get_builtin_funcs(List<String> *r_keywords) {
Set<String> kws;
@@ -3168,6 +3365,36 @@ bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, Str
return true;
}
+bool ShaderLanguage::_check_node_constness(const Node *p_node) const {
+ switch (p_node->type) {
+ case Node::TYPE_OPERATOR: {
+ OperatorNode *op_node = (OperatorNode *)p_node;
+ for (int i = int(op_node->op == OP_CALL); i < op_node->arguments.size(); i++) {
+ if (!_check_node_constness(op_node->arguments[i])) {
+ return false;
+ }
+ }
+ } break;
+ case Node::TYPE_CONSTANT:
+ break;
+ case Node::TYPE_VARIABLE: {
+ VariableNode *varn = (VariableNode *)p_node;
+ if (!varn->is_const) {
+ return false;
+ }
+ } break;
+ case Node::TYPE_ARRAY: {
+ ArrayNode *arrn = (ArrayNode *)p_node;
+ if (!arrn->is_const) {
+ return false;
+ }
+ } break;
+ default:
+ return false;
+ }
+ return true;
+}
+
bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message) {
if (p_node->type == Node::TYPE_OPERATOR) {
OperatorNode *op = static_cast<OperatorNode *>(p_node);
@@ -3305,11 +3532,12 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
ERR_FAIL_V(false); //bug? function not found
}
-ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size) {
+ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info) {
DataType type = TYPE_VOID;
String struct_name = "";
int array_size = 0;
bool auto_size = false;
+ bool undefined_size = false;
Token tk = _get_token();
if (tk.type == TK_CURLY_BRACKET_OPEN) {
@@ -3330,6 +3558,137 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
TkPos pos = _get_tkpos();
tk = _get_token();
if (tk.type == TK_BRACKET_CLOSE) {
+ undefined_size = true;
+ tk = _get_token();
+ } else {
+ _set_tkpos(pos);
+
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ 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_size = cnode->values[0].sint;
+ if (array_size <= 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;
+ }
+ }
+
+ ArrayConstructNode *an = alloc_node<ArrayConstructNode>();
+
+ if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization
+ int idx = 0;
+ while (true) {
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ if (!n) {
+ return nullptr;
+ }
+
+ // define type by using the first member
+ if (auto_size && idx == 0) {
+ type = n->get_datatype();
+ if (type == TYPE_STRUCT) {
+ struct_name = n->get_datatype_name();
+ }
+ } else {
+ if (!_compare_datatypes(type, struct_name, 0, n->get_datatype(), n->get_datatype_name(), 0)) {
+ return nullptr;
+ }
+ }
+
+ tk = _get_token();
+ if (tk.type == TK_COMMA) {
+ an->initializer.push_back(n);
+ } 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;
+ }
+ idx++;
+ }
+ if (!auto_size && !undefined_size && an->initializer.size() != array_size) {
+ _set_error("Array size mismatch");
+ return nullptr;
+ }
+ } else {
+ _set_error("Expected array initialization!");
+ return nullptr;
+ }
+
+ an->datatype = type;
+ an->struct_name = struct_name;
+ return an;
+}
+
+ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size) {
+ DataType type = TYPE_VOID;
+ String struct_name = "";
+ int array_size = 0;
+ bool auto_size = false;
+ TkPos prev_pos = _get_tkpos();
+ Token tk = _get_token();
+
+ if (tk.type == TK_CURLY_BRACKET_OPEN) {
+ auto_size = true;
+ } else {
+ if (shader->structs.has(tk.text)) {
+ type = TYPE_STRUCT;
+ struct_name = tk.text;
+ } else {
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_tkpos(prev_pos);
+
+ pass_array = true;
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ pass_array = false;
+
+ if (!n) {
+ _set_error("Invalid data type for array");
+ return nullptr;
+ }
+
+ if (!_compare_datatypes(p_type, p_struct_name, p_array_size, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) {
+ return nullptr;
+ }
+ return n;
+ }
+ type = get_token_datatype(tk.type);
+ }
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ TkPos pos = _get_tkpos();
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
array_size = p_array_size;
tk = _get_token();
} else {
@@ -3401,8 +3760,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
return nullptr;
}
- if (p_type != n->get_datatype() || p_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)) + "'");
+ if (!_compare_datatypes(p_type, p_struct_name, 0, n->get_datatype(), n->get_datatype_name(), 0)) {
return nullptr;
}
@@ -3502,50 +3860,73 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//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
+ } else if (is_token_nonvoid_datatype(tk.type) || tk.type == TK_CURLY_BRACKET_OPEN) {
+ if (tk.type == TK_CURLY_BRACKET_OPEN) {
+ //array constructor
- OperatorNode *func = alloc_node<OperatorNode>();
- func->op = OP_CONSTRUCT;
+ _set_tkpos(prepos);
+ expr = _parse_array_constructor(p_block, p_function_info);
+ } else {
+ DataType datatype;
+ DataPrecision precision;
+ bool precision_defined = false;
- if (is_token_precision(tk.type)) {
- func->return_precision_cache = get_token_precision(tk.type);
+ if (is_token_precision(tk.type)) {
+ precision = get_token_precision(tk.type);
+ precision_defined = true;
+ tk = _get_token();
+ }
+
+ datatype = get_token_datatype(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);
+ if (tk.type == TK_BRACKET_OPEN) {
+ //array constructor
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after type name");
- return nullptr;
- }
+ _set_tkpos(prepos);
+ expr = _parse_array_constructor(p_block, p_function_info);
+ } else {
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '(' after type name");
+ return nullptr;
+ }
+ //basic type constructor
- int carg = -1;
+ OperatorNode *func = alloc_node<OperatorNode>();
+ func->op = OP_CONSTRUCT;
- bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg);
+ if (precision_defined) {
+ func->return_precision_cache = precision;
+ }
- if (carg >= 0) {
- completion_type = COMPLETION_CALL_ARGUMENTS;
- completion_line = tk_line;
- completion_block = p_block;
- completion_function = funcname->name;
- completion_argument = carg;
- }
+ VariableNode *funcname = alloc_node<VariableNode>();
+ funcname->name = get_datatype_name(datatype);
+ func->arguments.push_back(funcname);
- if (!ok) {
- return nullptr;
- }
+ int carg = -1;
- if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) {
- _set_error("No matching constructor found for: '" + String(funcname->name) + "'");
- return nullptr;
- }
+ bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg);
- expr = _reduce_expression(p_block, func);
+ 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_function_info, 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);
@@ -3558,6 +3939,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (shader->structs.has(identifier)) {
pstruct = shader->structs[identifier].shader_struct;
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_STRUCT_FLAG) && used_structs.has(identifier)) {
+ used_structs[identifier].used = true;
+ }
+#endif // DEBUG_ENABLED
struct_init = true;
}
@@ -3588,11 +3974,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
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;
}
}
@@ -3614,7 +3996,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expr = func;
- } else { //a function
+ } else { //a function call
const StringName &name = identifier;
@@ -3626,7 +4008,9 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
int carg = -1;
+ pass_array = true;
bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg);
+ pass_array = false;
// Check if block has a variable with the same name as function to prevent shader crash.
ShaderLanguage::BlockNode *bnode = p_block;
@@ -3679,6 +4063,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
FunctionNode *call_function = shader->functions[function_index].function;
if (call_function) {
+ func->return_cache = call_function->get_datatype();
+ func->struct_name = call_function->get_datatype_name();
+ func->return_array_size = call_function->get_array_size();
+
//get current base function
FunctionNode *base_function = nullptr;
{
@@ -3781,11 +4169,17 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
}
expr = func;
+#ifdef DEBUG_ENABLED
+ if (check_warnings) {
+ _parse_used_identifier(name, IdentifierType::IDENTIFIER_FUNCTION);
+ }
+#endif // DEBUG_ENABLED
}
} else {
//an identifier
- last_const = false;
+ last_name = identifier;
+ last_type = IDENTIFIER_MAX;
_set_tkpos(pos);
DataType data_type;
@@ -3830,12 +4224,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
}
}
- last_const = is_const;
if (ident_type == IDENTIFIER_FUNCTION) {
_set_error("Can't use function as identifier: " + String(identifier));
return nullptr;
}
+ if (is_const) {
+ last_type = IDENTIFIER_CONSTANT;
+ } else {
+ last_type = ident_type;
+ }
}
Node *index_expression = nullptr;
@@ -3843,60 +4241,61 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
Node *assign_expression = nullptr;
if (array_size > 0) {
- tk = _get_token();
-
- if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD && tk.type != TK_OP_ASSIGN) {
- _set_error("Expected '[','.' or '='");
- return nullptr;
- }
+ if (!pass_array) {
+ tk = _get_token();
- if (tk.type == TK_OP_ASSIGN) {
- if (is_const) {
- _set_error("Constants cannot be modified.");
+ if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD && tk.type != TK_OP_ASSIGN) {
+ _set_error("Expected '[','.' or '='");
return nullptr;
}
- assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size);
- if (!assign_expression) {
- return nullptr;
- }
- } else 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_function_info);
- 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_function_info);
- if (!index_expression) {
- return nullptr;
- }
+ if (tk.type == TK_OP_ASSIGN) {
+ if (is_const) {
+ _set_error("Constants cannot be modified.");
+ return nullptr;
+ }
+ assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size);
+ if (!assign_expression) {
+ return nullptr;
+ }
+ } else 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_function_info);
+ 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_function_info);
+ 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->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.is_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;
+ if (index_expression->type == Node::TYPE_CONSTANT) {
+ ConstantNode *cnode = (ConstantNode *)index_expression;
+ if (cnode) {
+ if (!cnode->values.is_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;
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return nullptr;
+ }
}
}
@@ -3908,8 +4307,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
arrname->call_expression = call_expression;
arrname->assign_expression = assign_expression;
arrname->is_const = is_const;
+ arrname->array_size = array_size;
expr = arrname;
-
} else {
VariableNode *varname = alloc_node<VariableNode>();
varname->name = identifier;
@@ -3918,6 +4317,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
varname->struct_name = struct_name;
expr = varname;
}
+#ifdef DEBUG_ENABLED
+ if (check_warnings) {
+ _parse_used_identifier(identifier, ident_type);
+ }
+#endif // DEBUG_ENABLED
}
} else if (tk.type == TK_OP_ADD) {
continue; //this one does nothing
@@ -3956,8 +4360,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
ERR_FAIL_COND_V(!expr, nullptr);
/* OK now see what's NEXT to the operator.. */
- /* OK now see what's NEXT to the operator.. */
- /* OK now see what's NEXT to the operator.. */
while (true) {
TkPos pos2 = _get_tkpos();
@@ -3970,6 +4372,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
DataType dt = expr->get_datatype();
String st = expr->get_datatype_name();
+ if (!expr->is_indexed() && expr->get_array_size() > 0) {
+ completion_class = TAG_ARRAY;
+ p_block->block_tag = SubClassTag::TAG_ARRAY;
+ Node *call_expression = _parse_and_reduce_expression(p_block, p_function_info);
+ p_block->block_tag = SubClassTag::TAG_GLOBAL;
+ if (!call_expression) {
+ return nullptr;
+ }
+ expr = call_expression;
+ break;
+ }
+
StringName identifier;
if (_get_completable_identifier(p_block, dt == TYPE_STRUCT ? COMPLETION_STRUCT : COMPLETION_INDEX, identifier)) {
if (dt == TYPE_STRUCT) {
@@ -4246,10 +4660,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
mn->has_swizzling_duplicates = repeated;
if (array_size > 0) {
+ TkPos prev_pos = _get_tkpos();
tk = _get_token();
if (tk.type == TK_OP_ASSIGN) {
- if (last_const) {
- last_const = false;
+ if (last_type == IDENTIFIER_CONSTANT) {
_set_error("Constants cannot be modified.");
return nullptr;
}
@@ -4259,8 +4673,15 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
mn->assign_expression = assign_expression;
} else if (tk.type == TK_PERIOD) {
- _set_error("Nested array length() is not yet implemented");
- return nullptr;
+ completion_class = TAG_ARRAY;
+ p_block->block_tag = SubClassTag::TAG_ARRAY;
+ Node *call_expression = _parse_and_reduce_expression(p_block, p_function_info);
+ p_block->block_tag = SubClassTag::TAG_GLOBAL;
+ if (!call_expression) {
+ return nullptr;
+ }
+ mn->datatype = call_expression->get_datatype();
+ mn->call_expression = call_expression;
} else if (tk.type == TK_BRACKET_OPEN) {
Node *index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
@@ -4291,13 +4712,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
mn->index_expression = index_expression;
-
} else {
- _set_error("Expected '[','.' or '='");
- return nullptr;
+ if (!pass_array) {
+ _set_error("Expected '[','.' or '='");
+ return nullptr;
+ }
+ _set_tkpos(prev_pos);
}
}
-
expr = mn;
//todo
@@ -4322,117 +4744,130 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
DataType member_type = TYPE_VOID;
+ String member_struct_name;
- 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;
+ if (expr->get_array_size() > 0) {
+ uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+ if (index_constant >= (uint32_t)expr->get_array_size()) {
+ _set_error(vformat("Index [%s] out of range [%s..%s]", index_constant, 0, expr->get_array_size() - 1));
+ return nullptr;
+ }
+ member_type = expr->get_datatype();
+ if (member_type == TYPE_STRUCT) {
+ member_struct_name = expr->get_datatype_name();
+ }
+ } else {
+ 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;
- }
+ 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;
+ 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_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;
+ 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;
}
- 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->struct_name = member_struct_name;
op->arguments.push_back(expr);
op->arguments.push_back(index);
expr = op;
@@ -4448,7 +4883,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
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)) {
+ if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
_set_error("Invalid base type for increment/decrement operator");
return nullptr;
}
@@ -4599,9 +5034,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
bool unary = false;
bool ternary = false;
+ Operator op = expression[i].op;
int priority;
- switch (expression[i].op) {
+ switch (op) {
case OP_EQUAL:
priority = 8;
break;
@@ -4722,6 +5158,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
ERR_FAIL_V(nullptr); //unexpected operator
}
+#if DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::FLOAT_COMPARISON_FLAG) && (op == OP_EQUAL || op == OP_NOT_EQUAL) && expression[i - 1].node->get_datatype() == TYPE_FLOAT && expression[i + 1].node->get_datatype() == TYPE_FLOAT) {
+ _add_line_warning(ShaderWarning::FLOAT_COMPARISON);
+ }
+#endif // DEBUG_ENABLED
+
if (priority < min_priority) {
// < is used for left to right (default)
// <= is used for right to left
@@ -4735,7 +5177,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
ERR_FAIL_COND_V(next_op == -1, nullptr);
// OK! create operator..
- // OK! create operator..
if (is_unary) {
int expr_pos = next_op;
while (expression[expr_pos].is_op) {
@@ -4760,13 +5201,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.write[i].is_op = false;
expression.write[i].node = op;
- if (!_validate_operator(op, &op->return_cache)) {
+ if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
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());
+ if (!op->arguments[j]->is_indexed() && op->arguments[j]->get_array_size() > 0) {
+ at += "[";
+ at += itos(op->arguments[j]->get_array_size());
+ at += "]";
+ }
}
_set_error("Invalid arguments to unary operator '" + get_operator_text(op->op) + "' :" + at);
return nullptr;
@@ -4793,13 +5239,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.write[next_op - 1].is_op = false;
expression.write[next_op - 1].node = op;
- if (!_validate_operator(op, &op->return_cache)) {
+ if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
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());
+ if (!op->arguments[i]->is_indexed() && op->arguments[i]->get_array_size() > 0) {
+ at += "[";
+ at += itos(op->arguments[i]->get_array_size());
+ at += "]";
+ }
}
_set_error("Invalid argument to ternary ?: operator: " + at);
return nullptr;
@@ -4846,7 +5297,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//replace all 3 nodes by this operator and make it an expression
- if (!_validate_operator(op, &op->return_cache)) {
+ if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
String at;
for (int i = 0; i < op->arguments.size(); i++) {
if (i > 0) {
@@ -4857,6 +5308,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else {
at += get_datatype_name(op->arguments[i]->get_datatype());
}
+ if (!op->arguments[i]->is_indexed() && op->arguments[i]->get_array_size() > 0) {
+ at += "[";
+ at += itos(op->arguments[i]->get_array_size());
+ at += "]";
+ }
}
_set_error("Invalid arguments to operator '" + get_operator_text(op->op) + "' :" + at);
return nullptr;
@@ -5113,6 +5569,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
ArrayDeclarationNode::Declaration decl;
decl.name = name;
decl.size = 0U;
+ decl.single_expression = false;
pos = _get_tkpos();
tk = _get_token();
@@ -5179,179 +5636,205 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
+ TkPos prev_pos = _get_tkpos();
tk = _get_token();
- if (tk.type != TK_CURLY_BRACKET_OPEN) {
- if (unknown_size) {
- _set_error("Expected '{'");
- return ERR_PARSE_ERROR;
- }
-
- full_def = true;
+ if (tk.type == TK_IDENTIFIER) { // a function call array initialization
+ _set_tkpos(prev_pos);
+ pass_array = true;
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ pass_array = false;
- 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 (!n) {
+ _set_error("Expected correct array initializer!");
+ return ERR_PARSE_ERROR;
+ } else {
+ if (unknown_size) {
+ decl.size = n->get_array_size();
+ var.array_size = n->get_array_size();
}
- if (!is_token_nonvoid_datatype(tk.type)) {
- _set_error("Expected datatype after precision");
+
+ if (!_compare_datatypes(var.type, var.struct_name, var.array_size, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) {
return ERR_PARSE_ERROR;
}
- }
- DataType type2;
- StringName struct_name2 = "";
+ decl.single_expression = true;
+ decl.initializer.push_back(n);
+ }
- 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");
+ tk = _get_token();
+ } else {
+ if (tk.type != TK_CURLY_BRACKET_OPEN) {
+ if (unknown_size) {
+ _set_error("Expected '{'");
return ERR_PARSE_ERROR;
}
- type2 = get_token_datatype(tk.type);
- }
- int array_size2 = 0;
+ full_def = true;
- 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;
+ DataPrecision precision2 = PRECISION_DEFAULT;
+ if (is_token_precision(tk.type)) {
+ precision2 = get_token_precision(tk.type);
tk = _get_token();
- } else {
- _set_tkpos(pos2);
-
- Node *n = _parse_and_reduce_expression(p_block, p_function_info);
- if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
- _set_error("Expected single integer constant > 0");
+ 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;
+ }
+ }
- 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");
+ DataType type2;
+ StringName 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) {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
+ 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_function_info);
+ 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 += " ";
+ _set_error("Expected '['");
+ return ERR_PARSE_ERROR;
}
- if (type == TYPE_STRUCT) {
- error_str += struct_name;
- } else {
- error_str += get_datatype_name(type);
+
+ 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;
}
- 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;
+ 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 '('");
+ 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_function_info);
- if (!n) {
- return ERR_PARSE_ERROR;
- }
+ if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
+ while (true) {
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ 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 (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;
- }
+ if (!_compare_datatypes(var.type, struct_name, 0, n->get_datatype(), n->get_datatype_name(), 0)) {
+ 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 ','");
+ 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 {
- _set_error("Expected ')' or ','");
+ 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();
}
- 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) {
@@ -5387,8 +5870,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
- _set_error("Expected constant expression after '='");
- return ERR_PARSE_ERROR;
+ OperatorNode *op = ((OperatorNode *)n);
+ for (int i = 1; i < op->arguments.size(); i++) {
+ if (!_check_node_constness(op->arguments[i])) {
+ _set_error("Expected constant expression for argument '" + itos(i - 1) + "' of function call after '='");
+ return ERR_PARSE_ERROR;
+ }
+ }
}
decl.initializer = n;
@@ -5399,8 +5887,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
}
- 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)) + "'");
+ if (!_compare_datatypes(var.type, var.struct_name, var.array_size, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) {
return ERR_PARSE_ERROR;
}
tk = _get_token();
@@ -5430,7 +5917,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
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.");
@@ -5862,6 +6348,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
String return_struct_name = String(b->parent_function->return_struct_name);
+ String array_size_string;
+
+ if (b->parent_function->return_array_size > 0) {
+ array_size_string = "[" + itos(b->parent_function->return_array_size) + "]";
+ }
ControlFlowNode *flow = alloc_node<ControlFlowNode>();
flow->flow_op = FLOW_OP_RETURN;
@@ -5871,18 +6362,21 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (tk.type == TK_SEMICOLON) {
//all is good
if (b->parent_function->return_type != TYPE_VOID) {
- _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'");
+ _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'");
return ERR_PARSE_ERROR;
}
} else {
_set_tkpos(pos); //rollback, wants expression
+
+ pass_array = true;
Node *expr = _parse_and_reduce_expression(p_block, p_function_info);
if (!expr) {
return ERR_PARSE_ERROR;
}
+ pass_array = false;
- if (b->parent_function->return_type != expr->get_datatype() || return_struct_name != expr->get_datatype_name()) {
- _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'");
+ if (b->parent_function->return_type != expr->get_datatype() || b->parent_function->return_array_size != expr->get_array_size() || return_struct_name != expr->get_datatype_name()) {
+ _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'");
return ERR_PARSE_ERROR;
}
@@ -6260,7 +6754,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
shader->structs[st.name] = st;
shader->vstructs.push_back(st); // struct's order is important!
-
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_STRUCT_FLAG)) {
+ used_structs.insert(st.name, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
} break;
case TK_GLOBAL: {
tk = _get_token();
@@ -6607,6 +7105,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
shader->uniforms[name] = uniform2;
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_UNIFORM_FLAG)) {
+ used_uniforms.insert(name, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
+
//reset scope for next uniform
uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
@@ -6650,6 +7154,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
shader->varyings[name] = varying;
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_VARYING_FLAG)) {
+ used_varyings.insert(name, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
}
} break;
@@ -6662,6 +7171,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
DataPrecision precision = PRECISION_DEFAULT;
DataType type;
StringName name;
+ int return_array_size = 0;
if (tk.type == TK_CONST) {
is_constant = true;
@@ -6699,10 +7209,33 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
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;
+ bool error = false;
+ tk = _get_token();
+
+ if (tk.type == TK_INT_CONSTANT) {
+ return_array_size = (int)tk.constant;
+ if (return_array_size > 0) {
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+ if (error) {
+ _set_error("Expected integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+
+ prev_pos = _get_tkpos();
}
+
_set_tkpos(prev_pos);
_get_completable_identifier(nullptr, COMPLETION_MAIN_FUNCTION, name);
@@ -6916,8 +7449,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
- if (constant.type != n->get_datatype() || n->get_datatype_name() != struct_name) {
- _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (is_struct ? String(struct_name) : get_datatype_name(constant.type)) + "'");
+ if (!_compare_datatypes(constant.type, struct_name, 0, n->get_datatype(), n->get_datatype_name(), 0)) {
return ERR_PARSE_ERROR;
}
@@ -6967,14 +7499,18 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) {
- _set_error("Expected constant expression after '='");
- return ERR_PARSE_ERROR;
+ OperatorNode *op = ((OperatorNode *)expr);
+ for (int i = 1; i < op->arguments.size(); i++) {
+ if (!_check_node_constness(op->arguments[i])) {
+ _set_error("Expected constant expression for argument '" + itos(i - 1) + "' of function call after '='");
+ return ERR_PARSE_ERROR;
+ }
+ }
}
constant.initializer = static_cast<ConstantNode *>(expr);
- if (type != expr->get_datatype() || 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 '" + (is_struct ? String(struct_name) : get_datatype_name(type)) + "'");
+ if (!_compare_datatypes(type, struct_name, 0, expr->get_datatype(), expr->get_datatype_name(), 0)) {
return ERR_PARSE_ERROR;
}
}
@@ -6991,6 +7527,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
shader->constants[name] = constant;
shader->vconstants.push_back(constant);
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_CONSTANT_FLAG)) {
+ used_constants.insert(name, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
if (tk.type == TK_COMMA) {
tk = _get_token();
@@ -7049,9 +7590,16 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
func_node->return_type = type;
func_node->return_struct_name = struct_name;
func_node->return_precision = precision;
+ func_node->return_array_size = return_array_size;
if (p_functions.has(name)) {
func_node->can_discard = p_functions[name].can_discard;
+ } else {
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_FUNCTION_FLAG)) {
+ used_functions.insert(name, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
}
func_node->body = alloc_node<BlockNode>();
@@ -7096,6 +7644,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
StringName param_struct_name;
DataPrecision pprecision = PRECISION_DEFAULT;
bool use_precision = false;
+ int array_size = 0;
if (is_token_precision(tk.type)) {
pprecision = get_token_precision(tk.type);
@@ -7142,8 +7691,29 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- _set_error("Arrays as parameters are not implemented yet");
- return ERR_PARSE_ERROR;
+ bool error = false;
+ tk = _get_token();
+
+ if (tk.type == TK_INT_CONSTANT) {
+ array_size = (int)tk.constant;
+
+ if (array_size > 0) {
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+ if (error) {
+ _set_error("Expected integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
}
if (tk.type != TK_IDENTIFIER) {
_set_error("Expected identifier for argument name");
@@ -7177,14 +7747,41 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
arg.tex_argument_repeat = REPEAT_DEFAULT;
arg.is_const = is_const;
- 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 (array_size > 0) {
+ _set_error("Array size is already defined!");
+ return ERR_PARSE_ERROR;
+ }
+ bool error = false;
+ tk = _get_token();
+
+ if (tk.type == TK_INT_CONSTANT) {
+ array_size = (int)tk.constant;
+
+ if (array_size > 0) {
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+
+ if (error) {
+ _set_error("Expected integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
}
+ arg.array_size = array_size;
+ func_node->arguments.push_back(arg);
+
if (tk.type == TK_COMMA) {
tk = _get_token();
//do none and go on
@@ -7385,6 +7982,33 @@ String ShaderLanguage::get_shader_type(const String &p_code) {
return String();
}
+#ifdef DEBUG_ENABLED
+void ShaderLanguage::_check_warning_accums() {
+ for (Map<ShaderWarning::Code, Map<StringName, Usage> *>::Element *E = warnings_check_map.front(); E; E = E->next()) {
+ for (const Map<StringName, Usage>::Element *U = (*E->get()).front(); U; U = U->next()) {
+ if (!U->get().used) {
+ _add_warning(E->key(), U->get().decl_line, U->key());
+ }
+ }
+ }
+}
+List<ShaderWarning>::Element *ShaderLanguage::get_warnings_ptr() {
+ return warnings.front();
+}
+void ShaderLanguage::enable_warning_checking(bool p_enabled) {
+ check_warnings = p_enabled;
+}
+bool ShaderLanguage::is_warning_checking_enabled() const {
+ return check_warnings;
+}
+void ShaderLanguage::set_warning_flags(uint32_t p_flags) {
+ warning_flags = p_flags;
+}
+uint32_t ShaderLanguage::get_warning_flags() const {
+ return warning_flags;
+}
+#endif // DEBUG_ENABLED
+
Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) {
clear();
@@ -7397,6 +8021,12 @@ Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Functi
shader = alloc_node<ShaderNode>();
Error err = _parse_shader(p_functions, p_render_modes, p_shader_types);
+#ifdef DEBUG_ENABLED
+ if (check_warnings) {
+ _check_warning_accums();
+ }
+#endif // DEBUG_ENABLED
+
if (err != OK) {
return err;
}
@@ -7574,6 +8204,13 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
String calltip;
calltip += get_datatype_name(shader->functions[i].function->return_type);
+
+ if (shader->functions[i].function->return_array_size > 0) {
+ calltip += "[";
+ calltip += itos(shader->functions[i].function->return_array_size);
+ calltip += "]";
+ }
+
calltip += " ";
calltip += shader->functions[i].name;
calltip += "(";
@@ -7605,6 +8242,12 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
calltip += " ";
calltip += shader->functions[i].function->arguments[j].name;
+ if (shader->functions[i].function->arguments[j].array_size > 0) {
+ calltip += "[";
+ calltip += itos(shader->functions[i].function->arguments[j].array_size);
+ calltip += "]";
+ }
+
if (j == completion_argument) {
calltip += char32_t(0xFFFF);
}
@@ -7806,6 +8449,14 @@ ShaderLanguage::ShaderNode *ShaderLanguage::get_shader() {
ShaderLanguage::ShaderLanguage() {
nodes = nullptr;
completion_class = TAG_GLOBAL;
+
+#if DEBUG_ENABLED
+ warnings_check_map.insert(ShaderWarning::UNUSED_CONSTANT, &used_constants);
+ warnings_check_map.insert(ShaderWarning::UNUSED_FUNCTION, &used_functions);
+ warnings_check_map.insert(ShaderWarning::UNUSED_STRUCT, &used_structs);
+ warnings_check_map.insert(ShaderWarning::UNUSED_UNIFORM, &used_uniforms);
+ warnings_check_map.insert(ShaderWarning::UNUSED_VARYING, &used_varyings);
+#endif // DEBUG_ENABLED
}
ShaderLanguage::~ShaderLanguage() {
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 03327f9677..4120e04ee1 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -39,6 +39,10 @@
#include "core/typedefs.h"
#include "core/variant/variant.h"
+#ifdef DEBUG_ENABLED
+#include "shader_warnings.h"
+#endif // DEBUG_ENABLED
+
class ShaderLanguage {
public:
struct TkPos {
@@ -365,6 +369,8 @@ public:
virtual DataType get_datatype() const { return TYPE_VOID; }
virtual String get_datatype_name() const { return ""; }
+ virtual int get_array_size() const { return 0; }
+ virtual bool is_indexed() const { return false; }
Node(Type t) :
type(t) {}
@@ -384,11 +390,15 @@ public:
struct OperatorNode : public Node {
DataType return_cache = TYPE_VOID;
DataPrecision return_precision_cache = PRECISION_DEFAULT;
+ int return_array_size = 0;
Operator op = OP_EQUAL;
StringName struct_name;
Vector<Node *> arguments;
- virtual DataType get_datatype() const { return return_cache; }
- virtual String get_datatype_name() const { return String(struct_name); }
+
+ virtual DataType get_datatype() const override { return return_cache; }
+ virtual String get_datatype_name() const override { return String(struct_name); }
+ virtual int get_array_size() const override { return return_array_size; }
+ virtual bool is_indexed() const override { return op == OP_INDEX; }
OperatorNode() :
Node(TYPE_OPERATOR) {}
@@ -398,10 +408,11 @@ public:
DataType datatype_cache = TYPE_VOID;
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 = false;
+ virtual DataType get_datatype() const override { return datatype_cache; }
+ virtual String get_datatype_name() const override { return String(struct_name); }
+
VariableNode() :
Node(TYPE_VARIABLE) {}
};
@@ -416,9 +427,9 @@ public:
StringName name;
Node *initializer;
};
-
Vector<Declaration> declarations;
- virtual DataType get_datatype() const { return datatype; }
+
+ virtual DataType get_datatype() const override { return datatype; }
VariableDeclarationNode() :
Node(TYPE_VARIABLE_DECLARATION) {}
@@ -432,9 +443,12 @@ public:
Node *call_expression = nullptr;
Node *assign_expression = nullptr;
bool is_const = false;
+ int array_size = 0;
- virtual DataType get_datatype() const { return datatype_cache; }
- virtual String get_datatype_name() const { return String(struct_name); }
+ virtual DataType get_datatype() const override { return datatype_cache; }
+ virtual String get_datatype_name() const override { return String(struct_name); }
+ virtual int get_array_size() const override { return (index_expression || call_expression) ? 0 : array_size; }
+ virtual bool is_indexed() const override { return index_expression != nullptr; }
ArrayNode() :
Node(TYPE_ARRAY) {}
@@ -445,6 +459,10 @@ public:
String struct_name;
Vector<Node *> initializer;
+ virtual DataType get_datatype() const override { return datatype; }
+ virtual String get_datatype_name() const override { return struct_name; }
+ virtual int get_array_size() const override { return initializer.size(); }
+
ArrayConstructNode() :
Node(TYPE_ARRAY_CONSTRUCT) {}
};
@@ -460,10 +478,11 @@ public:
StringName name;
uint32_t size;
Vector<Node *> initializer;
+ bool single_expression;
};
-
Vector<Declaration> declarations;
- virtual DataType get_datatype() const { return datatype; }
+
+ virtual DataType get_datatype() const override { return datatype; }
ArrayDeclarationNode() :
Node(TYPE_ARRAY_DECLARATION) {}
@@ -483,8 +502,10 @@ public:
Vector<Value> values;
Vector<ArrayDeclarationNode::Declaration> array_declarations;
- virtual DataType get_datatype() const { return datatype; }
- virtual String get_datatype_name() const { return struct_name; }
+
+ virtual DataType get_datatype() const override { return datatype; }
+ virtual String get_datatype_name() const override { return struct_name; }
+ virtual int get_array_size() const override { return array_size; }
ConstantNode() :
Node(TYPE_CONSTANT) {}
@@ -546,10 +567,13 @@ public:
Node *owner = nullptr;
Node *index_expression = nullptr;
Node *assign_expression = nullptr;
+ Node *call_expression = nullptr;
bool has_swizzling_duplicates = false;
- virtual DataType get_datatype() const { return datatype; }
- virtual String get_datatype_name() const { return String(struct_name); }
+ virtual DataType get_datatype() const override { return datatype; }
+ virtual String get_datatype_name() const override { return String(struct_name); }
+ virtual int get_array_size() const override { return array_size; }
+ virtual bool is_indexed() const override { return index_expression != nullptr || call_expression != nullptr; }
MemberNode() :
Node(TYPE_MEMBER) {}
@@ -575,6 +599,7 @@ public:
bool tex_builtin_check;
StringName tex_builtin;
bool is_const;
+ int array_size;
Map<StringName, Set<int>> tex_argument_connect;
};
@@ -583,10 +608,15 @@ public:
DataType return_type = TYPE_VOID;
StringName return_struct_name;
DataPrecision return_precision = PRECISION_DEFAULT;
+ int return_array_size = 0;
Vector<Argument> arguments;
BlockNode *body = nullptr;
bool can_discard = false;
+ virtual DataType get_datatype() const override { return return_type; }
+ virtual String get_datatype_name() const override { return String(return_struct_name); }
+ virtual int get_array_size() const override { return return_array_size; }
+
FunctionNode() :
Node(TYPE_FUNCTION) {}
};
@@ -748,6 +778,7 @@ public:
static uint32_t get_type_size(DataType p_type);
static void get_keyword_list(List<String> *r_keywords);
+ static bool is_control_flow_keyword(String p_keyword);
static void get_builtin_funcs(List<String> *r_keywords);
struct BuiltInInfo {
@@ -801,12 +832,44 @@ private:
String error_str;
int error_line;
+#ifdef DEBUG_ENABLED
+ struct Usage {
+ int decl_line;
+ bool used = false;
+ Usage(int p_decl_line = -1) {
+ decl_line = p_decl_line;
+ }
+ };
+
+ Map<StringName, Usage> used_constants;
+ Map<StringName, Usage> used_varyings;
+ Map<StringName, Usage> used_uniforms;
+ Map<StringName, Usage> used_functions;
+ Map<StringName, Usage> used_structs;
+ Map<ShaderWarning::Code, Map<StringName, Usage> *> warnings_check_map;
+
+ List<ShaderWarning> warnings;
+
+ bool check_warnings = false;
+ uint32_t warning_flags;
+
+ void _add_line_warning(ShaderWarning::Code p_code, const StringName &p_subject = "") {
+ warnings.push_back(ShaderWarning(p_code, tk_line, p_subject));
+ }
+ void _add_warning(ShaderWarning::Code p_code, int p_line, const StringName &p_subject = "") {
+ warnings.push_back(ShaderWarning(p_code, p_line, p_subject));
+ }
+ void _check_warning_accums();
+#endif // DEBUG_ENABLED
+
String code;
int char_idx;
int tk_line;
StringName current_function;
bool last_const = false;
+ bool pass_array = false;
+ StringName last_name;
VaryingFunctionNames varying_function_names;
@@ -847,12 +910,18 @@ private:
IDENTIFIER_LOCAL_VAR,
IDENTIFIER_BUILTIN_VAR,
IDENTIFIER_CONSTANT,
+ IDENTIFIER_MAX,
};
+ IdentifierType last_type = IDENTIFIER_MAX;
+
bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, 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, ConstantNode::Value *r_constant_value = nullptr);
+#ifdef DEBUG_ENABLED
+ void _parse_used_identifier(const StringName &p_identifier, IdentifierType p_type);
+#endif // DEBUG_ENABLED
bool _is_operator_assign(Operator p_op) const;
bool _validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message = nullptr);
- bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr);
+ bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr, int *r_ret_size = nullptr);
struct BuiltinFuncDef {
enum { MAX_ARGS = 5 };
@@ -883,7 +952,8 @@ private:
static const BuiltinFuncOutArgs builtin_func_out_args[];
Error _validate_datatype(DataType p_type);
- bool _compare_datatypes_in_nodes(Node *a, Node *b) const;
+ bool _compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b);
+ bool _compare_datatypes_in_nodes(Node *a, Node *b);
bool _validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str);
bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr);
@@ -891,8 +961,10 @@ private:
bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin);
bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message);
bool _validate_varying_using(ShaderNode::Varying &p_varying, String *r_message);
+ bool _check_node_constness(const Node *p_node) const;
Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info);
+ Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info);
Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size);
ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);
@@ -907,6 +979,16 @@ private:
Error _find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op);
public:
+#ifdef DEBUG_ENABLED
+ List<ShaderWarning>::Element *get_warnings_ptr();
+
+ void enable_warning_checking(bool p_enabled);
+ bool is_warning_checking_enabled() const;
+
+ void set_warning_flags(uint32_t p_flags);
+ uint32_t get_warning_flags() const;
+#endif // DEBUG_ENABLED
+
//static void get_keyword_list(ShaderType p_type,List<String> *p_keywords);
void clear();
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 460fd5fc97..c4e7511374 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "shader_types.h"
+#include "core/math/math_defs.h"
const Map<StringName, ShaderLanguage::FunctionInfo> &ShaderTypes::get_functions(RS::ShaderMode p_mode) {
return shader_modes[p_mode].functions;
@@ -54,6 +55,9 @@ ShaderTypes::ShaderTypes() {
/*************** SPATIAL ***********************/
shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["E"] = 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;
@@ -88,6 +92,10 @@ ShaderTypes::ShaderTypes() {
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["vertex"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
+
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);
@@ -120,13 +128,17 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO_LIGHT_AFFECT"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_ROUGHNESS_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["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_ROUGHNESS_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
+
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);
@@ -200,7 +212,6 @@ ShaderTypes::ShaderTypes() {
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");
@@ -219,6 +230,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].modes.push_back("shadow_to_opacity");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("vertex_lighting");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("particle_trails");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage_and_one");
@@ -226,6 +238,9 @@ ShaderTypes::ShaderTypes() {
/************ CANVAS ITEM **************************/
shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["E"] = 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;
@@ -316,6 +331,9 @@ ShaderTypes::ShaderTypes() {
/************ PARTICLES **************************/
shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
@@ -327,7 +345,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL);
@@ -380,6 +398,9 @@ ShaderTypes::ShaderTypes() {
/************ SKY **************************/
shader_modes[RS::SHADER_SKY].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["E"] = 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);
diff --git a/servers/rendering/shader_warnings.cpp b/servers/rendering/shader_warnings.cpp
new file mode 100644
index 0000000000..aa11b4e397
--- /dev/null
+++ b/servers/rendering/shader_warnings.cpp
@@ -0,0 +1,131 @@
+/*************************************************************************/
+/* shader_warnings.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "shader_warnings.h"
+#include "core/variant/variant.h"
+
+#ifdef DEBUG_ENABLED
+
+ShaderWarning::Code ShaderWarning::get_code() const {
+ return code;
+}
+
+int ShaderWarning::get_line() const {
+ return line;
+}
+
+const StringName &ShaderWarning::get_subject() const {
+ return subject;
+}
+
+String ShaderWarning::get_message() const {
+ switch (code) {
+ case FLOAT_COMPARISON:
+ return vformat("Direct floating-point comparison (this may not evaluate to `true` as you expect). Instead, use `abs(a - b) < 0.0001` for an approximate but predictable comparison.");
+ case UNUSED_CONSTANT:
+ return vformat("The const '%s' is declared but never used.", subject);
+ case UNUSED_FUNCTION:
+ return vformat("The function '%s' is declared but never used.", subject);
+ case UNUSED_STRUCT:
+ return vformat("The struct '%s' is declared but never used.", subject);
+ case UNUSED_UNIFORM:
+ return vformat("The uniform '%s' is declared but never used.", subject);
+ case UNUSED_VARYING:
+ return vformat("The varying '%s' is declared but never used.", subject);
+ default:
+ break;
+ }
+ return String();
+}
+
+String ShaderWarning::get_name() const {
+ return get_name_from_code(code);
+}
+
+String ShaderWarning::get_name_from_code(Code p_code) {
+ ERR_FAIL_INDEX_V(p_code, WARNING_MAX, String());
+
+ static const char *names[] = {
+ "FLOAT_COMPARISON",
+ "UNUSED_CONSTANT",
+ "UNUSED_FUNCTION",
+ "UNUSED_STRUCT",
+ "UNUSED_UNIFORM",
+ "UNUSED_VARYING",
+ };
+
+ static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
+
+ return names[(int)p_code];
+}
+
+ShaderWarning::Code ShaderWarning::get_code_from_name(const String &p_name) {
+ for (int i = 0; i < WARNING_MAX; i++) {
+ if (get_name_from_code((Code)i) == p_name) {
+ return (Code)i;
+ }
+ }
+
+ ERR_FAIL_V_MSG(WARNING_MAX, "Invalid shader warning name: " + p_name);
+}
+
+static Map<int, uint32_t> *code_to_flags_map = nullptr;
+
+static void init_code_to_flags_map() {
+ code_to_flags_map = memnew((Map<int, uint32_t>));
+ code_to_flags_map->insert(ShaderWarning::FLOAT_COMPARISON, ShaderWarning::FLOAT_COMPARISON_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_CONSTANT, ShaderWarning::UNUSED_CONSTANT_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_FUNCTION, ShaderWarning::UNUSED_FUNCTION_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_STRUCT, ShaderWarning::UNUSED_STRUCT_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_UNIFORM, ShaderWarning::UNUSED_UNIFORM_FLAG);
+ code_to_flags_map->insert(ShaderWarning::UNUSED_VARYING, ShaderWarning::UNUSED_VARYING_FLAG);
+}
+
+ShaderWarning::CodeFlags ShaderWarning::get_flags_from_codemap(const Map<Code, bool> &p_map) {
+ uint32_t result = 0U;
+
+ if (code_to_flags_map == nullptr) {
+ init_code_to_flags_map();
+ }
+
+ for (Map<Code, bool>::Element *E = p_map.front(); E; E = E->next()) {
+ if (E->get()) {
+ ERR_FAIL_COND_V(!code_to_flags_map->has((int)E->key()), ShaderWarning::NONE_FLAG);
+ result |= (*code_to_flags_map)[(int)E->key()];
+ }
+ }
+ return (CodeFlags)result;
+}
+
+ShaderWarning::ShaderWarning(Code p_code, int p_line, const StringName &p_subject) :
+ code(p_code), line(p_line), subject(p_subject) {
+}
+
+#endif // DEBUG_ENABLED
diff --git a/platform/android/audio_driver_jandroid.h b/servers/rendering/shader_warnings.h
index 9007fd2f81..c40aeefa2d 100644
--- a/platform/android/audio_driver_jandroid.h
+++ b/servers/rendering/shader_warnings.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* audio_driver_jandroid.h */
+/* shader_warnings.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,51 +28,56 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef AUDIO_DRIVER_ANDROID_H
-#define AUDIO_DRIVER_ANDROID_H
+#ifndef SHADER_WARNINGS
+#define SHADER_WARNINGS
-#include "servers/audio_server.h"
+#ifdef DEBUG_ENABLED
-#include "java_godot_lib_jni.h"
-
-class AudioDriverAndroid : public AudioDriver {
- static Mutex mutex;
- static AudioDriverAndroid *s_ad;
- static jobject io;
- static jmethodID _init_audio;
- static jmethodID _write_buffer;
- static jmethodID _quit;
- static jmethodID _pause;
- static bool active;
- static bool quit;
-
- static jclass cls;
-
- static jobject audioBuffer;
- static void *audioBufferPinned;
- static int32_t *audioBuffer32;
- static int audioBufferFrames;
- static int mix_rate;
+#include "core/string/string_name.h"
+#include "core/templates/list.h"
+#include "core/templates/map.h"
+class ShaderWarning {
public:
- void set_singleton();
+ enum Code {
+ FLOAT_COMPARISON,
+ UNUSED_CONSTANT,
+ UNUSED_FUNCTION,
+ UNUSED_STRUCT,
+ UNUSED_UNIFORM,
+ UNUSED_VARYING,
+ WARNING_MAX,
+ };
- virtual const char *get_name() const;
+ enum CodeFlags : uint32_t {
+ NONE_FLAG = 0U,
+ FLOAT_COMPARISON_FLAG = 1U,
+ UNUSED_CONSTANT_FLAG = 2U,
+ UNUSED_FUNCTION_FLAG = 4U,
+ UNUSED_STRUCT_FLAG = 8U,
+ UNUSED_UNIFORM_FLAG = 16U,
+ UNUSED_VARYING_FLAG = 32U,
+ };
- virtual Error init();
- virtual void start();
- virtual int get_mix_rate() const;
- virtual SpeakerMode get_speaker_mode() const;
- virtual void lock();
- virtual void unlock();
- virtual void finish();
+private:
+ Code code;
+ int line;
+ StringName subject;
- virtual void set_pause(bool p_pause);
+public:
+ Code get_code() const;
+ int get_line() const;
+ const StringName &get_subject() const;
+ String get_message() const;
+ String get_name() const;
- static void setup(jobject p_io);
- static void thread_func(JNIEnv *env);
+ static String get_name_from_code(Code p_code);
+ static Code get_code_from_name(const String &p_name);
+ static CodeFlags get_flags_from_codemap(const Map<Code, bool> &p_map);
- AudioDriverAndroid();
+ ShaderWarning(Code p_code = WARNING_MAX, int p_line = -1, const StringName &p_subject = "");
};
-#endif // AUDIO_DRIVER_ANDROID_H
+#endif // DEBUG_ENABLED
+
+#endif // SHADER_WARNINGS
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index f8644b5ecb..f25f255321 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -349,7 +349,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
float vector[2] = { src[i].x, src[i].y };
- copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 2);
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 2);
if (i == 0) {
aabb = Rect2(src[i], SMALL_VEC2); //must have a bit of size
@@ -374,7 +374,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
float vector[3] = { src[i].x, src[i].y, src[i].z };
- copymem(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3);
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3);
if (i == 0) {
aabb = AABB(src[i], SMALL_VEC3);
@@ -403,7 +403,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
- copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
}
} break;
@@ -422,9 +422,11 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023);
value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
- value |= CLAMP(int((src[i * 4 + 3] * 0.5 + 0.5) * 3.0), 0, 3) << 30;
+ if (src[i * 4 + 3] > 0) {
+ value |= 3 << 30;
+ }
- copymem(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
}
} break;
@@ -442,7 +444,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
color16[1] = Math::make_half_float(src[i].g);
color16[2] = Math::make_half_float(src[i].b);
color16[3] = Math::make_half_float(src[i].a);
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], color16, 8);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], color16, 8);
}
} break;
case RS::ARRAY_TEX_UV: {
@@ -457,7 +459,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
for (int i = 0; i < p_vertex_array_len; i++) {
float uv[2] = { src[i].x, src[i].y };
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4);
}
} break;
@@ -472,8 +474,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const Vector2 *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) };
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 2);
+ float uv[2] = { src[i].x, src[i].y };
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4);
}
} break;
case RS::ARRAY_CUSTOM0:
@@ -495,7 +497,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const uint8_t *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 4], 4);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 4], 4);
}
} break;
@@ -510,7 +512,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const uint8_t *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 8], 8);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * 8], 8);
}
} break;
case ARRAY_CUSTOM_R_FLOAT:
@@ -528,7 +530,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const float *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- copymem(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s);
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s);
}
} break;
default: {
@@ -554,7 +556,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
data[j] = CLAMP(src[i * bone_count + j] * 65535, 0, 65535);
}
- copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count);
+ memcpy(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count);
}
}
@@ -578,7 +580,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
max_bone = MAX(data[j], max_bone);
}
- copymem(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count);
+ memcpy(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count);
}
} break;
@@ -600,11 +602,11 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
if (p_vertex_array_len < (1 << 16)) {
uint16_t v = src[i];
- copymem(&iw[i * 2], &v, 2);
+ memcpy(&iw[i * 2], &v, 2);
} else {
uint32_t v = src[i];
- copymem(&iw[i * 4], &v, 4);
+ memcpy(&iw[i * 4], &v, 4);
}
}
} break;
@@ -858,8 +860,10 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
case Variant::PACKED_VECTOR2_ARRAY: {
Vector<Vector2> v2 = p_arrays[i];
array_len = v2.size();
+ format |= ARRAY_FLAG_USE_2D_VERTICES;
} break;
case Variant::PACKED_VECTOR3_ARRAY: {
+ ERR_FAIL_COND_V(p_compress_format & ARRAY_FLAG_USE_2D_VERTICES, ERR_INVALID_PARAMETER);
Vector<Vector3> v3 = p_arrays[i];
array_len = v3.size();
} break;
@@ -871,10 +875,10 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
} else if (i == RS::ARRAY_BONES) {
switch (p_arrays[i].get_type()) {
case Variant::PACKED_INT32_ARRAY: {
- Vector<Vector3> vertexes = p_arrays[RS::ARRAY_VERTEX];
+ Vector<Vector3> vertices = p_arrays[RS::ARRAY_VERTEX];
Vector<int32_t> bones = p_arrays[i];
int32_t bone_8_group_count = bones.size() / (ARRAY_WEIGHTS_SIZE * 2);
- int32_t vertex_count = vertexes.size();
+ int32_t vertex_count = vertices.size();
if (vertex_count == bone_8_group_count) {
format |= RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
}
@@ -1172,7 +1176,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
for (int j = 0; j < p_vertex_len; j++) {
const uint8_t *v = (const uint8_t *)&ar[j * attrib_elem_size + offsets[i]];
- copymem(&w[j * s], v, s);
+ memcpy(&w[j * s], v, s);
}
ret[i] = arr;
@@ -1189,7 +1193,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
for (int j = 0; j < p_vertex_len; j++) {
const float *v = (const float *)&ar[j * attrib_elem_size + offsets[i]];
- copymem(&w[j * s], v, s * sizeof(float));
+ memcpy(&w[j * s], v, s * sizeof(float));
}
ret[i] = arr;
@@ -1567,34 +1571,34 @@ void RenderingServer::_bind_methods() {
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
+#warning TODO all voxel_gi 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);
+ ClassDB::bind_method(D_METHOD("voxel_gi_create"), &RenderingServer::voxel_gi_create);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_bounds", "probe", "bounds"), &RenderingServer::voxel_gi_set_bounds);
+ ClassDB::bind_method(D_METHOD("voxel_gi_get_bounds", "probe"), &RenderingServer::voxel_gi_get_bounds);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_cell_size", "probe", "range"), &RenderingServer::voxel_gi_set_cell_size);
+ ClassDB::bind_method(D_METHOD("voxel_gi_get_cell_size", "probe"), &RenderingServer::voxel_gi_get_cell_size);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_to_cell_xform", "probe", "xform"), &RenderingServer::voxel_gi_set_to_cell_xform);
+ ClassDB::bind_method(D_METHOD("voxel_gi_get_to_cell_xform", "probe"), &RenderingServer::voxel_gi_get_to_cell_xform);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_dynamic_data", "probe", "data"), &RenderingServer::voxel_gi_set_dynamic_data);
+ ClassDB::bind_method(D_METHOD("voxel_gi_get_dynamic_data", "probe"), &RenderingServer::voxel_gi_get_dynamic_data);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_dynamic_range", "probe", "range"), &RenderingServer::voxel_gi_set_dynamic_range);
+ ClassDB::bind_method(D_METHOD("voxel_gi_get_dynamic_range", "probe"), &RenderingServer::voxel_gi_get_dynamic_range);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_energy", "probe", "energy"), &RenderingServer::voxel_gi_set_energy);
+ ClassDB::bind_method(D_METHOD("voxel_gi_get_energy", "probe"), &RenderingServer::voxel_gi_get_energy);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_bias", "probe", "bias"), &RenderingServer::voxel_gi_set_bias);
+ ClassDB::bind_method(D_METHOD("voxel_gi_get_bias", "probe"), &RenderingServer::voxel_gi_get_bias);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_normal_bias", "probe", "bias"), &RenderingServer::voxel_gi_set_normal_bias);
+ ClassDB::bind_method(D_METHOD("voxel_gi_get_normal_bias", "probe"), &RenderingServer::voxel_gi_get_normal_bias);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_propagation", "probe", "propagation"), &RenderingServer::voxel_gi_set_propagation);
+ ClassDB::bind_method(D_METHOD("voxel_gi_get_propagation", "probe"), &RenderingServer::voxel_gi_get_propagation);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_interior", "probe", "enable"), &RenderingServer::voxel_gi_set_interior);
+ ClassDB::bind_method(D_METHOD("voxel_gi_is_interior", "probe"), &RenderingServer::voxel_gi_is_interior);
+ ClassDB::bind_method(D_METHOD("voxel_gi_set_compress", "probe", "enable"), &RenderingServer::voxel_gi_set_compress);
+ ClassDB::bind_method(D_METHOD("voxel_gi_is_compressed", "probe"), &RenderingServer::voxel_gi_is_compressed);
#endif
-/*
+ /*
ClassDB::bind_method(D_METHOD("lightmap_create()"), &RenderingServer::lightmap_capture_create);
ClassDB::bind_method(D_METHOD("lightmap_capture_set_bounds", "capture", "bounds"), &RenderingServer::lightmap_capture_set_bounds);
ClassDB::bind_method(D_METHOD("lightmap_capture_get_bounds", "capture"), &RenderingServer::lightmap_capture_get_bounds);
@@ -1607,6 +1611,10 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("lightmap_capture_set_energy", "capture", "energy"), &RenderingServer::lightmap_capture_set_energy);
ClassDB::bind_method(D_METHOD("lightmap_capture_get_energy", "capture"), &RenderingServer::lightmap_capture_get_energy);
*/
+
+ ClassDB::bind_method(D_METHOD("occluder_create"), &RenderingServer::occluder_create);
+ ClassDB::bind_method(D_METHOD("occluder_set_mesh"), &RenderingServer::occluder_set_mesh);
+
#endif
ClassDB::bind_method(D_METHOD("particles_create"), &RenderingServer::particles_create);
ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &RenderingServer::particles_set_emitting);
@@ -1667,6 +1675,9 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &RenderingServer::viewport_set_shadow_atlas_quadrant_subdivision);
ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &RenderingServer::viewport_set_msaa);
ClassDB::bind_method(D_METHOD("viewport_set_use_debanding", "viewport", "enable"), &RenderingServer::viewport_set_use_debanding);
+ ClassDB::bind_method(D_METHOD("viewport_set_use_occlusion_culling", "viewport", "enable"), &RenderingServer::viewport_set_use_occlusion_culling);
+ ClassDB::bind_method(D_METHOD("viewport_set_occlusion_rays_per_thread", "rays_per_thread"), &RenderingServer::viewport_set_occlusion_rays_per_thread);
+ ClassDB::bind_method(D_METHOD("viewport_set_occlusion_culling_build_quality", "quality"), &RenderingServer::viewport_set_occlusion_culling_build_quality);
ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "info"), &RenderingServer::viewport_get_render_info);
ClassDB::bind_method(D_METHOD("viewport_set_debug_draw", "viewport", "draw"), &RenderingServer::viewport_set_debug_draw);
@@ -1694,6 +1705,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("scenario_create"), &RenderingServer::scenario_create);
ClassDB::bind_method(D_METHOD("scenario_set_debug", "scenario", "debug_mode"), &RenderingServer::scenario_set_debug);
ClassDB::bind_method(D_METHOD("scenario_set_environment", "scenario", "environment"), &RenderingServer::scenario_set_environment);
+ ClassDB::bind_method(D_METHOD("scenario_set_camera_effects", "scenario", "effects"), &RenderingServer::scenario_set_camera_effects);
ClassDB::bind_method(D_METHOD("scenario_set_fallback_environment", "scenario", "environment"), &RenderingServer::scenario_set_fallback_environment);
#ifndef _3D_DISABLED
@@ -1713,11 +1725,11 @@ void RenderingServer::_bind_methods() {
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_set_visibility_parent", "instance", "parent"), &RenderingServer::instance_set_visibility_parent);
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("instance_geometry_set_visibility_range", "instance", "min", "max", "min_margin", "max_margin"), &RenderingServer::instance_geometry_set_visibility_range);
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()));
@@ -2012,9 +2024,9 @@ void RenderingServer::_bind_methods() {
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_VOXEL_GI_ALBEDO);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_VOXEL_GI_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);
@@ -2024,6 +2036,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SDFGI);
BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SDFGI_PROBES);
BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_BUFFER);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OCCLUDERS);
BIND_ENUM_CONSTANT(SKY_MODE_QUALITY);
BIND_ENUM_CONSTANT(SKY_MODE_REALTIME);
@@ -2093,6 +2106,10 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(SCENARIO_DEBUG_OVERDRAW);
BIND_ENUM_CONSTANT(SCENARIO_DEBUG_SHADELESS);
+ BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW);
+ BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM);
+ BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH);
+
BIND_ENUM_CONSTANT(INSTANCE_NONE);
BIND_ENUM_CONSTANT(INSTANCE_MESH);
BIND_ENUM_CONSTANT(INSTANCE_MULTIMESH);
@@ -2102,14 +2119,16 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(INSTANCE_LIGHT);
BIND_ENUM_CONSTANT(INSTANCE_REFLECTION_PROBE);
BIND_ENUM_CONSTANT(INSTANCE_DECAL);
- BIND_ENUM_CONSTANT(INSTANCE_GI_PROBE);
+ BIND_ENUM_CONSTANT(INSTANCE_VOXEL_GI);
BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP);
+ BIND_ENUM_CONSTANT(INSTANCE_OCCLUDER);
BIND_ENUM_CONSTANT(INSTANCE_MAX);
BIND_ENUM_CONSTANT(INSTANCE_GEOMETRY_MASK);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_USE_BAKED_LIGHT);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_USE_DYNAMIC_GI);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE);
+ BIND_ENUM_CONSTANT(INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_MAX);
BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF);
@@ -2265,6 +2284,10 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF_RST("rendering/textures/vram_compression/import_etc2", true);
GLOBAL_DEF_RST("rendering/textures/vram_compression/import_pvrtc", false);
+ GLOBAL_DEF("rendering/textures/lossless_compression/force_png", false);
+ GLOBAL_DEF("rendering/textures/lossless_compression/webp_compression_level", 2);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/lossless_compression/webp_compression_level", PropertyInfo(Variant::INT, "rendering/textures/lossless_compression/webp_compression_level", PROPERTY_HINT_RANGE, "0,9,1"));
+
GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::FLOAT, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"));
@@ -2282,8 +2305,18 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048);
- GLOBAL_DEF("rendering/driver/rd_renderer/use_low_end_renderer", false);
- GLOBAL_DEF("rendering/driver/rd_renderer/use_low_end_renderer.mobile", true);
+ GLOBAL_DEF_RST("rendering/vulkan/rendering/back_end", 0);
+ GLOBAL_DEF_RST("rendering/vulkan/rendering/back_end.mobile", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/vulkan/rendering/back_end",
+ PropertyInfo(Variant::INT,
+ "rendering/vulkan/rendering/back_end",
+ PROPERTY_HINT_ENUM, "ForwardClustered,ForwardMobile"));
+
+ GLOBAL_DEF("rendering/shader_compiler/shader_cache/enabled", true);
+ GLOBAL_DEF("rendering/shader_compiler/shader_cache/compress", true);
+ GLOBAL_DEF("rendering/shader_compiler/shader_cache/use_zstd_compression", true);
+ GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug", false);
+ GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug.release", true);
GLOBAL_DEF("rendering/reflections/sky_reflections/roughness_layers", 8);
GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections", true);
@@ -2297,9 +2330,9 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false);
- GLOBAL_DEF("rendering/global_illumination/gi_probes/anisotropic", false);
- GLOBAL_DEF("rendering/global_illumination/gi_probes/quality", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/gi_probes/quality", PropertyInfo(Variant::INT, "rendering/global_illumination/gi_probes/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)"));
+ GLOBAL_DEF("rendering/global_illumination/voxel_gi/anisotropic", false);
+ GLOBAL_DEF("rendering/global_illumination/voxel_gi/quality", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/voxel_gi/quality", PropertyInfo(Variant::INT, "rendering/global_illumination/voxel_gi/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)"));
GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading", false);
GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading.mobile", true);
@@ -2340,6 +2373,10 @@ RenderingServer::RenderingServer() {
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/amount", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01"));
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/limit", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01"));
+ GLOBAL_DEF_RST("rendering/occlusion_culling/occlusion_rays_per_thread", 512);
+ GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/occlusion_culling/bvh_build_quality", PropertyInfo(Variant::INT, "rendering/occlusion_culling/bvh_build_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"));
+
GLOBAL_DEF("rendering/environment/glow/upscale_mode", 1);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/glow/upscale_mode", PropertyInfo(Variant::INT, "rendering/environment/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)"));
GLOBAL_DEF("rendering/environment/glow/upscale_mode.mobile", 0);
@@ -2383,6 +2420,8 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/limits/cluster_builder/max_clustered_elements", 512);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/cluster_builder/max_clustered_elements", PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1"));
+
+ GLOBAL_DEF_RST("rendering/xr/enabled", false);
}
RenderingServer::~RenderingServer() {
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 694fae7fde..ac6b0a4d1a 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -371,7 +371,7 @@ public:
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(RID p_multimesh, int p_index, const Transform3D &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;
@@ -379,7 +379,7 @@ public:
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 Transform3D 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;
@@ -411,8 +411,8 @@ public:
virtual RID skeleton_create() = 0;
virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0;
virtual int skeleton_get_bone_count(RID p_skeleton) const = 0;
- virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0;
- virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0;
+ virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) = 0;
+ virtual Transform3D 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;
@@ -548,56 +548,56 @@ public:
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 */
+ /* VOXEL GI API */
- virtual RID gi_probe_create() = 0;
+ virtual RID voxel_gi_create() = 0;
- virtual void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0;
+ virtual void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &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 AABB voxel_gi_get_bounds(RID p_voxel_gi) const = 0;
+ virtual Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const = 0;
+ virtual Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const = 0;
+ virtual Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const = 0;
+ virtual Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const = 0;
+ virtual Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const = 0;
+ virtual Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) 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 voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) = 0;
+ virtual float voxel_gi_get_dynamic_range(RID p_voxel_gi) 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 voxel_gi_set_propagation(RID p_voxel_gi, float p_range) = 0;
+ virtual float voxel_gi_get_propagation(RID p_voxel_gi) 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 voxel_gi_set_energy(RID p_voxel_gi, float p_energy) = 0;
+ virtual float voxel_gi_get_energy(RID p_voxel_gi) 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 voxel_gi_set_ao(RID p_voxel_gi, float p_ao) = 0;
+ virtual float voxel_gi_get_ao(RID p_voxel_gi) 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 voxel_gi_set_ao_size(RID p_voxel_gi, float p_strength) = 0;
+ virtual float voxel_gi_get_ao_size(RID p_voxel_gi) 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 voxel_gi_set_bias(RID p_voxel_gi, float p_bias) = 0;
+ virtual float voxel_gi_get_bias(RID p_voxel_gi) 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 voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) = 0;
+ virtual float voxel_gi_get_normal_bias(RID p_voxel_gi) 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 voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) = 0;
+ virtual bool voxel_gi_is_interior(RID p_voxel_gi) 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 voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) = 0;
+ virtual bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) 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 void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) = 0;
+ virtual float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const = 0;
- enum GIProbeQuality {
- GI_PROBE_QUALITY_LOW,
- GI_PROBE_QUALITY_HIGH,
+ enum VoxelGIQuality {
+ VOXEL_GI_QUALITY_LOW,
+ VOXEL_GI_QUALITY_HIGH,
};
- virtual void gi_probe_set_quality(GIProbeQuality) = 0;
+ virtual void voxel_gi_set_quality(VoxelGIQuality) = 0;
/* LIGHTMAP */
@@ -618,6 +618,12 @@ public:
virtual RID particles_create() = 0;
+ enum ParticlesMode {
+ PARTICLES_MODE_2D,
+ PARTICLES_MODE_3D
+ };
+ virtual void particles_set_mode(RID p_particles, ParticlesMode p_mode) = 0;
+
virtual void particles_set_emitting(RID p_particles, bool p_enable) = 0;
virtual bool particles_get_emitting(RID p_particles) = 0;
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
@@ -631,8 +637,22 @@ public:
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0;
virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
+ virtual void particles_set_interpolate(RID p_particles, bool p_enable) = 0;
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
virtual void particles_set_collision_base_size(RID p_particles, float p_size) = 0;
+
+ enum ParticlesTransformAlign {
+ PARTICLES_TRANSFORM_ALIGN_DISABLED,
+ PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD,
+ PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY,
+ PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY,
+ };
+
+ virtual void particles_set_transform_align(RID p_particles, ParticlesTransformAlign p_transform_align) = 0;
+
+ virtual void particles_set_trails(RID p_particles, bool p_enable, float p_length_sec) = 0;
+ virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) = 0;
+
virtual bool particles_is_inactive(RID p_particles) = 0;
virtual void particles_request_process(RID p_particles) = 0;
virtual void particles_restart(RID p_particles) = 0;
@@ -647,11 +667,12 @@ public:
PARTICLES_EMIT_FLAG_CUSTOM = 16
};
- virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0;
+ virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0;
enum ParticlesDrawOrder {
PARTICLES_DRAW_ORDER_INDEX,
PARTICLES_DRAW_ORDER_LIFETIME,
+ PARTICLES_DRAW_ORDER_REVERSE_LIFETIME,
PARTICLES_DRAW_ORDER_VIEW_DEPTH,
};
@@ -662,7 +683,7 @@ public:
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
+ virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) = 0; //this is only used for 2D, in 3D it's automatic
/* PARTICLES COLLISION API */
@@ -701,13 +722,24 @@ public:
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field
+ /* VISIBILITY NOTIFIER API */
+
+ virtual RID visibility_notifier_create() = 0;
+ virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) = 0;
+ virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0;
+
+ /* OCCLUDER API */
+
+ virtual RID occluder_create() = 0;
+ virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) = 0;
+
/* 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_transform(RID p_camera, const Transform3D &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;
@@ -826,6 +858,17 @@ public:
virtual void viewport_set_lod_threshold(RID p_viewport, float p_pixels) = 0;
+ virtual void viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_debanding) = 0;
+ virtual void viewport_set_occlusion_rays_per_thread(int p_rays_per_thread) = 0;
+
+ enum ViewportOcclusionCullingBuildQuality {
+ VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW = 0,
+ VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM = 1,
+ VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH = 2,
+ };
+
+ virtual void viewport_set_occlusion_culling_build_quality(ViewportOcclusionCullingBuildQuality p_quality) = 0;
+
enum ViewportRenderInfo {
VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME,
VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME,
@@ -845,9 +888,9 @@ public:
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_VOXEL_GI_ALBEDO,
+ VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING,
+ VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION,
VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS,
VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE,
@@ -862,6 +905,7 @@ public:
VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS,
VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS,
VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES,
+ VIEWPORT_DEBUG_DRAW_OCCLUDERS,
};
virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0;
@@ -1107,8 +1151,10 @@ public:
INSTANCE_LIGHT,
INSTANCE_REFLECTION_PROBE,
INSTANCE_DECAL,
- INSTANCE_GI_PROBE,
+ INSTANCE_VOXEL_GI,
INSTANCE_LIGHTMAP,
+ INSTANCE_OCCLUDER,
+ INSTANCE_VISIBLITY_NOTIFIER,
INSTANCE_MAX,
INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE) | (1 << INSTANCE_PARTICLES)
@@ -1121,7 +1167,7 @@ public:
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_set_transform(RID p_instance, const Transform3D &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_override_material(RID p_instance, int p_surface, RID p_material) = 0;
@@ -1133,6 +1179,7 @@ public:
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;
+ virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0;
// don't use these in a game!
virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0;
@@ -1147,6 +1194,7 @@ public:
INSTANCE_FLAG_USE_BAKED_LIGHT,
INSTANCE_FLAG_USE_DYNAMIC_GI,
INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
+ INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING,
INSTANCE_FLAG_MAX
};
@@ -1161,8 +1209,7 @@ public:
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;
+ virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0;
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice) = 0;
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0;
@@ -1261,6 +1308,8 @@ public:
virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0;
+ virtual void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0;
+
enum CanvasGroupMode {
CANVAS_GROUP_MODE_DISABLED,
CANVAS_GROUP_MODE_OPAQUE,
@@ -1505,6 +1554,7 @@ VARIANT_ENUM_CAST(RenderingServer::ViewportMSAA);
VARIANT_ENUM_CAST(RenderingServer::ViewportScreenSpaceAA);
VARIANT_ENUM_CAST(RenderingServer::ViewportRenderInfo);
VARIANT_ENUM_CAST(RenderingServer::ViewportDebugDraw);
+VARIANT_ENUM_CAST(RenderingServer::ViewportOcclusionCullingBuildQuality);
VARIANT_ENUM_CAST(RenderingServer::SkyMode);
VARIANT_ENUM_CAST(RenderingServer::EnvironmentBG);
VARIANT_ENUM_CAST(RenderingServer::EnvironmentAmbientSource);
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 8b03565291..daed612b02 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -987,7 +987,7 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start,
while (i < ranges.size()) {
int j = i + 1;
while (j < ranges.size()) {
- if (Math::is_equal_approx(ranges[i].y, ranges[j].x, UNIT_EPSILON)) {
+ if (Math::is_equal_approx(ranges[i].y, ranges[j].x, (real_t)UNIT_EPSILON)) {
ranges.write[i].y = ranges[j].y;
ranges.remove(j);
continue;
diff --git a/servers/text_server.h b/servers/text_server.h
index 7fcfb91151..138ceb9356 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -31,7 +31,7 @@
#ifndef TEXT_SERVER_H
#define TEXT_SERVER_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/os/os.h"
#include "core/templates/rid.h"
#include "core/variant/variant.h"
diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp
index 9148631899..09e8e12f8b 100644
--- a/servers/xr/xr_interface.cpp
+++ b/servers/xr/xr_interface.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "xr_interface.h"
+#include "servers/rendering/renderer_compositor.h"
void XRInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_name"), &XRInterface::get_name);
@@ -45,7 +46,7 @@ void XRInterface::_bind_methods() {
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);
+ ClassDB::bind_method(D_METHOD("get_view_count"), &XRInterface::get_view_count);
ADD_GROUP("Interface", "interface_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_primary"), "set_is_primary", "is_primary");
diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h
index 8039018f35..6031bd7003 100644
--- a/servers/xr/xr_interface.h
+++ b/servers/xr/xr_interface.h
@@ -35,6 +35,9 @@
#include "core/os/thread_safe.h"
#include "servers/xr_server.h"
+// forward declaration
+struct BlitToScreen;
+
/**
@author Bastiaan Olij <mux213@gmail.com>
@@ -47,8 +50,8 @@
Note that we may make this into a fully instantiable class for GDNative support.
*/
-class XRInterface : public Reference {
- GDCLASS(XRInterface, Reference);
+class XRInterface : public RefCounted {
+ GDCLASS(XRInterface, RefCounted);
public:
enum Capabilities { /* purely meta data, provides some info about what this interface supports */
@@ -105,17 +108,22 @@ public:
/** 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 uint32_t get_view_count() = 0; /* returns the view count we need (1 is monoscopic, 2 is stereoscopic but can be more) */
+ virtual Transform3D get_camera_transform() = 0; /* returns the position of our camera for updating our camera node. For monoscopic this is equal to the views transform, for stereoscopic this should be an average */
+ virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) = 0; /* get each views transform */
+ virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each view projection matrix */
+
+ virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* commit rendered views to the XR interface */
virtual void process() = 0;
virtual void notification(int p_what) = 0;
XRInterface();
~XRInterface();
+
+ // deprecated
+ 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 */
};
VARIANT_ENUM_CAST(XRInterface::Capabilities);
diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp
index 5341390045..e9383db941 100644
--- a/servers/xr/xr_positional_tracker.cpp
+++ b/servers/xr/xr_positional_tracker.cpp
@@ -194,8 +194,8 @@ void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHan
};
};
-Transform XRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const {
- Transform new_transform;
+Transform3D XRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const {
+ Transform3D new_transform;
new_transform.basis = get_orientation();
new_transform.origin = get_position();
diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h
index a5c6459471..5577582929 100644
--- a/servers/xr/xr_positional_tracker.h
+++ b/servers/xr/xr_positional_tracker.h
@@ -43,8 +43,8 @@
This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking.
*/
-class XRPositionalTracker : public Reference {
- GDCLASS(XRPositionalTracker, Reference);
+class XRPositionalTracker : public RefCounted {
+ GDCLASS(XRPositionalTracker, RefCounted);
_THREAD_SAFE_CLASS_
public:
@@ -93,7 +93,7 @@ public:
void set_mesh(const Ref<Mesh> &p_mesh);
Ref<Mesh> get_mesh() const;
- Transform get_transform(bool p_adjust_by_reference_frame) const;
+ Transform3D get_transform(bool p_adjust_by_reference_frame) const;
XRPositionalTracker();
~XRPositionalTracker() {}
diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp
index 5678071857..b12fff319d 100644
--- a/servers/xr_server.cpp
+++ b/servers/xr_server.cpp
@@ -101,25 +101,25 @@ void XRServer::set_world_scale(real_t p_world_scale) {
world_scale = p_world_scale;
};
-Transform XRServer::get_world_origin() const {
+Transform3D XRServer::get_world_origin() const {
return world_origin;
};
-void XRServer::set_world_origin(const Transform &p_world_origin) {
+void XRServer::set_world_origin(const Transform3D &p_world_origin) {
world_origin = p_world_origin;
};
-Transform XRServer::get_reference_frame() const {
+Transform3D 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();
+ reference_frame = Transform3D();
// 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());
+ Transform3D new_reference_frame = primary_interface->get_camera_transform();
// remove our tilt
if (p_rotation_mode == 1) {
@@ -145,10 +145,10 @@ void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) {
};
};
-Transform XRServer::get_hmd_transform() {
- Transform hmd_transform;
+Transform3D XRServer::get_hmd_transform() {
+ Transform3D hmd_transform;
if (primary_interface != nullptr) {
- hmd_transform = primary_interface->get_transform_for_eye(XRInterface::EYE_MONO, hmd_transform);
+ hmd_transform = primary_interface->get_camera_transform();
};
return hmd_transform;
};
diff --git a/servers/xr_server.h b/servers/xr_server.h
index 46243d7fd0..25431844c2 100644
--- a/servers/xr_server.h
+++ b/servers/xr_server.h
@@ -31,7 +31,7 @@
#ifndef XR_SERVER_H
#define XR_SERVER_H
-#include "core/object/reference.h"
+#include "core/object/ref_counted.h"
#include "core/os/os.h"
#include "core/os/thread_safe.h"
#include "core/templates/rid.h"
@@ -82,8 +82,8 @@ private:
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 */
+ Transform3D world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */
+ Transform3D 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 */
@@ -122,8 +122,8 @@ public:
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);
+ Transform3D get_world_origin() const;
+ void set_world_origin(const Transform3D &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)
@@ -135,13 +135,13 @@ public:
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;
+ Transform3D 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();
+ Transform3D get_hmd_transform();
/*
Interfaces are objects that 'glue' Godot to an AR or VR SDK such as the Oculus SDK, OpenVR, OpenHMD, etc.
diff --git a/tests/test_aabb.h b/tests/test_aabb.h
index 517c4dcefd..39e3c6e45b 100644
--- a/tests/test_aabb.h
+++ b/tests/test_aabb.h
@@ -50,8 +50,8 @@ TEST_CASE("[AABB] Constructor methods") {
TEST_CASE("[AABB] String conversion") {
CHECK_MESSAGE(
- String(AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6))) == "-1.5, 2, -2.5 - 4, 5, 6",
- "The string representation shouild match the expected value.");
+ String(AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6))) == "[P: (-1.5, 2, -2.5), S: (4, 5, 6)]",
+ "The string representation should match the expected value.");
}
TEST_CASE("[AABB] Basic getters") {
diff --git a/tests/test_class_db.h b/tests/test_class_db.h
index 9ef4569c14..75785fa5ed 100644
--- a/tests/test_class_db.h
+++ b/tests/test_class_db.h
@@ -97,7 +97,7 @@ struct ExposedClass {
bool is_singleton = false;
bool is_instantiable = false;
- bool is_reference = false;
+ bool is_ref_counted = false;
ClassDB::APIType api_type;
@@ -131,7 +131,7 @@ struct ExposedClass {
struct NamesCache {
StringName variant_type = StaticCString::create("Variant");
StringName object_class = StaticCString::create("Object");
- StringName reference_class = StaticCString::create("Reference");
+ StringName ref_counted_class = StaticCString::create("RefCounted");
StringName string_type = StaticCString::create("String");
StringName string_name_type = StaticCString::create("StringName");
StringName node_path_type = StaticCString::create("NodePath");
@@ -240,10 +240,10 @@ bool arg_default_value_is_assignable_to_type(const Context &p_context, const Var
p_arg_type.name == p_context.names_cache.node_path_type;
case Variant::NODE_PATH:
return p_arg_type.name == p_context.names_cache.node_path_type;
- case Variant::TRANSFORM:
+ case Variant::TRANSFORM3D:
case Variant::TRANSFORM2D:
case Variant::BASIS:
- case Variant::QUAT:
+ case Variant::QUATERNION:
case Variant::PLANE:
case Variant::AABB:
case Variant::COLOR:
@@ -516,7 +516,7 @@ void add_exposed_classes(Context &r_context) {
exposed_class.api_type = api_type;
exposed_class.is_singleton = Engine::get_singleton()->has_singleton(class_name);
exposed_class.is_instantiable = class_info->creation_func && !exposed_class.is_singleton;
- exposed_class.is_reference = ClassDB::is_parent_class(class_name, "Reference");
+ exposed_class.is_ref_counted = ClassDB::is_parent_class(class_name, "RefCounted");
exposed_class.base = ClassDB::get_parent_class(class_name);
// Add properties
@@ -611,7 +611,7 @@ void add_exposed_classes(Context &r_context) {
method.return_type.name = return_info.class_name;
bool bad_reference_hint = !method.is_virtual && return_info.hint != PROPERTY_HINT_RESOURCE_TYPE &&
- ClassDB::is_parent_class(return_info.class_name, r_context.names_cache.reference_class);
+ ClassDB::is_parent_class(return_info.class_name, r_context.names_cache.ref_counted_class);
TEST_COND(bad_reference_hint, "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'.", " Are you returning a reference type by pointer? Method: '",
exposed_class.name, ".", method.name, "'.");
} else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
@@ -665,7 +665,7 @@ void add_exposed_classes(Context &r_context) {
TEST_COND(exposed_class.find_property_by_name(method.name),
"Method name conflicts with property: '", String(class_name), ".", String(method.name), "'.");
- // Classes starting with an underscore are ignored unless they're used as a property setter or getter
+ // Methods starting with an underscore are ignored unless they're virtual or used as a property setter or getter.
if (!method.is_virtual && String(method.name)[0] == '_') {
for (const List<PropertyData>::Element *F = exposed_class.properties.front(); F; F = F->next()) {
const PropertyData &prop = F->get();
@@ -678,6 +678,10 @@ void add_exposed_classes(Context &r_context) {
} else {
exposed_class.methods.push_back(method);
}
+
+ if (method.is_virtual) {
+ TEST_COND(String(method.name)[0] != '_', "Virtual method ", String(method.name), " does not start with underscore.");
+ }
}
// Add signals
diff --git a/tests/test_color.h b/tests/test_color.h
index eb8d7dcbd4..bffa890ae2 100644
--- a/tests/test_color.h
+++ b/tests/test_color.h
@@ -101,13 +101,13 @@ TEST_CASE("[Color] Reading methods") {
const Color dark_blue = Color(0, 0, 0.5, 0.4);
CHECK_MESSAGE(
- Math::is_equal_approx(dark_blue.get_h(), 240 / 360.0),
+ Math::is_equal_approx(dark_blue.get_h(), 240.0f / 360.0f),
"The returned HSV hue should match the expected value.");
CHECK_MESSAGE(
- Math::is_equal_approx(dark_blue.get_s(), 1),
+ Math::is_equal_approx(dark_blue.get_s(), 1.0f),
"The returned HSV saturation should match the expected value.");
CHECK_MESSAGE(
- Math::is_equal_approx(dark_blue.get_v(), 0.5),
+ Math::is_equal_approx(dark_blue.get_v(), 0.5f),
"The returned HSV value should match the expected value.");
}
@@ -140,7 +140,7 @@ TEST_CASE("[Color] Conversion methods") {
cyan.to_rgba64() == 0x0000'ffff'ffff'ffff,
"The returned 64-bit BGR number should match the expected value.");
CHECK_MESSAGE(
- String(cyan) == "0, 1, 1, 1",
+ String(cyan) == "(0, 1, 1, 1)",
"The string representation should match the expected value.");
}
diff --git a/tests/test_command_queue.h b/tests/test_command_queue.h
index 2f0f62f5c8..f0d4569942 100644
--- a/tests/test_command_queue.h
+++ b/tests/test_command_queue.h
@@ -127,20 +127,20 @@ public:
int func1_count = 0;
- void func1(Transform t) {
+ void func1(Transform3D t) {
func1_count++;
}
- void func2(Transform t, float f) {
+ void func2(Transform3D t, float f) {
func1_count++;
}
- void func3(Transform t1, Transform t2, Transform t3, Transform t4, Transform t5, Transform t6) {
+ void func3(Transform3D t1, Transform3D t2, Transform3D t3, Transform3D t4, Transform3D t5, Transform3D t6) {
func1_count++;
}
- Transform func1r(Transform t) {
+ Transform3D func1r(Transform3D t) {
func1_count++;
return t;
}
- Transform func2r(Transform t, float f) {
+ Transform3D func2r(Transform3D t, float f) {
func1_count++;
return t;
}
@@ -156,7 +156,7 @@ public:
command_queue.flush_all();
}
for (int i = 0; i < message_count_to_read; i++) {
- command_queue.wait_and_flush_one();
+ command_queue.wait_and_flush();
}
message_count_to_read = 0;
@@ -175,8 +175,8 @@ public:
during_writing = false;
writer_threadwork.thread_wait_for_work();
while (!exit_threads) {
- Transform tr;
- Transform otr;
+ Transform3D tr;
+ Transform3D otr;
float f = 1;
during_writing = true;
for (int i = 0; i < message_types_to_write.size(); i++) {
@@ -276,50 +276,6 @@ TEST_CASE("[CommandQueue] Test Queue Basics") {
ProjectSettings::get_singleton()->property_get_revert(COMMAND_QUEUE_SETTING));
}
-TEST_CASE("[CommandQueue] Test Waiting at Queue Full") {
- const char *COMMAND_QUEUE_SETTING = "memory/limits/command_queue/multithreading_queue_size_kb";
- ProjectSettings::get_singleton()->set_setting(COMMAND_QUEUE_SETTING, 1);
- SharedThreadState sts;
- sts.init_threads();
-
- int msgs_to_add = 24; // a queue of size 1kB fundamentally cannot fit 24 matrices.
- for (int i = 0; i < msgs_to_add; i++) {
- sts.add_msg_to_write(SharedThreadState::TEST_MSG_FUNC1_TRANSFORM);
- }
- sts.writer_threadwork.main_start_work();
- // If we call main_wait_for_done, we will deadlock. So instead...
- sts.message_count_to_read = 1;
- sts.reader_threadwork.main_start_work();
- sts.reader_threadwork.main_wait_for_done();
- CHECK_MESSAGE(sts.func1_count == 1,
- "Reader should have read one message");
- CHECK_MESSAGE(sts.during_writing,
- "Writer thread should still be blocked on writing.");
- sts.message_count_to_read = msgs_to_add - 3;
- sts.reader_threadwork.main_start_work();
- sts.reader_threadwork.main_wait_for_done();
- CHECK_MESSAGE(sts.func1_count >= msgs_to_add - 3,
- "Reader should have read most messages");
- sts.writer_threadwork.main_wait_for_done();
- CHECK_MESSAGE(sts.during_writing == false,
- "Writer thread should no longer be blocked on writing.");
- sts.message_count_to_read = 2;
- sts.reader_threadwork.main_start_work();
- sts.reader_threadwork.main_wait_for_done();
- sts.message_count_to_read = -1;
- sts.reader_threadwork.main_start_work();
- sts.reader_threadwork.main_wait_for_done();
- CHECK_MESSAGE(sts.func1_count == msgs_to_add,
- "Reader should have read all messages");
-
- sts.destroy_threads();
-
- CHECK_MESSAGE(sts.func1_count == msgs_to_add,
- "Reader should have read no additional messages after join");
- ProjectSettings::get_singleton()->set_setting(COMMAND_QUEUE_SETTING,
- ProjectSettings::get_singleton()->property_get_revert(COMMAND_QUEUE_SETTING));
-}
-
TEST_CASE("[CommandQueue] Test Queue Wrapping to same spot.") {
const char *COMMAND_QUEUE_SETTING = "memory/limits/command_queue/multithreading_queue_size_kb";
ProjectSettings::get_singleton()->set_setting(COMMAND_QUEUE_SETTING, 1);
diff --git a/tests/test_curve.h b/tests/test_curve.h
index 019941a7ce..3055cfd97b 100644
--- a/tests/test_curve.h
+++ b/tests/test_curve.h
@@ -83,13 +83,13 @@ TEST_CASE("[Curve] Custom curve with free tangents") {
Math::is_equal_approx(curve->interpolate(-0.1), 0),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.1), 0.352),
+ Math::is_equal_approx(curve->interpolate(0.1), (real_t)0.352),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.4), 0.352),
+ Math::is_equal_approx(curve->interpolate(0.4), (real_t)0.352),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.7), 0.896),
+ Math::is_equal_approx(curve->interpolate(0.7), (real_t)0.896),
"Custom free curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
Math::is_equal_approx(curve->interpolate(1), 1),
@@ -102,13 +102,13 @@ TEST_CASE("[Curve] Custom curve with free tangents") {
Math::is_equal_approx(curve->interpolate_baked(-0.1), 0),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.1), 0.352),
+ Math::is_equal_approx(curve->interpolate_baked(0.1), (real_t)0.352),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.4), 0.352),
+ Math::is_equal_approx(curve->interpolate_baked(0.4), (real_t)0.352),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.7), 0.896),
+ Math::is_equal_approx(curve->interpolate_baked(0.7), (real_t)0.896),
"Custom free curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
Math::is_equal_approx(curve->interpolate_baked(1), 1),
@@ -172,13 +172,13 @@ TEST_CASE("[Curve] Custom curve with linear tangents") {
Math::is_equal_approx(curve->interpolate(-0.1), 0),
"Custom linear curve should return the expected value at offset -0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.1), 0.4),
+ Math::is_equal_approx(curve->interpolate(0.1), (real_t)0.4),
"Custom linear curve should return the expected value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.4), 0.4),
+ Math::is_equal_approx(curve->interpolate(0.4), (real_t)0.4),
"Custom linear curve should return the expected value at offset 0.4.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.7), 0.8),
+ Math::is_equal_approx(curve->interpolate(0.7), (real_t)0.8),
"Custom linear curve should return the expected value at offset 0.7.");
CHECK_MESSAGE(
Math::is_equal_approx(curve->interpolate(1), 1),
@@ -191,13 +191,13 @@ TEST_CASE("[Curve] Custom curve with linear tangents") {
Math::is_equal_approx(curve->interpolate_baked(-0.1), 0),
"Custom linear curve should return the expected baked value at offset -0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.1), 0.4),
+ Math::is_equal_approx(curve->interpolate_baked(0.1), (real_t)0.4),
"Custom linear curve should return the expected baked value at offset 0.1.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.4), 0.4),
+ Math::is_equal_approx(curve->interpolate_baked(0.4), (real_t)0.4),
"Custom linear curve should return the expected baked value at offset 0.4.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.7), 0.8),
+ Math::is_equal_approx(curve->interpolate_baked(0.7), (real_t)0.8),
"Custom linear curve should return the expected baked value at offset 0.7.");
CHECK_MESSAGE(
Math::is_equal_approx(curve->interpolate_baked(1), 1),
@@ -210,10 +210,10 @@ TEST_CASE("[Curve] Custom curve with linear tangents") {
curve->remove_point(10);
ERR_PRINT_ON;
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate(0.7), 0.8),
+ Math::is_equal_approx(curve->interpolate(0.7), (real_t)0.8),
"Custom free curve should return the expected value at offset 0.7 after removing point at invalid index 10.");
CHECK_MESSAGE(
- Math::is_equal_approx(curve->interpolate_baked(0.7), 0.8),
+ Math::is_equal_approx(curve->interpolate_baked(0.7), (real_t)0.8),
"Custom free curve should return the expected baked value at offset 0.7 after removing point at invalid index 10.");
}
} // namespace TestCurve
diff --git a/tests/test_expression.h b/tests/test_expression.h
index 0ef60d1a19..cb1d29389f 100644
--- a/tests/test_expression.h
+++ b/tests/test_expression.h
@@ -83,42 +83,42 @@ TEST_CASE("[Expression] Floating-point arithmetic") {
expression.parse("-123.456") == OK,
"Float identity should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(float(expression.execute()), -123.456),
+ Math::is_equal_approx(double(expression.execute()), -123.456),
"Float identity should return the expected result.");
CHECK_MESSAGE(
expression.parse("2.0 + 3.0") == OK,
"Float addition should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(float(expression.execute()), 5),
+ Math::is_equal_approx(double(expression.execute()), 5),
"Float addition should return the expected result.");
CHECK_MESSAGE(
expression.parse("3.0 / 10") == OK,
"Float / integer division should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(float(expression.execute()), 0.3),
+ Math::is_equal_approx(double(expression.execute()), 0.3),
"Float / integer division should return the expected result.");
CHECK_MESSAGE(
expression.parse("3 / 10.0") == OK,
"Basic integer / float division should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(float(expression.execute()), 0.3),
+ Math::is_equal_approx(double(expression.execute()), 0.3),
"Basic integer / float division should return the expected result.");
CHECK_MESSAGE(
expression.parse("3.0 / 10.0") == OK,
"Float / float division should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(float(expression.execute()), 0.3),
+ Math::is_equal_approx(double(expression.execute()), 0.3),
"Float / float division should return the expected result.");
CHECK_MESSAGE(
expression.parse("2.5 * (6.0 + 14.25) / 2.0 - 5.12345") == OK,
"Float multiplication-addition-subtraction-division should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(float(expression.execute()), 20.18905),
+ Math::is_equal_approx(double(expression.execute()), 20.18905),
"Float multiplication-addition-subtraction-division should return the expected result.");
}
@@ -129,7 +129,7 @@ TEST_CASE("[Expression] Scientific notation") {
expression.parse("2.e5") == OK,
"The expression should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(float(expression.execute()), 200'000),
+ Math::is_equal_approx(double(expression.execute()), 200'000),
"The expression should return the expected result.");
// The middle "e" is ignored here.
@@ -137,14 +137,14 @@ TEST_CASE("[Expression] Scientific notation") {
expression.parse("2e5") == OK,
"The expression should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(float(expression.execute()), 25),
+ Math::is_equal_approx(double(expression.execute()), 25),
"The expression should return the expected result.");
CHECK_MESSAGE(
expression.parse("2e.5") == OK,
"The expression should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(float(expression.execute()), 2),
+ Math::is_equal_approx(double(expression.execute()), 2),
"The expression should return the expected result.");
}
@@ -176,14 +176,14 @@ TEST_CASE("[Expression] Built-in functions") {
expression.parse("snapped(sin(0.5), 0.01)") == OK,
"The expression should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(float(expression.execute()), 0.48),
+ Math::is_equal_approx(double(expression.execute()), 0.48),
"`snapped(sin(0.5), 0.01)` should return the expected result.");
CHECK_MESSAGE(
expression.parse("pow(2.0, -2500)") == OK,
"The expression should parse successfully.");
CHECK_MESSAGE(
- Math::is_zero_approx(float(expression.execute())),
+ Math::is_zero_approx(double(expression.execute())),
"`pow(2.0, -2500)` should return the expected result (asymptotically zero).");
}
@@ -410,7 +410,7 @@ TEST_CASE("[Expression] Unusual expressions") {
"The expression should parse successfully.");
ERR_PRINT_OFF;
CHECK_MESSAGE(
- Math::is_inf(float(expression.execute())),
+ Math::is_inf(double(expression.execute())),
"`-25.4 / 0` should return inf.");
ERR_PRINT_ON;
diff --git a/tests/test_file_access.h b/tests/test_file_access.h
index 00a314644c..cb74e08a0d 100644
--- a/tests/test_file_access.h
+++ b/tests/test_file_access.h
@@ -31,7 +31,7 @@
#ifndef TEST_FILE_ACCESS_H
#define TEST_FILE_ACCESS_H
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "test_utils.h"
namespace TestFileAccess {
diff --git a/tests/test_geometry_2d.h b/tests/test_geometry_2d.h
index c9313f3625..32d4114a1c 100644
--- a/tests/test_geometry_2d.h
+++ b/tests/test_geometry_2d.h
@@ -50,7 +50,7 @@ TEST_CASE("[Geometry2D] Point in circle") {
CHECK(Geometry2D::is_point_in_circle(Vector2(7, -42), Vector2(4, -40), 3.7));
CHECK_FALSE(Geometry2D::is_point_in_circle(Vector2(7, -42), Vector2(4, -40), 3.5));
- // This tests points on the edge of the circle. They are treated as beeing inside the circle.
+ // This tests points on the edge of the circle. They are treated as being inside the circle.
// In `is_point_in_triangle` and `is_point_in_polygon` they are treated as being outside, so in order the make
// the behaviour consistent this may change in the future (see issue #44717 and PR #44274).
CHECK(Geometry2D::is_point_in_circle(Vector2(1.0, 0.0), Vector2(0, 0), 1.0));
@@ -65,7 +65,7 @@ TEST_CASE("[Geometry2D] Point in triangle") {
CHECK(Geometry2D::is_point_in_triangle(Vector2(-3, -2.5), Vector2(-1, -4), Vector2(-3, -2), Vector2(-5, -4)));
CHECK_FALSE(Geometry2D::is_point_in_triangle(Vector2(0, 0), Vector2(1, 4), Vector2(3, 2), Vector2(5, 4)));
- // This tests points on the edge of the triangle. They are treated as beeing outside the triangle.
+ // This tests points on the edge of the triangle. They are treated as being outside the triangle.
// In `is_point_in_circle` they are treated as being inside, so in order the make
// the behaviour consistent this may change in the future (see issue #44717 and PR #44274).
CHECK_FALSE(Geometry2D::is_point_in_triangle(Vector2(1, 1), Vector2(-1, 1), Vector2(0, -1), Vector2(1, 1)));
@@ -95,7 +95,7 @@ TEST_CASE("[Geometry2D] Point in polygon") {
CHECK(Geometry2D::is_point_in_polygon(Vector2(370, 55), p));
CHECK(Geometry2D::is_point_in_polygon(Vector2(-160, 190), p));
- // This tests points on the edge of the polygon. They are treated as beeing outside the polygon.
+ // This tests points on the edge of the polygon. They are treated as being outside the polygon.
// In `is_point_in_circle` they are treated as being inside, so in order the make
// the behaviour consistent this may change in the future (see issue #44717 and PR #44274).
CHECK_FALSE(Geometry2D::is_point_in_polygon(Vector2(68, 112), p));
@@ -227,7 +227,7 @@ TEST_CASE("[Geometry2D] Polygon intersection") {
CHECK(r[0][2].is_equal_approx(Point2(160.52632, 92.63157)));
}
- SUBCASE("[Geometry2D] Intersection with one polygon beeing completly inside the other polygon") {
+ SUBCASE("[Geometry2D] Intersection with one polygon being completely inside the other polygon") {
b.push_back(Point2(80, 100));
b.push_back(Point2(50, 50));
b.push_back(Point2(150, 50));
diff --git a/tests/test_image.h b/tests/test_image.h
index d73717f5b7..99c2a9380d 100644
--- a/tests/test_image.h
+++ b/tests/test_image.h
@@ -101,8 +101,8 @@ TEST_CASE("[Image] Saving and loading") {
Ref<Image> image_bmp = memnew(Image());
FileAccessRef f_bmp = FileAccess::open(TestUtils::get_data_path("images/icon.bmp"), FileAccess::READ, &err);
PackedByteArray data_bmp;
- data_bmp.resize(f_bmp->get_len() + 1);
- f_bmp->get_buffer(data_bmp.ptrw(), f_bmp->get_len());
+ data_bmp.resize(f_bmp->get_length() + 1);
+ f_bmp->get_buffer(data_bmp.ptrw(), f_bmp->get_length());
CHECK_MESSAGE(
image_bmp->load_bmp_from_buffer(data_bmp) == OK,
"The BMP image should load successfully.");
@@ -111,8 +111,8 @@ TEST_CASE("[Image] Saving and loading") {
Ref<Image> image_jpg = memnew(Image());
FileAccessRef f_jpg = FileAccess::open(TestUtils::get_data_path("images/icon.jpg"), FileAccess::READ, &err);
PackedByteArray data_jpg;
- data_jpg.resize(f_jpg->get_len() + 1);
- f_jpg->get_buffer(data_jpg.ptrw(), f_jpg->get_len());
+ data_jpg.resize(f_jpg->get_length() + 1);
+ f_jpg->get_buffer(data_jpg.ptrw(), f_jpg->get_length());
CHECK_MESSAGE(
image_jpg->load_jpg_from_buffer(data_jpg) == OK,
"The JPG image should load successfully.");
@@ -121,8 +121,8 @@ TEST_CASE("[Image] Saving and loading") {
Ref<Image> image_webp = memnew(Image());
FileAccessRef f_webp = FileAccess::open(TestUtils::get_data_path("images/icon.webp"), FileAccess::READ, &err);
PackedByteArray data_webp;
- data_webp.resize(f_webp->get_len() + 1);
- f_webp->get_buffer(data_webp.ptrw(), f_webp->get_len());
+ data_webp.resize(f_webp->get_length() + 1);
+ f_webp->get_buffer(data_webp.ptrw(), f_webp->get_length());
CHECK_MESSAGE(
image_webp->load_webp_from_buffer(data_webp) == OK,
"The WEBP image should load successfully.");
@@ -131,8 +131,8 @@ TEST_CASE("[Image] Saving and loading") {
Ref<Image> image_png = memnew(Image());
FileAccessRef f_png = FileAccess::open(TestUtils::get_data_path("images/icon.png"), FileAccess::READ, &err);
PackedByteArray data_png;
- data_png.resize(f_png->get_len() + 1);
- f_png->get_buffer(data_png.ptrw(), f_png->get_len());
+ data_png.resize(f_png->get_length() + 1);
+ f_png->get_buffer(data_png.ptrw(), f_png->get_length());
CHECK_MESSAGE(
image_png->load_png_from_buffer(data_png) == OK,
"The PNG image should load successfully.");
@@ -141,8 +141,8 @@ TEST_CASE("[Image] Saving and loading") {
Ref<Image> image_tga = memnew(Image());
FileAccessRef f_tga = FileAccess::open(TestUtils::get_data_path("images/icon.tga"), FileAccess::READ, &err);
PackedByteArray data_tga;
- data_tga.resize(f_tga->get_len() + 1);
- f_tga->get_buffer(data_tga.ptrw(), f_tga->get_len());
+ data_tga.resize(f_tga->get_length() + 1);
+ f_tga->get_buffer(data_tga.ptrw(), f_tga->get_length());
CHECK_MESSAGE(
image_tga->load_tga_from_buffer(data_tga) == OK,
"The TGA image should load successfully.");
diff --git a/tests/test_json.h b/tests/test_json.h
index e652a8fced..f1cb4799dc 100644
--- a/tests/test_json.h
+++ b/tests/test_json.h
@@ -80,7 +80,7 @@ TEST_CASE("[JSON] Parsing single data types") {
err_line == 0,
"Parsing an integer number as JSON should parse successfully.");
CHECK_MESSAGE(
- Math::is_equal_approx(result, 123'456),
+ (int)result == 123'456,
"Parsing an integer number as JSON should return the expected value.");
json.parse("0.123456", result, err_str, err_line);
@@ -155,7 +155,7 @@ TEST_CASE("[JSON] Parsing objects (dictionaries)") {
dictionary["bugs"] == Variant(),
"The parsed JSON should contain the expected values.");
CHECK_MESSAGE(
- Math::is_equal_approx(Dictionary(dictionary["apples"])["blue"], -20),
+ (int)Dictionary(dictionary["apples"])["blue"] == -20,
"The parsed JSON should contain the expected values.");
CHECK_MESSAGE(
dictionary["empty_object"].hash() == Dictionary().hash(),
diff --git a/tests/test_macros.h b/tests/test_macros.h
index a13f3abbe7..a1f1932db4 100644
--- a/tests/test_macros.h
+++ b/tests/test_macros.h
@@ -91,10 +91,10 @@ DOCTEST_STRINGIFY_VARIANT(Vector3);
DOCTEST_STRINGIFY_VARIANT(Vector3i);
DOCTEST_STRINGIFY_VARIANT(Transform2D);
DOCTEST_STRINGIFY_VARIANT(Plane);
-DOCTEST_STRINGIFY_VARIANT(Quat);
+DOCTEST_STRINGIFY_VARIANT(Quaternion);
DOCTEST_STRINGIFY_VARIANT(AABB);
DOCTEST_STRINGIFY_VARIANT(Basis);
-DOCTEST_STRINGIFY_VARIANT(Transform);
+DOCTEST_STRINGIFY_VARIANT(Transform3D);
DOCTEST_STRINGIFY_VARIANT(::Color); // Disambiguate from `doctest::Color`.
DOCTEST_STRINGIFY_VARIANT(StringName);
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index d06d604532..d0466d1e2d 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -74,8 +74,11 @@
#include "test_shader_lang.h"
#include "test_string.h"
#include "test_text_server.h"
+#include "test_time.h"
+#include "test_translation.h"
#include "test_validate_testing.h"
#include "test_variant.h"
+#include "test_vector.h"
#include "test_xml_parser.h"
#include "modules/modules_tests.gen.h"
@@ -119,24 +122,27 @@ int test_main(int argc, char *argv[]) {
test_args.push_back(arg);
}
}
- // Convert Godot command line arguments back to standard arguments.
- char **doctest_args = new char *[test_args.size()];
- for (int x = 0; x < test_args.size(); x++) {
- // Operation to convert Godot string to non wchar string.
- CharString cs = test_args[x].utf8();
- const char *str = cs.get_data();
- // Allocate the string copy.
- doctest_args[x] = new char[strlen(str) + 1];
- // Copy this into memory.
- memcpy(doctest_args[x], str, strlen(str) + 1);
- }
- test_context.applyCommandLine(test_args.size(), doctest_args);
+ if (test_args.size() > 0) {
+ // Convert Godot command line arguments back to standard arguments.
+ char **doctest_args = new char *[test_args.size()];
+ for (int x = 0; x < test_args.size(); x++) {
+ // Operation to convert Godot string to non wchar string.
+ CharString cs = test_args[x].utf8();
+ const char *str = cs.get_data();
+ // Allocate the string copy.
+ doctest_args[x] = new char[strlen(str) + 1];
+ // Copy this into memory.
+ memcpy(doctest_args[x], str, strlen(str) + 1);
+ }
+
+ test_context.applyCommandLine(test_args.size(), doctest_args);
- for (int x = 0; x < test_args.size(); x++) {
- delete[] doctest_args[x];
+ for (int x = 0; x < test_args.size(); x++) {
+ delete[] doctest_args[x];
+ }
+ delete[] doctest_args;
}
- delete[] doctest_args;
return test_context.run();
}
diff --git a/tests/test_math.cpp b/tests/test_math.cpp
index 26c2aa2088..67d9a52539 100644
--- a/tests/test_math.cpp
+++ b/tests/test_math.cpp
@@ -30,13 +30,13 @@
#include "test_math.h"
+#include "core/io/file_access.h"
#include "core/math/basis.h"
#include "core/math/camera_matrix.h"
#include "core/math/delaunay_3d.h"
#include "core/math/geometry_2d.h"
#include "core/math/math_funcs.h"
-#include "core/math/transform.h"
-#include "core/os/file_access.h"
+#include "core/math/transform_3d.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -529,8 +529,8 @@ MainLoop *test() {
ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test);
Vector<uint8_t> buf;
- int flen = fa->get_len();
- buf.resize(fa->get_len() + 1);
+ uint64_t flen = fa->get_length();
+ buf.resize(fa->get_length() + 1);
fa->get_buffer(buf.ptrw(), flen);
buf.write[flen] = 0;
@@ -599,13 +599,13 @@ MainLoop *test() {
Basis m2(v2, a2);
- Quat q = m;
- Quat q2 = m2;
+ Quaternion q = m;
+ Quaternion q2 = m2;
Basis m3 = m.inverse() * m2;
- Quat q3 = (q.inverse() * q2); //.normalized();
+ Quaternion q3 = (q.inverse() * q2); //.normalized();
- print_line(Quat(m3));
+ print_line(Quaternion(m3));
print_line(q3);
print_line("before v: " + v + " a: " + rtos(a));
diff --git a/tests/test_object.h b/tests/test_object.h
index 142d76553d..b7eedc2670 100644
--- a/tests/test_object.h
+++ b/tests/test_object.h
@@ -93,35 +93,8 @@ public:
Ref<Script> get_script() const override {
return Ref<Script>();
}
- Vector<ScriptNetData> get_rpc_methods() const override {
- return Vector<ScriptNetData>();
- }
- uint16_t get_rpc_method_id(const StringName &p_method) const override {
- return 0;
- }
- StringName get_rpc_method(uint16_t p_id) const override {
- return StringName();
- }
- MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const override {
- return MultiplayerAPI::RPC_MODE_PUPPET;
- }
- MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override {
- return MultiplayerAPI::RPC_MODE_PUPPET;
- }
- Vector<ScriptNetData> get_rset_properties() const override {
- return Vector<ScriptNetData>();
- }
- uint16_t get_rset_property_id(const StringName &p_variable) const override {
- return 0;
- }
- StringName get_rset_property(uint16_t p_id) const override {
- return StringName();
- }
- MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const override {
- return MultiplayerAPI::RPC_MODE_PUPPET;
- }
- MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override {
- return MultiplayerAPI::RPC_MODE_PUPPET;
+ const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override {
+ return Vector<MultiplayerAPI::RPCConfig>();
}
ScriptLanguage *get_language() override {
return nullptr;
@@ -192,8 +165,8 @@ TEST_CASE("[Object] Construction") {
Object object;
CHECK_MESSAGE(
- !object.is_reference(),
- "Object is not a Reference.");
+ !object.is_ref_counted(),
+ "Object is not a RefCounted.");
Object *p_db = ObjectDB::get_instance(object.get_instance_id());
CHECK_MESSAGE(
diff --git a/tests/test_pck_packer.h b/tests/test_pck_packer.h
index 8e4721b821..06e4e64963 100644
--- a/tests/test_pck_packer.h
+++ b/tests/test_pck_packer.h
@@ -62,10 +62,10 @@ TEST_CASE("[PCKPacker] Pack an empty PCK file") {
err == OK,
"The generated empty PCK file should be opened successfully.");
CHECK_MESSAGE(
- f->get_len() >= 100,
+ f->get_length() >= 100,
"The generated empty PCK file shouldn't be too small (it should have the PCK header).");
CHECK_MESSAGE(
- f->get_len() <= 500,
+ f->get_length() <= 500,
"The generated empty PCK file shouldn't be too large.");
}
@@ -103,10 +103,10 @@ TEST_CASE("[PCKPacker] Pack a PCK file with some files and directories") {
err == OK,
"The generated non-empty PCK file should be opened successfully.");
CHECK_MESSAGE(
- f->get_len() >= 25000,
+ f->get_length() >= 25000,
"The generated non-empty PCK file should be large enough to actually hold the contents specified above.");
CHECK_MESSAGE(
- f->get_len() <= 35000,
+ f->get_length() <= 35000,
"The generated non-empty PCK file shouldn't be too large.");
}
} // namespace TestPCKPacker
diff --git a/tests/test_physics_2d.cpp b/tests/test_physics_2d.cpp
index 047697e314..a9e2e92b34 100644
--- a/tests/test_physics_2d.cpp
+++ b/tests/test_physics_2d.cpp
@@ -243,9 +243,7 @@ protected:
Size2 imgsize(5, 5); //vs->texture_get_width(body_shape_data[p_shape].image), vs->texture_get_height(body_shape_data[p_shape].image));
vs->canvas_item_add_texture_rect(sprite, Rect2(-imgsize / 2.0, imgsize), body_shape_data[p_shape].image);
- ps->body_set_force_integration_callback(body, this, "_body_moved", sprite);
- //RID q = ps->query_create(this,"_body_moved",sprite);
- //ps->query_body_state(q,body);
+ ps->body_set_force_integration_callback(body, callable_mp(this, &TestPhysics2DMainLoop::_body_moved), sprite);
return body;
}
@@ -310,7 +308,6 @@ protected:
}
static void _bind_methods() {
- ClassDB::bind_method(D_METHOD("_body_moved"), &TestPhysics2DMainLoop::_body_moved);
ClassDB::bind_method(D_METHOD("_ray_query_callback"), &TestPhysics2DMainLoop::_ray_query_callback);
}
@@ -323,7 +320,7 @@ public:
ps->space_set_active(space, true);
ps->set_active(true);
ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1));
- ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, 98);
+ ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, 980);
{
RID vp = vs->viewport_create();
diff --git a/tests/test_physics_3d.cpp b/tests/test_physics_3d.cpp
index bb324d8ffe..4488e4bf64 100644
--- a/tests/test_physics_3d.cpp
+++ b/tests/test_physics_3d.cpp
@@ -30,8 +30,8 @@
#include "test_physics_3d.h"
+#include "core/math/convex_hull.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/string/print_string.h"
@@ -70,18 +70,14 @@ class TestPhysics3DMainLoop : public MainLoop {
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();
+ Transform3D 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()) {
+ RID create_body(PhysicsServer3D::ShapeType p_shape, PhysicsServer3D::BodyMode p_body, const Transform3D p_location, bool p_active_default = true, const Transform3D &p_shape_xform = Transform3D()) {
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
@@ -93,7 +89,7 @@ protected:
ps->body_set_param(body, PhysicsServer3D::BODY_PARAM_BOUNCE, 0.0);
//todo set space
ps->body_add_shape(body, type_shape_map[p_shape]);
- ps->body_set_force_integration_callback(body, this, "body_changed_transform", mesh_instance);
+ ps->body_set_force_integration_callback(body, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance);
ps->body_set_state(body, PhysicsServer3D::BODY_STATE_TRANSFORM, p_location);
bodies.push_back(body);
@@ -173,7 +169,7 @@ protected:
RID convex_mesh = vs->mesh_create();
Geometry3D::MeshData convex_data = Geometry3D::build_convex_mesh(convex_planes);
- QuickHull::build(convex_data.vertices, convex_data);
+ ConvexHullComputer::convex_hull(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;
@@ -183,7 +179,7 @@ protected:
type_shape_map[PhysicsServer3D::SHAPE_CONVEX_POLYGON] = convex_shape;
}
- void make_trimesh(Vector<Vector3> p_faces, const Transform &p_xform = Transform()) {
+ void make_trimesh(Vector<Vector3> p_faces, const Transform3D &p_xform = Transform3D()) {
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
RID trimesh_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON);
@@ -213,12 +209,12 @@ protected:
ps->body_set_space(tribody, space);
//todo set space
ps->body_add_shape(tribody, trimesh_shape);
- Transform tritrans = p_xform;
+ Transform3D 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, real_t p_cellsize, real_t p_cellheight, const Transform &p_xform = Transform()) {
+ void make_grid(int p_width, int p_height, real_t p_cellsize, real_t p_cellheight, const Transform3D &p_xform = Transform3D()) {
Vector<Vector<real_t>> grid;
grid.resize(p_width);
@@ -265,7 +261,7 @@ public:
if (mover.is_valid()) {
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
- Transform t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM);
+ Transform3D 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);
@@ -291,7 +287,7 @@ public:
scenario = vs->scenario_create();
vs->light_set_shadow(lightaux, true);
light = vs->instance_create2(lightaux, scenario);
- Transform t;
+ Transform3D t;
t.rotate(Vector3(1.0, 0, 0), 0.6);
vs->instance_set_transform(light, t);
@@ -308,9 +304,9 @@ public:
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)));
+ vs->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 9, 12)));
- Transform gxf;
+ Transform3D 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);
@@ -321,12 +317,12 @@ public:
if (mover.is_valid()) {
static real_t joy_speed = 10;
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
- Transform t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM);
+ Transform3D 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;
+ Transform3D cameratr;
cameratr.rotate(Vector3(0, 1, 0), ofs_x);
cameratr.rotate(Vector3(1, 0, 0), -ofs_y);
cameratr.translate(Vector3(0, 2, 8));
@@ -359,21 +355,20 @@ public:
Dictionary capsule_params;
capsule_params["radius"] = 0.5;
capsule_params["height"] = 1;
- Transform shape_xform;
+ Transform3D 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();
- ps->body_set_mode(character, PhysicsServer3D::BODY_MODE_CHARACTER);
+ ps->body_set_mode(character, PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED);
ps->body_set_space(character, space);
//todo add space
ps->body_add_shape(character, capsule_shape);
+ ps->body_set_force_integration_callback(character, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance);
- 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)));
+ ps->body_set_state(character, PhysicsServer3D::BODY_STATE_TRANSFORM, Transform3D(Basis(), Vector3(-2, 5, -2)));
bodies.push_back(character);
}
@@ -388,19 +383,19 @@ public:
PhysicsServer3D::ShapeType type = shape_idx[i % 4];
- Transform t;
+ Transform3D 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_body(type, PhysicsServer3D::BODY_MODE_DYNAMIC, 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_body(PhysicsServer3D::SHAPE_BOX, PhysicsServer3D::BODY_MODE_DYNAMIC, Transform3D(Basis(), Vector3(0, 2, 0)), true);
create_static_plane(Plane(Vector3(0, 1, 0), -1));
}
diff --git a/tests/test_rect2.h b/tests/test_rect2.h
index b94a8b7d05..c5740167db 100644
--- a/tests/test_rect2.h
+++ b/tests/test_rect2.h
@@ -61,7 +61,7 @@ TEST_CASE("[Rect2] Constructor methods") {
TEST_CASE("[Rect2] String conversion") {
// Note: This also depends on the Vector2 string representation.
CHECK_MESSAGE(
- String(Rect2(0, 100, 1280, 720)) == "0, 100, 1280, 720",
+ String(Rect2(0, 100, 1280, 720)) == "[P: (0, 100), S: (1280, 720)]",
"The string representation should match the expected value.");
}
@@ -144,7 +144,7 @@ TEST_CASE("[Rect2] Absolute coordinates") {
"abs() should return the expected Rect2.");
}
-TEST_CASE("[Rect2] Intersecton") {
+TEST_CASE("[Rect2] Intersection") {
CHECK_MESSAGE(
Rect2(0, 100, 1280, 720).intersection(Rect2(0, 300, 100, 100)).is_equal_approx(Rect2(0, 300, 100, 100)),
"intersection() with fully enclosed Rect2 should return the expected result.");
@@ -273,7 +273,7 @@ TEST_CASE("[Rect2i] Constructor methods") {
TEST_CASE("[Rect2i] String conversion") {
// Note: This also depends on the Vector2 string representation.
CHECK_MESSAGE(
- String(Rect2i(0, 100, 1280, 720)) == "0, 100, 1280, 720",
+ String(Rect2i(0, 100, 1280, 720)) == "[P: (0, 100), S: (1280, 720)]",
"The string representation should match the expected value.");
}
@@ -312,19 +312,19 @@ TEST_CASE("[Rect2i] Basic setters") {
TEST_CASE("[Rect2i] Area getters") {
CHECK_MESSAGE(
- Math::is_equal_approx(Rect2i(0, 100, 1280, 720).get_area(), 921'600),
+ Rect2i(0, 100, 1280, 720).get_area() == 921'600,
"get_area() should return the expected value.");
CHECK_MESSAGE(
- Math::is_equal_approx(Rect2i(0, 100, -1280, -720).get_area(), 921'600),
+ Rect2i(0, 100, -1280, -720).get_area() == 921'600,
"get_area() should return the expected value.");
CHECK_MESSAGE(
- Math::is_equal_approx(Rect2i(0, 100, 1280, -720).get_area(), -921'600),
+ Rect2i(0, 100, 1280, -720).get_area() == -921'600,
"get_area() should return the expected value.");
CHECK_MESSAGE(
- Math::is_equal_approx(Rect2i(0, 100, -1280, 720).get_area(), -921'600),
+ Rect2i(0, 100, -1280, 720).get_area() == -921'600,
"get_area() should return the expected value.");
CHECK_MESSAGE(
- Math::is_zero_approx(Rect2i(0, 100, 0, 720).get_area()),
+ Rect2i(0, 100, 0, 720).get_area() == 0,
"get_area() should return the expected value.");
CHECK_MESSAGE(
diff --git a/tests/test_render.cpp b/tests/test_render.cpp
index 72b2840098..fe223ca258 100644
--- a/tests/test_render.cpp
+++ b/tests/test_render.cpp
@@ -30,8 +30,8 @@
#include "test_render.h"
+#include "core/math/convex_hull.h"
#include "core/math/math_funcs.h"
-#include "core/math/quick_hull.h"
#include "core/os/keyboard.h"
#include "core/os/main_loop.h"
#include "core/os/os.h"
@@ -53,7 +53,7 @@ class TestMainLoop : public MainLoop {
struct InstanceInfo {
RID instance;
- Transform base;
+ Transform3D base;
Vector3 rot_axis;
};
@@ -118,7 +118,7 @@ public:
vts.push_back(Vector3(-1, -1, -1));
Geometry3D::MeshData md;
- Error err = QuickHull::build(vts, md);
+ Error err = ConvexHullComputer::convex_hull(vts, md);
print_line("ERR: " + itos(err));
test_cube = vs->mesh_create();
vs->mesh_add_surface_from_mesh_data(test_cube, md);
@@ -165,7 +165,7 @@ public:
vs->viewport_set_active(viewport, true);
vs->viewport_attach_camera(viewport, camera);
vs->viewport_set_scenario(viewport, scenario);
- vs->camera_set_transform(camera, Transform(Basis(), Vector3(0, 3, 30)));
+ vs->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 3, 30)));
vs->camera_set_perspective(camera, 60, 0.1, 1000);
/*
@@ -182,7 +182,7 @@ public:
vs->light_set_color(lightaux, Color(1.0, 1.0, 1.0));
//vs->light_set_shadow( lightaux, true );
light = vs->instance_create2(lightaux, scenario);
- Transform lla;
+ Transform3D lla;
//lla.set_look_at(Vector3(),Vector3(1, -1, 1));
lla.set_look_at(Vector3(), Vector3(0.0, -0.836026, -0.548690));
@@ -201,7 +201,7 @@ public:
}
virtual bool iteration(float p_time) {
RenderingServer *vs = RenderingServer::get_singleton();
- //Transform t;
+ //Transform3D t;
//t.rotate(Vector3(0, 1, 0), ofs);
//t.translate(Vector3(0,0,20 ));
//vs->camera_set_transform(camera, t);
@@ -211,7 +211,7 @@ public:
//return quit;
for (List<InstanceInfo>::Element *E = instances.front(); E; E = E->next()) {
- Transform pre(Basis(E->get().rot_axis, ofs), Vector3());
+ Transform3D pre(Basis(E->get().rot_axis, ofs), Vector3());
vs->instance_set_transform(E->get().instance, pre * E->get().base);
/*
if( !E->next() ) {
diff --git a/tests/test_shader_lang.cpp b/tests/test_shader_lang.cpp
index 2169350c02..ad763b344e 100644
--- a/tests/test_shader_lang.cpp
+++ b/tests/test_shader_lang.cpp
@@ -30,7 +30,7 @@
#include "test_shader_lang.h"
-#include "core/os/file_access.h"
+#include "core/io/file_access.h"
#include "core/os/main_loop.h"
#include "core/os/os.h"
diff --git a/tests/test_string.h b/tests/test_string.h
index 6febf22765..7f404a34e8 100644
--- a/tests/test_string.h
+++ b/tests/test_string.h
@@ -299,6 +299,7 @@ TEST_CASE("[String] hex_encode_buffer") {
TEST_CASE("[String] Substr") {
String s = "Killer Baby";
CHECK(s.substr(3, 4) == "ler ");
+ CHECK(s.substr(3) == "ler Baby");
}
TEST_CASE("[String] Find") {
@@ -860,10 +861,10 @@ TEST_CASE("[String] match") {
}
TEST_CASE("[String] IPVX address to string") {
- IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
- IP_Address ip(0x0123, 0x4567, 0x89ab, 0xcdef, true);
- IP_Address ip2("fe80::52e5:49ff:fe93:1baf");
- IP_Address ip3("::ffff:192.168.0.1");
+ IPAddress ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+ IPAddress ip(0x0123, 0x4567, 0x89ab, 0xcdef, true);
+ IPAddress ip2("fe80::52e5:49ff:fe93:1baf");
+ IPAddress ip3("::ffff:192.168.0.1");
String ip4 = "192.168.0.1";
CHECK(ip4.is_valid_ip_address());
@@ -1045,7 +1046,7 @@ TEST_CASE("[String] lstrip and rstrip") {
TEST_CASE("[String] ensuring empty string into parse_utf8 passes empty string") {
String empty;
- CHECK(empty.parse_utf8(NULL, -1));
+ CHECK(empty.parse_utf8(nullptr, -1));
}
TEST_CASE("[String] Cyrillic to_lower()") {
@@ -1129,7 +1130,7 @@ TEST_CASE("[String] Path functions") {
CHECK(String(path[i]).get_basename() == base_name[i]);
CHECK(String(path[i]).get_extension() == ext[i]);
CHECK(String(path[i]).get_file() == file[i]);
- CHECK(String(path[i]).is_abs_path() == abs[i]);
+ CHECK(String(path[i]).is_absolute_path() == abs[i]);
CHECK(String(path[i]).is_rel_path() != abs[i]);
CHECK(String(path[i]).simplify_path().get_base_dir().plus_file(file[i]) == String(path[i]).simplify_path());
}
@@ -1156,6 +1157,17 @@ TEST_CASE("[String] uri_encode/unescape") {
String s = "Godot Engine:'docs'";
String t = "Godot%20Engine%3A%27docs%27";
+ String x1 = "T%C4%93%C5%A1t";
+ static const uint8_t u8str[] = { 0x54, 0xC4, 0x93, 0xC5, 0xA1, 0x74, 0x00 };
+ String x2 = String::utf8((const char *)u8str);
+ String x3 = U"Tēšt";
+
+ CHECK(x1.uri_decode() == x2);
+ CHECK(x1.uri_decode() == x3);
+ CHECK((x1 + x3).uri_decode() == (x2 + x3)); // Mixed unicode and URL encoded string, e.g. GTK+ bookmark.
+ CHECK(x2.uri_encode() == x1);
+ CHECK(x3.uri_encode() == x1);
+
CHECK(s.uri_encode() == t);
CHECK(t.uri_decode() == s);
}
@@ -1241,8 +1253,10 @@ TEST_CASE("[String] Trim") {
TEST_CASE("[String] Right/Left") {
String s = "aaaTestbbb";
// ^
- CHECK(s.right(6) == "tbbb");
+ CHECK(s.right(6) == "estbbb");
+ CHECK(s.right(-6) == "tbbb");
CHECK(s.left(6) == "aaaTes");
+ CHECK(s.left(-6) == "aaaT");
}
TEST_CASE("[String] Repeat") {
diff --git a/tests/test_time.h b/tests/test_time.h
new file mode 100644
index 0000000000..28f1cb2f20
--- /dev/null
+++ b/tests/test_time.h
@@ -0,0 +1,145 @@
+/*************************************************************************/
+/* test_time.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_TIME_H
+#define TEST_TIME_H
+
+#include "core/os/time.h"
+
+#include "thirdparty/doctest/doctest.h"
+
+#define YEAR_KEY "year"
+#define MONTH_KEY "month"
+#define DAY_KEY "day"
+#define WEEKDAY_KEY "weekday"
+#define HOUR_KEY "hour"
+#define MINUTE_KEY "minute"
+#define SECOND_KEY "second"
+#define DST_KEY "dst"
+
+namespace TestTime {
+
+TEST_CASE("[Time] Unix time conversion to/from datetime string") {
+ const Time *time = Time::get_singleton();
+
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1970-01-01T00:00:00") == 0, "Time get_unix_time_from_datetime_string: The timestamp for Unix epoch is zero.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1970-01-01 00:00:00") == 0, "Time get_unix_time_from_datetime_string: The timestamp for Unix epoch with space is zero.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1970-01-01") == 0, "Time get_unix_time_from_datetime_string: The timestamp for Unix epoch without time is zero.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("00:00:00") == 0, "Time get_unix_time_from_datetime_string: The timestamp for zero time without date is zero.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1969-12-31T23:59:59") == -1, "Time get_unix_time_from_datetime_string: The timestamp for just before Unix epoch is negative one.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1234-05-06T07:08:09") == -23215049511, "Time get_unix_time_from_datetime_string: The timestamp for an arbitrary datetime is as expected.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1234-05-06 07:08:09") == -23215049511, "Time get_unix_time_from_datetime_string: The timestamp for an arbitrary datetime with space is as expected.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1234-05-06") == -23215075200, "Time get_unix_time_from_datetime_string: The timestamp for an arbitrary date without time is as expected.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("07:08:09") == 25689, "Time get_unix_time_from_datetime_string: The timestamp for an arbitrary time without date is as expected.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("2014-02-09T22:10:30") == 1391983830, "Time get_unix_time_from_datetime_string: The timestamp for GODOT IS OPEN SOURCE is as expected.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("2014-02-09 22:10:30") == 1391983830, "Time get_unix_time_from_datetime_string: The timestamp for GODOT IS OPEN SOURCE with space is as expected.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("2014-02-09") == 1391904000, "Time get_unix_time_from_datetime_string: The date for GODOT IS OPEN SOURCE without time is as expected.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("22:10:30") == 79830, "Time get_unix_time_from_datetime_string: The time for GODOT IS OPEN SOURCE without date is as expected.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("-1000000000-01-01T00:00:00") == -31557014167219200, "Time get_unix_time_from_datetime_string: In the year negative a billion, Japan might not have been here.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1000000-01-01T00:00:00") == 31494784780800, "Time get_unix_time_from_datetime_string: The timestamp for the year a million is as expected.");
+
+ CHECK_MESSAGE(time->get_datetime_string_from_unix_time(0) == "1970-01-01T00:00:00", "Time get_datetime_string_from_unix_time: The timestamp string for Unix epoch is zero.");
+ CHECK_MESSAGE(time->get_datetime_string_from_unix_time(0, true) == "1970-01-01 00:00:00", "Time get_datetime_string_from_unix_time: The timestamp string for Unix epoch with space is zero.");
+ CHECK_MESSAGE(time->get_date_string_from_unix_time(0) == "1970-01-01", "Time get_date_string_from_unix_time: The date string for zero is Unix epoch date.");
+ CHECK_MESSAGE(time->get_time_string_from_unix_time(0) == "00:00:00", "Time get_time_string_from_unix_time: The date for zero zero is Unix epoch date.");
+ CHECK_MESSAGE(time->get_datetime_string_from_unix_time(-1) == "1969-12-31T23:59:59", "Time get_time_string_from_unix_time: The timestamp string for just before Unix epoch is as expected.");
+ CHECK_MESSAGE(time->get_datetime_string_from_unix_time(-23215049511) == "1234-05-06T07:08:09", "Time get_datetime_string_from_unix_time: The timestamp for an arbitrary datetime is as expected.");
+ CHECK_MESSAGE(time->get_datetime_string_from_unix_time(-23215049511, true) == "1234-05-06 07:08:09", "Time get_datetime_string_from_unix_time: The timestamp for an arbitrary datetime with space is as expected.");
+ CHECK_MESSAGE(time->get_date_string_from_unix_time(-23215075200) == "1234-05-06", "Time get_date_string_from_unix_time: The timestamp for an arbitrary date without time is as expected.");
+ CHECK_MESSAGE(time->get_time_string_from_unix_time(25689) == "07:08:09", "Time get_time_string_from_unix_time: The timestamp for an arbitrary time without date is as expected.");
+ CHECK_MESSAGE(time->get_datetime_string_from_unix_time(1391983830) == "2014-02-09T22:10:30", "Time get_datetime_string_from_unix_time: The timestamp for GODOT IS OPEN SOURCE is as expected.");
+ CHECK_MESSAGE(time->get_datetime_string_from_unix_time(1391983830, true) == "2014-02-09 22:10:30", "Time get_datetime_string_from_unix_time: The timestamp for GODOT IS OPEN SOURCE with space is as expected.");
+ CHECK_MESSAGE(time->get_date_string_from_unix_time(1391904000) == "2014-02-09", "Time get_date_string_from_unix_time: The date for GODOT IS OPEN SOURCE without time is as expected.");
+ CHECK_MESSAGE(time->get_time_string_from_unix_time(79830) == "22:10:30", "Time get_time_string_from_unix_time: The time for GODOT IS OPEN SOURCE without date is as expected.");
+ CHECK_MESSAGE(time->get_datetime_string_from_unix_time(31494784780800) == "1000000-01-01T00:00:00", "Time get_datetime_string_from_unix_time: The timestamp for the year a million is as expected.");
+}
+
+TEST_CASE("[Time] Datetime dictionary conversion methods") {
+ const Time *time = Time::get_singleton();
+
+ Dictionary datetime;
+ datetime[YEAR_KEY] = 2014;
+ datetime[MONTH_KEY] = 2;
+ datetime[DAY_KEY] = 9;
+ datetime[WEEKDAY_KEY] = Time::Weekday::WEEKDAY_SUNDAY;
+ datetime[HOUR_KEY] = 22;
+ datetime[MINUTE_KEY] = 10;
+ datetime[SECOND_KEY] = 30;
+
+ Dictionary date_only;
+ date_only[YEAR_KEY] = 2014;
+ date_only[MONTH_KEY] = 2;
+ date_only[DAY_KEY] = 9;
+ date_only[WEEKDAY_KEY] = Time::Weekday::WEEKDAY_SUNDAY;
+
+ Dictionary time_only;
+ time_only[HOUR_KEY] = 22;
+ time_only[MINUTE_KEY] = 10;
+ time_only[SECOND_KEY] = 30;
+
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(datetime) == 1391983830, "Time get_unix_time_from_datetime_dict: The datetime dictionary for GODOT IS OPEN SOURCE is converted to a timestamp as expected.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(date_only) == 1391904000, "Time get_unix_time_from_datetime_dict: The date dictionary for GODOT IS OPEN SOURCE is converted to a timestamp as expected.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(time_only) == 79830, "Time get_unix_time_from_datetime_dict: The time dictionary for GODOT IS OPEN SOURCE is converted to a timestamp as expected.");
+
+ CHECK_MESSAGE(time->get_datetime_dict_from_unix_time(1391983830).hash() == datetime.hash(), "Time get_datetime_dict_from_unix_time: The datetime timestamp for GODOT IS OPEN SOURCE is converted to a dictionary as expected.");
+ CHECK_MESSAGE(time->get_date_dict_from_unix_time(1391904000).hash() == date_only.hash(), "Time get_date_dict_from_unix_time: The date timestamp for GODOT IS OPEN SOURCE is converted to a dictionary as expected.");
+ CHECK_MESSAGE(time->get_time_dict_from_unix_time(79830).hash() == time_only.hash(), "Time get_time_dict_from_unix_time: The time timestamp for GODOT IS OPEN SOURCE is converted to a dictionary as expected.");
+
+ CHECK_MESSAGE((Time::Weekday)(int)time->get_datetime_dict_from_unix_time(0)[WEEKDAY_KEY] == Time::Weekday::WEEKDAY_THURSDAY, "Time get_datetime_dict_from_unix_time: The weekday for the Unix epoch is a Thursday as expected.");
+ CHECK_MESSAGE((Time::Weekday)(int)time->get_datetime_dict_from_unix_time(1391983830)[WEEKDAY_KEY] == Time::Weekday::WEEKDAY_SUNDAY, "Time get_datetime_dict_from_unix_time: The weekday for GODOT IS OPEN SOURCE is a Sunday as expected.");
+
+ CHECK_MESSAGE(time->get_datetime_dict_from_string("2014-02-09T22:10:30").hash() == datetime.hash(), "Time get_datetime_dict_from_string: The dictionary from string for GODOT IS OPEN SOURCE works as expected.");
+ CHECK_MESSAGE(!time->get_datetime_dict_from_string("2014-02-09T22:10:30", false).has(WEEKDAY_KEY), "Time get_datetime_dict_from_string: The dictionary from string for GODOT IS OPEN SOURCE without weekday doesn't contain the weekday key as expected.");
+ CHECK_MESSAGE(time->get_datetime_string_from_dict(datetime) == "2014-02-09T22:10:30", "Time get_datetime_string_from_dict: The string from dictionary for GODOT IS OPEN SOURCE works as expected.");
+ CHECK_MESSAGE(time->get_datetime_string_from_dict(time->get_datetime_dict_from_string("2014-02-09T22:10:30")) == "2014-02-09T22:10:30", "Time get_datetime_string_from_dict: The round-trip string to dict to string GODOT IS OPEN SOURCE works as expected.");
+ CHECK_MESSAGE(time->get_datetime_string_from_dict(time->get_datetime_dict_from_string("2014-02-09 22:10:30"), true) == "2014-02-09 22:10:30", "Time get_datetime_string_from_dict: The round-trip string to dict to string GODOT IS OPEN SOURCE with spaces works as expected.");
+}
+
+TEST_CASE("[Time] System time methods") {
+ const Time *time = Time::get_singleton();
+
+ const uint64_t ticks_msec = time->get_ticks_msec();
+ const uint64_t ticks_usec = time->get_ticks_usec();
+
+ CHECK_MESSAGE(time->get_unix_time_from_system() > 1000000000, "Time get_unix_time_from_system: The timestamp from system time doesn't fail and is very positive.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(time->get_datetime_dict_from_system()) > 1000000000, "Time get_datetime_string_from_system: The timestamp from system time doesn't fail and is very positive.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(time->get_date_dict_from_system()) > 1000000000, "Time get_datetime_string_from_system: The date from system time doesn't fail and is very positive.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(time->get_time_dict_from_system()) < 86400, "Time get_datetime_string_from_system: The time from system time doesn't fail and is within the acceptable range.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string(time->get_datetime_string_from_system()) > 1000000000, "Time get_datetime_string_from_system: The timestamp from system time doesn't fail and is very positive.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string(time->get_date_string_from_system()) > 1000000000, "Time get_datetime_string_from_system: The date from system time doesn't fail and is very positive.");
+ CHECK_MESSAGE(time->get_unix_time_from_datetime_string(time->get_time_string_from_system()) < 86400, "Time get_datetime_string_from_system: The time from system time doesn't fail and is within the acceptable range.");
+
+ CHECK_MESSAGE(time->get_ticks_msec() >= ticks_msec, "Time get_ticks_msec: The value has not decreased.");
+ CHECK_MESSAGE(time->get_ticks_usec() > ticks_usec, "Time get_ticks_usec: The value has increased.");
+}
+
+} // namespace TestTime
+
+#endif // TEST_TIME_H
diff --git a/tests/test_translation.h b/tests/test_translation.h
new file mode 100644
index 0000000000..52ff49bf9b
--- /dev/null
+++ b/tests/test_translation.h
@@ -0,0 +1,150 @@
+/*************************************************************************/
+/* test_translation.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_TRANSLATION_H
+#define TEST_TRANSLATION_H
+
+#include "core/string/optimized_translation.h"
+#include "core/string/translation.h"
+#include "core/string/translation_po.h"
+
+#include "thirdparty/doctest/doctest.h"
+
+namespace TestTranslation {
+
+TEST_CASE("[Translation] Messages") {
+ Ref<Translation> translation = memnew(Translation);
+ translation->set_locale("fr");
+ translation->add_message("Hello", "Bonjour");
+ CHECK(translation->get_message("Hello") == "Bonjour");
+
+ translation->erase_message("Hello");
+ // The message no longer exists, so it returns an empty string instead.
+ CHECK(translation->get_message("Hello") == "");
+
+ List<StringName> messages;
+ translation->get_message_list(&messages);
+ CHECK(translation->get_message_count() == 0);
+ CHECK(messages.size() == 0);
+
+ translation->add_message("Hello2", "Bonjour2");
+ translation->add_message("Hello3", "Bonjour3");
+ messages.clear();
+ translation->get_message_list(&messages);
+ CHECK(translation->get_message_count() == 2);
+ CHECK(messages.size() == 2);
+ // Messages are stored in a Map, don't assume ordering.
+ CHECK(messages.find("Hello2"));
+ CHECK(messages.find("Hello3"));
+}
+
+TEST_CASE("[TranslationPO] Messages with context") {
+ Ref<TranslationPO> translation = memnew(TranslationPO);
+ translation->set_locale("fr");
+ translation->add_message("Hello", "Bonjour");
+ translation->add_message("Hello", "Salut", "friendly");
+ CHECK(translation->get_message("Hello") == "Bonjour");
+ CHECK(translation->get_message("Hello", "friendly") == "Salut");
+ CHECK(translation->get_message("Hello", "nonexistent_context") == "");
+
+ // Only remove the message for the default context, not the "friendly" context.
+ translation->erase_message("Hello");
+ // The message no longer exists, so it returns an empty string instead.
+ CHECK(translation->get_message("Hello") == "");
+ CHECK(translation->get_message("Hello", "friendly") == "Salut");
+ CHECK(translation->get_message("Hello", "nonexistent_context") == "");
+
+ List<StringName> messages;
+ translation->get_message_list(&messages);
+
+ // `get_message_count()` takes all contexts into account.
+ CHECK(translation->get_message_count() == 1);
+ // Only the default context is taken into account.
+ // Since "Hello" is now only present in a non-default context, it is not counted in the list of messages.
+ CHECK(messages.size() == 0);
+
+ translation->add_message("Hello2", "Bonjour2");
+ translation->add_message("Hello2", "Salut2", "friendly");
+ translation->add_message("Hello3", "Bonjour3");
+ messages.clear();
+ translation->get_message_list(&messages);
+
+ // `get_message_count()` takes all contexts into account.
+ CHECK(translation->get_message_count() == 4);
+ // Only the default context is taken into account.
+ CHECK(messages.size() == 2);
+ // Messages are stored in a Map, don't assume ordering.
+ CHECK(messages.find("Hello2"));
+ CHECK(messages.find("Hello3"));
+}
+
+TEST_CASE("[TranslationPO] Plural messages") {
+ Ref<TranslationPO> translation = memnew(TranslationPO);
+ translation->set_locale("fr");
+ translation->set_plural_rule("Plural-Forms: nplurals=2; plural=(n >= 2);");
+ CHECK(translation->get_plural_forms() == 2);
+
+ PackedStringArray plurals;
+ plurals.push_back("Il y a %d pomme");
+ plurals.push_back("Il y a %d pommes");
+ translation->add_plural_message("There are %d apples", plurals);
+ ERR_PRINT_OFF;
+ // This is invalid, as the number passed to `get_plural_message()` may not be negative.
+ CHECK(vformat(translation->get_plural_message("There are %d apples", "", -1), -1) == "");
+ ERR_PRINT_ON;
+ CHECK(vformat(translation->get_plural_message("There are %d apples", "", 0), 0) == "Il y a 0 pomme");
+ CHECK(vformat(translation->get_plural_message("There are %d apples", "", 1), 1) == "Il y a 1 pomme");
+ CHECK(vformat(translation->get_plural_message("There are %d apples", "", 2), 2) == "Il y a 2 pommes");
+}
+
+TEST_CASE("[OptimizedTranslation] Generate from Translation and read messages") {
+ Ref<Translation> translation = memnew(Translation);
+ translation->set_locale("fr");
+ translation->add_message("Hello", "Bonjour");
+ translation->add_message("Hello2", "Bonjour2");
+ translation->add_message("Hello3", "Bonjour3");
+
+ Ref<OptimizedTranslation> optimized_translation = memnew(OptimizedTranslation);
+ optimized_translation->generate(translation);
+ CHECK(optimized_translation->get_message("Hello") == "Bonjour");
+ CHECK(optimized_translation->get_message("Hello2") == "Bonjour2");
+ CHECK(optimized_translation->get_message("Hello3") == "Bonjour3");
+ CHECK(optimized_translation->get_message("DoesNotExist") == "");
+
+ List<StringName> messages;
+ // `get_message_list()` can't return the list of messages stored in an OptimizedTranslation.
+ optimized_translation->get_message_list(&messages);
+ CHECK(optimized_translation->get_message_count() == 0);
+ CHECK(messages.size() == 0);
+}
+
+} // namespace TestTranslation
+
+#endif // TEST_TRANSLATION_H
diff --git a/tests/test_validate_testing.h b/tests/test_validate_testing.h
index 6d3eea724c..f301047509 100644
--- a/tests/test_validate_testing.h
+++ b/tests/test_validate_testing.h
@@ -84,7 +84,7 @@ TEST_SUITE("Validate tests") {
Plane plane(Vector3(1, 1, 1), 1.0);
INFO(plane);
- Quat quat(Vector3(0.5, 1.0, 2.0));
+ Quaternion quat(Vector3(0.5, 1.0, 2.0));
INFO(quat);
AABB aabb(Vector3(), Vector3(100, 100, 100));
@@ -93,7 +93,7 @@ TEST_SUITE("Validate tests") {
Basis basis(quat);
INFO(basis);
- Transform trans(basis);
+ Transform3D trans(basis);
INFO(trans);
Color color(1, 0.5, 0.2, 0.3);
diff --git a/tests/test_vector.h b/tests/test_vector.h
new file mode 100644
index 0000000000..02c56e59f6
--- /dev/null
+++ b/tests/test_vector.h
@@ -0,0 +1,496 @@
+/*************************************************************************/
+/* test_vector.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_VECTOR_H
+#define TEST_VECTOR_H
+
+#include "core/templates/vector.h"
+
+#include "tests/test_macros.h"
+
+namespace TestVector {
+
+TEST_CASE("[Vector] Push back and append") {
+ Vector<int> vector;
+ vector.push_back(0);
+ vector.push_back(1);
+ vector.push_back(2);
+ vector.push_back(3);
+ // Alias for `push_back`.
+ vector.append(4);
+
+ CHECK(vector[0] == 0);
+ CHECK(vector[1] == 1);
+ CHECK(vector[2] == 2);
+ CHECK(vector[3] == 3);
+ CHECK(vector[4] == 4);
+}
+
+TEST_CASE("[Vector] Append array") {
+ Vector<int> vector;
+ vector.push_back(1);
+ vector.push_back(2);
+
+ Vector<int> vector_other;
+ vector_other.push_back(128);
+ vector_other.push_back(129);
+ vector.append_array(vector_other);
+
+ CHECK(vector.size() == 4);
+ CHECK(vector[0] == 1);
+ CHECK(vector[1] == 2);
+ CHECK(vector[2] == 128);
+ CHECK(vector[3] == 129);
+}
+
+TEST_CASE("[Vector] Insert") {
+ Vector<int> vector;
+ vector.insert(0, 2);
+ vector.insert(0, 8);
+ vector.insert(2, 5);
+ vector.insert(1, 5);
+ vector.insert(0, -2);
+
+ CHECK(vector.size() == 5);
+ CHECK(vector[0] == -2);
+ CHECK(vector[1] == 8);
+ CHECK(vector[2] == 5);
+ CHECK(vector[3] == 2);
+ CHECK(vector[4] == 5);
+}
+
+TEST_CASE("[Vector] Ordered insert") {
+ Vector<int> vector;
+ vector.ordered_insert(2);
+ vector.ordered_insert(8);
+ vector.ordered_insert(5);
+ vector.ordered_insert(5);
+ vector.ordered_insert(-2);
+
+ CHECK(vector.size() == 5);
+ CHECK(vector[0] == -2);
+ CHECK(vector[1] == 2);
+ CHECK(vector[2] == 5);
+ CHECK(vector[3] == 5);
+ CHECK(vector[4] == 8);
+}
+
+TEST_CASE("[Vector] Insert + Ordered insert") {
+ Vector<int> vector;
+ vector.ordered_insert(2);
+ vector.ordered_insert(8);
+ vector.insert(0, 5);
+ vector.ordered_insert(5);
+ vector.insert(1, -2);
+
+ CHECK(vector.size() == 5);
+ CHECK(vector[0] == 5);
+ CHECK(vector[1] == -2);
+ CHECK(vector[2] == 2);
+ CHECK(vector[3] == 5);
+ CHECK(vector[4] == 8);
+}
+
+TEST_CASE("[Vector] Fill large array and modify it") {
+ Vector<int> vector;
+ vector.resize(1'000'000);
+ vector.fill(0x60d07);
+
+ vector.write[200] = 0;
+ CHECK(vector.size() == 1'000'000);
+ CHECK(vector[0] == 0x60d07);
+ CHECK(vector[200] == 0);
+ CHECK(vector[499'999] == 0x60d07);
+ CHECK(vector[999'999] == 0x60d07);
+ vector.remove(200);
+ CHECK(vector[200] == 0x60d07);
+
+ vector.clear();
+ CHECK(vector.size() == 0);
+}
+
+TEST_CASE("[Vector] Copy creation") {
+ Vector<int> vector;
+ vector.push_back(0);
+ vector.push_back(1);
+ vector.push_back(2);
+ vector.push_back(3);
+ vector.push_back(4);
+
+ Vector<int> vector_other = Vector<int>(vector);
+ vector_other.remove(0);
+ CHECK(vector_other[0] == 1);
+ CHECK(vector_other[1] == 2);
+ CHECK(vector_other[2] == 3);
+ CHECK(vector_other[3] == 4);
+
+ // Make sure the original vector isn't modified.
+ CHECK(vector[0] == 0);
+ CHECK(vector[1] == 1);
+ CHECK(vector[2] == 2);
+ CHECK(vector[3] == 3);
+ CHECK(vector[4] == 4);
+}
+
+TEST_CASE("[Vector] Duplicate") {
+ Vector<int> vector;
+ vector.push_back(0);
+ vector.push_back(1);
+ vector.push_back(2);
+ vector.push_back(3);
+ vector.push_back(4);
+
+ Vector<int> vector_other = vector.duplicate();
+ vector_other.remove(0);
+ CHECK(vector_other[0] == 1);
+ CHECK(vector_other[1] == 2);
+ CHECK(vector_other[2] == 3);
+ CHECK(vector_other[3] == 4);
+
+ // Make sure the original vector isn't modified.
+ CHECK(vector[0] == 0);
+ CHECK(vector[1] == 1);
+ CHECK(vector[2] == 2);
+ CHECK(vector[3] == 3);
+ CHECK(vector[4] == 4);
+}
+
+TEST_CASE("[Vector] Get, set") {
+ Vector<int> vector;
+ vector.push_back(0);
+ vector.push_back(1);
+ vector.push_back(2);
+ vector.push_back(3);
+ vector.push_back(4);
+
+ CHECK(vector.get(0) == 0);
+ CHECK(vector.get(1) == 1);
+ vector.set(2, 256);
+ CHECK(vector.get(2) == 256);
+ CHECK(vector.get(3) == 3);
+
+ ERR_PRINT_OFF;
+ // Invalid (but should not crash): setting out of bounds.
+ vector.set(6, 500);
+ ERR_PRINT_ON;
+
+ CHECK(vector.get(4) == 4);
+}
+
+TEST_CASE("[Vector] To byte array") {
+ Vector<int> vector;
+ vector.push_back(0);
+ vector.push_back(-1);
+ vector.push_back(2008);
+ vector.push_back(999999999);
+
+ Vector<uint8_t> byte_array = vector.to_byte_array();
+ CHECK(byte_array.size() == 16);
+ // vector[0]
+ CHECK(byte_array[0] == 0);
+ CHECK(byte_array[1] == 0);
+ CHECK(byte_array[2] == 0);
+ CHECK(byte_array[3] == 0);
+
+ // vector[1]
+ CHECK(byte_array[4] == 255);
+ CHECK(byte_array[5] == 255);
+ CHECK(byte_array[6] == 255);
+ CHECK(byte_array[7] == 255);
+
+ // vector[2]
+ CHECK(byte_array[8] == 216);
+ CHECK(byte_array[9] == 7);
+ CHECK(byte_array[10] == 0);
+ CHECK(byte_array[11] == 0);
+
+ // vector[3]
+ CHECK(byte_array[12] == 255);
+ CHECK(byte_array[13] == 201);
+ CHECK(byte_array[14] == 154);
+ CHECK(byte_array[15] == 59);
+}
+
+TEST_CASE("[Vector] Subarray") {
+ Vector<int> vector;
+ vector.push_back(0);
+ vector.push_back(1);
+ vector.push_back(2);
+ vector.push_back(3);
+ vector.push_back(4);
+
+ Vector<int> subarray1 = vector.subarray(1, 2);
+ CHECK(subarray1.size() == 2);
+ CHECK(subarray1[0] == 1);
+ CHECK(subarray1[1] == 2);
+
+ Vector<int> subarray2 = vector.subarray(1, -1);
+ CHECK(subarray2.size() == 4);
+ CHECK(subarray2[0] == 1);
+ CHECK(subarray2[1] == 2);
+ CHECK(subarray2[2] == 3);
+ CHECK(subarray2[3] == 4);
+
+ Vector<int> subarray3 = vector.subarray(-2, -1);
+ CHECK(subarray3.size() == 2);
+ CHECK(subarray3[0] == 3);
+ CHECK(subarray3[1] == 4);
+
+ Vector<int> subarray4 = vector.subarray(-3, 3);
+ CHECK(subarray4.size() == 2);
+ CHECK(subarray4[0] == 2);
+ CHECK(subarray4[1] == 3);
+}
+
+TEST_CASE("[Vector] Find, has") {
+ Vector<int> vector;
+ vector.push_back(3);
+ vector.push_back(1);
+ vector.push_back(4);
+ vector.push_back(0);
+ vector.push_back(2);
+
+ CHECK(vector[0] == 3);
+ CHECK(vector[1] == 1);
+ CHECK(vector[2] == 4);
+ CHECK(vector[3] == 0);
+ CHECK(vector[4] == 2);
+
+ CHECK(vector.find(0) == 3);
+ CHECK(vector.find(1) == 1);
+ CHECK(vector.find(2) == 4);
+ CHECK(vector.find(3) == 0);
+ CHECK(vector.find(4) == 2);
+
+ CHECK(vector.find(-1) == -1);
+ CHECK(vector.find(5) == -1);
+
+ CHECK(vector.has(0));
+ CHECK(vector.has(1));
+ CHECK(vector.has(2));
+ CHECK(vector.has(3));
+ CHECK(vector.has(4));
+
+ CHECK(!vector.has(-1));
+ CHECK(!vector.has(5));
+}
+
+TEST_CASE("[Vector] Remove") {
+ Vector<int> vector;
+ vector.push_back(0);
+ vector.push_back(1);
+ vector.push_back(2);
+ vector.push_back(3);
+ vector.push_back(4);
+
+ vector.remove(0);
+
+ CHECK(vector[0] == 1);
+ CHECK(vector[1] == 2);
+ CHECK(vector[2] == 3);
+ CHECK(vector[3] == 4);
+
+ vector.remove(2);
+
+ CHECK(vector[0] == 1);
+ CHECK(vector[1] == 2);
+ CHECK(vector[2] == 4);
+
+ vector.remove(1);
+
+ CHECK(vector[0] == 1);
+ CHECK(vector[1] == 4);
+
+ vector.remove(0);
+
+ CHECK(vector[0] == 4);
+}
+
+TEST_CASE("[Vector] Remove and find") {
+ Vector<int> vector;
+ vector.push_back(0);
+ vector.push_back(1);
+ vector.push_back(2);
+ vector.push_back(3);
+ vector.push_back(4);
+
+ CHECK(vector.size() == 5);
+
+ vector.remove(0);
+
+ CHECK(vector.size() == 4);
+
+ CHECK(vector.find(0) == -1);
+ CHECK(vector.find(1) != -1);
+ CHECK(vector.find(2) != -1);
+ CHECK(vector.find(3) != -1);
+ CHECK(vector.find(4) != -1);
+
+ vector.remove(vector.find(3));
+
+ CHECK(vector.size() == 3);
+
+ CHECK(vector.find(3) == -1);
+ CHECK(vector.find(1) != -1);
+ CHECK(vector.find(2) != -1);
+ CHECK(vector.find(4) != -1);
+
+ vector.remove(vector.find(2));
+
+ CHECK(vector.size() == 2);
+
+ CHECK(vector.find(2) == -1);
+ CHECK(vector.find(1) != -1);
+ CHECK(vector.find(4) != -1);
+
+ vector.remove(vector.find(4));
+
+ CHECK(vector.size() == 1);
+
+ CHECK(vector.find(4) == -1);
+ CHECK(vector.find(1) != -1);
+
+ vector.remove(0);
+
+ CHECK(vector.is_empty());
+ CHECK(vector.size() == 0);
+}
+
+TEST_CASE("[Vector] Erase") {
+ Vector<int> vector;
+ vector.push_back(1);
+ vector.push_back(3);
+ vector.push_back(0);
+ vector.push_back(2);
+ vector.push_back(4);
+
+ CHECK(vector.find(2) == 3);
+
+ vector.erase(2);
+
+ CHECK(vector.find(2) == -1);
+ CHECK(vector.size() == 4);
+}
+
+TEST_CASE("[Vector] Size, resize, reserve") {
+ Vector<int> vector;
+ CHECK(vector.is_empty());
+ CHECK(vector.size() == 0);
+
+ vector.resize(10);
+
+ CHECK(vector.size() == 10);
+
+ vector.resize(5);
+
+ CHECK(vector.size() == 5);
+
+ vector.remove(0);
+ vector.remove(0);
+ vector.remove(0);
+
+ CHECK(vector.size() == 2);
+
+ vector.clear();
+
+ CHECK(vector.size() == 0);
+ CHECK(vector.is_empty());
+
+ vector.push_back(0);
+ vector.push_back(0);
+ vector.push_back(0);
+
+ CHECK(vector.size() == 3);
+
+ vector.push_back(0);
+
+ CHECK(vector.size() == 4);
+}
+
+TEST_CASE("[Vector] Sort") {
+ Vector<int> vector;
+ vector.push_back(2);
+ vector.push_back(8);
+ vector.push_back(-4);
+ vector.push_back(5);
+ vector.sort();
+
+ CHECK(vector.size() == 4);
+ CHECK(vector[0] == -4);
+ CHECK(vector[1] == 2);
+ CHECK(vector[2] == 5);
+ CHECK(vector[3] == 8);
+}
+
+TEST_CASE("[Vector] Sort custom") {
+ Vector<String> vector;
+ vector.push_back("world");
+ vector.push_back("World");
+ vector.push_back("Hello");
+ vector.push_back("10Hello");
+ vector.push_back("12Hello");
+ vector.push_back("01Hello");
+ vector.push_back("1Hello");
+ vector.push_back(".Hello");
+ vector.sort_custom<NaturalNoCaseComparator>();
+
+ CHECK(vector.size() == 8);
+ CHECK(vector[0] == ".Hello");
+ CHECK(vector[1] == "01Hello");
+ CHECK(vector[2] == "1Hello");
+ CHECK(vector[3] == "10Hello");
+ CHECK(vector[4] == "12Hello");
+ CHECK(vector[5] == "Hello");
+ CHECK(vector[6] == "world");
+ CHECK(vector[7] == "World");
+}
+
+TEST_CASE("[Vector] Operators") {
+ Vector<int> vector;
+ vector.push_back(2);
+ vector.push_back(8);
+ vector.push_back(-4);
+ vector.push_back(5);
+
+ Vector<int> vector_other;
+ vector_other.push_back(2);
+ vector_other.push_back(8);
+ vector_other.push_back(-4);
+ vector_other.push_back(5);
+
+ CHECK(vector == vector_other);
+
+ vector_other.push_back(10);
+ CHECK(vector != vector_other);
+}
+
+} // namespace TestVector
+
+#endif // TEST_VECTOR_H
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 33ce2423d9..03a2ddf5e4 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -8,13 +8,12 @@ readability.
## basis_universal
- Upstream: https://github.com/BinomialLLC/basis_universal
-- Version: git (895ee8ee7e04f22267f8d16d46de04d5a01d63ac, 2020)
+- Version: git (ba1c3e40f1d434ebaf9a167b44e9b11d2bf0f765, 2021)
- License: Apache 2.0
Files extracted from upstream source:
-- `.cpp` and `.h` files in root folder except for `basisu_tool.cpp` (contains `main` and can cause link error)
-- `.cpp`, `.h` and `.inc` files in `transcoder/`, keeping folder structure
+- `encoder/` and `transcoder/` folders
- `LICENSE`
@@ -62,6 +61,26 @@ Files extracted from upstream source:
Extracted from .zip provided. Extracted license and header only.
+## embree
+
+- Upstream: https://github.com/embree/embree
+- Version: 3.13.0 (7c53133eb21424f7f0ae1e25bf357e358feaf6ab, 2021)
+- License: Apache 2.0
+
+Files extracted from upstream:
+
+- All cpp files listed in `modules/raycast/godot_update_embree.py`
+- All header files in the directories listed in `modules/raycast/godot_update_embree.py`
+
+The `modules/raycast/godot_update_embree.py` script can be used to pull the
+relevant files from the latest Embree release and apply some automatic changes.
+
+Some changes have been made in order to remove exceptions and fix minor build errors.
+They are marked with `// -- GODOT start --` and `// -- GODOT end --`
+comments. Apply the patches in the `patches/` folder when syncing on newer upstream
+commits.
+
+
## enet
- Upstream: http://enet.bespin.org
@@ -118,6 +137,10 @@ Files extracted from upstream source:
* Upstream: https://android.googlesource.com/platform/frameworks/base/+/master/data/fonts/
* Version: ? (pre-2014 commit when DroidSansJapanese.ttf was obsoleted)
* License: Apache 2.0
+- `OpenSans_SemiBold.ttf`:
+ * Upstream: https://fonts.google.com/specimen/Open+Sans
+ * Version: 1.10 (downloaded from Google Fonts in February 2021)
+ * License: Apache 2.0
- `Tamsyn*.png`:
* Upstream: http://www.fial.com/~scott/tamsyn-font/
* Version: 1.11 (2015)
@@ -186,17 +209,17 @@ Files extracted from upstream source:
## icu4c
- Upstream: https://github.com/unicode-org/icu
-- Version: 68.2 (84e1f26ea77152936e70d53178a816dbfbf69989, 2020)
+- Version: 69.1 (0e7b4428866f3133b4abba2d932ee3faa708db1d, 2021)
- License: Unicode
Files extracted from upstream source:
- the `common` folder
-- `APIChangeReport.md`, `LICENSE`
+- `LICENSE`
Files generated from upstream source:
-- the `icudt68l.dat` built with the provided `godot_data.json` config file (see
+- the `icudt69l.dat` built with the provided `godot_data.json` config file (see
https://github.com/unicode-org/icu/blob/master/docs/userguide/icu_data/buildtool.md
for instructions)
@@ -344,7 +367,7 @@ File extracted from upstream release tarball:
## meshoptimizer
- Upstream: https://github.com/zeux/meshoptimizer
-- Version: 0.16 (95893c0566646434dd675b708d293fcb2d526d08, 2021)
+- Version: git (f5d83e879c48f8664783a69b4f50711d27549b66, 2021)
- License: MIT
Files extracted from upstream repository:
@@ -352,6 +375,9 @@ Files extracted from upstream repository:
- All files in `src/`.
- `LICENSE.md`.
+An [experimental upstream feature](https://github.com/zeux/meshoptimizer/tree/simplify-attr),
+has been backported, see patch in `patches` directory.
+
## miniupnpc
@@ -443,6 +469,10 @@ Collection of single-file libraries used in Godot components.
* Version: git (2f625846a775501fb69456567409a8b12f10ea25, 2012)
* License: BSD-3-Clause
* Modifications: use `const char*` instead of `char*` for input string
+- `smolv.h`
+ * Upstream: https://github.com/aras-p/smol-v
+ * Version: git (4b52c165c13763051a18e80ffbc2ee436314ceb2, 2020)
+ * License: Public Domain or MIT
- `stb_rect_pack.h`
* Upstream: https://github.com/nothings/stb
* Version: 1.00 (2bb4a0accd4003c1db4c24533981e01b1adfd656, 2019)
@@ -705,3 +735,4 @@ Files extracted from upstream source:
- lib/{common/,compress/,decompress/,zstd.h}
- LICENSE
+
diff --git a/thirdparty/basis_universal/basisu_comp.cpp b/thirdparty/basis_universal/basisu_comp.cpp
deleted file mode 100644
index 1e4679311c..0000000000
--- a/thirdparty/basis_universal/basisu_comp.cpp
+++ /dev/null
@@ -1,1206 +0,0 @@
-// basisu_comp.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#include "basisu_comp.h"
-#include "basisu_enc.h"
-#include <unordered_set>
-
-#define BASISU_USE_STB_IMAGE_RESIZE_FOR_MIPMAP_GEN 0
-#define DEBUG_CROP_TEXTURE_TO_64x64 (0)
-#define DEBUG_RESIZE_TEXTURE (0)
-#define DEBUG_EXTRACT_SINGLE_BLOCK (0)
-
-namespace basisu
-{
- basis_compressor::basis_compressor() :
- m_total_blocks(0),
- m_auto_global_sel_pal(false),
- m_basis_file_size(0),
- m_basis_bits_per_texel(0),
- m_any_source_image_has_alpha(false)
- {
- debug_printf("basis_compressor::basis_compressor\n");
- }
-
- bool basis_compressor::init(const basis_compressor_params &params)
- {
- debug_printf("basis_compressor::init\n");
-
- m_params = params;
-
- if (m_params.m_debug)
- {
- debug_printf("basis_compressor::init:\n");
-
-#define PRINT_BOOL_VALUE(v) debug_printf("%s: %u %u\n", BASISU_STRINGIZE2(v), static_cast<int>(m_params.v), m_params.v.was_changed());
-#define PRINT_INT_VALUE(v) debug_printf("%s: %i %u\n", BASISU_STRINGIZE2(v), static_cast<int>(m_params.v), m_params.v.was_changed());
-#define PRINT_UINT_VALUE(v) debug_printf("%s: %u %u\n", BASISU_STRINGIZE2(v), static_cast<uint32_t>(m_params.v), m_params.v.was_changed());
-#define PRINT_FLOAT_VALUE(v) debug_printf("%s: %f %u\n", BASISU_STRINGIZE2(v), static_cast<float>(m_params.v), m_params.v.was_changed());
-
- debug_printf("Has global selector codebook: %i\n", m_params.m_pSel_codebook != nullptr);
-
- debug_printf("Source images: %u, source filenames: %u, source alpha filenames: %i\n",
- (uint32_t)m_params.m_source_images.size(), (uint32_t)m_params.m_source_filenames.size(), (uint32_t)m_params.m_source_alpha_filenames.size());
-
- PRINT_BOOL_VALUE(m_y_flip);
- PRINT_BOOL_VALUE(m_debug);
- PRINT_BOOL_VALUE(m_debug_images);
- PRINT_BOOL_VALUE(m_global_sel_pal);
- PRINT_BOOL_VALUE(m_auto_global_sel_pal);
- PRINT_BOOL_VALUE(m_compression_level);
- PRINT_BOOL_VALUE(m_no_hybrid_sel_cb);
- PRINT_BOOL_VALUE(m_perceptual);
- PRINT_BOOL_VALUE(m_no_endpoint_rdo);
- PRINT_BOOL_VALUE(m_no_selector_rdo);
- PRINT_BOOL_VALUE(m_read_source_images);
- PRINT_BOOL_VALUE(m_write_output_basis_files);
- PRINT_BOOL_VALUE(m_compute_stats);
- PRINT_BOOL_VALUE(m_check_for_alpha)
- PRINT_BOOL_VALUE(m_force_alpha)
- PRINT_BOOL_VALUE(m_seperate_rg_to_color_alpha);
- PRINT_BOOL_VALUE(m_multithreading);
- PRINT_BOOL_VALUE(m_disable_hierarchical_endpoint_codebooks);
-
- PRINT_FLOAT_VALUE(m_hybrid_sel_cb_quality_thresh);
-
- PRINT_INT_VALUE(m_global_pal_bits);
- PRINT_INT_VALUE(m_global_mod_bits);
-
- PRINT_FLOAT_VALUE(m_endpoint_rdo_thresh);
- PRINT_FLOAT_VALUE(m_selector_rdo_thresh);
-
- PRINT_BOOL_VALUE(m_mip_gen);
- PRINT_BOOL_VALUE(m_mip_renormalize);
- PRINT_BOOL_VALUE(m_mip_wrapping);
- PRINT_BOOL_VALUE(m_mip_srgb);
- PRINT_FLOAT_VALUE(m_mip_premultiplied);
- PRINT_FLOAT_VALUE(m_mip_scale);
- PRINT_INT_VALUE(m_mip_smallest_dimension);
- debug_printf("m_mip_filter: %s\n", m_params.m_mip_filter.c_str());
-
- debug_printf("m_max_endpoint_clusters: %u\n", m_params.m_max_endpoint_clusters);
- debug_printf("m_max_selector_clusters: %u\n", m_params.m_max_selector_clusters);
- debug_printf("m_quality_level: %i\n", m_params.m_quality_level);
-
- debug_printf("m_tex_type: %u\n", m_params.m_tex_type);
- debug_printf("m_userdata0: 0x%X, m_userdata1: 0x%X\n", m_params.m_userdata0, m_params.m_userdata1);
- debug_printf("m_us_per_frame: %i (%f fps)\n", m_params.m_us_per_frame, m_params.m_us_per_frame ? 1.0f / (m_params.m_us_per_frame / 1000000.0f) : 0);
-
-#undef PRINT_BOOL_VALUE
-#undef PRINT_INT_VALUE
-#undef PRINT_UINT_VALUE
-#undef PRINT_FLOAT_VALUE
- }
-
- if ((m_params.m_read_source_images) && (!m_params.m_source_filenames.size()))
- {
- assert(0);
- return false;
- }
-
- return true;
- }
-
- basis_compressor::error_code basis_compressor::process()
- {
- debug_printf("basis_compressor::process\n");
-
- if (!read_source_images())
- return cECFailedReadingSourceImages;
-
- if (!validate_texture_type_constraints())
- return cECFailedValidating;
-
- if (!process_frontend())
- return cECFailedFrontEnd;
-
- if (!extract_frontend_texture_data())
- return cECFailedFontendExtract;
-
- if (!process_backend())
- return cECFailedBackend;
-
- if (!create_basis_file_and_transcode())
- return cECFailedCreateBasisFile;
-
- if (!write_output_files_and_compute_stats())
- return cECFailedWritingOutput;
-
- return cECSuccess;
- }
-
- bool basis_compressor::generate_mipmaps(const image &img, std::vector<image> &mips, bool has_alpha)
- {
- debug_printf("basis_compressor::generate_mipmaps\n");
-
- uint32_t total_levels = 1;
- uint32_t w = img.get_width(), h = img.get_height();
- while (maximum<uint32_t>(w, h) > (uint32_t)m_params.m_mip_smallest_dimension)
- {
- w = maximum(w >> 1U, 1U);
- h = maximum(h >> 1U, 1U);
- total_levels++;
- }
-
-#if BASISU_USE_STB_IMAGE_RESIZE_FOR_MIPMAP_GEN
- // Requires stb_image_resize
- stbir_filter filter = STBIR_FILTER_DEFAULT;
- if (m_params.m_mip_filter == "box")
- filter = STBIR_FILTER_BOX;
- else if (m_params.m_mip_filter == "triangle")
- filter = STBIR_FILTER_TRIANGLE;
- else if (m_params.m_mip_filter == "cubic")
- filter = STBIR_FILTER_CUBICBSPLINE;
- else if (m_params.m_mip_filter == "catmull")
- filter = STBIR_FILTER_CATMULLROM;
- else if (m_params.m_mip_filter == "mitchell")
- filter = STBIR_FILTER_MITCHELL;
-
- for (uint32_t level = 1; level < total_levels; level++)
- {
- const uint32_t level_width = maximum<uint32_t>(1, img.get_width() >> level);
- const uint32_t level_height = maximum<uint32_t>(1, img.get_height() >> level);
-
- image &level_img = *enlarge_vector(mips, 1);
- level_img.resize(level_width, level_height);
-
- int result = stbir_resize_uint8_generic(
- (const uint8_t *)img.get_ptr(), img.get_width(), img.get_height(), img.get_pitch() * sizeof(color_rgba),
- (uint8_t *)level_img.get_ptr(), level_img.get_width(), level_img.get_height(), level_img.get_pitch() * sizeof(color_rgba),
- has_alpha ? 4 : 3, has_alpha ? 3 : STBIR_ALPHA_CHANNEL_NONE, m_params.m_mip_premultiplied ? STBIR_FLAG_ALPHA_PREMULTIPLIED : 0,
- m_params.m_mip_wrapping ? STBIR_EDGE_WRAP : STBIR_EDGE_CLAMP, filter, m_params.m_mip_srgb ? STBIR_COLORSPACE_SRGB : STBIR_COLORSPACE_LINEAR,
- nullptr);
-
- if (result == 0)
- {
- error_printf("basis_compressor::generate_mipmaps: stbir_resize_uint8_generic() failed!\n");
- return false;
- }
-
- if (m_params.m_mip_renormalize)
- level_img.renormalize_normal_map();
- }
-#else
- for (uint32_t level = 1; level < total_levels; level++)
- {
- const uint32_t level_width = maximum<uint32_t>(1, img.get_width() >> level);
- const uint32_t level_height = maximum<uint32_t>(1, img.get_height() >> level);
-
- image &level_img = *enlarge_vector(mips, 1);
- level_img.resize(level_width, level_height);
-
- bool status = image_resample(img, level_img, m_params.m_mip_srgb, m_params.m_mip_filter.c_str(), m_params.m_mip_scale, m_params.m_mip_wrapping, 0, has_alpha ? 4 : 3);
- if (!status)
- {
- error_printf("basis_compressor::generate_mipmaps: image_resample() failed!\n");
- return false;
- }
-
- if (m_params.m_mip_renormalize)
- level_img.renormalize_normal_map();
- }
-#endif
-
- return true;
- }
-
- bool basis_compressor::read_source_images()
- {
- debug_printf("basis_compressor::read_source_images\n");
-
- const uint32_t total_source_files = m_params.m_read_source_images ? (uint32_t)m_params.m_source_filenames.size() : (uint32_t)m_params.m_source_images.size();
- if (!total_source_files)
- return false;
-
- m_stats.resize(0);
- m_slice_descs.resize(0);
- m_slice_images.resize(0);
-
- m_total_blocks = 0;
- uint32_t total_macroblocks = 0;
-
- m_any_source_image_has_alpha = false;
-
- std::vector<image> source_images;
- std::vector<std::string> source_filenames;
-
- // First load all source images, and determine if any have an alpha channel.
- for (uint32_t source_file_index = 0; source_file_index < total_source_files; source_file_index++)
- {
- const char *pSource_filename = "";
-
- image file_image;
-
- if (m_params.m_read_source_images)
- {
- pSource_filename = m_params.m_source_filenames[source_file_index].c_str();
-
- // Load the source image
- if (!load_png(pSource_filename, file_image))
- {
- error_printf("Failed reading source image: %s\n", pSource_filename);
- return false;
- }
-
- printf("Read source image \"%s\", %ux%u\n", pSource_filename, file_image.get_width(), file_image.get_height());
-
- // Optionally load another image and put a grayscale version of it into the alpha channel.
- if ((source_file_index < m_params.m_source_alpha_filenames.size()) && (m_params.m_source_alpha_filenames[source_file_index].size()))
- {
- const char *pSource_alpha_image = m_params.m_source_alpha_filenames[source_file_index].c_str();
-
- image alpha_data;
-
- if (!load_png(pSource_alpha_image, alpha_data))
- {
- error_printf("Failed reading source image: %s\n", pSource_alpha_image);
- return false;
- }
-
- printf("Read source alpha image \"%s\", %ux%u\n", pSource_alpha_image, alpha_data.get_width(), alpha_data.get_height());
-
- alpha_data.crop(file_image.get_width(), file_image.get_height());
-
- for (uint32_t y = 0; y < file_image.get_height(); y++)
- for (uint32_t x = 0; x < file_image.get_width(); x++)
- file_image(x, y).a = (uint8_t)alpha_data(x, y).get_709_luma();
- }
- }
- else
- {
- file_image = m_params.m_source_images[source_file_index];
- }
-
- if (m_params.m_seperate_rg_to_color_alpha)
- {
- // Used for XY normal maps in RG - puts X in color, Y in alpha
- for (uint32_t y = 0; y < file_image.get_height(); y++)
- for (uint32_t x = 0; x < file_image.get_width(); x++)
- {
- const color_rgba &c = file_image(x, y);
- file_image(x, y).set_noclamp_rgba(c.r, c.r, c.r, c.g);
- }
- }
-
- bool has_alpha = false;
- if ((m_params.m_force_alpha) || (m_params.m_seperate_rg_to_color_alpha))
- has_alpha = true;
- else if (!m_params.m_check_for_alpha)
- file_image.set_alpha(255);
- else if (file_image.has_alpha())
- has_alpha = true;
-
- if (has_alpha)
- m_any_source_image_has_alpha = true;
-
- debug_printf("Source image index %u filename %s %ux%u has alpha: %u\n", source_file_index, pSource_filename, file_image.get_width(), file_image.get_height(), has_alpha);
-
- if (m_params.m_y_flip)
- file_image.flip_y();
-
-#if DEBUG_EXTRACT_SINGLE_BLOCK
- image block_image(4, 4);
- const uint32_t block_x = 0;
- const uint32_t block_y = 0;
- block_image.blit(block_x * 4, block_y * 4, 4, 4, 0, 0, file_image, 0);
- file_image = block_image;
-#endif
-
-#if DEBUG_CROP_TEXTURE_TO_64x64
- file_image.resize(64, 64);
-#endif
-#if DEBUG_RESIZE_TEXTURE
- image temp_img((file_image.get_width() + 1) / 2, (file_image.get_height() + 1) / 2);
- image_resample(file_image, temp_img, m_params.m_perceptual, "kaiser");
- temp_img.swap(file_image);
-#endif
-
- if ((!file_image.get_width()) || (!file_image.get_height()))
- {
- error_printf("basis_compressor::read_source_images: Source image has a zero width and/or height!\n");
- return false;
- }
-
- if ((file_image.get_width() > BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION) || (file_image.get_height() > BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION))
- {
- error_printf("basis_compressor::read_source_images: Source image is too large!\n");
- return false;
- }
-
- source_images.push_back(file_image);
- source_filenames.push_back(pSource_filename);
- }
-
- debug_printf("Any source image has alpha: %u\n", m_any_source_image_has_alpha);
-
- for (uint32_t source_file_index = 0; source_file_index < total_source_files; source_file_index++)
- {
- image &file_image = source_images[source_file_index];
- const std::string &source_filename = source_filenames[source_file_index];
-
- std::vector<image> slices;
-
- slices.reserve(32);
- slices.push_back(file_image);
-
- if (m_params.m_mip_gen)
- {
- if (!generate_mipmaps(file_image, slices, m_any_source_image_has_alpha))
- return false;
- }
-
- uint_vec mip_indices(slices.size());
- for (uint32_t i = 0; i < slices.size(); i++)
- mip_indices[i] = i;
-
- if (m_any_source_image_has_alpha)
- {
- // If source has alpha, then even mips will have RGB, and odd mips will have alpha in RGB.
- std::vector<image> alpha_slices;
- uint_vec new_mip_indices;
-
- alpha_slices.reserve(slices.size() * 2);
-
- for (uint32_t i = 0; i < slices.size(); i++)
- {
- image lvl_rgb(slices[i]);
- image lvl_a(lvl_rgb);
-
- for (uint32_t y = 0; y < lvl_a.get_height(); y++)
- {
- for (uint32_t x = 0; x < lvl_a.get_width(); x++)
- {
- uint8_t a = lvl_a(x, y).a;
- lvl_a(x, y).set_noclamp_rgba(a, a, a, 255);
- }
- }
-
- lvl_rgb.set_alpha(255);
-
- alpha_slices.push_back(lvl_rgb);
- new_mip_indices.push_back(i);
-
- alpha_slices.push_back(lvl_a);
- new_mip_indices.push_back(i);
- }
-
- slices.swap(alpha_slices);
- mip_indices.swap(new_mip_indices);
- }
-
- assert(slices.size() == mip_indices.size());
-
- for (uint32_t slice_index = 0; slice_index < slices.size(); slice_index++)
- {
- const bool is_alpha_slice = m_any_source_image_has_alpha && ((slice_index & 1) != 0);
-
- image &slice_image = slices[slice_index];
- const uint32_t orig_width = slice_image.get_width();
- const uint32_t orig_height = slice_image.get_height();
-
- // Enlarge the source image to 4x4 block boundaries, duplicating edge pixels if necessary to avoid introducing extra colors into blocks.
- slice_image.crop_dup_borders(slice_image.get_block_width(4) * 4, slice_image.get_block_height(4) * 4);
-
- if (m_params.m_debug_images)
- {
- save_png(string_format("basis_debug_source_image_%u_%u.png", source_file_index, slice_index).c_str(), slice_image);
- }
-
- enlarge_vector(m_stats, 1);
- enlarge_vector(m_slice_images, 1);
- enlarge_vector(m_slice_descs, 1);
-
- const uint32_t dest_image_index = (uint32_t)m_stats.size() - 1;
-
- m_stats[dest_image_index].m_filename = source_filename.c_str();
- m_stats[dest_image_index].m_width = orig_width;
- m_stats[dest_image_index].m_height = orig_height;
-
- m_slice_images[dest_image_index] = slice_image;
-
- debug_printf("****** Slice %u: mip %u, alpha_slice: %u, filename: \"%s\", original: %ux%u actual: %ux%u\n", m_slice_descs.size() - 1, mip_indices[slice_index], is_alpha_slice, source_filename.c_str(), orig_width, orig_height, slice_image.get_width(), slice_image.get_height());
-
- basisu_backend_slice_desc &slice_desc = m_slice_descs[dest_image_index];
-
- slice_desc.m_first_block_index = m_total_blocks;
-
- slice_desc.m_orig_width = orig_width;
- slice_desc.m_orig_height = orig_height;
-
- slice_desc.m_width = slice_image.get_width();
- slice_desc.m_height = slice_image.get_height();
-
- slice_desc.m_num_blocks_x = slice_image.get_block_width(4);
- slice_desc.m_num_blocks_y = slice_image.get_block_height(4);
-
- slice_desc.m_num_macroblocks_x = (slice_desc.m_num_blocks_x + 1) >> 1;
- slice_desc.m_num_macroblocks_y = (slice_desc.m_num_blocks_y + 1) >> 1;
-
- slice_desc.m_source_file_index = source_file_index;
-
- slice_desc.m_mip_index = mip_indices[slice_index];
-
- slice_desc.m_alpha = is_alpha_slice;
- slice_desc.m_iframe = false;
- if (m_params.m_tex_type == basist::cBASISTexTypeVideoFrames)
- {
- slice_desc.m_iframe = (source_file_index == 0);
- }
-
- m_total_blocks += slice_desc.m_num_blocks_x * slice_desc.m_num_blocks_y;
- total_macroblocks += slice_desc.m_num_macroblocks_x * slice_desc.m_num_macroblocks_y;
-
- } // slice_index
-
- } // source_file_index
-
- debug_printf("Total blocks: %u, Total macroblocks: %u\n", m_total_blocks, total_macroblocks);
-
- // Make sure we don't have too many slices
- if (m_slice_descs.size() > BASISU_MAX_SLICES)
- {
- error_printf("Too many slices!\n");
- return false;
- }
-
- // Basic sanity check on the slices
- for (uint32_t i = 1; i < m_slice_descs.size(); i++)
- {
- const basisu_backend_slice_desc &prev_slice_desc = m_slice_descs[i - 1];
- const basisu_backend_slice_desc &slice_desc = m_slice_descs[i];
-
- // Make sure images are in order
- int image_delta = (int)slice_desc.m_source_file_index - (int)prev_slice_desc.m_source_file_index;
- if (image_delta > 1)
- return false;
-
- // Make sure mipmap levels are in order
- if (!image_delta)
- {
- int level_delta = (int)slice_desc.m_mip_index - (int)prev_slice_desc.m_mip_index;
- if (level_delta > 1)
- return false;
- }
- }
-
- printf("Total basis file slices: %u\n", (uint32_t)m_slice_descs.size());
-
- for (uint32_t i = 0; i < m_slice_descs.size(); i++)
- {
- const basisu_backend_slice_desc &slice_desc = m_slice_descs[i];
-
- printf("Slice: %u, alpha: %u, orig width/height: %ux%u, width/height: %ux%u, first_block: %u, image_index: %u, mip_level: %u, iframe: %u\n",
- i, slice_desc.m_alpha, slice_desc.m_orig_width, slice_desc.m_orig_height, slice_desc.m_width, slice_desc.m_height, slice_desc.m_first_block_index, slice_desc.m_source_file_index, slice_desc.m_mip_index, slice_desc.m_iframe);
-
- if (m_any_source_image_has_alpha)
- {
- // Alpha slices must be at odd slice indices
- if (slice_desc.m_alpha)
- {
- if ((i & 1) == 0)
- return false;
-
- const basisu_backend_slice_desc &prev_slice_desc = m_slice_descs[i - 1];
-
- // Make sure previous slice has this image's color data
- if (prev_slice_desc.m_source_file_index != slice_desc.m_source_file_index)
- return false;
- if (prev_slice_desc.m_alpha)
- return false;
- if (prev_slice_desc.m_mip_index != slice_desc.m_mip_index)
- return false;
- if (prev_slice_desc.m_num_blocks_x != slice_desc.m_num_blocks_x)
- return false;
- if (prev_slice_desc.m_num_blocks_y != slice_desc.m_num_blocks_y)
- return false;
- }
- else if (i & 1)
- return false;
- }
- else if (slice_desc.m_alpha)
- {
- return false;
- }
-
- if ((slice_desc.m_orig_width > slice_desc.m_width) || (slice_desc.m_orig_height > slice_desc.m_height))
- return false;
- if ((slice_desc.m_source_file_index == 0) && (m_params.m_tex_type == basist::cBASISTexTypeVideoFrames))
- {
- if (!slice_desc.m_iframe)
- return false;
- }
- }
-
- return true;
- }
-
- // Do some basic validation for 2D arrays, cubemaps, video, and volumes.
- bool basis_compressor::validate_texture_type_constraints()
- {
- debug_printf("basis_compressor::validate_texture_type_constraints\n");
-
- // In 2D mode anything goes (each image may have a different resolution and # of mipmap levels).
- if (m_params.m_tex_type == basist::cBASISTexType2D)
- return true;
-
- uint32_t total_basis_images = 0;
-
- for (uint32_t slice_index = 0; slice_index < m_slice_images.size(); slice_index++)
- {
- const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
-
- total_basis_images = maximum<uint32_t>(total_basis_images, slice_desc.m_source_file_index + 1);
- }
-
- if (m_params.m_tex_type == basist::cBASISTexTypeCubemapArray)
- {
- // For cubemaps, validate that the total # of Basis images is a multiple of 6.
- if ((total_basis_images % 6) != 0)
- {
- error_printf("basis_compressor::validate_texture_type_constraints: For cubemaps the total number of input images is not a multiple of 6!\n");
- return false;
- }
- }
-
- // Now validate that all the mip0's have the same dimensions, and that each image has the same # of mipmap levels.
- uint_vec image_mipmap_levels(total_basis_images);
-
- int width = -1, height = -1;
- for (uint32_t slice_index = 0; slice_index < m_slice_images.size(); slice_index++)
- {
- const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
-
- image_mipmap_levels[slice_desc.m_source_file_index] = maximum(image_mipmap_levels[slice_desc.m_source_file_index], slice_desc.m_mip_index + 1);
-
- if (slice_desc.m_mip_index != 0)
- continue;
-
- if (width < 0)
- {
- width = slice_desc.m_orig_width;
- height = slice_desc.m_orig_height;
- }
- else if ((width != (int)slice_desc.m_orig_width) || (height != (int)slice_desc.m_orig_height))
- {
- error_printf("basis_compressor::validate_texture_type_constraints: The source image resolutions are not all equal!\n");
- return false;
- }
- }
-
- for (size_t i = 1; i < image_mipmap_levels.size(); i++)
- {
- if (image_mipmap_levels[0] != image_mipmap_levels[i])
- {
- error_printf("basis_compressor::validate_texture_type_constraints: Each image must have the same number of mipmap levels!\n");
- return false;
- }
- }
-
- return true;
- }
-
- bool basis_compressor::process_frontend()
- {
- debug_printf("basis_compressor::process_frontend\n");
-
- m_source_blocks.resize(m_total_blocks);
-
- for (uint32_t slice_index = 0; slice_index < m_slice_images.size(); slice_index++)
- {
- const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
-
- const uint32_t num_blocks_x = slice_desc.m_num_blocks_x;
- const uint32_t num_blocks_y = slice_desc.m_num_blocks_y;
-
- const image &source_image = m_slice_images[slice_index];
-
- for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
- for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
- source_image.extract_block_clamped(m_source_blocks[slice_desc.m_first_block_index + block_x + block_y * num_blocks_x].get_ptr(), block_x * 4, block_y * 4, 4, 4);
- }
-
-#if 0
- // TODO
- basis_etc1_pack_params pack_params;
- pack_params.m_quality = cETCQualityMedium;
- pack_params.m_perceptual = m_params.m_perceptual;
- pack_params.m_use_color4 = false;
-
- pack_etc1_block_context pack_context;
-
- std::unordered_set<uint64_t> endpoint_hash;
- std::unordered_set<uint32_t> selector_hash;
-
- for (uint32_t i = 0; i < m_source_blocks.size(); i++)
- {
- etc_block blk;
- pack_etc1_block(blk, m_source_blocks[i].get_ptr(), pack_params, pack_context);
-
- const color_rgba c0(blk.get_block_color(0, false));
- endpoint_hash.insert((c0.r | (c0.g << 5) | (c0.b << 10)) | (blk.get_inten_table(0) << 16));
-
- const color_rgba c1(blk.get_block_color(1, false));
- endpoint_hash.insert((c1.r | (c1.g << 5) | (c1.b << 10)) | (blk.get_inten_table(1) << 16));
-
- selector_hash.insert(blk.get_raw_selector_bits());
- }
-
- const uint32_t total_unique_endpoints = (uint32_t)endpoint_hash.size();
- const uint32_t total_unique_selectors = (uint32_t)selector_hash.size();
-
- if (m_params.m_debug)
- {
- debug_printf("Unique endpoints: %u, unique selectors: %u\n", total_unique_endpoints, total_unique_selectors);
- }
-#endif
-
- const double total_texels = m_total_blocks * 16.0f;
-
- int endpoint_clusters = m_params.m_max_endpoint_clusters;
- int selector_clusters = m_params.m_max_selector_clusters;
-
- if (endpoint_clusters > basisu_frontend::cMaxEndpointClusters)
- {
- error_printf("Too many endpoint clusters! (%u but max is %u)\n", endpoint_clusters, basisu_frontend::cMaxEndpointClusters);
- return false;
- }
- if (selector_clusters > basisu_frontend::cMaxSelectorClusters)
- {
- error_printf("Too many selector clusters! (%u but max is %u)\n", selector_clusters, basisu_frontend::cMaxSelectorClusters);
- return false;
- }
-
- if (m_params.m_quality_level != -1)
- {
- const float quality = saturate(m_params.m_quality_level / 255.0f);
-
- const float bits_per_endpoint_cluster = 14.0f;
- const float max_desired_endpoint_cluster_bits_per_texel = 1.0f; // .15f
- int max_endpoints = static_cast<int>((max_desired_endpoint_cluster_bits_per_texel * total_texels) / bits_per_endpoint_cluster);
-
- const float mid = 128.0f / 255.0f;
-
- float color_endpoint_quality = quality;
-
- const float endpoint_split_point = 0.5f;
- if (color_endpoint_quality <= mid)
- {
- color_endpoint_quality = lerp(0.0f, endpoint_split_point, powf(color_endpoint_quality / mid, .65f));
-
- max_endpoints = clamp<int>(max_endpoints, 256, 3072);
- max_endpoints = minimum<uint32_t>(max_endpoints, m_total_blocks);
-
- if (max_endpoints < 64)
- max_endpoints = 64;
- endpoint_clusters = clamp<uint32_t>((uint32_t)(.5f + lerp<float>(32, static_cast<float>(max_endpoints), color_endpoint_quality)), 32, basisu_frontend::cMaxEndpointClusters);
- }
- else
- {
- color_endpoint_quality = powf((color_endpoint_quality - mid) / (1.0f - mid), 1.6f);
-
- max_endpoints = clamp<int>(max_endpoints, 256, 8192);
- max_endpoints = minimum<uint32_t>(max_endpoints, m_total_blocks);
-
- if (max_endpoints < 3072)
- max_endpoints = 3072;
- endpoint_clusters = clamp<uint32_t>((uint32_t)(.5f + lerp<float>(3072, static_cast<float>(max_endpoints), color_endpoint_quality)), 32, basisu_frontend::cMaxEndpointClusters);
- }
-
- float bits_per_selector_cluster = m_params.m_global_sel_pal ? 21.0f : 14.0f;
-
- const float max_desired_selector_cluster_bits_per_texel = 1.0f; // .15f
- int max_selectors = static_cast<int>((max_desired_selector_cluster_bits_per_texel * total_texels) / bits_per_selector_cluster);
- max_selectors = clamp<int>(max_selectors, 256, basisu_frontend::cMaxSelectorClusters);
- max_selectors = minimum<uint32_t>(max_selectors, m_total_blocks);
-
- float color_selector_quality = quality;
- //color_selector_quality = powf(color_selector_quality, 1.65f);
- color_selector_quality = powf(color_selector_quality, 2.62f);
-
- if (max_selectors < 96)
- max_selectors = 96;
- selector_clusters = clamp<uint32_t>((uint32_t)(.5f + lerp<float>(96, static_cast<float>(max_selectors), color_selector_quality)), 8, basisu_frontend::cMaxSelectorClusters);
-
- debug_printf("Max endpoints: %u, max selectors: %u\n", endpoint_clusters, selector_clusters);
-
- if (m_params.m_quality_level >= 223)
- {
- if (!m_params.m_selector_rdo_thresh.was_changed())
- {
- if (!m_params.m_endpoint_rdo_thresh.was_changed())
- m_params.m_endpoint_rdo_thresh *= .25f;
-
- if (!m_params.m_selector_rdo_thresh.was_changed())
- m_params.m_selector_rdo_thresh *= .25f;
- }
- }
- else if (m_params.m_quality_level >= 192)
- {
- if (!m_params.m_endpoint_rdo_thresh.was_changed())
- m_params.m_endpoint_rdo_thresh *= .5f;
-
- if (!m_params.m_selector_rdo_thresh.was_changed())
- m_params.m_selector_rdo_thresh *= .5f;
- }
- else if (m_params.m_quality_level >= 160)
- {
- if (!m_params.m_endpoint_rdo_thresh.was_changed())
- m_params.m_endpoint_rdo_thresh *= .75f;
-
- if (!m_params.m_selector_rdo_thresh.was_changed())
- m_params.m_selector_rdo_thresh *= .75f;
- }
- else if (m_params.m_quality_level >= 129)
- {
- float l = (quality - 129 / 255.0f) / ((160 - 129) / 255.0f);
-
- if (!m_params.m_endpoint_rdo_thresh.was_changed())
- m_params.m_endpoint_rdo_thresh *= lerp<float>(1.0f, .75f, l);
-
- if (!m_params.m_selector_rdo_thresh.was_changed())
- m_params.m_selector_rdo_thresh *= lerp<float>(1.0f, .75f, l);
- }
- }
-
- m_auto_global_sel_pal = false;
- if (!m_params.m_global_sel_pal && m_params.m_auto_global_sel_pal)
- {
- const float bits_per_selector_cluster = 31.0f;
- double selector_codebook_bpp_est = (bits_per_selector_cluster * selector_clusters) / total_texels;
- debug_printf("selector_codebook_bpp_est: %f\n", selector_codebook_bpp_est);
- const float force_global_sel_pal_bpp_threshold = .15f;
- if ((total_texels <= 128.0f*128.0f) && (selector_codebook_bpp_est > force_global_sel_pal_bpp_threshold))
- {
- m_auto_global_sel_pal = true;
- debug_printf("Auto global selector palette enabled\n");
- }
- }
-
- basisu_frontend::params p;
- p.m_num_source_blocks = m_total_blocks;
- p.m_pSource_blocks = &m_source_blocks[0];
- p.m_max_endpoint_clusters = endpoint_clusters;
- p.m_max_selector_clusters = selector_clusters;
- p.m_perceptual = m_params.m_perceptual;
- p.m_debug_stats = m_params.m_debug;
- p.m_debug_images = m_params.m_debug_images;
- p.m_compression_level = m_params.m_compression_level;
- p.m_tex_type = m_params.m_tex_type;
- p.m_multithreaded = m_params.m_multithreading;
- p.m_disable_hierarchical_endpoint_codebooks = m_params.m_disable_hierarchical_endpoint_codebooks;
- p.m_pJob_pool = m_params.m_pJob_pool;
-
- if ((m_params.m_global_sel_pal) || (m_auto_global_sel_pal))
- {
- p.m_pGlobal_sel_codebook = m_params.m_pSel_codebook;
- p.m_num_global_sel_codebook_pal_bits = m_params.m_global_pal_bits;
- p.m_num_global_sel_codebook_mod_bits = m_params.m_global_mod_bits;
- p.m_use_hybrid_selector_codebooks = !m_params.m_no_hybrid_sel_cb;
- p.m_hybrid_codebook_quality_thresh = m_params.m_hybrid_sel_cb_quality_thresh;
- }
-
- if (!m_frontend.init(p))
- {
- error_printf("basisu_frontend::init() failed!\n");
- return false;
- }
-
- m_frontend.compress();
-
- if (m_params.m_debug_images)
- {
- for (uint32_t i = 0; i < m_slice_descs.size(); i++)
- {
- char filename[1024];
-#ifdef _WIN32
- sprintf_s(filename, sizeof(filename), "rdo_frontend_output_output_blocks_%u.png", i);
-#else
- snprintf(filename, sizeof(filename), "rdo_frontend_output_output_blocks_%u.png", i);
-#endif
- m_frontend.dump_debug_image(filename, m_slice_descs[i].m_first_block_index, m_slice_descs[i].m_num_blocks_x, m_slice_descs[i].m_num_blocks_y, true);
-
-#ifdef _WIN32
- sprintf_s(filename, sizeof(filename), "rdo_frontend_output_api_%u.png", i);
-#else
- snprintf(filename, sizeof(filename), "rdo_frontend_output_api_%u.png", i);
-#endif
- m_frontend.dump_debug_image(filename, m_slice_descs[i].m_first_block_index, m_slice_descs[i].m_num_blocks_x, m_slice_descs[i].m_num_blocks_y, false);
- }
- }
-
- return true;
- }
-
- bool basis_compressor::extract_frontend_texture_data()
- {
- debug_printf("basis_compressor::extract_frontend_texture_data\n");
-
- m_frontend_output_textures.resize(m_slice_descs.size());
- m_best_etc1s_images.resize(m_slice_descs.size());
- m_best_etc1s_images_unpacked.resize(m_slice_descs.size());
-
- for (uint32_t i = 0; i < m_slice_descs.size(); i++)
- {
- const basisu_backend_slice_desc &slice_desc = m_slice_descs[i];
-
- const uint32_t num_blocks_x = slice_desc.m_num_blocks_x;
- const uint32_t num_blocks_y = slice_desc.m_num_blocks_y;
-
- const uint32_t width = num_blocks_x * 4;
- const uint32_t height = num_blocks_y * 4;
-
- m_frontend_output_textures[i].init(texture_format::cETC1, width, height);
-
- for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
- for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
- memcpy(m_frontend_output_textures[i].get_block_ptr(block_x, block_y, 0), &m_frontend.get_output_block(slice_desc.m_first_block_index + block_x + block_y * num_blocks_x), sizeof(etc_block));
-
-#if 0
- if (m_params.m_debug_images)
- {
- char filename[1024];
- sprintf_s(filename, sizeof(filename), "rdo_etc_frontend_%u_", i);
- write_etc1_vis_images(m_frontend_output_textures[i], filename);
- }
-#endif
-
- m_best_etc1s_images[i].init(texture_format::cETC1, width, height);
- for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
- for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
- memcpy(m_best_etc1s_images[i].get_block_ptr(block_x, block_y, 0), &m_frontend.get_etc1s_block(slice_desc.m_first_block_index + block_x + block_y * num_blocks_x), sizeof(etc_block));
-
- m_best_etc1s_images[i].unpack(m_best_etc1s_images_unpacked[i]);
- }
-
- return true;
- }
-
- bool basis_compressor::process_backend()
- {
- debug_printf("basis_compressor::process_backend\n");
-
- basisu_backend_params backend_params;
- backend_params.m_debug = m_params.m_debug;
- backend_params.m_debug_images = m_params.m_debug_images;
- backend_params.m_etc1s = true;
- backend_params.m_compression_level = m_params.m_compression_level;
-
- if (!m_params.m_no_endpoint_rdo)
- backend_params.m_endpoint_rdo_quality_thresh = m_params.m_endpoint_rdo_thresh;
-
- if (!m_params.m_no_selector_rdo)
- backend_params.m_selector_rdo_quality_thresh = m_params.m_selector_rdo_thresh;
-
- backend_params.m_use_global_sel_codebook = (m_frontend.get_params().m_pGlobal_sel_codebook != NULL);
- backend_params.m_global_sel_codebook_pal_bits = m_frontend.get_params().m_num_global_sel_codebook_pal_bits;
- backend_params.m_global_sel_codebook_mod_bits = m_frontend.get_params().m_num_global_sel_codebook_mod_bits;
- backend_params.m_use_hybrid_sel_codebooks = m_frontend.get_params().m_use_hybrid_selector_codebooks;
-
- m_backend.init(&m_frontend, backend_params, m_slice_descs, m_params.m_pSel_codebook);
- uint32_t total_packed_bytes = m_backend.encode();
-
- if (!total_packed_bytes)
- {
- error_printf("basis_compressor::encode() failed!\n");
- return false;
- }
-
- debug_printf("Total packed bytes (estimated): %u\n", total_packed_bytes);
-
- return true;
- }
-
- bool basis_compressor::create_basis_file_and_transcode()
- {
- debug_printf("basis_compressor::create_basis_file_and_transcode\n");
-
- const basisu_backend_output &encoded_output = m_backend.get_output();
-
- if (!m_basis_file.init(encoded_output, m_params.m_tex_type, m_params.m_userdata0, m_params.m_userdata1, m_params.m_y_flip, m_params.m_us_per_frame))
- {
- error_printf("basis_compressor::write_output_files_and_compute_stats: basisu_backend:init() failed!\n");
- return false;
- }
-
- const uint8_vec &comp_data = m_basis_file.get_compressed_data();
-
- m_output_basis_file = comp_data;
-
- // Verify the compressed data by transcoding it to ETC1/BC1 and validating the CRC's.
- basist::basisu_transcoder decoder(m_params.m_pSel_codebook);
- if (!decoder.validate_file_checksums(&comp_data[0], (uint32_t)comp_data.size(), true))
- {
- error_printf("decoder.validate_file_checksums() failed!\n");
- return false;
- }
-
- m_decoded_output_textures.resize(m_slice_descs.size());
- m_decoded_output_textures_unpacked.resize(m_slice_descs.size());
-
- m_decoded_output_textures_bc1.resize(m_slice_descs.size());
- m_decoded_output_textures_unpacked_bc1.resize(m_slice_descs.size());
-
- interval_timer tm;
- tm.start();
-
- if (!decoder.start_transcoding(&comp_data[0], (uint32_t)comp_data.size()))
- {
- error_printf("decoder.start_transcoding() failed!\n");
- return false;
- }
-
- debug_printf("basisu_comppressor::start_transcoding() took %3.3fms\n", tm.get_elapsed_ms());
-
- uint32_t total_orig_pixels = 0;
- uint32_t total_texels = 0;
-
- double total_time_etc1 = 0;
-
- for (uint32_t i = 0; i < m_slice_descs.size(); i++)
- {
- gpu_image decoded_texture;
- decoded_texture.init(texture_format::cETC1, m_slice_descs[i].m_width, m_slice_descs[i].m_height);
-
- tm.start();
-
- if (!decoder.transcode_slice(&comp_data[0], (uint32_t)comp_data.size(), i,
- reinterpret_cast<etc_block *>(decoded_texture.get_ptr()), m_slice_descs[i].m_num_blocks_x * m_slice_descs[i].m_num_blocks_y, basist::block_format::cETC1, 8))
- {
- error_printf("Transcoding failed to ETC1 on slice %u!\n", i);
- return false;
- }
-
- total_time_etc1 += tm.get_elapsed_secs();
-
- uint32_t image_crc16 = basist::crc16(decoded_texture.get_ptr(), decoded_texture.get_size_in_bytes(), 0);
- if (image_crc16 != m_backend.get_output().m_slice_image_crcs[i])
- {
- error_printf("Decoded image data CRC check failed on slice %u!\n", i);
- return false;
- }
- debug_printf("Decoded image data CRC check succeeded on slice %i\n", i);
-
- m_decoded_output_textures[i] = decoded_texture;
-
- total_orig_pixels += m_slice_descs[i].m_orig_width * m_slice_descs[i].m_orig_height;
- total_texels += m_slice_descs[i].m_width * m_slice_descs[i].m_height;
- }
-
- tm.start();
-
- basist::basisu_transcoder_init();
-
- debug_printf("basist::basisu_transcoder_init: Took %f ms\n", tm.get_elapsed_ms());
-
- double total_time_bc1 = 0;
-
- for (uint32_t i = 0; i < m_slice_descs.size(); i++)
- {
- gpu_image decoded_texture;
- decoded_texture.init(texture_format::cBC1, m_slice_descs[i].m_width, m_slice_descs[i].m_height);
-
- tm.start();
-
- if (!decoder.transcode_slice(&comp_data[0], (uint32_t)comp_data.size(), i,
- reinterpret_cast<etc_block *>(decoded_texture.get_ptr()), m_slice_descs[i].m_num_blocks_x * m_slice_descs[i].m_num_blocks_y, basist::block_format::cBC1, 8))
- {
- error_printf("Transcoding failed to BC1 on slice %u!\n", i);
- return false;
- }
-
- total_time_bc1 += tm.get_elapsed_secs();
-
- m_decoded_output_textures_bc1[i] = decoded_texture;
- }
-
- for (uint32_t i = 0; i < m_slice_descs.size(); i++)
- {
- m_decoded_output_textures[i].unpack(m_decoded_output_textures_unpacked[i]);
- m_decoded_output_textures_bc1[i].unpack(m_decoded_output_textures_unpacked_bc1[i]);
- }
-
- debug_printf("Transcoded to ETC1 in %3.3fms, %f texels/sec\n", total_time_etc1 * 1000.0f, total_orig_pixels / total_time_etc1);
-
- debug_printf("Transcoded to BC1 in %3.3fms, %f texels/sec\n", total_time_bc1 * 1000.0f, total_orig_pixels / total_time_bc1);
-
- debug_printf("Total .basis output file size: %u, %3.3f bits/texel\n", comp_data.size(), comp_data.size() * 8.0f / total_orig_pixels);
-
- m_output_blocks.resize(0);
-
- uint32_t total_orig_texels = 0;
- for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++)
- {
- const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
-
- total_orig_texels += slice_desc.m_orig_width * slice_desc.m_orig_height;
-
- const uint32_t total_blocks = slice_desc.m_num_blocks_x * slice_desc.m_num_blocks_y;
-
- assert(m_decoded_output_textures[slice_index].get_total_blocks() == total_blocks);
-
- memcpy(enlarge_vector(m_output_blocks, total_blocks), m_decoded_output_textures[slice_index].get_ptr(), sizeof(etc_block) * total_blocks);
- }
-
- m_basis_file_size = (uint32_t)comp_data.size();
- m_basis_bits_per_texel = (comp_data.size() * 8.0f) / total_orig_texels;
-
- return true;
- }
-
- bool basis_compressor::write_output_files_and_compute_stats()
- {
- debug_printf("basis_compressor::write_output_files_and_compute_stats\n");
-
- if (m_params.m_write_output_basis_files)
- {
- const uint8_vec &comp_data = m_basis_file.get_compressed_data();
-
- const std::string& basis_filename = m_params.m_out_filename;
-
- if (!write_vec_to_file(basis_filename.c_str(), comp_data))
- {
- error_printf("Failed writing output data to file \"%s\"\n", basis_filename.c_str());
- return false;
- }
-
- printf("Wrote output .basis file \"%s\"\n", basis_filename.c_str());
- }
-
- m_stats.resize(m_slice_descs.size());
-
- uint32_t total_orig_texels = 0;
-
- for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++)
- {
- const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
-
- total_orig_texels += slice_desc.m_orig_width * slice_desc.m_orig_height;
-
- if (m_params.m_compute_stats)
- {
- printf("Slice: %u\n", slice_index);
-
- image_stats &s = m_stats[slice_index];
-
- // TODO: We used to output SSIM (during heavy encoder development), but this slowed down compression too much. We'll be adding it back.
-
- image_metrics em;
-
- // ---- .basis ETC1S stats
- em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 0);
- em.print(".basis ETC1S 709 Luma: ");
-
- s.m_basis_etc1s_luma_709_psnr = static_cast<float>(em.m_psnr);
- s.m_basis_etc1s_luma_709_ssim = static_cast<float>(em.m_ssim);
-
- em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 0, true, true);
- em.print(".basis ETC1S 601 Luma: ");
-
- s.m_basis_etc1s_luma_601_psnr = static_cast<float>(em.m_psnr);
-
- em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 3);
- em.print(".basis ETC1S RGB Avg: ");
-
- s.m_basis_etc1s_rgb_avg_psnr = em.m_psnr;
-
- if (m_slice_descs.size() == 1)
- {
- debug_printf(".basis Luma 709 PSNR per bit/texel*10000: %3.3f\n", 10000.0f * s.m_basis_etc1s_luma_709_psnr / ((m_backend.get_output().get_output_size_estimate() * 8.0f) / (slice_desc.m_orig_width * slice_desc.m_orig_height)));
- }
-
- // ---- .basis BC1 stats
- em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc1[slice_index], 0, 0);
- em.print(".basis BC1 709 Luma: ");
-
- s.m_basis_bc1_luma_709_psnr = static_cast<float>(em.m_psnr);
- s.m_basis_bc1_luma_709_ssim = static_cast<float>(em.m_ssim);
-
- em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc1[slice_index], 0, 0, true, true);
- em.print(".basis BC1 601 Luma: ");
-
- s.m_basis_bc1_luma_601_psnr = static_cast<float>(em.m_psnr);
-
- em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc1[slice_index], 0, 3);
- em.print(".basis BC1 RGB Avg: ");
-
- s.m_basis_bc1_rgb_avg_psnr = static_cast<float>(em.m_psnr);
-
- // ---- Nearly best possible ETC1S stats
- em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 0);
- em.print("Unquantized ETC1S 709 Luma: ");
-
- s.m_best_luma_709_psnr = static_cast<float>(em.m_psnr);
- s.m_best_luma_709_ssim = static_cast<float>(em.m_ssim);
-
- em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 0, true, true);
- em.print("Unquantized ETC1S 601 Luma: ");
-
- s.m_best_luma_601_psnr = static_cast<float>(em.m_psnr);
-
- em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 3);
- em.print("Unquantized ETC1S RGB Avg: ");
-
- s.m_best_rgb_avg_psnr = static_cast<float>(em.m_psnr);
- }
-
- if (m_frontend.get_params().m_debug_images)
- {
- std::string out_basename;
- if (m_params.m_out_filename.size())
- string_get_filename(m_params.m_out_filename.c_str(), out_basename);
- else if (m_params.m_source_filenames.size())
- string_get_filename(m_params.m_source_filenames[slice_desc.m_source_file_index].c_str(), out_basename);
-
- string_remove_extension(out_basename);
- out_basename = "basis_debug_" + out_basename + string_format("_slice_%u", slice_index);
-
- // Write "best" ETC1S debug images
- {
- gpu_image best_etc1s_gpu_image(m_best_etc1s_images[slice_index]);
- best_etc1s_gpu_image.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height);
- write_compressed_texture_file((out_basename + "_best_etc1s.ktx").c_str(), best_etc1s_gpu_image);
-
- image best_etc1s_unpacked;
- best_etc1s_gpu_image.unpack(best_etc1s_unpacked);
- save_png(out_basename + "_best_etc1s.png", best_etc1s_unpacked);
- }
-
- // Write decoded ETC1S debug images
- {
- gpu_image decoded_etc1s(m_decoded_output_textures[slice_index]);
- decoded_etc1s.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height);
- write_compressed_texture_file((out_basename + "_decoded_etc1s.ktx").c_str(), decoded_etc1s);
-
- image temp(m_decoded_output_textures_unpacked[slice_index]);
- temp.crop(slice_desc.m_orig_width, slice_desc.m_orig_height);
- save_png(out_basename + "_decoded_etc1s.png", temp);
- }
-
- // Write decoded BC1 debug images
- {
- gpu_image decoded_bc1(m_decoded_output_textures_bc1[slice_index]);
- decoded_bc1.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height);
- write_compressed_texture_file((out_basename + "_decoded_bc1.ktx").c_str(), decoded_bc1);
-
- image temp(m_decoded_output_textures_unpacked_bc1[slice_index]);
- temp.crop(slice_desc.m_orig_width, slice_desc.m_orig_height);
- save_png(out_basename + "_decoded_bc1.png", temp);
- }
- }
- }
-
- return true;
- }
-
-} // namespace basisu
diff --git a/thirdparty/basis_universal/basisu_etc.cpp b/thirdparty/basis_universal/basisu_etc.cpp
deleted file mode 100644
index 244f1d2e6b..0000000000
--- a/thirdparty/basis_universal/basisu_etc.cpp
+++ /dev/null
@@ -1,1074 +0,0 @@
-// basis_etc.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#include "basisu_etc.h"
-
-#define BASISU_DEBUG_ETC_ENCODER 0
-#define BASISU_DEBUG_ETC_ENCODER_DEEPER 0
-
-namespace basisu
-{
- const uint32_t BASISU_ETC1_CLUSTER_FIT_ORDER_TABLE_SIZE = 165;
-
- static const struct { uint8_t m_v[4]; } g_cluster_fit_order_tab[BASISU_ETC1_CLUSTER_FIT_ORDER_TABLE_SIZE] =
- {
- { { 0, 0, 0, 8 } },{ { 0, 5, 2, 1 } },{ { 0, 6, 1, 1 } },{ { 0, 7, 0, 1 } },{ { 0, 7, 1, 0 } },
- { { 0, 0, 8, 0 } },{ { 0, 0, 3, 5 } },{ { 0, 1, 7, 0 } },{ { 0, 0, 4, 4 } },{ { 0, 0, 2, 6 } },
- { { 0, 0, 7, 1 } },{ { 0, 0, 1, 7 } },{ { 0, 0, 5, 3 } },{ { 1, 6, 0, 1 } },{ { 0, 0, 6, 2 } },
- { { 0, 2, 6, 0 } },{ { 2, 4, 2, 0 } },{ { 0, 3, 5, 0 } },{ { 3, 3, 1, 1 } },{ { 4, 2, 0, 2 } },
- { { 1, 5, 2, 0 } },{ { 0, 5, 3, 0 } },{ { 0, 6, 2, 0 } },{ { 2, 4, 1, 1 } },{ { 5, 1, 0, 2 } },
- { { 6, 1, 1, 0 } },{ { 3, 3, 0, 2 } },{ { 6, 0, 0, 2 } },{ { 0, 8, 0, 0 } },{ { 6, 1, 0, 1 } },
- { { 0, 1, 6, 1 } },{ { 1, 6, 1, 0 } },{ { 4, 1, 3, 0 } },{ { 0, 2, 5, 1 } },{ { 5, 0, 3, 0 } },
- { { 5, 3, 0, 0 } },{ { 0, 1, 5, 2 } },{ { 0, 3, 4, 1 } },{ { 2, 5, 1, 0 } },{ { 1, 7, 0, 0 } },
- { { 0, 1, 4, 3 } },{ { 6, 0, 2, 0 } },{ { 0, 4, 4, 0 } },{ { 2, 6, 0, 0 } },{ { 0, 2, 4, 2 } },
- { { 0, 5, 1, 2 } },{ { 0, 6, 0, 2 } },{ { 3, 5, 0, 0 } },{ { 0, 4, 3, 1 } },{ { 3, 4, 1, 0 } },
- { { 4, 3, 1, 0 } },{ { 1, 5, 0, 2 } },{ { 0, 3, 3, 2 } },{ { 1, 4, 1, 2 } },{ { 0, 4, 2, 2 } },
- { { 2, 3, 3, 0 } },{ { 4, 4, 0, 0 } },{ { 1, 2, 4, 1 } },{ { 0, 5, 0, 3 } },{ { 0, 1, 3, 4 } },
- { { 1, 5, 1, 1 } },{ { 1, 4, 2, 1 } },{ { 1, 3, 2, 2 } },{ { 5, 2, 1, 0 } },{ { 1, 3, 3, 1 } },
- { { 0, 1, 2, 5 } },{ { 1, 1, 5, 1 } },{ { 0, 3, 2, 3 } },{ { 2, 5, 0, 1 } },{ { 3, 2, 2, 1 } },
- { { 2, 3, 0, 3 } },{ { 1, 4, 3, 0 } },{ { 2, 2, 1, 3 } },{ { 6, 2, 0, 0 } },{ { 1, 0, 6, 1 } },
- { { 3, 3, 2, 0 } },{ { 7, 1, 0, 0 } },{ { 3, 1, 4, 0 } },{ { 0, 2, 3, 3 } },{ { 0, 4, 1, 3 } },
- { { 0, 4, 0, 4 } },{ { 0, 1, 0, 7 } },{ { 2, 0, 5, 1 } },{ { 2, 0, 4, 2 } },{ { 3, 0, 2, 3 } },
- { { 2, 2, 4, 0 } },{ { 2, 2, 3, 1 } },{ { 4, 0, 3, 1 } },{ { 3, 2, 3, 0 } },{ { 2, 3, 2, 1 } },
- { { 1, 3, 4, 0 } },{ { 7, 0, 1, 0 } },{ { 3, 0, 4, 1 } },{ { 1, 0, 5, 2 } },{ { 8, 0, 0, 0 } },
- { { 3, 0, 1, 4 } },{ { 4, 1, 1, 2 } },{ { 4, 0, 2, 2 } },{ { 1, 2, 5, 0 } },{ { 4, 2, 1, 1 } },
- { { 3, 4, 0, 1 } },{ { 2, 0, 3, 3 } },{ { 5, 0, 1, 2 } },{ { 5, 0, 0, 3 } },{ { 2, 4, 0, 2 } },
- { { 2, 1, 4, 1 } },{ { 4, 0, 1, 3 } },{ { 2, 1, 5, 0 } },{ { 4, 2, 2, 0 } },{ { 4, 0, 4, 0 } },
- { { 1, 0, 4, 3 } },{ { 1, 4, 0, 3 } },{ { 3, 0, 3, 2 } },{ { 4, 3, 0, 1 } },{ { 0, 1, 1, 6 } },
- { { 1, 3, 1, 3 } },{ { 0, 2, 2, 4 } },{ { 2, 0, 2, 4 } },{ { 5, 1, 1, 1 } },{ { 3, 0, 5, 0 } },
- { { 2, 3, 1, 2 } },{ { 3, 0, 0, 5 } },{ { 0, 3, 1, 4 } },{ { 5, 0, 2, 1 } },{ { 2, 1, 3, 2 } },
- { { 2, 0, 6, 0 } },{ { 3, 1, 3, 1 } },{ { 5, 1, 2, 0 } },{ { 1, 0, 3, 4 } },{ { 1, 1, 6, 0 } },
- { { 4, 0, 0, 4 } },{ { 2, 0, 1, 5 } },{ { 0, 3, 0, 5 } },{ { 1, 3, 0, 4 } },{ { 4, 1, 2, 1 } },
- { { 1, 2, 3, 2 } },{ { 3, 1, 0, 4 } },{ { 5, 2, 0, 1 } },{ { 1, 2, 2, 3 } },{ { 3, 2, 1, 2 } },
- { { 2, 2, 2, 2 } },{ { 6, 0, 1, 1 } },{ { 1, 2, 1, 4 } },{ { 1, 1, 4, 2 } },{ { 3, 2, 0, 3 } },
- { { 1, 2, 0, 5 } },{ { 1, 0, 7, 0 } },{ { 3, 1, 2, 2 } },{ { 1, 0, 2, 5 } },{ { 2, 0, 0, 6 } },
- { { 2, 1, 1, 4 } },{ { 2, 2, 0, 4 } },{ { 1, 1, 3, 3 } },{ { 7, 0, 0, 1 } },{ { 1, 0, 0, 7 } },
- { { 2, 1, 2, 3 } },{ { 4, 1, 0, 3 } },{ { 3, 1, 1, 3 } },{ { 1, 1, 2, 4 } },{ { 2, 1, 0, 5 } },
- { { 1, 0, 1, 6 } },{ { 0, 2, 1, 5 } },{ { 0, 2, 0, 6 } },{ { 1, 1, 1, 5 } },{ { 1, 1, 0, 6 } }
- };
-
- const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues] =
- {
- { -8, -2, 2, 8 }, { -17, -5, 5, 17 }, { -29, -9, 9, 29 }, { -42, -13, 13, 42 },
- { -60, -18, 18, 60 }, { -80, -24, 24, 80 }, { -106, -33, 33, 106 }, { -183, -47, 47, 183 }
- };
-
- const uint8_t g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 };
- const uint8_t g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 };
-
- // [flip][subblock][pixel_index]
- const etc_coord2 g_etc1_pixel_coords[2][2][8] =
- {
- {
- {
- { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 },
- { 1, 0 }, { 1, 1 }, { 1, 2 }, { 1, 3 }
- },
- {
- { 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 },
- { 3, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 }
- }
- },
- {
- {
- { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
- { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }
- },
- {
- { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },
- { 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 }
- },
- }
- };
-
- // [flip][subblock][pixel_index]
- const uint32_t g_etc1_pixel_indices[2][2][8] =
- {
- {
- {
- 0 + 4 * 0, 0 + 4 * 1, 0 + 4 * 2, 0 + 4 * 3,
- 1 + 4 * 0, 1 + 4 * 1, 1 + 4 * 2, 1 + 4 * 3
- },
- {
- 2 + 4 * 0, 2 + 4 * 1, 2 + 4 * 2, 2 + 4 * 3,
- 3 + 4 * 0, 3 + 4 * 1, 3 + 4 * 2, 3 + 4 * 3
- }
- },
- {
- {
- 0 + 4 * 0, 1 + 4 * 0, 2 + 4 * 0, 3 + 4 * 0,
- 0 + 4 * 1, 1 + 4 * 1, 2 + 4 * 1, 3 + 4 * 1
- },
- {
- 0 + 4 * 2, 1 + 4 * 2, 2 + 4 * 2, 3 + 4 * 2,
- 0 + 4 * 3, 1 + 4 * 3, 2 + 4 * 3, 3 + 4 * 3
- },
- }
- };
-
- uint16_t etc_block::pack_color5(const color_rgba& color, bool scaled, uint32_t bias)
- {
- return pack_color5(color.r, color.g, color.b, scaled, bias);
- }
-
- uint16_t etc_block::pack_color5(uint32_t r, uint32_t g, uint32_t b, bool scaled, uint32_t bias)
- {
- if (scaled)
- {
- r = (r * 31U + bias) / 255U;
- g = (g * 31U + bias) / 255U;
- b = (b * 31U + bias) / 255U;
- }
-
- r = minimum(r, 31U);
- g = minimum(g, 31U);
- b = minimum(b, 31U);
-
- return static_cast<uint16_t>(b | (g << 5U) | (r << 10U));
- }
-
- color_rgba etc_block::unpack_color5(uint16_t packed_color5, bool scaled, uint32_t alpha)
- {
- uint32_t b = packed_color5 & 31U;
- uint32_t g = (packed_color5 >> 5U) & 31U;
- uint32_t r = (packed_color5 >> 10U) & 31U;
-
- if (scaled)
- {
- b = (b << 3U) | (b >> 2U);
- g = (g << 3U) | (g >> 2U);
- r = (r << 3U) | (r >> 2U);
- }
-
- return color_rgba(cNoClamp, r, g, b, minimum(alpha, 255U));
- }
-
- void etc_block::unpack_color5(color_rgba& result, uint16_t packed_color5, bool scaled)
- {
- result = unpack_color5(packed_color5, scaled, 255);
- }
-
- void etc_block::unpack_color5(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color5, bool scaled)
- {
- color_rgba c(unpack_color5(packed_color5, scaled, 0));
- r = c.r;
- g = c.g;
- b = c.b;
- }
-
- bool etc_block::unpack_color5(color_rgba& result, uint16_t packed_color5, uint16_t packed_delta3, bool scaled, uint32_t alpha)
- {
- color_rgba_i16 dc(unpack_delta3(packed_delta3));
-
- int b = (packed_color5 & 31U) + dc.b;
- int g = ((packed_color5 >> 5U) & 31U) + dc.g;
- int r = ((packed_color5 >> 10U) & 31U) + dc.r;
-
- bool success = true;
- if (static_cast<uint32_t>(r | g | b) > 31U)
- {
- success = false;
- r = clamp<int>(r, 0, 31);
- g = clamp<int>(g, 0, 31);
- b = clamp<int>(b, 0, 31);
- }
-
- if (scaled)
- {
- b = (b << 3U) | (b >> 2U);
- g = (g << 3U) | (g >> 2U);
- r = (r << 3U) | (r >> 2U);
- }
-
- result.set_noclamp_rgba(r, g, b, minimum(alpha, 255U));
- return success;
- }
-
- bool etc_block::unpack_color5(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color5, uint16_t packed_delta3, bool scaled, uint32_t alpha)
- {
- color_rgba result;
- const bool success = unpack_color5(result, packed_color5, packed_delta3, scaled, alpha);
- r = result.r;
- g = result.g;
- b = result.b;
- return success;
- }
-
- uint16_t etc_block::pack_delta3(const color_rgba_i16& color)
- {
- return pack_delta3(color.r, color.g, color.b);
- }
-
- uint16_t etc_block::pack_delta3(int r, int g, int b)
- {
- assert((r >= cETC1ColorDeltaMin) && (r <= cETC1ColorDeltaMax));
- assert((g >= cETC1ColorDeltaMin) && (g <= cETC1ColorDeltaMax));
- assert((b >= cETC1ColorDeltaMin) && (b <= cETC1ColorDeltaMax));
- if (r < 0) r += 8;
- if (g < 0) g += 8;
- if (b < 0) b += 8;
- return static_cast<uint16_t>(b | (g << 3) | (r << 6));
- }
-
- color_rgba_i16 etc_block::unpack_delta3(uint16_t packed_delta3)
- {
- int r = (packed_delta3 >> 6) & 7;
- int g = (packed_delta3 >> 3) & 7;
- int b = packed_delta3 & 7;
- if (r >= 4) r -= 8;
- if (g >= 4) g -= 8;
- if (b >= 4) b -= 8;
- return color_rgba_i16(r, g, b, 255);
- }
-
- void etc_block::unpack_delta3(int& r, int& g, int& b, uint16_t packed_delta3)
- {
- r = (packed_delta3 >> 6) & 7;
- g = (packed_delta3 >> 3) & 7;
- b = packed_delta3 & 7;
- if (r >= 4) r -= 8;
- if (g >= 4) g -= 8;
- if (b >= 4) b -= 8;
- }
-
- uint16_t etc_block::pack_color4(const color_rgba& color, bool scaled, uint32_t bias)
- {
- return pack_color4(color.r, color.g, color.b, scaled, bias);
- }
-
- uint16_t etc_block::pack_color4(uint32_t r, uint32_t g, uint32_t b, bool scaled, uint32_t bias)
- {
- if (scaled)
- {
- r = (r * 15U + bias) / 255U;
- g = (g * 15U + bias) / 255U;
- b = (b * 15U + bias) / 255U;
- }
-
- r = minimum(r, 15U);
- g = minimum(g, 15U);
- b = minimum(b, 15U);
-
- return static_cast<uint16_t>(b | (g << 4U) | (r << 8U));
- }
-
- color_rgba etc_block::unpack_color4(uint16_t packed_color4, bool scaled, uint32_t alpha)
- {
- uint32_t b = packed_color4 & 15U;
- uint32_t g = (packed_color4 >> 4U) & 15U;
- uint32_t r = (packed_color4 >> 8U) & 15U;
-
- if (scaled)
- {
- b = (b << 4U) | b;
- g = (g << 4U) | g;
- r = (r << 4U) | r;
- }
-
- return color_rgba(cNoClamp, r, g, b, minimum(alpha, 255U));
- }
-
- void etc_block::unpack_color4(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color4, bool scaled)
- {
- color_rgba c(unpack_color4(packed_color4, scaled, 0));
- r = c.r;
- g = c.g;
- b = c.b;
- }
-
- void etc_block::get_diff_subblock_colors(color_rgba* pDst, uint16_t packed_color5, uint32_t table_idx)
- {
- assert(table_idx < cETC1IntenModifierValues);
- const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
-
- uint32_t r, g, b;
- unpack_color5(r, g, b, packed_color5, true);
-
- const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
-
- const int y0 = pInten_modifer_table[0];
- pDst[0].set(ir + y0, ig + y0, ib + y0, 255);
-
- const int y1 = pInten_modifer_table[1];
- pDst[1].set(ir + y1, ig + y1, ib + y1, 255);
-
- const int y2 = pInten_modifer_table[2];
- pDst[2].set(ir + y2, ig + y2, ib + y2, 255);
-
- const int y3 = pInten_modifer_table[3];
- pDst[3].set(ir + y3, ig + y3, ib + y3, 255);
- }
-
- bool etc_block::get_diff_subblock_colors(color_rgba* pDst, uint16_t packed_color5, uint16_t packed_delta3, uint32_t table_idx)
- {
- assert(table_idx < cETC1IntenModifierValues);
- const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
-
- uint32_t r, g, b;
- bool success = unpack_color5(r, g, b, packed_color5, packed_delta3, true);
-
- const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
-
- const int y0 = pInten_modifer_table[0];
- pDst[0].set(ir + y0, ig + y0, ib + y0, 255);
-
- const int y1 = pInten_modifer_table[1];
- pDst[1].set(ir + y1, ig + y1, ib + y1, 255);
-
- const int y2 = pInten_modifer_table[2];
- pDst[2].set(ir + y2, ig + y2, ib + y2, 255);
-
- const int y3 = pInten_modifer_table[3];
- pDst[3].set(ir + y3, ig + y3, ib + y3, 255);
-
- return success;
- }
-
- void etc_block::get_abs_subblock_colors(color_rgba* pDst, uint16_t packed_color4, uint32_t table_idx)
- {
- assert(table_idx < cETC1IntenModifierValues);
- const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
-
- uint32_t r, g, b;
- unpack_color4(r, g, b, packed_color4, true);
-
- const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
-
- const int y0 = pInten_modifer_table[0];
- pDst[0].set(ir + y0, ig + y0, ib + y0, 255);
-
- const int y1 = pInten_modifer_table[1];
- pDst[1].set(ir + y1, ig + y1, ib + y1, 255);
-
- const int y2 = pInten_modifer_table[2];
- pDst[2].set(ir + y2, ig + y2, ib + y2, 255);
-
- const int y3 = pInten_modifer_table[3];
- pDst[3].set(ir + y3, ig + y3, ib + y3, 255);
- }
-
- bool unpack_etc1(const etc_block& block, color_rgba *pDst, bool preserve_alpha)
- {
- const bool diff_flag = block.get_diff_bit();
- const bool flip_flag = block.get_flip_bit();
- const uint32_t table_index0 = block.get_inten_table(0);
- const uint32_t table_index1 = block.get_inten_table(1);
-
- color_rgba subblock_colors0[4];
- color_rgba subblock_colors1[4];
-
- if (diff_flag)
- {
- const uint16_t base_color5 = block.get_base5_color();
- const uint16_t delta_color3 = block.get_delta3_color();
- etc_block::get_diff_subblock_colors(subblock_colors0, base_color5, table_index0);
-
- if (!etc_block::get_diff_subblock_colors(subblock_colors1, base_color5, delta_color3, table_index1))
- return false;
- }
- else
- {
- const uint16_t base_color4_0 = block.get_base4_color(0);
- etc_block::get_abs_subblock_colors(subblock_colors0, base_color4_0, table_index0);
-
- const uint16_t base_color4_1 = block.get_base4_color(1);
- etc_block::get_abs_subblock_colors(subblock_colors1, base_color4_1, table_index1);
- }
-
- if (preserve_alpha)
- {
- if (flip_flag)
- {
- for (uint32_t y = 0; y < 2; y++)
- {
- pDst[0].set_rgb(subblock_colors0[block.get_selector(0, y)]);
- pDst[1].set_rgb(subblock_colors0[block.get_selector(1, y)]);
- pDst[2].set_rgb(subblock_colors0[block.get_selector(2, y)]);
- pDst[3].set_rgb(subblock_colors0[block.get_selector(3, y)]);
- pDst += 4;
- }
-
- for (uint32_t y = 2; y < 4; y++)
- {
- pDst[0].set_rgb(subblock_colors1[block.get_selector(0, y)]);
- pDst[1].set_rgb(subblock_colors1[block.get_selector(1, y)]);
- pDst[2].set_rgb(subblock_colors1[block.get_selector(2, y)]);
- pDst[3].set_rgb(subblock_colors1[block.get_selector(3, y)]);
- pDst += 4;
- }
- }
- else
- {
- for (uint32_t y = 0; y < 4; y++)
- {
- pDst[0].set_rgb(subblock_colors0[block.get_selector(0, y)]);
- pDst[1].set_rgb(subblock_colors0[block.get_selector(1, y)]);
- pDst[2].set_rgb(subblock_colors1[block.get_selector(2, y)]);
- pDst[3].set_rgb(subblock_colors1[block.get_selector(3, y)]);
- pDst += 4;
- }
- }
- }
- else
- {
- if (flip_flag)
- {
- // 0000
- // 0000
- // 1111
- // 1111
- for (uint32_t y = 0; y < 2; y++)
- {
- pDst[0] = subblock_colors0[block.get_selector(0, y)];
- pDst[1] = subblock_colors0[block.get_selector(1, y)];
- pDst[2] = subblock_colors0[block.get_selector(2, y)];
- pDst[3] = subblock_colors0[block.get_selector(3, y)];
- pDst += 4;
- }
-
- for (uint32_t y = 2; y < 4; y++)
- {
- pDst[0] = subblock_colors1[block.get_selector(0, y)];
- pDst[1] = subblock_colors1[block.get_selector(1, y)];
- pDst[2] = subblock_colors1[block.get_selector(2, y)];
- pDst[3] = subblock_colors1[block.get_selector(3, y)];
- pDst += 4;
- }
- }
- else
- {
- // 0011
- // 0011
- // 0011
- // 0011
- for (uint32_t y = 0; y < 4; y++)
- {
- pDst[0] = subblock_colors0[block.get_selector(0, y)];
- pDst[1] = subblock_colors0[block.get_selector(1, y)];
- pDst[2] = subblock_colors1[block.get_selector(2, y)];
- pDst[3] = subblock_colors1[block.get_selector(3, y)];
- pDst += 4;
- }
- }
- }
-
- return true;
- }
-
- inline int extend_6_to_8(uint32_t n)
- {
- return (n << 2) | (n >> 4);
- }
-
- inline int extend_7_to_8(uint32_t n)
- {
- return (n << 1) | (n >> 6);
- }
-
- inline int extend_4_to_8(uint32_t n)
- {
- return (n << 4) | n;
- }
-
- uint64_t etc_block::evaluate_etc1_error(const color_rgba* pBlock_pixels, bool perceptual, int subblock_index) const
- {
- color_rgba unpacked_block[16];
-
- unpack_etc1(*this, unpacked_block);
-
- uint64_t total_error = 0;
-
- if (subblock_index < 0)
- {
- for (uint32_t i = 0; i < 16; i++)
- total_error += color_distance(perceptual, pBlock_pixels[i], unpacked_block[i], false);
- }
- else
- {
- const bool flip_bit = get_flip_bit();
-
- for (uint32_t i = 0; i < 8; i++)
- {
- const uint32_t idx = g_etc1_pixel_indices[flip_bit][subblock_index][i];
-
- total_error += color_distance(perceptual, pBlock_pixels[idx], unpacked_block[idx], false);
- }
- }
-
- return total_error;
- }
-
- void etc_block::get_subblock_pixels(color_rgba* pPixels, int subblock_index) const
- {
- if (subblock_index < 0)
- unpack_etc1(*this, pPixels);
- else
- {
- color_rgba unpacked_block[16];
-
- unpack_etc1(*this, unpacked_block);
-
- const bool flip_bit = get_flip_bit();
-
- for (uint32_t i = 0; i < 8; i++)
- {
- const uint32_t idx = g_etc1_pixel_indices[flip_bit][subblock_index][i];
-
- pPixels[i] = unpacked_block[idx];
- }
- }
- }
-
- bool etc1_optimizer::compute()
- {
- assert(m_pResult->m_pSelectors);
-
- if ((m_pParams->m_pForce_selectors) || (m_pParams->m_pEval_solution_override))
- {
- assert(m_pParams->m_quality >= cETCQualitySlow);
- }
-
- const uint32_t n = m_pParams->m_num_src_pixels;
-
- if (m_pParams->m_cluster_fit)
- {
- if (m_pParams->m_quality == cETCQualityFast)
- compute_internal_cluster_fit(4);
- else if (m_pParams->m_quality == cETCQualityMedium)
- compute_internal_cluster_fit(32);
- else if (m_pParams->m_quality == cETCQualitySlow)
- compute_internal_cluster_fit(64);
- else
- compute_internal_cluster_fit(BASISU_ETC1_CLUSTER_FIT_ORDER_TABLE_SIZE);
- }
- else
- compute_internal_neighborhood(m_br, m_bg, m_bb);
-
- if (!m_best_solution.m_valid)
- {
- m_pResult->m_error = UINT32_MAX;
- return false;
- }
-
- const uint8_t* pSelectors = &m_best_solution.m_selectors[0];
-
-#ifdef BASISU_BUILD_DEBUG
- if (m_pParams->m_pEval_solution_override == nullptr)
- {
- color_rgba block_colors[4];
- m_best_solution.m_coords.get_block_colors(block_colors);
-
- const color_rgba* pSrc_pixels = m_pParams->m_pSrc_pixels;
- uint64_t actual_error = 0;
- for (uint32_t i = 0; i < n; i++)
- {
- if ((m_pParams->m_perceptual) && (m_pParams->m_quality >= cETCQualitySlow))
- actual_error += color_distance(true, pSrc_pixels[i], block_colors[pSelectors[i]], false);
- else
- actual_error += color_distance(pSrc_pixels[i], block_colors[pSelectors[i]], false);
- }
- assert(actual_error == m_best_solution.m_error);
- }
-#endif
-
- m_pResult->m_error = m_best_solution.m_error;
-
- m_pResult->m_block_color_unscaled = m_best_solution.m_coords.m_unscaled_color;
- m_pResult->m_block_color4 = m_best_solution.m_coords.m_color4;
-
- m_pResult->m_block_inten_table = m_best_solution.m_coords.m_inten_table;
- memcpy(m_pResult->m_pSelectors, pSelectors, n);
- m_pResult->m_n = n;
-
- return true;
- }
-
- void etc1_optimizer::refine_solution(uint32_t max_refinement_trials)
- {
- // Now we have the input block, the avg. color of the input pixels, a set of trial selector indices, and the block color+intensity index.
- // Now, for each component, attempt to refine the current solution by solving a simple linear equation. For example, for 4 colors:
- // The goal is:
- // pixel0 - (block_color+inten_table[selector0]) + pixel1 - (block_color+inten_table[selector1]) + pixel2 - (block_color+inten_table[selector2]) + pixel3 - (block_color+inten_table[selector3]) = 0
- // Rearranging this:
- // (pixel0 + pixel1 + pixel2 + pixel3) - (block_color+inten_table[selector0]) - (block_color+inten_table[selector1]) - (block_color+inten_table[selector2]) - (block_color+inten_table[selector3]) = 0
- // (pixel0 + pixel1 + pixel2 + pixel3) - block_color - inten_table[selector0] - block_color-inten_table[selector1] - block_color-inten_table[selector2] - block_color-inten_table[selector3] = 0
- // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - inten_table[selector0] - inten_table[selector1] - inten_table[selector2] - inten_table[selector3] = 0
- // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3]) = 0
- // (pixel0 + pixel1 + pixel2 + pixel3)/4 - block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4 = 0
- // block_color = (pixel0 + pixel1 + pixel2 + pixel3)/4 - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4
- // So what this means:
- // optimal_block_color = avg_input - avg_inten_delta
- // So the optimal block color can be computed by taking the average block color and subtracting the current average of the intensity delta.
- // Unfortunately, optimal_block_color must then be quantized to 555 or 444 so it's not always possible to improve matters using this formula.
- // Also, the above formula is for unclamped intensity deltas. The actual implementation takes into account clamping.
-
- const uint32_t n = m_pParams->m_num_src_pixels;
-
- for (uint32_t refinement_trial = 0; refinement_trial < max_refinement_trials; refinement_trial++)
- {
- const uint8_t* pSelectors = &m_best_solution.m_selectors[0];
- const int* pInten_table = g_etc1_inten_tables[m_best_solution.m_coords.m_inten_table];
-
- int delta_sum_r = 0, delta_sum_g = 0, delta_sum_b = 0;
- const color_rgba base_color(m_best_solution.m_coords.get_scaled_color());
- for (uint32_t r = 0; r < n; r++)
- {
- const uint32_t s = *pSelectors++;
- const int yd_temp = pInten_table[s];
- // Compute actual delta being applied to each pixel, taking into account clamping.
- delta_sum_r += clamp<int>(base_color.r + yd_temp, 0, 255) - base_color.r;
- delta_sum_g += clamp<int>(base_color.g + yd_temp, 0, 255) - base_color.g;
- delta_sum_b += clamp<int>(base_color.b + yd_temp, 0, 255) - base_color.b;
- }
-
- if ((!delta_sum_r) && (!delta_sum_g) && (!delta_sum_b))
- break;
-
- const float avg_delta_r_f = static_cast<float>(delta_sum_r) / n;
- const float avg_delta_g_f = static_cast<float>(delta_sum_g) / n;
- const float avg_delta_b_f = static_cast<float>(delta_sum_b) / n;
- const int br1 = clamp<int>(static_cast<uint32_t>((m_avg_color[0] - avg_delta_r_f) * m_limit / 255.0f + .5f), 0, m_limit);
- const int bg1 = clamp<int>(static_cast<uint32_t>((m_avg_color[1] - avg_delta_g_f) * m_limit / 255.0f + .5f), 0, m_limit);
- const int bb1 = clamp<int>(static_cast<uint32_t>((m_avg_color[2] - avg_delta_b_f) * m_limit / 255.0f + .5f), 0, m_limit);
-
-#if BASISU_DEBUG_ETC_ENCODER_DEEPER
- printf("Refinement trial %u, avg_delta %f %f %f\n", refinement_trial, avg_delta_r_f, avg_delta_g_f, avg_delta_b_f);
-#endif
-
- if (!evaluate_solution(etc1_solution_coordinates(br1, bg1, bb1, 0, m_pParams->m_use_color4), m_trial_solution, &m_best_solution))
- break;
-
- } // refinement_trial
- }
-
- void etc1_optimizer::compute_internal_neighborhood(int scan_r, int scan_g, int scan_b)
- {
- if (m_best_solution.m_error == 0)
- return;
-
- const uint32_t n = m_pParams->m_num_src_pixels;
- const int scan_delta_size = m_pParams->m_scan_delta_size;
-
- // Scan through a subset of the 3D lattice centered around the avg block color trying each 3D (555 or 444) lattice point as a potential block color.
- // Each time a better solution is found try to refine the current solution's block color based of the current selectors and intensity table index.
- for (int zdi = 0; zdi < scan_delta_size; zdi++)
- {
- const int zd = m_pParams->m_pScan_deltas[zdi];
- const int mbb = scan_b + zd;
- if (mbb < 0) continue; else if (mbb > m_limit) break;
-
- for (int ydi = 0; ydi < scan_delta_size; ydi++)
- {
- const int yd = m_pParams->m_pScan_deltas[ydi];
- const int mbg = scan_g + yd;
- if (mbg < 0) continue; else if (mbg > m_limit) break;
-
- for (int xdi = 0; xdi < scan_delta_size; xdi++)
- {
- const int xd = m_pParams->m_pScan_deltas[xdi];
- const int mbr = scan_r + xd;
- if (mbr < 0) continue; else if (mbr > m_limit) break;
-
- etc1_solution_coordinates coords(mbr, mbg, mbb, 0, m_pParams->m_use_color4);
-
- if (!evaluate_solution(coords, m_trial_solution, &m_best_solution))
- continue;
-
- if (m_pParams->m_refinement)
- {
- refine_solution((m_pParams->m_quality == cETCQualityFast) ? 2 : (((xd | yd | zd) == 0) ? 4 : 2));
- }
-
- } // xdi
- } // ydi
- } // zdi
- }
-
- void etc1_optimizer::compute_internal_cluster_fit(uint32_t total_perms_to_try)
- {
- if ((!m_best_solution.m_valid) || ((m_br != m_best_solution.m_coords.m_unscaled_color.r) || (m_bg != m_best_solution.m_coords.m_unscaled_color.g) || (m_bb != m_best_solution.m_coords.m_unscaled_color.b)))
- {
- evaluate_solution(etc1_solution_coordinates(m_br, m_bg, m_bb, 0, m_pParams->m_use_color4), m_trial_solution, &m_best_solution);
- }
-
- if ((m_best_solution.m_error == 0) || (!m_best_solution.m_valid))
- return;
-
- for (uint32_t i = 0; i < total_perms_to_try; i++)
- {
- int delta_sum_r = 0, delta_sum_g = 0, delta_sum_b = 0;
-
- const int *pInten_table = g_etc1_inten_tables[m_best_solution.m_coords.m_inten_table];
- const color_rgba base_color(m_best_solution.m_coords.get_scaled_color());
-
- const uint8_t *pNum_selectors = g_cluster_fit_order_tab[i].m_v;
-
- for (uint32_t q = 0; q < 4; q++)
- {
- const int yd_temp = pInten_table[q];
-
- delta_sum_r += pNum_selectors[q] * (clamp<int>(base_color.r + yd_temp, 0, 255) - base_color.r);
- delta_sum_g += pNum_selectors[q] * (clamp<int>(base_color.g + yd_temp, 0, 255) - base_color.g);
- delta_sum_b += pNum_selectors[q] * (clamp<int>(base_color.b + yd_temp, 0, 255) - base_color.b);
- }
-
- if ((!delta_sum_r) && (!delta_sum_g) && (!delta_sum_b))
- continue;
-
- const float avg_delta_r_f = static_cast<float>(delta_sum_r) / 8;
- const float avg_delta_g_f = static_cast<float>(delta_sum_g) / 8;
- const float avg_delta_b_f = static_cast<float>(delta_sum_b) / 8;
-
- const int br1 = clamp<int>(static_cast<uint32_t>((m_avg_color[0] - avg_delta_r_f) * m_limit / 255.0f + .5f), 0, m_limit);
- const int bg1 = clamp<int>(static_cast<uint32_t>((m_avg_color[1] - avg_delta_g_f) * m_limit / 255.0f + .5f), 0, m_limit);
- const int bb1 = clamp<int>(static_cast<uint32_t>((m_avg_color[2] - avg_delta_b_f) * m_limit / 255.0f + .5f), 0, m_limit);
-
-#if BASISU_DEBUG_ETC_ENCODER_DEEPER
- printf("Second refinement trial %u, avg_delta %f %f %f\n", i, avg_delta_r_f, avg_delta_g_f, avg_delta_b_f);
-#endif
-
- evaluate_solution(etc1_solution_coordinates(br1, bg1, bb1, 0, m_pParams->m_use_color4), m_trial_solution, &m_best_solution);
-
- if (m_best_solution.m_error == 0)
- break;
- }
- }
-
- void etc1_optimizer::init(const params& params, results& result)
- {
- m_pParams = &params;
- m_pResult = &result;
-
- const uint32_t n = m_pParams->m_num_src_pixels;
-
- m_selectors.resize(n);
- m_best_selectors.resize(n);
- m_temp_selectors.resize(n);
- m_trial_solution.m_selectors.resize(n);
- m_best_solution.m_selectors.resize(n);
-
- m_limit = m_pParams->m_use_color4 ? 15 : 31;
-
- vec3F avg_color(0.0f);
-
- m_luma.resize(n);
- m_sorted_luma_indices.resize(n);
- m_sorted_luma.resize(n);
-
- for (uint32_t i = 0; i < n; i++)
- {
- const color_rgba& c = m_pParams->m_pSrc_pixels[i];
- const vec3F fc(c.r, c.g, c.b);
-
- avg_color += fc;
-
- m_luma[i] = static_cast<uint16_t>(c.r + c.g + c.b);
- m_sorted_luma_indices[i] = i;
- }
- avg_color /= static_cast<float>(n);
- m_avg_color = avg_color;
-
- m_br = clamp<int>(static_cast<uint32_t>(m_avg_color[0] * m_limit / 255.0f + .5f), 0, m_limit);
- m_bg = clamp<int>(static_cast<uint32_t>(m_avg_color[1] * m_limit / 255.0f + .5f), 0, m_limit);
- m_bb = clamp<int>(static_cast<uint32_t>(m_avg_color[2] * m_limit / 255.0f + .5f), 0, m_limit);
-
-#if BASISU_DEBUG_ETC_ENCODER_DEEPER
- printf("Avg block color: %u %u %u\n", m_br, m_bg, m_bb);
-#endif
-
- if (m_pParams->m_quality <= cETCQualityMedium)
- {
- indirect_sort(n, &m_sorted_luma_indices[0], &m_luma[0]);
-
- m_pSorted_luma = &m_sorted_luma[0];
- m_pSorted_luma_indices = &m_sorted_luma_indices[0];
-
- for (uint32_t i = 0; i < n; i++)
- m_pSorted_luma[i] = m_luma[m_pSorted_luma_indices[i]];
- }
-
- m_best_solution.m_coords.clear();
- m_best_solution.m_valid = false;
- m_best_solution.m_error = UINT64_MAX;
-
- m_solutions_tried.clear();
- }
-
- bool etc1_optimizer::evaluate_solution_slow(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution)
- {
- uint32_t k = coords.m_unscaled_color.r | (coords.m_unscaled_color.g << 8) | (coords.m_unscaled_color.b << 16);
- if (!m_solutions_tried.insert(k).second)
- return false;
-
-#if BASISU_DEBUG_ETC_ENCODER_DEEPER
- printf("Eval solution: %u %u %u\n", coords.m_unscaled_color.r, coords.m_unscaled_color.g, coords.m_unscaled_color.b);
-#endif
-
- trial_solution.m_valid = false;
-
- if (m_pParams->m_constrain_against_base_color5)
- {
- const int dr = (int)coords.m_unscaled_color.r - (int)m_pParams->m_base_color5.r;
- const int dg = (int)coords.m_unscaled_color.g - (int)m_pParams->m_base_color5.g;
- const int db = (int)coords.m_unscaled_color.b - (int)m_pParams->m_base_color5.b;
-
- if ((minimum(dr, dg, db) < cETC1ColorDeltaMin) || (maximum(dr, dg, db) > cETC1ColorDeltaMax))
- {
-#if BASISU_DEBUG_ETC_ENCODER_DEEPER
- printf("Eval failed due to constraint from %u %u %u\n", m_pParams->m_base_color5.r, m_pParams->m_base_color5.g, m_pParams->m_base_color5.b);
-#endif
- return false;
- }
- }
-
- const color_rgba base_color(coords.get_scaled_color());
-
- const uint32_t n = m_pParams->m_num_src_pixels;
- assert(trial_solution.m_selectors.size() == n);
-
- trial_solution.m_error = UINT64_MAX;
-
- const uint8_t *pSelectors_to_use = m_pParams->m_pForce_selectors;
-
- for (uint32_t inten_table = 0; inten_table < cETC1IntenModifierValues; inten_table++)
- {
- const int* pInten_table = g_etc1_inten_tables[inten_table];
-
- color_rgba block_colors[4];
- for (uint32_t s = 0; s < 4; s++)
- {
- const int yd = pInten_table[s];
- block_colors[s].set(base_color.r + yd, base_color.g + yd, base_color.b + yd, 255);
- }
-
- uint64_t total_error = 0;
-
- const color_rgba* pSrc_pixels = m_pParams->m_pSrc_pixels;
- for (uint32_t c = 0; c < n; c++)
- {
- const color_rgba& src_pixel = *pSrc_pixels++;
-
- uint32_t best_selector_index = 0;
- uint32_t best_error = 0;
-
- if (pSelectors_to_use)
- {
- best_selector_index = pSelectors_to_use[c];
- best_error = color_distance(m_pParams->m_perceptual, src_pixel, block_colors[best_selector_index], false);
- }
- else
- {
- best_error = color_distance(m_pParams->m_perceptual, src_pixel, block_colors[0], false);
-
- uint32_t trial_error = color_distance(m_pParams->m_perceptual, src_pixel, block_colors[1], false);
- if (trial_error < best_error)
- {
- best_error = trial_error;
- best_selector_index = 1;
- }
-
- trial_error = color_distance(m_pParams->m_perceptual, src_pixel, block_colors[2], false);
- if (trial_error < best_error)
- {
- best_error = trial_error;
- best_selector_index = 2;
- }
-
- trial_error = color_distance(m_pParams->m_perceptual, src_pixel, block_colors[3], false);
- if (trial_error < best_error)
- {
- best_error = trial_error;
- best_selector_index = 3;
- }
- }
-
- m_temp_selectors[c] = static_cast<uint8_t>(best_selector_index);
-
- total_error += best_error;
- if ((m_pParams->m_pEval_solution_override == nullptr) && (total_error >= trial_solution.m_error))
- break;
- }
-
- if (m_pParams->m_pEval_solution_override)
- {
- if (!(*m_pParams->m_pEval_solution_override)(total_error, *m_pParams, block_colors, &m_temp_selectors[0], coords))
- return false;
- }
-
- if (total_error < trial_solution.m_error)
- {
- trial_solution.m_error = total_error;
- trial_solution.m_coords.m_inten_table = inten_table;
- trial_solution.m_selectors.swap(m_temp_selectors);
- trial_solution.m_valid = true;
- }
- }
- trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color;
- trial_solution.m_coords.m_color4 = m_pParams->m_use_color4;
-
-#if BASISU_DEBUG_ETC_ENCODER_DEEPER
- printf("Eval done: %u error: %I64u best error so far: %I64u\n", (trial_solution.m_error < pBest_solution->m_error), trial_solution.m_error, pBest_solution->m_error);
-#endif
-
- bool success = false;
- if (pBest_solution)
- {
- if (trial_solution.m_error < pBest_solution->m_error)
- {
- *pBest_solution = trial_solution;
- success = true;
- }
- }
-
- return success;
- }
-
- bool etc1_optimizer::evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution)
- {
- uint32_t k = coords.m_unscaled_color.r | (coords.m_unscaled_color.g << 8) | (coords.m_unscaled_color.b << 16);
- if (!m_solutions_tried.insert(k).second)
- return false;
-
-#if BASISU_DEBUG_ETC_ENCODER_DEEPER
- printf("Eval solution fast: %u %u %u\n", coords.m_unscaled_color.r, coords.m_unscaled_color.g, coords.m_unscaled_color.b);
-#endif
-
- if (m_pParams->m_constrain_against_base_color5)
- {
- const int dr = (int)coords.m_unscaled_color.r - (int)m_pParams->m_base_color5.r;
- const int dg = (int)coords.m_unscaled_color.g - (int)m_pParams->m_base_color5.g;
- const int db = (int)coords.m_unscaled_color.b - (int)m_pParams->m_base_color5.b;
-
- if ((minimum(dr, dg, db) < cETC1ColorDeltaMin) || (maximum(dr, dg, db) > cETC1ColorDeltaMax))
- {
- trial_solution.m_valid = false;
-
-#if BASISU_DEBUG_ETC_ENCODER_DEEPER
- printf("Eval failed due to constraint from %u %u %u\n", m_pParams->m_base_color5.r, m_pParams->m_base_color5.g, m_pParams->m_base_color5.b);
-#endif
- return false;
- }
- }
-
- const color_rgba base_color(coords.get_scaled_color());
-
- const uint32_t n = m_pParams->m_num_src_pixels;
- assert(trial_solution.m_selectors.size() == n);
-
- trial_solution.m_error = UINT64_MAX;
-
- for (int inten_table = cETC1IntenModifierValues - 1; inten_table >= 0; --inten_table)
- {
- const int* pInten_table = g_etc1_inten_tables[inten_table];
-
- uint32_t block_inten[4];
- color_rgba block_colors[4];
- for (uint32_t s = 0; s < 4; s++)
- {
- const int yd = pInten_table[s];
- color_rgba block_color(base_color.r + yd, base_color.g + yd, base_color.b + yd, 255);
- block_colors[s] = block_color;
- block_inten[s] = block_color.r + block_color.g + block_color.b;
- }
-
- // evaluate_solution_fast() enforces/assumesd a total ordering of the input colors along the intensity (1,1,1) axis to more quickly classify the inputs to selectors.
- // The inputs colors have been presorted along the projection onto this axis, and ETC1 block colors are always ordered along the intensity axis, so this classification is fast.
- // 0 1 2 3
- // 01 12 23
- const uint32_t block_inten_midpoints[3] = { block_inten[0] + block_inten[1], block_inten[1] + block_inten[2], block_inten[2] + block_inten[3] };
-
- uint64_t total_error = 0;
- const color_rgba* pSrc_pixels = m_pParams->m_pSrc_pixels;
- if ((m_pSorted_luma[n - 1] * 2) < block_inten_midpoints[0])
- {
- if (block_inten[0] > m_pSorted_luma[n - 1])
- {
- const uint32_t min_error = iabs((int)block_inten[0] - (int)m_pSorted_luma[n - 1]);
- if (min_error >= trial_solution.m_error)
- continue;
- }
-
- memset(&m_temp_selectors[0], 0, n);
-
- for (uint32_t c = 0; c < n; c++)
- total_error += color_distance(block_colors[0], pSrc_pixels[c], false);
- }
- else if ((m_pSorted_luma[0] * 2) >= block_inten_midpoints[2])
- {
- if (m_pSorted_luma[0] > block_inten[3])
- {
- const uint32_t min_error = iabs((int)m_pSorted_luma[0] - (int)block_inten[3]);
- if (min_error >= trial_solution.m_error)
- continue;
- }
-
- memset(&m_temp_selectors[0], 3, n);
-
- for (uint32_t c = 0; c < n; c++)
- total_error += color_distance(block_colors[3], pSrc_pixels[c], false);
- }
- else
- {
- uint32_t cur_selector = 0, c;
- for (c = 0; c < n; c++)
- {
- const uint32_t y = m_pSorted_luma[c];
- while ((y * 2) >= block_inten_midpoints[cur_selector])
- if (++cur_selector > 2)
- goto done;
- const uint32_t sorted_pixel_index = m_pSorted_luma_indices[c];
- m_temp_selectors[sorted_pixel_index] = static_cast<uint8_t>(cur_selector);
- total_error += color_distance(block_colors[cur_selector], pSrc_pixels[sorted_pixel_index], false);
- }
- done:
- while (c < n)
- {
- const uint32_t sorted_pixel_index = m_pSorted_luma_indices[c];
- m_temp_selectors[sorted_pixel_index] = 3;
- total_error += color_distance(block_colors[3], pSrc_pixels[sorted_pixel_index], false);
- ++c;
- }
- }
-
- if (total_error < trial_solution.m_error)
- {
- trial_solution.m_error = total_error;
- trial_solution.m_coords.m_inten_table = inten_table;
- trial_solution.m_selectors.swap(m_temp_selectors);
- trial_solution.m_valid = true;
- if (!total_error)
- break;
- }
- }
- trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color;
- trial_solution.m_coords.m_color4 = m_pParams->m_use_color4;
-
-#if BASISU_DEBUG_ETC_ENCODER_DEEPER
- printf("Eval done: %u error: %I64u best error so far: %I64u\n", (trial_solution.m_error < pBest_solution->m_error), trial_solution.m_error, pBest_solution->m_error);
-#endif
-
- bool success = false;
- if (pBest_solution)
- {
- if (trial_solution.m_error < pBest_solution->m_error)
- {
- *pBest_solution = trial_solution;
- success = true;
- }
- }
-
- return success;
- }
-
-} // namespace basisu
diff --git a/thirdparty/basis_universal/basisu_pvrtc1_4.cpp b/thirdparty/basis_universal/basisu_pvrtc1_4.cpp
deleted file mode 100644
index f0122fcb6c..0000000000
--- a/thirdparty/basis_universal/basisu_pvrtc1_4.cpp
+++ /dev/null
@@ -1,269 +0,0 @@
-// basisu_pvrtc1_4.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#include "basisu_pvrtc1_4.h"
-
-namespace basisu
-{
- uint32_t pvrtc4_swizzle_uv(uint32_t width, uint32_t height, uint32_t x, uint32_t y)
- {
- assert((x < width) && (y < height) && basisu::is_pow2(height) && basisu::is_pow2(width));
-
- uint32_t min_d = width, max_v = y;
- if (height < width)
- {
- min_d = height;
- max_v = x;
- }
-
- // Interleave the XY LSB's
- uint32_t shift_ofs = 0, swizzled = 0;
- for (uint32_t s_bit = 1, d_bit = 1; s_bit < min_d; s_bit <<= 1, d_bit <<= 2, ++shift_ofs)
- {
- if (y & s_bit) swizzled |= d_bit;
- if (x & s_bit) swizzled |= (2 * d_bit);
- }
-
- max_v >>= shift_ofs;
-
- // OR in the rest of the bits from the largest dimension
- swizzled |= (max_v << (2 * shift_ofs));
-
- return swizzled;
- }
-
- color_rgba pvrtc4_block::get_endpoint(uint32_t endpoint_index, bool unpack) const
- {
- assert(endpoint_index < 2);
- const uint32_t packed = m_endpoints >> (endpoint_index * 16);
-
- uint32_t r, g, b, a;
- if (packed & 0x8000)
- {
- // opaque 554 or 555
- if (!endpoint_index)
- {
- r = (packed >> 10) & 31;
- g = (packed >> 5) & 31;
- b = (packed >> 1) & 15;
-
- if (unpack)
- {
- b = (b << 1) | (b >> 3);
- }
- }
- else
- {
- r = (packed >> 10) & 31;
- g = (packed >> 5) & 31;
- b = packed & 31;
- }
-
- a = unpack ? 255 : 7;
- }
- else
- {
- // translucent 4433 or 4443
- if (!endpoint_index)
- {
- a = (packed >> 12) & 7;
- r = (packed >> 8) & 15;
- g = (packed >> 4) & 15;
- b = (packed >> 1) & 7;
-
- if (unpack)
- {
- a = (a << 1);
- a = (a << 4) | a;
-
- r = (r << 1) | (r >> 3);
- g = (g << 1) | (g >> 3);
- b = (b << 2) | (b >> 1);
- }
- }
- else
- {
- a = (packed >> 12) & 7;
- r = (packed >> 8) & 15;
- g = (packed >> 4) & 15;
- b = packed & 15;
-
- if (unpack)
- {
- a = (a << 1);
- a = (a << 4) | a;
-
- r = (r << 1) | (r >> 3);
- g = (g << 1) | (g >> 3);
- b = (b << 1) | (b >> 3);
- }
- }
- }
-
- if (unpack)
- {
- r = (r << 3) | (r >> 2);
- g = (g << 3) | (g >> 2);
- b = (b << 3) | (b >> 2);
- }
-
- assert((r < 256) && (g < 256) && (b < 256) && (a < 256));
-
- return color_rgba(r, g, b, a);
- }
-
- color_rgba pvrtc4_block::get_endpoint_5554(uint32_t endpoint_index) const
- {
- assert(endpoint_index < 2);
- const uint32_t packed = m_endpoints >> (endpoint_index * 16);
-
- uint32_t r, g, b, a;
- if (packed & 0x8000)
- {
- // opaque 554 or 555
- if (!endpoint_index)
- {
- r = (packed >> 10) & 31;
- g = (packed >> 5) & 31;
- b = (packed >> 1) & 15;
-
- b = (b << 1) | (b >> 3);
- }
- else
- {
- r = (packed >> 10) & 31;
- g = (packed >> 5) & 31;
- b = packed & 31;
- }
-
- a = 15;
- }
- else
- {
- // translucent 4433 or 4443
- if (!endpoint_index)
- {
- a = (packed >> 12) & 7;
- r = (packed >> 8) & 15;
- g = (packed >> 4) & 15;
- b = (packed >> 1) & 7;
-
- a = a << 1;
-
- r = (r << 1) | (r >> 3);
- g = (g << 1) | (g >> 3);
- b = (b << 2) | (b >> 1);
- }
- else
- {
- a = (packed >> 12) & 7;
- r = (packed >> 8) & 15;
- g = (packed >> 4) & 15;
- b = packed & 15;
-
- a = a << 1;
-
- r = (r << 1) | (r >> 3);
- g = (g << 1) | (g >> 3);
- b = (b << 1) | (b >> 3);
- }
- }
-
- assert((r < 32) && (g < 32) && (b < 32) && (a < 16));
-
- return color_rgba(r, g, b, a);
- }
-
- bool pvrtc4_image::get_interpolated_colors(uint32_t x, uint32_t y, color_rgba* pColors) const
- {
- assert((x < m_width) && (y < m_height));
-
- int block_x0 = (static_cast<int>(x) - 2) >> 2;
- int block_x1 = block_x0 + 1;
- int block_y0 = (static_cast<int>(y) - 2) >> 2;
- int block_y1 = block_y0 + 1;
-
- block_x0 = posmod(block_x0, m_block_width);
- block_x1 = posmod(block_x1, m_block_width);
- block_y0 = posmod(block_y0, m_block_height);
- block_y1 = posmod(block_y1, m_block_height);
-
- pColors[0] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));
- pColors[3] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));
-
- if (get_block_uses_transparent_modulation(x >> 2, y >> 2))
- {
- for (uint32_t c = 0; c < 4; c++)
- {
- uint32_t m = (pColors[0][c] + pColors[3][c]) / 2;
- pColors[1][c] = static_cast<uint8_t>(m);
- pColors[2][c] = static_cast<uint8_t>(m);
- }
- pColors[2][3] = 0;
- return true;
- }
-
- for (uint32_t c = 0; c < 4; c++)
- {
- pColors[1][c] = static_cast<uint8_t>((pColors[0][c] * 5 + pColors[3][c] * 3) / 8);
- pColors[2][c] = static_cast<uint8_t>((pColors[0][c] * 3 + pColors[3][c] * 5) / 8);
- }
-
- return false;
- }
-
- color_rgba pvrtc4_image::get_pixel(uint32_t x, uint32_t y, uint32_t m) const
- {
- assert((x < m_width) && (y < m_height));
-
- int block_x0 = (static_cast<int>(x) - 2) >> 2;
- int block_x1 = block_x0 + 1;
- int block_y0 = (static_cast<int>(y) - 2) >> 2;
- int block_y1 = block_y0 + 1;
-
- block_x0 = posmod(block_x0, m_block_width);
- block_x1 = posmod(block_x1, m_block_width);
- block_y0 = posmod(block_y0, m_block_height);
- block_y1 = posmod(block_y1, m_block_height);
-
- if (get_block_uses_transparent_modulation(x >> 2, y >> 2))
- {
- if (m == 0)
- return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));
- else if (m == 3)
- return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));
-
- color_rgba l(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0)));
- color_rgba h(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1)));
-
- return color_rgba((l[0] + h[0]) / 2, (l[1] + h[1]) / 2, (l[2] + h[2]) / 2, (m == 2) ? 0 : (l[3] + h[3]) / 2);
- }
- else
- {
- if (m == 0)
- return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));
- else if (m == 3)
- return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));
-
- color_rgba l(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0)));
- color_rgba h(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1)));
-
- if (m == 2)
- return color_rgba((l[0] * 3 + h[0] * 5) / 8, (l[1] * 3 + h[1] * 5) / 8, (l[2] * 3 + h[2] * 5) / 8, (l[3] * 3 + h[3] * 5) / 8);
- else
- return color_rgba((l[0] * 5 + h[0] * 3) / 8, (l[1] * 5 + h[1] * 3) / 8, (l[2] * 5 + h[2] * 3) / 8, (l[3] * 5 + h[3] * 3) / 8);
- }
- }
-
-} // basisu
diff --git a/thirdparty/basis_universal/encoder/apg_bmp.c b/thirdparty/basis_universal/encoder/apg_bmp.c
new file mode 100644
index 0000000000..ef3d015e40
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/apg_bmp.c
@@ -0,0 +1,541 @@
+/*
+BMP File Reader/Writer Implementation
+Anton Gerdelan
+Version: 3
+Licence: see apg_bmp.h
+C99
+*/
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS 1
+#endif
+
+#include "apg_bmp.h"
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Maximum pixel dimensions of width or height of an image. Should accommodate max used in graphics APIs.
+ NOTE: 65536*65536 is the biggest number storable in 32 bits.
+ This needs to be multiplied by n_channels so actual memory indices are not uint32 but size_t to avoid overflow.
+ Note this will crash stb_image_write et al at maximum size which use 32bits, so reduce max size to accom. */
+#define _BMP_MAX_DIMS 65536
+#define _BMP_FILE_HDR_SZ 14
+#define _BMP_MIN_DIB_HDR_SZ 40
+#define _BMP_MIN_HDR_SZ ( _BMP_FILE_HDR_SZ + _BMP_MIN_DIB_HDR_SZ )
+#define _BMP_MAX_IMAGE_FILE_SIZE (1024ULL*1024ULL*1024ULL)
+
+#pragma pack( push, 1 ) // supported on GCC in addition to individual packing attribs
+/* All BMP files, regardless of type, start with this file header */
+typedef struct _bmp_file_header_t {
+ char file_type[2];
+ uint32_t file_sz;
+ uint16_t reserved1;
+ uint16_t reserved2;
+ uint32_t image_data_offset;
+} _bmp_file_header_t;
+
+/* Following the file header is the BMP type header. this is the most commonly used format */
+typedef struct _bmp_dib_BITMAPINFOHEADER_t {
+ uint32_t this_header_sz;
+ int32_t w; // in older headers w & h these are shorts and may be unsigned
+ int32_t h; //
+ uint16_t n_planes; // must be 1
+ uint16_t bpp; // bits per pixel. 1,4,8,16,24,32.
+ uint32_t compression_method; // 16 and 32-bit images must have a value of 3 here
+ uint32_t image_uncompressed_sz; // not consistently used in the wild, so ignored here.
+ int32_t horiz_pixels_per_meter; // not used.
+ int32_t vert_pixels_per_meter; // not used.
+ uint32_t n_colours_in_palette; //
+ uint32_t n_important_colours; // not used.
+ /* NOTE(Anton) a DIB header may end here at 40-bytes. be careful using sizeof() */
+ /* if 'compression' value, above, is set to 3 ie the image is 16 or 32-bit, then these colour channel masks follow the headers.
+ these are big-endian order bit masks to assign bits of each pixel to different colours. bits used must be contiguous and not overlap. */
+ uint32_t bitmask_r;
+ uint32_t bitmask_g;
+ uint32_t bitmask_b;
+} _bmp_dib_BITMAPINFOHEADER_t;
+#pragma pack( pop )
+
+typedef enum _bmp_compression_t {
+ BI_RGB = 0,
+ BI_RLE8 = 1,
+ BI_RLE4 = 2,
+ BI_BITFIELDS = 3,
+ BI_JPEG = 4,
+ BI_PNG = 5,
+ BI_ALPHABITFIELDS = 6,
+ BI_CMYK = 11,
+ BI_CMYKRLE8 = 12,
+ BI_CMYRLE4 = 13
+} _bmp_compression_t;
+
+/* convenience struct and file->memory function */
+typedef struct _entire_file_t {
+ void* data;
+ size_t sz;
+} _entire_file_t;
+
+/*
+RETURNS
+- true on success. record->data is allocated memory and must be freed by the caller.
+- false on any error. Any allocated memory is freed if false is returned */
+static bool _read_entire_file( const char* filename, _entire_file_t* record ) {
+ FILE* fp = fopen( filename, "rb" );
+ if ( !fp ) { return false; }
+ fseek( fp, 0L, SEEK_END );
+ record->sz = (size_t)ftell( fp );
+
+ // Immediately bail on anything larger than _BMP_MAX_IMAGE_FILE_SIZE.
+ if (record->sz > _BMP_MAX_IMAGE_FILE_SIZE) {
+ fclose( fp );
+ return false;
+ }
+
+ record->data = malloc( record->sz );
+ if ( !record->data ) {
+ fclose( fp );
+ return false;
+ }
+ rewind( fp );
+ size_t nr = fread( record->data, record->sz, 1, fp );
+ fclose( fp );
+ if ( 1 != nr ) { return false; }
+ return true;
+}
+
+static bool _validate_file_hdr( _bmp_file_header_t* file_hdr_ptr, size_t file_sz ) {
+ if ( !file_hdr_ptr ) { return false; }
+ if ( file_hdr_ptr->file_type[0] != 'B' || file_hdr_ptr->file_type[1] != 'M' ) { return false; }
+ if ( file_hdr_ptr->image_data_offset > file_sz ) { return false; }
+ return true;
+}
+
+static bool _validate_dib_hdr( _bmp_dib_BITMAPINFOHEADER_t* dib_hdr_ptr, size_t file_sz ) {
+ if ( !dib_hdr_ptr ) { return false; }
+ if ( _BMP_FILE_HDR_SZ + dib_hdr_ptr->this_header_sz > file_sz ) { return false; }
+ if ( ( 32 == dib_hdr_ptr->bpp || 16 == dib_hdr_ptr->bpp ) && ( BI_BITFIELDS != dib_hdr_ptr->compression_method && BI_ALPHABITFIELDS != dib_hdr_ptr->compression_method ) ) {
+ return false;
+ }
+ if ( BI_RGB != dib_hdr_ptr->compression_method && BI_BITFIELDS != dib_hdr_ptr->compression_method && BI_ALPHABITFIELDS != dib_hdr_ptr->compression_method ) {
+ return false;
+ }
+ // NOTE(Anton) using abs() in the if-statement was blowing up on large negative numbers. switched to labs()
+ if ( 0 == dib_hdr_ptr->w || 0 == dib_hdr_ptr->h || labs( dib_hdr_ptr->w ) > _BMP_MAX_DIMS || labs( dib_hdr_ptr->h ) > _BMP_MAX_DIMS ) { return false; }
+
+ /* NOTE(Anton) if images reliably used n_colours_in_palette we could have done a palette/file size integrity check here.
+ because some always set 0 then we have to check every palette indexing as we read them */
+ return true;
+}
+
+/* NOTE(Anton) this could have ifdef branches on different compilers for the intrinsics versions for perf */
+static uint32_t _bitscan( uint32_t dword ) {
+ for ( uint32_t i = 0; i < 32; i++ ) {
+ if ( 1 & dword ) { return i; }
+ dword = dword >> 1;
+ }
+ return (uint32_t)-1;
+}
+
+unsigned char* apg_bmp_read( const char* filename, int* w, int* h, unsigned int* n_chans ) {
+ if ( !filename || !w || !h || !n_chans ) { return NULL; }
+
+ // read in the whole file into memory first - much faster than parsing on-the-fly
+ _entire_file_t record;
+ if ( !_read_entire_file( filename, &record ) ) { return NULL; }
+ if ( record.sz < _BMP_MIN_HDR_SZ ) {
+ free( record.data );
+ return NULL;
+ }
+
+ // grab and validate the first, file, header
+ _bmp_file_header_t* file_hdr_ptr = (_bmp_file_header_t*)record.data;
+ if ( !_validate_file_hdr( file_hdr_ptr, record.sz ) ) {
+ free( record.data );
+ return NULL;
+ }
+
+ // grad and validate the second, DIB, header
+ _bmp_dib_BITMAPINFOHEADER_t* dib_hdr_ptr = (_bmp_dib_BITMAPINFOHEADER_t*)( (uint8_t*)record.data + _BMP_FILE_HDR_SZ );
+ if ( !_validate_dib_hdr( dib_hdr_ptr, record.sz ) ) {
+ free( record.data );
+ return NULL;
+ }
+
+ // bitmaps can have negative dims to indicate the image should be flipped
+ uint32_t width = *w = abs( dib_hdr_ptr->w );
+ uint32_t height = *h = abs( dib_hdr_ptr->h );
+
+ // TODO(Anton) flip image memory at the end if this is true. because doing it per row was making me write bugs.
+ // bool vertically_flip = dib_hdr_ptr->h > 0 ? false : true;
+
+ // channel count and palette are not well defined in the header so we make a good guess here
+ uint32_t n_dst_chans = 3, n_src_chans = 3;
+ bool has_palette = false;
+ switch ( dib_hdr_ptr->bpp ) {
+ case 32: n_dst_chans = n_src_chans = 4; break; // technically can be RGB but not supported
+ case 24: n_dst_chans = n_src_chans = 3; break; // technically can be RGBA but not supported
+ case 8: // seems to always use a BGR0 palette, even for greyscale
+ n_dst_chans = 3;
+ has_palette = true;
+ n_src_chans = 1;
+ break;
+ case 4: // always has a palette - needed for a MS-saved BMP
+ n_dst_chans = 3;
+ has_palette = true;
+ n_src_chans = 1;
+ break;
+ case 1: // 1-bpp means the palette has 3 colour channels with 2 colours i.e. monochrome but not always black & white
+ n_dst_chans = 3;
+ has_palette = true;
+ n_src_chans = 1;
+ break;
+ default: // this includes 2bpp and 16bpp
+ free( record.data );
+ return NULL;
+ } // endswitch
+ *n_chans = n_dst_chans;
+ // NOTE(Anton) some image formats are not allowed a palette - could check for a bad header spec here also
+ if ( dib_hdr_ptr->n_colours_in_palette > 0 ) { has_palette = true; }
+
+#ifdef APG_BMP_DEBUG_OUTPUT
+ printf( "apg_bmp_debug: reading image\n|-filename `%s`\n|-dims %ux%u pixels\n|-bpp %u\n|-n_src_chans %u\n|-n_dst_chans %u\n", filename, *w, *h,
+ dib_hdr_ptr->bpp, n_src_chans, n_dst_chans );
+#endif
+
+ uint32_t palette_offset = _BMP_FILE_HDR_SZ + dib_hdr_ptr->this_header_sz;
+ bool has_bitmasks = false;
+ if ( BI_BITFIELDS == dib_hdr_ptr->compression_method || BI_ALPHABITFIELDS == dib_hdr_ptr->compression_method ) {
+ has_bitmasks = true;
+ palette_offset += 12;
+ }
+ if ( palette_offset > record.sz ) {
+ free( record.data );
+ return NULL;
+ }
+
+ // work out if any padding how much to skip at end of each row
+ uint32_t unpadded_row_sz = width * n_src_chans;
+ // bit-encoded palette indices have different padding properties
+ if ( 4 == dib_hdr_ptr->bpp ) {
+ unpadded_row_sz = width % 2 > 0 ? width / 2 + 1 : width / 2; // find how many whole bytes required for this bit width
+ }
+ if ( 1 == dib_hdr_ptr->bpp ) {
+ unpadded_row_sz = width % 8 > 0 ? width / 8 + 1 : width / 8; // find how many whole bytes required for this bit width
+ }
+ uint32_t row_padding_sz = 0 == unpadded_row_sz % 4 ? 0 : 4 - ( unpadded_row_sz % 4 ); // NOTE(Anton) didn't expect operator precedence of - over %
+
+ // another file size integrity check: partially validate source image data size
+ // 'image_data_offset' is by row padded to 4 bytes and is either colour data or palette indices.
+ if ( file_hdr_ptr->image_data_offset + ( unpadded_row_sz + row_padding_sz ) * height > record.sz ) {
+ free( record.data );
+ return NULL;
+ }
+
+ // find which bit number each colour channel starts at, so we can separate colours out
+ uint32_t bitshift_rgba[4] = {0, 0, 0, 0}; // NOTE(Anton) noticed this was int and not uint32_t so changed it. 17 Mar 2020
+ uint32_t bitmask_a = 0;
+ if ( has_bitmasks ) {
+ bitmask_a = ~( dib_hdr_ptr->bitmask_r | dib_hdr_ptr->bitmask_g | dib_hdr_ptr->bitmask_b );
+ bitshift_rgba[0] = _bitscan( dib_hdr_ptr->bitmask_r );
+ bitshift_rgba[1] = _bitscan( dib_hdr_ptr->bitmask_g );
+ bitshift_rgba[2] = _bitscan( dib_hdr_ptr->bitmask_b );
+ bitshift_rgba[3] = _bitscan( bitmask_a );
+ }
+
+ // allocate memory for the output pixels block. cast to size_t in case width and height are both the max of 65536 and n_dst_chans > 1
+ unsigned char* dst_img_ptr = malloc( (size_t)width * (size_t)height * (size_t)n_dst_chans );
+ if ( !dst_img_ptr ) {
+ free( record.data );
+ return NULL;
+ }
+
+ uint8_t* palette_data_ptr = (uint8_t*)record.data + palette_offset;
+ uint8_t* src_img_ptr = (uint8_t*)record.data + file_hdr_ptr->image_data_offset;
+ size_t dst_stride_sz = width * n_dst_chans;
+
+ // == 32-bpp -> 32-bit RGBA. == 32-bit and 16-bit require bitmasks
+ if ( 32 == dib_hdr_ptr->bpp ) {
+ // check source image has enough data in it to read from
+ if ( (size_t)file_hdr_ptr->image_data_offset + (size_t)height * (size_t)width * (size_t)n_src_chans > record.sz ) {
+ free( record.data );
+ free( dst_img_ptr );
+ return NULL;
+ }
+ size_t src_byte_idx = 0;
+ for ( uint32_t r = 0; r < height; r++ ) {
+ size_t dst_pixels_idx = r * dst_stride_sz;
+ for ( uint32_t c = 0; c < width; c++ ) {
+ uint32_t pixel;
+ memcpy( &pixel, &src_img_ptr[src_byte_idx], 4 );
+ // NOTE(Anton) the below assumes 32-bits is always RGBA 1 byte per channel. 10,10,10 RGB exists though and isn't handled.
+ dst_img_ptr[dst_pixels_idx++] = ( uint8_t )( ( pixel & dib_hdr_ptr->bitmask_r ) >> bitshift_rgba[0] );
+ dst_img_ptr[dst_pixels_idx++] = ( uint8_t )( ( pixel & dib_hdr_ptr->bitmask_g ) >> bitshift_rgba[1] );
+ dst_img_ptr[dst_pixels_idx++] = ( uint8_t )( ( pixel & dib_hdr_ptr->bitmask_b ) >> bitshift_rgba[2] );
+ dst_img_ptr[dst_pixels_idx++] = ( uint8_t )( ( pixel & bitmask_a ) >> bitshift_rgba[3] );
+ src_byte_idx += 4;
+ }
+ src_byte_idx += row_padding_sz;
+ }
+
+ // == 8-bpp -> 24-bit RGB ==
+ } else if ( 8 == dib_hdr_ptr->bpp && has_palette ) {
+ // validate indices (body of image data) fits in file
+ if ( file_hdr_ptr->image_data_offset + height * width > record.sz ) {
+ free( record.data );
+ free( dst_img_ptr );
+ return NULL;
+ }
+ size_t src_byte_idx = 0;
+ for ( uint32_t r = 0; r < height; r++ ) {
+ size_t dst_pixels_idx = ( height - 1 - r ) * dst_stride_sz;
+ for ( uint32_t c = 0; c < width; c++ ) {
+ // "most palettes are 4 bytes in RGB0 order but 3 for..." - it was actually BRG0 in old images -- Anton
+ uint8_t index = src_img_ptr[src_byte_idx]; // 8-bit index value per pixel
+
+ if ( palette_offset + index * 4 + 2 >= record.sz ) {
+ free( record.data );
+ return dst_img_ptr;
+ }
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[index * 4 + 2];
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[index * 4 + 1];
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[index * 4 + 0];
+ src_byte_idx++;
+ }
+ src_byte_idx += row_padding_sz;
+ }
+
+ // == 4-bpp (16-colour) -> 24-bit RGB ==
+ } else if ( 4 == dib_hdr_ptr->bpp && has_palette ) {
+ size_t src_byte_idx = 0;
+ for ( uint32_t r = 0; r < height; r++ ) {
+ size_t dst_pixels_idx = ( height - 1 - r ) * dst_stride_sz;
+ for ( uint32_t c = 0; c < width; c++ ) {
+ if ( file_hdr_ptr->image_data_offset + src_byte_idx > record.sz ) {
+ free( record.data );
+ free( dst_img_ptr );
+ return NULL;
+ }
+ // handle 2 pixels at a time
+ uint8_t pixel_duo = src_img_ptr[src_byte_idx];
+ uint8_t a_index = ( 0xFF & pixel_duo ) >> 4;
+ uint8_t b_index = 0xF & pixel_duo;
+
+ if ( palette_offset + a_index * 4 + 2 >= record.sz ) { // invalid src image
+ free( record.data );
+ return dst_img_ptr;
+ }
+ if ( dst_pixels_idx + 3 > width * height * n_dst_chans ) { // done
+ free( record.data );
+ return dst_img_ptr;
+ }
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[a_index * 4 + 2];
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[a_index * 4 + 1];
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[a_index * 4 + 0];
+ if ( ++c >= width ) { // advance a column
+ c = 0;
+ r++;
+ if ( r >= height ) { // done. no need to get second pixel. eg a 1x1 pixel image.
+ free( record.data );
+ return dst_img_ptr;
+ }
+ dst_pixels_idx = ( height - 1 - r ) * dst_stride_sz;
+ }
+
+ if ( palette_offset + b_index * 4 + 2 >= record.sz ) { // invalid src image
+ free( record.data );
+ return dst_img_ptr;
+ }
+ if ( dst_pixels_idx + 3 > width * height * n_dst_chans ) { // done. probably redundant check since checking r >= height.
+ free( record.data );
+ return dst_img_ptr;
+ }
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[b_index * 4 + 2];
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[b_index * 4 + 1];
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[b_index * 4 + 0];
+ src_byte_idx++;
+ }
+ src_byte_idx += row_padding_sz;
+ }
+
+ // == 1-bpp -> 24-bit RGB ==
+ } else if ( 1 == dib_hdr_ptr->bpp && has_palette ) {
+ /* encoding method for monochrome is not well documented.
+ a 2x2 pixel image is stored as 4 1-bit palette indexes
+ the palette is stored as any 2 RGB0 colours (not necessarily B&W)
+ so for an image with indexes like so:
+ 1 1
+ 0 1
+ it is bit-encoded as follows, starting at MSB:
+ 01000000 00000000 00000000 00000000 (first byte val 64)
+ 11000000 00000000 00000000 00000000 (first byte val 192)
+ data is still split by row and each row padded to 4 byte multiples
+ */
+ size_t src_byte_idx = 0;
+ for ( uint32_t r = 0; r < height; r++ ) {
+ uint8_t bit_idx = 0; // used in monochrome
+ size_t dst_pixels_idx = ( height - 1 - r ) * dst_stride_sz;
+ for ( uint32_t c = 0; c < width; c++ ) {
+ if ( 8 == bit_idx ) { // start reading from the next byte
+ src_byte_idx++;
+ bit_idx = 0;
+ }
+ if ( file_hdr_ptr->image_data_offset + src_byte_idx > record.sz ) {
+ free( record.data );
+ return dst_img_ptr;
+ }
+ uint8_t pixel_oct = src_img_ptr[src_byte_idx];
+ uint8_t bit = 128 >> bit_idx;
+ uint8_t masked = pixel_oct & bit;
+ uint8_t palette_idx = masked > 0 ? 1 : 0;
+
+ if ( palette_offset + palette_idx * 4 + 2 >= record.sz ) {
+ free( record.data );
+ return dst_img_ptr;
+ }
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[palette_idx * 4 + 2];
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[palette_idx * 4 + 1];
+ dst_img_ptr[dst_pixels_idx++] = palette_data_ptr[palette_idx * 4 + 0];
+ bit_idx++;
+ }
+ src_byte_idx += ( row_padding_sz + 1 ); // 1bpp is special here
+ }
+
+ // == 24-bpp -> 24-bit RGB == (but also should handle some other n_chans cases)
+ } else {
+ // NOTE(Anton) this only supports 1 byte per channel
+ if ( file_hdr_ptr->image_data_offset + height * width * n_dst_chans > record.sz ) {
+ free( record.data );
+ free( dst_img_ptr );
+ return NULL;
+ }
+ size_t src_byte_idx = 0;
+ for ( uint32_t r = 0; r < height; r++ ) {
+ size_t dst_pixels_idx = ( height - 1 - r ) * dst_stride_sz;
+ for ( uint32_t c = 0; c < width; c++ ) {
+ // re-orders from BGR to RGB
+ if ( n_dst_chans > 3 ) { dst_img_ptr[dst_pixels_idx++] = src_img_ptr[src_byte_idx + 3]; }
+ if ( n_dst_chans > 2 ) { dst_img_ptr[dst_pixels_idx++] = src_img_ptr[src_byte_idx + 2]; }
+ if ( n_dst_chans > 1 ) { dst_img_ptr[dst_pixels_idx++] = src_img_ptr[src_byte_idx + 1]; }
+ dst_img_ptr[dst_pixels_idx++] = src_img_ptr[src_byte_idx];
+ src_byte_idx += n_src_chans;
+ }
+ src_byte_idx += row_padding_sz;
+ }
+ } // endif bpp
+
+ free( record.data );
+ return dst_img_ptr;
+}
+
+void apg_bmp_free( unsigned char* pixels_ptr ) {
+ if ( !pixels_ptr ) { return; }
+ free( pixels_ptr );
+}
+
+unsigned int apg_bmp_write( const char* filename, unsigned char* pixels_ptr, int w, int h, unsigned int n_chans ) {
+ if ( !filename || !pixels_ptr ) { return 0; }
+ if ( 0 == w || 0 == h ) { return 0; }
+ if ( labs( w ) > _BMP_MAX_DIMS || labs( h ) > _BMP_MAX_DIMS ) { return 0; }
+ if ( n_chans != 3 && n_chans != 4 ) { return 0; }
+
+ uint32_t height = (uint32_t)labs( h );
+ uint32_t width = (uint32_t)labs( w );
+ // work out if any padding how much to skip at end of each row
+ const size_t unpadded_row_sz = width * n_chans;
+ const size_t row_padding_sz = 0 == unpadded_row_sz % 4 ? 0 : 4 - unpadded_row_sz % 4;
+ const size_t row_sz = unpadded_row_sz + row_padding_sz;
+ const size_t dst_pixels_padded_sz = row_sz * height;
+
+ const size_t dib_hdr_sz = sizeof( _bmp_dib_BITMAPINFOHEADER_t );
+ _bmp_file_header_t file_hdr;
+ {
+ file_hdr.file_type[0] = 'B';
+ file_hdr.file_type[1] = 'M';
+ file_hdr.file_sz = _BMP_FILE_HDR_SZ + (uint32_t)dib_hdr_sz + (uint32_t)dst_pixels_padded_sz;
+ file_hdr.reserved1 = 0;
+ file_hdr.reserved2 = 0;
+ file_hdr.image_data_offset = _BMP_FILE_HDR_SZ + (uint32_t)dib_hdr_sz;
+ }
+ _bmp_dib_BITMAPINFOHEADER_t dib_hdr;
+ {
+ dib_hdr.this_header_sz = _BMP_MIN_DIB_HDR_SZ; // NOTE: must be 40 and not include the bitmask memory in size here
+ dib_hdr.w = w;
+ dib_hdr.h = h;
+ dib_hdr.n_planes = 1;
+ dib_hdr.bpp = 3 == n_chans ? 24 : 32;
+ dib_hdr.compression_method = 3 == n_chans ? BI_RGB : BI_BITFIELDS;
+ dib_hdr.image_uncompressed_sz = 0;
+ dib_hdr.horiz_pixels_per_meter = 0;
+ dib_hdr.vert_pixels_per_meter = 0;
+ dib_hdr.n_colours_in_palette = 0;
+ dib_hdr.n_important_colours = 0;
+ // big-endian masks. only used in BI_BITFIELDS and BI_ALPHABITFIELDS ( 16 and 32-bit images )
+ // important note: GIMP stores BMP data in this array order for 32-bit: [A][B][G][R]
+ dib_hdr.bitmask_r = 0xFF000000;
+ dib_hdr.bitmask_g = 0x00FF0000;
+ dib_hdr.bitmask_b = 0x0000FF00;
+ }
+
+ uint8_t* dst_pixels_ptr = malloc( dst_pixels_padded_sz );
+ if ( !dst_pixels_ptr ) { return 0; }
+ {
+ size_t dst_byte_idx = 0;
+ uint8_t padding[4] = {0, 0, 0, 0};
+ uint8_t rgba[4] = {0, 0, 0, 0};
+ uint8_t bgra[4] = {0, 0, 0, 0};
+
+ for ( uint32_t row = 0; row < height; row++ ) {
+ size_t src_byte_idx = ( height - 1 - row ) * n_chans * width;
+ for ( uint32_t col = 0; col < width; col++ ) {
+ for ( uint32_t chan = 0; chan < n_chans; chan++ ) { rgba[chan] = pixels_ptr[src_byte_idx++]; }
+ if ( 3 == n_chans ) {
+ bgra[0] = rgba[2];
+ bgra[1] = rgba[1];
+ bgra[2] = rgba[0];
+ } else {
+ /* NOTE(Anton) RGBA with alpha channel would be better supported with an extended DIB header */
+ bgra[0] = rgba[3];
+ bgra[1] = rgba[2];
+ bgra[2] = rgba[1];
+ bgra[3] = rgba[0]; // alpha
+ }
+ memcpy( &dst_pixels_ptr[dst_byte_idx], bgra, n_chans );
+ dst_byte_idx += (size_t)n_chans;
+ } // endfor col
+ if ( row_padding_sz > 0 ) {
+ memcpy( &dst_pixels_ptr[dst_byte_idx], padding, row_padding_sz );
+ dst_byte_idx += row_padding_sz;
+ }
+ } // endfor row
+ }
+ {
+ FILE* fp = fopen( filename, "wb" );
+ if ( !fp ) {
+ free( dst_pixels_ptr );
+ return 0;
+ }
+ if ( 1 != fwrite( &file_hdr, _BMP_FILE_HDR_SZ, 1, fp ) ) {
+ free( dst_pixels_ptr );
+ fclose( fp );
+ return 0;
+ }
+ if ( 1 != fwrite( &dib_hdr, dib_hdr_sz, 1, fp ) ) {
+ free( dst_pixels_ptr );
+ fclose( fp );
+ return 0;
+ }
+ if ( 1 != fwrite( dst_pixels_ptr, dst_pixels_padded_sz, 1, fp ) ) {
+ free( dst_pixels_ptr );
+ fclose( fp );
+ return 0;
+ }
+ fclose( fp );
+ }
+ free( dst_pixels_ptr );
+
+ return 1;
+}
diff --git a/thirdparty/basis_universal/encoder/apg_bmp.h b/thirdparty/basis_universal/encoder/apg_bmp.h
new file mode 100644
index 0000000000..8cd73b62e0
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/apg_bmp.h
@@ -0,0 +1,123 @@
+/*
+BMP File Reader/Writer Implementation
+Anton Gerdelan
+Version: 3.1 18 March 2020.
+Licence: see bottom of file.
+C89 ( Implementation is C99 )
+
+Contributors:
+- Anton Gerdelan - Initial code.
+- Saija Sorsa - Fuzz testing.
+
+Instructions:
+- Just drop this header, and the matching .c file into your project.
+- To get debug printouts during parsing define APG_BMP_DEBUG_OUTPUT.
+
+Advantages:
+- The implementation is fast, simple, and supports more formats than most BMP reader libraries.
+- The reader function is fuzzed with AFL https://lcamtuf.coredump.cx/afl/.
+- The reader is robust to large files and malformed files, and will return any valid partial data in an image.
+- Reader supports 32bpp (with alpha channel), 24bpp, 8bpp, 4bpp, and 1bpp monochrome BMP images.
+- Reader handles indexed BMP images using a colour palette.
+- Writer supports 32bpp RGBA and 24bpp uncompressed RGB images.
+
+Current Limitations:
+- 16-bit images not supported (don't have any samples to test on).
+- No support for interleaved channel bit layouts eg RGB101010 RGB555 RGB565.
+- No support for compressed BMP images, although in practice these are not used.
+- Output images with alpha channel are written in BITMAPINFOHEADER format.
+ For better alpha support in other apps the 124-bit v5 header could be used instead,
+ at the cost of some backward compatibility and bloat.
+
+To Do:
+- FUZZING
+ - create a unique fuzz test set for (8,4,1 BPP).
+- (maybe) FEATURE Flipping the image based on negative width and height in header, and/or function arguments.
+- (maybe) PERF ifdef intrinsics/asm for bitscan. Platform-specific code so won't include unless necessary.
+- (maybe) FEATURE Add parameter for padding output memory to eg 4-byte alignment or n channels.
+- (maybe) FEATURE Improved apps support in alpha channel writing (using v5 header).
+*/
+
+#ifndef APG_BMP_H_
+#define APG_BMP_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* CPP */
+
+/* Reads a bitmap from a file, allocates memory for the raw image data, and returns it.
+PARAMS
+ * w,h, - Retrieves the width and height of the BMP in pixels.
+ * n_chans - Retrieves the number of channels in the BMP.
+RETURNS
+ * Tightly-packed pixel memory in RGBA order. The caller must call free() on the memory.
+ * NULL on any error. Any allocated memory is freed before returning NULL. */
+unsigned char* apg_bmp_read( const char* filename, int* w, int* h, unsigned int* n_chans );
+
+/* Calls free() on memory created by apg_bmp_read */
+void apg_bmp_free( unsigned char* pixels_ptr );
+
+/* Writes a bitmap to a file.
+PARAMS
+ * filename - e.g."my_bitmap.bmp". Must not be NULL.
+ * pixels_ptr - Pointer to tightly-packed pixel memory in RGBA order. Must not be NULL. There must be abs(w)*abs(h)*n_chans bytes in the memory pointed to.
+ * w,h, - Width and height of the image in pixels.
+ * n_chans - The number of channels in the BMP. 3 or 4 supported for writing, which means RGB or RGBA memory, respectively.
+RETURNS
+ * Zero on any error, non zero on success. */
+unsigned int apg_bmp_write( const char* filename, unsigned char* pixels_ptr, int w, int h, unsigned int n_chans );
+
+#ifdef __cplusplus
+}
+#endif /* CPP */
+
+#endif /*_APG_BMP_H_ */
+
+/*
+-------------------------------------------------------------------------------------
+This software is available under two licences - you may use it under either licence.
+-------------------------------------------------------------------------------------
+FIRST LICENCE OPTION
+
+> Apache License
+> Version 2.0, January 2004
+> http://www.apache.org/licenses/
+> Copyright 2019 Anton Gerdelan.
+> Licensed under the Apache License, Version 2.0 (the "License");
+> you may not use this file except in compliance with the License.
+> You may obtain a copy of the License at
+> http://www.apache.org/licenses/LICENSE-2.0
+> Unless required by applicable law or agreed to in writing, software
+> distributed under the License is distributed on an "AS IS" BASIS,
+> WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+> See the License for the specific language governing permissions and
+> limitations under the License.
+-------------------------------------------------------------------------------------
+SECOND LICENCE OPTION
+
+> This is free and unencumbered software released into the public domain.
+>
+> Anyone is free to copy, modify, publish, use, compile, sell, or
+> distribute this software, either in source code form or as a compiled
+> binary, for any purpose, commercial or non-commercial, and by any
+> means.
+>
+> In jurisdictions that recognize copyright laws, the author or authors
+> of this software dedicate any and all copyright interest in the
+> software to the public domain. We make this dedication for the benefit
+> of the public at large and to the detriment of our heirs and
+> successors. We intend this dedication to be an overt act of
+> relinquishment in perpetuity of all present and future rights to this
+> software under copyright law.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+> IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+> OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+> ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+> OTHER DEALINGS IN THE SOFTWARE.
+>
+> For more information, please refer to <http://unlicense.org>
+-------------------------------------------------------------------------------------
+*/
diff --git a/thirdparty/basis_universal/basisu_astc_decomp.cpp b/thirdparty/basis_universal/encoder/basisu_astc_decomp.cpp
index cc0a6ced7a..53bccfc515 100644
--- a/thirdparty/basis_universal/basisu_astc_decomp.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_astc_decomp.cpp
@@ -50,6 +50,13 @@ typedef uint64_t deUint64;
#define DE_ASSERT assert
+#ifdef _MSC_VER
+#pragma warning (disable:4505) // unreferenced local function has been removed
+#elif defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
namespace basisu_astc
{
static bool inBounds(int v, int l, int h)
@@ -150,7 +157,7 @@ namespace basisu_astc
UVec4 asUint() const
{
- return UVec4(std::max(0, m_c[0]), std::max(0, m_c[1]), std::max(0, m_c[2]), std::max(0, m_c[3]));
+ return UVec4(basisu::maximum(0, m_c[0]), basisu::maximum(0, m_c[1]), basisu::maximum(0, m_c[2]), basisu::maximum(0, m_c[3]));
}
int32_t operator[] (uint32_t idx) const { assert(idx < 4); return m_c[idx]; }
@@ -1256,7 +1263,7 @@ void interpolateWeights (TexelWeightPair* dst, const deUint32 (&unquantizedWeigh
const int numWeightsPerTexel = blockMode.isDualPlane ? 2 : 1;
const deUint32 scaleX = (1024 + blockWidth/2) / (blockWidth-1);
const deUint32 scaleY = (1024 + blockHeight/2) / (blockHeight-1);
- DE_ASSERT(blockMode.weightGridWidth*blockMode.weightGridHeight*numWeightsPerTexel <= DE_LENGTH_OF_ARRAY(unquantizedWeights));
+ DE_ASSERT(blockMode.weightGridWidth*blockMode.weightGridHeight*numWeightsPerTexel <= (int)DE_LENGTH_OF_ARRAY(unquantizedWeights));
for (int texelY = 0; texelY < blockHeight; texelY++)
{
for (int texelX = 0; texelX < blockWidth; texelX++)
@@ -1548,3 +1555,7 @@ bool decompress(uint8_t *pDst, const uint8_t * data, bool isSRGB, int blockWidth
} // astc
} // basisu_astc
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
diff --git a/thirdparty/basis_universal/basisu_astc_decomp.h b/thirdparty/basis_universal/encoder/basisu_astc_decomp.h
index 6cd053b7b6..9ec2e46076 100644
--- a/thirdparty/basis_universal/basisu_astc_decomp.h
+++ b/thirdparty/basis_universal/encoder/basisu_astc_decomp.h
@@ -23,7 +23,7 @@
* \brief ASTC Utilities.
*//*--------------------------------------------------------------------*/
-#include "transcoder/basisu.h" // to pick up the iterator debug level madness
+#include "../transcoder/basisu.h" // to pick up the iterator debug level madness
#include <vector>
#include <stdint.h>
diff --git a/thirdparty/basis_universal/basisu_backend.cpp b/thirdparty/basis_universal/encoder/basisu_backend.cpp
index 3a689e58d7..19911fcbb4 100644
--- a/thirdparty/basis_universal/basisu_backend.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_backend.cpp
@@ -1,5 +1,5 @@
// basisu_backend.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,6 +17,11 @@
//
#include "basisu_backend.h"
+#if BASISU_SUPPORT_SSE
+#define CPPSPMD_NAME(a) a##_sse41
+#include "basisu_kernels_declares.h"
+#endif
+
#define BASISU_FASTER_SELECTOR_REORDERING 0
#define BASISU_BACKEND_VERIFY(c) verify(c, __LINE__);
@@ -176,64 +181,117 @@ namespace basisu
void basisu_backend::reoptimize_and_sort_endpoints_codebook(uint32_t total_block_endpoints_remapped, uint_vec& all_endpoint_indices)
{
basisu_frontend& r = *m_pFront_end;
- const bool is_video = r.get_params().m_tex_type == basist::cBASISTexTypeVideoFrames;
+ //const bool is_video = r.get_params().m_tex_type == basist::cBASISTexTypeVideoFrames;
- if ((total_block_endpoints_remapped) && (m_params.m_compression_level > 0))
+ if (m_params.m_used_global_codebooks)
{
- // We're changed the block endpoint indices, so we need to go and adjust the endpoint codebook (remove unused entries, optimize existing entries that have changed)
- uint_vec new_block_endpoints(get_total_blocks());
-
- for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++)
+ m_endpoint_remap_table_old_to_new.clear();
+ m_endpoint_remap_table_old_to_new.resize(r.get_total_endpoint_clusters());
+ for (uint32_t i = 0; i < r.get_total_endpoint_clusters(); i++)
+ m_endpoint_remap_table_old_to_new[i] = i;
+ }
+ else
+ {
+ //if ((total_block_endpoints_remapped) && (m_params.m_compression_level > 0))
+ if ((total_block_endpoints_remapped) && (m_params.m_compression_level > 1))
{
- const uint32_t first_block_index = m_slices[slice_index].m_first_block_index;
- const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x;
- const uint32_t num_blocks_y = m_slices[slice_index].m_num_blocks_y;
+ // We've changed the block endpoint indices, so we need to go and adjust the endpoint codebook (remove unused entries, optimize existing entries that have changed)
+ uint_vec new_block_endpoints(get_total_blocks());
- for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
- for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
- new_block_endpoints[first_block_index + block_x + block_y * num_blocks_x] = m_slice_encoder_blocks[slice_index](block_x, block_y).m_endpoint_index;
- }
+ for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++)
+ {
+ const uint32_t first_block_index = m_slices[slice_index].m_first_block_index;
+ const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x;
+ const uint32_t num_blocks_y = m_slices[slice_index].m_num_blocks_y;
- int_vec old_to_new_endpoint_indices;
- r.reoptimize_remapped_endpoints(new_block_endpoints, old_to_new_endpoint_indices, true);
+ for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
+ for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
+ new_block_endpoints[first_block_index + block_x + block_y * num_blocks_x] = m_slice_encoder_blocks[slice_index](block_x, block_y).m_endpoint_index;
+ }
- create_endpoint_palette();
+ int_vec old_to_new_endpoint_indices;
+ r.reoptimize_remapped_endpoints(new_block_endpoints, old_to_new_endpoint_indices, true);
- for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++)
- {
- const uint32_t first_block_index = m_slices[slice_index].m_first_block_index;
+ create_endpoint_palette();
- const uint32_t width = m_slices[slice_index].m_width;
- const uint32_t height = m_slices[slice_index].m_height;
- const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x;
- const uint32_t num_blocks_y = m_slices[slice_index].m_num_blocks_y;
-
- for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
+ for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++)
{
- for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
+ //const uint32_t first_block_index = m_slices[slice_index].m_first_block_index;
+
+ //const uint32_t width = m_slices[slice_index].m_width;
+ //const uint32_t height = m_slices[slice_index].m_height;
+ const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x;
+ const uint32_t num_blocks_y = m_slices[slice_index].m_num_blocks_y;
+
+ for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
{
- const uint32_t block_index = first_block_index + block_x + block_y * num_blocks_x;
+ for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
+ {
+ //const uint32_t block_index = first_block_index + block_x + block_y * num_blocks_x;
- encoder_block& m = m_slice_encoder_blocks[slice_index](block_x, block_y);
+ encoder_block& m = m_slice_encoder_blocks[slice_index](block_x, block_y);
- m.m_endpoint_index = old_to_new_endpoint_indices[m.m_endpoint_index];
- } // block_x
- } // block_y
- } // slice_index
+ m.m_endpoint_index = old_to_new_endpoint_indices[m.m_endpoint_index];
+ } // block_x
+ } // block_y
+ } // slice_index
+
+ for (uint32_t i = 0; i < all_endpoint_indices.size(); i++)
+ all_endpoint_indices[i] = old_to_new_endpoint_indices[all_endpoint_indices[i]];
+
+ } //if (total_block_endpoints_remapped)
+
+ // Sort endpoint codebook
+ palette_index_reorderer reorderer;
+ reorderer.init((uint32_t)all_endpoint_indices.size(), &all_endpoint_indices[0], r.get_total_endpoint_clusters(), nullptr, nullptr, 0);
+ m_endpoint_remap_table_old_to_new = reorderer.get_remap_table();
+ }
- for (uint32_t i = 0; i < all_endpoint_indices.size(); i++)
- all_endpoint_indices[i] = old_to_new_endpoint_indices[all_endpoint_indices[i]];
+ // For endpoints, old_to_new[] may not be bijective!
+ // Some "old" entries may be unused and don't get remapped into the "new" array.
- } //if (total_block_endpoints_remapped)
+ m_old_endpoint_was_used.clear();
+ m_old_endpoint_was_used.resize(r.get_total_endpoint_clusters());
+ uint32_t first_old_entry_index = UINT32_MAX;
- // Sort endpoint codebook
- palette_index_reorderer reorderer;
- reorderer.init((uint32_t)all_endpoint_indices.size(), &all_endpoint_indices[0], r.get_total_endpoint_clusters(), nullptr, nullptr, 0);
- m_endpoint_remap_table_old_to_new = reorderer.get_remap_table();
+ for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++)
+ {
+ const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x, num_blocks_y = m_slices[slice_index].m_num_blocks_y;
+ for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
+ {
+ for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
+ {
+ encoder_block& m = m_slice_encoder_blocks[slice_index](block_x, block_y);
+ const uint32_t old_endpoint_index = m.m_endpoint_index;
+ m_old_endpoint_was_used[old_endpoint_index] = true;
+ first_old_entry_index = basisu::minimum(first_old_entry_index, old_endpoint_index);
+ } // block_x
+ } // block_y
+ } // slice_index
+
+ debug_printf("basisu_backend::reoptimize_and_sort_endpoints_codebook: First old entry index: %u\n", first_old_entry_index);
+
+ m_new_endpoint_was_used.clear();
+ m_new_endpoint_was_used.resize(r.get_total_endpoint_clusters());
+
+ m_endpoint_remap_table_new_to_old.clear();
m_endpoint_remap_table_new_to_old.resize(r.get_total_endpoint_clusters());
- for (uint32_t i = 0; i < m_endpoint_remap_table_old_to_new.size(); i++)
- m_endpoint_remap_table_new_to_old[m_endpoint_remap_table_old_to_new[i]] = i;
+
+ // Set unused entries in the new array to point to the first used entry in the old array.
+ m_endpoint_remap_table_new_to_old.set_all(first_old_entry_index);
+
+ for (uint32_t old_index = 0; old_index < m_endpoint_remap_table_old_to_new.size(); old_index++)
+ {
+ if (m_old_endpoint_was_used[old_index])
+ {
+ const uint32_t new_index = m_endpoint_remap_table_old_to_new[old_index];
+
+ m_new_endpoint_was_used[new_index] = true;
+
+ m_endpoint_remap_table_new_to_old[new_index] = old_index;
+ }
+ }
}
void basisu_backend::sort_selector_codebook()
@@ -242,7 +300,7 @@ namespace basisu
m_selector_remap_table_new_to_old.resize(r.get_total_selector_clusters());
- if (m_params.m_compression_level == 0)
+ if ((m_params.m_compression_level == 0) || (m_params.m_used_global_codebooks))
{
for (uint32_t i = 0; i < r.get_total_selector_clusters(); i++)
m_selector_remap_table_new_to_old[i] = i;
@@ -336,10 +394,10 @@ namespace basisu
for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++)
{
const bool is_iframe = m_slices[slice_index].m_iframe;
- const uint32_t first_block_index = m_slices[slice_index].m_first_block_index;
+ //const uint32_t first_block_index = m_slices[slice_index].m_first_block_index;
- const uint32_t width = m_slices[slice_index].m_width;
- const uint32_t height = m_slices[slice_index].m_height;
+ //const uint32_t width = m_slices[slice_index].m_width;
+ //const uint32_t height = m_slices[slice_index].m_height;
const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x;
const uint32_t num_blocks_y = m_slices[slice_index].m_num_blocks_y;
const int prev_frame_slice_index = find_video_frame(slice_index, -1);
@@ -393,6 +451,7 @@ namespace basisu
BASISU_BACKEND_VERIFY(total_invalid_crs == 0);
}
+
void basisu_backend::create_encoder_blocks()
{
basisu_frontend& r = *m_pFront_end;
@@ -411,8 +470,8 @@ namespace basisu
const bool is_iframe = m_slices[slice_index].m_iframe;
const uint32_t first_block_index = m_slices[slice_index].m_first_block_index;
- const uint32_t width = m_slices[slice_index].m_width;
- const uint32_t height = m_slices[slice_index].m_height;
+ //const uint32_t width = m_slices[slice_index].m_width;
+ //const uint32_t height = m_slices[slice_index].m_height;
const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x;
const uint32_t num_blocks_y = m_slices[slice_index].m_num_blocks_y;
@@ -590,7 +649,7 @@ namespace basisu
{
for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++)
{
- const uint32_t first_block_index = m_slices[slice_index].m_first_block_index;
+ //const uint32_t first_block_index = m_slices[slice_index].m_first_block_index;
const uint32_t width = m_slices[slice_index].m_width;
const uint32_t height = m_slices[slice_index].m_height;
const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x;
@@ -603,7 +662,7 @@ namespace basisu
{
for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
{
- const uint32_t block_index = first_block_index + block_x + block_y * num_blocks_x;
+ //const uint32_t block_index = first_block_index + block_x + block_y * num_blocks_x;
encoder_block& m = m_slice_encoder_blocks[slice_index](block_x, block_y);
@@ -662,7 +721,7 @@ namespace basisu
histogram selector_histogram(r.get_total_selector_clusters() + basist::MAX_SELECTOR_HISTORY_BUF_SIZE + 1);
histogram selector_history_buf_rle_histogram(1 << basist::SELECTOR_HISTORY_BUF_RLE_COUNT_BITS);
- std::vector<uint_vec> selector_syms(m_slices.size());
+ basisu::vector<uint_vec> selector_syms(m_slices.size());
const uint32_t SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX = r.get_total_selector_clusters();
const uint32_t SELECTOR_HISTORY_BUF_RLE_SYMBOL_INDEX = SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX + basist::MAX_SELECTOR_HISTORY_BUF_SIZE;
@@ -672,7 +731,7 @@ namespace basisu
histogram delta_endpoint_histogram(r.get_total_endpoint_clusters());
histogram endpoint_pred_histogram(basist::ENDPOINT_PRED_TOTAL_SYMBOLS);
- std::vector<uint_vec> endpoint_pred_syms(m_slices.size());
+ basisu::vector<uint_vec> endpoint_pred_syms(m_slices.size());
uint32_t total_endpoint_indices_remapped = 0;
@@ -680,11 +739,11 @@ namespace basisu
for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++)
{
- const int prev_frame_slice_index = is_video ? find_video_frame(slice_index, -1) : -1;
- const int next_frame_slice_index = is_video ? find_video_frame(slice_index, 1) : -1;
+ //const int prev_frame_slice_index = is_video ? find_video_frame(slice_index, -1) : -1;
+ //const int next_frame_slice_index = is_video ? find_video_frame(slice_index, 1) : -1;
const uint32_t first_block_index = m_slices[slice_index].m_first_block_index;
- const uint32_t width = m_slices[slice_index].m_width;
- const uint32_t height = m_slices[slice_index].m_height;
+ //const uint32_t width = m_slices[slice_index].m_width;
+ //const uint32_t height = m_slices[slice_index].m_height;
const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x;
const uint32_t num_blocks_y = m_slices[slice_index].m_num_blocks_y;
@@ -702,7 +761,7 @@ namespace basisu
{
for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
{
- const uint32_t block_index = first_block_index + block_x + block_y * num_blocks_x;
+ //const uint32_t block_index = first_block_index + block_x + block_y * num_blocks_x;
encoder_block& m = m_slice_encoder_blocks[slice_index](block_x, block_y);
@@ -723,6 +782,7 @@ namespace basisu
} // block_x
} // block_y
+
for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
{
for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
@@ -821,6 +881,10 @@ namespace basisu
if (trial_idx == new_endpoint_index)
continue;
+ // Skip it if this new endpoint palette entry is actually never used.
+ if (!m_new_endpoint_was_used[trial_idx])
+ continue;
+
const etc1_endpoint_palette_entry& p = m_endpoint_palette[m_endpoint_remap_table_new_to_old[trial_idx]];
trial_etc_blk.set_block_color5_etc1s(p.m_color5);
trial_etc_blk.set_inten_tables_etc1s(p.m_inten5);
@@ -884,23 +948,32 @@ namespace basisu
{
const pixel_block& src_pixels = r.get_source_pixel_block(block_index);
- etc_block etc_blk(r.get_output_block(block_index));
+ const etc_block& etc_blk = r.get_output_block(block_index);
color_rgba etc_blk_unpacked[16];
unpack_etc1(etc_blk, etc_blk_unpacked);
uint64_t cur_err = 0;
- for (uint32_t p = 0; p < 16; p++)
- cur_err += color_distance(r.get_params().m_perceptual, src_pixels.get_ptr()[p], etc_blk_unpacked[p], false);
-
+ if (r.get_params().m_perceptual)
+ {
+ for (uint32_t p = 0; p < 16; p++)
+ cur_err += color_distance(true, src_pixels.get_ptr()[p], etc_blk_unpacked[p], false);
+ }
+ else
+ {
+ for (uint32_t p = 0; p < 16; p++)
+ cur_err += color_distance(false, src_pixels.get_ptr()[p], etc_blk_unpacked[p], false);
+ }
+
uint64_t best_trial_err = UINT64_MAX;
int best_trial_idx = 0;
uint32_t best_trial_history_buf_idx = 0;
-
const float selector_remap_thresh = maximum(1.0f, m_params.m_selector_rdo_quality_thresh); //2.5f;
const bool use_strict_search = (m_params.m_compression_level == 0) && (selector_remap_thresh == 1.0f);
+ const uint64_t limit_err = (uint64_t)ceilf(cur_err * selector_remap_thresh);
+
for (uint32_t j = 0; j < selector_history_buf.size(); j++)
{
const int trial_idx = selector_history_buf[j];
@@ -917,31 +990,43 @@ namespace basisu
}
else
{
- for (uint32_t sy = 0; sy < 4; sy++)
- for (uint32_t sx = 0; sx < 4; sx++)
- etc_blk.set_selector(sx, sy, m_selector_palette[m_selector_remap_table_new_to_old[trial_idx]](sx, sy));
+ uint64_t trial_err = 0;
+ const uint64_t thresh_err = minimum(limit_err, best_trial_err);
- // TODO: Optimize this
- unpack_etc1(etc_blk, etc_blk_unpacked);
+ color_rgba block_colors[4];
+ etc_blk.get_block_colors(block_colors, 0);
- uint64_t trial_err = 0;
- const uint64_t thresh_err = minimum((uint64_t)ceilf(cur_err * selector_remap_thresh), best_trial_err);
- for (uint32_t p = 0; p < 16; p++)
+ const uint8_t* pSelectors = &m_selector_palette[m_selector_remap_table_new_to_old[trial_idx]](0, 0);
+
+ if (r.get_params().m_perceptual)
{
- trial_err += color_distance(r.get_params().m_perceptual, src_pixels.get_ptr()[p], etc_blk_unpacked[p], false);
- if (trial_err > thresh_err)
- break;
+ for (uint32_t p = 0; p < 16; p++)
+ {
+ uint32_t sel = pSelectors[p];
+ trial_err += color_distance(true, src_pixels.get_ptr()[p], block_colors[sel], false);
+ if (trial_err > thresh_err)
+ break;
+ }
}
-
- if (trial_err <= cur_err * selector_remap_thresh)
+ else
{
- if (trial_err < best_trial_err)
+ for (uint32_t p = 0; p < 16; p++)
{
- best_trial_err = trial_err;
- best_trial_idx = trial_idx;
- best_trial_history_buf_idx = j;
+ uint32_t sel = pSelectors[p];
+ trial_err += color_distance(false, src_pixels.get_ptr()[p], block_colors[sel], false);
+ if (trial_err > thresh_err)
+ break;
}
}
+
+ if ((trial_err < best_trial_err) && (trial_err <= thresh_err))
+ {
+ assert(trial_err <= limit_err);
+
+ best_trial_err = trial_err;
+ best_trial_idx = trial_idx;
+ best_trial_history_buf_idx = j;
+ }
}
}
@@ -1086,7 +1171,8 @@ namespace basisu
total_selector_indices_remapped, total_selector_indices_remapped * 100.0f / get_total_blocks(),
total_used_selector_history_buf, total_used_selector_history_buf * 100.0f / get_total_blocks());
- if ((total_endpoint_indices_remapped) && (m_params.m_compression_level > 0))
+ //if ((total_endpoint_indices_remapped) && (m_params.m_compression_level > 0))
+ if ((total_endpoint_indices_remapped) && (m_params.m_compression_level > 1) && (!m_params.m_used_global_codebooks))
{
int_vec unused;
r.reoptimize_remapped_endpoints(block_endpoint_indices, unused, false, &block_selector_indices);
@@ -1168,8 +1254,8 @@ namespace basisu
for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++)
{
- const uint32_t width = m_slices[slice_index].m_width;
- const uint32_t height = m_slices[slice_index].m_height;
+ //const uint32_t width = m_slices[slice_index].m_width;
+ //const uint32_t height = m_slices[slice_index].m_height;
const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x;
const uint32_t num_blocks_y = m_slices[slice_index].m_num_blocks_y;
@@ -1296,10 +1382,53 @@ namespace basisu
{
const basisu_frontend& r = *m_pFront_end;
+ // The endpoint indices may have been changed by the backend's RDO step, so go and figure out which ones are actually used again.
+ bool_vec old_endpoint_was_used(r.get_total_endpoint_clusters());
+ uint32_t first_old_entry_index = UINT32_MAX;
+
+ for (uint32_t slice_index = 0; slice_index < m_slices.size(); slice_index++)
+ {
+ const uint32_t num_blocks_x = m_slices[slice_index].m_num_blocks_x, num_blocks_y = m_slices[slice_index].m_num_blocks_y;
+ for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
+ {
+ for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
+ {
+ encoder_block& m = m_slice_encoder_blocks[slice_index](block_x, block_y);
+ const uint32_t old_endpoint_index = m.m_endpoint_index;
+
+ old_endpoint_was_used[old_endpoint_index] = true;
+ first_old_entry_index = basisu::minimum(first_old_entry_index, old_endpoint_index);
+ } // block_x
+ } // block_y
+ } // slice_index
+
+ debug_printf("basisu_backend::encode_endpoint_palette: first_old_entry_index: %u\n", first_old_entry_index);
+
// Maps NEW to OLD endpoints
- uint_vec endpoint_remap_table_inv(r.get_total_endpoint_clusters());
+ uint_vec endpoint_remap_table_new_to_old(r.get_total_endpoint_clusters());
+ endpoint_remap_table_new_to_old.set_all(first_old_entry_index);
+
+ bool_vec new_endpoint_was_used(r.get_total_endpoint_clusters());
+
for (uint32_t old_endpoint_index = 0; old_endpoint_index < m_endpoint_remap_table_old_to_new.size(); old_endpoint_index++)
- endpoint_remap_table_inv[m_endpoint_remap_table_old_to_new[old_endpoint_index]] = old_endpoint_index;
+ {
+ if (old_endpoint_was_used[old_endpoint_index])
+ {
+ const uint32_t new_endpoint_index = m_endpoint_remap_table_old_to_new[old_endpoint_index];
+
+ new_endpoint_was_used[new_endpoint_index] = true;
+
+ endpoint_remap_table_new_to_old[new_endpoint_index] = old_endpoint_index;
+ }
+ }
+
+ // TODO: Some new endpoint palette entries may actually be unused and aren't worth coding. Fix that.
+
+ uint32_t total_unused_new_entries = 0;
+ for (uint32_t i = 0; i < new_endpoint_was_used.size(); i++)
+ if (!new_endpoint_was_used[i])
+ total_unused_new_entries++;
+ debug_printf("basisu_backend::encode_endpoint_palette: total_unused_new_entries: %u out of %u\n", total_unused_new_entries, new_endpoint_was_used.size());
bool is_grayscale = true;
for (uint32_t old_endpoint_index = 0; old_endpoint_index < (uint32_t)m_endpoint_palette.size(); old_endpoint_index++)
@@ -1324,7 +1453,7 @@ namespace basisu
for (uint32_t new_endpoint_index = 0; new_endpoint_index < r.get_total_endpoint_clusters(); new_endpoint_index++)
{
- const uint32_t old_endpoint_index = endpoint_remap_table_inv[new_endpoint_index];
+ const uint32_t old_endpoint_index = endpoint_remap_table_new_to_old[new_endpoint_index];
int delta_inten = m_endpoint_palette[old_endpoint_index].m_inten5 - prev_inten;
inten_delta_hist.inc(delta_inten & 7);
@@ -1390,7 +1519,7 @@ namespace basisu
for (uint32_t new_endpoint_index = 0; new_endpoint_index < r.get_total_endpoint_clusters(); new_endpoint_index++)
{
- const uint32_t old_endpoint_index = endpoint_remap_table_inv[new_endpoint_index];
+ const uint32_t old_endpoint_index = endpoint_remap_table_new_to_old[new_endpoint_index];
int delta_inten = (m_endpoint_palette[old_endpoint_index].m_inten5 - prev_inten) & 7;
coder.put_code(delta_inten, inten_delta_model);
@@ -1644,9 +1773,11 @@ namespace basisu
uint32_t basisu_backend::encode()
{
- const bool is_video = m_pFront_end->get_params().m_tex_type == basist::cBASISTexTypeVideoFrames;
+ //const bool is_video = m_pFront_end->get_params().m_tex_type == basist::cBASISTexTypeVideoFrames;
m_output.m_slice_desc = m_slices;
m_output.m_etc1s = m_params.m_etc1s;
+ m_output.m_uses_global_codebooks = m_params.m_used_global_codebooks;
+ m_output.m_srgb = m_pFront_end->get_params().m_perceptual;
create_endpoint_palette();
create_selector_palette();
diff --git a/thirdparty/basis_universal/basisu_backend.h b/thirdparty/basis_universal/encoder/basisu_backend.h
index 1c72fa8cc8..393dccd22f 100644
--- a/thirdparty/basis_universal/basisu_backend.h
+++ b/thirdparty/basis_universal/encoder/basisu_backend.h
@@ -1,5 +1,5 @@
// basisu_backend.h
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,10 +14,10 @@
// limitations under the License.
#pragma once
-#include "transcoder/basisu.h"
+#include "../transcoder/basisu.h"
#include "basisu_enc.h"
-#include "transcoder/basisu_transcoder_internal.h"
-#include "transcoder/basisu_global_selector_palette.h"
+#include "../transcoder/basisu_transcoder_internal.h"
+#include "../transcoder/basisu_global_selector_palette.h"
#include "basisu_frontend.h"
namespace basisu
@@ -49,7 +49,7 @@ namespace basisu
}
};
- typedef std::vector<encoder_block> encoder_block_vec;
+ typedef basisu::vector<encoder_block> encoder_block_vec;
typedef vector2D<encoder_block> encoder_block_vec2D;
struct etc1_endpoint_palette_entry
@@ -69,7 +69,7 @@ namespace basisu
}
};
- typedef std::vector<etc1_endpoint_palette_entry> etc1_endpoint_palette_entry_vec;
+ typedef basisu::vector<etc1_endpoint_palette_entry> etc1_endpoint_palette_entry_vec;
struct basisu_backend_params
{
@@ -84,6 +84,8 @@ namespace basisu
uint32_t m_global_sel_codebook_mod_bits;
bool m_use_hybrid_sel_codebooks;
+ bool m_used_global_codebooks;
+
basisu_backend_params()
{
clear();
@@ -102,6 +104,7 @@ namespace basisu
m_global_sel_codebook_pal_bits = ETC1_GLOBAL_SELECTOR_CODEBOOK_MAX_PAL_BITS;
m_global_sel_codebook_mod_bits = basist::etc1_global_palette_entry_modifier::cTotalBits;
m_use_hybrid_sel_codebooks = false;
+ m_used_global_codebooks = false;
}
};
@@ -111,10 +114,12 @@ namespace basisu
{
clear();
}
+
void clear()
{
clear_obj(*this);
}
+
uint32_t m_first_block_index;
uint32_t m_orig_width;
@@ -135,11 +140,15 @@ namespace basisu
bool m_iframe;
};
- typedef std::vector<basisu_backend_slice_desc> basisu_backend_slice_desc_vec;
+ typedef basisu::vector<basisu_backend_slice_desc> basisu_backend_slice_desc_vec;
struct basisu_backend_output
{
+ basist::basis_tex_format m_tex_format;
+
bool m_etc1s;
+ bool m_uses_global_codebooks;
+ bool m_srgb;
uint32_t m_num_endpoints;
uint32_t m_num_selectors;
@@ -150,7 +159,7 @@ namespace basisu
basisu_backend_slice_desc_vec m_slice_desc;
uint8_vec m_slice_image_tables;
- std::vector<uint8_vec> m_slice_image_data;
+ basisu::vector<uint8_vec> m_slice_image_data;
uint16_vec m_slice_image_crcs;
basisu_backend_output()
@@ -160,7 +169,10 @@ namespace basisu
void clear()
{
+ m_tex_format = basist::basis_tex_format::cETC1S;
m_etc1s = false;
+ m_uses_global_codebooks = false;
+ m_srgb = true;
m_num_endpoints = 0;
m_num_selectors = 0;
@@ -198,6 +210,7 @@ namespace basisu
uint32_t encode();
const basisu_backend_output &get_output() const { return m_output; }
+ const basisu_backend_params& get_params() const { return m_params; }
private:
basisu_frontend *m_pFront_end;
@@ -216,15 +229,17 @@ namespace basisu
bool m_was_used;
};
- typedef std::vector<etc1_global_selector_cb_entry_desc> etc1_global_selector_cb_entry_desc_vec;
+ typedef basisu::vector<etc1_global_selector_cb_entry_desc> etc1_global_selector_cb_entry_desc_vec;
etc1_global_selector_cb_entry_desc_vec m_global_selector_palette_desc;
- std::vector<encoder_block_vec2D> m_slice_encoder_blocks;
+ basisu::vector<encoder_block_vec2D> m_slice_encoder_blocks;
// Maps OLD to NEW endpoint/selector indices
uint_vec m_endpoint_remap_table_old_to_new;
uint_vec m_endpoint_remap_table_new_to_old;
+ bool_vec m_old_endpoint_was_used;
+ bool_vec m_new_endpoint_was_used;
uint_vec m_selector_remap_table_old_to_new;
diff --git a/thirdparty/basis_universal/basisu_basis_file.cpp b/thirdparty/basis_universal/encoder/basisu_basis_file.cpp
index 3e6b1906b9..f4c77bef23 100644
--- a/thirdparty/basis_universal/basisu_basis_file.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_basis_file.cpp
@@ -1,5 +1,5 @@
// basisu_basis_file.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "basisu_basis_file.h"
-#include "transcoder/basisu_transcoder.h"
+#include "../transcoder/basisu_transcoder.h"
// The output file version. Keep in sync with BASISD_SUPPORTED_BASIS_VERSION.
#define BASIS_FILE_VERSION (0x13)
@@ -31,15 +31,26 @@ namespace basisu
m_header.m_total_images = 0;
for (uint32_t i = 0; i < encoder_output.m_slice_desc.size(); i++)
m_header.m_total_images = maximum<uint32_t>(m_header.m_total_images, encoder_output.m_slice_desc[i].m_source_file_index + 1);
-
- m_header.m_format = 0;// basist::block_format::cETC1;
+
+ m_header.m_tex_format = (int)encoder_output.m_tex_format;
m_header.m_flags = 0;
if (encoder_output.m_etc1s)
+ {
+ assert(encoder_output.m_tex_format == basist::basis_tex_format::cETC1S);
m_header.m_flags = m_header.m_flags | basist::cBASISHeaderFlagETC1S;
+ }
+ else
+ {
+ assert(encoder_output.m_tex_format != basist::basis_tex_format::cETC1S);
+ }
if (y_flipped)
m_header.m_flags = m_header.m_flags | basist::cBASISHeaderFlagYFlipped;
+ if (encoder_output.m_uses_global_codebooks)
+ m_header.m_flags = m_header.m_flags | basist::cBASISHeaderFlagUsesGlobalCodebook;
+ if (encoder_output.m_srgb)
+ m_header.m_flags = m_header.m_flags | basist::cBASISHeaderFlagSRGB;
for (uint32_t i = 0; i < encoder_output.m_slice_desc.size(); i++)
{
@@ -57,12 +68,26 @@ namespace basisu
m_header.m_userdata1 = userdata1;
m_header.m_total_endpoints = encoder_output.m_num_endpoints;
- m_header.m_endpoint_cb_file_ofs = m_endpoint_cb_file_ofs;
- m_header.m_endpoint_cb_file_size = (uint32_t)encoder_output.m_endpoint_palette.size();
+ if (!encoder_output.m_uses_global_codebooks)
+ {
+ m_header.m_endpoint_cb_file_ofs = m_endpoint_cb_file_ofs;
+ m_header.m_endpoint_cb_file_size = (uint32_t)encoder_output.m_endpoint_palette.size();
+ }
+ else
+ {
+ assert(!m_endpoint_cb_file_ofs);
+ }
m_header.m_total_selectors = encoder_output.m_num_selectors;
- m_header.m_selector_cb_file_ofs = m_selector_cb_file_ofs;
- m_header.m_selector_cb_file_size = (uint32_t)encoder_output.m_selector_palette.size();
+ if (!encoder_output.m_uses_global_codebooks)
+ {
+ m_header.m_selector_cb_file_ofs = m_selector_cb_file_ofs;
+ m_header.m_selector_cb_file_size = (uint32_t)encoder_output.m_selector_palette.size();
+ }
+ else
+ {
+ assert(!m_selector_cb_file_ofs);
+ }
m_header.m_tables_file_ofs = m_tables_file_ofs;
m_header.m_tables_file_size = (uint32_t)encoder_output.m_slice_image_tables.size();
@@ -85,7 +110,7 @@ namespace basisu
m_images_descs[i].m_level_index = slice_descs[i].m_mip_index;
if (slice_descs[i].m_alpha)
- m_images_descs[i].m_flags = m_images_descs[i].m_flags | basist::cSliceDescFlagsIsAlphaData;
+ m_images_descs[i].m_flags = m_images_descs[i].m_flags | basist::cSliceDescFlagsHasAlpha;
if (slice_descs[i].m_iframe)
m_images_descs[i].m_flags = m_images_descs[i].m_flags | basist::cSliceDescFlagsFrameIsIFrame;
@@ -127,14 +152,26 @@ namespace basisu
assert(m_comp_data.size() == m_slice_descs_file_ofs);
append_vector(m_comp_data, reinterpret_cast<const uint8_t*>(&m_images_descs[0]), m_images_descs.size() * sizeof(m_images_descs[0]));
- assert(m_comp_data.size() == m_endpoint_cb_file_ofs);
- append_vector(m_comp_data, reinterpret_cast<const uint8_t*>(&encoder_output.m_endpoint_palette[0]), encoder_output.m_endpoint_palette.size());
+ if (!encoder_output.m_uses_global_codebooks)
+ {
+ if (encoder_output.m_endpoint_palette.size())
+ {
+ assert(m_comp_data.size() == m_endpoint_cb_file_ofs);
+ append_vector(m_comp_data, reinterpret_cast<const uint8_t*>(&encoder_output.m_endpoint_palette[0]), encoder_output.m_endpoint_palette.size());
+ }
- assert(m_comp_data.size() == m_selector_cb_file_ofs);
- append_vector(m_comp_data, reinterpret_cast<const uint8_t*>(&encoder_output.m_selector_palette[0]), encoder_output.m_selector_palette.size());
+ if (encoder_output.m_selector_palette.size())
+ {
+ assert(m_comp_data.size() == m_selector_cb_file_ofs);
+ append_vector(m_comp_data, reinterpret_cast<const uint8_t*>(&encoder_output.m_selector_palette[0]), encoder_output.m_selector_palette.size());
+ }
+ }
- assert(m_comp_data.size() == m_tables_file_ofs);
- append_vector(m_comp_data, reinterpret_cast<const uint8_t*>(&encoder_output.m_slice_image_tables[0]), encoder_output.m_slice_image_tables.size());
+ if (encoder_output.m_slice_image_tables.size())
+ {
+ assert(m_comp_data.size() == m_tables_file_ofs);
+ append_vector(m_comp_data, reinterpret_cast<const uint8_t*>(&encoder_output.m_slice_image_tables[0]), encoder_output.m_slice_image_tables.size());
+ }
assert(m_comp_data.size() == m_first_image_file_ofs);
for (uint32_t i = 0; i < slice_descs.size(); i++)
@@ -163,8 +200,17 @@ namespace basisu
const basisu_backend_slice_desc_vec &slice_descs = encoder_output.m_slice_desc;
// The Basis file uses 32-bit fields for lots of stuff, so make sure it's not too large.
- uint64_t check_size = (uint64_t)sizeof(basist::basis_file_header) + (uint64_t)sizeof(basist::basis_slice_desc) * slice_descs.size() +
+ uint64_t check_size = 0;
+ if (!encoder_output.m_uses_global_codebooks)
+ {
+ check_size = (uint64_t)sizeof(basist::basis_file_header) + (uint64_t)sizeof(basist::basis_slice_desc) * slice_descs.size() +
(uint64_t)encoder_output.m_endpoint_palette.size() + (uint64_t)encoder_output.m_selector_palette.size() + (uint64_t)encoder_output.m_slice_image_tables.size();
+ }
+ else
+ {
+ check_size = (uint64_t)sizeof(basist::basis_file_header) + (uint64_t)sizeof(basist::basis_slice_desc) * slice_descs.size() +
+ (uint64_t)encoder_output.m_slice_image_tables.size();
+ }
if (check_size >= 0xFFFF0000ULL)
{
error_printf("basisu_file::init: File is too large!\n");
@@ -173,10 +219,29 @@ namespace basisu
m_header_file_ofs = 0;
m_slice_descs_file_ofs = sizeof(basist::basis_file_header);
- m_endpoint_cb_file_ofs = m_slice_descs_file_ofs + sizeof(basist::basis_slice_desc) * (uint32_t)slice_descs.size();
- m_selector_cb_file_ofs = m_endpoint_cb_file_ofs + (uint32_t)encoder_output.m_endpoint_palette.size();
- m_tables_file_ofs = m_selector_cb_file_ofs + (uint32_t)encoder_output.m_selector_palette.size();
- m_first_image_file_ofs = m_tables_file_ofs + (uint32_t)encoder_output.m_slice_image_tables.size();
+ if (encoder_output.m_tex_format == basist::basis_tex_format::cETC1S)
+ {
+ if (encoder_output.m_uses_global_codebooks)
+ {
+ m_endpoint_cb_file_ofs = 0;
+ m_selector_cb_file_ofs = 0;
+ m_tables_file_ofs = m_slice_descs_file_ofs + sizeof(basist::basis_slice_desc) * (uint32_t)slice_descs.size();
+ }
+ else
+ {
+ m_endpoint_cb_file_ofs = m_slice_descs_file_ofs + sizeof(basist::basis_slice_desc) * (uint32_t)slice_descs.size();
+ m_selector_cb_file_ofs = m_endpoint_cb_file_ofs + (uint32_t)encoder_output.m_endpoint_palette.size();
+ m_tables_file_ofs = m_selector_cb_file_ofs + (uint32_t)encoder_output.m_selector_palette.size();
+ }
+ m_first_image_file_ofs = m_tables_file_ofs + (uint32_t)encoder_output.m_slice_image_tables.size();
+ }
+ else
+ {
+ m_endpoint_cb_file_ofs = 0;
+ m_selector_cb_file_ofs = 0;
+ m_tables_file_ofs = 0;
+ m_first_image_file_ofs = m_slice_descs_file_ofs + sizeof(basist::basis_slice_desc) * (uint32_t)slice_descs.size();
+ }
uint64_t total_file_size = m_first_image_file_ofs;
for (uint32_t i = 0; i < encoder_output.m_slice_image_data.size(); i++)
diff --git a/thirdparty/basis_universal/basisu_basis_file.h b/thirdparty/basis_universal/encoder/basisu_basis_file.h
index df3abbdcfd..98498a0121 100644
--- a/thirdparty/basis_universal/basisu_basis_file.h
+++ b/thirdparty/basis_universal/encoder/basisu_basis_file.h
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
-#include "transcoder/basisu_file_headers.h"
+#include "../transcoder/basisu_file_headers.h"
#include "basisu_backend.h"
namespace basisu
@@ -49,7 +49,7 @@ namespace basisu
private:
basist::basis_file_header m_header;
- std::vector<basist::basis_slice_desc> m_images_descs;
+ basisu::vector<basist::basis_slice_desc> m_images_descs;
uint8_vec m_comp_data;
diff --git a/thirdparty/basis_universal/encoder/basisu_bc7enc.cpp b/thirdparty/basis_universal/encoder/basisu_bc7enc.cpp
new file mode 100644
index 0000000000..06aa7eb8b1
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_bc7enc.cpp
@@ -0,0 +1,1984 @@
+// File: basisu_bc7enc.cpp
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "basisu_bc7enc.h"
+
+#ifdef _DEBUG
+#define BC7ENC_CHECK_OVERALL_ERROR 1
+#else
+#define BC7ENC_CHECK_OVERALL_ERROR 0
+#endif
+
+using namespace basist;
+
+namespace basisu
+{
+
+// Helpers
+static inline color_quad_u8 *color_quad_u8_set_clamped(color_quad_u8 *pRes, int32_t r, int32_t g, int32_t b, int32_t a) { pRes->m_c[0] = (uint8_t)clampi(r, 0, 255); pRes->m_c[1] = (uint8_t)clampi(g, 0, 255); pRes->m_c[2] = (uint8_t)clampi(b, 0, 255); pRes->m_c[3] = (uint8_t)clampi(a, 0, 255); return pRes; }
+static inline color_quad_u8 *color_quad_u8_set(color_quad_u8 *pRes, int32_t r, int32_t g, int32_t b, int32_t a) { assert((uint32_t)(r | g | b | a) <= 255); pRes->m_c[0] = (uint8_t)r; pRes->m_c[1] = (uint8_t)g; pRes->m_c[2] = (uint8_t)b; pRes->m_c[3] = (uint8_t)a; return pRes; }
+static inline bc7enc_bool color_quad_u8_notequals(const color_quad_u8 *pLHS, const color_quad_u8 *pRHS) { return (pLHS->m_c[0] != pRHS->m_c[0]) || (pLHS->m_c[1] != pRHS->m_c[1]) || (pLHS->m_c[2] != pRHS->m_c[2]) || (pLHS->m_c[3] != pRHS->m_c[3]); }
+static inline bc7enc_vec4F*vec4F_set_scalar(bc7enc_vec4F*pV, float x) { pV->m_c[0] = x; pV->m_c[1] = x; pV->m_c[2] = x; pV->m_c[3] = x; return pV; }
+static inline bc7enc_vec4F*vec4F_set(bc7enc_vec4F*pV, float x, float y, float z, float w) { pV->m_c[0] = x; pV->m_c[1] = y; pV->m_c[2] = z; pV->m_c[3] = w; return pV; }
+static inline bc7enc_vec4F*vec4F_saturate_in_place(bc7enc_vec4F*pV) { pV->m_c[0] = saturate(pV->m_c[0]); pV->m_c[1] = saturate(pV->m_c[1]); pV->m_c[2] = saturate(pV->m_c[2]); pV->m_c[3] = saturate(pV->m_c[3]); return pV; }
+static inline bc7enc_vec4F vec4F_saturate(const bc7enc_vec4F*pV) { bc7enc_vec4F res; res.m_c[0] = saturate(pV->m_c[0]); res.m_c[1] = saturate(pV->m_c[1]); res.m_c[2] = saturate(pV->m_c[2]); res.m_c[3] = saturate(pV->m_c[3]); return res; }
+static inline bc7enc_vec4F vec4F_from_color(const color_quad_u8 *pC) { bc7enc_vec4F res; vec4F_set(&res, pC->m_c[0], pC->m_c[1], pC->m_c[2], pC->m_c[3]); return res; }
+static inline bc7enc_vec4F vec4F_add(const bc7enc_vec4F*pLHS, const bc7enc_vec4F*pRHS) { bc7enc_vec4F res; vec4F_set(&res, pLHS->m_c[0] + pRHS->m_c[0], pLHS->m_c[1] + pRHS->m_c[1], pLHS->m_c[2] + pRHS->m_c[2], pLHS->m_c[3] + pRHS->m_c[3]); return res; }
+static inline bc7enc_vec4F vec4F_sub(const bc7enc_vec4F*pLHS, const bc7enc_vec4F*pRHS) { bc7enc_vec4F res; vec4F_set(&res, pLHS->m_c[0] - pRHS->m_c[0], pLHS->m_c[1] - pRHS->m_c[1], pLHS->m_c[2] - pRHS->m_c[2], pLHS->m_c[3] - pRHS->m_c[3]); return res; }
+static inline float vec4F_dot(const bc7enc_vec4F*pLHS, const bc7enc_vec4F*pRHS) { return pLHS->m_c[0] * pRHS->m_c[0] + pLHS->m_c[1] * pRHS->m_c[1] + pLHS->m_c[2] * pRHS->m_c[2] + pLHS->m_c[3] * pRHS->m_c[3]; }
+static inline bc7enc_vec4F vec4F_mul(const bc7enc_vec4F*pLHS, float s) { bc7enc_vec4F res; vec4F_set(&res, pLHS->m_c[0] * s, pLHS->m_c[1] * s, pLHS->m_c[2] * s, pLHS->m_c[3] * s); return res; }
+static inline bc7enc_vec4F* vec4F_normalize_in_place(bc7enc_vec4F*pV) { float s = pV->m_c[0] * pV->m_c[0] + pV->m_c[1] * pV->m_c[1] + pV->m_c[2] * pV->m_c[2] + pV->m_c[3] * pV->m_c[3]; if (s != 0.0f) { s = 1.0f / sqrtf(s); pV->m_c[0] *= s; pV->m_c[1] *= s; pV->m_c[2] *= s; pV->m_c[3] *= s; } return pV; }
+
+// Precomputed weight constants used during least fit determination. For each entry in g_bc7_weights[]: w * w, (1.0f - w) * w, (1.0f - w) * (1.0f - w), w
+const float g_bc7_weights1x[2 * 4] = { 0.000000f, 0.000000f, 1.000000f, 0.000000f, 1.000000f, 0.000000f, 0.000000f, 1.000000f };
+
+const float g_bc7_weights2x[4 * 4] = { 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.107666f, 0.220459f, 0.451416f, 0.328125f, 0.451416f, 0.220459f, 0.107666f, 0.671875f, 1.000000f, 0.000000f, 0.000000f, 1.000000f };
+
+const float g_bc7_weights3x[8 * 4] = { 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.019775f, 0.120850f, 0.738525f, 0.140625f, 0.079102f, 0.202148f, 0.516602f, 0.281250f, 0.177979f, 0.243896f, 0.334229f, 0.421875f, 0.334229f, 0.243896f, 0.177979f, 0.578125f, 0.516602f, 0.202148f,
+ 0.079102f, 0.718750f, 0.738525f, 0.120850f, 0.019775f, 0.859375f, 1.000000f, 0.000000f, 0.000000f, 1.000000f };
+
+const float g_bc7_weights4x[16 * 4] = { 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.003906f, 0.058594f, 0.878906f, 0.062500f, 0.019775f, 0.120850f, 0.738525f, 0.140625f, 0.041260f, 0.161865f, 0.635010f, 0.203125f, 0.070557f, 0.195068f, 0.539307f, 0.265625f, 0.107666f, 0.220459f,
+ 0.451416f, 0.328125f, 0.165039f, 0.241211f, 0.352539f, 0.406250f, 0.219727f, 0.249023f, 0.282227f, 0.468750f, 0.282227f, 0.249023f, 0.219727f, 0.531250f, 0.352539f, 0.241211f, 0.165039f, 0.593750f, 0.451416f, 0.220459f, 0.107666f, 0.671875f, 0.539307f, 0.195068f, 0.070557f, 0.734375f,
+ 0.635010f, 0.161865f, 0.041260f, 0.796875f, 0.738525f, 0.120850f, 0.019775f, 0.859375f, 0.878906f, 0.058594f, 0.003906f, 0.937500f, 1.000000f, 0.000000f, 0.000000f, 1.000000f };
+
+const float g_astc_weights4x[16 * 4] = { 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.003906f, 0.058594f, 0.878906f, 0.062500f, 0.015625f, 0.109375f, 0.765625f, 0.125000f, 0.035156f, 0.152344f, 0.660156f, 0.187500f, 0.070557f, 0.195068f, 0.539307f, 0.265625f, 0.107666f, 0.220459f,
+ 0.451416f, 0.328125f, 0.152588f, 0.238037f, 0.371338f, 0.390625f, 0.205322f, 0.247803f, 0.299072f, 0.453125f, 0.299072f, 0.247803f, 0.205322f, 0.546875f, 0.371338f, 0.238037f, 0.152588f, 0.609375f, 0.451416f, 0.220459f, 0.107666f, 0.671875f, 0.539307f, 0.195068f, 0.070557f, 0.734375f,
+ 0.660156f, 0.152344f, 0.035156f, 0.812500f, 0.765625f, 0.109375f, 0.015625f, 0.875000f, 0.878906f, 0.058594f, 0.003906f, 0.937500f, 1.000000f, 0.000000f, 0.000000f, 1.000000f };
+
+const float g_astc_weights5x[32 * 4] = { 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.000977f, 0.030273f, 0.938477f, 0.031250f, 0.003906f, 0.058594f, 0.878906f, 0.062500f, 0.008789f, 0.084961f, 0.821289f,
+ 0.093750f, 0.015625f, 0.109375f, 0.765625f, 0.125000f, 0.024414f, 0.131836f, 0.711914f, 0.156250f, 0.035156f, 0.152344f, 0.660156f, 0.187500f, 0.047852f, 0.170898f, 0.610352f, 0.218750f, 0.062500f, 0.187500f,
+ 0.562500f, 0.250000f, 0.079102f, 0.202148f, 0.516602f, 0.281250f, 0.097656f, 0.214844f, 0.472656f, 0.312500f, 0.118164f, 0.225586f, 0.430664f, 0.343750f, 0.140625f, 0.234375f, 0.390625f, 0.375000f, 0.165039f,
+ 0.241211f, 0.352539f, 0.406250f, 0.191406f, 0.246094f, 0.316406f, 0.437500f, 0.219727f, 0.249023f, 0.282227f, 0.468750f, 0.282227f, 0.249023f, 0.219727f, 0.531250f, 0.316406f, 0.246094f, 0.191406f, 0.562500f,
+ 0.352539f, 0.241211f, 0.165039f, 0.593750f, 0.390625f, 0.234375f, 0.140625f, 0.625000f, 0.430664f, 0.225586f, 0.118164f, 0.656250f, 0.472656f, 0.214844f, 0.097656f, 0.687500f, 0.516602f, 0.202148f, 0.079102f,
+ 0.718750f, 0.562500f, 0.187500f, 0.062500f, 0.750000f, 0.610352f, 0.170898f, 0.047852f, 0.781250f, 0.660156f, 0.152344f, 0.035156f, 0.812500f, 0.711914f, 0.131836f, 0.024414f, 0.843750f, 0.765625f, 0.109375f,
+ 0.015625f, 0.875000f, 0.821289f, 0.084961f, 0.008789f, 0.906250f, 0.878906f, 0.058594f, 0.003906f, 0.937500f, 0.938477f, 0.030273f, 0.000977f, 0.968750f, 1.000000f, 0.000000f, 0.000000f, 1.000000f };
+
+const float g_astc_weights_3levelsx[3 * 4] = {
+ 0.000000f, 0.000000f, 1.000000f, 0.000000f,
+ .5f * .5f, (1.0f - .5f) * .5f, (1.0f - .5f) * (1.0f - .5f), .5f,
+ 1.000000f, 0.000000f, 0.000000f, 1.000000f };
+
+static endpoint_err g_bc7_mode_1_optimal_endpoints[256][2]; // [c][pbit]
+static const uint32_t BC7ENC_MODE_1_OPTIMAL_INDEX = 2;
+
+static endpoint_err g_astc_4bit_3bit_optimal_endpoints[256]; // [c]
+static const uint32_t BC7ENC_ASTC_4BIT_3BIT_OPTIMAL_INDEX = 2;
+
+static endpoint_err g_astc_4bit_2bit_optimal_endpoints[256]; // [c]
+static const uint32_t BC7ENC_ASTC_4BIT_2BIT_OPTIMAL_INDEX = 1;
+
+static endpoint_err g_astc_range7_2bit_optimal_endpoints[256]; // [c]
+static const uint32_t BC7ENC_ASTC_RANGE7_2BIT_OPTIMAL_INDEX = 1;
+
+static endpoint_err g_astc_range13_4bit_optimal_endpoints[256]; // [c]
+static const uint32_t BC7ENC_ASTC_RANGE13_4BIT_OPTIMAL_INDEX = 2;
+
+static endpoint_err g_astc_range13_2bit_optimal_endpoints[256]; // [c]
+static const uint32_t BC7ENC_ASTC_RANGE13_2BIT_OPTIMAL_INDEX = 1;
+
+static endpoint_err g_astc_range11_5bit_optimal_endpoints[256]; // [c]
+static const uint32_t BC7ENC_ASTC_RANGE11_5BIT_OPTIMAL_INDEX = 13; // not 1, which is optimal, because 26 losslessly maps to BC7 4-bit weights
+
+astc_quant_bin g_astc_sorted_order_unquant[BC7ENC_TOTAL_ASTC_RANGES][256]; // [sorted unquantized order]
+
+static uint8_t g_astc_nearest_sorted_index[BC7ENC_TOTAL_ASTC_RANGES][256];
+
+static void astc_init()
+{
+ for (uint32_t range = 0; range < BC7ENC_TOTAL_ASTC_RANGES; range++)
+ {
+ if (!astc_is_valid_endpoint_range(range))
+ continue;
+
+ const uint32_t levels = astc_get_levels(range);
+
+ uint32_t vals[256];
+ // TODO
+ for (uint32_t i = 0; i < levels; i++)
+ vals[i] = (unquant_astc_endpoint_val(i, range) << 8) | i;
+
+ std::sort(vals, vals + levels);
+
+ for (uint32_t i = 0; i < levels; i++)
+ {
+ uint32_t order = vals[i] & 0xFF;
+ uint32_t unq = vals[i] >> 8;
+
+ g_astc_sorted_order_unquant[range][i].m_unquant = (uint8_t)unq;
+ g_astc_sorted_order_unquant[range][i].m_index = (uint8_t)order;
+
+ } // i
+
+#if 0
+ if (g_astc_bise_range_table[range][1] || g_astc_bise_range_table[range][2])
+ {
+ printf("// Range: %u, Levels: %u, Bits: %u, Trits: %u, Quints: %u\n", range, levels, g_astc_bise_range_table[range][0], g_astc_bise_range_table[range][1], g_astc_bise_range_table[range][2]);
+
+ printf("{");
+ for (uint32_t i = 0; i < levels; i++)
+ {
+ printf("{%u,%u}", g_astc_sorted_order_unquant[range][i].m_index, g_astc_sorted_order_unquant[range][i].m_unquant);
+ if (i != (levels - 1))
+ printf(",");
+ }
+ printf("}\n");
+ }
+#endif
+
+#if 0
+ if (g_astc_bise_range_table[range][1] || g_astc_bise_range_table[range][2])
+ {
+ printf("// Range: %u, Levels: %u, Bits: %u, Trits: %u, Quints: %u\n", range, levels, g_astc_bise_range_table[range][0], g_astc_bise_range_table[range][1], g_astc_bise_range_table[range][2]);
+
+ printf("{");
+ for (uint32_t i = 0; i < levels; i++)
+ {
+ printf("{%u,%u}", g_astc_unquant[range][i].m_index, g_astc_unquant[range][i].m_unquant);
+ if (i != (levels - 1))
+ printf(",");
+ }
+ printf("}\n");
+ }
+#endif
+
+ for (uint32_t i = 0; i < 256; i++)
+ {
+ uint32_t best_index = 0;
+ int best_err = INT32_MAX;
+
+ for (uint32_t j = 0; j < levels; j++)
+ {
+ int err = g_astc_sorted_order_unquant[range][j].m_unquant - i;
+ if (err < 0)
+ err = -err;
+ if (err < best_err)
+ {
+ best_err = err;
+ best_index = j;
+ }
+ }
+
+ g_astc_nearest_sorted_index[range][i] = (uint8_t)best_index;
+ } // i
+ } // range
+}
+
+static inline uint32_t astc_interpolate(uint32_t l, uint32_t h, uint32_t w)
+{
+ // This is for linear values, not sRGB.
+ l = (l << 8) | l;
+ h = (h << 8) | h;
+ uint32_t k = (l * (64 - w) + h * w + 32) >> 6;
+ return k >> 8;
+}
+
+// Initialize the lookup table used for optimal single color compression in mode 1. Must be called before encoding.
+void bc7enc_compress_block_init()
+{
+ astc_init();
+
+ // BC7 666.1
+ for (int c = 0; c < 256; c++)
+ {
+ for (uint32_t lp = 0; lp < 2; lp++)
+ {
+ endpoint_err best;
+ best.m_error = (uint16_t)UINT16_MAX;
+ for (uint32_t l = 0; l < 64; l++)
+ {
+ uint32_t low = ((l << 1) | lp) << 1;
+ low |= (low >> 7);
+ for (uint32_t h = 0; h < 64; h++)
+ {
+ uint32_t high = ((h << 1) | lp) << 1;
+ high |= (high >> 7);
+ const int k = (low * (64 - g_bc7_weights3[BC7ENC_MODE_1_OPTIMAL_INDEX]) + high * g_bc7_weights3[BC7ENC_MODE_1_OPTIMAL_INDEX] + 32) >> 6;
+ const int err = (k - c) * (k - c);
+ if (err < best.m_error)
+ {
+ best.m_error = (uint16_t)err;
+ best.m_lo = (uint8_t)l;
+ best.m_hi = (uint8_t)h;
+ }
+ } // h
+ } // l
+ g_bc7_mode_1_optimal_endpoints[c][lp] = best;
+ } // lp
+ } // c
+
+ // ASTC [0,15] 3-bit
+ for (int c = 0; c < 256; c++)
+ {
+ endpoint_err best;
+ best.m_error = (uint16_t)UINT16_MAX;
+ for (uint32_t l = 0; l < 16; l++)
+ {
+ uint32_t low = (l << 4) | l;
+
+ for (uint32_t h = 0; h < 16; h++)
+ {
+ uint32_t high = (h << 4) | h;
+
+ const int k = astc_interpolate(low, high, g_bc7_weights3[BC7ENC_ASTC_4BIT_3BIT_OPTIMAL_INDEX]);
+ const int err = (k - c) * (k - c);
+
+ if (err < best.m_error)
+ {
+ best.m_error = (uint16_t)err;
+ best.m_lo = (uint8_t)l;
+ best.m_hi = (uint8_t)h;
+ }
+ } // h
+ } // l
+
+ g_astc_4bit_3bit_optimal_endpoints[c] = best;
+
+ } // c
+
+ // ASTC [0,15] 2-bit
+ for (int c = 0; c < 256; c++)
+ {
+ endpoint_err best;
+ best.m_error = (uint16_t)UINT16_MAX;
+ for (uint32_t l = 0; l < 16; l++)
+ {
+ uint32_t low = (l << 4) | l;
+
+ for (uint32_t h = 0; h < 16; h++)
+ {
+ uint32_t high = (h << 4) | h;
+
+ const int k = astc_interpolate(low, high, g_bc7_weights2[BC7ENC_ASTC_4BIT_2BIT_OPTIMAL_INDEX]);
+ const int err = (k - c) * (k - c);
+
+ if (err < best.m_error)
+ {
+ best.m_error = (uint16_t)err;
+ best.m_lo = (uint8_t)l;
+ best.m_hi = (uint8_t)h;
+ }
+ } // h
+ } // l
+
+ g_astc_4bit_2bit_optimal_endpoints[c] = best;
+
+ } // c
+
+ // ASTC range 7 [0,11] 2-bit
+ for (int c = 0; c < 256; c++)
+ {
+ endpoint_err best;
+ best.m_error = (uint16_t)UINT16_MAX;
+ for (uint32_t l = 0; l < 12; l++)
+ {
+ uint32_t low = g_astc_sorted_order_unquant[7][l].m_unquant;
+
+ for (uint32_t h = 0; h < 12; h++)
+ {
+ uint32_t high = g_astc_sorted_order_unquant[7][h].m_unquant;
+
+ const int k = astc_interpolate(low, high, g_bc7_weights2[BC7ENC_ASTC_RANGE7_2BIT_OPTIMAL_INDEX]);
+ const int err = (k - c) * (k - c);
+
+ if (err < best.m_error)
+ {
+ best.m_error = (uint16_t)err;
+ best.m_lo = (uint8_t)l;
+ best.m_hi = (uint8_t)h;
+ }
+ } // h
+ } // l
+
+ g_astc_range7_2bit_optimal_endpoints[c] = best;
+
+ } // c
+
+ // ASTC range 13 [0,47] 4-bit
+ for (int c = 0; c < 256; c++)
+ {
+ endpoint_err best;
+ best.m_error = (uint16_t)UINT16_MAX;
+ for (uint32_t l = 0; l < 48; l++)
+ {
+ uint32_t low = g_astc_sorted_order_unquant[13][l].m_unquant;
+
+ for (uint32_t h = 0; h < 48; h++)
+ {
+ uint32_t high = g_astc_sorted_order_unquant[13][h].m_unquant;
+
+ const int k = astc_interpolate(low, high, g_astc_weights4[BC7ENC_ASTC_RANGE13_4BIT_OPTIMAL_INDEX]);
+ const int err = (k - c) * (k - c);
+
+ if (err < best.m_error)
+ {
+ best.m_error = (uint16_t)err;
+ best.m_lo = (uint8_t)l;
+ best.m_hi = (uint8_t)h;
+ }
+ } // h
+ } // l
+
+ g_astc_range13_4bit_optimal_endpoints[c] = best;
+
+ } // c
+
+ // ASTC range 13 [0,47] 2-bit
+ for (int c = 0; c < 256; c++)
+ {
+ endpoint_err best;
+ best.m_error = (uint16_t)UINT16_MAX;
+ for (uint32_t l = 0; l < 48; l++)
+ {
+ uint32_t low = g_astc_sorted_order_unquant[13][l].m_unquant;
+
+ for (uint32_t h = 0; h < 48; h++)
+ {
+ uint32_t high = g_astc_sorted_order_unquant[13][h].m_unquant;
+
+ const int k = astc_interpolate(low, high, g_bc7_weights2[BC7ENC_ASTC_RANGE13_2BIT_OPTIMAL_INDEX]);
+ const int err = (k - c) * (k - c);
+
+ if (err < best.m_error)
+ {
+ best.m_error = (uint16_t)err;
+ best.m_lo = (uint8_t)l;
+ best.m_hi = (uint8_t)h;
+ }
+ } // h
+ } // l
+
+ g_astc_range13_2bit_optimal_endpoints[c] = best;
+
+ } // c
+
+ // ASTC range 11 [0,31] 5-bit
+ for (int c = 0; c < 256; c++)
+ {
+ endpoint_err best;
+ best.m_error = (uint16_t)UINT16_MAX;
+ for (uint32_t l = 0; l < 32; l++)
+ {
+ uint32_t low = g_astc_sorted_order_unquant[11][l].m_unquant;
+
+ for (uint32_t h = 0; h < 32; h++)
+ {
+ uint32_t high = g_astc_sorted_order_unquant[11][h].m_unquant;
+
+ const int k = astc_interpolate(low, high, g_astc_weights5[BC7ENC_ASTC_RANGE11_5BIT_OPTIMAL_INDEX]);
+ const int err = (k - c) * (k - c);
+
+ if (err < best.m_error)
+ {
+ best.m_error = (uint16_t)err;
+ best.m_lo = (uint8_t)l;
+ best.m_hi = (uint8_t)h;
+ }
+ } // h
+ } // l
+
+ g_astc_range11_5bit_optimal_endpoints[c] = best;
+
+ } // c
+}
+
+static void compute_least_squares_endpoints_rgba(uint32_t N, const uint8_t *pSelectors, const bc7enc_vec4F* pSelector_weights, bc7enc_vec4F* pXl, bc7enc_vec4F* pXh, const color_quad_u8 *pColors)
+{
+ // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf
+ // I did this in matrix form first, expanded out all the ops, then optimized it a bit.
+ double z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f;
+ double q00_r = 0.0f, q10_r = 0.0f, t_r = 0.0f;
+ double q00_g = 0.0f, q10_g = 0.0f, t_g = 0.0f;
+ double q00_b = 0.0f, q10_b = 0.0f, t_b = 0.0f;
+ double q00_a = 0.0f, q10_a = 0.0f, t_a = 0.0f;
+
+ for (uint32_t i = 0; i < N; i++)
+ {
+ const uint32_t sel = pSelectors[i];
+ z00 += pSelector_weights[sel].m_c[0];
+ z10 += pSelector_weights[sel].m_c[1];
+ z11 += pSelector_weights[sel].m_c[2];
+ float w = pSelector_weights[sel].m_c[3];
+ q00_r += w * pColors[i].m_c[0]; t_r += pColors[i].m_c[0];
+ q00_g += w * pColors[i].m_c[1]; t_g += pColors[i].m_c[1];
+ q00_b += w * pColors[i].m_c[2]; t_b += pColors[i].m_c[2];
+ q00_a += w * pColors[i].m_c[3]; t_a += pColors[i].m_c[3];
+ }
+
+ q10_r = t_r - q00_r;
+ q10_g = t_g - q00_g;
+ q10_b = t_b - q00_b;
+ q10_a = t_a - q00_a;
+
+ z01 = z10;
+
+ double det = z00 * z11 - z01 * z10;
+ if (det != 0.0f)
+ det = 1.0f / det;
+
+ double iz00, iz01, iz10, iz11;
+ iz00 = z11 * det;
+ iz01 = -z01 * det;
+ iz10 = -z10 * det;
+ iz11 = z00 * det;
+
+ pXl->m_c[0] = (float)(iz00 * q00_r + iz01 * q10_r); pXh->m_c[0] = (float)(iz10 * q00_r + iz11 * q10_r);
+ pXl->m_c[1] = (float)(iz00 * q00_g + iz01 * q10_g); pXh->m_c[1] = (float)(iz10 * q00_g + iz11 * q10_g);
+ pXl->m_c[2] = (float)(iz00 * q00_b + iz01 * q10_b); pXh->m_c[2] = (float)(iz10 * q00_b + iz11 * q10_b);
+ pXl->m_c[3] = (float)(iz00 * q00_a + iz01 * q10_a); pXh->m_c[3] = (float)(iz10 * q00_a + iz11 * q10_a);
+
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ if ((pXl->m_c[c] < 0.0f) || (pXh->m_c[c] > 255.0f))
+ {
+ uint32_t lo_v = UINT32_MAX, hi_v = 0;
+ for (uint32_t i = 0; i < N; i++)
+ {
+ lo_v = minimumu(lo_v, pColors[i].m_c[c]);
+ hi_v = maximumu(hi_v, pColors[i].m_c[c]);
+ }
+
+ if (lo_v == hi_v)
+ {
+ pXl->m_c[c] = (float)lo_v;
+ pXh->m_c[c] = (float)hi_v;
+ }
+ }
+ }
+}
+
+static void compute_least_squares_endpoints_rgb(uint32_t N, const uint8_t *pSelectors, const bc7enc_vec4F*pSelector_weights, bc7enc_vec4F*pXl, bc7enc_vec4F*pXh, const color_quad_u8 *pColors)
+{
+ double z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f;
+ double q00_r = 0.0f, q10_r = 0.0f, t_r = 0.0f;
+ double q00_g = 0.0f, q10_g = 0.0f, t_g = 0.0f;
+ double q00_b = 0.0f, q10_b = 0.0f, t_b = 0.0f;
+
+ for (uint32_t i = 0; i < N; i++)
+ {
+ const uint32_t sel = pSelectors[i];
+ z00 += pSelector_weights[sel].m_c[0];
+ z10 += pSelector_weights[sel].m_c[1];
+ z11 += pSelector_weights[sel].m_c[2];
+ float w = pSelector_weights[sel].m_c[3];
+ q00_r += w * pColors[i].m_c[0]; t_r += pColors[i].m_c[0];
+ q00_g += w * pColors[i].m_c[1]; t_g += pColors[i].m_c[1];
+ q00_b += w * pColors[i].m_c[2]; t_b += pColors[i].m_c[2];
+ }
+
+ q10_r = t_r - q00_r;
+ q10_g = t_g - q00_g;
+ q10_b = t_b - q00_b;
+
+ z01 = z10;
+
+ double det = z00 * z11 - z01 * z10;
+ if (det != 0.0f)
+ det = 1.0f / det;
+
+ double iz00, iz01, iz10, iz11;
+ iz00 = z11 * det;
+ iz01 = -z01 * det;
+ iz10 = -z10 * det;
+ iz11 = z00 * det;
+
+ pXl->m_c[0] = (float)(iz00 * q00_r + iz01 * q10_r); pXh->m_c[0] = (float)(iz10 * q00_r + iz11 * q10_r);
+ pXl->m_c[1] = (float)(iz00 * q00_g + iz01 * q10_g); pXh->m_c[1] = (float)(iz10 * q00_g + iz11 * q10_g);
+ pXl->m_c[2] = (float)(iz00 * q00_b + iz01 * q10_b); pXh->m_c[2] = (float)(iz10 * q00_b + iz11 * q10_b);
+ pXl->m_c[3] = 255.0f; pXh->m_c[3] = 255.0f;
+
+ for (uint32_t c = 0; c < 3; c++)
+ {
+ if ((pXl->m_c[c] < 0.0f) || (pXh->m_c[c] > 255.0f))
+ {
+ uint32_t lo_v = UINT32_MAX, hi_v = 0;
+ for (uint32_t i = 0; i < N; i++)
+ {
+ lo_v = minimumu(lo_v, pColors[i].m_c[c]);
+ hi_v = maximumu(hi_v, pColors[i].m_c[c]);
+ }
+
+ if (lo_v == hi_v)
+ {
+ pXl->m_c[c] = (float)lo_v;
+ pXh->m_c[c] = (float)hi_v;
+ }
+ }
+ }
+}
+
+static inline color_quad_u8 scale_color(const color_quad_u8* pC, const color_cell_compressor_params* pParams)
+{
+ color_quad_u8 results;
+
+ if (pParams->m_astc_endpoint_range)
+ {
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ results.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pC->m_c[i]].m_unquant;
+ }
+ }
+ else
+ {
+ const uint32_t n = pParams->m_comp_bits + (pParams->m_has_pbits ? 1 : 0);
+ assert((n >= 4) && (n <= 8));
+
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ uint32_t v = pC->m_c[i] << (8 - n);
+ v |= (v >> n);
+ assert(v <= 255);
+ results.m_c[i] = (uint8_t)(v);
+ }
+ }
+
+ return results;
+}
+
+static inline uint64_t compute_color_distance_rgb(const color_quad_u8 *pE1, const color_quad_u8 *pE2, bc7enc_bool perceptual, const uint32_t weights[4])
+{
+ int dr, dg, db;
+
+ if (perceptual)
+ {
+ const int l1 = pE1->m_c[0] * 109 + pE1->m_c[1] * 366 + pE1->m_c[2] * 37;
+ const int cr1 = ((int)pE1->m_c[0] << 9) - l1;
+ const int cb1 = ((int)pE1->m_c[2] << 9) - l1;
+ const int l2 = pE2->m_c[0] * 109 + pE2->m_c[1] * 366 + pE2->m_c[2] * 37;
+ const int cr2 = ((int)pE2->m_c[0] << 9) - l2;
+ const int cb2 = ((int)pE2->m_c[2] << 9) - l2;
+ dr = (l1 - l2) >> 8;
+ dg = (cr1 - cr2) >> 8;
+ db = (cb1 - cb2) >> 8;
+ }
+ else
+ {
+ dr = (int)pE1->m_c[0] - (int)pE2->m_c[0];
+ dg = (int)pE1->m_c[1] - (int)pE2->m_c[1];
+ db = (int)pE1->m_c[2] - (int)pE2->m_c[2];
+ }
+
+ return weights[0] * (uint32_t)(dr * dr) + weights[1] * (uint32_t)(dg * dg) + weights[2] * (uint32_t)(db * db);
+}
+
+static inline uint64_t compute_color_distance_rgba(const color_quad_u8 *pE1, const color_quad_u8 *pE2, bc7enc_bool perceptual, const uint32_t weights[4])
+{
+ int da = (int)pE1->m_c[3] - (int)pE2->m_c[3];
+ return compute_color_distance_rgb(pE1, pE2, perceptual, weights) + (weights[3] * (uint32_t)(da * da));
+}
+
+static uint64_t pack_mode1_to_one_color(const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults, uint32_t r, uint32_t g, uint32_t b, uint8_t *pSelectors)
+{
+ uint32_t best_err = UINT_MAX;
+ uint32_t best_p = 0;
+
+ for (uint32_t p = 0; p < 2; p++)
+ {
+ uint32_t err = g_bc7_mode_1_optimal_endpoints[r][p].m_error + g_bc7_mode_1_optimal_endpoints[g][p].m_error + g_bc7_mode_1_optimal_endpoints[b][p].m_error;
+ if (err < best_err)
+ {
+ best_err = err;
+ best_p = p;
+ }
+ }
+
+ const endpoint_err *pEr = &g_bc7_mode_1_optimal_endpoints[r][best_p];
+ const endpoint_err *pEg = &g_bc7_mode_1_optimal_endpoints[g][best_p];
+ const endpoint_err *pEb = &g_bc7_mode_1_optimal_endpoints[b][best_p];
+
+ color_quad_u8_set(&pResults->m_low_endpoint, pEr->m_lo, pEg->m_lo, pEb->m_lo, 0);
+ color_quad_u8_set(&pResults->m_high_endpoint, pEr->m_hi, pEg->m_hi, pEb->m_hi, 0);
+ pResults->m_pbits[0] = best_p;
+ pResults->m_pbits[1] = 0;
+
+ memset(pSelectors, BC7ENC_MODE_1_OPTIMAL_INDEX, pParams->m_num_pixels);
+
+ color_quad_u8 p;
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ uint32_t low = ((pResults->m_low_endpoint.m_c[i] << 1) | pResults->m_pbits[0]) << 1;
+ low |= (low >> 7);
+
+ uint32_t high = ((pResults->m_high_endpoint.m_c[i] << 1) | pResults->m_pbits[0]) << 1;
+ high |= (high >> 7);
+
+ p.m_c[i] = (uint8_t)((low * (64 - g_bc7_weights3[BC7ENC_MODE_1_OPTIMAL_INDEX]) + high * g_bc7_weights3[BC7ENC_MODE_1_OPTIMAL_INDEX] + 32) >> 6);
+ }
+ p.m_c[3] = 255;
+
+ uint64_t total_err = 0;
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ total_err += compute_color_distance_rgb(&p, &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights);
+
+ pResults->m_best_overall_err = total_err;
+
+ return total_err;
+}
+
+static uint64_t pack_astc_4bit_3bit_to_one_color(const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults, uint32_t r, uint32_t g, uint32_t b, uint8_t *pSelectors)
+{
+ const endpoint_err *pEr = &g_astc_4bit_3bit_optimal_endpoints[r];
+ const endpoint_err *pEg = &g_astc_4bit_3bit_optimal_endpoints[g];
+ const endpoint_err *pEb = &g_astc_4bit_3bit_optimal_endpoints[b];
+
+ color_quad_u8_set(&pResults->m_low_endpoint, pEr->m_lo, pEg->m_lo, pEb->m_lo, 0);
+ color_quad_u8_set(&pResults->m_high_endpoint, pEr->m_hi, pEg->m_hi, pEb->m_hi, 0);
+ pResults->m_pbits[0] = 0;
+ pResults->m_pbits[1] = 0;
+
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ pResults->m_astc_low_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_low_endpoint.m_c[i]].m_index;
+ pResults->m_astc_high_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_high_endpoint.m_c[i]].m_index;
+ }
+
+ memset(pSelectors, BC7ENC_ASTC_4BIT_3BIT_OPTIMAL_INDEX, pParams->m_num_pixels);
+
+ color_quad_u8 p;
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ uint32_t low = (pResults->m_low_endpoint.m_c[i] << 4) | pResults->m_low_endpoint.m_c[i];
+ uint32_t high = (pResults->m_high_endpoint.m_c[i] << 4) | pResults->m_high_endpoint.m_c[i];
+
+ p.m_c[i] = (uint8_t)astc_interpolate(low, high, g_bc7_weights3[BC7ENC_ASTC_4BIT_3BIT_OPTIMAL_INDEX]);
+ }
+ p.m_c[3] = 255;
+
+ uint64_t total_err = 0;
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ total_err += compute_color_distance_rgb(&p, &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights);
+
+ pResults->m_best_overall_err = total_err;
+
+ return total_err;
+}
+
+static uint64_t pack_astc_4bit_2bit_to_one_color_rgba(const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults, uint32_t r, uint32_t g, uint32_t b, uint32_t a, uint8_t *pSelectors)
+{
+ const endpoint_err *pEr = &g_astc_4bit_2bit_optimal_endpoints[r];
+ const endpoint_err *pEg = &g_astc_4bit_2bit_optimal_endpoints[g];
+ const endpoint_err *pEb = &g_astc_4bit_2bit_optimal_endpoints[b];
+ const endpoint_err *pEa = &g_astc_4bit_2bit_optimal_endpoints[a];
+
+ color_quad_u8_set(&pResults->m_low_endpoint, pEr->m_lo, pEg->m_lo, pEb->m_lo, pEa->m_lo);
+ color_quad_u8_set(&pResults->m_high_endpoint, pEr->m_hi, pEg->m_hi, pEb->m_hi, pEa->m_hi);
+ pResults->m_pbits[0] = 0;
+ pResults->m_pbits[1] = 0;
+
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ pResults->m_astc_low_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_low_endpoint.m_c[i]].m_index;
+ pResults->m_astc_high_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_high_endpoint.m_c[i]].m_index;
+ }
+
+ memset(pSelectors, BC7ENC_ASTC_4BIT_2BIT_OPTIMAL_INDEX, pParams->m_num_pixels);
+
+ color_quad_u8 p;
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ uint32_t low = (pResults->m_low_endpoint.m_c[i] << 4) | pResults->m_low_endpoint.m_c[i];
+ uint32_t high = (pResults->m_high_endpoint.m_c[i] << 4) | pResults->m_high_endpoint.m_c[i];
+
+ p.m_c[i] = (uint8_t)astc_interpolate(low, high, g_bc7_weights2[BC7ENC_ASTC_4BIT_2BIT_OPTIMAL_INDEX]);
+ }
+
+ uint64_t total_err = 0;
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ total_err += compute_color_distance_rgba(&p, &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights);
+
+ pResults->m_best_overall_err = total_err;
+
+ return total_err;
+}
+
+static uint64_t pack_astc_range7_2bit_to_one_color(const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults, uint32_t r, uint32_t g, uint32_t b, uint8_t *pSelectors)
+{
+ assert(pParams->m_astc_endpoint_range == 7 && pParams->m_num_selector_weights == 4);
+
+ const endpoint_err *pEr = &g_astc_range7_2bit_optimal_endpoints[r];
+ const endpoint_err *pEg = &g_astc_range7_2bit_optimal_endpoints[g];
+ const endpoint_err *pEb = &g_astc_range7_2bit_optimal_endpoints[b];
+
+ color_quad_u8_set(&pResults->m_low_endpoint, pEr->m_lo, pEg->m_lo, pEb->m_lo, 0);
+ color_quad_u8_set(&pResults->m_high_endpoint, pEr->m_hi, pEg->m_hi, pEb->m_hi, 0);
+ pResults->m_pbits[0] = 0;
+ pResults->m_pbits[1] = 0;
+
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ pResults->m_astc_low_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_low_endpoint.m_c[i]].m_index;
+ pResults->m_astc_high_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_high_endpoint.m_c[i]].m_index;
+ }
+
+ memset(pSelectors, BC7ENC_ASTC_RANGE7_2BIT_OPTIMAL_INDEX, pParams->m_num_pixels);
+
+ color_quad_u8 p;
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ uint32_t low = g_astc_sorted_order_unquant[7][pResults->m_low_endpoint.m_c[i]].m_unquant;
+ uint32_t high = g_astc_sorted_order_unquant[7][pResults->m_high_endpoint.m_c[i]].m_unquant;
+
+ p.m_c[i] = (uint8_t)astc_interpolate(low, high, g_bc7_weights2[BC7ENC_ASTC_RANGE7_2BIT_OPTIMAL_INDEX]);
+ }
+ p.m_c[3] = 255;
+
+ uint64_t total_err = 0;
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ total_err += compute_color_distance_rgb(&p, &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights);
+
+ pResults->m_best_overall_err = total_err;
+
+ return total_err;
+}
+
+static uint64_t pack_astc_range13_2bit_to_one_color(const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults, uint32_t r, uint32_t g, uint32_t b, uint8_t *pSelectors)
+{
+ assert(pParams->m_astc_endpoint_range == 13 && pParams->m_num_selector_weights == 4 && !pParams->m_has_alpha);
+
+ const endpoint_err *pEr = &g_astc_range13_2bit_optimal_endpoints[r];
+ const endpoint_err *pEg = &g_astc_range13_2bit_optimal_endpoints[g];
+ const endpoint_err *pEb = &g_astc_range13_2bit_optimal_endpoints[b];
+
+ color_quad_u8_set(&pResults->m_low_endpoint, pEr->m_lo, pEg->m_lo, pEb->m_lo, 47);
+ color_quad_u8_set(&pResults->m_high_endpoint, pEr->m_hi, pEg->m_hi, pEb->m_hi, 47);
+ pResults->m_pbits[0] = 0;
+ pResults->m_pbits[1] = 0;
+
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ pResults->m_astc_low_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_low_endpoint.m_c[i]].m_index;
+ pResults->m_astc_high_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_high_endpoint.m_c[i]].m_index;
+ }
+
+ memset(pSelectors, BC7ENC_ASTC_RANGE13_2BIT_OPTIMAL_INDEX, pParams->m_num_pixels);
+
+ color_quad_u8 p;
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ uint32_t low = g_astc_sorted_order_unquant[13][pResults->m_low_endpoint.m_c[i]].m_unquant;
+ uint32_t high = g_astc_sorted_order_unquant[13][pResults->m_high_endpoint.m_c[i]].m_unquant;
+
+ p.m_c[i] = (uint8_t)astc_interpolate(low, high, g_bc7_weights2[BC7ENC_ASTC_RANGE13_2BIT_OPTIMAL_INDEX]);
+ }
+
+ uint64_t total_err = 0;
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ total_err += compute_color_distance_rgb(&p, &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights);
+
+ pResults->m_best_overall_err = total_err;
+
+ return total_err;
+}
+
+static uint64_t pack_astc_range11_5bit_to_one_color(const color_cell_compressor_params* pParams, color_cell_compressor_results* pResults, uint32_t r, uint32_t g, uint32_t b, uint8_t* pSelectors)
+{
+ assert(pParams->m_astc_endpoint_range == 11 && pParams->m_num_selector_weights == 32 && !pParams->m_has_alpha);
+
+ const endpoint_err* pEr = &g_astc_range11_5bit_optimal_endpoints[r];
+ const endpoint_err* pEg = &g_astc_range11_5bit_optimal_endpoints[g];
+ const endpoint_err* pEb = &g_astc_range11_5bit_optimal_endpoints[b];
+
+ color_quad_u8_set(&pResults->m_low_endpoint, pEr->m_lo, pEg->m_lo, pEb->m_lo, 31);
+ color_quad_u8_set(&pResults->m_high_endpoint, pEr->m_hi, pEg->m_hi, pEb->m_hi, 31);
+ pResults->m_pbits[0] = 0;
+ pResults->m_pbits[1] = 0;
+
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ pResults->m_astc_low_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_low_endpoint.m_c[i]].m_index;
+ pResults->m_astc_high_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_high_endpoint.m_c[i]].m_index;
+ }
+
+ memset(pSelectors, BC7ENC_ASTC_RANGE11_5BIT_OPTIMAL_INDEX, pParams->m_num_pixels);
+
+ color_quad_u8 p;
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ uint32_t low = g_astc_sorted_order_unquant[11][pResults->m_low_endpoint.m_c[i]].m_unquant;
+ uint32_t high = g_astc_sorted_order_unquant[11][pResults->m_high_endpoint.m_c[i]].m_unquant;
+
+ p.m_c[i] = (uint8_t)astc_interpolate(low, high, g_astc_weights5[BC7ENC_ASTC_RANGE11_5BIT_OPTIMAL_INDEX]);
+ }
+
+ uint64_t total_err = 0;
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ total_err += compute_color_distance_rgb(&p, &pParams->m_pPixels[i], pParams->m_perceptual, pParams->m_weights);
+
+ pResults->m_best_overall_err = total_err;
+
+ return total_err;
+}
+
+static uint64_t evaluate_solution(const color_quad_u8 *pLow, const color_quad_u8 *pHigh, const uint32_t pbits[2], const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults)
+{
+ color_quad_u8 quantMinColor = *pLow;
+ color_quad_u8 quantMaxColor = *pHigh;
+
+ if (pParams->m_has_pbits)
+ {
+ uint32_t minPBit, maxPBit;
+
+ if (pParams->m_endpoints_share_pbit)
+ maxPBit = minPBit = pbits[0];
+ else
+ {
+ minPBit = pbits[0];
+ maxPBit = pbits[1];
+ }
+
+ quantMinColor.m_c[0] = (uint8_t)((pLow->m_c[0] << 1) | minPBit);
+ quantMinColor.m_c[1] = (uint8_t)((pLow->m_c[1] << 1) | minPBit);
+ quantMinColor.m_c[2] = (uint8_t)((pLow->m_c[2] << 1) | minPBit);
+ quantMinColor.m_c[3] = (uint8_t)((pLow->m_c[3] << 1) | minPBit);
+
+ quantMaxColor.m_c[0] = (uint8_t)((pHigh->m_c[0] << 1) | maxPBit);
+ quantMaxColor.m_c[1] = (uint8_t)((pHigh->m_c[1] << 1) | maxPBit);
+ quantMaxColor.m_c[2] = (uint8_t)((pHigh->m_c[2] << 1) | maxPBit);
+ quantMaxColor.m_c[3] = (uint8_t)((pHigh->m_c[3] << 1) | maxPBit);
+ }
+
+ color_quad_u8 actualMinColor = scale_color(&quantMinColor, pParams);
+ color_quad_u8 actualMaxColor = scale_color(&quantMaxColor, pParams);
+
+ const uint32_t N = pParams->m_num_selector_weights;
+ assert(N >= 1 && N <= 32);
+
+ color_quad_u8 weightedColors[32];
+ weightedColors[0] = actualMinColor;
+ weightedColors[N - 1] = actualMaxColor;
+
+ const uint32_t nc = pParams->m_has_alpha ? 4 : 3;
+ if (pParams->m_astc_endpoint_range)
+ {
+ for (uint32_t i = 1; i < (N - 1); i++)
+ {
+ for (uint32_t j = 0; j < nc; j++)
+ weightedColors[i].m_c[j] = (uint8_t)(astc_interpolate(actualMinColor.m_c[j], actualMaxColor.m_c[j], pParams->m_pSelector_weights[i]));
+ }
+ }
+ else
+ {
+ for (uint32_t i = 1; i < (N - 1); i++)
+ for (uint32_t j = 0; j < nc; j++)
+ weightedColors[i].m_c[j] = (uint8_t)((actualMinColor.m_c[j] * (64 - pParams->m_pSelector_weights[i]) + actualMaxColor.m_c[j] * pParams->m_pSelector_weights[i] + 32) >> 6);
+ }
+
+ const int lr = actualMinColor.m_c[0];
+ const int lg = actualMinColor.m_c[1];
+ const int lb = actualMinColor.m_c[2];
+ const int dr = actualMaxColor.m_c[0] - lr;
+ const int dg = actualMaxColor.m_c[1] - lg;
+ const int db = actualMaxColor.m_c[2] - lb;
+
+ uint64_t total_err = 0;
+
+ if (pParams->m_pForce_selectors)
+ {
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ const color_quad_u8* pC = &pParams->m_pPixels[i];
+
+ const uint8_t sel = pParams->m_pForce_selectors[i];
+ assert(sel < N);
+
+ total_err += (pParams->m_has_alpha ? compute_color_distance_rgba : compute_color_distance_rgb)(&weightedColors[sel], pC, pParams->m_perceptual, pParams->m_weights);
+
+ pResults->m_pSelectors_temp[i] = sel;
+ }
+ }
+ else if (!pParams->m_perceptual)
+ {
+ if (pParams->m_has_alpha)
+ {
+ const int la = actualMinColor.m_c[3];
+ const int da = actualMaxColor.m_c[3] - la;
+
+ const float f = N / (float)(squarei(dr) + squarei(dg) + squarei(db) + squarei(da) + .00000125f);
+
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ const color_quad_u8 *pC = &pParams->m_pPixels[i];
+ int r = pC->m_c[0];
+ int g = pC->m_c[1];
+ int b = pC->m_c[2];
+ int a = pC->m_c[3];
+
+ int best_sel = (int)((float)((r - lr) * dr + (g - lg) * dg + (b - lb) * db + (a - la) * da) * f + .5f);
+ best_sel = clampi(best_sel, 1, N - 1);
+
+ uint64_t err0 = compute_color_distance_rgba(&weightedColors[best_sel - 1], pC, BC7ENC_FALSE, pParams->m_weights);
+ uint64_t err1 = compute_color_distance_rgba(&weightedColors[best_sel], pC, BC7ENC_FALSE, pParams->m_weights);
+
+ if (err0 == err1)
+ {
+ // Prefer non-interpolation
+ if ((best_sel - 1) == 0)
+ best_sel = 0;
+ }
+ else if (err1 > err0)
+ {
+ err1 = err0;
+ --best_sel;
+ }
+ total_err += err1;
+
+ pResults->m_pSelectors_temp[i] = (uint8_t)best_sel;
+ }
+ }
+ else
+ {
+ const float f = N / (float)(squarei(dr) + squarei(dg) + squarei(db) + .00000125f);
+
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ const color_quad_u8 *pC = &pParams->m_pPixels[i];
+ int r = pC->m_c[0];
+ int g = pC->m_c[1];
+ int b = pC->m_c[2];
+
+ int sel = (int)((float)((r - lr) * dr + (g - lg) * dg + (b - lb) * db) * f + .5f);
+ sel = clampi(sel, 1, N - 1);
+
+ uint64_t err0 = compute_color_distance_rgb(&weightedColors[sel - 1], pC, BC7ENC_FALSE, pParams->m_weights);
+ uint64_t err1 = compute_color_distance_rgb(&weightedColors[sel], pC, BC7ENC_FALSE, pParams->m_weights);
+
+ int best_sel = sel;
+ uint64_t best_err = err1;
+ if (err0 == err1)
+ {
+ // Prefer non-interpolation
+ if ((best_sel - 1) == 0)
+ best_sel = 0;
+ }
+ else if (err0 < best_err)
+ {
+ best_err = err0;
+ best_sel = sel - 1;
+ }
+
+ total_err += best_err;
+
+ pResults->m_pSelectors_temp[i] = (uint8_t)best_sel;
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ uint64_t best_err = UINT64_MAX;
+ uint32_t best_sel = 0;
+
+ if (pParams->m_has_alpha)
+ {
+ for (uint32_t j = 0; j < N; j++)
+ {
+ uint64_t err = compute_color_distance_rgba(&weightedColors[j], &pParams->m_pPixels[i], BC7ENC_TRUE, pParams->m_weights);
+ if (err < best_err)
+ {
+ best_err = err;
+ best_sel = j;
+ }
+ // Prefer non-interpolation
+ else if ((err == best_err) && (j == (N - 1)))
+ best_sel = j;
+ }
+ }
+ else
+ {
+ for (uint32_t j = 0; j < N; j++)
+ {
+ uint64_t err = compute_color_distance_rgb(&weightedColors[j], &pParams->m_pPixels[i], BC7ENC_TRUE, pParams->m_weights);
+ if (err < best_err)
+ {
+ best_err = err;
+ best_sel = j;
+ }
+ // Prefer non-interpolation
+ else if ((err == best_err) && (j == (N - 1)))
+ best_sel = j;
+ }
+ }
+
+ total_err += best_err;
+
+ pResults->m_pSelectors_temp[i] = (uint8_t)best_sel;
+ }
+ }
+
+ if (total_err < pResults->m_best_overall_err)
+ {
+ pResults->m_best_overall_err = total_err;
+
+ pResults->m_low_endpoint = *pLow;
+ pResults->m_high_endpoint = *pHigh;
+
+ pResults->m_pbits[0] = pbits[0];
+ pResults->m_pbits[1] = pbits[1];
+
+ memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels);
+ }
+
+ return total_err;
+}
+
+static bool areDegenerateEndpoints(color_quad_u8* pTrialMinColor, color_quad_u8* pTrialMaxColor, const bc7enc_vec4F* pXl, const bc7enc_vec4F* pXh)
+{
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ if (pTrialMinColor->m_c[i] == pTrialMaxColor->m_c[i])
+ {
+ if (fabs(pXl->m_c[i] - pXh->m_c[i]) > 0.0f)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void fixDegenerateEndpoints(uint32_t mode, color_quad_u8 *pTrialMinColor, color_quad_u8 *pTrialMaxColor, const bc7enc_vec4F*pXl, const bc7enc_vec4F*pXh, uint32_t iscale, int flags)
+{
+ if (mode == 255)
+ {
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ if (pTrialMinColor->m_c[i] == pTrialMaxColor->m_c[i])
+ {
+ if (fabs(pXl->m_c[i] - pXh->m_c[i]) > 0.000125f)
+ {
+ if (flags & 1)
+ {
+ if (pTrialMinColor->m_c[i] > 0)
+ pTrialMinColor->m_c[i]--;
+ }
+ if (flags & 2)
+ {
+ if (pTrialMaxColor->m_c[i] < iscale)
+ pTrialMaxColor->m_c[i]++;
+ }
+ }
+ }
+ }
+ }
+ else if (mode == 1)
+ {
+ // fix degenerate case where the input collapses to a single colorspace voxel, and we loose all freedom (test with grayscale ramps)
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ if (pTrialMinColor->m_c[i] == pTrialMaxColor->m_c[i])
+ {
+ if (fabs(pXl->m_c[i] - pXh->m_c[i]) > 0.000125f)
+ {
+ if (pTrialMinColor->m_c[i] > (iscale >> 1))
+ {
+ if (pTrialMinColor->m_c[i] > 0)
+ pTrialMinColor->m_c[i]--;
+ else
+ if (pTrialMaxColor->m_c[i] < iscale)
+ pTrialMaxColor->m_c[i]++;
+ }
+ else
+ {
+ if (pTrialMaxColor->m_c[i] < iscale)
+ pTrialMaxColor->m_c[i]++;
+ else if (pTrialMinColor->m_c[i] > 0)
+ pTrialMinColor->m_c[i]--;
+ }
+ }
+ }
+ }
+ }
+}
+
+static uint64_t find_optimal_solution(uint32_t mode, bc7enc_vec4F xl, bc7enc_vec4F xh, const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults)
+{
+ vec4F_saturate_in_place(&xl); vec4F_saturate_in_place(&xh);
+
+ if (pParams->m_astc_endpoint_range)
+ {
+ const uint32_t levels = astc_get_levels(pParams->m_astc_endpoint_range);
+
+ const float scale = 255.0f;
+
+ color_quad_u8 trialMinColor8Bit, trialMaxColor8Bit;
+ color_quad_u8_set_clamped(&trialMinColor8Bit, (int)(xl.m_c[0] * scale + .5f), (int)(xl.m_c[1] * scale + .5f), (int)(xl.m_c[2] * scale + .5f), (int)(xl.m_c[3] * scale + .5f));
+ color_quad_u8_set_clamped(&trialMaxColor8Bit, (int)(xh.m_c[0] * scale + .5f), (int)(xh.m_c[1] * scale + .5f), (int)(xh.m_c[2] * scale + .5f), (int)(xh.m_c[3] * scale + .5f));
+
+ color_quad_u8 trialMinColor, trialMaxColor;
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ trialMinColor.m_c[i] = g_astc_nearest_sorted_index[pParams->m_astc_endpoint_range][trialMinColor8Bit.m_c[i]];
+ trialMaxColor.m_c[i] = g_astc_nearest_sorted_index[pParams->m_astc_endpoint_range][trialMaxColor8Bit.m_c[i]];
+ }
+
+ if (areDegenerateEndpoints(&trialMinColor, &trialMaxColor, &xl, &xh))
+ {
+ color_quad_u8 trialMinColorOrig(trialMinColor), trialMaxColorOrig(trialMaxColor);
+
+ fixDegenerateEndpoints(mode, &trialMinColor, &trialMaxColor, &xl, &xh, levels - 1, 1);
+ if ((pResults->m_best_overall_err == UINT64_MAX) || color_quad_u8_notequals(&trialMinColor, &pResults->m_low_endpoint) || color_quad_u8_notequals(&trialMaxColor, &pResults->m_high_endpoint))
+ evaluate_solution(&trialMinColor, &trialMaxColor, pResults->m_pbits, pParams, pResults);
+
+ trialMinColor = trialMinColorOrig;
+ trialMaxColor = trialMaxColorOrig;
+ fixDegenerateEndpoints(mode, &trialMinColor, &trialMaxColor, &xl, &xh, levels - 1, 0);
+ if ((pResults->m_best_overall_err == UINT64_MAX) || color_quad_u8_notequals(&trialMinColor, &pResults->m_low_endpoint) || color_quad_u8_notequals(&trialMaxColor, &pResults->m_high_endpoint))
+ evaluate_solution(&trialMinColor, &trialMaxColor, pResults->m_pbits, pParams, pResults);
+
+ trialMinColor = trialMinColorOrig;
+ trialMaxColor = trialMaxColorOrig;
+ fixDegenerateEndpoints(mode, &trialMinColor, &trialMaxColor, &xl, &xh, levels - 1, 2);
+ if ((pResults->m_best_overall_err == UINT64_MAX) || color_quad_u8_notequals(&trialMinColor, &pResults->m_low_endpoint) || color_quad_u8_notequals(&trialMaxColor, &pResults->m_high_endpoint))
+ evaluate_solution(&trialMinColor, &trialMaxColor, pResults->m_pbits, pParams, pResults);
+
+ trialMinColor = trialMinColorOrig;
+ trialMaxColor = trialMaxColorOrig;
+ fixDegenerateEndpoints(mode, &trialMinColor, &trialMaxColor, &xl, &xh, levels - 1, 3);
+ if ((pResults->m_best_overall_err == UINT64_MAX) || color_quad_u8_notequals(&trialMinColor, &pResults->m_low_endpoint) || color_quad_u8_notequals(&trialMaxColor, &pResults->m_high_endpoint))
+ evaluate_solution(&trialMinColor, &trialMaxColor, pResults->m_pbits, pParams, pResults);
+ }
+ else
+ {
+ if ((pResults->m_best_overall_err == UINT64_MAX) || color_quad_u8_notequals(&trialMinColor, &pResults->m_low_endpoint) || color_quad_u8_notequals(&trialMaxColor, &pResults->m_high_endpoint))
+ {
+ evaluate_solution(&trialMinColor, &trialMaxColor, pResults->m_pbits, pParams, pResults);
+ }
+ }
+
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ pResults->m_astc_low_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_low_endpoint.m_c[i]].m_index;
+ pResults->m_astc_high_endpoint.m_c[i] = g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_high_endpoint.m_c[i]].m_index;
+ }
+ }
+ else if (pParams->m_has_pbits)
+ {
+ const int iscalep = (1 << (pParams->m_comp_bits + 1)) - 1;
+ const float scalep = (float)iscalep;
+
+ const int32_t totalComps = pParams->m_has_alpha ? 4 : 3;
+
+ uint32_t best_pbits[2];
+ color_quad_u8 bestMinColor, bestMaxColor;
+
+ if (!pParams->m_endpoints_share_pbit)
+ {
+ float best_err0 = 1e+9;
+ float best_err1 = 1e+9;
+
+ for (int p = 0; p < 2; p++)
+ {
+ color_quad_u8 xMinColor, xMaxColor;
+
+ // Notes: The pbit controls which quantization intervals are selected.
+ // total_levels=2^(comp_bits+1), where comp_bits=4 for mode 0, etc.
+ // pbit 0: v=(b*2)/(total_levels-1), pbit 1: v=(b*2+1)/(total_levels-1) where b is the component bin from [0,total_levels/2-1] and v is the [0,1] component value
+ // rearranging you get for pbit 0: b=floor(v*(total_levels-1)/2+.5)
+ // rearranging you get for pbit 1: b=floor((v*(total_levels-1)-1)/2+.5)
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ xMinColor.m_c[c] = (uint8_t)(clampi(((int)((xl.m_c[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));
+ xMaxColor.m_c[c] = (uint8_t)(clampi(((int)((xh.m_c[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));
+ }
+
+ color_quad_u8 scaledLow = scale_color(&xMinColor, pParams);
+ color_quad_u8 scaledHigh = scale_color(&xMaxColor, pParams);
+
+ float err0 = 0, err1 = 0;
+ for (int i = 0; i < totalComps; i++)
+ {
+ err0 += squaref(scaledLow.m_c[i] - xl.m_c[i] * 255.0f);
+ err1 += squaref(scaledHigh.m_c[i] - xh.m_c[i] * 255.0f);
+ }
+
+ if (err0 < best_err0)
+ {
+ best_err0 = err0;
+ best_pbits[0] = p;
+
+ bestMinColor.m_c[0] = xMinColor.m_c[0] >> 1;
+ bestMinColor.m_c[1] = xMinColor.m_c[1] >> 1;
+ bestMinColor.m_c[2] = xMinColor.m_c[2] >> 1;
+ bestMinColor.m_c[3] = xMinColor.m_c[3] >> 1;
+ }
+
+ if (err1 < best_err1)
+ {
+ best_err1 = err1;
+ best_pbits[1] = p;
+
+ bestMaxColor.m_c[0] = xMaxColor.m_c[0] >> 1;
+ bestMaxColor.m_c[1] = xMaxColor.m_c[1] >> 1;
+ bestMaxColor.m_c[2] = xMaxColor.m_c[2] >> 1;
+ bestMaxColor.m_c[3] = xMaxColor.m_c[3] >> 1;
+ }
+ }
+ }
+ else
+ {
+ // Endpoints share pbits
+ float best_err = 1e+9;
+
+ for (int p = 0; p < 2; p++)
+ {
+ color_quad_u8 xMinColor, xMaxColor;
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ xMinColor.m_c[c] = (uint8_t)(clampi(((int)((xl.m_c[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));
+ xMaxColor.m_c[c] = (uint8_t)(clampi(((int)((xh.m_c[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));
+ }
+
+ color_quad_u8 scaledLow = scale_color(&xMinColor, pParams);
+ color_quad_u8 scaledHigh = scale_color(&xMaxColor, pParams);
+
+ float err = 0;
+ for (int i = 0; i < totalComps; i++)
+ err += squaref((scaledLow.m_c[i] / 255.0f) - xl.m_c[i]) + squaref((scaledHigh.m_c[i] / 255.0f) - xh.m_c[i]);
+
+ if (err < best_err)
+ {
+ best_err = err;
+ best_pbits[0] = p;
+ best_pbits[1] = p;
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ bestMinColor.m_c[j] = xMinColor.m_c[j] >> 1;
+ bestMaxColor.m_c[j] = xMaxColor.m_c[j] >> 1;
+ }
+ }
+ }
+ }
+
+ fixDegenerateEndpoints(mode, &bestMinColor, &bestMaxColor, &xl, &xh, iscalep >> 1, 0);
+
+ if ((pResults->m_best_overall_err == UINT64_MAX) || color_quad_u8_notequals(&bestMinColor, &pResults->m_low_endpoint) || color_quad_u8_notequals(&bestMaxColor, &pResults->m_high_endpoint) || (best_pbits[0] != pResults->m_pbits[0]) || (best_pbits[1] != pResults->m_pbits[1]))
+ evaluate_solution(&bestMinColor, &bestMaxColor, best_pbits, pParams, pResults);
+ }
+ else
+ {
+ const int iscale = (1 << pParams->m_comp_bits) - 1;
+ const float scale = (float)iscale;
+
+ color_quad_u8 trialMinColor, trialMaxColor;
+ color_quad_u8_set_clamped(&trialMinColor, (int)(xl.m_c[0] * scale + .5f), (int)(xl.m_c[1] * scale + .5f), (int)(xl.m_c[2] * scale + .5f), (int)(xl.m_c[3] * scale + .5f));
+ color_quad_u8_set_clamped(&trialMaxColor, (int)(xh.m_c[0] * scale + .5f), (int)(xh.m_c[1] * scale + .5f), (int)(xh.m_c[2] * scale + .5f), (int)(xh.m_c[3] * scale + .5f));
+
+ fixDegenerateEndpoints(mode, &trialMinColor, &trialMaxColor, &xl, &xh, iscale, 0);
+
+ if ((pResults->m_best_overall_err == UINT64_MAX) || color_quad_u8_notequals(&trialMinColor, &pResults->m_low_endpoint) || color_quad_u8_notequals(&trialMaxColor, &pResults->m_high_endpoint))
+ evaluate_solution(&trialMinColor, &trialMaxColor, pResults->m_pbits, pParams, pResults);
+ }
+
+ return pResults->m_best_overall_err;
+}
+
+void check_best_overall_error(const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults)
+{
+ const uint32_t n = pParams->m_num_selector_weights;
+
+ assert(n <= 32);
+
+ color_quad_u8 colors[32];
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ colors[0].m_c[c] = g_astc_unquant[pParams->m_astc_endpoint_range][pResults->m_astc_low_endpoint.m_c[c]].m_unquant;
+ assert(colors[0].m_c[c] == g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_low_endpoint.m_c[c]].m_unquant);
+
+ colors[n-1].m_c[c] = g_astc_unquant[pParams->m_astc_endpoint_range][pResults->m_astc_high_endpoint.m_c[c]].m_unquant;
+ assert(colors[n-1].m_c[c] == g_astc_sorted_order_unquant[pParams->m_astc_endpoint_range][pResults->m_high_endpoint.m_c[c]].m_unquant);
+ }
+
+ for (uint32_t i = 1; i < pParams->m_num_selector_weights - 1; i++)
+ for (uint32_t c = 0; c < 4; c++)
+ colors[i].m_c[c] = (uint8_t)astc_interpolate(colors[0].m_c[c], colors[n - 1].m_c[c], pParams->m_pSelector_weights[i]);
+
+ uint64_t total_err = 0;
+ for (uint32_t p = 0; p < pParams->m_num_pixels; p++)
+ {
+ const color_quad_u8 &orig = pParams->m_pPixels[p];
+ const color_quad_u8 &packed = colors[pResults->m_pSelectors[p]];
+
+ if (pParams->m_has_alpha)
+ total_err += compute_color_distance_rgba(&orig, &packed, pParams->m_perceptual, pParams->m_weights);
+ else
+ total_err += compute_color_distance_rgb(&orig, &packed, pParams->m_perceptual, pParams->m_weights);
+ }
+ assert(total_err == pResults->m_best_overall_err);
+
+ // HACK HACK
+ //if (total_err != pResults->m_best_overall_err)
+ // printf("X");
+}
+
+static bool is_solid_rgb(const color_cell_compressor_params *pParams, uint32_t &r, uint32_t &g, uint32_t &b)
+{
+ r = pParams->m_pPixels[0].m_c[0];
+ g = pParams->m_pPixels[0].m_c[1];
+ b = pParams->m_pPixels[0].m_c[2];
+
+ bool allSame = true;
+ for (uint32_t i = 1; i < pParams->m_num_pixels; i++)
+ {
+ if ((r != pParams->m_pPixels[i].m_c[0]) || (g != pParams->m_pPixels[i].m_c[1]) || (b != pParams->m_pPixels[i].m_c[2]))
+ {
+ allSame = false;
+ break;
+ }
+ }
+
+ return allSame;
+}
+
+static bool is_solid_rgba(const color_cell_compressor_params *pParams, uint32_t &r, uint32_t &g, uint32_t &b, uint32_t &a)
+{
+ r = pParams->m_pPixels[0].m_c[0];
+ g = pParams->m_pPixels[0].m_c[1];
+ b = pParams->m_pPixels[0].m_c[2];
+ a = pParams->m_pPixels[0].m_c[3];
+
+ bool allSame = true;
+ for (uint32_t i = 1; i < pParams->m_num_pixels; i++)
+ {
+ if ((r != pParams->m_pPixels[i].m_c[0]) || (g != pParams->m_pPixels[i].m_c[1]) || (b != pParams->m_pPixels[i].m_c[2]) || (a != pParams->m_pPixels[i].m_c[3]))
+ {
+ allSame = false;
+ break;
+ }
+ }
+
+ return allSame;
+}
+
+uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_params *pParams, color_cell_compressor_results *pResults, const bc7enc_compress_block_params *pComp_params)
+{
+ if (!pParams->m_astc_endpoint_range)
+ {
+ assert((mode == 6) || (!pParams->m_has_alpha));
+ }
+ assert(pParams->m_num_selector_weights >= 1 && pParams->m_num_selector_weights <= 32);
+ assert(pParams->m_pSelector_weights[0] == 0);
+ assert(pParams->m_pSelector_weights[pParams->m_num_selector_weights - 1] == 64);
+
+ pResults->m_best_overall_err = UINT64_MAX;
+
+ uint32_t cr, cg, cb, ca;
+
+ // If the partition's colors are all the same, then just pack them as a single color.
+ if (!pParams->m_pForce_selectors)
+ {
+ if (mode == 1)
+ {
+ if (is_solid_rgb(pParams, cr, cg, cb))
+ return pack_mode1_to_one_color(pParams, pResults, cr, cg, cb, pResults->m_pSelectors);
+ }
+ else if ((pParams->m_astc_endpoint_range == 8) && (pParams->m_num_selector_weights == 8) && (!pParams->m_has_alpha))
+ {
+ if (is_solid_rgb(pParams, cr, cg, cb))
+ return pack_astc_4bit_3bit_to_one_color(pParams, pResults, cr, cg, cb, pResults->m_pSelectors);
+ }
+ else if ((pParams->m_astc_endpoint_range == 7) && (pParams->m_num_selector_weights == 4) && (!pParams->m_has_alpha))
+ {
+ if (is_solid_rgb(pParams, cr, cg, cb))
+ return pack_astc_range7_2bit_to_one_color(pParams, pResults, cr, cg, cb, pResults->m_pSelectors);
+ }
+ else if ((pParams->m_astc_endpoint_range == 8) && (pParams->m_num_selector_weights == 4) && (pParams->m_has_alpha))
+ {
+ if (is_solid_rgba(pParams, cr, cg, cb, ca))
+ return pack_astc_4bit_2bit_to_one_color_rgba(pParams, pResults, cr, cg, cb, ca, pResults->m_pSelectors);
+ }
+ else if ((pParams->m_astc_endpoint_range == 13) && (pParams->m_num_selector_weights == 4) && (!pParams->m_has_alpha))
+ {
+ if (is_solid_rgb(pParams, cr, cg, cb))
+ return pack_astc_range13_2bit_to_one_color(pParams, pResults, cr, cg, cb, pResults->m_pSelectors);
+ }
+ else if ((pParams->m_astc_endpoint_range == 11) && (pParams->m_num_selector_weights == 32) && (!pParams->m_has_alpha))
+ {
+ if (is_solid_rgb(pParams, cr, cg, cb))
+ return pack_astc_range11_5bit_to_one_color(pParams, pResults, cr, cg, cb, pResults->m_pSelectors);
+ }
+ }
+
+ // Compute partition's mean color and principle axis.
+ bc7enc_vec4F meanColor, axis;
+ vec4F_set_scalar(&meanColor, 0.0f);
+
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ bc7enc_vec4F color = vec4F_from_color(&pParams->m_pPixels[i]);
+ meanColor = vec4F_add(&meanColor, &color);
+ }
+
+ bc7enc_vec4F meanColorScaled = vec4F_mul(&meanColor, 1.0f / (float)(pParams->m_num_pixels));
+
+ meanColor = vec4F_mul(&meanColor, 1.0f / (float)(pParams->m_num_pixels * 255.0f));
+ vec4F_saturate_in_place(&meanColor);
+
+ if (pParams->m_has_alpha)
+ {
+ // Use incremental PCA for RGBA PCA, because it's simple.
+ vec4F_set_scalar(&axis, 0.0f);
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ bc7enc_vec4F color = vec4F_from_color(&pParams->m_pPixels[i]);
+ color = vec4F_sub(&color, &meanColorScaled);
+ bc7enc_vec4F a = vec4F_mul(&color, color.m_c[0]);
+ bc7enc_vec4F b = vec4F_mul(&color, color.m_c[1]);
+ bc7enc_vec4F c = vec4F_mul(&color, color.m_c[2]);
+ bc7enc_vec4F d = vec4F_mul(&color, color.m_c[3]);
+ bc7enc_vec4F n = i ? axis : color;
+ vec4F_normalize_in_place(&n);
+ axis.m_c[0] += vec4F_dot(&a, &n);
+ axis.m_c[1] += vec4F_dot(&b, &n);
+ axis.m_c[2] += vec4F_dot(&c, &n);
+ axis.m_c[3] += vec4F_dot(&d, &n);
+ }
+ vec4F_normalize_in_place(&axis);
+ }
+ else
+ {
+ // Use covar technique for RGB PCA, because it doesn't require per-pixel normalization.
+ float cov[6] = { 0, 0, 0, 0, 0, 0 };
+
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ const color_quad_u8 *pV = &pParams->m_pPixels[i];
+ float r = pV->m_c[0] - meanColorScaled.m_c[0];
+ float g = pV->m_c[1] - meanColorScaled.m_c[1];
+ float b = pV->m_c[2] - meanColorScaled.m_c[2];
+ cov[0] += r*r; cov[1] += r*g; cov[2] += r*b; cov[3] += g*g; cov[4] += g*b; cov[5] += b*b;
+ }
+
+ float xr = .9f, xg = 1.0f, xb = .7f;
+ for (uint32_t iter = 0; iter < 3; iter++)
+ {
+ float r = xr * cov[0] + xg * cov[1] + xb * cov[2];
+ float g = xr * cov[1] + xg * cov[3] + xb * cov[4];
+ float b = xr * cov[2] + xg * cov[4] + xb * cov[5];
+
+ float m = maximumf(maximumf(fabsf(r), fabsf(g)), fabsf(b));
+ if (m > 1e-10f)
+ {
+ m = 1.0f / m;
+ r *= m; g *= m; b *= m;
+ }
+
+ xr = r; xg = g; xb = b;
+ }
+
+ float len = xr * xr + xg * xg + xb * xb;
+ if (len < 1e-10f)
+ vec4F_set_scalar(&axis, 0.0f);
+ else
+ {
+ len = 1.0f / sqrtf(len);
+ xr *= len; xg *= len; xb *= len;
+ vec4F_set(&axis, xr, xg, xb, 0);
+ }
+ }
+
+ if (vec4F_dot(&axis, &axis) < .5f)
+ {
+ if (pParams->m_perceptual)
+ vec4F_set(&axis, .213f, .715f, .072f, pParams->m_has_alpha ? .715f : 0);
+ else
+ vec4F_set(&axis, 1.0f, 1.0f, 1.0f, pParams->m_has_alpha ? 1.0f : 0);
+ vec4F_normalize_in_place(&axis);
+ }
+
+ bc7enc_vec4F minColor, maxColor;
+
+ float l = 1e+9f, h = -1e+9f;
+
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ bc7enc_vec4F color = vec4F_from_color(&pParams->m_pPixels[i]);
+
+ bc7enc_vec4F q = vec4F_sub(&color, &meanColorScaled);
+ float d = vec4F_dot(&q, &axis);
+
+ l = minimumf(l, d);
+ h = maximumf(h, d);
+ }
+
+ l *= (1.0f / 255.0f);
+ h *= (1.0f / 255.0f);
+
+ bc7enc_vec4F b0 = vec4F_mul(&axis, l);
+ bc7enc_vec4F b1 = vec4F_mul(&axis, h);
+ bc7enc_vec4F c0 = vec4F_add(&meanColor, &b0);
+ bc7enc_vec4F c1 = vec4F_add(&meanColor, &b1);
+ minColor = vec4F_saturate(&c0);
+ maxColor = vec4F_saturate(&c1);
+
+ bc7enc_vec4F whiteVec;
+ vec4F_set_scalar(&whiteVec, 1.0f);
+ if (vec4F_dot(&minColor, &whiteVec) > vec4F_dot(&maxColor, &whiteVec))
+ {
+#if 1
+ std::swap(minColor.m_c[0], maxColor.m_c[0]);
+ std::swap(minColor.m_c[1], maxColor.m_c[1]);
+ std::swap(minColor.m_c[2], maxColor.m_c[2]);
+ std::swap(minColor.m_c[3], maxColor.m_c[3]);
+#elif 0
+ // Fails to compile correctly with MSVC 2019 (code generation bug)
+ std::swap(minColor, maxColor);
+#else
+ // Fails with MSVC 2019
+ bc7enc_vec4F temp = minColor;
+ minColor = maxColor;
+ maxColor = temp;
+#endif
+ }
+
+ // First find a solution using the block's PCA.
+ if (!find_optimal_solution(mode, minColor, maxColor, pParams, pResults))
+ return 0;
+
+ for (uint32_t i = 0; i < pComp_params->m_least_squares_passes; i++)
+ {
+ // Now try to refine the solution using least squares by computing the optimal endpoints from the current selectors.
+ bc7enc_vec4F xl, xh;
+ vec4F_set_scalar(&xl, 0.0f);
+ vec4F_set_scalar(&xh, 0.0f);
+ if (pParams->m_has_alpha)
+ compute_least_squares_endpoints_rgba(pParams->m_num_pixels, pResults->m_pSelectors, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels);
+ else
+ compute_least_squares_endpoints_rgb(pParams->m_num_pixels, pResults->m_pSelectors, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels);
+
+ xl = vec4F_mul(&xl, (1.0f / 255.0f));
+ xh = vec4F_mul(&xh, (1.0f / 255.0f));
+
+ if (!find_optimal_solution(mode, xl, xh, pParams, pResults))
+ return 0;
+ }
+
+ if ((!pParams->m_pForce_selectors) && (pComp_params->m_uber_level > 0))
+ {
+ // In uber level 1, try varying the selectors a little, somewhat like cluster fit would. First try incrementing the minimum selectors,
+ // then try decrementing the selectrors, then try both.
+ uint8_t selectors_temp[16], selectors_temp1[16];
+ memcpy(selectors_temp, pResults->m_pSelectors, pParams->m_num_pixels);
+
+ const int max_selector = pParams->m_num_selector_weights - 1;
+
+ uint32_t min_sel = 256;
+ uint32_t max_sel = 0;
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ uint32_t sel = selectors_temp[i];
+ min_sel = minimumu(min_sel, sel);
+ max_sel = maximumu(max_sel, sel);
+ }
+
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ uint32_t sel = selectors_temp[i];
+ if ((sel == min_sel) && (sel < (pParams->m_num_selector_weights - 1)))
+ sel++;
+ selectors_temp1[i] = (uint8_t)sel;
+ }
+
+ bc7enc_vec4F xl, xh;
+ vec4F_set_scalar(&xl, 0.0f);
+ vec4F_set_scalar(&xh, 0.0f);
+ if (pParams->m_has_alpha)
+ compute_least_squares_endpoints_rgba(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels);
+ else
+ compute_least_squares_endpoints_rgb(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels);
+
+ xl = vec4F_mul(&xl, (1.0f / 255.0f));
+ xh = vec4F_mul(&xh, (1.0f / 255.0f));
+
+ if (!find_optimal_solution(mode, xl, xh, pParams, pResults))
+ return 0;
+
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ uint32_t sel = selectors_temp[i];
+ if ((sel == max_sel) && (sel > 0))
+ sel--;
+ selectors_temp1[i] = (uint8_t)sel;
+ }
+
+ if (pParams->m_has_alpha)
+ compute_least_squares_endpoints_rgba(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels);
+ else
+ compute_least_squares_endpoints_rgb(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels);
+
+ xl = vec4F_mul(&xl, (1.0f / 255.0f));
+ xh = vec4F_mul(&xh, (1.0f / 255.0f));
+
+ if (!find_optimal_solution(mode, xl, xh, pParams, pResults))
+ return 0;
+
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ {
+ uint32_t sel = selectors_temp[i];
+ if ((sel == min_sel) && (sel < (pParams->m_num_selector_weights - 1)))
+ sel++;
+ else if ((sel == max_sel) && (sel > 0))
+ sel--;
+ selectors_temp1[i] = (uint8_t)sel;
+ }
+
+ if (pParams->m_has_alpha)
+ compute_least_squares_endpoints_rgba(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels);
+ else
+ compute_least_squares_endpoints_rgb(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels);
+
+ xl = vec4F_mul(&xl, (1.0f / 255.0f));
+ xh = vec4F_mul(&xh, (1.0f / 255.0f));
+
+ if (!find_optimal_solution(mode, xl, xh, pParams, pResults))
+ return 0;
+
+ // In uber levels 2+, try taking more advantage of endpoint extrapolation by scaling the selectors in one direction or another.
+ const uint32_t uber_err_thresh = (pParams->m_num_pixels * 56) >> 4;
+ if ((pComp_params->m_uber_level >= 2) && (pResults->m_best_overall_err > uber_err_thresh))
+ {
+ const int Q = (pComp_params->m_uber_level >= 4) ? (pComp_params->m_uber_level - 2) : 1;
+ for (int ly = -Q; ly <= 1; ly++)
+ {
+ for (int hy = max_selector - 1; hy <= (max_selector + Q); hy++)
+ {
+ if ((ly == 0) && (hy == max_selector))
+ continue;
+
+ for (uint32_t i = 0; i < pParams->m_num_pixels; i++)
+ selectors_temp1[i] = (uint8_t)clampf(floorf((float)max_selector * ((float)selectors_temp[i] - (float)ly) / ((float)hy - (float)ly) + .5f), 0, (float)max_selector);
+
+ //bc7enc_vec4F xl, xh;
+ vec4F_set_scalar(&xl, 0.0f);
+ vec4F_set_scalar(&xh, 0.0f);
+ if (pParams->m_has_alpha)
+ compute_least_squares_endpoints_rgba(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels);
+ else
+ compute_least_squares_endpoints_rgb(pParams->m_num_pixels, selectors_temp1, pParams->m_pSelector_weightsx, &xl, &xh, pParams->m_pPixels);
+
+ xl = vec4F_mul(&xl, (1.0f / 255.0f));
+ xh = vec4F_mul(&xh, (1.0f / 255.0f));
+
+ if (!find_optimal_solution(mode, xl, xh, pParams, pResults))
+ return 0;
+ }
+ }
+ }
+ }
+
+ if (!pParams->m_pForce_selectors)
+ {
+ // Try encoding the partition as a single color by using the optimal single colors tables to encode the block to its mean.
+ if (mode == 1)
+ {
+ color_cell_compressor_results avg_results = *pResults;
+ const uint32_t r = (int)(.5f + meanColor.m_c[0] * 255.0f), g = (int)(.5f + meanColor.m_c[1] * 255.0f), b = (int)(.5f + meanColor.m_c[2] * 255.0f);
+ uint64_t avg_err = pack_mode1_to_one_color(pParams, &avg_results, r, g, b, pResults->m_pSelectors_temp);
+ if (avg_err < pResults->m_best_overall_err)
+ {
+ *pResults = avg_results;
+ memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels);
+ pResults->m_best_overall_err = avg_err;
+ }
+ }
+ else if ((pParams->m_astc_endpoint_range == 8) && (pParams->m_num_selector_weights == 8) && (!pParams->m_has_alpha))
+ {
+ color_cell_compressor_results avg_results = *pResults;
+ const uint32_t r = (int)(.5f + meanColor.m_c[0] * 255.0f), g = (int)(.5f + meanColor.m_c[1] * 255.0f), b = (int)(.5f + meanColor.m_c[2] * 255.0f);
+ uint64_t avg_err = pack_astc_4bit_3bit_to_one_color(pParams, &avg_results, r, g, b, pResults->m_pSelectors_temp);
+ if (avg_err < pResults->m_best_overall_err)
+ {
+ *pResults = avg_results;
+ memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels);
+ pResults->m_best_overall_err = avg_err;
+ }
+ }
+ else if ((pParams->m_astc_endpoint_range == 7) && (pParams->m_num_selector_weights == 4) && (!pParams->m_has_alpha))
+ {
+ color_cell_compressor_results avg_results = *pResults;
+ const uint32_t r = (int)(.5f + meanColor.m_c[0] * 255.0f), g = (int)(.5f + meanColor.m_c[1] * 255.0f), b = (int)(.5f + meanColor.m_c[2] * 255.0f);
+ uint64_t avg_err = pack_astc_range7_2bit_to_one_color(pParams, &avg_results, r, g, b, pResults->m_pSelectors_temp);
+ if (avg_err < pResults->m_best_overall_err)
+ {
+ *pResults = avg_results;
+ memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels);
+ pResults->m_best_overall_err = avg_err;
+ }
+ }
+ else if ((pParams->m_astc_endpoint_range == 8) && (pParams->m_num_selector_weights == 4) && (pParams->m_has_alpha))
+ {
+ color_cell_compressor_results avg_results = *pResults;
+ const uint32_t r = (int)(.5f + meanColor.m_c[0] * 255.0f), g = (int)(.5f + meanColor.m_c[1] * 255.0f), b = (int)(.5f + meanColor.m_c[2] * 255.0f), a = (int)(.5f + meanColor.m_c[3] * 255.0f);
+ uint64_t avg_err = pack_astc_4bit_2bit_to_one_color_rgba(pParams, &avg_results, r, g, b, a, pResults->m_pSelectors_temp);
+ if (avg_err < pResults->m_best_overall_err)
+ {
+ *pResults = avg_results;
+ memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels);
+ pResults->m_best_overall_err = avg_err;
+ }
+ }
+ else if ((pParams->m_astc_endpoint_range == 13) && (pParams->m_num_selector_weights == 4) && (!pParams->m_has_alpha))
+ {
+ color_cell_compressor_results avg_results = *pResults;
+ const uint32_t r = (int)(.5f + meanColor.m_c[0] * 255.0f), g = (int)(.5f + meanColor.m_c[1] * 255.0f), b = (int)(.5f + meanColor.m_c[2] * 255.0f);
+ uint64_t avg_err = pack_astc_range13_2bit_to_one_color(pParams, &avg_results, r, g, b, pResults->m_pSelectors_temp);
+ if (avg_err < pResults->m_best_overall_err)
+ {
+ *pResults = avg_results;
+ memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels);
+ pResults->m_best_overall_err = avg_err;
+ }
+ }
+ else if ((pParams->m_astc_endpoint_range == 11) && (pParams->m_num_selector_weights == 32) && (!pParams->m_has_alpha))
+ {
+ color_cell_compressor_results avg_results = *pResults;
+ const uint32_t r = (int)(.5f + meanColor.m_c[0] * 255.0f), g = (int)(.5f + meanColor.m_c[1] * 255.0f), b = (int)(.5f + meanColor.m_c[2] * 255.0f);
+ uint64_t avg_err = pack_astc_range11_5bit_to_one_color(pParams, &avg_results, r, g, b, pResults->m_pSelectors_temp);
+ if (avg_err < pResults->m_best_overall_err)
+ {
+ *pResults = avg_results;
+ memcpy(pResults->m_pSelectors, pResults->m_pSelectors_temp, sizeof(pResults->m_pSelectors[0]) * pParams->m_num_pixels);
+ pResults->m_best_overall_err = avg_err;
+ }
+ }
+ }
+
+#if BC7ENC_CHECK_OVERALL_ERROR
+ check_best_overall_error(pParams, pResults);
+#endif
+
+ return pResults->m_best_overall_err;
+}
+
+uint64_t color_cell_compression_est_astc(
+ uint32_t num_weights, uint32_t num_comps, const uint32_t *pWeight_table,
+ uint32_t num_pixels, const color_quad_u8* pPixels,
+ uint64_t best_err_so_far, const uint32_t weights[4])
+{
+ assert(num_comps == 3 || num_comps == 4);
+ assert(num_weights >= 1 && num_weights <= 32);
+ assert(pWeight_table[0] == 0 && pWeight_table[num_weights - 1] == 64);
+
+ // Find RGB bounds as an approximation of the block's principle axis
+ uint32_t lr = 255, lg = 255, lb = 255, la = 255;
+ uint32_t hr = 0, hg = 0, hb = 0, ha = 0;
+ if (num_comps == 4)
+ {
+ for (uint32_t i = 0; i < num_pixels; i++)
+ {
+ const color_quad_u8* pC = &pPixels[i];
+ if (pC->m_c[0] < lr) lr = pC->m_c[0];
+ if (pC->m_c[1] < lg) lg = pC->m_c[1];
+ if (pC->m_c[2] < lb) lb = pC->m_c[2];
+ if (pC->m_c[3] < la) la = pC->m_c[3];
+
+ if (pC->m_c[0] > hr) hr = pC->m_c[0];
+ if (pC->m_c[1] > hg) hg = pC->m_c[1];
+ if (pC->m_c[2] > hb) hb = pC->m_c[2];
+ if (pC->m_c[3] > ha) ha = pC->m_c[3];
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < num_pixels; i++)
+ {
+ const color_quad_u8* pC = &pPixels[i];
+ if (pC->m_c[0] < lr) lr = pC->m_c[0];
+ if (pC->m_c[1] < lg) lg = pC->m_c[1];
+ if (pC->m_c[2] < lb) lb = pC->m_c[2];
+
+ if (pC->m_c[0] > hr) hr = pC->m_c[0];
+ if (pC->m_c[1] > hg) hg = pC->m_c[1];
+ if (pC->m_c[2] > hb) hb = pC->m_c[2];
+ }
+ la = 255;
+ ha = 255;
+ }
+
+ color_quad_u8 lowColor, highColor;
+ color_quad_u8_set(&lowColor, lr, lg, lb, la);
+ color_quad_u8_set(&highColor, hr, hg, hb, ha);
+
+ // Place endpoints at bbox diagonals and compute interpolated colors
+ color_quad_u8 weightedColors[32];
+
+ weightedColors[0] = lowColor;
+ weightedColors[num_weights - 1] = highColor;
+ for (uint32_t i = 1; i < (num_weights - 1); i++)
+ {
+ weightedColors[i].m_c[0] = (uint8_t)astc_interpolate(lowColor.m_c[0], highColor.m_c[0], pWeight_table[i]);
+ weightedColors[i].m_c[1] = (uint8_t)astc_interpolate(lowColor.m_c[1], highColor.m_c[1], pWeight_table[i]);
+ weightedColors[i].m_c[2] = (uint8_t)astc_interpolate(lowColor.m_c[2], highColor.m_c[2], pWeight_table[i]);
+ weightedColors[i].m_c[3] = (num_comps == 4) ? (uint8_t)astc_interpolate(lowColor.m_c[3], highColor.m_c[3], pWeight_table[i]) : 255;
+ }
+
+ // Compute dots and thresholds
+ const int ar = highColor.m_c[0] - lowColor.m_c[0];
+ const int ag = highColor.m_c[1] - lowColor.m_c[1];
+ const int ab = highColor.m_c[2] - lowColor.m_c[2];
+ const int aa = highColor.m_c[3] - lowColor.m_c[3];
+
+ int dots[32];
+ if (num_comps == 4)
+ {
+ for (uint32_t i = 0; i < num_weights; i++)
+ dots[i] = weightedColors[i].m_c[0] * ar + weightedColors[i].m_c[1] * ag + weightedColors[i].m_c[2] * ab + weightedColors[i].m_c[3] * aa;
+ }
+ else
+ {
+ assert(aa == 0);
+ for (uint32_t i = 0; i < num_weights; i++)
+ dots[i] = weightedColors[i].m_c[0] * ar + weightedColors[i].m_c[1] * ag + weightedColors[i].m_c[2] * ab;
+ }
+
+ int thresh[32 - 1];
+ for (uint32_t i = 0; i < (num_weights - 1); i++)
+ thresh[i] = (dots[i] + dots[i + 1] + 1) >> 1;
+
+ uint64_t total_err = 0;
+ if ((weights[0] | weights[1] | weights[2] | weights[3]) == 1)
+ {
+ if (num_comps == 4)
+ {
+ for (uint32_t i = 0; i < num_pixels; i++)
+ {
+ const color_quad_u8* pC = &pPixels[i];
+
+ int d = ar * pC->m_c[0] + ag * pC->m_c[1] + ab * pC->m_c[2] + aa * pC->m_c[3];
+
+ // Find approximate selector
+ uint32_t s = 0;
+ for (int j = num_weights - 2; j >= 0; j--)
+ {
+ if (d >= thresh[j])
+ {
+ s = j + 1;
+ break;
+ }
+ }
+
+ // Compute error
+ const color_quad_u8* pE1 = &weightedColors[s];
+
+ int dr = (int)pE1->m_c[0] - (int)pC->m_c[0];
+ int dg = (int)pE1->m_c[1] - (int)pC->m_c[1];
+ int db = (int)pE1->m_c[2] - (int)pC->m_c[2];
+ int da = (int)pE1->m_c[3] - (int)pC->m_c[3];
+
+ total_err += (dr * dr) + (dg * dg) + (db * db) + (da * da);
+ if (total_err > best_err_so_far)
+ break;
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < num_pixels; i++)
+ {
+ const color_quad_u8* pC = &pPixels[i];
+
+ int d = ar * pC->m_c[0] + ag * pC->m_c[1] + ab * pC->m_c[2];
+
+ // Find approximate selector
+ uint32_t s = 0;
+ for (int j = num_weights - 2; j >= 0; j--)
+ {
+ if (d >= thresh[j])
+ {
+ s = j + 1;
+ break;
+ }
+ }
+
+ // Compute error
+ const color_quad_u8* pE1 = &weightedColors[s];
+
+ int dr = (int)pE1->m_c[0] - (int)pC->m_c[0];
+ int dg = (int)pE1->m_c[1] - (int)pC->m_c[1];
+ int db = (int)pE1->m_c[2] - (int)pC->m_c[2];
+
+ total_err += (dr * dr) + (dg * dg) + (db * db);
+ if (total_err > best_err_so_far)
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (num_comps == 4)
+ {
+ for (uint32_t i = 0; i < num_pixels; i++)
+ {
+ const color_quad_u8* pC = &pPixels[i];
+
+ int d = ar * pC->m_c[0] + ag * pC->m_c[1] + ab * pC->m_c[2] + aa * pC->m_c[3];
+
+ // Find approximate selector
+ uint32_t s = 0;
+ for (int j = num_weights - 2; j >= 0; j--)
+ {
+ if (d >= thresh[j])
+ {
+ s = j + 1;
+ break;
+ }
+ }
+
+ // Compute error
+ const color_quad_u8* pE1 = &weightedColors[s];
+
+ int dr = (int)pE1->m_c[0] - (int)pC->m_c[0];
+ int dg = (int)pE1->m_c[1] - (int)pC->m_c[1];
+ int db = (int)pE1->m_c[2] - (int)pC->m_c[2];
+ int da = (int)pE1->m_c[3] - (int)pC->m_c[3];
+
+ total_err += weights[0] * (dr * dr) + weights[1] * (dg * dg) + weights[2] * (db * db) + weights[3] * (da * da);
+ if (total_err > best_err_so_far)
+ break;
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < num_pixels; i++)
+ {
+ const color_quad_u8* pC = &pPixels[i];
+
+ int d = ar * pC->m_c[0] + ag * pC->m_c[1] + ab * pC->m_c[2];
+
+ // Find approximate selector
+ uint32_t s = 0;
+ for (int j = num_weights - 2; j >= 0; j--)
+ {
+ if (d >= thresh[j])
+ {
+ s = j + 1;
+ break;
+ }
+ }
+
+ // Compute error
+ const color_quad_u8* pE1 = &weightedColors[s];
+
+ int dr = (int)pE1->m_c[0] - (int)pC->m_c[0];
+ int dg = (int)pE1->m_c[1] - (int)pC->m_c[1];
+ int db = (int)pE1->m_c[2] - (int)pC->m_c[2];
+
+ total_err += weights[0] * (dr * dr) + weights[1] * (dg * dg) + weights[2] * (db * db);
+ if (total_err > best_err_so_far)
+ break;
+ }
+ }
+ }
+
+ return total_err;
+}
+
+} // namespace basisu
diff --git a/thirdparty/basis_universal/encoder/basisu_bc7enc.h b/thirdparty/basis_universal/encoder/basisu_bc7enc.h
new file mode 100644
index 0000000000..23469912e2
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_bc7enc.h
@@ -0,0 +1,131 @@
+// File: basisu_bc7enc.h
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "basisu_enc.h"
+#include "../transcoder/basisu_transcoder_uastc.h"
+
+namespace basisu
+{
+
+#define BC7ENC_MAX_PARTITIONS1 (64)
+#define BC7ENC_MAX_UBER_LEVEL (4)
+
+ typedef uint8_t bc7enc_bool;
+
+#define BC7ENC_TRUE (1)
+#define BC7ENC_FALSE (0)
+
+ typedef struct { float m_c[4]; } bc7enc_vec4F;
+
+ extern const float g_bc7_weights1x[2 * 4];
+ extern const float g_bc7_weights2x[4 * 4];
+ extern const float g_bc7_weights3x[8 * 4];
+ extern const float g_bc7_weights4x[16 * 4];
+ extern const float g_astc_weights4x[16 * 4];
+ extern const float g_astc_weights5x[32 * 4];
+ extern const float g_astc_weights_3levelsx[3 * 4];
+
+ extern basist::astc_quant_bin g_astc_sorted_order_unquant[basist::BC7ENC_TOTAL_ASTC_RANGES][256]; // [sorted unquantized order]
+
+ struct color_cell_compressor_params
+ {
+ uint32_t m_num_pixels;
+ const basist::color_quad_u8* m_pPixels;
+
+ uint32_t m_num_selector_weights;
+ const uint32_t* m_pSelector_weights;
+
+ const bc7enc_vec4F* m_pSelector_weightsx;
+ uint32_t m_comp_bits;
+
+ const uint8_t *m_pForce_selectors;
+
+ // Non-zero m_astc_endpoint_range enables ASTC mode. m_comp_bits and m_has_pbits are always false. We only support 2, 3, or 4 bit weight encodings.
+ uint32_t m_astc_endpoint_range;
+
+ uint32_t m_weights[4];
+ bc7enc_bool m_has_alpha;
+ bc7enc_bool m_has_pbits;
+ bc7enc_bool m_endpoints_share_pbit;
+ bc7enc_bool m_perceptual;
+ };
+
+ struct color_cell_compressor_results
+ {
+ uint64_t m_best_overall_err;
+ basist::color_quad_u8 m_low_endpoint;
+ basist::color_quad_u8 m_high_endpoint;
+ uint32_t m_pbits[2];
+ uint8_t* m_pSelectors;
+ uint8_t* m_pSelectors_temp;
+
+ // Encoded ASTC indices, if ASTC mode is enabled
+ basist::color_quad_u8 m_astc_low_endpoint;
+ basist::color_quad_u8 m_astc_high_endpoint;
+ };
+
+ struct bc7enc_compress_block_params
+ {
+ // m_max_partitions_mode1 may range from 0 (disables mode 1) to BC7ENC_MAX_PARTITIONS1. The higher this value, the slower the compressor, but the higher the quality.
+ uint32_t m_max_partitions_mode1;
+
+ // Relative RGBA or YCbCrA weights.
+ uint32_t m_weights[4];
+
+ // m_uber_level may range from 0 to BC7ENC_MAX_UBER_LEVEL. The higher this value, the slower the compressor, but the higher the quality.
+ uint32_t m_uber_level;
+
+ // If m_perceptual is true, colorspace error is computed in YCbCr space, otherwise RGB.
+ bc7enc_bool m_perceptual;
+
+ uint32_t m_least_squares_passes;
+ };
+
+ uint64_t color_cell_compression(uint32_t mode, const color_cell_compressor_params* pParams, color_cell_compressor_results* pResults, const bc7enc_compress_block_params* pComp_params);
+
+ uint64_t color_cell_compression_est_astc(
+ uint32_t num_weights, uint32_t num_comps, const uint32_t* pWeight_table,
+ uint32_t num_pixels, const basist::color_quad_u8* pPixels,
+ uint64_t best_err_so_far, const uint32_t weights[4]);
+
+ inline void bc7enc_compress_block_params_init_linear_weights(bc7enc_compress_block_params* p)
+ {
+ p->m_perceptual = BC7ENC_FALSE;
+ p->m_weights[0] = 1;
+ p->m_weights[1] = 1;
+ p->m_weights[2] = 1;
+ p->m_weights[3] = 1;
+ }
+
+ inline void bc7enc_compress_block_params_init_perceptual_weights(bc7enc_compress_block_params* p)
+ {
+ p->m_perceptual = BC7ENC_TRUE;
+ p->m_weights[0] = 128;
+ p->m_weights[1] = 64;
+ p->m_weights[2] = 16;
+ p->m_weights[3] = 32;
+ }
+
+ inline void bc7enc_compress_block_params_init(bc7enc_compress_block_params* p)
+ {
+ p->m_max_partitions_mode1 = BC7ENC_MAX_PARTITIONS1;
+ p->m_least_squares_passes = 1;
+ p->m_uber_level = 0;
+ bc7enc_compress_block_params_init_perceptual_weights(p);
+ }
+
+ // bc7enc_compress_block_init() MUST be called before calling bc7enc_compress_block() (or you'll get artifacts).
+ void bc7enc_compress_block_init();
+
+} // namespace basisu
diff --git a/thirdparty/basis_universal/encoder/basisu_comp.cpp b/thirdparty/basis_universal/encoder/basisu_comp.cpp
new file mode 100644
index 0000000000..dc4ae11539
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_comp.cpp
@@ -0,0 +1,2113 @@
+// basisu_comp.cpp
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "basisu_comp.h"
+#include "basisu_enc.h"
+#include <unordered_set>
+#include <atomic>
+
+// basisu_transcoder.cpp is where basisu_miniz lives now, we just need the declarations here.
+#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
+#include "basisu_miniz.h"
+
+#if !BASISD_SUPPORT_KTX2
+#error BASISD_SUPPORT_KTX2 must be enabled (set to 1).
+#endif
+
+#if BASISD_SUPPORT_KTX2_ZSTD
+#include "../zstd/zstd.h"
+#endif
+
+// Set to 1 to disable the mipPadding alignment workaround (which only seems to be needed when no key-values are written at all)
+#define BASISU_DISABLE_KTX2_ALIGNMENT_WORKAROUND (0)
+
+// Set to 1 to disable writing all KTX2 key values, triggering the validator bug.
+#define BASISU_DISABLE_KTX2_KEY_VALUES (0)
+
+using namespace buminiz;
+
+#define BASISU_USE_STB_IMAGE_RESIZE_FOR_MIPMAP_GEN 0
+#define DEBUG_CROP_TEXTURE_TO_64x64 (0)
+#define DEBUG_RESIZE_TEXTURE (0)
+#define DEBUG_EXTRACT_SINGLE_BLOCK (0)
+
+namespace basisu
+{
+ basis_compressor::basis_compressor() :
+ m_basis_file_size(0),
+ m_basis_bits_per_texel(0.0f),
+ m_total_blocks(0),
+ m_auto_global_sel_pal(false),
+ m_any_source_image_has_alpha(false)
+ {
+ debug_printf("basis_compressor::basis_compressor\n");
+ }
+
+ bool basis_compressor::init(const basis_compressor_params &params)
+ {
+ debug_printf("basis_compressor::init\n");
+
+ m_params = params;
+
+ if (m_params.m_debug)
+ {
+ debug_printf("basis_compressor::init:\n");
+
+#define PRINT_BOOL_VALUE(v) debug_printf("%s: %u %u\n", BASISU_STRINGIZE2(v), static_cast<int>(m_params.v), m_params.v.was_changed());
+#define PRINT_INT_VALUE(v) debug_printf("%s: %i %u\n", BASISU_STRINGIZE2(v), static_cast<int>(m_params.v), m_params.v.was_changed());
+#define PRINT_UINT_VALUE(v) debug_printf("%s: %u %u\n", BASISU_STRINGIZE2(v), static_cast<uint32_t>(m_params.v), m_params.v.was_changed());
+#define PRINT_FLOAT_VALUE(v) debug_printf("%s: %f %u\n", BASISU_STRINGIZE2(v), static_cast<float>(m_params.v), m_params.v.was_changed());
+
+ debug_printf("Has global selector codebook: %i\n", m_params.m_pSel_codebook != nullptr);
+
+ debug_printf("Source images: %u, source filenames: %u, source alpha filenames: %i, Source mipmap images: %u\n",
+ m_params.m_source_images.size(), m_params.m_source_filenames.size(), m_params.m_source_alpha_filenames.size(), m_params.m_source_mipmap_images.size());
+
+ if (m_params.m_source_mipmap_images.size())
+ {
+ debug_printf("m_source_mipmap_images array sizes:\n");
+ for (uint32_t i = 0; i < m_params.m_source_mipmap_images.size(); i++)
+ debug_printf("%u ", m_params.m_source_mipmap_images[i].size());
+ debug_printf("\n");
+ }
+
+ PRINT_BOOL_VALUE(m_uastc);
+ PRINT_BOOL_VALUE(m_y_flip);
+ PRINT_BOOL_VALUE(m_debug);
+ PRINT_BOOL_VALUE(m_validate);
+ PRINT_BOOL_VALUE(m_debug_images);
+ PRINT_BOOL_VALUE(m_global_sel_pal);
+ PRINT_BOOL_VALUE(m_auto_global_sel_pal);
+ PRINT_INT_VALUE(m_compression_level);
+ PRINT_BOOL_VALUE(m_no_hybrid_sel_cb);
+ PRINT_BOOL_VALUE(m_perceptual);
+ PRINT_BOOL_VALUE(m_no_endpoint_rdo);
+ PRINT_BOOL_VALUE(m_no_selector_rdo);
+ PRINT_BOOL_VALUE(m_read_source_images);
+ PRINT_BOOL_VALUE(m_write_output_basis_files);
+ PRINT_BOOL_VALUE(m_compute_stats);
+ PRINT_BOOL_VALUE(m_check_for_alpha);
+ PRINT_BOOL_VALUE(m_force_alpha);
+ debug_printf("swizzle: %d,%d,%d,%d\n",
+ m_params.m_swizzle[0],
+ m_params.m_swizzle[1],
+ m_params.m_swizzle[2],
+ m_params.m_swizzle[3]);
+ PRINT_BOOL_VALUE(m_renormalize);
+ PRINT_BOOL_VALUE(m_multithreading);
+ PRINT_BOOL_VALUE(m_disable_hierarchical_endpoint_codebooks);
+
+ PRINT_FLOAT_VALUE(m_hybrid_sel_cb_quality_thresh);
+
+ PRINT_INT_VALUE(m_global_pal_bits);
+ PRINT_INT_VALUE(m_global_mod_bits);
+
+ PRINT_FLOAT_VALUE(m_endpoint_rdo_thresh);
+ PRINT_FLOAT_VALUE(m_selector_rdo_thresh);
+
+ PRINT_BOOL_VALUE(m_mip_gen);
+ PRINT_BOOL_VALUE(m_mip_renormalize);
+ PRINT_BOOL_VALUE(m_mip_wrapping);
+ PRINT_BOOL_VALUE(m_mip_fast);
+ PRINT_BOOL_VALUE(m_mip_srgb);
+ PRINT_FLOAT_VALUE(m_mip_premultiplied);
+ PRINT_FLOAT_VALUE(m_mip_scale);
+ PRINT_INT_VALUE(m_mip_smallest_dimension);
+ debug_printf("m_mip_filter: %s\n", m_params.m_mip_filter.c_str());
+
+ debug_printf("m_max_endpoint_clusters: %u\n", m_params.m_max_endpoint_clusters);
+ debug_printf("m_max_selector_clusters: %u\n", m_params.m_max_selector_clusters);
+ debug_printf("m_quality_level: %i\n", m_params.m_quality_level);
+
+ debug_printf("m_tex_type: %u\n", m_params.m_tex_type);
+ debug_printf("m_userdata0: 0x%X, m_userdata1: 0x%X\n", m_params.m_userdata0, m_params.m_userdata1);
+ debug_printf("m_us_per_frame: %i (%f fps)\n", m_params.m_us_per_frame, m_params.m_us_per_frame ? 1.0f / (m_params.m_us_per_frame / 1000000.0f) : 0);
+ debug_printf("m_pack_uastc_flags: 0x%X\n", m_params.m_pack_uastc_flags);
+
+ PRINT_BOOL_VALUE(m_rdo_uastc);
+ PRINT_FLOAT_VALUE(m_rdo_uastc_quality_scalar);
+ PRINT_INT_VALUE(m_rdo_uastc_dict_size);
+ PRINT_FLOAT_VALUE(m_rdo_uastc_max_allowed_rms_increase_ratio);
+ PRINT_FLOAT_VALUE(m_rdo_uastc_skip_block_rms_thresh);
+ PRINT_FLOAT_VALUE(m_rdo_uastc_max_smooth_block_error_scale);
+ PRINT_FLOAT_VALUE(m_rdo_uastc_smooth_block_max_std_dev);
+ PRINT_BOOL_VALUE(m_rdo_uastc_favor_simpler_modes_in_rdo_mode)
+ PRINT_BOOL_VALUE(m_rdo_uastc_multithreading);
+
+ PRINT_INT_VALUE(m_resample_width);
+ PRINT_INT_VALUE(m_resample_height);
+ PRINT_FLOAT_VALUE(m_resample_factor);
+ debug_printf("Has global codebooks: %u\n", m_params.m_pGlobal_codebooks ? 1 : 0);
+ if (m_params.m_pGlobal_codebooks)
+ {
+ debug_printf("Global codebook endpoints: %u selectors: %u\n", m_params.m_pGlobal_codebooks->get_endpoints().size(), m_params.m_pGlobal_codebooks->get_selectors().size());
+ }
+
+ PRINT_BOOL_VALUE(m_create_ktx2_file);
+
+ debug_printf("KTX2 UASTC supercompression: %u\n", m_params.m_ktx2_uastc_supercompression);
+ debug_printf("KTX2 Zstd supercompression level: %i\n", (int)m_params.m_ktx2_zstd_supercompression_level);
+ debug_printf("KTX2 sRGB transfer func: %u\n", (int)m_params.m_ktx2_srgb_transfer_func);
+ debug_printf("Total KTX2 key values: %u\n", m_params.m_ktx2_key_values.size());
+ for (uint32_t i = 0; i < m_params.m_ktx2_key_values.size(); i++)
+ {
+ debug_printf("Key: \"%s\"\n", m_params.m_ktx2_key_values[i].m_key.data());
+ debug_printf("Value size: %u\n", m_params.m_ktx2_key_values[i].m_value.size());
+ }
+
+#undef PRINT_BOOL_VALUE
+#undef PRINT_INT_VALUE
+#undef PRINT_UINT_VALUE
+#undef PRINT_FLOAT_VALUE
+ }
+
+ if ((m_params.m_read_source_images) && (!m_params.m_source_filenames.size()))
+ {
+ assert(0);
+ return false;
+ }
+
+ return true;
+ }
+
+ basis_compressor::error_code basis_compressor::process()
+ {
+ debug_printf("basis_compressor::process\n");
+
+ if (!read_source_images())
+ return cECFailedReadingSourceImages;
+
+ if (!validate_texture_type_constraints())
+ return cECFailedValidating;
+
+ if (m_params.m_create_ktx2_file)
+ {
+ if (!validate_ktx2_constraints())
+ return cECFailedValidating;
+ }
+
+ if (!extract_source_blocks())
+ return cECFailedFrontEnd;
+
+ if (m_params.m_uastc)
+ {
+ error_code ec = encode_slices_to_uastc();
+ if (ec != cECSuccess)
+ return ec;
+ }
+ else
+ {
+ if (!process_frontend())
+ return cECFailedFrontEnd;
+
+ if (!extract_frontend_texture_data())
+ return cECFailedFontendExtract;
+
+ if (!process_backend())
+ return cECFailedBackend;
+ }
+
+ if (!create_basis_file_and_transcode())
+ return cECFailedCreateBasisFile;
+
+ if (m_params.m_create_ktx2_file)
+ {
+ if (!create_ktx2_file())
+ return cECFailedCreateKTX2File;
+ }
+
+ if (!write_output_files_and_compute_stats())
+ return cECFailedWritingOutput;
+
+ return cECSuccess;
+ }
+
+ basis_compressor::error_code basis_compressor::encode_slices_to_uastc()
+ {
+ debug_printf("basis_compressor::encode_slices_to_uastc\n");
+
+ m_uastc_slice_textures.resize(m_slice_descs.size());
+ for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++)
+ m_uastc_slice_textures[slice_index].init(texture_format::cUASTC4x4, m_slice_descs[slice_index].m_orig_width, m_slice_descs[slice_index].m_orig_height);
+
+ m_uastc_backend_output.m_tex_format = basist::basis_tex_format::cUASTC4x4;
+ m_uastc_backend_output.m_etc1s = false;
+ m_uastc_backend_output.m_slice_desc = m_slice_descs;
+ m_uastc_backend_output.m_slice_image_data.resize(m_slice_descs.size());
+ m_uastc_backend_output.m_slice_image_crcs.resize(m_slice_descs.size());
+
+ for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++)
+ {
+ gpu_image& tex = m_uastc_slice_textures[slice_index];
+ basisu_backend_slice_desc& slice_desc = m_slice_descs[slice_index];
+ (void)slice_desc;
+
+ const uint32_t num_blocks_x = tex.get_blocks_x();
+ const uint32_t num_blocks_y = tex.get_blocks_y();
+ const uint32_t total_blocks = tex.get_total_blocks();
+ const image& source_image = m_slice_images[slice_index];
+
+ std::atomic<uint32_t> total_blocks_processed;
+ total_blocks_processed = 0;
+
+ const uint32_t N = 256;
+ for (uint32_t block_index_iter = 0; block_index_iter < total_blocks; block_index_iter += N)
+ {
+ const uint32_t first_index = block_index_iter;
+ const uint32_t last_index = minimum<uint32_t>(total_blocks, block_index_iter + N);
+
+ // FIXME: This sucks, but we're having a stack size related problem with std::function with emscripten.
+#ifndef __EMSCRIPTEN__
+ m_params.m_pJob_pool->add_job([this, first_index, last_index, num_blocks_x, num_blocks_y, total_blocks, &source_image, &tex, &total_blocks_processed]
+ {
+#endif
+ BASISU_NOTE_UNUSED(num_blocks_y);
+
+ uint32_t uastc_flags = m_params.m_pack_uastc_flags;
+ if ((m_params.m_rdo_uastc) && (m_params.m_rdo_uastc_favor_simpler_modes_in_rdo_mode))
+ uastc_flags |= cPackUASTCFavorSimplerModes;
+
+ for (uint32_t block_index = first_index; block_index < last_index; block_index++)
+ {
+ const uint32_t block_x = block_index % num_blocks_x;
+ const uint32_t block_y = block_index / num_blocks_x;
+
+ color_rgba block_pixels[4][4];
+
+ source_image.extract_block_clamped((color_rgba*)block_pixels, block_x * 4, block_y * 4, 4, 4);
+
+ basist::uastc_block& dest_block = *(basist::uastc_block*)tex.get_block_ptr(block_x, block_y);
+
+ encode_uastc(&block_pixels[0][0].r, dest_block, uastc_flags);
+
+ total_blocks_processed++;
+
+ uint32_t val = total_blocks_processed;
+ if ((val & 16383) == 16383)
+ {
+ debug_printf("basis_compressor::encode_slices_to_uastc: %3.1f%% done\n", static_cast<float>(val) * 100.0f / total_blocks);
+ }
+
+ }
+
+#ifndef __EMSCRIPTEN__
+ });
+#endif
+
+ } // block_index_iter
+
+#ifndef __EMSCRIPTEN__
+ m_params.m_pJob_pool->wait_for_all();
+#endif
+
+ if (m_params.m_rdo_uastc)
+ {
+ uastc_rdo_params rdo_params;
+ rdo_params.m_lambda = m_params.m_rdo_uastc_quality_scalar;
+ rdo_params.m_max_allowed_rms_increase_ratio = m_params.m_rdo_uastc_max_allowed_rms_increase_ratio;
+ rdo_params.m_skip_block_rms_thresh = m_params.m_rdo_uastc_skip_block_rms_thresh;
+ rdo_params.m_lz_dict_size = m_params.m_rdo_uastc_dict_size;
+ rdo_params.m_smooth_block_max_error_scale = m_params.m_rdo_uastc_max_smooth_block_error_scale;
+ rdo_params.m_max_smooth_block_std_dev = m_params.m_rdo_uastc_smooth_block_max_std_dev;
+
+ bool status = uastc_rdo(tex.get_total_blocks(), (basist::uastc_block*)tex.get_ptr(),
+ (const color_rgba *)m_source_blocks[slice_desc.m_first_block_index].m_pixels, rdo_params, m_params.m_pack_uastc_flags, m_params.m_rdo_uastc_multithreading ? m_params.m_pJob_pool : nullptr,
+ (m_params.m_rdo_uastc_multithreading && m_params.m_pJob_pool) ? basisu::minimum<uint32_t>(4, (uint32_t)m_params.m_pJob_pool->get_total_threads()) : 0);
+ if (!status)
+ {
+ return cECFailedUASTCRDOPostProcess;
+ }
+ }
+
+ m_uastc_backend_output.m_slice_image_data[slice_index].resize(tex.get_size_in_bytes());
+ memcpy(&m_uastc_backend_output.m_slice_image_data[slice_index][0], tex.get_ptr(), tex.get_size_in_bytes());
+
+ m_uastc_backend_output.m_slice_image_crcs[slice_index] = basist::crc16(tex.get_ptr(), tex.get_size_in_bytes(), 0);
+
+ } // slice_index
+
+ return cECSuccess;
+ }
+
+ bool basis_compressor::generate_mipmaps(const image &img, basisu::vector<image> &mips, bool has_alpha)
+ {
+ debug_printf("basis_compressor::generate_mipmaps\n");
+
+ interval_timer tm;
+ tm.start();
+
+ uint32_t total_levels = 1;
+ uint32_t w = img.get_width(), h = img.get_height();
+ while (maximum<uint32_t>(w, h) > (uint32_t)m_params.m_mip_smallest_dimension)
+ {
+ w = maximum(w >> 1U, 1U);
+ h = maximum(h >> 1U, 1U);
+ total_levels++;
+ }
+
+#if BASISU_USE_STB_IMAGE_RESIZE_FOR_MIPMAP_GEN
+ // Requires stb_image_resize
+ stbir_filter filter = STBIR_FILTER_DEFAULT;
+ if (m_params.m_mip_filter == "box")
+ filter = STBIR_FILTER_BOX;
+ else if (m_params.m_mip_filter == "triangle")
+ filter = STBIR_FILTER_TRIANGLE;
+ else if (m_params.m_mip_filter == "cubic")
+ filter = STBIR_FILTER_CUBICBSPLINE;
+ else if (m_params.m_mip_filter == "catmull")
+ filter = STBIR_FILTER_CATMULLROM;
+ else if (m_params.m_mip_filter == "mitchell")
+ filter = STBIR_FILTER_MITCHELL;
+
+ for (uint32_t level = 1; level < total_levels; level++)
+ {
+ const uint32_t level_width = maximum<uint32_t>(1, img.get_width() >> level);
+ const uint32_t level_height = maximum<uint32_t>(1, img.get_height() >> level);
+
+ image &level_img = *enlarge_vector(mips, 1);
+ level_img.resize(level_width, level_height);
+
+ int result = stbir_resize_uint8_generic(
+ (const uint8_t *)img.get_ptr(), img.get_width(), img.get_height(), img.get_pitch() * sizeof(color_rgba),
+ (uint8_t *)level_img.get_ptr(), level_img.get_width(), level_img.get_height(), level_img.get_pitch() * sizeof(color_rgba),
+ has_alpha ? 4 : 3, has_alpha ? 3 : STBIR_ALPHA_CHANNEL_NONE, m_params.m_mip_premultiplied ? STBIR_FLAG_ALPHA_PREMULTIPLIED : 0,
+ m_params.m_mip_wrapping ? STBIR_EDGE_WRAP : STBIR_EDGE_CLAMP, filter, m_params.m_mip_srgb ? STBIR_COLORSPACE_SRGB : STBIR_COLORSPACE_LINEAR,
+ nullptr);
+
+ if (result == 0)
+ {
+ error_printf("basis_compressor::generate_mipmaps: stbir_resize_uint8_generic() failed!\n");
+ return false;
+ }
+
+ if (m_params.m_mip_renormalize)
+ level_img.renormalize_normal_map();
+ }
+#else
+ for (uint32_t level = 1; level < total_levels; level++)
+ {
+ const uint32_t level_width = maximum<uint32_t>(1, img.get_width() >> level);
+ const uint32_t level_height = maximum<uint32_t>(1, img.get_height() >> level);
+
+ image& level_img = *enlarge_vector(mips, 1);
+ level_img.resize(level_width, level_height);
+
+ const image* pSource_image = &img;
+
+ if (m_params.m_mip_fast)
+ {
+ if (level > 1)
+ pSource_image = &mips[level - 1];
+ }
+
+ bool status = image_resample(*pSource_image, level_img, m_params.m_mip_srgb, m_params.m_mip_filter.c_str(), m_params.m_mip_scale, m_params.m_mip_wrapping, 0, has_alpha ? 4 : 3);
+ if (!status)
+ {
+ error_printf("basis_compressor::generate_mipmaps: image_resample() failed!\n");
+ return false;
+ }
+
+ if (m_params.m_mip_renormalize)
+ level_img.renormalize_normal_map();
+ }
+#endif
+
+ if (m_params.m_debug)
+ debug_printf("Total mipmap generation time: %f secs\n", tm.get_elapsed_secs());
+
+ return true;
+ }
+
+ bool basis_compressor::read_source_images()
+ {
+ debug_printf("basis_compressor::read_source_images\n");
+
+ const uint32_t total_source_files = m_params.m_read_source_images ? (uint32_t)m_params.m_source_filenames.size() : (uint32_t)m_params.m_source_images.size();
+ if (!total_source_files)
+ return false;
+
+ m_stats.resize(0);
+ m_slice_descs.resize(0);
+ m_slice_images.resize(0);
+
+ m_total_blocks = 0;
+ uint32_t total_macroblocks = 0;
+
+ m_any_source_image_has_alpha = false;
+
+ basisu::vector<image> source_images;
+ basisu::vector<std::string> source_filenames;
+
+ // First load all source images, and determine if any have an alpha channel.
+ for (uint32_t source_file_index = 0; source_file_index < total_source_files; source_file_index++)
+ {
+ const char *pSource_filename = "";
+
+ image file_image;
+
+ if (m_params.m_read_source_images)
+ {
+ pSource_filename = m_params.m_source_filenames[source_file_index].c_str();
+
+ // Load the source image
+ if (!load_image(pSource_filename, file_image))
+ {
+ error_printf("Failed reading source image: %s\n", pSource_filename);
+ return false;
+ }
+
+ printf("Read source image \"%s\", %ux%u\n", pSource_filename, file_image.get_width(), file_image.get_height());
+
+ // Optionally load another image and put a grayscale version of it into the alpha channel.
+ if ((source_file_index < m_params.m_source_alpha_filenames.size()) && (m_params.m_source_alpha_filenames[source_file_index].size()))
+ {
+ const char *pSource_alpha_image = m_params.m_source_alpha_filenames[source_file_index].c_str();
+
+ image alpha_data;
+
+ if (!load_image(pSource_alpha_image, alpha_data))
+ {
+ error_printf("Failed reading source image: %s\n", pSource_alpha_image);
+ return false;
+ }
+
+ printf("Read source alpha image \"%s\", %ux%u\n", pSource_alpha_image, alpha_data.get_width(), alpha_data.get_height());
+
+ alpha_data.crop(file_image.get_width(), file_image.get_height());
+
+ for (uint32_t y = 0; y < file_image.get_height(); y++)
+ for (uint32_t x = 0; x < file_image.get_width(); x++)
+ file_image(x, y).a = (uint8_t)alpha_data(x, y).get_709_luma();
+ }
+ }
+ else
+ {
+ file_image = m_params.m_source_images[source_file_index];
+ }
+
+ if (m_params.m_renormalize)
+ file_image.renormalize_normal_map();
+
+ bool alpha_swizzled = false;
+ if (m_params.m_swizzle[0] != 0 ||
+ m_params.m_swizzle[1] != 1 ||
+ m_params.m_swizzle[2] != 2 ||
+ m_params.m_swizzle[3] != 3)
+ {
+ // Used for XY normal maps in RG - puts X in color, Y in alpha
+ for (uint32_t y = 0; y < file_image.get_height(); y++)
+ for (uint32_t x = 0; x < file_image.get_width(); x++)
+ {
+ const color_rgba &c = file_image(x, y);
+ file_image(x, y).set_noclamp_rgba(c[m_params.m_swizzle[0]], c[m_params.m_swizzle[1]], c[m_params.m_swizzle[2]], c[m_params.m_swizzle[3]]);
+ }
+ alpha_swizzled = m_params.m_swizzle[3] != 3;
+ }
+
+ bool has_alpha = false;
+ if (m_params.m_force_alpha || alpha_swizzled)
+ has_alpha = true;
+ else if (!m_params.m_check_for_alpha)
+ file_image.set_alpha(255);
+ else if (file_image.has_alpha())
+ has_alpha = true;
+
+ if (has_alpha)
+ m_any_source_image_has_alpha = true;
+
+ debug_printf("Source image index %u filename %s %ux%u has alpha: %u\n", source_file_index, pSource_filename, file_image.get_width(), file_image.get_height(), has_alpha);
+
+ if (m_params.m_y_flip)
+ file_image.flip_y();
+
+#if DEBUG_EXTRACT_SINGLE_BLOCK
+ image block_image(4, 4);
+ const uint32_t block_x = 0;
+ const uint32_t block_y = 0;
+ block_image.blit(block_x * 4, block_y * 4, 4, 4, 0, 0, file_image, 0);
+ file_image = block_image;
+#endif
+
+#if DEBUG_CROP_TEXTURE_TO_64x64
+ file_image.resize(64, 64);
+#endif
+
+ if (m_params.m_resample_width > 0 && m_params.m_resample_height > 0)
+ {
+ int new_width = basisu::minimum<int>(m_params.m_resample_width, BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION);
+ int new_height = basisu::minimum<int>(m_params.m_resample_height, BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION);
+
+ debug_printf("Resampling to %ix%i\n", new_width, new_height);
+
+ // TODO: A box filter - kaiser looks too sharp on video. Let the caller control this.
+ image temp_img(new_width, new_height);
+ image_resample(file_image, temp_img, m_params.m_perceptual, "box"); // "kaiser");
+ temp_img.swap(file_image);
+ }
+ else if (m_params.m_resample_factor > 0.0f)
+ {
+ int new_width = basisu::minimum<int>(basisu::maximum(1, (int)ceilf(file_image.get_width() * m_params.m_resample_factor)), BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION);
+ int new_height = basisu::minimum<int>(basisu::maximum(1, (int)ceilf(file_image.get_height() * m_params.m_resample_factor)), BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION);
+
+ debug_printf("Resampling to %ix%i\n", new_width, new_height);
+
+ // TODO: A box filter - kaiser looks too sharp on video. Let the caller control this.
+ image temp_img(new_width, new_height);
+ image_resample(file_image, temp_img, m_params.m_perceptual, "box"); // "kaiser");
+ temp_img.swap(file_image);
+ }
+
+ if ((!file_image.get_width()) || (!file_image.get_height()))
+ {
+ error_printf("basis_compressor::read_source_images: Source image has a zero width and/or height!\n");
+ return false;
+ }
+
+ if ((file_image.get_width() > BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION) || (file_image.get_height() > BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION))
+ {
+ error_printf("basis_compressor::read_source_images: Source image is too large!\n");
+ return false;
+ }
+
+ source_images.push_back(file_image);
+ source_filenames.push_back(pSource_filename);
+ }
+
+ // Check if the caller has generated their own mipmaps.
+ if (m_params.m_source_mipmap_images.size())
+ {
+ // Make sure they've passed us enough mipmap chains.
+ if ((m_params.m_source_images.size() != m_params.m_source_mipmap_images.size()) || (total_source_files != m_params.m_source_images.size()))
+ {
+ error_printf("basis_compressor::read_source_images(): m_params.m_source_mipmap_images.size() must equal m_params.m_source_images.size()!\n");
+ return false;
+ }
+
+ // Check if any of the user-supplied mipmap levels has alpha.
+ // We're assuming the user has already preswizzled their mipmap source images.
+ if (!m_any_source_image_has_alpha)
+ {
+ for (uint32_t source_file_index = 0; source_file_index < total_source_files; source_file_index++)
+ {
+ for (uint32_t mip_index = 0; mip_index < m_params.m_source_mipmap_images[source_file_index].size(); mip_index++)
+ {
+ const image& mip_img = m_params.m_source_mipmap_images[source_file_index][mip_index];
+
+ if (mip_img.has_alpha())
+ {
+ m_any_source_image_has_alpha = true;
+ break;
+ }
+ }
+
+ if (m_any_source_image_has_alpha)
+ break;
+ }
+ }
+ }
+
+ debug_printf("Any source image has alpha: %u\n", m_any_source_image_has_alpha);
+
+ for (uint32_t source_file_index = 0; source_file_index < total_source_files; source_file_index++)
+ {
+ image &file_image = source_images[source_file_index];
+ const std::string &source_filename = source_filenames[source_file_index];
+
+ // Now, for each source image, create the slices corresponding to that image.
+ basisu::vector<image> slices;
+
+ slices.reserve(32);
+
+ // The first (largest) mipmap level.
+ slices.push_back(file_image);
+
+ if (m_params.m_source_mipmap_images.size())
+ {
+ // User-provided mipmaps for each layer or image in the texture array.
+ for (uint32_t mip_index = 0; mip_index < m_params.m_source_mipmap_images[source_file_index].size(); mip_index++)
+ {
+ image& mip_img = m_params.m_source_mipmap_images[source_file_index][mip_index];
+
+ if (m_params.m_swizzle[0] != 0 ||
+ m_params.m_swizzle[1] != 1 ||
+ m_params.m_swizzle[2] != 2 ||
+ m_params.m_swizzle[3] != 3)
+ {
+ // Used for XY normal maps in RG - puts X in color, Y in alpha
+ for (uint32_t y = 0; y < mip_img.get_height(); y++)
+ for (uint32_t x = 0; x < mip_img.get_width(); x++)
+ {
+ const color_rgba &c = mip_img(x, y);
+ mip_img(x, y).set_noclamp_rgba(c[m_params.m_swizzle[0]], c[m_params.m_swizzle[1]], c[m_params.m_swizzle[2]], c[m_params.m_swizzle[3]]);
+ }
+ }
+
+ slices.push_back(mip_img);
+ }
+ }
+ else if (m_params.m_mip_gen)
+ {
+ // Automatically generate mipmaps.
+ if (!generate_mipmaps(file_image, slices, m_any_source_image_has_alpha))
+ return false;
+ }
+
+ uint_vec mip_indices(slices.size());
+ for (uint32_t i = 0; i < slices.size(); i++)
+ mip_indices[i] = i;
+
+ if ((m_any_source_image_has_alpha) && (!m_params.m_uastc))
+ {
+ // For ETC1S, if source has alpha, then even mips will have RGB, and odd mips will have alpha in RGB.
+ basisu::vector<image> alpha_slices;
+ uint_vec new_mip_indices;
+
+ alpha_slices.reserve(slices.size() * 2);
+
+ for (uint32_t i = 0; i < slices.size(); i++)
+ {
+ image lvl_rgb(slices[i]);
+ image lvl_a(lvl_rgb);
+
+ for (uint32_t y = 0; y < lvl_a.get_height(); y++)
+ {
+ for (uint32_t x = 0; x < lvl_a.get_width(); x++)
+ {
+ uint8_t a = lvl_a(x, y).a;
+ lvl_a(x, y).set_noclamp_rgba(a, a, a, 255);
+ }
+ }
+
+ lvl_rgb.set_alpha(255);
+
+ alpha_slices.push_back(lvl_rgb);
+ new_mip_indices.push_back(i);
+
+ alpha_slices.push_back(lvl_a);
+ new_mip_indices.push_back(i);
+ }
+
+ slices.swap(alpha_slices);
+ mip_indices.swap(new_mip_indices);
+ }
+
+ assert(slices.size() == mip_indices.size());
+
+ for (uint32_t slice_index = 0; slice_index < slices.size(); slice_index++)
+ {
+ image& slice_image = slices[slice_index];
+ const uint32_t orig_width = slice_image.get_width();
+ const uint32_t orig_height = slice_image.get_height();
+
+ bool is_alpha_slice = false;
+ if (m_any_source_image_has_alpha)
+ {
+ if (m_params.m_uastc)
+ {
+ is_alpha_slice = slice_image.has_alpha();
+ }
+ else
+ {
+ is_alpha_slice = (slice_index & 1) != 0;
+ }
+ }
+
+ // Enlarge the source image to 4x4 block boundaries, duplicating edge pixels if necessary to avoid introducing extra colors into blocks.
+ slice_image.crop_dup_borders(slice_image.get_block_width(4) * 4, slice_image.get_block_height(4) * 4);
+
+ if (m_params.m_debug_images)
+ {
+ save_png(string_format("basis_debug_source_image_%u_slice_%u.png", source_file_index, slice_index).c_str(), slice_image);
+ }
+
+ enlarge_vector(m_stats, 1);
+ enlarge_vector(m_slice_images, 1);
+ enlarge_vector(m_slice_descs, 1);
+
+ const uint32_t dest_image_index = (uint32_t)m_stats.size() - 1;
+
+ m_stats[dest_image_index].m_filename = source_filename.c_str();
+ m_stats[dest_image_index].m_width = orig_width;
+ m_stats[dest_image_index].m_height = orig_height;
+
+ m_slice_images[dest_image_index] = slice_image;
+
+ debug_printf("****** Slice %u: mip %u, alpha_slice: %u, filename: \"%s\", original: %ux%u actual: %ux%u\n", m_slice_descs.size() - 1, mip_indices[slice_index], is_alpha_slice, source_filename.c_str(), orig_width, orig_height, slice_image.get_width(), slice_image.get_height());
+
+ basisu_backend_slice_desc &slice_desc = m_slice_descs[dest_image_index];
+
+ slice_desc.m_first_block_index = m_total_blocks;
+
+ slice_desc.m_orig_width = orig_width;
+ slice_desc.m_orig_height = orig_height;
+
+ slice_desc.m_width = slice_image.get_width();
+ slice_desc.m_height = slice_image.get_height();
+
+ slice_desc.m_num_blocks_x = slice_image.get_block_width(4);
+ slice_desc.m_num_blocks_y = slice_image.get_block_height(4);
+
+ slice_desc.m_num_macroblocks_x = (slice_desc.m_num_blocks_x + 1) >> 1;
+ slice_desc.m_num_macroblocks_y = (slice_desc.m_num_blocks_y + 1) >> 1;
+
+ slice_desc.m_source_file_index = source_file_index;
+
+ slice_desc.m_mip_index = mip_indices[slice_index];
+
+ slice_desc.m_alpha = is_alpha_slice;
+ slice_desc.m_iframe = false;
+ if (m_params.m_tex_type == basist::cBASISTexTypeVideoFrames)
+ {
+ slice_desc.m_iframe = (source_file_index == 0);
+ }
+
+ m_total_blocks += slice_desc.m_num_blocks_x * slice_desc.m_num_blocks_y;
+ total_macroblocks += slice_desc.m_num_macroblocks_x * slice_desc.m_num_macroblocks_y;
+
+ } // slice_index
+
+ } // source_file_index
+
+ debug_printf("Total blocks: %u, Total macroblocks: %u\n", m_total_blocks, total_macroblocks);
+
+ // Make sure we don't have too many slices
+ if (m_slice_descs.size() > BASISU_MAX_SLICES)
+ {
+ error_printf("Too many slices!\n");
+ return false;
+ }
+
+ // Basic sanity check on the slices
+ for (uint32_t i = 1; i < m_slice_descs.size(); i++)
+ {
+ const basisu_backend_slice_desc &prev_slice_desc = m_slice_descs[i - 1];
+ const basisu_backend_slice_desc &slice_desc = m_slice_descs[i];
+
+ // Make sure images are in order
+ int image_delta = (int)slice_desc.m_source_file_index - (int)prev_slice_desc.m_source_file_index;
+ if (image_delta > 1)
+ return false;
+
+ // Make sure mipmap levels are in order
+ if (!image_delta)
+ {
+ int level_delta = (int)slice_desc.m_mip_index - (int)prev_slice_desc.m_mip_index;
+ if (level_delta > 1)
+ return false;
+ }
+ }
+
+ if (m_params.m_status_output)
+ {
+ printf("Total basis file slices: %u\n", (uint32_t)m_slice_descs.size());
+ }
+
+ for (uint32_t i = 0; i < m_slice_descs.size(); i++)
+ {
+ const basisu_backend_slice_desc &slice_desc = m_slice_descs[i];
+
+ if (m_params.m_status_output)
+ {
+ printf("Slice: %u, alpha: %u, orig width/height: %ux%u, width/height: %ux%u, first_block: %u, image_index: %u, mip_level: %u, iframe: %u\n",
+ i, slice_desc.m_alpha, slice_desc.m_orig_width, slice_desc.m_orig_height, slice_desc.m_width, slice_desc.m_height, slice_desc.m_first_block_index, slice_desc.m_source_file_index, slice_desc.m_mip_index, slice_desc.m_iframe);
+ }
+
+ if (m_any_source_image_has_alpha)
+ {
+ if (!m_params.m_uastc)
+ {
+ // For ETC1S, alpha slices must be at odd slice indices.
+ if (slice_desc.m_alpha)
+ {
+ if ((i & 1) == 0)
+ return false;
+
+ const basisu_backend_slice_desc& prev_slice_desc = m_slice_descs[i - 1];
+
+ // Make sure previous slice has this image's color data
+ if (prev_slice_desc.m_source_file_index != slice_desc.m_source_file_index)
+ return false;
+ if (prev_slice_desc.m_alpha)
+ return false;
+ if (prev_slice_desc.m_mip_index != slice_desc.m_mip_index)
+ return false;
+ if (prev_slice_desc.m_num_blocks_x != slice_desc.m_num_blocks_x)
+ return false;
+ if (prev_slice_desc.m_num_blocks_y != slice_desc.m_num_blocks_y)
+ return false;
+ }
+ else if (i & 1)
+ return false;
+ }
+ }
+ else if (slice_desc.m_alpha)
+ {
+ return false;
+ }
+
+ if ((slice_desc.m_orig_width > slice_desc.m_width) || (slice_desc.m_orig_height > slice_desc.m_height))
+ return false;
+ if ((slice_desc.m_source_file_index == 0) && (m_params.m_tex_type == basist::cBASISTexTypeVideoFrames))
+ {
+ if (!slice_desc.m_iframe)
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // Do some basic validation for 2D arrays, cubemaps, video, and volumes.
+ bool basis_compressor::validate_texture_type_constraints()
+ {
+ debug_printf("basis_compressor::validate_texture_type_constraints\n");
+
+ // In 2D mode anything goes (each image may have a different resolution and # of mipmap levels).
+ if (m_params.m_tex_type == basist::cBASISTexType2D)
+ return true;
+
+ uint32_t total_basis_images = 0;
+
+ for (uint32_t slice_index = 0; slice_index < m_slice_images.size(); slice_index++)
+ {
+ const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
+
+ total_basis_images = maximum<uint32_t>(total_basis_images, slice_desc.m_source_file_index + 1);
+ }
+
+ if (m_params.m_tex_type == basist::cBASISTexTypeCubemapArray)
+ {
+ // For cubemaps, validate that the total # of Basis images is a multiple of 6.
+ if ((total_basis_images % 6) != 0)
+ {
+ error_printf("basis_compressor::validate_texture_type_constraints: For cubemaps the total number of input images is not a multiple of 6!\n");
+ return false;
+ }
+ }
+
+ // Now validate that all the mip0's have the same dimensions, and that each image has the same # of mipmap levels.
+ uint_vec image_mipmap_levels(total_basis_images);
+
+ int width = -1, height = -1;
+ for (uint32_t slice_index = 0; slice_index < m_slice_images.size(); slice_index++)
+ {
+ const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
+
+ image_mipmap_levels[slice_desc.m_source_file_index] = maximum(image_mipmap_levels[slice_desc.m_source_file_index], slice_desc.m_mip_index + 1);
+
+ if (slice_desc.m_mip_index != 0)
+ continue;
+
+ if (width < 0)
+ {
+ width = slice_desc.m_orig_width;
+ height = slice_desc.m_orig_height;
+ }
+ else if ((width != (int)slice_desc.m_orig_width) || (height != (int)slice_desc.m_orig_height))
+ {
+ error_printf("basis_compressor::validate_texture_type_constraints: The source image resolutions are not all equal!\n");
+ return false;
+ }
+ }
+
+ for (size_t i = 1; i < image_mipmap_levels.size(); i++)
+ {
+ if (image_mipmap_levels[0] != image_mipmap_levels[i])
+ {
+ error_printf("basis_compressor::validate_texture_type_constraints: Each image must have the same number of mipmap levels!\n");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool basis_compressor::extract_source_blocks()
+ {
+ debug_printf("basis_compressor::extract_source_blocks\n");
+
+ m_source_blocks.resize(m_total_blocks);
+
+ for (uint32_t slice_index = 0; slice_index < m_slice_images.size(); slice_index++)
+ {
+ const basisu_backend_slice_desc& slice_desc = m_slice_descs[slice_index];
+
+ const uint32_t num_blocks_x = slice_desc.m_num_blocks_x;
+ const uint32_t num_blocks_y = slice_desc.m_num_blocks_y;
+
+ const image& source_image = m_slice_images[slice_index];
+
+ for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
+ for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
+ source_image.extract_block_clamped(m_source_blocks[slice_desc.m_first_block_index + block_x + block_y * num_blocks_x].get_ptr(), block_x * 4, block_y * 4, 4, 4);
+ }
+
+ return true;
+ }
+
+ bool basis_compressor::process_frontend()
+ {
+ debug_printf("basis_compressor::process_frontend\n");
+
+#if 0
+ // TODO
+ basis_etc1_pack_params pack_params;
+ pack_params.m_quality = cETCQualityMedium;
+ pack_params.m_perceptual = m_params.m_perceptual;
+ pack_params.m_use_color4 = false;
+
+ pack_etc1_block_context pack_context;
+
+ std::unordered_set<uint64_t> endpoint_hash;
+ std::unordered_set<uint32_t> selector_hash;
+
+ for (uint32_t i = 0; i < m_source_blocks.size(); i++)
+ {
+ etc_block blk;
+ pack_etc1_block(blk, m_source_blocks[i].get_ptr(), pack_params, pack_context);
+
+ const color_rgba c0(blk.get_block_color(0, false));
+ endpoint_hash.insert((c0.r | (c0.g << 5) | (c0.b << 10)) | (blk.get_inten_table(0) << 16));
+
+ const color_rgba c1(blk.get_block_color(1, false));
+ endpoint_hash.insert((c1.r | (c1.g << 5) | (c1.b << 10)) | (blk.get_inten_table(1) << 16));
+
+ selector_hash.insert(blk.get_raw_selector_bits());
+ }
+
+ const uint32_t total_unique_endpoints = (uint32_t)endpoint_hash.size();
+ const uint32_t total_unique_selectors = (uint32_t)selector_hash.size();
+
+ if (m_params.m_debug)
+ {
+ debug_printf("Unique endpoints: %u, unique selectors: %u\n", total_unique_endpoints, total_unique_selectors);
+ }
+#endif
+
+ const double total_texels = m_total_blocks * 16.0f;
+
+ int endpoint_clusters = m_params.m_max_endpoint_clusters;
+ int selector_clusters = m_params.m_max_selector_clusters;
+
+ if (endpoint_clusters > basisu_frontend::cMaxEndpointClusters)
+ {
+ error_printf("Too many endpoint clusters! (%u but max is %u)\n", endpoint_clusters, basisu_frontend::cMaxEndpointClusters);
+ return false;
+ }
+ if (selector_clusters > basisu_frontend::cMaxSelectorClusters)
+ {
+ error_printf("Too many selector clusters! (%u but max is %u)\n", selector_clusters, basisu_frontend::cMaxSelectorClusters);
+ return false;
+ }
+
+ if (m_params.m_quality_level != -1)
+ {
+ const float quality = saturate(m_params.m_quality_level / 255.0f);
+
+ const float bits_per_endpoint_cluster = 14.0f;
+ const float max_desired_endpoint_cluster_bits_per_texel = 1.0f; // .15f
+ int max_endpoints = static_cast<int>((max_desired_endpoint_cluster_bits_per_texel * total_texels) / bits_per_endpoint_cluster);
+
+ const float mid = 128.0f / 255.0f;
+
+ float color_endpoint_quality = quality;
+
+ const float endpoint_split_point = 0.5f;
+
+ // In v1.2 and in previous versions, the endpoint codebook size at quality 128 was 3072. This wasn't quite large enough.
+ const int ENDPOINT_CODEBOOK_MID_QUALITY_CODEBOOK_SIZE = 4800;
+ const int MAX_ENDPOINT_CODEBOOK_SIZE = 8192;
+
+ if (color_endpoint_quality <= mid)
+ {
+ color_endpoint_quality = lerp(0.0f, endpoint_split_point, powf(color_endpoint_quality / mid, .65f));
+
+ max_endpoints = clamp<int>(max_endpoints, 256, ENDPOINT_CODEBOOK_MID_QUALITY_CODEBOOK_SIZE);
+ max_endpoints = minimum<uint32_t>(max_endpoints, m_total_blocks);
+
+ if (max_endpoints < 64)
+ max_endpoints = 64;
+ endpoint_clusters = clamp<uint32_t>((uint32_t)(.5f + lerp<float>(32, static_cast<float>(max_endpoints), color_endpoint_quality)), 32, basisu_frontend::cMaxEndpointClusters);
+ }
+ else
+ {
+ color_endpoint_quality = powf((color_endpoint_quality - mid) / (1.0f - mid), 1.6f);
+
+ max_endpoints = clamp<int>(max_endpoints, 256, MAX_ENDPOINT_CODEBOOK_SIZE);
+ max_endpoints = minimum<uint32_t>(max_endpoints, m_total_blocks);
+
+ if (max_endpoints < ENDPOINT_CODEBOOK_MID_QUALITY_CODEBOOK_SIZE)
+ max_endpoints = ENDPOINT_CODEBOOK_MID_QUALITY_CODEBOOK_SIZE;
+ endpoint_clusters = clamp<uint32_t>((uint32_t)(.5f + lerp<float>(ENDPOINT_CODEBOOK_MID_QUALITY_CODEBOOK_SIZE, static_cast<float>(max_endpoints), color_endpoint_quality)), 32, basisu_frontend::cMaxEndpointClusters);
+ }
+
+ float bits_per_selector_cluster = m_params.m_global_sel_pal ? 21.0f : 14.0f;
+
+ const float max_desired_selector_cluster_bits_per_texel = 1.0f; // .15f
+ int max_selectors = static_cast<int>((max_desired_selector_cluster_bits_per_texel * total_texels) / bits_per_selector_cluster);
+ max_selectors = clamp<int>(max_selectors, 256, basisu_frontend::cMaxSelectorClusters);
+ max_selectors = minimum<uint32_t>(max_selectors, m_total_blocks);
+
+ float color_selector_quality = quality;
+ //color_selector_quality = powf(color_selector_quality, 1.65f);
+ color_selector_quality = powf(color_selector_quality, 2.62f);
+
+ if (max_selectors < 96)
+ max_selectors = 96;
+ selector_clusters = clamp<uint32_t>((uint32_t)(.5f + lerp<float>(96, static_cast<float>(max_selectors), color_selector_quality)), 8, basisu_frontend::cMaxSelectorClusters);
+
+ debug_printf("Max endpoints: %u, max selectors: %u\n", endpoint_clusters, selector_clusters);
+
+ if (m_params.m_quality_level >= 223)
+ {
+ if (!m_params.m_selector_rdo_thresh.was_changed())
+ {
+ if (!m_params.m_endpoint_rdo_thresh.was_changed())
+ m_params.m_endpoint_rdo_thresh *= .25f;
+
+ if (!m_params.m_selector_rdo_thresh.was_changed())
+ m_params.m_selector_rdo_thresh *= .25f;
+ }
+ }
+ else if (m_params.m_quality_level >= 192)
+ {
+ if (!m_params.m_endpoint_rdo_thresh.was_changed())
+ m_params.m_endpoint_rdo_thresh *= .5f;
+
+ if (!m_params.m_selector_rdo_thresh.was_changed())
+ m_params.m_selector_rdo_thresh *= .5f;
+ }
+ else if (m_params.m_quality_level >= 160)
+ {
+ if (!m_params.m_endpoint_rdo_thresh.was_changed())
+ m_params.m_endpoint_rdo_thresh *= .75f;
+
+ if (!m_params.m_selector_rdo_thresh.was_changed())
+ m_params.m_selector_rdo_thresh *= .75f;
+ }
+ else if (m_params.m_quality_level >= 129)
+ {
+ float l = (quality - 129 / 255.0f) / ((160 - 129) / 255.0f);
+
+ if (!m_params.m_endpoint_rdo_thresh.was_changed())
+ m_params.m_endpoint_rdo_thresh *= lerp<float>(1.0f, .75f, l);
+
+ if (!m_params.m_selector_rdo_thresh.was_changed())
+ m_params.m_selector_rdo_thresh *= lerp<float>(1.0f, .75f, l);
+ }
+ }
+
+ m_auto_global_sel_pal = false;
+ if (!m_params.m_global_sel_pal && m_params.m_auto_global_sel_pal)
+ {
+ const float bits_per_selector_cluster = 31.0f;
+ double selector_codebook_bpp_est = (bits_per_selector_cluster * selector_clusters) / total_texels;
+ debug_printf("selector_codebook_bpp_est: %f\n", selector_codebook_bpp_est);
+ const float force_global_sel_pal_bpp_threshold = .15f;
+ if ((total_texels <= 128.0f*128.0f) && (selector_codebook_bpp_est > force_global_sel_pal_bpp_threshold))
+ {
+ m_auto_global_sel_pal = true;
+ debug_printf("Auto global selector palette enabled\n");
+ }
+ }
+
+ basisu_frontend::params p;
+ p.m_num_source_blocks = m_total_blocks;
+ p.m_pSource_blocks = &m_source_blocks[0];
+ p.m_max_endpoint_clusters = endpoint_clusters;
+ p.m_max_selector_clusters = selector_clusters;
+ p.m_perceptual = m_params.m_perceptual;
+ p.m_debug_stats = m_params.m_debug;
+ p.m_debug_images = m_params.m_debug_images;
+ p.m_compression_level = m_params.m_compression_level;
+ p.m_tex_type = m_params.m_tex_type;
+ p.m_multithreaded = m_params.m_multithreading;
+ p.m_disable_hierarchical_endpoint_codebooks = m_params.m_disable_hierarchical_endpoint_codebooks;
+ p.m_validate = m_params.m_validate;
+ p.m_pJob_pool = m_params.m_pJob_pool;
+ p.m_pGlobal_codebooks = m_params.m_pGlobal_codebooks;
+
+ if ((m_params.m_global_sel_pal) || (m_auto_global_sel_pal))
+ {
+ p.m_pGlobal_sel_codebook = m_params.m_pSel_codebook;
+ p.m_num_global_sel_codebook_pal_bits = m_params.m_global_pal_bits;
+ p.m_num_global_sel_codebook_mod_bits = m_params.m_global_mod_bits;
+ p.m_use_hybrid_selector_codebooks = !m_params.m_no_hybrid_sel_cb;
+ p.m_hybrid_codebook_quality_thresh = m_params.m_hybrid_sel_cb_quality_thresh;
+ }
+
+ if (!m_frontend.init(p))
+ {
+ error_printf("basisu_frontend::init() failed!\n");
+ return false;
+ }
+
+ m_frontend.compress();
+
+ if (m_params.m_debug_images)
+ {
+ for (uint32_t i = 0; i < m_slice_descs.size(); i++)
+ {
+ char filename[1024];
+#ifdef _WIN32
+ sprintf_s(filename, sizeof(filename), "rdo_frontend_output_output_blocks_%u.png", i);
+#else
+ snprintf(filename, sizeof(filename), "rdo_frontend_output_output_blocks_%u.png", i);
+#endif
+ m_frontend.dump_debug_image(filename, m_slice_descs[i].m_first_block_index, m_slice_descs[i].m_num_blocks_x, m_slice_descs[i].m_num_blocks_y, true);
+
+#ifdef _WIN32
+ sprintf_s(filename, sizeof(filename), "rdo_frontend_output_api_%u.png", i);
+#else
+ snprintf(filename, sizeof(filename), "rdo_frontend_output_api_%u.png", i);
+#endif
+ m_frontend.dump_debug_image(filename, m_slice_descs[i].m_first_block_index, m_slice_descs[i].m_num_blocks_x, m_slice_descs[i].m_num_blocks_y, false);
+ }
+ }
+
+ return true;
+ }
+
+ bool basis_compressor::extract_frontend_texture_data()
+ {
+ debug_printf("basis_compressor::extract_frontend_texture_data\n");
+
+ m_frontend_output_textures.resize(m_slice_descs.size());
+ m_best_etc1s_images.resize(m_slice_descs.size());
+ m_best_etc1s_images_unpacked.resize(m_slice_descs.size());
+
+ for (uint32_t i = 0; i < m_slice_descs.size(); i++)
+ {
+ const basisu_backend_slice_desc &slice_desc = m_slice_descs[i];
+
+ const uint32_t num_blocks_x = slice_desc.m_num_blocks_x;
+ const uint32_t num_blocks_y = slice_desc.m_num_blocks_y;
+
+ const uint32_t width = num_blocks_x * 4;
+ const uint32_t height = num_blocks_y * 4;
+
+ m_frontend_output_textures[i].init(texture_format::cETC1, width, height);
+
+ for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
+ for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
+ memcpy(m_frontend_output_textures[i].get_block_ptr(block_x, block_y, 0), &m_frontend.get_output_block(slice_desc.m_first_block_index + block_x + block_y * num_blocks_x), sizeof(etc_block));
+
+#if 0
+ if (m_params.m_debug_images)
+ {
+ char filename[1024];
+ sprintf_s(filename, sizeof(filename), "rdo_etc_frontend_%u_", i);
+ write_etc1_vis_images(m_frontend_output_textures[i], filename);
+ }
+#endif
+
+ m_best_etc1s_images[i].init(texture_format::cETC1, width, height);
+ for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
+ for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
+ memcpy(m_best_etc1s_images[i].get_block_ptr(block_x, block_y, 0), &m_frontend.get_etc1s_block(slice_desc.m_first_block_index + block_x + block_y * num_blocks_x), sizeof(etc_block));
+
+ m_best_etc1s_images[i].unpack(m_best_etc1s_images_unpacked[i]);
+ }
+
+ return true;
+ }
+
+ bool basis_compressor::process_backend()
+ {
+ debug_printf("basis_compressor::process_backend\n");
+
+ basisu_backend_params backend_params;
+ backend_params.m_debug = m_params.m_debug;
+ backend_params.m_debug_images = m_params.m_debug_images;
+ backend_params.m_etc1s = true;
+ backend_params.m_compression_level = m_params.m_compression_level;
+
+ if (!m_params.m_no_endpoint_rdo)
+ backend_params.m_endpoint_rdo_quality_thresh = m_params.m_endpoint_rdo_thresh;
+
+ if (!m_params.m_no_selector_rdo)
+ backend_params.m_selector_rdo_quality_thresh = m_params.m_selector_rdo_thresh;
+
+ backend_params.m_use_global_sel_codebook = (m_frontend.get_params().m_pGlobal_sel_codebook != NULL);
+ backend_params.m_global_sel_codebook_pal_bits = m_frontend.get_params().m_num_global_sel_codebook_pal_bits;
+ backend_params.m_global_sel_codebook_mod_bits = m_frontend.get_params().m_num_global_sel_codebook_mod_bits;
+ backend_params.m_use_hybrid_sel_codebooks = m_frontend.get_params().m_use_hybrid_selector_codebooks;
+ backend_params.m_used_global_codebooks = m_frontend.get_params().m_pGlobal_codebooks != nullptr;
+
+ m_backend.init(&m_frontend, backend_params, m_slice_descs, m_params.m_pSel_codebook);
+ uint32_t total_packed_bytes = m_backend.encode();
+
+ if (!total_packed_bytes)
+ {
+ error_printf("basis_compressor::encode() failed!\n");
+ return false;
+ }
+
+ debug_printf("Total packed bytes (estimated): %u\n", total_packed_bytes);
+
+ return true;
+ }
+
+ bool basis_compressor::create_basis_file_and_transcode()
+ {
+ debug_printf("basis_compressor::create_basis_file_and_transcode\n");
+
+ const basisu_backend_output& encoded_output = m_params.m_uastc ? m_uastc_backend_output : m_backend.get_output();
+
+ if (!m_basis_file.init(encoded_output, m_params.m_tex_type, m_params.m_userdata0, m_params.m_userdata1, m_params.m_y_flip, m_params.m_us_per_frame))
+ {
+ error_printf("basis_compressor::create_basis_file_and_transcode: basisu_backend:init() failed!\n");
+ return false;
+ }
+
+ const uint8_vec &comp_data = m_basis_file.get_compressed_data();
+
+ m_output_basis_file = comp_data;
+
+ interval_timer tm;
+ tm.start();
+
+ basist::basisu_transcoder_init();
+
+ debug_printf("basist::basisu_transcoder_init: Took %f ms\n", tm.get_elapsed_ms());
+
+ // Verify the compressed data by transcoding it to ASTC (or ETC1)/BC7 and validating the CRC's.
+ basist::basisu_transcoder decoder(m_params.m_pSel_codebook);
+ if (!decoder.validate_file_checksums(&comp_data[0], (uint32_t)comp_data.size(), true))
+ {
+ error_printf("decoder.validate_file_checksums() failed!\n");
+ return false;
+ }
+
+ m_decoded_output_textures.resize(m_slice_descs.size());
+ m_decoded_output_textures_unpacked.resize(m_slice_descs.size());
+
+ m_decoded_output_textures_bc7.resize(m_slice_descs.size());
+ m_decoded_output_textures_unpacked_bc7.resize(m_slice_descs.size());
+
+ tm.start();
+ if (m_params.m_pGlobal_codebooks)
+ {
+ decoder.set_global_codebooks(m_params.m_pGlobal_codebooks);
+ }
+
+ if (!decoder.start_transcoding(&comp_data[0], (uint32_t)comp_data.size()))
+ {
+ error_printf("decoder.start_transcoding() failed!\n");
+ return false;
+ }
+
+ double start_transcoding_time = tm.get_elapsed_secs();
+
+ debug_printf("basisu_compressor::start_transcoding() took %3.3fms\n", start_transcoding_time * 1000.0f);
+
+ uint32_t total_orig_pixels = 0;
+ uint32_t total_texels = 0;
+
+ double total_time_etc1s_or_astc = 0;
+
+ for (uint32_t i = 0; i < m_slice_descs.size(); i++)
+ {
+ gpu_image decoded_texture;
+ decoded_texture.init(m_params.m_uastc ? texture_format::cASTC4x4 : texture_format::cETC1, m_slice_descs[i].m_width, m_slice_descs[i].m_height);
+
+ tm.start();
+
+ basist::block_format format = m_params.m_uastc ? basist::block_format::cASTC_4x4 : basist::block_format::cETC1;
+ uint32_t bytes_per_block = m_params.m_uastc ? 16 : 8;
+
+ if (!decoder.transcode_slice(&comp_data[0], (uint32_t)comp_data.size(), i,
+ reinterpret_cast<etc_block *>(decoded_texture.get_ptr()), m_slice_descs[i].m_num_blocks_x * m_slice_descs[i].m_num_blocks_y, format, bytes_per_block))
+ {
+ error_printf("Transcoding failed on slice %u!\n", i);
+ return false;
+ }
+
+ total_time_etc1s_or_astc += tm.get_elapsed_secs();
+
+ if (encoded_output.m_tex_format == basist::basis_tex_format::cETC1S)
+ {
+ uint32_t image_crc16 = basist::crc16(decoded_texture.get_ptr(), decoded_texture.get_size_in_bytes(), 0);
+ if (image_crc16 != encoded_output.m_slice_image_crcs[i])
+ {
+ error_printf("Decoded image data CRC check failed on slice %u!\n", i);
+ return false;
+ }
+ debug_printf("Decoded image data CRC check succeeded on slice %i\n", i);
+ }
+
+ m_decoded_output_textures[i] = decoded_texture;
+
+ total_orig_pixels += m_slice_descs[i].m_orig_width * m_slice_descs[i].m_orig_height;
+ total_texels += m_slice_descs[i].m_width * m_slice_descs[i].m_height;
+ }
+
+ double total_time_bc7 = 0;
+
+ if (basist::basis_is_format_supported(basist::transcoder_texture_format::cTFBC7_RGBA, basist::basis_tex_format::cUASTC4x4) &&
+ basist::basis_is_format_supported(basist::transcoder_texture_format::cTFBC7_RGBA, basist::basis_tex_format::cETC1S))
+ {
+ for (uint32_t i = 0; i < m_slice_descs.size(); i++)
+ {
+ gpu_image decoded_texture;
+ decoded_texture.init(texture_format::cBC7, m_slice_descs[i].m_width, m_slice_descs[i].m_height);
+
+ tm.start();
+
+ if (!decoder.transcode_slice(&comp_data[0], (uint32_t)comp_data.size(), i,
+ reinterpret_cast<etc_block*>(decoded_texture.get_ptr()), m_slice_descs[i].m_num_blocks_x * m_slice_descs[i].m_num_blocks_y, basist::block_format::cBC7, 16))
+ {
+ error_printf("Transcoding failed to BC7 on slice %u!\n", i);
+ return false;
+ }
+
+ total_time_bc7 += tm.get_elapsed_secs();
+
+ m_decoded_output_textures_bc7[i] = decoded_texture;
+ }
+ }
+
+ for (uint32_t i = 0; i < m_slice_descs.size(); i++)
+ {
+ m_decoded_output_textures[i].unpack(m_decoded_output_textures_unpacked[i]);
+
+ if (m_decoded_output_textures_bc7[i].get_pixel_width())
+ m_decoded_output_textures_bc7[i].unpack(m_decoded_output_textures_unpacked_bc7[i]);
+ }
+
+ debug_printf("Transcoded to %s in %3.3fms, %f texels/sec\n", m_params.m_uastc ? "ASTC" : "ETC1", total_time_etc1s_or_astc * 1000.0f, total_orig_pixels / total_time_etc1s_or_astc);
+
+ if (total_time_bc7 != 0)
+ debug_printf("Transcoded to BC7 in %3.3fms, %f texels/sec\n", total_time_bc7 * 1000.0f, total_orig_pixels / total_time_bc7);
+
+ debug_printf("Total .basis output file size: %u, %3.3f bits/texel\n", comp_data.size(), comp_data.size() * 8.0f / total_orig_pixels);
+
+ uint32_t total_orig_texels = 0;
+ for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++)
+ {
+ const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
+
+ total_orig_texels += slice_desc.m_orig_width * slice_desc.m_orig_height;
+
+ const uint32_t total_blocks = slice_desc.m_num_blocks_x * slice_desc.m_num_blocks_y;
+ BASISU_NOTE_UNUSED(total_blocks);
+
+ assert(m_decoded_output_textures[slice_index].get_total_blocks() == total_blocks);
+ }
+
+ m_basis_file_size = (uint32_t)comp_data.size();
+ m_basis_bits_per_texel = (comp_data.size() * 8.0f) / total_orig_texels;
+
+ return true;
+ }
+
+ bool basis_compressor::write_output_files_and_compute_stats()
+ {
+ debug_printf("basis_compressor::write_output_files_and_compute_stats\n");
+
+ const uint8_vec& comp_data = m_params.m_create_ktx2_file ? m_output_ktx2_file : m_basis_file.get_compressed_data();
+ if (m_params.m_write_output_basis_files)
+ {
+ const std::string& output_filename = m_params.m_out_filename;
+
+ if (!write_vec_to_file(output_filename.c_str(), comp_data))
+ {
+ error_printf("Failed writing output data to file \"%s\"\n", output_filename.c_str());
+ return false;
+ }
+
+ printf("Wrote output .basis/.ktx2 file \"%s\"\n", output_filename.c_str());
+ }
+
+ size_t comp_size = 0;
+ if ((m_params.m_compute_stats) && (m_params.m_uastc) && (comp_data.size()))
+ {
+ void* pComp_data = tdefl_compress_mem_to_heap(&comp_data[0], comp_data.size(), &comp_size, TDEFL_MAX_PROBES_MASK);// TDEFL_DEFAULT_MAX_PROBES);
+ size_t decomp_size = 0;
+ void* pDecomp_data = tinfl_decompress_mem_to_heap(pComp_data, comp_size, &decomp_size, 0);
+ if ((decomp_size != comp_data.size()) || (memcmp(pDecomp_data, &comp_data[0], decomp_size) != 0))
+ {
+ printf("basis_compressor::create_basis_file_and_transcode:: miniz compression or decompression failed!\n");
+ return false;
+ }
+
+ mz_free(pComp_data);
+ mz_free(pDecomp_data);
+
+ uint32_t total_texels = 0;
+ for (uint32_t i = 0; i < m_slice_descs.size(); i++)
+ total_texels += (m_slice_descs[i].m_num_blocks_x * m_slice_descs[i].m_num_blocks_y) * 16;
+
+ m_basis_bits_per_texel = comp_size * 8.0f / total_texels;
+
+ debug_printf(".basis file size: %u, LZ compressed file size: %u, %3.2f bits/texel\n",
+ (uint32_t)comp_data.size(),
+ (uint32_t)comp_size,
+ m_basis_bits_per_texel);
+ }
+
+ m_stats.resize(m_slice_descs.size());
+
+ uint32_t total_orig_texels = 0;
+
+ for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++)
+ {
+ const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
+
+ total_orig_texels += slice_desc.m_orig_width * slice_desc.m_orig_height;
+
+ if (m_params.m_compute_stats)
+ {
+ printf("Slice: %u\n", slice_index);
+
+ image_stats &s = m_stats[slice_index];
+
+ // TODO: We used to output SSIM (during heavy encoder development), but this slowed down compression too much. We'll be adding it back.
+
+ image_metrics em;
+
+ // ---- .basis stats
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 3);
+ em.print(".basis RGB Avg: ");
+ s.m_basis_rgb_avg_psnr = em.m_psnr;
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 4);
+ em.print(".basis RGBA Avg: ");
+ s.m_basis_rgba_avg_psnr = em.m_psnr;
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 1);
+ em.print(".basis R Avg: ");
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 1, 1);
+ em.print(".basis G Avg: ");
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 2, 1);
+ em.print(".basis B Avg: ");
+
+ if (m_params.m_uastc)
+ {
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 3, 1);
+ em.print(".basis A Avg: ");
+
+ s.m_basis_a_avg_psnr = em.m_psnr;
+ }
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 0);
+ em.print(".basis 709 Luma: ");
+ s.m_basis_luma_709_psnr = static_cast<float>(em.m_psnr);
+ s.m_basis_luma_709_ssim = static_cast<float>(em.m_ssim);
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 0, true, true);
+ em.print(".basis 601 Luma: ");
+ s.m_basis_luma_601_psnr = static_cast<float>(em.m_psnr);
+
+ if (m_slice_descs.size() == 1)
+ {
+ const uint32_t output_size = comp_size ? (uint32_t)comp_size : (uint32_t)comp_data.size();
+ debug_printf(".basis RGB PSNR per bit/texel*10000: %3.3f\n", 10000.0f * s.m_basis_rgb_avg_psnr / ((output_size * 8.0f) / (slice_desc.m_orig_width * slice_desc.m_orig_height)));
+ debug_printf(".basis Luma 709 PSNR per bit/texel*10000: %3.3f\n", 10000.0f * s.m_basis_luma_709_psnr / ((output_size * 8.0f) / (slice_desc.m_orig_width * slice_desc.m_orig_height)));
+ }
+
+ if (m_decoded_output_textures_unpacked_bc7[slice_index].get_width())
+ {
+ // ---- BC7 stats
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 0, 3);
+ em.print("BC7 RGB Avg: ");
+ s.m_bc7_rgb_avg_psnr = em.m_psnr;
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 0, 4);
+ em.print("BC7 RGBA Avg: ");
+ s.m_bc7_rgba_avg_psnr = em.m_psnr;
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 0, 1);
+ em.print("BC7 R Avg: ");
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 1, 1);
+ em.print("BC7 G Avg: ");
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 2, 1);
+ em.print("BC7 B Avg: ");
+
+ if (m_params.m_uastc)
+ {
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 3, 1);
+ em.print("BC7 A Avg: ");
+
+ s.m_bc7_a_avg_psnr = em.m_psnr;
+ }
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 0, 0);
+ em.print("BC7 709 Luma: ");
+ s.m_bc7_luma_709_psnr = static_cast<float>(em.m_psnr);
+ s.m_bc7_luma_709_ssim = static_cast<float>(em.m_ssim);
+
+ em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc7[slice_index], 0, 0, true, true);
+ em.print("BC7 601 Luma: ");
+ s.m_bc7_luma_601_psnr = static_cast<float>(em.m_psnr);
+ }
+
+ if (!m_params.m_uastc)
+ {
+ // ---- Nearly best possible ETC1S stats
+ em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 0);
+ em.print("Unquantized ETC1S 709 Luma: ");
+
+ s.m_best_etc1s_luma_709_psnr = static_cast<float>(em.m_psnr);
+ s.m_best_etc1s_luma_709_ssim = static_cast<float>(em.m_ssim);
+
+ em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 0, true, true);
+ em.print("Unquantized ETC1S 601 Luma: ");
+
+ s.m_best_etc1s_luma_601_psnr = static_cast<float>(em.m_psnr);
+
+ em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 3);
+ em.print("Unquantized ETC1S RGB Avg: ");
+
+ s.m_best_etc1s_rgb_avg_psnr = static_cast<float>(em.m_psnr);
+ }
+ }
+
+ std::string out_basename;
+ if (m_params.m_out_filename.size())
+ string_get_filename(m_params.m_out_filename.c_str(), out_basename);
+ else if (m_params.m_source_filenames.size())
+ string_get_filename(m_params.m_source_filenames[slice_desc.m_source_file_index].c_str(), out_basename);
+
+ string_remove_extension(out_basename);
+ out_basename = "basis_debug_" + out_basename + string_format("_slice_%u", slice_index);
+
+ if ((!m_params.m_uastc) && (m_frontend.get_params().m_debug_images))
+ {
+ // Write "best" ETC1S debug images
+ if (!m_params.m_uastc)
+ {
+ gpu_image best_etc1s_gpu_image(m_best_etc1s_images[slice_index]);
+ best_etc1s_gpu_image.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height);
+ write_compressed_texture_file((out_basename + "_best_etc1s.ktx").c_str(), best_etc1s_gpu_image);
+
+ image best_etc1s_unpacked;
+ best_etc1s_gpu_image.unpack(best_etc1s_unpacked);
+ save_png(out_basename + "_best_etc1s.png", best_etc1s_unpacked);
+ }
+ }
+
+ if (m_params.m_debug_images)
+ {
+ // Write decoded ETC1S/ASTC debug images
+ {
+ gpu_image decoded_etc1s_or_astc(m_decoded_output_textures[slice_index]);
+ decoded_etc1s_or_astc.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height);
+ write_compressed_texture_file((out_basename + "_transcoded_etc1s_or_astc.ktx").c_str(), decoded_etc1s_or_astc);
+
+ image temp(m_decoded_output_textures_unpacked[slice_index]);
+ temp.crop(slice_desc.m_orig_width, slice_desc.m_orig_height);
+ save_png(out_basename + "_transcoded_etc1s_or_astc.png", temp);
+ }
+
+ // Write decoded BC7 debug images
+ if (m_decoded_output_textures_bc7[slice_index].get_pixel_width())
+ {
+ gpu_image decoded_bc7(m_decoded_output_textures_bc7[slice_index]);
+ decoded_bc7.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height);
+ write_compressed_texture_file((out_basename + "_transcoded_bc7.ktx").c_str(), decoded_bc7);
+
+ image temp(m_decoded_output_textures_unpacked_bc7[slice_index]);
+ temp.crop(slice_desc.m_orig_width, slice_desc.m_orig_height);
+ save_png(out_basename + "_transcoded_bc7.png", temp);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // Make sure all the mip 0's have the same dimensions and number of mipmap levels, or we can't encode the KTX2 file.
+ bool basis_compressor::validate_ktx2_constraints()
+ {
+ uint32_t base_width = 0, base_height = 0;
+ uint32_t total_layers = 0;
+ for (uint32_t i = 0; i < m_slice_descs.size(); i++)
+ {
+ if (m_slice_descs[i].m_mip_index == 0)
+ {
+ if (!base_width)
+ {
+ base_width = m_slice_descs[i].m_orig_width;
+ base_height = m_slice_descs[i].m_orig_height;
+ }
+ else
+ {
+ if ((m_slice_descs[i].m_orig_width != base_width) || (m_slice_descs[i].m_orig_height != base_height))
+ {
+ return false;
+ }
+ }
+
+ total_layers = maximum<uint32_t>(total_layers, m_slice_descs[i].m_source_file_index + 1);
+ }
+ }
+
+ basisu::vector<uint32_t> total_mips(total_layers);
+ for (uint32_t i = 0; i < m_slice_descs.size(); i++)
+ total_mips[m_slice_descs[i].m_source_file_index] = maximum<uint32_t>(total_mips[m_slice_descs[i].m_source_file_index], m_slice_descs[i].m_mip_index + 1);
+
+ for (uint32_t i = 1; i < total_layers; i++)
+ {
+ if (total_mips[0] != total_mips[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ static uint8_t g_ktx2_etc1s_nonalpha_dfd[44] = { 0x2C,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x28,0x0,0xA3,0x1,0x2,0x0,0x3,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3F,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF };
+ static uint8_t g_ktx2_etc1s_alpha_dfd[60] = { 0x3C,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x38,0x0,0xA3,0x1,0x2,0x0,0x3,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3F,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x40,0x0,0x3F,0xF,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF };
+ static uint8_t g_ktx2_uastc_nonalpha_dfd[44] = { 0x2C,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x28,0x0,0xA6,0x1,0x2,0x0,0x3,0x3,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7F,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF };
+ static uint8_t g_ktx2_uastc_alpha_dfd[44] = { 0x2C,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x28,0x0,0xA6,0x1,0x2,0x0,0x3,0x3,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7F,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF };
+
+ void basis_compressor::get_dfd(uint8_vec &dfd, const basist::ktx2_header &header)
+ {
+ const uint8_t* pDFD;
+ uint32_t dfd_len;
+
+ if (m_params.m_uastc)
+ {
+ if (m_any_source_image_has_alpha)
+ {
+ pDFD = g_ktx2_uastc_alpha_dfd;
+ dfd_len = sizeof(g_ktx2_uastc_alpha_dfd);
+ }
+ else
+ {
+ pDFD = g_ktx2_uastc_nonalpha_dfd;
+ dfd_len = sizeof(g_ktx2_uastc_nonalpha_dfd);
+ }
+ }
+ else
+ {
+ if (m_any_source_image_has_alpha)
+ {
+ pDFD = g_ktx2_etc1s_alpha_dfd;
+ dfd_len = sizeof(g_ktx2_etc1s_alpha_dfd);
+ }
+ else
+ {
+ pDFD = g_ktx2_etc1s_nonalpha_dfd;
+ dfd_len = sizeof(g_ktx2_etc1s_nonalpha_dfd);
+ }
+ }
+
+ assert(dfd_len >= 44);
+
+ dfd.resize(dfd_len);
+ memcpy(dfd.data(), pDFD, dfd_len);
+
+ uint32_t dfd_bits = basisu::read_le_dword(dfd.data() + 3 * sizeof(uint32_t));
+
+ dfd_bits &= ~(0xFF << 16);
+
+ if (m_params.m_ktx2_srgb_transfer_func)
+ dfd_bits |= (basist::KTX2_KHR_DF_TRANSFER_SRGB << 16);
+ else
+ dfd_bits |= (basist::KTX2_KHR_DF_TRANSFER_LINEAR << 16);
+
+ basisu::write_le_dword(dfd.data() + 3 * sizeof(uint32_t), dfd_bits);
+
+ if (header.m_supercompression_scheme != basist::KTX2_SS_NONE)
+ {
+ uint32_t plane_bits = basisu::read_le_dword(dfd.data() + 5 * sizeof(uint32_t));
+
+ plane_bits &= ~0xFF;
+
+ basisu::write_le_dword(dfd.data() + 5 * sizeof(uint32_t), plane_bits);
+ }
+
+ // Fix up the DFD channel(s)
+ uint32_t dfd_chan0 = basisu::read_le_dword(dfd.data() + 7 * sizeof(uint32_t));
+
+ if (m_params.m_uastc)
+ {
+ dfd_chan0 &= ~(0xF << 24);
+
+ // TODO: Allow the caller to override this
+ if (m_any_source_image_has_alpha)
+ dfd_chan0 |= (basist::KTX2_DF_CHANNEL_UASTC_RGBA << 24);
+ else
+ dfd_chan0 |= (basist::KTX2_DF_CHANNEL_UASTC_RGB << 24);
+ }
+
+ basisu::write_le_dword(dfd.data() + 7 * sizeof(uint32_t), dfd_chan0);
+ }
+
+ bool basis_compressor::create_ktx2_file()
+ {
+ if (m_params.m_uastc)
+ {
+ if ((m_params.m_ktx2_uastc_supercompression != basist::KTX2_SS_NONE) && (m_params.m_ktx2_uastc_supercompression != basist::KTX2_SS_ZSTANDARD))
+ return false;
+ }
+
+ const basisu_backend_output& backend_output = m_backend.get_output();
+
+ // Determine the width/height, number of array layers, mipmap levels, and the number of faces (1 for 2D, 6 for cubemap).
+ // This does not support 1D or 3D.
+ uint32_t base_width = 0, base_height = 0, total_layers = 0, total_levels = 0, total_faces = 1;
+
+ for (uint32_t i = 0; i < m_slice_descs.size(); i++)
+ {
+ if ((m_slice_descs[i].m_mip_index == 0) && (!base_width))
+ {
+ base_width = m_slice_descs[i].m_orig_width;
+ base_height = m_slice_descs[i].m_orig_height;
+ }
+
+ total_layers = maximum<uint32_t>(total_layers, m_slice_descs[i].m_source_file_index + 1);
+
+ if (!m_slice_descs[i].m_source_file_index)
+ total_levels = maximum<uint32_t>(total_levels, m_slice_descs[i].m_mip_index + 1);
+ }
+
+ if (m_params.m_tex_type == basist::cBASISTexTypeCubemapArray)
+ {
+ assert((total_layers % 6) == 0);
+
+ total_layers /= 6;
+ assert(total_layers >= 1);
+
+ total_faces = 6;
+ }
+
+ basist::ktx2_header header;
+ memset(&header, 0, sizeof(header));
+
+ memcpy(header.m_identifier, basist::g_ktx2_file_identifier, sizeof(basist::g_ktx2_file_identifier));
+ header.m_pixel_width = base_width;
+ header.m_pixel_height = base_height;
+ header.m_face_count = total_faces;
+ header.m_vk_format = basist::KTX2_VK_FORMAT_UNDEFINED;
+ header.m_type_size = 1;
+ header.m_level_count = total_levels;
+ header.m_layer_count = (total_layers > 1) ? total_layers : 0;
+
+ if (m_params.m_uastc)
+ {
+ switch (m_params.m_ktx2_uastc_supercompression)
+ {
+ case basist::KTX2_SS_NONE:
+ {
+ header.m_supercompression_scheme = basist::KTX2_SS_NONE;
+ break;
+ }
+ case basist::KTX2_SS_ZSTANDARD:
+ {
+#if BASISD_SUPPORT_KTX2_ZSTD
+ header.m_supercompression_scheme = basist::KTX2_SS_ZSTANDARD;
+#else
+ header.m_supercompression_scheme = basist::KTX2_SS_NONE;
+#endif
+ break;
+ }
+ default: assert(0); return false;
+ }
+ }
+
+ basisu::vector<uint8_vec> level_data_bytes(total_levels);
+ basisu::vector<uint8_vec> compressed_level_data_bytes(total_levels);
+ uint_vec slice_level_offsets(m_slice_descs.size());
+
+ // This will append the texture data in the correct order (for each level: layer, then face).
+ for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++)
+ {
+ const basisu_backend_slice_desc& slice_desc = m_slice_descs[slice_index];
+
+ slice_level_offsets[slice_index] = level_data_bytes[slice_desc.m_mip_index].size();
+
+ if (m_params.m_uastc)
+ append_vector(level_data_bytes[slice_desc.m_mip_index], m_uastc_backend_output.m_slice_image_data[slice_index]);
+ else
+ append_vector(level_data_bytes[slice_desc.m_mip_index], backend_output.m_slice_image_data[slice_index]);
+ }
+
+ // UASTC supercompression
+ if ((m_params.m_uastc) && (header.m_supercompression_scheme == basist::KTX2_SS_ZSTANDARD))
+ {
+#if BASISD_SUPPORT_KTX2_ZSTD
+ for (uint32_t level_index = 0; level_index < total_levels; level_index++)
+ {
+ compressed_level_data_bytes[level_index].resize(ZSTD_compressBound(level_data_bytes[level_index].size()));
+
+ size_t result = ZSTD_compress(compressed_level_data_bytes[level_index].data(), compressed_level_data_bytes[level_index].size(),
+ level_data_bytes[level_index].data(), level_data_bytes[level_index].size(),
+ m_params.m_ktx2_zstd_supercompression_level);
+
+ if (ZSTD_isError(result))
+ return false;
+
+ compressed_level_data_bytes[level_index].resize(result);
+ }
+#else
+ // Can't get here
+ assert(0);
+ return false;
+#endif
+ }
+ else
+ {
+ // No supercompression
+ compressed_level_data_bytes = level_data_bytes;
+ }
+
+ uint8_vec etc1s_global_data;
+
+ // Create ETC1S global supercompressed data
+ if (!m_params.m_uastc)
+ {
+ basist::ktx2_etc1s_global_data_header etc1s_global_data_header;
+ clear_obj(etc1s_global_data_header);
+
+ etc1s_global_data_header.m_endpoint_count = backend_output.m_num_endpoints;
+ etc1s_global_data_header.m_selector_count = backend_output.m_num_selectors;
+ etc1s_global_data_header.m_endpoints_byte_length = backend_output.m_endpoint_palette.size();
+ etc1s_global_data_header.m_selectors_byte_length = backend_output.m_selector_palette.size();
+ etc1s_global_data_header.m_tables_byte_length = backend_output.m_slice_image_tables.size();
+
+ basisu::vector<basist::ktx2_etc1s_image_desc> etc1s_image_descs(total_levels * total_layers * total_faces);
+ memset(etc1s_image_descs.data(), 0, etc1s_image_descs.size_in_bytes());
+
+ for (uint32_t slice_index = 0; slice_index < m_slice_descs.size(); slice_index++)
+ {
+ const basisu_backend_slice_desc& slice_desc = m_slice_descs[slice_index];
+
+ const uint32_t level_index = slice_desc.m_mip_index;
+ uint32_t layer_index = slice_desc.m_source_file_index;
+ uint32_t face_index = 0;
+
+ if (m_params.m_tex_type == basist::cBASISTexTypeCubemapArray)
+ {
+ face_index = layer_index % 6;
+ layer_index /= 6;
+ }
+
+ const uint32_t etc1s_image_index = level_index * (total_layers * total_faces) + layer_index * total_faces + face_index;
+
+ if (slice_desc.m_alpha)
+ {
+ etc1s_image_descs[etc1s_image_index].m_alpha_slice_byte_length = backend_output.m_slice_image_data[slice_index].size();
+ etc1s_image_descs[etc1s_image_index].m_alpha_slice_byte_offset = slice_level_offsets[slice_index];
+ }
+ else
+ {
+ if (m_params.m_tex_type == basist::cBASISTexTypeVideoFrames)
+ etc1s_image_descs[etc1s_image_index].m_image_flags = !slice_desc.m_iframe ? basist::KTX2_IMAGE_IS_P_FRAME : 0;
+
+ etc1s_image_descs[etc1s_image_index].m_rgb_slice_byte_length = backend_output.m_slice_image_data[slice_index].size();
+ etc1s_image_descs[etc1s_image_index].m_rgb_slice_byte_offset = slice_level_offsets[slice_index];
+ }
+ } // slice_index
+
+ append_vector(etc1s_global_data, (const uint8_t*)&etc1s_global_data_header, sizeof(etc1s_global_data_header));
+ append_vector(etc1s_global_data, (const uint8_t*)etc1s_image_descs.data(), etc1s_image_descs.size_in_bytes());
+ append_vector(etc1s_global_data, backend_output.m_endpoint_palette);
+ append_vector(etc1s_global_data, backend_output.m_selector_palette);
+ append_vector(etc1s_global_data, backend_output.m_slice_image_tables);
+
+ header.m_supercompression_scheme = basist::KTX2_SS_BASISLZ;
+ }
+
+ // Key values
+ basist::ktx2_transcoder::key_value_vec key_values(m_params.m_ktx2_key_values);
+ key_values.enlarge(1);
+
+ const char* pKTXwriter = "KTXwriter";
+ key_values.back().m_key.resize(strlen(pKTXwriter) + 1);
+ memcpy(key_values.back().m_key.data(), pKTXwriter, strlen(pKTXwriter) + 1);
+
+ char writer_id[128];
+#ifdef _MSC_VER
+ sprintf_s(writer_id, sizeof(writer_id), "Basis Universal %s", BASISU_LIB_VERSION_STRING);
+#else
+ snprintf(writer_id, sizeof(writer_id), "Basis Universal %s", BASISU_LIB_VERSION_STRING);
+#endif
+ key_values.back().m_value.resize(strlen(writer_id) + 1);
+ memcpy(key_values.back().m_value.data(), writer_id, strlen(writer_id) + 1);
+
+ key_values.sort();
+
+#if BASISU_DISABLE_KTX2_KEY_VALUES
+ // HACK HACK - Clear the key values array, which causes no key values to be written (triggering the ktx2check validator bug).
+ key_values.clear();
+#endif
+
+ uint8_vec key_value_data;
+
+ // DFD
+ uint8_vec dfd;
+ get_dfd(dfd, header);
+
+ const uint32_t kvd_file_offset = sizeof(header) + sizeof(basist::ktx2_level_index) * total_levels + dfd.size();
+
+ for (uint32_t pass = 0; pass < 2; pass++)
+ {
+ for (uint32_t i = 0; i < key_values.size(); i++)
+ {
+ if (key_values[i].m_key.size() < 2)
+ return false;
+
+ if (key_values[i].m_key.back() != 0)
+ return false;
+
+ const uint64_t total_len = (uint64_t)key_values[i].m_key.size() + (uint64_t)key_values[i].m_value.size();
+ if (total_len >= UINT32_MAX)
+ return false;
+
+ packed_uint<4> le_len((uint32_t)total_len);
+ append_vector(key_value_data, (const uint8_t*)&le_len, sizeof(le_len));
+
+ append_vector(key_value_data, key_values[i].m_key);
+ append_vector(key_value_data, key_values[i].m_value);
+
+ const uint32_t ofs = key_value_data.size() & 3;
+ const uint32_t padding = (4 - ofs) & 3;
+ for (uint32_t p = 0; p < padding; p++)
+ key_value_data.push_back(0);
+ }
+
+ if (header.m_supercompression_scheme != basist::KTX2_SS_NONE)
+ break;
+
+#if BASISU_DISABLE_KTX2_ALIGNMENT_WORKAROUND
+ break;
+#endif
+
+ // Hack to ensure the KVD block ends on a 16 byte boundary, because we have no other official way of aligning the data.
+ uint32_t kvd_end_file_offset = kvd_file_offset + key_value_data.size();
+ uint32_t bytes_needed_to_pad = (16 - (kvd_end_file_offset & 15)) & 15;
+ if (!bytes_needed_to_pad)
+ {
+ // We're good. No need to add a dummy key.
+ break;
+ }
+
+ assert(!pass);
+ if (pass)
+ return false;
+
+ if (bytes_needed_to_pad < 6)
+ bytes_needed_to_pad += 16;
+
+ printf("WARNING: Due to a KTX2 validator bug related to mipPadding, we must insert a dummy key into the KTX2 file of %u bytes\n", bytes_needed_to_pad);
+
+ // We're not good - need to add a dummy key large enough to force file alignment so the mip level array gets aligned.
+ // We can't just add some bytes before the mip level array because ktx2check will see that as extra data in the file that shouldn't be there in ktxValidator::validateDataSize().
+ key_values.enlarge(1);
+ for (uint32_t i = 0; i < (bytes_needed_to_pad - 4 - 1 - 1); i++)
+ key_values.back().m_key.push_back(127);
+
+ key_values.back().m_key.push_back(0);
+
+ key_values.back().m_value.push_back(0);
+
+ key_values.sort();
+
+ key_value_data.resize(0);
+
+ // Try again
+ }
+
+ basisu::vector<basist::ktx2_level_index> level_index_array(total_levels);
+ memset(level_index_array.data(), 0, level_index_array.size_in_bytes());
+
+ m_output_ktx2_file.clear();
+ m_output_ktx2_file.reserve(m_output_basis_file.size());
+
+ // Dummy header
+ m_output_ktx2_file.resize(sizeof(header));
+
+ // Level index array
+ append_vector(m_output_ktx2_file, (const uint8_t*)level_index_array.data(), level_index_array.size_in_bytes());
+
+ // DFD
+ const uint8_t* pDFD = dfd.data();
+ uint32_t dfd_len = dfd.size();
+
+ header.m_dfd_byte_offset = m_output_ktx2_file.size();
+ header.m_dfd_byte_length = dfd_len;
+ append_vector(m_output_ktx2_file, pDFD, dfd_len);
+
+ // Key value data
+ if (key_value_data.size())
+ {
+ assert(kvd_file_offset == m_output_ktx2_file.size());
+
+ header.m_kvd_byte_offset = m_output_ktx2_file.size();
+ header.m_kvd_byte_length = key_value_data.size();
+ append_vector(m_output_ktx2_file, key_value_data);
+ }
+
+ // Global Supercompressed Data
+ if (etc1s_global_data.size())
+ {
+ uint32_t ofs = m_output_ktx2_file.size() & 7;
+ uint32_t padding = (8 - ofs) & 7;
+ for (uint32_t i = 0; i < padding; i++)
+ m_output_ktx2_file.push_back(0);
+
+ header.m_sgd_byte_length = etc1s_global_data.size();
+ header.m_sgd_byte_offset = m_output_ktx2_file.size();
+
+ append_vector(m_output_ktx2_file, etc1s_global_data);
+ }
+
+ // mipPadding
+ if (header.m_supercompression_scheme == basist::KTX2_SS_NONE)
+ {
+ // We currently can't do this or the validator will incorrectly give an error.
+ uint32_t ofs = m_output_ktx2_file.size() & 15;
+ uint32_t padding = (16 - ofs) & 15;
+
+ // Make sure we're always aligned here (due to a validator bug).
+ if (padding)
+ {
+ printf("Warning: KTX2 mip level data is not 16-byte aligned. This may trigger a ktx2check validation bug. Writing %u bytes of mipPadding.\n", padding);
+ }
+
+ for (uint32_t i = 0; i < padding; i++)
+ m_output_ktx2_file.push_back(0);
+ }
+
+ // Level data - write the smallest mipmap first.
+ for (int level = total_levels - 1; level >= 0; level--)
+ {
+ level_index_array[level].m_byte_length = compressed_level_data_bytes[level].size();
+ if (m_params.m_uastc)
+ level_index_array[level].m_uncompressed_byte_length = level_data_bytes[level].size();
+
+ level_index_array[level].m_byte_offset = m_output_ktx2_file.size();
+ append_vector(m_output_ktx2_file, compressed_level_data_bytes[level]);
+ }
+
+ // Write final header
+ memcpy(m_output_ktx2_file.data(), &header, sizeof(header));
+
+ // Write final level index array
+ memcpy(m_output_ktx2_file.data() + sizeof(header), level_index_array.data(), level_index_array.size_in_bytes());
+
+ debug_printf("Total .ktx2 output file size: %u\n", m_output_ktx2_file.size());
+
+ return true;
+ }
+
+} // namespace basisu
diff --git a/thirdparty/basis_universal/basisu_comp.h b/thirdparty/basis_universal/encoder/basisu_comp.h
index 1c201ddbed..2c3af968f7 100644
--- a/thirdparty/basis_universal/basisu_comp.h
+++ b/thirdparty/basis_universal/encoder/basisu_comp.h
@@ -1,5 +1,5 @@
// basisu_comp.h
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,8 +16,23 @@
#include "basisu_frontend.h"
#include "basisu_backend.h"
#include "basisu_basis_file.h"
-#include "transcoder/basisu_global_selector_palette.h"
-#include "transcoder/basisu_transcoder.h"
+#include "../transcoder/basisu_global_selector_palette.h"
+#include "../transcoder/basisu_transcoder.h"
+#include "basisu_uastc_enc.h"
+
+#define BASISU_LIB_VERSION 115
+#define BASISU_LIB_VERSION_STRING "1.15"
+
+#ifndef BASISD_SUPPORT_KTX2
+ #error BASISD_SUPPORT_KTX2 is undefined
+#endif
+#ifndef BASISD_SUPPORT_KTX2_ZSTD
+ #error BASISD_SUPPORT_KTX2_ZSTD is undefined
+#endif
+
+#if !BASISD_SUPPORT_KTX2
+ #error BASISD_SUPPORT_KTX2 must be enabled when building the encoder. To reduce code size if KTX2 support is not needed, set BASISD_SUPPORT_KTX2_ZSTD to 0
+#endif
namespace basisu
{
@@ -40,6 +55,10 @@ namespace basisu
const uint32_t BASISU_MAX_SLICES = 0xFFFFFF;
+ const int BASISU_RDO_UASTC_DICT_SIZE_DEFAULT = 4096; // 32768;
+ const int BASISU_RDO_UASTC_DICT_SIZE_MIN = 64;
+ const int BASISU_RDO_UASTC_DICT_SIZE_MAX = 65536;
+
struct image_stats
{
image_stats()
@@ -52,43 +71,52 @@ namespace basisu
m_filename.clear();
m_width = 0;
m_height = 0;
-
- m_basis_etc1s_rgb_avg_psnr = 0.0f;
- m_basis_etc1s_luma_709_psnr = 0.0f;
- m_basis_etc1s_luma_601_psnr = 0.0f;
- m_basis_etc1s_luma_709_ssim = 0.0f;
-
- m_basis_bc1_rgb_avg_psnr = 0.0f;
- m_basis_bc1_luma_709_psnr = 0.0f;
- m_basis_bc1_luma_601_psnr = 0.0f;
- m_basis_bc1_luma_709_ssim = 0.0f;
-
- m_best_rgb_avg_psnr = 0.0f;
- m_best_luma_709_psnr = 0.0f;
- m_best_luma_601_psnr = 0.0f;
- m_best_luma_709_ssim = 0.0f;
+
+ m_basis_rgb_avg_psnr = 0.0f;
+ m_basis_rgba_avg_psnr = 0.0f;
+ m_basis_a_avg_psnr = 0.0f;
+ m_basis_luma_709_psnr = 0.0f;
+ m_basis_luma_601_psnr = 0.0f;
+ m_basis_luma_709_ssim = 0.0f;
+
+ m_bc7_rgb_avg_psnr = 0.0f;
+ m_bc7_rgba_avg_psnr = 0.0f;
+ m_bc7_a_avg_psnr = 0.0f;
+ m_bc7_luma_709_psnr = 0.0f;
+ m_bc7_luma_601_psnr = 0.0f;
+ m_bc7_luma_709_ssim = 0.0f;
+
+ m_best_etc1s_rgb_avg_psnr = 0.0f;
+ m_best_etc1s_luma_709_psnr = 0.0f;
+ m_best_etc1s_luma_601_psnr = 0.0f;
+ m_best_etc1s_luma_709_ssim = 0.0f;
}
std::string m_filename;
uint32_t m_width;
uint32_t m_height;
- // .basis compressed
- float m_basis_etc1s_rgb_avg_psnr;
- float m_basis_etc1s_luma_709_psnr;
- float m_basis_etc1s_luma_601_psnr;
- float m_basis_etc1s_luma_709_ssim;
+ // .basis compressed (ETC1S or UASTC statistics)
+ float m_basis_rgb_avg_psnr;
+ float m_basis_rgba_avg_psnr;
+ float m_basis_a_avg_psnr;
+ float m_basis_luma_709_psnr;
+ float m_basis_luma_601_psnr;
+ float m_basis_luma_709_ssim;
+
+ // BC7 statistics
+ float m_bc7_rgb_avg_psnr;
+ float m_bc7_rgba_avg_psnr;
+ float m_bc7_a_avg_psnr;
+ float m_bc7_luma_709_psnr;
+ float m_bc7_luma_601_psnr;
+ float m_bc7_luma_709_ssim;
- float m_basis_bc1_rgb_avg_psnr;
- float m_basis_bc1_luma_709_psnr;
- float m_basis_bc1_luma_601_psnr;
- float m_basis_bc1_luma_709_ssim;
-
- // Normal (highest quality) compressed ETC1S
- float m_best_rgb_avg_psnr;
- float m_best_luma_709_psnr;
- float m_best_luma_601_psnr;
- float m_best_luma_709_ssim;
+ // Highest achievable quality ETC1S statistics
+ float m_best_etc1s_rgb_avg_psnr;
+ float m_best_etc1s_luma_709_psnr;
+ float m_best_etc1s_luma_601_psnr;
+ float m_best_etc1s_luma_709_ssim;
};
template<bool def>
@@ -175,18 +203,30 @@ namespace basisu
struct basis_compressor_params
{
basis_compressor_params() :
+ m_pSel_codebook(NULL),
+ m_compression_level((int)BASISU_DEFAULT_COMPRESSION_LEVEL, 0, (int)BASISU_MAX_COMPRESSION_LEVEL),
+ m_selector_rdo_thresh(BASISU_DEFAULT_SELECTOR_RDO_THRESH, 0.0f, 1e+10f),
+ m_endpoint_rdo_thresh(BASISU_DEFAULT_ENDPOINT_RDO_THRESH, 0.0f, 1e+10f),
m_hybrid_sel_cb_quality_thresh(BASISU_DEFAULT_HYBRID_SEL_CB_QUALITY_THRESH, 0.0f, 1e+10f),
m_global_pal_bits(8, 0, ETC1_GLOBAL_SELECTOR_CODEBOOK_MAX_PAL_BITS),
m_global_mod_bits(8, 0, basist::etc1_global_palette_entry_modifier::cTotalBits),
- m_endpoint_rdo_thresh(BASISU_DEFAULT_ENDPOINT_RDO_THRESH, 0.0f, 1e+10f),
- m_selector_rdo_thresh(BASISU_DEFAULT_SELECTOR_RDO_THRESH, 0.0f, 1e+10f),
- m_pSel_codebook(NULL),
+ m_mip_scale(1.0f, .000125f, 4.0f),
+ m_mip_smallest_dimension(1, 1, 16384),
m_max_endpoint_clusters(512),
m_max_selector_clusters(512),
m_quality_level(-1),
- m_mip_scale(1.0f, .000125f, 4.0f),
- m_mip_smallest_dimension(1, 1, 16384),
- m_compression_level((int)BASISU_DEFAULT_COMPRESSION_LEVEL, 0, (int)BASISU_MAX_COMPRESSION_LEVEL),
+ m_pack_uastc_flags(cPackUASTCLevelDefault),
+ m_rdo_uastc_quality_scalar(1.0f, 0.001f, 50.0f),
+ m_rdo_uastc_dict_size(BASISU_RDO_UASTC_DICT_SIZE_DEFAULT, BASISU_RDO_UASTC_DICT_SIZE_MIN, BASISU_RDO_UASTC_DICT_SIZE_MAX),
+ m_rdo_uastc_max_smooth_block_error_scale(UASTC_RDO_DEFAULT_SMOOTH_BLOCK_MAX_ERROR_SCALE, 1.0f, 300.0f),
+ m_rdo_uastc_smooth_block_max_std_dev(UASTC_RDO_DEFAULT_MAX_SMOOTH_BLOCK_STD_DEV, .01f, 65536.0f),
+ m_rdo_uastc_max_allowed_rms_increase_ratio(UASTC_RDO_DEFAULT_MAX_ALLOWED_RMS_INCREASE_RATIO, .01f, 100.0f),
+ m_rdo_uastc_skip_block_rms_thresh(UASTC_RDO_DEFAULT_SKIP_BLOCK_RMS_THRESH, .01f, 100.0f),
+ m_resample_width(0, 1, 16384),
+ m_resample_height(0, 1, 16384),
+ m_resample_factor(0.0f, .00125f, 100.0f),
+ m_ktx2_uastc_supercompression(basist::KTX2_SS_NONE),
+ m_ktx2_zstd_supercompression_level(6, INT_MIN, INT_MAX),
m_pJob_pool(nullptr)
{
clear();
@@ -196,15 +236,20 @@ namespace basisu
{
m_pSel_codebook = NULL;
+ m_uastc.clear();
+ m_status_output.clear();
+
m_source_filenames.clear();
m_source_alpha_filenames.clear();
m_source_images.clear();
+ m_source_mipmap_images.clear();
m_out_filename.clear();
m_y_flip.clear();
m_debug.clear();
+ m_validate.clear();
m_debug_images.clear();
m_global_sel_pal.clear();
m_auto_global_sel_pal.clear();
@@ -219,7 +264,11 @@ namespace basisu
m_check_for_alpha.clear();
m_force_alpha.clear();
m_multithreading.clear();
- m_seperate_rg_to_color_alpha.clear();
+ m_swizzle[0] = 0;
+ m_swizzle[1] = 1;
+ m_swizzle[2] = 2;
+ m_swizzle[3] = 3;
+ m_renormalize.clear();
m_hybrid_sel_cb_quality_thresh.clear();
m_global_pal_bits.clear();
m_global_mod_bits.clear();
@@ -236,6 +285,7 @@ namespace basisu
m_mip_premultiplied.clear();
m_mip_renormalize.clear();
m_mip_wrapping.clear();
+ m_mip_fast.clear();
m_mip_smallest_dimension.clear();
m_max_endpoint_clusters = 0;
@@ -247,30 +297,63 @@ namespace basisu
m_userdata1 = 0;
m_us_per_frame = 0;
+ m_pack_uastc_flags = cPackUASTCLevelDefault;
+ m_rdo_uastc.clear();
+ m_rdo_uastc_quality_scalar.clear();
+ m_rdo_uastc_max_smooth_block_error_scale.clear();
+ m_rdo_uastc_smooth_block_max_std_dev.clear();
+ m_rdo_uastc_max_allowed_rms_increase_ratio.clear();
+ m_rdo_uastc_skip_block_rms_thresh.clear();
+ m_rdo_uastc_favor_simpler_modes_in_rdo_mode.clear();
+ m_rdo_uastc_multithreading.clear();
+
+ m_resample_width.clear();
+ m_resample_height.clear();
+ m_resample_factor.clear();
+
+ m_pGlobal_codebooks = nullptr;
+
+ m_create_ktx2_file.clear();
+ m_ktx2_uastc_supercompression = basist::KTX2_SS_NONE;
+ m_ktx2_key_values.clear();
+ m_ktx2_zstd_supercompression_level.clear();
+ m_ktx2_srgb_transfer_func.clear();
+
m_pJob_pool = nullptr;
}
-
+
// Pointer to the global selector codebook, or nullptr to not use a global selector codebook
const basist::etc1_global_selector_codebook *m_pSel_codebook;
+ // True to generate UASTC .basis file data, otherwise ETC1S.
+ bool_param<false> m_uastc;
+
// If m_read_source_images is true, m_source_filenames (and optionally m_source_alpha_filenames) contains the filenames of PNG images to read.
// Otherwise, the compressor processes the images in m_source_images.
- std::vector<std::string> m_source_filenames;
- std::vector<std::string> m_source_alpha_filenames;
+ basisu::vector<std::string> m_source_filenames;
+ basisu::vector<std::string> m_source_alpha_filenames;
- std::vector<image> m_source_images;
- // TODO: Allow caller to supply their own mipmaps
+ basisu::vector<image> m_source_images;
+
+ // Stores mipmaps starting from level 1. Level 0 is still stored in m_source_images, as usual.
+ // If m_source_mipmaps isn't empty, automatic mipmap generation isn't done. m_source_mipmaps.size() MUST equal m_source_images.size() or the compressor returns an error.
+ // The compressor applies the user-provided swizzling (in m_swizzle) to these images.
+ basisu::vector< basisu::vector<image> > m_source_mipmap_images;
// Filename of the output basis file
- std::string m_out_filename;
+ std::string m_out_filename;
// The params are done this way so we can detect when the user has explictly changed them.
// Flip images across Y axis
bool_param<false> m_y_flip;
+
+ // If true, the compressor will print basis status to stdout during compression.
+ bool_param<true> m_status_output;
// Output debug information during compression
bool_param<false> m_debug;
+ bool_param<false> m_validate;
// m_debug_images is pretty slow
bool_param<false> m_debug_images;
@@ -284,7 +367,7 @@ namespace basisu
// Frontend/backend codec parameters
bool_param<false> m_no_hybrid_sel_cb;
- // Use perceptual sRGB colorspace metrics (for normal maps, etc.)
+ // Use perceptual sRGB colorspace metrics instead of linear
bool_param<true> m_perceptual;
// Disable selector RDO, for faster compression but larger files
@@ -299,7 +382,7 @@ namespace basisu
// Write the output basis file to disk using m_out_filename
bool_param<false> m_write_output_basis_files;
-
+
// Compute and display image metrics
bool_param<false> m_compute_stats;
@@ -311,7 +394,9 @@ namespace basisu
bool_param<true> m_multithreading;
// Split the R channel to RGB and the G channel to alpha, then write a basis file with alpha channels
- bool_param<false> m_seperate_rg_to_color_alpha;
+ char m_swizzle[4];
+
+ bool_param<false> m_renormalize;
bool_param<false> m_disable_hierarchical_endpoint_codebooks;
@@ -328,10 +413,11 @@ namespace basisu
bool_param<true> m_mip_premultiplied; // not currently supported
bool_param<false> m_mip_renormalize;
bool_param<true> m_mip_wrapping;
+ bool_param<true> m_mip_fast;
param<int> m_mip_smallest_dimension;
// Codebook size (quality) control.
- // If m_quality_level != -1, it controls the quality level. It ranges from [0,255].
+ // If m_quality_level != -1, it controls the quality level. It ranges from [0,255] or [BASISU_QUALITY_MIN, BASISU_QUALITY_MAX].
// Otherwise m_max_endpoint_clusters/m_max_selector_clusters controls the codebook sizes directly.
uint32_t m_max_endpoint_clusters;
uint32_t m_max_selector_clusters;
@@ -343,6 +429,31 @@ namespace basisu
uint32_t m_userdata1;
uint32_t m_us_per_frame;
+ // cPackUASTCLevelDefault, etc.
+ uint32_t m_pack_uastc_flags;
+ bool_param<false> m_rdo_uastc;
+ param<float> m_rdo_uastc_quality_scalar;
+ param<int> m_rdo_uastc_dict_size;
+ param<float> m_rdo_uastc_max_smooth_block_error_scale;
+ param<float> m_rdo_uastc_smooth_block_max_std_dev;
+ param<float> m_rdo_uastc_max_allowed_rms_increase_ratio;
+ param<float> m_rdo_uastc_skip_block_rms_thresh;
+ bool_param<true> m_rdo_uastc_favor_simpler_modes_in_rdo_mode;
+ bool_param<true> m_rdo_uastc_multithreading;
+
+ param<int> m_resample_width;
+ param<int> m_resample_height;
+ param<float> m_resample_factor;
+ const basist::basisu_lowlevel_etc1s_transcoder *m_pGlobal_codebooks;
+
+ // KTX2 specific parameters.
+ // Internally, the compressor always creates a .basis file then it converts that lossless to KTX2.
+ bool_param<false> m_create_ktx2_file;
+ basist::ktx2_supercompression m_ktx2_uastc_supercompression;
+ basist::ktx2_transcoder::key_value_vec m_ktx2_key_values;
+ param<int> m_ktx2_zstd_supercompression_level;
+ bool_param<false> m_ktx2_srgb_transfer_func;
+
job_pool *m_pJob_pool;
};
@@ -360,35 +471,41 @@ namespace basisu
cECSuccess = 0,
cECFailedReadingSourceImages,
cECFailedValidating,
+ cECFailedEncodeUASTC,
cECFailedFrontEnd,
cECFailedFontendExtract,
cECFailedBackend,
cECFailedCreateBasisFile,
- cECFailedWritingOutput
+ cECFailedWritingOutput,
+ cECFailedUASTCRDOPostProcess,
+ cECFailedCreateKTX2File
};
error_code process();
+ // The output .basis file will always be valid of process() succeeded.
const uint8_vec &get_output_basis_file() const { return m_output_basis_file; }
- const etc_block_vec &get_output_blocks() const { return m_output_blocks; }
+
+ // The output .ktx2 file will only be valid if m_create_ktx2_file was true and process() succeeded.
+ const uint8_vec& get_output_ktx2_file() const { return m_output_ktx2_file; }
- const std::vector<image_stats> &get_stats() const { return m_stats; }
+ const basisu::vector<image_stats> &get_stats() const { return m_stats; }
uint32_t get_basis_file_size() const { return m_basis_file_size; }
double get_basis_bits_per_texel() const { return m_basis_bits_per_texel; }
-
+
bool get_any_source_image_has_alpha() const { return m_any_source_image_has_alpha; }
-
+
private:
basis_compressor_params m_params;
- std::vector<image> m_slice_images;
+ basisu::vector<image> m_slice_images;
- std::vector<image_stats> m_stats;
+ basisu::vector<image_stats> m_stats;
uint32_t m_basis_file_size;
double m_basis_bits_per_texel;
-
+
basisu_backend_slice_desc_vec m_slice_descs;
uint32_t m_total_blocks;
@@ -397,33 +514,41 @@ namespace basisu
basisu_frontend m_frontend;
pixel_block_vec m_source_blocks;
- std::vector<gpu_image> m_frontend_output_textures;
+ basisu::vector<gpu_image> m_frontend_output_textures;
- std::vector<gpu_image> m_best_etc1s_images;
- std::vector<image> m_best_etc1s_images_unpacked;
+ basisu::vector<gpu_image> m_best_etc1s_images;
+ basisu::vector<image> m_best_etc1s_images_unpacked;
basisu_backend m_backend;
basisu_file m_basis_file;
- std::vector<gpu_image> m_decoded_output_textures;
- std::vector<image> m_decoded_output_textures_unpacked;
- std::vector<gpu_image> m_decoded_output_textures_bc1;
- std::vector<image> m_decoded_output_textures_unpacked_bc1;
+ basisu::vector<gpu_image> m_decoded_output_textures;
+ basisu::vector<image> m_decoded_output_textures_unpacked;
+ basisu::vector<gpu_image> m_decoded_output_textures_bc7;
+ basisu::vector<image> m_decoded_output_textures_unpacked_bc7;
uint8_vec m_output_basis_file;
- etc_block_vec m_output_blocks;
+ uint8_vec m_output_ktx2_file;
+
+ basisu::vector<gpu_image> m_uastc_slice_textures;
+ basisu_backend_output m_uastc_backend_output;
bool m_any_source_image_has_alpha;
bool read_source_images();
+ bool extract_source_blocks();
bool process_frontend();
bool extract_frontend_texture_data();
bool process_backend();
bool create_basis_file_and_transcode();
bool write_output_files_and_compute_stats();
- bool generate_mipmaps(const image &img, std::vector<image> &mips, bool has_alpha);
+ error_code encode_slices_to_uastc();
+ bool generate_mipmaps(const image &img, basisu::vector<image> &mips, bool has_alpha);
bool validate_texture_type_constraints();
+ bool validate_ktx2_constraints();
+ void get_dfd(uint8_vec& dfd, const basist::ktx2_header& hdr);
+ bool create_ktx2_file();
};
} // namespace basisu
diff --git a/thirdparty/basis_universal/basisu_enc.cpp b/thirdparty/basis_universal/encoder/basisu_enc.cpp
index 7057c65cf8..f02fb62c11 100644
--- a/thirdparty/basis_universal/basisu_enc.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_enc.cpp
@@ -1,5 +1,5 @@
// basisu_enc.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,7 +17,11 @@
#include "basisu_resampler.h"
#include "basisu_resampler_filters.h"
#include "basisu_etc.h"
-#include "transcoder/basisu_transcoder.h"
+#include "../transcoder/basisu_transcoder.h"
+#include "basisu_bc7enc.h"
+#include "apg_bmp.h"
+#include "jpgd.h"
+#include <vector>
#if defined(_WIN32)
// For QueryPerformanceCounter/QueryPerformanceFrequency
@@ -29,6 +33,9 @@ namespace basisu
{
uint64_t interval_timer::g_init_ticks, interval_timer::g_freq;
double interval_timer::g_timer_freq;
+#if BASISU_SUPPORT_SSE
+ bool g_cpu_supports_sse41;
+#endif
uint8_t g_hamming_dist[256] =
{
@@ -50,10 +57,117 @@ namespace basisu
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
+ // This is a Public Domain 8x8 font from here:
+ // https://github.com/dhepper/font8x8/blob/master/font8x8_basic.h
+ const uint8_t g_debug_font8x8_basic[127 - 32 + 1][8] =
+ {
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 ( )
+ { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!)
+ { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (")
+ { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#)
+ { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($)
+ { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%)
+ { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&)
+ { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (')
+ { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (()
+ { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ())
+ { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*)
+ { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+)
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,)
+ { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-)
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.)
+ { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/)
+ { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0)
+ { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1)
+ { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2)
+ { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3)
+ { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4)
+ { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5)
+ { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6)
+ { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7)
+ { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8)
+ { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9)
+ { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:)
+ { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;)
+ { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<)
+ { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=)
+ { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>)
+ { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?)
+ { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@)
+ { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
+ { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B)
+ { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C)
+ { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D)
+ { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E)
+ { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F)
+ { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G)
+ { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H)
+ { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I)
+ { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J)
+ { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K)
+ { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L)
+ { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M)
+ { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N)
+ { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O)
+ { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P)
+ { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q)
+ { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R)
+ { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S)
+ { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T)
+ { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U)
+ { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V)
+ { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W)
+ { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X)
+ { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y)
+ { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z)
+ { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([)
+ { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\)
+ { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (])
+ { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^)
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_)
+ { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`)
+ { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a)
+ { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b)
+ { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c)
+ { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d)
+ { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e)
+ { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f)
+ { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g)
+ { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h)
+ { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i)
+ { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j)
+ { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k)
+ { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l)
+ { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m)
+ { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n)
+ { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o)
+ { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p)
+ { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q)
+ { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r)
+ { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s)
+ { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t)
+ { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u)
+ { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v)
+ { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w)
+ { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x)
+ { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y)
+ { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z)
+ { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({)
+ { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|)
+ { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (})
+ { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~)
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F
+ };
+
// Encoder library initialization (just call once at startup)
void basisu_encoder_init()
{
+ detect_sse41();
+
basist::basisu_transcoder_init();
+ pack_etc1_solid_color_init();
+ //uastc_init();
+ bc7enc_compress_block_init(); // must be after uastc_init()
}
void error_printf(const char *pFmt, ...)
@@ -108,7 +222,7 @@ namespace basisu
#else
#error TODO
#endif
-
+
interval_timer::interval_timer() : m_start_time(0), m_stop_time(0), m_started(false), m_stopped(false)
{
if (!g_timer_freq)
@@ -169,38 +283,142 @@ namespace basisu
return ticks * g_timer_freq;
}
- bool load_png(const char* pFilename, image& img)
+ const uint32_t MAX_32BIT_ALLOC_SIZE = 250000000;
+
+ bool load_bmp(const char* pFilename, image& img)
{
- std::vector<uint8_t> buffer;
- unsigned err = lodepng::load_file(buffer, std::string(pFilename));
- if (err)
+ int w = 0, h = 0;
+ unsigned int n_chans = 0;
+ unsigned char* pImage_data = apg_bmp_read(pFilename, &w, &h, &n_chans);
+
+ if ((!pImage_data) || (!w) || (!h) || ((n_chans != 3) && (n_chans != 4)))
+ {
+ error_printf("Failed loading .BMP image \"%s\"!\n", pFilename);
+
+ if (pImage_data)
+ apg_bmp_free(pImage_data);
+
return false;
+ }
- unsigned w = 0, h = 0;
+ if (sizeof(void *) == sizeof(uint32_t))
+ {
+ if ((w * h * n_chans) > MAX_32BIT_ALLOC_SIZE)
+ {
+ error_printf("Image \"%s\" is too large (%ux%u) to process in a 32-bit build!\n", pFilename, w, h);
+
+ if (pImage_data)
+ apg_bmp_free(pImage_data);
+
+ return false;
+ }
+ }
+
+ img.resize(w, h);
+
+ const uint8_t *pSrc = pImage_data;
+ for (int y = 0; y < h; y++)
+ {
+ color_rgba *pDst = &img(0, y);
+
+ for (int x = 0; x < w; x++)
+ {
+ pDst->r = pSrc[0];
+ pDst->g = pSrc[1];
+ pDst->b = pSrc[2];
+ pDst->a = (n_chans == 3) ? 255 : pSrc[3];
+
+ pSrc += n_chans;
+ ++pDst;
+ }
+ }
+
+ apg_bmp_free(pImage_data);
+
+ return true;
+ }
+
+ bool load_tga(const char* pFilename, image& img)
+ {
+ int w = 0, h = 0, n_chans = 0;
+ uint8_t* pImage_data = read_tga(pFilename, w, h, n_chans);
+ if ((!pImage_data) || (!w) || (!h) || ((n_chans != 3) && (n_chans != 4)))
+ {
+ error_printf("Failed loading .TGA image \"%s\"!\n", pFilename);
+
+ if (pImage_data)
+ free(pImage_data);
+
+ return false;
+ }
+
if (sizeof(void *) == sizeof(uint32_t))
{
+ if ((w * h * n_chans) > MAX_32BIT_ALLOC_SIZE)
+ {
+ error_printf("Image \"%s\" is too large (%ux%u) to process in a 32-bit build!\n", pFilename, w, h);
+
+ if (pImage_data)
+ free(pImage_data);
+
+ return false;
+ }
+ }
+
+ img.resize(w, h);
+
+ const uint8_t *pSrc = pImage_data;
+ for (int y = 0; y < h; y++)
+ {
+ color_rgba *pDst = &img(0, y);
+
+ for (int x = 0; x < w; x++)
+ {
+ pDst->r = pSrc[0];
+ pDst->g = pSrc[1];
+ pDst->b = pSrc[2];
+ pDst->a = (n_chans == 3) ? 255 : pSrc[3];
+
+ pSrc += n_chans;
+ ++pDst;
+ }
+ }
+
+ free(pImage_data);
+
+ return true;
+ }
+
+ bool load_png(const uint8_t *pBuf, size_t buf_size, image &img, const char *pFilename)
+ {
+ if (!buf_size)
+ return false;
+
+ unsigned err = 0, w = 0, h = 0;
+
+ if (sizeof(void*) == sizeof(uint32_t))
+ {
// Inspect the image first on 32-bit builds, to see if the image would require too much memory.
lodepng::State state;
- err = lodepng_inspect(&w, &h, &state, &buffer[0], buffer.size());
+ err = lodepng_inspect(&w, &h, &state, pBuf, buf_size);
if ((err != 0) || (!w) || (!h))
return false;
const uint32_t exepected_alloc_size = w * h * sizeof(uint32_t);
-
+
// If the file is too large on 32-bit builds then just bail now, to prevent causing a memory exception.
- const uint32_t MAX_ALLOC_SIZE = 250000000;
- if (exepected_alloc_size >= MAX_ALLOC_SIZE)
+ if (exepected_alloc_size >= MAX_32BIT_ALLOC_SIZE)
{
- error_printf("Image \"%s\" is too large (%ux%u) to process in a 32-bit build!\n", pFilename, w, h);
+ error_printf("Image \"%s\" is too large (%ux%u) to process in a 32-bit build!\n", (pFilename != nullptr) ? pFilename : "<memory>", w, h);
return false;
}
-
+
w = h = 0;
}
-
+
std::vector<uint8_t> out;
- err = lodepng::decode(out, w, h, &buffer[0], buffer.size());
+ err = lodepng::decode(out, w, h, pBuf, buf_size);
if ((err != 0) || (!w) || (!h))
return false;
@@ -213,12 +431,62 @@ namespace basisu
return true;
}
+
+ bool load_png(const char* pFilename, image& img)
+ {
+ std::vector<uint8_t> buffer;
+ unsigned err = lodepng::load_file(buffer, std::string(pFilename));
+ if (err)
+ return false;
+
+
+ return load_png(buffer.data(), buffer.size(), img, pFilename);
+ }
+
+ bool load_jpg(const char *pFilename, image& img)
+ {
+ int width = 0, height = 0, actual_comps = 0;
+ uint8_t *pImage_data = jpgd::decompress_jpeg_image_from_file(pFilename, &width, &height, &actual_comps, 4, jpgd::jpeg_decoder::cFlagLinearChromaFiltering);
+ if (!pImage_data)
+ return false;
+
+ img.init(pImage_data, width, height, 4);
+
+ free(pImage_data);
+
+ return true;
+ }
+
+ bool load_image(const char* pFilename, image& img)
+ {
+ std::string ext(string_get_extension(std::string(pFilename)));
+
+ if (ext.length() == 0)
+ return false;
+
+ const char *pExt = ext.c_str();
+
+ if (strcasecmp(pExt, "png") == 0)
+ return load_png(pFilename, img);
+ if (strcasecmp(pExt, "bmp") == 0)
+ return load_bmp(pFilename, img);
+ if (strcasecmp(pExt, "tga") == 0)
+ return load_tga(pFilename, img);
+ if ( (strcasecmp(pExt, "jpg") == 0) || (strcasecmp(pExt, "jfif") == 0) || (strcasecmp(pExt, "jpeg") == 0) )
+ return load_jpg(pFilename, img);
+
+ return false;
+ }
- bool save_png(const char* pFilename, const image & img, uint32_t image_save_flags, uint32_t grayscale_comp)
+ bool save_png(const char* pFilename, const image &img, uint32_t image_save_flags, uint32_t grayscale_comp)
{
if (!img.get_total_pixels())
return false;
+ const uint32_t MAX_PNG_IMAGE_DIM = 32768;
+ if ((img.get_width() > MAX_PNG_IMAGE_DIM) || (img.get_height() > MAX_PNG_IMAGE_DIM))
+ return false;
+
std::vector<uint8_t> out;
unsigned err = 0;
@@ -231,16 +499,19 @@ namespace basisu
for (uint32_t x = 0; x < img.get_width(); x++)
*pDst++ = img(x, y)[grayscale_comp];
- err = lodepng::encode(out, (const uint8_t*)& g_pixels[0], img.get_width(), img.get_height(), LCT_GREY, 8);
+ err = lodepng::encode(out, (const uint8_t*)&g_pixels[0], img.get_width(), img.get_height(), LCT_GREY, 8);
}
else
{
bool has_alpha = img.has_alpha();
if ((!has_alpha) || ((image_save_flags & cImageSaveIgnoreAlpha) != 0))
{
- uint8_vec rgb_pixels(img.get_width() * 3 * img.get_height());
+ const uint64_t total_bytes = (uint64_t)img.get_width() * 3U * (uint64_t)img.get_height();
+ if (total_bytes > INT_MAX)
+ return false;
+ uint8_vec rgb_pixels(static_cast<size_t>(total_bytes));
uint8_t *pDst = &rgb_pixels[0];
-
+
for (uint32_t y = 0; y < img.get_height(); y++)
{
for (uint32_t x = 0; x < img.get_width(); x++)
@@ -302,7 +573,11 @@ namespace basisu
}
}
- data.resize((size_t)filesize);
+ if (!data.try_resize((size_t)filesize))
+ {
+ fclose(pFile);
+ return false;
+ }
if (filesize)
{
@@ -525,7 +800,7 @@ namespace basisu
if ((s >= num_syms) || (A[r].m_key < A[s].m_key))
{
A[next].m_key = A[r].m_key;
- A[r].m_key = static_cast<uint16_t>(next);
+ A[r].m_key = next;
++r;
}
else
@@ -536,13 +811,13 @@ namespace basisu
if ((s >= num_syms) || ((r < next) && A[r].m_key < A[s].m_key))
{
- A[next].m_key = static_cast<uint16_t>(A[next].m_key + A[r].m_key);
- A[r].m_key = static_cast<uint16_t>(next);
+ A[next].m_key = A[next].m_key + A[r].m_key;
+ A[r].m_key = next;
++r;
}
else
{
- A[next].m_key = static_cast<uint16_t>(A[next].m_key + A[s].m_key);
+ A[next].m_key = A[next].m_key + A[s].m_key;
++s;
}
}
@@ -562,7 +837,7 @@ namespace basisu
;
for ( ; num_avail > num_used; --next, --num_avail)
- A[next].m_key = static_cast<uint16_t>(depth);
+ A[next].m_key = depth;
num_avail = 2 * num_used;
num_used = 0;
@@ -610,6 +885,10 @@ namespace basisu
for (i = 0; i < num_syms; i++)
{
uint32_t freq = pSyms0[i].m_key;
+
+ // We scale all input frequencies to 16-bits.
+ assert(freq <= UINT16_MAX);
+
hist[freq & 0xFF]++;
hist[256 + ((freq >> 8) & 0xFF)]++;
}
@@ -731,8 +1010,13 @@ namespace basisu
else
{
for (uint32_t i = 0; i < num_syms; i++)
+ {
if (pSym_freq[i])
- sym_freq[i] = static_cast<uint16_t>(maximum<uint32_t>((pSym_freq[i] * 65534U + (max_freq >> 1)) / max_freq, 1));
+ {
+ uint32_t f = static_cast<uint32_t>((static_cast<uint64_t>(pSym_freq[i]) * 65534U + (max_freq >> 1)) / max_freq);
+ sym_freq[i] = static_cast<uint16_t>(clamp<uint32_t>(f, 1, 65534));
+ }
+ }
}
return init(num_syms, &sym_freq[0], max_code_size);
@@ -1125,10 +1409,10 @@ namespace basisu
void image_metrics::calc(const image &a, const image &b, uint32_t first_chan, uint32_t total_chans, bool avg_comp_error, bool use_601_luma)
{
assert((first_chan < 4U) && (first_chan + total_chans <= 4U));
-
- const uint32_t width = std::min(a.get_width(), b.get_width());
- const uint32_t height = std::min(a.get_height(), b.get_height());
-
+
+ const uint32_t width = basisu::minimum(a.get_width(), b.get_width());
+ const uint32_t height = basisu::minimum(a.get_height(), b.get_height());
+
double hist[256];
clear_obj(hist);
@@ -1159,7 +1443,7 @@ namespace basisu
{
if (hist[i])
{
- m_max = std::max<float>(m_max, (float)i);
+ m_max = basisu::maximum<float>(m_max, (float)i);
double v = i * hist[i];
sum += v;
sum2 += i * v;
@@ -1171,9 +1455,9 @@ namespace basisu
total_values *= (double)clamp<uint32_t>(total_chans, 1, 4);
m_mean = (float)clamp<double>(sum / total_values, 0.0f, 255.0);
- m_mean_squared = (float)clamp<double>(sum2 / total_values, 0.0f, 255.0 * 255.0);
+ m_mean_squared = (float)clamp<double>(sum2 / total_values, 0.0f, 255.0f * 255.0f);
m_rms = (float)sqrt(m_mean_squared);
- m_psnr = m_rms ? (float)clamp<double>(log10(255.0 / m_rms) * 20.0, 0.0f, 300.0f) : 1e+10f;
+ m_psnr = m_rms ? (float)clamp<double>(log10(255.0 / m_rms) * 20.0f, 0.0f, 100.0f) : 100.0f;
}
void fill_buffer_with_random_bytes(void *pBuf, size_t size, uint32_t seed)
@@ -1253,8 +1537,8 @@ namespace basisu
}
job_pool::job_pool(uint32_t num_threads) :
- m_kill_flag(false),
- m_num_active_jobs(0)
+ m_num_active_jobs(0),
+ m_kill_flag(false)
{
assert(num_threads >= 1U);
@@ -1302,13 +1586,15 @@ namespace basisu
std::unique_lock<std::mutex> lock(m_mutex);
m_queue.emplace_back(std::move(job));
-
+
const size_t queue_size = m_queue.size();
lock.unlock();
if (queue_size > 1)
+ {
m_has_work.notify_one();
+ }
}
void job_pool::wait_for_all()
@@ -1373,4 +1659,481 @@ namespace basisu
debug_printf("job_pool::job_thread: exiting\n");
}
+ // .TGA image loading
+ #pragma pack(push)
+ #pragma pack(1)
+ struct tga_header
+ {
+ uint8_t m_id_len;
+ uint8_t m_cmap;
+ uint8_t m_type;
+ packed_uint<2> m_cmap_first;
+ packed_uint<2> m_cmap_len;
+ uint8_t m_cmap_bpp;
+ packed_uint<2> m_x_org;
+ packed_uint<2> m_y_org;
+ packed_uint<2> m_width;
+ packed_uint<2> m_height;
+ uint8_t m_depth;
+ uint8_t m_desc;
+ };
+ #pragma pack(pop)
+
+ const uint32_t MAX_TGA_IMAGE_SIZE = 16384;
+
+ enum tga_image_type
+ {
+ cITPalettized = 1,
+ cITRGB = 2,
+ cITGrayscale = 3
+ };
+
+ uint8_t *read_tga(const uint8_t *pBuf, uint32_t buf_size, int &width, int &height, int &n_chans)
+ {
+ width = 0;
+ height = 0;
+ n_chans = 0;
+
+ if (buf_size <= sizeof(tga_header))
+ return nullptr;
+
+ const tga_header &hdr = *reinterpret_cast<const tga_header *>(pBuf);
+
+ if ((!hdr.m_width) || (!hdr.m_height) || (hdr.m_width > MAX_TGA_IMAGE_SIZE) || (hdr.m_height > MAX_TGA_IMAGE_SIZE))
+ return nullptr;
+
+ if (hdr.m_desc >> 6)
+ return nullptr;
+
+ // Simple validation
+ if ((hdr.m_cmap != 0) && (hdr.m_cmap != 1))
+ return nullptr;
+
+ if (hdr.m_cmap)
+ {
+ if ((hdr.m_cmap_bpp == 0) || (hdr.m_cmap_bpp > 32))
+ return nullptr;
+
+ // Nobody implements CMapFirst correctly, so we're not supporting it. Never seen it used, either.
+ if (hdr.m_cmap_first != 0)
+ return nullptr;
+ }
+
+ const bool x_flipped = (hdr.m_desc & 0x10) != 0;
+ const bool y_flipped = (hdr.m_desc & 0x20) == 0;
+
+ bool rle_flag = false;
+ int file_image_type = hdr.m_type;
+ if (file_image_type > 8)
+ {
+ file_image_type -= 8;
+ rle_flag = true;
+ }
+
+ const tga_image_type image_type = static_cast<tga_image_type>(file_image_type);
+
+ switch (file_image_type)
+ {
+ case cITRGB:
+ if (hdr.m_depth == 8)
+ return nullptr;
+ break;
+ case cITPalettized:
+ if ((hdr.m_depth != 8) || (hdr.m_cmap != 1) || (hdr.m_cmap_len == 0))
+ return nullptr;
+ break;
+ case cITGrayscale:
+ if ((hdr.m_cmap != 0) || (hdr.m_cmap_len != 0))
+ return nullptr;
+ if ((hdr.m_depth != 8) && (hdr.m_depth != 16))
+ return nullptr;
+ break;
+ default:
+ return nullptr;
+ }
+
+ uint32_t tga_bytes_per_pixel = 0;
+
+ switch (hdr.m_depth)
+ {
+ case 32:
+ tga_bytes_per_pixel = 4;
+ n_chans = 4;
+ break;
+ case 24:
+ tga_bytes_per_pixel = 3;
+ n_chans = 3;
+ break;
+ case 16:
+ case 15:
+ tga_bytes_per_pixel = 2;
+ // For compatibility with stb_image_write.h
+ n_chans = ((file_image_type == cITGrayscale) && (hdr.m_depth == 16)) ? 4 : 3;
+ break;
+ case 8:
+ tga_bytes_per_pixel = 1;
+ // For palettized RGBA support, which both FreeImage and stb_image support.
+ n_chans = ((file_image_type == cITPalettized) && (hdr.m_cmap_bpp == 32)) ? 4 : 3;
+ break;
+ default:
+ return nullptr;
+ }
+
+ const uint32_t bytes_per_line = hdr.m_width * tga_bytes_per_pixel;
+
+ const uint8_t *pSrc = pBuf + sizeof(tga_header);
+ uint32_t bytes_remaining = buf_size - sizeof(tga_header);
+
+ if (hdr.m_id_len)
+ {
+ if (bytes_remaining < hdr.m_id_len)
+ return nullptr;
+ pSrc += hdr.m_id_len;
+ bytes_remaining += hdr.m_id_len;
+ }
+
+ color_rgba pal[256];
+ for (uint32_t i = 0; i < 256; i++)
+ pal[i].set(0, 0, 0, 255);
+
+ if ((hdr.m_cmap) && (hdr.m_cmap_len))
+ {
+ if (image_type == cITPalettized)
+ {
+ // Note I cannot find any files using 32bpp palettes in the wild (never seen any in ~30 years).
+ if ( ((hdr.m_cmap_bpp != 32) && (hdr.m_cmap_bpp != 24) && (hdr.m_cmap_bpp != 15) && (hdr.m_cmap_bpp != 16)) || (hdr.m_cmap_len > 256) )
+ return nullptr;
+
+ if (hdr.m_cmap_bpp == 32)
+ {
+ const uint32_t pal_size = hdr.m_cmap_len * 4;
+ if (bytes_remaining < pal_size)
+ return nullptr;
+
+ for (uint32_t i = 0; i < hdr.m_cmap_len; i++)
+ {
+ pal[i].r = pSrc[i * 4 + 2];
+ pal[i].g = pSrc[i * 4 + 1];
+ pal[i].b = pSrc[i * 4 + 0];
+ pal[i].a = pSrc[i * 4 + 3];
+ }
+
+ bytes_remaining -= pal_size;
+ pSrc += pal_size;
+ }
+ else if (hdr.m_cmap_bpp == 24)
+ {
+ const uint32_t pal_size = hdr.m_cmap_len * 3;
+ if (bytes_remaining < pal_size)
+ return nullptr;
+
+ for (uint32_t i = 0; i < hdr.m_cmap_len; i++)
+ {
+ pal[i].r = pSrc[i * 3 + 2];
+ pal[i].g = pSrc[i * 3 + 1];
+ pal[i].b = pSrc[i * 3 + 0];
+ pal[i].a = 255;
+ }
+
+ bytes_remaining -= pal_size;
+ pSrc += pal_size;
+ }
+ else
+ {
+ const uint32_t pal_size = hdr.m_cmap_len * 2;
+ if (bytes_remaining < pal_size)
+ return nullptr;
+
+ for (uint32_t i = 0; i < hdr.m_cmap_len; i++)
+ {
+ const uint32_t v = pSrc[i * 2 + 0] | (pSrc[i * 2 + 1] << 8);
+
+ pal[i].r = (((v >> 10) & 31) * 255 + 15) / 31;
+ pal[i].g = (((v >> 5) & 31) * 255 + 15) / 31;
+ pal[i].b = ((v & 31) * 255 + 15) / 31;
+ pal[i].a = 255;
+ }
+
+ bytes_remaining -= pal_size;
+ pSrc += pal_size;
+ }
+ }
+ else
+ {
+ const uint32_t bytes_to_skip = (hdr.m_cmap_bpp >> 3) * hdr.m_cmap_len;
+ if (bytes_remaining < bytes_to_skip)
+ return nullptr;
+ pSrc += bytes_to_skip;
+ bytes_remaining += bytes_to_skip;
+ }
+ }
+
+ width = hdr.m_width;
+ height = hdr.m_height;
+
+ const uint32_t source_pitch = width * tga_bytes_per_pixel;
+ const uint32_t dest_pitch = width * n_chans;
+
+ uint8_t *pImage = (uint8_t *)malloc(dest_pitch * height);
+ if (!pImage)
+ return nullptr;
+
+ std::vector<uint8_t> input_line_buf;
+ if (rle_flag)
+ input_line_buf.resize(source_pitch);
+
+ int run_type = 0, run_remaining = 0;
+ uint8_t run_pixel[4];
+ memset(run_pixel, 0, sizeof(run_pixel));
+
+ for (int y = 0; y < height; y++)
+ {
+ const uint8_t *pLine_data;
+
+ if (rle_flag)
+ {
+ int pixels_remaining = width;
+ uint8_t *pDst = &input_line_buf[0];
+
+ do
+ {
+ if (!run_remaining)
+ {
+ if (bytes_remaining < 1)
+ {
+ free(pImage);
+ return nullptr;
+ }
+
+ int v = *pSrc++;
+ bytes_remaining--;
+
+ run_type = v & 0x80;
+ run_remaining = (v & 0x7F) + 1;
+
+ if (run_type)
+ {
+ if (bytes_remaining < tga_bytes_per_pixel)
+ {
+ free(pImage);
+ return nullptr;
+ }
+
+ memcpy(run_pixel, pSrc, tga_bytes_per_pixel);
+ pSrc += tga_bytes_per_pixel;
+ bytes_remaining -= tga_bytes_per_pixel;
+ }
+ }
+
+ const uint32_t n = basisu::minimum<uint32_t>(pixels_remaining, run_remaining);
+ pixels_remaining -= n;
+ run_remaining -= n;
+
+ if (run_type)
+ {
+ for (uint32_t i = 0; i < n; i++)
+ for (uint32_t j = 0; j < tga_bytes_per_pixel; j++)
+ *pDst++ = run_pixel[j];
+ }
+ else
+ {
+ const uint32_t bytes_wanted = n * tga_bytes_per_pixel;
+
+ if (bytes_remaining < bytes_wanted)
+ {
+ free(pImage);
+ return nullptr;
+ }
+
+ memcpy(pDst, pSrc, bytes_wanted);
+ pDst += bytes_wanted;
+
+ pSrc += bytes_wanted;
+ bytes_remaining -= bytes_wanted;
+ }
+
+ } while (pixels_remaining);
+
+ assert((pDst - &input_line_buf[0]) == width * tga_bytes_per_pixel);
+
+ pLine_data = &input_line_buf[0];
+ }
+ else
+ {
+ if (bytes_remaining < source_pitch)
+ {
+ free(pImage);
+ return nullptr;
+ }
+
+ pLine_data = pSrc;
+ bytes_remaining -= source_pitch;
+ pSrc += source_pitch;
+ }
+
+ // Convert to 24bpp RGB or 32bpp RGBA.
+ uint8_t *pDst = pImage + (y_flipped ? (height - 1 - y) : y) * dest_pitch + (x_flipped ? (width - 1) * n_chans : 0);
+ const int dst_stride = x_flipped ? -((int)n_chans) : n_chans;
+
+ switch (hdr.m_depth)
+ {
+ case 32:
+ assert(tga_bytes_per_pixel == 4 && n_chans == 4);
+ for (int i = 0; i < width; i++, pLine_data += 4, pDst += dst_stride)
+ {
+ pDst[0] = pLine_data[2];
+ pDst[1] = pLine_data[1];
+ pDst[2] = pLine_data[0];
+ pDst[3] = pLine_data[3];
+ }
+ break;
+ case 24:
+ assert(tga_bytes_per_pixel == 3 && n_chans == 3);
+ for (int i = 0; i < width; i++, pLine_data += 3, pDst += dst_stride)
+ {
+ pDst[0] = pLine_data[2];
+ pDst[1] = pLine_data[1];
+ pDst[2] = pLine_data[0];
+ }
+ break;
+ case 16:
+ case 15:
+ if (image_type == cITRGB)
+ {
+ assert(tga_bytes_per_pixel == 2 && n_chans == 3);
+ for (int i = 0; i < width; i++, pLine_data += 2, pDst += dst_stride)
+ {
+ const uint32_t v = pLine_data[0] | (pLine_data[1] << 8);
+ pDst[0] = (((v >> 10) & 31) * 255 + 15) / 31;
+ pDst[1] = (((v >> 5) & 31) * 255 + 15) / 31;
+ pDst[2] = ((v & 31) * 255 + 15) / 31;
+ }
+ }
+ else
+ {
+ assert(image_type == cITGrayscale && tga_bytes_per_pixel == 2 && n_chans == 4);
+ for (int i = 0; i < width; i++, pLine_data += 2, pDst += dst_stride)
+ {
+ pDst[0] = pLine_data[0];
+ pDst[1] = pLine_data[0];
+ pDst[2] = pLine_data[0];
+ pDst[3] = pLine_data[1];
+ }
+ }
+ break;
+ case 8:
+ assert(tga_bytes_per_pixel == 1);
+ if (image_type == cITPalettized)
+ {
+ if (hdr.m_cmap_bpp == 32)
+ {
+ assert(n_chans == 4);
+ for (int i = 0; i < width; i++, pLine_data++, pDst += dst_stride)
+ {
+ const uint32_t c = *pLine_data;
+ pDst[0] = pal[c].r;
+ pDst[1] = pal[c].g;
+ pDst[2] = pal[c].b;
+ pDst[3] = pal[c].a;
+ }
+ }
+ else
+ {
+ assert(n_chans == 3);
+ for (int i = 0; i < width; i++, pLine_data++, pDst += dst_stride)
+ {
+ const uint32_t c = *pLine_data;
+ pDst[0] = pal[c].r;
+ pDst[1] = pal[c].g;
+ pDst[2] = pal[c].b;
+ }
+ }
+ }
+ else
+ {
+ assert(n_chans == 3);
+ for (int i = 0; i < width; i++, pLine_data++, pDst += dst_stride)
+ {
+ const uint8_t c = *pLine_data;
+ pDst[0] = c;
+ pDst[1] = c;
+ pDst[2] = c;
+ }
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ } // y
+
+ return pImage;
+ }
+
+ uint8_t *read_tga(const char *pFilename, int &width, int &height, int &n_chans)
+ {
+ width = height = n_chans = 0;
+
+ uint8_vec filedata;
+ if (!read_file_to_vec(pFilename, filedata))
+ return nullptr;
+
+ if (!filedata.size() || (filedata.size() > UINT32_MAX))
+ return nullptr;
+
+ return read_tga(&filedata[0], (uint32_t)filedata.size(), width, height, n_chans);
+ }
+
+ void image::debug_text(uint32_t x_ofs, uint32_t y_ofs, uint32_t scale_x, uint32_t scale_y, const color_rgba& fg, const color_rgba* pBG, bool alpha_only, const char* pFmt, ...)
+ {
+ char buf[2048];
+
+ va_list args;
+ va_start(args, pFmt);
+#ifdef _WIN32
+ vsprintf_s(buf, sizeof(buf), pFmt, args);
+#else
+ vsnprintf(buf, sizeof(buf), pFmt, args);
+#endif
+ va_end(args);
+
+ const char* p = buf;
+
+ const uint32_t orig_x_ofs = x_ofs;
+
+ while (*p)
+ {
+ uint8_t c = *p++;
+ if ((c < 32) || (c > 127))
+ c = '.';
+
+ const uint8_t* pGlpyh = &g_debug_font8x8_basic[c - 32][0];
+
+ for (uint32_t y = 0; y < 8; y++)
+ {
+ uint32_t row_bits = pGlpyh[y];
+ for (uint32_t x = 0; x < 8; x++)
+ {
+ const uint32_t q = row_bits & (1 << x);
+
+ const color_rgba* pColor = q ? &fg : pBG;
+ if (!pColor)
+ continue;
+
+ if (alpha_only)
+ fill_box_alpha(x_ofs + x * scale_x, y_ofs + y * scale_y, scale_x, scale_y, *pColor);
+ else
+ fill_box(x_ofs + x * scale_x, y_ofs + y * scale_y, scale_x, scale_y, *pColor);
+ }
+ }
+
+ x_ofs += 8 * scale_x;
+ if ((x_ofs + 8 * scale_x) > m_width)
+ {
+ x_ofs = orig_x_ofs;
+ y_ofs += 8 * scale_y;
+ }
+ }
+ }
+
} // namespace basisu
diff --git a/thirdparty/basis_universal/basisu_enc.h b/thirdparty/basis_universal/encoder/basisu_enc.h
index 0a0c3c6fc0..05c95cbc3b 100644
--- a/thirdparty/basis_universal/basisu_enc.h
+++ b/thirdparty/basis_universal/encoder/basisu_enc.h
@@ -1,5 +1,5 @@
// basisu_enc.h
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,8 +13,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
-#include "transcoder/basisu.h"
-#include "transcoder/basisu_transcoder_internal.h"
+#include "../transcoder/basisu.h"
+#include "../transcoder/basisu_transcoder_internal.h"
#include <mutex>
#include <atomic>
@@ -28,13 +28,29 @@
#include <libgen.h>
#endif
+// This module is really just a huge grab bag of classes and helper functions needed by the encoder.
+
+// If BASISU_USE_HIGH_PRECISION_COLOR_DISTANCE is 1, quality in perceptual mode will be slightly greater, but at a large increase in encoding CPU time.
+#define BASISU_USE_HIGH_PRECISION_COLOR_DISTANCE (0)
+
namespace basisu
{
extern uint8_t g_hamming_dist[256];
+ extern const uint8_t g_debug_font8x8_basic[127 - 32 + 1][8];
- // Encoder library initialization
+ // Encoder library initialization.
+ // This function MUST be called before encoding anything!
void basisu_encoder_init();
+ // basisu_kernels_sse.cpp - will be a no-op and g_cpu_supports_sse41 will always be false unless compiled with BASISU_SUPPORT_SSE=1
+ extern void detect_sse41();
+
+#if BASISU_SUPPORT_SSE
+ extern bool g_cpu_supports_sse41;
+#else
+ const bool g_cpu_supports_sse41 = false;
+#endif
+
void error_printf(const char *pFmt, ...);
// Helpers
@@ -43,7 +59,68 @@ namespace basisu
{
return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i);
}
-
+
+ inline int32_t clampi(int32_t value, int32_t low, int32_t high)
+ {
+ if (value < low)
+ value = low;
+ else if (value > high)
+ value = high;
+ return value;
+ }
+
+ inline uint8_t mul_8(uint32_t v, uint32_t a)
+ {
+ v = v * a + 128;
+ return (uint8_t)((v + (v >> 8)) >> 8);
+ }
+
+ inline uint64_t read_bits(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)
+ {
+ assert(codesize <= 64);
+ uint64_t bits = 0;
+ uint32_t total_bits = 0;
+
+ while (total_bits < codesize)
+ {
+ uint32_t byte_bit_offset = bit_offset & 7;
+ uint32_t bits_to_read = minimum<int>(codesize - total_bits, 8 - byte_bit_offset);
+
+ uint32_t byte_bits = pBuf[bit_offset >> 3] >> byte_bit_offset;
+ byte_bits &= ((1 << bits_to_read) - 1);
+
+ bits |= ((uint64_t)(byte_bits) << total_bits);
+
+ total_bits += bits_to_read;
+ bit_offset += bits_to_read;
+ }
+
+ return bits;
+ }
+
+ inline uint32_t read_bits32(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)
+ {
+ assert(codesize <= 32);
+ uint32_t bits = 0;
+ uint32_t total_bits = 0;
+
+ while (total_bits < codesize)
+ {
+ uint32_t byte_bit_offset = bit_offset & 7;
+ uint32_t bits_to_read = minimum<int>(codesize - total_bits, 8 - byte_bit_offset);
+
+ uint32_t byte_bits = pBuf[bit_offset >> 3] >> byte_bit_offset;
+ byte_bits &= ((1 << bits_to_read) - 1);
+
+ bits |= (byte_bits << total_bits);
+
+ total_bits += bits_to_read;
+ bit_offset += bits_to_read;
+ }
+
+ return bits;
+ }
+
// Hashing
inline uint32_t bitmix32c(uint32_t v)
@@ -69,6 +146,16 @@ namespace basisu
return v;
}
+ inline uint32_t wang_hash(uint32_t seed)
+ {
+ seed = (seed ^ 61) ^ (seed >> 16);
+ seed *= 9;
+ seed = seed ^ (seed >> 4);
+ seed *= 0x27d4eb2d;
+ seed = seed ^ (seed >> 15);
+ return seed;
+ }
+
uint32_t hash_hsieh(const uint8_t* pBuf, size_t len);
template <typename Key>
@@ -80,6 +167,72 @@ namespace basisu
}
};
+ class running_stat
+ {
+ public:
+ running_stat() :
+ m_n(0),
+ m_old_m(0), m_new_m(0), m_old_s(0), m_new_s(0)
+ {
+ }
+ void clear()
+ {
+ m_n = 0;
+ }
+ void push(double x)
+ {
+ m_n++;
+ if (m_n == 1)
+ {
+ m_old_m = m_new_m = x;
+ m_old_s = 0.0;
+ m_min = x;
+ m_max = x;
+ }
+ else
+ {
+ m_new_m = m_old_m + (x - m_old_m) / m_n;
+ m_new_s = m_old_s + (x - m_old_m) * (x - m_new_m);
+ m_old_m = m_new_m;
+ m_old_s = m_new_s;
+ m_min = basisu::minimum(x, m_min);
+ m_max = basisu::maximum(x, m_max);
+ }
+ }
+ uint32_t get_num() const
+ {
+ return m_n;
+ }
+ double get_mean() const
+ {
+ return (m_n > 0) ? m_new_m : 0.0;
+ }
+
+ double get_variance() const
+ {
+ return ((m_n > 1) ? m_new_s / (m_n - 1) : 0.0);
+ }
+
+ double get_std_dev() const
+ {
+ return sqrt(get_variance());
+ }
+
+ double get_min() const
+ {
+ return m_min;
+ }
+
+ double get_max() const
+ {
+ return m_max;
+ }
+
+ private:
+ uint32_t m_n;
+ double m_old_m, m_new_m, m_old_s, m_new_s, m_min, m_max;
+ };
+
// Linear algebra
template <uint32_t N, typename T>
@@ -118,7 +271,7 @@ namespace basisu
inline vec &set(const vec<OtherN, OtherT> &other)
{
uint32_t i;
- if (static_cast<void *>(&other) == static_cast<void *>(this))
+ if ((const void *)(&other) == (const void *)(this))
return *this;
const uint32_t m = minimum(OtherN, N);
for (i = 0; i < m; i++)
@@ -358,6 +511,7 @@ namespace basisu
BASISU_NO_EQUALS_OR_COPY_CONSTRUCT(job_pool);
public:
+ // num_threads is the TOTAL number of job pool threads, including the calling thread! So 2=1 new thread, 3=2 new threads, etc.
job_pool(uint32_t num_threads);
~job_pool();
@@ -370,7 +524,7 @@ namespace basisu
private:
std::vector<std::thread> m_threads;
- std::vector<std::function<void()> > m_queue;
+ std::vector<std::function<void()> > m_queue;
std::mutex m_mutex;
std::condition_variable m_has_work;
@@ -420,7 +574,7 @@ namespace basisu
return *this;
}
};
-
+
class color_rgba
{
public:
@@ -440,6 +594,25 @@ namespace basisu
inline color_rgba()
{
static_assert(sizeof(*this) == 4, "sizeof(*this) != 4");
+ static_assert(sizeof(*this) == sizeof(basist::color32), "sizeof(*this) != sizeof(basist::color32)");
+ }
+
+ // Not too hot about this idea.
+ inline color_rgba(const basist::color32& other) :
+ r(other.r),
+ g(other.g),
+ b(other.b),
+ a(other.a)
+ {
+ }
+
+ color_rgba& operator= (const basist::color32& rhs)
+ {
+ r = rhs.r;
+ g = rhs.g;
+ b = rhs.b;
+ a = rhs.a;
+ return *this;
}
inline color_rgba(int y)
@@ -563,11 +736,20 @@ namespace basisu
inline int get_601_luma() const { return (19595U * m_comps[0] + 38470U * m_comps[1] + 7471U * m_comps[2] + 32768U) >> 16U; }
inline int get_709_luma() const { return (13938U * m_comps[0] + 46869U * m_comps[1] + 4729U * m_comps[2] + 32768U) >> 16U; }
inline int get_luma(bool luma_601) const { return luma_601 ? get_601_luma() : get_709_luma(); }
+
+ inline basist::color32 get_color32() const
+ {
+ return basist::color32(r, g, b, a);
+ }
+
+ static color_rgba comp_min(const color_rgba& a, const color_rgba& b) { return color_rgba(basisu::minimum(a[0], b[0]), basisu::minimum(a[1], b[1]), basisu::minimum(a[2], b[2]), basisu::minimum(a[3], b[3])); }
+ static color_rgba comp_max(const color_rgba& a, const color_rgba& b) { return color_rgba(basisu::maximum(a[0], b[0]), basisu::maximum(a[1], b[1]), basisu::maximum(a[2], b[2]), basisu::maximum(a[3], b[3])); }
};
- typedef std::vector<color_rgba> color_rgba_vec;
+ typedef basisu::vector<color_rgba> color_rgba_vec;
const color_rgba g_black_color(0, 0, 0, 255);
+ const color_rgba g_black_trans_color(0, 0, 0, 0);
const color_rgba g_white_color(255, 255, 255, 255);
inline int color_distance(int r0, int g0, int b0, int r1, int g1, int b1)
@@ -595,6 +777,7 @@ namespace basisu
{
if (perceptual)
{
+#if BASISU_USE_HIGH_PRECISION_COLOR_DISTANCE
const float l1 = e1.r * .2126f + e1.g * .715f + e1.b * .0722f;
const float l2 = e2.r * .2126f + e2.g * .715f + e2.b * .0722f;
@@ -617,11 +800,61 @@ namespace basisu
}
return d;
+#elif 1
+ int dr = e1.r - e2.r;
+ int dg = e1.g - e2.g;
+ int db = e1.b - e2.b;
+
+ int delta_l = dr * 27 + dg * 92 + db * 9;
+ int delta_cr = dr * 128 - delta_l;
+ int delta_cb = db * 128 - delta_l;
+
+ uint32_t id = ((uint32_t)(delta_l * delta_l) >> 7U) +
+ ((((uint32_t)(delta_cr * delta_cr) >> 7U) * 26U) >> 7U) +
+ ((((uint32_t)(delta_cb * delta_cb) >> 7U) * 3U) >> 7U);
+
+ if (alpha)
+ {
+ int da = (e1.a - e2.a) << 7;
+ id += ((uint32_t)(da * da) >> 7U);
+ }
+
+ return id;
+#else
+ int dr = e1.r - e2.r;
+ int dg = e1.g - e2.g;
+ int db = e1.b - e2.b;
+
+ int64_t delta_l = dr * 27 + dg * 92 + db * 9;
+ int64_t delta_cr = dr * 128 - delta_l;
+ int64_t delta_cb = db * 128 - delta_l;
+
+ int64_t id = ((delta_l * delta_l) * 128) +
+ ((delta_cr * delta_cr) * 26) +
+ ((delta_cb * delta_cb) * 3);
+
+ if (alpha)
+ {
+ int64_t da = (e1.a - e2.a);
+ id += (da * da) * 128;
+ }
+
+ int d = (id + 8192) >> 14;
+
+ return d;
+#endif
}
else
return color_distance(e1, e2, alpha);
}
+ static inline uint32_t color_distance_la(const color_rgba& a, const color_rgba& b)
+ {
+ const int dl = a.r - b.r;
+ const int da = a.a - b.a;
+ return dl * dl + da * da;
+ }
+
// String helpers
inline int string_find_right(const std::string& filename, char c)
@@ -929,7 +1162,7 @@ namespace basisu
float m_priority;
};
- std::vector<entry> m_heap;
+ basisu::vector<entry> m_heap;
uint32_t m_size;
// Push down entry at index
@@ -961,7 +1194,7 @@ namespace basisu
public:
typedef TrainingVectorType training_vec_type;
typedef std::pair<TrainingVectorType, uint64_t> training_vec_with_weight;
- typedef std::vector< training_vec_with_weight > array_of_weighted_training_vecs;
+ typedef basisu::vector< training_vec_with_weight > array_of_weighted_training_vecs;
tree_vector_quant() :
m_next_codebook_index(0)
@@ -981,7 +1214,7 @@ namespace basisu
const array_of_weighted_training_vecs &get_training_vecs() const { return m_training_vecs; }
array_of_weighted_training_vecs &get_training_vecs() { return m_training_vecs; }
- void retrieve(std::vector< std::vector<uint32_t> > &codebook) const
+ void retrieve(basisu::vector< basisu::vector<uint32_t> > &codebook) const
{
for (uint32_t i = 0; i < m_nodes.size(); i++)
{
@@ -994,7 +1227,7 @@ namespace basisu
}
}
- void retrieve(std::vector<TrainingVectorType> &codebook) const
+ void retrieve(basisu::vector<TrainingVectorType> &codebook) const
{
for (uint32_t i = 0; i < m_nodes.size(); i++)
{
@@ -1007,7 +1240,7 @@ namespace basisu
}
}
- void retrieve(uint32_t max_clusters, std::vector<uint_vec> &codebook) const
+ void retrieve(uint32_t max_clusters, basisu::vector<uint_vec> &codebook) const
{
uint_vec node_stack;
node_stack.reserve(512);
@@ -1054,7 +1287,7 @@ namespace basisu
priority_queue var_heap;
var_heap.init(max_size, 0, m_nodes[0].m_var);
- std::vector<uint32_t> l_children, r_children;
+ basisu::vector<uint32_t> l_children, r_children;
// Now split the worst nodes
l_children.reserve(m_training_vecs.size() + 1);
@@ -1092,7 +1325,7 @@ namespace basisu
inline tsvq_node() : m_weight(0), m_origin(cZero), m_left_index(-1), m_right_index(-1), m_codebook_index(-1) { }
// vecs is erased
- inline void set(const TrainingVectorType &org, uint64_t weight, float var, std::vector<uint32_t> &vecs) { m_origin = org; m_weight = weight; m_var = var; m_training_vecs.swap(vecs); }
+ inline void set(const TrainingVectorType &org, uint64_t weight, float var, basisu::vector<uint32_t> &vecs) { m_origin = org; m_weight = weight; m_var = var; m_training_vecs.swap(vecs); }
inline bool is_leaf() const { return m_left_index < 0; }
@@ -1100,11 +1333,11 @@ namespace basisu
uint64_t m_weight;
TrainingVectorType m_origin;
int32_t m_left_index, m_right_index;
- std::vector<uint32_t> m_training_vecs;
+ basisu::vector<uint32_t> m_training_vecs;
int m_codebook_index;
};
- typedef std::vector<tsvq_node> tsvq_node_vec;
+ typedef basisu::vector<tsvq_node> tsvq_node_vec;
tsvq_node_vec m_nodes;
array_of_weighted_training_vecs m_training_vecs;
@@ -1139,7 +1372,7 @@ namespace basisu
return root;
}
- bool split_node(uint32_t node_index, priority_queue &var_heap, std::vector<uint32_t> &l_children, std::vector<uint32_t> &r_children)
+ bool split_node(uint32_t node_index, priority_queue &var_heap, basisu::vector<uint32_t> &l_children, basisu::vector<uint32_t> &r_children)
{
TrainingVectorType l_child_org, r_child_org;
uint64_t l_weight = 0, r_weight = 0;
@@ -1239,7 +1472,7 @@ namespace basisu
bool prep_split(const tsvq_node &node, TrainingVectorType &l_child_result, TrainingVectorType &r_child_result) const
{
- const uint32_t N = TrainingVectorType::num_elements;
+ //const uint32_t N = TrainingVectorType::num_elements;
if (2 == node.m_training_vecs.size())
{
@@ -1304,7 +1537,7 @@ namespace basisu
if (largest_axis_index < 0)
return false;
- std::vector<float> keys(node.m_training_vecs.size());
+ basisu::vector<float> keys(node.m_training_vecs.size());
for (uint32_t i = 0; i < node.m_training_vecs.size(); i++)
keys[i] = m_training_vecs[node.m_training_vecs[i]].first[largest_axis_index];
@@ -1352,8 +1585,8 @@ namespace basisu
}
bool refine_split(const tsvq_node &node,
- TrainingVectorType &l_child, uint64_t &l_weight, float &l_var, std::vector<uint32_t> &l_children,
- TrainingVectorType &r_child, uint64_t &r_weight, float &r_var, std::vector<uint32_t> &r_children) const
+ TrainingVectorType &l_child, uint64_t &l_weight, float &l_var, basisu::vector<uint32_t> &l_children,
+ TrainingVectorType &r_child, uint64_t &r_weight, float &r_var, basisu::vector<uint32_t> &r_children) const
{
l_children.reserve(node.m_training_vecs.size());
r_children.reserve(node.m_training_vecs.size());
@@ -1466,8 +1699,8 @@ namespace basisu
template<typename Quantizer>
bool generate_hierarchical_codebook_threaded_internal(Quantizer& q,
uint32_t max_codebook_size, uint32_t max_parent_codebook_size,
- std::vector<uint_vec>& codebook,
- std::vector<uint_vec>& parent_codebook,
+ basisu::vector<uint_vec>& codebook,
+ basisu::vector<uint_vec>& parent_codebook,
uint32_t max_threads, bool limit_clusterizers, job_pool *pJob_pool)
{
codebook.resize(0);
@@ -1493,7 +1726,7 @@ namespace basisu
if (!q.generate(max_threads))
return false;
- std::vector<uint_vec> initial_codebook;
+ basisu::vector<uint_vec> initial_codebook;
q.retrieve(initial_codebook);
@@ -1512,12 +1745,14 @@ namespace basisu
bool success_flags[cMaxThreads];
clear_obj(success_flags);
- std::vector<uint_vec> local_clusters[cMaxThreads];
- std::vector<uint_vec> local_parent_clusters[cMaxThreads];
+ basisu::vector<uint_vec> local_clusters[cMaxThreads];
+ basisu::vector<uint_vec> local_parent_clusters[cMaxThreads];
for (uint32_t thread_iter = 0; thread_iter < max_threads; thread_iter++)
{
+#ifndef __EMSCRIPTEN__
pJob_pool->add_job( [thread_iter, &local_clusters, &local_parent_clusters, &success_flags, &quantizers, &initial_codebook, &q, &limit_clusterizers, &max_codebook_size, &max_threads, &max_parent_codebook_size] {
+#endif
Quantizer& lq = quantizers[thread_iter];
uint_vec& cluster_indices = initial_codebook[thread_iter];
@@ -1558,11 +1793,15 @@ namespace basisu
}
}
+#ifndef __EMSCRIPTEN__
} );
+#endif
} // thread_iter
+#ifndef __EMSCRIPTEN__
pJob_pool->wait_for_all();
+#endif
uint32_t total_clusters = 0, total_parent_clusters = 0;
@@ -1598,8 +1837,8 @@ namespace basisu
template<typename Quantizer>
bool generate_hierarchical_codebook_threaded(Quantizer& q,
uint32_t max_codebook_size, uint32_t max_parent_codebook_size,
- std::vector<uint_vec>& codebook,
- std::vector<uint_vec>& parent_codebook,
+ basisu::vector<uint_vec>& codebook,
+ basisu::vector<uint_vec>& parent_codebook,
uint32_t max_threads, job_pool *pJob_pool)
{
typedef bit_hasher<typename Quantizer::training_vec_type> training_vec_bit_hasher;
@@ -1629,7 +1868,7 @@ namespace basisu
Quantizer group_quant;
typedef typename group_hash::const_iterator group_hash_const_iter;
- std::vector<group_hash_const_iter> unique_vec_iters;
+ basisu::vector<group_hash_const_iter> unique_vec_iters;
unique_vec_iters.reserve(unique_vecs.size());
for (auto iter = unique_vecs.begin(); iter != unique_vecs.end(); ++iter)
@@ -1644,7 +1883,7 @@ namespace basisu
debug_printf("Limit clusterizers: %u\n", limit_clusterizers);
- std::vector<uint_vec> group_codebook, group_parent_codebook;
+ basisu::vector<uint_vec> group_codebook, group_parent_codebook;
bool status = generate_hierarchical_codebook_threaded_internal(group_quant,
max_codebook_size, max_parent_codebook_size,
group_codebook,
@@ -1693,7 +1932,7 @@ namespace basisu
class histogram
{
- std::vector<uint32_t> m_hist;
+ basisu::vector<uint32_t> m_hist;
public:
histogram(uint32_t size = 0) { init(size); }
@@ -1754,7 +1993,8 @@ namespace basisu
struct sym_freq
{
- uint16_t m_key, m_sym_index;
+ uint32_t m_key;
+ uint16_t m_sym_index;
};
sym_freq *canonical_huffman_radix_sort_syms(uint32_t num_syms, sym_freq *pSyms0, sym_freq *pSyms1);
@@ -1835,7 +2075,7 @@ namespace basisu
{
if (m_bit_buffer_size)
{
- m_total_bits += 8;
+ m_total_bits += 8 - (m_bit_buffer_size & 7);
append_byte(static_cast<uint8_t>(m_bit_buffer));
m_bit_buffer = 0;
@@ -2107,6 +2347,12 @@ namespace basisu
resize(w, h, p);
}
+ image(const uint8_t *pImage, uint32_t width, uint32_t height, uint32_t comps) :
+ m_width(0), m_height(0), m_pitch(0)
+ {
+ init(pImage, width, height, comps);
+ }
+
image(const image &other) :
m_width(0), m_height(0), m_pitch(0)
{
@@ -2155,6 +2401,47 @@ namespace basisu
return *this;
}
+ void init(const uint8_t *pImage, uint32_t width, uint32_t height, uint32_t comps)
+ {
+ assert(comps >= 1 && comps <= 4);
+
+ resize(width, height);
+
+ for (uint32_t y = 0; y < height; y++)
+ {
+ for (uint32_t x = 0; x < width; x++)
+ {
+ const uint8_t *pSrc = &pImage[(x + y * width) * comps];
+ color_rgba &dst = (*this)(x, y);
+
+ if (comps == 1)
+ {
+ dst.r = pSrc[0];
+ dst.g = pSrc[0];
+ dst.b = pSrc[0];
+ dst.a = 255;
+ }
+ else if (comps == 2)
+ {
+ dst.r = pSrc[0];
+ dst.g = pSrc[0];
+ dst.b = pSrc[0];
+ dst.a = pSrc[1];
+ }
+ else
+ {
+ dst.r = pSrc[0];
+ dst.g = pSrc[1];
+ dst.b = pSrc[2];
+ if (comps == 4)
+ dst.a = pSrc[3];
+ else
+ dst.a = 255;
+ }
+ }
+ }
+ }
+
image &fill_box(uint32_t x, uint32_t y, uint32_t w, uint32_t h, const color_rgba &c)
{
for (uint32_t iy = 0; iy < h; iy++)
@@ -2163,6 +2450,14 @@ namespace basisu
return *this;
}
+ image& fill_box_alpha(uint32_t x, uint32_t y, uint32_t w, uint32_t h, const color_rgba& c)
+ {
+ for (uint32_t iy = 0; iy < h; iy++)
+ for (uint32_t ix = 0; ix < w; ix++)
+ set_clipped_alpha(x + ix, y + iy, c);
+ return *this;
+ }
+
image &crop_dup_borders(uint32_t w, uint32_t h)
{
const uint32_t orig_w = m_width, orig_h = m_height;
@@ -2252,6 +2547,13 @@ namespace basisu
return *this;
}
+ inline image& set_clipped_alpha(int x, int y, const color_rgba& c)
+ {
+ if ((static_cast<uint32_t>(x) < m_width) && (static_cast<uint32_t>(y) < m_height))
+ (*this)(x, y).m_comps[3] = c.m_comps[3];
+ return *this;
+ }
+
// Very straightforward blit with full clipping. Not fast, but it works.
image &blit(const image &src, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y)
{
@@ -2376,6 +2678,8 @@ namespace basisu
}
return *this;
}
+
+ void debug_text(uint32_t x_ofs, uint32_t y_ofs, uint32_t x_scale, uint32_t y_scale, const color_rgba &fg, const color_rgba *pBG, bool alpha_only, const char* p, ...);
private:
uint32_t m_width, m_height, m_pitch; // all in pixels
@@ -2384,7 +2688,7 @@ namespace basisu
// Float images
- typedef std::vector<vec4F> vec4F_vec;
+ typedef basisu::vector<vec4F> vec4F_vec;
class imagef
{
@@ -2635,10 +2939,27 @@ namespace basisu
};
// Image saving/loading/resampling
-
+
+ bool load_png(const uint8_t* pBuf, size_t buf_size, image& img, const char* pFilename = nullptr);
bool load_png(const char* pFilename, image& img);
inline bool load_png(const std::string &filename, image &img) { return load_png(filename.c_str(), img); }
+ bool load_bmp(const char* pFilename, image& img);
+ inline bool load_bmp(const std::string &filename, image &img) { return load_bmp(filename.c_str(), img); }
+
+ bool load_tga(const char* pFilename, image& img);
+ inline bool load_tga(const std::string &filename, image &img) { return load_tga(filename.c_str(), img); }
+
+ bool load_jpg(const char *pFilename, image& img);
+ inline bool load_jpg(const std::string &filename, image &img) { return load_jpg(filename.c_str(), img); }
+
+ // Currently loads .BMP, .PNG, or .TGA.
+ bool load_image(const char* pFilename, image& img);
+ inline bool load_image(const std::string &filename, image &img) { return load_image(filename.c_str(), img); }
+
+ uint8_t *read_tga(const uint8_t *pBuf, uint32_t buf_size, int &width, int &height, int &n_chans);
+ uint8_t *read_tga(const char *pFilename, int &width, int &height, int &n_chans);
+
enum
{
cImageSaveGrayscale = 1,
@@ -2697,7 +3018,7 @@ namespace basisu
template<typename T>
class vector2D
{
- typedef std::vector<T> TVec;
+ typedef basisu::vector<T> TVec;
uint32_t m_width, m_height;
TVec m_values;
@@ -2800,7 +3121,7 @@ namespace basisu
}
void fill_buffer_with_random_bytes(void *pBuf, size_t size, uint32_t seed = 1);
-
+
} // namespace basisu
diff --git a/thirdparty/basis_universal/encoder/basisu_etc.cpp b/thirdparty/basis_universal/encoder/basisu_etc.cpp
new file mode 100644
index 0000000000..232e8965b0
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_etc.cpp
@@ -0,0 +1,1593 @@
+// basis_etc.cpp
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "basisu_etc.h"
+
+#if BASISU_SUPPORT_SSE
+#define CPPSPMD_NAME(a) a##_sse41
+#include "basisu_kernels_declares.h"
+#endif
+
+#define BASISU_DEBUG_ETC_ENCODER 0
+#define BASISU_DEBUG_ETC_ENCODER_DEEPER 0
+
+namespace basisu
+{
+ const int8_t g_etc2_eac_tables[16][8] =
+ {
+ { -3, -6, -9, -15, 2, 5, 8, 14 }, { -3, -7, -10, -13, 2, 6, 9, 12 }, { -2, -5, -8, -13, 1, 4, 7, 12 }, { -2, -4, -6, -13, 1, 3, 5, 12 },
+ { -3, -6, -8, -12, 2, 5, 7, 11 }, { -3, -7, -9, -11, 2, 6, 8, 10 }, { -4, -7, -8, -11, 3, 6, 7, 10 }, { -3, -5, -8, -11, 2, 4, 7, 10 },
+ { -2, -6, -8, -10, 1, 5, 7, 9 }, { -2, -5, -8, -10, 1, 4, 7, 9 }, { -2, -4, -8, -10, 1, 3, 7, 9 }, { -2, -5, -7, -10, 1, 4, 6, 9 },
+ { -3, -4, -7, -10, 2, 3, 6, 9 }, { -1, -2, -3, -10, 0, 1, 2, 9 }, { -4, -6, -8, -9, 3, 5, 7, 8 }, { -3, -5, -7, -9, 2, 4, 6, 8 }
+ };
+
+ const int8_t g_etc2_eac_tables8[16][8] =
+ {
+ { -24, -48, -72, -120, 16, 40, 64, 112 }, { -24,-56,-80,-104,16,48,72,96 }, { -16,-40,-64,-104,8,32,56,96 }, { -16,-32,-48,-104,8,24,40,96 },
+ { -24,-48,-64,-96,16,40,56,88 }, { -24,-56,-72,-88,16,48,64,80 }, { -32,-56,-64,-88,24,48,56,80 }, { -24,-40,-64,-88,16,32,56,80 },
+ { -16,-48,-64,-80,8,40,56,72 }, { -16,-40,-64,-80,8,32,56,72 }, { -16,-32,-64,-80,8,24,56,72 }, { -16,-40,-56,-80,8,32,48,72 },
+ { -24,-32,-56,-80,16,24,48,72 }, { -8,-16,-24,-80,0,8,16,72 }, { -32,-48,-64,-72,24,40,56,64 }, { -24,-40,-56,-72,16,32,48,64 }
+ };
+
+ // Given an ETC1 diff/inten_table/selector, and an 8-bit desired color, this table encodes the best packed_color in the low byte, and the abs error in the high byte.
+ static uint16_t g_etc1_inverse_lookup[2 * 8 * 4][256]; // [ diff/inten_table/selector][desired_color ]
+
+ // g_color8_to_etc_block_config[color][table_index] = Supplies for each 8-bit color value a list of packed ETC1 diff/intensity table/selectors/packed_colors that map to that color.
+ // To pack: diff | (inten << 1) | (selector << 4) | (packed_c << 8)
+ static const uint16_t g_etc1_color8_to_etc_block_config_0_255[2][33] =
+ {
+ { 0x0000, 0x0010, 0x0002, 0x0012, 0x0004, 0x0014, 0x0006, 0x0016, 0x0008, 0x0018, 0x000A, 0x001A, 0x000C, 0x001C, 0x000E, 0x001E, 0x0001, 0x0011, 0x0003, 0x0013, 0x0005, 0x0015, 0x0007, 0x0017, 0x0009, 0x0019, 0x000B, 0x001B, 0x000D, 0x001D, 0x000F, 0x001F, 0xFFFF },
+ { 0x0F20, 0x0F30, 0x0E32, 0x0F22, 0x0E34, 0x0F24, 0x0D36, 0x0F26, 0x0C38, 0x0E28, 0x0B3A, 0x0E2A, 0x093C, 0x0E2C, 0x053E, 0x0D2E, 0x1E31, 0x1F21, 0x1D33, 0x1F23, 0x1C35, 0x1E25, 0x1A37, 0x1E27, 0x1839, 0x1D29, 0x163B, 0x1C2B, 0x133D, 0x1B2D, 0x093F, 0x1A2F, 0xFFFF },
+ };
+
+ // Really only [254][11].
+ static const uint16_t g_etc1_color8_to_etc_block_config_1_to_254[254][12] =
+ {
+ { 0x021C, 0x0D0D, 0xFFFF }, { 0x0020, 0x0021, 0x0A0B, 0x061F, 0xFFFF }, { 0x0113, 0x0217, 0xFFFF }, { 0x0116, 0x031E, 0x0B0E, 0x0405, 0xFFFF }, { 0x0022, 0x0204, 0x050A, 0x0023, 0xFFFF }, { 0x0111, 0x0319, 0x0809, 0x170F, 0xFFFF }, {
+ 0x0303, 0x0215, 0x0607, 0xFFFF }, { 0x0030, 0x0114, 0x0408, 0x0031, 0x0201, 0x051D, 0xFFFF }, { 0x0100, 0x0024, 0x0306, 0x0025, 0x041B, 0x0E0D, 0xFFFF }, { 0x021A, 0x0121, 0x0B0B, 0x071F, 0xFFFF }, { 0x0213, 0x0317, 0xFFFF }, { 0x0112,
+ 0x0505, 0xFFFF }, { 0x0026, 0x070C, 0x0123, 0x0027, 0xFFFF }, { 0x0211, 0x0909, 0xFFFF }, { 0x0110, 0x0315, 0x0707, 0x0419, 0x180F, 0xFFFF }, { 0x0218, 0x0131, 0x0301, 0x0403, 0x061D, 0xFFFF }, { 0x0032, 0x0202, 0x0033, 0x0125, 0x051B,
+ 0x0F0D, 0xFFFF }, { 0x0028, 0x031C, 0x0221, 0x0029, 0xFFFF }, { 0x0120, 0x0313, 0x0C0B, 0x081F, 0xFFFF }, { 0x0605, 0x0417, 0xFFFF }, { 0x0216, 0x041E, 0x0C0E, 0x0223, 0x0127, 0xFFFF }, { 0x0122, 0x0304, 0x060A, 0x0311, 0x0A09, 0xFFFF
+ }, { 0x0519, 0x190F, 0xFFFF }, { 0x002A, 0x0231, 0x0503, 0x0415, 0x0807, 0x002B, 0x071D, 0xFFFF }, { 0x0130, 0x0214, 0x0508, 0x0401, 0x0133, 0x0225, 0x061B, 0xFFFF }, { 0x0200, 0x0124, 0x0406, 0x0321, 0x0129, 0x100D, 0xFFFF }, { 0x031A,
+ 0x0D0B, 0x091F, 0xFFFF }, { 0x0413, 0x0705, 0x0517, 0xFFFF }, { 0x0212, 0x0034, 0x0323, 0x0035, 0x0227, 0xFFFF }, { 0x0126, 0x080C, 0x0B09, 0xFFFF }, { 0x0411, 0x0619, 0x1A0F, 0xFFFF }, { 0x0210, 0x0331, 0x0603, 0x0515, 0x0907, 0x012B,
+ 0xFFFF }, { 0x0318, 0x002C, 0x0501, 0x0233, 0x0325, 0x071B, 0x002D, 0x081D, 0xFFFF }, { 0x0132, 0x0302, 0x0229, 0x110D, 0xFFFF }, { 0x0128, 0x041C, 0x0421, 0x0E0B, 0x0A1F, 0xFFFF }, { 0x0220, 0x0513, 0x0617, 0xFFFF }, { 0x0135, 0x0805,
+ 0x0327, 0xFFFF }, { 0x0316, 0x051E, 0x0D0E, 0x0423, 0xFFFF }, { 0x0222, 0x0404, 0x070A, 0x0511, 0x0719, 0x0C09, 0x1B0F, 0xFFFF }, { 0x0703, 0x0615, 0x0A07, 0x022B, 0xFFFF }, { 0x012A, 0x0431, 0x0601, 0x0333, 0x012D, 0x091D, 0xFFFF }, {
+ 0x0230, 0x0314, 0x0036, 0x0608, 0x0425, 0x0037, 0x0329, 0x081B, 0x120D, 0xFFFF }, { 0x0300, 0x0224, 0x0506, 0x0521, 0x0F0B, 0x0B1F, 0xFFFF }, { 0x041A, 0x0613, 0x0717, 0xFFFF }, { 0x0235, 0x0905, 0xFFFF }, { 0x0312, 0x0134, 0x0523,
+ 0x0427, 0xFFFF }, { 0x0226, 0x090C, 0x002E, 0x0611, 0x0D09, 0x002F, 0xFFFF }, { 0x0715, 0x0B07, 0x0819, 0x032B, 0x1C0F, 0xFFFF }, { 0x0310, 0x0531, 0x0701, 0x0803, 0x022D, 0x0A1D, 0xFFFF }, { 0x0418, 0x012C, 0x0433, 0x0525, 0x0137, 0x091B,
+ 0x130D, 0xFFFF }, { 0x0232, 0x0402, 0x0621, 0x0429, 0xFFFF }, { 0x0228, 0x051C, 0x0713, 0x100B, 0x0C1F, 0xFFFF }, { 0x0320, 0x0335, 0x0A05, 0x0817, 0xFFFF }, { 0x0623, 0x0527, 0xFFFF }, { 0x0416, 0x061E, 0x0E0E, 0x0711, 0x0E09, 0x012F,
+ 0xFFFF }, { 0x0322, 0x0504, 0x080A, 0x0919, 0x1D0F, 0xFFFF }, { 0x0631, 0x0903, 0x0815, 0x0C07, 0x042B, 0x032D, 0x0B1D, 0xFFFF }, { 0x022A, 0x0801, 0x0533, 0x0625, 0x0237, 0x0A1B, 0xFFFF }, { 0x0330, 0x0414, 0x0136, 0x0708, 0x0721, 0x0529,
+ 0x140D, 0xFFFF }, { 0x0400, 0x0324, 0x0606, 0x0038, 0x0039, 0x110B, 0x0D1F, 0xFFFF }, { 0x051A, 0x0813, 0x0B05, 0x0917, 0xFFFF }, { 0x0723, 0x0435, 0x0627, 0xFFFF }, { 0x0412, 0x0234, 0x0F09, 0x022F, 0xFFFF }, { 0x0326, 0x0A0C, 0x012E,
+ 0x0811, 0x0A19, 0x1E0F, 0xFFFF }, { 0x0731, 0x0A03, 0x0915, 0x0D07, 0x052B, 0xFFFF }, { 0x0410, 0x0901, 0x0633, 0x0725, 0x0337, 0x0B1B, 0x042D, 0x0C1D, 0xFFFF }, { 0x0518, 0x022C, 0x0629, 0x150D, 0xFFFF }, { 0x0332, 0x0502, 0x0821, 0x0139,
+ 0x120B, 0x0E1F, 0xFFFF }, { 0x0328, 0x061C, 0x0913, 0x0A17, 0xFFFF }, { 0x0420, 0x0535, 0x0C05, 0x0727, 0xFFFF }, { 0x0823, 0x032F, 0xFFFF }, { 0x0516, 0x071E, 0x0F0E, 0x0911, 0x0B19, 0x1009, 0x1F0F, 0xFFFF }, { 0x0422, 0x0604, 0x090A,
+ 0x0B03, 0x0A15, 0x0E07, 0x062B, 0xFFFF }, { 0x0831, 0x0A01, 0x0733, 0x052D, 0x0D1D, 0xFFFF }, { 0x032A, 0x0825, 0x0437, 0x0729, 0x0C1B, 0x160D, 0xFFFF }, { 0x0430, 0x0514, 0x0236, 0x0808, 0x0921, 0x0239, 0x130B, 0x0F1F, 0xFFFF }, { 0x0500,
+ 0x0424, 0x0706, 0x0138, 0x0A13, 0x0B17, 0xFFFF }, { 0x061A, 0x0635, 0x0D05, 0xFFFF }, { 0x0923, 0x0827, 0xFFFF }, { 0x0512, 0x0334, 0x003A, 0x0A11, 0x1109, 0x003B, 0x042F, 0xFFFF }, { 0x0426, 0x0B0C, 0x022E, 0x0B15, 0x0F07, 0x0C19,
+ 0x072B, 0xFFFF }, { 0x0931, 0x0B01, 0x0C03, 0x062D, 0x0E1D, 0xFFFF }, { 0x0510, 0x0833, 0x0925, 0x0537, 0x0D1B, 0x170D, 0xFFFF }, { 0x0618, 0x032C, 0x0A21, 0x0339, 0x0829, 0xFFFF }, { 0x0432, 0x0602, 0x0B13, 0x140B, 0x101F, 0xFFFF }, {
+ 0x0428, 0x071C, 0x0735, 0x0E05, 0x0C17, 0xFFFF }, { 0x0520, 0x0A23, 0x0927, 0xFFFF }, { 0x0B11, 0x1209, 0x013B, 0x052F, 0xFFFF }, { 0x0616, 0x081E, 0x0D19, 0xFFFF }, { 0x0522, 0x0704, 0x0A0A, 0x0A31, 0x0D03, 0x0C15, 0x1007, 0x082B, 0x072D,
+ 0x0F1D, 0xFFFF }, { 0x0C01, 0x0933, 0x0A25, 0x0637, 0x0E1B, 0xFFFF }, { 0x042A, 0x0B21, 0x0929, 0x180D, 0xFFFF }, { 0x0530, 0x0614, 0x0336, 0x0908, 0x0439, 0x150B, 0x111F, 0xFFFF }, { 0x0600, 0x0524, 0x0806, 0x0238, 0x0C13, 0x0F05,
+ 0x0D17, 0xFFFF }, { 0x071A, 0x0B23, 0x0835, 0x0A27, 0xFFFF }, { 0x1309, 0x023B, 0x062F, 0xFFFF }, { 0x0612, 0x0434, 0x013A, 0x0C11, 0x0E19, 0xFFFF }, { 0x0526, 0x0C0C, 0x032E, 0x0B31, 0x0E03, 0x0D15, 0x1107, 0x092B, 0xFFFF }, { 0x0D01,
+ 0x0A33, 0x0B25, 0x0737, 0x0F1B, 0x082D, 0x101D, 0xFFFF }, { 0x0610, 0x0A29, 0x190D, 0xFFFF }, { 0x0718, 0x042C, 0x0C21, 0x0539, 0x160B, 0x121F, 0xFFFF }, { 0x0532, 0x0702, 0x0D13, 0x0E17, 0xFFFF }, { 0x0528, 0x081C, 0x0935, 0x1005, 0x0B27,
+ 0xFFFF }, { 0x0620, 0x0C23, 0x033B, 0x072F, 0xFFFF }, { 0x0D11, 0x0F19, 0x1409, 0xFFFF }, { 0x0716, 0x003C, 0x091E, 0x0F03, 0x0E15, 0x1207, 0x0A2B, 0x003D, 0xFFFF }, { 0x0622, 0x0804, 0x0B0A, 0x0C31, 0x0E01, 0x0B33, 0x092D, 0x111D,
+ 0xFFFF }, { 0x0C25, 0x0837, 0x0B29, 0x101B, 0x1A0D, 0xFFFF }, { 0x052A, 0x0D21, 0x0639, 0x170B, 0x131F, 0xFFFF }, { 0x0630, 0x0714, 0x0436, 0x0A08, 0x0E13, 0x0F17, 0xFFFF }, { 0x0700, 0x0624, 0x0906, 0x0338, 0x0A35, 0x1105, 0xFFFF }, {
+ 0x081A, 0x0D23, 0x0C27, 0xFFFF }, { 0x0E11, 0x1509, 0x043B, 0x082F, 0xFFFF }, { 0x0712, 0x0534, 0x023A, 0x0F15, 0x1307, 0x1019, 0x0B2B, 0x013D, 0xFFFF }, { 0x0626, 0x0D0C, 0x042E, 0x0D31, 0x0F01, 0x1003, 0x0A2D, 0x121D, 0xFFFF }, { 0x0C33,
+ 0x0D25, 0x0937, 0x111B, 0x1B0D, 0xFFFF }, { 0x0710, 0x0E21, 0x0739, 0x0C29, 0xFFFF }, { 0x0818, 0x052C, 0x0F13, 0x180B, 0x141F, 0xFFFF }, { 0x0632, 0x0802, 0x0B35, 0x1205, 0x1017, 0xFFFF }, { 0x0628, 0x091C, 0x0E23, 0x0D27, 0xFFFF }, {
+ 0x0720, 0x0F11, 0x1609, 0x053B, 0x092F, 0xFFFF }, { 0x1119, 0x023D, 0xFFFF }, { 0x0816, 0x013C, 0x0A1E, 0x0E31, 0x1103, 0x1015, 0x1407, 0x0C2B, 0x0B2D, 0x131D, 0xFFFF }, { 0x0722, 0x0904, 0x0C0A, 0x1001, 0x0D33, 0x0E25, 0x0A37, 0x121B,
+ 0xFFFF }, { 0x0F21, 0x0D29, 0x1C0D, 0xFFFF }, { 0x062A, 0x0839, 0x190B, 0x151F, 0xFFFF }, { 0x0730, 0x0814, 0x0536, 0x0B08, 0x1013, 0x1305, 0x1117, 0xFFFF }, { 0x0800, 0x0724, 0x0A06, 0x0438, 0x0F23, 0x0C35, 0x0E27, 0xFFFF }, { 0x091A,
+ 0x1709, 0x063B, 0x0A2F, 0xFFFF }, { 0x1011, 0x1219, 0x033D, 0xFFFF }, { 0x0812, 0x0634, 0x033A, 0x0F31, 0x1203, 0x1115, 0x1507, 0x0D2B, 0xFFFF }, { 0x0726, 0x0E0C, 0x052E, 0x1101, 0x0E33, 0x0F25, 0x0B37, 0x131B, 0x0C2D, 0x141D, 0xFFFF }, {
+ 0x0E29, 0x1D0D, 0xFFFF }, { 0x0810, 0x1021, 0x0939, 0x1A0B, 0x161F, 0xFFFF }, { 0x0918, 0x062C, 0x1113, 0x1217, 0xFFFF }, { 0x0732, 0x0902, 0x0D35, 0x1405, 0x0F27, 0xFFFF }, { 0x0728, 0x0A1C, 0x1023, 0x073B, 0x0B2F, 0xFFFF }, { 0x0820,
+ 0x1111, 0x1319, 0x1809, 0xFFFF }, { 0x1303, 0x1215, 0x1607, 0x0E2B, 0x043D, 0xFFFF }, { 0x0916, 0x023C, 0x0B1E, 0x1031, 0x1201, 0x0F33, 0x0D2D, 0x151D, 0xFFFF }, { 0x0822, 0x0A04, 0x0D0A, 0x1025, 0x0C37, 0x0F29, 0x141B, 0x1E0D, 0xFFFF }, {
+ 0x1121, 0x0A39, 0x1B0B, 0x171F, 0xFFFF }, { 0x072A, 0x1213, 0x1317, 0xFFFF }, { 0x0830, 0x0914, 0x0636, 0x0C08, 0x0E35, 0x1505, 0xFFFF }, { 0x0900, 0x0824, 0x0B06, 0x0538, 0x1123, 0x1027, 0xFFFF }, { 0x0A1A, 0x1211, 0x1909, 0x083B, 0x0C2F,
+ 0xFFFF }, { 0x1315, 0x1707, 0x1419, 0x0F2B, 0x053D, 0xFFFF }, { 0x0912, 0x0734, 0x043A, 0x1131, 0x1301, 0x1403, 0x0E2D, 0x161D, 0xFFFF }, { 0x0826, 0x0F0C, 0x062E, 0x1033, 0x1125, 0x0D37, 0x151B, 0x1F0D, 0xFFFF }, { 0x1221, 0x0B39, 0x1029,
+ 0xFFFF }, { 0x0910, 0x1313, 0x1C0B, 0x181F, 0xFFFF }, { 0x0A18, 0x072C, 0x0F35, 0x1605, 0x1417, 0xFFFF }, { 0x0832, 0x0A02, 0x1223, 0x1127, 0xFFFF }, { 0x0828, 0x0B1C, 0x1311, 0x1A09, 0x093B, 0x0D2F, 0xFFFF }, { 0x0920, 0x1519, 0x063D,
+ 0xFFFF }, { 0x1231, 0x1503, 0x1415, 0x1807, 0x102B, 0x0F2D, 0x171D, 0xFFFF }, { 0x0A16, 0x033C, 0x0C1E, 0x1401, 0x1133, 0x1225, 0x0E37, 0x161B, 0xFFFF }, { 0x0922, 0x0B04, 0x0E0A, 0x1321, 0x1129, 0xFFFF }, { 0x0C39, 0x1D0B, 0x191F, 0xFFFF
+ }, { 0x082A, 0x1413, 0x1705, 0x1517, 0xFFFF }, { 0x0930, 0x0A14, 0x0736, 0x0D08, 0x1323, 0x1035, 0x1227, 0xFFFF }, { 0x0A00, 0x0924, 0x0C06, 0x0638, 0x1B09, 0x0A3B, 0x0E2F, 0xFFFF }, { 0x0B1A, 0x1411, 0x1619, 0x073D, 0xFFFF }, { 0x1331,
+ 0x1603, 0x1515, 0x1907, 0x112B, 0xFFFF }, { 0x0A12, 0x0834, 0x053A, 0x1501, 0x1233, 0x1325, 0x0F37, 0x171B, 0x102D, 0x181D, 0xFFFF }, { 0x0926, 0x072E, 0x1229, 0xFFFF }, { 0x1421, 0x0D39, 0x1E0B, 0x1A1F, 0xFFFF }, { 0x0A10, 0x1513,
+ 0x1617, 0xFFFF }, { 0x0B18, 0x082C, 0x1135, 0x1805, 0x1327, 0xFFFF }, { 0x0932, 0x0B02, 0x1423, 0x0B3B, 0x0F2F, 0xFFFF }, { 0x0928, 0x0C1C, 0x1511, 0x1719, 0x1C09, 0xFFFF }, { 0x0A20, 0x1703, 0x1615, 0x1A07, 0x122B, 0x083D, 0xFFFF }, {
+ 0x1431, 0x1601, 0x1333, 0x112D, 0x191D, 0xFFFF }, { 0x0B16, 0x043C, 0x0D1E, 0x1425, 0x1037, 0x1329, 0x181B, 0xFFFF }, { 0x0A22, 0x0C04, 0x0F0A, 0x1521, 0x0E39, 0x1F0B, 0x1B1F, 0xFFFF }, { 0x1613, 0x1717, 0xFFFF }, { 0x092A, 0x1235, 0x1905,
+ 0xFFFF }, { 0x0A30, 0x0B14, 0x0836, 0x0E08, 0x1523, 0x1427, 0xFFFF }, { 0x0B00, 0x0A24, 0x0D06, 0x0738, 0x1611, 0x1D09, 0x0C3B, 0x102F, 0xFFFF }, { 0x0C1A, 0x1715, 0x1B07, 0x1819, 0x132B, 0x093D, 0xFFFF }, { 0x1531, 0x1701, 0x1803, 0x122D,
+ 0x1A1D, 0xFFFF }, { 0x0B12, 0x0934, 0x063A, 0x1433, 0x1525, 0x1137, 0x191B, 0xFFFF }, { 0x0A26, 0x003E, 0x082E, 0x1621, 0x0F39, 0x1429, 0x003F, 0xFFFF }, { 0x1713, 0x1C1F, 0xFFFF }, { 0x0B10, 0x1335, 0x1A05, 0x1817, 0xFFFF }, { 0x0C18,
+ 0x092C, 0x1623, 0x1527, 0xFFFF }, { 0x0A32, 0x0C02, 0x1711, 0x1E09, 0x0D3B, 0x112F, 0xFFFF }, { 0x0A28, 0x0D1C, 0x1919, 0x0A3D, 0xFFFF }, { 0x0B20, 0x1631, 0x1903, 0x1815, 0x1C07, 0x142B, 0x132D, 0x1B1D, 0xFFFF }, { 0x1801, 0x1533, 0x1625,
+ 0x1237, 0x1A1B, 0xFFFF }, { 0x0C16, 0x053C, 0x0E1E, 0x1721, 0x1529, 0x013F, 0xFFFF }, { 0x0B22, 0x0D04, 0x1039, 0x1D1F, 0xFFFF }, { 0x1813, 0x1B05, 0x1917, 0xFFFF }, { 0x0A2A, 0x1723, 0x1435, 0x1627, 0xFFFF }, { 0x0B30, 0x0C14, 0x0936,
+ 0x0F08, 0x1F09, 0x0E3B, 0x122F, 0xFFFF }, { 0x0C00, 0x0B24, 0x0E06, 0x0838, 0x1811, 0x1A19, 0x0B3D, 0xFFFF }, { 0x0D1A, 0x1731, 0x1A03, 0x1915, 0x1D07, 0x152B, 0xFFFF }, { 0x1901, 0x1633, 0x1725, 0x1337, 0x1B1B, 0x142D, 0x1C1D, 0xFFFF }, {
+ 0x0C12, 0x0A34, 0x073A, 0x1629, 0x023F, 0xFFFF }, { 0x0B26, 0x013E, 0x092E, 0x1821, 0x1139, 0x1E1F, 0xFFFF }, { 0x1913, 0x1A17, 0xFFFF }, { 0x0C10, 0x1535, 0x1C05, 0x1727, 0xFFFF }, { 0x0D18, 0x0A2C, 0x1823, 0x0F3B, 0x132F, 0xFFFF }, {
+ 0x0B32, 0x0D02, 0x1911, 0x1B19, 0xFFFF }, { 0x0B28, 0x0E1C, 0x1B03, 0x1A15, 0x1E07, 0x162B, 0x0C3D, 0xFFFF }, { 0x0C20, 0x1831, 0x1A01, 0x1733, 0x152D, 0x1D1D, 0xFFFF }, { 0x1825, 0x1437, 0x1729, 0x1C1B, 0x033F, 0xFFFF }, { 0x0D16, 0x063C,
+ 0x0F1E, 0x1921, 0x1239, 0x1F1F, 0xFFFF }, { 0x0C22, 0x0E04, 0x1A13, 0x1B17, 0xFFFF }, { 0x1635, 0x1D05, 0xFFFF }, { 0x0B2A, 0x1923, 0x1827, 0xFFFF }, { 0x0C30, 0x0D14, 0x0A36, 0x1A11, 0x103B, 0x142F, 0xFFFF }, { 0x0D00, 0x0C24, 0x0F06,
+ 0x0938, 0x1B15, 0x1F07, 0x1C19, 0x172B, 0x0D3D, 0xFFFF }, { 0x0E1A, 0x1931, 0x1B01, 0x1C03, 0x162D, 0x1E1D, 0xFFFF }, { 0x1833, 0x1925, 0x1537, 0x1D1B, 0xFFFF }, { 0x0D12, 0x0B34, 0x083A, 0x1A21, 0x1339, 0x1829, 0x043F, 0xFFFF }, { 0x0C26,
+ 0x023E, 0x0A2E, 0x1B13, 0xFFFF }, { 0x1735, 0x1E05, 0x1C17, 0xFFFF }, { 0x0D10, 0x1A23, 0x1927, 0xFFFF }, { 0x0E18, 0x0B2C, 0x1B11, 0x113B, 0x152F, 0xFFFF }, { 0x0C32, 0x0E02, 0x1D19, 0x0E3D, 0xFFFF }, { 0x0C28, 0x0F1C, 0x1A31, 0x1D03,
+ 0x1C15, 0x182B, 0x172D, 0x1F1D, 0xFFFF }, { 0x0D20, 0x1C01, 0x1933, 0x1A25, 0x1637, 0x1E1B, 0xFFFF }, { 0x1B21, 0x1929, 0x053F, 0xFFFF }, { 0x0E16, 0x073C, 0x1439, 0xFFFF }, { 0x0D22, 0x0F04, 0x1C13, 0x1F05, 0x1D17, 0xFFFF }, { 0x1B23,
+ 0x1835, 0x1A27, 0xFFFF }, { 0x0C2A, 0x123B, 0x162F, 0xFFFF }, { 0x0D30, 0x0E14, 0x0B36, 0x1C11, 0x1E19, 0x0F3D, 0xFFFF }, { 0x0E00, 0x0D24, 0x0A38, 0x1B31, 0x1E03, 0x1D15, 0x192B, 0xFFFF }, { 0x0F1A, 0x1D01, 0x1A33, 0x1B25, 0x1737, 0x1F1B,
+ 0x182D, 0xFFFF }, { 0x1A29, 0x063F, 0xFFFF }, { 0x0E12, 0x0C34, 0x093A, 0x1C21, 0x1539, 0xFFFF }, { 0x0D26, 0x033E, 0x0B2E, 0x1D13, 0x1E17, 0xFFFF }, { 0x1935, 0x1B27, 0xFFFF }, { 0x0E10, 0x1C23, 0x133B, 0x172F, 0xFFFF }, { 0x0F18,
+ 0x0C2C, 0x1D11, 0x1F19, 0xFFFF }, { 0x0D32, 0x0F02, 0x1F03, 0x1E15, 0x1A2B, 0x103D, 0xFFFF }, { 0x0D28, 0x1C31, 0x1E01, 0x1B33, 0x192D, 0xFFFF }, { 0x0E20, 0x1C25, 0x1837, 0x1B29, 0x073F, 0xFFFF }, { 0x1D21, 0x1639, 0xFFFF }, { 0x0F16,
+ 0x083C, 0x1E13, 0x1F17, 0xFFFF }, { 0x0E22, 0x1A35, 0xFFFF }, { 0x1D23, 0x1C27, 0xFFFF }, { 0x0D2A, 0x1E11, 0x143B, 0x182F, 0xFFFF }, { 0x0E30, 0x0F14, 0x0C36, 0x1F15, 0x1B2B, 0x113D, 0xFFFF }, { 0x0F00, 0x0E24, 0x0B38, 0x1D31, 0x1F01,
+ 0x1A2D, 0xFFFF }, { 0x1C33, 0x1D25, 0x1937, 0xFFFF }, { 0x1E21, 0x1739, 0x1C29, 0x083F, 0xFFFF }, { 0x0F12, 0x0D34, 0x0A3A, 0x1F13, 0xFFFF }, { 0x0E26, 0x043E, 0x0C2E, 0x1B35, 0xFFFF }, { 0x1E23, 0x1D27, 0xFFFF }, { 0x0F10, 0x1F11, 0x153B, 0x192F, 0xFFFF }, { 0x0D2C, 0x123D, 0xFFFF },
+ };
+
+ static uint32_t etc1_decode_value(uint32_t diff, uint32_t inten, uint32_t selector, uint32_t packed_c)
+ {
+ const uint32_t limit = diff ? 32 : 16;
+ BASISU_NOTE_UNUSED(limit);
+ assert((diff < 2) && (inten < 8) && (selector < 4) && (packed_c < limit));
+ int c;
+ if (diff)
+ c = (packed_c >> 2) | (packed_c << 3);
+ else
+ c = packed_c | (packed_c << 4);
+ c += g_etc1_inten_tables[inten][selector];
+ c = clamp<int>(c, 0, 255);
+ return c;
+ }
+
+ void pack_etc1_solid_color_init()
+ {
+ for (uint32_t diff = 0; diff < 2; diff++)
+ {
+ const uint32_t limit = diff ? 32 : 16;
+
+ for (uint32_t inten = 0; inten < 8; inten++)
+ {
+ for (uint32_t selector = 0; selector < 4; selector++)
+ {
+ const uint32_t inverse_table_index = diff + (inten << 1) + (selector << 4);
+ for (uint32_t color = 0; color < 256; color++)
+ {
+ uint32_t best_error = UINT32_MAX, best_packed_c = 0;
+ for (uint32_t packed_c = 0; packed_c < limit; packed_c++)
+ {
+ int v = etc1_decode_value(diff, inten, selector, packed_c);
+ uint32_t err = (uint32_t)labs(v - static_cast<int>(color));
+ if (err < best_error)
+ {
+ best_error = err;
+ best_packed_c = packed_c;
+ if (!best_error)
+ break;
+ }
+ }
+ assert(best_error <= 255);
+ g_etc1_inverse_lookup[inverse_table_index][color] = static_cast<uint16_t>(best_packed_c | (best_error << 8));
+ }
+ }
+ }
+ }
+ }
+
+ // Packs solid color blocks efficiently using a set of small precomputed tables.
+ // For random 888 inputs, MSE results are better than Erricson's ETC1 packer in "slow" mode ~9.5% of the time, is slightly worse only ~.01% of the time, and is equal the rest of the time.
+ uint64_t pack_etc1_block_solid_color(etc_block& block, const uint8_t* pColor)
+ {
+ assert(g_etc1_inverse_lookup[0][255]);
+
+ static uint32_t s_next_comp[4] = { 1, 2, 0, 1 };
+
+ uint32_t best_error = UINT32_MAX, best_i = 0;
+ int best_x = 0, best_packed_c1 = 0, best_packed_c2 = 0;
+
+ // For each possible 8-bit value, there is a precomputed list of diff/inten/selector configurations that allow that 8-bit value to be encoded with no error.
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ const uint32_t c1 = pColor[s_next_comp[i]], c2 = pColor[s_next_comp[i + 1]];
+
+ const int delta_range = 1;
+ for (int delta = -delta_range; delta <= delta_range; delta++)
+ {
+ const int c_plus_delta = clamp<int>(pColor[i] + delta, 0, 255);
+
+ const uint16_t* pTable;
+ if (!c_plus_delta)
+ pTable = g_etc1_color8_to_etc_block_config_0_255[0];
+ else if (c_plus_delta == 255)
+ pTable = g_etc1_color8_to_etc_block_config_0_255[1];
+ else
+ pTable = g_etc1_color8_to_etc_block_config_1_to_254[c_plus_delta - 1];
+
+ do
+ {
+ const uint32_t x = *pTable++;
+
+#ifdef _DEBUG
+ const uint32_t diff = x & 1;
+ const uint32_t inten = (x >> 1) & 7;
+ const uint32_t selector = (x >> 4) & 3;
+ const uint32_t p0 = (x >> 8) & 255;
+ assert(etc1_decode_value(diff, inten, selector, p0) == (uint32_t)c_plus_delta);
+#endif
+
+ const uint16_t* pInverse_table = g_etc1_inverse_lookup[x & 0xFF];
+ uint16_t p1 = pInverse_table[c1];
+ uint16_t p2 = pInverse_table[c2];
+ const uint32_t trial_error = square(c_plus_delta - pColor[i]) + square(p1 >> 8) + square(p2 >> 8);
+ if (trial_error < best_error)
+ {
+ best_error = trial_error;
+ best_x = x;
+ best_packed_c1 = p1 & 0xFF;
+ best_packed_c2 = p2 & 0xFF;
+ best_i = i;
+ if (!best_error)
+ goto found_perfect_match;
+ }
+ } while (*pTable != 0xFFFF);
+ }
+ }
+ found_perfect_match:
+
+ const uint32_t diff = best_x & 1;
+ const uint32_t inten = (best_x >> 1) & 7;
+
+ block.m_bytes[3] = static_cast<uint8_t>(((inten | (inten << 3)) << 2) | (diff << 1));
+
+ const uint32_t etc1_selector = g_selector_index_to_etc1[(best_x >> 4) & 3];
+ *reinterpret_cast<uint16_t*>(&block.m_bytes[4]) = (etc1_selector & 2) ? 0xFFFF : 0;
+ *reinterpret_cast<uint16_t*>(&block.m_bytes[6]) = (etc1_selector & 1) ? 0xFFFF : 0;
+
+ const uint32_t best_packed_c0 = (best_x >> 8) & 255;
+ if (diff)
+ {
+ block.m_bytes[best_i] = static_cast<uint8_t>(best_packed_c0 << 3);
+ block.m_bytes[s_next_comp[best_i]] = static_cast<uint8_t>(best_packed_c1 << 3);
+ block.m_bytes[s_next_comp[best_i + 1]] = static_cast<uint8_t>(best_packed_c2 << 3);
+ }
+ else
+ {
+ block.m_bytes[best_i] = static_cast<uint8_t>(best_packed_c0 | (best_packed_c0 << 4));
+ block.m_bytes[s_next_comp[best_i]] = static_cast<uint8_t>(best_packed_c1 | (best_packed_c1 << 4));
+ block.m_bytes[s_next_comp[best_i + 1]] = static_cast<uint8_t>(best_packed_c2 | (best_packed_c2 << 4));
+ }
+
+ return best_error;
+ }
+
+ const uint32_t BASISU_ETC1_CLUSTER_FIT_ORDER_TABLE_SIZE = 165;
+
+ static const struct { uint8_t m_v[4]; } g_cluster_fit_order_tab[BASISU_ETC1_CLUSTER_FIT_ORDER_TABLE_SIZE] =
+ {
+ { { 0, 0, 0, 8 } },{ { 0, 5, 2, 1 } },{ { 0, 6, 1, 1 } },{ { 0, 7, 0, 1 } },{ { 0, 7, 1, 0 } },
+ { { 0, 0, 8, 0 } },{ { 0, 0, 3, 5 } },{ { 0, 1, 7, 0 } },{ { 0, 0, 4, 4 } },{ { 0, 0, 2, 6 } },
+ { { 0, 0, 7, 1 } },{ { 0, 0, 1, 7 } },{ { 0, 0, 5, 3 } },{ { 1, 6, 0, 1 } },{ { 0, 0, 6, 2 } },
+ { { 0, 2, 6, 0 } },{ { 2, 4, 2, 0 } },{ { 0, 3, 5, 0 } },{ { 3, 3, 1, 1 } },{ { 4, 2, 0, 2 } },
+ { { 1, 5, 2, 0 } },{ { 0, 5, 3, 0 } },{ { 0, 6, 2, 0 } },{ { 2, 4, 1, 1 } },{ { 5, 1, 0, 2 } },
+ { { 6, 1, 1, 0 } },{ { 3, 3, 0, 2 } },{ { 6, 0, 0, 2 } },{ { 0, 8, 0, 0 } },{ { 6, 1, 0, 1 } },
+ { { 0, 1, 6, 1 } },{ { 1, 6, 1, 0 } },{ { 4, 1, 3, 0 } },{ { 0, 2, 5, 1 } },{ { 5, 0, 3, 0 } },
+ { { 5, 3, 0, 0 } },{ { 0, 1, 5, 2 } },{ { 0, 3, 4, 1 } },{ { 2, 5, 1, 0 } },{ { 1, 7, 0, 0 } },
+ { { 0, 1, 4, 3 } },{ { 6, 0, 2, 0 } },{ { 0, 4, 4, 0 } },{ { 2, 6, 0, 0 } },{ { 0, 2, 4, 2 } },
+ { { 0, 5, 1, 2 } },{ { 0, 6, 0, 2 } },{ { 3, 5, 0, 0 } },{ { 0, 4, 3, 1 } },{ { 3, 4, 1, 0 } },
+ { { 4, 3, 1, 0 } },{ { 1, 5, 0, 2 } },{ { 0, 3, 3, 2 } },{ { 1, 4, 1, 2 } },{ { 0, 4, 2, 2 } },
+ { { 2, 3, 3, 0 } },{ { 4, 4, 0, 0 } },{ { 1, 2, 4, 1 } },{ { 0, 5, 0, 3 } },{ { 0, 1, 3, 4 } },
+ { { 1, 5, 1, 1 } },{ { 1, 4, 2, 1 } },{ { 1, 3, 2, 2 } },{ { 5, 2, 1, 0 } },{ { 1, 3, 3, 1 } },
+ { { 0, 1, 2, 5 } },{ { 1, 1, 5, 1 } },{ { 0, 3, 2, 3 } },{ { 2, 5, 0, 1 } },{ { 3, 2, 2, 1 } },
+ { { 2, 3, 0, 3 } },{ { 1, 4, 3, 0 } },{ { 2, 2, 1, 3 } },{ { 6, 2, 0, 0 } },{ { 1, 0, 6, 1 } },
+ { { 3, 3, 2, 0 } },{ { 7, 1, 0, 0 } },{ { 3, 1, 4, 0 } },{ { 0, 2, 3, 3 } },{ { 0, 4, 1, 3 } },
+ { { 0, 4, 0, 4 } },{ { 0, 1, 0, 7 } },{ { 2, 0, 5, 1 } },{ { 2, 0, 4, 2 } },{ { 3, 0, 2, 3 } },
+ { { 2, 2, 4, 0 } },{ { 2, 2, 3, 1 } },{ { 4, 0, 3, 1 } },{ { 3, 2, 3, 0 } },{ { 2, 3, 2, 1 } },
+ { { 1, 3, 4, 0 } },{ { 7, 0, 1, 0 } },{ { 3, 0, 4, 1 } },{ { 1, 0, 5, 2 } },{ { 8, 0, 0, 0 } },
+ { { 3, 0, 1, 4 } },{ { 4, 1, 1, 2 } },{ { 4, 0, 2, 2 } },{ { 1, 2, 5, 0 } },{ { 4, 2, 1, 1 } },
+ { { 3, 4, 0, 1 } },{ { 2, 0, 3, 3 } },{ { 5, 0, 1, 2 } },{ { 5, 0, 0, 3 } },{ { 2, 4, 0, 2 } },
+ { { 2, 1, 4, 1 } },{ { 4, 0, 1, 3 } },{ { 2, 1, 5, 0 } },{ { 4, 2, 2, 0 } },{ { 4, 0, 4, 0 } },
+ { { 1, 0, 4, 3 } },{ { 1, 4, 0, 3 } },{ { 3, 0, 3, 2 } },{ { 4, 3, 0, 1 } },{ { 0, 1, 1, 6 } },
+ { { 1, 3, 1, 3 } },{ { 0, 2, 2, 4 } },{ { 2, 0, 2, 4 } },{ { 5, 1, 1, 1 } },{ { 3, 0, 5, 0 } },
+ { { 2, 3, 1, 2 } },{ { 3, 0, 0, 5 } },{ { 0, 3, 1, 4 } },{ { 5, 0, 2, 1 } },{ { 2, 1, 3, 2 } },
+ { { 2, 0, 6, 0 } },{ { 3, 1, 3, 1 } },{ { 5, 1, 2, 0 } },{ { 1, 0, 3, 4 } },{ { 1, 1, 6, 0 } },
+ { { 4, 0, 0, 4 } },{ { 2, 0, 1, 5 } },{ { 0, 3, 0, 5 } },{ { 1, 3, 0, 4 } },{ { 4, 1, 2, 1 } },
+ { { 1, 2, 3, 2 } },{ { 3, 1, 0, 4 } },{ { 5, 2, 0, 1 } },{ { 1, 2, 2, 3 } },{ { 3, 2, 1, 2 } },
+ { { 2, 2, 2, 2 } },{ { 6, 0, 1, 1 } },{ { 1, 2, 1, 4 } },{ { 1, 1, 4, 2 } },{ { 3, 2, 0, 3 } },
+ { { 1, 2, 0, 5 } },{ { 1, 0, 7, 0 } },{ { 3, 1, 2, 2 } },{ { 1, 0, 2, 5 } },{ { 2, 0, 0, 6 } },
+ { { 2, 1, 1, 4 } },{ { 2, 2, 0, 4 } },{ { 1, 1, 3, 3 } },{ { 7, 0, 0, 1 } },{ { 1, 0, 0, 7 } },
+ { { 2, 1, 2, 3 } },{ { 4, 1, 0, 3 } },{ { 3, 1, 1, 3 } },{ { 1, 1, 2, 4 } },{ { 2, 1, 0, 5 } },
+ { { 1, 0, 1, 6 } },{ { 0, 2, 1, 5 } },{ { 0, 2, 0, 6 } },{ { 1, 1, 1, 5 } },{ { 1, 1, 0, 6 } }
+ };
+
+ const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues] =
+ {
+ { -8, -2, 2, 8 }, { -17, -5, 5, 17 }, { -29, -9, 9, 29 }, { -42, -13, 13, 42 },
+ { -60, -18, 18, 60 }, { -80, -24, 24, 80 }, { -106, -33, 33, 106 }, { -183, -47, 47, 183 }
+ };
+
+ const uint8_t g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 };
+ const uint8_t g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 };
+
+ // [flip][subblock][pixel_index]
+ const etc_coord2 g_etc1_pixel_coords[2][2][8] =
+ {
+ {
+ {
+ { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 },
+ { 1, 0 }, { 1, 1 }, { 1, 2 }, { 1, 3 }
+ },
+ {
+ { 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 },
+ { 3, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 }
+ }
+ },
+ {
+ {
+ { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
+ { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }
+ },
+ {
+ { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },
+ { 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 }
+ },
+ }
+ };
+
+ // [flip][subblock][pixel_index]
+ const uint32_t g_etc1_pixel_indices[2][2][8] =
+ {
+ {
+ {
+ 0 + 4 * 0, 0 + 4 * 1, 0 + 4 * 2, 0 + 4 * 3,
+ 1 + 4 * 0, 1 + 4 * 1, 1 + 4 * 2, 1 + 4 * 3
+ },
+ {
+ 2 + 4 * 0, 2 + 4 * 1, 2 + 4 * 2, 2 + 4 * 3,
+ 3 + 4 * 0, 3 + 4 * 1, 3 + 4 * 2, 3 + 4 * 3
+ }
+ },
+ {
+ {
+ 0 + 4 * 0, 1 + 4 * 0, 2 + 4 * 0, 3 + 4 * 0,
+ 0 + 4 * 1, 1 + 4 * 1, 2 + 4 * 1, 3 + 4 * 1
+ },
+ {
+ 0 + 4 * 2, 1 + 4 * 2, 2 + 4 * 2, 3 + 4 * 2,
+ 0 + 4 * 3, 1 + 4 * 3, 2 + 4 * 3, 3 + 4 * 3
+ },
+ }
+ };
+
+ uint16_t etc_block::pack_color5(const color_rgba& color, bool scaled, uint32_t bias)
+ {
+ return pack_color5(color.r, color.g, color.b, scaled, bias);
+ }
+
+ uint16_t etc_block::pack_color5(uint32_t r, uint32_t g, uint32_t b, bool scaled, uint32_t bias)
+ {
+ if (scaled)
+ {
+ r = (r * 31U + bias) / 255U;
+ g = (g * 31U + bias) / 255U;
+ b = (b * 31U + bias) / 255U;
+ }
+
+ r = minimum(r, 31U);
+ g = minimum(g, 31U);
+ b = minimum(b, 31U);
+
+ return static_cast<uint16_t>(b | (g << 5U) | (r << 10U));
+ }
+
+ color_rgba etc_block::unpack_color5(uint16_t packed_color5, bool scaled, uint32_t alpha)
+ {
+ uint32_t b = packed_color5 & 31U;
+ uint32_t g = (packed_color5 >> 5U) & 31U;
+ uint32_t r = (packed_color5 >> 10U) & 31U;
+
+ if (scaled)
+ {
+ b = (b << 3U) | (b >> 2U);
+ g = (g << 3U) | (g >> 2U);
+ r = (r << 3U) | (r >> 2U);
+ }
+
+ return color_rgba(cNoClamp, r, g, b, minimum(alpha, 255U));
+ }
+
+ void etc_block::unpack_color5(color_rgba& result, uint16_t packed_color5, bool scaled)
+ {
+ result = unpack_color5(packed_color5, scaled, 255);
+ }
+
+ void etc_block::unpack_color5(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color5, bool scaled)
+ {
+ color_rgba c(unpack_color5(packed_color5, scaled, 0));
+ r = c.r;
+ g = c.g;
+ b = c.b;
+ }
+
+ bool etc_block::unpack_color5(color_rgba& result, uint16_t packed_color5, uint16_t packed_delta3, bool scaled, uint32_t alpha)
+ {
+ color_rgba_i16 dc(unpack_delta3(packed_delta3));
+
+ int b = (packed_color5 & 31U) + dc.b;
+ int g = ((packed_color5 >> 5U) & 31U) + dc.g;
+ int r = ((packed_color5 >> 10U) & 31U) + dc.r;
+
+ bool success = true;
+ if (static_cast<uint32_t>(r | g | b) > 31U)
+ {
+ success = false;
+ r = clamp<int>(r, 0, 31);
+ g = clamp<int>(g, 0, 31);
+ b = clamp<int>(b, 0, 31);
+ }
+
+ if (scaled)
+ {
+ b = (b << 3U) | (b >> 2U);
+ g = (g << 3U) | (g >> 2U);
+ r = (r << 3U) | (r >> 2U);
+ }
+
+ result.set_noclamp_rgba(r, g, b, minimum(alpha, 255U));
+ return success;
+ }
+
+ bool etc_block::unpack_color5(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color5, uint16_t packed_delta3, bool scaled, uint32_t alpha)
+ {
+ color_rgba result;
+ const bool success = unpack_color5(result, packed_color5, packed_delta3, scaled, alpha);
+ r = result.r;
+ g = result.g;
+ b = result.b;
+ return success;
+ }
+
+ uint16_t etc_block::pack_delta3(const color_rgba_i16& color)
+ {
+ return pack_delta3(color.r, color.g, color.b);
+ }
+
+ uint16_t etc_block::pack_delta3(int r, int g, int b)
+ {
+ assert((r >= cETC1ColorDeltaMin) && (r <= cETC1ColorDeltaMax));
+ assert((g >= cETC1ColorDeltaMin) && (g <= cETC1ColorDeltaMax));
+ assert((b >= cETC1ColorDeltaMin) && (b <= cETC1ColorDeltaMax));
+ if (r < 0) r += 8;
+ if (g < 0) g += 8;
+ if (b < 0) b += 8;
+ return static_cast<uint16_t>(b | (g << 3) | (r << 6));
+ }
+
+ color_rgba_i16 etc_block::unpack_delta3(uint16_t packed_delta3)
+ {
+ int r = (packed_delta3 >> 6) & 7;
+ int g = (packed_delta3 >> 3) & 7;
+ int b = packed_delta3 & 7;
+ if (r >= 4) r -= 8;
+ if (g >= 4) g -= 8;
+ if (b >= 4) b -= 8;
+ return color_rgba_i16(r, g, b, 255);
+ }
+
+ void etc_block::unpack_delta3(int& r, int& g, int& b, uint16_t packed_delta3)
+ {
+ r = (packed_delta3 >> 6) & 7;
+ g = (packed_delta3 >> 3) & 7;
+ b = packed_delta3 & 7;
+ if (r >= 4) r -= 8;
+ if (g >= 4) g -= 8;
+ if (b >= 4) b -= 8;
+ }
+
+ uint16_t etc_block::pack_color4(const color_rgba& color, bool scaled, uint32_t bias)
+ {
+ return pack_color4(color.r, color.g, color.b, scaled, bias);
+ }
+
+ uint16_t etc_block::pack_color4(uint32_t r, uint32_t g, uint32_t b, bool scaled, uint32_t bias)
+ {
+ if (scaled)
+ {
+ r = (r * 15U + bias) / 255U;
+ g = (g * 15U + bias) / 255U;
+ b = (b * 15U + bias) / 255U;
+ }
+
+ r = minimum(r, 15U);
+ g = minimum(g, 15U);
+ b = minimum(b, 15U);
+
+ return static_cast<uint16_t>(b | (g << 4U) | (r << 8U));
+ }
+
+ color_rgba etc_block::unpack_color4(uint16_t packed_color4, bool scaled, uint32_t alpha)
+ {
+ uint32_t b = packed_color4 & 15U;
+ uint32_t g = (packed_color4 >> 4U) & 15U;
+ uint32_t r = (packed_color4 >> 8U) & 15U;
+
+ if (scaled)
+ {
+ b = (b << 4U) | b;
+ g = (g << 4U) | g;
+ r = (r << 4U) | r;
+ }
+
+ return color_rgba(cNoClamp, r, g, b, minimum(alpha, 255U));
+ }
+
+ void etc_block::unpack_color4(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color4, bool scaled)
+ {
+ color_rgba c(unpack_color4(packed_color4, scaled, 0));
+ r = c.r;
+ g = c.g;
+ b = c.b;
+ }
+
+ void etc_block::get_diff_subblock_colors(color_rgba* pDst, uint16_t packed_color5, uint32_t table_idx)
+ {
+ assert(table_idx < cETC1IntenModifierValues);
+ const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
+
+ uint32_t r, g, b;
+ unpack_color5(r, g, b, packed_color5, true);
+
+ const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
+
+ const int y0 = pInten_modifer_table[0];
+ pDst[0].set(ir + y0, ig + y0, ib + y0, 255);
+
+ const int y1 = pInten_modifer_table[1];
+ pDst[1].set(ir + y1, ig + y1, ib + y1, 255);
+
+ const int y2 = pInten_modifer_table[2];
+ pDst[2].set(ir + y2, ig + y2, ib + y2, 255);
+
+ const int y3 = pInten_modifer_table[3];
+ pDst[3].set(ir + y3, ig + y3, ib + y3, 255);
+ }
+
+ bool etc_block::get_diff_subblock_colors(color_rgba* pDst, uint16_t packed_color5, uint16_t packed_delta3, uint32_t table_idx)
+ {
+ assert(table_idx < cETC1IntenModifierValues);
+ const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
+
+ uint32_t r, g, b;
+ bool success = unpack_color5(r, g, b, packed_color5, packed_delta3, true);
+
+ const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
+
+ const int y0 = pInten_modifer_table[0];
+ pDst[0].set(ir + y0, ig + y0, ib + y0, 255);
+
+ const int y1 = pInten_modifer_table[1];
+ pDst[1].set(ir + y1, ig + y1, ib + y1, 255);
+
+ const int y2 = pInten_modifer_table[2];
+ pDst[2].set(ir + y2, ig + y2, ib + y2, 255);
+
+ const int y3 = pInten_modifer_table[3];
+ pDst[3].set(ir + y3, ig + y3, ib + y3, 255);
+
+ return success;
+ }
+
+ void etc_block::get_abs_subblock_colors(color_rgba* pDst, uint16_t packed_color4, uint32_t table_idx)
+ {
+ assert(table_idx < cETC1IntenModifierValues);
+ const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
+
+ uint32_t r, g, b;
+ unpack_color4(r, g, b, packed_color4, true);
+
+ const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
+
+ const int y0 = pInten_modifer_table[0];
+ pDst[0].set(ir + y0, ig + y0, ib + y0, 255);
+
+ const int y1 = pInten_modifer_table[1];
+ pDst[1].set(ir + y1, ig + y1, ib + y1, 255);
+
+ const int y2 = pInten_modifer_table[2];
+ pDst[2].set(ir + y2, ig + y2, ib + y2, 255);
+
+ const int y3 = pInten_modifer_table[3];
+ pDst[3].set(ir + y3, ig + y3, ib + y3, 255);
+ }
+
+ bool unpack_etc1(const etc_block& block, color_rgba *pDst, bool preserve_alpha)
+ {
+ const bool diff_flag = block.get_diff_bit();
+ const bool flip_flag = block.get_flip_bit();
+ const uint32_t table_index0 = block.get_inten_table(0);
+ const uint32_t table_index1 = block.get_inten_table(1);
+
+ color_rgba subblock_colors0[4];
+ color_rgba subblock_colors1[4];
+
+ if (diff_flag)
+ {
+ const uint16_t base_color5 = block.get_base5_color();
+ const uint16_t delta_color3 = block.get_delta3_color();
+ etc_block::get_diff_subblock_colors(subblock_colors0, base_color5, table_index0);
+
+ if (!etc_block::get_diff_subblock_colors(subblock_colors1, base_color5, delta_color3, table_index1))
+ return false;
+ }
+ else
+ {
+ const uint16_t base_color4_0 = block.get_base4_color(0);
+ etc_block::get_abs_subblock_colors(subblock_colors0, base_color4_0, table_index0);
+
+ const uint16_t base_color4_1 = block.get_base4_color(1);
+ etc_block::get_abs_subblock_colors(subblock_colors1, base_color4_1, table_index1);
+ }
+
+ if (preserve_alpha)
+ {
+ if (flip_flag)
+ {
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ pDst[0].set_rgb(subblock_colors0[block.get_selector(0, y)]);
+ pDst[1].set_rgb(subblock_colors0[block.get_selector(1, y)]);
+ pDst[2].set_rgb(subblock_colors0[block.get_selector(2, y)]);
+ pDst[3].set_rgb(subblock_colors0[block.get_selector(3, y)]);
+ pDst += 4;
+ }
+
+ for (uint32_t y = 2; y < 4; y++)
+ {
+ pDst[0].set_rgb(subblock_colors1[block.get_selector(0, y)]);
+ pDst[1].set_rgb(subblock_colors1[block.get_selector(1, y)]);
+ pDst[2].set_rgb(subblock_colors1[block.get_selector(2, y)]);
+ pDst[3].set_rgb(subblock_colors1[block.get_selector(3, y)]);
+ pDst += 4;
+ }
+ }
+ else
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ pDst[0].set_rgb(subblock_colors0[block.get_selector(0, y)]);
+ pDst[1].set_rgb(subblock_colors0[block.get_selector(1, y)]);
+ pDst[2].set_rgb(subblock_colors1[block.get_selector(2, y)]);
+ pDst[3].set_rgb(subblock_colors1[block.get_selector(3, y)]);
+ pDst += 4;
+ }
+ }
+ }
+ else
+ {
+ if (flip_flag)
+ {
+ // 0000
+ // 0000
+ // 1111
+ // 1111
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ pDst[0] = subblock_colors0[block.get_selector(0, y)];
+ pDst[1] = subblock_colors0[block.get_selector(1, y)];
+ pDst[2] = subblock_colors0[block.get_selector(2, y)];
+ pDst[3] = subblock_colors0[block.get_selector(3, y)];
+ pDst += 4;
+ }
+
+ for (uint32_t y = 2; y < 4; y++)
+ {
+ pDst[0] = subblock_colors1[block.get_selector(0, y)];
+ pDst[1] = subblock_colors1[block.get_selector(1, y)];
+ pDst[2] = subblock_colors1[block.get_selector(2, y)];
+ pDst[3] = subblock_colors1[block.get_selector(3, y)];
+ pDst += 4;
+ }
+ }
+ else
+ {
+ // 0011
+ // 0011
+ // 0011
+ // 0011
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ pDst[0] = subblock_colors0[block.get_selector(0, y)];
+ pDst[1] = subblock_colors0[block.get_selector(1, y)];
+ pDst[2] = subblock_colors1[block.get_selector(2, y)];
+ pDst[3] = subblock_colors1[block.get_selector(3, y)];
+ pDst += 4;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ inline int extend_6_to_8(uint32_t n)
+ {
+ return (n << 2) | (n >> 4);
+ }
+
+ inline int extend_7_to_8(uint32_t n)
+ {
+ return (n << 1) | (n >> 6);
+ }
+
+ inline int extend_4_to_8(uint32_t n)
+ {
+ return (n << 4) | n;
+ }
+
+ uint64_t etc_block::evaluate_etc1_error(const color_rgba* pBlock_pixels, bool perceptual, int subblock_index) const
+ {
+ color_rgba unpacked_block[16];
+
+ unpack_etc1(*this, unpacked_block);
+
+ uint64_t total_error = 0;
+
+ if (subblock_index < 0)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ total_error += color_distance(perceptual, pBlock_pixels[i], unpacked_block[i], false);
+ }
+ else
+ {
+ const bool flip_bit = get_flip_bit();
+
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ const uint32_t idx = g_etc1_pixel_indices[flip_bit][subblock_index][i];
+
+ total_error += color_distance(perceptual, pBlock_pixels[idx], unpacked_block[idx], false);
+ }
+ }
+
+ return total_error;
+ }
+
+ void etc_block::get_subblock_pixels(color_rgba* pPixels, int subblock_index) const
+ {
+ if (subblock_index < 0)
+ unpack_etc1(*this, pPixels);
+ else
+ {
+ color_rgba unpacked_block[16];
+
+ unpack_etc1(*this, unpacked_block);
+
+ const bool flip_bit = get_flip_bit();
+
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ const uint32_t idx = g_etc1_pixel_indices[flip_bit][subblock_index][i];
+
+ pPixels[i] = unpacked_block[idx];
+ }
+ }
+ }
+
+ bool etc1_optimizer::compute()
+ {
+ assert(m_pResult->m_pSelectors);
+
+ if (m_pParams->m_pForce_selectors)
+ {
+ assert(m_pParams->m_quality >= cETCQualitySlow);
+ if (m_pParams->m_quality < cETCQualitySlow)
+ return false;
+ }
+
+ const uint32_t n = m_pParams->m_num_src_pixels;
+
+ if (m_pParams->m_cluster_fit)
+ {
+ if (m_pParams->m_quality == cETCQualityFast)
+ compute_internal_cluster_fit(4);
+ else if (m_pParams->m_quality == cETCQualityMedium)
+ compute_internal_cluster_fit(16);
+ else if (m_pParams->m_quality == cETCQualitySlow)
+ compute_internal_cluster_fit(64);
+ else
+ compute_internal_cluster_fit(BASISU_ETC1_CLUSTER_FIT_ORDER_TABLE_SIZE);
+ }
+ else
+ compute_internal_neighborhood(m_br, m_bg, m_bb);
+
+ if (!m_best_solution.m_valid)
+ {
+ m_pResult->m_error = UINT32_MAX;
+ return false;
+ }
+
+ //const uint8_t* pSelectors = &m_best_solution.m_selectors[0];
+ const uint8_t* pSelectors = m_pParams->m_pForce_selectors ? m_pParams->m_pForce_selectors : &m_best_solution.m_selectors[0];
+
+#if defined(DEBUG) || defined(_DEBUG)
+ {
+ // sanity check the returned error
+ color_rgba block_colors[4];
+ m_best_solution.m_coords.get_block_colors(block_colors);
+
+ const color_rgba* pSrc_pixels = m_pParams->m_pSrc_pixels;
+ uint64_t actual_error = 0;
+
+ bool perceptual;
+ if (m_pParams->m_quality >= cETCQualityMedium)
+ perceptual = m_pParams->m_perceptual;
+ else
+ perceptual = (m_pParams->m_quality == cETCQualityFast) ? false : m_pParams->m_perceptual;
+
+ for (uint32_t i = 0; i < n; i++)
+ actual_error += color_distance(perceptual, pSrc_pixels[i], block_colors[pSelectors[i]], false);
+
+ assert(actual_error == m_best_solution.m_error);
+ }
+#endif
+
+ m_pResult->m_error = m_best_solution.m_error;
+
+ m_pResult->m_block_color_unscaled = m_best_solution.m_coords.m_unscaled_color;
+ m_pResult->m_block_color4 = m_best_solution.m_coords.m_color4;
+
+ m_pResult->m_block_inten_table = m_best_solution.m_coords.m_inten_table;
+ memcpy(m_pResult->m_pSelectors, pSelectors, n);
+ m_pResult->m_n = n;
+
+ return true;
+ }
+
+ void etc1_optimizer::refine_solution(uint32_t max_refinement_trials)
+ {
+ // Now we have the input block, the avg. color of the input pixels, a set of trial selector indices, and the block color+intensity index.
+ // Now, for each component, attempt to refine the current solution by solving a simple linear equation. For example, for 4 colors:
+ // The goal is:
+ // pixel0 - (block_color+inten_table[selector0]) + pixel1 - (block_color+inten_table[selector1]) + pixel2 - (block_color+inten_table[selector2]) + pixel3 - (block_color+inten_table[selector3]) = 0
+ // Rearranging this:
+ // (pixel0 + pixel1 + pixel2 + pixel3) - (block_color+inten_table[selector0]) - (block_color+inten_table[selector1]) - (block_color+inten_table[selector2]) - (block_color+inten_table[selector3]) = 0
+ // (pixel0 + pixel1 + pixel2 + pixel3) - block_color - inten_table[selector0] - block_color-inten_table[selector1] - block_color-inten_table[selector2] - block_color-inten_table[selector3] = 0
+ // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - inten_table[selector0] - inten_table[selector1] - inten_table[selector2] - inten_table[selector3] = 0
+ // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3]) = 0
+ // (pixel0 + pixel1 + pixel2 + pixel3)/4 - block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4 = 0
+ // block_color = (pixel0 + pixel1 + pixel2 + pixel3)/4 - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4
+ // So what this means:
+ // optimal_block_color = avg_input - avg_inten_delta
+ // So the optimal block color can be computed by taking the average block color and subtracting the current average of the intensity delta.
+ // Unfortunately, optimal_block_color must then be quantized to 555 or 444 so it's not always possible to improve matters using this formula.
+ // Also, the above formula is for unclamped intensity deltas. The actual implementation takes into account clamping.
+
+ const uint32_t n = m_pParams->m_num_src_pixels;
+
+ for (uint32_t refinement_trial = 0; refinement_trial < max_refinement_trials; refinement_trial++)
+ {
+ const uint8_t* pSelectors = &m_best_solution.m_selectors[0];
+ const int* pInten_table = g_etc1_inten_tables[m_best_solution.m_coords.m_inten_table];
+
+ int delta_sum_r = 0, delta_sum_g = 0, delta_sum_b = 0;
+ const color_rgba base_color(m_best_solution.m_coords.get_scaled_color());
+ for (uint32_t r = 0; r < n; r++)
+ {
+ const uint32_t s = *pSelectors++;
+ const int yd_temp = pInten_table[s];
+ // Compute actual delta being applied to each pixel, taking into account clamping.
+ delta_sum_r += clamp<int>(base_color.r + yd_temp, 0, 255) - base_color.r;
+ delta_sum_g += clamp<int>(base_color.g + yd_temp, 0, 255) - base_color.g;
+ delta_sum_b += clamp<int>(base_color.b + yd_temp, 0, 255) - base_color.b;
+ }
+
+ if ((!delta_sum_r) && (!delta_sum_g) && (!delta_sum_b))
+ break;
+
+ const float avg_delta_r_f = static_cast<float>(delta_sum_r) / n;
+ const float avg_delta_g_f = static_cast<float>(delta_sum_g) / n;
+ const float avg_delta_b_f = static_cast<float>(delta_sum_b) / n;
+ const int br1 = clamp<int>(static_cast<int32_t>((m_avg_color[0] - avg_delta_r_f) * m_limit / 255.0f + .5f), 0, m_limit);
+ const int bg1 = clamp<int>(static_cast<int32_t>((m_avg_color[1] - avg_delta_g_f) * m_limit / 255.0f + .5f), 0, m_limit);
+ const int bb1 = clamp<int>(static_cast<int32_t>((m_avg_color[2] - avg_delta_b_f) * m_limit / 255.0f + .5f), 0, m_limit);
+
+#if BASISU_DEBUG_ETC_ENCODER_DEEPER
+ printf("Refinement trial %u, avg_delta %f %f %f\n", refinement_trial, avg_delta_r_f, avg_delta_g_f, avg_delta_b_f);
+#endif
+
+ if (!evaluate_solution(etc1_solution_coordinates(br1, bg1, bb1, 0, m_pParams->m_use_color4), m_trial_solution, &m_best_solution))
+ break;
+
+ } // refinement_trial
+ }
+
+ void etc1_optimizer::compute_internal_neighborhood(int scan_r, int scan_g, int scan_b)
+ {
+ if (m_best_solution.m_error == 0)
+ return;
+
+ //const uint32_t n = m_pParams->m_num_src_pixels;
+ const int scan_delta_size = m_pParams->m_scan_delta_size;
+
+ // Scan through a subset of the 3D lattice centered around the avg block color trying each 3D (555 or 444) lattice point as a potential block color.
+ // Each time a better solution is found try to refine the current solution's block color based of the current selectors and intensity table index.
+ for (int zdi = 0; zdi < scan_delta_size; zdi++)
+ {
+ const int zd = m_pParams->m_pScan_deltas[zdi];
+ const int mbb = scan_b + zd;
+ if (mbb < 0) continue; else if (mbb > m_limit) break;
+
+ for (int ydi = 0; ydi < scan_delta_size; ydi++)
+ {
+ const int yd = m_pParams->m_pScan_deltas[ydi];
+ const int mbg = scan_g + yd;
+ if (mbg < 0) continue; else if (mbg > m_limit) break;
+
+ for (int xdi = 0; xdi < scan_delta_size; xdi++)
+ {
+ const int xd = m_pParams->m_pScan_deltas[xdi];
+ const int mbr = scan_r + xd;
+ if (mbr < 0) continue; else if (mbr > m_limit) break;
+
+ etc1_solution_coordinates coords(mbr, mbg, mbb, 0, m_pParams->m_use_color4);
+
+ if (!evaluate_solution(coords, m_trial_solution, &m_best_solution))
+ continue;
+
+ if (m_pParams->m_refinement)
+ {
+ refine_solution((m_pParams->m_quality == cETCQualityFast) ? 2 : (((xd | yd | zd) == 0) ? 4 : 2));
+ }
+
+ } // xdi
+ } // ydi
+ } // zdi
+ }
+
+ void etc1_optimizer::compute_internal_cluster_fit(uint32_t total_perms_to_try)
+ {
+ if ((!m_best_solution.m_valid) || ((m_br != m_best_solution.m_coords.m_unscaled_color.r) || (m_bg != m_best_solution.m_coords.m_unscaled_color.g) || (m_bb != m_best_solution.m_coords.m_unscaled_color.b)))
+ {
+ evaluate_solution(etc1_solution_coordinates(m_br, m_bg, m_bb, 0, m_pParams->m_use_color4), m_trial_solution, &m_best_solution);
+ }
+
+ if ((m_best_solution.m_error == 0) || (!m_best_solution.m_valid))
+ return;
+
+ for (uint32_t i = 0; i < total_perms_to_try; i++)
+ {
+ int delta_sum_r = 0, delta_sum_g = 0, delta_sum_b = 0;
+
+ const int *pInten_table = g_etc1_inten_tables[m_best_solution.m_coords.m_inten_table];
+ const color_rgba base_color(m_best_solution.m_coords.get_scaled_color());
+
+ const uint8_t *pNum_selectors = g_cluster_fit_order_tab[i].m_v;
+
+ for (uint32_t q = 0; q < 4; q++)
+ {
+ const int yd_temp = pInten_table[q];
+
+ delta_sum_r += pNum_selectors[q] * (clamp<int>(base_color.r + yd_temp, 0, 255) - base_color.r);
+ delta_sum_g += pNum_selectors[q] * (clamp<int>(base_color.g + yd_temp, 0, 255) - base_color.g);
+ delta_sum_b += pNum_selectors[q] * (clamp<int>(base_color.b + yd_temp, 0, 255) - base_color.b);
+ }
+
+ if ((!delta_sum_r) && (!delta_sum_g) && (!delta_sum_b))
+ continue;
+
+ const float avg_delta_r_f = static_cast<float>(delta_sum_r) / 8;
+ const float avg_delta_g_f = static_cast<float>(delta_sum_g) / 8;
+ const float avg_delta_b_f = static_cast<float>(delta_sum_b) / 8;
+
+ const int br1 = clamp<int>(static_cast<int32_t>((m_avg_color[0] - avg_delta_r_f) * m_limit / 255.0f + .5f), 0, m_limit);
+ const int bg1 = clamp<int>(static_cast<int32_t>((m_avg_color[1] - avg_delta_g_f) * m_limit / 255.0f + .5f), 0, m_limit);
+ const int bb1 = clamp<int>(static_cast<int32_t>((m_avg_color[2] - avg_delta_b_f) * m_limit / 255.0f + .5f), 0, m_limit);
+
+#if BASISU_DEBUG_ETC_ENCODER_DEEPER
+ printf("Second refinement trial %u, avg_delta %f %f %f\n", i, avg_delta_r_f, avg_delta_g_f, avg_delta_b_f);
+#endif
+
+ evaluate_solution(etc1_solution_coordinates(br1, bg1, bb1, 0, m_pParams->m_use_color4), m_trial_solution, &m_best_solution);
+
+ if (m_best_solution.m_error == 0)
+ break;
+ }
+ }
+
+ void etc1_optimizer::init(const params& params, results& result)
+ {
+ m_pParams = &params;
+ m_pResult = &result;
+
+ const uint32_t n = m_pParams->m_num_src_pixels;
+
+ m_selectors.resize(n);
+ m_best_selectors.resize(n);
+ m_temp_selectors.resize(n);
+ m_trial_solution.m_selectors.resize(n);
+ m_best_solution.m_selectors.resize(n);
+
+ m_limit = m_pParams->m_use_color4 ? 15 : 31;
+
+ vec3F avg_color(0.0f);
+
+ m_luma.resize(n);
+ m_sorted_luma_indices.resize(n);
+ m_sorted_luma.resize(n);
+
+ int min_r = 255, min_g = 255, min_b = 255;
+ int max_r = 0, max_g = 0, max_b = 0;
+
+ for (uint32_t i = 0; i < n; i++)
+ {
+ const color_rgba& c = m_pParams->m_pSrc_pixels[i];
+
+ min_r = basisu::minimum<int>(min_r, c.r);
+ min_g = basisu::minimum<int>(min_g, c.g);
+ min_b = basisu::minimum<int>(min_b, c.b);
+
+ max_r = basisu::maximum<int>(max_r, c.r);
+ max_g = basisu::maximum<int>(max_g, c.g);
+ max_b = basisu::maximum<int>(max_b, c.b);
+
+ const vec3F fc(c.r, c.g, c.b);
+
+ avg_color += fc;
+
+ m_luma[i] = static_cast<uint16_t>(c.r + c.g + c.b);
+ m_sorted_luma_indices[i] = i;
+ }
+ avg_color /= static_cast<float>(n);
+ m_avg_color = avg_color;
+ m_max_comp_spread = basisu::maximum(basisu::maximum(max_r - min_r, max_g - min_g), max_b - min_b);
+
+ m_br = clamp<int>(static_cast<uint32_t>(m_avg_color[0] * m_limit / 255.0f + .5f), 0, m_limit);
+ m_bg = clamp<int>(static_cast<uint32_t>(m_avg_color[1] * m_limit / 255.0f + .5f), 0, m_limit);
+ m_bb = clamp<int>(static_cast<uint32_t>(m_avg_color[2] * m_limit / 255.0f + .5f), 0, m_limit);
+
+#if BASISU_DEBUG_ETC_ENCODER_DEEPER
+ printf("Avg block color: %u %u %u\n", m_br, m_bg, m_bb);
+#endif
+
+ if (m_pParams->m_quality == cETCQualityFast)
+ {
+ indirect_sort(n, &m_sorted_luma_indices[0], &m_luma[0]);
+
+ m_pSorted_luma = &m_sorted_luma[0];
+ m_pSorted_luma_indices = &m_sorted_luma_indices[0];
+
+ for (uint32_t i = 0; i < n; i++)
+ m_pSorted_luma[i] = m_luma[m_pSorted_luma_indices[i]];
+ }
+
+ m_best_solution.m_coords.clear();
+ m_best_solution.m_valid = false;
+ m_best_solution.m_error = UINT64_MAX;
+
+ clear_obj(m_solutions_tried);
+ }
+
+ // Return false if we've probably already tried this solution, true if we have definitely not.
+ bool etc1_optimizer::check_for_redundant_solution(const etc1_solution_coordinates& coords)
+ {
+ // Hash first 3 bytes of color (RGB)
+ uint32_t kh = hash_hsieh((uint8_t*)&coords.m_unscaled_color.r, 3);
+
+ uint32_t h0 = kh & cSolutionsTriedHashMask;
+ uint32_t h1 = (kh >> cSolutionsTriedHashBits) & cSolutionsTriedHashMask;
+
+ // Simple Bloom filter lookup with k=2
+ if ( ((m_solutions_tried[h0 >> 3] & (1 << (h0 & 7))) != 0) &&
+ ((m_solutions_tried[h1 >> 3] & (1 << (h1 & 7))) != 0) )
+ return false;
+
+ m_solutions_tried[h0 >> 3] |= (1 << (h0 & 7));
+ m_solutions_tried[h1 >> 3] |= (1 << (h1 & 7));
+
+ return true;
+ }
+
+ static uint8_t g_eval_dist_tables[8][256] =
+ {
+ // 99% threshold
+ { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
+ { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
+ { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
+ { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,},
+ { 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,},
+ { 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
+ { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,}
+ };
+
+ bool etc1_optimizer::evaluate_solution_slow(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution)
+ {
+ if (!check_for_redundant_solution(coords))
+ return false;
+
+#if BASISU_DEBUG_ETC_ENCODER_DEEPER
+ printf("Eval solution: %u %u %u\n", coords.m_unscaled_color.r, coords.m_unscaled_color.g, coords.m_unscaled_color.b);
+#endif
+
+ trial_solution.m_valid = false;
+
+ if (m_pParams->m_constrain_against_base_color5)
+ {
+ const int dr = (int)coords.m_unscaled_color.r - (int)m_pParams->m_base_color5.r;
+ const int dg = (int)coords.m_unscaled_color.g - (int)m_pParams->m_base_color5.g;
+ const int db = (int)coords.m_unscaled_color.b - (int)m_pParams->m_base_color5.b;
+
+ if ((minimum(dr, dg, db) < cETC1ColorDeltaMin) || (maximum(dr, dg, db) > cETC1ColorDeltaMax))
+ {
+#if BASISU_DEBUG_ETC_ENCODER_DEEPER
+ printf("Eval failed due to constraint from %u %u %u\n", m_pParams->m_base_color5.r, m_pParams->m_base_color5.g, m_pParams->m_base_color5.b);
+#endif
+ return false;
+ }
+ }
+
+ const color_rgba base_color(coords.get_scaled_color());
+
+ const uint32_t n = m_pParams->m_num_src_pixels;
+ assert(trial_solution.m_selectors.size() == n);
+
+ trial_solution.m_error = INT64_MAX;
+
+ const uint8_t *pSelectors_to_use = m_pParams->m_pForce_selectors;
+
+ for (uint32_t inten_table = 0; inten_table < cETC1IntenModifierValues; inten_table++)
+ {
+ if (m_pParams->m_quality <= cETCQualityMedium)
+ {
+ if (!g_eval_dist_tables[inten_table][m_max_comp_spread])
+ continue;
+ }
+#if 0
+ if (m_pParams->m_quality <= cETCQualityMedium)
+ {
+ // For tables 5-7, if the max component spread falls within certain ranges, skip the inten table. Statistically they are extremely unlikely to result in lower error.
+ if (inten_table == 7)
+ {
+ if (m_max_comp_spread < 42)
+ continue;
+ }
+ else if (inten_table == 6)
+ {
+ if ((m_max_comp_spread >= 12) && (m_max_comp_spread <= 31))
+ continue;
+ }
+ else if (inten_table == 5)
+ {
+ if ((m_max_comp_spread >= 13) && (m_max_comp_spread <= 21))
+ continue;
+ }
+ }
+#endif
+
+ const int* pInten_table = g_etc1_inten_tables[inten_table];
+
+ color_rgba block_colors[4];
+ for (uint32_t s = 0; s < 4; s++)
+ {
+ const int yd = pInten_table[s];
+ block_colors[s].set(base_color.r + yd, base_color.g + yd, base_color.b + yd, 255);
+ }
+
+ uint64_t total_error = 0;
+
+ const color_rgba* pSrc_pixels = m_pParams->m_pSrc_pixels;
+
+ if (!g_cpu_supports_sse41)
+ {
+ for (uint32_t c = 0; c < n; c++)
+ {
+ const color_rgba& src_pixel = *pSrc_pixels++;
+
+ uint32_t best_selector_index = 0;
+ uint32_t best_error = 0;
+
+ if (pSelectors_to_use)
+ {
+ best_selector_index = pSelectors_to_use[c];
+ best_error = color_distance(m_pParams->m_perceptual, src_pixel, block_colors[best_selector_index], false);
+ }
+ else
+ {
+ best_error = color_distance(m_pParams->m_perceptual, src_pixel, block_colors[0], false);
+
+ uint32_t trial_error = color_distance(m_pParams->m_perceptual, src_pixel, block_colors[1], false);
+ if (trial_error < best_error)
+ {
+ best_error = trial_error;
+ best_selector_index = 1;
+ }
+
+ trial_error = color_distance(m_pParams->m_perceptual, src_pixel, block_colors[2], false);
+ if (trial_error < best_error)
+ {
+ best_error = trial_error;
+ best_selector_index = 2;
+ }
+
+ trial_error = color_distance(m_pParams->m_perceptual, src_pixel, block_colors[3], false);
+ if (trial_error < best_error)
+ {
+ best_error = trial_error;
+ best_selector_index = 3;
+ }
+ }
+
+ m_temp_selectors[c] = static_cast<uint8_t>(best_selector_index);
+
+ total_error += best_error;
+ if (total_error >= trial_solution.m_error)
+ break;
+ }
+ }
+ else
+ {
+#if BASISU_SUPPORT_SSE
+ if (pSelectors_to_use)
+ {
+ if (m_pParams->m_perceptual)
+ perceptual_distance_rgb_4_N_sse41((int64_t*)&total_error, pSelectors_to_use, block_colors, pSrc_pixels, n, trial_solution.m_error);
+ else
+ linear_distance_rgb_4_N_sse41((int64_t*)&total_error, pSelectors_to_use, block_colors, pSrc_pixels, n, trial_solution.m_error);
+ }
+ else
+ {
+ if (m_pParams->m_perceptual)
+ find_selectors_perceptual_rgb_4_N_sse41((int64_t*)&total_error, &m_temp_selectors[0], block_colors, pSrc_pixels, n, trial_solution.m_error);
+ else
+ find_selectors_linear_rgb_4_N_sse41((int64_t*)&total_error, &m_temp_selectors[0], block_colors, pSrc_pixels, n, trial_solution.m_error);
+ }
+#endif
+ }
+
+ if (total_error < trial_solution.m_error)
+ {
+ trial_solution.m_error = total_error;
+ trial_solution.m_coords.m_inten_table = inten_table;
+ trial_solution.m_selectors.swap(m_temp_selectors);
+ trial_solution.m_valid = true;
+ }
+ }
+ trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color;
+ trial_solution.m_coords.m_color4 = m_pParams->m_use_color4;
+
+#if BASISU_DEBUG_ETC_ENCODER_DEEPER
+ printf("Eval done: %u error: %I64u best error so far: %I64u\n", (trial_solution.m_error < pBest_solution->m_error), trial_solution.m_error, pBest_solution->m_error);
+#endif
+
+ bool success = false;
+ if (pBest_solution)
+ {
+ if (trial_solution.m_error < pBest_solution->m_error)
+ {
+ *pBest_solution = trial_solution;
+ success = true;
+ }
+ }
+
+ return success;
+ }
+
+ bool etc1_optimizer::evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution)
+ {
+ if (!check_for_redundant_solution(coords))
+ return false;
+
+#if BASISU_DEBUG_ETC_ENCODER_DEEPER
+ printf("Eval solution fast: %u %u %u\n", coords.m_unscaled_color.r, coords.m_unscaled_color.g, coords.m_unscaled_color.b);
+#endif
+
+ if (m_pParams->m_constrain_against_base_color5)
+ {
+ const int dr = (int)coords.m_unscaled_color.r - (int)m_pParams->m_base_color5.r;
+ const int dg = (int)coords.m_unscaled_color.g - (int)m_pParams->m_base_color5.g;
+ const int db = (int)coords.m_unscaled_color.b - (int)m_pParams->m_base_color5.b;
+
+ if ((minimum(dr, dg, db) < cETC1ColorDeltaMin) || (maximum(dr, dg, db) > cETC1ColorDeltaMax))
+ {
+ trial_solution.m_valid = false;
+
+#if BASISU_DEBUG_ETC_ENCODER_DEEPER
+ printf("Eval failed due to constraint from %u %u %u\n", m_pParams->m_base_color5.r, m_pParams->m_base_color5.g, m_pParams->m_base_color5.b);
+#endif
+ return false;
+ }
+ }
+
+ const color_rgba base_color(coords.get_scaled_color());
+
+ const uint32_t n = m_pParams->m_num_src_pixels;
+ assert(trial_solution.m_selectors.size() == n);
+
+ trial_solution.m_error = UINT64_MAX;
+
+ const bool perceptual = (m_pParams->m_quality == cETCQualityFast) ? false : m_pParams->m_perceptual;
+
+ for (int inten_table = cETC1IntenModifierValues - 1; inten_table >= 0; --inten_table)
+ {
+ const int* pInten_table = g_etc1_inten_tables[inten_table];
+
+ uint32_t block_inten[4];
+ color_rgba block_colors[4];
+ for (uint32_t s = 0; s < 4; s++)
+ {
+ const int yd = pInten_table[s];
+ color_rgba block_color(base_color.r + yd, base_color.g + yd, base_color.b + yd, 255);
+ block_colors[s] = block_color;
+ block_inten[s] = block_color.r + block_color.g + block_color.b;
+ }
+
+ // evaluate_solution_fast() enforces/assumes a total ordering of the input colors along the intensity (1,1,1) axis to more quickly classify the inputs to selectors.
+ // The inputs colors have been presorted along the projection onto this axis, and ETC1 block colors are always ordered along the intensity axis, so this classification is fast.
+ // 0 1 2 3
+ // 01 12 23
+ const uint32_t block_inten_midpoints[3] = { block_inten[0] + block_inten[1], block_inten[1] + block_inten[2], block_inten[2] + block_inten[3] };
+
+ uint64_t total_error = 0;
+ const color_rgba* pSrc_pixels = m_pParams->m_pSrc_pixels;
+
+ if (perceptual)
+ {
+ if ((m_pSorted_luma[n - 1] * 2) < block_inten_midpoints[0])
+ {
+ if (block_inten[0] > m_pSorted_luma[n - 1])
+ {
+ const uint32_t min_error = iabs((int)block_inten[0] - (int)m_pSorted_luma[n - 1]);
+ if (min_error >= trial_solution.m_error)
+ continue;
+ }
+
+ memset(&m_temp_selectors[0], 0, n);
+
+ for (uint32_t c = 0; c < n; c++)
+ total_error += color_distance(true, block_colors[0], pSrc_pixels[c], false);
+ }
+ else if ((m_pSorted_luma[0] * 2) >= block_inten_midpoints[2])
+ {
+ if (m_pSorted_luma[0] > block_inten[3])
+ {
+ const uint32_t min_error = iabs((int)m_pSorted_luma[0] - (int)block_inten[3]);
+ if (min_error >= trial_solution.m_error)
+ continue;
+ }
+
+ memset(&m_temp_selectors[0], 3, n);
+
+ for (uint32_t c = 0; c < n; c++)
+ total_error += color_distance(true, block_colors[3], pSrc_pixels[c], false);
+ }
+ else
+ {
+ if (!g_cpu_supports_sse41)
+ {
+ uint32_t cur_selector = 0, c;
+ for (c = 0; c < n; c++)
+ {
+ const uint32_t y = m_pSorted_luma[c];
+ while ((y * 2) >= block_inten_midpoints[cur_selector])
+ if (++cur_selector > 2)
+ goto done;
+ const uint32_t sorted_pixel_index = m_pSorted_luma_indices[c];
+ m_temp_selectors[sorted_pixel_index] = static_cast<uint8_t>(cur_selector);
+ total_error += color_distance(true, block_colors[cur_selector], pSrc_pixels[sorted_pixel_index], false);
+ }
+ done:
+ while (c < n)
+ {
+ const uint32_t sorted_pixel_index = m_pSorted_luma_indices[c];
+ m_temp_selectors[sorted_pixel_index] = 3;
+ total_error += color_distance(true, block_colors[3], pSrc_pixels[sorted_pixel_index], false);
+ ++c;
+ }
+ }
+ else
+ {
+#if BASISU_SUPPORT_SSE
+ uint32_t cur_selector = 0, c;
+
+ for (c = 0; c < n; c++)
+ {
+ const uint32_t y = m_pSorted_luma[c];
+ while ((y * 2) >= block_inten_midpoints[cur_selector])
+ {
+ if (++cur_selector > 2)
+ goto done3;
+ }
+ const uint32_t sorted_pixel_index = m_pSorted_luma_indices[c];
+ m_temp_selectors[sorted_pixel_index] = static_cast<uint8_t>(cur_selector);
+ }
+ done3:
+
+ while (c < n)
+ {
+ const uint32_t sorted_pixel_index = m_pSorted_luma_indices[c];
+ m_temp_selectors[sorted_pixel_index] = 3;
+ ++c;
+ }
+
+ int64_t block_error;
+ perceptual_distance_rgb_4_N_sse41(&block_error, &m_temp_selectors[0], block_colors, pSrc_pixels, n, INT64_MAX);
+ total_error += block_error;
+#endif
+ }
+ }
+ }
+ else
+ {
+ if ((m_pSorted_luma[n - 1] * 2) < block_inten_midpoints[0])
+ {
+ if (block_inten[0] > m_pSorted_luma[n - 1])
+ {
+ const uint32_t min_error = iabs((int)block_inten[0] - (int)m_pSorted_luma[n - 1]);
+ if (min_error >= trial_solution.m_error)
+ continue;
+ }
+
+ memset(&m_temp_selectors[0], 0, n);
+
+ for (uint32_t c = 0; c < n; c++)
+ total_error += color_distance(block_colors[0], pSrc_pixels[c], false);
+ }
+ else if ((m_pSorted_luma[0] * 2) >= block_inten_midpoints[2])
+ {
+ if (m_pSorted_luma[0] > block_inten[3])
+ {
+ const uint32_t min_error = iabs((int)m_pSorted_luma[0] - (int)block_inten[3]);
+ if (min_error >= trial_solution.m_error)
+ continue;
+ }
+
+ memset(&m_temp_selectors[0], 3, n);
+
+ for (uint32_t c = 0; c < n; c++)
+ total_error += color_distance(block_colors[3], pSrc_pixels[c], false);
+ }
+ else
+ {
+ uint32_t cur_selector = 0, c;
+ for (c = 0; c < n; c++)
+ {
+ const uint32_t y = m_pSorted_luma[c];
+ while ((y * 2) >= block_inten_midpoints[cur_selector])
+ if (++cur_selector > 2)
+ goto done2;
+ const uint32_t sorted_pixel_index = m_pSorted_luma_indices[c];
+ m_temp_selectors[sorted_pixel_index] = static_cast<uint8_t>(cur_selector);
+ total_error += color_distance(block_colors[cur_selector], pSrc_pixels[sorted_pixel_index], false);
+ }
+ done2:
+ while (c < n)
+ {
+ const uint32_t sorted_pixel_index = m_pSorted_luma_indices[c];
+ m_temp_selectors[sorted_pixel_index] = 3;
+ total_error += color_distance(block_colors[3], pSrc_pixels[sorted_pixel_index], false);
+ ++c;
+ }
+ }
+ }
+
+ if (total_error < trial_solution.m_error)
+ {
+ trial_solution.m_error = total_error;
+ trial_solution.m_coords.m_inten_table = inten_table;
+ trial_solution.m_selectors.swap(m_temp_selectors);
+ trial_solution.m_valid = true;
+ if (!total_error)
+ break;
+ }
+ }
+ trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color;
+ trial_solution.m_coords.m_color4 = m_pParams->m_use_color4;
+
+#if BASISU_DEBUG_ETC_ENCODER_DEEPER
+ printf("Eval done: %u error: %I64u best error so far: %I64u\n", (trial_solution.m_error < pBest_solution->m_error), trial_solution.m_error, pBest_solution->m_error);
+#endif
+
+ bool success = false;
+ if (pBest_solution)
+ {
+ if (trial_solution.m_error < pBest_solution->m_error)
+ {
+ *pBest_solution = trial_solution;
+ success = true;
+ }
+ }
+
+ return success;
+ }
+
+ uint64_t pack_eac_a8(pack_eac_a8_results& results, const uint8_t* pPixels, uint32_t num_pixels, uint32_t base_search_rad, uint32_t mul_search_rad, uint32_t table_mask)
+ {
+ results.m_selectors.resize(num_pixels);
+ results.m_selectors_temp.resize(num_pixels);
+
+ uint32_t min_alpha = 255, max_alpha = 0;
+ for (uint32_t i = 0; i < num_pixels; i++)
+ {
+ const uint32_t a = pPixels[i];
+ if (a < min_alpha) min_alpha = a;
+ if (a > max_alpha) max_alpha = a;
+ }
+
+ if (min_alpha == max_alpha)
+ {
+ results.m_base = min_alpha;
+ results.m_table = 13;
+ results.m_multiplier = 1;
+ for (uint32_t i = 0; i < num_pixels; i++)
+ results.m_selectors[i] = 4;
+ return 0;
+ }
+
+ const uint32_t alpha_range = max_alpha - min_alpha;
+
+ uint64_t best_err = UINT64_MAX;
+
+ for (uint32_t table = 0; table < 16; table++)
+ {
+ if ((table_mask & (1U << table)) == 0)
+ continue;
+
+ const float range = (float)(g_etc2_eac_tables[table][ETC2_EAC_MAX_VALUE_SELECTOR] - g_etc2_eac_tables[table][ETC2_EAC_MIN_VALUE_SELECTOR]);
+ const int center = (int)roundf(lerp((float)min_alpha, (float)max_alpha, (float)(0 - g_etc2_eac_tables[table][ETC2_EAC_MIN_VALUE_SELECTOR]) / range));
+
+ const int base_min = clamp255(center - base_search_rad);
+ const int base_max = clamp255(center + base_search_rad);
+
+ const int mul = (int)roundf(alpha_range / range);
+ const int mul_low = clamp<int>(mul - mul_search_rad, 1, 15);
+ const int mul_high = clamp<int>(mul + mul_search_rad, 1, 15);
+
+ for (int base = base_min; base <= base_max; base++)
+ {
+ for (int multiplier = mul_low; multiplier <= mul_high; multiplier++)
+ {
+ uint64_t total_err = 0;
+
+ for (uint32_t i = 0; i < num_pixels; i++)
+ {
+ const int a = pPixels[i];
+
+ uint32_t best_s_err = UINT32_MAX;
+ uint32_t best_s = 0;
+ for (uint32_t s = 0; s < 8; s++)
+ {
+ const int v = clamp255((int)multiplier * g_etc2_eac_tables[table][s] + (int)base);
+
+ uint32_t err = iabs(a - v);
+ if (err < best_s_err)
+ {
+ best_s_err = err;
+ best_s = s;
+ }
+ }
+
+ results.m_selectors_temp[i] = static_cast<uint8_t>(best_s);
+
+ total_err += best_s_err * best_s_err;
+ if (total_err >= best_err)
+ break;
+ }
+
+ if (total_err < best_err)
+ {
+ best_err = total_err;
+ results.m_base = base;
+ results.m_multiplier = multiplier;
+ results.m_table = table;
+ results.m_selectors.swap(results.m_selectors_temp);
+ if (!best_err)
+ return best_err;
+ }
+
+ } // table
+
+ } // multiplier
+
+ } // base
+
+ return best_err;
+ }
+
+ void pack_eac_a8(eac_a8_block* pBlock, const uint8_t* pPixels, uint32_t base_search_rad, uint32_t mul_search_rad, uint32_t table_mask)
+ {
+ pack_eac_a8_results results;
+ pack_eac_a8(results, pPixels, 16, base_search_rad, mul_search_rad, table_mask);
+
+ pBlock->m_base = results.m_base;
+ pBlock->m_multiplier = results.m_multiplier;
+ pBlock->m_table = results.m_table;
+ for (uint32_t y = 0; y < 4; y++)
+ for (uint32_t x = 0; x < 4; x++)
+ pBlock->set_selector(x, y, results.m_selectors[x + y * 4]);
+ }
+
+} // namespace basisu
diff --git a/thirdparty/basis_universal/basisu_etc.h b/thirdparty/basis_universal/encoder/basisu_etc.h
index a202d01f6e..1e3ece43b8 100644
--- a/thirdparty/basis_universal/basisu_etc.h
+++ b/thirdparty/basis_universal/encoder/basisu_etc.h
@@ -1,5 +1,5 @@
// basis_etc.h
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,9 +13,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
-#include "transcoder/basisu.h"
+#include "../transcoder/basisu.h"
#include "basisu_enc.h"
-#include <set>
namespace basisu
{
@@ -116,7 +115,7 @@ namespace basisu
{
assert((ofs + num) <= 64U);
assert(num && (num < 32U));
- return (read_be64(&m_uint64) >> ofs) & ((1UL << num) - 1UL);
+ return (uint32_t)(read_be64(&m_uint64) >> ofs) & ((1UL << num) - 1UL);
}
inline void set_general_bits(uint32_t ofs, uint32_t num, uint32_t bits)
@@ -266,6 +265,27 @@ namespace basisu
p[-2] |= (msb << byte_bit_ofs);
}
+ // Selector "etc1_val" ranges from 0-3 and is a direct (raw) ETC1 selector.
+ inline void set_raw_selector(uint32_t x, uint32_t y, uint32_t etc1_val)
+ {
+ assert((x | y | etc1_val) < 4);
+ const uint32_t bit_index = x * 4 + y;
+
+ uint8_t* p = &m_bytes[7 - (bit_index >> 3)];
+
+ const uint32_t byte_bit_ofs = bit_index & 7;
+ const uint32_t mask = 1 << byte_bit_ofs;
+
+ const uint32_t lsb = etc1_val & 1;
+ const uint32_t msb = etc1_val >> 1;
+
+ p[0] &= ~mask;
+ p[0] |= (lsb << byte_bit_ofs);
+
+ p[-2] &= ~mask;
+ p[-2] |= (msb << byte_bit_ofs);
+ }
+
inline uint32_t get_raw_selector_bits() const
{
return m_bytes[4] | (m_bytes[5] << 8) | (m_bytes[6] << 16) | (m_bytes[7] << 24);
@@ -622,6 +642,23 @@ namespace basisu
return true;
}
+ bool set_block_color5_clamp(const color_rgba &c0_unscaled, const color_rgba &c1_unscaled)
+ {
+ set_diff_bit(true);
+ set_base5_color(pack_color5(c0_unscaled, false));
+
+ int dr = c1_unscaled.r - c0_unscaled.r;
+ int dg = c1_unscaled.g - c0_unscaled.g;
+ int db = c1_unscaled.b - c0_unscaled.b;
+
+ dr = clamp<int>(dr, cETC1ColorDeltaMin, cETC1ColorDeltaMax);
+ dg = clamp<int>(dg, cETC1ColorDeltaMin, cETC1ColorDeltaMax);
+ db = clamp<int>(db, cETC1ColorDeltaMin, cETC1ColorDeltaMax);
+
+ set_delta3_color(pack_delta3(dr, dg, db));
+
+ return true;
+ }
color_rgba get_selector_color(uint32_t x, uint32_t y, uint32_t s) const
{
color_rgba block_colors[4];
@@ -720,7 +757,7 @@ namespace basisu
}
};
- typedef std::vector<etc_block> etc_block_vec;
+ typedef basisu::vector<etc_block> etc_block_vec;
// Returns false if the unpack fails (could be bogus data or ETC2)
bool unpack_etc1(const etc_block& block, color_rgba *pDst, bool preserve_alpha = false);
@@ -844,10 +881,10 @@ namespace basisu
bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
}
const int* pInten_table = g_etc1_inten_tables[m_inten_table];
- pBlock_colors[0].set((uint8_t)(br + pInten_table[0]), (uint8_t)(bg + pInten_table[0]), (uint8_t)(bb + pInten_table[0]), 255);
- pBlock_colors[1].set((uint8_t)(br + pInten_table[1]), (uint8_t)(bg + pInten_table[1]), (uint8_t)(bb + pInten_table[1]), 255);
- pBlock_colors[2].set((uint8_t)(br + pInten_table[2]), (uint8_t)(bg + pInten_table[2]), (uint8_t)(bb + pInten_table[2]), 255);
- pBlock_colors[3].set((uint8_t)(br + pInten_table[3]), (uint8_t)(bg + pInten_table[3]), (uint8_t)(bb + pInten_table[3]), 255);
+ pBlock_colors[0].set(br + pInten_table[0], bg + pInten_table[0], bb + pInten_table[0], 255);
+ pBlock_colors[1].set(br + pInten_table[1], bg + pInten_table[1], bb + pInten_table[1], 255);
+ pBlock_colors[2].set(br + pInten_table[2], bg + pInten_table[2], bb + pInten_table[2], 255);
+ pBlock_colors[3].set(br + pInten_table[3], bg + pInten_table[3], bb + pInten_table[3], 255);
}
color_rgba m_unscaled_color;
@@ -914,9 +951,6 @@ namespace basisu
m_refinement = true;
m_pForce_selectors = nullptr;
-
- m_pEval_solution_override = nullptr;
- m_pEval_solution_override_data = nullptr;
}
uint32_t m_num_src_pixels;
@@ -932,9 +966,6 @@ namespace basisu
bool m_refinement;
const uint8_t* m_pForce_selectors;
-
- evaluate_solution_override_func m_pEval_solution_override;
- void *m_pEval_solution_override_data;
};
struct results
@@ -970,7 +1001,7 @@ namespace basisu
}
etc1_solution_coordinates m_coords;
- std::vector<uint8_t> m_selectors;
+ basisu::vector<uint8_t> m_selectors;
uint64_t m_error;
bool m_valid;
@@ -1001,33 +1032,36 @@ namespace basisu
vec3F m_avg_color;
int m_br, m_bg, m_bb;
- std::vector<uint16_t> m_luma;
- std::vector<uint32_t> m_sorted_luma;
- std::vector<uint32_t> m_sorted_luma_indices;
+ int m_max_comp_spread;
+ basisu::vector<uint16_t> m_luma;
+ basisu::vector<uint32_t> m_sorted_luma;
+ basisu::vector<uint32_t> m_sorted_luma_indices;
const uint32_t* m_pSorted_luma_indices;
uint32_t* m_pSorted_luma;
- std::vector<uint8_t> m_selectors;
- std::vector<uint8_t> m_best_selectors;
+ basisu::vector<uint8_t> m_selectors;
+ basisu::vector<uint8_t> m_best_selectors;
potential_solution m_best_solution;
potential_solution m_trial_solution;
- std::vector<uint8_t> m_temp_selectors;
-
- std::set<uint32_t> m_solutions_tried;
+ basisu::vector<uint8_t> m_temp_selectors;
+ enum { cSolutionsTriedHashBits = 10, cTotalSolutionsTriedHashSize = 1 << cSolutionsTriedHashBits, cSolutionsTriedHashMask = cTotalSolutionsTriedHashSize - 1 };
+ uint8_t m_solutions_tried[cTotalSolutionsTriedHashSize / 8];
+
void get_nearby_inten_tables(uint32_t idx, int &first_inten_table, int &last_inten_table)
{
first_inten_table = maximum<int>(idx - 1, 0);
last_inten_table = minimum<int>(cETC1IntenModifierValues, idx + 1);
}
-
+
+ bool check_for_redundant_solution(const etc1_solution_coordinates& coords);
bool evaluate_solution_slow(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
bool evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
inline bool evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution)
{
- if (m_pParams->m_quality >= cETCQualitySlow)
+ if (m_pParams->m_quality >= cETCQualityMedium)
return evaluate_solution_slow(coords, trial_solution, pBest_solution);
else
return evaluate_solution_fast(coords, trial_solution, pBest_solution);
@@ -1042,5 +1076,77 @@ namespace basisu
{
etc1_optimizer m_optimizer;
};
+
+ void pack_etc1_solid_color_init();
+ uint64_t pack_etc1_block_solid_color(etc_block& block, const uint8_t* pColor);
+
+ // ETC EAC
+ extern const int8_t g_etc2_eac_tables[16][8];
+ extern const int8_t g_etc2_eac_tables8[16][8];
+
+ const uint32_t ETC2_EAC_MIN_VALUE_SELECTOR = 3, ETC2_EAC_MAX_VALUE_SELECTOR = 7;
+
+ struct eac_a8_block
+ {
+ uint16_t m_base : 8;
+ uint16_t m_table : 4;
+ uint16_t m_multiplier : 4;
+
+ uint8_t m_selectors[6];
+
+ inline uint32_t get_selector(uint32_t x, uint32_t y, uint64_t selector_bits) const
+ {
+ assert((x < 4) && (y < 4));
+ return static_cast<uint32_t>((selector_bits >> (45 - (y + x * 4) * 3)) & 7);
+ }
+
+ inline uint64_t get_selector_bits() const
+ {
+ uint64_t pixels = ((uint64_t)m_selectors[0] << 40) | ((uint64_t)m_selectors[1] << 32) | ((uint64_t)m_selectors[2] << 24) | ((uint64_t)m_selectors[3] << 16) | ((uint64_t)m_selectors[4] << 8) | m_selectors[5];
+ return pixels;
+ }
+
+ inline void set_selector_bits(uint64_t pixels)
+ {
+ m_selectors[0] = (uint8_t)(pixels >> 40);
+ m_selectors[1] = (uint8_t)(pixels >> 32);
+ m_selectors[2] = (uint8_t)(pixels >> 24);
+ m_selectors[3] = (uint8_t)(pixels >> 16);
+ m_selectors[4] = (uint8_t)(pixels >> 8);
+ m_selectors[5] = (uint8_t)(pixels);
+ }
+
+ void set_selector(uint32_t x, uint32_t y, uint32_t s)
+ {
+ assert((x < 4) && (y < 4) && (s < 8));
+
+ const uint32_t ofs = 45 - (y + x * 4) * 3;
+
+ uint64_t pixels = get_selector_bits();
+
+ pixels &= ~(7ULL << ofs);
+ pixels |= (static_cast<uint64_t>(s) << ofs);
+
+ set_selector_bits(pixels);
+ }
+ };
+
+ struct etc2_rgba_block
+ {
+ eac_a8_block m_alpha;
+ etc_block m_rgb;
+ };
+ struct pack_eac_a8_results
+ {
+ uint32_t m_base;
+ uint32_t m_table;
+ uint32_t m_multiplier;
+ uint8_vec m_selectors;
+ uint8_vec m_selectors_temp;
+ };
+
+ uint64_t pack_eac_a8(pack_eac_a8_results& results, const uint8_t* pPixels, uint32_t num_pixels, uint32_t base_search_rad, uint32_t mul_search_rad, uint32_t table_mask = UINT32_MAX);
+ void pack_eac_a8(eac_a8_block* pBlock, const uint8_t* pPixels, uint32_t base_search_rad, uint32_t mul_search_rad, uint32_t table_mask = UINT32_MAX);
+
} // namespace basisu
diff --git a/thirdparty/basis_universal/basisu_frontend.cpp b/thirdparty/basis_universal/encoder/basisu_frontend.cpp
index 6f7a9bf889..324fc8e447 100644
--- a/thirdparty/basis_universal/basisu_frontend.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_frontend.cpp
@@ -1,5 +1,5 @@
// basisu_frontend.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,11 +17,16 @@
// This code originally supported full ETC1 and ETC1S, so there's some legacy stuff to be cleaned up in here.
// Add endpoint tiling support (where we force adjacent blocks to use the same endpoints during quantization), for a ~10% or more increase in bitrate at same SSIM. The backend already supports this.
//
-#include "transcoder/basisu.h"
+#include "../transcoder/basisu.h"
#include "basisu_frontend.h"
#include <unordered_set>
#include <unordered_map>
+#if BASISU_SUPPORT_SSE
+#define CPPSPMD_NAME(a) a##_sse41
+#include "basisu_kernels_declares.h"
+#endif
+
#define BASISU_FRONTEND_VERIFY(c) do { if (!(c)) handle_verify_failure(__LINE__); } while(0)
namespace basisu
@@ -29,10 +34,11 @@ namespace basisu
const uint32_t cMaxCodebookCreationThreads = 8;
const uint32_t BASISU_MAX_ENDPOINT_REFINEMENT_STEPS = 3;
- const uint32_t BASISU_MAX_SELECTOR_REFINEMENT_STEPS = 3;
+ //const uint32_t BASISU_MAX_SELECTOR_REFINEMENT_STEPS = 3;
const uint32_t BASISU_ENDPOINT_PARENT_CODEBOOK_SIZE = 16;
- const uint32_t BASISU_SELECTOR_PARENT_CODEBOOK_SIZE = 16;
+ const uint32_t BASISU_SELECTOR_PARENT_CODEBOOK_SIZE_COMP_LEVEL_01 = 32;
+ const uint32_t BASISU_SELECTOR_PARENT_CODEBOOK_SIZE_COMP_LEVEL_DEFAULT = 16;
// TODO - How to handle internal verifies in the basisu lib
static inline void handle_verify_failure(int line)
@@ -57,14 +63,14 @@ namespace basisu
uint32_t tv = size / sizeof(vec6F_quantizer::training_vec_with_weight);
- std::vector<vec6F_quantizer::training_vec_with_weight> v(tv);
+ basisu::vector<vec6F_quantizer::training_vec_with_weight> v(tv);
fread(&v[0], 1, sizeof(v[0]) * tv, pFile);
for (uint32_t i = 0; i < tv; i++)
m_endpoint_clusterizer.add_training_vec(v[i].first, v[i].second);
m_endpoint_clusterizer.generate(16128);
- std::vector<uint_vec> codebook;
+ basisu::vector<uint_vec> codebook;
m_endpoint_clusterizer.retrieve(codebook);
printf("Generated %u entries\n", (uint32_t)codebook.size());
@@ -78,6 +84,7 @@ namespace basisu
{
if (!p.m_pGlobal_sel_codebook)
{
+ debug_printf("basisu_frontend::init: No global sel codebook!\n");
assert(0);
return false;
}
@@ -128,11 +135,19 @@ namespace basisu
case 2:
{
m_endpoint_refinement = true;
+ m_use_hierarchical_endpoint_codebooks = true;
+ m_use_hierarchical_selector_codebooks = true;
+
+ break;
+ }
+ case 3:
+ {
+ m_endpoint_refinement = true;
m_use_hierarchical_endpoint_codebooks = false;
m_use_hierarchical_selector_codebooks = false;
break;
}
- case 3:
+ case 4:
{
m_endpoint_refinement = true;
m_use_hierarchical_endpoint_codebooks = true;
@@ -141,7 +156,7 @@ namespace basisu
m_num_selector_codebook_iterations = BASISU_MAX_ENDPOINT_REFINEMENT_STEPS;
break;
}
- case 4:
+ case 5:
{
m_endpoint_refinement = true;
m_use_hierarchical_endpoint_codebooks = false;
@@ -150,7 +165,8 @@ namespace basisu
m_num_selector_codebook_iterations = BASISU_MAX_ENDPOINT_REFINEMENT_STEPS;
break;
}
- case 5:
+ case 6:
+ default:
{
m_endpoint_refinement = true;
m_use_hierarchical_endpoint_codebooks = false;
@@ -180,106 +196,113 @@ namespace basisu
init_etc1_images();
- init_endpoint_training_vectors();
-
- generate_endpoint_clusters();
-
- for (uint32_t refine_endpoint_step = 0; refine_endpoint_step < m_num_endpoint_codebook_iterations; refine_endpoint_step++)
+ if (m_params.m_pGlobal_codebooks)
{
- BASISU_FRONTEND_VERIFY(check_etc1s_constraints());
-
- if (refine_endpoint_step)
- {
- introduce_new_endpoint_clusters();
- }
-
- generate_endpoint_codebook(refine_endpoint_step);
-
- if ((m_params.m_debug_images) && (m_params.m_dump_endpoint_clusterization))
- {
- char buf[256];
- snprintf(buf, sizeof(buf), "endpoint_cluster_vis_pre_%u.png", refine_endpoint_step);
- dump_endpoint_clusterization_visualization(buf, false);
- }
-
- bool early_out = false;
+ init_global_codebooks();
+ }
+ else
+ {
+ init_endpoint_training_vectors();
- if (m_endpoint_refinement)
+ generate_endpoint_clusters();
+
+ for (uint32_t refine_endpoint_step = 0; refine_endpoint_step < m_num_endpoint_codebook_iterations; refine_endpoint_step++)
{
- //dump_endpoint_clusterization_visualization("endpoint_clusters_before_refinement.png");
-
- if (!refine_endpoint_clusterization())
- early_out = true;
+ BASISU_FRONTEND_VERIFY(check_etc1s_constraints());
- if ((m_params.m_tex_type == basist::cBASISTexTypeVideoFrames) && (!refine_endpoint_step) && (m_num_endpoint_codebook_iterations == 1))
+ if (refine_endpoint_step)
{
- eliminate_redundant_or_empty_endpoint_clusters();
- generate_endpoint_codebook(refine_endpoint_step);
+ introduce_new_endpoint_clusters();
}
+ generate_endpoint_codebook(refine_endpoint_step);
+
if ((m_params.m_debug_images) && (m_params.m_dump_endpoint_clusterization))
{
char buf[256];
- snprintf(buf, sizeof(buf), "endpoint_cluster_vis_post_%u.png", refine_endpoint_step);
-
+ snprintf(buf, sizeof(buf), "endpoint_cluster_vis_pre_%u.png", refine_endpoint_step);
dump_endpoint_clusterization_visualization(buf, false);
- snprintf(buf, sizeof(buf), "endpoint_cluster_colors_vis_post_%u.png", refine_endpoint_step);
+ }
+
+ bool early_out = false;
- dump_endpoint_clusterization_visualization(buf, true);
+ if (m_endpoint_refinement)
+ {
+ //dump_endpoint_clusterization_visualization("endpoint_clusters_before_refinement.png");
+
+ if (!refine_endpoint_clusterization())
+ early_out = true;
+
+ if ((m_params.m_tex_type == basist::cBASISTexTypeVideoFrames) && (!refine_endpoint_step) && (m_num_endpoint_codebook_iterations == 1))
+ {
+ eliminate_redundant_or_empty_endpoint_clusters();
+ generate_endpoint_codebook(refine_endpoint_step);
+ }
+
+ if ((m_params.m_debug_images) && (m_params.m_dump_endpoint_clusterization))
+ {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "endpoint_cluster_vis_post_%u.png", refine_endpoint_step);
+
+ dump_endpoint_clusterization_visualization(buf, false);
+ snprintf(buf, sizeof(buf), "endpoint_cluster_colors_vis_post_%u.png", refine_endpoint_step);
+
+ dump_endpoint_clusterization_visualization(buf, true);
+ }
}
- }
- eliminate_redundant_or_empty_endpoint_clusters();
+ eliminate_redundant_or_empty_endpoint_clusters();
- if (m_params.m_debug_stats)
- debug_printf("Total endpoint clusters: %u\n", (uint32_t)m_endpoint_clusters.size());
+ if (m_params.m_debug_stats)
+ debug_printf("Total endpoint clusters: %u\n", (uint32_t)m_endpoint_clusters.size());
- if (early_out)
- break;
- }
+ if (early_out)
+ break;
+ }
- BASISU_FRONTEND_VERIFY(check_etc1s_constraints());
+ BASISU_FRONTEND_VERIFY(check_etc1s_constraints());
- generate_block_endpoint_clusters();
+ generate_block_endpoint_clusters();
- create_initial_packed_texture();
+ create_initial_packed_texture();
- generate_selector_clusters();
+ generate_selector_clusters();
- if (m_use_hierarchical_selector_codebooks)
- compute_selector_clusters_within_each_parent_cluster();
+ if (m_use_hierarchical_selector_codebooks)
+ compute_selector_clusters_within_each_parent_cluster();
- if (m_params.m_compression_level == 0)
- {
- create_optimized_selector_codebook(0);
+ if (m_params.m_compression_level == 0)
+ {
+ create_optimized_selector_codebook(0);
- find_optimal_selector_clusters_for_each_block();
+ find_optimal_selector_clusters_for_each_block();
- introduce_special_selector_clusters();
- }
- else
- {
- const uint32_t num_refine_selector_steps = m_params.m_pGlobal_sel_codebook ? 1 : m_num_selector_codebook_iterations;
- for (uint32_t refine_selector_steps = 0; refine_selector_steps < num_refine_selector_steps; refine_selector_steps++)
+ introduce_special_selector_clusters();
+ }
+ else
{
- create_optimized_selector_codebook(refine_selector_steps);
+ const uint32_t num_refine_selector_steps = m_params.m_pGlobal_sel_codebook ? 1 : m_num_selector_codebook_iterations;
+ for (uint32_t refine_selector_steps = 0; refine_selector_steps < num_refine_selector_steps; refine_selector_steps++)
+ {
+ create_optimized_selector_codebook(refine_selector_steps);
- find_optimal_selector_clusters_for_each_block();
+ find_optimal_selector_clusters_for_each_block();
- introduce_special_selector_clusters();
+ introduce_special_selector_clusters();
- if ((m_params.m_compression_level >= 3) || (m_params.m_tex_type == basist::cBASISTexTypeVideoFrames))
- {
- if (!refine_block_endpoints_given_selectors())
- break;
+ if ((m_params.m_compression_level >= 4) || (m_params.m_tex_type == basist::cBASISTexTypeVideoFrames))
+ {
+ if (!refine_block_endpoints_given_selectors())
+ break;
+ }
}
}
- }
-
- optimize_selector_codebook();
+
+ optimize_selector_codebook();
- if (m_params.m_debug_stats)
- debug_printf("Total selector clusters: %u\n", (uint32_t)m_selector_cluster_indices.size());
+ if (m_params.m_debug_stats)
+ debug_printf("Total selector clusters: %u\n", (uint32_t)m_selector_cluster_block_indices.size());
+ }
finalize();
@@ -294,6 +317,259 @@ namespace basisu
return true;
}
+ bool basisu_frontend::init_global_codebooks()
+ {
+ const basist::basisu_lowlevel_etc1s_transcoder* pTranscoder = m_params.m_pGlobal_codebooks;
+
+ const basist::basisu_lowlevel_etc1s_transcoder::endpoint_vec& endpoints = pTranscoder->get_endpoints();
+ const basist::basisu_lowlevel_etc1s_transcoder::selector_vec& selectors = pTranscoder->get_selectors();
+
+ m_endpoint_cluster_etc_params.resize(endpoints.size());
+ for (uint32_t i = 0; i < endpoints.size(); i++)
+ {
+ m_endpoint_cluster_etc_params[i].m_inten_table[0] = endpoints[i].m_inten5;
+ m_endpoint_cluster_etc_params[i].m_inten_table[1] = endpoints[i].m_inten5;
+
+ m_endpoint_cluster_etc_params[i].m_color_unscaled[0].set(endpoints[i].m_color5.r, endpoints[i].m_color5.g, endpoints[i].m_color5.b, 255);
+ m_endpoint_cluster_etc_params[i].m_color_used[0] = true;
+ m_endpoint_cluster_etc_params[i].m_valid = true;
+ }
+
+ m_optimized_cluster_selectors.resize(selectors.size());
+ for (uint32_t i = 0; i < m_optimized_cluster_selectors.size(); i++)
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ for (uint32_t x = 0; x < 4; x++)
+ m_optimized_cluster_selectors[i].set_selector(x, y, selectors[i].get_selector(x, y));
+ }
+
+ m_block_endpoint_clusters_indices.resize(m_total_blocks);
+
+ m_orig_encoded_blocks.resize(m_total_blocks);
+
+ m_block_selector_cluster_index.resize(m_total_blocks);
+
+#if 0
+ for (uint32_t block_index_iter = 0; block_index_iter < m_total_blocks; block_index_iter += N)
+ {
+ const uint32_t first_index = block_index_iter;
+ const uint32_t last_index = minimum<uint32_t>(m_total_blocks, first_index + N);
+
+#ifndef __EMSCRIPTEN__
+ m_params.m_pJob_pool->add_job([this, first_index, last_index] {
+#endif
+
+ for (uint32_t block_index = first_index; block_index < last_index; block_index++)
+ {
+ const etc_block& blk = m_etc1_blocks_etc1s[block_index];
+
+ const uint32_t block_endpoint_index = m_block_endpoint_clusters_indices[block_index][0];
+
+ etc_block trial_blk;
+ trial_blk.set_block_color5_etc1s(blk.m_color_unscaled[0]);
+ trial_blk.set_flip_bit(true);
+
+ uint64_t best_err = UINT64_MAX;
+ uint32_t best_index = 0;
+
+ for (uint32_t i = 0; i < m_optimized_cluster_selectors.size(); i++)
+ {
+ trial_blk.set_raw_selector_bits(m_optimized_cluster_selectors[i].get_raw_selector_bits());
+
+ const uint64_t cur_err = trial_blk.evaluate_etc1_error(get_source_pixel_block(block_index).get_ptr(), m_params.m_perceptual);
+ if (cur_err < best_err)
+ {
+ best_err = cur_err;
+ best_index = i;
+ if (!cur_err)
+ break;
+ }
+
+ } // block_index
+
+ m_block_selector_cluster_index[block_index] = best_index;
+ }
+
+#ifndef __EMSCRIPTEN__
+ });
+#endif
+
+ }
+
+#ifndef __EMSCRIPTEN__
+ m_params.m_pJob_pool->wait_for_all();
+#endif
+
+ m_encoded_blocks.resize(m_total_blocks);
+ for (uint32_t block_index = 0; block_index < m_total_blocks; block_index++)
+ {
+ const uint32_t endpoint_index = m_block_endpoint_clusters_indices[block_index][0];
+ const uint32_t selector_index = m_block_selector_cluster_index[block_index];
+
+ etc_block& blk = m_encoded_blocks[block_index];
+
+ blk.set_block_color5_etc1s(m_endpoint_cluster_etc_params[endpoint_index].m_color_unscaled[0]);
+ blk.set_inten_tables_etc1s(m_endpoint_cluster_etc_params[endpoint_index].m_inten_table[0]);
+ blk.set_flip_bit(true);
+ blk.set_raw_selector_bits(m_optimized_cluster_selectors[selector_index].get_raw_selector_bits());
+ }
+#endif
+
+ // HACK HACK
+ const uint32_t NUM_PASSES = 3;
+ for (uint32_t pass = 0; pass < NUM_PASSES; pass++)
+ {
+ debug_printf("init_global_codebooks: pass %u\n", pass);
+
+ const uint32_t N = 128;
+ for (uint32_t block_index_iter = 0; block_index_iter < m_total_blocks; block_index_iter += N)
+ {
+ const uint32_t first_index = block_index_iter;
+ const uint32_t last_index = minimum<uint32_t>(m_total_blocks, first_index + N);
+
+#ifndef __EMSCRIPTEN__
+ m_params.m_pJob_pool->add_job([this, first_index, last_index, pass] {
+#endif
+
+ for (uint32_t block_index = first_index; block_index < last_index; block_index++)
+ {
+ const etc_block& blk = pass ? m_encoded_blocks[block_index] : m_etc1_blocks_etc1s[block_index];
+ const uint32_t blk_raw_selector_bits = blk.get_raw_selector_bits();
+
+ etc_block trial_blk(blk);
+ trial_blk.set_raw_selector_bits(blk_raw_selector_bits);
+ trial_blk.set_flip_bit(true);
+
+ uint64_t best_err = UINT64_MAX;
+ uint32_t best_index = 0;
+ etc_block best_block(trial_blk);
+
+ for (uint32_t i = 0; i < m_endpoint_cluster_etc_params.size(); i++)
+ {
+ if (m_endpoint_cluster_etc_params[i].m_inten_table[0] > blk.get_inten_table(0))
+ continue;
+
+ trial_blk.set_block_color5_etc1s(m_endpoint_cluster_etc_params[i].m_color_unscaled[0]);
+ trial_blk.set_inten_tables_etc1s(m_endpoint_cluster_etc_params[i].m_inten_table[0]);
+
+ const color_rgba* pSource_pixels = get_source_pixel_block(block_index).get_ptr();
+ uint64_t cur_err;
+ if (!pass)
+ cur_err = trial_blk.determine_selectors(pSource_pixels, m_params.m_perceptual);
+ else
+ cur_err = trial_blk.evaluate_etc1_error(pSource_pixels, m_params.m_perceptual);
+
+ if (cur_err < best_err)
+ {
+ best_err = cur_err;
+ best_index = i;
+ best_block = trial_blk;
+
+ if (!cur_err)
+ break;
+ }
+ }
+
+ m_block_endpoint_clusters_indices[block_index][0] = best_index;
+ m_block_endpoint_clusters_indices[block_index][1] = best_index;
+
+ m_orig_encoded_blocks[block_index] = best_block;
+
+ } // block_index
+
+#ifndef __EMSCRIPTEN__
+ });
+#endif
+
+ }
+
+#ifndef __EMSCRIPTEN__
+ m_params.m_pJob_pool->wait_for_all();
+#endif
+
+ m_endpoint_clusters.resize(0);
+ m_endpoint_clusters.resize(endpoints.size());
+ for (uint32_t block_index = 0; block_index < m_total_blocks; block_index++)
+ {
+ const uint32_t endpoint_cluster_index = m_block_endpoint_clusters_indices[block_index][0];
+ m_endpoint_clusters[endpoint_cluster_index].push_back(block_index * 2);
+ m_endpoint_clusters[endpoint_cluster_index].push_back(block_index * 2 + 1);
+ }
+
+ m_block_selector_cluster_index.resize(m_total_blocks);
+
+ for (uint32_t block_index_iter = 0; block_index_iter < m_total_blocks; block_index_iter += N)
+ {
+ const uint32_t first_index = block_index_iter;
+ const uint32_t last_index = minimum<uint32_t>(m_total_blocks, first_index + N);
+
+#ifndef __EMSCRIPTEN__
+ m_params.m_pJob_pool->add_job([this, first_index, last_index] {
+#endif
+
+ for (uint32_t block_index = first_index; block_index < last_index; block_index++)
+ {
+ const uint32_t block_endpoint_index = m_block_endpoint_clusters_indices[block_index][0];
+
+ etc_block trial_blk;
+ trial_blk.set_block_color5_etc1s(m_endpoint_cluster_etc_params[block_endpoint_index].m_color_unscaled[0]);
+ trial_blk.set_inten_tables_etc1s(m_endpoint_cluster_etc_params[block_endpoint_index].m_inten_table[0]);
+ trial_blk.set_flip_bit(true);
+
+ uint64_t best_err = UINT64_MAX;
+ uint32_t best_index = 0;
+
+ for (uint32_t i = 0; i < m_optimized_cluster_selectors.size(); i++)
+ {
+ trial_blk.set_raw_selector_bits(m_optimized_cluster_selectors[i].get_raw_selector_bits());
+
+ const uint64_t cur_err = trial_blk.evaluate_etc1_error(get_source_pixel_block(block_index).get_ptr(), m_params.m_perceptual);
+ if (cur_err < best_err)
+ {
+ best_err = cur_err;
+ best_index = i;
+ if (!cur_err)
+ break;
+ }
+
+ } // block_index
+
+ m_block_selector_cluster_index[block_index] = best_index;
+ }
+
+#ifndef __EMSCRIPTEN__
+ });
+#endif
+
+ }
+
+#ifndef __EMSCRIPTEN__
+ m_params.m_pJob_pool->wait_for_all();
+#endif
+
+ m_encoded_blocks.resize(m_total_blocks);
+ for (uint32_t block_index = 0; block_index < m_total_blocks; block_index++)
+ {
+ const uint32_t endpoint_index = m_block_endpoint_clusters_indices[block_index][0];
+ const uint32_t selector_index = m_block_selector_cluster_index[block_index];
+
+ etc_block& blk = m_encoded_blocks[block_index];
+
+ blk.set_block_color5_etc1s(m_endpoint_cluster_etc_params[endpoint_index].m_color_unscaled[0]);
+ blk.set_inten_tables_etc1s(m_endpoint_cluster_etc_params[endpoint_index].m_inten_table[0]);
+ blk.set_flip_bit(true);
+ blk.set_raw_selector_bits(m_optimized_cluster_selectors[selector_index].get_raw_selector_bits());
+ }
+
+ } // pass
+
+ m_selector_cluster_block_indices.resize(selectors.size());
+ for (uint32_t block_index = 0; block_index < m_etc1_blocks_etc1s.size(); block_index++)
+ m_selector_cluster_block_indices[m_block_selector_cluster_index[block_index]].push_back(block_index);
+
+ return true;
+ }
+
void basisu_frontend::introduce_special_selector_clusters()
{
debug_printf("introduce_special_selector_clusters\n");
@@ -302,7 +578,7 @@ namespace basisu
return;
uint32_t total_blocks_relocated = 0;
- const uint32_t initial_selector_clusters = (uint32_t)m_selector_cluster_indices.size();
+ const uint32_t initial_selector_clusters = (uint32_t)m_selector_cluster_block_indices.size();
bool_vec block_relocated_flags(m_total_blocks);
@@ -328,7 +604,7 @@ namespace basisu
m_optimized_cluster_selectors.push_back(blk);
- vector_ensure_element_is_valid(m_selector_cluster_indices, new_selector_cluster_index);
+ vector_ensure_element_is_valid(m_selector_cluster_block_indices, new_selector_cluster_index);
for (uint32_t block_index = 0; block_index < m_total_blocks; block_index++)
{
@@ -357,14 +633,14 @@ namespace basisu
// Change the block to use the new cluster
m_block_selector_cluster_index[block_index] = new_selector_cluster_index;
- m_selector_cluster_indices[new_selector_cluster_index].push_back(block_index);
+ m_selector_cluster_block_indices[new_selector_cluster_index].push_back(block_index);
block_relocated_flags[block_index] = true;
#if 0
- int j = vector_find(m_selector_cluster_indices[old_selector_cluster_index], block_index);
+ int j = vector_find(m_selector_cluster_block_indices[old_selector_cluster_index], block_index);
if (j >= 0)
- m_selector_cluster_indices[old_selector_cluster_index].erase(m_selector_cluster_indices[old_selector_cluster_index].begin() + j);
+ m_selector_cluster_block_indices[old_selector_cluster_index].erase(m_selector_cluster_block_indices[old_selector_cluster_index].begin() + j);
#endif
total_blocks_relocated++;
@@ -381,7 +657,7 @@ namespace basisu
for (int selector_cluster_index = 0; selector_cluster_index < (int)initial_selector_clusters; selector_cluster_index++)
{
- uint_vec& block_indices = m_selector_cluster_indices[selector_cluster_index];
+ uint_vec& block_indices = m_selector_cluster_block_indices[selector_cluster_index];
uint32_t dst_ofs = 0;
@@ -399,6 +675,7 @@ namespace basisu
debug_printf("Total blocks relocated to new flat selector clusters: %u\n", total_blocks_relocated);
}
+ // This method will change the number and ordering of the selector codebook clusters.
void basisu_frontend::optimize_selector_codebook()
{
debug_printf("optimize_selector_codebook\n");
@@ -436,15 +713,17 @@ namespace basisu
new_to_old.push_back(i);
}
+ debug_printf("Original selector clusters: %u, new cluster selectors: %u\n", orig_total_selector_clusters, total_new_entries);
+
for (uint32_t i = 0; i < m_block_selector_cluster_index.size(); i++)
{
BASISU_FRONTEND_VERIFY((old_to_new[m_block_selector_cluster_index[i]] >= 0) && (old_to_new[m_block_selector_cluster_index[i]] < (int)total_new_entries));
m_block_selector_cluster_index[i] = old_to_new[m_block_selector_cluster_index[i]];
}
- std::vector<etc_block> new_optimized_cluster_selectors(m_optimized_cluster_selectors.size() ? total_new_entries : 0);
+ basisu::vector<etc_block> new_optimized_cluster_selectors(m_optimized_cluster_selectors.size() ? total_new_entries : 0);
basist::etc1_global_selector_codebook_entry_id_vec new_optimized_cluster_selector_global_cb_ids(m_optimized_cluster_selector_global_cb_ids.size() ? total_new_entries : 0);
- std::vector<uint_vec> new_selector_cluster_indices(m_selector_cluster_indices.size() ? total_new_entries : 0);
+ basisu::vector<uint_vec> new_selector_cluster_indices(m_selector_cluster_block_indices.size() ? total_new_entries : 0);
bool_vec new_selector_cluster_uses_global_cb(m_selector_cluster_uses_global_cb.size() ? total_new_entries : 0);
for (uint32_t i = 0; i < total_new_entries; i++)
@@ -455,24 +734,40 @@ namespace basisu
if (m_optimized_cluster_selector_global_cb_ids.size())
new_optimized_cluster_selector_global_cb_ids[i] = m_optimized_cluster_selector_global_cb_ids[new_to_old[i]];
- if (m_selector_cluster_indices.size())
- new_selector_cluster_indices[i] = m_selector_cluster_indices[new_to_old[i]];
+ //if (m_selector_cluster_block_indices.size())
+ // new_selector_cluster_indices[i] = m_selector_cluster_block_indices[new_to_old[i]];
if (m_selector_cluster_uses_global_cb.size())
new_selector_cluster_uses_global_cb[i] = m_selector_cluster_uses_global_cb[new_to_old[i]];
}
+ for (uint32_t i = 0; i < m_block_selector_cluster_index.size(); i++)
+ {
+ new_selector_cluster_indices[m_block_selector_cluster_index[i]].push_back(i);
+ }
+
m_optimized_cluster_selectors.swap(new_optimized_cluster_selectors);
m_optimized_cluster_selector_global_cb_ids.swap(new_optimized_cluster_selector_global_cb_ids);
- m_selector_cluster_indices.swap(new_selector_cluster_indices);
+ m_selector_cluster_block_indices.swap(new_selector_cluster_indices);
m_selector_cluster_uses_global_cb.swap(new_selector_cluster_uses_global_cb);
-
+
+ // This isn't strictly necessary - doing it for completeness/future sanity.
+ if (m_selector_clusters_within_each_parent_cluster.size())
+ {
+ for (uint32_t i = 0; i < m_selector_clusters_within_each_parent_cluster.size(); i++)
+ for (uint32_t j = 0; j < m_selector_clusters_within_each_parent_cluster[i].size(); j++)
+ m_selector_clusters_within_each_parent_cluster[i][j] = old_to_new[m_selector_clusters_within_each_parent_cluster[i][j]];
+ }
+
debug_printf("optimize_selector_codebook: Before: %u After: %u\n", orig_total_selector_clusters, total_new_entries);
}
void basisu_frontend::init_etc1_images()
{
debug_printf("basisu_frontend::init_etc1_images\n");
+
+ interval_timer tm;
+ tm.start();
m_etc1_blocks_etc1s.resize(m_total_blocks);
@@ -481,8 +776,10 @@ namespace basisu
{
const uint32_t first_index = block_index_iter;
const uint32_t last_index = minimum<uint32_t>(m_total_blocks, first_index + N);
-
+
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->add_job( [this, first_index, last_index] {
+#endif
for (uint32_t block_index = first_index; block_index < last_index; block_index++)
{
@@ -494,6 +791,8 @@ namespace basisu
if (m_params.m_compression_level == 0)
optimizer_params.m_quality = cETCQualityFast;
+ else if (m_params.m_compression_level == 1)
+ optimizer_params.m_quality = cETCQualityMedium;
else if (m_params.m_compression_level == BASISU_MAX_COMPRESSION_LEVEL)
optimizer_params.m_quality = cETCQualityUber;
@@ -506,8 +805,9 @@ namespace basisu
optimizer_results.m_n = 16;
optimizer.init(optimizer_params, optimizer_results);
- optimizer.compute();
-
+ if (!optimizer.compute())
+ BASISU_FRONTEND_VERIFY(false);
+
etc_block &blk = m_etc1_blocks_etc1s[block_index];
memset(&blk, 0, sizeof(blk));
@@ -520,10 +820,17 @@ namespace basisu
blk.set_selector(x, y, selectors[x + y * 4]);
}
+#ifndef __EMSCRIPTEN__
} );
+#endif
+
}
-
+
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
+#endif
+
+ debug_printf("Elapsed time: %3.3f secs\n", tm.get_elapsed_secs());
}
void basisu_frontend::init_endpoint_training_vectors()
@@ -540,7 +847,9 @@ namespace basisu
const uint32_t first_index = block_index_iter;
const uint32_t last_index = minimum<uint32_t>(m_total_blocks, first_index + N);
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->add_job( [this, first_index, last_index, &training_vecs] {
+#endif
for (uint32_t block_index = first_index; block_index < last_index; block_index++)
{
@@ -562,11 +871,15 @@ namespace basisu
} // block_index;
+#ifndef __EMSCRIPTEN__
} );
+#endif
} // block_index_iter
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
+#endif
}
void basisu_frontend::generate_endpoint_clusters()
@@ -649,7 +962,7 @@ namespace basisu
for (int cluster_index = 0; cluster_index < static_cast<int>(m_endpoint_clusters.size()); cluster_index++)
{
- const std::vector<uint32_t>& cluster_indices = m_endpoint_clusters[cluster_index];
+ const basisu::vector<uint32_t>& cluster_indices = m_endpoint_clusters[cluster_index];
for (uint32_t cluster_indices_iter = 0; cluster_indices_iter < cluster_indices.size(); cluster_indices_iter++)
{
@@ -707,17 +1020,19 @@ namespace basisu
const uint32_t first_index = cluster_index_iter;
const uint32_t last_index = minimum<uint32_t>((uint32_t)m_endpoint_clusters.size(), cluster_index_iter + N);
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->add_job( [this, first_index, last_index] {
+#endif
for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++)
{
- const std::vector<uint32_t>& cluster_indices = m_endpoint_clusters[cluster_index];
+ const basisu::vector<uint32_t>& cluster_indices = m_endpoint_clusters[cluster_index];
assert(cluster_indices.size());
for (uint32_t cluster_indices_iter = 0; cluster_indices_iter < cluster_indices.size(); cluster_indices_iter++)
{
- std::vector<color_rgba> cluster_pixels(8);
+ basisu::vector<color_rgba> cluster_pixels(8);
const uint32_t block_index = cluster_indices[cluster_indices_iter] >> 1;
const uint32_t subblock_index = cluster_indices[cluster_indices_iter] & 1;
@@ -775,10 +1090,15 @@ namespace basisu
}
} // cluster_index
+#ifndef __EMSCRIPTEN__
} );
+#endif
+
} // cluster_index_iter
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
+#endif
vector_sort(m_subblock_endpoint_quant_err_vec);
}
@@ -837,7 +1157,7 @@ namespace basisu
continue;
#endif
- const uint32_t new_endpoint_cluster_index = (uint32_t)m_endpoint_clusters.size();
+ //const uint32_t new_endpoint_cluster_index = (uint32_t)m_endpoint_clusters.size();
enlarge_vector(m_endpoint_clusters, 1)->push_back(training_vector_index);
enlarge_vector(m_endpoint_cluster_etc_params, 1);
@@ -893,18 +1213,20 @@ namespace basisu
{
const uint32_t first_index = cluster_index_iter;
const uint32_t last_index = minimum<uint32_t>((uint32_t)m_endpoint_clusters.size(), cluster_index_iter + N);
-
+
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->add_job( [this, first_index, last_index, step ] {
+#endif
for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++)
{
- const std::vector<uint32_t>& cluster_indices = m_endpoint_clusters[cluster_index];
+ const basisu::vector<uint32_t>& cluster_indices = m_endpoint_clusters[cluster_index];
BASISU_FRONTEND_VERIFY(cluster_indices.size());
const uint32_t total_pixels = (uint32_t)cluster_indices.size() * 8;
- std::vector<color_rgba> cluster_pixels(total_pixels);
+ basisu::vector<color_rgba> cluster_pixels(total_pixels);
for (uint32_t cluster_indices_iter = 0; cluster_indices_iter < cluster_indices.size(); cluster_indices_iter++)
{
@@ -935,20 +1257,21 @@ namespace basisu
cluster_optimizer_params.m_use_color4 = false;
cluster_optimizer_params.m_perceptual = m_params.m_perceptual;
- if (m_params.m_compression_level == 0)
+ if (m_params.m_compression_level <= 1)
cluster_optimizer_params.m_quality = cETCQualityMedium;
else if (m_params.m_compression_level == BASISU_MAX_COMPRESSION_LEVEL)
cluster_optimizer_params.m_quality = cETCQualityUber;
etc1_optimizer::results cluster_optimizer_results;
- std::vector<uint8_t> cluster_selectors(total_pixels);
+ basisu::vector<uint8_t> cluster_selectors(total_pixels);
cluster_optimizer_results.m_n = total_pixels;
cluster_optimizer_results.m_pSelectors = &cluster_selectors[0];
optimizer.init(cluster_optimizer_params, cluster_optimizer_results);
- optimizer.compute();
+ if (!optimizer.compute())
+ BASISU_FRONTEND_VERIFY(false);
new_subblock_params.m_color_unscaled[0] = cluster_optimizer_results.m_block_color_unscaled;
new_subblock_params.m_inten_table[0] = cluster_optimizer_results.m_block_inten_table;
@@ -1012,20 +1335,24 @@ namespace basisu
} // cluster_index
+#ifndef __EMSCRIPTEN__
} );
+#endif
} // cluster_index_iter
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
+#endif
}
bool basisu_frontend::check_etc1s_constraints() const
{
- std::vector<vec2U> block_clusters(m_total_blocks);
+ basisu::vector<vec2U> block_clusters(m_total_blocks);
for (int cluster_index = 0; cluster_index < static_cast<int>(m_endpoint_clusters.size()); cluster_index++)
{
- const std::vector<uint32_t>& cluster_indices = m_endpoint_clusters[cluster_index];
+ const basisu::vector<uint32_t>& cluster_indices = m_endpoint_clusters[cluster_index];
for (uint32_t cluster_indices_iter = 0; cluster_indices_iter < cluster_indices.size(); cluster_indices_iter++)
{
@@ -1053,11 +1380,11 @@ namespace basisu
if (m_use_hierarchical_endpoint_codebooks)
compute_endpoint_clusters_within_each_parent_cluster();
- std::vector<vec2U> block_clusters(m_total_blocks);
+ basisu::vector<vec2U> block_clusters(m_total_blocks);
for (int cluster_index = 0; cluster_index < static_cast<int>(m_endpoint_clusters.size()); cluster_index++)
{
- const std::vector<uint32_t>& cluster_indices = m_endpoint_clusters[cluster_index];
+ const basisu::vector<uint32_t>& cluster_indices = m_endpoint_clusters[cluster_index];
for (uint32_t cluster_indices_iter = 0; cluster_indices_iter < cluster_indices.size(); cluster_indices_iter++)
{
@@ -1081,19 +1408,19 @@ namespace basisu
const uint32_t first_index = block_index_iter;
const uint32_t last_index = minimum<uint32_t>(m_total_blocks, first_index + N);
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->add_job( [this, first_index, last_index, &best_cluster_indices, &block_clusters] {
+#endif
for (uint32_t block_index = first_index; block_index < last_index; block_index++)
{
- const bool is_flipped = true;
-
const uint32_t cluster_index = block_clusters[block_index][0];
BASISU_FRONTEND_VERIFY(cluster_index == block_clusters[block_index][1]);
- const color_rgba *subblock_pixels = get_source_pixel_block(block_index).get_ptr();
+ const color_rgba *pSubblock_pixels = get_source_pixel_block(block_index).get_ptr();
const uint32_t num_subblock_pixels = 16;
- uint64_t best_cluster_err = UINT64_MAX;
+ uint64_t best_cluster_err = INT64_MAX;
uint32_t best_cluster_index = 0;
const uint32_t block_parent_endpoint_cluster_index = m_block_parent_endpoint_cluster.size() ? m_block_parent_endpoint_cluster[block_index] : 0;
@@ -1116,19 +1443,20 @@ namespace basisu
// Can't assign it here - may result in too much error when selector quant occurs
if (cluster_etc_inten > m_endpoint_cluster_etc_params[cluster_index].m_inten_table[0])
{
- total_err = UINT64_MAX;
+ total_err = INT64_MAX;
goto skip_cluster;
}
etc_block::get_block_colors5(subblock_colors, cluster_etc_base_color, cluster_etc_inten);
-
+
+#if 0
for (uint32_t p = 0; p < num_subblock_pixels; p++)
{
uint64_t best_err = UINT64_MAX;
for (uint32_t r = low_selector; r <= high_selector; r++)
{
- uint64_t err = color_distance(m_params.m_perceptual, subblock_pixels[p], subblock_colors[r], false);
+ uint64_t err = color_distance(m_params.m_perceptual, pSubblock_pixels[p], subblock_colors[r], false);
best_err = minimum(best_err, err);
if (!best_err)
break;
@@ -1138,6 +1466,64 @@ namespace basisu
if (total_err > best_cluster_err)
break;
} // p
+#else
+ if (m_params.m_perceptual)
+ {
+ if (!g_cpu_supports_sse41)
+ {
+ for (uint32_t p = 0; p < num_subblock_pixels; p++)
+ {
+ uint64_t best_err = UINT64_MAX;
+
+ for (uint32_t r = low_selector; r <= high_selector; r++)
+ {
+ uint64_t err = color_distance(true, pSubblock_pixels[p], subblock_colors[r], false);
+ best_err = minimum(best_err, err);
+ if (!best_err)
+ break;
+ }
+
+ total_err += best_err;
+ if (total_err > best_cluster_err)
+ break;
+ } // p
+ }
+ else
+ {
+#if BASISU_SUPPORT_SSE
+ find_lowest_error_perceptual_rgb_4_N_sse41((int64_t*)&total_err, subblock_colors, pSubblock_pixels, num_subblock_pixels, best_cluster_err);
+#endif
+ }
+ }
+ else
+ {
+ if (!g_cpu_supports_sse41)
+ {
+ for (uint32_t p = 0; p < num_subblock_pixels; p++)
+ {
+ uint64_t best_err = UINT64_MAX;
+
+ for (uint32_t r = low_selector; r <= high_selector; r++)
+ {
+ uint64_t err = color_distance(false, pSubblock_pixels[p], subblock_colors[r], false);
+ best_err = minimum(best_err, err);
+ if (!best_err)
+ break;
+ }
+
+ total_err += best_err;
+ if (total_err > best_cluster_err)
+ break;
+ } // p
+ }
+ else
+ {
+#if BASISU_SUPPORT_SSE
+ find_lowest_error_linear_rgb_4_N_sse41((int64_t*)&total_err, subblock_colors, pSubblock_pixels, num_subblock_pixels, best_cluster_err);
+#endif
+ }
+ }
+#endif
skip_cluster:
if ((total_err < best_cluster_err) ||
@@ -1154,14 +1540,18 @@ namespace basisu
best_cluster_indices[block_index] = best_cluster_index;
} // block_index
-
+
+#ifndef __EMSCRIPTEN__
} );
+#endif
} // block_index_iter
-
+
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
+#endif
- std::vector<typename std::vector<uint32_t> > optimized_endpoint_clusters(m_endpoint_clusters.size());
+ basisu::vector<typename basisu::vector<uint32_t> > optimized_endpoint_clusters(m_endpoint_clusters.size());
uint32_t total_subblocks_reassigned = 0;
for (uint32_t block_index = 0; block_index < m_total_blocks; block_index++)
@@ -1199,8 +1589,8 @@ namespace basisu
indirect_sort((uint32_t)m_endpoint_clusters.size(), &sorted_endpoint_cluster_indices[0], &m_endpoint_cluster_etc_params[0]);
- std::vector<std::vector<uint32_t> > new_endpoint_clusters(m_endpoint_clusters.size());
- std::vector<endpoint_cluster_etc_params> new_subblock_etc_params(m_endpoint_clusters.size());
+ basisu::vector<basisu::vector<uint32_t> > new_endpoint_clusters(m_endpoint_clusters.size());
+ basisu::vector<endpoint_cluster_etc_params> new_subblock_etc_params(m_endpoint_clusters.size());
for (uint32_t i = 0; i < m_endpoint_clusters.size(); i++)
{
@@ -1264,7 +1654,9 @@ namespace basisu
const uint32_t first_index = block_index_iter;
const uint32_t last_index = minimum<uint32_t>(m_total_blocks, first_index + N);
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->add_job( [this, first_index, last_index] {
+#endif
for (uint32_t block_index = first_index; block_index < last_index; block_index++)
{
@@ -1288,12 +1680,16 @@ namespace basisu
blk.determine_selectors(pSource_pixels, m_params.m_perceptual);
} // block_index
-
+
+#ifndef __EMSCRIPTEN__
} );
+#endif
} // block_index_iter
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
+#endif
m_orig_encoded_blocks = m_encoded_blocks;
}
@@ -1302,9 +1698,9 @@ namespace basisu
{
uint_vec block_selector_cluster_indices(m_total_blocks);
- for (int cluster_index = 0; cluster_index < static_cast<int>(m_selector_cluster_indices.size()); cluster_index++)
+ for (int cluster_index = 0; cluster_index < static_cast<int>(m_selector_cluster_block_indices.size()); cluster_index++)
{
- const std::vector<uint32_t>& cluster_indices = m_selector_cluster_indices[cluster_index];
+ const basisu::vector<uint32_t>& cluster_indices = m_selector_cluster_block_indices[cluster_index];
for (uint32_t cluster_indices_iter = 0; cluster_indices_iter < cluster_indices.size(); cluster_indices_iter++)
{
@@ -1317,7 +1713,7 @@ namespace basisu
} // cluster_index
m_selector_clusters_within_each_parent_cluster.resize(0);
- m_selector_clusters_within_each_parent_cluster.resize(m_selector_parent_cluster_indices.size());
+ m_selector_clusters_within_each_parent_cluster.resize(m_selector_parent_cluster_block_indices.size());
for (uint32_t block_index = 0; block_index < m_total_blocks; block_index++)
{
@@ -1355,7 +1751,9 @@ namespace basisu
const uint32_t first_index = block_index_iter;
const uint32_t last_index = minimum<uint32_t>(m_total_blocks, first_index + N);
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->add_job( [this, first_index, last_index, &training_vecs] {
+#endif
for (uint32_t block_index = first_index; block_index < last_index; block_index++)
{
@@ -1382,47 +1780,54 @@ namespace basisu
} // block_index
+#ifndef __EMSCRIPTEN__
} );
+#endif
} // block_index_iter
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
+#endif
vec16F_clusterizer selector_clusterizer;
for (uint32_t i = 0; i < m_total_blocks; i++)
selector_clusterizer.add_training_vec(training_vecs[i].first, training_vecs[i].second);
- const uint32_t parent_codebook_size = (m_params.m_max_selector_clusters >= 256) ? BASISU_SELECTOR_PARENT_CODEBOOK_SIZE : 0;
+ const int selector_parent_codebook_size = (m_params.m_compression_level <= 1) ? BASISU_SELECTOR_PARENT_CODEBOOK_SIZE_COMP_LEVEL_01 : BASISU_SELECTOR_PARENT_CODEBOOK_SIZE_COMP_LEVEL_DEFAULT;
+ const uint32_t parent_codebook_size = (m_params.m_max_selector_clusters >= 256) ? selector_parent_codebook_size : 0;
+ debug_printf("Using selector parent codebook size %u\n", parent_codebook_size);
uint32_t max_threads = 0;
max_threads = m_params.m_multithreaded ? minimum<int>(std::thread::hardware_concurrency(), cMaxCodebookCreationThreads) : 0;
bool status = generate_hierarchical_codebook_threaded(selector_clusterizer,
m_params.m_max_selector_clusters, m_use_hierarchical_selector_codebooks ? parent_codebook_size : 0,
- m_selector_cluster_indices,
- m_selector_parent_cluster_indices,
+ m_selector_cluster_block_indices,
+ m_selector_parent_cluster_block_indices,
max_threads, m_params.m_pJob_pool);
BASISU_FRONTEND_VERIFY(status);
if (m_use_hierarchical_selector_codebooks)
{
- if (!m_selector_parent_cluster_indices.size())
+ if (!m_selector_parent_cluster_block_indices.size())
{
- m_selector_parent_cluster_indices.resize(0);
- m_selector_parent_cluster_indices.resize(1);
+ m_selector_parent_cluster_block_indices.resize(0);
+ m_selector_parent_cluster_block_indices.resize(1);
for (uint32_t i = 0; i < m_total_blocks; i++)
- m_selector_parent_cluster_indices[0].push_back(i);
+ m_selector_parent_cluster_block_indices[0].push_back(i);
}
- BASISU_ASSUME(BASISU_SELECTOR_PARENT_CODEBOOK_SIZE <= UINT8_MAX);
+ BASISU_ASSUME(BASISU_SELECTOR_PARENT_CODEBOOK_SIZE_COMP_LEVEL_01 <= UINT8_MAX);
+ BASISU_ASSUME(BASISU_SELECTOR_PARENT_CODEBOOK_SIZE_COMP_LEVEL_DEFAULT <= UINT8_MAX);
m_block_parent_selector_cluster.resize(0);
m_block_parent_selector_cluster.resize(m_total_blocks);
vector_set_all(m_block_parent_selector_cluster, 0xFF);
- for (uint32_t parent_cluster_index = 0; parent_cluster_index < m_selector_parent_cluster_indices.size(); parent_cluster_index++)
+ for (uint32_t parent_cluster_index = 0; parent_cluster_index < m_selector_parent_cluster_block_indices.size(); parent_cluster_index++)
{
- const uint_vec &cluster = m_selector_parent_cluster_indices[parent_cluster_index];
+ const uint_vec &cluster = m_selector_parent_cluster_block_indices[parent_cluster_index];
for (uint32_t j = 0; j < cluster.size(); j++)
m_block_parent_selector_cluster[cluster[j]] = static_cast<uint8_t>(parent_cluster_index);
}
@@ -1432,9 +1837,9 @@ namespace basisu
}
// Ensure that all the blocks within each cluster are all in the same parent cluster, or something is very wrong.
- for (uint32_t cluster_index = 0; cluster_index < m_selector_cluster_indices.size(); cluster_index++)
+ for (uint32_t cluster_index = 0; cluster_index < m_selector_cluster_block_indices.size(); cluster_index++)
{
- const uint_vec &cluster = m_selector_cluster_indices[cluster_index];
+ const uint_vec &cluster = m_selector_cluster_block_indices[cluster_index];
uint32_t parent_cluster_index = 0;
for (uint32_t j = 0; j < cluster.size(); j++)
@@ -1452,14 +1857,16 @@ namespace basisu
}
}
- debug_printf("Total selector clusters: %u, total parent selector clusters: %u\n", (uint32_t)m_selector_cluster_indices.size(), (uint32_t)m_selector_parent_cluster_indices.size());
+ debug_printf("Total selector clusters: %u, total parent selector clusters: %u\n", (uint32_t)m_selector_cluster_block_indices.size(), (uint32_t)m_selector_parent_cluster_block_indices.size());
}
void basisu_frontend::create_optimized_selector_codebook(uint32_t iter)
{
debug_printf("create_optimized_selector_codebook\n");
- const uint32_t total_selector_clusters = (uint32_t)m_selector_cluster_indices.size();
+ const uint32_t total_selector_clusters = (uint32_t)m_selector_cluster_block_indices.size();
+
+ debug_printf("Total selector clusters (from m_selector_cluster_block_indices.size()): %u\n", (uint32_t)m_selector_cluster_block_indices.size());
m_optimized_cluster_selectors.resize(total_selector_clusters);
@@ -1474,12 +1881,14 @@ namespace basisu
{
const uint32_t first_index = cluster_index_iter;
const uint32_t last_index = minimum<uint32_t>((uint32_t)total_selector_clusters, cluster_index_iter + N);
-
+
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->add_job( [this, first_index, last_index, &total_clusters_processed, &total_selector_clusters] {
+#endif
for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++)
{
- const std::vector<uint32_t> &cluster_block_indices = m_selector_cluster_indices[cluster_index];
+ const basisu::vector<uint32_t> &cluster_block_indices = m_selector_cluster_block_indices[cluster_index];
if (!cluster_block_indices.size())
continue;
@@ -1528,11 +1937,15 @@ namespace basisu
} // cluster_index
+#ifndef __EMSCRIPTEN__
} );
+#endif
} // cluster_index_iter
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
+#endif
}
else
{
@@ -1552,12 +1965,14 @@ namespace basisu
{
const uint32_t first_index = cluster_index_iter;
const uint32_t last_index = minimum<uint32_t>((uint32_t)total_selector_clusters, cluster_index_iter + N);
-
+
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->add_job( [this, first_index, last_index, &uses_hybrid_sel_codebook, &total_clusters_processed, &total_selector_clusters] {
+#endif
for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++)
{
- const std::vector<uint32_t> &cluster_block_indices = m_selector_cluster_indices[cluster_index];
+ const basisu::vector<uint32_t> &cluster_block_indices = m_selector_cluster_block_indices[cluster_index];
if (!cluster_block_indices.size())
continue;
@@ -1667,29 +2082,33 @@ namespace basisu
} // cluster_index
+#ifndef __EMSCRIPTEN__
} );
+#endif
} // cluster_index_iter
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
+#endif
} // if (m_params.m_pGlobal_sel_codebook)
-
+
if (m_params.m_debug_images)
{
uint32_t max_selector_cluster_size = 0;
- for (uint32_t i = 0; i < m_selector_cluster_indices.size(); i++)
- max_selector_cluster_size = maximum<uint32_t>(max_selector_cluster_size, (uint32_t)m_selector_cluster_indices[i].size());
+ for (uint32_t i = 0; i < m_selector_cluster_block_indices.size(); i++)
+ max_selector_cluster_size = maximum<uint32_t>(max_selector_cluster_size, (uint32_t)m_selector_cluster_block_indices[i].size());
if ((max_selector_cluster_size * 5) < 32768)
{
const uint32_t x_spacer_len = 16;
- image selector_cluster_vis(x_spacer_len + max_selector_cluster_size * 5, (uint32_t)m_selector_cluster_indices.size() * 5);
+ image selector_cluster_vis(x_spacer_len + max_selector_cluster_size * 5, (uint32_t)m_selector_cluster_block_indices.size() * 5);
- for (uint32_t selector_cluster_index = 0; selector_cluster_index < m_selector_cluster_indices.size(); selector_cluster_index++)
+ for (uint32_t selector_cluster_index = 0; selector_cluster_index < m_selector_cluster_block_indices.size(); selector_cluster_index++)
{
- const std::vector<uint32_t> &cluster_block_indices = m_selector_cluster_indices[selector_cluster_index];
+ const basisu::vector<uint32_t> &cluster_block_indices = m_selector_cluster_block_indices[selector_cluster_index];
for (uint32_t y = 0; y < 4; y++)
for (uint32_t x = 0; x < 4; x++)
@@ -1717,31 +2136,56 @@ namespace basisu
void basisu_frontend::find_optimal_selector_clusters_for_each_block()
{
debug_printf("find_optimal_selector_clusters_for_each_block\n");
-
+
+ // Sanity checks
+ BASISU_FRONTEND_VERIFY(m_selector_cluster_block_indices.size() == m_optimized_cluster_selectors.size());
+ for (uint32_t i = 0; i < m_selector_clusters_within_each_parent_cluster.size(); i++)
+ {
+ for (uint32_t j = 0; j < m_selector_clusters_within_each_parent_cluster[i].size(); j++)
+ {
+ BASISU_FRONTEND_VERIFY(m_selector_clusters_within_each_parent_cluster[i][j] < m_optimized_cluster_selectors.size());
+ }
+ }
+
m_block_selector_cluster_index.resize(m_total_blocks);
-
+
if (m_params.m_compression_level == 0)
{
// Don't do anything, just leave the blocks in their original selector clusters.
- for (uint32_t i = 0; i < m_selector_cluster_indices.size(); i++)
+ for (uint32_t i = 0; i < m_selector_cluster_block_indices.size(); i++)
{
- for (uint32_t j = 0; j < m_selector_cluster_indices[i].size(); j++)
- m_block_selector_cluster_index[m_selector_cluster_indices[i][j]] = i;
+ for (uint32_t j = 0; j < m_selector_cluster_block_indices[i].size(); j++)
+ m_block_selector_cluster_index[m_selector_cluster_block_indices[i][j]] = i;
}
}
else
{
- std::vector< std::vector<uint32_t> > new_cluster_indices;
-
+ // Note that this method may leave some empty clusters (i.e. arrays with no block indices), including at the end.
+ basisu::vector< basisu::vector<uint32_t> > new_cluster_indices(m_optimized_cluster_selectors.size());
+
// For each block: Determine which quantized selectors best encode that block, given its quantized endpoints.
+ basisu::vector<uint8_t> unpacked_optimized_cluster_selectors(16 * m_optimized_cluster_selectors.size());
+ for (uint32_t cluster_index = 0; cluster_index < m_optimized_cluster_selectors.size(); cluster_index++)
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ unpacked_optimized_cluster_selectors[cluster_index * 16 + y * 4 + x] = (uint8_t)m_optimized_cluster_selectors[cluster_index].get_selector(x, y);
+ }
+ }
+ }
+
const uint32_t N = 1024;
for (uint32_t block_index_iter = 0; block_index_iter < m_total_blocks; block_index_iter += N)
{
const uint32_t first_index = block_index_iter;
const uint32_t last_index = minimum<uint32_t>(m_total_blocks, first_index + N);
- m_params.m_pJob_pool->add_job( [this, first_index, last_index, &new_cluster_indices] {
+#ifndef __EMSCRIPTEN__
+ m_params.m_pJob_pool->add_job( [this, first_index, last_index, &new_cluster_indices, &unpacked_optimized_cluster_selectors] {
+#endif
for (uint32_t block_index = first_index; block_index < last_index; block_index++)
{
@@ -1752,20 +2196,32 @@ namespace basisu
color_rgba trial_block_colors[4];
blk.get_block_colors(trial_block_colors, 0);
- uint64_t best_cluster_err = UINT64_MAX;
+ // precompute errors for the i-th block pixel and selector sel: [sel][i]
+ uint32_t trial_errors[4][16];
+
+ for (int sel = 0; sel < 4; ++sel)
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ trial_errors[sel][i] = color_distance(m_params.m_perceptual, pBlock_pixels[i], trial_block_colors[sel], false);
+ }
+ }
+
+ uint64_t best_cluster_err = INT64_MAX;
uint32_t best_cluster_index = 0;
const uint32_t parent_selector_cluster = m_block_parent_selector_cluster.size() ? m_block_parent_selector_cluster[block_index] : 0;
const uint_vec *pCluster_indices = m_selector_clusters_within_each_parent_cluster.size() ? &m_selector_clusters_within_each_parent_cluster[parent_selector_cluster] : nullptr;
- const uint32_t total_clusters = m_use_hierarchical_selector_codebooks ? (uint32_t)pCluster_indices->size() : (uint32_t)m_selector_cluster_indices.size();
+ const uint32_t total_clusters = m_use_hierarchical_selector_codebooks ? (uint32_t)pCluster_indices->size() : (uint32_t)m_selector_cluster_block_indices.size();
+#if 0
for (uint32_t cluster_iter = 0; cluster_iter < total_clusters; cluster_iter++)
{
const uint32_t cluster_index = m_use_hierarchical_selector_codebooks ? (*pCluster_indices)[cluster_iter] : cluster_iter;
const etc_block& cluster_blk = m_optimized_cluster_selectors[cluster_index];
-
+
uint64_t trial_err = 0;
for (int y = 0; y < 4; y++)
{
@@ -1778,18 +2234,82 @@ namespace basisu
goto early_out;
}
}
-
+
if (trial_err < best_cluster_err)
{
best_cluster_err = trial_err;
best_cluster_index = cluster_index;
- if (!best_cluster_err)
+ if (!best_cluster_err)
break;
}
early_out:
;
}
+#else
+ if (m_params.m_perceptual)
+ {
+ for (uint32_t cluster_iter = 0; cluster_iter < total_clusters; cluster_iter++)
+ {
+ const uint32_t cluster_index = m_use_hierarchical_selector_codebooks ? (*pCluster_indices)[cluster_iter] : cluster_iter;
+ //const etc_block& cluster_blk = m_optimized_cluster_selectors[cluster_index];
+
+ uint64_t trial_err = 0;
+
+ for (int i = 0; i < 16; i++)
+ {
+ const uint32_t sel = unpacked_optimized_cluster_selectors[cluster_index * 16 + i];
+
+ trial_err += trial_errors[sel][i];
+ if (trial_err > best_cluster_err)
+ goto early_out;
+ }
+
+ if (trial_err < best_cluster_err)
+ {
+ best_cluster_err = trial_err;
+ best_cluster_index = cluster_index;
+ if (!best_cluster_err)
+ break;
+ }
+
+ early_out:
+ ;
+
+ } // cluster_iter
+ }
+ else
+ {
+ for (uint32_t cluster_iter = 0; cluster_iter < total_clusters; cluster_iter++)
+ {
+ const uint32_t cluster_index = m_use_hierarchical_selector_codebooks ? (*pCluster_indices)[cluster_iter] : cluster_iter;
+ //const etc_block& cluster_blk = m_optimized_cluster_selectors[cluster_index];
+
+ uint64_t trial_err = 0;
+
+ for (int i = 0; i < 16; i++)
+ {
+ const uint32_t sel = unpacked_optimized_cluster_selectors[cluster_index * 16 + i];
+
+ trial_err += trial_errors[sel][i];
+ if (trial_err > best_cluster_err)
+ goto early_out2;
+ }
+
+ if (trial_err < best_cluster_err)
+ {
+ best_cluster_err = trial_err;
+ best_cluster_index = cluster_index;
+ if (!best_cluster_err)
+ break;
+ }
+
+ early_out2:
+ ;
+
+ } // cluster_iter
+ }
+#endif
blk.set_raw_selector_bits(m_optimized_cluster_selectors[best_cluster_index].get_raw_selector_bits());
@@ -1804,17 +2324,21 @@ namespace basisu
} // block_index
+#ifndef __EMSCRIPTEN__
} );
+#endif
} // block_index_iter
-
+
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
-
- m_selector_cluster_indices.swap(new_cluster_indices);
+#endif
+
+ m_selector_cluster_block_indices.swap(new_cluster_indices);
}
- for (uint32_t i = 0; i < m_selector_cluster_indices.size(); i++)
- vector_sort(m_selector_cluster_indices[i]);
+ for (uint32_t i = 0; i < m_selector_cluster_block_indices.size(); i++)
+ vector_sort(m_selector_cluster_block_indices[i]);
}
// TODO: Remove old ETC1 specific stuff, and thread this.
@@ -1842,7 +2366,7 @@ namespace basisu
const uint_vec &subblocks = subblock_params.m_subblocks;
//uint32_t total_pixels = subblock.m_subblocks.size() * 8;
- std::vector<color_rgba> subblock_colors[2]; // [use_individual_mode]
+ basisu::vector<color_rgba> subblock_colors[2]; // [use_individual_mode]
uint8_vec subblock_selectors[2];
uint64_t cur_subblock_err[2] = { 0, 0 };
@@ -1882,7 +2406,7 @@ namespace basisu
clear_obj(cluster_optimizer_results);
- std::vector<uint8_t> cluster_selectors[2];
+ basisu::vector<uint8_t> cluster_selectors[2];
for (uint32_t use_individual_mode = 0; use_individual_mode < 2; use_individual_mode++)
{
@@ -1938,7 +2462,7 @@ namespace basisu
const uint32_t block_index = training_vector_index >> 1;
const uint32_t subblock_index = training_vector_index & 1;
- const bool is_flipped = true;
+ //const bool is_flipped = true;
etc_block &blk = m_encoded_blocks[block_index];
@@ -2002,7 +2526,7 @@ namespace basisu
if (m_params.m_debug_stats)
debug_printf("Total subblock endpoints refined: %u (%3.1f%%)\n", total_subblocks_refined, total_subblocks_refined * 100.0f / total_subblocks_examined);
-
+
return total_subblocks_refined;
}
@@ -2012,8 +2536,8 @@ namespace basisu
uint32_t max_endpoint_cluster_size = 0;
- std::vector<uint32_t> cluster_sizes(m_endpoint_clusters.size());
- std::vector<uint32_t> sorted_cluster_indices(m_endpoint_clusters.size());
+ basisu::vector<uint32_t> cluster_sizes(m_endpoint_clusters.size());
+ basisu::vector<uint32_t> sorted_cluster_indices(m_endpoint_clusters.size());
for (uint32_t i = 0; i < m_endpoint_clusters.size(); i++)
{
max_endpoint_cluster_size = maximum<uint32_t>(max_endpoint_cluster_size, (uint32_t)m_endpoint_clusters[i].size());
@@ -2100,30 +2624,33 @@ namespace basisu
{
debug_printf("reoptimize_remapped_endpoints\n");
- std::vector<uint_vec> new_endpoint_cluster_block_indices(m_endpoint_clusters.size());
+ basisu::vector<uint_vec> new_endpoint_cluster_block_indices(m_endpoint_clusters.size());
for (uint32_t i = 0; i < new_block_endpoints.size(); i++)
new_endpoint_cluster_block_indices[new_block_endpoints[i]].push_back(i);
- std::vector<uint8_t> cluster_valid(new_endpoint_cluster_block_indices.size());
- std::vector<uint8_t> cluster_improved(new_endpoint_cluster_block_indices.size());
+ basisu::vector<uint8_t> cluster_valid(new_endpoint_cluster_block_indices.size());
+ basisu::vector<uint8_t> cluster_improved(new_endpoint_cluster_block_indices.size());
const uint32_t N = 256;
for (uint32_t cluster_index_iter = 0; cluster_index_iter < new_endpoint_cluster_block_indices.size(); cluster_index_iter += N)
{
const uint32_t first_index = cluster_index_iter;
const uint32_t last_index = minimum<uint32_t>((uint32_t)new_endpoint_cluster_block_indices.size(), cluster_index_iter + N);
-
+
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->add_job( [this, first_index, last_index, &cluster_improved, &cluster_valid, &new_endpoint_cluster_block_indices, &pBlock_selector_indices ] {
+#endif
+
for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++)
{
- const std::vector<uint32_t>& cluster_block_indices = new_endpoint_cluster_block_indices[cluster_index];
+ const basisu::vector<uint32_t>& cluster_block_indices = new_endpoint_cluster_block_indices[cluster_index];
if (!cluster_block_indices.size())
continue;
const uint32_t total_pixels = (uint32_t)cluster_block_indices.size() * 16;
- std::vector<color_rgba> cluster_pixels(total_pixels);
+ basisu::vector<color_rgba> cluster_pixels(total_pixels);
uint8_vec force_selectors(total_pixels);
etc_block blk;
@@ -2170,16 +2697,19 @@ namespace basisu
if (m_params.m_compression_level == BASISU_MAX_COMPRESSION_LEVEL)
cluster_optimizer_params.m_quality = cETCQualityUber;
+ else
+ cluster_optimizer_params.m_quality = cETCQualitySlow;
etc1_optimizer::results cluster_optimizer_results;
- std::vector<uint8_t> cluster_selectors(total_pixels);
+ basisu::vector<uint8_t> cluster_selectors(total_pixels);
cluster_optimizer_results.m_n = total_pixels;
cluster_optimizer_results.m_pSelectors = &cluster_selectors[0];
optimizer.init(cluster_optimizer_params, cluster_optimizer_results);
- optimizer.compute();
+ if (!optimizer.compute())
+ BASISU_FRONTEND_VERIFY(false);
new_endpoint_cluster_etc_params.m_color_unscaled[0] = cluster_optimizer_results.m_block_color_unscaled;
new_endpoint_cluster_etc_params.m_inten_table[0] = cluster_optimizer_results.m_block_inten_table;
@@ -2198,11 +2728,16 @@ namespace basisu
cluster_valid[cluster_index] = true;
} // cluster_index
+
+#ifndef __EMSCRIPTEN__
} );
+#endif
} // cluster_index_iter
+#ifndef __EMSCRIPTEN__
m_params.m_pJob_pool->wait_for_all();
+#endif
uint32_t total_unused_clusters = 0;
uint32_t total_improved_clusters = 0;
@@ -2239,7 +2774,7 @@ namespace basisu
debug_printf("basisu_frontend::reoptimize_remapped_endpoints: stage 1\n");
- std::vector<uint_vec> new_endpoint_clusters(total_new_endpoint_clusters);
+ basisu::vector<uint_vec> new_endpoint_clusters(total_new_endpoint_clusters);
for (uint32_t block_index = 0; block_index < new_block_endpoints.size(); block_index++)
{
diff --git a/thirdparty/basis_universal/basisu_frontend.h b/thirdparty/basis_universal/encoder/basisu_frontend.h
index c3f5d23c71..4ff6d40466 100644
--- a/thirdparty/basis_universal/basisu_frontend.h
+++ b/thirdparty/basis_universal/encoder/basisu_frontend.h
@@ -1,5 +1,5 @@
// basisu_frontend.h
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,7 +17,8 @@
#include "basisu_etc.h"
#include "basisu_gpu_texture.h"
#include "basisu_global_selector_palette_helpers.h"
-#include "transcoder/basisu_file_headers.h"
+#include "../transcoder/basisu_file_headers.h"
+#include "../transcoder/basisu_transcoder.h"
namespace basisu
{
@@ -34,8 +35,8 @@ namespace basisu
uint32_t &operator[] (uint32_t i) { assert(i < 2); return m_comps[i]; }
};
- const uint32_t BASISU_DEFAULT_COMPRESSION_LEVEL = 1;
- const uint32_t BASISU_MAX_COMPRESSION_LEVEL = 5;
+ const uint32_t BASISU_DEFAULT_COMPRESSION_LEVEL = 2;
+ const uint32_t BASISU_MAX_COMPRESSION_LEVEL = 6;
class basisu_frontend
{
@@ -72,16 +73,19 @@ namespace basisu
m_perceptual(true),
m_debug_stats(false),
m_debug_images(false),
+
m_dump_endpoint_clusterization(true),
+ m_validate(false),
+ m_multithreaded(false),
+ m_disable_hierarchical_endpoint_codebooks(false),
m_pGlobal_sel_codebook(NULL),
m_num_global_sel_codebook_pal_bits(0),
m_num_global_sel_codebook_mod_bits(0),
m_use_hybrid_selector_codebooks(false),
m_hybrid_codebook_quality_thresh(0.0f),
- m_validate(false),
m_tex_type(basist::cBASISTexType2D),
- m_multithreaded(false),
- m_disable_hierarchical_endpoint_codebooks(false),
+ m_pGlobal_codebooks(nullptr),
+
m_pJob_pool(nullptr)
{
}
@@ -108,6 +112,7 @@ namespace basisu
bool m_use_hybrid_selector_codebooks;
float m_hybrid_codebook_quality_thresh;
basist::basis_texture_type m_tex_type;
+ const basist::basisu_lowlevel_etc1s_transcoder *m_pGlobal_codebooks;
job_pool *m_pJob_pool;
};
@@ -142,7 +147,7 @@ namespace basisu
bool get_endpoint_cluster_color_is_used(uint32_t cluster_index, bool individual_mode) const { return m_endpoint_cluster_etc_params[cluster_index].m_color_used[individual_mode]; }
// Selector clusters
- uint32_t get_total_selector_clusters() const { return static_cast<uint32_t>(m_selector_cluster_indices.size()); }
+ uint32_t get_total_selector_clusters() const { return static_cast<uint32_t>(m_selector_cluster_block_indices.size()); }
uint32_t get_block_selector_cluster_index(uint32_t block_index) const { return m_block_selector_cluster_index[block_index]; }
const etc_block &get_selector_cluster_selector_bits(uint32_t cluster_index) const { return m_optimized_cluster_selectors[cluster_index]; }
@@ -150,7 +155,7 @@ namespace basisu
const bool_vec &get_selector_cluster_uses_global_cb_vec() const { return m_selector_cluster_uses_global_cb; }
// Returns block indices using each selector cluster
- const uint_vec &get_selector_cluster_block_indices(uint32_t selector_cluster_index) const { return m_selector_cluster_indices[selector_cluster_index]; }
+ const uint_vec &get_selector_cluster_block_indices(uint32_t selector_cluster_index) const { return m_selector_cluster_block_indices[selector_cluster_index]; }
void dump_debug_image(const char *pFilename, uint32_t first_block, uint32_t num_blocks_x, uint32_t num_blocks_y, bool output_blocks);
@@ -188,16 +193,16 @@ namespace basisu
// For each endpoint cluster: An array of which subblock indices (block_index*2+subblock) are located in that cluster.
// Array of block indices for each endpoint cluster
- std::vector<uint_vec> m_endpoint_clusters;
+ basisu::vector<uint_vec> m_endpoint_clusters;
// Array of block indices for each parent endpoint cluster
- std::vector<uint_vec> m_endpoint_parent_clusters;
+ basisu::vector<uint_vec> m_endpoint_parent_clusters;
// Each block's parent cluster index
uint8_vec m_block_parent_endpoint_cluster;
// Array of endpoint cluster indices for each parent endpoint cluster
- std::vector<uint_vec> m_endpoint_clusters_within_each_parent_cluster;
+ basisu::vector<uint_vec> m_endpoint_clusters_within_each_parent_cluster;
struct endpoint_cluster_etc_params
{
@@ -267,35 +272,35 @@ namespace basisu
}
};
- typedef std::vector<endpoint_cluster_etc_params> cluster_subblock_etc_params_vec;
+ typedef basisu::vector<endpoint_cluster_etc_params> cluster_subblock_etc_params_vec;
// Each endpoint cluster's ETC1S parameters
cluster_subblock_etc_params_vec m_endpoint_cluster_etc_params;
// The endpoint cluster index used by each ETC1 subblock.
- std::vector<vec2U> m_block_endpoint_clusters_indices;
+ basisu::vector<vec2U> m_block_endpoint_clusters_indices;
// The block(s) within each selector cluster
// Note: If you add anything here that uses selector cluster indicies, be sure to update optimize_selector_codebook()!
- std::vector<uint_vec> m_selector_cluster_indices;
+ basisu::vector<uint_vec> m_selector_cluster_block_indices;
// The selector bits for each selector cluster.
- std::vector<etc_block> m_optimized_cluster_selectors;
+ basisu::vector<etc_block> m_optimized_cluster_selectors;
// The block(s) within each parent selector cluster.
- std::vector<uint_vec> m_selector_parent_cluster_indices;
+ basisu::vector<uint_vec> m_selector_parent_cluster_block_indices;
// Each block's parent selector cluster
uint8_vec m_block_parent_selector_cluster;
// Array of selector cluster indices for each parent selector cluster
- std::vector<uint_vec> m_selector_clusters_within_each_parent_cluster;
+ basisu::vector<uint_vec> m_selector_clusters_within_each_parent_cluster;
basist::etc1_global_selector_codebook_entry_id_vec m_optimized_cluster_selector_global_cb_ids;
bool_vec m_selector_cluster_uses_global_cb;
// Each block's selector cluster index
- std::vector<uint32_t> m_block_selector_cluster_index;
+ basisu::vector<uint32_t> m_block_selector_cluster_index;
struct subblock_endpoint_quant_err
{
@@ -321,13 +326,14 @@ namespace basisu
};
// The sorted subblock endpoint quant error for each endpoint cluster
- std::vector<subblock_endpoint_quant_err> m_subblock_endpoint_quant_err_vec;
+ basisu::vector<subblock_endpoint_quant_err> m_subblock_endpoint_quant_err_vec;
std::mutex m_lock;
//-----------------------------------------------------------------------------
void init_etc1_images();
+ bool init_global_codebooks();
void init_endpoint_training_vectors();
void dump_endpoint_clusterization_visualization(const char *pFilename, bool vis_endpoint_colors);
void generate_endpoint_clusters();
diff --git a/thirdparty/basis_universal/basisu_global_selector_palette_helpers.cpp b/thirdparty/basis_universal/encoder/basisu_global_selector_palette_helpers.cpp
index 102fc24980..102fc24980 100644
--- a/thirdparty/basis_universal/basisu_global_selector_palette_helpers.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_global_selector_palette_helpers.cpp
diff --git a/thirdparty/basis_universal/basisu_global_selector_palette_helpers.h b/thirdparty/basis_universal/encoder/basisu_global_selector_palette_helpers.h
index 32692c516b..7c35439df8 100644
--- a/thirdparty/basis_universal/basisu_global_selector_palette_helpers.h
+++ b/thirdparty/basis_universal/encoder/basisu_global_selector_palette_helpers.h
@@ -14,9 +14,9 @@
// limitations under the License.
#pragma once
-#include "transcoder/basisu.h"
+#include "../transcoder/basisu.h"
#include "basisu_etc.h"
-#include "transcoder/basisu_global_selector_palette.h"
+#include "../transcoder/basisu_global_selector_palette.h"
namespace basisu
{
@@ -36,7 +36,7 @@ namespace basisu
void clear() { clear_obj(*this); }
};
- typedef std::vector<pixel_block> pixel_block_vec;
+ typedef basisu::vector<pixel_block> pixel_block_vec;
uint64_t etc1_global_selector_codebook_find_best_entry(const basist::etc1_global_selector_codebook &codebook,
uint32_t num_src_pixel_blocks, const pixel_block *pSrc_pixel_blocks, const etc_block *pBlock_endpoints,
diff --git a/thirdparty/basis_universal/basisu_gpu_texture.cpp b/thirdparty/basis_universal/encoder/basisu_gpu_texture.cpp
index 117668c5e2..3f9fb67bdd 100644
--- a/thirdparty/basis_universal/basisu_gpu_texture.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_gpu_texture.cpp
@@ -1,5 +1,5 @@
// basisu_gpu_texture.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,38 +16,10 @@
#include "basisu_enc.h"
#include "basisu_pvrtc1_4.h"
#include "basisu_astc_decomp.h"
+#include "basisu_bc7enc.h"
namespace basisu
{
- const int8_t g_etc2_eac_tables[16][8] =
- {
- { -3, -6, -9, -15, 2, 5, 8, 14 }, { -3, -7, -10, -13, 2, 6, 9, 12 }, { -2, -5, -8, -13, 1, 4, 7, 12 }, { -2, -4, -6, -13, 1, 3, 5, 12 },
- { -3, -6, -8, -12, 2, 5, 7, 11 }, { -3, -7, -9, -11, 2, 6, 8, 10 }, { -4, -7, -8, -11, 3, 6, 7, 10 }, { -3, -5, -8, -11, 2, 4, 7, 10 },
- { -2, -6, -8, -10, 1, 5, 7, 9 }, { -2, -5, -8, -10, 1, 4, 7, 9 }, { -2, -4, -8, -10, 1, 3, 7, 9 }, { -2, -5, -7, -10, 1, 4, 6, 9 },
- { -3, -4, -7, -10, 2, 3, 6, 9 }, { -1, -2, -3, -10, 0, 1, 2, 9 }, { -4, -6, -8, -9, 3, 5, 7, 8 }, { -3, -5, -7, -9, 2, 4, 6, 8 }
- };
-
- struct eac_a8_block
- {
- uint16_t m_base : 8;
- uint16_t m_table : 4;
- uint16_t m_multiplier : 4;
-
- uint8_t m_selectors[6];
-
- inline uint32_t get_selector(uint32_t x, uint32_t y, uint64_t selector_bits) const
- {
- assert((x < 4) && (y < 4));
- return static_cast<uint32_t>((selector_bits >> (45 - (y + x * 4) * 3)) & 7);
- }
-
- inline uint64_t get_selector_bits() const
- {
- uint64_t pixels = ((uint64_t)m_selectors[0] << 40) | ((uint64_t)m_selectors[1] << 32) | ((uint64_t)m_selectors[2] << 24) | ((uint64_t)m_selectors[3] << 16) | ((uint64_t)m_selectors[4] << 8) | m_selectors[5];
- return pixels;
- }
- };
-
void unpack_etc2_eac(const void *pBlock_bits, color_rgba *pPixels)
{
static_assert(sizeof(eac_a8_block) == 8, "sizeof(eac_a8_block) == 8");
@@ -123,19 +95,18 @@ namespace basisu
bc1_block::unpack_color(l, r0, g0, b0);
bc1_block::unpack_color(h, r1, g1, b1);
+ c[0].set_noclamp_rgba(r0, g0, b0, 255);
+ c[1].set_noclamp_rgba(r1, g1, b1, 255);
+
bool used_punchthrough = false;
if (l > h)
{
- c[0].set_noclamp_rgba(r0, g0, b0, 255);
- c[1].set_noclamp_rgba(r1, g1, b1, 255);
c[2].set_noclamp_rgba((r0 * 2 + r1) / 3, (g0 * 2 + g1) / 3, (b0 * 2 + b1) / 3, 255);
c[3].set_noclamp_rgba((r1 * 2 + r0) / 3, (g1 * 2 + g0) / 3, (b1 * 2 + b0) / 3, 255);
}
else
{
- c[0].set_noclamp_rgba(r0, g0, b0, 255);
- c[1].set_noclamp_rgba(r1, g1, b1, 255);
c[2].set_noclamp_rgba((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 255);
c[3].set_noclamp_rgba(0, 0, 0, 0);
used_punchthrough = true;
@@ -165,6 +136,142 @@ namespace basisu
return used_punchthrough;
}
+ bool unpack_bc1_nv(const void *pBlock_bits, color_rgba *pPixels, bool set_alpha)
+ {
+ static_assert(sizeof(bc1_block) == 8, "sizeof(bc1_block) == 8");
+
+ const bc1_block *pBlock = static_cast<const bc1_block *>(pBlock_bits);
+
+ const uint32_t l = pBlock->get_low_color();
+ const uint32_t h = pBlock->get_high_color();
+
+ color_rgba c[4];
+
+ int r0 = (l >> 11) & 31;
+ int g0 = (l >> 5) & 63;
+ int b0 = l & 31;
+ int r1 = (h >> 11) & 31;
+ int g1 = (h >> 5) & 63;
+ int b1 = h & 31;
+
+ c[0].b = (uint8_t)((3 * b0 * 22) / 8);
+ c[0].g = (uint8_t)((g0 << 2) | (g0 >> 4));
+ c[0].r = (uint8_t)((3 * r0 * 22) / 8);
+ c[0].a = 0xFF;
+
+ c[1].r = (uint8_t)((3 * r1 * 22) / 8);
+ c[1].g = (uint8_t)((g1 << 2) | (g1 >> 4));
+ c[1].b = (uint8_t)((3 * b1 * 22) / 8);
+ c[1].a = 0xFF;
+
+ int gdiff = c[1].g - c[0].g;
+
+ bool used_punchthrough = false;
+
+ if (l > h)
+ {
+ c[2].r = (uint8_t)(((2 * r0 + r1) * 22) / 8);
+ c[2].g = (uint8_t)(((256 * c[0].g + gdiff/4 + 128 + gdiff * 80) / 256));
+ c[2].b = (uint8_t)(((2 * b0 + b1) * 22) / 8);
+ c[2].a = 0xFF;
+
+ c[3].r = (uint8_t)(((2 * r1 + r0) * 22) / 8);
+ c[3].g = (uint8_t)((256 * c[1].g - gdiff/4 + 128 - gdiff * 80) / 256);
+ c[3].b = (uint8_t)(((2 * b1 + b0) * 22) / 8);
+ c[3].a = 0xFF;
+ }
+ else
+ {
+ c[2].r = (uint8_t)(((r0 + r1) * 33) / 8);
+ c[2].g = (uint8_t)((256 * c[0].g + gdiff/4 + 128 + gdiff * 128) / 256);
+ c[2].b = (uint8_t)(((b0 + b1) * 33) / 8);
+ c[2].a = 0xFF;
+
+ c[3].set_noclamp_rgba(0, 0, 0, 0);
+ used_punchthrough = true;
+ }
+
+ if (set_alpha)
+ {
+ for (uint32_t y = 0; y < 4; y++, pPixels += 4)
+ {
+ pPixels[0] = c[pBlock->get_selector(0, y)];
+ pPixels[1] = c[pBlock->get_selector(1, y)];
+ pPixels[2] = c[pBlock->get_selector(2, y)];
+ pPixels[3] = c[pBlock->get_selector(3, y)];
+ }
+ }
+ else
+ {
+ for (uint32_t y = 0; y < 4; y++, pPixels += 4)
+ {
+ pPixels[0].set_rgb(c[pBlock->get_selector(0, y)]);
+ pPixels[1].set_rgb(c[pBlock->get_selector(1, y)]);
+ pPixels[2].set_rgb(c[pBlock->get_selector(2, y)]);
+ pPixels[3].set_rgb(c[pBlock->get_selector(3, y)]);
+ }
+ }
+
+ return used_punchthrough;
+ }
+
+ static inline int interp_5_6_amd(int c0, int c1) { assert(c0 < 256 && c1 < 256); return (c0 * 43 + c1 * 21 + 32) >> 6; }
+ static inline int interp_half_5_6_amd(int c0, int c1) { assert(c0 < 256 && c1 < 256); return (c0 + c1 + 1) >> 1; }
+
+ bool unpack_bc1_amd(const void *pBlock_bits, color_rgba *pPixels, bool set_alpha)
+ {
+ const bc1_block *pBlock = static_cast<const bc1_block *>(pBlock_bits);
+
+ const uint32_t l = pBlock->get_low_color();
+ const uint32_t h = pBlock->get_high_color();
+
+ color_rgba c[4];
+
+ uint32_t r0, g0, b0, r1, g1, b1;
+ bc1_block::unpack_color(l, r0, g0, b0);
+ bc1_block::unpack_color(h, r1, g1, b1);
+
+ c[0].set_noclamp_rgba(r0, g0, b0, 255);
+ c[1].set_noclamp_rgba(r1, g1, b1, 255);
+
+ bool used_punchthrough = false;
+
+ if (l > h)
+ {
+ c[2].set_noclamp_rgba(interp_5_6_amd(r0, r1), interp_5_6_amd(g0, g1), interp_5_6_amd(b0, b1), 255);
+ c[3].set_noclamp_rgba(interp_5_6_amd(r1, r0), interp_5_6_amd(g1, g0), interp_5_6_amd(b1, b0), 255);
+ }
+ else
+ {
+ c[2].set_noclamp_rgba(interp_half_5_6_amd(r0, r1), interp_half_5_6_amd(g0, g1), interp_half_5_6_amd(b0, b1), 255);
+ c[3].set_noclamp_rgba(0, 0, 0, 0);
+ used_punchthrough = true;
+ }
+
+ if (set_alpha)
+ {
+ for (uint32_t y = 0; y < 4; y++, pPixels += 4)
+ {
+ pPixels[0] = c[pBlock->get_selector(0, y)];
+ pPixels[1] = c[pBlock->get_selector(1, y)];
+ pPixels[2] = c[pBlock->get_selector(2, y)];
+ pPixels[3] = c[pBlock->get_selector(3, y)];
+ }
+ }
+ else
+ {
+ for (uint32_t y = 0; y < 4; y++, pPixels += 4)
+ {
+ pPixels[0].set_rgb(c[pBlock->get_selector(0, y)]);
+ pPixels[1].set_rgb(c[pBlock->get_selector(1, y)]);
+ pPixels[2].set_rgb(c[pBlock->get_selector(2, y)]);
+ pPixels[3].set_rgb(c[pBlock->get_selector(3, y)]);
+ }
+ }
+
+ return used_punchthrough;
+ }
+
struct bc4_block
{
enum { cBC4SelectorBits = 3, cTotalSelectorBytes = 6, cMaxSelectorValues = 8 };
@@ -292,7 +399,7 @@ namespace basisu
if (mode)
{
- c[1].set(std::max(0, c[0].r - (c[3].r >> 2)), std::max(0, c[0].g - (c[3].g >> 2)), std::max(0, c[0].b - (c[3].b >> 2)), 255);
+ c[1].set(basisu::maximum(0, c[0].r - (c[3].r >> 2)), basisu::maximum(0, c[0].g - (c[3].g >> 2)), basisu::maximum(0, c[0].b - (c[3].b >> 2)), 255);
c[2] = c[0];
c[0].set(0, 0, 0, 255);
}
@@ -317,6 +424,191 @@ namespace basisu
}
}
+ // BC7 mode 0-7 decompression.
+ // Instead of one monster routine to unpack all the BC7 modes, we're lumping the 3 subset, 2 subset, 1 subset, and dual plane modes together into simple shared routines.
+
+ static inline uint32_t bc7_dequant(uint32_t val, uint32_t pbit, uint32_t val_bits) { assert(val < (1U << val_bits)); assert(pbit < 2); assert(val_bits >= 4 && val_bits <= 8); const uint32_t total_bits = val_bits + 1; val = (val << 1) | pbit; val <<= (8 - total_bits); val |= (val >> total_bits); assert(val <= 255); return val; }
+ static inline uint32_t bc7_dequant(uint32_t val, uint32_t val_bits) { assert(val < (1U << val_bits)); assert(val_bits >= 4 && val_bits <= 8); val <<= (8 - val_bits); val |= (val >> val_bits); assert(val <= 255); return val; }
+
+ static inline uint32_t bc7_interp2(uint32_t l, uint32_t h, uint32_t w) { assert(w < 4); return (l * (64 - basist::g_bc7_weights2[w]) + h * basist::g_bc7_weights2[w] + 32) >> 6; }
+ static inline uint32_t bc7_interp3(uint32_t l, uint32_t h, uint32_t w) { assert(w < 8); return (l * (64 - basist::g_bc7_weights3[w]) + h * basist::g_bc7_weights3[w] + 32) >> 6; }
+ static inline uint32_t bc7_interp4(uint32_t l, uint32_t h, uint32_t w) { assert(w < 16); return (l * (64 - basist::g_bc7_weights4[w]) + h * basist::g_bc7_weights4[w] + 32) >> 6; }
+ static inline uint32_t bc7_interp(uint32_t l, uint32_t h, uint32_t w, uint32_t bits)
+ {
+ assert(l <= 255 && h <= 255);
+ switch (bits)
+ {
+ case 2: return bc7_interp2(l, h, w);
+ case 3: return bc7_interp3(l, h, w);
+ case 4: return bc7_interp4(l, h, w);
+ default:
+ break;
+ }
+ return 0;
+ }
+
+ bool unpack_bc7_mode0_2(uint32_t mode, const void* pBlock_bits, color_rgba* pPixels)
+ {
+ //const uint32_t SUBSETS = 3;
+ const uint32_t ENDPOINTS = 6;
+ const uint32_t COMPS = 3;
+ const uint32_t WEIGHT_BITS = (mode == 0) ? 3 : 2;
+ const uint32_t ENDPOINT_BITS = (mode == 0) ? 4 : 5;
+ const uint32_t PBITS = (mode == 0) ? 6 : 0;
+ const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS;
+
+ uint32_t bit_offset = 0;
+ const uint8_t* pBuf = static_cast<const uint8_t*>(pBlock_bits);
+
+ if (read_bits32(pBuf, bit_offset, mode + 1) != (1U << mode)) return false;
+
+ const uint32_t part = read_bits32(pBuf, bit_offset, (mode == 0) ? 4 : 6);
+
+ color_rgba endpoints[ENDPOINTS];
+ for (uint32_t c = 0; c < COMPS; c++)
+ for (uint32_t e = 0; e < ENDPOINTS; e++)
+ endpoints[e][c] = (uint8_t)read_bits32(pBuf, bit_offset, ENDPOINT_BITS);
+
+ uint32_t pbits[6];
+ for (uint32_t p = 0; p < PBITS; p++)
+ pbits[p] = read_bits32(pBuf, bit_offset, 1);
+
+ uint32_t weights[16];
+ for (uint32_t i = 0; i < 16; i++)
+ weights[i] = read_bits32(pBuf, bit_offset, ((!i) || (i == basist::g_bc7_table_anchor_index_third_subset_1[part]) || (i == basist::g_bc7_table_anchor_index_third_subset_2[part])) ? (WEIGHT_BITS - 1) : WEIGHT_BITS);
+
+ assert(bit_offset == 128);
+
+ for (uint32_t e = 0; e < ENDPOINTS; e++)
+ for (uint32_t c = 0; c < 4; c++)
+ endpoints[e][c] = (uint8_t)((c == 3) ? 255 : (PBITS ? bc7_dequant(endpoints[e][c], pbits[e], ENDPOINT_BITS) : bc7_dequant(endpoints[e][c], ENDPOINT_BITS)));
+
+ color_rgba block_colors[3][8];
+ for (uint32_t s = 0; s < 3; s++)
+ for (uint32_t i = 0; i < WEIGHT_VALS; i++)
+ {
+ for (uint32_t c = 0; c < 3; c++)
+ block_colors[s][i][c] = (uint8_t)bc7_interp(endpoints[s * 2 + 0][c], endpoints[s * 2 + 1][c], i, WEIGHT_BITS);
+ block_colors[s][i][3] = 255;
+ }
+
+ for (uint32_t i = 0; i < 16; i++)
+ pPixels[i] = block_colors[basist::g_bc7_partition3[part * 16 + i]][weights[i]];
+
+ return true;
+ }
+
+ bool unpack_bc7_mode1_3_7(uint32_t mode, const void* pBlock_bits, color_rgba* pPixels)
+ {
+ //const uint32_t SUBSETS = 2;
+ const uint32_t ENDPOINTS = 4;
+ const uint32_t COMPS = (mode == 7) ? 4 : 3;
+ const uint32_t WEIGHT_BITS = (mode == 1) ? 3 : 2;
+ const uint32_t ENDPOINT_BITS = (mode == 7) ? 5 : ((mode == 1) ? 6 : 7);
+ const uint32_t PBITS = (mode == 1) ? 2 : 4;
+ const uint32_t SHARED_PBITS = (mode == 1) ? true : false;
+ const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS;
+
+ uint32_t bit_offset = 0;
+ const uint8_t* pBuf = static_cast<const uint8_t*>(pBlock_bits);
+
+ if (read_bits32(pBuf, bit_offset, mode + 1) != (1U << mode)) return false;
+
+ const uint32_t part = read_bits32(pBuf, bit_offset, 6);
+
+ color_rgba endpoints[ENDPOINTS];
+ for (uint32_t c = 0; c < COMPS; c++)
+ for (uint32_t e = 0; e < ENDPOINTS; e++)
+ endpoints[e][c] = (uint8_t)read_bits32(pBuf, bit_offset, ENDPOINT_BITS);
+
+ uint32_t pbits[4];
+ for (uint32_t p = 0; p < PBITS; p++)
+ pbits[p] = read_bits32(pBuf, bit_offset, 1);
+
+ uint32_t weights[16];
+ for (uint32_t i = 0; i < 16; i++)
+ weights[i] = read_bits32(pBuf, bit_offset, ((!i) || (i == basist::g_bc7_table_anchor_index_second_subset[part])) ? (WEIGHT_BITS - 1) : WEIGHT_BITS);
+
+ assert(bit_offset == 128);
+
+ for (uint32_t e = 0; e < ENDPOINTS; e++)
+ for (uint32_t c = 0; c < 4; c++)
+ endpoints[e][c] = (uint8_t)((c == ((mode == 7U) ? 4U : 3U)) ? 255 : bc7_dequant(endpoints[e][c], pbits[SHARED_PBITS ? (e >> 1) : e], ENDPOINT_BITS));
+
+ color_rgba block_colors[2][8];
+ for (uint32_t s = 0; s < 2; s++)
+ for (uint32_t i = 0; i < WEIGHT_VALS; i++)
+ {
+ for (uint32_t c = 0; c < COMPS; c++)
+ block_colors[s][i][c] = (uint8_t)bc7_interp(endpoints[s * 2 + 0][c], endpoints[s * 2 + 1][c], i, WEIGHT_BITS);
+ block_colors[s][i][3] = (COMPS == 3) ? 255 : block_colors[s][i][3];
+ }
+
+ for (uint32_t i = 0; i < 16; i++)
+ pPixels[i] = block_colors[basist::g_bc7_partition2[part * 16 + i]][weights[i]];
+
+ return true;
+ }
+
+ bool unpack_bc7_mode4_5(uint32_t mode, const void* pBlock_bits, color_rgba* pPixels)
+ {
+ const uint32_t ENDPOINTS = 2;
+ const uint32_t COMPS = 4;
+ const uint32_t WEIGHT_BITS = 2;
+ const uint32_t A_WEIGHT_BITS = (mode == 4) ? 3 : 2;
+ const uint32_t ENDPOINT_BITS = (mode == 4) ? 5 : 7;
+ const uint32_t A_ENDPOINT_BITS = (mode == 4) ? 6 : 8;
+ //const uint32_t WEIGHT_VALS = 1 << WEIGHT_BITS;
+ //const uint32_t A_WEIGHT_VALS = 1 << A_WEIGHT_BITS;
+
+ uint32_t bit_offset = 0;
+ const uint8_t* pBuf = static_cast<const uint8_t*>(pBlock_bits);
+
+ if (read_bits32(pBuf, bit_offset, mode + 1) != (1U << mode)) return false;
+
+ const uint32_t comp_rot = read_bits32(pBuf, bit_offset, 2);
+ const uint32_t index_mode = (mode == 4) ? read_bits32(pBuf, bit_offset, 1) : 0;
+
+ color_rgba endpoints[ENDPOINTS];
+ for (uint32_t c = 0; c < COMPS; c++)
+ for (uint32_t e = 0; e < ENDPOINTS; e++)
+ endpoints[e][c] = (uint8_t)read_bits32(pBuf, bit_offset, (c == 3) ? A_ENDPOINT_BITS : ENDPOINT_BITS);
+
+ const uint32_t weight_bits[2] = { index_mode ? A_WEIGHT_BITS : WEIGHT_BITS, index_mode ? WEIGHT_BITS : A_WEIGHT_BITS };
+
+ uint32_t weights[16], a_weights[16];
+
+ for (uint32_t i = 0; i < 16; i++)
+ (index_mode ? a_weights : weights)[i] = read_bits32(pBuf, bit_offset, weight_bits[index_mode] - ((!i) ? 1 : 0));
+
+ for (uint32_t i = 0; i < 16; i++)
+ (index_mode ? weights : a_weights)[i] = read_bits32(pBuf, bit_offset, weight_bits[1 - index_mode] - ((!i) ? 1 : 0));
+
+ assert(bit_offset == 128);
+
+ for (uint32_t e = 0; e < ENDPOINTS; e++)
+ for (uint32_t c = 0; c < 4; c++)
+ endpoints[e][c] = (uint8_t)bc7_dequant(endpoints[e][c], (c == 3) ? A_ENDPOINT_BITS : ENDPOINT_BITS);
+
+ color_rgba block_colors[8];
+ for (uint32_t i = 0; i < (1U << weight_bits[0]); i++)
+ for (uint32_t c = 0; c < 3; c++)
+ block_colors[i][c] = (uint8_t)bc7_interp(endpoints[0][c], endpoints[1][c], i, weight_bits[0]);
+
+ for (uint32_t i = 0; i < (1U << weight_bits[1]); i++)
+ block_colors[i][3] = (uint8_t)bc7_interp(endpoints[0][3], endpoints[1][3], i, weight_bits[1]);
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ pPixels[i] = block_colors[weights[i]];
+ pPixels[i].a = block_colors[a_weights[i]].a;
+ if (comp_rot >= 1)
+ std::swap(pPixels[i].a, pPixels[i].m_comps[comp_rot - 1]);
+ }
+
+ return true;
+ }
+
struct bc7_mode_6
{
struct
@@ -364,9 +656,6 @@ namespace basisu
};
};
- static const uint32_t g_bc7_weights4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
-
- // The transcoder only outputs mode 6 at the moment, so this is easy.
bool unpack_bc7_mode6(const void *pBlock_bits, color_rgba *pPixels)
{
static_assert(sizeof(bc7_mode_6) == 16, "sizeof(bc7_mode_6) == 16");
@@ -388,7 +677,7 @@ namespace basisu
color_rgba vals[16];
for (uint32_t i = 0; i < 16; i++)
{
- const uint32_t w = g_bc7_weights4[i];
+ const uint32_t w = basist::g_bc7_weights4[i];
const uint32_t iw = 64 - w;
vals[i].set_noclamp_rgba(
(r0 * iw + r1 * w + 32) >> 6,
@@ -420,183 +709,37 @@ namespace basisu
return true;
}
- static inline uint32_t get_block_bits(const uint8_t* pBytes, uint32_t bit_ofs, uint32_t bits_wanted)
+ bool unpack_bc7(const void *pBlock, color_rgba *pPixels)
{
- assert(bits_wanted < 32);
+ const uint32_t first_byte = static_cast<const uint8_t*>(pBlock)[0];
- uint32_t v = 0;
- uint32_t total_bits = 0;
-
- while (total_bits < bits_wanted)
+ for (uint32_t mode = 0; mode <= 7; mode++)
{
- uint32_t k = pBytes[bit_ofs >> 3];
- k >>= (bit_ofs & 7);
- uint32_t num_bits_in_byte = 8 - (bit_ofs & 7);
-
- v |= (k << total_bits);
- total_bits += num_bits_in_byte;
- bit_ofs += num_bits_in_byte;
- }
-
- return v & ((1 << bits_wanted) - 1);
- }
-
- struct bc7_mode_5
- {
- union
- {
- struct
+ if (first_byte & (1U << mode))
{
- uint64_t m_mode : 6;
- uint64_t m_rot : 2;
-
- uint64_t m_r0 : 7;
- uint64_t m_r1 : 7;
- uint64_t m_g0 : 7;
- uint64_t m_g1 : 7;
- uint64_t m_b0 : 7;
- uint64_t m_b1 : 7;
- uint64_t m_a0 : 8;
- uint64_t m_a1_0 : 6;
-
- } m_lo;
-
- uint64_t m_lo_bits;
- };
-
- union
- {
- struct
- {
- uint64_t m_a1_1 : 2;
-
- // bit 2
- uint64_t m_c00 : 1;
- uint64_t m_c10 : 2;
- uint64_t m_c20 : 2;
- uint64_t m_c30 : 2;
-
- uint64_t m_c01 : 2;
- uint64_t m_c11 : 2;
- uint64_t m_c21 : 2;
- uint64_t m_c31 : 2;
-
- uint64_t m_c02 : 2;
- uint64_t m_c12 : 2;
- uint64_t m_c22 : 2;
- uint64_t m_c32 : 2;
-
- uint64_t m_c03 : 2;
- uint64_t m_c13 : 2;
- uint64_t m_c23 : 2;
- uint64_t m_c33 : 2;
-
- // bit 33
- uint64_t m_a00 : 1;
- uint64_t m_a10 : 2;
- uint64_t m_a20 : 2;
- uint64_t m_a30 : 2;
-
- uint64_t m_a01 : 2;
- uint64_t m_a11 : 2;
- uint64_t m_a21 : 2;
- uint64_t m_a31 : 2;
-
- uint64_t m_a02 : 2;
- uint64_t m_a12 : 2;
- uint64_t m_a22 : 2;
- uint64_t m_a32 : 2;
-
- uint64_t m_a03 : 2;
- uint64_t m_a13 : 2;
- uint64_t m_a23 : 2;
- uint64_t m_a33 : 2;
-
- } m_hi;
-
- uint64_t m_hi_bits;
- };
-
- color_rgba get_low_color() const
- {
- return color_rgba(cNoClamp,
- (int)((m_lo.m_r0 << 1) | (m_lo.m_r0 >> 6)),
- (int)((m_lo.m_g0 << 1) | (m_lo.m_g0 >> 6)),
- (int)((m_lo.m_b0 << 1) | (m_lo.m_b0 >> 6)),
- m_lo.m_a0);
- }
-
- color_rgba get_high_color() const
- {
- return color_rgba(cNoClamp,
- (int)((m_lo.m_r1 << 1) | (m_lo.m_r1 >> 6)),
- (int)((m_lo.m_g1 << 1) | (m_lo.m_g1 >> 6)),
- (int)((m_lo.m_b1 << 1) | (m_lo.m_b1 >> 6)),
- (int)m_lo.m_a1_0 | ((int)m_hi.m_a1_1 << 6));
- }
-
- void get_block_colors(color_rgba* pColors) const
- {
- const color_rgba low_color(get_low_color());
- const color_rgba high_color(get_high_color());
-
- for (uint32_t i = 0; i < 4; i++)
- {
- static const uint32_t s_bc7_weights2[4] = { 0, 21, 43, 64 };
-
- pColors[i].set_noclamp_rgba(
- (low_color.r * (64 - s_bc7_weights2[i]) + high_color.r * s_bc7_weights2[i] + 32) >> 6,
- (low_color.g * (64 - s_bc7_weights2[i]) + high_color.g * s_bc7_weights2[i] + 32) >> 6,
- (low_color.b * (64 - s_bc7_weights2[i]) + high_color.b * s_bc7_weights2[i] + 32) >> 6,
- (low_color.a * (64 - s_bc7_weights2[i]) + high_color.a * s_bc7_weights2[i] + 32) >> 6);
+ switch (mode)
+ {
+ case 0:
+ case 2:
+ return unpack_bc7_mode0_2(mode, pBlock, pPixels);
+ case 1:
+ case 3:
+ case 7:
+ return unpack_bc7_mode1_3_7(mode, pBlock, pPixels);
+ case 4:
+ case 5:
+ return unpack_bc7_mode4_5(mode, pBlock, pPixels);
+ case 6:
+ return unpack_bc7_mode6(pBlock, pPixels);
+ default:
+ break;
+ }
}
- }
-
- uint32_t get_selector(uint32_t idx, bool alpha) const
- {
- const uint32_t size = (idx == 0) ? 1 : 2;
-
- uint32_t ofs = alpha ? 97 : 66;
-
- if (idx)
- ofs += 1 + 2 * (idx - 1);
-
- return get_block_bits(reinterpret_cast<const uint8_t*>(this), ofs, size);
- }
- };
-
- bool unpack_bc7_mode5(const void* pBlock_bits, color_rgba* pPixels)
- {
- static_assert(sizeof(bc7_mode_5) == 16, "sizeof(bc7_mode_5) == 16");
-
- const bc7_mode_5& block = *static_cast<const bc7_mode_5*>(pBlock_bits);
-
- if (block.m_lo.m_mode != (1 << 5))
- return false;
-
- color_rgba block_colors[4];
- block.get_block_colors(block_colors);
-
- const uint32_t rot = block.m_lo.m_rot;
-
- for (uint32_t i = 0; i < 16; i++)
- {
- const uint32_t cs = block.get_selector(i, false);
-
- color_rgba c(block_colors[cs]);
-
- const uint32_t as = block.get_selector(i, true);
- c.a = block_colors[as].a;
-
- if (rot > 0)
- std::swap(c[3], c[rot - 1]);
-
- pPixels[i] = c;
}
- return true;
+ return false;
}
-
+
struct fxt1_block
{
union
@@ -903,13 +1046,14 @@ namespace basisu
etc2_eac_r11 m_c[2];
};
- static void unpack_etc2_eac_r(const etc2_eac_r11* p, color_rgba* pPixels, uint32_t c)
+ void unpack_etc2_eac_r(const void *p, color_rgba* pPixels, uint32_t c)
{
- const uint64_t sels = p->get_sels();
+ const etc2_eac_r11* pBlock = static_cast<const etc2_eac_r11*>(p);
+ const uint64_t sels = pBlock->get_sels();
- const int base = (int)p->m_base * 8 + 4;
- const int mul = p->m_mul ? ((int)p->m_mul * 8) : 1;
- const int table = (int)p->m_table;
+ const int base = (int)pBlock->m_base * 8 + 4;
+ const int mul = pBlock->m_mul ? ((int)pBlock->m_mul * 8) : 1;
+ const int table = (int)pBlock->m_table;
for (uint32_t y = 0; y < 4; y++)
{
@@ -923,7 +1067,8 @@ namespace basisu
val = clamp<int>(val, 0, 2047);
// Convert to 8-bits with rounding
- pPixels[x + y * 4].m_comps[c] = static_cast<uint8_t>((val * 255 + 1024) / 2047);
+ //pPixels[x + y * 4].m_comps[c] = static_cast<uint8_t>((val * 255 + 1024) / 2047);
+ pPixels[x + y * 4].m_comps[c] = static_cast<uint8_t>((val * 255 + 1023) / 2047);
} // x
} // y
@@ -939,6 +1084,11 @@ namespace basisu
}
}
+ void unpack_uastc(const void* p, color_rgba* pPixels)
+ {
+ basist::unpack_uastc(*static_cast<const basist::uastc_block*>(p), (basist::color32 *)pPixels, false);
+ }
+
// Unpacks to RGBA, R, RG, or A
bool unpack_block(texture_format fmt, const void* pBlock, color_rgba* pPixels)
{
@@ -949,6 +1099,16 @@ namespace basisu
unpack_bc1(pBlock, pPixels, true);
break;
}
+ case texture_format::cBC1_NV:
+ {
+ unpack_bc1_nv(pBlock, pPixels, true);
+ break;
+ }
+ case texture_format::cBC1_AMD:
+ {
+ unpack_bc1_amd(pBlock, pPixels, true);
+ break;
+ }
case texture_format::cBC3:
{
return unpack_bc3(pBlock, pPixels);
@@ -966,14 +1126,7 @@ namespace basisu
}
case texture_format::cBC7:
{
- // We only support modes 5 and 6.
- if (!unpack_bc7_mode5(pBlock, pPixels))
- {
- if (!unpack_bc7_mode6(pBlock, pPixels))
- return false;
- }
-
- break;
+ return unpack_bc7(pBlock, pPixels);
}
// Full ETC2 color blocks (planar/T/H modes) is currently unsupported in basisu, but we do support ETC2 with alpha (using ETC1 for color)
case texture_format::cETC2_RGB:
@@ -1032,6 +1185,11 @@ namespace basisu
unpack_etc2_eac_rg(pBlock, pPixels);
break;
}
+ case texture_format::cUASTC4x4:
+ {
+ unpack_uastc(pBlock, pPixels);
+ break;
+ }
default:
{
assert(0);
@@ -1113,6 +1271,7 @@ namespace basisu
KTX_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02,
KTX_COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0,
KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0,
+ KTX_COMPRESSED_RGBA_UASTC_4x4_KHR = 0x94CC, // TODO - Use proper value!
KTX_ATC_RGB_AMD = 0x8C92,
KTX_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE,
KTX_COMPRESSED_RGB_FXT1_3DFX = 0x86B0,
@@ -1143,7 +1302,7 @@ namespace basisu
};
// Input is a texture array of mipmapped gpu_image's: gpu_images[array_index][level_index]
- bool create_ktx_texture_file(uint8_vec &ktx_data, const std::vector<gpu_image_vec>& gpu_images, bool cubemap_flag)
+ bool create_ktx_texture_file(uint8_vec &ktx_data, const basisu::vector<gpu_image_vec>& gpu_images, bool cubemap_flag)
{
if (!gpu_images.size())
{
@@ -1220,6 +1379,8 @@ namespace basisu
switch (fmt)
{
case texture_format::cBC1:
+ case texture_format::cBC1_NV:
+ case texture_format::cBC1_AMD:
{
internal_fmt = KTX_COMPRESSED_RGB_S3TC_DXT1_EXT;
break;
@@ -1305,6 +1466,12 @@ namespace basisu
base_internal_fmt = KTX_RG;
break;
}
+ case texture_format::cUASTC4x4:
+ {
+ internal_fmt = KTX_COMPRESSED_RGBA_UASTC_4x4_KHR;
+ base_internal_fmt = KTX_RGBA;
+ break;
+ }
case texture_format::cFXT1_RGB:
{
internal_fmt = KTX_COMPRESSED_RGB_FXT1_3DFX;
@@ -1378,7 +1545,7 @@ namespace basisu
return true;
}
- bool write_compressed_texture_file(const char* pFilename, const std::vector<gpu_image_vec>& g, bool cubemap_flag)
+ bool write_compressed_texture_file(const char* pFilename, const basisu::vector<gpu_image_vec>& g, bool cubemap_flag)
{
std::string extension(string_tolower(string_get_extension(pFilename)));
@@ -1410,12 +1577,12 @@ namespace basisu
bool write_compressed_texture_file(const char* pFilename, const gpu_image& g)
{
- std::vector<gpu_image_vec> v;
+ basisu::vector<gpu_image_vec> v;
enlarge_vector(v, 1)->push_back(g);
return write_compressed_texture_file(pFilename, v, false);
}
- const uint32_t OUT_FILE_MAGIC = 'TEXC';
+ //const uint32_t OUT_FILE_MAGIC = 'TEXC';
struct out_file_header
{
packed_uint<4> m_magic;
@@ -1428,7 +1595,11 @@ namespace basisu
bool write_3dfx_out_file(const char* pFilename, const gpu_image& gi)
{
out_file_header hdr;
- hdr.m_magic = OUT_FILE_MAGIC;
+ //hdr.m_magic = OUT_FILE_MAGIC;
+ hdr.m_magic.m_bytes[0] = 67;
+ hdr.m_magic.m_bytes[1] = 88;
+ hdr.m_magic.m_bytes[2] = 69;
+ hdr.m_magic.m_bytes[3] = 84;
hdr.m_pad = 0;
hdr.m_width = gi.get_blocks_x() * 8;
hdr.m_height = gi.get_blocks_y() * 4;
diff --git a/thirdparty/basis_universal/basisu_gpu_texture.h b/thirdparty/basis_universal/encoder/basisu_gpu_texture.h
index 8a49757ca7..619926f5f9 100644
--- a/thirdparty/basis_universal/basisu_gpu_texture.h
+++ b/thirdparty/basis_universal/encoder/basisu_gpu_texture.h
@@ -1,5 +1,5 @@
// basisu_gpu_texture.h
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,13 +13,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
-#include "transcoder/basisu.h"
+#include "../transcoder/basisu.h"
#include "basisu_etc.h"
namespace basisu
{
- // GPU texture image
-
+ // GPU texture "image"
class gpu_image
{
public:
@@ -115,17 +114,17 @@ namespace basisu
uint64_vec m_blocks;
};
- typedef std::vector<gpu_image> gpu_image_vec;
+ typedef basisu::vector<gpu_image> gpu_image_vec;
// KTX file writing
- bool create_ktx_texture_file(uint8_vec &ktx_data, const std::vector<gpu_image_vec>& gpu_images, bool cubemap_flag);
+ bool create_ktx_texture_file(uint8_vec &ktx_data, const basisu::vector<gpu_image_vec>& gpu_images, bool cubemap_flag);
- bool write_compressed_texture_file(const char *pFilename, const std::vector<gpu_image_vec>& g, bool cubemap_flag);
+ bool write_compressed_texture_file(const char *pFilename, const basisu::vector<gpu_image_vec>& g, bool cubemap_flag);
inline bool write_compressed_texture_file(const char *pFilename, const gpu_image_vec &g)
{
- std::vector<gpu_image_vec> a;
+ basisu::vector<gpu_image_vec> a;
a.push_back(g);
return write_compressed_texture_file(pFilename, a, false);
}
@@ -133,22 +132,23 @@ namespace basisu
bool write_compressed_texture_file(const char *pFilename, const gpu_image &g);
bool write_3dfx_out_file(const char* pFilename, const gpu_image& gi);
- // GPU texture block unpacking
+ // GPU texture block unpacking
void unpack_etc2_eac(const void *pBlock_bits, color_rgba *pPixels);
bool unpack_bc1(const void *pBlock_bits, color_rgba *pPixels, bool set_alpha);
void unpack_bc4(const void *pBlock_bits, uint8_t *pPixels, uint32_t stride);
bool unpack_bc3(const void *pBlock_bits, color_rgba *pPixels);
void unpack_bc5(const void *pBlock_bits, color_rgba *pPixels);
bool unpack_bc7_mode6(const void *pBlock_bits, color_rgba *pPixels);
- bool unpack_bc7_mode5(const void* pBlock_bits, color_rgba* pPixels);
+ bool unpack_bc7(const void* pBlock_bits, color_rgba* pPixels);
void unpack_atc(const void* pBlock_bits, color_rgba* pPixels);
bool unpack_fxt1(const void* p, color_rgba* pPixels);
bool unpack_pvrtc2(const void* p, color_rgba* pPixels);
+ void unpack_etc2_eac_r(const void *p, color_rgba* pPixels, uint32_t c);
void unpack_etc2_eac_rg(const void* p, color_rgba* pPixels);
- // unpack_block() is only capable of unpacking texture data created by the transcoder.
- // For some texture formats (like BC7, or ETC2) it's not a complete implementation.
+ // unpack_block() is primarily intended to unpack texture data created by the transcoder.
+ // For some texture formats (like ETC2 RGB, PVRTC2, FXT1) it's not a complete implementation.
bool unpack_block(texture_format fmt, const void *pBlock, color_rgba *pPixels);
} // namespace basisu
diff --git a/thirdparty/basis_universal/encoder/basisu_kernels_declares.h b/thirdparty/basis_universal/encoder/basisu_kernels_declares.h
new file mode 100644
index 0000000000..e24bdd7978
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_kernels_declares.h
@@ -0,0 +1,25 @@
+// basisu_kernels_declares.h
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#if BASISU_SUPPORT_SSE
+void CPPSPMD_NAME(perceptual_distance_rgb_4_N)(int64_t* pDistance, const uint8_t* pSelectors, const basisu::color_rgba* pBlock_colors, const basisu::color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err);
+void CPPSPMD_NAME(linear_distance_rgb_4_N)(int64_t* pDistance, const uint8_t* pSelectors, const basisu::color_rgba* pBlock_colors, const basisu::color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err);
+
+void CPPSPMD_NAME(find_selectors_perceptual_rgb_4_N)(int64_t* pDistance, uint8_t* pSelectors, const basisu::color_rgba* pBlock_colors, const basisu::color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err);
+void CPPSPMD_NAME(find_selectors_linear_rgb_4_N)(int64_t* pDistance, uint8_t* pSelectors, const basisu::color_rgba* pBlock_colors, const basisu::color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err);
+
+void CPPSPMD_NAME(find_lowest_error_perceptual_rgb_4_N)(int64_t* pDistance, const basisu::color_rgba* pBlock_colors, const basisu::color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_error);
+void CPPSPMD_NAME(find_lowest_error_linear_rgb_4_N)(int64_t* pDistance, const basisu::color_rgba* pBlock_colors, const basisu::color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_error);
+#endif
diff --git a/thirdparty/basis_universal/encoder/basisu_kernels_imp.h b/thirdparty/basis_universal/encoder/basisu_kernels_imp.h
new file mode 100644
index 0000000000..046880517b
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_kernels_imp.h
@@ -0,0 +1,584 @@
+// basisu_kernels_imp.h - Do not directly include
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using namespace CPPSPMD;
+
+namespace CPPSPMD_NAME(basisu_kernels_namespace)
+{
+ struct perceptual_distance_rgb_4_N : spmd_kernel
+ {
+ void _call(int64_t* pDistance,
+ const uint8_t* pSelectors,
+ const color_rgba* pBlock_colors,
+ const color_rgba* pSrc_pixels, uint32_t n,
+ int64_t early_out_err)
+ {
+ assert(early_out_err >= 0);
+
+ *pDistance = 0;
+
+ __m128i block_colors[4];
+ vint block_colors_r[4], block_colors_g[4], block_colors_b[4];
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ block_colors[i] = load_rgba32(&pBlock_colors[i]);
+ store_all(block_colors_r[i], (int)pBlock_colors[i].r);
+ store_all(block_colors_g[i], (int)pBlock_colors[i].g);
+ store_all(block_colors_b[i], (int)pBlock_colors[i].b);
+ }
+
+ uint32_t i;
+ for (i = 0; (i + 4) <= n; i += 4)
+ {
+ __m128i c0 = load_rgba32(&pSrc_pixels[i + 0]), c1 = load_rgba32(&pSrc_pixels[i + 1]), c2 = load_rgba32(&pSrc_pixels[i + 2]), c3 = load_rgba32(&pSrc_pixels[i + 3]);
+
+ vint r, g, b, a;
+ transpose4x4(r.m_value, g.m_value, b.m_value, a.m_value, c0, c1, c2, c3);
+
+ int s0 = pSelectors[i], s1 = pSelectors[i + 1], s2 = pSelectors[i + 2], s3 = pSelectors[i + 3];
+
+ vint base_r, base_g, base_b, base_a;
+ if ((s0 == s1) && (s0 == s2) && (s0 == s3))
+ {
+ store_all(base_r, block_colors_r[s0]);
+ store_all(base_g, block_colors_g[s0]);
+ store_all(base_b, block_colors_b[s0]);
+ }
+ else
+ {
+ __m128i k0 = block_colors[s0], k1 = block_colors[s1], k2 = block_colors[s2], k3 = block_colors[s3];
+ transpose4x4(base_r.m_value, base_g.m_value, base_b.m_value, base_a.m_value, k0, k1, k2, k3);
+ }
+
+ vint dr = base_r - r;
+ vint dg = base_g - g;
+ vint db = base_b - b;
+
+ vint delta_l = dr * 27 + dg * 92 + db * 9;
+ vint delta_cr = dr * 128 - delta_l;
+ vint delta_cb = db * 128 - delta_l;
+
+ vint id = ((delta_l * delta_l) >> 7) +
+ ((((delta_cr * delta_cr) >> 7) * 26) >> 7) +
+ ((((delta_cb * delta_cb) >> 7) * 3) >> 7);
+
+ *pDistance += reduce_add(id);
+ if (*pDistance >= early_out_err)
+ return;
+ }
+
+ for (; i < n; i++)
+ {
+ int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
+
+ int sel = pSelectors[i];
+ int base_r = pBlock_colors[sel].r, base_g = pBlock_colors[sel].g, base_b = pBlock_colors[sel].b;
+
+ int dr = base_r - r;
+ int dg = base_g - g;
+ int db = base_b - b;
+
+ int delta_l = dr * 27 + dg * 92 + db * 9;
+ int delta_cr = dr * 128 - delta_l;
+ int delta_cb = db * 128 - delta_l;
+
+ int id = ((delta_l * delta_l) >> 7) +
+ ((((delta_cr * delta_cr) >> 7) * 26) >> 7) +
+ ((((delta_cb * delta_cb) >> 7) * 3) >> 7);
+
+ *pDistance += id;
+ if (*pDistance >= early_out_err)
+ return;
+ }
+ }
+ };
+
+ struct linear_distance_rgb_4_N : spmd_kernel
+ {
+ void _call(int64_t* pDistance,
+ const uint8_t* pSelectors,
+ const color_rgba* pBlock_colors,
+ const color_rgba* pSrc_pixels, uint32_t n,
+ int64_t early_out_err)
+ {
+ assert(early_out_err >= 0);
+
+ *pDistance = 0;
+
+ __m128i block_colors[4];
+ vint block_colors_r[4], block_colors_g[4], block_colors_b[4];
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ block_colors[i] = load_rgba32(&pBlock_colors[i]);
+ store_all(block_colors_r[i], (int)pBlock_colors[i].r);
+ store_all(block_colors_g[i], (int)pBlock_colors[i].g);
+ store_all(block_colors_b[i], (int)pBlock_colors[i].b);
+ }
+
+ uint32_t i;
+ for (i = 0; (i + 4) <= n; i += 4)
+ {
+ __m128i c0 = load_rgba32(&pSrc_pixels[i + 0]), c1 = load_rgba32(&pSrc_pixels[i + 1]), c2 = load_rgba32(&pSrc_pixels[i + 2]), c3 = load_rgba32(&pSrc_pixels[i + 3]);
+
+ vint r, g, b, a;
+ transpose4x4(r.m_value, g.m_value, b.m_value, a.m_value, c0, c1, c2, c3);
+
+ int s0 = pSelectors[i], s1 = pSelectors[i + 1], s2 = pSelectors[i + 2], s3 = pSelectors[i + 3];
+
+ vint base_r, base_g, base_b, base_a;
+ if ((s0 == s1) && (s0 == s2) && (s0 == s3))
+ {
+ store_all(base_r, block_colors_r[s0]);
+ store_all(base_g, block_colors_g[s0]);
+ store_all(base_b, block_colors_b[s0]);
+ }
+ else
+ {
+ __m128i k0 = block_colors[s0], k1 = block_colors[s1], k2 = block_colors[s2], k3 = block_colors[s3];
+ transpose4x4(base_r.m_value, base_g.m_value, base_b.m_value, base_a.m_value, k0, k1, k2, k3);
+ }
+
+ vint dr = base_r - r;
+ vint dg = base_g - g;
+ vint db = base_b - b;
+
+ vint id = dr * dr + dg * dg + db * db;
+
+ *pDistance += reduce_add(id);
+ if (*pDistance >= early_out_err)
+ return;
+ }
+
+ for (; i < n; i++)
+ {
+ int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
+
+ int sel = pSelectors[i];
+ int base_r = pBlock_colors[sel].r, base_g = pBlock_colors[sel].g, base_b = pBlock_colors[sel].b;
+
+ int dr = base_r - r;
+ int dg = base_g - g;
+ int db = base_b - b;
+
+ int id = dr * dr + dg * dg + db * db;
+
+ *pDistance += id;
+ if (*pDistance >= early_out_err)
+ return;
+ }
+ }
+ };
+
+ struct find_selectors_perceptual_rgb_4_N : spmd_kernel
+ {
+ inline vint compute_dist(
+ const vint& base_r, const vint& base_g, const vint& base_b,
+ const vint& r, const vint& g, const vint& b)
+ {
+ vint dr = base_r - r;
+ vint dg = base_g - g;
+ vint db = base_b - b;
+
+ vint delta_l = dr * 27 + dg * 92 + db * 9;
+ vint delta_cr = dr * 128 - delta_l;
+ vint delta_cb = db * 128 - delta_l;
+
+ vint id = VINT_SHIFT_RIGHT(delta_l * delta_l, 7) +
+ VINT_SHIFT_RIGHT(VINT_SHIFT_RIGHT(delta_cr * delta_cr, 7) * 26, 7) +
+ VINT_SHIFT_RIGHT(VINT_SHIFT_RIGHT(delta_cb * delta_cb, 7) * 3, 7);
+
+ return id;
+ }
+
+ void _call(int64_t* pDistance,
+ uint8_t* pSelectors,
+ const color_rgba* pBlock_colors,
+ const color_rgba* pSrc_pixels, uint32_t n,
+ int64_t early_out_err)
+ {
+ assert(early_out_err >= 0);
+
+ *pDistance = 0;
+
+ vint block_colors_r[4], block_colors_g[4], block_colors_b[4];
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ store_all(block_colors_r[i], (int)pBlock_colors[i].r);
+ store_all(block_colors_g[i], (int)pBlock_colors[i].g);
+ store_all(block_colors_b[i], (int)pBlock_colors[i].b);
+ }
+
+ const __m128i shuf = _mm_set_epi8(-128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, 12, 8, 4, 0);
+
+ uint32_t i;
+
+ for (i = 0; (i + 4) <= n; i += 4)
+ {
+ __m128i c0 = load_rgba32(&pSrc_pixels[i + 0]), c1 = load_rgba32(&pSrc_pixels[i + 1]), c2 = load_rgba32(&pSrc_pixels[i + 2]), c3 = load_rgba32(&pSrc_pixels[i + 3]);
+
+ vint r, g, b, a;
+ transpose4x4(r.m_value, g.m_value, b.m_value, a.m_value, c0, c1, c2, c3);
+
+ vint dist0 = compute_dist(block_colors_r[0], block_colors_g[0], block_colors_b[0], r, g, b);
+ vint dist1 = compute_dist(block_colors_r[1], block_colors_g[1], block_colors_b[1], r, g, b);
+ vint dist2 = compute_dist(block_colors_r[2], block_colors_g[2], block_colors_b[2], r, g, b);
+ vint dist3 = compute_dist(block_colors_r[3], block_colors_g[3], block_colors_b[3], r, g, b);
+
+ vint min_dist = min(min(min(dist0, dist1), dist2), dist3);
+
+ vint sels = spmd_ternaryi(min_dist == dist0, 0, spmd_ternaryi(min_dist == dist1, 1, spmd_ternaryi(min_dist == dist2, 2, 3)));
+
+ __m128i vsels = shuffle_epi8(sels.m_value, shuf);
+ storeu_si32((void *)(pSelectors + i), vsels);
+
+ *pDistance += reduce_add(min_dist);
+ if (*pDistance >= early_out_err)
+ return;
+ }
+
+ for (; i < n; i++)
+ {
+ int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
+
+ int best_err = INT_MAX, best_sel = 0;
+ for (int sel = 0; sel < 4; sel++)
+ {
+ int base_r = pBlock_colors[sel].r, base_g = pBlock_colors[sel].g, base_b = pBlock_colors[sel].b;
+
+ int dr = base_r - r;
+ int dg = base_g - g;
+ int db = base_b - b;
+
+ int delta_l = dr * 27 + dg * 92 + db * 9;
+ int delta_cr = dr * 128 - delta_l;
+ int delta_cb = db * 128 - delta_l;
+
+ int id = ((delta_l * delta_l) >> 7) +
+ ((((delta_cr * delta_cr) >> 7) * 26) >> 7) +
+ ((((delta_cb * delta_cb) >> 7) * 3) >> 7);
+ if (id < best_err)
+ {
+ best_err = id;
+ best_sel = sel;
+ }
+ }
+
+ pSelectors[i] = (uint8_t)best_sel;
+
+ *pDistance += best_err;
+ if (*pDistance >= early_out_err)
+ return;
+ }
+ }
+ };
+
+ struct find_selectors_linear_rgb_4_N : spmd_kernel
+ {
+ inline vint compute_dist(
+ const vint& base_r, const vint& base_g, const vint& base_b,
+ const vint& r, const vint& g, const vint& b)
+ {
+ vint dr = base_r - r;
+ vint dg = base_g - g;
+ vint db = base_b - b;
+
+ vint id = dr * dr + dg * dg + db * db;
+ return id;
+ }
+
+ void _call(int64_t* pDistance,
+ uint8_t* pSelectors,
+ const color_rgba* pBlock_colors,
+ const color_rgba* pSrc_pixels, uint32_t n,
+ int64_t early_out_err)
+ {
+ assert(early_out_err >= 0);
+
+ *pDistance = 0;
+
+ vint block_colors_r[4], block_colors_g[4], block_colors_b[4];
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ store_all(block_colors_r[i], (int)pBlock_colors[i].r);
+ store_all(block_colors_g[i], (int)pBlock_colors[i].g);
+ store_all(block_colors_b[i], (int)pBlock_colors[i].b);
+ }
+
+ const __m128i shuf = _mm_set_epi8(-128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, 12, 8, 4, 0);
+
+ uint32_t i;
+
+ for (i = 0; (i + 4) <= n; i += 4)
+ {
+ __m128i c0 = load_rgba32(&pSrc_pixels[i + 0]), c1 = load_rgba32(&pSrc_pixels[i + 1]), c2 = load_rgba32(&pSrc_pixels[i + 2]), c3 = load_rgba32(&pSrc_pixels[i + 3]);
+
+ vint r, g, b, a;
+ transpose4x4(r.m_value, g.m_value, b.m_value, a.m_value, c0, c1, c2, c3);
+
+ vint dist0 = compute_dist(block_colors_r[0], block_colors_g[0], block_colors_b[0], r, g, b);
+ vint dist1 = compute_dist(block_colors_r[1], block_colors_g[1], block_colors_b[1], r, g, b);
+ vint dist2 = compute_dist(block_colors_r[2], block_colors_g[2], block_colors_b[2], r, g, b);
+ vint dist3 = compute_dist(block_colors_r[3], block_colors_g[3], block_colors_b[3], r, g, b);
+
+ vint min_dist = min(min(min(dist0, dist1), dist2), dist3);
+
+ vint sels = spmd_ternaryi(min_dist == dist0, 0, spmd_ternaryi(min_dist == dist1, 1, spmd_ternaryi(min_dist == dist2, 2, 3)));
+
+ __m128i vsels = shuffle_epi8(sels.m_value, shuf);
+ storeu_si32((void *)(pSelectors + i), vsels);
+
+ *pDistance += reduce_add(min_dist);
+ if (*pDistance >= early_out_err)
+ return;
+ }
+
+ for (; i < n; i++)
+ {
+ int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
+
+ int best_err = INT_MAX, best_sel = 0;
+ for (int sel = 0; sel < 4; sel++)
+ {
+ int base_r = pBlock_colors[sel].r, base_g = pBlock_colors[sel].g, base_b = pBlock_colors[sel].b;
+
+ int dr = base_r - r;
+ int dg = base_g - g;
+ int db = base_b - b;
+
+ int id = dr * dr + dg * dg + db * db;
+ if (id < best_err)
+ {
+ best_err = id;
+ best_sel = sel;
+ }
+ }
+
+ pSelectors[i] = (uint8_t)best_sel;
+
+ *pDistance += best_err;
+ if (*pDistance >= early_out_err)
+ return;
+ }
+ }
+ };
+
+ struct find_lowest_error_perceptual_rgb_4_N : spmd_kernel
+ {
+ inline vint compute_dist(
+ const vint& base_r, const vint& base_g, const vint& base_b,
+ const vint& r, const vint& g, const vint& b)
+ {
+ vint dr = base_r - r;
+ vint dg = base_g - g;
+ vint db = base_b - b;
+
+ vint delta_l = dr * 27 + dg * 92 + db * 9;
+ vint delta_cr = dr * 128 - delta_l;
+ vint delta_cb = db * 128 - delta_l;
+
+ vint id = VINT_SHIFT_RIGHT(delta_l * delta_l, 7) +
+ VINT_SHIFT_RIGHT(VINT_SHIFT_RIGHT(delta_cr * delta_cr, 7) * 26, 7) +
+ VINT_SHIFT_RIGHT(VINT_SHIFT_RIGHT(delta_cb * delta_cb, 7) * 3, 7);
+
+ return id;
+ }
+
+ void _call(int64_t* pDistance,
+ const color_rgba* pBlock_colors,
+ const color_rgba* pSrc_pixels, uint32_t n,
+ int64_t early_out_error)
+ {
+ assert(early_out_error >= 0);
+
+ *pDistance = 0;
+
+ vint block_colors_r[4], block_colors_g[4], block_colors_b[4];
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ store_all(block_colors_r[i], (int)pBlock_colors[i].r);
+ store_all(block_colors_g[i], (int)pBlock_colors[i].g);
+ store_all(block_colors_b[i], (int)pBlock_colors[i].b);
+ }
+
+ uint32_t i;
+
+ for (i = 0; (i + 4) <= n; i += 4)
+ {
+ __m128i c0 = load_rgba32(&pSrc_pixels[i + 0]), c1 = load_rgba32(&pSrc_pixels[i + 1]), c2 = load_rgba32(&pSrc_pixels[i + 2]), c3 = load_rgba32(&pSrc_pixels[i + 3]);
+
+ vint r, g, b, a;
+ transpose4x4(r.m_value, g.m_value, b.m_value, a.m_value, c0, c1, c2, c3);
+
+ vint dist0 = compute_dist(block_colors_r[0], block_colors_g[0], block_colors_b[0], r, g, b);
+ vint dist1 = compute_dist(block_colors_r[1], block_colors_g[1], block_colors_b[1], r, g, b);
+ vint dist2 = compute_dist(block_colors_r[2], block_colors_g[2], block_colors_b[2], r, g, b);
+ vint dist3 = compute_dist(block_colors_r[3], block_colors_g[3], block_colors_b[3], r, g, b);
+
+ vint min_dist = min(min(min(dist0, dist1), dist2), dist3);
+
+ *pDistance += reduce_add(min_dist);
+ if (*pDistance > early_out_error)
+ return;
+ }
+
+ for (; i < n; i++)
+ {
+ int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
+
+ int best_err = INT_MAX;
+ for (int sel = 0; sel < 4; sel++)
+ {
+ int base_r = pBlock_colors[sel].r, base_g = pBlock_colors[sel].g, base_b = pBlock_colors[sel].b;
+
+ int dr = base_r - r;
+ int dg = base_g - g;
+ int db = base_b - b;
+
+ int delta_l = dr * 27 + dg * 92 + db * 9;
+ int delta_cr = dr * 128 - delta_l;
+ int delta_cb = db * 128 - delta_l;
+
+ int id = ((delta_l * delta_l) >> 7) +
+ ((((delta_cr * delta_cr) >> 7) * 26) >> 7) +
+ ((((delta_cb * delta_cb) >> 7) * 3) >> 7);
+
+ if (id < best_err)
+ {
+ best_err = id;
+ }
+ }
+
+ *pDistance += best_err;
+ if (*pDistance > early_out_error)
+ return;
+ }
+ }
+ };
+
+ struct find_lowest_error_linear_rgb_4_N : spmd_kernel
+ {
+ inline vint compute_dist(
+ const vint& base_r, const vint& base_g, const vint& base_b,
+ const vint& r, const vint& g, const vint& b)
+ {
+ vint dr = base_r - r;
+ vint dg = base_g - g;
+ vint db = base_b - b;
+
+ vint id = dr * dr + dg * dg + db * db;
+
+ return id;
+ }
+
+ void _call(int64_t* pDistance,
+ const color_rgba* pBlock_colors,
+ const color_rgba* pSrc_pixels, uint32_t n,
+ int64_t early_out_error)
+ {
+ assert(early_out_error >= 0);
+
+ *pDistance = 0;
+
+ vint block_colors_r[4], block_colors_g[4], block_colors_b[4];
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ store_all(block_colors_r[i], (int)pBlock_colors[i].r);
+ store_all(block_colors_g[i], (int)pBlock_colors[i].g);
+ store_all(block_colors_b[i], (int)pBlock_colors[i].b);
+ }
+
+ uint32_t i;
+
+ for (i = 0; (i + 4) <= n; i += 4)
+ {
+ __m128i c0 = load_rgba32(&pSrc_pixels[i + 0]), c1 = load_rgba32(&pSrc_pixels[i + 1]), c2 = load_rgba32(&pSrc_pixels[i + 2]), c3 = load_rgba32(&pSrc_pixels[i + 3]);
+
+ vint r, g, b, a;
+ transpose4x4(r.m_value, g.m_value, b.m_value, a.m_value, c0, c1, c2, c3);
+
+ vint dist0 = compute_dist(block_colors_r[0], block_colors_g[0], block_colors_b[0], r, g, b);
+ vint dist1 = compute_dist(block_colors_r[1], block_colors_g[1], block_colors_b[1], r, g, b);
+ vint dist2 = compute_dist(block_colors_r[2], block_colors_g[2], block_colors_b[2], r, g, b);
+ vint dist3 = compute_dist(block_colors_r[3], block_colors_g[3], block_colors_b[3], r, g, b);
+
+ vint min_dist = min(min(min(dist0, dist1), dist2), dist3);
+
+ *pDistance += reduce_add(min_dist);
+ if (*pDistance > early_out_error)
+ return;
+ }
+
+ for (; i < n; i++)
+ {
+ int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
+
+ int best_err = INT_MAX;
+ for (int sel = 0; sel < 4; sel++)
+ {
+ int base_r = pBlock_colors[sel].r, base_g = pBlock_colors[sel].g, base_b = pBlock_colors[sel].b;
+
+ int dr = base_r - r;
+ int dg = base_g - g;
+ int db = base_b - b;
+
+ int id = dr * dr + dg * dg + db * db;
+
+ if (id < best_err)
+ {
+ best_err = id;
+ }
+ }
+
+ *pDistance += best_err;
+ if (*pDistance > early_out_error)
+ return;
+ }
+ }
+ };
+
+} // namespace
+
+using namespace CPPSPMD_NAME(basisu_kernels_namespace);
+
+void CPPSPMD_NAME(perceptual_distance_rgb_4_N)(int64_t* pDistance, const uint8_t* pSelectors, const color_rgba* pBlock_colors, const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err)
+{
+ spmd_call< perceptual_distance_rgb_4_N >(pDistance, pSelectors, pBlock_colors, pSrc_pixels, n, early_out_err);
+}
+
+void CPPSPMD_NAME(linear_distance_rgb_4_N)(int64_t* pDistance, const uint8_t* pSelectors, const color_rgba* pBlock_colors, const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err)
+{
+ spmd_call< linear_distance_rgb_4_N >(pDistance, pSelectors, pBlock_colors, pSrc_pixels, n, early_out_err);
+}
+
+void CPPSPMD_NAME(find_selectors_perceptual_rgb_4_N)(int64_t *pDistance, uint8_t* pSelectors, const color_rgba* pBlock_colors, const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err)
+{
+ spmd_call< find_selectors_perceptual_rgb_4_N >(pDistance, pSelectors, pBlock_colors, pSrc_pixels, n, early_out_err);
+}
+
+void CPPSPMD_NAME(find_selectors_linear_rgb_4_N)(int64_t* pDistance, uint8_t* pSelectors, const color_rgba* pBlock_colors, const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_err)
+{
+ spmd_call< find_selectors_linear_rgb_4_N >(pDistance, pSelectors, pBlock_colors, pSrc_pixels, n, early_out_err);
+}
+
+void CPPSPMD_NAME(find_lowest_error_perceptual_rgb_4_N)(int64_t* pDistance, const color_rgba* pBlock_colors, const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_error)
+{
+ spmd_call< find_lowest_error_perceptual_rgb_4_N >(pDistance, pBlock_colors, pSrc_pixels, n, early_out_error);
+}
+
+void CPPSPMD_NAME(find_lowest_error_linear_rgb_4_N)(int64_t* pDistance, const color_rgba* pBlock_colors, const color_rgba* pSrc_pixels, uint32_t n, int64_t early_out_error)
+{
+ spmd_call< find_lowest_error_linear_rgb_4_N >(pDistance, pBlock_colors, pSrc_pixels, n, early_out_error);
+}
+
diff --git a/thirdparty/basis_universal/encoder/basisu_kernels_sse.cpp b/thirdparty/basis_universal/encoder/basisu_kernels_sse.cpp
new file mode 100644
index 0000000000..12d2321f20
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_kernels_sse.cpp
@@ -0,0 +1,161 @@
+// basisu_kernels_sse.cpp
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "basisu_enc.h"
+
+#if BASISU_SUPPORT_SSE
+
+#define CPPSPMD_SSE2 0
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+
+#if !defined(_MSC_VER)
+ #if __AVX__ || __AVX2__ || __AVX512F__
+ #error Please check your compiler options
+ #endif
+
+ #if CPPSPMD_SSE2
+ #if __SSE4_1__ || __SSE3__ || __SSE4_2__ || __SSSE3__
+ #error SSE4.1/SSE3/SSE4.2/SSSE3 cannot be enabled to use this file
+ #endif
+ #else
+ #if !__SSE4_1__ || !__SSE3__ || __SSE4_2__ || !__SSSE3__
+ #error Please check your compiler options
+ #endif
+ #endif
+#endif
+
+#include "cppspmd_sse.h"
+
+#include "cppspmd_type_aliases.h"
+
+using namespace basisu;
+
+#include "basisu_kernels_declares.h"
+#include "basisu_kernels_imp.h"
+
+namespace basisu
+{
+
+struct cpu_info
+{
+ cpu_info() { memset(this, 0, sizeof(*this)); }
+
+ bool m_has_fpu;
+ bool m_has_mmx;
+ bool m_has_sse;
+ bool m_has_sse2;
+ bool m_has_sse3;
+ bool m_has_ssse3;
+ bool m_has_sse41;
+ bool m_has_sse42;
+ bool m_has_avx;
+ bool m_has_avx2;
+ bool m_has_pclmulqdq;
+};
+
+static void extract_x86_flags(cpu_info &info, uint32_t ecx, uint32_t edx)
+{
+ info.m_has_fpu = (edx & (1 << 0)) != 0;
+ info.m_has_mmx = (edx & (1 << 23)) != 0;
+ info.m_has_sse = (edx & (1 << 25)) != 0;
+ info.m_has_sse2 = (edx & (1 << 26)) != 0;
+ info.m_has_sse3 = (ecx & (1 << 0)) != 0;
+ info.m_has_ssse3 = (ecx & (1 << 9)) != 0;
+ info.m_has_sse41 = (ecx & (1 << 19)) != 0;
+ info.m_has_sse42 = (ecx & (1 << 20)) != 0;
+ info.m_has_pclmulqdq = (ecx & (1 << 1)) != 0;
+ info.m_has_avx = (ecx & (1 << 28)) != 0;
+}
+
+static void extract_x86_extended_flags(cpu_info &info, uint32_t ebx)
+{
+ info.m_has_avx2 = (ebx & (1 << 5)) != 0;
+}
+
+#ifndef _MSC_VER
+static void do_cpuid(uint32_t eax, uint32_t ecx, uint32_t* regs)
+{
+ uint32_t ebx = 0, edx = 0;
+
+#if defined(__PIC__) && defined(__i386__)
+ __asm__("movl %%ebx, %%edi;"
+ "cpuid;"
+ "xchgl %%ebx, %%edi;"
+ : "=D"(ebx), "+a"(eax), "+c"(ecx), "=d"(edx));
+#else
+ __asm__("cpuid;" : "+b"(ebx), "+a"(eax), "+c"(ecx), "=d"(edx));
+#endif
+
+ regs[0] = eax; regs[1] = ebx; regs[2] = ecx; regs[3] = edx;
+}
+#endif
+
+static void get_cpuinfo(cpu_info &info)
+{
+ int regs[4];
+
+#ifdef _MSC_VER
+ __cpuid(regs, 0);
+#else
+ do_cpuid(0, 0, (uint32_t *)regs);
+#endif
+
+ const uint32_t max_eax = regs[0];
+
+ if (max_eax >= 1U)
+ {
+#ifdef _MSC_VER
+ __cpuid(regs, 1);
+#else
+ do_cpuid(1, 0, (uint32_t*)regs);
+#endif
+ extract_x86_flags(info, regs[2], regs[3]);
+ }
+
+ if (max_eax >= 7U)
+ {
+#ifdef _MSC_VER
+ __cpuidex(regs, 7, 0);
+#else
+ do_cpuid(7, 0, (uint32_t*)regs);
+#endif
+
+ extract_x86_extended_flags(info, regs[1]);
+ }
+}
+
+void detect_sse41()
+{
+ cpu_info info;
+ get_cpuinfo(info);
+
+ // Check for everything from SSE to SSE 4.1
+ g_cpu_supports_sse41 = info.m_has_sse && info.m_has_sse2 && info.m_has_sse3 && info.m_has_ssse3 && info.m_has_sse41;
+}
+
+} // namespace basisu
+#else // #if BASISU_SUPPORT_SSE
+namespace basisu
+{
+
+void detect_sse41()
+{
+}
+
+} // namespace basisu
+#endif // #if BASISU_SUPPORT_SSE
+
diff --git a/thirdparty/basis_universal/encoder/basisu_miniz.h b/thirdparty/basis_universal/encoder/basisu_miniz.h
new file mode 100644
index 0000000000..8627abe893
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_miniz.h
@@ -0,0 +1,2514 @@
+/* miniz.c v1.15 - deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
+ Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
+
+ Forked from the public domain/unlicense version at: https://code.google.com/archive/p/miniz/
+
+ Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef MINIZ_HEADER_INCLUDED
+#define MINIZ_HEADER_INCLUDED
+
+#include <stdlib.h>
+
+// Defines to completely disable specific portions of miniz.c:
+// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl.
+
+// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O.
+//#define MINIZ_NO_STDIO
+
+// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or
+// get/set file times, and the C run-time funcs that get/set times won't be called.
+// The current downside is the times written to your archives will be from 1979.
+//#define MINIZ_NO_TIME
+
+// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's.
+//#define MINIZ_NO_ARCHIVE_APIS
+
+// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's.
+//#define MINIZ_NO_ARCHIVE_WRITING_APIS
+
+// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's.
+//#define MINIZ_NO_ZLIB_APIS
+
+// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib.
+//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
+
+// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
+// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc
+// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user
+// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work.
+//#define MINIZ_NO_MALLOC
+
+#if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
+ // TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux
+ #define MINIZ_NO_TIME
+#endif
+
+#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
+ #include <time.h>
+#endif
+
+#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)
+// MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
+#define MINIZ_X86_OR_X64_CPU 1
+#endif
+
+#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
+// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
+#define MINIZ_LITTLE_ENDIAN 1
+#endif
+
+#if MINIZ_X86_OR_X64_CPU
+// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses.
+#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
+#endif
+
+#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__)
+// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions).
+#define MINIZ_HAS_64BIT_REGISTERS 1
+#endif
+
+namespace buminiz {
+
+// ------------------- zlib-style API Definitions.
+
+// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits!
+typedef unsigned long mz_ulong;
+
+// mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap.
+void mz_free(void *p);
+
+#define MZ_ADLER32_INIT (1)
+// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL.
+mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
+
+#define MZ_CRC32_INIT (0)
+// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL.
+mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
+
+// Compression strategies.
+enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 };
+
+// Method
+#define MZ_DEFLATED 8
+
+#ifndef MINIZ_NO_ZLIB_APIS
+
+// Heap allocation callbacks.
+// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long.
+typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
+typedef void (*mz_free_func)(void *opaque, void *address);
+typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size);
+
+#define MZ_VERSION "9.1.15"
+#define MZ_VERNUM 0x91F0
+#define MZ_VER_MAJOR 9
+#define MZ_VER_MINOR 1
+#define MZ_VER_REVISION 15
+#define MZ_VER_SUBREVISION 0
+
+// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs).
+enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 };
+
+// Return status codes. MZ_PARAM_ERROR is non-standard.
+enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 };
+
+// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL.
+enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 };
+
+// Window bits
+#define MZ_DEFAULT_WINDOW_BITS 15
+
+struct mz_internal_state;
+
+// Compression/decompression stream struct.
+typedef struct mz_stream_s
+{
+ const unsigned char *next_in; // pointer to next byte to read
+ unsigned int avail_in; // number of bytes available at next_in
+ mz_ulong total_in; // total number of bytes consumed so far
+
+ unsigned char *next_out; // pointer to next byte to write
+ unsigned int avail_out; // number of bytes that can be written to next_out
+ mz_ulong total_out; // total number of bytes produced so far
+
+ char *msg; // error msg (unused)
+ struct mz_internal_state *state; // internal state, allocated by zalloc/zfree
+
+ mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc)
+ mz_free_func zfree; // optional heap free function (defaults to free)
+ void *opaque; // heap alloc function user pointer
+
+ int data_type; // data_type (unused)
+ mz_ulong adler; // adler32 of the source or uncompressed data
+ mz_ulong reserved; // not used
+} mz_stream;
+
+typedef mz_stream *mz_streamp;
+
+// Returns the version string of miniz.c.
+const char *mz_version(void);
+
+// mz_deflateInit() initializes a compressor with default options:
+// Parameters:
+// pStream must point to an initialized mz_stream struct.
+// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION].
+// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio.
+// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.)
+// Return values:
+// MZ_OK on success.
+// MZ_STREAM_ERROR if the stream is bogus.
+// MZ_PARAM_ERROR if the input parameters are bogus.
+// MZ_MEM_ERROR on out of memory.
+int mz_deflateInit(mz_streamp pStream, int level);
+
+// mz_deflateInit2() is like mz_deflate(), except with more control:
+// Additional parameters:
+// method must be MZ_DEFLATED
+// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer)
+// mem_level must be between [1, 9] (it's checked but ignored by miniz.c)
+int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy);
+
+// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2().
+int mz_deflateReset(mz_streamp pStream);
+
+// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible.
+// Parameters:
+// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members.
+// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH.
+// Return values:
+// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full).
+// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore.
+// MZ_STREAM_ERROR if the stream is bogus.
+// MZ_PARAM_ERROR if one of the parameters is invalid.
+// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.)
+int mz_deflate(mz_streamp pStream, int flush);
+
+// mz_deflateEnd() deinitializes a compressor:
+// Return values:
+// MZ_OK on success.
+// MZ_STREAM_ERROR if the stream is bogus.
+int mz_deflateEnd(mz_streamp pStream);
+
+// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH.
+mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
+
+// Single-call compression functions mz_compress() and mz_compress2():
+// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure.
+int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
+int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level);
+
+// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress().
+mz_ulong mz_compressBound(mz_ulong source_len);
+
+// Initializes a decompressor.
+int mz_inflateInit(mz_streamp pStream);
+
+// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer:
+// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate).
+int mz_inflateInit2(mz_streamp pStream, int window_bits);
+
+// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible.
+// Parameters:
+// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members.
+// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH.
+// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster).
+// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data.
+// Return values:
+// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full.
+// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified.
+// MZ_STREAM_ERROR if the stream is bogus.
+// MZ_DATA_ERROR if the deflate stream is invalid.
+// MZ_PARAM_ERROR if one of the parameters is invalid.
+// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again
+// with more input data, or with more room in the output buffer (except when using single call decompression, described above).
+int mz_inflate(mz_streamp pStream, int flush);
+
+// Deinitializes a decompressor.
+int mz_inflateEnd(mz_streamp pStream);
+
+// Single-call decompression.
+// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure.
+int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
+
+// Returns a string description of the specified error code, or NULL if the error code is invalid.
+const char *mz_error(int err);
+
+// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports.
+// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project.
+#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
+ typedef unsigned char Byte;
+ typedef unsigned int uInt;
+ typedef mz_ulong uLong;
+ typedef Byte Bytef;
+ typedef uInt uIntf;
+ typedef char charf;
+ typedef int intf;
+ typedef void *voidpf;
+ typedef uLong uLongf;
+ typedef void *voidp;
+ typedef void *const voidpc;
+ #define Z_NULL 0
+ #define Z_NO_FLUSH MZ_NO_FLUSH
+ #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
+ #define Z_SYNC_FLUSH MZ_SYNC_FLUSH
+ #define Z_FULL_FLUSH MZ_FULL_FLUSH
+ #define Z_FINISH MZ_FINISH
+ #define Z_BLOCK MZ_BLOCK
+ #define Z_OK MZ_OK
+ #define Z_STREAM_END MZ_STREAM_END
+ #define Z_NEED_DICT MZ_NEED_DICT
+ #define Z_ERRNO MZ_ERRNO
+ #define Z_STREAM_ERROR MZ_STREAM_ERROR
+ #define Z_DATA_ERROR MZ_DATA_ERROR
+ #define Z_MEM_ERROR MZ_MEM_ERROR
+ #define Z_BUF_ERROR MZ_BUF_ERROR
+ #define Z_VERSION_ERROR MZ_VERSION_ERROR
+ #define Z_PARAM_ERROR MZ_PARAM_ERROR
+ #define Z_NO_COMPRESSION MZ_NO_COMPRESSION
+ #define Z_BEST_SPEED MZ_BEST_SPEED
+ #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
+ #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
+ #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
+ #define Z_FILTERED MZ_FILTERED
+ #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
+ #define Z_RLE MZ_RLE
+ #define Z_FIXED MZ_FIXED
+ #define Z_DEFLATED MZ_DEFLATED
+ #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
+ #define alloc_func mz_alloc_func
+ #define free_func mz_free_func
+ #define internal_state mz_internal_state
+ #define z_stream mz_stream
+ #define deflateInit mz_deflateInit
+ #define deflateInit2 mz_deflateInit2
+ #define deflateReset mz_deflateReset
+ #define deflate mz_deflate
+ #define deflateEnd mz_deflateEnd
+ #define deflateBound mz_deflateBound
+ #define compress mz_compress
+ #define compress2 mz_compress2
+ #define compressBound mz_compressBound
+ #define inflateInit mz_inflateInit
+ #define inflateInit2 mz_inflateInit2
+ #define inflate mz_inflate
+ #define inflateEnd mz_inflateEnd
+ #define uncompress mz_uncompress
+ #define crc32 mz_crc32
+ #define adler32 mz_adler32
+ #define MAX_WBITS 15
+ #define MAX_MEM_LEVEL 9
+ #define zError mz_error
+ #define ZLIB_VERSION MZ_VERSION
+ #define ZLIB_VERNUM MZ_VERNUM
+ #define ZLIB_VER_MAJOR MZ_VER_MAJOR
+ #define ZLIB_VER_MINOR MZ_VER_MINOR
+ #define ZLIB_VER_REVISION MZ_VER_REVISION
+ #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
+ #define zlibVersion mz_version
+ #define zlib_version mz_version()
+#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
+
+#endif // MINIZ_NO_ZLIB_APIS
+
+// ------------------- Types and macros
+
+typedef unsigned char mz_uint8;
+typedef signed short mz_int16;
+typedef unsigned short mz_uint16;
+typedef unsigned int mz_uint32;
+typedef unsigned int mz_uint;
+typedef long long mz_int64;
+typedef unsigned long long mz_uint64;
+typedef int mz_bool;
+
+#define MZ_FALSE (0)
+#define MZ_TRUE (1)
+
+// An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message.
+#ifdef _MSC_VER
+ #define MZ_MACRO_END while (0, 0)
+#else
+ #define MZ_MACRO_END while (0)
+#endif
+
+// ------------------- Low-level Decompression API Definitions
+
+// Decompression flags used by tinfl_decompress().
+// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream.
+// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input.
+// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB).
+// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
+enum
+{
+ TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
+ TINFL_FLAG_HAS_MORE_INPUT = 2,
+ TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
+ TINFL_FLAG_COMPUTE_ADLER32 = 8
+};
+
+// High level decompression functions:
+// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
+// On entry:
+// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
+// On return:
+// Function returns a pointer to the decompressed data, or NULL on failure.
+// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
+// The caller must call mz_free() on the returned block when it's no longer needed.
+void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
+
+// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
+// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
+#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
+size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
+
+// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
+// Returns 1 on success or 0 on failure.
+typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
+int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
+
+struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
+
+// Max size of LZ dictionary.
+#define TINFL_LZ_DICT_SIZE 32768
+
+// Return status.
+typedef enum
+{
+ TINFL_STATUS_BAD_PARAM = -3,
+ TINFL_STATUS_ADLER32_MISMATCH = -2,
+ TINFL_STATUS_FAILED = -1,
+ TINFL_STATUS_DONE = 0,
+ TINFL_STATUS_NEEDS_MORE_INPUT = 1,
+ TINFL_STATUS_HAS_MORE_OUTPUT = 2
+} tinfl_status;
+
+// Initializes the decompressor to its initial state.
+#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
+#define tinfl_get_adler32(r) (r)->m_check_adler32
+
+// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
+// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
+tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
+
+// Internal/private bits follow.
+enum
+{
+ TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
+ TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
+};
+
+typedef struct
+{
+ mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
+ mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
+} tinfl_huff_table;
+
+#if MINIZ_HAS_64BIT_REGISTERS
+ #define TINFL_USE_64BIT_BITBUF 1
+#endif
+
+#if TINFL_USE_64BIT_BITBUF
+ typedef mz_uint64 tinfl_bit_buf_t;
+ #define TINFL_BITBUF_SIZE (64)
+#else
+ typedef mz_uint32 tinfl_bit_buf_t;
+ #define TINFL_BITBUF_SIZE (32)
+#endif
+
+struct tinfl_decompressor_tag
+{
+ mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
+ tinfl_bit_buf_t m_bit_buf;
+ size_t m_dist_from_out_buf_start;
+ tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
+ mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
+};
+
+// ------------------- Low-level Compression API Definitions
+
+// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently).
+#define TDEFL_LESS_MEMORY 0
+
+// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search):
+// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression).
+enum
+{
+ TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF
+};
+
+// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data.
+// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers).
+// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing.
+// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory).
+// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1)
+// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled.
+// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables.
+// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks.
+// The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK).
+enum
+{
+ TDEFL_WRITE_ZLIB_HEADER = 0x01000,
+ TDEFL_COMPUTE_ADLER32 = 0x02000,
+ TDEFL_GREEDY_PARSING_FLAG = 0x04000,
+ TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
+ TDEFL_RLE_MATCHES = 0x10000,
+ TDEFL_FILTER_MATCHES = 0x20000,
+ TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
+ TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
+};
+
+// High level compression functions:
+// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc().
+// On entry:
+// pSrc_buf, src_buf_len: Pointer and size of source block to compress.
+// flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression.
+// On return:
+// Function returns a pointer to the compressed data, or NULL on failure.
+// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data.
+// The caller must free() the returned block when it's no longer needed.
+void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
+
+// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory.
+// Returns 0 on failure.
+size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
+
+// Compresses an image to a compressed PNG file in memory.
+// On entry:
+// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4.
+// The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory.
+// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL
+// If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps).
+// On return:
+// Function returns a pointer to the compressed data, or NULL on failure.
+// *pLen_out will be set to the size of the PNG image file.
+// The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed.
+void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip);
+void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out);
+
+// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
+typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
+
+// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally.
+mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
+
+enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 };
+
+// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes).
+#if TDEFL_LESS_MEMORY
+enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
+#else
+enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
+#endif
+
+// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions.
+typedef enum
+{
+ TDEFL_STATUS_BAD_PARAM = -2,
+ TDEFL_STATUS_PUT_BUF_FAILED = -1,
+ TDEFL_STATUS_OKAY = 0,
+ TDEFL_STATUS_DONE = 1,
+} tdefl_status;
+
+// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
+typedef enum
+{
+ TDEFL_NO_FLUSH = 0,
+ TDEFL_SYNC_FLUSH = 2,
+ TDEFL_FULL_FLUSH = 3,
+ TDEFL_FINISH = 4
+} tdefl_flush;
+
+// tdefl's compression state structure.
+typedef struct
+{
+ tdefl_put_buf_func_ptr m_pPut_buf_func;
+ void *m_pPut_buf_user;
+ mz_uint m_flags, m_max_probes[2];
+ int m_greedy_parsing;
+ mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
+ mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
+ mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;
+ mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish;
+ tdefl_status m_prev_return_status;
+ const void *m_pIn_buf;
+ void *m_pOut_buf;
+ size_t *m_pIn_buf_size, *m_pOut_buf_size;
+ tdefl_flush m_flush;
+ const mz_uint8 *m_pSrc;
+ size_t m_src_buf_left, m_out_buf_ofs;
+ mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
+ mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
+ mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
+ mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
+ mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
+ mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
+ mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
+ mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
+} tdefl_compressor;
+
+// Initializes the compressor.
+// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory.
+// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression.
+// If pBut_buf_func is NULL the user should always call the tdefl_compress() API.
+// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.)
+tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
+
+// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible.
+tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush);
+
+// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr.
+// tdefl_compress_buffer() always consumes the entire input buffer.
+tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush);
+
+tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
+mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
+
+// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros.
+#ifndef MINIZ_NO_ZLIB_APIS
+// Create tdefl_compress() flags given zlib-style compression parameters.
+// level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files)
+// window_bits may be -15 (raw deflate) or 15 (zlib)
+// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED
+mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy);
+#endif // #ifndef MINIZ_NO_ZLIB_APIS
+
+} // namespace buminiz
+
+#endif // MINIZ_HEADER_INCLUDED
+
+// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
+
+#ifndef MINIZ_HEADER_FILE_ONLY
+
+#include <string.h>
+#include <assert.h>
+
+namespace buminiz {
+
+typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1];
+typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1];
+typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1];
+
+#define MZ_ASSERT(x) assert(x)
+
+#ifdef MINIZ_NO_MALLOC
+ #define MZ_MALLOC(x) NULL
+ #define MZ_FREE(x) (void)x, ((void)0)
+ #define MZ_REALLOC(p, x) NULL
+#else
+ #define MZ_MALLOC(x) malloc(x)
+ #define MZ_FREE(x) free(x)
+ #define MZ_REALLOC(p, x) realloc(p, x)
+#endif
+
+#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
+#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
+#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
+ #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
+ #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
+#else
+ #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
+ #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
+#endif
+
+#ifdef _MSC_VER
+ #define MZ_FORCEINLINE __forceinline
+#elif defined(__GNUC__)
+ #define MZ_FORCEINLINE inline __attribute__((__always_inline__))
+#else
+ #define MZ_FORCEINLINE inline
+#endif
+
+// ------------------- zlib-style API's
+
+mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len)
+{
+ mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552;
+ if (!ptr) return MZ_ADLER32_INIT;
+ while (buf_len) {
+ for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
+ s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
+ s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
+ }
+ for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
+ s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
+ }
+ return (s2 << 16) + s1;
+}
+
+// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/
+mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
+{
+ static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
+ mz_uint32 crcu32 = (mz_uint32)crc;
+ if (!ptr) return MZ_CRC32_INIT;
+ crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; }
+ return ~crcu32;
+}
+
+void mz_free(void *p)
+{
+ MZ_FREE(p);
+}
+
+#ifndef MINIZ_NO_ZLIB_APIS
+
+static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); }
+static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); }
+//static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); }
+
+const char *mz_version(void)
+{
+ return MZ_VERSION;
+}
+
+int mz_deflateInit(mz_streamp pStream, int level)
+{
+ return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY);
+}
+
+int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)
+{
+ tdefl_compressor *pComp;
+ mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
+
+ if (!pStream) return MZ_STREAM_ERROR;
+ if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR;
+
+ pStream->data_type = 0;
+ pStream->adler = MZ_ADLER32_INIT;
+ pStream->msg = NULL;
+ pStream->reserved = 0;
+ pStream->total_in = 0;
+ pStream->total_out = 0;
+ if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
+ if (!pStream->zfree) pStream->zfree = def_free_func;
+
+ pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor));
+ if (!pComp)
+ return MZ_MEM_ERROR;
+
+ pStream->state = (struct mz_internal_state *)pComp;
+
+ if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)
+ {
+ mz_deflateEnd(pStream);
+ return MZ_PARAM_ERROR;
+ }
+
+ return MZ_OK;
+}
+
+int mz_deflateReset(mz_streamp pStream)
+{
+ if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR;
+ pStream->total_in = pStream->total_out = 0;
+ tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags);
+ return MZ_OK;
+}
+
+int mz_deflate(mz_streamp pStream, int flush)
+{
+ size_t in_bytes, out_bytes;
+ mz_ulong orig_total_in, orig_total_out;
+ int mz_status = MZ_OK;
+
+ if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR;
+ if (!pStream->avail_out) return MZ_BUF_ERROR;
+
+ if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
+
+ if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE)
+ return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
+
+ orig_total_in = pStream->total_in; orig_total_out = pStream->total_out;
+ for ( ; ; )
+ {
+ tdefl_status defl_status;
+ in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
+
+ defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);
+ pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
+ pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state);
+
+ pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes;
+ pStream->total_out += (mz_uint)out_bytes;
+
+ if (defl_status < 0)
+ {
+ mz_status = MZ_STREAM_ERROR;
+ break;
+ }
+ else if (defl_status == TDEFL_STATUS_DONE)
+ {
+ mz_status = MZ_STREAM_END;
+ break;
+ }
+ else if (!pStream->avail_out)
+ break;
+ else if ((!pStream->avail_in) && (flush != MZ_FINISH))
+ {
+ if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out))
+ break;
+ return MZ_BUF_ERROR; // Can't make forward progress without some input.
+ }
+ }
+ return mz_status;
+}
+
+int mz_deflateEnd(mz_streamp pStream)
+{
+ if (!pStream) return MZ_STREAM_ERROR;
+ if (pStream->state)
+ {
+ pStream->zfree(pStream->opaque, pStream->state);
+ pStream->state = NULL;
+ }
+ return MZ_OK;
+}
+
+mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len)
+{
+ (void)pStream;
+ // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.)
+ mz_uint64 a = 128ULL + (source_len * 110ULL) / 100ULL;
+ mz_uint64 b = 128ULL + (mz_uint64)source_len + ((source_len / (31 * 1024)) + 1ULL) * 5ULL;
+
+ mz_uint64 t = MZ_MAX(a, b);
+ if (((mz_ulong)t) != t)
+ t = (mz_ulong)(-1);
+
+ return (mz_ulong)t;
+}
+
+int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level)
+{
+ int status;
+ mz_stream stream;
+ memset(&stream, 0, sizeof(stream));
+
+ // In case mz_ulong is 64-bits (argh I hate longs).
+ if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
+
+ stream.next_in = pSource;
+ stream.avail_in = (mz_uint32)source_len;
+ stream.next_out = pDest;
+ stream.avail_out = (mz_uint32)*pDest_len;
+
+ status = mz_deflateInit(&stream, level);
+ if (status != MZ_OK) return status;
+
+ status = mz_deflate(&stream, MZ_FINISH);
+ if (status != MZ_STREAM_END)
+ {
+ mz_deflateEnd(&stream);
+ return (status == MZ_OK) ? MZ_BUF_ERROR : status;
+ }
+
+ *pDest_len = stream.total_out;
+ return mz_deflateEnd(&stream);
+}
+
+int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
+{
+ return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION);
+}
+
+mz_ulong mz_compressBound(mz_ulong source_len)
+{
+ return mz_deflateBound(NULL, source_len);
+}
+
+typedef struct
+{
+ tinfl_decompressor m_decomp;
+ mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits;
+ mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
+ tinfl_status m_last_status;
+} inflate_state;
+
+int mz_inflateInit2(mz_streamp pStream, int window_bits)
+{
+ inflate_state *pDecomp;
+ if (!pStream) return MZ_STREAM_ERROR;
+ if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR;
+
+ pStream->data_type = 0;
+ pStream->adler = 0;
+ pStream->msg = NULL;
+ pStream->total_in = 0;
+ pStream->total_out = 0;
+ pStream->reserved = 0;
+ if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
+ if (!pStream->zfree) pStream->zfree = def_free_func;
+
+ pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));
+ if (!pDecomp) return MZ_MEM_ERROR;
+
+ pStream->state = (struct mz_internal_state *)pDecomp;
+
+ tinfl_init(&pDecomp->m_decomp);
+ pDecomp->m_dict_ofs = 0;
+ pDecomp->m_dict_avail = 0;
+ pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
+ pDecomp->m_first_call = 1;
+ pDecomp->m_has_flushed = 0;
+ pDecomp->m_window_bits = window_bits;
+
+ return MZ_OK;
+}
+
+int mz_inflateInit(mz_streamp pStream)
+{
+ return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
+}
+
+int mz_inflate(mz_streamp pStream, int flush)
+{
+ inflate_state* pState;
+ mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
+ size_t in_bytes, out_bytes, orig_avail_in;
+ tinfl_status status;
+
+ if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
+ if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
+ if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
+
+ pState = (inflate_state*)pStream->state;
+ if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
+ orig_avail_in = pStream->avail_in;
+
+ first_call = pState->m_first_call; pState->m_first_call = 0;
+ if (pState->m_last_status < 0) return MZ_DATA_ERROR;
+
+ if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
+ pState->m_has_flushed |= (flush == MZ_FINISH);
+
+ if ((flush == MZ_FINISH) && (first_call))
+ {
+ // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file.
+ decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
+ in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
+ status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);
+ pState->m_last_status = status;
+ pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes;
+ pStream->adler = tinfl_get_adler32(&pState->m_decomp);
+ pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes;
+
+ if (status < 0)
+ return MZ_DATA_ERROR;
+ else if (status != TINFL_STATUS_DONE)
+ {
+ pState->m_last_status = TINFL_STATUS_FAILED;
+ return MZ_BUF_ERROR;
+ }
+ return MZ_STREAM_END;
+ }
+ // flush != MZ_FINISH then we must assume there's more input.
+ if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
+
+ if (pState->m_dict_avail)
+ {
+ n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
+ memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
+ pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
+ pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
+ return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
+ }
+
+ for ( ; ; )
+ {
+ in_bytes = pStream->avail_in;
+ out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
+
+ status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
+ pState->m_last_status = status;
+
+ pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
+ pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp);
+
+ pState->m_dict_avail = (mz_uint)out_bytes;
+
+ n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
+ memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
+ pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
+ pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
+
+ if (status < 0)
+ return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well).
+ else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
+ return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH.
+ else if (flush == MZ_FINISH)
+ {
+ // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH.
+ if (status == TINFL_STATUS_DONE)
+ return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
+ // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong.
+ else if (!pStream->avail_out)
+ return MZ_BUF_ERROR;
+ }
+ else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))
+ break;
+ }
+
+ return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
+}
+
+int mz_inflateEnd(mz_streamp pStream)
+{
+ if (!pStream)
+ return MZ_STREAM_ERROR;
+ if (pStream->state)
+ {
+ pStream->zfree(pStream->opaque, pStream->state);
+ pStream->state = NULL;
+ }
+ return MZ_OK;
+}
+
+int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
+{
+ mz_stream stream;
+ int status;
+ memset(&stream, 0, sizeof(stream));
+
+ // In case mz_ulong is 64-bits (argh I hate longs).
+ if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
+
+ stream.next_in = pSource;
+ stream.avail_in = (mz_uint32)source_len;
+ stream.next_out = pDest;
+ stream.avail_out = (mz_uint32)*pDest_len;
+
+ status = mz_inflateInit(&stream);
+ if (status != MZ_OK)
+ return status;
+
+ status = mz_inflate(&stream, MZ_FINISH);
+ if (status != MZ_STREAM_END)
+ {
+ mz_inflateEnd(&stream);
+ return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status;
+ }
+ *pDest_len = stream.total_out;
+
+ return mz_inflateEnd(&stream);
+}
+
+const char *mz_error(int err)
+{
+ static struct { int m_err; const char *m_pDesc; } s_error_descs[] =
+ {
+ { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" },
+ { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" }
+ };
+ mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc;
+ return NULL;
+}
+
+#endif //MINIZ_NO_ZLIB_APIS
+
+// ------------------- Low-level Decompression (completely independent from all compression API's)
+
+#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
+#define TINFL_MEMSET(p, c, l) memset(p, c, l)
+
+#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
+#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
+#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
+#define TINFL_CR_FINISH }
+
+// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
+// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
+#define TINFL_GET_BYTE(state_index, c) do { \
+ if (pIn_buf_cur >= pIn_buf_end) { \
+ for ( ; ; ) { \
+ if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
+ TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
+ if (pIn_buf_cur < pIn_buf_end) { \
+ c = *pIn_buf_cur++; \
+ break; \
+ } \
+ } else { \
+ c = 0; \
+ break; \
+ } \
+ } \
+ } else c = *pIn_buf_cur++; } MZ_MACRO_END
+
+#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
+#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
+#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
+
+// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
+// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a
+// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the
+// bit buffer contains >=15 bits (deflate's max. Huffman code size).
+#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
+ do { \
+ temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
+ if (temp >= 0) { \
+ code_len = temp >> 9; \
+ if ((code_len) && (num_bits >= code_len)) \
+ break; \
+ } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
+ code_len = TINFL_FAST_LOOKUP_BITS; \
+ do { \
+ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
+ } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
+ } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
+ } while (num_bits < 15);
+
+// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read
+// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully
+// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32.
+// The slow path is only executed at the very end of the input buffer.
+#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
+ int temp; mz_uint code_len, c; \
+ if (num_bits < 15) { \
+ if ((pIn_buf_end - pIn_buf_cur) < 2) { \
+ TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
+ } else { \
+ bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
+ } \
+ } \
+ if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
+ code_len = temp >> 9, temp &= 511; \
+ else { \
+ code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
+ } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
+
+tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
+{
+ static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
+ static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+ static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+ static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+ static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+ static const int s_min_table_sizes[3] = { 257, 1, 4 };
+
+ tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
+ const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
+ mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
+ size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
+
+ // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter).
+ if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
+
+ num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
+ TINFL_CR_BEGIN
+
+ bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
+ if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
+ {
+ TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
+ counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
+ if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1ULL << (8U + (r->m_zhdr0 >> 4)))));
+ if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
+ }
+
+ do
+ {
+ TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
+ if (r->m_type == 0)
+ {
+ TINFL_SKIP_BITS(5, num_bits & 7);
+ for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
+ if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
+ while ((counter) && (num_bits))
+ {
+ TINFL_GET_BITS(51, dist, 8);
+ while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ *pOut_buf_cur++ = (mz_uint8)dist;
+ counter--;
+ }
+ while (counter)
+ {
+ size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ while (pIn_buf_cur >= pIn_buf_end)
+ {
+ if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
+ {
+ TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
+ }
+ else
+ {
+ TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
+ }
+ }
+ n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
+ TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
+ }
+ }
+ else if (r->m_type == 3)
+ {
+ TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
+ }
+ else
+ {
+ if (r->m_type == 1)
+ {
+ mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
+ r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
+ for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
+ }
+ else
+ {
+ for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
+ MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
+ r->m_table_sizes[2] = 19;
+ }
+ for ( ; (int)r->m_type >= 0; r->m_type--)
+ {
+ int tree_next, tree_cur; tinfl_huff_table *pTable;
+ mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
+ for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
+ used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
+ for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
+ if ((65536 != total) && (used_syms > 1))
+ {
+ TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
+ }
+ for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
+ {
+ mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
+ cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
+ if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
+ if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
+ rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
+ for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
+ {
+ tree_cur -= ((rev_code >>= 1) & 1);
+ if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
+ }
+ tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
+ }
+ if (r->m_type == 2)
+ {
+ for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
+ {
+ mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
+ if ((dist == 16) && (!counter))
+ {
+ TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
+ }
+ num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
+ TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
+ }
+ if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
+ {
+ TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
+ }
+ TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
+ }
+ }
+ for ( ; ; )
+ {
+ mz_uint8 *pSrc;
+ for ( ; ; )
+ {
+ if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
+ {
+ TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
+ if (counter >= 256)
+ break;
+ while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ *pOut_buf_cur++ = (mz_uint8)counter;
+ }
+ else
+ {
+ int sym2; mz_uint code_len;
+#if TINFL_USE_64BIT_BITBUF
+ if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
+#else
+ if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
+#endif
+ if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
+ code_len = sym2 >> 9;
+ else
+ {
+ code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
+ }
+ counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
+ if (counter & 256)
+ break;
+
+#if !TINFL_USE_64BIT_BITBUF
+ if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
+#endif
+ if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
+ code_len = sym2 >> 9;
+ else
+ {
+ code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
+ }
+ bit_buf >>= code_len; num_bits -= code_len;
+
+ pOut_buf_cur[0] = (mz_uint8)counter;
+ if (sym2 & 256)
+ {
+ pOut_buf_cur++;
+ counter = sym2;
+ break;
+ }
+ pOut_buf_cur[1] = (mz_uint8)sym2;
+ pOut_buf_cur += 2;
+ }
+ }
+ if ((counter &= 511) == 256) break;
+
+ num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
+ if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
+
+ TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
+ num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
+ if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
+
+ dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
+ if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
+ {
+ TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
+ }
+
+ pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
+
+ if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
+ {
+ while (counter--)
+ {
+ while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
+ *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
+ }
+ continue;
+ }
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
+ else if ((counter >= 9) && (counter <= dist))
+ {
+ const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
+ do
+ {
+ ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
+ ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
+ pOut_buf_cur += 8;
+ } while ((pSrc += 8) < pSrc_end);
+ if ((counter &= 7) < 3)
+ {
+ if (counter)
+ {
+ pOut_buf_cur[0] = pSrc[0];
+ if (counter > 1)
+ pOut_buf_cur[1] = pSrc[1];
+ pOut_buf_cur += counter;
+ }
+ continue;
+ }
+ }
+#endif
+ do
+ {
+ pOut_buf_cur[0] = pSrc[0];
+ pOut_buf_cur[1] = pSrc[1];
+ pOut_buf_cur[2] = pSrc[2];
+ pOut_buf_cur += 3; pSrc += 3;
+ } while ((int)(counter -= 3) > 2);
+ if ((int)counter > 0)
+ {
+ pOut_buf_cur[0] = pSrc[0];
+ if ((int)counter > 1)
+ pOut_buf_cur[1] = pSrc[1];
+ pOut_buf_cur += counter;
+ }
+ }
+ }
+ } while (!(r->m_final & 1));
+ if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
+ {
+ TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
+ }
+ TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
+ TINFL_CR_FINISH
+
+common_exit:
+ r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
+ *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
+ if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
+ {
+ const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
+ mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
+ while (buf_len)
+ {
+ for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
+ {
+ s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
+ s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
+ }
+ for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
+ s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
+ }
+ r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
+ }
+ return status;
+}
+
+// Higher level helper functions.
+void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
+{
+ tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
+ *pOut_len = 0;
+ tinfl_init(&decomp);
+ for ( ; ; )
+ {
+ size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
+ tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size,
+ (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
+ if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
+ {
+ MZ_FREE(pBuf); *pOut_len = 0; return NULL;
+ }
+ src_buf_ofs += src_buf_size;
+ *pOut_len += dst_buf_size;
+ if (status == TINFL_STATUS_DONE) break;
+ new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
+ pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
+ if (!pNew_buf)
+ {
+ MZ_FREE(pBuf); *pOut_len = 0; return NULL;
+ }
+ pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
+ }
+ return pBuf;
+}
+
+size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
+{
+ tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
+ status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
+ return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
+}
+
+int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
+{
+ int result = 0;
+ tinfl_decompressor decomp;
+ mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
+ if (!pDict)
+ return TINFL_STATUS_FAILED;
+ tinfl_init(&decomp);
+ for ( ; ; )
+ {
+ size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
+ tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
+ (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
+ in_buf_ofs += in_buf_size;
+ if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
+ break;
+ if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
+ {
+ result = (status == TINFL_STATUS_DONE);
+ break;
+ }
+ dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
+ }
+ MZ_FREE(pDict);
+ *pIn_buf_size = in_buf_ofs;
+ return result;
+}
+
+// ------------------- Low-level Compression (independent from all decompression API's)
+
+// Purposely making these tables static for faster init and thread safety.
+static const mz_uint16 s_tdefl_len_sym[256] = {
+ 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272,
+ 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276,
+ 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,
+ 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,
+ 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,
+ 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,
+ 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,
+ 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 };
+
+static const mz_uint8 s_tdefl_len_extra[256] = {
+ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 };
+
+static const mz_uint8 s_tdefl_small_dist_sym[512] = {
+ 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,
+ 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
+ 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+ 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 };
+
+static const mz_uint8 s_tdefl_small_dist_extra[512] = {
+ 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7 };
+
+static const mz_uint8 s_tdefl_large_dist_sym[128] = {
+ 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,
+ 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
+ 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 };
+
+static const mz_uint8 s_tdefl_large_dist_extra[128] = {
+ 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 };
+
+// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values.
+typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq;
+static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1)
+{
+ mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist);
+ for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; }
+ while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--;
+ for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8)
+ {
+ const mz_uint32* pHist = &hist[pass << 8];
+ mz_uint offsets[256], cur_ofs = 0;
+ for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; }
+ for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i];
+ { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; }
+ }
+ return pCur_syms;
+}
+
+// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
+static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n)
+{
+ int root, leaf, next, avbl, used, dpth;
+ if (n==0) return; else if (n==1) { A[0].m_key = 1; return; }
+ A[0].m_key += A[1].m_key; root = 0; leaf = 2;
+ for (next=1; next < n-1; next++)
+ {
+ if (leaf>=n || A[root].m_key<A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = (mz_uint16)next; } else A[next].m_key = A[leaf++].m_key;
+ if (leaf>=n || (root<next && A[root].m_key<A[leaf].m_key)) { A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); A[root++].m_key = (mz_uint16)next; } else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
+ }
+ A[n-2].m_key = 0; for (next=n-3; next>=0; next--) A[next].m_key = A[A[next].m_key].m_key+1;
+ avbl = 1; used = dpth = 0; root = n-2; next = n-1;
+ while (avbl>0)
+ {
+ while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; }
+ while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; }
+ avbl = 2*used; dpth++; used = 0;
+ }
+}
+
+// Limits canonical Huffman code table's max code size.
+enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
+static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size)
+{
+ int i; mz_uint32 total = 0; if (code_list_len <= 1) return;
+ for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i];
+ for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
+ while (total != (1UL << max_code_size))
+ {
+ pNum_codes[max_code_size]--;
+ for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; }
+ total--;
+ }
+}
+
+static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table)
+{
+ int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes);
+ if (static_table)
+ {
+ for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++;
+ }
+ else
+ {
+ tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms;
+ int num_used_syms = 0;
+ const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
+ for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; }
+
+ pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
+
+ for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++;
+
+ tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit);
+
+ MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
+ for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
+ for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
+ }
+
+ next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1);
+
+ for (i = 0; i < table_len; i++)
+ {
+ mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue;
+ code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1);
+ d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
+ }
+}
+
+#define TDEFL_PUT_BITS(b, l) do { \
+ mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \
+ d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \
+ while (d->m_bits_in >= 8) { \
+ if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
+ *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
+ d->m_bit_buffer >>= 8; \
+ d->m_bits_in -= 8; \
+ } \
+} MZ_MACRO_END
+
+#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \
+ if (rle_repeat_count < 3) { \
+ d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
+ while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
+ } else { \
+ d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \
+} rle_repeat_count = 0; } }
+
+#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \
+ if (rle_z_count < 3) { \
+ d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \
+ } else if (rle_z_count <= 10) { \
+ d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \
+ } else { \
+ d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \
+} rle_z_count = 0; } }
+
+static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+static void tdefl_start_dynamic_block(tdefl_compressor *d)
+{
+ int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index;
+ mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF;
+
+ d->m_huff_count[0][256] = 1;
+
+ tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
+ tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
+
+ for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break;
+ for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break;
+
+ memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
+ memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes);
+ total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0;
+
+ memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
+ for (i = 0; i < total_code_sizes_to_pack; i++)
+ {
+ mz_uint8 code_size = code_sizes_to_pack[i];
+ if (!code_size)
+ {
+ TDEFL_RLE_PREV_CODE_SIZE();
+ if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); }
+ }
+ else
+ {
+ TDEFL_RLE_ZERO_CODE_SIZE();
+ if (code_size != prev_code_size)
+ {
+ TDEFL_RLE_PREV_CODE_SIZE();
+ d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size;
+ }
+ else if (++rle_repeat_count == 6)
+ {
+ TDEFL_RLE_PREV_CODE_SIZE();
+ }
+ }
+ prev_code_size = code_size;
+ }
+ if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); }
+
+ tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
+
+ TDEFL_PUT_BITS(2, 2);
+
+ TDEFL_PUT_BITS(num_lit_codes - 257, 5);
+ TDEFL_PUT_BITS(num_dist_codes - 1, 5);
+
+ for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break;
+ num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
+ for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
+
+ for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; )
+ {
+ mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
+ TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
+ if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]);
+ }
+}
+
+static void tdefl_start_static_block(tdefl_compressor *d)
+{
+ mz_uint i;
+ mz_uint8 *p = &d->m_huff_code_sizes[0][0];
+
+ for (i = 0; i <= 143; ++i) *p++ = 8;
+ for ( ; i <= 255; ++i) *p++ = 9;
+ for ( ; i <= 279; ++i) *p++ = 7;
+ for ( ; i <= 287; ++i) *p++ = 8;
+
+ memset(d->m_huff_code_sizes[1], 5, 32);
+
+ tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
+ tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
+
+ TDEFL_PUT_BITS(1, 2);
+}
+
+static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
+static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
+{
+ mz_uint flags;
+ mz_uint8 *pLZ_codes;
+ mz_uint8 *pOutput_buf = d->m_pOutput_buf;
+ mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
+ mz_uint64 bit_buffer = d->m_bit_buffer;
+ mz_uint bits_in = d->m_bits_in;
+
+#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); }
+
+ flags = 1;
+ for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1)
+ {
+ if (flags == 1)
+ flags = *pLZ_codes++ | 0x100;
+
+ if (flags & 1)
+ {
+ mz_uint s0, s1, n0, n1, sym, num_extra_bits;
+ mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3;
+
+ MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
+ TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
+ TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
+
+ // This sequence coaxes MSVC into using cmov's vs. jmp's.
+ s0 = s_tdefl_small_dist_sym[match_dist & 511];
+ n0 = s_tdefl_small_dist_extra[match_dist & 511];
+ s1 = s_tdefl_large_dist_sym[match_dist >> 8];
+ n1 = s_tdefl_large_dist_extra[match_dist >> 8];
+ sym = (match_dist < 512) ? s0 : s1;
+ num_extra_bits = (match_dist < 512) ? n0 : n1;
+
+ MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
+ TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
+ TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
+ }
+ else
+ {
+ mz_uint lit = *pLZ_codes++;
+ MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
+ TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
+
+ if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
+ {
+ flags >>= 1;
+ lit = *pLZ_codes++;
+ MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
+ TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
+
+ if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
+ {
+ flags >>= 1;
+ lit = *pLZ_codes++;
+ MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
+ TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
+ }
+ }
+ }
+
+ if (pOutput_buf >= d->m_pOutput_buf_end)
+ return MZ_FALSE;
+
+ *(mz_uint64*)pOutput_buf = bit_buffer;
+ pOutput_buf += (bits_in >> 3);
+ bit_buffer >>= (bits_in & ~7);
+ bits_in &= 7;
+ }
+
+#undef TDEFL_PUT_BITS_FAST
+
+ d->m_pOutput_buf = pOutput_buf;
+ d->m_bits_in = 0;
+ d->m_bit_buffer = 0;
+
+ while (bits_in)
+ {
+ mz_uint32 n = MZ_MIN(bits_in, 16);
+ TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
+ bit_buffer >>= n;
+ bits_in -= n;
+ }
+
+ TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
+
+ return (d->m_pOutput_buf < d->m_pOutput_buf_end);
+}
+#else
+static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
+{
+ mz_uint flags;
+ mz_uint8 *pLZ_codes;
+
+ flags = 1;
+ for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1)
+ {
+ if (flags == 1)
+ flags = *pLZ_codes++ | 0x100;
+ if (flags & 1)
+ {
+ mz_uint sym, num_extra_bits;
+ mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3;
+
+ MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
+ TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
+ TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
+
+ if (match_dist < 512)
+ {
+ sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist];
+ }
+ else
+ {
+ sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
+ }
+ MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
+ TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
+ TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
+ }
+ else
+ {
+ mz_uint lit = *pLZ_codes++;
+ MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
+ TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
+ }
+ }
+
+ TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
+
+ return (d->m_pOutput_buf < d->m_pOutput_buf_end);
+}
+#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
+
+static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block)
+{
+ if (static_block)
+ tdefl_start_static_block(d);
+ else
+ tdefl_start_dynamic_block(d);
+ return tdefl_compress_lz_codes(d);
+}
+
+static int tdefl_flush_block(tdefl_compressor *d, int flush)
+{
+ mz_uint saved_bit_buf, saved_bits_in;
+ mz_uint8 *pSaved_output_buf;
+ mz_bool comp_block_succeeded = MZ_FALSE;
+ int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
+ mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf;
+
+ d->m_pOutput_buf = pOutput_buf_start;
+ d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
+
+ MZ_ASSERT(!d->m_output_flush_remaining);
+ d->m_output_flush_ofs = 0;
+ d->m_output_flush_remaining = 0;
+
+ *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
+ d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
+
+ if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index))
+ {
+ TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8);
+ }
+
+ TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
+
+ pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in;
+
+ if (!use_raw_block)
+ comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48));
+
+ // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead.
+ if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) &&
+ ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) )
+ {
+ mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
+ TDEFL_PUT_BITS(0, 2);
+ if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); }
+ for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF)
+ {
+ TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
+ }
+ for (i = 0; i < d->m_total_lz_bytes; ++i)
+ {
+ TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8);
+ }
+ }
+ // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes.
+ else if (!comp_block_succeeded)
+ {
+ d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
+ tdefl_compress_block(d, MZ_TRUE);
+ }
+
+ if (flush)
+ {
+ if (flush == TDEFL_FINISH)
+ {
+ if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); }
+ if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } }
+ }
+ else
+ {
+ mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); }
+ }
+ }
+
+ MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
+
+ memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
+ memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
+
+ d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++;
+
+ if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0)
+ {
+ if (d->m_pPut_buf_func)
+ {
+ *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
+ if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
+ return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
+ }
+ else if (pOutput_buf_start == d->m_output_buf)
+ {
+ int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
+ memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy);
+ d->m_out_buf_ofs += bytes_to_copy;
+ if ((n -= bytes_to_copy) != 0)
+ {
+ d->m_output_flush_ofs = bytes_to_copy;
+ d->m_output_flush_remaining = n;
+ }
+ }
+ else
+ {
+ d->m_out_buf_ofs += n;
+ }
+ }
+
+ return d->m_output_flush_remaining;
+}
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
+#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p)
+static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)
+{
+ mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
+ mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
+ const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q;
+ mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s);
+ MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return;
+ for ( ; ; )
+ {
+ for ( ; ; )
+ {
+ if (--num_probes_left == 0) return;
+ #define TDEFL_PROBE \
+ next_probe_pos = d->m_next[probe_pos]; \
+ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \
+ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
+ if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break;
+ TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE;
+ }
+ if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32;
+ do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
+ (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) );
+ if (!probe_len)
+ {
+ *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break;
+ }
+ else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len)
+ {
+ *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break;
+ c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
+ }
+ }
+}
+#else
+static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)
+{
+ mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
+ mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
+ const mz_uint8 *s = d->m_dict + pos, *p, *q;
+ mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
+ MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return;
+ for ( ; ; )
+ {
+ for ( ; ; )
+ {
+ if (--num_probes_left == 0) return;
+ #define TDEFL_PROBE \
+ next_probe_pos = d->m_next[probe_pos]; \
+ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \
+ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
+ if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break;
+ TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE;
+ }
+ if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break;
+ if (probe_len > match_len)
+ {
+ *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return;
+ c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1];
+ }
+ }
+}
+#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
+static mz_bool tdefl_compress_fast(tdefl_compressor *d)
+{
+ // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio.
+ mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left;
+ mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
+ mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
+
+ while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size)))
+ {
+ const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
+ mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
+ mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
+ d->m_src_buf_left -= num_bytes_to_process;
+ lookahead_size += num_bytes_to_process;
+
+ while (num_bytes_to_process)
+ {
+ mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
+ memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
+ if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
+ memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
+ d->m_pSrc += n;
+ dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
+ num_bytes_to_process -= n;
+ }
+
+ dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
+ if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break;
+
+ while (lookahead_size >= 4)
+ {
+ mz_uint cur_match_dist, cur_match_len = 1;
+ mz_uint8 *pCur_dict = d->m_dict + cur_pos;
+ mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
+ mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK;
+ mz_uint probe_pos = d->m_hash[hash];
+ d->m_hash[hash] = (mz_uint16)lookahead_pos;
+
+ if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram))
+ {
+ const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
+ const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
+ mz_uint32 probe_len = 32;
+ do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
+ (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) );
+ cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
+ if (!probe_len)
+ cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
+
+ if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)))
+ {
+ cur_match_len = 1;
+ *pLZ_code_buf++ = (mz_uint8)first_trigram;
+ *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
+ d->m_huff_count[0][(mz_uint8)first_trigram]++;
+ }
+ else
+ {
+ mz_uint32 s0, s1;
+ cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
+
+ MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
+
+ cur_match_dist--;
+
+ pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
+ *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
+ pLZ_code_buf += 3;
+ *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
+
+ s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
+ s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
+ d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
+
+ d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++;
+ }
+ }
+ else
+ {
+ *pLZ_code_buf++ = (mz_uint8)first_trigram;
+ *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
+ d->m_huff_count[0][(mz_uint8)first_trigram]++;
+ }
+
+ if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; }
+
+ total_lz_bytes += cur_match_len;
+ lookahead_pos += cur_match_len;
+ dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
+ cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
+ MZ_ASSERT(lookahead_size >= cur_match_len);
+ lookahead_size -= cur_match_len;
+
+ if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
+ {
+ int n;
+ d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
+ d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
+ if ((n = tdefl_flush_block(d, 0)) != 0)
+ return (n < 0) ? MZ_FALSE : MZ_TRUE;
+ total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left;
+ }
+ }
+
+ while (lookahead_size)
+ {
+ mz_uint8 lit = d->m_dict[cur_pos];
+
+ total_lz_bytes++;
+ *pLZ_code_buf++ = lit;
+ *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
+ if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; }
+
+ d->m_huff_count[0][lit]++;
+
+ lookahead_pos++;
+ dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
+ cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
+ lookahead_size--;
+
+ if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
+ {
+ int n;
+ d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
+ d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
+ if ((n = tdefl_flush_block(d, 0)) != 0)
+ return (n < 0) ? MZ_FALSE : MZ_TRUE;
+ total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left;
+ }
+ }
+ }
+
+ d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
+ d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
+ return MZ_TRUE;
+}
+#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
+
+static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit)
+{
+ d->m_total_lz_bytes++;
+ *d->m_pLZ_code_buf++ = lit;
+ *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; }
+ d->m_huff_count[0][lit]++;
+}
+
+static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist)
+{
+ mz_uint32 s0, s1;
+
+ MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE));
+
+ d->m_total_lz_bytes += match_len;
+
+ d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
+
+ match_dist -= 1;
+ d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
+ d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3;
+
+ *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; }
+
+ s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
+ d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
+
+ if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
+}
+
+static mz_bool tdefl_compress_normal(tdefl_compressor *d)
+{
+ const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left;
+ tdefl_flush flush = d->m_flush;
+
+ while ((src_buf_left) || ((flush) && (d->m_lookahead_size)))
+ {
+ mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
+ // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN.
+ if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1))
+ {
+ mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
+ mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
+ mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
+ const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
+ src_buf_left -= num_bytes_to_process;
+ d->m_lookahead_size += num_bytes_to_process;
+ while (pSrc != pSrc_end)
+ {
+ mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
+ hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
+ d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos);
+ dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++;
+ }
+ }
+ else
+ {
+ while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
+ {
+ mz_uint8 c = *pSrc++;
+ mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
+ src_buf_left--;
+ d->m_dict[dst_pos] = c;
+ if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
+ d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
+ if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN)
+ {
+ mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
+ mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
+ d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos);
+ }
+ }
+ }
+ d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
+ if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
+ break;
+
+ // Simple lazy/greedy parsing state machine.
+ len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
+ if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS))
+ {
+ if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))
+ {
+ mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
+ cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; }
+ if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1;
+ }
+ }
+ else
+ {
+ tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len);
+ }
+ if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5)))
+ {
+ cur_match_dist = cur_match_len = 0;
+ }
+ if (d->m_saved_match_len)
+ {
+ if (cur_match_len > d->m_saved_match_len)
+ {
+ tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
+ if (cur_match_len >= 128)
+ {
+ tdefl_record_match(d, cur_match_len, cur_match_dist);
+ d->m_saved_match_len = 0; len_to_move = cur_match_len;
+ }
+ else
+ {
+ d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len;
+ }
+ }
+ else
+ {
+ tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
+ len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0;
+ }
+ }
+ else if (!cur_match_dist)
+ tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
+ else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128))
+ {
+ tdefl_record_match(d, cur_match_len, cur_match_dist);
+ len_to_move = cur_match_len;
+ }
+ else
+ {
+ d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len;
+ }
+ // Move the lookahead forward by len_to_move bytes.
+ d->m_lookahead_pos += len_to_move;
+ MZ_ASSERT(d->m_lookahead_size >= len_to_move);
+ d->m_lookahead_size -= len_to_move;
+ d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE);
+ // Check if it's time to flush the current LZ codes to the internal output buffer.
+ if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
+ ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) )
+ {
+ int n;
+ d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left;
+ if ((n = tdefl_flush_block(d, 0)) != 0)
+ return (n < 0) ? MZ_FALSE : MZ_TRUE;
+ }
+ }
+
+ d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left;
+ return MZ_TRUE;
+}
+
+static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d)
+{
+ if (d->m_pIn_buf_size)
+ {
+ *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
+ }
+
+ if (d->m_pOut_buf_size)
+ {
+ size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining);
+ memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n);
+ d->m_output_flush_ofs += (mz_uint)n;
+ d->m_output_flush_remaining -= (mz_uint)n;
+ d->m_out_buf_ofs += n;
+
+ *d->m_pOut_buf_size = d->m_out_buf_ofs;
+ }
+
+ return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY;
+}
+
+tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush)
+{
+ if (!d)
+ {
+ if (pIn_buf_size) *pIn_buf_size = 0;
+ if (pOut_buf_size) *pOut_buf_size = 0;
+ return TDEFL_STATUS_BAD_PARAM;
+ }
+
+ d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size;
+ d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size;
+ d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
+ d->m_out_buf_ofs = 0;
+ d->m_flush = flush;
+
+ if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
+ (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) )
+ {
+ if (pIn_buf_size) *pIn_buf_size = 0;
+ if (pOut_buf_size) *pOut_buf_size = 0;
+ return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
+ }
+ d->m_wants_to_finish |= (flush == TDEFL_FINISH);
+
+ if ((d->m_output_flush_remaining) || (d->m_finished))
+ return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
+ if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
+ ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
+ ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0))
+ {
+ if (!tdefl_compress_fast(d))
+ return d->m_prev_return_status;
+ }
+ else
+#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
+ {
+ if (!tdefl_compress_normal(d))
+ return d->m_prev_return_status;
+ }
+
+ if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf))
+ d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf);
+
+ if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining))
+ {
+ if (tdefl_flush_block(d, flush) < 0)
+ return d->m_prev_return_status;
+ d->m_finished = (flush == TDEFL_FINISH);
+ if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; }
+ }
+
+ return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
+}
+
+tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush)
+{
+ MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
+}
+
+tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
+{
+ d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user;
+ d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
+ d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
+ if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash);
+ d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
+ d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
+ d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8;
+ d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY;
+ d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1;
+ d->m_pIn_buf = NULL; d->m_pOut_buf = NULL;
+ d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL;
+ d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0;
+ memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
+ memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
+ return TDEFL_STATUS_OKAY;
+}
+
+tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d)
+{
+ return d->m_prev_return_status;
+}
+
+mz_uint32 tdefl_get_adler32(tdefl_compressor *d)
+{
+ return d->m_adler32;
+}
+
+mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
+{
+ tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE;
+ pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE;
+ succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY);
+ succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE);
+ MZ_FREE(pComp); return succeeded;
+}
+
+typedef struct
+{
+ size_t m_size, m_capacity;
+ mz_uint8 *m_pBuf;
+ mz_bool m_expandable;
+} tdefl_output_buffer;
+
+static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser)
+{
+ tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
+ size_t new_size = p->m_size + len;
+ if (new_size > p->m_capacity)
+ {
+ size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE;
+ do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity);
+ pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE;
+ p->m_pBuf = pNew_buf; p->m_capacity = new_capacity;
+ }
+ memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size;
+ return MZ_TRUE;
+}
+
+void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
+{
+ tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf);
+ if (!pOut_len) return MZ_FALSE; else *pOut_len = 0;
+ out_buf.m_expandable = MZ_TRUE;
+ if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL;
+ *pOut_len = out_buf.m_size; return out_buf.m_pBuf;
+}
+
+size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
+{
+ tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf);
+ if (!pOut_buf) return 0;
+ out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len;
+ if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0;
+ return out_buf.m_size;
+}
+
+#ifndef MINIZ_NO_ZLIB_APIS
+static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
+
+// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files).
+mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy)
+{
+ mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
+ if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
+
+ if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
+ else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES;
+ else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK;
+ else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
+ else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES;
+
+ return comp_flags;
+}
+#endif //MINIZ_NO_ZLIB_APIS
+
+#ifdef _MSC_VER
+#pragma warning (push)
+#pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal)
+#endif
+
+// Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at
+// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
+// This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck.
+void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip)
+{
+ // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined.
+ static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
+ tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0;
+ if (!pComp) return NULL;
+ MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; }
+ // write dummy header
+ for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf);
+ // compress image data
+ tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
+ for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); }
+ if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+ // write real header
+ *pLen_out = out_buf.m_size-41;
+ {
+ static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
+ mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
+ 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,chans[num_chans],0,0,0,0,0,0,0,
+ (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54};
+ c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24);
+ memcpy(out_buf.m_pBuf, pnghdr, 41);
+ }
+ // write footer (IDAT CRC-32, followed by IEND chunk)
+ if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+ c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24);
+ // compute final size of file, grab compressed data buffer and return
+ *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf;
+}
+void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out)
+{
+ // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out)
+ return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE);
+}
+
+#ifdef _MSC_VER
+#pragma warning (pop)
+#endif
+
+} // namespace buminiz
+
+#endif // MINIZ_HEADER_FILE_ONLY
+
diff --git a/thirdparty/basis_universal/encoder/basisu_pvrtc1_4.cpp b/thirdparty/basis_universal/encoder/basisu_pvrtc1_4.cpp
new file mode 100644
index 0000000000..596fc197e6
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_pvrtc1_4.cpp
@@ -0,0 +1,564 @@
+// basisu_pvrtc1_4.cpp
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "basisu_pvrtc1_4.h"
+
+namespace basisu
+{
+#if 0
+ static const uint8_t g_pvrtc_5[32] = { 0,8,16,24,33,41,49,57,66,74,82,90,99,107,115,123,132,140,148,156,165,173,181,189,198,206,214,222,231,239,247,255 };
+ static const uint8_t g_pvrtc_4[16] = { 0,16,33,49,66,82,99,115,140,156,173,189,206,222,239,255 };
+ static const uint8_t g_pvrtc_3[8] = { 0,33,74,107,148,181,222,255 };
+ static const uint8_t g_pvrtc_alpha[9] = { 0,34,68,102,136,170,204,238,255 };
+#endif
+
+ static const uint8_t g_pvrtc_5_nearest[256] = { 0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31,31,31,31 };
+ static const uint8_t g_pvrtc_4_nearest[256] = { 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15 };
+#if 0
+ static const uint8_t g_pvrtc_3_nearest[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 };
+ static const uint8_t g_pvrtc_alpha_nearest[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8 };
+#endif
+
+#if 0
+ static const uint8_t g_pvrtc_5_floor[256] =
+ {
+ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,
+ 3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,
+ 7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,
+ 11,11,11,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,
+ 15,15,15,15,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,
+ 19,19,19,19,19,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,
+ 23,23,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,
+ 27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31
+ };
+
+ static const uint8_t g_pvrtc_5_ceil[256] =
+ {
+ 0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,
+ 4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,
+ 8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,12,12,12,12,12,
+ 12,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,
+ 16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,20,20,20,
+ 20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,
+ 24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,
+ 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,31
+ };
+
+ static const uint8_t g_pvrtc_4_floor[256] =
+ {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,
+ 9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,
+ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,
+ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15
+ };
+
+ static const uint8_t g_pvrtc_4_ceil[256] =
+ {
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,
+ 8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,
+ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,
+ 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,
+ 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15
+ };
+
+ static const uint8_t g_pvrtc_3_floor[256] =
+ {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7
+ };
+
+ static const uint8_t g_pvrtc_3_ceil[256] =
+ {
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+ };
+
+ static const uint8_t g_pvrtc_alpha_floor[256] =
+ {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8
+ };
+
+ static const uint8_t g_pvrtc_alpha_ceil[256] =
+ {
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+ };
+#endif
+
+ uint32_t pvrtc4_swizzle_uv(uint32_t width, uint32_t height, uint32_t x, uint32_t y)
+ {
+ assert((x < width) && (y < height) && basisu::is_pow2(height) && basisu::is_pow2(width));
+
+ uint32_t min_d = width, max_v = y;
+ if (height < width)
+ {
+ min_d = height;
+ max_v = x;
+ }
+
+ // Interleave the XY LSB's
+ uint32_t shift_ofs = 0, swizzled = 0;
+ for (uint32_t s_bit = 1, d_bit = 1; s_bit < min_d; s_bit <<= 1, d_bit <<= 2, ++shift_ofs)
+ {
+ if (y & s_bit) swizzled |= d_bit;
+ if (x & s_bit) swizzled |= (2 * d_bit);
+ }
+
+ max_v >>= shift_ofs;
+
+ // OR in the rest of the bits from the largest dimension
+ swizzled |= (max_v << (2 * shift_ofs));
+
+ return swizzled;
+ }
+
+ color_rgba pvrtc4_block::get_endpoint(uint32_t endpoint_index, bool unpack) const
+ {
+ assert(endpoint_index < 2);
+ const uint32_t packed = m_endpoints >> (endpoint_index * 16);
+
+ uint32_t r, g, b, a;
+ if (packed & 0x8000)
+ {
+ // opaque 554 or 555
+ if (!endpoint_index)
+ {
+ r = (packed >> 10) & 31;
+ g = (packed >> 5) & 31;
+ b = (packed >> 1) & 15;
+
+ if (unpack)
+ {
+ b = (b << 1) | (b >> 3);
+ }
+ }
+ else
+ {
+ r = (packed >> 10) & 31;
+ g = (packed >> 5) & 31;
+ b = packed & 31;
+ }
+
+ a = unpack ? 255 : 7;
+ }
+ else
+ {
+ // translucent 4433 or 4443
+ if (!endpoint_index)
+ {
+ a = (packed >> 12) & 7;
+ r = (packed >> 8) & 15;
+ g = (packed >> 4) & 15;
+ b = (packed >> 1) & 7;
+
+ if (unpack)
+ {
+ a = (a << 1);
+ a = (a << 4) | a;
+
+ r = (r << 1) | (r >> 3);
+ g = (g << 1) | (g >> 3);
+ b = (b << 2) | (b >> 1);
+ }
+ }
+ else
+ {
+ a = (packed >> 12) & 7;
+ r = (packed >> 8) & 15;
+ g = (packed >> 4) & 15;
+ b = packed & 15;
+
+ if (unpack)
+ {
+ a = (a << 1);
+ a = (a << 4) | a;
+
+ r = (r << 1) | (r >> 3);
+ g = (g << 1) | (g >> 3);
+ b = (b << 1) | (b >> 3);
+ }
+ }
+ }
+
+ if (unpack)
+ {
+ r = (r << 3) | (r >> 2);
+ g = (g << 3) | (g >> 2);
+ b = (b << 3) | (b >> 2);
+ }
+
+ assert((r < 256) && (g < 256) && (b < 256) && (a < 256));
+
+ return color_rgba(r, g, b, a);
+ }
+
+ color_rgba pvrtc4_block::get_endpoint_5554(uint32_t endpoint_index) const
+ {
+ assert(endpoint_index < 2);
+ const uint32_t packed = m_endpoints >> (endpoint_index * 16);
+
+ uint32_t r, g, b, a;
+ if (packed & 0x8000)
+ {
+ // opaque 554 or 555
+ if (!endpoint_index)
+ {
+ r = (packed >> 10) & 31;
+ g = (packed >> 5) & 31;
+ b = (packed >> 1) & 15;
+
+ b = (b << 1) | (b >> 3);
+ }
+ else
+ {
+ r = (packed >> 10) & 31;
+ g = (packed >> 5) & 31;
+ b = packed & 31;
+ }
+
+ a = 15;
+ }
+ else
+ {
+ // translucent 4433 or 4443
+ if (!endpoint_index)
+ {
+ a = (packed >> 12) & 7;
+ r = (packed >> 8) & 15;
+ g = (packed >> 4) & 15;
+ b = (packed >> 1) & 7;
+
+ a = a << 1;
+
+ r = (r << 1) | (r >> 3);
+ g = (g << 1) | (g >> 3);
+ b = (b << 2) | (b >> 1);
+ }
+ else
+ {
+ a = (packed >> 12) & 7;
+ r = (packed >> 8) & 15;
+ g = (packed >> 4) & 15;
+ b = packed & 15;
+
+ a = a << 1;
+
+ r = (r << 1) | (r >> 3);
+ g = (g << 1) | (g >> 3);
+ b = (b << 1) | (b >> 3);
+ }
+ }
+
+ assert((r < 32) && (g < 32) && (b < 32) && (a < 16));
+
+ return color_rgba(r, g, b, a);
+ }
+
+ bool pvrtc4_image::get_interpolated_colors(uint32_t x, uint32_t y, color_rgba* pColors) const
+ {
+ assert((x < m_width) && (y < m_height));
+
+ int block_x0 = (static_cast<int>(x) - 2) >> 2;
+ int block_x1 = block_x0 + 1;
+ int block_y0 = (static_cast<int>(y) - 2) >> 2;
+ int block_y1 = block_y0 + 1;
+
+ block_x0 = posmod(block_x0, m_block_width);
+ block_x1 = posmod(block_x1, m_block_width);
+ block_y0 = posmod(block_y0, m_block_height);
+ block_y1 = posmod(block_y1, m_block_height);
+
+ pColors[0] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));
+ pColors[3] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));
+
+ if (get_block_uses_transparent_modulation(x >> 2, y >> 2))
+ {
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ uint32_t m = (pColors[0][c] + pColors[3][c]) / 2;
+ pColors[1][c] = static_cast<uint8_t>(m);
+ pColors[2][c] = static_cast<uint8_t>(m);
+ }
+ pColors[2][3] = 0;
+ return true;
+ }
+
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ pColors[1][c] = static_cast<uint8_t>((pColors[0][c] * 5 + pColors[3][c] * 3) / 8);
+ pColors[2][c] = static_cast<uint8_t>((pColors[0][c] * 3 + pColors[3][c] * 5) / 8);
+ }
+
+ return false;
+ }
+
+ color_rgba pvrtc4_image::get_pixel(uint32_t x, uint32_t y, uint32_t m) const
+ {
+ assert((x < m_width) && (y < m_height));
+
+ int block_x0 = (static_cast<int>(x) - 2) >> 2;
+ int block_x1 = block_x0 + 1;
+ int block_y0 = (static_cast<int>(y) - 2) >> 2;
+ int block_y1 = block_y0 + 1;
+
+ block_x0 = posmod(block_x0, m_block_width);
+ block_x1 = posmod(block_x1, m_block_width);
+ block_y0 = posmod(block_y0, m_block_height);
+ block_y1 = posmod(block_y1, m_block_height);
+
+ if (get_block_uses_transparent_modulation(x >> 2, y >> 2))
+ {
+ if (m == 0)
+ return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));
+ else if (m == 3)
+ return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));
+
+ color_rgba l(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0)));
+ color_rgba h(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1)));
+
+ return color_rgba((l[0] + h[0]) / 2, (l[1] + h[1]) / 2, (l[2] + h[2]) / 2, (m == 2) ? 0 : (l[3] + h[3]) / 2);
+ }
+ else
+ {
+ if (m == 0)
+ return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));
+ else if (m == 3)
+ return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));
+
+ color_rgba l(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0)));
+ color_rgba h(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1)));
+
+ if (m == 2)
+ return color_rgba((l[0] * 3 + h[0] * 5) / 8, (l[1] * 3 + h[1] * 5) / 8, (l[2] * 3 + h[2] * 5) / 8, (l[3] * 3 + h[3] * 5) / 8);
+ else
+ return color_rgba((l[0] * 5 + h[0] * 3) / 8, (l[1] * 5 + h[1] * 3) / 8, (l[2] * 5 + h[2] * 3) / 8, (l[3] * 5 + h[3] * 3) / 8);
+ }
+ }
+
+ uint64_t pvrtc4_image::local_endpoint_optimization_opaque(uint32_t bx, uint32_t by, const image& orig_img, bool perceptual)
+ {
+ uint64_t initial_error = evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false);
+ if (!initial_error)
+ return initial_error;
+
+ vec3F c_avg_orig(0);
+
+ for (int y = 0; y < 7; y++)
+ {
+ const uint32_t py = wrap_y(by * 4 + y - 1);
+ for (uint32_t x = 0; x < 7; x++)
+ {
+ const uint32_t px = wrap_x(bx * 4 + x - 1);
+
+ const color_rgba& c = orig_img(px, py);
+
+ c_avg_orig[0] += c[0];
+ c_avg_orig[1] += c[1];
+ c_avg_orig[2] += c[2];
+ }
+ }
+
+ c_avg_orig *= 1.0f / 49.0f;
+
+ vec3F quant_colors[2];
+ quant_colors[0].set(c_avg_orig);
+ quant_colors[0] -= vec3F(.0125f);
+
+ quant_colors[1].set(c_avg_orig);
+ quant_colors[1] += vec3F(.0125f);
+
+ float total_weight[2];
+
+ bool success = true;
+
+ for (uint32_t pass = 0; pass < 4; pass++)
+ {
+ vec3F new_colors[2] = { vec3F(0), vec3F(0) };
+ memset(total_weight, 0, sizeof(total_weight));
+
+ static const float s_weights[7][7] =
+ {
+ { 1.000000f, 1.637089f, 2.080362f, 2.242640f, 2.080362f, 1.637089f, 1.000000f },
+ { 1.637089f, 2.414213f, 3.006572f, 3.242640f, 3.006572f, 2.414213f, 1.637089f },
+ { 2.080362f, 3.006572f, 3.828426f, 4.242640f, 3.828426f, 3.006572f, 2.080362f },
+ { 2.242640f, 3.242640f, 4.242640f, 5.000000f, 4.242640f, 3.242640f, 2.242640f },
+ { 2.080362f, 3.006572f, 3.828426f, 4.242640f, 3.828426f, 3.006572f, 2.080362f },
+ { 1.637089f, 2.414213f, 3.006572f, 3.242640f, 3.006572f, 2.414213f, 1.637089f },
+ { 1.000000f, 1.637089f, 2.080362f, 2.242640f, 2.080362f, 1.637089f, 1.000000f }
+ };
+
+ for (int y = 0; y < 7; y++)
+ {
+ const uint32_t py = wrap_y(by * 4 + y - 1);
+ for (uint32_t x = 0; x < 7; x++)
+ {
+ const uint32_t px = wrap_x(bx * 4 + x - 1);
+
+ const color_rgba& orig_c = orig_img(px, py);
+
+ vec3F color(orig_c[0], orig_c[1], orig_c[2]);
+
+ uint32_t c = quant_colors[0].squared_distance(color) > quant_colors[1].squared_distance(color);
+
+ const float weight = s_weights[y][x];
+ new_colors[c] += color * weight;
+
+ total_weight[c] += weight;
+ }
+ }
+
+ if (!total_weight[0] || !total_weight[1])
+ success = false;
+
+ quant_colors[0] = new_colors[0] / (float)total_weight[0];
+ quant_colors[1] = new_colors[1] / (float)total_weight[1];
+ }
+
+ if (!success)
+ {
+ quant_colors[0] = c_avg_orig;
+ quant_colors[1] = c_avg_orig;
+ }
+
+ vec4F colors[2] = { quant_colors[0], quant_colors[1] };
+
+ colors[0] += vec3F(.5f);
+ colors[1] += vec3F(.5f);
+ color_rgba color_0((int)colors[0][0], (int)colors[0][1], (int)colors[0][2], 0);
+ color_rgba color_1((int)colors[1][0], (int)colors[1][1], (int)colors[1][2], 0);
+
+ pvrtc4_block cur_blocks[3][3];
+
+ for (int y = -1; y <= 1; y++)
+ {
+ for (int x = -1; x <= 1; x++)
+ {
+ const uint32_t block_x = wrap_block_x(bx + x);
+ const uint32_t block_y = wrap_block_y(by + y);
+ cur_blocks[x + 1][y + 1] = m_blocks(block_x, block_y);
+ }
+ }
+
+ color_rgba l1(0), h1(0);
+
+ l1[0] = g_pvrtc_5_nearest[color_0[0]];
+ h1[0] = g_pvrtc_5_nearest[color_1[0]];
+
+ l1[1] = g_pvrtc_5_nearest[color_0[1]];
+ h1[1] = g_pvrtc_5_nearest[color_1[1]];
+
+ l1[2] = g_pvrtc_4_nearest[color_0[2]];
+ h1[2] = g_pvrtc_5_nearest[color_0[2]];
+
+ l1[3] = 0;
+ h1[3] = 0;
+
+ m_blocks(bx, by).set_endpoint_raw(0, l1, true);
+ m_blocks(bx, by).set_endpoint_raw(1, h1, true);
+
+ uint64_t e03_err_0 = remap_pixels_influenced_by_endpoint(bx, by, orig_img, perceptual, false);
+
+ pvrtc4_block blocks0[3][3];
+ for (int y = -1; y <= 1; y++)
+ {
+ for (int x = -1; x <= 1; x++)
+ {
+ const uint32_t block_x = wrap_block_x(bx + x);
+ const uint32_t block_y = wrap_block_y(by + y);
+ blocks0[x + 1][y + 1] = m_blocks(block_x, block_y);
+ }
+ }
+
+ l1[0] = g_pvrtc_5_nearest[color_1[0]];
+ h1[0] = g_pvrtc_5_nearest[color_0[0]];
+
+ l1[1] = g_pvrtc_5_nearest[color_1[1]];
+ h1[1] = g_pvrtc_5_nearest[color_0[1]];
+
+ l1[2] = g_pvrtc_4_nearest[color_1[2]];
+ h1[2] = g_pvrtc_5_nearest[color_0[2]];
+
+ l1[3] = 0;
+ h1[3] = 0;
+
+ m_blocks(bx, by).set_endpoint_raw(0, l1, true);
+ m_blocks(bx, by).set_endpoint_raw(1, h1, true);
+
+ uint64_t e03_err_1 = remap_pixels_influenced_by_endpoint(bx, by, orig_img, perceptual, false);
+
+ if (initial_error < basisu::minimum(e03_err_0, e03_err_1))
+ {
+ for (int y = -1; y <= 1; y++)
+ {
+ for (int x = -1; x <= 1; x++)
+ {
+ const uint32_t block_x = wrap_block_x(bx + x);
+ const uint32_t block_y = wrap_block_y(by + y);
+ m_blocks(block_x, block_y) = cur_blocks[x + 1][y + 1];
+ }
+ }
+ return initial_error;
+ }
+ else if (e03_err_0 < e03_err_1)
+ {
+ for (int y = -1; y <= 1; y++)
+ {
+ for (int x = -1; x <= 1; x++)
+ {
+ const uint32_t block_x = wrap_block_x(bx + x);
+ const uint32_t block_y = wrap_block_y(by + y);
+ m_blocks(block_x, block_y) = blocks0[x + 1][y + 1];
+ }
+ }
+ assert(e03_err_0 == evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false));
+ return e03_err_0;
+ }
+
+ assert(e03_err_1 == evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false));
+ return e03_err_1;
+ }
+
+} // basisu
diff --git a/thirdparty/basis_universal/basisu_pvrtc1_4.h b/thirdparty/basis_universal/encoder/basisu_pvrtc1_4.h
index 80b4413351..db6985a439 100644
--- a/thirdparty/basis_universal/basisu_pvrtc1_4.h
+++ b/thirdparty/basis_universal/encoder/basisu_pvrtc1_4.h
@@ -1,5 +1,5 @@
// basisu_pvrtc1_4.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -87,6 +87,14 @@ namespace basisu
return (m_modulation >> ((y * 4 + x) * 2)) & 3;
}
+ inline void set_modulation(uint32_t x, uint32_t y, uint32_t s)
+ {
+ assert((x < 4) && (y < 4) && (s < 4));
+ uint32_t n = (y * 4 + x) * 2;
+ m_modulation = (m_modulation & (~(3 << n))) | (s << n);
+ assert(get_modulation(x, y) == s);
+ }
+
// Scaled by 8
inline const uint32_t* get_scaled_modulation_values(bool block_uses_transparent_modulation) const
{
@@ -107,7 +115,7 @@ namespace basisu
}
// opaque endpoints: 554, 555
- // transparent endpoints: 3443 or 3444
+ // transparent endpoints: 3443, 3444
inline void set_endpoint_raw(uint32_t endpoint_index, const color_rgba& c, bool opaque_endpoint)
{
assert(endpoint_index < 2);
@@ -352,7 +360,93 @@ namespace basisu
return result;
}
-
+
+ inline void set_modulation(uint32_t x, uint32_t y, uint32_t s)
+ {
+ assert((x < m_width) && (y < m_height));
+ return m_blocks(x >> 2, y >> 2).set_modulation(x & 3, y & 3, s);
+ }
+
+ inline uint64_t map_pixel(uint32_t x, uint32_t y, const color_rgba& c, bool perceptual, bool alpha_is_significant, bool record = true)
+ {
+ color_rgba v[4];
+ get_interpolated_colors(x, y, v);
+
+ uint64_t best_dist = color_distance(perceptual, c, v[0], alpha_is_significant);
+ uint32_t best_v = 0;
+ for (uint32_t i = 1; i < 4; i++)
+ {
+ uint64_t dist = color_distance(perceptual, c, v[i], alpha_is_significant);
+ if (dist < best_dist)
+ {
+ best_dist = dist;
+ best_v = i;
+ }
+ }
+
+ if (record)
+ set_modulation(x, y, best_v);
+
+ return best_dist;
+ }
+
+ inline uint64_t remap_pixels_influenced_by_endpoint(uint32_t bx, uint32_t by, const image& orig_img, bool perceptual, bool alpha_is_significant)
+ {
+ uint64_t total_error = 0;
+
+ for (int yd = -3; yd <= 3; yd++)
+ {
+ const int y = wrap_y((int)by * 4 + 2 + yd);
+
+ for (int xd = -3; xd <= 3; xd++)
+ {
+ const int x = wrap_x((int)bx * 4 + 2 + xd);
+
+ total_error += map_pixel(x, y, orig_img(x, y), perceptual, alpha_is_significant);
+ }
+ }
+
+ return total_error;
+ }
+
+ inline uint64_t evaluate_1x1_endpoint_error(uint32_t bx, uint32_t by, const image& orig_img, bool perceptual, bool alpha_is_significant, uint64_t threshold_error = 0) const
+ {
+ uint64_t total_error = 0;
+
+ for (int yd = -3; yd <= 3; yd++)
+ {
+ const int y = wrap_y((int)by * 4 + 2 + yd);
+
+ for (int xd = -3; xd <= 3; xd++)
+ {
+ const int x = wrap_x((int)bx * 4 + 2 + xd);
+
+ total_error += color_distance(perceptual, get_pixel(x, y), orig_img(x, y), alpha_is_significant);
+
+ if ((threshold_error) && (total_error >= threshold_error))
+ return total_error;
+ }
+ }
+
+ return total_error;
+ }
+
+ uint64_t local_endpoint_optimization_opaque(uint32_t bx, uint32_t by, const image& orig_img, bool perceptual);
+
+ inline uint64_t map_all_pixels(const image& img, bool perceptual, bool alpha_is_significant)
+ {
+ assert(m_width == img.get_width());
+ assert(m_height == img.get_height());
+
+ uint64_t total_error = 0;
+ for (uint32_t y = 0; y < img.get_height(); y++)
+ for (uint32_t x = 0; x < img.get_width(); x++)
+ total_error += map_pixel(x, y, img(x, y), perceptual, alpha_is_significant);
+
+ return total_error;
+ }
+
+ public:
uint32_t m_width, m_height;
pvrtc4_block_vector2D m_blocks;
uint32_t m_block_width, m_block_height;
diff --git a/thirdparty/basis_universal/basisu_resample_filters.cpp b/thirdparty/basis_universal/encoder/basisu_resample_filters.cpp
index d0b2fd77bb..597cb3f618 100644
--- a/thirdparty/basis_universal/basisu_resample_filters.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_resample_filters.cpp
@@ -1,5 +1,5 @@
// basisu_resampler_filters.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -283,7 +283,7 @@ namespace basisu
return sum;
}
- static const float KAISER_ALPHA = 4.0;
+ //static const float KAISER_ALPHA = 4.0;
static double kaiser(double alpha, double half_width, double x)
{
const double ratio = (x / half_width);
@@ -310,10 +310,22 @@ namespace basisu
const resample_filter g_resample_filters[] =
{
- { "box", box_filter, BOX_FILTER_SUPPORT }, { "tent", tent_filter, TENT_FILTER_SUPPORT }, { "bell", bell_filter, BELL_SUPPORT }, { "b-spline", B_spline_filter, B_SPLINE_SUPPORT },
- { "mitchell", mitchell_filter, MITCHELL_SUPPORT }, { "lanczos3", lanczos3_filter, LANCZOS3_SUPPORT }, { "blackman", blackman_filter, BLACKMAN_SUPPORT }, { "lanczos4", lanczos4_filter, LANCZOS4_SUPPORT },
- { "lanczos6", lanczos6_filter, LANCZOS6_SUPPORT }, { "lanczos12", lanczos12_filter, LANCZOS12_SUPPORT }, { "kaiser", kaiser_filter, KAISER_SUPPORT }, { "gaussian", gaussian_filter, GAUSSIAN_SUPPORT },
- { "catmullrom", catmull_rom_filter, CATMULL_ROM_SUPPORT }, { "quadratic_interp", quadratic_interp_filter, QUADRATIC_SUPPORT }, { "quadratic_approx", quadratic_approx_filter, QUADRATIC_SUPPORT }, { "quadratic_mix", quadratic_mix_filter, QUADRATIC_SUPPORT },
+ { "box", box_filter, BOX_FILTER_SUPPORT },
+ { "tent", tent_filter, TENT_FILTER_SUPPORT },
+ { "bell", bell_filter, BELL_SUPPORT },
+ { "b-spline", B_spline_filter, B_SPLINE_SUPPORT },
+ { "mitchell", mitchell_filter, MITCHELL_SUPPORT },
+ { "blackman", blackman_filter, BLACKMAN_SUPPORT },
+ { "lanczos3", lanczos3_filter, LANCZOS3_SUPPORT },
+ { "lanczos4", lanczos4_filter, LANCZOS4_SUPPORT },
+ { "lanczos6", lanczos6_filter, LANCZOS6_SUPPORT },
+ { "lanczos12", lanczos12_filter, LANCZOS12_SUPPORT },
+ { "kaiser", kaiser_filter, KAISER_SUPPORT },
+ { "gaussian", gaussian_filter, GAUSSIAN_SUPPORT },
+ { "catmullrom", catmull_rom_filter, CATMULL_ROM_SUPPORT },
+ { "quadratic_interp", quadratic_interp_filter, QUADRATIC_SUPPORT },
+ { "quadratic_approx", quadratic_approx_filter, QUADRATIC_SUPPORT },
+ { "quadratic_mix", quadratic_mix_filter, QUADRATIC_SUPPORT },
};
const int g_num_resample_filters = BASISU_ARRAY_SIZE(g_resample_filters);
diff --git a/thirdparty/basis_universal/basisu_resampler.cpp b/thirdparty/basis_universal/encoder/basisu_resampler.cpp
index e193ce83ff..e193ce83ff 100644
--- a/thirdparty/basis_universal/basisu_resampler.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_resampler.cpp
diff --git a/thirdparty/basis_universal/basisu_resampler.h b/thirdparty/basis_universal/encoder/basisu_resampler.h
index c3f2e05c25..dc0978caeb 100644
--- a/thirdparty/basis_universal/basisu_resampler.h
+++ b/thirdparty/basis_universal/encoder/basisu_resampler.h
@@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
-#include "transcoder/basisu.h"
+#include "../transcoder/basisu.h"
#define BASISU_RESAMPLER_DEBUG_OPS (0)
#define BASISU_RESAMPLER_DEFAULT_FILTER "lanczos4"
diff --git a/thirdparty/basis_universal/basisu_resampler_filters.h b/thirdparty/basis_universal/encoder/basisu_resampler_filters.h
index 5659c5fe86..0ebb51c334 100644
--- a/thirdparty/basis_universal/basisu_resampler_filters.h
+++ b/thirdparty/basis_universal/encoder/basisu_resampler_filters.h
@@ -14,7 +14,7 @@
// limitations under the License.
#pragma once
-#include "transcoder/basisu.h"
+#include "../transcoder/basisu.h"
namespace basisu
{
diff --git a/thirdparty/basis_universal/basisu_ssim.cpp b/thirdparty/basis_universal/encoder/basisu_ssim.cpp
index cceb400b88..cceb400b88 100644
--- a/thirdparty/basis_universal/basisu_ssim.cpp
+++ b/thirdparty/basis_universal/encoder/basisu_ssim.cpp
diff --git a/thirdparty/basis_universal/basisu_ssim.h b/thirdparty/basis_universal/encoder/basisu_ssim.h
index 986ca3bbdf..986ca3bbdf 100644
--- a/thirdparty/basis_universal/basisu_ssim.h
+++ b/thirdparty/basis_universal/encoder/basisu_ssim.h
diff --git a/thirdparty/basis_universal/encoder/basisu_uastc_enc.cpp b/thirdparty/basis_universal/encoder/basisu_uastc_enc.cpp
new file mode 100644
index 0000000000..ca2b325693
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_uastc_enc.cpp
@@ -0,0 +1,4189 @@
+// basisu_uastc_enc.cpp
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "basisu_uastc_enc.h"
+#include "basisu_astc_decomp.h"
+#include "basisu_gpu_texture.h"
+#include "basisu_bc7enc.h"
+
+#ifdef _DEBUG
+// When BASISU_VALIDATE_UASTC_ENC is 1, we pack and unpack to/from UASTC and ASTC, then validate that each codec returns the exact same results. This is slower.
+#define BASISU_VALIDATE_UASTC_ENC 1
+#endif
+
+#define BASISU_SUPPORT_FORCE_MODE 0
+
+using namespace basist;
+
+namespace basisu
+{
+ const uint32_t MAX_ENCODE_RESULTS = 512;
+
+#if BASISU_VALIDATE_UASTC_ENC
+ static void validate_func(bool condition, int line)
+ {
+ if (!condition)
+ {
+ fprintf(stderr, "basisu_uastc_enc: Internal validation failed on line %u!\n", line);
+ }
+ }
+
+ #define VALIDATE(c) validate_func(c, __LINE__);
+#else
+ #define VALIDATE(c)
+#endif
+
+ enum dxt_constants
+ {
+ cDXT1SelectorBits = 2U, cDXT1SelectorValues = 1U << cDXT1SelectorBits, cDXT1SelectorMask = cDXT1SelectorValues - 1U,
+ cDXT5SelectorBits = 3U, cDXT5SelectorValues = 1U << cDXT5SelectorBits, cDXT5SelectorMask = cDXT5SelectorValues - 1U,
+ };
+
+ struct dxt1_block
+ {
+ enum { cTotalEndpointBytes = 2, cTotalSelectorBytes = 4 };
+
+ uint8_t m_low_color[cTotalEndpointBytes];
+ uint8_t m_high_color[cTotalEndpointBytes];
+ uint8_t m_selectors[cTotalSelectorBytes];
+
+ inline void clear() { basisu::clear_obj(*this); }
+
+ inline uint32_t get_high_color() const { return m_high_color[0] | (m_high_color[1] << 8U); }
+ inline uint32_t get_low_color() const { return m_low_color[0] | (m_low_color[1] << 8U); }
+ inline void set_low_color(uint16_t c) { m_low_color[0] = static_cast<uint8_t>(c & 0xFF); m_low_color[1] = static_cast<uint8_t>((c >> 8) & 0xFF); }
+ inline void set_high_color(uint16_t c) { m_high_color[0] = static_cast<uint8_t>(c & 0xFF); m_high_color[1] = static_cast<uint8_t>((c >> 8) & 0xFF); }
+ inline uint32_t get_selector(uint32_t x, uint32_t y) const { assert((x < 4U) && (y < 4U)); return (m_selectors[y] >> (x * cDXT1SelectorBits))& cDXT1SelectorMask; }
+ inline void set_selector(uint32_t x, uint32_t y, uint32_t val) { assert((x < 4U) && (y < 4U) && (val < 4U)); m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits))); m_selectors[y] |= (val << (x * cDXT1SelectorBits)); }
+
+ static uint16_t pack_color(const color_rgba& color, bool scaled, uint32_t bias = 127U)
+ {
+ uint32_t r = color.r, g = color.g, b = color.b;
+ if (scaled)
+ {
+ r = (r * 31U + bias) / 255U;
+ g = (g * 63U + bias) / 255U;
+ b = (b * 31U + bias) / 255U;
+ }
+ return static_cast<uint16_t>(basisu::minimum(b, 31U) | (basisu::minimum(g, 63U) << 5U) | (basisu::minimum(r, 31U) << 11U));
+ }
+
+ static uint16_t pack_unscaled_color(uint32_t r, uint32_t g, uint32_t b) { return static_cast<uint16_t>(b | (g << 5U) | (r << 11U)); }
+ };
+
+#define UASTC_WRITE_MODE_DESCS 0
+
+ static inline void uastc_write_bits(uint8_t* pBuf, uint32_t& bit_offset, uint64_t code, uint32_t codesize, const char* pDesc)
+ {
+ (void)pDesc;
+
+#if UASTC_WRITE_MODE_DESCS
+ if (pDesc)
+ printf("%s: %u %u\n", pDesc, bit_offset, codesize);
+#endif
+
+ assert((codesize == 64) || (code < (1ULL << codesize)));
+
+ while (codesize)
+ {
+ uint32_t byte_bit_offset = bit_offset & 7;
+ uint32_t bits_to_write = basisu::minimum<int>(codesize, 8 - byte_bit_offset);
+
+ pBuf[bit_offset >> 3] |= (code << byte_bit_offset);
+
+ code >>= bits_to_write;
+ codesize -= bits_to_write;
+ bit_offset += bits_to_write;
+ }
+ }
+
+ void pack_uastc(basist::uastc_block& blk, const uastc_encode_results& result, const etc_block& etc1_blk, uint32_t etc1_bias, const eac_a8_block& etc_eac_a8_blk, bool bc1_hint0, bool bc1_hint1)
+ {
+ if ((g_uastc_mode_has_alpha[result.m_uastc_mode]) && (result.m_uastc_mode != UASTC_MODE_INDEX_SOLID_COLOR))
+ {
+ assert(etc_eac_a8_blk.m_multiplier >= 1);
+ }
+
+ uint8_t buf[32];
+ memset(buf, 0, sizeof(buf));
+
+ uint32_t block_bit_offset = 0;
+
+#if UASTC_WRITE_MODE_DESCS
+ printf("**** Mode: %u\n", result.m_uastc_mode);
+#endif
+
+ uastc_write_bits(buf, block_bit_offset, g_uastc_mode_huff_codes[result.m_uastc_mode][0], g_uastc_mode_huff_codes[result.m_uastc_mode][1], "mode");
+
+ if (result.m_uastc_mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ uastc_write_bits(buf, block_bit_offset, result.m_solid_color.r, 8, "R");
+ uastc_write_bits(buf, block_bit_offset, result.m_solid_color.g, 8, "G");
+ uastc_write_bits(buf, block_bit_offset, result.m_solid_color.b, 8, "B");
+ uastc_write_bits(buf, block_bit_offset, result.m_solid_color.a, 8, "A");
+
+ uastc_write_bits(buf, block_bit_offset, etc1_blk.get_diff_bit(), 1, "ETC1D");
+ uastc_write_bits(buf, block_bit_offset, etc1_blk.get_inten_table(0), 3, "ETC1I");
+ uastc_write_bits(buf, block_bit_offset, etc1_blk.get_selector(0, 0), 2, "ETC1S");
+
+ uint32_t r, g, b;
+ if (etc1_blk.get_diff_bit())
+ etc_block::unpack_color5(r, g, b, etc1_blk.get_base5_color(), false);
+ else
+ etc_block::unpack_color4(r, g, b, etc1_blk.get_base4_color(0), false);
+
+ uastc_write_bits(buf, block_bit_offset, r, 5, "ETC1R");
+ uastc_write_bits(buf, block_bit_offset, g, 5, "ETC1G");
+ uastc_write_bits(buf, block_bit_offset, b, 5, "ETC1B");
+
+ memcpy(&blk, buf, sizeof(blk));
+ return;
+ }
+
+ if (g_uastc_mode_has_bc1_hint0[result.m_uastc_mode])
+ uastc_write_bits(buf, block_bit_offset, bc1_hint0, 1, "BC1H0");
+ else
+ {
+ assert(bc1_hint0 == false);
+ }
+
+ if (g_uastc_mode_has_bc1_hint1[result.m_uastc_mode])
+ uastc_write_bits(buf, block_bit_offset, bc1_hint1, 1, "BC1H1");
+ else
+ {
+ assert(bc1_hint1 == false);
+ }
+
+ uastc_write_bits(buf, block_bit_offset, etc1_blk.get_flip_bit(), 1, "ETC1F");
+ uastc_write_bits(buf, block_bit_offset, etc1_blk.get_diff_bit(), 1, "ETC1D");
+ uastc_write_bits(buf, block_bit_offset, etc1_blk.get_inten_table(0), 3, "ETC1I0");
+ uastc_write_bits(buf, block_bit_offset, etc1_blk.get_inten_table(1), 3, "ETC1I1");
+
+ if (g_uastc_mode_has_etc1_bias[result.m_uastc_mode])
+ uastc_write_bits(buf, block_bit_offset, etc1_bias, 5, "ETC1BIAS");
+ else
+ {
+ assert(etc1_bias == 0);
+ }
+
+ if (g_uastc_mode_has_alpha[result.m_uastc_mode])
+ {
+ const uint32_t etc2_hints = etc_eac_a8_blk.m_table | (etc_eac_a8_blk.m_multiplier << 4);
+
+ assert(etc2_hints > 0 && etc2_hints <= 0xFF);
+ uastc_write_bits(buf, block_bit_offset, etc2_hints, 8, "ETC2TM");
+ }
+
+ uint32_t subsets = 1;
+ switch (result.m_uastc_mode)
+ {
+ case 2:
+ case 4:
+ case 7:
+ case 9:
+ case 16:
+ uastc_write_bits(buf, block_bit_offset, result.m_common_pattern, 5, "PAT");
+ subsets = 2;
+ break;
+ case 3:
+ uastc_write_bits(buf, block_bit_offset, result.m_common_pattern, 4, "PAT");
+ subsets = 3;
+ break;
+ default:
+ break;
+ }
+
+#ifdef _DEBUG
+ uint32_t part_seed = 0;
+ switch (result.m_uastc_mode)
+ {
+ case 2:
+ case 4:
+ case 9:
+ case 16:
+ part_seed = g_astc_bc7_common_partitions2[result.m_common_pattern].m_astc;
+ break;
+ case 3:
+ part_seed = g_astc_bc7_common_partitions3[result.m_common_pattern].m_astc;
+ break;
+ case 7:
+ part_seed = g_bc7_3_astc2_common_partitions[result.m_common_pattern].m_astc2;
+ break;
+ default:
+ break;
+ }
+#endif
+
+ uint32_t total_planes = 1;
+ switch (result.m_uastc_mode)
+ {
+ case 6:
+ case 11:
+ case 13:
+ uastc_write_bits(buf, block_bit_offset, result.m_astc.m_ccs, 2, "COMPSEL");
+ total_planes = 2;
+ break;
+ case 17:
+ // CCS field is always 3 for dual plane LA.
+ assert(result.m_astc.m_ccs == 3);
+ total_planes = 2;
+ break;
+ default:
+ break;
+ }
+
+ uint8_t weights[32];
+ memcpy(weights, result.m_astc.m_weights, 16 * total_planes);
+
+ uint8_t endpoints[18];
+ memcpy(endpoints, result.m_astc.m_endpoints, sizeof(endpoints));
+
+ const uint32_t total_comps = g_uastc_mode_comps[result.m_uastc_mode];
+
+ // LLAA
+ // LLAA LLAA
+ // LLAA LLAA LLAA
+ // RRGGBB
+ // RRGGBB RRGGBB
+ // RRGGBB RRGGBB RRGGBB
+ // RRGGBBAA
+ // RRGGBBAA RRGGBBAA
+
+ const uint32_t weight_bits = g_uastc_mode_weight_bits[result.m_uastc_mode];
+
+ const uint8_t* pPartition_pattern;
+ const uint8_t* pSubset_anchor_indices = basist::get_anchor_indices(subsets, result.m_uastc_mode, result.m_common_pattern, pPartition_pattern);
+
+ for (uint32_t plane_index = 0; plane_index < total_planes; plane_index++)
+ {
+ for (uint32_t subset_index = 0; subset_index < subsets; subset_index++)
+ {
+ const uint32_t anchor_index = pSubset_anchor_indices[subset_index];
+
+#ifdef _DEBUG
+ if (subsets >= 2)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const uint32_t part_index = astc_compute_texel_partition(part_seed, i & 3, i >> 2, 0, subsets, true);
+ if (part_index == subset_index)
+ {
+ assert(anchor_index == i);
+ break;
+ }
+ }
+ }
+ else
+ {
+ assert(!anchor_index);
+ }
+#endif
+
+ // Check anchor weight's MSB - if it's set then invert this subset's weights and swap the endpoints
+ if (weights[anchor_index * total_planes + plane_index] & (1 << (weight_bits - 1)))
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const uint32_t part_index = pPartition_pattern[i];
+
+#ifdef _DEBUG
+ if (subsets >= 2)
+ {
+ assert(part_index == (uint32_t)astc_compute_texel_partition(part_seed, i & 3, i >> 2, 0, subsets, true));
+ }
+ else
+ {
+ assert(!part_index);
+ }
+#endif
+
+ if (part_index == subset_index)
+ weights[i * total_planes + plane_index] = ((1 << weight_bits) - 1) - weights[i * total_planes + plane_index];
+ }
+
+ if (total_planes == 2)
+ {
+ for (int c = 0; c < (int)total_comps; c++)
+ {
+ const uint32_t comp_plane = (total_comps == 2) ? c : ((c == result.m_astc.m_ccs) ? 1 : 0);
+
+ if (comp_plane == plane_index)
+ std::swap(endpoints[c * 2 + 0], endpoints[c * 2 + 1]);
+ }
+ }
+ else
+ {
+ for (uint32_t c = 0; c < total_comps; c++)
+ std::swap(endpoints[subset_index * total_comps * 2 + c * 2 + 0], endpoints[subset_index * total_comps * 2 + c * 2 + 1]);
+ }
+ }
+ } // subset_index
+ } // plane_index
+
+ const uint32_t total_values = total_comps * 2 * subsets;
+ const uint32_t endpoint_range = g_uastc_mode_endpoint_ranges[result.m_uastc_mode];
+
+ uint32_t bit_values[18];
+ uint32_t tq_values[8];
+ uint32_t total_tq_values = 0;
+ uint32_t tq_accum = 0;
+ uint32_t tq_mul = 1;
+
+ const uint32_t ep_bits = g_astc_bise_range_table[endpoint_range][0];
+ const uint32_t ep_trits = g_astc_bise_range_table[endpoint_range][1];
+ const uint32_t ep_quints = g_astc_bise_range_table[endpoint_range][2];
+
+ for (uint32_t i = 0; i < total_values; i++)
+ {
+ uint32_t val = endpoints[i];
+
+ uint32_t bits = val & ((1 << ep_bits) - 1);
+ uint32_t tq = val >> ep_bits;
+
+ bit_values[i] = bits;
+
+ if (ep_trits)
+ {
+ assert(tq < 3);
+ tq_accum += tq * tq_mul;
+ tq_mul *= 3;
+ if (tq_mul == 243)
+ {
+ tq_values[total_tq_values++] = tq_accum;
+ tq_accum = 0;
+ tq_mul = 1;
+ }
+ }
+ else if (ep_quints)
+ {
+ assert(tq < 5);
+ tq_accum += tq * tq_mul;
+ tq_mul *= 5;
+ if (tq_mul == 125)
+ {
+ tq_values[total_tq_values++] = tq_accum;
+ tq_accum = 0;
+ tq_mul = 1;
+ }
+ }
+ }
+
+ uint32_t total_endpoint_bits = 0;
+
+ for (uint32_t i = 0; i < total_tq_values; i++)
+ {
+ const uint32_t num_bits = ep_trits ? 8 : 7;
+ uastc_write_bits(buf, block_bit_offset, tq_values[i], num_bits, "ETQ");
+ total_endpoint_bits += num_bits;
+ }
+
+ if (tq_mul > 1)
+ {
+ uint32_t num_bits;
+ if (ep_trits)
+ {
+ if (tq_mul == 3)
+ num_bits = 2;
+ else if (tq_mul == 9)
+ num_bits = 4;
+ else if (tq_mul == 27)
+ num_bits = 5;
+ else //if (tq_mul == 81)
+ num_bits = 7;
+ }
+ else
+ {
+ if (tq_mul == 5)
+ num_bits = 3;
+ else //if (tq_mul == 25)
+ num_bits = 5;
+ }
+ uastc_write_bits(buf, block_bit_offset, tq_accum, num_bits, "ETQ");
+ total_endpoint_bits += num_bits;
+ }
+
+ for (uint32_t i = 0; i < total_values; i++)
+ {
+ uastc_write_bits(buf, block_bit_offset, bit_values[i], ep_bits, "EBITS");
+ total_endpoint_bits += ep_bits;
+ }
+
+#if UASTC_WRITE_MODE_DESCS
+ uint32_t weight_start = block_bit_offset;
+#endif
+
+ uint32_t total_weight_bits = 0;
+ const uint32_t plane_shift = (total_planes == 2) ? 1 : 0;
+ for (uint32_t i = 0; i < 16 * total_planes; i++)
+ {
+ uint32_t numbits = weight_bits;
+ for (uint32_t s = 0; s < subsets; s++)
+ {
+ if (pSubset_anchor_indices[s] == (i >> plane_shift))
+ {
+ numbits--;
+ break;
+ }
+ }
+
+ uastc_write_bits(buf, block_bit_offset, weights[i], numbits, nullptr);
+
+ total_weight_bits += numbits;
+ }
+
+#if UASTC_WRITE_MODE_DESCS
+ printf("WEIGHTS: %u %u\n", weight_start, total_weight_bits);
+#endif
+
+ assert(block_bit_offset <= 128);
+ memcpy(&blk, buf, sizeof(blk));
+
+#if UASTC_WRITE_MODE_DESCS
+ printf("Total bits: %u, endpoint bits: %u, weight bits: %u\n", block_bit_offset, total_endpoint_bits, total_weight_bits);
+#endif
+ }
+
+ // MODE 0
+ // 0. DualPlane: 0, WeightRange: 8 (16), Subsets: 1, CEM: 8 (RGB Direct ), EndpointRange: 19 (192) MODE6 RGB
+ // 18. DualPlane: 0, WeightRange: 11 (32), Subsets: 1, CEM: 8 (RGB Direct ), EndpointRange: 11 (32) MODE6 RGB
+ static void astc_mode0_or_18(uint32_t mode, const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params, const uint8_t *pForce_selectors = nullptr)
+ {
+ const uint32_t endpoint_range = (mode == 18) ? 11 : 19;
+ const uint32_t weight_range = (mode == 18) ? 11 : 8;
+
+ color_cell_compressor_params ccell_params;
+ memset(&ccell_params, 0, sizeof(ccell_params));
+
+ ccell_params.m_num_pixels = 16;
+ ccell_params.m_pPixels = (color_quad_u8*)&block[0][0];
+ ccell_params.m_num_selector_weights = (mode == 18) ? 32 : 16;
+ ccell_params.m_pSelector_weights = (mode == 18) ? g_astc_weights5 : g_astc_weights4;
+ ccell_params.m_pSelector_weightsx = (mode == 18) ? (const bc7enc_vec4F*)g_astc_weights5x : (const bc7enc_vec4F*)g_astc_weights4x;
+ ccell_params.m_astc_endpoint_range = endpoint_range;
+ ccell_params.m_weights[0] = 1;
+ ccell_params.m_weights[1] = 1;
+ ccell_params.m_weights[2] = 1;
+ ccell_params.m_weights[3] = 1;
+ ccell_params.m_pForce_selectors = pForce_selectors;
+
+ color_cell_compressor_results ccell_results;
+ uint8_t ccell_result_selectors[16];
+ uint8_t ccell_result_selectors_temp[16];
+ memset(&ccell_results, 0, sizeof(ccell_results));
+ ccell_results.m_pSelectors = &ccell_result_selectors[0];
+ ccell_results.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err = color_cell_compression(255, &ccell_params, &ccell_results, &comp_params);
+
+ // ASTC
+ astc_block_desc astc_results;
+ memset(&astc_results, 0, sizeof(astc_results));
+
+ astc_results.m_dual_plane = false;
+ astc_results.m_weight_range = weight_range;// (mode == 18) ? 11 : 8;
+
+ astc_results.m_ccs = 0;
+ astc_results.m_subsets = 1;
+ astc_results.m_partition_seed = 0;
+ astc_results.m_cem = 8;
+
+ astc_results.m_endpoints[0] = ccell_results.m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[1] = ccell_results.m_astc_high_endpoint.m_c[0];
+ astc_results.m_endpoints[2] = ccell_results.m_astc_low_endpoint.m_c[1];
+ astc_results.m_endpoints[3] = ccell_results.m_astc_high_endpoint.m_c[1];
+ astc_results.m_endpoints[4] = ccell_results.m_astc_low_endpoint.m_c[2];
+ astc_results.m_endpoints[5] = ccell_results.m_astc_high_endpoint.m_c[2];
+
+ bool invert = false;
+
+ if (pForce_selectors == nullptr)
+ {
+ int s0 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[0]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[2]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[1]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[3]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(astc_results.m_endpoints[0], astc_results.m_endpoints[1]);
+ std::swap(astc_results.m_endpoints[2], astc_results.m_endpoints[3]);
+ std::swap(astc_results.m_endpoints[4], astc_results.m_endpoints[5]);
+ invert = true;
+ }
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ astc_results.m_weights[x + y * 4] = ccell_result_selectors[x + y * 4];
+
+ if (invert)
+ astc_results.m_weights[x + y * 4] = ((mode == 18) ? 31 : 15) - astc_results.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = mode;
+ pResults[total_results].m_common_pattern = 0;
+ pResults[total_results].m_astc = astc_results;
+ pResults[total_results].m_astc_err = part_err;
+ total_results++;
+ }
+ }
+
+ // MODE 1
+ // 1-subset, 2-bit indices, 8-bit endpoints, BC7 mode 3
+ // DualPlane: 0, WeightRange: 2 (4), Subsets: 1, CEM: 8 (RGB Direct ), EndpointRange: 20 (256) MODE3 or MODE5 RGB
+ static void astc_mode1(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params)
+ {
+ color_cell_compressor_params ccell_params;
+ memset(&ccell_params, 0, sizeof(ccell_params));
+
+ ccell_params.m_num_pixels = 16;
+ ccell_params.m_pPixels = (color_quad_u8*)&block[0][0];
+ ccell_params.m_num_selector_weights = 4;
+ ccell_params.m_pSelector_weights = g_bc7_weights2;
+ ccell_params.m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights2x;
+ ccell_params.m_astc_endpoint_range = 20;
+ ccell_params.m_weights[0] = 1;
+ ccell_params.m_weights[1] = 1;
+ ccell_params.m_weights[2] = 1;
+ ccell_params.m_weights[3] = 1;
+
+ color_cell_compressor_results ccell_results;
+ uint8_t ccell_result_selectors[16];
+ uint8_t ccell_result_selectors_temp[16];
+ memset(&ccell_results, 0, sizeof(ccell_results));
+ ccell_results.m_pSelectors = &ccell_result_selectors[0];
+ ccell_results.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err = color_cell_compression(255, &ccell_params, &ccell_results, &comp_params);
+
+ // ASTC
+ astc_block_desc astc_results;
+ memset(&astc_results, 0, sizeof(astc_results));
+
+ astc_results.m_dual_plane = false;
+ astc_results.m_weight_range = 2;
+
+ astc_results.m_ccs = 0;
+ astc_results.m_subsets = 1;
+ astc_results.m_partition_seed = 0;
+ astc_results.m_cem = 8;
+
+ astc_results.m_endpoints[0] = ccell_results.m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[1] = ccell_results.m_astc_high_endpoint.m_c[0];
+ astc_results.m_endpoints[2] = ccell_results.m_astc_low_endpoint.m_c[1];
+ astc_results.m_endpoints[3] = ccell_results.m_astc_high_endpoint.m_c[1];
+ astc_results.m_endpoints[4] = ccell_results.m_astc_low_endpoint.m_c[2];
+ astc_results.m_endpoints[5] = ccell_results.m_astc_high_endpoint.m_c[2];
+
+ const uint32_t range = 20;
+
+ bool invert = false;
+
+ int s0 = g_astc_unquant[range][astc_results.m_endpoints[0]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[2]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[range][astc_results.m_endpoints[1]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[3]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(astc_results.m_endpoints[0], astc_results.m_endpoints[1]);
+ std::swap(astc_results.m_endpoints[2], astc_results.m_endpoints[3]);
+ std::swap(astc_results.m_endpoints[4], astc_results.m_endpoints[5]);
+ invert = true;
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ astc_results.m_weights[x + y * 4] = ccell_result_selectors[x + y * 4];
+
+ if (invert)
+ astc_results.m_weights[x + y * 4] = 3 - astc_results.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 1;
+ pResults[total_results].m_common_pattern = 0;
+ pResults[total_results].m_astc = astc_results;
+ pResults[total_results].m_astc_err = part_err;
+ total_results++;
+ }
+ }
+
+ static uint32_t estimate_partition2(uint32_t num_weights, uint32_t num_comps, const uint32_t* pWeights, const color_rgba block[4][4], const uint32_t weights[4])
+ {
+ assert(pWeights[0] == 0 && pWeights[num_weights - 1] == 64);
+
+ uint64_t best_err = UINT64_MAX;
+ uint32_t best_common_pattern = 0;
+
+ for (uint32_t common_pattern = 0; common_pattern < TOTAL_ASTC_BC7_COMMON_PARTITIONS2; common_pattern++)
+ {
+ const uint32_t bc7_pattern = g_astc_bc7_common_partitions2[common_pattern].m_bc7;
+
+ const uint8_t* pPartition = &g_bc7_partition2[bc7_pattern * 16];
+
+ color_quad_u8 subset_colors[2][16];
+ uint32_t subset_total_colors[2] = { 0, 0 };
+ for (uint32_t index = 0; index < 16; index++)
+ subset_colors[pPartition[index]][subset_total_colors[pPartition[index]]++] = ((const color_quad_u8*)block)[index];
+
+ uint64_t total_subset_err = 0;
+ for (uint32_t subset = 0; (subset < 2) && (total_subset_err < best_err); subset++)
+ total_subset_err += color_cell_compression_est_astc(num_weights, num_comps, pWeights, subset_total_colors[subset], &subset_colors[subset][0], best_err, weights);
+
+ if (total_subset_err < best_err)
+ {
+ best_err = total_subset_err;
+ best_common_pattern = common_pattern;
+ }
+ }
+
+ return best_common_pattern;
+ }
+
+ // MODE 2
+ // 2-subset, 3-bit indices, 4-bit endpoints, BC7 mode 1
+ // DualPlane: 0, WeightRange: 5 (8), Subsets: 2, CEM: 8 (RGB Direct ), EndpointRange: 8 (16) MODE1
+ static void astc_mode2(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params, bool estimate_partition)
+ {
+ uint32_t first_common_pattern = 0;
+ uint32_t last_common_pattern = TOTAL_ASTC_BC7_COMMON_PARTITIONS2;
+
+ if (estimate_partition)
+ {
+ const uint32_t weights[4] = { 1, 1, 1, 1 };
+ first_common_pattern = estimate_partition2(8, 3, g_bc7_weights3, block, weights);
+ last_common_pattern = first_common_pattern + 1;
+ }
+
+ for (uint32_t common_pattern = first_common_pattern; common_pattern < last_common_pattern; common_pattern++)
+ {
+ const uint32_t bc7_pattern = g_astc_bc7_common_partitions2[common_pattern].m_bc7;
+
+ color_rgba part_pixels[2][16];
+ uint32_t part_pixel_index[4][4];
+ uint32_t num_part_pixels[2] = { 0, 0 };
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t part = g_bc7_partition2[16 * bc7_pattern + x + y * 4];
+ part_pixel_index[y][x] = num_part_pixels[part];
+ part_pixels[part][num_part_pixels[part]++] = block[y][x];
+ }
+ }
+
+ color_cell_compressor_params ccell_params[2];
+ color_cell_compressor_results ccell_results[2];
+ uint8_t ccell_result_selectors[2][16];
+ uint8_t ccell_result_selectors_temp[2][16];
+
+ uint64_t total_part_err = 0;
+ for (uint32_t part = 0; part < 2; part++)
+ {
+ memset(&ccell_params[part], 0, sizeof(ccell_params[part]));
+
+ ccell_params[part].m_num_pixels = num_part_pixels[part];
+ ccell_params[part].m_pPixels = (color_quad_u8*)&part_pixels[part][0];
+ ccell_params[part].m_num_selector_weights = 8;
+ ccell_params[part].m_pSelector_weights = g_bc7_weights3;
+ ccell_params[part].m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights3x;
+ ccell_params[part].m_astc_endpoint_range = 8;
+ ccell_params[part].m_weights[0] = 1;
+ ccell_params[part].m_weights[1] = 1;
+ ccell_params[part].m_weights[2] = 1;
+ ccell_params[part].m_weights[3] = 1;
+
+ memset(&ccell_results[part], 0, sizeof(ccell_results[part]));
+ ccell_results[part].m_pSelectors = &ccell_result_selectors[part][0];
+ ccell_results[part].m_pSelectors_temp = &ccell_result_selectors_temp[part][0];
+
+ uint64_t part_err = color_cell_compression(255, &ccell_params[part], &ccell_results[part], &comp_params);
+ total_part_err += part_err;
+ } // part
+
+ {
+ // ASTC
+ astc_block_desc astc_results;
+ memset(&astc_results, 0, sizeof(astc_results));
+
+ astc_results.m_dual_plane = false;
+ astc_results.m_weight_range = 5;
+
+ astc_results.m_ccs = 0;
+ astc_results.m_subsets = 2;
+ astc_results.m_partition_seed = g_astc_bc7_common_partitions2[common_pattern].m_astc;
+ astc_results.m_cem = 8;
+
+ uint32_t p0 = 0;
+ uint32_t p1 = 1;
+ if (g_astc_bc7_common_partitions2[common_pattern].m_invert)
+ std::swap(p0, p1);
+
+ astc_results.m_endpoints[0] = ccell_results[p0].m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[1] = ccell_results[p0].m_astc_high_endpoint.m_c[0];
+ astc_results.m_endpoints[2] = ccell_results[p0].m_astc_low_endpoint.m_c[1];
+ astc_results.m_endpoints[3] = ccell_results[p0].m_astc_high_endpoint.m_c[1];
+ astc_results.m_endpoints[4] = ccell_results[p0].m_astc_low_endpoint.m_c[2];
+ astc_results.m_endpoints[5] = ccell_results[p0].m_astc_high_endpoint.m_c[2];
+
+ const uint32_t range = 8;
+
+ bool invert[2] = { false, false };
+
+ int s0 = g_astc_unquant[range][astc_results.m_endpoints[0]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[2]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[range][astc_results.m_endpoints[1]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[3]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(astc_results.m_endpoints[0], astc_results.m_endpoints[1]);
+ std::swap(astc_results.m_endpoints[2], astc_results.m_endpoints[3]);
+ std::swap(astc_results.m_endpoints[4], astc_results.m_endpoints[5]);
+ invert[0] = true;
+ }
+
+ astc_results.m_endpoints[6] = ccell_results[p1].m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[7] = ccell_results[p1].m_astc_high_endpoint.m_c[0];
+ astc_results.m_endpoints[8] = ccell_results[p1].m_astc_low_endpoint.m_c[1];
+ astc_results.m_endpoints[9] = ccell_results[p1].m_astc_high_endpoint.m_c[1];
+ astc_results.m_endpoints[10] = ccell_results[p1].m_astc_low_endpoint.m_c[2];
+ astc_results.m_endpoints[11] = ccell_results[p1].m_astc_high_endpoint.m_c[2];
+
+ s0 = g_astc_unquant[range][astc_results.m_endpoints[0 + 6]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[2 + 6]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[4 + 6]].m_unquant;
+ s1 = g_astc_unquant[range][astc_results.m_endpoints[1 + 6]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[3 + 6]].m_unquant + g_astc_unquant[range][astc_results.m_endpoints[5 + 6]].m_unquant;
+
+ if (s1 < s0)
+ {
+ std::swap(astc_results.m_endpoints[0 + 6], astc_results.m_endpoints[1 + 6]);
+ std::swap(astc_results.m_endpoints[2 + 6], astc_results.m_endpoints[3 + 6]);
+ std::swap(astc_results.m_endpoints[4 + 6], astc_results.m_endpoints[5 + 6]);
+ invert[1] = true;
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t bc7_part = g_bc7_partition2[16 * bc7_pattern + x + y * 4];
+
+ astc_results.m_weights[x + y * 4] = ccell_result_selectors[bc7_part][part_pixel_index[y][x]];
+
+ uint32_t astc_part = bc7_part;
+ if (g_astc_bc7_common_partitions2[common_pattern].m_invert)
+ astc_part = 1 - astc_part;
+
+ if (invert[astc_part])
+ astc_results.m_weights[x + y * 4] = 7 - astc_results.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 2;
+ pResults[total_results].m_common_pattern = common_pattern;
+ pResults[total_results].m_astc = astc_results;
+ pResults[total_results].m_astc_err = total_part_err;
+ total_results++;
+ }
+ }
+
+ } // common_pattern
+ }
+
+ // MODE 3
+ // 3-subsets, 2-bit indices, [0,11] endpoints, BC7 mode 2
+ // DualPlane: 0, WeightRange: 2 (4), Subsets: 3, CEM: 8 (RGB Direct ), EndpointRange: 7 (12) MODE2
+ static void astc_mode3(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params, bool estimate_partition)
+ {
+ uint32_t first_common_pattern = 0;
+ uint32_t last_common_pattern = TOTAL_ASTC_BC7_COMMON_PARTITIONS3;
+
+ if (estimate_partition)
+ {
+ uint64_t best_err = UINT64_MAX;
+ uint32_t best_common_pattern = 0;
+ const uint32_t weights[4] = { 1, 1, 1, 1 };
+
+ for (uint32_t common_pattern = 0; common_pattern < TOTAL_ASTC_BC7_COMMON_PARTITIONS3; common_pattern++)
+ {
+ const uint32_t bc7_pattern = g_astc_bc7_common_partitions3[common_pattern].m_bc7;
+
+ const uint8_t* pPartition = &g_bc7_partition3[bc7_pattern * 16];
+
+ color_quad_u8 subset_colors[3][16];
+ uint32_t subset_total_colors[3] = { 0, 0 };
+ for (uint32_t index = 0; index < 16; index++)
+ subset_colors[pPartition[index]][subset_total_colors[pPartition[index]]++] = ((const color_quad_u8*)block)[index];
+
+ uint64_t total_subset_err = 0;
+ for (uint32_t subset = 0; (subset < 3) && (total_subset_err < best_err); subset++)
+ total_subset_err += color_cell_compression_est_astc(4, 3, g_bc7_weights2, subset_total_colors[subset], &subset_colors[subset][0], best_err, weights);
+
+ if (total_subset_err < best_err)
+ {
+ best_err = total_subset_err;
+ best_common_pattern = common_pattern;
+ }
+ }
+
+ first_common_pattern = best_common_pattern;
+ last_common_pattern = best_common_pattern + 1;
+ }
+
+ for (uint32_t common_pattern = first_common_pattern; common_pattern < last_common_pattern; common_pattern++)
+ {
+ const uint32_t endpoint_range = 7;
+
+ const uint32_t bc7_pattern = g_astc_bc7_common_partitions3[common_pattern].m_bc7;
+
+ color_rgba part_pixels[3][16];
+ uint32_t part_pixel_index[4][4];
+ uint32_t num_part_pixels[3] = { 0, 0, 0 };
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t bc7_part = g_bc7_partition3[16 * bc7_pattern + x + y * 4];
+ part_pixel_index[y][x] = num_part_pixels[bc7_part];
+ part_pixels[bc7_part][num_part_pixels[bc7_part]++] = block[y][x];
+ }
+ }
+
+ color_cell_compressor_params ccell_params[3];
+ color_cell_compressor_results ccell_results[3];
+ uint8_t ccell_result_selectors[3][16];
+ uint8_t ccell_result_selectors_temp[3][16];
+
+ uint64_t total_part_err = 0;
+ for (uint32_t bc7_part = 0; bc7_part < 3; bc7_part++)
+ {
+ memset(&ccell_params[bc7_part], 0, sizeof(ccell_params[bc7_part]));
+
+ ccell_params[bc7_part].m_num_pixels = num_part_pixels[bc7_part];
+ ccell_params[bc7_part].m_pPixels = (color_quad_u8*)&part_pixels[bc7_part][0];
+ ccell_params[bc7_part].m_num_selector_weights = 4;
+ ccell_params[bc7_part].m_pSelector_weights = g_bc7_weights2;
+ ccell_params[bc7_part].m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights2x;
+ ccell_params[bc7_part].m_astc_endpoint_range = endpoint_range;
+ ccell_params[bc7_part].m_weights[0] = 1;
+ ccell_params[bc7_part].m_weights[1] = 1;
+ ccell_params[bc7_part].m_weights[2] = 1;
+ ccell_params[bc7_part].m_weights[3] = 1;
+
+ memset(&ccell_results[bc7_part], 0, sizeof(ccell_results[bc7_part]));
+ ccell_results[bc7_part].m_pSelectors = &ccell_result_selectors[bc7_part][0];
+ ccell_results[bc7_part].m_pSelectors_temp = &ccell_result_selectors_temp[bc7_part][0];
+
+ uint64_t part_err = color_cell_compression(255, &ccell_params[bc7_part], &ccell_results[bc7_part], &comp_params);
+ total_part_err += part_err;
+ } // part
+
+ {
+ // ASTC
+ astc_block_desc astc_results;
+ memset(&astc_results, 0, sizeof(astc_results));
+
+ astc_results.m_dual_plane = false;
+ astc_results.m_weight_range = 2;
+
+ astc_results.m_ccs = 0;
+ astc_results.m_subsets = 3;
+ astc_results.m_partition_seed = g_astc_bc7_common_partitions3[common_pattern].m_astc;
+ astc_results.m_cem = 8;
+
+ uint32_t astc_to_bc7_part[3]; // converts ASTC to BC7 partition index
+ const uint32_t perm = g_astc_bc7_common_partitions3[common_pattern].m_astc_to_bc7_perm;
+ astc_to_bc7_part[0] = g_astc_to_bc7_partition_index_perm_tables[perm][0];
+ astc_to_bc7_part[1] = g_astc_to_bc7_partition_index_perm_tables[perm][1];
+ astc_to_bc7_part[2] = g_astc_to_bc7_partition_index_perm_tables[perm][2];
+
+ bool invert_astc_part[3] = { false, false, false };
+
+ for (uint32_t astc_part = 0; astc_part < 3; astc_part++)
+ {
+ uint8_t* pEndpoints = &astc_results.m_endpoints[6 * astc_part];
+
+ pEndpoints[0] = ccell_results[astc_to_bc7_part[astc_part]].m_astc_low_endpoint.m_c[0];
+ pEndpoints[1] = ccell_results[astc_to_bc7_part[astc_part]].m_astc_high_endpoint.m_c[0];
+ pEndpoints[2] = ccell_results[astc_to_bc7_part[astc_part]].m_astc_low_endpoint.m_c[1];
+ pEndpoints[3] = ccell_results[astc_to_bc7_part[astc_part]].m_astc_high_endpoint.m_c[1];
+ pEndpoints[4] = ccell_results[astc_to_bc7_part[astc_part]].m_astc_low_endpoint.m_c[2];
+ pEndpoints[5] = ccell_results[astc_to_bc7_part[astc_part]].m_astc_high_endpoint.m_c[2];
+
+ int s0 = g_astc_unquant[endpoint_range][pEndpoints[0]].m_unquant + g_astc_unquant[endpoint_range][pEndpoints[2]].m_unquant + g_astc_unquant[endpoint_range][pEndpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][pEndpoints[1]].m_unquant + g_astc_unquant[endpoint_range][pEndpoints[3]].m_unquant + g_astc_unquant[endpoint_range][pEndpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(pEndpoints[0], pEndpoints[1]);
+ std::swap(pEndpoints[2], pEndpoints[3]);
+ std::swap(pEndpoints[4], pEndpoints[5]);
+ invert_astc_part[astc_part] = true;
+ }
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t bc7_part = g_bc7_partition3[16 * bc7_pattern + x + y * 4];
+
+ astc_results.m_weights[x + y * 4] = ccell_result_selectors[bc7_part][part_pixel_index[y][x]];
+
+ uint32_t astc_part = 0;
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ if (astc_to_bc7_part[i] == bc7_part)
+ {
+ astc_part = i;
+ break;
+ }
+ }
+
+ if (invert_astc_part[astc_part])
+ astc_results.m_weights[x + y * 4] = 3 - astc_results.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 3;
+ pResults[total_results].m_common_pattern = common_pattern;
+ pResults[total_results].m_astc = astc_results;
+ pResults[total_results].m_astc_err = total_part_err;
+ total_results++;
+ }
+
+ }
+
+ } // common_pattern
+ }
+
+ // MODE 4
+ // DualPlane: 0, WeightRange: 2 (4), Subsets: 2, CEM: 8 (RGB Direct ), EndpointRange: 12 (40) MODE3
+ static void astc_mode4(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params, bool estimate_partition)
+ {
+ //const uint32_t weight_range = 2;
+ const uint32_t endpoint_range = 12;
+
+ uint32_t first_common_pattern = 0;
+ uint32_t last_common_pattern = TOTAL_ASTC_BC7_COMMON_PARTITIONS2;
+
+ if (estimate_partition)
+ {
+ const uint32_t weights[4] = { 1, 1, 1, 1 };
+ first_common_pattern = estimate_partition2(4, 3, g_bc7_weights2, block, weights);
+ last_common_pattern = first_common_pattern + 1;
+ }
+
+ for (uint32_t common_pattern = first_common_pattern; common_pattern < last_common_pattern; common_pattern++)
+ {
+ const uint32_t bc7_pattern = g_astc_bc7_common_partitions2[common_pattern].m_bc7;
+
+ color_rgba part_pixels[2][16];
+ uint32_t part_pixel_index[4][4];
+ uint32_t num_part_pixels[2] = { 0, 0 };
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t part = g_bc7_partition2[16 * bc7_pattern + x + y * 4];
+ part_pixel_index[y][x] = num_part_pixels[part];
+ part_pixels[part][num_part_pixels[part]++] = block[y][x];
+ }
+ }
+
+ color_cell_compressor_params ccell_params[2];
+ color_cell_compressor_results ccell_results[2];
+ uint8_t ccell_result_selectors[2][16];
+ uint8_t ccell_result_selectors_temp[2][16];
+
+ uint64_t total_part_err = 0;
+ for (uint32_t part = 0; part < 2; part++)
+ {
+ memset(&ccell_params[part], 0, sizeof(ccell_params[part]));
+
+ ccell_params[part].m_num_pixels = num_part_pixels[part];
+ ccell_params[part].m_pPixels = (color_quad_u8*)&part_pixels[part][0];
+ ccell_params[part].m_num_selector_weights = 4;
+ ccell_params[part].m_pSelector_weights = g_bc7_weights2;
+ ccell_params[part].m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights2x;
+ ccell_params[part].m_astc_endpoint_range = endpoint_range;
+ ccell_params[part].m_weights[0] = 1;
+ ccell_params[part].m_weights[1] = 1;
+ ccell_params[part].m_weights[2] = 1;
+ ccell_params[part].m_weights[3] = 1;
+
+ memset(&ccell_results[part], 0, sizeof(ccell_results[part]));
+ ccell_results[part].m_pSelectors = &ccell_result_selectors[part][0];
+ ccell_results[part].m_pSelectors_temp = &ccell_result_selectors_temp[part][0];
+
+ uint64_t part_err = color_cell_compression(255, &ccell_params[part], &ccell_results[part], &comp_params);
+ total_part_err += part_err;
+ } // part
+
+ // ASTC
+ astc_block_desc astc_results;
+ memset(&astc_results, 0, sizeof(astc_results));
+
+ astc_results.m_dual_plane = false;
+ astc_results.m_weight_range = 2;
+
+ astc_results.m_ccs = 0;
+ astc_results.m_subsets = 2;
+ astc_results.m_partition_seed = g_astc_bc7_common_partitions2[common_pattern].m_astc;
+ astc_results.m_cem = 8;
+
+ uint32_t p0 = 0;
+ uint32_t p1 = 1;
+ if (g_astc_bc7_common_partitions2[common_pattern].m_invert)
+ std::swap(p0, p1);
+
+ astc_results.m_endpoints[0] = ccell_results[p0].m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[1] = ccell_results[p0].m_astc_high_endpoint.m_c[0];
+ astc_results.m_endpoints[2] = ccell_results[p0].m_astc_low_endpoint.m_c[1];
+ astc_results.m_endpoints[3] = ccell_results[p0].m_astc_high_endpoint.m_c[1];
+ astc_results.m_endpoints[4] = ccell_results[p0].m_astc_low_endpoint.m_c[2];
+ astc_results.m_endpoints[5] = ccell_results[p0].m_astc_high_endpoint.m_c[2];
+
+ bool invert[2] = { false, false };
+
+ int s0 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[0]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[2]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[1]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[3]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(astc_results.m_endpoints[0], astc_results.m_endpoints[1]);
+ std::swap(astc_results.m_endpoints[2], astc_results.m_endpoints[3]);
+ std::swap(astc_results.m_endpoints[4], astc_results.m_endpoints[5]);
+ invert[0] = true;
+ }
+
+ astc_results.m_endpoints[6] = ccell_results[p1].m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[7] = ccell_results[p1].m_astc_high_endpoint.m_c[0];
+ astc_results.m_endpoints[8] = ccell_results[p1].m_astc_low_endpoint.m_c[1];
+ astc_results.m_endpoints[9] = ccell_results[p1].m_astc_high_endpoint.m_c[1];
+ astc_results.m_endpoints[10] = ccell_results[p1].m_astc_low_endpoint.m_c[2];
+ astc_results.m_endpoints[11] = ccell_results[p1].m_astc_high_endpoint.m_c[2];
+
+ s0 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[0 + 6]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[2 + 6]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[4 + 6]].m_unquant;
+ s1 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[1 + 6]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[3 + 6]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[5 + 6]].m_unquant;
+
+ if (s1 < s0)
+ {
+ std::swap(astc_results.m_endpoints[0 + 6], astc_results.m_endpoints[1 + 6]);
+ std::swap(astc_results.m_endpoints[2 + 6], astc_results.m_endpoints[3 + 6]);
+ std::swap(astc_results.m_endpoints[4 + 6], astc_results.m_endpoints[5 + 6]);
+ invert[1] = true;
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t bc7_part = g_bc7_partition2[16 * bc7_pattern + x + y * 4];
+
+ astc_results.m_weights[x + y * 4] = ccell_result_selectors[bc7_part][part_pixel_index[y][x]];
+
+ uint32_t astc_part = bc7_part;
+ if (g_astc_bc7_common_partitions2[common_pattern].m_invert)
+ astc_part = 1 - astc_part;
+
+ if (invert[astc_part])
+ astc_results.m_weights[x + y * 4] = 3 - astc_results.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 4;
+ pResults[total_results].m_common_pattern = common_pattern;
+ pResults[total_results].m_astc = astc_results;
+ pResults[total_results].m_astc_err = total_part_err;
+ total_results++;
+ }
+
+ } // common_pattern
+ }
+
+ // MODE 5
+ // DualPlane: 0, WeightRange: 5 (8), Subsets: 1, CEM: 8 (RGB Direct ), EndpointRange: 20 (256) BC7 MODE 6 (or MODE 1 1-subset)
+ static void astc_mode5(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params)
+ {
+ const uint32_t weight_range = 5;
+ const uint32_t endpoint_range = 20;
+
+ color_cell_compressor_params ccell_params;
+ memset(&ccell_params, 0, sizeof(ccell_params));
+
+ ccell_params.m_num_pixels = 16;
+ ccell_params.m_pPixels = (color_quad_u8*)&block[0][0];
+ ccell_params.m_num_selector_weights = 8;
+ ccell_params.m_pSelector_weights = g_bc7_weights3;
+ ccell_params.m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights3x;
+ ccell_params.m_astc_endpoint_range = endpoint_range;
+ ccell_params.m_weights[0] = 1;
+ ccell_params.m_weights[1] = 1;
+ ccell_params.m_weights[2] = 1;
+ ccell_params.m_weights[3] = 1;
+
+ color_cell_compressor_results ccell_results;
+ uint8_t ccell_result_selectors[16];
+ uint8_t ccell_result_selectors_temp[16];
+ memset(&ccell_results, 0, sizeof(ccell_results));
+ ccell_results.m_pSelectors = &ccell_result_selectors[0];
+ ccell_results.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err = color_cell_compression(255, &ccell_params, &ccell_results, &comp_params);
+
+ // ASTC
+ astc_block_desc blk;
+ memset(&blk, 0, sizeof(blk));
+
+ blk.m_dual_plane = false;
+ blk.m_weight_range = weight_range;
+
+ blk.m_ccs = 0;
+ blk.m_subsets = 1;
+ blk.m_partition_seed = 0;
+ blk.m_cem = 8;
+
+ blk.m_endpoints[0] = ccell_results.m_astc_low_endpoint.m_c[0];
+ blk.m_endpoints[1] = ccell_results.m_astc_high_endpoint.m_c[0];
+ blk.m_endpoints[2] = ccell_results.m_astc_low_endpoint.m_c[1];
+ blk.m_endpoints[3] = ccell_results.m_astc_high_endpoint.m_c[1];
+ blk.m_endpoints[4] = ccell_results.m_astc_low_endpoint.m_c[2];
+ blk.m_endpoints[5] = ccell_results.m_astc_high_endpoint.m_c[2];
+
+ bool invert = false;
+
+ int s0 = g_astc_unquant[endpoint_range][blk.m_endpoints[0]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[2]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][blk.m_endpoints[1]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[3]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(blk.m_endpoints[0], blk.m_endpoints[1]);
+ std::swap(blk.m_endpoints[2], blk.m_endpoints[3]);
+ std::swap(blk.m_endpoints[4], blk.m_endpoints[5]);
+ invert = true;
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ blk.m_weights[x + y * 4] = ccell_result_selectors[x + y * 4];
+
+ if (invert)
+ blk.m_weights[x + y * 4] = 7 - blk.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 5;
+ pResults[total_results].m_common_pattern = 0;
+ pResults[total_results].m_astc = blk;
+ pResults[total_results].m_astc_err = part_err;
+ total_results++;
+ }
+ }
+
+ // MODE 6
+ // DualPlane: 1, WeightRange: 2 (4), Subsets: 1, CEM: 8 (RGB Direct ), EndpointRange: 18 (160) BC7 MODE5
+ static void astc_mode6(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params)
+ {
+ for (uint32_t rot_comp = 0; rot_comp < 3; rot_comp++)
+ {
+ const uint32_t weight_range = 2;
+ const uint32_t endpoint_range = 18;
+
+ color_quad_u8 block_rgb[16];
+ color_quad_u8 block_a[16];
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ block_rgb[i] = ((color_quad_u8*)&block[0][0])[i];
+ block_a[i] = block_rgb[i];
+
+ uint8_t c = block_a[i].m_c[rot_comp];
+ block_a[i].m_c[0] = c;
+ block_a[i].m_c[1] = c;
+ block_a[i].m_c[2] = c;
+ block_a[i].m_c[3] = 255;
+
+ block_rgb[i].m_c[rot_comp] = 255;
+ }
+
+ uint8_t ccell_result_selectors_temp[16];
+
+ color_cell_compressor_params ccell_params_rgb;
+ memset(&ccell_params_rgb, 0, sizeof(ccell_params_rgb));
+
+ ccell_params_rgb.m_num_pixels = 16;
+ ccell_params_rgb.m_pPixels = block_rgb;
+ ccell_params_rgb.m_num_selector_weights = 4;
+ ccell_params_rgb.m_pSelector_weights = g_bc7_weights2;
+ ccell_params_rgb.m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights2x;
+ ccell_params_rgb.m_astc_endpoint_range = endpoint_range;
+ ccell_params_rgb.m_weights[0] = 1;
+ ccell_params_rgb.m_weights[1] = 1;
+ ccell_params_rgb.m_weights[2] = 1;
+ ccell_params_rgb.m_weights[3] = 1;
+
+ color_cell_compressor_results ccell_results_rgb;
+ uint8_t ccell_result_selectors_rgb[16];
+ memset(&ccell_results_rgb, 0, sizeof(ccell_results_rgb));
+ ccell_results_rgb.m_pSelectors = &ccell_result_selectors_rgb[0];
+ ccell_results_rgb.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err_rgb = color_cell_compression(255, &ccell_params_rgb, &ccell_results_rgb, &comp_params);
+
+ color_cell_compressor_params ccell_params_a;
+ memset(&ccell_params_a, 0, sizeof(ccell_params_a));
+
+ ccell_params_a.m_num_pixels = 16;
+ ccell_params_a.m_pPixels = block_a;
+ ccell_params_a.m_num_selector_weights = 4;
+ ccell_params_a.m_pSelector_weights = g_bc7_weights2;
+ ccell_params_a.m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights2x;
+ ccell_params_a.m_astc_endpoint_range = endpoint_range;
+ ccell_params_a.m_weights[0] = 1;
+ ccell_params_a.m_weights[1] = 1;
+ ccell_params_a.m_weights[2] = 1;
+ ccell_params_a.m_weights[3] = 1;
+
+ color_cell_compressor_results ccell_results_a;
+ uint8_t ccell_result_selectors_a[16];
+ memset(&ccell_results_a, 0, sizeof(ccell_results_a));
+ ccell_results_a.m_pSelectors = &ccell_result_selectors_a[0];
+ ccell_results_a.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err_a = color_cell_compression(255, &ccell_params_a, &ccell_results_a, &comp_params) / 3;
+
+ uint64_t total_err = part_err_rgb + part_err_a;
+
+ // ASTC
+ astc_block_desc blk;
+ memset(&blk, 0, sizeof(blk));
+
+ blk.m_dual_plane = true;
+ blk.m_weight_range = weight_range;
+
+ blk.m_ccs = rot_comp;
+ blk.m_subsets = 1;
+ blk.m_partition_seed = 0;
+ blk.m_cem = 8;
+
+ blk.m_endpoints[0] = (rot_comp == 0 ? ccell_results_a : ccell_results_rgb).m_astc_low_endpoint.m_c[0];
+ blk.m_endpoints[1] = (rot_comp == 0 ? ccell_results_a : ccell_results_rgb).m_astc_high_endpoint.m_c[0];
+ blk.m_endpoints[2] = (rot_comp == 1 ? ccell_results_a : ccell_results_rgb).m_astc_low_endpoint.m_c[1];
+ blk.m_endpoints[3] = (rot_comp == 1 ? ccell_results_a : ccell_results_rgb).m_astc_high_endpoint.m_c[1];
+ blk.m_endpoints[4] = (rot_comp == 2 ? ccell_results_a : ccell_results_rgb).m_astc_low_endpoint.m_c[2];
+ blk.m_endpoints[5] = (rot_comp == 2 ? ccell_results_a : ccell_results_rgb).m_astc_high_endpoint.m_c[2];
+
+ bool invert = false;
+
+ int s0 = g_astc_unquant[endpoint_range][blk.m_endpoints[0]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[2]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][blk.m_endpoints[1]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[3]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(blk.m_endpoints[0], blk.m_endpoints[1]);
+ std::swap(blk.m_endpoints[2], blk.m_endpoints[3]);
+ std::swap(blk.m_endpoints[4], blk.m_endpoints[5]);
+ invert = true;
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ uint32_t rgb_index = ccell_result_selectors_rgb[x + y * 4];
+ uint32_t a_index = ccell_result_selectors_a[x + y * 4];
+
+ if (invert)
+ {
+ rgb_index = 3 - rgb_index;
+ a_index = 3 - a_index;
+ }
+
+ blk.m_weights[(x + y * 4) * 2 + 0] = (uint8_t)rgb_index;
+ blk.m_weights[(x + y * 4) * 2 + 1] = (uint8_t)a_index;
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 6;
+ pResults[total_results].m_common_pattern = 0;
+ pResults[total_results].m_astc = blk;
+ pResults[total_results].m_astc_err = total_err;
+ total_results++;
+ }
+ } // rot_comp
+ }
+
+ // MODE 7 - 2 subset ASTC, 3 subset BC7
+ // DualPlane: 0, WeightRange: 2 (4), Subsets: 2, CEM: 8 (RGB Direct ), EndpointRange: 12 (40) MODE2
+ static void astc_mode7(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params, bool estimate_partition)
+ {
+ uint32_t first_common_pattern = 0;
+ uint32_t last_common_pattern = TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS;
+
+ if (estimate_partition)
+ {
+ uint64_t best_err = UINT64_MAX;
+ uint32_t best_common_pattern = 0;
+ const uint32_t weights[4] = { 1, 1, 1, 1 };
+
+ for (uint32_t common_pattern = 0; common_pattern < TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS; common_pattern++)
+ {
+ const uint8_t* pPartition = &g_bc7_3_astc2_patterns2[common_pattern][0];
+
+#ifdef _DEBUG
+ const uint32_t astc_pattern = g_bc7_3_astc2_common_partitions[common_pattern].m_astc2;
+ const uint32_t bc7_pattern = g_bc7_3_astc2_common_partitions[common_pattern].m_bc73;
+ const uint32_t common_pattern_k = g_bc7_3_astc2_common_partitions[common_pattern].k;
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t astc_part = bc7_convert_partition_index_3_to_2(g_bc7_partition3[16 * bc7_pattern + x + y * 4], common_pattern_k);
+ assert((int)astc_part == astc_compute_texel_partition(astc_pattern, x, y, 0, 2, true));
+ assert(astc_part == pPartition[x + y * 4]);
+ }
+ }
+#endif
+
+ color_quad_u8 subset_colors[2][16];
+ uint32_t subset_total_colors[2] = { 0, 0 };
+ for (uint32_t index = 0; index < 16; index++)
+ subset_colors[pPartition[index]][subset_total_colors[pPartition[index]]++] = ((const color_quad_u8*)block)[index];
+
+ uint64_t total_subset_err = 0;
+ for (uint32_t subset = 0; (subset < 2) && (total_subset_err < best_err); subset++)
+ total_subset_err += color_cell_compression_est_astc(4, 3, g_bc7_weights2, subset_total_colors[subset], &subset_colors[subset][0], best_err, weights);
+
+ if (total_subset_err < best_err)
+ {
+ best_err = total_subset_err;
+ best_common_pattern = common_pattern;
+ }
+ }
+
+ first_common_pattern = best_common_pattern;
+ last_common_pattern = best_common_pattern + 1;
+ }
+
+ //const uint32_t weight_range = 2;
+ const uint32_t endpoint_range = 12;
+
+ for (uint32_t common_pattern = first_common_pattern; common_pattern < last_common_pattern; common_pattern++)
+ {
+ const uint32_t astc_pattern = g_bc7_3_astc2_common_partitions[common_pattern].m_astc2;
+ const uint32_t bc7_pattern = g_bc7_3_astc2_common_partitions[common_pattern].m_bc73;
+ const uint32_t common_pattern_k = g_bc7_3_astc2_common_partitions[common_pattern].k;
+
+ color_rgba part_pixels[2][16];
+ uint32_t part_pixel_index[4][4];
+ uint32_t num_part_pixels[2] = { 0, 0 };
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t astc_part = bc7_convert_partition_index_3_to_2(g_bc7_partition3[16 * bc7_pattern + x + y * 4], common_pattern_k);
+#ifdef _DEBUG
+ assert((int)astc_part == astc_compute_texel_partition(astc_pattern, x, y, 0, 2, true));
+#endif
+
+ part_pixel_index[y][x] = num_part_pixels[astc_part];
+ part_pixels[astc_part][num_part_pixels[astc_part]++] = block[y][x];
+ }
+ }
+
+ color_cell_compressor_params ccell_params[2];
+ color_cell_compressor_results ccell_results[2];
+ uint8_t ccell_result_selectors[2][16];
+ uint8_t ccell_result_selectors_temp[2][16];
+
+ uint64_t total_part_err = 0;
+ for (uint32_t part = 0; part < 2; part++)
+ {
+ memset(&ccell_params[part], 0, sizeof(ccell_params[part]));
+
+ ccell_params[part].m_num_pixels = num_part_pixels[part];
+ ccell_params[part].m_pPixels = (color_quad_u8*)&part_pixels[part][0];
+ ccell_params[part].m_num_selector_weights = 4;
+ ccell_params[part].m_pSelector_weights = g_bc7_weights2;
+ ccell_params[part].m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights2x;
+ ccell_params[part].m_astc_endpoint_range = endpoint_range;
+ ccell_params[part].m_weights[0] = 1;
+ ccell_params[part].m_weights[1] = 1;
+ ccell_params[part].m_weights[2] = 1;
+ ccell_params[part].m_weights[3] = 1;
+
+ memset(&ccell_results[part], 0, sizeof(ccell_results[part]));
+ ccell_results[part].m_pSelectors = &ccell_result_selectors[part][0];
+ ccell_results[part].m_pSelectors_temp = &ccell_result_selectors_temp[part][0];
+
+ uint64_t part_err = color_cell_compression(255, &ccell_params[part], &ccell_results[part], &comp_params);
+ total_part_err += part_err;
+ } // part
+
+ // ASTC
+ astc_block_desc blk;
+ memset(&blk, 0, sizeof(blk));
+
+ blk.m_dual_plane = false;
+ blk.m_weight_range = 2;
+
+ blk.m_ccs = 0;
+ blk.m_subsets = 2;
+ blk.m_partition_seed = astc_pattern;
+ blk.m_cem = 8;
+
+ const uint32_t p0 = 0;
+ const uint32_t p1 = 1;
+
+ blk.m_endpoints[0] = ccell_results[p0].m_astc_low_endpoint.m_c[0];
+ blk.m_endpoints[1] = ccell_results[p0].m_astc_high_endpoint.m_c[0];
+ blk.m_endpoints[2] = ccell_results[p0].m_astc_low_endpoint.m_c[1];
+ blk.m_endpoints[3] = ccell_results[p0].m_astc_high_endpoint.m_c[1];
+ blk.m_endpoints[4] = ccell_results[p0].m_astc_low_endpoint.m_c[2];
+ blk.m_endpoints[5] = ccell_results[p0].m_astc_high_endpoint.m_c[2];
+
+ bool invert[2] = { false, false };
+
+ int s0 = g_astc_unquant[endpoint_range][blk.m_endpoints[0]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[2]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][blk.m_endpoints[1]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[3]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(blk.m_endpoints[0], blk.m_endpoints[1]);
+ std::swap(blk.m_endpoints[2], blk.m_endpoints[3]);
+ std::swap(blk.m_endpoints[4], blk.m_endpoints[5]);
+ invert[0] = true;
+ }
+
+ blk.m_endpoints[6] = ccell_results[p1].m_astc_low_endpoint.m_c[0];
+ blk.m_endpoints[7] = ccell_results[p1].m_astc_high_endpoint.m_c[0];
+ blk.m_endpoints[8] = ccell_results[p1].m_astc_low_endpoint.m_c[1];
+ blk.m_endpoints[9] = ccell_results[p1].m_astc_high_endpoint.m_c[1];
+ blk.m_endpoints[10] = ccell_results[p1].m_astc_low_endpoint.m_c[2];
+ blk.m_endpoints[11] = ccell_results[p1].m_astc_high_endpoint.m_c[2];
+
+ s0 = g_astc_unquant[endpoint_range][blk.m_endpoints[0 + 6]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[2 + 6]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[4 + 6]].m_unquant;
+ s1 = g_astc_unquant[endpoint_range][blk.m_endpoints[1 + 6]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[3 + 6]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[5 + 6]].m_unquant;
+
+ if (s1 < s0)
+ {
+ std::swap(blk.m_endpoints[0 + 6], blk.m_endpoints[1 + 6]);
+ std::swap(blk.m_endpoints[2 + 6], blk.m_endpoints[3 + 6]);
+ std::swap(blk.m_endpoints[4 + 6], blk.m_endpoints[5 + 6]);
+ invert[1] = true;
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t astc_part = bc7_convert_partition_index_3_to_2(g_bc7_partition3[16 * bc7_pattern + x + y * 4], common_pattern_k);
+
+ blk.m_weights[x + y * 4] = ccell_result_selectors[astc_part][part_pixel_index[y][x]];
+
+ if (invert[astc_part])
+ blk.m_weights[x + y * 4] = 3 - blk.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 7;
+ pResults[total_results].m_common_pattern = common_pattern;
+ pResults[total_results].m_astc = blk;
+ pResults[total_results].m_astc_err = total_part_err;
+ total_results++;
+ }
+
+ } // common_pattern
+ }
+
+ static void estimate_partition2_list(uint32_t num_weights, uint32_t num_comps, const uint32_t* pWeights, const color_rgba block[4][4], uint32_t* pParts, uint32_t max_parts, const uint32_t weights[4])
+ {
+ assert(pWeights[0] == 0 && pWeights[num_weights - 1] == 64);
+
+ const uint32_t MAX_PARTS = 8;
+ assert(max_parts <= MAX_PARTS);
+
+ uint64_t part_error[MAX_PARTS];
+ memset(part_error, 0xFF, sizeof(part_error));
+ memset(pParts, 0, sizeof(pParts[0]) * max_parts);
+
+ for (uint32_t common_pattern = 0; common_pattern < TOTAL_ASTC_BC7_COMMON_PARTITIONS2; common_pattern++)
+ {
+ const uint32_t bc7_pattern = g_astc_bc7_common_partitions2[common_pattern].m_bc7;
+
+ const uint8_t* pPartition = &g_bc7_partition2[bc7_pattern * 16];
+
+ color_quad_u8 subset_colors[2][16];
+ uint32_t subset_total_colors[2] = { 0, 0 };
+ for (uint32_t index = 0; index < 16; index++)
+ subset_colors[pPartition[index]][subset_total_colors[pPartition[index]]++] = ((const color_quad_u8*)block)[index];
+
+ uint64_t total_subset_err = 0;
+ for (uint32_t subset = 0; subset < 2; subset++)
+ total_subset_err += color_cell_compression_est_astc(num_weights, num_comps, pWeights, subset_total_colors[subset], &subset_colors[subset][0], UINT64_MAX, weights);
+
+ for (int i = 0; i < (int)max_parts; i++)
+ {
+ if (total_subset_err < part_error[i])
+ {
+ for (int j = max_parts - 1; j > i; --j)
+ {
+ pParts[j] = pParts[j - 1];
+ part_error[j] = part_error[j - 1];
+ }
+
+ pParts[i] = common_pattern;
+ part_error[i] = total_subset_err;
+
+ break;
+ }
+ }
+ }
+
+#ifdef _DEBUG
+ for (uint32_t i = 0; i < max_parts - 1; i++)
+ {
+ assert(part_error[i] <= part_error[i + 1]);
+ }
+#endif
+ }
+
+ // 9. DualPlane: 0, WeightRange: 2 (4), Subsets: 2, CEM: 12 (RGBA Direct), EndpointRange: 8 (16) - BC7 MODE 7
+ // 16. DualPlane: 0, WeightRange : 2 (4), Subsets : 2, CEM: 4 (LA Direct), EndpointRange : 20 (256) - BC7 MODE 7
+ static void astc_mode9_or_16(uint32_t mode, const color_rgba source_block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params, uint32_t estimate_partition_list_size)
+ {
+ assert(mode == 9 || mode == 16);
+
+ const color_rgba* pBlock = &source_block[0][0];
+
+ color_rgba temp_block[16];
+ if (mode == 16)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ if (mode == 16)
+ {
+ assert(pBlock[i].r == pBlock[i].g);
+ assert(pBlock[i].r == pBlock[i].b);
+ }
+
+ const uint32_t l = pBlock[i].r;
+ const uint32_t a = pBlock[i].a;
+
+ // Use (l,0,0,a) not (l,l,l,a) so both components are treated equally.
+ temp_block[i].set_noclamp_rgba(l, 0, 0, a);
+ }
+
+ pBlock = temp_block;
+ }
+
+ const uint32_t weights[4] = { 1, 1, 1, 1 };
+
+ //const uint32_t weight_range = 2;
+ const uint32_t endpoint_range = (mode == 16) ? 20 : 8;
+
+ uint32_t first_common_pattern = 0;
+ uint32_t last_common_pattern = TOTAL_ASTC_BC7_COMMON_PARTITIONS2;
+ bool use_part_list = false;
+
+ const uint32_t MAX_PARTS = 8;
+ uint32_t parts[MAX_PARTS];
+
+ if (estimate_partition_list_size == 1)
+ {
+ first_common_pattern = estimate_partition2(4, 4, g_bc7_weights2, (const color_rgba(*)[4])pBlock, weights);
+ last_common_pattern = first_common_pattern + 1;
+ }
+ else if (estimate_partition_list_size > 0)
+ {
+ assert(estimate_partition_list_size <= MAX_PARTS);
+ estimate_partition_list_size = basisu::minimum(estimate_partition_list_size, MAX_PARTS);
+
+ estimate_partition2_list(4, 4, g_bc7_weights2, (const color_rgba(*)[4])pBlock, parts, estimate_partition_list_size, weights);
+
+ first_common_pattern = 0;
+ last_common_pattern = estimate_partition_list_size;
+ use_part_list = true;
+
+#ifdef _DEBUG
+ assert(parts[0] == estimate_partition2(4, 4, g_bc7_weights2, (const color_rgba(*)[4])pBlock, weights));
+#endif
+ }
+
+ for (uint32_t common_pattern_iter = first_common_pattern; common_pattern_iter < last_common_pattern; common_pattern_iter++)
+ {
+ const uint32_t common_pattern = use_part_list ? parts[common_pattern_iter] : common_pattern_iter;
+
+ const uint32_t bc7_pattern = g_astc_bc7_common_partitions2[common_pattern].m_bc7;
+
+ color_rgba part_pixels[2][16];
+ uint32_t part_pixel_index[4][4];
+ uint32_t num_part_pixels[2] = { 0, 0 };
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t part = g_bc7_partition2[16 * bc7_pattern + x + y * 4];
+ part_pixel_index[y][x] = num_part_pixels[part];
+ part_pixels[part][num_part_pixels[part]++] = pBlock[y * 4 + x];
+ }
+ }
+
+ color_cell_compressor_params ccell_params[2];
+ color_cell_compressor_results ccell_results[2];
+ uint8_t ccell_result_selectors[2][16];
+ uint8_t ccell_result_selectors_temp[2][16];
+
+ uint64_t total_err = 0;
+ for (uint32_t subset = 0; subset < 2; subset++)
+ {
+ memset(&ccell_params[subset], 0, sizeof(ccell_params[subset]));
+
+ ccell_params[subset].m_num_pixels = num_part_pixels[subset];
+ ccell_params[subset].m_pPixels = (color_quad_u8*)&part_pixels[subset][0];
+ ccell_params[subset].m_num_selector_weights = 4;
+ ccell_params[subset].m_pSelector_weights = g_bc7_weights2;
+ ccell_params[subset].m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights2x;
+ ccell_params[subset].m_astc_endpoint_range = endpoint_range;
+ ccell_params[subset].m_weights[0] = weights[0];
+ ccell_params[subset].m_weights[1] = weights[1];
+ ccell_params[subset].m_weights[2] = weights[2];
+ ccell_params[subset].m_weights[3] = weights[3];
+ ccell_params[subset].m_has_alpha = true;
+
+ memset(&ccell_results[subset], 0, sizeof(ccell_results[subset]));
+ ccell_results[subset].m_pSelectors = &ccell_result_selectors[subset][0];
+ ccell_results[subset].m_pSelectors_temp = &ccell_result_selectors_temp[subset][0];
+
+ uint64_t subset_err = color_cell_compression(255, &ccell_params[subset], &ccell_results[subset], &comp_params);
+
+ if (mode == 16)
+ {
+ color_rgba colors[4];
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ colors[0].m_comps[c] = g_astc_unquant[endpoint_range][ccell_results[subset].m_astc_low_endpoint.m_c[(c < 3) ? 0 : 3]].m_unquant;
+ colors[3].m_comps[c] = g_astc_unquant[endpoint_range][ccell_results[subset].m_astc_high_endpoint.m_c[(c < 3) ? 0 : 3]].m_unquant;
+ }
+
+ for (uint32_t i = 1; i < 4 - 1; i++)
+ for (uint32_t c = 0; c < 4; c++)
+ colors[i].m_comps[c] = (uint8_t)astc_interpolate(colors[0].m_comps[c], colors[3].m_comps[c], g_bc7_weights2[i], false);
+
+ for (uint32_t p = 0; p < ccell_params[subset].m_num_pixels; p++)
+ {
+ color_rgba orig_pix(part_pixels[subset][p]);
+ orig_pix.g = orig_pix.r;
+ orig_pix.b = orig_pix.r;
+ total_err += color_distance_la(orig_pix, colors[ccell_result_selectors[subset][p]]);
+ }
+ }
+ else
+ {
+ total_err += subset_err;
+ }
+ } // subset
+
+ // ASTC
+ astc_block_desc astc_results;
+ memset(&astc_results, 0, sizeof(astc_results));
+
+ astc_results.m_dual_plane = false;
+ astc_results.m_weight_range = 2;
+
+ astc_results.m_ccs = 0;
+ astc_results.m_subsets = 2;
+ astc_results.m_partition_seed = g_astc_bc7_common_partitions2[common_pattern].m_astc;
+ astc_results.m_cem = (mode == 16) ? 4 : 12;
+
+ uint32_t part[2] = { 0, 1 };
+ if (g_astc_bc7_common_partitions2[common_pattern].m_invert)
+ std::swap(part[0], part[1]);
+
+ bool invert[2] = { false, false };
+
+ for (uint32_t p = 0; p < 2; p++)
+ {
+ if (mode == 16)
+ {
+ astc_results.m_endpoints[p * 4 + 0] = ccell_results[part[p]].m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[p * 4 + 1] = ccell_results[part[p]].m_astc_high_endpoint.m_c[0];
+
+ astc_results.m_endpoints[p * 4 + 2] = ccell_results[part[p]].m_astc_low_endpoint.m_c[3];
+ astc_results.m_endpoints[p * 4 + 3] = ccell_results[part[p]].m_astc_high_endpoint.m_c[3];
+ }
+ else
+ {
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ astc_results.m_endpoints[p * 8 + c * 2] = ccell_results[part[p]].m_astc_low_endpoint.m_c[c];
+ astc_results.m_endpoints[p * 8 + c * 2 + 1] = ccell_results[part[p]].m_astc_high_endpoint.m_c[c];
+ }
+
+ int s0 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[p * 8 + 0]].m_unquant +
+ g_astc_unquant[endpoint_range][astc_results.m_endpoints[p * 8 + 2]].m_unquant +
+ g_astc_unquant[endpoint_range][astc_results.m_endpoints[p * 8 + 4]].m_unquant;
+
+ int s1 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[p * 8 + 1]].m_unquant +
+ g_astc_unquant[endpoint_range][astc_results.m_endpoints[p * 8 + 3]].m_unquant +
+ g_astc_unquant[endpoint_range][astc_results.m_endpoints[p * 8 + 5]].m_unquant;
+
+ if (s1 < s0)
+ {
+ std::swap(astc_results.m_endpoints[p * 8 + 0], astc_results.m_endpoints[p * 8 + 1]);
+ std::swap(astc_results.m_endpoints[p * 8 + 2], astc_results.m_endpoints[p * 8 + 3]);
+ std::swap(astc_results.m_endpoints[p * 8 + 4], astc_results.m_endpoints[p * 8 + 5]);
+ std::swap(astc_results.m_endpoints[p * 8 + 6], astc_results.m_endpoints[p * 8 + 7]);
+ invert[p] = true;
+ }
+ }
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t bc7_part = g_bc7_partition2[16 * bc7_pattern + x + y * 4];
+
+ astc_results.m_weights[x + y * 4] = ccell_result_selectors[bc7_part][part_pixel_index[y][x]];
+
+ uint32_t astc_part = bc7_part;
+ if (g_astc_bc7_common_partitions2[common_pattern].m_invert)
+ astc_part = 1 - astc_part;
+
+ if (invert[astc_part])
+ astc_results.m_weights[x + y * 4] = 3 - astc_results.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = mode;
+ pResults[total_results].m_common_pattern = common_pattern;
+ pResults[total_results].m_astc = astc_results;
+ pResults[total_results].m_astc_err = total_err;
+ total_results++;
+ }
+
+ } // common_pattern
+ }
+
+ // MODE 10
+ // DualPlane: 0, WeightRange: 8 (16), Subsets: 1, CEM: 12 (RGBA Direct ), EndpointRange: 13 (48) MODE6
+ static void astc_mode10(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params)
+ {
+ const uint32_t weight_range = 8;
+ const uint32_t endpoint_range = 13;
+
+ color_cell_compressor_params ccell_params;
+ memset(&ccell_params, 0, sizeof(ccell_params));
+
+ ccell_params.m_num_pixels = 16;
+ ccell_params.m_pPixels = (color_quad_u8*)&block[0][0];
+ ccell_params.m_num_selector_weights = 16;
+ ccell_params.m_pSelector_weights = g_astc_weights4;
+ ccell_params.m_pSelector_weightsx = (const bc7enc_vec4F*)g_astc_weights4x;
+ ccell_params.m_astc_endpoint_range = endpoint_range;
+ ccell_params.m_weights[0] = 1;
+ ccell_params.m_weights[1] = 1;
+ ccell_params.m_weights[2] = 1;
+ ccell_params.m_weights[3] = 1;
+ ccell_params.m_has_alpha = true;
+
+ color_cell_compressor_results ccell_results;
+ uint8_t ccell_result_selectors[16];
+ uint8_t ccell_result_selectors_temp[16];
+ memset(&ccell_results, 0, sizeof(ccell_results));
+ ccell_results.m_pSelectors = &ccell_result_selectors[0];
+ ccell_results.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err = color_cell_compression(255, &ccell_params, &ccell_results, &comp_params);
+
+ // ASTC
+ astc_block_desc astc_results;
+ memset(&astc_results, 0, sizeof(astc_results));
+
+ astc_results.m_dual_plane = false;
+ astc_results.m_weight_range = weight_range;
+
+ astc_results.m_ccs = 0;
+ astc_results.m_subsets = 1;
+ astc_results.m_partition_seed = 0;
+ astc_results.m_cem = 12;
+
+ astc_results.m_endpoints[0] = ccell_results.m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[1] = ccell_results.m_astc_high_endpoint.m_c[0];
+ astc_results.m_endpoints[2] = ccell_results.m_astc_low_endpoint.m_c[1];
+ astc_results.m_endpoints[3] = ccell_results.m_astc_high_endpoint.m_c[1];
+ astc_results.m_endpoints[4] = ccell_results.m_astc_low_endpoint.m_c[2];
+ astc_results.m_endpoints[5] = ccell_results.m_astc_high_endpoint.m_c[2];
+ astc_results.m_endpoints[6] = ccell_results.m_astc_low_endpoint.m_c[3];
+ astc_results.m_endpoints[7] = ccell_results.m_astc_high_endpoint.m_c[3];
+
+ bool invert = false;
+
+ int s0 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[0]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[2]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[1]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[3]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(astc_results.m_endpoints[0], astc_results.m_endpoints[1]);
+ std::swap(astc_results.m_endpoints[2], astc_results.m_endpoints[3]);
+ std::swap(astc_results.m_endpoints[4], astc_results.m_endpoints[5]);
+ std::swap(astc_results.m_endpoints[6], astc_results.m_endpoints[7]);
+ invert = true;
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ astc_results.m_weights[x + y * 4] = ccell_result_selectors[x + y * 4];
+
+ if (invert)
+ astc_results.m_weights[x + y * 4] = 15 - astc_results.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 10;
+ pResults[total_results].m_common_pattern = 0;
+ pResults[total_results].m_astc = astc_results;
+ pResults[total_results].m_astc_err = part_err;
+ total_results++;
+ }
+ }
+
+ // 11. DualPlane: 1, WeightRange: 2 (4), Subsets: 1, CEM: 12 (RGBA Direct), EndpointRange: 13 (48) MODE5
+ // 17. DualPlane: 1, WeightRange : 2 (4), Subsets : 1, CEM : 4 (LA Direct), EndpointRange : 20 (256) BC7 MODE5
+ static void astc_mode11_or_17(uint32_t mode, const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params)
+ {
+ assert((mode == 11) || (mode == 17));
+
+ const uint32_t weight_range = 2;
+ const uint32_t endpoint_range = (mode == 17) ? 20 : 13;
+
+ bc7enc_compress_block_params local_comp_params(comp_params);
+ local_comp_params.m_perceptual = false;
+ local_comp_params.m_weights[0] = 1;
+ local_comp_params.m_weights[1] = 1;
+ local_comp_params.m_weights[2] = 1;
+ local_comp_params.m_weights[3] = 1;
+
+ const uint32_t last_rot_comp = (mode == 17) ? 1 : 4;
+
+ for (uint32_t rot_comp = 0; rot_comp < last_rot_comp; rot_comp++)
+ {
+ color_quad_u8 block_rgb[16];
+ color_quad_u8 block_a[16];
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ block_rgb[i] = ((color_quad_u8*)&block[0][0])[i];
+ block_a[i] = block_rgb[i];
+
+ if (mode == 17)
+ {
+ assert(block_rgb[i].m_c[0] == block_rgb[i].m_c[1]);
+ assert(block_rgb[i].m_c[0] == block_rgb[i].m_c[2]);
+
+ block_a[i].m_c[0] = block_rgb[i].m_c[3];
+ block_a[i].m_c[1] = block_rgb[i].m_c[3];
+ block_a[i].m_c[2] = block_rgb[i].m_c[3];
+ block_a[i].m_c[3] = 255;
+
+ block_rgb[i].m_c[1] = block_rgb[i].m_c[0];
+ block_rgb[i].m_c[2] = block_rgb[i].m_c[0];
+ block_rgb[i].m_c[3] = 255;
+ }
+ else
+ {
+ uint8_t c = block_a[i].m_c[rot_comp];
+ block_a[i].m_c[0] = c;
+ block_a[i].m_c[1] = c;
+ block_a[i].m_c[2] = c;
+ block_a[i].m_c[3] = 255;
+
+ block_rgb[i].m_c[rot_comp] = block_rgb[i].m_c[3];
+ block_rgb[i].m_c[3] = 255;
+ }
+ }
+
+ uint8_t ccell_result_selectors_temp[16];
+
+ color_cell_compressor_params ccell_params_rgb;
+ memset(&ccell_params_rgb, 0, sizeof(ccell_params_rgb));
+
+ ccell_params_rgb.m_num_pixels = 16;
+ ccell_params_rgb.m_pPixels = block_rgb;
+ ccell_params_rgb.m_num_selector_weights = 4;
+ ccell_params_rgb.m_pSelector_weights = g_bc7_weights2;
+ ccell_params_rgb.m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights2x;
+ ccell_params_rgb.m_astc_endpoint_range = endpoint_range;
+ ccell_params_rgb.m_weights[0] = 1;
+ ccell_params_rgb.m_weights[1] = 1;
+ ccell_params_rgb.m_weights[2] = 1;
+ ccell_params_rgb.m_weights[3] = 1;
+
+ color_cell_compressor_results ccell_results_rgb;
+ uint8_t ccell_result_selectors_rgb[16];
+ memset(&ccell_results_rgb, 0, sizeof(ccell_results_rgb));
+ ccell_results_rgb.m_pSelectors = &ccell_result_selectors_rgb[0];
+ ccell_results_rgb.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err_rgb = color_cell_compression(255, &ccell_params_rgb, &ccell_results_rgb, &local_comp_params);
+
+ color_cell_compressor_params ccell_params_a;
+ memset(&ccell_params_a, 0, sizeof(ccell_params_a));
+
+ ccell_params_a.m_num_pixels = 16;
+ ccell_params_a.m_pPixels = block_a;
+ ccell_params_a.m_num_selector_weights = 4;
+ ccell_params_a.m_pSelector_weights = g_bc7_weights2;
+ ccell_params_a.m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights2x;
+ ccell_params_a.m_astc_endpoint_range = endpoint_range;
+ ccell_params_a.m_weights[0] = 1;
+ ccell_params_a.m_weights[1] = 1;
+ ccell_params_a.m_weights[2] = 1;
+ ccell_params_a.m_weights[3] = 1;
+
+ color_cell_compressor_results ccell_results_a;
+ uint8_t ccell_result_selectors_a[16];
+ memset(&ccell_results_a, 0, sizeof(ccell_results_a));
+ ccell_results_a.m_pSelectors = &ccell_result_selectors_a[0];
+ ccell_results_a.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err_a = color_cell_compression(255, &ccell_params_a, &ccell_results_a, &local_comp_params) / 3;
+
+ uint64_t total_err = (mode == 17) ? ((part_err_rgb / 3) + part_err_a) : (part_err_rgb + part_err_a);
+
+ // ASTC
+ astc_block_desc blk;
+ memset(&blk, 0, sizeof(blk));
+
+ blk.m_dual_plane = true;
+ blk.m_weight_range = weight_range;
+
+ blk.m_ccs = (mode == 17) ? 3 : rot_comp;
+ blk.m_subsets = 1;
+ blk.m_partition_seed = 0;
+ blk.m_cem = (mode == 17) ? 4 : 12;
+
+ bool invert = false;
+
+ if (mode == 17)
+ {
+ assert(ccell_results_rgb.m_astc_low_endpoint.m_c[0] == ccell_results_rgb.m_astc_low_endpoint.m_c[1]);
+ assert(ccell_results_rgb.m_astc_low_endpoint.m_c[0] == ccell_results_rgb.m_astc_low_endpoint.m_c[2]);
+
+ assert(ccell_results_rgb.m_astc_high_endpoint.m_c[0] == ccell_results_rgb.m_astc_high_endpoint.m_c[1]);
+ assert(ccell_results_rgb.m_astc_high_endpoint.m_c[0] == ccell_results_rgb.m_astc_high_endpoint.m_c[2]);
+
+ blk.m_endpoints[0] = ccell_results_rgb.m_astc_low_endpoint.m_c[0];
+ blk.m_endpoints[1] = ccell_results_rgb.m_astc_high_endpoint.m_c[0];
+
+ blk.m_endpoints[2] = ccell_results_a.m_astc_low_endpoint.m_c[0];
+ blk.m_endpoints[3] = ccell_results_a.m_astc_high_endpoint.m_c[0];
+ }
+ else
+ {
+ blk.m_endpoints[0] = (rot_comp == 0 ? ccell_results_a : ccell_results_rgb).m_astc_low_endpoint.m_c[0];
+ blk.m_endpoints[1] = (rot_comp == 0 ? ccell_results_a : ccell_results_rgb).m_astc_high_endpoint.m_c[0];
+ blk.m_endpoints[2] = (rot_comp == 1 ? ccell_results_a : ccell_results_rgb).m_astc_low_endpoint.m_c[1];
+ blk.m_endpoints[3] = (rot_comp == 1 ? ccell_results_a : ccell_results_rgb).m_astc_high_endpoint.m_c[1];
+ blk.m_endpoints[4] = (rot_comp == 2 ? ccell_results_a : ccell_results_rgb).m_astc_low_endpoint.m_c[2];
+ blk.m_endpoints[5] = (rot_comp == 2 ? ccell_results_a : ccell_results_rgb).m_astc_high_endpoint.m_c[2];
+ if (rot_comp == 3)
+ {
+ blk.m_endpoints[6] = ccell_results_a.m_astc_low_endpoint.m_c[0];
+ blk.m_endpoints[7] = ccell_results_a.m_astc_high_endpoint.m_c[0];
+ }
+ else
+ {
+ blk.m_endpoints[6] = ccell_results_rgb.m_astc_low_endpoint.m_c[rot_comp];
+ blk.m_endpoints[7] = ccell_results_rgb.m_astc_high_endpoint.m_c[rot_comp];
+ }
+
+ int s0 = g_astc_unquant[endpoint_range][blk.m_endpoints[0]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[2]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][blk.m_endpoints[1]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[3]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(blk.m_endpoints[0], blk.m_endpoints[1]);
+ std::swap(blk.m_endpoints[2], blk.m_endpoints[3]);
+ std::swap(blk.m_endpoints[4], blk.m_endpoints[5]);
+ std::swap(blk.m_endpoints[6], blk.m_endpoints[7]);
+ invert = true;
+ }
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ uint32_t rgb_index = ccell_result_selectors_rgb[x + y * 4];
+ uint32_t a_index = ccell_result_selectors_a[x + y * 4];
+
+ if (invert)
+ {
+ rgb_index = 3 - rgb_index;
+ a_index = 3 - a_index;
+ }
+
+ blk.m_weights[(x + y * 4) * 2 + 0] = (uint8_t)rgb_index;
+ blk.m_weights[(x + y * 4) * 2 + 1] = (uint8_t)a_index;
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = mode;
+ pResults[total_results].m_common_pattern = 0;
+ pResults[total_results].m_astc = blk;
+ pResults[total_results].m_astc_err = total_err;
+ total_results++;
+ }
+ } // rot_comp
+ }
+
+ // MODE 12
+ // DualPlane: 0, WeightRange: 5 (8), Subsets: 1, CEM: 12 (RGBA Direct ), EndpointRange: 19 (192) MODE6
+ static void astc_mode12(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params)
+ {
+ const uint32_t weight_range = 5;
+ const uint32_t endpoint_range = 19;
+
+ color_cell_compressor_params ccell_params;
+ memset(&ccell_params, 0, sizeof(ccell_params));
+
+ ccell_params.m_num_pixels = 16;
+ ccell_params.m_pPixels = (color_quad_u8*)&block[0][0];
+ ccell_params.m_num_selector_weights = 8;
+ ccell_params.m_pSelector_weights = g_bc7_weights3;
+ ccell_params.m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights3x;
+ ccell_params.m_astc_endpoint_range = endpoint_range;
+ ccell_params.m_weights[0] = 1;
+ ccell_params.m_weights[1] = 1;
+ ccell_params.m_weights[2] = 1;
+ ccell_params.m_weights[3] = 1;
+ ccell_params.m_has_alpha = true;
+
+ color_cell_compressor_results ccell_results;
+ uint8_t ccell_result_selectors[16];
+ uint8_t ccell_result_selectors_temp[16];
+ memset(&ccell_results, 0, sizeof(ccell_results));
+ ccell_results.m_pSelectors = &ccell_result_selectors[0];
+ ccell_results.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err = color_cell_compression(255, &ccell_params, &ccell_results, &comp_params);
+
+ // ASTC
+ astc_block_desc astc_results;
+ memset(&astc_results, 0, sizeof(astc_results));
+
+ astc_results.m_dual_plane = false;
+ astc_results.m_weight_range = weight_range;
+
+ astc_results.m_ccs = 0;
+ astc_results.m_subsets = 1;
+ astc_results.m_partition_seed = 0;
+ astc_results.m_cem = 12;
+
+ astc_results.m_endpoints[0] = ccell_results.m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[1] = ccell_results.m_astc_high_endpoint.m_c[0];
+ astc_results.m_endpoints[2] = ccell_results.m_astc_low_endpoint.m_c[1];
+ astc_results.m_endpoints[3] = ccell_results.m_astc_high_endpoint.m_c[1];
+ astc_results.m_endpoints[4] = ccell_results.m_astc_low_endpoint.m_c[2];
+ astc_results.m_endpoints[5] = ccell_results.m_astc_high_endpoint.m_c[2];
+ astc_results.m_endpoints[6] = ccell_results.m_astc_low_endpoint.m_c[3];
+ astc_results.m_endpoints[7] = ccell_results.m_astc_high_endpoint.m_c[3];
+
+ bool invert = false;
+
+ int s0 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[0]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[2]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[1]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[3]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(astc_results.m_endpoints[0], astc_results.m_endpoints[1]);
+ std::swap(astc_results.m_endpoints[2], astc_results.m_endpoints[3]);
+ std::swap(astc_results.m_endpoints[4], astc_results.m_endpoints[5]);
+ std::swap(astc_results.m_endpoints[6], astc_results.m_endpoints[7]);
+ invert = true;
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ astc_results.m_weights[x + y * 4] = ccell_result_selectors[x + y * 4];
+
+ if (invert)
+ astc_results.m_weights[x + y * 4] = 7 - astc_results.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 12;
+ pResults[total_results].m_common_pattern = 0;
+ pResults[total_results].m_astc = astc_results;
+ pResults[total_results].m_astc_err = part_err;
+ total_results++;
+ }
+ }
+
+ // 13. DualPlane: 1, WeightRange: 0 (2), Subsets: 1, CEM: 12 (RGBA Direct ), EndpointRange: 20 (256) MODE5
+ static void astc_mode13(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params)
+ {
+ bc7enc_compress_block_params local_comp_params(comp_params);
+ local_comp_params.m_perceptual = false;
+ local_comp_params.m_weights[0] = 1;
+ local_comp_params.m_weights[1] = 1;
+ local_comp_params.m_weights[2] = 1;
+ local_comp_params.m_weights[3] = 1;
+
+ for (uint32_t rot_comp = 0; rot_comp < 4; rot_comp++)
+ {
+ const uint32_t weight_range = 0;
+ const uint32_t endpoint_range = 20;
+
+ color_quad_u8 block_rgb[16];
+ color_quad_u8 block_a[16];
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ block_rgb[i] = ((color_quad_u8*)&block[0][0])[i];
+ block_a[i] = block_rgb[i];
+
+ uint8_t c = block_a[i].m_c[rot_comp];
+ block_a[i].m_c[0] = c;
+ block_a[i].m_c[1] = c;
+ block_a[i].m_c[2] = c;
+ block_a[i].m_c[3] = 255;
+
+ block_rgb[i].m_c[rot_comp] = block_rgb[i].m_c[3];
+ block_rgb[i].m_c[3] = 255;
+ }
+
+ uint8_t ccell_result_selectors_temp[16];
+
+ color_cell_compressor_params ccell_params_rgb;
+ memset(&ccell_params_rgb, 0, sizeof(ccell_params_rgb));
+
+ ccell_params_rgb.m_num_pixels = 16;
+ ccell_params_rgb.m_pPixels = block_rgb;
+ ccell_params_rgb.m_num_selector_weights = 2;
+ ccell_params_rgb.m_pSelector_weights = g_bc7_weights1;
+ ccell_params_rgb.m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights1x;
+ ccell_params_rgb.m_astc_endpoint_range = endpoint_range;
+ ccell_params_rgb.m_weights[0] = 1;
+ ccell_params_rgb.m_weights[1] = 1;
+ ccell_params_rgb.m_weights[2] = 1;
+ ccell_params_rgb.m_weights[3] = 1;
+
+ color_cell_compressor_results ccell_results_rgb;
+ uint8_t ccell_result_selectors_rgb[16];
+ memset(&ccell_results_rgb, 0, sizeof(ccell_results_rgb));
+ ccell_results_rgb.m_pSelectors = &ccell_result_selectors_rgb[0];
+ ccell_results_rgb.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err_rgb = color_cell_compression(255, &ccell_params_rgb, &ccell_results_rgb, &local_comp_params);
+
+ color_cell_compressor_params ccell_params_a;
+ memset(&ccell_params_a, 0, sizeof(ccell_params_a));
+
+ ccell_params_a.m_num_pixels = 16;
+ ccell_params_a.m_pPixels = block_a;
+ ccell_params_a.m_num_selector_weights = 2;
+ ccell_params_a.m_pSelector_weights = g_bc7_weights1;
+ ccell_params_a.m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights1x;
+ ccell_params_a.m_astc_endpoint_range = endpoint_range;
+ ccell_params_a.m_weights[0] = 1;
+ ccell_params_a.m_weights[1] = 1;
+ ccell_params_a.m_weights[2] = 1;
+ ccell_params_a.m_weights[3] = 1;
+
+ color_cell_compressor_results ccell_results_a;
+ uint8_t ccell_result_selectors_a[16];
+ memset(&ccell_results_a, 0, sizeof(ccell_results_a));
+ ccell_results_a.m_pSelectors = &ccell_result_selectors_a[0];
+ ccell_results_a.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err_a = color_cell_compression(255, &ccell_params_a, &ccell_results_a, &local_comp_params) / 3;
+
+ uint64_t total_err = part_err_rgb + part_err_a;
+
+ // ASTC
+ astc_block_desc blk;
+ memset(&blk, 0, sizeof(blk));
+
+ blk.m_dual_plane = true;
+ blk.m_weight_range = weight_range;
+
+ blk.m_ccs = rot_comp;
+ blk.m_subsets = 1;
+ blk.m_partition_seed = 0;
+ blk.m_cem = 12;
+
+ blk.m_endpoints[0] = (rot_comp == 0 ? ccell_results_a : ccell_results_rgb).m_astc_low_endpoint.m_c[0];
+ blk.m_endpoints[1] = (rot_comp == 0 ? ccell_results_a : ccell_results_rgb).m_astc_high_endpoint.m_c[0];
+ blk.m_endpoints[2] = (rot_comp == 1 ? ccell_results_a : ccell_results_rgb).m_astc_low_endpoint.m_c[1];
+ blk.m_endpoints[3] = (rot_comp == 1 ? ccell_results_a : ccell_results_rgb).m_astc_high_endpoint.m_c[1];
+ blk.m_endpoints[4] = (rot_comp == 2 ? ccell_results_a : ccell_results_rgb).m_astc_low_endpoint.m_c[2];
+ blk.m_endpoints[5] = (rot_comp == 2 ? ccell_results_a : ccell_results_rgb).m_astc_high_endpoint.m_c[2];
+ if (rot_comp == 3)
+ {
+ blk.m_endpoints[6] = ccell_results_a.m_astc_low_endpoint.m_c[0];
+ blk.m_endpoints[7] = ccell_results_a.m_astc_high_endpoint.m_c[0];
+ }
+ else
+ {
+ blk.m_endpoints[6] = ccell_results_rgb.m_astc_low_endpoint.m_c[rot_comp];
+ blk.m_endpoints[7] = ccell_results_rgb.m_astc_high_endpoint.m_c[rot_comp];
+ }
+
+ bool invert = false;
+
+ int s0 = g_astc_unquant[endpoint_range][blk.m_endpoints[0]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[2]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][blk.m_endpoints[1]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[3]].m_unquant + g_astc_unquant[endpoint_range][blk.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(blk.m_endpoints[0], blk.m_endpoints[1]);
+ std::swap(blk.m_endpoints[2], blk.m_endpoints[3]);
+ std::swap(blk.m_endpoints[4], blk.m_endpoints[5]);
+ std::swap(blk.m_endpoints[6], blk.m_endpoints[7]);
+ invert = true;
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ uint32_t rgb_index = ccell_result_selectors_rgb[x + y * 4];
+ uint32_t a_index = ccell_result_selectors_a[x + y * 4];
+
+ if (invert)
+ {
+ rgb_index = 1 - rgb_index;
+ a_index = 1 - a_index;
+ }
+
+ blk.m_weights[(x + y * 4) * 2 + 0] = (uint8_t)rgb_index;
+ blk.m_weights[(x + y * 4) * 2 + 1] = (uint8_t)a_index;
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 13;
+ pResults[total_results].m_common_pattern = 0;
+ pResults[total_results].m_astc = blk;
+ pResults[total_results].m_astc_err = total_err;
+ total_results++;
+ }
+ } // rot_comp
+ }
+
+ // MODE14
+ // DualPlane: 0, WeightRange: 2 (4), Subsets: 1, CEM: 12 (RGBA Direct ), EndpointRange: 20 (256) MODE6
+ static void astc_mode14(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params)
+ {
+ const uint32_t weight_range = 2;
+ const uint32_t endpoint_range = 20;
+
+ color_cell_compressor_params ccell_params;
+ memset(&ccell_params, 0, sizeof(ccell_params));
+
+ ccell_params.m_num_pixels = 16;
+ ccell_params.m_pPixels = (color_quad_u8*)&block[0][0];
+ ccell_params.m_num_selector_weights = 4;
+ ccell_params.m_pSelector_weights = g_bc7_weights2;
+ ccell_params.m_pSelector_weightsx = (const bc7enc_vec4F*)g_bc7_weights2x;
+ ccell_params.m_astc_endpoint_range = endpoint_range;
+ ccell_params.m_weights[0] = 1;
+ ccell_params.m_weights[1] = 1;
+ ccell_params.m_weights[2] = 1;
+ ccell_params.m_weights[3] = 1;
+ ccell_params.m_has_alpha = true;
+
+ color_cell_compressor_results ccell_results;
+ uint8_t ccell_result_selectors[16];
+ uint8_t ccell_result_selectors_temp[16];
+ memset(&ccell_results, 0, sizeof(ccell_results));
+ ccell_results.m_pSelectors = &ccell_result_selectors[0];
+ ccell_results.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ uint64_t part_err = color_cell_compression(255, &ccell_params, &ccell_results, &comp_params);
+
+ // ASTC
+ astc_block_desc astc_results;
+ memset(&astc_results, 0, sizeof(astc_results));
+
+ astc_results.m_dual_plane = false;
+ astc_results.m_weight_range = weight_range;
+
+ astc_results.m_ccs = 0;
+ astc_results.m_subsets = 1;
+ astc_results.m_partition_seed = 0;
+ astc_results.m_cem = 12;
+
+ astc_results.m_endpoints[0] = ccell_results.m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[1] = ccell_results.m_astc_high_endpoint.m_c[0];
+ astc_results.m_endpoints[2] = ccell_results.m_astc_low_endpoint.m_c[1];
+ astc_results.m_endpoints[3] = ccell_results.m_astc_high_endpoint.m_c[1];
+ astc_results.m_endpoints[4] = ccell_results.m_astc_low_endpoint.m_c[2];
+ astc_results.m_endpoints[5] = ccell_results.m_astc_high_endpoint.m_c[2];
+ astc_results.m_endpoints[6] = ccell_results.m_astc_low_endpoint.m_c[3];
+ astc_results.m_endpoints[7] = ccell_results.m_astc_high_endpoint.m_c[3];
+
+ bool invert = false;
+
+ int s0 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[0]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[2]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[4]].m_unquant;
+ int s1 = g_astc_unquant[endpoint_range][astc_results.m_endpoints[1]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[3]].m_unquant + g_astc_unquant[endpoint_range][astc_results.m_endpoints[5]].m_unquant;
+ if (s1 < s0)
+ {
+ std::swap(astc_results.m_endpoints[0], astc_results.m_endpoints[1]);
+ std::swap(astc_results.m_endpoints[2], astc_results.m_endpoints[3]);
+ std::swap(astc_results.m_endpoints[4], astc_results.m_endpoints[5]);
+ std::swap(astc_results.m_endpoints[6], astc_results.m_endpoints[7]);
+ invert = true;
+ }
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ astc_results.m_weights[x + y * 4] = ccell_result_selectors[x + y * 4];
+
+ if (invert)
+ astc_results.m_weights[x + y * 4] = 3 - astc_results.m_weights[x + y * 4];
+ }
+ }
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 14;
+ pResults[total_results].m_common_pattern = 0;
+ pResults[total_results].m_astc = astc_results;
+ pResults[total_results].m_astc_err = part_err;
+ total_results++;
+ }
+ }
+
+ // MODE 15
+ // DualPlane: 0, WeightRange : 8 (16), Subsets : 1, CEM : 4 (LA Direct), EndpointRange : 20 (256) BC7 MODE6
+ static void astc_mode15(const color_rgba block[4][4], uastc_encode_results* pResults, uint32_t& total_results, bc7enc_compress_block_params& comp_params)
+ {
+ const uint32_t weight_range = 8;
+ const uint32_t endpoint_range = 20;
+
+ color_cell_compressor_params ccell_params;
+ memset(&ccell_params, 0, sizeof(ccell_params));
+
+ color_rgba temp_block[16];
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const uint32_t l = ((const color_rgba*)block)[i].r;
+ const uint32_t a = ((const color_rgba*)block)[i].a;
+
+ // Use (l,0,0,a) not (l,l,l,a) so both components are treated equally.
+ temp_block[i].set_noclamp_rgba(l, 0, 0, a);
+ }
+
+ ccell_params.m_num_pixels = 16;
+ //ccell_params.m_pPixels = (color_quad_u8*)&block[0][0];
+ ccell_params.m_pPixels = (color_quad_u8*)temp_block;
+ ccell_params.m_num_selector_weights = 16;
+ ccell_params.m_pSelector_weights = g_astc_weights4;
+ ccell_params.m_pSelector_weightsx = (const bc7enc_vec4F*)g_astc_weights4x;
+ ccell_params.m_astc_endpoint_range = endpoint_range;
+ ccell_params.m_weights[0] = 1;
+ ccell_params.m_weights[1] = 1;
+ ccell_params.m_weights[2] = 1;
+ ccell_params.m_weights[3] = 1;
+ ccell_params.m_has_alpha = true;
+
+ color_cell_compressor_results ccell_results;
+ uint8_t ccell_result_selectors[16];
+ uint8_t ccell_result_selectors_temp[16];
+ memset(&ccell_results, 0, sizeof(ccell_results));
+ ccell_results.m_pSelectors = &ccell_result_selectors[0];
+ ccell_results.m_pSelectors_temp = &ccell_result_selectors_temp[0];
+
+ color_cell_compression(255, &ccell_params, &ccell_results, &comp_params);
+
+ // ASTC
+ astc_block_desc astc_results;
+ memset(&astc_results, 0, sizeof(astc_results));
+
+ astc_results.m_dual_plane = false;
+ astc_results.m_weight_range = weight_range;
+
+ astc_results.m_ccs = 0;
+ astc_results.m_subsets = 1;
+ astc_results.m_partition_seed = 0;
+ astc_results.m_cem = 4;
+
+ astc_results.m_endpoints[0] = ccell_results.m_astc_low_endpoint.m_c[0];
+ astc_results.m_endpoints[1] = ccell_results.m_astc_high_endpoint.m_c[0];
+
+ astc_results.m_endpoints[2] = ccell_results.m_astc_low_endpoint.m_c[3];
+ astc_results.m_endpoints[3] = ccell_results.m_astc_high_endpoint.m_c[3];
+
+ for (uint32_t y = 0; y < 4; y++)
+ for (uint32_t x = 0; x < 4; x++)
+ astc_results.m_weights[x + y * 4] = ccell_result_selectors[x + y * 4];
+
+ color_rgba colors[16];
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ colors[0].m_comps[c] = g_astc_unquant[endpoint_range][ccell_results.m_astc_low_endpoint.m_c[(c < 3) ? 0 : 3]].m_unquant;
+ colors[15].m_comps[c] = g_astc_unquant[endpoint_range][ccell_results.m_astc_high_endpoint.m_c[(c < 3) ? 0 : 3]].m_unquant;
+ }
+
+ for (uint32_t i = 1; i < 16 - 1; i++)
+ for (uint32_t c = 0; c < 4; c++)
+ colors[i].m_comps[c] = (uint8_t)astc_interpolate(colors[0].m_comps[c], colors[15].m_comps[c], g_astc_weights4[i], false);
+
+ uint64_t total_err = 0;
+ for (uint32_t p = 0; p < 16; p++)
+ total_err += color_distance_la(((const color_rgba*)block)[p], colors[ccell_result_selectors[p]]);
+
+ assert(total_results < MAX_ENCODE_RESULTS);
+ if (total_results < MAX_ENCODE_RESULTS)
+ {
+ pResults[total_results].m_uastc_mode = 15;
+ pResults[total_results].m_common_pattern = 0;
+ pResults[total_results].m_astc = astc_results;
+ pResults[total_results].m_astc_err = total_err;
+ total_results++;
+ }
+ }
+
+ static void compute_block_error(const color_rgba block[4][4], const color_rgba decoded_block[4][4], uint64_t &total_rgb_err, uint64_t &total_rgba_err, uint64_t &total_la_err)
+ {
+ uint64_t total_err_r = 0, total_err_g = 0, total_err_b = 0, total_err_a = 0;
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const int dr = (int)block[y][x].m_comps[0] - (int)decoded_block[y][x].m_comps[0];
+ const int dg = (int)block[y][x].m_comps[1] - (int)decoded_block[y][x].m_comps[1];
+ const int db = (int)block[y][x].m_comps[2] - (int)decoded_block[y][x].m_comps[2];
+ const int da = (int)block[y][x].m_comps[3] - (int)decoded_block[y][x].m_comps[3];
+
+ total_err_r += dr * dr;
+ total_err_g += dg * dg;
+ total_err_b += db * db;
+ total_err_a += da * da;
+ }
+ }
+
+ total_la_err = total_err_r + total_err_a;
+ total_rgb_err = total_err_r + total_err_g + total_err_b;
+ total_rgba_err = total_rgb_err + total_err_a;
+ }
+
+ static void compute_bc1_hints(bool &bc1_hint0, bool &bc1_hint1, const uastc_encode_results &best_results, const color_rgba block[4][4], const color_rgba decoded_uastc_block[4][4])
+ {
+ const uint32_t best_mode = best_results.m_uastc_mode;
+ const bool perceptual = false;
+
+ bc1_hint0 = false;
+ bc1_hint1 = false;
+
+ if (best_mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ return;
+
+ if (!g_uastc_mode_has_bc1_hint0[best_mode] && !g_uastc_mode_has_bc1_hint1[best_mode])
+ return;
+
+ color_rgba tblock_bc1[4][4];
+ dxt1_block tbc1_block[8];
+ basist::encode_bc1(tbc1_block, (const uint8_t*)&decoded_uastc_block[0][0], 0);
+ unpack_block(texture_format::cBC1, tbc1_block, &tblock_bc1[0][0]);
+
+ color_rgba tblock_hint0_bc1[4][4];
+ color_rgba tblock_hint1_bc1[4][4];
+
+ etc_block etc1_blk;
+ memset(&etc1_blk, 0, sizeof(etc1_blk));
+
+ eac_a8_block etc2_blk;
+ memset(&etc2_blk, 0, sizeof(etc2_blk));
+ etc2_blk.m_multiplier = 1;
+
+ // Pack to UASTC, then unpack, because the endpoints may be swapped.
+
+ uastc_block temp_ublock;
+ pack_uastc(temp_ublock, best_results, etc1_blk, 0, etc2_blk, false, false);
+
+ unpacked_uastc_block temp_ublock_unpacked;
+ unpack_uastc(temp_ublock, temp_ublock_unpacked, false);
+
+ unpacked_uastc_block ublock;
+ memset(&ublock, 0, sizeof(ublock));
+ ublock.m_mode = best_results.m_uastc_mode;
+ ublock.m_common_pattern = best_results.m_common_pattern;
+ ublock.m_astc = temp_ublock_unpacked.m_astc;
+
+ dxt1_block b;
+
+ // HINT1
+ if (!g_uastc_mode_has_bc1_hint1[best_mode])
+ {
+ memset(tblock_hint1_bc1, 0, sizeof(tblock_hint1_bc1));
+ }
+ else
+ {
+ transcode_uastc_to_bc1_hint1(ublock, (color32 (*)[4]) decoded_uastc_block, &b, false);
+
+ unpack_block(texture_format::cBC1, &b, &tblock_hint1_bc1[0][0]);
+ }
+
+ // HINT0
+ if (!g_uastc_mode_has_bc1_hint0[best_mode])
+ {
+ memset(tblock_hint0_bc1, 0, sizeof(tblock_hint0_bc1));
+ }
+ else
+ {
+ transcode_uastc_to_bc1_hint0(ublock, &b);
+
+ unpack_block(texture_format::cBC1, &b, &tblock_hint0_bc1[0][0]);
+ }
+
+ // Compute block errors
+ uint64_t total_t_err = 0, total_hint0_err = 0, total_hint1_err = 0;
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ total_t_err += color_distance(perceptual, block[y][x], tblock_bc1[y][x], false);
+ total_hint0_err += color_distance(perceptual, block[y][x], tblock_hint0_bc1[y][x], false);
+ total_hint1_err += color_distance(perceptual, block[y][x], tblock_hint1_bc1[y][x], false);
+ }
+ }
+
+ const float t_err = sqrtf((float)total_t_err);
+ const float t_err_hint0 = sqrtf((float)total_hint0_err);
+ const float t_err_hint1 = sqrtf((float)total_hint1_err);
+
+ const float err_thresh0 = 1.075f;
+ const float err_thresh1 = 1.075f;
+
+ if ((g_uastc_mode_has_bc1_hint0[best_mode]) && (t_err_hint0 <= t_err * err_thresh0))
+ bc1_hint0 = true;
+
+ if ((g_uastc_mode_has_bc1_hint1[best_mode]) && (t_err_hint1 <= t_err * err_thresh1))
+ bc1_hint1 = true;
+ }
+
+ struct ycbcr
+ {
+ int32_t m_y;
+ int32_t m_cb;
+ int32_t m_cr;
+ };
+
+ static inline void rgb_to_y_cb_cr(const color_rgba& c, ycbcr& dst)
+ {
+ const int y = c.r * 54 + c.g * 183 + c.b * 19;
+ dst.m_y = y;
+ dst.m_cb = (c.b << 8) - y;
+ dst.m_cr = (c.r << 8) - y;
+ }
+
+ static inline uint64_t color_diff(const ycbcr& a, const ycbcr& b)
+ {
+ const int y_delta = a.m_y - b.m_y;
+ const int cb_delta = a.m_cb - b.m_cb;
+ const int cr_delta = a.m_cr - b.m_cr;
+ return ((int64_t)y_delta * y_delta * 4) + ((int64_t)cr_delta * cr_delta) + ((int64_t)cb_delta * cb_delta);
+ }
+
+ static inline int gray_distance2(const color_rgba& c, int r, int g, int b)
+ {
+ int gray_dist = (((int)c[0] - r) + ((int)c[1] - g) + ((int)c[2] - b) + 1) / 3;
+
+ int gray_point_r = clamp255(r + gray_dist);
+ int gray_point_g = clamp255(g + gray_dist);
+ int gray_point_b = clamp255(b + gray_dist);
+
+ int dist_to_gray_point_r = c[0] - gray_point_r;
+ int dist_to_gray_point_g = c[1] - gray_point_g;
+ int dist_to_gray_point_b = c[2] - gray_point_b;
+
+ return (dist_to_gray_point_r * dist_to_gray_point_r) + (dist_to_gray_point_g * dist_to_gray_point_g) + (dist_to_gray_point_b * dist_to_gray_point_b);
+ }
+
+ static bool pack_etc1_estimate_flipped(const color_rgba* pSrc_pixels)
+ {
+ int sums[3][2][2];
+
+#define GET_XY(x, y, c) pSrc_pixels[(x) + ((y) * 4)][c]
+
+ for (uint32_t c = 0; c < 3; c++)
+ {
+ sums[c][0][0] = GET_XY(0, 0, c) + GET_XY(0, 1, c) + GET_XY(1, 0, c) + GET_XY(1, 1, c);
+ sums[c][1][0] = GET_XY(2, 0, c) + GET_XY(2, 1, c) + GET_XY(3, 0, c) + GET_XY(3, 1, c);
+ sums[c][0][1] = GET_XY(0, 2, c) + GET_XY(0, 3, c) + GET_XY(1, 2, c) + GET_XY(1, 3, c);
+ sums[c][1][1] = GET_XY(2, 2, c) + GET_XY(2, 3, c) + GET_XY(3, 2, c) + GET_XY(3, 3, c);
+ }
+
+ int upper_avg[3], lower_avg[3], left_avg[3], right_avg[3];
+ for (uint32_t c = 0; c < 3; c++)
+ {
+ upper_avg[c] = (sums[c][0][0] + sums[c][1][0] + 4) / 8;
+ lower_avg[c] = (sums[c][0][1] + sums[c][1][1] + 4) / 8;
+ left_avg[c] = (sums[c][0][0] + sums[c][0][1] + 4) / 8;
+ right_avg[c] = (sums[c][1][0] + sums[c][1][1] + 4) / 8;
+ }
+
+#undef GET_XY
+#define GET_XY(x, y, a) gray_distance2(pSrc_pixels[(x) + ((y) * 4)], a[0], a[1], a[2])
+
+ int upper_gray_dist = 0, lower_gray_dist = 0, left_gray_dist = 0, right_gray_dist = 0;
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ for (uint32_t j = 0; j < 2; j++)
+ {
+ upper_gray_dist += GET_XY(i, j, upper_avg);
+ lower_gray_dist += GET_XY(i, 2 + j, lower_avg);
+ left_gray_dist += GET_XY(j, i, left_avg);
+ right_gray_dist += GET_XY(2 + j, i, right_avg);
+ }
+ }
+
+#undef GET_XY
+
+ int upper_lower_sum = upper_gray_dist + lower_gray_dist;
+ int left_right_sum = left_gray_dist + right_gray_dist;
+
+ return upper_lower_sum < left_right_sum;
+ }
+
+ static void compute_etc1_hints(etc_block& best_etc1_blk, uint32_t& best_etc1_bias, const uastc_encode_results& best_results, const color_rgba block[4][4], const color_rgba decoded_uastc_block[4][4], int level, uint32_t flags)
+ {
+ best_etc1_bias = 0;
+
+ if (best_results.m_uastc_mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ pack_etc1_block_solid_color(best_etc1_blk, &best_results.m_solid_color.m_comps[0]);
+ return;
+ }
+
+ const bool faster_etc1 = (flags & cPackUASTCETC1FasterHints) != 0;
+ const bool fastest_etc1 = (flags & cPackUASTCETC1FastestHints) != 0;
+
+ const bool has_bias = g_uastc_mode_has_etc1_bias[best_results.m_uastc_mode];
+
+ // 0 should be at the top, but we need 13 first because it represents bias (0,0,0).
+ const uint8_t s_sorted_bias_modes[32] = { 13, 0, 22, 29, 27, 12, 26, 9, 30, 31, 8, 10, 25, 2, 23, 5, 15, 7, 3, 11, 6, 17, 28, 18, 1, 19, 20, 21, 24, 4, 14, 16 };
+
+ uint32_t last_bias = 1;
+ bool use_faster_bias_mode_table = false;
+ const bool flip_estimate = (level <= cPackUASTCLevelFaster) || (faster_etc1) || (fastest_etc1);
+ if (has_bias)
+ {
+ switch (level)
+ {
+ case cPackUASTCLevelFastest:
+ {
+ last_bias = fastest_etc1 ? 1 : (faster_etc1 ? 1 : 2);
+ use_faster_bias_mode_table = true;
+ break;
+ }
+ case cPackUASTCLevelFaster:
+ {
+ last_bias = fastest_etc1 ? 1 : (faster_etc1 ? 3 : 5);
+ use_faster_bias_mode_table = true;
+ break;
+ }
+ case cPackUASTCLevelDefault:
+ {
+ last_bias = fastest_etc1 ? 1 : (faster_etc1 ? 10 : 20);
+ use_faster_bias_mode_table = true;
+ break;
+ }
+ case cPackUASTCLevelSlower:
+ {
+ last_bias = fastest_etc1 ? 1 : (faster_etc1 ? 16 : 32);
+ use_faster_bias_mode_table = true;
+ break;
+ }
+ default:
+ {
+ last_bias = 32;
+ break;
+ }
+ }
+ }
+
+ memset(&best_etc1_blk, 0, sizeof(best_etc1_blk));
+ uint64_t best_err = UINT64_MAX;
+
+ etc_block trial_block;
+ memset(&trial_block, 0, sizeof(trial_block));
+
+ ycbcr block_ycbcr[4][4], decoded_uastc_block_ycbcr[4][4];
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ rgb_to_y_cb_cr(block[y][x], block_ycbcr[y][x]);
+ rgb_to_y_cb_cr(decoded_uastc_block[y][x], decoded_uastc_block_ycbcr[y][x]);
+ }
+ }
+
+ uint32_t first_flip = 0, last_flip = 2;
+ uint32_t first_individ = 0, last_individ = 2;
+
+ if (flags & cPackUASTCETC1DisableFlipAndIndividual)
+ {
+ last_flip = 1;
+ last_individ = 1;
+ }
+ else if (flip_estimate)
+ {
+ if (pack_etc1_estimate_flipped(&decoded_uastc_block[0][0]))
+ first_flip = 1;
+ last_flip = first_flip + 1;
+ }
+
+ for (uint32_t flip = first_flip; flip < last_flip; flip++)
+ {
+ trial_block.set_flip_bit(flip != 0);
+
+ for (uint32_t individ = first_individ; individ < last_individ; individ++)
+ {
+ const uint32_t mul = individ ? 15 : 31;
+
+ trial_block.set_diff_bit(individ == 0);
+
+ color_rgba unbiased_block_colors[2];
+
+ int min_r[2] = { 255, 255 }, min_g[2] = { 255, 255 }, min_b[2] = { 255, 255 }, max_r[2] = { 0, 0 }, max_g[2] = { 0, 0 }, max_b[2] = { 0, 0 };
+
+ for (uint32_t subset = 0; subset < 2; subset++)
+ {
+ uint32_t avg_color[3];
+ memset(avg_color, 0, sizeof(avg_color));
+
+ for (uint32_t j = 0; j < 8; j++)
+ {
+ const etc_coord2 &c = g_etc1_pixel_coords[flip][subset][j];
+ const color_rgba& p = decoded_uastc_block[c.m_y][c.m_x];
+
+ avg_color[0] += p.r;
+ avg_color[1] += p.g;
+ avg_color[2] += p.b;
+
+ min_r[subset] = basisu::minimum<uint32_t>(min_r[subset], p.r);
+ min_g[subset] = basisu::minimum<uint32_t>(min_g[subset], p.g);
+ min_b[subset] = basisu::minimum<uint32_t>(min_b[subset], p.b);
+
+ max_r[subset] = basisu::maximum<uint32_t>(max_r[subset], p.r);
+ max_g[subset] = basisu::maximum<uint32_t>(max_g[subset], p.g);
+ max_b[subset] = basisu::maximum<uint32_t>(max_b[subset], p.b);
+ } // j
+
+ unbiased_block_colors[subset][0] = (uint8_t)((avg_color[0] * mul + 1020) / (8 * 255));
+ unbiased_block_colors[subset][1] = (uint8_t)((avg_color[1] * mul + 1020) / (8 * 255));
+ unbiased_block_colors[subset][2] = (uint8_t)((avg_color[2] * mul + 1020) / (8 * 255));
+ unbiased_block_colors[subset][3] = 0;
+
+ } // subset
+
+ for (uint32_t bias_iter = 0; bias_iter < last_bias; bias_iter++)
+ {
+ const uint32_t bias = use_faster_bias_mode_table ? s_sorted_bias_modes[bias_iter] : bias_iter;
+
+ color_rgba block_colors[2];
+ for (uint32_t subset = 0; subset < 2; subset++)
+ block_colors[subset] = has_bias ? apply_etc1_bias((color32&)unbiased_block_colors[subset], bias, mul, subset) : unbiased_block_colors[subset];
+
+ if (individ)
+ trial_block.set_block_color4(block_colors[0], block_colors[1]);
+ else
+ trial_block.set_block_color5_clamp(block_colors[0], block_colors[1]);
+
+ uint32_t range[2];
+ for (uint32_t subset = 0; subset < 2; subset++)
+ {
+ const color_rgba base_c(trial_block.get_block_color(subset, true));
+
+ const int pos_r = iabs(max_r[subset] - base_c.r);
+ const int neg_r = iabs(base_c.r - min_r[subset]);
+
+ const int pos_g = iabs(max_g[subset] - base_c.g);
+ const int neg_g = iabs(base_c.g - min_g[subset]);
+
+ const int pos_b = iabs(max_b[subset] - base_c.b);
+ const int neg_b = iabs(base_c.b - min_b[subset]);
+
+ range[subset] = maximum(maximum(pos_r, neg_r, pos_g, neg_g), pos_b, neg_b);
+ }
+
+ uint32_t best_inten_table[2] = { 0, 0 };
+
+ for (uint32_t subset = 0; subset < 2; subset++)
+ {
+ uint64_t best_subset_err = UINT64_MAX;
+
+ const uint32_t inten_table_limit = (level == cPackUASTCLevelVerySlow) ? 8 : ((range[subset] > 51) ? 8 : (range[subset] >= 7 ? 4 : 2));
+
+ for (uint32_t inten_table = 0; inten_table < inten_table_limit; inten_table++)
+ {
+ trial_block.set_inten_table(subset, inten_table);
+
+ color_rgba color_table[4];
+ trial_block.get_block_colors(color_table, subset);
+
+ ycbcr color_table_ycbcr[4];
+ for (uint32_t i = 0; i < 4; i++)
+ rgb_to_y_cb_cr(color_table[i], color_table_ycbcr[i]);
+
+ uint64_t total_error = 0;
+ if (flip)
+ {
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ {
+ const ycbcr& c = decoded_uastc_block_ycbcr[subset * 2 + y][0];
+ total_error += minimum(color_diff(color_table_ycbcr[0], c), color_diff(color_table_ycbcr[1], c), color_diff(color_table_ycbcr[2], c), color_diff(color_table_ycbcr[3], c));
+ }
+ {
+ const ycbcr& c = decoded_uastc_block_ycbcr[subset * 2 + y][1];
+ total_error += minimum(color_diff(color_table_ycbcr[0], c), color_diff(color_table_ycbcr[1], c), color_diff(color_table_ycbcr[2], c), color_diff(color_table_ycbcr[3], c));
+ }
+ {
+ const ycbcr& c = decoded_uastc_block_ycbcr[subset * 2 + y][2];
+ total_error += minimum(color_diff(color_table_ycbcr[0], c), color_diff(color_table_ycbcr[1], c), color_diff(color_table_ycbcr[2], c), color_diff(color_table_ycbcr[3], c));
+ }
+ {
+ const ycbcr& c = decoded_uastc_block_ycbcr[subset * 2 + y][3];
+ total_error += minimum(color_diff(color_table_ycbcr[0], c), color_diff(color_table_ycbcr[1], c), color_diff(color_table_ycbcr[2], c), color_diff(color_table_ycbcr[3], c));
+ }
+ if (total_error >= best_subset_err)
+ break;
+ }
+ }
+ else
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ {
+ const ycbcr& c = decoded_uastc_block_ycbcr[y][subset * 2 + 0];
+ total_error += minimum(color_diff(color_table_ycbcr[0], c), color_diff(color_table_ycbcr[1], c), color_diff(color_table_ycbcr[2], c), color_diff(color_table_ycbcr[3], c));
+ }
+ {
+ const ycbcr& c = decoded_uastc_block_ycbcr[y][subset * 2 + 1];
+ total_error += minimum(color_diff(color_table_ycbcr[0], c), color_diff(color_table_ycbcr[1], c), color_diff(color_table_ycbcr[2], c), color_diff(color_table_ycbcr[3], c));
+ }
+ }
+ if (total_error >= best_subset_err)
+ break;
+ }
+
+ if (total_error < best_subset_err)
+ {
+ best_subset_err = total_error;
+ best_inten_table[subset] = inten_table;
+ }
+
+ } // inten_table
+
+ } // subset
+
+ trial_block.set_inten_table(0, best_inten_table[0]);
+ trial_block.set_inten_table(1, best_inten_table[1]);
+
+ // Compute error against the ORIGINAL block.
+ uint64_t err = 0;
+
+ for (uint32_t subset = 0; subset < 2; subset++)
+ {
+ color_rgba color_table[4];
+ trial_block.get_block_colors(color_table, subset);
+
+ ycbcr color_table_ycbcr[4];
+ for (uint32_t i = 0; i < 4; i++)
+ rgb_to_y_cb_cr(color_table[i], color_table_ycbcr[i]);
+
+ if (flip)
+ {
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const ycbcr& c = decoded_uastc_block_ycbcr[subset * 2 + y][x];
+ const uint64_t best_index_err = minimum(color_diff(color_table_ycbcr[0], c) << 2, (color_diff(color_table_ycbcr[1], c) << 2) + 1, (color_diff(color_table_ycbcr[2], c) << 2) + 2, (color_diff(color_table_ycbcr[3], c) << 2) + 3);
+
+ const uint32_t best_index = (uint32_t)best_index_err & 3;
+ err += color_diff(block_ycbcr[subset * 2 + y][x], color_table_ycbcr[best_index]);
+ }
+ if (err >= best_err)
+ break;
+ }
+ }
+ else
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 2; x++)
+ {
+ const ycbcr& c = decoded_uastc_block_ycbcr[y][subset * 2 + x];
+ const uint64_t best_index_err = minimum(color_diff(color_table_ycbcr[0], c) << 2, (color_diff(color_table_ycbcr[1], c) << 2) + 1, (color_diff(color_table_ycbcr[2], c) << 2) + 2, (color_diff(color_table_ycbcr[3], c) << 2) + 3);
+
+ const uint32_t best_index = (uint32_t)best_index_err & 3;
+ err += color_diff(block_ycbcr[y][subset * 2 + x], color_table_ycbcr[best_index]);
+ }
+ if (err >= best_err)
+ break;
+ }
+ }
+
+ } // subset
+
+ if (err < best_err)
+ {
+ best_err = err;
+
+ best_etc1_blk = trial_block;
+ best_etc1_bias = bias;
+ }
+
+ } // bias_iter
+
+ } // individ
+
+ } // flip
+ }
+
+ struct uastc_pack_eac_a8_results
+ {
+ uint32_t m_base;
+ uint32_t m_table;
+ uint32_t m_multiplier;
+ };
+
+ static uint64_t uastc_pack_eac_a8(uastc_pack_eac_a8_results& results, const uint8_t* pPixels, uint32_t num_pixels, uint32_t base_search_rad, uint32_t mul_search_rad, uint32_t table_mask)
+ {
+ assert(num_pixels <= 16);
+
+ uint32_t min_alpha = 255, max_alpha = 0;
+ for (uint32_t i = 0; i < num_pixels; i++)
+ {
+ const uint32_t a = pPixels[i];
+ if (a < min_alpha) min_alpha = a;
+ if (a > max_alpha) max_alpha = a;
+ }
+
+ if (min_alpha == max_alpha)
+ {
+ results.m_base = min_alpha;
+ results.m_table = 13;
+ results.m_multiplier = 1;
+ return 0;
+ }
+
+ const uint32_t alpha_range = max_alpha - min_alpha;
+
+ uint64_t best_err = UINT64_MAX;
+
+ for (uint32_t table = 0; table < 16; table++)
+ {
+ if ((table_mask & (1U << table)) == 0)
+ continue;
+
+ const float range = (float)(g_etc2_eac_tables[table][ETC2_EAC_MAX_VALUE_SELECTOR] - g_etc2_eac_tables[table][ETC2_EAC_MIN_VALUE_SELECTOR]);
+ const int center = (int)roundf(lerp((float)min_alpha, (float)max_alpha, (float)(0 - g_etc2_eac_tables[table][ETC2_EAC_MIN_VALUE_SELECTOR]) / range));
+
+ const int base_min = clamp255(center - base_search_rad);
+ const int base_max = clamp255(center + base_search_rad);
+
+ const int mul = (int)roundf(alpha_range / range);
+ const int mul_low = clamp<int>(mul - mul_search_rad, 1, 15);
+ const int mul_high = clamp<int>(mul + mul_search_rad, 1, 15);
+
+ for (int base = base_min; base <= base_max; base++)
+ {
+ for (int multiplier = mul_low; multiplier <= mul_high; multiplier++)
+ {
+ uint64_t total_err = 0;
+
+ for (uint32_t i = 0; i < num_pixels; i++)
+ {
+ const int a = pPixels[i];
+
+ uint32_t best_s_err = UINT32_MAX;
+ //uint32_t best_s = 0;
+ for (uint32_t s = 0; s < 8; s++)
+ {
+ const int v = clamp255((int)multiplier * g_etc2_eac_tables[table][s] + (int)base);
+
+ uint32_t err = iabs(a - v);
+ if (err < best_s_err)
+ {
+ best_s_err = err;
+ //best_s = s;
+ }
+ }
+
+ total_err += best_s_err * best_s_err;
+ if (total_err >= best_err)
+ break;
+ }
+
+ if (total_err < best_err)
+ {
+ best_err = total_err;
+ results.m_base = base;
+ results.m_multiplier = multiplier;
+ results.m_table = table;
+ if (!best_err)
+ return best_err;
+ }
+
+ } // table
+
+ } // multiplier
+
+ } // base
+
+ return best_err;
+ }
+
+ const int32_t DEFAULT_BC7_ERROR_WEIGHT = 50;
+ const float UASTC_ERROR_THRESH = 1.3f;
+
+ // TODO: This is a quick hack to favor certain modes when we know we'll be followed up with an RDO postprocess.
+ static inline float get_uastc_mode_weight(uint32_t mode)
+ {
+ const float FAVORED_MODE_WEIGHT = .8f;
+
+ switch (mode)
+ {
+ case 0:
+ case 10:
+ return FAVORED_MODE_WEIGHT;
+ default:
+ break;
+ }
+
+ return 1.0f;
+ }
+
+ void encode_uastc(const uint8_t* pRGBAPixels, uastc_block& output_block, uint32_t flags)
+ {
+// printf("encode_uastc: \n");
+// for (int i = 0; i < 16; i++)
+// printf("[%u %u %u %u] ", pRGBAPixels[i * 4 + 0], pRGBAPixels[i * 4 + 1], pRGBAPixels[i * 4 + 2], pRGBAPixels[i * 4 + 3]);
+// printf("\n");
+
+ const color_rgba(*block)[4] = reinterpret_cast<const color_rgba(*)[4]>(pRGBAPixels);
+
+ bool solid_color = true, has_alpha = false, is_la = true;
+
+ const color_rgba first_color(block[0][0]);
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ if (block[y][x].a < 255)
+ has_alpha = true;
+
+ if (block[y][x] != first_color)
+ solid_color = false;
+
+ if ((block[y][x].r != block[y][x].g) || (block[y][x].r != block[y][x].b))
+ is_la = false;
+ }
+ }
+
+ if (solid_color)
+ {
+ // Solid color blocks are so common that we handle them specially and as quickly as we can.
+ uastc_encode_results solid_results;
+ solid_results.m_uastc_mode = UASTC_MODE_INDEX_SOLID_COLOR;
+ solid_results.m_astc_err = 0;
+ solid_results.m_common_pattern = 0;
+ solid_results.m_solid_color = first_color;
+ memset(&solid_results.m_astc, 0, sizeof(solid_results.m_astc));
+
+ etc_block etc1_blk;
+ uint32_t etc1_bias = 0;
+
+ pack_etc1_block_solid_color(etc1_blk, &first_color.m_comps[0]);
+
+ eac_a8_block eac_a8_blk;
+ eac_a8_blk.m_table = 0;
+ eac_a8_blk.m_multiplier = 1;
+
+ pack_uastc(output_block, solid_results, etc1_blk, etc1_bias, eac_a8_blk, false, false);
+
+// printf(" Solid\n");
+
+ return;
+ }
+
+ int level = flags & 7;
+ const bool favor_uastc_error = (flags & cPackUASTCFavorUASTCError) != 0;
+ const bool favor_bc7_error = !favor_uastc_error && ((flags & cPackUASTCFavorBC7Error) != 0);
+ //const bool etc1_perceptual = true;
+
+ uastc_encode_results results[MAX_ENCODE_RESULTS];
+
+ level = clampi(level, cPackUASTCLevelFastest, cPackUASTCLevelVerySlow);
+
+ // Set all options to slowest, then configure from there depending on the selected level.
+ uint32_t mode_mask = UINT32_MAX;
+ uint32_t uber_level = 6;
+ bool estimate_partition = false;
+ bool always_try_alpha_modes = true;
+ uint32_t eac_a8_mul_search_rad = 3;
+ uint32_t eac_a8_table_mask = UINT32_MAX;
+ uint32_t least_squares_passes = 2;
+ bool bc1_hints = true;
+ bool only_use_la_on_transparent_blocks = false;
+
+ switch (level)
+ {
+ case cPackUASTCLevelFastest:
+ {
+ mode_mask = (1 << 0) | (1 << 8) |
+ (1 << 11) | (1 << 12) |
+ (1 << 15);
+ always_try_alpha_modes = false;
+ eac_a8_mul_search_rad = 0;
+ eac_a8_table_mask = (1 << 2) | (1 << 8) | (1 << 11) | (1 << 13);
+ uber_level = 0;
+ least_squares_passes = 1;
+ bc1_hints = false;
+ estimate_partition = true;
+ only_use_la_on_transparent_blocks = true;
+ break;
+ }
+ case cPackUASTCLevelFaster:
+ {
+ mode_mask = (1 << 0) | (1 << 4) | (1 << 6) | (1 << 8) |
+ (1 << 9) | (1 << 11) | (1 << 12) |
+ (1 << 15) | (1 << 17);
+ always_try_alpha_modes = false;
+ eac_a8_mul_search_rad = 0;
+ eac_a8_table_mask = (1 << 2) | (1 << 8) | (1 << 11) | (1 << 13);
+ uber_level = 0;
+ least_squares_passes = 1;
+ estimate_partition = true;
+ break;
+ }
+ case cPackUASTCLevelDefault:
+ {
+ mode_mask = (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) |
+ (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | (1 << 13) |
+ (1 << 15) | (1 << 16) | (1 << 17);
+ always_try_alpha_modes = false;
+ eac_a8_mul_search_rad = 1;
+ eac_a8_table_mask = (1 << 0) | (1 << 2) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 10) | (1 << 11) | (1 << 13);
+ uber_level = 1;
+ least_squares_passes = 1;
+ estimate_partition = true;
+ break;
+ }
+ case cPackUASTCLevelSlower:
+ {
+ always_try_alpha_modes = false;
+ eac_a8_mul_search_rad = 2;
+ uber_level = 3;
+ estimate_partition = true;
+ break;
+ }
+ case cPackUASTCLevelVerySlow:
+ {
+ break;
+ }
+ }
+
+#if BASISU_SUPPORT_FORCE_MODE
+ static int force_mode = -1;
+ force_mode = (force_mode + 1) % TOTAL_UASTC_MODES;
+ mode_mask = UINT32_MAX;
+ always_try_alpha_modes = true;
+ only_use_la_on_transparent_blocks = false;
+#endif
+
+ // HACK HACK
+ //mode_mask &= ~(1 << 18);
+ //mode_mask = (1 << 18)| (1 << 10);
+
+ uint32_t total_results = 0;
+
+ if (only_use_la_on_transparent_blocks)
+ {
+ if ((is_la) && (!has_alpha))
+ is_la = false;
+ }
+
+ const bool try_alpha_modes = has_alpha || always_try_alpha_modes;
+
+ bc7enc_compress_block_params comp_params;
+ memset(&comp_params, 0, sizeof(comp_params));
+ comp_params.m_max_partitions_mode1 = 64;
+ comp_params.m_least_squares_passes = least_squares_passes;
+ comp_params.m_weights[0] = 1;
+ comp_params.m_weights[1] = 1;
+ comp_params.m_weights[2] = 1;
+ comp_params.m_weights[3] = 1;
+ comp_params.m_uber_level = uber_level;
+
+ if (is_la)
+ {
+ if (mode_mask & (1U << 15))
+ astc_mode15(block, results, total_results, comp_params);
+
+ if (mode_mask & (1U << 16))
+ astc_mode9_or_16(16, block, results, total_results, comp_params, estimate_partition ? 4 : 0);
+
+ if (mode_mask & (1U << 17))
+ astc_mode11_or_17(17, block, results, total_results, comp_params);
+ }
+
+ if (!has_alpha)
+ {
+ if (mode_mask & (1U << 0))
+ astc_mode0_or_18(0, block, results, total_results, comp_params);
+
+ if (mode_mask & (1U << 1))
+ astc_mode1(block, results, total_results, comp_params);
+
+ if (mode_mask & (1U << 2))
+ astc_mode2(block, results, total_results, comp_params, estimate_partition);
+
+ if (mode_mask & (1U << 3))
+ astc_mode3(block, results, total_results, comp_params, estimate_partition);
+
+ if (mode_mask & (1U << 4))
+ astc_mode4(block, results, total_results, comp_params, estimate_partition);
+
+ if (mode_mask & (1U << 5))
+ astc_mode5(block, results, total_results, comp_params);
+
+ if (mode_mask & (1U << 6))
+ astc_mode6(block, results, total_results, comp_params);
+
+ if (mode_mask & (1U << 7))
+ astc_mode7(block, results, total_results, comp_params, estimate_partition);
+
+ if (mode_mask & (1U << 18))
+ astc_mode0_or_18(18, block, results, total_results, comp_params);
+ }
+
+ if (try_alpha_modes)
+ {
+ if (mode_mask & (1U << 9))
+ astc_mode9_or_16(9, block, results, total_results, comp_params, estimate_partition ? 4 : 0);
+
+ if (mode_mask & (1U << 10))
+ astc_mode10(block, results, total_results, comp_params);
+
+ if (mode_mask & (1U << 11))
+ astc_mode11_or_17(11, block, results, total_results, comp_params);
+
+ if (mode_mask & (1U << 12))
+ astc_mode12(block, results, total_results, comp_params);
+
+ if (mode_mask & (1U << 13))
+ astc_mode13(block, results, total_results, comp_params);
+
+ if (mode_mask & (1U << 14))
+ astc_mode14(block, results, total_results, comp_params);
+ }
+
+ assert(total_results);
+
+ // Fix up the errors so we consistently have LA, RGB, or RGBA error.
+ for (uint32_t i = 0; i < total_results; i++)
+ {
+ uastc_encode_results& r = results[i];
+ if (!is_la)
+ {
+ if (g_uastc_mode_is_la[r.m_uastc_mode])
+ {
+ color_rgba unpacked_block[16];
+ unpack_uastc(r.m_uastc_mode, r.m_common_pattern, r.m_solid_color.get_color32(), r.m_astc, (basist::color32 *)unpacked_block, false);
+
+ uint64_t total_err = 0;
+ for (uint32_t j = 0; j < 16; j++)
+ total_err += color_distance(unpacked_block[j], ((const color_rgba*)block)[j], true);
+
+ r.m_astc_err = total_err;
+ }
+ }
+ else
+ {
+ if (!g_uastc_mode_is_la[r.m_uastc_mode])
+ {
+ color_rgba unpacked_block[16];
+ unpack_uastc(r.m_uastc_mode, r.m_common_pattern, r.m_solid_color.get_color32(), r.m_astc, (basist::color32 *)unpacked_block, false);
+
+ uint64_t total_err = 0;
+ for (uint32_t j = 0; j < 16; j++)
+ total_err += color_distance_la(unpacked_block[j], ((const color_rgba*)block)[j]);
+
+ r.m_astc_err = total_err;
+ }
+ }
+ }
+
+ unpacked_uastc_block unpacked_ublock;
+ memset(&unpacked_ublock, 0, sizeof(unpacked_ublock));
+
+ uint64_t total_overall_err[MAX_ENCODE_RESULTS];
+ float uastc_err_f[MAX_ENCODE_RESULTS];
+ double best_uastc_err_f = 1e+20f;
+
+ int best_index = -1;
+
+ if (total_results == 1)
+ {
+ best_index = 0;
+ }
+ else
+ {
+ const uint32_t bc7_err_weight = favor_bc7_error ? 100 : ((favor_uastc_error ? 0 : DEFAULT_BC7_ERROR_WEIGHT));
+ const uint32_t uastc_err_weight = favor_bc7_error ? 0 : 100;
+
+ // Find best overall results, balancing UASTC and UASTC->BC7 error.
+ // We purposely allow UASTC error to increase a little, if doing so lowers the BC7 error.
+ for (uint32_t i = 0; i < total_results; i++)
+ {
+#if BASISU_SUPPORT_FORCE_MODE
+ if (results[i].m_uastc_mode == force_mode)
+ {
+ best_index = i;
+ break;
+ }
+#endif
+
+ unpacked_ublock.m_mode = results[i].m_uastc_mode;
+ unpacked_ublock.m_astc = results[i].m_astc;
+ unpacked_ublock.m_common_pattern = results[i].m_common_pattern;
+ unpacked_ublock.m_solid_color = results[i].m_solid_color.get_color32();
+
+ color_rgba decoded_uastc_block[4][4];
+ bool success = unpack_uastc(results[i].m_uastc_mode, results[i].m_common_pattern, results[i].m_solid_color.get_color32(), results[i].m_astc, (basist::color32 *)&decoded_uastc_block[0][0], false);
+ (void)success;
+ VALIDATE(success);
+
+ uint64_t total_uastc_rgb_err, total_uastc_rgba_err, total_uastc_la_err;
+ compute_block_error(block, decoded_uastc_block, total_uastc_rgb_err, total_uastc_rgba_err, total_uastc_la_err);
+
+ // Validate the computed error, or we're go mad if it's inaccurate.
+ if (results[i].m_uastc_mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ VALIDATE(total_uastc_rgba_err == 0);
+ }
+ else if (is_la)
+ {
+ VALIDATE(total_uastc_la_err == results[i].m_astc_err);
+ }
+ else if (g_uastc_mode_has_alpha[results[i].m_uastc_mode])
+ {
+ VALIDATE(total_uastc_rgba_err == results[i].m_astc_err);
+ }
+ else
+ {
+ VALIDATE(total_uastc_rgb_err == results[i].m_astc_err);
+ }
+
+ // Transcode to BC7
+ bc7_optimization_results bc7_results;
+ transcode_uastc_to_bc7(unpacked_ublock, bc7_results);
+
+ bc7_block bc7_data;
+ encode_bc7_block(&bc7_data, &bc7_results);
+
+ color_rgba decoded_bc7_block[4][4];
+ unpack_block(texture_format::cBC7, &bc7_data, &decoded_bc7_block[0][0]);
+
+ // Compute BC7 error
+ uint64_t total_bc7_la_err, total_bc7_rgb_err, total_bc7_rgba_err;
+ compute_block_error(block, decoded_bc7_block, total_bc7_rgb_err, total_bc7_rgba_err, total_bc7_la_err);
+
+ if (results[i].m_uastc_mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ VALIDATE(total_bc7_rgba_err == 0);
+
+ best_index = i;
+ break;
+ }
+
+ uint64_t total_uastc_err = 0, total_bc7_err = 0;
+ if (is_la)
+ {
+ total_bc7_err = total_bc7_la_err;
+ total_uastc_err = total_uastc_la_err;
+ }
+ else if (has_alpha)
+ {
+ total_bc7_err = total_bc7_rgba_err;
+ total_uastc_err = total_uastc_rgba_err;
+ }
+ else
+ {
+ total_bc7_err = total_bc7_rgb_err;
+ total_uastc_err = total_uastc_rgb_err;
+ }
+
+ total_overall_err[i] = ((total_bc7_err * bc7_err_weight) / 100) + ((total_uastc_err * uastc_err_weight) / 100);
+ if (!total_overall_err[i])
+ {
+ best_index = i;
+ break;
+ }
+
+ uastc_err_f[i] = sqrtf((float)total_uastc_err);
+
+ if (uastc_err_f[i] < best_uastc_err_f)
+ {
+ best_uastc_err_f = uastc_err_f[i];
+ }
+
+ } // total_results
+
+ if (best_index < 0)
+ {
+ uint64_t best_err = UINT64_MAX;
+
+ if ((best_uastc_err_f == 0.0f) || (favor_bc7_error))
+ {
+ for (uint32_t i = 0; i < total_results; i++)
+ {
+ // TODO: This is a quick hack to favor modes 0 or 10 for better RDO compression.
+ const float err_weight = (flags & cPackUASTCFavorSimplerModes) ? get_uastc_mode_weight(results[i].m_uastc_mode) : 1.0f;
+
+ const uint64_t w = (uint64_t)(total_overall_err[i] * err_weight);
+ if (w < best_err)
+ {
+ best_err = w;
+ best_index = i;
+ if (!best_err)
+ break;
+ }
+ } // i
+ }
+ else
+ {
+ // Scan the UASTC results, and consider all results within a window that has the best UASTC+BC7 error.
+ for (uint32_t i = 0; i < total_results; i++)
+ {
+ double err_delta = uastc_err_f[i] / best_uastc_err_f;
+
+ if (err_delta <= UASTC_ERROR_THRESH)
+ {
+ // TODO: This is a quick hack to favor modes 0 or 10 for better RDO compression.
+ const float err_weight = (flags & cPackUASTCFavorSimplerModes) ? get_uastc_mode_weight(results[i].m_uastc_mode) : 1.0f;
+
+ const uint64_t w = (uint64_t)(total_overall_err[i] * err_weight);
+ if (w < best_err)
+ {
+ best_err = w;
+ best_index = i;
+ if (!best_err)
+ break;
+ }
+ }
+ } // i
+ }
+ }
+ }
+
+ const uastc_encode_results& best_results = results[best_index];
+ const uint32_t best_mode = best_results.m_uastc_mode;
+ const astc_block_desc& best_astc_results = best_results.m_astc;
+
+ color_rgba decoded_uastc_block[4][4];
+ bool success = unpack_uastc(best_mode, best_results.m_common_pattern, best_results.m_solid_color.get_color32(), best_astc_results, (basist::color32 *)&decoded_uastc_block[0][0], false);
+ (void)success;
+ VALIDATE(success);
+
+#if BASISU_VALIDATE_UASTC_ENC
+ // Make sure that the UASTC block unpacks to the same exact pixels as the ASTC block does, using two different decoders.
+ {
+ // Round trip to packed UASTC and back, then decode to pixels.
+ etc_block etc1_blk;
+ memset(&etc1_blk, 0, sizeof(etc1_blk));
+ eac_a8_block etc_eac_a8_blk;
+ memset(&etc_eac_a8_blk, 0, sizeof(etc_eac_a8_blk));
+ etc_eac_a8_blk.m_multiplier = 1;
+
+ basist::uastc_block temp_block;
+ pack_uastc(temp_block, best_results, etc1_blk, 0, etc_eac_a8_blk, false, false);
+
+ basist::color32 temp_block_unpacked[4][4];
+ success = basist::unpack_uastc(temp_block, (basist::color32 *)temp_block_unpacked, false);
+ VALIDATE(success);
+
+ // Now round trip to packed ASTC and back, then decode to pixels.
+ uint32_t astc_data[4];
+
+ if (best_results.m_uastc_mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ pack_astc_solid_block(astc_data, (color32 &)best_results.m_solid_color);
+ else
+ {
+ success = pack_astc_block(astc_data, &best_astc_results, best_results.m_uastc_mode);
+ VALIDATE(success);
+ }
+
+ color_rgba decoded_astc_block[4][4];
+ success = basisu_astc::astc::decompress((uint8_t*)decoded_astc_block, (uint8_t*)&astc_data, false, 4, 4);
+ VALIDATE(success);
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ VALIDATE(decoded_astc_block[y][x] == decoded_uastc_block[y][x]);
+
+ VALIDATE(temp_block_unpacked[y][x].c[0] == decoded_uastc_block[y][x].r);
+ VALIDATE(temp_block_unpacked[y][x].c[1] == decoded_uastc_block[y][x].g);
+ VALIDATE(temp_block_unpacked[y][x].c[2] == decoded_uastc_block[y][x].b);
+ VALIDATE(temp_block_unpacked[y][x].c[3] == decoded_uastc_block[y][x].a);
+ }
+ }
+ }
+#endif
+
+ // Compute BC1 hints
+ bool bc1_hint0 = false, bc1_hint1 = false;
+ if (bc1_hints)
+ compute_bc1_hints(bc1_hint0, bc1_hint1, best_results, block, decoded_uastc_block);
+
+ eac_a8_block eac_a8_blk;
+ if ((g_uastc_mode_has_alpha[best_mode]) && (best_mode != UASTC_MODE_INDEX_SOLID_COLOR))
+ {
+ // Compute ETC2 hints
+ uint8_t decoded_uastc_block_alpha[16];
+ for (uint32_t i = 0; i < 16; i++)
+ decoded_uastc_block_alpha[i] = decoded_uastc_block[i >> 2][i & 3].a;
+
+ uastc_pack_eac_a8_results eac8_a8_results;
+ memset(&eac8_a8_results, 0, sizeof(eac8_a8_results));
+ uastc_pack_eac_a8(eac8_a8_results, decoded_uastc_block_alpha, 16, 0, eac_a8_mul_search_rad, eac_a8_table_mask);
+
+ // All we care about for hinting is the table and multiplier.
+ eac_a8_blk.m_table = eac8_a8_results.m_table;
+ eac_a8_blk.m_multiplier = eac8_a8_results.m_multiplier;
+ }
+ else
+ {
+ memset(&eac_a8_blk, 0, sizeof(eac_a8_blk));
+ }
+
+ // Compute ETC1 hints
+ etc_block etc1_blk;
+ uint32_t etc1_bias = 0;
+ compute_etc1_hints(etc1_blk, etc1_bias, best_results, block, decoded_uastc_block, level, flags);
+
+ // Finally, pack the UASTC block with its hints and we're done.
+ pack_uastc(output_block, best_results, etc1_blk, etc1_bias, eac_a8_blk, bc1_hint0, bc1_hint1);
+
+// printf(" Packed: ");
+// for (int i = 0; i < 16; i++)
+// printf("%X ", output_block.m_bytes[i]);
+// printf("\n");
+ }
+
+ static bool uastc_recompute_hints(basist::uastc_block* pBlock, const color_rgba* pBlock_pixels, uint32_t flags, const unpacked_uastc_block *pUnpacked_blk)
+ {
+ unpacked_uastc_block unpacked_blk;
+
+ if (pUnpacked_blk)
+ unpacked_blk = *pUnpacked_blk;
+ else
+ {
+ if (!unpack_uastc(*pBlock, unpacked_blk, false, true))
+ return false;
+ }
+ color_rgba decoded_uastc_block[4][4];
+ if (!unpack_uastc(unpacked_blk, (basist::color32 *)decoded_uastc_block, false))
+ return false;
+ uastc_encode_results results;
+ results.m_uastc_mode = unpacked_blk.m_mode;
+ results.m_common_pattern = unpacked_blk.m_common_pattern;
+ results.m_astc = unpacked_blk.m_astc;
+ results.m_solid_color = unpacked_blk.m_solid_color;
+ results.m_astc_err = 0;
+ bool bc1_hints = true;
+ uint32_t eac_a8_mul_search_rad = 3;
+ uint32_t eac_a8_table_mask = UINT32_MAX;
+ const uint32_t level = flags & cPackUASTCLevelMask;
+ switch (level)
+ {
+ case cPackUASTCLevelFastest:
+ {
+ eac_a8_mul_search_rad = 0;
+ eac_a8_table_mask = (1 << 2) | (1 << 8) | (1 << 11) | (1 << 13);
+ bc1_hints = false;
+ break;
+ }
+ case cPackUASTCLevelFaster:
+ {
+ eac_a8_mul_search_rad = 0;
+ eac_a8_table_mask = (1 << 2) | (1 << 8) | (1 << 11) | (1 << 13);
+ break;
+ }
+ case cPackUASTCLevelDefault:
+ {
+ eac_a8_mul_search_rad = 1;
+ eac_a8_table_mask = (1 << 0) | (1 << 2) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 10) | (1 << 11) | (1 << 13);
+ break;
+ }
+ case cPackUASTCLevelSlower:
+ {
+ eac_a8_mul_search_rad = 2;
+ break;
+ }
+ case cPackUASTCLevelVerySlow:
+ {
+ break;
+ }
+ }
+ bool bc1_hint0 = false, bc1_hint1 = false;
+ if (bc1_hints)
+ compute_bc1_hints(bc1_hint0, bc1_hint1, results, (color_rgba (*)[4])pBlock_pixels, decoded_uastc_block);
+ const uint32_t best_mode = unpacked_blk.m_mode;
+ eac_a8_block eac_a8_blk;
+ if ((g_uastc_mode_has_alpha[best_mode]) && (best_mode != UASTC_MODE_INDEX_SOLID_COLOR))
+ {
+ uint8_t decoded_uastc_block_alpha[16];
+ for (uint32_t i = 0; i < 16; i++)
+ decoded_uastc_block_alpha[i] = decoded_uastc_block[i >> 2][i & 3].a;
+ uastc_pack_eac_a8_results eac8_a8_results;
+ memset(&eac8_a8_results, 0, sizeof(eac8_a8_results));
+ uastc_pack_eac_a8(eac8_a8_results, decoded_uastc_block_alpha, 16, 0, eac_a8_mul_search_rad, eac_a8_table_mask);
+ eac_a8_blk.m_table = eac8_a8_results.m_table;
+ eac_a8_blk.m_multiplier = eac8_a8_results.m_multiplier;
+ }
+ else
+ {
+ memset(&eac_a8_blk, 0, sizeof(eac_a8_blk));
+ }
+ etc_block etc1_blk;
+ uint32_t etc1_bias = 0;
+ compute_etc1_hints(etc1_blk, etc1_bias, results, (color_rgba (*)[4])pBlock_pixels, decoded_uastc_block, level, flags);
+ pack_uastc(*pBlock, results, etc1_blk, etc1_bias, eac_a8_blk, bc1_hint0, bc1_hint1);
+ return true;
+ }
+
+ static const uint8_t g_uastc_mode_selector_bits[TOTAL_UASTC_MODES][2] =
+ {
+ { 65, 63 }, { 69, 31 }, { 73, 46 }, { 89, 29 },
+ { 89, 30 }, { 68, 47 }, { 66, 62 }, { 89, 30 },
+ { 0, 0 }, { 97, 30 }, { 65, 63 }, { 66, 62 },
+ { 81, 47 }, { 94, 30 }, { 92, 31 }, { 62, 63 },
+ { 98, 30 }, { 61, 62 }, { 49, 79 }
+ };
+
+ static inline uint32_t set_block_bits(uint8_t* pBytes, uint64_t val, uint32_t num_bits, uint32_t cur_ofs)
+ {
+ assert(num_bits <= 64);
+ assert((num_bits == 64) || (val < (1ULL << num_bits)));
+ uint64_t mask = (num_bits == 64) ? UINT64_MAX : ((1ULL << num_bits) - 1);
+ while (num_bits)
+ {
+ const uint32_t n = basisu::minimum<uint32_t>(8U - (cur_ofs & 7U), num_bits);
+ pBytes[cur_ofs >> 3] &= ~static_cast<uint8_t>(mask << (cur_ofs & 7U));
+ pBytes[cur_ofs >> 3] |= static_cast<uint8_t>(val << (cur_ofs & 7U));
+ val >>= n;
+ mask >>= n;
+ num_bits -= n;
+ cur_ofs += n;
+ }
+ return cur_ofs;
+ }
+
+ static const uint8_t g_tdefl_small_dist_extra[512] =
+ {
+ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7
+ };
+
+ static const uint8_t g_tdefl_large_dist_extra[128] =
+ {
+ 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13
+ };
+
+ static inline uint32_t compute_match_cost_estimate(uint32_t dist)
+ {
+ uint32_t len_cost = 7;
+ uint32_t dist_cost = 5;
+ if (dist < 512)
+ dist_cost += g_tdefl_small_dist_extra[dist & 511];
+ else
+ {
+ dist_cost += g_tdefl_large_dist_extra[basisu::minimum<uint32_t>(dist, 32767) >> 8];
+ while (dist >= 32768)
+ {
+ dist_cost++;
+ dist >>= 1;
+ }
+ }
+ return len_cost + dist_cost;
+ }
+
+ struct selector_bitsequence
+ {
+ uint64_t m_sel;
+ uint32_t m_ofs;
+ selector_bitsequence() { }
+ selector_bitsequence(uint32_t bit_ofs, uint64_t sel) : m_sel(sel), m_ofs(bit_ofs) { }
+ bool operator== (const selector_bitsequence& other) const
+ {
+ return (m_ofs == other.m_ofs) && (m_sel == other.m_sel);
+ }
+
+ bool operator< (const selector_bitsequence& other) const
+ {
+ if (m_ofs < other.m_ofs)
+ return true;
+ else if (m_ofs == other.m_ofs)
+ return m_sel < other.m_sel;
+
+ return false;
+ }
+ };
+
+ struct selector_bitsequence_hash
+ {
+ std::size_t operator()(selector_bitsequence const& s) const noexcept
+ {
+ return static_cast<std::size_t>(hash_hsieh((uint8_t *)&s, sizeof(s)) ^ s.m_sel);
+ }
+ };
+
+ class tracked_stat
+ {
+ public:
+ tracked_stat() { clear(); }
+
+ void clear() { m_num = 0; m_total = 0; m_total2 = 0; }
+
+ void update(uint32_t val) { m_num++; m_total += val; m_total2 += val * val; }
+
+ tracked_stat& operator += (uint32_t val) { update(val); return *this; }
+
+ uint32_t get_number_of_values() { return m_num; }
+ uint64_t get_total() const { return m_total; }
+ uint64_t get_total2() const { return m_total2; }
+
+ float get_average() const { return m_num ? (float)m_total / m_num : 0.0f; };
+ float get_std_dev() const { return m_num ? sqrtf((float)(m_num * m_total2 - m_total * m_total)) / m_num : 0.0f; }
+ float get_variance() const { float s = get_std_dev(); return s * s; }
+
+ private:
+ uint32_t m_num;
+ uint64_t m_total;
+ uint64_t m_total2;
+ };
+
+ static bool uastc_rdo_blocks(uint32_t first_index, uint32_t last_index, basist::uastc_block* pBlocks, const color_rgba* pBlock_pixels, const uastc_rdo_params& params, uint32_t flags,
+ uint32_t &total_skipped, uint32_t &total_refined, uint32_t &total_modified, uint32_t &total_smooth)
+ {
+ debug_printf("uastc_rdo_blocks: Processing blocks %u to %u\n", first_index, last_index);
+
+ const int total_blocks_to_check = basisu::maximum<uint32_t>(1U, params.m_lz_dict_size / sizeof(basist::uastc_block));
+ const bool perceptual = false;
+
+ std::unordered_map<selector_bitsequence, uint32_t, selector_bitsequence_hash> selector_history;
+
+ for (uint32_t block_index = first_index; block_index < last_index; block_index++)
+ {
+ const basist::uastc_block& blk = pBlocks[block_index];
+ const color_rgba* pPixels = &pBlock_pixels[16 * block_index];
+
+ unpacked_uastc_block unpacked_blk;
+ if (!unpack_uastc(blk, unpacked_blk, false, true))
+ return false;
+
+ const uint32_t block_mode = unpacked_blk.m_mode;
+ if (block_mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ continue;
+
+ tracked_stat r_stats, g_stats, b_stats, a_stats;
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ r_stats.update(pPixels[i].r);
+ g_stats.update(pPixels[i].g);
+ b_stats.update(pPixels[i].b);
+ a_stats.update(pPixels[i].a);
+ }
+
+ const float max_std_dev = basisu::maximum<float>(basisu::maximum<float>(basisu::maximum(r_stats.get_std_dev(), g_stats.get_std_dev()), b_stats.get_std_dev()), a_stats.get_std_dev());
+
+ float yl = clamp<float>(max_std_dev / params.m_max_smooth_block_std_dev, 0.0f, 1.0f);
+ yl = yl * yl;
+ const float smooth_block_error_scale = lerp<float>(params.m_smooth_block_max_error_scale, 1.0f, yl);
+ if (smooth_block_error_scale > 1.0f)
+ total_smooth++;
+
+ color_rgba decoded_uastc_block[4][4];
+ if (!unpack_uastc(unpacked_blk, (basist::color32*)decoded_uastc_block, false))
+ return false;
+
+ uint64_t uastc_err = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ uastc_err += color_distance(perceptual, pPixels[i], ((color_rgba*)decoded_uastc_block)[i], true);
+
+ // Transcode to BC7
+ bc7_optimization_results b7_results;
+ if (!transcode_uastc_to_bc7(unpacked_blk, b7_results))
+ return false;
+
+ basist::bc7_block b7_block;
+ basist::encode_bc7_block(&b7_block, &b7_results);
+
+ color_rgba decoded_b7_blk[4][4];
+ unpack_block(texture_format::cBC7, &b7_block, &decoded_b7_blk[0][0]);
+
+ uint64_t bc7_err = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ bc7_err += color_distance(perceptual, pPixels[i], ((color_rgba*)decoded_b7_blk)[i], true);
+
+ uint64_t cur_err = (uastc_err + bc7_err) / 2;
+
+ // Divide by 16*4 to compute RMS error
+ const float cur_ms_err = (float)cur_err * (1.0f / 64.0f);
+ const float cur_rms_err = sqrt(cur_ms_err);
+
+ const uint32_t first_sel_bit = g_uastc_mode_selector_bits[block_mode][0];
+ const uint32_t total_sel_bits = g_uastc_mode_selector_bits[block_mode][1];
+ assert(first_sel_bit + total_sel_bits <= 128);
+ assert(total_sel_bits > 0);
+
+ uint32_t cur_bit_offset = first_sel_bit;
+ uint64_t cur_sel_bits = read_bits((const uint8_t*)&blk, cur_bit_offset, basisu::minimum(64U, total_sel_bits));
+
+ if (cur_rms_err >= params.m_skip_block_rms_thresh)
+ {
+ auto cur_search_res = selector_history.insert(std::make_pair(selector_bitsequence(first_sel_bit, cur_sel_bits), block_index));
+
+ // Block already has too much error, so don't mess with it.
+ if (!cur_search_res.second)
+ (*cur_search_res.first).second = block_index;
+
+ total_skipped++;
+ continue;
+ }
+
+ int cur_bits;
+ auto cur_find_res = selector_history.find(selector_bitsequence(first_sel_bit, cur_sel_bits));
+ if (cur_find_res == selector_history.end())
+ {
+ // Wasn't found - wildly estimate literal cost
+ //cur_bits = (total_sel_bits * 5) / 4;
+ cur_bits = (total_sel_bits * params.m_lz_literal_cost) / 100;
+ }
+ else
+ {
+ // Was found - wildly estimate match cost
+ uint32_t match_block_index = cur_find_res->second;
+ const int block_dist_in_bytes = (block_index - match_block_index) * 16;
+ cur_bits = compute_match_cost_estimate(block_dist_in_bytes);
+ }
+
+ int first_block_to_check = basisu::maximum<int>(first_index, block_index - total_blocks_to_check);
+ int last_block_to_check = block_index - 1;
+
+ basist::uastc_block best_block(blk);
+ uint32_t best_block_index = block_index;
+
+ float best_t = cur_ms_err * smooth_block_error_scale + cur_bits * params.m_lambda;
+
+ // Now scan through previous blocks, insert their selector bit patterns into the current block, and find
+ // selector bit patterns which don't increase the overall block error too much.
+ for (int prev_block_index = last_block_to_check; prev_block_index >= first_block_to_check; --prev_block_index)
+ {
+ const basist::uastc_block& prev_blk = pBlocks[prev_block_index];
+
+ uint32_t bit_offset = first_sel_bit;
+ uint64_t sel_bits = read_bits((const uint8_t*)&prev_blk, bit_offset, basisu::minimum(64U, total_sel_bits));
+
+ int match_block_index = prev_block_index;
+ auto res = selector_history.find(selector_bitsequence(first_sel_bit, sel_bits));
+ if (res != selector_history.end())
+ match_block_index = res->second;
+ // Have we already checked this bit pattern? If so then skip this block.
+ if (match_block_index > prev_block_index)
+ continue;
+
+ unpacked_uastc_block unpacked_prev_blk;
+ if (!unpack_uastc(prev_blk, unpacked_prev_blk, false, true))
+ return false;
+
+ basist::uastc_block trial_blk(blk);
+
+ set_block_bits((uint8_t*)&trial_blk, sel_bits, basisu::minimum(64U, total_sel_bits), first_sel_bit);
+
+ if (total_sel_bits > 64)
+ {
+ sel_bits = read_bits((const uint8_t*)&prev_blk, bit_offset, total_sel_bits - 64U);
+
+ set_block_bits((uint8_t*)&trial_blk, sel_bits, total_sel_bits - 64U, first_sel_bit + basisu::minimum(64U, total_sel_bits));
+ }
+
+ unpacked_uastc_block unpacked_trial_blk;
+ if (!unpack_uastc(trial_blk, unpacked_trial_blk, false, true))
+ continue;
+
+ color_rgba decoded_trial_uastc_block[4][4];
+ if (!unpack_uastc(unpacked_trial_blk, (basist::color32*)decoded_trial_uastc_block, false))
+ continue;
+
+ uint64_t trial_uastc_err = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ trial_uastc_err += color_distance(perceptual, pPixels[i], ((color_rgba*)decoded_trial_uastc_block)[i], true);
+
+ // Transcode trial to BC7, compute error
+ bc7_optimization_results trial_b7_results;
+ if (!transcode_uastc_to_bc7(unpacked_trial_blk, trial_b7_results))
+ return false;
+
+ basist::bc7_block trial_b7_block;
+ basist::encode_bc7_block(&trial_b7_block, &trial_b7_results);
+
+ color_rgba decoded_trial_b7_blk[4][4];
+ unpack_block(texture_format::cBC7, &trial_b7_block, &decoded_trial_b7_blk[0][0]);
+
+ uint64_t trial_bc7_err = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ trial_bc7_err += color_distance(perceptual, pPixels[i], ((color_rgba*)decoded_trial_b7_blk)[i], true);
+
+ uint64_t trial_err = (trial_uastc_err + trial_bc7_err) / 2;
+
+ const float trial_ms_err = (float)trial_err * (1.0f / 64.0f);
+ const float trial_rms_err = sqrtf(trial_ms_err);
+
+ if (trial_rms_err > cur_rms_err * params.m_max_allowed_rms_increase_ratio)
+ continue;
+
+ const int block_dist_in_bytes = (block_index - match_block_index) * 16;
+ const int match_bits = compute_match_cost_estimate(block_dist_in_bytes);
+
+ float t = trial_ms_err * smooth_block_error_scale + match_bits * params.m_lambda;
+ if (t < best_t)
+ {
+ best_t = t;
+ best_block_index = prev_block_index;
+
+ best_block = trial_blk;
+ }
+
+ } // prev_block_index
+
+ if (best_block_index != block_index)
+ {
+ total_modified++;
+
+ unpacked_uastc_block unpacked_best_blk;
+ if (!unpack_uastc(best_block, unpacked_best_blk, false, false))
+ return false;
+
+ if ((params.m_endpoint_refinement) && (block_mode == 0))
+ {
+ // Attempt to refine mode 0 block's endpoints, using the new selectors. This doesn't help much, but it does help.
+ // TODO: We could do this with the other modes too.
+ color_rgba decoded_best_uastc_block[4][4];
+ if (!unpack_uastc(unpacked_best_blk, (basist::color32*)decoded_best_uastc_block, false))
+ return false;
+
+ // Compute the block's current error (with the modified selectors).
+ uint64_t best_uastc_err = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ best_uastc_err += color_distance(perceptual, pPixels[i], ((color_rgba*)decoded_best_uastc_block)[i], true);
+
+ bc7enc_compress_block_params comp_params;
+ memset(&comp_params, 0, sizeof(comp_params));
+ comp_params.m_max_partitions_mode1 = 64;
+ comp_params.m_least_squares_passes = 1;
+ comp_params.m_weights[0] = 1;
+ comp_params.m_weights[1] = 1;
+ comp_params.m_weights[2] = 1;
+ comp_params.m_weights[3] = 1;
+ comp_params.m_uber_level = 0;
+
+ uastc_encode_results results;
+ uint32_t total_results = 0;
+ astc_mode0_or_18(0, (color_rgba(*)[4])pPixels, &results, total_results, comp_params, unpacked_best_blk.m_astc.m_weights);
+ assert(total_results == 1);
+
+ // See if the overall error has actually gone done.
+
+ color_rgba decoded_trial_uastc_block[4][4];
+ bool success = unpack_uastc(results.m_uastc_mode, results.m_common_pattern, results.m_solid_color.get_color32(), results.m_astc, (basist::color32*) & decoded_trial_uastc_block[0][0], false);
+ assert(success);
+
+ BASISU_NOTE_UNUSED(success);
+
+ uint64_t trial_uastc_err = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ trial_uastc_err += color_distance(perceptual, pPixels[i], ((color_rgba*)decoded_trial_uastc_block)[i], true);
+
+ if (trial_uastc_err < best_uastc_err)
+ {
+ // The error went down, so accept the new endpoints.
+
+ // Ensure the selectors haven't changed, otherwise we'll invalidate the LZ matches.
+ for (uint32_t i = 0; i < 16; i++)
+ assert(unpacked_best_blk.m_astc.m_weights[i] == results.m_astc.m_weights[i]);
+
+ unpacked_best_blk.m_astc = results.m_astc;
+
+ total_refined++;
+ }
+ } // if ((params.m_endpoint_refinement) && (block_mode == 0))
+
+ // The selectors have changed, so go recompute the block hints.
+ if (!uastc_recompute_hints(&best_block, pPixels, flags, &unpacked_best_blk))
+ return false;
+
+ // Write the modified block
+ pBlocks[block_index] = best_block;
+
+ } // if (best_block_index != block_index)
+
+ {
+ uint32_t bit_offset = first_sel_bit;
+ uint64_t sel_bits = read_bits((const uint8_t*)&best_block, bit_offset, basisu::minimum(64U, total_sel_bits));
+
+ auto res = selector_history.insert(std::make_pair(selector_bitsequence(first_sel_bit, sel_bits), block_index));
+ if (!res.second)
+ (*res.first).second = block_index;
+ }
+
+ } // block_index
+
+ return true;
+ }
+
+ // This function implements a basic form of rate distortion optimization (RDO) for UASTC.
+ // It only changes selectors and then updates the hints. It uses very approximate LZ bitprice estimation.
+ // There's A LOT that can be done better in here, but it's a start.
+ // One nice advantage of the method used here is that it works for any input, no matter which or how many modes it uses.
+ bool uastc_rdo(uint32_t num_blocks, basist::uastc_block* pBlocks, const color_rgba* pBlock_pixels, const uastc_rdo_params& params, uint32_t flags, job_pool* pJob_pool, uint32_t total_jobs)
+ {
+ assert(params.m_max_allowed_rms_increase_ratio > 1.0f);
+ assert(params.m_lz_dict_size > 0);
+ assert(params.m_lambda > 0.0f);
+
+ uint32_t total_skipped = 0, total_modified = 0, total_refined = 0, total_smooth = 0;
+
+ uint32_t blocks_per_job = total_jobs ? (num_blocks / total_jobs) : 0;
+
+ std::mutex stat_mutex;
+
+ bool status = false;
+
+ if ((!pJob_pool) || (total_jobs <= 1) || (blocks_per_job <= 8))
+ {
+ status = uastc_rdo_blocks(0, num_blocks, pBlocks, pBlock_pixels, params, flags, total_skipped, total_refined, total_modified, total_smooth);
+ }
+ else
+ {
+ bool all_succeeded = true;
+
+ for (uint32_t block_index_iter = 0; block_index_iter < num_blocks; block_index_iter += blocks_per_job)
+ {
+ const uint32_t first_index = block_index_iter;
+ const uint32_t last_index = minimum<uint32_t>(num_blocks, block_index_iter + blocks_per_job);
+
+#ifndef __EMSCRIPTEN__
+ pJob_pool->add_job([first_index, last_index, pBlocks, pBlock_pixels, &params, flags, &total_skipped, &total_modified, &total_refined, &total_smooth, &all_succeeded, &stat_mutex] {
+#endif
+
+ uint32_t job_skipped = 0, job_modified = 0, job_refined = 0, job_smooth = 0;
+
+ bool status = uastc_rdo_blocks(first_index, last_index, pBlocks, pBlock_pixels, params, flags, job_skipped, job_refined, job_modified, job_smooth);
+
+ {
+ std::lock_guard<std::mutex> lck(stat_mutex);
+
+ all_succeeded = all_succeeded && status;
+ total_skipped += job_skipped;
+ total_modified += job_modified;
+ total_refined += job_refined;
+ total_smooth += job_smooth;
+ }
+
+#ifndef __EMSCRIPTEN__
+ }
+ );
+#endif
+
+ } // block_index_iter
+
+#ifndef __EMSCRIPTEN__
+ pJob_pool->wait_for_all();
+#endif
+
+ status = all_succeeded;
+ }
+
+ debug_printf("uastc_rdo: Total modified: %3.2f%%, total skipped: %3.2f%%, total refined: %3.2f%%, total smooth: %3.2f%%\n", total_modified * 100.0f / num_blocks, total_skipped * 100.0f / num_blocks, total_refined * 100.0f / num_blocks, total_smooth * 100.0f / num_blocks);
+
+ return status;
+ }
+} // namespace basisu
+
+
+
+
+
diff --git a/thirdparty/basis_universal/encoder/basisu_uastc_enc.h b/thirdparty/basis_universal/encoder/basisu_uastc_enc.h
new file mode 100644
index 0000000000..ba39a558b3
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/basisu_uastc_enc.h
@@ -0,0 +1,140 @@
+// basisu_uastc_enc.h
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+#include "basisu_etc.h"
+
+#include "../transcoder/basisu_transcoder_uastc.h"
+
+namespace basisu
+{
+ const uint32_t TOTAL_PACK_UASTC_LEVELS = 5;
+
+ enum
+ {
+ // Fastest is the lowest quality, although it's stil substantially higher quality vs. BC1/ETC1. It supports 5 modes.
+ // The output may be somewhat blocky because this setting doesn't support 2/3-subset UASTC modes, but it should be less blocky vs. BC1/ETC1.
+ // This setting doesn't write BC1 hints, so BC1 transcoding will be slower.
+ // Transcoded ETC1 quality will be lower because it only considers 2 hints out of 32.
+ // Avg. 43.45 dB
+ cPackUASTCLevelFastest = 0,
+
+ // Faster is ~3x slower than fastest. It supports 9 modes.
+ // Avg. 46.49 dB
+ cPackUASTCLevelFaster = 1,
+
+ // Default is ~5.5x slower than fastest. It supports 14 modes.
+ // Avg. 47.47 dB
+ cPackUASTCLevelDefault = 2,
+
+ // Slower is ~14.5x slower than fastest. It supports all 18 modes.
+ // Avg. 48.01 dB
+ cPackUASTCLevelSlower = 3,
+
+ // VerySlow is ~200x slower than fastest.
+ // The best quality the codec is capable of, but you'll need to be patient or have a lot of cores.
+ // Avg. 48.24 dB
+ cPackUASTCLevelVerySlow = 4,
+
+ cPackUASTCLevelMask = 0xF,
+
+ // By default the encoder tries to strike a balance between UASTC and transcoded BC7 quality.
+ // These flags allow you to favor only optimizing for lowest UASTC error, or lowest BC7 error.
+ cPackUASTCFavorUASTCError = 8,
+ cPackUASTCFavorBC7Error = 16,
+
+ cPackUASTCETC1FasterHints = 64,
+ cPackUASTCETC1FastestHints = 128,
+ cPackUASTCETC1DisableFlipAndIndividual = 256,
+
+ // Favor UASTC modes 0 and 10 more than the others (this is experimental, it's useful for RDO compression)
+ cPackUASTCFavorSimplerModes = 512,
+ };
+
+ // pRGBAPixels: Pointer to source 4x4 block of RGBA pixels (R first in memory).
+ // block: Reference to destination UASTC block.
+ // level: Controls compression speed vs. performance tradeoff.
+ void encode_uastc(const uint8_t* pRGBAPixels, basist::uastc_block& output_block, uint32_t flags = cPackUASTCLevelDefault);
+
+ struct uastc_encode_results
+ {
+ uint32_t m_uastc_mode;
+ uint32_t m_common_pattern;
+ basist::astc_block_desc m_astc;
+ color_rgba m_solid_color;
+ uint64_t m_astc_err;
+ };
+
+ void pack_uastc(basist::uastc_block& blk, const uastc_encode_results& result, const etc_block& etc1_blk, uint32_t etc1_bias, const eac_a8_block& etc_eac_a8_blk, bool bc1_hint0, bool bc1_hint1);
+
+ const uint32_t UASCT_RDO_DEFAULT_LZ_DICT_SIZE = 4096;
+
+ const float UASTC_RDO_DEFAULT_MAX_ALLOWED_RMS_INCREASE_RATIO = 10.0f;
+ const float UASTC_RDO_DEFAULT_SKIP_BLOCK_RMS_THRESH = 8.0f;
+
+ // The RDO encoder computes a smoothness factor, from [0,1], for each block. To do this it computes each block's maximum component variance, then it divides this by this factor and clamps the result.
+ // Larger values will result in more blocks being protected from too much distortion.
+ const float UASTC_RDO_DEFAULT_MAX_SMOOTH_BLOCK_STD_DEV = 18.0f;
+
+ // The RDO encoder can artifically boost the error of smooth blocks, in order to suppress distortions on smooth areas of the texture.
+ // The encoder will use this value as the maximum error scale to use on smooth blocks. The larger this value, the better smooth bocks will look. Set to 1.0 to disable this completely.
+ const float UASTC_RDO_DEFAULT_SMOOTH_BLOCK_MAX_ERROR_SCALE = 10.0f;
+
+ struct uastc_rdo_params
+ {
+ uastc_rdo_params()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ m_lz_dict_size = UASCT_RDO_DEFAULT_LZ_DICT_SIZE;
+ m_lambda = 0.5f;
+ m_max_allowed_rms_increase_ratio = UASTC_RDO_DEFAULT_MAX_ALLOWED_RMS_INCREASE_RATIO;
+ m_skip_block_rms_thresh = UASTC_RDO_DEFAULT_SKIP_BLOCK_RMS_THRESH;
+ m_endpoint_refinement = true;
+ m_lz_literal_cost = 100;
+
+ m_max_smooth_block_std_dev = UASTC_RDO_DEFAULT_MAX_SMOOTH_BLOCK_STD_DEV;
+ m_smooth_block_max_error_scale = UASTC_RDO_DEFAULT_SMOOTH_BLOCK_MAX_ERROR_SCALE;
+ }
+
+ // m_lz_dict_size: Size of LZ dictionary to simulate in bytes. The larger this value, the slower the encoder but the higher the quality per LZ compressed bit.
+ uint32_t m_lz_dict_size;
+
+ // m_lambda: The post-processor tries to reduce distortion+rate*lambda (rate is approximate LZ bits and distortion is scaled MS error).
+ // Larger values push the postprocessor towards optimizing more for lower rate, and smaller values more for distortion. 0=minimal distortion.
+ float m_lambda;
+
+ // m_max_allowed_rms_increase_ratio: How much the RMS error of a block is allowed to increase before a trial is rejected. 1.0=no increase allowed, 1.05=5% increase allowed, etc.
+ float m_max_allowed_rms_increase_ratio;
+
+ // m_skip_block_rms_thresh: Blocks with this much RMS error or more are completely skipped by the RDO encoder.
+ float m_skip_block_rms_thresh;
+
+ // m_endpoint_refinement: If true, the post-process will attempt to refine the endpoints of blocks with modified selectors.
+ bool m_endpoint_refinement;
+
+ float m_max_smooth_block_std_dev;
+ float m_smooth_block_max_error_scale;
+
+ uint32_t m_lz_literal_cost;
+ };
+
+ // num_blocks, pBlocks: Number of blocks and pointer to UASTC blocks to process.
+ // pBlock_pixels: Pointer to an array of 4x4 blocks containing the original texture pixels. This is NOT a raster image, but a pointer to individual 4x4 blocks.
+ // flags: Pass in the same flags used to encode the UASTC blocks. The flags are used to reencode the transcode hints in the same way.
+ bool uastc_rdo(uint32_t num_blocks, basist::uastc_block* pBlocks, const color_rgba* pBlock_pixels, const uastc_rdo_params &params, uint32_t flags = cPackUASTCLevelDefault, job_pool* pJob_pool = nullptr, uint32_t total_jobs = 0);
+} // namespace basisu
diff --git a/thirdparty/basis_universal/encoder/cppspmd_flow.h b/thirdparty/basis_universal/encoder/cppspmd_flow.h
new file mode 100644
index 0000000000..f6930476aa
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/cppspmd_flow.h
@@ -0,0 +1,590 @@
+// Do not include this header directly.
+// Control flow functionality in common between all the headers.
+//
+// Copyright 2020-2021 Binomial LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifdef _DEBUG
+CPPSPMD_FORCE_INLINE void spmd_kernel::check_masks()
+{
+ assert(!any(andnot(m_kernel_exec, m_exec)));
+}
+#endif
+
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_break()
+{
+#ifdef _DEBUG
+ assert(m_in_loop);
+#endif
+
+ m_exec = exec_mask::all_off();
+}
+
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_continue()
+{
+#ifdef _DEBUG
+ assert(m_in_loop);
+#endif
+
+ // Kill any active lanes, and remember which lanes were active so we can re-enable them at the end of the loop body.
+ m_continue_mask = m_continue_mask | m_exec;
+ m_exec = exec_mask::all_off();
+}
+
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_return()
+{
+ // Permenantly kill all active lanes
+ m_kernel_exec = andnot(m_exec, m_kernel_exec);
+ m_exec = exec_mask::all_off();
+}
+
+template<typename UnmaskedBody>
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_unmasked(const UnmaskedBody& unmaskedBody)
+{
+ exec_mask orig_exec = m_exec, orig_kernel_exec = m_kernel_exec;
+
+ m_kernel_exec = exec_mask::all_on();
+ m_exec = exec_mask::all_on();
+
+ unmaskedBody();
+
+ m_kernel_exec = m_kernel_exec & orig_kernel_exec;
+ m_exec = m_exec & orig_exec;
+
+ check_masks();
+}
+
+struct scoped_unmasked_restorer
+{
+ spmd_kernel *m_pKernel;
+ exec_mask m_orig_exec, m_orig_kernel_exec;
+
+ CPPSPMD_FORCE_INLINE scoped_unmasked_restorer(spmd_kernel *pKernel) :
+ m_pKernel(pKernel),
+ m_orig_exec(pKernel->m_exec),
+ m_orig_kernel_exec(pKernel->m_kernel_exec)
+ {
+ pKernel->m_kernel_exec = exec_mask::all_on();
+ pKernel->m_exec = exec_mask::all_on();
+ }
+
+ CPPSPMD_FORCE_INLINE ~scoped_unmasked_restorer()
+ {
+ m_pKernel->m_kernel_exec = m_pKernel->m_kernel_exec & m_orig_kernel_exec;
+ m_pKernel->m_exec = m_pKernel->m_exec & m_orig_exec;
+ m_pKernel->check_masks();
+ }
+};
+
+#define SPMD_UNMASKED_BEGIN { scoped_unmasked_restorer _unmasked_restorer(this);
+#define SPMD_UNMASKED_END }
+
+#if 0
+template<typename SPMDKernel, typename... Args>
+CPPSPMD_FORCE_INLINE decltype(auto) spmd_kernel::spmd_call(Args&&... args)
+{
+ SPMDKernel kernel;
+ kernel.init(m_exec);
+ return kernel._call(std::forward<Args>(args)...);
+}
+#else
+template<typename SPMDKernel, typename... Args>
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_call(Args&&... args)
+{
+ SPMDKernel kernel;
+ kernel.init(m_exec);
+ kernel._call(std::forward<Args>(args)...);
+}
+#endif
+
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_if_break(const vbool& cond)
+{
+#ifdef _DEBUG
+ assert(m_in_loop);
+#endif
+
+ exec_mask cond_exec(cond);
+
+ m_exec = andnot(m_exec & cond_exec, m_exec);
+
+ check_masks();
+}
+
+// No SPMD breaks, continues, etc. allowed
+template<typename IfBody>
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_sif(const vbool& cond, const IfBody& ifBody)
+{
+ exec_mask im = m_exec & exec_mask(cond);
+
+ if (any(im))
+ {
+ const exec_mask orig_exec = m_exec;
+ m_exec = im;
+ ifBody();
+ m_exec = orig_exec;
+ }
+}
+
+// No SPMD breaks, continues, etc. allowed
+template<typename IfBody, typename ElseBody>
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_sifelse(const vbool& cond, const IfBody& ifBody, const ElseBody &elseBody)
+{
+ const exec_mask orig_exec = m_exec;
+
+ exec_mask im = m_exec & exec_mask(cond);
+
+ if (any(im))
+ {
+ m_exec = im;
+ ifBody();
+ }
+
+ exec_mask em = orig_exec & exec_mask(!cond);
+
+ if (any(em))
+ {
+ m_exec = em;
+ elseBody();
+ }
+
+ m_exec = orig_exec;
+}
+
+template<typename IfBody>
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_if(const vbool& cond, const IfBody& ifBody)
+{
+ exec_mask cond_exec(cond);
+
+ exec_mask pre_if_exec = cond_exec & m_exec;
+
+ if (any(pre_if_exec))
+ {
+ exec_mask unexecuted_lanes = andnot(cond_exec, m_exec);
+ m_exec = pre_if_exec;
+
+ ifBody();
+
+ // Propagate any lanes that got disabled inside the if body into the exec mask outside the if body, but turn on any lanes that didn't execute inside the if body.
+ m_exec = m_exec | unexecuted_lanes;
+
+ check_masks();
+ }
+}
+
+template<typename IfBody, typename ElseBody>
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_ifelse(const vbool& cond, const IfBody& ifBody, const ElseBody& elseBody)
+{
+ bool all_flag = false;
+
+ exec_mask cond_exec(cond);
+
+ {
+ exec_mask pre_if_exec = cond_exec & m_exec;
+
+ int mask = pre_if_exec.get_movemask();
+ if (mask != 0)
+ {
+ all_flag = ((uint32_t)mask == m_exec.get_movemask());
+
+ exec_mask unexecuted_lanes = andnot(cond_exec, m_exec);
+ m_exec = pre_if_exec;
+
+ ifBody();
+
+ // Propagate any lanes that got disabled inside the if body into the exec mask outside the if body, but turn on any lanes that didn't execute inside the if body.
+ m_exec = m_exec | unexecuted_lanes;
+
+ check_masks();
+ }
+ }
+
+ if (!all_flag)
+ {
+ exec_mask pre_if_exec = andnot(cond_exec, m_exec);
+
+ if (any(pre_if_exec))
+ {
+ exec_mask unexecuted_lanes = cond_exec & m_exec;
+ m_exec = pre_if_exec;
+
+ ifBody();
+
+ // Propagate any lanes that got disabled inside the if body into the exec mask outside the if body, but turn on any lanes that didn't execute inside the if body.
+ m_exec = m_exec | unexecuted_lanes;
+
+ check_masks();
+ }
+ }
+}
+
+struct scoped_exec_restorer
+{
+ exec_mask *m_pMask;
+ exec_mask m_prev_mask;
+ CPPSPMD_FORCE_INLINE scoped_exec_restorer(exec_mask *pExec_mask) : m_pMask(pExec_mask), m_prev_mask(*pExec_mask) { }
+ CPPSPMD_FORCE_INLINE ~scoped_exec_restorer() { *m_pMask = m_prev_mask; }
+};
+
+// Cannot use SPMD break, continue, or return inside "simple" if/else
+#define SPMD_SIF(cond) exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(vbool(cond))); if (any(CPPSPMD_GLUER2(_exec_temp, __LINE__))) \
+ { CPPSPMD::scoped_exec_restorer CPPSPMD_GLUER2(_exec_restore_, __LINE__)(&m_exec); m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
+
+#define SPMD_SELSE(cond) } exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(!vbool(cond))); if (any(CPPSPMD_GLUER2(_exec_temp, __LINE__))) \
+ { CPPSPMD::scoped_exec_restorer CPPSPMD_GLUER2(_exec_restore_, __LINE__)(&m_exec); m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
+
+#define SPMD_SENDIF }
+
+// Same as SPMD_SIF, except doesn't use a scoped object
+#define SPMD_SIF2(cond) exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(vbool(cond))); if (any(CPPSPMD_GLUER2(_exec_temp, __LINE__))) \
+ { exec_mask _orig_exec = m_exec; m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
+
+#define SPMD_SELSE2(cond) m_exec = _orig_exec; } exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(!vbool(cond))); if (any(CPPSPMD_GLUER2(_exec_temp, __LINE__))) \
+ { exec_mask _orig_exec = m_exec; m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
+
+#define SPMD_SEND_IF2 m_exec = _orig_exec; }
+
+// Same as SPMD_SIF(), except the if/else blocks are always executed
+#define SPMD_SAIF(cond) exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(vbool(cond))); { CPPSPMD::scoped_exec_restorer CPPSPMD_GLUER2(_exec_restore_, __LINE__)(&m_exec); \
+ m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
+
+#define SPMD_SAELSE(cond) } exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(!vbool(cond))); { CPPSPMD::scoped_exec_restorer CPPSPMD_GLUER2(_exec_restore_, __LINE__)(&m_exec); \
+ m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
+
+#define SPMD_SAENDIF }
+
+// Cannot use SPMD break, continue, or return inside sselect
+#define SPMD_SSELECT(var) do { vint_t _select_var = var; scoped_exec_restorer _orig_exec(&m_exec); exec_mask _select_executed(exec_mask::all_off());
+#define SPMD_SCASE(value) exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(_orig_exec.m_prev_mask & exec_mask(vbool(_select_var == (value)))); if (any(CPPSPMD_GLUER2(_exec_temp, __LINE__))) \
+ { m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__); _select_executed = _select_executed | m_exec;
+
+//#define SPMD_SCASE_END if (_select_executed.get_movemask() == _orig_exec.m_prev_mask.get_movemask()) break; }
+#define SPMD_SCASE_END if (!any(_select_executed ^ _orig_exec.m_prev_mask)) break; }
+#define SPMD_SDEFAULT exec_mask _all_other_lanes(andnot(_select_executed, _orig_exec.m_prev_mask)); if (any(_all_other_lanes)) { m_exec = _all_other_lanes;
+#define SPMD_SDEFAULT_END }
+#define SPMD_SSELECT_END } while(0);
+
+// Same as SPMD_SSELECT, except all cases are executed.
+// Cannot use SPMD break, continue, or return inside sselect
+#define SPMD_SASELECT(var) do { vint_t _select_var = var; scoped_exec_restorer _orig_exec(&m_exec); exec_mask _select_executed(exec_mask::all_off());
+
+#define SPMD_SACASE(value) exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(_orig_exec.m_prev_mask & exec_mask(vbool(_select_var == (value)))); { m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__); \
+ _select_executed = _select_executed | m_exec;
+
+#define SPMD_SACASE_END }
+#define SPMD_SADEFAULT exec_mask _all_other_lanes(andnot(_select_executed, _orig_exec.m_prev_mask)); { m_exec = _all_other_lanes;
+#define SPMD_SADEFAULT_END }
+#define SPMD_SASELECT_END } while(0);
+
+struct scoped_exec_restorer2
+{
+ spmd_kernel *m_pKernel;
+ exec_mask m_unexecuted_lanes;
+
+ CPPSPMD_FORCE_INLINE scoped_exec_restorer2(spmd_kernel *pKernel, const vbool &cond) :
+ m_pKernel(pKernel)
+ {
+ exec_mask cond_exec(cond);
+ m_unexecuted_lanes = andnot(cond_exec, pKernel->m_exec);
+ pKernel->m_exec = cond_exec & pKernel->m_exec;
+ }
+
+ CPPSPMD_FORCE_INLINE ~scoped_exec_restorer2()
+ {
+ m_pKernel->m_exec = m_pKernel->m_exec | m_unexecuted_lanes;
+ m_pKernel->check_masks();
+ }
+};
+
+#define SPMD_IF(cond) { CPPSPMD::scoped_exec_restorer2 CPPSPMD_GLUER2(_exec_restore2_, __LINE__)(this, vbool(cond)); if (any(m_exec)) {
+#define SPMD_ELSE(cond) } } { CPPSPMD::scoped_exec_restorer2 CPPSPMD_GLUER2(_exec_restore2_, __LINE__)(this, !vbool(cond)); if (any(m_exec)) {
+#define SPMD_END_IF } }
+
+// Same as SPMD_IF, except the conditional block is always executed.
+#define SPMD_AIF(cond) { CPPSPMD::scoped_exec_restorer2 CPPSPMD_GLUER2(_exec_restore2_, __LINE__)(this, vbool(cond)); {
+#define SPMD_AELSE(cond) } } { CPPSPMD::scoped_exec_restorer2 CPPSPMD_GLUER2(_exec_restore2_, __LINE__)(this, !vbool(cond)); {
+#define SPMD_AEND_IF } }
+
+class scoped_exec_saver
+{
+ exec_mask m_exec, m_kernel_exec, m_continue_mask;
+ spmd_kernel *m_pKernel;
+#ifdef _DEBUG
+ bool m_in_loop;
+#endif
+
+public:
+ inline scoped_exec_saver(spmd_kernel *pKernel) :
+ m_exec(pKernel->m_exec), m_kernel_exec(pKernel->m_kernel_exec), m_continue_mask(pKernel->m_continue_mask),
+ m_pKernel(pKernel)
+ {
+#ifdef _DEBUG
+ m_in_loop = pKernel->m_in_loop;
+#endif
+ }
+
+ inline ~scoped_exec_saver()
+ {
+ m_pKernel->m_exec = m_exec;
+ m_pKernel->m_continue_mask = m_continue_mask;
+ m_pKernel->m_kernel_exec = m_kernel_exec;
+#ifdef _DEBUG
+ m_pKernel->m_in_loop = m_in_loop;
+ m_pKernel->check_masks();
+#endif
+ }
+};
+
+#define SPMD_BEGIN_CALL scoped_exec_saver CPPSPMD_GLUER2(_begin_call_scoped_exec_saver, __LINE__)(this); m_continue_mask = exec_mask::all_off();
+#define SPMD_BEGIN_CALL_ALL_LANES scoped_exec_saver CPPSPMD_GLUER2(_begin_call_scoped_exec_saver, __LINE__)(this); m_exec = exec_mask::all_on(); m_continue_mask = exec_mask::all_off();
+
+template<typename ForeachBody>
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_foreach(int begin, int end, const ForeachBody& foreachBody)
+{
+ if (begin == end)
+ return;
+
+ if (!any(m_exec))
+ return;
+
+ // We don't support iterating backwards.
+ if (begin > end)
+ std::swap(begin, end);
+
+ exec_mask prev_continue_mask = m_continue_mask, prev_exec = m_exec;
+
+ int total_full = (end - begin) / PROGRAM_COUNT;
+ int total_partial = (end - begin) % PROGRAM_COUNT;
+
+ lint_t loop_index = begin + program_index;
+
+ const int total_loops = total_full + (total_partial ? 1 : 0);
+
+ m_continue_mask = exec_mask::all_off();
+
+ for (int i = 0; i < total_loops; i++)
+ {
+ int n = PROGRAM_COUNT;
+ if ((i == (total_loops - 1)) && (total_partial))
+ {
+ exec_mask partial_mask = exec_mask(vint_t(total_partial) > vint_t(program_index));
+ m_exec = m_exec & partial_mask;
+ n = total_partial;
+ }
+
+ foreachBody(loop_index, n);
+
+ m_exec = m_exec | m_continue_mask;
+ if (!any(m_exec))
+ break;
+
+ m_continue_mask = exec_mask::all_off();
+ check_masks();
+
+ store_all(loop_index, loop_index + PROGRAM_COUNT);
+ }
+
+ m_exec = prev_exec & m_kernel_exec;
+ m_continue_mask = prev_continue_mask;
+ check_masks();
+}
+
+template<typename WhileCondBody, typename WhileBody>
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_while(const WhileCondBody& whileCondBody, const WhileBody& whileBody)
+{
+ exec_mask orig_exec = m_exec;
+
+ exec_mask orig_continue_mask = m_continue_mask;
+ m_continue_mask = exec_mask::all_off();
+
+#ifdef _DEBUG
+ const bool prev_in_loop = m_in_loop;
+ m_in_loop = true;
+#endif
+
+ while(true)
+ {
+ exec_mask cond_exec = exec_mask(whileCondBody());
+ m_exec = m_exec & cond_exec;
+
+ if (!any(m_exec))
+ break;
+
+ whileBody();
+
+ m_exec = m_exec | m_continue_mask;
+ m_continue_mask = exec_mask::all_off();
+ check_masks();
+ }
+
+#ifdef _DEBUG
+ m_in_loop = prev_in_loop;
+#endif
+
+ m_exec = orig_exec & m_kernel_exec;
+ m_continue_mask = orig_continue_mask;
+ check_masks();
+}
+
+struct scoped_while_restorer
+{
+ spmd_kernel *m_pKernel;
+ exec_mask m_orig_exec, m_orig_continue_mask;
+#ifdef _DEBUG
+ bool m_prev_in_loop;
+#endif
+
+ CPPSPMD_FORCE_INLINE scoped_while_restorer(spmd_kernel *pKernel) :
+ m_pKernel(pKernel),
+ m_orig_exec(pKernel->m_exec),
+ m_orig_continue_mask(pKernel->m_continue_mask)
+ {
+ pKernel->m_continue_mask.all_off();
+
+#ifdef _DEBUG
+ m_prev_in_loop = pKernel->m_in_loop;
+ pKernel->m_in_loop = true;
+#endif
+ }
+
+ CPPSPMD_FORCE_INLINE ~scoped_while_restorer()
+ {
+ m_pKernel->m_exec = m_orig_exec & m_pKernel->m_kernel_exec;
+ m_pKernel->m_continue_mask = m_orig_continue_mask;
+#ifdef _DEBUG
+ m_pKernel->m_in_loop = m_prev_in_loop;
+ m_pKernel->check_masks();
+#endif
+ }
+};
+
+#undef SPMD_WHILE
+#undef SPMD_WEND
+#define SPMD_WHILE(cond) { scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); while(true) { exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(cond)); \
+ m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break;
+
+#define SPMD_WEND m_exec = m_exec | m_continue_mask; m_continue_mask = exec_mask::all_off(); check_masks(); } }
+
+// Nesting is not supported (although it will compile, but the results won't make much sense).
+#define SPMD_FOREACH(loop_var, bi, ei) if (((bi) != (ei)) && (any(m_exec))) { \
+ scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); \
+ uint32_t b = (uint32_t)(bi), e = (uint32_t)(ei); if ((b) > (e)) { std::swap(b, e); } const uint32_t total_full = ((e) - (b)) >> PROGRAM_COUNT_SHIFT, total_partial = ((e) - (b)) & (PROGRAM_COUNT - 1); \
+ lint_t loop_var = program_index + (int)b; const uint32_t total_loops = total_full + (total_partial ? 1U : 0U); \
+ for (uint32_t CPPSPMD_GLUER2(_foreach_counter, __LINE__) = 0; CPPSPMD_GLUER2(_foreach_counter, __LINE__) < total_loops; ++CPPSPMD_GLUER2(_foreach_counter, __LINE__)) { \
+ if ((CPPSPMD_GLUER2(_foreach_counter, __LINE__) == (total_loops - 1)) && (total_partial)) { exec_mask partial_mask = exec_mask(vint_t((int)total_partial) > vint_t(program_index)); m_exec = m_exec & partial_mask; }
+
+#define SPMD_FOREACH_END(loop_var) m_exec = m_exec | m_continue_mask; if (!any(m_exec)) break; m_continue_mask = exec_mask::all_off(); check_masks(); store_all(loop_var, loop_var + PROGRAM_COUNT); } }
+
+// Okay to use spmd_continue or spmd_return, but not spmd_break
+#define SPMD_FOREACH_ACTIVE(index_var) int64_t index_var; { uint64_t _movemask = m_exec.get_movemask(); if (_movemask) { scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); \
+ for (uint32_t _i = 0; _i < PROGRAM_COUNT; ++_i) { \
+ if (_movemask & (1U << _i)) { \
+ m_exec.enable_lane(_i); m_exec = m_exec & m_kernel_exec; \
+ (index_var) = _i; \
+
+#define SPMD_FOREACH_ACTIVE_END } } } }
+
+// Okay to use spmd_continue, but not spmd_break/spmd_continue
+#define SPMD_FOREACH_UNIQUE_INT(index_var, var) { scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); \
+ CPPSPMD_DECL(int_t, _vals[PROGRAM_COUNT]); store_linear_all(_vals, var); std::sort(_vals, _vals + PROGRAM_COUNT); \
+ const int _n = (int)(std::unique(_vals, _vals + PROGRAM_COUNT) - _vals); \
+ for (int _i = 0; _i < _n; ++_i) { int index_var = _vals[_i]; vbool cond = (vint_t(var) == vint_t(index_var)); m_exec = exec_mask(cond);
+
+#define SPMD_FOREACH_UNIQUE_INT_END } }
+
+struct scoped_simple_while_restorer
+{
+ spmd_kernel* m_pKernel;
+ exec_mask m_orig_exec;
+#ifdef _DEBUG
+ bool m_prev_in_loop;
+#endif
+
+ CPPSPMD_FORCE_INLINE scoped_simple_while_restorer(spmd_kernel* pKernel) :
+ m_pKernel(pKernel),
+ m_orig_exec(pKernel->m_exec)
+ {
+
+#ifdef _DEBUG
+ m_prev_in_loop = pKernel->m_in_loop;
+ pKernel->m_in_loop = true;
+#endif
+ }
+
+ CPPSPMD_FORCE_INLINE ~scoped_simple_while_restorer()
+ {
+ m_pKernel->m_exec = m_orig_exec;
+#ifdef _DEBUG
+ m_pKernel->m_in_loop = m_prev_in_loop;
+ m_pKernel->check_masks();
+#endif
+ }
+};
+
+// Cannot use SPMD break, continue, or return inside simple while
+
+#define SPMD_SWHILE(cond) { scoped_simple_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); \
+ while(true) { \
+ exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(cond)); m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break;
+#define SPMD_SWEND } }
+
+// Cannot use SPMD break, continue, or return inside simple do
+#define SPMD_SDO { scoped_simple_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); while(true) {
+#define SPMD_SEND_DO(cond) exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(cond)); m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break; } }
+
+#undef SPMD_FOR
+#undef SPMD_END_FOR
+#define SPMD_FOR(for_init, for_cond) { for_init; scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); while(true) { exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(for_cond)); \
+ m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break;
+#define SPMD_END_FOR(for_inc) m_exec = m_exec | m_continue_mask; m_continue_mask = exec_mask::all_off(); check_masks(); for_inc; } }
+
+template<typename ForInitBody, typename ForCondBody, typename ForIncrBody, typename ForBody>
+CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_for(const ForInitBody& forInitBody, const ForCondBody& forCondBody, const ForIncrBody& forIncrBody, const ForBody& forBody)
+{
+ exec_mask orig_exec = m_exec;
+
+ forInitBody();
+
+ exec_mask orig_continue_mask = m_continue_mask;
+ m_continue_mask = exec_mask::all_off();
+
+#ifdef _DEBUG
+ const bool prev_in_loop = m_in_loop;
+ m_in_loop = true;
+#endif
+
+ while(true)
+ {
+ exec_mask cond_exec = exec_mask(forCondBody());
+ m_exec = m_exec & cond_exec;
+
+ if (!any(m_exec))
+ break;
+
+ forBody();
+
+ m_exec = m_exec | m_continue_mask;
+ m_continue_mask = exec_mask::all_off();
+ check_masks();
+
+ forIncrBody();
+ }
+
+ m_exec = orig_exec & m_kernel_exec;
+ m_continue_mask = orig_continue_mask;
+
+#ifdef _DEBUG
+ m_in_loop = prev_in_loop;
+ check_masks();
+#endif
+}
diff --git a/thirdparty/basis_universal/encoder/cppspmd_math.h b/thirdparty/basis_universal/encoder/cppspmd_math.h
new file mode 100644
index 0000000000..e7b3202b8e
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/cppspmd_math.h
@@ -0,0 +1,725 @@
+// Do not include this header directly.
+//
+// Copyright 2020-2021 Binomial LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// The general goal of these vectorized estimated math functions is scalability/performance.
+// There are explictly no checks NaN's/Inf's on the input arguments. There are no assertions either.
+// These are fast estimate functions - if you need more than that, use stdlib. Please do a proper
+// engineering analysis before relying on them.
+// I have chosen functions written by others, ported them to CppSPMD, then measured their abs/rel errors.
+// I compared each to the ones in DirectXMath and stdlib's for accuracy/performance.
+
+CPPSPMD_FORCE_INLINE vfloat fmod_inv(const vfloat& a, const vfloat& b, const vfloat& b_inv)
+{
+ vfloat c = frac(abs(a * b_inv)) * abs(b);
+ return spmd_ternaryf(a < 0, -c, c);
+}
+
+CPPSPMD_FORCE_INLINE vfloat fmod_inv_p(const vfloat& a, const vfloat& b, const vfloat& b_inv)
+{
+ return frac(a * b_inv) * b;
+}
+
+// Avoids dividing by zero or very small values.
+CPPSPMD_FORCE_INLINE vfloat safe_div(vfloat a, vfloat b, float fDivThresh = 1e-7f)
+{
+ return a / spmd_ternaryf( abs(b) > fDivThresh, b, spmd_ternaryf(b < 0.0f, -fDivThresh, fDivThresh) );
+}
+
+/*
+ clang 9.0.0 for win /fp:precise release
+ f range: 0.0000000000001250 10000000000.0000000000000000, vals: 1073741824
+
+ log2_est():
+ max abs err: 0.0000023076808731
+ max rel err: 0.0000000756678881
+ avg abs err: 0.0000007535452724
+ avg rel err: 0.0000000235117843
+
+ XMVectorLog2():
+ max abs err: 0.0000023329709933
+ max rel err: 0.0000000826961046
+ avg abs err: 0.0000007564889684
+ avg rel err: 0.0000000236051899
+
+ std::log2f():
+ max abs err: 0.0000020265979401
+ max rel err: 0.0000000626647654
+ avg abs err: 0.0000007494445227
+ avg rel err: 0.0000000233800985
+*/
+
+// See https://tech.ebayinc.com/engineering/fast-approximate-logarithms-part-iii-the-formulas/
+inline vfloat spmd_kernel::log2_est(vfloat v)
+{
+ vfloat signif, fexp;
+
+ // Just clamp to a very small value, instead of checking for invalid inputs.
+ vfloat x = max(v, 2.2e-38f);
+
+ /*
+ * Assume IEEE representation, which is sgn(1):exp(8):frac(23)
+ * representing (1+frac)*2^(exp-127). Call 1+frac the significand
+ */
+
+ // get exponent
+ vint ux1_i = cast_vfloat_to_vint(x);
+
+ vint exp = VUINT_SHIFT_RIGHT(ux1_i & 0x7F800000, 23);
+
+ // actual exponent is exp-127, will subtract 127 later
+
+ vint ux2_i;
+ vfloat ux2_f;
+
+ vint greater = ux1_i & 0x00400000; // true if signif > 1.5
+ SPMD_SIF(greater != 0)
+ {
+ // signif >= 1.5 so need to divide by 2. Accomplish this by stuffing exp = 126 which corresponds to an exponent of -1
+ store_all(ux2_i, (ux1_i & 0x007FFFFF) | 0x3f000000);
+
+ store_all(ux2_f, cast_vint_to_vfloat(ux2_i));
+
+ // 126 instead of 127 compensates for division by 2
+ store_all(fexp, vfloat(exp - 126));
+ }
+ SPMD_SELSE(greater != 0)
+ {
+ // get signif by stuffing exp = 127 which corresponds to an exponent of 0
+ store(ux2_i, (ux1_i & 0x007FFFFF) | 0x3f800000);
+
+ store(ux2_f, cast_vint_to_vfloat(ux2_i));
+
+ store(fexp, vfloat(exp - 127));
+ }
+ SPMD_SENDIF
+
+ store_all(signif, ux2_f);
+ store_all(signif, signif - 1.0f);
+
+ const float a = 0.1501692f, b = 3.4226132f, c = 5.0225057f, d = 4.1130283f, e = 3.4813372f;
+
+ vfloat xm1 = signif;
+ vfloat xm1sqr = xm1 * xm1;
+
+ return fexp + ((a * (xm1sqr * xm1) + b * xm1sqr + c * xm1) / (xm1sqr + d * xm1 + e));
+
+ // fma lowers accuracy for SSE4.1 - no idea why (compiler reordering?)
+ //return fexp + ((vfma(a, (xm1sqr * xm1), vfma(b, xm1sqr, c * xm1))) / (xm1sqr + vfma(d, xm1, e)));
+}
+
+// Uses log2_est(), so this function must be <= the precision of that.
+inline vfloat spmd_kernel::log_est(vfloat v)
+{
+ return log2_est(v) * 0.693147181f;
+}
+
+CPPSPMD_FORCE_INLINE void spmd_kernel::reduce_expb(vfloat& arg, vfloat& two_int_a, vint& adjustment)
+{
+ // Assume we're using equation (2)
+ store_all(adjustment, 0);
+
+ // integer part of the input argument
+ vint int_arg = (vint)arg;
+
+ // if frac(arg) is in [0.5, 1.0]...
+ SPMD_SIF((arg - int_arg) > 0.5f)
+ {
+ store(adjustment, 1);
+
+ // then change it to [0.0, 0.5]
+ store(arg, arg - 0.5f);
+ }
+ SPMD_SENDIF
+
+ // arg == just the fractional part
+ store_all(arg, arg - (vfloat)int_arg);
+
+ // Now compute 2** (int) arg.
+ store_all(int_arg, min(int_arg + 127, 254));
+
+ store_all(two_int_a, cast_vint_to_vfloat(VINT_SHIFT_LEFT(int_arg, 23)));
+}
+
+/*
+ clang 9.0.0 for win /fp:precise release
+ f range : -50.0000000000000000 49.9999940395355225, vals : 16777216
+
+ exp2_est():
+ Total passed near - zero check : 16777216
+ Total sign diffs : 0
+ max abs err: 1668910609.7500000000000000
+ max rel err: 0.0000015642030031
+ avg abs err: 10793794.4007573910057545
+ avg rel err: 0.0000003890893282
+
+ XMVectorExp2():
+ Total passed near-zero check: 16777216
+ Total sign diffs: 0
+ max abs err: 1665552836.8750000000000000
+ max rel err: 0.0000114674862370
+ avg abs err: 10771868.2627860084176064
+ avg rel err: 0.0000011218880770
+
+ std::exp2f():
+ Total passed near-zero check: 16777216
+ Total sign diffs: 0
+ max abs err: 1591636585.6250000000000000
+ max rel err: 0.0000014849731018
+ avg abs err: 10775800.3204844966530800
+ avg rel err: 0.0000003851496422
+*/
+
+// http://www.ganssle.com/item/approximations-c-code-exponentiation-log.htm
+inline vfloat spmd_kernel::exp2_est(vfloat arg)
+{
+ SPMD_BEGIN_CALL
+
+ const vfloat P00 = +7.2152891521493f;
+ const vfloat P01 = +0.0576900723731f;
+ const vfloat Q00 = +20.8189237930062f;
+ const vfloat Q01 = +1.0f;
+ const vfloat sqrt2 = 1.4142135623730950488f; // sqrt(2) for scaling
+
+ vfloat result = 0.0f;
+
+ // Return 0 if arg is too large.
+ // We're not introducing inf/nan's into calculations, or risk doing so by returning huge default values.
+ SPMD_IF(abs(arg) > 126.0f)
+ {
+ spmd_return();
+ }
+ SPMD_END_IF
+
+ // 2**(int(a))
+ vfloat two_int_a;
+
+ // set to 1 by reduce_expb
+ vint adjustment;
+
+ // 0 if arg is +; 1 if negative
+ vint negative = 0;
+
+ // If the input is negative, invert it. At the end we'll take the reciprocal, since n**(-1) = 1/(n**x).
+ SPMD_SIF(arg < 0.0f)
+ {
+ store(arg, -arg);
+ store(negative, 1);
+ }
+ SPMD_SENDIF
+
+ store_all(arg, min(arg, 126.0f));
+
+ // reduce to [0.0, 0.5]
+ reduce_expb(arg, two_int_a, adjustment);
+
+ // The format of the polynomial is:
+ // answer=(Q(x**2) + x*P(x**2))/(Q(x**2) - x*P(x**2))
+ //
+ // The following computes the polynomial in several steps:
+
+ // Q(x**2)
+ vfloat Q = vfma(Q01, (arg * arg), Q00);
+
+ // x*P(x**2)
+ vfloat x_P = arg * (vfma(P01, arg * arg, P00));
+
+ vfloat answer = (Q + x_P) / (Q - x_P);
+
+ // Now correct for the scaling factor of 2**(int(a))
+ store_all(answer, answer * two_int_a);
+
+ // If the result had a fractional part > 0.5, correct for that
+ store_all(answer, spmd_ternaryf(adjustment != 0, answer * sqrt2, answer));
+
+ // Correct for a negative input
+ SPMD_SIF(negative != 0)
+ {
+ store(answer, 1.0f / answer);
+ }
+ SPMD_SENDIF
+
+ store(result, answer);
+
+ return result;
+}
+
+inline vfloat spmd_kernel::exp_est(vfloat arg)
+{
+ // e^x = exp2(x / log_base_e(2))
+ // constant is 1.0/(log(2)/log(e)) or 1/log(2)
+ return exp2_est(arg * 1.44269504f);
+}
+
+inline vfloat spmd_kernel::pow_est(vfloat arg1, vfloat arg2)
+{
+ return exp_est(log_est(arg1) * arg2);
+}
+
+/*
+ clang 9.0.0 for win /fp:precise release
+ Total near-zero: 144, output above near-zero tresh: 30
+ Total near-zero avg: 0.0000067941016621 max: 0.0000134706497192
+ Total near-zero sign diffs: 5
+ Total passed near-zero check: 16777072
+ Total sign diffs: 5
+ max abs err: 0.0000031375306036
+ max rel err: 0.1140846017075028
+ avg abs err: 0.0000003026226621
+ avg rel err: 0.0000033564977623
+*/
+
+// Math from this web page: http://developer.download.nvidia.com/cg/sin.html
+// This is ~2x slower than sin_est() or cos_est(), and less accurate, but I'm keeping it here for comparison purposes to help validate/sanity check sin_est() and cos_est().
+inline vfloat spmd_kernel::sincos_est_a(vfloat a, bool sin_flag)
+{
+ const float c0_x = 0.0f, c0_y = 0.5f, c0_z = 1.0f;
+ const float c1_x = 0.25f, c1_y = -9.0f, c1_z = 0.75f, c1_w = 0.159154943091f;
+ const float c2_x = 24.9808039603f, c2_y = -24.9808039603f, c2_z = -60.1458091736f, c2_w = 60.1458091736f;
+ const float c3_x = 85.4537887573f, c3_y = -85.4537887573f, c3_z = -64.9393539429f, c3_w = 64.9393539429f;
+ const float c4_x = 19.7392082214f, c4_y = -19.7392082214f, c4_z = -1.0f, c4_w = 1.0f;
+
+ vfloat r0_x, r0_y, r0_z, r1_x, r1_y, r1_z, r2_x, r2_y, r2_z;
+
+ store_all(r1_x, sin_flag ? vfms(c1_w, a, c1_x) : c1_w * a);
+
+ store_all(r1_y, frac(r1_x));
+
+ store_all(r2_x, (vfloat)(r1_y < c1_x));
+
+ store_all(r2_y, (vfloat)(r1_y >= c1_y));
+ store_all(r2_z, (vfloat)(r1_y >= c1_z));
+
+ store_all(r2_y, vfma(r2_x, c4_z, vfma(r2_y, c4_w, r2_z * c4_z)));
+
+ store_all(r0_x, c0_x - r1_y);
+ store_all(r0_y, c0_y - r1_y);
+ store_all(r0_z, c0_z - r1_y);
+
+ store_all(r0_x, r0_x * r0_x);
+ store_all(r0_y, r0_y * r0_y);
+ store_all(r0_z, r0_z * r0_z);
+
+ store_all(r1_x, vfma(c2_x, r0_x, c2_z));
+ store_all(r1_y, vfma(c2_y, r0_y, c2_w));
+ store_all(r1_z, vfma(c2_x, r0_z, c2_z));
+
+ store_all(r1_x, vfma(r1_x, r0_x, c3_x));
+ store_all(r1_y, vfma(r1_y, r0_y, c3_y));
+ store_all(r1_z, vfma(r1_z, r0_z, c3_x));
+
+ store_all(r1_x, vfma(r1_x, r0_x, c3_z));
+ store_all(r1_y, vfma(r1_y, r0_y, c3_w));
+ store_all(r1_z, vfma(r1_z, r0_z, c3_z));
+
+ store_all(r1_x, vfma(r1_x, r0_x, c4_x));
+ store_all(r1_y, vfma(r1_y, r0_y, c4_y));
+ store_all(r1_z, vfma(r1_z, r0_z, c4_x));
+
+ store_all(r1_x, vfma(r1_x, r0_x, c4_z));
+ store_all(r1_y, vfma(r1_y, r0_y, c4_w));
+ store_all(r1_z, vfma(r1_z, r0_z, c4_z));
+
+ store_all(r0_x, vfnma(r1_x, r2_x, vfnma(r1_y, r2_y, r1_z * -r2_z)));
+
+ return r0_x;
+}
+
+// positive values only
+CPPSPMD_FORCE_INLINE vfloat spmd_kernel::recip_est1(const vfloat& q)
+{
+ //const int mag = 0x7EF312AC; // 2 NR iters, 3 is 0x7EEEEBB3
+ const int mag = 0x7EF311C3;
+ const float fMinThresh = .0000125f;
+
+ vfloat l = spmd_ternaryf(q >= fMinThresh, q, cast_vint_to_vfloat(vint(mag)));
+
+ vint x_l = vint(mag) - cast_vfloat_to_vint(l);
+
+ vfloat rcp_l = cast_vint_to_vfloat(x_l);
+
+ return rcp_l * vfnma(rcp_l, q, 2.0f);
+}
+
+CPPSPMD_FORCE_INLINE vfloat spmd_kernel::recip_est1_pn(const vfloat& t)
+{
+ //const int mag = 0x7EF312AC; // 2 NR iters, 3 is 0x7EEEEBB3
+ const int mag = 0x7EF311C3;
+ const float fMinThresh = .0000125f;
+
+ vfloat s = sign(t);
+ vfloat q = abs(t);
+
+ vfloat l = spmd_ternaryf(q >= fMinThresh, q, cast_vint_to_vfloat(vint(mag)));
+
+ vint x_l = vint(mag) - cast_vfloat_to_vint(l);
+
+ vfloat rcp_l = cast_vint_to_vfloat(x_l);
+
+ return rcp_l * vfnma(rcp_l, q, 2.0f) * s;
+}
+
+// https://basesandframes.files.wordpress.com/2020/04/even_faster_math_functions_green_2020.pdf
+// https://github.com/hcs0/Hackers-Delight/blob/master/rsqrt.c.txt
+CPPSPMD_FORCE_INLINE vfloat spmd_kernel::rsqrt_est1(vfloat x0)
+{
+ vfloat xhalf = 0.5f * x0;
+ vfloat x = cast_vint_to_vfloat(vint(0x5F375A82) - (VINT_SHIFT_RIGHT(cast_vfloat_to_vint(x0), 1)));
+ return x * vfnma(xhalf * x, x, 1.5008909f);
+}
+
+CPPSPMD_FORCE_INLINE vfloat spmd_kernel::rsqrt_est2(vfloat x0)
+{
+ vfloat xhalf = 0.5f * x0;
+ vfloat x = cast_vint_to_vfloat(vint(0x5F37599E) - (VINT_SHIFT_RIGHT(cast_vfloat_to_vint(x0), 1)));
+ vfloat x1 = x * vfnma(xhalf * x, x, 1.5);
+ vfloat x2 = x1 * vfnma(xhalf * x1, x1, 1.5);
+ return x2;
+}
+
+// Math from: http://developer.download.nvidia.com/cg/atan2.html
+// TODO: Needs more validation, parameter checking.
+CPPSPMD_FORCE_INLINE vfloat spmd_kernel::atan2_est(vfloat y, vfloat x)
+{
+ vfloat t1 = abs(y);
+ vfloat t3 = abs(x);
+
+ vfloat t0 = max(t3, t1);
+ store_all(t1, min(t3, t1));
+
+ store_all(t3, t1 / t0);
+
+ vfloat t4 = t3 * t3;
+ store_all(t0, vfma(-0.013480470f, t4, 0.057477314f));
+ store_all(t0, vfms(t0, t4, 0.121239071f));
+ store_all(t0, vfma(t0, t4, 0.195635925f));
+ store_all(t0, vfms(t0, t4, 0.332994597f));
+ store_all(t0, vfma(t0, t4, 0.999995630f));
+ store_all(t3, t0 * t3);
+
+ store_all(t3, spmd_ternaryf(abs(y) > abs(x), vfloat(1.570796327f) - t3, t3));
+
+ store_all(t3, spmd_ternaryf(x < 0.0f, vfloat(3.141592654f) - t3, t3));
+ store_all(t3, spmd_ternaryf(y < 0.0f, -t3, t3));
+
+ return t3;
+}
+
+/*
+ clang 9.0.0 for win /fp:precise release
+ Tested range: -25.1327412287183449 25.1327382326621169, vals : 16777216
+ Skipped angles near 90/270 within +- .001 radians.
+ Near-zero threshold: .0000125f
+ Near-zero output above check threshold: 1e-6f
+
+ Total near-zero: 144, output above near-zero tresh: 20
+ Total near-zero avg: 0.0000067510751968 max: 0.0000133514404297
+ Total near-zero sign diffs: 5
+ Total passed near-zero check: 16766400
+ Total sign diffs: 5
+ max abs err: 1.4982600811139264
+ max rel err: 0.1459155900188041
+ avg rel err: 0.0000054659502568
+
+ XMVectorTan() precise:
+ Total near-zero: 144, output above near-zero tresh: 18
+ Total near-zero avg: 0.0000067641216186 max: 0.0000133524126795
+ Total near-zero sign diffs: 0
+ Total passed near-zero check: 16766400
+ Total sign diffs: 0
+ max abs err: 1.9883573246424930
+ max rel err: 0.1459724171926864
+ avg rel err: 0.0000054965766843
+
+ std::tanf():
+ Total near-zero: 144, output above near-zero tresh: 0
+ Total near-zero avg: 0.0000067116930779 max: 0.0000127713074107
+ Total near-zero sign diffs: 11
+ Total passed near-zero check: 16766400
+ Total sign diffs: 11
+ max abs err: 0.8989131818294709
+ max rel err: 0.0573181403173166
+ avg rel err: 0.0000030791301203
+
+ Originally from:
+ http://www.ganssle.com/approx.htm
+*/
+
+CPPSPMD_FORCE_INLINE vfloat spmd_kernel::tan82(vfloat x)
+{
+ // Original double version was 8.2 digits
+ //double c1 = 211.849369664121f, c2 = -12.5288887278448f, c3 = 269.7350131214121f, c4 = -71.4145309347748f;
+ // Tuned float constants for lower avg rel error (without using FMA3):
+ const float c1 = 211.849350f, c2 = -12.5288887f, c3 = 269.734985f, c4 = -71.4145203f;
+ vfloat x2 = x * x;
+ return (x * (vfma(c2, x2, c1)) / (vfma(x2, (c4 + x2), c3)));
+}
+
+// Don't call this for angles close to 90/270!.
+inline vfloat spmd_kernel::tan_est(vfloat x)
+{
+ const float fPi = 3.141592653589793f, fOneOverPi = 0.3183098861837907f;
+ CPPSPMD_DECL(const uint8_t, s_table0[16]) = { 128 + 0, 128 + 2, 128 + -2, 128 + 4, 128 + 0, 128 + 2, 128 + -2, 128 + 4, 128 + 0, 128 + 2, 128 + -2, 128 + 4, 128 + 0, 128 + 2, 128 + -2, 128 + 4 };
+
+ vint table = init_lookup4(s_table0); // a load
+ vint sgn = cast_vfloat_to_vint(x) & 0x80000000;
+
+ store_all(x, abs(x));
+ vfloat orig_x = x;
+
+ vfloat q = x * fOneOverPi;
+ store_all(x, q - floor(q));
+
+ vfloat x4 = x * 4.0f;
+ vint octant = (vint)(x4);
+
+ vfloat x0 = spmd_ternaryf((octant & 1) != 0, -x4, x4);
+
+ vint k = table_lookup4_8(octant, table) & 0xFF; // a shuffle
+
+ vfloat bias = (vfloat)k + -128.0f;
+ vfloat y = x0 + bias;
+
+ vfloat z = tan82(y);
+
+ vfloat r;
+
+ vbool octant_one_or_two = (octant == 1) || (octant == 2);
+
+ // SPMD optimization - skip costly divide if we can
+ if (spmd_any(octant_one_or_two))
+ {
+ const float fDivThresh = .4371e-7f;
+ vfloat one_over_z = 1.0f / spmd_ternaryf(abs(z) > fDivThresh, z, spmd_ternaryf(z < 0.0f, -fDivThresh, fDivThresh));
+
+ vfloat b = spmd_ternaryf(octant_one_or_two, one_over_z, z);
+ store_all(r, spmd_ternaryf((octant & 2) != 0, -b, b));
+ }
+ else
+ {
+ store_all(r, spmd_ternaryf(octant == 0, z, -z));
+ }
+
+ // Small angle approximation, to decrease the max rel error near Pi.
+ SPMD_SIF(x >= (1.0f - .0003125f*4.0f))
+ {
+ store(r, vfnma(floor(q) + 1.0f, fPi, orig_x));
+ }
+ SPMD_SENDIF
+
+ return cast_vint_to_vfloat(cast_vfloat_to_vint(r) ^ sgn);
+}
+
+inline void spmd_kernel::seed_rand(rand_context& x, vint seed)
+{
+ store(x.a, 0xf1ea5eed);
+ store(x.b, seed ^ 0xd8487b1f);
+ store(x.c, seed ^ 0xdbadef9a);
+ store(x.d, seed);
+ for (int i = 0; i < 20; ++i)
+ (void)get_randu(x);
+}
+
+// https://burtleburtle.net/bob/rand/smallprng.html
+// Returns 32-bit unsigned random numbers.
+inline vint spmd_kernel::get_randu(rand_context& x)
+{
+ vint e = x.a - VINT_ROT(x.b, 27);
+ store(x.a, x.b ^ VINT_ROT(x.c, 17));
+ store(x.b, x.c + x.d);
+ store(x.c, x.d + e);
+ store(x.d, e + x.a);
+ return x.d;
+}
+
+// Returns random numbers between [low, high), or low if low >= high
+inline vint spmd_kernel::get_randi(rand_context& x, vint low, vint high)
+{
+ vint rnd = get_randu(x);
+
+ vint range = high - low;
+
+ vint rnd_range = mulhiu(rnd, range);
+
+ return spmd_ternaryi(low < high, low + rnd_range, low);
+}
+
+// Returns random numbers between [low, high), or low if low >= high
+inline vfloat spmd_kernel::get_randf(rand_context& x, vfloat low, vfloat high)
+{
+ vint rndi = get_randu(x) & 0x7fffff;
+
+ vfloat rnd = (vfloat)(rndi) * (1.0f / 8388608.0f);
+
+ return spmd_ternaryf(low < high, vfma(high - low, rnd, low), low);
+}
+
+CPPSPMD_FORCE_INLINE void spmd_kernel::init_reverse_bits(vint& tab1, vint& tab2)
+{
+ const uint8_t tab1_bytes[16] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
+ const uint8_t tab2_bytes[16] = { 0, 8 << 4, 4 << 4, 12 << 4, 2 << 4, 10 << 4, 6 << 4, 14 << 4, 1 << 4, 9 << 4, 5 << 4, 13 << 4, 3 << 4, 11 << 4, 7 << 4, 15 << 4 };
+ store_all(tab1, init_lookup4(tab1_bytes));
+ store_all(tab2, init_lookup4(tab2_bytes));
+}
+
+CPPSPMD_FORCE_INLINE vint spmd_kernel::reverse_bits(vint k, vint tab1, vint tab2)
+{
+ vint r0 = table_lookup4_8(k & 0x7F7F7F7F, tab2);
+ vint r1 = table_lookup4_8(VUINT_SHIFT_RIGHT(k, 4) & 0x7F7F7F7F, tab1);
+ vint r3 = r0 | r1;
+ return byteswap(r3);
+}
+
+CPPSPMD_FORCE_INLINE vint spmd_kernel::count_leading_zeros(vint x)
+{
+ CPPSPMD_DECL(const uint8_t, s_tab[16]) = { 0, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ vint tab = init_lookup4(s_tab);
+
+ //x <= 0x0000ffff
+ vbool c0 = (x & 0xFFFF0000) == 0;
+ vint n0 = spmd_ternaryi(c0, 16, 0);
+ vint x0 = spmd_ternaryi(c0, VINT_SHIFT_LEFT(x, 16), x);
+
+ //x <= 0x00ffffff
+ vbool c1 = (x0 & 0xFF000000) == 0;
+ vint n1 = spmd_ternaryi(c1, n0 + 8, n0);
+ vint x1 = spmd_ternaryi(c1, VINT_SHIFT_LEFT(x0, 8), x0);
+
+ //x <= 0x0fffffff
+ vbool c2 = (x1 & 0xF0000000) == 0;
+ vint n2 = spmd_ternaryi(c2, n1 + 4, n1);
+ vint x2 = spmd_ternaryi(c2, VINT_SHIFT_LEFT(x1, 4), x1);
+
+ return table_lookup4_8(VUINT_SHIFT_RIGHT(x2, 28), tab) + n2;
+}
+
+CPPSPMD_FORCE_INLINE vint spmd_kernel::count_leading_zeros_alt(vint x)
+{
+ //x <= 0x0000ffff
+ vbool c0 = (x & 0xFFFF0000) == 0;
+ vint n0 = spmd_ternaryi(c0, 16, 0);
+ vint x0 = spmd_ternaryi(c0, VINT_SHIFT_LEFT(x, 16), x);
+
+ //x <= 0x00ffffff
+ vbool c1 = (x0 & 0xFF000000) == 0;
+ vint n1 = spmd_ternaryi(c1, n0 + 8, n0);
+ vint x1 = spmd_ternaryi(c1, VINT_SHIFT_LEFT(x0, 8), x0);
+
+ //x <= 0x0fffffff
+ vbool c2 = (x1 & 0xF0000000) == 0;
+ vint n2 = spmd_ternaryi(c2, n1 + 4, n1);
+ vint x2 = spmd_ternaryi(c2, VINT_SHIFT_LEFT(x1, 4), x1);
+
+ // x <= 0x3fffffff
+ vbool c3 = (x2 & 0xC0000000) == 0;
+ vint n3 = spmd_ternaryi(c3, n2 + 2, n2);
+ vint x3 = spmd_ternaryi(c3, VINT_SHIFT_LEFT(x2, 2), x2);
+
+ // x <= 0x7fffffff
+ vbool c4 = (x3 & 0x80000000) == 0;
+ return spmd_ternaryi(c4, n3 + 1, n3);
+}
+
+CPPSPMD_FORCE_INLINE vint spmd_kernel::count_trailing_zeros(vint x)
+{
+ // cast the least significant bit in v to a float
+ vfloat f = (vfloat)(x & -x);
+
+ // extract exponent and adjust
+ return VUINT_SHIFT_RIGHT(cast_vfloat_to_vint(f), 23) - 0x7F;
+}
+
+CPPSPMD_FORCE_INLINE vint spmd_kernel::count_set_bits(vint x)
+{
+ vint v = x - (VUINT_SHIFT_RIGHT(x, 1) & 0x55555555);
+ vint v1 = (v & 0x33333333) + (VUINT_SHIFT_RIGHT(v, 2) & 0x33333333);
+ return VUINT_SHIFT_RIGHT(((v1 + VUINT_SHIFT_RIGHT(v1, 4) & 0xF0F0F0F) * 0x1010101), 24);
+}
+
+CPPSPMD_FORCE_INLINE vint cmple_epu16(const vint &a, const vint &b)
+{
+ return cmpeq_epi16(subs_epu16(a, b), vint(0));
+}
+
+CPPSPMD_FORCE_INLINE vint cmpge_epu16(const vint &a, const vint &b)
+{
+ return cmple_epu16(b, a);
+}
+
+CPPSPMD_FORCE_INLINE vint cmpgt_epu16(const vint &a, const vint &b)
+{
+ return andnot(cmpeq_epi16(a, b), cmple_epu16(b, a));
+}
+
+CPPSPMD_FORCE_INLINE vint cmplt_epu16(const vint &a, const vint &b)
+{
+ return cmpgt_epu16(b, a);
+}
+
+CPPSPMD_FORCE_INLINE vint cmpge_epi16(const vint &a, const vint &b)
+{
+ return cmpeq_epi16(a, b) | cmpgt_epi16(a, b);
+}
+
+CPPSPMD_FORCE_INLINE vint cmple_epi16(const vint &a, const vint &b)
+{
+ return cmpge_epi16(b, a);
+}
+
+void spmd_kernel::print_vint(vint v)
+{
+ for (uint32_t i = 0; i < PROGRAM_COUNT; i++)
+ printf("%i ", extract(v, i));
+ printf("\n");
+}
+
+void spmd_kernel::print_vbool(vbool v)
+{
+ for (uint32_t i = 0; i < PROGRAM_COUNT; i++)
+ printf("%i ", extract(v, i) ? 1 : 0);
+ printf("\n");
+}
+
+void spmd_kernel::print_vint_hex(vint v)
+{
+ for (uint32_t i = 0; i < PROGRAM_COUNT; i++)
+ printf("0x%X ", extract(v, i));
+ printf("\n");
+}
+
+void spmd_kernel::print_active_lanes(const char *pPrefix)
+{
+ CPPSPMD_DECL(int, flags[PROGRAM_COUNT]);
+ memset(flags, 0, sizeof(flags));
+ storeu_linear(flags, vint(1));
+
+ if (pPrefix)
+ printf("%s", pPrefix);
+
+ for (uint32_t i = 0; i < PROGRAM_COUNT; i++)
+ {
+ if (flags[i])
+ printf("%u ", i);
+ }
+ printf("\n");
+}
+
+void spmd_kernel::print_vfloat(vfloat v)
+{
+ for (uint32_t i = 0; i < PROGRAM_COUNT; i++)
+ printf("%f ", extract(v, i));
+ printf("\n");
+}
diff --git a/thirdparty/basis_universal/encoder/cppspmd_math_declares.h b/thirdparty/basis_universal/encoder/cppspmd_math_declares.h
new file mode 100644
index 0000000000..cdb6447b62
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/cppspmd_math_declares.h
@@ -0,0 +1,89 @@
+// Do not include this header directly.
+// This header defines shared struct spmd_kernel helpers.
+//
+// Copyright 2020-2021 Binomial LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// See cppspmd_math.h for detailed error statistics.
+
+CPPSPMD_FORCE_INLINE void reduce_expb(vfloat& arg, vfloat& two_int_a, vint& adjustment);
+CPPSPMD_FORCE_INLINE vfloat tan56(vfloat x);
+CPPSPMD_FORCE_INLINE vfloat tan82(vfloat x);
+
+inline vfloat log2_est(vfloat v);
+
+inline vfloat log_est(vfloat v);
+
+inline vfloat exp2_est(vfloat arg);
+
+inline vfloat exp_est(vfloat arg);
+
+inline vfloat pow_est(vfloat arg1, vfloat arg2);
+
+CPPSPMD_FORCE_INLINE vfloat recip_est1(const vfloat& q);
+CPPSPMD_FORCE_INLINE vfloat recip_est1_pn(const vfloat& q);
+
+inline vfloat mod_angles(vfloat a);
+
+inline vfloat sincos_est_a(vfloat a, bool sin_flag);
+CPPSPMD_FORCE_INLINE vfloat sin_est_a(vfloat a) { return sincos_est_a(a, true); }
+CPPSPMD_FORCE_INLINE vfloat cos_est_a(vfloat a) { return sincos_est_a(a, false); }
+
+inline vfloat sin_est(vfloat a);
+
+inline vfloat cos_est(vfloat a);
+
+// Don't call with values <= 0.
+CPPSPMD_FORCE_INLINE vfloat rsqrt_est1(vfloat x0);
+
+// Don't call with values <= 0.
+CPPSPMD_FORCE_INLINE vfloat rsqrt_est2(vfloat x0);
+
+CPPSPMD_FORCE_INLINE vfloat atan2_est(vfloat y, vfloat x);
+
+CPPSPMD_FORCE_INLINE vfloat atan_est(vfloat x) { return atan2_est(x, vfloat(1.0f)); }
+
+// Don't call this for angles close to 90/270!
+inline vfloat tan_est(vfloat x);
+
+// https://burtleburtle.net/bob/rand/smallprng.html
+struct rand_context { vint a, b, c, d; };
+
+inline void seed_rand(rand_context& x, vint seed);
+
+// Returns 32-bit unsigned random numbers.
+inline vint get_randu(rand_context& x);
+
+// Returns random numbers between [low, high), or low if low >= high
+inline vint get_randi(rand_context& x, vint low, vint high);
+
+// Returns random numbers between [low, high), or low if low >= high
+inline vfloat get_randf(rand_context& x, vfloat low, vfloat high);
+
+CPPSPMD_FORCE_INLINE void init_reverse_bits(vint& tab1, vint& tab2);
+CPPSPMD_FORCE_INLINE vint reverse_bits(vint k, vint tab1, vint tab2);
+
+CPPSPMD_FORCE_INLINE vint count_leading_zeros(vint x);
+CPPSPMD_FORCE_INLINE vint count_leading_zeros_alt(vint x);
+
+CPPSPMD_FORCE_INLINE vint count_trailing_zeros(vint x);
+
+CPPSPMD_FORCE_INLINE vint count_set_bits(vint x);
+
+void print_vint(vint v);
+void print_vbool(vbool v);
+void print_vint_hex(vint v);
+void print_active_lanes(const char *pPrefix);
+void print_vfloat(vfloat v);
+
diff --git a/thirdparty/basis_universal/encoder/cppspmd_sse.h b/thirdparty/basis_universal/encoder/cppspmd_sse.h
new file mode 100644
index 0000000000..b39cb82a5f
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/cppspmd_sse.h
@@ -0,0 +1,2118 @@
+// cppspmd_sse.h
+// Note for Basis Universal: All of the "cppspmd" code and headers are OPTIONAL to Basis Universal. if BASISU_SUPPORT_SSE is 0, it will never be included and does not impact compilation.
+// SSE 2 or 4.1
+// Originally written by Nicolas Guillemot, Jefferson Amstutz in the "CppSPMD" project.
+// 4/20: Richard Geldreich: Macro control flow, more SIMD instruction sets, optimizations, supports using multiple SIMD instruction sets in same executable. Still a work in progress!
+//
+// Originally Copyright 2016 Nicolas Guillemot
+// Changed from the MIT license to Apache 2.0 with permission from the author.
+//
+// Modifications/enhancements Copyright 2020-2021 Binomial LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <math.h>
+#include <utility>
+#include <algorithm>
+
+#if CPPSPMD_SSE2
+#include <xmmintrin.h> // SSE
+#include <emmintrin.h> // SSE2
+#else
+#include <xmmintrin.h> // SSE
+#include <emmintrin.h> // SSE2
+#include <pmmintrin.h> // SSE3
+#include <tmmintrin.h> // SSSE3
+#include <smmintrin.h> // SSE4.1
+//#include <nmmintrin.h> // SSE4.2
+#endif
+
+#undef CPPSPMD_SSE
+#undef CPPSPMD_AVX1
+#undef CPPSPMD_AVX2
+#undef CPPSPMD_AVX
+#undef CPPSPMD_FLOAT4
+#undef CPPSPMD_INT16
+
+#define CPPSPMD_SSE 1
+#define CPPSPMD_AVX 0
+#define CPPSPMD_AVX1 0
+#define CPPSPMD_AVX2 0
+#define CPPSPMD_FLOAT4 0
+#define CPPSPMD_INT16 0
+
+#ifdef _MSC_VER
+ #ifndef CPPSPMD_DECL
+ #define CPPSPMD_DECL(type, name) __declspec(align(16)) type name
+ #endif
+
+ #ifndef CPPSPMD_ALIGN
+ #define CPPSPMD_ALIGN(v) __declspec(align(v))
+ #endif
+
+ #define _mm_undefined_si128 _mm_setzero_si128
+ #define _mm_undefined_ps _mm_setzero_ps
+#else
+ #ifndef CPPSPMD_DECL
+ #define CPPSPMD_DECL(type, name) type name __attribute__((aligned(32)))
+ #endif
+
+ #ifndef CPPSPMD_ALIGN
+ #define CPPSPMD_ALIGN(v) __attribute__((aligned(v)))
+ #endif
+#endif
+
+#ifndef CPPSPMD_FORCE_INLINE
+#ifdef _DEBUG
+#define CPPSPMD_FORCE_INLINE inline
+#else
+ #ifdef _MSC_VER
+ #define CPPSPMD_FORCE_INLINE __forceinline
+ #else
+ #define CPPSPMD_FORCE_INLINE inline
+ #endif
+#endif
+#endif
+
+#undef CPPSPMD
+#undef CPPSPMD_ARCH
+
+#if CPPSPMD_SSE2
+ #define CPPSPMD_SSE41 0
+ #define CPPSPMD cppspmd_sse2
+ #define CPPSPMD_ARCH _sse2
+#else
+ #define CPPSPMD_SSE41 1
+ #define CPPSPMD cppspmd_sse41
+ #define CPPSPMD_ARCH _sse41
+#endif
+
+#ifndef CPPSPMD_GLUER
+ #define CPPSPMD_GLUER(a, b) a##b
+#endif
+
+#ifndef CPPSPMD_GLUER2
+ #define CPPSPMD_GLUER2(a, b) CPPSPMD_GLUER(a, b)
+#endif
+
+#ifndef CPPSPMD_NAME
+#define CPPSPMD_NAME(a) CPPSPMD_GLUER2(a, CPPSPMD_ARCH)
+#endif
+
+#undef VASSERT
+#define VCOND(cond) ((exec_mask(vbool(cond)) & m_exec).get_movemask() == m_exec.get_movemask())
+#define VASSERT(cond) assert( VCOND(cond) )
+
+#define CPPSPMD_ALIGNMENT (16)
+
+#define storeu_si32(p, a) (void)(*(int*)(p) = _mm_cvtsi128_si32((a)))
+
+namespace CPPSPMD
+{
+
+const int PROGRAM_COUNT_SHIFT = 2;
+const int PROGRAM_COUNT = 1 << PROGRAM_COUNT_SHIFT;
+
+template <typename N> inline N* aligned_new() { void* p = _mm_malloc(sizeof(N), 64); new (p) N; return static_cast<N*>(p); }
+template <typename N> void aligned_delete(N* p) { if (p) { p->~N(); _mm_free(p); } }
+
+CPPSPMD_DECL(const uint32_t, g_allones_128[4]) = { UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX };
+CPPSPMD_DECL(const uint32_t, g_x_128[4]) = { UINT32_MAX, 0, 0, 0 };
+CPPSPMD_DECL(const float, g_onef_128[4]) = { 1.0f, 1.0f, 1.0f, 1.0f };
+CPPSPMD_DECL(const uint32_t, g_oneu_128[4]) = { 1, 1, 1, 1 };
+
+CPPSPMD_DECL(const uint32_t, g_lane_masks_128[4][4]) =
+{
+ { UINT32_MAX, 0, 0, 0 },
+ { 0, UINT32_MAX, 0, 0 },
+ { 0, 0, UINT32_MAX, 0 },
+ { 0, 0, 0, UINT32_MAX },
+};
+
+#if CPPSPMD_SSE41
+CPPSPMD_FORCE_INLINE __m128i _mm_blendv_epi32(__m128i a, __m128i b, __m128i c) { return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _mm_castsi128_ps(c))); }
+#endif
+
+CPPSPMD_FORCE_INLINE __m128i blendv_epi8(__m128i a, __m128i b, __m128i mask)
+{
+#if CPPSPMD_SSE2
+ return _mm_castps_si128(_mm_or_ps(_mm_and_ps(_mm_castsi128_ps(mask), _mm_castsi128_ps(b)), _mm_andnot_ps(_mm_castsi128_ps(mask), _mm_castsi128_ps(a))));
+#else
+ return _mm_blendv_epi8(a, b, mask);
+#endif
+}
+
+CPPSPMD_FORCE_INLINE __m128 blendv_mask_ps(__m128 a, __m128 b, __m128 mask)
+{
+#if CPPSPMD_SSE2
+ // We know it's a mask, so we can just emulate the blend.
+ return _mm_or_ps(_mm_and_ps(mask, b), _mm_andnot_ps(mask, a));
+#else
+ return _mm_blendv_ps(a, b, mask);
+#endif
+}
+
+CPPSPMD_FORCE_INLINE __m128 blendv_ps(__m128 a, __m128 b, __m128 mask)
+{
+#if CPPSPMD_SSE2
+ // Input is not a mask, but MSB bits - so emulate _mm_blendv_ps() by replicating bit 31.
+ mask = _mm_castsi128_ps(_mm_srai_epi32(_mm_castps_si128(mask), 31));
+ return _mm_or_ps(_mm_and_ps(mask, b), _mm_andnot_ps(mask, a));
+#else
+ return _mm_blendv_ps(a, b, mask);
+#endif
+}
+
+CPPSPMD_FORCE_INLINE __m128i blendv_mask_epi32(__m128i a, __m128i b, __m128i mask)
+{
+ return _mm_castps_si128(blendv_mask_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _mm_castsi128_ps(mask)));
+}
+
+CPPSPMD_FORCE_INLINE __m128i blendv_epi32(__m128i a, __m128i b, __m128i mask)
+{
+ return _mm_castps_si128(blendv_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _mm_castsi128_ps(mask)));
+}
+
+#if CPPSPMD_SSE2
+CPPSPMD_FORCE_INLINE int extract_x(const __m128i& vec) { return _mm_cvtsi128_si32(vec); }
+CPPSPMD_FORCE_INLINE int extract_y(const __m128i& vec) { return _mm_cvtsi128_si32(_mm_shuffle_epi32(vec, 0x55)); }
+CPPSPMD_FORCE_INLINE int extract_z(const __m128i& vec) { return _mm_cvtsi128_si32(_mm_shuffle_epi32(vec, 0xAA)); }
+CPPSPMD_FORCE_INLINE int extract_w(const __m128i& vec) { return _mm_cvtsi128_si32(_mm_shuffle_epi32(vec, 0xFF)); }
+
+// Returns float bits as int, to emulate _mm_extract_ps()
+CPPSPMD_FORCE_INLINE int extract_ps_x(const __m128& vec) { float f = _mm_cvtss_f32(vec); return *(const int*)&f; }
+CPPSPMD_FORCE_INLINE int extract_ps_y(const __m128& vec) { float f = _mm_cvtss_f32(_mm_shuffle_ps(vec, vec, 0x55)); return *(const int*)&f; }
+CPPSPMD_FORCE_INLINE int extract_ps_z(const __m128& vec) { float f = _mm_cvtss_f32(_mm_shuffle_ps(vec, vec, 0xAA)); return *(const int*)&f; }
+CPPSPMD_FORCE_INLINE int extract_ps_w(const __m128& vec) { float f = _mm_cvtss_f32(_mm_shuffle_ps(vec, vec, 0xFF)); return *(const int*)&f; }
+
+// Returns floats
+CPPSPMD_FORCE_INLINE float extractf_ps_x(const __m128& vec) { return _mm_cvtss_f32(vec); }
+CPPSPMD_FORCE_INLINE float extractf_ps_y(const __m128& vec) { return _mm_cvtss_f32(_mm_shuffle_ps(vec, vec, 0x55)); }
+CPPSPMD_FORCE_INLINE float extractf_ps_z(const __m128& vec) { return _mm_cvtss_f32(_mm_shuffle_ps(vec, vec, 0xAA)); }
+CPPSPMD_FORCE_INLINE float extractf_ps_w(const __m128& vec) { return _mm_cvtss_f32(_mm_shuffle_ps(vec, vec, 0xFF)); }
+#else
+CPPSPMD_FORCE_INLINE int extract_x(const __m128i& vec) { return _mm_extract_epi32(vec, 0); }
+CPPSPMD_FORCE_INLINE int extract_y(const __m128i& vec) { return _mm_extract_epi32(vec, 1); }
+CPPSPMD_FORCE_INLINE int extract_z(const __m128i& vec) { return _mm_extract_epi32(vec, 2); }
+CPPSPMD_FORCE_INLINE int extract_w(const __m128i& vec) { return _mm_extract_epi32(vec, 3); }
+
+// Returns float bits as int
+CPPSPMD_FORCE_INLINE int extract_ps_x(const __m128& vec) { return _mm_extract_ps(vec, 0); }
+CPPSPMD_FORCE_INLINE int extract_ps_y(const __m128& vec) { return _mm_extract_ps(vec, 1); }
+CPPSPMD_FORCE_INLINE int extract_ps_z(const __m128& vec) { return _mm_extract_ps(vec, 2); }
+CPPSPMD_FORCE_INLINE int extract_ps_w(const __m128& vec) { return _mm_extract_ps(vec, 3); }
+
+// Returns floats
+CPPSPMD_FORCE_INLINE float extractf_ps_x(const __m128& vec) { int v = extract_ps_x(vec); return *(const float*)&v; }
+CPPSPMD_FORCE_INLINE float extractf_ps_y(const __m128& vec) { int v = extract_ps_y(vec); return *(const float*)&v; }
+CPPSPMD_FORCE_INLINE float extractf_ps_z(const __m128& vec) { int v = extract_ps_z(vec); return *(const float*)&v; }
+CPPSPMD_FORCE_INLINE float extractf_ps_w(const __m128& vec) { int v = extract_ps_w(vec); return *(const float*)&v; }
+#endif
+
+#if CPPSPMD_SSE2
+CPPSPMD_FORCE_INLINE __m128i insert_x(const __m128i& vec, int v) { return _mm_insert_epi16(_mm_insert_epi16(vec, v, 0), (uint32_t)v >> 16U, 1); }
+CPPSPMD_FORCE_INLINE __m128i insert_y(const __m128i& vec, int v) { return _mm_insert_epi16(_mm_insert_epi16(vec, v, 2), (uint32_t)v >> 16U, 3); }
+CPPSPMD_FORCE_INLINE __m128i insert_z(const __m128i& vec, int v) { return _mm_insert_epi16(_mm_insert_epi16(vec, v, 4), (uint32_t)v >> 16U, 5); }
+CPPSPMD_FORCE_INLINE __m128i insert_w(const __m128i& vec, int v) { return _mm_insert_epi16(_mm_insert_epi16(vec, v, 6), (uint32_t)v >> 16U, 7); }
+#else
+CPPSPMD_FORCE_INLINE __m128i insert_x(const __m128i& vec, int v) { return _mm_insert_epi32(vec, v, 0); }
+CPPSPMD_FORCE_INLINE __m128i insert_y(const __m128i& vec, int v) { return _mm_insert_epi32(vec, v, 1); }
+CPPSPMD_FORCE_INLINE __m128i insert_z(const __m128i& vec, int v) { return _mm_insert_epi32(vec, v, 2); }
+CPPSPMD_FORCE_INLINE __m128i insert_w(const __m128i& vec, int v) { return _mm_insert_epi32(vec, v, 3); }
+#endif
+
+#if CPPSPMD_SSE2
+inline __m128i shuffle_epi8(const __m128i& a, const __m128i& b)
+{
+ // Just emulate _mm_shuffle_epi8. This is very slow, but what else can we do?
+ CPPSPMD_ALIGN(16) uint8_t av[16];
+ _mm_store_si128((__m128i*)av, a);
+
+ CPPSPMD_ALIGN(16) uint8_t bvi[16];
+ _mm_store_ps((float*)bvi, _mm_and_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(_mm_set1_epi32(0x0F0F0F0F))));
+
+ CPPSPMD_ALIGN(16) uint8_t result[16];
+
+ result[0] = av[bvi[0]];
+ result[1] = av[bvi[1]];
+ result[2] = av[bvi[2]];
+ result[3] = av[bvi[3]];
+
+ result[4] = av[bvi[4]];
+ result[5] = av[bvi[5]];
+ result[6] = av[bvi[6]];
+ result[7] = av[bvi[7]];
+
+ result[8] = av[bvi[8]];
+ result[9] = av[bvi[9]];
+ result[10] = av[bvi[10]];
+ result[11] = av[bvi[11]];
+
+ result[12] = av[bvi[12]];
+ result[13] = av[bvi[13]];
+ result[14] = av[bvi[14]];
+ result[15] = av[bvi[15]];
+
+ return _mm_andnot_si128(_mm_cmplt_epi8(b, _mm_setzero_si128()), _mm_load_si128((__m128i*)result));
+}
+#else
+CPPSPMD_FORCE_INLINE __m128i shuffle_epi8(const __m128i& a, const __m128i& b)
+{
+ return _mm_shuffle_epi8(a, b);
+}
+#endif
+
+#if CPPSPMD_SSE2
+CPPSPMD_FORCE_INLINE __m128i min_epi32(__m128i a, __m128i b)
+{
+ return blendv_mask_epi32(b, a, _mm_cmplt_epi32(a, b));
+}
+CPPSPMD_FORCE_INLINE __m128i max_epi32(__m128i a, __m128i b)
+{
+ return blendv_mask_epi32(b, a, _mm_cmpgt_epi32(a, b));
+}
+CPPSPMD_FORCE_INLINE __m128i min_epu32(__m128i a, __m128i b)
+{
+ __m128i n = _mm_set1_epi32(0x80000000);
+ __m128i ac = _mm_add_epi32(a, n);
+ __m128i bc = _mm_add_epi32(b, n);
+ return blendv_mask_epi32(b, a, _mm_cmplt_epi32(ac, bc));
+}
+CPPSPMD_FORCE_INLINE __m128i max_epu32(__m128i a, __m128i b)
+{
+ __m128i n = _mm_set1_epi32(0x80000000);
+ __m128i ac = _mm_add_epi32(a, n);
+ __m128i bc = _mm_add_epi32(b, n);
+ return blendv_mask_epi32(b, a, _mm_cmpgt_epi32(ac, bc));
+}
+#else
+CPPSPMD_FORCE_INLINE __m128i min_epi32(__m128i a, __m128i b)
+{
+ return _mm_min_epi32(a, b);
+}
+CPPSPMD_FORCE_INLINE __m128i max_epi32(__m128i a, __m128i b)
+{
+ return _mm_max_epi32(a, b);
+}
+CPPSPMD_FORCE_INLINE __m128i min_epu32(__m128i a, __m128i b)
+{
+ return _mm_min_epu32(a, b);
+}
+CPPSPMD_FORCE_INLINE __m128i max_epu32(__m128i a, __m128i b)
+{
+ return _mm_max_epu32(a, b);
+}
+#endif
+
+#if CPPSPMD_SSE2
+CPPSPMD_FORCE_INLINE __m128i abs_epi32(__m128i a)
+{
+ __m128i sign_mask = _mm_srai_epi32(a, 31);
+ return _mm_sub_epi32(_mm_castps_si128(_mm_xor_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(sign_mask))), sign_mask);
+}
+#else
+CPPSPMD_FORCE_INLINE __m128i abs_epi32(__m128i a)
+{
+ return _mm_abs_epi32(a);
+}
+#endif
+
+#if CPPSPMD_SSE2
+CPPSPMD_FORCE_INLINE __m128i mullo_epi32(__m128i a, __m128i b)
+{
+ __m128i tmp1 = _mm_mul_epu32(a, b);
+ __m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(a, 4), _mm_srli_si128(b, 4));
+ return _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0)));
+}
+#else
+CPPSPMD_FORCE_INLINE __m128i mullo_epi32(__m128i a, __m128i b)
+{
+ return _mm_mullo_epi32(a, b);
+}
+#endif
+
+CPPSPMD_FORCE_INLINE __m128i mulhi_epu32(__m128i a, __m128i b)
+{
+ __m128i tmp1 = _mm_mul_epu32(a, b);
+ __m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(a, 4), _mm_srli_si128(b, 4));
+ return _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 3, 1)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 3, 1)));
+}
+
+#if CPPSPMD_SSE2
+inline __m128i load_rgba32(const void* p)
+{
+ __m128i xmm = _mm_cvtsi32_si128(*(const int*)p);
+ xmm = _mm_unpacklo_epi8(xmm, _mm_setzero_si128());
+ xmm = _mm_unpacklo_epi16(xmm, _mm_setzero_si128());
+ return xmm;
+}
+#else
+inline __m128i load_rgba32(const void* p)
+{
+ return _mm_cvtepu8_epi32(_mm_castps_si128(_mm_load_ss((const float*)p)));
+}
+#endif
+
+inline void transpose4x4(__m128i& x, __m128i& y, __m128i& z, __m128i& w, const __m128i& r0, const __m128i& r1, const __m128i& r2, const __m128i& r3)
+{
+ __m128i t0 = _mm_unpacklo_epi32(r0, r1);
+ __m128i t1 = _mm_unpacklo_epi32(r2, r3);
+ __m128i t2 = _mm_unpackhi_epi32(r0, r1);
+ __m128i t3 = _mm_unpackhi_epi32(r2, r3);
+ x = _mm_unpacklo_epi64(t0, t1);
+ y = _mm_unpackhi_epi64(t0, t1);
+ z = _mm_unpacklo_epi64(t2, t3);
+ w = _mm_unpackhi_epi64(t2, t3);
+}
+
+const uint32_t ALL_ON_MOVEMASK = 0xF;
+
+struct spmd_kernel
+{
+ struct vint;
+ struct lint;
+ struct vbool;
+ struct vfloat;
+
+ typedef int int_t;
+ typedef vint vint_t;
+ typedef lint lint_t;
+
+ // Exec mask
+ struct exec_mask
+ {
+ __m128i m_mask;
+
+ exec_mask() = default;
+
+ CPPSPMD_FORCE_INLINE explicit exec_mask(const vbool& b);
+ CPPSPMD_FORCE_INLINE explicit exec_mask(const __m128i& mask) : m_mask(mask) { }
+
+ CPPSPMD_FORCE_INLINE void enable_lane(uint32_t lane) { m_mask = _mm_load_si128((const __m128i *)&g_lane_masks_128[lane][0]); }
+
+ static CPPSPMD_FORCE_INLINE exec_mask all_on() { return exec_mask{ _mm_load_si128((const __m128i*)g_allones_128) }; }
+ static CPPSPMD_FORCE_INLINE exec_mask all_off() { return exec_mask{ _mm_setzero_si128() }; }
+
+ CPPSPMD_FORCE_INLINE uint32_t get_movemask() const { return _mm_movemask_ps(_mm_castsi128_ps(m_mask)); }
+ };
+
+ friend CPPSPMD_FORCE_INLINE bool all(const exec_mask& e);
+ friend CPPSPMD_FORCE_INLINE bool any(const exec_mask& e);
+
+ CPPSPMD_FORCE_INLINE bool spmd_all() const { return all(m_exec); }
+ CPPSPMD_FORCE_INLINE bool spmd_any() const { return any(m_exec); }
+ CPPSPMD_FORCE_INLINE bool spmd_none() { return !any(m_exec); }
+
+ // true if cond is true for all active lanes - false if no active lanes
+ CPPSPMD_FORCE_INLINE bool spmd_all(const vbool& e) { uint32_t m = m_exec.get_movemask(); return (m != 0) && ((exec_mask(e) & m_exec).get_movemask() == m); }
+ // true if cond is true for any active lanes
+ CPPSPMD_FORCE_INLINE bool spmd_any(const vbool& e) { return (exec_mask(e) & m_exec).get_movemask() != 0; }
+ CPPSPMD_FORCE_INLINE bool spmd_none(const vbool& e) { return !spmd_any(e); }
+
+ friend CPPSPMD_FORCE_INLINE exec_mask operator^ (const exec_mask& a, const exec_mask& b);
+ friend CPPSPMD_FORCE_INLINE exec_mask operator& (const exec_mask& a, const exec_mask& b);
+ friend CPPSPMD_FORCE_INLINE exec_mask operator| (const exec_mask& a, const exec_mask& b);
+
+ exec_mask m_exec;
+ exec_mask m_kernel_exec;
+ exec_mask m_continue_mask;
+#ifdef _DEBUG
+ bool m_in_loop;
+#endif
+
+ CPPSPMD_FORCE_INLINE uint32_t get_movemask() const { return m_exec.get_movemask(); }
+
+ void init(const exec_mask& kernel_exec);
+
+ // Varying bool
+
+ struct vbool
+ {
+ __m128i m_value;
+
+ vbool() = default;
+
+ CPPSPMD_FORCE_INLINE vbool(bool value) : m_value(_mm_set1_epi32(value ? UINT32_MAX : 0)) { }
+
+ CPPSPMD_FORCE_INLINE explicit vbool(const __m128i& value) : m_value(value) { }
+
+ CPPSPMD_FORCE_INLINE explicit operator vfloat() const;
+ CPPSPMD_FORCE_INLINE explicit operator vint() const;
+
+ private:
+ vbool& operator=(const vbool&);
+ };
+
+ friend vbool operator!(const vbool& v);
+
+ CPPSPMD_FORCE_INLINE vbool& store(vbool& dst, const vbool& src)
+ {
+ dst.m_value = blendv_mask_epi32(dst.m_value, src.m_value, m_exec.m_mask);
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vbool& store_all(vbool& dst, const vbool& src)
+ {
+ dst.m_value = src.m_value;
+ return dst;
+ }
+
+ // Varying float
+ struct vfloat
+ {
+ __m128 m_value;
+
+ vfloat() = default;
+
+ CPPSPMD_FORCE_INLINE explicit vfloat(const __m128& v) : m_value(v) { }
+
+ CPPSPMD_FORCE_INLINE vfloat(float value) : m_value(_mm_set1_ps(value)) { }
+
+ CPPSPMD_FORCE_INLINE explicit vfloat(int value) : m_value(_mm_set1_ps((float)value)) { }
+
+ private:
+ vfloat& operator=(const vfloat&);
+ };
+
+ CPPSPMD_FORCE_INLINE vfloat& store(vfloat& dst, const vfloat& src)
+ {
+ dst.m_value = blendv_mask_ps(dst.m_value, src.m_value, _mm_castsi128_ps(m_exec.m_mask));
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat& store(vfloat&& dst, const vfloat& src)
+ {
+ dst.m_value = blendv_mask_ps(dst.m_value, src.m_value, _mm_castsi128_ps(m_exec.m_mask));
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat& store_all(vfloat& dst, const vfloat& src)
+ {
+ dst.m_value = src.m_value;
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat& store_all(vfloat&& dst, const vfloat& src)
+ {
+ dst.m_value = src.m_value;
+ return dst;
+ }
+
+ // Linear ref to floats
+ struct float_lref
+ {
+ float* m_pValue;
+
+ private:
+ float_lref& operator=(const float_lref&);
+ };
+
+ CPPSPMD_FORCE_INLINE const float_lref& store(const float_lref& dst, const vfloat& src)
+ {
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ if (mask == ALL_ON_MOVEMASK)
+ _mm_storeu_ps(dst.m_pValue, src.m_value);
+ else
+ _mm_storeu_ps(dst.m_pValue, blendv_mask_ps(_mm_loadu_ps(dst.m_pValue), src.m_value, _mm_castsi128_ps(m_exec.m_mask)));
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE const float_lref& store(const float_lref&& dst, const vfloat& src)
+ {
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ if (mask == ALL_ON_MOVEMASK)
+ _mm_storeu_ps(dst.m_pValue, src.m_value);
+ else
+ _mm_storeu_ps(dst.m_pValue, blendv_mask_ps(_mm_loadu_ps(dst.m_pValue), src.m_value, _mm_castsi128_ps(m_exec.m_mask)));
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE const float_lref& store_all(const float_lref& dst, const vfloat& src)
+ {
+ _mm_storeu_ps(dst.m_pValue, src.m_value);
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE const float_lref& store_all(const float_lref&& dst, const vfloat& src)
+ {
+ _mm_storeu_ps(dst.m_pValue, src.m_value);
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat load(const float_lref& src)
+ {
+ return vfloat{ _mm_and_ps(_mm_loadu_ps(src.m_pValue), _mm_castsi128_ps(m_exec.m_mask)) };
+ }
+
+ // Varying ref to floats
+ struct float_vref
+ {
+ __m128i m_vindex;
+ float* m_pValue;
+
+ private:
+ float_vref& operator=(const float_vref&);
+ };
+
+ // Varying ref to varying float
+ struct vfloat_vref
+ {
+ __m128i m_vindex;
+ vfloat* m_pValue;
+
+ private:
+ vfloat_vref& operator=(const vfloat_vref&);
+ };
+
+ // Varying ref to varying int
+ struct vint_vref
+ {
+ __m128i m_vindex;
+ vint* m_pValue;
+
+ private:
+ vint_vref& operator=(const vint_vref&);
+ };
+
+ CPPSPMD_FORCE_INLINE const float_vref& store(const float_vref& dst, const vfloat& src);
+ CPPSPMD_FORCE_INLINE const float_vref& store(const float_vref&& dst, const vfloat& src);
+
+ CPPSPMD_FORCE_INLINE const float_vref& store_all(const float_vref& dst, const vfloat& src);
+ CPPSPMD_FORCE_INLINE const float_vref& store_all(const float_vref&& dst, const vfloat& src);
+
+ CPPSPMD_FORCE_INLINE vfloat load(const float_vref& src)
+ {
+ CPPSPMD_ALIGN(16) int vindex[4];
+ _mm_store_si128((__m128i *)vindex, src.m_vindex);
+
+ CPPSPMD_ALIGN(16) float loaded[4];
+
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ for (int i = 0; i < 4; i++)
+ {
+ if (mask & (1 << i))
+ loaded[i] = src.m_pValue[vindex[i]];
+ }
+ return vfloat{ _mm_and_ps(_mm_castsi128_ps(m_exec.m_mask), _mm_load_ps((const float*)loaded)) };
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat load_all(const float_vref& src)
+ {
+ CPPSPMD_ALIGN(16) int vindex[4];
+ _mm_store_si128((__m128i *)vindex, src.m_vindex);
+
+ CPPSPMD_ALIGN(16) float loaded[4];
+
+ for (int i = 0; i < 4; i++)
+ loaded[i] = src.m_pValue[vindex[i]];
+ return vfloat{ _mm_load_ps((const float*)loaded) };
+ }
+
+ // Linear ref to ints
+ struct int_lref
+ {
+ int* m_pValue;
+
+ private:
+ int_lref& operator=(const int_lref&);
+ };
+
+ CPPSPMD_FORCE_INLINE const int_lref& store(const int_lref& dst, const vint& src)
+ {
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ if (mask == ALL_ON_MOVEMASK)
+ {
+ _mm_storeu_si128((__m128i *)dst.m_pValue, src.m_value);
+ }
+ else
+ {
+ CPPSPMD_ALIGN(16) int stored[4];
+ _mm_store_si128((__m128i *)stored, src.m_value);
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (mask & (1 << i))
+ dst.m_pValue[i] = stored[i];
+ }
+ }
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vint load(const int_lref& src)
+ {
+ __m128i v = _mm_loadu_si128((const __m128i*)src.m_pValue);
+
+ v = _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(v), _mm_castsi128_ps(m_exec.m_mask)));
+
+ return vint{ v };
+ }
+
+ // Linear ref to int16's
+ struct int16_lref
+ {
+ int16_t* m_pValue;
+
+ private:
+ int16_lref& operator=(const int16_lref&);
+ };
+
+ CPPSPMD_FORCE_INLINE const int16_lref& store(const int16_lref& dst, const vint& src)
+ {
+ CPPSPMD_ALIGN(16) int stored[4];
+ _mm_store_si128((__m128i *)stored, src.m_value);
+
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ for (int i = 0; i < 4; i++)
+ {
+ if (mask & (1 << i))
+ dst.m_pValue[i] = static_cast<int16_t>(stored[i]);
+ }
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE const int16_lref& store_all(const int16_lref& dst, const vint& src)
+ {
+ CPPSPMD_ALIGN(16) int stored[4];
+ _mm_store_si128((__m128i *)stored, src.m_value);
+
+ for (int i = 0; i < 4; i++)
+ dst.m_pValue[i] = static_cast<int16_t>(stored[i]);
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vint load(const int16_lref& src)
+ {
+ CPPSPMD_ALIGN(16) int values[4];
+
+ for (int i = 0; i < 4; i++)
+ values[i] = static_cast<int16_t>(src.m_pValue[i]);
+
+ __m128i t = _mm_load_si128( (const __m128i *)values );
+
+ return vint{ _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps( t ), _mm_castsi128_ps(m_exec.m_mask))) };
+ }
+
+ CPPSPMD_FORCE_INLINE vint load_all(const int16_lref& src)
+ {
+ CPPSPMD_ALIGN(16) int values[4];
+
+ for (int i = 0; i < 4; i++)
+ values[i] = static_cast<int16_t>(src.m_pValue[i]);
+
+ __m128i t = _mm_load_si128( (const __m128i *)values );
+
+ return vint{ t };
+ }
+
+ // Linear ref to constant ints
+ struct cint_lref
+ {
+ const int* m_pValue;
+
+ private:
+ cint_lref& operator=(const cint_lref&);
+ };
+
+ CPPSPMD_FORCE_INLINE vint load(const cint_lref& src)
+ {
+ __m128i v = _mm_loadu_si128((const __m128i *)src.m_pValue);
+ v = _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(v), _mm_castsi128_ps(m_exec.m_mask)));
+ return vint{ v };
+ }
+
+ CPPSPMD_FORCE_INLINE vint load_all(const cint_lref& src)
+ {
+ return vint{ _mm_loadu_si128((const __m128i *)src.m_pValue) };
+ }
+
+ // Varying ref to ints
+ struct int_vref
+ {
+ __m128i m_vindex;
+ int* m_pValue;
+
+ private:
+ int_vref& operator=(const int_vref&);
+ };
+
+ // Varying ref to constant ints
+ struct cint_vref
+ {
+ __m128i m_vindex;
+ const int* m_pValue;
+
+ private:
+ cint_vref& operator=(const cint_vref&);
+ };
+
+ // Varying int
+ struct vint
+ {
+ __m128i m_value;
+
+ vint() = default;
+
+ CPPSPMD_FORCE_INLINE explicit vint(const __m128i& value) : m_value(value) { }
+
+ CPPSPMD_FORCE_INLINE explicit vint(const lint &other) : m_value(other.m_value) { }
+
+ CPPSPMD_FORCE_INLINE vint& operator=(const lint& other) { m_value = other.m_value; return *this; }
+
+ CPPSPMD_FORCE_INLINE vint(int value) : m_value(_mm_set1_epi32(value)) { }
+
+ CPPSPMD_FORCE_INLINE explicit vint(float value) : m_value(_mm_set1_epi32((int)value)) { }
+
+ CPPSPMD_FORCE_INLINE explicit vint(const vfloat& other) : m_value(_mm_cvttps_epi32(other.m_value)) { }
+
+ CPPSPMD_FORCE_INLINE explicit operator vbool() const
+ {
+ return vbool{ _mm_xor_si128( _mm_load_si128((const __m128i*)g_allones_128), _mm_cmpeq_epi32(m_value, _mm_setzero_si128())) };
+ }
+
+ CPPSPMD_FORCE_INLINE explicit operator vfloat() const
+ {
+ return vfloat{ _mm_cvtepi32_ps(m_value) };
+ }
+
+ CPPSPMD_FORCE_INLINE int_vref operator[](int* ptr) const
+ {
+ return int_vref{ m_value, ptr };
+ }
+
+ CPPSPMD_FORCE_INLINE cint_vref operator[](const int* ptr) const
+ {
+ return cint_vref{ m_value, ptr };
+ }
+
+ CPPSPMD_FORCE_INLINE float_vref operator[](float* ptr) const
+ {
+ return float_vref{ m_value, ptr };
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat_vref operator[](vfloat* ptr) const
+ {
+ return vfloat_vref{ m_value, ptr };
+ }
+
+ CPPSPMD_FORCE_INLINE vint_vref operator[](vint* ptr) const
+ {
+ return vint_vref{ m_value, ptr };
+ }
+
+ private:
+ vint& operator=(const vint&);
+ };
+
+ // Load/store linear int
+ CPPSPMD_FORCE_INLINE void storeu_linear(int *pDst, const vint& src)
+ {
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ if (mask == ALL_ON_MOVEMASK)
+ _mm_storeu_si128((__m128i *)pDst, src.m_value);
+ else
+ {
+ if (mask & 1) pDst[0] = extract_x(src.m_value);
+ if (mask & 2) pDst[1] = extract_y(src.m_value);
+ if (mask & 4) pDst[2] = extract_z(src.m_value);
+ if (mask & 8) pDst[3] = extract_w(src.m_value);
+ }
+ }
+
+ CPPSPMD_FORCE_INLINE void storeu_linear_all(int *pDst, const vint& src)
+ {
+ _mm_storeu_si128((__m128i*)pDst, src.m_value);
+ }
+
+ CPPSPMD_FORCE_INLINE void store_linear_all(int *pDst, const vint& src)
+ {
+ _mm_store_si128((__m128i*)pDst, src.m_value);
+ }
+
+ CPPSPMD_FORCE_INLINE vint loadu_linear(const int *pSrc)
+ {
+ __m128i v = _mm_loadu_si128((const __m128i*)pSrc);
+
+ v = _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(v), _mm_castsi128_ps(m_exec.m_mask)));
+
+ return vint{ v };
+ }
+
+ CPPSPMD_FORCE_INLINE vint loadu_linear_all(const int *pSrc)
+ {
+ return vint{ _mm_loadu_si128((__m128i*)pSrc) };
+ }
+
+ CPPSPMD_FORCE_INLINE vint load_linear_all(const int *pSrc)
+ {
+ return vint{ _mm_load_si128((__m128i*)pSrc) };
+ }
+
+ // Load/store linear float
+ CPPSPMD_FORCE_INLINE void storeu_linear(float *pDst, const vfloat& src)
+ {
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ if (mask == ALL_ON_MOVEMASK)
+ _mm_storeu_ps((float*)pDst, src.m_value);
+ else
+ {
+ int *pDstI = (int *)pDst;
+ if (mask & 1) pDstI[0] = extract_ps_x(src.m_value);
+ if (mask & 2) pDstI[1] = extract_ps_y(src.m_value);
+ if (mask & 4) pDstI[2] = extract_ps_z(src.m_value);
+ if (mask & 8) pDstI[3] = extract_ps_w(src.m_value);
+ }
+ }
+
+ CPPSPMD_FORCE_INLINE void storeu_linear_all(float *pDst, const vfloat& src)
+ {
+ _mm_storeu_ps((float*)pDst, src.m_value);
+ }
+
+ CPPSPMD_FORCE_INLINE void store_linear_all(float *pDst, const vfloat& src)
+ {
+ _mm_store_ps((float*)pDst, src.m_value);
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat loadu_linear(const float *pSrc)
+ {
+ __m128 v = _mm_loadu_ps((const float*)pSrc);
+
+ v = _mm_and_ps(v, _mm_castsi128_ps(m_exec.m_mask));
+
+ return vfloat{ v };
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat loadu_linear_all(const float *pSrc)
+ {
+ return vfloat{ _mm_loadu_ps((float*)pSrc) };
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat load_linear_all(const float *pSrc)
+ {
+ return vfloat{ _mm_load_ps((float*)pSrc) };
+ }
+
+ CPPSPMD_FORCE_INLINE vint& store(vint& dst, const vint& src)
+ {
+ dst.m_value = blendv_mask_epi32(dst.m_value, src.m_value, m_exec.m_mask);
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE const int_vref& store(const int_vref& dst, const vint& src)
+ {
+ CPPSPMD_ALIGN(16) int vindex[4];
+ _mm_store_si128((__m128i*)vindex, dst.m_vindex);
+
+ CPPSPMD_ALIGN(16) int stored[4];
+ _mm_store_si128((__m128i*)stored, src.m_value);
+
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ for (int i = 0; i < 4; i++)
+ {
+ if (mask & (1 << i))
+ dst.m_pValue[vindex[i]] = stored[i];
+ }
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vint& store_all(vint& dst, const vint& src)
+ {
+ dst.m_value = src.m_value;
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE const int_vref& store_all(const int_vref& dst, const vint& src)
+ {
+ CPPSPMD_ALIGN(16) int vindex[4];
+ _mm_store_si128((__m128i*)vindex, dst.m_vindex);
+
+ CPPSPMD_ALIGN(16) int stored[4];
+ _mm_store_si128((__m128i*)stored, src.m_value);
+
+ for (int i = 0; i < 4; i++)
+ dst.m_pValue[vindex[i]] = stored[i];
+
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vint load(const int_vref& src)
+ {
+ CPPSPMD_ALIGN(16) int values[4];
+
+ CPPSPMD_ALIGN(16) int indices[4];
+ _mm_store_si128((__m128i *)indices, src.m_vindex);
+
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ for (int i = 0; i < 4; i++)
+ {
+ if (mask & (1 << i))
+ values[i] = src.m_pValue[indices[i]];
+ }
+
+ return vint{ _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(m_exec.m_mask), _mm_load_ps((const float*)values))) };
+ }
+
+ CPPSPMD_FORCE_INLINE vint load_all(const int_vref& src)
+ {
+ CPPSPMD_ALIGN(16) int values[4];
+
+ CPPSPMD_ALIGN(16) int indices[4];
+ _mm_store_si128((__m128i *)indices, src.m_vindex);
+
+ for (int i = 0; i < 4; i++)
+ values[i] = src.m_pValue[indices[i]];
+
+ return vint{ _mm_castps_si128( _mm_load_ps((const float*)values)) };
+ }
+
+ CPPSPMD_FORCE_INLINE vint load(const cint_vref& src)
+ {
+ CPPSPMD_ALIGN(16) int values[4];
+
+ CPPSPMD_ALIGN(16) int indices[4];
+ _mm_store_si128((__m128i *)indices, src.m_vindex);
+
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ for (int i = 0; i < 4; i++)
+ {
+ if (mask & (1 << i))
+ values[i] = src.m_pValue[indices[i]];
+ }
+
+ return vint{ _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(m_exec.m_mask), _mm_load_ps((const float*)values))) };
+ }
+
+ CPPSPMD_FORCE_INLINE vint load_all(const cint_vref& src)
+ {
+ CPPSPMD_ALIGN(16) int values[4];
+
+ CPPSPMD_ALIGN(16) int indices[4];
+ _mm_store_si128((__m128i *)indices, src.m_vindex);
+
+ for (int i = 0; i < 4; i++)
+ values[i] = src.m_pValue[indices[i]];
+
+ return vint{ _mm_castps_si128( _mm_load_ps((const float*)values)) };
+ }
+
+ CPPSPMD_FORCE_INLINE vint load_bytes_all(const cint_vref& src)
+ {
+ __m128i v0_l;
+
+ const uint8_t* pSrc = (const uint8_t*)src.m_pValue;
+ v0_l = insert_x(_mm_undefined_si128(), ((int*)(pSrc + extract_x(src.m_vindex)))[0]);
+ v0_l = insert_y(v0_l, ((int*)(pSrc + extract_y(src.m_vindex)))[0]);
+ v0_l = insert_z(v0_l, ((int*)(pSrc + extract_z(src.m_vindex)))[0]);
+ v0_l = insert_w(v0_l, ((int*)(pSrc + extract_w(src.m_vindex)))[0]);
+
+ return vint{ v0_l };
+ }
+
+ CPPSPMD_FORCE_INLINE vint load_words_all(const cint_vref& src)
+ {
+ __m128i v0_l;
+
+ const uint8_t* pSrc = (const uint8_t*)src.m_pValue;
+ v0_l = insert_x(_mm_undefined_si128(), ((int16_t*)(pSrc + 2 * extract_x(src.m_vindex)))[0]);
+ v0_l = insert_y(v0_l, ((int16_t*)(pSrc + 2 * extract_y(src.m_vindex)))[0]);
+ v0_l = insert_z(v0_l, ((int16_t*)(pSrc + 2 * extract_z(src.m_vindex)))[0]);
+ v0_l = insert_w(v0_l, ((int16_t*)(pSrc + 2 * extract_w(src.m_vindex)))[0]);
+
+ return vint{ v0_l };
+ }
+
+ CPPSPMD_FORCE_INLINE void store_strided(int *pDst, uint32_t stride, const vint &v)
+ {
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+
+ if (mask & 1) pDst[0] = extract_x(v.m_value);
+ if (mask & 2) pDst[stride] = extract_y(v.m_value);
+ if (mask & 4) pDst[stride*2] = extract_z(v.m_value);
+ if (mask & 8) pDst[stride*3] = extract_w(v.m_value);
+ }
+
+ CPPSPMD_FORCE_INLINE void store_strided(float *pDstF, uint32_t stride, const vfloat &v)
+ {
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+
+ if (mask & 1) ((int *)pDstF)[0] = extract_ps_x(v.m_value);
+ if (mask & 2) ((int *)pDstF)[stride] = extract_ps_y(v.m_value);
+ if (mask & 4) ((int *)pDstF)[stride*2] = extract_ps_z(v.m_value);
+ if (mask & 8) ((int *)pDstF)[stride*3] = extract_ps_w(v.m_value);
+ }
+
+ CPPSPMD_FORCE_INLINE void store_all_strided(int *pDst, uint32_t stride, const vint &v)
+ {
+ pDst[0] = extract_x(v.m_value);
+ pDst[stride] = extract_y(v.m_value);
+ pDst[stride*2] = extract_z(v.m_value);
+ pDst[stride*3] = extract_w(v.m_value);
+ }
+
+ CPPSPMD_FORCE_INLINE void store_all_strided(float *pDstF, uint32_t stride, const vfloat &v)
+ {
+ ((int *)pDstF)[0] = extract_ps_x(v.m_value);
+ ((int *)pDstF)[stride] = extract_ps_y(v.m_value);
+ ((int *)pDstF)[stride*2] = extract_ps_z(v.m_value);
+ ((int *)pDstF)[stride*3] = extract_ps_w(v.m_value);
+ }
+
+ CPPSPMD_FORCE_INLINE vint load_strided(const int *pSrc, uint32_t stride)
+ {
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+
+#if CPPSPMD_SSE2
+ CPPSPMD_ALIGN(16) int vals[4] = { 0, 0, 0, 0 };
+ if (mask & 1) vals[0] = pSrc[0];
+ if (mask & 2) vals[1] = pSrc[stride];
+ if (mask & 4) vals[2] = pSrc[stride * 2];
+ if (mask & 8) vals[3] = pSrc[stride * 3];
+ return vint{ _mm_load_si128((__m128i*)vals) };
+#else
+ const float* pSrcF = (const float*)pSrc;
+ __m128 v = _mm_setzero_ps();
+ if (mask & 1) v = _mm_load_ss(pSrcF);
+ if (mask & 2) v = _mm_insert_ps(v, _mm_load_ss(pSrcF + stride), 0x10);
+ if (mask & 4) v = _mm_insert_ps(v, _mm_load_ss(pSrcF + 2 * stride), 0x20);
+ if (mask & 8) v = _mm_insert_ps(v, _mm_load_ss(pSrcF + 3 * stride), 0x30);
+ return vint{ _mm_castps_si128(v) };
+#endif
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat load_strided(const float *pSrc, uint32_t stride)
+ {
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+
+#if CPPSPMD_SSE2
+ CPPSPMD_ALIGN(16) float vals[4] = { 0, 0, 0, 0 };
+ if (mask & 1) vals[0] = pSrc[0];
+ if (mask & 2) vals[1] = pSrc[stride];
+ if (mask & 4) vals[2] = pSrc[stride * 2];
+ if (mask & 8) vals[3] = pSrc[stride * 3];
+ return vfloat{ _mm_load_ps(vals) };
+#else
+ __m128 v = _mm_setzero_ps();
+ if (mask & 1) v = _mm_load_ss(pSrc);
+ if (mask & 2) v = _mm_insert_ps(v, _mm_load_ss(pSrc + stride), 0x10);
+ if (mask & 4) v = _mm_insert_ps(v, _mm_load_ss(pSrc + 2 * stride), 0x20);
+ if (mask & 8) v = _mm_insert_ps(v, _mm_load_ss(pSrc + 3 * stride), 0x30);
+ return vfloat{ v };
+#endif
+ }
+
+ CPPSPMD_FORCE_INLINE vint load_all_strided(const int *pSrc, uint32_t stride)
+ {
+#if CPPSPMD_SSE2
+ CPPSPMD_ALIGN(16) int vals[4];
+ vals[0] = pSrc[0];
+ vals[1] = pSrc[stride];
+ vals[2] = pSrc[stride * 2];
+ vals[3] = pSrc[stride * 3];
+ return vint{ _mm_load_si128((__m128i*)vals) };
+#else
+ const float* pSrcF = (const float*)pSrc;
+ __m128 v = _mm_load_ss(pSrcF);
+ v = _mm_insert_ps(v, _mm_load_ss(pSrcF + stride), 0x10);
+ v = _mm_insert_ps(v, _mm_load_ss(pSrcF + 2 * stride), 0x20);
+ v = _mm_insert_ps(v, _mm_load_ss(pSrcF + 3 * stride), 0x30);
+ return vint{ _mm_castps_si128(v) };
+#endif
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat load_all_strided(const float *pSrc, uint32_t stride)
+ {
+#if CPPSPMD_SSE2
+ CPPSPMD_ALIGN(16) float vals[4];
+ vals[0] = pSrc[0];
+ vals[1] = pSrc[stride];
+ vals[2] = pSrc[stride * 2];
+ vals[3] = pSrc[stride * 3];
+ return vfloat{ _mm_load_ps(vals) };
+#else
+ __m128 v = _mm_load_ss(pSrc);
+ v = _mm_insert_ps(v, _mm_load_ss(pSrc + stride), 0x10);
+ v = _mm_insert_ps(v, _mm_load_ss(pSrc + 2 * stride), 0x20);
+ v = _mm_insert_ps(v, _mm_load_ss(pSrc + 3 * stride), 0x30);
+ return vfloat{ v };
+#endif
+ }
+
+ CPPSPMD_FORCE_INLINE const vfloat_vref& store(const vfloat_vref& dst, const vfloat& src)
+ {
+ // TODO: There's surely a better way
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+
+ if (mask & 1) ((int *)(&dst.m_pValue[extract_x(dst.m_vindex)]))[0] = extract_x(_mm_castps_si128(src.m_value));
+ if (mask & 2) ((int *)(&dst.m_pValue[extract_y(dst.m_vindex)]))[1] = extract_y(_mm_castps_si128(src.m_value));
+ if (mask & 4) ((int *)(&dst.m_pValue[extract_z(dst.m_vindex)]))[2] = extract_z(_mm_castps_si128(src.m_value));
+ if (mask & 8) ((int *)(&dst.m_pValue[extract_w(dst.m_vindex)]))[3] = extract_w(_mm_castps_si128(src.m_value));
+
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vfloat load(const vfloat_vref& src)
+ {
+ // TODO: There's surely a better way
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+
+ __m128i k = _mm_setzero_si128();
+
+ if (mask & 1) k = insert_x(k, ((int *)(&src.m_pValue[extract_x(src.m_vindex)]))[0]);
+ if (mask & 2) k = insert_y(k, ((int *)(&src.m_pValue[extract_y(src.m_vindex)]))[1]);
+ if (mask & 4) k = insert_z(k, ((int *)(&src.m_pValue[extract_z(src.m_vindex)]))[2]);
+ if (mask & 8) k = insert_w(k, ((int *)(&src.m_pValue[extract_w(src.m_vindex)]))[3]);
+
+ return vfloat{ _mm_castsi128_ps(k) };
+ }
+
+ CPPSPMD_FORCE_INLINE const vint_vref& store(const vint_vref& dst, const vint& src)
+ {
+ // TODO: There's surely a better way
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+
+ if (mask & 1) ((int *)(&dst.m_pValue[extract_x(dst.m_vindex)]))[0] = extract_x(src.m_value);
+ if (mask & 2) ((int *)(&dst.m_pValue[extract_y(dst.m_vindex)]))[1] = extract_y(src.m_value);
+ if (mask & 4) ((int *)(&dst.m_pValue[extract_z(dst.m_vindex)]))[2] = extract_z(src.m_value);
+ if (mask & 8) ((int *)(&dst.m_pValue[extract_w(dst.m_vindex)]))[3] = extract_w(src.m_value);
+
+ return dst;
+ }
+
+ CPPSPMD_FORCE_INLINE vint load(const vint_vref& src)
+ {
+ // TODO: There's surely a better way
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+
+ __m128i k = _mm_setzero_si128();
+
+ if (mask & 1) k = insert_x(k, ((int *)(&src.m_pValue[extract_x(src.m_vindex)]))[0]);
+ if (mask & 2) k = insert_y(k, ((int *)(&src.m_pValue[extract_y(src.m_vindex)]))[1]);
+ if (mask & 4) k = insert_z(k, ((int *)(&src.m_pValue[extract_z(src.m_vindex)]))[2]);
+ if (mask & 8) k = insert_w(k, ((int *)(&src.m_pValue[extract_w(src.m_vindex)]))[3]);
+
+ return vint{ k };
+ }
+
+ CPPSPMD_FORCE_INLINE vint load_all(const vint_vref& src)
+ {
+ // TODO: There's surely a better way
+ __m128i k;
+
+ k = insert_x(k, ((int*)(&src.m_pValue[extract_x(src.m_vindex)]))[0]);
+ k = insert_y(k, ((int*)(&src.m_pValue[extract_y(src.m_vindex)]))[1]);
+ k = insert_z(k, ((int*)(&src.m_pValue[extract_z(src.m_vindex)]))[2]);
+ k = insert_w(k, ((int*)(&src.m_pValue[extract_w(src.m_vindex)]))[3]);
+
+ return vint{ k };
+ }
+
+ // Linear integer
+ struct lint
+ {
+ __m128i m_value;
+
+ CPPSPMD_FORCE_INLINE explicit lint(__m128i value)
+ : m_value(value)
+ { }
+
+ CPPSPMD_FORCE_INLINE explicit operator vfloat() const
+ {
+ return vfloat{ _mm_cvtepi32_ps(m_value) };
+ }
+
+ CPPSPMD_FORCE_INLINE explicit operator vint() const
+ {
+ return vint{ m_value };
+ }
+
+ CPPSPMD_FORCE_INLINE int get_first_value() const
+ {
+ return _mm_cvtsi128_si32(m_value);
+ }
+
+ CPPSPMD_FORCE_INLINE float_lref operator[](float* ptr) const
+ {
+ return float_lref{ ptr + get_first_value() };
+ }
+
+ CPPSPMD_FORCE_INLINE int_lref operator[](int* ptr) const
+ {
+ return int_lref{ ptr + get_first_value() };
+ }
+
+ CPPSPMD_FORCE_INLINE int16_lref operator[](int16_t* ptr) const
+ {
+ return int16_lref{ ptr + get_first_value() };
+ }
+
+ CPPSPMD_FORCE_INLINE cint_lref operator[](const int* ptr) const
+ {
+ return cint_lref{ ptr + get_first_value() };
+ }
+
+ private:
+ lint& operator=(const lint&);
+ };
+
+ CPPSPMD_FORCE_INLINE lint& store_all(lint& dst, const lint& src)
+ {
+ dst.m_value = src.m_value;
+ return dst;
+ }
+
+ const lint program_index = lint{ _mm_set_epi32( 3, 2, 1, 0 ) };
+
+ // SPMD condition helpers
+
+ template<typename IfBody>
+ CPPSPMD_FORCE_INLINE void spmd_if(const vbool& cond, const IfBody& ifBody);
+
+ CPPSPMD_FORCE_INLINE void spmd_if_break(const vbool& cond);
+
+ // No breaks, continues, etc. allowed
+ template<typename IfBody>
+ CPPSPMD_FORCE_INLINE void spmd_sif(const vbool& cond, const IfBody& ifBody);
+
+ // No breaks, continues, etc. allowed
+ template<typename IfBody, typename ElseBody>
+ CPPSPMD_FORCE_INLINE void spmd_sifelse(const vbool& cond, const IfBody& ifBody, const ElseBody &elseBody);
+
+ template<typename IfBody, typename ElseBody>
+ CPPSPMD_FORCE_INLINE void spmd_ifelse(const vbool& cond, const IfBody& ifBody, const ElseBody& elseBody);
+
+ template<typename WhileCondBody, typename WhileBody>
+ CPPSPMD_FORCE_INLINE void spmd_while(const WhileCondBody& whileCondBody, const WhileBody& whileBody);
+
+ template<typename ForInitBody, typename ForCondBody, typename ForIncrBody, typename ForBody>
+ CPPSPMD_FORCE_INLINE void spmd_for(const ForInitBody& forInitBody, const ForCondBody& forCondBody, const ForIncrBody& forIncrBody, const ForBody& forBody);
+
+ template<typename ForeachBody>
+ CPPSPMD_FORCE_INLINE void spmd_foreach(int begin, int end, const ForeachBody& foreachBody);
+
+#ifdef _DEBUG
+ CPPSPMD_FORCE_INLINE void check_masks();
+#else
+ CPPSPMD_FORCE_INLINE void check_masks() { }
+#endif
+
+ CPPSPMD_FORCE_INLINE void spmd_break();
+ CPPSPMD_FORCE_INLINE void spmd_continue();
+
+ CPPSPMD_FORCE_INLINE void spmd_return();
+
+ template<typename UnmaskedBody>
+ CPPSPMD_FORCE_INLINE void spmd_unmasked(const UnmaskedBody& unmaskedBody);
+
+ template<typename SPMDKernel, typename... Args>
+ //CPPSPMD_FORCE_INLINE decltype(auto) spmd_call(Args&&... args);
+ CPPSPMD_FORCE_INLINE void spmd_call(Args&&... args);
+
+ CPPSPMD_FORCE_INLINE void swap(vint &a, vint &b) { vint temp = a; store(a, b); store(b, temp); }
+ CPPSPMD_FORCE_INLINE void swap(vfloat &a, vfloat &b) { vfloat temp = a; store(a, b); store(b, temp); }
+ CPPSPMD_FORCE_INLINE void swap(vbool &a, vbool &b) { vbool temp = a; store(a, b); store(b, temp); }
+
+ CPPSPMD_FORCE_INLINE float reduce_add(vfloat v)
+ {
+ __m128 k3210 = _mm_castsi128_ps(blendv_mask_epi32(_mm_setzero_si128(), _mm_castps_si128(v.m_value), m_exec.m_mask));
+
+//#if CPPSPMD_SSE2
+#if 1
+ // See https://stackoverflow.com/questions/6996764/fastest-way-to-do-horizontal-sse-vector-sum-or-other-reduction/35270026#35270026
+ __m128 shuf = _mm_shuffle_ps(k3210, k3210, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128 sums = _mm_add_ps(k3210, shuf);
+ shuf = _mm_movehl_ps(shuf, sums);
+ sums = _mm_add_ss(sums, shuf);
+ return _mm_cvtss_f32(sums);
+#else
+ // This is pretty slow.
+ __m128 a = _mm_hadd_ps(k3210, k3210);
+ __m128 b = _mm_hadd_ps(a, a);
+ return extractf_ps_x(b);
+#endif
+ }
+
+ CPPSPMD_FORCE_INLINE int reduce_add(vint v)
+ {
+ __m128i k3210 = blendv_mask_epi32(_mm_setzero_si128(), v.m_value, m_exec.m_mask);
+
+ // See https://stackoverflow.com/questions/6996764/fastest-way-to-do-horizontal-sse-vector-sum-or-other-reduction/35270026#35270026
+ __m128i shuf = _mm_shuffle_epi32(k3210, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i sums = _mm_add_epi32(k3210, shuf);
+ shuf = _mm_castps_si128(_mm_movehl_ps(_mm_castsi128_ps(shuf), _mm_castsi128_ps(sums)));
+ sums = _mm_add_epi32(sums, shuf);
+ return extract_x(sums);
+ }
+
+ #include "cppspmd_math_declares.h"
+
+}; // struct spmd_kernel
+
+using exec_mask = spmd_kernel::exec_mask;
+using vint = spmd_kernel::vint;
+using int_lref = spmd_kernel::int_lref;
+using cint_vref = spmd_kernel::cint_vref;
+using cint_lref = spmd_kernel::cint_lref;
+using int_vref = spmd_kernel::int_vref;
+using lint = spmd_kernel::lint;
+using vbool = spmd_kernel::vbool;
+using vfloat = spmd_kernel::vfloat;
+using float_lref = spmd_kernel::float_lref;
+using float_vref = spmd_kernel::float_vref;
+using vfloat_vref = spmd_kernel::vfloat_vref;
+using vint_vref = spmd_kernel::vint_vref;
+
+CPPSPMD_FORCE_INLINE spmd_kernel::vbool::operator vfloat() const
+{
+ return vfloat { _mm_and_ps( _mm_castsi128_ps(m_value), *(const __m128 *)g_onef_128 ) };
+}
+
+// Returns UINT32_MAX's for true, 0 for false. (Should it return 1's?)
+CPPSPMD_FORCE_INLINE spmd_kernel::vbool::operator vint() const
+{
+ return vint { m_value };
+}
+
+CPPSPMD_FORCE_INLINE vbool operator!(const vbool& v)
+{
+ return vbool{ _mm_castps_si128(_mm_xor_ps(_mm_load_ps((const float*)g_allones_128), _mm_castsi128_ps(v.m_value))) };
+}
+
+CPPSPMD_FORCE_INLINE exec_mask::exec_mask(const vbool& b) { m_mask = b.m_value; }
+
+CPPSPMD_FORCE_INLINE exec_mask operator^(const exec_mask& a, const exec_mask& b) { return exec_mask{ _mm_xor_si128(a.m_mask, b.m_mask) }; }
+CPPSPMD_FORCE_INLINE exec_mask operator&(const exec_mask& a, const exec_mask& b) { return exec_mask{ _mm_and_si128(a.m_mask, b.m_mask) }; }
+CPPSPMD_FORCE_INLINE exec_mask operator|(const exec_mask& a, const exec_mask& b) { return exec_mask{ _mm_or_si128(a.m_mask, b.m_mask) }; }
+
+CPPSPMD_FORCE_INLINE bool all(const exec_mask& e) { return _mm_movemask_ps(_mm_castsi128_ps(e.m_mask)) == ALL_ON_MOVEMASK; }
+CPPSPMD_FORCE_INLINE bool any(const exec_mask& e) { return _mm_movemask_ps(_mm_castsi128_ps(e.m_mask)) != 0; }
+
+// Bad pattern - doesn't factor in the current exec mask. Prefer spmd_any() instead.
+CPPSPMD_FORCE_INLINE bool all(const vbool& e) { return _mm_movemask_ps(_mm_castsi128_ps(e.m_value)) == ALL_ON_MOVEMASK; }
+CPPSPMD_FORCE_INLINE bool any(const vbool& e) { return _mm_movemask_ps(_mm_castsi128_ps(e.m_value)) != 0; }
+
+CPPSPMD_FORCE_INLINE exec_mask andnot(const exec_mask& a, const exec_mask& b) { return exec_mask{ _mm_andnot_si128(a.m_mask, b.m_mask) }; }
+CPPSPMD_FORCE_INLINE vbool operator||(const vbool& a, const vbool& b) { return vbool{ _mm_or_si128(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vbool operator&&(const vbool& a, const vbool& b) { return vbool{ _mm_and_si128(a.m_value, b.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vfloat operator+(const vfloat& a, const vfloat& b) { return vfloat{ _mm_add_ps(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vfloat operator-(const vfloat& a, const vfloat& b) { return vfloat{ _mm_sub_ps(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vfloat operator+(float a, const vfloat& b) { return vfloat(a) + b; }
+CPPSPMD_FORCE_INLINE vfloat operator+(const vfloat& a, float b) { return a + vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator-(const vfloat& a, const vint& b) { return a - vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator-(const vint& a, const vfloat& b) { return vfloat(a) - b; }
+CPPSPMD_FORCE_INLINE vfloat operator-(const vfloat& a, int b) { return a - vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator-(int a, const vfloat& b) { return vfloat(a) - b; }
+CPPSPMD_FORCE_INLINE vfloat operator-(const vfloat& a, float b) { return a - vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator-(float a, const vfloat& b) { return vfloat(a) - b; }
+
+CPPSPMD_FORCE_INLINE vfloat operator*(const vfloat& a, const vfloat& b) { return vfloat{ _mm_mul_ps(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vfloat operator*(const vfloat& a, float b) { return a * vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator*(float a, const vfloat& b) { return vfloat(a) * b; }
+CPPSPMD_FORCE_INLINE vfloat operator*(const vfloat& a, int b) { return a * vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator*(int a, const vfloat& b) { return vfloat(a) * b; }
+
+CPPSPMD_FORCE_INLINE vfloat operator/(const vfloat& a, const vfloat& b) { return vfloat{ _mm_div_ps(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vfloat operator/(const vfloat& a, int b) { return a / vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator/(int a, const vfloat& b) { return vfloat(a) / b; }
+CPPSPMD_FORCE_INLINE vfloat operator/(const vfloat& a, float b) { return a / vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator/(float a, const vfloat& b) { return vfloat(a) / b; }
+CPPSPMD_FORCE_INLINE vfloat operator-(const vfloat& v) { return vfloat{ _mm_sub_ps(_mm_xor_ps(v.m_value, v.m_value), v.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vbool operator==(const vfloat& a, const vfloat& b) { return vbool{ _mm_castps_si128(_mm_cmpeq_ps(a.m_value, b.m_value)) }; }
+CPPSPMD_FORCE_INLINE vbool operator==(const vfloat& a, float b) { return a == vfloat(b); }
+
+CPPSPMD_FORCE_INLINE vbool operator!=(const vfloat& a, const vfloat& b) { return !vbool{ _mm_castps_si128(_mm_cmpeq_ps(a.m_value, b.m_value)) }; }
+CPPSPMD_FORCE_INLINE vbool operator!=(const vfloat& a, float b) { return a != vfloat(b); }
+
+CPPSPMD_FORCE_INLINE vbool operator<(const vfloat& a, const vfloat& b) { return vbool{ _mm_castps_si128(_mm_cmplt_ps(a.m_value, b.m_value)) }; }
+CPPSPMD_FORCE_INLINE vbool operator<(const vfloat& a, float b) { return a < vfloat(b); }
+
+CPPSPMD_FORCE_INLINE vbool operator>(const vfloat& a, const vfloat& b) { return vbool{ _mm_castps_si128(_mm_cmpgt_ps(a.m_value, b.m_value)) }; }
+CPPSPMD_FORCE_INLINE vbool operator>(const vfloat& a, float b) { return a > vfloat(b); }
+
+CPPSPMD_FORCE_INLINE vbool operator<=(const vfloat& a, const vfloat& b) { return vbool{ _mm_castps_si128(_mm_cmple_ps(a.m_value, b.m_value)) }; }
+CPPSPMD_FORCE_INLINE vbool operator<=(const vfloat& a, float b) { return a <= vfloat(b); }
+
+CPPSPMD_FORCE_INLINE vbool operator>=(const vfloat& a, const vfloat& b) { return vbool{ _mm_castps_si128(_mm_cmpge_ps(a.m_value, b.m_value)) }; }
+CPPSPMD_FORCE_INLINE vbool operator>=(const vfloat& a, float b) { return a >= vfloat(b); }
+
+CPPSPMD_FORCE_INLINE vfloat spmd_ternaryf(const vbool& cond, const vfloat& a, const vfloat& b) { return vfloat{ blendv_mask_ps(b.m_value, a.m_value, _mm_castsi128_ps(cond.m_value)) }; }
+CPPSPMD_FORCE_INLINE vint spmd_ternaryi(const vbool& cond, const vint& a, const vint& b) { return vint{ blendv_mask_epi32(b.m_value, a.m_value, cond.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vfloat sqrt(const vfloat& v) { return vfloat{ _mm_sqrt_ps(v.m_value) }; }
+CPPSPMD_FORCE_INLINE vfloat abs(const vfloat& v) { return vfloat{ _mm_andnot_ps(_mm_set1_ps(-0.0f), v.m_value) }; }
+CPPSPMD_FORCE_INLINE vfloat max(const vfloat& a, const vfloat& b) { return vfloat{ _mm_max_ps(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vfloat min(const vfloat& a, const vfloat& b) { return vfloat{ _mm_min_ps(a.m_value, b.m_value) }; }
+
+#if CPPSPMD_SSE2
+CPPSPMD_FORCE_INLINE vfloat round_truncate(const vfloat& a)
+{
+ __m128i abs_a = _mm_and_si128(_mm_castps_si128(a.m_value), _mm_set1_epi32(0x7FFFFFFFU) );
+ __m128i has_fractional = _mm_cmplt_epi32(abs_a, _mm_castps_si128(_mm_set1_ps(8388608.0f)));
+
+ __m128i ai = _mm_cvttps_epi32(a.m_value);
+
+ __m128 af = _mm_cvtepi32_ps(ai);
+ return vfloat{ blendv_mask_ps(a.m_value, af, _mm_castsi128_ps(has_fractional)) };
+}
+
+CPPSPMD_FORCE_INLINE vfloat floor(const vfloat& a)
+{
+ __m128i abs_a = _mm_and_si128(_mm_castps_si128(a.m_value), _mm_set1_epi32(0x7FFFFFFFU));
+ __m128i has_fractional = _mm_cmplt_epi32(abs_a, _mm_castps_si128(_mm_set1_ps(8388608.0f)));
+
+ __m128i ai = _mm_cvtps_epi32(a.m_value);
+ __m128 af = _mm_cvtepi32_ps(ai);
+ __m128 changed = _mm_cvtepi32_ps(_mm_castps_si128(_mm_cmpgt_ps(af, a.m_value)));
+
+ af = _mm_add_ps(af, changed);
+
+ return vfloat{ blendv_mask_ps(a.m_value, af, _mm_castsi128_ps(has_fractional)) };
+}
+
+CPPSPMD_FORCE_INLINE vfloat ceil(const vfloat& a)
+{
+ __m128i abs_a = _mm_and_si128(_mm_castps_si128(a.m_value), _mm_set1_epi32(0x7FFFFFFFU));
+ __m128i has_fractional = _mm_cmplt_epi32(abs_a, _mm_castps_si128(_mm_set1_ps(8388608.0f)));
+
+ __m128i ai = _mm_cvtps_epi32(a.m_value);
+ __m128 af = _mm_cvtepi32_ps(ai);
+ __m128 changed = _mm_cvtepi32_ps(_mm_castps_si128(_mm_cmplt_ps(af, a.m_value)));
+
+ af = _mm_sub_ps(af, changed);
+
+ return vfloat{ blendv_mask_ps(a.m_value, af, _mm_castsi128_ps(has_fractional)) };
+}
+
+// We need to disable unsafe math optimizations for the key operations used for rounding to nearest.
+// I wish there was a better way.
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
+inline __m128 add_sub(__m128 a, __m128 b) __attribute__((optimize("-fno-unsafe-math-optimizations")))
+#elif defined(__clang__)
+inline __m128 add_sub(__m128 a, __m128 b) __attribute__((optnone))
+#elif defined (_MSC_VER)
+#pragma float_control(push)
+#pragma float_control(precise, on)
+inline __m128 add_sub(__m128 a, __m128 b)
+#else
+inline __m128 add_sub(__m128 a, __m128 b)
+#endif
+{
+ return _mm_sub_ps(_mm_add_ps(a, b), b);
+}
+
+#if defined (_MSC_VER)
+#pragma float_control(pop)
+#endif
+
+CPPSPMD_FORCE_INLINE vfloat round_nearest(const vfloat& a)
+{
+ __m128i no_fract_fp_bits = _mm_castps_si128(_mm_set1_ps(8388608.0f));
+
+ __m128i sign_a = _mm_and_si128(_mm_castps_si128(a.m_value), _mm_set1_epi32(0x80000000U));
+ __m128 force_int = _mm_castsi128_ps(_mm_or_si128(no_fract_fp_bits, sign_a));
+
+ // Can't use individual _mm_add_ps/_mm_sub_ps - this will be optimized out with /fp:fast by clang and probably other compilers.
+ //__m128 temp1 = _mm_add_ps(a.m_value, force_int);
+ //__m128 temp2 = _mm_sub_ps(temp1, force_int);
+ __m128 temp2 = add_sub(a.m_value, force_int);
+
+ __m128i abs_a = _mm_and_si128(_mm_castps_si128(a.m_value), _mm_set1_epi32(0x7FFFFFFFU));
+ __m128i has_fractional = _mm_cmplt_epi32(abs_a, no_fract_fp_bits);
+ return vfloat{ blendv_mask_ps(a.m_value, temp2, _mm_castsi128_ps(has_fractional)) };
+}
+
+#else
+CPPSPMD_FORCE_INLINE vfloat floor(const vfloat& v) { return vfloat{ _mm_floor_ps(v.m_value) }; }
+CPPSPMD_FORCE_INLINE vfloat ceil(const vfloat& a) { return vfloat{ _mm_ceil_ps(a.m_value) }; }
+CPPSPMD_FORCE_INLINE vfloat round_nearest(const vfloat &a) { return vfloat{ _mm_round_ps(a.m_value, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC ) }; }
+CPPSPMD_FORCE_INLINE vfloat round_truncate(const vfloat &a) { return vfloat{ _mm_round_ps(a.m_value, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC ) }; }
+#endif
+
+CPPSPMD_FORCE_INLINE vfloat frac(const vfloat& a) { return a - floor(a); }
+CPPSPMD_FORCE_INLINE vfloat fmod(vfloat a, vfloat b) { vfloat c = frac(abs(a / b)) * abs(b); return spmd_ternaryf(a < 0, -c, c); }
+CPPSPMD_FORCE_INLINE vfloat sign(const vfloat& a) { return spmd_ternaryf(a < 0.0f, 1.0f, 1.0f); }
+
+CPPSPMD_FORCE_INLINE vint max(const vint& a, const vint& b) { return vint{ max_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint min(const vint& a, const vint& b) { return vint{ min_epi32(a.m_value, b.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vint maxu(const vint& a, const vint& b) { return vint{ max_epu32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint minu(const vint& a, const vint& b) { return vint{ min_epu32(a.m_value, b.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vint abs(const vint& v) { return vint{ abs_epi32(v.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vint byteswap(const vint& v) { return vint{ shuffle_epi8(v.m_value, _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3)) }; }
+
+CPPSPMD_FORCE_INLINE vint cast_vfloat_to_vint(const vfloat& v) { return vint{ _mm_castps_si128(v.m_value) }; }
+CPPSPMD_FORCE_INLINE vfloat cast_vint_to_vfloat(const vint& v) { return vfloat{ _mm_castsi128_ps(v.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vfloat clamp(const vfloat& v, const vfloat& a, const vfloat& b)
+{
+ return vfloat{ _mm_min_ps(b.m_value, _mm_max_ps(v.m_value, a.m_value) ) };
+}
+
+CPPSPMD_FORCE_INLINE vint clamp(const vint& v, const vint& a, const vint& b)
+{
+ return vint{ min_epi32(b.m_value, max_epi32(v.m_value, a.m_value) ) };
+}
+
+CPPSPMD_FORCE_INLINE vfloat vfma(const vfloat& a, const vfloat& b, const vfloat& c)
+{
+ return vfloat{ _mm_add_ps(_mm_mul_ps(a.m_value, b.m_value), c.m_value) };
+}
+
+CPPSPMD_FORCE_INLINE vfloat vfms(const vfloat& a, const vfloat& b, const vfloat& c)
+{
+ return vfloat{ _mm_sub_ps(_mm_mul_ps(a.m_value, b.m_value), c.m_value) };
+}
+
+CPPSPMD_FORCE_INLINE vfloat vfnma(const vfloat& a, const vfloat& b, const vfloat& c)
+{
+ return vfloat{ _mm_sub_ps(c.m_value, _mm_mul_ps(a.m_value, b.m_value)) };
+}
+
+CPPSPMD_FORCE_INLINE vfloat vfnms(const vfloat& a, const vfloat& b, const vfloat& c)
+{
+ return vfloat{ _mm_sub_ps(_mm_sub_ps(_mm_xor_ps(a.m_value, a.m_value), _mm_mul_ps(a.m_value, b.m_value)), c.m_value) };
+}
+
+CPPSPMD_FORCE_INLINE vfloat lerp(const vfloat &x, const vfloat &y, const vfloat &s) { return vfma(y - x, s, x); }
+
+CPPSPMD_FORCE_INLINE lint operator+(int a, const lint& b) { return lint{ _mm_add_epi32(_mm_set1_epi32(a), b.m_value) }; }
+CPPSPMD_FORCE_INLINE lint operator+(const lint& a, int b) { return lint{ _mm_add_epi32(a.m_value, _mm_set1_epi32(b)) }; }
+CPPSPMD_FORCE_INLINE vfloat operator+(float a, const lint& b) { return vfloat(a) + vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator+(const lint& a, float b) { return vfloat(a) + vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator*(const lint& a, float b) { return vfloat(a) * vfloat(b); }
+CPPSPMD_FORCE_INLINE vfloat operator*(float b, const lint& a) { return vfloat(a) * vfloat(b); }
+
+CPPSPMD_FORCE_INLINE vint operator&(const vint& a, const vint& b) { return vint{ _mm_and_si128(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint operator&(const vint& a, int b) { return a & vint(b); }
+CPPSPMD_FORCE_INLINE vint andnot(const vint& a, const vint& b) { return vint{ _mm_andnot_si128(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint operator|(const vint& a, const vint& b) { return vint{ _mm_or_si128(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint operator|(const vint& a, int b) { return a | vint(b); }
+CPPSPMD_FORCE_INLINE vint operator^(const vint& a, const vint& b) { return vint{ _mm_xor_si128(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint operator^(const vint& a, int b) { return a ^ vint(b); }
+CPPSPMD_FORCE_INLINE vbool operator==(const vint& a, const vint& b) { return vbool{ _mm_cmpeq_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vbool operator!=(const vint& a, const vint& b) { return !vbool{ _mm_cmpeq_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vbool operator<(const vint& a, const vint& b) { return vbool{ _mm_cmpgt_epi32(b.m_value, a.m_value) }; }
+CPPSPMD_FORCE_INLINE vbool operator<=(const vint& a, const vint& b) { return !vbool{ _mm_cmpgt_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vbool operator>=(const vint& a, const vint& b) { return !vbool{ _mm_cmpgt_epi32(b.m_value, a.m_value) }; }
+CPPSPMD_FORCE_INLINE vbool operator>(const vint& a, const vint& b) { return vbool{ _mm_cmpgt_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint operator+(const vint& a, const vint& b) { return vint{ _mm_add_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint operator-(const vint& a, const vint& b) { return vint{ _mm_sub_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint operator+(const vint& a, int b) { return a + vint(b); }
+CPPSPMD_FORCE_INLINE vint operator-(const vint& a, int b) { return a - vint(b); }
+CPPSPMD_FORCE_INLINE vint operator+(int a, const vint& b) { return vint(a) + b; }
+CPPSPMD_FORCE_INLINE vint operator-(int a, const vint& b) { return vint(a) - b; }
+CPPSPMD_FORCE_INLINE vint operator*(const vint& a, const vint& b) { return vint{ mullo_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint operator*(const vint& a, int b) { return a * vint(b); }
+CPPSPMD_FORCE_INLINE vint operator*(int a, const vint& b) { return vint(a) * b; }
+
+CPPSPMD_FORCE_INLINE vint mulhiu(const vint& a, const vint& b) { return vint{ mulhi_epu32(a.m_value, b.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vint operator-(const vint& v) { return vint{ _mm_sub_epi32(_mm_setzero_si128(), v.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vint operator~(const vint& a) { return vint{ -a - 1 }; }
+
+// A few of these break the lane-based abstraction model. They are supported in SSE2, so it makes sense to support them and let the user figure it out.
+CPPSPMD_FORCE_INLINE vint adds_epu8(const vint& a, const vint& b) { return vint{ _mm_adds_epu8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint subs_epu8(const vint& a, const vint& b) { return vint{ _mm_subs_epu8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint avg_epu8(const vint & a, const vint & b) { return vint{ _mm_avg_epu8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint max_epu8(const vint& a, const vint& b) { return vint{ _mm_max_epu8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint min_epu8(const vint& a, const vint& b) { return vint{ _mm_min_epu8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint sad_epu8(const vint& a, const vint& b) { return vint{ _mm_sad_epu8(a.m_value, b.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vint add_epi8(const vint& a, const vint& b) { return vint{ _mm_add_epi8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint adds_epi8(const vint& a, const vint& b) { return vint{ _mm_adds_epi8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint sub_epi8(const vint& a, const vint& b) { return vint{ _mm_sub_epi8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint subs_epi8(const vint& a, const vint& b) { return vint{ _mm_subs_epi8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint cmpeq_epi8(const vint& a, const vint& b) { return vint{ _mm_cmpeq_epi8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint cmpgt_epi8(const vint& a, const vint& b) { return vint{ _mm_cmpgt_epi8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint cmplt_epi8(const vint& a, const vint& b) { return vint{ _mm_cmplt_epi8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint unpacklo_epi8(const vint& a, const vint& b) { return vint{ _mm_unpacklo_epi8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint unpackhi_epi8(const vint& a, const vint& b) { return vint{ _mm_unpackhi_epi8(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE int movemask_epi8(const vint& a) { return _mm_movemask_epi8(a.m_value); }
+CPPSPMD_FORCE_INLINE int movemask_epi32(const vint& a) { return _mm_movemask_ps(_mm_castsi128_ps(a.m_value)); }
+
+CPPSPMD_FORCE_INLINE vint cmple_epu8(const vint& a, const vint& b) { return vint{ _mm_cmpeq_epi8(_mm_min_epu8(a.m_value, b.m_value), a.m_value) }; }
+CPPSPMD_FORCE_INLINE vint cmpge_epu8(const vint& a, const vint& b) { return vint{ cmple_epu8(b, a) }; }
+CPPSPMD_FORCE_INLINE vint cmpgt_epu8(const vint& a, const vint& b) { return vint{ _mm_andnot_si128(_mm_cmpeq_epi8(a.m_value, b.m_value), _mm_cmpeq_epi8(_mm_max_epu8(a.m_value, b.m_value), a.m_value)) }; }
+CPPSPMD_FORCE_INLINE vint cmplt_epu8(const vint& a, const vint& b) { return vint{ cmpgt_epu8(b, a) }; }
+CPPSPMD_FORCE_INLINE vint absdiff_epu8(const vint& a, const vint& b) { return vint{ _mm_or_si128(_mm_subs_epu8(a.m_value, b.m_value), _mm_subs_epu8(b.m_value, a.m_value)) }; }
+
+CPPSPMD_FORCE_INLINE vint blendv_epi8(const vint& a, const vint& b, const vint &mask) { return vint{ blendv_epi8(a.m_value, b.m_value, _mm_cmplt_epi8(mask.m_value, _mm_setzero_si128())) }; }
+CPPSPMD_FORCE_INLINE vint blendv_epi32(const vint& a, const vint& b, const vint &mask) { return vint{ blendv_epi32(a.m_value, b.m_value, mask.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vint add_epi16(const vint& a, const vint& b) { return vint{ _mm_add_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint adds_epi16(const vint& a, const vint& b) { return vint{ _mm_adds_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint adds_epu16(const vint& a, const vint& b) { return vint{ _mm_adds_epu16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint avg_epu16(const vint& a, const vint& b) { return vint{ _mm_avg_epu16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint sub_epi16(const vint& a, const vint& b) { return vint{ _mm_sub_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint subs_epi16(const vint& a, const vint& b) { return vint{ _mm_subs_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint subs_epu16(const vint& a, const vint& b) { return vint{ _mm_subs_epu16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint mullo_epi16(const vint& a, const vint& b) { return vint{ _mm_mullo_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint mulhi_epi16(const vint& a, const vint& b) { return vint{ _mm_mulhi_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint mulhi_epu16(const vint& a, const vint& b) { return vint{ _mm_mulhi_epu16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint min_epi16(const vint& a, const vint& b) { return vint{ _mm_min_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint max_epi16(const vint& a, const vint& b) { return vint{ _mm_max_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint madd_epi16(const vint& a, const vint& b) { return vint{ _mm_madd_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint cmpeq_epi16(const vint& a, const vint& b) { return vint{ _mm_cmpeq_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint cmpgt_epi16(const vint& a, const vint& b) { return vint{ _mm_cmpgt_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint cmplt_epi16(const vint& a, const vint& b) { return vint{ _mm_cmplt_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint packs_epi16(const vint& a, const vint& b) { return vint{ _mm_packs_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint packus_epi16(const vint& a, const vint& b) { return vint{ _mm_packus_epi16(a.m_value, b.m_value) }; }
+
+CPPSPMD_FORCE_INLINE vint uniform_shift_left_epi16(const vint& a, const vint& b) { return vint{ _mm_sll_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint uniform_arith_shift_right_epi16(const vint& a, const vint& b) { return vint{ _mm_sra_epi16(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vint uniform_shift_right_epi16(const vint& a, const vint& b) { return vint{ _mm_srl_epi16(a.m_value, b.m_value) }; }
+
+#define VINT_SHIFT_LEFT_EPI16(a, b) vint(_mm_slli_epi16((a).m_value, b))
+#define VINT_SHIFT_RIGHT_EPI16(a, b) vint(_mm_srai_epi16((a).m_value, b))
+#define VUINT_SHIFT_RIGHT_EPI16(a, b) vint(_mm_srli_epi16((a).m_value, b))
+
+CPPSPMD_FORCE_INLINE vint undefined_vint() { return vint{ _mm_undefined_si128() }; }
+CPPSPMD_FORCE_INLINE vfloat undefined_vfloat() { return vfloat{ _mm_undefined_ps() }; }
+
+// control is an 8-bit immediate value containing 4 2-bit indices which shuffles the int32's in each 128-bit lane.
+#define VINT_LANE_SHUFFLE_EPI32(a, control) vint(_mm_shuffle_epi32((a).m_value, control))
+
+// control is an 8-bit immediate value containing 4 2-bit indices which shuffles the int16's in either the high or low 64-bit lane.
+#define VINT_LANE_SHUFFLELO_EPI16(a, control) vint(_mm_shufflelo_epi16((a).m_value, control))
+#define VINT_LANE_SHUFFLEHI_EPI16(a, control) vint(_mm_shufflehi_epi16((a).m_value, control))
+
+#define VINT_LANE_SHUFFLE_MASK(a, b, c, d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6))
+#define VINT_LANE_SHUFFLE_MASK_R(d, c, b, a) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6))
+
+#define VINT_LANE_SHIFT_LEFT_BYTES(a, l) vint(_mm_slli_si128((a).m_value, l))
+#define VINT_LANE_SHIFT_RIGHT_BYTES(a, l) vint(_mm_srli_si128((a).m_value, l))
+
+// Unpack and interleave 8-bit integers from the low or high half of a and b
+CPPSPMD_FORCE_INLINE vint vint_lane_unpacklo_epi8(const vint& a, const vint& b) { return vint(_mm_unpacklo_epi8(a.m_value, b.m_value)); }
+CPPSPMD_FORCE_INLINE vint vint_lane_unpackhi_epi8(const vint& a, const vint& b) { return vint(_mm_unpackhi_epi8(a.m_value, b.m_value)); }
+
+// Unpack and interleave 16-bit integers from the low or high half of a and b
+CPPSPMD_FORCE_INLINE vint vint_lane_unpacklo_epi16(const vint& a, const vint& b) { return vint(_mm_unpacklo_epi16(a.m_value, b.m_value)); }
+CPPSPMD_FORCE_INLINE vint vint_lane_unpackhi_epi16(const vint& a, const vint& b) { return vint(_mm_unpackhi_epi16(a.m_value, b.m_value)); }
+
+// Unpack and interleave 32-bit integers from the low or high half of a and b
+CPPSPMD_FORCE_INLINE vint vint_lane_unpacklo_epi32(const vint& a, const vint& b) { return vint(_mm_unpacklo_epi32(a.m_value, b.m_value)); }
+CPPSPMD_FORCE_INLINE vint vint_lane_unpackhi_epi32(const vint& a, const vint& b) { return vint(_mm_unpackhi_epi32(a.m_value, b.m_value)); }
+
+// Unpack and interleave 64-bit integers from the low or high half of a and b
+CPPSPMD_FORCE_INLINE vint vint_lane_unpacklo_epi64(const vint& a, const vint& b) { return vint(_mm_unpacklo_epi64(a.m_value, b.m_value)); }
+CPPSPMD_FORCE_INLINE vint vint_lane_unpackhi_epi64(const vint& a, const vint& b) { return vint(_mm_unpackhi_epi64(a.m_value, b.m_value)); }
+
+CPPSPMD_FORCE_INLINE vint vint_set1_epi8(int8_t a) { return vint(_mm_set1_epi8(a)); }
+CPPSPMD_FORCE_INLINE vint vint_set1_epi16(int16_t a) { return vint(_mm_set1_epi16(a)); }
+CPPSPMD_FORCE_INLINE vint vint_set1_epi32(int32_t a) { return vint(_mm_set1_epi32(a)); }
+CPPSPMD_FORCE_INLINE vint vint_set1_epi64(int64_t a) { return vint(_mm_set1_epi64x(a)); }
+
+CPPSPMD_FORCE_INLINE vint mul_epu32(const vint &a, const vint& b) { return vint(_mm_mul_epu32(a.m_value, b.m_value)); }
+
+CPPSPMD_FORCE_INLINE vint div_epi32(const vint &a, const vint& b)
+{
+ __m128d al = _mm_cvtepi32_pd(a.m_value);
+ __m128d ah = _mm_cvtepi32_pd(_mm_unpackhi_epi64(a.m_value, a.m_value));
+
+ __m128d bl = _mm_cvtepi32_pd(b.m_value);
+ __m128d bh = _mm_cvtepi32_pd(_mm_unpackhi_epi64(b.m_value, b.m_value));
+
+ __m128d rl = _mm_div_pd(al, bl);
+ __m128d rh = _mm_div_pd(ah, bh);
+
+ __m128i rli = _mm_cvttpd_epi32(rl);
+ __m128i rhi = _mm_cvttpd_epi32(rh);
+
+ return vint(_mm_unpacklo_epi64(rli, rhi));
+}
+
+CPPSPMD_FORCE_INLINE vint mod_epi32(const vint &a, const vint& b)
+{
+ vint aa = abs(a), ab = abs(b);
+ vint q = div_epi32(aa, ab);
+ vint r = aa - q * ab;
+ return spmd_ternaryi(a < 0, -r, r);
+}
+
+CPPSPMD_FORCE_INLINE vint operator/ (const vint& a, const vint& b)
+{
+ return div_epi32(a, b);
+}
+
+CPPSPMD_FORCE_INLINE vint operator/ (const vint& a, int b)
+{
+ return div_epi32(a, vint(b));
+}
+
+CPPSPMD_FORCE_INLINE vint operator% (const vint& a, const vint& b)
+{
+ return mod_epi32(a, b);
+}
+
+CPPSPMD_FORCE_INLINE vint operator% (const vint& a, int b)
+{
+ return mod_epi32(a, vint(b));
+}
+
+CPPSPMD_FORCE_INLINE vint operator<< (const vint& a, const vint& b)
+{
+#if 0
+ CPPSPMD_ALIGN(32) int result[4];
+ result[0] = extract_x(a.m_value) << extract_x(b.m_value);
+ result[1] = extract_y(a.m_value) << extract_y(b.m_value);
+ result[2] = extract_z(a.m_value) << extract_z(b.m_value);
+ result[3] = extract_w(a.m_value) << extract_w(b.m_value);
+
+ return vint{ _mm_load_si128((__m128i*)result) };
+#elif 0
+ int x = extract_x(a.m_value) << extract_x(b.m_value);
+ int y = extract_y(a.m_value) << extract_y(b.m_value);
+ int z = extract_z(a.m_value) << extract_z(b.m_value);
+ int w = extract_w(a.m_value) << extract_w(b.m_value);
+
+ __m128i v = insert_x(_mm_undefined_si128(), x);
+ v = insert_y(v, y);
+ v = insert_z(v, z);
+ return vint{ insert_w(v, w) };
+#else
+ // What this does: shift left each b lane by 23 bits (to move the shift amount into the FP exponent position), then epi32 add to the integer rep of 1.0f, then cast that to float, then convert that to int to get fast 2^x.
+ return a * vint(cast_vint_to_vfloat(vint(_mm_slli_epi32(b.m_value, 23)) + cast_vfloat_to_vint(vfloat(1.0f))));
+#endif
+}
+
+// uniform shift left
+CPPSPMD_FORCE_INLINE vint operator<< (const vint& a, int b)
+{
+ __m128i bv = _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(_mm_set1_epi32(b)), _mm_castsi128_ps(_mm_load_si128((const __m128i *)g_x_128))));
+ return vint{ _mm_sll_epi32(a.m_value, bv) };
+}
+
+// uniform arithmetic shift right
+CPPSPMD_FORCE_INLINE vint operator>> (const vint& a, int b)
+{
+ __m128i bv = _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(_mm_set1_epi32(b)), _mm_castsi128_ps(_mm_load_si128((const __m128i *)g_x_128))));
+ return vint{ _mm_sra_epi32(a.m_value, bv) };
+}
+
+// uniform shift right
+CPPSPMD_FORCE_INLINE vint vuint_shift_right(const vint& a, int b)
+{
+ __m128i bv = _mm_castps_si128(_mm_and_ps(_mm_castsi128_ps(_mm_set1_epi32(b)), _mm_castsi128_ps(_mm_load_si128((const __m128i *)g_x_128))));
+ return vint{ _mm_srl_epi32(a.m_value, bv) };
+}
+
+CPPSPMD_FORCE_INLINE vint vuint_shift_right(const vint& a, const vint& b)
+{
+#if 0
+ CPPSPMD_ALIGN(32) int result[4];
+ result[0] = ((uint32_t)extract_x(a.m_value)) >> extract_x(b.m_value);
+ result[1] = ((uint32_t)extract_y(a.m_value)) >> extract_y(b.m_value);
+ result[2] = ((uint32_t)extract_z(a.m_value)) >> extract_z(b.m_value);
+ result[3] = ((uint32_t)extract_w(a.m_value)) >> extract_w(b.m_value);
+
+ return vint{ _mm_load_si128((__m128i*)result) };
+#elif 0
+ uint32_t x = ((uint32_t)extract_x(a.m_value)) >> ((uint32_t)extract_x(b.m_value));
+ uint32_t y = ((uint32_t)extract_y(a.m_value)) >> ((uint32_t)extract_y(b.m_value));
+ uint32_t z = ((uint32_t)extract_z(a.m_value)) >> ((uint32_t)extract_z(b.m_value));
+ uint32_t w = ((uint32_t)extract_w(a.m_value)) >> ((uint32_t)extract_w(b.m_value));
+
+ __m128i v = insert_x(_mm_undefined_si128(), x);
+ v = insert_y(v, y);
+ v = insert_z(v, z);
+ return vint{ insert_w(v, w) };
+#else
+ //vint inv_shift = 32 - b;
+ //vfloat f = cast_vint_to_vfloat(vint(_mm_slli_epi32(inv_shift.m_value, 23)) + cast_vfloat_to_vint(vfloat(1.0f)));
+
+ // Take float rep of 1.0f (0x3f800000), subtract (32<<23), subtract (shift<<23), cast to float.
+ vfloat f = cast_vint_to_vfloat(vint(_mm_sub_epi32(_mm_set1_epi32(0x4f800000), _mm_slli_epi32(b.m_value, 23))));
+
+ // Now convert scale factor to integer.
+ vint r = vint(f);
+
+ // mulhi_epu32 (using two _mm_mul_epu32), to emulate varying shift left.
+ vint q(mulhi_epu32(a.m_value, r.m_value));
+
+ // Handle shift amounts of 0.
+ return spmd_ternaryi(b > 0, q, a);
+#endif
+}
+
+CPPSPMD_FORCE_INLINE vint vuint_shift_right_not_zero(const vint& a, const vint& b)
+{
+ //vint inv_shift = 32 - b;
+ //vfloat f = cast_vint_to_vfloat(vint(_mm_slli_epi32(inv_shift.m_value, 23)) + cast_vfloat_to_vint(vfloat(1.0f)));
+
+ // Take float rep of 1.0f (0x3f800000), subtract (32<<23), subtract (shift<<23), cast to float.
+ vfloat f = cast_vint_to_vfloat(vint(_mm_sub_epi32(_mm_set1_epi32(0x4f800000), _mm_slli_epi32(b.m_value, 23))));
+
+ // Now convert scale factor to integer.
+ vint r = vint(f);
+
+ // mulhi_epu32 (using two _mm_mul_epu32), to emulate varying shift left.
+ return vint(mulhi_epu32(a.m_value, r.m_value));
+}
+
+CPPSPMD_FORCE_INLINE vint operator>> (const vint& a, const vint& b)
+{
+#if 0
+ CPPSPMD_ALIGN(32) int result[4];
+ result[0] = extract_x(a.m_value) >> extract_x(b.m_value);
+ result[1] = extract_y(a.m_value) >> extract_y(b.m_value);
+ result[2] = extract_z(a.m_value) >> extract_z(b.m_value);
+ result[3] = extract_w(a.m_value) >> extract_w(b.m_value);
+
+ return vint{ _mm_load_si128((__m128i*)result) };
+#elif 0
+ int x = extract_x(a.m_value) >> extract_x(b.m_value);
+ int y = extract_y(a.m_value) >> extract_y(b.m_value);
+ int z = extract_z(a.m_value) >> extract_z(b.m_value);
+ int w = extract_w(a.m_value) >> extract_w(b.m_value);
+
+ __m128i v = insert_x(_mm_undefined_si128(), x);
+ v = insert_y(v, y);
+ v = insert_z(v, z);
+ return vint{ insert_w(v, w) };
+#else
+ vint sign_mask(_mm_cmplt_epi32(a.m_value, _mm_setzero_si128()));
+ vint a_shifted = vuint_shift_right(a ^ sign_mask, b) ^ sign_mask;
+ return a_shifted;
+#endif
+}
+
+#undef VINT_SHIFT_LEFT
+#undef VINT_SHIFT_RIGHT
+#undef VUINT_SHIFT_RIGHT
+
+// Shift left/right by a uniform immediate constant
+#define VINT_SHIFT_LEFT(a, b) vint(_mm_slli_epi32( (a).m_value, (b) ) )
+#define VINT_SHIFT_RIGHT(a, b) vint( _mm_srai_epi32( (a).m_value, (b) ) )
+#define VUINT_SHIFT_RIGHT(a, b) vint( _mm_srli_epi32( (a).m_value, (b) ) )
+#define VINT_ROT(x, k) (VINT_SHIFT_LEFT((x), (k)) | VUINT_SHIFT_RIGHT((x), 32 - (k)))
+
+CPPSPMD_FORCE_INLINE vbool operator==(const lint& a, const lint& b) { return vbool{ _mm_cmpeq_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vbool operator==(const lint& a, int b) { return vint(a) == vint(b); }
+CPPSPMD_FORCE_INLINE vbool operator==(int a, const lint& b) { return vint(a) == vint(b); }
+CPPSPMD_FORCE_INLINE vbool operator<(const lint& a, const lint& b) { return vbool{ _mm_cmpgt_epi32(b.m_value, a.m_value) }; }
+CPPSPMD_FORCE_INLINE vbool operator>(const lint& a, const lint& b) { return vbool{ _mm_cmpgt_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vbool operator<=(const lint& a, const lint& b) { return !vbool{ _mm_cmpgt_epi32(a.m_value, b.m_value) }; }
+CPPSPMD_FORCE_INLINE vbool operator>=(const lint& a, const lint& b) { return !vbool{ _mm_cmpgt_epi32(b.m_value, a.m_value) }; }
+
+CPPSPMD_FORCE_INLINE float extract(const vfloat& v, int instance) { assert(instance < 4); CPPSPMD_ALIGN(16) float values[4]; _mm_store_ps(values, v.m_value); return values[instance]; }
+CPPSPMD_FORCE_INLINE int extract(const vint& v, int instance) { assert(instance < 4); CPPSPMD_ALIGN(16) int values[4]; _mm_store_si128((__m128i*)values, v.m_value); return values[instance]; }
+CPPSPMD_FORCE_INLINE int extract(const lint& v, int instance) { assert(instance < 4); CPPSPMD_ALIGN(16) int values[4]; _mm_store_si128((__m128i*)values, v.m_value); return values[instance]; }
+CPPSPMD_FORCE_INLINE bool extract(const vbool& v, int instance) { assert(instance < 4); CPPSPMD_ALIGN(16) int values[4]; _mm_store_si128((__m128i*)values, v.m_value); return values[instance] != 0; }
+
+#undef VINT_EXTRACT
+#undef VBOOL_EXTRACT
+#undef VFLOAT_EXTRACT
+
+#if CPPSPMD_SSE2
+// Pass in an immediate constant and the compiler will optimize these expressions.
+#define VINT_EXTRACT(v, instance) ( ((instance) == 0) ? extract_x((v).m_value) : (((instance) == 1) ? extract_y((v).m_value) : (((instance) == 2) ? extract_z((v).m_value) : extract_w((v).m_value))) )
+#define VBOOL_EXTRACT(v, instance) ( ((instance) == 0) ? extract_x((v).m_value) : (((instance) == 1) ? extract_y((v).m_value) : (((instance) == 2) ? extract_z((v).m_value) : extract_w((v).m_value))) )
+#define VFLOAT_EXTRACT(v, instance) ( ((instance) == 0) ? extractf_ps_x((v).m_value) : (((instance) == 1) ? extractf_ps_y((v).m_value) : (((instance) == 2) ? extractf_ps_z((v).m_value) : extractf_ps_w((v).m_value))) )
+#else
+CPPSPMD_FORCE_INLINE float cast_int_bits_as_float(int v) { return *(const float*)&v; }
+
+#define VINT_EXTRACT(v, instance) _mm_extract_epi32((v).m_value, instance)
+#define VBOOL_EXTRACT(v, instance) _mm_extract_epi32((v).m_value, instance)
+#define VFLOAT_EXTRACT(v, instance) cast_int_bits_as_float(_mm_extract_ps((v).m_value, instance))
+#endif
+
+CPPSPMD_FORCE_INLINE vfloat &insert(vfloat& v, int instance, float f)
+{
+ assert(instance < 4);
+ CPPSPMD_ALIGN(16) float values[4];
+ _mm_store_ps(values, v.m_value);
+ values[instance] = f;
+ v.m_value = _mm_load_ps(values);
+ return v;
+}
+
+CPPSPMD_FORCE_INLINE vint &insert(vint& v, int instance, int i)
+{
+ assert(instance < 4);
+ CPPSPMD_ALIGN(16) int values[4];
+ _mm_store_si128((__m128i *)values, v.m_value);
+ values[instance] = i;
+ v.m_value = _mm_load_si128((__m128i *)values);
+ return v;
+}
+
+CPPSPMD_FORCE_INLINE vint init_lookup4(const uint8_t pTab[16])
+{
+ __m128i l = _mm_loadu_si128((const __m128i*)pTab);
+ return vint{ l };
+}
+
+CPPSPMD_FORCE_INLINE vint table_lookup4_8(const vint& a, const vint& table)
+{
+ return vint{ shuffle_epi8(table.m_value, a.m_value) };
+}
+
+CPPSPMD_FORCE_INLINE void init_lookup5(const uint8_t pTab[32], vint& table_0, vint& table_1)
+{
+ __m128i l = _mm_loadu_si128((const __m128i*)pTab);
+ __m128i h = _mm_loadu_si128((const __m128i*)(pTab + 16));
+ table_0.m_value = l;
+ table_1.m_value = h;
+}
+
+CPPSPMD_FORCE_INLINE vint table_lookup5_8(const vint& a, const vint& table_0, const vint& table_1)
+{
+ __m128i l_0 = shuffle_epi8(table_0.m_value, a.m_value);
+ __m128i h_0 = shuffle_epi8(table_1.m_value, a.m_value);
+
+ __m128i m_0 = _mm_slli_epi32(a.m_value, 31 - 4);
+
+ __m128 v_0 = blendv_ps(_mm_castsi128_ps(l_0), _mm_castsi128_ps(h_0), _mm_castsi128_ps(m_0));
+
+ return vint{ _mm_castps_si128(v_0) };
+}
+
+CPPSPMD_FORCE_INLINE void init_lookup6(const uint8_t pTab[64], vint& table_0, vint& table_1, vint& table_2, vint& table_3)
+{
+ __m128i a = _mm_loadu_si128((const __m128i*)pTab);
+ __m128i b = _mm_loadu_si128((const __m128i*)(pTab + 16));
+ __m128i c = _mm_loadu_si128((const __m128i*)(pTab + 32));
+ __m128i d = _mm_loadu_si128((const __m128i*)(pTab + 48));
+
+ table_0.m_value = a;
+ table_1.m_value = b;
+ table_2.m_value = c;
+ table_3.m_value = d;
+}
+
+CPPSPMD_FORCE_INLINE vint table_lookup6_8(const vint& a, const vint& table_0, const vint& table_1, const vint& table_2, const vint& table_3)
+{
+ __m128i m_0 = _mm_slli_epi32(a.m_value, 31 - 4);
+
+ __m128 av_0;
+ {
+ __m128i al_0 = shuffle_epi8(table_0.m_value, a.m_value);
+ __m128i ah_0 = shuffle_epi8(table_1.m_value, a.m_value);
+ av_0 = blendv_ps(_mm_castsi128_ps(al_0), _mm_castsi128_ps(ah_0), _mm_castsi128_ps(m_0));
+ }
+
+ __m128 bv_0;
+ {
+ __m128i bl_0 = shuffle_epi8(table_2.m_value, a.m_value);
+ __m128i bh_0 = shuffle_epi8(table_3.m_value, a.m_value);
+ bv_0 = blendv_ps(_mm_castsi128_ps(bl_0), _mm_castsi128_ps(bh_0), _mm_castsi128_ps(m_0));
+ }
+
+ __m128i m2_0 = _mm_slli_epi32(a.m_value, 31 - 5);
+ __m128 v2_0 = blendv_ps(av_0, bv_0, _mm_castsi128_ps(m2_0));
+
+ return vint{ _mm_castps_si128(v2_0) };
+}
+
+#if 0
+template<typename SPMDKernel, typename... Args>
+CPPSPMD_FORCE_INLINE decltype(auto) spmd_call(Args&&... args)
+{
+ SPMDKernel kernel;
+ kernel.init(exec_mask::all_on());
+ return kernel._call(std::forward<Args>(args)...);
+}
+#else
+template<typename SPMDKernel, typename... Args>
+CPPSPMD_FORCE_INLINE void spmd_call(Args&&... args)
+{
+ SPMDKernel kernel;
+ kernel.init(exec_mask::all_on());
+ kernel._call(std::forward<Args>(args)...);
+}
+#endif
+
+CPPSPMD_FORCE_INLINE void spmd_kernel::init(const spmd_kernel::exec_mask& kernel_exec)
+{
+ m_exec = kernel_exec;
+ m_kernel_exec = kernel_exec;
+ m_continue_mask = exec_mask::all_off();
+
+#ifdef _DEBUG
+ m_in_loop = false;
+#endif
+}
+
+CPPSPMD_FORCE_INLINE const float_vref& spmd_kernel::store(const float_vref& dst, const vfloat& src)
+{
+ CPPSPMD_ALIGN(16) int vindex[4];
+ _mm_store_si128((__m128i*)vindex, dst.m_vindex);
+
+ CPPSPMD_ALIGN(16) float stored[4];
+ _mm_store_ps(stored, src.m_value);
+
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ for (int i = 0; i < 4; i++)
+ {
+ if (mask & (1 << i))
+ dst.m_pValue[vindex[i]] = stored[i];
+ }
+ return dst;
+}
+
+CPPSPMD_FORCE_INLINE const float_vref& spmd_kernel::store_all(const float_vref& dst, const vfloat& src)
+{
+ CPPSPMD_ALIGN(16) int vindex[4];
+ _mm_store_si128((__m128i*)vindex, dst.m_vindex);
+
+ CPPSPMD_ALIGN(16) float stored[4];
+ _mm_store_ps(stored, src.m_value);
+
+ for (int i = 0; i < 4; i++)
+ dst.m_pValue[vindex[i]] = stored[i];
+ return dst;
+}
+
+CPPSPMD_FORCE_INLINE const float_vref& spmd_kernel::store(const float_vref&& dst, const vfloat& src)
+{
+ CPPSPMD_ALIGN(16) int vindex[4];
+ _mm_store_si128((__m128i*)vindex, dst.m_vindex);
+
+ CPPSPMD_ALIGN(16) float stored[4];
+ _mm_store_ps(stored, src.m_value);
+
+ int mask = _mm_movemask_ps(_mm_castsi128_ps(m_exec.m_mask));
+ for (int i = 0; i < 4; i++)
+ {
+ if (mask & (1 << i))
+ dst.m_pValue[vindex[i]] = stored[i];
+ }
+ return dst;
+}
+
+CPPSPMD_FORCE_INLINE const float_vref& spmd_kernel::store_all(const float_vref&& dst, const vfloat& src)
+{
+ CPPSPMD_ALIGN(16) int vindex[4];
+ _mm_store_si128((__m128i*)vindex, dst.m_vindex);
+
+ CPPSPMD_ALIGN(16) float stored[4];
+ _mm_store_ps(stored, src.m_value);
+
+ for (int i = 0; i < 4; i++)
+ dst.m_pValue[vindex[i]] = stored[i];
+ return dst;
+}
+
+#include "cppspmd_flow.h"
+#include "cppspmd_math.h"
+
+} // namespace cppspmd_sse41
+
diff --git a/thirdparty/basis_universal/encoder/cppspmd_type_aliases.h b/thirdparty/basis_universal/encoder/cppspmd_type_aliases.h
new file mode 100644
index 0000000000..0dfb28b88f
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/cppspmd_type_aliases.h
@@ -0,0 +1,47 @@
+// cppspmd_type_aliases.h
+// Do not include this file directly
+//
+// Copyright 2020-2021 Binomial LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#ifndef CPPSPMD_TYPES
+#define CPPSPMD_TYPES
+
+using exec_mask = CPPSPMD::exec_mask;
+
+#if CPPSPMD_INT16
+using vint16 = CPPSPMD::vint16;
+using int16_lref = CPPSPMD::int16_lref;
+using cint16_vref = CPPSPMD::cint16_vref;
+using int16_vref = CPPSPMD::int16_vref;
+using lint16 = CPPSPMD::lint16;
+using vint16_vref = CPPSPMD::vint16_vref;
+#else
+using vint = CPPSPMD::vint;
+using int_lref = CPPSPMD::int_lref;
+using cint_vref = CPPSPMD::cint_vref;
+using int_vref = CPPSPMD::int_vref;
+using lint = CPPSPMD::lint;
+using vint_vref = CPPSPMD::vint_vref;
+#endif
+
+using vbool = CPPSPMD::vbool;
+using vfloat = CPPSPMD::vfloat;
+using float_lref = CPPSPMD::float_lref;
+using float_vref = CPPSPMD::float_vref;
+using vfloat_vref = CPPSPMD::vfloat_vref;
+
+#endif // CPPSPMD_TYPES
diff --git a/thirdparty/basis_universal/encoder/jpgd.cpp b/thirdparty/basis_universal/encoder/jpgd.cpp
new file mode 100644
index 0000000000..460834409d
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/jpgd.cpp
@@ -0,0 +1,3241 @@
+// jpgd.cpp - C++ class for JPEG decompression. Written by Richard Geldreich <richgel99@gmail.com> between 1994-2020.
+// Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2.
+// Supports box and linear chroma upsampling.
+//
+// Released under two licenses. You are free to choose which license you want:
+// License 1:
+// Public Domain
+//
+// License 2:
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Alex Evans: Linear memory allocator (taken from jpge.h).
+// v1.04, May. 19, 2012: Code tweaks to fix VS2008 static code analysis warnings
+// v2.00, March 20, 2020: Fuzzed with zzuf and afl. Fixed several issues, converted most assert()'s to run-time checks. Added chroma upsampling. Removed freq. domain upsampling. gcc/clang warnings.
+//
+#ifdef _MSC_VER
+#ifndef BASISU_NO_ITERATOR_DEBUG_LEVEL
+#if defined(_DEBUG) || defined(DEBUG)
+#define _ITERATOR_DEBUG_LEVEL 1
+#define _SECURE_SCL 1
+#else
+#define _SECURE_SCL 0
+#define _ITERATOR_DEBUG_LEVEL 0
+#endif
+#endif
+#endif
+
+#include "jpgd.h"
+#include <string.h>
+#include <algorithm>
+#include <assert.h>
+
+#ifdef _MSC_VER
+#pragma warning (disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable
+#endif
+
+#define JPGD_TRUE (1)
+#define JPGD_FALSE (0)
+
+#define JPGD_MAX(a,b) (((a)>(b)) ? (a) : (b))
+#define JPGD_MIN(a,b) (((a)<(b)) ? (a) : (b))
+
+namespace jpgd {
+
+ static inline void* jpgd_malloc(size_t nSize) { return malloc(nSize); }
+ static inline void jpgd_free(void* p) { free(p); }
+
+ // DCT coefficients are stored in this sequence.
+ static int g_ZAG[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 };
+
+ enum JPEG_MARKER
+ {
+ M_SOF0 = 0xC0, M_SOF1 = 0xC1, M_SOF2 = 0xC2, M_SOF3 = 0xC3, M_SOF5 = 0xC5, M_SOF6 = 0xC6, M_SOF7 = 0xC7, M_JPG = 0xC8,
+ M_SOF9 = 0xC9, M_SOF10 = 0xCA, M_SOF11 = 0xCB, M_SOF13 = 0xCD, M_SOF14 = 0xCE, M_SOF15 = 0xCF, M_DHT = 0xC4, M_DAC = 0xCC,
+ M_RST0 = 0xD0, M_RST1 = 0xD1, M_RST2 = 0xD2, M_RST3 = 0xD3, M_RST4 = 0xD4, M_RST5 = 0xD5, M_RST6 = 0xD6, M_RST7 = 0xD7,
+ M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_DNL = 0xDC, M_DRI = 0xDD, M_DHP = 0xDE, M_EXP = 0xDF,
+ M_APP0 = 0xE0, M_APP15 = 0xEF, M_JPG0 = 0xF0, M_JPG13 = 0xFD, M_COM = 0xFE, M_TEM = 0x01, M_ERROR = 0x100, RST0 = 0xD0
+ };
+
+ enum JPEG_SUBSAMPLING { JPGD_GRAYSCALE = 0, JPGD_YH1V1, JPGD_YH2V1, JPGD_YH1V2, JPGD_YH2V2 };
+
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#define SCALEDONE ((int32)1)
+
+#define FIX_0_298631336 ((int32)2446) /* FIX(0.298631336) */
+#define FIX_0_390180644 ((int32)3196) /* FIX(0.390180644) */
+#define FIX_0_541196100 ((int32)4433) /* FIX(0.541196100) */
+#define FIX_0_765366865 ((int32)6270) /* FIX(0.765366865) */
+#define FIX_0_899976223 ((int32)7373) /* FIX(0.899976223) */
+#define FIX_1_175875602 ((int32)9633) /* FIX(1.175875602) */
+#define FIX_1_501321110 ((int32)12299) /* FIX(1.501321110) */
+#define FIX_1_847759065 ((int32)15137) /* FIX(1.847759065) */
+#define FIX_1_961570560 ((int32)16069) /* FIX(1.961570560) */
+#define FIX_2_053119869 ((int32)16819) /* FIX(2.053119869) */
+#define FIX_2_562915447 ((int32)20995) /* FIX(2.562915447) */
+#define FIX_3_072711026 ((int32)25172) /* FIX(3.072711026) */
+
+#define DESCALE(x,n) (((x) + (SCALEDONE << ((n)-1))) >> (n))
+#define DESCALE_ZEROSHIFT(x,n) (((x) + (128 << (n)) + (SCALEDONE << ((n)-1))) >> (n))
+
+#define MULTIPLY(var, cnst) ((var) * (cnst))
+
+#define CLAMP(i) ((static_cast<uint>(i) > 255) ? (((~i) >> 31) & 0xFF) : (i))
+
+ static inline int left_shifti(int val, uint32_t bits)
+ {
+ return static_cast<int>(static_cast<uint32_t>(val) << bits);
+ }
+
+ // Compiler creates a fast path 1D IDCT for X non-zero columns
+ template <int NONZERO_COLS>
+ struct Row
+ {
+ static void idct(int* pTemp, const jpgd_block_t* pSrc)
+ {
+ // ACCESS_COL() will be optimized at compile time to either an array access, or 0. Good compilers will then optimize out muls against 0.
+#define ACCESS_COL(x) (((x) < NONZERO_COLS) ? (int)pSrc[x] : 0)
+
+ const int z2 = ACCESS_COL(2), z3 = ACCESS_COL(6);
+
+ const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ const int tmp2 = z1 + MULTIPLY(z3, -FIX_1_847759065);
+ const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
+
+ const int tmp0 = left_shifti(ACCESS_COL(0) + ACCESS_COL(4), CONST_BITS);
+ const int tmp1 = left_shifti(ACCESS_COL(0) - ACCESS_COL(4), CONST_BITS);
+
+ const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2;
+
+ const int atmp0 = ACCESS_COL(7), atmp1 = ACCESS_COL(5), atmp2 = ACCESS_COL(3), atmp3 = ACCESS_COL(1);
+
+ const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3;
+ const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602);
+
+ const int az1 = MULTIPLY(bz1, -FIX_0_899976223);
+ const int az2 = MULTIPLY(bz2, -FIX_2_562915447);
+ const int az3 = MULTIPLY(bz3, -FIX_1_961570560) + bz5;
+ const int az4 = MULTIPLY(bz4, -FIX_0_390180644) + bz5;
+
+ const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3;
+ const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4;
+ const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3;
+ const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4;
+
+ pTemp[0] = DESCALE(tmp10 + btmp3, CONST_BITS - PASS1_BITS);
+ pTemp[7] = DESCALE(tmp10 - btmp3, CONST_BITS - PASS1_BITS);
+ pTemp[1] = DESCALE(tmp11 + btmp2, CONST_BITS - PASS1_BITS);
+ pTemp[6] = DESCALE(tmp11 - btmp2, CONST_BITS - PASS1_BITS);
+ pTemp[2] = DESCALE(tmp12 + btmp1, CONST_BITS - PASS1_BITS);
+ pTemp[5] = DESCALE(tmp12 - btmp1, CONST_BITS - PASS1_BITS);
+ pTemp[3] = DESCALE(tmp13 + btmp0, CONST_BITS - PASS1_BITS);
+ pTemp[4] = DESCALE(tmp13 - btmp0, CONST_BITS - PASS1_BITS);
+ }
+ };
+
+ template <>
+ struct Row<0>
+ {
+ static void idct(int* pTemp, const jpgd_block_t* pSrc)
+ {
+ (void)pTemp;
+ (void)pSrc;
+ }
+ };
+
+ template <>
+ struct Row<1>
+ {
+ static void idct(int* pTemp, const jpgd_block_t* pSrc)
+ {
+ const int dcval = left_shifti(pSrc[0], PASS1_BITS);
+
+ pTemp[0] = dcval;
+ pTemp[1] = dcval;
+ pTemp[2] = dcval;
+ pTemp[3] = dcval;
+ pTemp[4] = dcval;
+ pTemp[5] = dcval;
+ pTemp[6] = dcval;
+ pTemp[7] = dcval;
+ }
+ };
+
+ // Compiler creates a fast path 1D IDCT for X non-zero rows
+ template <int NONZERO_ROWS>
+ struct Col
+ {
+ static void idct(uint8* pDst_ptr, const int* pTemp)
+ {
+ // ACCESS_ROW() will be optimized at compile time to either an array access, or 0.
+#define ACCESS_ROW(x) (((x) < NONZERO_ROWS) ? pTemp[x * 8] : 0)
+
+ const int z2 = ACCESS_ROW(2);
+ const int z3 = ACCESS_ROW(6);
+
+ const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ const int tmp2 = z1 + MULTIPLY(z3, -FIX_1_847759065);
+ const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
+
+ const int tmp0 = left_shifti(ACCESS_ROW(0) + ACCESS_ROW(4), CONST_BITS);
+ const int tmp1 = left_shifti(ACCESS_ROW(0) - ACCESS_ROW(4), CONST_BITS);
+
+ const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2;
+
+ const int atmp0 = ACCESS_ROW(7), atmp1 = ACCESS_ROW(5), atmp2 = ACCESS_ROW(3), atmp3 = ACCESS_ROW(1);
+
+ const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3;
+ const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602);
+
+ const int az1 = MULTIPLY(bz1, -FIX_0_899976223);
+ const int az2 = MULTIPLY(bz2, -FIX_2_562915447);
+ const int az3 = MULTIPLY(bz3, -FIX_1_961570560) + bz5;
+ const int az4 = MULTIPLY(bz4, -FIX_0_390180644) + bz5;
+
+ const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3;
+ const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4;
+ const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3;
+ const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4;
+
+ int i = DESCALE_ZEROSHIFT(tmp10 + btmp3, CONST_BITS + PASS1_BITS + 3);
+ pDst_ptr[8 * 0] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp10 - btmp3, CONST_BITS + PASS1_BITS + 3);
+ pDst_ptr[8 * 7] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp11 + btmp2, CONST_BITS + PASS1_BITS + 3);
+ pDst_ptr[8 * 1] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp11 - btmp2, CONST_BITS + PASS1_BITS + 3);
+ pDst_ptr[8 * 6] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp12 + btmp1, CONST_BITS + PASS1_BITS + 3);
+ pDst_ptr[8 * 2] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp12 - btmp1, CONST_BITS + PASS1_BITS + 3);
+ pDst_ptr[8 * 5] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp13 + btmp0, CONST_BITS + PASS1_BITS + 3);
+ pDst_ptr[8 * 3] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp13 - btmp0, CONST_BITS + PASS1_BITS + 3);
+ pDst_ptr[8 * 4] = (uint8)CLAMP(i);
+ }
+ };
+
+ template <>
+ struct Col<1>
+ {
+ static void idct(uint8* pDst_ptr, const int* pTemp)
+ {
+ int dcval = DESCALE_ZEROSHIFT(pTemp[0], PASS1_BITS + 3);
+ const uint8 dcval_clamped = (uint8)CLAMP(dcval);
+ pDst_ptr[0 * 8] = dcval_clamped;
+ pDst_ptr[1 * 8] = dcval_clamped;
+ pDst_ptr[2 * 8] = dcval_clamped;
+ pDst_ptr[3 * 8] = dcval_clamped;
+ pDst_ptr[4 * 8] = dcval_clamped;
+ pDst_ptr[5 * 8] = dcval_clamped;
+ pDst_ptr[6 * 8] = dcval_clamped;
+ pDst_ptr[7 * 8] = dcval_clamped;
+ }
+ };
+
+ static const uint8 s_idct_row_table[] =
+ {
+ 1,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0, 2,1,0,0,0,0,0,0, 2,1,1,0,0,0,0,0, 2,2,1,0,0,0,0,0, 3,2,1,0,0,0,0,0, 4,2,1,0,0,0,0,0, 4,3,1,0,0,0,0,0,
+ 4,3,2,0,0,0,0,0, 4,3,2,1,0,0,0,0, 4,3,2,1,1,0,0,0, 4,3,2,2,1,0,0,0, 4,3,3,2,1,0,0,0, 4,4,3,2,1,0,0,0, 5,4,3,2,1,0,0,0, 6,4,3,2,1,0,0,0,
+ 6,5,3,2,1,0,0,0, 6,5,4,2,1,0,0,0, 6,5,4,3,1,0,0,0, 6,5,4,3,2,0,0,0, 6,5,4,3,2,1,0,0, 6,5,4,3,2,1,1,0, 6,5,4,3,2,2,1,0, 6,5,4,3,3,2,1,0,
+ 6,5,4,4,3,2,1,0, 6,5,5,4,3,2,1,0, 6,6,5,4,3,2,1,0, 7,6,5,4,3,2,1,0, 8,6,5,4,3,2,1,0, 8,7,5,4,3,2,1,0, 8,7,6,4,3,2,1,0, 8,7,6,5,3,2,1,0,
+ 8,7,6,5,4,2,1,0, 8,7,6,5,4,3,1,0, 8,7,6,5,4,3,2,0, 8,7,6,5,4,3,2,1, 8,7,6,5,4,3,2,2, 8,7,6,5,4,3,3,2, 8,7,6,5,4,4,3,2, 8,7,6,5,5,4,3,2,
+ 8,7,6,6,5,4,3,2, 8,7,7,6,5,4,3,2, 8,8,7,6,5,4,3,2, 8,8,8,6,5,4,3,2, 8,8,8,7,5,4,3,2, 8,8,8,7,6,4,3,2, 8,8,8,7,6,5,3,2, 8,8,8,7,6,5,4,2,
+ 8,8,8,7,6,5,4,3, 8,8,8,7,6,5,4,4, 8,8,8,7,6,5,5,4, 8,8,8,7,6,6,5,4, 8,8,8,7,7,6,5,4, 8,8,8,8,7,6,5,4, 8,8,8,8,8,6,5,4, 8,8,8,8,8,7,5,4,
+ 8,8,8,8,8,7,6,4, 8,8,8,8,8,7,6,5, 8,8,8,8,8,7,6,6, 8,8,8,8,8,7,7,6, 8,8,8,8,8,8,7,6, 8,8,8,8,8,8,8,6, 8,8,8,8,8,8,8,7, 8,8,8,8,8,8,8,8,
+ };
+
+ static const uint8 s_idct_col_table[] =
+ {
+ 1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
+ };
+
+ // Scalar "fast pathing" IDCT.
+ static void idct(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr, int block_max_zag)
+ {
+ assert(block_max_zag >= 1);
+ assert(block_max_zag <= 64);
+
+ if (block_max_zag <= 1)
+ {
+ int k = ((pSrc_ptr[0] + 4) >> 3) + 128;
+ k = CLAMP(k);
+ k = k | (k << 8);
+ k = k | (k << 16);
+
+ for (int i = 8; i > 0; i--)
+ {
+ *(int*)&pDst_ptr[0] = k;
+ *(int*)&pDst_ptr[4] = k;
+ pDst_ptr += 8;
+ }
+ return;
+ }
+
+ int temp[64];
+
+ const jpgd_block_t* pSrc = pSrc_ptr;
+ int* pTemp = temp;
+
+ const uint8* pRow_tab = &s_idct_row_table[(block_max_zag - 1) * 8];
+ int i;
+ for (i = 8; i > 0; i--, pRow_tab++)
+ {
+ switch (*pRow_tab)
+ {
+ case 0: Row<0>::idct(pTemp, pSrc); break;
+ case 1: Row<1>::idct(pTemp, pSrc); break;
+ case 2: Row<2>::idct(pTemp, pSrc); break;
+ case 3: Row<3>::idct(pTemp, pSrc); break;
+ case 4: Row<4>::idct(pTemp, pSrc); break;
+ case 5: Row<5>::idct(pTemp, pSrc); break;
+ case 6: Row<6>::idct(pTemp, pSrc); break;
+ case 7: Row<7>::idct(pTemp, pSrc); break;
+ case 8: Row<8>::idct(pTemp, pSrc); break;
+ }
+
+ pSrc += 8;
+ pTemp += 8;
+ }
+
+ pTemp = temp;
+
+ const int nonzero_rows = s_idct_col_table[block_max_zag - 1];
+ for (i = 8; i > 0; i--)
+ {
+ switch (nonzero_rows)
+ {
+ case 1: Col<1>::idct(pDst_ptr, pTemp); break;
+ case 2: Col<2>::idct(pDst_ptr, pTemp); break;
+ case 3: Col<3>::idct(pDst_ptr, pTemp); break;
+ case 4: Col<4>::idct(pDst_ptr, pTemp); break;
+ case 5: Col<5>::idct(pDst_ptr, pTemp); break;
+ case 6: Col<6>::idct(pDst_ptr, pTemp); break;
+ case 7: Col<7>::idct(pDst_ptr, pTemp); break;
+ case 8: Col<8>::idct(pDst_ptr, pTemp); break;
+ }
+
+ pTemp++;
+ pDst_ptr++;
+ }
+ }
+
+ // Retrieve one character from the input stream.
+ inline uint jpeg_decoder::get_char()
+ {
+ // Any bytes remaining in buffer?
+ if (!m_in_buf_left)
+ {
+ // Try to get more bytes.
+ prep_in_buffer();
+ // Still nothing to get?
+ if (!m_in_buf_left)
+ {
+ // Pad the end of the stream with 0xFF 0xD9 (EOI marker)
+ int t = m_tem_flag;
+ m_tem_flag ^= 1;
+ if (t)
+ return 0xD9;
+ else
+ return 0xFF;
+ }
+ }
+
+ uint c = *m_pIn_buf_ofs++;
+ m_in_buf_left--;
+
+ return c;
+ }
+
+ // Same as previous method, except can indicate if the character is a pad character or not.
+ inline uint jpeg_decoder::get_char(bool* pPadding_flag)
+ {
+ if (!m_in_buf_left)
+ {
+ prep_in_buffer();
+ if (!m_in_buf_left)
+ {
+ *pPadding_flag = true;
+ int t = m_tem_flag;
+ m_tem_flag ^= 1;
+ if (t)
+ return 0xD9;
+ else
+ return 0xFF;
+ }
+ }
+
+ *pPadding_flag = false;
+
+ uint c = *m_pIn_buf_ofs++;
+ m_in_buf_left--;
+
+ return c;
+ }
+
+ // Inserts a previously retrieved character back into the input buffer.
+ inline void jpeg_decoder::stuff_char(uint8 q)
+ {
+ // This could write before the input buffer, but we've placed another array there.
+ *(--m_pIn_buf_ofs) = q;
+ m_in_buf_left++;
+ }
+
+ // Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered.
+ inline uint8 jpeg_decoder::get_octet()
+ {
+ bool padding_flag;
+ int c = get_char(&padding_flag);
+
+ if (c == 0xFF)
+ {
+ if (padding_flag)
+ return 0xFF;
+
+ c = get_char(&padding_flag);
+ if (padding_flag)
+ {
+ stuff_char(0xFF);
+ return 0xFF;
+ }
+
+ if (c == 0x00)
+ return 0xFF;
+ else
+ {
+ stuff_char(static_cast<uint8>(c));
+ stuff_char(0xFF);
+ return 0xFF;
+ }
+ }
+
+ return static_cast<uint8>(c);
+ }
+
+ // Retrieves a variable number of bits from the input stream. Does not recognize markers.
+ inline uint jpeg_decoder::get_bits(int num_bits)
+ {
+ if (!num_bits)
+ return 0;
+
+ uint i = m_bit_buf >> (32 - num_bits);
+
+ if ((m_bits_left -= num_bits) <= 0)
+ {
+ m_bit_buf <<= (num_bits += m_bits_left);
+
+ uint c1 = get_char();
+ uint c2 = get_char();
+ m_bit_buf = (m_bit_buf & 0xFFFF0000) | (c1 << 8) | c2;
+
+ m_bit_buf <<= -m_bits_left;
+
+ m_bits_left += 16;
+
+ assert(m_bits_left >= 0);
+ }
+ else
+ m_bit_buf <<= num_bits;
+
+ return i;
+ }
+
+ // Retrieves a variable number of bits from the input stream. Markers will not be read into the input bit buffer. Instead, an infinite number of all 1's will be returned when a marker is encountered.
+ inline uint jpeg_decoder::get_bits_no_markers(int num_bits)
+ {
+ if (!num_bits)
+ return 0;
+
+ assert(num_bits <= 16);
+
+ uint i = m_bit_buf >> (32 - num_bits);
+
+ if ((m_bits_left -= num_bits) <= 0)
+ {
+ m_bit_buf <<= (num_bits += m_bits_left);
+
+ if ((m_in_buf_left < 2) || (m_pIn_buf_ofs[0] == 0xFF) || (m_pIn_buf_ofs[1] == 0xFF))
+ {
+ uint c1 = get_octet();
+ uint c2 = get_octet();
+ m_bit_buf |= (c1 << 8) | c2;
+ }
+ else
+ {
+ m_bit_buf |= ((uint)m_pIn_buf_ofs[0] << 8) | m_pIn_buf_ofs[1];
+ m_in_buf_left -= 2;
+ m_pIn_buf_ofs += 2;
+ }
+
+ m_bit_buf <<= -m_bits_left;
+
+ m_bits_left += 16;
+
+ assert(m_bits_left >= 0);
+ }
+ else
+ m_bit_buf <<= num_bits;
+
+ return i;
+ }
+
+ // Decodes a Huffman encoded symbol.
+ inline int jpeg_decoder::huff_decode(huff_tables* pH)
+ {
+ if (!pH)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ int symbol;
+ // Check first 8-bits: do we have a complete symbol?
+ if ((symbol = pH->look_up[m_bit_buf >> 24]) < 0)
+ {
+ // Decode more bits, use a tree traversal to find symbol.
+ int ofs = 23;
+ do
+ {
+ unsigned int idx = -(int)(symbol + ((m_bit_buf >> ofs) & 1));
+
+ // This should never happen, but to be safe I'm turning these asserts into a run-time check.
+ if ((idx >= JPGD_HUFF_TREE_MAX_LENGTH) || (ofs < 0))
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ symbol = pH->tree[idx];
+ ofs--;
+ } while (symbol < 0);
+
+ get_bits_no_markers(8 + (23 - ofs));
+ }
+ else
+ {
+ assert(symbol < JPGD_HUFF_CODE_SIZE_MAX_LENGTH);
+ get_bits_no_markers(pH->code_size[symbol]);
+ }
+
+ return symbol;
+ }
+
+ // Decodes a Huffman encoded symbol.
+ inline int jpeg_decoder::huff_decode(huff_tables* pH, int& extra_bits)
+ {
+ int symbol;
+
+ if (!pH)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ // Check first 8-bits: do we have a complete symbol?
+ if ((symbol = pH->look_up2[m_bit_buf >> 24]) < 0)
+ {
+ // Use a tree traversal to find symbol.
+ int ofs = 23;
+ do
+ {
+ unsigned int idx = -(int)(symbol + ((m_bit_buf >> ofs) & 1));
+
+ // This should never happen, but to be safe I'm turning these asserts into a run-time check.
+ if ((idx >= JPGD_HUFF_TREE_MAX_LENGTH) || (ofs < 0))
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ symbol = pH->tree[idx];
+ ofs--;
+ } while (symbol < 0);
+
+ get_bits_no_markers(8 + (23 - ofs));
+
+ extra_bits = get_bits_no_markers(symbol & 0xF);
+ }
+ else
+ {
+ if (symbol & 0x8000)
+ {
+ //get_bits_no_markers((symbol >> 8) & 31);
+ assert(((symbol >> 8) & 31) <= 15);
+ get_bits_no_markers((symbol >> 8) & 15);
+ extra_bits = symbol >> 16;
+ }
+ else
+ {
+ int code_size = (symbol >> 8) & 31;
+ int num_extra_bits = symbol & 0xF;
+ int bits = code_size + num_extra_bits;
+
+ if (bits <= 16)
+ extra_bits = get_bits_no_markers(bits) & ((1 << num_extra_bits) - 1);
+ else
+ {
+ get_bits_no_markers(code_size);
+ extra_bits = get_bits_no_markers(num_extra_bits);
+ }
+ }
+
+ symbol &= 0xFF;
+ }
+
+ return symbol;
+ }
+
+ // Tables and macro used to fully decode the DPCM differences.
+ static const int s_extend_test[16] = { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
+ static const int s_extend_offset[16] = { 0, -1, -3, -7, -15, -31, -63, -127, -255, -511, -1023, -2047, -4095, -8191, -16383, -32767 };
+ //static const int s_extend_mask[] = { 0, (1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7), (1 << 8), (1 << 9), (1 << 10), (1 << 11), (1 << 12), (1 << 13), (1 << 14), (1 << 15), (1 << 16) };
+
+#define JPGD_HUFF_EXTEND(x, s) (((x) < s_extend_test[s & 15]) ? ((x) + s_extend_offset[s & 15]) : (x))
+
+ // Unconditionally frees all allocated m_blocks.
+ void jpeg_decoder::free_all_blocks()
+ {
+ m_pStream = nullptr;
+ for (mem_block* b = m_pMem_blocks; b; )
+ {
+ mem_block* n = b->m_pNext;
+ jpgd_free(b);
+ b = n;
+ }
+ m_pMem_blocks = nullptr;
+ }
+
+ // This method handles all errors. It will never return.
+ // It could easily be changed to use C++ exceptions.
+ JPGD_NORETURN void jpeg_decoder::stop_decoding(jpgd_status status)
+ {
+ m_error_code = status;
+ free_all_blocks();
+ longjmp(m_jmp_state, status);
+ }
+
+ void* jpeg_decoder::alloc(size_t nSize, bool zero)
+ {
+ nSize = (JPGD_MAX(nSize, 1) + 3) & ~3;
+ char* rv = nullptr;
+ for (mem_block* b = m_pMem_blocks; b; b = b->m_pNext)
+ {
+ if ((b->m_used_count + nSize) <= b->m_size)
+ {
+ rv = b->m_data + b->m_used_count;
+ b->m_used_count += nSize;
+ break;
+ }
+ }
+ if (!rv)
+ {
+ int capacity = JPGD_MAX(32768 - 256, ((int)nSize + 2047) & ~2047);
+ mem_block* b = (mem_block*)jpgd_malloc(sizeof(mem_block) + capacity);
+ if (!b)
+ {
+ stop_decoding(JPGD_NOTENOUGHMEM);
+ }
+
+ b->m_pNext = m_pMem_blocks;
+ m_pMem_blocks = b;
+ b->m_used_count = nSize;
+ b->m_size = capacity;
+ rv = b->m_data;
+ }
+ if (zero) memset(rv, 0, nSize);
+ return rv;
+ }
+
+ void jpeg_decoder::word_clear(void* p, uint16 c, uint n)
+ {
+ uint8* pD = (uint8*)p;
+ const uint8 l = c & 0xFF, h = (c >> 8) & 0xFF;
+ while (n)
+ {
+ pD[0] = l;
+ pD[1] = h;
+ pD += 2;
+ n--;
+ }
+ }
+
+ // Refill the input buffer.
+ // This method will sit in a loop until (A) the buffer is full or (B)
+ // the stream's read() method reports and end of file condition.
+ void jpeg_decoder::prep_in_buffer()
+ {
+ m_in_buf_left = 0;
+ m_pIn_buf_ofs = m_in_buf;
+
+ if (m_eof_flag)
+ return;
+
+ do
+ {
+ int bytes_read = m_pStream->read(m_in_buf + m_in_buf_left, JPGD_IN_BUF_SIZE - m_in_buf_left, &m_eof_flag);
+ if (bytes_read == -1)
+ stop_decoding(JPGD_STREAM_READ);
+
+ m_in_buf_left += bytes_read;
+ } while ((m_in_buf_left < JPGD_IN_BUF_SIZE) && (!m_eof_flag));
+
+ m_total_bytes_read += m_in_buf_left;
+
+ // Pad the end of the block with M_EOI (prevents the decompressor from going off the rails if the stream is invalid).
+ // (This dates way back to when this decompressor was written in C/asm, and the all-asm Huffman decoder did some fancy things to increase perf.)
+ word_clear(m_pIn_buf_ofs + m_in_buf_left, 0xD9FF, 64);
+ }
+
+ // Read a Huffman code table.
+ void jpeg_decoder::read_dht_marker()
+ {
+ int i, index, count;
+ uint8 huff_num[17];
+ uint8 huff_val[256];
+
+ uint num_left = get_bits(16);
+
+ if (num_left < 2)
+ stop_decoding(JPGD_BAD_DHT_MARKER);
+
+ num_left -= 2;
+
+ while (num_left)
+ {
+ index = get_bits(8);
+
+ huff_num[0] = 0;
+
+ count = 0;
+
+ for (i = 1; i <= 16; i++)
+ {
+ huff_num[i] = static_cast<uint8>(get_bits(8));
+ count += huff_num[i];
+ }
+
+ if (count > 255)
+ stop_decoding(JPGD_BAD_DHT_COUNTS);
+
+ bool symbol_present[256];
+ memset(symbol_present, 0, sizeof(symbol_present));
+
+ for (i = 0; i < count; i++)
+ {
+ const int s = get_bits(8);
+
+ // Check for obviously bogus tables.
+ if (symbol_present[s])
+ stop_decoding(JPGD_BAD_DHT_COUNTS);
+
+ huff_val[i] = static_cast<uint8_t>(s);
+ symbol_present[s] = true;
+ }
+
+ i = 1 + 16 + count;
+
+ if (num_left < (uint)i)
+ stop_decoding(JPGD_BAD_DHT_MARKER);
+
+ num_left -= i;
+
+ if ((index & 0x10) > 0x10)
+ stop_decoding(JPGD_BAD_DHT_INDEX);
+
+ index = (index & 0x0F) + ((index & 0x10) >> 4) * (JPGD_MAX_HUFF_TABLES >> 1);
+
+ if (index >= JPGD_MAX_HUFF_TABLES)
+ stop_decoding(JPGD_BAD_DHT_INDEX);
+
+ if (!m_huff_num[index])
+ m_huff_num[index] = (uint8*)alloc(17);
+
+ if (!m_huff_val[index])
+ m_huff_val[index] = (uint8*)alloc(256);
+
+ m_huff_ac[index] = (index & 0x10) != 0;
+ memcpy(m_huff_num[index], huff_num, 17);
+ memcpy(m_huff_val[index], huff_val, 256);
+ }
+ }
+
+ // Read a quantization table.
+ void jpeg_decoder::read_dqt_marker()
+ {
+ int n, i, prec;
+ uint num_left;
+ uint temp;
+
+ num_left = get_bits(16);
+
+ if (num_left < 2)
+ stop_decoding(JPGD_BAD_DQT_MARKER);
+
+ num_left -= 2;
+
+ while (num_left)
+ {
+ n = get_bits(8);
+ prec = n >> 4;
+ n &= 0x0F;
+
+ if (n >= JPGD_MAX_QUANT_TABLES)
+ stop_decoding(JPGD_BAD_DQT_TABLE);
+
+ if (!m_quant[n])
+ m_quant[n] = (jpgd_quant_t*)alloc(64 * sizeof(jpgd_quant_t));
+
+ // read quantization entries, in zag order
+ for (i = 0; i < 64; i++)
+ {
+ temp = get_bits(8);
+
+ if (prec)
+ temp = (temp << 8) + get_bits(8);
+
+ m_quant[n][i] = static_cast<jpgd_quant_t>(temp);
+ }
+
+ i = 64 + 1;
+
+ if (prec)
+ i += 64;
+
+ if (num_left < (uint)i)
+ stop_decoding(JPGD_BAD_DQT_LENGTH);
+
+ num_left -= i;
+ }
+ }
+
+ // Read the start of frame (SOF) marker.
+ void jpeg_decoder::read_sof_marker()
+ {
+ int i;
+ uint num_left;
+
+ num_left = get_bits(16);
+
+ /* precision: sorry, only 8-bit precision is supported */
+ if (get_bits(8) != 8)
+ stop_decoding(JPGD_BAD_PRECISION);
+
+ m_image_y_size = get_bits(16);
+
+ if ((m_image_y_size < 1) || (m_image_y_size > JPGD_MAX_HEIGHT))
+ stop_decoding(JPGD_BAD_HEIGHT);
+
+ m_image_x_size = get_bits(16);
+
+ if ((m_image_x_size < 1) || (m_image_x_size > JPGD_MAX_WIDTH))
+ stop_decoding(JPGD_BAD_WIDTH);
+
+ m_comps_in_frame = get_bits(8);
+
+ if (m_comps_in_frame > JPGD_MAX_COMPONENTS)
+ stop_decoding(JPGD_TOO_MANY_COMPONENTS);
+
+ if (num_left != (uint)(m_comps_in_frame * 3 + 8))
+ stop_decoding(JPGD_BAD_SOF_LENGTH);
+
+ for (i = 0; i < m_comps_in_frame; i++)
+ {
+ m_comp_ident[i] = get_bits(8);
+ m_comp_h_samp[i] = get_bits(4);
+ m_comp_v_samp[i] = get_bits(4);
+
+ if (!m_comp_h_samp[i] || !m_comp_v_samp[i] || (m_comp_h_samp[i] > 2) || (m_comp_v_samp[i] > 2))
+ stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
+
+ m_comp_quant[i] = get_bits(8);
+ if (m_comp_quant[i] >= JPGD_MAX_QUANT_TABLES)
+ stop_decoding(JPGD_DECODE_ERROR);
+ }
+ }
+
+ // Used to skip unrecognized markers.
+ void jpeg_decoder::skip_variable_marker()
+ {
+ uint num_left;
+
+ num_left = get_bits(16);
+
+ if (num_left < 2)
+ stop_decoding(JPGD_BAD_VARIABLE_MARKER);
+
+ num_left -= 2;
+
+ while (num_left)
+ {
+ get_bits(8);
+ num_left--;
+ }
+ }
+
+ // Read a define restart interval (DRI) marker.
+ void jpeg_decoder::read_dri_marker()
+ {
+ if (get_bits(16) != 4)
+ stop_decoding(JPGD_BAD_DRI_LENGTH);
+
+ m_restart_interval = get_bits(16);
+ }
+
+ // Read a start of scan (SOS) marker.
+ void jpeg_decoder::read_sos_marker()
+ {
+ uint num_left;
+ int i, ci, n, c, cc;
+
+ num_left = get_bits(16);
+
+ n = get_bits(8);
+
+ m_comps_in_scan = n;
+
+ num_left -= 3;
+
+ if ((num_left != (uint)(n * 2 + 3)) || (n < 1) || (n > JPGD_MAX_COMPS_IN_SCAN))
+ stop_decoding(JPGD_BAD_SOS_LENGTH);
+
+ for (i = 0; i < n; i++)
+ {
+ cc = get_bits(8);
+ c = get_bits(8);
+ num_left -= 2;
+
+ for (ci = 0; ci < m_comps_in_frame; ci++)
+ if (cc == m_comp_ident[ci])
+ break;
+
+ if (ci >= m_comps_in_frame)
+ stop_decoding(JPGD_BAD_SOS_COMP_ID);
+
+ if (ci >= JPGD_MAX_COMPONENTS)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ m_comp_list[i] = ci;
+
+ m_comp_dc_tab[ci] = (c >> 4) & 15;
+ m_comp_ac_tab[ci] = (c & 15) + (JPGD_MAX_HUFF_TABLES >> 1);
+
+ if (m_comp_dc_tab[ci] >= JPGD_MAX_HUFF_TABLES)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ if (m_comp_ac_tab[ci] >= JPGD_MAX_HUFF_TABLES)
+ stop_decoding(JPGD_DECODE_ERROR);
+ }
+
+ m_spectral_start = get_bits(8);
+ m_spectral_end = get_bits(8);
+ m_successive_high = get_bits(4);
+ m_successive_low = get_bits(4);
+
+ if (!m_progressive_flag)
+ {
+ m_spectral_start = 0;
+ m_spectral_end = 63;
+ }
+
+ num_left -= 3;
+
+ /* read past whatever is num_left */
+ while (num_left)
+ {
+ get_bits(8);
+ num_left--;
+ }
+ }
+
+ // Finds the next marker.
+ int jpeg_decoder::next_marker()
+ {
+ uint c, bytes;
+
+ bytes = 0;
+
+ do
+ {
+ do
+ {
+ bytes++;
+ c = get_bits(8);
+ } while (c != 0xFF);
+
+ do
+ {
+ c = get_bits(8);
+ } while (c == 0xFF);
+
+ } while (c == 0);
+
+ // If bytes > 0 here, there where extra bytes before the marker (not good).
+
+ return c;
+ }
+
+ // Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is
+ // encountered.
+ int jpeg_decoder::process_markers()
+ {
+ int c;
+
+ for (; ; )
+ {
+ c = next_marker();
+
+ switch (c)
+ {
+ case M_SOF0:
+ case M_SOF1:
+ case M_SOF2:
+ case M_SOF3:
+ case M_SOF5:
+ case M_SOF6:
+ case M_SOF7:
+ // case M_JPG:
+ case M_SOF9:
+ case M_SOF10:
+ case M_SOF11:
+ case M_SOF13:
+ case M_SOF14:
+ case M_SOF15:
+ case M_SOI:
+ case M_EOI:
+ case M_SOS:
+ {
+ return c;
+ }
+ case M_DHT:
+ {
+ read_dht_marker();
+ break;
+ }
+ // No arithmitic support - dumb patents!
+ case M_DAC:
+ {
+ stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT);
+ break;
+ }
+ case M_DQT:
+ {
+ read_dqt_marker();
+ break;
+ }
+ case M_DRI:
+ {
+ read_dri_marker();
+ break;
+ }
+ //case M_APP0: /* no need to read the JFIF marker */
+ case M_JPG:
+ case M_RST0: /* no parameters */
+ case M_RST1:
+ case M_RST2:
+ case M_RST3:
+ case M_RST4:
+ case M_RST5:
+ case M_RST6:
+ case M_RST7:
+ case M_TEM:
+ {
+ stop_decoding(JPGD_UNEXPECTED_MARKER);
+ break;
+ }
+ default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */
+ {
+ skip_variable_marker();
+ break;
+ }
+ }
+ }
+ }
+
+ // Finds the start of image (SOI) marker.
+ void jpeg_decoder::locate_soi_marker()
+ {
+ uint lastchar, thischar;
+ uint bytesleft;
+
+ lastchar = get_bits(8);
+
+ thischar = get_bits(8);
+
+ /* ok if it's a normal JPEG file without a special header */
+
+ if ((lastchar == 0xFF) && (thischar == M_SOI))
+ return;
+
+ bytesleft = 4096;
+
+ for (; ; )
+ {
+ if (--bytesleft == 0)
+ stop_decoding(JPGD_NOT_JPEG);
+
+ lastchar = thischar;
+
+ thischar = get_bits(8);
+
+ if (lastchar == 0xFF)
+ {
+ if (thischar == M_SOI)
+ break;
+ else if (thischar == M_EOI) // get_bits will keep returning M_EOI if we read past the end
+ stop_decoding(JPGD_NOT_JPEG);
+ }
+ }
+
+ // Check the next character after marker: if it's not 0xFF, it can't be the start of the next marker, so the file is bad.
+ thischar = (m_bit_buf >> 24) & 0xFF;
+
+ if (thischar != 0xFF)
+ stop_decoding(JPGD_NOT_JPEG);
+ }
+
+ // Find a start of frame (SOF) marker.
+ void jpeg_decoder::locate_sof_marker()
+ {
+ locate_soi_marker();
+
+ int c = process_markers();
+
+ switch (c)
+ {
+ case M_SOF2:
+ {
+ m_progressive_flag = JPGD_TRUE;
+ read_sof_marker();
+ break;
+ }
+ case M_SOF0: /* baseline DCT */
+ case M_SOF1: /* extended sequential DCT */
+ {
+ read_sof_marker();
+ break;
+ }
+ case M_SOF9: /* Arithmitic coding */
+ {
+ stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT);
+ break;
+ }
+ default:
+ {
+ stop_decoding(JPGD_UNSUPPORTED_MARKER);
+ break;
+ }
+ }
+ }
+
+ // Find a start of scan (SOS) marker.
+ int jpeg_decoder::locate_sos_marker()
+ {
+ int c;
+
+ c = process_markers();
+
+ if (c == M_EOI)
+ return JPGD_FALSE;
+ else if (c != M_SOS)
+ stop_decoding(JPGD_UNEXPECTED_MARKER);
+
+ read_sos_marker();
+
+ return JPGD_TRUE;
+ }
+
+ // Reset everything to default/uninitialized state.
+ void jpeg_decoder::init(jpeg_decoder_stream* pStream, uint32_t flags)
+ {
+ m_flags = flags;
+ m_pMem_blocks = nullptr;
+ m_error_code = JPGD_SUCCESS;
+ m_ready_flag = false;
+ m_image_x_size = m_image_y_size = 0;
+ m_pStream = pStream;
+ m_progressive_flag = JPGD_FALSE;
+
+ memset(m_huff_ac, 0, sizeof(m_huff_ac));
+ memset(m_huff_num, 0, sizeof(m_huff_num));
+ memset(m_huff_val, 0, sizeof(m_huff_val));
+ memset(m_quant, 0, sizeof(m_quant));
+
+ m_scan_type = 0;
+ m_comps_in_frame = 0;
+
+ memset(m_comp_h_samp, 0, sizeof(m_comp_h_samp));
+ memset(m_comp_v_samp, 0, sizeof(m_comp_v_samp));
+ memset(m_comp_quant, 0, sizeof(m_comp_quant));
+ memset(m_comp_ident, 0, sizeof(m_comp_ident));
+ memset(m_comp_h_blocks, 0, sizeof(m_comp_h_blocks));
+ memset(m_comp_v_blocks, 0, sizeof(m_comp_v_blocks));
+
+ m_comps_in_scan = 0;
+ memset(m_comp_list, 0, sizeof(m_comp_list));
+ memset(m_comp_dc_tab, 0, sizeof(m_comp_dc_tab));
+ memset(m_comp_ac_tab, 0, sizeof(m_comp_ac_tab));
+
+ m_spectral_start = 0;
+ m_spectral_end = 0;
+ m_successive_low = 0;
+ m_successive_high = 0;
+ m_max_mcu_x_size = 0;
+ m_max_mcu_y_size = 0;
+ m_blocks_per_mcu = 0;
+ m_max_blocks_per_row = 0;
+ m_mcus_per_row = 0;
+ m_mcus_per_col = 0;
+
+ memset(m_mcu_org, 0, sizeof(m_mcu_org));
+
+ m_total_lines_left = 0;
+ m_mcu_lines_left = 0;
+ m_num_buffered_scanlines = 0;
+ m_real_dest_bytes_per_scan_line = 0;
+ m_dest_bytes_per_scan_line = 0;
+ m_dest_bytes_per_pixel = 0;
+
+ memset(m_pHuff_tabs, 0, sizeof(m_pHuff_tabs));
+
+ memset(m_dc_coeffs, 0, sizeof(m_dc_coeffs));
+ memset(m_ac_coeffs, 0, sizeof(m_ac_coeffs));
+ memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu));
+
+ m_eob_run = 0;
+
+ m_pIn_buf_ofs = m_in_buf;
+ m_in_buf_left = 0;
+ m_eof_flag = false;
+ m_tem_flag = 0;
+
+ memset(m_in_buf_pad_start, 0, sizeof(m_in_buf_pad_start));
+ memset(m_in_buf, 0, sizeof(m_in_buf));
+ memset(m_in_buf_pad_end, 0, sizeof(m_in_buf_pad_end));
+
+ m_restart_interval = 0;
+ m_restarts_left = 0;
+ m_next_restart_num = 0;
+
+ m_max_mcus_per_row = 0;
+ m_max_blocks_per_mcu = 0;
+ m_max_mcus_per_col = 0;
+
+ memset(m_last_dc_val, 0, sizeof(m_last_dc_val));
+ m_pMCU_coefficients = nullptr;
+ m_pSample_buf = nullptr;
+ m_pSample_buf_prev = nullptr;
+ m_sample_buf_prev_valid = false;
+
+ m_total_bytes_read = 0;
+
+ m_pScan_line_0 = nullptr;
+ m_pScan_line_1 = nullptr;
+
+ // Ready the input buffer.
+ prep_in_buffer();
+
+ // Prime the bit buffer.
+ m_bits_left = 16;
+ m_bit_buf = 0;
+
+ get_bits(16);
+ get_bits(16);
+
+ for (int i = 0; i < JPGD_MAX_BLOCKS_PER_MCU; i++)
+ m_mcu_block_max_zag[i] = 64;
+ }
+
+#define SCALEBITS 16
+#define ONE_HALF ((int) 1 << (SCALEBITS-1))
+#define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5f))
+
+ // Create a few tables that allow us to quickly convert YCbCr to RGB.
+ void jpeg_decoder::create_look_ups()
+ {
+ for (int i = 0; i <= 255; i++)
+ {
+ int k = i - 128;
+ m_crr[i] = (FIX(1.40200f) * k + ONE_HALF) >> SCALEBITS;
+ m_cbb[i] = (FIX(1.77200f) * k + ONE_HALF) >> SCALEBITS;
+ m_crg[i] = (-FIX(0.71414f)) * k;
+ m_cbg[i] = (-FIX(0.34414f)) * k + ONE_HALF;
+ }
+ }
+
+ // This method throws back into the stream any bytes that where read
+ // into the bit buffer during initial marker scanning.
+ void jpeg_decoder::fix_in_buffer()
+ {
+ // In case any 0xFF's where pulled into the buffer during marker scanning.
+ assert((m_bits_left & 7) == 0);
+
+ if (m_bits_left == 16)
+ stuff_char((uint8)(m_bit_buf & 0xFF));
+
+ if (m_bits_left >= 8)
+ stuff_char((uint8)((m_bit_buf >> 8) & 0xFF));
+
+ stuff_char((uint8)((m_bit_buf >> 16) & 0xFF));
+ stuff_char((uint8)((m_bit_buf >> 24) & 0xFF));
+
+ m_bits_left = 16;
+ get_bits_no_markers(16);
+ get_bits_no_markers(16);
+ }
+
+ void jpeg_decoder::transform_mcu(int mcu_row)
+ {
+ jpgd_block_t* pSrc_ptr = m_pMCU_coefficients;
+ if (mcu_row * m_blocks_per_mcu >= m_max_blocks_per_row)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ uint8* pDst_ptr = m_pSample_buf + mcu_row * m_blocks_per_mcu * 64;
+
+ for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
+ {
+ idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]);
+ pSrc_ptr += 64;
+ pDst_ptr += 64;
+ }
+ }
+
+ // Loads and dequantizes the next row of (already decoded) coefficients.
+ // Progressive images only.
+ void jpeg_decoder::load_next_row()
+ {
+ int i;
+ jpgd_block_t* p;
+ jpgd_quant_t* q;
+ int mcu_row, mcu_block, row_block = 0;
+ int component_num, component_id;
+ int block_x_mcu[JPGD_MAX_COMPONENTS];
+
+ memset(block_x_mcu, 0, JPGD_MAX_COMPONENTS * sizeof(int));
+
+ for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
+ {
+ int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0;
+
+ for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
+ {
+ component_id = m_mcu_org[mcu_block];
+ if (m_comp_quant[component_id] >= JPGD_MAX_QUANT_TABLES)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ q = m_quant[m_comp_quant[component_id]];
+
+ p = m_pMCU_coefficients + 64 * mcu_block;
+
+ jpgd_block_t* pAC = coeff_buf_getp(m_ac_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
+ jpgd_block_t* pDC = coeff_buf_getp(m_dc_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
+ p[0] = pDC[0];
+ memcpy(&p[1], &pAC[1], 63 * sizeof(jpgd_block_t));
+
+ for (i = 63; i > 0; i--)
+ if (p[g_ZAG[i]])
+ break;
+
+ m_mcu_block_max_zag[mcu_block] = i + 1;
+
+ for (; i >= 0; i--)
+ if (p[g_ZAG[i]])
+ p[g_ZAG[i]] = static_cast<jpgd_block_t>(p[g_ZAG[i]] * q[i]);
+
+ row_block++;
+
+ if (m_comps_in_scan == 1)
+ block_x_mcu[component_id]++;
+ else
+ {
+ if (++block_x_mcu_ofs == m_comp_h_samp[component_id])
+ {
+ block_x_mcu_ofs = 0;
+
+ if (++block_y_mcu_ofs == m_comp_v_samp[component_id])
+ {
+ block_y_mcu_ofs = 0;
+
+ block_x_mcu[component_id] += m_comp_h_samp[component_id];
+ }
+ }
+ }
+ }
+
+ transform_mcu(mcu_row);
+ }
+
+ if (m_comps_in_scan == 1)
+ m_block_y_mcu[m_comp_list[0]]++;
+ else
+ {
+ for (component_num = 0; component_num < m_comps_in_scan; component_num++)
+ {
+ component_id = m_comp_list[component_num];
+
+ m_block_y_mcu[component_id] += m_comp_v_samp[component_id];
+ }
+ }
+ }
+
+ // Restart interval processing.
+ void jpeg_decoder::process_restart()
+ {
+ int i;
+ int c = 0;
+
+ // Align to a byte boundry
+ // FIXME: Is this really necessary? get_bits_no_markers() never reads in markers!
+ //get_bits_no_markers(m_bits_left & 7);
+
+ // Let's scan a little bit to find the marker, but not _too_ far.
+ // 1536 is a "fudge factor" that determines how much to scan.
+ for (i = 1536; i > 0; i--)
+ if (get_char() == 0xFF)
+ break;
+
+ if (i == 0)
+ stop_decoding(JPGD_BAD_RESTART_MARKER);
+
+ for (; i > 0; i--)
+ if ((c = get_char()) != 0xFF)
+ break;
+
+ if (i == 0)
+ stop_decoding(JPGD_BAD_RESTART_MARKER);
+
+ // Is it the expected marker? If not, something bad happened.
+ if (c != (m_next_restart_num + M_RST0))
+ stop_decoding(JPGD_BAD_RESTART_MARKER);
+
+ // Reset each component's DC prediction values.
+ memset(&m_last_dc_val, 0, m_comps_in_frame * sizeof(uint));
+
+ m_eob_run = 0;
+
+ m_restarts_left = m_restart_interval;
+
+ m_next_restart_num = (m_next_restart_num + 1) & 7;
+
+ // Get the bit buffer going again...
+
+ m_bits_left = 16;
+ get_bits_no_markers(16);
+ get_bits_no_markers(16);
+ }
+
+ static inline int dequantize_ac(int c, int q) { c *= q; return c; }
+
+ // Decodes and dequantizes the next row of coefficients.
+ void jpeg_decoder::decode_next_row()
+ {
+ int row_block = 0;
+
+ for (int mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
+ {
+ if ((m_restart_interval) && (m_restarts_left == 0))
+ process_restart();
+
+ jpgd_block_t* p = m_pMCU_coefficients;
+ for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++, p += 64)
+ {
+ int component_id = m_mcu_org[mcu_block];
+ if (m_comp_quant[component_id] >= JPGD_MAX_QUANT_TABLES)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ jpgd_quant_t* q = m_quant[m_comp_quant[component_id]];
+
+ int r, s;
+ s = huff_decode(m_pHuff_tabs[m_comp_dc_tab[component_id]], r);
+ if (s >= 16)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ s = JPGD_HUFF_EXTEND(r, s);
+
+ m_last_dc_val[component_id] = (s += m_last_dc_val[component_id]);
+
+ p[0] = static_cast<jpgd_block_t>(s * q[0]);
+
+ int prev_num_set = m_mcu_block_max_zag[mcu_block];
+
+ huff_tables* pH = m_pHuff_tabs[m_comp_ac_tab[component_id]];
+
+ int k;
+ for (k = 1; k < 64; k++)
+ {
+ int extra_bits;
+ s = huff_decode(pH, extra_bits);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s)
+ {
+ if (r)
+ {
+ if ((k + r) > 63)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ if (k < prev_num_set)
+ {
+ int n = JPGD_MIN(r, prev_num_set - k);
+ int kt = k;
+ while (n--)
+ p[g_ZAG[kt++]] = 0;
+ }
+
+ k += r;
+ }
+
+ s = JPGD_HUFF_EXTEND(extra_bits, s);
+
+ if (k >= 64)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ p[g_ZAG[k]] = static_cast<jpgd_block_t>(dequantize_ac(s, q[k])); //s * q[k];
+ }
+ else
+ {
+ if (r == 15)
+ {
+ if ((k + 16) > 64)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ if (k < prev_num_set)
+ {
+ int n = JPGD_MIN(16, prev_num_set - k);
+ int kt = k;
+ while (n--)
+ {
+ if (kt > 63)
+ stop_decoding(JPGD_DECODE_ERROR);
+ p[g_ZAG[kt++]] = 0;
+ }
+ }
+
+ k += 16 - 1; // - 1 because the loop counter is k
+
+ if (p[g_ZAG[k & 63]] != 0)
+ stop_decoding(JPGD_DECODE_ERROR);
+ }
+ else
+ break;
+ }
+ }
+
+ if (k < prev_num_set)
+ {
+ int kt = k;
+ while (kt < prev_num_set)
+ p[g_ZAG[kt++]] = 0;
+ }
+
+ m_mcu_block_max_zag[mcu_block] = k;
+
+ row_block++;
+ }
+
+ transform_mcu(mcu_row);
+
+ m_restarts_left--;
+ }
+ }
+
+ // YCbCr H1V1 (1x1:1:1, 3 m_blocks per MCU) to RGB
+ void jpeg_decoder::H1V1Convert()
+ {
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8* d = m_pScan_line_0;
+ uint8* s = m_pSample_buf + row * 8;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ int y = s[j];
+ int cb = s[64 + j];
+ int cr = s[128 + j];
+
+ d[0] = clamp(y + m_crr[cr]);
+ d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
+ d[2] = clamp(y + m_cbb[cb]);
+ d[3] = 255;
+
+ d += 4;
+ }
+
+ s += 64 * 3;
+ }
+ }
+
+ // YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB
+ void jpeg_decoder::H2V1Convert()
+ {
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8* d0 = m_pScan_line_0;
+ uint8* y = m_pSample_buf + row * 8;
+ uint8* c = m_pSample_buf + 2 * 64 + row * 8;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ for (int l = 0; l < 2; l++)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ int cb = c[0];
+ int cr = c[64];
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ int yy = y[j << 1];
+ d0[0] = clamp(yy + rc);
+ d0[1] = clamp(yy + gc);
+ d0[2] = clamp(yy + bc);
+ d0[3] = 255;
+
+ yy = y[(j << 1) + 1];
+ d0[4] = clamp(yy + rc);
+ d0[5] = clamp(yy + gc);
+ d0[6] = clamp(yy + bc);
+ d0[7] = 255;
+
+ d0 += 8;
+
+ c++;
+ }
+ y += 64;
+ }
+
+ y += 64 * 4 - 64 * 2;
+ c += 64 * 4 - 8;
+ }
+ }
+
+ // YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB
+ void jpeg_decoder::H2V1ConvertFiltered()
+ {
+ const uint BLOCKS_PER_MCU = 4;
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8* d0 = m_pScan_line_0;
+
+ const int half_image_x_size = (m_image_x_size >> 1) - 1;
+ const int row_x8 = row * 8;
+
+ for (int x = 0; x < m_image_x_size; x++)
+ {
+ int y = m_pSample_buf[check_sample_buf_ofs((x >> 4) * BLOCKS_PER_MCU * 64 + ((x & 8) ? 64 : 0) + (x & 7) + row_x8)];
+
+ int c_x0 = (x - 1) >> 1;
+ int c_x1 = JPGD_MIN(c_x0 + 1, half_image_x_size);
+ c_x0 = JPGD_MAX(c_x0, 0);
+
+ int a = (c_x0 >> 3) * BLOCKS_PER_MCU * 64 + (c_x0 & 7) + row_x8 + 128;
+ int cb0 = m_pSample_buf[check_sample_buf_ofs(a)];
+ int cr0 = m_pSample_buf[check_sample_buf_ofs(a + 64)];
+
+ int b = (c_x1 >> 3) * BLOCKS_PER_MCU * 64 + (c_x1 & 7) + row_x8 + 128;
+ int cb1 = m_pSample_buf[check_sample_buf_ofs(b)];
+ int cr1 = m_pSample_buf[check_sample_buf_ofs(b + 64)];
+
+ int w0 = (x & 1) ? 3 : 1;
+ int w1 = (x & 1) ? 1 : 3;
+
+ int cb = (cb0 * w0 + cb1 * w1 + 2) >> 2;
+ int cr = (cr0 * w0 + cr1 * w1 + 2) >> 2;
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ d0[0] = clamp(y + rc);
+ d0[1] = clamp(y + gc);
+ d0[2] = clamp(y + bc);
+ d0[3] = 255;
+
+ d0 += 4;
+ }
+ }
+
+ // YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB
+ void jpeg_decoder::H1V2Convert()
+ {
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8* d0 = m_pScan_line_0;
+ uint8* d1 = m_pScan_line_1;
+ uint8* y;
+ uint8* c;
+
+ if (row < 8)
+ y = m_pSample_buf + row * 8;
+ else
+ y = m_pSample_buf + 64 * 1 + (row & 7) * 8;
+
+ c = m_pSample_buf + 64 * 2 + (row >> 1) * 8;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ int cb = c[0 + j];
+ int cr = c[64 + j];
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ int yy = y[j];
+ d0[0] = clamp(yy + rc);
+ d0[1] = clamp(yy + gc);
+ d0[2] = clamp(yy + bc);
+ d0[3] = 255;
+
+ yy = y[8 + j];
+ d1[0] = clamp(yy + rc);
+ d1[1] = clamp(yy + gc);
+ d1[2] = clamp(yy + bc);
+ d1[3] = 255;
+
+ d0 += 4;
+ d1 += 4;
+ }
+
+ y += 64 * 4;
+ c += 64 * 4;
+ }
+ }
+
+ // YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB
+ void jpeg_decoder::H1V2ConvertFiltered()
+ {
+ const uint BLOCKS_PER_MCU = 4;
+ int y = m_image_y_size - m_total_lines_left;
+ int row = y & 15;
+
+ const int half_image_y_size = (m_image_y_size >> 1) - 1;
+
+ uint8* d0 = m_pScan_line_0;
+
+ const int w0 = (row & 1) ? 3 : 1;
+ const int w1 = (row & 1) ? 1 : 3;
+
+ int c_y0 = (y - 1) >> 1;
+ int c_y1 = JPGD_MIN(c_y0 + 1, half_image_y_size);
+
+ const uint8_t* p_YSamples = m_pSample_buf;
+ const uint8_t* p_C0Samples = m_pSample_buf;
+ if ((c_y0 >= 0) && (((row & 15) == 0) || ((row & 15) == 15)) && (m_total_lines_left > 1))
+ {
+ assert(y > 0);
+ assert(m_sample_buf_prev_valid);
+
+ if ((row & 15) == 15)
+ p_YSamples = m_pSample_buf_prev;
+
+ p_C0Samples = m_pSample_buf_prev;
+ }
+
+ const int y_sample_base_ofs = ((row & 8) ? 64 : 0) + (row & 7) * 8;
+ const int y0_base = (c_y0 & 7) * 8 + 128;
+ const int y1_base = (c_y1 & 7) * 8 + 128;
+
+ for (int x = 0; x < m_image_x_size; x++)
+ {
+ const int base_ofs = (x >> 3) * BLOCKS_PER_MCU * 64 + (x & 7);
+
+ int y_sample = p_YSamples[check_sample_buf_ofs(base_ofs + y_sample_base_ofs)];
+
+ int a = base_ofs + y0_base;
+ int cb0_sample = p_C0Samples[check_sample_buf_ofs(a)];
+ int cr0_sample = p_C0Samples[check_sample_buf_ofs(a + 64)];
+
+ int b = base_ofs + y1_base;
+ int cb1_sample = m_pSample_buf[check_sample_buf_ofs(b)];
+ int cr1_sample = m_pSample_buf[check_sample_buf_ofs(b + 64)];
+
+ int cb = (cb0_sample * w0 + cb1_sample * w1 + 2) >> 2;
+ int cr = (cr0_sample * w0 + cr1_sample * w1 + 2) >> 2;
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ d0[0] = clamp(y_sample + rc);
+ d0[1] = clamp(y_sample + gc);
+ d0[2] = clamp(y_sample + bc);
+ d0[3] = 255;
+
+ d0 += 4;
+ }
+ }
+
+ // YCbCr H2V2 (2x2:1:1, 6 m_blocks per MCU) to RGB
+ void jpeg_decoder::H2V2Convert()
+ {
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8* d0 = m_pScan_line_0;
+ uint8* d1 = m_pScan_line_1;
+ uint8* y;
+ uint8* c;
+
+ if (row < 8)
+ y = m_pSample_buf + row * 8;
+ else
+ y = m_pSample_buf + 64 * 2 + (row & 7) * 8;
+
+ c = m_pSample_buf + 64 * 4 + (row >> 1) * 8;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ for (int l = 0; l < 2; l++)
+ {
+ for (int j = 0; j < 8; j += 2)
+ {
+ int cb = c[0];
+ int cr = c[64];
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ int yy = y[j];
+ d0[0] = clamp(yy + rc);
+ d0[1] = clamp(yy + gc);
+ d0[2] = clamp(yy + bc);
+ d0[3] = 255;
+
+ yy = y[j + 1];
+ d0[4] = clamp(yy + rc);
+ d0[5] = clamp(yy + gc);
+ d0[6] = clamp(yy + bc);
+ d0[7] = 255;
+
+ yy = y[j + 8];
+ d1[0] = clamp(yy + rc);
+ d1[1] = clamp(yy + gc);
+ d1[2] = clamp(yy + bc);
+ d1[3] = 255;
+
+ yy = y[j + 8 + 1];
+ d1[4] = clamp(yy + rc);
+ d1[5] = clamp(yy + gc);
+ d1[6] = clamp(yy + bc);
+ d1[7] = 255;
+
+ d0 += 8;
+ d1 += 8;
+
+ c++;
+ }
+ y += 64;
+ }
+
+ y += 64 * 6 - 64 * 2;
+ c += 64 * 6 - 8;
+ }
+ }
+
+ uint32_t jpeg_decoder::H2V2ConvertFiltered()
+ {
+ const uint BLOCKS_PER_MCU = 6;
+ int y = m_image_y_size - m_total_lines_left;
+ int row = y & 15;
+
+ const int half_image_y_size = (m_image_y_size >> 1) - 1;
+
+ uint8* d0 = m_pScan_line_0;
+
+ int c_y0 = (y - 1) >> 1;
+ int c_y1 = JPGD_MIN(c_y0 + 1, half_image_y_size);
+
+ const uint8_t* p_YSamples = m_pSample_buf;
+ const uint8_t* p_C0Samples = m_pSample_buf;
+ if ((c_y0 >= 0) && (((row & 15) == 0) || ((row & 15) == 15)) && (m_total_lines_left > 1))
+ {
+ assert(y > 0);
+ assert(m_sample_buf_prev_valid);
+
+ if ((row & 15) == 15)
+ p_YSamples = m_pSample_buf_prev;
+
+ p_C0Samples = m_pSample_buf_prev;
+ }
+
+ const int y_sample_base_ofs = ((row & 8) ? 128 : 0) + (row & 7) * 8;
+ const int y0_base = (c_y0 & 7) * 8 + 256;
+ const int y1_base = (c_y1 & 7) * 8 + 256;
+
+ const int half_image_x_size = (m_image_x_size >> 1) - 1;
+
+ static const uint8_t s_muls[2][2][4] =
+ {
+ { { 1, 3, 3, 9 }, { 3, 9, 1, 3 }, },
+ { { 3, 1, 9, 3 }, { 9, 3, 3, 1 } }
+ };
+
+ if (((row & 15) >= 1) && ((row & 15) <= 14))
+ {
+ assert((row & 1) == 1);
+ assert(((y + 1 - 1) >> 1) == c_y0);
+
+ assert(p_YSamples == m_pSample_buf);
+ assert(p_C0Samples == m_pSample_buf);
+
+ uint8* d1 = m_pScan_line_1;
+ const int y_sample_base_ofs1 = (((row + 1) & 8) ? 128 : 0) + ((row + 1) & 7) * 8;
+
+ for (int x = 0; x < m_image_x_size; x++)
+ {
+ int k = (x >> 4) * BLOCKS_PER_MCU * 64 + ((x & 8) ? 64 : 0) + (x & 7);
+ int y_sample0 = p_YSamples[check_sample_buf_ofs(k + y_sample_base_ofs)];
+ int y_sample1 = p_YSamples[check_sample_buf_ofs(k + y_sample_base_ofs1)];
+
+ int c_x0 = (x - 1) >> 1;
+ int c_x1 = JPGD_MIN(c_x0 + 1, half_image_x_size);
+ c_x0 = JPGD_MAX(c_x0, 0);
+
+ int a = (c_x0 >> 3) * BLOCKS_PER_MCU * 64 + (c_x0 & 7);
+ int cb00_sample = p_C0Samples[check_sample_buf_ofs(a + y0_base)];
+ int cr00_sample = p_C0Samples[check_sample_buf_ofs(a + y0_base + 64)];
+
+ int cb01_sample = m_pSample_buf[check_sample_buf_ofs(a + y1_base)];
+ int cr01_sample = m_pSample_buf[check_sample_buf_ofs(a + y1_base + 64)];
+
+ int b = (c_x1 >> 3) * BLOCKS_PER_MCU * 64 + (c_x1 & 7);
+ int cb10_sample = p_C0Samples[check_sample_buf_ofs(b + y0_base)];
+ int cr10_sample = p_C0Samples[check_sample_buf_ofs(b + y0_base + 64)];
+
+ int cb11_sample = m_pSample_buf[check_sample_buf_ofs(b + y1_base)];
+ int cr11_sample = m_pSample_buf[check_sample_buf_ofs(b + y1_base + 64)];
+
+ {
+ const uint8_t* pMuls = &s_muls[row & 1][x & 1][0];
+ int cb = (cb00_sample * pMuls[0] + cb01_sample * pMuls[1] + cb10_sample * pMuls[2] + cb11_sample * pMuls[3] + 8) >> 4;
+ int cr = (cr00_sample * pMuls[0] + cr01_sample * pMuls[1] + cr10_sample * pMuls[2] + cr11_sample * pMuls[3] + 8) >> 4;
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ d0[0] = clamp(y_sample0 + rc);
+ d0[1] = clamp(y_sample0 + gc);
+ d0[2] = clamp(y_sample0 + bc);
+ d0[3] = 255;
+
+ d0 += 4;
+ }
+
+ {
+ const uint8_t* pMuls = &s_muls[(row + 1) & 1][x & 1][0];
+ int cb = (cb00_sample * pMuls[0] + cb01_sample * pMuls[1] + cb10_sample * pMuls[2] + cb11_sample * pMuls[3] + 8) >> 4;
+ int cr = (cr00_sample * pMuls[0] + cr01_sample * pMuls[1] + cr10_sample * pMuls[2] + cr11_sample * pMuls[3] + 8) >> 4;
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ d1[0] = clamp(y_sample1 + rc);
+ d1[1] = clamp(y_sample1 + gc);
+ d1[2] = clamp(y_sample1 + bc);
+ d1[3] = 255;
+
+ d1 += 4;
+ }
+
+ if (((x & 1) == 1) && (x < m_image_x_size - 1))
+ {
+ const int nx = x + 1;
+ assert(c_x0 == (nx - 1) >> 1);
+
+ k = (nx >> 4) * BLOCKS_PER_MCU * 64 + ((nx & 8) ? 64 : 0) + (nx & 7);
+ y_sample0 = p_YSamples[check_sample_buf_ofs(k + y_sample_base_ofs)];
+ y_sample1 = p_YSamples[check_sample_buf_ofs(k + y_sample_base_ofs1)];
+
+ {
+ const uint8_t* pMuls = &s_muls[row & 1][nx & 1][0];
+ int cb = (cb00_sample * pMuls[0] + cb01_sample * pMuls[1] + cb10_sample * pMuls[2] + cb11_sample * pMuls[3] + 8) >> 4;
+ int cr = (cr00_sample * pMuls[0] + cr01_sample * pMuls[1] + cr10_sample * pMuls[2] + cr11_sample * pMuls[3] + 8) >> 4;
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ d0[0] = clamp(y_sample0 + rc);
+ d0[1] = clamp(y_sample0 + gc);
+ d0[2] = clamp(y_sample0 + bc);
+ d0[3] = 255;
+
+ d0 += 4;
+ }
+
+ {
+ const uint8_t* pMuls = &s_muls[(row + 1) & 1][nx & 1][0];
+ int cb = (cb00_sample * pMuls[0] + cb01_sample * pMuls[1] + cb10_sample * pMuls[2] + cb11_sample * pMuls[3] + 8) >> 4;
+ int cr = (cr00_sample * pMuls[0] + cr01_sample * pMuls[1] + cr10_sample * pMuls[2] + cr11_sample * pMuls[3] + 8) >> 4;
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ d1[0] = clamp(y_sample1 + rc);
+ d1[1] = clamp(y_sample1 + gc);
+ d1[2] = clamp(y_sample1 + bc);
+ d1[3] = 255;
+
+ d1 += 4;
+ }
+
+ ++x;
+ }
+ }
+
+ return 2;
+ }
+ else
+ {
+ for (int x = 0; x < m_image_x_size; x++)
+ {
+ int y_sample = p_YSamples[check_sample_buf_ofs((x >> 4) * BLOCKS_PER_MCU * 64 + ((x & 8) ? 64 : 0) + (x & 7) + y_sample_base_ofs)];
+
+ int c_x0 = (x - 1) >> 1;
+ int c_x1 = JPGD_MIN(c_x0 + 1, half_image_x_size);
+ c_x0 = JPGD_MAX(c_x0, 0);
+
+ int a = (c_x0 >> 3) * BLOCKS_PER_MCU * 64 + (c_x0 & 7);
+ int cb00_sample = p_C0Samples[check_sample_buf_ofs(a + y0_base)];
+ int cr00_sample = p_C0Samples[check_sample_buf_ofs(a + y0_base + 64)];
+
+ int cb01_sample = m_pSample_buf[check_sample_buf_ofs(a + y1_base)];
+ int cr01_sample = m_pSample_buf[check_sample_buf_ofs(a + y1_base + 64)];
+
+ int b = (c_x1 >> 3) * BLOCKS_PER_MCU * 64 + (c_x1 & 7);
+ int cb10_sample = p_C0Samples[check_sample_buf_ofs(b + y0_base)];
+ int cr10_sample = p_C0Samples[check_sample_buf_ofs(b + y0_base + 64)];
+
+ int cb11_sample = m_pSample_buf[check_sample_buf_ofs(b + y1_base)];
+ int cr11_sample = m_pSample_buf[check_sample_buf_ofs(b + y1_base + 64)];
+
+ const uint8_t* pMuls = &s_muls[row & 1][x & 1][0];
+ int cb = (cb00_sample * pMuls[0] + cb01_sample * pMuls[1] + cb10_sample * pMuls[2] + cb11_sample * pMuls[3] + 8) >> 4;
+ int cr = (cr00_sample * pMuls[0] + cr01_sample * pMuls[1] + cr10_sample * pMuls[2] + cr11_sample * pMuls[3] + 8) >> 4;
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ d0[0] = clamp(y_sample + rc);
+ d0[1] = clamp(y_sample + gc);
+ d0[2] = clamp(y_sample + bc);
+ d0[3] = 255;
+
+ d0 += 4;
+ }
+
+ return 1;
+ }
+ }
+
+ // Y (1 block per MCU) to 8-bit grayscale
+ void jpeg_decoder::gray_convert()
+ {
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8* d = m_pScan_line_0;
+ uint8* s = m_pSample_buf + row * 8;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ *(uint*)d = *(uint*)s;
+ *(uint*)(&d[4]) = *(uint*)(&s[4]);
+
+ s += 64;
+ d += 8;
+ }
+ }
+
+ // Find end of image (EOI) marker, so we can return to the user the exact size of the input stream.
+ void jpeg_decoder::find_eoi()
+ {
+ if (!m_progressive_flag)
+ {
+ // Attempt to read the EOI marker.
+ //get_bits_no_markers(m_bits_left & 7);
+
+ // Prime the bit buffer
+ m_bits_left = 16;
+ get_bits(16);
+ get_bits(16);
+
+ // The next marker _should_ be EOI
+ process_markers();
+ }
+
+ m_total_bytes_read -= m_in_buf_left;
+ }
+
+ int jpeg_decoder::decode_next_mcu_row()
+ {
+ if (setjmp(m_jmp_state))
+ return JPGD_FAILED;
+
+ const bool chroma_y_filtering = (m_flags & cFlagLinearChromaFiltering) && ((m_scan_type == JPGD_YH2V2) || (m_scan_type == JPGD_YH1V2));
+ if (chroma_y_filtering)
+ {
+ std::swap(m_pSample_buf, m_pSample_buf_prev);
+
+ m_sample_buf_prev_valid = true;
+ }
+
+ if (m_progressive_flag)
+ load_next_row();
+ else
+ decode_next_row();
+
+ // Find the EOI marker if that was the last row.
+ if (m_total_lines_left <= m_max_mcu_y_size)
+ find_eoi();
+
+ m_mcu_lines_left = m_max_mcu_y_size;
+ return 0;
+ }
+
+ int jpeg_decoder::decode(const void** pScan_line, uint* pScan_line_len)
+ {
+ if ((m_error_code) || (!m_ready_flag))
+ return JPGD_FAILED;
+
+ if (m_total_lines_left == 0)
+ return JPGD_DONE;
+
+ const bool chroma_y_filtering = (m_flags & cFlagLinearChromaFiltering) && ((m_scan_type == JPGD_YH2V2) || (m_scan_type == JPGD_YH1V2));
+
+ bool get_another_mcu_row = false;
+ bool got_mcu_early = false;
+ if (chroma_y_filtering)
+ {
+ if (m_total_lines_left == m_image_y_size)
+ get_another_mcu_row = true;
+ else if ((m_mcu_lines_left == 1) && (m_total_lines_left > 1))
+ {
+ get_another_mcu_row = true;
+ got_mcu_early = true;
+ }
+ }
+ else
+ {
+ get_another_mcu_row = (m_mcu_lines_left == 0);
+ }
+
+ if (get_another_mcu_row)
+ {
+ int status = decode_next_mcu_row();
+ if (status != 0)
+ return status;
+ }
+
+ switch (m_scan_type)
+ {
+ case JPGD_YH2V2:
+ {
+ if (m_flags & cFlagLinearChromaFiltering)
+ {
+ if (m_num_buffered_scanlines == 1)
+ {
+ *pScan_line = m_pScan_line_1;
+ }
+ else if (m_num_buffered_scanlines == 0)
+ {
+ m_num_buffered_scanlines = H2V2ConvertFiltered();
+ *pScan_line = m_pScan_line_0;
+ }
+
+ m_num_buffered_scanlines--;
+ }
+ else
+ {
+ if ((m_mcu_lines_left & 1) == 0)
+ {
+ H2V2Convert();
+ *pScan_line = m_pScan_line_0;
+ }
+ else
+ *pScan_line = m_pScan_line_1;
+ }
+
+ break;
+ }
+ case JPGD_YH2V1:
+ {
+ if (m_flags & cFlagLinearChromaFiltering)
+ H2V1ConvertFiltered();
+ else
+ H2V1Convert();
+ *pScan_line = m_pScan_line_0;
+ break;
+ }
+ case JPGD_YH1V2:
+ {
+ if (chroma_y_filtering)
+ {
+ H1V2ConvertFiltered();
+ *pScan_line = m_pScan_line_0;
+ }
+ else
+ {
+ if ((m_mcu_lines_left & 1) == 0)
+ {
+ H1V2Convert();
+ *pScan_line = m_pScan_line_0;
+ }
+ else
+ *pScan_line = m_pScan_line_1;
+ }
+
+ break;
+ }
+ case JPGD_YH1V1:
+ {
+ H1V1Convert();
+ *pScan_line = m_pScan_line_0;
+ break;
+ }
+ case JPGD_GRAYSCALE:
+ {
+ gray_convert();
+ *pScan_line = m_pScan_line_0;
+
+ break;
+ }
+ }
+
+ *pScan_line_len = m_real_dest_bytes_per_scan_line;
+
+ if (!got_mcu_early)
+ {
+ m_mcu_lines_left--;
+ }
+
+ m_total_lines_left--;
+
+ return JPGD_SUCCESS;
+ }
+
+ // Creates the tables needed for efficient Huffman decoding.
+ void jpeg_decoder::make_huff_table(int index, huff_tables* pH)
+ {
+ int p, i, l, si;
+ uint8 huffsize[258];
+ uint huffcode[258];
+ uint code;
+ uint subtree;
+ int code_size;
+ int lastp;
+ int nextfreeentry;
+ int currententry;
+
+ pH->ac_table = m_huff_ac[index] != 0;
+
+ p = 0;
+
+ for (l = 1; l <= 16; l++)
+ {
+ for (i = 1; i <= m_huff_num[index][l]; i++)
+ {
+ if (p >= 257)
+ stop_decoding(JPGD_DECODE_ERROR);
+ huffsize[p++] = static_cast<uint8>(l);
+ }
+ }
+
+ assert(p < 258);
+ huffsize[p] = 0;
+
+ lastp = p;
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+
+ while (huffsize[p])
+ {
+ while (huffsize[p] == si)
+ {
+ if (p >= 257)
+ stop_decoding(JPGD_DECODE_ERROR);
+ huffcode[p++] = code;
+ code++;
+ }
+
+ code <<= 1;
+ si++;
+ }
+
+ memset(pH->look_up, 0, sizeof(pH->look_up));
+ memset(pH->look_up2, 0, sizeof(pH->look_up2));
+ memset(pH->tree, 0, sizeof(pH->tree));
+ memset(pH->code_size, 0, sizeof(pH->code_size));
+
+ nextfreeentry = -1;
+
+ p = 0;
+
+ while (p < lastp)
+ {
+ i = m_huff_val[index][p];
+
+ code = huffcode[p];
+ code_size = huffsize[p];
+
+ assert(i < JPGD_HUFF_CODE_SIZE_MAX_LENGTH);
+ pH->code_size[i] = static_cast<uint8>(code_size);
+
+ if (code_size <= 8)
+ {
+ code <<= (8 - code_size);
+
+ for (l = 1 << (8 - code_size); l > 0; l--)
+ {
+ if (code >= 256)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ pH->look_up[code] = i;
+
+ bool has_extrabits = false;
+ int extra_bits = 0;
+ int num_extra_bits = i & 15;
+
+ int bits_to_fetch = code_size;
+ if (num_extra_bits)
+ {
+ int total_codesize = code_size + num_extra_bits;
+ if (total_codesize <= 8)
+ {
+ has_extrabits = true;
+ extra_bits = ((1 << num_extra_bits) - 1) & (code >> (8 - total_codesize));
+
+ if (extra_bits > 0x7FFF)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ bits_to_fetch += num_extra_bits;
+ }
+ }
+
+ if (!has_extrabits)
+ pH->look_up2[code] = i | (bits_to_fetch << 8);
+ else
+ pH->look_up2[code] = i | 0x8000 | (extra_bits << 16) | (bits_to_fetch << 8);
+
+ code++;
+ }
+ }
+ else
+ {
+ subtree = (code >> (code_size - 8)) & 0xFF;
+
+ currententry = pH->look_up[subtree];
+
+ if (currententry == 0)
+ {
+ pH->look_up[subtree] = currententry = nextfreeentry;
+ pH->look_up2[subtree] = currententry = nextfreeentry;
+
+ nextfreeentry -= 2;
+ }
+
+ code <<= (16 - (code_size - 8));
+
+ for (l = code_size; l > 9; l--)
+ {
+ if ((code & 0x8000) == 0)
+ currententry--;
+
+ unsigned int idx = -currententry - 1;
+
+ if (idx >= JPGD_HUFF_TREE_MAX_LENGTH)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ if (pH->tree[idx] == 0)
+ {
+ pH->tree[idx] = nextfreeentry;
+
+ currententry = nextfreeentry;
+
+ nextfreeentry -= 2;
+ }
+ else
+ {
+ currententry = pH->tree[idx];
+ }
+
+ code <<= 1;
+ }
+
+ if ((code & 0x8000) == 0)
+ currententry--;
+
+ if ((-currententry - 1) >= JPGD_HUFF_TREE_MAX_LENGTH)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ pH->tree[-currententry - 1] = i;
+ }
+
+ p++;
+ }
+ }
+
+ // Verifies the quantization tables needed for this scan are available.
+ void jpeg_decoder::check_quant_tables()
+ {
+ for (int i = 0; i < m_comps_in_scan; i++)
+ if (m_quant[m_comp_quant[m_comp_list[i]]] == nullptr)
+ stop_decoding(JPGD_UNDEFINED_QUANT_TABLE);
+ }
+
+ // Verifies that all the Huffman tables needed for this scan are available.
+ void jpeg_decoder::check_huff_tables()
+ {
+ for (int i = 0; i < m_comps_in_scan; i++)
+ {
+ if ((m_spectral_start == 0) && (m_huff_num[m_comp_dc_tab[m_comp_list[i]]] == nullptr))
+ stop_decoding(JPGD_UNDEFINED_HUFF_TABLE);
+
+ if ((m_spectral_end > 0) && (m_huff_num[m_comp_ac_tab[m_comp_list[i]]] == nullptr))
+ stop_decoding(JPGD_UNDEFINED_HUFF_TABLE);
+ }
+
+ for (int i = 0; i < JPGD_MAX_HUFF_TABLES; i++)
+ if (m_huff_num[i])
+ {
+ if (!m_pHuff_tabs[i])
+ m_pHuff_tabs[i] = (huff_tables*)alloc(sizeof(huff_tables));
+
+ make_huff_table(i, m_pHuff_tabs[i]);
+ }
+ }
+
+ // Determines the component order inside each MCU.
+ // Also calcs how many MCU's are on each row, etc.
+ bool jpeg_decoder::calc_mcu_block_order()
+ {
+ int component_num, component_id;
+ int max_h_samp = 0, max_v_samp = 0;
+
+ for (component_id = 0; component_id < m_comps_in_frame; component_id++)
+ {
+ if (m_comp_h_samp[component_id] > max_h_samp)
+ max_h_samp = m_comp_h_samp[component_id];
+
+ if (m_comp_v_samp[component_id] > max_v_samp)
+ max_v_samp = m_comp_v_samp[component_id];
+ }
+
+ for (component_id = 0; component_id < m_comps_in_frame; component_id++)
+ {
+ m_comp_h_blocks[component_id] = ((((m_image_x_size * m_comp_h_samp[component_id]) + (max_h_samp - 1)) / max_h_samp) + 7) / 8;
+ m_comp_v_blocks[component_id] = ((((m_image_y_size * m_comp_v_samp[component_id]) + (max_v_samp - 1)) / max_v_samp) + 7) / 8;
+ }
+
+ if (m_comps_in_scan == 1)
+ {
+ m_mcus_per_row = m_comp_h_blocks[m_comp_list[0]];
+ m_mcus_per_col = m_comp_v_blocks[m_comp_list[0]];
+ }
+ else
+ {
+ m_mcus_per_row = (((m_image_x_size + 7) / 8) + (max_h_samp - 1)) / max_h_samp;
+ m_mcus_per_col = (((m_image_y_size + 7) / 8) + (max_v_samp - 1)) / max_v_samp;
+ }
+
+ if (m_comps_in_scan == 1)
+ {
+ m_mcu_org[0] = m_comp_list[0];
+
+ m_blocks_per_mcu = 1;
+ }
+ else
+ {
+ m_blocks_per_mcu = 0;
+
+ for (component_num = 0; component_num < m_comps_in_scan; component_num++)
+ {
+ int num_blocks;
+
+ component_id = m_comp_list[component_num];
+
+ num_blocks = m_comp_h_samp[component_id] * m_comp_v_samp[component_id];
+
+ while (num_blocks--)
+ m_mcu_org[m_blocks_per_mcu++] = component_id;
+ }
+ }
+
+ if (m_blocks_per_mcu > m_max_blocks_per_mcu)
+ return false;
+
+ for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
+ {
+ int comp_id = m_mcu_org[mcu_block];
+ if (comp_id >= JPGD_MAX_QUANT_TABLES)
+ return false;
+ }
+
+ return true;
+ }
+
+ // Starts a new scan.
+ int jpeg_decoder::init_scan()
+ {
+ if (!locate_sos_marker())
+ return JPGD_FALSE;
+
+ if (!calc_mcu_block_order())
+ return JPGD_FALSE;
+
+ check_huff_tables();
+
+ check_quant_tables();
+
+ memset(m_last_dc_val, 0, m_comps_in_frame * sizeof(uint));
+
+ m_eob_run = 0;
+
+ if (m_restart_interval)
+ {
+ m_restarts_left = m_restart_interval;
+ m_next_restart_num = 0;
+ }
+
+ fix_in_buffer();
+
+ return JPGD_TRUE;
+ }
+
+ // Starts a frame. Determines if the number of components or sampling factors
+ // are supported.
+ void jpeg_decoder::init_frame()
+ {
+ int i;
+
+ if (m_comps_in_frame == 1)
+ {
+ if ((m_comp_h_samp[0] != 1) || (m_comp_v_samp[0] != 1))
+ stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
+
+ m_scan_type = JPGD_GRAYSCALE;
+ m_max_blocks_per_mcu = 1;
+ m_max_mcu_x_size = 8;
+ m_max_mcu_y_size = 8;
+ }
+ else if (m_comps_in_frame == 3)
+ {
+ if (((m_comp_h_samp[1] != 1) || (m_comp_v_samp[1] != 1)) ||
+ ((m_comp_h_samp[2] != 1) || (m_comp_v_samp[2] != 1)))
+ stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
+
+ if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1))
+ {
+ m_scan_type = JPGD_YH1V1;
+
+ m_max_blocks_per_mcu = 3;
+ m_max_mcu_x_size = 8;
+ m_max_mcu_y_size = 8;
+ }
+ else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1))
+ {
+ m_scan_type = JPGD_YH2V1;
+ m_max_blocks_per_mcu = 4;
+ m_max_mcu_x_size = 16;
+ m_max_mcu_y_size = 8;
+ }
+ else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 2))
+ {
+ m_scan_type = JPGD_YH1V2;
+ m_max_blocks_per_mcu = 4;
+ m_max_mcu_x_size = 8;
+ m_max_mcu_y_size = 16;
+ }
+ else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2))
+ {
+ m_scan_type = JPGD_YH2V2;
+ m_max_blocks_per_mcu = 6;
+ m_max_mcu_x_size = 16;
+ m_max_mcu_y_size = 16;
+ }
+ else
+ stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
+ }
+ else
+ stop_decoding(JPGD_UNSUPPORTED_COLORSPACE);
+
+ m_max_mcus_per_row = (m_image_x_size + (m_max_mcu_x_size - 1)) / m_max_mcu_x_size;
+ m_max_mcus_per_col = (m_image_y_size + (m_max_mcu_y_size - 1)) / m_max_mcu_y_size;
+
+ // These values are for the *destination* pixels: after conversion.
+ if (m_scan_type == JPGD_GRAYSCALE)
+ m_dest_bytes_per_pixel = 1;
+ else
+ m_dest_bytes_per_pixel = 4;
+
+ m_dest_bytes_per_scan_line = ((m_image_x_size + 15) & 0xFFF0) * m_dest_bytes_per_pixel;
+
+ m_real_dest_bytes_per_scan_line = (m_image_x_size * m_dest_bytes_per_pixel);
+
+ // Initialize two scan line buffers.
+ m_pScan_line_0 = (uint8*)alloc(m_dest_bytes_per_scan_line, true);
+ if ((m_scan_type == JPGD_YH1V2) || (m_scan_type == JPGD_YH2V2))
+ m_pScan_line_1 = (uint8*)alloc(m_dest_bytes_per_scan_line, true);
+
+ m_max_blocks_per_row = m_max_mcus_per_row * m_max_blocks_per_mcu;
+
+ // Should never happen
+ if (m_max_blocks_per_row > JPGD_MAX_BLOCKS_PER_ROW)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ // Allocate the coefficient buffer, enough for one MCU
+ m_pMCU_coefficients = (jpgd_block_t*)alloc(m_max_blocks_per_mcu * 64 * sizeof(jpgd_block_t));
+
+ for (i = 0; i < m_max_blocks_per_mcu; i++)
+ m_mcu_block_max_zag[i] = 64;
+
+ m_pSample_buf = (uint8*)alloc(m_max_blocks_per_row * 64);
+ m_pSample_buf_prev = (uint8*)alloc(m_max_blocks_per_row * 64);
+
+ m_total_lines_left = m_image_y_size;
+
+ m_mcu_lines_left = 0;
+
+ create_look_ups();
+ }
+
+ // The coeff_buf series of methods originally stored the coefficients
+ // into a "virtual" file which was located in EMS, XMS, or a disk file. A cache
+ // was used to make this process more efficient. Now, we can store the entire
+ // thing in RAM.
+ jpeg_decoder::coeff_buf* jpeg_decoder::coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y)
+ {
+ coeff_buf* cb = (coeff_buf*)alloc(sizeof(coeff_buf));
+
+ cb->block_num_x = block_num_x;
+ cb->block_num_y = block_num_y;
+ cb->block_len_x = block_len_x;
+ cb->block_len_y = block_len_y;
+ cb->block_size = (block_len_x * block_len_y) * sizeof(jpgd_block_t);
+ cb->pData = (uint8*)alloc(cb->block_size * block_num_x * block_num_y, true);
+ return cb;
+ }
+
+ inline jpgd_block_t* jpeg_decoder::coeff_buf_getp(coeff_buf* cb, int block_x, int block_y)
+ {
+ if ((block_x >= cb->block_num_x) || (block_y >= cb->block_num_y))
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ return (jpgd_block_t*)(cb->pData + block_x * cb->block_size + block_y * (cb->block_size * cb->block_num_x));
+ }
+
+ // The following methods decode the various types of m_blocks encountered
+ // in progressively encoded images.
+ void jpeg_decoder::decode_block_dc_first(jpeg_decoder* pD, int component_id, int block_x, int block_y)
+ {
+ int s, r;
+ jpgd_block_t* p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y);
+
+ if ((s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_dc_tab[component_id]])) != 0)
+ {
+ if (s >= 16)
+ pD->stop_decoding(JPGD_DECODE_ERROR);
+
+ r = pD->get_bits_no_markers(s);
+ s = JPGD_HUFF_EXTEND(r, s);
+ }
+
+ pD->m_last_dc_val[component_id] = (s += pD->m_last_dc_val[component_id]);
+
+ p[0] = static_cast<jpgd_block_t>(s << pD->m_successive_low);
+ }
+
+ void jpeg_decoder::decode_block_dc_refine(jpeg_decoder* pD, int component_id, int block_x, int block_y)
+ {
+ if (pD->get_bits_no_markers(1))
+ {
+ jpgd_block_t* p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y);
+
+ p[0] |= (1 << pD->m_successive_low);
+ }
+ }
+
+ void jpeg_decoder::decode_block_ac_first(jpeg_decoder* pD, int component_id, int block_x, int block_y)
+ {
+ int k, s, r;
+
+ if (pD->m_eob_run)
+ {
+ pD->m_eob_run--;
+ return;
+ }
+
+ jpgd_block_t* p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y);
+
+ for (k = pD->m_spectral_start; k <= pD->m_spectral_end; k++)
+ {
+ unsigned int idx = pD->m_comp_ac_tab[component_id];
+ if (idx >= JPGD_MAX_HUFF_TABLES)
+ pD->stop_decoding(JPGD_DECODE_ERROR);
+
+ s = pD->huff_decode(pD->m_pHuff_tabs[idx]);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s)
+ {
+ if ((k += r) > 63)
+ pD->stop_decoding(JPGD_DECODE_ERROR);
+
+ r = pD->get_bits_no_markers(s);
+ s = JPGD_HUFF_EXTEND(r, s);
+
+ p[g_ZAG[k]] = static_cast<jpgd_block_t>(s << pD->m_successive_low);
+ }
+ else
+ {
+ if (r == 15)
+ {
+ if ((k += 15) > 63)
+ pD->stop_decoding(JPGD_DECODE_ERROR);
+ }
+ else
+ {
+ pD->m_eob_run = 1 << r;
+
+ if (r)
+ pD->m_eob_run += pD->get_bits_no_markers(r);
+
+ pD->m_eob_run--;
+
+ break;
+ }
+ }
+ }
+ }
+
+ void jpeg_decoder::decode_block_ac_refine(jpeg_decoder* pD, int component_id, int block_x, int block_y)
+ {
+ int s, k, r;
+
+ int p1 = 1 << pD->m_successive_low;
+
+ //int m1 = (-1) << pD->m_successive_low;
+ int m1 = static_cast<int>((UINT32_MAX << pD->m_successive_low));
+
+ jpgd_block_t* p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y);
+ if (pD->m_spectral_end > 63)
+ pD->stop_decoding(JPGD_DECODE_ERROR);
+
+ k = pD->m_spectral_start;
+
+ if (pD->m_eob_run == 0)
+ {
+ for (; k <= pD->m_spectral_end; k++)
+ {
+ unsigned int idx = pD->m_comp_ac_tab[component_id];
+ if (idx >= JPGD_MAX_HUFF_TABLES)
+ pD->stop_decoding(JPGD_DECODE_ERROR);
+
+ s = pD->huff_decode(pD->m_pHuff_tabs[idx]);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s)
+ {
+ if (s != 1)
+ pD->stop_decoding(JPGD_DECODE_ERROR);
+
+ if (pD->get_bits_no_markers(1))
+ s = p1;
+ else
+ s = m1;
+ }
+ else
+ {
+ if (r != 15)
+ {
+ pD->m_eob_run = 1 << r;
+
+ if (r)
+ pD->m_eob_run += pD->get_bits_no_markers(r);
+
+ break;
+ }
+ }
+
+ do
+ {
+ jpgd_block_t* this_coef = p + g_ZAG[k & 63];
+
+ if (*this_coef != 0)
+ {
+ if (pD->get_bits_no_markers(1))
+ {
+ if ((*this_coef & p1) == 0)
+ {
+ if (*this_coef >= 0)
+ *this_coef = static_cast<jpgd_block_t>(*this_coef + p1);
+ else
+ *this_coef = static_cast<jpgd_block_t>(*this_coef + m1);
+ }
+ }
+ }
+ else
+ {
+ if (--r < 0)
+ break;
+ }
+
+ k++;
+
+ } while (k <= pD->m_spectral_end);
+
+ if ((s) && (k < 64))
+ {
+ p[g_ZAG[k]] = static_cast<jpgd_block_t>(s);
+ }
+ }
+ }
+
+ if (pD->m_eob_run > 0)
+ {
+ for (; k <= pD->m_spectral_end; k++)
+ {
+ jpgd_block_t* this_coef = p + g_ZAG[k & 63]; // logical AND to shut up static code analysis
+
+ if (*this_coef != 0)
+ {
+ if (pD->get_bits_no_markers(1))
+ {
+ if ((*this_coef & p1) == 0)
+ {
+ if (*this_coef >= 0)
+ *this_coef = static_cast<jpgd_block_t>(*this_coef + p1);
+ else
+ *this_coef = static_cast<jpgd_block_t>(*this_coef + m1);
+ }
+ }
+ }
+ }
+
+ pD->m_eob_run--;
+ }
+ }
+
+ // Decode a scan in a progressively encoded image.
+ void jpeg_decoder::decode_scan(pDecode_block_func decode_block_func)
+ {
+ int mcu_row, mcu_col, mcu_block;
+ int block_x_mcu[JPGD_MAX_COMPONENTS], block_y_mcu[JPGD_MAX_COMPONENTS];
+
+ memset(block_y_mcu, 0, sizeof(block_y_mcu));
+
+ for (mcu_col = 0; mcu_col < m_mcus_per_col; mcu_col++)
+ {
+ int component_num, component_id;
+
+ memset(block_x_mcu, 0, sizeof(block_x_mcu));
+
+ for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
+ {
+ int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0;
+
+ if ((m_restart_interval) && (m_restarts_left == 0))
+ process_restart();
+
+ for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
+ {
+ component_id = m_mcu_org[mcu_block];
+
+ decode_block_func(this, component_id, block_x_mcu[component_id] + block_x_mcu_ofs, block_y_mcu[component_id] + block_y_mcu_ofs);
+
+ if (m_comps_in_scan == 1)
+ block_x_mcu[component_id]++;
+ else
+ {
+ if (++block_x_mcu_ofs == m_comp_h_samp[component_id])
+ {
+ block_x_mcu_ofs = 0;
+
+ if (++block_y_mcu_ofs == m_comp_v_samp[component_id])
+ {
+ block_y_mcu_ofs = 0;
+ block_x_mcu[component_id] += m_comp_h_samp[component_id];
+ }
+ }
+ }
+ }
+
+ m_restarts_left--;
+ }
+
+ if (m_comps_in_scan == 1)
+ block_y_mcu[m_comp_list[0]]++;
+ else
+ {
+ for (component_num = 0; component_num < m_comps_in_scan; component_num++)
+ {
+ component_id = m_comp_list[component_num];
+ block_y_mcu[component_id] += m_comp_v_samp[component_id];
+ }
+ }
+ }
+ }
+
+ // Decode a progressively encoded image.
+ void jpeg_decoder::init_progressive()
+ {
+ int i;
+
+ if (m_comps_in_frame == 4)
+ stop_decoding(JPGD_UNSUPPORTED_COLORSPACE);
+
+ // Allocate the coefficient buffers.
+ for (i = 0; i < m_comps_in_frame; i++)
+ {
+ m_dc_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 1, 1);
+ m_ac_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 8, 8);
+ }
+
+ // See https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf
+ uint32_t total_scans = 0;
+ const uint32_t MAX_SCANS_TO_PROCESS = 1000;
+
+ for (; ; )
+ {
+ int dc_only_scan, refinement_scan;
+ pDecode_block_func decode_block_func;
+
+ if (!init_scan())
+ break;
+
+ dc_only_scan = (m_spectral_start == 0);
+ refinement_scan = (m_successive_high != 0);
+
+ if ((m_spectral_start > m_spectral_end) || (m_spectral_end > 63))
+ stop_decoding(JPGD_BAD_SOS_SPECTRAL);
+
+ if (dc_only_scan)
+ {
+ if (m_spectral_end)
+ stop_decoding(JPGD_BAD_SOS_SPECTRAL);
+ }
+ else if (m_comps_in_scan != 1) /* AC scans can only contain one component */
+ stop_decoding(JPGD_BAD_SOS_SPECTRAL);
+
+ if ((refinement_scan) && (m_successive_low != m_successive_high - 1))
+ stop_decoding(JPGD_BAD_SOS_SUCCESSIVE);
+
+ if (dc_only_scan)
+ {
+ if (refinement_scan)
+ decode_block_func = decode_block_dc_refine;
+ else
+ decode_block_func = decode_block_dc_first;
+ }
+ else
+ {
+ if (refinement_scan)
+ decode_block_func = decode_block_ac_refine;
+ else
+ decode_block_func = decode_block_ac_first;
+ }
+
+ decode_scan(decode_block_func);
+
+ m_bits_left = 16;
+ get_bits(16);
+ get_bits(16);
+
+ total_scans++;
+ if (total_scans > MAX_SCANS_TO_PROCESS)
+ stop_decoding(JPGD_TOO_MANY_SCANS);
+ }
+
+ m_comps_in_scan = m_comps_in_frame;
+
+ for (i = 0; i < m_comps_in_frame; i++)
+ m_comp_list[i] = i;
+
+ if (!calc_mcu_block_order())
+ stop_decoding(JPGD_DECODE_ERROR);
+ }
+
+ void jpeg_decoder::init_sequential()
+ {
+ if (!init_scan())
+ stop_decoding(JPGD_UNEXPECTED_MARKER);
+ }
+
+ void jpeg_decoder::decode_start()
+ {
+ init_frame();
+
+ if (m_progressive_flag)
+ init_progressive();
+ else
+ init_sequential();
+ }
+
+ void jpeg_decoder::decode_init(jpeg_decoder_stream* pStream, uint32_t flags)
+ {
+ init(pStream, flags);
+ locate_sof_marker();
+ }
+
+ jpeg_decoder::jpeg_decoder(jpeg_decoder_stream* pStream, uint32_t flags)
+ {
+ if (setjmp(m_jmp_state))
+ return;
+ decode_init(pStream, flags);
+ }
+
+ int jpeg_decoder::begin_decoding()
+ {
+ if (m_ready_flag)
+ return JPGD_SUCCESS;
+
+ if (m_error_code)
+ return JPGD_FAILED;
+
+ if (setjmp(m_jmp_state))
+ return JPGD_FAILED;
+
+ decode_start();
+
+ m_ready_flag = true;
+
+ return JPGD_SUCCESS;
+ }
+
+ jpeg_decoder::~jpeg_decoder()
+ {
+ free_all_blocks();
+ }
+
+ jpeg_decoder_file_stream::jpeg_decoder_file_stream()
+ {
+ m_pFile = nullptr;
+ m_eof_flag = false;
+ m_error_flag = false;
+ }
+
+ void jpeg_decoder_file_stream::close()
+ {
+ if (m_pFile)
+ {
+ fclose(m_pFile);
+ m_pFile = nullptr;
+ }
+
+ m_eof_flag = false;
+ m_error_flag = false;
+ }
+
+ jpeg_decoder_file_stream::~jpeg_decoder_file_stream()
+ {
+ close();
+ }
+
+ bool jpeg_decoder_file_stream::open(const char* Pfilename)
+ {
+ close();
+
+ m_eof_flag = false;
+ m_error_flag = false;
+
+#if defined(_MSC_VER)
+ m_pFile = nullptr;
+ fopen_s(&m_pFile, Pfilename, "rb");
+#else
+ m_pFile = fopen(Pfilename, "rb");
+#endif
+ return m_pFile != nullptr;
+ }
+
+ int jpeg_decoder_file_stream::read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag)
+ {
+ if (!m_pFile)
+ return -1;
+
+ if (m_eof_flag)
+ {
+ *pEOF_flag = true;
+ return 0;
+ }
+
+ if (m_error_flag)
+ return -1;
+
+ int bytes_read = static_cast<int>(fread(pBuf, 1, max_bytes_to_read, m_pFile));
+ if (bytes_read < max_bytes_to_read)
+ {
+ if (ferror(m_pFile))
+ {
+ m_error_flag = true;
+ return -1;
+ }
+
+ m_eof_flag = true;
+ *pEOF_flag = true;
+ }
+
+ return bytes_read;
+ }
+
+ bool jpeg_decoder_mem_stream::open(const uint8* pSrc_data, uint size)
+ {
+ close();
+ m_pSrc_data = pSrc_data;
+ m_ofs = 0;
+ m_size = size;
+ return true;
+ }
+
+ int jpeg_decoder_mem_stream::read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag)
+ {
+ *pEOF_flag = false;
+
+ if (!m_pSrc_data)
+ return -1;
+
+ uint bytes_remaining = m_size - m_ofs;
+ if ((uint)max_bytes_to_read > bytes_remaining)
+ {
+ max_bytes_to_read = bytes_remaining;
+ *pEOF_flag = true;
+ }
+
+ memcpy(pBuf, m_pSrc_data + m_ofs, max_bytes_to_read);
+ m_ofs += max_bytes_to_read;
+
+ return max_bytes_to_read;
+ }
+
+ unsigned char* decompress_jpeg_image_from_stream(jpeg_decoder_stream* pStream, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags)
+ {
+ if (!actual_comps)
+ return nullptr;
+ *actual_comps = 0;
+
+ if ((!pStream) || (!width) || (!height) || (!req_comps))
+ return nullptr;
+
+ if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4))
+ return nullptr;
+
+ jpeg_decoder decoder(pStream, flags);
+ if (decoder.get_error_code() != JPGD_SUCCESS)
+ return nullptr;
+
+ const int image_width = decoder.get_width(), image_height = decoder.get_height();
+ *width = image_width;
+ *height = image_height;
+ *actual_comps = decoder.get_num_components();
+
+ if (decoder.begin_decoding() != JPGD_SUCCESS)
+ return nullptr;
+
+ const int dst_bpl = image_width * req_comps;
+
+ uint8* pImage_data = (uint8*)jpgd_malloc(dst_bpl * image_height);
+ if (!pImage_data)
+ return nullptr;
+
+ for (int y = 0; y < image_height; y++)
+ {
+ const uint8* pScan_line;
+ uint scan_line_len;
+ if (decoder.decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS)
+ {
+ jpgd_free(pImage_data);
+ return nullptr;
+ }
+
+ uint8* pDst = pImage_data + y * dst_bpl;
+
+ if (((req_comps == 1) && (decoder.get_num_components() == 1)) || ((req_comps == 4) && (decoder.get_num_components() == 3)))
+ memcpy(pDst, pScan_line, dst_bpl);
+ else if (decoder.get_num_components() == 1)
+ {
+ if (req_comps == 3)
+ {
+ for (int x = 0; x < image_width; x++)
+ {
+ uint8 luma = pScan_line[x];
+ pDst[0] = luma;
+ pDst[1] = luma;
+ pDst[2] = luma;
+ pDst += 3;
+ }
+ }
+ else
+ {
+ for (int x = 0; x < image_width; x++)
+ {
+ uint8 luma = pScan_line[x];
+ pDst[0] = luma;
+ pDst[1] = luma;
+ pDst[2] = luma;
+ pDst[3] = 255;
+ pDst += 4;
+ }
+ }
+ }
+ else if (decoder.get_num_components() == 3)
+ {
+ if (req_comps == 1)
+ {
+ const int YR = 19595, YG = 38470, YB = 7471;
+ for (int x = 0; x < image_width; x++)
+ {
+ int r = pScan_line[x * 4 + 0];
+ int g = pScan_line[x * 4 + 1];
+ int b = pScan_line[x * 4 + 2];
+ *pDst++ = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
+ }
+ }
+ else
+ {
+ for (int x = 0; x < image_width; x++)
+ {
+ pDst[0] = pScan_line[x * 4 + 0];
+ pDst[1] = pScan_line[x * 4 + 1];
+ pDst[2] = pScan_line[x * 4 + 2];
+ pDst += 3;
+ }
+ }
+ }
+ }
+
+ return pImage_data;
+ }
+
+ unsigned char* decompress_jpeg_image_from_memory(const unsigned char* pSrc_data, int src_data_size, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags)
+ {
+ jpgd::jpeg_decoder_mem_stream mem_stream(pSrc_data, src_data_size);
+ return decompress_jpeg_image_from_stream(&mem_stream, width, height, actual_comps, req_comps, flags);
+ }
+
+ unsigned char* decompress_jpeg_image_from_file(const char* pSrc_filename, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags)
+ {
+ jpgd::jpeg_decoder_file_stream file_stream;
+ if (!file_stream.open(pSrc_filename))
+ return nullptr;
+ return decompress_jpeg_image_from_stream(&file_stream, width, height, actual_comps, req_comps, flags);
+ }
+
+} // namespace jpgd
diff --git a/thirdparty/basis_universal/encoder/jpgd.h b/thirdparty/basis_universal/encoder/jpgd.h
new file mode 100644
index 0000000000..86a7814cae
--- /dev/null
+++ b/thirdparty/basis_universal/encoder/jpgd.h
@@ -0,0 +1,347 @@
+// jpgd.h - C++ class for JPEG decompression.
+// Public domain, Rich Geldreich <richgel99@gmail.com>
+#ifndef JPEG_DECODER_H
+#define JPEG_DECODER_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include <assert.h>
+#include <stdint.h>
+
+#ifdef _MSC_VER
+#define JPGD_NORETURN __declspec(noreturn)
+#elif defined(__GNUC__)
+#define JPGD_NORETURN __attribute__ ((noreturn))
+#else
+#define JPGD_NORETURN
+#endif
+
+#define JPGD_HUFF_TREE_MAX_LENGTH 512
+#define JPGD_HUFF_CODE_SIZE_MAX_LENGTH 256
+
+namespace jpgd
+{
+ typedef unsigned char uint8;
+ typedef signed short int16;
+ typedef unsigned short uint16;
+ typedef unsigned int uint;
+ typedef signed int int32;
+
+ // Loads a JPEG image from a memory buffer or a file.
+ // req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA).
+ // On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB).
+ // Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly.
+ // Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp.
+ unsigned char* decompress_jpeg_image_from_memory(const unsigned char* pSrc_data, int src_data_size, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags = 0);
+ unsigned char* decompress_jpeg_image_from_file(const char* pSrc_filename, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags = 0);
+
+ // Success/failure error codes.
+ enum jpgd_status
+ {
+ JPGD_SUCCESS = 0, JPGD_FAILED = -1, JPGD_DONE = 1,
+ JPGD_BAD_DHT_COUNTS = -256, JPGD_BAD_DHT_INDEX, JPGD_BAD_DHT_MARKER, JPGD_BAD_DQT_MARKER, JPGD_BAD_DQT_TABLE,
+ JPGD_BAD_PRECISION, JPGD_BAD_HEIGHT, JPGD_BAD_WIDTH, JPGD_TOO_MANY_COMPONENTS,
+ JPGD_BAD_SOF_LENGTH, JPGD_BAD_VARIABLE_MARKER, JPGD_BAD_DRI_LENGTH, JPGD_BAD_SOS_LENGTH,
+ JPGD_BAD_SOS_COMP_ID, JPGD_W_EXTRA_BYTES_BEFORE_MARKER, JPGD_NO_ARITHMITIC_SUPPORT, JPGD_UNEXPECTED_MARKER,
+ JPGD_NOT_JPEG, JPGD_UNSUPPORTED_MARKER, JPGD_BAD_DQT_LENGTH, JPGD_TOO_MANY_BLOCKS,
+ JPGD_UNDEFINED_QUANT_TABLE, JPGD_UNDEFINED_HUFF_TABLE, JPGD_NOT_SINGLE_SCAN, JPGD_UNSUPPORTED_COLORSPACE,
+ JPGD_UNSUPPORTED_SAMP_FACTORS, JPGD_DECODE_ERROR, JPGD_BAD_RESTART_MARKER,
+ JPGD_BAD_SOS_SPECTRAL, JPGD_BAD_SOS_SUCCESSIVE, JPGD_STREAM_READ, JPGD_NOTENOUGHMEM, JPGD_TOO_MANY_SCANS
+ };
+
+ // Input stream interface.
+ // Derive from this class to read input data from sources other than files or memory. Set m_eof_flag to true when no more data is available.
+ // The decoder is rather greedy: it will keep on calling this method until its internal input buffer is full, or until the EOF flag is set.
+ // It the input stream contains data after the JPEG stream's EOI (end of image) marker it will probably be pulled into the internal buffer.
+ // Call the get_total_bytes_read() method to determine the actual size of the JPEG stream after successful decoding.
+ class jpeg_decoder_stream
+ {
+ public:
+ jpeg_decoder_stream() { }
+ virtual ~jpeg_decoder_stream() { }
+
+ // The read() method is called when the internal input buffer is empty.
+ // Parameters:
+ // pBuf - input buffer
+ // max_bytes_to_read - maximum bytes that can be written to pBuf
+ // pEOF_flag - set this to true if at end of stream (no more bytes remaining)
+ // Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0).
+ // Notes: This method will be called in a loop until you set *pEOF_flag to true or the internal buffer is full.
+ virtual int read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag) = 0;
+ };
+
+ // stdio FILE stream class.
+ class jpeg_decoder_file_stream : public jpeg_decoder_stream
+ {
+ jpeg_decoder_file_stream(const jpeg_decoder_file_stream&);
+ jpeg_decoder_file_stream& operator =(const jpeg_decoder_file_stream&);
+
+ FILE* m_pFile;
+ bool m_eof_flag, m_error_flag;
+
+ public:
+ jpeg_decoder_file_stream();
+ virtual ~jpeg_decoder_file_stream();
+
+ bool open(const char* Pfilename);
+ void close();
+
+ virtual int read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag);
+ };
+
+ // Memory stream class.
+ class jpeg_decoder_mem_stream : public jpeg_decoder_stream
+ {
+ const uint8* m_pSrc_data;
+ uint m_ofs, m_size;
+
+ public:
+ jpeg_decoder_mem_stream() : m_pSrc_data(NULL), m_ofs(0), m_size(0) { }
+ jpeg_decoder_mem_stream(const uint8* pSrc_data, uint size) : m_pSrc_data(pSrc_data), m_ofs(0), m_size(size) { }
+
+ virtual ~jpeg_decoder_mem_stream() { }
+
+ bool open(const uint8* pSrc_data, uint size);
+ void close() { m_pSrc_data = NULL; m_ofs = 0; m_size = 0; }
+
+ virtual int read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag);
+ };
+
+ // Loads JPEG file from a jpeg_decoder_stream.
+ unsigned char* decompress_jpeg_image_from_stream(jpeg_decoder_stream* pStream, int* width, int* height, int* actual_comps, int req_comps, uint32_t flags = 0);
+
+ enum
+ {
+ JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4,
+ JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 16384, JPGD_MAX_HEIGHT = 32768, JPGD_MAX_WIDTH = 32768
+ };
+
+ typedef int16 jpgd_quant_t;
+ typedef int16 jpgd_block_t;
+
+ class jpeg_decoder
+ {
+ public:
+ enum
+ {
+ cFlagLinearChromaFiltering = 1
+ };
+
+ // Call get_error_code() after constructing to determine if the stream is valid or not. You may call the get_width(), get_height(), etc.
+ // methods after the constructor is called. You may then either destruct the object, or begin decoding the image by calling begin_decoding(), then decode() on each scanline.
+ jpeg_decoder(jpeg_decoder_stream* pStream, uint32_t flags = cFlagLinearChromaFiltering);
+
+ ~jpeg_decoder();
+
+ // Call this method after constructing the object to begin decompression.
+ // If JPGD_SUCCESS is returned you may then call decode() on each scanline.
+
+ int begin_decoding();
+
+ // Returns the next scan line.
+ // For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1).
+ // Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4).
+ // Returns JPGD_SUCCESS if a scan line has been returned.
+ // Returns JPGD_DONE if all scan lines have been returned.
+ // Returns JPGD_FAILED if an error occurred. Call get_error_code() for a more info.
+ int decode(const void** pScan_line, uint* pScan_line_len);
+
+ inline jpgd_status get_error_code() const { return m_error_code; }
+
+ inline int get_width() const { return m_image_x_size; }
+ inline int get_height() const { return m_image_y_size; }
+
+ inline int get_num_components() const { return m_comps_in_frame; }
+
+ inline int get_bytes_per_pixel() const { return m_dest_bytes_per_pixel; }
+ inline int get_bytes_per_scan_line() const { return m_image_x_size * get_bytes_per_pixel(); }
+
+ // Returns the total number of bytes actually consumed by the decoder (which should equal the actual size of the JPEG file).
+ inline int get_total_bytes_read() const { return m_total_bytes_read; }
+
+ private:
+ jpeg_decoder(const jpeg_decoder&);
+ jpeg_decoder& operator =(const jpeg_decoder&);
+
+ typedef void (*pDecode_block_func)(jpeg_decoder*, int, int, int);
+
+ struct huff_tables
+ {
+ bool ac_table;
+ uint look_up[256];
+ uint look_up2[256];
+ uint8 code_size[JPGD_HUFF_CODE_SIZE_MAX_LENGTH];
+ uint tree[JPGD_HUFF_TREE_MAX_LENGTH];
+ };
+
+ struct coeff_buf
+ {
+ uint8* pData;
+ int block_num_x, block_num_y;
+ int block_len_x, block_len_y;
+ int block_size;
+ };
+
+ struct mem_block
+ {
+ mem_block* m_pNext;
+ size_t m_used_count;
+ size_t m_size;
+ char m_data[1];
+ };
+
+ jmp_buf m_jmp_state;
+ uint32_t m_flags;
+ mem_block* m_pMem_blocks;
+ int m_image_x_size;
+ int m_image_y_size;
+ jpeg_decoder_stream* m_pStream;
+
+ int m_progressive_flag;
+
+ uint8 m_huff_ac[JPGD_MAX_HUFF_TABLES];
+ uint8* m_huff_num[JPGD_MAX_HUFF_TABLES]; // pointer to number of Huffman codes per bit size
+ uint8* m_huff_val[JPGD_MAX_HUFF_TABLES]; // pointer to Huffman codes per bit size
+ jpgd_quant_t* m_quant[JPGD_MAX_QUANT_TABLES]; // pointer to quantization tables
+ int m_scan_type; // Gray, Yh1v1, Yh1v2, Yh2v1, Yh2v2 (CMYK111, CMYK4114 no longer supported)
+ int m_comps_in_frame; // # of components in frame
+ int m_comp_h_samp[JPGD_MAX_COMPONENTS]; // component's horizontal sampling factor
+ int m_comp_v_samp[JPGD_MAX_COMPONENTS]; // component's vertical sampling factor
+ int m_comp_quant[JPGD_MAX_COMPONENTS]; // component's quantization table selector
+ int m_comp_ident[JPGD_MAX_COMPONENTS]; // component's ID
+ int m_comp_h_blocks[JPGD_MAX_COMPONENTS];
+ int m_comp_v_blocks[JPGD_MAX_COMPONENTS];
+ int m_comps_in_scan; // # of components in scan
+ int m_comp_list[JPGD_MAX_COMPS_IN_SCAN]; // components in this scan
+ int m_comp_dc_tab[JPGD_MAX_COMPONENTS]; // component's DC Huffman coding table selector
+ int m_comp_ac_tab[JPGD_MAX_COMPONENTS]; // component's AC Huffman coding table selector
+ int m_spectral_start; // spectral selection start
+ int m_spectral_end; // spectral selection end
+ int m_successive_low; // successive approximation low
+ int m_successive_high; // successive approximation high
+ int m_max_mcu_x_size; // MCU's max. X size in pixels
+ int m_max_mcu_y_size; // MCU's max. Y size in pixels
+ int m_blocks_per_mcu;
+ int m_max_blocks_per_row;
+ int m_mcus_per_row, m_mcus_per_col;
+ int m_mcu_org[JPGD_MAX_BLOCKS_PER_MCU];
+ int m_total_lines_left; // total # lines left in image
+ int m_mcu_lines_left; // total # lines left in this MCU
+ int m_num_buffered_scanlines;
+ int m_real_dest_bytes_per_scan_line;
+ int m_dest_bytes_per_scan_line; // rounded up
+ int m_dest_bytes_per_pixel; // 4 (RGB) or 1 (Y)
+ huff_tables* m_pHuff_tabs[JPGD_MAX_HUFF_TABLES];
+ coeff_buf* m_dc_coeffs[JPGD_MAX_COMPONENTS];
+ coeff_buf* m_ac_coeffs[JPGD_MAX_COMPONENTS];
+ int m_eob_run;
+ int m_block_y_mcu[JPGD_MAX_COMPONENTS];
+ uint8* m_pIn_buf_ofs;
+ int m_in_buf_left;
+ int m_tem_flag;
+
+ uint8 m_in_buf_pad_start[64];
+ uint8 m_in_buf[JPGD_IN_BUF_SIZE + 128];
+ uint8 m_in_buf_pad_end[64];
+
+ int m_bits_left;
+ uint m_bit_buf;
+ int m_restart_interval;
+ int m_restarts_left;
+ int m_next_restart_num;
+ int m_max_mcus_per_row;
+ int m_max_blocks_per_mcu;
+
+ int m_max_mcus_per_col;
+ uint m_last_dc_val[JPGD_MAX_COMPONENTS];
+ jpgd_block_t* m_pMCU_coefficients;
+ int m_mcu_block_max_zag[JPGD_MAX_BLOCKS_PER_MCU];
+ uint8* m_pSample_buf;
+ uint8* m_pSample_buf_prev;
+ int m_crr[256];
+ int m_cbb[256];
+ int m_crg[256];
+ int m_cbg[256];
+ uint8* m_pScan_line_0;
+ uint8* m_pScan_line_1;
+ jpgd_status m_error_code;
+ int m_total_bytes_read;
+
+ bool m_ready_flag;
+ bool m_eof_flag;
+ bool m_sample_buf_prev_valid;
+
+ inline int check_sample_buf_ofs(int ofs) const { assert(ofs >= 0); assert(ofs < m_max_blocks_per_row * 64); return ofs; }
+ void free_all_blocks();
+ JPGD_NORETURN void stop_decoding(jpgd_status status);
+ void* alloc(size_t n, bool zero = false);
+ void word_clear(void* p, uint16 c, uint n);
+ void prep_in_buffer();
+ void read_dht_marker();
+ void read_dqt_marker();
+ void read_sof_marker();
+ void skip_variable_marker();
+ void read_dri_marker();
+ void read_sos_marker();
+ int next_marker();
+ int process_markers();
+ void locate_soi_marker();
+ void locate_sof_marker();
+ int locate_sos_marker();
+ void init(jpeg_decoder_stream* pStream, uint32_t flags);
+ void create_look_ups();
+ void fix_in_buffer();
+ void transform_mcu(int mcu_row);
+ coeff_buf* coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y);
+ inline jpgd_block_t* coeff_buf_getp(coeff_buf* cb, int block_x, int block_y);
+ void load_next_row();
+ void decode_next_row();
+ void make_huff_table(int index, huff_tables* pH);
+ void check_quant_tables();
+ void check_huff_tables();
+ bool calc_mcu_block_order();
+ int init_scan();
+ void init_frame();
+ void process_restart();
+ void decode_scan(pDecode_block_func decode_block_func);
+ void init_progressive();
+ void init_sequential();
+ void decode_start();
+ void decode_init(jpeg_decoder_stream* pStream, uint32_t flags);
+ void H2V2Convert();
+ uint32_t H2V2ConvertFiltered();
+ void H2V1Convert();
+ void H2V1ConvertFiltered();
+ void H1V2Convert();
+ void H1V2ConvertFiltered();
+ void H1V1Convert();
+ void gray_convert();
+ void find_eoi();
+ inline uint get_char();
+ inline uint get_char(bool* pPadding_flag);
+ inline void stuff_char(uint8 q);
+ inline uint8 get_octet();
+ inline uint get_bits(int num_bits);
+ inline uint get_bits_no_markers(int numbits);
+ inline int huff_decode(huff_tables* pH);
+ inline int huff_decode(huff_tables* pH, int& extrabits);
+
+ // Clamps a value between 0-255.
+ static inline uint8 clamp(int i)
+ {
+ if (static_cast<uint>(i) > 255)
+ i = (((~i) >> 31) & 0xFF);
+ return static_cast<uint8>(i);
+ }
+ int decode_next_mcu_row();
+
+ static void decode_block_dc_first(jpeg_decoder* pD, int component_id, int block_x, int block_y);
+ static void decode_block_dc_refine(jpeg_decoder* pD, int component_id, int block_x, int block_y);
+ static void decode_block_ac_first(jpeg_decoder* pD, int component_id, int block_x, int block_y);
+ static void decode_block_ac_refine(jpeg_decoder* pD, int component_id, int block_x, int block_y);
+ };
+
+} // namespace jpgd
+
+#endif // JPEG_DECODER_H
diff --git a/thirdparty/basis_universal/lodepng.cpp b/thirdparty/basis_universal/encoder/lodepng.cpp
index cf964d0555..63adcf49b6 100644
--- a/thirdparty/basis_universal/lodepng.cpp
+++ b/thirdparty/basis_universal/encoder/lodepng.cpp
@@ -29,6 +29,7 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for
*/
#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
#pragma warning (disable : 4201)
#ifndef BASISU_NO_ITERATOR_DEBUG_LEVEL
@@ -200,6 +201,7 @@ static void uivector_init(uivector* p) {
/*returns 1 if success, 0 if failure ==> nothing done*/
static unsigned uivector_push_back(uivector* p, unsigned c) {
if(!uivector_resize(p, p->size + 1)) return 0;
+ if (!p->data) return 0;
p->data[p->size - 1] = c;
return 1;
}
diff --git a/thirdparty/basis_universal/lodepng.h b/thirdparty/basis_universal/encoder/lodepng.h
index 476a2061e2..476a2061e2 100644
--- a/thirdparty/basis_universal/lodepng.h
+++ b/thirdparty/basis_universal/encoder/lodepng.h
diff --git a/thirdparty/basis_universal/transcoder/basisu.h b/thirdparty/basis_universal/transcoder/basisu.h
index 25600a69bf..f33baf67c8 100644
--- a/thirdparty/basis_universal/transcoder/basisu.h
+++ b/thirdparty/basis_universal/transcoder/basisu.h
@@ -1,5 +1,5 @@
// basisu.h
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -41,10 +41,6 @@
#endif
#endif // defined(_DEBUG) || defined(DEBUG)
- #ifndef NOMINMAX
- #define NOMINMAX
- #endif
-
#endif // BASISU_NO_ITERATOR_DEBUG_LEVEL
#endif // _MSC_VER
@@ -63,10 +59,11 @@
#include <functional>
#include <iterator>
#include <type_traits>
-#include <vector>
#include <assert.h>
#include <random>
+#include "basisu_containers.h"
+
#ifdef max
#undef max
#endif
@@ -79,20 +76,20 @@
#define strcasecmp _stricmp
#endif
-// Set to one to enable debug printf()'s when any errors occur, for development/debugging.
-#ifndef BASISU_DEVEL_MESSAGES
-#define BASISU_DEVEL_MESSAGES 0
+// Set to one to enable debug printf()'s when any errors occur, for development/debugging. Especially useful for WebGL development.
+#ifndef BASISU_FORCE_DEVEL_MESSAGES
+#define BASISU_FORCE_DEVEL_MESSAGES 0
#endif
#define BASISU_NOTE_UNUSED(x) (void)(x)
#define BASISU_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#define BASISU_NO_EQUALS_OR_COPY_CONSTRUCT(x) x(const x &) = delete; x& operator= (const x &) = delete;
#define BASISU_ASSUME(x) static_assert(x, #x);
-#define BASISU_OFFSETOF(s, m) (uint32_t)(intptr_t)(&((s *)(0))->m)
+#define BASISU_OFFSETOF(s, m) offsetof(s, m)
#define BASISU_STRINGIZE(x) #x
#define BASISU_STRINGIZE2(x) BASISU_STRINGIZE(x)
-#if BASISU_DEVEL_MESSAGES
+#if BASISU_FORCE_DEVEL_MESSAGES
#define BASISU_DEVEL_ERROR(...) do { basisu::debug_printf(__VA_ARGS__); } while(0)
#else
#define BASISU_DEVEL_ERROR(...)
@@ -108,26 +105,43 @@ namespace basisu
const char BASISU_PATH_SEPERATOR_CHAR = '/';
#endif
- typedef std::vector<uint8_t> uint8_vec;
- typedef std::vector<int16_t> int16_vec;
- typedef std::vector<uint16_t> uint16_vec;
- typedef std::vector<uint32_t> uint_vec;
- typedef std::vector<uint64_t> uint64_vec;
- typedef std::vector<int> int_vec;
- typedef std::vector<bool> bool_vec;
+ typedef basisu::vector<uint8_t> uint8_vec;
+ typedef basisu::vector<int16_t> int16_vec;
+ typedef basisu::vector<uint16_t> uint16_vec;
+ typedef basisu::vector<uint32_t> uint_vec;
+ typedef basisu::vector<uint64_t> uint64_vec;
+ typedef basisu::vector<int> int_vec;
+ typedef basisu::vector<bool> bool_vec;
void enable_debug_printf(bool enabled);
void debug_printf(const char *pFmt, ...);
+
template <typename T> inline void clear_obj(T& obj) { memset(&obj, 0, sizeof(obj)); }
template <typename T0, typename T1> inline T0 lerp(T0 a, T0 b, T1 c) { return a + (b - a) * c; }
template <typename S> inline S maximum(S a, S b) { return (a > b) ? a : b; }
template <typename S> inline S maximum(S a, S b, S c) { return maximum(maximum(a, b), c); }
+ template <typename S> inline S maximum(S a, S b, S c, S d) { return maximum(maximum(maximum(a, b), c), d); }
template <typename S> inline S minimum(S a, S b) { return (a < b) ? a : b; }
template <typename S> inline S minimum(S a, S b, S c) { return minimum(minimum(a, b), c); }
+ template <typename S> inline S minimum(S a, S b, S c, S d) { return minimum(minimum(minimum(a, b), c), d); }
+
+ inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; }
+ inline float saturate(float value) { return clampf(value, 0, 1.0f); }
+ inline uint8_t minimumub(uint8_t a, uint8_t b) { return (a < b) ? a : b; }
+ inline uint32_t minimumu(uint32_t a, uint32_t b) { return (a < b) ? a : b; }
+ inline int32_t minimumi(int32_t a, int32_t b) { return (a < b) ? a : b; }
+ inline float minimumf(float a, float b) { return (a < b) ? a : b; }
+ inline uint8_t maximumub(uint8_t a, uint8_t b) { return (a > b) ? a : b; }
+ inline uint32_t maximumu(uint32_t a, uint32_t b) { return (a > b) ? a : b; }
+ inline int32_t maximumi(int32_t a, int32_t b) { return (a > b) ? a : b; }
+ inline float maximumf(float a, float b) { return (a > b) ? a : b; }
+ inline int squarei(int i) { return i * i; }
+ inline float squaref(float i) { return i * i; }
+ template<typename T> inline T square(T a) { return a * a; }
template <typename S> inline S clamp(S value, S low, S high) { return (value < low) ? low : ((value > high) ? high : value); }
@@ -137,12 +151,10 @@ namespace basisu
template<typename T> inline void clear_vector(T &vec) { vec.erase(vec.begin(), vec.end()); }
template<typename T> inline typename T::value_type *enlarge_vector(T &vec, size_t n) { size_t cs = vec.size(); vec.resize(cs + n); return &vec[cs]; }
- template<typename S> inline S square(S val) { return val * val; }
-
inline bool is_pow2(uint32_t x) { return x && ((x & (x - 1U)) == 0U); }
inline bool is_pow2(uint64_t x) { return x && ((x & (x - 1U)) == 0U); }
- template<typename T> inline T open_range_check(T v, T minv, T maxv) { assert(v >= minv && v < maxv); return v; }
+ template<typename T> inline T open_range_check(T v, T minv, T maxv) { assert(v >= minv && v < maxv); BASISU_NOTE_UNUSED(minv); BASISU_NOTE_UNUSED(maxv); return v; }
template<typename T> inline T open_range_check(T v, T maxv) { assert(v < maxv); BASISU_NOTE_UNUSED(maxv); return v; }
inline uint32_t total_bits(uint32_t v) { uint32_t l = 0; for ( ; v > 0U; ++l) v >>= 1; return l; }
@@ -244,27 +256,92 @@ namespace basisu
if ((ha <= lb) || (la >= hb)) return false;
return true;
}
+
+ static inline uint32_t read_le_dword(const uint8_t *pBytes)
+ {
+ return (pBytes[3] << 24U) | (pBytes[2] << 16U) | (pBytes[1] << 8U) | (pBytes[0]);
+ }
+
+ static inline void write_le_dword(uint8_t* pBytes, uint32_t val)
+ {
+ pBytes[0] = (uint8_t)val;
+ pBytes[1] = (uint8_t)(val >> 8U);
+ pBytes[2] = (uint8_t)(val >> 16U);
+ pBytes[3] = (uint8_t)(val >> 24U);
+ }
- // Always little endian 2-4 byte unsigned int
+ // Always little endian 1-8 byte unsigned int
template<uint32_t NumBytes>
struct packed_uint
{
uint8_t m_bytes[NumBytes];
- inline packed_uint() { static_assert(NumBytes <= 4, "NumBytes <= 4"); }
- inline packed_uint(uint32_t v) { *this = v; }
+ inline packed_uint() { static_assert(NumBytes <= sizeof(uint64_t), "Invalid NumBytes"); }
+ inline packed_uint(uint64_t v) { *this = v; }
inline packed_uint(const packed_uint& other) { *this = other; }
+
+ inline packed_uint& operator= (uint64_t v)
+ {
+ for (uint32_t i = 0; i < NumBytes; i++)
+ m_bytes[i] = static_cast<uint8_t>(v >> (i * 8));
+ return *this;
+ }
- inline packed_uint& operator= (uint32_t v) { for (uint32_t i = 0; i < NumBytes; i++) m_bytes[i] = static_cast<uint8_t>(v >> (i * 8)); return *this; }
+ inline packed_uint& operator= (const packed_uint& rhs)
+ {
+ memcpy(m_bytes, rhs.m_bytes, sizeof(m_bytes));
+ return *this;
+ }
inline operator uint32_t() const
{
switch (NumBytes)
{
- case 1: return m_bytes[0];
- case 2: return (m_bytes[1] << 8U) | m_bytes[0];
- case 3: return (m_bytes[2] << 16U) | (m_bytes[1] << 8U) | (m_bytes[0]);
- default: return (m_bytes[3] << 24U) | (m_bytes[2] << 16U) | (m_bytes[1] << 8U) | (m_bytes[0]);
+ case 1:
+ {
+ return m_bytes[0];
+ }
+ case 2:
+ {
+ return (m_bytes[1] << 8U) | m_bytes[0];
+ }
+ case 3:
+ {
+ return (m_bytes[2] << 16U) | (m_bytes[1] << 8U) | m_bytes[0];
+ }
+ case 4:
+ {
+ return read_le_dword(m_bytes);
+ }
+ case 5:
+ {
+ uint32_t l = read_le_dword(m_bytes);
+ uint32_t h = m_bytes[4];
+ return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
+ }
+ case 6:
+ {
+ uint32_t l = read_le_dword(m_bytes);
+ uint32_t h = (m_bytes[5] << 8U) | m_bytes[4];
+ return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
+ }
+ case 7:
+ {
+ uint32_t l = read_le_dword(m_bytes);
+ uint32_t h = (m_bytes[6] << 16U) | (m_bytes[5] << 8U) | m_bytes[4];
+ return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
+ }
+ case 8:
+ {
+ uint32_t l = read_le_dword(m_bytes);
+ uint32_t h = read_le_dword(m_bytes + 4);
+ return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
+ }
+ default:
+ {
+ assert(0);
+ return 0;
+ }
}
}
};
@@ -278,7 +355,7 @@ namespace basisu
enum
{
cHuffmanMaxSupportedCodeSize = 16, cHuffmanMaxSupportedInternalCodeSize = 31,
- cHuffmanFastLookupBits = 10, cHuffmanFastLookupSize = 1 << cHuffmanFastLookupBits,
+ cHuffmanFastLookupBits = 10,
cHuffmanMaxSymsLog2 = 14, cHuffmanMaxSyms = 1 << cHuffmanMaxSymsLog2,
// Small zero runs
@@ -308,15 +385,15 @@ namespace basisu
// Block-based formats
cETC1, // ETC1
cETC1S, // ETC1 (subset: diff colors only, no subblocks)
- cETC2_RGB, // ETC2 color block
- cETC2_RGBA, // ETC2 alpha block followed by ETC2 color block
+ cETC2_RGB, // ETC2 color block (basisu doesn't support ETC2 planar/T/H modes - just basic ETC1)
+ cETC2_RGBA, // ETC2 EAC alpha block followed by ETC2 color block
cETC2_ALPHA, // ETC2 EAC alpha block
cBC1, // DXT1
- cBC3, // DXT5 (DXT5A block followed by a DXT1 block)
+ cBC3, // DXT5 (BC4/DXT5A block followed by a BC1/DXT1 block)
cBC4, // DXT5A
- cBC5, // 3DC/DXN (two DXT5A blocks)
+ cBC5, // 3DC/DXN (two BC4/DXT5A blocks)
cBC7,
- cASTC4x4,
+ cASTC4x4, // LDR only
cPVRTC1_4_RGB,
cPVRTC1_4_RGBA,
cATC_RGB,
@@ -325,6 +402,9 @@ namespace basisu
cPVRTC2_4_RGBA,
cETC2_R11_EAC,
cETC2_RG11_EAC,
+ cUASTC4x4,
+ cBC1_NV,
+ cBC1_AMD,
// Uncompressed/raw pixels
cRGBA32,
@@ -343,6 +423,8 @@ namespace basisu
case texture_format::cETC2_RGB:
case texture_format::cETC2_ALPHA:
case texture_format::cBC1:
+ case texture_format::cBC1_NV:
+ case texture_format::cBC1_AMD:
case texture_format::cBC4:
case texture_format::cPVRTC1_4_RGB:
case texture_format::cPVRTC1_4_RGBA:
diff --git a/thirdparty/basis_universal/transcoder/basisu_containers.h b/thirdparty/basis_universal/transcoder/basisu_containers.h
new file mode 100644
index 0000000000..1ca4bab307
--- /dev/null
+++ b/thirdparty/basis_universal/transcoder/basisu_containers.h
@@ -0,0 +1,1908 @@
+// basisu_containers.h
+#pragma once
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <algorithm>
+
+#if defined(__linux__) && !defined(ANDROID)
+// Only for malloc_usable_size() in basisu_containers_impl.h
+#include <malloc.h>
+#define HAS_MALLOC_USABLE_SIZE 1
+#endif
+
+#ifdef _MSC_VER
+#define BASISU_FORCE_INLINE __forceinline
+#else
+#define BASISU_FORCE_INLINE inline
+#endif
+
+namespace basisu
+{
+ enum { cInvalidIndex = -1 };
+
+ namespace helpers
+ {
+ inline bool is_power_of_2(uint32_t x) { return x && ((x & (x - 1U)) == 0U); }
+ inline bool is_power_of_2(uint64_t x) { return x && ((x & (x - 1U)) == 0U); }
+ template<class T> const T& minimum(const T& a, const T& b) { return (b < a) ? b : a; }
+ template<class T> const T& maximum(const T& a, const T& b) { return (a < b) ? b : a; }
+
+ inline uint32_t floor_log2i(uint32_t v)
+ {
+ uint32_t l = 0;
+ while (v > 1U)
+ {
+ v >>= 1;
+ l++;
+ }
+ return l;
+ }
+
+ inline uint32_t next_pow2(uint32_t val)
+ {
+ val--;
+ val |= val >> 16;
+ val |= val >> 8;
+ val |= val >> 4;
+ val |= val >> 2;
+ val |= val >> 1;
+ return val + 1;
+ }
+
+ inline uint64_t next_pow2(uint64_t val)
+ {
+ val--;
+ val |= val >> 32;
+ val |= val >> 16;
+ val |= val >> 8;
+ val |= val >> 4;
+ val |= val >> 2;
+ val |= val >> 1;
+ return val + 1;
+ }
+ } // namespace helpers
+
+ template <typename T>
+ inline T* construct(T* p)
+ {
+ return new (static_cast<void*>(p)) T;
+ }
+
+ template <typename T, typename U>
+ inline T* construct(T* p, const U& init)
+ {
+ return new (static_cast<void*>(p)) T(init);
+ }
+
+ template <typename T>
+ inline void construct_array(T* p, size_t n)
+ {
+ T* q = p + n;
+ for (; p != q; ++p)
+ new (static_cast<void*>(p)) T;
+ }
+
+ template <typename T, typename U>
+ inline void construct_array(T* p, size_t n, const U& init)
+ {
+ T* q = p + n;
+ for (; p != q; ++p)
+ new (static_cast<void*>(p)) T(init);
+ }
+
+ template <typename T>
+ inline void destruct(T* p)
+ {
+ (void)p;
+ p->~T();
+ }
+
+ template <typename T> inline void destruct_array(T* p, size_t n)
+ {
+ T* q = p + n;
+ for (; p != q; ++p)
+ p->~T();
+ }
+
+ template<typename T> struct int_traits { enum { cMin = INT32_MIN, cMax = INT32_MAX, cSigned = true }; };
+
+ template<> struct int_traits<int8_t> { enum { cMin = INT8_MIN, cMax = INT8_MAX, cSigned = true }; };
+ template<> struct int_traits<int16_t> { enum { cMin = INT16_MIN, cMax = INT16_MAX, cSigned = true }; };
+ template<> struct int_traits<int32_t> { enum { cMin = INT32_MIN, cMax = INT32_MAX, cSigned = true }; };
+
+ template<> struct int_traits<uint8_t> { enum { cMin = 0, cMax = UINT8_MAX, cSigned = false }; };
+ template<> struct int_traits<uint16_t> { enum { cMin = 0, cMax = UINT16_MAX, cSigned = false }; };
+ template<> struct int_traits<uint32_t> { enum { cMin = 0, cMax = UINT32_MAX, cSigned = false }; };
+
+ template<typename T>
+ struct scalar_type
+ {
+ enum { cFlag = false };
+ static inline void construct(T* p) { basisu::construct(p); }
+ static inline void construct(T* p, const T& init) { basisu::construct(p, init); }
+ static inline void construct_array(T* p, size_t n) { basisu::construct_array(p, n); }
+ static inline void destruct(T* p) { basisu::destruct(p); }
+ static inline void destruct_array(T* p, size_t n) { basisu::destruct_array(p, n); }
+ };
+
+ template<typename T> struct scalar_type<T*>
+ {
+ enum { cFlag = true };
+ static inline void construct(T** p) { memset(p, 0, sizeof(T*)); }
+ static inline void construct(T** p, T* init) { *p = init; }
+ static inline void construct_array(T** p, size_t n) { memset(p, 0, sizeof(T*) * n); }
+ static inline void destruct(T** p) { p; }
+ static inline void destruct_array(T** p, size_t n) { p, n; }
+ };
+
+#define BASISU_DEFINE_BUILT_IN_TYPE(X) \
+ template<> struct scalar_type<X> { \
+ enum { cFlag = true }; \
+ static inline void construct(X* p) { memset(p, 0, sizeof(X)); } \
+ static inline void construct(X* p, const X& init) { memcpy(p, &init, sizeof(X)); } \
+ static inline void construct_array(X* p, size_t n) { memset(p, 0, sizeof(X) * n); } \
+ static inline void destruct(X* p) { p; } \
+ static inline void destruct_array(X* p, size_t n) { p, n; } };
+
+ BASISU_DEFINE_BUILT_IN_TYPE(bool)
+ BASISU_DEFINE_BUILT_IN_TYPE(char)
+ BASISU_DEFINE_BUILT_IN_TYPE(unsigned char)
+ BASISU_DEFINE_BUILT_IN_TYPE(short)
+ BASISU_DEFINE_BUILT_IN_TYPE(unsigned short)
+ BASISU_DEFINE_BUILT_IN_TYPE(int)
+ BASISU_DEFINE_BUILT_IN_TYPE(unsigned int)
+ BASISU_DEFINE_BUILT_IN_TYPE(long)
+ BASISU_DEFINE_BUILT_IN_TYPE(unsigned long)
+#ifdef __GNUC__
+ BASISU_DEFINE_BUILT_IN_TYPE(long long)
+ BASISU_DEFINE_BUILT_IN_TYPE(unsigned long long)
+#else
+ BASISU_DEFINE_BUILT_IN_TYPE(__int64)
+ BASISU_DEFINE_BUILT_IN_TYPE(unsigned __int64)
+#endif
+ BASISU_DEFINE_BUILT_IN_TYPE(float)
+ BASISU_DEFINE_BUILT_IN_TYPE(double)
+ BASISU_DEFINE_BUILT_IN_TYPE(long double)
+
+#undef BASISU_DEFINE_BUILT_IN_TYPE
+
+ template<typename T>
+ struct bitwise_movable { enum { cFlag = false }; };
+
+#define BASISU_DEFINE_BITWISE_MOVABLE(Q) template<> struct bitwise_movable<Q> { enum { cFlag = true }; };
+
+ template<typename T>
+ struct bitwise_copyable { enum { cFlag = false }; };
+
+#define BASISU_DEFINE_BITWISE_COPYABLE(Q) template<> struct bitwise_copyable<Q> { enum { cFlag = true }; };
+
+#define BASISU_IS_POD(T) __is_pod(T)
+
+#define BASISU_IS_SCALAR_TYPE(T) (scalar_type<T>::cFlag)
+
+#if defined(__GNUC__) && __GNUC__<5
+ #define BASISU_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
+#else
+ #define BASISU_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value
+#endif
+
+// TODO: clean this up
+#define BASISU_IS_BITWISE_COPYABLE(T) (BASISU_IS_SCALAR_TYPE(T) || BASISU_IS_POD(T) || BASISU_IS_TRIVIALLY_COPYABLE(T) || (bitwise_copyable<T>::cFlag))
+
+#define BASISU_IS_BITWISE_COPYABLE_OR_MOVABLE(T) (BASISU_IS_BITWISE_COPYABLE(T) || (bitwise_movable<T>::cFlag))
+
+#define BASISU_HAS_DESTRUCTOR(T) ((!scalar_type<T>::cFlag) && (!__is_pod(T)))
+
+ typedef char(&yes_t)[1];
+ typedef char(&no_t)[2];
+
+ template <class U> yes_t class_test(int U::*);
+ template <class U> no_t class_test(...);
+
+ template <class T> struct is_class
+ {
+ enum { value = (sizeof(class_test<T>(0)) == sizeof(yes_t)) };
+ };
+
+ template <typename T> struct is_pointer
+ {
+ enum { value = false };
+ };
+
+ template <typename T> struct is_pointer<T*>
+ {
+ enum { value = true };
+ };
+
+ struct empty_type { };
+
+ BASISU_DEFINE_BITWISE_COPYABLE(empty_type);
+ BASISU_DEFINE_BITWISE_MOVABLE(empty_type);
+
+ template<typename T> struct rel_ops
+ {
+ friend bool operator!=(const T& x, const T& y) { return (!(x == y)); }
+ friend bool operator> (const T& x, const T& y) { return (y < x); }
+ friend bool operator<=(const T& x, const T& y) { return (!(y < x)); }
+ friend bool operator>=(const T& x, const T& y) { return (!(x < y)); }
+ };
+
+ struct elemental_vector
+ {
+ void* m_p;
+ uint32_t m_size;
+ uint32_t m_capacity;
+
+ typedef void (*object_mover)(void* pDst, void* pSrc, uint32_t num);
+
+ bool increase_capacity(uint32_t min_new_capacity, bool grow_hint, uint32_t element_size, object_mover pRelocate, bool nofail);
+ };
+
+ template<typename T>
+ class vector : public rel_ops< vector<T> >
+ {
+ public:
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ typedef T value_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+
+ inline vector() :
+ m_p(NULL),
+ m_size(0),
+ m_capacity(0)
+ {
+ }
+
+ inline vector(uint32_t n, const T& init) :
+ m_p(NULL),
+ m_size(0),
+ m_capacity(0)
+ {
+ increase_capacity(n, false);
+ construct_array(m_p, n, init);
+ m_size = n;
+ }
+
+ inline vector(const vector& other) :
+ m_p(NULL),
+ m_size(0),
+ m_capacity(0)
+ {
+ increase_capacity(other.m_size, false);
+
+ m_size = other.m_size;
+
+ if (BASISU_IS_BITWISE_COPYABLE(T))
+ memcpy(m_p, other.m_p, m_size * sizeof(T));
+ else
+ {
+ T* pDst = m_p;
+ const T* pSrc = other.m_p;
+ for (uint32_t i = m_size; i > 0; i--)
+ construct(pDst++, *pSrc++);
+ }
+ }
+
+ inline explicit vector(size_t size) :
+ m_p(NULL),
+ m_size(0),
+ m_capacity(0)
+ {
+ resize(size);
+ }
+
+ inline ~vector()
+ {
+ if (m_p)
+ {
+ scalar_type<T>::destruct_array(m_p, m_size);
+ free(m_p);
+ }
+ }
+
+ inline vector& operator= (const vector& other)
+ {
+ if (this == &other)
+ return *this;
+
+ if (m_capacity >= other.m_size)
+ resize(0);
+ else
+ {
+ clear();
+ increase_capacity(other.m_size, false);
+ }
+
+ if (BASISU_IS_BITWISE_COPYABLE(T))
+ memcpy(m_p, other.m_p, other.m_size * sizeof(T));
+ else
+ {
+ T* pDst = m_p;
+ const T* pSrc = other.m_p;
+ for (uint32_t i = other.m_size; i > 0; i--)
+ construct(pDst++, *pSrc++);
+ }
+
+ m_size = other.m_size;
+
+ return *this;
+ }
+
+ BASISU_FORCE_INLINE const T* begin() const { return m_p; }
+ BASISU_FORCE_INLINE T* begin() { return m_p; }
+
+ BASISU_FORCE_INLINE const T* end() const { return m_p + m_size; }
+ BASISU_FORCE_INLINE T* end() { return m_p + m_size; }
+
+ BASISU_FORCE_INLINE bool empty() const { return !m_size; }
+ BASISU_FORCE_INLINE uint32_t size() const { return m_size; }
+ BASISU_FORCE_INLINE uint32_t size_in_bytes() const { return m_size * sizeof(T); }
+ BASISU_FORCE_INLINE uint32_t capacity() const { return m_capacity; }
+
+ // operator[] will assert on out of range indices, but in final builds there is (and will never be) any range checking on this method.
+ //BASISU_FORCE_INLINE const T& operator[] (uint32_t i) const { assert(i < m_size); return m_p[i]; }
+ //BASISU_FORCE_INLINE T& operator[] (uint32_t i) { assert(i < m_size); return m_p[i]; }
+
+ BASISU_FORCE_INLINE const T& operator[] (size_t i) const { assert(i < m_size); return m_p[i]; }
+ BASISU_FORCE_INLINE T& operator[] (size_t i) { assert(i < m_size); return m_p[i]; }
+
+ // at() always includes range checking, even in final builds, unlike operator [].
+ // The first element is returned if the index is out of range.
+ BASISU_FORCE_INLINE const T& at(size_t i) const { assert(i < m_size); return (i >= m_size) ? m_p[0] : m_p[i]; }
+ BASISU_FORCE_INLINE T& at(size_t i) { assert(i < m_size); return (i >= m_size) ? m_p[0] : m_p[i]; }
+
+ BASISU_FORCE_INLINE const T& front() const { assert(m_size); return m_p[0]; }
+ BASISU_FORCE_INLINE T& front() { assert(m_size); return m_p[0]; }
+
+ BASISU_FORCE_INLINE const T& back() const { assert(m_size); return m_p[m_size - 1]; }
+ BASISU_FORCE_INLINE T& back() { assert(m_size); return m_p[m_size - 1]; }
+
+ BASISU_FORCE_INLINE const T* get_ptr() const { return m_p; }
+ BASISU_FORCE_INLINE T* get_ptr() { return m_p; }
+
+ BASISU_FORCE_INLINE const T* data() const { return m_p; }
+ BASISU_FORCE_INLINE T* data() { return m_p; }
+
+ // clear() sets the container to empty, then frees the allocated block.
+ inline void clear()
+ {
+ if (m_p)
+ {
+ scalar_type<T>::destruct_array(m_p, m_size);
+ free(m_p);
+ m_p = NULL;
+ m_size = 0;
+ m_capacity = 0;
+ }
+ }
+
+ inline void clear_no_destruction()
+ {
+ if (m_p)
+ {
+ free(m_p);
+ m_p = NULL;
+ m_size = 0;
+ m_capacity = 0;
+ }
+ }
+
+ inline void reserve(size_t new_capacity_size_t)
+ {
+ if (new_capacity_size_t > UINT32_MAX)
+ {
+ assert(0);
+ return;
+ }
+
+ uint32_t new_capacity = (uint32_t)new_capacity_size_t;
+
+ if (new_capacity > m_capacity)
+ increase_capacity(new_capacity, false);
+ else if (new_capacity < m_capacity)
+ {
+ // Must work around the lack of a "decrease_capacity()" method.
+ // This case is rare enough in practice that it's probably not worth implementing an optimized in-place resize.
+ vector tmp;
+ tmp.increase_capacity(helpers::maximum(m_size, new_capacity), false);
+ tmp = *this;
+ swap(tmp);
+ }
+ }
+
+ inline bool try_reserve(size_t new_capacity_size_t)
+ {
+ if (new_capacity_size_t > UINT32_MAX)
+ {
+ assert(0);
+ return false;
+ }
+
+ uint32_t new_capacity = (uint32_t)new_capacity_size_t;
+
+ if (new_capacity > m_capacity)
+ {
+ if (!increase_capacity(new_capacity, false))
+ return false;
+ }
+ else if (new_capacity < m_capacity)
+ {
+ // Must work around the lack of a "decrease_capacity()" method.
+ // This case is rare enough in practice that it's probably not worth implementing an optimized in-place resize.
+ vector tmp;
+ tmp.increase_capacity(helpers::maximum(m_size, new_capacity), false);
+ tmp = *this;
+ swap(tmp);
+ }
+
+ return true;
+ }
+
+ // resize(0) sets the container to empty, but does not free the allocated block.
+ inline void resize(size_t new_size_size_t, bool grow_hint = false)
+ {
+ if (new_size_size_t > UINT32_MAX)
+ {
+ assert(0);
+ return;
+ }
+
+ uint32_t new_size = (uint32_t)new_size_size_t;
+
+ if (m_size != new_size)
+ {
+ if (new_size < m_size)
+ scalar_type<T>::destruct_array(m_p + new_size, m_size - new_size);
+ else
+ {
+ if (new_size > m_capacity)
+ increase_capacity(new_size, (new_size == (m_size + 1)) || grow_hint);
+
+ scalar_type<T>::construct_array(m_p + m_size, new_size - m_size);
+ }
+
+ m_size = new_size;
+ }
+ }
+
+ inline bool try_resize(size_t new_size_size_t, bool grow_hint = false)
+ {
+ if (new_size_size_t > UINT32_MAX)
+ {
+ assert(0);
+ return false;
+ }
+
+ uint32_t new_size = (uint32_t)new_size_size_t;
+
+ if (m_size != new_size)
+ {
+ if (new_size < m_size)
+ scalar_type<T>::destruct_array(m_p + new_size, m_size - new_size);
+ else
+ {
+ if (new_size > m_capacity)
+ {
+ if (!increase_capacity(new_size, (new_size == (m_size + 1)) || grow_hint, true))
+ return false;
+ }
+
+ scalar_type<T>::construct_array(m_p + m_size, new_size - m_size);
+ }
+
+ m_size = new_size;
+ }
+
+ return true;
+ }
+
+ // If size >= capacity/2, reset() sets the container's size to 0 but doesn't free the allocated block (because the container may be similarly loaded in the future).
+ // Otherwise it blows away the allocated block. See http://www.codercorner.com/blog/?p=494
+ inline void reset()
+ {
+ if (m_size >= (m_capacity >> 1))
+ resize(0);
+ else
+ clear();
+ }
+
+ inline T* enlarge(uint32_t i)
+ {
+ uint32_t cur_size = m_size;
+ resize(cur_size + i, true);
+ return get_ptr() + cur_size;
+ }
+
+ inline T* try_enlarge(uint32_t i)
+ {
+ uint32_t cur_size = m_size;
+ if (!try_resize(cur_size + i, true))
+ return NULL;
+ return get_ptr() + cur_size;
+ }
+
+ BASISU_FORCE_INLINE void push_back(const T& obj)
+ {
+ assert(!m_p || (&obj < m_p) || (&obj >= (m_p + m_size)));
+
+ if (m_size >= m_capacity)
+ increase_capacity(m_size + 1, true);
+
+ scalar_type<T>::construct(m_p + m_size, obj);
+ m_size++;
+ }
+
+ inline bool try_push_back(const T& obj)
+ {
+ assert(!m_p || (&obj < m_p) || (&obj >= (m_p + m_size)));
+
+ if (m_size >= m_capacity)
+ {
+ if (!increase_capacity(m_size + 1, true, true))
+ return false;
+ }
+
+ scalar_type<T>::construct(m_p + m_size, obj);
+ m_size++;
+
+ return true;
+ }
+
+ inline void push_back_value(T obj)
+ {
+ if (m_size >= m_capacity)
+ increase_capacity(m_size + 1, true);
+
+ scalar_type<T>::construct(m_p + m_size, obj);
+ m_size++;
+ }
+
+ inline void pop_back()
+ {
+ assert(m_size);
+
+ if (m_size)
+ {
+ m_size--;
+ scalar_type<T>::destruct(&m_p[m_size]);
+ }
+ }
+
+ inline void insert(uint32_t index, const T* p, uint32_t n)
+ {
+ assert(index <= m_size);
+ if (!n)
+ return;
+
+ const uint32_t orig_size = m_size;
+ resize(m_size + n, true);
+
+ const uint32_t num_to_move = orig_size - index;
+
+ if (BASISU_IS_BITWISE_COPYABLE(T))
+ {
+ // This overwrites the destination object bits, but bitwise copyable means we don't need to worry about destruction.
+ memmove(m_p + index + n, m_p + index, sizeof(T) * num_to_move);
+ }
+ else
+ {
+ const T* pSrc = m_p + orig_size - 1;
+ T* pDst = const_cast<T*>(pSrc) + n;
+
+ for (uint32_t i = 0; i < num_to_move; i++)
+ {
+ assert((pDst - m_p) < (int)m_size);
+ *pDst-- = *pSrc--;
+ }
+ }
+
+ T* pDst = m_p + index;
+
+ if (BASISU_IS_BITWISE_COPYABLE(T))
+ {
+ // This copies in the new bits, overwriting the existing objects, which is OK for copyable types that don't need destruction.
+ memcpy(pDst, p, sizeof(T) * n);
+ }
+ else
+ {
+ for (uint32_t i = 0; i < n; i++)
+ {
+ assert((pDst - m_p) < (int)m_size);
+ *pDst++ = *p++;
+ }
+ }
+ }
+
+ inline void insert(T* p, const T& obj)
+ {
+ int64_t ofs = p - begin();
+ if ((ofs < 0) || (ofs > UINT32_MAX))
+ {
+ assert(0);
+ return;
+ }
+
+ insert((uint32_t)ofs, &obj, 1);
+ }
+
+ // push_front() isn't going to be very fast - it's only here for usability.
+ inline void push_front(const T& obj)
+ {
+ insert(0, &obj, 1);
+ }
+
+ vector& append(const vector& other)
+ {
+ if (other.m_size)
+ insert(m_size, &other[0], other.m_size);
+ return *this;
+ }
+
+ vector& append(const T* p, uint32_t n)
+ {
+ if (n)
+ insert(m_size, p, n);
+ return *this;
+ }
+
+ inline void erase(uint32_t start, uint32_t n)
+ {
+ assert((start + n) <= m_size);
+ if ((start + n) > m_size)
+ return;
+
+ if (!n)
+ return;
+
+ const uint32_t num_to_move = m_size - (start + n);
+
+ T* pDst = m_p + start;
+
+ const T* pSrc = m_p + start + n;
+
+ if (BASISU_IS_BITWISE_COPYABLE_OR_MOVABLE(T))
+ {
+ // This test is overly cautious.
+ if ((!BASISU_IS_BITWISE_COPYABLE(T)) || (BASISU_HAS_DESTRUCTOR(T)))
+ {
+ // Type has been marked explictly as bitwise movable, which means we can move them around but they may need to be destructed.
+ // First destroy the erased objects.
+ scalar_type<T>::destruct_array(pDst, n);
+ }
+
+ // Copy "down" the objects to preserve, filling in the empty slots.
+ memmove(pDst, pSrc, num_to_move * sizeof(T));
+ }
+ else
+ {
+ // Type is not bitwise copyable or movable.
+ // Move them down one at a time by using the equals operator, and destroying anything that's left over at the end.
+ T* pDst_end = pDst + num_to_move;
+ while (pDst != pDst_end)
+ *pDst++ = *pSrc++;
+
+ scalar_type<T>::destruct_array(pDst_end, n);
+ }
+
+ m_size -= n;
+ }
+
+ inline void erase(uint32_t index)
+ {
+ erase(index, 1);
+ }
+
+ inline void erase(T* p)
+ {
+ assert((p >= m_p) && (p < (m_p + m_size)));
+ erase(static_cast<uint32_t>(p - m_p));
+ }
+
+ inline void erase(T *pFirst, T *pEnd)
+ {
+ assert(pFirst <= pEnd);
+ assert(pFirst >= begin() && pFirst <= end());
+ assert(pEnd >= begin() && pEnd <= end());
+
+ int64_t ofs = pFirst - begin();
+ if ((ofs < 0) || (ofs > UINT32_MAX))
+ {
+ assert(0);
+ return;
+ }
+
+ int64_t n = pEnd - pFirst;
+ if ((n < 0) || (n > UINT32_MAX))
+ {
+ assert(0);
+ return;
+ }
+
+ erase((uint32_t)ofs, (uint32_t)n);
+ }
+
+ void erase_unordered(uint32_t index)
+ {
+ assert(index < m_size);
+
+ if ((index + 1) < m_size)
+ (*this)[index] = back();
+
+ pop_back();
+ }
+
+ inline bool operator== (const vector& rhs) const
+ {
+ if (m_size != rhs.m_size)
+ return false;
+ else if (m_size)
+ {
+ if (scalar_type<T>::cFlag)
+ return memcmp(m_p, rhs.m_p, sizeof(T) * m_size) == 0;
+ else
+ {
+ const T* pSrc = m_p;
+ const T* pDst = rhs.m_p;
+ for (uint32_t i = m_size; i; i--)
+ if (!(*pSrc++ == *pDst++))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ inline bool operator< (const vector& rhs) const
+ {
+ const uint32_t min_size = helpers::minimum(m_size, rhs.m_size);
+
+ const T* pSrc = m_p;
+ const T* pSrc_end = m_p + min_size;
+ const T* pDst = rhs.m_p;
+
+ while ((pSrc < pSrc_end) && (*pSrc == *pDst))
+ {
+ pSrc++;
+ pDst++;
+ }
+
+ if (pSrc < pSrc_end)
+ return *pSrc < *pDst;
+
+ return m_size < rhs.m_size;
+ }
+
+ inline void swap(vector& other)
+ {
+ std::swap(m_p, other.m_p);
+ std::swap(m_size, other.m_size);
+ std::swap(m_capacity, other.m_capacity);
+ }
+
+ inline void sort()
+ {
+ std::sort(begin(), end());
+ }
+
+ inline void unique()
+ {
+ if (!empty())
+ {
+ sort();
+
+ resize(std::unique(begin(), end()) - begin());
+ }
+ }
+
+ inline void reverse()
+ {
+ uint32_t j = m_size >> 1;
+ for (uint32_t i = 0; i < j; i++)
+ std::swap(m_p[i], m_p[m_size - 1 - i]);
+ }
+
+ inline int find(const T& key) const
+ {
+ const T* p = m_p;
+ const T* p_end = m_p + m_size;
+
+ uint32_t index = 0;
+
+ while (p != p_end)
+ {
+ if (key == *p)
+ return index;
+
+ p++;
+ index++;
+ }
+
+ return cInvalidIndex;
+ }
+
+ inline int find_sorted(const T& key) const
+ {
+ if (m_size)
+ {
+ // Uniform binary search - Knuth Algorithm 6.2.1 U, unrolled twice.
+ int i = ((m_size + 1) >> 1) - 1;
+ int m = m_size;
+
+ for (; ; )
+ {
+ assert(i >= 0 && i < (int)m_size);
+ const T* pKey_i = m_p + i;
+ int cmp = key < *pKey_i;
+#if defined(_DEBUG) || defined(DEBUG)
+ int cmp2 = *pKey_i < key;
+ assert((cmp != cmp2) || (key == *pKey_i));
+#endif
+ if ((!cmp) && (key == *pKey_i)) return i;
+ m >>= 1;
+ if (!m) break;
+ cmp = -cmp;
+ i += (((m + 1) >> 1) ^ cmp) - cmp;
+ if (i < 0)
+ break;
+
+ assert(i >= 0 && i < (int)m_size);
+ pKey_i = m_p + i;
+ cmp = key < *pKey_i;
+#if defined(_DEBUG) || defined(DEBUG)
+ cmp2 = *pKey_i < key;
+ assert((cmp != cmp2) || (key == *pKey_i));
+#endif
+ if ((!cmp) && (key == *pKey_i)) return i;
+ m >>= 1;
+ if (!m) break;
+ cmp = -cmp;
+ i += (((m + 1) >> 1) ^ cmp) - cmp;
+ if (i < 0)
+ break;
+ }
+ }
+
+ return cInvalidIndex;
+ }
+
+ template<typename Q>
+ inline int find_sorted(const T& key, Q less_than) const
+ {
+ if (m_size)
+ {
+ // Uniform binary search - Knuth Algorithm 6.2.1 U, unrolled twice.
+ int i = ((m_size + 1) >> 1) - 1;
+ int m = m_size;
+
+ for (; ; )
+ {
+ assert(i >= 0 && i < (int)m_size);
+ const T* pKey_i = m_p + i;
+ int cmp = less_than(key, *pKey_i);
+ if ((!cmp) && (!less_than(*pKey_i, key))) return i;
+ m >>= 1;
+ if (!m) break;
+ cmp = -cmp;
+ i += (((m + 1) >> 1) ^ cmp) - cmp;
+ if (i < 0)
+ break;
+
+ assert(i >= 0 && i < (int)m_size);
+ pKey_i = m_p + i;
+ cmp = less_than(key, *pKey_i);
+ if ((!cmp) && (!less_than(*pKey_i, key))) return i;
+ m >>= 1;
+ if (!m) break;
+ cmp = -cmp;
+ i += (((m + 1) >> 1) ^ cmp) - cmp;
+ if (i < 0)
+ break;
+ }
+ }
+
+ return cInvalidIndex;
+ }
+
+ inline uint32_t count_occurences(const T& key) const
+ {
+ uint32_t c = 0;
+
+ const T* p = m_p;
+ const T* p_end = m_p + m_size;
+
+ while (p != p_end)
+ {
+ if (key == *p)
+ c++;
+
+ p++;
+ }
+
+ return c;
+ }
+
+ inline void set_all(const T& o)
+ {
+ if ((sizeof(T) == 1) && (scalar_type<T>::cFlag))
+ memset(m_p, *reinterpret_cast<const uint8_t*>(&o), m_size);
+ else
+ {
+ T* pDst = m_p;
+ T* pDst_end = pDst + m_size;
+ while (pDst != pDst_end)
+ *pDst++ = o;
+ }
+ }
+
+ // Caller assumes ownership of the heap block associated with the container. Container is cleared.
+ inline void* assume_ownership()
+ {
+ T* p = m_p;
+ m_p = NULL;
+ m_size = 0;
+ m_capacity = 0;
+ return p;
+ }
+
+ // Caller is granting ownership of the indicated heap block.
+ // Block must have size constructed elements, and have enough room for capacity elements.
+ inline bool grant_ownership(T* p, uint32_t size, uint32_t capacity)
+ {
+ // To to prevent the caller from obviously shooting themselves in the foot.
+ if (((p + capacity) > m_p) && (p < (m_p + m_capacity)))
+ {
+ // Can grant ownership of a block inside the container itself!
+ assert(0);
+ return false;
+ }
+
+ if (size > capacity)
+ {
+ assert(0);
+ return false;
+ }
+
+ if (!p)
+ {
+ if (capacity)
+ {
+ assert(0);
+ return false;
+ }
+ }
+ else if (!capacity)
+ {
+ assert(0);
+ return false;
+ }
+
+ clear();
+ m_p = p;
+ m_size = size;
+ m_capacity = capacity;
+ return true;
+ }
+
+ private:
+ T* m_p;
+ uint32_t m_size;
+ uint32_t m_capacity;
+
+ template<typename Q> struct is_vector { enum { cFlag = false }; };
+ template<typename Q> struct is_vector< vector<Q> > { enum { cFlag = true }; };
+
+ static void object_mover(void* pDst_void, void* pSrc_void, uint32_t num)
+ {
+ T* pSrc = static_cast<T*>(pSrc_void);
+ T* const pSrc_end = pSrc + num;
+ T* pDst = static_cast<T*>(pDst_void);
+
+ while (pSrc != pSrc_end)
+ {
+ // placement new
+ new (static_cast<void*>(pDst)) T(*pSrc);
+ pSrc->~T();
+ ++pSrc;
+ ++pDst;
+ }
+ }
+
+ inline bool increase_capacity(uint32_t min_new_capacity, bool grow_hint, bool nofail = false)
+ {
+ return reinterpret_cast<elemental_vector*>(this)->increase_capacity(
+ min_new_capacity, grow_hint, sizeof(T),
+ (BASISU_IS_BITWISE_COPYABLE_OR_MOVABLE(T) || (is_vector<T>::cFlag)) ? NULL : object_mover, nofail);
+ }
+ };
+
+ template<typename T> struct bitwise_movable< vector<T> > { enum { cFlag = true }; };
+
+ // Hash map
+
+ template <typename T>
+ struct hasher
+ {
+ inline size_t operator() (const T& key) const { return static_cast<size_t>(key); }
+ };
+
+ template <typename T>
+ struct equal_to
+ {
+ inline bool operator()(const T& a, const T& b) const { return a == b; }
+ };
+
+ // Important: The Hasher and Equals objects must be bitwise movable!
+ template<typename Key, typename Value = empty_type, typename Hasher = hasher<Key>, typename Equals = equal_to<Key> >
+ class hash_map
+ {
+ public:
+ class iterator;
+ class const_iterator;
+
+ private:
+ friend class iterator;
+ friend class const_iterator;
+
+ enum state
+ {
+ cStateInvalid = 0,
+ cStateValid = 1
+ };
+
+ enum
+ {
+ cMinHashSize = 4U
+ };
+
+ public:
+ typedef hash_map<Key, Value, Hasher, Equals> hash_map_type;
+ typedef std::pair<Key, Value> value_type;
+ typedef Key key_type;
+ typedef Value referent_type;
+ typedef Hasher hasher_type;
+ typedef Equals equals_type;
+
+ hash_map() :
+ m_hash_shift(32), m_num_valid(0), m_grow_threshold(0)
+ {
+ }
+
+ hash_map(const hash_map& other) :
+ m_values(other.m_values),
+ m_hash_shift(other.m_hash_shift),
+ m_hasher(other.m_hasher),
+ m_equals(other.m_equals),
+ m_num_valid(other.m_num_valid),
+ m_grow_threshold(other.m_grow_threshold)
+ {
+ }
+
+ hash_map& operator= (const hash_map& other)
+ {
+ if (this == &other)
+ return *this;
+
+ clear();
+
+ m_values = other.m_values;
+ m_hash_shift = other.m_hash_shift;
+ m_num_valid = other.m_num_valid;
+ m_grow_threshold = other.m_grow_threshold;
+ m_hasher = other.m_hasher;
+ m_equals = other.m_equals;
+
+ return *this;
+ }
+
+ inline ~hash_map()
+ {
+ clear();
+ }
+
+ const Equals& get_equals() const { return m_equals; }
+ Equals& get_equals() { return m_equals; }
+
+ void set_equals(const Equals& equals) { m_equals = equals; }
+
+ const Hasher& get_hasher() const { return m_hasher; }
+ Hasher& get_hasher() { return m_hasher; }
+
+ void set_hasher(const Hasher& hasher) { m_hasher = hasher; }
+
+ inline void clear()
+ {
+ if (!m_values.empty())
+ {
+ if (BASISU_HAS_DESTRUCTOR(Key) || BASISU_HAS_DESTRUCTOR(Value))
+ {
+ node* p = &get_node(0);
+ node* p_end = p + m_values.size();
+
+ uint32_t num_remaining = m_num_valid;
+ while (p != p_end)
+ {
+ if (p->state)
+ {
+ destruct_value_type(p);
+ num_remaining--;
+ if (!num_remaining)
+ break;
+ }
+
+ p++;
+ }
+ }
+
+ m_values.clear_no_destruction();
+
+ m_hash_shift = 32;
+ m_num_valid = 0;
+ m_grow_threshold = 0;
+ }
+ }
+
+ inline void reset()
+ {
+ if (!m_num_valid)
+ return;
+
+ if (BASISU_HAS_DESTRUCTOR(Key) || BASISU_HAS_DESTRUCTOR(Value))
+ {
+ node* p = &get_node(0);
+ node* p_end = p + m_values.size();
+
+ uint32_t num_remaining = m_num_valid;
+ while (p != p_end)
+ {
+ if (p->state)
+ {
+ destruct_value_type(p);
+ p->state = cStateInvalid;
+
+ num_remaining--;
+ if (!num_remaining)
+ break;
+ }
+
+ p++;
+ }
+ }
+ else if (sizeof(node) <= 32)
+ {
+ memset(&m_values[0], 0, m_values.size_in_bytes());
+ }
+ else
+ {
+ node* p = &get_node(0);
+ node* p_end = p + m_values.size();
+
+ uint32_t num_remaining = m_num_valid;
+ while (p != p_end)
+ {
+ if (p->state)
+ {
+ p->state = cStateInvalid;
+
+ num_remaining--;
+ if (!num_remaining)
+ break;
+ }
+
+ p++;
+ }
+ }
+
+ m_num_valid = 0;
+ }
+
+ inline uint32_t size()
+ {
+ return m_num_valid;
+ }
+
+ inline uint32_t get_table_size()
+ {
+ return m_values.size();
+ }
+
+ inline bool empty()
+ {
+ return !m_num_valid;
+ }
+
+ inline void reserve(uint32_t new_capacity)
+ {
+ uint64_t new_hash_size = helpers::maximum(1U, new_capacity);
+
+ new_hash_size = new_hash_size * 2ULL;
+
+ if (!helpers::is_power_of_2(new_hash_size))
+ new_hash_size = helpers::next_pow2(new_hash_size);
+
+ new_hash_size = helpers::maximum<uint64_t>(cMinHashSize, new_hash_size);
+
+ new_hash_size = helpers::minimum<uint64_t>(0x80000000UL, new_hash_size);
+
+ if (new_hash_size > m_values.size())
+ rehash((uint32_t)new_hash_size);
+ }
+
+ class iterator
+ {
+ friend class hash_map<Key, Value, Hasher, Equals>;
+ friend class hash_map<Key, Value, Hasher, Equals>::const_iterator;
+
+ public:
+ inline iterator() : m_pTable(NULL), m_index(0) { }
+ inline iterator(hash_map_type& table, uint32_t index) : m_pTable(&table), m_index(index) { }
+ inline iterator(const iterator& other) : m_pTable(other.m_pTable), m_index(other.m_index) { }
+
+ inline iterator& operator= (const iterator& other)
+ {
+ m_pTable = other.m_pTable;
+ m_index = other.m_index;
+ return *this;
+ }
+
+ // post-increment
+ inline iterator operator++(int)
+ {
+ iterator result(*this);
+ ++*this;
+ return result;
+ }
+
+ // pre-increment
+ inline iterator& operator++()
+ {
+ probe();
+ return *this;
+ }
+
+ inline value_type& operator*() const { return *get_cur(); }
+ inline value_type* operator->() const { return get_cur(); }
+
+ inline bool operator == (const iterator& b) const { return (m_pTable == b.m_pTable) && (m_index == b.m_index); }
+ inline bool operator != (const iterator& b) const { return !(*this == b); }
+ inline bool operator == (const const_iterator& b) const { return (m_pTable == b.m_pTable) && (m_index == b.m_index); }
+ inline bool operator != (const const_iterator& b) const { return !(*this == b); }
+
+ private:
+ hash_map_type* m_pTable;
+ uint32_t m_index;
+
+ inline value_type* get_cur() const
+ {
+ assert(m_pTable && (m_index < m_pTable->m_values.size()));
+ assert(m_pTable->get_node_state(m_index) == cStateValid);
+
+ return &m_pTable->get_node(m_index);
+ }
+
+ inline void probe()
+ {
+ assert(m_pTable);
+ m_index = m_pTable->find_next(m_index);
+ }
+ };
+
+ class const_iterator
+ {
+ friend class hash_map<Key, Value, Hasher, Equals>;
+ friend class hash_map<Key, Value, Hasher, Equals>::iterator;
+
+ public:
+ inline const_iterator() : m_pTable(NULL), m_index(0) { }
+ inline const_iterator(const hash_map_type& table, uint32_t index) : m_pTable(&table), m_index(index) { }
+ inline const_iterator(const iterator& other) : m_pTable(other.m_pTable), m_index(other.m_index) { }
+ inline const_iterator(const const_iterator& other) : m_pTable(other.m_pTable), m_index(other.m_index) { }
+
+ inline const_iterator& operator= (const const_iterator& other)
+ {
+ m_pTable = other.m_pTable;
+ m_index = other.m_index;
+ return *this;
+ }
+
+ inline const_iterator& operator= (const iterator& other)
+ {
+ m_pTable = other.m_pTable;
+ m_index = other.m_index;
+ return *this;
+ }
+
+ // post-increment
+ inline const_iterator operator++(int)
+ {
+ const_iterator result(*this);
+ ++*this;
+ return result;
+ }
+
+ // pre-increment
+ inline const_iterator& operator++()
+ {
+ probe();
+ return *this;
+ }
+
+ inline const value_type& operator*() const { return *get_cur(); }
+ inline const value_type* operator->() const { return get_cur(); }
+
+ inline bool operator == (const const_iterator& b) const { return (m_pTable == b.m_pTable) && (m_index == b.m_index); }
+ inline bool operator != (const const_iterator& b) const { return !(*this == b); }
+ inline bool operator == (const iterator& b) const { return (m_pTable == b.m_pTable) && (m_index == b.m_index); }
+ inline bool operator != (const iterator& b) const { return !(*this == b); }
+
+ private:
+ const hash_map_type* m_pTable;
+ uint32_t m_index;
+
+ inline const value_type* get_cur() const
+ {
+ assert(m_pTable && (m_index < m_pTable->m_values.size()));
+ assert(m_pTable->get_node_state(m_index) == cStateValid);
+
+ return &m_pTable->get_node(m_index);
+ }
+
+ inline void probe()
+ {
+ assert(m_pTable);
+ m_index = m_pTable->find_next(m_index);
+ }
+ };
+
+ inline const_iterator begin() const
+ {
+ if (!m_num_valid)
+ return end();
+
+ return const_iterator(*this, find_next(UINT32_MAX));
+ }
+
+ inline const_iterator end() const
+ {
+ return const_iterator(*this, m_values.size());
+ }
+
+ inline iterator begin()
+ {
+ if (!m_num_valid)
+ return end();
+
+ return iterator(*this, find_next(UINT32_MAX));
+ }
+
+ inline iterator end()
+ {
+ return iterator(*this, m_values.size());
+ }
+
+ // insert_result.first will always point to inserted key/value (or the already existing key/value).
+ // insert_resutt.second will be true if a new key/value was inserted, or false if the key already existed (in which case first will point to the already existing value).
+ typedef std::pair<iterator, bool> insert_result;
+
+ inline insert_result insert(const Key& k, const Value& v = Value())
+ {
+ insert_result result;
+ if (!insert_no_grow(result, k, v))
+ {
+ grow();
+
+ // This must succeed.
+ if (!insert_no_grow(result, k, v))
+ {
+ fprintf(stderr, "insert() failed");
+ abort();
+ }
+ }
+
+ return result;
+ }
+
+ inline insert_result insert(const value_type& v)
+ {
+ return insert(v.first, v.second);
+ }
+
+ inline const_iterator find(const Key& k) const
+ {
+ return const_iterator(*this, find_index(k));
+ }
+
+ inline iterator find(const Key& k)
+ {
+ return iterator(*this, find_index(k));
+ }
+
+ inline bool erase(const Key& k)
+ {
+ uint32_t i = find_index(k);
+
+ if (i >= m_values.size())
+ return false;
+
+ node* pDst = &get_node(i);
+ destruct_value_type(pDst);
+ pDst->state = cStateInvalid;
+
+ m_num_valid--;
+
+ for (; ; )
+ {
+ uint32_t r, j = i;
+
+ node* pSrc = pDst;
+
+ do
+ {
+ if (!i)
+ {
+ i = m_values.size() - 1;
+ pSrc = &get_node(i);
+ }
+ else
+ {
+ i--;
+ pSrc--;
+ }
+
+ if (!pSrc->state)
+ return true;
+
+ r = hash_key(pSrc->first);
+
+ } while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r));
+
+ move_node(pDst, pSrc);
+
+ pDst = pSrc;
+ }
+ }
+
+ inline void swap(hash_map_type& other)
+ {
+ m_values.swap(other.m_values);
+ std::swap(m_hash_shift, other.m_hash_shift);
+ std::swap(m_num_valid, other.m_num_valid);
+ std::swap(m_grow_threshold, other.m_grow_threshold);
+ std::swap(m_hasher, other.m_hasher);
+ std::swap(m_equals, other.m_equals);
+ }
+
+ private:
+ struct node : public value_type
+ {
+ uint8_t state;
+ };
+
+ static inline void construct_value_type(value_type* pDst, const Key& k, const Value& v)
+ {
+ if (BASISU_IS_BITWISE_COPYABLE(Key))
+ memcpy(&pDst->first, &k, sizeof(Key));
+ else
+ scalar_type<Key>::construct(&pDst->first, k);
+
+ if (BASISU_IS_BITWISE_COPYABLE(Value))
+ memcpy(&pDst->second, &v, sizeof(Value));
+ else
+ scalar_type<Value>::construct(&pDst->second, v);
+ }
+
+ static inline void construct_value_type(value_type* pDst, const value_type* pSrc)
+ {
+ if ((BASISU_IS_BITWISE_COPYABLE(Key)) && (BASISU_IS_BITWISE_COPYABLE(Value)))
+ {
+ memcpy(pDst, pSrc, sizeof(value_type));
+ }
+ else
+ {
+ if (BASISU_IS_BITWISE_COPYABLE(Key))
+ memcpy(&pDst->first, &pSrc->first, sizeof(Key));
+ else
+ scalar_type<Key>::construct(&pDst->first, pSrc->first);
+
+ if (BASISU_IS_BITWISE_COPYABLE(Value))
+ memcpy(&pDst->second, &pSrc->second, sizeof(Value));
+ else
+ scalar_type<Value>::construct(&pDst->second, pSrc->second);
+ }
+ }
+
+ static inline void destruct_value_type(value_type* p)
+ {
+ scalar_type<Key>::destruct(&p->first);
+ scalar_type<Value>::destruct(&p->second);
+ }
+
+ // Moves *pSrc to *pDst efficiently.
+ // pDst should NOT be constructed on entry.
+ static inline void move_node(node* pDst, node* pSrc, bool update_src_state = true)
+ {
+ assert(!pDst->state);
+
+ if (BASISU_IS_BITWISE_COPYABLE_OR_MOVABLE(Key) && BASISU_IS_BITWISE_COPYABLE_OR_MOVABLE(Value))
+ {
+ memcpy(pDst, pSrc, sizeof(node));
+ }
+ else
+ {
+ if (BASISU_IS_BITWISE_COPYABLE_OR_MOVABLE(Key))
+ memcpy(&pDst->first, &pSrc->first, sizeof(Key));
+ else
+ {
+ scalar_type<Key>::construct(&pDst->first, pSrc->first);
+ scalar_type<Key>::destruct(&pSrc->first);
+ }
+
+ if (BASISU_IS_BITWISE_COPYABLE_OR_MOVABLE(Value))
+ memcpy(&pDst->second, &pSrc->second, sizeof(Value));
+ else
+ {
+ scalar_type<Value>::construct(&pDst->second, pSrc->second);
+ scalar_type<Value>::destruct(&pSrc->second);
+ }
+
+ pDst->state = cStateValid;
+ }
+
+ if (update_src_state)
+ pSrc->state = cStateInvalid;
+ }
+
+ struct raw_node
+ {
+ inline raw_node()
+ {
+ node* p = reinterpret_cast<node*>(this);
+ p->state = cStateInvalid;
+ }
+
+ inline ~raw_node()
+ {
+ node* p = reinterpret_cast<node*>(this);
+ if (p->state)
+ hash_map_type::destruct_value_type(p);
+ }
+
+ inline raw_node(const raw_node& other)
+ {
+ node* pDst = reinterpret_cast<node*>(this);
+ const node* pSrc = reinterpret_cast<const node*>(&other);
+
+ if (pSrc->state)
+ {
+ hash_map_type::construct_value_type(pDst, pSrc);
+ pDst->state = cStateValid;
+ }
+ else
+ pDst->state = cStateInvalid;
+ }
+
+ inline raw_node& operator= (const raw_node& rhs)
+ {
+ if (this == &rhs)
+ return *this;
+
+ node* pDst = reinterpret_cast<node*>(this);
+ const node* pSrc = reinterpret_cast<const node*>(&rhs);
+
+ if (pSrc->state)
+ {
+ if (pDst->state)
+ {
+ pDst->first = pSrc->first;
+ pDst->second = pSrc->second;
+ }
+ else
+ {
+ hash_map_type::construct_value_type(pDst, pSrc);
+ pDst->state = cStateValid;
+ }
+ }
+ else if (pDst->state)
+ {
+ hash_map_type::destruct_value_type(pDst);
+ pDst->state = cStateInvalid;
+ }
+
+ return *this;
+ }
+
+ uint8_t m_bits[sizeof(node)];
+ };
+
+ typedef basisu::vector<raw_node> node_vector;
+
+ node_vector m_values;
+ uint32_t m_hash_shift;
+
+ Hasher m_hasher;
+ Equals m_equals;
+
+ uint32_t m_num_valid;
+
+ uint32_t m_grow_threshold;
+
+ inline uint32_t hash_key(const Key& k) const
+ {
+ assert((1U << (32U - m_hash_shift)) == m_values.size());
+
+ uint32_t hash = static_cast<uint32_t>(m_hasher(k));
+
+ // Fibonacci hashing
+ hash = (2654435769U * hash) >> m_hash_shift;
+
+ assert(hash < m_values.size());
+ return hash;
+ }
+
+ inline const node& get_node(uint32_t index) const
+ {
+ return *reinterpret_cast<const node*>(&m_values[index]);
+ }
+
+ inline node& get_node(uint32_t index)
+ {
+ return *reinterpret_cast<node*>(&m_values[index]);
+ }
+
+ inline state get_node_state(uint32_t index) const
+ {
+ return static_cast<state>(get_node(index).state);
+ }
+
+ inline void set_node_state(uint32_t index, bool valid)
+ {
+ get_node(index).state = valid;
+ }
+
+ inline void grow()
+ {
+ uint64_t n = m_values.size() * 3ULL; // was * 2
+
+ if (!helpers::is_power_of_2(n))
+ n = helpers::next_pow2(n);
+
+ if (n > 0x80000000UL)
+ n = 0x80000000UL;
+
+ rehash(helpers::maximum<uint32_t>(cMinHashSize, (uint32_t)n));
+ }
+
+ inline void rehash(uint32_t new_hash_size)
+ {
+ assert(new_hash_size >= m_num_valid);
+ assert(helpers::is_power_of_2(new_hash_size));
+
+ if ((new_hash_size < m_num_valid) || (new_hash_size == m_values.size()))
+ return;
+
+ hash_map new_map;
+ new_map.m_values.resize(new_hash_size);
+ new_map.m_hash_shift = 32U - helpers::floor_log2i(new_hash_size);
+ assert(new_hash_size == (1U << (32U - new_map.m_hash_shift)));
+ new_map.m_grow_threshold = UINT_MAX;
+
+ node* pNode = reinterpret_cast<node*>(m_values.begin());
+ node* pNode_end = pNode + m_values.size();
+
+ while (pNode != pNode_end)
+ {
+ if (pNode->state)
+ {
+ new_map.move_into(pNode);
+
+ if (new_map.m_num_valid == m_num_valid)
+ break;
+ }
+
+ pNode++;
+ }
+
+ new_map.m_grow_threshold = (new_hash_size + 1U) >> 1U;
+
+ m_values.clear_no_destruction();
+ m_hash_shift = 32;
+
+ swap(new_map);
+ }
+
+ inline uint32_t find_next(uint32_t index) const
+ {
+ index++;
+
+ if (index >= m_values.size())
+ return index;
+
+ const node* pNode = &get_node(index);
+
+ for (; ; )
+ {
+ if (pNode->state)
+ break;
+
+ if (++index >= m_values.size())
+ break;
+
+ pNode++;
+ }
+
+ return index;
+ }
+
+ inline uint32_t find_index(const Key& k) const
+ {
+ if (m_num_valid)
+ {
+ uint32_t index = hash_key(k);
+ const node* pNode = &get_node(index);
+
+ if (pNode->state)
+ {
+ if (m_equals(pNode->first, k))
+ return index;
+
+ const uint32_t orig_index = index;
+
+ for (; ; )
+ {
+ if (!index)
+ {
+ index = m_values.size() - 1;
+ pNode = &get_node(index);
+ }
+ else
+ {
+ index--;
+ pNode--;
+ }
+
+ if (index == orig_index)
+ break;
+
+ if (!pNode->state)
+ break;
+
+ if (m_equals(pNode->first, k))
+ return index;
+ }
+ }
+ }
+
+ return m_values.size();
+ }
+
+ inline bool insert_no_grow(insert_result& result, const Key& k, const Value& v = Value())
+ {
+ if (!m_values.size())
+ return false;
+
+ uint32_t index = hash_key(k);
+ node* pNode = &get_node(index);
+
+ if (pNode->state)
+ {
+ if (m_equals(pNode->first, k))
+ {
+ result.first = iterator(*this, index);
+ result.second = false;
+ return true;
+ }
+
+ const uint32_t orig_index = index;
+
+ for (; ; )
+ {
+ if (!index)
+ {
+ index = m_values.size() - 1;
+ pNode = &get_node(index);
+ }
+ else
+ {
+ index--;
+ pNode--;
+ }
+
+ if (orig_index == index)
+ return false;
+
+ if (!pNode->state)
+ break;
+
+ if (m_equals(pNode->first, k))
+ {
+ result.first = iterator(*this, index);
+ result.second = false;
+ return true;
+ }
+ }
+ }
+
+ if (m_num_valid >= m_grow_threshold)
+ return false;
+
+ construct_value_type(pNode, k, v);
+
+ pNode->state = cStateValid;
+
+ m_num_valid++;
+ assert(m_num_valid <= m_values.size());
+
+ result.first = iterator(*this, index);
+ result.second = true;
+
+ return true;
+ }
+
+ inline void move_into(node* pNode)
+ {
+ uint32_t index = hash_key(pNode->first);
+ node* pDst_node = &get_node(index);
+
+ if (pDst_node->state)
+ {
+ const uint32_t orig_index = index;
+
+ for (; ; )
+ {
+ if (!index)
+ {
+ index = m_values.size() - 1;
+ pDst_node = &get_node(index);
+ }
+ else
+ {
+ index--;
+ pDst_node--;
+ }
+
+ if (index == orig_index)
+ {
+ assert(false);
+ return;
+ }
+
+ if (!pDst_node->state)
+ break;
+ }
+ }
+
+ move_node(pDst_node, pNode, false);
+
+ m_num_valid++;
+ }
+ };
+
+ template<typename Key, typename Value, typename Hasher, typename Equals>
+ struct bitwise_movable< hash_map<Key, Value, Hasher, Equals> > { enum { cFlag = true }; };
+
+#if BASISU_HASHMAP_TEST
+ extern void hash_map_test();
+#endif
+
+} // namespace basisu
+
+namespace std
+{
+ template<typename T>
+ inline void swap(basisu::vector<T>& a, basisu::vector<T>& b)
+ {
+ a.swap(b);
+ }
+
+ template<typename Key, typename Value, typename Hasher, typename Equals>
+ inline void swap(basisu::hash_map<Key, Value, Hasher, Equals>& a, basisu::hash_map<Key, Value, Hasher, Equals>& b)
+ {
+ a.swap(b);
+ }
+
+} // namespace std
diff --git a/thirdparty/basis_universal/transcoder/basisu_containers_impl.h b/thirdparty/basis_universal/transcoder/basisu_containers_impl.h
new file mode 100644
index 0000000000..6555171419
--- /dev/null
+++ b/thirdparty/basis_universal/transcoder/basisu_containers_impl.h
@@ -0,0 +1,311 @@
+// basisu_containers_impl.h
+// Do not include directly
+
+#ifdef _MSC_VER
+#pragma warning (disable:4127) // warning C4127: conditional expression is constant
+#endif
+
+namespace basisu
+{
+ bool elemental_vector::increase_capacity(uint32_t min_new_capacity, bool grow_hint, uint32_t element_size, object_mover pMover, bool nofail)
+ {
+ assert(m_size <= m_capacity);
+
+ if (sizeof(void *) == sizeof(uint64_t))
+ assert(min_new_capacity < (0x400000000ULL / element_size));
+ else
+ assert(min_new_capacity < (0x7FFF0000U / element_size));
+
+ if (m_capacity >= min_new_capacity)
+ return true;
+
+ size_t new_capacity = min_new_capacity;
+ if ((grow_hint) && (!helpers::is_power_of_2((uint64_t)new_capacity)))
+ {
+ new_capacity = (size_t)helpers::next_pow2((uint64_t)new_capacity);
+
+ assert(new_capacity && (new_capacity > m_capacity));
+
+ if (new_capacity < min_new_capacity)
+ {
+ if (nofail)
+ return false;
+ fprintf(stderr, "vector too large\n");
+ abort();
+ }
+ }
+
+ const size_t desired_size = element_size * new_capacity;
+ size_t actual_size = 0;
+ if (!pMover)
+ {
+ void* new_p = realloc(m_p, desired_size);
+ if (!new_p)
+ {
+ if (nofail)
+ return false;
+
+ char buf[256];
+#ifdef _MSC_VER
+ sprintf_s(buf, sizeof(buf), "vector: realloc() failed allocating %u bytes", (uint32_t)desired_size);
+#else
+ sprintf(buf, "vector: realloc() failed allocating %u bytes", (uint32_t)desired_size);
+#endif
+ fprintf(stderr, "%s", buf);
+ abort();
+ }
+
+#ifdef _MSC_VER
+ actual_size = _msize(new_p);
+#elif HAS_MALLOC_USABLE_SIZE
+ actual_size = malloc_usable_size(new_p);
+#else
+ actual_size = desired_size;
+#endif
+ m_p = new_p;
+ }
+ else
+ {
+ void* new_p = malloc(desired_size);
+ if (!new_p)
+ {
+ if (nofail)
+ return false;
+
+ char buf[256];
+#ifdef _MSC_VER
+ sprintf_s(buf, sizeof(buf), "vector: malloc() failed allocating %u bytes", (uint32_t)desired_size);
+#else
+ sprintf(buf, "vector: malloc() failed allocating %u bytes", (uint32_t)desired_size);
+#endif
+ fprintf(stderr, "%s", buf);
+ abort();
+ }
+
+#ifdef _MSC_VER
+ actual_size = _msize(new_p);
+#elif HAS_MALLOC_USABLE_SIZE
+ actual_size = malloc_usable_size(new_p);
+#else
+ actual_size = desired_size;
+#endif
+
+ (*pMover)(new_p, m_p, m_size);
+
+ if (m_p)
+ free(m_p);
+
+ m_p = new_p;
+ }
+
+ if (actual_size > desired_size)
+ m_capacity = static_cast<uint32_t>(actual_size / element_size);
+ else
+ m_capacity = static_cast<uint32_t>(new_capacity);
+
+ return true;
+ }
+
+#if BASISU_HASHMAP_TEST
+
+#define HASHMAP_TEST_VERIFY(c) do { if (!(c)) handle_hashmap_test_verify_failure(__LINE__); } while(0)
+
+ static void handle_hashmap_test_verify_failure(int line)
+ {
+ fprintf(stderr, "HASHMAP_TEST_VERIFY() faild on line %i\n", line);
+ abort();
+ }
+
+ class counted_obj
+ {
+ public:
+ counted_obj(uint32_t v = 0) :
+ m_val(v)
+ {
+ m_count++;
+ }
+
+ counted_obj(const counted_obj& obj) :
+ m_val(obj.m_val)
+ {
+ m_count++;
+ }
+
+ ~counted_obj()
+ {
+ assert(m_count > 0);
+ m_count--;
+ }
+
+ static uint32_t m_count;
+
+ uint32_t m_val;
+
+ operator size_t() const { return m_val; }
+
+ bool operator== (const counted_obj& rhs) const { return m_val == rhs.m_val; }
+ bool operator== (const uint32_t rhs) const { return m_val == rhs; }
+
+ };
+
+ uint32_t counted_obj::m_count;
+
+ static uint32_t urand32()
+ {
+ uint32_t a = rand();
+ uint32_t b = rand() << 15;
+ uint32_t c = rand() << (32 - 15);
+ return a ^ b ^ c;
+ }
+
+ static int irand32(int l, int h)
+ {
+ assert(l < h);
+ if (l >= h)
+ return l;
+
+ uint32_t range = static_cast<uint32_t>(h - l);
+
+ uint32_t rnd = urand32();
+
+ uint32_t rnd_range = static_cast<uint32_t>((((uint64_t)range) * ((uint64_t)rnd)) >> 32U);
+
+ int result = l + rnd_range;
+ assert((result >= l) && (result < h));
+ return result;
+ }
+
+ void hash_map_test()
+ {
+ {
+ basisu::hash_map<uint64_t, uint64_t> k;
+ basisu::hash_map<uint64_t, uint64_t> l;
+ std::swap(k, l);
+
+ k.begin();
+ k.end();
+ k.clear();
+ k.empty();
+ k.erase(0);
+ k.insert(0, 1);
+ k.find(0);
+ k.get_equals();
+ k.get_hasher();
+ k.get_table_size();
+ k.reset();
+ k.reserve(1);
+ k = l;
+ k.set_equals(l.get_equals());
+ k.set_hasher(l.get_hasher());
+ k.get_table_size();
+ }
+
+ uint32_t seed = 0;
+ for (; ; )
+ {
+ seed++;
+
+ typedef basisu::hash_map<counted_obj, counted_obj> my_hash_map;
+ my_hash_map m;
+
+ const uint32_t n = irand32(0, 100000);
+
+ printf("%u\n", n);
+
+ srand(seed); // r1.seed(seed);
+
+ basisu::vector<int> q;
+
+ uint32_t count = 0;
+ for (uint32_t i = 0; i < n; i++)
+ {
+ uint32_t v = urand32() & 0x7FFFFFFF;
+ my_hash_map::insert_result res = m.insert(counted_obj(v), counted_obj(v ^ 0xdeadbeef));
+ if (res.second)
+ {
+ count++;
+ q.push_back(v);
+ }
+ }
+
+ HASHMAP_TEST_VERIFY(m.size() == count);
+
+ srand(seed);
+
+ my_hash_map cm(m);
+ m.clear();
+ m = cm;
+ cm.reset();
+
+ for (uint32_t i = 0; i < n; i++)
+ {
+ uint32_t v = urand32() & 0x7FFFFFFF;
+ my_hash_map::const_iterator it = m.find(counted_obj(v));
+ HASHMAP_TEST_VERIFY(it != m.end());
+ HASHMAP_TEST_VERIFY(it->first == v);
+ HASHMAP_TEST_VERIFY(it->second == (v ^ 0xdeadbeef));
+ }
+
+ for (uint32_t t = 0; t < 2; t++)
+ {
+ const uint32_t nd = irand32(1, q.size() + 1);
+ for (uint32_t i = 0; i < nd; i++)
+ {
+ uint32_t p = irand32(0, q.size());
+
+ int k = q[p];
+ if (k >= 0)
+ {
+ q[p] = -k - 1;
+
+ bool s = m.erase(counted_obj(k));
+ HASHMAP_TEST_VERIFY(s);
+ }
+ }
+
+ typedef basisu::hash_map<uint32_t, empty_type> uint_hash_set;
+ uint_hash_set s;
+
+ for (uint32_t i = 0; i < q.size(); i++)
+ {
+ int v = q[i];
+
+ if (v >= 0)
+ {
+ my_hash_map::const_iterator it = m.find(counted_obj(v));
+ HASHMAP_TEST_VERIFY(it != m.end());
+ HASHMAP_TEST_VERIFY(it->first == (uint32_t)v);
+ HASHMAP_TEST_VERIFY(it->second == ((uint32_t)v ^ 0xdeadbeef));
+
+ s.insert(v);
+ }
+ else
+ {
+ my_hash_map::const_iterator it = m.find(counted_obj(-v - 1));
+ HASHMAP_TEST_VERIFY(it == m.end());
+ }
+ }
+
+ uint32_t found_count = 0;
+ for (my_hash_map::const_iterator it = m.begin(); it != m.end(); ++it)
+ {
+ HASHMAP_TEST_VERIFY(it->second == ((uint32_t)it->first ^ 0xdeadbeef));
+
+ uint_hash_set::const_iterator fit(s.find((uint32_t)it->first));
+ HASHMAP_TEST_VERIFY(fit != s.end());
+
+ HASHMAP_TEST_VERIFY(fit->first == it->first);
+
+ found_count++;
+ }
+
+ HASHMAP_TEST_VERIFY(found_count == s.size());
+ }
+
+ HASHMAP_TEST_VERIFY(counted_obj::m_count == m.size() * 2);
+ }
+ }
+
+#endif // BASISU_HASHMAP_TEST
+
+} // namespace basisu
diff --git a/thirdparty/basis_universal/transcoder/basisu_file_headers.h b/thirdparty/basis_universal/transcoder/basisu_file_headers.h
index c90b3f3af0..4316d738e6 100644
--- a/thirdparty/basis_universal/transcoder/basisu_file_headers.h
+++ b/thirdparty/basis_universal/transcoder/basisu_file_headers.h
@@ -1,5 +1,5 @@
// basis_file_headers.h
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2020 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,8 +20,11 @@ namespace basist
// Slice desc header flags
enum basis_slice_desc_flags
{
- cSliceDescFlagsIsAlphaData = 1,
- cSliceDescFlagsFrameIsIFrame = 2 // Video only: Frame doesn't refer to previous frame (no usage of conditional replenishment pred symbols)
+ cSliceDescFlagsHasAlpha = 1,
+
+ // Video only: Frame doesn't refer to previous frame (no usage of conditional replenishment pred symbols)
+ // Currently the first frame is always an I-Frame, all subsequent frames are P-Frames. This will eventually be changed to periodic I-Frames.
+ cSliceDescFlagsFrameIsIFrame = 2
};
#pragma pack(push)
@@ -38,7 +41,7 @@ namespace basist
basisu::packed_uint<2> m_num_blocks_x; // The slice's block X dimensions. Each block is 4x4 pixels. The slice's pixel resolution may or may not be a power of 2.
basisu::packed_uint<2> m_num_blocks_y; // The slice's block Y dimensions.
- basisu::packed_uint<4> m_file_ofs; // Offset from the header to the start of the slice's data
+ basisu::packed_uint<4> m_file_ofs; // Offset from the start of the file to the start of the slice's data
basisu::packed_uint<4> m_file_size; // The size of the compressed slice data in bytes
basisu::packed_uint<2> m_slice_data_crc16; // The CRC16 of the compressed slice data, for extra-paranoid use cases
@@ -47,9 +50,21 @@ namespace basist
// File header files
enum basis_header_flags
{
- cBASISHeaderFlagETC1S = 1, // Always set for basis universal files
- cBASISHeaderFlagYFlipped = 2, // Set if the texture had to be Y flipped before encoding
- cBASISHeaderFlagHasAlphaSlices = 4 // True if the odd slices contain alpha data
+ // Always set for ETC1S files. Not set for UASTC files.
+ cBASISHeaderFlagETC1S = 1,
+
+ // Set if the texture had to be Y flipped before encoding. The actual interpretation of this (is Y up or down?) is up to the user.
+ cBASISHeaderFlagYFlipped = 2,
+
+ // Set if any slices contain alpha (for ETC1S, if the odd slices contain alpha data)
+ cBASISHeaderFlagHasAlphaSlices = 4,
+
+ // For ETC1S files, this will be true if the file utilizes a codebook from another .basis file.
+ cBASISHeaderFlagUsesGlobalCodebook = 8,
+
+ // Set if the texture data is sRGB, otherwise it's linear.
+ // In reality, we have no idea if the texture data is actually linear or sRGB. This is the m_perceptual parameter passed to the compressor.
+ cBASISHeaderFlagSRGB = 16,
};
// The image type field attempts to describe how to interpret the image data in a Basis file.
@@ -71,6 +86,12 @@ namespace basist
cBASISMaxUSPerFrame = 0xFFFFFF
};
+ enum class basis_tex_format
+ {
+ cETC1S = 0,
+ cUASTC4x4 = 1
+ };
+
struct basis_file_header
{
enum
@@ -82,16 +103,16 @@ namespace basist
basisu::packed_uint<2> m_sig; // 2 byte file signature
basisu::packed_uint<2> m_ver; // Baseline file version
basisu::packed_uint<2> m_header_size; // Header size in bytes, sizeof(basis_file_header)
- basisu::packed_uint<2> m_header_crc16; // crc16 of the remaining header data
+ basisu::packed_uint<2> m_header_crc16; // CRC16 of the remaining header data
basisu::packed_uint<4> m_data_size; // The total size of all data after the header
basisu::packed_uint<2> m_data_crc16; // The CRC16 of all data after the header
- basisu::packed_uint<3> m_total_slices; // The total # of compressed slices (1 slice per image, or 2 for alpha basis files)
+ basisu::packed_uint<3> m_total_slices; // The total # of compressed slices (1 slice per image, or 2 for alpha .basis files)
basisu::packed_uint<3> m_total_images; // The total # of images
- basisu::packed_uint<1> m_format; // enum basist::block_format
+ basisu::packed_uint<1> m_tex_format; // enum basis_tex_format
basisu::packed_uint<2> m_flags; // enum basist::header_flags
basisu::packed_uint<1> m_tex_type; // enum basist::basis_texture_type
basisu::packed_uint<3> m_us_per_frame; // Framerate of video, in microseconds per frame
@@ -101,11 +122,11 @@ namespace basist
basisu::packed_uint<4> m_userdata1; // For client use
basisu::packed_uint<2> m_total_endpoints; // The number of endpoints in the endpoint codebook
- basisu::packed_uint<4> m_endpoint_cb_file_ofs; // The compressed endpoint codebook's file offset relative to the header
+ basisu::packed_uint<4> m_endpoint_cb_file_ofs; // The compressed endpoint codebook's file offset relative to the start of the file
basisu::packed_uint<3> m_endpoint_cb_file_size; // The compressed endpoint codebook's size in bytes
basisu::packed_uint<2> m_total_selectors; // The number of selectors in the endpoint codebook
- basisu::packed_uint<4> m_selector_cb_file_ofs; // The compressed selectors codebook's file offset relative to the header
+ basisu::packed_uint<4> m_selector_cb_file_ofs; // The compressed selectors codebook's file offset relative to the start of the file
basisu::packed_uint<3> m_selector_cb_file_size; // The compressed selector codebook's size in bytes
basisu::packed_uint<4> m_tables_file_ofs; // The file offset of the compressed Huffman codelength tables, for decompressing slices
diff --git a/thirdparty/basis_universal/transcoder/basisu_global_selector_cb.h b/thirdparty/basis_universal/transcoder/basisu_global_selector_cb.h
index 695b0b3b97..8ab5098898 100644
--- a/thirdparty/basis_universal/transcoder/basisu_global_selector_cb.h
+++ b/thirdparty/basis_universal/transcoder/basisu_global_selector_cb.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2020 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/thirdparty/basis_universal/transcoder/basisu_global_selector_palette.h b/thirdparty/basis_universal/transcoder/basisu_global_selector_palette.h
index b0260541c3..8bedf94710 100644
--- a/thirdparty/basis_universal/transcoder/basisu_global_selector_palette.h
+++ b/thirdparty/basis_universal/transcoder/basisu_global_selector_palette.h
@@ -1,5 +1,7 @@
// basisu_global_selector_palette.h
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
+//
+// TODO: NONE of this is used in .basis/.ktx2 files. It will be deleted soon.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -609,7 +611,7 @@ namespace basist
uint8_t m_selectors[16];
};
- typedef std::vector<etc1_selector_palette_entry> etc1_selector_palette_entry_vec;
+ typedef basisu::vector<etc1_selector_palette_entry> etc1_selector_palette_entry_vec;
extern const uint32_t g_global_selector_cb[];
extern const uint32_t g_global_selector_cb_size;
@@ -628,7 +630,7 @@ namespace basist
void set(uint32_t palette_index, const etc1_global_palette_entry_modifier &modifier) { m_palette_index = palette_index; m_modifier = modifier; }
};
- typedef std::vector<etc1_global_selector_codebook_entry_id> etc1_global_selector_codebook_entry_id_vec;
+ typedef basisu::vector<etc1_global_selector_codebook_entry_id> etc1_global_selector_codebook_entry_id_vec;
class etc1_global_selector_codebook
{
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder.cpp b/thirdparty/basis_universal/transcoder/basisu_transcoder.cpp
index d15b6013d9..29eb3c0d55 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder.cpp
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder.cpp
@@ -1,5 +1,5 @@
// basisu_transcoder.cpp
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,65 +15,88 @@
#include "basisu_transcoder.h"
#include <limits.h>
-#include <vector>
+#include "basisu_containers_impl.h"
+
+#ifndef BASISD_IS_BIG_ENDIAN
+// TODO: This doesn't work on OSX. How can this be so difficult?
+//#if defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) || defined(BIG_ENDIAN)
+// #define BASISD_IS_BIG_ENDIAN (1)
+//#else
+ #define BASISD_IS_BIG_ENDIAN (0)
+//#endif
+#endif
+
+#ifndef BASISD_USE_UNALIGNED_WORD_READS
+ #ifdef __EMSCRIPTEN__
+ // Can't use unaligned loads/stores with WebAssembly.
+ #define BASISD_USE_UNALIGNED_WORD_READS (0)
+ #elif defined(_M_AMD64) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)
+ #define BASISD_USE_UNALIGNED_WORD_READS (1)
+ #else
+ #define BASISD_USE_UNALIGNED_WORD_READS (0)
+ #endif
+#endif
-// The supported .basis file header version. Keep in sync with BASIS_FILE_VERSION.
#define BASISD_SUPPORTED_BASIS_VERSION (0x13)
+#ifndef BASISD_SUPPORT_KTX2
+ #error Must have defined BASISD_SUPPORT_KTX2
+#endif
+
+#ifndef BASISD_SUPPORT_KTX2_ZSTD
+#error Must have defined BASISD_SUPPORT_KTX2_ZSTD
+#endif
+
// Set to 1 for fuzz testing. This will disable all CRC16 checks on headers and compressed data.
#ifndef BASISU_NO_HEADER_OR_DATA_CRC16_CHECKS
-#define BASISU_NO_HEADER_OR_DATA_CRC16_CHECKS 0
+ #define BASISU_NO_HEADER_OR_DATA_CRC16_CHECKS 0
#endif
#ifndef BASISD_SUPPORT_DXT1
-#define BASISD_SUPPORT_DXT1 1
+ #define BASISD_SUPPORT_DXT1 1
#endif
#ifndef BASISD_SUPPORT_DXT5A
-#define BASISD_SUPPORT_DXT5A 1
+ #define BASISD_SUPPORT_DXT5A 1
#endif
// Disable all BC7 transcoders if necessary (useful when cross compiling to Javascript)
#if defined(BASISD_SUPPORT_BC7) && !BASISD_SUPPORT_BC7
- #ifndef BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY
- #define BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY 0
- #endif
#ifndef BASISD_SUPPORT_BC7_MODE5
- #define BASISD_SUPPORT_BC7_MODE5 0
+ #define BASISD_SUPPORT_BC7_MODE5 0
#endif
#endif // !BASISD_SUPPORT_BC7
-// BC7 mode 6 opaque only is the highest quality (compared to ETC1), but the tables are massive.
-// For web/mobile use you probably should disable this.
-#ifndef BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY
-#define BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY 1
-#endif
-
-// BC7 mode 5 supports both opaque and opaque+alpha textures, and uses substantially less memory than BC7 mode 6 and even BC1.
+// BC7 mode 5 supports both opaque and opaque+alpha textures, and uses less memory BC1.
#ifndef BASISD_SUPPORT_BC7_MODE5
-#define BASISD_SUPPORT_BC7_MODE5 1
+ #define BASISD_SUPPORT_BC7_MODE5 1
#endif
#ifndef BASISD_SUPPORT_PVRTC1
-#define BASISD_SUPPORT_PVRTC1 1
+ #define BASISD_SUPPORT_PVRTC1 1
#endif
#ifndef BASISD_SUPPORT_ETC2_EAC_A8
-#define BASISD_SUPPORT_ETC2_EAC_A8 1
+ #define BASISD_SUPPORT_ETC2_EAC_A8 1
+#endif
+
+// Set BASISD_SUPPORT_UASTC to 0 to completely disable support for transcoding UASTC files.
+#ifndef BASISD_SUPPORT_UASTC
+ #define BASISD_SUPPORT_UASTC 1
#endif
#ifndef BASISD_SUPPORT_ASTC
-#define BASISD_SUPPORT_ASTC 1
+ #define BASISD_SUPPORT_ASTC 1
#endif
// Note that if BASISD_SUPPORT_ATC is enabled, BASISD_SUPPORT_DXT5A should also be enabled for alpha support.
#ifndef BASISD_SUPPORT_ATC
-#define BASISD_SUPPORT_ATC 1
+ #define BASISD_SUPPORT_ATC 1
#endif
// Support for ETC2 EAC R11 and ETC2 EAC RG11
#ifndef BASISD_SUPPORT_ETC2_EAC_RG11
-#define BASISD_SUPPORT_ETC2_EAC_RG11 1
+ #define BASISD_SUPPORT_ETC2_EAC_RG11 1
#endif
// If BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY is 1, opaque blocks will be transcoded to ASTC at slightly higher quality (higher than BC1), but the transcoder tables will be 2x as large.
@@ -89,26 +112,25 @@
#endif
#ifndef BASISD_SUPPORT_FXT1
-#define BASISD_SUPPORT_FXT1 1
+ #define BASISD_SUPPORT_FXT1 1
#endif
#ifndef BASISD_SUPPORT_PVRTC2
-#define BASISD_SUPPORT_PVRTC2 1
+ #define BASISD_SUPPORT_PVRTC2 1
#endif
#if BASISD_SUPPORT_PVRTC2
-#if !BASISD_SUPPORT_ATC
-#error BASISD_SUPPORT_ATC must be 1 if BASISD_SUPPORT_PVRTC2 is 1
-#endif
+ #if !BASISD_SUPPORT_ATC
+ #error BASISD_SUPPORT_ATC must be 1 if BASISD_SUPPORT_PVRTC2 is 1
+ #endif
#endif
#if BASISD_SUPPORT_ATC
-#if !BASISD_SUPPORT_DXT5A
-#error BASISD_SUPPORT_DXT5A must be 1 if BASISD_SUPPORT_ATC is 1
-#endif
+ #if !BASISD_SUPPORT_DXT5A
+ #error BASISD_SUPPORT_DXT5A must be 1 if BASISD_SUPPORT_ATC is 1
+ #endif
#endif
-#define BASISD_WRITE_NEW_BC7_TABLES 0
#define BASISD_WRITE_NEW_BC7_MODE5_TABLES 0
#define BASISD_WRITE_NEW_DXT1_TABLES 0
#define BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES 0
@@ -117,7 +139,16 @@
#define BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES 0
#ifndef BASISD_ENABLE_DEBUG_FLAGS
-#define BASISD_ENABLE_DEBUG_FLAGS 0
+ #define BASISD_ENABLE_DEBUG_FLAGS 0
+#endif
+
+// If KTX2 support is enabled, we may need Zstd for decompression of supercompressed UASTC files. Include this header.
+#if BASISD_SUPPORT_KTX2
+ // If BASISD_SUPPORT_KTX2_ZSTD is 0, UASTC files compressed with Zstd cannot be loaded.
+ #if BASISD_SUPPORT_KTX2_ZSTD
+ // We only use two Zstd API's: ZSTD_decompress() and ZSTD_isError()
+ #include "../zstd/zstd.h"
+ #endif
#endif
namespace basisu
@@ -131,7 +162,7 @@ namespace basisu
void debug_printf(const char* pFmt, ...)
{
-#if BASISU_DEVEL_MESSAGES
+#if BASISU_FORCE_DEVEL_MESSAGES
g_debug_printf = true;
#endif
if (g_debug_printf)
@@ -146,9 +177,6 @@ namespace basisu
namespace basist
{
-#if BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY
-#include "basisu_transcoder_tables_bc7_m6.inc"
-#endif
#if BASISD_ENABLE_DEBUG_FLAGS
static uint32_t g_debug_flags = 0;
@@ -165,16 +193,28 @@ namespace basist
void set_debug_flags(uint32_t f)
{
- (void)f;
+ BASISU_NOTE_UNUSED(f);
#if BASISD_ENABLE_DEBUG_FLAGS
g_debug_flags = f;
#endif
}
+
+ inline uint16_t byteswap_uint16(uint16_t v)
+ {
+ return static_cast<uint16_t>((v >> 8) | (v << 8));
+ }
+
+ static inline int32_t clampi(int32_t value, int32_t low, int32_t high) { if (value < low) value = low; else if (value > high) value = high; return value; }
+ static inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; }
+ static inline float saturate(float value) { return clampf(value, 0, 1.0f); }
+
+ static inline uint8_t mul_8(uint32_t v, uint32_t q) { v = v * q + 128; return (uint8_t)((v + (v >> 8)) >> 8); }
+
uint16_t crc16(const void* r, size_t size, uint16_t crc)
{
crc = ~crc;
- const uint8_t* p = reinterpret_cast<const uint8_t*>(r);
+ const uint8_t* p = static_cast<const uint8_t*>(r);
for (; size; --size)
{
const uint16_t q = *p++ ^ (crc >> 8);
@@ -279,6 +319,9 @@ namespace basist
DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables, 1);
DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables16, 16);
DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables48, 3 * 16);
+
+ //const uint8_t g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 };
+ const uint8_t g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 };
static const uint8_t g_etc_5_to_8[32] = { 0, 8, 16, 24, 33, 41, 49, 57, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 198, 206, 214, 222, 231, 239, 247, 255 };
@@ -522,11 +565,39 @@ namespace basist
return static_cast<uint16_t>(b | (g << 5U) | (r << 10U));
}
+ inline uint16_t get_base4_color(uint32_t idx) const
+ {
+ uint32_t r, g, b;
+ if (idx)
+ {
+ r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);
+ g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);
+ b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);
+ }
+ else
+ {
+ r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);
+ g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);
+ b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);
+ }
+ return static_cast<uint16_t>(b | (g << 4U) | (r << 8U));
+ }
+
inline color32 get_base5_color_unscaled() const
{
return color32(m_differential.m_red1, m_differential.m_green1, m_differential.m_blue1, 255);
}
+ inline bool get_flip_bit() const
+ {
+ return (m_bytes[3] & 1) != 0;
+ }
+
+ inline bool get_diff_bit() const
+ {
+ return (m_bytes[3] & 2) != 0;
+ }
+
inline uint32_t get_inten_table(uint32_t subblock_id) const
{
assert(subblock_id < 2);
@@ -534,6 +605,38 @@ namespace basist
return (m_bytes[3] >> ofs) & 7;
}
+ inline uint16_t get_delta3_color() const
+ {
+ const uint32_t r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3);
+ const uint32_t g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3);
+ const uint32_t b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3);
+ return static_cast<uint16_t>(b | (g << 3U) | (r << 6U));
+ }
+
+ void get_block_colors(color32* pBlock_colors, uint32_t subblock_index) const
+ {
+ color32 b;
+
+ if (get_diff_bit())
+ {
+ if (subblock_index)
+ unpack_color5(b, get_base5_color(), get_delta3_color(), true, 255);
+ else
+ unpack_color5(b, get_base5_color(), true);
+ }
+ else
+ {
+ b = unpack_color4(get_base4_color(subblock_index), true, 255);
+ }
+
+ const int* pInten_table = g_etc1_inten_tables[get_inten_table(subblock_index)];
+
+ pBlock_colors[0].set_noclamp_rgba(clamp255(b.r + pInten_table[0]), clamp255(b.g + pInten_table[0]), clamp255(b.b + pInten_table[0]), 255);
+ pBlock_colors[1].set_noclamp_rgba(clamp255(b.r + pInten_table[1]), clamp255(b.g + pInten_table[1]), clamp255(b.b + pInten_table[1]), 255);
+ pBlock_colors[2].set_noclamp_rgba(clamp255(b.r + pInten_table[2]), clamp255(b.g + pInten_table[2]), clamp255(b.b + pInten_table[2]), 255);
+ pBlock_colors[3].set_noclamp_rgba(clamp255(b.r + pInten_table[3]), clamp255(b.g + pInten_table[3]), clamp255(b.b + pInten_table[3]), 255);
+ }
+
static uint16_t pack_color4(const color32& color, bool scaled, uint32_t bias = 127U)
{
return pack_color4(color.r, color.g, color.b, scaled, bias);
@@ -592,7 +695,17 @@ namespace basist
return static_cast<uint16_t>(b | (g << 3) | (r << 6));
}
- static color32 unpack_color5(uint16_t packed_color5, bool scaled, uint32_t alpha = 255)
+ static void unpack_delta3(int& r, int& g, int& b, uint16_t packed_delta3)
+ {
+ r = (packed_delta3 >> 6) & 7;
+ g = (packed_delta3 >> 3) & 7;
+ b = packed_delta3 & 7;
+ if (r >= 4) r -= 8;
+ if (g >= 4) g -= 8;
+ if (b >= 4) b -= 8;
+ }
+
+ static color32 unpack_color5(uint16_t packed_color5, bool scaled, uint32_t alpha)
{
uint32_t b = packed_color5 & 31U;
uint32_t g = (packed_color5 >> 5U) & 31U;
@@ -605,7 +718,9 @@ namespace basist
r = (r << 3U) | (r >> 2U);
}
- return color32(r, g, b, alpha);
+ assert(alpha <= 255);
+
+ return color32(cNoClamp, r, g, b, alpha);
}
static void unpack_color5(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color5, bool scaled)
@@ -615,6 +730,64 @@ namespace basist
g = c.g;
b = c.b;
}
+
+ static void unpack_color5(color32& result, uint16_t packed_color5, bool scaled)
+ {
+ result = unpack_color5(packed_color5, scaled, 255);
+ }
+
+ static bool unpack_color5(color32& result, uint16_t packed_color5, uint16_t packed_delta3, bool scaled, uint32_t alpha)
+ {
+ int dr, dg, db;
+ unpack_delta3(dr, dg, db, packed_delta3);
+
+ int r = ((packed_color5 >> 10U) & 31U) + dr;
+ int g = ((packed_color5 >> 5U) & 31U) + dg;
+ int b = (packed_color5 & 31U) + db;
+
+ bool success = true;
+ if (static_cast<uint32_t>(r | g | b) > 31U)
+ {
+ success = false;
+ r = basisu::clamp<int>(r, 0, 31);
+ g = basisu::clamp<int>(g, 0, 31);
+ b = basisu::clamp<int>(b, 0, 31);
+ }
+
+ if (scaled)
+ {
+ b = (b << 3U) | (b >> 2U);
+ g = (g << 3U) | (g >> 2U);
+ r = (r << 3U) | (r >> 2U);
+ }
+
+ result.set_noclamp_rgba(r, g, b, basisu::minimum(alpha, 255U));
+ return success;
+ }
+
+ static color32 unpack_color4(uint16_t packed_color4, bool scaled, uint32_t alpha)
+ {
+ uint32_t b = packed_color4 & 15U;
+ uint32_t g = (packed_color4 >> 4U) & 15U;
+ uint32_t r = (packed_color4 >> 8U) & 15U;
+
+ if (scaled)
+ {
+ b = (b << 4U) | b;
+ g = (g << 4U) | g;
+ r = (r << 4U) | r;
+ }
+
+ return color32(cNoClamp, r, g, b, basisu::minimum(alpha, 255U));
+ }
+
+ static void unpack_color4(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color4, bool scaled)
+ {
+ color32 c(unpack_color4(packed_color4, scaled, 0));
+ r = c.r;
+ g = c.g;
+ b = c.b;
+ }
static void get_diff_subblock_colors(color32* pDst, uint16_t packed_color5, uint32_t table_idx)
{
@@ -823,197 +996,6 @@ namespace basist
uint32_t m_high;
};
-#if BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY
- static dxt_selector_range g_etc1_to_bc7_selector_ranges[] =
- {
- { 0, 0 },
- { 1, 1 },
- { 2, 2 },
- { 3, 3 },
-
- { 0, 3 },
-
- { 1, 3 },
- { 0, 2 },
-
- { 1, 2 },
-
- { 2, 3 },
- { 0, 1 },
- };
- const uint32_t NUM_ETC1_TO_BC7_M6_SELECTOR_RANGES = sizeof(g_etc1_to_bc7_selector_ranges) / sizeof(g_etc1_to_bc7_selector_ranges[0]);
-
- static uint32_t g_etc1_to_bc7_m6_selector_range_index[4][4];
-
- static const uint8_t g_etc1_to_bc7_selector_mappings[][4] =
- {
-#if 1
- { 5 * 0, 5 * 0, 5 * 0, 5 * 0 },
- { 5 * 0, 5 * 0, 5 * 0, 5 * 1 },
- { 5 * 0, 5 * 0, 5 * 0, 5 * 2 },
- { 5 * 0, 5 * 0, 5 * 0, 5 * 3 },
- { 5 * 0, 5 * 0, 5 * 1, 5 * 1 },
- { 5 * 0, 5 * 0, 5 * 1, 5 * 2 },
- { 5 * 0, 5 * 0, 5 * 1, 5 * 3 },
- { 5 * 0, 5 * 0, 5 * 2, 5 * 2 },
- { 5 * 0, 5 * 0, 5 * 2, 5 * 3 },
- { 5 * 0, 5 * 0, 5 * 3, 5 * 3 },
- { 5 * 0, 5 * 1, 5 * 1, 5 * 1 },
- { 5 * 0, 5 * 1, 5 * 1, 5 * 2 },
- { 5 * 0, 5 * 1, 5 * 1, 5 * 3 },
- { 5 * 0, 5 * 1, 5 * 2, 5 * 2 },
- { 5 * 0, 5 * 1, 5 * 2, 5 * 3 },
- { 5 * 0, 5 * 1, 5 * 3, 5 * 3 },
- { 5 * 0, 5 * 2, 5 * 2, 5 * 2 },
- { 5 * 0, 5 * 2, 5 * 2, 5 * 3 },
- { 5 * 0, 5 * 2, 5 * 3, 5 * 3 },
- { 5 * 0, 5 * 3, 5 * 3, 5 * 3 },
- { 5 * 1, 5 * 1, 5 * 1, 5 * 1 },
- { 5 * 1, 5 * 1, 5 * 1, 5 * 2 },
- { 5 * 1, 5 * 1, 5 * 1, 5 * 3 },
- { 5 * 1, 5 * 1, 5 * 2, 5 * 2 },
- { 5 * 1, 5 * 1, 5 * 2, 5 * 3 },
- { 5 * 1, 5 * 1, 5 * 3, 5 * 3 },
- { 5 * 1, 5 * 2, 5 * 2, 5 * 2 },
- { 5 * 1, 5 * 2, 5 * 2, 5 * 3 },
- { 5 * 1, 5 * 2, 5 * 3, 5 * 3 },
- { 5 * 1, 5 * 3, 5 * 3, 5 * 3 },
- { 5 * 2, 5 * 2, 5 * 2, 5 * 2 },
- { 5 * 2, 5 * 2, 5 * 2, 5 * 3 },
- { 5 * 2, 5 * 2, 5 * 3, 5 * 3 },
- { 5 * 2, 5 * 3, 5 * 3, 5 * 3 },
- { 5 * 3, 5 * 3, 5 * 3, 5 * 3 },
-
- { 0, 1, 2, 3 },
- { 0, 0, 1, 1 },
- { 0, 0, 0, 1 },
- { 0, 2, 4, 6 },
- { 0, 3, 6, 9 },
- { 0, 4, 8, 12 },
-
- { 0, 4, 9, 15 },
- { 0, 6, 11, 15 },
-
- { 1, 2, 3, 4 },
- { 1, 3, 5, 7 },
-
- { 1, 8, 8, 14 },
-#else
- { 5 * 0, 5 * 0, 5 * 1, 5 * 1 },
- { 5 * 0, 5 * 0, 5 * 1, 5 * 2 },
- { 5 * 0, 5 * 0, 5 * 1, 5 * 3 },
- { 5 * 0, 5 * 0, 5 * 2, 5 * 3 },
- { 5 * 0, 5 * 1, 5 * 1, 5 * 1 },
- { 5 * 0, 5 * 1, 5 * 2, 5 * 2 },
- { 5 * 0, 5 * 1, 5 * 2, 5 * 3 },
- { 5 * 0, 5 * 2, 5 * 3, 5 * 3 },
- { 5 * 1, 5 * 2, 5 * 2, 5 * 2 },
-#endif
- { 5 * 1, 5 * 2, 5 * 3, 5 * 3 },
- { 8, 8, 8, 8 },
- };
- const uint32_t NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS = sizeof(g_etc1_to_bc7_selector_mappings) / sizeof(g_etc1_to_bc7_selector_mappings[0]);
-
- static uint8_t g_etc1_to_bc7_selector_mappings_inv[NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS][4];
-
- // encoding from LSB to MSB: low8, high8, error16, size is [32*8][NUM_ETC1_TO_BC7_M6_SELECTOR_RANGES][NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS]
- extern const uint32_t* g_etc1_to_bc7_m6_table[];
-
- const uint16_t s_bptc_table_aWeight4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
-
-#if BASISD_WRITE_NEW_BC7_TABLES
- static void create_etc1_to_bc7_m6_conversion_table()
- {
- FILE* pFile = NULL;
-
- pFile = fopen("basisu_decoder_tables_bc7_m6.inc", "w");
-
- for (int inten = 0; inten < 8; inten++)
- {
- for (uint32_t g = 0; g < 32; g++)
- {
- color32 block_colors[4];
- decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);
-
- fprintf(pFile, "static const uint32_t g_etc1_to_bc7_m6_table%u[] = {\n", g + inten * 32);
- uint32_t n = 0;
-
- for (uint32_t sr = 0; sr < NUM_ETC1_TO_BC7_M6_SELECTOR_RANGES; sr++)
- {
- const uint32_t low_selector = g_etc1_to_bc7_selector_ranges[sr].m_low;
- const uint32_t high_selector = g_etc1_to_bc7_selector_ranges[sr].m_high;
-
- for (uint32_t m = 0; m < NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS; m++)
- {
- uint32_t best_lo = 0;
- uint32_t best_hi = 0;
- uint64_t best_err = UINT64_MAX;
-
- for (uint32_t hi = 0; hi <= 127; hi++)
- {
- for (uint32_t lo = 0; lo <= 127; lo++)
- {
- uint32_t bc7_block_colors[16];
-
- bc7_block_colors[0] = lo << 1;
- bc7_block_colors[15] = (hi << 1) | 1;
-
- for (uint32_t i = 1; i < 15; i++)
- bc7_block_colors[i] = (bc7_block_colors[0] * (64 - s_bptc_table_aWeight4[i]) + bc7_block_colors[15] * s_bptc_table_aWeight4[i] + 32) >> 6;
-
- uint64_t total_err = 0;
-
- for (uint32_t s = low_selector; s <= high_selector; s++)
- {
- int err = (int)block_colors[s].g - (int)bc7_block_colors[g_etc1_to_bc7_selector_mappings[m][s]];
-
- total_err += err * err;
- }
-
- if (total_err < best_err)
- {
- best_err = total_err;
- best_lo = lo;
- best_hi = hi;
- }
- } // lo
-
- } // hi
-
- best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);
-
- const uint32_t index = (g + inten * 32) * (NUM_ETC1_TO_BC7_M6_SELECTOR_RANGES * NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS) + (sr * NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS) + m;
-
- uint32_t v = best_err | (best_lo << 18) | (best_hi << 25);
-
- fprintf(pFile, "0x%X,", v);
- n++;
- if ((n & 31) == 31)
- fprintf(pFile, "\n");
-
- } // m
- } // sr
-
- fprintf(pFile, "};\n");
-
- } // g
- } // inten
-
- fprintf(pFile, "const uint32_t *g_etc1_to_bc7_m6_table[] = {\n");
-
- for (uint32_t i = 0; i < 32 * 8; i++)
- {
- fprintf(pFile, "g_etc1_to_bc7_m6_table%u, ", i);
- if ((i & 15) == 15)
- fprintf(pFile, "\n");
- }
-
- fprintf(pFile, "};\n");
- fclose(pFile);
- }
-#endif
-#endif
-
struct etc1_to_dxt1_56_solution
{
uint8_t m_lo;
@@ -1064,7 +1046,9 @@ namespace basist
static const etc1_to_dxt1_56_solution g_etc1_to_dxt_5[32 * 8 * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS * NUM_ETC1_TO_DXT1_SELECTOR_RANGES] = {
#include "basisu_transcoder_tables_dxt1_5.inc"
};
+#endif // BASISD_SUPPORT_DXT1
+#if BASISD_SUPPORT_DXT1 || BASISD_SUPPORT_UASTC
// First saw the idea for optimal BC1 single-color block encoding using lookup tables in ryg_dxt.
struct bc1_match_entry
{
@@ -1089,14 +1073,15 @@ namespace basist
if (sel == 1)
{
// Selector 1
- e = abs(((hi_e * 2 + lo_e) / 3) - i) + ((abs(hi_e - lo_e) >> 5));
+ e = basisu::iabs(((hi_e * 2 + lo_e) / 3) - i);
+ e += (basisu::iabs(hi_e - lo_e) * 3) / 100;
}
else
{
assert(sel == 0);
// Selector 0
- e = abs(hi_e - i);
+ e = basisu::iabs(hi_e - i);
}
if (e < lowest_e)
@@ -1111,7 +1096,7 @@ namespace basist
} // lo
}
}
-#endif // BASISD_SUPPORT_DXT1
+#endif
#if BASISD_WRITE_NEW_DXT1_TABLES
static void create_etc1_to_dxt1_5_conversion_table()
@@ -1268,7 +1253,8 @@ namespace basist
}
#endif
-#if BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11
+
+#if BASISD_SUPPORT_UASTC || BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11
static const int8_t g_eac_modifier_table[16][8] =
{
{ -3, -6, -9, -15, 2, 5, 8, 14 },
@@ -1344,6 +1330,9 @@ namespace basist
}
};
+#endif // #if BASISD_SUPPORT_UASTC BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11
+
+#if BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11
static const dxt_selector_range s_etc2_eac_selector_ranges[] =
{
{ 0, 3 },
@@ -1372,8 +1361,8 @@ namespace basist
uint32_t m_base;
uint32_t m_table;
uint32_t m_multiplier;
- std::vector<uint8_t> m_selectors;
- std::vector<uint8_t> m_selectors_temp;
+ basisu::vector<uint8_t> m_selectors;
+ basisu::vector<uint8_t> m_selectors_temp;
};
static uint64_t pack_eac_a8_exhaustive(pack_eac_a8_results& results, const uint8_t* pPixels, uint32_t num_pixels)
@@ -1769,8 +1758,8 @@ namespace basist
uint32_t m_base;
uint32_t m_table;
uint32_t m_multiplier;
- std::vector<uint8_t> m_selectors;
- std::vector<uint8_t> m_selectors_temp;
+ basisu::vector<uint8_t> m_selectors;
+ basisu::vector<uint8_t> m_selectors_temp;
};
static uint64_t pack_eac_r11_exhaustive(pack_eac_r11_results& results, const uint8_t* pPixels, uint32_t num_pixels)
@@ -1924,14 +1913,28 @@ namespace basist
#if BASISD_SUPPORT_PVRTC2
static void transcoder_init_pvrtc2();
#endif
+
+#if BASISD_SUPPORT_UASTC
+ void uastc_init();
+#endif
+
+ static bool g_transcoder_initialized;
// Library global initialization. Requires ~9 milliseconds when compiled and executed natively on a Core i7 2.2 GHz.
// If this is too slow, these computed tables can easilky be moved to be compiled in.
void basisu_transcoder_init()
{
- static bool s_initialized;
- if (s_initialized)
+ if (g_transcoder_initialized)
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Called more than once\n");
return;
+ }
+
+ BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Initializing (this is not an error)\n");
+
+#if BASISD_SUPPORT_UASTC
+ uastc_init();
+#endif
#if BASISD_SUPPORT_ASTC
transcoder_init_astc();
@@ -1943,11 +1946,6 @@ namespace basist
exit(0);
#endif
-#if BASISD_WRITE_NEW_BC7_TABLES
- create_etc1_to_bc7_m6_conversion_table();
- exit(0);
-#endif
-
#if BASISD_WRITE_NEW_BC7_MODE5_TABLES
create_etc1_to_bc7_m5_color_conversion_table();
create_etc1_to_bc7_m5_alpha_conversion_table();
@@ -1975,7 +1973,7 @@ namespace basist
exit(0);
#endif
-#if BASISD_SUPPORT_DXT1
+#if BASISD_SUPPORT_DXT1 || BASISD_SUPPORT_UASTC
uint8_t bc1_expand5[32];
for (int i = 0; i < 32; i++)
bc1_expand5[i] = static_cast<uint8_t>((i << 3) | (i >> 2));
@@ -1988,6 +1986,17 @@ namespace basist
prepare_bc1_single_color_table(g_bc1_match6_equals_1, bc1_expand6, 64, 64, 1);
prepare_bc1_single_color_table(g_bc1_match6_equals_0, bc1_expand6, 1, 64, 0);
+#if 0
+ for (uint32_t i = 0; i < 256; i++)
+ {
+ printf("%u %u %u\n", i, (i * 63 + 127) / 255, g_bc1_match6_equals_0[i].m_hi);
+ }
+ exit(0);
+#endif
+
+#endif
+
+#if BASISD_SUPPORT_DXT1
for (uint32_t i = 0; i < NUM_ETC1_TO_DXT1_SELECTOR_RANGES; i++)
{
uint32_t l = g_etc1_to_dxt1_selector_ranges[i].m_low;
@@ -2023,19 +2032,6 @@ namespace basist
}
#endif
-#if BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY
- for (uint32_t i = 0; i < NUM_ETC1_TO_BC7_M6_SELECTOR_RANGES; i++)
- {
- uint32_t l = g_etc1_to_bc7_selector_ranges[i].m_low;
- uint32_t h = g_etc1_to_bc7_selector_ranges[i].m_high;
- g_etc1_to_bc7_m6_selector_range_index[l][h] = i;
- }
-
- for (uint32_t sm = 0; sm < NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS; sm++)
- for (uint32_t j = 0; j < 4; j++)
- g_etc1_to_bc7_selector_mappings_inv[sm][j] = 15 - g_etc1_to_bc7_selector_mappings[sm][j];
-#endif
-
#if BASISD_SUPPORT_BC7_MODE5
transcoder_init_bc7_mode5();
#endif
@@ -2048,7 +2044,7 @@ namespace basist
transcoder_init_pvrtc2();
#endif
- s_initialized = true;
+ g_transcoder_initialized = true;
}
#if BASISD_SUPPORT_DXT1
@@ -2780,7 +2776,7 @@ namespace basist
// PVRTC
-#if BASISD_SUPPORT_PVRTC1
+#if BASISD_SUPPORT_PVRTC1 || BASISD_SUPPORT_UASTC
static const uint16_t g_pvrtc_swizzle_table[256] =
{
0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
@@ -3304,6 +3300,7 @@ namespace basist
}
};
+#if 0
static const uint8_t g_pvrtc_bilinear_weights[16][4] =
{
{ 4, 4, 4, 4 }, { 2, 6, 2, 6 }, { 8, 0, 8, 0 }, { 6, 2, 6, 2 },
@@ -3311,6 +3308,7 @@ namespace basist
{ 8, 8, 0, 0 }, { 4, 12, 0, 0 }, { 16, 0, 0, 0 }, { 12, 4, 0, 0 },
{ 6, 6, 2, 2 }, { 3, 9, 1, 3 }, { 12, 0, 4, 0 }, { 9, 3, 3, 1 },
};
+#endif
struct pvrtc1_temp_block
{
@@ -3402,7 +3400,9 @@ namespace basist
color32 c(get_endpoint_8888(endpoints, endpoint_index));
return c.r + c.g + c.b + c.a;
}
+#endif
+#if BASISD_SUPPORT_PVRTC1
// TODO: Support decoding a non-pow2 ETC1S texture into the next larger pow2 PVRTC texture.
static void fixup_pvrtc1_4_modulation_rgb(const decoder_etc_block* pETC_Blocks, const uint32_t* pPVRTC_endpoints, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y)
{
@@ -3411,7 +3411,7 @@ namespace basist
const uint32_t x_bits = basisu::total_bits(x_mask);
const uint32_t y_bits = basisu::total_bits(y_mask);
const uint32_t min_bits = basisu::minimum(x_bits, y_bits);
- const uint32_t max_bits = basisu::maximum(x_bits, y_bits);
+ //const uint32_t max_bits = basisu::maximum(x_bits, y_bits);
const uint32_t swizzle_mask = (1 << (min_bits * 2)) - 1;
uint32_t block_index = 0;
@@ -3592,7 +3592,7 @@ namespace basist
const uint32_t x_bits = basisu::total_bits(x_mask);
const uint32_t y_bits = basisu::total_bits(y_mask);
const uint32_t min_bits = basisu::minimum(x_bits, y_bits);
- const uint32_t max_bits = basisu::maximum(x_bits, y_bits);
+ //const uint32_t max_bits = basisu::maximum(x_bits, y_bits);
const uint32_t swizzle_mask = (1 << (min_bits * 2)) - 1;
uint32_t block_index = 0;
@@ -3763,257 +3763,6 @@ namespace basist
}
#endif // BASISD_SUPPORT_PVRTC1
-#if BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY
- struct bc7_mode_6
- {
- struct
- {
- uint64_t m_mode : 7;
- uint64_t m_r0 : 7;
- uint64_t m_r1 : 7;
- uint64_t m_g0 : 7;
- uint64_t m_g1 : 7;
- uint64_t m_b0 : 7;
- uint64_t m_b1 : 7;
- uint64_t m_a0 : 7;
- uint64_t m_a1 : 7;
- uint64_t m_p0 : 1;
- } m_lo;
-
- union
- {
- struct
- {
- uint64_t m_p1 : 1;
- uint64_t m_s00 : 3;
- uint64_t m_s10 : 4;
- uint64_t m_s20 : 4;
- uint64_t m_s30 : 4;
-
- uint64_t m_s01 : 4;
- uint64_t m_s11 : 4;
- uint64_t m_s21 : 4;
- uint64_t m_s31 : 4;
-
- uint64_t m_s02 : 4;
- uint64_t m_s12 : 4;
- uint64_t m_s22 : 4;
- uint64_t m_s32 : 4;
-
- uint64_t m_s03 : 4;
- uint64_t m_s13 : 4;
- uint64_t m_s23 : 4;
- uint64_t m_s33 : 4;
-
- } m_hi;
-
- uint64_t m_hi_bits;
- };
- };
-
- static void convert_etc1s_to_bc7_m6(bc7_mode_6* pDst_block, const endpoint *pEndpoint, const selector* pSelector)
- {
-#if !BASISD_WRITE_NEW_BC7_TABLES
- const uint32_t low_selector = pSelector->m_lo_selector;
- const uint32_t high_selector = pSelector->m_hi_selector;
-
- const uint32_t base_color_r = pEndpoint->m_color5.r;
- const uint32_t base_color_g = pEndpoint->m_color5.g;
- const uint32_t base_color_b = pEndpoint->m_color5.b;
- const uint32_t inten_table = pEndpoint->m_inten5;
-
- if (pSelector->m_num_unique_selectors <= 2)
- {
- // Only two unique selectors so just switch to block truncation coding (BTC) to avoid quality issues on extreme blocks.
- pDst_block->m_lo.m_mode = 64;
-
- pDst_block->m_lo.m_a0 = 127;
- pDst_block->m_lo.m_a1 = 127;
-
- color32 block_colors[4];
-
- decoder_etc_block::get_block_colors5(block_colors, color32(base_color_r, base_color_g, base_color_b, 255), inten_table);
-
- const uint32_t r0 = block_colors[low_selector].r;
- const uint32_t g0 = block_colors[low_selector].g;
- const uint32_t b0 = block_colors[low_selector].b;
- const uint32_t low_bits0 = (r0 & 1) + (g0 & 1) + (b0 & 1);
- uint32_t p0 = low_bits0 >= 2;
-
- const uint32_t r1 = block_colors[high_selector].r;
- const uint32_t g1 = block_colors[high_selector].g;
- const uint32_t b1 = block_colors[high_selector].b;
- const uint32_t low_bits1 = (r1 & 1) + (g1 & 1) + (b1 & 1);
- uint32_t p1 = low_bits1 >= 2;
-
- pDst_block->m_lo.m_r0 = r0 >> 1;
- pDst_block->m_lo.m_g0 = g0 >> 1;
- pDst_block->m_lo.m_b0 = b0 >> 1;
- pDst_block->m_lo.m_p0 = p0;
-
- pDst_block->m_lo.m_r1 = r1 >> 1;
- pDst_block->m_lo.m_g1 = g1 >> 1;
- pDst_block->m_lo.m_b1 = b1 >> 1;
-
- uint32_t output_low_selector = 0;
- uint32_t output_bit_offset = 1;
- uint64_t output_hi_bits = p1;
-
- for (uint32_t y = 0; y < 4; y++)
- {
- for (uint32_t x = 0; x < 4; x++)
- {
- uint32_t s = pSelector->get_selector(x, y);
- uint32_t os = (s == low_selector) ? output_low_selector : (15 ^ output_low_selector);
-
- uint32_t num_bits = 4;
-
- if ((x | y) == 0)
- {
- if (os & 8)
- {
- pDst_block->m_lo.m_r0 = r1 >> 1;
- pDst_block->m_lo.m_g0 = g1 >> 1;
- pDst_block->m_lo.m_b0 = b1 >> 1;
- pDst_block->m_lo.m_p0 = p1;
-
- pDst_block->m_lo.m_r1 = r0 >> 1;
- pDst_block->m_lo.m_g1 = g0 >> 1;
- pDst_block->m_lo.m_b1 = b0 >> 1;
-
- output_hi_bits &= ~1ULL;
- output_hi_bits |= p0;
- std::swap(p0, p1);
-
- output_low_selector = 15;
- os = 0;
- }
-
- num_bits = 3;
- }
-
- output_hi_bits |= (static_cast<uint64_t>(os) << output_bit_offset);
- output_bit_offset += num_bits;
- }
- }
-
- pDst_block->m_hi_bits = output_hi_bits;
-
- assert(pDst_block->m_hi.m_p1 == p1);
-
- return;
- }
-
- uint32_t selector_range_table = g_etc1_to_bc7_m6_selector_range_index[low_selector][high_selector];
-
- const uint32_t* pTable_r = g_etc1_to_bc7_m6_table[base_color_r + inten_table * 32] + (selector_range_table * NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS);
- const uint32_t* pTable_g = g_etc1_to_bc7_m6_table[base_color_g + inten_table * 32] + (selector_range_table * NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS);
- const uint32_t* pTable_b = g_etc1_to_bc7_m6_table[base_color_b + inten_table * 32] + (selector_range_table * NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS);
-
-#if 1
- assert(NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS == 48);
-
- uint32_t best_err0 = UINT_MAX, best_err1 = UINT_MAX;
-
-#define DO_ITER2(idx) \
- { \
- uint32_t v0 = ((pTable_r[(idx)+0] + pTable_g[(idx)+0] + pTable_b[(idx)+0]) << 14) | ((idx) + 0); if (v0 < best_err0) best_err0 = v0; \
- uint32_t v1 = ((pTable_r[(idx)+1] + pTable_g[(idx)+1] + pTable_b[(idx)+1]) << 14) | ((idx) + 1); if (v1 < best_err1) best_err1 = v1; \
- }
-#define DO_ITER4(idx) DO_ITER2(idx); DO_ITER2((idx) + 2);
-#define DO_ITER8(idx) DO_ITER4(idx); DO_ITER4((idx) + 4);
-#define DO_ITER16(idx) DO_ITER8(idx); DO_ITER8((idx) + 8);
-
- DO_ITER16(0);
- DO_ITER16(16);
- DO_ITER16(32);
-#undef DO_ITER2
-#undef DO_ITER4
-#undef DO_ITER8
-#undef DO_ITER16
-
- uint32_t best_err = basisu::minimum(best_err0, best_err1);
- uint32_t best_mapping = best_err & 0xFF;
- //best_err >>= 14;
-#else
- uint32_t best_err = UINT_MAX;
- uint32_t best_mapping = 0;
- assert((NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS % 2) == 0);
- for (uint32_t m = 0; m < NUM_ETC1_TO_BC7_M6_SELECTOR_MAPPINGS; m += 2)
- {
-#define DO_ITER(idx) { uint32_t total_err = (pTable_r[idx] + pTable_g[idx] + pTable_b[idx]) & 0x3FFFF; if (total_err < best_err) { best_err = total_err; best_mapping = idx; } }
- DO_ITER(m);
- DO_ITER(m + 1);
-#undef DO_ITER
- }
-#endif
-
- pDst_block->m_lo.m_mode = 64;
-
- pDst_block->m_lo.m_a0 = 127;
- pDst_block->m_lo.m_a1 = 127;
-
- uint64_t v = 0;
- const uint8_t* pSelectors_xlat;
-
- if (g_etc1_to_bc7_selector_mappings[best_mapping][pSelector->get_selector(0, 0)] & 8)
- {
- pDst_block->m_lo.m_r1 = (pTable_r[best_mapping] >> 18) & 0x7F;
- pDst_block->m_lo.m_g1 = (pTable_g[best_mapping] >> 18) & 0x7F;
- pDst_block->m_lo.m_b1 = (pTable_b[best_mapping] >> 18) & 0x7F;
-
- pDst_block->m_lo.m_r0 = (pTable_r[best_mapping] >> 25) & 0x7F;
- pDst_block->m_lo.m_g0 = (pTable_g[best_mapping] >> 25) & 0x7F;
- pDst_block->m_lo.m_b0 = (pTable_b[best_mapping] >> 25) & 0x7F;
-
- pDst_block->m_lo.m_p0 = 1;
- pDst_block->m_hi.m_p1 = 0;
-
- v = 0;
- pSelectors_xlat = &g_etc1_to_bc7_selector_mappings_inv[best_mapping][0];
- }
- else
- {
- pDst_block->m_lo.m_r0 = (pTable_r[best_mapping] >> 18) & 0x7F;
- pDst_block->m_lo.m_g0 = (pTable_g[best_mapping] >> 18) & 0x7F;
- pDst_block->m_lo.m_b0 = (pTable_b[best_mapping] >> 18) & 0x7F;
-
- pDst_block->m_lo.m_r1 = (pTable_r[best_mapping] >> 25) & 0x7F;
- pDst_block->m_lo.m_g1 = (pTable_g[best_mapping] >> 25) & 0x7F;
- pDst_block->m_lo.m_b1 = (pTable_b[best_mapping] >> 25) & 0x7F;
-
- pDst_block->m_lo.m_p0 = 0;
- pDst_block->m_hi.m_p1 = 1;
-
- v = 1;
- pSelectors_xlat = &g_etc1_to_bc7_selector_mappings[best_mapping][0];
- }
-
- uint64_t v1 = 0, v2 = 0, v3 = 0;
-
-#define DO_X(x, s0, s1, s2, s3) { \
- v |= ((uint64_t)pSelectors_xlat[(pSelector->m_selectors[0] >> ((x) * 2)) & 3] << (s0)); \
- v1 |= ((uint64_t)pSelectors_xlat[(pSelector->m_selectors[1] >> ((x) * 2)) & 3] << (s1)); \
- v2 |= ((uint64_t)pSelectors_xlat[(pSelector->m_selectors[2] >> ((x) * 2)) & 3] << (s2)); \
- v3 |= ((uint64_t)pSelectors_xlat[(pSelector->m_selectors[3] >> ((x) * 2)) & 3] << (s3)); }
-
- // 1 4 8 12
- // 16 20 24 28
- // 32 36 40 44
- // 48 52 56 60
-
- DO_X(0, 1, 16, 32, 48);
- DO_X(1, 4, 20, 36, 52);
- DO_X(2, 8, 24, 40, 56);
- DO_X(3, 12, 28, 44, 60);
-#undef DO_X
-
- pDst_block->m_hi_bits = v | v1 | v2 | v3;
-#endif
-
- }
-#endif // BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY
-
#if BASISD_SUPPORT_BC7_MODE5
static dxt_selector_range g_etc1_to_bc7_m5_selector_ranges[] =
{
@@ -4085,7 +3834,7 @@ namespace basist
assert(num_bits < 32);
assert(val < (1ULL << num_bits));
- uint32_t mask = (1 << num_bits) - 1;
+ uint32_t mask = static_cast<uint32_t>((1ULL << num_bits) - 1);
while (num_bits)
{
@@ -4425,9 +4174,11 @@ namespace basist
{
bc7_mode_5* pDst_block = static_cast<bc7_mode_5*>(pDst);
+ // First ensure the block is cleared to all 0's
static_cast<uint64_t*>(pDst)[0] = 0;
static_cast<uint64_t*>(pDst)[1] = 0;
+ // Set alpha to 255
pDst_block->m_lo.m_mode = 1 << 5;
pDst_block->m_lo.m_a0 = 255;
pDst_block->m_lo.m_a1_0 = 63;
@@ -4690,7 +4441,11 @@ namespace basist
set_block_bits((uint8_t*)pDst, output_bits, 31, 97);
}
#endif // BASISD_SUPPORT_BC7_MODE5
-
+
+#if BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_UASTC
+ static const uint8_t g_etc2_eac_a8_sel4[6] = { 0x92, 0x49, 0x24, 0x92, 0x49, 0x24 };
+#endif
+
#if BASISD_SUPPORT_ETC2_EAC_A8
static void convert_etc1s_to_etc2_eac_a8(eac_block* pDst_block, const endpoint* pEndpoints, const selector* pSelector)
{
@@ -4712,8 +4467,7 @@ namespace basist
pDst_block->m_multiplier = 1;
// selectors are all 4's
- static const uint8_t s_etc2_eac_a8_sel4[6] = { 0x92, 0x49, 0x24, 0x92, 0x49, 0x24 };
- memcpy(pDst_block->m_selectors, s_etc2_eac_a8_sel4, sizeof(s_etc2_eac_a8_sel4));
+ memcpy(pDst_block->m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4));
return;
}
@@ -5325,31 +5079,30 @@ namespace basist
#endif
-#if BASISD_SUPPORT_ASTC
- struct astc_block_params
- {
- // 2 groups of 5, but only a max of 8 are used (RRGGBBAA00)
- uint8_t m_endpoints[10];
- uint8_t m_weights[32];
- };
-
+#if BASISD_SUPPORT_UASTC || BASISD_SUPPORT_ASTC
// Table encodes 5 trits to 8 output bits. 3^5 entries.
// Inverse of the trit bit manipulation process in https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-integer-sequence-encoding
- static const uint8_t g_astc_trit_encode[243] = { 0, 1, 2, 4, 5, 6, 8, 9, 10, 16, 17, 18, 20, 21, 22, 24, 25, 26, 3, 7, 11, 19, 23, 27, 12, 13, 14, 32, 33, 34, 36, 37, 38, 40, 41, 42, 48, 49, 50, 52, 53, 54, 56, 57, 58, 35, 39,
- 43, 51, 55, 59, 44, 45, 46, 64, 65, 66, 68, 69, 70, 72, 73, 74, 80, 81, 82, 84, 85, 86, 88, 89, 90, 67, 71, 75, 83, 87, 91, 76, 77, 78, 128, 129, 130, 132, 133, 134, 136, 137, 138, 144, 145, 146, 148, 149, 150, 152, 153, 154,
- 131, 135, 139, 147, 151, 155, 140, 141, 142, 160, 161, 162, 164, 165, 166, 168, 169, 170, 176, 177, 178, 180, 181, 182, 184, 185, 186, 163, 167, 171, 179, 183, 187, 172, 173, 174, 192, 193, 194, 196, 197, 198, 200, 201, 202,
- 208, 209, 210, 212, 213, 214, 216, 217, 218, 195, 199, 203, 211, 215, 219, 204, 205, 206, 96, 97, 98, 100, 101, 102, 104, 105, 106, 112, 113, 114, 116, 117, 118, 120, 121, 122, 99, 103, 107, 115, 119, 123, 108, 109, 110, 224,
- 225, 226, 228, 229, 230, 232, 233, 234, 240, 241, 242, 244, 245, 246, 248, 249, 250, 227, 231, 235, 243, 247, 251, 236, 237, 238, 28, 29, 30, 60, 61, 62, 92, 93, 94, 156, 157, 158, 188, 189, 190, 220, 221, 222, 31, 63, 95, 159,
+ static const uint8_t g_astc_trit_encode[243] = { 0, 1, 2, 4, 5, 6, 8, 9, 10, 16, 17, 18, 20, 21, 22, 24, 25, 26, 3, 7, 11, 19, 23, 27, 12, 13, 14, 32, 33, 34, 36, 37, 38, 40, 41, 42, 48, 49, 50, 52, 53, 54, 56, 57, 58, 35, 39,
+ 43, 51, 55, 59, 44, 45, 46, 64, 65, 66, 68, 69, 70, 72, 73, 74, 80, 81, 82, 84, 85, 86, 88, 89, 90, 67, 71, 75, 83, 87, 91, 76, 77, 78, 128, 129, 130, 132, 133, 134, 136, 137, 138, 144, 145, 146, 148, 149, 150, 152, 153, 154,
+ 131, 135, 139, 147, 151, 155, 140, 141, 142, 160, 161, 162, 164, 165, 166, 168, 169, 170, 176, 177, 178, 180, 181, 182, 184, 185, 186, 163, 167, 171, 179, 183, 187, 172, 173, 174, 192, 193, 194, 196, 197, 198, 200, 201, 202,
+ 208, 209, 210, 212, 213, 214, 216, 217, 218, 195, 199, 203, 211, 215, 219, 204, 205, 206, 96, 97, 98, 100, 101, 102, 104, 105, 106, 112, 113, 114, 116, 117, 118, 120, 121, 122, 99, 103, 107, 115, 119, 123, 108, 109, 110, 224,
+ 225, 226, 228, 229, 230, 232, 233, 234, 240, 241, 242, 244, 245, 246, 248, 249, 250, 227, 231, 235, 243, 247, 251, 236, 237, 238, 28, 29, 30, 60, 61, 62, 92, 93, 94, 156, 157, 158, 188, 189, 190, 220, 221, 222, 31, 63, 95, 159,
191, 223, 124, 125, 126 };
+ // Extracts bits [low,high]
+ static inline uint32_t astc_extract_bits(uint32_t bits, int low, int high)
+ {
+ return (bits >> low) & ((1 << (high - low + 1)) - 1);
+ }
+
// Writes bits to output in an endian safe way
- static inline void astc_set_bits(uint32_t *pOutput, int &bit_pos, uint32_t value, int total_bits)
+ static inline void astc_set_bits(uint32_t* pOutput, int& bit_pos, uint32_t value, uint32_t total_bits)
{
uint8_t* pBytes = reinterpret_cast<uint8_t*>(pOutput);
-
+
while (total_bits)
{
- const uint32_t bits_to_write = std::min(total_bits, 8 - (bit_pos & 7));
+ const uint32_t bits_to_write = basisu::minimum<int>(total_bits, 8 - (bit_pos & 7));
pBytes[bit_pos >> 3] |= static_cast<uint8_t>(value << (bit_pos & 7));
@@ -5359,14 +5112,8 @@ namespace basist
}
}
- // Extracts bits [low,high]
- static inline uint32_t astc_extract_bits(uint32_t bits, int low, int high)
- {
- return (bits >> low) & ((1 << (high - low + 1)) - 1);
- }
-
// Encodes 5 values to output, usable for any range that uses trits and bits
- static void astc_encode_trits(uint32_t *pOutput, const uint8_t *pValues, int& bit_pos, int n)
+ static void astc_encode_trits(uint32_t* pOutput, const uint8_t* pValues, int& bit_pos, int n)
{
// First extract the trits and the bits from the 5 input values
int trits = 0, bits[5];
@@ -5374,9 +5121,9 @@ namespace basist
for (int i = 0; i < 5; i++)
{
static const int s_muls[5] = { 1, 3, 9, 27, 81 };
-
+
const int t = pValues[i] >> n;
-
+
trits += t * s_muls[i];
bits[i] = pValues[i] & bit_mask;
}
@@ -5386,14 +5133,23 @@ namespace basist
assert(trits < 243);
const int T = g_astc_trit_encode[trits];
-
+
// Now interleave the 8 encoded trit bits with the bits to form the encoded output. See table 94.
astc_set_bits(pOutput, bit_pos, bits[0] | (astc_extract_bits(T, 0, 1) << n) | (bits[1] << (2 + n)), n * 2 + 2);
- astc_set_bits(pOutput, bit_pos, astc_extract_bits(T, 2, 3) | (bits[2] << 2) | (astc_extract_bits(T, 4, 4) << (2 + n)) | (bits[3] << (3 + n)) | (astc_extract_bits(T, 5, 6) << (3 + n * 2)) |
+ astc_set_bits(pOutput, bit_pos, astc_extract_bits(T, 2, 3) | (bits[2] << 2) | (astc_extract_bits(T, 4, 4) << (2 + n)) | (bits[3] << (3 + n)) | (astc_extract_bits(T, 5, 6) << (3 + n * 2)) |
(bits[4] << (5 + n * 2)) | (astc_extract_bits(T, 7, 7) << (5 + n * 3)), n * 3 + 6);
}
+#endif // #if BASISD_SUPPORT_UASTC || BASISD_SUPPORT_ASTC
+#if BASISD_SUPPORT_ASTC
+ struct astc_block_params
+ {
+ // 2 groups of 5, but only a max of 8 are used (RRGGBBAA00)
+ uint8_t m_endpoints[10];
+ uint8_t m_weights[32];
+ };
+
// Packs a single format ASTC block using Color Endpoint Mode 12 (LDR RGBA direct), endpoint BISE range 13, 2-bit weights (range 2).
// We're always going to output blocks containing alpha, even if the input doesn't have alpha, for simplicity.
// Each block always has 4x4 weights, uses range 13 BISE encoding on the endpoints (0-47), and each weight ranges from 0-3. This encoding should be roughly equal in quality vs. BC1 for color.
@@ -6255,12 +6011,15 @@ namespace basist
static const etc1s_to_atc_solution g_etc1s_to_pvrtc2_45[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] = {
#include "basisu_transcoder_tables_pvrtc2_45.inc"
};
-
+
+#if 0
static const etc1s_to_atc_solution g_etc1s_to_pvrtc2_alpha_33[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] = {
#include "basisu_transcoder_tables_pvrtc2_alpha_33.inc"
};
#endif
+#endif
+
static const etc1s_to_atc_solution g_etc1s_to_atc_55[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] = {
#include "basisu_transcoder_tables_atc_55.inc"
};
@@ -7167,10 +6926,7 @@ namespace basist
}
typedef struct { float c[4]; } vec4F;
-
- static inline int32_t clampi(int32_t value, int32_t low, int32_t high) { if (value < low) value = low; else if (value > high) value = high; return value; }
- static inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; }
- static inline float saturate(float value) { return clampf(value, 0, 1.0f); }
+
static inline vec4F* vec4F_set_scalar(vec4F* pV, float x) { pV->c[0] = x; pV->c[1] = x; pV->c[2] = x; pV->c[3] = x; return pV; }
static inline vec4F* vec4F_set(vec4F* pV, float x, float y, float z, float w) { pV->c[0] = x; pV->c[1] = y; pV->c[2] = z; pV->c[3] = w; return pV; }
static inline vec4F* vec4F_saturate_in_place(vec4F* pV) { pV->c[0] = saturate(pV->c[0]); pV->c[1] = saturate(pV->c[1]); pV->c[2] = saturate(pV->c[2]); pV->c[3] = saturate(pV->c[3]); return pV; }
@@ -7188,7 +6944,7 @@ namespace basist
}
static inline int sq(int x) { return x * x; }
-
+
// PVRTC2 is a slightly borked format for alpha: In Non-Interpolated mode, the way AlphaB8 is exanded from 4 to 8 bits means it can never be 0.
// This is actually very bad, because on 100% transparent blocks which have non-trivial color pixels, part of the color channel will leak into alpha!
// And there's nothing straightforward we can do because using the other modes is too expensive/complex. I can see why Apple didn't adopt it.
@@ -7461,7 +7217,7 @@ namespace basist
}
vec4F_normalize_in_place(&axis);
-
+
if (vec4F_dot(&axis, &axis) < .5f)
vec4F_set_scalar(&axis, .5f);
@@ -7488,7 +7244,15 @@ namespace basist
minColor = vec4F_saturate(&c0);
maxColor = vec4F_saturate(&c1);
if (minColor.c[3] > maxColor.c[3])
- std::swap(minColor, maxColor);
+ {
+ // VS 2019 release Code Generator issue
+ //std::swap(minColor, maxColor);
+
+ float a = minColor.c[0], b = minColor.c[1], c = minColor.c[2], d = minColor.c[3];
+ minColor.c[0] = maxColor.c[0]; minColor.c[1] = maxColor.c[1]; minColor.c[2] = maxColor.c[2]; minColor.c[3] = maxColor.c[3];
+ minColor.c[0] = maxColor.c[0]; minColor.c[1] = maxColor.c[1]; minColor.c[2] = maxColor.c[2]; minColor.c[3] = maxColor.c[3];
+ maxColor.c[0] = a; maxColor.c[1] = b; maxColor.c[2] = c; maxColor.c[3] = d;
+ }
}
else
{
@@ -7648,7 +7412,7 @@ namespace basist
uint32_t m = (le * 5 + he * 3) / 8;
- int err = labs((int)v - (int)m);
+ int err = (int)labs((int)v - (int)m);
if (err < lowest_err)
{
lowest_err = err;
@@ -7671,7 +7435,7 @@ namespace basist
uint32_t le = (l << 1);
le = (le << 4) | le;
- int err = labs((int)v - (int)le);
+ int err = (int)labs((int)v - (int)le);
if (err < lowest_err)
{
lowest_err = err;
@@ -7693,7 +7457,7 @@ namespace basist
uint32_t he = (h << 1) | 1;
he = (he << 4) | he;
- int err = labs((int)v - (int)he);
+ int err = (int)labs((int)v - (int)he);
if (err < lowest_err)
{
lowest_err = err;
@@ -7722,7 +7486,7 @@ namespace basist
uint32_t m = (le * 5 + he * 3) / 8;
- int err = labs((int)v - (int)m);
+ int err = (int)labs((int)v - (int)m);
if (err < lowest_err)
{
lowest_err = err;
@@ -7752,7 +7516,7 @@ namespace basist
uint32_t m = (le * 5 + he * 3) / 8;
- int err = labs((int)v - (int)m);
+ int err = (int)labs((int)v - (int)m);
if (err < lowest_err)
{
lowest_err = err;
@@ -7768,59 +7532,65 @@ namespace basist
}
#endif // BASISD_SUPPORT_PVRTC2
- basisu_lowlevel_transcoder::basisu_lowlevel_transcoder(const etc1_global_selector_codebook* pGlobal_sel_codebook) :
+ basisu_lowlevel_etc1s_transcoder::basisu_lowlevel_etc1s_transcoder(const etc1_global_selector_codebook* pGlobal_sel_codebook) :
+ m_pGlobal_codebook(nullptr),
m_pGlobal_sel_codebook(pGlobal_sel_codebook),
m_selector_history_buf_size(0)
{
}
- bool basisu_lowlevel_transcoder::decode_palettes(
+ bool basisu_lowlevel_etc1s_transcoder::decode_palettes(
uint32_t num_endpoints, const uint8_t* pEndpoints_data, uint32_t endpoints_data_size,
uint32_t num_selectors, const uint8_t* pSelectors_data, uint32_t selectors_data_size)
{
+ if (m_pGlobal_codebook)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 11\n");
+ return false;
+ }
bitwise_decoder sym_codec;
huffman_decoding_table color5_delta_model0, color5_delta_model1, color5_delta_model2, inten_delta_model;
if (!sym_codec.init(pEndpoints_data, endpoints_data_size))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 0\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 0\n");
return false;
}
if (!sym_codec.read_huffman_table(color5_delta_model0))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 1\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 1\n");
return false;
}
if (!sym_codec.read_huffman_table(color5_delta_model1))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 1a\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 1a\n");
return false;
}
if (!sym_codec.read_huffman_table(color5_delta_model2))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 2a\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 2a\n");
return false;
}
if (!sym_codec.read_huffman_table(inten_delta_model))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 2b\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 2b\n");
return false;
}
if (!color5_delta_model0.is_valid() || !color5_delta_model1.is_valid() || !color5_delta_model2.is_valid() || !inten_delta_model.is_valid())
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 2b\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 2b\n");
return false;
}
const bool endpoints_are_grayscale = sym_codec.get_bits(1) != 0;
- m_endpoints.resize(num_endpoints);
+ m_local_endpoints.resize(num_endpoints);
color32 prev_color5(16, 16, 16, 0);
uint32_t prev_inten = 0;
@@ -7828,8 +7598,8 @@ namespace basist
for (uint32_t i = 0; i < num_endpoints; i++)
{
uint32_t inten_delta = sym_codec.decode_huffman(inten_delta_model);
- m_endpoints[i].m_inten5 = static_cast<uint8_t>((inten_delta + prev_inten) & 7);
- prev_inten = m_endpoints[i].m_inten5;
+ m_local_endpoints[i].m_inten5 = static_cast<uint8_t>((inten_delta + prev_inten) & 7);
+ prev_inten = m_local_endpoints[i].m_inten5;
for (uint32_t c = 0; c < (endpoints_are_grayscale ? 1U : 3U); c++)
{
@@ -7843,25 +7613,25 @@ namespace basist
int v = (prev_color5[c] + delta) & 31;
- m_endpoints[i].m_color5[c] = static_cast<uint8_t>(v);
+ m_local_endpoints[i].m_color5[c] = static_cast<uint8_t>(v);
prev_color5[c] = static_cast<uint8_t>(v);
}
if (endpoints_are_grayscale)
{
- m_endpoints[i].m_color5[1] = m_endpoints[i].m_color5[0];
- m_endpoints[i].m_color5[2] = m_endpoints[i].m_color5[0];
+ m_local_endpoints[i].m_color5[1] = m_local_endpoints[i].m_color5[0];
+ m_local_endpoints[i].m_color5[2] = m_local_endpoints[i].m_color5[0];
}
}
sym_codec.stop();
- m_selectors.resize(num_selectors);
+ m_local_selectors.resize(num_selectors);
if (!sym_codec.init(pSelectors_data, selectors_data_size))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 5\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 5\n");
return false;
}
@@ -7880,12 +7650,12 @@ namespace basist
{
if (!sym_codec.read_huffman_table(mod_model))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 6\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 6\n");
return false;
}
if (!mod_model.is_valid())
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 6a\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 6a\n");
return false;
}
}
@@ -7902,7 +7672,7 @@ namespace basist
if (pal_index >= m_pGlobal_sel_codebook->size())
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 7z\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 7z\n");
return false;
}
@@ -7911,9 +7681,9 @@ namespace basist
// TODO: Optimize this
for (uint32_t y = 0; y < 4; y++)
for (uint32_t x = 0; x < 4; x++)
- m_selectors[i].set_selector(x, y, e[x + y * 4]);
+ m_local_selectors[i].set_selector(x, y, e[x + y * 4]);
- m_selectors[i].init_flags();
+ m_local_selectors[i].init_flags();
}
}
else
@@ -7928,12 +7698,12 @@ namespace basist
basist::huffman_decoding_table uses_global_cb_bitflags_model;
if (!sym_codec.read_huffman_table(uses_global_cb_bitflags_model))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 7\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 7\n");
return false;
}
if (!uses_global_cb_bitflags_model.is_valid())
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 7a\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 7a\n");
return false;
}
@@ -7942,12 +7712,12 @@ namespace basist
{
if (!sym_codec.read_huffman_table(global_mod_indices_model))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 8\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 8\n");
return false;
}
if (!global_mod_indices_model.is_valid())
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 8a\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 8a\n");
return false;
}
}
@@ -7975,7 +7745,7 @@ namespace basist
if (pal_index >= m_pGlobal_sel_codebook->size())
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 8b\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 8b\n");
return false;
}
@@ -7983,7 +7753,7 @@ namespace basist
for (uint32_t y = 0; y < 4; y++)
for (uint32_t x = 0; x < 4; x++)
- m_selectors[q].set_selector(x, y, e[x + y * 4]);
+ m_local_selectors[q].set_selector(x, y, e[x + y * 4]);
}
else
{
@@ -7992,11 +7762,11 @@ namespace basist
uint32_t cur_byte = sym_codec.get_bits(8);
for (uint32_t k = 0; k < 4; k++)
- m_selectors[q].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
+ m_local_selectors[q].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
}
}
- m_selectors[q].init_flags();
+ m_local_selectors[q].init_flags();
}
}
else
@@ -8012,23 +7782,23 @@ namespace basist
uint32_t cur_byte = sym_codec.get_bits(8);
for (uint32_t k = 0; k < 4; k++)
- m_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
+ m_local_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
}
- m_selectors[i].init_flags();
+ m_local_selectors[i].init_flags();
}
}
else
{
if (!sym_codec.read_huffman_table(delta_selector_pal_model))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 10\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 10\n");
return false;
}
if ((num_selectors > 1) && (!delta_selector_pal_model.is_valid()))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_palettes: fail 10a\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 10a\n");
return false;
}
@@ -8044,9 +7814,9 @@ namespace basist
prev_bytes[j] = static_cast<uint8_t>(cur_byte);
for (uint32_t k = 0; k < 4; k++)
- m_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
+ m_local_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
}
- m_selectors[i].init_flags();
+ m_local_selectors[i].init_flags();
continue;
}
@@ -8058,9 +7828,9 @@ namespace basist
prev_bytes[j] = static_cast<uint8_t>(cur_byte);
for (uint32_t k = 0; k < 4; k++)
- m_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
+ m_local_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);
}
- m_selectors[i].init_flags();
+ m_local_selectors[i].init_flags();
}
}
}
@@ -8071,60 +7841,60 @@ namespace basist
return true;
}
- bool basisu_lowlevel_transcoder::decode_tables(const uint8_t* pTable_data, uint32_t table_data_size)
+ bool basisu_lowlevel_etc1s_transcoder::decode_tables(const uint8_t* pTable_data, uint32_t table_data_size)
{
basist::bitwise_decoder sym_codec;
if (!sym_codec.init(pTable_data, table_data_size))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_tables: fail 0\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 0\n");
return false;
}
if (!sym_codec.read_huffman_table(m_endpoint_pred_model))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_tables: fail 1\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 1\n");
return false;
}
if (m_endpoint_pred_model.get_code_sizes().size() == 0)
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_tables: fail 1a\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 1a\n");
return false;
}
if (!sym_codec.read_huffman_table(m_delta_endpoint_model))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_tables: fail 2\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 2\n");
return false;
}
if (m_delta_endpoint_model.get_code_sizes().size() == 0)
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_tables: fail 2a\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 2a\n");
return false;
}
if (!sym_codec.read_huffman_table(m_selector_model))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_tables: fail 3\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 3\n");
return false;
}
if (m_selector_model.get_code_sizes().size() == 0)
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_tables: fail 3a\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 3a\n");
return false;
}
if (!sym_codec.read_huffman_table(m_selector_history_buf_rle_model))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_tables: fail 4\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 4\n");
return false;
}
if (m_selector_history_buf_rle_model.get_code_sizes().size() == 0)
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::decode_tables: fail 4a\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 4a\n");
return false;
}
@@ -8135,27 +7905,37 @@ namespace basist
return true;
}
- bool basisu_lowlevel_transcoder::transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
- uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const basis_file_header& header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels,
+ bool basisu_lowlevel_etc1s_transcoder::transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
+ uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const bool is_video, const bool is_alpha_slice, const uint32_t level_index, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels,
basisu_transcoder_state* pState, bool transcode_alpha, void *pAlpha_blocks, uint32_t output_rows_in_pixels)
{
- (void)transcode_alpha;
- (void)pAlpha_blocks;
+ // 'pDst_blocks' unused when disabling *all* hardware transcode options
+ // (and 'bc1_allow_threecolor_blocks' when disabling DXT)
+ BASISU_NOTE_UNUSED(pDst_blocks);
+ BASISU_NOTE_UNUSED(bc1_allow_threecolor_blocks);
+ BASISU_NOTE_UNUSED(transcode_alpha);
+ BASISU_NOTE_UNUSED(pAlpha_blocks);
+
+ assert(g_transcoder_initialized);
+ if (!g_transcoder_initialized)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: Transcoder not globally initialized.\n");
+ return false;
+ }
if (!pState)
pState = &m_def_state;
- const bool is_video = (header.m_tex_type == cBASISTexTypeVideoFrames);
const uint32_t total_blocks = num_blocks_x * num_blocks_y;
if (!output_row_pitch_in_blocks_or_pixels)
{
if (basis_block_format_is_uncompressed(fmt))
- output_row_pitch_in_blocks_or_pixels = slice_desc.m_orig_width;
+ output_row_pitch_in_blocks_or_pixels = orig_width;
else
{
if (fmt == block_format::cFXT1_RGB)
- output_row_pitch_in_blocks_or_pixels = (slice_desc.m_orig_width + 7) / 8;
+ output_row_pitch_in_blocks_or_pixels = (orig_width + 7) / 8;
else
output_row_pitch_in_blocks_or_pixels = num_blocks_x;
}
@@ -8164,23 +7944,23 @@ namespace basist
if (basis_block_format_is_uncompressed(fmt))
{
if (!output_rows_in_pixels)
- output_rows_in_pixels = slice_desc.m_orig_height;
+ output_rows_in_pixels = orig_height;
}
- std::vector<uint32_t>* pPrev_frame_indices = nullptr;
+ basisu::vector<uint32_t>* pPrev_frame_indices = nullptr;
if (is_video)
{
// TODO: Add check to make sure the caller hasn't tried skipping past p-frames
- const bool alpha_flag = (slice_desc.m_flags & cSliceDescFlagsIsAlphaData) != 0;
- const uint32_t level_index = slice_desc.m_level_index;
+ //const bool alpha_flag = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0;
+ //const uint32_t level_index = slice_desc.m_level_index;
if (level_index >= basisu_transcoder_state::cMaxPrevFrameLevels)
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::transcode_slice: unsupported level_index\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: unsupported level_index\n");
return false;
}
- pPrev_frame_indices = &pState->m_prev_frame_indices[alpha_flag][level_index];
+ pPrev_frame_indices = &pState->m_prev_frame_indices[is_alpha_slice][level_index];
if (pPrev_frame_indices->size() < total_blocks)
pPrev_frame_indices->resize(total_blocks);
}
@@ -8189,14 +7969,12 @@ namespace basist
if (!sym_codec.init(pImage_data, image_data_size))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::transcode_slice: sym_codec.init failed\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: sym_codec.init failed\n");
return false;
}
approx_move_to_front selector_history_buf(m_selector_history_buf_size);
-
- const uint32_t SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX = (uint32_t)m_selectors.size();
- const uint32_t SELECTOR_HISTORY_BUF_RLE_SYMBOL_INDEX = m_selector_history_buf_size + SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX;
+
uint32_t cur_selector_rle_count = 0;
decoder_etc_block block;
@@ -8212,7 +7990,7 @@ namespace basist
pPVRTC_work_mem = malloc(num_blocks_x * num_blocks_y * (sizeof(decoder_etc_block) + sizeof(uint32_t)));
if (!pPVRTC_work_mem)
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::transcode_slice: malloc failed\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: malloc failed\n");
return false;
}
pPVRTC_endpoints = (uint32_t*) & ((decoder_etc_block*)pPVRTC_work_mem)[num_blocks_x * num_blocks_y];
@@ -8228,6 +8006,16 @@ namespace basist
int prev_endpoint_pred_sym = 0;
int endpoint_pred_repeat_count = 0;
uint32_t prev_endpoint_index = 0;
+ const endpoint_vec& endpoints = m_pGlobal_codebook ? m_pGlobal_codebook->m_local_endpoints : m_local_endpoints;
+ const selector_vec& selectors = m_pGlobal_codebook ? m_pGlobal_codebook->m_local_selectors : m_local_selectors;
+ if (!endpoints.size() || !selectors.size())
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: global codebooks must be unpacked first\n");
+ return false;
+ }
+
+ const uint32_t SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX = (uint32_t)selectors.size();
+ const uint32_t SELECTOR_HISTORY_BUF_RLE_SYMBOL_INDEX = m_selector_history_buf_size + SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX;
for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
{
@@ -8279,7 +8067,7 @@ namespace basist
// Left
if (!block_x)
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::transcode_slice: invalid datastream (0)\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (0)\n");
if (pPVRTC_work_mem)
free(pPVRTC_work_mem);
return false;
@@ -8292,7 +8080,7 @@ namespace basist
// Upper
if (!block_y)
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::transcode_slice: invalid datastream (1)\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (1)\n");
if (pPVRTC_work_mem)
free(pPVRTC_work_mem);
return false;
@@ -8314,7 +8102,7 @@ namespace basist
// Upper left
if ((!block_x) || (!block_y))
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::transcode_slice: invalid datastream (2)\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (2)\n");
if (pPVRTC_work_mem)
free(pPVRTC_work_mem);
return false;
@@ -8329,8 +8117,8 @@ namespace basist
const uint32_t delta_sym = sym_codec.decode_huffman(m_delta_endpoint_model);
endpoint_index = delta_sym + prev_endpoint_index;
- if (endpoint_index >= m_endpoints.size())
- endpoint_index -= (int)m_endpoints.size();
+ if (endpoint_index >= endpoints.size())
+ endpoint_index -= (int)endpoints.size();
}
pState->m_block_endpoint_preds[cur_block_endpoint_pred_array][block_x].m_endpoint_index = (uint16_t)endpoint_index;
@@ -8345,7 +8133,7 @@ namespace basist
{
cur_selector_rle_count--;
- selector_sym = (int)m_selectors.size();
+ selector_sym = (int)selectors.size();
}
else
{
@@ -8363,28 +8151,28 @@ namespace basist
if (cur_selector_rle_count > total_blocks)
{
// The file is corrupted or we've got a bug.
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::transcode_slice: invalid datastream (3)\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (3)\n");
if (pPVRTC_work_mem)
free(pPVRTC_work_mem);
return false;
}
- selector_sym = (int)m_selectors.size();
+ selector_sym = (int)selectors.size();
cur_selector_rle_count--;
}
}
- if (selector_sym >= (int)m_selectors.size())
+ if (selector_sym >= (int)selectors.size())
{
assert(m_selector_history_buf_size > 0);
- int history_buf_index = selector_sym - (int)m_selectors.size();
+ int history_buf_index = selector_sym - (int)selectors.size();
if (history_buf_index >= (int)selector_history_buf.size())
{
// The file is corrupted or we've got a bug.
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::transcode_slice: invalid datastream (4)\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (4)\n");
if (pPVRTC_work_mem)
free(pPVRTC_work_mem);
return false;
@@ -8404,10 +8192,10 @@ namespace basist
}
}
- if ((endpoint_index >= m_endpoints.size()) || (selector_index >= m_selectors.size()))
+ if ((endpoint_index >= endpoints.size()) || (selector_index >= selectors.size()))
{
// The file is corrupted or we've got a bug.
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::transcode_slice: invalid datastream (5)\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (5)\n");
if (pPVRTC_work_mem)
free(pPVRTC_work_mem);
return false;
@@ -8428,8 +8216,8 @@ namespace basist
}
#endif
- const endpoint* pEndpoints = &m_endpoints[endpoint_index];
- const selector* pSelector = &m_selectors[selector_index];
+ const endpoint* pEndpoints = &endpoints[endpoint_index];
+ const selector* pSelector = &selectors[selector_index];
switch (fmt)
{
@@ -8448,9 +8236,8 @@ namespace basist
}
case block_format::cBC1:
{
- void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;
-
#if BASISD_SUPPORT_DXT1
+ void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;
#if BASISD_ENABLE_DEBUG_FLAGS
if (g_debug_flags & (cDebugFlagVisBC1Sels | cDebugFlagVisBC1Endpoints))
convert_etc1s_to_dxt1_vis(static_cast<dxt1_block*>(pDst_block), pEndpoints, pSelector, bc1_allow_threecolor_blocks);
@@ -8534,8 +8321,8 @@ namespace basist
const uint16_t* pAlpha_block = reinterpret_cast<uint16_t*>(static_cast<uint8_t*>(pAlpha_blocks) + (block_x + block_y * num_blocks_x) * sizeof(uint32_t));
- const endpoint* pAlpha_endpoints = &m_endpoints[pAlpha_block[0]];
- const selector* pAlpha_selector = &m_selectors[pAlpha_block[1]];
+ const endpoint* pAlpha_endpoints = &endpoints[pAlpha_block[0]];
+ const selector* pAlpha_selector = &selectors[pAlpha_block[1]];
const color32& alpha_base_color = pAlpha_endpoints->m_color5;
const uint32_t alpha_inten_table = pAlpha_endpoints->m_inten5;
@@ -8559,16 +8346,7 @@ namespace basist
break;
}
- case block_format::cBC7_M6_OPAQUE_ONLY:
- {
-#if BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY
- void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;
- convert_etc1s_to_bc7_m6(static_cast<bc7_mode_6*>(pDst_block), pEndpoints, pSelector);
-#else
- assert(0);
-#endif
- break;
- }
+ case block_format::cBC7: // for more consistency with UASTC
case block_format::cBC7_M5_COLOR:
{
#if BASISD_SUPPORT_BC7_MODE5
@@ -8603,7 +8381,7 @@ namespace basist
{
#if BASISD_SUPPORT_ASTC
void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;
- convert_etc1s_to_astc_4x4(pDst_block, pEndpoints, pSelector, transcode_alpha, &m_endpoints[0], &m_selectors[0]);
+ convert_etc1s_to_astc_4x4(pDst_block, pEndpoints, pSelector, transcode_alpha, &endpoints[0], &selectors[0]);
#else
assert(0);
#endif
@@ -8648,8 +8426,8 @@ namespace basist
assert(transcode_alpha);
void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;
-
- convert_etc1s_to_pvrtc2_rgba(pDst_block, pEndpoints, pSelector, &m_endpoints[0], &m_selectors[0]);
+
+ convert_etc1s_to_pvrtc2_rgba(pDst_block, pEndpoints, pSelector, &endpoints[0], &selectors[0]);
#endif
break;
}
@@ -8665,8 +8443,8 @@ namespace basist
assert(sizeof(uint32_t) == output_block_or_pixel_stride_in_bytes);
uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint32_t);
- const uint32_t max_x = basisu::minimum<int>(4, output_row_pitch_in_blocks_or_pixels - block_x * 4);
- const uint32_t max_y = basisu::minimum<int>(4, output_rows_in_pixels - block_y * 4);
+ const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);
+ const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);
int colors[4];
decoder_etc_block::get_block_colors5_g(colors, pEndpoints->m_color5, pEndpoints->m_inten5);
@@ -8705,8 +8483,8 @@ namespace basist
assert(sizeof(uint32_t) == output_block_or_pixel_stride_in_bytes);
uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint32_t);
- const uint32_t max_x = basisu::minimum<int>(4, output_row_pitch_in_blocks_or_pixels - block_x * 4);
- const uint32_t max_y = basisu::minimum<int>(4, output_rows_in_pixels - block_y * 4);
+ const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);
+ const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);
color32 colors[4];
decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);
@@ -8734,8 +8512,8 @@ namespace basist
assert(sizeof(uint32_t) == output_block_or_pixel_stride_in_bytes);
uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint32_t);
- const uint32_t max_x = basisu::minimum<int>(4, output_row_pitch_in_blocks_or_pixels - block_x * 4);
- const uint32_t max_y = basisu::minimum<int>(4, output_rows_in_pixels - block_y * 4);
+ const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);
+ const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);
color32 colors[4];
decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);
@@ -8765,8 +8543,8 @@ namespace basist
assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);
uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);
- const uint32_t max_x = basisu::minimum<int>(4, output_row_pitch_in_blocks_or_pixels - block_x * 4);
- const uint32_t max_y = basisu::minimum<int>(4, output_rows_in_pixels - block_y * 4);
+ const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);
+ const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);
color32 colors[4];
decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);
@@ -8775,12 +8553,20 @@ namespace basist
if (fmt == block_format::cRGB565)
{
for (uint32_t i = 0; i < 4; i++)
- packed_colors[i] = static_cast<uint16_t>(((colors[i].r >> 3) << 11) | ((colors[i].g >> 2) << 5) | (colors[i].b >> 3));
+ {
+ packed_colors[i] = static_cast<uint16_t>((mul_8(colors[i].r, 31) << 11) | (mul_8(colors[i].g, 63) << 5) | mul_8(colors[i].b, 31));
+ if (BASISD_IS_BIG_ENDIAN)
+ packed_colors[i] = byteswap_uint16(packed_colors[i]);
+ }
}
else
{
for (uint32_t i = 0; i < 4; i++)
- packed_colors[i] = static_cast<uint16_t>(((colors[i].b >> 3) << 11) | ((colors[i].g >> 2) << 5) | (colors[i].r >> 3));
+ {
+ packed_colors[i] = static_cast<uint16_t>((mul_8(colors[i].b, 31) << 11) | (mul_8(colors[i].g, 63) << 5) | mul_8(colors[i].r, 31));
+ if (BASISD_IS_BIG_ENDIAN)
+ packed_colors[i] = byteswap_uint16(packed_colors[i]);
+ }
}
for (uint32_t y = 0; y < max_y; y++)
@@ -8800,15 +8586,17 @@ namespace basist
assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);
uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);
- const uint32_t max_x = basisu::minimum<int>(4, output_row_pitch_in_blocks_or_pixels - block_x * 4);
- const uint32_t max_y = basisu::minimum<int>(4, output_rows_in_pixels - block_y * 4);
+ const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);
+ const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);
color32 colors[4];
decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);
uint16_t packed_colors[4];
for (uint32_t i = 0; i < 4; i++)
- packed_colors[i] = static_cast<uint16_t>(((colors[i].r >> 4) << 12) | ((colors[i].g >> 4) << 8) | ((colors[i].b >> 4) << 4));
+ {
+ packed_colors[i] = static_cast<uint16_t>((mul_8(colors[i].r, 15) << 12) | (mul_8(colors[i].g, 15) << 8) | (mul_8(colors[i].b, 15) << 4));
+ }
for (uint32_t y = 0; y < max_y; y++)
{
@@ -8817,7 +8605,14 @@ namespace basist
for (uint32_t x = 0; x < max_x; x++)
{
uint16_t cur = reinterpret_cast<uint16_t*>(pDst_pixels)[x];
+ if (BASISD_IS_BIG_ENDIAN)
+ cur = byteswap_uint16(cur);
+
cur = (cur & 0xF) | packed_colors[(s >> (x * 2)) & 3];
+
+ if (BASISD_IS_BIG_ENDIAN)
+ cur = byteswap_uint16(cur);
+
reinterpret_cast<uint16_t*>(pDst_pixels)[x] = cur;
}
@@ -8831,15 +8626,19 @@ namespace basist
assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);
uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);
- const uint32_t max_x = basisu::minimum<int>(4, output_row_pitch_in_blocks_or_pixels - block_x * 4);
- const uint32_t max_y = basisu::minimum<int>(4, output_rows_in_pixels - block_y * 4);
+ const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);
+ const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);
color32 colors[4];
decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);
uint16_t packed_colors[4];
for (uint32_t i = 0; i < 4; i++)
- packed_colors[i] = static_cast<uint16_t>(((colors[i].r >> 4) << 12) | ((colors[i].g >> 4) << 8) | ((colors[i].b >> 4) << 4) | 0xF);
+ {
+ packed_colors[i] = static_cast<uint16_t>((mul_8(colors[i].r, 15) << 12) | (mul_8(colors[i].g, 15) << 8) | (mul_8(colors[i].b, 15) << 4) | 0xF);
+ if (BASISD_IS_BIG_ENDIAN)
+ packed_colors[i] = byteswap_uint16(packed_colors[i]);
+ }
for (uint32_t y = 0; y < max_y; y++)
{
@@ -8858,22 +8657,28 @@ namespace basist
assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);
uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);
- const uint32_t max_x = basisu::minimum<int>(4, output_row_pitch_in_blocks_or_pixels - block_x * 4);
- const uint32_t max_y = basisu::minimum<int>(4, output_rows_in_pixels - block_y * 4);
+ const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);
+ const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);
color32 colors[4];
decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);
uint16_t packed_colors[4];
for (uint32_t i = 0; i < 4; i++)
- packed_colors[i] = colors[i].g >> 4;
+ {
+ packed_colors[i] = mul_8(colors[i].g, 15);
+ if (BASISD_IS_BIG_ENDIAN)
+ packed_colors[i] = byteswap_uint16(packed_colors[i]);
+ }
for (uint32_t y = 0; y < max_y; y++)
{
const uint32_t s = pSelector->m_selectors[y];
for (uint32_t x = 0; x < max_x; x++)
+ {
reinterpret_cast<uint16_t*>(pDst_pixels)[x] = packed_colors[(s >> (x * 2)) & 3];
+ }
pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint16_t);
}
@@ -8903,7 +8708,7 @@ namespace basist
if (endpoint_pred_repeat_count != 0)
{
- BASISU_DEVEL_ERROR("basisu_lowlevel_transcoder::transcode_slice: endpoint_pred_repeat_count != 0. The file is corrupted or this is a bug\n");
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: endpoint_pred_repeat_count != 0. The file is corrupted or this is a bug\n");
return false;
}
@@ -8914,7 +8719,7 @@ namespace basist
if (fmt == block_format::cPVRTC1_4_RGB)
fixup_pvrtc1_4_modulation_rgb((decoder_etc_block*)pPVRTC_work_mem, pPVRTC_endpoints, pDst_blocks, num_blocks_x, num_blocks_y);
else if (fmt == block_format::cPVRTC1_4_RGBA)
- fixup_pvrtc1_4_modulation_rgba((decoder_etc_block*)pPVRTC_work_mem, pPVRTC_endpoints, pDst_blocks, num_blocks_x, num_blocks_y, pAlpha_blocks, &m_endpoints[0], &m_selectors[0]);
+ fixup_pvrtc1_4_modulation_rgba((decoder_etc_block*)pPVRTC_work_mem, pPVRTC_endpoints, pDst_blocks, num_blocks_x, num_blocks_y, pAlpha_blocks, &endpoints[0], &selectors[0]);
#endif // BASISD_SUPPORT_PVRTC1
if (pPVRTC_work_mem)
@@ -8923,8 +8728,1187 @@ namespace basist
return true;
}
+ bool basis_validate_output_buffer_size(transcoder_texture_format target_format,
+ uint32_t output_blocks_buf_size_in_blocks_or_pixels,
+ uint32_t orig_width, uint32_t orig_height,
+ uint32_t output_row_pitch_in_blocks_or_pixels,
+ uint32_t output_rows_in_pixels,
+ uint32_t total_slice_blocks)
+ {
+ if (basis_transcoder_format_is_uncompressed(target_format))
+ {
+ // Assume the output buffer is orig_width by orig_height
+ if (!output_row_pitch_in_blocks_or_pixels)
+ output_row_pitch_in_blocks_or_pixels = orig_width;
+
+ if (!output_rows_in_pixels)
+ output_rows_in_pixels = orig_height;
+
+ // Now make sure the output buffer is large enough, or we'll overwrite memory.
+ if (output_blocks_buf_size_in_blocks_or_pixels < (output_rows_in_pixels * output_row_pitch_in_blocks_or_pixels))
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: output_blocks_buf_size_in_blocks_or_pixels < (output_rows_in_pixels * output_row_pitch_in_blocks_or_pixels)\n");
+ return false;
+ }
+ }
+ else if (target_format == transcoder_texture_format::cTFFXT1_RGB)
+ {
+ const uint32_t num_blocks_fxt1_x = (orig_width + 7) / 8;
+ const uint32_t num_blocks_fxt1_y = (orig_height + 3) / 4;
+ const uint32_t total_blocks_fxt1 = num_blocks_fxt1_x * num_blocks_fxt1_y;
+
+ if (output_blocks_buf_size_in_blocks_or_pixels < total_blocks_fxt1)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: output_blocks_buf_size_in_blocks_or_pixels < total_blocks_fxt1\n");
+ return false;
+ }
+ }
+ else
+ {
+ if (output_blocks_buf_size_in_blocks_or_pixels < total_slice_blocks)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: output_blocks_buf_size_in_blocks_or_pixels < transcode_image\n");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool basisu_lowlevel_etc1s_transcoder::transcode_image(
+ transcoder_texture_format target_format,
+ void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
+ const uint8_t* pCompressed_data, uint32_t compressed_data_length,
+ uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,
+ uint32_t rgb_offset, uint32_t rgb_length, uint32_t alpha_offset, uint32_t alpha_length,
+ uint32_t decode_flags,
+ bool basis_file_has_alpha_slices,
+ bool is_video,
+ uint32_t output_row_pitch_in_blocks_or_pixels,
+ basisu_transcoder_state* pState,
+ uint32_t output_rows_in_pixels)
+ {
+ if (((uint64_t)rgb_offset + rgb_length) > (uint64_t)compressed_data_length)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: source data buffer too small (color)\n");
+ return false;
+ }
+
+ if (alpha_length)
+ {
+ if (((uint64_t)alpha_offset + alpha_length) > (uint64_t)compressed_data_length)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: source data buffer too small (alpha)\n");
+ return false;
+ }
+ }
+ else
+ {
+ assert(!basis_file_has_alpha_slices);
+ }
+
+ if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGB) || (target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA))
+ {
+ if ((!basisu::is_pow2(num_blocks_x * 4)) || (!basisu::is_pow2(num_blocks_y * 4)))
+ {
+ // PVRTC1 only supports power of 2 dimensions
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: PVRTC1 only supports power of 2 dimensions\n");
+ return false;
+ }
+ }
+
+ if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA) && (!basis_file_has_alpha_slices))
+ {
+ // Switch to PVRTC1 RGB if the input doesn't have alpha.
+ target_format = transcoder_texture_format::cTFPVRTC1_4_RGB;
+ }
+
+ const bool transcode_alpha_data_to_opaque_formats = (decode_flags & cDecodeFlagsTranscodeAlphaDataToOpaqueFormats) != 0;
+ const uint32_t bytes_per_block_or_pixel = basis_get_bytes_per_block_or_pixel(target_format);
+ const uint32_t total_slice_blocks = num_blocks_x * num_blocks_y;
+
+ if (!basis_validate_output_buffer_size(target_format, output_blocks_buf_size_in_blocks_or_pixels, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, output_rows_in_pixels, total_slice_blocks))
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: output buffer size too small\n");
+ return false;
+ }
+
+ bool status = false;
+
+ const uint8_t* pData = pCompressed_data + rgb_offset;
+ uint32_t data_len = rgb_length;
+ bool is_alpha_slice = false;
+
+ // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
+ if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
+ {
+ pData = pCompressed_data + alpha_offset;
+ data_len = alpha_length;
+ is_alpha_slice = true;
+ }
+
+ switch (target_format)
+ {
+ case transcoder_texture_format::cTFETC1_RGB:
+ {
+ //status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cETC1, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC1 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFBC1_RGB:
+ {
+#if !BASISD_SUPPORT_DXT1
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: BC1/DXT1 unsupported\n");
+ return false;
+#else
+ // status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cBC1, bytes_per_block_or_pixel, true, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC1 failed\n");
+ }
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFBC4_R:
+ {
+#if !BASISD_SUPPORT_DXT5A
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: BC4/DXT5A unsupported\n");
+ return false;
+#else
+ //status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cBC4, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC4 failed\n");
+ }
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFPVRTC1_4_RGB:
+ {
+#if !BASISD_SUPPORT_PVRTC1
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: PVRTC1 4 unsupported\n");
+ return false;
+#else
+ // output_row_pitch_in_blocks_or_pixels is actually ignored because we're transcoding to PVRTC1. (Print a dev warning if it's != 0?)
+ //status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cPVRTC1_4_RGB, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to PVRTC1 4 RGB failed\n");
+ }
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFPVRTC1_4_RGBA:
+ {
+#if !BASISD_SUPPORT_PVRTC1
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: PVRTC1 4 unsupported\n");
+ return false;
+#else
+ assert(basis_file_has_alpha_slices);
+ assert(alpha_length);
+
+ // Temp buffer to hold alpha block endpoint/selector indices
+ basisu::vector<uint32_t> temp_block_indices(total_slice_blocks);
+
+ // First transcode alpha data to temp buffer
+ //status = transcode_slice(pData, data_size, slice_index + 1, &temp_block_indices[0], total_slice_blocks, block_format::cIndices, sizeof(uint32_t), decode_flags, pSlice_descs[slice_index].m_num_blocks_x, pState);
+ status = transcode_slice(&temp_block_indices[0], num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cIndices, sizeof(uint32_t), false, is_video, true, level_index, orig_width, orig_height, num_blocks_x, pState, false, nullptr, 0);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to PVRTC1 4 RGBA failed (0)\n");
+ }
+ else
+ {
+ // output_row_pitch_in_blocks_or_pixels is actually ignored because we're transcoding to PVRTC1. (Print a dev warning if it's != 0?)
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGBA, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState, &temp_block_indices[0]);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cPVRTC1_4_RGBA, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, &temp_block_indices[0], 0);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to PVRTC1 4 RGBA failed (1)\n");
+ }
+ }
+
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFBC7_RGBA:
+ case transcoder_texture_format::cTFBC7_ALT:
+ {
+#if !BASISD_SUPPORT_BC7_MODE5
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: BC7 unsupported\n");
+ return false;
+#else
+ assert(bytes_per_block_or_pixel == 16);
+ // We used to support transcoding just alpha to BC7 - but is that useful at all?
+
+ // First transcode the color slice. The cBC7_M5_COLOR transcoder will output opaque mode 5 blocks.
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC7_M5_COLOR, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cBC7_M5_COLOR, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+
+ if ((status) && (basis_file_has_alpha_slices))
+ {
+ // Now transcode the alpha slice. The cBC7_M5_ALPHA transcoder will now change the opaque mode 5 blocks to blocks with alpha.
+ //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC7_M5_ALPHA, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cBC7_M5_ALPHA, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ }
+
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC7 failed (0)\n");
+ }
+
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFETC2_RGBA:
+ {
+#if !BASISD_SUPPORT_ETC2_EAC_A8
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: ETC2 EAC A8 unsupported\n");
+ return false;
+#else
+ assert(bytes_per_block_or_pixel == 16);
+
+ if (basis_file_has_alpha_slices)
+ {
+ // First decode the alpha data
+ //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_A8, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cETC2_EAC_A8, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ }
+ else
+ {
+ //write_opaque_alpha_blocks(pSlice_descs[slice_index].m_num_blocks_x, pSlice_descs[slice_index].m_num_blocks_y, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_A8, 16, output_row_pitch_in_blocks_or_pixels);
+ basisu_transcoder::write_opaque_alpha_blocks(num_blocks_x, num_blocks_y, pOutput_blocks, block_format::cETC2_EAC_A8, 16, output_row_pitch_in_blocks_or_pixels);
+ status = true;
+ }
+
+ if (status)
+ {
+ // Now decode the color data
+ //status = transcode_slice(pData, data_size, slice_index, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice((uint8_t *)pOutput_blocks + 8, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cETC1, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC2 RGB failed\n");
+ }
+ }
+ else
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC2 A failed\n");
+ }
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFBC3_RGBA:
+ {
+#if !BASISD_SUPPORT_DXT1
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: DXT1 unsupported\n");
+ return false;
+#elif !BASISD_SUPPORT_DXT5A
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: DXT5A unsupported\n");
+ return false;
+#else
+ assert(bytes_per_block_or_pixel == 16);
+
+ // First decode the alpha data
+ if (basis_file_has_alpha_slices)
+ {
+ //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cBC4, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ }
+ else
+ {
+ basisu_transcoder::write_opaque_alpha_blocks(num_blocks_x, num_blocks_y, pOutput_blocks, block_format::cBC4, 16, output_row_pitch_in_blocks_or_pixels);
+ status = true;
+ }
+
+ if (status)
+ {
+ // Now decode the color data. Forbid 3 color blocks, which aren't allowed in BC3.
+ //status = transcode_slice(pData, data_size, slice_index, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC1, 16, decode_flags | cDecodeFlagsBC1ForbidThreeColorBlocks, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice((uint8_t *)pOutput_blocks + 8, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cBC1, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC3 RGB failed\n");
+ }
+ }
+ else
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC3 A failed\n");
+ }
+
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFBC5_RG:
+ {
+#if !BASISD_SUPPORT_DXT5A
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: DXT5A unsupported\n");
+ return false;
+#else
+ assert(bytes_per_block_or_pixel == 16);
+
+ //bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
+ // uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const bool is_video, const bool is_alpha_slice, const uint32_t level_index, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
+ // basisu_transcoder_state* pState = nullptr, bool astc_transcode_alpha = false, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0);
+
+ // Decode the R data (actually the green channel of the color data slice in the basis file)
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cBC4, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (status)
+ {
+ if (basis_file_has_alpha_slices)
+ {
+ // Decode the G data (actually the green channel of the alpha data slice in the basis file)
+ //status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice((uint8_t *)pOutput_blocks + 8, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cBC4, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC5 1 failed\n");
+ }
+ }
+ else
+ {
+ basisu_transcoder::write_opaque_alpha_blocks(num_blocks_x, num_blocks_y, (uint8_t*)pOutput_blocks + 8, block_format::cBC4, 16, output_row_pitch_in_blocks_or_pixels);
+ status = true;
+ }
+ }
+ else
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC5 channel 0 failed\n");
+ }
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFASTC_4x4_RGBA:
+ {
+#if !BASISD_SUPPORT_ASTC
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: ASTC unsupported\n");
+ return false;
+#else
+ assert(bytes_per_block_or_pixel == 16);
+
+ if (basis_file_has_alpha_slices)
+ {
+ // First decode the alpha data to the output (we're using the output texture as a temp buffer here).
+ //status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cIndices, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cIndices, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (status)
+ {
+ // Now decode the color data and transcode to ASTC. The transcoder function will read the alpha selector data from the output texture as it converts and
+ // transcode both the alpha and color data at the same time to ASTC.
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cASTC_4x4, 16, decode_flags | cDecodeFlagsOutputHasAlphaIndices, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cASTC_4x4, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, true, nullptr, output_rows_in_pixels);
+ }
+ }
+ else
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cASTC_4x4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cASTC_4x4, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ASTC failed (0)\n");
+ }
+
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFATC_RGB:
+ {
+#if !BASISD_SUPPORT_ATC
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: ATC unsupported\n");
+ return false;
+#else
+ //status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cATC_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cATC_RGB, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ATC_RGB failed\n");
+ }
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFATC_RGBA:
+ {
+#if !BASISD_SUPPORT_ATC
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: ATC unsupported\n");
+ return false;
+#elif !BASISD_SUPPORT_DXT5A
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: DXT5A unsupported\n");
+ return false;
+#else
+ assert(bytes_per_block_or_pixel == 16);
+
+ // First decode the alpha data
+ if (basis_file_has_alpha_slices)
+ {
+ //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cBC4, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ }
+ else
+ {
+ basisu_transcoder::write_opaque_alpha_blocks(num_blocks_x, num_blocks_y, pOutput_blocks, block_format::cBC4, 16, output_row_pitch_in_blocks_or_pixels);
+ status = true;
+ }
+
+ if (status)
+ {
+ //status = transcode_slice(pData, data_size, slice_index, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cATC_RGB, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice((uint8_t *)pOutput_blocks + 8, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cATC_RGB, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ATC RGB failed\n");
+ }
+ }
+ else
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ATC A failed\n");
+ }
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFPVRTC2_4_RGB:
+ {
+#if !BASISD_SUPPORT_PVRTC2
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: PVRTC2 unsupported\n");
+ return false;
+#else
+ //status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cPVRTC2_4_RGB, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to cPVRTC2_4_RGB failed\n");
+ }
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFPVRTC2_4_RGBA:
+ {
+#if !BASISD_SUPPORT_PVRTC2
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: PVRTC2 unsupported\n");
+ return false;
+#else
+ if (basis_file_has_alpha_slices)
+ {
+ // First decode the alpha data to the output (we're using the output texture as a temp buffer here).
+ //status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cIndices, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cIndices, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to failed\n");
+ }
+ else
+ {
+ // Now decode the color data and transcode to PVRTC2 RGBA.
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGBA, bytes_per_block_or_pixel, decode_flags | cDecodeFlagsOutputHasAlphaIndices, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cPVRTC2_4_RGBA, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, true, nullptr, output_rows_in_pixels);
+ }
+ }
+ else
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cPVRTC2_4_RGB, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to cPVRTC2_4_RGBA failed\n");
+ }
+
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFRGBA32:
+ {
+ // Raw 32bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory.
+
+ // First decode the alpha data
+ if (basis_file_has_alpha_slices)
+ //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cA32, sizeof(uint32_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cA32, sizeof(uint32_t), false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ else
+ status = true;
+
+ if (status)
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, basis_file_has_alpha_slices ? block_format::cRGB32 : block_format::cRGBA32, sizeof(uint32_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, basis_file_has_alpha_slices ? block_format::cRGB32 : block_format::cRGBA32, sizeof(uint32_t), false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to RGBA32 RGB failed\n");
+ }
+ }
+ else
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to RGBA32 A failed\n");
+ }
+
+ break;
+ }
+ case transcoder_texture_format::cTFRGB565:
+ case transcoder_texture_format::cTFBGR565:
+ {
+ // Raw 16bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory.
+
+ //status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, (fmt == transcoder_texture_format::cTFRGB565) ? block_format::cRGB565 : block_format::cBGR565, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, (target_format == transcoder_texture_format::cTFRGB565) ? block_format::cRGB565 : block_format::cBGR565, sizeof(uint16_t), false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to RGB565 RGB failed\n");
+ }
+
+ break;
+ }
+ case transcoder_texture_format::cTFRGBA4444:
+ {
+ // Raw 16bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory.
+
+ // First decode the alpha data
+ if (basis_file_has_alpha_slices)
+ //status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA4444_ALPHA, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cRGBA4444_ALPHA, sizeof(uint16_t), false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ else
+ status = true;
+
+ if (status)
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, basis_file_has_alpha_slices ? block_format::cRGBA4444_COLOR : block_format::cRGBA4444_COLOR_OPAQUE, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, basis_file_has_alpha_slices ? block_format::cRGBA4444_COLOR : block_format::cRGBA4444_COLOR_OPAQUE, sizeof(uint16_t), false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to RGBA4444 RGB failed\n");
+ }
+ }
+ else
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to RGBA4444 A failed\n");
+ }
+
+ break;
+ }
+ case transcoder_texture_format::cTFFXT1_RGB:
+ {
+#if !BASISD_SUPPORT_FXT1
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: FXT1 unsupported\n");
+ return false;
+#else
+ //status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cFXT1_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cFXT1_RGB, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to FXT1_RGB failed\n");
+ }
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFETC2_EAC_R11:
+ {
+#if !BASISD_SUPPORT_ETC2_EAC_RG11
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: EAC_RG11 unsupported\n");
+ return false;
+#else
+ //status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC2_EAC_R11 failed\n");
+ }
+
+ break;
+#endif
+ }
+ case transcoder_texture_format::cTFETC2_EAC_RG11:
+ {
+#if !BASISD_SUPPORT_ETC2_EAC_RG11
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: EAC_RG11 unsupported\n");
+ return false;
+#else
+ assert(bytes_per_block_or_pixel == 16);
+
+ if (basis_file_has_alpha_slices)
+ {
+ // First decode the alpha data to G
+ //status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice((uint8_t *)pOutput_blocks + 8, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ }
+ else
+ {
+ basisu_transcoder::write_opaque_alpha_blocks(num_blocks_x, num_blocks_y, (uint8_t*)pOutput_blocks + 8, block_format::cETC2_EAC_R11, 16, output_row_pitch_in_blocks_or_pixels);
+ status = true;
+ }
+
+ if (status)
+ {
+ // Now decode the color data to R
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC2_EAC_R11 R failed\n");
+ }
+ }
+ else
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC2_EAC_R11 G failed\n");
+ }
+
+ break;
+#endif
+ }
+ default:
+ {
+ assert(0);
+ BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: Invalid fmt\n");
+ break;
+ }
+ }
+
+ return status;
+ }
+
+ basisu_lowlevel_uastc_transcoder::basisu_lowlevel_uastc_transcoder()
+ {
+ }
+
+ bool basisu_lowlevel_uastc_transcoder::transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
+ uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels,
+ basisu_transcoder_state* pState, uint32_t output_rows_in_pixels, int channel0, int channel1, uint32_t decode_flags)
+ {
+ BASISU_NOTE_UNUSED(pState);
+ BASISU_NOTE_UNUSED(bc1_allow_threecolor_blocks);
+
+ assert(g_transcoder_initialized);
+ if (!g_transcoder_initialized)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_slice: Transcoder not globally initialized.\n");
+ return false;
+ }
+
+#if BASISD_SUPPORT_UASTC
+ const uint32_t total_blocks = num_blocks_x * num_blocks_y;
+
+ if (!output_row_pitch_in_blocks_or_pixels)
+ {
+ if (basis_block_format_is_uncompressed(fmt))
+ output_row_pitch_in_blocks_or_pixels = orig_width;
+ else
+ {
+ if (fmt == block_format::cFXT1_RGB)
+ output_row_pitch_in_blocks_or_pixels = (orig_width + 7) / 8;
+ else
+ output_row_pitch_in_blocks_or_pixels = num_blocks_x;
+ }
+ }
+
+ if (basis_block_format_is_uncompressed(fmt))
+ {
+ if (!output_rows_in_pixels)
+ output_rows_in_pixels = orig_height;
+ }
+
+ uint32_t total_expected_block_bytes = sizeof(uastc_block) * total_blocks;
+ if (image_data_size < total_expected_block_bytes)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_slice: image_data_size < total_expected_block_bytes The file is corrupted or this is a bug.\n");
+ return false;
+ }
+
+ const uastc_block* pSource_block = reinterpret_cast<const uastc_block *>(pImage_data);
+
+ const bool high_quality = (decode_flags & cDecodeFlagsHighQuality) != 0;
+ const bool from_alpha = has_alpha && (decode_flags & cDecodeFlagsTranscodeAlphaDataToOpaqueFormats) != 0;
+
+ bool status = false;
+ if ((fmt == block_format::cPVRTC1_4_RGB) || (fmt == block_format::cPVRTC1_4_RGBA))
+ {
+ if (fmt == block_format::cPVRTC1_4_RGBA)
+ transcode_uastc_to_pvrtc1_4_rgba((const uastc_block*)pImage_data, pDst_blocks, num_blocks_x, num_blocks_y, high_quality);
+ else
+ transcode_uastc_to_pvrtc1_4_rgb((const uastc_block *)pImage_data, pDst_blocks, num_blocks_x, num_blocks_y, high_quality, from_alpha);
+ }
+ else
+ {
+ for (uint32_t block_y = 0; block_y < num_blocks_y; ++block_y)
+ {
+ void* pDst_block = (uint8_t*)pDst_blocks + block_y * output_row_pitch_in_blocks_or_pixels * output_block_or_pixel_stride_in_bytes;
+
+ for (uint32_t block_x = 0; block_x < num_blocks_x; ++block_x, ++pSource_block, pDst_block = (uint8_t *)pDst_block + output_block_or_pixel_stride_in_bytes)
+ {
+ switch (fmt)
+ {
+ case block_format::cETC1:
+ {
+ if (from_alpha)
+ status = transcode_uastc_to_etc1(*pSource_block, pDst_block, 3);
+ else
+ status = transcode_uastc_to_etc1(*pSource_block, pDst_block);
+ break;
+ }
+ case block_format::cETC2_RGBA:
+ {
+ status = transcode_uastc_to_etc2_rgba(*pSource_block, pDst_block);
+ break;
+ }
+ case block_format::cBC1:
+ {
+ status = transcode_uastc_to_bc1(*pSource_block, pDst_block, high_quality);
+ break;
+ }
+ case block_format::cBC3:
+ {
+ status = transcode_uastc_to_bc3(*pSource_block, pDst_block, high_quality);
+ break;
+ }
+ case block_format::cBC4:
+ {
+ if (channel0 < 0)
+ channel0 = 0;
+ status = transcode_uastc_to_bc4(*pSource_block, pDst_block, high_quality, channel0);
+ break;
+ }
+ case block_format::cBC5:
+ {
+ if (channel0 < 0)
+ channel0 = 0;
+ if (channel1 < 0)
+ channel1 = 3;
+ status = transcode_uastc_to_bc5(*pSource_block, pDst_block, high_quality, channel0, channel1);
+ break;
+ }
+ case block_format::cBC7:
+ case block_format::cBC7_M5_COLOR: // for consistently with ETC1S
+ {
+ status = transcode_uastc_to_bc7(*pSource_block, pDst_block);
+ break;
+ }
+ case block_format::cASTC_4x4:
+ {
+ status = transcode_uastc_to_astc(*pSource_block, pDst_block);
+ break;
+ }
+ case block_format::cETC2_EAC_R11:
+ {
+ if (channel0 < 0)
+ channel0 = 0;
+ status = transcode_uastc_to_etc2_eac_r11(*pSource_block, pDst_block, high_quality, channel0);
+ break;
+ }
+ case block_format::cETC2_EAC_RG11:
+ {
+ if (channel0 < 0)
+ channel0 = 0;
+ if (channel1 < 0)
+ channel1 = 3;
+ status = transcode_uastc_to_etc2_eac_rg11(*pSource_block, pDst_block, high_quality, channel0, channel1);
+ break;
+ }
+ case block_format::cRGBA32:
+ {
+ color32 block_pixels[4][4];
+ status = unpack_uastc(*pSource_block, (color32 *)block_pixels, false);
+
+ assert(sizeof(uint32_t) == output_block_or_pixel_stride_in_bytes);
+ uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint32_t);
+
+ const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);
+ const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);
+
+ for (uint32_t y = 0; y < max_y; y++)
+ {
+ for (uint32_t x = 0; x < max_x; x++)
+ {
+ const color32& c = block_pixels[y][x];
+
+ pDst_pixels[0 + 4 * x] = c.r;
+ pDst_pixels[1 + 4 * x] = c.g;
+ pDst_pixels[2 + 4 * x] = c.b;
+ pDst_pixels[3 + 4 * x] = c.a;
+ }
+
+ pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint32_t);
+ }
+
+ break;
+ }
+ case block_format::cRGB565:
+ case block_format::cBGR565:
+ {
+ color32 block_pixels[4][4];
+ status = unpack_uastc(*pSource_block, (color32*)block_pixels, false);
+
+ assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);
+ uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);
+
+ const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);
+ const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);
+
+ for (uint32_t y = 0; y < max_y; y++)
+ {
+ for (uint32_t x = 0; x < max_x; x++)
+ {
+ const color32& c = block_pixels[y][x];
+
+ const uint16_t packed = (fmt == block_format::cRGB565) ? static_cast<uint16_t>((mul_8(c.r, 31) << 11) | (mul_8(c.g, 63) << 5) | mul_8(c.b, 31)) :
+ static_cast<uint16_t>((mul_8(c.b, 31) << 11) | (mul_8(c.g, 63) << 5) | mul_8(c.r, 31));
+
+ pDst_pixels[x * 2 + 0] = (uint8_t)(packed & 0xFF);
+ pDst_pixels[x * 2 + 1] = (uint8_t)((packed >> 8) & 0xFF);
+ }
+
+ pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint16_t);
+ }
+
+ break;
+ }
+ case block_format::cRGBA4444:
+ {
+ color32 block_pixels[4][4];
+ status = unpack_uastc(*pSource_block, (color32*)block_pixels, false);
+
+ assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);
+ uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);
+
+ const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);
+ const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);
+
+ for (uint32_t y = 0; y < max_y; y++)
+ {
+ for (uint32_t x = 0; x < max_x; x++)
+ {
+ const color32& c = block_pixels[y][x];
+
+ const uint16_t packed = static_cast<uint16_t>((mul_8(c.r, 15) << 12) | (mul_8(c.g, 15) << 8) | (mul_8(c.b, 15) << 4) | mul_8(c.a, 15));
+
+ pDst_pixels[x * 2 + 0] = (uint8_t)(packed & 0xFF);
+ pDst_pixels[x * 2 + 1] = (uint8_t)((packed >> 8) & 0xFF);
+ }
+
+ pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint16_t);
+ }
+ break;
+ }
+ default:
+ assert(0);
+ break;
+
+ }
+
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_slice: Transcoder failed to unpack a UASTC block - this is a bug, or the data was corrupted\n");
+ return false;
+ }
+
+ } // block_x
+
+ } // block_y
+ }
+
+ return true;
+#else
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_slice: UASTC is unsupported\n");
+
+ BASISU_NOTE_UNUSED(decode_flags);
+ BASISU_NOTE_UNUSED(channel0);
+ BASISU_NOTE_UNUSED(channel1);
+ BASISU_NOTE_UNUSED(output_rows_in_pixels);
+ BASISU_NOTE_UNUSED(output_row_pitch_in_blocks_or_pixels);
+ BASISU_NOTE_UNUSED(output_block_or_pixel_stride_in_bytes);
+ BASISU_NOTE_UNUSED(fmt);
+ BASISU_NOTE_UNUSED(image_data_size);
+ BASISU_NOTE_UNUSED(pImage_data);
+ BASISU_NOTE_UNUSED(num_blocks_x);
+ BASISU_NOTE_UNUSED(num_blocks_y);
+ BASISU_NOTE_UNUSED(pDst_blocks);
+
+ return false;
+#endif
+ }
+
+ bool basisu_lowlevel_uastc_transcoder::transcode_image(
+ transcoder_texture_format target_format,
+ void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
+ const uint8_t* pCompressed_data, uint32_t compressed_data_length,
+ uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,
+ uint32_t slice_offset, uint32_t slice_length,
+ uint32_t decode_flags,
+ bool has_alpha,
+ bool is_video,
+ uint32_t output_row_pitch_in_blocks_or_pixels,
+ basisu_transcoder_state* pState,
+ uint32_t output_rows_in_pixels,
+ int channel0, int channel1)
+ {
+ BASISU_NOTE_UNUSED(is_video);
+ BASISU_NOTE_UNUSED(level_index);
+
+ if (((uint64_t)slice_offset + slice_length) > (uint64_t)compressed_data_length)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: source data buffer too small\n");
+ return false;
+ }
+
+ if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGB) || (target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA))
+ {
+ if ((!basisu::is_pow2(num_blocks_x * 4)) || (!basisu::is_pow2(num_blocks_y * 4)))
+ {
+ // PVRTC1 only supports power of 2 dimensions
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: PVRTC1 only supports power of 2 dimensions\n");
+ return false;
+ }
+ }
+
+ if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA) && (!has_alpha))
+ {
+ // Switch to PVRTC1 RGB if the input doesn't have alpha.
+ target_format = transcoder_texture_format::cTFPVRTC1_4_RGB;
+ }
+
+ const bool transcode_alpha_data_to_opaque_formats = (decode_flags & cDecodeFlagsTranscodeAlphaDataToOpaqueFormats) != 0;
+ const uint32_t bytes_per_block_or_pixel = basis_get_bytes_per_block_or_pixel(target_format);
+ const uint32_t total_slice_blocks = num_blocks_x * num_blocks_y;
+
+ if (!basis_validate_output_buffer_size(target_format, output_blocks_buf_size_in_blocks_or_pixels, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, output_rows_in_pixels, total_slice_blocks))
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: output buffer size too small\n");
+ return false;
+ }
+
+ bool status = false;
+
+ // UASTC4x4
+ switch (target_format)
+ {
+ case transcoder_texture_format::cTFETC1_RGB:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC1,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1);
+
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to ETC1 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFETC2_RGBA:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_RGBA, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC2_RGBA,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to ETC2 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFBC1_RGB:
+ {
+ // TODO: ETC1S allows BC1 from alpha channel. That doesn't seem actually useful, though.
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC1,
+ bytes_per_block_or_pixel, true, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC1 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFBC3_RGBA:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC3, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC3,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC3 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFBC4_R:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState,
+ // nullptr, 0,
+ // ((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC4,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels,
+ ((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC4 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFBC5_RG:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC5, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState,
+ // nullptr, 0,
+ // 0, 3);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC5,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels,
+ 0, 3);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC5 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFBC7_RGBA:
+ case transcoder_texture_format::cTFBC7_ALT:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC7, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC7,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC7 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFPVRTC1_4_RGB:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cPVRTC1_4_RGB,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to PVRTC1 RGB 4bpp failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFPVRTC1_4_RGBA:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGBA, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cPVRTC1_4_RGBA,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to PVRTC1 RGBA 4bpp failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFASTC_4x4_RGBA:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cASTC_4x4, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cASTC_4x4,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to ASTC 4x4 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFATC_RGB:
+ case transcoder_texture_format::cTFATC_RGBA:
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: UASTC->ATC currently unsupported\n");
+ return false;
+ }
+ case transcoder_texture_format::cTFFXT1_RGB:
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: UASTC->FXT1 currently unsupported\n");
+ return false;
+ }
+ case transcoder_texture_format::cTFPVRTC2_4_RGB:
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: UASTC->PVRTC2 currently unsupported\n");
+ return false;
+ }
+ case transcoder_texture_format::cTFPVRTC2_4_RGBA:
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: UASTC->PVRTC2 currently unsupported\n");
+ return false;
+ }
+ case transcoder_texture_format::cTFETC2_EAC_R11:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState,
+ // nullptr, 0,
+ // ((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC2_EAC_R11,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels,
+ ((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to EAC R11 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFETC2_EAC_RG11:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_RG11, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState,
+ // nullptr, 0,
+ // 0, 3);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC2_EAC_RG11,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels,
+ 0, 3);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_basisu_lowlevel_uastc_transcodertranscoder::transcode_image: transcode_slice() to EAC RG11 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFRGBA32:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA32, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cRGBA32,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGBA32 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFRGB565:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGB565, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cRGB565,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGB565 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFBGR565:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBGR565, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBGR565,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGB565 failed\n");
+ }
+ break;
+ }
+ case transcoder_texture_format::cTFRGBA4444:
+ {
+ //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA4444, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cRGBA4444,
+ bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGBA4444 failed\n");
+ }
+ break;
+ }
+ default:
+ {
+ assert(0);
+ BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: Invalid format\n");
+ break;
+ }
+ }
+
+ return status;
+ }
+
basisu_transcoder::basisu_transcoder(const etc1_global_selector_codebook* pGlobal_sel_codebook) :
- m_lowlevel_decoder(pGlobal_sel_codebook)
+ m_lowlevel_etc1s_decoder(pGlobal_sel_codebook),
+ m_ready_to_transcode(false)
{
}
@@ -9027,22 +10011,33 @@ namespace basist
return false;
}
- if (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices)
+ if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)
{
- if (pHeader->m_total_slices & 1)
+ if (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: invalid alpha basis file\n");
+ if (pHeader->m_total_slices & 1)
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: invalid alpha .basis file\n");
+ return false;
+ }
+ }
+
+ // This flag dates back to pre-Basis Universal, when .basis supported full ETC1 too.
+ if ((pHeader->m_flags & cBASISHeaderFlagETC1S) == 0)
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: Invalid .basis file (ETC1S check)\n");
return false;
}
}
-
- if ((pHeader->m_flags & cBASISHeaderFlagETC1S) == 0)
+ else
{
- // We only support ETC1S in basis universal
- BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: invalid basis file (ETC1S flag check)\n");
- return false;
+ if ((pHeader->m_flags & cBASISHeaderFlagETC1S) != 0)
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: Invalid .basis file (ETC1S check)\n");
+ return false;
+ }
}
-
+
if ((pHeader->m_slice_desc_file_ofs >= data_size) ||
((data_size - pHeader->m_slice_desc_file_ofs) < (sizeof(basis_slice_desc) * pHeader->m_total_slices))
)
@@ -9103,6 +10098,19 @@ namespace basist
return pHeader->m_total_images;
}
+ basis_tex_format basisu_transcoder::get_tex_format(const void* pData, uint32_t data_size) const
+ {
+ if (!validate_header_quick(pData, data_size))
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: header validation failed\n");
+ return basis_tex_format::cETC1S;
+ }
+
+ const basis_file_header* pHeader = static_cast<const basis_file_header*>(pData);
+
+ return (basis_tex_format)(uint32_t)pHeader->m_tex_format;
+ }
+
bool basisu_transcoder::get_image_info(const void* pData, uint32_t data_size, basisu_image_info& image_info, uint32_t image_index) const
{
if (!validate_header_quick(pData, data_size))
@@ -9145,8 +10153,17 @@ namespace basist
image_info.m_image_index = image_index;
image_info.m_total_levels = total_levels;
- image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;
+
+ image_info.m_alpha_flag = false;
+
+ // For ETC1S, if anything has alpha all images have alpha. For UASTC, we only report alpha when the image actually has alpha.
+ if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)
+ image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;
+ else
+ image_info.m_alpha_flag = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0;
+
image_info.m_iframe_flag = (slice_desc.m_flags & cSliceDescFlagsFrameIsIFrame) != 0;
+
image_info.m_width = slice_desc.m_num_blocks_x * 4;
image_info.m_height = slice_desc.m_num_blocks_y * 4;
image_info.m_orig_width = slice_desc.m_orig_width;
@@ -9264,7 +10281,13 @@ namespace basist
image_info.m_image_index = image_index;
image_info.m_level_index = level_index;
- image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;
+
+ // For ETC1S, if anything has alpha all images have alpha. For UASTC, we only report alpha when the image actually has alpha.
+ if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)
+ image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;
+ else
+ image_info.m_alpha_flag = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0;
+
image_info.m_iframe_flag = (slice_desc.m_flags & cSliceDescFlagsFrameIsIFrame) != 0;
image_info.m_width = slice_desc.m_num_blocks_x * 4;
image_info.m_height = slice_desc.m_num_blocks_y * 4;
@@ -9275,6 +10298,21 @@ namespace basist
image_info.m_total_blocks = image_info.m_num_blocks_x * image_info.m_num_blocks_y;
image_info.m_first_slice_index = slice_index;
+ image_info.m_rgb_file_ofs = slice_desc.m_file_ofs;
+ image_info.m_rgb_file_len = slice_desc.m_file_size;
+ image_info.m_alpha_file_ofs = 0;
+ image_info.m_alpha_file_len = 0;
+
+ if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)
+ {
+ if (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices)
+ {
+ assert((slice_index + 1) < (int)pHeader->m_total_slices);
+ image_info.m_alpha_file_ofs = pSlice_descs[slice_index + 1].m_file_ofs;
+ image_info.m_alpha_file_len = pSlice_descs[slice_index + 1].m_file_size;
+ }
+ }
+
return true;
}
@@ -9294,14 +10332,20 @@ namespace basist
file_info.m_total_header_size = sizeof(basis_file_header) + pHeader->m_total_slices * sizeof(basis_slice_desc);
file_info.m_total_selectors = pHeader->m_total_selectors;
+ file_info.m_selector_codebook_ofs = pHeader->m_selector_cb_file_ofs;
file_info.m_selector_codebook_size = pHeader->m_selector_cb_file_size;
file_info.m_total_endpoints = pHeader->m_total_endpoints;
+ file_info.m_endpoint_codebook_ofs = pHeader->m_endpoint_cb_file_ofs;
file_info.m_endpoint_codebook_size = pHeader->m_endpoint_cb_file_size;
+ file_info.m_tables_ofs = pHeader->m_tables_file_ofs;
file_info.m_tables_size = pHeader->m_tables_file_size;
- file_info.m_etc1s = (pHeader->m_flags & cBASISHeaderFlagETC1S) != 0;
+ file_info.m_tex_format = static_cast<basis_tex_format>(static_cast<int>(pHeader->m_tex_format));
+
+ file_info.m_etc1s = (pHeader->m_tex_format == (int)basis_tex_format::cETC1S);
+
file_info.m_y_flipped = (pHeader->m_flags & cBASISHeaderFlagYFlipped) != 0;
file_info.m_has_alpha_slices = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;
@@ -9346,7 +10390,7 @@ namespace basist
slice_info.m_image_index = pSlice_descs[i].m_image_index;
slice_info.m_level_index = pSlice_descs[i].m_level_index;
slice_info.m_unpacked_slice_crc16 = pSlice_descs[i].m_slice_data_crc16;
- slice_info.m_alpha_flag = (pSlice_descs[i].m_flags & cSliceDescFlagsIsAlphaData) != 0;
+ slice_info.m_alpha_flag = (pSlice_descs[i].m_flags & cSliceDescFlagsHasAlpha) != 0;
slice_info.m_iframe_flag = (pSlice_descs[i].m_flags & cSliceDescFlagsFrameIsIFrame) != 0;
if (pSlice_descs[i].m_image_index >= pHeader->m_total_images)
@@ -9366,15 +10410,9 @@ namespace basist
return true;
}
-
- bool basisu_transcoder::start_transcoding(const void* pData, uint32_t data_size) const
+
+ bool basisu_transcoder::start_transcoding(const void* pData, uint32_t data_size)
{
- if (m_lowlevel_decoder.m_endpoints.size())
- {
- BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: already called start_transcoding\n");
- return true;
- }
-
if (!validate_header_quick(pData, data_size))
{
BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: header validation failed\n");
@@ -9382,59 +10420,123 @@ namespace basist
}
const basis_file_header* pHeader = reinterpret_cast<const basis_file_header*>(pData);
-
const uint8_t* pDataU8 = static_cast<const uint8_t*>(pData);
- if (!pHeader->m_endpoint_cb_file_size || !pHeader->m_selector_cb_file_size || !pHeader->m_tables_file_size)
+ if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted (0)\n");
- }
+ if (m_lowlevel_etc1s_decoder.m_local_endpoints.size())
+ {
+ m_lowlevel_etc1s_decoder.clear();
+ }
- if ((pHeader->m_endpoint_cb_file_ofs > data_size) || (pHeader->m_selector_cb_file_ofs > data_size) || (pHeader->m_tables_file_ofs > data_size))
- {
- BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (1)\n");
- return false;
- }
+ if (pHeader->m_flags & cBASISHeaderFlagUsesGlobalCodebook)
+ {
+ if (!m_lowlevel_etc1s_decoder.get_global_codebooks())
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: File uses global codebooks, but set_global_codebooks() has not been called\n");
+ return false;
+ }
+ if (!m_lowlevel_etc1s_decoder.get_global_codebooks()->get_endpoints().size())
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: Global codebooks must be unpacked first by calling start_transcoding()\n");
+ return false;
+ }
+ if ((m_lowlevel_etc1s_decoder.get_global_codebooks()->get_endpoints().size() != pHeader->m_total_endpoints) ||
+ (m_lowlevel_etc1s_decoder.get_global_codebooks()->get_selectors().size() != pHeader->m_total_selectors))
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: Global codebook size mismatch (wrong codebooks for file).\n");
+ return false;
+ }
+ if (!pHeader->m_tables_file_size)
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted (2)\n");
+ return false;
+ }
+ if (pHeader->m_tables_file_ofs > data_size)
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (4)\n");
+ return false;
+ }
+ if (pHeader->m_tables_file_size > (data_size - pHeader->m_tables_file_ofs))
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (5)\n");
+ return false;
+ }
+ }
+ else
+ {
+ if (!pHeader->m_endpoint_cb_file_size || !pHeader->m_selector_cb_file_size || !pHeader->m_tables_file_size)
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted (0)\n");
+ return false;
+ }
- if (pHeader->m_endpoint_cb_file_size > (data_size - pHeader->m_endpoint_cb_file_ofs))
- {
- BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (2)\n");
- return false;
- }
+ if ((pHeader->m_endpoint_cb_file_ofs > data_size) || (pHeader->m_selector_cb_file_ofs > data_size) || (pHeader->m_tables_file_ofs > data_size))
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (1)\n");
+ return false;
+ }
- if (pHeader->m_selector_cb_file_size > (data_size - pHeader->m_selector_cb_file_ofs))
- {
- BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (3)\n");
- return false;
- }
+ if (pHeader->m_endpoint_cb_file_size > (data_size - pHeader->m_endpoint_cb_file_ofs))
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (2)\n");
+ return false;
+ }
- if (pHeader->m_tables_file_size > (data_size - pHeader->m_tables_file_ofs))
- {
- BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (3)\n");
- return false;
- }
+ if (pHeader->m_selector_cb_file_size > (data_size - pHeader->m_selector_cb_file_ofs))
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (3)\n");
+ return false;
+ }
- if (!m_lowlevel_decoder.decode_palettes(
- pHeader->m_total_endpoints, pDataU8 + pHeader->m_endpoint_cb_file_ofs, pHeader->m_endpoint_cb_file_size,
- pHeader->m_total_selectors, pDataU8 + pHeader->m_selector_cb_file_ofs, pHeader->m_selector_cb_file_size))
- {
- BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: decode_palettes failed\n");
- return false;
- }
+ if (pHeader->m_tables_file_size > (data_size - pHeader->m_tables_file_ofs))
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (3)\n");
+ return false;
+ }
- if (!m_lowlevel_decoder.decode_tables(pDataU8 + pHeader->m_tables_file_ofs, pHeader->m_tables_file_size))
+ if (!m_lowlevel_etc1s_decoder.decode_palettes(
+ pHeader->m_total_endpoints, pDataU8 + pHeader->m_endpoint_cb_file_ofs, pHeader->m_endpoint_cb_file_size,
+ pHeader->m_total_selectors, pDataU8 + pHeader->m_selector_cb_file_ofs, pHeader->m_selector_cb_file_size))
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: decode_palettes failed\n");
+ return false;
+ }
+ }
+
+ if (!m_lowlevel_etc1s_decoder.decode_tables(pDataU8 + pHeader->m_tables_file_ofs, pHeader->m_tables_file_size))
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: decode_tables failed\n");
+ return false;
+ }
+ }
+ else
{
- BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: decode_tables failed\n");
- return false;
+ // Nothing special to do for UASTC.
+ if (m_lowlevel_etc1s_decoder.m_local_endpoints.size())
+ {
+ m_lowlevel_etc1s_decoder.clear();
+ }
}
+
+ m_ready_to_transcode = true;
+
+ return true;
+ }
+ bool basisu_transcoder::stop_transcoding()
+ {
+ m_lowlevel_etc1s_decoder.clear();
+
+ m_ready_to_transcode = false;
+
return true;
}
bool basisu_transcoder::transcode_slice(const void* pData, uint32_t data_size, uint32_t slice_index, void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels, block_format fmt,
- uint32_t output_block_or_pixel_stride_in_bytes, uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, basisu_transcoder_state* pState, void *pAlpha_blocks, uint32_t output_rows_in_pixels) const
+ uint32_t output_block_or_pixel_stride_in_bytes, uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, basisu_transcoder_state* pState, void *pAlpha_blocks, uint32_t output_rows_in_pixels, int channel0, int channel1) const
{
- if (!m_lowlevel_decoder.m_endpoints.size())
+ if (!m_ready_to_transcode)
{
BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: must call start_transcoding first\n");
return false;
@@ -9529,16 +10631,26 @@ namespace basist
BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: invalid slice_desc.m_file_size, or passed in buffer too small\n");
return false;
}
-
- return m_lowlevel_decoder.transcode_slice(pOutput_blocks, slice_desc.m_num_blocks_x, slice_desc.m_num_blocks_y,
- pDataU8 + slice_desc.m_file_ofs, slice_desc.m_file_size,
- fmt, output_block_or_pixel_stride_in_bytes, (decode_flags & cDecodeFlagsBC1ForbidThreeColorBlocks) == 0, *pHeader, slice_desc, output_row_pitch_in_blocks_or_pixels, pState,
- (decode_flags & cDecodeFlagsOutputHasAlphaIndices) != 0, pAlpha_blocks, output_rows_in_pixels);
+
+ if (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4)
+ {
+ return m_lowlevel_uastc_decoder.transcode_slice(pOutput_blocks, slice_desc.m_num_blocks_x, slice_desc.m_num_blocks_y,
+ pDataU8 + slice_desc.m_file_ofs, slice_desc.m_file_size,
+ fmt, output_block_or_pixel_stride_in_bytes, (decode_flags & cDecodeFlagsBC1ForbidThreeColorBlocks) == 0, *pHeader, slice_desc, output_row_pitch_in_blocks_or_pixels, pState,
+ output_rows_in_pixels, channel0, channel1, decode_flags);
+ }
+ else
+ {
+ return m_lowlevel_etc1s_decoder.transcode_slice(pOutput_blocks, slice_desc.m_num_blocks_x, slice_desc.m_num_blocks_y,
+ pDataU8 + slice_desc.m_file_ofs, slice_desc.m_file_size,
+ fmt, output_block_or_pixel_stride_in_bytes, (decode_flags & cDecodeFlagsBC1ForbidThreeColorBlocks) == 0, *pHeader, slice_desc, output_row_pitch_in_blocks_or_pixels, pState,
+ (decode_flags & cDecodeFlagsOutputHasAlphaIndices) != 0, pAlpha_blocks, output_rows_in_pixels);
+ }
}
int basisu_transcoder::find_first_slice_index(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index) const
{
- (void)data_size;
+ BASISU_NOTE_UNUSED(data_size);
const basis_file_header* pHeader = reinterpret_cast<const basis_file_header*>(pData);
const uint8_t* pDataU8 = static_cast<const uint8_t*>(pData);
@@ -9576,9 +10688,16 @@ namespace basist
const basis_slice_desc& slice_desc = pSlice_descs[slice_iter];
if ((slice_desc.m_image_index == image_index) && (slice_desc.m_level_index == level_index))
{
- const bool slice_alpha = (slice_desc.m_flags & cSliceDescFlagsIsAlphaData) != 0;
- if (slice_alpha == alpha_data)
+ if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)
+ {
+ const bool slice_alpha = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0;
+ if (slice_alpha == alpha_data)
+ return slice_iter;
+ }
+ else
+ {
return slice_iter;
+ }
}
}
@@ -9587,12 +10706,16 @@ namespace basist
return -1;
}
- static void write_opaque_alpha_blocks(
+ void basisu_transcoder::write_opaque_alpha_blocks(
uint32_t num_blocks_x, uint32_t num_blocks_y,
- void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels, block_format fmt,
+ void* pOutput_blocks, block_format fmt,
uint32_t block_stride_in_bytes, uint32_t output_row_pitch_in_blocks_or_pixels)
{
- BASISU_NOTE_UNUSED(output_blocks_buf_size_in_blocks_or_pixels);
+ // 'num_blocks_y', 'pOutput_blocks' & 'block_stride_in_bytes' unused
+ // when disabling BASISD_SUPPORT_ETC2_EAC_A8 *and* BASISD_SUPPORT_DXT5A
+ BASISU_NOTE_UNUSED(num_blocks_y);
+ BASISU_NOTE_UNUSED(pOutput_blocks);
+ BASISU_NOTE_UNUSED(block_stride_in_bytes);
if (!output_row_pitch_in_blocks_or_pixels)
output_row_pitch_in_blocks_or_pixels = num_blocks_x;
@@ -9606,8 +10729,7 @@ namespace basist
blk.m_table = 13;
// Selectors are all 4's
- static const uint8_t s_etc2_eac_a8_sel4[6] = { 0x92, 0x49, 0x24, 0x92, 0x49, 0x24 };
- memcpy(&blk.m_selectors, s_etc2_eac_a8_sel4, sizeof(s_etc2_eac_a8_sel4));
+ memcpy(&blk.m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4));
for (uint32_t y = 0; y < num_blocks_y; y++)
{
@@ -9648,9 +10770,9 @@ namespace basist
transcoder_texture_format fmt,
uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, basisu_transcoder_state *pState, uint32_t output_rows_in_pixels) const
{
- const uint32_t bytes_per_block = basis_get_bytes_per_block(fmt);
+ const uint32_t bytes_per_block_or_pixel = basis_get_bytes_per_block_or_pixel(fmt);
- if (!m_lowlevel_decoder.m_endpoints.size())
+ if (!m_ready_to_transcode)
{
BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: must call start_transcoding() first\n");
return false;
@@ -9693,37 +10815,40 @@ namespace basist
fmt = transcoder_texture_format::cTFPVRTC1_4_RGB;
}
- if (pSlice_descs[slice_index].m_flags & cSliceDescFlagsIsAlphaData)
+ if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file has out of order alpha slice\n");
-
- // The first slice shouldn't have alpha data in a properly formed basis file
- return false;
- }
-
- if (basis_file_has_alpha_slices)
- {
- // The alpha data should immediately follow the color data, and have the same resolution.
- if ((slice_index + 1U) >= pHeader->m_total_slices)
+ if (pSlice_descs[slice_index].m_flags & cSliceDescFlagsHasAlpha)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file has missing alpha slice\n");
- // basis file is missing the alpha slice
- return false;
- }
+ BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file has out of order alpha slice\n");
- // Basic sanity checks
- if ((pSlice_descs[slice_index + 1].m_flags & cSliceDescFlagsIsAlphaData) == 0)
- {
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file has missing alpha slice (flag check)\n");
- // This slice should have alpha data
+ // The first slice shouldn't have alpha data in a properly formed basis file
return false;
}
- if ((pSlice_descs[slice_index].m_num_blocks_x != pSlice_descs[slice_index + 1].m_num_blocks_x) || (pSlice_descs[slice_index].m_num_blocks_y != pSlice_descs[slice_index + 1].m_num_blocks_y))
+ if (basis_file_has_alpha_slices)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file slice dimensions bad\n");
- // Alpha slice should have been the same res as the color slice
- return false;
+ // The alpha data should immediately follow the color data, and have the same resolution.
+ if ((slice_index + 1U) >= pHeader->m_total_slices)
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file has missing alpha slice\n");
+ // basis file is missing the alpha slice
+ return false;
+ }
+
+ // Basic sanity checks
+ if ((pSlice_descs[slice_index + 1].m_flags & cSliceDescFlagsHasAlpha) == 0)
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file has missing alpha slice (flag check)\n");
+ // This slice should have alpha data
+ return false;
+ }
+
+ if ((pSlice_descs[slice_index].m_num_blocks_x != pSlice_descs[slice_index + 1].m_num_blocks_x) || (pSlice_descs[slice_index].m_num_blocks_y != pSlice_descs[slice_index + 1].m_num_blocks_y))
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file slice dimensions bad\n");
+ // Alpha slice should have been the same res as the color slice
+ return false;
+ }
}
}
@@ -9735,798 +10860,6745 @@ namespace basist
{
// The transcoder doesn't write beyond total_slice_blocks, so we need to clear the rest ourselves.
// For GL usage, PVRTC1 4bpp image size is (max(width, 8)* max(height, 8) * 4 + 7) / 8.
- // However, for KTX and internally in Basis this formula isn't used, it's just ((width+3)/4) * ((height+3)/4) * bytes_per_block. This is all the transcoder actually writes to memory.
- memset(static_cast<uint8_t*>(pOutput_blocks) + total_slice_blocks * bytes_per_block, 0, (output_blocks_buf_size_in_blocks_or_pixels - total_slice_blocks) * bytes_per_block);
+ // However, for KTX and internally in Basis this formula isn't used, it's just ((width+3)/4) * ((height+3)/4) * bytes_per_block_or_pixel. This is all the transcoder actually writes to memory.
+ memset(static_cast<uint8_t*>(pOutput_blocks) + total_slice_blocks * bytes_per_block_or_pixel, 0, (output_blocks_buf_size_in_blocks_or_pixels - total_slice_blocks) * bytes_per_block_or_pixel);
}
-
+
+ if (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4)
+ {
+ const basis_slice_desc* pSlice_desc = &pSlice_descs[slice_index];
+
+ // Use the container independent image transcode method.
+ status = m_lowlevel_uastc_decoder.transcode_image(fmt,
+ pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels,
+ (const uint8_t*)pData, data_size, pSlice_desc->m_num_blocks_x, pSlice_desc->m_num_blocks_y, pSlice_desc->m_orig_width, pSlice_desc->m_orig_height, pSlice_desc->m_level_index,
+ pSlice_desc->m_file_ofs, pSlice_desc->m_file_size,
+ decode_flags, basis_file_has_alpha_slices, pHeader->m_tex_type == cBASISTexTypeVideoFrames, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);
+ }
+ else
+ {
+ // ETC1S
+ const basis_slice_desc* pSlice_desc = &pSlice_descs[slice_index];
+ const basis_slice_desc* pAlpha_slice_desc = basis_file_has_alpha_slices ? &pSlice_descs[slice_index + 1] : nullptr;
+
+ assert((pSlice_desc->m_flags & cSliceDescFlagsHasAlpha) == 0);
+
+ if (pAlpha_slice_desc)
+ {
+ // Basic sanity checks
+ assert((pAlpha_slice_desc->m_flags & cSliceDescFlagsHasAlpha) != 0);
+ assert(pSlice_desc->m_num_blocks_x == pAlpha_slice_desc->m_num_blocks_x);
+ assert(pSlice_desc->m_num_blocks_y == pAlpha_slice_desc->m_num_blocks_y);
+ assert(pSlice_desc->m_level_index == pAlpha_slice_desc->m_level_index);
+ }
+
+ // Use the container independent image transcode method.
+ status = m_lowlevel_etc1s_decoder.transcode_image(fmt,
+ pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels,
+ (const uint8_t *)pData, data_size, pSlice_desc->m_num_blocks_x, pSlice_desc->m_num_blocks_y, pSlice_desc->m_orig_width, pSlice_desc->m_orig_height, pSlice_desc->m_level_index,
+ pSlice_desc->m_file_ofs, pSlice_desc->m_file_size,
+ (pAlpha_slice_desc != nullptr) ? (uint32_t)pAlpha_slice_desc->m_file_ofs : 0U, (pAlpha_slice_desc != nullptr) ? (uint32_t)pAlpha_slice_desc->m_file_size : 0U,
+ decode_flags, basis_file_has_alpha_slices, pHeader->m_tex_type == cBASISTexTypeVideoFrames, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);
+
+ } // if (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4)
+
+ if (!status)
+ {
+ BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Returning false\n");
+ }
+ else
+ {
+ //BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Returning true\n");
+ }
+
+ return status;
+ }
+
+ uint32_t basis_get_bytes_per_block_or_pixel(transcoder_texture_format fmt)
+ {
switch (fmt)
{
case transcoder_texture_format::cTFETC1_RGB:
+ case transcoder_texture_format::cTFBC1_RGB:
+ case transcoder_texture_format::cTFBC4_R:
+ case transcoder_texture_format::cTFPVRTC1_4_RGB:
+ case transcoder_texture_format::cTFPVRTC1_4_RGBA:
+ case transcoder_texture_format::cTFATC_RGB:
+ case transcoder_texture_format::cTFPVRTC2_4_RGB:
+ case transcoder_texture_format::cTFPVRTC2_4_RGBA:
+ case transcoder_texture_format::cTFETC2_EAC_R11:
+ return 8;
+ case transcoder_texture_format::cTFBC7_RGBA:
+ case transcoder_texture_format::cTFBC7_ALT:
+ case transcoder_texture_format::cTFETC2_RGBA:
+ case transcoder_texture_format::cTFBC3_RGBA:
+ case transcoder_texture_format::cTFBC5_RG:
+ case transcoder_texture_format::cTFASTC_4x4_RGBA:
+ case transcoder_texture_format::cTFATC_RGBA:
+ case transcoder_texture_format::cTFFXT1_RGB:
+ case transcoder_texture_format::cTFETC2_EAC_RG11:
+ return 16;
+ case transcoder_texture_format::cTFRGBA32:
+ return sizeof(uint32_t);
+ case transcoder_texture_format::cTFRGB565:
+ case transcoder_texture_format::cTFBGR565:
+ case transcoder_texture_format::cTFRGBA4444:
+ return sizeof(uint16_t);
+ default:
+ assert(0);
+ BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");
+ break;
+ }
+ return 0;
+ }
+
+ const char* basis_get_format_name(transcoder_texture_format fmt)
+ {
+ switch (fmt)
{
- uint32_t slice_index_to_decode = slice_index;
- // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
- if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
- slice_index_to_decode++;
+ case transcoder_texture_format::cTFETC1_RGB: return "ETC1_RGB";
+ case transcoder_texture_format::cTFBC1_RGB: return "BC1_RGB";
+ case transcoder_texture_format::cTFBC4_R: return "BC4_R";
+ case transcoder_texture_format::cTFPVRTC1_4_RGB: return "PVRTC1_4_RGB";
+ case transcoder_texture_format::cTFPVRTC1_4_RGBA: return "PVRTC1_4_RGBA";
+ case transcoder_texture_format::cTFBC7_RGBA: return "BC7_RGBA";
+ case transcoder_texture_format::cTFBC7_ALT: return "BC7_RGBA";
+ case transcoder_texture_format::cTFETC2_RGBA: return "ETC2_RGBA";
+ case transcoder_texture_format::cTFBC3_RGBA: return "BC3_RGBA";
+ case transcoder_texture_format::cTFBC5_RG: return "BC5_RG";
+ case transcoder_texture_format::cTFASTC_4x4_RGBA: return "ASTC_RGBA";
+ case transcoder_texture_format::cTFATC_RGB: return "ATC_RGB";
+ case transcoder_texture_format::cTFATC_RGBA: return "ATC_RGBA";
+ case transcoder_texture_format::cTFRGBA32: return "RGBA32";
+ case transcoder_texture_format::cTFRGB565: return "RGB565";
+ case transcoder_texture_format::cTFBGR565: return "BGR565";
+ case transcoder_texture_format::cTFRGBA4444: return "RGBA4444";
+ case transcoder_texture_format::cTFFXT1_RGB: return "FXT1_RGB";
+ case transcoder_texture_format::cTFPVRTC2_4_RGB: return "PVRTC2_4_RGB";
+ case transcoder_texture_format::cTFPVRTC2_4_RGBA: return "PVRTC2_4_RGBA";
+ case transcoder_texture_format::cTFETC2_EAC_R11: return "ETC2_EAC_R11";
+ case transcoder_texture_format::cTFETC2_EAC_RG11: return "ETC2_EAC_RG11";
+ default:
+ assert(0);
+ BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");
+ break;
+ }
+ return "";
+ }
- status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ const char* basis_get_block_format_name(block_format fmt)
+ {
+ switch (fmt)
+ {
+ case block_format::cETC1: return "ETC1";
+ case block_format::cBC1: return "BC1";
+ case block_format::cPVRTC1_4_RGB: return "PVRTC1_4_RGB";
+ case block_format::cPVRTC1_4_RGBA: return "PVRTC1_4_RGBA";
+ case block_format::cBC7: return "BC7";
+ case block_format::cETC2_RGBA: return "ETC2_RGBA";
+ case block_format::cBC3: return "BC3";
+ case block_format::cASTC_4x4: return "ASTC_4x4";
+ case block_format::cATC_RGB: return "ATC_RGB";
+ case block_format::cRGBA32: return "RGBA32";
+ case block_format::cRGB565: return "RGB565";
+ case block_format::cBGR565: return "BGR565";
+ case block_format::cRGBA4444: return "RGBA4444";
+ case block_format::cFXT1_RGB: return "FXT1_RGB";
+ case block_format::cPVRTC2_4_RGB: return "PVRTC2_4_RGB";
+ case block_format::cPVRTC2_4_RGBA: return "PVRTC2_4_RGBA";
+ case block_format::cETC2_EAC_R11: return "ETC2_EAC_R11";
+ case block_format::cETC2_EAC_RG11: return "ETC2_EAC_RG11";
+ default:
+ assert(0);
+ BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");
+ break;
+ }
+ return "";
+ }
+
+ const char* basis_get_texture_type_name(basis_texture_type tex_type)
+ {
+ switch (tex_type)
+ {
+ case cBASISTexType2D: return "2D";
+ case cBASISTexType2DArray: return "2D array";
+ case cBASISTexTypeCubemapArray: return "cubemap array";
+ case cBASISTexTypeVideoFrames: return "video";
+ case cBASISTexTypeVolume: return "3D";
+ default:
+ assert(0);
+ BASISU_DEVEL_ERROR("basis_get_texture_type_name: Invalid tex_type\n");
+ break;
+ }
+ return "";
+ }
+
+ bool basis_transcoder_format_has_alpha(transcoder_texture_format fmt)
+ {
+ switch (fmt)
+ {
+ case transcoder_texture_format::cTFETC2_RGBA:
+ case transcoder_texture_format::cTFBC3_RGBA:
+ case transcoder_texture_format::cTFASTC_4x4_RGBA:
+ case transcoder_texture_format::cTFBC7_RGBA:
+ case transcoder_texture_format::cTFBC7_ALT:
+ case transcoder_texture_format::cTFPVRTC1_4_RGBA:
+ case transcoder_texture_format::cTFPVRTC2_4_RGBA:
+ case transcoder_texture_format::cTFATC_RGBA:
+ case transcoder_texture_format::cTFRGBA32:
+ case transcoder_texture_format::cTFRGBA4444:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ basisu::texture_format basis_get_basisu_texture_format(transcoder_texture_format fmt)
+ {
+ switch (fmt)
+ {
+ case transcoder_texture_format::cTFETC1_RGB: return basisu::texture_format::cETC1;
+ case transcoder_texture_format::cTFBC1_RGB: return basisu::texture_format::cBC1;
+ case transcoder_texture_format::cTFBC4_R: return basisu::texture_format::cBC4;
+ case transcoder_texture_format::cTFPVRTC1_4_RGB: return basisu::texture_format::cPVRTC1_4_RGB;
+ case transcoder_texture_format::cTFPVRTC1_4_RGBA: return basisu::texture_format::cPVRTC1_4_RGBA;
+ case transcoder_texture_format::cTFBC7_RGBA: return basisu::texture_format::cBC7;
+ case transcoder_texture_format::cTFBC7_ALT: return basisu::texture_format::cBC7;
+ case transcoder_texture_format::cTFETC2_RGBA: return basisu::texture_format::cETC2_RGBA;
+ case transcoder_texture_format::cTFBC3_RGBA: return basisu::texture_format::cBC3;
+ case transcoder_texture_format::cTFBC5_RG: return basisu::texture_format::cBC5;
+ case transcoder_texture_format::cTFASTC_4x4_RGBA: return basisu::texture_format::cASTC4x4;
+ case transcoder_texture_format::cTFATC_RGB: return basisu::texture_format::cATC_RGB;
+ case transcoder_texture_format::cTFATC_RGBA: return basisu::texture_format::cATC_RGBA_INTERPOLATED_ALPHA;
+ case transcoder_texture_format::cTFRGBA32: return basisu::texture_format::cRGBA32;
+ case transcoder_texture_format::cTFRGB565: return basisu::texture_format::cRGB565;
+ case transcoder_texture_format::cTFBGR565: return basisu::texture_format::cBGR565;
+ case transcoder_texture_format::cTFRGBA4444: return basisu::texture_format::cRGBA4444;
+ case transcoder_texture_format::cTFFXT1_RGB: return basisu::texture_format::cFXT1_RGB;
+ case transcoder_texture_format::cTFPVRTC2_4_RGB: return basisu::texture_format::cPVRTC2_4_RGBA;
+ case transcoder_texture_format::cTFPVRTC2_4_RGBA: return basisu::texture_format::cPVRTC2_4_RGBA;
+ case transcoder_texture_format::cTFETC2_EAC_R11: return basisu::texture_format::cETC2_R11_EAC;
+ case transcoder_texture_format::cTFETC2_EAC_RG11: return basisu::texture_format::cETC2_RG11_EAC;
+ default:
+ assert(0);
+ BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");
+ break;
+ }
+ return basisu::texture_format::cInvalidTextureFormat;
+ }
+
+ bool basis_transcoder_format_is_uncompressed(transcoder_texture_format tex_type)
+ {
+ switch (tex_type)
+ {
+ case transcoder_texture_format::cTFRGBA32:
+ case transcoder_texture_format::cTFRGB565:
+ case transcoder_texture_format::cTFBGR565:
+ case transcoder_texture_format::cTFRGBA4444:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ bool basis_block_format_is_uncompressed(block_format blk_fmt)
+ {
+ switch (blk_fmt)
+ {
+ case block_format::cRGB32:
+ case block_format::cRGBA32:
+ case block_format::cA32:
+ case block_format::cRGB565:
+ case block_format::cBGR565:
+ case block_format::cRGBA4444:
+ case block_format::cRGBA4444_COLOR:
+ case block_format::cRGBA4444_ALPHA:
+ case block_format::cRGBA4444_COLOR_OPAQUE:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ uint32_t basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format fmt)
+ {
+ switch (fmt)
+ {
+ case transcoder_texture_format::cTFRGBA32:
+ return sizeof(uint32_t);
+ case transcoder_texture_format::cTFRGB565:
+ case transcoder_texture_format::cTFBGR565:
+ case transcoder_texture_format::cTFRGBA4444:
+ return sizeof(uint16_t);
+ default:
+ break;
+ }
+ return 0;
+ }
+
+ uint32_t basis_get_block_width(transcoder_texture_format tex_type)
+ {
+ switch (tex_type)
+ {
+ case transcoder_texture_format::cTFFXT1_RGB:
+ return 8;
+ default:
+ break;
+ }
+ return 4;
+ }
+
+ uint32_t basis_get_block_height(transcoder_texture_format tex_type)
+ {
+ BASISU_NOTE_UNUSED(tex_type);
+ return 4;
+ }
+
+ bool basis_is_format_supported(transcoder_texture_format tex_type, basis_tex_format fmt)
+ {
+ if (fmt == basis_tex_format::cUASTC4x4)
+ {
+#if BASISD_SUPPORT_UASTC
+ switch (tex_type)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to ETC1 failed\n");
+ // These niche formats aren't currently supported for UASTC - everything else is.
+ case transcoder_texture_format::cTFPVRTC2_4_RGB:
+ case transcoder_texture_format::cTFPVRTC2_4_RGBA:
+ case transcoder_texture_format::cTFATC_RGB:
+ case transcoder_texture_format::cTFATC_RGBA:
+ case transcoder_texture_format::cTFFXT1_RGB:
+ return false;
+ default:
+ return true;
}
- break;
+#endif
}
- case transcoder_texture_format::cTFBC1_RGB:
+ else
{
-#if !BASISD_SUPPORT_DXT1
- return false;
+ switch (tex_type)
+ {
+ // ETC1 and uncompressed are always supported.
+ case transcoder_texture_format::cTFETC1_RGB:
+ case transcoder_texture_format::cTFRGBA32:
+ case transcoder_texture_format::cTFRGB565:
+ case transcoder_texture_format::cTFBGR565:
+ case transcoder_texture_format::cTFRGBA4444:
+ return true;
+#if BASISD_SUPPORT_DXT1
+ case transcoder_texture_format::cTFBC1_RGB:
+ return true;
+#endif
+#if BASISD_SUPPORT_DXT5A
+ case transcoder_texture_format::cTFBC4_R:
+ case transcoder_texture_format::cTFBC5_RG:
+ return true;
+#endif
+#if BASISD_SUPPORT_DXT1 && BASISD_SUPPORT_DXT5A
+ case transcoder_texture_format::cTFBC3_RGBA:
+ return true;
+#endif
+#if BASISD_SUPPORT_PVRTC1
+ case transcoder_texture_format::cTFPVRTC1_4_RGB:
+ case transcoder_texture_format::cTFPVRTC1_4_RGBA:
+ return true;
+#endif
+#if BASISD_SUPPORT_BC7_MODE5
+ case transcoder_texture_format::cTFBC7_RGBA:
+ case transcoder_texture_format::cTFBC7_ALT:
+ return true;
+#endif
+#if BASISD_SUPPORT_ETC2_EAC_A8
+ case transcoder_texture_format::cTFETC2_RGBA:
+ return true;
+#endif
+#if BASISD_SUPPORT_ASTC
+ case transcoder_texture_format::cTFASTC_4x4_RGBA:
+ return true;
+#endif
+#if BASISD_SUPPORT_ATC
+ case transcoder_texture_format::cTFATC_RGB:
+ case transcoder_texture_format::cTFATC_RGBA:
+ return true;
+#endif
+#if BASISD_SUPPORT_FXT1
+ case transcoder_texture_format::cTFFXT1_RGB:
+ return true;
+#endif
+#if BASISD_SUPPORT_PVRTC2
+ case transcoder_texture_format::cTFPVRTC2_4_RGB:
+ case transcoder_texture_format::cTFPVRTC2_4_RGBA:
+ return true;
#endif
- uint32_t slice_index_to_decode = slice_index;
- // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
- if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
- slice_index_to_decode++;
+#if BASISD_SUPPORT_ETC2_EAC_RG11
+ case transcoder_texture_format::cTFETC2_EAC_R11:
+ case transcoder_texture_format::cTFETC2_EAC_RG11:
+ return true;
+#endif
+ default:
+ break;
+ }
+ }
- status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC1, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ return false;
+ }
+
+ // ------------------------------------------------------------------------------------------------------
+ // UASTC
+ // ------------------------------------------------------------------------------------------------------
+
+#if BASISD_SUPPORT_UASTC
+ const astc_bc7_common_partition2_desc g_astc_bc7_common_partitions2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2] =
+ {
+ { 0, 28, false }, { 1, 20, false }, { 2, 16, true }, { 3, 29, false },
+ { 4, 91, true }, { 5, 9, false }, { 6, 107, true }, { 7, 72, true },
+ { 8, 149, false }, { 9, 204, true }, { 10, 50, false }, { 11, 114, true },
+ { 12, 496, true }, { 13, 17, true }, { 14, 78, false }, { 15, 39, true },
+ { 17, 252, true }, { 18, 828, true }, { 19, 43, false }, { 20, 156, false },
+ { 21, 116, false }, { 22, 210, true }, { 23, 476, true }, { 24, 273, false },
+ { 25, 684, true }, { 26, 359, false }, { 29, 246, true }, { 32, 195, true },
+ { 33, 694, true }, { 52, 524, true }
+ };
+
+ const bc73_astc2_common_partition_desc g_bc7_3_astc2_common_partitions[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS] =
+ {
+ { 10, 36, 4 }, { 11, 48, 4 }, { 0, 61, 3 }, { 2, 137, 4 },
+ { 8, 161, 5 }, { 13, 183, 4 }, { 1, 226, 2 }, { 33, 281, 2 },
+ { 40, 302, 3 }, { 20, 307, 4 }, { 21, 479, 0 }, { 58, 495, 3 },
+ { 3, 593, 0 }, { 32, 594, 2 }, { 59, 605, 1 }, { 34, 799, 3 },
+ { 20, 812, 1 }, { 14, 988, 4 }, { 31, 993, 3 }
+ };
+
+ const astc_bc7_common_partition3_desc g_astc_bc7_common_partitions3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3] =
+ {
+ { 4, 260, 0 }, { 8, 74, 5 }, { 9, 32, 5 }, { 10, 156, 2 },
+ { 11, 183, 2 }, { 12, 15, 0 }, { 13, 745, 4 }, { 20, 0, 1 },
+ { 35, 335, 1 }, { 36, 902, 5 }, { 57, 254, 0 }
+ };
+
+ const uint8_t g_astc_to_bc7_partition_index_perm_tables[6][3] = { { 0, 1, 2 }, { 1, 2, 0 }, { 2, 0, 1 }, { 2, 1, 0 }, { 0, 2, 1 }, { 1, 0, 2 } };
+
+ const uint8_t g_bc7_to_astc_partition_index_perm_tables[6][3] = { { 0, 1, 2 }, { 2, 0, 1 }, { 1, 2, 0 }, { 2, 1, 0 }, { 0, 2, 1 }, { 1, 0, 2 } };
+
+ uint32_t bc7_convert_partition_index_3_to_2(uint32_t p, uint32_t k)
+ {
+ assert(k < 6);
+ switch (k >> 1)
+ {
+ case 0:
+ if (p <= 1)
+ p = 0;
+ else
+ p = 1;
+ break;
+ case 1:
+ if (p == 0)
+ p = 0;
+ else
+ p = 1;
+ break;
+ case 2:
+ if ((p == 0) || (p == 2))
+ p = 0;
+ else
+ p = 1;
+ break;
+ }
+ if (k & 1)
+ p = 1 - p;
+ return p;
+ }
+
+ static const uint8_t g_zero_pattern[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ const uint8_t g_astc_bc7_patterns2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][16] =
+ {
+ { 0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1 }, { 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1 }, { 1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0 }, { 0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1 },
+ { 1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,0 }, { 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1 }, { 1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0 }, { 1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1 }, { 1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1 }, { 1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0 },
+ { 1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0 }, { 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1 }, { 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0 },
+ { 1,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1 }, { 1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,1 }, { 0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0 }, { 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0 }, { 1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1 }, { 1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,0 }, { 0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0 },
+ { 1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1 }, { 0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0 }, { 1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1 }, { 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0 },
+ { 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0 }, { 1,0,0,1,0,0,1,1,0,1,1,0,1,1,0,0 }
+ };
+
+ const uint8_t g_astc_bc7_patterns3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][16] =
+ {
+ { 0,0,0,0,0,0,0,0,1,1,2,2,1,1,2,2 }, { 1,1,1,1,1,1,1,1,0,0,0,0,2,2,2,2 }, { 1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2 }, { 1,1,1,1,2,2,2,2,0,0,0,0,0,0,0,0 },
+ { 1,1,2,0,1,1,2,0,1,1,2,0,1,1,2,0 }, { 0,1,1,2,0,1,1,2,0,1,1,2,0,1,1,2 }, { 0,2,1,1,0,2,1,1,0,2,1,1,0,2,1,1 }, { 2,0,0,0,2,0,0,0,2,1,1,1,2,1,1,1 },
+ { 2,0,1,2,2,0,1,2,2,0,1,2,2,0,1,2 }, { 1,1,1,1,0,0,0,0,2,2,2,2,1,1,1,1 }, { 0,0,2,2,0,0,1,1,0,0,1,1,0,0,2,2 }
+ };
+
+ const uint8_t g_bc7_3_astc2_patterns2[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][16] =
+ {
+ { 0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0 }, { 0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0 }, { 1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,0,1,1,0,0,1,1 },
+ { 1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1 }, { 0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0 }, { 0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1 }, { 0,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1 },
+ { 1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0 }, { 0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,0 }, { 1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0 },
+ { 0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, { 1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0 }, { 1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,0 },
+ { 1,1,1,1,1,1,1,1,1,0,0,0,1,0,0,0 }, { 0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0 }, { 1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0 }
+ };
+
+ const uint8_t g_astc_bc7_pattern2_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][3] =
+ {
+ { 0, 2 }, { 0, 3 }, { 1, 0 }, { 0, 3 }, { 7, 0 }, { 0, 2 }, { 3, 0 }, { 7, 0 },
+ { 0, 11 }, { 2, 0 }, { 0, 7 }, { 11, 0 }, { 3, 0 }, { 8, 0 }, { 0, 4 }, { 12, 0 },
+ { 1, 0 }, { 8, 0 }, { 0, 1 }, { 0, 2 }, { 0, 4 }, { 8, 0 }, { 1, 0 }, { 0, 2 },
+ { 4, 0 }, { 0, 1 }, { 4, 0 }, { 1, 0 }, { 4, 0 }, { 1, 0 }
+ };
+
+ const uint8_t g_astc_bc7_pattern3_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][3] =
+ {
+ { 0, 8, 10 }, { 8, 0, 12 }, { 4, 0, 12 }, { 8, 0, 4 }, { 3, 0, 2 }, { 0, 1, 3 }, { 0, 2, 1 }, { 1, 9, 0 }, { 1, 2, 0 }, { 4, 0, 8 }, { 0, 6, 2 }
+ };
+
+ const uint8_t g_bc7_3_astc2_patterns2_anchors[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][3] =
+ {
+ { 0, 4 }, { 0, 2 }, { 2, 0 }, { 0, 7 }, { 8, 0 }, { 0, 1 }, { 0, 3 }, { 0, 1 }, { 2, 0 }, { 0, 1 }, { 0, 8 }, { 2, 0 }, { 0, 1 }, { 0, 7 }, { 12, 0 }, { 2, 0 }, { 9, 0 }, { 0, 2 }, { 4, 0 }
+ };
+
+ const uint32_t g_uastc_mode_huff_codes[TOTAL_UASTC_MODES + 1][2] =
+ {
+ { 0x1, 4 },
+ { 0x35, 6 },
+ { 0x1D, 5 },
+ { 0x3, 5 },
+
+ { 0x13, 5 },
+ { 0xB, 5 },
+ { 0x1B, 5 },
+ { 0x7, 5 },
+
+ { 0x17, 5 },
+ { 0xF, 5 },
+ { 0x2, 3 },
+ { 0x0, 2 },
+
+ { 0x6, 3 },
+ { 0x1F, 5 },
+ { 0xD, 5 },
+ { 0x5, 7 },
+
+ { 0x15, 6 },
+ { 0x25, 6 },
+ { 0x9, 4 },
+ { 0x45, 7 } // future expansion
+ };
+
+ // If g_uastc_mode_huff_codes[] changes this table must be updated!
+ static const uint8_t g_uastc_huff_modes[128] =
+ {
+ 11,0,10,3,11,15,12,7,11,18,10,5,11,14,12,9,11,0,10,4,11,16,12,8,11,18,10,6,11,2,12,13,11,0,10,3,11,17,12,7,11,18,10,5,11,14,12,9,11,0,10,4,11,1,12,8,11,18,10,6,11,2,12,13,11,0,10,3,11,
+ 19,12,7,11,18,10,5,11,14,12,9,11,0,10,4,11,16,12,8,11,18,10,6,11,2,12,13,11,0,10,3,11,17,12,7,11,18,10,5,11,14,12,9,11,0,10,4,11,1,12,8,11,18,10,6,11,2,12,13
+ };
+
+ const uint8_t g_uastc_mode_weight_bits[TOTAL_UASTC_MODES] = { 4, 2, 3, 2, 2, 3, 2, 2, 0, 2, 4, 2, 3, 1, 2, 4, 2, 2, 5 };
+ const uint8_t g_uastc_mode_weight_ranges[TOTAL_UASTC_MODES] = { 8, 2, 5, 2, 2, 5, 2, 2, 0, 2, 8, 2, 5, 0, 2, 8, 2, 2, 11 };
+ const uint8_t g_uastc_mode_endpoint_ranges[TOTAL_UASTC_MODES] = { 19, 20, 8, 7, 12, 20, 18, 12, 0, 8, 13, 13, 19, 20, 20, 20, 20, 20, 11 };
+ const uint8_t g_uastc_mode_subsets[TOTAL_UASTC_MODES] = { 1, 1, 2, 3, 2, 1, 1, 2, 0, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1 };
+ const uint8_t g_uastc_mode_planes[TOTAL_UASTC_MODES] = { 1, 1, 1, 1, 1, 1, 2, 1, 0, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1 };
+ const uint8_t g_uastc_mode_comps[TOTAL_UASTC_MODES] = { 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 3 };
+ const uint8_t g_uastc_mode_has_etc1_bias[TOTAL_UASTC_MODES] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 };
+ const uint8_t g_uastc_mode_has_bc1_hint0[TOTAL_UASTC_MODES] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ const uint8_t g_uastc_mode_has_bc1_hint1[TOTAL_UASTC_MODES] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 };
+ const uint8_t g_uastc_mode_cem[TOTAL_UASTC_MODES] = { 8, 8, 8, 8, 8, 8, 8, 8, 0, 12, 12, 12, 12, 12, 12, 4, 4, 4, 8 };
+ const uint8_t g_uastc_mode_has_alpha[TOTAL_UASTC_MODES] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 };
+ const uint8_t g_uastc_mode_is_la[TOTAL_UASTC_MODES] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0 };
+ const uint8_t g_uastc_mode_total_hint_bits[TOTAL_UASTC_MODES] = { 15, 15, 15, 15, 15, 15, 15, 15, 0, 23, 17, 17, 17, 23, 23, 23, 23, 23, 15 };
+
+ // bits, trits, quints
+ const int g_astc_bise_range_table[TOTAL_ASTC_RANGES][3] =
+ {
+ { 1, 0, 0 }, // 0-1 0
+ { 0, 1, 0 }, // 0-2 1
+ { 2, 0, 0 }, // 0-3 2
+ { 0, 0, 1 }, // 0-4 3
+
+ { 1, 1, 0 }, // 0-5 4
+ { 3, 0, 0 }, // 0-7 5
+ { 1, 0, 1 }, // 0-9 6
+ { 2, 1, 0 }, // 0-11 7
+
+ { 4, 0, 0 }, // 0-15 8
+ { 2, 0, 1 }, // 0-19 9
+ { 3, 1, 0 }, // 0-23 10
+ { 5, 0, 0 }, // 0-31 11
+
+ { 3, 0, 1 }, // 0-39 12
+ { 4, 1, 0 }, // 0-47 13
+ { 6, 0, 0 }, // 0-63 14
+ { 4, 0, 1 }, // 0-79 15
+
+ { 5, 1, 0 }, // 0-95 16
+ { 7, 0, 0 }, // 0-127 17
+ { 5, 0, 1 }, // 0-159 18
+ { 6, 1, 0 }, // 0-191 19
+
+ { 8, 0, 0 }, // 0-255 20
+ };
+
+ int astc_get_levels(int range)
+ {
+ assert(range < (int)BC7ENC_TOTAL_ASTC_RANGES);
+ return (1 + 2 * g_astc_bise_range_table[range][1] + 4 * g_astc_bise_range_table[range][2]) << g_astc_bise_range_table[range][0];
+ }
+
+ // g_astc_unquant[] is the inverse of g_astc_sorted_order_unquant[]
+ astc_quant_bin g_astc_unquant[BC7ENC_TOTAL_ASTC_RANGES][256]; // [ASTC encoded endpoint index]
+
+ // Taken right from the ASTC spec.
+ static struct
+ {
+ const char* m_pB_str;
+ uint32_t m_c;
+ } g_astc_endpoint_unquant_params[BC7ENC_TOTAL_ASTC_RANGES] =
+ {
+ { "", 0 },
+ { "", 0 },
+ { "", 0 },
+ { "", 0 },
+ { "000000000", 204, }, // 0-5
+ { "", 0 },
+ { "000000000", 113, }, // 0-9
+ { "b000b0bb0", 93 }, // 0-11
+ { "", 0 },
+ { "b0000bb00", 54 }, // 0-19
+ { "cb000cbcb", 44 }, // 0-23
+ { "", 0 },
+ { "cb0000cbc", 26 }, // 0-39
+ { "dcb000dcb", 22 }, // 0-47
+ { "", 0 },
+ { "dcb0000dc", 13 }, // 0-79
+ { "edcb000ed", 11 }, // 0-95
+ { "", 0 },
+ { "edcb0000e", 6 }, // 0-159
+ { "fedcb000f", 5 }, // 0-191
+ { "", 0 },
+ };
+
+ bool astc_is_valid_endpoint_range(uint32_t range)
+ {
+ if ((g_astc_bise_range_table[range][1] == 0) && (g_astc_bise_range_table[range][2] == 0))
+ return true;
+
+ return g_astc_endpoint_unquant_params[range].m_c != 0;
+ }
+
+ uint32_t unquant_astc_endpoint(uint32_t packed_bits, uint32_t packed_trits, uint32_t packed_quints, uint32_t range)
+ {
+ assert(range < BC7ENC_TOTAL_ASTC_RANGES);
+
+ const uint32_t bits = g_astc_bise_range_table[range][0];
+ const uint32_t trits = g_astc_bise_range_table[range][1];
+ const uint32_t quints = g_astc_bise_range_table[range][2];
+
+ uint32_t val = 0;
+ if ((!trits) && (!quints))
+ {
+ assert(!packed_trits && !packed_quints);
+
+ int bits_left = 8;
+ while (bits_left > 0)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to BC1 failed\n");
+ uint32_t v = packed_bits;
+
+ int n = basisu::minimumi(bits_left, bits);
+ if (n < (int)bits)
+ v >>= (bits - n);
+
+ assert(v < (1U << n));
+
+ val |= (v << (bits_left - n));
+ bits_left -= n;
}
- break;
}
- case transcoder_texture_format::cTFBC4_R:
+ else
{
-#if !BASISD_SUPPORT_DXT5A
- return false;
-#endif
- uint32_t slice_index_to_decode = slice_index;
- // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
- if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
- slice_index_to_decode++;
+ const uint32_t A = (packed_bits & 1) ? 511 : 0;
+ const uint32_t C = g_astc_endpoint_unquant_params[range].m_c;
+ const uint32_t D = trits ? packed_trits : packed_quints;
- status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ assert(C);
+
+ uint32_t B = 0;
+ for (uint32_t i = 0; i < 9; i++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to BC4 failed\n");
+ B <<= 1;
+
+ char c = g_astc_endpoint_unquant_params[range].m_pB_str[i];
+ if (c != '0')
+ {
+ c -= 'a';
+ B |= ((packed_bits >> c) & 1);
+ }
}
- break;
+
+ val = D * C + B;
+ val = val ^ A;
+ val = (A & 0x80) | (val >> 2);
}
- case transcoder_texture_format::cTFPVRTC1_4_RGB:
+
+ return val;
+ }
+
+ uint32_t unquant_astc_endpoint_val(uint32_t packed_val, uint32_t range)
+ {
+ assert(range < BC7ENC_TOTAL_ASTC_RANGES);
+ assert(packed_val < (uint32_t)astc_get_levels(range));
+
+ const uint32_t bits = g_astc_bise_range_table[range][0];
+ const uint32_t trits = g_astc_bise_range_table[range][1];
+ const uint32_t quints = g_astc_bise_range_table[range][2];
+
+ if ((!trits) && (!quints))
+ return unquant_astc_endpoint(packed_val, 0, 0, range);
+ else if (trits)
+ return unquant_astc_endpoint(packed_val & ((1 << bits) - 1), packed_val >> bits, 0, range);
+ else
+ return unquant_astc_endpoint(packed_val & ((1 << bits) - 1), 0, packed_val >> bits, range);
+ }
+
+ // BC7 - Various BC7 tables/helpers
+ const uint32_t g_bc7_weights1[2] = { 0, 64 };
+ const uint32_t g_bc7_weights2[4] = { 0, 21, 43, 64 };
+ const uint32_t g_bc7_weights3[8] = { 0, 9, 18, 27, 37, 46, 55, 64 };
+ const uint32_t g_bc7_weights4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
+ const uint32_t g_astc_weights4[16] = { 0, 4, 8, 12, 17, 21, 25, 29, 35, 39, 43, 47, 52, 56, 60, 64 };
+ const uint32_t g_astc_weights5[32] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64 };
+ const uint32_t g_astc_weights_3levels[3] = { 0, 32, 64 };
+
+ const uint8_t g_bc7_partition1[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+ const uint8_t g_bc7_partition2[64 * 16] =
+ {
+ 0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, 0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1, 0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1, 0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1, 0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,
+ 0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1, 0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,
+ 0,0,0,0,1,0,0,0,1,1,1,0,1,1,1,1, 0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0, 0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0, 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,
+ 0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0, 0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0, 0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0, 0,0,0,1,0,1,1,1,1,1,1,0,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0, 0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0,
+ 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, 0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0, 0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0, 0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1, 0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1,
+ 0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0, 0,0,0,1,0,0,1,1,1,1,0,0,1,0,0,0, 0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0, 0,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0, 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, 0,0,1,1,1,1,0,0,1,1,0,0,0,0,1,1, 0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1, 0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,
+ 0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0, 0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,1,1,1,0,0,1,0, 0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0, 0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,1,0,0,1,1,1,0,0, 0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0,
+ 0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,1, 0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1, 0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,1, 0,0,0,0,1,1,1,1,0,0,1,1,0,0,1,1, 0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0, 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0, 0,1,0,0,0,1,0,0,0,1,1,1,0,1,1,1
+ };
+
+ const uint8_t g_bc7_partition3[64 * 16] =
+ {
+ 0,0,1,1,0,0,1,1,0,2,2,1,2,2,2,2, 0,0,0,1,0,0,1,1,2,2,1,1,2,2,2,1, 0,0,0,0,2,0,0,1,2,2,1,1,2,2,1,1, 0,2,2,2,0,0,2,2,0,0,1,1,0,1,1,1, 0,0,0,0,0,0,0,0,1,1,2,2,1,1,2,2, 0,0,1,1,0,0,1,1,0,0,2,2,0,0,2,2, 0,0,2,2,0,0,2,2,1,1,1,1,1,1,1,1, 0,0,1,1,0,0,1,1,2,2,1,1,2,2,1,1,
+ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2, 0,0,1,2,0,0,1,2,0,0,1,2,0,0,1,2, 0,1,1,2,0,1,1,2,0,1,1,2,0,1,1,2, 0,1,2,2,0,1,2,2,0,1,2,2,0,1,2,2, 0,0,1,1,0,1,1,2,1,1,2,2,1,2,2,2, 0,0,1,1,2,0,0,1,2,2,0,0,2,2,2,0,
+ 0,0,0,1,0,0,1,1,0,1,1,2,1,1,2,2, 0,1,1,1,0,0,1,1,2,0,0,1,2,2,0,0, 0,0,0,0,1,1,2,2,1,1,2,2,1,1,2,2, 0,0,2,2,0,0,2,2,0,0,2,2,1,1,1,1, 0,1,1,1,0,1,1,1,0,2,2,2,0,2,2,2, 0,0,0,1,0,0,0,1,2,2,2,1,2,2,2,1, 0,0,0,0,0,0,1,1,0,1,2,2,0,1,2,2, 0,0,0,0,1,1,0,0,2,2,1,0,2,2,1,0,
+ 0,1,2,2,0,1,2,2,0,0,1,1,0,0,0,0, 0,0,1,2,0,0,1,2,1,1,2,2,2,2,2,2, 0,1,1,0,1,2,2,1,1,2,2,1,0,1,1,0, 0,0,0,0,0,1,1,0,1,2,2,1,1,2,2,1, 0,0,2,2,1,1,0,2,1,1,0,2,0,0,2,2, 0,1,1,0,0,1,1,0,2,0,0,2,2,2,2,2, 0,0,1,1,0,1,2,2,0,1,2,2,0,0,1,1, 0,0,0,0,2,0,0,0,2,2,1,1,2,2,2,1,
+ 0,0,0,0,0,0,0,2,1,1,2,2,1,2,2,2, 0,2,2,2,0,0,2,2,0,0,1,2,0,0,1,1, 0,0,1,1,0,0,1,2,0,0,2,2,0,2,2,2, 0,1,2,0,0,1,2,0,0,1,2,0,0,1,2,0, 0,0,0,0,1,1,1,1,2,2,2,2,0,0,0,0, 0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0, 0,1,2,0,2,0,1,2,1,2,0,1,0,1,2,0, 0,0,1,1,2,2,0,0,1,1,2,2,0,0,1,1,
+ 0,0,1,1,1,1,2,2,2,2,0,0,0,0,1,1, 0,1,0,1,0,1,0,1,2,2,2,2,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,2,1,2,1,2,1, 0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2, 0,0,2,2,0,0,1,1,0,0,2,2,0,0,1,1, 0,2,2,0,1,2,2,1,0,2,2,0,1,2,2,1, 0,1,0,1,2,2,2,2,2,2,2,2,0,1,0,1, 0,0,0,0,2,1,2,1,2,1,2,1,2,1,2,1,
+ 0,1,0,1,0,1,0,1,0,1,0,1,2,2,2,2, 0,2,2,2,0,1,1,1,0,2,2,2,0,1,1,1, 0,0,0,2,1,1,1,2,0,0,0,2,1,1,1,2, 0,0,0,0,2,1,1,2,2,1,1,2,2,1,1,2, 0,2,2,2,0,1,1,1,0,1,1,1,0,2,2,2, 0,0,0,2,1,1,1,2,1,1,1,2,0,0,0,2, 0,1,1,0,0,1,1,0,0,1,1,0,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,1,2,2,1,1,2,
+ 0,1,1,0,0,1,1,0,2,2,2,2,2,2,2,2, 0,0,2,2,0,0,1,1,0,0,1,1,0,0,2,2, 0,0,2,2,1,1,2,2,1,1,2,2,0,0,2,2, 0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,2, 0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,1, 0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2, 0,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2, 0,1,1,1,2,0,1,1,2,2,0,1,2,2,2,0,
+ };
+
+ const uint8_t g_bc7_table_anchor_index_second_subset[64] = { 15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15, 15, 2, 8, 2, 2, 8, 8,15, 2, 8, 2, 2, 8, 8, 2, 2, 15,15, 6, 8, 2, 8,15,15, 2, 8, 2, 2, 2,15,15, 6, 6, 2, 6, 8,15,15, 2, 2, 15,15,15,15,15, 2, 2,15 };
+
+ const uint8_t g_bc7_table_anchor_index_third_subset_1[64] =
+ {
+ 3, 3,15,15, 8, 3,15,15, 8, 8, 6, 6, 6, 5, 3, 3, 3, 3, 8,15, 3, 3, 6,10, 5, 8, 8, 6, 8, 5,15,15, 8,15, 3, 5, 6,10, 8,15, 15, 3,15, 5,15,15,15,15, 3,15, 5, 5, 5, 8, 5,10, 5,10, 8,13,15,12, 3, 3
+ };
+
+ const uint8_t g_bc7_table_anchor_index_third_subset_2[64] =
+ {
+ 15, 8, 8, 3,15,15, 3, 8, 15,15,15,15,15,15,15, 8, 15, 8,15, 3,15, 8,15, 8, 3,15, 6,10,15,15,10, 8, 15, 3,15,10,10, 8, 9,10, 6,15, 8,15, 3, 6, 6, 8, 15, 3,15,15,15,15,15,15, 15,15,15,15, 3,15,15, 8
+ };
+
+ const uint8_t g_bc7_num_subsets[8] = { 3, 2, 3, 2, 1, 1, 1, 2 };
+ const uint8_t g_bc7_partition_bits[8] = { 4, 6, 6, 6, 0, 0, 0, 6 };
+ const uint8_t g_bc7_color_index_bitcount[8] = { 3, 3, 2, 2, 2, 2, 4, 2 };
+
+ const uint8_t g_bc7_mode_has_p_bits[8] = { 1, 1, 0, 1, 0, 0, 1, 1 };
+ const uint8_t g_bc7_mode_has_shared_p_bits[8] = { 0, 1, 0, 0, 0, 0, 0, 0 };
+ const uint8_t g_bc7_color_precision_table[8] = { 4, 6, 5, 7, 5, 7, 7, 5 };
+ const int8_t g_bc7_alpha_precision_table[8] = { 0, 0, 0, 0, 6, 8, 7, 5 };
+
+ const uint8_t g_bc7_alpha_index_bitcount[8] = { 0, 0, 0, 0, 3, 2, 4, 2 };
+
+ endpoint_err g_bc7_mode_6_optimal_endpoints[256][2]; // [c][pbit]
+ endpoint_err g_bc7_mode_5_optimal_endpoints[256]; // [c]
+
+ static inline void bc7_set_block_bits(uint8_t* pBytes, uint32_t val, uint32_t num_bits, uint32_t* pCur_ofs)
+ {
+ assert((num_bits <= 32) && (val < (1ULL << num_bits)));
+ while (num_bits)
{
-#if !BASISD_SUPPORT_PVRTC1
- return false;
-#endif
- uint32_t slice_index_to_decode = slice_index;
- // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
- if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
- slice_index_to_decode++;
+ const uint32_t n = basisu::minimumu(8 - (*pCur_ofs & 7), num_bits);
+ pBytes[*pCur_ofs >> 3] |= (uint8_t)(val << (*pCur_ofs & 7));
+ val >>= n;
+ num_bits -= n;
+ *pCur_ofs += n;
+ }
+ assert(*pCur_ofs <= 128);
+ }
- // output_row_pitch_in_blocks_or_pixels is actually ignored because we're transcoding to PVRTC1. (Print a dev warning if it's != 0?)
- status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGB, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ // TODO: Optimize this.
+ void encode_bc7_block(void* pBlock, const bc7_optimization_results* pResults)
+ {
+ const uint32_t best_mode = pResults->m_mode;
+
+ const uint32_t total_subsets = g_bc7_num_subsets[best_mode];
+ const uint32_t total_partitions = 1 << g_bc7_partition_bits[best_mode];
+ //const uint32_t num_rotations = 1 << g_bc7_rotation_bits[best_mode];
+ //const uint32_t num_index_selectors = (best_mode == 4) ? 2 : 1;
+
+ const uint8_t* pPartition;
+ if (total_subsets == 1)
+ pPartition = &g_bc7_partition1[0];
+ else if (total_subsets == 2)
+ pPartition = &g_bc7_partition2[pResults->m_partition * 16];
+ else
+ pPartition = &g_bc7_partition3[pResults->m_partition * 16];
+
+ uint8_t color_selectors[16];
+ memcpy(color_selectors, pResults->m_selectors, 16);
+
+ uint8_t alpha_selectors[16];
+ memcpy(alpha_selectors, pResults->m_alpha_selectors, 16);
+
+ color_quad_u8 low[3], high[3];
+ memcpy(low, pResults->m_low, sizeof(low));
+ memcpy(high, pResults->m_high, sizeof(high));
+
+ uint32_t pbits[3][2];
+ memcpy(pbits, pResults->m_pbits, sizeof(pbits));
+
+ int anchor[3] = { -1, -1, -1 };
+
+ for (uint32_t k = 0; k < total_subsets; k++)
+ {
+ uint32_t anchor_index = 0;
+ if (k)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to PVRTC1 4 RGB failed\n");
+ if ((total_subsets == 3) && (k == 1))
+ anchor_index = g_bc7_table_anchor_index_third_subset_1[pResults->m_partition];
+ else if ((total_subsets == 3) && (k == 2))
+ anchor_index = g_bc7_table_anchor_index_third_subset_2[pResults->m_partition];
+ else
+ anchor_index = g_bc7_table_anchor_index_second_subset[pResults->m_partition];
+ }
+
+ anchor[k] = anchor_index;
+
+ const uint32_t color_index_bits = get_bc7_color_index_size(best_mode, pResults->m_index_selector);
+ const uint32_t num_color_indices = 1 << color_index_bits;
+
+ if (color_selectors[anchor_index] & (num_color_indices >> 1))
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ if (pPartition[i] == k)
+ color_selectors[i] = (uint8_t)((num_color_indices - 1) - color_selectors[i]);
+
+ if (get_bc7_mode_has_seperate_alpha_selectors(best_mode))
+ {
+ for (uint32_t q = 0; q < 3; q++)
+ {
+ uint8_t t = low[k].m_c[q];
+ low[k].m_c[q] = high[k].m_c[q];
+ high[k].m_c[q] = t;
+ }
+ }
+ else
+ {
+ color_quad_u8 tmp = low[k];
+ low[k] = high[k];
+ high[k] = tmp;
+ }
+
+ if (!g_bc7_mode_has_shared_p_bits[best_mode])
+ {
+ uint32_t t = pbits[k][0];
+ pbits[k][0] = pbits[k][1];
+ pbits[k][1] = t;
+ }
+ }
+
+ if (get_bc7_mode_has_seperate_alpha_selectors(best_mode))
+ {
+ const uint32_t alpha_index_bits = get_bc7_alpha_index_size(best_mode, pResults->m_index_selector);
+ const uint32_t num_alpha_indices = 1 << alpha_index_bits;
+
+ if (alpha_selectors[anchor_index] & (num_alpha_indices >> 1))
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ if (pPartition[i] == k)
+ alpha_selectors[i] = (uint8_t)((num_alpha_indices - 1) - alpha_selectors[i]);
+
+ uint8_t t = low[k].m_c[3];
+ low[k].m_c[3] = high[k].m_c[3];
+ high[k].m_c[3] = t;
+ }
}
- break;
}
- case transcoder_texture_format::cTFPVRTC1_4_RGBA:
+
+ uint8_t* pBlock_bytes = (uint8_t*)(pBlock);
+ memset(pBlock_bytes, 0, BC7ENC_BLOCK_SIZE);
+
+ uint32_t cur_bit_ofs = 0;
+ bc7_set_block_bits(pBlock_bytes, 1 << best_mode, best_mode + 1, &cur_bit_ofs);
+
+ if ((best_mode == 4) || (best_mode == 5))
+ bc7_set_block_bits(pBlock_bytes, pResults->m_rotation, 2, &cur_bit_ofs);
+
+ if (best_mode == 4)
+ bc7_set_block_bits(pBlock_bytes, pResults->m_index_selector, 1, &cur_bit_ofs);
+
+ if (total_partitions > 1)
+ bc7_set_block_bits(pBlock_bytes, pResults->m_partition, (total_partitions == 64) ? 6 : 4, &cur_bit_ofs);
+
+ const uint32_t total_comps = (best_mode >= 4) ? 4 : 3;
+ for (uint32_t comp = 0; comp < total_comps; comp++)
{
-#if !BASISD_SUPPORT_PVRTC1
- return false;
-#endif
- assert(basis_file_has_alpha_slices);
+ for (uint32_t subset = 0; subset < total_subsets; subset++)
+ {
+ bc7_set_block_bits(pBlock_bytes, low[subset].m_c[comp], (comp == 3) ? g_bc7_alpha_precision_table[best_mode] : g_bc7_color_precision_table[best_mode], &cur_bit_ofs);
+ bc7_set_block_bits(pBlock_bytes, high[subset].m_c[comp], (comp == 3) ? g_bc7_alpha_precision_table[best_mode] : g_bc7_color_precision_table[best_mode], &cur_bit_ofs);
+ }
+ }
- // Temp buffer to hold alpha block endpoint/selector indices
- std::vector<uint32_t> temp_block_indices(total_slice_blocks);
+ if (g_bc7_mode_has_p_bits[best_mode])
+ {
+ for (uint32_t subset = 0; subset < total_subsets; subset++)
+ {
+ bc7_set_block_bits(pBlock_bytes, pbits[subset][0], 1, &cur_bit_ofs);
+ if (!g_bc7_mode_has_shared_p_bits[best_mode])
+ bc7_set_block_bits(pBlock_bytes, pbits[subset][1], 1, &cur_bit_ofs);
+ }
+ }
- // First transcode alpha data to temp buffer
- status = transcode_slice(pData, data_size, slice_index + 1, &temp_block_indices[0], total_slice_blocks, block_format::cIndices, sizeof(uint32_t), decode_flags, pSlice_descs[slice_index].m_num_blocks_x, pState);
- if (!status)
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to PVRTC1 4 RGBA failed (0)\n");
+ int idx = x + y * 4;
+
+ uint32_t n = pResults->m_index_selector ? get_bc7_alpha_index_size(best_mode, pResults->m_index_selector) : get_bc7_color_index_size(best_mode, pResults->m_index_selector);
+
+ if ((idx == anchor[0]) || (idx == anchor[1]) || (idx == anchor[2]))
+ n--;
+
+ bc7_set_block_bits(pBlock_bytes, pResults->m_index_selector ? alpha_selectors[idx] : color_selectors[idx], n, &cur_bit_ofs);
}
- else
+ }
+
+ if (get_bc7_mode_has_seperate_alpha_selectors(best_mode))
+ {
+ for (uint32_t y = 0; y < 4; y++)
{
- // output_row_pitch_in_blocks_or_pixels is actually ignored because we're transcoding to PVRTC1. (Print a dev warning if it's != 0?)
- status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGBA, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState, &temp_block_indices[0]);
- if (!status)
+ for (uint32_t x = 0; x < 4; x++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to PVRTC1 4 RGBA failed (1)\n");
+ int idx = x + y * 4;
+
+ uint32_t n = pResults->m_index_selector ? get_bc7_color_index_size(best_mode, pResults->m_index_selector) : get_bc7_alpha_index_size(best_mode, pResults->m_index_selector);
+
+ if ((idx == anchor[0]) || (idx == anchor[1]) || (idx == anchor[2]))
+ n--;
+
+ bc7_set_block_bits(pBlock_bytes, pResults->m_index_selector ? color_selectors[idx] : alpha_selectors[idx], n, &cur_bit_ofs);
}
}
+ }
- break;
+ assert(cur_bit_ofs == 128);
+ }
+
+ // ASTC
+ static inline void astc_set_bits_1_to_9(uint32_t* pDst, int& bit_offset, uint32_t code, uint32_t codesize)
+ {
+ uint8_t* pBuf = reinterpret_cast<uint8_t*>(pDst);
+
+ assert(codesize <= 9);
+ if (codesize)
+ {
+ uint32_t byte_bit_offset = bit_offset & 7;
+ uint32_t val = code << byte_bit_offset;
+
+ uint32_t index = bit_offset >> 3;
+ pBuf[index] |= (uint8_t)val;
+
+ if (codesize > (8 - byte_bit_offset))
+ pBuf[index + 1] |= (uint8_t)(val >> 8);
+
+ bit_offset += codesize;
}
- case transcoder_texture_format::cTFBC7_M6_RGB:
+ }
+
+ void pack_astc_solid_block(void* pDst_block, const color32& color)
+ {
+ uint32_t r = color[0], g = color[1], b = color[2];
+ uint32_t a = color[3];
+
+ uint32_t* pOutput = static_cast<uint32_t*>(pDst_block);
+ uint8_t* pBytes = reinterpret_cast<uint8_t*>(pDst_block);
+
+ pBytes[0] = 0xfc; pBytes[1] = 0xfd; pBytes[2] = 0xff; pBytes[3] = 0xff;
+
+ pOutput[1] = 0xffffffff;
+ pOutput[2] = 0;
+ pOutput[3] = 0;
+
+ int bit_pos = 64;
+ astc_set_bits(reinterpret_cast<uint32_t*>(pDst_block), bit_pos, r | (r << 8), 16);
+ astc_set_bits(reinterpret_cast<uint32_t*>(pDst_block), bit_pos, g | (g << 8), 16);
+ astc_set_bits(reinterpret_cast<uint32_t*>(pDst_block), bit_pos, b | (b << 8), 16);
+ astc_set_bits(reinterpret_cast<uint32_t*>(pDst_block), bit_pos, a | (a << 8), 16);
+ }
+
+ // See 23.21 https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.inline.html#_partition_pattern_generation
+#ifdef _DEBUG
+ static inline uint32_t astc_hash52(uint32_t v)
+ {
+ uint32_t p = v;
+ p ^= p >> 15; p -= p << 17; p += p << 7; p += p << 4;
+ p ^= p >> 5; p += p << 16; p ^= p >> 7; p ^= p >> 3;
+ p ^= p << 6; p ^= p >> 17;
+ return p;
+ }
+
+ int astc_compute_texel_partition(int seed, int x, int y, int z, int partitioncount, bool small_block)
+ {
+ if (small_block)
+ {
+ x <<= 1; y <<= 1; z <<= 1;
+ }
+ seed += (partitioncount - 1) * 1024;
+ uint32_t rnum = astc_hash52(seed);
+ uint8_t seed1 = rnum & 0xF;
+ uint8_t seed2 = (rnum >> 4) & 0xF;
+ uint8_t seed3 = (rnum >> 8) & 0xF;
+ uint8_t seed4 = (rnum >> 12) & 0xF;
+ uint8_t seed5 = (rnum >> 16) & 0xF;
+ uint8_t seed6 = (rnum >> 20) & 0xF;
+ uint8_t seed7 = (rnum >> 24) & 0xF;
+ uint8_t seed8 = (rnum >> 28) & 0xF;
+ uint8_t seed9 = (rnum >> 18) & 0xF;
+ uint8_t seed10 = (rnum >> 22) & 0xF;
+ uint8_t seed11 = (rnum >> 26) & 0xF;
+ uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF;
+
+ seed1 *= seed1; seed2 *= seed2;
+ seed3 *= seed3; seed4 *= seed4;
+ seed5 *= seed5; seed6 *= seed6;
+ seed7 *= seed7; seed8 *= seed8;
+ seed9 *= seed9; seed10 *= seed10;
+ seed11 *= seed11; seed12 *= seed12;
+
+ int sh1, sh2, sh3;
+ if (seed & 1)
+ {
+ sh1 = (seed & 2 ? 4 : 5); sh2 = (partitioncount == 3 ? 6 : 5);
+ }
+ else
{
-#if !BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY
- return false;
+ sh1 = (partitioncount == 3 ? 6 : 5); sh2 = (seed & 2 ? 4 : 5);
+ }
+ sh3 = (seed & 0x10) ? sh1 : sh2;
+
+ seed1 >>= sh1; seed2 >>= sh2; seed3 >>= sh1; seed4 >>= sh2;
+ seed5 >>= sh1; seed6 >>= sh2; seed7 >>= sh1; seed8 >>= sh2;
+ seed9 >>= sh3; seed10 >>= sh3; seed11 >>= sh3; seed12 >>= sh3;
+
+ int a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
+ int b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
+ int c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
+ int d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);
+
+ a &= 0x3F; b &= 0x3F; c &= 0x3F; d &= 0x3F;
+
+ if (partitioncount < 4) d = 0;
+ if (partitioncount < 3) c = 0;
+
+ if (a >= b && a >= c && a >= d)
+ return 0;
+ else if (b >= c && b >= d)
+ return 1;
+ else if (c >= d)
+ return 2;
+ else
+ return 3;
+ }
#endif
- uint32_t slice_index_to_decode = slice_index;
- // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
- if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
- slice_index_to_decode++;
- status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC7_M6_OPAQUE_ONLY, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ static const uint8_t g_astc_quint_encode[125] =
+ {
+ 0, 1, 2, 3, 4, 8, 9, 10, 11, 12, 16, 17, 18, 19, 20, 24, 25, 26, 27, 28, 5, 13, 21, 29, 6, 32, 33, 34, 35, 36, 40, 41, 42, 43, 44, 48, 49, 50, 51, 52, 56, 57,
+ 58, 59, 60, 37, 45, 53, 61, 14, 64, 65, 66, 67, 68, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 88, 89, 90, 91, 92, 69, 77, 85, 93, 22, 96, 97, 98, 99, 100, 104,
+ 105, 106, 107, 108, 112, 113, 114, 115, 116, 120, 121, 122, 123, 124, 101, 109, 117, 125, 30, 102, 103, 70, 71, 38, 110, 111, 78, 79, 46, 118, 119, 86, 87, 54,
+ 126, 127, 94, 95, 62, 39, 47, 55, 63, 31
+ };
+
+ // Encodes 3 values to output, usable for any range that uses quints and bits
+ static inline void astc_encode_quints(uint32_t* pOutput, const uint8_t* pValues, int& bit_pos, int n)
+ {
+ // First extract the trits and the bits from the 5 input values
+ int quints = 0, bits[3];
+ const uint32_t bit_mask = (1 << n) - 1;
+ for (int i = 0; i < 3; i++)
+ {
+ static const int s_muls[3] = { 1, 5, 25 };
+
+ const int t = pValues[i] >> n;
+
+ quints += t * s_muls[i];
+ bits[i] = pValues[i] & bit_mask;
+ }
+
+ // Encode the quints, by inverting the bit manipulations done by the decoder, converting 3 quints into 7-bits.
+ // See https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-integer-sequence-encoding
+
+ assert(quints < 125);
+ const int T = g_astc_quint_encode[quints];
+
+ // Now interleave the 7 encoded quint bits with the bits to form the encoded output. See table 95-96.
+ astc_set_bits(pOutput, bit_pos, bits[0] | (astc_extract_bits(T, 0, 2) << n) | (bits[1] << (3 + n)) | (astc_extract_bits(T, 3, 4) << (3 + n * 2)) |
+ (bits[2] << (5 + n * 2)) | (astc_extract_bits(T, 5, 6) << (5 + n * 3)), 7 + n * 3);
+ }
+
+ // Packs values using ASTC's BISE to output buffer.
+ static void astc_pack_bise(uint32_t* pDst, const uint8_t* pSrc_vals, int bit_pos, int num_vals, int range)
+ {
+ uint32_t temp[5] = { 0, 0, 0, 0, 0 };
+
+ const int num_bits = g_astc_bise_range_table[range][0];
+
+ int group_size = 0;
+ if (g_astc_bise_range_table[range][1])
+ group_size = 5;
+ else if (g_astc_bise_range_table[range][2])
+ group_size = 3;
+
+ if (group_size)
+ {
+ // Range has trits or quints - pack each group of 5 or 3 values
+ const int total_groups = (group_size == 5) ? ((num_vals + 4) / 5) : ((num_vals + 2) / 3);
+
+ for (int group_index = 0; group_index < total_groups; group_index++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to BC7 m6 opaque only failed\n");
+ uint8_t vals[5] = { 0, 0, 0, 0, 0 };
+
+ const int limit = basisu::minimum(group_size, num_vals - group_index * group_size);
+ for (int i = 0; i < limit; i++)
+ vals[i] = pSrc_vals[group_index * group_size + i];
+
+ if (group_size == 5)
+ astc_encode_trits(temp, vals, bit_pos, num_bits);
+ else
+ astc_encode_quints(temp, vals, bit_pos, num_bits);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < num_vals; i++)
+ astc_set_bits_1_to_9(temp, bit_pos, pSrc_vals[i], num_bits);
+ }
+
+ pDst[0] |= temp[0]; pDst[1] |= temp[1];
+ pDst[2] |= temp[2]; pDst[3] |= temp[3];
+ }
+
+ const uint32_t ASTC_BLOCK_MODE_BITS = 11;
+ const uint32_t ASTC_PART_BITS = 2;
+ const uint32_t ASTC_CEM_BITS = 4;
+ const uint32_t ASTC_PARTITION_INDEX_BITS = 10;
+ const uint32_t ASTC_CCS_BITS = 2;
+
+ const uint32_t g_uastc_mode_astc_block_mode[TOTAL_UASTC_MODES] = { 0x242, 0x42, 0x53, 0x42, 0x42, 0x53, 0x442, 0x42, 0, 0x42, 0x242, 0x442, 0x53, 0x441, 0x42, 0x242, 0x42, 0x442, 0x253 };
+
+ bool pack_astc_block(uint32_t* pDst, const astc_block_desc* pBlock, uint32_t uastc_mode)
+ {
+ assert(uastc_mode < TOTAL_UASTC_MODES);
+ uint8_t* pDst_bytes = reinterpret_cast<uint8_t*>(pDst);
+
+ const int total_weights = pBlock->m_dual_plane ? 32 : 16;
+
+ // Set mode bits - see Table 146-147
+ uint32_t mode = g_uastc_mode_astc_block_mode[uastc_mode];
+ pDst_bytes[0] = (uint8_t)mode;
+ pDst_bytes[1] = (uint8_t)(mode >> 8);
+
+ memset(pDst_bytes + 2, 0, 16 - 2);
+
+ int bit_pos = ASTC_BLOCK_MODE_BITS;
+
+ // We only support 1-5 bit weight indices
+ assert(!g_astc_bise_range_table[pBlock->m_weight_range][1] && !g_astc_bise_range_table[pBlock->m_weight_range][2]);
+ const int bits_per_weight = g_astc_bise_range_table[pBlock->m_weight_range][0];
+
+ // See table 143 - PART
+ astc_set_bits_1_to_9(pDst, bit_pos, pBlock->m_subsets - 1, ASTC_PART_BITS);
+
+ if (pBlock->m_subsets == 1)
+ astc_set_bits_1_to_9(pDst, bit_pos, pBlock->m_cem, ASTC_CEM_BITS);
+ else
+ {
+ // See table 145
+ astc_set_bits(pDst, bit_pos, pBlock->m_partition_seed, ASTC_PARTITION_INDEX_BITS);
+
+ // Table 150 - we assume all CEM's are equal, so write 2 0's along with the CEM
+ astc_set_bits_1_to_9(pDst, bit_pos, (pBlock->m_cem << 2) & 63, ASTC_CEM_BITS + 2);
+ }
+
+ if (pBlock->m_dual_plane)
+ {
+ const int total_weight_bits = total_weights * bits_per_weight;
+
+ // See Illegal Encodings 23.24
+ // https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.inline.html#_illegal_encodings
+ assert((total_weight_bits >= 24) && (total_weight_bits <= 96));
+
+ int ccs_bit_pos = 128 - total_weight_bits - ASTC_CCS_BITS;
+ astc_set_bits_1_to_9(pDst, ccs_bit_pos, pBlock->m_ccs, ASTC_CCS_BITS);
+ }
+
+ const int num_cem_pairs = (1 + (pBlock->m_cem >> 2)) * pBlock->m_subsets;
+ assert(num_cem_pairs <= 9);
+
+ astc_pack_bise(pDst, pBlock->m_endpoints, bit_pos, num_cem_pairs * 2, g_uastc_mode_endpoint_ranges[uastc_mode]);
+
+ // Write the weight bits in reverse bit order.
+ switch (bits_per_weight)
+ {
+ case 1:
+ {
+ const uint32_t N = 1;
+ for (int i = 0; i < total_weights; i++)
+ {
+ const uint32_t ofs = 128 - N - i;
+ assert((ofs >> 3) < 16);
+ pDst_bytes[ofs >> 3] |= (pBlock->m_weights[i] << (ofs & 7));
}
break;
}
- case transcoder_texture_format::cTFBC7_M5_RGBA:
+ case 2:
{
-#if !BASISD_SUPPORT_BC7_MODE5
- return false;
-#else
- assert(bytes_per_block == 16);
+ const uint32_t N = 2;
+ for (int i = 0; i < total_weights; i++)
+ {
+ static const uint8_t s_reverse_bits2[4] = { 0, 2, 1, 3 };
+ const uint32_t ofs = 128 - N - (i * N);
+ assert((ofs >> 3) < 16);
+ pDst_bytes[ofs >> 3] |= (s_reverse_bits2[pBlock->m_weights[i]] << (ofs & 7));
+ }
+ break;
+ }
+ case 3:
+ {
+ const uint32_t N = 3;
+ for (int i = 0; i < total_weights; i++)
+ {
+ static const uint8_t s_reverse_bits3[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
- // First transcode the color slice. The cBC7_M5_COLOR transcoder will output opaque mode 5 blocks.
- status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC7_M5_COLOR, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ const uint32_t ofs = 128 - N - (i * N);
+ const uint32_t rev = s_reverse_bits3[pBlock->m_weights[i]] << (ofs & 7);
- if ((status) && (basis_file_has_alpha_slices))
+ uint32_t index = ofs >> 3;
+ assert(index < 16);
+ pDst_bytes[index++] |= rev & 0xFF;
+ if (index < 16)
+ pDst_bytes[index++] |= (rev >> 8);
+ }
+ break;
+ }
+ case 4:
+ {
+ const uint32_t N = 4;
+ for (int i = 0; i < total_weights; i++)
{
- // Now transcode the alpha slice. The cBC7_M5_ALPHA transcoder will now change the opaque mode 5 blocks to blocks with alpha.
- status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC7_M5_ALPHA, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ static const uint8_t s_reverse_bits4[16] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
+ const int ofs = 128 - N - (i * N);
+ assert(ofs >= 0 && (ofs >> 3) < 16);
+ pDst_bytes[ofs >> 3] |= (s_reverse_bits4[pBlock->m_weights[i]] << (ofs & 7));
+ }
+ break;
+ }
+ case 5:
+ {
+ const uint32_t N = 5;
+ for (int i = 0; i < total_weights; i++)
+ {
+ static const uint8_t s_reverse_bits5[32] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 };
+
+ const uint32_t ofs = 128 - N - (i * N);
+ const uint32_t rev = s_reverse_bits5[pBlock->m_weights[i]] << (ofs & 7);
+
+ uint32_t index = ofs >> 3;
+ assert(index < 16);
+ pDst_bytes[index++] |= rev & 0xFF;
+ if (index < 16)
+ pDst_bytes[index++] |= (rev >> 8);
}
break;
-#endif
}
- case transcoder_texture_format::cTFETC2_RGBA:
+ default:
+ assert(0);
+ break;
+ }
+
+ return true;
+ }
+
+ const uint8_t* get_anchor_indices(uint32_t subsets, uint32_t mode, uint32_t common_pattern, const uint8_t*& pPartition_pattern)
+ {
+ const uint8_t* pSubset_anchor_indices = g_zero_pattern;
+ pPartition_pattern = g_zero_pattern;
+
+ if (subsets >= 2)
{
-#if !BASISD_SUPPORT_ETC2_EAC_A8
- return false;
+ if (subsets == 3)
+ {
+ pPartition_pattern = &g_astc_bc7_patterns3[common_pattern][0];
+ pSubset_anchor_indices = &g_astc_bc7_pattern3_anchors[common_pattern][0];
+ }
+ else if (mode == 7)
+ {
+ pPartition_pattern = &g_bc7_3_astc2_patterns2[common_pattern][0];
+ pSubset_anchor_indices = &g_bc7_3_astc2_patterns2_anchors[common_pattern][0];
+ }
+ else
+ {
+ pPartition_pattern = &g_astc_bc7_patterns2[common_pattern][0];
+ pSubset_anchor_indices = &g_astc_bc7_pattern2_anchors[common_pattern][0];
+ }
+ }
+
+ return pSubset_anchor_indices;
+ }
+
+ static inline uint32_t read_bit(const uint8_t* pBuf, uint32_t& bit_offset)
+ {
+ uint32_t byte_bits = pBuf[bit_offset >> 3] >> (bit_offset & 7);
+ bit_offset += 1;
+ return byte_bits & 1;
+ }
+
+ static inline uint32_t read_bits1_to_9(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)
+ {
+ assert(codesize <= 9);
+ if (!codesize)
+ return 0;
+
+ if ((BASISD_IS_BIG_ENDIAN) || (!BASISD_USE_UNALIGNED_WORD_READS) || (bit_offset >= 112))
+ {
+ const uint8_t* pBytes = &pBuf[bit_offset >> 3U];
+
+ uint32_t byte_bit_offset = bit_offset & 7U;
+
+ uint32_t bits = pBytes[0] >> byte_bit_offset;
+ uint32_t bits_read = basisu::minimum<int>(codesize, 8 - byte_bit_offset);
+
+ uint32_t bits_remaining = codesize - bits_read;
+ if (bits_remaining)
+ bits |= ((uint32_t)pBytes[1]) << bits_read;
+
+ bit_offset += codesize;
+
+ return bits & ((1U << codesize) - 1U);
+ }
+
+ uint32_t byte_bit_offset = bit_offset & 7U;
+ const uint16_t w = *(const uint16_t *)(&pBuf[bit_offset >> 3U]);
+ bit_offset += codesize;
+ return (w >> byte_bit_offset) & ((1U << codesize) - 1U);
+ }
+
+ inline uint64_t read_bits64(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)
+ {
+ assert(codesize <= 64U);
+ uint64_t bits = 0;
+ uint32_t total_bits = 0;
+
+ while (total_bits < codesize)
+ {
+ uint32_t byte_bit_offset = bit_offset & 7U;
+ uint32_t bits_to_read = basisu::minimum<int>(codesize - total_bits, 8U - byte_bit_offset);
+
+ uint32_t byte_bits = pBuf[bit_offset >> 3U] >> byte_bit_offset;
+ byte_bits &= ((1U << bits_to_read) - 1U);
+
+ bits |= ((uint64_t)(byte_bits) << total_bits);
+
+ total_bits += bits_to_read;
+ bit_offset += bits_to_read;
+ }
+
+ return bits;
+ }
+
+ static inline uint32_t read_bits1_to_9_fst(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)
+ {
+ assert(codesize <= 9);
+ if (!codesize)
+ return 0;
+ assert(bit_offset < 112);
+
+ if ((BASISD_IS_BIG_ENDIAN) || (!BASISD_USE_UNALIGNED_WORD_READS))
+ {
+ const uint8_t* pBytes = &pBuf[bit_offset >> 3U];
+
+ uint32_t byte_bit_offset = bit_offset & 7U;
+
+ uint32_t bits = pBytes[0] >> byte_bit_offset;
+ uint32_t bits_read = basisu::minimum<int>(codesize, 8 - byte_bit_offset);
+
+ uint32_t bits_remaining = codesize - bits_read;
+ if (bits_remaining)
+ bits |= ((uint32_t)pBytes[1]) << bits_read;
+
+ bit_offset += codesize;
+
+ return bits & ((1U << codesize) - 1U);
+ }
+
+ uint32_t byte_bit_offset = bit_offset & 7U;
+ const uint16_t w = *(const uint16_t*)(&pBuf[bit_offset >> 3U]);
+ bit_offset += codesize;
+ return (w >> byte_bit_offset)& ((1U << codesize) - 1U);
+ }
+
+ bool unpack_uastc(const uastc_block& blk, unpacked_uastc_block& unpacked, bool blue_contract_check, bool read_hints)
+ {
+ //memset(&unpacked, 0, sizeof(unpacked));
+
+#if 0
+ uint8_t table[128];
+ memset(table, 0xFF, sizeof(table));
+
+ {
+ for (uint32_t mode = 0; mode <= TOTAL_UASTC_MODES; mode++)
+ {
+ const uint32_t code = g_uastc_mode_huff_codes[mode][0];
+ const uint32_t codesize = g_uastc_mode_huff_codes[mode][1];
+
+ table[code] = mode;
+
+ uint32_t bits_left = 7 - codesize;
+ for (uint32_t i = 0; i < (1 << bits_left); i++)
+ table[code | (i << codesize)] = mode;
+ }
+
+ for (uint32_t i = 0; i < 128; i++)
+ printf("%u,", table[i]);
+ exit(0);
+ }
#endif
- assert(bytes_per_block == 16);
- if (basis_file_has_alpha_slices)
+ const int mode = g_uastc_huff_modes[blk.m_bytes[0] & 127];
+ if (mode >= (int)TOTAL_UASTC_MODES)
+ return false;
+
+ unpacked.m_mode = mode;
+
+ uint32_t bit_ofs = g_uastc_mode_huff_codes[mode][1];
+
+ if (mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ unpacked.m_solid_color.r = (uint8_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 8);
+ unpacked.m_solid_color.g = (uint8_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 8);
+ unpacked.m_solid_color.b = (uint8_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 8);
+ unpacked.m_solid_color.a = (uint8_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 8);
+
+ if (read_hints)
{
- // First decode the alpha data
- status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_A8, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ unpacked.m_etc1_flip = false;
+ unpacked.m_etc1_diff = read_bit(blk.m_bytes, bit_ofs) != 0;
+ unpacked.m_etc1_inten0 = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 3);
+ unpacked.m_etc1_inten1 = 0;
+ unpacked.m_etc1_selector = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 2);
+ unpacked.m_etc1_r = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 5);
+ unpacked.m_etc1_g = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 5);
+ unpacked.m_etc1_b = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 5);
+ unpacked.m_etc1_bias = 0;
+ unpacked.m_etc2_hints = 0;
}
+
+ return true;
+ }
+
+ if (read_hints)
+ {
+ if (g_uastc_mode_has_bc1_hint0[mode])
+ unpacked.m_bc1_hint0 = read_bit(blk.m_bytes, bit_ofs) != 0;
+ else
+ unpacked.m_bc1_hint0 = false;
+
+ if (g_uastc_mode_has_bc1_hint1[mode])
+ unpacked.m_bc1_hint1 = read_bit(blk.m_bytes, bit_ofs) != 0;
else
+ unpacked.m_bc1_hint1 = false;
+
+ unpacked.m_etc1_flip = read_bit(blk.m_bytes, bit_ofs) != 0;
+ unpacked.m_etc1_diff = read_bit(blk.m_bytes, bit_ofs) != 0;
+ unpacked.m_etc1_inten0 = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 3);
+ unpacked.m_etc1_inten1 = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 3);
+
+ if (g_uastc_mode_has_etc1_bias[mode])
+ unpacked.m_etc1_bias = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 5);
+ else
+ unpacked.m_etc1_bias = 0;
+
+ if (g_uastc_mode_has_alpha[mode])
{
- write_opaque_alpha_blocks(pSlice_descs[slice_index].m_num_blocks_x, pSlice_descs[slice_index].m_num_blocks_y, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_A8, 16, output_row_pitch_in_blocks_or_pixels);
- status = true;
+ unpacked.m_etc2_hints = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 8);
+ //assert(unpacked.m_etc2_hints > 0);
}
+ else
+ unpacked.m_etc2_hints = 0;
+ }
+ else
+ bit_ofs += g_uastc_mode_total_hint_bits[mode];
+
+ uint32_t subsets = 1;
+ switch (mode)
+ {
+ case 2:
+ case 4:
+ case 7:
+ case 9:
+ case 16:
+ unpacked.m_common_pattern = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 5);
+ subsets = 2;
+ break;
+ case 3:
+ unpacked.m_common_pattern = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 4);
+ subsets = 3;
+ break;
+ default:
+ break;
+ }
- if (status)
+ uint32_t part_seed = 0;
+ switch (mode)
+ {
+ case 2:
+ case 4:
+ case 9:
+ case 16:
+ if (unpacked.m_common_pattern >= TOTAL_ASTC_BC7_COMMON_PARTITIONS2)
+ return false;
+
+ part_seed = g_astc_bc7_common_partitions2[unpacked.m_common_pattern].m_astc;
+ break;
+ case 3:
+ if (unpacked.m_common_pattern >= TOTAL_ASTC_BC7_COMMON_PARTITIONS3)
+ return false;
+
+ part_seed = g_astc_bc7_common_partitions3[unpacked.m_common_pattern].m_astc;
+ break;
+ case 7:
+ if (unpacked.m_common_pattern >= TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS)
+ return false;
+
+ part_seed = g_bc7_3_astc2_common_partitions[unpacked.m_common_pattern].m_astc2;
+ break;
+ default:
+ break;
+ }
+
+ uint32_t total_planes = 1;
+ switch (mode)
+ {
+ case 6:
+ case 11:
+ case 13:
+ unpacked.m_astc.m_ccs = (int)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 2);
+ total_planes = 2;
+ break;
+ case 17:
+ unpacked.m_astc.m_ccs = 3;
+ total_planes = 2;
+ break;
+ default:
+ break;
+ }
+
+ unpacked.m_astc.m_dual_plane = (total_planes == 2);
+
+ unpacked.m_astc.m_subsets = subsets;
+ unpacked.m_astc.m_partition_seed = part_seed;
+
+ const uint32_t total_comps = g_uastc_mode_comps[mode];
+
+ const uint32_t weight_bits = g_uastc_mode_weight_bits[mode];
+
+ unpacked.m_astc.m_weight_range = g_uastc_mode_weight_ranges[mode];
+
+ const uint32_t total_values = total_comps * 2 * subsets;
+ const uint32_t endpoint_range = g_uastc_mode_endpoint_ranges[mode];
+
+ const uint32_t cem = g_uastc_mode_cem[mode];
+ unpacked.m_astc.m_cem = cem;
+
+ const uint32_t ep_bits = g_astc_bise_range_table[endpoint_range][0];
+ const uint32_t ep_trits = g_astc_bise_range_table[endpoint_range][1];
+ const uint32_t ep_quints = g_astc_bise_range_table[endpoint_range][2];
+
+ uint32_t total_tqs = 0;
+ uint32_t bundle_size = 0, mul = 0;
+ if (ep_trits)
+ {
+ total_tqs = (total_values + 4) / 5;
+ bundle_size = 5;
+ mul = 3;
+ }
+ else if (ep_quints)
+ {
+ total_tqs = (total_values + 2) / 3;
+ bundle_size = 3;
+ mul = 5;
+ }
+
+ uint32_t tq_values[8];
+ for (uint32_t i = 0; i < total_tqs; i++)
+ {
+ uint32_t num_bits = ep_trits ? 8 : 7;
+ if (i == (total_tqs - 1))
{
- // Now decode the color data
- status = transcode_slice(pData, data_size, slice_index, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ uint32_t num_remaining = total_values - (total_tqs - 1) * bundle_size;
+ if (ep_trits)
+ {
+ switch (num_remaining)
+ {
+ case 1: num_bits = 2; break;
+ case 2: num_bits = 4; break;
+ case 3: num_bits = 5; break;
+ case 4: num_bits = 7; break;
+ default: break;
+ }
+ }
+ else if (ep_quints)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to ETC2 RGB failed\n");
+ switch (num_remaining)
+ {
+ case 1: num_bits = 3; break;
+ case 2: num_bits = 5; break;
+ default: break;
+ }
}
}
- else
+
+ tq_values[i] = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, num_bits);
+ } // i
+
+ uint32_t accum = 0;
+ uint32_t accum_remaining = 0;
+ uint32_t next_tq_index = 0;
+
+ for (uint32_t i = 0; i < total_values; i++)
+ {
+ uint32_t value = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, ep_bits);
+
+ if (total_tqs)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to ETC2 A failed\n");
+ if (!accum_remaining)
+ {
+ assert(next_tq_index < total_tqs);
+ accum = tq_values[next_tq_index++];
+ accum_remaining = bundle_size;
+ }
+
+ // TODO: Optimize with tables
+ uint32_t v = accum % mul;
+ accum /= mul;
+ accum_remaining--;
+
+ value |= (v << ep_bits);
}
- break;
+
+ unpacked.m_astc.m_endpoints[i] = (uint8_t)value;
}
- case transcoder_texture_format::cTFBC3_RGBA:
+
+ const uint8_t* pPartition_pattern;
+ const uint8_t* pSubset_anchor_indices = get_anchor_indices(subsets, mode, unpacked.m_common_pattern, pPartition_pattern);
+
+#ifdef _DEBUG
+ for (uint32_t i = 0; i < 16; i++)
+ assert(pPartition_pattern[i] == astc_compute_texel_partition(part_seed, i & 3, i >> 2, 0, subsets, true));
+
+ for (uint32_t subset_index = 0; subset_index < subsets; subset_index++)
{
-#if !BASISD_SUPPORT_DXT1
- return false;
-#endif
-#if !BASISD_SUPPORT_DXT5A
- return false;
+ uint32_t anchor_index = 0;
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ if (pPartition_pattern[i] == subset_index)
+ {
+ anchor_index = i;
+ break;
+ }
+ }
+
+ assert(pSubset_anchor_indices[subset_index] == anchor_index);
+ }
#endif
- assert(bytes_per_block == 16);
- // First decode the alpha data
- if (basis_file_has_alpha_slices)
+#if 0
+ const uint32_t total_planes_shift = total_planes - 1;
+ for (uint32_t i = 0; i < 16 * total_planes; i++)
+ {
+ uint32_t num_bits = weight_bits;
+ for (uint32_t s = 0; s < subsets; s++)
{
- status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ if (pSubset_anchor_indices[s] == (i >> total_planes_shift))
+ {
+ num_bits--;
+ break;
+ }
}
+
+ unpacked.m_astc.m_weights[i] = (uint8_t)read_bits1_to_9(blk.m_bytes, bit_ofs, num_bits);
+ }
+#endif
+
+ if (mode == 18)
+ {
+ // Mode 18 is the only mode with more than 64 weight bits.
+ for (uint32_t i = 0; i < 16; i++)
+ unpacked.m_astc.m_weights[i] = (uint8_t)read_bits1_to_9(blk.m_bytes, bit_ofs, i ? weight_bits : (weight_bits - 1));
+ }
+ else
+ {
+ // All other modes have <= 64 weight bits.
+ uint64_t bits;
+
+ // Read the weight bits
+ if ((BASISD_IS_BIG_ENDIAN) || (!BASISD_USE_UNALIGNED_WORD_READS))
+ bits = read_bits64(blk.m_bytes, bit_ofs, basisu::minimum<int>(64, 128 - (int)bit_ofs));
else
{
- write_opaque_alpha_blocks(pSlice_descs[slice_index].m_num_blocks_x, pSlice_descs[slice_index].m_num_blocks_y, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, output_row_pitch_in_blocks_or_pixels);
- status = true;
+#ifdef __EMSCRIPTEN__
+ bits = blk.m_dwords[2];
+ bits |= (((uint64_t)blk.m_dwords[3]) << 32U);
+#else
+ bits = blk.m_qwords[1];
+#endif
+
+ if (bit_ofs >= 64U)
+ bits >>= (bit_ofs - 64U);
+ else
+ {
+ assert(bit_ofs >= 56U);
+
+ uint32_t bits_needed = 64U - bit_ofs;
+ bits <<= bits_needed;
+ bits |= (blk.m_bytes[7] >> (8U - bits_needed));
+ }
}
+
+ bit_ofs = 0;
- if (status)
+ const uint32_t mask = (1U << weight_bits) - 1U;
+ const uint32_t anchor_mask = (1U << (weight_bits - 1U)) - 1U;
+
+ if (total_planes == 2)
{
- // Now decode the color data. Forbid 3 color blocks, which aren't allowed in BC3.
- status = transcode_slice(pData, data_size, slice_index, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC1, 16, decode_flags | cDecodeFlagsBC1ForbidThreeColorBlocks, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ // Dual plane modes always have a single subset, and the first 2 weights are anchors.
+
+ unpacked.m_astc.m_weights[0] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask);
+ bit_ofs += (weight_bits - 1);
+
+ unpacked.m_astc.m_weights[1] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask);
+ bit_ofs += (weight_bits - 1);
+
+ for (uint32_t i = 2; i < 32; i++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to BC3 RGB failed\n");
+ unpacked.m_astc.m_weights[i] = (uint8_t)((uint32_t)(bits >> bit_ofs) & mask);
+ bit_ofs += weight_bits;
}
}
else
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to BC3 A failed\n");
- }
+ if (subsets == 1)
+ {
+ // Specialize the single subset case.
+ if (weight_bits == 4)
+ {
+ assert(bit_ofs == 0);
+
+ // Specialize the most common case: 4-bit weights.
+ unpacked.m_astc.m_weights[0] = (uint8_t)((uint32_t)(bits) & 7);
+ unpacked.m_astc.m_weights[1] = (uint8_t)((uint32_t)(bits >> 3) & 15);
+ unpacked.m_astc.m_weights[2] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 1)) & 15);
+ unpacked.m_astc.m_weights[3] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 2)) & 15);
+
+ unpacked.m_astc.m_weights[4] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 3)) & 15);
+ unpacked.m_astc.m_weights[5] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 4)) & 15);
+ unpacked.m_astc.m_weights[6] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 5)) & 15);
+ unpacked.m_astc.m_weights[7] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 6)) & 15);
+
+ unpacked.m_astc.m_weights[8] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 7)) & 15);
+ unpacked.m_astc.m_weights[9] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 8)) & 15);
+ unpacked.m_astc.m_weights[10] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 9)) & 15);
+ unpacked.m_astc.m_weights[11] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 10)) & 15);
+
+ unpacked.m_astc.m_weights[12] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 11)) & 15);
+ unpacked.m_astc.m_weights[13] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 12)) & 15);
+ unpacked.m_astc.m_weights[14] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 13)) & 15);
+ unpacked.m_astc.m_weights[15] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 14)) & 15);
+ }
+ else
+ {
+ // First weight is always an anchor.
+ unpacked.m_astc.m_weights[0] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask);
+ bit_ofs += (weight_bits - 1);
- break;
+ for (uint32_t i = 1; i < 16; i++)
+ {
+ unpacked.m_astc.m_weights[i] = (uint8_t)((uint32_t)(bits >> bit_ofs) & mask);
+ bit_ofs += weight_bits;
+ }
+ }
+ }
+ else
+ {
+ const uint32_t a0 = pSubset_anchor_indices[0], a1 = pSubset_anchor_indices[1], a2 = pSubset_anchor_indices[2];
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ if ((i == a0) || (i == a1) || (i == a2))
+ {
+ unpacked.m_astc.m_weights[i] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask);
+ bit_ofs += (weight_bits - 1);
+ }
+ else
+ {
+ unpacked.m_astc.m_weights[i] = (uint8_t)((uint32_t)(bits >> bit_ofs) & mask);
+ bit_ofs += weight_bits;
+ }
+ }
+ }
+ }
}
- case transcoder_texture_format::cTFBC5_RG:
+
+ if ((blue_contract_check) && (total_comps >= 3))
{
-#if !BASISD_SUPPORT_DXT5A
- return false;
-#endif
- assert(bytes_per_block == 16);
+ // We only need to disable ASTC Blue Contraction when we'll be packing to ASTC. The other transcoders don't care.
+ bool invert_subset[3] = { false, false, false };
+ bool any_flag = false;
- // Decode the R data (actually the green channel of the color data slice in the basis file)
- status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (status)
+ for (uint32_t subset_index = 0; subset_index < subsets; subset_index++)
{
- if (basis_file_has_alpha_slices)
+ const int s0 = g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 0]].m_unquant +
+ g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 2]].m_unquant +
+ g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 4]].m_unquant;
+
+ const int s1 = g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 1]].m_unquant +
+ g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 3]].m_unquant +
+ g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 5]].m_unquant;
+
+ if (s1 < s0)
{
- // Decode the G data (actually the green channel of the alpha data slice in the basis file)
- status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ for (uint32_t c = 0; c < total_comps; c++)
+ std::swap(unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + c * 2 + 0], unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + c * 2 + 1]);
+
+ invert_subset[subset_index] = true;
+ any_flag = true;
+ }
+ }
+
+ if (any_flag)
+ {
+ const uint32_t weight_mask = (1 << weight_bits) - 1;
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ uint32_t subset = pPartition_pattern[i];
+
+ if (invert_subset[subset])
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to BC5 1 failed\n");
+ unpacked.m_astc.m_weights[i * total_planes] = (uint8_t)(weight_mask - unpacked.m_astc.m_weights[i * total_planes]);
+
+ if (total_planes == 2)
+ unpacked.m_astc.m_weights[i * total_planes + 1] = (uint8_t)(weight_mask - unpacked.m_astc.m_weights[i * total_planes + 1]);
}
}
+ }
+ }
+
+ return true;
+ }
+
+ static const uint32_t* g_astc_weight_tables[6] = { nullptr, g_bc7_weights1, g_bc7_weights2, g_bc7_weights3, g_astc_weights4, g_astc_weights5 };
+
+ bool unpack_uastc(uint32_t mode, uint32_t common_pattern, const color32& solid_color, const astc_block_desc& astc, color32* pPixels, bool srgb)
+ {
+ if (mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ pPixels[i] = solid_color;
+ return true;
+ }
+
+ color32 endpoints[3][2];
+
+ const uint32_t total_subsets = g_uastc_mode_subsets[mode];
+ const uint32_t total_comps = basisu::minimum<uint32_t>(4U, g_uastc_mode_comps[mode]);
+ const uint32_t endpoint_range = g_uastc_mode_endpoint_ranges[mode];
+ const uint32_t total_planes = g_uastc_mode_planes[mode];
+ const uint32_t weight_bits = g_uastc_mode_weight_bits[mode];
+ const uint32_t weight_levels = 1 << weight_bits;
+
+ for (uint32_t subset_index = 0; subset_index < total_subsets; subset_index++)
+ {
+ if (total_comps == 2)
+ {
+ const uint32_t ll = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + 0 * 2 + 0]].m_unquant;
+ const uint32_t lh = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + 0 * 2 + 1]].m_unquant;
+
+ const uint32_t al = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + 1 * 2 + 0]].m_unquant;
+ const uint32_t ah = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + 1 * 2 + 1]].m_unquant;
+
+ endpoints[subset_index][0].set_noclamp_rgba(ll, ll, ll, al);
+ endpoints[subset_index][1].set_noclamp_rgba(lh, lh, lh, ah);
+ }
+ else
+ {
+ for (uint32_t comp_index = 0; comp_index < total_comps; comp_index++)
+ {
+ endpoints[subset_index][0][comp_index] = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + comp_index * 2 + 0]].m_unquant;
+ endpoints[subset_index][1][comp_index] = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + comp_index * 2 + 1]].m_unquant;
+ }
+ for (uint32_t comp_index = total_comps; comp_index < 4; comp_index++)
+ {
+ endpoints[subset_index][0][comp_index] = 255;
+ endpoints[subset_index][1][comp_index] = 255;
+ }
+ }
+ }
+
+ color32 block_colors[3][32];
+
+ const uint32_t* pWeights = g_astc_weight_tables[weight_bits];
+
+ for (uint32_t subset_index = 0; subset_index < total_subsets; subset_index++)
+ {
+ for (uint32_t l = 0; l < weight_levels; l++)
+ {
+ if (total_comps == 2)
+ {
+ const uint8_t lc = (uint8_t)astc_interpolate(endpoints[subset_index][0][0], endpoints[subset_index][1][0], pWeights[l], srgb);
+ const uint8_t ac = (uint8_t)astc_interpolate(endpoints[subset_index][0][3], endpoints[subset_index][1][3], pWeights[l], srgb);
+
+ block_colors[subset_index][l].set(lc, lc, lc, ac);
+ }
else
{
- write_opaque_alpha_blocks(pSlice_descs[slice_index].m_num_blocks_x, pSlice_descs[slice_index].m_num_blocks_y, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, output_row_pitch_in_blocks_or_pixels);
- status = true;
+ uint32_t comp_index;
+ for (comp_index = 0; comp_index < total_comps; comp_index++)
+ block_colors[subset_index][l][comp_index] = (uint8_t)astc_interpolate(endpoints[subset_index][0][comp_index], endpoints[subset_index][1][comp_index], pWeights[l], srgb);
+
+ for (; comp_index < 4; comp_index++)
+ block_colors[subset_index][l][comp_index] = 255;
}
}
+ }
+
+ const uint8_t* pPartition_pattern = g_zero_pattern;
+
+ if (total_subsets >= 2)
+ {
+ if (total_subsets == 3)
+ pPartition_pattern = &g_astc_bc7_patterns3[common_pattern][0];
+ else if (mode == 7)
+ pPartition_pattern = &g_bc7_3_astc2_patterns2[common_pattern][0];
else
+ pPartition_pattern = &g_astc_bc7_patterns2[common_pattern][0];
+
+#ifdef _DEBUG
+ for (uint32_t i = 0; i < 16; i++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to BC5 channel 0 failed\n");
+ assert(pPartition_pattern[i] == (uint8_t)astc_compute_texel_partition(astc.m_partition_seed, i & 3, i >> 2, 0, total_subsets, true));
}
- break;
+#endif
}
- case transcoder_texture_format::cTFASTC_4x4_RGBA:
+
+ if (total_planes == 1)
{
-#if !BASISD_SUPPORT_ASTC
+ if (total_subsets == 1)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ assert(astc.m_weights[i] < weight_levels);
+ pPixels[i] = block_colors[0][astc.m_weights[i]];
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ assert(astc.m_weights[i] < weight_levels);
+ pPixels[i] = block_colors[pPartition_pattern[i]][astc.m_weights[i]];
+ }
+ }
+ }
+ else
+ {
+ assert(total_subsets == 1);
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const uint32_t subset_index = 0; // pPartition_pattern[i];
+
+ const uint32_t weight_index0 = astc.m_weights[i * 2];
+ const uint32_t weight_index1 = astc.m_weights[i * 2 + 1];
+
+ assert(weight_index0 < weight_levels && weight_index1 < weight_levels);
+
+ color32& c = pPixels[i];
+ for (uint32_t comp = 0; comp < 4; comp++)
+ {
+ if ((int)comp == astc.m_ccs)
+ c[comp] = block_colors[subset_index][weight_index1][comp];
+ else
+ c[comp] = block_colors[subset_index][weight_index0][comp];
+ }
+ }
+ }
+
+ return true;
+ }
+
+ bool unpack_uastc(const unpacked_uastc_block& unpacked_blk, color32* pPixels, bool srgb)
+ {
+ return unpack_uastc(unpacked_blk.m_mode, unpacked_blk.m_common_pattern, unpacked_blk.m_solid_color, unpacked_blk.m_astc, pPixels, srgb);
+ }
+
+ bool unpack_uastc(const uastc_block& blk, color32* pPixels, bool srgb)
+ {
+ unpacked_uastc_block unpacked_blk;
+
+ if (!unpack_uastc(blk, unpacked_blk, false, false))
return false;
-#endif
- assert(bytes_per_block == 16);
- if (basis_file_has_alpha_slices)
+ return unpack_uastc(unpacked_blk, pPixels, srgb);
+ }
+
+ // Determines the best shared pbits to use to encode xl/xh
+ static void determine_shared_pbits(
+ uint32_t total_comps, uint32_t comp_bits, float xl[4], float xh[4],
+ color_quad_u8& bestMinColor, color_quad_u8& bestMaxColor, uint32_t best_pbits[2])
+ {
+ const uint32_t total_bits = comp_bits + 1;
+ assert(total_bits >= 4 && total_bits <= 8);
+
+ const int iscalep = (1 << total_bits) - 1;
+ const float scalep = (float)iscalep;
+
+ float best_err = 1e+9f;
+
+ for (int p = 0; p < 2; p++)
+ {
+ color_quad_u8 xMinColor, xMaxColor;
+ for (uint32_t c = 0; c < 4; c++)
{
- // First decode the alpha data to the output (we're using the output texture as a temp buffer here).
- status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cIndices, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ xMinColor.m_c[c] = (uint8_t)(clampi(((int)((xl[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));
+ xMaxColor.m_c[c] = (uint8_t)(clampi(((int)((xh[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));
+ }
+
+ color_quad_u8 scaledLow, scaledHigh;
+
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ scaledLow.m_c[i] = (xMinColor.m_c[i] << (8 - total_bits));
+ scaledLow.m_c[i] |= (scaledLow.m_c[i] >> total_bits);
+ assert(scaledLow.m_c[i] <= 255);
+
+ scaledHigh.m_c[i] = (xMaxColor.m_c[i] << (8 - total_bits));
+ scaledHigh.m_c[i] |= (scaledHigh.m_c[i] >> total_bits);
+ assert(scaledHigh.m_c[i] <= 255);
+ }
+
+ float err = 0;
+ for (uint32_t i = 0; i < total_comps; i++)
+ err += basisu::squaref((scaledLow.m_c[i] / 255.0f) - xl[i]) + basisu::squaref((scaledHigh.m_c[i] / 255.0f) - xh[i]);
+
+ if (err < best_err)
+ {
+ best_err = err;
+ best_pbits[0] = p;
+ best_pbits[1] = p;
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ bestMinColor.m_c[j] = xMinColor.m_c[j] >> 1;
+ bestMaxColor.m_c[j] = xMaxColor.m_c[j] >> 1;
+ }
+ }
+ }
+ }
+
+ // Determines the best unique pbits to use to encode xl/xh
+ static void determine_unique_pbits(
+ uint32_t total_comps, uint32_t comp_bits, float xl[4], float xh[4],
+ color_quad_u8& bestMinColor, color_quad_u8& bestMaxColor, uint32_t best_pbits[2])
+ {
+ const uint32_t total_bits = comp_bits + 1;
+ const int iscalep = (1 << total_bits) - 1;
+ const float scalep = (float)iscalep;
+
+ float best_err0 = 1e+9f;
+ float best_err1 = 1e+9f;
+
+ for (int p = 0; p < 2; p++)
+ {
+ color_quad_u8 xMinColor, xMaxColor;
+
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ xMinColor.m_c[c] = (uint8_t)(clampi(((int)((xl[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));
+ xMaxColor.m_c[c] = (uint8_t)(clampi(((int)((xh[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));
+ }
+
+ color_quad_u8 scaledLow, scaledHigh;
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ scaledLow.m_c[i] = (xMinColor.m_c[i] << (8 - total_bits));
+ scaledLow.m_c[i] |= (scaledLow.m_c[i] >> total_bits);
+ assert(scaledLow.m_c[i] <= 255);
+
+ scaledHigh.m_c[i] = (xMaxColor.m_c[i] << (8 - total_bits));
+ scaledHigh.m_c[i] |= (scaledHigh.m_c[i] >> total_bits);
+ assert(scaledHigh.m_c[i] <= 255);
+ }
+
+ float err0 = 0, err1 = 0;
+ for (uint32_t i = 0; i < total_comps; i++)
+ {
+ err0 += basisu::squaref(scaledLow.m_c[i] - xl[i] * 255.0f);
+ err1 += basisu::squaref(scaledHigh.m_c[i] - xh[i] * 255.0f);
+ }
+
+ if (err0 < best_err0)
+ {
+ best_err0 = err0;
+ best_pbits[0] = p;
+
+ bestMinColor.m_c[0] = xMinColor.m_c[0] >> 1;
+ bestMinColor.m_c[1] = xMinColor.m_c[1] >> 1;
+ bestMinColor.m_c[2] = xMinColor.m_c[2] >> 1;
+ bestMinColor.m_c[3] = xMinColor.m_c[3] >> 1;
+ }
+
+ if (err1 < best_err1)
+ {
+ best_err1 = err1;
+ best_pbits[1] = p;
+
+ bestMaxColor.m_c[0] = xMaxColor.m_c[0] >> 1;
+ bestMaxColor.m_c[1] = xMaxColor.m_c[1] >> 1;
+ bestMaxColor.m_c[2] = xMaxColor.m_c[2] >> 1;
+ bestMaxColor.m_c[3] = xMaxColor.m_c[3] >> 1;
+ }
+ }
+ }
+
+ bool transcode_uastc_to_astc(const uastc_block& src_blk, void* pDst)
+ {
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, true, false))
+ return false;
+
+ bool success = false;
+ if (unpacked_src_blk.m_mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ pack_astc_solid_block(pDst, unpacked_src_blk.m_solid_color);
+ success = true;
+ }
+ else
+ {
+ success = pack_astc_block(static_cast<uint32_t*>(pDst), &unpacked_src_blk.m_astc, unpacked_src_blk.m_mode);
+ }
+
+ return success;
+ }
+
+ bool transcode_uastc_to_bc7(const unpacked_uastc_block& unpacked_src_blk, bc7_optimization_results& dst_blk)
+ {
+ memset(&dst_blk, 0, sizeof(dst_blk));
+
+ const uint32_t mode = unpacked_src_blk.m_mode;
+
+ const uint32_t endpoint_range = g_uastc_mode_endpoint_ranges[mode];
+ const uint32_t total_comps = g_uastc_mode_comps[mode];
+
+ switch (mode)
+ {
+ case 0:
+ case 5:
+ case 10:
+ case 12:
+ case 14:
+ case 15:
+ case 18:
+ {
+ // MODE 0: DualPlane: 0, WeightRange: 8 (16), Subsets: 1, EndpointRange: 19 (192) - BC7 MODE6 RGB
+ // MODE 5: DualPlane: 0, WeightRange : 5 (8), Subsets : 1, EndpointRange : 20 (256) - BC7 MODE6 RGB
+ // MODE 10 DualPlane: 0, WeightRange: 8 (16), Subsets: 1, EndpointRange: 13 (48) - BC7 MODE6
+ // MODE 12: DualPlane: 0, WeightRange : 5 (8), Subsets : 1, EndpointRange : 19 (192) - BC7 MODE6
+ // MODE 14: DualPlane: 0, WeightRange : 2 (4), Subsets : 1, EndpointRange : 20 (256) - BC7 MODE6
+ // MODE 18: DualPlane: 0, WeightRange : 11 (32), Subsets : 1, CEM : 8, EndpointRange : 11 (32) - BC7 MODE6
+ // MODE 15: DualPlane: 0, WeightRange : 8 (16), Subsets : 1, CEM : 4 (LA Direct), EndpointRange : 20 (256) - BC7 MODE6
+ dst_blk.m_mode = 6;
+
+ float xl[4], xh[4];
+ if (total_comps == 2)
+ {
+ xl[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[0]].m_unquant / 255.0f;
+ xh[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[1]].m_unquant / 255.0f;
+
+ xl[1] = xl[0];
+ xh[1] = xh[0];
+
+ xl[2] = xl[0];
+ xh[2] = xh[0];
+
+ xl[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[2]].m_unquant / 255.0f;
+ xh[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[3]].m_unquant / 255.0f;
+ }
+ else
+ {
+ xl[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[0]].m_unquant / 255.0f;
+ xl[1] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[2]].m_unquant / 255.0f;
+ xl[2] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[4]].m_unquant / 255.0f;
+
+ xh[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[1]].m_unquant / 255.0f;
+ xh[1] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[3]].m_unquant / 255.0f;
+ xh[2] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[5]].m_unquant / 255.0f;
+
+ if (total_comps == 4)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to failed\n");
+ xl[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[6]].m_unquant / 255.0f;
+ xh[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[7]].m_unquant / 255.0f;
}
else
{
- // Now decode the color data and transcode to ASTC. The transcoder function will read the alpha selector data from the output texture as it converts and
- // transcode both the alpha and color data at the same time to ASTC.
- status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cASTC_4x4, 16, decode_flags | cDecodeFlagsOutputHasAlphaIndices, output_row_pitch_in_blocks_or_pixels, pState);
+ xl[3] = 1.0f;
+ xh[3] = 1.0f;
}
}
+
+ uint32_t best_pbits[2];
+ color_quad_u8 bestMinColor, bestMaxColor;
+ determine_unique_pbits((total_comps == 2) ? 4 : total_comps, 7, xl, xh, bestMinColor, bestMaxColor, best_pbits);
+
+ dst_blk.m_low[0] = bestMinColor;
+ dst_blk.m_high[0] = bestMaxColor;
+
+ if (total_comps == 3)
+ {
+ dst_blk.m_low[0].m_c[3] = 127;
+ dst_blk.m_high[0].m_c[3] = 127;
+ }
+
+ dst_blk.m_pbits[0][0] = best_pbits[0];
+ dst_blk.m_pbits[0][1] = best_pbits[1];
+
+ if (mode == 18)
+ {
+ const uint8_t s_bc7_5_to_4[32] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15 };
+ for (uint32_t i = 0; i < 16; i++)
+ dst_blk.m_selectors[i] = s_bc7_5_to_4[unpacked_src_blk.m_astc.m_weights[i]];
+ }
+ else if (mode == 14)
+ {
+ const uint8_t s_bc7_2_to_4[4] = { 0, 5, 10, 15 };
+ for (uint32_t i = 0; i < 16; i++)
+ dst_blk.m_selectors[i] = s_bc7_2_to_4[unpacked_src_blk.m_astc.m_weights[i]];
+ }
+ else if ((mode == 5) || (mode == 12))
+ {
+ const uint8_t s_bc7_3_to_4[8] = { 0, 2, 4, 6, 9, 11, 13, 15 };
+ for (uint32_t i = 0; i < 16; i++)
+ dst_blk.m_selectors[i] = s_bc7_3_to_4[unpacked_src_blk.m_astc.m_weights[i]];
+ }
else
- status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cASTC_4x4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];
+ }
break;
}
- case transcoder_texture_format::cTFATC_RGB:
+ case 1:
{
-#if !BASISD_SUPPORT_ATC
- return false;
-#endif
- uint32_t slice_index_to_decode = slice_index;
- // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
- if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
- slice_index_to_decode++;
+ // DualPlane: 0, WeightRange : 2 (4), Subsets : 1, EndpointRange : 20 (256) - BC7 MODE3
+ // Mode 1 uses endpoint range 20 - no need to use ASTC dequant tables.
+ dst_blk.m_mode = 3;
- status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cATC_RGB, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ float xl[4], xh[4];
+ xl[0] = unpacked_src_blk.m_astc.m_endpoints[0] / 255.0f;
+ xl[1] = unpacked_src_blk.m_astc.m_endpoints[2] / 255.0f;
+ xl[2] = unpacked_src_blk.m_astc.m_endpoints[4] / 255.0f;
+ xl[3] = 1.0f;
+
+ xh[0] = unpacked_src_blk.m_astc.m_endpoints[1] / 255.0f;
+ xh[1] = unpacked_src_blk.m_astc.m_endpoints[3] / 255.0f;
+ xh[2] = unpacked_src_blk.m_astc.m_endpoints[5] / 255.0f;
+ xh[3] = 1.0f;
+
+ uint32_t best_pbits[2];
+ color_quad_u8 bestMinColor, bestMaxColor;
+ memset(&bestMinColor, 0, sizeof(bestMinColor));
+ memset(&bestMaxColor, 0, sizeof(bestMaxColor));
+ determine_unique_pbits(3, 7, xl, xh, bestMinColor, bestMaxColor, best_pbits);
+
+ for (uint32_t i = 0; i < 3; i++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to ATC_RGB failed\n");
+ dst_blk.m_low[0].m_c[i] = bestMinColor.m_c[i];
+ dst_blk.m_high[0].m_c[i] = bestMaxColor.m_c[i];
+ dst_blk.m_low[1].m_c[i] = bestMinColor.m_c[i];
+ dst_blk.m_high[1].m_c[i] = bestMaxColor.m_c[i];
}
+ dst_blk.m_pbits[0][0] = best_pbits[0];
+ dst_blk.m_pbits[0][1] = best_pbits[1];
+ dst_blk.m_pbits[1][0] = best_pbits[0];
+ dst_blk.m_pbits[1][1] = best_pbits[1];
+
+ for (uint32_t i = 0; i < 16; i++)
+ dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];
+
break;
}
- case transcoder_texture_format::cTFATC_RGBA:
+ case 2:
{
-#if !BASISD_SUPPORT_ATC
- return false;
-#endif
-#if !BASISD_SUPPORT_DXT5A
- return false;
-#endif
- assert(bytes_per_block == 16);
+ // 2. DualPlane: 0, WeightRange : 5 (8), Subsets : 2, EndpointRange : 8 (16) - BC7 MODE1
+ dst_blk.m_mode = 1;
+ dst_blk.m_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_bc7;
- // First decode the alpha data
- if (basis_file_has_alpha_slices)
+ const bool invert_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_invert;
+
+ float xl[4], xh[4];
+ xl[3] = 1.0f;
+ xh[3] = 1.0f;
+
+ for (uint32_t subset = 0; subset < 2; subset++)
{
- status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ uint32_t v = unpacked_src_blk.m_astc.m_endpoints[i * 2 + subset * 6];
+ v = (v << 4) | v;
+ xl[i] = v / 255.0f;
+
+ v = unpacked_src_blk.m_astc.m_endpoints[i * 2 + subset * 6 + 1];
+ v = (v << 4) | v;
+ xh[i] = v / 255.0f;
+ }
+
+ uint32_t best_pbits[2] = { 0, 0 };
+ color_quad_u8 bestMinColor, bestMaxColor;
+ memset(&bestMinColor, 0, sizeof(bestMinColor));
+ memset(&bestMaxColor, 0, sizeof(bestMaxColor));
+ determine_shared_pbits(3, 6, xl, xh, bestMinColor, bestMaxColor, best_pbits);
+
+ const uint32_t bc7_subset_index = invert_partition ? (1 - subset) : subset;
+
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ dst_blk.m_low[bc7_subset_index].m_c[i] = bestMinColor.m_c[i];
+ dst_blk.m_high[bc7_subset_index].m_c[i] = bestMaxColor.m_c[i];
+ }
+
+ dst_blk.m_pbits[bc7_subset_index][0] = best_pbits[0];
+ } // subset
+
+ for (uint32_t i = 0; i < 16; i++)
+ dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];
+
+ break;
+ }
+ case 3:
+ {
+ // DualPlane: 0, WeightRange : 2 (4), Subsets : 3, EndpointRange : 7 (12) - BC7 MODE2
+ dst_blk.m_mode = 2;
+ dst_blk.m_partition = g_astc_bc7_common_partitions3[unpacked_src_blk.m_common_pattern].m_bc7;
+
+ const uint32_t perm = g_astc_bc7_common_partitions3[unpacked_src_blk.m_common_pattern].m_astc_to_bc7_perm;
+
+ for (uint32_t subset = 0; subset < 3; subset++)
+ {
+ for (uint32_t comp = 0; comp < 3; comp++)
+ {
+ uint32_t lo = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[comp * 2 + 0 + subset * 6]].m_unquant;
+ uint32_t hi = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[comp * 2 + 1 + subset * 6]].m_unquant;
+
+ // TODO: I think this can be improved by using tables like Basis Universal does with ETC1S conversion.
+ lo = (lo * 31 + 127) / 255;
+ hi = (hi * 31 + 127) / 255;
+
+ const uint32_t bc7_subset_index = g_astc_to_bc7_partition_index_perm_tables[perm][subset];
+
+ dst_blk.m_low[bc7_subset_index].m_c[comp] = (uint8_t)lo;
+ dst_blk.m_high[bc7_subset_index].m_c[comp] = (uint8_t)hi;
+ }
+ }
+
+ for (uint32_t i = 0; i < 16; i++)
+ dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];
+
+ break;
+ }
+ case 4:
+ {
+ // 4. DualPlane: 0, WeightRange: 2 (4), Subsets: 2, EndpointRange: 12 (40) - BC7 MODE3
+ dst_blk.m_mode = 3;
+ dst_blk.m_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_bc7;
+
+ const bool invert_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_invert;
+
+ float xl[4], xh[4];
+ xl[3] = 1.0f;
+ xh[3] = 1.0f;
+
+ for (uint32_t subset = 0; subset < 2; subset++)
+ {
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ xl[i] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[i * 2 + subset * 6]].m_unquant / 255.0f;
+ xh[i] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[i * 2 + subset * 6 + 1]].m_unquant / 255.0f;
+ }
+
+ uint32_t best_pbits[2] = { 0, 0 };
+ color_quad_u8 bestMinColor, bestMaxColor;
+ memset(&bestMinColor, 0, sizeof(bestMinColor));
+ memset(&bestMaxColor, 0, sizeof(bestMaxColor));
+ determine_unique_pbits(3, 7, xl, xh, bestMinColor, bestMaxColor, best_pbits);
+
+ const uint32_t bc7_subset_index = invert_partition ? (1 - subset) : subset;
+
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ dst_blk.m_low[bc7_subset_index].m_c[i] = bestMinColor.m_c[i];
+ dst_blk.m_high[bc7_subset_index].m_c[i] = bestMaxColor.m_c[i];
+ }
+ dst_blk.m_low[bc7_subset_index].m_c[3] = 127;
+ dst_blk.m_high[bc7_subset_index].m_c[3] = 127;
+
+ dst_blk.m_pbits[bc7_subset_index][0] = best_pbits[0];
+ dst_blk.m_pbits[bc7_subset_index][1] = best_pbits[1];
+
+ } // subset
+
+ for (uint32_t i = 0; i < 16; i++)
+ dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];
+
+ break;
+ }
+ case 6:
+ case 11:
+ case 13:
+ case 17:
+ {
+ // MODE 6: DualPlane: 1, WeightRange : 2 (4), Subsets : 1, EndpointRange : 18 (160) - BC7 MODE5 RGB
+ // MODE 11: DualPlane: 1, WeightRange: 2 (4), Subsets: 1, EndpointRange: 13 (48) - BC7 MODE5
+ // MODE 13: DualPlane: 1, WeightRange: 0 (2), Subsets : 1, EndpointRange : 20 (256) - BC7 MODE5
+ // MODE 17: DualPlane: 1, WeightRange: 2 (4), Subsets: 1, CEM: 4 (LA Direct), EndpointRange: 20 (256) - BC7 MODE5
+ dst_blk.m_mode = 5;
+ dst_blk.m_rotation = (unpacked_src_blk.m_astc.m_ccs + 1) & 3;
+
+ if (total_comps == 2)
+ {
+ assert(unpacked_src_blk.m_astc.m_ccs == 3);
+
+ dst_blk.m_low->m_c[0] = (uint8_t)((g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[0]].m_unquant * 127 + 127) / 255);
+ dst_blk.m_high->m_c[0] = (uint8_t)((g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[1]].m_unquant * 127 + 127) / 255);
+
+ dst_blk.m_low->m_c[1] = dst_blk.m_low->m_c[0];
+ dst_blk.m_high->m_c[1] = dst_blk.m_high->m_c[0];
+
+ dst_blk.m_low->m_c[2] = dst_blk.m_low->m_c[0];
+ dst_blk.m_high->m_c[2] = dst_blk.m_high->m_c[0];
+
+ dst_blk.m_low->m_c[3] = (uint8_t)(g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[2]].m_unquant);
+ dst_blk.m_high->m_c[3] = (uint8_t)(g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[3]].m_unquant);
}
else
{
- write_opaque_alpha_blocks(pSlice_descs[slice_index].m_num_blocks_x, pSlice_descs[slice_index].m_num_blocks_y, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, output_row_pitch_in_blocks_or_pixels);
- status = true;
+ for (uint32_t astc_comp = 0; astc_comp < 4; astc_comp++)
+ {
+ uint32_t bc7_comp = astc_comp;
+ // ASTC and BC7 handle dual plane component rotations differently:
+ // ASTC: 2nd plane separately interpolates the CCS channel.
+ // BC7: 2nd plane channel is swapped with alpha, 2nd plane controls alpha interpolation, then we swap alpha with the desired channel.
+ if (astc_comp == (uint32_t)unpacked_src_blk.m_astc.m_ccs)
+ bc7_comp = 3;
+ else if (astc_comp == 3)
+ bc7_comp = unpacked_src_blk.m_astc.m_ccs;
+
+ uint32_t l = 255, h = 255;
+ if (astc_comp < total_comps)
+ {
+ l = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[astc_comp * 2 + 0]].m_unquant;
+ h = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[astc_comp * 2 + 1]].m_unquant;
+ }
+
+ if (bc7_comp < 3)
+ {
+ l = (l * 127 + 127) / 255;
+ h = (h * 127 + 127) / 255;
+ }
+
+ dst_blk.m_low->m_c[bc7_comp] = (uint8_t)l;
+ dst_blk.m_high->m_c[bc7_comp] = (uint8_t)h;
+ }
}
- if (status)
+ if (mode == 13)
{
- status = transcode_slice(pData, data_size, slice_index, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cATC_RGB, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ for (uint32_t i = 0; i < 16; i++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to ATC RGB failed\n");
+ dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i * 2] ? 3 : 0;
+ dst_blk.m_alpha_selectors[i] = unpacked_src_blk.m_astc.m_weights[i * 2 + 1] ? 3 : 0;
}
}
else
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to ATC A failed\n");
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i * 2];
+ dst_blk.m_alpha_selectors[i] = unpacked_src_blk.m_astc.m_weights[i * 2 + 1];
+ }
}
+
break;
}
- case transcoder_texture_format::cTFPVRTC2_4_RGB:
+ case 7:
{
-#if !BASISD_SUPPORT_PVRTC2
- return false;
-#endif
- uint32_t slice_index_to_decode = slice_index;
- // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
- if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
- slice_index_to_decode++;
+ // DualPlane: 0, WeightRange : 2 (4), Subsets : 2, EndpointRange : 12 (40) - BC7 MODE2
+ dst_blk.m_mode = 2;
+ dst_blk.m_partition = g_bc7_3_astc2_common_partitions[unpacked_src_blk.m_common_pattern].m_bc73;
- status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGB, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ const uint32_t common_pattern_k = g_bc7_3_astc2_common_partitions[unpacked_src_blk.m_common_pattern].k;
+
+ for (uint32_t bc7_part = 0; bc7_part < 3; bc7_part++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to cPVRTC2_4_RGB failed\n");
+ const uint32_t astc_part = bc7_convert_partition_index_3_to_2(bc7_part, common_pattern_k);
+
+ for (uint32_t c = 0; c < 3; c++)
+ {
+ dst_blk.m_low[bc7_part].m_c[c] = (g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[c * 2 + 0 + astc_part * 6]].m_unquant * 31 + 127) / 255;
+ dst_blk.m_high[bc7_part].m_c[c] = (g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[c * 2 + 1 + astc_part * 6]].m_unquant * 31 + 127) / 255;
+ }
}
+
+ for (uint32_t i = 0; i < 16; i++)
+ dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];
+
break;
}
- case transcoder_texture_format::cTFPVRTC2_4_RGBA:
+ case UASTC_MODE_INDEX_SOLID_COLOR:
{
-#if !BASISD_SUPPORT_PVRTC2
- return false;
-#endif
- if (basis_file_has_alpha_slices)
+ // Void-Extent: Solid Color RGBA (BC7 MODE5 or MODE6)
+ const color32& solid_color = unpacked_src_blk.m_solid_color;
+
+ uint32_t best_err0 = g_bc7_mode_6_optimal_endpoints[solid_color.r][0].m_error + g_bc7_mode_6_optimal_endpoints[solid_color.g][0].m_error +
+ g_bc7_mode_6_optimal_endpoints[solid_color.b][0].m_error + g_bc7_mode_6_optimal_endpoints[solid_color.a][0].m_error;
+
+ uint32_t best_err1 = g_bc7_mode_6_optimal_endpoints[solid_color.r][1].m_error + g_bc7_mode_6_optimal_endpoints[solid_color.g][1].m_error +
+ g_bc7_mode_6_optimal_endpoints[solid_color.b][1].m_error + g_bc7_mode_6_optimal_endpoints[solid_color.a][1].m_error;
+
+ if (best_err0 > 0 && best_err1 > 0)
{
- // First decode the alpha data to the output (we're using the output texture as a temp buffer here).
- status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cIndices, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ dst_blk.m_mode = 5;
+
+ for (uint32_t c = 0; c < 3; c++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to failed\n");
+ dst_blk.m_low[0].m_c[c] = g_bc7_mode_5_optimal_endpoints[solid_color.c[c]].m_lo;
+ dst_blk.m_high[0].m_c[c] = g_bc7_mode_5_optimal_endpoints[solid_color.c[c]].m_hi;
}
- else
+
+ memset(dst_blk.m_selectors, BC7ENC_MODE_5_OPTIMAL_INDEX, 16);
+
+ dst_blk.m_low[0].m_c[3] = solid_color.c[3];
+ dst_blk.m_high[0].m_c[3] = solid_color.c[3];
+
+ //memset(dst_blk.m_alpha_selectors, 0, 16);
+ }
+ else
+ {
+ dst_blk.m_mode = 6;
+
+ uint32_t best_p = 0;
+ if (best_err1 < best_err0)
+ best_p = 1;
+
+ for (uint32_t c = 0; c < 4; c++)
{
- // Now decode the color data and transcode to PVRTC2 RGBA.
- status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGBA, bytes_per_block, decode_flags | cDecodeFlagsOutputHasAlphaIndices, output_row_pitch_in_blocks_or_pixels, pState);
+ dst_blk.m_low[0].m_c[c] = g_bc7_mode_6_optimal_endpoints[solid_color.c[c]][best_p].m_lo;
+ dst_blk.m_high[0].m_c[c] = g_bc7_mode_6_optimal_endpoints[solid_color.c[c]][best_p].m_hi;
}
+
+ dst_blk.m_pbits[0][0] = best_p;
+ dst_blk.m_pbits[0][1] = best_p;
+ memset(dst_blk.m_selectors, BC7ENC_MODE_6_OPTIMAL_INDEX, 16);
}
- else
- status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGB, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ break;
+ }
+ case 9:
+ case 16:
+ {
+ // 9. DualPlane: 0, WeightRange : 2 (4), Subsets : 2, EndpointRange : 8 (16) - BC7 MODE7
+ // 16. DualPlane: 0, WeightRange: 2 (4), Subsets: 2, CEM: 4 (LA Direct), EndpointRange: 20 (256) - BC7 MODE7
+
+ dst_blk.m_mode = 7;
+ dst_blk.m_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_bc7;
+
+ const bool invert_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_invert;
+
+ for (uint32_t astc_subset = 0; astc_subset < 2; astc_subset++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to cPVRTC2_4_RGBA failed\n");
- }
+ float xl[4], xh[4];
+
+ if (total_comps == 2)
+ {
+ xl[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[0 + astc_subset * 4]].m_unquant / 255.0f;
+ xh[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[1 + astc_subset * 4]].m_unquant / 255.0f;
+
+ xl[1] = xl[0];
+ xh[1] = xh[0];
+
+ xl[2] = xl[0];
+ xh[2] = xh[0];
+
+ xl[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[2 + astc_subset * 4]].m_unquant / 255.0f;
+ xh[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[3 + astc_subset * 4]].m_unquant / 255.0f;
+ }
+ else
+ {
+ xl[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[0 + astc_subset * 8]].m_unquant / 255.0f;
+ xl[1] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[2 + astc_subset * 8]].m_unquant / 255.0f;
+ xl[2] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[4 + astc_subset * 8]].m_unquant / 255.0f;
+ xl[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[6 + astc_subset * 8]].m_unquant / 255.0f;
+
+ xh[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[1 + astc_subset * 8]].m_unquant / 255.0f;
+ xh[1] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[3 + astc_subset * 8]].m_unquant / 255.0f;
+ xh[2] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[5 + astc_subset * 8]].m_unquant / 255.0f;
+ xh[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[7 + astc_subset * 8]].m_unquant / 255.0f;
+ }
+
+ uint32_t best_pbits[2] = { 0, 0 };
+ color_quad_u8 bestMinColor, bestMaxColor;
+ memset(&bestMinColor, 0, sizeof(bestMinColor));
+ memset(&bestMaxColor, 0, sizeof(bestMaxColor));
+ determine_unique_pbits(4, 5, xl, xh, bestMinColor, bestMaxColor, best_pbits);
+
+ const uint32_t bc7_subset_index = invert_partition ? (1 - astc_subset) : astc_subset;
+
+ dst_blk.m_low[bc7_subset_index] = bestMinColor;
+ dst_blk.m_high[bc7_subset_index] = bestMaxColor;
+
+ dst_blk.m_pbits[bc7_subset_index][0] = best_pbits[0];
+ dst_blk.m_pbits[bc7_subset_index][1] = best_pbits[1];
+ } // astc_subset
+
+ for (uint32_t i = 0; i < 16; i++)
+ dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];
break;
}
- case transcoder_texture_format::cTFRGBA32:
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ bool transcode_uastc_to_bc7(const uastc_block& src_blk, bc7_optimization_results& dst_blk)
+ {
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, false, false))
+ return false;
+
+ return transcode_uastc_to_bc7(unpacked_src_blk, dst_blk);
+ }
+
+ bool transcode_uastc_to_bc7(const uastc_block& src_blk, void* pDst)
+ {
+ bc7_optimization_results temp;
+ if (!transcode_uastc_to_bc7(src_blk, temp))
+ return false;
+
+ encode_bc7_block(pDst, &temp);
+ return true;
+ }
+
+ color32 apply_etc1_bias(const color32 &block_color, uint32_t bias, uint32_t limit, uint32_t subblock)
+ {
+ color32 result;
+
+ for (uint32_t c = 0; c < 3; c++)
{
- // Raw 32bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory.
+ static const int s_divs[3] = { 1, 3, 9 };
- // First decode the alpha data
- if (basis_file_has_alpha_slices)
- status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cA32, sizeof(uint32_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);
+ int delta = 0;
+
+ switch (bias)
+ {
+ case 2: delta = subblock ? 0 : ((c == 0) ? -1 : 0); break;
+ case 5: delta = subblock ? 0 : ((c == 1) ? -1 : 0); break;
+ case 6: delta = subblock ? 0 : ((c == 2) ? -1 : 0); break;
+
+ case 7: delta = subblock ? 0 : ((c == 0) ? 1 : 0); break;
+ case 11: delta = subblock ? 0 : ((c == 1) ? 1 : 0); break;
+ case 15: delta = subblock ? 0 : ((c == 2) ? 1 : 0); break;
+
+ case 18: delta = subblock ? ((c == 0) ? -1 : 0) : 0; break;
+ case 19: delta = subblock ? ((c == 1) ? -1 : 0) : 0; break;
+ case 20: delta = subblock ? ((c == 2) ? -1 : 0) : 0; break;
+
+ case 21: delta = subblock ? ((c == 0) ? 1 : 0) : 0; break;
+ case 24: delta = subblock ? ((c == 1) ? 1 : 0) : 0; break;
+ case 8: delta = subblock ? ((c == 2) ? 1 : 0) : 0; break;
+
+ case 10: delta = -2; break;
+
+ case 27: delta = subblock ? 0 : -1; break;
+ case 28: delta = subblock ? -1 : 1; break;
+ case 29: delta = subblock ? 1 : 0; break;
+ case 30: delta = subblock ? -1 : 0; break;
+ case 31: delta = subblock ? 0 : 1; break;
+
+ default:
+ delta = ((bias / s_divs[c]) % 3) - 1;
+ break;
+ }
+
+ int v = block_color[c];
+ if (v == 0)
+ {
+ if (delta == -2)
+ v += 3;
+ else
+ v += delta + 1;
+ }
+ else if (v == (int)limit)
+ {
+ v += (delta - 1);
+ }
else
- status = true;
+ {
+ v += delta;
+ if ((v < 0) || (v > (int)limit))
+ v = (v - delta) - delta;
+ }
- if (status)
+ assert(v >= 0);
+ assert(v <= (int)limit);
+
+ result[c] = (uint8_t)v;
+ }
+
+ return result;
+ }
+
+ static void etc1_determine_selectors(decoder_etc_block& dst_blk, const color32* pSource_pixels, uint32_t first_subblock, uint32_t last_subblock)
+ {
+ static const uint8_t s_tran[4] = { 1, 0, 2, 3 };
+
+ uint16_t l_bitmask = 0;
+ uint16_t h_bitmask = 0;
+
+ for (uint32_t subblock = first_subblock; subblock < last_subblock; subblock++)
+ {
+ color32 block_colors[4];
+ dst_blk.get_block_colors(block_colors, subblock);
+
+ uint32_t block_y[4];
+ for (uint32_t i = 0; i < 4; i++)
+ block_y[i] = block_colors[i][0] * 54 + block_colors[i][1] * 183 + block_colors[i][2] * 19;
+
+ const uint32_t block_y01 = block_y[0] + block_y[1];
+ const uint32_t block_y12 = block_y[1] + block_y[2];
+ const uint32_t block_y23 = block_y[2] + block_y[3];
+
+ // X0 X0 X0 X0 X1 X1 X1 X1 X2 X2 X2 X2 X3 X3 X3 X3
+ // Y0 Y1 Y2 Y3 Y0 Y1 Y2 Y3 Y0 Y1 Y2 Y3 Y0 Y1 Y2 Y3
+
+ if (dst_blk.get_flip_bit())
{
- status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, basis_file_has_alpha_slices ? block_format::cRGB32 : block_format::cRGBA32, sizeof(uint32_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);
- if (!status)
+ uint32_t ofs = subblock * 2;
+
+ for (uint32_t y = 0; y < 2; y++)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to RGBA32 RGB failed\n");
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const color32& c = pSource_pixels[x + (subblock * 2 + y) * 4];
+ const uint32_t l = c[0] * 108 + c[1] * 366 + c[2] * 38;
+
+ uint32_t t = s_tran[(l < block_y01) + (l < block_y12) + (l < block_y23)];
+
+ assert(ofs < 16);
+ l_bitmask |= ((t & 1) << ofs);
+ h_bitmask |= ((t >> 1) << ofs);
+ ofs += 4;
+ }
+
+ ofs = (int)ofs + 1 - 4 * 4;
}
}
else
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to RGBA32 A failed\n");
+ uint32_t ofs = (subblock * 2) * 4;
+ for (uint32_t x = 0; x < 2; x++)
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ const color32& c = pSource_pixels[subblock * 2 + x + y * 4];
+ const uint32_t l = c[0] * 108 + c[1] * 366 + c[2] * 38;
+
+ uint32_t t = s_tran[(l < block_y01) + (l < block_y12) + (l < block_y23)];
+
+ assert(ofs < 16);
+ l_bitmask |= ((t & 1) << ofs);
+ h_bitmask |= ((t >> 1) << ofs);
+ ++ofs;
+ }
+ }
}
+ }
- break;
+ dst_blk.m_bytes[7] = (uint8_t)(l_bitmask);
+ dst_blk.m_bytes[6] = (uint8_t)(l_bitmask >> 8);
+ dst_blk.m_bytes[5] = (uint8_t)(h_bitmask);
+ dst_blk.m_bytes[4] = (uint8_t)(h_bitmask >> 8);
+ }
+
+ static const uint8_t s_etc1_solid_selectors[4][4] = { { 255, 255, 255, 255 }, { 255, 255, 0, 0 }, { 0, 0, 0, 0 }, {0, 0, 255, 255 } };
+
+ struct etc_coord2
+ {
+ uint8_t m_x, m_y;
+ };
+
+ // [flip][subblock][pixel_index]
+ const etc_coord2 g_etc1_pixel_coords[2][2][8] =
+ {
+ {
+ {
+ { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 },
+ { 1, 0 }, { 1, 1 }, { 1, 2 }, { 1, 3 }
+ },
+ {
+ { 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 },
+ { 3, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 }
+ }
+ },
+ {
+ {
+ { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
+ { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }
+ },
+ {
+ { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },
+ { 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 }
+ },
}
- case transcoder_texture_format::cTFRGB565:
- case transcoder_texture_format::cTFBGR565:
+ };
+
+ void transcode_uastc_to_etc1(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst)
+ {
+ decoder_etc_block& dst_blk = *static_cast<decoder_etc_block*>(pDst);
+
+ if (unpacked_src_blk.m_mode == UASTC_MODE_INDEX_SOLID_COLOR)
{
- // Raw 16bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory.
-
- uint32_t slice_index_to_decode = slice_index;
- // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
- if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
- slice_index_to_decode++;
+ dst_blk.m_bytes[3] = (uint8_t)((unpacked_src_blk.m_etc1_diff << 1) | (unpacked_src_blk.m_etc1_inten0 << 5) | (unpacked_src_blk.m_etc1_inten0 << 2));
- status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, (fmt == transcoder_texture_format::cTFRGB565) ? block_format::cRGB565 : block_format::cBGR565, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);
- if (!status)
+ if (unpacked_src_blk.m_etc1_diff)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to RGB565 RGB failed\n");
+ dst_blk.m_bytes[0] = (uint8_t)(unpacked_src_blk.m_etc1_r << 3);
+ dst_blk.m_bytes[1] = (uint8_t)(unpacked_src_blk.m_etc1_g << 3);
+ dst_blk.m_bytes[2] = (uint8_t)(unpacked_src_blk.m_etc1_b << 3);
+ }
+ else
+ {
+ dst_blk.m_bytes[0] = (uint8_t)(unpacked_src_blk.m_etc1_r | (unpacked_src_blk.m_etc1_r << 4));
+ dst_blk.m_bytes[1] = (uint8_t)(unpacked_src_blk.m_etc1_g | (unpacked_src_blk.m_etc1_g << 4));
+ dst_blk.m_bytes[2] = (uint8_t)(unpacked_src_blk.m_etc1_b | (unpacked_src_blk.m_etc1_b << 4));
}
- break;
+ memcpy(dst_blk.m_bytes + 4, &s_etc1_solid_selectors[unpacked_src_blk.m_etc1_selector][0], 4);
+
+ return;
}
- case transcoder_texture_format::cTFRGBA4444:
+
+ const bool flip = unpacked_src_blk.m_etc1_flip != 0;
+ const bool diff = unpacked_src_blk.m_etc1_diff != 0;
+
+ dst_blk.m_bytes[3] = (uint8_t)((int)flip | (diff << 1) | (unpacked_src_blk.m_etc1_inten0 << 5) | (unpacked_src_blk.m_etc1_inten1 << 2));
+
+ const uint32_t limit = diff ? 31 : 15;
+
+ color32 block_colors[2];
+
+ for (uint32_t subset = 0; subset < 2; subset++)
{
- // Raw 16bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory.
+ uint32_t avg_color[3];
+ memset(avg_color, 0, sizeof(avg_color));
- // First decode the alpha data
- if (basis_file_has_alpha_slices)
- status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA4444_ALPHA, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);
+ for (uint32_t j = 0; j < 8; j++)
+ {
+ const etc_coord2& c = g_etc1_pixel_coords[flip][subset][j];
+
+ avg_color[0] += block_pixels[c.m_y][c.m_x].r;
+ avg_color[1] += block_pixels[c.m_y][c.m_x].g;
+ avg_color[2] += block_pixels[c.m_y][c.m_x].b;
+ } // j
+
+ block_colors[subset][0] = (uint8_t)((avg_color[0] * limit + 1020) / (8 * 255));
+ block_colors[subset][1] = (uint8_t)((avg_color[1] * limit + 1020) / (8 * 255));
+ block_colors[subset][2] = (uint8_t)((avg_color[2] * limit + 1020) / (8 * 255));
+ block_colors[subset][3] = 0;
+
+ if (g_uastc_mode_has_etc1_bias[unpacked_src_blk.m_mode])
+ {
+ block_colors[subset] = apply_etc1_bias(block_colors[subset], unpacked_src_blk.m_etc1_bias, limit, subset);
+ }
+
+ } // subset
+
+ if (diff)
+ {
+ int dr = block_colors[1].r - block_colors[0].r;
+ int dg = block_colors[1].g - block_colors[0].g;
+ int db = block_colors[1].b - block_colors[0].b;
+
+ dr = basisu::clamp<int>(dr, cETC1ColorDeltaMin, cETC1ColorDeltaMax);
+ dg = basisu::clamp<int>(dg, cETC1ColorDeltaMin, cETC1ColorDeltaMax);
+ db = basisu::clamp<int>(db, cETC1ColorDeltaMin, cETC1ColorDeltaMax);
+
+ if (dr < 0) dr += 8;
+ if (dg < 0) dg += 8;
+ if (db < 0) db += 8;
+
+ dst_blk.m_bytes[0] = (uint8_t)((block_colors[0].r << 3) | dr);
+ dst_blk.m_bytes[1] = (uint8_t)((block_colors[0].g << 3) | dg);
+ dst_blk.m_bytes[2] = (uint8_t)((block_colors[0].b << 3) | db);
+ }
+ else
+ {
+ dst_blk.m_bytes[0] = (uint8_t)(block_colors[1].r | (block_colors[0].r << 4));
+ dst_blk.m_bytes[1] = (uint8_t)(block_colors[1].g | (block_colors[0].g << 4));
+ dst_blk.m_bytes[2] = (uint8_t)(block_colors[1].b | (block_colors[0].b << 4));
+ }
+
+ etc1_determine_selectors(dst_blk, &block_pixels[0][0], 0, 2);
+ }
+
+ bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst)
+ {
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, false))
+ return false;
+
+ color32 block_pixels[4][4];
+ if (unpacked_src_blk.m_mode != UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ const bool unpack_srgb = false;
+ if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))
+ return false;
+ }
+
+ transcode_uastc_to_etc1(unpacked_src_blk, block_pixels, pDst);
+
+ return true;
+ }
+
+ static inline int gray_distance2(const uint8_t c, int y)
+ {
+ int gray_dist = (int)c - y;
+ return gray_dist * gray_dist;
+ }
+
+ static bool pack_etc1_y_estimate_flipped(const uint8_t* pSrc_pixels,
+ int& upper_avg, int& lower_avg, int& left_avg, int& right_avg)
+ {
+ int sums[2][2];
+
+#define GET_XY(x, y) pSrc_pixels[(x) + ((y) * 4)]
+
+ sums[0][0] = GET_XY(0, 0) + GET_XY(0, 1) + GET_XY(1, 0) + GET_XY(1, 1);
+ sums[1][0] = GET_XY(2, 0) + GET_XY(2, 1) + GET_XY(3, 0) + GET_XY(3, 1);
+ sums[0][1] = GET_XY(0, 2) + GET_XY(0, 3) + GET_XY(1, 2) + GET_XY(1, 3);
+ sums[1][1] = GET_XY(2, 2) + GET_XY(2, 3) + GET_XY(3, 2) + GET_XY(3, 3);
+
+ upper_avg = (sums[0][0] + sums[1][0] + 4) / 8;
+ lower_avg = (sums[0][1] + sums[1][1] + 4) / 8;
+ left_avg = (sums[0][0] + sums[0][1] + 4) / 8;
+ right_avg = (sums[1][0] + sums[1][1] + 4) / 8;
+
+#undef GET_XY
+#define GET_XY(x, y, a) gray_distance2(pSrc_pixels[(x) + ((y) * 4)], a)
+
+ int upper_gray_dist = 0, lower_gray_dist = 0, left_gray_dist = 0, right_gray_dist = 0;
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ for (uint32_t j = 0; j < 2; j++)
+ {
+ upper_gray_dist += GET_XY(i, j, upper_avg);
+ lower_gray_dist += GET_XY(i, 2 + j, lower_avg);
+ left_gray_dist += GET_XY(j, i, left_avg);
+ right_gray_dist += GET_XY(2 + j, i, right_avg);
+ }
+ }
+
+#undef GET_XY
+
+ int upper_lower_sum = upper_gray_dist + lower_gray_dist;
+ int left_right_sum = left_gray_dist + right_gray_dist;
+
+ return upper_lower_sum < left_right_sum;
+ }
+
+ // Base Sel Table
+ // XXXXX XX XXX
+ static const uint16_t g_etc1_y_solid_block_configs[256] =
+ {
+ 0,781,64,161,260,192,33,131,96,320,65,162,261,193,34,291,97,224,66,163,262,194,35,549,98,4,67,653,164,195,523,36,99,5,578,68,165,353,196,37,135,100,324,69,166,354,197,38,295,101,228,70,167,
+ 355,198,39,553,102,8,71,608,168,199,527,40,103,9,582,72,169,357,200,41,139,104,328,73,170,358,201,42,299,105,232,74,171,359,202,43,557,106,12,75,612,172,203,531,44,107,13,586,76,173,361,
+ 204,45,143,108,332,77,174,362,205,46,303,109,236,78,175,363,206,47,561,110,16,79,616,176,207,535,48,111,17,590,80,177,365,208,49,147,112,336,81,178,366,209,50,307,113,240,82,179,367,210,
+ 51,565,114,20,83,620,180,211,539,52,115,21,594,84,181,369,212,53,151,116,340,85,182,370,213,54,311,117,244,86,183,371,214,55,569,118,24,87,624,184,215,543,56,119,25,598,88,185,373,216,57,
+ 155,120,344,89,186,374,217,58,315,121,248,90,187,375,218,59,573,122,28,91,628,188,219,754,60,123,29,602,92,189,377,220,61,159,124,348,93,190,378,221,62,319,125,252,94,191,379,222,63,882,126
+ };
+
+ // individual
+ // table base sel0 sel1 sel2 sel3
+ static const uint16_t g_etc1_y_solid_block_4i_configs[256] =
+ {
+ 0xA000,0xA800,0x540B,0xAA01,0xAA01,0xFE00,0xFF00,0xFF00,0x8,0x5515,0x5509,0x5509,0xAA03,0x5508,0x5508,0x9508,0xA508,0xA908,0xAA08,0x5513,0xAA09,0xAA09,0xAA05,0xFF08,0xFF08,0x10,0x551D,0x5511,0x5511,
+ 0xAA0B,0x5510,0x5510,0x9510,0xA510,0xA910,0xAA10,0x551B,0xAA11,0xAA11,0xAA0D,0xFF10,0xFF10,0x18,0x5525,0x5519,0x5519,0xAA13,0x5518,0x5518,0x9518,0xA518,0xA918,0xAA18,0x5523,0xAA19,0xAA19,0xAA15,
+ 0xFF18,0xFF18,0x20,0x552D,0x5521,0x5521,0xAA1B,0x5520,0x5520,0x9520,0xA520,0xA920,0xAA20,0x552B,0xAA21,0xAA21,0xAA1D,0xFF20,0xFF20,0x28,0x5535,0x5529,0x5529,0xAA23,0x5528,0x5528,0x9528,0xA528,0xA928,
+ 0xAA28,0x5533,0xAA29,0xAA29,0xAA25,0xFF28,0xFF28,0x30,0x553D,0x5531,0x5531,0xAA2B,0x5530,0x5530,0x9530,0xA530,0xA930,0xAA30,0x553B,0xAA31,0xAA31,0xAA2D,0xFF30,0xFF30,0x38,0x5545,0x5539,0x5539,0xAA33,
+ 0x5538,0x5538,0x9538,0xA538,0xA938,0xAA38,0x5543,0xAA39,0xAA39,0xAA35,0xFF38,0xFF38,0x40,0x554D,0x5541,0x5541,0xAA3B,0x5540,0x5540,0x9540,0xA540,0xA940,0xAA40,0x554B,0xAA41,0xAA41,0xAA3D,0xFF40,0xFF40,
+ 0x48,0x5555,0x5549,0x5549,0xAA43,0x5548,0x5548,0x9548,0xA548,0xA948,0xAA48,0x5553,0xAA49,0xAA49,0xAA45,0xFF48,0xFF48,0x50,0x555D,0x5551,0x5551,0xAA4B,0x5550,0x5550,0x9550,0xA550,0xA950,0xAA50,0x555B,
+ 0xAA51,0xAA51,0xAA4D,0xFF50,0xFF50,0x58,0x5565,0x5559,0x5559,0xAA53,0x5558,0x5558,0x9558,0xA558,0xA958,0xAA58,0x5563,0xAA59,0xAA59,0xAA55,0xFF58,0xFF58,0x60,0x556D,0x5561,0x5561,0xAA5B,0x5560,0x5560,
+ 0x9560,0xA560,0xA960,0xAA60,0x556B,0xAA61,0xAA61,0xAA5D,0xFF60,0xFF60,0x68,0x5575,0x5569,0x5569,0xAA63,0x5568,0x5568,0x9568,0xA568,0xA968,0xAA68,0x5573,0xAA69,0xAA69,0xAA65,0xFF68,0xFF68,0x70,0x557D,
+ 0x5571,0x5571,0xAA6B,0x5570,0x5570,0x9570,0xA570,0xA970,0xAA70,0x557B,0xAA71,0xAA71,0xAA6D,0xFF70,0xFF70,0x78,0x78,0x5579,0x5579,0xAA73,0x5578,0x9578,0x2578,0xE6E,0x278
+ };
+
+ static const uint16_t g_etc1_y_solid_block_2i_configs[256] =
+ {
+ 0x416,0x800,0xA00,0x50B,0xA01,0xA01,0xF00,0xF00,0xF00,0x8,0x515,0x509,0x509,0xA03,0x508,0x508,0xF01,0xF01,0xA08,0xA08,0x513,0xA09,0xA09,0xA05,0xF08,0xF08,0x10,0x51D,0x511,0x511,0xA0B,0x510,0x510,0xF09,
+ 0xF09,0xA10,0xA10,0x51B,0xA11,0xA11,0xA0D,0xF10,0xF10,0x18,0x525,0x519,0x519,0xA13,0x518,0x518,0xF11,0xF11,0xA18,0xA18,0x523,0xA19,0xA19,0xA15,0xF18,0xF18,0x20,0x52D,0x521,0x521,0xA1B,0x520,0x520,0xF19,
+ 0xF19,0xA20,0xA20,0x52B,0xA21,0xA21,0xA1D,0xF20,0xF20,0x28,0x535,0x529,0x529,0xA23,0x528,0x528,0xF21,0xF21,0xA28,0xA28,0x533,0xA29,0xA29,0xA25,0xF28,0xF28,0x30,0x53D,0x531,0x531,0xA2B,0x530,0x530,0xF29,
+ 0xF29,0xA30,0xA30,0x53B,0xA31,0xA31,0xA2D,0xF30,0xF30,0x38,0x545,0x539,0x539,0xA33,0x538,0x538,0xF31,0xF31,0xA38,0xA38,0x543,0xA39,0xA39,0xA35,0xF38,0xF38,0x40,0x54D,0x541,0x541,0xA3B,0x540,0x540,0xF39,
+ 0xF39,0xA40,0xA40,0x54B,0xA41,0xA41,0xA3D,0xF40,0xF40,0x48,0x555,0x549,0x549,0xA43,0x548,0x548,0xF41,0xF41,0xA48,0xA48,0x553,0xA49,0xA49,0xA45,0xF48,0xF48,0x50,0x55D,0x551,0x551,0xA4B,0x550,0x550,0xF49,
+ 0xF49,0xA50,0xA50,0x55B,0xA51,0xA51,0xA4D,0xF50,0xF50,0x58,0x565,0x559,0x559,0xA53,0x558,0x558,0xF51,0xF51,0xA58,0xA58,0x563,0xA59,0xA59,0xA55,0xF58,0xF58,0x60,0x56D,0x561,0x561,0xA5B,0x560,0x560,0xF59,
+ 0xF59,0xA60,0xA60,0x56B,0xA61,0xA61,0xA5D,0xF60,0xF60,0x68,0x575,0x569,0x569,0xA63,0x568,0x568,0xF61,0xF61,0xA68,0xA68,0x573,0xA69,0xA69,0xA65,0xF68,0xF68,0x70,0x57D,0x571,0x571,0xA6B,0x570,0x570,0xF69,
+ 0xF69,0xA70,0xA70,0x57B,0xA71,0xA71,0xA6D,0xF70,0xF70,0x78,0x78,0x579,0x579,0xA73,0x578,0x578,0xE6E,0x278
+ };
+
+ static const uint16_t g_etc1_y_solid_block_1i_configs[256] =
+ {
+ 0x0,0x116,0x200,0x200,0x10B,0x201,0x201,0x300,0x300,0x8,0x115,0x109,0x109,0x203,0x108,0x108,0x114,0x301,0x204,0x208,0x208,0x113,0x209,0x209,0x205,0x308,0x10,0x11D,0x111,0x111,0x20B,0x110,0x110,0x11C,0x309,
+ 0x20C,0x210,0x210,0x11B,0x211,0x211,0x20D,0x310,0x18,0x125,0x119,0x119,0x213,0x118,0x118,0x124,0x311,0x214,0x218,0x218,0x123,0x219,0x219,0x215,0x318,0x20,0x12D,0x121,0x121,0x21B,0x120,0x120,0x12C,0x319,0x21C,
+ 0x220,0x220,0x12B,0x221,0x221,0x21D,0x320,0x28,0x135,0x129,0x129,0x223,0x128,0x128,0x134,0x321,0x224,0x228,0x228,0x133,0x229,0x229,0x225,0x328,0x30,0x13D,0x131,0x131,0x22B,0x130,0x130,0x13C,0x329,0x22C,0x230,
+ 0x230,0x13B,0x231,0x231,0x22D,0x330,0x38,0x145,0x139,0x139,0x233,0x138,0x138,0x144,0x331,0x234,0x238,0x238,0x143,0x239,0x239,0x235,0x338,0x40,0x14D,0x141,0x141,0x23B,0x140,0x140,0x14C,0x339,0x23C,0x240,0x240,
+ 0x14B,0x241,0x241,0x23D,0x340,0x48,0x155,0x149,0x149,0x243,0x148,0x148,0x154,0x341,0x244,0x248,0x248,0x153,0x249,0x249,0x245,0x348,0x50,0x15D,0x151,0x151,0x24B,0x150,0x150,0x15C,0x349,0x24C,0x250,0x250,0x15B,
+ 0x251,0x251,0x24D,0x350,0x58,0x165,0x159,0x159,0x253,0x158,0x158,0x164,0x351,0x254,0x258,0x258,0x163,0x259,0x259,0x255,0x358,0x60,0x16D,0x161,0x161,0x25B,0x160,0x160,0x16C,0x359,0x25C,0x260,0x260,0x16B,0x261,
+ 0x261,0x25D,0x360,0x68,0x175,0x169,0x169,0x263,0x168,0x168,0x174,0x361,0x264,0x268,0x268,0x173,0x269,0x269,0x265,0x368,0x70,0x17D,0x171,0x171,0x26B,0x170,0x170,0x17C,0x369,0x26C,0x270,0x270,0x17B,0x271,0x271,
+ 0x26D,0x370,0x78,0x78,0x179,0x179,0x273,0x178,0x178,0x26E,0x278
+ };
+
+ // We don't have any useful hints to accelerate single channel ETC1, so we need to real-time encode from scratch.
+ bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst, uint32_t channel)
+ {
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, false))
+ return false;
+
+#if 0
+ for (uint32_t individ = 0; individ < 2; individ++)
+ {
+ uint32_t overall_error = 0;
+
+ for (uint32_t c = 0; c < 256; c++)
+ {
+ uint32_t best_err = UINT32_MAX;
+ uint32_t best_individ = 0;
+ uint32_t best_base = 0;
+ uint32_t best_sels[4] = { 0,0,0,0 };
+ uint32_t best_table = 0;
+
+ const uint32_t limit = individ ? 16 : 32;
+
+ for (uint32_t table = 0; table < 8; table++)
+ {
+ for (uint32_t base = 0; base < limit; base++)
+ {
+ uint32_t total_e = 0;
+ uint32_t sels[4] = { 0,0,0,0 };
+
+ const uint32_t N = 4;
+ for (uint32_t i = 0; i < basisu::minimum<uint32_t>(N, (256 - c)); i++)
+ {
+ uint32_t best_sel_e = UINT32_MAX;
+ uint32_t best_sel = 0;
+
+ for (uint32_t sel = 0; sel < 4; sel++)
+ {
+ int val = individ ? ((base << 4) | base) : ((base << 3) | (base >> 2));
+ val = clamp255(val + g_etc1_inten_tables[table][sel]);
+
+ int e = iabs(val - clamp255(c + i));
+ if (e < best_sel_e)
+ {
+ best_sel_e = e;
+ best_sel = sel;
+ }
+
+ } // sel
+
+ sels[i] = best_sel;
+ total_e += best_sel_e * best_sel_e;
+
+ } // i
+
+ if (total_e < best_err)
+ {
+ best_err = total_e;
+ best_individ = individ;
+ best_base = base;
+ memcpy(best_sels, sels, sizeof(best_sels));
+ best_table = table;
+ }
+
+ } // base
+ } // table
+
+ //printf("%u: %u,%u,%u,%u,%u,%u,%u,%u\n", c, best_err, best_individ, best_table, best_base, best_sels[0], best_sels[1], best_sels[2], best_sels[3]);
+
+ uint32_t encoded = best_table | (best_base << 3) |
+ (best_sels[0] << 8) |
+ (best_sels[1] << 10) |
+ (best_sels[2] << 12) |
+ (best_sels[3] << 14);
+
+ printf("0x%X,", encoded);
+
+ overall_error += best_err;
+ } // c
+
+ printf("\n");
+ printf("Overall error: %u\n", overall_error);
+
+ } // individ
+
+ exit(0);
+#endif
+
+#if 0
+ for (uint32_t individ = 0; individ < 2; individ++)
+ {
+ uint32_t overall_error = 0;
+
+ for (uint32_t c = 0; c < 256; c++)
+ {
+ uint32_t best_err = UINT32_MAX;
+ uint32_t best_individ = 0;
+ uint32_t best_base = 0;
+ uint32_t best_sels[4] = { 0,0,0,0 };
+ uint32_t best_table = 0;
+
+ const uint32_t limit = individ ? 16 : 32;
+
+ for (uint32_t table = 0; table < 8; table++)
+ {
+ for (uint32_t base = 0; base < limit; base++)
+ {
+ uint32_t total_e = 0;
+ uint32_t sels[4] = { 0,0,0,0 };
+
+ const uint32_t N = 1;
+ for (uint32_t i = 0; i < basisu::minimum<uint32_t>(N, (256 - c)); i++)
+ {
+ uint32_t best_sel_e = UINT32_MAX;
+ uint32_t best_sel = 0;
+
+ for (uint32_t sel = 0; sel < 4; sel++)
+ {
+ int val = individ ? ((base << 4) | base) : ((base << 3) | (base >> 2));
+ val = clamp255(val + g_etc1_inten_tables[table][sel]);
+
+ int e = iabs(val - clamp255(c + i));
+ if (e < best_sel_e)
+ {
+ best_sel_e = e;
+ best_sel = sel;
+ }
+
+ } // sel
+
+ sels[i] = best_sel;
+ total_e += best_sel_e * best_sel_e;
+
+ } // i
+
+ if (total_e < best_err)
+ {
+ best_err = total_e;
+ best_individ = individ;
+ best_base = base;
+ memcpy(best_sels, sels, sizeof(best_sels));
+ best_table = table;
+ }
+
+ } // base
+ } // table
+
+ //printf("%u: %u,%u,%u,%u,%u,%u,%u,%u\n", c, best_err, best_individ, best_table, best_base, best_sels[0], best_sels[1], best_sels[2], best_sels[3]);
+
+ uint32_t encoded = best_table | (best_base << 3) |
+ (best_sels[0] << 8) |
+ (best_sels[1] << 10) |
+ (best_sels[2] << 12) |
+ (best_sels[3] << 14);
+
+ printf("0x%X,", encoded);
+
+ overall_error += best_err;
+ } // c
+
+ printf("\n");
+ printf("Overall error: %u\n", overall_error);
+
+ } // individ
+
+ exit(0);
+#endif
+
+ decoder_etc_block& dst_blk = *static_cast<decoder_etc_block*>(pDst);
+
+ if (unpacked_src_blk.m_mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ const uint32_t y = unpacked_src_blk.m_solid_color[channel];
+ const uint32_t encoded_config = g_etc1_y_solid_block_configs[y];
+
+ const uint32_t base = encoded_config & 31;
+ const uint32_t sel = (encoded_config >> 5) & 3;
+ const uint32_t table = encoded_config >> 7;
+
+ dst_blk.m_bytes[3] = (uint8_t)(2 | (table << 5) | (table << 2));
+
+ dst_blk.m_bytes[0] = (uint8_t)(base << 3);
+ dst_blk.m_bytes[1] = (uint8_t)(base << 3);
+ dst_blk.m_bytes[2] = (uint8_t)(base << 3);
+
+ memcpy(dst_blk.m_bytes + 4, &s_etc1_solid_selectors[sel][0], 4);
+ return true;
+ }
+
+ color32 block_pixels[4][4];
+ const bool unpack_srgb = false;
+ if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))
+ return false;
+
+ uint8_t block_y[4][4];
+ for (uint32_t i = 0; i < 16; i++)
+ ((uint8_t*)block_y)[i] = ((color32*)block_pixels)[i][channel];
+
+ int upper_avg, lower_avg, left_avg, right_avg;
+ bool flip = pack_etc1_y_estimate_flipped(&block_y[0][0], upper_avg, lower_avg, left_avg, right_avg);
+
+ // non-flipped: | |
+ // vs.
+ // flipped: --
+ // --
+
+ uint32_t low[2] = { 255, 255 }, high[2] = { 0, 0 };
+
+ if (flip)
+ {
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t v = block_y[y][x];
+ low[0] = basisu::minimum(low[0], v);
+ high[0] = basisu::maximum(high[0], v);
+ }
+ }
+ for (uint32_t y = 2; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const uint32_t v = block_y[y][x];
+ low[1] = basisu::minimum(low[1], v);
+ high[1] = basisu::maximum(high[1], v);
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 2; x++)
+ {
+ const uint32_t v = block_y[y][x];
+ low[0] = basisu::minimum(low[0], v);
+ high[0] = basisu::maximum(high[0], v);
+ }
+ }
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 2; x < 4; x++)
+ {
+ const uint32_t v = block_y[y][x];
+ low[1] = basisu::minimum(low[1], v);
+ high[1] = basisu::maximum(high[1], v);
+ }
+ }
+ }
+
+ const uint32_t range[2] = { high[0] - low[0], high[1] - low[1] };
+
+ dst_blk.m_bytes[3] = (uint8_t)((int)flip);
+
+ if ((range[0] <= 3) && (range[1] <= 3))
+ {
+ // This is primarily for better gradients.
+ dst_blk.m_bytes[0] = 0;
+ dst_blk.m_bytes[1] = 0;
+ dst_blk.m_bytes[2] = 0;
+
+ uint16_t l_bitmask = 0, h_bitmask = 0;
+
+ for (uint32_t subblock = 0; subblock < 2; subblock++)
+ {
+ const uint32_t encoded = (range[subblock] == 0) ? g_etc1_y_solid_block_1i_configs[low[subblock]] : ((range[subblock] < 2) ? g_etc1_y_solid_block_2i_configs[low[subblock]] : g_etc1_y_solid_block_4i_configs[low[subblock]]);
+
+ const uint32_t table = encoded & 7;
+ const uint32_t base = (encoded >> 3) & 31;
+ assert(base <= 15);
+ const uint32_t sels[4] = { (encoded >> 8) & 3, (encoded >> 10) & 3, (encoded >> 12) & 3, (encoded >> 14) & 3 };
+
+ dst_blk.m_bytes[3] |= (uint8_t)(table << (subblock ? 2 : 5));
+
+ const uint32_t sv = base << (subblock ? 0 : 4);
+ dst_blk.m_bytes[0] |= (uint8_t)(sv);
+ dst_blk.m_bytes[1] |= (uint8_t)(sv);
+ dst_blk.m_bytes[2] |= (uint8_t)(sv);
+
+ if (flip)
+ {
+ uint32_t ofs = subblock * 2;
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ uint32_t t = block_y[y + subblock * 2][x];
+ assert(t >= low[subblock] && t <= high[subblock]);
+ t -= low[subblock];
+ assert(t <= 3);
+
+ t = g_selector_index_to_etc1[sels[t]];
+
+ assert(ofs < 16);
+ l_bitmask |= ((t & 1) << ofs);
+ h_bitmask |= ((t >> 1) << ofs);
+ ofs += 4;
+ }
+
+ ofs = (int)ofs + 1 - 4 * 4;
+ }
+ }
+ else
+ {
+ uint32_t ofs = (subblock * 2) * 4;
+ for (uint32_t x = 0; x < 2; x++)
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ uint32_t t = block_y[y][x + subblock * 2];
+ assert(t >= low[subblock] && t <= high[subblock]);
+ t -= low[subblock];
+ assert(t <= 3);
+
+ t = g_selector_index_to_etc1[sels[t]];
+
+ assert(ofs < 16);
+ l_bitmask |= ((t & 1) << ofs);
+ h_bitmask |= ((t >> 1) << ofs);
+ ++ofs;
+ }
+ }
+ }
+ } // subblock
+
+ dst_blk.m_bytes[7] = (uint8_t)(l_bitmask);
+ dst_blk.m_bytes[6] = (uint8_t)(l_bitmask >> 8);
+ dst_blk.m_bytes[5] = (uint8_t)(h_bitmask);
+ dst_blk.m_bytes[4] = (uint8_t)(h_bitmask >> 8);
+
+ return true;
+ }
+
+ uint32_t y0 = ((flip ? upper_avg : left_avg) * 31 + 127) / 255;
+ uint32_t y1 = ((flip ? lower_avg : right_avg) * 31 + 127) / 255;
+
+ bool diff = true;
+
+ int dy = y1 - y0;
+
+ if ((dy < cETC1ColorDeltaMin) || (dy > cETC1ColorDeltaMax))
+ {
+ diff = false;
+
+ y0 = ((flip ? upper_avg : left_avg) * 15 + 127) / 255;
+ y1 = ((flip ? lower_avg : right_avg) * 15 + 127) / 255;
+
+ dst_blk.m_bytes[0] = (uint8_t)(y1 | (y0 << 4));
+ dst_blk.m_bytes[1] = (uint8_t)(y1 | (y0 << 4));
+ dst_blk.m_bytes[2] = (uint8_t)(y1 | (y0 << 4));
+ }
+ else
+ {
+ dy = basisu::clamp<int>(dy, cETC1ColorDeltaMin, cETC1ColorDeltaMax);
+
+ y1 = y0 + dy;
+
+ if (dy < 0) dy += 8;
+
+ dst_blk.m_bytes[0] = (uint8_t)((y0 << 3) | dy);
+ dst_blk.m_bytes[1] = (uint8_t)((y0 << 3) | dy);
+ dst_blk.m_bytes[2] = (uint8_t)((y0 << 3) | dy);
+
+ dst_blk.m_bytes[3] |= 2;
+ }
+
+ const uint32_t base_y[2] = { diff ? ((y0 << 3) | (y0 >> 2)) : ((y0 << 4) | y0), diff ? ((y1 << 3) | (y1 >> 2)) : ((y1 << 4) | y1) };
+
+ uint32_t enc_range[2];
+ for (uint32_t subset = 0; subset < 2; subset++)
+ {
+ const int pos = basisu::iabs((int)high[subset] - (int)base_y[subset]);
+ const int neg = basisu::iabs((int)base_y[subset] - (int)low[subset]);
+
+ enc_range[subset] = basisu::maximum(pos, neg);
+ }
+
+ uint16_t l_bitmask = 0, h_bitmask = 0;
+ for (uint32_t subblock = 0; subblock < 2; subblock++)
+ {
+ if ((!diff) && (range[subblock] <= 3))
+ {
+ const uint32_t encoded = (range[subblock] == 0) ? g_etc1_y_solid_block_1i_configs[low[subblock]] : ((range[subblock] < 2) ? g_etc1_y_solid_block_2i_configs[low[subblock]] : g_etc1_y_solid_block_4i_configs[low[subblock]]);
+
+ const uint32_t table = encoded & 7;
+ const uint32_t base = (encoded >> 3) & 31;
+ assert(base <= 15);
+ const uint32_t sels[4] = { (encoded >> 8) & 3, (encoded >> 10) & 3, (encoded >> 12) & 3, (encoded >> 14) & 3 };
+
+ dst_blk.m_bytes[3] |= (uint8_t)(table << (subblock ? 2 : 5));
+
+ const uint32_t mask = ~(0xF << (subblock ? 0 : 4));
+
+ dst_blk.m_bytes[0] &= mask;
+ dst_blk.m_bytes[1] &= mask;
+ dst_blk.m_bytes[2] &= mask;
+
+ const uint32_t sv = base << (subblock ? 0 : 4);
+ dst_blk.m_bytes[0] |= (uint8_t)(sv);
+ dst_blk.m_bytes[1] |= (uint8_t)(sv);
+ dst_blk.m_bytes[2] |= (uint8_t)(sv);
+
+ if (flip)
+ {
+ uint32_t ofs = subblock * 2;
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ uint32_t t = block_y[y + subblock * 2][x];
+ assert(t >= low[subblock] && t <= high[subblock]);
+ t -= low[subblock];
+ assert(t <= 3);
+
+ t = g_selector_index_to_etc1[sels[t]];
+
+ assert(ofs < 16);
+ l_bitmask |= ((t & 1) << ofs);
+ h_bitmask |= ((t >> 1) << ofs);
+ ofs += 4;
+ }
+
+ ofs = (int)ofs + 1 - 4 * 4;
+ }
+ }
+ else
+ {
+ uint32_t ofs = (subblock * 2) * 4;
+ for (uint32_t x = 0; x < 2; x++)
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ uint32_t t = block_y[y][x + subblock * 2];
+ assert(t >= low[subblock] && t <= high[subblock]);
+ t -= low[subblock];
+ assert(t <= 3);
+
+ t = g_selector_index_to_etc1[sels[t]];
+
+ assert(ofs < 16);
+ l_bitmask |= ((t & 1) << ofs);
+ h_bitmask |= ((t >> 1) << ofs);
+ ++ofs;
+ }
+ }
+ }
+
+ continue;
+ } // if
+
+ uint32_t best_err = UINT32_MAX;
+ uint8_t best_sels[8];
+ uint32_t best_inten = 0;
+
+ const int base = base_y[subblock];
+
+ const int low_limit = -base;
+ const int high_limit = 255 - base;
+
+ assert(low_limit <= 0 && high_limit >= 0);
+
+ uint32_t inten_table_mask = 0xFF;
+ const uint32_t er = enc_range[subblock];
+ // Each one of these tables is expensive to evaluate, so let's only examine the ones we know may be useful.
+ if (er <= 51)
+ {
+ inten_table_mask = 0xF;
+
+ if (er > 22)
+ inten_table_mask &= ~(1 << 0);
+
+ if ((er < 4) || (er > 39))
+ inten_table_mask &= ~(1 << 1);
+
+ if (er < 9)
+ inten_table_mask &= ~(1 << 2);
+
+ if (er < 12)
+ inten_table_mask &= ~(1 << 3);
+ }
else
- status = true;
+ {
+ inten_table_mask &= ~((1 << 0) | (1 << 1));
- if (status)
+ if (er > 60)
+ inten_table_mask &= ~(1 << 2);
+
+ if (er > 89)
+ inten_table_mask &= ~(1 << 3);
+
+ if (er > 120)
+ inten_table_mask &= ~(1 << 4);
+
+ if (er > 136)
+ inten_table_mask &= ~(1 << 5);
+
+ if (er > 174)
+ inten_table_mask &= ~(1 << 6);
+ }
+
+ for (uint32_t inten = 0; inten < 8; inten++)
{
- status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, basis_file_has_alpha_slices ? block_format::cRGBA4444_COLOR : block_format::cRGBA4444_COLOR_OPAQUE, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);
- if (!status)
+ if ((inten_table_mask & (1 << inten)) == 0)
+ continue;
+
+ const int t0 = basisu::maximum(low_limit, g_etc1_inten_tables[inten][0]);
+ const int t1 = basisu::maximum(low_limit, g_etc1_inten_tables[inten][1]);
+ const int t2 = basisu::minimum(high_limit, g_etc1_inten_tables[inten][2]);
+ const int t3 = basisu::minimum(high_limit, g_etc1_inten_tables[inten][3]);
+ assert((t0 <= t1) && (t1 <= t2) && (t2 <= t3));
+
+ const int tv[4] = { t2, t3, t1, t0 };
+
+ const int thresh01 = t0 + t1;
+ const int thresh12 = t1 + t2;
+ const int thresh23 = t2 + t3;
+
+ assert(thresh01 <= thresh12 && thresh12 <= thresh23);
+
+ static const uint8_t s_table[4] = { 1, 0, 2, 3 };
+
+ uint32_t total_err = 0;
+ uint8_t sels[8];
+
+ if (flip)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to RGBA4444 RGB failed\n");
+ if (((int)high[subblock] - base) * 2 < thresh01)
+ {
+ memset(sels, 3, 8);
+
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const int delta = (int)block_y[y + subblock * 2][x] - base;
+
+ const uint32_t c = 3;
+
+ uint32_t e = basisu::iabs(tv[c] - delta);
+ total_err += e * e;
+ }
+ if (total_err >= best_err)
+ break;
+ }
+ }
+ else if (((int)low[subblock] - base) * 2 >= thresh23)
+ {
+ memset(sels, 1, 8);
+
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const int delta = (int)block_y[y + subblock * 2][x] - base;
+
+ const uint32_t c = 1;
+
+ uint32_t e = basisu::iabs(tv[c] - delta);
+ total_err += e * e;
+ }
+ if (total_err >= best_err)
+ break;
+ }
+ }
+ else
+ {
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ const int delta = (int)block_y[y + subblock * 2][x] - base;
+ const int delta2 = delta * 2;
+
+ uint32_t c = s_table[(delta2 < thresh01) + (delta2 < thresh12) + (delta2 < thresh23)];
+ sels[y * 4 + x] = (uint8_t)c;
+
+ uint32_t e = basisu::iabs(tv[c] - delta);
+ total_err += e * e;
+ }
+ if (total_err >= best_err)
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (((int)high[subblock] - base) * 2 < thresh01)
+ {
+ memset(sels, 3, 8);
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 2; x++)
+ {
+ const int delta = (int)block_y[y][x + subblock * 2] - base;
+
+ const uint32_t c = 3;
+
+ uint32_t e = basisu::iabs(tv[c] - delta);
+ total_err += e * e;
+ }
+ if (total_err >= best_err)
+ break;
+ }
+ }
+ else if (((int)low[subblock] - base) * 2 >= thresh23)
+ {
+ memset(sels, 1, 8);
+
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 2; x++)
+ {
+ const int delta = (int)block_y[y][x + subblock * 2] - base;
+
+ const uint32_t c = 1;
+
+ uint32_t e = basisu::iabs(tv[c] - delta);
+ total_err += e * e;
+ }
+ if (total_err >= best_err)
+ break;
+ }
+ }
+ else
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ for (uint32_t x = 0; x < 2; x++)
+ {
+ const int delta = (int)block_y[y][x + subblock * 2] - base;
+ const int delta2 = delta * 2;
+
+ uint32_t c = s_table[(delta2 < thresh01) + (delta2 < thresh12) + (delta2 < thresh23)];
+ sels[y * 2 + x] = (uint8_t)c;
+
+ uint32_t e = basisu::iabs(tv[c] - delta);
+ total_err += e * e;
+ }
+ if (total_err >= best_err)
+ break;
+ }
+ }
+ }
+
+ if (total_err < best_err)
+ {
+ best_err = total_err;
+ best_inten = inten;
+ memcpy(best_sels, sels, 8);
+ }
+
+ } // inten
+
+ //g_inten_hist[best_inten][enc_range[subblock]]++;
+
+ dst_blk.m_bytes[3] |= (uint8_t)(best_inten << (subblock ? 2 : 5));
+
+ if (flip)
+ {
+ uint32_t ofs = subblock * 2;
+ for (uint32_t y = 0; y < 2; y++)
+ {
+ for (uint32_t x = 0; x < 4; x++)
+ {
+ uint32_t t = best_sels[y * 4 + x];
+
+ assert(ofs < 16);
+ l_bitmask |= ((t & 1) << ofs);
+ h_bitmask |= ((t >> 1) << ofs);
+ ofs += 4;
+ }
+
+ ofs = (int)ofs + 1 - 4 * 4;
}
}
else
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to RGBA4444 A failed\n");
+ uint32_t ofs = (subblock * 2) * 4;
+ for (uint32_t x = 0; x < 2; x++)
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ {
+ uint32_t t = best_sels[y * 2 + x];
+
+ assert(ofs < 16);
+ l_bitmask |= ((t & 1) << ofs);
+ h_bitmask |= ((t >> 1) << ofs);
+ ++ofs;
+ }
+ }
}
- break;
+ } // subblock
+
+ dst_blk.m_bytes[7] = (uint8_t)(l_bitmask);
+ dst_blk.m_bytes[6] = (uint8_t)(l_bitmask >> 8);
+ dst_blk.m_bytes[5] = (uint8_t)(h_bitmask);
+ dst_blk.m_bytes[4] = (uint8_t)(h_bitmask >> 8);
+
+ return true;
+ }
+
+ const uint32_t ETC2_EAC_MIN_VALUE_SELECTOR = 3, ETC2_EAC_MAX_VALUE_SELECTOR = 7;
+
+ void transcode_uastc_to_etc2_eac_a8(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst)
+ {
+ eac_block& dst = *static_cast<eac_block*>(pDst);
+ const color32* pSrc_pixels = &block_pixels[0][0];
+
+ if ((!g_uastc_mode_has_alpha[unpacked_src_blk.m_mode]) || (unpacked_src_blk.m_mode == UASTC_MODE_INDEX_SOLID_COLOR))
+ {
+ const uint32_t a = (unpacked_src_blk.m_mode == UASTC_MODE_INDEX_SOLID_COLOR) ? unpacked_src_blk.m_solid_color[3] : 255;
+
+ dst.m_base = a;
+ dst.m_table = 13;
+ dst.m_multiplier = 1;
+
+ memcpy(dst.m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4));
+
+ return;
}
- case transcoder_texture_format::cTFFXT1_RGB:
+
+ uint32_t min_a = 255, max_a = 0;
+ for (uint32_t i = 0; i < 16; i++)
{
-#if !BASISD_SUPPORT_FXT1
+ min_a = basisu::minimum<uint32_t>(min_a, pSrc_pixels[i].a);
+ max_a = basisu::maximum<uint32_t>(max_a, pSrc_pixels[i].a);
+ }
+
+ if (min_a == max_a)
+ {
+ dst.m_base = min_a;
+ dst.m_table = 13;
+ dst.m_multiplier = 1;
+
+ memcpy(dst.m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4));
+ return;
+ }
+
+ const uint32_t table = unpacked_src_blk.m_etc2_hints & 0xF;
+ const int multiplier = unpacked_src_blk.m_etc2_hints >> 4;
+
+ assert(multiplier >= 1);
+
+ dst.m_multiplier = multiplier;
+ dst.m_table = table;
+
+ const float range = (float)(g_eac_modifier_table[dst.m_table][ETC2_EAC_MAX_VALUE_SELECTOR] - g_eac_modifier_table[dst.m_table][ETC2_EAC_MIN_VALUE_SELECTOR]);
+ const int center = (int)roundf(basisu::lerp((float)min_a, (float)max_a, (float)(0 - g_eac_modifier_table[dst.m_table][ETC2_EAC_MIN_VALUE_SELECTOR]) / range));
+
+ dst.m_base = center;
+
+ const int8_t* pTable = &g_eac_modifier_table[dst.m_table][0];
+
+ uint32_t vals[8];
+ for (uint32_t j = 0; j < 8; j++)
+ vals[j] = clamp255(center + (pTable[j] * multiplier));
+
+ uint64_t sels = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const uint32_t a = block_pixels[i & 3][i >> 2].a;
+
+ const uint32_t err0 = (basisu::iabs(vals[0] - a) << 3) | 0;
+ const uint32_t err1 = (basisu::iabs(vals[1] - a) << 3) | 1;
+ const uint32_t err2 = (basisu::iabs(vals[2] - a) << 3) | 2;
+ const uint32_t err3 = (basisu::iabs(vals[3] - a) << 3) | 3;
+ const uint32_t err4 = (basisu::iabs(vals[4] - a) << 3) | 4;
+ const uint32_t err5 = (basisu::iabs(vals[5] - a) << 3) | 5;
+ const uint32_t err6 = (basisu::iabs(vals[6] - a) << 3) | 6;
+ const uint32_t err7 = (basisu::iabs(vals[7] - a) << 3) | 7;
+
+ const uint32_t min_err = basisu::minimum(basisu::minimum(basisu::minimum(basisu::minimum(basisu::minimum(basisu::minimum(err0, err1, err2), err3), err4), err5), err6), err7);
+
+ const uint64_t best_index = min_err & 7;
+ sels |= (best_index << (45 - i * 3));
+ }
+
+ dst.set_selector_bits(sels);
+ }
+
+ bool transcode_uastc_to_etc2_rgba(const uastc_block& src_blk, void* pDst)
+ {
+ eac_block& dst_etc2_eac_a8_blk = *static_cast<eac_block*>(pDst);
+ decoder_etc_block& dst_etc1_blk = static_cast<decoder_etc_block*>(pDst)[1];
+
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, false))
return false;
-#endif
- uint32_t slice_index_to_decode = slice_index;
- // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
- if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
- slice_index_to_decode++;
- status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cFXT1_RGB, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ color32 block_pixels[4][4];
+ if (unpacked_src_blk.m_mode != UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ const bool unpack_srgb = false;
+ if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))
+ return false;
+ }
+
+ transcode_uastc_to_etc2_eac_a8(unpacked_src_blk, block_pixels, &dst_etc2_eac_a8_blk);
+
+ transcode_uastc_to_etc1(unpacked_src_blk, block_pixels, &dst_etc1_blk);
+
+ return true;
+ }
+
+ static const uint8_t s_uastc5_to_bc1[32] = { 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1 };
+ static const uint8_t s_uastc4_to_bc1[16] = { 0, 0, 0, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 1, 1, 1 };
+ static const uint8_t s_uastc3_to_bc1[8] = { 0, 0, 2, 2, 3, 3, 1, 1 };
+ static const uint8_t s_uastc2_to_bc1[4] = { 0, 2, 3, 1 };
+ static const uint8_t s_uastc1_to_bc1[2] = { 0, 1 };
+ const uint8_t* s_uastc_to_bc1_weights[6] = { nullptr, s_uastc1_to_bc1, s_uastc2_to_bc1, s_uastc3_to_bc1, s_uastc4_to_bc1, s_uastc5_to_bc1 };
+
+ void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride)
+ {
+ uint32_t min0_v, max0_v, min1_v, max1_v,min2_v, max2_v, min3_v, max3_v;
+
+ {
+ min0_v = max0_v = pPixels[0 * stride];
+ min1_v = max1_v = pPixels[1 * stride];
+ min2_v = max2_v = pPixels[2 * stride];
+ min3_v = max3_v = pPixels[3 * stride];
+ }
+
+ {
+ uint32_t v0 = pPixels[4 * stride]; min0_v = basisu::minimum(min0_v, v0); max0_v = basisu::maximum(max0_v, v0);
+ uint32_t v1 = pPixels[5 * stride]; min1_v = basisu::minimum(min1_v, v1); max1_v = basisu::maximum(max1_v, v1);
+ uint32_t v2 = pPixels[6 * stride]; min2_v = basisu::minimum(min2_v, v2); max2_v = basisu::maximum(max2_v, v2);
+ uint32_t v3 = pPixels[7 * stride]; min3_v = basisu::minimum(min3_v, v3); max3_v = basisu::maximum(max3_v, v3);
+ }
+
+ {
+ uint32_t v0 = pPixels[8 * stride]; min0_v = basisu::minimum(min0_v, v0); max0_v = basisu::maximum(max0_v, v0);
+ uint32_t v1 = pPixels[9 * stride]; min1_v = basisu::minimum(min1_v, v1); max1_v = basisu::maximum(max1_v, v1);
+ uint32_t v2 = pPixels[10 * stride]; min2_v = basisu::minimum(min2_v, v2); max2_v = basisu::maximum(max2_v, v2);
+ uint32_t v3 = pPixels[11 * stride]; min3_v = basisu::minimum(min3_v, v3); max3_v = basisu::maximum(max3_v, v3);
+ }
+
+ {
+ uint32_t v0 = pPixels[12 * stride]; min0_v = basisu::minimum(min0_v, v0); max0_v = basisu::maximum(max0_v, v0);
+ uint32_t v1 = pPixels[13 * stride]; min1_v = basisu::minimum(min1_v, v1); max1_v = basisu::maximum(max1_v, v1);
+ uint32_t v2 = pPixels[14 * stride]; min2_v = basisu::minimum(min2_v, v2); max2_v = basisu::maximum(max2_v, v2);
+ uint32_t v3 = pPixels[15 * stride]; min3_v = basisu::minimum(min3_v, v3); max3_v = basisu::maximum(max3_v, v3);
+ }
+
+ const uint32_t min_v = basisu::minimum(min0_v, min1_v, min2_v, min3_v);
+ const uint32_t max_v = basisu::maximum(max0_v, max1_v, max2_v, max3_v);
+
+ uint8_t* pDst_bytes = static_cast<uint8_t*>(pDst);
+ pDst_bytes[0] = (uint8_t)max_v;
+ pDst_bytes[1] = (uint8_t)min_v;
+
+ if (max_v == min_v)
+ {
+ memset(pDst_bytes + 2, 0, 6);
+ return;
+ }
+
+ const uint32_t delta = max_v - min_v;
+
+ // min_v is now 0. Compute thresholds between values by scaling max_v. It's x14 because we're adding two x7 scale factors.
+ const int t0 = delta * 13;
+ const int t1 = delta * 11;
+ const int t2 = delta * 9;
+ const int t3 = delta * 7;
+ const int t4 = delta * 5;
+ const int t5 = delta * 3;
+ const int t6 = delta * 1;
+
+ // BC4 floors in its divisions, which we compensate for with the 4 bias.
+ // This function is optimal for all possible inputs (i.e. it outputs the same results as checking all 8 values and choosing the closest one).
+ const int bias = 4 - min_v * 14;
+
+ static const uint32_t s_tran0[8] = { 1U , 7U , 6U , 5U , 4U , 3U , 2U , 0U };
+ static const uint32_t s_tran1[8] = { 1U << 3U, 7U << 3U, 6U << 3U, 5U << 3U, 4U << 3U, 3U << 3U, 2U << 3U, 0U << 3U };
+ static const uint32_t s_tran2[8] = { 1U << 6U, 7U << 6U, 6U << 6U, 5U << 6U, 4U << 6U, 3U << 6U, 2U << 6U, 0U << 6U };
+ static const uint32_t s_tran3[8] = { 1U << 9U, 7U << 9U, 6U << 9U, 5U << 9U, 4U << 9U, 3U << 9U, 2U << 9U, 0U << 9U };
+
+ uint64_t a0, a1, a2, a3;
+ {
+ const int v0 = pPixels[0 * stride] * 14 + bias;
+ const int v1 = pPixels[1 * stride] * 14 + bias;
+ const int v2 = pPixels[2 * stride] * 14 + bias;
+ const int v3 = pPixels[3 * stride] * 14 + bias;
+ a0 = s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)];
+ a1 = s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)];
+ a2 = s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)];
+ a3 = s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)];
+ }
+
+ {
+ const int v0 = pPixels[4 * stride] * 14 + bias;
+ const int v1 = pPixels[5 * stride] * 14 + bias;
+ const int v2 = pPixels[6 * stride] * 14 + bias;
+ const int v3 = pPixels[7 * stride] * 14 + bias;
+ a0 |= (s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)] << 12U);
+ a1 |= (s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)] << 12U);
+ a2 |= (s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)] << 12U);
+ a3 |= (s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)] << 12U);
+ }
+
+ {
+ const int v0 = pPixels[8 * stride] * 14 + bias;
+ const int v1 = pPixels[9 * stride] * 14 + bias;
+ const int v2 = pPixels[10 * stride] * 14 + bias;
+ const int v3 = pPixels[11 * stride] * 14 + bias;
+ a0 |= (((uint64_t)s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)]) << 24U);
+ a1 |= (((uint64_t)s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)]) << 24U);
+ a2 |= (((uint64_t)s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)]) << 24U);
+ a3 |= (((uint64_t)s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)]) << 24U);
+ }
+
+ {
+ const int v0 = pPixels[12 * stride] * 14 + bias;
+ const int v1 = pPixels[13 * stride] * 14 + bias;
+ const int v2 = pPixels[14 * stride] * 14 + bias;
+ const int v3 = pPixels[15 * stride] * 14 + bias;
+ a0 |= (((uint64_t)s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)]) << 36U);
+ a1 |= (((uint64_t)s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)]) << 36U);
+ a2 |= (((uint64_t)s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)]) << 36U);
+ a3 |= (((uint64_t)s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)]) << 36U);
+ }
+
+ const uint64_t f = a0 | a1 | a2 | a3;
+
+ pDst_bytes[2] = (uint8_t)f;
+ pDst_bytes[3] = (uint8_t)(f >> 8U);
+ pDst_bytes[4] = (uint8_t)(f >> 16U);
+ pDst_bytes[5] = (uint8_t)(f >> 24U);
+ pDst_bytes[6] = (uint8_t)(f >> 32U);
+ pDst_bytes[7] = (uint8_t)(f >> 40U);
+ }
+
+ static void bc1_find_sels(const color32 *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16])
+ {
+ uint32_t block_r[4], block_g[4], block_b[4];
+
+ block_r[0] = (lr << 3) | (lr >> 2); block_g[0] = (lg << 2) | (lg >> 4); block_b[0] = (lb << 3) | (lb >> 2);
+ block_r[3] = (hr << 3) | (hr >> 2); block_g[3] = (hg << 2) | (hg >> 4); block_b[3] = (hb << 3) | (hb >> 2);
+ block_r[1] = (block_r[0] * 2 + block_r[3]) / 3; block_g[1] = (block_g[0] * 2 + block_g[3]) / 3; block_b[1] = (block_b[0] * 2 + block_b[3]) / 3;
+ block_r[2] = (block_r[3] * 2 + block_r[0]) / 3; block_g[2] = (block_g[3] * 2 + block_g[0]) / 3; block_b[2] = (block_b[3] * 2 + block_b[0]) / 3;
+
+ int ar = block_r[3] - block_r[0], ag = block_g[3] - block_g[0], ab = block_b[3] - block_b[0];
+
+ int dots[4];
+ for (uint32_t i = 0; i < 4; i++)
+ dots[i] = (int)block_r[i] * ar + (int)block_g[i] * ag + (int)block_b[i] * ab;
+
+ int t0 = dots[0] + dots[1], t1 = dots[1] + dots[2], t2 = dots[2] + dots[3];
+
+ ar *= 2; ag *= 2; ab *= 2;
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const int d = pSrc_pixels[i].r * ar + pSrc_pixels[i].g * ag + pSrc_pixels[i].b * ab;
+ static const uint8_t s_sels[4] = { 3, 2, 1, 0 };
+
+ // Rounding matters here!
+ // d <= t0: <=, not <, to the later LS step "sees" a wider range of selectors. It matters for quality.
+ sels[i] = s_sels[(d <= t0) + (d < t1) + (d < t2)];
+ }
+ }
+
+ static inline void bc1_find_sels_2(const color32* pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16])
+ {
+ uint32_t block_r[4], block_g[4], block_b[4];
+
+ block_r[0] = (lr << 3) | (lr >> 2); block_g[0] = (lg << 2) | (lg >> 4); block_b[0] = (lb << 3) | (lb >> 2);
+ block_r[3] = (hr << 3) | (hr >> 2); block_g[3] = (hg << 2) | (hg >> 4); block_b[3] = (hb << 3) | (hb >> 2);
+ block_r[1] = (block_r[0] * 2 + block_r[3]) / 3; block_g[1] = (block_g[0] * 2 + block_g[3]) / 3; block_b[1] = (block_b[0] * 2 + block_b[3]) / 3;
+ block_r[2] = (block_r[3] * 2 + block_r[0]) / 3; block_g[2] = (block_g[3] * 2 + block_g[0]) / 3; block_b[2] = (block_b[3] * 2 + block_b[0]) / 3;
+
+ int ar = block_r[3] - block_r[0], ag = block_g[3] - block_g[0], ab = block_b[3] - block_b[0];
+
+ int dots[4];
+ for (uint32_t i = 0; i < 4; i++)
+ dots[i] = (int)block_r[i] * ar + (int)block_g[i] * ag + (int)block_b[i] * ab;
+
+ int t0 = dots[0] + dots[1], t1 = dots[1] + dots[2], t2 = dots[2] + dots[3];
+
+ ar *= 2; ag *= 2; ab *= 2;
+
+ static const uint8_t s_sels[4] = { 3, 2, 1, 0 };
+
+ for (uint32_t i = 0; i < 16; i += 4)
+ {
+ const int d0 = pSrc_pixels[i+0].r * ar + pSrc_pixels[i+0].g * ag + pSrc_pixels[i+0].b * ab;
+ const int d1 = pSrc_pixels[i+1].r * ar + pSrc_pixels[i+1].g * ag + pSrc_pixels[i+1].b * ab;
+ const int d2 = pSrc_pixels[i+2].r * ar + pSrc_pixels[i+2].g * ag + pSrc_pixels[i+2].b * ab;
+ const int d3 = pSrc_pixels[i+3].r * ar + pSrc_pixels[i+3].g * ag + pSrc_pixels[i+3].b * ab;
+
+ sels[i+0] = s_sels[(d0 <= t0) + (d0 < t1) + (d0 < t2)];
+ sels[i+1] = s_sels[(d1 <= t0) + (d1 < t1) + (d1 < t2)];
+ sels[i+2] = s_sels[(d2 <= t0) + (d2 < t1) + (d2 < t2)];
+ sels[i+3] = s_sels[(d3 <= t0) + (d3 < t1) + (d3 < t2)];
+ }
+ }
+
+ struct vec3F { float c[3]; };
+
+ static bool compute_least_squares_endpoints_rgb(const color32* pColors, const uint8_t* pSelectors, vec3F* pXl, vec3F* pXh)
+ {
+ // Derived from bc7enc16's LS function.
+ // Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf
+ // I did this in matrix form first, expanded out all the ops, then optimized it a bit.
+ uint32_t uq00_r = 0, uq10_r = 0, ut_r = 0, uq00_g = 0, uq10_g = 0, ut_g = 0, uq00_b = 0, uq10_b = 0, ut_b = 0;
+
+ // This table is: 9 * (w * w), 9 * ((1.0f - w) * w), 9 * ((1.0f - w) * (1.0f - w))
+ // where w is [0,1/3,2/3,1]. 9 is the perfect multiplier.
+ static const uint32_t s_weight_vals[4] = { 0x000009, 0x010204, 0x040201, 0x090000 };
+
+ uint32_t weight_accum = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const uint32_t r = pColors[i].c[0], g = pColors[i].c[1], b = pColors[i].c[2];
+ const uint32_t sel = pSelectors[i];
+ ut_r += r;
+ ut_g += g;
+ ut_b += b;
+ weight_accum += s_weight_vals[sel];
+ uq00_r += sel * r;
+ uq00_g += sel * g;
+ uq00_b += sel * b;
+ }
+
+ float q00_r = (float)uq00_r, q10_r = (float)uq10_r, t_r = (float)ut_r;
+ float q00_g = (float)uq00_g, q10_g = (float)uq10_g, t_g = (float)ut_g;
+ float q00_b = (float)uq00_b, q10_b = (float)uq10_b, t_b = (float)ut_b;
+
+ q10_r = t_r * 3.0f - q00_r;
+ q10_g = t_g * 3.0f - q00_g;
+ q10_b = t_b * 3.0f - q00_b;
+
+ float z00 = (float)((weight_accum >> 16) & 0xFF);
+ float z10 = (float)((weight_accum >> 8) & 0xFF);
+ float z11 = (float)(weight_accum & 0xFF);
+ float z01 = z10;
+
+ float det = z00 * z11 - z01 * z10;
+ if (fabs(det) < 1e-8f)
+ return false;
+
+ det = 3.0f / det;
+
+ float iz00, iz01, iz10, iz11;
+ iz00 = z11 * det;
+ iz01 = -z01 * det;
+ iz10 = -z10 * det;
+ iz11 = z00 * det;
+
+ pXl->c[0] = iz00 * q00_r + iz01 * q10_r; pXh->c[0] = iz10 * q00_r + iz11 * q10_r;
+ pXl->c[1] = iz00 * q00_g + iz01 * q10_g; pXh->c[1] = iz10 * q00_g + iz11 * q10_g;
+ pXl->c[2] = iz00 * q00_b + iz01 * q10_b; pXh->c[2] = iz10 * q00_b + iz11 * q10_b;
+
+ // Check and fix channel singularities - might not be needed, but is in UASTC's encoder.
+ for (uint32_t c = 0; c < 3; c++)
+ {
+ if ((pXl->c[c] < 0.0f) || (pXh->c[c] > 255.0f))
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to FXT1_RGB failed\n");
+ uint32_t lo_v = UINT32_MAX, hi_v = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ lo_v = basisu::minimumu(lo_v, pColors[i].c[c]);
+ hi_v = basisu::maximumu(hi_v, pColors[i].c[c]);
+ }
+
+ if (lo_v == hi_v)
+ {
+ pXl->c[c] = (float)lo_v;
+ pXh->c[c] = (float)hi_v;
+ }
}
- break;
}
- case transcoder_texture_format::cTFETC2_EAC_R11:
+
+ return true;
+ }
+
+ void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb)
+ {
+ dxt1_block* pDst_block = static_cast<dxt1_block*>(pDst);
+
+ uint32_t mask = 0xAA;
+ uint32_t max16 = (g_bc1_match5_equals_1[fr].m_hi << 11) | (g_bc1_match6_equals_1[fg].m_hi << 5) | g_bc1_match5_equals_1[fb].m_hi;
+ uint32_t min16 = (g_bc1_match5_equals_1[fr].m_lo << 11) | (g_bc1_match6_equals_1[fg].m_lo << 5) | g_bc1_match5_equals_1[fb].m_lo;
+
+ if (min16 == max16)
{
-#if !BASISD_SUPPORT_ETC2_EAC_RG11
- return false;
-#endif
- uint32_t slice_index_to_decode = slice_index;
- // If the caller wants us to transcode the mip level's alpha data, then use the next slice.
- if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))
- slice_index_to_decode++;
+ // Always forbid 3 color blocks
+ // This is to guarantee that BC3 blocks never use punchthrough alpha (3 color) mode, which isn't supported on some (all?) GPU's.
+ mask = 0;
- status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, bytes_per_block, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ // Make l > h
+ if (min16 > 0)
+ min16--;
+ else
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to ETC2_EAC_R11 failed\n");
+ // l = h = 0
+ assert(min16 == max16 && max16 == 0);
+
+ max16 = 1;
+ min16 = 0;
+ mask = 0x55;
}
- break;
+ assert(max16 > min16);
}
- case transcoder_texture_format::cTFETC2_EAC_RG11:
+
+ if (max16 < min16)
{
-#if !BASISD_SUPPORT_ETC2_EAC_RG11
- return false;
+ std::swap(max16, min16);
+ mask ^= 0x55;
+ }
+
+ pDst_block->set_low_color(static_cast<uint16_t>(max16));
+ pDst_block->set_high_color(static_cast<uint16_t>(min16));
+ pDst_block->m_selectors[0] = static_cast<uint8_t>(mask);
+ pDst_block->m_selectors[1] = static_cast<uint8_t>(mask);
+ pDst_block->m_selectors[2] = static_cast<uint8_t>(mask);
+ pDst_block->m_selectors[3] = static_cast<uint8_t>(mask);
+ }
+
+ static inline uint8_t to_5(uint32_t v) { v = v * 31 + 128; return (uint8_t)((v + (v >> 8)) >> 8); }
+ static inline uint8_t to_6(uint32_t v) { v = v * 63 + 128; return (uint8_t)((v + (v >> 8)) >> 8); }
+
+ // Good references: squish library, stb_dxt.
+ void encode_bc1(void* pDst, const uint8_t* pPixels, uint32_t flags)
+ {
+ const color32* pSrc_pixels = (const color32*)pPixels;
+ dxt1_block* pDst_block = static_cast<dxt1_block*>(pDst);
+
+ int avg_r = -1, avg_g = 0, avg_b = 0;
+ int lr = 0, lg = 0, lb = 0, hr = 0, hg = 0, hb = 0;
+ uint8_t sels[16];
+
+ const bool use_sels = (flags & cEncodeBC1UseSelectors) != 0;
+ if (use_sels)
+ {
+ // Caller is jamming in their own selectors for us to try.
+ const uint32_t s = pDst_block->m_selectors[0] | (pDst_block->m_selectors[1] << 8) | (pDst_block->m_selectors[2] << 16) | (pDst_block->m_selectors[3] << 24);
+
+ static const uint8_t s_sel_tran[4] = { 0, 3, 1, 2 };
+
+ for (uint32_t i = 0; i < 16; i++)
+ sels[i] = s_sel_tran[(s >> (i * 2)) & 3];
+ }
+ else
+ {
+ const uint32_t fr = pSrc_pixels[0].r, fg = pSrc_pixels[0].g, fb = pSrc_pixels[0].b;
+
+ uint32_t j;
+ for (j = 1; j < 16; j++)
+ if ((pSrc_pixels[j].r != fr) || (pSrc_pixels[j].g != fg) || (pSrc_pixels[j].b != fb))
+ break;
+
+ if (j == 16)
+ {
+ encode_bc1_solid_block(pDst, fr, fg, fb);
+ return;
+ }
+
+ // Select 2 colors along the principle axis. (There must be a faster/simpler way.)
+ int total_r = fr, total_g = fg, total_b = fb;
+ int max_r = fr, max_g = fg, max_b = fb;
+ int min_r = fr, min_g = fg, min_b = fb;
+ for (uint32_t i = 1; i < 16; i++)
+ {
+ const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
+ max_r = basisu::maximum(max_r, r); max_g = basisu::maximum(max_g, g); max_b = basisu::maximum(max_b, b);
+ min_r = basisu::minimum(min_r, r); min_g = basisu::minimum(min_g, g); min_b = basisu::minimum(min_b, b);
+ total_r += r; total_g += g; total_b += b;
+ }
+
+ avg_r = (total_r + 8) >> 4;
+ avg_g = (total_g + 8) >> 4;
+ avg_b = (total_b + 8) >> 4;
+
+ int icov[6] = { 0, 0, 0, 0, 0, 0 };
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ int r = (int)pSrc_pixels[i].r - avg_r;
+ int g = (int)pSrc_pixels[i].g - avg_g;
+ int b = (int)pSrc_pixels[i].b - avg_b;
+ icov[0] += r * r;
+ icov[1] += r * g;
+ icov[2] += r * b;
+ icov[3] += g * g;
+ icov[4] += g * b;
+ icov[5] += b * b;
+ }
+
+ float cov[6];
+ for (uint32_t i = 0; i < 6; i++)
+ cov[i] = static_cast<float>(icov[i])* (1.0f / 255.0f);
+
+#if 0
+ // Seems silly to use full PCA to choose 2 colors. The diff in avg. PSNR between using PCA vs. not is small (~.025 difference).
+ // TODO: Try 2 or 3 different normalized diagonal vectors, choose the one that results in the largest dot delta
+ int saxis_r = max_r - min_r;
+ int saxis_g = max_g - min_g;
+ int saxis_b = max_b - min_b;
+#else
+ float xr = (float)(max_r - min_r);
+ float xg = (float)(max_g - min_g);
+ float xb = (float)(max_b - min_b);
+ //float xr = (float)(max_r - avg_r); // max-avg is nearly the same, and doesn't require computing min's
+ //float xg = (float)(max_g - avg_g);
+ //float xb = (float)(max_b - avg_b);
+ for (uint32_t power_iter = 0; power_iter < 4; power_iter++)
+ {
+ float r = xr * cov[0] + xg * cov[1] + xb * cov[2];
+ float g = xr * cov[1] + xg * cov[3] + xb * cov[4];
+ float b = xr * cov[2] + xg * cov[4] + xb * cov[5];
+ xr = r; xg = g; xb = b;
+ }
+
+ float k = basisu::maximum(fabsf(xr), fabsf(xg), fabsf(xb));
+ int saxis_r = 306, saxis_g = 601, saxis_b = 117;
+ if (k >= 2)
+ {
+ float m = 1024.0f / k;
+ saxis_r = (int)(xr * m);
+ saxis_g = (int)(xg * m);
+ saxis_b = (int)(xb * m);
+ }
#endif
- assert(bytes_per_block == 16);
+
+ int low_dot = INT_MAX, high_dot = INT_MIN, low_c = 0, high_c = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ int dot = pSrc_pixels[i].r * saxis_r + pSrc_pixels[i].g * saxis_g + pSrc_pixels[i].b * saxis_b;
+ if (dot < low_dot)
+ {
+ low_dot = dot;
+ low_c = i;
+ }
+ if (dot > high_dot)
+ {
+ high_dot = dot;
+ high_c = i;
+ }
+ }
- if (basis_file_has_alpha_slices)
+ lr = to_5(pSrc_pixels[low_c].r);
+ lg = to_6(pSrc_pixels[low_c].g);
+ lb = to_5(pSrc_pixels[low_c].b);
+
+ hr = to_5(pSrc_pixels[high_c].r);
+ hg = to_6(pSrc_pixels[high_c].g);
+ hb = to_5(pSrc_pixels[high_c].b);
+
+ bc1_find_sels(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels);
+ } // if (use_sels)
+
+ const uint32_t total_ls_passes = (flags & cEncodeBC1HigherQuality) ? 3 : (flags & cEncodeBC1HighQuality ? 2 : 1);
+ for (uint32_t ls_pass = 0; ls_pass < total_ls_passes; ls_pass++)
+ {
+ // This is where the real magic happens. We have an array of candidate selectors, so let's use least squares to compute the optimal low/high endpoint colors.
+ vec3F xl, xh;
+ if (!compute_least_squares_endpoints_rgb(pSrc_pixels, sels, &xl, &xh))
{
- // First decode the alpha data to G
- status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t *)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
+ if (avg_r < 0)
+ {
+ int total_r = 0, total_g = 0, total_b = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ total_r += pSrc_pixels[i].r;
+ total_g += pSrc_pixels[i].g;
+ total_b += pSrc_pixels[i].b;
+ }
+
+ avg_r = (total_r + 8) >> 4;
+ avg_g = (total_g + 8) >> 4;
+ avg_b = (total_b + 8) >> 4;
+ }
+
+ // All selectors equal - treat it as a solid block which should always be equal or better.
+ lr = g_bc1_match5_equals_1[avg_r].m_hi;
+ lg = g_bc1_match6_equals_1[avg_g].m_hi;
+ lb = g_bc1_match5_equals_1[avg_b].m_hi;
+
+ hr = g_bc1_match5_equals_1[avg_r].m_lo;
+ hg = g_bc1_match6_equals_1[avg_g].m_lo;
+ hb = g_bc1_match5_equals_1[avg_b].m_lo;
+
+ // In high/higher quality mode, let it try again in case the optimal tables have caused the sels to diverge.
}
else
{
- write_opaque_alpha_blocks(pSlice_descs[slice_index].m_num_blocks_x, pSlice_descs[slice_index].m_num_blocks_y, (uint8_t *)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, 16, output_row_pitch_in_blocks_or_pixels);
- status = true;
+ lr = basisu::clamp((int)((xl.c[0]) * (31.0f / 255.0f) + .5f), 0, 31);
+ lg = basisu::clamp((int)((xl.c[1]) * (63.0f / 255.0f) + .5f), 0, 63);
+ lb = basisu::clamp((int)((xl.c[2]) * (31.0f / 255.0f) + .5f), 0, 31);
+
+ hr = basisu::clamp((int)((xh.c[0]) * (31.0f / 255.0f) + .5f), 0, 31);
+ hg = basisu::clamp((int)((xh.c[1]) * (63.0f / 255.0f) + .5f), 0, 63);
+ hb = basisu::clamp((int)((xh.c[2]) * (31.0f / 255.0f) + .5f), 0, 31);
}
+
+ bc1_find_sels(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels);
+ }
- if (status)
+ uint32_t lc16 = dxt1_block::pack_unscaled_color(lr, lg, lb);
+ uint32_t hc16 = dxt1_block::pack_unscaled_color(hr, hg, hb);
+
+ // Always forbid 3 color blocks
+ if (lc16 == hc16)
+ {
+ uint8_t mask = 0;
+
+ // Make l > h
+ if (hc16 > 0)
+ hc16--;
+ else
{
- // Now decode the color data to R
- status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);
- if (!status)
+ // lc16 = hc16 = 0
+ assert(lc16 == hc16 && hc16 == 0);
+
+ hc16 = 0;
+ lc16 = 1;
+ mask = 0x55; // select hc16
+ }
+
+ assert(lc16 > hc16);
+ pDst_block->set_low_color(static_cast<uint16_t>(lc16));
+ pDst_block->set_high_color(static_cast<uint16_t>(hc16));
+
+ pDst_block->m_selectors[0] = mask;
+ pDst_block->m_selectors[1] = mask;
+ pDst_block->m_selectors[2] = mask;
+ pDst_block->m_selectors[3] = mask;
+ }
+ else
+ {
+ uint8_t invert_mask = 0;
+ if (lc16 < hc16)
+ {
+ std::swap(lc16, hc16);
+ invert_mask = 0x55;
+ }
+
+ assert(lc16 > hc16);
+ pDst_block->set_low_color((uint16_t)lc16);
+ pDst_block->set_high_color((uint16_t)hc16);
+
+ uint32_t packed_sels = 0;
+ static const uint8_t s_sel_trans[4] = { 0, 2, 3, 1 };
+ for (uint32_t i = 0; i < 16; i++)
+ packed_sels |= ((uint32_t)s_sel_trans[sels[i]] << (i * 2));
+
+ pDst_block->m_selectors[0] = (uint8_t)packed_sels ^ invert_mask;
+ pDst_block->m_selectors[1] = (uint8_t)(packed_sels >> 8) ^ invert_mask;
+ pDst_block->m_selectors[2] = (uint8_t)(packed_sels >> 16) ^ invert_mask;
+ pDst_block->m_selectors[3] = (uint8_t)(packed_sels >> 24) ^ invert_mask;
+ }
+ }
+
+ void encode_bc1_alt(void* pDst, const uint8_t* pPixels, uint32_t flags)
+ {
+ const color32* pSrc_pixels = (const color32*)pPixels;
+ dxt1_block* pDst_block = static_cast<dxt1_block*>(pDst);
+
+ int avg_r = -1, avg_g = 0, avg_b = 0;
+ int lr = 0, lg = 0, lb = 0, hr = 0, hg = 0, hb = 0;
+ uint8_t sels[16];
+
+ const bool use_sels = (flags & cEncodeBC1UseSelectors) != 0;
+ if (use_sels)
+ {
+ // Caller is jamming in their own selectors for us to try.
+ const uint32_t s = pDst_block->m_selectors[0] | (pDst_block->m_selectors[1] << 8) | (pDst_block->m_selectors[2] << 16) | (pDst_block->m_selectors[3] << 24);
+
+ static const uint8_t s_sel_tran[4] = { 0, 3, 1, 2 };
+
+ for (uint32_t i = 0; i < 16; i++)
+ sels[i] = s_sel_tran[(s >> (i * 2)) & 3];
+ }
+ else
+ {
+ const uint32_t fr = pSrc_pixels[0].r, fg = pSrc_pixels[0].g, fb = pSrc_pixels[0].b;
+
+ uint32_t j;
+ for (j = 1; j < 16; j++)
+ if ((pSrc_pixels[j].r != fr) || (pSrc_pixels[j].g != fg) || (pSrc_pixels[j].b != fb))
+ break;
+
+ if (j == 16)
+ {
+ encode_bc1_solid_block(pDst, fr, fg, fb);
+ return;
+ }
+
+ // Select 2 colors along the principle axis. (There must be a faster/simpler way.)
+ int total_r = fr, total_g = fg, total_b = fb;
+ int max_r = fr, max_g = fg, max_b = fb;
+ int min_r = fr, min_g = fg, min_b = fb;
+ uint32_t grayscale_flag = (fr == fg) && (fr == fb);
+ for (uint32_t i = 1; i < 16; i++)
+ {
+ const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
+ grayscale_flag &= ((r == g) && (r == b));
+ max_r = basisu::maximum(max_r, r); max_g = basisu::maximum(max_g, g); max_b = basisu::maximum(max_b, b);
+ min_r = basisu::minimum(min_r, r); min_g = basisu::minimum(min_g, g); min_b = basisu::minimum(min_b, b);
+ total_r += r; total_g += g; total_b += b;
+ }
+
+ if (grayscale_flag)
+ {
+ // Grayscale blocks are a common enough case to specialize.
+ if ((max_r - min_r) < 2)
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to ETC2_EAC_R11 R failed\n");
+ lr = lb = hr = hb = to_5(fr);
+ lg = hg = to_6(fr);
+ }
+ else
+ {
+ lr = lb = to_5(min_r);
+ lg = to_6(min_r);
+
+ hr = hb = to_5(max_r);
+ hg = to_6(max_r);
}
}
else
{
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: transcode_slice() to ETC2_EAC_R11 G failed\n");
+ avg_r = (total_r + 8) >> 4;
+ avg_g = (total_g + 8) >> 4;
+ avg_b = (total_b + 8) >> 4;
+
+ // Find the shortest vector from a AABB corner to the block's average color.
+ // This is to help avoid outliers.
+
+ uint32_t dist[3][2];
+ dist[0][0] = basisu::square(min_r - avg_r) << 3; dist[0][1] = basisu::square(max_r - avg_r) << 3;
+ dist[1][0] = basisu::square(min_g - avg_g) << 3; dist[1][1] = basisu::square(max_g - avg_g) << 3;
+ dist[2][0] = basisu::square(min_b - avg_b) << 3; dist[2][1] = basisu::square(max_b - avg_b) << 3;
+
+ uint32_t min_d0 = (dist[0][0] + dist[1][0] + dist[2][0]);
+ uint32_t d4 = (dist[0][0] + dist[1][0] + dist[2][1]) | 4;
+ min_d0 = basisu::minimum(min_d0, d4);
+
+ uint32_t min_d1 = (dist[0][1] + dist[1][0] + dist[2][0]) | 1;
+ uint32_t d5 = (dist[0][1] + dist[1][0] + dist[2][1]) | 5;
+ min_d1 = basisu::minimum(min_d1, d5);
+
+ uint32_t d2 = (dist[0][0] + dist[1][1] + dist[2][0]) | 2;
+ min_d0 = basisu::minimum(min_d0, d2);
+
+ uint32_t d3 = (dist[0][1] + dist[1][1] + dist[2][0]) | 3;
+ min_d1 = basisu::minimum(min_d1, d3);
+
+ uint32_t d6 = (dist[0][0] + dist[1][1] + dist[2][1]) | 6;
+ min_d0 = basisu::minimum(min_d0, d6);
+
+ uint32_t d7 = (dist[0][1] + dist[1][1] + dist[2][1]) | 7;
+ min_d1 = basisu::minimum(min_d1, d7);
+
+ uint32_t min_d = basisu::minimum(min_d0, min_d1);
+ uint32_t best_i = min_d & 7;
+
+ int delta_r = (best_i & 1) ? (max_r - avg_r) : (avg_r - min_r);
+ int delta_g = (best_i & 2) ? (max_g - avg_g) : (avg_g - min_g);
+ int delta_b = (best_i & 4) ? (max_b - avg_b) : (avg_b - min_b);
+
+ // Note: if delta_r/g/b==0, we actually want to choose a single color, so the block average color optimization kicks in.
+ uint32_t low_c = 0, high_c = 0;
+ if ((delta_r | delta_g | delta_b) != 0)
+ {
+ // Now we have a smaller AABB going from the block's average color to a cornerpoint of the larger AABB.
+ // Project all pixels colors along the 4 vectors going from a smaller AABB cornerpoint to the opposite cornerpoint, find largest projection.
+ // One of these vectors will be a decent approximation of the block's PCA.
+ const int saxis0_r = delta_r, saxis0_g = delta_g, saxis0_b = delta_b;
+
+ int low_dot0 = INT_MAX, high_dot0 = INT_MIN;
+ int low_dot1 = INT_MAX, high_dot1 = INT_MIN;
+ int low_dot2 = INT_MAX, high_dot2 = INT_MIN;
+ int low_dot3 = INT_MAX, high_dot3 = INT_MIN;
+
+ //int low_c0, low_c1, low_c2, low_c3;
+ //int high_c0, high_c1, high_c2, high_c3;
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const int dotx = pSrc_pixels[i].r * saxis0_r;
+ const int doty = pSrc_pixels[i].g * saxis0_g;
+ const int dotz = pSrc_pixels[i].b * saxis0_b;
+
+ const int dot0 = ((dotz + dotx + doty) << 4) + i;
+ const int dot1 = ((dotz - dotx - doty) << 4) + i;
+ const int dot2 = ((dotz - dotx + doty) << 4) + i;
+ const int dot3 = ((dotz + dotx - doty) << 4) + i;
+
+ if (dot0 < low_dot0)
+ {
+ low_dot0 = dot0;
+ //low_c0 = i;
+ }
+ if ((dot0 ^ 15) > high_dot0)
+ {
+ high_dot0 = dot0 ^ 15;
+ //high_c0 = i;
+ }
+
+ if (dot1 < low_dot1)
+ {
+ low_dot1 = dot1;
+ //low_c1 = i;
+ }
+ if ((dot1 ^ 15) > high_dot1)
+ {
+ high_dot1 = dot1 ^ 15;
+ //high_c1 = i;
+ }
+
+ if (dot2 < low_dot2)
+ {
+ low_dot2 = dot2;
+ //low_c2 = i;
+ }
+ if ((dot2 ^ 15) > high_dot2)
+ {
+ high_dot2 = dot2 ^ 15;
+ //high_c2 = i;
+ }
+
+ if (dot3 < low_dot3)
+ {
+ low_dot3 = dot3;
+ //low_c3 = i;
+ }
+ if ((dot3 ^ 15) > high_dot3)
+ {
+ high_dot3 = dot3 ^ 15;
+ //high_c3 = i;
+ }
+ }
+
+ low_c = low_dot0 & 15;
+ high_c = ~high_dot0 & 15;
+ uint32_t r = (high_dot0 & ~15) - (low_dot0 & ~15);
+
+ uint32_t tr = (high_dot1 & ~15) - (low_dot1 & ~15);
+ if (tr > r) {
+ low_c = low_dot1 & 15;
+ high_c = ~high_dot1 & 15;
+ r = tr;
+ }
+
+ tr = (high_dot2 & ~15) - (low_dot2 & ~15);
+ if (tr > r) {
+ low_c = low_dot2 & 15;
+ high_c = ~high_dot2 & 15;
+ r = tr;
+ }
+
+ tr = (high_dot3 & ~15) - (low_dot3 & ~15);
+ if (tr > r) {
+ low_c = low_dot3 & 15;
+ high_c = ~high_dot3 & 15;
+ }
+ }
+
+ lr = to_5(pSrc_pixels[low_c].r);
+ lg = to_6(pSrc_pixels[low_c].g);
+ lb = to_5(pSrc_pixels[low_c].b);
+
+ hr = to_5(pSrc_pixels[high_c].r);
+ hg = to_6(pSrc_pixels[high_c].g);
+ hb = to_5(pSrc_pixels[high_c].b);
}
- break;
+ bc1_find_sels_2(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels);
+ } // if (use_sels)
+
+ const uint32_t total_ls_passes = (flags & cEncodeBC1HigherQuality) ? 3 : (flags & cEncodeBC1HighQuality ? 2 : 1);
+ for (uint32_t ls_pass = 0; ls_pass < total_ls_passes; ls_pass++)
+ {
+ int prev_lr = lr, prev_lg = lg, prev_lb = lb, prev_hr = hr, prev_hg = hg, prev_hb = hb;
+
+ // This is where the real magic happens. We have an array of candidate selectors, so let's use least squares to compute the optimal low/high endpoint colors.
+ vec3F xl, xh;
+ if (!compute_least_squares_endpoints_rgb(pSrc_pixels, sels, &xl, &xh))
+ {
+ if (avg_r < 0)
+ {
+ int total_r = 0, total_g = 0, total_b = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ total_r += pSrc_pixels[i].r;
+ total_g += pSrc_pixels[i].g;
+ total_b += pSrc_pixels[i].b;
+ }
+
+ avg_r = (total_r + 8) >> 4;
+ avg_g = (total_g + 8) >> 4;
+ avg_b = (total_b + 8) >> 4;
+ }
+
+ // All selectors equal - treat it as a solid block which should always be equal or better.
+ lr = g_bc1_match5_equals_1[avg_r].m_hi;
+ lg = g_bc1_match6_equals_1[avg_g].m_hi;
+ lb = g_bc1_match5_equals_1[avg_b].m_hi;
+
+ hr = g_bc1_match5_equals_1[avg_r].m_lo;
+ hg = g_bc1_match6_equals_1[avg_g].m_lo;
+ hb = g_bc1_match5_equals_1[avg_b].m_lo;
+
+ // In high/higher quality mode, let it try again in case the optimal tables have caused the sels to diverge.
+ }
+ else
+ {
+ lr = basisu::clamp((int)((xl.c[0]) * (31.0f / 255.0f) + .5f), 0, 31);
+ lg = basisu::clamp((int)((xl.c[1]) * (63.0f / 255.0f) + .5f), 0, 63);
+ lb = basisu::clamp((int)((xl.c[2]) * (31.0f / 255.0f) + .5f), 0, 31);
+
+ hr = basisu::clamp((int)((xh.c[0]) * (31.0f / 255.0f) + .5f), 0, 31);
+ hg = basisu::clamp((int)((xh.c[1]) * (63.0f / 255.0f) + .5f), 0, 63);
+ hb = basisu::clamp((int)((xh.c[2]) * (31.0f / 255.0f) + .5f), 0, 31);
+ }
+
+ if ((prev_lr == lr) && (prev_lg == lg) && (prev_lb == lb) && (prev_hr == hr) && (prev_hg == hg) && (prev_hb == hb))
+ break;
+
+ bc1_find_sels_2(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels);
}
- default:
+
+ uint32_t lc16 = dxt1_block::pack_unscaled_color(lr, lg, lb);
+ uint32_t hc16 = dxt1_block::pack_unscaled_color(hr, hg, hb);
+
+ // Always forbid 3 color blocks
+ if (lc16 == hc16)
{
- assert(0);
- BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Invalid fmt\n");
- break;
+ uint8_t mask = 0;
+
+ // Make l > h
+ if (hc16 > 0)
+ hc16--;
+ else
+ {
+ // lc16 = hc16 = 0
+ assert(lc16 == hc16 && hc16 == 0);
+
+ hc16 = 0;
+ lc16 = 1;
+ mask = 0x55; // select hc16
+ }
+
+ assert(lc16 > hc16);
+ pDst_block->set_low_color(static_cast<uint16_t>(lc16));
+ pDst_block->set_high_color(static_cast<uint16_t>(hc16));
+
+ pDst_block->m_selectors[0] = mask;
+ pDst_block->m_selectors[1] = mask;
+ pDst_block->m_selectors[2] = mask;
+ pDst_block->m_selectors[3] = mask;
}
+ else
+ {
+ uint8_t invert_mask = 0;
+ if (lc16 < hc16)
+ {
+ std::swap(lc16, hc16);
+ invert_mask = 0x55;
+ }
+
+ assert(lc16 > hc16);
+ pDst_block->set_low_color((uint16_t)lc16);
+ pDst_block->set_high_color((uint16_t)hc16);
+
+ uint32_t packed_sels = 0;
+ static const uint8_t s_sel_trans[4] = { 0, 2, 3, 1 };
+ for (uint32_t i = 0; i < 16; i++)
+ packed_sels |= ((uint32_t)s_sel_trans[sels[i]] << (i * 2));
+
+ pDst_block->m_selectors[0] = (uint8_t)packed_sels ^ invert_mask;
+ pDst_block->m_selectors[1] = (uint8_t)(packed_sels >> 8) ^ invert_mask;
+ pDst_block->m_selectors[2] = (uint8_t)(packed_sels >> 16) ^ invert_mask;
+ pDst_block->m_selectors[3] = (uint8_t)(packed_sels >> 24) ^ invert_mask;
}
+ }
- return status;
+ // Scale the UASTC first subset endpoints and first plane's weight indices directly to BC1's - fastest.
+ void transcode_uastc_to_bc1_hint0(const unpacked_uastc_block& unpacked_src_blk, void* pDst)
+ {
+ const uint32_t mode = unpacked_src_blk.m_mode;
+ const astc_block_desc& astc_blk = unpacked_src_blk.m_astc;
+
+ dxt1_block& b = *static_cast<dxt1_block*>(pDst);
+
+ const uint32_t endpoint_range = g_uastc_mode_endpoint_ranges[mode];
+
+ const uint32_t total_comps = g_uastc_mode_comps[mode];
+
+ if (total_comps == 2)
+ {
+ const uint32_t l = g_astc_unquant[endpoint_range][astc_blk.m_endpoints[0]].m_unquant;
+ const uint32_t h = g_astc_unquant[endpoint_range][astc_blk.m_endpoints[1]].m_unquant;
+
+ b.set_low_color(dxt1_block::pack_color(color32(l, l, l, 255), true, 127));
+ b.set_high_color(dxt1_block::pack_color(color32(h, h, h, 255), true, 127));
+ }
+ else
+ {
+ b.set_low_color(dxt1_block::pack_color(
+ color32(g_astc_unquant[endpoint_range][astc_blk.m_endpoints[0]].m_unquant,
+ g_astc_unquant[endpoint_range][astc_blk.m_endpoints[2]].m_unquant,
+ g_astc_unquant[endpoint_range][astc_blk.m_endpoints[4]].m_unquant,
+ 255), true, 127)
+ );
+
+ b.set_high_color(dxt1_block::pack_color(
+ color32(g_astc_unquant[endpoint_range][astc_blk.m_endpoints[1]].m_unquant,
+ g_astc_unquant[endpoint_range][astc_blk.m_endpoints[3]].m_unquant,
+ g_astc_unquant[endpoint_range][astc_blk.m_endpoints[5]].m_unquant,
+ 255), true, 127)
+ );
+ }
+
+ if (b.get_low_color() == b.get_high_color())
+ {
+ // Always forbid 3 color blocks
+ uint16_t lc16 = (uint16_t)b.get_low_color();
+ uint16_t hc16 = (uint16_t)b.get_high_color();
+
+ uint8_t mask = 0;
+
+ // Make l > h
+ if (hc16 > 0)
+ hc16--;
+ else
+ {
+ // lc16 = hc16 = 0
+ assert(lc16 == hc16 && hc16 == 0);
+
+ hc16 = 0;
+ lc16 = 1;
+ mask = 0x55; // select hc16
+ }
+
+ assert(lc16 > hc16);
+ b.set_low_color(static_cast<uint16_t>(lc16));
+ b.set_high_color(static_cast<uint16_t>(hc16));
+
+ b.m_selectors[0] = mask;
+ b.m_selectors[1] = mask;
+ b.m_selectors[2] = mask;
+ b.m_selectors[3] = mask;
+ }
+ else
+ {
+ bool invert = false;
+ if (b.get_low_color() < b.get_high_color())
+ {
+ std::swap(b.m_low_color[0], b.m_high_color[0]);
+ std::swap(b.m_low_color[1], b.m_high_color[1]);
+ invert = true;
+ }
+
+ const uint8_t* pTran = s_uastc_to_bc1_weights[g_uastc_mode_weight_bits[mode]];
+
+ const uint32_t plane_shift = g_uastc_mode_planes[mode] - 1;
+
+ uint32_t sels = 0;
+ for (int i = 15; i >= 0; --i)
+ {
+ uint32_t s = pTran[astc_blk.m_weights[i << plane_shift]];
+
+ if (invert)
+ s ^= 1;
+
+ sels = (sels << 2) | s;
+ }
+ b.m_selectors[0] = sels & 0xFF;
+ b.m_selectors[1] = (sels >> 8) & 0xFF;
+ b.m_selectors[2] = (sels >> 16) & 0xFF;
+ b.m_selectors[3] = (sels >> 24) & 0xFF;
+ }
}
- uint32_t basis_get_bytes_per_block(transcoder_texture_format fmt)
+ // Scale the UASTC first plane's weight indices to BC1, use 1 or 2 least squares passes to compute endpoints - no PCA needed.
+ void transcode_uastc_to_bc1_hint1(const unpacked_uastc_block& unpacked_src_blk, const color32 block_pixels[4][4], void* pDst, bool high_quality)
{
- switch (fmt)
+ const uint32_t mode = unpacked_src_blk.m_mode;
+
+ const astc_block_desc& astc_blk = unpacked_src_blk.m_astc;
+
+ dxt1_block& b = *static_cast<dxt1_block*>(pDst);
+
+ b.set_low_color(1);
+ b.set_high_color(0);
+
+ const uint8_t* pTran = s_uastc_to_bc1_weights[g_uastc_mode_weight_bits[mode]];
+
+ const uint32_t plane_shift = g_uastc_mode_planes[mode] - 1;
+
+ uint32_t sels = 0;
+ for (int i = 15; i >= 0; --i)
{
- case transcoder_texture_format::cTFETC1_RGB:
- case transcoder_texture_format::cTFBC1_RGB:
- case transcoder_texture_format::cTFBC4_R:
- case transcoder_texture_format::cTFPVRTC1_4_RGB:
- case transcoder_texture_format::cTFPVRTC1_4_RGBA:
- case transcoder_texture_format::cTFATC_RGB:
- case transcoder_texture_format::cTFPVRTC2_4_RGB:
- case transcoder_texture_format::cTFPVRTC2_4_RGBA:
- case transcoder_texture_format::cTFETC2_EAC_R11:
- return 8;
- case transcoder_texture_format::cTFBC7_M6_RGB:
- case transcoder_texture_format::cTFBC7_M5_RGBA:
- case transcoder_texture_format::cTFETC2_RGBA:
- case transcoder_texture_format::cTFBC3_RGBA:
- case transcoder_texture_format::cTFBC5_RG:
- case transcoder_texture_format::cTFASTC_4x4_RGBA:
- case transcoder_texture_format::cTFATC_RGBA:
- case transcoder_texture_format::cTFFXT1_RGB:
- case transcoder_texture_format::cTFETC2_EAC_RG11:
- return 16;
- case transcoder_texture_format::cTFRGBA32:
- return sizeof(uint32_t) * 16;
- case transcoder_texture_format::cTFRGB565:
- case transcoder_texture_format::cTFBGR565:
- case transcoder_texture_format::cTFRGBA4444:
- return sizeof(uint16_t) * 16;
- default:
- assert(0);
- BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");
- break;
+ sels <<= 2;
+ sels |= pTran[astc_blk.m_weights[i << plane_shift]];
}
- return 0;
+
+ b.m_selectors[0] = sels & 0xFF;
+ b.m_selectors[1] = (sels >> 8) & 0xFF;
+ b.m_selectors[2] = (sels >> 16) & 0xFF;
+ b.m_selectors[3] = (sels >> 24) & 0xFF;
+
+ encode_bc1(&b, (const uint8_t*)&block_pixels[0][0].c[0], (high_quality ? cEncodeBC1HighQuality : 0) | cEncodeBC1UseSelectors);
}
- const char* basis_get_format_name(transcoder_texture_format fmt)
+ bool transcode_uastc_to_bc1(const uastc_block& src_blk, void* pDst, bool high_quality)
{
- switch (fmt)
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, false))
+ return false;
+
+ const uint32_t mode = unpacked_src_blk.m_mode;
+
+ if (mode == UASTC_MODE_INDEX_SOLID_COLOR)
{
- case transcoder_texture_format::cTFETC1_RGB: return "ETC1_RGB";
- case transcoder_texture_format::cTFBC1_RGB: return "BC1_RGB";
- case transcoder_texture_format::cTFBC4_R: return "BC4_R";
- case transcoder_texture_format::cTFPVRTC1_4_RGB: return "PVRTC1_4_RGB";
- case transcoder_texture_format::cTFPVRTC1_4_RGBA: return "PVRTC1_4_RGBA";
- case transcoder_texture_format::cTFBC7_M6_RGB: return "BC7_M6_RGB";
- case transcoder_texture_format::cTFBC7_M5_RGBA: return "BC7_M5_RGBA";
- case transcoder_texture_format::cTFETC2_RGBA: return "ETC2_RGBA";
- case transcoder_texture_format::cTFBC3_RGBA: return "BC3_RGBA";
- case transcoder_texture_format::cTFBC5_RG: return "BC5_RG";
- case transcoder_texture_format::cTFASTC_4x4_RGBA: return "ASTC_RGBA";
- case transcoder_texture_format::cTFATC_RGB: return "ATC_RGB";
- case transcoder_texture_format::cTFATC_RGBA: return "ATC_RGBA";
- case transcoder_texture_format::cTFRGBA32: return "RGBA32";
- case transcoder_texture_format::cTFRGB565: return "RGB565";
- case transcoder_texture_format::cTFBGR565: return "BGR565";
- case transcoder_texture_format::cTFRGBA4444: return "RGBA4444";
- case transcoder_texture_format::cTFFXT1_RGB: return "FXT1_RGB";
- case transcoder_texture_format::cTFPVRTC2_4_RGB: return "PVRTC2_4_RGB";
- case transcoder_texture_format::cTFPVRTC2_4_RGBA: return "PVRTC2_4_RGBA";
- case transcoder_texture_format::cTFETC2_EAC_R11: return "ETC2_EAC_R11";
- case transcoder_texture_format::cTFETC2_EAC_RG11: return "ETC2_EAC_RG11";
- default:
- assert(0);
- BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");
- break;
+ encode_bc1_solid_block(pDst, unpacked_src_blk.m_solid_color.r, unpacked_src_blk.m_solid_color.g, unpacked_src_blk.m_solid_color.b);
+ return true;
}
- return "";
+
+ if ((!high_quality) && (unpacked_src_blk.m_bc1_hint0))
+ transcode_uastc_to_bc1_hint0(unpacked_src_blk, pDst);
+ else
+ {
+ color32 block_pixels[4][4];
+ const bool unpack_srgb = false;
+ if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))
+ return false;
+
+ if (unpacked_src_blk.m_bc1_hint1)
+ transcode_uastc_to_bc1_hint1(unpacked_src_blk, block_pixels, pDst, high_quality);
+ else
+ encode_bc1(pDst, &block_pixels[0][0].r, high_quality ? cEncodeBC1HighQuality : 0);
+ }
+
+ return true;
}
- const char* basis_get_texture_type_name(basis_texture_type tex_type)
+ static void write_bc4_solid_block(uint8_t* pDst, uint32_t a)
{
- switch (tex_type)
+ pDst[0] = (uint8_t)a;
+ pDst[1] = (uint8_t)a;
+ memset(pDst + 2, 0, 6);
+ }
+
+ bool transcode_uastc_to_bc3(const uastc_block& src_blk, void* pDst, bool high_quality)
+ {
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, false))
+ return false;
+
+ const uint32_t mode = unpacked_src_blk.m_mode;
+
+ void* pBC4_block = pDst;
+ dxt1_block* pBC1_block = &static_cast<dxt1_block*>(pDst)[1];
+
+ if (mode == UASTC_MODE_INDEX_SOLID_COLOR)
{
- case cBASISTexType2D: return "2D";
- case cBASISTexType2DArray: return "2D array";
- case cBASISTexTypeCubemapArray: return "cubemap array";
- case cBASISTexTypeVideoFrames: return "video";
- case cBASISTexTypeVolume: return "3D";
- default:
- assert(0);
- BASISU_DEVEL_ERROR("basis_get_texture_type_name: Invalid tex_type\n");
- break;
+ write_bc4_solid_block(static_cast<uint8_t*>(pBC4_block), unpacked_src_blk.m_solid_color.a);
+ encode_bc1_solid_block(pBC1_block, unpacked_src_blk.m_solid_color.r, unpacked_src_blk.m_solid_color.g, unpacked_src_blk.m_solid_color.b);
+ return true;
}
- return "";
+
+ color32 block_pixels[4][4];
+ const bool unpack_srgb = false;
+ if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))
+ return false;
+
+ basist::encode_bc4(pBC4_block, &block_pixels[0][0].a, sizeof(color32));
+
+ if ((!high_quality) && (unpacked_src_blk.m_bc1_hint0))
+ transcode_uastc_to_bc1_hint0(unpacked_src_blk, pBC1_block);
+ else
+ {
+ if (unpacked_src_blk.m_bc1_hint1)
+ transcode_uastc_to_bc1_hint1(unpacked_src_blk, block_pixels, pBC1_block, high_quality);
+ else
+ encode_bc1(pBC1_block, &block_pixels[0][0].r, high_quality ? cEncodeBC1HighQuality : 0);
+ }
+
+ return true;
}
- bool basis_transcoder_format_has_alpha(transcoder_texture_format fmt)
+ bool transcode_uastc_to_bc4(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0)
{
- switch (fmt)
+ BASISU_NOTE_UNUSED(high_quality);
+
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, false))
+ return false;
+
+ const uint32_t mode = unpacked_src_blk.m_mode;
+
+ void* pBC4_block = pDst;
+
+ if (mode == UASTC_MODE_INDEX_SOLID_COLOR)
{
- case transcoder_texture_format::cTFETC2_RGBA:
- case transcoder_texture_format::cTFBC3_RGBA:
- case transcoder_texture_format::cTFASTC_4x4_RGBA:
- case transcoder_texture_format::cTFBC7_M5_RGBA:
- case transcoder_texture_format::cTFPVRTC1_4_RGBA:
- case transcoder_texture_format::cTFPVRTC2_4_RGBA:
- case transcoder_texture_format::cTFATC_RGBA:
- case transcoder_texture_format::cTFRGBA32:
- case transcoder_texture_format::cTFRGBA4444:
+ write_bc4_solid_block(static_cast<uint8_t*>(pBC4_block), unpacked_src_blk.m_solid_color.c[chan0]);
return true;
- default:
- break;
}
- return false;
+
+ color32 block_pixels[4][4];
+ const bool unpack_srgb = false;
+ if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))
+ return false;
+
+ basist::encode_bc4(pBC4_block, &block_pixels[0][0].c[chan0], sizeof(color32));
+
+ return true;
}
- basisu::texture_format basis_get_basisu_texture_format(transcoder_texture_format fmt)
+ bool transcode_uastc_to_bc5(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1)
{
- switch (fmt)
+ BASISU_NOTE_UNUSED(high_quality);
+
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, false))
+ return false;
+
+ const uint32_t mode = unpacked_src_blk.m_mode;
+
+ void* pBC4_block0 = pDst;
+ void* pBC4_block1 = (uint8_t*)pDst + 8;
+
+ if (mode == UASTC_MODE_INDEX_SOLID_COLOR)
{
- case transcoder_texture_format::cTFETC1_RGB: return basisu::texture_format::cETC1;
- case transcoder_texture_format::cTFBC1_RGB: return basisu::texture_format::cBC1;
- case transcoder_texture_format::cTFBC4_R: return basisu::texture_format::cBC4;
- case transcoder_texture_format::cTFPVRTC1_4_RGB: return basisu::texture_format::cPVRTC1_4_RGB;
- case transcoder_texture_format::cTFPVRTC1_4_RGBA: return basisu::texture_format::cPVRTC1_4_RGBA;
- case transcoder_texture_format::cTFBC7_M6_RGB: return basisu::texture_format::cBC7;
- case transcoder_texture_format::cTFBC7_M5_RGBA: return basisu::texture_format::cBC7;
- case transcoder_texture_format::cTFETC2_RGBA: return basisu::texture_format::cETC2_RGBA;
- case transcoder_texture_format::cTFBC3_RGBA: return basisu::texture_format::cBC3;
- case transcoder_texture_format::cTFBC5_RG: return basisu::texture_format::cBC5;
- case transcoder_texture_format::cTFASTC_4x4_RGBA: return basisu::texture_format::cASTC4x4;
- case transcoder_texture_format::cTFATC_RGB: return basisu::texture_format::cATC_RGB;
- case transcoder_texture_format::cTFATC_RGBA: return basisu::texture_format::cATC_RGBA_INTERPOLATED_ALPHA;
- case transcoder_texture_format::cTFRGBA32: return basisu::texture_format::cRGBA32;
- case transcoder_texture_format::cTFRGB565: return basisu::texture_format::cRGB565;
- case transcoder_texture_format::cTFBGR565: return basisu::texture_format::cBGR565;
- case transcoder_texture_format::cTFRGBA4444: return basisu::texture_format::cRGBA4444;
- case transcoder_texture_format::cTFFXT1_RGB: return basisu::texture_format::cFXT1_RGB;
- case transcoder_texture_format::cTFPVRTC2_4_RGB: return basisu::texture_format::cPVRTC2_4_RGBA;
- case transcoder_texture_format::cTFPVRTC2_4_RGBA: return basisu::texture_format::cPVRTC2_4_RGBA;
- case transcoder_texture_format::cTFETC2_EAC_R11: return basisu::texture_format::cETC2_R11_EAC;
- case transcoder_texture_format::cTFETC2_EAC_RG11: return basisu::texture_format::cETC2_RG11_EAC;
- default:
- assert(0);
- BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");
- break;
+ write_bc4_solid_block(static_cast<uint8_t*>(pBC4_block0), unpacked_src_blk.m_solid_color.c[chan0]);
+ write_bc4_solid_block(static_cast<uint8_t*>(pBC4_block1), unpacked_src_blk.m_solid_color.c[chan1]);
+ return true;
}
- return basisu::texture_format::cInvalidTextureFormat;
+
+ color32 block_pixels[4][4];
+ const bool unpack_srgb = false;
+ if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))
+ return false;
+
+ basist::encode_bc4(pBC4_block0, &block_pixels[0][0].c[chan0], sizeof(color32));
+ basist::encode_bc4(pBC4_block1, &block_pixels[0][0].c[chan1], sizeof(color32));
+
+ return true;
}
- bool basis_transcoder_format_is_uncompressed(transcoder_texture_format tex_type)
+ static const uint8_t s_etc2_eac_bit_ofs[16] = { 45, 33, 21, 9, 42, 30, 18, 6, 39, 27, 15, 3, 36, 24, 12, 0 };
+
+ static void pack_eac_solid_block(eac_block& blk, uint32_t a)
{
- switch (tex_type)
+ blk.m_base = static_cast<uint8_t>(a);
+ blk.m_table = 13;
+ blk.m_multiplier = 0;
+
+ memcpy(blk.m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4));
+
+ return;
+ }
+
+ // Only checks 4 tables.
+ static void pack_eac(eac_block& blk, const uint8_t* pPixels, uint32_t stride)
+ {
+ uint32_t min_alpha = 255, max_alpha = 0;
+ for (uint32_t i = 0; i < 16; i++)
{
- case transcoder_texture_format::cTFRGBA32:
- case transcoder_texture_format::cTFRGB565:
- case transcoder_texture_format::cTFBGR565:
- case transcoder_texture_format::cTFRGBA4444:
+ const uint32_t a = pPixels[i * stride];
+ if (a < min_alpha) min_alpha = a;
+ if (a > max_alpha) max_alpha = a;
+ }
+
+ if (min_alpha == max_alpha)
+ {
+ pack_eac_solid_block(blk, min_alpha);
+ return;
+ }
+
+ const uint32_t alpha_range = max_alpha - min_alpha;
+
+ const uint32_t SINGLE_TABLE_THRESH = 5;
+ if (alpha_range <= SINGLE_TABLE_THRESH)
+ {
+ // If alpha_range <= 5 table 13 is lossless
+ int base = clamp255((int)max_alpha - 2);
+
+ blk.m_base = base;
+ blk.m_multiplier = 1;
+ blk.m_table = 13;
+
+ base -= 3;
+
+ uint64_t packed_sels = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const int a = pPixels[i * stride];
+
+ static const uint8_t s_sels[6] = { 2, 1, 0, 4, 5, 6 };
+
+ int sel = a - base;
+ assert(sel >= 0 && sel <= 5);
+
+ packed_sels |= (static_cast<uint64_t>(s_sels[sel]) << s_etc2_eac_bit_ofs[i]);
+ }
+
+ blk.set_selector_bits(packed_sels);
+
+ return;
+ }
+
+ const uint32_t T0 = 2, T1 = 8, T2 = 11, T3 = 13;
+ static const uint8_t s_tables[4] = { T0, T1, T2, T3 };
+
+ int base[4], mul[4];
+ uint32_t mul_or = 0;
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ const uint32_t table = s_tables[i];
+
+ const float range = (float)(g_eac_modifier_table[table][ETC2_EAC_MAX_VALUE_SELECTOR] - g_eac_modifier_table[table][ETC2_EAC_MIN_VALUE_SELECTOR]);
+
+ base[i] = clamp255((int)roundf(basisu::lerp((float)min_alpha, (float)max_alpha, (float)(0 - g_eac_modifier_table[table][ETC2_EAC_MIN_VALUE_SELECTOR]) / range)));
+ mul[i] = clampi((int)roundf(alpha_range / range), 1, 15);
+ mul_or |= mul[i];
+ }
+
+ uint32_t total_err[4] = { 0, 0, 0, 0 };
+ uint8_t sels[4][16];
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const int a = pPixels[i * stride];
+
+ uint32_t l0 = UINT32_MAX, l1 = UINT32_MAX, l2 = UINT32_MAX, l3 = UINT32_MAX;
+
+ if ((a < 7) || (a > (255 - 7)))
+ {
+ for (uint32_t s = 0; s < 8; s++)
+ {
+ const int v0 = clamp255(mul[0] * g_eac_modifier_table[T0][s] + base[0]);
+ const int v1 = clamp255(mul[1] * g_eac_modifier_table[T1][s] + base[1]);
+ const int v2 = clamp255(mul[2] * g_eac_modifier_table[T2][s] + base[2]);
+ const int v3 = clamp255(mul[3] * g_eac_modifier_table[T3][s] + base[3]);
+
+ l0 = basisu::minimum(l0, (basisu::iabs(v0 - a) << 3) | s);
+ l1 = basisu::minimum(l1, (basisu::iabs(v1 - a) << 3) | s);
+ l2 = basisu::minimum(l2, (basisu::iabs(v2 - a) << 3) | s);
+ l3 = basisu::minimum(l3, (basisu::iabs(v3 - a) << 3) | s);
+ }
+ }
+ else if (mul_or == 1)
+ {
+ const int a0 = base[0] - a, a1 = base[1] - a, a2 = base[2] - a, a3 = base[3] - a;
+
+ for (uint32_t s = 0; s < 8; s++)
+ {
+ const int v0 = g_eac_modifier_table[T0][s] + a0;
+ const int v1 = g_eac_modifier_table[T1][s] + a1;
+ const int v2 = g_eac_modifier_table[T2][s] + a2;
+ const int v3 = g_eac_modifier_table[T3][s] + a3;
+
+ l0 = basisu::minimum(l0, (basisu::iabs(v0) << 3) | s);
+ l1 = basisu::minimum(l1, (basisu::iabs(v1) << 3) | s);
+ l2 = basisu::minimum(l2, (basisu::iabs(v2) << 3) | s);
+ l3 = basisu::minimum(l3, (basisu::iabs(v3) << 3) | s);
+ }
+ }
+ else
+ {
+ const int a0 = base[0] - a, a1 = base[1] - a, a2 = base[2] - a, a3 = base[3] - a;
+
+ for (uint32_t s = 0; s < 8; s++)
+ {
+ const int v0 = mul[0] * g_eac_modifier_table[T0][s] + a0;
+ const int v1 = mul[1] * g_eac_modifier_table[T1][s] + a1;
+ const int v2 = mul[2] * g_eac_modifier_table[T2][s] + a2;
+ const int v3 = mul[3] * g_eac_modifier_table[T3][s] + a3;
+
+ l0 = basisu::minimum(l0, (basisu::iabs(v0) << 3) | s);
+ l1 = basisu::minimum(l1, (basisu::iabs(v1) << 3) | s);
+ l2 = basisu::minimum(l2, (basisu::iabs(v2) << 3) | s);
+ l3 = basisu::minimum(l3, (basisu::iabs(v3) << 3) | s);
+ }
+ }
+
+ sels[0][i] = l0 & 7;
+ sels[1][i] = l1 & 7;
+ sels[2][i] = l2 & 7;
+ sels[3][i] = l3 & 7;
+
+ total_err[0] += basisu::square<uint32_t>(l0 >> 3);
+ total_err[1] += basisu::square<uint32_t>(l1 >> 3);
+ total_err[2] += basisu::square<uint32_t>(l2 >> 3);
+ total_err[3] += basisu::square<uint32_t>(l3 >> 3);
+ }
+
+ uint32_t min_err = total_err[0], min_index = 0;
+ for (uint32_t i = 1; i < 4; i++)
+ {
+ if (total_err[i] < min_err)
+ {
+ min_err = total_err[i];
+ min_index = i;
+ }
+ }
+
+ blk.m_base = base[min_index];
+ blk.m_multiplier = mul[min_index];
+ blk.m_table = s_tables[min_index];
+
+ uint64_t packed_sels = 0;
+ const uint8_t* pSels = &sels[min_index][0];
+ for (uint32_t i = 0; i < 16; i++)
+ packed_sels |= (static_cast<uint64_t>(pSels[i]) << s_etc2_eac_bit_ofs[i]);
+
+ blk.set_selector_bits(packed_sels);
+ }
+
+ // Checks all 16 tables. Around ~2 dB better vs. pack_eac(), ~1.2 dB less than near-optimal.
+ static void pack_eac_high_quality(eac_block& blk, const uint8_t* pPixels, uint32_t stride)
+ {
+ uint32_t min_alpha = 255, max_alpha = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const uint32_t a = pPixels[i * stride];
+ if (a < min_alpha) min_alpha = a;
+ if (a > max_alpha) max_alpha = a;
+ }
+
+ if (min_alpha == max_alpha)
+ {
+ pack_eac_solid_block(blk, min_alpha);
+ return;
+ }
+
+ const uint32_t alpha_range = max_alpha - min_alpha;
+
+ const uint32_t SINGLE_TABLE_THRESH = 5;
+ if (alpha_range <= SINGLE_TABLE_THRESH)
+ {
+ // If alpha_range <= 5 table 13 is lossless
+ int base = clamp255((int)max_alpha - 2);
+
+ blk.m_base = base;
+ blk.m_multiplier = 1;
+ blk.m_table = 13;
+
+ base -= 3;
+
+ uint64_t packed_sels = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const int a = pPixels[i * stride];
+
+ static const uint8_t s_sels[6] = { 2, 1, 0, 4, 5, 6 };
+
+ int sel = a - base;
+ assert(sel >= 0 && sel <= 5);
+
+ packed_sels |= (static_cast<uint64_t>(s_sels[sel]) << s_etc2_eac_bit_ofs[i]);
+ }
+
+ blk.set_selector_bits(packed_sels);
+
+ return;
+ }
+
+ int base[16], mul[16];
+ for (uint32_t table = 0; table < 16; table++)
+ {
+ const float range = (float)(g_eac_modifier_table[table][ETC2_EAC_MAX_VALUE_SELECTOR] - g_eac_modifier_table[table][ETC2_EAC_MIN_VALUE_SELECTOR]);
+
+ base[table] = clamp255((int)roundf(basisu::lerp((float)min_alpha, (float)max_alpha, (float)(0 - g_eac_modifier_table[table][ETC2_EAC_MIN_VALUE_SELECTOR]) / range)));
+ mul[table] = clampi((int)roundf(alpha_range / range), 1, 15);
+ }
+
+ uint32_t total_err[16];
+ memset(total_err, 0, sizeof(total_err));
+
+ uint8_t sels[16][16];
+
+ for (uint32_t table = 0; table < 16; table++)
+ {
+ const int8_t* pTable = &g_eac_modifier_table[table][0];
+ const int m = mul[table], b = base[table];
+
+ uint32_t prev_l = 0, prev_a = UINT32_MAX;
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const int a = pPixels[i * stride];
+
+ if ((uint32_t)a == prev_a)
+ {
+ sels[table][i] = prev_l & 7;
+ total_err[table] += basisu::square<uint32_t>(prev_l >> 3);
+ }
+ else
+ {
+ uint32_t l = basisu::iabs(clamp255(m * pTable[0] + b) - a) << 3;
+ l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[1] + b) - a) << 3) | 1);
+ l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[2] + b) - a) << 3) | 2);
+ l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[3] + b) - a) << 3) | 3);
+ l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[4] + b) - a) << 3) | 4);
+ l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[5] + b) - a) << 3) | 5);
+ l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[6] + b) - a) << 3) | 6);
+ l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[7] + b) - a) << 3) | 7);
+
+ sels[table][i] = l & 7;
+ total_err[table] += basisu::square<uint32_t>(l >> 3);
+
+ prev_l = l;
+ prev_a = a;
+ }
+ }
+ }
+
+ uint32_t min_err = total_err[0], min_index = 0;
+ for (uint32_t i = 1; i < 16; i++)
+ {
+ if (total_err[i] < min_err)
+ {
+ min_err = total_err[i];
+ min_index = i;
+ }
+ }
+
+ blk.m_base = base[min_index];
+ blk.m_multiplier = mul[min_index];
+ blk.m_table = min_index;
+
+ uint64_t packed_sels = 0;
+ const uint8_t* pSels = &sels[min_index][0];
+ for (uint32_t i = 0; i < 16; i++)
+ packed_sels |= (static_cast<uint64_t>(pSels[i]) << s_etc2_eac_bit_ofs[i]);
+
+ blk.set_selector_bits(packed_sels);
+ }
+
+ bool transcode_uastc_to_etc2_eac_r11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0)
+ {
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, false))
+ return false;
+
+ const uint32_t mode = unpacked_src_blk.m_mode;
+
+ if (mode == UASTC_MODE_INDEX_SOLID_COLOR)
+ {
+ pack_eac_solid_block(*static_cast<eac_block*>(pDst), unpacked_src_blk.m_solid_color.c[chan0]);
return true;
- default:
- break;
}
- return false;
+
+ color32 block_pixels[4][4];
+ const bool unpack_srgb = false;
+ if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))
+ return false;
+
+ if (chan0 == 3)
+ transcode_uastc_to_etc2_eac_a8(unpacked_src_blk, block_pixels, pDst);
+ else
+ (high_quality ? pack_eac_high_quality : pack_eac)(*static_cast<eac_block*>(pDst), &block_pixels[0][0].c[chan0], sizeof(color32));
+
+ return true;
}
- bool basis_block_format_is_uncompressed(block_format tex_type)
+ bool transcode_uastc_to_etc2_eac_rg11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1)
{
- switch (tex_type)
+ unpacked_uastc_block unpacked_src_blk;
+ if (!unpack_uastc(src_blk, unpacked_src_blk, false))
+ return false;
+
+ const uint32_t mode = unpacked_src_blk.m_mode;
+
+ if (mode == UASTC_MODE_INDEX_SOLID_COLOR)
{
- case block_format::cRGB32:
- case block_format::cRGBA32:
- case block_format::cA32:
- case block_format::cRGB565:
- case block_format::cBGR565:
- case block_format::cRGBA4444_COLOR:
- case block_format::cRGBA4444_ALPHA:
- case block_format::cRGBA4444_COLOR_OPAQUE:
+ pack_eac_solid_block(static_cast<eac_block*>(pDst)[0], unpacked_src_blk.m_solid_color.c[chan0]);
+ pack_eac_solid_block(static_cast<eac_block*>(pDst)[1], unpacked_src_blk.m_solid_color.c[chan1]);
return true;
- default:
- break;
}
- return false;
+
+ color32 block_pixels[4][4];
+ const bool unpack_srgb = false;
+ if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))
+ return false;
+
+ if (chan0 == 3)
+ transcode_uastc_to_etc2_eac_a8(unpacked_src_blk, block_pixels, &static_cast<eac_block*>(pDst)[0]);
+ else
+ (high_quality ? pack_eac_high_quality : pack_eac)(static_cast<eac_block*>(pDst)[0], &block_pixels[0][0].c[chan0], sizeof(color32));
+
+ if (chan1 == 3)
+ transcode_uastc_to_etc2_eac_a8(unpacked_src_blk, block_pixels, &static_cast<eac_block*>(pDst)[1]);
+ else
+ (high_quality ? pack_eac_high_quality : pack_eac)(static_cast<eac_block*>(pDst)[1], &block_pixels[0][0].c[chan1], sizeof(color32));
+ return true;
}
-
- uint32_t basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format fmt)
+
+ // PVRTC1
+ static void fixup_pvrtc1_4_modulation_rgb(
+ const uastc_block* pSrc_blocks,
+ const uint32_t* pPVRTC_endpoints,
+ void* pDst_blocks,
+ uint32_t num_blocks_x, uint32_t num_blocks_y, bool from_alpha)
{
- switch (fmt)
+ const uint32_t x_mask = num_blocks_x - 1;
+ const uint32_t y_mask = num_blocks_y - 1;
+ const uint32_t x_bits = basisu::total_bits(x_mask);
+ const uint32_t y_bits = basisu::total_bits(y_mask);
+ const uint32_t min_bits = basisu::minimum(x_bits, y_bits);
+ //const uint32_t max_bits = basisu::maximum(x_bits, y_bits);
+ const uint32_t swizzle_mask = (1 << (min_bits * 2)) - 1;
+
+ uint32_t block_index = 0;
+
+ // really 3x3
+ int e0[4][4], e1[4][4];
+
+ for (int y = 0; y < static_cast<int>(num_blocks_y); y++)
{
- case transcoder_texture_format::cTFRGBA32:
- return sizeof(uint32_t);
- case transcoder_texture_format::cTFRGB565:
- case transcoder_texture_format::cTFBGR565:
- case transcoder_texture_format::cTFRGBA4444:
- return sizeof(uint16_t);
- default:
- break;
+ const uint32_t* pE_rows[3];
+
+ for (int ey = 0; ey < 3; ey++)
+ {
+ int by = y + ey - 1;
+
+ const uint32_t* pE = &pPVRTC_endpoints[(by & y_mask) * num_blocks_x];
+
+ pE_rows[ey] = pE;
+
+ for (int ex = 0; ex < 3; ex++)
+ {
+ int bx = 0 + ex - 1;
+
+ const uint32_t e = pE[bx & x_mask];
+
+ e0[ex][ey] = (get_opaque_endpoint_l0(e) * 255) / 31;
+ e1[ex][ey] = (get_opaque_endpoint_l1(e) * 255) / 31;
+ }
+ }
+
+ const uint32_t y_swizzle = (g_pvrtc_swizzle_table[y >> 8] << 16) | g_pvrtc_swizzle_table[y & 0xFF];
+
+ for (int x = 0; x < static_cast<int>(num_blocks_x); x++, block_index++)
+ {
+ const uastc_block& src_block = pSrc_blocks[block_index];
+
+ color32 block_pixels[4][4];
+ unpack_uastc(src_block, &block_pixels[0][0], false);
+ if (from_alpha)
+ {
+ // Just set RGB to alpha to avoid adding complexity below.
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ const uint8_t a = ((color32*)block_pixels)[i].a;
+ ((color32*)block_pixels)[i].set(a, a, a, 255);
+ }
+ }
+
+ const uint32_t x_swizzle = (g_pvrtc_swizzle_table[x >> 8] << 17) | (g_pvrtc_swizzle_table[x & 0xFF] << 1);
+
+ uint32_t swizzled = x_swizzle | y_swizzle;
+ if (num_blocks_x != num_blocks_y)
+ {
+ swizzled &= swizzle_mask;
+
+ if (num_blocks_x > num_blocks_y)
+ swizzled |= ((x >> min_bits) << (min_bits * 2));
+ else
+ swizzled |= ((y >> min_bits) << (min_bits * 2));
+ }
+
+ pvrtc4_block* pDst_block = static_cast<pvrtc4_block*>(pDst_blocks) + swizzled;
+ pDst_block->m_endpoints = pPVRTC_endpoints[block_index];
+
+ {
+ const uint32_t ex = 2;
+ int bx = x + ex - 1;
+ bx &= x_mask;
+
+#define DO_ROW(ey) \
+ { \
+ const uint32_t e = pE_rows[ey][bx]; \
+ e0[ex][ey] = (get_opaque_endpoint_l0(e) * 255) / 31; \
+ e1[ex][ey] = (get_opaque_endpoint_l1(e) * 255) / 31; \
+ }
+
+ DO_ROW(0);
+ DO_ROW(1);
+ DO_ROW(2);
+#undef DO_ROW
+ }
+
+ uint32_t mod = 0;
+
+#define DO_PIX(lx, ly, w0, w1, w2, w3) \
+ { \
+ int ca_l = a0 * w0 + a1 * w1 + a2 * w2 + a3 * w3; \
+ int cb_l = b0 * w0 + b1 * w1 + b2 * w2 + b3 * w3; \
+ int cl = (block_pixels[ly][lx].r + block_pixels[ly][lx].g + block_pixels[ly][lx].b) * 16; \
+ int dl = cb_l - ca_l; \
+ int vl = cl - ca_l; \
+ int p = vl * 16; \
+ if (ca_l > cb_l) { p = -p; dl = -dl; } \
+ uint32_t m = 0; \
+ if (p > 3 * dl) m = (uint32_t)(1 << ((ly) * 8 + (lx) * 2)); \
+ if (p > 8 * dl) m = (uint32_t)(2 << ((ly) * 8 + (lx) * 2)); \
+ if (p > 13 * dl) m = (uint32_t)(3 << ((ly) * 8 + (lx) * 2)); \
+ mod |= m; \
+ }
+
+ {
+ const uint32_t ex = 0, ey = 0;
+ const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];
+ const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];
+ DO_PIX(0, 0, 4, 4, 4, 4);
+ DO_PIX(1, 0, 2, 6, 2, 6);
+ DO_PIX(0, 1, 2, 2, 6, 6);
+ DO_PIX(1, 1, 1, 3, 3, 9);
+ }
+
+ {
+ const uint32_t ex = 1, ey = 0;
+ const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];
+ const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];
+ DO_PIX(2, 0, 8, 0, 8, 0);
+ DO_PIX(3, 0, 6, 2, 6, 2);
+ DO_PIX(2, 1, 4, 0, 12, 0);
+ DO_PIX(3, 1, 3, 1, 9, 3);
+ }
+
+ {
+ const uint32_t ex = 0, ey = 1;
+ const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];
+ const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];
+ DO_PIX(0, 2, 8, 8, 0, 0);
+ DO_PIX(1, 2, 4, 12, 0, 0);
+ DO_PIX(0, 3, 6, 6, 2, 2);
+ DO_PIX(1, 3, 3, 9, 1, 3);
+ }
+
+ {
+ const uint32_t ex = 1, ey = 1;
+ const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];
+ const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];
+ DO_PIX(2, 2, 16, 0, 0, 0);
+ DO_PIX(3, 2, 12, 4, 0, 0);
+ DO_PIX(2, 3, 12, 0, 4, 0);
+ DO_PIX(3, 3, 9, 3, 3, 1);
+ }
+#undef DO_PIX
+
+ pDst_block->m_modulation = mod;
+
+ e0[0][0] = e0[1][0]; e0[1][0] = e0[2][0];
+ e0[0][1] = e0[1][1]; e0[1][1] = e0[2][1];
+ e0[0][2] = e0[1][2]; e0[1][2] = e0[2][2];
+
+ e1[0][0] = e1[1][0]; e1[1][0] = e1[2][0];
+ e1[0][1] = e1[1][1]; e1[1][1] = e1[2][1];
+ e1[0][2] = e1[1][2]; e1[1][2] = e1[2][2];
+
+ } // x
+ } // y
+ }
+
+ static void fixup_pvrtc1_4_modulation_rgba(
+ const uastc_block* pSrc_blocks,
+ const uint32_t* pPVRTC_endpoints,
+ void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y)
+ {
+ const uint32_t x_mask = num_blocks_x - 1;
+ const uint32_t y_mask = num_blocks_y - 1;
+ const uint32_t x_bits = basisu::total_bits(x_mask);
+ const uint32_t y_bits = basisu::total_bits(y_mask);
+ const uint32_t min_bits = basisu::minimum(x_bits, y_bits);
+ //const uint32_t max_bits = basisu::maximum(x_bits, y_bits);
+ const uint32_t swizzle_mask = (1 << (min_bits * 2)) - 1;
+
+ uint32_t block_index = 0;
+
+ // really 3x3
+ int e0[4][4], e1[4][4];
+
+ for (int y = 0; y < static_cast<int>(num_blocks_y); y++)
+ {
+ const uint32_t* pE_rows[3];
+
+ for (int ey = 0; ey < 3; ey++)
+ {
+ int by = y + ey - 1;
+
+ const uint32_t* pE = &pPVRTC_endpoints[(by & y_mask) * num_blocks_x];
+
+ pE_rows[ey] = pE;
+
+ for (int ex = 0; ex < 3; ex++)
+ {
+ int bx = 0 + ex - 1;
+
+ const uint32_t e = pE[bx & x_mask];
+
+ e0[ex][ey] = get_endpoint_l8(e, 0);
+ e1[ex][ey] = get_endpoint_l8(e, 1);
+ }
+ }
+
+ const uint32_t y_swizzle = (g_pvrtc_swizzle_table[y >> 8] << 16) | g_pvrtc_swizzle_table[y & 0xFF];
+
+ for (int x = 0; x < static_cast<int>(num_blocks_x); x++, block_index++)
+ {
+ const uastc_block& src_block = pSrc_blocks[block_index];
+
+ color32 block_pixels[4][4];
+ unpack_uastc(src_block, &block_pixels[0][0], false);
+
+ const uint32_t x_swizzle = (g_pvrtc_swizzle_table[x >> 8] << 17) | (g_pvrtc_swizzle_table[x & 0xFF] << 1);
+
+ uint32_t swizzled = x_swizzle | y_swizzle;
+ if (num_blocks_x != num_blocks_y)
+ {
+ swizzled &= swizzle_mask;
+
+ if (num_blocks_x > num_blocks_y)
+ swizzled |= ((x >> min_bits) << (min_bits * 2));
+ else
+ swizzled |= ((y >> min_bits) << (min_bits * 2));
+ }
+
+ pvrtc4_block* pDst_block = static_cast<pvrtc4_block*>(pDst_blocks) + swizzled;
+ pDst_block->m_endpoints = pPVRTC_endpoints[block_index];
+
+ {
+ const uint32_t ex = 2;
+ int bx = x + ex - 1;
+ bx &= x_mask;
+
+#define DO_ROW(ey) \
+ { \
+ const uint32_t e = pE_rows[ey][bx]; \
+ e0[ex][ey] = get_endpoint_l8(e, 0); \
+ e1[ex][ey] = get_endpoint_l8(e, 1); \
+ }
+
+ DO_ROW(0);
+ DO_ROW(1);
+ DO_ROW(2);
+#undef DO_ROW
+ }
+
+ uint32_t mod = 0;
+
+#define DO_PIX(lx, ly, w0, w1, w2, w3) \
+ { \
+ int ca_l = a0 * w0 + a1 * w1 + a2 * w2 + a3 * w3; \
+ int cb_l = b0 * w0 + b1 * w1 + b2 * w2 + b3 * w3; \
+ int cl = 16 * (block_pixels[ly][lx].r + block_pixels[ly][lx].g + block_pixels[ly][lx].b + block_pixels[ly][lx].a); \
+ int dl = cb_l - ca_l; \
+ int vl = cl - ca_l; \
+ int p = vl * 16; \
+ if (ca_l > cb_l) { p = -p; dl = -dl; } \
+ uint32_t m = 0; \
+ if (p > 3 * dl) m = (uint32_t)(1 << ((ly) * 8 + (lx) * 2)); \
+ if (p > 8 * dl) m = (uint32_t)(2 << ((ly) * 8 + (lx) * 2)); \
+ if (p > 13 * dl) m = (uint32_t)(3 << ((ly) * 8 + (lx) * 2)); \
+ mod |= m; \
+ }
+
+ {
+ const uint32_t ex = 0, ey = 0;
+ const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];
+ const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];
+ DO_PIX(0, 0, 4, 4, 4, 4);
+ DO_PIX(1, 0, 2, 6, 2, 6);
+ DO_PIX(0, 1, 2, 2, 6, 6);
+ DO_PIX(1, 1, 1, 3, 3, 9);
+ }
+
+ {
+ const uint32_t ex = 1, ey = 0;
+ const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];
+ const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];
+ DO_PIX(2, 0, 8, 0, 8, 0);
+ DO_PIX(3, 0, 6, 2, 6, 2);
+ DO_PIX(2, 1, 4, 0, 12, 0);
+ DO_PIX(3, 1, 3, 1, 9, 3);
+ }
+
+ {
+ const uint32_t ex = 0, ey = 1;
+ const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];
+ const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];
+ DO_PIX(0, 2, 8, 8, 0, 0);
+ DO_PIX(1, 2, 4, 12, 0, 0);
+ DO_PIX(0, 3, 6, 6, 2, 2);
+ DO_PIX(1, 3, 3, 9, 1, 3);
+ }
+
+ {
+ const uint32_t ex = 1, ey = 1;
+ const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];
+ const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];
+ DO_PIX(2, 2, 16, 0, 0, 0);
+ DO_PIX(3, 2, 12, 4, 0, 0);
+ DO_PIX(2, 3, 12, 0, 4, 0);
+ DO_PIX(3, 3, 9, 3, 3, 1);
+ }
+#undef DO_PIX
+
+ pDst_block->m_modulation = mod;
+
+ e0[0][0] = e0[1][0]; e0[1][0] = e0[2][0];
+ e0[0][1] = e0[1][1]; e0[1][1] = e0[2][1];
+ e0[0][2] = e0[1][2]; e0[1][2] = e0[2][2];
+
+ e1[0][0] = e1[1][0]; e1[1][0] = e1[2][0];
+ e1[0][1] = e1[1][1]; e1[1][1] = e1[2][1];
+ e1[0][2] = e1[1][2]; e1[1][2] = e1[2][2];
+
+ } // x
+ } // y
+ }
+
+ bool transcode_uastc_to_pvrtc1_4_rgb(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality, bool from_alpha)
+ {
+ BASISU_NOTE_UNUSED(high_quality);
+
+ if ((!num_blocks_x) || (!num_blocks_y))
+ return false;
+
+ const uint32_t width = num_blocks_x * 4;
+ const uint32_t height = num_blocks_y * 4;
+ if (!basisu::is_pow2(width) || !basisu::is_pow2(height))
+ return false;
+
+ basisu::vector<uint32_t> temp_endpoints(num_blocks_x * num_blocks_y);
+
+ for (uint32_t y = 0; y < num_blocks_y; y++)
+ {
+ for (uint32_t x = 0; x < num_blocks_x; x++)
+ {
+ color32 block_pixels[16];
+ if (!unpack_uastc(pSrc_blocks[x + y * num_blocks_x], block_pixels, false))
+ return false;
+
+ // Get block's RGB bounding box
+ color32 low_color(255, 255, 255, 255), high_color(0, 0, 0, 0);
+
+ if (from_alpha)
+ {
+ uint32_t low_a = 255, high_a = 0;
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ low_a = basisu::minimum<uint32_t>(low_a, block_pixels[i].a);
+ high_a = basisu::maximum<uint32_t>(high_a, block_pixels[i].a);
+ }
+ low_color.set(low_a, low_a, low_a, 255);
+ high_color.set(high_a, high_a, high_a, 255);
+ }
+ else
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ low_color = color32::comp_min(low_color, block_pixels[i]);
+ high_color = color32::comp_max(high_color, block_pixels[i]);
+ }
+ }
+
+ // Set PVRTC1 endpoints to floor/ceil of bounding box's coordinates.
+ pvrtc4_block temp;
+ temp.set_opaque_endpoint_floor(0, low_color);
+ temp.set_opaque_endpoint_ceil(1, high_color);
+
+ temp_endpoints[x + y * num_blocks_x] = temp.m_endpoints;
+ }
}
- return 0;
+
+ fixup_pvrtc1_4_modulation_rgb(pSrc_blocks, &temp_endpoints[0], pDst_blocks, num_blocks_x, num_blocks_y, from_alpha);
+
+ return true;
}
-
- uint32_t basis_get_block_width(transcoder_texture_format tex_type)
+
+ bool transcode_uastc_to_pvrtc1_4_rgba(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality)
{
- switch (tex_type)
+ BASISU_NOTE_UNUSED(high_quality);
+
+ if ((!num_blocks_x) || (!num_blocks_y))
+ return false;
+
+ const uint32_t width = num_blocks_x * 4;
+ const uint32_t height = num_blocks_y * 4;
+ if (!basisu::is_pow2(width) || !basisu::is_pow2(height))
+ return false;
+
+ basisu::vector<uint32_t> temp_endpoints(num_blocks_x * num_blocks_y);
+
+ for (uint32_t y = 0; y < num_blocks_y; y++)
{
- case transcoder_texture_format::cTFFXT1_RGB:
- return 8;
- default:
+ for (uint32_t x = 0; x < num_blocks_x; x++)
+ {
+ color32 block_pixels[16];
+ if (!unpack_uastc(pSrc_blocks[x + y * num_blocks_x], block_pixels, false))
+ return false;
+
+ // Get block's RGBA bounding box
+ color32 low_color(255, 255, 255, 255), high_color(0, 0, 0, 0);
+
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ low_color = color32::comp_min(low_color, block_pixels[i]);
+ high_color = color32::comp_max(high_color, block_pixels[i]);
+ }
+
+ // Set PVRTC1 endpoints to floor/ceil of bounding box's coordinates.
+ pvrtc4_block temp;
+ temp.set_endpoint_floor(0, low_color);
+ temp.set_endpoint_ceil(1, high_color);
+
+ temp_endpoints[x + y * num_blocks_x] = temp.m_endpoints;
+ }
+ }
+
+ fixup_pvrtc1_4_modulation_rgba(pSrc_blocks, &temp_endpoints[0], pDst_blocks, num_blocks_x, num_blocks_y);
+
+ return true;
+ }
+
+ void uastc_init()
+ {
+ for (uint32_t range = 0; range < BC7ENC_TOTAL_ASTC_RANGES; range++)
+ {
+ if (!astc_is_valid_endpoint_range(range))
+ continue;
+
+ const uint32_t levels = astc_get_levels(range);
+
+ uint32_t vals[256];
+ for (uint32_t i = 0; i < levels; i++)
+ vals[i] = (unquant_astc_endpoint_val(i, range) << 8) | i;
+
+ std::sort(vals, vals + levels);
+
+ for (uint32_t i = 0; i < levels; i++)
+ {
+ const uint32_t order = vals[i] & 0xFF;
+ const uint32_t unq = vals[i] >> 8;
+
+ g_astc_unquant[range][order].m_unquant = (uint8_t)unq;
+ g_astc_unquant[range][order].m_index = (uint8_t)i;
+
+ } // i
+ }
+
+ // TODO: Precompute?
+ // BC7 777.1
+ for (int c = 0; c < 256; c++)
+ {
+ for (uint32_t lp = 0; lp < 2; lp++)
+ {
+ endpoint_err best;
+ best.m_error = (uint16_t)UINT16_MAX;
+
+ for (uint32_t l = 0; l < 128; l++)
+ {
+ const uint32_t low = (l << 1) | lp;
+
+ for (uint32_t h = 0; h < 128; h++)
+ {
+ const uint32_t high = (h << 1) | lp;
+
+ const int k = (low * (64 - g_bc7_weights4[BC7ENC_MODE_6_OPTIMAL_INDEX]) + high * g_bc7_weights4[BC7ENC_MODE_6_OPTIMAL_INDEX] + 32) >> 6;
+
+ const int err = (k - c) * (k - c);
+ if (err < best.m_error)
+ {
+ best.m_error = (uint16_t)err;
+ best.m_lo = (uint8_t)l;
+ best.m_hi = (uint8_t)h;
+ }
+ } // h
+ } // l
+
+ g_bc7_mode_6_optimal_endpoints[c][lp] = best;
+ } // lp
+
+ } // c
+
+ // BC7 777
+ for (int c = 0; c < 256; c++)
+ {
+ endpoint_err best;
+ best.m_error = (uint16_t)UINT16_MAX;
+
+ for (uint32_t l = 0; l < 128; l++)
+ {
+ const uint32_t low = (l << 1) | (l >> 6);
+
+ for (uint32_t h = 0; h < 128; h++)
+ {
+ const uint32_t high = (h << 1) | (h >> 6);
+
+ const int k = (low * (64 - g_bc7_weights2[BC7ENC_MODE_5_OPTIMAL_INDEX]) + high * g_bc7_weights2[BC7ENC_MODE_5_OPTIMAL_INDEX] + 32) >> 6;
+
+ const int err = (k - c) * (k - c);
+ if (err < best.m_error)
+ {
+ best.m_error = (uint16_t)err;
+ best.m_lo = (uint8_t)l;
+ best.m_hi = (uint8_t)h;
+ }
+ } // h
+ } // l
+
+ g_bc7_mode_5_optimal_endpoints[c] = best;
+
+ } // c
+ }
+
+#endif // #if BASISD_SUPPORT_UASTC
+
+// ------------------------------------------------------------------------------------------------------
+// KTX2
+// ------------------------------------------------------------------------------------------------------
+
+#if BASISD_SUPPORT_KTX2
+ const uint8_t g_ktx2_file_identifier[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
+
+ ktx2_transcoder::ktx2_transcoder(basist::etc1_global_selector_codebook* pGlobal_sel_codebook) :
+ m_etc1s_transcoder(pGlobal_sel_codebook)
+ {
+ clear();
+ }
+
+ void ktx2_transcoder::clear()
+ {
+ m_pData = nullptr;
+ m_data_size = 0;
+
+ memset(&m_header, 0, sizeof(m_header));
+ m_levels.clear();
+ m_dfd.clear();
+ m_key_values.clear();
+ memset(&m_etc1s_header, 0, sizeof(m_etc1s_header));
+ m_etc1s_image_descs.clear();
+
+ m_format = basist::basis_tex_format::cETC1S;
+
+ m_dfd_color_model = 0;
+ m_dfd_color_prims = KTX2_DF_PRIMARIES_UNSPECIFIED;
+ m_dfd_transfer_func = 0;
+ m_dfd_flags = 0;
+ m_dfd_samples = 0;
+ m_dfd_chan0 = KTX2_DF_CHANNEL_UASTC_RGB;
+ m_dfd_chan1 = KTX2_DF_CHANNEL_UASTC_RGB;
+
+ m_etc1s_transcoder.clear();
+
+ m_def_transcoder_state.clear();
+
+ m_has_alpha = false;
+ m_is_video = false;
+ }
+
+ bool ktx2_transcoder::init(const void* pData, uint32_t data_size)
+ {
+ clear();
+
+ if (!pData)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: pData is nullptr\n");
+ assert(0);
+ return false;
+ }
+
+ if (data_size <= sizeof(ktx2_header))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: File is impossibly too small to be a valid KTX2 file\n");
+ return false;
+ }
+
+ if (memcmp(pData, g_ktx2_file_identifier, sizeof(g_ktx2_file_identifier)) != 0)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: KTX2 file identifier is not present\n");
+ return false;
+ }
+
+ m_pData = static_cast<const uint8_t *>(pData);
+ m_data_size = data_size;
+
+ memcpy(&m_header, pData, sizeof(m_header));
+
+ // We only support UASTC and ETC1S
+ if (m_header.m_vk_format != KTX2_VK_FORMAT_UNDEFINED)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: KTX2 file must be in ETC1S or UASTC format\n");
+ return false;
+ }
+
+ // 3.3: "When format is VK_FORMAT_UNDEFINED, typeSize must equal 1."
+ if (m_header.m_type_size != 1)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid type_size\n");
+ return false;
+ }
+
+ // We only currently support 2D textures (plain, cubemapped, or texture array), which is by far the most common use case.
+ // The BasisU library does not support 1D or 3D textures at all.
+ if ((m_header.m_pixel_width < 1) || (m_header.m_pixel_height < 1) || (m_header.m_pixel_depth > 0))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Only 2D or cubemap textures are supported\n");
+ return false;
+ }
+
+ // Face count must be 1 or 6
+ if ((m_header.m_face_count != 1) && (m_header.m_face_count != 6))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid face count, file is corrupted or invalid\n");
+ return false;
+ }
+
+ if (m_header.m_face_count > 1)
+ {
+ // 3.4: Make sure cubemaps are square.
+ if (m_header.m_pixel_width != m_header.m_pixel_height)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Cubemap is not square\n");
+ return false;
+ }
+ }
+
+ // 3.7 levelCount: "levelCount=0 is allowed, except for block-compressed formats"
+ if (m_header.m_level_count < 1)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level count\n");
+ return false;
+ }
+
+ // Sanity check the level count.
+ if (m_header.m_level_count > KTX2_MAX_SUPPORTED_LEVEL_COUNT)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Too many levels or file is corrupted or invalid\n");
+ return false;
+ }
+
+ if (m_header.m_supercompression_scheme > KTX2_SS_ZSTANDARD)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid/unsupported supercompression or file is corrupted or invalid\n");
+ return false;
+ }
+
+ if (m_header.m_supercompression_scheme == KTX2_SS_BASISLZ)
+ {
+ if (m_header.m_sgd_byte_length <= sizeof(ktx2_etc1s_global_data_header))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Supercompression global data is too small\n");
+ return false;
+ }
+
+ if (m_header.m_sgd_byte_offset < sizeof(ktx2_header))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Supercompression global data offset is too low\n");
+ return false;
+ }
+
+ if (m_header.m_sgd_byte_offset + m_header.m_sgd_byte_length > m_data_size)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Supercompression global data offset and/or length is too high\n");
+ return false;
+ }
+ }
+
+ if (!m_levels.try_resize(m_header.m_level_count))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Out of memory\n");
+ return false;
+ }
+
+ const uint32_t level_index_size_in_bytes = basisu::maximum(1U, (uint32_t)m_header.m_level_count) * sizeof(ktx2_level_index);
+
+ if ((sizeof(ktx2_header) + level_index_size_in_bytes) > m_data_size)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: File is too small (can't read level index array)\n");
+ return false;
+ }
+
+ memcpy(&m_levels[0], m_pData + sizeof(ktx2_header), level_index_size_in_bytes);
+
+ // Sanity check the level offsets and byte sizes
+ for (uint32_t i = 0; i < m_levels.size(); i++)
+ {
+ if (m_levels[i].m_byte_offset < sizeof(ktx2_header))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level offset (too low)\n");
+ return false;
+ }
+
+ if (!m_levels[i].m_byte_length)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level byte length\n");
+ }
+
+ if ((m_levels[i].m_byte_offset + m_levels[i].m_byte_length) > m_data_size)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level offset and/or length\n");
+ return false;
+ }
+
+ const uint64_t MAX_SANE_LEVEL_UNCOMP_SIZE = 2048ULL * 1024ULL * 1024ULL;
+
+ if (m_levels[i].m_uncompressed_byte_length >= MAX_SANE_LEVEL_UNCOMP_SIZE)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level offset (too large)\n");
+ return false;
+ }
+
+ if (m_header.m_supercompression_scheme == KTX2_SS_BASISLZ)
+ {
+ if (m_levels[i].m_uncompressed_byte_length)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid uncompressed length (0)\n");
+ return false;
+ }
+ }
+ else if (m_header.m_supercompression_scheme >= KTX2_SS_ZSTANDARD)
+ {
+ if (!m_levels[i].m_uncompressed_byte_length)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid uncompressed length (1)\n");
+ return false;
+ }
+ }
+ }
+
+ const uint32_t DFD_MINIMUM_SIZE = 44, DFD_MAXIMUM_SIZE = 60;
+ if ((m_header.m_dfd_byte_length != DFD_MINIMUM_SIZE) && (m_header.m_dfd_byte_length != DFD_MAXIMUM_SIZE))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Unsupported DFD size\n");
+ return false;
+ }
+
+ if (((m_header.m_dfd_byte_offset + m_header.m_dfd_byte_length) > m_data_size) || (m_header.m_dfd_byte_offset < sizeof(ktx2_header)))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid DFD offset and/or length\n");
+ return false;
+ }
+
+ const uint8_t* pDFD = m_pData + m_header.m_dfd_byte_offset;
+
+ if (!m_dfd.try_resize(m_header.m_dfd_byte_length))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Out of memory\n");
+ return false;
+ }
+
+ memcpy(m_dfd.data(), pDFD, m_header.m_dfd_byte_length);
+
+ // This is all hard coded for only ETC1S and UASTC.
+ uint32_t dfd_total_size = basisu::read_le_dword(pDFD);
+
+ // 3.10.3: Sanity check
+ if (dfd_total_size != m_header.m_dfd_byte_length)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: DFD size validation failed (1)\n");
+ return false;
+ }
+
+ // 3.10.3: More sanity checking
+ if (m_header.m_kvd_byte_length)
+ {
+ if (dfd_total_size != m_header.m_kvd_byte_offset - m_header.m_dfd_byte_offset)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: DFD size validation failed (2)\n");
+ return false;
+ }
+ }
+
+ const uint32_t dfd_bits = basisu::read_le_dword(pDFD + 3 * sizeof(uint32_t));
+ const uint32_t sample_channel0 = basisu::read_le_dword(pDFD + 7 * sizeof(uint32_t));
+
+ m_dfd_color_model = dfd_bits & 255;
+ m_dfd_color_prims = (ktx2_df_color_primaries)((dfd_bits >> 8) & 255);
+ m_dfd_transfer_func = (dfd_bits >> 16) & 255;
+ m_dfd_flags = (dfd_bits >> 24) & 255;
+
+ // See 3.10.1.Restrictions
+ if ((m_dfd_transfer_func != KTX2_KHR_DF_TRANSFER_LINEAR) && (m_dfd_transfer_func != KTX2_KHR_DF_TRANSFER_SRGB))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid DFD transfer function\n");
+ return false;
+ }
+
+ if (m_dfd_color_model == KTX2_KDF_DF_MODEL_ETC1S)
+ {
+ m_format = basist::basis_tex_format::cETC1S;
+
+ // 3.10.2: "Whether the image has 1 or 2 slices can be determined from the DFD’s sample count."
+ // If m_has_alpha is true it may be 2-channel RRRG or 4-channel RGBA, but we let the caller deal with that.
+ m_has_alpha = (m_header.m_dfd_byte_length == 60);
+
+ m_dfd_samples = m_has_alpha ? 2 : 1;
+ m_dfd_chan0 = (ktx2_df_channel_id)((sample_channel0 >> 24) & 15);
+
+ if (m_has_alpha)
+ {
+ const uint32_t sample_channel1 = basisu::read_le_dword(pDFD + 11 * sizeof(uint32_t));
+ m_dfd_chan1 = (ktx2_df_channel_id)((sample_channel1 >> 24) & 15);
+ }
+ }
+ else if (m_dfd_color_model == KTX2_KDF_DF_MODEL_UASTC)
+ {
+ m_format = basist::basis_tex_format::cUASTC4x4;
+
+ m_dfd_samples = 1;
+ m_dfd_chan0 = (ktx2_df_channel_id)((sample_channel0 >> 24) & 15);
+
+ // We're assuming "DATA" means RGBA so it has alpha.
+ m_has_alpha = (m_dfd_chan0 == KTX2_DF_CHANNEL_UASTC_RGBA) || (m_dfd_chan0 == KTX2_DF_CHANNEL_UASTC_RRRG);
+ }
+ else
+ {
+ // Unsupported DFD color model.
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: Unsupported DFD color model\n");
+ return false;
+ }
+
+ if (!read_key_values())
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::init: read_key_values() failed\n");
+ return false;
+ }
+
+ // Check for a KTXanimData key
+ for (uint32_t i = 0; i < m_key_values.size(); i++)
+ {
+ if (strcmp(reinterpret_cast<const char*>(m_key_values[i].m_key.data()), "KTXanimData") == 0)
+ {
+ m_is_video = true;
break;
+ }
}
- return 4;
+
+ return true;
}
- uint32_t basis_get_block_height(transcoder_texture_format tex_type)
+ uint32_t ktx2_transcoder::get_etc1s_image_descs_image_flags(uint32_t level_index, uint32_t layer_index, uint32_t face_index) const
{
- (void)tex_type;
- return 4;
+ const uint32_t etc1s_image_index =
+ (level_index * basisu::maximum<uint32_t>(m_header.m_layer_count, 1) * m_header.m_face_count) +
+ layer_index * m_header.m_face_count +
+ face_index;
+
+ if (etc1s_image_index >= get_etc1s_image_descs().size())
+ {
+ assert(0);
+ return 0;
+ }
+
+ return get_etc1s_image_descs()[etc1s_image_index].m_image_flags;
+ }
+
+ const basisu::uint8_vec* ktx2_transcoder::find_key(const std::string& key_name) const
+ {
+ for (uint32_t i = 0; i < m_key_values.size(); i++)
+ if (strcmp((const char *)m_key_values[i].m_key.data(), key_name.c_str()) == 0)
+ return &m_key_values[i].m_value;
+
+ return nullptr;
}
- bool basis_is_format_supported(transcoder_texture_format tex_type)
+ bool ktx2_transcoder::start_transcoding()
{
- switch (tex_type)
+ if (!m_pData)
{
- // ETC1 and uncompressed are always supported.
- case transcoder_texture_format::cTFETC1_RGB:
- case transcoder_texture_format::cTFRGBA32:
- case transcoder_texture_format::cTFRGB565:
- case transcoder_texture_format::cTFBGR565:
- case transcoder_texture_format::cTFRGBA4444:
- return true;
-#if BASISD_SUPPORT_DXT1
- case transcoder_texture_format::cTFBC1_RGB:
- return true;
-#endif
-#if BASISD_SUPPORT_DXT5A
- case transcoder_texture_format::cTFBC4_R:
- case transcoder_texture_format::cTFBC5_RG:
- return true;
-#endif
-#if BASISD_SUPPORT_DXT1 && BASISD_SUPPORT_DXT5A
- case transcoder_texture_format::cTFBC3_RGBA:
- return true;
-#endif
-#if BASISD_SUPPORT_PVRTC1
- case transcoder_texture_format::cTFPVRTC1_4_RGB:
- case transcoder_texture_format::cTFPVRTC1_4_RGBA:
- return true;
-#endif
-#if BASISD_SUPPORT_BC7_MODE6_OPAQUE_ONLY
- case transcoder_texture_format::cTFBC7_M6_RGB:
- return true;
-#endif
-#if BASISD_SUPPORT_BC7_MODE5
- case transcoder_texture_format::cTFBC7_M5_RGBA:
- return true;
-#endif
-#if BASISD_SUPPORT_ETC2_EAC_A8
- case transcoder_texture_format::cTFETC2_RGBA:
- return true;
-#endif
-#if BASISD_SUPPORT_ASTC
- case transcoder_texture_format::cTFASTC_4x4_RGBA:
- return true;
-#endif
-#if BASISD_SUPPORT_ATC
- case transcoder_texture_format::cTFATC_RGB:
- case transcoder_texture_format::cTFATC_RGBA:
- return true;
-#endif
-#if BASISD_SUPPORT_FXT1
- case transcoder_texture_format::cTFFXT1_RGB:
- return true;
+ BASISU_DEVEL_ERROR("ktx2_transcoder::start_transcoding: Must call init() first\n");
+ return false;
+ }
+
+ if (m_header.m_supercompression_scheme == KTX2_SS_BASISLZ)
+ {
+ // Check if we've already decompressed the ETC1S global data. If so don't unpack it again.
+ if (!m_etc1s_transcoder.get_endpoints().empty())
+ return true;
+
+ if (!decompress_etc1s_global_data())
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::start_transcoding: decompress_etc1s_global_data() failed\n");
+ return false;
+ }
+
+ if (!m_is_video)
+ {
+ // See if there are any P-frames. If so it must be a video, even if there wasn't a KTXanimData key.
+ // Video cannot be a cubemap, and it must be a texture array.
+ if ((m_header.m_face_count == 1) && (m_header.m_layer_count > 1))
+ {
+ for (uint32_t i = 0; i < m_etc1s_image_descs.size(); i++)
+ {
+ if (m_etc1s_image_descs[i].m_image_flags & KTX2_IMAGE_IS_P_FRAME)
+ {
+ m_is_video = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (m_header.m_supercompression_scheme == KTX2_SS_ZSTANDARD)
+ {
+#if !BASISD_SUPPORT_KTX2_ZSTD
+ BASISU_DEVEL_ERROR("ktx2_transcoder::start_transcoding: File uses zstd supercompression, but zstd support was not enabled at compilation time (BASISD_SUPPORT_KTX2_ZSTD == 0)\n");
+ return false;
#endif
-#if BASISD_SUPPORT_PVRTC2
- case transcoder_texture_format::cTFPVRTC2_4_RGB:
- case transcoder_texture_format::cTFPVRTC2_4_RGBA:
- return true;
+ }
+
+ return true;
+ }
+
+ bool ktx2_transcoder::get_image_level_info(ktx2_image_level_info& level_info, uint32_t level_index, uint32_t layer_index, uint32_t face_index) const
+ {
+ if (level_index >= m_levels.size())
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::get_image_level_info: level_index >= m_levels.size()\n");
+ return false;
+ }
+
+ if (m_header.m_face_count > 1)
+ {
+ if (face_index >= 6)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::get_image_level_info: face_index >= 6\n");
+ return false;
+ }
+ }
+ else if (face_index != 0)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::get_image_level_info: face_index != 0\n");
+ return false;
+ }
+
+ if (layer_index >= basisu::maximum<uint32_t>(m_header.m_layer_count, 1))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::get_image_level_info: layer_index >= maximum<uint32_t>(m_header.m_layer_count, 1)\n");
+ return false;
+ }
+
+ const uint32_t level_width = basisu::maximum<uint32_t>(m_header.m_pixel_width >> level_index, 1);
+ const uint32_t level_height = basisu::maximum<uint32_t>(m_header.m_pixel_height >> level_index, 1);
+ const uint32_t num_blocks_x = (level_width + 3) >> 2;
+ const uint32_t num_blocks_y = (level_height + 3) >> 2;
+
+ level_info.m_face_index = face_index;
+ level_info.m_layer_index = layer_index;
+ level_info.m_level_index = level_index;
+ level_info.m_orig_width = level_width;
+ level_info.m_orig_height = level_height;
+ level_info.m_width = num_blocks_x * 4;
+ level_info.m_height = num_blocks_y * 4;
+ level_info.m_num_blocks_x = num_blocks_x;
+ level_info.m_num_blocks_y = num_blocks_y;
+ level_info.m_total_blocks = num_blocks_x * num_blocks_y;
+ level_info.m_alpha_flag = m_has_alpha;
+ level_info.m_iframe_flag = false;
+ if (m_etc1s_image_descs.size())
+ {
+ const uint32_t etc1s_image_index =
+ (level_index * basisu::maximum<uint32_t>(m_header.m_layer_count, 1) * m_header.m_face_count) +
+ layer_index * m_header.m_face_count +
+ face_index;
+
+ level_info.m_iframe_flag = (m_etc1s_image_descs[etc1s_image_index].m_image_flags & KTX2_IMAGE_IS_P_FRAME) == 0;
+ }
+
+ return true;
+ }
+
+ bool ktx2_transcoder::transcode_image_level(
+ uint32_t level_index, uint32_t layer_index, uint32_t face_index,
+ void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
+ basist::transcoder_texture_format fmt,
+ uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, uint32_t output_rows_in_pixels, int channel0, int channel1,
+ ktx2_transcoder_state* pState)
+ {
+ if (!m_pData)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: Must call init() first\n");
+ return false;
+ }
+
+ if (!pState)
+ pState = &m_def_transcoder_state;
+
+ if (level_index >= m_levels.size())
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: level_index >= m_levels.size()\n");
+ return false;
+ }
+
+ if (m_header.m_face_count > 1)
+ {
+ if (face_index >= 6)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: face_index >= 6\n");
+ return false;
+ }
+ }
+ else if (face_index != 0)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: face_index != 0\n");
+ return false;
+ }
+
+ if (layer_index >= basisu::maximum<uint32_t>(m_header.m_layer_count, 1))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: layer_index >= maximum<uint32_t>(m_header.m_layer_count, 1)\n");
+ return false;
+ }
+
+ const uint8_t* pComp_level_data = m_pData + m_levels[level_index].m_byte_offset;
+ uint64_t comp_level_data_size = m_levels[level_index].m_byte_length;
+
+ const uint8_t* pUncomp_level_data = pComp_level_data;
+ uint64_t uncomp_level_data_size = comp_level_data_size;
+
+ if (uncomp_level_data_size > UINT32_MAX)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: uncomp_level_data_size > UINT32_MAX\n");
+ return false;
+ }
+
+ if (m_header.m_supercompression_scheme == KTX2_SS_ZSTANDARD)
+ {
+ // Check if we've already decompressed this level's supercompressed data.
+ if ((int)level_index != pState->m_uncomp_data_level_index)
+ {
+ // Uncompress the entire level's supercompressed data.
+ if (!decompress_level_data(level_index, pState->m_level_uncomp_data))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: decompress_level_data() failed\n");
+ return false;
+ }
+ pState->m_uncomp_data_level_index = level_index;
+ }
+
+ pUncomp_level_data = pState->m_level_uncomp_data.data();
+ uncomp_level_data_size = pState->m_level_uncomp_data.size();
+ }
+
+ const uint32_t level_width = basisu::maximum<uint32_t>(m_header.m_pixel_width >> level_index, 1);
+ const uint32_t level_height = basisu::maximum<uint32_t>(m_header.m_pixel_height >> level_index, 1);
+ const uint32_t num_blocks_x = (level_width + 3) >> 2;
+ const uint32_t num_blocks_y = (level_height + 3) >> 2;
+
+ if (m_format == basist::basis_tex_format::cETC1S)
+ {
+ // Ensure start_transcoding() was called.
+ if (m_etc1s_transcoder.get_endpoints().empty())
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: must call start_transcoding() first\n");
+ return false;
+ }
+
+ const uint32_t etc1s_image_index =
+ (level_index * basisu::maximum<uint32_t>(m_header.m_layer_count, 1) * m_header.m_face_count) +
+ layer_index * m_header.m_face_count +
+ face_index;
+
+ // Sanity check
+ if (etc1s_image_index >= m_etc1s_image_descs.size())
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: etc1s_image_index >= m_etc1s_image_descs.size()\n");
+ assert(0);
+ return false;
+ }
+
+ if (static_cast<uint32_t>(m_data_size) != m_data_size)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: File is too large\n");
+ return false;
+ }
+
+ const ktx2_etc1s_image_desc& image_desc = m_etc1s_image_descs[etc1s_image_index];
+
+ if (!m_etc1s_transcoder.transcode_image(fmt,
+ pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, m_pData, static_cast<uint32_t>(m_data_size),
+ num_blocks_x, num_blocks_y, level_width, level_height,
+ level_index,
+ m_levels[level_index].m_byte_offset + image_desc.m_rgb_slice_byte_offset, image_desc.m_rgb_slice_byte_length,
+ image_desc.m_alpha_slice_byte_length ? (m_levels[level_index].m_byte_offset + image_desc.m_alpha_slice_byte_offset) : 0, image_desc.m_alpha_slice_byte_length,
+ decode_flags, m_has_alpha,
+ m_is_video, output_row_pitch_in_blocks_or_pixels, &pState->m_transcoder_state, output_rows_in_pixels))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: ETC1S transcode_image() failed, this is either a bug or the file is corrupted/invalid\n");
+ return false;
+ }
+ }
+ else if (m_format == basist::basis_tex_format::cUASTC4x4)
+ {
+ // Compute length and offset to uncompressed 2D UASTC texture data, given the face/layer indices.
+ assert(uncomp_level_data_size == m_levels[level_index].m_uncompressed_byte_length);
+ const uint32_t total_2D_image_size = num_blocks_x * num_blocks_y * KTX2_UASTC_BLOCK_SIZE;
+
+ const uint32_t uncomp_ofs = (layer_index * m_header.m_face_count + face_index) * total_2D_image_size;
+
+ // Sanity checks
+ if (uncomp_ofs >= uncomp_level_data_size)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: uncomp_ofs >= total_2D_image_size\n");
+ return false;
+ }
+
+ if ((uncomp_level_data_size - uncomp_ofs) < total_2D_image_size)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: (uncomp_level_data_size - uncomp_ofs) < total_2D_image_size\n");
+ return false;
+ }
+
+ if (!m_uastc_transcoder.transcode_image(fmt,
+ pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels,
+ (const uint8_t*)pUncomp_level_data + uncomp_ofs, (uint32_t)total_2D_image_size, num_blocks_x, num_blocks_y, level_width, level_height, level_index,
+ 0, (uint32_t)total_2D_image_size,
+ decode_flags, m_has_alpha, m_is_video, output_row_pitch_in_blocks_or_pixels, nullptr, output_rows_in_pixels, channel0, channel1))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: UASTC transcode_image() failed, this is either a bug or the file is corrupted/invalid\n");
+ return false;
+ }
+ }
+ else
+ {
+ // Shouldn't get here.
+ BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: Internal error\n");
+ assert(0);
+ return false;
+ }
+
+ return true;
+ }
+
+ bool ktx2_transcoder::decompress_level_data(uint32_t level_index, basisu::uint8_vec& uncomp_data)
+ {
+ const uint8_t* pComp_data = m_levels[level_index].m_byte_offset + m_pData;
+ const uint64_t comp_size = m_levels[level_index].m_byte_length;
+
+ const uint64_t uncomp_size = m_levels[level_index].m_uncompressed_byte_length;
+
+ if (((size_t)comp_size) != comp_size)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Compressed data too large\n");
+ return false;
+ }
+ if (((size_t)uncomp_size) != uncomp_size)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Uncompressed data too large\n");
+ return false;
+ }
+
+ if (!uncomp_data.try_resize(uncomp_size))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Out of memory\n");
+ return false;
+ }
+
+ if (m_header.m_supercompression_scheme == KTX2_SS_ZSTANDARD)
+ {
+#if BASISD_SUPPORT_KTX2_ZSTD
+ size_t actualUncompSize = ZSTD_decompress(uncomp_data.data(), (size_t)uncomp_size, pComp_data, (size_t)comp_size);
+ if (ZSTD_isError(actualUncompSize))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Zstd decompression failed, file is invalid or corrupted\n");
+ return false;
+ }
+ if (actualUncompSize != uncomp_size)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Zstd decompression returned too few bytes, file is invalid or corrupted\n");
+ return false;
+ }
+#else
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: File uses Zstd supercompression, but Zstd support was not enabled at compile time (BASISD_SUPPORT_KTX2_ZSTD is 0)\n");
+ return false;
#endif
-#if BASISD_SUPPORT_ETC2_EAC_RG11
- case transcoder_texture_format::cTFETC2_EAC_R11:
- case transcoder_texture_format::cTFETC2_EAC_RG11:
+ }
+
+ return true;
+ }
+
+ bool ktx2_transcoder::decompress_etc1s_global_data()
+ {
+ // Note: we don't actually support 3D textures in here yet
+ //uint32_t layer_pixel_depth = basisu::maximum<uint32_t>(m_header.m_pixel_depth, 1);
+ //for (uint32_t i = 1; i < m_header.m_level_count; i++)
+ // layer_pixel_depth += basisu::maximum<uint32_t>(m_header.m_pixel_depth >> i, 1);
+
+ const uint32_t image_count = basisu::maximum<uint32_t>(m_header.m_layer_count, 1) * m_header.m_face_count * m_header.m_level_count;
+ assert(image_count);
+
+ const uint8_t* pSrc = m_pData + m_header.m_sgd_byte_offset;
+
+ memcpy(&m_etc1s_header, pSrc, sizeof(ktx2_etc1s_global_data_header));
+ pSrc += sizeof(ktx2_etc1s_global_data_header);
+
+ if ((!m_etc1s_header.m_endpoints_byte_length) || (!m_etc1s_header.m_selectors_byte_length) || (!m_etc1s_header.m_tables_byte_length))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: Invalid ETC1S global data\n");
+ return false;
+ }
+
+ if ((!m_etc1s_header.m_endpoint_count) || (!m_etc1s_header.m_selector_count))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: endpoint and/or selector count is 0, file is invalid or corrupted\n");
+ return false;
+ }
+
+ // Sanity check the ETC1S header.
+ if ((sizeof(ktx2_etc1s_global_data_header) +
+ sizeof(ktx2_etc1s_image_desc) * image_count +
+ m_etc1s_header.m_endpoints_byte_length +
+ m_etc1s_header.m_selectors_byte_length +
+ m_etc1s_header.m_tables_byte_length +
+ m_etc1s_header.m_extended_byte_length) > m_header.m_sgd_byte_length)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: SGD byte length is too small, file is invalid or corrupted\n");
+ return false;
+ }
+
+ if (!m_etc1s_image_descs.try_resize(image_count))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: Out of memory\n");
+ return false;
+ }
+
+ memcpy(m_etc1s_image_descs.data(), pSrc, sizeof(ktx2_etc1s_image_desc) * image_count);
+ pSrc += sizeof(ktx2_etc1s_image_desc) * image_count;
+
+ // Sanity check the ETC1S image descs
+ for (uint32_t i = 0; i < image_count; i++)
+ {
+ // m_etc1s_transcoder.transcode_image() will validate the slice offsets/lengths before transcoding.
+
+ if (!m_etc1s_image_descs[i].m_rgb_slice_byte_length)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: ETC1S image descs sanity check failed (1)\n");
+ return false;
+ }
+
+ if (m_has_alpha)
+ {
+ if (!m_etc1s_image_descs[i].m_alpha_slice_byte_length)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: ETC1S image descs sanity check failed (2)\n");
+ return false;
+ }
+ }
+ }
+
+ const uint8_t* pEndpoint_data = pSrc;
+ const uint8_t* pSelector_data = pSrc + m_etc1s_header.m_endpoints_byte_length;
+ const uint8_t* pTables_data = pSrc + m_etc1s_header.m_endpoints_byte_length + m_etc1s_header.m_selectors_byte_length;
+
+ if (!m_etc1s_transcoder.decode_tables(pTables_data, m_etc1s_header.m_tables_byte_length))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: decode_tables() failed, file is invalid or corrupted\n");
+ return false;
+ }
+
+ if (!m_etc1s_transcoder.decode_palettes(
+ m_etc1s_header.m_endpoint_count, pEndpoint_data, m_etc1s_header.m_endpoints_byte_length,
+ m_etc1s_header.m_selector_count, pSelector_data, m_etc1s_header.m_selectors_byte_length))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: decode_palettes() failed, file is likely corrupted\n");
+ return false;
+ }
+
+ return true;
+ }
+
+ bool ktx2_transcoder::read_key_values()
+ {
+ if (!m_header.m_kvd_byte_length)
+ {
+ if (m_header.m_kvd_byte_offset)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Invalid KVD byte offset (it should be zero when the length is zero)\n");
+ return false;
+ }
+
return true;
-#endif
- default:
- break;
}
+ if (m_header.m_kvd_byte_offset < sizeof(ktx2_header))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Invalid KVD byte offset\n");
+ return false;
+ }
+
+ if ((m_header.m_kvd_byte_offset + m_header.m_kvd_byte_length) > m_data_size)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Invalid KVD byte offset and/or length\n");
+ return false;
+ }
+
+ const uint8_t* pSrc = m_pData + m_header.m_kvd_byte_offset;
+ uint32_t src_left = m_header.m_kvd_byte_length;
+
+ if (!m_key_values.try_reserve(8))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n");
+ return false;
+ }
+
+ while (src_left > sizeof(uint32_t))
+ {
+ uint32_t l = basisu::read_le_dword(pSrc);
+
+ pSrc += sizeof(uint32_t);
+ src_left -= sizeof(uint32_t);
+
+ if (l < 2)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Failed reading key value fields (0)\n");
+ return false;
+ }
+
+ if (src_left < l)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Failed reading key value fields (1)\n");
+ return false;
+ }
+
+ if (!m_key_values.try_resize(m_key_values.size() + 1))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n");
+ return false;
+ }
+
+ basisu::uint8_vec& key_data = m_key_values.back().m_key;
+ basisu::uint8_vec& value_data = m_key_values.back().m_value;
+
+ do
+ {
+ if (!l)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Failed reading key value fields (2)\n");
+ return false;
+ }
+
+ if (!key_data.try_push_back(*pSrc++))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n");
+ return false;
+ }
+
+ src_left--;
+ l--;
+
+ } while (key_data.back());
+
+ if (!value_data.try_resize(l))
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n");
+ return false;
+ }
+
+ if (l)
+ {
+ memcpy(value_data.data(), pSrc, l);
+ pSrc += l;
+ src_left -= l;
+ }
+
+ uint32_t ofs = (uint32_t)(pSrc - m_pData) & 3;
+ uint32_t alignment_bytes = (4 - ofs) & 3;
+
+ if (src_left < alignment_bytes)
+ {
+ BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Failed reading key value fields (3)\n");
+ return false;
+ }
+
+ pSrc += alignment_bytes;
+ src_left -= alignment_bytes;
+ }
+
+ return true;
+ }
+
+#endif // BASISD_SUPPORT_KTX2
+
+ bool basisu_transcoder_supports_ktx2()
+ {
+#if BASISD_SUPPORT_KTX2
+ return true;
+#else
return false;
+#endif
}
-} // namespace basist
+ bool basisu_transcoder_supports_ktx2_zstd()
+ {
+#if BASISD_SUPPORT_KTX2_ZSTD
+ return true;
+#else
+ return false;
+#endif
+ }
+} // namespace basist
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder.h b/thirdparty/basis_universal/transcoder/basisu_transcoder.h
index 770c64122d..bf3aed3dc3 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder.h
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder.h
@@ -1,5 +1,5 @@
// basisu_transcoder.h
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,10 +15,25 @@
// limitations under the License.
#pragma once
-// Set BASISU_DEVEL_MESSAGES to 1 to enable debug printf()'s whenever an error occurs, for easier debugging during development.
-//#define BASISU_DEVEL_MESSAGES 1
+// By default KTX2 support is enabled to simplify compilation. This implies the need for the Zstandard library (which we distribute as a single source file in the "zstd" directory) by default.
+// Set BASISD_SUPPORT_KTX2 to 0 to completely disable KTX2 support as well as Zstd/miniz usage which is only required for UASTC supercompression in KTX2 files.
+// Also see BASISD_SUPPORT_KTX2_ZSTD in basisu_transcoder.cpp, which individually disables Zstd usage.
+#ifndef BASISD_SUPPORT_KTX2
+ #define BASISD_SUPPORT_KTX2 1
+#endif
+
+// Set BASISD_SUPPORT_KTX2_ZSTD to 0 to disable Zstd usage and KTX2 UASTC Zstd supercompression support
+#ifndef BASISD_SUPPORT_KTX2_ZSTD
+ #define BASISD_SUPPORT_KTX2_ZSTD 1
+#endif
+
+// Set BASISU_FORCE_DEVEL_MESSAGES to 1 to enable debug printf()'s whenever an error occurs, for easier debugging during development.
+#ifndef BASISU_FORCE_DEVEL_MESSAGES
+ #define BASISU_FORCE_DEVEL_MESSAGES 0
+#endif
#include "basisu_transcoder_internal.h"
+#include "basisu_transcoder_uastc.h"
#include "basisu_global_selector_palette.h"
#include "basisu_file_headers.h"
@@ -45,12 +60,11 @@ namespace basist
cTFBC3_RGBA = 3, // Opaque+alpha, BC4 followed by a BC1 block, alpha channel will be opaque for opaque .basis files
cTFBC4_R = 4, // Red only, alpha slice is transcoded to output if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
cTFBC5_RG = 5, // XY: Two BC4 blocks, X=R and Y=Alpha, .basis file should have alpha data (if not Y will be all 255's)
- cTFBC7_M6_RGB = 6, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. Highest quality of all the non-ETC1 formats.
- cTFBC7_M5_RGBA = 7, // Opaque+alpha, alpha channel will be opaque for opaque .basis files
+ cTFBC7_RGBA = 6, // RGB or RGBA, mode 5 for ETC1S, modes (1,2,3,5,6,7) for UASTC
// PVRTC1 4bpp (mobile, PowerVR devices)
cTFPVRTC1_4_RGB = 8, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified, nearly lowest quality of any texture format.
- cTFPVRTC1_4_RGBA = 9, // Opaque+alpha, most useful for simple opacity maps. If .basis file doens't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format.
+ cTFPVRTC1_4_RGBA = 9, // Opaque+alpha, most useful for simple opacity maps. If .basis file doesn't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format.
// ASTC (mobile, Intel devices, hopefully all desktop GPU's one day)
cTFASTC_4x4_RGBA = 10, // Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files. Transcoder uses RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and [0,255]) endpoint precisions.
@@ -69,10 +83,10 @@ namespace basist
cTFETC2_EAC_R11 = 20, // R only (ETC2 EAC R11 unsigned)
cTFETC2_EAC_RG11 = 21, // RG only (ETC2 EAC RG11 unsigned), R=opaque.r, G=alpha - for tangent space normal maps
-
+
// Uncompressed (raw pixel) formats
cTFRGBA32 = 13, // 32bpp RGBA image stored in raster (not block) order in memory, R is first byte, A is last byte.
- cTFRGB565 = 14, // 166pp RGB image stored in raster (not block) order in memory, R at bit position 11
+ cTFRGB565 = 14, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 11
cTFBGR565 = 15, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 0
cTFRGBA4444 = 16, // 16bpp RGBA image stored in raster (not block) order in memory, R at bit position 12, A at bit position 0
@@ -85,27 +99,62 @@ namespace basist
cTFBC3 = cTFBC3_RGBA,
cTFBC4 = cTFBC4_R,
cTFBC5 = cTFBC5_RG,
- cTFBC7_M6_OPAQUE_ONLY = cTFBC7_M6_RGB,
- cTFBC7_M5 = cTFBC7_M5_RGBA,
+
+ // Previously, the caller had some control over which BC7 mode the transcoder output. We've simplified this due to UASTC, which supports numerous modes.
+ cTFBC7_M6_RGB = cTFBC7_RGBA, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. Highest quality of all the non-ETC1 formats.
+ cTFBC7_M5_RGBA = cTFBC7_RGBA, // Opaque+alpha, alpha channel will be opaque for opaque .basis files
+ cTFBC7_M6_OPAQUE_ONLY = cTFBC7_RGBA,
+ cTFBC7_M5 = cTFBC7_RGBA,
+ cTFBC7_ALT = 7,
+
cTFASTC_4x4 = cTFASTC_4x4_RGBA,
+
cTFATC_RGBA_INTERPOLATED_ALPHA = cTFATC_RGBA,
};
- uint32_t basis_get_bytes_per_block(transcoder_texture_format fmt);
+ // For compressed texture formats, this returns the # of bytes per block. For uncompressed, it returns the # of bytes per pixel.
+ // NOTE: Previously, this function was called basis_get_bytes_per_block(), and it always returned 16*bytes_per_pixel for uncompressed formats which was confusing.
+ uint32_t basis_get_bytes_per_block_or_pixel(transcoder_texture_format fmt);
+
+ // Returns format's name in ASCII
const char* basis_get_format_name(transcoder_texture_format fmt);
+
+ // Returns block format name in ASCII
+ const char* basis_get_block_format_name(block_format fmt);
+
+ // Returns true if the format supports an alpha channel.
bool basis_transcoder_format_has_alpha(transcoder_texture_format fmt);
+
+ // Returns the basisu::texture_format corresponding to the specified transcoder_texture_format.
basisu::texture_format basis_get_basisu_texture_format(transcoder_texture_format fmt);
+
+ // Returns the texture type's name in ASCII.
const char* basis_get_texture_type_name(basis_texture_type tex_type);
-
+
+ // Returns true if the transcoder texture type is an uncompressed (raw pixel) format.
bool basis_transcoder_format_is_uncompressed(transcoder_texture_format tex_type);
+
+ // Returns the # of bytes per pixel for uncompressed formats, or 0 for block texture formats.
uint32_t basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format fmt);
-
+
+ // Returns the block width for the specified texture format, which is currently either 4 or 8 for FXT1.
uint32_t basis_get_block_width(transcoder_texture_format tex_type);
+
+ // Returns the block height for the specified texture format, which is currently always 4.
uint32_t basis_get_block_height(transcoder_texture_format tex_type);
// Returns true if the specified format was enabled at compile time.
- bool basis_is_format_supported(transcoder_texture_format tex_type);
-
+ bool basis_is_format_supported(transcoder_texture_format tex_type, basis_tex_format fmt = basis_tex_format::cETC1S);
+
+ // Validates that the output buffer is large enough to hold the entire transcoded texture.
+ // For uncompressed texture formats, most input parameters are in pixels, not blocks. Blocks are 4x4 pixels.
+ bool basis_validate_output_buffer_size(transcoder_texture_format target_format,
+ uint32_t output_blocks_buf_size_in_blocks_or_pixels,
+ uint32_t orig_width, uint32_t orig_height,
+ uint32_t output_row_pitch_in_blocks_or_pixels,
+ uint32_t output_rows_in_pixels,
+ uint32_t total_slice_blocks);
+
class basisu_transcoder;
// This struct holds all state used during transcoding. For video, it needs to persist between image transcodes (it holds the previous frame).
@@ -118,46 +167,161 @@ namespace basist
uint8_t m_pred_bits;
};
- std::vector<block_preds> m_block_endpoint_preds[2];
-
+ basisu::vector<block_preds> m_block_endpoint_preds[2];
+
enum { cMaxPrevFrameLevels = 16 };
- std::vector<uint32_t> m_prev_frame_indices[2][cMaxPrevFrameLevels]; // [alpha_flag][level_index]
+ basisu::vector<uint32_t> m_prev_frame_indices[2][cMaxPrevFrameLevels]; // [alpha_flag][level_index]
+
+ void clear()
+ {
+ for (uint32_t i = 0; i < 2; i++)
+ {
+ m_block_endpoint_preds[i].clear();
+
+ for (uint32_t j = 0; j < cMaxPrevFrameLevels; j++)
+ m_prev_frame_indices[i][j].clear();
+ }
+ }
};
-
+
// Low-level helper class that does the actual transcoding.
- class basisu_lowlevel_transcoder
+ class basisu_lowlevel_etc1s_transcoder
{
friend class basisu_transcoder;
-
+
public:
- basisu_lowlevel_transcoder(const basist::etc1_global_selector_codebook *pGlobal_sel_codebook);
+ basisu_lowlevel_etc1s_transcoder(const basist::etc1_global_selector_codebook* pGlobal_sel_codebook);
+
+ void set_global_codebooks(const basisu_lowlevel_etc1s_transcoder* pGlobal_codebook) { m_pGlobal_codebook = pGlobal_codebook; }
+ const basisu_lowlevel_etc1s_transcoder* get_global_codebooks() const { return m_pGlobal_codebook; }
bool decode_palettes(
- uint32_t num_endpoints, const uint8_t *pEndpoints_data, uint32_t endpoints_data_size,
- uint32_t num_selectors, const uint8_t *pSelectors_data, uint32_t selectors_data_size);
+ uint32_t num_endpoints, const uint8_t* pEndpoints_data, uint32_t endpoints_data_size,
+ uint32_t num_selectors, const uint8_t* pSelectors_data, uint32_t selectors_data_size);
+
+ bool decode_tables(const uint8_t* pTable_data, uint32_t table_data_size);
+
+ bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
+ uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const bool is_video, const bool is_alpha_slice, const uint32_t level_index, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
+ basisu_transcoder_state* pState = nullptr, bool astc_transcode_alpha = false, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0);
+
+ bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
+ uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const basis_file_header& header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
+ basisu_transcoder_state* pState = nullptr, bool astc_transcode_alpha = false, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0)
+ {
+ return transcode_slice(pDst_blocks, num_blocks_x, num_blocks_y, pImage_data, image_data_size, fmt, output_block_or_pixel_stride_in_bytes, bc1_allow_threecolor_blocks,
+ header.m_tex_type == cBASISTexTypeVideoFrames, (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0, slice_desc.m_level_index,
+ slice_desc.m_orig_width, slice_desc.m_orig_height, output_row_pitch_in_blocks_or_pixels, pState,
+ astc_transcode_alpha,
+ pAlpha_blocks,
+ output_rows_in_pixels);
+ }
+
+ // Container independent transcoding
+ bool transcode_image(
+ transcoder_texture_format target_format,
+ void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
+ const uint8_t* pCompressed_data, uint32_t compressed_data_length,
+ uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,
+ uint32_t rgb_offset, uint32_t rgb_length, uint32_t alpha_offset, uint32_t alpha_length,
+ uint32_t decode_flags = 0,
+ bool basis_file_has_alpha_slices = false,
+ bool is_video = false,
+ uint32_t output_row_pitch_in_blocks_or_pixels = 0,
+ basisu_transcoder_state* pState = nullptr,
+ uint32_t output_rows_in_pixels = 0);
+
+ void clear()
+ {
+ m_local_endpoints.clear();
+ m_local_selectors.clear();
+ m_endpoint_pred_model.clear();
+ m_delta_endpoint_model.clear();
+ m_selector_model.clear();
+ m_selector_history_buf_rle_model.clear();
+ m_selector_history_buf_size = 0;
+ }
- bool decode_tables(const uint8_t *pTable_data, uint32_t table_data_size);
+ // Low-level methods
+ typedef basisu::vector<endpoint> endpoint_vec;
+ const endpoint_vec& get_endpoints() const { return m_local_endpoints; }
- bool transcode_slice(void *pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t *pImage_data, uint32_t image_data_size, block_format fmt,
- uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const basis_file_header &header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
- basisu_transcoder_state *pState = nullptr, bool astc_transcode_alpha = false, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0);
+ typedef basisu::vector<selector> selector_vec;
+ const selector_vec& get_selectors() const { return m_local_selectors; }
+
+ const etc1_global_selector_codebook* get_global_sel_codebook() const { return m_pGlobal_sel_codebook; }
private:
- typedef std::vector<endpoint> endpoint_vec;
- endpoint_vec m_endpoints;
+ const basisu_lowlevel_etc1s_transcoder* m_pGlobal_codebook;
- typedef std::vector<selector> selector_vec;
- selector_vec m_selectors;
+ endpoint_vec m_local_endpoints;
+ selector_vec m_local_selectors;
- const etc1_global_selector_codebook *m_pGlobal_sel_codebook;
+ const etc1_global_selector_codebook* m_pGlobal_sel_codebook;
huffman_decoding_table m_endpoint_pred_model, m_delta_endpoint_model, m_selector_model, m_selector_history_buf_rle_model;
uint32_t m_selector_history_buf_size;
-
+
basisu_transcoder_state m_def_state;
};
+ enum basisu_decode_flags
+ {
+ // PVRTC1: decode non-pow2 ETC1S texture level to the next larger power of 2 (not implemented yet, but we're going to support it). Ignored if the slice's dimensions are already a power of 2.
+ cDecodeFlagsPVRTCDecodeToNextPow2 = 2,
+
+ // When decoding to an opaque texture format, if the basis file has alpha, decode the alpha slice instead of the color slice to the output texture format.
+ // This is primarily to allow decoding of textures with alpha to multiple ETC1 textures (one for color, another for alpha).
+ cDecodeFlagsTranscodeAlphaDataToOpaqueFormats = 4,
+
+ // Forbid usage of BC1 3 color blocks (we don't support BC1 punchthrough alpha yet).
+ // This flag is used internally when decoding to BC3.
+ cDecodeFlagsBC1ForbidThreeColorBlocks = 8,
+
+ // The output buffer contains alpha endpoint/selector indices.
+ // Used internally when decoding formats like ASTC that require both color and alpha data to be available when transcoding to the output format.
+ cDecodeFlagsOutputHasAlphaIndices = 16,
+
+ cDecodeFlagsHighQuality = 32
+ };
+
+ class basisu_lowlevel_uastc_transcoder
+ {
+ friend class basisu_transcoder;
+
+ public:
+ basisu_lowlevel_uastc_transcoder();
+
+ bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
+ uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
+ basisu_transcoder_state* pState = nullptr, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1, uint32_t decode_flags = 0);
+
+ bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
+ uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const basis_file_header& header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
+ basisu_transcoder_state* pState = nullptr, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1, uint32_t decode_flags = 0)
+ {
+ return transcode_slice(pDst_blocks, num_blocks_x, num_blocks_y, pImage_data, image_data_size, fmt,
+ output_block_or_pixel_stride_in_bytes, bc1_allow_threecolor_blocks, (header.m_flags & cBASISHeaderFlagHasAlphaSlices) != 0, slice_desc.m_orig_width, slice_desc.m_orig_height, output_row_pitch_in_blocks_or_pixels,
+ pState, output_rows_in_pixels, channel0, channel1, decode_flags);
+ }
+
+ // Container independent transcoding
+ bool transcode_image(
+ transcoder_texture_format target_format,
+ void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
+ const uint8_t* pCompressed_data, uint32_t compressed_data_length,
+ uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,
+ uint32_t slice_offset, uint32_t slice_length,
+ uint32_t decode_flags = 0,
+ bool has_alpha = false,
+ bool is_video = false,
+ uint32_t output_row_pitch_in_blocks_or_pixels = 0,
+ basisu_transcoder_state* pState = nullptr,
+ uint32_t output_rows_in_pixels = 0,
+ int channel0 = -1, int channel1 = -1);
+ };
+
struct basisu_slice_info
{
uint32_t m_orig_width;
@@ -175,19 +339,19 @@ namespace basist
uint32_t m_slice_index; // the slice index in the .basis file
uint32_t m_image_index; // the source image index originally provided to the encoder
uint32_t m_level_index; // the mipmap level within this image
-
+
uint32_t m_unpacked_slice_crc16;
-
+
bool m_alpha_flag; // true if the slice has alpha data
bool m_iframe_flag; // true if the slice is an I-Frame
};
- typedef std::vector<basisu_slice_info> basisu_slice_info_vec;
+ typedef basisu::vector<basisu_slice_info> basisu_slice_info_vec;
struct basisu_image_info
{
uint32_t m_image_index;
- uint32_t m_total_levels;
+ uint32_t m_total_levels;
uint32_t m_orig_width;
uint32_t m_orig_height;
@@ -199,8 +363,8 @@ namespace basist
uint32_t m_num_blocks_y;
uint32_t m_total_blocks;
- uint32_t m_first_slice_index;
-
+ uint32_t m_first_slice_index;
+
bool m_alpha_flag; // true if the image has alpha data
bool m_iframe_flag; // true if the image is an I-Frame
};
@@ -220,8 +384,13 @@ namespace basist
uint32_t m_num_blocks_y;
uint32_t m_total_blocks;
- uint32_t m_first_slice_index;
-
+ uint32_t m_first_slice_index;
+
+ uint32_t m_rgb_file_ofs;
+ uint32_t m_rgb_file_len;
+ uint32_t m_alpha_file_ofs;
+ uint32_t m_alpha_file_len;
+
bool m_alpha_flag; // true if the image has alpha data
bool m_iframe_flag; // true if the image is an I-Frame
};
@@ -232,13 +401,19 @@ namespace basist
uint32_t m_total_header_size;
uint32_t m_total_selectors;
+ // will be 0 for UASTC or if the file uses global codebooks
+ uint32_t m_selector_codebook_ofs;
uint32_t m_selector_codebook_size;
uint32_t m_total_endpoints;
+ // will be 0 for UASTC or if the file uses global codebooks
+ uint32_t m_endpoint_codebook_ofs;
uint32_t m_endpoint_codebook_size;
+ uint32_t m_tables_ofs;
uint32_t m_tables_size;
- uint32_t m_slices_size;
+
+ uint32_t m_slices_size;
basis_texture_type m_tex_type;
uint32_t m_us_per_frame;
@@ -247,14 +422,16 @@ namespace basist
basisu_slice_info_vec m_slice_info;
uint32_t m_total_images; // total # of images
- std::vector<uint32_t> m_image_mipmap_levels; // the # of mipmap levels for each image
+ basisu::vector<uint32_t> m_image_mipmap_levels; // the # of mipmap levels for each image
uint32_t m_userdata0;
uint32_t m_userdata1;
-
- bool m_etc1s; // always true for basis universal
+
+ basis_tex_format m_tex_format; // ETC1S, UASTC, etc.
+
bool m_y_flipped; // true if the image was Y flipped
- bool m_has_alpha_slices; // true if the texture has alpha slices (even slices RGB, odd slices alpha)
+ bool m_etc1s; // true if the file is ETC1S
+ bool m_has_alpha_slices; // true if the texture has alpha slices (for ETC1S: even slices RGB, odd slices alpha)
};
// High-level transcoder class which accepts .basis file data and allows the caller to query information about the file and transcode image levels to various texture formats.
@@ -265,81 +442,67 @@ namespace basist
basisu_transcoder& operator= (const basisu_transcoder&);
public:
- basisu_transcoder(const etc1_global_selector_codebook *pGlobal_sel_codebook);
+ basisu_transcoder(const etc1_global_selector_codebook* pGlobal_sel_codebook);
// Validates the .basis file. This computes a crc16 over the entire file, so it's slow.
- bool validate_file_checksums(const void *pData, uint32_t data_size, bool full_validation) const;
+ bool validate_file_checksums(const void* pData, uint32_t data_size, bool full_validation) const;
// Quick header validation - no crc16 checks.
- bool validate_header(const void *pData, uint32_t data_size) const;
+ bool validate_header(const void* pData, uint32_t data_size) const;
+
+ basis_texture_type get_texture_type(const void* pData, uint32_t data_size) const;
+ bool get_userdata(const void* pData, uint32_t data_size, uint32_t& userdata0, uint32_t& userdata1) const;
- basis_texture_type get_texture_type(const void *pData, uint32_t data_size) const;
- bool get_userdata(const void *pData, uint32_t data_size, uint32_t &userdata0, uint32_t &userdata1) const;
-
// Returns the total number of images in the basis file (always 1 or more).
// Note that the number of mipmap levels for each image may differ, and that images may have different resolutions.
- uint32_t get_total_images(const void *pData, uint32_t data_size) const;
+ uint32_t get_total_images(const void* pData, uint32_t data_size) const;
+
+ basis_tex_format get_tex_format(const void* pData, uint32_t data_size) const;
// Returns the number of mipmap levels in an image.
- uint32_t get_total_image_levels(const void *pData, uint32_t data_size, uint32_t image_index) const;
-
+ uint32_t get_total_image_levels(const void* pData, uint32_t data_size, uint32_t image_index) const;
+
// Returns basic information about an image. Note that orig_width/orig_height may not be a multiple of 4.
- bool get_image_level_desc(const void *pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, uint32_t &orig_width, uint32_t &orig_height, uint32_t &total_blocks) const;
+ bool get_image_level_desc(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, uint32_t& orig_width, uint32_t& orig_height, uint32_t& total_blocks) const;
// Returns information about the specified image.
- bool get_image_info(const void *pData, uint32_t data_size, basisu_image_info &image_info, uint32_t image_index) const;
+ bool get_image_info(const void* pData, uint32_t data_size, basisu_image_info& image_info, uint32_t image_index) const;
// Returns information about the specified image's mipmap level.
- bool get_image_level_info(const void *pData, uint32_t data_size, basisu_image_level_info &level_info, uint32_t image_index, uint32_t level_index) const;
-
+ bool get_image_level_info(const void* pData, uint32_t data_size, basisu_image_level_info& level_info, uint32_t image_index, uint32_t level_index) const;
+
// Get a description of the basis file and low-level information about each slice.
- bool get_file_info(const void *pData, uint32_t data_size, basisu_file_info &file_info) const;
-
+ bool get_file_info(const void* pData, uint32_t data_size, basisu_file_info& file_info) const;
+
// start_transcoding() must be called before calling transcode_slice() or transcode_image_level().
- // This decompresses the selector/endpoint codebooks, so ideally you would only call this once per .basis file (not each image/mipmap level).
- bool start_transcoding(const void *pData, uint32_t data_size) const;
-
+ // For ETC1S files, this call decompresses the selector/endpoint codebooks, so ideally you would only call this once per .basis file (not each image/mipmap level).
+ bool start_transcoding(const void* pData, uint32_t data_size);
+
+ bool stop_transcoding();
+
// Returns true if start_transcoding() has been called.
- bool get_ready_to_transcode() const { return m_lowlevel_decoder.m_endpoints.size() > 0; }
+ bool get_ready_to_transcode() const { return m_ready_to_transcode; }
- enum
- {
- // PVRTC1: decode non-pow2 ETC1S texture level to the next larger power of 2 (not implemented yet, but we're going to support it). Ignored if the slice's dimensions are already a power of 2.
- cDecodeFlagsPVRTCDecodeToNextPow2 = 2,
-
- // When decoding to an opaque texture format, if the basis file has alpha, decode the alpha slice instead of the color slice to the output texture format.
- // This is primarily to allow decoding of textures with alpha to multiple ETC1 textures (one for color, another for alpha).
- cDecodeFlagsTranscodeAlphaDataToOpaqueFormats = 4,
-
- // Forbid usage of BC1 3 color blocks (we don't support BC1 punchthrough alpha yet).
- // This flag is used internally when decoding to BC3.
- cDecodeFlagsBC1ForbidThreeColorBlocks = 8,
-
- // The output buffer contains alpha endpoint/selector indices.
- // Used internally when decoding formats like ASTC that require both color and alpha data to be available when transcoding to the output format.
- cDecodeFlagsOutputHasAlphaIndices = 16
- };
-
// transcode_image_level() decodes a single mipmap level from the .basis file to any of the supported output texture formats.
// It'll first find the slice(s) to transcode, then call transcode_slice() one or two times to decode both the color and alpha texture data (or RG texture data from two slices for BC5).
// If the .basis file doesn't have alpha slices, the output alpha blocks will be set to fully opaque (all 255's).
// Currently, to decode to PVRTC1 the basis texture's dimensions in pixels must be a power of 2, due to PVRTC1 format requirements.
// output_blocks_buf_size_in_blocks_or_pixels should be at least the image level's total_blocks (num_blocks_x * num_blocks_y), or the total number of output pixels if fmt==cTFRGBA32.
// output_row_pitch_in_blocks_or_pixels: Number of blocks or pixels per row. If 0, the transcoder uses the slice's num_blocks_x or orig_width (NOT num_blocks_x * 4). Ignored for PVRTC1 (due to texture swizzling).
- // output_rows_in_pixels: Ignored unless fmt is cRGBA32. The total number of output rows in the output buffer. If 0, the transcoder assumes the slice's orig_height (NOT num_blocks_y * 4).
+ // output_rows_in_pixels: Ignored unless fmt is uncompressed (cRGBA32, etc.). The total number of output rows in the output buffer. If 0, the transcoder assumes the slice's orig_height (NOT num_blocks_y * 4).
// Notes:
// - basisu_transcoder_init() must have been called first to initialize the transcoder lookup tables before calling this function.
// - This method assumes the output texture buffer is readable. In some cases to handle alpha, the transcoder will write temporary data to the output texture in
// a first pass, which will be read in a second pass.
bool transcode_image_level(
- const void *pData, uint32_t data_size,
- uint32_t image_index, uint32_t level_index,
- void *pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
+ const void* pData, uint32_t data_size,
+ uint32_t image_index, uint32_t level_index,
+ void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
transcoder_texture_format fmt,
- uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state *pState = nullptr, uint32_t output_rows_in_pixels = 0) const;
+ uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state* pState = nullptr, uint32_t output_rows_in_pixels = 0) const;
// Finds the basis slice corresponding to the specified image/level/alpha params, or -1 if the slice can't be found.
- int find_slice(const void *pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, bool alpha_data) const;
+ int find_slice(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, bool alpha_data) const;
// transcode_slice() decodes a single slice from the .basis file. It's a low-level API - most likely you want to use transcode_image_level().
// This is a low-level API, and will be needed to be called multiple times to decode some texture formats (like BC3, BC5, or ETC2).
@@ -350,21 +513,39 @@ namespace basist
// output_rows_in_pixels: Ignored unless fmt is cRGBA32. The total number of output rows in the output buffer. If 0, the transcoder assumes the slice's orig_height (NOT num_blocks_y * 4).
// Notes:
// - basisu_transcoder_init() must have been called first to initialize the transcoder lookup tables before calling this function.
- bool transcode_slice(const void *pData, uint32_t data_size, uint32_t slice_index,
- void *pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
- block_format fmt, uint32_t output_block_stride_in_bytes, uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state * pState = nullptr, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0) const;
+ bool transcode_slice(const void* pData, uint32_t data_size, uint32_t slice_index,
+ void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
+ block_format fmt, uint32_t output_block_stride_in_bytes, uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state* pState = nullptr, void* pAlpha_blocks = nullptr,
+ uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1) const;
+
+ static void write_opaque_alpha_blocks(
+ uint32_t num_blocks_x, uint32_t num_blocks_y,
+ void* pOutput_blocks, block_format fmt,
+ uint32_t block_stride_in_bytes, uint32_t output_row_pitch_in_blocks_or_pixels);
+
+ void set_global_codebooks(const basisu_lowlevel_etc1s_transcoder* pGlobal_codebook) { m_lowlevel_etc1s_decoder.set_global_codebooks(pGlobal_codebook); }
+ const basisu_lowlevel_etc1s_transcoder* get_global_codebooks() const { return m_lowlevel_etc1s_decoder.get_global_codebooks(); }
+
+ const basisu_lowlevel_etc1s_transcoder& get_lowlevel_etc1s_decoder() const { return m_lowlevel_etc1s_decoder; }
+ basisu_lowlevel_etc1s_transcoder& get_lowlevel_etc1s_decoder() { return m_lowlevel_etc1s_decoder; }
+
+ const basisu_lowlevel_uastc_transcoder& get_lowlevel_uastc_decoder() const { return m_lowlevel_uastc_decoder; }
+ basisu_lowlevel_uastc_transcoder& get_lowlevel_uastc_decoder() { return m_lowlevel_uastc_decoder; }
private:
- mutable basisu_lowlevel_transcoder m_lowlevel_decoder;
+ mutable basisu_lowlevel_etc1s_transcoder m_lowlevel_etc1s_decoder;
+ mutable basisu_lowlevel_uastc_transcoder m_lowlevel_uastc_decoder;
+
+ bool m_ready_to_transcode;
int find_first_slice_index(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index) const;
-
+
bool validate_header_quick(const void* pData, uint32_t data_size) const;
};
- // basisu_transcoder_init() must be called before a .basis file can be transcoded.
+ // basisu_transcoder_init() MUST be called before a .basis file can be transcoded.
void basisu_transcoder_init();
-
+
enum debug_flags_t
{
cDebugFlagVisCRs = 1,
@@ -374,4 +555,387 @@ namespace basist
uint32_t get_debug_flags();
void set_debug_flags(uint32_t f);
+ // ------------------------------------------------------------------------------------------------------
+ // Optional .KTX2 file format support
+ // KTX2 reading optionally requires miniz or Zstd decompressors for supercompressed UASTC files.
+ // ------------------------------------------------------------------------------------------------------
+#if BASISD_SUPPORT_KTX2
+#pragma pack(push)
+#pragma pack(1)
+ struct ktx2_header
+ {
+ uint8_t m_identifier[12];
+ basisu::packed_uint<4> m_vk_format;
+ basisu::packed_uint<4> m_type_size;
+ basisu::packed_uint<4> m_pixel_width;
+ basisu::packed_uint<4> m_pixel_height;
+ basisu::packed_uint<4> m_pixel_depth;
+ basisu::packed_uint<4> m_layer_count;
+ basisu::packed_uint<4> m_face_count;
+ basisu::packed_uint<4> m_level_count;
+ basisu::packed_uint<4> m_supercompression_scheme;
+ basisu::packed_uint<4> m_dfd_byte_offset;
+ basisu::packed_uint<4> m_dfd_byte_length;
+ basisu::packed_uint<4> m_kvd_byte_offset;
+ basisu::packed_uint<4> m_kvd_byte_length;
+ basisu::packed_uint<8> m_sgd_byte_offset;
+ basisu::packed_uint<8> m_sgd_byte_length;
+ };
+
+ struct ktx2_level_index
+ {
+ basisu::packed_uint<8> m_byte_offset;
+ basisu::packed_uint<8> m_byte_length;
+ basisu::packed_uint<8> m_uncompressed_byte_length;
+ };
+
+ struct ktx2_etc1s_global_data_header
+ {
+ basisu::packed_uint<2> m_endpoint_count;
+ basisu::packed_uint<2> m_selector_count;
+ basisu::packed_uint<4> m_endpoints_byte_length;
+ basisu::packed_uint<4> m_selectors_byte_length;
+ basisu::packed_uint<4> m_tables_byte_length;
+ basisu::packed_uint<4> m_extended_byte_length;
+ };
+
+ struct ktx2_etc1s_image_desc
+ {
+ basisu::packed_uint<4> m_image_flags;
+ basisu::packed_uint<4> m_rgb_slice_byte_offset;
+ basisu::packed_uint<4> m_rgb_slice_byte_length;
+ basisu::packed_uint<4> m_alpha_slice_byte_offset;
+ basisu::packed_uint<4> m_alpha_slice_byte_length;
+ };
+
+ struct ktx2_animdata
+ {
+ basisu::packed_uint<4> m_duration;
+ basisu::packed_uint<4> m_timescale;
+ basisu::packed_uint<4> m_loopcount;
+ };
+#pragma pack(pop)
+
+ const uint32_t KTX2_VK_FORMAT_UNDEFINED = 0;
+ const uint32_t KTX2_KDF_DF_MODEL_UASTC = 166;
+ const uint32_t KTX2_KDF_DF_MODEL_ETC1S = 163;
+ const uint32_t KTX2_IMAGE_IS_P_FRAME = 2;
+ const uint32_t KTX2_UASTC_BLOCK_SIZE = 16;
+ const uint32_t KTX2_MAX_SUPPORTED_LEVEL_COUNT = 16; // this is an implementation specific constraint and can be increased
+
+ // The KTX2 transfer functions supported by KTX2
+ const uint32_t KTX2_KHR_DF_TRANSFER_LINEAR = 1;
+ const uint32_t KTX2_KHR_DF_TRANSFER_SRGB = 2;
+
+ enum ktx2_supercompression
+ {
+ KTX2_SS_NONE = 0,
+ KTX2_SS_BASISLZ = 1,
+ KTX2_SS_ZSTANDARD = 2
+ };
+
+ extern const uint8_t g_ktx2_file_identifier[12];
+
+ enum ktx2_df_channel_id
+ {
+ KTX2_DF_CHANNEL_ETC1S_RGB = 0U,
+ KTX2_DF_CHANNEL_ETC1S_RRR = 3U,
+ KTX2_DF_CHANNEL_ETC1S_GGG = 4U,
+ KTX2_DF_CHANNEL_ETC1S_AAA = 15U,
+
+ KTX2_DF_CHANNEL_UASTC_DATA = 0U,
+ KTX2_DF_CHANNEL_UASTC_RGB = 0U,
+ KTX2_DF_CHANNEL_UASTC_RGBA = 3U,
+ KTX2_DF_CHANNEL_UASTC_RRR = 4U,
+ KTX2_DF_CHANNEL_UASTC_RRRG = 5U,
+ KTX2_DF_CHANNEL_UASTC_RG = 6U,
+ };
+
+ inline const char* ktx2_get_etc1s_df_channel_id_str(ktx2_df_channel_id id)
+ {
+ switch (id)
+ {
+ case KTX2_DF_CHANNEL_ETC1S_RGB: return "RGB";
+ case KTX2_DF_CHANNEL_ETC1S_RRR: return "RRR";
+ case KTX2_DF_CHANNEL_ETC1S_GGG: return "GGG";
+ case KTX2_DF_CHANNEL_ETC1S_AAA: return "AAA";
+ default: break;
+ }
+ return "?";
+ }
+
+ inline const char* ktx2_get_uastc_df_channel_id_str(ktx2_df_channel_id id)
+ {
+ switch (id)
+ {
+ case KTX2_DF_CHANNEL_UASTC_RGB: return "RGB";
+ case KTX2_DF_CHANNEL_UASTC_RGBA: return "RGBA";
+ case KTX2_DF_CHANNEL_UASTC_RRR: return "RRR";
+ case KTX2_DF_CHANNEL_UASTC_RRRG: return "RRRG";
+ case KTX2_DF_CHANNEL_UASTC_RG: return "RG";
+ default: break;
+ }
+ return "?";
+ }
+
+ enum ktx2_df_color_primaries
+ {
+ KTX2_DF_PRIMARIES_UNSPECIFIED = 0,
+ KTX2_DF_PRIMARIES_BT709 = 1,
+ KTX2_DF_PRIMARIES_SRGB = 1,
+ KTX2_DF_PRIMARIES_BT601_EBU = 2,
+ KTX2_DF_PRIMARIES_BT601_SMPTE = 3,
+ KTX2_DF_PRIMARIES_BT2020 = 4,
+ KTX2_DF_PRIMARIES_CIEXYZ = 5,
+ KTX2_DF_PRIMARIES_ACES = 6,
+ KTX2_DF_PRIMARIES_ACESCC = 7,
+ KTX2_DF_PRIMARIES_NTSC1953 = 8,
+ KTX2_DF_PRIMARIES_PAL525 = 9,
+ KTX2_DF_PRIMARIES_DISPLAYP3 = 10,
+ KTX2_DF_PRIMARIES_ADOBERGB = 11
+ };
+
+ inline const char* ktx2_get_df_color_primaries_str(ktx2_df_color_primaries p)
+ {
+ switch (p)
+ {
+ case KTX2_DF_PRIMARIES_UNSPECIFIED: return "UNSPECIFIED";
+ case KTX2_DF_PRIMARIES_BT709: return "BT709";
+ case KTX2_DF_PRIMARIES_BT601_EBU: return "EBU";
+ case KTX2_DF_PRIMARIES_BT601_SMPTE: return "SMPTE";
+ case KTX2_DF_PRIMARIES_BT2020: return "BT2020";
+ case KTX2_DF_PRIMARIES_CIEXYZ: return "CIEXYZ";
+ case KTX2_DF_PRIMARIES_ACES: return "ACES";
+ case KTX2_DF_PRIMARIES_ACESCC: return "ACESCC";
+ case KTX2_DF_PRIMARIES_NTSC1953: return "NTSC1953";
+ case KTX2_DF_PRIMARIES_PAL525: return "PAL525";
+ case KTX2_DF_PRIMARIES_DISPLAYP3: return "DISPLAYP3";
+ case KTX2_DF_PRIMARIES_ADOBERGB: return "ADOBERGB";
+ default: break;
+ }
+ return "?";
+ }
+
+ // Information about a single 2D texture "image" in a KTX2 file.
+ struct ktx2_image_level_info
+ {
+ // The mipmap level index (0=largest), texture array layer index, and cubemap face index of the image.
+ uint32_t m_level_index;
+ uint32_t m_layer_index;
+ uint32_t m_face_index;
+
+ // The image's actual (or the original source image's) width/height in pixels, which may not be divisible by 4 pixels.
+ uint32_t m_orig_width;
+ uint32_t m_orig_height;
+
+ // The image's physical width/height, which will always be divisible by 4 pixels.
+ uint32_t m_width;
+ uint32_t m_height;
+
+ // The texture's dimensions in 4x4 texel blocks.
+ uint32_t m_num_blocks_x;
+ uint32_t m_num_blocks_y;
+
+ // The total number of blocks
+ uint32_t m_total_blocks;
+
+ // true if the image has alpha data
+ bool m_alpha_flag;
+
+ // true if the image is an I-Frame. Currently, for ETC1S textures, the first frame will always be an I-Frame, and subsequent frames will always be P-Frames.
+ bool m_iframe_flag;
+ };
+
+ // Thread-specific ETC1S/supercompressed UASTC transcoder state. (If you're not doing multithreading transcoding you can ignore this.)
+ struct ktx2_transcoder_state
+ {
+ basist::basisu_transcoder_state m_transcoder_state;
+ basisu::uint8_vec m_level_uncomp_data;
+ int m_uncomp_data_level_index;
+
+ void clear()
+ {
+ m_transcoder_state.clear();
+ m_level_uncomp_data.clear();
+ m_uncomp_data_level_index = -1;
+ }
+ };
+
+ // This class is quite similar to basisu_transcoder. It treats KTX2 files as a simple container for ETC1S/UASTC texture data.
+ // It does not support 1D or 3D textures.
+ // It only supports 2D and cubemap textures, with or without mipmaps, texture arrays of 2D/cubemap textures, and texture video files.
+ // It only supports raw non-supercompressed UASTC, ETC1S, UASTC+Zstd, or UASTC+zlib compressed files.
+ // DFD (Data Format Descriptor) parsing is purposely as simple as possible.
+ // If you need to know how to interpret the texture channels you'll need to parse the DFD yourself after calling get_dfd().
+ class ktx2_transcoder
+ {
+ public:
+ ktx2_transcoder(basist::etc1_global_selector_codebook* pGlobal_sel_codebook);
+
+ // Frees all allocations, resets object.
+ void clear();
+
+ // init() parses the KTX2 header, level index array, DFD, and key values, but nothing else.
+ // Importantly, it does not parse or decompress the ETC1S global supercompressed data, so some things (like which frames are I/P-Frames) won't be available until start_transcoding() is called.
+ // This method holds a pointer to the file data until clear() is called.
+ bool init(const void* pData, uint32_t data_size);
+
+ // Returns the data/size passed to init().
+ const uint8_t* get_data() const { return m_pData; }
+ uint32_t get_data_size() const { return m_data_size; }
+
+ // Returns the KTX2 header. Valid after init().
+ const ktx2_header& get_header() const { return m_header; }
+
+ // Returns the KTX2 level index array. There will be one entry for each mipmap level. Valid after init().
+ const basisu::vector<ktx2_level_index>& get_level_index() const { return m_levels; }
+
+ // Returns the texture's width in texels. Always non-zero, might not be divisible by 4. Valid after init().
+ uint32_t get_width() const { return m_header.m_pixel_width; }
+
+ // Returns the texture's height in texels. Always non-zero, might not be divisible by 4. Valid after init().
+ uint32_t get_height() const { return m_header.m_pixel_height; }
+
+ // Returns the texture's number of mipmap levels. Always returns 1 or higher. Valid after init().
+ uint32_t get_levels() const { return m_header.m_level_count; }
+
+ // Returns the number of faces. Returns 1 for 2D textures and or 6 for cubemaps. Valid after init().
+ uint32_t get_faces() const { return m_header.m_face_count; }
+
+ // Returns 0 or the number of layers in the texture array or texture video. Valid after init().
+ uint32_t get_layers() const { return m_header.m_layer_count; }
+
+ // Returns cETC1S or cUASTC4x4. Valid after init().
+ basist::basis_tex_format get_format() const { return m_format; }
+
+ bool is_etc1s() const { return get_format() == basist::basis_tex_format::cETC1S; }
+
+ bool is_uastc() const { return get_format() == basist::basis_tex_format::cUASTC4x4; }
+
+ // Returns true if the ETC1S file has two planes (typically RGBA, or RRRG), or true if the UASTC file has alpha data. Valid after init().
+ uint32_t get_has_alpha() const { return m_has_alpha; }
+
+ // Returns the entire Data Format Descriptor (DFD) from the KTX2 file. Valid after init().
+ // See https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html#_the_khronos_data_format_descriptor_overview
+ const basisu::uint8_vec& get_dfd() const { return m_dfd; }
+
+ // Some basic DFD accessors. Valid after init().
+ uint32_t get_dfd_color_model() const { return m_dfd_color_model; }
+
+ // Returns the DFD color primary.
+ // We do not validate the color primaries, so the returned value may not be in the ktx2_df_color_primaries enum.
+ ktx2_df_color_primaries get_dfd_color_primaries() const { return m_dfd_color_prims; }
+
+ // Returns KTX2_KHR_DF_TRANSFER_LINEAR or KTX2_KHR_DF_TRANSFER_SRGB.
+ uint32_t get_dfd_transfer_func() const { return m_dfd_transfer_func; }
+
+ uint32_t get_dfd_flags() const { return m_dfd_flags; }
+
+ // Returns 1 (ETC1S/UASTC) or 2 (ETC1S with an internal alpha channel).
+ uint32_t get_dfd_total_samples() const { return m_dfd_samples; }
+
+ // Returns the channel mapping for each DFD "sample". UASTC always has 1 sample, ETC1S can have one or two.
+ // Note the returned value SHOULD be one of the ktx2_df_channel_id enums, but we don't validate that.
+ // It's up to the caller to decide what to do if the value isn't in the enum.
+ ktx2_df_channel_id get_dfd_channel_id0() const { return m_dfd_chan0; }
+ ktx2_df_channel_id get_dfd_channel_id1() const { return m_dfd_chan1; }
+
+ // Key value field data.
+ struct key_value
+ {
+ // The key field is UTF8 and always zero terminated.
+ basisu::uint8_vec m_key;
+
+ // The value may be empty. It consists of raw bytes which may or may not be zero terminated.
+ basisu::uint8_vec m_value;
+
+ bool operator< (const key_value& rhs) const { return strcmp((const char*)m_key.data(), (const char *)rhs.m_key.data()) < 0; }
+ };
+ typedef basisu::vector<key_value> key_value_vec;
+
+ // Returns the array of key-value entries. This may be empty. Valid after init().
+ // The order of key values fields in this array exactly matches the order they were stored in the file. The keys are supposed to be sorted by their Unicode code points.
+ const key_value_vec& get_key_values() const { return m_key_values; }
+
+ const basisu::uint8_vec *find_key(const std::string& key_name) const;
+
+ // Low-level ETC1S specific accessors
+
+ // Returns the ETC1S global supercompression data header, which is only valid after start_transcoding() is called.
+ const ktx2_etc1s_global_data_header& get_etc1s_header() const { return m_etc1s_header; }
+
+ // Returns the array of ETC1S image descriptors, which is only valid after get_etc1s_image_descs() is called.
+ const basisu::vector<ktx2_etc1s_image_desc>& get_etc1s_image_descs() const { return m_etc1s_image_descs; }
+
+ // Must have called startTranscoding() first
+ uint32_t get_etc1s_image_descs_image_flags(uint32_t level_index, uint32_t layer_index, uint32_t face_index) const;
+
+ // is_video() is only valid after start_transcoding() is called.
+ // For ETC1S data, if this returns true you must currently transcode the file from first to last frame, in order, without skipping any frames.
+ bool is_video() const { return m_is_video; }
+
+ // start_transcoding() MUST be called before calling transcode_image().
+ // This method decompresses the ETC1S global endpoint/selector codebooks, which is not free, so try to avoid calling it excessively.
+ bool start_transcoding();
+
+ // get_image_level_info() be called after init(), but the m_iframe_flag's won't be valid until start_transcoding() is called.
+ // You can call this method before calling transcode_image_level() to retrieve basic information about the mipmap level's dimensions, etc.
+ bool get_image_level_info(ktx2_image_level_info& level_info, uint32_t level_index, uint32_t layer_index, uint32_t face_index) const;
+
+ // transcode_image_level() transcodes a single 2D texture or cubemap face from the KTX2 file.
+ // Internally it uses the same low-level transcode API's as basisu_transcoder::transcode_image_level().
+ // If the file is UASTC and is supercompressed with Zstandard, and the file is a texture array or cubemap, it's highly recommended that each mipmap level is
+ // completely transcoded before switching to another level. Every time the mipmap level is changed all supercompressed level data must be decompressed using Zstandard as a single unit.
+ // Currently ETC1S videos must always be transcoded from first to last frame (or KTX2 "layer"), in order, with no skipping of frames.
+ // By default this method is not thread safe unless you specify a pointer to a user allocated thread-specific transcoder_state struct.
+ bool transcode_image_level(
+ uint32_t level_index, uint32_t layer_index, uint32_t face_index,
+ void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
+ basist::transcoder_texture_format fmt,
+ uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1,
+ ktx2_transcoder_state *pState = nullptr);
+
+ private:
+ const uint8_t* m_pData;
+ uint32_t m_data_size;
+
+ ktx2_header m_header;
+ basisu::vector<ktx2_level_index> m_levels;
+ basisu::uint8_vec m_dfd;
+ key_value_vec m_key_values;
+
+ ktx2_etc1s_global_data_header m_etc1s_header;
+ basisu::vector<ktx2_etc1s_image_desc> m_etc1s_image_descs;
+
+ basist::basis_tex_format m_format;
+
+ uint32_t m_dfd_color_model;
+ ktx2_df_color_primaries m_dfd_color_prims;
+ uint32_t m_dfd_transfer_func;
+ uint32_t m_dfd_flags;
+ uint32_t m_dfd_samples;
+ ktx2_df_channel_id m_dfd_chan0, m_dfd_chan1;
+
+ basist::basisu_lowlevel_etc1s_transcoder m_etc1s_transcoder;
+ basist::basisu_lowlevel_uastc_transcoder m_uastc_transcoder;
+
+ ktx2_transcoder_state m_def_transcoder_state;
+
+ bool m_has_alpha;
+ bool m_is_video;
+
+ bool decompress_level_data(uint32_t level_index, basisu::uint8_vec& uncomp_data);
+ bool decompress_etc1s_global_data();
+ bool read_key_values();
+ };
+
+#endif // BASISD_SUPPORT_KTX2
+
+ // Returns true if the transcoder was compiled with KTX2 support.
+ bool basisu_transcoder_supports_ktx2();
+
+ // Returns true if the transcoder was compiled with Zstandard support.
+ bool basisu_transcoder_supports_ktx2_zstd();
+
} // namespace basisu
+
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_internal.h b/thirdparty/basis_universal/transcoder/basisu_transcoder_internal.h
index a9c6823d92..2422d788a9 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_internal.h
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_internal.h
@@ -1,5 +1,5 @@
// basisu_transcoder_internal.h - Universal texture format transcoder library.
-// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
//
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
//
@@ -20,8 +20,8 @@
#pragma warning (disable: 4127) // conditional expression is constant
#endif
-#define BASISD_LIB_VERSION 107
-#define BASISD_VERSION_STRING "01.11"
+#define BASISD_LIB_VERSION 115
+#define BASISD_VERSION_STRING "01.15"
#ifdef _DEBUG
#define BASISD_BUILD_DEBUG
@@ -45,38 +45,44 @@ namespace basist
enum class block_format
{
cETC1, // ETC1S RGB
+ cETC2_RGBA, // full ETC2 EAC RGBA8 block
cBC1, // DXT1 RGB
+ cBC3, // BC4 block followed by a four color BC1 block
cBC4, // DXT5A (alpha block only)
+ cBC5, // two BC4 blocks
cPVRTC1_4_RGB, // opaque-only PVRTC1 4bpp
cPVRTC1_4_RGBA, // PVRTC1 4bpp RGBA
- cBC7_M6_OPAQUE_ONLY, // RGB BC7 mode 6
+ cBC7, // Full BC7 block, any mode
cBC7_M5_COLOR, // RGB BC7 mode 5 color (writes an opaque mode 5 block)
cBC7_M5_ALPHA, // alpha portion of BC7 mode 5 (cBC7_M5_COLOR output data must have been written to the output buffer first to set the mode/rot fields etc.)
cETC2_EAC_A8, // alpha block of ETC2 EAC (first 8 bytes of the 16-bit ETC2 EAC RGBA format)
cASTC_4x4, // ASTC 4x4 (either color-only or color+alpha). Note that the transcoder always currently assumes sRGB is not enabled when outputting ASTC
// data. If you use a sRGB ASTC format you'll get ~1 LSB of additional error, because of the different way ASTC decoders scale 8-bit endpoints to 16-bits during unpacking.
+
cATC_RGB,
cATC_RGBA_INTERPOLATED_ALPHA,
cFXT1_RGB, // Opaque-only, has oddball 8x4 pixel block size
+
+ cPVRTC2_4_RGB,
+ cPVRTC2_4_RGBA,
+
+ cETC2_EAC_R11,
+ cETC2_EAC_RG11,
cIndices, // Used internally: Write 16-bit endpoint and selector indices directly to output (output block must be at least 32-bits)
cRGB32, // Writes RGB components to 32bpp output pixels
cRGBA32, // Writes RGB255 components to 32bpp output pixels
cA32, // Writes alpha component to 32bpp output pixels
-
+
cRGB565,
cBGR565,
cRGBA4444_COLOR,
cRGBA4444_ALPHA,
cRGBA4444_COLOR_OPAQUE,
-
- cPVRTC2_4_RGB,
- cPVRTC2_4_RGBA,
-
- cETC2_EAC_R11,
-
+ cRGBA4444,
+
cTotalBlockFormats
};
@@ -116,7 +122,7 @@ namespace basist
basisu::clear_vector(m_tree);
}
- bool init(uint32_t total_syms, const uint8_t *pCode_sizes)
+ bool init(uint32_t total_syms, const uint8_t *pCode_sizes, uint32_t fast_lookup_bits = basisu::cHuffmanFastLookupBits)
{
if (!total_syms)
{
@@ -127,8 +133,10 @@ namespace basist
m_code_sizes.resize(total_syms);
memcpy(&m_code_sizes[0], pCode_sizes, total_syms);
+ const uint32_t huffman_fast_lookup_size = 1 << fast_lookup_bits;
+
m_lookup.resize(0);
- m_lookup.resize(basisu::cHuffmanFastLookupSize);
+ m_lookup.resize(huffman_fast_lookup_size);
m_tree.resize(0);
m_tree.resize(total_syms * 2);
@@ -166,10 +174,10 @@ namespace basist
for (l = code_size; l > 0; l--, cur_code >>= 1)
rev_code = (rev_code << 1) | (cur_code & 1);
- if (code_size <= basisu::cHuffmanFastLookupBits)
+ if (code_size <= fast_lookup_bits)
{
uint32_t k = (code_size << 16) | sym_index;
- while (rev_code < basisu::cHuffmanFastLookupSize)
+ while (rev_code < huffman_fast_lookup_size)
{
if (m_lookup[rev_code] != 0)
{
@@ -184,9 +192,9 @@ namespace basist
}
int tree_cur;
- if (0 == (tree_cur = m_lookup[rev_code & (basisu::cHuffmanFastLookupSize - 1)]))
+ if (0 == (tree_cur = m_lookup[rev_code & (huffman_fast_lookup_size - 1)]))
{
- const uint32_t idx = rev_code & (basisu::cHuffmanFastLookupSize - 1);
+ const uint32_t idx = rev_code & (huffman_fast_lookup_size - 1);
if (m_lookup[idx] != 0)
{
// Supplied codesizes can't create a valid prefix code.
@@ -204,9 +212,9 @@ namespace basist
return false;
}
- rev_code >>= (basisu::cHuffmanFastLookupBits - 1);
+ rev_code >>= (fast_lookup_bits - 1);
- for (int j = code_size; j > (basisu::cHuffmanFastLookupBits + 1); j--)
+ for (int j = code_size; j > ((int)fast_lookup_bits + 1); j--)
{
tree_cur -= ((rev_code >>= 1) & 1);
@@ -254,6 +262,8 @@ namespace basist
}
const basisu::uint8_vec &get_code_sizes() const { return m_code_sizes; }
+ const basisu::int_vec get_lookup() const { return m_lookup; }
+ const basisu::int16_vec get_tree() const { return m_tree; }
bool is_valid() const { return m_code_sizes.size() > 0; }
@@ -430,9 +440,11 @@ namespace basist
return v;
}
- inline uint32_t decode_huffman(const huffman_decoding_table &ct)
+ inline uint32_t decode_huffman(const huffman_decoding_table &ct, int fast_lookup_bits = basisu::cHuffmanFastLookupBits)
{
assert(ct.m_code_sizes.size());
+
+ const uint32_t huffman_fast_lookup_size = 1 << fast_lookup_bits;
while (m_bit_buf_size < 16)
{
@@ -448,14 +460,14 @@ namespace basist
int code_len;
int sym;
- if ((sym = ct.m_lookup[m_bit_buf & (basisu::cHuffmanFastLookupSize - 1)]) >= 0)
+ if ((sym = ct.m_lookup[m_bit_buf & (huffman_fast_lookup_size - 1)]) >= 0)
{
code_len = sym >> 16;
sym &= 0xFFFF;
}
else
{
- code_len = basisu::cHuffmanFastLookupBits;
+ code_len = fast_lookup_bits;
do
{
sym = ct.m_tree[~sym + ((m_bit_buf >> code_len++) & 1)]; // ~sym = -sym - 1
@@ -635,6 +647,11 @@ namespace basist
return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i);
}
+ enum eNoClamp
+ {
+ cNoClamp = 0
+ };
+
struct color32
{
union
@@ -655,21 +672,33 @@ namespace basist
color32() { }
color32(uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { set(vr, vg, vb, va); }
+ color32(eNoClamp unused, uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { (void)unused; set_noclamp_rgba(vr, vg, vb, va); }
void set(uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { c[0] = static_cast<uint8_t>(vr); c[1] = static_cast<uint8_t>(vg); c[2] = static_cast<uint8_t>(vb); c[3] = static_cast<uint8_t>(va); }
+ void set_noclamp_rgb(uint32_t vr, uint32_t vg, uint32_t vb) { c[0] = static_cast<uint8_t>(vr); c[1] = static_cast<uint8_t>(vg); c[2] = static_cast<uint8_t>(vb); }
+ void set_noclamp_rgba(uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { set(vr, vg, vb, va); }
+
void set_clamped(int vr, int vg, int vb, int va) { c[0] = clamp255(vr); c[1] = clamp255(vg); c[2] = clamp255(vb); c[3] = clamp255(va); }
uint8_t operator[] (uint32_t idx) const { assert(idx < 4); return c[idx]; }
uint8_t &operator[] (uint32_t idx) { assert(idx < 4); return c[idx]; }
bool operator== (const color32&rhs) const { return m == rhs.m; }
+
+ static color32 comp_min(const color32& a, const color32& b) { return color32(cNoClamp, basisu::minimum(a[0], b[0]), basisu::minimum(a[1], b[1]), basisu::minimum(a[2], b[2]), basisu::minimum(a[3], b[3])); }
+ static color32 comp_max(const color32& a, const color32& b) { return color32(cNoClamp, basisu::maximum(a[0], b[0]), basisu::maximum(a[1], b[1]), basisu::maximum(a[2], b[2]), basisu::maximum(a[3], b[3])); }
};
struct endpoint
{
color32 m_color5;
uint8_t m_inten5;
+ bool operator== (const endpoint& rhs) const
+ {
+ return (m_color5.r == rhs.m_color5.r) && (m_color5.g == rhs.m_color5.g) && (m_color5.b == rhs.m_color5.b) && (m_inten5 == rhs.m_inten5);
+ }
+ bool operator!= (const endpoint& rhs) const { return !(*this == rhs); }
};
struct selector
@@ -682,6 +711,17 @@ namespace basist
uint8_t m_lo_selector, m_hi_selector;
uint8_t m_num_unique_selectors;
+ bool operator== (const selector& rhs) const
+ {
+ return (m_selectors[0] == rhs.m_selectors[0]) &&
+ (m_selectors[1] == rhs.m_selectors[1]) &&
+ (m_selectors[2] == rhs.m_selectors[2]) &&
+ (m_selectors[3] == rhs.m_selectors[3]);
+ }
+ bool operator!= (const selector& rhs) const
+ {
+ return !(*this == rhs);
+ }
void init_flags()
{
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_astc.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_astc.inc
index 7f38f4a863..cd634c0df5 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_astc.inc
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_astc.inc
@@ -478,4 +478,4 @@
{31,1,10801},{47,1,12162},{14,1,6117},{14,1,6117},{8,1,50},{20,1,7322},{0,1,1241},{21,1,914},{21,1,914},{21,1,914},{7,1,274},{35,5,1513},{9,1,585},{9,1,585},{26,1,0},{27,1,1513},{26,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{0,1,0},{1,1,0},{0,1,0},{47,0,9250},{47,0,9250},{47,0,9250},{47,0,9250},{12,1,3690},
{12,1,3690},{12,1,3690},{8,1,50},{0,1,1241},{0,1,1241},{45,1,65535},{14,1,33274},{42,1,19608},{42,1,13375},{47,1,62627},{42,1,22211},{10,1,6045},{24,1,138},{36,1,39015},{0,1,1732},{35,1,1048},{5,1,766},{5,1,666},{37,1,212},{3,3,1473},{7,1,675},{23,1,410},{14,1,1},{3,3,1473},{14,1,1},{13,1,14121},{13,1,14121},{13,1,14121},{45,1,10571},{45,1,11434},{30,1,6081},{30,1,6081},
{40,1,137},{36,1,6926},{2,1,1445},{5,1,666},{5,1,666},{5,1,666},{37,1,212},{35,3,1105},{23,1,410},{23,1,410},{14,1,1},{25,1,1105},{14,1,1},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{0,1,0},{1,1,0},{0,1,0},{15,0,9256},{15,0,9256},{15,0,9256},{15,0,9256},{14,1,3985},{14,1,3985},{14,1,3985},{40,1,137},{2,1,1445},
-{2,1,1445}, \ No newline at end of file
+{2,1,1445},
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_astc_0_255.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_astc_0_255.inc
index 5e7a75396d..da4e7fee98 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_astc_0_255.inc
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_astc_0_255.inc
@@ -478,4 +478,4 @@
{137,255,10742},{135,255,12066},{107,255,6089},{107,255,6089},{67,255,45},{37,255,7233},{1,255,1184},{218,255,900},{218,255,900},{218,255,900},{204,255,272},{255,167,1513},{189,255,562},{189,255,562},{86,255,0},{253,213,1513},{86,255,0},{255,252,0},{255,254,0},{254,255,0},{252,255,0},{255,252,0},{255,254,0},{252,255,0},{0,255,0},{255,254,0},{0,255,0},{132,0,9248},{132,0,9248},{132,0,9248},{132,0,9248},{98,255,3656},
{98,255,3656},{98,255,3656},{67,255,45},{1,255,1184},{1,255,1184},{138,255,65535},{107,255,33448},{95,255,19729},{89,255,13446},{135,255,62717},{95,255,22307},{79,255,6021},{73,255,105},{40,255,38959},{0,254,1627},{230,255,996},{224,255,756},{221,255,653},{213,255,194},{255,204,1473},{207,255,675},{198,255,405},{110,255,0},{255,230,1473},{110,255,0},{162,255,14060},{162,255,14060},{162,255,14060},{146,255,10545},{141,255,11378},{116,255,6077},{116,255,6077},
{76,255,137},{40,255,6873},{7,255,1412},{221,255,653},{221,255,653},{221,255,653},{213,255,194},{255,180,1105},{198,255,405},{198,255,405},{110,255,0},{255,218,1105},{110,255,0},{255,252,0},{255,254,0},{254,255,0},{252,255,0},{255,252,0},{255,254,0},{252,255,0},{0,255,0},{255,254,0},{0,255,0},{140,0,9248},{140,0,9248},{140,0,9248},{140,0,9248},{107,255,3929},{107,255,3929},{107,255,3929},{76,255,137},{7,255,1412},
-{7,255,1412}, \ No newline at end of file
+{7,255,1412},
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_atc_55.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_atc_55.inc
index 61f7476efc..7acedd6a6f 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_atc_55.inc
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_atc_55.inc
@@ -478,4 +478,4 @@
{17,31,11312},{16,31,11037},{13,31,6429},{13,31,6429},{8,31,260},{6,31,10457},{0,31,2642},{26,31,872},{26,31,872},{26,31,872},{25,31,397},{31,22,1513},{23,31,794},{23,31,794},{13,31,1},{29,27,1513},{13,31,1},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{0,31,0},{31,31,0},{0,31,0},{16,0,9248},{16,0,9248},{16,0,9248},{16,0,9248},{12,31,3074},
{12,31,3074},{12,31,3074},{8,31,260},{0,31,2642},{0,31,2642},{17,31,58848},{15,31,39619},{13,31,24975},{12,31,19007},{16,31,54474},{13,31,27057},{10,31,8569},{9,31,461},{8,31,51302},{0,31,5046},{28,31,979},{27,31,806},{27,31,637},{26,31,292},{31,26,1473},{26,31,953},{24,31,605},{16,31,0},{29,29,1473},{16,31,0},{19,31,13604},{19,31,13604},{19,31,13604},{18,31,11057},{16,31,10429},{14,31,6339},{14,31,6339},
{10,31,424},{8,31,9713},{1,31,2900},{27,31,637},{27,31,637},{27,31,637},{26,31,292},{30,25,1105},{24,31,605},{24,31,605},{16,31,0},{30,27,1105},{16,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{0,31,0},{31,31,0},{0,31,0},{17,0,9248},{17,0,9248},{17,0,9248},{17,0,9248},{12,31,3330},{12,31,3330},{12,31,3330},{10,31,424},{1,31,2900},
-{1,31,2900}, \ No newline at end of file
+{1,31,2900},
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_atc_56.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_atc_56.inc
index f57a232a85..2b56c0944c 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_atc_56.inc
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_atc_56.inc
@@ -478,4 +478,4 @@
{17,63,11312},{16,63,11037},{13,63,6429},{13,63,6429},{8,63,260},{6,63,10457},{0,63,2642},{26,63,872},{26,63,872},{26,63,872},{25,63,397},{31,45,1513},{23,63,794},{23,63,794},{13,63,1},{31,52,1513},{13,63,1},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{0,63,0},{31,63,0},{0,63,0},{16,0,9248},{16,0,9248},{16,0,9248},{16,0,9248},{12,63,3074},
{12,63,3074},{12,63,3074},{8,63,260},{0,63,2642},{0,63,2642},{17,63,58848},{15,63,39619},{13,63,24975},{12,63,19007},{16,63,54474},{13,63,27057},{10,63,8569},{9,63,461},{8,63,51302},{0,63,5046},{28,63,979},{27,63,806},{27,63,637},{26,63,292},{30,56,1473},{26,63,953},{24,63,605},{16,63,0},{30,58,1473},{16,63,0},{19,63,13604},{19,63,13604},{19,63,13604},{18,63,11057},{16,63,10429},{14,63,6339},{14,63,6339},
{10,63,424},{8,63,9713},{1,63,2900},{27,63,637},{27,63,637},{27,63,637},{26,63,292},{31,48,1105},{24,63,605},{24,63,605},{16,63,0},{31,54,1105},{16,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{0,63,0},{31,63,0},{0,63,0},{17,0,9248},{17,0,9248},{17,0,9248},{17,0,9248},{12,63,3330},{12,63,3330},{12,63,3330},{10,63,424},{1,63,2900},
-{1,63,2900}, \ No newline at end of file
+{1,63,2900},
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m5_alpha.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m5_alpha.inc
index 433b126a71..6669852923 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m5_alpha.inc
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m5_alpha.inc
@@ -46,4 +46,4 @@
{76,0,3},{255,1,27},{255,7,24},{255,1,27},{179,39,8},{255,22,16},{85,0,3},{255,2,27},{255,22,24},{255,7,27},{187,47,8},{255,47,16},{93,0,3},{255,4,27},{251,100,28},{182,0,7},{195,55,8},{255,71,16},{101,0,3},{255,4,27},{253,108,28},{191,0,7},{203,63,8},{255,95,16},{109,0,3},{255,7,27},{255,118,28},{200,0,7},{212,72,8},{255,123,16},{118,0,3},{246,0,7},
{255,129,28},{209,0,7},{220,80,8},{255,147,16},{126,0,3},{246,0,7},{255,138,28},{218,0,7},{228,88,8},{255,172,16},{134,0,3},{249,3,7},{245,91,8},{228,3,7},{236,96,8},{255,196,16},{142,6,3},{251,14,7},{250,102,8},{237,12,7},{245,105,8},{255,223,16},{151,15,3},{253,22,7},{254,112,8},{245,20,7},{253,113,8},{255,248,16},{159,23,3},{253,31,7},{255,124,8},{249,28,7},
{255,124,8},{255,0,0},{167,31,3},{254,39,7},{255,10,4},{252,37,7},{255,10,4},{255,0,0},{175,39,3},{255,48,7},{255,38,4},{254,48,7},{255,38,4},{255,0,0},{184,48,3},{255,56,7},{255,62,4},{255,56,7},{255,62,4},{255,0,0},{192,56,3},{255,65,7},{255,86,4},{255,65,7},{255,86,4},{255,0,0},{200,64,3},{255,74,7},{255,111,4},{255,77,7},{255,111,4},{255,0,0},
-{208,5,2}, \ No newline at end of file
+{208,5,2},
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m5_color.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m5_color.inc
index 357b14b7a1..c0780988d8 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m5_color.inc
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m5_color.inc
@@ -478,4 +478,4 @@
{70,127,10779},{68,127,12146},{54,127,6176},{54,127,6176},{34,127,52},{14,127,7281},{2,127,1213},{109,127,937},{109,127,937},{109,127,937},{102,127,281},{127,84,1513},{93,127,565},{93,127,565},{43,127,0},{127,106,1513},{43,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{0,127,0},{127,127,0},{0,127,0},{65,0,9250},{65,0,9250},{65,0,9250},{65,0,9250},{49,127,3656},
{49,127,3656},{49,127,3656},{34,127,52},{2,127,1213},{2,127,1213},{71,127,63180},{60,127,37225},{52,127,26137},{48,127,18128},{68,127,59595},{51,127,22636},{42,127,8480},{37,127,164},{22,127,37455},{0,126,2073},{114,127,1019},{111,127,766},{111,127,666},{105,127,205},{127,102,1473},{102,127,681},{99,127,405},{56,127,0},{127,115,1473},{56,127,0},{79,127,14066},{79,127,14066},{79,127,14066},{73,127,10571},{71,127,11450},{59,127,6166},{59,127,6166},
{37,127,148},{25,127,6914},{5,127,1413},{111,127,666},{111,127,666},{111,127,666},{105,127,205},{127,90,1105},{99,127,405},{99,127,405},{56,127,0},{127,109,1105},{56,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{0,127,0},{127,127,0},{0,127,0},{69,0,9250},{69,0,9250},{69,0,9250},{69,0,9250},{52,127,3940},{52,127,3940},{52,127,3940},{37,127,148},{5,127,1413},
-{5,127,1413}, \ No newline at end of file
+{5,127,1413},
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m6.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m6.inc
deleted file mode 100644
index 6b814e6132..0000000000
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_bc7_m6.inc
+++ /dev/null
@@ -1,4383 +0,0 @@
-// Copyright (C) 2017-2019 Binomial LLC. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-static const uint32_t g_etc1_to_bc7_m6_table0[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x80000,0x80000,0x1,0x40000,0x40000,0x40000,0x80000,0x80000,0x1,0x80000,0x80000,0x1,0x1,0x40000,0x40000,0x40000,0x80000,0x80000,0x1,0x80000,0x80000,0x1,0x1,0x80000,
-0x80000,0x1,0x1,0x1,0x40000,0x40000,0x40000,0x40000,0x40000,0x80000,0x80000,0x80000,0x40000,0x40000,0x80000,0x1,0x80000,0x100000,0x180000,0x2C0000,0x6000001,0x180000,0x2C0000,0x6000001,0x2C0000,0x6000001,0x6000001,0x180000,0x2C0000,0x6000001,0x2C0000,0x6000001,
-0x6000001,0x2C0000,0x6000001,0x6000001,0x6000001,0x180000,0x2C0000,0x6000001,0x2C0000,0x6000001,0x6000001,0x2C0000,0x6000001,0x6000001,0x6000001,0x2C0000,0x6000001,0x6000001,0x6000001,0x6000001,0x140000,0x100000,0x100000,0x180000,0x240000,0x440000,0x6000001,0x6000001,0x140000,0x1C0000,0xD40000,0x6000001,
-0x200000,0x4002C,0x16000004,0xA000005,0x6000005,0xE000012,0x8000005,0x6000001,0x6000012,0x400000A,0x4000012,0x8000023,0x600000D,0x6000005,0x6000016,0x400000E,0x4000016,0x4000023,0x4000013,0x400001B,0x2000023,0x4002C,0x6000011,0x6000009,0x600001A,0x4000012,0x400001A,0x2040027,0x4000017,0x200001F,0x2000024,0x8002C,
-0x400001C,0x2000022,0x2000027,0x200002C,0x1600000B,0x48000012,0x78000004,0xE00000C,0xA000009,0x600000C,0x6000009,0x4000011,0x1000000F,0xA000012,0x4000013,0x200001F,0x8002C,0x80024,0x12040004,0xA040004,0x6000005,0xE000012,0x8000005,0x6000001,0x6000012,0x400000A,0x4000012,0x80023,0x600000D,0x6000005,0x6000016,0x400000E,
-0x4000016,0xC0023,0x4000013,0x400001B,0x2000023,0x80023,0x600000D,0x6000005,0x6000016,0x400000E,0x4000016,0xC0023,0x4000013,0x400001B,0x2000023,0xC0023,0x4000013,0x400001B,0x2000023,0x2000023,0x1600000B,0x48000012,0x5A040004,0xE00000C,0xA000009,0x600000C,0x6000009,0x4000011,0x1000000E,0xA000011,0x4000013,0x400001B,
-0xC0023,0x4,0x4,0x4,0x4,0x4000000,0x4000000,0x4000000,0x2000000,0x2000000,0x1,0x2000002,0x2000002,0x2000002,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2000003,0x2000003,0x2000003,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x3,
-0x3,0x3,0x3,0x3,0x4000001,0x18000000,0x4,0x2000001,0x4000001,0x1,0x1,0x1,0x2000001,0x4000001,0x2,0x2,0x3,0x4,0x4,0x4,0x4,0x4000000,0x4000000,0x4000000,0x2000000,0x2000000,0x1,0x2000002,0x2000002,0x2000002,0x1,0x1,
-0x1,0x2,0x2,0x2,0x2,0x2000002,0x2000002,0x2000002,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x4000001,0x18000000,0x4,0x2000001,0x4000001,0x1,0x1,0x1,0x2000001,0x4000001,0x2,0x2,
-0x2,0x80014,0x12040000,0xA040000,0x6040001,0x20C0012,0x8000005,0x6000001,0x180012,0x400000A,0x4000012,0x20C0012,0x8000005,0x6000001,0x180012,0x400000A,0x4000012,0x180012,0x400000A,0x4000012,0x4000012,0x20C0012,0x8000005,0x6000001,0x180012,0x400000A,0x4000012,0x180012,0x400000A,0x4000012,0x4000012,0x180012,
-0x400000A,0x4000012,0x4000012,0x4000012,0x1C000008,0xC080012,0x5A040000,0xA040008,0xA000005,0x6000008,0x6000005,0x600000A,0x14000008,0xC000008,0x6000005,0x4000012,0x140012,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table1[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0x100000,0x100000,0x100000,0x100000,0x100000,
-0x100000,0x200000,0x200000,0x200000,0x4000001,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x200000,0x200000,0x200000,0x4000001,0x200000,0x200000,0x200000,0x4000001,0x4000001,0xC0000,0xC0000,0xC0000,0x20C0000,0x40C0000,0x100000,0x100000,0x140000,0x20C0000,0x40C0000,0x180000,0x200000,
-0x180000,0x140000,0x140000,0x140000,0x140000,0x1C0000,0x1C0000,0x1C0000,0x380000,0x380000,0x8000001,0x1C0000,0x1C0000,0x1C0000,0x380000,0x380000,0x8000001,0x380000,0x380000,0x8000001,0x8000001,0x1C0000,0x1C0000,0x1C0000,0x380000,0x380000,0x8000001,0x380000,0x380000,0x8000001,0x8000001,0x380000,
-0x380000,0x8000001,0x8000001,0x8000001,0x180000,0x2140000,0x140000,0x2180000,0x200000,0x280000,0x2C0000,0x440000,0x180000,0x1C0000,0x280000,0x8000001,0x280000,0x200000,0x300000,0x5C0000,0xE000001,0x300000,0x5C0000,0xE000001,0x5C0000,0xE000001,0xE000001,0x300000,0x5C0000,0xE000001,0x5C0000,0xE000001,
-0xE000001,0x5C0000,0xE000001,0xE000001,0xE000001,0x300000,0x5C0000,0xE000001,0x5C0000,0xE000001,0xE000001,0x5C0000,0xE000001,0xE000001,0xE000001,0x5C0000,0xE000001,0xE000001,0xE000001,0xE000001,0x280000,0x8200000,0x8200000,0x340000,0x4C0000,0x940000,0xE000001,0xE000001,0x2C0000,0x3C0000,0x1D40000,0xE000001,
-0x400000,0x100088,0x220C0034,0x140C0034,0xE0C0035,0x1E080026,0x14080015,0xE080019,0x10080026,0xE040016,0xC040026,0x20000033,0x16000009,0x1004000F,0x12000012,0xE000002,0xC000016,0x10000033,0xE000011,0xA00001B,0xA000033,0x180088,0x1200003D,0xE000034,0x12000036,0xE00001B,0xC000026,0xC00004B,0xC000023,0xA00002B,0xA000043,0x2C0088,
-0xA000054,0xA00004C,0x800005F,0x600008C,0x48000002,0x8C080026,0x9E0C0034,0x26000001,0x18000002,0x12000002,0x10000002,0xE000002,0x3200000E,0x1E000005,0x1000000B,0xA00002B,0x200088,0x140034,0x1E100008,0x12100009,0xE100009,0x1A0C0012,0x120C0001,0x100C0001,0x100C0012,0xE0C0005,0xC0C0012,0x200033,0x14040009,0xE080009,0x12000012,0xE000002,
-0xC040012,0x3C0033,0xE000011,0xA00001B,0xA000033,0x200033,0x14040009,0xE080009,0x12000012,0xE000002,0xC040012,0x3C0033,0xE000011,0xA00001B,0xA000033,0x3C0033,0xE000011,0xA00001B,0xA000033,0xA000033,0x44040001,0x6E0C0012,0x80100008,0x20040001,0x18000002,0x12000002,0xE040002,0xE000002,0x32000005,0x1E000001,0x1000000A,0xA00001B,
-0x2C0033,0xC0034,0xC0034,0xC0034,0xC0034,0x14080014,0x14080014,0x14080014,0xC080014,0xC080014,0x8040015,0x16000008,0x16000008,0x16000008,0xE000001,0xE000001,0xA000005,0xA00000A,0xA00000A,0x8000001,0x600000A,0x20C0033,0x20C0033,0x20C0033,0xC000015,0xC000015,0x8000013,0x8000019,0x8000019,0x800000A,0x600000E,0x180033,
-0x180033,0x6000023,0x4000023,0x4000033,0x48000001,0x5C080014,0xC0034,0x24000001,0x18000001,0x12000001,0x10000001,0xC000001,0x24000009,0x1C000004,0xE000009,0x800000A,0x140033,0x100008,0x100008,0x100008,0x100008,0x100C0000,0x100C0000,0x100C0000,0xA0C0001,0xA0C0001,0x80C0001,0x180008,0x180008,0x180008,0xA080001,0xA080001,
-0x8080001,0x2C0008,0x2C0008,0x8000001,0x600000A,0x180008,0x180008,0x180008,0xA080001,0xA080001,0x8080001,0x2C0008,0x2C0008,0x8000001,0x600000A,0x2C0008,0x2C0008,0x8000001,0x600000A,0x600000A,0x3A040000,0x3E0C0000,0x100008,0x1E040000,0x14040000,0x10040000,0xC080001,0xC040000,0x26040001,0x1C000000,0x200008,0x8000001,
-0x200008,0x180014,0x1A140000,0x12140000,0xE140001,0x2240012,0x120C0001,0xE100001,0x4C0012,0xE000001,0xC000012,0x2240012,0x120C0001,0xE100001,0x4C0012,0xE000001,0xC000012,0x4C0012,0xE000001,0xC000012,0xC000012,0x2240012,0x120C0001,0xE100001,0x4C0012,0xE000001,0xC000012,0x4C0012,0xE000001,0xC000012,0xC000012,0x4C0012,
-0xE000001,0xC000012,0xC000012,0xC000012,0x44040001,0x1C0012,0x62140000,0x26000000,0x18000001,0x12000001,0xE040001,0xE000002,0x36000002,0x1E000001,0x10040000,0xC000012,0x340012,0x40014,0x40014,0x40014,0x40014,0x40014,0x40014,0x40014,0x40014,0x40014,0x40014,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,
-0x10000000,0x8000000,0x8000000,0x8000000,0x4000001,0x80012,0x80012,0x80012,0x80012,0x80012,0x80012,0x6000005,0x6000005,0x6000005,0x4000005,0xC0012,0xC0012,0xC0012,0x400000A,0x2000012,0x58000000,0x40014,0x40014,0x28000000,0x1C000000,0x14000000,0x14000000,0xE000000,0x20000005,0x16000002,0xA000001,0x6000005,
-0xC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table2[] = {
-0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x2C0000,
-0x2C0000,0x2C0000,0x2C0000,0x6000001,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x180000,0x200000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x280000,0x280000,0x280000,0x280000,0x280000,
-0x280000,0x500000,0x500000,0x500000,0xC000001,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x500000,0x500000,0x500000,0xC000001,0x500000,0x500000,0x500000,0xC000001,0xC000001,0x61C0000,0x1C0000,0x1C0000,0x200000,0x4200000,0x2240000,0x2240000,0x22C0000,0x200000,0x4200000,0x380000,0x500000,
-0x380000,0x240000,0x240000,0x240000,0x240000,0x340000,0x340000,0x340000,0x680000,0x680000,0x10000001,0x340000,0x340000,0x340000,0x680000,0x680000,0x10000001,0x680000,0x680000,0x10000001,0x10000001,0x340000,0x340000,0x340000,0x680000,0x680000,0x10000001,0x680000,0x680000,0x10000001,0x10000001,0x680000,
-0x680000,0x10000001,0x10000001,0x10000001,0x2280000,0xA240000,0x240000,0x300000,0x3C0000,0x4C0000,0x540000,0x800000,0x2C0000,0x340000,0x4C0000,0x10000001,0x4C0000,0x300000,0x2440000,0x8C0000,0x16000001,0x2440000,0x8C0000,0x16000001,0x8C0000,0x16000001,0x16000001,0x2440000,0x8C0000,0x16000001,0x8C0000,0x16000001,
-0x16000001,0x8C0000,0x16000001,0x16000001,0x16000001,0x2440000,0x8C0000,0x16000001,0x8C0000,0x16000001,0x16000001,0x8C0000,0x16000001,0x16000001,0x16000001,0x8C0000,0x16000001,0x16000001,0x16000001,0x16000001,0x3C0000,0x340000,0x340000,0x500000,0x740000,0xE00000,0x16000001,0x16000001,0x400000,0x580000,0x9E40000,0x16000001,
-0x640000,0x200088,0x2A1C0034,0x1C1C0034,0x161C0035,0x26180026,0x1C180015,0x16180019,0x18180026,0x16140016,0x14140026,0x28100033,0x1E100009,0x1814000F,0x1A100012,0x16100002,0x14100016,0x18100033,0x160C000F,0x140C001A,0x12100033,0x300088,0x22040033,0x16100034,0x1C040026,0x18080013,0x140C0024,0x1A000035,0x1604000A,0x14000013,0x12040033,0x5C0088,
-0x1600003C,0x12000034,0x10000044,0xE00008C,0x50100002,0x94180026,0xA61C0034,0x2E100001,0x20100002,0x1A100002,0x18100002,0x16100002,0x4A080001,0x2A0C0001,0x180C0009,0x14000013,0x400088,0x240034,0x26200008,0x1A200009,0x16200009,0x221C0012,0x1A1C0001,0x181C0001,0x181C0012,0x161C0005,0x141C0012,0x380033,0x1C140009,0x16180009,0x1A100012,0x16100002,
-0x14140012,0x700033,0x16040009,0x14000012,0x12000033,0x380033,0x1C140009,0x16180009,0x1A100012,0x16100002,0x14140012,0x700033,0x16040009,0x14000012,0x12000033,0x700033,0x16040009,0x14000012,0x12000033,0x12000033,0x4C140001,0x761C0012,0x88200008,0x28140001,0x20100002,0x1A100002,0x16140002,0x160C0002,0x4A080001,0x26100001,0x180C0008,0x14000012,
-0x500033,0x1C0034,0x1C0034,0x1C0034,0x1C0034,0x1C180014,0x1C180014,0x1C180014,0x14180014,0x14180014,0x10140015,0x1E100008,0x1E100008,0x1E100008,0x16100001,0x16100001,0x12100005,0x1210000A,0x1210000A,0x10100001,0xE10000A,0x2240033,0x2240033,0x2240033,0x18080012,0x18080012,0x10100013,0x16040009,0x16040009,0x10080002,0xE08000A,0x4C0033,
-0x4C0033,0x10000013,0xE00000E,0xC000033,0x50100001,0x64180014,0x1C0034,0x2C100001,0x20100001,0x1A100001,0x18100001,0x14100001,0x48080000,0x2A0C0000,0x16100009,0x10080002,0x340033,0x200008,0x200008,0x200008,0x200008,0x181C0000,0x181C0000,0x181C0000,0x121C0001,0x121C0001,0x101C0001,0x300008,0x300008,0x300008,0x12180001,0x12180001,
-0x10180001,0x5C0008,0x5C0008,0x10100001,0xE00000A,0x300008,0x300008,0x300008,0x12180001,0x12180001,0x10180001,0x5C0008,0x5C0008,0x10100001,0xE00000A,0x5C0008,0x5C0008,0x10100001,0xE00000A,0xE00000A,0x42140000,0x461C0000,0x200008,0x26140000,0x1C140000,0x18140000,0x14180001,0x14140000,0x3E0C0000,0x24100000,0x400008,0x10100001,
-0x400008,0x280014,0x22240000,0x1A240000,0x16240001,0x23C0012,0x1A1C0001,0x16200001,0x7C0012,0x16100001,0x14000012,0x23C0012,0x1A1C0001,0x16200001,0x7C0012,0x16100001,0x14000012,0x7C0012,0x16100001,0x14000012,0x14000012,0x23C0012,0x1A1C0001,0x16200001,0x7C0012,0x16100001,0x14000012,0x7C0012,0x16100001,0x14000012,0x14000012,0x7C0012,
-0x16100001,0x14000012,0x14000012,0x14000012,0x5C0C0000,0x2C0012,0x6A240000,0x2E100000,0x20100001,0x1C0C0000,0x16140001,0x16080001,0x52040000,0x2E080000,0x18140000,0x14000012,0x580012,0x140014,0x140014,0x140014,0x140014,0x140014,0x140014,0x140014,0x140014,0x140014,0x140014,0x18100000,0x18100000,0x18100000,0x18100000,0x18100000,
-0x18100000,0x10100000,0x10100000,0x10100000,0xC100001,0x200012,0x200012,0x200012,0x200012,0x200012,0x200012,0x10080001,0x10080001,0x10080001,0xC0C0001,0x3C0012,0x3C0012,0x3C0012,0xC000002,0xA000012,0x60100000,0x140014,0x140014,0x30100000,0x24100000,0x1C100000,0x1C100000,0x16100000,0x48080000,0x2A0C0000,0x12100001,0x10080001,
-0x2C0012,};
-static const uint32_t g_etc1_to_bc7_m6_table3[] = {
-0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x5C0000,
-0x5C0000,0x5C0000,0x5C0000,0xE000001,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x8200000,0x8200000,0x8200000,0x300000,0x400000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x400000,0x400000,0x400000,0x400000,0x400000,
-0x400000,0x800000,0x800000,0x800000,0x14000001,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x800000,0x800000,0x800000,0x14000001,0x800000,0x800000,0x800000,0x14000001,0x14000001,0xE2C0000,0x2C0000,0x2C0000,0x340000,0x4340000,0x3C0000,0x3C0000,0x480000,0x340000,0x4340000,0x5C0000,0x800000,
-0x5C0000,0x340000,0x340000,0x340000,0x340000,0x4C0000,0x4C0000,0x4C0000,0x980000,0x980000,0x18000001,0x4C0000,0x4C0000,0x4C0000,0x980000,0x980000,0x18000001,0x980000,0x980000,0x18000001,0x18000001,0x4C0000,0x4C0000,0x4C0000,0x980000,0x980000,0x18000001,0x980000,0x980000,0x18000001,0x18000001,0x980000,
-0x980000,0x18000001,0x18000001,0x18000001,0x3C0000,0x380000,0x340000,0x2440000,0x2540000,0x6C0000,0x7C0000,0xBC0000,0x400000,0x4C0000,0x6C0000,0x18000001,0x6C0000,0x400000,0x25C0000,0xBC0000,0x1E000001,0x25C0000,0xBC0000,0x1E000001,0xBC0000,0x1E000001,0x1E000001,0x25C0000,0xBC0000,0x1E000001,0xBC0000,0x1E000001,
-0x1E000001,0xBC0000,0x1E000001,0x1E000001,0x1E000001,0x25C0000,0xBC0000,0x1E000001,0xBC0000,0x1E000001,0x1E000001,0xBC0000,0x1E000001,0x1E000001,0x1E000001,0xBC0000,0x1E000001,0x1E000001,0x1E000001,0x1E000001,0x500000,0x440000,0x440000,0x6C0000,0x9C0000,0x1300000,0x1E000001,0x1E000001,0x2540000,0x780000,0x11F40000,0x1E000001,
-0x880000,0x300088,0x322C0034,0x242C0034,0x1E2C0035,0x2E280026,0x24280015,0x1E280019,0x20280026,0x1E240016,0x1C240026,0x30200033,0x26200009,0x2024000F,0x22200012,0x1E200002,0x1C200016,0x20200033,0x1E1C000F,0x1C1C001A,0x1A200033,0x2440088,0x2A140033,0x1E200034,0x24140026,0x20180013,0x1C1C0024,0x240C0033,0x1E14000A,0x1C100013,0x1A140033,0x8C0088,
-0x1E000034,0x1C000024,0x1A000037,0x1600008C,0x58200002,0x9C280026,0xAE2C0034,0x36200001,0x28200002,0x22200002,0x20200002,0x1E200002,0x52180001,0x321C0001,0x201C0009,0x1C100013,0x640088,0x340034,0x2E300008,0x22300009,0x1E300009,0x2A2C0012,0x222C0001,0x202C0001,0x202C0012,0x1E2C0005,0x1C2C0012,0x500033,0x24240009,0x1E280009,0x22200012,0x1E200002,
-0x1C240012,0xA00033,0x1E140009,0x1C100012,0x1A000033,0x500033,0x24240009,0x1E280009,0x22200012,0x1E200002,0x1C240012,0xA00033,0x1E140009,0x1C100012,0x1A000033,0xA00033,0x1E140009,0x1C100012,0x1A000033,0x1A000033,0x54240001,0x7E2C0012,0x90300008,0x30240001,0x28200002,0x22200002,0x1E240002,0x1E1C0002,0x52180001,0x2E200001,0x201C0008,0x1C100012,
-0x700033,0x2C0034,0x2C0034,0x2C0034,0x2C0034,0x24280014,0x24280014,0x24280014,0x1C280014,0x1C280014,0x18240015,0x26200008,0x26200008,0x26200008,0x1E200001,0x1E200001,0x1A200005,0x1A20000A,0x1A20000A,0x18200001,0x1620000A,0x23C0033,0x23C0033,0x23C0033,0x20180012,0x20180012,0x18200013,0x1E140009,0x1E140009,0x18180002,0x1618000A,0x7C0033,
-0x7C0033,0x180C0013,0x1604000A,0x14000033,0x58200001,0x6C280014,0x2C0034,0x34200001,0x28200001,0x22200001,0x20200001,0x1C200001,0x50180000,0x321C0000,0x1E200009,0x18180002,0x580033,0x300008,0x300008,0x300008,0x300008,0x202C0000,0x202C0000,0x202C0000,0x1A2C0001,0x1A2C0001,0x182C0001,0x2440008,0x2440008,0x2440008,0x1A280001,0x1A280001,
-0x18280001,0x8C0008,0x8C0008,0x18200001,0x1600000A,0x2440008,0x2440008,0x2440008,0x1A280001,0x1A280001,0x18280001,0x8C0008,0x8C0008,0x18200001,0x1600000A,0x8C0008,0x8C0008,0x18200001,0x1600000A,0x1600000A,0x4A240000,0x4E2C0000,0x300008,0x2E240000,0x24240000,0x20240000,0x1C280001,0x1C240000,0x461C0000,0x2C200000,0x640008,0x18200001,
-0x640008,0x380014,0x2A340000,0x22340000,0x1E340001,0x540012,0x222C0001,0x1E300001,0xAC0012,0x1E200001,0x1C000012,0x540012,0x222C0001,0x1E300001,0xAC0012,0x1E200001,0x1C000012,0xAC0012,0x1E200001,0x1C000012,0x1C000012,0x540012,0x222C0001,0x1E300001,0xAC0012,0x1E200001,0x1C000012,0xAC0012,0x1E200001,0x1C000012,0x1C000012,0xAC0012,
-0x1E200001,0x1C000012,0x1C000012,0x1C000012,0x641C0000,0x63C0012,0x72340000,0x36200000,0x28200001,0x241C0000,0x1E240001,0x1E180001,0x5A140000,0x36180000,0x20240000,0x1C000012,0x780012,0x240014,0x240014,0x240014,0x240014,0x240014,0x240014,0x240014,0x240014,0x240014,0x240014,0x20200000,0x20200000,0x20200000,0x20200000,0x20200000,
-0x20200000,0x18200000,0x18200000,0x18200000,0x14200001,0x380012,0x380012,0x380012,0x380012,0x380012,0x380012,0x18180001,0x18180001,0x18180001,0x141C0001,0x700012,0x700012,0x700012,0x140C0001,0x12000012,0x68200000,0x240014,0x240014,0x38200000,0x2C200000,0x24200000,0x24200000,0x1E200000,0x50180000,0x321C0000,0x1A200001,0x18180001,
-0x500012,};
-static const uint32_t g_etc1_to_bc7_m6_table4[] = {
-0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x940000,
-0x940000,0x940000,0x940000,0x18000000,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x2340000,0x2340000,0x2340000,0x480000,0x680000,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,
-0x5C0000,0xB80000,0xB80000,0xB80000,0x1E000000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0xB80000,0xB80000,0xB80000,0x1E000000,0xB80000,0xB80000,0xB80000,0x1E000000,0x1E000000,0x8400000,0x3C0001,0x3C0001,0x480000,0x24C0000,0x540000,0x540000,0x680000,0x480000,0x24C0000,0x800000,0xB80000,
-0x800000,0x440001,0x440001,0x440001,0x440001,0x680000,0x680000,0x680000,0xD00000,0xD00000,0x22000000,0x680000,0x680000,0x680000,0xD00000,0xD00000,0x22000000,0xD00000,0xD00000,0x22000000,0x22000000,0x680000,0x680000,0x680000,0xD00000,0xD00000,0x22000000,0xD00000,0xD00000,0x22000000,0x22000000,0xD00000,
-0xD00000,0x22000000,0x22000000,0x22000000,0x500000,0xC480000,0x440001,0x25C0000,0x740000,0x940000,0xA80000,0x1000000,0x580000,0x680000,0x940000,0x22000000,0x940000,0x500001,0x780000,0xF40000,0x28000000,0x780000,0xF40000,0x28000000,0xF40000,0x28000000,0x28000000,0x780000,0xF40000,0x28000000,0xF40000,0x28000000,
-0x28000000,0xF40000,0x28000000,0x28000000,0x28000000,0x780000,0xF40000,0x28000000,0xF40000,0x28000000,0x28000000,0xF40000,0x28000000,0x28000000,0x28000000,0xF40000,0x28000000,0x28000000,0x28000000,0x28000000,0x4640000,0x580000,0x580000,0x880000,0xC80000,0x1880000,0x28000000,0x28000000,0x700000,0x980000,0x1BE80000,0x28000000,
-0xAC0000,0x40008C,0x3E3C0033,0x2E3C0033,0x283C0033,0x38380024,0x2E380013,0x2A38001A,0x2A380024,0x26380016,0x24380026,0x36340034,0x2E34000A,0x2A34000F,0x2C300013,0x28300002,0x24340016,0x28340034,0x2630000F,0x24300019,0x22300035,0x600088,0x32280033,0x28300033,0x2C280026,0x282C0012,0x24300026,0x2E1C0033,0x28200009,0x24240015,0x22280034,0xC40088,
-0x280C0033,0x24140026,0x22080034,0x20000088,0x62340002,0xB4380024,0xC63C0033,0x3C340002,0x30340002,0x2A340002,0x28340002,0x28300002,0x5E280001,0x3E2C0001,0x28300009,0x24240015,0x8C0088,0x480033,0x3644000A,0x2C40000A,0x2840000A,0x30400013,0x2C3C0002,0x28400001,0x28400013,0x283C0005,0x243C0015,0x2680033,0x2E340009,0x2838000A,0x2C300012,0x28300001,
-0x24380014,0xD80033,0x28200008,0x24240014,0x22000034,0x2680033,0x2E340009,0x2838000A,0x2C300012,0x28300001,0x24380014,0xD80033,0x28200008,0x24240014,0x22000034,0xD80033,0x28200008,0x24240014,0x22000034,0x22000034,0x62340001,0x78400013,0x8A44000A,0x3C340001,0x30340001,0x2A340001,0x28340001,0x28300001,0x5E280001,0x3A300001,0x28300009,0x24240014,
-0x980033,0x3C0033,0x3C0033,0x3C0033,0x3C0033,0x30380012,0x30380012,0x30380012,0x26380012,0x26380012,0x22380012,0x2E340009,0x2E340009,0x2E340009,0x26340002,0x26340002,0x22340005,0x24300009,0x24300009,0x22300001,0x20300009,0x580033,0x580033,0x580033,0x282C0012,0x282C0012,0x22300012,0x26280009,0x26280009,0x22280001,0x20280009,0xB00033,
-0xB00033,0x221C0012,0x20100008,0x1E000034,0x56340002,0x84380012,0x3C0033,0x3A340001,0x30340001,0x2A340001,0x28340002,0x26300002,0x5E280000,0x38300001,0x28300008,0x22280001,0x7C0033,0x40000A,0x40000A,0x40000A,0x40000A,0x28400001,0x28400001,0x28400001,0x243C0001,0x243C0001,0x223C0001,0x600008,0x600008,0x600008,0x24380001,0x24380001,
-0x22380001,0xC40008,0xC40008,0x222C0000,0x20000008,0x600008,0x600008,0x600008,0x24380001,0x24380001,0x22380001,0xC40008,0xC40008,0x222C0000,0x20000008,0xC40008,0xC40008,0x222C0000,0x20000008,0x20000008,0x4A380000,0x48400001,0x40000A,0x3A340000,0x2C380000,0x28380000,0x26380000,0x24380001,0x4C300000,0x34340000,0x8C0008,0x222C0000,
-0x8C0008,0x4C0012,0x32480001,0x2A480001,0x28440001,0x700012,0x2C3C0001,0x28400000,0xE40012,0x282C0000,0x24000014,0x700012,0x2C3C0001,0x28400000,0xE40012,0x282C0000,0x24000014,0xE40012,0x282C0000,0x24000014,0x24000014,0x700012,0x2C3C0001,0x28400000,0xE40012,0x282C0000,0x24000014,0xE40012,0x282C0000,0x24000014,0x24000014,0xE40012,
-0x282C0000,0x24000014,0x24000014,0x24000014,0x722C0000,0x500012,0x6C480001,0x40300000,0x30340001,0x2C300000,0x28340000,0x28240000,0x66240000,0x3E2C0000,0x28380001,0x24000014,0xA00012,0x380012,0x380012,0x380012,0x380012,0x380012,0x380012,0x380012,0x380012,0x380012,0x380012,0x28340001,0x28340001,0x28340001,0x28340001,0x28340001,
-0x28340001,0x20340001,0x20340001,0x20340001,0x1E300001,0x2500012,0x2500012,0x2500012,0x2500012,0x2500012,0x2500012,0x22280001,0x22280001,0x22280001,0x1E2C0000,0xA40012,0xA40012,0xA40012,0x1E180000,0x1A000014,0x62340001,0x380012,0x380012,0x3A340001,0x30340001,0x2A340001,0x2A340001,0x26340001,0x5E280000,0x402C0000,0x24300000,0x22280001,
-0x740012,};
-static const uint32_t g_etc1_to_bc7_m6_table5[] = {
-0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0xC40000,
-0xC40000,0xC40000,0xC40000,0x20000000,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0xA440000,0xA440000,0xA440000,0x600000,0x8C0000,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x740000,0x740000,0x740000,0x740000,0x740000,
-0x740000,0xE80000,0xE80000,0xE80000,0x26000000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0xE80000,0xE80000,0xE80000,0x26000000,0xE80000,0xE80000,0xE80000,0x26000000,0x26000000,0x540000,0x4C0001,0x4C0001,0x4580000,0x2600000,0x2680000,0x2680000,0x2800000,0x4580000,0x2600000,0xA40000,0xE80000,
-0xA40000,0x540001,0x540001,0x540001,0x540001,0x800000,0x800000,0x800000,0x1000000,0x1000000,0x2A000000,0x800000,0x800000,0x800000,0x1000000,0x1000000,0x2A000000,0x1000000,0x1000000,0x2A000000,0x2A000000,0x800000,0x800000,0x800000,0x1000000,0x1000000,0x2A000000,0x1000000,0x1000000,0x2A000000,0x2A000000,0x1000000,
-0x1000000,0x2A000000,0x2A000000,0x2A000000,0x640000,0x5C0000,0x540001,0x740000,0x900000,0xB40000,0xD00000,0x13C0000,0x6C0000,0x800000,0xB40000,0x2A000000,0xB40000,0x600001,0x900000,0x1240000,0x30000000,0x900000,0x1240000,0x30000000,0x1240000,0x30000000,0x30000000,0x900000,0x1240000,0x30000000,0x1240000,0x30000000,
-0x30000000,0x1240000,0x30000000,0x30000000,0x30000000,0x900000,0x1240000,0x30000000,0x1240000,0x30000000,0x30000000,0x1240000,0x30000000,0x30000000,0x30000000,0x1240000,0x30000000,0x30000000,0x30000000,0x30000000,0x4780000,0x680000,0x680000,0xA40000,0xEC0000,0x1D80000,0x30000000,0x30000000,0x840000,0xB80000,0x23F80000,0x30000000,
-0xD00000,0x50008C,0x464C0033,0x364C0033,0x304C0033,0x40480024,0x36480013,0x3248001A,0x32480024,0x2E480016,0x2C480026,0x3E440034,0x3644000A,0x3244000F,0x34400013,0x30400002,0x2C440016,0x30440034,0x2E40000F,0x2C400019,0x2A400035,0x780088,0x3A380033,0x30400033,0x34380026,0x303C0012,0x2C400026,0x362C0033,0x30300009,0x2C340015,0x2A380034,0xF40088,
-0x301C0033,0x2C240026,0x2A180034,0x28000088,0x6A440002,0xBC480024,0xCE4C0033,0x44440002,0x38440002,0x32440002,0x30440002,0x30400002,0x66380001,0x463C0001,0x30400009,0x2C340015,0xAC0088,0x580033,0x3E54000A,0x3450000A,0x3050000A,0x38500013,0x344C0002,0x30500001,0x30500013,0x304C0005,0x2C4C0015,0x2800033,0x36440009,0x3048000A,0x34400012,0x30400001,
-0x2C480014,0x1080033,0x30300008,0x2C340014,0x2A000034,0x2800033,0x36440009,0x3048000A,0x34400012,0x30400001,0x2C480014,0x1080033,0x30300008,0x2C340014,0x2A000034,0x1080033,0x30300008,0x2C340014,0x2A000034,0x2A000034,0x6A440001,0x80500013,0x9254000A,0x44440001,0x38440001,0x32440001,0x30440001,0x30400001,0x66380001,0x42400001,0x30400009,0x2C340014,
-0xB80033,0x4C0033,0x4C0033,0x4C0033,0x4C0033,0x38480012,0x38480012,0x38480012,0x2E480012,0x2E480012,0x2A480012,0x36440009,0x36440009,0x36440009,0x2E440002,0x2E440002,0x2A440005,0x2C400009,0x2C400009,0x2A400001,0x28400009,0x700033,0x700033,0x700033,0x303C0012,0x303C0012,0x2A400012,0x2E380009,0x2E380009,0x2A380001,0x28380009,0xE40033,
-0xE40033,0x2A2C0012,0x28200008,0x26000034,0x5E440002,0x8C480012,0x4C0033,0x42440001,0x38440001,0x32440001,0x30440002,0x2E400002,0x66380000,0x40400001,0x30400008,0x2A380001,0xA00033,0x50000A,0x50000A,0x50000A,0x50000A,0x30500001,0x30500001,0x30500001,0x2C4C0001,0x2C4C0001,0x2A4C0001,0x780008,0x780008,0x780008,0x2C480001,0x2C480001,
-0x2A480001,0xF40008,0xF40008,0x2A3C0000,0x28000008,0x780008,0x780008,0x780008,0x2C480001,0x2C480001,0x2A480001,0xF40008,0xF40008,0x2A3C0000,0x28000008,0xF40008,0xF40008,0x2A3C0000,0x28000008,0x28000008,0x52480000,0x50500001,0x50000A,0x42440000,0x34480000,0x30480000,0x2E480000,0x2C480001,0x54400000,0x3C440000,0xAC0008,0x2A3C0000,
-0xAC0008,0x5C0012,0x3A580001,0x32580001,0x30540001,0x880012,0x344C0001,0x30500000,0x1140012,0x303C0000,0x2C000014,0x880012,0x344C0001,0x30500000,0x1140012,0x303C0000,0x2C000014,0x1140012,0x303C0000,0x2C000014,0x2C000014,0x880012,0x344C0001,0x30500000,0x1140012,0x303C0000,0x2C000014,0x1140012,0x303C0000,0x2C000014,0x2C000014,0x1140012,
-0x303C0000,0x2C000014,0x2C000014,0x2C000014,0x7A3C0000,0x8600012,0x74580001,0x48400000,0x38440001,0x34400000,0x30440000,0x30340000,0x6E340000,0x463C0000,0x30480001,0x2C000014,0xC00012,0x480012,0x480012,0x480012,0x480012,0x480012,0x480012,0x480012,0x480012,0x480012,0x480012,0x30440001,0x30440001,0x30440001,0x30440001,0x30440001,
-0x30440001,0x28440001,0x28440001,0x28440001,0x26400001,0x2680012,0x2680012,0x2680012,0x2680012,0x2680012,0x2680012,0x2A380001,0x2A380001,0x2A380001,0x263C0000,0xD80012,0xD80012,0xD80012,0x26280000,0x22000014,0x6A440001,0x480012,0x480012,0x42440001,0x38440001,0x32440001,0x32440001,0x2E440001,0x66380000,0x483C0000,0x2C400000,0x2A380001,
-0x980012,};
-static const uint32_t g_etc1_to_bc7_m6_table6[] = {
-0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0xF40000,
-0xF40000,0xF40000,0xF40000,0x28000000,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x580000,0x580000,0x580000,0x780000,0xAC0000,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,
-0x8C0000,0x1180000,0x1180000,0x1180000,0x2E000000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x1180000,0x1180000,0x1180000,0x2E000000,0x1180000,0x1180000,0x1180000,0x2E000000,0x2E000000,0x640000,0x5C0001,0x5C0001,0x6C0000,0x2740000,0x800000,0x800000,0x9C0000,0x6C0000,0x2740000,0xC80000,0x1180000,
-0xC80000,0x640001,0x640001,0x640001,0x640001,0x980000,0x980000,0x980000,0x1300000,0x1300000,0x32000000,0x980000,0x980000,0x980000,0x1300000,0x1300000,0x32000000,0x1300000,0x1300000,0x32000000,0x32000000,0x980000,0x980000,0x980000,0x1300000,0x1300000,0x32000000,0x1300000,0x1300000,0x32000000,0x32000000,0x1300000,
-0x1300000,0x32000000,0x32000000,0x32000000,0x4740000,0x6C0000,0x640001,0x2880000,0xAC0000,0xD80000,0xF80000,0x1780000,0x800000,0x980000,0xD80000,0x32000000,0xD80000,0x700001,0xA80000,0x1580000,0x38000000,0xA80000,0x1580000,0x38000000,0x1580000,0x38000000,0x38000000,0xA80000,0x1580000,0x38000000,0x1580000,0x38000000,
-0x38000000,0x1580000,0x38000000,0x38000000,0x38000000,0xA80000,0x1580000,0x38000000,0x1580000,0x38000000,0x38000000,0x1580000,0x38000000,0x38000000,0x38000000,0x1580000,0x38000000,0x38000000,0x38000000,0x38000000,0x48C0000,0x4780000,0x4780000,0xC00000,0x1140000,0x7F80000,0x38000000,0x38000000,0x2980000,0xD40000,0x2DCC0000,0x38000000,
-0xF00000,0x60008C,0x4E5C0033,0x3E5C0033,0x385C0033,0x48580024,0x3E580013,0x3A58001A,0x3A580024,0x36580016,0x34580026,0x46540034,0x3E54000A,0x3A54000F,0x3C500013,0x38500002,0x34540016,0x38540034,0x3650000F,0x34500019,0x32500035,0x900088,0x42480033,0x38500033,0x3C480026,0x384C0012,0x34500026,0x3E3C0033,0x38400009,0x34440015,0x32480034,0x1240088,
-0x382C0033,0x34340026,0x32280034,0x30000088,0x72540002,0xC4580024,0xD65C0033,0x4C540002,0x40540002,0x3A540002,0x38540002,0x38500002,0x6E480001,0x4E4C0001,0x38500009,0x34440015,0xD00088,0x680033,0x4664000A,0x3C60000A,0x3860000A,0x40600013,0x3C5C0002,0x38600001,0x38600013,0x385C0005,0x345C0015,0x2980033,0x3E540009,0x3858000A,0x3C500012,0x38500001,
-0x34580014,0x1380033,0x38400008,0x34440014,0x32000034,0x2980033,0x3E540009,0x3858000A,0x3C500012,0x38500001,0x34580014,0x1380033,0x38400008,0x34440014,0x32000034,0x1380033,0x38400008,0x34440014,0x32000034,0x32000034,0x72540001,0x88600013,0x9A64000A,0x4C540001,0x40540001,0x3A540001,0x38540001,0x38500001,0x6E480001,0x4A500001,0x38500009,0x34440014,
-0xDC0033,0x5C0033,0x5C0033,0x5C0033,0x5C0033,0x40580012,0x40580012,0x40580012,0x36580012,0x36580012,0x32580012,0x3E540009,0x3E540009,0x3E540009,0x36540002,0x36540002,0x32540005,0x34500009,0x34500009,0x32500001,0x30500009,0x880033,0x880033,0x880033,0x384C0012,0x384C0012,0x32500012,0x36480009,0x36480009,0x32480001,0x30480009,0x1140033,
-0x1140033,0x323C0012,0x30300008,0x2E000034,0x66540002,0x94580012,0x5C0033,0x4A540001,0x40540001,0x3A540001,0x38540002,0x36500002,0x6E480000,0x48500001,0x38500008,0x32480001,0xC00033,0x60000A,0x60000A,0x60000A,0x60000A,0x38600001,0x38600001,0x38600001,0x345C0001,0x345C0001,0x325C0001,0x900008,0x900008,0x900008,0x34580001,0x34580001,
-0x32580001,0x1240008,0x1240008,0x324C0000,0x30000008,0x900008,0x900008,0x900008,0x34580001,0x34580001,0x32580001,0x1240008,0x1240008,0x324C0000,0x30000008,0x1240008,0x1240008,0x324C0000,0x30000008,0x30000008,0x5A580000,0x58600001,0x60000A,0x4A540000,0x3C580000,0x38580000,0x36580000,0x34580001,0x5C500000,0x44540000,0xD00008,0x324C0000,
-0xD00008,0x6C0012,0x42680001,0x3A680001,0x38640001,0xA00012,0x3C5C0001,0x38600000,0x1440012,0x384C0000,0x34000014,0xA00012,0x3C5C0001,0x38600000,0x1440012,0x384C0000,0x34000014,0x1440012,0x384C0000,0x34000014,0x34000014,0xA00012,0x3C5C0001,0x38600000,0x1440012,0x384C0000,0x34000014,0x1440012,0x384C0000,0x34000014,0x34000014,0x1440012,
-0x384C0000,0x34000014,0x34000014,0x34000014,0x824C0000,0x740012,0x7C680001,0x50500000,0x40540001,0x3C500000,0x38540000,0x38440000,0x76440000,0x4E4C0000,0x38580001,0x34000014,0xE40012,0x580012,0x580012,0x580012,0x580012,0x580012,0x580012,0x580012,0x580012,0x580012,0x580012,0x38540001,0x38540001,0x38540001,0x38540001,0x38540001,
-0x38540001,0x30540001,0x30540001,0x30540001,0x2E500001,0x2800012,0x2800012,0x2800012,0x2800012,0x2800012,0x2800012,0x32480001,0x32480001,0x32480001,0x2E4C0000,0x1080012,0x1080012,0x1080012,0x2E380000,0x2A000014,0x72540001,0x580012,0x580012,0x4A540001,0x40540001,0x3A540001,0x3A540001,0x36540001,0x6E480000,0x504C0000,0x34500000,0x32480001,
-0xB80012,};
-static const uint32_t g_etc1_to_bc7_m6_table7[] = {
-0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x1240000,
-0x1240000,0x1240000,0x1240000,0x30000000,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x680000,0x680000,0x680000,0x900000,0xD00000,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,
-0xA40000,0x14C0000,0x14C0000,0x14C0000,0x36000000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0x14C0000,0x14C0000,0x14C0000,0x36000000,0x14C0000,0x14C0000,0x14C0000,0x36000000,0x36000000,0x2740000,0x6C0001,0x6C0001,0x800000,0x2880000,0x940000,0x940000,0xB80000,0x800000,0x2880000,0xE80000,0x14C0000,
-0xE80000,0x740001,0x740001,0x740001,0x740001,0xB00000,0xB00000,0xB00000,0x1640000,0x1640000,0x3A000000,0xB00000,0xB00000,0xB00000,0x1640000,0x1640000,0x3A000000,0x1640000,0x1640000,0x3A000000,0x3A000000,0xB00000,0xB00000,0xB00000,0x1640000,0x1640000,0x3A000000,0x1640000,0x1640000,0x3A000000,0x3A000000,0x1640000,
-0x1640000,0x3A000000,0x3A000000,0x3A000000,0x880000,0x67C0000,0x740001,0xA00000,0xC40000,0xF80000,0x1200000,0x1B40000,0x940000,0xB00000,0xF80000,0x3A000000,0xF80000,0x800001,0xC00000,0x1880000,0x40000000,0xC00000,0x1880000,0x40000000,0x1880000,0x40000000,0x40000000,0xC00000,0x1880000,0x40000000,0x1880000,0x40000000,
-0x40000000,0x1880000,0x40000000,0x40000000,0x40000000,0xC00000,0x1880000,0x40000000,0x1880000,0x40000000,0x40000000,0x1880000,0x40000000,0x40000000,0x40000000,0x1880000,0x40000000,0x40000000,0x40000000,0x40000000,0x4A00000,0xC880000,0xC880000,0xD80000,0x13C0000,0x11F80000,0x40000000,0x40000000,0xB00000,0xF40000,0x35DC0000,0x40000000,
-0x1140000,0x70008C,0x566C0033,0x466C0033,0x406C0033,0x50680024,0x46680013,0x4268001A,0x42680024,0x3E680016,0x3C680026,0x4E640034,0x4664000A,0x4264000F,0x44600013,0x40600002,0x3C640016,0x40640034,0x3E60000F,0x3C600019,0x3A600035,0xA80088,0x4A580033,0x40600033,0x44580026,0x405C0012,0x3C600026,0x464C0033,0x40500009,0x3C540015,0x3A580034,0x1580088,
-0x403C0033,0x3C440026,0x3A380034,0x38000088,0x7A640002,0xCC680024,0xDE6C0033,0x54640002,0x48640002,0x42640002,0x40640002,0x40600002,0x76580001,0x565C0001,0x40600009,0x3C540015,0xF00088,0x780033,0x4E74000A,0x4470000A,0x4070000A,0x48700013,0x446C0002,0x40700001,0x40700013,0x406C0005,0x3C6C0015,0x2B00033,0x46640009,0x4068000A,0x44600012,0x40600001,
-0x3C680014,0x1680033,0x40500008,0x3C540014,0x3A000034,0x2B00033,0x46640009,0x4068000A,0x44600012,0x40600001,0x3C680014,0x1680033,0x40500008,0x3C540014,0x3A000034,0x1680033,0x40500008,0x3C540014,0x3A000034,0x3A000034,0x7A640001,0x90700013,0xA274000A,0x54640001,0x48640001,0x42640001,0x40640001,0x40600001,0x76580001,0x52600001,0x40600009,0x3C540014,
-0xFC0033,0x6C0033,0x6C0033,0x6C0033,0x6C0033,0x48680012,0x48680012,0x48680012,0x3E680012,0x3E680012,0x3A680012,0x46640009,0x46640009,0x46640009,0x3E640002,0x3E640002,0x3A640005,0x3C600009,0x3C600009,0x3A600001,0x38600009,0xA00033,0xA00033,0xA00033,0x405C0012,0x405C0012,0x3A600012,0x3E580009,0x3E580009,0x3A580001,0x38580009,0x1440033,
-0x1440033,0x3A4C0012,0x38400008,0x36000034,0x6E640002,0x9C680012,0x6C0033,0x52640001,0x48640001,0x42640001,0x40640002,0x3E600002,0x76580000,0x50600001,0x40600008,0x3A580001,0xE40033,0x70000A,0x70000A,0x70000A,0x70000A,0x40700001,0x40700001,0x40700001,0x3C6C0001,0x3C6C0001,0x3A6C0001,0xA80008,0xA80008,0xA80008,0x3C680001,0x3C680001,
-0x3A680001,0x1580008,0x1580008,0x3A5C0000,0x38000008,0xA80008,0xA80008,0xA80008,0x3C680001,0x3C680001,0x3A680001,0x1580008,0x1580008,0x3A5C0000,0x38000008,0x1580008,0x1580008,0x3A5C0000,0x38000008,0x38000008,0x62680000,0x60700001,0x70000A,0x52640000,0x44680000,0x40680000,0x3E680000,0x3C680001,0x64600000,0x4C640000,0xF00008,0x3A5C0000,
-0xF00008,0x7C0012,0x4A780001,0x42780001,0x40740001,0xB80012,0x446C0001,0x40700000,0x1740012,0x405C0000,0x3C000014,0xB80012,0x446C0001,0x40700000,0x1740012,0x405C0000,0x3C000014,0x1740012,0x405C0000,0x3C000014,0x3C000014,0xB80012,0x446C0001,0x40700000,0x1740012,0x405C0000,0x3C000014,0x1740012,0x405C0000,0x3C000014,0x3C000014,0x1740012,
-0x405C0000,0x3C000014,0x3C000014,0x3C000014,0x8A5C0000,0x840012,0x84780001,0x58600000,0x48640001,0x44600000,0x40640000,0x40540000,0x7E540000,0x565C0000,0x40680001,0x3C000014,0x1080012,0x680012,0x680012,0x680012,0x680012,0x680012,0x680012,0x680012,0x680012,0x680012,0x680012,0x40640001,0x40640001,0x40640001,0x40640001,0x40640001,
-0x40640001,0x38640001,0x38640001,0x38640001,0x36600001,0x2980012,0x2980012,0x2980012,0x2980012,0x2980012,0x2980012,0x3A580001,0x3A580001,0x3A580001,0x365C0000,0x1380012,0x1380012,0x1380012,0x36480000,0x32000014,0x7A640001,0x680012,0x680012,0x52640001,0x48640001,0x42640001,0x42640001,0x3E640001,0x76580000,0x585C0000,0x3C600000,0x3A580001,
-0xDC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table8[] = {
-0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0x15C0000,
-0x15C0000,0x15C0000,0x15C0000,0x38000001,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x7C0000,0x7C0000,0x7C0000,0xAC0000,0xF40000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,
-0x2BC0000,0x1800000,0x1800000,0x1800000,0x3E000001,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x1800000,0x1800000,0x1800000,0x3E000001,0x1800000,0x1800000,0x1800000,0x3E000001,0x3E000001,0x880000,0x800000,0x800000,0x940000,0xA00000,0x2AC0000,0x2AC0000,0x2D40000,0x940000,0xA00000,0x1100000,0x1800000,
-0x1100000,0x880000,0x880000,0x880000,0x880000,0xC80000,0xC80000,0xC80000,0x1980000,0x1980000,0x42000001,0xC80000,0xC80000,0xC80000,0x1980000,0x1980000,0x42000001,0x1980000,0x1980000,0x42000001,0x42000001,0xC80000,0xC80000,0xC80000,0x1980000,0x1980000,0x42000001,0x1980000,0x1980000,0x42000001,0x42000001,0x1980000,
-0x1980000,0x42000001,0x42000001,0x42000001,0x49C0000,0x900000,0x880000,0xB80000,0xE40000,0x1200000,0x14C0000,0x1F80000,0x2A80000,0xC80000,0x1200000,0x42000001,0x1200000,0x940000,0xDC0000,0x1BC0000,0x48000001,0xDC0000,0x1BC0000,0x48000001,0x1BC0000,0x48000001,0x48000001,0xDC0000,0x1BC0000,0x48000001,0x1BC0000,0x48000001,
-0x48000001,0x1BC0000,0x48000001,0x48000001,0x48000001,0xDC0000,0x1BC0000,0x48000001,0x1BC0000,0x48000001,0x48000001,0x1BC0000,0x48000001,0x48000001,0x48000001,0x1BC0000,0x48000001,0x48000001,0x48000001,0x48000001,0xB80000,0x69C0000,0x69C0000,0xF80000,0x1680000,0x1DF40000,0x48000001,0x48000001,0xC80000,0x1140000,0x3FD00000,0x48000001,
-0x1380000,0x840088,0x5C800034,0x4E800034,0x48800035,0x587C0026,0x4E7C0015,0x487C0019,0x4A7C0026,0x48780016,0x46780026,0x5A740033,0x50740009,0x4A78000F,0x4C740012,0x48740002,0x46740016,0x4A740033,0x4870000F,0x4670001A,0x44740033,0xC40088,0x54680033,0x48740034,0x4E680026,0x4A6C0013,0x46700024,0x4E600033,0x4868000A,0x46640013,0x44680033,0x18C0088,
-0x48540034,0x46500024,0x44440033,0x4000008C,0x82740002,0xC67C0026,0xD8800034,0x60740001,0x52740002,0x4C740002,0x4A740002,0x48740002,0x7C6C0001,0x5C700001,0x4A700009,0x46640013,0x1180088,0x880034,0x58840008,0x4C840009,0x48840009,0x54800012,0x4C800001,0x4A800001,0x4A800012,0x48800005,0x46800012,0xCC0033,0x4E780009,0x487C0009,0x4C740012,0x48740002,
-0x46780012,0x1A00033,0x48680009,0x46640012,0x44000033,0xCC0033,0x4E780009,0x487C0009,0x4C740012,0x48740002,0x46780012,0x1A00033,0x48680009,0x46640012,0x44000033,0x1A00033,0x48680009,0x46640012,0x44000033,0x44000033,0x7E780001,0xA8800012,0xBA840008,0x5A780001,0x52740002,0x4C740002,0x48780002,0x48700002,0x7C6C0001,0x58740001,0x4A700008,0x46640012,
-0x1240033,0x800034,0x800034,0x800034,0x800034,0x4E7C0014,0x4E7C0014,0x4E7C0014,0x467C0014,0x467C0014,0x42780015,0x50740008,0x50740008,0x50740008,0x48740001,0x48740001,0x44740005,0x4474000A,0x4474000A,0x42740001,0x4074000A,0xBC0033,0xBC0033,0xBC0033,0x4A6C0012,0x4A6C0012,0x42740013,0x48680009,0x48680009,0x426C0002,0x406C000A,0x17C0033,
-0x17C0033,0x42600013,0x4058000A,0x3E000033,0x82740001,0x967C0014,0x800034,0x5E740001,0x52740001,0x4C740001,0x4A740001,0x46740001,0x7A6C0000,0x5C700000,0x48740009,0x426C0002,0x10C0033,0x840008,0x840008,0x840008,0x840008,0x4A800000,0x4A800000,0x4A800000,0x44800001,0x44800001,0x42800001,0xC40008,0xC40008,0xC40008,0x447C0001,0x447C0001,
-0x427C0001,0x18C0008,0x18C0008,0x42740001,0x4000000A,0xC40008,0xC40008,0xC40008,0x447C0001,0x447C0001,0x427C0001,0x18C0008,0x18C0008,0x42740001,0x4000000A,0x18C0008,0x18C0008,0x42740001,0x4000000A,0x4000000A,0x74780000,0x78800000,0x840008,0x58780000,0x4E780000,0x4A780000,0x467C0001,0x46780000,0x70700000,0x56740000,0x1180008,0x42740001,
-0x1180008,0x8C0014,0x54880000,0x4C880000,0x48880001,0x2D00012,0x4C800001,0x48840001,0x1AC0012,0x48740001,0x46000012,0x2D00012,0x4C800001,0x48840001,0x1AC0012,0x48740001,0x46000012,0x1AC0012,0x48740001,0x46000012,0x46000012,0x2D00012,0x4C800001,0x48840001,0x1AC0012,0x48740001,0x46000012,0x1AC0012,0x48740001,0x46000012,0x46000012,0x1AC0012,
-0x48740001,0x46000012,0x46000012,0x46000012,0x8E700000,0x980012,0x9C880000,0x60740000,0x52740001,0x4E700000,0x48780001,0x486C0001,0x84680000,0x606C0000,0x4A780000,0x46000012,0x12C0012,0x780014,0x780014,0x780014,0x780014,0x780014,0x780014,0x780014,0x780014,0x780014,0x780014,0x4A740000,0x4A740000,0x4A740000,0x4A740000,0x4A740000,
-0x4A740000,0x42740000,0x42740000,0x42740000,0x3E740001,0xB40012,0xB40012,0xB40012,0xB40012,0xB40012,0xB40012,0x426C0001,0x426C0001,0x426C0001,0x3E700001,0x1700012,0x1700012,0x1700012,0x3E600001,0x3C000012,0x92740000,0x780014,0x780014,0x62740000,0x56740000,0x4E740000,0x4E740000,0x48740000,0x7A6C0000,0x5C700000,0x44740001,0x426C0001,
-0x1000012,};
-static const uint32_t g_etc1_to_bc7_m6_table9[] = {
-0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0x18C0000,
-0x18C0000,0x18C0000,0x18C0000,0x40000001,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x8C0000,0x8C0000,0x8C0000,0xC40000,0x1180000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,
-0xD40000,0x1B00000,0x1B00000,0x1B00000,0x46000001,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0x1B00000,0x1B00000,0x1B00000,0x46000001,0x1B00000,0x1B00000,0x1B00000,0x46000001,0x46000001,0x4980000,0x900000,0x900000,0xA80000,0xB40000,0xC40000,0xC40000,0xF00000,0xA80000,0xB40000,0x1300000,0x1B00000,
-0x1300000,0x980000,0x980000,0x980000,0x980000,0xE00000,0xE00000,0xE00000,0x1CC0000,0x1CC0000,0x4A000001,0xE00000,0xE00000,0xE00000,0x1CC0000,0x1CC0000,0x4A000001,0x1CC0000,0x1CC0000,0x4A000001,0x4A000001,0xE00000,0xE00000,0xE00000,0x1CC0000,0x1CC0000,0x4A000001,0x1CC0000,0x1CC0000,0x4A000001,0x4A000001,0x1CC0000,
-0x1CC0000,0x4A000001,0x4A000001,0x4A000001,0xB00000,0x8A00000,0x980000,0x2CC0000,0x1000000,0x1400000,0x1740000,0xBFC0000,0x2BC0000,0xE00000,0x1400000,0x4A000001,0x1400000,0xA40000,0xF40000,0x1F00000,0x50000001,0xF40000,0x1F00000,0x50000001,0x1F00000,0x50000001,0x50000001,0xF40000,0x1F00000,0x50000001,0x1F00000,0x50000001,
-0x50000001,0x1F00000,0x50000001,0x50000001,0x50000001,0xF40000,0x1F00000,0x50000001,0x1F00000,0x50000001,0x50000001,0x1F00000,0x50000001,0x50000001,0x50000001,0x1F00000,0x50000001,0x50000001,0x50000001,0x50000001,0x2CC0000,0xEAC0000,0xEAC0000,0x1140000,0x1900000,0x27F40000,0x50000001,0x50000001,0x2DC0000,0x1340000,0x47E00000,0x50000001,
-0x15C0000,0x940088,0x64900034,0x56900034,0x50900035,0x608C0026,0x568C0015,0x508C0019,0x528C0026,0x50880016,0x4E880026,0x62840033,0x58840009,0x5288000F,0x54840012,0x50840002,0x4E840016,0x52840033,0x5080000F,0x4E80001A,0x4C840033,0xDC0088,0x5C780033,0x50840034,0x56780026,0x527C0013,0x4E800024,0x56700033,0x5078000A,0x4E740013,0x4C780033,0x1BC0088,
-0x50640034,0x4E600024,0x4C540033,0x4800008C,0x8A840002,0xCE8C0026,0xE0900034,0x68840001,0x5A840002,0x54840002,0x52840002,0x50840002,0x847C0001,0x64800001,0x52800009,0x4E740013,0x1380088,0x980034,0x60940008,0x54940009,0x50940009,0x5C900012,0x54900001,0x52900001,0x52900012,0x50900005,0x4E900012,0xE40033,0x56880009,0x508C0009,0x54840012,0x50840002,
-0x4E880012,0x1D00033,0x50780009,0x4E740012,0x4C000033,0xE40033,0x56880009,0x508C0009,0x54840012,0x50840002,0x4E880012,0x1D00033,0x50780009,0x4E740012,0x4C000033,0x1D00033,0x50780009,0x4E740012,0x4C000033,0x4C000033,0x86880001,0xB0900012,0xC2940008,0x62880001,0x5A840002,0x54840002,0x50880002,0x50800002,0x847C0001,0x60840001,0x52800008,0x4E740012,
-0x1480033,0x900034,0x900034,0x900034,0x900034,0x568C0014,0x568C0014,0x568C0014,0x4E8C0014,0x4E8C0014,0x4A880015,0x58840008,0x58840008,0x58840008,0x50840001,0x50840001,0x4C840005,0x4C84000A,0x4C84000A,0x4A840001,0x4884000A,0x2D00033,0x2D00033,0x2D00033,0x527C0012,0x527C0012,0x4A840013,0x50780009,0x50780009,0x4A7C0002,0x487C000A,0x1AC0033,
-0x1AC0033,0x4A700013,0x4868000A,0x46000033,0x8A840001,0x9E8C0014,0x900034,0x66840001,0x5A840001,0x54840001,0x52840001,0x4E840001,0x827C0000,0x64800000,0x50840009,0x4A7C0002,0x12C0033,0x940008,0x940008,0x940008,0x940008,0x52900000,0x52900000,0x52900000,0x4C900001,0x4C900001,0x4A900001,0xDC0008,0xDC0008,0xDC0008,0x4C8C0001,0x4C8C0001,
-0x4A8C0001,0x1BC0008,0x1BC0008,0x4A840001,0x4800000A,0xDC0008,0xDC0008,0xDC0008,0x4C8C0001,0x4C8C0001,0x4A8C0001,0x1BC0008,0x1BC0008,0x4A840001,0x4800000A,0x1BC0008,0x1BC0008,0x4A840001,0x4800000A,0x4800000A,0x7C880000,0x80900000,0x940008,0x60880000,0x56880000,0x52880000,0x4E8C0001,0x4E880000,0x78800000,0x5E840000,0x1380008,0x4A840001,
-0x1380008,0x9C0014,0x5C980000,0x54980000,0x50980001,0x2E80012,0x54900001,0x50940001,0x1DC0012,0x50840001,0x4E000012,0x2E80012,0x54900001,0x50940001,0x1DC0012,0x50840001,0x4E000012,0x1DC0012,0x50840001,0x4E000012,0x4E000012,0x2E80012,0x54900001,0x50940001,0x1DC0012,0x50840001,0x4E000012,0x1DC0012,0x50840001,0x4E000012,0x4E000012,0x1DC0012,
-0x50840001,0x4E000012,0x4E000012,0x4E000012,0x96800000,0xA80012,0xA4980000,0x68840000,0x5A840001,0x56800000,0x50880001,0x507C0001,0x8C780000,0x687C0000,0x52880000,0x4E000012,0x1500012,0x880014,0x880014,0x880014,0x880014,0x880014,0x880014,0x880014,0x880014,0x880014,0x880014,0x52840000,0x52840000,0x52840000,0x52840000,0x52840000,
-0x52840000,0x4A840000,0x4A840000,0x4A840000,0x46840001,0xCC0012,0xCC0012,0xCC0012,0xCC0012,0xCC0012,0xCC0012,0x4A7C0001,0x4A7C0001,0x4A7C0001,0x46800001,0x1A00012,0x1A00012,0x1A00012,0x46700001,0x44000012,0x9A840000,0x880014,0x880014,0x6A840000,0x5E840000,0x56840000,0x56840000,0x50840000,0x827C0000,0x64800000,0x4C840001,0x4A7C0001,
-0x1240012,};
-static const uint32_t g_etc1_to_bc7_m6_table10[] = {
-0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0x1BC0000,
-0x1BC0000,0x1BC0000,0x1BC0000,0x48000001,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x69C0000,0x69C0000,0x69C0000,0xDC0000,0x1380000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,
-0xEC0000,0x1E40000,0x1E40000,0x1E40000,0x4E000001,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0x1E40000,0x1E40000,0x1E40000,0x4E000001,0x1E40000,0x1E40000,0x1E40000,0x4E000001,0x4E000001,0xCA80000,0xA00000,0xA00000,0x4B80000,0xC80000,0xD80000,0xD80000,0x10C0000,0x4B80000,0xC80000,0x1540000,0x1E40000,
-0x1540000,0xA80000,0xA80000,0xA80000,0xA80000,0xF80000,0xF80000,0xF80000,0x1FC0000,0x1FC0000,0x52000001,0xF80000,0xF80000,0xF80000,0x1FC0000,0x1FC0000,0x52000001,0x1FC0000,0x1FC0000,0x52000001,0x52000001,0xF80000,0xF80000,0xF80000,0x1FC0000,0x1FC0000,0x52000001,0x1FC0000,0x1FC0000,0x52000001,0x52000001,0x1FC0000,
-0x1FC0000,0x52000001,0x52000001,0x52000001,0xC40000,0xB40000,0xA80000,0xE40000,0x1180000,0x1640000,0x19C0000,0x17F80000,0x4D00000,0xF80000,0x1640000,0x52000001,0x1640000,0xB40000,0x10C0000,0xBF80000,0x58000001,0x10C0000,0xBF80000,0x58000001,0xBF80000,0x58000001,0x58000001,0x10C0000,0xBF80000,0x58000001,0xBF80000,0x58000001,
-0x58000001,0xBF80000,0x58000001,0x58000001,0x58000001,0x10C0000,0xBF80000,0x58000001,0xBF80000,0x58000001,0x58000001,0xBF80000,0x58000001,0x58000001,0x58000001,0xBF80000,0x58000001,0x58000001,0x58000001,0x58000001,0x2E00000,0xC00000,0xC00000,0x32C0000,0x1B80000,0x31F40000,0x58000001,0x58000001,0xF40000,0x1500000,0x4FF00000,0x58000001,
-0x17C0000,0xA40088,0x6CA00034,0x5EA00034,0x58A00035,0x689C0026,0x5E9C0015,0x589C0019,0x5A9C0026,0x58980016,0x56980026,0x6A940033,0x60940009,0x5A98000F,0x5C940012,0x58940002,0x56940016,0x5A940033,0x5890000F,0x5690001A,0x54940033,0xF40088,0x64880033,0x58940034,0x5E880026,0x5A8C0013,0x56900024,0x5E800033,0x5888000A,0x56840013,0x54880033,0x1F00088,
-0x58740034,0x56700024,0x54640033,0x5000008C,0x92940002,0xD69C0026,0xE8A00034,0x70940001,0x62940002,0x5C940002,0x5A940002,0x58940002,0x8C8C0001,0x6C900001,0x5A900009,0x56840013,0x15C0088,0xA80034,0x68A40008,0x5CA40009,0x58A40009,0x64A00012,0x5CA00001,0x5AA00001,0x5AA00012,0x58A00005,0x56A00012,0xFC0033,0x5E980009,0x589C0009,0x5C940012,0x58940002,
-0x56980012,0x3F80033,0x58880009,0x56840012,0x54000033,0xFC0033,0x5E980009,0x589C0009,0x5C940012,0x58940002,0x56980012,0x3F80033,0x58880009,0x56840012,0x54000033,0x3F80033,0x58880009,0x56840012,0x54000033,0x54000033,0x8E980001,0xB8A00012,0xCAA40008,0x6A980001,0x62940002,0x5C940002,0x58980002,0x58900002,0x8C8C0001,0x68940001,0x5A900008,0x56840012,
-0x1680033,0xA00034,0xA00034,0xA00034,0xA00034,0x5E9C0014,0x5E9C0014,0x5E9C0014,0x569C0014,0x569C0014,0x52980015,0x60940008,0x60940008,0x60940008,0x58940001,0x58940001,0x54940005,0x5494000A,0x5494000A,0x52940001,0x5094000A,0x2E80033,0x2E80033,0x2E80033,0x5A8C0012,0x5A8C0012,0x52940013,0x58880009,0x58880009,0x528C0002,0x508C000A,0x1DC0033,
-0x1DC0033,0x52800013,0x5078000A,0x4E000033,0x92940001,0xA69C0014,0xA00034,0x6E940001,0x62940001,0x5C940001,0x5A940001,0x56940001,0x8A8C0000,0x6C900000,0x58940009,0x528C0002,0x1500033,0xA40008,0xA40008,0xA40008,0xA40008,0x5AA00000,0x5AA00000,0x5AA00000,0x54A00001,0x54A00001,0x52A00001,0xF40008,0xF40008,0xF40008,0x549C0001,0x549C0001,
-0x529C0001,0x1F00008,0x1F00008,0x52940001,0x5000000A,0xF40008,0xF40008,0xF40008,0x549C0001,0x549C0001,0x529C0001,0x1F00008,0x1F00008,0x52940001,0x5000000A,0x1F00008,0x1F00008,0x52940001,0x5000000A,0x5000000A,0x84980000,0x88A00000,0xA40008,0x68980000,0x5E980000,0x5A980000,0x569C0001,0x56980000,0x80900000,0x66940000,0x15C0008,0x52940001,
-0x15C0008,0xAC0014,0x64A80000,0x5CA80000,0x58A80001,0x3000012,0x5CA00001,0x58A40001,0x5FC0012,0x58940001,0x56000012,0x3000012,0x5CA00001,0x58A40001,0x5FC0012,0x58940001,0x56000012,0x5FC0012,0x58940001,0x56000012,0x56000012,0x3000012,0x5CA00001,0x58A40001,0x5FC0012,0x58940001,0x56000012,0x5FC0012,0x58940001,0x56000012,0x56000012,0x5FC0012,
-0x58940001,0x56000012,0x56000012,0x56000012,0x9E900000,0x4B80012,0xACA80000,0x70940000,0x62940001,0x5E900000,0x58980001,0x588C0001,0x94880000,0x708C0000,0x5A980000,0x56000012,0x1700012,0x980014,0x980014,0x980014,0x980014,0x980014,0x980014,0x980014,0x980014,0x980014,0x980014,0x5A940000,0x5A940000,0x5A940000,0x5A940000,0x5A940000,
-0x5A940000,0x52940000,0x52940000,0x52940000,0x4E940001,0xE40012,0xE40012,0xE40012,0xE40012,0xE40012,0xE40012,0x528C0001,0x528C0001,0x528C0001,0x4E900001,0x1D00012,0x1D00012,0x1D00012,0x4E800001,0x4C000012,0xA2940000,0x980014,0x980014,0x72940000,0x66940000,0x5E940000,0x5E940000,0x58940000,0x8A8C0000,0x6C900000,0x54940001,0x528C0001,
-0x1480012,};
-static const uint32_t g_etc1_to_bc7_m6_table11[] = {
-0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0x1F00000,
-0x1F00000,0x1F00000,0x1F00000,0x50000001,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xEAC0000,0xEAC0000,0xEAC0000,0xF40000,0x15C0000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,
-0x1040000,0x7FC0000,0x7FC0000,0x7FC0000,0x56000001,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x7FC0000,0x7FC0000,0x7FC0000,0x56000001,0x7FC0000,0x7FC0000,0x7FC0000,0x56000001,0x56000001,0xBC0000,0xB00000,0xB00000,0xCC0000,0xDC0000,0xF00000,0xF00000,0x1280000,0xCC0000,0xDC0000,0x1740000,0x7FC0000,
-0x1740000,0xB80000,0xB80000,0xB80000,0xB80000,0x1100000,0x1100000,0x1100000,0xDFC0000,0xDFC0000,0x5A000001,0x1100000,0x1100000,0x1100000,0xDFC0000,0xDFC0000,0x5A000001,0xDFC0000,0xDFC0000,0x5A000001,0x5A000001,0x1100000,0x1100000,0x1100000,0xDFC0000,0xDFC0000,0x5A000001,0xDFC0000,0xDFC0000,0x5A000001,0x5A000001,0xDFC0000,
-0xDFC0000,0x5A000001,0x5A000001,0x5A000001,0x2D40000,0xC40000,0xB80000,0x2F80000,0x1340000,0x1880000,0x1C00000,0x21FC0000,0x4E40000,0x1100000,0x1880000,0x5A000001,0x1880000,0xC40000,0x1240000,0x17F80000,0x60000001,0x1240000,0x17F80000,0x60000001,0x17F80000,0x60000001,0x60000001,0x1240000,0x17F80000,0x60000001,0x17F80000,0x60000001,
-0x60000001,0x17F80000,0x60000001,0x60000001,0x60000001,0x1240000,0x17F80000,0x60000001,0x17F80000,0x60000001,0x60000001,0x17F80000,0x60000001,0x60000001,0x60000001,0x17F80000,0x60000001,0x60000001,0x60000001,0x60000001,0x2F40000,0xD00000,0xD00000,0x1480000,0x1E00000,0x3BF40000,0x60000001,0x60000001,0x3080000,0x1700000,0x59C40000,0x60000001,
-0x1A00000,0xB40088,0x74B00034,0x66B00034,0x60B00035,0x70AC0026,0x66AC0015,0x60AC0019,0x62AC0026,0x60A80016,0x5EA80026,0x72A40033,0x68A40009,0x62A8000F,0x64A40012,0x60A40002,0x5EA40016,0x62A40033,0x60A0000F,0x5EA0001A,0x5CA40033,0x10C0088,0x6C980033,0x60A40034,0x66980026,0x629C0013,0x5EA00024,0x66900033,0x6098000A,0x5E940013,0x5C980033,0xBF80088,
-0x60840034,0x5E800024,0x5C740033,0x5800008C,0x9AA40002,0xDEAC0026,0xF0B00034,0x78A40001,0x6AA40002,0x64A40002,0x62A40002,0x60A40002,0x949C0001,0x74A00001,0x62A00009,0x5E940013,0x17C0088,0xB80034,0x70B40008,0x64B40009,0x60B40009,0x6CB00012,0x64B00001,0x62B00001,0x62B00012,0x60B00005,0x5EB00012,0x1140033,0x66A80009,0x60AC0009,0x64A40012,0x60A40002,
-0x5EA80012,0xFF80033,0x60980009,0x5E940012,0x5C000033,0x1140033,0x66A80009,0x60AC0009,0x64A40012,0x60A40002,0x5EA80012,0xFF80033,0x60980009,0x5E940012,0x5C000033,0xFF80033,0x60980009,0x5E940012,0x5C000033,0x5C000033,0x96A80001,0xC0B00012,0xD2B40008,0x72A80001,0x6AA40002,0x64A40002,0x60A80002,0x60A00002,0x949C0001,0x70A40001,0x62A00008,0x5E940012,
-0x18C0033,0xB00034,0xB00034,0xB00034,0xB00034,0x66AC0014,0x66AC0014,0x66AC0014,0x5EAC0014,0x5EAC0014,0x5AA80015,0x68A40008,0x68A40008,0x68A40008,0x60A40001,0x60A40001,0x5CA40005,0x5CA4000A,0x5CA4000A,0x5AA40001,0x58A4000A,0x3000033,0x3000033,0x3000033,0x629C0012,0x629C0012,0x5AA40013,0x60980009,0x60980009,0x5A9C0002,0x589C000A,0x5FC0033,
-0x5FC0033,0x5A900013,0x5888000A,0x56000033,0x9AA40001,0xAEAC0014,0xB00034,0x76A40001,0x6AA40001,0x64A40001,0x62A40001,0x5EA40001,0x929C0000,0x74A00000,0x60A40009,0x5A9C0002,0x1700033,0xB40008,0xB40008,0xB40008,0xB40008,0x62B00000,0x62B00000,0x62B00000,0x5CB00001,0x5CB00001,0x5AB00001,0x10C0008,0x10C0008,0x10C0008,0x5CAC0001,0x5CAC0001,
-0x5AAC0001,0xBF80008,0xBF80008,0x5AA40001,0x5800000A,0x10C0008,0x10C0008,0x10C0008,0x5CAC0001,0x5CAC0001,0x5AAC0001,0xBF80008,0xBF80008,0x5AA40001,0x5800000A,0xBF80008,0xBF80008,0x5AA40001,0x5800000A,0x5800000A,0x8CA80000,0x90B00000,0xB40008,0x70A80000,0x66A80000,0x62A80000,0x5EAC0001,0x5EA80000,0x88A00000,0x6EA40000,0x17C0008,0x5AA40001,
-0x17C0008,0xBC0014,0x6CB80000,0x64B80000,0x60B80001,0x3180012,0x64B00001,0x60B40001,0x11FC0012,0x60A40001,0x5E000012,0x3180012,0x64B00001,0x60B40001,0x11FC0012,0x60A40001,0x5E000012,0x11FC0012,0x60A40001,0x5E000012,0x5E000012,0x3180012,0x64B00001,0x60B40001,0x11FC0012,0x60A40001,0x5E000012,0x11FC0012,0x60A40001,0x5E000012,0x5E000012,0x11FC0012,
-0x60A40001,0x5E000012,0x5E000012,0x5E000012,0xA6A00000,0xCC80012,0xB4B80000,0x78A40000,0x6AA40001,0x66A00000,0x60A80001,0x609C0001,0x9C980000,0x789C0000,0x62A80000,0x5E000012,0x1940012,0xA80014,0xA80014,0xA80014,0xA80014,0xA80014,0xA80014,0xA80014,0xA80014,0xA80014,0xA80014,0x62A40000,0x62A40000,0x62A40000,0x62A40000,0x62A40000,
-0x62A40000,0x5AA40000,0x5AA40000,0x5AA40000,0x56A40001,0xFC0012,0xFC0012,0xFC0012,0xFC0012,0xFC0012,0xFC0012,0x5A9C0001,0x5A9C0001,0x5A9C0001,0x56A00001,0x3F80012,0x3F80012,0x3F80012,0x56900001,0x54000012,0xAAA40000,0xA80014,0xA80014,0x7AA40000,0x6EA40000,0x66A40000,0x66A40000,0x60A40000,0x929C0000,0x74A00000,0x5CA40001,0x5A9C0001,
-0x1680012,};
-static const uint32_t g_etc1_to_bc7_m6_table12[] = {
-0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0xBFC0000,
-0xBFC0000,0xBFC0000,0xBFC0000,0x5A000000,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0x8C00000,0x8C00000,0x8C00000,0x30C0000,0x1800000,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,
-0x1200000,0x15F80000,0x15F80000,0x15F80000,0x60000000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x15F80000,0x15F80000,0x15F80000,0x60000000,0x15F80000,0x15F80000,0x15F80000,0x60000000,0x60000000,0xECC0000,0xC00001,0xC00001,0x2E00000,0xF40000,0x1080000,0x1080000,0x1440000,0x2E00000,0xF40000,0x19C0000,0x15F80000,
-0x19C0000,0xC80001,0xC80001,0xC80001,0xC80001,0x12C0000,0x12C0000,0x12C0000,0x1BF80000,0x1BF80000,0x64000000,0x12C0000,0x12C0000,0x12C0000,0x1BF80000,0x1BF80000,0x64000000,0x1BF80000,0x1BF80000,0x64000000,0x64000000,0x12C0000,0x12C0000,0x12C0000,0x1BF80000,0x1BF80000,0x64000000,0x1BF80000,0x1BF80000,0x64000000,0x64000000,0x1BF80000,
-0x1BF80000,0x64000000,0x64000000,0x64000000,0x6E80000,0xD80000,0xC80001,0x3100000,0x1540000,0x1AC0000,0x1EC0000,0x2DFC0000,0xFC0000,0x12C0000,0x1AC0000,0x64000000,0x1AC0000,0xD40001,0x33C0000,0x23FC0000,0x6A000000,0x33C0000,0x23FC0000,0x6A000000,0x23FC0000,0x6A000000,0x6A000000,0x33C0000,0x23FC0000,0x6A000000,0x23FC0000,0x6A000000,
-0x6A000000,0x23FC0000,0x6A000000,0x6A000000,0x6A000000,0x33C0000,0x23FC0000,0x6A000000,0x23FC0000,0x6A000000,0x6A000000,0x23FC0000,0x6A000000,0x6A000000,0x6A000000,0x23FC0000,0x6A000000,0x6A000000,0x6A000000,0x6A000000,0x10C0000,0xE40000,0xE40000,0x1680000,0x7F80000,0x45FC0000,0x6A000000,0x6A000000,0x1240000,0x1900000,0x61F40000,0x6A000000,
-0x1C80000,0xC4008C,0x80C00033,0x70C00033,0x6AC00033,0x7ABC0024,0x70BC0013,0x6CBC001A,0x6CBC0024,0x68BC0016,0x66BC0026,0x78B80034,0x70B8000A,0x6CB8000F,0x6EB40013,0x6AB40002,0x66B80016,0x6AB80034,0x68B4000F,0x66B40019,0x64B40035,0x3240088,0x74AC0033,0x6AB40033,0x6EAC0026,0x6AB00012,0x66B40026,0x70A00033,0x6AA40009,0x66A80015,0x64AC0034,0x17FC0088,
-0x6A900033,0x66980026,0x648C0034,0x62000088,0xA4B80002,0xF6BC0024,0xF8C00034,0x7EB80002,0x72B80002,0x6CB80002,0x6AB80002,0x6AB40002,0xA0AC0001,0x80B00001,0x6AB40009,0x66A80015,0x1A40088,0xCC0033,0x78C8000A,0x6EC4000A,0x6AC4000A,0x72C40013,0x6EC00002,0x6AC40001,0x6AC40013,0x6AC00005,0x66C00015,0x1300033,0x70B80009,0x6ABC000A,0x6EB40012,0x6AB40001,
-0x66BC0014,0x1DF40033,0x6AA40008,0x66A80014,0x64000034,0x1300033,0x70B80009,0x6ABC000A,0x6EB40012,0x6AB40001,0x66BC0014,0x1DF40033,0x6AA40008,0x66A80014,0x64000034,0x1DF40033,0x6AA40008,0x66A80014,0x64000034,0x64000034,0xA4B80001,0xBAC40013,0xCCC8000A,0x7EB80001,0x72B80001,0x6CB80001,0x6AB80001,0x6AB40001,0xA0AC0001,0x7CB40001,0x6AB40009,0x66A80014,
-0x1B00033,0xC00033,0xC00033,0xC00033,0xC00033,0x72BC0012,0x72BC0012,0x72BC0012,0x68BC0012,0x68BC0012,0x64BC0012,0x70B80009,0x70B80009,0x70B80009,0x68B80002,0x68B80002,0x64B80005,0x66B40009,0x66B40009,0x64B40001,0x62B40009,0x11C0033,0x11C0033,0x11C0033,0x6AB00012,0x6AB00012,0x64B40012,0x68AC0009,0x68AC0009,0x64AC0001,0x62AC0009,0x13FC0033,
-0x13FC0033,0x64A00012,0x62940008,0x60000034,0x98B80002,0xC6BC0012,0xC00033,0x7CB80001,0x72B80001,0x6CB80001,0x6AB80002,0x68B40002,0xA0AC0000,0x7AB40001,0x6AB40008,0x64AC0001,0x1980033,0xC4000A,0xC4000A,0xC4000A,0xC4000A,0x6AC40001,0x6AC40001,0x6AC40001,0x66C00001,0x66C00001,0x64C00001,0x3240008,0x3240008,0x3240008,0x66BC0001,0x66BC0001,
-0x64BC0001,0x17FC0008,0x17FC0008,0x64B00000,0x62000008,0x3240008,0x3240008,0x3240008,0x66BC0001,0x66BC0001,0x64BC0001,0x17FC0008,0x17FC0008,0x64B00000,0x62000008,0x17FC0008,0x17FC0008,0x64B00000,0x62000008,0x62000008,0x8CBC0000,0x8AC40001,0xC4000A,0x7CB80000,0x6EBC0000,0x6ABC0000,0x68BC0000,0x66BC0001,0x8EB40000,0x76B80000,0x1A40008,0x64B00000,
-0x1A40008,0xD00012,0x74CC0001,0x6CCC0001,0x6AC80001,0x1340012,0x6EC00001,0x6AC40000,0x1FF80012,0x6AB00000,0x66000014,0x1340012,0x6EC00001,0x6AC40000,0x1FF80012,0x6AB00000,0x66000014,0x1FF80012,0x6AB00000,0x66000014,0x66000014,0x1340012,0x6EC00001,0x6AC40000,0x1FF80012,0x6AB00000,0x66000014,0x1FF80012,0x6AB00000,0x66000014,0x66000014,0x1FF80012,
-0x6AB00000,0x66000014,0x66000014,0x66000014,0xB4B00000,0x6DC0012,0xAECC0001,0x82B40000,0x72B80001,0x6EB40000,0x6AB80000,0x6AA80000,0xA8A80000,0x80B00000,0x6ABC0001,0x66000014,0x1B80012,0xBC0012,0xBC0012,0xBC0012,0xBC0012,0xBC0012,0xBC0012,0xBC0012,0xBC0012,0xBC0012,0xBC0012,0x6AB80001,0x6AB80001,0x6AB80001,0x6AB80001,0x6AB80001,
-0x6AB80001,0x62B80001,0x62B80001,0x62B80001,0x60B40001,0x1180012,0x1180012,0x1180012,0x1180012,0x1180012,0x1180012,0x64AC0001,0x64AC0001,0x64AC0001,0x60B00000,0x11F80012,0x11F80012,0x11F80012,0x609C0000,0x5C000014,0xA4B80001,0xBC0012,0xBC0012,0x7CB80001,0x72B80001,0x6CB80001,0x6CB80001,0x68B80001,0xA0AC0000,0x82B00000,0x66B40000,0x64AC0001,
-0x1900012,};
-static const uint32_t g_etc1_to_bc7_m6_table13[] = {
-0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,0x17FC0000,
-0x17FC0000,0x17FC0000,0x17FC0000,0x62000000,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xD40000,0xD40000,0xD40000,0x3240000,0x1A40000,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,
-0x1380000,0x21F80000,0x21F80000,0x21F80000,0x68000000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x21F80000,0x21F80000,0x21F80000,0x68000000,0x21F80000,0x21F80000,0x21F80000,0x68000000,0x68000000,0xE00000,0xD00001,0xD00001,0xF40000,0x1080000,0x11C0000,0x11C0000,0x1600000,0xF40000,0x1080000,0x1BC0000,0x21F80000,
-0x1BC0000,0xD80001,0xD80001,0xD80001,0xD80001,0x1440000,0x1440000,0x1440000,0x27F80000,0x27F80000,0x6C000000,0x1440000,0x1440000,0x1440000,0x27F80000,0x27F80000,0x6C000000,0x27F80000,0x27F80000,0x6C000000,0x6C000000,0x1440000,0x1440000,0x1440000,0x27F80000,0x27F80000,0x6C000000,0x27F80000,0x27F80000,0x6C000000,0x6C000000,0x27F80000,
-0x27F80000,0x6C000000,0x6C000000,0x6C000000,0x2FC0000,0xE80000,0xD80001,0x1280000,0x36C0000,0x1D00000,0x9FC0000,0x39F80000,0x1100000,0x1440000,0x1D00000,0x6C000000,0x1D00000,0xE40001,0x1540000,0x2FFC0000,0x72000000,0x1540000,0x2FFC0000,0x72000000,0x2FFC0000,0x72000000,0x72000000,0x1540000,0x2FFC0000,0x72000000,0x2FFC0000,0x72000000,
-0x72000000,0x2FFC0000,0x72000000,0x72000000,0x72000000,0x1540000,0x2FFC0000,0x72000000,0x2FFC0000,0x72000000,0x72000000,0x2FFC0000,0x72000000,0x72000000,0x72000000,0x2FFC0000,0x72000000,0x72000000,0x72000000,0x72000000,0x1200000,0x2F40000,0x2F40000,0x3800000,0x15F80000,0x4FFC0000,0x72000000,0x72000000,0x1380000,0x1B00000,0x6BC80000,0x72000000,
-0x1E80000,0xD4008C,0x88D00033,0x78D00033,0x72D00033,0x82CC0024,0x78CC0013,0x74CC001A,0x74CC0024,0x70CC0016,0x6ECC0026,0x80C80034,0x78C8000A,0x74C8000F,0x76C40013,0x72C40002,0x6EC80016,0x72C80034,0x70C4000F,0x6EC40019,0x6CC40035,0x33C0088,0x7CBC0033,0x72C40033,0x76BC0026,0x72C00012,0x6EC40026,0x78B00033,0x72B40009,0x6EB80015,0x6CBC0034,0x23FC0088,
-0x72A00033,0x6EA80026,0x6C9C0034,0x6A000088,0xACC80002,0xFECC0024,0xF0D00037,0x86C80002,0x7AC80002,0x74C80002,0x72C80002,0x72C40002,0xA8BC0001,0x88C00001,0x72C40009,0x6EB80015,0x1C80088,0xDC0033,0x80D8000A,0x76D4000A,0x72D4000A,0x7AD40013,0x76D00002,0x72D40001,0x72D40013,0x72D00005,0x6ED00015,0x3440033,0x78C80009,0x72CC000A,0x76C40012,0x72C40001,
-0x6ECC0014,0x27FC0033,0x72B40008,0x6EB80014,0x6C000034,0x3440033,0x78C80009,0x72CC000A,0x76C40012,0x72C40001,0x6ECC0014,0x27FC0033,0x72B40008,0x6EB80014,0x6C000034,0x27FC0033,0x72B40008,0x6EB80014,0x6C000034,0x6C000034,0xACC80001,0xC2D40013,0xD4D8000A,0x86C80001,0x7AC80001,0x74C80001,0x72C80001,0x72C40001,0xA8BC0001,0x84C40001,0x72C40009,0x6EB80014,
-0x1D40033,0xD00033,0xD00033,0xD00033,0xD00033,0x7ACC0012,0x7ACC0012,0x7ACC0012,0x70CC0012,0x70CC0012,0x6CCC0012,0x78C80009,0x78C80009,0x78C80009,0x70C80002,0x70C80002,0x6CC80005,0x6EC40009,0x6EC40009,0x6CC40001,0x6AC40009,0x1340033,0x1340033,0x1340033,0x72C00012,0x72C00012,0x6CC40012,0x70BC0009,0x70BC0009,0x6CBC0001,0x6ABC0009,0x1FF80033,
-0x1FF80033,0x6CB00012,0x6AA40008,0x68000034,0xA0C80002,0xCECC0012,0xD00033,0x84C80001,0x7AC80001,0x74C80001,0x72C80002,0x70C40002,0xA8BC0000,0x82C40001,0x72C40008,0x6CBC0001,0x1B80033,0xD4000A,0xD4000A,0xD4000A,0xD4000A,0x72D40001,0x72D40001,0x72D40001,0x6ED00001,0x6ED00001,0x6CD00001,0x33C0008,0x33C0008,0x33C0008,0x6ECC0001,0x6ECC0001,
-0x6CCC0001,0x23FC0008,0x23FC0008,0x6CC00000,0x6A000008,0x33C0008,0x33C0008,0x33C0008,0x6ECC0001,0x6ECC0001,0x6CCC0001,0x23FC0008,0x23FC0008,0x6CC00000,0x6A000008,0x23FC0008,0x23FC0008,0x6CC00000,0x6A000008,0x6A000008,0x94CC0000,0x92D40001,0xD4000A,0x84C80000,0x76CC0000,0x72CC0000,0x70CC0000,0x6ECC0001,0x96C40000,0x7EC80000,0x1C80008,0x6CC00000,
-0x1C80008,0xE00012,0x7CDC0001,0x74DC0001,0x72D80001,0x14C0012,0x76D00001,0x72D40000,0x2BF80012,0x72C00000,0x6E000014,0x14C0012,0x76D00001,0x72D40000,0x2BF80012,0x72C00000,0x6E000014,0x2BF80012,0x72C00000,0x6E000014,0x6E000014,0x14C0012,0x76D00001,0x72D40000,0x2BF80012,0x72C00000,0x6E000014,0x2BF80012,0x72C00000,0x6E000014,0x6E000014,0x2BF80012,
-0x72C00000,0x6E000014,0x6E000014,0x6E000014,0xBCC00000,0xEEC0012,0xB6DC0001,0x8AC40000,0x7AC80001,0x76C40000,0x72C80000,0x72B80000,0xB0B80000,0x88C00000,0x72CC0001,0x6E000014,0x1DC0012,0xCC0012,0xCC0012,0xCC0012,0xCC0012,0xCC0012,0xCC0012,0xCC0012,0xCC0012,0xCC0012,0xCC0012,0x72C80001,0x72C80001,0x72C80001,0x72C80001,0x72C80001,
-0x72C80001,0x6AC80001,0x6AC80001,0x6AC80001,0x68C40001,0x1300012,0x1300012,0x1300012,0x1300012,0x1300012,0x1300012,0x6CBC0001,0x6CBC0001,0x6CBC0001,0x68C00000,0x1DF40012,0x1DF40012,0x1DF40012,0x68AC0000,0x64000014,0xACC80001,0xCC0012,0xCC0012,0x84C80001,0x7AC80001,0x74C80001,0x74C80001,0x70C80001,0xA8BC0000,0x8AC00000,0x6EC40000,0x6CBC0001,
-0x1B00012,};
-static const uint32_t g_etc1_to_bc7_m6_table14[] = {
-0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x23FC0000,
-0x23FC0000,0x23FC0000,0x23FC0000,0x6A000000,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xE40000,0xE40000,0xE40000,0x33C0000,0x1C80000,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,
-0x1500000,0x2DF80000,0x2DF80000,0x2DF80000,0x70000000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x2DF80000,0x2DF80000,0x2DF80000,0x70000000,0x2DF80000,0x2DF80000,0x2DF80000,0x70000000,0x70000000,0xF00000,0xE00001,0xE00001,0x7040000,0x11C0000,0x1340000,0x1340000,0x17C0000,0x7040000,0x11C0000,0x1E00000,0x2DF80000,
-0x1E00000,0xE80001,0xE80001,0xE80001,0xE80001,0x15C0000,0x15C0000,0x15C0000,0x33F80000,0x33F80000,0x74000000,0x15C0000,0x15C0000,0x15C0000,0x33F80000,0x33F80000,0x74000000,0x33F80000,0x33F80000,0x74000000,0x74000000,0x15C0000,0x15C0000,0x15C0000,0x33F80000,0x33F80000,0x74000000,0x33F80000,0x33F80000,0x74000000,0x74000000,0x33F80000,
-0x33F80000,0x74000000,0x74000000,0x74000000,0x1100000,0x4F80000,0xE80001,0x33C0000,0x1880000,0x1F00000,0x17FC0000,0x43FC0000,0x1240000,0x15C0000,0x1F00000,0x74000000,0x1F00000,0xF40001,0x16C0000,0x3BFC0000,0x7A000000,0x16C0000,0x3BFC0000,0x7A000000,0x3BFC0000,0x7A000000,0x7A000000,0x16C0000,0x3BFC0000,0x7A000000,0x3BFC0000,0x7A000000,
-0x7A000000,0x3BFC0000,0x7A000000,0x7A000000,0x7A000000,0x16C0000,0x3BFC0000,0x7A000000,0x3BFC0000,0x7A000000,0x7A000000,0x3BFC0000,0x7A000000,0x7A000000,0x7A000000,0x3BFC0000,0x7A000000,0x7A000000,0x7A000000,0x7A000000,0x1340000,0xB040000,0xB040000,0x19C0000,0x21FC0000,0x59FC0000,0x7A000000,0x7A000000,0x34C0000,0x1CC0000,0x73D80000,0x7A000000,
-0x7FC0000,0xE4008C,0x90E00033,0x80E00033,0x7AE00033,0x8ADC0024,0x80DC0013,0x7CDC001A,0x7CDC0024,0x78DC0016,0x76DC0026,0x88D80034,0x80D8000A,0x7CD8000F,0x7ED40013,0x7AD40002,0x76D80016,0x7AD80034,0x78D4000F,0x76D40019,0x74D40035,0x1540088,0x84CC0033,0x7AD40033,0x7ECC0026,0x7AD00012,0x76D40026,0x80C00033,0x7AC40009,0x76C80015,0x74CC0034,0x2FFC0088,
-0x7AB00033,0x76B80026,0x74AC0034,0x72000088,0xB4D80002,0xF6DC0026,0xF8E00037,0x8ED80002,0x82D80002,0x7CD80002,0x7AD80002,0x7AD40002,0xB0CC0001,0x90D00001,0x7AD40009,0x76C80015,0x1E80088,0xEC0033,0x88E8000A,0x7EE4000A,0x7AE4000A,0x82E40013,0x7EE00002,0x7AE40001,0x7AE40013,0x7AE00005,0x76E00015,0x35C0033,0x80D80009,0x7ADC000A,0x7ED40012,0x7AD40001,
-0x76DC0014,0x33FC0033,0x7AC40008,0x76C80014,0x74000034,0x35C0033,0x80D80009,0x7ADC000A,0x7ED40012,0x7AD40001,0x76DC0014,0x33FC0033,0x7AC40008,0x76C80014,0x74000034,0x33FC0033,0x7AC40008,0x76C80014,0x74000034,0x74000034,0xB4D80001,0xCAE40013,0xDCE8000A,0x8ED80001,0x82D80001,0x7CD80001,0x7AD80001,0x7AD40001,0xB0CC0001,0x8CD40001,0x7AD40009,0x76C80014,
-0x1F40033,0xE00033,0xE00033,0xE00033,0xE00033,0x82DC0012,0x82DC0012,0x82DC0012,0x78DC0012,0x78DC0012,0x74DC0012,0x80D80009,0x80D80009,0x80D80009,0x78D80002,0x78D80002,0x74D80005,0x76D40009,0x76D40009,0x74D40001,0x72D40009,0x14C0033,0x14C0033,0x14C0033,0x7AD00012,0x7AD00012,0x74D40012,0x78CC0009,0x78CC0009,0x74CC0001,0x72CC0009,0x2BF80033,
-0x2BF80033,0x74C00012,0x72B40008,0x70000034,0xA8D80002,0xD6DC0012,0xE00033,0x8CD80001,0x82D80001,0x7CD80001,0x7AD80002,0x78D40002,0xB0CC0000,0x8AD40001,0x7AD40008,0x74CC0001,0x1DC0033,0xE4000A,0xE4000A,0xE4000A,0xE4000A,0x7AE40001,0x7AE40001,0x7AE40001,0x76E00001,0x76E00001,0x74E00001,0x1540008,0x1540008,0x1540008,0x76DC0001,0x76DC0001,
-0x74DC0001,0x2FFC0008,0x2FFC0008,0x74D00000,0x72000008,0x1540008,0x1540008,0x1540008,0x76DC0001,0x76DC0001,0x74DC0001,0x2FFC0008,0x2FFC0008,0x74D00000,0x72000008,0x2FFC0008,0x2FFC0008,0x74D00000,0x72000008,0x72000008,0x9CDC0000,0x9AE40001,0xE4000A,0x8CD80000,0x7EDC0000,0x7ADC0000,0x78DC0000,0x76DC0001,0x9ED40000,0x86D80000,0x1E80008,0x74D00000,
-0x1E80008,0xF00012,0x84EC0001,0x7CEC0001,0x7AE80001,0x1640012,0x7EE00001,0x7AE40000,0x37F80012,0x7AD00000,0x76000014,0x1640012,0x7EE00001,0x7AE40000,0x37F80012,0x7AD00000,0x76000014,0x37F80012,0x7AD00000,0x76000014,0x76000014,0x1640012,0x7EE00001,0x7AE40000,0x37F80012,0x7AD00000,0x76000014,0x37F80012,0x7AD00000,0x76000014,0x76000014,0x37F80012,
-0x7AD00000,0x76000014,0x76000014,0x76000014,0xC4D00000,0x1000012,0xBEEC0001,0x92D40000,0x82D80001,0x7ED40000,0x7AD80000,0x7AC80000,0xB8C80000,0x90D00000,0x7ADC0001,0x76000014,0x1FC0012,0xDC0012,0xDC0012,0xDC0012,0xDC0012,0xDC0012,0xDC0012,0xDC0012,0xDC0012,0xDC0012,0xDC0012,0x7AD80001,0x7AD80001,0x7AD80001,0x7AD80001,0x7AD80001,
-0x7AD80001,0x72D80001,0x72D80001,0x72D80001,0x70D40001,0x3440012,0x3440012,0x3440012,0x3440012,0x3440012,0x3440012,0x74CC0001,0x74CC0001,0x74CC0001,0x70D00000,0x27FC0012,0x27FC0012,0x27FC0012,0x70BC0000,0x6C000014,0xB4D80001,0xDC0012,0xDC0012,0x8CD80001,0x82D80001,0x7CD80001,0x7CD80001,0x78D80001,0xB0CC0000,0x92D00000,0x76D40000,0x74CC0001,
-0x1D40012,};
-static const uint32_t g_etc1_to_bc7_m6_table15[] = {
-0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x2FFC0000,
-0x2FFC0000,0x2FFC0000,0x2FFC0000,0x72000000,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0x2F40000,0x2F40000,0x2F40000,0x1540000,0x1E80000,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,
-0x1680000,0x39F80000,0x39F80000,0x39F80000,0x78000000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x39F80000,0x39F80000,0x39F80000,0x78000000,0x39F80000,0x39F80000,0x39F80000,0x78000000,0x78000000,0x9000000,0xF00001,0xF00001,0x3180000,0x1300000,0x1480000,0x1480000,0x3940000,0x3180000,0x1300000,0x3FC0000,0x39F80000,
-0x3FC0000,0xF80001,0xF80001,0xF80001,0xF80001,0x1740000,0x1740000,0x1740000,0x3FF80000,0x3FF80000,0x7C000000,0x1740000,0x1740000,0x1740000,0x3FF80000,0x3FF80000,0x7C000000,0x3FF80000,0x3FF80000,0x7C000000,0x7C000000,0x1740000,0x1740000,0x1740000,0x3FF80000,0x3FF80000,0x7C000000,0x3FF80000,0x3FF80000,0x7C000000,0x7C000000,0x3FF80000,
-0x3FF80000,0x7C000000,0x7C000000,0x7C000000,0x7200000,0xD080000,0xF80001,0x1540000,0x1A40000,0xBFC0000,0x25FC0000,0x4FF80000,0x1380000,0x1740000,0xBFC0000,0x7C000000,0xBFC0000,0x1040001,0x1840000,0x47FC0000,0x82000000,0x1840000,0x47FC0000,0x82000000,0x47FC0000,0x82000000,0x82000000,0x1840000,0x47FC0000,0x82000000,0x47FC0000,0x82000000,
-0x82000000,0x47FC0000,0x82000000,0x82000000,0x82000000,0x1840000,0x47FC0000,0x82000000,0x47FC0000,0x82000000,0x82000000,0x47FC0000,0x82000000,0x82000000,0x82000000,0x47FC0000,0x82000000,0x82000000,0x82000000,0x82000000,0x1480000,0x1180000,0x1180000,0x1B80000,0x2FFC0000,0x65F00000,0x82000000,0x82000000,0x1640000,0x1EC0000,0x7BE80000,0x82000000,
-0x17FC0000,0xF4008C,0x98F00033,0x88F00033,0x82F00033,0x92EC0024,0x88EC0013,0x84EC001A,0x84EC0024,0x80EC0016,0x7EEC0026,0x90E80034,0x88E8000A,0x84E8000F,0x86E40013,0x82E40002,0x7EE80016,0x82E80034,0x80E4000F,0x7EE40019,0x7CE40035,0x16C0088,0x8CDC0033,0x82E40033,0x86DC0026,0x82E00012,0x7EE40026,0x88D00033,0x82D40009,0x7ED80015,0x7CDC0034,0x3BFC0088,
-0x82C00033,0x7EC80026,0x7CBC0034,0x7A000088,0xBCE80002,0xFEEC0026,0xF0F0003C,0x96E80002,0x8AE80002,0x84E80002,0x82E80002,0x82E40002,0xB8DC0001,0x98E00001,0x82E40009,0x7ED80015,0x7FC0088,0xFC0033,0x90F8000A,0x86F4000A,0x82F4000A,0x8AF40013,0x86F00002,0x82F40001,0x82F40013,0x82F00005,0x7EF00015,0x3740033,0x88E80009,0x82EC000A,0x86E40012,0x82E40001,
-0x7EEC0014,0x3FFC0033,0x82D40008,0x7ED80014,0x7C000034,0x3740033,0x88E80009,0x82EC000A,0x86E40012,0x82E40001,0x7EEC0014,0x3FFC0033,0x82D40008,0x7ED80014,0x7C000034,0x3FFC0033,0x82D40008,0x7ED80014,0x7C000034,0x7C000034,0xBCE80001,0xD2F40013,0xE4F8000A,0x96E80001,0x8AE80001,0x84E80001,0x82E80001,0x82E40001,0xB8DC0001,0x94E40001,0x82E40009,0x7ED80014,
-0xDFC0033,0xF00033,0xF00033,0xF00033,0xF00033,0x8AEC0012,0x8AEC0012,0x8AEC0012,0x80EC0012,0x80EC0012,0x7CEC0012,0x88E80009,0x88E80009,0x88E80009,0x80E80002,0x80E80002,0x7CE80005,0x7EE40009,0x7EE40009,0x7CE40001,0x7AE40009,0x1640033,0x1640033,0x1640033,0x82E00012,0x82E00012,0x7CE40012,0x80DC0009,0x80DC0009,0x7CDC0001,0x7ADC0009,0x37F80033,
-0x37F80033,0x7CD00012,0x7AC40008,0x78000034,0xB0E80002,0xDEEC0012,0xF00033,0x94E80001,0x8AE80001,0x84E80001,0x82E80002,0x80E40002,0xB8DC0000,0x92E40001,0x82E40008,0x7CDC0001,0x1FC0033,0xF4000A,0xF4000A,0xF4000A,0xF4000A,0x82F40001,0x82F40001,0x82F40001,0x7EF00001,0x7EF00001,0x7CF00001,0x16C0008,0x16C0008,0x16C0008,0x7EEC0001,0x7EEC0001,
-0x7CEC0001,0x3BFC0008,0x3BFC0008,0x7CE00000,0x7A000008,0x16C0008,0x16C0008,0x16C0008,0x7EEC0001,0x7EEC0001,0x7CEC0001,0x3BFC0008,0x3BFC0008,0x7CE00000,0x7A000008,0x3BFC0008,0x3BFC0008,0x7CE00000,0x7A000008,0x7A000008,0xA4EC0000,0xA2F40001,0xF4000A,0x94E80000,0x86EC0000,0x82EC0000,0x80EC0000,0x7EEC0001,0xA6E40000,0x8EE80000,0x7FC0008,0x7CE00000,
-0x7FC0008,0x1000012,0x8CFC0001,0x84FC0001,0x82F80001,0x17C0012,0x86F00001,0x82F40000,0x43F80012,0x82E00000,0x7E000014,0x17C0012,0x86F00001,0x82F40000,0x43F80012,0x82E00000,0x7E000014,0x43F80012,0x82E00000,0x7E000014,0x7E000014,0x17C0012,0x86F00001,0x82F40000,0x43F80012,0x82E00000,0x7E000014,0x43F80012,0x82E00000,0x7E000014,0x7E000014,0x43F80012,
-0x82E00000,0x7E000014,0x7E000014,0x7E000014,0xCCE00000,0x1100012,0xC6FC0001,0x9AE40000,0x8AE80001,0x86E40000,0x82E80000,0x82D80000,0xC0D80000,0x98E00000,0x82EC0001,0x7E000014,0x11FC0012,0xEC0012,0xEC0012,0xEC0012,0xEC0012,0xEC0012,0xEC0012,0xEC0012,0xEC0012,0xEC0012,0xEC0012,0x82E80001,0x82E80001,0x82E80001,0x82E80001,0x82E80001,
-0x82E80001,0x7AE80001,0x7AE80001,0x7AE80001,0x78E40001,0x35C0012,0x35C0012,0x35C0012,0x35C0012,0x35C0012,0x35C0012,0x7CDC0001,0x7CDC0001,0x7CDC0001,0x78E00000,0x33FC0012,0x33FC0012,0x33FC0012,0x78CC0000,0x74000014,0xBCE80001,0xEC0012,0xEC0012,0x94E80001,0x8AE80001,0x84E80001,0x84E80001,0x80E80001,0xB8DC0000,0x9AE00000,0x7EE40000,0x7CDC0001,
-0x1F40012,};
-static const uint32_t g_etc1_to_bc7_m6_table16[] = {
-0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x3DF80000,
-0x3DF80000,0x3DF80000,0x3DF80000,0x7A000001,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0x1080000,0x1080000,0x1080000,0x1700000,0x9FC0000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x3800000,0x3800000,0x3800000,0x3800000,0x3800000,
-0x3800000,0x45FC0000,0x45FC0000,0x45FC0000,0x80000001,0x3800000,0x3800000,0x3800000,0x3800000,0x3800000,0x3800000,0x45FC0000,0x45FC0000,0x45FC0000,0x80000001,0x45FC0000,0x45FC0000,0x45FC0000,0x80000001,0x80000001,0x3140000,0x1040000,0x1040000,0x52C0000,0x3440000,0x1600000,0x1600000,0x1B40000,0x52C0000,0x3440000,0x15FC0000,0x45FC0000,
-0x15FC0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x38C0000,0x38C0000,0x38C0000,0x4BFC0000,0x4BFC0000,0x84000001,0x38C0000,0x38C0000,0x38C0000,0x4BFC0000,0x4BFC0000,0x84000001,0x4BFC0000,0x4BFC0000,0x84000001,0x84000001,0x38C0000,0x38C0000,0x38C0000,0x4BFC0000,0x4BFC0000,0x84000001,0x4BFC0000,0x4BFC0000,0x84000001,0x84000001,0x4BFC0000,
-0x4BFC0000,0x84000001,0x84000001,0x84000001,0x1380000,0x71C0000,0x10C0000,0x16C0000,0x3C00000,0x1DF80000,0x35F80000,0x5BF80000,0x1500000,0x38C0000,0x1DF80000,0x84000001,0x1DF80000,0x1180000,0x1A00000,0x55F80000,0x8A000001,0x1A00000,0x55F80000,0x8A000001,0x55F80000,0x8A000001,0x8A000001,0x1A00000,0x55F80000,0x8A000001,0x55F80000,0x8A000001,
-0x8A000001,0x55F80000,0x8A000001,0x8A000001,0x8A000001,0x1A00000,0x55F80000,0x8A000001,0x55F80000,0x8A000001,0x8A000001,0x55F80000,0x8A000001,0x8A000001,0x8A000001,0x55F80000,0x8A000001,0x8A000001,0x8A000001,0x8A000001,0x1600000,0xD280000,0xD280000,0x3D40000,0x3FF80000,0x6FF80000,0x8A000001,0x8A000001,0x17C0000,0xBFC0000,0x85DC0000,0x8A000001,
-0x27FC0000,0x1080088,0x9F040034,0x91040034,0x8B040035,0x9B000026,0x91000015,0x8B000019,0x8D000026,0x8AFC0016,0x88FC0026,0x9CF80033,0x92F80009,0x8CFC000F,0x8EF80012,0x8AF80002,0x88F80016,0x8CF80033,0x8AF4000F,0x88F4001A,0x86F80033,0x1880088,0x96EC0033,0x8AF80034,0x90EC0026,0x8CF00013,0x88F40024,0x90E40033,0x8AEC000A,0x88E80013,0x86EC0033,0x49F80088,
-0x8AD80034,0x88D40024,0x86C80033,0x8200008C,0xC4F80002,0xF9000028,0xFB040038,0xA2F80001,0x94F80002,0x8EF80002,0x8CF80002,0x8AF80002,0xBEF00001,0x9EF40001,0x8CF40009,0x88E80013,0x19FC0088,0x10C0034,0x9B080008,0x8F080009,0x8B080009,0x97040012,0x8F040001,0x8D040001,0x8D040012,0x8B040005,0x89040012,0x1900033,0x90FC0009,0x8B000009,0x8EF80012,0x8AF80002,
-0x88FC0012,0x4DFC0033,0x8AEC0009,0x88E80012,0x86000033,0x1900033,0x90FC0009,0x8B000009,0x8EF80012,0x8AF80002,0x88FC0012,0x4DFC0033,0x8AEC0009,0x88E80012,0x86000033,0x4DFC0033,0x8AEC0009,0x88E80012,0x86000033,0x86000033,0xC0FC0001,0xEB040012,0xFD080008,0x9CFC0001,0x94F80002,0x8EF80002,0x8AFC0002,0x8AF40002,0xBEF00001,0x9AF80001,0x8CF40008,0x88E80012,
-0x1FF80033,0x1040034,0x1040034,0x1040034,0x1040034,0x91000014,0x91000014,0x91000014,0x89000014,0x89000014,0x84FC0015,0x92F80008,0x92F80008,0x92F80008,0x8AF80001,0x8AF80001,0x86F80005,0x86F8000A,0x86F8000A,0x84F80001,0x82F8000A,0x1800033,0x1800033,0x1800033,0x8CF00012,0x8CF00012,0x84F80013,0x8AEC0009,0x8AEC0009,0x84F00002,0x82F0000A,0x45F80033,
-0x45F80033,0x84E40013,0x82DC000A,0x80000033,0xC4F80001,0xD9000014,0x1040034,0xA0F80001,0x94F80001,0x8EF80001,0x8CF80001,0x88F80001,0xBCF00000,0x9EF40000,0x8AF80009,0x84F00002,0x13FC0033,0x1080008,0x1080008,0x1080008,0x1080008,0x8D040000,0x8D040000,0x8D040000,0x87040001,0x87040001,0x85040001,0x1880008,0x1880008,0x1880008,0x87000001,0x87000001,
-0x85000001,0x49F80008,0x49F80008,0x84F80001,0x8200000A,0x1880008,0x1880008,0x1880008,0x87000001,0x87000001,0x85000001,0x49F80008,0x49F80008,0x84F80001,0x8200000A,0x49F80008,0x49F80008,0x84F80001,0x8200000A,0x8200000A,0xB6FC0000,0xBB040000,0x1080008,0x9AFC0000,0x90FC0000,0x8CFC0000,0x89000001,0x88FC0000,0xB2F40000,0x98F80000,0x19FC0008,0x84F80001,
-0x19FC0008,0x1100014,0x970C0000,0x8F0C0000,0x8B0C0001,0x1980012,0x8F040001,0x8B080001,0x51F80012,0x8AF80001,0x88000012,0x1980012,0x8F040001,0x8B080001,0x51F80012,0x8AF80001,0x88000012,0x51F80012,0x8AF80001,0x88000012,0x88000012,0x1980012,0x8F040001,0x8B080001,0x51F80012,0x8AF80001,0x88000012,0x51F80012,0x8AF80001,0x88000012,0x88000012,0x51F80012,
-0x8AF80001,0x88000012,0x88000012,0x88000012,0xD0F40000,0x1240012,0xDF0C0000,0xA2F80000,0x94F80001,0x90F40000,0x8AFC0001,0x8AF00001,0xC6EC0000,0xA2F00000,0x8CFC0000,0x88000012,0x21FC0012,0xFC0014,0xFC0014,0xFC0014,0xFC0014,0xFC0014,0xFC0014,0xFC0014,0xFC0014,0xFC0014,0xFC0014,0x8CF80000,0x8CF80000,0x8CF80000,0x8CF80000,0x8CF80000,
-0x8CF80000,0x84F80000,0x84F80000,0x84F80000,0x80F80001,0x1780012,0x1780012,0x1780012,0x1780012,0x1780012,0x1780012,0x84F00001,0x84F00001,0x84F00001,0x80F40001,0x41FC0012,0x41FC0012,0x41FC0012,0x80E40001,0x7E000012,0xD4F80000,0xFC0014,0xFC0014,0xA4F80000,0x98F80000,0x90F80000,0x90F80000,0x8AF80000,0xBCF00000,0x9EF40000,0x86F80001,0x84F00001,
-0xFFC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table17[] = {
-0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x49F80000,
-0x49F80000,0x49F80000,0x49F80000,0x82000001,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x5180000,0x5180000,0x5180000,0x1880000,0x19FC0000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,
-0x3980000,0x51FC0000,0x51FC0000,0x51FC0000,0x88000001,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,0x51FC0000,0x51FC0000,0x51FC0000,0x88000001,0x51FC0000,0x51FC0000,0x51FC0000,0x88000001,0x88000001,0xB240000,0x1140000,0x1140000,0x1400000,0x3580000,0x1780000,0x1780000,0x1D00000,0x1400000,0x3580000,0x23FC0000,0x51FC0000,
-0x23FC0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x3A40000,0x3A40000,0x3A40000,0x57FC0000,0x57FC0000,0x8C000001,0x3A40000,0x3A40000,0x3A40000,0x57FC0000,0x57FC0000,0x8C000001,0x57FC0000,0x57FC0000,0x8C000001,0x8C000001,0x3A40000,0x3A40000,0x3A40000,0x57FC0000,0x57FC0000,0x8C000001,0x57FC0000,0x57FC0000,0x8C000001,0x8C000001,0x57FC0000,
-0x57FC0000,0x8C000001,0x8C000001,0x8C000001,0x5480000,0xF2C0000,0x11C0000,0x3800000,0x1DC0000,0x2BFC0000,0x41FC0000,0x65FC0000,0x1640000,0x3A40000,0x2BFC0000,0x8C000001,0x2BFC0000,0x1280000,0x1B80000,0x61F80000,0x92000001,0x1B80000,0x61F80000,0x92000001,0x61F80000,0x92000001,0x92000001,0x1B80000,0x61F80000,0x92000001,0x61F80000,0x92000001,
-0x92000001,0x61F80000,0x92000001,0x92000001,0x92000001,0x1B80000,0x61F80000,0x92000001,0x61F80000,0x92000001,0x92000001,0x61F80000,0x92000001,0x92000001,0x92000001,0x61F80000,0x92000001,0x92000001,0x92000001,0x92000001,0x1740000,0x13C0000,0x13C0000,0x1F00000,0x4BFC0000,0x79F80000,0x92000001,0x92000001,0x3900000,0x1BFC0000,0x8DEC0000,0x92000001,
-0x37FC0000,0x1180088,0xA7140034,0x99140034,0x93140035,0xA3100026,0x99100015,0x93100019,0x95100026,0x930C0016,0x910C0026,0xA5080033,0x9B080009,0x950C000F,0x97080012,0x93080002,0x91080016,0x95080033,0x9304000F,0x9104001A,0x8F080033,0x1A00088,0x9EFC0033,0x93080034,0x98FC0026,0x95000013,0x91040024,0x98F40033,0x92FC000A,0x90F80013,0x8EFC0033,0x55F80088,
-0x92E80034,0x90E40024,0x8ED80033,0x8A00008C,0xCD080002,0xF110002E,0xF314003D,0xAB080001,0x9D080002,0x97080002,0x95080002,0x93080002,0xC7000001,0xA7040001,0x95040009,0x90F80013,0x27FC0088,0x11C0034,0xA3180008,0x97180009,0x93180009,0x9F140012,0x97140001,0x95140001,0x95140012,0x93140005,0x91140012,0x1A80033,0x990C0009,0x93100009,0x97080012,0x93080002,
-0x910C0012,0x59FC0033,0x92FC0009,0x90F80012,0x8E000033,0x1A80033,0x990C0009,0x93100009,0x97080012,0x93080002,0x910C0012,0x59FC0033,0x92FC0009,0x90F80012,0x8E000033,0x59FC0033,0x92FC0009,0x90F80012,0x8E000033,0x8E000033,0xC90C0001,0xF3140012,0xF5180009,0xA50C0001,0x9D080002,0x97080002,0x930C0002,0x93040002,0xC7000001,0xA3080001,0x95040008,0x90F80012,
-0x2DFC0033,0x1140034,0x1140034,0x1140034,0x1140034,0x99100014,0x99100014,0x99100014,0x91100014,0x91100014,0x8D0C0015,0x9B080008,0x9B080008,0x9B080008,0x93080001,0x93080001,0x8F080005,0x8F08000A,0x8F08000A,0x8D080001,0x8B08000A,0x1980033,0x1980033,0x1980033,0x95000012,0x95000012,0x8D080013,0x92FC0009,0x92FC0009,0x8D000002,0x8B00000A,0x51F80033,
-0x51F80033,0x8CF40013,0x8AEC000A,0x88000033,0xCD080001,0xE1100014,0x1140034,0xA9080001,0x9D080001,0x97080001,0x95080001,0x91080001,0xC5000000,0xA7040000,0x93080009,0x8D000002,0x21FC0033,0x1180008,0x1180008,0x1180008,0x1180008,0x95140000,0x95140000,0x95140000,0x8F140001,0x8F140001,0x8D140001,0x1A00008,0x1A00008,0x1A00008,0x8F100001,0x8F100001,
-0x8D100001,0x55F80008,0x55F80008,0x8D080001,0x8A00000A,0x1A00008,0x1A00008,0x1A00008,0x8F100001,0x8F100001,0x8D100001,0x55F80008,0x55F80008,0x8D080001,0x8A00000A,0x55F80008,0x55F80008,0x8D080001,0x8A00000A,0x8A00000A,0xBF0C0000,0xC3140000,0x1180008,0xA30C0000,0x990C0000,0x950C0000,0x91100001,0x910C0000,0xBB040000,0xA1080000,0x27FC0008,0x8D080001,
-0x27FC0008,0x1200014,0x9F1C0000,0x971C0000,0x931C0001,0x1B00012,0x97140001,0x93180001,0x5DF40012,0x93080001,0x90000012,0x1B00012,0x97140001,0x93180001,0x5DF40012,0x93080001,0x90000012,0x5DF40012,0x93080001,0x90000012,0x90000012,0x1B00012,0x97140001,0x93180001,0x5DF40012,0x93080001,0x90000012,0x5DF40012,0x93080001,0x90000012,0x90000012,0x5DF40012,
-0x93080001,0x90000012,0x90000012,0x90000012,0xD9040000,0x3340012,0xE71C0000,0xAB080000,0x9D080001,0x99040000,0x930C0001,0x93000001,0xCEFC0000,0xAB000000,0x950C0000,0x90000012,0x31FC0012,0x10C0014,0x10C0014,0x10C0014,0x10C0014,0x10C0014,0x10C0014,0x10C0014,0x10C0014,0x10C0014,0x10C0014,0x95080000,0x95080000,0x95080000,0x95080000,0x95080000,
-0x95080000,0x8D080000,0x8D080000,0x8D080000,0x89080001,0x1900012,0x1900012,0x1900012,0x1900012,0x1900012,0x1900012,0x8D000001,0x8D000001,0x8D000001,0x89040001,0x4DFC0012,0x4DFC0012,0x4DFC0012,0x88F40001,0x86000012,0xDD080000,0x10C0014,0x10C0014,0xAD080000,0xA1080000,0x99080000,0x99080000,0x93080000,0xC5000000,0xA7040000,0x8F080001,0x8D000001,
-0x1FF80012,};
-static const uint32_t g_etc1_to_bc7_m6_table18[] = {
-0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x55F80000,
-0x55F80000,0x55F80000,0x55F80000,0x8A000001,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0xD280000,0xD280000,0xD280000,0x1A00000,0x27FC0000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,
-0x3B00000,0x5DFC0000,0x5DFC0000,0x5DFC0000,0x90000001,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x5DFC0000,0x5DFC0000,0x5DFC0000,0x90000001,0x5DFC0000,0x5DFC0000,0x5DFC0000,0x90000001,0x90000001,0x1380000,0x1240000,0x1240000,0x1540000,0x36C0000,0x18C0000,0x18C0000,0x1EC0000,0x1540000,0x36C0000,0x33FC0000,0x5DFC0000,
-0x33FC0000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x3BC0000,0x3BC0000,0x3BC0000,0x63FC0000,0x63FC0000,0x94000001,0x3BC0000,0x3BC0000,0x3BC0000,0x63FC0000,0x63FC0000,0x94000001,0x63FC0000,0x63FC0000,0x94000001,0x94000001,0x3BC0000,0x3BC0000,0x3BC0000,0x63FC0000,0x63FC0000,0x94000001,0x63FC0000,0x63FC0000,0x94000001,0x94000001,0x63FC0000,
-0x63FC0000,0x94000001,0x94000001,0x94000001,0x15C0000,0x1400000,0x12C0000,0x1980000,0x1F80000,0x3BFC0000,0x4FFC0000,0x71F80000,0x1780000,0x3BC0000,0x3BFC0000,0x94000001,0x3BFC0000,0x1380000,0x1D00000,0x6DF80000,0x9A000001,0x1D00000,0x6DF80000,0x9A000001,0x6DF80000,0x9A000001,0x9A000001,0x1D00000,0x6DF80000,0x9A000001,0x6DF80000,0x9A000001,
-0x9A000001,0x6DF80000,0x9A000001,0x9A000001,0x9A000001,0x1D00000,0x6DF80000,0x9A000001,0x6DF80000,0x9A000001,0x9A000001,0x6DF80000,0x9A000001,0x9A000001,0x9A000001,0x6DF80000,0x9A000001,0x9A000001,0x9A000001,0x9A000001,0x1880000,0x14C0000,0x14C0000,0xDFC0000,0x59FC0000,0x83F80000,0x9A000001,0x9A000001,0x1A80000,0x2DFC0000,0x95FC0000,0x9A000001,
-0x45FC0000,0x1280088,0xAF240034,0xA1240034,0x9B240035,0xAB200026,0xA1200015,0x9B200019,0x9D200026,0x9B1C0016,0x991C0026,0xAD180033,0xA3180009,0x9D1C000F,0x9F180012,0x9B180002,0x99180016,0x9D180033,0x9B14000F,0x9914001A,0x97180033,0x1B80088,0xA70C0033,0x9B180034,0xA10C0026,0x9D100013,0x99140024,0xA1040033,0x9B0C000A,0x99080013,0x970C0033,0x61F80088,
-0x9AF80034,0x98F40024,0x96E80033,0x9200008C,0xD5180002,0xF920002E,0xFB24003D,0xB3180001,0xA5180002,0x9F180002,0x9D180002,0x9B180002,0xCF100001,0xAF140001,0x9D140009,0x99080013,0x37FC0088,0x12C0034,0xAB280008,0x9F280009,0x9B280009,0xA7240012,0x9F240001,0x9D240001,0x9D240012,0x9B240005,0x99240012,0x1C00033,0xA11C0009,0x9B200009,0x9F180012,0x9B180002,
-0x991C0012,0x65F80033,0x9B0C0009,0x99080012,0x96000033,0x1C00033,0xA11C0009,0x9B200009,0x9F180012,0x9B180002,0x991C0012,0x65F80033,0x9B0C0009,0x99080012,0x96000033,0x65F80033,0x9B0C0009,0x99080012,0x96000033,0x96000033,0xD11C0001,0xFB240012,0xFD280009,0xAD1C0001,0xA5180002,0x9F180002,0x9B1C0002,0x9B140002,0xCF100001,0xAB180001,0x9D140008,0x99080012,
-0x3DF80033,0x1240034,0x1240034,0x1240034,0x1240034,0xA1200014,0xA1200014,0xA1200014,0x99200014,0x99200014,0x951C0015,0xA3180008,0xA3180008,0xA3180008,0x9B180001,0x9B180001,0x97180005,0x9718000A,0x9718000A,0x95180001,0x9318000A,0x1B00033,0x1B00033,0x1B00033,0x9D100012,0x9D100012,0x95180013,0x9B0C0009,0x9B0C0009,0x95100002,0x9310000A,0x5DF40033,
-0x5DF40033,0x95040013,0x92FC000A,0x90000033,0xD5180001,0xE9200014,0x1240034,0xB1180001,0xA5180001,0x9F180001,0x9D180001,0x99180001,0xCD100000,0xAF140000,0x9B180009,0x95100002,0x31FC0033,0x1280008,0x1280008,0x1280008,0x1280008,0x9D240000,0x9D240000,0x9D240000,0x97240001,0x97240001,0x95240001,0x1B80008,0x1B80008,0x1B80008,0x97200001,0x97200001,
-0x95200001,0x61F80008,0x61F80008,0x95180001,0x9200000A,0x1B80008,0x1B80008,0x1B80008,0x97200001,0x97200001,0x95200001,0x61F80008,0x61F80008,0x95180001,0x9200000A,0x61F80008,0x61F80008,0x95180001,0x9200000A,0x9200000A,0xC71C0000,0xCB240000,0x1280008,0xAB1C0000,0xA11C0000,0x9D1C0000,0x99200001,0x991C0000,0xC3140000,0xA9180000,0x37FC0008,0x95180001,
-0x37FC0008,0x1300014,0xA72C0000,0x9F2C0000,0x9B2C0001,0x3C40012,0x9F240001,0x9B280001,0x67FC0012,0x9B180001,0x98000012,0x3C40012,0x9F240001,0x9B280001,0x67FC0012,0x9B180001,0x98000012,0x67FC0012,0x9B180001,0x98000012,0x98000012,0x3C40012,0x9F240001,0x9B280001,0x67FC0012,0x9B180001,0x98000012,0x67FC0012,0x9B180001,0x98000012,0x98000012,0x67FC0012,
-0x9B180001,0x98000012,0x98000012,0x98000012,0xE1140000,0xB440012,0xEF2C0000,0xB3180000,0xA5180001,0xA1140000,0x9B1C0001,0x9B100001,0xD70C0000,0xB3100000,0x9D1C0000,0x98000012,0x3FFC0012,0x11C0014,0x11C0014,0x11C0014,0x11C0014,0x11C0014,0x11C0014,0x11C0014,0x11C0014,0x11C0014,0x11C0014,0x9D180000,0x9D180000,0x9D180000,0x9D180000,0x9D180000,
-0x9D180000,0x95180000,0x95180000,0x95180000,0x91180001,0x1A80012,0x1A80012,0x1A80012,0x1A80012,0x1A80012,0x1A80012,0x95100001,0x95100001,0x95100001,0x91140001,0x59FC0012,0x59FC0012,0x59FC0012,0x91040001,0x8E000012,0xE5180000,0x11C0014,0x11C0014,0xB5180000,0xA9180000,0xA1180000,0xA1180000,0x9B180000,0xCD100000,0xAF140000,0x97180001,0x95100001,
-0x2DFC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table19[] = {
-0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x61F80000,
-0x61F80000,0x61F80000,0x61F80000,0x92000001,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x13C0000,0x13C0000,0x13C0000,0x1B80000,0x37FC0000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,
-0x1C80000,0x69FC0000,0x69FC0000,0x69FC0000,0x98000001,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x69FC0000,0x69FC0000,0x69FC0000,0x98000001,0x69FC0000,0x69FC0000,0x69FC0000,0x98000001,0x98000001,0x1480000,0x1340000,0x1340000,0x5640000,0x3800000,0x1A40000,0x1A40000,0x7FC0000,0x5640000,0x3800000,0x41FC0000,0x69FC0000,
-0x41FC0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x1D40000,0x1D40000,0x1D40000,0x6FFC0000,0x6FFC0000,0x9C000001,0x1D40000,0x1D40000,0x1D40000,0x6FFC0000,0x6FFC0000,0x9C000001,0x6FFC0000,0x6FFC0000,0x9C000001,0x9C000001,0x1D40000,0x1D40000,0x1D40000,0x6FFC0000,0x6FFC0000,0x9C000001,0x6FFC0000,0x6FFC0000,0x9C000001,0x9C000001,0x6FFC0000,
-0x6FFC0000,0x9C000001,0x9C000001,0x9C000001,0x1700000,0x1500000,0x13C0000,0x3AC0000,0x11FC0000,0x49FC0000,0x5DF80000,0x7BFC0000,0x18C0000,0x1D40000,0x49FC0000,0x9C000001,0x49FC0000,0x1480000,0x1E80000,0x79F80000,0xA2000001,0x1E80000,0x79F80000,0xA2000001,0x79F80000,0xA2000001,0xA2000001,0x1E80000,0x79F80000,0xA2000001,0x79F80000,0xA2000001,
-0xA2000001,0x79F80000,0xA2000001,0xA2000001,0xA2000001,0x1E80000,0x79F80000,0xA2000001,0x79F80000,0xA2000001,0xA2000001,0x79F80000,0xA2000001,0xA2000001,0xA2000001,0x79F80000,0xA2000001,0xA2000001,0xA2000001,0xA2000001,0x19C0000,0x75C0000,0x75C0000,0x21FC0000,0x67F80000,0x8DF80000,0xA2000001,0xA2000001,0x3BC0000,0x3DFC0000,0x9FD00000,0xA2000001,
-0x55FC0000,0x1380088,0xB7340034,0xA9340034,0xA3340035,0xB3300026,0xA9300015,0xA3300019,0xA5300026,0xA32C0016,0xA12C0026,0xB5280033,0xAB280009,0xA52C000F,0xA7280012,0xA3280002,0xA1280016,0xA5280033,0xA324000F,0xA124001A,0x9F280033,0x1D00088,0xAF1C0033,0xA3280034,0xA91C0026,0xA5200013,0xA1240024,0xA9140033,0xA31C000A,0xA1180013,0x9F1C0033,0x6DF80088,
-0xA3080034,0xA1040024,0x9EF80033,0x9A00008C,0xDD280002,0xF1300038,0xF3340044,0xBB280001,0xAD280002,0xA7280002,0xA5280002,0xA3280002,0xD7200001,0xB7240001,0xA5240009,0xA1180013,0x45FC0088,0x13C0034,0xB3380008,0xA7380009,0xA3380009,0xAF340012,0xA7340001,0xA5340001,0xA5340012,0xA3340005,0xA1340012,0x1D80033,0xA92C0009,0xA3300009,0xA7280012,0xA3280002,
-0xA12C0012,0x71F80033,0xA31C0009,0xA1180012,0x9E000033,0x1D80033,0xA92C0009,0xA3300009,0xA7280012,0xA3280002,0xA12C0012,0x71F80033,0xA31C0009,0xA1180012,0x9E000033,0x71F80033,0xA31C0009,0xA1180012,0x9E000033,0x9E000033,0xD92C0001,0xF3340014,0xF538000C,0xB52C0001,0xAD280002,0xA7280002,0xA32C0002,0xA3240002,0xD7200001,0xB3280001,0xA5240008,0xA1180012,
-0x4BFC0033,0x1340034,0x1340034,0x1340034,0x1340034,0xA9300014,0xA9300014,0xA9300014,0xA1300014,0xA1300014,0x9D2C0015,0xAB280008,0xAB280008,0xAB280008,0xA3280001,0xA3280001,0x9F280005,0x9F28000A,0x9F28000A,0x9D280001,0x9B28000A,0x3C40033,0x3C40033,0x3C40033,0xA5200012,0xA5200012,0x9D280013,0xA31C0009,0xA31C0009,0x9D200002,0x9B20000A,0x67FC0033,
-0x67FC0033,0x9D140013,0x9B0C000A,0x98000033,0xDD280001,0xF1300014,0x1340034,0xB9280001,0xAD280001,0xA7280001,0xA5280001,0xA1280001,0xD5200000,0xB7240000,0xA3280009,0x9D200002,0x3FFC0033,0x1380008,0x1380008,0x1380008,0x1380008,0xA5340000,0xA5340000,0xA5340000,0x9F340001,0x9F340001,0x9D340001,0x1D00008,0x1D00008,0x1D00008,0x9F300001,0x9F300001,
-0x9D300001,0x6DF80008,0x6DF80008,0x9D280001,0x9A00000A,0x1D00008,0x1D00008,0x1D00008,0x9F300001,0x9F300001,0x9D300001,0x6DF80008,0x6DF80008,0x9D280001,0x9A00000A,0x6DF80008,0x6DF80008,0x9D280001,0x9A00000A,0x9A00000A,0xCF2C0000,0xD3340000,0x1380008,0xB32C0000,0xA92C0000,0xA52C0000,0xA1300001,0xA12C0000,0xCB240000,0xB1280000,0x45FC0008,0x9D280001,
-0x45FC0008,0x1400014,0xAF3C0000,0xA73C0000,0xA33C0001,0x3DC0012,0xA7340001,0xA3380001,0x73FC0012,0xA3280001,0xA0000012,0x3DC0012,0xA7340001,0xA3380001,0x73FC0012,0xA3280001,0xA0000012,0x73FC0012,0xA3280001,0xA0000012,0xA0000012,0x3DC0012,0xA7340001,0xA3380001,0x73FC0012,0xA3280001,0xA0000012,0x73FC0012,0xA3280001,0xA0000012,0xA0000012,0x73FC0012,
-0xA3280001,0xA0000012,0xA0000012,0xA0000012,0xE9240000,0x1580012,0xF73C0000,0xBB280000,0xAD280001,0xA9240000,0xA32C0001,0xA3200001,0xDF1C0000,0xBB200000,0xA52C0000,0xA0000012,0x4FFC0012,0x12C0014,0x12C0014,0x12C0014,0x12C0014,0x12C0014,0x12C0014,0x12C0014,0x12C0014,0x12C0014,0x12C0014,0xA5280000,0xA5280000,0xA5280000,0xA5280000,0xA5280000,
-0xA5280000,0x9D280000,0x9D280000,0x9D280000,0x99280001,0x1C00012,0x1C00012,0x1C00012,0x1C00012,0x1C00012,0x1C00012,0x9D200001,0x9D200001,0x9D200001,0x99240001,0x65F80012,0x65F80012,0x65F80012,0x99140001,0x96000012,0xED280000,0x12C0014,0x12C0014,0xBD280000,0xB1280000,0xA9280000,0xA9280000,0xA3280000,0xD5200000,0xB7240000,0x9F280001,0x9D200001,
-0x3DF80012,};
-static const uint32_t g_etc1_to_bc7_m6_table20[] = {
-0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x6DFC0000,
-0x6DFC0000,0x6DFC0000,0x6DFC0000,0x9C000000,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0xF4C0000,0xF4C0000,0xF4C0000,0x3D00000,0x47FC0000,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,
-0x1E40000,0x77F80000,0x77F80000,0x77F80000,0xA2000000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x77F80000,0x77F80000,0x77F80000,0xA2000000,0x77F80000,0x77F80000,0x77F80000,0xA2000000,0xA2000000,0x15C0000,0x1440001,0x1440001,0x17C0000,0x1980000,0x1BC0000,0x1BC0000,0x1DFC0000,0x17C0000,0x1980000,0x53FC0000,0x77F80000,
-0x53FC0000,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x1F00000,0x1F00000,0x1F00000,0x7DF80000,0x7DF80000,0xA6000000,0x1F00000,0x1F00000,0x1F00000,0x7DF80000,0x7DF80000,0xA6000000,0x7DF80000,0x7DF80000,0xA6000000,0xA6000000,0x1F00000,0x1F00000,0x1F00000,0x7DF80000,0x7DF80000,0xA6000000,0x7DF80000,0x7DF80000,0xA6000000,0xA6000000,0x7DF80000,
-0x7DF80000,0xA6000000,0xA6000000,0xA6000000,0x1840000,0x1640000,0x14C0001,0x3C40000,0x27FC0000,0x5BFC0000,0x6BFC0000,0x87FC0000,0x5A00000,0x1F00000,0x5BFC0000,0xA6000000,0x5BFC0000,0x1580001,0x7FC0000,0x85FC0000,0xAC000000,0x7FC0000,0x85FC0000,0xAC000000,0x85FC0000,0xAC000000,0xAC000000,0x7FC0000,0x85FC0000,0xAC000000,0x85FC0000,0xAC000000,
-0xAC000000,0x85FC0000,0xAC000000,0xAC000000,0xAC000000,0x7FC0000,0x85FC0000,0xAC000000,0x85FC0000,0xAC000000,0xAC000000,0x85FC0000,0xAC000000,0xAC000000,0xAC000000,0x85FC0000,0xAC000000,0xAC000000,0xAC000000,0xAC000000,0x3B00000,0x1700000,0x1700000,0x37FC0000,0x75FC0000,0x99F40000,0xAC000000,0xAC000000,0x3D40000,0x51FC0000,0xA9C40000,0xAC000000,
-0x65FC0000,0x148008C,0xC3440033,0xB3440033,0xAD440033,0xBD400024,0xB3400013,0xAF40001A,0xAF400024,0xAB400016,0xA9400026,0xBB3C0034,0xB33C000A,0xAF3C000F,0xB1380013,0xAD380002,0xA93C0016,0xAD3C0034,0xAB38000F,0xA9380019,0xA7380035,0x3E80088,0xB7300033,0xAD380033,0xB1300026,0xAD340012,0xA9380026,0xB3240033,0xAD280009,0xA92C0015,0xA7300034,0x79FC0088,
-0xAD140033,0xA91C0026,0xA7100034,0xA4000088,0xE73C0002,0xFB440034,0xFD480044,0xC13C0002,0xB53C0002,0xAF3C0002,0xAD3C0002,0xAD380002,0xE3300001,0xC3340001,0xAD380009,0xA92C0015,0x57FC0088,0x1500033,0xBB4C000A,0xB148000A,0xAD48000A,0xB5480013,0xB1440002,0xAD480001,0xAD480013,0xAD440005,0xA9440015,0x1F40033,0xB33C0009,0xAD40000A,0xB1380012,0xAD380001,
-0xA9400014,0x7FF80033,0xAD280008,0xA92C0014,0xA6000034,0x1F40033,0xB33C0009,0xAD40000A,0xB1380012,0xAD380001,0xA9400014,0x7FF80033,0xAD280008,0xA92C0014,0xA6000034,0x7FF80033,0xAD280008,0xA92C0014,0xA6000034,0xA6000034,0xE73C0001,0xFD480013,0xFF4C000B,0xC13C0001,0xB53C0001,0xAF3C0001,0xAD3C0001,0xAD380001,0xE3300001,0xBF380001,0xAD380009,0xA92C0014,
-0x5DF80033,0x1440033,0x1440033,0x1440033,0x1440033,0xB5400012,0xB5400012,0xB5400012,0xAB400012,0xAB400012,0xA7400012,0xB33C0009,0xB33C0009,0xB33C0009,0xAB3C0002,0xAB3C0002,0xA73C0005,0xA9380009,0xA9380009,0xA7380001,0xA5380009,0x1E00033,0x1E00033,0x1E00033,0xAD340012,0xAD340012,0xA7380012,0xAB300009,0xAB300009,0xA7300001,0xA5300009,0x75FC0033,
-0x75FC0033,0xA7240012,0xA5180008,0xA2000034,0xDB3C0002,0xF9400013,0x1440033,0xBF3C0001,0xB53C0001,0xAF3C0001,0xAD3C0002,0xAB380002,0xE3300000,0xBD380001,0xAD380008,0xA7300001,0x51FC0033,0x148000A,0x148000A,0x148000A,0x148000A,0xAD480001,0xAD480001,0xAD480001,0xA9440001,0xA9440001,0xA7440001,0x3E80008,0x3E80008,0x3E80008,0xA9400001,0xA9400001,
-0xA7400001,0x79FC0008,0x79FC0008,0xA7340000,0xA4000008,0x3E80008,0x3E80008,0x3E80008,0xA9400001,0xA9400001,0xA7400001,0x79FC0008,0x79FC0008,0xA7340000,0xA4000008,0x79FC0008,0x79FC0008,0xA7340000,0xA4000008,0xA4000008,0xCF400000,0xCD480001,0x148000A,0xBF3C0000,0xB1400000,0xAD400000,0xAB400000,0xA9400001,0xD1380000,0xB93C0000,0x57FC0008,0xA7340000,
-0x57FC0008,0x1540012,0xB7500001,0xAF500001,0xAD4C0001,0x1F80012,0xB1440001,0xAD480000,0x81FC0012,0xAD340000,0xA8000014,0x1F80012,0xB1440001,0xAD480000,0x81FC0012,0xAD340000,0xA8000014,0x81FC0012,0xAD340000,0xA8000014,0xA8000014,0x1F80012,0xB1440001,0xAD480000,0x81FC0012,0xAD340000,0xA8000014,0x81FC0012,0xAD340000,0xA8000014,0xA8000014,0x81FC0012,
-0xAD340000,0xA8000014,0xA8000014,0xA8000014,0xF7340000,0xD680012,0xF1500001,0xC5380000,0xB53C0001,0xB1380000,0xAD3C0000,0xAD2C0000,0xEB2C0000,0xC3340000,0xAD400001,0xA8000014,0x5FFC0012,0x1400012,0x1400012,0x1400012,0x1400012,0x1400012,0x1400012,0x1400012,0x1400012,0x1400012,0x1400012,0xAD3C0001,0xAD3C0001,0xAD3C0001,0xAD3C0001,0xAD3C0001,
-0xAD3C0001,0xA53C0001,0xA53C0001,0xA53C0001,0xA3380001,0x1DC0012,0x1DC0012,0x1DC0012,0x1DC0012,0x1DC0012,0x1DC0012,0xA7300001,0xA7300001,0xA7300001,0xA3340000,0x73F80012,0x73F80012,0x73F80012,0xA3200000,0x9E000014,0xE73C0001,0x1400012,0x1400012,0xBF3C0001,0xB53C0001,0xAF3C0001,0xAF3C0001,0xAB3C0001,0xE3300000,0xC5340000,0xA9380000,0xA7300001,
-0x4DFC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table21[] = {
-0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x79FC0000,
-0x79FC0000,0x79FC0000,0x79FC0000,0xA4000000,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1600000,0x1600000,0x1600000,0x3E80000,0x57FC0000,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,
-0x1FC0000,0x83F80000,0x83F80000,0x83F80000,0xAA000000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x83F80000,0x83F80000,0x83F80000,0xAA000000,0x83F80000,0x83F80000,0x83F80000,0xAA000000,0xAA000000,0x16C0000,0x1540001,0x1540001,0x38C0000,0x1AC0000,0x1D00000,0x1D00000,0x31FC0000,0x38C0000,0x1AC0000,0x61FC0000,0x83F80000,
-0x61FC0000,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0xDFC0000,0xDFC0000,0xDFC0000,0x89F80000,0x89F80000,0xAE000000,0xDFC0000,0xDFC0000,0xDFC0000,0x89F80000,0x89F80000,0xAE000000,0x89F80000,0x89F80000,0xAE000000,0xAE000000,0xDFC0000,0xDFC0000,0xDFC0000,0x89F80000,0x89F80000,0xAE000000,0x89F80000,0x89F80000,0xAE000000,0xAE000000,0x89F80000,
-0x89F80000,0xAE000000,0xAE000000,0xAE000000,0x1980000,0x3740000,0x15C0001,0x1DC0000,0x3BFC0000,0x69FC0000,0x79FC0000,0x93F80000,0x5B40000,0xDFC0000,0x69FC0000,0xAE000000,0x69FC0000,0x1680001,0x1FFC0000,0x91FC0000,0xB4000000,0x1FFC0000,0x91FC0000,0xB4000000,0x91FC0000,0xB4000000,0xB4000000,0x1FFC0000,0x91FC0000,0xB4000000,0x91FC0000,0xB4000000,
-0xB4000000,0x91FC0000,0xB4000000,0xB4000000,0xB4000000,0x1FFC0000,0x91FC0000,0xB4000000,0x91FC0000,0xB4000000,0xB4000000,0x91FC0000,0xB4000000,0xB4000000,0xB4000000,0x91FC0000,0xB4000000,0xB4000000,0xB4000000,0xB4000000,0x3C40000,0x9800000,0x9800000,0x4BFC0000,0x83FC0000,0xA3F40000,0xB4000000,0xB4000000,0x1EC0000,0x63FC0000,0xB1D40000,0xB4000000,
-0x75FC0000,0x158008C,0xCB540033,0xBB540033,0xB5540033,0xC5500024,0xBB500013,0xB750001A,0xB7500024,0xB3500016,0xB1500026,0xC34C0034,0xBB4C000A,0xB74C000F,0xB9480013,0xB5480002,0xB14C0016,0xB54C0034,0xB348000F,0xB1480019,0xAF480035,0x7FC0088,0xBF400033,0xB5480033,0xB9400026,0xB5440012,0xB1480026,0xBB340033,0xB5380009,0xB13C0015,0xAF400034,0x85FC0088,
-0xB5240033,0xB12C0026,0xAF200034,0xAC000088,0xEF4C0002,0xF354003E,0xF558004B,0xC94C0002,0xBD4C0002,0xB74C0002,0xB54C0002,0xB5480002,0xEB400001,0xCB440001,0xB5480009,0xB13C0015,0x65FC0088,0x1600033,0xC35C000A,0xB958000A,0xB558000A,0xBD580013,0xB9540002,0xB5580001,0xB5580013,0xB5540005,0xB1540015,0xFFC0033,0xBB4C0009,0xB550000A,0xB9480012,0xB5480001,
-0xB1500014,0x8BF80033,0xB5380008,0xB13C0014,0xAE000034,0xFFC0033,0xBB4C0009,0xB550000A,0xB9480012,0xB5480001,0xB1500014,0x8BF80033,0xB5380008,0xB13C0014,0xAE000034,0x8BF80033,0xB5380008,0xB13C0014,0xAE000034,0xAE000034,0xEF4C0001,0xF5580015,0xF75C000E,0xC94C0001,0xBD4C0001,0xB74C0001,0xB54C0001,0xB5480001,0xEB400001,0xC7480001,0xB5480009,0xB13C0014,
-0x6BFC0033,0x1540033,0x1540033,0x1540033,0x1540033,0xBD500012,0xBD500012,0xBD500012,0xB3500012,0xB3500012,0xAF500012,0xBB4C0009,0xBB4C0009,0xBB4C0009,0xB34C0002,0xB34C0002,0xAF4C0005,0xB1480009,0xB1480009,0xAF480001,0xAD480009,0x1F80033,0x1F80033,0x1F80033,0xB5440012,0xB5440012,0xAF480012,0xB3400009,0xB3400009,0xAF400001,0xAD400009,0x81FC0033,
-0x81FC0033,0xAF340012,0xAD280008,0xAA000034,0xE34C0002,0xF1500016,0x1540033,0xC74C0001,0xBD4C0001,0xB74C0001,0xB54C0002,0xB3480002,0xEB400000,0xC5480001,0xB5480008,0xAF400001,0x5FFC0033,0x158000A,0x158000A,0x158000A,0x158000A,0xB5580001,0xB5580001,0xB5580001,0xB1540001,0xB1540001,0xAF540001,0x7FC0008,0x7FC0008,0x7FC0008,0xB1500001,0xB1500001,
-0xAF500001,0x85FC0008,0x85FC0008,0xAF440000,0xAC000008,0x7FC0008,0x7FC0008,0x7FC0008,0xB1500001,0xB1500001,0xAF500001,0x85FC0008,0x85FC0008,0xAF440000,0xAC000008,0x85FC0008,0x85FC0008,0xAF440000,0xAC000008,0xAC000008,0xD7500000,0xD5580001,0x158000A,0xC74C0000,0xB9500000,0xB5500000,0xB3500000,0xB1500001,0xD9480000,0xC14C0000,0x65FC0008,0xAF440000,
-0x65FC0008,0x1640012,0xBF600001,0xB7600001,0xB55C0001,0x15FC0012,0xB9540001,0xB5580000,0x8DFC0012,0xB5440000,0xB0000014,0x15FC0012,0xB9540001,0xB5580000,0x8DFC0012,0xB5440000,0xB0000014,0x8DFC0012,0xB5440000,0xB0000014,0xB0000014,0x15FC0012,0xB9540001,0xB5580000,0x8DFC0012,0xB5440000,0xB0000014,0x8DFC0012,0xB5440000,0xB0000014,0xB0000014,0x8DFC0012,
-0xB5440000,0xB0000014,0xB0000014,0xB0000014,0xFF440000,0x17C0012,0xF9600001,0xCD480000,0xBD4C0001,0xB9480000,0xB54C0000,0xB53C0000,0xF33C0000,0xCB440000,0xB5500001,0xB0000014,0x6FFC0012,0x1500012,0x1500012,0x1500012,0x1500012,0x1500012,0x1500012,0x1500012,0x1500012,0x1500012,0x1500012,0xB54C0001,0xB54C0001,0xB54C0001,0xB54C0001,0xB54C0001,
-0xB54C0001,0xAD4C0001,0xAD4C0001,0xAD4C0001,0xAB480001,0x1F40012,0x1F40012,0x1F40012,0x1F40012,0x1F40012,0x1F40012,0xAF400001,0xAF400001,0xAF400001,0xAB440000,0x7FF80012,0x7FF80012,0x7FF80012,0xAB300000,0xA6000014,0xEF4C0001,0x1500012,0x1500012,0xC74C0001,0xBD4C0001,0xB74C0001,0xB74C0001,0xB34C0001,0xEB400000,0xCD440000,0xB1480000,0xAF400001,
-0x5DF80012,};
-static const uint32_t g_etc1_to_bc7_m6_table22[] = {
-0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x85FC0000,
-0x85FC0000,0x85FC0000,0x85FC0000,0xAC000000,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1700000,0x1700000,0x1700000,0x7FC0000,0x65FC0000,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,
-0x19FC0000,0x8FF80000,0x8FF80000,0x8FF80000,0xB2000000,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x8FF80000,0x8FF80000,0x8FF80000,0xB2000000,0x8FF80000,0x8FF80000,0x8FF80000,0xB2000000,0xB2000000,0x77C0000,0x1640001,0x1640001,0x1A00000,0x1C00000,0x1E80000,0x1E80000,0x45FC0000,0x1A00000,0x1C00000,0x71FC0000,0x8FF80000,
-0x71FC0000,0x16C0001,0x16C0001,0x16C0001,0x16C0001,0x25FC0000,0x25FC0000,0x25FC0000,0x95F80000,0x95F80000,0xB6000000,0x25FC0000,0x25FC0000,0x25FC0000,0x95F80000,0x95F80000,0xB6000000,0x95F80000,0x95F80000,0xB6000000,0xB6000000,0x25FC0000,0x25FC0000,0x25FC0000,0x95F80000,0x95F80000,0xB6000000,0x95F80000,0x95F80000,0xB6000000,0xB6000000,0x95F80000,
-0x95F80000,0xB6000000,0xB6000000,0xB6000000,0x3A80000,0xB840000,0x16C0001,0x3F00000,0x4FFC0000,0x79FC0000,0x87F80000,0x9DFC0000,0x1CC0000,0x25FC0000,0x79FC0000,0xB6000000,0x79FC0000,0x1780001,0x37FC0000,0x9DFC0000,0xBC000000,0x37FC0000,0x9DFC0000,0xBC000000,0x9DFC0000,0xBC000000,0xBC000000,0x37FC0000,0x9DFC0000,0xBC000000,0x9DFC0000,0xBC000000,
-0xBC000000,0x9DFC0000,0xBC000000,0xBC000000,0xBC000000,0x37FC0000,0x9DFC0000,0xBC000000,0x9DFC0000,0xBC000000,0xBC000000,0x9DFC0000,0xBC000000,0xBC000000,0xBC000000,0x9DFC0000,0xBC000000,0xBC000000,0xBC000000,0xBC000000,0x3D80000,0x1940000,0x1940000,0x5DFC0000,0x91FC0000,0xADF40000,0xBC000000,0xBC000000,0x9FC0000,0x73FC0000,0xB9E40000,0xBC000000,
-0x83FC0000,0x168008C,0xD3640033,0xC3640033,0xBD640033,0xCD600024,0xC3600013,0xBF60001A,0xBF600024,0xBB600016,0xB9600026,0xCB5C0034,0xC35C000A,0xBF5C000F,0xC1580013,0xBD580002,0xB95C0016,0xBD5C0034,0xBB58000F,0xB9580019,0xB7580035,0x1FFC0088,0xC7500033,0xBD580033,0xC1500026,0xBD540012,0xB9580026,0xC3440033,0xBD480009,0xB94C0015,0xB7500034,0x91FC0088,
-0xBD340033,0xB93C0026,0xB7300034,0xB4000088,0xF75C0002,0xFB64003E,0xFD68004B,0xD15C0002,0xC55C0002,0xBF5C0002,0xBD5C0002,0xBD580002,0xF3500001,0xD3540001,0xBD580009,0xB94C0015,0x75FC0088,0x1700033,0xCB6C000A,0xC168000A,0xBD68000A,0xC5680013,0xC1640002,0xBD680001,0xBD680013,0xBD640005,0xB9640015,0x29FC0033,0xC35C0009,0xBD60000A,0xC1580012,0xBD580001,
-0xB9600014,0x97F80033,0xBD480008,0xB94C0014,0xB6000034,0x29FC0033,0xC35C0009,0xBD60000A,0xC1580012,0xBD580001,0xB9600014,0x97F80033,0xBD480008,0xB94C0014,0xB6000034,0x97F80033,0xBD480008,0xB94C0014,0xB6000034,0xB6000034,0xF75C0001,0xFD680015,0xFF6C000E,0xD15C0001,0xC55C0001,0xBF5C0001,0xBD5C0001,0xBD580001,0xF3500001,0xCF580001,0xBD580009,0xB94C0014,
-0x7BFC0033,0x1640033,0x1640033,0x1640033,0x1640033,0xC5600012,0xC5600012,0xC5600012,0xBB600012,0xBB600012,0xB7600012,0xC35C0009,0xC35C0009,0xC35C0009,0xBB5C0002,0xBB5C0002,0xB75C0005,0xB9580009,0xB9580009,0xB7580001,0xB5580009,0x15FC0033,0x15FC0033,0x15FC0033,0xBD540012,0xBD540012,0xB7580012,0xBB500009,0xBB500009,0xB7500001,0xB5500009,0x8DFC0033,
-0x8DFC0033,0xB7440012,0xB5380008,0xB2000034,0xEB5C0002,0xF9600016,0x1640033,0xCF5C0001,0xC55C0001,0xBF5C0001,0xBD5C0002,0xBB580002,0xF3500000,0xCD580001,0xBD580008,0xB7500001,0x6FFC0033,0x168000A,0x168000A,0x168000A,0x168000A,0xBD680001,0xBD680001,0xBD680001,0xB9640001,0xB9640001,0xB7640001,0x1FFC0008,0x1FFC0008,0x1FFC0008,0xB9600001,0xB9600001,
-0xB7600001,0x91FC0008,0x91FC0008,0xB7540000,0xB4000008,0x1FFC0008,0x1FFC0008,0x1FFC0008,0xB9600001,0xB9600001,0xB7600001,0x91FC0008,0x91FC0008,0xB7540000,0xB4000008,0x91FC0008,0x91FC0008,0xB7540000,0xB4000008,0xB4000008,0xDF600000,0xDD680001,0x168000A,0xCF5C0000,0xC1600000,0xBD600000,0xBB600000,0xB9600001,0xE1580000,0xC95C0000,0x75FC0008,0xB7540000,
-0x75FC0008,0x1740012,0xC7700001,0xBF700001,0xBD6C0001,0x2FFC0012,0xC1640001,0xBD680000,0x99FC0012,0xBD540000,0xB8000014,0x2FFC0012,0xC1640001,0xBD680000,0x99FC0012,0xBD540000,0xB8000014,0x99FC0012,0xBD540000,0xB8000014,0xB8000014,0x2FFC0012,0xC1640001,0xBD680000,0x99FC0012,0xBD540000,0xB8000014,0x99FC0012,0xBD540000,0xB8000014,0xB8000014,0x99FC0012,
-0xBD540000,0xB8000014,0xB8000014,0xB8000014,0xF15C0001,0x18C0012,0xF1700002,0xD5580000,0xC55C0001,0xC1580000,0xBD5C0000,0xBD4C0000,0xFB4C0000,0xD3540000,0xBD600001,0xB8000014,0x7FF80012,0x1600012,0x1600012,0x1600012,0x1600012,0x1600012,0x1600012,0x1600012,0x1600012,0x1600012,0x1600012,0xBD5C0001,0xBD5C0001,0xBD5C0001,0xBD5C0001,0xBD5C0001,
-0xBD5C0001,0xB55C0001,0xB55C0001,0xB55C0001,0xB3580001,0xFFC0012,0xFFC0012,0xFFC0012,0xFFC0012,0xFFC0012,0xFFC0012,0xB7500001,0xB7500001,0xB7500001,0xB3540000,0x8BF80012,0x8BF80012,0x8BF80012,0xB3400000,0xAE000014,0xF75C0001,0x1600012,0x1600012,0xCF5C0001,0xC55C0001,0xBF5C0001,0xBF5C0001,0xBB5C0001,0xF3500000,0xD5540000,0xB9580000,0xB7500001,
-0x6BFC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table23[] = {
-0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x91FC0000,
-0x91FC0000,0x91FC0000,0x91FC0000,0xB4000000,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x9800000,0x9800000,0x9800000,0x1FFC0000,0x75FC0000,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,
-0x31FC0000,0x9BF80000,0x9BF80000,0x9BF80000,0xBA000000,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x9BF80000,0x9BF80000,0x9BF80000,0xBA000000,0x9BF80000,0x9BF80000,0x9BF80000,0xBA000000,0xBA000000,0xF8C0000,0x1740001,0x1740001,0x1B40000,0x1D40000,0x1FC0000,0x1FC0000,0x59FC0000,0x1B40000,0x1D40000,0x7FFC0000,0x9BF80000,
-0x7FFC0000,0x17C0001,0x17C0001,0x17C0001,0x17C0001,0x3DFC0000,0x3DFC0000,0x3DFC0000,0xA1F80000,0xA1F80000,0xBE000000,0x3DFC0000,0x3DFC0000,0x3DFC0000,0xA1F80000,0xA1F80000,0xBE000000,0xA1F80000,0xA1F80000,0xBE000000,0xBE000000,0x3DFC0000,0x3DFC0000,0x3DFC0000,0xA1F80000,0xA1F80000,0xBE000000,0xA1F80000,0xA1F80000,0xBE000000,0xBE000000,0xA1F80000,
-0xA1F80000,0xBE000000,0xBE000000,0xBE000000,0x1BC0000,0x1980000,0x17C0001,0xFFC0000,0x63FC0000,0x87FC0000,0x95F80000,0xA9F40000,0x1E00000,0x3DFC0000,0x87FC0000,0xBE000000,0x87FC0000,0x1880001,0x4FFC0000,0xA9FC0000,0xC4000000,0x4FFC0000,0xA9FC0000,0xC4000000,0xA9FC0000,0xC4000000,0xC4000000,0x4FFC0000,0xA9FC0000,0xC4000000,0xA9FC0000,0xC4000000,
-0xC4000000,0xA9FC0000,0xC4000000,0xC4000000,0xC4000000,0x4FFC0000,0xA9FC0000,0xC4000000,0xA9FC0000,0xC4000000,0xC4000000,0xA9FC0000,0xC4000000,0xC4000000,0xC4000000,0xA9FC0000,0xC4000000,0xC4000000,0xC4000000,0xC4000000,0x3EC0000,0x1A40000,0x1A40000,0x71FC0000,0x9FF80000,0xB7F40000,0xC4000000,0xC4000000,0x27FC0000,0x85FC0000,0xC1F40000,0xC4000000,
-0x93FC0000,0x178008C,0xDB740033,0xCB740033,0xC5740033,0xD5700024,0xCB700013,0xC770001A,0xC7700024,0xC3700016,0xC1700026,0xD36C0034,0xCB6C000A,0xC76C000F,0xC9680013,0xC5680002,0xC16C0016,0xC56C0034,0xC368000F,0xC1680019,0xBF680035,0x37FC0088,0xCF600033,0xC5680033,0xC9600026,0xC5640012,0xC1680026,0xCB540033,0xC5580009,0xC15C0015,0xBF600034,0x9DFC0088,
-0xC5440033,0xC14C0026,0xBF400034,0xBC000088,0xFF6C0002,0xF374004C,0xF5780054,0xD96C0002,0xCD6C0002,0xC76C0002,0xC56C0002,0xC5680002,0xFB600001,0xDB640001,0xC5680009,0xC15C0015,0x83FC0088,0x1800033,0xD37C000A,0xC978000A,0xC578000A,0xCD780013,0xC9740002,0xC5780001,0xC5780013,0xC5740005,0xC1740015,0x41FC0033,0xCB6C0009,0xC570000A,0xC9680012,0xC5680001,
-0xC1700014,0xA1FC0033,0xC5580008,0xC15C0014,0xBE000034,0x41FC0033,0xCB6C0009,0xC570000A,0xC9680012,0xC5680001,0xC1700014,0xA1FC0033,0xC5580008,0xC15C0014,0xBE000034,0xA1FC0033,0xC5580008,0xC15C0014,0xBE000034,0xBE000034,0xFF6C0001,0xF578001B,0xF77C0013,0xD96C0001,0xCD6C0001,0xC76C0001,0xC56C0001,0xC5680001,0xFB600001,0xD7680001,0xC5680009,0xC15C0014,
-0x89FC0033,0x1740033,0x1740033,0x1740033,0x1740033,0xCD700012,0xCD700012,0xCD700012,0xC3700012,0xC3700012,0xBF700012,0xCB6C0009,0xCB6C0009,0xCB6C0009,0xC36C0002,0xC36C0002,0xBF6C0005,0xC1680009,0xC1680009,0xBF680001,0xBD680009,0x2FFC0033,0x2FFC0033,0x2FFC0033,0xC5640012,0xC5640012,0xBF680012,0xC3600009,0xC3600009,0xBF600001,0xBD600009,0x99FC0033,
-0x99FC0033,0xBF540012,0xBD480008,0xBA000034,0xF36C0002,0xF170001B,0x1740033,0xD76C0001,0xCD6C0001,0xC76C0001,0xC56C0002,0xC3680002,0xFB600000,0xD5680001,0xC5680008,0xBF600001,0x7FF80033,0x178000A,0x178000A,0x178000A,0x178000A,0xC5780001,0xC5780001,0xC5780001,0xC1740001,0xC1740001,0xBF740001,0x37FC0008,0x37FC0008,0x37FC0008,0xC1700001,0xC1700001,
-0xBF700001,0x9DFC0008,0x9DFC0008,0xBF640000,0xBC000008,0x37FC0008,0x37FC0008,0x37FC0008,0xC1700001,0xC1700001,0xBF700001,0x9DFC0008,0x9DFC0008,0xBF640000,0xBC000008,0x9DFC0008,0x9DFC0008,0xBF640000,0xBC000008,0xBC000008,0xE7700000,0xE5780001,0x178000A,0xD76C0000,0xC9700000,0xC5700000,0xC3700000,0xC1700001,0xE9680000,0xD16C0000,0x83FC0008,0xBF640000,
-0x83FC0008,0x1840012,0xCF800001,0xC7800001,0xC57C0001,0x47FC0012,0xC9740001,0xC5780000,0xA5F80012,0xC5640000,0xC0000014,0x47FC0012,0xC9740001,0xC5780000,0xA5F80012,0xC5640000,0xC0000014,0xA5F80012,0xC5640000,0xC0000014,0xC0000014,0x47FC0012,0xC9740001,0xC5780000,0xA5F80012,0xC5640000,0xC0000014,0xA5F80012,0xC5640000,0xC0000014,0xC0000014,0xA5F80012,
-0xC5640000,0xC0000014,0xC0000014,0xC0000014,0xF96C0001,0x79C0012,0xF9800002,0xDD680000,0xCD6C0001,0xC9680000,0xC56C0000,0xC55C0000,0xF9640001,0xDB640000,0xC5700001,0xC0000014,0x8DFC0012,0x1700012,0x1700012,0x1700012,0x1700012,0x1700012,0x1700012,0x1700012,0x1700012,0x1700012,0x1700012,0xC56C0001,0xC56C0001,0xC56C0001,0xC56C0001,0xC56C0001,
-0xC56C0001,0xBD6C0001,0xBD6C0001,0xBD6C0001,0xBB680001,0x29FC0012,0x29FC0012,0x29FC0012,0x29FC0012,0x29FC0012,0x29FC0012,0xBF600001,0xBF600001,0xBF600001,0xBB640000,0x97F80012,0x97F80012,0x97F80012,0xBB500000,0xB6000014,0xFF6C0001,0x1700012,0x1700012,0xD76C0001,0xCD6C0001,0xC76C0001,0xC76C0001,0xC36C0001,0xFB600000,0xDD640000,0xC1680000,0xBF600001,
-0x7BFC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table24[] = {
-0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x9FF80000,
-0x9FF80000,0x9FF80000,0x9FF80000,0xBC000001,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x3940000,0x3940000,0x3940000,0x3BFC0000,0x85FC0000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x4DFC0000,
-0x4DFC0000,0xA7FC0000,0xA7FC0000,0xA7FC0000,0xC2000001,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0xA7FC0000,0xA7FC0000,0xA7FC0000,0xC2000001,0xA7FC0000,0xA7FC0000,0xA7FC0000,0xC2000001,0xC2000001,0x9A00000,0x1880000,0x1880000,0x1C80000,0x1EC0000,0x23FC0000,0x23FC0000,0x6FFC0000,0x1C80000,0x1EC0000,0x91FC0000,0xA7FC0000,
-0x91FC0000,0x1900000,0x1900000,0x1900000,0x1900000,0x59FC0000,0x59FC0000,0x59FC0000,0xADFC0000,0xADFC0000,0xC6000001,0x59FC0000,0x59FC0000,0x59FC0000,0xADFC0000,0xADFC0000,0xC6000001,0xADFC0000,0xADFC0000,0xC6000001,0xC6000001,0x59FC0000,0x59FC0000,0x59FC0000,0xADFC0000,0xADFC0000,0xC6000001,0xADFC0000,0xADFC0000,0xC6000001,0xC6000001,0xADFC0000,
-0xADFC0000,0xC6000001,0xC6000001,0xC6000001,0x1D00000,0xDA80000,0x1900000,0x31FC0000,0x79FC0000,0x99FC0000,0xA3FC0000,0xB5F80000,0x3F40000,0x59FC0000,0x99FC0000,0xC6000001,0x99FC0000,0x19C0000,0x6BFC0000,0xB7F80000,0xCC000001,0x6BFC0000,0xB7F80000,0xCC000001,0xB7F80000,0xCC000001,0xCC000001,0x6BFC0000,0xB7F80000,0xCC000001,0xB7F80000,0xCC000001,
-0xCC000001,0xB7F80000,0xCC000001,0xCC000001,0xCC000001,0x6BFC0000,0xB7F80000,0xCC000001,0xB7F80000,0xCC000001,0xCC000001,0xB7F80000,0xCC000001,0xCC000001,0xCC000001,0xB7F80000,0xCC000001,0xCC000001,0xCC000001,0xCC000001,0x11FC0000,0x1B80000,0x1B80000,0x87FC0000,0xADFC0000,0xC3F00000,0xCC000001,0xCC000001,0x49FC0000,0x97FC0000,0xCBE80000,0xCC000001,
-0xA3FC0000,0x18C0088,0xE1880034,0xD3880034,0xCD880035,0xDD840026,0xD3840015,0xCD840019,0xCF840026,0xCD800016,0xCB800026,0xDF7C0033,0xD57C0009,0xCF80000F,0xD17C0012,0xCD7C0002,0xCB7C0016,0xCF7C0033,0xCD78000F,0xCB78001A,0xC97C0033,0x53FC0088,0xD9700033,0xCD7C0034,0xD3700026,0xCF740013,0xCB780024,0xD3680033,0xCD70000A,0xCB6C0013,0xC9700033,0xABF80088,
-0xCD5C0034,0xCB580024,0xC94C0033,0xC400008C,0xFF800006,0xFD880048,0xFD880058,0xE57C0001,0xD77C0002,0xD17C0002,0xCF7C0002,0xCD7C0002,0xFF740004,0xE1780001,0xCF780009,0xCB6C0013,0x95FC0088,0x1900034,0xDD8C0008,0xD18C0009,0xCD8C0009,0xD9880012,0xD1880001,0xCF880001,0xCF880012,0xCD880005,0xCB880012,0x5BFC0033,0xD3800009,0xCD840009,0xD17C0012,0xCD7C0002,
-0xCB800012,0xAFFC0033,0xCD700009,0xCB6C0012,0xC8000033,0x5BFC0033,0xD3800009,0xCD840009,0xD17C0012,0xCD7C0002,0xCB800012,0xAFFC0033,0xCD700009,0xCB6C0012,0xC8000033,0xAFFC0033,0xCD700009,0xCB6C0012,0xC8000033,0xC8000033,0xFF800002,0xFF8C0018,0xFF8C0018,0xDF800001,0xD77C0002,0xD17C0002,0xCD800002,0xCD780002,0xFB780003,0xDD7C0001,0xCF780008,0xCB6C0012,
-0x9BFC0033,0x1880034,0x1880034,0x1880034,0x1880034,0xD3840014,0xD3840014,0xD3840014,0xCB840014,0xCB840014,0xC7800015,0xD57C0008,0xD57C0008,0xD57C0008,0xCD7C0001,0xCD7C0001,0xC97C0005,0xC97C000A,0xC97C000A,0xC77C0001,0xC57C000A,0x49FC0033,0x49FC0033,0x49FC0033,0xCF740012,0xCF740012,0xC77C0013,0xCD700009,0xCD700009,0xC7740002,0xC574000A,0xA7F80033,
-0xA7F80033,0xC7680013,0xC560000A,0xC2000033,0xF9800004,0xFB840018,0x1880034,0xE37C0001,0xD77C0001,0xD17C0001,0xCF7C0001,0xCB7C0001,0xFF740000,0xE1780000,0xCD7C0009,0xC7740002,0x8FFC0033,0x18C0008,0x18C0008,0x18C0008,0x18C0008,0xCF880000,0xCF880000,0xCF880000,0xC9880001,0xC9880001,0xC7880001,0x53FC0008,0x53FC0008,0x53FC0008,0xC9840001,0xC9840001,
-0xC7840001,0xABF80008,0xABF80008,0xC77C0001,0xC400000A,0x53FC0008,0x53FC0008,0x53FC0008,0xC9840001,0xC9840001,0xC7840001,0xABF80008,0xABF80008,0xC77C0001,0xC400000A,0xABF80008,0xABF80008,0xC77C0001,0xC400000A,0xC400000A,0xF9800000,0xFD880000,0x18C0008,0xDD800000,0xD3800000,0xCF800000,0xCB840001,0xCB800000,0xF5780000,0xDB7C0000,0x95FC0008,0xC77C0001,
-0x95FC0008,0x1940014,0xD9900000,0xD1900000,0xCD900001,0x63FC0012,0xD1880001,0xCD8C0001,0xB3F80012,0xCD7C0001,0xCA000012,0x63FC0012,0xD1880001,0xCD8C0001,0xB3F80012,0xCD7C0001,0xCA000012,0xB3F80012,0xCD7C0001,0xCA000012,0xCA000012,0x63FC0012,0xD1880001,0xCD8C0001,0xB3F80012,0xCD7C0001,0xCA000012,0xB3F80012,0xCD7C0001,0xCA000012,0xCA000012,0xB3F80012,
-0xCD7C0001,0xCA000012,0xCA000012,0xCA000012,0xF7840002,0x1B00012,0xF3940005,0xE57C0000,0xD77C0001,0xD3780000,0xCD800001,0xCD740001,0xF57C0002,0xE5740000,0xCF800000,0xCA000012,0x9FF80012,0x1800014,0x1800014,0x1800014,0x1800014,0x1800014,0x1800014,0x1800014,0x1800014,0x1800014,0x1800014,0xCF7C0000,0xCF7C0000,0xCF7C0000,0xCF7C0000,0xCF7C0000,
-0xCF7C0000,0xC77C0000,0xC77C0000,0xC77C0000,0xC37C0001,0x43FC0012,0x43FC0012,0x43FC0012,0x43FC0012,0x43FC0012,0x43FC0012,0xC7740001,0xC7740001,0xC7740001,0xC3780001,0xA3FC0012,0xA3FC0012,0xA3FC0012,0xC3680001,0xC0000012,0xF77C0004,0x1800014,0x1800014,0xE77C0000,0xDB7C0000,0xD37C0000,0xD37C0000,0xCD7C0000,0xFF740000,0xE1780000,0xC97C0001,0xC7740001,
-0x8BFC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table25[] = {
-0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0xABF80000,
-0xABF80000,0xABF80000,0xABF80000,0xC4000001,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0xBA40000,0xBA40000,0xBA40000,0x53FC0000,0x95FC0000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x65FC0000,0x65FC0000,0x65FC0000,0x65FC0000,0x65FC0000,
-0x65FC0000,0xB3FC0000,0xB3FC0000,0xB3FC0000,0xCA000001,0x65FC0000,0x65FC0000,0x65FC0000,0x65FC0000,0x65FC0000,0x65FC0000,0xB3FC0000,0xB3FC0000,0xB3FC0000,0xCA000001,0xB3FC0000,0xB3FC0000,0xB3FC0000,0xCA000001,0xCA000001,0x1B40000,0x1980000,0x1980000,0x5D80000,0x7FC0000,0x41FC0000,0x41FC0000,0x83FC0000,0x5D80000,0x7FC0000,0x9FFC0000,0xB3FC0000,
-0x9FFC0000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x71FC0000,0x71FC0000,0x71FC0000,0xB9FC0000,0xB9FC0000,0xCE000001,0x71FC0000,0x71FC0000,0x71FC0000,0xB9FC0000,0xB9FC0000,0xCE000001,0xB9FC0000,0xB9FC0000,0xCE000001,0xCE000001,0x71FC0000,0x71FC0000,0x71FC0000,0xB9FC0000,0xB9FC0000,0xCE000001,0xB9FC0000,0xB9FC0000,0xCE000001,0xCE000001,0xB9FC0000,
-0xB9FC0000,0xCE000001,0xCE000001,0xCE000001,0x1E40000,0x1BC0000,0x1A00000,0x4FFC0000,0x8DFC0000,0xA7FC0000,0xB1FC0000,0xBFFC0000,0x1BFC0000,0x71FC0000,0xA7FC0000,0xCE000001,0xA7FC0000,0x1AC0000,0x83FC0000,0xC3F80000,0xD4000001,0x83FC0000,0xC3F80000,0xD4000001,0xC3F80000,0xD4000001,0xD4000001,0x83FC0000,0xC3F80000,0xD4000001,0xC3F80000,0xD4000001,
-0xD4000001,0xC3F80000,0xD4000001,0xD4000001,0xD4000001,0x83FC0000,0xC3F80000,0xD4000001,0xC3F80000,0xD4000001,0xD4000001,0xC3F80000,0xD4000001,0xD4000001,0xD4000001,0xC3F80000,0xD4000001,0xD4000001,0xD4000001,0xD4000001,0x37FC0000,0x1C80000,0x1C80000,0x9BFC0000,0xBBFC0000,0xCDF00000,0xD4000001,0xD4000001,0x67FC0000,0xA9FC0000,0xD3F80000,0xD4000001,
-0xB3FC0000,0x19C0088,0xE9980034,0xDB980034,0xD5980035,0xE5940026,0xDB940015,0xD5940019,0xD7940026,0xD5900016,0xD3900026,0xE78C0033,0xDD8C0009,0xD790000F,0xD98C0012,0xD58C0002,0xD38C0016,0xD78C0033,0xD588000F,0xD388001A,0xD18C0033,0x6BFC0088,0xE1800033,0xD58C0034,0xDB800026,0xD7840013,0xD3880024,0xDB780033,0xD580000A,0xD37C0013,0xD1800033,0xB7F80088,
-0xD56C0034,0xD3680024,0xD15C0033,0xCC00008C,0xFF90000E,0xF5980056,0xF79C0061,0xED8C0001,0xDF8C0002,0xD98C0002,0xD78C0002,0xD58C0002,0xFF880008,0xE9880001,0xD7880009,0xD37C0013,0xA3FC0088,0x1A00034,0xE59C0008,0xD99C0009,0xD59C0009,0xE1980012,0xD9980001,0xD7980001,0xD7980012,0xD5980005,0xD3980012,0x75FC0033,0xDB900009,0xD5940009,0xD98C0012,0xD58C0002,
-0xD3900012,0xBBFC0033,0xD5800009,0xD37C0012,0xD0000033,0x75FC0033,0xDB900009,0xD5940009,0xD98C0012,0xD58C0002,0xD3900012,0xBBFC0033,0xD5800009,0xD37C0012,0xD0000033,0xBBFC0033,0xD5800009,0xD37C0012,0xD0000033,0xD0000033,0xFF940003,0xF79C001E,0xF9A00019,0xE7900001,0xDF8C0002,0xD98C0002,0xD5900002,0xD5880002,0xFF880004,0xE58C0001,0xD7880008,0xD37C0012,
-0xA9FC0033,0x1980034,0x1980034,0x1980034,0x1980034,0xDB940014,0xDB940014,0xDB940014,0xD3940014,0xD3940014,0xCF900015,0xDD8C0008,0xDD8C0008,0xDD8C0008,0xD58C0001,0xD58C0001,0xD18C0005,0xD18C000A,0xD18C000A,0xCF8C0001,0xCD8C000A,0x63FC0033,0x63FC0033,0x63FC0033,0xD7840012,0xD7840012,0xCF8C0013,0xD5800009,0xD5800009,0xCF840002,0xCD84000A,0xB3F80033,
-0xB3F80033,0xCF780013,0xCD70000A,0xCA000033,0xFF900005,0xF394001D,0x1980034,0xEB8C0001,0xDF8C0001,0xD98C0001,0xD78C0001,0xD38C0001,0xFB880002,0xE9880000,0xD58C0009,0xCF840002,0x9FF80033,0x19C0008,0x19C0008,0x19C0008,0x19C0008,0xD7980000,0xD7980000,0xD7980000,0xD1980001,0xD1980001,0xCF980001,0x6BFC0008,0x6BFC0008,0x6BFC0008,0xD1940001,0xD1940001,
-0xCF940001,0xB7F80008,0xB7F80008,0xCF8C0001,0xCC00000A,0x6BFC0008,0x6BFC0008,0x6BFC0008,0xD1940001,0xD1940001,0xCF940001,0xB7F80008,0xB7F80008,0xCF8C0001,0xCC00000A,0xB7F80008,0xB7F80008,0xCF8C0001,0xCC00000A,0xCC00000A,0xEB940001,0xF5980001,0x19C0008,0xE5900000,0xDB900000,0xD7900000,0xD3940001,0xD3900000,0xFD880000,0xE38C0000,0xA3FC0008,0xCF8C0001,
-0xA3FC0008,0x1A40014,0xE1A00000,0xD9A00000,0xD5A00001,0x7BFC0012,0xD9980001,0xD59C0001,0xBFF80012,0xD58C0001,0xD2000012,0x7BFC0012,0xD9980001,0xD59C0001,0xBFF80012,0xD58C0001,0xD2000012,0xBFF80012,0xD58C0001,0xD2000012,0xD2000012,0x7BFC0012,0xD9980001,0xD59C0001,0xBFF80012,0xD58C0001,0xD2000012,0xBFF80012,0xD58C0001,0xD2000012,0xD2000012,0xBFF80012,
-0xD58C0001,0xD2000012,0xD2000012,0xD2000012,0xFF940002,0x9C00012,0xFBA40005,0xED8C0000,0xDF8C0001,0xDB880000,0xD5900001,0xD5840001,0xFD8C0002,0xED840000,0xD7900000,0xD2000012,0xADFC0012,0x1900014,0x1900014,0x1900014,0x1900014,0x1900014,0x1900014,0x1900014,0x1900014,0x1900014,0x1900014,0xD78C0000,0xD78C0000,0xD78C0000,0xD78C0000,0xD78C0000,
-0xD78C0000,0xCF8C0000,0xCF8C0000,0xCF8C0000,0xCB8C0001,0x5BFC0012,0x5BFC0012,0x5BFC0012,0x5BFC0012,0x5BFC0012,0x5BFC0012,0xCF840001,0xCF840001,0xCF840001,0xCB880001,0xAFFC0012,0xAFFC0012,0xAFFC0012,0xCB780001,0xC8000012,0xFF8C0004,0x1900014,0x1900014,0xEF8C0000,0xE38C0000,0xDB8C0000,0xDB8C0000,0xD58C0000,0xFB880001,0xE9880000,0xD18C0001,0xCF840001,
-0x9BFC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table26[] = {
-0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0xB7F80000,
-0xB7F80000,0xB7F80000,0xB7F80000,0xCC000001,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x1B80000,0x1B80000,0x1B80000,0x6BFC0000,0xA3FC0000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x7DFC0000,0x7DFC0000,0x7DFC0000,0x7DFC0000,0x7DFC0000,
-0x7DFC0000,0xBFFC0000,0xBFFC0000,0xBFFC0000,0xD2000001,0x7DFC0000,0x7DFC0000,0x7DFC0000,0x7DFC0000,0x7DFC0000,0x7DFC0000,0xBFFC0000,0xBFFC0000,0xBFFC0000,0xD2000001,0xBFFC0000,0xBFFC0000,0xBFFC0000,0xD2000001,0xD2000001,0x1C40000,0x1A80000,0x1A80000,0x1EC0000,0x2DFC0000,0x5FFC0000,0x5FFC0000,0x97FC0000,0x1EC0000,0x2DFC0000,0xAFFC0000,0xBFFC0000,
-0xAFFC0000,0x1B00000,0x1B00000,0x1B00000,0x1B00000,0x89FC0000,0x89FC0000,0x89FC0000,0xC5FC0000,0xC5FC0000,0xD6000001,0x89FC0000,0x89FC0000,0x89FC0000,0xC5FC0000,0xC5FC0000,0xD6000001,0xC5FC0000,0xC5FC0000,0xD6000001,0xD6000001,0x89FC0000,0x89FC0000,0x89FC0000,0xC5FC0000,0xC5FC0000,0xD6000001,0xC5FC0000,0xC5FC0000,0xD6000001,0xD6000001,0xC5FC0000,
-0xC5FC0000,0xD6000001,0xD6000001,0xD6000001,0x5F40000,0x1CC0000,0x1B00000,0x6FFC0000,0xA1FC0000,0xB7FC0000,0xBFF80000,0xCBF80000,0x41FC0000,0x89FC0000,0xB7FC0000,0xD6000001,0xB7FC0000,0x1BC0000,0x9BFC0000,0xCFF80000,0xDC000001,0x9BFC0000,0xCFF80000,0xDC000001,0xCFF80000,0xDC000001,0xDC000001,0x9BFC0000,0xCFF80000,0xDC000001,0xCFF80000,0xDC000001,
-0xDC000001,0xCFF80000,0xDC000001,0xDC000001,0xDC000001,0x9BFC0000,0xCFF80000,0xDC000001,0xCFF80000,0xDC000001,0xDC000001,0xCFF80000,0xDC000001,0xDC000001,0xDC000001,0xCFF80000,0xDC000001,0xDC000001,0xDC000001,0xDC000001,0x5FFC0000,0x5D80000,0x5D80000,0xAFFC0000,0xC9F80000,0xD7F00000,0xDC000001,0xDC000001,0x85FC0000,0xB9FC0000,0xDDCC0000,0xDC000001,
-0xC1FC0000,0x1AC0088,0xF1A80034,0xE3A80034,0xDDA80035,0xEDA40026,0xE3A40015,0xDDA40019,0xDFA40026,0xDDA00016,0xDBA00026,0xEF9C0033,0xE59C0009,0xDFA0000F,0xE19C0012,0xDD9C0002,0xDB9C0016,0xDF9C0033,0xDD98000F,0xDB98001A,0xD99C0033,0x83FC0088,0xE9900033,0xDD9C0034,0xE3900026,0xDF940013,0xDB980024,0xE3880033,0xDD90000A,0xDB8C0013,0xD9900033,0xC3F80088,
-0xDD7C0034,0xDB780024,0xD96C0033,0xD400008C,0xFFA00016,0xFDA80056,0xFFAC0061,0xF59C0001,0xE79C0002,0xE19C0002,0xDF9C0002,0xDD9C0002,0xFF9C0013,0xF1980001,0xDF980009,0xDB8C0013,0xB3FC0088,0x1B00034,0xEDAC0008,0xE1AC0009,0xDDAC0009,0xE9A80012,0xE1A80001,0xDFA80001,0xDFA80012,0xDDA80005,0xDBA80012,0x8DFC0033,0xE3A00009,0xDDA40009,0xE19C0012,0xDD9C0002,
-0xDBA00012,0xC7FC0033,0xDD900009,0xDB8C0012,0xD8000033,0x8DFC0033,0xE3A00009,0xDDA40009,0xE19C0012,0xDD9C0002,0xDBA00012,0xC7FC0033,0xDD900009,0xDB8C0012,0xD8000033,0xC7FC0033,0xDD900009,0xDB8C0012,0xD8000033,0xD8000033,0xF9A80009,0xFFAC001E,0xF1B00020,0xEFA00001,0xE79C0002,0xE19C0002,0xDDA00002,0xDD980002,0xFDA00009,0xED9C0001,0xDF980008,0xDB8C0012,
-0xB9FC0033,0x1A80034,0x1A80034,0x1A80034,0x1A80034,0xE3A40014,0xE3A40014,0xE3A40014,0xDBA40014,0xDBA40014,0xD7A00015,0xE59C0008,0xE59C0008,0xE59C0008,0xDD9C0001,0xDD9C0001,0xD99C0005,0xD99C000A,0xD99C000A,0xD79C0001,0xD59C000A,0x7BFC0033,0x7BFC0033,0x7BFC0033,0xDF940012,0xDF940012,0xD79C0013,0xDD900009,0xDD900009,0xD7940002,0xD594000A,0xBFF80033,
-0xBFF80033,0xD7880013,0xD580000A,0xD2000033,0xFFA00006,0xFBA4001D,0x1A80034,0xF39C0001,0xE79C0001,0xE19C0001,0xDF9C0001,0xDB9C0001,0xFB980006,0xF1980000,0xDD9C0009,0xD7940002,0xADFC0033,0x1AC0008,0x1AC0008,0x1AC0008,0x1AC0008,0xDFA80000,0xDFA80000,0xDFA80000,0xD9A80001,0xD9A80001,0xD7A80001,0x83FC0008,0x83FC0008,0x83FC0008,0xD9A40001,0xD9A40001,
-0xD7A40001,0xC3F80008,0xC3F80008,0xD79C0001,0xD400000A,0x83FC0008,0x83FC0008,0x83FC0008,0xD9A40001,0xD9A40001,0xD7A40001,0xC3F80008,0xC3F80008,0xD79C0001,0xD400000A,0xC3F80008,0xC3F80008,0xD79C0001,0xD400000A,0xD400000A,0xF3A40001,0xFDA80001,0x1AC0008,0xEDA00000,0xE3A00000,0xDFA00000,0xDBA40001,0xDBA00000,0xF5A00001,0xEB9C0000,0xB3FC0008,0xD79C0001,
-0xB3FC0008,0x1B40014,0xE9B00000,0xE1B00000,0xDDB00001,0x93FC0012,0xE1A80001,0xDDAC0001,0xCBF80012,0xDD9C0001,0xDA000012,0x93FC0012,0xE1A80001,0xDDAC0001,0xCBF80012,0xDD9C0001,0xDA000012,0xCBF80012,0xDD9C0001,0xDA000012,0xDA000012,0x93FC0012,0xE1A80001,0xDDAC0001,0xCBF80012,0xDD9C0001,0xDA000012,0xCBF80012,0xDD9C0001,0xDA000012,0xDA000012,0xCBF80012,
-0xDD9C0001,0xDA000012,0xDA000012,0xDA000012,0xF9A80005,0x1D40012,0xF3B40008,0xF59C0000,0xE79C0001,0xE3980000,0xDDA00001,0xDD940001,0xFBA40005,0xF5940000,0xDFA00000,0xDA000012,0xBDF80012,0x1A00014,0x1A00014,0x1A00014,0x1A00014,0x1A00014,0x1A00014,0x1A00014,0x1A00014,0x1A00014,0x1A00014,0xDF9C0000,0xDF9C0000,0xDF9C0000,0xDF9C0000,0xDF9C0000,
-0xDF9C0000,0xD79C0000,0xD79C0000,0xD79C0000,0xD39C0001,0x75FC0012,0x75FC0012,0x75FC0012,0x75FC0012,0x75FC0012,0x75FC0012,0xD7940001,0xD7940001,0xD7940001,0xD3980001,0xBBFC0012,0xBBFC0012,0xBBFC0012,0xD3880001,0xD0000012,0xF9A00005,0x1A00014,0x1A00014,0xF79C0000,0xEB9C0000,0xE39C0000,0xE39C0000,0xDD9C0000,0xFB980002,0xF1980000,0xD99C0001,0xD7940001,
-0xA9FC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table27[] = {
-0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0xC3F80000,
-0xC3F80000,0xC3F80000,0xC3F80000,0xD4000001,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1C80000,0x1C80000,0x1C80000,0x83FC0000,0xB3FC0000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x95FC0000,0x95FC0000,0x95FC0000,0x95FC0000,0x95FC0000,
-0x95FC0000,0xCBFC0000,0xCBFC0000,0xCBFC0000,0xDA000001,0x95FC0000,0x95FC0000,0x95FC0000,0x95FC0000,0x95FC0000,0x95FC0000,0xCBFC0000,0xCBFC0000,0xCBFC0000,0xDA000001,0xCBFC0000,0xCBFC0000,0xCBFC0000,0xDA000001,0xDA000001,0x3D40000,0x1B80000,0x1B80000,0x9FC0000,0x55FC0000,0x7DFC0000,0x7DFC0000,0xABFC0000,0x9FC0000,0x55FC0000,0xBFF80000,0xCBFC0000,
-0xBFF80000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xD1FC0000,0xD1FC0000,0xDE000001,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xD1FC0000,0xD1FC0000,0xDE000001,0xD1FC0000,0xD1FC0000,0xDE000001,0xDE000001,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xD1FC0000,0xD1FC0000,0xDE000001,0xD1FC0000,0xD1FC0000,0xDE000001,0xDE000001,0xD1FC0000,
-0xD1FC0000,0xDE000001,0xDE000001,0xDE000001,0x27FC0000,0x7DC0000,0x1C00000,0x8DFC0000,0xB3FC0000,0xC5FC0000,0xCBFC0000,0xD5FC0000,0x69FC0000,0xA3FC0000,0xC5FC0000,0xDE000001,0xC5FC0000,0x1CC0000,0xB5FC0000,0xDBF80000,0xE4000001,0xB5FC0000,0xDBF80000,0xE4000001,0xDBF80000,0xE4000001,0xE4000001,0xB5FC0000,0xDBF80000,0xE4000001,0xDBF80000,0xE4000001,
-0xE4000001,0xDBF80000,0xE4000001,0xE4000001,0xE4000001,0xB5FC0000,0xDBF80000,0xE4000001,0xDBF80000,0xE4000001,0xE4000001,0xDBF80000,0xE4000001,0xE4000001,0xE4000001,0xDBF80000,0xE4000001,0xE4000001,0xE4000001,0xE4000001,0x87FC0000,0xDE80000,0xDE80000,0xC3FC0000,0xD5FC0000,0xE1F00000,0xE4000001,0xE4000001,0xA3FC0000,0xCBFC0000,0xE5DC0000,0xE4000001,
-0xD1FC0000,0x1BC0088,0xF9B80034,0xEBB80034,0xE5B80035,0xF5B40026,0xEBB40015,0xE5B40019,0xE7B40026,0xE5B00016,0xE3B00026,0xF7AC0033,0xEDAC0009,0xE7B0000F,0xE9AC0012,0xE5AC0002,0xE3AC0016,0xE7AC0033,0xE5A8000F,0xE3A8001A,0xE1AC0033,0x9BFC0088,0xF1A00033,0xE5AC0034,0xEBA00026,0xE7A40013,0xE3A80024,0xEB980033,0xE5A0000A,0xE39C0013,0xE1A00033,0xCFF80088,
-0xE58C0034,0xE3880024,0xE17C0033,0xDC00008C,0xFFB40021,0xF5B80068,0xF7BC006C,0xFDAC0001,0xEFAC0002,0xE9AC0002,0xE7AC0002,0xE5AC0002,0xFDB00021,0xF9A80001,0xE7A80009,0xE39C0013,0xC1FC0088,0x1C00034,0xF5BC0008,0xE9BC0009,0xE5BC0009,0xF1B80012,0xE9B80001,0xE7B80001,0xE7B80012,0xE5B80005,0xE3B80012,0xA5FC0033,0xEBB00009,0xE5B40009,0xE9AC0012,0xE5AC0002,
-0xE3B00012,0xD3FC0033,0xE5A00009,0xE39C0012,0xE0000033,0xA5FC0033,0xEBB00009,0xE5B40009,0xE9AC0012,0xE5AC0002,0xE3B00012,0xD3FC0033,0xE5A00009,0xE39C0012,0xE0000033,0xD3FC0033,0xE5A00009,0xE39C0012,0xE0000033,0xE0000033,0xFDB8000E,0xF9C00024,0xF9C00020,0xF7B00001,0xEFAC0002,0xE9AC0002,0xE5B00002,0xE5A80002,0xFDB00011,0xF5AC0001,0xE7A80008,0xE39C0012,
-0xC7FC0033,0x1B80034,0x1B80034,0x1B80034,0x1B80034,0xEBB40014,0xEBB40014,0xEBB40014,0xE3B40014,0xE3B40014,0xDFB00015,0xEDAC0008,0xEDAC0008,0xEDAC0008,0xE5AC0001,0xE5AC0001,0xE1AC0005,0xE1AC000A,0xE1AC000A,0xDFAC0001,0xDDAC000A,0x93FC0033,0x93FC0033,0x93FC0033,0xE7A40012,0xE7A40012,0xDFAC0013,0xE5A00009,0xE5A00009,0xDFA40002,0xDDA4000A,0xCBF80033,
-0xCBF80033,0xDF980013,0xDD90000A,0xDA000033,0xF9B00011,0xF3B40024,0x1B80034,0xFBAC0001,0xEFAC0001,0xE9AC0001,0xE7AC0001,0xE3AC0001,0xFBAC0009,0xF9A80000,0xE5AC0009,0xDFA40002,0xBDF80033,0x1BC0008,0x1BC0008,0x1BC0008,0x1BC0008,0xE7B80000,0xE7B80000,0xE7B80000,0xE1B80001,0xE1B80001,0xDFB80001,0x9BFC0008,0x9BFC0008,0x9BFC0008,0xE1B40001,0xE1B40001,
-0xDFB40001,0xCFF80008,0xCFF80008,0xDFAC0001,0xDC00000A,0x9BFC0008,0x9BFC0008,0x9BFC0008,0xE1B40001,0xE1B40001,0xDFB40001,0xCFF80008,0xCFF80008,0xDFAC0001,0xDC00000A,0xCFF80008,0xCFF80008,0xDFAC0001,0xDC00000A,0xDC00000A,0xFBB40001,0xF5B80004,0x1BC0008,0xF5B00000,0xEBB00000,0xE7B00000,0xE3B40001,0xE3B00000,0xFDB00001,0xF3AC0000,0xC1FC0008,0xDFAC0001,
-0xC1FC0008,0x1C40014,0xF1C00000,0xE9C00000,0xE5C00001,0xABFC0012,0xE9B80001,0xE5BC0001,0xD7F80012,0xE5AC0001,0xE2000012,0xABFC0012,0xE9B80001,0xE5BC0001,0xD7F80012,0xE5AC0001,0xE2000012,0xD7F80012,0xE5AC0001,0xE2000012,0xE2000012,0xABFC0012,0xE9B80001,0xE5BC0001,0xD7F80012,0xE5AC0001,0xE2000012,0xD7F80012,0xE5AC0001,0xE2000012,0xE2000012,0xD7F80012,
-0xE5AC0001,0xE2000012,0xE2000012,0xE2000012,0xFBBC0008,0x1E40012,0xFBC40008,0xFDAC0000,0xEFAC0001,0xEBA80000,0xE5B00001,0xE5A40001,0xF3BC0008,0xFDA40000,0xE7B00000,0xE2000012,0xCBFC0012,0x1B00014,0x1B00014,0x1B00014,0x1B00014,0x1B00014,0x1B00014,0x1B00014,0x1B00014,0x1B00014,0x1B00014,0xE7AC0000,0xE7AC0000,0xE7AC0000,0xE7AC0000,0xE7AC0000,
-0xE7AC0000,0xDFAC0000,0xDFAC0000,0xDFAC0000,0xDBAC0001,0x8DFC0012,0x8DFC0012,0x8DFC0012,0x8DFC0012,0x8DFC0012,0x8DFC0012,0xDFA40001,0xDFA40001,0xDFA40001,0xDBA80001,0xC7FC0012,0xC7FC0012,0xC7FC0012,0xDB980001,0xD8000012,0xF1B00008,0x1B00014,0x1B00014,0xFFAC0000,0xF3AC0000,0xEBAC0000,0xEBAC0000,0xE5AC0000,0xF7AC0005,0xF9A80000,0xE1AC0001,0xDFA40001,
-0xB9FC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table28[] = {
-0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0xD1F80000,
-0xD1F80000,0xD1F80000,0xD1F80000,0xDE000000,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1DC0000,0x1DC0000,0x1DC0000,0x9FFC0000,0xC3FC0000,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xB1FC0000,
-0xB1FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xE4000000,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xE4000000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xE4000000,0xE4000000,0x1E80000,0x1C80001,0x1C80001,0x49FC0000,0x81FC0000,0x9FFC0000,0x9FFC0000,0xC1FC0000,0x49FC0000,0x81FC0000,0xCFFC0000,0xD9FC0000,
-0xCFFC0000,0x1D00001,0x1D00001,0x1D00001,0x1D00001,0xBDFC0000,0xBDFC0000,0xBDFC0000,0xDFF80000,0xDFF80000,0xE8000000,0xBDFC0000,0xBDFC0000,0xBDFC0000,0xDFF80000,0xDFF80000,0xE8000000,0xDFF80000,0xDFF80000,0xE8000000,0xE8000000,0xBDFC0000,0xBDFC0000,0xBDFC0000,0xDFF80000,0xDFF80000,0xE8000000,0xDFF80000,0xDFF80000,0xE8000000,0xE8000000,0xDFF80000,
-0xDFF80000,0xE8000000,0xE8000000,0xE8000000,0x67FC0000,0x1F00000,0x1D00001,0xAFFC0000,0xCBFC0000,0xD7FC0000,0xDBFC0000,0xE1FC0000,0x95FC0000,0xBDFC0000,0xD7FC0000,0xE8000000,0xD7FC0000,0x1DC0001,0xCFFC0000,0xE7FC0000,0xEE000000,0xCFFC0000,0xE7FC0000,0xEE000000,0xE7FC0000,0xEE000000,0xEE000000,0xCFFC0000,0xE7FC0000,0xEE000000,0xE7FC0000,0xEE000000,
-0xEE000000,0xE7FC0000,0xEE000000,0xEE000000,0xEE000000,0xCFFC0000,0xE7FC0000,0xEE000000,0xE7FC0000,0xEE000000,0xEE000000,0xE7FC0000,0xEE000000,0xEE000000,0xEE000000,0xE7FC0000,0xEE000000,0xEE000000,0xEE000000,0xEE000000,0xB3FC0000,0x7FC0000,0x7FC0000,0xD9FC0000,0xE5FC0000,0xEBFC0000,0xEE000000,0xEE000000,0xC5FC0000,0xDDFC0000,0xEFD00000,0xEE000000,
-0xE1FC0000,0x1CC008C,0xFFC80037,0xF5C80033,0xEFC80033,0xFFC40024,0xF5C40013,0xF1C4001A,0xF1C40024,0xEDC40016,0xEBC40026,0xFDC00034,0xF5C0000A,0xF1C0000F,0xF3BC0013,0xEFBC0002,0xEBC00016,0xEFC00034,0xEDBC000F,0xEBBC0019,0xE9BC0035,0xB7FC0088,0xF9B40033,0xEFBC0033,0xF3B40026,0xEFB80012,0xEBBC0026,0xF5A80033,0xEFAC0009,0xEBB00015,0xE9B40034,0xDDF40088,
-0xEF980033,0xEBA00026,0xE9940034,0xE6000088,0xFDC8003F,0xFFCC0064,0xFFCC006C,0xFFC00007,0xF7C00002,0xF1C00002,0xEFC00002,0xEFBC0002,0xFFC40034,0xFFBC0005,0xEFBC0009,0xEBB00015,0xD3FC0088,0x1D40033,0xFDD0000A,0xF3CC000A,0xEFCC000A,0xF7CC0013,0xF3C80002,0xEFCC0001,0xEFCC0013,0xEFC80005,0xEBC80015,0xC1FC0033,0xF5C00009,0xEFC4000A,0xF3BC0012,0xEFBC0001,
-0xEBC40014,0xE1F80033,0xEFAC0008,0xEBB00014,0xE8000034,0xC1FC0033,0xF5C00009,0xEFC4000A,0xF3BC0012,0xEFBC0001,0xEBC40014,0xE1F80033,0xEFAC0008,0xEBB00014,0xE8000034,0xE1F80033,0xEFAC0008,0xEBB00014,0xE8000034,0xE8000034,0xFDCC0014,0xF1D0002D,0xF3D4002A,0xFFC40003,0xF7C00001,0xF1C00001,0xEFC00001,0xEFBC0001,0xF7CC0019,0xFFC00002,0xEFBC0009,0xEBB00014,
-0xD9FC0033,0x1C80033,0x1C80033,0x1C80033,0x1C80033,0xF7C40012,0xF7C40012,0xF7C40012,0xEDC40012,0xEDC40012,0xE9C40012,0xF5C00009,0xF5C00009,0xF5C00009,0xEDC00002,0xEDC00002,0xE9C00005,0xEBBC0009,0xEBBC0009,0xE9BC0001,0xE7BC0009,0xAFFC0033,0xAFFC0033,0xAFFC0033,0xEFB80012,0xEFB80012,0xE9BC0012,0xEDB40009,0xEDB40009,0xE9B40001,0xE7B40009,0xD7FC0033,
-0xD7FC0033,0xE9A80012,0xE79C0008,0xE4000034,0xFBC40013,0xFDC80023,0x1C80033,0xFDC00003,0xF7C00001,0xF1C00001,0xEFC00002,0xEDBC0002,0xFDC00013,0xFFBC0001,0xEFBC0008,0xE9B40001,0xCDFC0033,0x1CC000A,0x1CC000A,0x1CC000A,0x1CC000A,0xEFCC0001,0xEFCC0001,0xEFCC0001,0xEBC80001,0xEBC80001,0xE9C80001,0xB7FC0008,0xB7FC0008,0xB7FC0008,0xEBC40001,0xEBC40001,
-0xE9C40001,0xDDF40008,0xDDF40008,0xE9B80000,0xE6000008,0xB7FC0008,0xB7FC0008,0xB7FC0008,0xEBC40001,0xEBC40001,0xE9C40001,0xDDF40008,0xDDF40008,0xE9B80000,0xE6000008,0xDDF40008,0xDDF40008,0xE9B80000,0xE6000008,0xE6000008,0xFDC80002,0xFFCC0002,0x1CC000A,0xF5C80001,0xF3C40000,0xEFC40000,0xEDC40000,0xEBC40001,0xFFC40002,0xFBC00000,0xD3FC0008,0xE9B80000,
-0xD3FC0008,0x1D80012,0xF9D40001,0xF1D40001,0xEFD00001,0xC7FC0012,0xF3C80001,0xEFCC0000,0xE3FC0012,0xEFB80000,0xEA000014,0xC7FC0012,0xF3C80001,0xEFCC0000,0xE3FC0012,0xEFB80000,0xEA000014,0xE3FC0012,0xEFB80000,0xEA000014,0xEA000014,0xC7FC0012,0xF3C80001,0xEFCC0000,0xE3FC0012,0xEFB80000,0xEA000014,0xE3FC0012,0xEFB80000,0xEA000014,0xEA000014,0xE3FC0012,
-0xEFB80000,0xEA000014,0xEA000014,0xEA000014,0xFFD00008,0x1F80012,0xF5D8000D,0xFFC40002,0xF7C00001,0xF3BC0000,0xEFC00000,0xEFB00000,0xF9D00008,0xFFC00001,0xEFC40001,0xEA000014,0xDDF80012,0x1C40012,0x1C40012,0x1C40012,0x1C40012,0x1C40012,0x1C40012,0x1C40012,0x1C40012,0x1C40012,0x1C40012,0xEFC00001,0xEFC00001,0xEFC00001,0xEFC00001,0xEFC00001,
-0xEFC00001,0xE7C00001,0xE7C00001,0xE7C00001,0xE5BC0001,0xA9FC0012,0xA9FC0012,0xA9FC0012,0xA9FC0012,0xA9FC0012,0xA9FC0012,0xE9B40001,0xE9B40001,0xE9B40001,0xE5B80000,0xD5F80012,0xD5F80012,0xD5F80012,0xE5A40000,0xE0000014,0xF9C0000A,0x1C40012,0x1C40012,0xF9C00002,0xF7C00001,0xF1C00001,0xF1C00001,0xEDC00001,0xFFBC0005,0xFFBC0001,0xEBBC0000,0xE9B40001,
-0xC9FC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table29[] = {
-0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xDDF40000,
-0xDDF40000,0xDDF40000,0xDDF40000,0xE6000000,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1EC0000,0x1EC0000,0x1EC0000,0xB7FC0000,0xD3FC0000,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xC9FC0000,
-0xC9FC0000,0xE5F80000,0xE5F80000,0xE5F80000,0xEC000000,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xE5F80000,0xE5F80000,0xE5F80000,0xEC000000,0xE5F80000,0xE5F80000,0xE5F80000,0xEC000000,0xEC000000,0x5F80000,0x1D80001,0x1D80001,0x83FC0000,0xA9FC0000,0xBDFC0000,0xBDFC0000,0xD3FC0000,0x83FC0000,0xA9FC0000,0xDFF80000,0xE5F80000,
-0xDFF80000,0x1E00001,0x1E00001,0x1E00001,0x1E00001,0xD5FC0000,0xD5FC0000,0xD5FC0000,0xEBF80000,0xEBF80000,0xF0000000,0xD5FC0000,0xD5FC0000,0xD5FC0000,0xEBF80000,0xEBF80000,0xF0000000,0xEBF80000,0xEBF80000,0xF0000000,0xF0000000,0xD5FC0000,0xD5FC0000,0xD5FC0000,0xEBF80000,0xEBF80000,0xF0000000,0xEBF80000,0xEBF80000,0xF0000000,0xF0000000,0xEBF80000,
-0xEBF80000,0xF0000000,0xF0000000,0xF0000000,0x9FFC0000,0x27FC0000,0x1E00001,0xCDFC0000,0xDDFC0000,0xE5FC0000,0xE9F80000,0xEDF80000,0xBDFC0000,0xD5FC0000,0xE5FC0000,0xF0000000,0xE5FC0000,0x1EC0001,0xE9FC0000,0xF3FC0000,0xF6000000,0xE9FC0000,0xF3FC0000,0xF6000000,0xF3FC0000,0xF6000000,0xF6000000,0xE9FC0000,0xF3FC0000,0xF6000000,0xF3FC0000,0xF6000000,
-0xF6000000,0xF3FC0000,0xF6000000,0xF6000000,0xF6000000,0xE9FC0000,0xF3FC0000,0xF6000000,0xF3FC0000,0xF6000000,0xF6000000,0xF3FC0000,0xF6000000,0xF6000000,0xF6000000,0xF3FC0000,0xF6000000,0xF6000000,0xF6000000,0xF6000000,0xDBFC0000,0x87FC0000,0x87FC0000,0xEDFC0000,0xF3F80000,0xF5FC0000,0xF6000000,0xF6000000,0xE3FC0000,0xEFFC0000,0xF7E00000,0xF6000000,
-0xF1FC0000,0x1DC008C,0xFFDC0044,0xFDD80033,0xF7D80033,0xFDD80034,0xFDD40013,0xF9D4001A,0xF9D40024,0xF5D40016,0xF3D40026,0xFFD0003C,0xFDD0000A,0xF9D0000F,0xFBCC0013,0xF7CC0002,0xF3D00016,0xF7D00034,0xF5CC000F,0xF3CC0019,0xF1CC0035,0xCFFC0088,0xFFC80035,0xF7CC0033,0xFBC40026,0xF7C80012,0xF3CC0026,0xFDB80033,0xF7BC0009,0xF3C00015,0xF1C40034,0xE7FC0088,
-0xF7A80033,0xF3B00026,0xF1A40034,0xEE000088,0xFFD8004E,0xF7DC0076,0xF7DC007B,0xFFD4001A,0xFFD00002,0xF9D00002,0xF7D00002,0xF7CC0002,0xFFD4004A,0xFFD00015,0xF7CC0009,0xF3C00015,0xE1FC0088,0x1E40033,0xFFE0000E,0xFBDC000A,0xF7DC000A,0xFFDC0013,0xFBD80002,0xF7DC0001,0xF7DC0013,0xF7D80005,0xF3D80015,0xD9FC0033,0xFDD00009,0xF7D4000A,0xFBCC0012,0xF7CC0001,
-0xF3D40014,0xEDF80033,0xF7BC0008,0xF3C00014,0xF0000034,0xD9FC0033,0xFDD00009,0xF7D4000A,0xFBCC0012,0xF7CC0001,0xF3D40014,0xEDF80033,0xF7BC0008,0xF3C00014,0xF0000034,0xEDF80033,0xF7BC0008,0xF3C00014,0xF0000034,0xF0000034,0xFDE00021,0xF9E0002D,0xFBE4002A,0xFFD8000D,0xFFD00001,0xF9D00001,0xF7D00001,0xF7CC0001,0xFFDC0019,0xFFD4000A,0xF7CC0009,0xF3C00014,
-0xE7FC0033,0x1D80033,0x1D80033,0x1D80033,0x1D80033,0xFFD40012,0xFFD40012,0xFFD40012,0xF5D40012,0xF5D40012,0xF1D40012,0xFDD00009,0xFDD00009,0xFDD00009,0xF5D00002,0xF5D00002,0xF1D00005,0xF3CC0009,0xF3CC0009,0xF1CC0001,0xEFCC0009,0xC7FC0033,0xC7FC0033,0xC7FC0033,0xF7C80012,0xF7C80012,0xF1CC0012,0xF5C40009,0xF5C40009,0xF1C40001,0xEFC40009,0xE3FC0033,
-0xE3FC0033,0xF1B80012,0xEFAC0008,0xEC000034,0xFDD4001D,0xF5D8002A,0x1D80033,0xFFD4000A,0xFFD00001,0xF9D00001,0xF7D00002,0xF5CC0002,0xFFD00018,0xFFD00005,0xF7CC0008,0xF1C40001,0xDDF80033,0x1DC000A,0x1DC000A,0x1DC000A,0x1DC000A,0xF7DC0001,0xF7DC0001,0xF7DC0001,0xF3D80001,0xF3D80001,0xF1D80001,0xCFFC0008,0xCFFC0008,0xCFFC0008,0xF3D40001,0xF3D40001,
-0xF1D40001,0xE7FC0008,0xE7FC0008,0xF1C80000,0xEE000008,0xCFFC0008,0xCFFC0008,0xCFFC0008,0xF3D40001,0xF3D40001,0xF1D40001,0xE7FC0008,0xE7FC0008,0xF1C80000,0xEE000008,0xE7FC0008,0xE7FC0008,0xF1C80000,0xEE000008,0xEE000008,0xFFD80004,0xF7DC0005,0x1DC000A,0xFDD80001,0xFBD40000,0xF7D40000,0xF5D40000,0xF3D40001,0xF1DC0005,0xFBD40001,0xE1FC0008,0xF1C80000,
-0xE1FC0008,0x1E80012,0xFDE40002,0xF9E40001,0xF7E00001,0xDFFC0012,0xFBD80001,0xF7DC0000,0xEFFC0012,0xF7C80000,0xF2000014,0xDFFC0012,0xFBD80001,0xF7DC0000,0xEFFC0012,0xF7C80000,0xF2000014,0xEFFC0012,0xF7C80000,0xF2000014,0xF2000014,0xDFFC0012,0xFBD80001,0xF7DC0000,0xEFFC0012,0xF7C80000,0xF2000014,0xEFFC0012,0xF7C80000,0xF2000014,0xF2000014,0xEFFC0012,
-0xF7C80000,0xF2000014,0xF2000014,0xF2000014,0xF7E8000D,0x57FC0012,0xFDE8000D,0xFDE00008,0xFFD00001,0xFBCC0000,0xF7D00000,0xF7C00000,0xF9E4000D,0xFFD80005,0xF7D40001,0xF2000014,0xEBFC0012,0x1D40012,0x1D40012,0x1D40012,0x1D40012,0x1D40012,0x1D40012,0x1D40012,0x1D40012,0x1D40012,0x1D40012,0xF7D00001,0xF7D00001,0xF7D00001,0xF7D00001,0xF7D00001,
-0xF7D00001,0xEFD00001,0xEFD00001,0xEFD00001,0xEDCC0001,0xC1FC0012,0xC1FC0012,0xC1FC0012,0xC1FC0012,0xC1FC0012,0xC1FC0012,0xF1C40001,0xF1C40001,0xF1C40001,0xEDC80000,0xE1F80012,0xE1F80012,0xE1F80012,0xEDB40000,0xE8000014,0xF3D4000D,0x1D40012,0x1D40012,0xFBD00005,0xFFD00001,0xF9D00001,0xF9D00001,0xF5D00001,0xFBD00008,0xFDCC0004,0xF3CC0000,0xF1C40001,
-0xD9FC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table30[] = {
-0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xE7FC0000,
-0xE7FC0000,0xE7FC0000,0xE7FC0000,0xEE000000,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0x7FC0000,0x7FC0000,0x7FC0000,0xCFFC0000,0xE1FC0000,0x1E80001,0x1E80001,0x1E80001,0x1E80001,0x1E80001,0x1E80001,0x1E80001,0x1E80001,0x1E80001,0x1E80001,0xE3FC0000,0xE3FC0000,0xE3FC0000,0xE3FC0000,0xE3FC0000,
-0xE3FC0000,0xF1F80000,0xF1F80000,0xF1F80000,0xF4000000,0xE3FC0000,0xE3FC0000,0xE3FC0000,0xE3FC0000,0xE3FC0000,0xE3FC0000,0xF1F80000,0xF1F80000,0xF1F80000,0xF4000000,0xF1F80000,0xF1F80000,0xF1F80000,0xF4000000,0xF4000000,0x67FC0000,0x1E80001,0x1E80001,0xBBFC0000,0xD1FC0000,0xDBFC0000,0xDBFC0000,0xE7FC0000,0xBBFC0000,0xD1FC0000,0xEDFC0000,0xF1F80000,
-0xEDFC0000,0x1F00001,0x1F00001,0x1F00001,0x1F00001,0xEFFC0000,0xEFFC0000,0xEFFC0000,0xF7F80000,0xF7F80000,0xF8000000,0xEFFC0000,0xEFFC0000,0xEFFC0000,0xF7F80000,0xF7F80000,0xF8000000,0xF7F80000,0xF7F80000,0xF8000000,0xF8000000,0xEFFC0000,0xEFFC0000,0xEFFC0000,0xF7F80000,0xF7F80000,0xF8000000,0xF7F80000,0xF7F80000,0xF8000000,0xF8000000,0xF7F80000,
-0xF7F80000,0xF8000000,0xF8000000,0xF8000000,0xD7FC0000,0xA7FC0000,0x1F00001,0xEBFC0000,0xF1FC0000,0xF5FC0000,0xF5FC0000,0xF7FC0000,0xE3FC0000,0xEFFC0000,0xF5FC0000,0xF8000000,0xF5FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1EC008C,0xFFEC005F,0xFFE80043,0xFFE80033,0xFFE8004C,0xFFE4002B,0xFFE4001B,0xFFE40026,0xFDE40016,0xFBE40026,0xFFE80054,0xFFE40023,0xFFE00011,0xFFE0001B,0xFFDC0002,0xFBE00016,0xFFE00034,0xFDDC000F,0xFBDC0019,0xF9DC0035,0xE9FC0088,0xFFE4004B,0xFFDC0033,0xFFD80036,0xFFD80012,0xFBDC0026,0xFFD8003D,0xFFCC0009,0xFBD00015,0xF9D40034,0xF3FC0088,
-0xFFB80033,0xFBC00026,0xF9B40034,0xF6000088,0xFFEC006A,0xFFEC0076,0xFFEC007B,0xFFE8004F,0xFFE40026,0xFFE0000C,0xFFE00002,0xFFDC0002,0xFDEC006A,0xFFE4004A,0xFFDC0009,0xFBD00015,0xF1FC0088,0x1F40033,0xFDF00023,0xFFF0000E,0xFFEC000A,0xFDF00023,0xFFEC000A,0xFFEC0001,0xFFEC0013,0xFFE80005,0xFBE80015,0xF1FC0033,0xFFEC0019,0xFFE4000A,0xFFE40015,0xFFDC0001,
-0xFBE40014,0xF9F80033,0xFFCC0008,0xFBD00014,0xF8000034,0xF1FC0033,0xFFEC0019,0xFFE4000A,0xFFE40015,0xFFDC0001,0xFBE40014,0xF9F80033,0xFFCC0008,0xFBD00014,0xF8000034,0xF9F80033,0xFFCC0008,0xFBD00014,0xF8000034,0xF8000034,0xFDF4002A,0xF3F40033,0xF3F40033,0xFFEC001E,0xFFE80012,0xFFE40009,0xFFE00001,0xFFDC0001,0xFFF00029,0xFFF00021,0xFFDC0009,0xFBD00014,
-0xF7FC0033,0x1E80033,0x1E80033,0x1E80033,0x1E80033,0xFDE4001B,0xFDE4001B,0xFDE4001B,0xFDE40012,0xFDE40012,0xF9E40012,0xFFE00011,0xFFE00011,0xFFE00011,0xFDE00002,0xFDE00002,0xF9E00005,0xFBDC0009,0xFBDC0009,0xF9DC0001,0xF7DC0009,0xDFFC0033,0xDFFC0033,0xDFFC0033,0xFFD80012,0xFFD80012,0xF9DC0012,0xFDD40009,0xFDD40009,0xF9D40001,0xF7D40009,0xEFFC0033,
-0xEFFC0033,0xF9C80012,0xF7BC0008,0xF4000034,0xFFE80022,0xFDE8002A,0x1E80033,0xFDE4001A,0xFFE4000D,0xFFE00003,0xFFE00002,0xFDDC0002,0xFFE40021,0xFFE00018,0xFFDC0008,0xF9D40001,0xEBFC0033,0x1EC000A,0x1EC000A,0x1EC000A,0x1EC000A,0xFFEC0001,0xFFEC0001,0xFFEC0001,0xFBE80001,0xFBE80001,0xF9E80001,0xE9FC0008,0xE9FC0008,0xE9FC0008,0xFBE40001,0xFBE40001,
-0xF9E40001,0xF3FC0008,0xF3FC0008,0xF9D80000,0xF6000008,0xE9FC0008,0xE9FC0008,0xE9FC0008,0xFBE40001,0xFBE40001,0xF9E40001,0xF3FC0008,0xF3FC0008,0xF9D80000,0xF6000008,0xF3FC0008,0xF3FC0008,0xF9D80000,0xF6000008,0xF6000008,0xFBEC0005,0xFFEC0005,0x1EC000A,0xF9EC0005,0xFDE80002,0xFFE40000,0xFDE40000,0xFBE40001,0xF9EC0005,0xFFE80002,0xF1FC0008,0xF9D80000,
-0xF1FC0008,0x1F80012,0xFFF4000A,0xFFF00005,0xFFF00001,0xF7FC0012,0xFFF00005,0xFFEC0000,0xFBFC0012,0xFFD80000,0xFA000014,0xF7FC0012,0xFFF00005,0xFFEC0000,0xFBFC0012,0xFFD80000,0xFA000014,0xFBFC0012,0xFFD80000,0xFA000014,0xFA000014,0xF7FC0012,0xFFF00005,0xFFEC0000,0xFBFC0012,0xFFD80000,0xFA000014,0xFBFC0012,0xFFD80000,0xFA000014,0xFA000014,0xFBFC0012,
-0xFFD80000,0xFA000014,0xFA000014,0xFA000014,0xFFF8000D,0xD7FC0012,0xF5F80012,0xFFF4000D,0xFDF4000D,0xFFE80005,0xFFE00000,0xFFD00000,0xF5FC0012,0xFFF00011,0xFFE40001,0xFA000014,0xFBFC0012,0x1E40012,0x1E40012,0x1E40012,0x1E40012,0x1E40012,0x1E40012,0x1E40012,0x1E40012,0x1E40012,0x1E40012,0xFFE00001,0xFFE00001,0xFFE00001,0xFFE00001,0xFFE00001,
-0xFFE00001,0xF7E00001,0xF7E00001,0xF7E00001,0xF5DC0001,0xD9FC0012,0xD9FC0012,0xD9FC0012,0xD9FC0012,0xD9FC0012,0xD9FC0012,0xF9D40001,0xF9D40001,0xF9D40001,0xF5D80000,0xEDF80012,0xEDF80012,0xEDF80012,0xF5C40000,0xF0000014,0xFBE4000D,0x1E40012,0x1E40012,0xFBE0000A,0xFDE00005,0xFFE00002,0xFFE00002,0xFDE00001,0xF7E4000D,0xFDE00008,0xFBDC0000,0xF9D40001,
-0xE7FC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table31[] = {
-0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xF3FC0000,
-0xF3FC0000,0xF3FC0000,0xF3FC0000,0xF6000000,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0x87FC0000,0x87FC0000,0x87FC0000,0xE9FC0000,0xF1FC0000,0x1F80001,0x1F80001,0x1F80001,0x1F80001,0x1F80001,0x1F80001,0x1F80001,0x1F80001,0x1F80001,0x1F80001,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xFBFC0000,
-0xFBFC0000,0xFDF80000,0xFDF80000,0xFDF80000,0xFC000000,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xFDF80000,0xFDF80000,0xFDF80000,0xFC000000,0xFDF80000,0xFDF80000,0xFDF80000,0xFC000000,0xFC000000,0xE7FC0000,0x1F80001,0x1F80001,0xF5FC0000,0xF7FC0000,0xF9FC0000,0xF9FC0000,0xFBFC0000,0xF5FC0000,0xF7FC0000,0xFDF80000,0xFDF80000,
-0xFDF80000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1F8002C,0xFFF80027,0xFFF80024,0xFFF80023,0xFFF80022,0xFFF4001F,0xFFF4001B,0xFFF4001A,0xFFF40016,0xFFF40012,0xFFF4001C,0xFFF40017,0xFFF40013,0xFFF00012,0xFFF0000E,0xFFF0000A,0xFFF00009,0xFFF00005,0xFFF00001,0xFFEC0005,0xF7FC002C,0xFDF80027,0xFFF40023,0xFFF0001A,0xFFF00016,0xFFF00012,0xFFF00011,0xFFF0000D,0xFFE40005,0xFFE40005,0xFBFC002C,
-0xFFEC0023,0xFFE00012,0xFFCC0004,0xFC00002C,0xFFF80027,0xF5F8002C,0xF5F8002C,0xFFF80022,0xFFF4001A,0xFFF40012,0xFFF40011,0xFFF00009,0xFFF80022,0xFFF4001F,0xFFF0000B,0xFFE40005,0xFBFC002C,0x1FC0003,0xFDFC0003,0xFFFC0002,0xFFFC0002,0xFDFC0003,0xFFFC0002,0xFFFC0002,0xFFFC0001,0xFFFC0001,0xFFF80001,0xFDFC0003,0xFFFC0002,0xFFFC0002,0xFFFC0001,0xFFF80001,
-0xFFF80000,0xFFF80003,0xFFF80002,0xFFF00000,0xFE000004,0xFDFC0003,0xFFFC0002,0xFFFC0002,0xFFFC0001,0xFFF80001,0xFFF80000,0xFFF80003,0xFFF80002,0xFFF00000,0xFE000004,0xFFF80003,0xFFF80002,0xFFF00000,0xFE000004,0xFE000004,0xFDFC0003,0xF7FC0003,0xF7FC0003,0xFDFC0003,0xFFFC0002,0xFFFC0001,0xFFF80001,0xFFF80001,0xFDFC0003,0xFDFC0003,0xFFF80002,0xFFF00000,
-0xFFF80003,0x1F80023,0x1F80023,0x1F80023,0x1F80023,0xFFF4001B,0xFFF4001B,0xFFF4001B,0xFFF40016,0xFFF40016,0xFFF40012,0xFFF40013,0xFFF40013,0xFFF40013,0xFFF0000E,0xFFF0000E,0xFFF0000A,0xFFF00005,0xFFF00005,0xFFF00001,0xFDEC0005,0xF7FC0023,0xF7FC0023,0xF7FC0023,0xFFF00016,0xFFF00016,0xFFF00012,0xFFF0000D,0xFFF0000D,0xFFE40005,0xFDE80004,0xFBFC0023,
-0xFBFC0023,0xFFE00012,0xFDD40004,0xFA000024,0xFFF40022,0xF5F80023,0x1F80023,0xFFF4001D,0xFFF40016,0xFFF40011,0xFFF40011,0xFFF00009,0xFFF4001D,0xFFF40016,0xFFF0000B,0xFFE40005,0xFBFC0023,0x1FC0002,0x1FC0002,0x1FC0002,0x1FC0002,0xFDFC0002,0xFDFC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFF80001,0xFDFC0002,0xFDFC0002,0xFDFC0002,0xFFF80001,0xFFF80001,
-0xFFF80000,0xFFF80002,0xFFF80002,0xFFF00000,0xFC000004,0xFDFC0002,0xFDFC0002,0xFDFC0002,0xFFF80001,0xFFF80001,0xFFF80000,0xFFF80002,0xFFF80002,0xFFF00000,0xFC000004,0xFFF80002,0xFFF80002,0xFFF00000,0xFC000004,0xFC000004,0xFBFC0002,0xF7FC0002,0x1FC0002,0xFDFC0002,0xFDFC0002,0xFFF80001,0xFFF80001,0xFFF80001,0xFDFC0002,0xFDFC0002,0xFFF80002,0xFFF00000,
-0xFFF80002,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1F40012,0x1F40012,0x1F40012,0x1F40012,0x1F40012,0x1F40012,0x1F40012,0x1F40012,0x1F40012,0x1F40012,0xFDF0000A,0xFDF0000A,0xFDF0000A,0xFDF0000A,0xFDF0000A,
-0xFDF0000A,0xFFF00001,0xFFF00001,0xFFF00001,0xFDEC0001,0xF1FC0012,0xF1FC0012,0xF1FC0012,0xF1FC0012,0xF1FC0012,0xF1FC0012,0xFDEC0005,0xFDEC0005,0xFDEC0005,0xFDE80000,0xF9F80012,0xF9F80012,0xF9F80012,0xFDD40000,0xF8000014,0xF3F40012,0x1F40012,0x1F40012,0xFFF4000D,0xFDF4000D,0xFFF0000A,0xFFF0000A,0xFFF00005,0xFFF4000D,0xFDF4000D,0xFFF00002,0xFDEC0005,
-0xF7FC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table32[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x80001,0x80001,0x80001,0x80001,0x20C0000,0x20C0000,0x20C0000,0x180000,0x180000,0x4000000,0x20C0000,0x20C0000,0x20C0000,0x180000,0x180000,0x4000000,0x180000,0x180000,0x4000000,0x4000000,0x20C0000,0x20C0000,0x20C0000,0x180000,0x180000,0x4000000,0x180000,0x180000,0x4000000,0x4000000,0x180000,
-0x180000,0x4000000,0x4000000,0x4000000,0xC0000,0xC080000,0x80001,0xC0000,0x100000,0x140000,0x140000,0x200000,0xC0000,0x20C0000,0x140000,0x4000000,0x140000,0x200001,0x2300000,0x640000,0x10000000,0x2300000,0x640000,0x10000000,0x640000,0x10000000,0x10000000,0x2300000,0x640000,0x10000000,0x640000,0x10000000,
-0x10000000,0x640000,0x10000000,0x10000000,0x10000000,0x2300000,0x640000,0x10000000,0x640000,0x10000000,0x10000000,0x640000,0x10000000,0x10000000,0x10000000,0x640000,0x10000000,0x10000000,0x10000000,0x10000000,0x2280000,0x240000,0x240000,0x380000,0x500000,0x9C0000,0x10000000,0x10000000,0x22C0000,0x400000,0x1F40000,0x10000000,
-0x480000,0xC00C2,0x2E040011,0x18040011,0x10040011,0x20000048,0x18000009,0x10000001,0x10000048,0xE00001D,0xA000048,0x14000099,0x12000035,0xE00001D,0xC000060,0xC000030,0xA000058,0xA000099,0xA000059,0x8000074,0x6000099,0x1000C2,0x12000059,0xC000031,0xC000070,0xC000040,0x8000062,0x80000A7,0xA000069,0x800007D,0x600009D,0x1800C2,
-0x8000089,0x8000098,0x40000B2,0x40000C2,0x42000029,0xA8000048,0xEA040011,0x1E000029,0x16000032,0xE000032,0xC000022,0xA00003D,0x2C000056,0x1A00003D,0xC00004F,0x800007D,0x1400C2,0x10009A,0x2E04000D,0x1804000D,0x1004000D,0x20000048,0x18000009,0x10000001,0x10000048,0xE00001D,0xA000048,0x140099,0x12000035,0xE00001D,0xC000060,0xC000030,
-0xA000058,0x240099,0xA000059,0x8000074,0x6000099,0x140099,0x12000035,0xE00001D,0xC000060,0xC000030,0xA000058,0x240099,0xA000059,0x8000074,0x6000099,0x240099,0xA000059,0x8000074,0x6000099,0x6000099,0x42000029,0xA8000048,0xEA04000D,0x1E000029,0x16000032,0xE000032,0xC000022,0xA00003D,0x2C00004D,0x1A000039,0xC00004E,0x8000074,
-0x1C0099,0x40011,0x40011,0x40011,0x40011,0xE000000,0xE000000,0xE000000,0x6000000,0x6000000,0x4000000,0x400000D,0x400000D,0x400000D,0x6000004,0x6000004,0x4000004,0x200000D,0x200000D,0x2000008,0x200000D,0x40011,0x40011,0x40011,0x6000008,0x6000008,0x2000006,0x200000E,0x200000E,0x2000009,0x200000E,0x80011,
-0x80011,0x200000C,0x2000011,0x12,0x20000004,0x48000000,0x40011,0x10000004,0x6000005,0x8000004,0x8000004,0x4000005,0xC000009,0xA000006,0x200000D,0x2000009,0x80011,0x4000D,0x4000D,0x4000D,0x4000D,0xE000000,0xE000000,0xE000000,0x6000000,0x6000000,0x4000000,0x4000D,0x4000D,0x4000D,0x6000004,0x6000004,
-0x4000004,0x8000D,0x8000D,0x2000008,0x200000D,0x4000D,0x4000D,0x4000D,0x6000004,0x6000004,0x4000004,0x8000D,0x8000D,0x2000008,0x200000D,0x8000D,0x8000D,0x2000008,0x200000D,0x200000D,0x20000004,0x48000000,0x4000D,0x10000004,0x6000005,0x8000004,0x8000004,0x4000005,0x4040008,0xA000005,0x8000D,0x2000008,
-0x8000D,0x14004A,0x260C0001,0x16080001,0x10080001,0x200048,0x18000009,0x10000001,0x3C0048,0xE00001D,0xA000048,0x200048,0x18000009,0x10000001,0x3C0048,0xE00001D,0xA000048,0x3C0048,0xE00001D,0xA000048,0xA000048,0x200048,0x18000009,0x10000001,0x3C0048,0xE00001D,0xA000048,0x3C0048,0xE00001D,0xA000048,0xA000048,0x3C0048,
-0xE00001D,0xA000048,0xA000048,0xA000048,0x42000019,0x180048,0xAE0C0001,0x1E000019,0x16000019,0x10000019,0xE000014,0xE000028,0x32000022,0x1E00001D,0x10000011,0xA000048,0x2C0048,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table33[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x40001,0x40001,0x40001,0x40001,0x40001,0x40001,0x40001,0x40001,0x40001,0x40001,0x80000,0x80000,0x80000,0x80000,0x80000,
-0x80000,0xC0000,0xC0000,0xC0000,0x2000000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0xC0000,0xC0000,0xC0000,0x2000000,0xC0000,0xC0000,0xC0000,0x2000000,0x2000000,0xA040000,0x40001,0x40001,0x6040000,0x80000,0x80000,0x80000,0x80000,0x6040000,0x80000,0xC0000,0xC0000,
-0xC0000,0x180001,0x180001,0x180001,0x180001,0x2240000,0x2240000,0x2240000,0x4C0000,0x4C0000,0xC000000,0x2240000,0x2240000,0x2240000,0x4C0000,0x4C0000,0xC000000,0x4C0000,0x4C0000,0xC000000,0xC000000,0x2240000,0x2240000,0x2240000,0x4C0000,0x4C0000,0xC000000,0x4C0000,0x4C0000,0xC000000,0xC000000,0x4C0000,
-0x4C0000,0xC000000,0xC000000,0xC000000,0x41C0000,0x1C0000,0x180001,0x240000,0x2C0000,0x340000,0x3C0000,0x5C0000,0x200000,0x2240000,0x340000,0xC000000,0x340000,0x300001,0x480000,0x940000,0x18000000,0x480000,0x940000,0x18000000,0x940000,0x18000000,0x18000000,0x480000,0x940000,0x18000000,0x940000,0x18000000,
-0x18000000,0x940000,0x18000000,0x18000000,0x18000000,0x480000,0x940000,0x18000000,0x940000,0x18000000,0x18000000,0x940000,0x18000000,0x18000000,0x18000000,0x940000,0x18000000,0x18000000,0x18000000,0x18000000,0x23C0000,0x2340000,0x2340000,0x540000,0x780000,0xEC0000,0x18000000,0x18000000,0x440000,0x5C0000,0xBC80000,0x18000000,
-0x680000,0x14017F,0x3E0C005E,0x220C005E,0x180C005E,0x3404004D,0x22040006,0x1804000E,0x1A04004D,0x16000011,0x1204004D,0x2A0000F3,0x22000045,0x18000032,0x18000069,0x14000021,0x12000051,0x140000F3,0x10000084,0x10000090,0xC0000F4,0x1C017F,0x1E0000AE,0x18000072,0x180000A9,0x12000051,0x12000075,0x12000118,0x100000A8,0xE0000B2,0xC000104,0x38017F,
-0x100000FD,0xE0000FD,0xA000139,0xA000181,0x6400001A,0xFA04004F,0xFE0C0067,0x3400001A,0x22000021,0x1A00001A,0x1600000E,0x14000038,0x42000066,0x2C000041,0x1600005C,0xE0000B2,0x28017F,0x1C00F3,0x3A100032,0x20100032,0x18100032,0x30080049,0x22040002,0x18080005,0x1A040049,0x1604000E,0x12040049,0x2800F3,0x22000045,0x18000032,0x18000069,0x14000021,
-0x12000051,0x5000F3,0x10000084,0x10000090,0xC0000F4,0x2800F3,0x22000045,0x18000032,0x18000069,0x14000021,0x12000051,0x5000F3,0x10000084,0x10000090,0xC0000F4,0x5000F3,0x10000084,0x10000090,0xC0000F4,0xC0000F4,0x6400001A,0xEC080049,0xF0100036,0x3400001A,0x22000021,0x1A00001A,0x1600000E,0x14000038,0x50000052,0x2C000038,0x1600005B,0x10000090,
-0x3800F3,0xC005E,0xC005E,0xC005E,0xC005E,0x22040005,0x22040005,0x22040005,0x12040005,0x12040005,0xC040005,0x16000032,0x16000032,0x16000032,0x12000009,0x12000009,0xC000001,0xA000034,0xA000034,0xA000014,0x6000034,0x20C005D,0x20C005D,0x20C005D,0xC000021,0xC000021,0xC000011,0x8000043,0x8000043,0x8000022,0x6000038,0x18005D,
-0x18005D,0x800003D,0x400004D,0x400005D,0x52000005,0xAA040005,0xC005E,0x2C00000A,0x1A000008,0x1600000A,0x12000008,0xC00000D,0x3400001D,0x1C000016,0xE000033,0x8000022,0x14005D,0x100032,0x100032,0x100032,0x100032,0x1E080001,0x1E080001,0x1E080001,0x10080001,0x10080001,0xC040001,0x180032,0x180032,0x180032,0x12000009,0x12000009,
-0xC000001,0x2C0032,0x2C0032,0xA000014,0x6000034,0x180032,0x180032,0x180032,0x12000009,0x12000009,0xC000001,0x2C0032,0x2C0032,0xA000014,0x6000034,0x2C0032,0x2C0032,0xA000014,0x6000034,0x6000034,0x52000005,0x8C080001,0x100032,0x2C00000A,0x1A000008,0x1600000A,0x12000008,0xC00000D,0x34000014,0x1C000012,0x200032,0xA000014,
-0x200032,0x24004A,0x2E1C0001,0x1E180001,0x18180001,0x380048,0x22040001,0x180C0001,0x700048,0x16000008,0x12000048,0x380048,0x22040001,0x180C0001,0x700048,0x16000008,0x12000048,0x700048,0x16000008,0x12000048,0x12000048,0x380048,0x22040001,0x180C0001,0x700048,0x16000008,0x12000048,0x700048,0x16000008,0x12000048,0x12000048,0x700048,
-0x16000008,0x12000048,0x12000048,0x12000048,0x7400000A,0x280048,0xB61C0001,0x38000008,0x2204000D,0x1C000008,0x18000004,0x14000014,0x50000012,0x2E00000D,0x1A000001,0x12000048,0x500048,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,
-0x8000000,0x4000000,0x4000000,0x4000000,0x2000000,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x2000002,0x2000002,0x2000002,0x2000001,0x5,0x5,0x5,0x2000004,0x5,0x28000000,0x40005,0x40005,0x12000000,0xC000000,0xA000000,0xA000000,0x6000000,0x12000001,0xC000001,0x4000000,0x2000002,
-0x5,};
-static const uint32_t g_etc1_to_bc7_m6_table34[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x140001,0x140001,0x140001,0x140001,0x140001,0x140001,0x140001,0x140001,0x140001,0x140001,0x200000,0x200000,0x200000,0x200000,0x200000,
-0x200000,0x3C0000,0x3C0000,0x3C0000,0xA000000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x3C0000,0x3C0000,0x3C0000,0xA000000,0x3C0000,0x3C0000,0x3C0000,0xA000000,0xA000000,0x180000,0x140001,0x140001,0x2180000,0x1C0000,0x1C0000,0x1C0000,0x240000,0x2180000,0x1C0000,0x2C0000,0x3C0000,
-0x2C0000,0x280001,0x280001,0x280001,0x280001,0x23C0000,0x23C0000,0x23C0000,0x7C0000,0x7C0000,0x14000000,0x23C0000,0x23C0000,0x23C0000,0x7C0000,0x7C0000,0x14000000,0x7C0000,0x7C0000,0x14000000,0x14000000,0x23C0000,0x23C0000,0x23C0000,0x7C0000,0x7C0000,0x14000000,0x7C0000,0x7C0000,0x14000000,0x14000000,0x7C0000,
-0x7C0000,0x14000000,0x14000000,0x14000000,0x300000,0x2C0000,0x280001,0x380000,0x440000,0x580000,0x640000,0x980000,0x340000,0x23C0000,0x580000,0x14000000,0x580000,0x400001,0x600000,0xC40000,0x20000000,0x600000,0xC40000,0x20000000,0xC40000,0x20000000,0x20000000,0x600000,0xC40000,0x20000000,0xC40000,0x20000000,
-0x20000000,0xC40000,0x20000000,0x20000000,0x20000000,0x600000,0xC40000,0x20000000,0xC40000,0x20000000,0x20000000,0xC40000,0x20000000,0x20000000,0x20000000,0xC40000,0x20000000,0x20000000,0x20000000,0x20000000,0x4500000,0xA440000,0xA440000,0x26C0000,0xA00000,0x13C0000,0x20000000,0x20000000,0x580000,0x7C0000,0x13D80000,0x20000000,
-0x8C0000,0x200253,0x4E1400DE,0x2A1400DF,0x201400DE,0x440C0085,0x2C0C0042,0x220C005A,0x240C0085,0x1E0C0045,0x1A0C0085,0x420000F3,0x30000032,0x2008004A,0x2600004E,0x20000001,0x1A00004C,0x200000F3,0x1C000054,0x18000074,0x140000F4,0x300253,0x28000106,0x200000DD,0x220000D3,0x1E000069,0x18000099,0x1E000158,0x1A0000AF,0x180000B4,0x14000125,0x5C0253,
-0x16000179,0x16000159,0x100001AD,0x10000255,0x9C000003,0xF01000B1,0xF4180106,0x4E000001,0x36000001,0x28000001,0x20000005,0x1E00000C,0x64000051,0x3E00001D,0x20000042,0x180000B4,0x400253,0x2C00F3,0x42200032,0x28200032,0x20200032,0x38180049,0x2A140002,0x20180005,0x22140049,0x1E14000E,0x1A140049,0x4000F3,0x30000032,0x20100032,0x2404004E,0x20000001,
-0x1A040049,0x8000F3,0x1C000054,0x18000074,0x140000F4,0x4000F3,0x30000032,0x20100032,0x2404004E,0x20000001,0x1A040049,0x8000F3,0x1C000054,0x18000074,0x140000F4,0x8000F3,0x1C000054,0x18000074,0x140000F4,0x140000F4,0x9C000003,0xF4180049,0xF8200036,0x4E000001,0x36000001,0x28000001,0x20080001,0x1E00000C,0x6C000021,0x3E00000D,0x2000003E,0x18000074,
-0x5C00F3,0x1400DE,0x1400DE,0x1400DE,0x1400DE,0x320C003D,0x320C003D,0x320C003D,0x1C0C003D,0x1C0C003D,0x140C003D,0x30000032,0x30000032,0x30000032,0x1E000001,0x1E000001,0x1604000C,0x16000034,0x16000034,0x12000008,0xE000034,0x2000DD,0x2000DD,0x2000DD,0x18000059,0x18000059,0x12000041,0x12000068,0x12000068,0x1200002C,0xE00004D,0x3C00DD,
-0x3C00DD,0xE000089,0xA000095,0xA0000DD,0x98000002,0xEE0C003D,0x1400DE,0x4E000000,0x32000001,0x26000001,0x24000002,0x1A000001,0x56000023,0x36000012,0x1E000036,0x1200002C,0x2C00DD,0x200032,0x200032,0x200032,0x200032,0x26180001,0x26180001,0x26180001,0x18180001,0x18180001,0x14140001,0x300032,0x300032,0x300032,0x1C040001,0x1C040001,
-0x140C0000,0x5C0032,0x5C0032,0x12000008,0xE000034,0x300032,0x300032,0x300032,0x1C040001,0x1C040001,0x140C0000,0x5C0032,0x5C0032,0x12000008,0xE000034,0x5C0032,0x5C0032,0x12000008,0xE000034,0xE000034,0x7A080000,0x94180001,0x200032,0x4E000000,0x2C080001,0x24040000,0x1E080001,0x1A000001,0x5C000008,0x3C000002,0x400032,0x12000008,
-0x400032,0x34004A,0x362C0001,0x26280001,0x20280001,0x500048,0x2A140001,0x201C0001,0xA00048,0x20000001,0x1A000048,0x500048,0x2A140001,0x201C0001,0xA00048,0x20000001,0x1A000048,0xA00048,0x20000001,0x1A000048,0x1A000048,0x500048,0x2A140001,0x201C0001,0xA00048,0x20000001,0x1A000048,0xA00048,0x20000001,0x1A000048,0x1A000048,0xA00048,
-0x20000001,0x1A000048,0x1A000048,0x1A000048,0x9C000002,0x4380048,0xBE2C0001,0x4A040001,0x36000001,0x28000001,0x20080000,0x1E000008,0x72000008,0x46000004,0x220C0000,0x1A000048,0x700048,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,
-0x20000000,0x10000000,0x10000000,0x10000000,0xA000000,0x10003D,0x10003D,0x10003D,0x10003D,0x10003D,0x10003D,0xC000014,0xC000014,0xC000014,0x800000D,0x18003D,0x18003D,0x18003D,0x8000028,0x400003D,0xA8000000,0xC003D,0xC003D,0x4A000000,0x34000000,0x28000000,0x28000000,0x1A000000,0x44000011,0x34000009,0x14000001,0xC000014,
-0x14003D,};
-static const uint32_t g_etc1_to_bc7_m6_table35[] = {
-0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x240000,
-0x240000,0x240000,0x240000,0x6000000,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xE0C0000,0xE0C0000,0xE0C0000,0x140000,0x1C0000,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x380000,0x380000,0x380000,0x380000,0x380000,
-0x380000,0x700000,0x700000,0x700000,0x12000000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x700000,0x700000,0x700000,0x12000000,0x700000,0x700000,0x700000,0x12000000,0x12000000,0x280000,0x240001,0x240001,0x2C0000,0x300000,0x340000,0x340000,0x400000,0x2C0000,0x300000,0x500000,0x700000,
-0x500000,0x380001,0x380001,0x380001,0x380001,0x540000,0x540000,0x540000,0xAC0000,0xAC0000,0x1C000000,0x540000,0x540000,0x540000,0xAC0000,0xAC0000,0x1C000000,0xAC0000,0xAC0000,0x1C000000,0x1C000000,0x540000,0x540000,0x540000,0xAC0000,0xAC0000,0x1C000000,0xAC0000,0xAC0000,0x1C000000,0x1C000000,0xAC0000,
-0xAC0000,0x1C000000,0x1C000000,0x1C000000,0x440000,0x63C0000,0x380001,0x24C0000,0x600000,0x780000,0x8C0000,0xD40000,0x480000,0x540000,0x780000,0x1C000000,0x780000,0x500001,0x780000,0xF40000,0x28000000,0x780000,0xF40000,0x28000000,0xF40000,0x28000000,0x28000000,0x780000,0xF40000,0x28000000,0xF40000,0x28000000,
-0x28000000,0xF40000,0x28000000,0x28000000,0x28000000,0x780000,0xF40000,0x28000000,0xF40000,0x28000000,0x28000000,0xF40000,0x28000000,0x28000000,0x28000000,0xF40000,0x28000000,0x28000000,0x28000000,0x28000000,0x4640000,0x580000,0x580000,0x880000,0xC80000,0x1880000,0x28000000,0x28000000,0x700000,0x980000,0x1BE80000,0x28000000,
-0xAC0000,0x300274,0x562400F3,0x322400F4,0x282400F3,0x4C1C0092,0x341C004F,0x2A1C0067,0x2C1C0092,0x2818004E,0x22180092,0x4A1000F4,0x38100033,0x2A140051,0x300C004A,0x28100002,0x2210004D,0x280C00F4,0x24080053,0x20080069,0x1C0C00F5,0x2440274,0x3A0000F5,0x281000F4,0x2E0000AA,0x28000049,0x22040090,0x2800011F,0x2400005D,0x20000069,0x1C0000FD,0x8C0274,
-0x2000015B,0x1C000120,0x1A000181,0x16000278,0xA4100004,0xF82000C2,0xFC28011F,0x56100002,0x3E100002,0x30100002,0x28100006,0x260C0006,0x90000009,0x54040000,0x2A080035,0x20000069,0x640274,0x3C00F3,0x4A300032,0x30300032,0x28300032,0x40280049,0x32240002,0x28280005,0x2A240049,0x2624000E,0x22240049,0x5800F3,0x38100032,0x28200032,0x300C0049,0x28100001,
-0x22140049,0xB000F3,0x2600003E,0x20000059,0x1C0000F4,0x5800F3,0x38100032,0x28200032,0x300C0049,0x28100001,0x22140049,0xB000F3,0x2600003E,0x20000059,0x1C0000F4,0xB000F3,0x2600003E,0x20000059,0x1C0000F4,0x1C0000F4,0xA4100003,0xFC280049,0xF030003B,0x56100001,0x3E100001,0x30100001,0x28180001,0x28080004,0x90000005,0x54040000,0x2A040033,0x20000059,
-0x7C00F3,0x2400F3,0x2400F3,0x2400F3,0x2400F3,0x3A1C004A,0x3A1C004A,0x3A1C004A,0x2418004A,0x2418004A,0x1C18004A,0x38100033,0x38100033,0x38100033,0x26100002,0x26100002,0x1E10000E,0x200C0033,0x200C0033,0x1C0C0005,0x160C0035,0x3400F3,0x3400F3,0x3400F3,0x28000049,0x28000049,0x1C08004A,0x22000042,0x22000042,0x1A000009,0x16000035,0x6800F3,
-0x6800F3,0x16000074,0x16000074,0x120000F4,0xA0100003,0xF61C004A,0x2400F3,0x56100001,0x3A100002,0x2E100002,0x2C100003,0x240C0001,0x84000005,0x54040000,0x260C0033,0x1A000009,0x4C00F3,0x300032,0x300032,0x300032,0x300032,0x2E280001,0x2E280001,0x2E280001,0x20280001,0x20280001,0x1C240001,0x2440032,0x2440032,0x2440032,0x24140001,0x24140001,
-0x1C1C0000,0x8C0032,0x8C0032,0x1C000000,0x16000034,0x2440032,0x2440032,0x2440032,0x24140001,0x24140001,0x1C1C0000,0x8C0032,0x8C0032,0x1C000000,0x16000034,0x8C0032,0x8C0032,0x1C000000,0x16000034,0x16000034,0x82180000,0x9C280001,0x300032,0x56100000,0x34180001,0x2C140000,0x26180001,0x240C0000,0x84040001,0x4E080000,0x640032,0x1C000000,
-0x640032,0x44004A,0x3E3C0001,0x2E380001,0x28380001,0x680048,0x32240001,0x282C0001,0xD00048,0x28080000,0x22000048,0x680048,0x32240001,0x282C0001,0xD00048,0x28080000,0x22000048,0xD00048,0x28080000,0x22000048,0x22000048,0x680048,0x32240001,0x282C0001,0xD00048,0x28080000,0x22000048,0xD00048,0x28080000,0x22000048,0x22000048,0xD00048,
-0x28080000,0x22000048,0x22000048,0x22000048,0xB8080000,0xC480048,0xC63C0001,0x5A0C0000,0x3E0C0001,0x32080000,0x28180000,0x28000001,0x94000002,0x54040000,0x2A1C0000,0x22000048,0x940048,0x18004A,0x18004A,0x18004A,0x18004A,0x18004A,0x18004A,0x18004A,0x18004A,0x18004A,0x18004A,0x28100001,0x28100001,0x28100001,0x28100001,0x28100001,
-0x28100001,0x180C0001,0x180C0001,0x180C0001,0x120C0001,0x2240048,0x2240048,0x2240048,0x2240048,0x2240048,0x2240048,0x18000005,0x18000005,0x18000005,0x12000001,0x4C0048,0x4C0048,0x4C0048,0x10000014,0xC000048,0xB0100001,0x18004A,0x18004A,0x52100001,0x3C100001,0x30100001,0x30100001,0x22100001,0x84000001,0x54040000,0x1C0C0001,0x18000005,
-0x340048,};
-static const uint32_t g_etc1_to_bc7_m6_table36[] = {
-0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x5C0000,
-0x5C0000,0x5C0000,0x5C0000,0xE000001,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x8200000,0x8200000,0x8200000,0x300000,0x400000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,
-0x2500000,0xA40000,0xA40000,0xA40000,0x1A000001,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,0xA40000,0xA40000,0xA40000,0x1A000001,0xA40000,0xA40000,0xA40000,0x1A000001,0x1A000001,0x3C0000,0x380000,0x380000,0x400000,0x2440000,0x4C0000,0x4C0000,0x5C0000,0x400000,0x2440000,0x740000,0xA40000,
-0x740000,0x4C0000,0x4C0000,0x4C0000,0x4C0000,0x700000,0x700000,0x700000,0xE40000,0xE40000,0x24000001,0x700000,0x700000,0x700000,0xE40000,0xE40000,0x24000001,0xE40000,0xE40000,0x24000001,0x24000001,0x700000,0x700000,0x700000,0xE40000,0xE40000,0x24000001,0xE40000,0xE40000,0x24000001,0x24000001,0xE40000,
-0xE40000,0x24000001,0x24000001,0x24000001,0x580000,0x500000,0x4C0000,0x680000,0x800000,0xA00000,0xB80000,0x1180000,0x600000,0x700000,0xA00000,0x24000001,0xA00000,0x640000,0x940000,0x12C0000,0x30000001,0x940000,0x12C0000,0x30000001,0x12C0000,0x30000001,0x30000001,0x940000,0x12C0000,0x30000001,0x12C0000,0x30000001,
-0x30000001,0x12C0000,0x30000001,0x30000001,0x30000001,0x940000,0x12C0000,0x30000001,0x12C0000,0x30000001,0x30000001,0x12C0000,0x30000001,0x30000001,0x30000001,0x12C0000,0x30000001,0x30000001,0x30000001,0x30000001,0x7C0000,0xC680000,0xC680000,0xA80000,0xF40000,0x1E00000,0x30000001,0x30000001,0x880000,0xBC0000,0x25DC0000,0x30000001,
-0xD40000,0x400278,0x5E3800F4,0x3C3800F4,0x303800F5,0x582C0090,0x402C004D,0x34300069,0x362C0090,0x302C004D,0x2A2C0092,0x542000F3,0x42200032,0x34280053,0x38200049,0x30200002,0x2C20004E,0x302000F4,0x2E1C0051,0x2A1C0067,0x262000F3,0x600274,0x460C00F3,0x302000F4,0x3E040092,0x3210004A,0x2A180092,0x360400FD,0x30000033,0x2A00004F,0x260800F4,0xC40274,
-0x2C000121,0x260000E2,0x2400014C,0x20000274,0xB4200005,0xF23400D0,0xF63C012C,0x62200000,0x48200001,0x38200002,0x32240006,0x30200006,0xAC080002,0x5A180002,0x321C0035,0x2A00004F,0x8C0274,0x4C00F4,0x52440034,0x3A400034,0x30400035,0x4C380048,0x3A380001,0x32380005,0x3238004A,0x3034000E,0x2A38004A,0x7400F3,0x40240032,0x32300033,0x38200049,0x30200002,
-0x2A28004A,0xE800F3,0x30000033,0x2A00004B,0x260000F3,0x7400F3,0x40240032,0x32300033,0x38200049,0x30200002,0x2A28004A,0xE800F3,0x30000033,0x2A00004B,0x260000F3,0xE800F3,0x30000033,0x2A00004B,0x260000F3,0x260000F3,0xA8240003,0xF63C004C,0xFA440038,0x62200000,0x48200001,0x38200002,0x32280001,0x30180003,0xAC080001,0x5A180001,0x34140032,0x2A00004B,
-0xA400F3,0x3800F4,0x3800F4,0x3800F4,0x3800F4,0x462C0048,0x462C0048,0x462C0048,0x2C2C0049,0x2C2C0049,0x242C0049,0x42200032,0x42200032,0x42200032,0x30200001,0x30200001,0x2624000E,0x28200032,0x28200032,0x24200005,0x20200032,0x5000F3,0x5000F3,0x5000F3,0x32100049,0x32100049,0x241C0049,0x30000032,0x30000032,0x240C0002,0x20100032,0xA000F3,
-0xA000F3,0x22000059,0x1E000053,0x1A0000F3,0xA8200004,0xFE2C0049,0x3800F4,0x62200000,0x44200001,0x38200001,0x34200004,0x2C200001,0xA20C0000,0x5A180001,0x301C0032,0x240C0002,0x7000F3,0x400034,0x400034,0x400034,0x400034,0x38380000,0x38380000,0x38380000,0x2A380000,0x2A380000,0x24380001,0x600032,0x600032,0x600032,0x2C280001,0x2C280001,
-0x24300001,0xC40032,0xC40032,0x24140001,0x20000032,0x600032,0x600032,0x600032,0x2C280001,0x2C280001,0x24300001,0xC40032,0xC40032,0x24140001,0x20000032,0xC40032,0xC40032,0x24140001,0x20000032,0x20000032,0x90280000,0xB4380000,0x400034,0x62200000,0x42240000,0x36240000,0x32280000,0x2C200001,0xA20C0000,0x5A180000,0x8C0032,0x24140001,
-0x8C0032,0x580048,0x4A4C0000,0x364C0001,0x304C0001,0x2800048,0x3A380001,0x30400001,0x1080048,0x301C0001,0x2A00004A,0x2800048,0x3A380001,0x30400001,0x1080048,0x301C0001,0x2A00004A,0x1080048,0x301C0001,0x2A00004A,0x2A00004A,0x2800048,0x3A380001,0x30400001,0x1080048,0x301C0001,0x2A00004A,0x1080048,0x301C0001,0x2A00004A,0x2A00004A,0x1080048,
-0x301C0001,0x2A00004A,0x2A00004A,0x2A00004A,0xC4180000,0x65C0048,0xDE4C0000,0x62200000,0x46200001,0x3A1C0000,0x302C0001,0x300C0001,0xB4040000,0x5E140000,0x32300001,0x2A00004A,0xB80048,0x2C0048,0x2C0048,0x2C0048,0x2C0048,0x2C0048,0x2C0048,0x2C0048,0x2C0048,0x2C0048,0x2C0048,0x34200000,0x34200000,0x34200000,0x34200000,0x34200000,
-0x34200000,0x20200001,0x20200001,0x20200001,0x1A200001,0x400048,0x400048,0x400048,0x400048,0x400048,0x400048,0x240C0001,0x240C0001,0x240C0001,0x1A140001,0x800048,0x800048,0x800048,0x1A000005,0x1400004A,0xC8200000,0x2C0048,0x2C0048,0x62200000,0x48200000,0x3C200000,0x3C200000,0x2C200000,0x9E0C0000,0x62140000,0x281C0000,0x240C0001,
-0x5C0048,};
-static const uint32_t g_etc1_to_bc7_m6_table37[] = {
-0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x8C0000,
-0x8C0000,0x8C0000,0x8C0000,0x16000001,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x340000,0x340000,0x340000,0x2440000,0x640000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x2680000,0x2680000,0x2680000,0x2680000,0x2680000,
-0x2680000,0xD80000,0xD80000,0xD80000,0x22000001,0x2680000,0x2680000,0x2680000,0x2680000,0x2680000,0x2680000,0xD80000,0xD80000,0xD80000,0x22000001,0xD80000,0xD80000,0xD80000,0x22000001,0x22000001,0x4C0000,0x480000,0x480000,0x540000,0x2580000,0x600000,0x600000,0x780000,0x540000,0x2580000,0x980000,0xD80000,
-0x980000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x880000,0x880000,0x880000,0x1140000,0x1140000,0x2C000001,0x880000,0x880000,0x880000,0x1140000,0x1140000,0x2C000001,0x1140000,0x1140000,0x2C000001,0x2C000001,0x880000,0x880000,0x880000,0x1140000,0x1140000,0x2C000001,0x1140000,0x1140000,0x2C000001,0x2C000001,0x1140000,
-0x1140000,0x2C000001,0x2C000001,0x2C000001,0x6680000,0x8600000,0x5C0000,0x7C0000,0x980000,0xC00000,0xE00000,0x1540000,0x740000,0x880000,0xC00000,0x2C000001,0xC00000,0x740000,0xAC0000,0x15C0000,0x38000001,0xAC0000,0x15C0000,0x38000001,0x15C0000,0x38000001,0x38000001,0xAC0000,0x15C0000,0x38000001,0x15C0000,0x38000001,
-0x38000001,0x15C0000,0x38000001,0x38000001,0x38000001,0xAC0000,0x15C0000,0x38000001,0x15C0000,0x38000001,0x38000001,0x15C0000,0x38000001,0x38000001,0x38000001,0x15C0000,0x38000001,0x38000001,0x38000001,0x38000001,0x900000,0x7C0000,0x7C0000,0x2C00000,0x11C0000,0x9F00000,0x38000001,0x38000001,0x9C0000,0xD80000,0x2DEC0000,0x38000001,
-0xF40000,0x500278,0x664800F4,0x444800F4,0x384800F5,0x603C0090,0x483C004D,0x3C400069,0x3E3C0090,0x383C004D,0x323C0092,0x5C3000F3,0x4A300032,0x3C380053,0x40300049,0x38300002,0x3430004E,0x383000F4,0x362C0051,0x322C0067,0x2E3000F3,0x780274,0x4E1C00F3,0x383000F4,0x46140092,0x3A20004A,0x32280092,0x440400F3,0x38100033,0x3210004F,0x2E1800F4,0xF40274,
-0x36000104,0x320000B2,0x2C00011F,0x28000274,0xBC300005,0xFA4400D0,0xFE4C012C,0x6A300000,0x50300001,0x40300002,0x3A340006,0x38300006,0xB4180002,0x62280002,0x3A2C0035,0x3210004F,0xAC0274,0x5C00F4,0x5A540034,0x42500034,0x38500035,0x54480048,0x42480001,0x3A480005,0x3A48004A,0x3844000E,0x3248004A,0x8C00F3,0x48340032,0x3A400033,0x40300049,0x38300002,
-0x3238004A,0x11800F3,0x38100033,0x3208004A,0x2E0000F3,0x8C00F3,0x48340032,0x3A400033,0x40300049,0x38300002,0x3238004A,0x11800F3,0x38100033,0x3208004A,0x2E0000F3,0x11800F3,0x38100033,0x3208004A,0x2E0000F3,0x2E0000F3,0xB0340003,0xFE4C004C,0xF254003D,0x6A300000,0x50300001,0x40300002,0x3A380001,0x38280003,0xB4180001,0x62280001,0x3C240032,0x3208004A,
-0xC800F3,0x4800F4,0x4800F4,0x4800F4,0x4800F4,0x4E3C0048,0x4E3C0048,0x4E3C0048,0x343C0049,0x343C0049,0x2C3C0049,0x4A300032,0x4A300032,0x4A300032,0x38300001,0x38300001,0x2E34000E,0x30300032,0x30300032,0x2C300005,0x28300032,0x6800F3,0x6800F3,0x6800F3,0x3A200049,0x3A200049,0x2C2C0049,0x38100032,0x38100032,0x2C1C0002,0x28200032,0xD000F3,
-0xD000F3,0x2C000049,0x2600003E,0x220000F3,0xB0300004,0xF63C004C,0x4800F4,0x6A300000,0x4C300001,0x40300001,0x3C300004,0x34300001,0xAA1C0000,0x62280001,0x382C0032,0x2C1C0002,0x9400F3,0x500034,0x500034,0x500034,0x500034,0x40480000,0x40480000,0x40480000,0x32480000,0x32480000,0x2C480001,0x780032,0x780032,0x780032,0x34380001,0x34380001,
-0x2C400001,0xF40032,0xF40032,0x2C240001,0x28000032,0x780032,0x780032,0x780032,0x34380001,0x34380001,0x2C400001,0xF40032,0xF40032,0x2C240001,0x28000032,0xF40032,0xF40032,0x2C240001,0x28000032,0x28000032,0x98380000,0xBC480000,0x500034,0x6A300000,0x4A340000,0x3E340000,0x3A380000,0x34300001,0xAA1C0000,0x62280000,0xAC0032,0x2C240001,
-0xAC0032,0x680048,0x525C0000,0x3E5C0001,0x385C0001,0x2980048,0x42480001,0x38500001,0x1380048,0x382C0001,0x3200004A,0x2980048,0x42480001,0x38500001,0x1380048,0x382C0001,0x3200004A,0x1380048,0x382C0001,0x3200004A,0x3200004A,0x2980048,0x42480001,0x38500001,0x1380048,0x382C0001,0x3200004A,0x1380048,0x382C0001,0x3200004A,0x3200004A,0x1380048,
-0x382C0001,0x3200004A,0x3200004A,0x3200004A,0xCC280000,0xE6C0048,0xE65C0000,0x6A300000,0x4E300001,0x422C0000,0x383C0001,0x381C0001,0xBC140000,0x66240000,0x3A400001,0x3200004A,0xDC0048,0x3C0048,0x3C0048,0x3C0048,0x3C0048,0x3C0048,0x3C0048,0x3C0048,0x3C0048,0x3C0048,0x3C0048,0x3C300000,0x3C300000,0x3C300000,0x3C300000,0x3C300000,
-0x3C300000,0x28300001,0x28300001,0x28300001,0x22300001,0x580048,0x580048,0x580048,0x580048,0x580048,0x580048,0x2C1C0001,0x2C1C0001,0x2C1C0001,0x22240001,0xB00048,0xB00048,0xB00048,0x22000001,0x1C00004A,0xD0300000,0x3C0048,0x3C0048,0x6A300000,0x50300000,0x44300000,0x44300000,0x34300000,0xA61C0000,0x6A240000,0x302C0000,0x2C1C0001,
-0x7C0048,};
-static const uint32_t g_etc1_to_bc7_m6_table38[] = {
-0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0xBC0000,
-0xBC0000,0xBC0000,0xBC0000,0x1E000001,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x440000,0x440000,0x440000,0x25C0000,0x880000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x2800000,0x2800000,0x2800000,0x2800000,0x2800000,
-0x2800000,0x1080000,0x1080000,0x1080000,0x2A000001,0x2800000,0x2800000,0x2800000,0x2800000,0x2800000,0x2800000,0x1080000,0x1080000,0x1080000,0x2A000001,0x1080000,0x1080000,0x1080000,0x2A000001,0x2A000001,0x65C0000,0x580000,0x580000,0x4640000,0x26C0000,0x780000,0x780000,0x940000,0x4640000,0x26C0000,0xB80000,0x1080000,
-0xB80000,0x6C0000,0x6C0000,0x6C0000,0x6C0000,0xA00000,0xA00000,0xA00000,0x1440000,0x1440000,0x34000001,0xA00000,0xA00000,0xA00000,0x1440000,0x1440000,0x34000001,0x1440000,0x1440000,0x34000001,0x34000001,0xA00000,0xA00000,0xA00000,0x1440000,0x1440000,0x34000001,0x1440000,0x1440000,0x34000001,0x34000001,0x1440000,
-0x1440000,0x34000001,0x34000001,0x34000001,0x27C0000,0x740000,0x6C0000,0x2900000,0xB40000,0xE40000,0x1080000,0x1900000,0x880000,0xA00000,0xE40000,0x34000001,0xE40000,0x840000,0xC40000,0x18C0000,0x40000001,0xC40000,0x18C0000,0x40000001,0x18C0000,0x40000001,0x40000001,0xC40000,0x18C0000,0x40000001,0x18C0000,0x40000001,
-0x40000001,0x18C0000,0x40000001,0x40000001,0x40000001,0xC40000,0x18C0000,0x40000001,0x18C0000,0x40000001,0x40000001,0x18C0000,0x40000001,0x40000001,0x40000001,0x18C0000,0x40000001,0x40000001,0x40000001,0x40000001,0xA40000,0x8C0000,0x8C0000,0xDC0000,0x1400000,0x13F00000,0x40000001,0x40000001,0xB40000,0xF80000,0x35FC0000,0x40000001,
-0x1180000,0x600278,0x6E5800F4,0x4C5800F4,0x405800F5,0x684C0090,0x504C004D,0x44500069,0x464C0090,0x404C004D,0x3A4C0092,0x644000F3,0x52400032,0x44480053,0x48400049,0x40400002,0x3C40004E,0x404000F4,0x3E3C0051,0x3A3C0067,0x364000F3,0x900274,0x562C00F3,0x404000F4,0x4E240092,0x4230004A,0x3A380092,0x4C1400F3,0x40200033,0x3A20004F,0x362800F4,0x1240274,
-0x400000F5,0x3A00009A,0x3400010B,0x30000274,0xC4400005,0xF25400E2,0xF65C0139,0x72400000,0x58400001,0x48400002,0x42440006,0x40400006,0xBC280002,0x6A380002,0x423C0035,0x3A20004F,0xD00274,0x6C00F4,0x62640034,0x4A600034,0x40600035,0x5C580048,0x4A580001,0x42580005,0x4258004A,0x4054000E,0x3A58004A,0xA400F3,0x50440032,0x42500033,0x48400049,0x40400002,
-0x3A48004A,0x14C00F3,0x40200033,0x3A18004A,0x360000F3,0xA400F3,0x50440032,0x42500033,0x48400049,0x40400002,0x3A48004A,0x14C00F3,0x40200033,0x3A18004A,0x360000F3,0x14C00F3,0x40200033,0x3A18004A,0x360000F3,0x360000F3,0xB8440003,0xF65C004E,0xFA64003D,0x72400000,0x58400001,0x48400002,0x42480001,0x40380003,0xBC280001,0x6A380001,0x44340032,0x3A18004A,
-0xE800F3,0x5800F4,0x5800F4,0x5800F4,0x5800F4,0x564C0048,0x564C0048,0x564C0048,0x3C4C0049,0x3C4C0049,0x344C0049,0x52400032,0x52400032,0x52400032,0x40400001,0x40400001,0x3644000E,0x38400032,0x38400032,0x34400005,0x30400032,0x8000F3,0x8000F3,0x8000F3,0x42300049,0x42300049,0x343C0049,0x40200032,0x40200032,0x342C0002,0x30300032,0x10000F3,
-0x10000F3,0x340C0049,0x30000033,0x2A0000F3,0xB8400004,0xFE4C004C,0x5800F4,0x72400000,0x54400001,0x48400001,0x44400004,0x3C400001,0xB22C0000,0x6A380001,0x403C0032,0x342C0002,0xB400F3,0x600034,0x600034,0x600034,0x600034,0x48580000,0x48580000,0x48580000,0x3A580000,0x3A580000,0x34580001,0x900032,0x900032,0x900032,0x3C480001,0x3C480001,
-0x34500001,0x1240032,0x1240032,0x34340001,0x30000032,0x900032,0x900032,0x900032,0x3C480001,0x3C480001,0x34500001,0x1240032,0x1240032,0x34340001,0x30000032,0x1240032,0x1240032,0x34340001,0x30000032,0x30000032,0xA0480000,0xC4580000,0x600034,0x72400000,0x52440000,0x46440000,0x42480000,0x3C400001,0xB22C0000,0x6A380000,0xD00032,0x34340001,
-0xD00032,0x780048,0x5A6C0000,0x466C0001,0x406C0001,0x2B00048,0x4A580001,0x40600001,0x1680048,0x403C0001,0x3A00004A,0x2B00048,0x4A580001,0x40600001,0x1680048,0x403C0001,0x3A00004A,0x1680048,0x403C0001,0x3A00004A,0x3A00004A,0x2B00048,0x4A580001,0x40600001,0x1680048,0x403C0001,0x3A00004A,0x1680048,0x403C0001,0x3A00004A,0x3A00004A,0x1680048,
-0x403C0001,0x3A00004A,0x3A00004A,0x3A00004A,0xD4380000,0x800048,0xEE6C0000,0x72400000,0x56400001,0x4A3C0000,0x404C0001,0x402C0001,0xC4240000,0x6E340000,0x42500001,0x3A00004A,0xFC0048,0x4C0048,0x4C0048,0x4C0048,0x4C0048,0x4C0048,0x4C0048,0x4C0048,0x4C0048,0x4C0048,0x4C0048,0x44400000,0x44400000,0x44400000,0x44400000,0x44400000,
-0x44400000,0x30400001,0x30400001,0x30400001,0x2A400001,0x700048,0x700048,0x700048,0x700048,0x700048,0x700048,0x342C0001,0x342C0001,0x342C0001,0x2A340001,0xE40048,0xE40048,0xE40048,0x2A100001,0x2400004A,0xD8400000,0x4C0048,0x4C0048,0x72400000,0x58400000,0x4C400000,0x4C400000,0x3C400000,0xAE2C0000,0x72340000,0x383C0000,0x342C0001,
-0xA00048,};
-static const uint32_t g_etc1_to_bc7_m6_table39[] = {
-0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0xF00000,
-0xF00000,0xF00000,0xF00000,0x26000001,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x2540000,0x2540000,0x2540000,0x2740000,0xA80000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,
-0x2980000,0x1380000,0x1380000,0x1380000,0x32000001,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,0x1380000,0x1380000,0x1380000,0x32000001,0x1380000,0x1380000,0x1380000,0x32000001,0x32000001,0xE6C0000,0x680000,0x680000,0x780000,0x2800000,0x8C0000,0x8C0000,0x2AC0000,0x780000,0x2800000,0xDC0000,0x1380000,
-0xDC0000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0xB80000,0xB80000,0xB80000,0x1740000,0x1740000,0x3C000001,0xB80000,0xB80000,0xB80000,0x1740000,0x1740000,0x3C000001,0x1740000,0x1740000,0x3C000001,0x3C000001,0xB80000,0xB80000,0xB80000,0x1740000,0x1740000,0x3C000001,0x1740000,0x1740000,0x3C000001,0x3C000001,0x1740000,
-0x1740000,0x3C000001,0x3C000001,0x3C000001,0x900000,0x840000,0x7C0000,0xA80000,0xD00000,0x1080000,0x12C0000,0x1CC0000,0x9C0000,0xB80000,0x1080000,0x3C000001,0x1080000,0x940000,0xDC0000,0x1BC0000,0x48000001,0xDC0000,0x1BC0000,0x48000001,0x1BC0000,0x48000001,0x48000001,0xDC0000,0x1BC0000,0x48000001,0x1BC0000,0x48000001,
-0x48000001,0x1BC0000,0x48000001,0x48000001,0x48000001,0xDC0000,0x1BC0000,0x48000001,0x1BC0000,0x48000001,0x48000001,0x1BC0000,0x48000001,0x48000001,0x48000001,0x1BC0000,0x48000001,0x48000001,0x48000001,0x48000001,0xB80000,0x69C0000,0x69C0000,0xF80000,0x1680000,0x1DF40000,0x48000001,0x48000001,0xC80000,0x1140000,0x3FD00000,0x48000001,
-0x1380000,0x700278,0x766800F4,0x546800F4,0x486800F5,0x705C0090,0x585C004D,0x4C600069,0x4E5C0090,0x485C004D,0x425C0092,0x6C5000F3,0x5A500032,0x4C580053,0x50500049,0x48500002,0x4450004E,0x485000F4,0x464C0051,0x424C0067,0x3E5000F3,0xA80274,0x5E3C00F3,0x485000F4,0x56340092,0x4A40004A,0x42480092,0x542400F3,0x48300033,0x4230004F,0x3E3800F4,0x1580274,
-0x480C00F4,0x42040092,0x3E0000F7,0x38000274,0xCC500005,0xFA6400E2,0xFE6C0139,0x7A500000,0x60500001,0x50500002,0x4A540006,0x48500006,0xC4380002,0x72480002,0x4A4C0035,0x4230004F,0xF00274,0x7C00F4,0x6A740034,0x52700034,0x48700035,0x64680048,0x52680001,0x4A680005,0x4A68004A,0x4864000E,0x4268004A,0xBC00F3,0x58540032,0x4A600033,0x50500049,0x48500002,
-0x4258004A,0x17C00F3,0x48300033,0x4228004A,0x3E0000F3,0xBC00F3,0x58540032,0x4A600033,0x50500049,0x48500002,0x4258004A,0x17C00F3,0x48300033,0x4228004A,0x3E0000F3,0x17C00F3,0x48300033,0x4228004A,0x3E0000F3,0x3E0000F3,0xC0540003,0xFE6C004E,0xF2740044,0x7A500000,0x60500001,0x50500002,0x4A580001,0x48480003,0xC4380001,0x72480001,0x4C440032,0x4228004A,
-0x10C00F3,0x6800F4,0x6800F4,0x6800F4,0x6800F4,0x5E5C0048,0x5E5C0048,0x5E5C0048,0x445C0049,0x445C0049,0x3C5C0049,0x5A500032,0x5A500032,0x5A500032,0x48500001,0x48500001,0x3E54000E,0x40500032,0x40500032,0x3C500005,0x38500032,0x9800F3,0x9800F3,0x9800F3,0x4A400049,0x4A400049,0x3C4C0049,0x48300032,0x48300032,0x3C3C0002,0x38400032,0x13000F3,
-0x13000F3,0x3C1C0049,0x38080032,0x320000F3,0xC0500004,0xF65C0051,0x6800F4,0x7A500000,0x5C500001,0x50500001,0x4C500004,0x44500001,0xBA3C0000,0x72480001,0x484C0032,0x3C3C0002,0xD800F3,0x700034,0x700034,0x700034,0x700034,0x50680000,0x50680000,0x50680000,0x42680000,0x42680000,0x3C680001,0xA80032,0xA80032,0xA80032,0x44580001,0x44580001,
-0x3C600001,0x1580032,0x1580032,0x3C440001,0x38000032,0xA80032,0xA80032,0xA80032,0x44580001,0x44580001,0x3C600001,0x1580032,0x1580032,0x3C440001,0x38000032,0x1580032,0x1580032,0x3C440001,0x38000032,0x38000032,0xA8580000,0xCC680000,0x700034,0x7A500000,0x5A540000,0x4E540000,0x4A580000,0x44500001,0xBA3C0000,0x72480000,0xF00032,0x3C440001,
-0xF00032,0x880048,0x627C0000,0x4E7C0001,0x487C0001,0xC80048,0x52680001,0x48700001,0x1980048,0x484C0001,0x4200004A,0xC80048,0x52680001,0x48700001,0x1980048,0x484C0001,0x4200004A,0x1980048,0x484C0001,0x4200004A,0x4200004A,0xC80048,0x52680001,0x48700001,0x1980048,0x484C0001,0x4200004A,0x1980048,0x484C0001,0x4200004A,0x4200004A,0x1980048,
-0x484C0001,0x4200004A,0x4200004A,0x4200004A,0xDC480000,0x900048,0xF67C0000,0x7A500000,0x5E500001,0x524C0000,0x485C0001,0x483C0001,0xCC340000,0x76440000,0x4A600001,0x4200004A,0x1200048,0x5C0048,0x5C0048,0x5C0048,0x5C0048,0x5C0048,0x5C0048,0x5C0048,0x5C0048,0x5C0048,0x5C0048,0x4C500000,0x4C500000,0x4C500000,0x4C500000,0x4C500000,
-0x4C500000,0x38500001,0x38500001,0x38500001,0x32500001,0x880048,0x880048,0x880048,0x880048,0x880048,0x880048,0x3C3C0001,0x3C3C0001,0x3C3C0001,0x32440001,0x1140048,0x1140048,0x1140048,0x32200001,0x2C00004A,0xE0500000,0x5C0048,0x5C0048,0x7A500000,0x60500000,0x54500000,0x54500000,0x44500000,0xB63C0000,0x7A440000,0x404C0000,0x3C3C0001,
-0xC00048,};
-static const uint32_t g_etc1_to_bc7_m6_table40[] = {
-0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x1240000,
-0x1240000,0x1240000,0x1240000,0x30000000,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x680000,0x680000,0x680000,0x900000,0xD00000,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,
-0xB40000,0x1700000,0x1700000,0x1700000,0x3C000000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0x1700000,0x1700000,0x1700000,0x3C000000,0x1700000,0x1700000,0x1700000,0x3C000000,0x3C000000,0x8800000,0x780001,0x780001,0x28C0000,0x980000,0x2A40000,0x2A40000,0xCC0000,0x28C0000,0x980000,0x1000000,0x1700000,
-0x1000000,0x8C0001,0x8C0001,0x8C0001,0x8C0001,0x2D00000,0x2D00000,0x2D00000,0x1AC0000,0x1AC0000,0x46000000,0x2D00000,0x2D00000,0x2D00000,0x1AC0000,0x1AC0000,0x46000000,0x1AC0000,0x1AC0000,0x46000000,0x46000000,0x2D00000,0x2D00000,0x2D00000,0x1AC0000,0x1AC0000,0x46000000,0x1AC0000,0x1AC0000,0x46000000,0x46000000,0x1AC0000,
-0x1AC0000,0x46000000,0x46000000,0x46000000,0xA40000,0x980000,0x8C0001,0xC00000,0x2EC0000,0x12C0000,0x15C0000,0x5F80000,0x2B00000,0x2D00000,0x12C0000,0x46000000,0x12C0000,0xA40001,0x2F40000,0x1F40000,0x52000000,0x2F40000,0x1F40000,0x52000000,0x1F40000,0x52000000,0x52000000,0x2F40000,0x1F40000,0x52000000,0x1F40000,0x52000000,
-0x52000000,0x1F40000,0x52000000,0x52000000,0x52000000,0x2F40000,0x1F40000,0x52000000,0x1F40000,0x52000000,0x52000000,0x1F40000,0x52000000,0x52000000,0x52000000,0x1F40000,0x52000000,0x52000000,0x52000000,0x52000000,0xD00000,0xB00000,0xB00000,0x3140000,0x1940000,0x27FC0000,0x52000000,0x52000000,0xE00000,0x1380000,0x49C40000,0x52000000,
-0x1600000,0x840274,0x807800F3,0x5C7800F4,0x527800F3,0x76700092,0x5E70004F,0x54700067,0x56700092,0x526C004E,0x4C6C0092,0x746400F4,0x62640033,0x54680051,0x5A60004A,0x52640002,0x4C64004D,0x526000F4,0x4E5C0053,0x4A5C0069,0x466000F5,0xC40274,0x684C00F3,0x526400F4,0x5E480092,0x52540049,0x4C580090,0x5C3800F3,0x52400032,0x4C40004D,0x464C00F4,0x18C0274,
-0x521800F3,0x4C140090,0x460800F4,0x40000278,0xCE640004,0xF47800F4,0xF67C014C,0x80640002,0x68640002,0x5A640002,0x52640006,0x50600006,0xCE4C0002,0x7E580000,0x545C0035,0x4C40004D,0x1180274,0x9000F3,0x74840032,0x5A840032,0x52840032,0x6A7C0049,0x5C780002,0x527C0005,0x54780049,0x5078000E,0x4C780049,0xD400F3,0x62640032,0x52740032,0x5A600049,0x52640001,
-0x4C680049,0x1B000F3,0x523C0032,0x4C380048,0x460000F4,0xD400F3,0x62640032,0x52740032,0x5A600049,0x52640001,0x4C680049,0x1B000F3,0x523C0032,0x4C380048,0x460000F4,0x1B000F3,0x523C0032,0x4C380048,0x460000F4,0x460000F4,0xCE640003,0xF8800053,0xFC880043,0x80640001,0x68640001,0x5A640001,0x526C0001,0x525C0004,0xD4480001,0x7E580000,0x54580033,0x4C380048,
-0x13000F3,0x7800F3,0x7800F3,0x7800F3,0x7800F3,0x6470004A,0x6470004A,0x6470004A,0x4E6C004A,0x4E6C004A,0x466C004A,0x62640033,0x62640033,0x62640033,0x50640002,0x50640002,0x4864000E,0x4A600033,0x4A600033,0x46600005,0x40600035,0x2B000F3,0x2B000F3,0x2B000F3,0x52540049,0x52540049,0x465C004A,0x50440032,0x50440032,0x464C0001,0x42500034,0x16800F3,
-0x16800F3,0x462C0048,0x40200034,0x3C0000F4,0xCA640003,0xF0700053,0x7800F3,0x80640001,0x64640002,0x58640002,0x56640003,0x4E600001,0xBE500000,0x7E580000,0x50600033,0x464C0001,0xFC00F3,0x840032,0x840032,0x840032,0x840032,0x587C0001,0x587C0001,0x587C0001,0x4A7C0001,0x4A7C0001,0x46780001,0xC40032,0xC40032,0xC40032,0x4E680001,0x4E680001,
-0x46700000,0x18C0032,0x18C0032,0x46500000,0x40000034,0xC40032,0xC40032,0xC40032,0x4E680001,0x4E680001,0x46700000,0x18C0032,0x18C0032,0x46500000,0x40000034,0x18C0032,0x18C0032,0x46500000,0x40000034,0x40000034,0xAC6C0000,0xC67C0001,0x840032,0x80640000,0x5E6C0001,0x56680000,0x506C0001,0x4E600000,0xBE500000,0x785C0000,0x1180032,0x46500000,
-0x1180032,0x98004A,0x68900001,0x588C0001,0x528C0001,0xE40048,0x5C780001,0x52800001,0x1D00048,0x525C0000,0x4C000048,0xE40048,0x5C780001,0x52800001,0x1D00048,0x525C0000,0x4C000048,0x1D00048,0x525C0000,0x4C000048,0x4C000048,0xE40048,0x5C780001,0x52800001,0x1D00048,0x525C0000,0x4C000048,0x1D00048,0x525C0000,0x4C000048,0x4C000048,0x1D00048,
-0x525C0000,0x4C000048,0x4C000048,0x4C000048,0xE25C0000,0xA40048,0xF0900001,0x84600000,0x68600001,0x5C5C0000,0x526C0000,0x52480000,0xD8440000,0x7E580000,0x54700000,0x4C000048,0x1480048,0x6C004A,0x6C004A,0x6C004A,0x6C004A,0x6C004A,0x6C004A,0x6C004A,0x6C004A,0x6C004A,0x6C004A,0x52640001,0x52640001,0x52640001,0x52640001,0x52640001,
-0x52640001,0x42600001,0x42600001,0x42600001,0x3C600001,0xA40048,0xA40048,0xA40048,0xA40048,0xA40048,0xA40048,0x464C0001,0x464C0001,0x464C0001,0x3C540001,0x14C0048,0x14C0048,0x14C0048,0x3C300000,0x36000048,0xDA640001,0x6C004A,0x6C004A,0x7C640001,0x66640001,0x5A640001,0x5A640001,0x4C640001,0xBA500000,0x7E580000,0x46600001,0x464C0001,
-0xE80048,};
-static const uint32_t g_etc1_to_bc7_m6_table41[] = {
-0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0x1580000,
-0x1580000,0x1580000,0x1580000,0x38000000,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x4780000,0x4780000,0x4780000,0xA80000,0xF00000,0x880001,0x880001,0x880001,0x880001,0x880001,0x880001,0x880001,0x880001,0x880001,0x880001,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,
-0xCC0000,0x1A00000,0x1A00000,0x1A00000,0x44000000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0x1A00000,0x1A00000,0x1A00000,0x44000000,0x1A00000,0x1A00000,0x1A00000,0x44000000,0x44000000,0x940000,0x880001,0x880001,0xA00000,0xAC0000,0xBC0000,0xBC0000,0xE80000,0xA00000,0xAC0000,0x1240000,0x1A00000,
-0x1240000,0x9C0001,0x9C0001,0x9C0001,0x9C0001,0x2E80000,0x2E80000,0x2E80000,0x1DC0000,0x1DC0000,0x4E000000,0x2E80000,0x2E80000,0x2E80000,0x1DC0000,0x1DC0000,0x4E000000,0x1DC0000,0x1DC0000,0x4E000000,0x4E000000,0x2E80000,0x2E80000,0x2E80000,0x1DC0000,0x1DC0000,0x4E000000,0x1DC0000,0x1DC0000,0x4E000000,0x4E000000,0x1DC0000,
-0x1DC0000,0x4E000000,0x4E000000,0x4E000000,0xB80000,0xA80000,0x9C0001,0x2D40000,0x1080000,0x1500000,0x1800000,0x11F40000,0x2C40000,0x2E80000,0x1500000,0x4E000000,0x1500000,0xB40001,0x30C0000,0xBFC0000,0x5A000000,0x30C0000,0xBFC0000,0x5A000000,0xBFC0000,0x5A000000,0x5A000000,0x30C0000,0xBFC0000,0x5A000000,0xBFC0000,0x5A000000,
-0x5A000000,0xBFC0000,0x5A000000,0x5A000000,0x5A000000,0x30C0000,0xBFC0000,0x5A000000,0xBFC0000,0x5A000000,0x5A000000,0xBFC0000,0x5A000000,0x5A000000,0x5A000000,0xBFC0000,0x5A000000,0x5A000000,0x5A000000,0x5A000000,0xE40000,0x8C00000,0x8C00000,0x1300000,0x1BC0000,0x31FC0000,0x5A000000,0x5A000000,0xF80000,0x1540000,0x51D40000,0x5A000000,
-0x1800000,0x940274,0x888800F3,0x648800F4,0x5A8800F3,0x7E800092,0x6680004F,0x5C800067,0x5E800092,0x5A7C004E,0x547C0092,0x7C7400F4,0x6A740033,0x5C780051,0x6270004A,0x5A740002,0x5474004D,0x5A7000F4,0x566C0053,0x526C0069,0x4E7000F5,0xDC0274,0x705C00F3,0x5A7400F4,0x66580092,0x5A640049,0x54680090,0x644800F3,0x5A500032,0x5450004D,0x4E5C00F4,0x1BC0274,
-0x5A2800F3,0x54240090,0x4E1800F4,0x48000278,0xD6740004,0xFC8800F4,0xFE8C014C,0x88740002,0x70740002,0x62740002,0x5A740006,0x58700006,0xD65C0002,0x86680000,0x5C6C0035,0x5450004D,0x1380274,0xA000F3,0x7C940032,0x62940032,0x5A940032,0x728C0049,0x64880002,0x5A8C0005,0x5C880049,0x5888000E,0x54880049,0xEC00F3,0x6A740032,0x5A840032,0x62700049,0x5A740001,
-0x54780049,0x1E400F3,0x5A4C0032,0x54480048,0x4E0000F4,0xEC00F3,0x6A740032,0x5A840032,0x62700049,0x5A740001,0x54780049,0x1E400F3,0x5A4C0032,0x54480048,0x4E0000F4,0x1E400F3,0x5A4C0032,0x54480048,0x4E0000F4,0x4E0000F4,0xD6740003,0xF0900059,0xF498004A,0x88740001,0x70740001,0x62740001,0x5A7C0001,0x5A6C0004,0xDC580001,0x86680000,0x5C680033,0x54480048,
-0x15400F3,0x8800F3,0x8800F3,0x8800F3,0x8800F3,0x6C80004A,0x6C80004A,0x6C80004A,0x567C004A,0x567C004A,0x4E7C004A,0x6A740033,0x6A740033,0x6A740033,0x58740002,0x58740002,0x5074000E,0x52700033,0x52700033,0x4E700005,0x48700035,0xC800F3,0xC800F3,0xC800F3,0x5A640049,0x5A640049,0x4E6C004A,0x58540032,0x58540032,0x4E5C0001,0x4A600034,0x19800F3,
-0x19800F3,0x4E3C0048,0x48300034,0x440000F4,0xD2740003,0xF8800053,0x8800F3,0x88740001,0x6C740002,0x60740002,0x5E740003,0x56700001,0xC6600000,0x86680000,0x58700033,0x4E5C0001,0x12000F3,0x940032,0x940032,0x940032,0x940032,0x608C0001,0x608C0001,0x608C0001,0x528C0001,0x528C0001,0x4E880001,0xDC0032,0xDC0032,0xDC0032,0x56780001,0x56780001,
-0x4E800000,0x1BC0032,0x1BC0032,0x4E600000,0x48000034,0xDC0032,0xDC0032,0xDC0032,0x56780001,0x56780001,0x4E800000,0x1BC0032,0x1BC0032,0x4E600000,0x48000034,0x1BC0032,0x1BC0032,0x4E600000,0x48000034,0x48000034,0xB47C0000,0xCE8C0001,0x940032,0x88740000,0x667C0001,0x5E780000,0x587C0001,0x56700000,0xC6600000,0x806C0000,0x1380032,0x4E600000,
-0x1380032,0xA8004A,0x70A00001,0x609C0001,0x5A9C0001,0xFC0048,0x64880001,0x5A900001,0x3F80048,0x5A6C0000,0x54000048,0xFC0048,0x64880001,0x5A900001,0x3F80048,0x5A6C0000,0x54000048,0x3F80048,0x5A6C0000,0x54000048,0x54000048,0xFC0048,0x64880001,0x5A900001,0x3F80048,0x5A6C0000,0x54000048,0x3F80048,0x5A6C0000,0x54000048,0x54000048,0x3F80048,
-0x5A6C0000,0x54000048,0x54000048,0x54000048,0xEA6C0000,0x2B40048,0xF8A00001,0x8C700000,0x70700001,0x646C0000,0x5A7C0000,0x5A580000,0xE0540000,0x86680000,0x5C800000,0x54000048,0x1680048,0x7C004A,0x7C004A,0x7C004A,0x7C004A,0x7C004A,0x7C004A,0x7C004A,0x7C004A,0x7C004A,0x7C004A,0x5A740001,0x5A740001,0x5A740001,0x5A740001,0x5A740001,
-0x5A740001,0x4A700001,0x4A700001,0x4A700001,0x44700001,0xBC0048,0xBC0048,0xBC0048,0xBC0048,0xBC0048,0xBC0048,0x4E5C0001,0x4E5C0001,0x4E5C0001,0x44640001,0x17C0048,0x17C0048,0x17C0048,0x44400000,0x3E000048,0xE2740001,0x7C004A,0x7C004A,0x84740001,0x6E740001,0x62740001,0x62740001,0x54740001,0xC2600000,0x86680000,0x4E700001,0x4E5C0001,
-0x10C0048,};
-static const uint32_t g_etc1_to_bc7_m6_table42[] = {
-0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0x1880000,
-0x1880000,0x1880000,0x1880000,0x40000000,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0xC880000,0xC880000,0xC880000,0xC00000,0x1140000,0x980001,0x980001,0x980001,0x980001,0x980001,0x980001,0x980001,0x980001,0x980001,0x980001,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,
-0xE40000,0x1D00000,0x1D00000,0x1D00000,0x4C000000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0x1D00000,0x1D00000,0x1D00000,0x4C000000,0x1D00000,0x1D00000,0x1D00000,0x4C000000,0x4C000000,0xA40000,0x980001,0x980001,0xB40000,0xC00000,0xD00000,0xD00000,0x3000000,0xB40000,0xC00000,0x1480000,0x1D00000,
-0x1480000,0xAC0001,0xAC0001,0xAC0001,0xAC0001,0x3000000,0x3000000,0x3000000,0x5FC0000,0x5FC0000,0x56000000,0x3000000,0x3000000,0x3000000,0x5FC0000,0x5FC0000,0x56000000,0x5FC0000,0x5FC0000,0x56000000,0x56000000,0x3000000,0x3000000,0x3000000,0x5FC0000,0x5FC0000,0x56000000,0x5FC0000,0x5FC0000,0x56000000,0x56000000,0x5FC0000,
-0x5FC0000,0x56000000,0x56000000,0x56000000,0x4C80000,0x4B80000,0xAC0001,0xEC0000,0x1240000,0x1700000,0x1A80000,0x1BF80000,0x2D80000,0x3000000,0x1700000,0x56000000,0x1700000,0xC40001,0x3240000,0x17FC0000,0x62000000,0x3240000,0x17FC0000,0x62000000,0x17FC0000,0x62000000,0x62000000,0x3240000,0x17FC0000,0x62000000,0x17FC0000,0x62000000,
-0x62000000,0x17FC0000,0x62000000,0x62000000,0x62000000,0x3240000,0x17FC0000,0x62000000,0x17FC0000,0x62000000,0x62000000,0x17FC0000,0x62000000,0x62000000,0x62000000,0x17FC0000,0x62000000,0x62000000,0x62000000,0x62000000,0xF80000,0xD40000,0xD40000,0x14C0000,0x1E40000,0x3BFC0000,0x62000000,0x62000000,0x10C0000,0x1740000,0x59E40000,0x62000000,
-0x1A40000,0xA40274,0x909800F3,0x6C9800F4,0x629800F3,0x86900092,0x6E90004F,0x64900067,0x66900092,0x628C004E,0x5C8C0092,0x848400F4,0x72840033,0x64880051,0x6A80004A,0x62840002,0x5C84004D,0x628000F4,0x5E7C0053,0x5A7C0069,0x568000F5,0xF40274,0x786C00F3,0x628400F4,0x6E680092,0x62740049,0x5C780090,0x6C5800F3,0x62600032,0x5C60004D,0x566C00F4,0x1F00274,
-0x623800F3,0x5C340090,0x562800F4,0x50000278,0xDE840004,0xF498010A,0xF8A0015B,0x90840002,0x78840002,0x6A840002,0x62840006,0x60800006,0xDE6C0002,0x8E780000,0x647C0035,0x5C60004D,0x15C0274,0xB000F3,0x84A40032,0x6AA40032,0x62A40032,0x7A9C0049,0x6C980002,0x629C0005,0x64980049,0x6098000E,0x5C980049,0x10400F3,0x72840032,0x62940032,0x6A800049,0x62840001,
-0x5C880049,0x7FC00F3,0x625C0032,0x5C580048,0x560000F4,0x10400F3,0x72840032,0x62940032,0x6A800049,0x62840001,0x5C880049,0x7FC00F3,0x625C0032,0x5C580048,0x560000F4,0x7FC00F3,0x625C0032,0x5C580048,0x560000F4,0x560000F4,0xDE840003,0xF8A00059,0xFCA8004A,0x90840001,0x78840001,0x6A840001,0x628C0001,0x627C0004,0xE4680001,0x8E780000,0x64780033,0x5C580048,
-0x17400F3,0x9800F3,0x9800F3,0x9800F3,0x9800F3,0x7490004A,0x7490004A,0x7490004A,0x5E8C004A,0x5E8C004A,0x568C004A,0x72840033,0x72840033,0x72840033,0x60840002,0x60840002,0x5884000E,0x5A800033,0x5A800033,0x56800005,0x50800035,0xE000F3,0xE000F3,0xE000F3,0x62740049,0x62740049,0x567C004A,0x60640032,0x60640032,0x566C0001,0x52700034,0x1CC00F3,
-0x1CC00F3,0x564C0048,0x50400034,0x4C0000F4,0xDA840003,0xF090005A,0x9800F3,0x90840001,0x74840002,0x68840002,0x66840003,0x5E800001,0xCE700000,0x8E780000,0x60800033,0x566C0001,0x14000F3,0xA40032,0xA40032,0xA40032,0xA40032,0x689C0001,0x689C0001,0x689C0001,0x5A9C0001,0x5A9C0001,0x56980001,0xF40032,0xF40032,0xF40032,0x5E880001,0x5E880001,
-0x56900000,0x1F00032,0x1F00032,0x56700000,0x50000034,0xF40032,0xF40032,0xF40032,0x5E880001,0x5E880001,0x56900000,0x1F00032,0x1F00032,0x56700000,0x50000034,0x1F00032,0x1F00032,0x56700000,0x50000034,0x50000034,0xBC8C0000,0xD69C0001,0xA40032,0x90840000,0x6E8C0001,0x66880000,0x608C0001,0x5E800000,0xCE700000,0x887C0000,0x15C0032,0x56700000,
-0x15C0032,0xB8004A,0x78B00001,0x68AC0001,0x62AC0001,0x1140048,0x6C980001,0x62A00001,0xFF80048,0x627C0000,0x5C000048,0x1140048,0x6C980001,0x62A00001,0xFF80048,0x627C0000,0x5C000048,0xFF80048,0x627C0000,0x5C000048,0x5C000048,0x1140048,0x6C980001,0x62A00001,0xFF80048,0x627C0000,0x5C000048,0xFF80048,0x627C0000,0x5C000048,0x5C000048,0xFF80048,
-0x627C0000,0x5C000048,0x5C000048,0x5C000048,0xF27C0000,0xAC40048,0xF0B00002,0x94800000,0x78800001,0x6C7C0000,0x628C0000,0x62680000,0xE8640000,0x8E780000,0x64900000,0x5C000048,0x18C0048,0x8C004A,0x8C004A,0x8C004A,0x8C004A,0x8C004A,0x8C004A,0x8C004A,0x8C004A,0x8C004A,0x8C004A,0x62840001,0x62840001,0x62840001,0x62840001,0x62840001,
-0x62840001,0x52800001,0x52800001,0x52800001,0x4C800001,0x2D00048,0x2D00048,0x2D00048,0x2D00048,0x2D00048,0x2D00048,0x566C0001,0x566C0001,0x566C0001,0x4C740001,0x1AC0048,0x1AC0048,0x1AC0048,0x4C500000,0x46000048,0xEA840001,0x8C004A,0x8C004A,0x8C840001,0x76840001,0x6A840001,0x6A840001,0x5C840001,0xCA700000,0x8E780000,0x56800001,0x566C0001,
-0x12C0048,};
-static const uint32_t g_etc1_to_bc7_m6_table43[] = {
-0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0x1B80000,
-0x1B80000,0x1B80000,0x1B80000,0x48000000,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x9C0000,0x9C0000,0x9C0000,0xD80000,0x1340000,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,
-0xFC0000,0x3F80000,0x3F80000,0x3F80000,0x54000000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0x3F80000,0x3F80000,0x3F80000,0x54000000,0x3F80000,0x3F80000,0x3F80000,0x54000000,0x54000000,0x2B40000,0xA80001,0xA80001,0x2C40000,0xD40000,0xE80000,0xE80000,0x11C0000,0x2C40000,0xD40000,0x1680000,0x3F80000,
-0x1680000,0xBC0001,0xBC0001,0xBC0001,0xBC0001,0x3180000,0x3180000,0x3180000,0x11FC0000,0x11FC0000,0x5E000000,0x3180000,0x3180000,0x3180000,0x11FC0000,0x11FC0000,0x5E000000,0x11FC0000,0x11FC0000,0x5E000000,0x5E000000,0x3180000,0x3180000,0x3180000,0x11FC0000,0x11FC0000,0x5E000000,0x11FC0000,0x11FC0000,0x5E000000,0x5E000000,0x11FC0000,
-0x11FC0000,0x5E000000,0x5E000000,0x5E000000,0xDC0000,0xCC80000,0xBC0001,0x3000000,0x1400000,0x1940000,0x1D00000,0x25FC0000,0x2EC0000,0x3180000,0x1940000,0x5E000000,0x1940000,0xD40001,0x33C0000,0x23FC0000,0x6A000000,0x33C0000,0x23FC0000,0x6A000000,0x23FC0000,0x6A000000,0x6A000000,0x33C0000,0x23FC0000,0x6A000000,0x23FC0000,0x6A000000,
-0x6A000000,0x23FC0000,0x6A000000,0x6A000000,0x6A000000,0x33C0000,0x23FC0000,0x6A000000,0x23FC0000,0x6A000000,0x6A000000,0x23FC0000,0x6A000000,0x6A000000,0x6A000000,0x23FC0000,0x6A000000,0x6A000000,0x6A000000,0x6A000000,0x10C0000,0xE40000,0xE40000,0x1680000,0x7F80000,0x45FC0000,0x6A000000,0x6A000000,0x1240000,0x1900000,0x61F40000,0x6A000000,
-0x1C80000,0xB40274,0x98A800F3,0x74A800F4,0x6AA800F3,0x8EA00092,0x76A0004F,0x6CA00067,0x6EA00092,0x6A9C004E,0x649C0092,0x8C9400F4,0x7A940033,0x6C980051,0x7290004A,0x6A940002,0x6494004D,0x6A9000F4,0x668C0053,0x628C0069,0x5E9000F5,0x10C0274,0x807C00F3,0x6A9400F4,0x76780092,0x6A840049,0x64880090,0x746800F3,0x6A700032,0x6470004D,0x5E7C00F4,0xBF80274,
-0x6A4800F3,0x64440090,0x5E3800F4,0x58000278,0xE6940004,0xFCA8010A,0xFEAC015F,0x98940002,0x80940002,0x72940002,0x6A940006,0x68900006,0xE67C0002,0x96880000,0x6C8C0035,0x6470004D,0x17C0274,0xC000F3,0x8CB40032,0x72B40032,0x6AB40032,0x82AC0049,0x74A80002,0x6AAC0005,0x6CA80049,0x68A8000E,0x64A80049,0x11C00F3,0x7A940032,0x6AA40032,0x72900049,0x6A940001,
-0x64980049,0x13FC00F3,0x6A6C0032,0x64680048,0x5E0000F4,0x11C00F3,0x7A940032,0x6AA40032,0x72900049,0x6A940001,0x64980049,0x13FC00F3,0x6A6C0032,0x64680048,0x5E0000F4,0x13FC00F3,0x6A6C0032,0x64680048,0x5E0000F4,0x5E0000F4,0xE6940003,0xF0B00063,0xF4B80053,0x98940001,0x80940001,0x72940001,0x6A9C0001,0x6A8C0004,0xEC780001,0x96880000,0x6C880033,0x64680048,
-0x19800F3,0xA800F3,0xA800F3,0xA800F3,0xA800F3,0x7CA0004A,0x7CA0004A,0x7CA0004A,0x669C004A,0x669C004A,0x5E9C004A,0x7A940033,0x7A940033,0x7A940033,0x68940002,0x68940002,0x6094000E,0x62900033,0x62900033,0x5E900005,0x58900035,0xF800F3,0xF800F3,0xF800F3,0x6A840049,0x6A840049,0x5E8C004A,0x68740032,0x68740032,0x5E7C0001,0x5A800034,0x1FC00F3,
-0x1FC00F3,0x5E5C0048,0x58500034,0x540000F4,0xE2940003,0xF8A0005A,0xA800F3,0x98940001,0x7C940002,0x70940002,0x6E940003,0x66900001,0xD6800000,0x96880000,0x68900033,0x5E7C0001,0x16400F3,0xB40032,0xB40032,0xB40032,0xB40032,0x70AC0001,0x70AC0001,0x70AC0001,0x62AC0001,0x62AC0001,0x5EA80001,0x10C0032,0x10C0032,0x10C0032,0x66980001,0x66980001,
-0x5EA00000,0xBF80032,0xBF80032,0x5E800000,0x58000034,0x10C0032,0x10C0032,0x10C0032,0x66980001,0x66980001,0x5EA00000,0xBF80032,0xBF80032,0x5E800000,0x58000034,0xBF80032,0xBF80032,0x5E800000,0x58000034,0x58000034,0xC49C0000,0xDEAC0001,0xB40032,0x98940000,0x769C0001,0x6E980000,0x689C0001,0x66900000,0xD6800000,0x908C0000,0x17C0032,0x5E800000,
-0x17C0032,0xC8004A,0x80C00001,0x70BC0001,0x6ABC0001,0x12C0048,0x74A80001,0x6AB00001,0x1BF80048,0x6A8C0000,0x64000048,0x12C0048,0x74A80001,0x6AB00001,0x1BF80048,0x6A8C0000,0x64000048,0x1BF80048,0x6A8C0000,0x64000048,0x64000048,0x12C0048,0x74A80001,0x6AB00001,0x1BF80048,0x6A8C0000,0x64000048,0x1BF80048,0x6A8C0000,0x64000048,0x64000048,0x1BF80048,
-0x6A8C0000,0x64000048,0x64000048,0x64000048,0xFA8C0000,0xD80048,0xF8C00002,0x9C900000,0x80900001,0x748C0000,0x6A9C0000,0x6A780000,0xF0740000,0x96880000,0x6CA00000,0x64000048,0x1AC0048,0x9C004A,0x9C004A,0x9C004A,0x9C004A,0x9C004A,0x9C004A,0x9C004A,0x9C004A,0x9C004A,0x9C004A,0x6A940001,0x6A940001,0x6A940001,0x6A940001,0x6A940001,
-0x6A940001,0x5A900001,0x5A900001,0x5A900001,0x54900001,0x2E80048,0x2E80048,0x2E80048,0x2E80048,0x2E80048,0x2E80048,0x5E7C0001,0x5E7C0001,0x5E7C0001,0x54840001,0x1DC0048,0x1DC0048,0x1DC0048,0x54600000,0x4E000048,0xF2940001,0x9C004A,0x9C004A,0x94940001,0x7E940001,0x72940001,0x72940001,0x64940001,0xD2800000,0x96880000,0x5E900001,0x5E7C0001,
-0x1500048,};
-static const uint32_t g_etc1_to_bc7_m6_table44[] = {
-0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0x1F00000,
-0x1F00000,0x1F00000,0x1F00000,0x50000001,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xEAC0000,0xEAC0000,0xEAC0000,0xF40000,0x15C0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,
-0x1180000,0x11F80000,0x11F80000,0x11F80000,0x5C000001,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x11F80000,0x11F80000,0x11F80000,0x5C000001,0x11F80000,0x11F80000,0x11F80000,0x5C000001,0x5C000001,0xC80000,0xBC0000,0xBC0000,0x4D80000,0xEC0000,0x1000000,0x1000000,0x13C0000,0x4D80000,0xEC0000,0x1900000,0x11F80000,
-0x1900000,0xD00000,0xD00000,0xD00000,0xD00000,0x1340000,0x1340000,0x1340000,0x1FF80000,0x1FF80000,0x66000001,0x1340000,0x1340000,0x1340000,0x1FF80000,0x1FF80000,0x66000001,0x1FF80000,0x1FF80000,0x66000001,0x66000001,0x1340000,0x1340000,0x1340000,0x1FF80000,0x1FF80000,0x66000001,0x1FF80000,0x1FF80000,0x66000001,0x66000001,0x1FF80000,
-0x1FF80000,0x66000001,0x66000001,0x66000001,0x2F00000,0x6DC0000,0xD00000,0x3180000,0x15C0000,0x1B80000,0x1FC0000,0x33F40000,0x1040000,0x1340000,0x1B80000,0x66000001,0x1B80000,0xE80000,0x1580000,0x31F80000,0x72000001,0x1580000,0x31F80000,0x72000001,0x31F80000,0x72000001,0x72000001,0x1580000,0x31F80000,0x72000001,0x31F80000,0x72000001,
-0x72000001,0x31F80000,0x72000001,0x72000001,0x72000001,0x1580000,0x31F80000,0x72000001,0x31F80000,0x72000001,0x72000001,0x31F80000,0x72000001,0x72000001,0x72000001,0x31F80000,0x72000001,0x72000001,0x72000001,0x72000001,0x5200000,0xF80000,0xF80000,0x1840000,0x15FC0000,0x51F80000,0x72000001,0x72000001,0x13C0000,0x1B40000,0x6BE80000,0x72000001,
-0x1EC0000,0xC40278,0xA0BC00F4,0x7EBC00F4,0x72BC00F5,0x9AB00090,0x82B0004D,0x76B40069,0x78B00090,0x72B0004D,0x6CB00092,0x96A400F3,0x84A40032,0x76AC0053,0x7AA40049,0x72A40002,0x6EA4004E,0x72A400F4,0x70A00051,0x6CA00067,0x68A400F3,0x3240274,0x889000F3,0x72A400F4,0x80880092,0x7494004A,0x6C9C0092,0x7E7800F3,0x72840033,0x6C84004F,0x688C00F4,0x17FC0274,
-0x726000F4,0x6C580092,0x684400F3,0x62000274,0xF6A40005,0xF6BC0120,0xF8C0016C,0xA4A40000,0x8AA40001,0x7AA40002,0x74A80006,0x72A40006,0xEE8C0002,0x9C9C0002,0x74A00035,0x6C84004F,0x1A40274,0xD000F4,0x94C80034,0x7CC40034,0x72C40035,0x8EBC0048,0x7CBC0001,0x74BC0005,0x74BC004A,0x72B8000E,0x6CBC004A,0x13800F3,0x82A80032,0x74B40033,0x7AA40049,0x72A40002,
-0x6CAC004A,0x21F800F3,0x72840033,0x6C7C004A,0x680000F3,0x13800F3,0x82A80032,0x74B40033,0x7AA40049,0x72A40002,0x6CAC004A,0x21F800F3,0x72840033,0x6C7C004A,0x680000F3,0x21F800F3,0x72840033,0x6C7C004A,0x680000F3,0x680000F3,0xEAA80003,0xFAC40060,0xFECC0054,0xA4A40000,0x8AA40001,0x7AA40002,0x74AC0001,0x729C0003,0xEE8C0001,0x9C9C0001,0x76980032,0x6C7C004A,
-0x1BC00F3,0xBC00F4,0xBC00F4,0xBC00F4,0xBC00F4,0x88B00048,0x88B00048,0x88B00048,0x6EB00049,0x6EB00049,0x66B00049,0x84A40032,0x84A40032,0x84A40032,0x72A40001,0x72A40001,0x68A8000E,0x6AA40032,0x6AA40032,0x66A40005,0x62A40032,0x11400F3,0x11400F3,0x11400F3,0x74940049,0x74940049,0x66A00049,0x72840032,0x72840032,0x66900002,0x62940032,0xFF800F3,
-0xFF800F3,0x66700049,0x625C0032,0x5C0000F3,0xEAA40004,0xF2B40060,0xBC00F4,0xA4A40000,0x86A40001,0x7AA40001,0x76A40004,0x6EA40001,0xE4900000,0x9C9C0001,0x72A00032,0x66900002,0x18C00F3,0xC40034,0xC40034,0xC40034,0xC40034,0x7ABC0000,0x7ABC0000,0x7ABC0000,0x6CBC0000,0x6CBC0000,0x66BC0001,0x3240032,0x3240032,0x3240032,0x6EAC0001,0x6EAC0001,
-0x66B40001,0x17FC0032,0x17FC0032,0x66980001,0x62000032,0x3240032,0x3240032,0x3240032,0x6EAC0001,0x6EAC0001,0x66B40001,0x17FC0032,0x17FC0032,0x66980001,0x62000032,0x17FC0032,0x17FC0032,0x66980001,0x62000032,0x62000032,0xD2AC0000,0xF6BC0000,0xC40034,0xA4A40000,0x84A80000,0x78A80000,0x74AC0000,0x6EA40001,0xE4900000,0x9C9C0000,0x1A40032,0x66980001,
-0x1A40032,0xDC0048,0x8CD00000,0x78D00001,0x72D00001,0x3440048,0x7CBC0001,0x72C40001,0x27FC0048,0x72A00001,0x6C00004A,0x3440048,0x7CBC0001,0x72C40001,0x27FC0048,0x72A00001,0x6C00004A,0x27FC0048,0x72A00001,0x6C00004A,0x6C00004A,0x3440048,0x7CBC0001,0x72C40001,0x27FC0048,0x72A00001,0x6C00004A,0x27FC0048,0x72A00001,0x6C00004A,0x6C00004A,0x27FC0048,
-0x72A00001,0x6C00004A,0x6C00004A,0x6C00004A,0xF6A40001,0xCE80048,0xF2D40005,0xA4A40000,0x88A40001,0x7CA00000,0x72B00001,0x72900001,0xF6880000,0xA0980000,0x74B40001,0x6C00004A,0x1D40048,0xB00048,0xB00048,0xB00048,0xB00048,0xB00048,0xB00048,0xB00048,0xB00048,0xB00048,0xB00048,0x76A40000,0x76A40000,0x76A40000,0x76A40000,0x76A40000,
-0x76A40000,0x62A40001,0x62A40001,0x62A40001,0x5CA40001,0x1040048,0x1040048,0x1040048,0x1040048,0x1040048,0x1040048,0x66900001,0x66900001,0x66900001,0x5C980001,0x7FC0048,0x7FC0048,0x7FC0048,0x5C740001,0x5600004A,0xFAA40001,0xB00048,0xB00048,0xA4A40000,0x8AA40000,0x7EA40000,0x7EA40000,0x6EA40000,0xE0900000,0xA4980000,0x6AA00000,0x66900001,
-0x1740048,};
-static const uint32_t g_etc1_to_bc7_m6_table45[] = {
-0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0xBF80000,
-0xBF80000,0xBF80000,0xBF80000,0x58000001,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xC00000,0xC00000,0xC00000,0x10C0000,0x17C0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,
-0x1300000,0x1DF40000,0x1DF40000,0x1DF40000,0x64000001,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1DF40000,0x1DF40000,0x1DF40000,0x64000001,0x1DF40000,0x1DF40000,0x1DF40000,0x64000001,0x64000001,0x4D80000,0xCC0000,0xCC0000,0xEC0000,0x1000000,0x1140000,0x1140000,0x3540000,0xEC0000,0x1000000,0x1B00000,0x1DF40000,
-0x1B00000,0xE00000,0xE00000,0xE00000,0xE00000,0x14C0000,0x14C0000,0x14C0000,0x2BF80000,0x2BF80000,0x6E000001,0x14C0000,0x14C0000,0x14C0000,0x2BF80000,0x2BF80000,0x6E000001,0x2BF80000,0x2BF80000,0x6E000001,0x6E000001,0x14C0000,0x14C0000,0x14C0000,0x2BF80000,0x2BF80000,0x6E000001,0x2BF80000,0x2BF80000,0x6E000001,0x6E000001,0x2BF80000,
-0x2BF80000,0x6E000001,0x6E000001,0x6E000001,0x1040000,0xEEC0000,0xE00000,0x1300000,0x1780000,0x1DC0000,0xFFC0000,0x3DF80000,0x1180000,0x14C0000,0x1DC0000,0x6E000001,0x1DC0000,0xF80000,0x1700000,0x3DF80000,0x7A000001,0x1700000,0x3DF80000,0x7A000001,0x3DF80000,0x7A000001,0x7A000001,0x1700000,0x3DF80000,0x7A000001,0x3DF80000,0x7A000001,
-0x7A000001,0x3DF80000,0x7A000001,0x7A000001,0x7A000001,0x1700000,0x3DF80000,0x7A000001,0x3DF80000,0x7A000001,0x7A000001,0x3DF80000,0x7A000001,0x7A000001,0x7A000001,0x3DF80000,0x7A000001,0x7A000001,0x7A000001,0x7A000001,0x5340000,0x1080000,0x1080000,0x1A00000,0x23FC0000,0x5BF80000,0x7A000001,0x7A000001,0x1500000,0x1D00000,0x73F80000,0x7A000001,
-0x9FC0000,0xD40278,0xA8CC00F4,0x86CC00F4,0x7ACC00F5,0xA2C00090,0x8AC0004D,0x7EC40069,0x80C00090,0x7AC0004D,0x74C00092,0x9EB400F3,0x8CB40032,0x7EBC0053,0x82B40049,0x7AB40002,0x76B4004E,0x7AB400F4,0x78B00051,0x74B00067,0x70B400F3,0x33C0274,0x90A000F3,0x7AB400F4,0x88980092,0x7CA4004A,0x74AC0092,0x868800F3,0x7A940033,0x7494004F,0x709C00F4,0x23FC0274,
-0x7A7000F4,0x74680092,0x705400F3,0x6A000274,0xFEB40005,0xFECC0120,0xF0D00181,0xACB40000,0x92B40001,0x82B40002,0x7CB80006,0x7AB40006,0xF69C0002,0xA4AC0002,0x7CB00035,0x7494004F,0x1C80274,0xE000F4,0x9CD80034,0x84D40034,0x7AD40035,0x96CC0048,0x84CC0001,0x7CCC0005,0x7CCC004A,0x7AC8000E,0x74CC004A,0x15000F3,0x8AB80032,0x7CC40033,0x82B40049,0x7AB40002,
-0x74BC004A,0x2DF800F3,0x7A940033,0x748C004A,0x700000F3,0x15000F3,0x8AB80032,0x7CC40033,0x82B40049,0x7AB40002,0x74BC004A,0x2DF800F3,0x7A940033,0x748C004A,0x700000F3,0x2DF800F3,0x7A940033,0x748C004A,0x700000F3,0x700000F3,0xF2B80003,0xF2D4006A,0xF6DC005D,0xACB40000,0x92B40001,0x82B40002,0x7CBC0001,0x7AAC0003,0xF69C0001,0xA4AC0001,0x7EA80032,0x748C004A,
-0x1E000F3,0xCC00F4,0xCC00F4,0xCC00F4,0xCC00F4,0x90C00048,0x90C00048,0x90C00048,0x76C00049,0x76C00049,0x6EC00049,0x8CB40032,0x8CB40032,0x8CB40032,0x7AB40001,0x7AB40001,0x70B8000E,0x72B40032,0x72B40032,0x6EB40005,0x6AB40032,0x12C00F3,0x12C00F3,0x12C00F3,0x7CA40049,0x7CA40049,0x6EB00049,0x7A940032,0x7A940032,0x6EA00002,0x6AA40032,0x1BF800F3,
-0x1BF800F3,0x6E800049,0x6A6C0032,0x640000F3,0xF2B40004,0xFAC40060,0xCC00F4,0xACB40000,0x8EB40001,0x82B40001,0x7EB40004,0x76B40001,0xECA00000,0xA4AC0001,0x7AB00032,0x6EA00002,0x1AC00F3,0xD40034,0xD40034,0xD40034,0xD40034,0x82CC0000,0x82CC0000,0x82CC0000,0x74CC0000,0x74CC0000,0x6ECC0001,0x33C0032,0x33C0032,0x33C0032,0x76BC0001,0x76BC0001,
-0x6EC40001,0x23FC0032,0x23FC0032,0x6EA80001,0x6A000032,0x33C0032,0x33C0032,0x33C0032,0x76BC0001,0x76BC0001,0x6EC40001,0x23FC0032,0x23FC0032,0x6EA80001,0x6A000032,0x23FC0032,0x23FC0032,0x6EA80001,0x6A000032,0x6A000032,0xDABC0000,0xFECC0000,0xD40034,0xACB40000,0x8CB80000,0x80B80000,0x7CBC0000,0x76B40001,0xECA00000,0xA4AC0000,0x1C80032,0x6EA80001,
-0x1C80032,0xEC0048,0x94E00000,0x80E00001,0x7AE00001,0x35C0048,0x84CC0001,0x7AD40001,0x33FC0048,0x7AB00001,0x7400004A,0x35C0048,0x84CC0001,0x7AD40001,0x33FC0048,0x7AB00001,0x7400004A,0x33FC0048,0x7AB00001,0x7400004A,0x7400004A,0x35C0048,0x84CC0001,0x7AD40001,0x33FC0048,0x7AB00001,0x7400004A,0x33FC0048,0x7AB00001,0x7400004A,0x7400004A,0x33FC0048,
-0x7AB00001,0x7400004A,0x7400004A,0x7400004A,0xFEB40001,0xFC0048,0xFAE40005,0xACB40000,0x90B40001,0x84B00000,0x7AC00001,0x7AA00001,0xFE980000,0xA8A80000,0x7CC40001,0x7400004A,0x1F40048,0xC00048,0xC00048,0xC00048,0xC00048,0xC00048,0xC00048,0xC00048,0xC00048,0xC00048,0xC00048,0x7EB40000,0x7EB40000,0x7EB40000,0x7EB40000,0x7EB40000,
-0x7EB40000,0x6AB40001,0x6AB40001,0x6AB40001,0x64B40001,0x11C0048,0x11C0048,0x11C0048,0x11C0048,0x11C0048,0x11C0048,0x6EA00001,0x6EA00001,0x6EA00001,0x64A80001,0x13FC0048,0x13FC0048,0x13FC0048,0x64840001,0x5E00004A,0xF2B40004,0xC00048,0xC00048,0xACB40000,0x92B40000,0x86B40000,0x86B40000,0x76B40000,0xE8A00000,0xACA80000,0x72B00000,0x6EA00001,
-0x1980048,};
-static const uint32_t g_etc1_to_bc7_m6_table46[] = {
-0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x17F80000,
-0x17F80000,0x17F80000,0x17F80000,0x60000001,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xD00000,0xD00000,0xD00000,0x1240000,0x1A00000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0x3440000,0x3440000,0x3440000,0x3440000,0x3440000,
-0x3440000,0x27FC0000,0x27FC0000,0x27FC0000,0x6C000001,0x3440000,0x3440000,0x3440000,0x3440000,0x3440000,0x3440000,0x27FC0000,0x27FC0000,0x27FC0000,0x6C000001,0x27FC0000,0x27FC0000,0x27FC0000,0x6C000001,0x6C000001,0xCE80000,0xDC0000,0xDC0000,0x1000000,0x1140000,0x12C0000,0x12C0000,0x1700000,0x1000000,0x1140000,0x1D40000,0x27FC0000,
-0x1D40000,0xF00000,0xF00000,0xF00000,0xF00000,0x1640000,0x1640000,0x1640000,0x37F80000,0x37F80000,0x76000001,0x1640000,0x1640000,0x1640000,0x37F80000,0x37F80000,0x76000001,0x37F80000,0x37F80000,0x76000001,0x76000001,0x1640000,0x1640000,0x1640000,0x37F80000,0x37F80000,0x76000001,0x37F80000,0x37F80000,0x76000001,0x76000001,0x37F80000,
-0x37F80000,0x76000001,0x76000001,0x76000001,0x1180000,0x1000000,0xF00000,0x3440000,0x1940000,0x1FC0000,0x1DF80000,0x47FC0000,0x12C0000,0x1640000,0x1FC0000,0x76000001,0x1FC0000,0x1080000,0x1880000,0x49F80000,0x82000001,0x1880000,0x49F80000,0x82000001,0x49F80000,0x82000001,0x82000001,0x1880000,0x49F80000,0x82000001,0x49F80000,0x82000001,
-0x82000001,0x49F80000,0x82000001,0x82000001,0x82000001,0x1880000,0x49F80000,0x82000001,0x49F80000,0x82000001,0x82000001,0x49F80000,0x82000001,0x82000001,0x82000001,0x49F80000,0x82000001,0x82000001,0x82000001,0x82000001,0x14C0000,0x5180000,0x5180000,0x1BC0000,0x31FC0000,0x65F80000,0x82000001,0x82000001,0x1680000,0x1F00000,0x7DCC0000,0x82000001,
-0x19FC0000,0xE40278,0xB0DC00F4,0x8EDC00F4,0x82DC00F5,0xAAD00090,0x92D0004D,0x86D40069,0x88D00090,0x82D0004D,0x7CD00092,0xA6C400F3,0x94C40032,0x86CC0053,0x8AC40049,0x82C40002,0x7EC4004E,0x82C400F4,0x80C00051,0x7CC00067,0x78C400F3,0x1540274,0x98B000F3,0x82C400F4,0x90A80092,0x84B4004A,0x7CBC0092,0x8E9800F3,0x82A40033,0x7CA4004F,0x78AC00F4,0x2FFC0274,
-0x828000F4,0x7C780092,0x786400F3,0x72000274,0xFAC80007,0xF6DC013A,0xF8E00181,0xB4C40000,0x9AC40001,0x8AC40002,0x84C80006,0x82C40006,0xFEAC0002,0xACBC0002,0x84C00035,0x7CA4004F,0x1E80274,0xF000F4,0xA4E80034,0x8CE40034,0x82E40035,0x9EDC0048,0x8CDC0001,0x84DC0005,0x84DC004A,0x82D8000E,0x7CDC004A,0x16800F3,0x92C80032,0x84D40033,0x8AC40049,0x82C40002,
-0x7CCC004A,0x39F800F3,0x82A40033,0x7C9C004A,0x780000F3,0x16800F3,0x92C80032,0x84D40033,0x8AC40049,0x82C40002,0x7CCC004A,0x39F800F3,0x82A40033,0x7C9C004A,0x780000F3,0x39F800F3,0x82A40033,0x7C9C004A,0x780000F3,0x780000F3,0xFAC80003,0xFAE4006A,0xFEEC005D,0xB4C40000,0x9AC40001,0x8AC40002,0x84CC0001,0x82BC0003,0xFEAC0001,0xACBC0001,0x86B80032,0x7C9C004A,
-0x3FC00F3,0xDC00F4,0xDC00F4,0xDC00F4,0xDC00F4,0x98D00048,0x98D00048,0x98D00048,0x7ED00049,0x7ED00049,0x76D00049,0x94C40032,0x94C40032,0x94C40032,0x82C40001,0x82C40001,0x78C8000E,0x7AC40032,0x7AC40032,0x76C40005,0x72C40032,0x14400F3,0x14400F3,0x14400F3,0x84B40049,0x84B40049,0x76C00049,0x82A40032,0x82A40032,0x76B00002,0x72B40032,0x27F800F3,
-0x27F800F3,0x76900049,0x727C0032,0x6C0000F3,0xFAC40004,0xF2D40069,0xDC00F4,0xB4C40000,0x96C40001,0x8AC40001,0x86C40004,0x7EC40001,0xF4B00000,0xACBC0001,0x82C00032,0x76B00002,0x1D000F3,0xE40034,0xE40034,0xE40034,0xE40034,0x8ADC0000,0x8ADC0000,0x8ADC0000,0x7CDC0000,0x7CDC0000,0x76DC0001,0x1540032,0x1540032,0x1540032,0x7ECC0001,0x7ECC0001,
-0x76D40001,0x2FFC0032,0x2FFC0032,0x76B80001,0x72000032,0x1540032,0x1540032,0x1540032,0x7ECC0001,0x7ECC0001,0x76D40001,0x2FFC0032,0x2FFC0032,0x76B80001,0x72000032,0x2FFC0032,0x2FFC0032,0x76B80001,0x72000032,0x72000032,0xE2CC0000,0xF6DC0001,0xE40034,0xB4C40000,0x94C80000,0x88C80000,0x84CC0000,0x7EC40001,0xF4B00000,0xACBC0000,0x1E80032,0x76B80001,
-0x1E80032,0xFC0048,0x9CF00000,0x88F00001,0x82F00001,0x3740048,0x8CDC0001,0x82E40001,0x3FFC0048,0x82C00001,0x7C00004A,0x3740048,0x8CDC0001,0x82E40001,0x3FFC0048,0x82C00001,0x7C00004A,0x3FFC0048,0x82C00001,0x7C00004A,0x7C00004A,0x3740048,0x8CDC0001,0x82E40001,0x3FFC0048,0x82C00001,0x7C00004A,0x3FFC0048,0x82C00001,0x7C00004A,0x7C00004A,0x3FFC0048,
-0x82C00001,0x7C00004A,0x7C00004A,0x7C00004A,0xFAC80002,0x10C0048,0xF2F40008,0xB4C40000,0x98C40001,0x8CC00000,0x82D00001,0x82B00001,0xFEAC0001,0xB0B80000,0x84D40001,0x7C00004A,0xDFC0048,0xD00048,0xD00048,0xD00048,0xD00048,0xD00048,0xD00048,0xD00048,0xD00048,0xD00048,0xD00048,0x86C40000,0x86C40000,0x86C40000,0x86C40000,0x86C40000,
-0x86C40000,0x72C40001,0x72C40001,0x72C40001,0x6CC40001,0x1340048,0x1340048,0x1340048,0x1340048,0x1340048,0x1340048,0x76B00001,0x76B00001,0x76B00001,0x6CB80001,0x1FF80048,0x1FF80048,0x1FF80048,0x6C940001,0x6600004A,0xFAC40004,0xD00048,0xD00048,0xB4C40000,0x9AC40000,0x8EC40000,0x8EC40000,0x7EC40000,0xF0B00000,0xB4B80000,0x7AC00000,0x76B00001,
-0x1B80048,};
-static const uint32_t g_etc1_to_bc7_m6_table47[] = {
-0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x21FC0000,
-0x21FC0000,0x21FC0000,0x21FC0000,0x68000001,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0x8E00000,0x8E00000,0x8E00000,0x13C0000,0x1C00000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,
-0x35C0000,0x33FC0000,0x33FC0000,0x33FC0000,0x74000001,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x33FC0000,0x33FC0000,0x33FC0000,0x74000001,0x33FC0000,0x33FC0000,0x33FC0000,0x74000001,0x74000001,0xFC0000,0xEC0000,0xEC0000,0x5100000,0x1280000,0x1400000,0x1400000,0x18C0000,0x5100000,0x1280000,0x1F40000,0x33FC0000,
-0x1F40000,0x1000000,0x1000000,0x1000000,0x1000000,0x17C0000,0x17C0000,0x17C0000,0x43F80000,0x43F80000,0x7E000001,0x17C0000,0x17C0000,0x17C0000,0x43F80000,0x43F80000,0x7E000001,0x43F80000,0x43F80000,0x7E000001,0x7E000001,0x17C0000,0x17C0000,0x17C0000,0x43F80000,0x43F80000,0x7E000001,0x43F80000,0x43F80000,0x7E000001,0x7E000001,0x43F80000,
-0x43F80000,0x7E000001,0x7E000001,0x7E000001,0x3280000,0x1100000,0x1000000,0x15C0000,0x3AC0000,0x11FC0000,0x29FC0000,0x53F80000,0x1400000,0x17C0000,0x11FC0000,0x7E000001,0x11FC0000,0x1180000,0x1A00000,0x55F80000,0x8A000001,0x1A00000,0x55F80000,0x8A000001,0x55F80000,0x8A000001,0x8A000001,0x1A00000,0x55F80000,0x8A000001,0x55F80000,0x8A000001,
-0x8A000001,0x55F80000,0x8A000001,0x8A000001,0x8A000001,0x1A00000,0x55F80000,0x8A000001,0x55F80000,0x8A000001,0x8A000001,0x55F80000,0x8A000001,0x8A000001,0x8A000001,0x55F80000,0x8A000001,0x8A000001,0x8A000001,0x8A000001,0x1600000,0xD280000,0xD280000,0x3D40000,0x3FF80000,0x6FF80000,0x8A000001,0x8A000001,0x17C0000,0xBFC0000,0x85DC0000,0x8A000001,
-0x27FC0000,0xF40278,0xB8EC00F4,0x96EC00F4,0x8AEC00F5,0xB2E00090,0x9AE0004D,0x8EE40069,0x90E00090,0x8AE0004D,0x84E00092,0xAED400F3,0x9CD40032,0x8EDC0053,0x92D40049,0x8AD40002,0x86D4004E,0x8AD400F4,0x88D00051,0x84D00067,0x80D400F3,0x16C0274,0xA0C000F3,0x8AD400F4,0x98B80092,0x8CC4004A,0x84CC0092,0x96A800F3,0x8AB40033,0x84B4004F,0x80BC00F4,0x3BFC0274,
-0x8A9000F4,0x84880092,0x807400F3,0x7A000274,0xFED8000A,0xFEEC013A,0xF0F00198,0xBCD40000,0xA2D40001,0x92D40002,0x8CD80006,0x8AD40006,0xFCC00004,0xB4CC0002,0x8CD00035,0x84B4004F,0x7FC0274,0x10000F4,0xACF80034,0x94F40034,0x8AF40035,0xA6EC0048,0x94EC0001,0x8CEC0005,0x8CEC004A,0x8AE8000E,0x84EC004A,0x18000F3,0x9AD80032,0x8CE40033,0x92D40049,0x8AD40002,
-0x84DC004A,0x45F800F3,0x8AB40033,0x84AC004A,0x800000F3,0x18000F3,0x9AD80032,0x8CE40033,0x92D40049,0x8AD40002,0x84DC004A,0x45F800F3,0x8AB40033,0x84AC004A,0x800000F3,0x45F800F3,0x8AB40033,0x84AC004A,0x800000F3,0x800000F3,0xF6DC0006,0xF4F80074,0xF6FC0068,0xBCD40000,0xA2D40001,0x92D40002,0x8CDC0001,0x8ACC0003,0xFCC00004,0xB4CC0001,0x8EC80032,0x84AC004A,
-0x13FC00F3,0xEC00F4,0xEC00F4,0xEC00F4,0xEC00F4,0xA0E00048,0xA0E00048,0xA0E00048,0x86E00049,0x86E00049,0x7EE00049,0x9CD40032,0x9CD40032,0x9CD40032,0x8AD40001,0x8AD40001,0x80D8000E,0x82D40032,0x82D40032,0x7ED40005,0x7AD40032,0x15C00F3,0x15C00F3,0x15C00F3,0x8CC40049,0x8CC40049,0x7ED00049,0x8AB40032,0x8AB40032,0x7EC00002,0x7AC40032,0x33F800F3,
-0x33F800F3,0x7EA00049,0x7A8C0032,0x740000F3,0xF6D80005,0xFAE40069,0xEC00F4,0xBCD40000,0x9ED40001,0x92D40001,0x8ED40004,0x86D40001,0xFCC00000,0xB4CC0001,0x8AD00032,0x7EC00002,0x1F000F3,0xF40034,0xF40034,0xF40034,0xF40034,0x92EC0000,0x92EC0000,0x92EC0000,0x84EC0000,0x84EC0000,0x7EEC0001,0x16C0032,0x16C0032,0x16C0032,0x86DC0001,0x86DC0001,
-0x7EE40001,0x3BFC0032,0x3BFC0032,0x7EC80001,0x7A000032,0x16C0032,0x16C0032,0x16C0032,0x86DC0001,0x86DC0001,0x7EE40001,0x3BFC0032,0x3BFC0032,0x7EC80001,0x7A000032,0x3BFC0032,0x3BFC0032,0x7EC80001,0x7A000032,0x7A000032,0xEADC0000,0xFEEC0001,0xF40034,0xBCD40000,0x9CD80000,0x90D80000,0x8CDC0000,0x86D40001,0xFCC00000,0xB4CC0000,0x7FC0032,0x7EC80001,
-0x7FC0032,0x10C0048,0xA5000000,0x91000001,0x8B000001,0x38C0048,0x94EC0001,0x8AF40001,0x4BFC0048,0x8AD00001,0x8400004A,0x38C0048,0x94EC0001,0x8AF40001,0x4BFC0048,0x8AD00001,0x8400004A,0x4BFC0048,0x8AD00001,0x8400004A,0x8400004A,0x38C0048,0x94EC0001,0x8AF40001,0x4BFC0048,0x8AD00001,0x8400004A,0x4BFC0048,0x8AD00001,0x8400004A,0x8400004A,0x4BFC0048,
-0x8AD00001,0x8400004A,0x8400004A,0x8400004A,0xF2E00005,0x71C0048,0xFB040008,0xBCD40000,0xA0D40001,0x94D00000,0x8AE00001,0x8AC00001,0xF4C80002,0xB8C80000,0x8CE40001,0x8400004A,0x1DF80048,0xE00048,0xE00048,0xE00048,0xE00048,0xE00048,0xE00048,0xE00048,0xE00048,0xE00048,0xE00048,0x8ED40000,0x8ED40000,0x8ED40000,0x8ED40000,0x8ED40000,
-0x8ED40000,0x7AD40001,0x7AD40001,0x7AD40001,0x74D40001,0x14C0048,0x14C0048,0x14C0048,0x14C0048,0x14C0048,0x14C0048,0x7EC00001,0x7EC00001,0x7EC00001,0x74C80001,0x2BF80048,0x2BF80048,0x2BF80048,0x74A40001,0x6E00004A,0xF4D80005,0xE00048,0xE00048,0xBCD40000,0xA2D40000,0x96D40000,0x96D40000,0x86D40000,0xF8C00000,0xBCC80000,0x82D00000,0x7EC00001,
-0x1DC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table48[] = {
-0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x2FFC0000,
-0x2FFC0000,0x2FFC0000,0x2FFC0000,0x72000000,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0x2F40000,0x2F40000,0x2F40000,0x1540000,0x1E80000,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,
-0x1780000,0x41FC0000,0x41FC0000,0x41FC0000,0x7E000000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x41FC0000,0x41FC0000,0x41FC0000,0x7E000000,0x41FC0000,0x41FC0000,0x41FC0000,0x7E000000,0x7E000000,0xF0C0000,0xFC0001,0xFC0001,0x1280000,0x33C0000,0x1580000,0x1580000,0x1AC0000,0x1280000,0x33C0000,0xFFC0000,0x41FC0000,
-0xFFC0000,0x1100001,0x1100001,0x1100001,0x1100001,0x1980000,0x1980000,0x1980000,0x51F80000,0x51F80000,0x88000000,0x1980000,0x1980000,0x1980000,0x51F80000,0x51F80000,0x88000000,0x51F80000,0x51F80000,0x88000000,0x88000000,0x1980000,0x1980000,0x1980000,0x51F80000,0x51F80000,0x88000000,0x51F80000,0x51F80000,0x88000000,0x88000000,0x51F80000,
-0x51F80000,0x88000000,0x88000000,0x88000000,0x73C0000,0x1240000,0x1100001,0x1740000,0x1CC0000,0x21FC0000,0x39FC0000,0x5FF80000,0x1580000,0x1980000,0x21FC0000,0x88000000,0x21FC0000,0x1280001,0x1BC0000,0x61FC0000,0x94000000,0x1BC0000,0x61FC0000,0x94000000,0x61FC0000,0x94000000,0x94000000,0x1BC0000,0x61FC0000,0x94000000,0x61FC0000,0x94000000,
-0x94000000,0x61FC0000,0x94000000,0x94000000,0x94000000,0x1BC0000,0x61FC0000,0x94000000,0x61FC0000,0x94000000,0x94000000,0x61FC0000,0x94000000,0x94000000,0x94000000,0x61FC0000,0x94000000,0x94000000,0x94000000,0x94000000,0x3740000,0x73C0000,0x73C0000,0x1F40000,0x4DFC0000,0x7BF40000,0x94000000,0x94000000,0x1940000,0x1DFC0000,0x8FD00000,0x94000000,
-0x39FC0000,0x1080274,0xC2FC00F3,0x9EFC00F4,0x94FC00F3,0xB8F40092,0xA0F4004F,0x96F40067,0x98F40092,0x94F0004E,0x8EF00092,0xB6E800F4,0xA4E80033,0x96EC0051,0x9CE4004A,0x94E80002,0x8EE8004D,0x94E400F4,0x90E00053,0x8CE00069,0x88E400F5,0x1880274,0xAAD000F3,0x94E800F4,0xA0CC0092,0x94D80049,0x8EDC0090,0x9EBC00F3,0x94C40032,0x8EC4004D,0x88D000F4,0x49F80274,
-0x949C00F3,0x8E980090,0x888C00F4,0x82000278,0xFEEC0012,0xF9000154,0xFB040194,0xC2E80002,0xAAE80002,0x9CE80002,0x94E80006,0x92E40006,0xFCD80009,0xC0DC0000,0x96E00035,0x8EC4004D,0x19FC0274,0x11400F3,0xB7080032,0x9D080032,0x95080032,0xAD000049,0x9EFC0002,0x95000005,0x96FC0049,0x92FC000E,0x8EFC0049,0x39800F3,0xA4E80032,0x94F80032,0x9CE40049,0x94E80001,
-0x8EEC0049,0x51FC00F3,0x94C00032,0x8EBC0048,0x880000F4,0x39800F3,0xA4E80032,0x94F80032,0x9CE40049,0x94E80001,0x8EEC0049,0x51FC00F3,0x94C00032,0x8EBC0048,0x880000F4,0x51FC00F3,0x94C00032,0x8EBC0048,0x880000F4,0x880000F4,0xFAF00006,0xFD080073,0xFF0C006B,0xC2E80001,0xAAE80001,0x9CE80001,0x94F00001,0x94E00004,0xFCD80005,0xC0DC0000,0x96DC0033,0x8EBC0048,
-0x23FC00F3,0xFC00F3,0xFC00F3,0xFC00F3,0xFC00F3,0xA6F4004A,0xA6F4004A,0xA6F4004A,0x90F0004A,0x90F0004A,0x88F0004A,0xA4E80033,0xA4E80033,0xA4E80033,0x92E80002,0x92E80002,0x8AE8000E,0x8CE40033,0x8CE40033,0x88E40005,0x82E40035,0x37400F3,0x37400F3,0x37400F3,0x94D80049,0x94D80049,0x88E0004A,0x92C80032,0x92C80032,0x88D00001,0x84D40034,0x3FFC00F3,
-0x3FFC00F3,0x88B00048,0x82A40034,0x7E0000F4,0xFEE80006,0xF4F80073,0xFC00F3,0xC2E80001,0xA6E80002,0x9AE80002,0x98E80003,0x90E40001,0xFCD40001,0xC0DC0000,0x92E40033,0x88D00001,0xDFC00F3,0x1080032,0x1080032,0x1080032,0x1080032,0x9B000001,0x9B000001,0x9B000001,0x8D000001,0x8D000001,0x88FC0001,0x1880032,0x1880032,0x1880032,0x90EC0001,0x90EC0001,
-0x88F40000,0x49F80032,0x49F80032,0x88D40000,0x82000034,0x1880032,0x1880032,0x1880032,0x90EC0001,0x90EC0001,0x88F40000,0x49F80032,0x49F80032,0x88D40000,0x82000034,0x49F80032,0x49F80032,0x88D40000,0x82000034,0x82000034,0xEEF00000,0xF9000002,0x1080032,0xC2E80000,0xA0F00001,0x98EC0000,0x92F00001,0x90E40000,0xF0DC0001,0xBAE00000,0x19FC0032,0x88D40000,
-0x19FC0032,0x11C004A,0xAB140001,0x9B100001,0x95100001,0x1A80048,0x9EFC0001,0x95040001,0x59FC0048,0x94E00000,0x8E000048,0x1A80048,0x9EFC0001,0x95040001,0x59FC0048,0x94E00000,0x8E000048,0x59FC0048,0x94E00000,0x8E000048,0x8E000048,0x1A80048,0x9EFC0001,0x95040001,0x59FC0048,0x94E00000,0x8E000048,0x59FC0048,0x94E00000,0x8E000048,0x8E000048,0x59FC0048,
-0x94E00000,0x8E000048,0x8E000048,0x8E000048,0xFAF00005,0x1300048,0xF518000D,0xC6E40000,0xAAE40001,0x9EE00000,0x94F00000,0x94CC0000,0xFCD80004,0xC0DC0000,0x96F40000,0x8E000048,0x2DFC0048,0xF0004A,0xF0004A,0xF0004A,0xF0004A,0xF0004A,0xF0004A,0xF0004A,0xF0004A,0xF0004A,0xF0004A,0x94E80001,0x94E80001,0x94E80001,0x94E80001,0x94E80001,
-0x94E80001,0x84E40001,0x84E40001,0x84E40001,0x7EE40001,0x1680048,0x1680048,0x1680048,0x1680048,0x1680048,0x1680048,0x88D00001,0x88D00001,0x88D00001,0x7ED80001,0x39F80048,0x39F80048,0x39F80048,0x7EB40000,0x78000048,0xFCE80005,0xF0004A,0xF0004A,0xBEE80001,0xA8E80001,0x9CE80001,0x9CE80001,0x8EE80001,0xFCD40000,0xC0DC0000,0x88E40001,0x88D00001,
-0x3FC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table49[] = {
-0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x3BFC0000,
-0x3BFC0000,0x3BFC0000,0x3BFC0000,0x7A000000,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xB040000,0xB040000,0xB040000,0x16C0000,0x7FC0000,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,
-0x1900000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x86000000,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x86000000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x86000000,0x86000000,0x1200000,0x10C0001,0x10C0001,0x5380000,0x5500000,0x1700000,0x1700000,0x1C40000,0x5380000,0x5500000,0x1FF80000,0x4DFC0000,
-0x1FF80000,0x1200001,0x1200001,0x1200001,0x1200001,0x1B00000,0x1B00000,0x1B00000,0x5DF40000,0x5DF40000,0x90000000,0x1B00000,0x1B00000,0x1B00000,0x5DF40000,0x5DF40000,0x90000000,0x5DF40000,0x5DF40000,0x90000000,0x90000000,0x1B00000,0x1B00000,0x1B00000,0x5DF40000,0x5DF40000,0x90000000,0x5DF40000,0x5DF40000,0x90000000,0x90000000,0x5DF40000,
-0x5DF40000,0x90000000,0x90000000,0x90000000,0x1500000,0x3340000,0x1200001,0x3880000,0x1E80000,0x31FC0000,0x47F80000,0x69FC0000,0x16C0000,0x1B00000,0x31FC0000,0x90000000,0x31FC0000,0x1380001,0x3D00000,0x6DFC0000,0x9C000000,0x3D00000,0x6DFC0000,0x9C000000,0x6DFC0000,0x9C000000,0x9C000000,0x3D00000,0x6DFC0000,0x9C000000,0x6DFC0000,0x9C000000,
-0x9C000000,0x6DFC0000,0x9C000000,0x9C000000,0x9C000000,0x3D00000,0x6DFC0000,0x9C000000,0x6DFC0000,0x9C000000,0x9C000000,0x6DFC0000,0x9C000000,0x9C000000,0x9C000000,0x6DFC0000,0x9C000000,0x9C000000,0x9C000000,0x9C000000,0x3880000,0xF4C0000,0xF4C0000,0xFFC0000,0x5BFC0000,0x85F40000,0x9C000000,0x9C000000,0x1AC0000,0x2FFC0000,0x97E00000,0x9C000000,
-0x47FC0000,0x1180274,0xCB0C00F3,0xA70C00F4,0x9D0C00F3,0xC1040092,0xA904004F,0x9F040067,0xA1040092,0x9D00004E,0x97000092,0xBEF800F4,0xACF80033,0x9EFC0051,0xA4F4004A,0x9CF80002,0x96F8004D,0x9CF400F4,0x98F00053,0x94F00069,0x90F400F5,0x1A00274,0xB2E000F3,0x9CF800F4,0xA8DC0092,0x9CE80049,0x96EC0090,0xA6CC00F3,0x9CD40032,0x96D4004D,0x90E000F4,0x55F80274,
-0x9CAC00F3,0x96A80090,0x909C00F4,0x8A000278,0xFCFC0024,0xFF0C0164,0xF31401AB,0xCAF80002,0xB2F80002,0xA4F80002,0x9CF80006,0x9AF40006,0xFCEC0016,0xC8EC0000,0x9EF00035,0x96D4004D,0x27FC0274,0x12400F3,0xBF180032,0xA5180032,0x9D180032,0xB5100049,0xA70C0002,0x9D100005,0x9F0C0049,0x9B0C000E,0x970C0049,0x3B000F3,0xACF80032,0x9D080032,0xA4F40049,0x9CF80001,
-0x96FC0049,0x5DFC00F3,0x9CD00032,0x96CC0048,0x900000F4,0x3B000F3,0xACF80032,0x9D080032,0xA4F40049,0x9CF80001,0x96FC0049,0x5DFC00F3,0x9CD00032,0x96CC0048,0x900000F4,0x5DFC00F3,0x9CD00032,0x96CC0048,0x900000F4,0x900000F4,0xFF00000B,0xF5180081,0xF9200076,0xCAF80001,0xB2F80001,0xA4F80001,0x9D000001,0x9CF00004,0xFCEC000D,0xC8EC0000,0x9EEC0033,0x96CC0048,
-0x33FC00F3,0x10C00F3,0x10C00F3,0x10C00F3,0x10C00F3,0xAF04004A,0xAF04004A,0xAF04004A,0x9900004A,0x9900004A,0x9100004A,0xACF80033,0xACF80033,0xACF80033,0x9AF80002,0x9AF80002,0x92F8000E,0x94F40033,0x94F40033,0x90F40005,0x8AF40035,0x38C00F3,0x38C00F3,0x38C00F3,0x9CE80049,0x9CE80049,0x90F0004A,0x9AD80032,0x9AD80032,0x90E00001,0x8CE40034,0x4BFC00F3,
-0x4BFC00F3,0x90C00048,0x8AB40034,0x860000F4,0xFAFC000B,0xFD080073,0x10C00F3,0xCAF80001,0xAEF80002,0xA2F80002,0xA0F80003,0x98F40001,0xF8E80005,0xC8EC0000,0x9AF40033,0x90E00001,0x1DF800F3,0x1180032,0x1180032,0x1180032,0x1180032,0xA3100001,0xA3100001,0xA3100001,0x95100001,0x95100001,0x910C0001,0x1A00032,0x1A00032,0x1A00032,0x98FC0001,0x98FC0001,
-0x91040000,0x55F80032,0x55F80032,0x90E40000,0x8A000034,0x1A00032,0x1A00032,0x1A00032,0x98FC0001,0x98FC0001,0x91040000,0x55F80032,0x55F80032,0x90E40000,0x8A000034,0x55F80032,0x55F80032,0x90E40000,0x8A000034,0x8A000034,0xF7000000,0xF1100005,0x1180032,0xCAF80000,0xA9000001,0xA0FC0000,0x9B000001,0x98F40000,0xF8EC0001,0xC2F00000,0x27FC0032,0x90E40000,
-0x27FC0032,0x12C004A,0xB3240001,0xA3200001,0x9D200001,0x1C00048,0xA70C0001,0x9D140001,0x65F80048,0x9CF00000,0x96000048,0x1C00048,0xA70C0001,0x9D140001,0x65F80048,0x9CF00000,0x96000048,0x65F80048,0x9CF00000,0x96000048,0x96000048,0x1C00048,0xA70C0001,0x9D140001,0x65F80048,0x9CF00000,0x96000048,0x65F80048,0x9CF00000,0x96000048,0x96000048,0x65F80048,
-0x9CF00000,0x96000048,0x96000048,0x96000048,0xFB040008,0x9400048,0xFD28000D,0xCEF40000,0xB2F40001,0xA6F00000,0x9D000000,0x9CDC0000,0xFEF00005,0xC8EC0000,0x9F040000,0x96000048,0x3DF80048,0x100004A,0x100004A,0x100004A,0x100004A,0x100004A,0x100004A,0x100004A,0x100004A,0x100004A,0x100004A,0x9CF80001,0x9CF80001,0x9CF80001,0x9CF80001,0x9CF80001,
-0x9CF80001,0x8CF40001,0x8CF40001,0x8CF40001,0x86F40001,0x1800048,0x1800048,0x1800048,0x1800048,0x1800048,0x1800048,0x90E00001,0x90E00001,0x90E00001,0x86E80001,0x45F80048,0x45F80048,0x45F80048,0x86C40000,0x80000048,0xF4F8000A,0x100004A,0x100004A,0xC6F80001,0xB0F80001,0xA4F80001,0xA4F80001,0x96F80001,0xF8E80001,0xC8EC0000,0x90F40001,0x90E00001,
-0x13FC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table50[] = {
-0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x47FC0000,
-0x47FC0000,0x47FC0000,0x47FC0000,0x82000000,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1180000,0x1180000,0x1180000,0x1840000,0x17FC0000,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,
-0x1A80000,0x59FC0000,0x59FC0000,0x59FC0000,0x8E000000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x59FC0000,0x59FC0000,0x59FC0000,0x8E000000,0x59FC0000,0x59FC0000,0x59FC0000,0x8E000000,0x8E000000,0x1300000,0x11C0001,0x11C0001,0x14C0000,0x5640000,0x1840000,0x1840000,0x1E00000,0x14C0000,0x5640000,0x2DFC0000,0x59FC0000,
-0x2DFC0000,0x1300001,0x1300001,0x1300001,0x1300001,0x3C40000,0x3C40000,0x3C40000,0x67FC0000,0x67FC0000,0x98000000,0x3C40000,0x3C40000,0x3C40000,0x67FC0000,0x67FC0000,0x98000000,0x67FC0000,0x67FC0000,0x98000000,0x98000000,0x3C40000,0x3C40000,0x3C40000,0x67FC0000,0x67FC0000,0x98000000,0x67FC0000,0x67FC0000,0x98000000,0x98000000,0x67FC0000,
-0x67FC0000,0x98000000,0x98000000,0x98000000,0x1640000,0xB440000,0x1300001,0x1A00000,0x5FC0000,0x3FFC0000,0x55F80000,0x75F80000,0x1800000,0x3C40000,0x3FFC0000,0x98000000,0x3FFC0000,0x1480001,0x3E80000,0x79FC0000,0xA4000000,0x3E80000,0x79FC0000,0xA4000000,0x79FC0000,0xA4000000,0xA4000000,0x3E80000,0x79FC0000,0xA4000000,0x79FC0000,0xA4000000,
-0xA4000000,0x79FC0000,0xA4000000,0xA4000000,0xA4000000,0x3E80000,0x79FC0000,0xA4000000,0x79FC0000,0xA4000000,0xA4000000,0x79FC0000,0xA4000000,0xA4000000,0xA4000000,0x79FC0000,0xA4000000,0xA4000000,0xA4000000,0xA4000000,0x39C0000,0x1600000,0x1600000,0x23FC0000,0x69F80000,0x8FF40000,0xA4000000,0xA4000000,0x1C00000,0x41FC0000,0x9FF00000,0xA4000000,
-0x57FC0000,0x1280274,0xD31C00F3,0xAF1C00F4,0xA51C00F3,0xC9140092,0xB114004F,0xA7140067,0xA9140092,0xA510004E,0x9F100092,0xC70800F4,0xB5080033,0xA70C0051,0xAD04004A,0xA5080002,0x9F08004D,0xA50400F4,0xA1000053,0x9D000069,0x990400F5,0x1B80274,0xBAF000F3,0xA50800F4,0xB0EC0092,0xA4F80049,0x9EFC0090,0xAEDC00F3,0xA4E40032,0x9EE4004D,0x98F000F4,0x61F80274,
-0xA4BC00F3,0x9EB80090,0x98AC00F4,0x92000278,0xFF0C0032,0xF9200172,0xFB2401AB,0xD3080002,0xBB080002,0xAD080002,0xA5080006,0xA3040006,0xFCFC0024,0xD0FC0000,0xA7000035,0x9EE4004D,0x37FC0274,0x13400F3,0xC7280032,0xAD280032,0xA5280032,0xBD200049,0xAF1C0002,0xA5200005,0xA71C0049,0xA31C000E,0x9F1C0049,0x1C800F3,0xB5080032,0xA5180032,0xAD040049,0xA5080001,
-0x9F0C0049,0x69FC00F3,0xA4E00032,0x9EDC0048,0x980000F4,0x1C800F3,0xB5080032,0xA5180032,0xAD040049,0xA5080001,0x9F0C0049,0x69FC00F3,0xA4E00032,0x9EDC0048,0x980000F4,0x69FC00F3,0xA4E00032,0x9EDC0048,0x980000F4,0x980000F4,0xFF14000E,0xFD280081,0xFF2C007A,0xD3080001,0xBB080001,0xAD080001,0xA5100001,0xA5000004,0xFF000013,0xD0FC0000,0xA6FC0033,0x9EDC0048,
-0x41FC00F3,0x11C00F3,0x11C00F3,0x11C00F3,0x11C00F3,0xB714004A,0xB714004A,0xB714004A,0xA110004A,0xA110004A,0x9910004A,0xB5080033,0xB5080033,0xB5080033,0xA3080002,0xA3080002,0x9B08000E,0x9D040033,0x9D040033,0x99040005,0x93040035,0x3A400F3,0x3A400F3,0x3A400F3,0xA4F80049,0xA4F80049,0x9900004A,0xA2E80032,0xA2E80032,0x98F00001,0x94F40034,0x57FC00F3,
-0x57FC00F3,0x98D00048,0x92C40034,0x8E0000F4,0xFF0C000E,0xF518007E,0x11C00F3,0xD3080001,0xB7080002,0xAB080002,0xA9080003,0xA1040001,0xFEF80006,0xD0FC0000,0xA3040033,0x98F00001,0x2BFC00F3,0x1280032,0x1280032,0x1280032,0x1280032,0xAB200001,0xAB200001,0xAB200001,0x9D200001,0x9D200001,0x991C0001,0x1B80032,0x1B80032,0x1B80032,0xA10C0001,0xA10C0001,
-0x99140000,0x61F80032,0x61F80032,0x98F40000,0x92000034,0x1B80032,0x1B80032,0x1B80032,0xA10C0001,0xA10C0001,0x99140000,0x61F80032,0x61F80032,0x98F40000,0x92000034,0x61F80032,0x61F80032,0x98F40000,0x92000034,0x92000034,0xFF100000,0xF9200005,0x1280032,0xD3080000,0xB1100001,0xA90C0000,0xA3100001,0xA1040000,0xF5000002,0xCB000000,0x37FC0032,0x98F40000,
-0x37FC0032,0x13C004A,0xBB340001,0xAB300001,0xA5300001,0x1D80048,0xAF1C0001,0xA5240001,0x71F80048,0xA5000000,0x9E000048,0x1D80048,0xAF1C0001,0xA5240001,0x71F80048,0xA5000000,0x9E000048,0x71F80048,0xA5000000,0x9E000048,0x9E000048,0x1D80048,0xAF1C0001,0xA5240001,0x71F80048,0xA5000000,0x9E000048,0x71F80048,0xA5000000,0x9E000048,0x9E000048,0x71F80048,
-0xA5000000,0x9E000048,0x9E000048,0x9E000048,0xFF14000A,0x1540048,0xF5380012,0xD7040000,0xBB040001,0xAF000000,0xA5100000,0xA4EC0000,0xF7080008,0xD0FC0000,0xA7140000,0x9E000048,0x4BFC0048,0x110004A,0x110004A,0x110004A,0x110004A,0x110004A,0x110004A,0x110004A,0x110004A,0x110004A,0x110004A,0xA5080001,0xA5080001,0xA5080001,0xA5080001,0xA5080001,
-0xA5080001,0x95040001,0x95040001,0x95040001,0x8F040001,0x1980048,0x1980048,0x1980048,0x1980048,0x1980048,0x1980048,0x98F00001,0x98F00001,0x98F00001,0x8EF80001,0x51F80048,0x51F80048,0x51F80048,0x8ED40000,0x88000048,0xFD08000A,0x110004A,0x110004A,0xCF080001,0xB9080001,0xAD080001,0xAD080001,0x9F080001,0xF8F80002,0xD0FC0000,0x99040001,0x98F00001,
-0x21FC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table51[] = {
-0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x53FC0000,
-0x53FC0000,0x53FC0000,0x53FC0000,0x8A000000,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1280000,0x1280000,0x1280000,0x19C0000,0x25FC0000,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,
-0x1C00000,0x65F80000,0x65F80000,0x65F80000,0x96000000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x65F80000,0x65F80000,0x65F80000,0x96000000,0x65F80000,0x65F80000,0x65F80000,0x96000000,0x96000000,0x9400000,0x12C0001,0x12C0001,0x1600000,0x5780000,0x3980000,0x3980000,0x1FC0000,0x1600000,0x5780000,0x3DF80000,0x65F80000,
-0x3DF80000,0x1400001,0x1400001,0x1400001,0x1400001,0x3DC0000,0x3DC0000,0x3DC0000,0x73FC0000,0x73FC0000,0xA0000000,0x3DC0000,0x3DC0000,0x3DC0000,0x73FC0000,0x73FC0000,0xA0000000,0x73FC0000,0x73FC0000,0xA0000000,0xA0000000,0x3DC0000,0x3DC0000,0x3DC0000,0x73FC0000,0x73FC0000,0xA0000000,0x73FC0000,0x73FC0000,0xA0000000,0xA0000000,0x73FC0000,
-0x73FC0000,0xA0000000,0xA0000000,0xA0000000,0x5740000,0x1580000,0x1400001,0x3B40000,0x19FC0000,0x4FFC0000,0x61FC0000,0x7FFC0000,0x1940000,0x3DC0000,0x4FFC0000,0xA0000000,0x4FFC0000,0x1580001,0x7FC0000,0x85FC0000,0xAC000000,0x7FC0000,0x85FC0000,0xAC000000,0x85FC0000,0xAC000000,0xAC000000,0x7FC0000,0x85FC0000,0xAC000000,0x85FC0000,0xAC000000,
-0xAC000000,0x85FC0000,0xAC000000,0xAC000000,0xAC000000,0x7FC0000,0x85FC0000,0xAC000000,0x85FC0000,0xAC000000,0xAC000000,0x85FC0000,0xAC000000,0xAC000000,0xAC000000,0x85FC0000,0xAC000000,0xAC000000,0xAC000000,0xAC000000,0x3B00000,0x1700000,0x1700000,0x37FC0000,0x75FC0000,0x99F40000,0xAC000000,0xAC000000,0x3D40000,0x51FC0000,0xA9C40000,0xAC000000,
-0x65FC0000,0x1380274,0xDB2C00F3,0xB72C00F4,0xAD2C00F3,0xD1240092,0xB924004F,0xAF240067,0xB1240092,0xAD20004E,0xA7200092,0xCF1800F4,0xBD180033,0xAF1C0051,0xB514004A,0xAD180002,0xA718004D,0xAD1400F4,0xA9100053,0xA5100069,0xA11400F5,0x1D00274,0xC30000F3,0xAD1800F4,0xB8FC0092,0xAD080049,0xA70C0090,0xB6EC00F3,0xACF40032,0xA6F4004D,0xA10000F4,0x6DF80274,
-0xACCC00F3,0xA6C80090,0xA0BC00F4,0x9A000278,0xFF20003E,0xFF2C018A,0xF33401C4,0xDB180002,0xC3180002,0xB5180002,0xAD180006,0xAB140006,0xFF10002E,0xD90C0000,0xAF100035,0xA6F4004D,0x45FC0274,0x14400F3,0xCF380032,0xB5380032,0xAD380032,0xC5300049,0xB72C0002,0xAD300005,0xAF2C0049,0xAB2C000E,0xA72C0049,0x1E000F3,0xBD180032,0xAD280032,0xB5140049,0xAD180001,
-0xA71C0049,0x75FC00F3,0xACF00032,0xA6EC0048,0xA00000F4,0x1E000F3,0xBD180032,0xAD280032,0xB5140049,0xAD180001,0xA71C0049,0x75FC00F3,0xACF00032,0xA6EC0048,0xA00000F4,0x75FC00F3,0xACF00032,0xA6EC0048,0xA00000F4,0xA00000F4,0xF928001A,0xF73C008B,0xF9400083,0xDB180001,0xC3180001,0xB5180001,0xAD200001,0xAD100004,0xFD140019,0xD90C0000,0xAF0C0033,0xA6EC0048,
-0x51FC00F3,0x12C00F3,0x12C00F3,0x12C00F3,0x12C00F3,0xBF24004A,0xBF24004A,0xBF24004A,0xA920004A,0xA920004A,0xA120004A,0xBD180033,0xBD180033,0xBD180033,0xAB180002,0xAB180002,0xA318000E,0xA5140033,0xA5140033,0xA1140005,0x9B140035,0x3BC00F3,0x3BC00F3,0x3BC00F3,0xAD080049,0xAD080049,0xA110004A,0xAAF80032,0xAAF80032,0xA1000001,0x9D040034,0x63FC00F3,
-0x63FC00F3,0xA0E00048,0x9AD40034,0x960000F4,0xFD1C0016,0xFD28007E,0x12C00F3,0xDB180001,0xBF180002,0xB3180002,0xB1180003,0xA9140001,0xFD0C000D,0xD90C0000,0xAB140033,0xA1000001,0x3BFC00F3,0x1380032,0x1380032,0x1380032,0x1380032,0xB3300001,0xB3300001,0xB3300001,0xA5300001,0xA5300001,0xA12C0001,0x1D00032,0x1D00032,0x1D00032,0xA91C0001,0xA91C0001,
-0xA1240000,0x6DF80032,0x6DF80032,0xA1040000,0x9A000034,0x1D00032,0x1D00032,0x1D00032,0xA91C0001,0xA91C0001,0xA1240000,0x6DF80032,0x6DF80032,0xA1040000,0x9A000034,0x6DF80032,0x6DF80032,0xA1040000,0x9A000034,0x9A000034,0xFF200001,0xF130000A,0x1380032,0xDB180000,0xB9200001,0xB11C0000,0xAB200001,0xA9140000,0xFD100002,0xD3100000,0x45FC0032,0xA1040000,
-0x45FC0032,0x14C004A,0xC3440001,0xB3400001,0xAD400001,0x1F00048,0xB72C0001,0xAD340001,0x7DF80048,0xAD100000,0xA6000048,0x1F00048,0xB72C0001,0xAD340001,0x7DF80048,0xAD100000,0xA6000048,0x7DF80048,0xAD100000,0xA6000048,0xA6000048,0x1F00048,0xB72C0001,0xAD340001,0x7DF80048,0xAD100000,0xA6000048,0x7DF80048,0xAD100000,0xA6000048,0xA6000048,0x7DF80048,
-0xAD100000,0xA6000048,0xA6000048,0xA6000048,0xFB2C000D,0x1640048,0xFD480012,0xDF140000,0xC3140001,0xB7100000,0xAD200000,0xACFC0000,0xFF180008,0xD90C0000,0xAF240000,0xA6000048,0x5BFC0048,0x120004A,0x120004A,0x120004A,0x120004A,0x120004A,0x120004A,0x120004A,0x120004A,0x120004A,0x120004A,0xAD180001,0xAD180001,0xAD180001,0xAD180001,0xAD180001,
-0xAD180001,0x9D140001,0x9D140001,0x9D140001,0x97140001,0x1B00048,0x1B00048,0x1B00048,0x1B00048,0x1B00048,0x1B00048,0xA1000001,0xA1000001,0xA1000001,0x97080001,0x5DF40048,0x5DF40048,0x5DF40048,0x96E40000,0x90000048,0xF71C000D,0x120004A,0x120004A,0xD7180001,0xC1180001,0xB5180001,0xB5180001,0xA7180001,0xFB080004,0xD90C0000,0xA1140001,0xA1000001,
-0x31FC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table52[] = {
-0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x61F80000,
-0x61F80000,0x61F80000,0x61F80000,0x92000001,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x13C0000,0x13C0000,0x13C0000,0x1B80000,0x37FC0000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,
-0x1DC0000,0x73F80000,0x73F80000,0x73F80000,0x9E000001,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x73F80000,0x73F80000,0x73F80000,0x9E000001,0x73F80000,0x73F80000,0x73F80000,0x9E000001,0x9E000001,0x3540000,0x1400000,0x1400000,0x1740000,0x1900000,0x1B40000,0x1B40000,0x17FC0000,0x1740000,0x1900000,0x4DFC0000,0x73F80000,
-0x4DFC0000,0x1540000,0x1540000,0x1540000,0x1540000,0x1F80000,0x1F80000,0x1F80000,0x81FC0000,0x81FC0000,0xA8000001,0x1F80000,0x1F80000,0x1F80000,0x81FC0000,0x81FC0000,0xA8000001,0x81FC0000,0x81FC0000,0xA8000001,0xA8000001,0x1F80000,0x1F80000,0x1F80000,0x81FC0000,0x81FC0000,0xA8000001,0x81FC0000,0x81FC0000,0xA8000001,0xA8000001,0x81FC0000,
-0x81FC0000,0xA8000001,0xA8000001,0xA8000001,0x18C0000,0xD680000,0x1540000,0x3CC0000,0x2FFC0000,0x5FFC0000,0x71FC0000,0x8BFC0000,0x3A80000,0x1F80000,0x5FFC0000,0xA8000001,0x5FFC0000,0x16C0000,0x23FC0000,0x93FC0000,0xB4000001,0x23FC0000,0x93FC0000,0xB4000001,0x93FC0000,0xB4000001,0xB4000001,0x23FC0000,0x93FC0000,0xB4000001,0x93FC0000,0xB4000001,
-0xB4000001,0x93FC0000,0xB4000001,0xB4000001,0xB4000001,0x23FC0000,0x93FC0000,0xB4000001,0x93FC0000,0xB4000001,0xB4000001,0x93FC0000,0xB4000001,0xB4000001,0xB4000001,0x93FC0000,0xB4000001,0xB4000001,0xB4000001,0xB4000001,0x1C80000,0x1840000,0x1840000,0x4DFC0000,0x85FC0000,0xA5F00000,0xB4000001,0xB4000001,0x1F00000,0x65FC0000,0xB1F40000,0xB4000001,
-0x77FC0000,0x1480278,0xE34000F4,0xC14000F4,0xB54000F5,0xDD340090,0xC534004D,0xB9380069,0xBB340090,0xB534004D,0xAF340092,0xD92800F3,0xC7280032,0xB9300053,0xBD280049,0xB5280002,0xB128004E,0xB52800F4,0xB3240051,0xAF240067,0xAB2800F3,0x3E80274,0xCB1400F3,0xB52800F4,0xC30C0092,0xB718004A,0xAF200092,0xC0FC00F3,0xB5080033,0xAF08004F,0xAB1000F4,0x79FC0274,
-0xB4E400F4,0xAEDC0092,0xAAC800F3,0xA4000274,0xFF340059,0xFB440190,0xFD4801C4,0xE7280000,0xCD280001,0xBD280002,0xB72C0006,0xB5280006,0xFF24004F,0xDF200002,0xB7240035,0xAF08004F,0x57FC0274,0x15400F4,0xD74C0034,0xBF480034,0xB5480035,0xD1400048,0xBF400001,0xB7400005,0xB740004A,0xB53C000E,0xAF40004A,0x1FC00F3,0xC52C0032,0xB7380033,0xBD280049,0xB5280002,
-0xAF30004A,0x83F800F3,0xB5080033,0xAF00004A,0xAA0000F3,0x1FC00F3,0xC52C0032,0xB7380033,0xBD280049,0xB5280002,0xAF30004A,0x83F800F3,0xB5080033,0xAF00004A,0xAA0000F3,0x83F800F3,0xB5080033,0xAF00004A,0xAA0000F3,0xAA0000F3,0xFF3C0024,0xFF4C008C,0xF1500095,0xE7280000,0xCD280001,0xBD280002,0xB7300001,0xB5200003,0xFB2C002A,0xDF200001,0xB91C0032,0xAF00004A,
-0x61FC00F3,0x14000F4,0x14000F4,0x14000F4,0x14000F4,0xCB340048,0xCB340048,0xCB340048,0xB1340049,0xB1340049,0xA9340049,0xC7280032,0xC7280032,0xC7280032,0xB5280001,0xB5280001,0xAB2C000E,0xAD280032,0xAD280032,0xA9280005,0xA5280032,0x1D800F3,0x1D800F3,0x1D800F3,0xB7180049,0xB7180049,0xA9240049,0xB5080032,0xB5080032,0xA9140002,0xA5180032,0x71F800F3,
-0x71F800F3,0xA8F40049,0xA4E00032,0x9E0000F3,0xF9300024,0xF73C008C,0x14000F4,0xE7280000,0xC9280001,0xBD280001,0xB9280004,0xB1280001,0xFF200012,0xDF200001,0xB5240032,0xA9140002,0x4BFC00F3,0x1480034,0x1480034,0x1480034,0x1480034,0xBD400000,0xBD400000,0xBD400000,0xAF400000,0xAF400000,0xA9400001,0x3E80032,0x3E80032,0x3E80032,0xB1300001,0xB1300001,
-0xA9380001,0x79FC0032,0x79FC0032,0xA91C0001,0xA4000032,0x3E80032,0x3E80032,0x3E80032,0xB1300001,0xB1300001,0xA9380001,0x79FC0032,0x79FC0032,0xA91C0001,0xA4000032,0x79FC0032,0x79FC0032,0xA91C0001,0xA4000032,0xA4000032,0xFB340004,0xFB440008,0x1480034,0xE7280000,0xC72C0000,0xBB2C0000,0xB7300000,0xB1280001,0xF9280005,0xDF200000,0x57FC0032,0xA91C0001,
-0x57FC0032,0x1600048,0xCF540000,0xBB540001,0xB5540001,0xFFC0048,0xBF400001,0xB5480001,0x8BF80048,0xB5240001,0xAE00004A,0xFFC0048,0xBF400001,0xB5480001,0x8BF80048,0xB5240001,0xAE00004A,0x8BF80048,0xB5240001,0xAE00004A,0xAE00004A,0xFFC0048,0xBF400001,0xB5480001,0x8BF80048,0xB5240001,0xAE00004A,0x8BF80048,0xB5240001,0xAE00004A,0xAE00004A,0x8BF80048,
-0xB5240001,0xAE00004A,0xAE00004A,0xAE00004A,0xFD400012,0x1780048,0xF75C0019,0xE7280000,0xCB280001,0xBF240000,0xB5340001,0xB5140001,0xFF2C0011,0xE31C0000,0xB7380001,0xAE00004A,0x6BFC0048,0x1340048,0x1340048,0x1340048,0x1340048,0x1340048,0x1340048,0x1340048,0x1340048,0x1340048,0x1340048,0xB9280000,0xB9280000,0xB9280000,0xB9280000,0xB9280000,
-0xB9280000,0xA5280001,0xA5280001,0xA5280001,0x9F280001,0x1C80048,0x1C80048,0x1C80048,0x1C80048,0x1C80048,0x1C80048,0xA9140001,0xA9140001,0xA9140001,0x9F1C0001,0x69FC0048,0x69FC0048,0x69FC0048,0x9EF80001,0x9800004A,0xFF2C000D,0x1340048,0x1340048,0xE7280000,0xCD280000,0xC1280000,0xC1280000,0xB1280000,0xFD1C0005,0xE71C0000,0xAD240000,0xA9140001,
-0x41FC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table53[] = {
-0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x6DF80000,
-0x6DF80000,0x6DF80000,0x6DF80000,0x9A000001,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x14C0000,0x14C0000,0x14C0000,0x1D00000,0x45FC0000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,
-0x1F40000,0x7FF80000,0x7FF80000,0x7FF80000,0xA6000001,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x7FF80000,0x7FF80000,0x7FF80000,0xA6000001,0x7FF80000,0x7FF80000,0x7FF80000,0xA6000001,0xA6000001,0xB640000,0x1500000,0x1500000,0x7840000,0x1A40000,0x1C80000,0x1C80000,0x2BFC0000,0x7840000,0x1A40000,0x5DF80000,0x7FF80000,
-0x5DF80000,0x1640000,0x1640000,0x1640000,0x1640000,0x15FC0000,0x15FC0000,0x15FC0000,0x8DFC0000,0x8DFC0000,0xB0000001,0x15FC0000,0x15FC0000,0x15FC0000,0x8DFC0000,0x8DFC0000,0xB0000001,0x8DFC0000,0x8DFC0000,0xB0000001,0xB0000001,0x15FC0000,0x15FC0000,0x15FC0000,0x8DFC0000,0x8DFC0000,0xB0000001,0x8DFC0000,0x8DFC0000,0xB0000001,0xB0000001,0x8DFC0000,
-0x8DFC0000,0xB0000001,0xB0000001,0xB0000001,0x59C0000,0x17C0000,0x1640000,0x1E40000,0x43FC0000,0x6FFC0000,0x7FF80000,0x97F80000,0x3BC0000,0x15FC0000,0x6FFC0000,0xB0000001,0x6FFC0000,0x17C0000,0x3BFC0000,0x9FF80000,0xBC000001,0x3BFC0000,0x9FF80000,0xBC000001,0x9FF80000,0xBC000001,0xBC000001,0x3BFC0000,0x9FF80000,0xBC000001,0x9FF80000,0xBC000001,
-0xBC000001,0x9FF80000,0xBC000001,0xBC000001,0xBC000001,0x3BFC0000,0x9FF80000,0xBC000001,0x9FF80000,0xBC000001,0xBC000001,0x9FF80000,0xBC000001,0xBC000001,0xBC000001,0x9FF80000,0xBC000001,0xBC000001,0xBC000001,0xBC000001,0x1DC0000,0x3940000,0x3940000,0x61FC0000,0x93F80000,0xAFF00000,0xBC000001,0xBC000001,0xDFC0000,0x75FC0000,0xBBC80000,0xBC000001,
-0x85FC0000,0x1580278,0xEB5000F4,0xC95000F4,0xBD5000F5,0xE5440090,0xCD44004D,0xC1480069,0xC3440090,0xBD44004D,0xB7440092,0xE13800F3,0xCF380032,0xC1400053,0xC5380049,0xBD380002,0xB938004E,0xBD3800F4,0xBB340051,0xB7340067,0xB33800F3,0x7FC0274,0xD32400F3,0xBD3800F4,0xCB1C0092,0xBF28004A,0xB7300092,0xC90C00F3,0xBD180033,0xB718004F,0xB32000F4,0x85FC0274,
-0xBCF400F4,0xB6EC0092,0xB2D800F3,0xAC000274,0xFF44007E,0xF35401B2,0xF55801DD,0xEF380000,0xD5380001,0xC5380002,0xBF3C0006,0xBD380006,0xFF34006A,0xE7300002,0xBF340035,0xB718004F,0x65FC0274,0x16400F4,0xDF5C0034,0xC7580034,0xBD580035,0xD9500048,0xC7500001,0xBF500005,0xBF50004A,0xBD4C000E,0xB750004A,0x19FC00F3,0xCD3C0032,0xBF480033,0xC5380049,0xBD380002,
-0xB740004A,0x8FF800F3,0xBD180033,0xB710004A,0xB20000F3,0x19FC00F3,0xCD3C0032,0xBF480033,0xC5380049,0xBD380002,0xB740004A,0x8FF800F3,0xBD180033,0xB710004A,0xB20000F3,0x8FF800F3,0xBD180033,0xB710004A,0xB20000F3,0xB20000F3,0xFD4C002D,0xF960009A,0xF9600095,0xEF380000,0xD5380001,0xC5380002,0xBF400001,0xBD300003,0xFD400033,0xE7300001,0xC12C0032,0xB710004A,
-0x71FC00F3,0x15000F4,0x15000F4,0x15000F4,0x15000F4,0xD3440048,0xD3440048,0xD3440048,0xB9440049,0xB9440049,0xB1440049,0xCF380032,0xCF380032,0xCF380032,0xBD380001,0xBD380001,0xB33C000E,0xB5380032,0xB5380032,0xB1380005,0xAD380032,0x1F000F3,0x1F000F3,0x1F000F3,0xBF280049,0xBF280049,0xB1340049,0xBD180032,0xBD180032,0xB1240002,0xAD280032,0x7DF800F3,
-0x7DF800F3,0xB1040049,0xACF00032,0xA60000F3,0xF940002D,0xFF4C008C,0x15000F4,0xEF380000,0xD1380001,0xC5380001,0xC1380004,0xB9380001,0xFF340019,0xE7300001,0xBD340032,0xB1240002,0x5BFC00F3,0x1580034,0x1580034,0x1580034,0x1580034,0xC5500000,0xC5500000,0xC5500000,0xB7500000,0xB7500000,0xB1500001,0x7FC0032,0x7FC0032,0x7FC0032,0xB9400001,0xB9400001,
-0xB1480001,0x85FC0032,0x85FC0032,0xB12C0001,0xAC000032,0x7FC0032,0x7FC0032,0x7FC0032,0xB9400001,0xB9400001,0xB1480001,0x85FC0032,0x85FC0032,0xB12C0001,0xAC000032,0x85FC0032,0x85FC0032,0xB12C0001,0xAC000032,0xAC000032,0xF7480005,0xF354000D,0x1580034,0xEF380000,0xCF3C0000,0xC33C0000,0xBF400000,0xB9380001,0xF53C0008,0xE7300000,0x65FC0032,0xB12C0001,
-0x65FC0032,0x1700048,0xD7640000,0xC3640001,0xBD640001,0x29FC0048,0xC7500001,0xBD580001,0x97F80048,0xBD340001,0xB600004A,0x29FC0048,0xC7500001,0xBD580001,0x97F80048,0xBD340001,0xB600004A,0x97F80048,0xBD340001,0xB600004A,0xB600004A,0x29FC0048,0xC7500001,0xBD580001,0x97F80048,0xBD340001,0xB600004A,0x97F80048,0xBD340001,0xB600004A,0xB600004A,0x97F80048,
-0xBD340001,0xB600004A,0xB600004A,0xB600004A,0xFF500014,0x1880048,0xFF6C0019,0xEF380000,0xD3380001,0xC7340000,0xBD440001,0xBD240001,0xF9480012,0xEB2C0000,0xBF480001,0xB600004A,0x7BFC0048,0x1440048,0x1440048,0x1440048,0x1440048,0x1440048,0x1440048,0x1440048,0x1440048,0x1440048,0x1440048,0xC1380000,0xC1380000,0xC1380000,0xC1380000,0xC1380000,
-0xC1380000,0xAD380001,0xAD380001,0xAD380001,0xA7380001,0x1E00048,0x1E00048,0x1E00048,0x1E00048,0x1E00048,0x1E00048,0xB1240001,0xB1240001,0xB1240001,0xA72C0001,0x75FC0048,0x75FC0048,0x75FC0048,0xA7080001,0xA000004A,0xF73C0014,0x1440048,0x1440048,0xEF380000,0xD5380000,0xC9380000,0xC9380000,0xB9380000,0xF9300008,0xEF2C0000,0xB5340000,0xB1240001,
-0x51FC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table54[] = {
-0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x79F80000,
-0x79F80000,0x79F80000,0x79F80000,0xA2000001,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x75C0000,0x75C0000,0x75C0000,0x1E80000,0x55FC0000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0xFFC0000,0xFFC0000,0xFFC0000,0xFFC0000,0xFFC0000,
-0xFFC0000,0x8BF80000,0x8BF80000,0x8BF80000,0xAE000001,0xFFC0000,0xFFC0000,0xFFC0000,0xFFC0000,0xFFC0000,0xFFC0000,0x8BF80000,0x8BF80000,0x8BF80000,0xAE000001,0x8BF80000,0x8BF80000,0x8BF80000,0xAE000001,0xAE000001,0x1780000,0x1600000,0x1600000,0x3980000,0x1B80000,0x3DC0000,0x3DC0000,0x3DFC0000,0x3980000,0x1B80000,0x6BFC0000,0x8BF80000,
-0x6BFC0000,0x1740000,0x1740000,0x1740000,0x1740000,0x2FFC0000,0x2FFC0000,0x2FFC0000,0x99FC0000,0x99FC0000,0xB8000001,0x2FFC0000,0x2FFC0000,0x2FFC0000,0x99FC0000,0x99FC0000,0xB8000001,0x99FC0000,0x99FC0000,0xB8000001,0xB8000001,0x2FFC0000,0x2FFC0000,0x2FFC0000,0x99FC0000,0x99FC0000,0xB8000001,0x99FC0000,0x99FC0000,0xB8000001,0xB8000001,0x99FC0000,
-0x99FC0000,0xB8000001,0xB8000001,0xB8000001,0x1B00000,0x18C0000,0x1740000,0x3F80000,0x57FC0000,0x7FF80000,0x8BFC0000,0xA1FC0000,0x5D00000,0x2FFC0000,0x7FF80000,0xB8000001,0x7FF80000,0x18C0000,0x53FC0000,0xABF80000,0xC4000001,0x53FC0000,0xABF80000,0xC4000001,0xABF80000,0xC4000001,0xC4000001,0x53FC0000,0xABF80000,0xC4000001,0xABF80000,0xC4000001,
-0xC4000001,0xABF80000,0xC4000001,0xC4000001,0xC4000001,0x53FC0000,0xABF80000,0xC4000001,0xABF80000,0xC4000001,0xC4000001,0xABF80000,0xC4000001,0xC4000001,0xC4000001,0xABF80000,0xC4000001,0xC4000001,0xC4000001,0xC4000001,0x1F00000,0xBA40000,0xBA40000,0x73FC0000,0x9FFC0000,0xB9F00000,0xC4000001,0xC4000001,0x2BFC0000,0x87FC0000,0xC3D80000,0xC4000001,
-0x95FC0000,0x1680278,0xF36000F4,0xD16000F4,0xC56000F5,0xED540090,0xD554004D,0xC9580069,0xCB540090,0xC554004D,0xBF540092,0xE94800F3,0xD7480032,0xC9500053,0xCD480049,0xC5480002,0xC148004E,0xC54800F4,0xC3440051,0xBF440067,0xBB4800F3,0x1FFC0274,0xDB3400F3,0xC54800F4,0xD32C0092,0xC738004A,0xBF400092,0xD11C00F3,0xC5280033,0xBF28004F,0xBB3000F4,0x91FC0274,
-0xC50400F4,0xBEFC0092,0xBAE800F3,0xB4000274,0xFF580096,0xFB6401B2,0xFD6801DD,0xF7480000,0xDD480001,0xCD480002,0xC74C0006,0xC5480006,0xFD4C008A,0xEF400002,0xC7440035,0xBF28004F,0x75FC0274,0x17400F4,0xE76C0034,0xCF680034,0xC5680035,0xE1600048,0xCF600001,0xC7600005,0xC760004A,0xC55C000E,0xBF60004A,0x31FC00F3,0xD54C0032,0xC7580033,0xCD480049,0xC5480002,
-0xBF50004A,0x9BF800F3,0xC5280033,0xBF20004A,0xBA0000F3,0x31FC00F3,0xD54C0032,0xC7580033,0xCD480049,0xC5480002,0xBF50004A,0x9BF800F3,0xC5280033,0xBF20004A,0xBA0000F3,0x9BF800F3,0xC5280033,0xBF20004A,0xBA0000F3,0xBA0000F3,0xFD60003E,0xFF6C009E,0xF37400A4,0xF7480000,0xDD480001,0xCD480002,0xC7500001,0xC5400003,0xFB54003D,0xEF400001,0xC93C0032,0xBF20004A,
-0x7FFC00F3,0x16000F4,0x16000F4,0x16000F4,0x16000F4,0xDB540048,0xDB540048,0xDB540048,0xC1540049,0xC1540049,0xB9540049,0xD7480032,0xD7480032,0xD7480032,0xC5480001,0xC5480001,0xBB4C000E,0xBD480032,0xBD480032,0xB9480005,0xB5480032,0xDFC00F3,0xDFC00F3,0xDFC00F3,0xC7380049,0xC7380049,0xB9440049,0xC5280032,0xC5280032,0xB9340002,0xB5380032,0x89F800F3,
-0x89F800F3,0xB9140049,0xB5000032,0xAE0000F3,0xFD540035,0xF75C0099,0x16000F4,0xF7480000,0xD9480001,0xCD480001,0xC9480004,0xC1480001,0xFB480029,0xEF400001,0xC5440032,0xB9340002,0x69FC00F3,0x1680034,0x1680034,0x1680034,0x1680034,0xCD600000,0xCD600000,0xCD600000,0xBF600000,0xBF600000,0xB9600001,0x1FFC0032,0x1FFC0032,0x1FFC0032,0xC1500001,0xC1500001,
-0xB9580001,0x91FC0032,0x91FC0032,0xB93C0001,0xB4000032,0x1FFC0032,0x1FFC0032,0x1FFC0032,0xC1500001,0xC1500001,0xB9580001,0x91FC0032,0x91FC0032,0xB93C0001,0xB4000032,0x91FC0032,0x91FC0032,0xB93C0001,0xB4000032,0xB4000032,0xFF580005,0xFB64000D,0x1680034,0xF7480000,0xD74C0000,0xCB4C0000,0xC7500000,0xC1480001,0xFD4C0008,0xEF400000,0x75FC0032,0xB93C0001,
-0x75FC0032,0x1800048,0xDF740000,0xCB740001,0xC5740001,0x41FC0048,0xCF600001,0xC5680001,0xA1FC0048,0xC5440001,0xBE00004A,0x41FC0048,0xCF600001,0xC5680001,0xA1FC0048,0xC5440001,0xBE00004A,0xA1FC0048,0xC5440001,0xBE00004A,0xBE00004A,0x41FC0048,0xCF600001,0xC5680001,0xA1FC0048,0xC5440001,0xBE00004A,0xA1FC0048,0xC5440001,0xBE00004A,0xBE00004A,0xA1FC0048,
-0xC5440001,0xBE00004A,0xBE00004A,0xBE00004A,0xF7680019,0x5980048,0xF77C0020,0xF7480000,0xDB480001,0xCF440000,0xC5540001,0xC5340001,0xFD580014,0xF33C0000,0xC7580001,0xBE00004A,0x89FC0048,0x1540048,0x1540048,0x1540048,0x1540048,0x1540048,0x1540048,0x1540048,0x1540048,0x1540048,0x1540048,0xC9480000,0xC9480000,0xC9480000,0xC9480000,0xC9480000,
-0xC9480000,0xB5480001,0xB5480001,0xB5480001,0xAF480001,0x1F80048,0x1F80048,0x1F80048,0x1F80048,0x1F80048,0x1F80048,0xB9340001,0xB9340001,0xB9340001,0xAF3C0001,0x81FC0048,0x81FC0048,0x81FC0048,0xAF180001,0xA800004A,0xFF4C0014,0x1540048,0x1540048,0xF7480000,0xDD480000,0xD1480000,0xD1480000,0xC1480000,0xF544000D,0xF73C0000,0xBD440000,0xB9340001,
-0x5FFC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table55[] = {
-0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x85F80000,
-0x85F80000,0x85F80000,0x85F80000,0xAA000001,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0xF6C0000,0xF6C0000,0xF6C0000,0x3FC0000,0x63FC0000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x29FC0000,0x29FC0000,0x29FC0000,0x29FC0000,0x29FC0000,
-0x29FC0000,0x97F80000,0x97F80000,0x97F80000,0xB6000001,0x29FC0000,0x29FC0000,0x29FC0000,0x29FC0000,0x29FC0000,0x29FC0000,0x97F80000,0x97F80000,0x97F80000,0xB6000001,0x97F80000,0x97F80000,0x97F80000,0xB6000001,0xB6000001,0x1880000,0x1700000,0x1700000,0x1AC0000,0x3CC0000,0x1F40000,0x1F40000,0x51FC0000,0x1AC0000,0x3CC0000,0x7BFC0000,0x97F80000,
-0x7BFC0000,0x1840000,0x1840000,0x1840000,0x1840000,0x47FC0000,0x47FC0000,0x47FC0000,0xA5F80000,0xA5F80000,0xC0000001,0x47FC0000,0x47FC0000,0x47FC0000,0xA5F80000,0xA5F80000,0xC0000001,0xA5F80000,0xA5F80000,0xC0000001,0xC0000001,0x47FC0000,0x47FC0000,0x47FC0000,0xA5F80000,0xA5F80000,0xC0000001,0xA5F80000,0xA5F80000,0xC0000001,0xC0000001,0xA5F80000,
-0xA5F80000,0xC0000001,0xC0000001,0xC0000001,0x1C40000,0x79C0000,0x1840000,0x1BFC0000,0x6BFC0000,0x8DFC0000,0x99FC0000,0xADF80000,0x5E40000,0x47FC0000,0x8DFC0000,0xC0000001,0x8DFC0000,0x19C0000,0x6BFC0000,0xB7F80000,0xCC000001,0x6BFC0000,0xB7F80000,0xCC000001,0xB7F80000,0xCC000001,0xCC000001,0x6BFC0000,0xB7F80000,0xCC000001,0xB7F80000,0xCC000001,
-0xCC000001,0xB7F80000,0xCC000001,0xCC000001,0xCC000001,0x6BFC0000,0xB7F80000,0xCC000001,0xB7F80000,0xCC000001,0xCC000001,0xB7F80000,0xCC000001,0xCC000001,0xCC000001,0xB7F80000,0xCC000001,0xCC000001,0xCC000001,0xCC000001,0x11FC0000,0x1B80000,0x1B80000,0x87FC0000,0xADFC0000,0xC3F00000,0xCC000001,0xCC000001,0x49FC0000,0x97FC0000,0xCBE80000,0xCC000001,
-0xA3FC0000,0x1780278,0xFB7000F4,0xD97000F4,0xCD7000F5,0xF5640090,0xDD64004D,0xD1680069,0xD3640090,0xCD64004D,0xC7640092,0xF15800F3,0xDF580032,0xD1600053,0xD5580049,0xCD580002,0xC958004E,0xCD5800F4,0xCB540051,0xC7540067,0xC35800F3,0x37FC0274,0xE34400F3,0xCD5800F4,0xDB3C0092,0xCF48004A,0xC7500092,0xD92C00F3,0xCD380033,0xC738004F,0xC34000F4,0x9DFC0274,
-0xCD1400F4,0xC70C0092,0xC2F800F3,0xBC000274,0xFF6C00C2,0xF37401D8,0xF57801F8,0xFF580000,0xE5580001,0xD5580002,0xCF5C0006,0xCD580006,0xFF5C00A6,0xF7500002,0xCF540035,0xC738004F,0x83FC0274,0x18400F4,0xEF7C0034,0xD7780034,0xCD780035,0xE9700048,0xD7700001,0xCF700005,0xCF70004A,0xCD6C000E,0xC770004A,0x49FC00F3,0xDD5C0032,0xCF680033,0xD5580049,0xCD580002,
-0xC760004A,0xA7F800F3,0xCD380033,0xC730004A,0xC20000F3,0x49FC00F3,0xDD5C0032,0xCF680033,0xD5580049,0xCD580002,0xC760004A,0xA7F800F3,0xCD380033,0xC730004A,0xC20000F3,0xA7F800F3,0xCD380033,0xC730004A,0xC20000F3,0xC20000F3,0xFD740049,0xF98000A8,0xFB8400A4,0xFF580000,0xE5580001,0xD5580002,0xCF600001,0xCD500003,0xFB680055,0xF7500001,0xD14C0032,0xC730004A,
-0x8FFC00F3,0x17000F4,0x17000F4,0x17000F4,0x17000F4,0xE3640048,0xE3640048,0xE3640048,0xC9640049,0xC9640049,0xC1640049,0xDF580032,0xDF580032,0xDF580032,0xCD580001,0xCD580001,0xC35C000E,0xC5580032,0xC5580032,0xC1580005,0xBD580032,0x25FC00F3,0x25FC00F3,0x25FC00F3,0xCF480049,0xCF480049,0xC1540049,0xCD380032,0xCD380032,0xC1440002,0xBD480032,0x95F800F3,
-0x95F800F3,0xC1240049,0xBD100032,0xB60000F3,0xFD64003E,0xFF6C0099,0x17000F4,0xFF580000,0xE1580001,0xD5580001,0xD1580004,0xC9580001,0xFF580032,0xF7500001,0xCD540032,0xC1440002,0x79FC00F3,0x1780034,0x1780034,0x1780034,0x1780034,0xD5700000,0xD5700000,0xD5700000,0xC7700000,0xC7700000,0xC1700001,0x37FC0032,0x37FC0032,0x37FC0032,0xC9600001,0xC9600001,
-0xC1680001,0x9DFC0032,0x9DFC0032,0xC14C0001,0xBC000032,0x37FC0032,0x37FC0032,0x37FC0032,0xC9600001,0xC9600001,0xC1680001,0x9DFC0032,0x9DFC0032,0xC14C0001,0xBC000032,0x9DFC0032,0x9DFC0032,0xC14C0001,0xBC000032,0xBC000032,0xFB6C0008,0xF3740014,0x1780034,0xFF580000,0xDF5C0000,0xD35C0000,0xCF600000,0xC9580001,0xF564000D,0xF7500000,0x83FC0032,0xC14C0001,
-0x83FC0032,0x1900048,0xE7840000,0xD3840001,0xCD840001,0x59FC0048,0xD7700001,0xCD780001,0xADFC0048,0xCD540001,0xC600004A,0x59FC0048,0xD7700001,0xCD780001,0xADFC0048,0xCD540001,0xC600004A,0xADFC0048,0xCD540001,0xC600004A,0xC600004A,0x59FC0048,0xD7700001,0xCD780001,0xADFC0048,0xCD540001,0xC600004A,0xADFC0048,0xCD540001,0xC600004A,0xC600004A,0xADFC0048,
-0xCD540001,0xC600004A,0xC600004A,0xC600004A,0xFF780019,0xDA80048,0xFF8C0020,0xFF580000,0xE3580001,0xD7540000,0xCD640001,0xCD440001,0xFF700019,0xFB4C0000,0xCF680001,0xC600004A,0x99FC0048,0x1640048,0x1640048,0x1640048,0x1640048,0x1640048,0x1640048,0x1640048,0x1640048,0x1640048,0x1640048,0xD1580000,0xD1580000,0xD1580000,0xD1580000,0xD1580000,
-0xD1580000,0xBD580001,0xBD580001,0xBD580001,0xB7580001,0x15FC0048,0x15FC0048,0x15FC0048,0x15FC0048,0x15FC0048,0x15FC0048,0xC1440001,0xC1440001,0xC1440001,0xB74C0001,0x8DFC0048,0x8DFC0048,0x8DFC0048,0xB7280001,0xB000004A,0xF9600019,0x1640048,0x1640048,0xFF580000,0xE5580000,0xD9580000,0xD9580000,0xC9580000,0xFD54000D,0xFF4C0000,0xC5540000,0xC1440001,
-0x6FFC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table56[] = {
-0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x91FC0000,
-0x91FC0000,0x91FC0000,0x91FC0000,0xB4000000,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x9800000,0x9800000,0x9800000,0x1FFC0000,0x75FC0000,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,
-0x43FC0000,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xC0000000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xC0000000,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xC0000000,0xC0000000,0x19C0000,0x1800001,0x1800001,0x1C00000,0x1E40000,0x17FC0000,0x17FC0000,0x67FC0000,0x1C00000,0x1E40000,0x8BFC0000,0xA3FC0000,
-0x8BFC0000,0x1940001,0x1940001,0x1940001,0x1940001,0x63FC0000,0x63FC0000,0x63FC0000,0xB3F80000,0xB3F80000,0xCA000000,0x63FC0000,0x63FC0000,0x63FC0000,0xB3F80000,0xB3F80000,0xCA000000,0xB3F80000,0xB3F80000,0xCA000000,0xCA000000,0x63FC0000,0x63FC0000,0x63FC0000,0xB3F80000,0xB3F80000,0xCA000000,0xB3F80000,0xB3F80000,0xCA000000,0xCA000000,0xB3F80000,
-0xB3F80000,0xCA000000,0xCA000000,0xCA000000,0x1D80000,0x1B00000,0x1940001,0x3DFC0000,0x81FC0000,0x9FF80000,0xA9F80000,0xB9F80000,0x1FC0000,0x63FC0000,0x9FF80000,0xCA000000,0x9FF80000,0x1AC0001,0x87FC0000,0xC5F80000,0xD6000000,0x87FC0000,0xC5F80000,0xD6000000,0xC5F80000,0xD6000000,0xD6000000,0x87FC0000,0xC5F80000,0xD6000000,0xC5F80000,0xD6000000,
-0xD6000000,0xC5F80000,0xD6000000,0xD6000000,0xD6000000,0x87FC0000,0xC5F80000,0xD6000000,0xC5F80000,0xD6000000,0xD6000000,0xC5F80000,0xD6000000,0xD6000000,0xD6000000,0xC5F80000,0xD6000000,0xD6000000,0xD6000000,0xD6000000,0x3DFC0000,0xDC80000,0xDC80000,0x9DFC0000,0xBDF80000,0xCDF80000,0xD6000000,0xD6000000,0x6BFC0000,0xABFC0000,0xD5DC0000,0xD6000000,
-0xB5FC0000,0x18C0274,0xFF8000F7,0xE18000F4,0xD78000F3,0xFB780092,0xE378004F,0xD9780067,0xDB780092,0xD774004E,0xD1740092,0xF96C00F4,0xE76C0033,0xD9700051,0xDF68004A,0xD76C0002,0xD16C004D,0xD76800F4,0xD3640053,0xCF640069,0xCB6800F5,0x53FC0274,0xED5400F3,0xD76C00F4,0xE3500092,0xD75C0049,0xD1600090,0xE14000F3,0xD7480032,0xD148004D,0xCB5400F4,0xABF80274,
-0xD72000F3,0xD11C0090,0xCB1000F4,0xC4000278,0xFF8000EA,0xFD8801D4,0xFD8801FC,0xFF70000E,0xED6C0002,0xDF6C0002,0xD76C0006,0xD5680006,0xFD7400D7,0xFF600006,0xD9640035,0xD148004D,0x95FC0274,0x19800F3,0xF98C0032,0xDF8C0032,0xD78C0032,0xEF840049,0xE1800002,0xD7840005,0xD9800049,0xD580000E,0xD1800049,0x65FC00F3,0xE76C0032,0xD77C0032,0xDF680049,0xD76C0001,
-0xD1700049,0xB3FC00F3,0xD7440032,0xD1400048,0xCA0000F4,0x65FC00F3,0xE76C0032,0xD77C0032,0xDF680049,0xD76C0001,0xD1700049,0xB3FC00F3,0xD7440032,0xD1400048,0xCA0000F4,0xB3FC00F3,0xD7440032,0xD1400048,0xCA0000F4,0xCA0000F4,0xFD880063,0xF39400B9,0xF39400B6,0xFF700005,0xED6C0001,0xDF6C0001,0xD7740001,0xD7640004,0xFF780062,0xFF640002,0xD9600033,0xD1400048,
-0x9FFC00F3,0x18000F3,0x18000F3,0x18000F3,0x18000F3,0xE978004A,0xE978004A,0xE978004A,0xD374004A,0xD374004A,0xCB74004A,0xE76C0033,0xE76C0033,0xE76C0033,0xD56C0002,0xD56C0002,0xCD6C000E,0xCF680033,0xCF680033,0xCB680005,0xC5680035,0x41FC00F3,0x41FC00F3,0x41FC00F3,0xD75C0049,0xD75C0049,0xCB64004A,0xD54C0032,0xD54C0032,0xCB540001,0xC7580034,0xA1FC00F3,
-0xA1FC00F3,0xCB340048,0xC5280034,0xC00000F4,0xFF740053,0xF77C00AB,0x18000F3,0xFD6C0006,0xE96C0002,0xDD6C0002,0xDB6C0003,0xD3680001,0xFF6C0049,0xFF600002,0xD5680033,0xCB540001,0x89FC00F3,0x18C0032,0x18C0032,0x18C0032,0x18C0032,0xDD840001,0xDD840001,0xDD840001,0xCF840001,0xCF840001,0xCB800001,0x53FC0032,0x53FC0032,0x53FC0032,0xD3700001,0xD3700001,
-0xCB780000,0xABF80032,0xABF80032,0xCB580000,0xC4000034,0x53FC0032,0x53FC0032,0x53FC0032,0xD3700001,0xD3700001,0xCB780000,0xABF80032,0xABF80032,0xCB580000,0xC4000034,0xABF80032,0xABF80032,0xCB580000,0xC4000034,0xC4000034,0xF780000D,0xFD880012,0x18C0032,0xFB700001,0xE3740001,0xDB700000,0xD5740001,0xD3680000,0xFD74000D,0xFD640000,0x95FC0032,0xCB580000,
-0x95FC0032,0x1A0004A,0xED980001,0xDD940001,0xD7940001,0x75FC0048,0xE1800001,0xD7880001,0xBBFC0048,0xD7640000,0xD0000048,0x75FC0048,0xE1800001,0xD7880001,0xBBFC0048,0xD7640000,0xD0000048,0xBBFC0048,0xD7640000,0xD0000048,0xD0000048,0x75FC0048,0xE1800001,0xD7880001,0xBBFC0048,0xD7640000,0xD0000048,0xBBFC0048,0xD7640000,0xD0000048,0xD0000048,0xBBFC0048,
-0xD7640000,0xD0000048,0xD0000048,0xD0000048,0xFD900020,0x7BC0048,0xF9A00029,0xFF740002,0xED680001,0xE1640000,0xD7740000,0xD7500000,0xFB880020,0xFF640001,0xD9780000,0xD0000048,0xA9FC0048,0x174004A,0x174004A,0x174004A,0x174004A,0x174004A,0x174004A,0x174004A,0x174004A,0x174004A,0x174004A,0xD76C0001,0xD76C0001,0xD76C0001,0xD76C0001,0xD76C0001,
-0xD76C0001,0xC7680001,0xC7680001,0xC7680001,0xC1680001,0x31FC0048,0x31FC0048,0x31FC0048,0x31FC0048,0x31FC0048,0x31FC0048,0xCB540001,0xCB540001,0xCB540001,0xC15C0001,0x9BF80048,0x9BF80048,0x9BF80048,0xC1380000,0xBA000048,0xF1700022,0x174004A,0x174004A,0xFB6C0002,0xEB6C0001,0xDF6C0001,0xDF6C0001,0xD16C0001,0xF9680012,0xFD600001,0xCB680001,0xCB540001,
-0x7FFC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table57[] = {
-0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x9DFC0000,
-0x9DFC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1940000,0x1940000,0x1940000,0x37FC0000,0x83FC0000,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x5BFC0000,0x5BFC0000,0x5BFC0000,0x5BFC0000,0x5BFC0000,
-0x5BFC0000,0xAFFC0000,0xAFFC0000,0xAFFC0000,0xC8000000,0x5BFC0000,0x5BFC0000,0x5BFC0000,0x5BFC0000,0x5BFC0000,0x5BFC0000,0xAFFC0000,0xAFFC0000,0xAFFC0000,0xC8000000,0xAFFC0000,0xAFFC0000,0xAFFC0000,0xC8000000,0xC8000000,0x1AC0000,0x1900001,0x1900001,0x1D40000,0x1F80000,0x35FC0000,0x35FC0000,0x7BFC0000,0x1D40000,0x1F80000,0x9BFC0000,0xAFFC0000,
-0x9BFC0000,0x1A40001,0x1A40001,0x1A40001,0x1A40001,0x7BFC0000,0x7BFC0000,0x7BFC0000,0xBFF80000,0xBFF80000,0xD2000000,0x7BFC0000,0x7BFC0000,0x7BFC0000,0xBFF80000,0xBFF80000,0xD2000000,0xBFF80000,0xBFF80000,0xD2000000,0xD2000000,0x7BFC0000,0x7BFC0000,0x7BFC0000,0xBFF80000,0xBFF80000,0xD2000000,0xBFF80000,0xBFF80000,0xD2000000,0xD2000000,0xBFF80000,
-0xBFF80000,0xD2000000,0xD2000000,0xD2000000,0x7E80000,0x9C00000,0x1A40001,0x5BFC0000,0x93FC0000,0xADFC0000,0xB5FC0000,0xC3FC0000,0x29FC0000,0x7BFC0000,0xADFC0000,0xD2000000,0xADFC0000,0x1BC0001,0x9FFC0000,0xD1F80000,0xDE000000,0x9FFC0000,0xD1F80000,0xDE000000,0xD1F80000,0xDE000000,0xDE000000,0x9FFC0000,0xD1F80000,0xDE000000,0xD1F80000,0xDE000000,
-0xDE000000,0xD1F80000,0xDE000000,0xDE000000,0xDE000000,0x9FFC0000,0xD1F80000,0xDE000000,0xD1F80000,0xDE000000,0xDE000000,0xD1F80000,0xDE000000,0xDE000000,0xDE000000,0xD1F80000,0xDE000000,0xDE000000,0xDE000000,0xDE000000,0x63FC0000,0x1DC0000,0x1DC0000,0xB1FC0000,0xC9FC0000,0xD7F80000,0xDE000000,0xDE000000,0x89FC0000,0xBBFC0000,0xDDEC0000,0xDE000000,
-0xC3FC0000,0x19C0274,0xFD94010B,0xE99000F4,0xDF9000F3,0xFD88009A,0xEB88004F,0xE1880067,0xE3880092,0xDF84004E,0xD9840092,0xFD7C00F5,0xEF7C0033,0xE1800051,0xE778004A,0xDF7C0002,0xD97C004D,0xDF7800F4,0xDB740053,0xD7740069,0xD37800F5,0x6BFC0274,0xF56400F3,0xDF7C00F4,0xEB600092,0xDF6C0049,0xD9700090,0xE95000F3,0xDF580032,0xD958004D,0xD36400F4,0xB7F80274,
-0xDF3000F3,0xD92C0090,0xD32000F4,0xCC000278,0xFF8C0114,0xF59801FA,0xF79C0217,0xFF800026,0xF57C0002,0xE77C0002,0xDF7C0006,0xDD780006,0xFF880104,0xFF78001B,0xE1740035,0xD958004D,0xA3FC0274,0x1A800F3,0xFF9C0033,0xE79C0032,0xDF9C0032,0xF7940049,0xE9900002,0xDF940005,0xE1900049,0xDD90000E,0xD9900049,0x7DFC00F3,0xEF7C0032,0xDF8C0032,0xE7780049,0xDF7C0001,
-0xD9800049,0xBFFC00F3,0xDF540032,0xD9500048,0xD20000F4,0x7DFC00F3,0xEF7C0032,0xDF8C0032,0xE7780049,0xDF7C0001,0xD9800049,0xBFFC00F3,0xDF540032,0xD9500048,0xD20000F4,0xBFFC00F3,0xDF540032,0xD9500048,0xD20000F4,0xD20000F4,0xFB980075,0xFBA400B9,0xFBA400B6,0xFF880013,0xF57C0001,0xE77C0001,0xDF840001,0xDF740004,0xFF900071,0xFD7C000D,0xE1700033,0xD9500048,
-0xAFFC00F3,0x19000F3,0x19000F3,0x19000F3,0x19000F3,0xF188004A,0xF188004A,0xF188004A,0xDB84004A,0xDB84004A,0xD384004A,0xEF7C0033,0xEF7C0033,0xEF7C0033,0xDD7C0002,0xDD7C0002,0xD57C000E,0xD7780033,0xD7780033,0xD3780005,0xCD780035,0x59FC00F3,0x59FC00F3,0x59FC00F3,0xDF6C0049,0xDF6C0049,0xD374004A,0xDD5C0032,0xDD5C0032,0xD3640001,0xCF680034,0xADFC00F3,
-0xADFC00F3,0xD3440048,0xCD380034,0xC80000F4,0xFF840062,0xFF8C00AB,0x19000F3,0xFF80000D,0xF17C0002,0xE57C0002,0xE37C0003,0xDB780001,0xFF800055,0xFF740006,0xDD780033,0xD3640001,0x99FC00F3,0x19C0032,0x19C0032,0x19C0032,0x19C0032,0xE5940001,0xE5940001,0xE5940001,0xD7940001,0xD7940001,0xD3900001,0x6BFC0032,0x6BFC0032,0x6BFC0032,0xDB800001,0xDB800001,
-0xD3880000,0xB7F80032,0xB7F80032,0xD3680000,0xCC000034,0x6BFC0032,0x6BFC0032,0x6BFC0032,0xDB800001,0xDB800001,0xD3880000,0xB7F80032,0xB7F80032,0xD3680000,0xCC000034,0xB7F80032,0xB7F80032,0xD3680000,0xCC000034,0xCC000034,0xFF90000D,0xF5980019,0x19C0032,0xFD840002,0xEB840001,0xE3800000,0xDD840001,0xDB780000,0xFD880012,0xFB7C0002,0xA3FC0032,0xD3680000,
-0xA3FC0032,0x1B0004A,0xF5A80001,0xE5A40001,0xDFA40001,0x8DFC0048,0xE9900001,0xDF980001,0xC7FC0048,0xDF740000,0xD8000048,0x8DFC0048,0xE9900001,0xDF980001,0xC7FC0048,0xDF740000,0xD8000048,0xC7FC0048,0xDF740000,0xD8000048,0xD8000048,0x8DFC0048,0xE9900001,0xDF980001,0xC7FC0048,0xDF740000,0xD8000048,0xC7FC0048,0xDF740000,0xD8000048,0xD8000048,0xC7FC0048,
-0xDF740000,0xD8000048,0xD8000048,0xD8000048,0xF7A40029,0xFCC0048,0xFFAC002D,0xFF8C0008,0xF5780001,0xE9740000,0xDF840000,0xDF600000,0xFF980022,0xFD800005,0xE1880000,0xD8000048,0xB9FC0048,0x184004A,0x184004A,0x184004A,0x184004A,0x184004A,0x184004A,0x184004A,0x184004A,0x184004A,0x184004A,0xDF7C0001,0xDF7C0001,0xDF7C0001,0xDF7C0001,0xDF7C0001,
-0xDF7C0001,0xCF780001,0xCF780001,0xCF780001,0xC9780001,0x49FC0048,0x49FC0048,0x49FC0048,0x49FC0048,0x49FC0048,0x49FC0048,0xD3640001,0xD3640001,0xD3640001,0xC96C0001,0xA7F80048,0xA7F80048,0xA7F80048,0xC9480000,0xC2000048,0xF9800022,0x184004A,0x184004A,0xFB7C0005,0xF37C0001,0xE77C0001,0xE77C0001,0xD97C0001,0xF57C0019,0xFD740002,0xD3780001,0xD3640001,
-0x8FFC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table58[] = {
-0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0xA9FC0000,
-0xA9FC0000,0xA9FC0000,0xA9FC0000,0xC4000000,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1A40000,0x1A40000,0x1A40000,0x4FFC0000,0x93FC0000,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x75FC0000,0x75FC0000,0x75FC0000,0x75FC0000,0x75FC0000,
-0x75FC0000,0xBBFC0000,0xBBFC0000,0xBBFC0000,0xD0000000,0x75FC0000,0x75FC0000,0x75FC0000,0x75FC0000,0x75FC0000,0x75FC0000,0xBBFC0000,0xBBFC0000,0xBBFC0000,0xD0000000,0xBBFC0000,0xBBFC0000,0xBBFC0000,0xD0000000,0xD0000000,0x7BC0000,0x1A00001,0x1A00001,0x5E40000,0x1FFC0000,0x53FC0000,0x53FC0000,0x8FFC0000,0x5E40000,0x1FFC0000,0xA9FC0000,0xBBFC0000,
-0xA9FC0000,0x1B40001,0x1B40001,0x1B40001,0x1B40001,0x93FC0000,0x93FC0000,0x93FC0000,0xCBF80000,0xCBF80000,0xDA000000,0x93FC0000,0x93FC0000,0x93FC0000,0xCBF80000,0xCBF80000,0xDA000000,0xCBF80000,0xCBF80000,0xDA000000,0xDA000000,0x93FC0000,0x93FC0000,0x93FC0000,0xCBF80000,0xCBF80000,0xDA000000,0xCBF80000,0xCBF80000,0xDA000000,0xDA000000,0xCBF80000,
-0xCBF80000,0xDA000000,0xDA000000,0xDA000000,0x3FC0000,0x1D40000,0x1B40001,0x79FC0000,0xA7FC0000,0xBDF80000,0xC3FC0000,0xCFF80000,0x51FC0000,0x93FC0000,0xBDF80000,0xDA000000,0xBDF80000,0x1CC0001,0xB7FC0000,0xDDF40000,0xE6000000,0xB7FC0000,0xDDF40000,0xE6000000,0xDDF40000,0xE6000000,0xE6000000,0xB7FC0000,0xDDF40000,0xE6000000,0xDDF40000,0xE6000000,
-0xE6000000,0xDDF40000,0xE6000000,0xE6000000,0xE6000000,0xB7FC0000,0xDDF40000,0xE6000000,0xDDF40000,0xE6000000,0xE6000000,0xDDF40000,0xE6000000,0xE6000000,0xE6000000,0xDDF40000,0xE6000000,0xE6000000,0xE6000000,0xE6000000,0x8BFC0000,0x1EC0000,0x1EC0000,0xC5FC0000,0xD7FC0000,0xE1FC0000,0xE6000000,0xE6000000,0xA7FC0000,0xCDFC0000,0xE5FC0000,0xE6000000,
-0xD3FC0000,0x1AC0274,0xFFA4011F,0xF1A000F4,0xE7A000F3,0xFF9800B2,0xF398004F,0xE9980067,0xEB980092,0xE794004E,0xE1940092,0xFF900104,0xF78C0033,0xE9900051,0xEF88004A,0xE78C0002,0xE18C004D,0xE78800F4,0xE3840053,0xDF840069,0xDB8800F5,0x83FC0274,0xFD7400F3,0xE78C00F4,0xF3700092,0xE77C0049,0xE1800090,0xF16000F3,0xE7680032,0xE168004D,0xDB7400F4,0xC3F80274,
-0xE74000F3,0xE13C0090,0xDB3000F4,0xD4000278,0xFFA00136,0xFDA801FA,0xFFAC0217,0xFF940053,0xFD8C0002,0xEF8C0002,0xE78C0006,0xE5880006,0xFF98012A,0xFF8C0042,0xE9840035,0xE168004D,0xB3FC0274,0x1B800F3,0xFFB0003E,0xEFAC0032,0xE7AC0032,0xFFA40049,0xF1A00002,0xE7A40005,0xE9A00049,0xE5A0000E,0xE1A00049,0x95FC00F3,0xF78C0032,0xE79C0032,0xEF880049,0xE78C0001,
-0xE1900049,0xCBFC00F3,0xE7640032,0xE1600048,0xDA0000F4,0x95FC00F3,0xF78C0032,0xE79C0032,0xEF880049,0xE78C0001,0xE1900049,0xCBFC00F3,0xE7640032,0xE1600048,0xDA0000F4,0xCBFC00F3,0xE7640032,0xE1600048,0xDA0000F4,0xDA0000F4,0xFBAC0082,0xF3B400CB,0xF3B400CB,0xFF980029,0xFD8C0001,0xEF8C0001,0xE7940001,0xE7840004,0xFFA40082,0xFF90001E,0xE9800033,0xE1600048,
-0xBFF800F3,0x1A000F3,0x1A000F3,0x1A000F3,0x1A000F3,0xF998004A,0xF998004A,0xF998004A,0xE394004A,0xE394004A,0xDB94004A,0xF78C0033,0xF78C0033,0xF78C0033,0xE58C0002,0xE58C0002,0xDD8C000E,0xDF880033,0xDF880033,0xDB880005,0xD5880035,0x71FC00F3,0x71FC00F3,0x71FC00F3,0xE77C0049,0xE77C0049,0xDB84004A,0xE56C0032,0xE56C0032,0xDB740001,0xD7780034,0xB9FC00F3,
-0xB9FC00F3,0xDB540048,0xD5480034,0xD00000F4,0xFB980075,0xF9A000BA,0x1A000F3,0xFF90001A,0xF98C0002,0xED8C0002,0xEB8C0003,0xE3880001,0xFF940064,0xFD8C0019,0xE5880033,0xDB740001,0xA7FC00F3,0x1AC0032,0x1AC0032,0x1AC0032,0x1AC0032,0xEDA40001,0xEDA40001,0xEDA40001,0xDFA40001,0xDFA40001,0xDBA00001,0x83FC0032,0x83FC0032,0x83FC0032,0xE3900001,0xE3900001,
-0xDB980000,0xC3F80032,0xC3F80032,0xDB780000,0xD4000034,0x83FC0032,0x83FC0032,0x83FC0032,0xE3900001,0xE3900001,0xDB980000,0xC3F80032,0xC3F80032,0xDB780000,0xD4000034,0xC3F80032,0xC3F80032,0xDB780000,0xD4000034,0xD4000034,0xFFA00014,0xFDA80019,0x1AC0032,0xFF980005,0xF3940001,0xEB900000,0xE5940001,0xE3880000,0xF5A00019,0xFB900005,0xB3FC0032,0xDB780000,
-0xB3FC0032,0x1C0004A,0xFDB80001,0xEDB40001,0xE7B40001,0xA5FC0048,0xF1A00001,0xE7A80001,0xD3FC0048,0xE7840000,0xE0000048,0xA5FC0048,0xF1A00001,0xE7A80001,0xD3FC0048,0xE7840000,0xE0000048,0xD3FC0048,0xE7840000,0xE0000048,0xE0000048,0xA5FC0048,0xF1A00001,0xE7A80001,0xD3FC0048,0xE7840000,0xE0000048,0xD3FC0048,0xE7840000,0xE0000048,0xE0000048,0xD3FC0048,
-0xE7840000,0xE0000048,0xE0000048,0xE0000048,0xFFB40029,0x1E00048,0xF9C00032,0xFFA00011,0xFD880001,0xF1840000,0xE7940000,0xE7700000,0xFFAC002D,0xFD9C000D,0xE9980000,0xE0000048,0xC7FC0048,0x194004A,0x194004A,0x194004A,0x194004A,0x194004A,0x194004A,0x194004A,0x194004A,0x194004A,0x194004A,0xE78C0001,0xE78C0001,0xE78C0001,0xE78C0001,0xE78C0001,
-0xE78C0001,0xD7880001,0xD7880001,0xD7880001,0xD1880001,0x63FC0048,0x63FC0048,0x63FC0048,0x63FC0048,0x63FC0048,0x63FC0048,0xDB740001,0xDB740001,0xDB740001,0xD17C0001,0xB3F80048,0xB3F80048,0xB3F80048,0xD1580000,0xCA000048,0xF3940029,0x194004A,0x194004A,0xFD8C000A,0xFB8C0001,0xEF8C0001,0xEF8C0001,0xE18C0001,0xFD8C0019,0xF9880008,0xDB880001,0xDB740001,
-0x9FF80048,};
-static const uint32_t g_etc1_to_bc7_m6_table59[] = {
-0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0xB5FC0000,
-0xB5FC0000,0xB5FC0000,0xB5FC0000,0xCC000000,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x3B40000,0x3B40000,0x3B40000,0x69FC0000,0xA1FC0000,0x1B00001,0x1B00001,0x1B00001,0x1B00001,0x1B00001,0x1B00001,0x1B00001,0x1B00001,0x1B00001,0x1B00001,0x8DFC0000,0x8DFC0000,0x8DFC0000,0x8DFC0000,0x8DFC0000,
-0x8DFC0000,0xC7FC0000,0xC7FC0000,0xC7FC0000,0xD8000000,0x8DFC0000,0x8DFC0000,0x8DFC0000,0x8DFC0000,0x8DFC0000,0x8DFC0000,0xC7FC0000,0xC7FC0000,0xC7FC0000,0xD8000000,0xC7FC0000,0xC7FC0000,0xC7FC0000,0xD8000000,0xD8000000,0xFCC0000,0x1B00001,0x1B00001,0x1F80000,0x47FC0000,0x71FC0000,0x71FC0000,0xA3FC0000,0x1F80000,0x47FC0000,0xB9FC0000,0xC7FC0000,
-0xB9FC0000,0x1C40001,0x1C40001,0x1C40001,0x1C40001,0xABFC0000,0xABFC0000,0xABFC0000,0xD7F80000,0xD7F80000,0xE2000000,0xABFC0000,0xABFC0000,0xABFC0000,0xD7F80000,0xD7F80000,0xE2000000,0xD7F80000,0xD7F80000,0xE2000000,0xE2000000,0xABFC0000,0xABFC0000,0xABFC0000,0xD7F80000,0xD7F80000,0xE2000000,0xD7F80000,0xD7F80000,0xE2000000,0xE2000000,0xD7F80000,
-0xD7F80000,0xE2000000,0xE2000000,0xE2000000,0x3BFC0000,0x1E40000,0x1C40001,0x97FC0000,0xBBFC0000,0xCBFC0000,0xD1FC0000,0xD9FC0000,0x77FC0000,0xABFC0000,0xCBFC0000,0xE2000000,0xCBFC0000,0x1DC0001,0xCFFC0000,0xE7FC0000,0xEE000000,0xCFFC0000,0xE7FC0000,0xEE000000,0xE7FC0000,0xEE000000,0xEE000000,0xCFFC0000,0xE7FC0000,0xEE000000,0xE7FC0000,0xEE000000,
-0xEE000000,0xE7FC0000,0xEE000000,0xEE000000,0xEE000000,0xCFFC0000,0xE7FC0000,0xEE000000,0xE7FC0000,0xEE000000,0xEE000000,0xE7FC0000,0xEE000000,0xEE000000,0xEE000000,0xE7FC0000,0xEE000000,0xEE000000,0xEE000000,0xEE000000,0xB3FC0000,0x7FC0000,0x7FC0000,0xD9FC0000,0xE5FC0000,0xEBFC0000,0xEE000000,0xEE000000,0xC5FC0000,0xDDFC0000,0xEFD00000,0xEE000000,
-0xE1FC0000,0x1BC0274,0xFFB4014C,0xF9B000F4,0xEFB000F3,0xFFB000E2,0xFBA8004F,0xF1A80067,0xF3A80092,0xEFA4004E,0xE9A40092,0xFFA40121,0xFF9C0033,0xF1A00051,0xF798004A,0xEF9C0002,0xE99C004D,0xEF9800F4,0xEB940053,0xE7940069,0xE39800F5,0x9BFC0274,0xFD9000FD,0xEF9C00F4,0xFB800092,0xEF8C0049,0xE9900090,0xF97000F3,0xEF780032,0xE978004D,0xE38400F4,0xCFF80274,
-0xEF5000F3,0xE94C0090,0xE34000F4,0xDC000278,0xFFB4016B,0xF5B80224,0xF7BC0234,0xFFAC009E,0xFF9C0013,0xF79C0002,0xEF9C0006,0xED980006,0xFDB0016B,0xFFA00086,0xF1940035,0xE978004D,0xC1FC0274,0x1C800F3,0xFDC00053,0xF7BC0032,0xEFBC0032,0xFDB80059,0xF9B00002,0xEFB40005,0xF1B00049,0xEDB0000E,0xE9B00049,0xAFFC00F3,0xFF9C0032,0xEFAC0032,0xF7980049,0xEF9C0001,
-0xE9A00049,0xD7FC00F3,0xEF740032,0xE9700048,0xE20000F4,0xAFFC00F3,0xFF9C0032,0xEFAC0032,0xF7980049,0xEF9C0001,0xE9A00049,0xD7FC00F3,0xEF740032,0xE9700048,0xE20000F4,0xD7FC00F3,0xEF740032,0xE9700048,0xE20000F4,0xE20000F4,0xFFBC0095,0xFBC400CB,0xFBC400CB,0xFFB00042,0xFFA40009,0xF79C0001,0xEFA40001,0xEF940004,0xFFB4009E,0xFFAC003D,0xF1900033,0xE9700048,
-0xCDFC00F3,0x1B000F3,0x1B000F3,0x1B000F3,0x1B000F3,0xFFA8004B,0xFFA8004B,0xFFA8004B,0xEBA4004A,0xEBA4004A,0xE3A4004A,0xFF9C0033,0xFF9C0033,0xFF9C0033,0xED9C0002,0xED9C0002,0xE59C000E,0xE7980033,0xE7980033,0xE3980005,0xDD980035,0x89FC00F3,0x89FC00F3,0x89FC00F3,0xEF8C0049,0xEF8C0049,0xE394004A,0xED7C0032,0xED7C0032,0xE3840001,0xDF880034,0xC5FC00F3,
-0xC5FC00F3,0xE3640048,0xDD580034,0xD80000F4,0xFFAC0082,0xFFAC00BE,0x1B000F3,0xFFA40033,0xFF9C0003,0xF59C0002,0xF39C0003,0xEB980001,0xFFA00079,0xFF9C002A,0xED980033,0xE3840001,0xB7FC00F3,0x1BC0032,0x1BC0032,0x1BC0032,0x1BC0032,0xF5B40001,0xF5B40001,0xF5B40001,0xE7B40001,0xE7B40001,0xE3B00001,0x9BFC0032,0x9BFC0032,0x9BFC0032,0xEBA00001,0xEBA00001,
-0xE3A80000,0xCFF80032,0xCFF80032,0xE3880000,0xDC000034,0x9BFC0032,0x9BFC0032,0x9BFC0032,0xEBA00001,0xEBA00001,0xE3A80000,0xCFF80032,0xCFF80032,0xE3880000,0xDC000034,0xCFF80032,0xCFF80032,0xE3880000,0xDC000034,0xDC000034,0xFBB40019,0xF5B80022,0x1BC0032,0xFBAC000D,0xFBA40001,0xF3A00000,0xEDA40001,0xEB980000,0xFDB00019,0xFFA40008,0xC1FC0032,0xE3880000,
-0xC1FC0032,0x1D0004A,0xFFC80005,0xF5C40001,0xEFC40001,0xBDFC0048,0xF9B00001,0xEFB80001,0xDFF80048,0xEF940000,0xE8000048,0xBDFC0048,0xF9B00001,0xEFB80001,0xDFF80048,0xEF940000,0xE8000048,0xDFF80048,0xEF940000,0xE8000048,0xE8000048,0xBDFC0048,0xF9B00001,0xEFB80001,0xDFF80048,0xEF940000,0xE8000048,0xDFF80048,0xEF940000,0xE8000048,0xE8000048,0xDFF80048,
-0xEF940000,0xE8000048,0xE8000048,0xE8000048,0xFBC80034,0x1F00048,0xFFCC003A,0xFDBC0019,0xFFA40005,0xF9940000,0xEFA40000,0xEF800000,0xF9C80032,0xFBB80019,0xF1A80000,0xE8000048,0xD7FC0048,0x1A4004A,0x1A4004A,0x1A4004A,0x1A4004A,0x1A4004A,0x1A4004A,0x1A4004A,0x1A4004A,0x1A4004A,0x1A4004A,0xEF9C0001,0xEF9C0001,0xEF9C0001,0xEF9C0001,0xEF9C0001,
-0xEF9C0001,0xDF980001,0xDF980001,0xDF980001,0xD9980001,0x7BFC0048,0x7BFC0048,0x7BFC0048,0x7BFC0048,0x7BFC0048,0x7BFC0048,0xE3840001,0xE3840001,0xE3840001,0xD98C0001,0xBFF80048,0xBFF80048,0xBFF80048,0xD9680000,0xD2000048,0xFBA40029,0x1A4004A,0x1A4004A,0xFFA0000D,0xFD9C0002,0xF79C0001,0xF79C0001,0xE99C0001,0xFD9C0020,0xFB98000D,0xE3980001,0xE3840001,
-0xADFC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table60[] = {
-0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0xC3F80000,
-0xC3F80000,0xC3F80000,0xC3F80000,0xD4000001,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1C80000,0x1C80000,0x1C80000,0x83FC0000,0xB3FC0000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,
-0xA9FC0000,0xD5F80000,0xD5F80000,0xD5F80000,0xE0000001,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xD5F80000,0xD5F80000,0xD5F80000,0xE0000001,0xD5F80000,0xD5F80000,0xD5F80000,0xE0000001,0xE0000001,0x9E00000,0x1C40000,0x1C40000,0x35FC0000,0x73FC0000,0x93FC0000,0x93FC0000,0xB9FC0000,0x35FC0000,0x73FC0000,0xC9FC0000,0xD5F80000,
-0xC9FC0000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0xC7FC0000,0xC7FC0000,0xC7FC0000,0xE3FC0000,0xE3FC0000,0xEA000001,0xC7FC0000,0xC7FC0000,0xC7FC0000,0xE3FC0000,0xE3FC0000,0xEA000001,0xE3FC0000,0xE3FC0000,0xEA000001,0xEA000001,0xC7FC0000,0xC7FC0000,0xC7FC0000,0xE3FC0000,0xE3FC0000,0xEA000001,0xE3FC0000,0xE3FC0000,0xEA000001,0xEA000001,0xE3FC0000,
-0xE3FC0000,0xEA000001,0xEA000001,0xEA000001,0x7BFC0000,0x1F80000,0x1D80000,0xB9FC0000,0xD1FC0000,0xDDF80000,0xDFFC0000,0xE5FC0000,0xA3FC0000,0xC7FC0000,0xDDF80000,0xEA000001,0xDDF80000,0x1F00000,0xEBFC0000,0xF5FC0000,0xF6000001,0xEBFC0000,0xF5FC0000,0xF6000001,0xF5FC0000,0xF6000001,0xF6000001,0xEBFC0000,0xF5FC0000,0xF6000001,0xF5FC0000,0xF6000001,
-0xF6000001,0xF5FC0000,0xF6000001,0xF6000001,0xF6000001,0xEBFC0000,0xF5FC0000,0xF6000001,0xF5FC0000,0xF6000001,0xF6000001,0xF5FC0000,0xF6000001,0xF6000001,0xF6000001,0xF5FC0000,0xF6000001,0xF6000001,0xF6000001,0xF6000001,0xDFFC0000,0x97FC0000,0x97FC0000,0xEFFC0000,0xF5F80000,0xF7F40000,0xF6000001,0xF6000001,0xE7FC0000,0xF1FC0000,0xF9C40000,0xF6000001,
-0xF3FC0000,0x1CC0278,0xFFC80181,0xFFC400FD,0xF7C400F5,0xFFC40120,0xFFBC0069,0xFBBC0069,0xFDB80090,0xF7B8004D,0xF1B80092,0xFFBC015B,0xFFB4005D,0xFBB40053,0xFFAC0049,0xF7AC0002,0xF3AC004E,0xF7AC00F4,0xF5A80051,0xF1A80067,0xEDAC00F3,0xB7FC0274,0xFFAC011F,0xF7AC00F4,0xFF9C00AA,0xF99C004A,0xF1A40092,0xFF8800F5,0xF78C0033,0xF18C004F,0xED9400F4,0xDDF40274,
-0xF76800F4,0xF1600092,0xED4C00F3,0xE6000274,0xFFC401B8,0xFFCC0220,0xFFCC0234,0xFFC000F1,0xFFB40059,0xFFAC0002,0xF9B00006,0xF7AC0006,0xFFC401A8,0xFFB800EA,0xF9A80035,0xF18C004F,0xD3FC0274,0x1D800F4,0xFFD00074,0xFFCC0035,0xF7CC0035,0xFFD00074,0xFFC40009,0xF9C40005,0xF9C4004A,0xF7C0000E,0xF1C4004A,0xC9FC00F3,0xFFB80042,0xF9BC0033,0xFFAC0049,0xF7AC0002,
-0xF1B4004A,0xE5F800F3,0xF78C0033,0xF184004A,0xEC0000F3,0xC9FC00F3,0xFFB80042,0xF9BC0033,0xFFAC0049,0xF7AC0002,0xF1B4004A,0xE5F800F3,0xF78C0033,0xF184004A,0xEC0000F3,0xE5F800F3,0xF78C0033,0xF184004A,0xEC0000F3,0xEC0000F3,0xFFD000AB,0xF5D800DE,0xF5D800DD,0xFFC80076,0xFFBC002E,0xFFAC0002,0xF9B40001,0xF7A40003,0xFDD000B5,0xFFC80063,0xFBA00032,0xF184004A,
-0xDFF800F3,0x1C400F4,0x1C400F4,0x1C400F4,0x1C400F4,0xFFBC0059,0xFFBC0059,0xFFBC0059,0xF3B80049,0xF3B80049,0xEBB80049,0xFFB0003E,0xFFB0003E,0xFFB0003E,0xF7AC0001,0xF7AC0001,0xEDB0000E,0xEFAC0032,0xEFAC0032,0xEBAC0005,0xE7AC0032,0xA5FC00F3,0xA5FC00F3,0xA5FC00F3,0xF99C0049,0xF99C0049,0xEBA80049,0xF78C0032,0xF78C0032,0xEB980002,0xE79C0032,0xD3FC00F3,
-0xD3FC00F3,0xEB780049,0xE7640032,0xE00000F3,0xFFBC0095,0xF9C000CC,0x1C400F4,0xFDB80056,0xFFB00018,0xFFAC0001,0xFBAC0004,0xF3AC0001,0xFFB40091,0xFFB00045,0xF7A80032,0xEB980002,0xC7FC00F3,0x1CC0034,0x1CC0034,0x1CC0034,0x1CC0034,0xFFC40000,0xFFC40000,0xFFC40000,0xF1C40000,0xF1C40000,0xEBC40001,0xB7FC0032,0xB7FC0032,0xB7FC0032,0xF3B40001,0xF3B40001,
-0xEBBC0001,0xDDF40032,0xDDF40032,0xEBA00001,0xE6000032,0xB7FC0032,0xB7FC0032,0xB7FC0032,0xF3B40001,0xF3B40001,0xEBBC0001,0xDDF40032,0xDDF40032,0xEBA00001,0xE6000032,0xDDF40032,0xDDF40032,0xEBA00001,0xE6000032,0xE6000032,0xFDC80020,0xFFCC0020,0x1CC0034,0xFDC00014,0xFDBC0005,0xFDB00000,0xF9B40000,0xF3AC0001,0xFFC40020,0xFBC00012,0xD3FC0032,0xEBA00001,
-0xD3FC0032,0x1E40048,0xFFDC0014,0xFDD80001,0xF7D80001,0xD9FC0048,0xFFC80005,0xF7CC0001,0xEDF80048,0xF7A80001,0xF000004A,0xD9FC0048,0xFFC80005,0xF7CC0001,0xEDF80048,0xF7A80001,0xF000004A,0xEDF80048,0xF7A80001,0xF000004A,0xF000004A,0xD9FC0048,0xFFC80005,0xF7CC0001,0xEDF80048,0xF7A80001,0xF000004A,0xEDF80048,0xF7A80001,0xF000004A,0xF000004A,0xEDF80048,
-0xF7A80001,0xF000004A,0xF000004A,0xF000004A,0xF5E4003D,0x37FC0048,0xFBE4003D,0xFFD40029,0xFDCC0019,0xFFAC0001,0xF7B80001,0xF7980001,0xFFDC0032,0xFFCC0028,0xF9BC0001,0xF000004A,0xE7FC0048,0x1B80048,0x1B80048,0x1B80048,0x1B80048,0x1B80048,0x1B80048,0x1B80048,0x1B80048,0x1B80048,0x1B80048,0xFBAC0000,0xFBAC0000,0xFBAC0000,0xFBAC0000,0xFBAC0000,
-0xFBAC0000,0xE7AC0001,0xE7AC0001,0xE7AC0001,0xE1AC0001,0x95FC0048,0x95FC0048,0x95FC0048,0x95FC0048,0x95FC0048,0x95FC0048,0xEB980001,0xEB980001,0xEB980001,0xE1A00001,0xCBFC0048,0xCBFC0048,0xCBFC0048,0xE17C0001,0xDA00004A,0xF3B40034,0x1B80048,0x1B80048,0xFBB40019,0xFDB00008,0xFFAC0001,0xFFAC0001,0xF3AC0000,0xF9B00029,0xFBAC0014,0xEFA80000,0xEB980001,
-0xBFF80048,};
-static const uint32_t g_etc1_to_bc7_m6_table61[] = {
-0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0xCFF80000,
-0xCFF80000,0xCFF80000,0xCFF80000,0xDC000001,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x5D80000,0x5D80000,0x5D80000,0x9BFC0000,0xC1FC0000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,
-0xC1FC0000,0xE1F80000,0xE1F80000,0xE1F80000,0xE8000001,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xE1F80000,0xE1F80000,0xE1F80000,0xE8000001,0xE1F80000,0xE1F80000,0xE1F80000,0xE8000001,0xE8000001,0x1F40000,0x1D40000,0x1D40000,0x6DFC0000,0x9BFC0000,0xB1FC0000,0xB1FC0000,0xCDFC0000,0x6DFC0000,0x9BFC0000,0xD9FC0000,0xE1F80000,
-0xD9FC0000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0xDFFC0000,0xDFFC0000,0xDFFC0000,0xEFFC0000,0xEFFC0000,0xF2000001,0xDFFC0000,0xDFFC0000,0xDFFC0000,0xEFFC0000,0xEFFC0000,0xF2000001,0xEFFC0000,0xEFFC0000,0xF2000001,0xF2000001,0xDFFC0000,0xDFFC0000,0xDFFC0000,0xEFFC0000,0xEFFC0000,0xF2000001,0xEFFC0000,0xEFFC0000,0xF2000001,0xF2000001,0xEFFC0000,
-0xEFFC0000,0xF2000001,0xF2000001,0xF2000001,0xB5FC0000,0x57FC0000,0x1E80000,0xD7FC0000,0xE5FC0000,0xEBFC0000,0xEDFC0000,0xF1F80000,0xCBFC0000,0xDFFC0000,0xEBFC0000,0xF2000001,0xEBFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1DC0255,0xFFDC01AD,0xFFD40125,0xFFD400F4,0xFFD00159,0xFFCC00B4,0xFFCC0074,0xFFCC0099,0xFFC8004C,0xF9C80085,0xFFD00179,0xFFC800AF,0xFFC40054,0xFFC00069,0xFFBC0001,0xF9C00045,0xFFBC00DD,0xFBBC004A,0xF9B8005A,0xF5BC00DE,0xCFFC0253,0xFFC00158,0xFFBC00F3,0xFFB800D3,0xFFAC004E,0xF9B40085,0xFFAC0106,0xFF9C0032,0xF99C0042,0xF5A400DF,0xE7FC0253,
-0xFF7800F3,0xF9700085,0xF55C00DE,0xEE000253,0xFFD801C7,0xF7DC0229,0xF7DC0234,0xFFD40139,0xFFCC00B5,0xFFC0003C,0xFFC0000C,0xFFBC0005,0xFFD401B7,0xFFD00122,0xFFB80036,0xF99C0042,0xE1FC0253,0x1E800DD,0xFDE40095,0xFFE0004D,0xFFDC0034,0xFFDC0089,0xFFD8002C,0xFFD80008,0xFFD40041,0xFDD0000C,0xF9D4003D,0xDFFC00DD,0xFFD80068,0xFFCC0034,0xFFCC0059,0xFFBC0001,
-0xF9C4003D,0xEFFC00DD,0xFF9C0032,0xF994003D,0xF40000DE,0xDFFC00DD,0xFFD80068,0xFFCC0034,0xFFCC0059,0xFFBC0001,0xF9C4003D,0xEFFC00DD,0xFF9C0032,0xF994003D,0xF40000DE,0xEFFC00DD,0xFF9C0032,0xF994003D,0xF40000DE,0xF40000DE,0xFFE400B5,0xFDE800C9,0xFDE800C8,0xFFDC0089,0xFFD40062,0xFFC8001E,0xFFC40001,0xFFB40002,0xFFE000BA,0xFFDC0082,0xFFB80036,0xF994003D,
-0xEBFC00DD,0x1D400F4,0x1D400F4,0x1D400F4,0x1D400F4,0xFDCC0074,0xFDCC0074,0xFDCC0074,0xFBC80049,0xFBC80049,0xF3C80049,0xFFC40054,0xFFC40054,0xFFC40054,0xFFBC0001,0xFFBC0001,0xF5C0000E,0xF7BC0032,0xF7BC0032,0xF3BC0005,0xEFBC0032,0xBDFC00F3,0xBDFC00F3,0xBDFC00F3,0xFDB4004E,0xFDB4004E,0xF3B80049,0xFF9C0032,0xFF9C0032,0xF3A80002,0xEFAC0032,0xDFF800F3,
-0xDFF800F3,0xF3880049,0xEF740032,0xE80000F3,0xFFCC00A8,0xFFCC00E0,0x1D400F4,0xFFCC0071,0xFFC40038,0xFFC00018,0xFFC0000C,0xFBBC0001,0xFDCC00A3,0xFFC40068,0xFFB80032,0xF3A80002,0xD7FC00F3,0x1DC0034,0x1DC0034,0x1DC0034,0x1DC0034,0xFDD80008,0xFDD80008,0xFDD80008,0xF9D40000,0xF9D40000,0xF3D40001,0xCFFC0032,0xCFFC0032,0xCFFC0032,0xFBC40001,0xFBC40001,
-0xF3CC0001,0xE7FC0032,0xE7FC0032,0xF3B00001,0xEE000032,0xCFFC0032,0xCFFC0032,0xCFFC0032,0xFBC40001,0xFBC40001,0xF3CC0001,0xE7FC0032,0xE7FC0032,0xF3B00001,0xEE000032,0xE7FC0032,0xE7FC0032,0xF3B00001,0xEE000032,0xEE000032,0xFFD80022,0xF7DC0029,0x1DC0034,0xFDD80019,0xFDD0000D,0xFFC80005,0xFFC40001,0xFBBC0001,0xF1DC0029,0xFBD40019,0xE1FC0032,0xF3B00001,
-0xE1FC0032,0x1F4003D,0xFFEC0028,0xFFEC000D,0xFFE80000,0xEFFC003D,0xFFE40014,0xFFDC0000,0xF7F8003D,0xFFB80000,0xF800003D,0xEFFC003D,0xFFE40014,0xFFDC0000,0xF7F8003D,0xFFB80000,0xF800003D,0xF7F8003D,0xFFB80000,0xF800003D,0xF800003D,0xEFFC003D,0xFFE40014,0xFFDC0000,0xF7F8003D,0xFFB80000,0xF800003D,0xF7F8003D,0xFFB80000,0xF800003D,0xF800003D,0xF7F8003D,
-0xFFB80000,0xF800003D,0xF800003D,0xF800003D,0xFBF00034,0xA7FC003D,0xF3F4003D,0xFFEC0029,0xFFE80020,0xFFD40011,0xFFC80000,0xFFA80000,0xFFF00032,0xFFEC0032,0xFFD00001,0xF800003D,0xF5FC003D,0x1C80048,0x1C80048,0x1C80048,0x1C80048,0x1C80048,0x1C80048,0x1C80048,0x1C80048,0x1C80048,0x1C80048,0xFFBC0001,0xFFBC0001,0xFFBC0001,0xFFBC0001,0xFFBC0001,
-0xFFBC0001,0xEFBC0001,0xEFBC0001,0xEFBC0001,0xE9BC0001,0xAFFC0048,0xAFFC0048,0xAFFC0048,0xAFFC0048,0xAFFC0048,0xAFFC0048,0xF3A80001,0xF3A80001,0xF3A80001,0xE9B00001,0xD7FC0048,0xD7FC0048,0xD7FC0048,0xE98C0001,0xE200004A,0xFBC40034,0x1C80048,0x1C80048,0xFBC40020,0xFDC00014,0xFDC00008,0xFDC00008,0xFBBC0000,0xF5C40032,0xFFBC001D,0xF7B80000,0xF3A80001,
-0xCDFC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table62[] = {
-0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xDBF80000,
-0xDBF80000,0xDBF80000,0xDBF80000,0xE4000001,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0xDE80000,0xDE80000,0xDE80000,0xB5FC0000,0xD1FC0000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,
-0xD9FC0000,0xEDF80000,0xEDF80000,0xEDF80000,0xF0000001,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xEDF80000,0xEDF80000,0xEDF80000,0xF0000001,0xEDF80000,0xEDF80000,0xEDF80000,0xF0000001,0xF0000001,0x37FC0000,0x1E40000,0x1E40000,0xA7FC0000,0xC1FC0000,0xCFFC0000,0xCFFC0000,0xE1FC0000,0xA7FC0000,0xC1FC0000,0xE7FC0000,0xEDF80000,
-0xE7FC0000,0x1F80000,0x1F80000,0x1F80000,0x1F80000,0xF7FC0000,0xF7FC0000,0xF7FC0000,0xFBFC0000,0xFBFC0000,0xFA000001,0xF7FC0000,0xF7FC0000,0xF7FC0000,0xFBFC0000,0xFBFC0000,0xFA000001,0xFBFC0000,0xFBFC0000,0xFA000001,0xFA000001,0xF7FC0000,0xF7FC0000,0xF7FC0000,0xFBFC0000,0xFBFC0000,0xFA000001,0xFBFC0000,0xFBFC0000,0xFA000001,0xFA000001,0xFBFC0000,
-0xFBFC0000,0xFA000001,0xFA000001,0xFA000001,0xEDFC0000,0xD7FC0000,0x1F80000,0xF5FC0000,0xF9FC0000,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xF3FC0000,0xF7FC0000,0xFBFC0000,0xFA000001,0xFBFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1E80181,0xFFE80139,0xFFE40104,0xFFE400F4,0xFFE000FD,0xFFE000B2,0xFFDC0090,0xFFD80075,0xFFD80051,0xFDD8004D,0xFFDC00FD,0xFFDC00A8,0xFFDC0084,0xFFD80051,0xFFD00021,0xFFD00011,0xFFCC0072,0xFFCC0032,0xFDCC000E,0xF9CC005E,0xE3FC017F,0xFFD80118,0xFFD400F3,0xFFCC00A9,0xFFCC0069,0xFDC8004D,0xFFC000AE,0xFFB80045,0xFDB40006,0xF9B8005E,0xF1F8017F,
-0xFFA800F3,0xFD90004D,0xF97C005E,0xF400017F,0xFFE40135,0xFDE8015D,0xFDE8016C,0xFFE000F5,0xFFDC00A3,0xFFD40055,0xFFD00038,0xFFD0000E,0xFFE40142,0xFFDC00E3,0xFFD0004E,0xFDB40006,0xEDFC017F,0x1F4005D,0xFDF0004D,0xFFF00038,0xFFEC0034,0xFFEC003D,0xFFEC0022,0xFFE80014,0xFFE40011,0xFFE40001,0xFDE40005,0xF1FC005D,0xFFEC0043,0xFFE40034,0xFFE40021,0xFFD80009,
-0xFDD80005,0xF9F8005D,0xFFCC0032,0xFDB40005,0xF800005E,0xF1FC005D,0xFFEC0043,0xFFE40034,0xFFE40021,0xFFD80009,0xFDD80005,0xF9F8005D,0xFFCC0032,0xFDB40005,0xF800005E,0xF9F8005D,0xFFCC0032,0xFDB40005,0xF800005E,0xF800005E,0xFDF00051,0xF3F4005D,0xF3F4005D,0xFFEC0042,0xFFE80030,0xFFE4001B,0xFFE0000D,0xFFD80008,0xFBF00051,0xFFE80044,0xFFDC0033,0xFDB40005,
-0xF7FC005D,0x1E400F4,0x1E400F4,0x1E400F4,0x1E400F4,0xFFDC0090,0xFFDC0090,0xFFDC0090,0xFFD80051,0xFFD80051,0xFBD80049,0xFFDC0084,0xFFDC0084,0xFFDC0084,0xFFD00021,0xFFD00021,0xFDD0000E,0xFFCC0032,0xFFCC0032,0xFBCC0005,0xF7CC0032,0xD5FC00F3,0xD5FC00F3,0xD5FC00F3,0xFFCC0069,0xFFCC0069,0xFBC80049,0xFFB80045,0xFFB80045,0xFBB80002,0xF7BC0032,0xEBF800F3,
-0xEBF800F3,0xFB980049,0xF7840032,0xF00000F3,0xFBE000C9,0xF9E000E1,0x1E400F4,0xFFDC0095,0xFFD80068,0xFFD40045,0xFFD00038,0xFFD0000E,0xFDE000CA,0xFFDC0092,0xFFD0004D,0xFBB80002,0xE5FC00F3,0x1EC0034,0x1EC0034,0x1EC0034,0x1EC0034,0xFFE80014,0xFFE80014,0xFFE80014,0xFFE40001,0xFFE40001,0xFBE40001,0xE9FC0032,0xE9FC0032,0xE9FC0032,0xFFD80009,0xFFD80009,
-0xFBDC0001,0xF3FC0032,0xF3FC0032,0xFBC00001,0xF6000032,0xE9FC0032,0xE9FC0032,0xE9FC0032,0xFFD80009,0xFFD80009,0xFBDC0001,0xF3FC0032,0xF3FC0032,0xFBC00001,0xF6000032,0xF3FC0032,0xF3FC0032,0xFBC00001,0xF6000032,0xF6000032,0xFBEC0029,0xFFEC0029,0x1EC0034,0xF9EC0029,0xFDE80020,0xFFE40012,0xFFE0000D,0xFFD80008,0xF9EC0029,0xFFE80020,0xF1FC0032,0xFBC00001,
-0xF1FC0032,0x1FC0005,0xFFF80004,0xFFF80001,0xFFF80000,0xFBFC0005,0xFFF80002,0xFFF40000,0xFDF80005,0xFFEC0000,0xFC000005,0xFBFC0005,0xFFF80002,0xFFF40000,0xFDF80005,0xFFEC0000,0xFC000005,0xFDF80005,0xFFEC0000,0xFC000005,0xFC000005,0xFBFC0005,0xFFF80002,0xFFF40000,0xFDF80005,0xFFEC0000,0xFC000005,0xFDF80005,0xFFEC0000,0xFC000005,0xFC000005,0xFDF80005,
-0xFFEC0000,0xFC000005,0xFC000005,0xFC000005,0xFFF80004,0xE7FC0005,0xF7FC0005,0xFBFC0005,0xFFF80002,0xFFF00001,0xFFF00000,0xFFE40000,0xF9FC0005,0xFBFC0005,0xFFF00000,0xFC000005,0xFDF80005,0x1D80048,0x1D80048,0x1D80048,0x1D80048,0x1D80048,0x1D80048,0x1D80048,0x1D80048,0x1D80048,0x1D80048,0xFFD00008,0xFFD00008,0xFFD00008,0xFFD00008,0xFFD00008,
-0xFFD00008,0xF7CC0001,0xF7CC0001,0xF7CC0001,0xF1CC0001,0xC7FC0048,0xC7FC0048,0xC7FC0048,0xC7FC0048,0xC7FC0048,0xC7FC0048,0xFBB80001,0xFBB80001,0xFBB80001,0xF1C00001,0xE3FC0048,0xE3FC0048,0xE3FC0048,0xF19C0001,0xEA00004A,0xF5D8003D,0x1D80048,0x1D80048,0xFDD40029,0xFFD0001D,0xFDD00014,0xFDD00014,0xFFCC0004,0xFDD40032,0xFFD00022,0xFFC80000,0xFBB80001,
-0xDDF80048,};
-static const uint32_t g_etc1_to_bc7_m6_table63[] = {
-0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xE7F80000,
-0xE7F80000,0xE7F80000,0xE7F80000,0xEC000001,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1FC0000,0x1FC0000,0x1FC0000,0xCDFC0000,0xDFFC0000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0xF1FC0000,0xF1FC0000,0xF1FC0000,0xF1FC0000,0xF1FC0000,
-0xF1FC0000,0xF9F80000,0xF9F80000,0xF9F80000,0xF8000001,0xF1FC0000,0xF1FC0000,0xF1FC0000,0xF1FC0000,0xF1FC0000,0xF1FC0000,0xF9F80000,0xF9F80000,0xF9F80000,0xF8000001,0xF9F80000,0xF9F80000,0xF9F80000,0xF8000001,0xF8000001,0xB7FC0000,0x1F40000,0x1F40000,0xDFFC0000,0xE9FC0000,0xEFFC0000,0xEFFC0000,0xF3FC0000,0xDFFC0000,0xE9FC0000,0xF7FC0000,0xF9F80000,
-0xF7FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1F400C2,0xFDF000B2,0xFFF0009D,0xFFF00099,0xFFEC0098,0xFFEC007D,0xFFEC0074,0xFFEC0062,0xFFE80058,0xFFE80048,0xFFEC0089,0xFFE80069,0xFFE80059,0xFFE40040,0xFFE40030,0xFFE0001D,0xFFE40031,0xFFE0001D,0xFFDC0001,0xFDDC0011,0xEFFC00C2,0xFFEC00A7,0xFFE80099,0xFFE40070,0xFFE40060,0xFFDC0048,0xFFD80059,0xFFD80035,0xFFCC0009,0xFDCC0011,0xF7F800C2,
-0xFFD40099,0xFFB80048,0xFD9C0011,0xF80000C2,0xFDF000B0,0xF3F400C2,0xF3F400C2,0xFFF0008E,0xFFEC006D,0xFFE8004A,0xFFE8003D,0xFFE40022,0xFFF000A2,0xFFF0008E,0xFFE0003F,0xFFCC0009,0xF5FC00C2,0x1FC0012,0xFFF80011,0xFFF8000E,0xFFF8000D,0xFFF8000C,0xFFF80009,0xFFF80008,0xFFF80006,0xFFF40004,0xFFF40000,0xFBFC0011,0xFFF8000E,0xFFF4000D,0xFFF00008,0xFFF00004,
-0xFFF00000,0xFDF80011,0xFFEC000D,0xFFE00000,0xFC000011,0xFBFC0011,0xFFF8000E,0xFFF4000D,0xFFF00008,0xFFF00004,0xFFF00000,0xFDF80011,0xFFEC000D,0xFFE00000,0xFC000011,0xFDF80011,0xFFEC000D,0xFFE00000,0xFC000011,0xFC000011,0xFFF80011,0xF7FC0012,0xF7FC0012,0xFFF8000C,0xFFF4000E,0xFFF40006,0xFFF40005,0xFFEC0004,0xFFF8000C,0xFBFC0011,0xFFF0000D,0xFFE00000,
-0xFDF80011,0x1F00099,0x1F00099,0x1F00099,0x1F00099,0xFFEC0074,0xFFEC0074,0xFFEC0074,0xFFE80058,0xFFE80058,0xFFE80048,0xFFE80059,0xFFE80059,0xFFE80059,0xFFE40030,0xFFE40030,0xFFE0001D,0xFFE0001D,0xFFE0001D,0xFFDC0001,0xFDDC000D,0xEBFC0099,0xEBFC0099,0xEBFC0099,0xFFE40060,0xFFE40060,0xFFDC0048,0xFFD80035,0xFFD80035,0xFFCC0009,0xFDCC000D,0xF5FC0099,
-0xF5FC0099,0xFFB80048,0xFD9C000D,0xF600009A,0xFFEC0089,0xFFEC0090,0x1F00099,0xFFE80074,0xFFEC005D,0xFFE80046,0xFFE8003D,0xFFE40022,0xFBEC0089,0xFFE80072,0xFFE0003E,0xFFCC0009,0xF3FC0099,0x1F8000D,0x1F8000D,0x1F8000D,0x1F8000D,0xFFF80008,0xFFF80008,0xFFF80008,0xFFF40004,0xFFF40004,0xFFF40000,0xF7FC000D,0xF7FC000D,0xF7FC000D,0xFFF00004,0xFFF00004,
-0xFFF00000,0xFBFC000D,0xFBFC000D,0xFFE00000,0xFC00000D,0xF7FC000D,0xF7FC000D,0xF7FC000D,0xFFF00004,0xFFF00004,0xFFF00000,0xFBFC000D,0xFBFC000D,0xFFE00000,0xFC00000D,0xFBFC000D,0xFBFC000D,0xFFE00000,0xFC00000D,0xFC00000D,0xF5FC000D,0xF5F8000D,0x1F8000D,0xFFF80008,0xFFF4000A,0xFFF40005,0xFFF40005,0xFFEC0004,0xFFF80008,0xFFF4000A,0xFBFC000D,0xFFE00000,
-0xFBFC000D,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1E80048,0x1E80048,0x1E80048,0x1E80048,0x1E80048,0x1E80048,0x1E80048,0x1E80048,0x1E80048,0x1E80048,0xFFE0001D,0xFFE0001D,0xFFE0001D,0xFFE0001D,0xFFE0001D,
-0xFFE0001D,0xFFDC0001,0xFFDC0001,0xFFDC0001,0xF9DC0001,0xDFFC0048,0xDFFC0048,0xDFFC0048,0xDFFC0048,0xDFFC0048,0xDFFC0048,0xFFCC0009,0xFFCC0009,0xFFCC0009,0xF9D00001,0xEFFC0048,0xEFFC0048,0xEFFC0048,0xF9AC0001,0xF200004A,0xFDE8003D,0x1E80048,0x1E80048,0xFDE40034,0xFFE40029,0xFFE00028,0xFFE00028,0xFFE00014,0xF9E8003D,0xFFE40032,0xFFDC000A,0xFFCC0009,
-0xEBFC0048,};
-static const uint32_t g_etc1_to_bc7_m6_table64[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x100001,0x100001,0x100001,0x100001,0x2180000,0x2180000,0x2180000,0x300000,0x300000,0x8000000,0x2180000,0x2180000,0x2180000,0x300000,0x300000,0x8000000,0x300000,0x300000,0x8000000,0x8000000,0x2180000,0x2180000,0x2180000,0x300000,0x300000,0x8000000,0x300000,0x300000,0x8000000,0x8000000,0x300000,
-0x300000,0x8000000,0x8000000,0x8000000,0x140000,0x140000,0x100001,0x180000,0x1C0000,0x240000,0x280000,0x3C0000,0x2140000,0x2180000,0x240000,0x8000000,0x240000,0x380001,0x540000,0xAC0000,0x1C000000,0x540000,0xAC0000,0x1C000000,0xAC0000,0x1C000000,0x1C000000,0x540000,0xAC0000,0x1C000000,0xAC0000,0x1C000000,
-0x1C000000,0xAC0000,0x1C000000,0x1C000000,0x1C000000,0x540000,0xAC0000,0x1C000000,0xAC0000,0x1C000000,0x1C000000,0xAC0000,0x1C000000,0x1C000000,0x1C000000,0xAC0000,0x1C000000,0x1C000000,0x1C000000,0x1C000000,0x480000,0x63C0000,0x63C0000,0x600000,0x8C0000,0x1140000,0x1C000000,0x1C000000,0x24C0000,0x6C0000,0xFD00000,0x1C000000,
-0x780000,0x140232,0x4E080039,0x28080039,0x1C040039,0x380000C8,0x28000011,0x1C000001,0x1C0000C8,0x16000048,0x120000C8,0x260001B9,0x22000096,0x18000051,0x18000110,0x16000088,0x120000EC,0x120001B9,0x1000010D,0x10000149,0xC0001B9,0x1C0232,0x1E000109,0x18000091,0x18000150,0x140000BB,0x12000110,0x120001DD,0x10000131,0xE000165,0xC0001C9,0x300232,
-0x10000186,0xA0001AA,0xA0001F2,0x8000232,0x7400007B,0xFA0400D2,0xFE0C0082,0x3400007B,0x2200008A,0x1A00007B,0x16000061,0x140000B5,0x460000F1,0x280000BD,0x160000CB,0xE000165,0x240232,0x1801BA,0x4E080029,0x28080029,0x1C080029,0x380000C8,0x28000011,0x1C000001,0x1C0000C8,0x16000048,0x120000C8,0x22401B9,0x22000096,0x18000051,0x18000110,0x16000088,
-0x120000EC,0x4C01B9,0x1000010D,0x10000149,0xC0001B9,0x22401B9,0x22000096,0x18000051,0x18000110,0x16000088,0x120000EC,0x4C01B9,0x1000010D,0x10000149,0xC0001B9,0x4C01B9,0x1000010D,0x10000149,0xC0001B9,0xC0001B9,0x7400007B,0xFA0400CE,0xFE0C005E,0x3400007B,0x2200008A,0x1A00007B,0x16000061,0x140000B5,0x500000DB,0x280000B4,0x160000CA,0x10000149,
-0x3401B9,0x40039,0x40039,0x40039,0x40039,0x1A000000,0x1A000000,0x1A000000,0xC000000,0xC000000,0x8000000,0xA000029,0xA000029,0xA000029,0xC000010,0xC000010,0x6000008,0x6000029,0x6000029,0x4000019,0x4000029,0x80036,0x80036,0x80036,0x6000018,0x6000018,0x600000C,0x600002D,0x600002D,0x400001D,0x400002D,0xC0036,
-0xC0036,0x4000022,0x2000031,0x2000036,0x3600000A,0x88000000,0x40039,0x1C000011,0x1000000D,0xC00000D,0xC00000A,0xA000011,0x1600001A,0x10000013,0x6000029,0x400001D,0xC0036,0x80029,0x80029,0x80029,0x80029,0x1A000000,0x1A000000,0x1A000000,0xC000000,0xC000000,0x8000000,0xC0029,0xC0029,0xC0029,0xC000010,0xC000010,
-0x6000008,0x140029,0x140029,0x4000019,0x4000029,0xC0029,0xC0029,0xC0029,0xC000010,0xC000010,0x6000008,0x140029,0x140029,0x4000019,0x4000029,0x140029,0x140029,0x4000019,0x4000029,0x4000029,0x3600000A,0x88000000,0x80029,0x1C000011,0x1000000D,0xC00000D,0xC00000A,0xA000011,0x16000019,0x10000012,0x100029,0x4000019,
-0x100029,0x2400CA,0x42140001,0x26100001,0x1C100001,0x3800C8,0x28000011,0x1C000001,0x7000C8,0x16000048,0x120000C8,0x3800C8,0x28000011,0x1C000001,0x7000C8,0x16000048,0x120000C8,0x7000C8,0x16000048,0x120000C8,0x120000C8,0x3800C8,0x28000011,0x1C000001,0x7000C8,0x16000048,0x120000C8,0x7000C8,0x16000048,0x120000C8,0x120000C8,0x7000C8,
-0x16000048,0x120000C8,0x120000C8,0x120000C8,0x7400004A,0x2800C8,0xF418000D,0x3C000041,0x2A000049,0x1E000041,0x18000034,0x18000061,0x50000062,0x34000050,0x1C000028,0x120000C8,0x5000C8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table65[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x200001,0x200001,0x200001,0x200001,0x2300000,0x2300000,0x2300000,0x640000,0x640000,0x10000000,0x2300000,0x2300000,0x2300000,0x640000,0x640000,0x10000000,0x640000,0x640000,0x10000000,0x10000000,0x2300000,0x2300000,0x2300000,0x640000,0x640000,0x10000000,0x640000,0x640000,0x10000000,0x10000000,0x640000,
-0x640000,0x10000000,0x10000000,0x10000000,0x280000,0x240000,0x200001,0x22C0000,0x380000,0x480000,0x500000,0x780000,0x2280000,0x2300000,0x480000,0x10000000,0x480000,0x480001,0x6C0000,0xDC0000,0x24000000,0x6C0000,0xDC0000,0x24000000,0xDC0000,0x24000000,0x24000000,0x6C0000,0xDC0000,0x24000000,0xDC0000,0x24000000,
-0x24000000,0xDC0000,0x24000000,0x24000000,0x24000000,0x6C0000,0xDC0000,0x24000000,0xDC0000,0x24000000,0x24000000,0xDC0000,0x24000000,0x24000000,0x24000000,0xDC0000,0x24000000,0x24000000,0x24000000,0x24000000,0x5C0000,0xE4C0000,0xE4C0000,0x7C0000,0xB40000,0x1600000,0x24000000,0x24000000,0x640000,0x880000,0x17E00000,0x24000000,
-0x9C0000,0x1C03A2,0x620C00C1,0x320C00C2,0x240C00C1,0x500000C8,0x34000001,0x26000014,0x260000CA,0x20000029,0x1A0000C8,0x360002AE,0x2E0000FE,0x220000A1,0x22000153,0x1E000098,0x18000110,0x1A0002AE,0x160001A9,0x160001C9,0x100002B1,0x2803A2,0x280001B3,0x2200011A,0x220001CC,0x1E0000FC,0x18000150,0x180002F1,0x160001E9,0x14000205,0x100002D5,0x4C03A2,
-0x1600028A,0x10000282,0x1000032A,0xC0003A2,0x96000085,0xFE0C0142,0xF2140189,0x48000099,0x360000A2,0x26000098,0x1E000065,0x1C0000E0,0x6400015C,0x3C0000E9,0x1E000145,0x14000205,0x3403A2,0x2402AE,0x5E100091,0x32100091,0x24100091,0x500000C8,0x34000001,0x26040011,0x260000CA,0x20000029,0x1A0000C8,0x3402AE,0x2E0000FE,0x220000A1,0x22000153,0x1E000098,
-0x18000110,0x6802AE,0x160001A9,0x160001C9,0x100002B1,0x3402AE,0x2E0000FE,0x220000A1,0x22000153,0x1E000098,0x18000110,0x6802AE,0x160001A9,0x160001C9,0x100002B1,0x6802AE,0x160001A9,0x160001C9,0x100002B1,0x100002B1,0x96000085,0xFE0C011E,0xF418010D,0x48000099,0x360000A2,0x26000098,0x1E000065,0x1C0000E0,0x64000138,0x3C0000D9,0x1E000141,0x160001C9,
-0x4C02AE,0xC00C1,0xC00C1,0xC00C1,0xC00C1,0x32000000,0x32000000,0x32000000,0x18000000,0x18000000,0x10000000,0x16000091,0x16000091,0x16000091,0x12000034,0x12000034,0xE00001D,0xC000091,0xC000091,0xA000055,0x8000091,0x1000C1,0x1000C1,0x1000C1,0x12000058,0x12000058,0xC000030,0xC0000A1,0xC0000A1,0xA000065,0x6000099,0x2000C1,
-0x2000C1,0xA000086,0x60000AE,0x40000C2,0x6000002D,0xF8000001,0xC00C1,0x3200003A,0x1E000034,0x1A00003A,0x1600002D,0xE000048,0x3400005E,0x26000054,0xE000092,0xA000065,0x1800C1,0x100091,0x100091,0x100091,0x100091,0x32000000,0x32000000,0x32000000,0x18000000,0x18000000,0x10000000,0x180091,0x180091,0x180091,0x12000034,0x12000034,
-0xE00001D,0x2C0091,0x2C0091,0xA000055,0x8000091,0x180091,0x180091,0x180091,0x12000034,0x12000034,0xE00001D,0x2C0091,0x2C0091,0xA000055,0x8000091,0x2C0091,0x2C0091,0xA000055,0x8000091,0x8000091,0x6000002D,0xF8000001,0x100091,0x3200003A,0x1E000034,0x1A00003A,0x1600002D,0xE000048,0x34000055,0x26000050,0x200091,0xA000055,
-0x200091,0x3400CA,0x4A240001,0x2E200001,0x24200001,0x5000C8,0x34000001,0x240C0001,0xA000C8,0x20000029,0x1A0000C8,0x5000C8,0x34000001,0x240C0001,0xA000C8,0x20000029,0x1A0000C8,0xA000C8,0x20000029,0x1A0000C8,0x1A0000C8,0x5000C8,0x34000001,0x240C0001,0xA000C8,0x20000029,0x1A0000C8,0xA000C8,0x20000029,0x1A0000C8,0x1A0000C8,0xA000C8,
-0x20000029,0x1A0000C8,0x1A0000C8,0x1A0000C8,0xA400002D,0x43800C8,0xFC28000D,0x52000022,0x36000029,0x28000029,0x22000014,0x20000041,0x72000048,0x46000034,0x2400000D,0x1A0000C8,0x7000C8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table66[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0x140000,0x140000,0x140000,0x140000,0x140000,
-0x140000,0x240000,0x240000,0x240000,0x6000000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x240000,0x240000,0x240000,0x6000000,0x240000,0x240000,0x240000,0x6000000,0x6000000,0xE0C0000,0xC0001,0xC0001,0x100000,0x100000,0x2100000,0x2100000,0x2140000,0x100000,0x100000,0x1C0000,0x240000,
-0x1C0000,0x300001,0x300001,0x300001,0x300001,0x480000,0x480000,0x480000,0x940000,0x940000,0x18000000,0x480000,0x480000,0x480000,0x940000,0x940000,0x18000000,0x940000,0x940000,0x18000000,0x18000000,0x480000,0x480000,0x480000,0x940000,0x940000,0x18000000,0x940000,0x940000,0x18000000,0x18000000,0x940000,
-0x940000,0x18000000,0x18000000,0x18000000,0x4380000,0x2340000,0x300001,0x440000,0x540000,0x680000,0x780000,0xB40000,0x23C0000,0x480000,0x680000,0x18000000,0x680000,0x580001,0x840000,0x10C0000,0x2C000000,0x840000,0x10C0000,0x2C000000,0x10C0000,0x2C000000,0x2C000000,0x840000,0x10C0000,0x2C000000,0x10C0000,0x2C000000,
-0x2C000000,0x10C0000,0x2C000000,0x2C000000,0x2C000000,0x840000,0x10C0000,0x2C000000,0x10C0000,0x2C000000,0x2C000000,0x10C0000,0x2C000000,0x2C000000,0x2C000000,0x10C0000,0x2C000000,0x2C000000,0x2C000000,0x2C000000,0x700000,0x600000,0x600000,0x2940000,0xDC0000,0x1B00000,0x2C000000,0x2C000000,0x2780000,0xA80000,0x1FF00000,0x2C000000,
-0xBC0000,0x2804C3,0x7414014E,0x3C14014F,0x2C14014E,0x600800E1,0x4008001A,0x2C0C0049,0x300800E3,0x28040036,0x220800E1,0x4E0002D3,0x3A0000CD,0x2C0000A4,0x2E00011A,0x2800003D,0x220000D8,0x260002D3,0x2000017A,0x1C0001A0,0x180002D4,0x3804C1,0x34000216,0x2800016D,0x280001F7,0x280000E6,0x22000151,0x22000354,0x200001F3,0x1C000204,0x18000314,0x7004C1,
-0x1C00031D,0x1A000305,0x160003C9,0x120004C1,0xC2000036,0xF41801F1,0xF8200266,0x6600003E,0x40000049,0x34000043,0x2A000015,0x24000084,0x82000121,0x5000009F,0x26000118,0x1C000204,0x5004C1,0x3402D3,0x662000A2,0x3A2000A2,0x2C2000A2,0x581000C9,0x3C100002,0x2E100015,0x300C00C9,0x2A080026,0x220C00C9,0x4C02D3,0x3A0000CD,0x2C0400A2,0x2E00011A,0x2800003D,
-0x220000D8,0x9802D3,0x2000017A,0x1C0001A0,0x180002D4,0x4C02D3,0x3A0000CD,0x2C0400A2,0x2E00011A,0x2800003D,0x220000D8,0x9802D3,0x2000017A,0x1C0001A0,0x180002D4,0x9802D3,0x2000017A,0x1C0001A0,0x180002D4,0x180002D4,0xC2000036,0xF8200139,0xFC280126,0x6600003E,0x40000049,0x34000043,0x2A000015,0x24000084,0x900000DD,0x50000086,0x26000114,0x1C0001A0,
-0x6C02D3,0x14014E,0x14014E,0x14014E,0x14014E,0x42080019,0x42080019,0x42080019,0x22080019,0x22080019,0x18080019,0x300000A2,0x300000A2,0x300000A2,0x22000011,0x22000011,0x18000001,0x160000A4,0x160000A4,0x14000041,0xE0000A4,0x20014D,0x20014D,0x20014D,0x1E00007D,0x1E00007D,0x14000041,0x120000D8,0x120000D8,0x1200006C,0xE0000BD,0x3C014D,
-0x3C014D,0x100000C9,0xA000105,0xA00014D,0xA000000D,0xFE0C002E,0x14014E,0x50000019,0x32000019,0x2A000014,0x2600000D,0x20000025,0x56000063,0x3C000042,0x1E0000A6,0x1200006C,0x2C014D,0x2000A2,0x2000A2,0x2000A2,0x2000A2,0x3A100001,0x3A100001,0x3A100001,0x20100001,0x20100001,0x180C0001,0x3000A2,0x3000A2,0x3000A2,0x22000011,0x22000011,
-0x18000001,0x5C00A2,0x5C00A2,0x14000041,0xE0000A4,0x3000A2,0x3000A2,0x3000A2,0x22000011,0x22000011,0x18000001,0x5C00A2,0x5C00A2,0x14000041,0xE0000A4,0x5C00A2,0x5C00A2,0x14000041,0xE0000A4,0xE0000A4,0xA000000D,0xF0100005,0x2000A2,0x50000019,0x32000019,0x2A000014,0x2600000D,0x20000025,0x64000041,0x3C000032,0x4000A2,0x14000041,
-0x4000A2,0x4400CA,0x52340001,0x36300001,0x2C300001,0x6800C8,0x3C100001,0x2C1C0001,0xD000C8,0x2A000014,0x220000C8,0x6800C8,0x3C100001,0x2C1C0001,0xD000C8,0x2A000014,0x220000C8,0xD000C8,0x2A000014,0x220000C8,0x220000C8,0x6800C8,0x3C100001,0x2C1C0001,0xD000C8,0x2A000014,0x220000C8,0xD000C8,0x2A000014,0x220000C8,0x220000C8,0xD000C8,
-0x2A000014,0x220000C8,0x220000C8,0x220000C8,0xC4040019,0xC4800C8,0xF4380012,0x6600000D,0x42040019,0x36000011,0x2C000004,0x28000029,0x94000032,0x58000019,0x2E000001,0x220000C8,0x9400C8,0x80019,0x80019,0x80019,0x80019,0x80019,0x80019,0x80019,0x80019,0x80019,0x80019,0x14000000,0x14000000,0x14000000,0x14000000,0x14000000,
-0x14000000,0xA000000,0xA000000,0xA000000,0x6000000,0x80019,0x80019,0x80019,0x80019,0x80019,0x80019,0x6000008,0x6000008,0x6000008,0x6000004,0xC0019,0xC0019,0xC0019,0x400000D,0x2000019,0x68000000,0x80019,0x80019,0x2E000000,0x20000000,0x18000000,0x18000000,0x10000000,0x20000008,0x20000004,0xC000001,0x6000008,
-0xC0019,};
-static const uint32_t g_etc1_to_bc7_m6_table67[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,
-0x2C0000,0x580000,0x580000,0x580000,0xE000000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x580000,0x580000,0x580000,0xE000000,0x580000,0x580000,0x580000,0xE000000,0xE000000,0x200000,0x1C0001,0x1C0001,0x6200000,0x240000,0x280000,0x280000,0x300000,0x6200000,0x240000,0x3C0000,0x580000,
-0x3C0000,0x400001,0x400001,0x400001,0x400001,0x600000,0x600000,0x600000,0xC40000,0xC40000,0x20000000,0x600000,0x600000,0x600000,0xC40000,0xC40000,0x20000000,0xC40000,0xC40000,0x20000000,0x20000000,0x600000,0x600000,0x600000,0xC40000,0xC40000,0x20000000,0xC40000,0xC40000,0x20000000,0x20000000,0xC40000,
-0xC40000,0x20000000,0x20000000,0x20000000,0x4C0000,0xA440000,0x400001,0x580000,0x26C0000,0x8C0000,0xA00000,0xF00000,0x4500000,0x600000,0x8C0000,0x20000000,0x8C0000,0x680001,0x9C0000,0x13C0000,0x34000000,0x9C0000,0x13C0000,0x34000000,0x13C0000,0x34000000,0x34000000,0x9C0000,0x13C0000,0x34000000,0x13C0000,0x34000000,
-0x34000000,0x13C0000,0x34000000,0x34000000,0x34000000,0x9C0000,0x13C0000,0x34000000,0x13C0000,0x34000000,0x34000000,0x13C0000,0x34000000,0x34000000,0x34000000,0x13C0000,0x34000000,0x34000000,0x34000000,0x34000000,0x840000,0x700000,0x700000,0xB00000,0x1000000,0x3F00000,0x34000000,0x34000000,0x900000,0xC40000,0x29C40000,0x34000000,
-0xE00000,0x340627,0x80200222,0x46200222,0x34200222,0x72100139,0x4C100076,0x361400C1,0x3A10013B,0x320C0082,0x2A100139,0x660002D3,0x4C0000A5,0x360800C8,0x3C0000E9,0x32000009,0x2A0000C9,0x320002D3,0x2C00012A,0x26000161,0x200002D4,0x480625,0x400002BE,0x34000225,0x3400024F,0x2E000106,0x2800017D,0x2E0003BC,0x280001FB,0x24000204,0x1E00034C,0x940625,
-0x26000412,0x200003A5,0x1C00047D,0x18000625,0xF8000009,0xFA2402DD,0xFE2C038E,0x7E00000B,0x5600000E,0x40000009,0x36000004,0x30000032,0xA40000F6,0x66000062,0x340000D4,0x24000204,0x680625,0x4402D3,0x6E3000A2,0x423000A2,0x343000A2,0x602000C9,0x44200002,0x36200015,0x381C00C9,0x32180026,0x2A1C00C9,0x6402D3,0x4C0000A5,0x341400A2,0x3C0000E9,0x32000009,
-0x2A0400C8,0xCC02D3,0x2C00012A,0x26000161,0x200002D4,0x6402D3,0x4C0000A5,0x341400A2,0x3C0000E9,0x32000009,0x2A0400C8,0xCC02D3,0x2C00012A,0x26000161,0x200002D4,0xCC02D3,0x2C00012A,0x26000161,0x200002D4,0x200002D4,0xF8000009,0xFE2C0141,0xF438013B,0x7E00000B,0x5600000E,0x40000009,0x34040002,0x30000032,0xAC000086,0x68000035,0x340000CB,0x26000161,
-0x9002D3,0x200222,0x200222,0x200222,0x200222,0x52100071,0x52100071,0x52100071,0x2C100071,0x2C100071,0x20100071,0x480000A2,0x480000A2,0x480000A2,0x2E000001,0x2E000001,0x2204000C,0x220000A2,0x220000A2,0x1C000020,0x160000A4,0x300222,0x300222,0x300222,0x280000C6,0x280000C6,0x1E000081,0x1E000118,0x1E000118,0x1A00007E,0x160000E4,0x5C0222,
-0x5C0222,0x16000145,0x14000178,0xE000225,0xE8000000,0xF21400BD,0x200222,0x7A000004,0x50000001,0x3C000002,0x36000000,0x2A000005,0x8200006D,0x56000032,0x2C0000AB,0x1A00007E,0x400222,0x3000A2,0x3000A2,0x3000A2,0x3000A2,0x42200001,0x42200001,0x42200001,0x28200001,0x28200001,0x201C0001,0x24400A2,0x24400A2,0x24400A2,0x2E000001,0x2E000001,
-0x200C0000,0x8C00A2,0x8C00A2,0x1C000020,0x160000A4,0x24400A2,0x24400A2,0x24400A2,0x2E000001,0x2E000001,0x200C0000,0x8C00A2,0x8C00A2,0x1C000020,0x160000A4,0x8C00A2,0x8C00A2,0x1C000020,0x160000A4,0x160000A4,0xE8000000,0xF8200005,0x3000A2,0x7A000004,0x50000001,0x3C000002,0x36000000,0x2A000005,0x96000028,0x5A000012,0x6400A2,0x1C000020,
-0x6400A2,0x5400CA,0x5A440001,0x3E400001,0x34400001,0x8000C8,0x44200001,0x342C0001,0x10000C8,0x32000005,0x2A0000C8,0x8000C8,0x44200001,0x342C0001,0x10000C8,0x32000005,0x2A0000C8,0x10000C8,0x32000005,0x2A0000C8,0x2A0000C8,0x8000C8,0x44200001,0x342C0001,0x10000C8,0x32000005,0x2A0000C8,0x10000C8,0x32000005,0x2A0000C8,0x2A0000C8,0x10000C8,
-0x32000005,0x2A0000C8,0x2A0000C8,0x2A0000C8,0xF8000008,0x5C00C8,0xFC480012,0x7E000002,0x56000005,0x3E040005,0x34080000,0x32000014,0xB6000020,0x6E00000A,0x36100001,0x2A0000C8,0xB400C8,0x100071,0x100071,0x100071,0x100071,0x100071,0x100071,0x100071,0x100071,0x100071,0x100071,0x2C000000,0x2C000000,0x2C000000,0x2C000000,0x2C000000,
-0x2C000000,0x16000000,0x16000000,0x16000000,0xE000000,0x140071,0x140071,0x140071,0x140071,0x140071,0x140071,0x12000028,0x12000028,0x12000028,0xC000014,0x240071,0x240071,0x240071,0xA000041,0x6000071,0xE8000000,0x100071,0x100071,0x68000000,0x48000000,0x36000000,0x36000000,0x24000000,0x52000022,0x42000011,0x1C000004,0x12000028,
-0x1C0071,};
-static const uint32_t g_etc1_to_bc7_m6_table68[] = {
-0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0x140000,
-0x140000,0x140000,0x140000,0x2000001,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0xC0000,0x100000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,
-0x2440000,0x8C0000,0x8C0000,0x8C0000,0x16000001,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x8C0000,0x8C0000,0x8C0000,0x16000001,0x8C0000,0x8C0000,0x8C0000,0x16000001,0x16000001,0x340000,0x300000,0x300000,0x380000,0x3C0000,0x400000,0x400000,0x500000,0x380000,0x3C0000,0x640000,0x8C0000,
-0x640000,0x540000,0x540000,0x540000,0x540000,0x7C0000,0x7C0000,0x7C0000,0xFC0000,0xFC0000,0x28000001,0x7C0000,0x7C0000,0x7C0000,0xFC0000,0xFC0000,0x28000001,0xFC0000,0xFC0000,0x28000001,0x28000001,0x7C0000,0x7C0000,0x7C0000,0xFC0000,0xFC0000,0x28000001,0xFC0000,0xFC0000,0x28000001,0x28000001,0xFC0000,
-0xFC0000,0x28000001,0x28000001,0x28000001,0x2600000,0x4580000,0x540000,0x2700000,0x8C0000,0xB00000,0xCC0000,0x1340000,0x680000,0x7C0000,0xB00000,0x28000001,0xB00000,0x7C0000,0xB80000,0x1740000,0x3C000001,0xB80000,0x1740000,0x3C000001,0x1740000,0x3C000001,0x3C000001,0xB80000,0x1740000,0x3C000001,0x1740000,0x3C000001,
-0x3C000001,0x1740000,0x3C000001,0x3C000001,0x3C000001,0xB80000,0x1740000,0x3C000001,0x1740000,0x3C000001,0x3C000001,0x1740000,0x3C000001,0x3C000001,0x3C000001,0x1740000,0x3C000001,0x3C000001,0x3C000001,0x3C000001,0x9C0000,0x840000,0x840000,0xD00000,0x12C0000,0xDF80000,0x3C000001,0x3C000001,0xA80000,0xE80000,0x31F40000,0x3C000001,
-0x1080000,0x400738,0x8A3002D4,0x503002D4,0x3C3002D5,0x801C0190,0x581C00D5,0x3E24013A,0x461C0190,0x3A1C00D5,0x321C0192,0x7A0802D3,0x5A0800A2,0x421400FF,0x4A0800D1,0x3C080002,0x320C00D7,0x3C0802D4,0x380000FD,0x3000013B,0x2A0802D3,0x600734,0x5200031F,0x3C0802D4,0x46000252,0x3A000107,0x320001A4,0x3A0003C9,0x340001AE,0x2E0001B3,0x2800032C,0xC40734,
-0x2C000479,0x2C0003F2,0x260004DF,0x20000734,0xFC100021,0xF23403D0,0xF63C049C,0x92080000,0x64080001,0x4A080002,0x3E0C0012,0x3A080011,0xD000008E,0x7E000018,0x3E0000AB,0x2E0001B3,0x8C0734,0x5402D4,0x764400A4,0x4A4400A4,0x3C4000A5,0x6C3000C8,0x4E300001,0x3E340015,0x403000C8,0x3A2C0026,0x323000CA,0x8002D3,0x580C00A2,0x3C2800A3,0x4C0000C9,0x3C080002,
-0x341400CA,0x10002D3,0x380000ED,0x3000012B,0x2A0002D3,0x8002D3,0x580C00A2,0x3C2800A3,0x4C0000C9,0x3C080002,0x341400CA,0x10002D3,0x380000ED,0x3000012B,0x2A0002D3,0x10002D3,0x380000ED,0x3000012B,0x2A0002D3,0x2A0002D3,0xFE140009,0xFA44014C,0xFE4C0138,0x92080000,0x64080001,0x4A080002,0x3E140002,0x3A00000A,0xD000003D,0x7E000008,0x3E0000AB,0x3000012B,
-0xB402D3,0x3002D4,0x3002D4,0x3002D4,0x3002D4,0x621C00C8,0x621C00C8,0x621C00C8,0x361C00C8,0x361C00C8,0x281C00C9,0x5A0800A2,0x5A0800A2,0x5A0800A2,0x3C080001,0x3C080001,0x2C0C0026,0x2E0800A2,0x2E0800A2,0x28040015,0x200800A2,0x4402D3,0x4402D3,0x4402D3,0x340000FE,0x340000FE,0x2A0000C9,0x2E00011D,0x2E00011D,0x2400005A,0x1E0000CE,0x8802D3,
-0x8802D3,0x20000199,0x1C0001A3,0x160002D3,0xFE0C0009,0xFA240139,0x3002D4,0x92080000,0x60080001,0x4A080001,0x440C0006,0x36080002,0xB400004B,0x76000012,0x3E0000A2,0x2400005A,0x6002D3,0x4000A4,0x4000A4,0x4000A4,0x4000A4,0x4E300000,0x4E300000,0x4E300000,0x32300000,0x32300000,0x28300001,0x6000A2,0x6000A2,0x6000A2,0x38100001,0x38100001,
-0x28200001,0xC400A2,0xC400A2,0x2600000D,0x200000A2,0x6000A2,0x6000A2,0x6000A2,0x38100001,0x38100001,0x28200001,0xC400A2,0xC400A2,0x2600000D,0x200000A2,0xC400A2,0xC400A2,0x2600000D,0x200000A2,0x200000A2,0xEA140000,0xF2340008,0x4000A4,0x92080000,0x5E0C0000,0x480C0000,0x3E140001,0x38040000,0xC200000D,0x7C000002,0x8C00A2,0x2600000D,
-0x8C00A2,0x6800C8,0x66540000,0x46540001,0x3C540001,0x29800C8,0x4E300001,0x3C400001,0x13800C8,0x3C040001,0x320000CA,0x29800C8,0x4E300001,0x3C400001,0x13800C8,0x3C040001,0x320000CA,0x13800C8,0x3C040001,0x320000CA,0x320000CA,0x29800C8,0x4E300001,0x3C400001,0x13800C8,0x3C040001,0x320000CA,0x13800C8,0x3C040001,0x320000CA,0x320000CA,0x13800C8,
-0x3C040001,0x320000CA,0x320000CA,0x320000CA,0xFE140008,0xE6C00C8,0xF65C0019,0x8E0C0000,0x64040001,0x4C040000,0x3C1C0001,0x3A00000A,0xD6040012,0x7E040002,0x40200000,0x320000CA,0xDC00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x40080000,0x40080000,0x40080000,0x40080000,0x40080000,
-0x40080000,0x20080001,0x20080001,0x20080001,0x16080001,0x2800C8,0x2800C8,0x2800C8,0x2800C8,0x2800C8,0x2800C8,0x1E00002D,0x1E00002D,0x1E00002D,0x16000011,0x5000C8,0x5000C8,0x5000C8,0x10000062,0xC0000CA,0xFE0C0008,0x1C00C8,0x1C00C8,0x8E080000,0x64080000,0x4E080000,0x4E080000,0x34080000,0x92000022,0x74000009,0x28040001,0x1E00002D,
-0x3800C8,};
-static const uint32_t g_etc1_to_bc7_m6_table69[] = {
-0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x240000,0x240000,0x240000,0x240000,0x240000,0x240000,0x240000,0x240000,0x240000,0x240000,0x440000,
-0x440000,0x440000,0x440000,0xA000001,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x4180000,0x4180000,0x4180000,0x240000,0x300000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,
-0x25C0000,0xBC0000,0xBC0000,0xBC0000,0x1E000001,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0xBC0000,0xBC0000,0xBC0000,0x1E000001,0xBC0000,0xBC0000,0xBC0000,0x1E000001,0x1E000001,0x440000,0x400000,0x400000,0x4480000,0x500000,0x2540000,0x2540000,0x6C0000,0x4480000,0x500000,0x880000,0xBC0000,
-0x880000,0x640000,0x640000,0x640000,0x640000,0x940000,0x940000,0x940000,0x12C0000,0x12C0000,0x30000001,0x940000,0x940000,0x940000,0x12C0000,0x12C0000,0x30000001,0x12C0000,0x12C0000,0x30000001,0x30000001,0x940000,0x940000,0x940000,0x12C0000,0x12C0000,0x30000001,0x12C0000,0x12C0000,0x30000001,0x30000001,0x12C0000,
-0x12C0000,0x30000001,0x30000001,0x30000001,0x740000,0xC680000,0x640000,0x880000,0xA80000,0xD40000,0xF40000,0x1700000,0x7C0000,0x940000,0xD40000,0x30000001,0xD40000,0x8C0000,0xD00000,0x1A40000,0x44000001,0xD00000,0x1A40000,0x44000001,0x1A40000,0x44000001,0x44000001,0xD00000,0x1A40000,0x44000001,0x1A40000,0x44000001,
-0x44000001,0x1A40000,0x44000001,0x44000001,0x44000001,0xD00000,0x1A40000,0x44000001,0x1A40000,0x44000001,0x44000001,0x1A40000,0x44000001,0x44000001,0x44000001,0x1A40000,0x44000001,0x44000001,0x44000001,0x44000001,0xB00000,0x2940000,0x2940000,0xEC0000,0x1540000,0x17F80000,0x44000001,0x44000001,0x2BC0000,0x1040000,0x3BC80000,0x44000001,
-0x1280000,0x500738,0x924002D4,0x584002D4,0x444002D5,0x882C0190,0x602C00D5,0x4634013A,0x4E2C0190,0x422C00D5,0x3A2C0192,0x821802D3,0x621800A2,0x4A2400FF,0x521800D1,0x44180002,0x3A1C00D7,0x441802D4,0x401000FD,0x3810013B,0x321802D3,0x780734,0x620002DD,0x441802D4,0x520001E2,0x460000CF,0x3A080192,0x46000361,0x4000011E,0x3800012F,0x300002EB,0xF40734,
-0x38000401,0x32000352,0x2C000477,0x28000734,0xFE20002A,0xFA4403D0,0xFE4C049C,0x9A180000,0x6C180001,0x52180002,0x461C0012,0x42180011,0xF6000022,0x8E080002,0x480C00A9,0x3800012F,0xAC0734,0x6402D4,0x7E5400A4,0x525400A4,0x445000A5,0x744000C8,0x56400001,0x46440015,0x484000C8,0x423C0026,0x3A4000CA,0x9802D3,0x601C00A2,0x443800A3,0x541000C9,0x44180002,
-0x3C2400CA,0x13002D3,0x420000CB,0x380000FE,0x320002D3,0x9802D3,0x601C00A2,0x443800A3,0x541000C9,0x44180002,0x3C2400CA,0x13002D3,0x420000CB,0x380000FE,0x320002D3,0x13002D3,0x420000CB,0x380000FE,0x320002D3,0x320002D3,0xF8280011,0xF254015E,0xF65C014D,0x9A180000,0x6C180001,0x52180002,0x46240002,0x440C0005,0xFA000013,0x8E080001,0x4A0400A2,0x380000FE,
-0xD802D3,0x4002D4,0x4002D4,0x4002D4,0x4002D4,0x6A2C00C8,0x6A2C00C8,0x6A2C00C8,0x3E2C00C8,0x3E2C00C8,0x302C00C9,0x621800A2,0x621800A2,0x621800A2,0x44180001,0x44180001,0x341C0026,0x361800A2,0x361800A2,0x30140015,0x281800A2,0x5C02D3,0x5C02D3,0x5C02D3,0x460000CE,0x460000CE,0x321000C9,0x3A0000D5,0x3A0000D5,0x2E000012,0x280000A3,0xB802D3,
-0xB802D3,0x2A00015B,0x2400016B,0x1E0002D3,0xFC1C0011,0xF234014C,0x4002D4,0x9A180000,0x68180001,0x52180001,0x4C1C0006,0x3E180002,0xE400000D,0x8E080001,0x461000A2,0x2E000012,0x8002D3,0x5000A4,0x5000A4,0x5000A4,0x5000A4,0x56400000,0x56400000,0x56400000,0x3A400000,0x3A400000,0x30400001,0x7800A2,0x7800A2,0x7800A2,0x40200001,0x40200001,
-0x30300001,0xF400A2,0xF400A2,0x30000002,0x280000A2,0x7800A2,0x7800A2,0x7800A2,0x40200001,0x40200001,0x30300001,0xF400A2,0xF400A2,0x30000002,0x280000A2,0xF400A2,0xF400A2,0x30000002,0x280000A2,0x280000A2,0xF2240000,0xFA440008,0x5000A4,0x9A180000,0x661C0000,0x501C0000,0x46240001,0x40140000,0xF4000004,0x8E080000,0xAC00A2,0x30000002,
-0xAC00A2,0x7800C8,0x6E640000,0x4E640001,0x44640001,0x2B000C8,0x56400001,0x44500001,0x16800C8,0x44140001,0x3A0000CA,0x2B000C8,0x56400001,0x44500001,0x16800C8,0x44140001,0x3A0000CA,0x16800C8,0x44140001,0x3A0000CA,0x3A0000CA,0x2B000C8,0x56400001,0x44500001,0x16800C8,0x44140001,0x3A0000CA,0x16800C8,0x44140001,0x3A0000CA,0x3A0000CA,0x16800C8,
-0x44140001,0x3A0000CA,0x3A0000CA,0x3A0000CA,0xF828000D,0x8000C8,0xFE6C0019,0x961C0000,0x6C140001,0x54140000,0x442C0001,0x44000002,0xF8040008,0x90080000,0x48300000,0x3A0000CA,0xFC00C8,0x2C00C8,0x2C00C8,0x2C00C8,0x2C00C8,0x2C00C8,0x2C00C8,0x2C00C8,0x2C00C8,0x2C00C8,0x2C00C8,0x48180000,0x48180000,0x48180000,0x48180000,0x48180000,
-0x48180000,0x28180001,0x28180001,0x28180001,0x1E180001,0x4000C8,0x4000C8,0x4000C8,0x4000C8,0x4000C8,0x4000C8,0x2E000009,0x2E000009,0x2E000009,0x1E040001,0x8000C8,0x8000C8,0x8000C8,0x1C00003A,0x140000CA,0xF61C000D,0x2C00C8,0x2C00C8,0x96180000,0x6C180000,0x56180000,0x56180000,0x3C180000,0xE0000004,0x86080001,0x30140001,0x2E000009,
-0x5C00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table70[] = {
-0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x740000,
-0x740000,0x740000,0x740000,0x12000001,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0xC280000,0xC280000,0xC280000,0x3C0000,0x540000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,
-0x2740000,0xF00000,0xF00000,0xF00000,0x26000001,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0xF00000,0xF00000,0xF00000,0x26000001,0xF00000,0xF00000,0xF00000,0x26000001,0x26000001,0x2540000,0x500000,0x500000,0x5C0000,0x640000,0x6C0000,0x6C0000,0x840000,0x5C0000,0x640000,0xA80000,0xF00000,
-0xA80000,0x740000,0x740000,0x740000,0x740000,0xAC0000,0xAC0000,0xAC0000,0x15C0000,0x15C0000,0x38000001,0xAC0000,0xAC0000,0xAC0000,0x15C0000,0x15C0000,0x38000001,0x15C0000,0x15C0000,0x38000001,0x38000001,0xAC0000,0xAC0000,0xAC0000,0x15C0000,0x15C0000,0x38000001,0x15C0000,0x15C0000,0x38000001,0x38000001,0x15C0000,
-0x15C0000,0x38000001,0x38000001,0x38000001,0x6840000,0x7C0000,0x740000,0x9C0000,0x2C00000,0xF40000,0x11C0000,0x1AC0000,0x900000,0xAC0000,0xF40000,0x38000001,0xF40000,0x9C0000,0xE80000,0x1D80000,0x4C000001,0xE80000,0x1D80000,0x4C000001,0x1D80000,0x4C000001,0x4C000001,0xE80000,0x1D80000,0x4C000001,0x1D80000,0x4C000001,
-0x4C000001,0x1D80000,0x4C000001,0x4C000001,0x4C000001,0xE80000,0x1D80000,0x4C000001,0x1D80000,0x4C000001,0x4C000001,0x1D80000,0x4C000001,0x4C000001,0x4C000001,0x1D80000,0x4C000001,0x4C000001,0x4C000001,0x4C000001,0xC40000,0xAA40000,0xAA40000,0x1040000,0x17C0000,0x21FC0000,0x4C000001,0x4C000001,0xD40000,0x1240000,0x43D80000,0x4C000001,
-0x14C0000,0x600738,0x9A5002D4,0x605002D4,0x4C5002D5,0x903C0190,0x683C00D5,0x4E44013A,0x563C0190,0x4A3C00D5,0x423C0192,0x8A2802D3,0x6A2800A2,0x523400FF,0x5A2800D1,0x4C280002,0x422C00D7,0x4C2802D4,0x482000FD,0x4020013B,0x3A2802D3,0x900734,0x720402D3,0x4C2802D4,0x6200019A,0x4E1000CF,0x42180192,0x52000319,0x4A0000C6,0x420000E7,0x3A0002D4,0x1240734,
-0x440003A9,0x3E0002E2,0x3600041C,0x30000734,0xFE34003D,0xF2540402,0xF65C04C1,0xA2280000,0x74280001,0x5A280002,0x4E2C0012,0x4A280011,0xFE100022,0x96180002,0x501C00A9,0x420000E7,0xD00734,0x7402D4,0x866400A4,0x5A6400A4,0x4C6000A5,0x7C5000C8,0x5E500001,0x4E540015,0x505000C8,0x4A4C0026,0x425000CA,0xB002D3,0x682C00A2,0x4C4800A3,0x5C2000C9,0x4C280002,
-0x443400CA,0x16402D3,0x4A0000AD,0x420000E3,0x3A0002D3,0xB002D3,0x682C00A2,0x4C4800A3,0x5C2000C9,0x4C280002,0x443400CA,0x16402D3,0x4A0000AD,0x420000E3,0x3A0002D3,0x16402D3,0x4A0000AD,0x420000E3,0x3A0002D3,0x3A0002D3,0xFC380018,0xFA64015E,0xFE6C014D,0xA2280000,0x74280001,0x5A280002,0x4E340002,0x4C1C0005,0xFE100019,0x96180001,0x521400A2,0x420000E3,
-0xF802D3,0x5002D4,0x5002D4,0x5002D4,0x5002D4,0x723C00C8,0x723C00C8,0x723C00C8,0x463C00C8,0x463C00C8,0x383C00C9,0x6A2800A2,0x6A2800A2,0x6A2800A2,0x4C280001,0x4C280001,0x3C2C0026,0x3E2800A2,0x3E2800A2,0x38240015,0x302800A2,0x7402D3,0x7402D3,0x7402D3,0x520800C9,0x520800C9,0x3A2000C9,0x460000AD,0x460000AD,0x38040002,0x300C00A2,0xE802D3,
-0xE802D3,0x32000119,0x2C000126,0x260002D3,0xFE2C0016,0xFA44014C,0x5002D4,0xA2280000,0x70280001,0x5A280001,0x542C0006,0x46280002,0xFA0C0005,0x96180001,0x4E2000A2,0x38040002,0xA402D3,0x6000A4,0x6000A4,0x6000A4,0x6000A4,0x5E500000,0x5E500000,0x5E500000,0x42500000,0x42500000,0x38500001,0x9000A2,0x9000A2,0x9000A2,0x48300001,0x48300001,
-0x38400001,0x12400A2,0x12400A2,0x38080001,0x300000A2,0x9000A2,0x9000A2,0x9000A2,0x48300001,0x48300001,0x38400001,0x12400A2,0x12400A2,0x38080001,0x300000A2,0x12400A2,0x12400A2,0x38080001,0x300000A2,0x300000A2,0xFA340000,0xF254000D,0x6000A4,0xA2280000,0x6E2C0000,0x582C0000,0x4E340001,0x48240000,0xFE0C0002,0x96180000,0xD000A2,0x38080001,
-0xD000A2,0x8800C8,0x76740000,0x56740001,0x4C740001,0xC800C8,0x5E500001,0x4C600001,0x19800C8,0x4C240001,0x420000CA,0xC800C8,0x5E500001,0x4C600001,0x19800C8,0x4C240001,0x420000CA,0x19800C8,0x4C240001,0x420000CA,0x420000CA,0xC800C8,0x5E500001,0x4C600001,0x19800C8,0x4C240001,0x420000CA,0x19800C8,0x4C240001,0x420000CA,0x420000CA,0x19800C8,
-0x4C240001,0x420000CA,0x420000CA,0x420000CA,0xFA3C0012,0x9000C8,0xF67C0020,0x9E2C0000,0x74240001,0x5C240000,0x4C3C0001,0x4C080001,0xFC14000A,0x98180000,0x50400000,0x420000CA,0x12000C8,0x3C00C8,0x3C00C8,0x3C00C8,0x3C00C8,0x3C00C8,0x3C00C8,0x3C00C8,0x3C00C8,0x3C00C8,0x3C00C8,0x50280000,0x50280000,0x50280000,0x50280000,0x50280000,
-0x50280000,0x30280001,0x30280001,0x30280001,0x26280001,0x5800C8,0x5800C8,0x5800C8,0x5800C8,0x5800C8,0x5800C8,0x38040001,0x38040001,0x38040001,0x26140001,0xB000C8,0xB000C8,0xB000C8,0x24000022,0x1C0000CA,0xFE2C000D,0x3C00C8,0x3C00C8,0x9E280000,0x74280000,0x5E280000,0x5E280000,0x44280000,0xF40C0001,0x8E180001,0x38240001,0x38040001,
-0x7C00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table71[] = {
-0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,0xA40000,
-0xA40000,0xA40000,0xA40000,0x1A000001,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x3C0000,0x3C0000,0x3C0000,0x2500000,0x740000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,
-0x28C0000,0x1200000,0x1200000,0x1200000,0x2E000001,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x1200000,0x1200000,0x1200000,0x2E000001,0x1200000,0x1200000,0x1200000,0x2E000001,0x2E000001,0xA640000,0x600000,0x600000,0x700000,0x780000,0x2800000,0x2800000,0xA00000,0x700000,0x780000,0xCC0000,0x1200000,
-0xCC0000,0x840000,0x840000,0x840000,0x840000,0xC40000,0xC40000,0xC40000,0x18C0000,0x18C0000,0x40000001,0xC40000,0xC40000,0xC40000,0x18C0000,0x18C0000,0x40000001,0x18C0000,0x18C0000,0x40000001,0x40000001,0xC40000,0xC40000,0xC40000,0x18C0000,0x18C0000,0x40000001,0x18C0000,0x18C0000,0x40000001,0x40000001,0x18C0000,
-0x18C0000,0x40000001,0x40000001,0x40000001,0x2980000,0x8C0000,0x840000,0xB40000,0xDC0000,0x1180000,0x1400000,0x1E80000,0xA40000,0xC40000,0x1180000,0x40000001,0x1180000,0xAC0000,0x1000000,0x5F80000,0x54000001,0x1000000,0x5F80000,0x54000001,0x5F80000,0x54000001,0x54000001,0x1000000,0x5F80000,0x54000001,0x5F80000,0x54000001,
-0x54000001,0x5F80000,0x54000001,0x54000001,0x54000001,0x1000000,0x5F80000,0x54000001,0x5F80000,0x54000001,0x54000001,0x5F80000,0x54000001,0x54000001,0x54000001,0x5F80000,0x54000001,0x54000001,0x54000001,0x54000001,0xD80000,0xB80000,0xB80000,0x1200000,0x1A40000,0x2BFC0000,0x54000001,0x54000001,0x2E80000,0x3400000,0x4BE80000,0x54000001,
-0x16C0000,0x700738,0xA26002D4,0x686002D4,0x546002D5,0x984C0190,0x704C00D5,0x5654013A,0x5E4C0190,0x524C00D5,0x4A4C0192,0x923802D3,0x723800A2,0x5A4400FF,0x623800D1,0x54380002,0x4A3C00D7,0x543802D4,0x503000FD,0x4830013B,0x423802D3,0xA80734,0x7A1402D3,0x543802D4,0x6C080192,0x562000CF,0x4A280192,0x620002E3,0x540000A3,0x4A0000D7,0x421002D4,0x1580734,
-0x4A000361,0x44000272,0x3E0003BF,0x38000734,0xFE440056,0xFA640402,0xFE6C04C1,0xAA380000,0x7C380001,0x62380002,0x563C0012,0x52380011,0xFE24003B,0x9E280002,0x582C00A9,0x4A0000D7,0xF00734,0x8402D4,0x8E7400A4,0x627400A4,0x547000A5,0x846000C8,0x66600001,0x56640015,0x586000C8,0x525C0026,0x4A6000CA,0x2C402D3,0x703C00A2,0x545800A3,0x643000C9,0x54380002,
-0x4C4400CA,0x19402D3,0x540000A3,0x4A0000CE,0x420002D3,0x2C402D3,0x703C00A2,0x545800A3,0x643000C9,0x54380002,0x4C4400CA,0x19402D3,0x540000A3,0x4A0000CE,0x420002D3,0x19402D3,0x540000A3,0x4A0000CE,0x420002D3,0x420002D3,0xFC4C001D,0xF2740174,0xF67C0164,0xAA380000,0x7C380001,0x62380002,0x56440002,0x542C0005,0xFE240022,0x9E280001,0x5A2400A2,0x4A0000CE,
-0x11C02D3,0x6002D4,0x6002D4,0x6002D4,0x6002D4,0x7A4C00C8,0x7A4C00C8,0x7A4C00C8,0x4E4C00C8,0x4E4C00C8,0x404C00C9,0x723800A2,0x723800A2,0x723800A2,0x54380001,0x54380001,0x443C0026,0x463800A2,0x463800A2,0x40340015,0x383800A2,0x8C02D3,0x8C02D3,0x8C02D3,0x5A1800C9,0x5A1800C9,0x423000C9,0x540000A2,0x540000A2,0x40140002,0x381C00A2,0x11802D3,
-0x11802D3,0x3E0000F1,0x360000FB,0x2E0002D3,0xF840001D,0xF2540161,0x6002D4,0xAA380000,0x78380001,0x62380001,0x5C3C0006,0x4E380002,0xFC1C000A,0x9E280001,0x563000A2,0x40140002,0xC802D3,0x7000A4,0x7000A4,0x7000A4,0x7000A4,0x66600000,0x66600000,0x66600000,0x4A600000,0x4A600000,0x40600001,0xA800A2,0xA800A2,0xA800A2,0x50400001,0x50400001,
-0x40500001,0x15800A2,0x15800A2,0x40180001,0x380000A2,0xA800A2,0xA800A2,0xA800A2,0x50400001,0x50400001,0x40500001,0x15800A2,0x15800A2,0x40180001,0x380000A2,0x15800A2,0x15800A2,0x40180001,0x380000A2,0x380000A2,0xF6480001,0xFA64000D,0x7000A4,0xAA380000,0x763C0000,0x603C0000,0x56440001,0x50340000,0xF6240005,0x9E280000,0xF000A2,0x40180001,
-0xF000A2,0x9800C8,0x7E840000,0x5E840001,0x54840001,0xE000C8,0x66600001,0x54700001,0x1CC00C8,0x54340001,0x4A0000CA,0xE000C8,0x66600001,0x54700001,0x1CC00C8,0x54340001,0x4A0000CA,0x1CC00C8,0x54340001,0x4A0000CA,0x4A0000CA,0xE000C8,0x66600001,0x54700001,0x1CC00C8,0x54340001,0x4A0000CA,0x1CC00C8,0x54340001,0x4A0000CA,0x4A0000CA,0x1CC00C8,
-0x54340001,0x4A0000CA,0x4A0000CA,0x4A0000CA,0xFC4C0014,0x8A000C8,0xFE8C0020,0xA63C0000,0x7C340001,0x64340000,0x544C0001,0x54180001,0xFE2C000D,0xA0280000,0x58500000,0x4A0000CA,0x14000C8,0x4C00C8,0x4C00C8,0x4C00C8,0x4C00C8,0x4C00C8,0x4C00C8,0x4C00C8,0x4C00C8,0x4C00C8,0x4C00C8,0x58380000,0x58380000,0x58380000,0x58380000,0x58380000,
-0x58380000,0x38380001,0x38380001,0x38380001,0x2E380001,0x7000C8,0x7000C8,0x7000C8,0x7000C8,0x7000C8,0x7000C8,0x40140001,0x40140001,0x40140001,0x2E240001,0xE400C8,0xE400C8,0xE400C8,0x2C00000D,0x240000CA,0xF63C0014,0x4C00C8,0x4C00C8,0xA6380000,0x7C380000,0x66380000,0x66380000,0x4C380000,0xFC1C0001,0x96280001,0x40340001,0x40140001,
-0xA000C8,};
-static const uint32_t g_etc1_to_bc7_m6_table72[] = {
-0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x6C0000,0x6C0000,0x6C0000,0x6C0000,0x6C0000,0x6C0000,0x6C0000,0x6C0000,0x6C0000,0x6C0000,0xDC0000,
-0xDC0000,0xDC0000,0xDC0000,0x24000000,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0x480001,0xE4C0000,0xE4C0000,0xE4C0000,0x6C0000,0x9C0000,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,
-0xA80000,0x1580000,0x1580000,0x1580000,0x38000000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0x1580000,0x1580000,0x1580000,0x38000000,0x1580000,0x1580000,0x1580000,0x38000000,0x38000000,0x4780000,0x700001,0x700001,0x840000,0x48C0000,0x2980000,0x2980000,0xC00000,0x840000,0x48C0000,0xF00000,0x1580000,
-0xF00000,0x940001,0x940001,0x940001,0x940001,0x2DC0000,0x2DC0000,0x2DC0000,0x1C40000,0x1C40000,0x4A000000,0x2DC0000,0x2DC0000,0x2DC0000,0x1C40000,0x1C40000,0x4A000000,0x1C40000,0x1C40000,0x4A000000,0x4A000000,0x2DC0000,0x2DC0000,0x2DC0000,0x1C40000,0x1C40000,0x4A000000,0x1C40000,0x1C40000,0x4A000000,0x4A000000,0x1C40000,
-0x1C40000,0x4A000000,0x4A000000,0x4A000000,0x4AC0000,0xA00000,0x940001,0xCC0000,0xFC0000,0x13C0000,0x16C0000,0xBF80000,0xBC0000,0x2DC0000,0x13C0000,0x4A000000,0x13C0000,0xBC0001,0x3180000,0x11FC0000,0x5E000000,0x3180000,0x11FC0000,0x5E000000,0x11FC0000,0x5E000000,0x5E000000,0x3180000,0x11FC0000,0x5E000000,0x11FC0000,0x5E000000,
-0x5E000000,0x11FC0000,0x5E000000,0x5E000000,0x5E000000,0x3180000,0x11FC0000,0x5E000000,0x11FC0000,0x5E000000,0x5E000000,0x11FC0000,0x5E000000,0x5E000000,0x5E000000,0x11FC0000,0x5E000000,0x5E000000,0x5E000000,0x5E000000,0x2EC0000,0xCC80000,0xCC80000,0x1400000,0x1D00000,0x37F40000,0x5E000000,0x5E000000,0x3000000,0x1640000,0x55DC0000,0x5E000000,
-0x1940000,0x840734,0xAE7002D3,0x707002D4,0x5E7002D3,0xA0600192,0x786000D7,0x6264013B,0x66600192,0x5C5C00D7,0x545C0192,0x984C02D4,0x7A4C00A3,0x625400FD,0x6A4800CF,0x5E4C0002,0x545000D5,0x5E4802D4,0x584000FF,0x5048013A,0x4A4802D5,0xC40734,0x822802D3,0x5E4C02D4,0x76180192,0x5E3000D1,0x54380190,0x700002D3,0x5E1000A2,0x541400D5,0x4A2402D4,0x18C0734,
-0x5600031B,0x50000212,0x48000378,0x40000738,0xFE580072,0xF4780434,0xF67C04EC,0xB24C0002,0x84480003,0x6C4C0002,0x5E500011,0x5C440012,0xFE34004E,0xAA380000,0x604000A9,0x541400D5,0x1180734,0x9802D3,0x988400A2,0x6C8400A2,0x5E8400A2,0x8A7400C9,0x6E740002,0x60740015,0x627000C9,0x5C6C0026,0x547000C9,0xE002D3,0x7A4C00A2,0x5E6800A2,0x6E4000C9,0x5E4C0001,
-0x545800C8,0x1CC02D3,0x5E0C00A2,0x540000C8,0x4A0002D4,0xE002D3,0x7A4C00A2,0x5E6800A2,0x6E4000C9,0x5E4C0001,0x545800C8,0x1CC02D3,0x5E0C00A2,0x540000C8,0x4A0002D4,0x1CC02D3,0x5E0C00A2,0x540000C8,0x4A0002D4,0x4A0002D4,0xFC60002D,0xFC880173,0xFE8C016B,0xB24C0001,0x84480002,0x6C4C0001,0x5E580002,0x5C3C0006,0xFE3C0033,0xAA380000,0x623800A2,0x540000C8,
-0x14002D3,0x7002D3,0x7002D3,0x7002D3,0x7002D3,0x806000CA,0x806000CA,0x806000CA,0x585C00CA,0x585C00CA,0x4A5C00CA,0x7A4C00A3,0x7A4C00A3,0x7A4C00A3,0x5C4C0002,0x5C4C0002,0x4C500026,0x4E4C00A3,0x4E4C00A3,0x48480015,0x404800A5,0x2A402D3,0x2A402D3,0x2A402D3,0x622C00C9,0x622C00C9,0x4A4400C8,0x5C1400A2,0x5C1400A2,0x4A240001,0x403000A4,0x15002D3,
-0x15002D3,0x480000D4,0x3E0000CD,0x380002D4,0xFC540026,0xFC68015E,0x7002D3,0xB6480001,0x804C0002,0x6A4C0002,0x644C0005,0x58480002,0xFE34000E,0xAA380000,0x5E4400A3,0x4A240001,0xEC02D3,0x8400A2,0x8400A2,0x8400A2,0x8400A2,0x6C740001,0x6C740001,0x6C740001,0x52740001,0x52740001,0x4A700001,0xC400A2,0xC400A2,0xC400A2,0x58540001,0x58540001,
-0x4A600000,0x18C00A2,0x18C00A2,0x4A280000,0x400000A4,0xC400A2,0xC400A2,0xC400A2,0x58540001,0x58540001,0x4A600000,0x18C00A2,0x18C00A2,0x4A280000,0x400000A4,0x18C00A2,0x18C00A2,0x4A280000,0x400000A4,0x400000A4,0xFE580001,0xF4780012,0x8400A2,0xB6480000,0x7C500000,0x68500000,0x60540000,0x58480001,0xFE340005,0xAA380000,0x11800A2,0x4A280000,
-0x11800A2,0xA800CA,0x84980001,0x68940001,0x5E940001,0xFC00C8,0x6E740001,0x5E800001,0x3F800C8,0x5E440000,0x540000C8,0xFC00C8,0x6E740001,0x5E800001,0x3F800C8,0x5E440000,0x540000C8,0x3F800C8,0x5E440000,0x540000C8,0x540000C8,0xFC00C8,0x6E740001,0x5E800001,0x3F800C8,0x5E440000,0x540000C8,0x3F800C8,0x5E440000,0x540000C8,0x540000C8,0x3F800C8,
-0x5E440000,0x540000C8,0x540000C8,0x540000C8,0xF6680019,0x2B400C8,0xF8A00029,0xB24C0000,0x84480001,0x6E440000,0x5E5C0000,0x5E240000,0xF4480012,0xAA380000,0x60640001,0x540000C8,0x16800C8,0x5C00CA,0x5C00CA,0x5C00CA,0x5C00CA,0x5C00CA,0x5C00CA,0x5C00CA,0x5C00CA,0x5C00CA,0x5C00CA,0x5E4C0001,0x5E4C0001,0x5E4C0001,0x5E4C0001,0x5E4C0001,
-0x5E4C0001,0x42480001,0x42480001,0x42480001,0x38480001,0x8C00C8,0x8C00C8,0x8C00C8,0x8C00C8,0x8C00C8,0x8C00C8,0x48280001,0x48280001,0x48280001,0x38340001,0x11800C8,0x11800C8,0x11800C8,0x38000001,0x2E0000C8,0xF0500019,0x5C00CA,0x5C00CA,0xAA4C0001,0x824C0001,0x6C4C0001,0x6C4C0001,0x544C0001,0xF8300002,0xA8380000,0x4C440000,0x48280001,
-0xC800C8,};
-static const uint32_t g_etc1_to_bc7_m6_table73[] = {
-0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x10C0000,
-0x10C0000,0x10C0000,0x10C0000,0x2C000000,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x580001,0x600000,0x600000,0x600000,0x840000,0xBC0000,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,
-0xC00000,0x1880000,0x1880000,0x1880000,0x40000000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0x1880000,0x1880000,0x1880000,0x40000000,0x1880000,0x1880000,0x1880000,0x40000000,0x40000000,0xC880000,0x800001,0x800001,0x980000,0x4A00000,0xB00000,0xB00000,0xD80000,0x980000,0x4A00000,0x1140000,0x1880000,
-0x1140000,0xA40001,0xA40001,0xA40001,0xA40001,0x2F40000,0x2F40000,0x2F40000,0x1F40000,0x1F40000,0x52000000,0x2F40000,0x2F40000,0x2F40000,0x1F40000,0x1F40000,0x52000000,0x1F40000,0x1F40000,0x52000000,0x52000000,0x2F40000,0x2F40000,0x2F40000,0x1F40000,0x1F40000,0x52000000,0x1F40000,0x1F40000,0x52000000,0x52000000,0x1F40000,
-0x1F40000,0x52000000,0x52000000,0x52000000,0xC00000,0xB00000,0xA40001,0xE00000,0x3140000,0x1600000,0x1940000,0x15FC0000,0xD00000,0x2F40000,0x1600000,0x52000000,0x1600000,0xCC0001,0x3300000,0x1DFC0000,0x66000000,0x3300000,0x1DFC0000,0x66000000,0x1DFC0000,0x66000000,0x66000000,0x3300000,0x1DFC0000,0x66000000,0x1DFC0000,0x66000000,
-0x66000000,0x1DFC0000,0x66000000,0x66000000,0x66000000,0x3300000,0x1DFC0000,0x66000000,0x1DFC0000,0x66000000,0x66000000,0x1DFC0000,0x66000000,0x66000000,0x66000000,0x1DFC0000,0x66000000,0x66000000,0x66000000,0x66000000,0x3000000,0xDC0000,0xDC0000,0x1580000,0x1F80000,0x41F40000,0x66000000,0x66000000,0x1180000,0x3800000,0x5DEC0000,0x66000000,
-0x1B40000,0x940734,0xB68002D3,0x788002D4,0x668002D3,0xA8700192,0x807000D7,0x6A74013B,0x6E700192,0x646C00D7,0x5C6C0192,0xA05C02D4,0x825C00A3,0x6A6400FD,0x725800CF,0x665C0002,0x5C6000D5,0x665802D4,0x605000FF,0x5858013A,0x525802D5,0xDC0734,0x8A3802D3,0x665C02D4,0x7E280192,0x664000D1,0x5C480190,0x781002D3,0x662000A2,0x5C2400D5,0x523402D4,0x1BC0734,
-0x600002F8,0x5A0001E0,0x50000339,0x48000738,0xFE6C0096,0xFC880434,0xFE8C04EC,0xBA5C0002,0x8C580003,0x745C0002,0x66600011,0x64540012,0xFC4C006E,0xB2480000,0x685000A9,0x5C2400D5,0x1380734,0xA802D3,0xA09400A2,0x749400A2,0x669400A2,0x928400C9,0x76840002,0x68840015,0x6A8000C9,0x647C0026,0x5C8000C9,0xF802D3,0x825C00A2,0x667800A2,0x765000C9,0x665C0001,
-0x5C6800C8,0x1FC02D3,0x661C00A2,0x5C1000C8,0x520002D4,0xF802D3,0x825C00A2,0x667800A2,0x765000C9,0x665C0001,0x5C6800C8,0x1FC02D3,0x661C00A2,0x5C1000C8,0x520002D4,0x1FC02D3,0x661C00A2,0x5C1000C8,0x520002D4,0x520002D4,0xFC740036,0xF4980189,0xF8A0017A,0xBA5C0001,0x8C580002,0x745C0001,0x66680002,0x644C0006,0xFC50003D,0xB2480000,0x6A4800A2,0x5C1000C8,
-0x16402D3,0x8002D3,0x8002D3,0x8002D3,0x8002D3,0x887000CA,0x887000CA,0x887000CA,0x606C00CA,0x606C00CA,0x526C00CA,0x825C00A3,0x825C00A3,0x825C00A3,0x645C0002,0x645C0002,0x54600026,0x565C00A3,0x565C00A3,0x50580015,0x485800A5,0x2BC02D3,0x2BC02D3,0x2BC02D3,0x6A3C00C9,0x6A3C00C9,0x525400C8,0x642400A2,0x642400A2,0x52340001,0x484000A4,0x18002D3,
-0x18002D3,0x520000CA,0x480000B4,0x400002D4,0xFC64002D,0xF4780173,0x8002D3,0xBE580001,0x885C0002,0x725C0002,0x6C5C0005,0x60580002,0xFE440019,0xB2480000,0x665400A3,0x52340001,0x11002D3,0x9400A2,0x9400A2,0x9400A2,0x9400A2,0x74840001,0x74840001,0x74840001,0x5A840001,0x5A840001,0x52800001,0xDC00A2,0xDC00A2,0xDC00A2,0x60640001,0x60640001,
-0x52700000,0x1BC00A2,0x1BC00A2,0x52380000,0x480000A4,0xDC00A2,0xDC00A2,0xDC00A2,0x60640001,0x60640001,0x52700000,0x1BC00A2,0x1BC00A2,0x52380000,0x480000A4,0x1BC00A2,0x1BC00A2,0x52380000,0x480000A4,0x480000A4,0xFA6C0002,0xFC880012,0x9400A2,0xBE580000,0x84600000,0x70600000,0x68640000,0x60580001,0xFA48000A,0xB2480000,0x13800A2,0x52380000,
-0x13800A2,0xB800CA,0x8CA80001,0x70A40001,0x66A40001,0x11400C8,0x76840001,0x66900001,0xFF800C8,0x66540000,0x5C0000C8,0x11400C8,0x76840001,0x66900001,0xFF800C8,0x66540000,0x5C0000C8,0xFF800C8,0x66540000,0x5C0000C8,0x5C0000C8,0x11400C8,0x76840001,0x66900001,0xFF800C8,0x66540000,0x5C0000C8,0xFF800C8,0x66540000,0x5C0000C8,0x5C0000C8,0xFF800C8,
-0x66540000,0x5C0000C8,0x5C0000C8,0x5C0000C8,0xFE780019,0xAC400C8,0xFEAC002D,0xBA5C0000,0x8C580001,0x76540000,0x666C0000,0x66340000,0xFC580012,0xB2480000,0x68740001,0x5C0000C8,0x18C00C8,0x6C00CA,0x6C00CA,0x6C00CA,0x6C00CA,0x6C00CA,0x6C00CA,0x6C00CA,0x6C00CA,0x6C00CA,0x6C00CA,0x665C0001,0x665C0001,0x665C0001,0x665C0001,0x665C0001,
-0x665C0001,0x4A580001,0x4A580001,0x4A580001,0x40580001,0xA400C8,0xA400C8,0xA400C8,0xA400C8,0xA400C8,0xA400C8,0x50380001,0x50380001,0x50380001,0x40440001,0x14C00C8,0x14C00C8,0x14C00C8,0x40080000,0x360000C8,0xF8600019,0x6C00CA,0x6C00CA,0xB25C0001,0x8A5C0001,0x745C0001,0x745C0001,0x5C5C0001,0xF4440005,0xB0480000,0x54540000,0x50380001,
-0xE800C8,};
-static const uint32_t g_etc1_to_bc7_m6_table74[] = {
-0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x13C0000,
-0x13C0000,0x13C0000,0x13C0000,0x34000000,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x700000,0x700000,0x700000,0x9C0000,0xE00000,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,
-0xD80000,0x1B80000,0x1B80000,0x1B80000,0x48000000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0x1B80000,0x1B80000,0x1B80000,0x48000000,0x1B80000,0x1B80000,0x1B80000,0x48000000,0x48000000,0x9C0000,0x900001,0x900001,0x2A80000,0x4B40000,0x2C40000,0x2C40000,0xF40000,0x2A80000,0x4B40000,0x1340000,0x1B80000,
-0x1340000,0xB40001,0xB40001,0xB40001,0xB40001,0x30C0000,0x30C0000,0x30C0000,0xBFC0000,0xBFC0000,0x5A000000,0x30C0000,0x30C0000,0x30C0000,0xBFC0000,0xBFC0000,0x5A000000,0xBFC0000,0xBFC0000,0x5A000000,0x5A000000,0x30C0000,0x30C0000,0x30C0000,0xBFC0000,0xBFC0000,0x5A000000,0xBFC0000,0xBFC0000,0x5A000000,0x5A000000,0xBFC0000,
-0xBFC0000,0x5A000000,0x5A000000,0x5A000000,0xD40000,0x8C00000,0xB40001,0xF80000,0x1300000,0x1800000,0x1BC0000,0x21F40000,0xE40000,0x30C0000,0x1800000,0x5A000000,0x1800000,0xDC0001,0x1480000,0x29FC0000,0x6E000000,0x1480000,0x29FC0000,0x6E000000,0x29FC0000,0x6E000000,0x6E000000,0x1480000,0x29FC0000,0x6E000000,0x29FC0000,0x6E000000,
-0x6E000000,0x29FC0000,0x6E000000,0x6E000000,0x6E000000,0x1480000,0x29FC0000,0x6E000000,0x29FC0000,0x6E000000,0x6E000000,0x29FC0000,0x6E000000,0x6E000000,0x6E000000,0x29FC0000,0x6E000000,0x6E000000,0x6E000000,0x6E000000,0x3140000,0xEC0000,0xEC0000,0x1740000,0xDFC0000,0x4BF40000,0x6E000000,0x6E000000,0x32C0000,0x1A00000,0x65FC0000,0x6E000000,
-0x1D80000,0xA40734,0xBE9002D3,0x809002D4,0x6E9002D3,0xB0800192,0x888000D7,0x7284013B,0x76800192,0x6C7C00D7,0x647C0192,0xA86C02D4,0x8A6C00A3,0x727400FD,0x7A6800CF,0x6E6C0002,0x647000D5,0x6E6802D4,0x686000FF,0x6068013A,0x5A6802D5,0xF40734,0x924802D3,0x6E6C02D4,0x86380192,0x6E5000D1,0x64580190,0x802002D3,0x6E3000A2,0x643400D5,0x5A4402D4,0x1F00734,
-0x6C0002D8,0x600001B8,0x5A000314,0x50000738,0xFC7C00BA,0xF498046A,0xF8A00513,0xC26C0002,0x94680003,0x7C6C0002,0x6E700011,0x6C640012,0xFE5C0082,0xBA580000,0x706000A9,0x643400D5,0x15C0734,0xB802D3,0xA8A400A2,0x7CA400A2,0x6EA400A2,0x9A9400C9,0x7E940002,0x70940015,0x729000C9,0x6C8C0026,0x649000C9,0x11002D3,0x8A6C00A2,0x6E8800A2,0x7E6000C9,0x6E6C0001,
-0x647800C8,0xDFC02D3,0x6E2C00A2,0x642000C8,0x5A0002D4,0x11002D3,0x8A6C00A2,0x6E8800A2,0x7E6000C9,0x6E6C0001,0x647800C8,0xDFC02D3,0x6E2C00A2,0x642000C8,0x5A0002D4,0xDFC02D3,0x6E2C00A2,0x642000C8,0x5A0002D4,0x5A0002D4,0xFE800049,0xFCA80189,0xFEAC0186,0xC26C0001,0x94680002,0x7C6C0001,0x6E780002,0x6C5C0006,0xFE600051,0xBA580000,0x725800A2,0x642000C8,
-0x18802D3,0x9002D3,0x9002D3,0x9002D3,0x9002D3,0x908000CA,0x908000CA,0x908000CA,0x687C00CA,0x687C00CA,0x5A7C00CA,0x8A6C00A3,0x8A6C00A3,0x8A6C00A3,0x6C6C0002,0x6C6C0002,0x5C700026,0x5E6C00A3,0x5E6C00A3,0x58680015,0x506800A5,0xD402D3,0xD402D3,0xD402D3,0x724C00C9,0x724C00C9,0x5A6400C8,0x6C3400A2,0x6C3400A2,0x5A440001,0x505000A4,0x1B002D3,
-0x1B002D3,0x5A0C00C8,0x500000A5,0x480002D4,0xFE74003B,0xFC880173,0x9002D3,0xC6680001,0x906C0002,0x7A6C0002,0x746C0005,0x68680002,0xFE580021,0xBA580000,0x6E6400A3,0x5A440001,0x13002D3,0xA400A2,0xA400A2,0xA400A2,0xA400A2,0x7C940001,0x7C940001,0x7C940001,0x62940001,0x62940001,0x5A900001,0xF400A2,0xF400A2,0xF400A2,0x68740001,0x68740001,
-0x5A800000,0x1F000A2,0x1F000A2,0x5A480000,0x500000A4,0xF400A2,0xF400A2,0xF400A2,0x68740001,0x68740001,0x5A800000,0x1F000A2,0x1F000A2,0x5A480000,0x500000A4,0x1F000A2,0x1F000A2,0x5A480000,0x500000A4,0x500000A4,0xF6800005,0xF4980019,0xA400A2,0xC6680000,0x8C700000,0x78700000,0x70740000,0x68680001,0xF260000D,0xBA580000,0x15C00A2,0x5A480000,
-0x15C00A2,0xC800CA,0x94B80001,0x78B40001,0x6EB40001,0x12C00C8,0x7E940001,0x6EA00001,0x1BF800C8,0x6E640000,0x640000C8,0x12C00C8,0x7E940001,0x6EA00001,0x1BF800C8,0x6E640000,0x640000C8,0x1BF800C8,0x6E640000,0x640000C8,0x640000C8,0x12C00C8,0x7E940001,0x6EA00001,0x1BF800C8,0x6E640000,0x640000C8,0x1BF800C8,0x6E640000,0x640000C8,0x640000C8,0x1BF800C8,
-0x6E640000,0x640000C8,0x640000C8,0x640000C8,0xFA8C0020,0xD800C8,0xF8C00032,0xC26C0000,0x94680001,0x7E640000,0x6E7C0000,0x6E440000,0xFC6C0019,0xBA580000,0x70840001,0x640000C8,0x1AC00C8,0x7C00CA,0x7C00CA,0x7C00CA,0x7C00CA,0x7C00CA,0x7C00CA,0x7C00CA,0x7C00CA,0x7C00CA,0x7C00CA,0x6E6C0001,0x6E6C0001,0x6E6C0001,0x6E6C0001,0x6E6C0001,
-0x6E6C0001,0x52680001,0x52680001,0x52680001,0x48680001,0xBC00C8,0xBC00C8,0xBC00C8,0xBC00C8,0xBC00C8,0xBC00C8,0x58480001,0x58480001,0x58480001,0x48540001,0x17C00C8,0x17C00C8,0x17C00C8,0x48180000,0x3E0000C8,0xF0700022,0x7C00CA,0x7C00CA,0xBA6C0001,0x926C0001,0x7C6C0001,0x7C6C0001,0x646C0001,0xFC540005,0xB8580000,0x5C640000,0x58480001,
-0x10C00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table75[] = {
-0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0x1700000,
-0x1700000,0x1700000,0x1700000,0x3C000000,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x8800000,0x8800000,0x8800000,0xB40000,0x1000000,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,
-0xF00000,0x1E80000,0x1E80000,0x1E80000,0x50000000,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,0x1E80000,0x1E80000,0x1E80000,0x50000000,0x1E80000,0x1E80000,0x1E80000,0x50000000,0x50000000,0xAC0000,0xA00001,0xA00001,0xBC0000,0xCC0000,0xDC0000,0xDC0000,0x1100000,0xBC0000,0xCC0000,0x1580000,0x1E80000,
-0x1580000,0xC40001,0xC40001,0xC40001,0xC40001,0x3240000,0x3240000,0x3240000,0x17FC0000,0x17FC0000,0x62000000,0x3240000,0x3240000,0x3240000,0x17FC0000,0x17FC0000,0x62000000,0x17FC0000,0x17FC0000,0x62000000,0x62000000,0x3240000,0x3240000,0x3240000,0x17FC0000,0x17FC0000,0x62000000,0x17FC0000,0x17FC0000,0x62000000,0x62000000,0x17FC0000,
-0x17FC0000,0x62000000,0x62000000,0x62000000,0x4E40000,0xD40000,0xC40001,0x10C0000,0x14C0000,0x1A40000,0x1E40000,0x2BF80000,0xF80000,0x3240000,0x1A40000,0x62000000,0x1A40000,0xEC0001,0x1600000,0x35FC0000,0x76000000,0x1600000,0x35FC0000,0x76000000,0x35FC0000,0x76000000,0x76000000,0x1600000,0x35FC0000,0x76000000,0x35FC0000,0x76000000,
-0x76000000,0x35FC0000,0x76000000,0x76000000,0x76000000,0x1600000,0x35FC0000,0x76000000,0x35FC0000,0x76000000,0x76000000,0x35FC0000,0x76000000,0x76000000,0x76000000,0x35FC0000,0x76000000,0x76000000,0x76000000,0x76000000,0x3280000,0x6FC0000,0x6FC0000,0x1900000,0x1BFC0000,0x55F40000,0x76000000,0x76000000,0x1440000,0x1C00000,0x6FD00000,0x76000000,
-0x1F80000,0xB40734,0xC6A002D3,0x88A002D4,0x76A002D3,0xB8900192,0x909000D7,0x7A94013B,0x7E900192,0x748C00D7,0x6C8C0192,0xB07C02D4,0x927C00A3,0x7A8400FD,0x827800CF,0x767C0002,0x6C8000D5,0x767802D4,0x707000FF,0x6878013A,0x627802D5,0x10C0734,0x9A5802D3,0x767C02D4,0x8E480192,0x766000D1,0x6C680190,0x883002D3,0x764000A2,0x6C4400D5,0x625402D4,0xBF80734,
-0x760002D3,0x6C000198,0x600002F8,0x58000738,0xFE8C00D4,0xFCA8046A,0xFEAC0517,0xCA7C0002,0x9C780003,0x847C0002,0x76800011,0x74740012,0xFE7000A7,0xC2680000,0x787000A9,0x6C4400D5,0x17C0734,0xC802D3,0xB0B400A2,0x84B400A2,0x76B400A2,0xA2A400C9,0x86A40002,0x78A40015,0x7AA000C9,0x749C0026,0x6CA000C9,0x12802D3,0x927C00A2,0x769800A2,0x867000C9,0x767C0001,
-0x6C8800C8,0x19FC02D3,0x763C00A2,0x6C3000C8,0x620002D4,0x12802D3,0x927C00A2,0x769800A2,0x867000C9,0x767C0001,0x6C8800C8,0x19FC02D3,0x763C00A2,0x6C3000C8,0x620002D4,0x19FC02D3,0x763C00A2,0x6C3000C8,0x620002D4,0x620002D4,0xFE940050,0xF4B801A3,0xF8C00193,0xCA7C0001,0x9C780002,0x847C0001,0x76880002,0x746C0006,0xFE780056,0xC2680000,0x7A6800A2,0x6C3000C8,
-0x1A802D3,0xA002D3,0xA002D3,0xA002D3,0xA002D3,0x989000CA,0x989000CA,0x989000CA,0x708C00CA,0x708C00CA,0x628C00CA,0x927C00A3,0x927C00A3,0x927C00A3,0x747C0002,0x747C0002,0x64800026,0x667C00A3,0x667C00A3,0x60780015,0x587800A5,0xEC02D3,0xEC02D3,0xEC02D3,0x7A5C00C9,0x7A5C00C9,0x627400C8,0x744400A2,0x744400A2,0x62540001,0x586000A4,0x1E402D3,
-0x1E402D3,0x621C00C8,0x580800A4,0x500002D4,0xFE840046,0xF498018A,0xA002D3,0xCE780001,0x987C0002,0x827C0002,0x7C7C0005,0x70780002,0xF86C0032,0xC2680000,0x767400A3,0x62540001,0x15402D3,0xB400A2,0xB400A2,0xB400A2,0xB400A2,0x84A40001,0x84A40001,0x84A40001,0x6AA40001,0x6AA40001,0x62A00001,0x10C00A2,0x10C00A2,0x10C00A2,0x70840001,0x70840001,
-0x62900000,0xBF800A2,0xBF800A2,0x62580000,0x580000A4,0x10C00A2,0x10C00A2,0x10C00A2,0x70840001,0x70840001,0x62900000,0xBF800A2,0xBF800A2,0x62580000,0x580000A4,0xBF800A2,0xBF800A2,0x62580000,0x580000A4,0x580000A4,0xFE900005,0xFCA80019,0xB400A2,0xCE780000,0x94800000,0x80800000,0x78840000,0x70780001,0xFA70000D,0xC2680000,0x17C00A2,0x62580000,
-0x17C00A2,0xD800CA,0x9CC80001,0x80C40001,0x76C40001,0x14400C8,0x86A40001,0x76B00001,0x27F800C8,0x76740000,0x6C0000C8,0x14400C8,0x86A40001,0x76B00001,0x27F800C8,0x76740000,0x6C0000C8,0x27F800C8,0x76740000,0x6C0000C8,0x6C0000C8,0x14400C8,0x86A40001,0x76B00001,0x27F800C8,0x76740000,0x6C0000C8,0x27F800C8,0x76740000,0x6C0000C8,0x6C0000C8,0x27F800C8,
-0x76740000,0x6C0000C8,0x6C0000C8,0x6C0000C8,0xF4A00029,0xE800C8,0xFECC003A,0xCA7C0000,0x9C780001,0x86740000,0x768C0000,0x76540000,0xF8840020,0xC2680000,0x78940001,0x6C0000C8,0x1D000C8,0x8C00CA,0x8C00CA,0x8C00CA,0x8C00CA,0x8C00CA,0x8C00CA,0x8C00CA,0x8C00CA,0x8C00CA,0x8C00CA,0x767C0001,0x767C0001,0x767C0001,0x767C0001,0x767C0001,
-0x767C0001,0x5A780001,0x5A780001,0x5A780001,0x50780001,0x2D000C8,0x2D000C8,0x2D000C8,0x2D000C8,0x2D000C8,0x2D000C8,0x60580001,0x60580001,0x60580001,0x50640001,0x1AC00C8,0x1AC00C8,0x1AC00C8,0x50280000,0x460000C8,0xF8800022,0x8C00CA,0x8C00CA,0xC27C0001,0x9A7C0001,0x847C0001,0x847C0001,0x6C7C0001,0xFC640008,0xC0680000,0x64740000,0x60580001,
-0x12C00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table76[] = {
-0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0xD00000,0xD00000,0xD00000,0xD00000,0xD00000,0xD00000,0xD00000,0xD00000,0xD00000,0xD00000,0x1A40000,
-0x1A40000,0x1A40000,0x1A40000,0x44000001,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x2940000,0x2940000,0x2940000,0xD00000,0x1280000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,
-0x10C0000,0xBF80000,0xBF80000,0xBF80000,0x58000001,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0xBF80000,0xBF80000,0xBF80000,0x58000001,0xBF80000,0xBF80000,0xBF80000,0x58000001,0x58000001,0xC00000,0xB40000,0xB40000,0xD00000,0x2E00000,0xF40000,0xF40000,0x32C0000,0xD00000,0x2E00000,0x17C0000,0xBF80000,
-0x17C0000,0xD80000,0xD80000,0xD80000,0xD80000,0x1400000,0x1400000,0x1400000,0x25F80000,0x25F80000,0x6A000001,0x1400000,0x1400000,0x1400000,0x25F80000,0x25F80000,0x6A000001,0x25F80000,0x25F80000,0x6A000001,0x6A000001,0x1400000,0x1400000,0x1400000,0x25F80000,0x25F80000,0x6A000001,0x25F80000,0x25F80000,0x6A000001,0x6A000001,0x25F80000,
-0x25F80000,0x6A000001,0x6A000001,0x6A000001,0xFC0000,0xAE40000,0xD80000,0x3240000,0x16C0000,0x1CC0000,0x9F80000,0x37FC0000,0x50C0000,0x1400000,0x1CC0000,0x6A000001,0x1CC0000,0x1000000,0x17C0000,0x43F80000,0x7E000001,0x17C0000,0x43F80000,0x7E000001,0x43F80000,0x7E000001,0x7E000001,0x17C0000,0x43F80000,0x7E000001,0x43F80000,0x7E000001,
-0x7E000001,0x43F80000,0x7E000001,0x7E000001,0x7E000001,0x17C0000,0x43F80000,0x7E000001,0x43F80000,0x7E000001,0x7E000001,0x43F80000,0x7E000001,0x7E000001,0x7E000001,0x43F80000,0x7E000001,0x7E000001,0x7E000001,0x7E000001,0x1400000,0x1100000,0x1100000,0x3AC0000,0x29FC0000,0x61F00000,0x7E000001,0x7E000001,0x15C0000,0x1E00000,0x79C40000,0x7E000001,
-0x11FC0000,0xC40738,0xCCB402D4,0x92B402D4,0x7EB402D5,0xC2A00190,0x9AA000D5,0x80A8013A,0x88A00190,0x7CA000D5,0x74A00192,0xBC8C02D3,0x9C8C00A2,0x849800FF,0x8C8C00D1,0x7E8C0002,0x749000D7,0x7E8C02D4,0x7A8400FD,0x7284013B,0x6C8C02D3,0x3240734,0xA46802D3,0x7E8C02D4,0x965C0192,0x807400CF,0x747C0192,0x904402D3,0x7E5400A3,0x745400D7,0x6C6402D4,0x17FC0734,
-0x7E1402D4,0x74080192,0x6C0002DC,0x62000734,0xFEA000FE,0xF6BC04A0,0xF8C0053C,0xD48C0000,0xA68C0001,0x8C8C0002,0x80900012,0x7C8C0011,0xFE8800DC,0xC87C0002,0x828000A9,0x745400D7,0x1A40734,0xD802D4,0xB8C800A4,0x8CC800A4,0x7EC400A5,0xAEB400C8,0x90B40001,0x80B80015,0x82B400C8,0x7CB00026,0x74B400CA,0x14402D3,0x9A9000A2,0x7EAC00A3,0x8E8400C9,0x7E8C0002,
-0x769800CA,0x27F802D3,0x7E5400A3,0x744400CA,0x6C0002D3,0x14402D3,0x9A9000A2,0x7EAC00A3,0x8E8400C9,0x7E8C0002,0x769800CA,0x27F802D3,0x7E5400A3,0x744400CA,0x6C0002D3,0x27F802D3,0x7E5400A3,0x744400CA,0x6C0002D3,0x6C0002D3,0xFAAC0065,0xFECC01A0,0xF2D401AD,0xD48C0000,0xA68C0001,0x8C8C0002,0x80980002,0x7E800005,0xFA900071,0xC87C0001,0x847800A2,0x744400CA,
-0x1D002D3,0xB402D4,0xB402D4,0xB402D4,0xB402D4,0xA4A000C8,0xA4A000C8,0xA4A000C8,0x78A000C8,0x78A000C8,0x6AA000C9,0x9C8C00A2,0x9C8C00A2,0x9C8C00A2,0x7E8C0001,0x7E8C0001,0x6E900026,0x708C00A2,0x708C00A2,0x6A880015,0x628C00A2,0x10802D3,0x10802D3,0x10802D3,0x846C00C9,0x846C00C9,0x6C8400C9,0x7E5400A2,0x7E5400A2,0x6A680002,0x627000A2,0x9F802D3,
-0x9F802D3,0x6A3000C9,0x621400A2,0x580002D3,0xFC9C005A,0xFEAC0189,0xB402D4,0xD48C0000,0xA28C0001,0x8C8C0001,0x86900006,0x788C0002,0xFE80003E,0xC87C0001,0x808400A2,0x6A680002,0x17802D3,0xC400A4,0xC400A4,0xC400A4,0xC400A4,0x90B40000,0x90B40000,0x90B40000,0x74B40000,0x74B40000,0x6AB40001,0x32400A2,0x32400A2,0x32400A2,0x7A940001,0x7A940001,
-0x6AA40001,0x17FC00A2,0x17FC00A2,0x6A6C0001,0x620000A2,0x32400A2,0x32400A2,0x32400A2,0x7A940001,0x7A940001,0x6AA40001,0x17FC00A2,0x17FC00A2,0x6A6C0001,0x620000A2,0x17FC00A2,0x17FC00A2,0x6A6C0001,0x620000A2,0x620000A2,0xFEA0000A,0xF6BC0020,0xC400A4,0xD48C0000,0xA0900000,0x8A900000,0x80980001,0x7A880000,0xF8880012,0xC87C0000,0x1A400A2,0x6A6C0001,
-0x1A400A2,0xEC00C8,0xA8D80000,0x88D80001,0x7ED80001,0x35C00C8,0x90B40001,0x7EC40001,0x33FC00C8,0x7E880001,0x740000CA,0x35C00C8,0x90B40001,0x7EC40001,0x33FC00C8,0x7E880001,0x740000CA,0x33FC00C8,0x7E880001,0x740000CA,0x740000CA,0x35C00C8,0x90B40001,0x7EC40001,0x33FC00C8,0x7E880001,0x740000CA,0x33FC00C8,0x7E880001,0x740000CA,0x740000CA,0x33FC00C8,
-0x7E880001,0x740000CA,0x740000CA,0x740000CA,0xFEB40029,0xFC00C8,0xFAE4003D,0xD0900000,0xA6880001,0x8E880000,0x7EA00001,0x7E6C0001,0xFE980020,0xCA7C0000,0x82A40000,0x740000CA,0x1F400C8,0xA000C8,0xA000C8,0xA000C8,0xA000C8,0xA000C8,0xA000C8,0xA000C8,0xA000C8,0xA000C8,0xA000C8,0x828C0000,0x828C0000,0x828C0000,0x828C0000,0x828C0000,
-0x828C0000,0x628C0001,0x628C0001,0x628C0001,0x588C0001,0xEC00C8,0xEC00C8,0xEC00C8,0xEC00C8,0xEC00C8,0xEC00C8,0x6A680001,0x6A680001,0x6A680001,0x58780001,0x1E400C8,0x1E400C8,0x1E400C8,0x583C0001,0x4E0000CA,0xF2940029,0xA000C8,0xA000C8,0xD08C0000,0xA68C0000,0x908C0000,0x908C0000,0x768C0000,0xF47C000D,0xC07C0001,0x6A880001,0x6A680001,
-0x15400C8,};
-static const uint32_t g_etc1_to_bc7_m6_table77[] = {
-0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0x1D80000,
-0x1D80000,0x1D80000,0x1D80000,0x4C000001,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0xAA40000,0xAA40000,0xAA40000,0xE80000,0x14C0000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,
-0x1240000,0x17F80000,0x17F80000,0x17F80000,0x60000001,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x17F80000,0x17F80000,0x17F80000,0x60000001,0x17F80000,0x17F80000,0x17F80000,0x60000001,0x60000001,0xD00000,0xC40000,0xC40000,0xE40000,0x2F40000,0x3080000,0x3080000,0x1480000,0xE40000,0x2F40000,0x1A00000,0x17F80000,
-0x1A00000,0xE80000,0xE80000,0xE80000,0xE80000,0x1580000,0x1580000,0x1580000,0x31F80000,0x31F80000,0x72000001,0x1580000,0x1580000,0x1580000,0x31F80000,0x31F80000,0x72000001,0x31F80000,0x31F80000,0x72000001,0x72000001,0x1580000,0x1580000,0x1580000,0x31F80000,0x31F80000,0x72000001,0x31F80000,0x31F80000,0x72000001,0x72000001,0x31F80000,
-0x31F80000,0x72000001,0x72000001,0x72000001,0x30C0000,0xF80000,0xE80000,0x13C0000,0x1840000,0x1EC0000,0x15FC0000,0x43F40000,0x5200000,0x1580000,0x1EC0000,0x72000001,0x1EC0000,0x1100000,0x1940000,0x4FF80000,0x86000001,0x1940000,0x4FF80000,0x86000001,0x4FF80000,0x86000001,0x86000001,0x1940000,0x4FF80000,0x86000001,0x4FF80000,0x86000001,
-0x86000001,0x4FF80000,0x86000001,0x86000001,0x86000001,0x1940000,0x4FF80000,0x86000001,0x4FF80000,0x86000001,0x86000001,0x4FF80000,0x86000001,0x86000001,0x86000001,0x4FF80000,0x86000001,0x86000001,0x86000001,0x86000001,0x1540000,0x9200000,0x9200000,0x1C80000,0x37FC0000,0x6BF00000,0x86000001,0x86000001,0x3700000,0x3FC0000,0x81D40000,0x86000001,
-0x1FFC0000,0xD40738,0xD4C402D4,0x9AC402D4,0x86C402D5,0xCAB00190,0xA2B000D5,0x88B8013A,0x90B00190,0x84B000D5,0x7CB00192,0xC49C02D3,0xA49C00A2,0x8CA800FF,0x949C00D1,0x869C0002,0x7CA000D7,0x869C02D4,0x829400FD,0x7A94013B,0x749C02D3,0x33C0734,0xAC7802D3,0x869C02D4,0x9E6C0192,0x888400CF,0x7C8C0192,0x985402D3,0x866400A3,0x7C6400D7,0x747402D4,0x23FC0734,
-0x862402D4,0x7C180192,0x740002D4,0x6A000734,0xFEB4012D,0xFECC04A0,0xFECC0554,0xDC9C0000,0xAE9C0001,0x949C0002,0x88A00012,0x849C0011,0xFE9800FA,0xD08C0002,0x8A9000A9,0x7C6400D7,0x1C80734,0xE802D4,0xC0D800A4,0x94D800A4,0x86D400A5,0xB6C400C8,0x98C40001,0x88C80015,0x8AC400C8,0x84C00026,0x7CC400CA,0x15C02D3,0xA2A000A2,0x86BC00A3,0x969400C9,0x869C0002,
-0x7EA800CA,0x33F802D3,0x866400A3,0x7C5400CA,0x740002D3,0x15C02D3,0xA2A000A2,0x86BC00A3,0x969400C9,0x869C0002,0x7EA800CA,0x33F802D3,0x866400A3,0x7C5400CA,0x740002D3,0x33F802D3,0x866400A3,0x7C5400CA,0x740002D3,0x740002D3,0xFEBC0076,0xF6DC01BA,0xFAE401AD,0xDC9C0000,0xAE9C0001,0x949C0002,0x88A80002,0x86900005,0xFEA40081,0xD08C0001,0x8C8800A2,0x7C5400CA,
-0x1F002D3,0xC402D4,0xC402D4,0xC402D4,0xC402D4,0xACB000C8,0xACB000C8,0xACB000C8,0x80B000C8,0x80B000C8,0x72B000C9,0xA49C00A2,0xA49C00A2,0xA49C00A2,0x869C0001,0x869C0001,0x76A00026,0x789C00A2,0x789C00A2,0x72980015,0x6A9C00A2,0x12002D3,0x12002D3,0x12002D3,0x8C7C00C9,0x8C7C00C9,0x749400C9,0x866400A2,0x866400A2,0x72780002,0x6A8000A2,0x15F802D3,
-0x15F802D3,0x724000C9,0x6A2400A2,0x600002D3,0xFEAC0065,0xF6BC01A0,0xC402D4,0xDC9C0000,0xAA9C0001,0x949C0001,0x8EA00006,0x809C0002,0xFE90004A,0xD08C0001,0x889400A2,0x72780002,0x19C02D3,0xD400A4,0xD400A4,0xD400A4,0xD400A4,0x98C40000,0x98C40000,0x98C40000,0x7CC40000,0x7CC40000,0x72C40001,0x33C00A2,0x33C00A2,0x33C00A2,0x82A40001,0x82A40001,
-0x72B40001,0x23FC00A2,0x23FC00A2,0x727C0001,0x6A0000A2,0x33C00A2,0x33C00A2,0x33C00A2,0x82A40001,0x82A40001,0x72B40001,0x23FC00A2,0x23FC00A2,0x727C0001,0x6A0000A2,0x23FC00A2,0x23FC00A2,0x727C0001,0x6A0000A2,0x6A0000A2,0xFAB4000D,0xFECC0020,0xD400A4,0xDC9C0000,0xA8A00000,0x92A00000,0x88A80001,0x82980000,0xF29C0019,0xD08C0000,0x1C800A2,0x727C0001,
-0x1C800A2,0xFC00C8,0xB0E80000,0x90E80001,0x86E80001,0x37400C8,0x98C40001,0x86D40001,0x3FFC00C8,0x86980001,0x7C0000CA,0x37400C8,0x98C40001,0x86D40001,0x3FFC00C8,0x86980001,0x7C0000CA,0x3FFC00C8,0x86980001,0x7C0000CA,0x7C0000CA,0x37400C8,0x98C40001,0x86D40001,0x3FFC00C8,0x86980001,0x7C0000CA,0x3FFC00C8,0x86980001,0x7C0000CA,0x7C0000CA,0x3FFC00C8,
-0x86980001,0x7C0000CA,0x7C0000CA,0x7C0000CA,0xFAC80032,0x10C00C8,0xF2F40048,0xD8A00000,0xAE980001,0x96980000,0x86B00001,0x867C0001,0xFEAC0029,0xD28C0000,0x8AB40000,0x7C0000CA,0xDFC00C8,0xB000C8,0xB000C8,0xB000C8,0xB000C8,0xB000C8,0xB000C8,0xB000C8,0xB000C8,0xB000C8,0xB000C8,0x8A9C0000,0x8A9C0000,0x8A9C0000,0x8A9C0000,0x8A9C0000,
-0x8A9C0000,0x6A9C0001,0x6A9C0001,0x6A9C0001,0x609C0001,0x10400C8,0x10400C8,0x10400C8,0x10400C8,0x10400C8,0x10400C8,0x72780001,0x72780001,0x72780001,0x60880001,0x7FC00C8,0x7FC00C8,0x7FC00C8,0x604C0001,0x560000CA,0xFAA40029,0xB000C8,0xB000C8,0xD89C0000,0xAE9C0000,0x989C0000,0x989C0000,0x7E9C0000,0xFC8C000D,0xC88C0001,0x72980001,0x72780001,
-0x17400C8,};
-static const uint32_t g_etc1_to_bc7_m6_table78[] = {
-0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0x1000000,0x1000000,0x1000000,0x1000000,0x1000000,0x1000000,0x1000000,0x1000000,0x1000000,0x1000000,0x5F80000,
-0x5F80000,0x5F80000,0x5F80000,0x54000001,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xB80000,0xB80000,0xB80000,0x1000000,0x16C0000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,
-0x13C0000,0x21FC0000,0x21FC0000,0x21FC0000,0x68000001,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x21FC0000,0x21FC0000,0x21FC0000,0x68000001,0x21FC0000,0x21FC0000,0x21FC0000,0x68000001,0x68000001,0x8E00000,0xD40000,0xD40000,0x4F40000,0x3080000,0x1200000,0x1200000,0x1640000,0x4F40000,0x3080000,0x1C00000,0x21FC0000,
-0x1C00000,0xF80000,0xF80000,0xF80000,0xF80000,0x1700000,0x1700000,0x1700000,0x3DF80000,0x3DF80000,0x7A000001,0x1700000,0x1700000,0x1700000,0x3DF80000,0x3DF80000,0x7A000001,0x3DF80000,0x3DF80000,0x7A000001,0x7A000001,0x1700000,0x1700000,0x1700000,0x3DF80000,0x3DF80000,0x7A000001,0x3DF80000,0x3DF80000,0x7A000001,0x7A000001,0x3DF80000,
-0x3DF80000,0x7A000001,0x7A000001,0x7A000001,0x1200000,0x1080000,0xF80000,0x1500000,0x1A00000,0x9FC0000,0x23FC0000,0x4DFC0000,0x5340000,0x1700000,0x9FC0000,0x7A000001,0x9FC0000,0x1200000,0x1AC0000,0x5BF80000,0x8E000001,0x1AC0000,0x5BF80000,0x8E000001,0x5BF80000,0x8E000001,0x8E000001,0x1AC0000,0x5BF80000,0x8E000001,0x5BF80000,0x8E000001,
-0x8E000001,0x5BF80000,0x8E000001,0x8E000001,0x8E000001,0x1AC0000,0x5BF80000,0x8E000001,0x5BF80000,0x8E000001,0x8E000001,0x5BF80000,0x8E000001,0x8E000001,0x8E000001,0x5BF80000,0x8E000001,0x8E000001,0x8E000001,0x8E000001,0x1680000,0x1340000,0x1340000,0x1E40000,0x45FC0000,0x75F00000,0x8E000001,0x8E000001,0x1880000,0x13FC0000,0x89E40000,0x8E000001,
-0x2FFC0000,0xE40738,0xDCD402D4,0xA2D402D4,0x8ED402D5,0xD2C00190,0xAAC000D5,0x90C8013A,0x98C00190,0x8CC000D5,0x84C00192,0xCCAC02D3,0xACAC00A2,0x94B800FF,0x9CAC00D1,0x8EAC0002,0x84B000D7,0x8EAC02D4,0x8AA400FD,0x82A4013B,0x7CAC02D3,0x1540734,0xB48802D3,0x8EAC02D4,0xA67C0192,0x909400CF,0x849C0192,0xA06402D3,0x8E7400A3,0x847400D7,0x7C8402D4,0x2FFC0734,
-0x8E3402D4,0x84280192,0x7C0C02D3,0x72000734,0xFEC40168,0xF6DC04DA,0xF8E00569,0xE4AC0000,0xB6AC0001,0x9CAC0002,0x90B00012,0x8CAC0011,0xFCB0013D,0xD89C0002,0x92A000A9,0x847400D7,0x1E80734,0xF802D4,0xC8E800A4,0x9CE800A4,0x8EE400A5,0xBED400C8,0xA0D40001,0x90D80015,0x92D400C8,0x8CD00026,0x84D400CA,0x17402D3,0xAAB000A2,0x8ECC00A3,0x9EA400C9,0x8EAC0002,
-0x86B800CA,0x3FF802D3,0x8E7400A3,0x846400CA,0x7C0002D3,0x17402D3,0xAAB000A2,0x8ECC00A3,0x9EA400C9,0x8EAC0002,0x86B800CA,0x3FF802D3,0x8E7400A3,0x846400CA,0x7C0002D3,0x3FF802D3,0x8E7400A3,0x846400CA,0x7C0002D3,0x7C0002D3,0xFED00083,0xFEEC01BA,0xF2F401C8,0xE4AC0000,0xB6AC0001,0x9CAC0002,0x90B80002,0x8EA00005,0xFEB40095,0xD89C0001,0x949800A2,0x846400CA,
-0xBFC02D3,0xD402D4,0xD402D4,0xD402D4,0xD402D4,0xB4C000C8,0xB4C000C8,0xB4C000C8,0x88C000C8,0x88C000C8,0x7AC000C9,0xACAC00A2,0xACAC00A2,0xACAC00A2,0x8EAC0001,0x8EAC0001,0x7EB00026,0x80AC00A2,0x80AC00A2,0x7AA80015,0x72AC00A2,0x13802D3,0x13802D3,0x13802D3,0x948C00C9,0x948C00C9,0x7CA400C9,0x8E7400A2,0x8E7400A2,0x7A880002,0x729000A2,0x21F802D3,
-0x21F802D3,0x7A5000C9,0x723400A2,0x680002D3,0xFEBC0075,0xFECC01A0,0xD402D4,0xE4AC0000,0xB2AC0001,0x9CAC0001,0x96B00006,0x88AC0002,0xFEA0005A,0xD89C0001,0x90A400A2,0x7A880002,0x1BC02D3,0xE400A4,0xE400A4,0xE400A4,0xE400A4,0xA0D40000,0xA0D40000,0xA0D40000,0x84D40000,0x84D40000,0x7AD40001,0x15400A2,0x15400A2,0x15400A2,0x8AB40001,0x8AB40001,
-0x7AC40001,0x2FFC00A2,0x2FFC00A2,0x7A8C0001,0x720000A2,0x15400A2,0x15400A2,0x15400A2,0x8AB40001,0x8AB40001,0x7AC40001,0x2FFC00A2,0x2FFC00A2,0x7A8C0001,0x720000A2,0x2FFC00A2,0x2FFC00A2,0x7A8C0001,0x720000A2,0x720000A2,0xF6C80012,0xF6DC0029,0xE400A4,0xE4AC0000,0xB0B00000,0x9AB00000,0x90B80001,0x8AA80000,0xFAAC0019,0xD89C0000,0x1E800A2,0x7A8C0001,
-0x1E800A2,0x10C00C8,0xB8F80000,0x98F80001,0x8EF80001,0x38C00C8,0xA0D40001,0x8EE40001,0x4BFC00C8,0x8EA80001,0x840000CA,0x38C00C8,0xA0D40001,0x8EE40001,0x4BFC00C8,0x8EA80001,0x840000CA,0x4BFC00C8,0x8EA80001,0x840000CA,0x840000CA,0x38C00C8,0xA0D40001,0x8EE40001,0x4BFC00C8,0x8EA80001,0x840000CA,0x4BFC00C8,0x8EA80001,0x840000CA,0x840000CA,0x4BFC00C8,
-0x8EA80001,0x840000CA,0x840000CA,0x840000CA,0xF2E0003D,0x71C00C8,0xFB040048,0xE0B00000,0xB6A80001,0x9EA80000,0x8EC00001,0x8E8C0001,0xF4C80032,0xDA9C0000,0x92C40000,0x840000CA,0x1DF800C8,0xC000C8,0xC000C8,0xC000C8,0xC000C8,0xC000C8,0xC000C8,0xC000C8,0xC000C8,0xC000C8,0xC000C8,0x92AC0000,0x92AC0000,0x92AC0000,0x92AC0000,0x92AC0000,
-0x92AC0000,0x72AC0001,0x72AC0001,0x72AC0001,0x68AC0001,0x11C00C8,0x11C00C8,0x11C00C8,0x11C00C8,0x11C00C8,0x11C00C8,0x7A880001,0x7A880001,0x7A880001,0x68980001,0x13FC00C8,0x13FC00C8,0x13FC00C8,0x685C0001,0x5E0000CA,0xF2B40034,0xC000C8,0xC000C8,0xE0AC0000,0xB6AC0000,0xA0AC0000,0xA0AC0000,0x86AC0000,0xFC9C0012,0xD09C0001,0x7AA80001,0x7A880001,
-0x19800C8,};
-static const uint32_t g_etc1_to_bc7_m6_table79[] = {
-0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x11F80000,
-0x11F80000,0x11F80000,0x11F80000,0x5C000001,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xC80000,0xC80000,0xC80000,0x1180000,0x1900000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,
-0x3500000,0x2DFC0000,0x2DFC0000,0x2DFC0000,0x70000001,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,0x2DFC0000,0x2DFC0000,0x2DFC0000,0x70000001,0x2DFC0000,0x2DFC0000,0x2DFC0000,0x70000001,0x70000001,0xF40000,0xE40000,0xE40000,0x1080000,0x31C0000,0x3340000,0x3340000,0x1800000,0x1080000,0x31C0000,0x1E40000,0x2DFC0000,
-0x1E40000,0x1080000,0x1080000,0x1080000,0x1080000,0x1880000,0x1880000,0x1880000,0x49F80000,0x49F80000,0x82000001,0x1880000,0x1880000,0x1880000,0x49F80000,0x49F80000,0x82000001,0x49F80000,0x49F80000,0x82000001,0x82000001,0x1880000,0x1880000,0x1880000,0x49F80000,0x49F80000,0x82000001,0x49F80000,0x49F80000,0x82000001,0x82000001,0x49F80000,
-0x49F80000,0x82000001,0x82000001,0x82000001,0x1340000,0x5180000,0x1080000,0x1680000,0x1BC0000,0x19FC0000,0x31FC0000,0x59F40000,0x14C0000,0x1880000,0x19FC0000,0x82000001,0x19FC0000,0x1300000,0x1C40000,0x67F80000,0x96000001,0x1C40000,0x67F80000,0x96000001,0x67F80000,0x96000001,0x96000001,0x1C40000,0x67F80000,0x96000001,0x67F80000,0x96000001,
-0x96000001,0x67F80000,0x96000001,0x96000001,0x96000001,0x1C40000,0x67F80000,0x96000001,0x67F80000,0x96000001,0x96000001,0x67F80000,0x96000001,0x96000001,0x96000001,0x67F80000,0x96000001,0x96000001,0x96000001,0x96000001,0x17C0000,0x1440000,0x1440000,0x3FC0000,0x53F80000,0x7FF00000,0x96000001,0x96000001,0x19C0000,0x25FC0000,0x91F40000,0x96000001,
-0x3FF80000,0xF40738,0xE4E402D4,0xAAE402D4,0x96E402D5,0xDAD00190,0xB2D000D5,0x98D8013A,0xA0D00190,0x94D000D5,0x8CD00192,0xD4BC02D3,0xB4BC00A2,0x9CC800FF,0xA4BC00D1,0x96BC0002,0x8CC000D7,0x96BC02D4,0x92B400FD,0x8AB4013B,0x84BC02D3,0x16C0734,0xBC9802D3,0x96BC02D4,0xAE8C0192,0x98A400CF,0x8CAC0192,0xA87402D3,0x968400A3,0x8C8400D7,0x849402D4,0x3BFC0734,
-0x964402D4,0x8C380192,0x841C02D3,0x7A000734,0xFED8019A,0xFEEC04DA,0xFEEC0585,0xECBC0000,0xBEBC0001,0xA4BC0002,0x98C00012,0x94BC0011,0xFEBC0167,0xE0AC0002,0x9AB000A9,0x8C8400D7,0x7FC0734,0x10802D4,0xD0F800A4,0xA4F800A4,0x96F400A5,0xC6E400C8,0xA8E40001,0x98E80015,0x9AE400C8,0x94E00026,0x8CE400CA,0x18C02D3,0xB2C000A2,0x96DC00A3,0xA6B400C9,0x96BC0002,
-0x8EC800CA,0x4BF802D3,0x968400A3,0x8C7400CA,0x840002D3,0x18C02D3,0xB2C000A2,0x96DC00A3,0xA6B400C9,0x96BC0002,0x8EC800CA,0x4BF802D3,0x968400A3,0x8C7400CA,0x840002D3,0x4BF802D3,0x968400A3,0x8C7400CA,0x840002D3,0x840002D3,0xFEE400A6,0xF90001D4,0xFB0401C8,0xECBC0000,0xBEBC0001,0xA4BC0002,0x98C80002,0x96B00005,0xFACC00B5,0xE0AC0001,0x9CA800A2,0x8C7400CA,
-0x1BFC02D3,0xE402D4,0xE402D4,0xE402D4,0xE402D4,0xBCD000C8,0xBCD000C8,0xBCD000C8,0x90D000C8,0x90D000C8,0x82D000C9,0xB4BC00A2,0xB4BC00A2,0xB4BC00A2,0x96BC0001,0x96BC0001,0x86C00026,0x88BC00A2,0x88BC00A2,0x82B80015,0x7ABC00A2,0x15002D3,0x15002D3,0x15002D3,0x9C9C00C9,0x9C9C00C9,0x84B400C9,0x968400A2,0x968400A2,0x82980002,0x7AA000A2,0x2DF802D3,
-0x2DF802D3,0x826000C9,0x7A4400A2,0x700002D3,0xFECC0084,0xF6DC01B9,0xE402D4,0xECBC0000,0xBABC0001,0xA4BC0001,0x9EC00006,0x90BC0002,0xFEB40065,0xE0AC0001,0x98B400A2,0x82980002,0x1E002D3,0xF400A4,0xF400A4,0xF400A4,0xF400A4,0xA8E40000,0xA8E40000,0xA8E40000,0x8CE40000,0x8CE40000,0x82E40001,0x16C00A2,0x16C00A2,0x16C00A2,0x92C40001,0x92C40001,
-0x82D40001,0x3BFC00A2,0x3BFC00A2,0x829C0001,0x7A0000A2,0x16C00A2,0x16C00A2,0x16C00A2,0x92C40001,0x92C40001,0x82D40001,0x3BFC00A2,0x3BFC00A2,0x829C0001,0x7A0000A2,0x3BFC00A2,0x3BFC00A2,0x829C0001,0x7A0000A2,0x7A0000A2,0xFED80012,0xFEEC0029,0xF400A4,0xECBC0000,0xB8C00000,0xA2C00000,0x98C80001,0x92B80000,0xFCC00020,0xE0AC0000,0x7FC00A2,0x829C0001,
-0x7FC00A2,0x11C00C8,0xC1080000,0xA1080001,0x97080001,0x3A400C8,0xA8E40001,0x96F40001,0x57FC00C8,0x96B80001,0x8C0000CA,0x3A400C8,0xA8E40001,0x96F40001,0x57FC00C8,0x96B80001,0x8C0000CA,0x57FC00C8,0x96B80001,0x8C0000CA,0x8C0000CA,0x3A400C8,0xA8E40001,0x96F40001,0x57FC00C8,0x96B80001,0x8C0000CA,0x57FC00C8,0x96B80001,0x8C0000CA,0x8C0000CA,0x57FC00C8,
-0x96B80001,0x8C0000CA,0x8C0000CA,0x8C0000CA,0xFAF0003D,0xF2C00C8,0xF3140055,0xE8C00000,0xBEB80001,0xA6B80000,0x96D00001,0x969C0001,0xFCD80032,0xE2AC0000,0x9AD40000,0x8C0000CA,0x2BFC00C8,0xD000C8,0xD000C8,0xD000C8,0xD000C8,0xD000C8,0xD000C8,0xD000C8,0xD000C8,0xD000C8,0xD000C8,0x9ABC0000,0x9ABC0000,0x9ABC0000,0x9ABC0000,0x9ABC0000,
-0x9ABC0000,0x7ABC0001,0x7ABC0001,0x7ABC0001,0x70BC0001,0x13400C8,0x13400C8,0x13400C8,0x13400C8,0x13400C8,0x13400C8,0x82980001,0x82980001,0x82980001,0x70A80001,0x1FF800C8,0x1FF800C8,0x1FF800C8,0x706C0001,0x660000CA,0xFAC40034,0xD000C8,0xD000C8,0xE8BC0000,0xBEBC0000,0xA8BC0000,0xA8BC0000,0x8EBC0000,0xF8B00019,0xD8AC0001,0x82B80001,0x82980001,
-0x1B800C8,};
-static const uint32_t g_etc1_to_bc7_m6_table80[] = {
-0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0x3300000,0x3300000,0x3300000,0x3300000,0x3300000,0x3300000,0x3300000,0x3300000,0x3300000,0x3300000,0x1DFC0000,
-0x1DFC0000,0x1DFC0000,0x1DFC0000,0x66000000,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0xDC0000,0xDC0000,0xDC0000,0x3300000,0x1B40000,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,
-0x16C0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x7A000000,0xB040000,0xF40001,0xF40001,0x51C0000,0x1340000,0x34C0000,0x34C0000,0x19C0000,0x51C0000,0x1340000,0x7FC0000,0x3BFC0000,
-0x7FC0000,0x1180001,0x1180001,0x1180001,0x1180001,0x1A40000,0x1A40000,0x1A40000,0x57F80000,0x57F80000,0x8C000000,0x1A40000,0x1A40000,0x1A40000,0x57F80000,0x57F80000,0x8C000000,0x57F80000,0x57F80000,0x8C000000,0x8C000000,0x1A40000,0x1A40000,0x1A40000,0x57F80000,0x57F80000,0x8C000000,0x57F80000,0x57F80000,0x8C000000,0x8C000000,0x57F80000,
-0x57F80000,0x8C000000,0x8C000000,0x8C000000,0x1480000,0x12C0000,0x1180001,0x1800000,0x1D80000,0x29FC0000,0x3FFC0000,0x65F40000,0x3600000,0x1A40000,0x29FC0000,0x8C000000,0x29FC0000,0x1400001,0x3DC0000,0x73FC0000,0xA0000000,0x3DC0000,0x73FC0000,0xA0000000,0x73FC0000,0xA0000000,0xA0000000,0x3DC0000,0x73FC0000,0xA0000000,0x73FC0000,0xA0000000,
-0xA0000000,0x73FC0000,0xA0000000,0xA0000000,0xA0000000,0x3DC0000,0x73FC0000,0xA0000000,0x73FC0000,0xA0000000,0xA0000000,0x73FC0000,0xA0000000,0xA0000000,0xA0000000,0x73FC0000,0xA0000000,0xA0000000,0xA0000000,0xA0000000,0x1940000,0x1580000,0x1580000,0x19FC0000,0x61FC0000,0x89FC0000,0xA0000000,0xA0000000,0x3B40000,0x37FC0000,0x9BE80000,0xA0000000,
-0x4FFC0000,0x1080734,0xF0F402D3,0xB2F402D4,0xA0F402D3,0xE2E40192,0xBAE400D7,0xA4E8013B,0xA8E40192,0x9EE000D7,0x96E00192,0xDAD002D4,0xBCD000A3,0xA4D800FD,0xACCC00CF,0xA0D00002,0x96D400D5,0xA0CC02D4,0x9AC400FF,0x92CC013A,0x8CCC02D5,0x1880734,0xC4AC02D3,0xA0D002D4,0xB89C0192,0xA0B400D1,0x96BC0190,0xB28402D3,0xA09400A2,0x969800D5,0x8CA802D4,0x49F80734,
-0xA05402D3,0x96440190,0x8C3002D4,0x82000738,0xFEEC01E2,0xF9000514,0xFB040594,0xF4D00002,0xC6CC0003,0xAED00002,0xA0D40011,0x9EC80012,0xFED4019A,0xECBC0000,0xA2C400A9,0x969800D5,0x19FC0734,0x11C02D3,0xDB0800A2,0xAF0800A2,0xA10800A2,0xCCF800C9,0xB0F80002,0xA2F80015,0xA4F400C9,0x9EF00026,0x96F400C9,0x3A402D3,0xBCD000A2,0xA0EC00A2,0xB0C400C9,0xA0D00001,
-0x96DC00C8,0x57FC02D3,0xA09000A2,0x968400C8,0x8C0002D4,0x3A402D3,0xBCD000A2,0xA0EC00A2,0xB0C400C9,0xA0D00001,0x96DC00C8,0x57FC02D3,0xA09000A2,0x968400C8,0x8C0002D4,0x57FC02D3,0xA09000A2,0x968400C8,0x8C0002D4,0x8C0002D4,0xFEF800B6,0xFF0C01E3,0xF51801E6,0xF4D00001,0xC6CC0002,0xAED00001,0xA0DC0002,0x9EC00006,0xFEDC00C5,0xECBC0000,0xA4BC00A2,0x968400C8,
-0x2BFC02D3,0xF402D3,0xF402D3,0xF402D3,0xF402D3,0xC2E400CA,0xC2E400CA,0xC2E400CA,0x9AE000CA,0x9AE000CA,0x8CE000CA,0xBCD000A3,0xBCD000A3,0xBCD000A3,0x9ED00002,0x9ED00002,0x8ED40026,0x90D000A3,0x90D000A3,0x8ACC0015,0x82CC00A5,0x36802D3,0x36802D3,0x36802D3,0xA4B000C9,0xA4B000C9,0x8CC800C8,0x9E9800A2,0x9E9800A2,0x8CA80001,0x82B400A4,0x39FC02D3,
-0x39FC02D3,0x8C7000C8,0x825C00A4,0x7A0002D4,0xFAE000A6,0xFEEC01BE,0xF402D3,0xF8CC0001,0xC2D00002,0xACD00002,0xA6D00005,0x9ACC0002,0xFCCC0080,0xECBC0000,0xA0C800A3,0x8CA80001,0x5FC02D3,0x10800A2,0x10800A2,0x10800A2,0x10800A2,0xAEF80001,0xAEF80001,0xAEF80001,0x94F80001,0x94F80001,0x8CF40001,0x18800A2,0x18800A2,0x18800A2,0x9AD80001,0x9AD80001,
-0x8CE40000,0x49F800A2,0x49F800A2,0x8CAC0000,0x820000A4,0x18800A2,0x18800A2,0x18800A2,0x9AD80001,0x9AD80001,0x8CE40000,0x49F800A2,0x49F800A2,0x8CAC0000,0x820000A4,0x49F800A2,0x49F800A2,0x8CAC0000,0x820000A4,0x820000A4,0xFAEC0019,0xF9000032,0x10800A2,0xF8CC0000,0xBED40000,0xAAD40000,0xA2D80000,0x9ACC0001,0xFED00028,0xECBC0000,0x19FC00A2,0x8CAC0000,
-0x19FC00A2,0x12C00CA,0xC71C0001,0xAB180001,0xA1180001,0x1C000C8,0xB0F80001,0xA1040001,0x65F800C8,0xA0C80000,0x960000C8,0x1C000C8,0xB0F80001,0xA1040001,0x65F800C8,0xA0C80000,0x960000C8,0x65F800C8,0xA0C80000,0x960000C8,0x960000C8,0x1C000C8,0xB0F80001,0xA1040001,0x65F800C8,0xA0C80000,0x960000C8,0x65F800C8,0xA0C80000,0x960000C8,0x960000C8,0x65F800C8,
-0xA0C80000,0x960000C8,0x960000C8,0x960000C8,0xFB040048,0x94000C8,0xFD280055,0xF4D00000,0xC6CC0001,0xB0C80000,0xA0E00000,0xA0A80000,0xFEF0003D,0xECBC0000,0xA2E80001,0x960000C8,0x3DF800C8,0xE000CA,0xE000CA,0xE000CA,0xE000CA,0xE000CA,0xE000CA,0xE000CA,0xE000CA,0xE000CA,0xE000CA,0xA0D00001,0xA0D00001,0xA0D00001,0xA0D00001,0xA0D00001,
-0xA0D00001,0x84CC0001,0x84CC0001,0x84CC0001,0x7ACC0001,0x15000C8,0x15000C8,0x15000C8,0x15000C8,0x15000C8,0x15000C8,0x8AAC0001,0x8AAC0001,0x8AAC0001,0x7AB80001,0x2DF800C8,0x2DF800C8,0x2DF800C8,0x7A7C0000,0x700000C8,0xF4D8003D,0xE000CA,0xE000CA,0xECD00001,0xC4D00001,0xAED00001,0xAED00001,0x96D00001,0xF4C40020,0xEABC0000,0x8EC80000,0x8AAC0001,
-0x1E000C8,};
-static const uint32_t g_etc1_to_bc7_m6_table81[] = {
-0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x29FC0000,
-0x29FC0000,0x29FC0000,0x29FC0000,0x6E000000,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xDC0001,0xEC0000,0xEC0000,0xEC0000,0x1480000,0x1D80000,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,
-0x1840000,0x47FC0000,0x47FC0000,0x47FC0000,0x82000000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x47FC0000,0x47FC0000,0x47FC0000,0x82000000,0x47FC0000,0x47FC0000,0x47FC0000,0x82000000,0x82000000,0x1180000,0x1040001,0x1040001,0x1300000,0x1480000,0x1640000,0x1640000,0x1B80000,0x1300000,0x1480000,0x17FC0000,0x47FC0000,
-0x17FC0000,0x1280001,0x1280001,0x1280001,0x1280001,0x1BC0000,0x1BC0000,0x1BC0000,0x61FC0000,0x61FC0000,0x94000000,0x1BC0000,0x1BC0000,0x1BC0000,0x61FC0000,0x61FC0000,0x94000000,0x61FC0000,0x61FC0000,0x94000000,0x94000000,0x1BC0000,0x1BC0000,0x1BC0000,0x61FC0000,0x61FC0000,0x94000000,0x61FC0000,0x61FC0000,0x94000000,0x94000000,0x61FC0000,
-0x61FC0000,0x94000000,0x94000000,0x94000000,0x5580000,0x73C0000,0x1280001,0x1940000,0x1F40000,0x39FC0000,0x4DFC0000,0x6FFC0000,0x3740000,0x1BC0000,0x39FC0000,0x94000000,0x39FC0000,0x1500001,0x3F40000,0x7FFC0000,0xA8000000,0x3F40000,0x7FFC0000,0xA8000000,0x7FFC0000,0xA8000000,0xA8000000,0x3F40000,0x7FFC0000,0xA8000000,0x7FFC0000,0xA8000000,
-0xA8000000,0x7FFC0000,0xA8000000,0xA8000000,0xA8000000,0x3F40000,0x7FFC0000,0xA8000000,0x7FFC0000,0xA8000000,0xA8000000,0x7FFC0000,0xA8000000,0xA8000000,0xA8000000,0x7FFC0000,0xA8000000,0xA8000000,0xA8000000,0xA8000000,0x1A80000,0x1680000,0x1680000,0x2DFC0000,0x6FFC0000,0x93FC0000,0xA8000000,0xA8000000,0x1CC0000,0x49FC0000,0xA3F80000,0xA8000000,
-0x5FF80000,0x1180734,0xF90402D3,0xBB0402D4,0xA90402D3,0xEAF40192,0xC2F400D7,0xACF8013B,0xB0F40192,0xA6F000D7,0x9EF00192,0xE2E002D4,0xC4E000A3,0xACE800FD,0xB4DC00CF,0xA8E00002,0x9EE400D5,0xA8DC02D4,0xA2D400FF,0x9ADC013A,0x94DC02D5,0x1A00734,0xCCBC02D3,0xA8E002D4,0xC0AC0192,0xA8C400D1,0x9ECC0190,0xBA9402D3,0xA8A400A2,0x9EA800D5,0x94B802D4,0x55F80734,
-0xA86402D3,0x9E540190,0x944002D4,0x8A000738,0xFEF8021F,0xFF0C0524,0xF31405C3,0xFCE00002,0xCEDC0003,0xB6E00002,0xA8E40011,0xA6D80012,0xFCEC01F6,0xF4CC0000,0xAAD400A9,0x9EA800D5,0x27FC0734,0x12C02D3,0xE31800A2,0xB71800A2,0xA91800A2,0xD50800C9,0xB9080002,0xAB080015,0xAD0400C9,0xA7000026,0x9F0400C9,0x3BC02D3,0xC4E000A2,0xA8FC00A2,0xB8D400C9,0xA8E00001,
-0x9EEC00C8,0x63FC02D3,0xA8A000A2,0x9E9400C8,0x940002D4,0x3BC02D3,0xC4E000A2,0xA8FC00A2,0xB8D400C9,0xA8E00001,0x9EEC00C8,0x63FC02D3,0xA8A000A2,0x9E9400C8,0x940002D4,0x63FC02D3,0xA8A000A2,0x9E9400C8,0x940002D4,0x940002D4,0xFB0C00DE,0xF92001F1,0xFD2801E6,0xFCE00001,0xCEDC0002,0xB6E00001,0xA8EC0002,0xA6D00006,0xFCF400E1,0xF4CC0000,0xACCC00A2,0x9E9400C8,
-0x3BFC02D3,0x10402D3,0x10402D3,0x10402D3,0x10402D3,0xCAF400CA,0xCAF400CA,0xCAF400CA,0xA2F000CA,0xA2F000CA,0x94F000CA,0xC4E000A3,0xC4E000A3,0xC4E000A3,0xA6E00002,0xA6E00002,0x96E40026,0x98E000A3,0x98E000A3,0x92DC0015,0x8ADC00A5,0x38002D3,0x38002D3,0x38002D3,0xACC000C9,0xACC000C9,0x94D800C8,0xA6A800A2,0xA6A800A2,0x94B80001,0x8AC400A4,0x45FC02D3,
-0x45FC02D3,0x948000C8,0x8A6C00A4,0x820002D4,0xFEF400BA,0xF90001D3,0x10402D3,0xF6E00002,0xCAE00002,0xB4E00002,0xAEE00005,0xA2DC0002,0xFED800A1,0xF4CC0000,0xA8D800A3,0x94B80001,0x15FC02D3,0x11800A2,0x11800A2,0x11800A2,0x11800A2,0xB7080001,0xB7080001,0xB7080001,0x9D080001,0x9D080001,0x95040001,0x1A000A2,0x1A000A2,0x1A000A2,0xA2E80001,0xA2E80001,
-0x94F40000,0x55F800A2,0x55F800A2,0x94BC0000,0x8A0000A4,0x1A000A2,0x1A000A2,0x1A000A2,0xA2E80001,0xA2E80001,0x94F40000,0x55F800A2,0x55F800A2,0x94BC0000,0x8A0000A4,0x55F800A2,0x55F800A2,0x94BC0000,0x8A0000A4,0x8A0000A4,0xF7000020,0xFF0C003A,0x11800A2,0xF4E40001,0xC6E40000,0xB2E40000,0xAAE80000,0xA2DC0001,0xF8EC0029,0xF4CC0000,0x27FC00A2,0x94BC0000,
-0x27FC00A2,0x13C00CA,0xCF2C0001,0xB3280001,0xA9280001,0x1D800C8,0xB9080001,0xA9140001,0x71F800C8,0xA8D80000,0x9E0000C8,0x1D800C8,0xB9080001,0xA9140001,0x71F800C8,0xA8D80000,0x9E0000C8,0x71F800C8,0xA8D80000,0x9E0000C8,0x9E0000C8,0x1D800C8,0xB9080001,0xA9140001,0x71F800C8,0xA8D80000,0x9E0000C8,0x71F800C8,0xA8D80000,0x9E0000C8,0x9E0000C8,0x71F800C8,
-0xA8D80000,0x9E0000C8,0x9E0000C8,0x9E0000C8,0xFF14004A,0x15400C8,0xF5380062,0xFCE00000,0xCEDC0001,0xB8D80000,0xA8F00000,0xA8B80000,0xF7080048,0xF4CC0000,0xAAF80001,0x9E0000C8,0x4BFC00C8,0xF000CA,0xF000CA,0xF000CA,0xF000CA,0xF000CA,0xF000CA,0xF000CA,0xF000CA,0xF000CA,0xF000CA,0xA8E00001,0xA8E00001,0xA8E00001,0xA8E00001,0xA8E00001,
-0xA8E00001,0x8CDC0001,0x8CDC0001,0x8CDC0001,0x82DC0001,0x16800C8,0x16800C8,0x16800C8,0x16800C8,0x16800C8,0x16800C8,0x92BC0001,0x92BC0001,0x92BC0001,0x82C80001,0x39F800C8,0x39F800C8,0x39F800C8,0x828C0000,0x780000C8,0xFCE8003D,0xF000CA,0xF000CA,0xF4E00001,0xCCE00001,0xB6E00001,0xB6E00001,0x9EE00001,0xFCD40020,0xF2CC0000,0x96D80000,0x92BC0001,
-0x3FC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table82[] = {
-0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x35FC0000,
-0x35FC0000,0x35FC0000,0x35FC0000,0x76000000,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0x6FC0000,0x6FC0000,0x6FC0000,0x1600000,0x1F80000,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,
-0x19C0000,0x53FC0000,0x53FC0000,0x53FC0000,0x8A000000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x53FC0000,0x53FC0000,0x53FC0000,0x8A000000,0x53FC0000,0x53FC0000,0x53FC0000,0x8A000000,0x8A000000,0x1280000,0x1140001,0x1140001,0x1440000,0x15C0000,0x3780000,0x3780000,0x1D40000,0x1440000,0x15C0000,0x25FC0000,0x53FC0000,
-0x25FC0000,0x1380001,0x1380001,0x1380001,0x1380001,0x3D00000,0x3D00000,0x3D00000,0x6DFC0000,0x6DFC0000,0x9C000000,0x3D00000,0x3D00000,0x3D00000,0x6DFC0000,0x6DFC0000,0x9C000000,0x6DFC0000,0x6DFC0000,0x9C000000,0x9C000000,0x3D00000,0x3D00000,0x3D00000,0x6DFC0000,0x6DFC0000,0x9C000000,0x6DFC0000,0x6DFC0000,0x9C000000,0x9C000000,0x6DFC0000,
-0x6DFC0000,0x9C000000,0x9C000000,0x9C000000,0x16C0000,0xF4C0000,0x1380001,0x1AC0000,0xFFC0000,0x47FC0000,0x5BFC0000,0x7BF40000,0x3880000,0x3D00000,0x47FC0000,0x9C000000,0x47FC0000,0x1600001,0x13FC0000,0x8BFC0000,0xB0000000,0x13FC0000,0x8BFC0000,0xB0000000,0x8BFC0000,0xB0000000,0xB0000000,0x13FC0000,0x8BFC0000,0xB0000000,0x8BFC0000,0xB0000000,
-0xB0000000,0x8BFC0000,0xB0000000,0xB0000000,0xB0000000,0x13FC0000,0x8BFC0000,0xB0000000,0x8BFC0000,0xB0000000,0xB0000000,0x8BFC0000,0xB0000000,0xB0000000,0xB0000000,0x8BFC0000,0xB0000000,0xB0000000,0xB0000000,0xB0000000,0x1BC0000,0x5780000,0x5780000,0x41FC0000,0x7DF80000,0x9DFC0000,0xB0000000,0xB0000000,0x1E00000,0x59FC0000,0xADCC0000,0xB0000000,
-0x6DFC0000,0x1280734,0xFD1402D4,0xC31402D4,0xB11402D3,0xF3040192,0xCB0400D7,0xB508013B,0xB9040192,0xAF0000D7,0xA7000192,0xEAF002D4,0xCCF000A3,0xB4F800FD,0xBCEC00CF,0xB0F00002,0xA6F400D5,0xB0EC02D4,0xAAE400FF,0xA2EC013A,0x9CEC02D5,0x1B80734,0xD4CC02D3,0xB0F002D4,0xC8BC0192,0xB0D400D1,0xA6DC0190,0xC2A402D3,0xB0B400A2,0xA6B800D5,0x9CC802D4,0x61F80734,
-0xB07402D3,0xA6640190,0x9C5002D4,0x92000738,0xFF0C0252,0xF9200552,0xFB2405C3,0xFEF00006,0xD6EC0003,0xBEF00002,0xB0F40011,0xAEE80012,0xFEF8021A,0xFCDC0000,0xB2E400A9,0xA6B800D5,0x37FC0734,0x13C02D3,0xEB2800A2,0xBF2800A2,0xB12800A2,0xDD1800C9,0xC1180002,0xB3180015,0xB51400C9,0xAF100026,0xA71400C9,0x1D402D3,0xCCF000A2,0xB10C00A2,0xC0E400C9,0xB0F00001,
-0xA6FC00C8,0x6FFC02D3,0xB0B000A2,0xA6A400C8,0x9C0002D4,0x1D402D3,0xCCF000A2,0xB10C00A2,0xC0E400C9,0xB0F00001,0xA6FC00C8,0x6FFC02D3,0xB0B000A2,0xA6A400C8,0x9C0002D4,0x6FFC02D3,0xB0B000A2,0xA6A400C8,0x9C0002D4,0x9C0002D4,0xFD1C00F5,0xFF2C0209,0xF5380203,0xFCF40005,0xD6EC0002,0xBEF00001,0xB0FC0002,0xAEE00006,0xFF0800F4,0xFCDC0000,0xB4DC00A2,0xA6A400C8,
-0x49FC02D3,0x11402D3,0x11402D3,0x11402D3,0x11402D3,0xD30400CA,0xD30400CA,0xD30400CA,0xAB0000CA,0xAB0000CA,0x9D0000CA,0xCCF000A3,0xCCF000A3,0xCCF000A3,0xAEF00002,0xAEF00002,0x9EF40026,0xA0F000A3,0xA0F000A3,0x9AEC0015,0x92EC00A5,0x39802D3,0x39802D3,0x39802D3,0xB4D000C9,0xB4D000C9,0x9CE800C8,0xAEB800A2,0xAEB800A2,0x9CC80001,0x92D400A4,0x51FC02D3,
-0x51FC02D3,0x9C9000C8,0x927C00A4,0x8A0002D4,0xFF0400CB,0xFF0C01DB,0x11402D3,0xFEF00002,0xD2F00002,0xBCF00002,0xB6F00005,0xAAEC0002,0xFCF000B5,0xFCDC0000,0xB0E800A3,0x9CC80001,0x23FC02D3,0x12800A2,0x12800A2,0x12800A2,0x12800A2,0xBF180001,0xBF180001,0xBF180001,0xA5180001,0xA5180001,0x9D140001,0x1B800A2,0x1B800A2,0x1B800A2,0xAAF80001,0xAAF80001,
-0x9D040000,0x61F800A2,0x61F800A2,0x9CCC0000,0x920000A4,0x1B800A2,0x1B800A2,0x1B800A2,0xAAF80001,0xAAF80001,0x9D040000,0x61F800A2,0x61F800A2,0x9CCC0000,0x920000A4,0x61F800A2,0x61F800A2,0x9CCC0000,0x920000A4,0x920000A4,0xFF100020,0xF920003D,0x12800A2,0xFCF40001,0xCEF40000,0xBAF40000,0xB2F80000,0xAAEC0001,0xFEF8002D,0xFCDC0000,0x37FC00A2,0x9CCC0000,
-0x37FC00A2,0x14C00CA,0xD73C0001,0xBB380001,0xB1380001,0x1F000C8,0xC1180001,0xB1240001,0x7DF800C8,0xB0E80000,0xA60000C8,0x1F000C8,0xC1180001,0xB1240001,0x7DF800C8,0xB0E80000,0xA60000C8,0x7DF800C8,0xB0E80000,0xA60000C8,0xA60000C8,0x1F000C8,0xC1180001,0xB1240001,0x7DF800C8,0xB0E80000,0xA60000C8,0x7DF800C8,0xB0E80000,0xA60000C8,0xA60000C8,0x7DF800C8,
-0xB0E80000,0xA60000C8,0xA60000C8,0xA60000C8,0xFB2C0055,0x16400C8,0xFD480062,0xFEF40001,0xD6EC0001,0xC0E80000,0xB1000000,0xB0C80000,0xFF180048,0xFCDC0000,0xB3080001,0xA60000C8,0x5BFC00C8,0x10000CA,0x10000CA,0x10000CA,0x10000CA,0x10000CA,0x10000CA,0x10000CA,0x10000CA,0x10000CA,0x10000CA,0xB0F00001,0xB0F00001,0xB0F00001,0xB0F00001,0xB0F00001,
-0xB0F00001,0x94EC0001,0x94EC0001,0x94EC0001,0x8AEC0001,0x18000C8,0x18000C8,0x18000C8,0x18000C8,0x18000C8,0x18000C8,0x9ACC0001,0x9ACC0001,0x9ACC0001,0x8AD80001,0x45F800C8,0x45F800C8,0x45F800C8,0x8A9C0000,0x800000C8,0xF4F8004A,0x10000CA,0x10000CA,0xFCF00001,0xD4F00001,0xBEF00001,0xBEF00001,0xA6F00001,0xF8E80029,0xFADC0000,0x9EE80000,0x9ACC0001,
-0x13FC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table83[] = {
-0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x41FC0000,
-0x41FC0000,0x41FC0000,0x41FC0000,0x7E000000,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xF0C0000,0xF0C0000,0xF0C0000,0x1780000,0xFFC0000,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,
-0x1B40000,0x5FF80000,0x5FF80000,0x5FF80000,0x92000000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x5FF80000,0x5FF80000,0x5FF80000,0x92000000,0x5FF80000,0x5FF80000,0x5FF80000,0x92000000,0x92000000,0x5380000,0x1240001,0x1240001,0x3540000,0x1700000,0x1900000,0x1900000,0x3EC0000,0x3540000,0x1700000,0x35FC0000,0x5FF80000,
-0x35FC0000,0x1480001,0x1480001,0x1480001,0x1480001,0x3E80000,0x3E80000,0x3E80000,0x79FC0000,0x79FC0000,0xA4000000,0x3E80000,0x3E80000,0x3E80000,0x79FC0000,0x79FC0000,0xA4000000,0x79FC0000,0x79FC0000,0xA4000000,0xA4000000,0x3E80000,0x3E80000,0x3E80000,0x79FC0000,0x79FC0000,0xA4000000,0x79FC0000,0x79FC0000,0xA4000000,0xA4000000,0x79FC0000,
-0x79FC0000,0xA4000000,0xA4000000,0xA4000000,0x1800000,0x1600000,0x1480001,0x1C00000,0x23FC0000,0x57FC0000,0x69F80000,0x85F80000,0x39C0000,0x3E80000,0x57FC0000,0xA4000000,0x57FC0000,0x1700001,0x2BFC0000,0x97FC0000,0xB8000000,0x2BFC0000,0x97FC0000,0xB8000000,0x97FC0000,0xB8000000,0xB8000000,0x2BFC0000,0x97FC0000,0xB8000000,0x97FC0000,0xB8000000,
-0xB8000000,0x97FC0000,0xB8000000,0xB8000000,0xB8000000,0x2BFC0000,0x97FC0000,0xB8000000,0x97FC0000,0xB8000000,0xB8000000,0x97FC0000,0xB8000000,0xB8000000,0xB8000000,0x97FC0000,0xB8000000,0xB8000000,0xB8000000,0xB8000000,0x1D00000,0xD880000,0xD880000,0x53FC0000,0x89FC0000,0xA7FC0000,0xB8000000,0xB8000000,0x1F80000,0x6BFC0000,0xB5DC0000,0xB8000000,
-0x7DF80000,0x1380734,0xFF2402DC,0xCB2402D4,0xB92402D3,0xFB140192,0xD31400D7,0xBD18013B,0xC1140192,0xB71000D7,0xAF100192,0xF30002D4,0xD50000A3,0xBD0800FD,0xC4FC00CF,0xB9000002,0xAF0400D5,0xB8FC02D4,0xB2F400FF,0xAAFC013A,0xA4FC02D5,0x1D00734,0xDCDC02D3,0xB90002D4,0xD0CC0192,0xB8E400D1,0xAEEC0190,0xCAB402D3,0xB8C400A2,0xAEC800D5,0xA4D802D4,0x6DF80734,
-0xB88402D3,0xAE740190,0xA46002D4,0x9A000738,0xFF20028E,0xFF2C056A,0xF33405F4,0xFF04001E,0xDEFC0003,0xC7000002,0xB9040011,0xB6F80012,0xFF10025E,0xFEF00006,0xBAF400A9,0xAEC800D5,0x45FC0734,0x14C02D3,0xF33800A2,0xC73800A2,0xB93800A2,0xE52800C9,0xC9280002,0xBB280015,0xBD2400C9,0xB7200026,0xAF2400C9,0x1EC02D3,0xD50000A2,0xB91C00A2,0xC8F400C9,0xB9000001,
-0xAF0C00C8,0x7BFC02D3,0xB8C000A2,0xAEB400C8,0xA40002D4,0x1EC02D3,0xD50000A2,0xB91C00A2,0xC8F400C9,0xB9000001,0xAF0C00C8,0x7BFC02D3,0xB8C000A2,0xAEB400C8,0xA40002D4,0x7BFC02D3,0xB8C000A2,0xAEB400C8,0xA40002D4,0xA40002D4,0xFD30010A,0xFB44020B,0xFD480203,0xFF08000D,0xDEFC0002,0xC7000001,0xB90C0002,0xB6F00006,0xFF180119,0xFEF00005,0xBCEC00A2,0xAEB400C8,
-0x59FC02D3,0x12402D3,0x12402D3,0x12402D3,0x12402D3,0xDB1400CA,0xDB1400CA,0xDB1400CA,0xB31000CA,0xB31000CA,0xA51000CA,0xD50000A3,0xD50000A3,0xD50000A3,0xB7000002,0xB7000002,0xA7040026,0xA90000A3,0xA90000A3,0xA2FC0015,0x9AFC00A5,0x3B002D3,0x3B002D3,0x3B002D3,0xBCE000C9,0xBCE000C9,0xA4F800C8,0xB6C800A2,0xB6C800A2,0xA4D80001,0x9AE400A4,0x5DFC02D3,
-0x5DFC02D3,0xA4A000C8,0x9A8C00A4,0x920002D4,0xFF1000F1,0xF92001EE,0x12402D3,0xFF00000B,0xDB000002,0xC5000002,0xBF000005,0xB2FC0002,0xFF0000CB,0xFCF00002,0xB8F800A3,0xA4D80001,0x33FC02D3,0x13800A2,0x13800A2,0x13800A2,0x13800A2,0xC7280001,0xC7280001,0xC7280001,0xAD280001,0xAD280001,0xA5240001,0x1D000A2,0x1D000A2,0x1D000A2,0xB3080001,0xB3080001,
-0xA5140000,0x6DF800A2,0x6DF800A2,0xA4DC0000,0x9A0000A4,0x1D000A2,0x1D000A2,0x1D000A2,0xB3080001,0xB3080001,0xA5140000,0x6DF800A2,0x6DF800A2,0xA4DC0000,0x9A0000A4,0x6DF800A2,0x6DF800A2,0xA4DC0000,0x9A0000A4,0x9A0000A4,0xFF200029,0xFF2C0049,0x13800A2,0xFD040004,0xD7040000,0xC3040000,0xBB080000,0xB2FC0001,0xFD100032,0xFCF00001,0x45FC00A2,0xA4DC0000,
-0x45FC00A2,0x15C00CA,0xDF4C0001,0xC3480001,0xB9480001,0xDFC00C8,0xC9280001,0xB9340001,0x89F800C8,0xB8F80000,0xAE0000C8,0xDFC00C8,0xC9280001,0xB9340001,0x89F800C8,0xB8F80000,0xAE0000C8,0x89F800C8,0xB8F80000,0xAE0000C8,0xAE0000C8,0xDFC00C8,0xC9280001,0xB9340001,0x89F800C8,0xB8F80000,0xAE0000C8,0x89F800C8,0xB8F80000,0xAE0000C8,0xAE0000C8,0x89F800C8,
-0xB8F80000,0xAE0000C8,0xAE0000C8,0xAE0000C8,0xF7400062,0x37400C8,0xF5580071,0xFD100005,0xDEFC0001,0xC8F80000,0xB9100000,0xB8D80000,0xFF2C0055,0xF8FC0002,0xBB180001,0xAE0000C8,0x69FC00C8,0x11000CA,0x11000CA,0x11000CA,0x11000CA,0x11000CA,0x11000CA,0x11000CA,0x11000CA,0x11000CA,0x11000CA,0xB9000001,0xB9000001,0xB9000001,0xB9000001,0xB9000001,
-0xB9000001,0x9CFC0001,0x9CFC0001,0x9CFC0001,0x92FC0001,0x19800C8,0x19800C8,0x19800C8,0x19800C8,0x19800C8,0x19800C8,0xA2DC0001,0xA2DC0001,0xA2DC0001,0x92E80001,0x51F800C8,0x51F800C8,0x51F800C8,0x92AC0000,0x880000C8,0xFD08004A,0x11000CA,0x11000CA,0xFD000002,0xDD000001,0xC7000001,0xC7000001,0xAF000001,0xFEF4002D,0xFAF00001,0xA6F80000,0xA2DC0001,
-0x21FC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table84[] = {
-0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x4FF80000,
-0x4FF80000,0x4FF80000,0x4FF80000,0x86000001,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x9200000,0x9200000,0x9200000,0x1940000,0x1FFC0000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,
-0x1D00000,0x6DF80000,0x6DF80000,0x6DF80000,0x9A000001,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x6DF80000,0x6DF80000,0x6DF80000,0x9A000001,0x6DF80000,0x6DF80000,0x6DF80000,0x9A000001,0x9A000001,0x14C0000,0x1380000,0x1380000,0x7680000,0x1880000,0x1A80000,0x1A80000,0xDFC0000,0x7680000,0x1880000,0x45FC0000,0x6DF80000,
-0x45FC0000,0x15C0000,0x15C0000,0x15C0000,0x15C0000,0x9FC0000,0x9FC0000,0x9FC0000,0x87FC0000,0x87FC0000,0xAC000001,0x9FC0000,0x9FC0000,0x9FC0000,0x87FC0000,0x87FC0000,0xAC000001,0x87FC0000,0x87FC0000,0xAC000001,0xAC000001,0x9FC0000,0x9FC0000,0x9FC0000,0x87FC0000,0x87FC0000,0xAC000001,0x87FC0000,0x87FC0000,0xAC000001,0xAC000001,0x87FC0000,
-0x87FC0000,0xAC000001,0xAC000001,0xAC000001,0x1940000,0x1740000,0x15C0000,0x1D80000,0x39FC0000,0x67FC0000,0x77FC0000,0x91FC0000,0x1B40000,0x9FC0000,0x67FC0000,0xAC000001,0x67FC0000,0x1840000,0x47FC0000,0xA5F80000,0xC0000001,0x47FC0000,0xA5F80000,0xC0000001,0xA5F80000,0xC0000001,0xC0000001,0x47FC0000,0xA5F80000,0xC0000001,0xA5F80000,0xC0000001,
-0xC0000001,0xA5F80000,0xC0000001,0xC0000001,0xC0000001,0x47FC0000,0xA5F80000,0xC0000001,0xA5F80000,0xC0000001,0xC0000001,0xA5F80000,0xC0000001,0xC0000001,0xC0000001,0xA5F80000,0xC0000001,0xC0000001,0xC0000001,0xC0000001,0x5E40000,0x79C0000,0x79C0000,0x6BFC0000,0x99FC0000,0xB3F80000,0xC0000001,0xC0000001,0x1BFC0000,0x7DFC0000,0xBFD00000,0xC0000001,
-0x8DFC0000,0x1480738,0xFD3802F8,0xD53802D4,0xC13802D5,0xFF240198,0xDD2400D5,0xC32C013A,0xCB240190,0xBF2400D5,0xB7240192,0xFF1002D3,0xDF1000A2,0xC71C00FF,0xCF1000D1,0xC1100002,0xB71400D7,0xC11002D4,0xBD0800FD,0xB508013B,0xAF1002D3,0x3E80734,0xE6EC02D3,0xC11002D4,0xD8E00192,0xC2F800CF,0xB7000192,0xD2C802D3,0xC0D800A3,0xB6D800D7,0xAEE802D4,0x79FC0734,
-0xC09802D4,0xB68C0192,0xAE7002D3,0xA4000734,0xFF3402E1,0xFB440590,0xFD4805F4,0xFF18004A,0xE9100001,0xCF100002,0xC3140012,0xBF100011,0xFF2402C7,0xFF080025,0xC50400A9,0xB6D800D7,0x57FC0734,0x15C02D4,0xFB4C00A4,0xCF4C00A4,0xC14800A5,0xF13800C8,0xD3380001,0xC33C0015,0xC53800C8,0xBF340026,0xB73800CA,0xDFC02D3,0xDD1400A2,0xC13000A3,0xD10800C9,0xC1100002,
-0xB91C00CA,0x89F802D3,0xC0D800A3,0xB6C800CA,0xAE0002D3,0xDFC02D3,0xDD1400A2,0xC13000A3,0xD10800C9,0xC1100002,0xB91C00CA,0x89F802D3,0xC0D800A3,0xB6C800CA,0xAE0002D3,0x89F802D3,0xC0D800A3,0xB6C800CA,0xAE0002D3,0xAE0002D3,0xFF44013A,0xF558022A,0xF5580225,0xFF20002A,0xE9100001,0xCF100002,0xC31C0002,0xC1040005,0xFF34013A,0xFF0C0012,0xC6FC00A2,0xB6C800CA,
-0x69FC02D3,0x13802D4,0x13802D4,0x13802D4,0x13802D4,0xE72400C8,0xE72400C8,0xE72400C8,0xBB2400C8,0xBB2400C8,0xAD2400C9,0xDF1000A2,0xDF1000A2,0xDF1000A2,0xC1100001,0xC1100001,0xB1140026,0xB31000A2,0xB31000A2,0xAD0C0015,0xA51000A2,0x1CC02D3,0x1CC02D3,0x1CC02D3,0xC6F000C9,0xC6F000C9,0xAF0800C9,0xC0D800A2,0xC0D800A2,0xACEC0002,0xA4F400A2,0x6BF802D3,
-0x6BF802D3,0xACB400C9,0xA49800A2,0x9A0002D3,0xFD28010A,0xFF2C0209,0x13802D4,0xFF180019,0xE5100001,0xCF100001,0xC9140006,0xBB100002,0xFF1400E5,0xFF04000E,0xC30800A2,0xACEC0002,0x43FC02D3,0x14800A4,0x14800A4,0x14800A4,0x14800A4,0xD3380000,0xD3380000,0xD3380000,0xB7380000,0xB7380000,0xAD380001,0x3E800A2,0x3E800A2,0x3E800A2,0xBD180001,0xBD180001,
-0xAD280001,0x79FC00A2,0x79FC00A2,0xACF00001,0xA40000A2,0x3E800A2,0x3E800A2,0x3E800A2,0xBD180001,0xBD180001,0xAD280001,0x79FC00A2,0x79FC00A2,0xACF00001,0xA40000A2,0x79FC00A2,0x79FC00A2,0xACF00001,0xA40000A2,0xA40000A2,0xFB340034,0xFB440048,0x14800A4,0xFF1C0008,0xE3140000,0xCD140000,0xC31C0001,0xBD0C0000,0xF928003D,0xF90C0005,0x57FC00A2,0xACF00001,
-0x57FC00A2,0x17000C8,0xEB5C0000,0xCB5C0001,0xC15C0001,0x29FC00C8,0xD3380001,0xC1480001,0x97F800C8,0xC10C0001,0xB60000CA,0x29FC00C8,0xD3380001,0xC1480001,0x97F800C8,0xC10C0001,0xB60000CA,0x97F800C8,0xC10C0001,0xB60000CA,0xB60000CA,0x29FC00C8,0xD3380001,0xC1480001,0x97F800C8,0xC10C0001,0xB60000CA,0x97F800C8,0xC10C0001,0xB60000CA,0xB60000CA,0x97F800C8,
-0xC10C0001,0xB60000CA,0xB60000CA,0xB60000CA,0xFF500064,0x18800C8,0xFF6C0071,0xFD28000D,0xE90C0001,0xD10C0000,0xC1240001,0xC0F00001,0xF9480062,0xFF100005,0xC5280000,0xB60000CA,0x7BFC00C8,0x12400C8,0x12400C8,0x12400C8,0x12400C8,0x12400C8,0x12400C8,0x12400C8,0x12400C8,0x12400C8,0x12400C8,0xC5100000,0xC5100000,0xC5100000,0xC5100000,0xC5100000,
-0xC5100000,0xA5100001,0xA5100001,0xA5100001,0x9B100001,0x3B000C8,0x3B000C8,0x3B000C8,0x3B000C8,0x3B000C8,0x3B000C8,0xACEC0001,0xACEC0001,0xACEC0001,0x9AFC0001,0x5DFC00C8,0x5DFC00C8,0x5DFC00C8,0x9AC00001,0x900000CA,0xF71C0055,0x12400C8,0x12400C8,0xF9140008,0xE9100000,0xD3100000,0xD3100000,0xB9100000,0xFD0C0032,0xFF000004,0xAD0C0001,0xACEC0001,
-0x33FC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table85[] = {
-0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x5BF80000,
-0x5BF80000,0x5BF80000,0x5BF80000,0x8E000001,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1340000,0x1340000,0x1340000,0x1AC0000,0x2FFC0000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,
-0x1E80000,0x79F80000,0x79F80000,0x79F80000,0xA2000001,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x79F80000,0x79F80000,0x79F80000,0xA2000001,0x79F80000,0x79F80000,0x79F80000,0xA2000001,0xA2000001,0x75C0000,0x1480000,0x1480000,0x37C0000,0x19C0000,0x3BC0000,0x3BC0000,0x21FC0000,0x37C0000,0x19C0000,0x55FC0000,0x79F80000,
-0x55FC0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x23FC0000,0x23FC0000,0x23FC0000,0x93FC0000,0x93FC0000,0xB4000001,0x23FC0000,0x23FC0000,0x23FC0000,0x93FC0000,0x93FC0000,0xB4000001,0x93FC0000,0x93FC0000,0xB4000001,0xB4000001,0x23FC0000,0x23FC0000,0x23FC0000,0x93FC0000,0x93FC0000,0xB4000001,0x93FC0000,0x93FC0000,0xB4000001,0xB4000001,0x93FC0000,
-0x93FC0000,0xB4000001,0xB4000001,0xB4000001,0x1A80000,0x1840000,0x16C0000,0x1F00000,0x4DFC0000,0x77FC0000,0x85FC0000,0x9DF40000,0x1C80000,0x23FC0000,0x77FC0000,0xB4000001,0x77FC0000,0x1940000,0x5FFC0000,0xB1F80000,0xC8000001,0x5FFC0000,0xB1F80000,0xC8000001,0xB1F80000,0xC8000001,0xC8000001,0x5FFC0000,0xB1F80000,0xC8000001,0xB1F80000,0xC8000001,
-0xC8000001,0xB1F80000,0xC8000001,0xC8000001,0xC8000001,0x5FFC0000,0xB1F80000,0xC8000001,0xB1F80000,0xC8000001,0xC8000001,0xB1F80000,0xC8000001,0xC8000001,0xC8000001,0xB1F80000,0xC8000001,0xC8000001,0xC8000001,0xC8000001,0x5F80000,0xFAC0000,0xFAC0000,0x7DFC0000,0xA7F80000,0xBDF80000,0xC8000001,0xC8000001,0x39FC0000,0x8FFC0000,0xC7E00000,0xC8000001,
-0x9DF80000,0x1580738,0xFF480314,0xDD4802D4,0xC94802D5,0xFD3801B8,0xE53400D5,0xCB3C013A,0xD3340190,0xC73400D5,0xBF340192,0xFF2402D8,0xE72000A2,0xCF2C00FF,0xD72000D1,0xC9200002,0xBF2400D7,0xC92002D4,0xC51800FD,0xBD18013B,0xB72002D3,0x7FC0734,0xEEFC02D3,0xC92002D4,0xE0F00192,0xCB0800CF,0xBF100192,0xDAD802D3,0xC8E800A3,0xBEE800D7,0xB6F802D4,0x85FC0734,
-0xC8A802D4,0xBE9C0192,0xB68002D3,0xAC000734,0xFF44033E,0xFF4C05D0,0xF5580625,0xFF2C0086,0xF1200001,0xD7200002,0xCB240012,0xC7200011,0xFF3402FA,0xFF1C0054,0xCD1400A9,0xBEE800D7,0x65FC0734,0x16C02D4,0xFF5C00A5,0xD75C00A4,0xC95800A5,0xF94800C8,0xDB480001,0xCB4C0015,0xCD4800C8,0xC7440026,0xBF4800CA,0x25FC02D3,0xE52400A2,0xC94000A3,0xD91800C9,0xC9200002,
-0xC12C00CA,0x95F802D3,0xC8E800A3,0xBED800CA,0xB60002D3,0x25FC02D3,0xE52400A2,0xC94000A3,0xD91800C9,0xC9200002,0xC12C00CA,0x95F802D3,0xC8E800A3,0xBED800CA,0xB60002D3,0x95F802D3,0xC8E800A3,0xBED800CA,0xB60002D3,0xB60002D3,0xFF500155,0xFD68022A,0xFD680225,0xFF340042,0xF1200001,0xD7200002,0xCB2C0002,0xC9140005,0xFF44015B,0xFF240029,0xCF0C00A2,0xBED800CA,
-0x79FC02D3,0x14802D4,0x14802D4,0x14802D4,0x14802D4,0xEF3400C8,0xEF3400C8,0xEF3400C8,0xC33400C8,0xC33400C8,0xB53400C9,0xE72000A2,0xE72000A2,0xE72000A2,0xC9200001,0xC9200001,0xB9240026,0xBB2000A2,0xBB2000A2,0xB51C0015,0xAD2000A2,0x1E402D3,0x1E402D3,0x1E402D3,0xCF0000C9,0xCF0000C9,0xB71800C9,0xC8E800A2,0xC8E800A2,0xB4FC0002,0xAD0400A2,0x77F802D3,
-0x77F802D3,0xB4C400C9,0xACA800A2,0xA20002D3,0xFD380124,0xFB44020C,0x14802D4,0xFD280035,0xED200001,0xD7200001,0xD1240006,0xC3200002,0xFB2C0109,0xFF18001A,0xCB1800A2,0xB4FC0002,0x53FC02D3,0x15800A4,0x15800A4,0x15800A4,0x15800A4,0xDB480000,0xDB480000,0xDB480000,0xBF480000,0xBF480000,0xB5480001,0x7FC00A2,0x7FC00A2,0x7FC00A2,0xC5280001,0xC5280001,
-0xB5380001,0x85FC00A2,0x85FC00A2,0xB5000001,0xAC0000A2,0x7FC00A2,0x7FC00A2,0x7FC00A2,0xC5280001,0xC5280001,0xB5380001,0x85FC00A2,0x85FC00A2,0xB5000001,0xAC0000A2,0x85FC00A2,0x85FC00A2,0xB5000001,0xAC0000A2,0xAC0000A2,0xF748003D,0xF3540055,0x15800A4,0xFD30000D,0xEB240000,0xD5240000,0xCB2C0001,0xC51C0000,0xFF340041,0xFD200008,0x65FC00A2,0xB5000001,
-0x65FC00A2,0x18000C8,0xF36C0000,0xD36C0001,0xC96C0001,0x41FC00C8,0xDB480001,0xC9580001,0xA1FC00C8,0xC91C0001,0xBE0000CA,0x41FC00C8,0xDB480001,0xC9580001,0xA1FC00C8,0xC91C0001,0xBE0000CA,0xA1FC00C8,0xC91C0001,0xBE0000CA,0xBE0000CA,0x41FC00C8,0xDB480001,0xC9580001,0xA1FC00C8,0xC91C0001,0xBE0000CA,0xA1FC00C8,0xC91C0001,0xBE0000CA,0xBE0000CA,0xA1FC00C8,
-0xC91C0001,0xBE0000CA,0xBE0000CA,0xBE0000CA,0xF7680071,0x59800C8,0xF77C0080,0xFF400012,0xF11C0001,0xD91C0000,0xC9340001,0xC9000001,0xFD580064,0xFF2C000D,0xCD380000,0xBE0000CA,0x89FC00C8,0x13400C8,0x13400C8,0x13400C8,0x13400C8,0x13400C8,0x13400C8,0x13400C8,0x13400C8,0x13400C8,0x13400C8,0xCD200000,0xCD200000,0xCD200000,0xCD200000,0xCD200000,
-0xCD200000,0xAD200001,0xAD200001,0xAD200001,0xA3200001,0x1C800C8,0x1C800C8,0x1C800C8,0x1C800C8,0x1C800C8,0x1C800C8,0xB4FC0001,0xB4FC0001,0xB4FC0001,0xA30C0001,0x69FC00C8,0x69FC00C8,0x69FC00C8,0xA2D00001,0x980000CA,0xFF2C0055,0x13400C8,0x13400C8,0xFB24000D,0xF1200000,0xDB200000,0xDB200000,0xC1200000,0xFD1C003D,0xFF140005,0xB51C0001,0xB4FC0001,
-0x41FC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table86[] = {
-0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x67F80000,
-0x67F80000,0x67F80000,0x67F80000,0x96000001,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1440000,0x1440000,0x1440000,0x1C40000,0x3FF80000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,
-0x3FC0000,0x85F80000,0x85F80000,0x85F80000,0xAA000001,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x85F80000,0x85F80000,0x85F80000,0xAA000001,0x85F80000,0x85F80000,0x85F80000,0xAA000001,0xAA000001,0xF6C0000,0x1580000,0x1580000,0x1900000,0x1B00000,0x1D40000,0x1D40000,0x33FC0000,0x1900000,0x1B00000,0x63FC0000,0x85F80000,
-0x63FC0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x9FF80000,0x9FF80000,0xBC000001,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x9FF80000,0x9FF80000,0xBC000001,0x9FF80000,0x9FF80000,0xBC000001,0xBC000001,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x9FF80000,0x9FF80000,0xBC000001,0x9FF80000,0x9FF80000,0xBC000001,0xBC000001,0x9FF80000,
-0x9FF80000,0xBC000001,0xBC000001,0xBC000001,0x5B80000,0x3940000,0x17C0000,0xDFC0000,0x61FC0000,0x85FC0000,0x93F80000,0xA7F80000,0x1DC0000,0x3BFC0000,0x85FC0000,0xBC000001,0x85FC0000,0x1A40000,0x77FC0000,0xBDF80000,0xD0000001,0x77FC0000,0xBDF80000,0xD0000001,0xBDF80000,0xD0000001,0xD0000001,0x77FC0000,0xBDF80000,0xD0000001,0xBDF80000,0xD0000001,
-0xD0000001,0xBDF80000,0xD0000001,0xD0000001,0xD0000001,0x77FC0000,0xBDF80000,0xD0000001,0xBDF80000,0xD0000001,0xD0000001,0xBDF80000,0xD0000001,0xD0000001,0xD0000001,0xBDF80000,0xD0000001,0xD0000001,0xD0000001,0xD0000001,0x23FC0000,0x1C00000,0x1C00000,0x91FC0000,0xB5F80000,0xC7F80000,0xD0000001,0xD0000001,0x57FC0000,0xA1FC0000,0xCFF00000,0xD0000001,
-0xABFC0000,0x1680738,0xFF5C0339,0xE55802D4,0xD15802D5,0xFF4801E0,0xED4400D5,0xD34C013A,0xDB440190,0xCF4400D5,0xC7440192,0xFD3802F8,0xEF3000A2,0xD73C00FF,0xDF3000D1,0xD1300002,0xC73400D7,0xD13002D4,0xCD2800FD,0xC528013B,0xBF3002D3,0x1FFC0734,0xF70C02D3,0xD13002D4,0xE9000192,0xD31800CF,0xC7200192,0xE2E802D3,0xD0F800A3,0xC6F800D7,0xBF0802D4,0x91FC0734,
-0xD0B802D4,0xC6AC0192,0xBE9002D3,0xB4000734,0xFF580386,0xFB6405D2,0xFD680625,0xFF4000D3,0xF9300001,0xDF300002,0xD3340012,0xCF300011,0xFD4C036A,0xFF300099,0xD52400A9,0xC6F800D7,0x75FC0734,0x17C02D4,0xFF6C00B4,0xDF6C00A4,0xD16800A5,0xFD5800CA,0xE3580001,0xD35C0015,0xD55800C8,0xCF540026,0xC75800CA,0x3DFC02D3,0xED3400A2,0xD15000A3,0xE12800C9,0xD1300002,
-0xC93C00CA,0xA1F802D3,0xD0F800A3,0xC6E800CA,0xBE0002D3,0x3DFC02D3,0xED3400A2,0xD15000A3,0xE12800C9,0xD1300002,0xC93C00CA,0xA1F802D3,0xD0F800A3,0xC6E800CA,0xBE0002D3,0xA1F802D3,0xD0F800A3,0xC6E800CA,0xBE0002D3,0xBE0002D3,0xFF64017A,0xF5780248,0xF77C0244,0xFF48006E,0xF9300001,0xDF300002,0xD33C0002,0xD1240005,0xFF5C016D,0xFD3C004B,0xD71C00A2,0xC6E800CA,
-0x87FC02D3,0x15802D4,0x15802D4,0x15802D4,0x15802D4,0xF74400C8,0xF74400C8,0xF74400C8,0xCB4400C8,0xCB4400C8,0xBD4400C9,0xEF3000A2,0xEF3000A2,0xEF3000A2,0xD1300001,0xD1300001,0xC1340026,0xC33000A2,0xC33000A2,0xBD2C0015,0xB53000A2,0x1FC02D3,0x1FC02D3,0x1FC02D3,0xD71000C9,0xD71000C9,0xBF2800C9,0xD0F800A2,0xD0F800A2,0xBD0C0002,0xB51400A2,0x83F802D3,
-0x83F802D3,0xBCD400C9,0xB4B800A2,0xAA0002D3,0xFD48013D,0xF3540229,0x15802D4,0xFF3C0048,0xF5300001,0xDF300001,0xD9340006,0xCB300002,0xFF3C0120,0xFD2C0035,0xD32800A2,0xBD0C0002,0x61FC02D3,0x16800A4,0x16800A4,0x16800A4,0x16800A4,0xE3580000,0xE3580000,0xE3580000,0xC7580000,0xC7580000,0xBD580001,0x1FFC00A2,0x1FFC00A2,0x1FFC00A2,0xCD380001,0xCD380001,
-0xBD480001,0x91FC00A2,0x91FC00A2,0xBD100001,0xB40000A2,0x1FFC00A2,0x1FFC00A2,0x1FFC00A2,0xCD380001,0xCD380001,0xBD480001,0x91FC00A2,0x91FC00A2,0xBD100001,0xB40000A2,0x91FC00A2,0x91FC00A2,0xBD100001,0xB40000A2,0xB40000A2,0xFF58003D,0xFB640055,0x16800A4,0xFF440012,0xF3340000,0xDD340000,0xD33C0001,0xCD2C0000,0xFD4C0048,0xFF300011,0x75FC00A2,0xBD100001,
-0x75FC00A2,0x19000C8,0xFB7C0000,0xDB7C0001,0xD17C0001,0x59FC00C8,0xE3580001,0xD1680001,0xADFC00C8,0xD12C0001,0xC60000CA,0x59FC00C8,0xE3580001,0xD1680001,0xADFC00C8,0xD12C0001,0xC60000CA,0xADFC00C8,0xD12C0001,0xC60000CA,0xC60000CA,0x59FC00C8,0xE3580001,0xD1680001,0xADFC00C8,0xD12C0001,0xC60000CA,0xADFC00C8,0xD12C0001,0xC60000CA,0xC60000CA,0xADFC00C8,
-0xD12C0001,0xC60000CA,0xC60000CA,0xC60000CA,0xFF780071,0xDA800C8,0xFF8C0080,0xFF580020,0xF92C0001,0xE12C0000,0xD1440001,0xD1100001,0xFF700071,0xFD480019,0xD5480000,0xC60000CA,0x99FC00C8,0x14400C8,0x14400C8,0x14400C8,0x14400C8,0x14400C8,0x14400C8,0x14400C8,0x14400C8,0x14400C8,0x14400C8,0xD5300000,0xD5300000,0xD5300000,0xD5300000,0xD5300000,
-0xD5300000,0xB5300001,0xB5300001,0xB5300001,0xAB300001,0x1E000C8,0x1E000C8,0x1E000C8,0x1E000C8,0x1E000C8,0x1E000C8,0xBD0C0001,0xBD0C0001,0xBD0C0001,0xAB1C0001,0x75FC00C8,0x75FC00C8,0x75FC00C8,0xAAE00001,0xA00000CA,0xF73C0064,0x14400C8,0x14400C8,0xFB340014,0xF9300000,0xE3300000,0xE3300000,0xC9300000,0xF9300048,0xF928000D,0xBD2C0001,0xBD0C0001,
-0x51FC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table87[] = {
-0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x73F80000,
-0x73F80000,0x73F80000,0x73F80000,0x9E000001,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x3540000,0x3540000,0x3540000,0x1DC0000,0x4DFC0000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,
-0x1BFC0000,0x91F80000,0x91F80000,0x91F80000,0xB2000001,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x91F80000,0x91F80000,0x91F80000,0xB2000001,0x91F80000,0x91F80000,0x91F80000,0xB2000001,0xB2000001,0x1800000,0x1680000,0x1680000,0x7A00000,0x1C40000,0x3E80000,0x3E80000,0x47FC0000,0x7A00000,0x1C40000,0x73FC0000,0x91F80000,
-0x73FC0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x53FC0000,0x53FC0000,0x53FC0000,0xABF80000,0xABF80000,0xC4000001,0x53FC0000,0x53FC0000,0x53FC0000,0xABF80000,0xABF80000,0xC4000001,0xABF80000,0xABF80000,0xC4000001,0xC4000001,0x53FC0000,0x53FC0000,0x53FC0000,0xABF80000,0xABF80000,0xC4000001,0xABF80000,0xABF80000,0xC4000001,0xC4000001,0xABF80000,
-0xABF80000,0xC4000001,0xC4000001,0xC4000001,0x1CC0000,0xBA40000,0x18C0000,0x2BFC0000,0x73FC0000,0x95FC0000,0x9FFC0000,0xB3F40000,0x1F00000,0x53FC0000,0x95FC0000,0xC4000001,0x95FC0000,0x1B40000,0x8FFC0000,0xC9F80000,0xD8000001,0x8FFC0000,0xC9F80000,0xD8000001,0xC9F80000,0xD8000001,0xD8000001,0x8FFC0000,0xC9F80000,0xD8000001,0xC9F80000,0xD8000001,
-0xD8000001,0xC9F80000,0xD8000001,0xD8000001,0xD8000001,0x8FFC0000,0xC9F80000,0xD8000001,0xC9F80000,0xD8000001,0xD8000001,0xC9F80000,0xD8000001,0xD8000001,0xD8000001,0xC9F80000,0xD8000001,0xD8000001,0xD8000001,0xD8000001,0x4BFC0000,0x1D00000,0x1D00000,0xA5FC0000,0xC1FC0000,0xD1F80000,0xD8000001,0xD8000001,0x75FC0000,0xB1FC0000,0xD9C40000,0xD8000001,
-0xBBFC0000,0x1780738,0xFF6C0378,0xED6802D4,0xD96802D5,0xFF5C0212,0xF55400D5,0xDB5C013A,0xE3540190,0xD75400D5,0xCF540192,0xFF50031B,0xF74000A2,0xDF4C00FF,0xE74000D1,0xD9400002,0xCF4400D7,0xD94002D4,0xD53800FD,0xCD38013B,0xC74002D3,0x37FC0734,0xFF1C02D3,0xD94002D4,0xF1100192,0xDB2800CF,0xCF300192,0xEAF802D3,0xD90800A3,0xCF0800D7,0xC71802D4,0x9DFC0734,
-0xD8C802D4,0xCEBC0192,0xC6A002D3,0xBC000734,0xFF6403DE,0xF3740618,0xF5780658,0xFF54012A,0xFF400006,0xE7400002,0xDB440012,0xD7400011,0xFF5C03A6,0xFF4400EA,0xDD3400A9,0xCF0800D7,0x83FC0734,0x18C02D4,0xFF8000CD,0xE77C00A4,0xD97800A5,0xFF6C00D4,0xEB680001,0xDB6C0015,0xDD6800C8,0xD7640026,0xCF6800CA,0x55FC02D3,0xF54400A2,0xD96000A3,0xE93800C9,0xD9400002,
-0xD14C00CA,0xADF802D3,0xD90800A3,0xCEF800CA,0xC60002D3,0x55FC02D3,0xF54400A2,0xD96000A3,0xE93800C9,0xD9400002,0xD14C00CA,0xADF802D3,0xD90800A3,0xCEF800CA,0xC60002D3,0xADF802D3,0xD90800A3,0xCEF800CA,0xC60002D3,0xC60002D3,0xFF780191,0xFD880248,0xFF8C0244,0xFF5C0096,0xFD440005,0xE7400002,0xDB4C0002,0xD9340005,0xFF7001A5,0xFF540071,0xDF2C00A2,0xCEF800CA,
-0x97FC02D3,0x16802D4,0x16802D4,0x16802D4,0x16802D4,0xFF5400C8,0xFF5400C8,0xFF5400C8,0xD35400C8,0xD35400C8,0xC55400C9,0xF74000A2,0xF74000A2,0xF74000A2,0xD9400001,0xD9400001,0xC9440026,0xCB4000A2,0xCB4000A2,0xC53C0015,0xBD4000A2,0x19FC02D3,0x19FC02D3,0x19FC02D3,0xDF2000C9,0xDF2000C9,0xC73800C9,0xD90800A2,0xD90800A2,0xC51C0002,0xBD2400A2,0x8FF802D3,
-0x8FF802D3,0xC4E400C9,0xBCC800A2,0xB20002D3,0xFF58015D,0xFB640229,0x16802D4,0xFF4C0065,0xFD400001,0xE7400001,0xE1440006,0xD3400002,0xFF500139,0xFF3C0054,0xDB3800A2,0xC51C0002,0x71FC02D3,0x17800A4,0x17800A4,0x17800A4,0x17800A4,0xEB680000,0xEB680000,0xEB680000,0xCF680000,0xCF680000,0xC5680001,0x37FC00A2,0x37FC00A2,0x37FC00A2,0xD5480001,0xD5480001,
-0xC5580001,0x9DFC00A2,0x9DFC00A2,0xC5200001,0xBC0000A2,0x37FC00A2,0x37FC00A2,0x37FC00A2,0xD5480001,0xD5480001,0xC5580001,0x9DFC00A2,0x9DFC00A2,0xC5200001,0xBC0000A2,0x9DFC00A2,0x9DFC00A2,0xC5200001,0xBC0000A2,0xBC0000A2,0xFB6C0048,0xF3740064,0x17800A4,0xFD580019,0xFB440000,0xE5440000,0xDB4C0001,0xD53C0000,0xF5640055,0xFF480014,0x83FC00A2,0xC5200001,
-0x83FC00A2,0x1A000C8,0xFF8C0001,0xE38C0001,0xD98C0001,0x71FC00C8,0xEB680001,0xD9780001,0xB9FC00C8,0xD93C0001,0xCE0000CA,0x71FC00C8,0xEB680001,0xD9780001,0xB9FC00C8,0xD93C0001,0xCE0000CA,0xB9FC00C8,0xD93C0001,0xCE0000CA,0xCE0000CA,0x71FC00C8,0xEB680001,0xD9780001,0xB9FC00C8,0xD93C0001,0xCE0000CA,0xB9FC00C8,0xD93C0001,0xCE0000CA,0xCE0000CA,0xB9FC00C8,
-0xD93C0001,0xCE0000CA,0xCE0000CA,0xCE0000CA,0xFF8C0080,0x1BC00C8,0xF79C0091,0xFF6C002D,0xFB480005,0xE93C0000,0xD9540001,0xD9200001,0xF7880080,0xFF600029,0xDD580000,0xCE0000CA,0xA7FC00C8,0x15400C8,0x15400C8,0x15400C8,0x15400C8,0x15400C8,0x15400C8,0x15400C8,0x15400C8,0x15400C8,0x15400C8,0xDD400000,0xDD400000,0xDD400000,0xDD400000,0xDD400000,
-0xDD400000,0xBD400001,0xBD400001,0xBD400001,0xB3400001,0x1F800C8,0x1F800C8,0x1F800C8,0x1F800C8,0x1F800C8,0x1F800C8,0xC51C0001,0xC51C0001,0xC51C0001,0xB32C0001,0x81FC00C8,0x81FC00C8,0x81FC00C8,0xB2F00001,0xA80000CA,0xFF4C0064,0x15400C8,0x15400C8,0xFD480019,0xFD400001,0xEB400000,0xEB400000,0xD1400000,0xFF3C0050,0xFD380014,0xC53C0001,0xC51C0001,
-0x5FFC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table88[] = {
-0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x3F40000,0x3F40000,0x3F40000,0x3F40000,0x3F40000,0x3F40000,0x3F40000,0x3F40000,0x3F40000,0x3F40000,0x7FFC0000,
-0x7FFC0000,0x7FFC0000,0x7FFC0000,0xA8000000,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1500001,0x1680000,0x1680000,0x1680000,0x3F40000,0x5FF80000,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,
-0x37FC0000,0x9DFC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x9DFC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x9DFC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0xBC000000,0x1940000,0x1780001,0x1780001,0x1B80000,0x3D80000,0x9FC0000,0x9FC0000,0x5DFC0000,0x1B80000,0x3D80000,0x83FC0000,0x9DFC0000,
-0x83FC0000,0x19C0001,0x19C0001,0x19C0001,0x19C0001,0x6FFC0000,0x6FFC0000,0x6FFC0000,0xB9F80000,0xB9F80000,0xCE000000,0x6FFC0000,0x6FFC0000,0x6FFC0000,0xB9F80000,0xB9F80000,0xCE000000,0xB9F80000,0xB9F80000,0xCE000000,0xCE000000,0x6FFC0000,0x6FFC0000,0x6FFC0000,0xB9F80000,0xB9F80000,0xCE000000,0xB9F80000,0xB9F80000,0xCE000000,0xCE000000,0xB9F80000,
-0xB9F80000,0xCE000000,0xCE000000,0xCE000000,0x3E00000,0x5B80000,0x19C0001,0x4DFC0000,0x8BFC0000,0xA5FC0000,0xAFFC0000,0xBFF40000,0x15FC0000,0x6FFC0000,0xA5FC0000,0xCE000000,0xA5FC0000,0x1C40001,0xABFC0000,0xD7F80000,0xE2000000,0xABFC0000,0xD7F80000,0xE2000000,0xD7F80000,0xE2000000,0xE2000000,0xABFC0000,0xD7F80000,0xE2000000,0xD7F80000,0xE2000000,
-0xE2000000,0xD7F80000,0xE2000000,0xE2000000,0xE2000000,0xABFC0000,0xD7F80000,0xE2000000,0xD7F80000,0xE2000000,0xE2000000,0xD7F80000,0xE2000000,0xE2000000,0xE2000000,0xD7F80000,0xE2000000,0xE2000000,0xE2000000,0xE2000000,0x77FC0000,0x1E40000,0x1E40000,0xBBFC0000,0xD1FC0000,0xDDF40000,0xE2000000,0xE2000000,0x97FC0000,0xC5FC0000,0xE1F40000,0xE2000000,
-0xCBFC0000,0x18C0734,0xFF8003BF,0xF57802D4,0xE37802D3,0xFF740272,0xFD6800D7,0xE76C013B,0xEB680192,0xE16400D7,0xD9640192,0xFF680361,0xFF5400A3,0xE75C00FD,0xEF5000CF,0xE3540002,0xD95800D5,0xE35002D4,0xDD4800FF,0xD550013A,0xCF5002D5,0x53FC0734,0xFF3802E3,0xE35402D4,0xFB200192,0xE33800D1,0xD9400190,0xF50802D3,0xE31800A2,0xD91C00D5,0xCF2C02D4,0xABF80734,
-0xE2D802D3,0xD8C80190,0xCEB402D4,0xC4000738,0xFF780447,0xFD880614,0xFD88065C,0xFF6C01B7,0xFF58002E,0xF1540002,0xE3580011,0xE14C0012,0xFF700413,0xFF5C016A,0xE54800A9,0xD91C00D5,0x95FC0734,0x1A002D3,0xFF9000FB,0xF18C00A2,0xE38C00A2,0xFF8000F1,0xF37C0002,0xE57C0015,0xE77800C9,0xE1740026,0xD97800C9,0x71FC02D3,0xFF5400A2,0xE37000A2,0xF34800C9,0xE3540001,
-0xD96000C8,0xB9FC02D3,0xE31400A2,0xD90800C8,0xCE0002D4,0x71FC02D3,0xFF5400A2,0xE37000A2,0xF34800C9,0xE3540001,0xD96000C8,0xB9FC02D3,0xE31400A2,0xD90800C8,0xCE0002D4,0xB9FC02D3,0xE31400A2,0xD90800C8,0xCE0002D4,0xCE0002D4,0xFD9001C4,0xF79C0269,0xF79C0266,0xFF7800D1,0xFF5C001A,0xF1540001,0xE3600002,0xE1440006,0xFF8801C3,0xFF7000B5,0xE74000A2,0xD90800C8,
-0xA7FC02D3,0x17802D3,0x17802D3,0x17802D3,0x17802D3,0xFF6800CE,0xFF6800CE,0xFF6800CE,0xDD6400CA,0xDD6400CA,0xCF6400CA,0xFF5400A3,0xFF5400A3,0xFF5400A3,0xE1540002,0xE1540002,0xD1580026,0xD35400A3,0xD35400A3,0xCD500015,0xC55000A5,0x35FC02D3,0x35FC02D3,0x35FC02D3,0xE73400C9,0xE73400C9,0xCF4C00C8,0xE11C00A2,0xE11C00A2,0xCF2C0001,0xC53800A4,0x9DF402D3,
-0x9DF402D3,0xCEF400C8,0xC4E000A4,0xBC0002D4,0xFF680189,0xF374024B,0x17802D3,0xFF600099,0xFF540009,0xEF540002,0xE9540005,0xDD500002,0xFF64016D,0xFF540079,0xE34C00A3,0xCF2C0001,0x81FC02D3,0x18C00A2,0x18C00A2,0x18C00A2,0x18C00A2,0xF17C0001,0xF17C0001,0xF17C0001,0xD77C0001,0xD77C0001,0xCF780001,0x53FC00A2,0x53FC00A2,0x53FC00A2,0xDD5C0001,0xDD5C0001,
-0xCF680000,0xABF800A2,0xABF800A2,0xCF300000,0xC40000A4,0x53FC00A2,0x53FC00A2,0x53FC00A2,0xDD5C0001,0xDD5C0001,0xCF680000,0xABF800A2,0xABF800A2,0xCF300000,0xC40000A4,0xABF800A2,0xABF800A2,0xCF300000,0xC40000A4,0xC40000A4,0xF7800055,0xFD880062,0x18C00A2,0xFB700029,0xFF580001,0xED580000,0xE55C0000,0xDD500001,0xFD740055,0xFD640020,0x95FC00A2,0xCF300000,
-0x95FC00A2,0x1B000CA,0xFFA4000D,0xED9C0001,0xE39C0001,0x8DFC00C8,0xF37C0001,0xE3880001,0xC7FC00C8,0xE34C0000,0xD80000C8,0x8DFC00C8,0xF37C0001,0xE3880001,0xC7FC00C8,0xE34C0000,0xD80000C8,0xC7FC00C8,0xE34C0000,0xD80000C8,0xD80000C8,0x8DFC00C8,0xF37C0001,0xE3880001,0xC7FC00C8,0xE34C0000,0xD80000C8,0xC7FC00C8,0xE34C0000,0xD80000C8,0xD80000C8,0xC7FC00C8,
-0xE34C0000,0xD80000C8,0xD80000C8,0xD80000C8,0xF7A40091,0xFCC00C8,0xFFAC0095,0xFF8C0048,0xFF64000D,0xF34C0000,0xE3640000,0xE32C0000,0xFF980082,0xFD80003D,0xE56C0001,0xD80000C8,0xB9FC00C8,0x16400CA,0x16400CA,0x16400CA,0x16400CA,0x16400CA,0x16400CA,0x16400CA,0x16400CA,0x16400CA,0x16400CA,0xE3540001,0xE3540001,0xE3540001,0xE3540001,0xE3540001,
-0xE3540001,0xC7500001,0xC7500001,0xC7500001,0xBD500001,0x19FC00C8,0x19FC00C8,0x19FC00C8,0x19FC00C8,0x19FC00C8,0x19FC00C8,0xCD300001,0xCD300001,0xCD300001,0xBD3C0001,0x8FF800C8,0x8FF800C8,0x8FF800C8,0xBD000000,0xB20000C8,0xF9600071,0x16400CA,0x16400CA,0xFF580022,0xFD540005,0xF1540001,0xF1540001,0xD9540001,0xFD540055,0xFF500019,0xD14C0000,0xCD300001,
-0x71FC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table89[] = {
-0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x13FC0000,0x13FC0000,0x13FC0000,0x13FC0000,0x13FC0000,0x13FC0000,0x13FC0000,0x13FC0000,0x13FC0000,0x13FC0000,0x8BFC0000,
-0x8BFC0000,0x8BFC0000,0x8BFC0000,0xB0000000,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x1600001,0x5780000,0x5780000,0x5780000,0x13FC0000,0x6DFC0000,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,
-0x4FFC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xC4000000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xC4000000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xC4000000,0xC4000000,0x1A40000,0x1880001,0x1880001,0x5C80000,0x3EC0000,0x27FC0000,0x27FC0000,0x71FC0000,0x5C80000,0x3EC0000,0x93FC0000,0xA9FC0000,
-0x93FC0000,0x1AC0001,0x1AC0001,0x1AC0001,0x1AC0001,0x87FC0000,0x87FC0000,0x87FC0000,0xC5F80000,0xC5F80000,0xD6000000,0x87FC0000,0x87FC0000,0x87FC0000,0xC5F80000,0xC5F80000,0xD6000000,0xC5F80000,0xC5F80000,0xD6000000,0xD6000000,0x87FC0000,0x87FC0000,0x87FC0000,0xC5F80000,0xC5F80000,0xD6000000,0xC5F80000,0xC5F80000,0xD6000000,0xD6000000,0xC5F80000,
-0xC5F80000,0xD6000000,0xD6000000,0xD6000000,0x1F40000,0xDC80000,0x1AC0001,0x6BFC0000,0x9DFC0000,0xB5FC0000,0xBDF80000,0xC9F80000,0x3DFC0000,0x87FC0000,0xB5FC0000,0xD6000000,0xB5FC0000,0x1D40001,0xC3FC0000,0xE1FC0000,0xEA000000,0xC3FC0000,0xE1FC0000,0xEA000000,0xE1FC0000,0xEA000000,0xEA000000,0xC3FC0000,0xE1FC0000,0xEA000000,0xE1FC0000,0xEA000000,
-0xEA000000,0xE1FC0000,0xEA000000,0xEA000000,0xEA000000,0xC3FC0000,0xE1FC0000,0xEA000000,0xE1FC0000,0xEA000000,0xEA000000,0xE1FC0000,0xEA000000,0xEA000000,0xEA000000,0xE1FC0000,0xEA000000,0xEA000000,0xEA000000,0xEA000000,0x9FFC0000,0x3F40000,0x3F40000,0xCFFC0000,0xDFF80000,0xE7F40000,0xEA000000,0xEA000000,0xB5FC0000,0xD5FC0000,0xEBC80000,0xEA000000,
-0xDBFC0000,0x19C0734,0xFF90041C,0xFD8802D4,0xEB8802D3,0xFF8002E2,0xFF7800E7,0xEF7C013B,0xF3780192,0xE97400D7,0xE1740192,0xFF7403A9,0xFF6800C6,0xEF6C00FD,0xF76000CF,0xEB640002,0xE16800D5,0xEB6002D4,0xE55800FF,0xDD60013A,0xD76002D5,0x6BFC0734,0xFF580319,0xEB6402D4,0xFF38019A,0xEB4800D1,0xE1500190,0xFD1802D3,0xEB2800A2,0xE12C00D5,0xD73C02D4,0xB7F80734,
-0xEAE802D3,0xE0D80190,0xD6C402D4,0xCC000738,0xFF8C0494,0xF598065A,0xF79C068F,0xFF800236,0xFF6C0086,0xF9640002,0xEB680011,0xE95C0012,0xFF800481,0xFF7401F7,0xED5800A9,0xE12C00D5,0xA3FC0734,0x1B002D3,0xFFA40126,0xF99C00A2,0xEB9C00A2,0xFF980119,0xFB8C0002,0xED8C0015,0xEF8800C9,0xE9840026,0xE18800C9,0x89FC02D3,0xFF7000AD,0xEB8000A2,0xFB5800C9,0xEB640001,
-0xE17000C8,0xC5FC02D3,0xEB2400A2,0xE11800C8,0xD60002D4,0x89FC02D3,0xFF7000AD,0xEB8000A2,0xFB5800C9,0xEB640001,0xE17000C8,0xC5FC02D3,0xEB2400A2,0xE11800C8,0xD60002D4,0xC5FC02D3,0xEB2400A2,0xE11800C8,0xD60002D4,0xD60002D4,0xFFA001E5,0xFFAC0269,0xFFAC0266,0xFF94010A,0xFF7C0049,0xF9640001,0xEB700002,0xE9540006,0xFF9801E6,0xFF8400E2,0xEF5000A2,0xE11800C8,
-0xB7FC02D3,0x18802D3,0x18802D3,0x18802D3,0x18802D3,0xFF7800E3,0xFF7800E3,0xFF7800E3,0xE57400CA,0xE57400CA,0xD77400CA,0xFF6800AD,0xFF6800AD,0xFF6800AD,0xE9640002,0xE9640002,0xD9680026,0xDB6400A3,0xDB6400A3,0xD5600015,0xCD6000A5,0x4DFC02D3,0x4DFC02D3,0x4DFC02D3,0xEF4400C9,0xEF4400C9,0xD75C00C8,0xE92C00A2,0xE92C00A2,0xD73C0001,0xCD4800A4,0xA7FC02D3,
-0xA7FC02D3,0xD70400C8,0xCCF000A4,0xC40002D4,0xFD8001A6,0xFB84024B,0x18802D3,0xFF7000CA,0xFF6C0022,0xF7640002,0xF1640005,0xE5600002,0xFF78018A,0xFF6800A8,0xEB5C00A3,0xD73C0001,0x91FC02D3,0x19C00A2,0x19C00A2,0x19C00A2,0x19C00A2,0xF98C0001,0xF98C0001,0xF98C0001,0xDF8C0001,0xDF8C0001,0xD7880001,0x6BFC00A2,0x6BFC00A2,0x6BFC00A2,0xE56C0001,0xE56C0001,
-0xD7780000,0xB7F800A2,0xB7F800A2,0xD7400000,0xCC0000A4,0x6BFC00A2,0x6BFC00A2,0x6BFC00A2,0xE56C0001,0xE56C0001,0xD7780000,0xB7F800A2,0xB7F800A2,0xD7400000,0xCC0000A4,0xB7F800A2,0xB7F800A2,0xD7400000,0xCC0000A4,0xCC0000A4,0xFF900055,0xF5980071,0x19C00A2,0xFD840032,0xFF700005,0xF5680000,0xED6C0000,0xE5600001,0xFD880062,0xFF74002D,0xA3FC00A2,0xD7400000,
-0xA3FC00A2,0x1C000CA,0xFFB40022,0xF5AC0001,0xEBAC0001,0xA5FC00C8,0xFB8C0001,0xEB980001,0xD3FC00C8,0xEB5C0000,0xE00000C8,0xA5FC00C8,0xFB8C0001,0xEB980001,0xD3FC00C8,0xEB5C0000,0xE00000C8,0xD3FC00C8,0xEB5C0000,0xE00000C8,0xE00000C8,0xA5FC00C8,0xFB8C0001,0xEB980001,0xD3FC00C8,0xEB5C0000,0xE00000C8,0xD3FC00C8,0xEB5C0000,0xE00000C8,0xE00000C8,0xD3FC00C8,
-0xEB5C0000,0xE00000C8,0xE00000C8,0xE00000C8,0xFFB40091,0x1E000C8,0xF9C000A2,0xFFA00059,0xFF7C0025,0xFB5C0000,0xEB740000,0xEB3C0000,0xFFAC0095,0xFF940050,0xED7C0001,0xE00000C8,0xC7FC00C8,0x17400CA,0x17400CA,0x17400CA,0x17400CA,0x17400CA,0x17400CA,0x17400CA,0x17400CA,0x17400CA,0x17400CA,0xEB640001,0xEB640001,0xEB640001,0xEB640001,0xEB640001,
-0xEB640001,0xCF600001,0xCF600001,0xCF600001,0xC5600001,0x31FC00C8,0x31FC00C8,0x31FC00C8,0x31FC00C8,0x31FC00C8,0x31FC00C8,0xD5400001,0xD5400001,0xD5400001,0xC54C0001,0x9BF800C8,0x9BF800C8,0x9BF800C8,0xC5100000,0xBA0000C8,0xFF6C007D,0x17400CA,0x17400CA,0xFF68002D,0xFF64000A,0xF9640001,0xF9640001,0xE1640001,0xF9680062,0xFD600029,0xD95C0000,0xD5400001,
-0x7FFC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table90[] = {
-0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x97FC0000,
-0x97FC0000,0x97FC0000,0x97FC0000,0xB8000000,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0xD880000,0xD880000,0xD880000,0x2BFC0000,0x7DF80000,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,
-0x69FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xCC000000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xCC000000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xCC000000,0xCC000000,0x3B40000,0x1980001,0x1980001,0x1DC0000,0xBFC0000,0x45FC0000,0x45FC0000,0x85FC0000,0x1DC0000,0xBFC0000,0xA1FC0000,0xB5FC0000,
-0xA1FC0000,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x9FFC0000,0x9FFC0000,0x9FFC0000,0xD1F80000,0xD1F80000,0xDE000000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0xD1F80000,0xD1F80000,0xDE000000,0xD1F80000,0xD1F80000,0xDE000000,0xDE000000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0xD1F80000,0xD1F80000,0xDE000000,0xD1F80000,0xD1F80000,0xDE000000,0xDE000000,0xD1F80000,
-0xD1F80000,0xDE000000,0xDE000000,0xDE000000,0x1FFC0000,0x1DC0000,0x1BC0001,0x89FC0000,0xB1FC0000,0xC3FC0000,0xC9FC0000,0xD5F40000,0x63FC0000,0x9FFC0000,0xC3FC0000,0xDE000000,0xC3FC0000,0x1E40001,0xDBFC0000,0xEDFC0000,0xF2000000,0xDBFC0000,0xEDFC0000,0xF2000000,0xEDFC0000,0xF2000000,0xF2000000,0xDBFC0000,0xEDFC0000,0xF2000000,0xEDFC0000,0xF2000000,
-0xF2000000,0xEDFC0000,0xF2000000,0xF2000000,0xF2000000,0xDBFC0000,0xEDFC0000,0xF2000000,0xEDFC0000,0xF2000000,0xF2000000,0xEDFC0000,0xF2000000,0xF2000000,0xF2000000,0xEDFC0000,0xF2000000,0xF2000000,0xF2000000,0xF2000000,0xC7FC0000,0x47FC0000,0x47FC0000,0xE3FC0000,0xEBFC0000,0xF1F40000,0xF2000000,0xF2000000,0xD3FC0000,0xE7FC0000,0xF3D80000,0xF2000000,
-0xE9FC0000,0x1AC0734,0xFFA40477,0xFF9C02EB,0xF39802D3,0xFF980352,0xFF8C012F,0xF78C013B,0xFB880192,0xF18400D7,0xE9840192,0xFF8C0401,0xFF7C011E,0xF77C00FD,0xFF7000CF,0xF3740002,0xE97800D5,0xF37002D4,0xED6800FF,0xE570013A,0xDF7002D5,0x83FC0734,0xFF700361,0xF37402D4,0xFF5801E2,0xF35800D1,0xE9600190,0xFF3802DD,0xF33800A2,0xE93C00D5,0xDF4C02D4,0xC3F80734,
-0xF2F802D3,0xE8E80190,0xDED402D4,0xD4000738,0xFFA004E6,0xFDA8065A,0xFFAC068F,0xFF9402CB,0xFF84010B,0xFF740006,0xF3780011,0xF16C0012,0xFF9804CA,0xFF84028B,0xF56800A9,0xE93C00D5,0xB3FC0734,0x1C002D3,0xFFB4016B,0xFFAC00A3,0xF3AC00A2,0xFFA8015B,0xFF9C0012,0xF59C0015,0xF79800C9,0xF1940026,0xE99800C9,0xA3FC02D3,0xFF8800D5,0xF39000A2,0xFF7000CE,0xF3740001,
-0xE98000C8,0xD1FC02D3,0xF33400A2,0xE92800C8,0xDE0002D4,0xA3FC02D3,0xFF8800D5,0xF39000A2,0xFF7000CE,0xF3740001,0xE98000C8,0xD1FC02D3,0xF33400A2,0xE92800C8,0xDE0002D4,0xD1FC02D3,0xF33400A2,0xE92800C8,0xDE0002D4,0xDE0002D4,0xFFB40202,0xF7BC028B,0xF7BC028B,0xFFA4015B,0xFF900089,0xFF740005,0xF3800002,0xF1640006,0xFDB00222,0xFF980136,0xF76000A2,0xE92800C8,
-0xC5FC02D3,0x19802D3,0x19802D3,0x19802D3,0x19802D3,0xFF8C00FE,0xFF8C00FE,0xFF8C00FE,0xED8400CA,0xED8400CA,0xDF8400CA,0xFF7800CB,0xFF7800CB,0xFF7800CB,0xF1740002,0xF1740002,0xE1780026,0xE37400A3,0xE37400A3,0xDD700015,0xD57000A5,0x65FC02D3,0x65FC02D3,0x65FC02D3,0xF75400C9,0xF75400C9,0xDF6C00C8,0xF13C00A2,0xF13C00A2,0xDF4C0001,0xD55800A4,0xB3FC02D3,
-0xB3FC02D3,0xDF1400C8,0xD50000A4,0xCC0002D4,0xFF9001C6,0xF598026A,0x19802D3,0xFF8800F3,0xFF80004A,0xFF740002,0xF9740005,0xED700002,0xFD8801C3,0xFF8000DD,0xF36C00A3,0xDF4C0001,0x9FFC02D3,0x1AC00A2,0x1AC00A2,0x1AC00A2,0x1AC00A2,0xFF9C0002,0xFF9C0002,0xFF9C0002,0xE79C0001,0xE79C0001,0xDF980001,0x83FC00A2,0x83FC00A2,0x83FC00A2,0xED7C0001,0xED7C0001,
-0xDF880000,0xC3F800A2,0xC3F800A2,0xDF500000,0xD40000A4,0x83FC00A2,0x83FC00A2,0x83FC00A2,0xED7C0001,0xED7C0001,0xDF880000,0xC3F800A2,0xC3F800A2,0xDF500000,0xD40000A4,0xC3F800A2,0xC3F800A2,0xDF500000,0xD40000A4,0xD40000A4,0xFFA00064,0xFDA80071,0x1AC00A2,0xFF98003D,0xFF840011,0xFD780000,0xF57C0000,0xED700001,0xF5A00071,0xFB90003D,0xB3FC00A2,0xDF500000,
-0xB3FC00A2,0x1D000CA,0xFFC4003A,0xFDBC0001,0xF3BC0001,0xBDFC00C8,0xFFA00009,0xF3A80001,0xDFF800C8,0xF36C0000,0xE80000C8,0xBDFC00C8,0xFFA00009,0xF3A80001,0xDFF800C8,0xF36C0000,0xE80000C8,0xDFF800C8,0xF36C0000,0xE80000C8,0xE80000C8,0xBDFC00C8,0xFFA00009,0xF3A80001,0xDFF800C8,0xF36C0000,0xE80000C8,0xDFF800C8,0xF36C0000,0xE80000C8,0xE80000C8,0xDFF800C8,
-0xF36C0000,0xE80000C8,0xE80000C8,0xE80000C8,0xFBC800A4,0x1F000C8,0xFFCC00AA,0xFDBC0071,0xFFA4003D,0xFF740004,0xF3840000,0xF34C0000,0xF9C800A2,0xFBB80071,0xF58C0001,0xE80000C8,0xD7FC00C8,0x18400CA,0x18400CA,0x18400CA,0x18400CA,0x18400CA,0x18400CA,0x18400CA,0x18400CA,0x18400CA,0x18400CA,0xF3740001,0xF3740001,0xF3740001,0xF3740001,0xF3740001,
-0xF3740001,0xD7700001,0xD7700001,0xD7700001,0xCD700001,0x49FC00C8,0x49FC00C8,0x49FC00C8,0x49FC00C8,0x49FC00C8,0x49FC00C8,0xDD500001,0xDD500001,0xDD500001,0xCD5C0001,0xA7F800C8,0xA7F800C8,0xA7F800C8,0xCD200000,0xC20000C8,0xF9800082,0x18400CA,0x18400CA,0xFB7C003D,0xFF780012,0xFD740002,0xFD740002,0xE9740001,0xFF74006A,0xFD740032,0xE16C0000,0xDD500001,
-0x8FFC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table91[] = {
-0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0xA3FC0000,
-0xA3FC0000,0xA3FC0000,0xA3FC0000,0xC0000000,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x19C0000,0x19C0000,0x19C0000,0x43FC0000,0x8BFC0000,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,
-0x81FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xD4000000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xD4000000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xD4000000,0xD4000000,0xBC40000,0x1A80001,0x1A80001,0x1F00000,0x33FC0000,0x63FC0000,0x63FC0000,0x99FC0000,0x1F00000,0x33FC0000,0xB1FC0000,0xC1FC0000,
-0xB1FC0000,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xDDF40000,0xDDF40000,0xE6000000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xDDF40000,0xDDF40000,0xE6000000,0xDDF40000,0xDDF40000,0xE6000000,0xE6000000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xDDF40000,0xDDF40000,0xE6000000,0xDDF40000,0xDDF40000,0xE6000000,0xE6000000,0xDDF40000,
-0xDDF40000,0xE6000000,0xE6000000,0xE6000000,0x57FC0000,0x1EC0000,0x1CC0001,0xA7FC0000,0xC5FC0000,0xD3FC0000,0xD7FC0000,0xDFF80000,0x8BFC0000,0xB7FC0000,0xD3FC0000,0xE6000000,0xD3FC0000,0x1F40001,0xF5FC0000,0xF9FC0000,0xFA000000,0xF5FC0000,0xF9FC0000,0xFA000000,0xF9FC0000,0xFA000000,0xFA000000,0xF5FC0000,0xF9FC0000,0xFA000000,0xF9FC0000,0xFA000000,
-0xFA000000,0xF9FC0000,0xFA000000,0xFA000000,0xFA000000,0xF5FC0000,0xF9FC0000,0xFA000000,0xF9FC0000,0xFA000000,0xFA000000,0xF9FC0000,0xFA000000,0xFA000000,0xFA000000,0xF9FC0000,0xFA000000,0xFA000000,0xFA000000,0xFA000000,0xEDFC0000,0xC7FC0000,0xC7FC0000,0xF7FC0000,0xF9FC0000,0xFBF40000,0xFA000000,0xFA000000,0xF1FC0000,0xF7FC0000,0xFBE80000,0xFA000000,
-0xF9FC0000,0x1BC0734,0xFFB004DF,0xFFAC032C,0xFBA802D3,0xFFA403F2,0xFFA001B3,0xFF9C013B,0xFF9401A4,0xF99400D7,0xF1940192,0xFFA40479,0xFF9401AE,0xFF8C00FD,0xFF880107,0xFB840002,0xF18800D5,0xFB8002D4,0xF57800FF,0xED80013A,0xE78002D5,0x9BFC0734,0xFF8803C9,0xFB8402D4,0xFF700252,0xFB6800D1,0xF1700190,0xFF58031F,0xFB4800A2,0xF14C00D5,0xE75C02D4,0xCFF80734,
-0xFB0802D3,0xF0F80190,0xE6E402D4,0xDC000738,0xFFB40553,0xF5B806A4,0xF7BC06C4,0xFFA4038C,0xFF9801BF,0xFF88005A,0xFB880011,0xF97C0012,0xFDB00553,0xFF98033A,0xFD7800A9,0xF14C00D5,0xC1FC0734,0x1D002D3,0xFFC401A3,0xFFC000CE,0xFBBC00A2,0xFFBC0199,0xFFB4005A,0xFDAC0015,0xFFA800C9,0xF9A40026,0xF1A800C9,0xBBFC02D3,0xFFA0011D,0xFBA000A2,0xFF8800FE,0xFB840001,
-0xF19000C8,0xDDFC02D3,0xFB4400A2,0xF13800C8,0xE60002D4,0xBBFC02D3,0xFFA0011D,0xFBA000A2,0xFF8800FE,0xFB840001,0xF19000C8,0xDDFC02D3,0xFB4400A2,0xF13800C8,0xE60002D4,0xDDFC02D3,0xFB4400A2,0xF13800C8,0xE60002D4,0xE60002D4,0xFBC80244,0xFFCC028B,0xFFCC028B,0xFFC001A6,0xFFA800ED,0xFF900039,0xFB900002,0xF9740006,0xFFC40243,0xFFB0019E,0xFF7000A2,0xF13800C8,
-0xD5FC02D3,0x1A802D3,0x1A802D3,0x1A802D3,0x1A802D3,0xFF9C012B,0xFF9C012B,0xFF9C012B,0xF59400CA,0xF59400CA,0xE79400CA,0xFF8C00ED,0xFF8C00ED,0xFF8C00ED,0xF9840002,0xF9840002,0xE9880026,0xEB8400A3,0xEB8400A3,0xE5800015,0xDD8000A5,0x7DFC02D3,0x7DFC02D3,0x7DFC02D3,0xFF6400C9,0xFF6400C9,0xE77C00C8,0xF94C00A2,0xF94C00A2,0xE75C0001,0xDD6800A4,0xBFFC02D3,
-0xBFFC02D3,0xE72400C8,0xDD1000A4,0xD40002D4,0xFFA001E5,0xFDA8026A,0x1A802D3,0xFF980126,0xFF940082,0xFF88001A,0xFF88000A,0xF5800002,0xFD9C01E1,0xFF900111,0xFB7C00A3,0xE75C0001,0xAFFC02D3,0x1BC00A2,0x1BC00A2,0x1BC00A2,0x1BC00A2,0xFFB0000D,0xFFB0000D,0xFFB0000D,0xEFAC0001,0xEFAC0001,0xE7A80001,0x9BFC00A2,0x9BFC00A2,0x9BFC00A2,0xF58C0001,0xF58C0001,
-0xE7980000,0xCFF800A2,0xCFF800A2,0xE7600000,0xDC0000A4,0x9BFC00A2,0x9BFC00A2,0x9BFC00A2,0xF58C0001,0xF58C0001,0xE7980000,0xCFF800A2,0xCFF800A2,0xE7600000,0xDC0000A4,0xCFF800A2,0xCFF800A2,0xE7600000,0xDC0000A4,0xDC0000A4,0xFBB40071,0xF5B80082,0x1BC00A2,0xFBAC0055,0xFF9C0022,0xFF900008,0xFD8C0000,0xF5800001,0xFDB00071,0xFFA40048,0xC1FC00A2,0xE7600000,
-0xC1FC00A2,0x1E000CA,0xFFDC0062,0xFFCC0011,0xFBCC0001,0xD5FC00C8,0xFFC0002D,0xFBB80001,0xEBF800C8,0xFB7C0000,0xF00000C8,0xD5FC00C8,0xFFC0002D,0xFBB80001,0xEBF800C8,0xFB7C0000,0xF00000C8,0xEBF800C8,0xFB7C0000,0xF00000C8,0xF00000C8,0xD5FC00C8,0xFFC0002D,0xFBB80001,0xEBF800C8,0xFB7C0000,0xF00000C8,0xEBF800C8,0xFB7C0000,0xF00000C8,0xF00000C8,0xEBF800C8,
-0xFB7C0000,0xF00000C8,0xF00000C8,0xF00000C8,0xF3E000B5,0x27FC00C8,0xF9E000B5,0xFDD40091,0xFFBC0061,0xFFA40022,0xFB940000,0xFB5C0000,0xFDD800A4,0xFFCC0082,0xFD9C0001,0xF00000C8,0xE5FC00C8,0x19400CA,0x19400CA,0x19400CA,0x19400CA,0x19400CA,0x19400CA,0x19400CA,0x19400CA,0x19400CA,0x19400CA,0xFB840001,0xFB840001,0xFB840001,0xFB840001,0xFB840001,
-0xFB840001,0xDF800001,0xDF800001,0xDF800001,0xD5800001,0x63FC00C8,0x63FC00C8,0x63FC00C8,0x63FC00C8,0x63FC00C8,0x63FC00C8,0xE5600001,0xE5600001,0xE5600001,0xD56C0001,0xB3F800C8,0xB3F800C8,0xB3F800C8,0xD5300000,0xCA0000C8,0xF3940091,0x19400CA,0x19400CA,0xFD8C004A,0xFD880022,0xFD84000A,0xFD84000A,0xF1840001,0xFD8C0071,0xF9880048,0xE97C0000,0xE5600001,
-0x9FF800C8,};
-static const uint32_t g_etc1_to_bc7_m6_table92[] = {
-0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x5FFC0000,0x5FFC0000,0x5FFC0000,0x5FFC0000,0x5FFC0000,0x5FFC0000,0x5FFC0000,0x5FFC0000,0x5FFC0000,0x5FFC0000,0xB1F80000,
-0xB1F80000,0xB1F80000,0xB1F80000,0xC8000001,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0x1940000,0xFAC0000,0xFAC0000,0xFAC0000,0x5FFC0000,0x9DF80000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,
-0x9BFC0000,0xCFF80000,0xCFF80000,0xCFF80000,0xDC000001,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0xCFF80000,0xCFF80000,0xCFF80000,0xDC000001,0xCFF80000,0xCFF80000,0xCFF80000,0xDC000001,0xDC000001,0x5D80000,0x1BC0000,0x1BC0000,0x17FC0000,0x5FFC0000,0x85FC0000,0x85FC0000,0xAFFC0000,0x17FC0000,0x5FFC0000,0xC1FC0000,0xCFF80000,
-0xC1FC0000,0x1E00000,0x1E00000,0x1E00000,0x1E00000,0xD3FC0000,0xD3FC0000,0xD3FC0000,0xE9FC0000,0xE9FC0000,0xEE000001,0xD3FC0000,0xD3FC0000,0xD3FC0000,0xE9FC0000,0xE9FC0000,0xEE000001,0xE9FC0000,0xE9FC0000,0xEE000001,0xEE000001,0xD3FC0000,0xD3FC0000,0xD3FC0000,0xE9FC0000,0xE9FC0000,0xEE000001,0xE9FC0000,0xE9FC0000,0xEE000001,0xEE000001,0xE9FC0000,
-0xE9FC0000,0xEE000001,0xEE000001,0xEE000001,0x97FC0000,0x17FC0000,0x1E00000,0xC9FC0000,0xDBFC0000,0xE3FC0000,0xE7F80000,0xEBF80000,0xB7FC0000,0xD3FC0000,0xE3FC0000,0xEE000001,0xE3FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1CC0625,0xFFC4047D,0xFFC0034C,0xFFBC02D4,0xFFBC03A5,0xFFB40204,0xFFB00161,0xFFAC017D,0xFFA800C9,0xF7A80139,0xFFB00412,0xFFAC01FB,0xFFA4012A,0xFFA00106,0xFF980009,0xF9980082,0xFF940225,0xFB9000C8,0xF59000C1,0xEF940222,0xB5FC0625,0xFFA003BC,0xFF9802D3,0xFF94024F,0xFF8400E9,0xF784013B,0xFF7C02BE,0xFF6400A5,0xF7640076,0xEF700222,0xDBF80625,
-0xFF2C02D3,0xF7180139,0xEEFC0222,0xE4000627,0xFFC404D9,0xFDC8059D,0xFFCC05C5,0xFFB40375,0xFFA801FF,0xFFA400B5,0xFF9C0032,0xFF900004,0xFFBC04B6,0xFFB00336,0xFF9000B4,0xF7640076,0xD1FC0625,0x1DC0225,0xFFD40178,0xFFCC00E4,0xFFCC00A4,0xFFD00145,0xFFC8007E,0xFFC40020,0xFFC00081,0xFDB8000C,0xF7BC0071,0xCFFC0222,0xFFC00118,0xFFB800A2,0xFFAC00C6,0xFF9C0001,
-0xF7A40071,0xE7FC0222,0xFF6C00A2,0xF7540071,0xEE000222,0xCFFC0222,0xFFC00118,0xFFB800A2,0xFFAC00C6,0xFF9C0001,0xF7A40071,0xE7FC0222,0xFF6C00A2,0xF7540071,0xEE000222,0xE7FC0222,0xFF6C00A2,0xF7540071,0xEE000222,0xEE000222,0xFFD801C3,0xF7DC0201,0xF7DC0204,0xFDD00171,0xFFC000F2,0xFFAC0059,0xFFA80005,0xFF900000,0xFDD801C5,0xFFC80146,0xFF9800AB,0xF7540071,
-0xE1FC0222,0x1BC02D4,0x1BC02D4,0x1BC02D4,0x1BC02D4,0xFFB00161,0xFFB00161,0xFFB00161,0xFDA800C8,0xFDA800C8,0xEFA800C9,0xFFA4012A,0xFFA4012A,0xFFA4012A,0xFF980009,0xFF980009,0xF3980026,0xF59400A2,0xF59400A2,0xEF900015,0xE79400A2,0x99FC02D3,0x99FC02D3,0x99FC02D3,0xFF8400E9,0xFF8400E9,0xF18C00C9,0xFF6400A5,0xFF6400A5,0xEF700002,0xE77800A2,0xCDFC02D3,
-0xCDFC02D3,0xEF3800C9,0xE71C00A2,0xDC0002D3,0xFBB40225,0xF5B8028C,0x1BC02D4,0xFFAC0175,0xFFA400D9,0xFF9C0059,0xFF9C0032,0xFD940002,0xFDB00201,0xFFA40163,0xFF9000AB,0xEF700002,0xBFFC02D3,0x1CC00A4,0x1CC00A4,0x1CC00A4,0x1CC00A4,0xFFC40020,0xFFC40020,0xFFC40020,0xF9BC0000,0xF9BC0000,0xEFBC0001,0xB7FC00A2,0xB7FC00A2,0xB7FC00A2,0xFF9C0001,0xFF9C0001,
-0xEFAC0001,0xDDF400A2,0xDDF400A2,0xEF740001,0xE60000A2,0xB7FC00A2,0xB7FC00A2,0xB7FC00A2,0xFF9C0001,0xFF9C0001,0xEFAC0001,0xDDF400A2,0xDDF400A2,0xEF740001,0xE60000A2,0xDDF400A2,0xDDF400A2,0xEF740001,0xE60000A2,0xE60000A2,0xFDC80080,0xFFCC0080,0x1CC00A4,0xFDC00064,0xFDBC003D,0xFFAC0019,0xFFA80005,0xFF900000,0xFFC40080,0xFBC00062,0xD3FC00A2,0xEF740001,
-0xD3FC00A2,0x1F00071,0xFFE80041,0xFFE40014,0xFFE00000,0xE9FC0071,0xFFD80028,0xFFD00000,0xF3FC0071,0xFFA00000,0xF6000071,0xE9FC0071,0xFFD80028,0xFFD00000,0xF3FC0071,0xFFA00000,0xF6000071,0xF3FC0071,0xFFA00000,0xF6000071,0xF6000071,0xE9FC0071,0xFFD80028,0xFFD00000,0xF3FC0071,0xFFA00000,0xF6000071,0xF3FC0071,0xFFA00000,0xF6000071,0xF6000071,0xF3FC0071,
-0xFFA00000,0xF6000071,0xF6000071,0xF6000071,0xFFEC0062,0x87FC0071,0xFFEC0064,0xFDE80055,0xFDE40048,0xFFC8001D,0xFFB40000,0xFF8C0000,0xFDEC0062,0xFFE40055,0xFFBC0004,0xF6000071,0xF1FC0071,0x1A800C8,0x1A800C8,0x1A800C8,0x1A800C8,0x1A800C8,0x1A800C8,0x1A800C8,0x1A800C8,0x1A800C8,0x1A800C8,0xFF980005,0xFF980005,0xFF980005,0xFF980005,0xFF980005,
-0xFF980005,0xE7940001,0xE7940001,0xE7940001,0xDD940001,0x7DFC00C8,0x7DFC00C8,0x7DFC00C8,0x7DFC00C8,0x7DFC00C8,0x7DFC00C8,0xEF700001,0xEF700001,0xEF700001,0xDD800001,0xBFFC00C8,0xBFFC00C8,0xBFFC00C8,0xDD440001,0xD20000CA,0xFBA40091,0x1A800C8,0x1A800C8,0xFFA00055,0xFD9C0034,0xFF980014,0xFF980014,0xFB940000,0xFD9C0082,0xFD9C0055,0xEF900001,0xEF700001,
-0xAFFC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table93[] = {
-0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x77FC0000,0x77FC0000,0x77FC0000,0x77FC0000,0x77FC0000,0x77FC0000,0x77FC0000,0x77FC0000,0x77FC0000,0x77FC0000,0xBDF80000,
-0xBDF80000,0xBDF80000,0xBDF80000,0xD0000001,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1C00000,0x1C00000,0x1C00000,0x77FC0000,0xABFC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,
-0xB5FC0000,0xDBF80000,0xDBF80000,0xDBF80000,0xE4000001,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xDBF80000,0xDBF80000,0xDBF80000,0xE4000001,0xDBF80000,0xDBF80000,0xDBF80000,0xE4000001,0xE4000001,0xDE80000,0x1CC0000,0x1CC0000,0x51FC0000,0x87FC0000,0xA3FC0000,0xA3FC0000,0xC3FC0000,0x51FC0000,0x87FC0000,0xD1FC0000,0xDBF80000,
-0xD1FC0000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0xEBFC0000,0xEBFC0000,0xEBFC0000,0xF5FC0000,0xF5FC0000,0xF6000001,0xEBFC0000,0xEBFC0000,0xEBFC0000,0xF5FC0000,0xF5FC0000,0xF6000001,0xF5FC0000,0xF5FC0000,0xF6000001,0xF6000001,0xEBFC0000,0xEBFC0000,0xEBFC0000,0xF5FC0000,0xF5FC0000,0xF6000001,0xF5FC0000,0xF5FC0000,0xF6000001,0xF6000001,0xF5FC0000,
-0xF5FC0000,0xF6000001,0xF6000001,0xF6000001,0xD1FC0000,0x97FC0000,0x1F00000,0xE7FC0000,0xEFFC0000,0xF3FC0000,0xF5F80000,0xF7F40000,0xDFFC0000,0xEBFC0000,0xF3FC0000,0xF6000001,0xF3FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1D804C1,0xFFD003C9,0xFFCC0314,0xFFCC02D4,0xFFC80305,0xFFC40204,0xFFC401A0,0xFFB80151,0xFFB800D8,0xFBB800E1,0xFFC4031D,0xFFBC01F3,0xFFBC017A,0xFFAC00E6,0xFFAC003D,0xFBA80036,0xFFAC016D,0xFFA400A4,0xF9A40049,0xF5A4014E,0xC7FC04C1,0xFFB80354,0xFFB002D3,0xFFAC01F7,0xFFA0011A,0xFB9800E3,0xFF940216,0xFF8800CD,0xFB78001A,0xF580014F,0xE3FC04C1,
-0xFF6002D3,0xFB3800E1,0xF514014E,0xEA0004C3,0xFFD003DA,0xF5D80485,0xF5D8049C,0xFFC402E5,0xFFBC01E3,0xFFB800E7,0xFFB40084,0xFFA80015,0xFFD003C4,0xFFC402B9,0xFFA800E4,0xFB78001A,0xDDF804C1,0x1E8014D,0xFDE40105,0xFFE000BD,0xFFDC00A4,0xFFDC00C9,0xFFD8006C,0xFFD40041,0xFFCC0041,0xFFCC0001,0xFBCC0019,0xDFFC014D,0xFFD800D8,0xFFCC00A4,0xFFC0007D,0xFFB80011,
-0xFBB80019,0xEFFC014D,0xFF9C00A2,0xFB740019,0xF400014E,0xDFFC014D,0xFFD800D8,0xFFCC00A4,0xFFC0007D,0xFFB80011,0xFBB80019,0xEFFC014D,0xFF9C00A2,0xFB740019,0xF400014E,0xEFFC014D,0xFF9C00A2,0xFB740019,0xF400014E,0xF400014E,0xFFE4011D,0xFDE80131,0xFDE80138,0xFFDC00E1,0xFFD400AA,0xFFC80056,0xFFBC0025,0xFFB0000D,0xFFE00122,0xFFDC00DA,0xFFB800A6,0xFB740019,
-0xEBFC014D,0x1CC02D4,0x1CC02D4,0x1CC02D4,0x1CC02D4,0xFFC401A0,0xFFC401A0,0xFFC401A0,0xFFB800D8,0xFFB800D8,0xF7B800C9,0xFFBC017A,0xFFBC017A,0xFFBC017A,0xFFAC003D,0xFFAC003D,0xFBA80026,0xFDA400A2,0xFDA400A2,0xF7A00015,0xEFA400A2,0xB1FC02D3,0xB1FC02D3,0xB1FC02D3,0xFFA0011A,0xFFA0011A,0xF99C00C9,0xFF8800CD,0xFF8800CD,0xF7800002,0xEF8800A2,0xD9FC02D3,
-0xD9FC02D3,0xF74800C9,0xEF2C00A2,0xE40002D3,0xFDC80244,0xFDC8028C,0x1CC02D4,0xFFBC01BA,0xFFB40131,0xFFB400A8,0xFFB40084,0xFFA80015,0xFFBC0236,0xFFBC01A6,0xFFA800DB,0xF7800002,0xCFFC02D3,0x1DC00A4,0x1DC00A4,0x1DC00A4,0x1DC00A4,0xFFD40041,0xFFD40041,0xFFD40041,0xFFCC0001,0xFFCC0001,0xF7CC0001,0xCFFC00A2,0xCFFC00A2,0xCFFC00A2,0xFFB80011,0xFFB80011,
-0xF7BC0001,0xE7FC00A2,0xE7FC00A2,0xF7840001,0xEE0000A2,0xCFFC00A2,0xCFFC00A2,0xCFFC00A2,0xFFB80011,0xFFB80011,0xF7BC0001,0xE7FC00A2,0xE7FC00A2,0xF7840001,0xEE0000A2,0xE7FC00A2,0xE7FC00A2,0xF7840001,0xEE0000A2,0xEE0000A2,0xFFD80082,0xF7DC0091,0x1DC00A4,0xFDD80071,0xFDD00055,0xFFC8003D,0xFFBC0025,0xFFB0000D,0xF1DC0091,0xFBD40071,0xE1FC00A2,0xF7840001,
-0xE1FC00A2,0x1F80019,0xFFF4000D,0xFFF00004,0xFFF00000,0xF5FC0019,0xFFF00008,0xFFE80000,0xF9FC0019,0xFFD40000,0xFA000019,0xF5FC0019,0xFFF00008,0xFFE80000,0xF9FC0019,0xFFD40000,0xFA000019,0xF9FC0019,0xFFD40000,0xFA000019,0xFA000019,0xF5FC0019,0xFFF00008,0xFFE80000,0xF9FC0019,0xFFD40000,0xFA000019,0xF9FC0019,0xFFD40000,0xFA000019,0xFA000019,0xF9FC0019,
-0xFFD40000,0xFA000019,0xFA000019,0xFA000019,0xFDF40014,0xC7FC0019,0xF5F80019,0xFFF40012,0xFFE80010,0xFFE80008,0xFFDC0000,0xFFC80000,0xF1FC0019,0xFFF00014,0xFFE00001,0xFA000019,0xF9FC0019,0x1B800C8,0x1B800C8,0x1B800C8,0x1B800C8,0x1B800C8,0x1B800C8,0x1B800C8,0x1B800C8,0x1B800C8,0x1B800C8,0xFFA80014,0xFFA80014,0xFFA80014,0xFFA80014,0xFFA80014,
-0xFFA80014,0xEFA40001,0xEFA40001,0xEFA40001,0xE5A40001,0x95FC00C8,0x95FC00C8,0x95FC00C8,0x95FC00C8,0x95FC00C8,0x95FC00C8,0xF7800001,0xF7800001,0xF7800001,0xE5900001,0xCBFC00C8,0xCBFC00C8,0xCBFC00C8,0xE5540001,0xDA0000CA,0xF3B400A4,0x1B800C8,0x1B800C8,0xFBB40071,0xFDB00048,0xFFAC0029,0xFFAC0029,0xFFA40004,0xF9B00091,0xFBAC0064,0xF7A00001,0xF7800001,
-0xBFF800C8,};
-static const uint32_t g_etc1_to_bc7_m6_table94[] = {
-0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0xC9F80000,
-0xC9F80000,0xC9F80000,0xC9F80000,0xD8000001,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1D00000,0x1D00000,0x1D00000,0x8FFC0000,0xBBFC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,
-0xCDFC0000,0xE7F80000,0xE7F80000,0xE7F80000,0xEC000001,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xE7F80000,0xE7F80000,0xE7F80000,0xEC000001,0xE7F80000,0xE7F80000,0xE7F80000,0xEC000001,0xEC000001,0x1FC0000,0x1DC0000,0x1DC0000,0x89FC0000,0xADFC0000,0xC1FC0000,0xC1FC0000,0xD7FC0000,0x89FC0000,0xADFC0000,0xDFFC0000,0xE7F80000,
-0xDFFC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1E403A2,0xFFDC032A,0xFFD802D5,0xFFD802B1,0xFFDC0282,0xFFD40205,0xFFD001C9,0xFFCC0150,0xFFCC0110,0xFFC800C8,0xFFD0028A,0xFFD001E9,0xFFC801A9,0xFFC000FC,0xFFC00098,0xFFBC0029,0xFFB8011A,0xFFB800A1,0xFFB00014,0xF9B400C1,0xD5FC03A2,0xFFCC02F1,0xFFC802AE,0xFFB801CC,0xFFB80153,0xFFAC00CA,0xFFAC01B3,0xFFA000FE,0xFF900001,0xF99400C2,0xEBF803A2,
-0xFF9002AE,0xFF5800C8,0xF93400C1,0xF00003A2,0xFDE00326,0xF9E00370,0xFBE40389,0xFFD40272,0xFFD001DA,0xFFC8012F,0xFFC400E0,0xFFB80065,0xFFD8030F,0xFFD00253,0xFFBC010D,0xFF900001,0xE5FC03A2,0x1F400C2,0xFDF000AE,0xFFF00099,0xFFEC0091,0xFFE80086,0xFFE80065,0xFFE80055,0xFFE40030,0xFFE0001D,0xFFDC0000,0xEFFC00C1,0xFFE400A1,0xFFE40091,0xFFD80058,0xFFD80034,
-0xFFCC0000,0xF7F800C1,0xFFC80091,0xFF940000,0xF80000C1,0xEFFC00C1,0xFFE400A1,0xFFE40091,0xFFD80058,0xFFD80034,0xFFCC0000,0xF7F800C1,0xFFC80091,0xFF940000,0xF80000C1,0xF7F800C1,0xFFC80091,0xFF940000,0xF80000C1,0xF80000C1,0xFDF000AC,0xFFEC00C0,0xF3F400C2,0xFFEC009B,0xFFE80081,0xFFE0005E,0xFFE00048,0xFFD0002D,0xFBF000AC,0xFFE80095,0xFFD80092,0xFF940000,
-0xF5FC00C1,0x1D802B1,0x1D802B1,0x1D802B1,0x1D802B1,0xFFD001C9,0xFFD001C9,0xFFD001C9,0xFFCC0110,0xFFCC0110,0xFFC800C8,0xFFC801A9,0xFFC801A9,0xFFC801A9,0xFFC00098,0xFFC00098,0xFFBC0029,0xFFB800A1,0xFFB800A1,0xFDB00011,0xF7B40091,0xC9FC02AE,0xC9FC02AE,0xC9FC02AE,0xFFB80153,0xFFB80153,0xFFAC00CA,0xFFA000FE,0xFFA000FE,0xFF900001,0xF7980091,0xE5F802AE,
-0xE5F802AE,0xFF5800C8,0xF73C0091,0xEC0002AE,0xFFD80245,0xF5D8028C,0x1D802B1,0xFFD401E2,0xFFCC017A,0xFFC40114,0xFFC400E0,0xFFB80065,0xFFD0022E,0xFFD001C3,0xFFBC0109,0xFF900001,0xDFF802AE,0x1EC0091,0x1EC0091,0x1EC0091,0x1EC0091,0xFFE80055,0xFFE80055,0xFFE80055,0xFFE0001D,0xFFE0001D,0xFFDC0000,0xE5FC0091,0xE5FC0091,0xE5FC0091,0xFFD80034,0xFFD80034,
-0xFFCC0000,0xF3F80091,0xF3F80091,0xFF940000,0xF6000091,0xE5FC0091,0xE5FC0091,0xE5FC0091,0xFFD80034,0xFFD80034,0xFFCC0000,0xF3F80091,0xF3F80091,0xFF940000,0xF6000091,0xF3F80091,0xF3F80091,0xFF940000,0xF6000091,0xF6000091,0xFBEC0080,0xFFEC0080,0x1EC0091,0xF9EC0080,0xFFE0006A,0xFFE00055,0xFFE00048,0xFFD0002D,0xF9EC0080,0xFFE80071,0xEFFC0091,0xFF940000,
-0xEFFC0091,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1C800C8,0x1C800C8,0x1C800C8,0x1C800C8,0x1C800C8,0x1C800C8,0x1C800C8,0x1C800C8,0x1C800C8,0x1C800C8,0xFFBC0029,0xFFBC0029,0xFFBC0029,0xFFBC0029,0xFFBC0029,
-0xFFBC0029,0xF7B40001,0xF7B40001,0xF7B40001,0xEDB40001,0xAFFC00C8,0xAFFC00C8,0xAFFC00C8,0xAFFC00C8,0xAFFC00C8,0xAFFC00C8,0xFF900001,0xFF900001,0xFF900001,0xEDA00001,0xD7FC00C8,0xD7FC00C8,0xD7FC00C8,0xED640001,0xE20000CA,0xFBC400A4,0x1C800C8,0x1C800C8,0xFBC40080,0xFFBC0061,0xFFBC0041,0xFFBC0041,0xFFB80014,0xFFBC009D,0xFFBC0075,0xFFB00001,0xFF900001,
-0xCDFC00C8,};
-static const uint32_t g_etc1_to_bc7_m6_table95[] = {
-0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xD5F80000,
-0xD5F80000,0xD5F80000,0xD5F80000,0xE0000001,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x9E00000,0x9E00000,0x9E00000,0xA9FC0000,0xC9FC0000,0x1EC0000,0x1EC0000,0x1EC0000,0x1EC0000,0x1EC0000,0x1EC0000,0x1EC0000,0x1EC0000,0x1EC0000,0x1EC0000,0xE5FC0000,0xE5FC0000,0xE5FC0000,0xE5FC0000,0xE5FC0000,
-0xE5FC0000,0xF3F80000,0xF3F80000,0xF3F80000,0xF4000001,0xE5FC0000,0xE5FC0000,0xE5FC0000,0xE5FC0000,0xE5FC0000,0xE5FC0000,0xF3F80000,0xF3F80000,0xF3F80000,0xF4000001,0xF3F80000,0xF3F80000,0xF3F80000,0xF4000001,0xF4000001,0x77FC0000,0x1EC0000,0x1EC0000,0xC3FC0000,0xD5FC0000,0xDFFC0000,0xDFFC0000,0xEBFC0000,0xC3FC0000,0xD5FC0000,0xEFFC0000,0xF3F80000,
-0xEFFC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1EC0232,0xFFE801F2,0xFFE401C9,0xFFE401B9,0xFFE801AA,0xFFE00165,0xFFDC0149,0xFFD80110,0xFFD800EC,0xFFD800C8,0xFFDC0186,0xFFDC0131,0xFFDC010D,0xFFD400BB,0xFFD00088,0xFFD00048,0xFFCC0091,0xFFCC0051,0xFFC40001,0xFBC40039,0xE3FC0232,0xFFD801DD,0xFFD801B9,0xFFCC0150,0xFFCC0110,0xFFC400C8,0xFFC00109,0xFFB80096,0xFFAC0011,0xFBAC0039,0xF1F80232,
-0xFFAC01B9,0xFF8800C8,0xFB5C0039,0xF4000232,0xFFE401E6,0xFDE80210,0xFFEC0221,0xFFE0019E,0xFFDC013E,0xFFD400D8,0xFFD000B5,0xFFD00061,0xFFE401ED,0xFFDC018C,0xFFD000AF,0xFFAC0011,0xEDFC0232,0x1F80036,0xFFF80031,0xFFF4002D,0xFFF40029,0xFFF40022,0xFFF4001D,0xFFF40019,0xFFF0000C,0xFFF00008,0xFFEC0000,0xF7FC0036,0xFFF0002D,0xFFF00029,0xFFF00018,0xFFE40010,
-0xFFE40000,0xFBFC0036,0xFFE00029,0xFFC80000,0xFA000039,0xF7FC0036,0xFFF0002D,0xFFF00029,0xFFF00018,0xFFE40010,0xFFE40000,0xFBFC0036,0xFFE00029,0xFFC80000,0xFA000039,0xFBFC0036,0xFFE00029,0xFFC80000,0xFA000039,0xFA000039,0xFFF40030,0xF5F80036,0xF5F80036,0xFFF8002C,0xFFF00022,0xFFEC0018,0xFFE80011,0xFFE4000A,0xFFF8002C,0xFFF4002B,0xFFE8002A,0xFFC80000,
-0xFBFC0036,0x1E401B9,0x1E401B9,0x1E401B9,0x1E401B9,0xFFDC0149,0xFFDC0149,0xFFDC0149,0xFFD800EC,0xFFD800EC,0xFFD800C8,0xFFDC010D,0xFFDC010D,0xFFDC010D,0xFFD00088,0xFFD00088,0xFFD00048,0xFFCC0051,0xFFCC0051,0xFFC40001,0xFBC40029,0xD9FC01B9,0xD9FC01B9,0xD9FC01B9,0xFFCC0110,0xFFCC0110,0xFFC400C8,0xFFB80096,0xFFB80096,0xFFAC0011,0xFBAC0029,0xEDF801B9,
-0xEDF801B9,0xFF8800C8,0xFB5C0029,0xF20001BA,0xFDE40182,0xFBE401A0,0x1E401B9,0xFFDC0144,0xFFD80101,0xFFD400C8,0xFFD000B5,0xFFD00061,0xFDE00181,0xFFDC013B,0xFFD000AE,0xFFAC0011,0xE7FC01B9,0x1F40029,0x1F40029,0x1F40029,0x1F40029,0xFFF40019,0xFFF40019,0xFFF40019,0xFFF00008,0xFFF00008,0xFFEC0000,0xF1FC0029,0xF1FC0029,0xF1FC0029,0xFFE40010,0xFFE40010,
-0xFFE40000,0xF9F80029,0xF9F80029,0xFFC80000,0xFA000029,0xF1FC0029,0xF1FC0029,0xF1FC0029,0xFFE40010,0xFFE40010,0xFFE40000,0xF9F80029,0xF9F80029,0xFFC80000,0xFA000029,0xF9F80029,0xF9F80029,0xFFC80000,0xFA000029,0xFA000029,0xFFF40020,0xF3F40029,0x1F40029,0xFDF40020,0xFFF00019,0xFFEC0014,0xFFE80011,0xFFE4000A,0xFDF40020,0xFDF00022,0xF7FC0029,0xFFC80000,
-0xF7FC0029,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1D800C8,0x1D800C8,0x1D800C8,0x1D800C8,0x1D800C8,0x1D800C8,0x1D800C8,0x1D800C8,0x1D800C8,0x1D800C8,0xFFD00048,0xFFD00048,0xFFD00048,0xFFD00048,0xFFD00048,
-0xFFD00048,0xFFC40001,0xFFC40001,0xFFC40001,0xF5C40001,0xC7FC00C8,0xC7FC00C8,0xC7FC00C8,0xC7FC00C8,0xC7FC00C8,0xC7FC00C8,0xFFAC0011,0xFFAC0011,0xFFAC0011,0xF5B00001,0xE3FC00C8,0xE3FC00C8,0xE3FC00C8,0xF5740001,0xEA0000CA,0xF5D800B5,0x1D800C8,0x1D800C8,0xFDD40091,0xFFD00075,0xFFCC0061,0xFFCC0061,0xFFCC0034,0xFDD400A2,0xFFD00082,0xFFC4001D,0xFFAC0011,
-0xDDF800C8,};
-static const uint32_t g_etc1_to_bc7_m6_table96[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x180001,0x180001,0x180001,0x180001,0x2240000,0x2240000,0x2240000,0x4C0000,0x4C0000,0xC000000,0x2240000,0x2240000,0x2240000,0x4C0000,0x4C0000,0xC000000,0x4C0000,0x4C0000,0xC000000,0xC000000,0x2240000,0x2240000,0x2240000,0x4C0000,0x4C0000,0xC000000,0x4C0000,0x4C0000,0xC000000,0xC000000,0x4C0000,
-0x4C0000,0xC000000,0xC000000,0xC000000,0x41C0000,0x1C0000,0x180001,0x240000,0x2C0000,0x340000,0x3C0000,0x5C0000,0x200000,0x2240000,0x340000,0xC000000,0x340000,0x540000,0x7C0000,0xFC0000,0x28000001,0x7C0000,0xFC0000,0x28000001,0xFC0000,0x28000001,0x28000001,0x7C0000,0xFC0000,0x28000001,0xFC0000,0x28000001,
-0x28000001,0xFC0000,0x28000001,0x28000001,0x28000001,0x7C0000,0xFC0000,0x28000001,0xFC0000,0x28000001,0x28000001,0xFC0000,0x28000001,0x28000001,0x28000001,0xFC0000,0x28000001,0x28000001,0x28000001,0x28000001,0x680000,0x4580000,0x4580000,0x8C0000,0xCC0000,0x1940000,0x28000001,0x28000001,0x2700000,0x9C0000,0x1DCC0000,0x28000001,
-0xB00000,0x1C0499,0x76080071,0x3C080071,0x28080072,0x500001A5,0x3A000028,0x28000001,0x280001A5,0x200000A2,0x1A0001A5,0x3600039D,0x2E000149,0x240000AA,0x22000236,0x2000011B,0x180001F1,0x1A00039D,0x1C000236,0x160002AE,0x1200039E,0x280499,0x28000216,0x22000127,0x220002AF,0x1E000181,0x18000231,0x180003E2,0x1600028E,0x140002EE,0x120003C2,0x500499,
-0x1600032F,0x10000373,0x1000041B,0xC00049B,0xA4000108,0xFE0C0229,0xF21401F2,0x48000118,0x3600011B,0x2800011B,0x220000C2,0x20000173,0x64000209,0x3C00017A,0x1E0001B6,0x140002EE,0x380499,0x24039D,0x720C0055,0x3A0C0055,0x280C0056,0x500001A5,0x3A000028,0x28000001,0x280001A5,0x200000A2,0x1A0001A5,0x34039D,0x2E000149,0x240000AA,0x22000236,0x2000011B,
-0x180001F1,0x68039D,0x1C000236,0x160002AE,0x1200039E,0x34039D,0x2E000149,0x240000AA,0x22000236,0x2000011B,0x180001F1,0x68039D,0x1C000236,0x160002AE,0x1200039E,0x68039D,0x1C000236,0x160002AE,0x1200039E,0x1200039E,0xA4000108,0xFE0C0205,0xF61C016E,0x48000118,0x3600011B,0x2800011B,0x220000C2,0x20000173,0x6C0001DB,0x3C00016A,0x1E0001B2,0x160002AE,
-0x4C039D,0x80071,0x80071,0x80071,0x80071,0x26000000,0x26000000,0x26000000,0x12000000,0x12000000,0xC000000,0x10000055,0x10000055,0x10000055,0xC000020,0xC000020,0xC000010,0x8000055,0x8000055,0x8000034,0x6000055,0xC0071,0xC0071,0xC0071,0xC000030,0xC000030,0xC000020,0x600005D,0x600005D,0x800003D,0x6000059,0x140071,
-0x140071,0x4000052,0x4000062,0x4000072,0x44000019,0xC8000000,0x80071,0x24000022,0x1A00001D,0x12000022,0x1200001D,0xC000022,0x24000036,0x1A00002D,0xA000056,0x800003D,0x100071,0xC0055,0xC0055,0xC0055,0xC0055,0x26000000,0x26000000,0x26000000,0x12000000,0x12000000,0xC000000,0x100055,0x100055,0x100055,0xC000020,0xC000020,
-0xC000010,0x200055,0x200055,0x8000034,0x6000055,0x100055,0x100055,0x100055,0xC000020,0xC000020,0xC000010,0x200055,0x200055,0x8000034,0x6000055,0x200055,0x200055,0x8000034,0x6000055,0x6000055,0x44000019,0xC8000000,0xC0055,0x24000022,0x1A00001D,0x12000022,0x1200001D,0xC000022,0x24000032,0x1A000029,0x180055,0x8000034,
-0x180055,0x3801A5,0x621C0001,0x361C0001,0x28180002,0x5001A5,0x3A000028,0x28000001,0xA001A5,0x200000A2,0x1A0001A5,0x5001A5,0x3A000028,0x28000001,0xA001A5,0x200000A2,0x1A0001A5,0xA001A5,0x200000A2,0x1A0001A5,0x1A0001A5,0x5001A5,0x3A000028,0x28000001,0xA001A5,0x200000A2,0x1A0001A5,0xA001A5,0x200000A2,0x1A0001A5,0x1A0001A5,0xA001A5,
-0x200000A2,0x1A0001A5,0x1A0001A5,0x1A0001A5,0xA40000A4,0x3C01A5,0xFC280062,0x52000091,0x360000A2,0x2C00009D,0x2400006A,0x200000CA,0x720000DD,0x4C0000B4,0x26000059,0x1A0001A5,0x7001A5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table97[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x280001,0x280001,0x280001,0x280001,0x23C0000,0x23C0000,0x23C0000,0x7C0000,0x7C0000,0x14000000,0x23C0000,0x23C0000,0x23C0000,0x7C0000,0x7C0000,0x14000000,0x7C0000,0x7C0000,0x14000000,0x14000000,0x23C0000,0x23C0000,0x23C0000,0x7C0000,0x7C0000,0x14000000,0x7C0000,0x7C0000,0x14000000,0x14000000,0x7C0000,
-0x7C0000,0x14000000,0x14000000,0x14000000,0x300000,0x2C0000,0x280001,0x380000,0x440000,0x580000,0x640000,0x980000,0x340000,0x23C0000,0x580000,0x14000000,0x580000,0x640000,0x940000,0x12C0000,0x30000001,0x940000,0x12C0000,0x30000001,0x12C0000,0x30000001,0x30000001,0x940000,0x12C0000,0x30000001,0x12C0000,0x30000001,
-0x30000001,0x12C0000,0x30000001,0x30000001,0x30000001,0x940000,0x12C0000,0x30000001,0x12C0000,0x30000001,0x30000001,0x12C0000,0x30000001,0x30000001,0x30000001,0x12C0000,0x30000001,0x30000001,0x30000001,0x30000001,0x7C0000,0xC680000,0xC680000,0xA80000,0xF40000,0x1E00000,0x30000001,0x30000001,0x880000,0xBC0000,0x25DC0000,0x30000001,
-0xD40000,0x240691,0x86100129,0x460C0129,0x300C012A,0x6A0001A5,0x46000008,0x32000011,0x340001A5,0x2C00006A,0x220001A5,0x480004ED,0x3A0001D1,0x2E00010E,0x2E00029E,0x2800012B,0x2200021E,0x220004ED,0x20000306,0x1C000362,0x160004EE,0x340691,0x34000316,0x280001E3,0x28000367,0x280001D4,0x1E000295,0x1E000566,0x2000037F,0x1C0003C6,0x1600052E,0x680691,
-0x1C00048F,0x1600049F,0x140005C6,0x10000693,0xC2000118,0xF2140349,0xF61C0372,0x66000128,0x4000013B,0x34000135,0x2A0000C3,0x240001AE,0x82000289,0x500001CD,0x26000266,0x1C0003C6,0x4C0691,0x3004ED,0x821400DD,0x441400DD,0x301400DE,0x6A0001A5,0x46000008,0x3204000E,0x340001A5,0x2C00006A,0x220001A5,0x24404ED,0x3A0001D1,0x2E00010E,0x2E00029E,0x2800012B,
-0x2200021E,0x8C04ED,0x20000306,0x1C000362,0x160004EE,0x24404ED,0x3A0001D1,0x2E00010E,0x2E00029E,0x2800012B,0x2200021E,0x8C04ED,0x20000306,0x1C000362,0x160004EE,0x8C04ED,0x20000306,0x1C000362,0x160004EE,0x160004EE,0xC2000118,0xF61C02BD,0xFA24026E,0x66000128,0x4000013B,0x34000135,0x2A0000C3,0x240001AE,0x82000249,0x500001B4,0x26000262,0x1C000362,
-0x6404ED,0xC0129,0xC0129,0xC0129,0xC0129,0x3E000000,0x3E000000,0x3E000000,0x1E000000,0x1E000000,0x14000000,0x1C0000DD,0x1C0000DD,0x1C0000DD,0x18000050,0x18000050,0x12000028,0xE0000DD,0xE0000DD,0xE000088,0xA0000DD,0x140126,0x140126,0x140126,0x12000088,0x12000088,0x1200004C,0xC0000F1,0xC0000F1,0xC0000A1,0x80000EA,0x240126,
-0x240126,0xA0000C6,0x8000105,0x6000126,0x76000041,0xFA040011,0xC0129,0x3A000059,0x28000050,0x22000055,0x1E000049,0x16000061,0x42000092,0x3200007D,0x120000DE,0xC0000A1,0x1C0126,0x1400DD,0x1400DD,0x1400DD,0x1400DD,0x3E000000,0x3E000000,0x3E000000,0x1E000000,0x1E000000,0x14000000,0x1C00DD,0x1C00DD,0x1C00DD,0x18000050,0x18000050,
-0x12000028,0x3800DD,0x3800DD,0xE000088,0xA0000DD,0x1C00DD,0x1C00DD,0x1C00DD,0x18000050,0x18000050,0x12000028,0x3800DD,0x3800DD,0xE000088,0xA0000DD,0x3800DD,0x3800DD,0xE000088,0xA0000DD,0xA0000DD,0x76000041,0xFA04000D,0x1400DD,0x3A000059,0x28000050,0x22000055,0x1E000049,0x16000061,0x42000082,0x32000074,0x2800DD,0xE000088,
-0x2800DD,0x4801A5,0x6A2C0001,0x3E2C0001,0x30280002,0x6801A5,0x46000008,0x30100001,0xD001A5,0x2C00006A,0x220001A5,0x6801A5,0x46000008,0x30100001,0xD001A5,0x2C00006A,0x220001A5,0xD001A5,0x2C00006A,0x220001A5,0x220001A5,0x6801A5,0x46000008,0x30100001,0xD001A5,0x2C00006A,0x220001A5,0xD001A5,0x2C00006A,0x220001A5,0x220001A5,0xD001A5,
-0x2C00006A,0x220001A5,0x220001A5,0x220001A5,0xD6000075,0x4C01A5,0xF4380071,0x6E000059,0x4A00006A,0x36000064,0x2E00003A,0x280000A2,0x920400B5,0x5E00007D,0x32000028,0x220001A5,0x9401A5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table98[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x40001,0x40001,0x40001,0x40001,0x40001,0x40001,0x40001,0x40001,0x40001,0x40001,0x80000,0x80000,0x80000,0x80000,0x80000,
-0x80000,0xC0000,0xC0000,0xC0000,0x2000000,0x80000,0x80000,0x80000,0x80000,0x80000,0x80000,0xC0000,0xC0000,0xC0000,0x2000000,0xC0000,0xC0000,0xC0000,0x2000000,0x2000000,0xA040000,0x40001,0x40001,0x6040000,0x80000,0x80000,0x80000,0x80000,0x6040000,0x80000,0xC0000,0xC0000,
-0xC0000,0x380001,0x380001,0x380001,0x380001,0x540000,0x540000,0x540000,0xAC0000,0xAC0000,0x1C000000,0x540000,0x540000,0x540000,0xAC0000,0xAC0000,0x1C000000,0xAC0000,0xAC0000,0x1C000000,0x1C000000,0x540000,0x540000,0x540000,0xAC0000,0xAC0000,0x1C000000,0xAC0000,0xAC0000,0x1C000000,0x1C000000,0xAC0000,
-0xAC0000,0x1C000000,0x1C000000,0x1C000000,0x440000,0x63C0000,0x380001,0x24C0000,0x600000,0x780000,0x8C0000,0xD40000,0x480000,0x540000,0x780000,0x1C000000,0x780000,0x740000,0xAC0000,0x15C0000,0x38000001,0xAC0000,0x15C0000,0x38000001,0x15C0000,0x38000001,0x38000001,0xAC0000,0x15C0000,0x38000001,0x15C0000,0x38000001,
-0x38000001,0x15C0000,0x38000001,0x38000001,0x38000001,0xAC0000,0x15C0000,0x38000001,0x15C0000,0x38000001,0x38000001,0x15C0000,0x38000001,0x38000001,0x38000001,0x15C0000,0x38000001,0x38000001,0x38000001,0x38000001,0x900000,0x7C0000,0x7C0000,0x2C00000,0x11C0000,0x9F00000,0x38000001,0x38000001,0x9C0000,0xD80000,0x2DEC0000,0x38000001,
-0xF40000,0x2C088E,0x9A1401FE,0x501401FE,0x381401FF,0x7E0401AA,0x54040005,0x3C08003E,0x3E0401AA,0x3404004F,0x2A0401AA,0x5A0005EA,0x46000218,0x36000163,0x3A0002BD,0x3000010A,0x28000215,0x2C0005EA,0x26000383,0x240003DD,0x1C0005ED,0x40088E,0x40000401,0x3400028E,0x340003FA,0x2E0001F3,0x280002BE,0x2800069F,0x2600042C,0x20000463,0x1C000651,0x80088E,
-0x200005EF,0x1C0005B2,0x1A000749,0x1600088E,0xF40000E9,0xF61C0486,0xFA24050F,0x74000111,0x5000011D,0x3C000103,0x34000096,0x2C00019A,0xA40002D1,0x5E0001D1,0x320002B1,0x20000463,0x5C088E,0x3C05EA,0x8E200152,0x4E200152,0x38200153,0x7A0801A6,0x54040001,0x3A10002A,0x3E0401A6,0x3404004B,0x2A0401A6,0x5805EA,0x46000218,0x36000163,0x3A0002BD,0x3000010A,
-0x28000215,0xB005EA,0x26000383,0x240003DD,0x1C0005ED,0x5805EA,0x46000218,0x36000163,0x3A0002BD,0x3000010A,0x28000215,0xB005EA,0x26000383,0x240003DD,0x1C0005ED,0xB005EA,0x26000383,0x240003DD,0x1C0005ED,0x1C0005ED,0xF40000E9,0xFC280356,0xFE2C0353,0x74000111,0x5000011D,0x3C000103,0x34000096,0x2C00019A,0xA400026D,0x5E0001AD,0x320002A8,0x240003DD,
-0x7C05EA,0x1401FE,0x1401FE,0x1401FE,0x1401FE,0x52040005,0x52040005,0x52040005,0x28040006,0x28040006,0x1C040005,0x30000152,0x30000152,0x30000152,0x22000059,0x22000059,0x1A000028,0x16000154,0x16000154,0x160000B4,0xE000154,0x2001FD,0x2001FD,0x2001FD,0x220000D2,0x220000D2,0x18000069,0x12000188,0x12000188,0x140000EA,0xE00016D,0x3C01FD,
-0x3C01FD,0x10000149,0xA0001B5,0xA0001FD,0xB6000049,0xFE0C005E,0x1401FE,0x50000071,0x3C000061,0x2E000061,0x2A000049,0x2000007D,0x640000DD,0x440000AD,0x1E000156,0x140000EA,0x2C01FD,0x200152,0x200152,0x200152,0x200152,0x4E080001,0x4E080001,0x4E080001,0x28080001,0x28080001,0x1C040001,0x300152,0x300152,0x300152,0x22000059,0x22000059,
-0x1A000028,0x5C0152,0x5C0152,0x160000B4,0xE000154,0x300152,0x300152,0x300152,0x22000059,0x22000059,0x1A000028,0x5C0152,0x5C0152,0x160000B4,0xE000154,0x5C0152,0x5C0152,0x160000B4,0xE000154,0xE000154,0xB6000049,0xFE0C003A,0x200152,0x50000071,0x3C000061,0x2E000061,0x2A000049,0x2000007D,0x640000B9,0x4400009D,0x400152,0x160000B4,
-0x400152,0x5801A5,0x723C0001,0x463C0001,0x38380002,0x8001A5,0x54040000,0x38200001,0x10001A5,0x36000049,0x2A0001A5,0x8001A5,0x54040000,0x38200001,0x10001A5,0x36000049,0x2A0001A5,0x10001A5,0x36000049,0x2A0001A5,0x2A0001A5,0x8001A5,0x54040000,0x38200001,0x10001A5,0x36000049,0x2A0001A5,0x10001A5,0x36000049,0x2A0001A5,0x2A0001A5,0x10001A5,
-0x36000049,0x2A0001A5,0x2A0001A5,0x2A0001A5,0xF6040055,0x5C01A5,0xFC480071,0x84000034,0x56000048,0x40000048,0x36000019,0x32000071,0xB4040091,0x6E000055,0x3C00000A,0x2A0001A5,0xB401A5,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,
-0x8000000,0x4000000,0x4000000,0x4000000,0x2000000,0x40005,0x40005,0x40005,0x40005,0x40005,0x40005,0x2000002,0x2000002,0x2000002,0x2000001,0x5,0x5,0x5,0x2000004,0x5,0x28000000,0x40005,0x40005,0x12000000,0xC000000,0xA000000,0xA000000,0x6000000,0x12000001,0xC000001,0x4000000,0x2000002,
-0x5,};
-static const uint32_t g_etc1_to_bc7_m6_table99[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x140001,0x140001,0x140001,0x140001,0x140001,0x140001,0x140001,0x140001,0x140001,0x140001,0x200000,0x200000,0x200000,0x200000,0x200000,
-0x200000,0x3C0000,0x3C0000,0x3C0000,0xA000000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x3C0000,0x3C0000,0x3C0000,0xA000000,0x3C0000,0x3C0000,0x3C0000,0xA000000,0xA000000,0x180000,0x140001,0x140001,0x2180000,0x1C0000,0x1C0000,0x1C0000,0x240000,0x2180000,0x1C0000,0x2C0000,0x3C0000,
-0x2C0000,0x480001,0x480001,0x480001,0x480001,0x6C0000,0x6C0000,0x6C0000,0xDC0000,0xDC0000,0x24000000,0x6C0000,0x6C0000,0x6C0000,0xDC0000,0xDC0000,0x24000000,0xDC0000,0xDC0000,0x24000000,0x24000000,0x6C0000,0x6C0000,0x6C0000,0xDC0000,0xDC0000,0x24000000,0xDC0000,0xDC0000,0x24000000,0x24000000,0xDC0000,
-0xDC0000,0x24000000,0x24000000,0x24000000,0x2540000,0xE4C0000,0x480001,0x640000,0x7C0000,0x9C0000,0xB40000,0x1100000,0x5C0000,0x6C0000,0x9C0000,0x24000000,0x9C0000,0x840000,0xC40000,0x18C0000,0x40000001,0xC40000,0x18C0000,0x40000001,0x18C0000,0x40000001,0x40000001,0xC40000,0x18C0000,0x40000001,0x18C0000,0x40000001,
-0x40000001,0x18C0000,0x40000001,0x40000001,0x40000001,0xC40000,0x18C0000,0x40000001,0x18C0000,0x40000001,0x40000001,0x18C0000,0x40000001,0x40000001,0x40000001,0x18C0000,0x40000001,0x40000001,0x40000001,0x40000001,0xA40000,0x8C0000,0x8C0000,0xDC0000,0x1400000,0x13F00000,0x40000001,0x40000001,0xB40000,0xF80000,0x35FC0000,0x40000001,
-0x1180000,0x380A26,0xA62002D2,0x5A2002D2,0x402002D3,0x8E0C01E2,0x600C003F,0x461000A2,0x480C01E2,0x3C080073,0x320C01E2,0x720005EA,0x580001A8,0x40040159,0x4600024D,0x3A00007A,0x320001C9,0x380005EA,0x320002FB,0x2C000362,0x240005ED,0x540A26,0x4C000489,0x3C00031B,0x40000432,0x3A0001E3,0x2E0002BE,0x34000717,0x30000415,0x2A00043D,0x2400067D,0xA40A26,
-0x260006D7,0x26000662,0x20000819,0x1C000A26,0xFA0400DE,0xFC2805A6,0xFE2C0687,0x90000086,0x6200008B,0x4C00007A,0x40000029,0x380000FA,0xC200025D,0x76000142,0x3C000233,0x2A00043D,0x740A26,0x4C05EA,0x96300152,0x56300152,0x40300153,0x821801A6,0x5C140001,0x4220002A,0x461401A6,0x3C14004B,0x321401A6,0x7005EA,0x580001A8,0x40080153,0x4600024D,0x3A00007A,
-0x320001C9,0xE405EA,0x320002FB,0x2C000362,0x240005ED,0x7005EA,0x580001A8,0x40080153,0x4600024D,0x3A00007A,0x320001C9,0xE405EA,0x320002FB,0x2C000362,0x240005ED,0xE405EA,0x320002FB,0x2C000362,0x240005ED,0x240005ED,0xFC0800CE,0xF438037A,0xFA44035E,0x90000086,0x6200008B,0x4C00007A,0x40000029,0x380000FA,0xD00001C1,0x7C000105,0x3C000223,0x2C000362,
-0xA005EA,0x2002D2,0x2002D2,0x2002D2,0x2002D2,0x620C003D,0x620C003D,0x620C003D,0x320C003E,0x320C003E,0x240C003D,0x48000152,0x48000152,0x48000152,0x34000025,0x34000025,0x24000001,0x22000152,0x22000152,0x1C000080,0x16000154,0x3002D2,0x3002D2,0x3002D2,0x280000FE,0x280000FE,0x2200007D,0x1E0001C8,0x1E0001C8,0x1C0000E4,0x16000194,0x5C02D2,
-0x5C02D2,0x160001B5,0x14000228,0xE0002D5,0xF6000014,0xF21400F5,0x2002D2,0x7A000034,0x54000028,0x40000028,0x38000019,0x2A00003D,0x820000D5,0x5A000086,0x2C00015B,0x1C0000E4,0x4002D2,0x300152,0x300152,0x300152,0x300152,0x56180001,0x56180001,0x56180001,0x30180001,0x30180001,0x24140001,0x2440152,0x2440152,0x2440152,0x34000025,0x34000025,
-0x24000001,0x8C0152,0x8C0152,0x1C000080,0x16000154,0x2440152,0x2440152,0x2440152,0x34000025,0x34000025,0x24000001,0x8C0152,0x8C0152,0x1C000080,0x16000154,0x8C0152,0x8C0152,0x1C000080,0x16000154,0x16000154,0xF6000014,0xF820003D,0x300152,0x7A000034,0x54000028,0x40000028,0x38000019,0x2A00003D,0x96000088,0x5A000062,0x640152,0x1C000080,
-0x640152,0x6801A5,0x7A4C0001,0x4E4C0001,0x40480002,0x9801A5,0x5C140000,0x40300001,0x13001A5,0x3E000022,0x320001A5,0x9801A5,0x5C140000,0x40300001,0x13001A5,0x3E000022,0x320001A5,0x13001A5,0x3E000022,0x320001A5,0x320001A5,0x9801A5,0x5C140000,0x40300001,0x13001A5,0x3E000022,0x320001A5,0x13001A5,0x3E000022,0x320001A5,0x320001A5,0x13001A5,
-0x3E000022,0x320001A5,0x320001A5,0x320001A5,0xFE140055,0x6C01A5,0xF4580082,0x9A000019,0x6A000028,0x4E000022,0x40000005,0x3A000055,0xD2040071,0x8600003A,0x44000001,0x320001A5,0xD801A5,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0xC003D,0x20000000,0x20000000,0x20000000,0x20000000,0x20000000,
-0x20000000,0x10000000,0x10000000,0x10000000,0xA000000,0x10003D,0x10003D,0x10003D,0x10003D,0x10003D,0x10003D,0xC000014,0xC000014,0xC000014,0x800000D,0x18003D,0x18003D,0x18003D,0x8000028,0x400003D,0xA8000000,0xC003D,0xC003D,0x4A000000,0x34000000,0x28000000,0x28000000,0x1A000000,0x44000011,0x34000009,0x14000001,0xC000014,
-0x14003D,};
-static const uint32_t g_etc1_to_bc7_m6_table100[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,
-0x3C0000,0x740000,0x740000,0x740000,0x12000001,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x740000,0x740000,0x740000,0x12000001,0x740000,0x740000,0x740000,0x12000001,0x12000001,0xC280000,0x280000,0x280000,0x42C0000,0x2300000,0x2340000,0x2340000,0x2400000,0x42C0000,0x2300000,0x540000,0x740000,
-0x540000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x880000,0x880000,0x880000,0x1140000,0x1140000,0x2C000001,0x880000,0x880000,0x880000,0x1140000,0x1140000,0x2C000001,0x1140000,0x1140000,0x2C000001,0x2C000001,0x880000,0x880000,0x880000,0x1140000,0x1140000,0x2C000001,0x1140000,0x1140000,0x2C000001,0x2C000001,0x1140000,
-0x1140000,0x2C000001,0x2C000001,0x2C000001,0x6680000,0x8600000,0x5C0000,0x7C0000,0x980000,0xC00000,0xE00000,0x1540000,0x740000,0x880000,0xC00000,0x2C000001,0xC00000,0x940001,0x2DC0000,0x1C40000,0x4A000000,0x2DC0000,0x1C40000,0x4A000000,0x1C40000,0x4A000000,0x4A000000,0x2DC0000,0x1C40000,0x4A000000,0x1C40000,0x4A000000,
-0x4A000000,0x1C40000,0x4A000000,0x4A000000,0x4A000000,0x2DC0000,0x1C40000,0x4A000000,0x1C40000,0x4A000000,0x4A000000,0x1C40000,0x4A000000,0x4A000000,0x4A000000,0x1C40000,0x4A000000,0x4A000000,0x4A000000,0x4A000000,0xBC0000,0xA00000,0xA00000,0xFC0000,0x16C0000,0x1DFC0000,0x4A000000,0x4A000000,0xCC0000,0x1180000,0x3FF00000,0x4A000000,
-0x13C0000,0x480C65,0xB62C0428,0x642C0428,0x4A2C0428,0xA014026D,0x6A1400D8,0x4C1C0165,0x5414026D,0x461000F0,0x3C14026D,0x8E0005EA,0x6A000163,0x4E080192,0x580001F6,0x4600001D,0x3C0001A5,0x440005ED,0x3E000284,0x38000301,0x2E0005EA,0x680C63,0x5E000594,0x48000438,0x4C0004BF,0x40000222,0x3A000313,0x400007BE,0x3A00041D,0x34000436,0x2E0006CB,0xD00C63,
-0x32000818,0x2C00076D,0x2600094E,0x22000C63,0xFE140162,0xF43807A1,0xF840089D,0xB400001E,0x76000024,0x5A000018,0x4A000001,0x4200007A,0xF2000212,0x900000D7,0x460001D4,0x34000436,0x940C63,0x5C05ED,0x9E440154,0x5E440154,0x4A400154,0x8C2801A5,0x64280002,0x4A300029,0x4E2801A5,0x4424004C,0x3C2801A5,0x8C05EA,0x6A000163,0x4A180152,0x580001F6,0x4600001D,
-0x3C0001A5,0x11805EA,0x3E000284,0x38000301,0x2E0005EA,0x8C05EA,0x6A000163,0x4A180152,0x580001F6,0x4600001D,0x3C0001A5,0x11805EA,0x3E000284,0x38000301,0x2E0005EA,0x11805EA,0x3E000284,0x38000301,0x2E0005EA,0x2E0005EA,0xFC1C00E5,0xFE4C0379,0xF2540384,0xB400001E,0x76000024,0x5A000018,0x4A000001,0x4200007A,0xF2000131,0x90000086,0x460001C4,0x38000301,
-0xC805EA,0x2C0428,0x2C0428,0x2C0428,0x2C0428,0x761400C8,0x761400C8,0x761400C8,0x3E1400C8,0x3E1400C8,0x2C1400C9,0x64000152,0x64000152,0x64000152,0x40000005,0x40000005,0x2E04000E,0x30000152,0x30000152,0x26000055,0x20000152,0x400428,0x400428,0x400428,0x3400018E,0x3400018E,0x2A0000F1,0x2800022D,0x2800022D,0x240000FA,0x1E0001BE,0x800428,
-0x800428,0x1C00028B,0x1C0002DB,0x1400042B,0xFC0C003E,0xF82001F1,0x2C0428,0xA400000D,0x6C000008,0x52000008,0x4C000000,0x38000019,0xB40000E3,0x76000072,0x3E000162,0x240000FA,0x5C0428,0x400154,0x400154,0x400154,0x400154,0x62280000,0x62280000,0x62280000,0x3A280000,0x3A280000,0x2C280001,0x600152,0x600152,0x600152,0x40000005,0x40000005,
-0x2C100001,0xC40152,0xC40152,0x26000055,0x20000152,0x600152,0x600152,0x600152,0x40000005,0x40000005,0x2C100001,0xC40152,0xC40152,0x26000055,0x20000152,0xC40152,0xC40152,0x26000055,0x20000152,0x20000152,0xFE100012,0xF2340048,0x400154,0xA400000D,0x6C000008,0x52000008,0x4C000000,0x38000019,0xC2000055,0x7C000032,0x8C0152,0x26000055,
-0x8C0152,0x7801A5,0x845C0000,0x585C0000,0x4A5C0000,0xB401A5,0x66240000,0x4A400000,0x16801A5,0x4800000D,0x3C0001A5,0xB401A5,0x66240000,0x4A400000,0x16801A5,0x4800000D,0x3C0001A5,0x16801A5,0x4800000D,0x3C0001A5,0x3C0001A5,0xB401A5,0x66240000,0x4A400000,0x16801A5,0x4800000D,0x3C0001A5,0x16801A5,0x4800000D,0x3C0001A5,0x3C0001A5,0x16801A5,
-0x4800000D,0x3C0001A5,0x3C0001A5,0x3C0001A5,0xFE280062,0x8001A5,0xFE6C0080,0xB4000005,0x78000012,0x5A000008,0x4A080000,0x46000034,0xF6080055,0x98000019,0x4E100000,0x3C0001A5,0xFC01A5,0x1400C8,0x1400C8,0x1400C8,0x1400C8,0x1400C8,0x1400C8,0x1400C8,0x1400C8,0x1400C8,0x1400C8,0x3C000000,0x3C000000,0x3C000000,0x3C000000,0x3C000000,
-0x3C000000,0x1C000001,0x1C000001,0x1C000001,0x12000001,0x1C00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x1C00C8,0x18000049,0x18000049,0x18000049,0x12000025,0x3800C8,0x3800C8,0x3800C8,0xE00007D,0x80000CA,0xFA040008,0x1400C8,0x1400C8,0x8A000000,0x60000000,0x4A000000,0x4A000000,0x30000000,0x7600003A,0x5600001D,0x24000004,0x18000049,
-0x2800C8,};
-static const uint32_t g_etc1_to_bc7_m6_table101[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,
-0x2500000,0xA40000,0xA40000,0xA40000,0x1A000001,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,0x2500000,0xA40000,0xA40000,0xA40000,0x1A000001,0xA40000,0xA40000,0xA40000,0x1A000001,0x1A000001,0x3C0000,0x380000,0x380000,0x400000,0x2440000,0x4C0000,0x4C0000,0x5C0000,0x400000,0x2440000,0x740000,0xA40000,
-0x740000,0x6C0000,0x6C0000,0x6C0000,0x6C0000,0xA00000,0xA00000,0xA00000,0x1440000,0x1440000,0x34000001,0xA00000,0xA00000,0xA00000,0x1440000,0x1440000,0x34000001,0x1440000,0x1440000,0x34000001,0x34000001,0xA00000,0xA00000,0xA00000,0x1440000,0x1440000,0x34000001,0x1440000,0x1440000,0x34000001,0x34000001,0x1440000,
-0x1440000,0x34000001,0x34000001,0x34000001,0x27C0000,0x740000,0x6C0000,0x2900000,0xB40000,0xE40000,0x1080000,0x1900000,0x880000,0xA00000,0xE40000,0x34000001,0xE40000,0xA40001,0x2F40000,0x1F40000,0x52000000,0x2F40000,0x1F40000,0x52000000,0x1F40000,0x52000000,0x52000000,0x2F40000,0x1F40000,0x52000000,0x1F40000,0x52000000,
-0x52000000,0x1F40000,0x52000000,0x52000000,0x52000000,0x2F40000,0x1F40000,0x52000000,0x1F40000,0x52000000,0x52000000,0x1F40000,0x52000000,0x52000000,0x52000000,0x1F40000,0x52000000,0x52000000,0x52000000,0x52000000,0xD00000,0xB00000,0xB00000,0x3140000,0x1940000,0x27FC0000,0x52000000,0x52000000,0xE00000,0x1380000,0x49C40000,0x52000000,
-0x1600000,0x540EC9,0xC23805B4,0x6C3805B5,0x523805B4,0xB21C032D,0x762001A4,0x56240261,0x5E1C032D,0x501801A4,0x441C032D,0xA60005EA,0x7C000153,0x581001FE,0x620001B9,0x50000005,0x440401B9,0x500005ED,0x4A000234,0x3E0002A5,0x360005EA,0x780EC7,0x680006C8,0x520005B3,0x5800057F,0x4C0002A2,0x400003A7,0x4C000876,0x46000455,0x3C00044E,0x34000717,0xF40EC7,
-0x380009AC,0x320008B1,0x30000A97,0x28000EC7,0xFE20025D,0xFA440995,0xFE4C0AC9,0xCC000001,0x8A000004,0x66000003,0x5408001C,0x4E000030,0xFE000225,0xA60000A2,0x54000194,0x3C00044E,0xAC0EC7,0x6C05ED,0xA6540154,0x66540154,0x52500154,0x943801A5,0x6C380002,0x52400029,0x563801A5,0x4C34004C,0x443801A5,0xA405EA,0x78040153,0x52280152,0x620001B9,0x50000005,
-0x441001A5,0x14C05EA,0x4A000234,0x3E0002A5,0x360005EA,0xA405EA,0x78040153,0x52280152,0x620001B9,0x50000005,0x441001A5,0x14C05EA,0x4A000234,0x3E0002A5,0x360005EA,0x14C05EA,0x4A000234,0x3E0002A5,0x360005EA,0x360005EA,0xFC3000F8,0xF65C039D,0xFA640384,0xCC000001,0x8A000004,0x66000003,0x52100001,0x4E000030,0xFE08010A,0xA8000035,0x5400017B,0x3E0002A5,
-0xE805EA,0x3805B4,0x3805B4,0x3805B4,0x3805B4,0x861C0188,0x861C0188,0x861C0188,0x481C0188,0x481C0188,0x341C0189,0x7C000152,0x7C000152,0x7C000152,0x50000001,0x50000001,0x36080042,0x3C000152,0x3C000152,0x3200002D,0x28000152,0x5005B3,0x5005B3,0x5005B3,0x4000024E,0x4000024E,0x3400019B,0x340002A5,0x340002A5,0x2E000122,0x280001FB,0xA005B3,
-0xA005B3,0x26000389,0x200003B6,0x1A0005B3,0xF81400D1,0xFE2C0329,0x3805B4,0xC6000001,0x84000001,0x64000001,0x5A040009,0x48000004,0xE4000105,0x9600006A,0x4C00016B,0x2E000122,0x7005B3,0x500154,0x500154,0x500154,0x500154,0x6A380000,0x6A380000,0x6A380000,0x42380000,0x42380000,0x34380001,0x780152,0x780152,0x780152,0x4C080001,0x4C080001,
-0x34200001,0xF40152,0xF40152,0x3200002D,0x28000152,0x780152,0x780152,0x780152,0x4C080001,0x4C080001,0x34200001,0xF40152,0xF40152,0x3200002D,0x28000152,0xF40152,0xF40152,0x3200002D,0x28000152,0x28000152,0xFE200019,0xFA440048,0x500154,0xC4040001,0x80040000,0x62040000,0x54100000,0x48000004,0xF4000034,0x9A000012,0xAC0152,0x3200002D,
-0xAC0152,0x8801A5,0x8C6C0000,0x606C0000,0x526C0000,0xC801A5,0x6E340000,0x52500000,0x19801A5,0x50000004,0x440001A5,0xC801A5,0x6E340000,0x52500000,0x19801A5,0x50000004,0x440001A5,0x19801A5,0x50000004,0x440001A5,0x440001A5,0xC801A5,0x6E340000,0x52500000,0x19801A5,0x50000004,0x440001A5,0x19801A5,0x50000004,0x440001A5,0x440001A5,0x19801A5,
-0x50000004,0x440001A5,0x440001A5,0x440001A5,0xF6400071,0x9001A5,0xF67C0091,0xCC000000,0x8A000004,0x66000002,0x52180000,0x5000001D,0xFE180055,0xAE00000A,0x56200000,0x440001A5,0x12001A5,0x1C0188,0x1C0188,0x1C0188,0x1C0188,0x1C0188,0x1C0188,0x1C0188,0x1C0188,0x1C0188,0x1C0188,0x54000000,0x54000000,0x54000000,0x54000000,0x54000000,
-0x54000000,0x28000000,0x28000000,0x28000000,0x1A000001,0x280188,0x280188,0x280188,0x280188,0x280188,0x280188,0x22000089,0x22000089,0x22000089,0x18000049,0x500188,0x500188,0x500188,0x100000F2,0xC00018A,0xFE0C0048,0x1C0188,0x1C0188,0xC4000000,0x88000000,0x68000000,0x68000000,0x44000000,0xA000007D,0x74000041,0x34000009,0x22000089,
-0x380188,};
-static const uint32_t g_etc1_to_bc7_m6_table102[] = {
-0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x240000,
-0x240000,0x240000,0x240000,0x6000000,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xC0001,0xE0C0000,0xE0C0000,0xE0C0000,0x140000,0x1C0000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x2680000,0x2680000,0x2680000,0x2680000,0x2680000,
-0x2680000,0xD80000,0xD80000,0xD80000,0x22000001,0x2680000,0x2680000,0x2680000,0x2680000,0x2680000,0x2680000,0xD80000,0xD80000,0xD80000,0x22000001,0xD80000,0xD80000,0xD80000,0x22000001,0x22000001,0x4C0000,0x480000,0x480000,0x540000,0x2580000,0x600000,0x600000,0x780000,0x540000,0x2580000,0x980000,0xD80000,
-0x980000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0xB80000,0xB80000,0xB80000,0x1740000,0x1740000,0x3C000001,0xB80000,0xB80000,0xB80000,0x1740000,0x1740000,0x3C000001,0x1740000,0x1740000,0x3C000001,0x3C000001,0xB80000,0xB80000,0xB80000,0x1740000,0x1740000,0x3C000001,0x1740000,0x1740000,0x3C000001,0x3C000001,0x1740000,
-0x1740000,0x3C000001,0x3C000001,0x3C000001,0x900000,0x840000,0x7C0000,0xA80000,0xD00000,0x1080000,0x12C0000,0x1CC0000,0x9C0000,0xB80000,0x1080000,0x3C000001,0x1080000,0xB40001,0x30C0000,0xBFC0000,0x5A000000,0x30C0000,0xBFC0000,0x5A000000,0xBFC0000,0x5A000000,0x5A000000,0x30C0000,0xBFC0000,0x5A000000,0xBFC0000,0x5A000000,
-0x5A000000,0xBFC0000,0x5A000000,0x5A000000,0x5A000000,0x30C0000,0xBFC0000,0x5A000000,0xBFC0000,0x5A000000,0x5A000000,0xBFC0000,0x5A000000,0x5A000000,0x5A000000,0xBFC0000,0x5A000000,0x5A000000,0x5A000000,0x5A000000,0xE40000,0x8C00000,0x8C00000,0x1300000,0x1BC0000,0x31FC0000,0x5A000000,0x5A000000,0xF80000,0x1540000,0x51D40000,0x5A000000,
-0x1800000,0x600F1E,0xCA4805ED,0x764405ED,0x5A4405ED,0xBA2C034A,0x7E3001C5,0x5E340286,0x662C034A,0x582801BD,0x4C2C034A,0xAE1005EB,0x84100154,0x6020020F,0x6C0801B6,0x58100006,0x4C1401BE,0x5A0C05EB,0x5204020D,0x4604028A,0x3E0C05EB,0x900F1A,0x7A000675,0x5A1005EA,0x680004BE,0x5800021D,0x4C000362,0x580007E9,0x4E00036B,0x46000371,0x3C00069F,0x1240F1A,
-0x44000939,0x3E0007FE,0x38000A17,0x30000F1A,0xFE3402CD,0xFE4C0A1A,0xF65C0B55,0xD4100002,0x920C0004,0x6E100004,0x5C180025,0x560C0023,0xFE100262,0xBC000021,0x5E000159,0x46000371,0xD00F1A,0x7C05ED,0xAE640154,0x6E640154,0x5A600154,0x9C4801A5,0x74480002,0x5A500029,0x5E4801A5,0x5444004C,0x4C4801A5,0xBC05EA,0x80140153,0x5A380152,0x700001A6,0x58100005,
-0x4C2001A5,0x17C05EA,0x500001E8,0x48000266,0x3E0005EA,0xBC05EA,0x80140153,0x5A380152,0x700001A6,0x58100005,0x4C2001A5,0x17C05EA,0x500001E8,0x48000266,0x3E0005EA,0x17C05EA,0x500001E8,0x48000266,0x3E0005EA,0x3E0005EA,0xFE3C0121,0xFE6C039D,0xF27403AD,0xD4100001,0x920C0003,0x6E100003,0x5A200001,0x5800000D,0xFE180129,0xBC000008,0x5E000158,0x48000266,
-0x10C05EA,0x4405ED,0x4405ED,0x4405ED,0x4405ED,0x8E2C01A5,0x8E2C01A5,0x8E2C01A5,0x502C01A5,0x502C01A5,0x3C2C01A6,0x84100153,0x84100153,0x84100153,0x58100002,0x58100002,0x3E18004B,0x44100153,0x44100153,0x380C002A,0x300C0153,0x6805EA,0x6805EA,0x6805EA,0x52000205,0x52000205,0x3C0401A6,0x40000248,0x40000248,0x3A0000A9,0x2E00019A,0xD005EA,
-0xD005EA,0x2C000356,0x2A00037E,0x220005EA,0xFE2000FA,0xF63C0379,0x4405ED,0xD80C0001,0x8C100002,0x6C100002,0x6410000B,0x500C0002,0xFE0000B5,0xB6000015,0x5A040153,0x3A0000A9,0x9405EA,0x600154,0x600154,0x600154,0x600154,0x72480000,0x72480000,0x72480000,0x4A480000,0x4A480000,0x3C480001,0x900152,0x900152,0x900152,0x54180001,0x54180001,
-0x3C300001,0x1240152,0x1240152,0x3A000019,0x30000152,0x900152,0x900152,0x900152,0x54180001,0x54180001,0x3C300001,0x1240152,0x1240152,0x3A000019,0x30000152,0x1240152,0x1240152,0x3A000019,0x30000152,0x30000152,0xFA340020,0xF2540055,0x600154,0xD80C0000,0x88140000,0x6A140000,0x5C200000,0x52080000,0xFE0C0032,0xBC000004,0xD00152,0x3A000019,
-0xD00152,0x9801A5,0x947C0000,0x687C0000,0x5A7C0000,0xE001A5,0x76440000,0x5A600000,0x1CC01A5,0x5A040000,0x4C0001A5,0xE001A5,0x76440000,0x5A600000,0x1CC01A5,0x5A040000,0x4C0001A5,0x1CC01A5,0x5A040000,0x4C0001A5,0x4C0001A5,0xE001A5,0x76440000,0x5A600000,0x1CC01A5,0x5A040000,0x4C0001A5,0x1CC01A5,0x5A040000,0x4C0001A5,0x4C0001A5,0x1CC01A5,
-0x5A040000,0x4C0001A5,0x4C0001A5,0x4C0001A5,0xFE500071,0xA401A5,0xFE8C0091,0xD4100000,0x98000000,0x70080000,0x5A280000,0x5800000D,0xFE2C0062,0xBC040002,0x5E300000,0x4C0001A5,0x14001A5,0x2C01A5,0x2C01A5,0x2C01A5,0x2C01A5,0x2C01A5,0x2C01A5,0x2C01A5,0x2C01A5,0x2C01A5,0x2C01A5,0x5C100001,0x5C100001,0x5C100001,0x5C100001,0x5C100001,
-0x5C100001,0x30100001,0x30100001,0x30100001,0x220C0002,0x4001A5,0x4001A5,0x4001A5,0x4001A5,0x4001A5,0x4001A5,0x2E000050,0x2E000050,0x2E000050,0x22000011,0x7C01A5,0x7C01A5,0x7C01A5,0x1C0000C1,0x140001A5,0xF61C0062,0x2C01A5,0x2C01A5,0xCC100001,0x90100001,0x70100001,0x70100001,0x4C100001,0xE0000041,0xA400000D,0x40080001,0x2E000050,
-0x5801A5,};
-static const uint32_t g_etc1_to_bc7_m6_table103[] = {
-0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x580000,
-0x580000,0x580000,0x580000,0xE000000,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x200000,0x200000,0x200000,0x2C0000,0x3C0000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x2800000,0x2800000,0x2800000,0x2800000,0x2800000,
-0x2800000,0x1080000,0x1080000,0x1080000,0x2A000001,0x2800000,0x2800000,0x2800000,0x2800000,0x2800000,0x2800000,0x1080000,0x1080000,0x1080000,0x2A000001,0x1080000,0x1080000,0x1080000,0x2A000001,0x2A000001,0x65C0000,0x580000,0x580000,0x4640000,0x26C0000,0x780000,0x780000,0x940000,0x4640000,0x26C0000,0xB80000,0x1080000,
-0xB80000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0xD00000,0xD00000,0xD00000,0x1A40000,0x1A40000,0x44000001,0xD00000,0xD00000,0xD00000,0x1A40000,0x1A40000,0x44000001,0x1A40000,0x1A40000,0x44000001,0x44000001,0xD00000,0xD00000,0xD00000,0x1A40000,0x1A40000,0x44000001,0x1A40000,0x1A40000,0x44000001,0x44000001,0x1A40000,
-0x1A40000,0x44000001,0x44000001,0x44000001,0x6A00000,0x2940000,0x8C0000,0x2BC0000,0xEC0000,0x1280000,0x1540000,0x3FC0000,0xB00000,0xD00000,0x1280000,0x44000001,0x1280000,0xC40001,0x3240000,0x17FC0000,0x62000000,0x3240000,0x17FC0000,0x62000000,0x17FC0000,0x62000000,0x62000000,0x3240000,0x17FC0000,0x62000000,0x17FC0000,0x62000000,
-0x62000000,0x17FC0000,0x62000000,0x62000000,0x62000000,0x3240000,0x17FC0000,0x62000000,0x17FC0000,0x62000000,0x62000000,0x17FC0000,0x62000000,0x62000000,0x62000000,0x17FC0000,0x62000000,0x62000000,0x62000000,0x62000000,0xF80000,0xD40000,0xD40000,0x14C0000,0x1E40000,0x3BFC0000,0x62000000,0x62000000,0x10C0000,0x1740000,0x59E40000,0x62000000,
-0x1A40000,0x700F1E,0xD25805ED,0x7E5405ED,0x625405ED,0xC23C034A,0x864001C5,0x66440286,0x6E3C034A,0x603801BD,0x543C034A,0xB62005EB,0x8C200154,0x6830020F,0x741801B6,0x60200006,0x542401BE,0x621C05EB,0x5A14020D,0x4E14028A,0x461C05EB,0xA80F1A,0x8C000615,0x622005EA,0x74000416,0x620001BA,0x5404034A,0x6200073B,0x5800028C,0x4E0002AB,0x4600062A,0x1580F1A,
-0x50000899,0x4A000746,0x3E000983,0x38000F1A,0xFE440322,0xFA640A2E,0xFE6C0B55,0xDC200002,0x9A1C0004,0x76200004,0x64280025,0x5E1C0023,0xFE1C02BE,0xD0040000,0x66100159,0x4E0002AB,0xF00F1A,0x8C05ED,0xB6740154,0x76740154,0x62700154,0xA45801A5,0x7C580002,0x62600029,0x665801A5,0x5C54004C,0x545801A5,0x2D005EA,0x88240153,0x62480152,0x7A0C01A5,0x60200005,
-0x543001A5,0x1AC05EA,0x5C0001A8,0x50000221,0x460005EA,0x2D005EA,0x88240153,0x62480152,0x7A0C01A5,0x60200005,0x543001A5,0x1AC05EA,0x5C0001A8,0x50000221,0x460005EA,0x1AC05EA,0x5C0001A8,0x50000221,0x460005EA,0x460005EA,0xFE500132,0xF67C03C5,0xFA8403AD,0xDC200001,0x9A1C0003,0x76200003,0x62300001,0x6008000C,0xFC300155,0xD0040000,0x68040152,0x50000221,
-0x12C05EA,0x5405ED,0x5405ED,0x5405ED,0x5405ED,0x963C01A5,0x963C01A5,0x963C01A5,0x583C01A5,0x583C01A5,0x443C01A6,0x8C200153,0x8C200153,0x8C200153,0x60200002,0x60200002,0x4628004B,0x4C200153,0x4C200153,0x401C002A,0x381C0153,0x8005EA,0x8005EA,0x8005EA,0x620001BA,0x620001BA,0x441401A6,0x520001E4,0x520001E4,0x4200003B,0x38000162,0x10005EA,
-0x10005EA,0x380002DE,0x32000303,0x2A0005EA,0xFC380111,0xFE4C0379,0x5405ED,0xE01C0001,0x94200002,0x74200002,0x6C20000B,0x581C0002,0xFE1400C8,0xD0040000,0x62140153,0x4200003B,0xB405EA,0x700154,0x700154,0x700154,0x700154,0x7A580000,0x7A580000,0x7A580000,0x52580000,0x52580000,0x44580001,0xA80152,0xA80152,0xA80152,0x5C280001,0x5C280001,
-0x44400001,0x1580152,0x1580152,0x44000005,0x38000152,0xA80152,0xA80152,0xA80152,0x5C280001,0x5C280001,0x44400001,0x1580152,0x1580152,0x44000005,0x38000152,0x1580152,0x1580152,0x44000005,0x38000152,0x38000152,0xF6480029,0xFA640055,0x700154,0xE01C0000,0x90240000,0x72240000,0x64300000,0x5A180000,0xF624003D,0xD0040000,0xF00152,0x44000005,
-0xF00152,0xA801A5,0x9C8C0000,0x708C0000,0x628C0000,0xF801A5,0x7E540000,0x62700000,0x1FC01A5,0x62140000,0x540001A5,0xF801A5,0x7E540000,0x62700000,0x1FC01A5,0x62140000,0x540001A5,0x1FC01A5,0x62140000,0x540001A5,0x540001A5,0xF801A5,0x7E540000,0x62700000,0x1FC01A5,0x62140000,0x540001A5,0x1FC01A5,0x62140000,0x540001A5,0x540001A5,0x1FC01A5,
-0x62140000,0x540001A5,0x540001A5,0x540001A5,0xFA640080,0xB401A5,0xF69C00A4,0xDC200000,0xA0100000,0x78180000,0x62380000,0x60000005,0xF4480071,0xD0040000,0x66400000,0x540001A5,0x16401A5,0x3C01A5,0x3C01A5,0x3C01A5,0x3C01A5,0x3C01A5,0x3C01A5,0x3C01A5,0x3C01A5,0x3C01A5,0x3C01A5,0x64200001,0x64200001,0x64200001,0x64200001,0x64200001,
-0x64200001,0x38200001,0x38200001,0x38200001,0x2A1C0002,0x5401A5,0x5401A5,0x5401A5,0x5401A5,0x5401A5,0x5401A5,0x3A000020,0x3A000020,0x3A000020,0x2A040001,0xAC01A5,0xAC01A5,0xAC01A5,0x26000092,0x1C0001A5,0xFE2C0062,0x3C01A5,0x3C01A5,0xD4200001,0x98200001,0x78200001,0x78200001,0x54200001,0xFA080029,0xCE040000,0x48180001,0x3A000020,
-0x7801A5,};
-static const uint32_t g_etc1_to_bc7_m6_table104[] = {
-0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x8C0000,
-0x8C0000,0x8C0000,0x8C0000,0x16000001,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x340000,0x340000,0x340000,0x2440000,0x640000,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x680001,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,
-0x9C0000,0x13C0000,0x13C0000,0x13C0000,0x34000000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x9C0000,0x13C0000,0x13C0000,0x13C0000,0x34000000,0x13C0000,0x13C0000,0x13C0000,0x34000000,0x34000000,0x700000,0x680001,0x680001,0x7C0000,0x840000,0x900000,0x900000,0xB00000,0x7C0000,0x840000,0xE00000,0x13C0000,
-0xE00000,0x9C0001,0x9C0001,0x9C0001,0x9C0001,0x2E80000,0x2E80000,0x2E80000,0x1DC0000,0x1DC0000,0x4E000000,0x2E80000,0x2E80000,0x2E80000,0x1DC0000,0x1DC0000,0x4E000000,0x1DC0000,0x1DC0000,0x4E000000,0x4E000000,0x2E80000,0x2E80000,0x2E80000,0x1DC0000,0x1DC0000,0x4E000000,0x1DC0000,0x1DC0000,0x4E000000,0x4E000000,0x1DC0000,
-0x1DC0000,0x4E000000,0x4E000000,0x4E000000,0xB80000,0xA80000,0x9C0001,0x2D40000,0x1080000,0x1500000,0x1800000,0x11F40000,0x2C40000,0x2E80000,0x1500000,0x4E000000,0x1500000,0xD80000,0x1400000,0x25F80000,0x6A000001,0x1400000,0x25F80000,0x6A000001,0x25F80000,0x6A000001,0x6A000001,0x1400000,0x25F80000,0x6A000001,0x25F80000,0x6A000001,
-0x6A000001,0x25F80000,0x6A000001,0x6A000001,0x6A000001,0x1400000,0x25F80000,0x6A000001,0x25F80000,0x6A000001,0x6A000001,0x25F80000,0x6A000001,0x6A000001,0x6A000001,0x25F80000,0x6A000001,0x6A000001,0x6A000001,0x6A000001,0x50C0000,0xAE40000,0xAE40000,0x16C0000,0x9F80000,0x47F80000,0x6A000001,0x6A000001,0x3240000,0x1940000,0x63D80000,0x6A000001,
-0x1CC0000,0x840F1A,0xDE6805EA,0x866805EA,0x6A6805EB,0xCC4C034A,0x8E5001C3,0x6E54028A,0x784C034A,0x684C01BE,0x5C4C034A,0xC23005EA,0x96300153,0x7040020D,0x7E2C01B2,0x6A300006,0x5E3401BD,0x6A3005EA,0x6224020F,0x58280286,0x4E3005ED,0xC40F1A,0x9E0005EB,0x6C3005EB,0x86000392,0x6C0801B6,0x5C18034A,0x740006B1,0x640001DC,0x5A000215,0x4E0005F1,0x18C0F1A,
-0x5C0007F7,0x50000662,0x4A0008D9,0x40000F1E,0xFE580372,0xF4780A82,0xF67C0B9A,0xE6300000,0xA2300003,0x80300002,0x6C380023,0x662C0025,0xFE3402F6,0xD6180002,0x7024015B,0x5A000215,0x1180F1A,0xA005EA,0xC0840152,0x80840152,0x6A840153,0xAC6C01A6,0x86680001,0x6C74002A,0x706801A6,0x6668004B,0x5C6801A6,0xEC05EA,0x90380153,0x6A5C0153,0x841C01A5,0x6A340002,
-0x5C4401A5,0x1E405EA,0x6600017D,0x5A0001F1,0x4E0005ED,0xEC05EA,0x90380153,0x6A5C0153,0x841C01A5,0x6A340002,0x5C4401A5,0x1E405EA,0x6600017D,0x5A0001F1,0x4E0005ED,0x1E405EA,0x6600017D,0x5A0001F1,0x4E0005ED,0x4E0005ED,0xFE640164,0xFE8C03CE,0xF49803D3,0xE6300000,0xA2300003,0x80300002,0x6C440002,0x6A1C000B,0xFE440171,0xD6180001,0x72140152,0x5A0001F1,
-0x15405EA,0x6805EA,0x6805EA,0x6805EA,0x6805EA,0xA24C01A5,0xA24C01A5,0xA24C01A5,0x624C01A5,0x624C01A5,0x4E4C01A5,0x96300152,0x96300152,0x96300152,0x68300005,0x68300005,0x503C004C,0x56300152,0x56300152,0x4A300029,0x40300154,0x29805EA,0x29805EA,0x29805EA,0x740001A5,0x740001A5,0x4E2401A5,0x5E00018B,0x5E00018B,0x4E000004,0x40080154,0x13805EA,
-0x13805EA,0x44000279,0x3C0002A5,0x320005ED,0xFC480129,0xF860039D,0x6805EA,0xE6300000,0xA0300002,0x80300002,0x7634000C,0x62300001,0xFE2800F2,0xD6180001,0x6C240152,0x4E000004,0xDC05EA,0x840152,0x840152,0x840152,0x840152,0x806C0001,0x806C0001,0x806C0001,0x5A6C0001,0x5A6C0001,0x4E680001,0xC40152,0xC40152,0xC40152,0x643C0001,0x643C0001,
-0x4E500000,0x18C0152,0x18C0152,0x4E000000,0x40000154,0xC40152,0xC40152,0xC40152,0x643C0001,0x643C0001,0x4E500000,0x18C0152,0x18C0152,0x4E000000,0x40000154,0x18C0152,0x18C0152,0x4E000000,0x40000154,0x40000154,0xFE580029,0xF4780062,0x840152,0xE6300000,0x98380000,0x7A380001,0x6E400000,0x622C0000,0xFE34003D,0xD6180000,0x1180152,0x4E000000,
-0x1180152,0xBC01A5,0xA4A00001,0x78A00001,0x6A9C0002,0x11401A5,0x86680000,0x6A840001,0xFF801A5,0x6A2C0001,0x5C0001A5,0x11401A5,0x86680000,0x6A840001,0xFF801A5,0x6A2C0001,0x5C0001A5,0xFF801A5,0x6A2C0001,0x5C0001A5,0x5C0001A5,0x11401A5,0x86680000,0x6A840001,0xFF801A5,0x6A2C0001,0x5C0001A5,0xFF801A5,0x6A2C0001,0x5C0001A5,0x5C0001A5,0xFF801A5,
-0x6A2C0001,0x5C0001A5,0x5C0001A5,0x5C0001A5,0xFE780080,0xC801A5,0xFEAC00AA,0xE2340000,0xA8240000,0x82280000,0x6A4C0001,0x6A000001,0xFC580071,0xD8180000,0x70500000,0x5C0001A5,0x18C01A5,0x4C01A5,0x4C01A5,0x4C01A5,0x4C01A5,0x4C01A5,0x4C01A5,0x4C01A5,0x4C01A5,0x4C01A5,0x4C01A5,0x6E300000,0x6E300000,0x6E300000,0x6E300000,0x6E300000,
-0x6E300000,0x42300000,0x42300000,0x42300000,0x34300000,0x7001A5,0x7001A5,0x7001A5,0x7001A5,0x7001A5,0x7001A5,0x4C000002,0x4C000002,0x4C000002,0x34140000,0xE401A5,0xE401A5,0xE401A5,0x30000061,0x260001A5,0xF8400071,0x4C01A5,0x4C01A5,0xE2300000,0xA4300000,0x84300000,0x84300000,0x5E300000,0xFC1C0032,0xCE180001,0x52280000,0x4C000002,
-0xA001A5,};
-static const uint32_t g_etc1_to_bc7_m6_table105[] = {
-0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0x25C0000,0xBC0000,
-0xBC0000,0xBC0000,0xBC0000,0x1E000001,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x440000,0x440000,0x440000,0x25C0000,0x880000,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0x780001,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,
-0xB40000,0x1700000,0x1700000,0x1700000,0x3C000000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0x1700000,0x1700000,0x1700000,0x3C000000,0x1700000,0x1700000,0x1700000,0x3C000000,0x3C000000,0x8800000,0x780001,0x780001,0x28C0000,0x980000,0x2A40000,0x2A40000,0xCC0000,0x28C0000,0x980000,0x1000000,0x1700000,
-0x1000000,0xAC0001,0xAC0001,0xAC0001,0xAC0001,0x3000000,0x3000000,0x3000000,0x5FC0000,0x5FC0000,0x56000000,0x3000000,0x3000000,0x3000000,0x5FC0000,0x5FC0000,0x56000000,0x5FC0000,0x5FC0000,0x56000000,0x56000000,0x3000000,0x3000000,0x3000000,0x5FC0000,0x5FC0000,0x56000000,0x5FC0000,0x5FC0000,0x56000000,0x56000000,0x5FC0000,
-0x5FC0000,0x56000000,0x56000000,0x56000000,0x4C80000,0x4B80000,0xAC0001,0xEC0000,0x1240000,0x1700000,0x1A80000,0x1BF80000,0x2D80000,0x3000000,0x1700000,0x56000000,0x1700000,0xE80000,0x1580000,0x31F80000,0x72000001,0x1580000,0x31F80000,0x72000001,0x31F80000,0x72000001,0x72000001,0x1580000,0x31F80000,0x72000001,0x31F80000,0x72000001,
-0x72000001,0x31F80000,0x72000001,0x72000001,0x72000001,0x1580000,0x31F80000,0x72000001,0x31F80000,0x72000001,0x72000001,0x31F80000,0x72000001,0x72000001,0x72000001,0x31F80000,0x72000001,0x72000001,0x72000001,0x72000001,0x5200000,0xF80000,0xF80000,0x1840000,0x15FC0000,0x51F80000,0x72000001,0x72000001,0x13C0000,0x1B40000,0x6BE80000,0x72000001,
-0x1EC0000,0x940F1A,0xE67805EA,0x8E7805EA,0x727805EB,0xD45C034A,0x966001C3,0x7664028A,0x805C034A,0x705C01BE,0x645C034A,0xCA4005EA,0x9E400153,0x7850020D,0x863C01B2,0x72400006,0x664401BD,0x724005EA,0x6A34020F,0x60380286,0x564005ED,0xDC0F1A,0xA61005EB,0x744005EB,0x9200035A,0x741801B6,0x6428034A,0x80000651,0x7000017C,0x620001D5,0x580805ED,0x1BC0F1A,
-0x66000786,0x5C0005BA,0x50000861,0x48000F1E,0xFE6403C8,0xFC880A82,0xFE8C0B9A,0xEE400000,0xAA400003,0x88400002,0x74480023,0x6E3C0025,0xFE440361,0xDE280002,0x7834015B,0x620001D5,0x1380F1A,0xB005EA,0xC8940152,0x88940152,0x72940153,0xB47C01A6,0x8E780001,0x7484002A,0x787801A6,0x6E78004B,0x647801A6,0x10405EA,0x98480153,0x726C0153,0x8C2C01A5,0x72440002,
-0x645401A5,0x7FC05EA,0x70000163,0x620001D5,0x560005ED,0x10405EA,0x98480153,0x726C0153,0x8C2C01A5,0x72440002,0x645401A5,0x7FC05EA,0x70000163,0x620001D5,0x560005ED,0x7FC05EA,0x70000163,0x620001D5,0x560005ED,0x560005ED,0xFE780179,0xF8A003EA,0xFCA803D3,0xEE400000,0xAA400003,0x88400002,0x74540002,0x722C000B,0xFE5C0189,0xDE280001,0x7A240152,0x620001D5,
-0x17405EA,0x7805EA,0x7805EA,0x7805EA,0x7805EA,0xAA5C01A5,0xAA5C01A5,0xAA5C01A5,0x6A5C01A5,0x6A5C01A5,0x565C01A5,0x9E400152,0x9E400152,0x9E400152,0x70400005,0x70400005,0x584C004C,0x5E400152,0x5E400152,0x52400029,0x48400154,0x2B005EA,0x2B005EA,0x2B005EA,0x7C1001A5,0x7C1001A5,0x563401A5,0x6A000163,0x6A000163,0x56080002,0x48180154,0x16805EA,
-0x16805EA,0x4E000239,0x44000248,0x3A0005ED,0xFE580149,0xFE6C03A5,0x7805EA,0xEE400000,0xA8400002,0x88400002,0x7E44000C,0x6A400001,0xFE3C010A,0xDE280001,0x74340152,0x56080002,0xFC05EA,0x940152,0x940152,0x940152,0x940152,0x887C0001,0x887C0001,0x887C0001,0x627C0001,0x627C0001,0x56780001,0xDC0152,0xDC0152,0xDC0152,0x6C4C0001,0x6C4C0001,
-0x56600000,0x1BC0152,0x1BC0152,0x56100000,0x48000154,0xDC0152,0xDC0152,0xDC0152,0x6C4C0001,0x6C4C0001,0x56600000,0x1BC0152,0x1BC0152,0x56100000,0x48000154,0x1BC0152,0x1BC0152,0x56100000,0x48000154,0x48000154,0xFA6C0032,0xFC880062,0x940152,0xEE400000,0xA0480000,0x82480001,0x76500000,0x6A3C0000,0xFA48004A,0xDE280000,0x1380152,0x56100000,
-0x1380152,0xCC01A5,0xACB00001,0x80B00001,0x72AC0002,0x12C01A5,0x8E780000,0x72940001,0x1BF801A5,0x723C0001,0x640001A5,0x12C01A5,0x8E780000,0x72940001,0x1BF801A5,0x723C0001,0x640001A5,0x1BF801A5,0x723C0001,0x640001A5,0x640001A5,0x12C01A5,0x8E780000,0x72940001,0x1BF801A5,0x723C0001,0x640001A5,0x1BF801A5,0x723C0001,0x640001A5,0x640001A5,0x1BF801A5,
-0x723C0001,0x640001A5,0x640001A5,0x640001A5,0xFA8C0091,0xD801A5,0xF8C000B5,0xEA440000,0xB0340000,0x8A380000,0x725C0001,0x72100001,0xFC6C0082,0xE0280000,0x78600000,0x640001A5,0x1AC01A5,0x5C01A5,0x5C01A5,0x5C01A5,0x5C01A5,0x5C01A5,0x5C01A5,0x5C01A5,0x5C01A5,0x5C01A5,0x5C01A5,0x76400000,0x76400000,0x76400000,0x76400000,0x76400000,
-0x76400000,0x4A400000,0x4A400000,0x4A400000,0x3C400000,0x8801A5,0x8801A5,0x8801A5,0x8801A5,0x8801A5,0x8801A5,0x58080000,0x58080000,0x58080000,0x3C240000,0x11401A5,0x11401A5,0x11401A5,0x38000034,0x2E0001A5,0xFE4C0075,0x5C01A5,0x5C01A5,0xEA400000,0xAC400000,0x8C400000,0x8C400000,0x66400000,0xF830003D,0xD6280001,0x5A380000,0x58080000,
-0xC001A5,};
-static const uint32_t g_etc1_to_bc7_m6_table106[] = {
-0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0x2740000,0xF00000,
-0xF00000,0xF00000,0xF00000,0x26000001,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x2540000,0x2540000,0x2540000,0x2740000,0xA80000,0x880001,0x880001,0x880001,0x880001,0x880001,0x880001,0x880001,0x880001,0x880001,0x880001,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,
-0xCC0000,0x1A00000,0x1A00000,0x1A00000,0x44000000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0x1A00000,0x1A00000,0x1A00000,0x44000000,0x1A00000,0x1A00000,0x1A00000,0x44000000,0x44000000,0x940000,0x880001,0x880001,0xA00000,0xAC0000,0xBC0000,0xBC0000,0xE80000,0xA00000,0xAC0000,0x1240000,0x1A00000,
-0x1240000,0xBC0001,0xBC0001,0xBC0001,0xBC0001,0x3180000,0x3180000,0x3180000,0x11FC0000,0x11FC0000,0x5E000000,0x3180000,0x3180000,0x3180000,0x11FC0000,0x11FC0000,0x5E000000,0x11FC0000,0x11FC0000,0x5E000000,0x5E000000,0x3180000,0x3180000,0x3180000,0x11FC0000,0x11FC0000,0x5E000000,0x11FC0000,0x11FC0000,0x5E000000,0x5E000000,0x11FC0000,
-0x11FC0000,0x5E000000,0x5E000000,0x5E000000,0xDC0000,0xCC80000,0xBC0001,0x3000000,0x1400000,0x1940000,0x1D00000,0x25FC0000,0x2EC0000,0x3180000,0x1940000,0x5E000000,0x1940000,0xF80000,0x1700000,0x3DF80000,0x7A000001,0x1700000,0x3DF80000,0x7A000001,0x3DF80000,0x7A000001,0x7A000001,0x1700000,0x3DF80000,0x7A000001,0x3DF80000,0x7A000001,
-0x7A000001,0x3DF80000,0x7A000001,0x7A000001,0x7A000001,0x1700000,0x3DF80000,0x7A000001,0x3DF80000,0x7A000001,0x7A000001,0x3DF80000,0x7A000001,0x7A000001,0x7A000001,0x3DF80000,0x7A000001,0x7A000001,0x7A000001,0x7A000001,0x5340000,0x1080000,0x1080000,0x1A00000,0x23FC0000,0x5BF80000,0x7A000001,0x7A000001,0x1500000,0x1D00000,0x73F80000,0x7A000001,
-0x9FC0000,0xA40F1A,0xEE8805EA,0x968805EA,0x7A8805EB,0xDC6C034A,0x9E7001C3,0x7E74028A,0x886C034A,0x786C01BE,0x6C6C034A,0xD25005EA,0xA6500153,0x8060020D,0x8E4C01B2,0x7A500006,0x6E5401BD,0x7A5005EA,0x7244020F,0x68480286,0x5E5005ED,0xF40F1A,0xAE2005EB,0x7C5005EB,0xA004034A,0x7C2801B6,0x6C38034A,0x8C000611,0x7A000155,0x6A0801C5,0x601805ED,0x1F00F1A,
-0x6C000716,0x66000542,0x5C0007E9,0x50000F1E,0xFE780419,0xF4980ADA,0xF8A00BDB,0xF6500000,0xB2500003,0x90500002,0x7C580023,0x764C0025,0xFE5C03A2,0xE6380002,0x8044015B,0x6A0801C5,0x15C0F1A,0xC005EA,0xD0A40152,0x90A40152,0x7AA40153,0xBC8C01A6,0x96880001,0x7C94002A,0x808801A6,0x7688004B,0x6C8801A6,0x11C05EA,0xA0580153,0x7A7C0153,0x943C01A5,0x7A540002,
-0x6C6401A5,0x13FC05EA,0x7A000155,0x6C0001B5,0x5E0005ED,0x11C05EA,0xA0580153,0x7A7C0153,0x943C01A5,0x7A540002,0x6C6401A5,0x13FC05EA,0x7A000155,0x6C0001B5,0x5E0005ED,0x13FC05EA,0x7A000155,0x6C0001B5,0x5E0005ED,0x5E0005ED,0xFC9001A9,0xFEAC03FE,0xF4B803FE,0xF6500000,0xB2500003,0x90500002,0x7C640002,0x7A3C000B,0xFE7001C3,0xE6380001,0x82340152,0x6C0001B5,
-0x19805EA,0x8805EA,0x8805EA,0x8805EA,0x8805EA,0xB26C01A5,0xB26C01A5,0xB26C01A5,0x726C01A5,0x726C01A5,0x5E6C01A5,0xA6500152,0xA6500152,0xA6500152,0x78500005,0x78500005,0x605C004C,0x66500152,0x66500152,0x5A500029,0x50500154,0xC805EA,0xC805EA,0xC805EA,0x842001A5,0x842001A5,0x5E4401A5,0x78040153,0x78040153,0x5E180002,0x50280154,0x19805EA,
-0x19805EA,0x560001FD,0x4E00020D,0x420005ED,0xFE680164,0xF88003C2,0x8805EA,0xF6500000,0xB0500002,0x90500002,0x8654000C,0x72500001,0xFC4C0123,0xE6380001,0x7C440152,0x5E180002,0x12005EA,0xA40152,0xA40152,0xA40152,0xA40152,0x908C0001,0x908C0001,0x908C0001,0x6A8C0001,0x6A8C0001,0x5E880001,0xF40152,0xF40152,0xF40152,0x745C0001,0x745C0001,
-0x5E700000,0x1F00152,0x1F00152,0x5E200000,0x50000154,0xF40152,0xF40152,0xF40152,0x745C0001,0x745C0001,0x5E700000,0x1F00152,0x1F00152,0x5E200000,0x50000154,0x1F00152,0x1F00152,0x5E200000,0x50000154,0x50000154,0xF680003D,0xF4980071,0xA40152,0xF6500000,0xA8580000,0x8A580001,0x7E600000,0x724C0000,0xF2600055,0xE6380000,0x15C0152,0x5E200000,
-0x15C0152,0xDC01A5,0xB4C00001,0x88C00001,0x7ABC0002,0x14401A5,0x96880000,0x7AA40001,0x27F801A5,0x7A4C0001,0x6C0001A5,0x14401A5,0x96880000,0x7AA40001,0x27F801A5,0x7A4C0001,0x6C0001A5,0x27F801A5,0x7A4C0001,0x6C0001A5,0x6C0001A5,0x14401A5,0x96880000,0x7AA40001,0x27F801A5,0x7A4C0001,0x6C0001A5,0x27F801A5,0x7A4C0001,0x6C0001A5,0x6C0001A5,0x27F801A5,
-0x7A4C0001,0x6C0001A5,0x6C0001A5,0x6C0001A5,0xFAA000A2,0xE801A5,0xFECC00C1,0xF2540000,0xB8440000,0x92480000,0x7A6C0001,0x7A200001,0xF6880091,0xE8380000,0x80700000,0x6C0001A5,0x1D001A5,0x6C01A5,0x6C01A5,0x6C01A5,0x6C01A5,0x6C01A5,0x6C01A5,0x6C01A5,0x6C01A5,0x6C01A5,0x6C01A5,0x7E500000,0x7E500000,0x7E500000,0x7E500000,0x7E500000,
-0x7E500000,0x52500000,0x52500000,0x52500000,0x44500000,0xA001A5,0xA001A5,0xA001A5,0xA001A5,0xA001A5,0xA001A5,0x60180000,0x60180000,0x60180000,0x44340000,0x14401A5,0x14401A5,0x14401A5,0x4200001D,0x360001A5,0xF8600080,0x6C01A5,0x6C01A5,0xF2500000,0xB4500000,0x94500000,0x94500000,0x6E500000,0xFE3C0041,0xDE380001,0x62480000,0x60180000,
-0xE401A5,};
-static const uint32_t g_etc1_to_bc7_m6_table107[] = {
-0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x1200000,
-0x1200000,0x1200000,0x1200000,0x2E000001,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0xA640000,0xA640000,0xA640000,0x28C0000,0xCC0000,0x980001,0x980001,0x980001,0x980001,0x980001,0x980001,0x980001,0x980001,0x980001,0x980001,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,
-0xE40000,0x1D00000,0x1D00000,0x1D00000,0x4C000000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0x1D00000,0x1D00000,0x1D00000,0x4C000000,0x1D00000,0x1D00000,0x1D00000,0x4C000000,0x4C000000,0xA40000,0x980001,0x980001,0xB40000,0xC00000,0xD00000,0xD00000,0x3000000,0xB40000,0xC00000,0x1480000,0x1D00000,
-0x1480000,0xCC0001,0xCC0001,0xCC0001,0xCC0001,0x3300000,0x3300000,0x3300000,0x1DFC0000,0x1DFC0000,0x66000000,0x3300000,0x3300000,0x3300000,0x1DFC0000,0x1DFC0000,0x66000000,0x1DFC0000,0x1DFC0000,0x66000000,0x66000000,0x3300000,0x3300000,0x3300000,0x1DFC0000,0x1DFC0000,0x66000000,0x1DFC0000,0x1DFC0000,0x66000000,0x66000000,0x1DFC0000,
-0x1DFC0000,0x66000000,0x66000000,0x66000000,0xF00000,0xDC0000,0xCC0001,0x1180000,0x1580000,0x1B40000,0x1F80000,0x31F80000,0x3000000,0x3300000,0x1B40000,0x66000000,0x1B40000,0x1080000,0x1880000,0x49F80000,0x82000001,0x1880000,0x49F80000,0x82000001,0x49F80000,0x82000001,0x82000001,0x1880000,0x49F80000,0x82000001,0x49F80000,0x82000001,
-0x82000001,0x49F80000,0x82000001,0x82000001,0x82000001,0x1880000,0x49F80000,0x82000001,0x49F80000,0x82000001,0x82000001,0x49F80000,0x82000001,0x82000001,0x82000001,0x49F80000,0x82000001,0x82000001,0x82000001,0x82000001,0x14C0000,0x5180000,0x5180000,0x1BC0000,0x31FC0000,0x65F80000,0x82000001,0x82000001,0x1680000,0x1F00000,0x7DCC0000,0x82000001,
-0x19FC0000,0xB40F1A,0xF69805EA,0x9E9805EA,0x829805EB,0xE47C034A,0xA68001C3,0x8684028A,0x907C034A,0x807C01BE,0x747C034A,0xDA6005EA,0xAE600153,0x8870020D,0x965C01B2,0x82600006,0x766401BD,0x826005EA,0x7A54020F,0x70580286,0x666005ED,0x10C0F1A,0xB63005EB,0x846005EB,0xA814034A,0x843801B6,0x7448034A,0x980005F1,0x820C0154,0x721801C5,0x682805ED,0xBF80F1A,
-0x780006AE,0x6C0004B6,0x64000795,0x58000F1E,0xFE8C046E,0xFCA80ADA,0xFEAC0BDF,0xFE600000,0xBA600003,0x98600002,0x84680023,0x7E5C0025,0xFE700403,0xEE480002,0x8854015B,0x721801C5,0x17C0F1A,0xD005EA,0xD8B40152,0x98B40152,0x82B40153,0xC49C01A6,0x9E980001,0x84A4002A,0x889801A6,0x7E98004B,0x749801A6,0x13405EA,0xA8680153,0x828C0153,0x9C4C01A5,0x82640002,
-0x747401A5,0x1FF805EA,0x820C0153,0x740001A9,0x660005ED,0x13405EA,0xA8680153,0x828C0153,0x9C4C01A5,0x82640002,0x747401A5,0x1FF805EA,0x820C0153,0x740001A9,0x660005ED,0x1FF805EA,0x820C0153,0x740001A9,0x660005ED,0x660005ED,0xFEA001C8,0xFAC40412,0xFCC803FE,0xFE600000,0xBA600003,0x98600002,0x84740002,0x824C000B,0xFC8401E2,0xEE480001,0x8A440152,0x740001A9,
-0x1B805EA,0x9805EA,0x9805EA,0x9805EA,0x9805EA,0xBA7C01A5,0xBA7C01A5,0xBA7C01A5,0x7A7C01A5,0x7A7C01A5,0x667C01A5,0xAE600152,0xAE600152,0xAE600152,0x80600005,0x80600005,0x686C004C,0x6E600152,0x6E600152,0x62600029,0x58600154,0xE005EA,0xE005EA,0xE005EA,0x8C3001A5,0x8C3001A5,0x665401A5,0x80140153,0x80140153,0x66280002,0x58380154,0x1CC05EA,
-0x1CC05EA,0x600001D5,0x560001C8,0x4A0005ED,0xFA7C0191,0xFE8C03CE,0x9805EA,0xFE600000,0xB8600002,0x98600002,0x8E64000C,0x7A600001,0xFC600152,0xEE480001,0x84540152,0x66280002,0x14005EA,0xB40152,0xB40152,0xB40152,0xB40152,0x989C0001,0x989C0001,0x989C0001,0x729C0001,0x729C0001,0x66980001,0x10C0152,0x10C0152,0x10C0152,0x7C6C0001,0x7C6C0001,
-0x66800000,0xBF80152,0xBF80152,0x66300000,0x58000154,0x10C0152,0x10C0152,0x10C0152,0x7C6C0001,0x7C6C0001,0x66800000,0xBF80152,0xBF80152,0x66300000,0x58000154,0xBF80152,0xBF80152,0x66300000,0x58000154,0x58000154,0xFE90003D,0xFCA80071,0xB40152,0xFE600000,0xB0680000,0x92680001,0x86700000,0x7A5C0000,0xFA700055,0xEE480000,0x17C0152,0x66300000,
-0x17C0152,0xEC01A5,0xBCD00001,0x90D00001,0x82CC0002,0x15C01A5,0x9E980000,0x82B40001,0x33F801A5,0x825C0001,0x740001A5,0x15C01A5,0x9E980000,0x82B40001,0x33F801A5,0x825C0001,0x740001A5,0x33F801A5,0x825C0001,0x740001A5,0x740001A5,0x15C01A5,0x9E980000,0x82B40001,0x33F801A5,0x825C0001,0x740001A5,0x33F801A5,0x825C0001,0x740001A5,0x740001A5,0x33F801A5,
-0x825C0001,0x740001A5,0x740001A5,0x740001A5,0xFCB000A4,0xFC01A5,0xF8E000CA,0xFA640000,0xC0540000,0x9A580000,0x827C0001,0x82300001,0xFE980091,0xF0480000,0x88800000,0x740001A5,0x1F001A5,0x7C01A5,0x7C01A5,0x7C01A5,0x7C01A5,0x7C01A5,0x7C01A5,0x7C01A5,0x7C01A5,0x7C01A5,0x7C01A5,0x86600000,0x86600000,0x86600000,0x86600000,0x86600000,
-0x86600000,0x5A600000,0x5A600000,0x5A600000,0x4C600000,0xB801A5,0xB801A5,0xB801A5,0xB801A5,0xB801A5,0xB801A5,0x68280000,0x68280000,0x68280000,0x4C440000,0x17401A5,0x17401A5,0x17401A5,0x4A000008,0x3E0001A5,0xFE6C0088,0x7C01A5,0x7C01A5,0xFA600000,0xBC600000,0x9C600000,0x9C600000,0x76600000,0xFA50004A,0xE6480001,0x6A580000,0x68280000,
-0x10801A5,};
-static const uint32_t g_etc1_to_bc7_m6_table108[] = {
-0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0x1580000,
-0x1580000,0x1580000,0x1580000,0x38000000,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x4780000,0x4780000,0x4780000,0xA80000,0xF00000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0x1000000,0x1000000,0x1000000,0x1000000,0x1000000,
-0x1000000,0x5F80000,0x5F80000,0x5F80000,0x54000001,0x1000000,0x1000000,0x1000000,0x1000000,0x1000000,0x1000000,0x5F80000,0x5F80000,0x5F80000,0x54000001,0x5F80000,0x5F80000,0x5F80000,0x54000001,0x54000001,0xB80000,0xAC0000,0xAC0000,0xC80000,0xD80000,0x2E80000,0x2E80000,0x1200000,0xC80000,0xD80000,0x16C0000,0x5F80000,
-0x16C0000,0xE00000,0xE00000,0xE00000,0xE00000,0x14C0000,0x14C0000,0x14C0000,0x2BF80000,0x2BF80000,0x6E000001,0x14C0000,0x14C0000,0x14C0000,0x2BF80000,0x2BF80000,0x6E000001,0x2BF80000,0x2BF80000,0x6E000001,0x6E000001,0x14C0000,0x14C0000,0x14C0000,0x2BF80000,0x2BF80000,0x6E000001,0x2BF80000,0x2BF80000,0x6E000001,0x6E000001,0x2BF80000,
-0x2BF80000,0x6E000001,0x6E000001,0x6E000001,0x1040000,0xEEC0000,0xE00000,0x1300000,0x1780000,0x1DC0000,0xFFC0000,0x3DF80000,0x1180000,0x14C0000,0x1DC0000,0x6E000001,0x1DC0000,0x1180001,0x1A40000,0x57F80000,0x8C000000,0x1A40000,0x57F80000,0x8C000000,0x57F80000,0x8C000000,0x8C000000,0x1A40000,0x57F80000,0x8C000000,0x57F80000,0x8C000000,
-0x8C000000,0x57F80000,0x8C000000,0x8C000000,0x8C000000,0x1A40000,0x57F80000,0x8C000000,0x57F80000,0x8C000000,0x8C000000,0x57F80000,0x8C000000,0x8C000000,0x8C000000,0x57F80000,0x8C000000,0x8C000000,0x8C000000,0x8C000000,0x3600000,0x12C0000,0x12C0000,0x1D80000,0x3FFC0000,0x71F40000,0x8C000000,0x8C000000,0x1800000,0xDFC0000,0x85FC0000,0x8C000000,
-0x29FC0000,0xC40F1E,0xFCAC05ED,0xA8A805ED,0x8CA805ED,0xEC90034A,0xB09401C5,0x90980286,0x9890034A,0x8A8C01BD,0x7E90034A,0xE07405EB,0xB6740154,0x9284020F,0x9E6C01B6,0x8A740006,0x7E7801BE,0x8C7005EB,0x8468020D,0x7868028A,0x707005EB,0x3240F1A,0xC04005EB,0x8C7405EA,0xB224034A,0x8E4C01B2,0x7E58034A,0xA40C05EB,0x8C1C0153,0x7C2C01C3,0x703C05EA,0x17FC0F1A,
-0x8400065A,0x7800043A,0x6C00071A,0x62000F1A,0xFEA004CC,0xF6BC0B32,0xF8C00C1E,0xFE74000E,0xC4700004,0xA0740004,0x8E7C0025,0x88700023,0xFE800477,0xFA580000,0x90640159,0x7C2C01C3,0x1A40F1A,0xE005ED,0xE0C80154,0xA0C80154,0x8CC40154,0xCEAC01A5,0xA6AC0002,0x8CB40029,0x90AC01A5,0x86A8004C,0x7EAC01A5,0x15005EA,0xB2780153,0x8C9C0152,0xA46001A5,0x8A740005,
-0x7E8401A5,0x2DF805EA,0x8C180152,0x7E0401A5,0x700005EA,0x15005EA,0xB2780153,0x8C9C0152,0xA46001A5,0x8A740005,0x7E8401A5,0x2DF805EA,0x8C180152,0x7E0401A5,0x700005EA,0x2DF805EA,0x8C180152,0x7E0401A5,0x700005EA,0x700005EA,0xFEB401E6,0xF2D4043D,0xF6DC0428,0xFE780005,0xC4700003,0xA0740003,0x8C840001,0x8A5C000C,0xFE980202,0xFA580000,0x92580152,0x7E0401A5,
-0x1E005EA,0xA805ED,0xA805ED,0xA805ED,0xA805ED,0xC09001A5,0xC09001A5,0xC09001A5,0x829001A5,0x829001A5,0x6E9001A6,0xB6740153,0xB6740153,0xB6740153,0x8A740002,0x8A740002,0x707C004B,0x76740153,0x76740153,0x6A70002A,0x62700153,0xFC05EA,0xFC05EA,0xFC05EA,0x964001A5,0x964001A5,0x6E6801A6,0x88280153,0x88280153,0x703C0001,0x62480152,0x3F805EA,
-0x3F805EA,0x6C0001B2,0x6000019A,0x540005EA,0xFE9001AE,0xFAA403EA,0xA805ED,0xFE740005,0xBE740002,0x9E740002,0x9674000B,0x82700002,0xFE74016D,0xFA580000,0x8C680153,0x703C0001,0x16805EA,0xC40154,0xC40154,0xC40154,0xC40154,0xA4AC0000,0xA4AC0000,0xA4AC0000,0x7CAC0000,0x7CAC0000,0x6EAC0001,0x3240152,0x3240152,0x3240152,0x867C0001,0x867C0001,
-0x6E940001,0x17FC0152,0x17FC0152,0x6E440001,0x62000152,0x3240152,0x3240152,0x3240152,0x867C0001,0x867C0001,0x6E940001,0x17FC0152,0x17FC0152,0x6E440001,0x62000152,0x17FC0152,0x17FC0152,0x6E440001,0x62000152,0x62000152,0xFEA0004A,0xF6BC0080,0xC40154,0xFE780001,0xBA780000,0x9C780000,0x8E840000,0x846C0000,0xF8880062,0xFA580000,0x1A40152,0x6E440001,
-0x1A40152,0xFC01A5,0xC6E00000,0x9AE00000,0x8CE00000,0x17801A5,0xA8A80000,0x8CC40000,0x3FFC01A5,0x8C680000,0x7E0001A5,0x17801A5,0xA8A80000,0x8CC40000,0x3FFC01A5,0x8C680000,0x7E0001A5,0x3FFC01A5,0x8C680000,0x7E0001A5,0x7E0001A5,0x17801A5,0xA8A80000,0x8CC40000,0x3FFC01A5,0x8C680000,0x7E0001A5,0x3FFC01A5,0x8C680000,0x7E0001A5,0x7E0001A5,0x3FFC01A5,
-0x8C680000,0x7E0001A5,0x7E0001A5,0x7E0001A5,0xFAC800B5,0x10C01A5,0xF2F400DD,0xFC7C0002,0xCA640000,0xA26C0000,0x8C8C0000,0x8C3C0000,0xFEAC00A4,0xFA580000,0x90940000,0x7E0001A5,0xDFC01A5,0x9001A5,0x9001A5,0x9001A5,0x9001A5,0x9001A5,0x9001A5,0x9001A5,0x9001A5,0x9001A5,0x9001A5,0x8E740001,0x8E740001,0x8E740001,0x8E740001,0x8E740001,
-0x8E740001,0x62740001,0x62740001,0x62740001,0x54700002,0xD401A5,0xD401A5,0xD401A5,0xD401A5,0xD401A5,0xD401A5,0x703C0000,0x703C0000,0x703C0000,0x54580001,0x1AC01A5,0x1AC01A5,0x1AC01A5,0x54000001,0x460001A5,0xFA840091,0x9001A5,0x9001A5,0xFE740001,0xC2740001,0xA2740001,0xA2740001,0x7E740001,0xF8680055,0xF8580000,0x726C0001,0x703C0000,
-0x12C01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table109[] = {
-0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0x1880000,
-0x1880000,0x1880000,0x1880000,0x40000000,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0x800001,0xC880000,0xC880000,0xC880000,0xC00000,0x1140000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,
-0x1180000,0x11F80000,0x11F80000,0x11F80000,0x5C000001,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x11F80000,0x11F80000,0x11F80000,0x5C000001,0x11F80000,0x11F80000,0x11F80000,0x5C000001,0x5C000001,0xC80000,0xBC0000,0xBC0000,0x4D80000,0xEC0000,0x1000000,0x1000000,0x13C0000,0x4D80000,0xEC0000,0x1900000,0x11F80000,
-0x1900000,0xF00000,0xF00000,0xF00000,0xF00000,0x1640000,0x1640000,0x1640000,0x37F80000,0x37F80000,0x76000001,0x1640000,0x1640000,0x1640000,0x37F80000,0x37F80000,0x76000001,0x37F80000,0x37F80000,0x76000001,0x76000001,0x1640000,0x1640000,0x1640000,0x37F80000,0x37F80000,0x76000001,0x37F80000,0x37F80000,0x76000001,0x76000001,0x37F80000,
-0x37F80000,0x76000001,0x76000001,0x76000001,0x1180000,0x1000000,0xF00000,0x3440000,0x1940000,0x1FC0000,0x1DF80000,0x47FC0000,0x12C0000,0x1640000,0x1FC0000,0x76000001,0x1FC0000,0x1280001,0x1BC0000,0x61FC0000,0x94000000,0x1BC0000,0x61FC0000,0x94000000,0x61FC0000,0x94000000,0x94000000,0x1BC0000,0x61FC0000,0x94000000,0x61FC0000,0x94000000,
-0x94000000,0x61FC0000,0x94000000,0x94000000,0x94000000,0x1BC0000,0x61FC0000,0x94000000,0x61FC0000,0x94000000,0x94000000,0x61FC0000,0x94000000,0x94000000,0x94000000,0x61FC0000,0x94000000,0x94000000,0x94000000,0x94000000,0x3740000,0x73C0000,0x73C0000,0x1F40000,0x4DFC0000,0x7BF40000,0x94000000,0x94000000,0x1940000,0x1DFC0000,0x8FD00000,0x94000000,
-0x39FC0000,0xD40F1E,0xFEBC05F1,0xB0B805ED,0x94B805ED,0xF4A0034A,0xB8A401C5,0x98A80286,0xA0A0034A,0x929C01BD,0x86A0034A,0xE88405EB,0xBE840154,0x9A94020F,0xA67C01B6,0x92840006,0x868801BE,0x948005EB,0x8C78020D,0x8078028A,0x788005EB,0x33C0F1A,0xC85005EB,0x948405EA,0xBA34034A,0x965C01B2,0x8668034A,0xAC1C05EB,0x942C0153,0x843C01C3,0x784C05EA,0x23FC0F1A,
-0x8E000629,0x820003F2,0x760006D7,0x6A000F1A,0xFEB40537,0xFECC0B32,0xFECC0C36,0xFE880026,0xCC800004,0xA8840004,0x968C0025,0x90800023,0xFE9804C6,0xFC6C0006,0x98740159,0x843C01C3,0x1C80F1A,0xF005ED,0xE8D80154,0xA8D80154,0x94D40154,0xD6BC01A5,0xAEBC0002,0x94C40029,0x98BC01A5,0x8EB8004C,0x86BC01A5,0x16805EA,0xBA880153,0x94AC0152,0xAC7001A5,0x92840005,
-0x869401A5,0x39F805EA,0x94280152,0x861401A5,0x780005EA,0x16805EA,0xBA880153,0x94AC0152,0xAC7001A5,0x92840005,0x869401A5,0x39F805EA,0x94280152,0x861401A5,0x780005EA,0x39F805EA,0x94280152,0x861401A5,0x780005EA,0x780005EA,0xFAC80226,0xFAE4043D,0xFEEC0428,0xFC900012,0xCC800003,0xA8840003,0x94940001,0x926C000C,0xFEAC0244,0xFE6C0002,0x9A680152,0x861401A5,
-0x3FC05EA,0xB805ED,0xB805ED,0xB805ED,0xB805ED,0xC8A001A5,0xC8A001A5,0xC8A001A5,0x8AA001A5,0x8AA001A5,0x76A001A6,0xBE840153,0xBE840153,0xBE840153,0x92840002,0x92840002,0x788C004B,0x7E840153,0x7E840153,0x7280002A,0x6A800153,0x11405EA,0x11405EA,0x11405EA,0x9E5001A5,0x9E5001A5,0x767801A6,0x90380153,0x90380153,0x784C0001,0x6A580152,0xFF805EA,
-0xFF805EA,0x760001A6,0x6800017E,0x5C0005EA,0xFEA001CB,0xFEAC040A,0xB805ED,0xFE88000D,0xC6840002,0xA6840002,0x9E84000B,0x8A800002,0xFE8001A3,0xFA6C0002,0x94780153,0x784C0001,0x18C05EA,0xD40154,0xD40154,0xD40154,0xD40154,0xACBC0000,0xACBC0000,0xACBC0000,0x84BC0000,0x84BC0000,0x76BC0001,0x33C0152,0x33C0152,0x33C0152,0x8E8C0001,0x8E8C0001,
-0x76A40001,0x23FC0152,0x23FC0152,0x76540001,0x6A000152,0x33C0152,0x33C0152,0x33C0152,0x8E8C0001,0x8E8C0001,0x76A40001,0x23FC0152,0x23FC0152,0x76540001,0x6A000152,0x23FC0152,0x23FC0152,0x76540001,0x6A000152,0x6A000152,0xFAB40055,0xFECC0080,0xD40154,0xFE880004,0xC2880000,0xA4880000,0x96940000,0x8C7C0000,0xFE94006A,0xFA6C0001,0x1C80152,0x76540001,
-0x1C80152,0x10C01A5,0xCEF00000,0xA2F00000,0x94F00000,0x19001A5,0xB0B80000,0x94D40000,0x4BFC01A5,0x94780000,0x860001A5,0x19001A5,0xB0B80000,0x94D40000,0x4BFC01A5,0x94780000,0x860001A5,0x4BFC01A5,0x94780000,0x860001A5,0x860001A5,0x19001A5,0xB0B80000,0x94D40000,0x4BFC01A5,0x94780000,0x860001A5,0x4BFC01A5,0x94780000,0x860001A5,0x860001A5,0x4BFC01A5,
-0x94780000,0x860001A5,0x860001A5,0x860001A5,0xF2E000C8,0x12001A5,0xFB0400DD,0xFE940005,0xD2740000,0xAA7C0000,0x949C0000,0x944C0000,0xF4C800B5,0xFE6C0001,0x98A40000,0x860001A5,0x1DF801A5,0xA001A5,0xA001A5,0xA001A5,0xA001A5,0xA001A5,0xA001A5,0xA001A5,0xA001A5,0xA001A5,0xA001A5,0x96840001,0x96840001,0x96840001,0x96840001,0x96840001,
-0x96840001,0x6A840001,0x6A840001,0x6A840001,0x5C800002,0xEC01A5,0xEC01A5,0xEC01A5,0xEC01A5,0xEC01A5,0xEC01A5,0x784C0000,0x784C0000,0x784C0000,0x5C680001,0x1DC01A5,0x1DC01A5,0x1DC01A5,0x5C100001,0x4E0001A5,0xF29400A2,0xA001A5,0xA001A5,0xFE840002,0xCA840001,0xAA840001,0xAA840001,0x86840001,0xFE740059,0xF86C0001,0x7A7C0001,0x784C0000,
-0x15001A5,};
-static const uint32_t g_etc1_to_bc7_m6_table110[] = {
-0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0x1B80000,
-0x1B80000,0x1B80000,0x1B80000,0x48000000,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x900001,0x9C0000,0x9C0000,0x9C0000,0xD80000,0x1340000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0xCC0000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,
-0x1300000,0x1DF40000,0x1DF40000,0x1DF40000,0x64000001,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1DF40000,0x1DF40000,0x1DF40000,0x64000001,0x1DF40000,0x1DF40000,0x1DF40000,0x64000001,0x64000001,0x4D80000,0xCC0000,0xCC0000,0xEC0000,0x1000000,0x1140000,0x1140000,0x3540000,0xEC0000,0x1000000,0x1B00000,0x1DF40000,
-0x1B00000,0x1000000,0x1000000,0x1000000,0x1000000,0x17C0000,0x17C0000,0x17C0000,0x43F80000,0x43F80000,0x7E000001,0x17C0000,0x17C0000,0x17C0000,0x43F80000,0x43F80000,0x7E000001,0x43F80000,0x43F80000,0x7E000001,0x7E000001,0x17C0000,0x17C0000,0x17C0000,0x43F80000,0x43F80000,0x7E000001,0x43F80000,0x43F80000,0x7E000001,0x7E000001,0x43F80000,
-0x43F80000,0x7E000001,0x7E000001,0x7E000001,0x3280000,0x1100000,0x1000000,0x15C0000,0x3AC0000,0x11FC0000,0x29FC0000,0x53F80000,0x1400000,0x17C0000,0x11FC0000,0x7E000001,0x11FC0000,0x1380001,0x3D00000,0x6DFC0000,0x9C000000,0x3D00000,0x6DFC0000,0x9C000000,0x6DFC0000,0x9C000000,0x9C000000,0x3D00000,0x6DFC0000,0x9C000000,0x6DFC0000,0x9C000000,
-0x9C000000,0x6DFC0000,0x9C000000,0x9C000000,0x9C000000,0x3D00000,0x6DFC0000,0x9C000000,0x6DFC0000,0x9C000000,0x9C000000,0x6DFC0000,0x9C000000,0x9C000000,0x9C000000,0x6DFC0000,0x9C000000,0x9C000000,0x9C000000,0x9C000000,0x3880000,0xF4C0000,0xF4C0000,0xFFC0000,0x5BFC0000,0x85F40000,0x9C000000,0x9C000000,0x1AC0000,0x2FFC0000,0x97E00000,0x9C000000,
-0x47FC0000,0xE40F1E,0xFCCC0606,0xB8C805ED,0x9CC805ED,0xFCB0034A,0xC0B401C5,0xA0B80286,0xA8B0034A,0x9AAC01BD,0x8EB0034A,0xF09405EB,0xC6940154,0xA2A4020F,0xAE8C01B6,0x9A940006,0x8E9801BE,0x9C9005EB,0x9488020D,0x8888028A,0x809005EB,0x1540F1A,0xD06005EB,0x9C9405EA,0xC244034A,0x9E6C01B2,0x8E78034A,0xB42C05EB,0x9C3C0153,0x8C4C01C3,0x805C05EA,0x2FFC0F1A,
-0x98000606,0x8A00039E,0x7E000686,0x72000F1A,0xFEC405AE,0xF6DC0B8E,0xF8E00C65,0xFE9C0054,0xD4900004,0xB0940004,0x9E9C0025,0x98900023,0xFCB00557,0xFE800014,0xA0840159,0x8C4C01C3,0x1E80F1A,0x10005ED,0xF0E80154,0xB0E80154,0x9CE40154,0xDECC01A5,0xB6CC0002,0x9CD40029,0xA0CC01A5,0x96C8004C,0x8ECC01A5,0x18005EA,0xC2980153,0x9CBC0152,0xB48001A5,0x9A940005,
-0x8EA401A5,0x45F805EA,0x9C380152,0x8E2401A5,0x800005EA,0x18005EA,0xC2980153,0x9CBC0152,0xB48001A5,0x9A940005,0x8EA401A5,0x45F805EA,0x9C380152,0x8E2401A5,0x800005EA,0x45F805EA,0x9C380152,0x8E2401A5,0x800005EA,0x800005EA,0xFED8024B,0xF4F80465,0xF6FC0455,0xFEA40029,0xD4900003,0xB0940003,0x9CA40001,0x9A7C000C,0xFCC00269,0xFE840008,0xA2780152,0x8E2401A5,
-0x13FC05EA,0xC805ED,0xC805ED,0xC805ED,0xC805ED,0xD0B001A5,0xD0B001A5,0xD0B001A5,0x92B001A5,0x92B001A5,0x7EB001A6,0xC6940153,0xC6940153,0xC6940153,0x9A940002,0x9A940002,0x809C004B,0x86940153,0x86940153,0x7A90002A,0x72900153,0x12C05EA,0x12C05EA,0x12C05EA,0xA66001A5,0xA66001A5,0x7E8801A6,0x98480153,0x98480153,0x805C0001,0x72680152,0x1BF805EA,
-0x1BF805EA,0x7E0801A6,0x72000162,0x640005EA,0xFAB40206,0xFAC40411,0xC805ED,0xFE98001A,0xCE940002,0xAE940002,0xA694000B,0x92900002,0xFE9401BA,0xFC7C000B,0x9C880153,0x805C0001,0x1AC05EA,0xE40154,0xE40154,0xE40154,0xE40154,0xB4CC0000,0xB4CC0000,0xB4CC0000,0x8CCC0000,0x8CCC0000,0x7ECC0001,0x1540152,0x1540152,0x1540152,0x969C0001,0x969C0001,
-0x7EB40001,0x2FFC0152,0x2FFC0152,0x7E640001,0x72000152,0x1540152,0x1540152,0x1540152,0x969C0001,0x969C0001,0x7EB40001,0x2FFC0152,0x2FFC0152,0x7E640001,0x72000152,0x2FFC0152,0x2FFC0152,0x7E640001,0x72000152,0x72000152,0xF6C80062,0xF6DC0091,0xE40154,0xFCA00008,0xCA980000,0xAC980000,0x9EA40000,0x948C0000,0xFAAC0071,0xFE800002,0x1E80152,0x7E640001,
-0x1E80152,0x11C01A5,0xD7000000,0xAB000000,0x9D000000,0x1A801A5,0xB8C80000,0x9CE40000,0x57FC01A5,0x9C880000,0x8E0001A5,0x1A801A5,0xB8C80000,0x9CE40000,0x57FC01A5,0x9C880000,0x8E0001A5,0x57FC01A5,0x9C880000,0x8E0001A5,0x8E0001A5,0x1A801A5,0xB8C80000,0x9CE40000,0x57FC01A5,0x9C880000,0x8E0001A5,0x57FC01A5,0x9C880000,0x8E0001A5,0x8E0001A5,0x57FC01A5,
-0x9C880000,0x8E0001A5,0x8E0001A5,0x8E0001A5,0xFAF000C8,0x13001A5,0xF31400F4,0xFCAC000D,0xDA840000,0xB28C0000,0x9CAC0000,0x9C5C0000,0xFCD800B5,0xFE880002,0xA0B40000,0x8E0001A5,0x2BFC01A5,0xB001A5,0xB001A5,0xB001A5,0xB001A5,0xB001A5,0xB001A5,0xB001A5,0xB001A5,0xB001A5,0xB001A5,0x9E940001,0x9E940001,0x9E940001,0x9E940001,0x9E940001,
-0x9E940001,0x72940001,0x72940001,0x72940001,0x64900002,0x10401A5,0x10401A5,0x10401A5,0x10401A5,0x10401A5,0x10401A5,0x805C0000,0x805C0000,0x805C0000,0x64780001,0x5FC01A5,0x5FC01A5,0x5FC01A5,0x64200001,0x560001A5,0xFAA400A2,0xB001A5,0xB001A5,0xF894000A,0xD2940001,0xB2940001,0xB2940001,0x8E940001,0xFA880064,0xFC7C0002,0x828C0001,0x805C0000,
-0x17001A5,};
-static const uint32_t g_etc1_to_bc7_m6_table111[] = {
-0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,0x1E80000,
-0x1E80000,0x1E80000,0x1E80000,0x50000000,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xAC0000,0xAC0000,0xAC0000,0xF00000,0x1580000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0x3440000,0x3440000,0x3440000,0x3440000,0x3440000,
-0x3440000,0x27FC0000,0x27FC0000,0x27FC0000,0x6C000001,0x3440000,0x3440000,0x3440000,0x3440000,0x3440000,0x3440000,0x27FC0000,0x27FC0000,0x27FC0000,0x6C000001,0x27FC0000,0x27FC0000,0x27FC0000,0x6C000001,0x6C000001,0xCE80000,0xDC0000,0xDC0000,0x1000000,0x1140000,0x12C0000,0x12C0000,0x1700000,0x1000000,0x1140000,0x1D40000,0x27FC0000,
-0x1D40000,0x1100000,0x1100000,0x1100000,0x1100000,0x1940000,0x1940000,0x1940000,0x4FF80000,0x4FF80000,0x86000001,0x1940000,0x1940000,0x1940000,0x4FF80000,0x4FF80000,0x86000001,0x4FF80000,0x4FF80000,0x86000001,0x86000001,0x1940000,0x1940000,0x1940000,0x4FF80000,0x4FF80000,0x86000001,0x4FF80000,0x4FF80000,0x86000001,0x86000001,0x4FF80000,
-0x4FF80000,0x86000001,0x86000001,0x86000001,0x13C0000,0x9200000,0x1100000,0x3700000,0x1C80000,0x1FFC0000,0x37FC0000,0x5DFC0000,0x1540000,0x1940000,0x1FFC0000,0x86000001,0x1FFC0000,0x1480001,0x3E80000,0x79FC0000,0xA4000000,0x3E80000,0x79FC0000,0xA4000000,0x79FC0000,0xA4000000,0xA4000000,0x3E80000,0x79FC0000,0xA4000000,0x79FC0000,0xA4000000,
-0xA4000000,0x79FC0000,0xA4000000,0xA4000000,0xA4000000,0x3E80000,0x79FC0000,0xA4000000,0x79FC0000,0xA4000000,0xA4000000,0x79FC0000,0xA4000000,0xA4000000,0xA4000000,0x79FC0000,0xA4000000,0xA4000000,0xA4000000,0xA4000000,0x39C0000,0x1600000,0x1600000,0x23FC0000,0x69F80000,0x8FF40000,0xA4000000,0xA4000000,0x1C00000,0x41FC0000,0x9FF00000,0xA4000000,
-0x57FC0000,0xF40F1E,0xFEDC061E,0xC0D805ED,0xA4D805ED,0xFCC00356,0xC8C401C5,0xA8C80286,0xB0C0034A,0xA2BC01BD,0x96C0034A,0xF8A405EB,0xCEA40154,0xAAB4020F,0xB69C01B6,0xA2A40006,0x96A801BE,0xA4A005EB,0x9C98020D,0x9098028A,0x88A005EB,0x16C0F1A,0xD87005EB,0xA4A405EA,0xCA54034A,0xA67C01B2,0x9688034A,0xBC3C05EB,0xA44C0153,0x945C01C3,0x886C05EA,0x3BFC0F1A,
-0xA20005F1,0x94000376,0x8400065A,0x7A000F1A,0xFED80614,0xFEEC0B8E,0xFEEC0C81,0xFEB00093,0xDCA00004,0xB8A40004,0xA6AC0025,0xA0A00023,0xFEBC05A3,0xFE94003E,0xA8940159,0x945C01C3,0x7FC0F1A,0x11005ED,0xF8F80154,0xB8F80154,0xA4F40154,0xE6DC01A5,0xBEDC0002,0xA4E40029,0xA8DC01A5,0x9ED8004C,0x96DC01A5,0x19805EA,0xCAA80153,0xA4CC0152,0xBC9001A5,0xA2A40005,
-0x96B401A5,0x51F805EA,0xA4480152,0x963401A5,0x880005EA,0x19805EA,0xCAA80153,0xA4CC0152,0xBC9001A5,0xA2A40005,0x96B401A5,0x51F805EA,0xA4480152,0x963401A5,0x880005EA,0x51F805EA,0xA4480152,0x963401A5,0x880005EA,0x880005EA,0xFEEC028B,0xFD080465,0xFF0C0455,0xFCBC0048,0xDCA00003,0xB8A40003,0xA4B40001,0xA28C000C,0xFCD80289,0xFE98001E,0xAA880152,0x963401A5,
-0x21FC05EA,0xD805ED,0xD805ED,0xD805ED,0xD805ED,0xD8C001A5,0xD8C001A5,0xD8C001A5,0x9AC001A5,0x9AC001A5,0x86C001A6,0xCEA40153,0xCEA40153,0xCEA40153,0xA2A40002,0xA2A40002,0x88AC004B,0x8EA40153,0x8EA40153,0x82A0002A,0x7AA00153,0x14405EA,0x14405EA,0x14405EA,0xAE7001A5,0xAE7001A5,0x869801A6,0xA0580153,0xA0580153,0x886C0001,0x7A780152,0x27F805EA,
-0x27F805EA,0x861801A6,0x7A000156,0x6C0005EA,0xFAC40225,0xFECC0439,0xD805ED,0xFEAC0032,0xD6A40002,0xB6A40002,0xAEA4000B,0x9AA00002,0xFAAC01E2,0xFE900015,0xA4980153,0x886C0001,0x1D005EA,0xF40154,0xF40154,0xF40154,0xF40154,0xBCDC0000,0xBCDC0000,0xBCDC0000,0x94DC0000,0x94DC0000,0x86DC0001,0x16C0152,0x16C0152,0x16C0152,0x9EAC0001,0x9EAC0001,
-0x86C40001,0x3BFC0152,0x3BFC0152,0x86740001,0x7A000152,0x16C0152,0x16C0152,0x16C0152,0x9EAC0001,0x9EAC0001,0x86C40001,0x3BFC0152,0x3BFC0152,0x86740001,0x7A000152,0x3BFC0152,0x3BFC0152,0x86740001,0x7A000152,0x7A000152,0xFED80062,0xFEEC0091,0xF40154,0xFEB4000D,0xD2A80000,0xB4A80000,0xA6B40000,0x9C9C0000,0xFCC00080,0xFE980005,0x7FC0152,0x86740001,
-0x7FC0152,0x12C01A5,0xDF100000,0xB3100000,0xA5100000,0x1C001A5,0xC0D80000,0xA4F40000,0x63FC01A5,0xA4980000,0x960001A5,0x1C001A5,0xC0D80000,0xA4F40000,0x63FC01A5,0xA4980000,0x960001A5,0x63FC01A5,0xA4980000,0x960001A5,0x960001A5,0x1C001A5,0xC0D80000,0xA4F40000,0x63FC01A5,0xA4980000,0x960001A5,0x63FC01A5,0xA4980000,0x960001A5,0x960001A5,0x63FC01A5,
-0xA4980000,0x960001A5,0x960001A5,0x960001A5,0xF70400DD,0x14001A5,0xFB2400F4,0xFEC00014,0xE2940000,0xBA9C0000,0xA4BC0000,0xA46C0000,0xFCEC00CA,0xFEA0000A,0xA8C40000,0x960001A5,0x3BFC01A5,0xC001A5,0xC001A5,0xC001A5,0xC001A5,0xC001A5,0xC001A5,0xC001A5,0xC001A5,0xC001A5,0xC001A5,0xA6A40001,0xA6A40001,0xA6A40001,0xA6A40001,0xA6A40001,
-0xA6A40001,0x7AA40001,0x7AA40001,0x7AA40001,0x6CA00002,0x11C01A5,0x11C01A5,0x11C01A5,0x11C01A5,0x11C01A5,0x11C01A5,0x886C0000,0x886C0000,0x886C0000,0x6C880001,0x11FC01A5,0x11FC01A5,0x11FC01A5,0x6C300001,0x5E0001A5,0xF2B400B5,0xC001A5,0xC001A5,0xFCA8000D,0xDAA40001,0xBAA40001,0xBAA40001,0x96A40001,0xFC9C0071,0xFC900005,0x8A9C0001,0x886C0000,
-0x19401A5,};
-static const uint32_t g_etc1_to_bc7_m6_table112[] = {
-0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0xBF80000,
-0xBF80000,0xBF80000,0xBF80000,0x58000001,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xC00000,0xC00000,0xC00000,0x10C0000,0x17C0000,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0xEC0001,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,
-0x1600000,0x35FC0000,0x35FC0000,0x35FC0000,0x76000000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x35FC0000,0x35FC0000,0x35FC0000,0x76000000,0x35FC0000,0x35FC0000,0x35FC0000,0x76000000,0x76000000,0x6FC0000,0xEC0001,0xEC0001,0x1140000,0x3280000,0x1440000,0x1440000,0x1900000,0x1140000,0x3280000,0x1F80000,0x35FC0000,
-0x1F80000,0x1200001,0x1200001,0x1200001,0x1200001,0x1B00000,0x1B00000,0x1B00000,0x5DF40000,0x5DF40000,0x90000000,0x1B00000,0x1B00000,0x1B00000,0x5DF40000,0x5DF40000,0x90000000,0x5DF40000,0x5DF40000,0x90000000,0x90000000,0x1B00000,0x1B00000,0x1B00000,0x5DF40000,0x5DF40000,0x90000000,0x5DF40000,0x5DF40000,0x90000000,0x90000000,0x5DF40000,
-0x5DF40000,0x90000000,0x90000000,0x90000000,0x1500000,0x3340000,0x1200001,0x3880000,0x1E80000,0x31FC0000,0x47F80000,0x69FC0000,0x16C0000,0x1B00000,0x31FC0000,0x90000000,0x31FC0000,0x15C0000,0x9FC0000,0x87FC0000,0xAC000001,0x9FC0000,0x87FC0000,0xAC000001,0x87FC0000,0xAC000001,0xAC000001,0x9FC0000,0x87FC0000,0xAC000001,0x87FC0000,0xAC000001,
-0xAC000001,0x87FC0000,0xAC000001,0xAC000001,0xAC000001,0x9FC0000,0x87FC0000,0xAC000001,0x87FC0000,0xAC000001,0xAC000001,0x87FC0000,0xAC000001,0xAC000001,0xAC000001,0x87FC0000,0xAC000001,0xAC000001,0xAC000001,0xAC000001,0x1B40000,0x1740000,0x1740000,0x39FC0000,0x77FC0000,0x99FC0000,0xAC000001,0xAC000001,0x1D80000,0x53FC0000,0xA9E40000,0xAC000001,
-0x67FC0000,0x1080F1A,0xFCF0065A,0xC8EC05EA,0xACEC05EB,0xFED40376,0xD0D401C3,0xB0D8028A,0xBAD0034A,0xAAD001BE,0x9ED0034A,0xFCB805F1,0xD8B40153,0xB2C4020D,0xC0B001B2,0xACB40006,0xA0B801BD,0xACB405EA,0xA4A8020F,0x9AAC0286,0x90B405ED,0x1880F1A,0xE08405EB,0xAEB405EB,0xD268034A,0xAE8C01B6,0x9E9C034A,0xC64805EB,0xAC600154,0x9C6C01C5,0x927C05ED,0x49F80F1A,
-0xAC0805EB,0x9C000356,0x9000061E,0x82000F1E,0xFEE4068A,0xF9000BEA,0xFB040CAA,0xFEC400EA,0xE4B40003,0xC2B40002,0xAEBC0023,0xA8B00025,0xFED40612,0xFEB0008D,0xB2A8015B,0x9C6C01C5,0x19FC0F1A,0x12405EA,0xFD080156,0xC3080152,0xAD080153,0xEEF001A6,0xC8EC0001,0xAEF8002A,0xB2EC01A6,0xA8EC004B,0x9EEC01A6,0x3B005EA,0xD2BC0153,0xACE00153,0xC6A001A5,0xACB80002,
-0x9EC801A5,0x5DFC05EA,0xAC600153,0x9E4801A5,0x900005ED,0x3B005EA,0xD2BC0153,0xACE00153,0xC6A001A5,0xACB80002,0x9EC801A5,0x5DFC05EA,0xAC600153,0x9E4801A5,0x900005ED,0x5DFC05EA,0xAC600153,0x9E4801A5,0x900005ED,0x900005ED,0xFF0002B2,0xF71C0492,0xF9200483,0xFED40072,0xE4B40003,0xC2B40002,0xAEC80002,0xACA0000B,0xFCEC02D4,0xFEB80048,0xB4980152,0x9E4801A5,
-0x33FC05EA,0xEC05EA,0xEC05EA,0xEC05EA,0xEC05EA,0xE4D001A5,0xE4D001A5,0xE4D001A5,0xA4D001A5,0xA4D001A5,0x90D001A5,0xD8B40152,0xD8B40152,0xD8B40152,0xAAB40005,0xAAB40005,0x92C0004C,0x98B40152,0x98B40152,0x8CB40029,0x82B40154,0x35C05EA,0x35C05EA,0x35C05EA,0xB68401A5,0xB68401A5,0x90A801A5,0xAA680153,0xAA680153,0x907C0002,0x828C0154,0x33FC05EA,
-0x33FC05EA,0x902801A5,0x820C0154,0x740005ED,0xFED80248,0xFAE4043D,0xEC05EA,0xFEBC0054,0xE2B40002,0xC2B40002,0xB8B8000C,0xA4B40001,0xFEBC020C,0xFEA40031,0xAEA80152,0x907C0002,0x1F405EA,0x1080152,0x1080152,0x1080152,0x1080152,0xC2F00001,0xC2F00001,0xC2F00001,0x9CF00001,0x9CF00001,0x90EC0001,0x1880152,0x1880152,0x1880152,0xA6C00001,0xA6C00001,
-0x90D40000,0x49F80152,0x49F80152,0x90840000,0x82000154,0x1880152,0x1880152,0x1880152,0xA6C00001,0xA6C00001,0x90D40000,0x49F80152,0x49F80152,0x90840000,0x82000154,0x49F80152,0x49F80152,0x90840000,0x82000154,0x82000154,0xFAEC0071,0xF90000A2,0x1080152,0xF6CC0019,0xDABC0000,0xBCBC0001,0xB0C40000,0xA4B00000,0xFED00088,0xFEB0000D,0x19FC0152,0x90840000,
-0x19FC0152,0x14001A5,0xE7240001,0xBB240001,0xAD200002,0x1D801A5,0xC8EC0000,0xAD080001,0x71F801A5,0xACB00001,0x9E0001A5,0x1D801A5,0xC8EC0000,0xAD080001,0x71F801A5,0xACB00001,0x9E0001A5,0x71F801A5,0xACB00001,0x9E0001A5,0x9E0001A5,0x1D801A5,0xC8EC0000,0xAD080001,0x71F801A5,0xACB00001,0x9E0001A5,0x71F801A5,0xACB00001,0x9E0001A5,0x9E0001A5,0x71F801A5,
-0xACB00001,0x9E0001A5,0x9E0001A5,0x9E0001A5,0xFF1400E1,0x15401A5,0xF5380109,0xFED80028,0xEAA80000,0xC4AC0000,0xACD00001,0xAC840001,0xF70800DD,0xFEC00012,0xB2D40000,0x9E0001A5,0x4BFC01A5,0xD001A5,0xD001A5,0xD001A5,0xD001A5,0xD001A5,0xD001A5,0xD001A5,0xD001A5,0xD001A5,0xD001A5,0xB0B40000,0xB0B40000,0xB0B40000,0xB0B40000,0xB0B40000,
-0xB0B40000,0x84B40000,0x84B40000,0x84B40000,0x76B40000,0x13401A5,0x13401A5,0x13401A5,0x13401A5,0x13401A5,0x13401A5,0x927C0000,0x927C0000,0x927C0000,0x76980000,0x1FF801A5,0x1FF801A5,0x1FF801A5,0x763C0000,0x680001A5,0xFCC800B5,0xD001A5,0xD001A5,0xFCB80014,0xE6B40000,0xC6B40000,0xC6B40000,0xA0B40000,0xF8B00080,0xFEA0000A,0x94AC0000,0x927C0000,
-0x1B801A5,};
-static const uint32_t g_etc1_to_bc7_m6_table113[] = {
-0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x17F80000,
-0x17F80000,0x17F80000,0x17F80000,0x60000001,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xD00000,0xD00000,0xD00000,0x1240000,0x1A00000,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0xFC0001,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,
-0x1780000,0x41FC0000,0x41FC0000,0x41FC0000,0x7E000000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x41FC0000,0x41FC0000,0x41FC0000,0x7E000000,0x41FC0000,0x41FC0000,0x41FC0000,0x7E000000,0x7E000000,0xF0C0000,0xFC0001,0xFC0001,0x1280000,0x33C0000,0x1580000,0x1580000,0x1AC0000,0x1280000,0x33C0000,0xFFC0000,0x41FC0000,
-0xFFC0000,0x1300001,0x1300001,0x1300001,0x1300001,0x3C40000,0x3C40000,0x3C40000,0x67FC0000,0x67FC0000,0x98000000,0x3C40000,0x3C40000,0x3C40000,0x67FC0000,0x67FC0000,0x98000000,0x67FC0000,0x67FC0000,0x98000000,0x98000000,0x3C40000,0x3C40000,0x3C40000,0x67FC0000,0x67FC0000,0x98000000,0x67FC0000,0x67FC0000,0x98000000,0x98000000,0x67FC0000,
-0x67FC0000,0x98000000,0x98000000,0x98000000,0x1640000,0xB440000,0x1300001,0x1A00000,0x5FC0000,0x3FFC0000,0x55F80000,0x75F80000,0x1800000,0x3C40000,0x3FFC0000,0x98000000,0x3FFC0000,0x16C0000,0x23FC0000,0x93FC0000,0xB4000001,0x23FC0000,0x93FC0000,0xB4000001,0x93FC0000,0xB4000001,0xB4000001,0x23FC0000,0x93FC0000,0xB4000001,0x93FC0000,0xB4000001,
-0xB4000001,0x93FC0000,0xB4000001,0xB4000001,0xB4000001,0x23FC0000,0x93FC0000,0xB4000001,0x93FC0000,0xB4000001,0xB4000001,0x93FC0000,0xB4000001,0xB4000001,0xB4000001,0x93FC0000,0xB4000001,0xB4000001,0xB4000001,0xB4000001,0x1C80000,0x1840000,0x1840000,0x4DFC0000,0x85FC0000,0xA5F00000,0xB4000001,0xB4000001,0x1F00000,0x65FC0000,0xB1F40000,0xB4000001,
-0x77FC0000,0x1180F1A,0xFF000686,0xD0FC05EA,0xB4FC05EB,0xFEE8039E,0xD8E401C3,0xB8E8028A,0xC2E0034A,0xB2E001BE,0xA6E0034A,0xFCCC0606,0xE0C40153,0xBAD4020D,0xC8C001B2,0xB4C40006,0xA8C801BD,0xB4C405EA,0xACB8020F,0xA2BC0286,0x98C405ED,0x1A00F1A,0xE89405EB,0xB6C405EB,0xDA78034A,0xB69C01B6,0xA6AC034A,0xCE5805EB,0xB4700154,0xA47C01C5,0x9A8C05ED,0x55F80F1A,
-0xB41805EB,0xA600034A,0x98000606,0x8A000F1E,0xFEF806F7,0xFF0C0BFA,0xFF0C0CEA,0xFED80150,0xECC40003,0xCAC40002,0xB6CC0023,0xB0C00025,0xFEE006BA,0xFEC000D3,0xBAB8015B,0xA47C01C5,0x27FC0F1A,0x13405EA,0xFF180162,0xCB180152,0xB5180153,0xF70001A6,0xD0FC0001,0xB708002A,0xBAFC01A6,0xB0FC004B,0xA6FC01A6,0x1C805EA,0xDACC0153,0xB4F00153,0xCEB001A5,0xB4C80002,
-0xA6D801A5,0x69FC05EA,0xB4700153,0xA65801A5,0x980005ED,0x1C805EA,0xDACC0153,0xB4F00153,0xCEB001A5,0xB4C80002,0xA6D801A5,0x69FC05EA,0xB4700153,0xA65801A5,0x980005ED,0x69FC05EA,0xB4700153,0xA65801A5,0x980005ED,0x980005ED,0xFF1402D5,0xFF2C0492,0xFF2C048B,0xFCE800A5,0xECC40003,0xCAC40002,0xB6D80002,0xB4B0000B,0xFEF802F6,0xFEC80065,0xBCA80152,0xA65801A5,
-0x41FC05EA,0xFC05EA,0xFC05EA,0xFC05EA,0xFC05EA,0xECE001A5,0xECE001A5,0xECE001A5,0xACE001A5,0xACE001A5,0x98E001A5,0xE0C40152,0xE0C40152,0xE0C40152,0xB2C40005,0xB2C40005,0x9AD0004C,0xA0C40152,0xA0C40152,0x94C40029,0x8AC40154,0x37405EA,0x37405EA,0x37405EA,0xBE9401A5,0xBE9401A5,0x98B801A5,0xB2780153,0xB2780153,0x988C0002,0x8A9C0154,0x3FFC05EA,
-0x3FFC05EA,0x983801A5,0x8A1C0154,0x7C0005ED,0xFEE80269,0xF4F80466,0xFC05EA,0xFED40071,0xEAC40002,0xCAC40002,0xC0C8000C,0xACC40001,0xFED00229,0xFEBC0048,0xB6B80152,0x988C0002,0xDFC05EA,0x1180152,0x1180152,0x1180152,0x1180152,0xCB000001,0xCB000001,0xCB000001,0xA5000001,0xA5000001,0x98FC0001,0x1A00152,0x1A00152,0x1A00152,0xAED00001,0xAED00001,
-0x98E40000,0x55F80152,0x55F80152,0x98940000,0x8A000154,0x1A00152,0x1A00152,0x1A00152,0xAED00001,0xAED00001,0x98E40000,0x55F80152,0x55F80152,0x98940000,0x8A000154,0x55F80152,0x55F80152,0x98940000,0x8A000154,0x8A000154,0xF7000080,0xFF0C00AA,0x1180152,0xFEDC0019,0xE2CC0000,0xC4CC0001,0xB8D40000,0xACC00000,0xF8EC0091,0xFEC40012,0x27FC0152,0x98940000,
-0x27FC0152,0x15001A5,0xEF340001,0xC3340001,0xB5300002,0x1F001A5,0xD0FC0000,0xB5180001,0x7DF801A5,0xB4C00001,0xA60001A5,0x1F001A5,0xD0FC0000,0xB5180001,0x7DF801A5,0xB4C00001,0xA60001A5,0x7DF801A5,0xB4C00001,0xA60001A5,0xA60001A5,0x1F001A5,0xD0FC0000,0xB5180001,0x7DF801A5,0xB4C00001,0xA60001A5,0x7DF801A5,0xB4C00001,0xA60001A5,0xA60001A5,0x7DF801A5,
-0xB4C00001,0xA60001A5,0xA60001A5,0xA60001A5,0xFB2C00F2,0x16401A5,0xFD480109,0xFEF40034,0xF2B80000,0xCCBC0000,0xB4E00001,0xB4940001,0xFF1800DD,0xFED80022,0xBAE40000,0xA60001A5,0x5BFC01A5,0xE001A5,0xE001A5,0xE001A5,0xE001A5,0xE001A5,0xE001A5,0xE001A5,0xE001A5,0xE001A5,0xE001A5,0xB8C40000,0xB8C40000,0xB8C40000,0xB8C40000,0xB8C40000,
-0xB8C40000,0x8CC40000,0x8CC40000,0x8CC40000,0x7EC40000,0x14C01A5,0x14C01A5,0x14C01A5,0x14C01A5,0x14C01A5,0x14C01A5,0x9A8C0000,0x9A8C0000,0x9A8C0000,0x7EA80000,0x2BF801A5,0x2BF801A5,0x2BF801A5,0x7E4C0000,0x700001A5,0xF4D800C8,0xE001A5,0xE001A5,0xFECC0019,0xEEC40000,0xCEC40000,0xCEC40000,0xA8C40000,0xFEBC0088,0xFEB4000D,0x9CBC0000,0x9A8C0000,
-0x1DC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table114[] = {
-0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x21FC0000,
-0x21FC0000,0x21FC0000,0x21FC0000,0x68000001,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0x8E00000,0x8E00000,0x8E00000,0x13C0000,0x1C00000,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x10C0001,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,
-0x1900000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x86000000,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x86000000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x86000000,0x86000000,0x1200000,0x10C0001,0x10C0001,0x5380000,0x5500000,0x1700000,0x1700000,0x1C40000,0x5380000,0x5500000,0x1FF80000,0x4DFC0000,
-0x1FF80000,0x1400001,0x1400001,0x1400001,0x1400001,0x3DC0000,0x3DC0000,0x3DC0000,0x73FC0000,0x73FC0000,0xA0000000,0x3DC0000,0x3DC0000,0x3DC0000,0x73FC0000,0x73FC0000,0xA0000000,0x73FC0000,0x73FC0000,0xA0000000,0xA0000000,0x3DC0000,0x3DC0000,0x3DC0000,0x73FC0000,0x73FC0000,0xA0000000,0x73FC0000,0x73FC0000,0xA0000000,0xA0000000,0x73FC0000,
-0x73FC0000,0xA0000000,0xA0000000,0xA0000000,0x5740000,0x1580000,0x1400001,0x3B40000,0x19FC0000,0x4FFC0000,0x61FC0000,0x7FFC0000,0x1940000,0x3DC0000,0x4FFC0000,0xA0000000,0x4FFC0000,0x17C0000,0x3BFC0000,0x9FF80000,0xBC000001,0x3BFC0000,0x9FF80000,0xBC000001,0x9FF80000,0xBC000001,0xBC000001,0x3BFC0000,0x9FF80000,0xBC000001,0x9FF80000,0xBC000001,
-0xBC000001,0x9FF80000,0xBC000001,0xBC000001,0xBC000001,0x3BFC0000,0x9FF80000,0xBC000001,0x9FF80000,0xBC000001,0xBC000001,0x9FF80000,0xBC000001,0xBC000001,0xBC000001,0x9FF80000,0xBC000001,0xBC000001,0xBC000001,0xBC000001,0x1DC0000,0x3940000,0x3940000,0x61FC0000,0x93F80000,0xAFF00000,0xBC000001,0xBC000001,0xDFC0000,0x75FC0000,0xBBC80000,0xBC000001,
-0x85FC0000,0x1280F1A,0xFF1006D7,0xD90C05EA,0xBD0C05EB,0xFEF803F2,0xE0F401C3,0xC0F8028A,0xCAF0034A,0xBAF001BE,0xAEF0034A,0xFEE00629,0xE8D40153,0xC2E4020D,0xD0D001B2,0xBCD40006,0xB0D801BD,0xBCD405EA,0xB4C8020F,0xAACC0286,0xA0D405ED,0x1B80F1A,0xF0A405EB,0xBED405EB,0xE288034A,0xBEAC01B6,0xAEBC034A,0xD66805EB,0xBC800154,0xAC8C01C5,0xA29C05ED,0x61F80F1A,
-0xBC2805EB,0xAE0C034A,0xA00005F1,0x92000F1E,0xFF0C0766,0xF9200C4A,0xFB240CF3,0xFEEC01C5,0xF4D40003,0xD2D40002,0xBEDC0023,0xB8D00025,0xFEF806FA,0xFED4013A,0xC2C8015B,0xAC8C01C5,0x37FC0F1A,0x14405EA,0xFD2C017E,0xD3280152,0xBD280153,0xFF1001A6,0xD90C0001,0xBF18002A,0xC30C01A6,0xB90C004B,0xAF0C01A6,0x1E005EA,0xE2DC0153,0xBD000153,0xD6C001A5,0xBCD80002,
-0xAEE801A5,0x75FC05EA,0xBC800153,0xAE6801A5,0xA00005ED,0x1E005EA,0xE2DC0153,0xBD000153,0xD6C001A5,0xBCD80002,0xAEE801A5,0x75FC05EA,0xBC800153,0xAE6801A5,0xA00005ED,0x75FC05EA,0xBC800153,0xAE6801A5,0xA00005ED,0xA00005ED,0xFF200312,0xF73C04BE,0xF94004B2,0xFEF800DE,0xF4D40003,0xD2D40002,0xBEE80002,0xBCC0000B,0xFD140322,0xFEE000A1,0xC4B80152,0xAE6801A5,
-0x51FC05EA,0x10C05EA,0x10C05EA,0x10C05EA,0x10C05EA,0xF4F001A5,0xF4F001A5,0xF4F001A5,0xB4F001A5,0xB4F001A5,0xA0F001A5,0xE8D40152,0xE8D40152,0xE8D40152,0xBAD40005,0xBAD40005,0xA2E0004C,0xA8D40152,0xA8D40152,0x9CD40029,0x92D40154,0x38C05EA,0x38C05EA,0x38C05EA,0xC6A401A5,0xC6A401A5,0xA0C801A5,0xBA880153,0xBA880153,0xA09C0002,0x92AC0154,0x4BFC05EA,
-0x4BFC05EA,0xA04801A5,0x922C0154,0x840005ED,0xFEF402A9,0xFD080466,0x10C05EA,0xFCE400A5,0xF2D40002,0xD2D40002,0xC8D8000C,0xB4D40001,0xFEE40266,0xFED00062,0xBEC80152,0xA09C0002,0x1DF805EA,0x1280152,0x1280152,0x1280152,0x1280152,0xD3100001,0xD3100001,0xD3100001,0xAD100001,0xAD100001,0xA10C0001,0x1B80152,0x1B80152,0x1B80152,0xB6E00001,0xB6E00001,
-0xA0F40000,0x61F80152,0x61F80152,0xA0A40000,0x92000154,0x1B80152,0x1B80152,0x1B80152,0xB6E00001,0xB6E00001,0xA0F40000,0x61F80152,0x61F80152,0xA0A40000,0x92000154,0x61F80152,0x61F80152,0xA0A40000,0x92000154,0x92000154,0xFF100080,0xF92000B5,0x1280152,0xFCF40029,0xEADC0000,0xCCDC0001,0xC0E40000,0xB4D00000,0xFEF80095,0xFEDC0019,0x37FC0152,0xA0A40000,
-0x37FC0152,0x16001A5,0xF7440001,0xCB440001,0xBD400002,0xDFC01A5,0xD90C0000,0xBD280001,0x89F801A5,0xBCD00001,0xAE0001A5,0xDFC01A5,0xD90C0000,0xBD280001,0x89F801A5,0xBCD00001,0xAE0001A5,0x89F801A5,0xBCD00001,0xAE0001A5,0xAE0001A5,0xDFC01A5,0xD90C0000,0xBD280001,0x89F801A5,0xBCD00001,0xAE0001A5,0x89F801A5,0xBCD00001,0xAE0001A5,0xAE0001A5,0x89F801A5,
-0xBCD00001,0xAE0001A5,0xAE0001A5,0xAE0001A5,0xF7400109,0x17801A5,0xF5580122,0xFD100048,0xFAC80000,0xD4CC0000,0xBCF00001,0xBCA40001,0xFF2C00F4,0xFEF0003A,0xC2F40000,0xAE0001A5,0x69FC01A5,0xF001A5,0xF001A5,0xF001A5,0xF001A5,0xF001A5,0xF001A5,0xF001A5,0xF001A5,0xF001A5,0xF001A5,0xC0D40000,0xC0D40000,0xC0D40000,0xC0D40000,0xC0D40000,
-0xC0D40000,0x94D40000,0x94D40000,0x94D40000,0x86D40000,0x16401A5,0x16401A5,0x16401A5,0x16401A5,0x16401A5,0x16401A5,0xA29C0000,0xA29C0000,0xA29C0000,0x86B80000,0x37F801A5,0x37F801A5,0x37F801A5,0x865C0000,0x780001A5,0xFCE800C8,0xF001A5,0xF001A5,0xFED80028,0xF6D40000,0xD6D40000,0xD6D40000,0xB0D40000,0xFCD40091,0xFAC80019,0xA4CC0000,0xA29C0000,
-0x1FC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table115[] = {
-0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,0x2DFC0000,
-0x2DFC0000,0x2DFC0000,0x2DFC0000,0x70000001,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xF40000,0xF40000,0xF40000,0x3500000,0x1E40000,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x11C0001,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,
-0x1A80000,0x59FC0000,0x59FC0000,0x59FC0000,0x8E000000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x59FC0000,0x59FC0000,0x59FC0000,0x8E000000,0x59FC0000,0x59FC0000,0x59FC0000,0x8E000000,0x8E000000,0x1300000,0x11C0001,0x11C0001,0x14C0000,0x5640000,0x1840000,0x1840000,0x1E00000,0x14C0000,0x5640000,0x2DFC0000,0x59FC0000,
-0x2DFC0000,0x1500001,0x1500001,0x1500001,0x1500001,0x3F40000,0x3F40000,0x3F40000,0x7FFC0000,0x7FFC0000,0xA8000000,0x3F40000,0x3F40000,0x3F40000,0x7FFC0000,0x7FFC0000,0xA8000000,0x7FFC0000,0x7FFC0000,0xA8000000,0xA8000000,0x3F40000,0x3F40000,0x3F40000,0x7FFC0000,0x7FFC0000,0xA8000000,0x7FFC0000,0x7FFC0000,0xA8000000,0xA8000000,0x7FFC0000,
-0x7FFC0000,0xA8000000,0xA8000000,0xA8000000,0x1880000,0x1680000,0x1500001,0x1CC0000,0x2DFC0000,0x5FF80000,0x6FFC0000,0x8BF80000,0x1A80000,0x3F40000,0x5FF80000,0xA8000000,0x5FF80000,0x18C0000,0x53FC0000,0xABF80000,0xC4000001,0x53FC0000,0xABF80000,0xC4000001,0xABF80000,0xC4000001,0xC4000001,0x53FC0000,0xABF80000,0xC4000001,0xABF80000,0xC4000001,
-0xC4000001,0xABF80000,0xC4000001,0xC4000001,0xC4000001,0x53FC0000,0xABF80000,0xC4000001,0xABF80000,0xC4000001,0xC4000001,0xABF80000,0xC4000001,0xC4000001,0xC4000001,0xABF80000,0xC4000001,0xC4000001,0xC4000001,0xC4000001,0x1F00000,0xBA40000,0xBA40000,0x73FC0000,0x9FFC0000,0xB9F00000,0xC4000001,0xC4000001,0x2BFC0000,0x87FC0000,0xC3D80000,0xC4000001,
-0x95FC0000,0x1380F1A,0xFF24071A,0xE11C05EA,0xC51C05EB,0xFF0C043A,0xE90401C3,0xC908028A,0xD300034A,0xC30001BE,0xB700034A,0xFEF4065A,0xF0E40153,0xCAF4020D,0xD8E001B2,0xC4E40006,0xB8E801BD,0xC4E405EA,0xBCD8020F,0xB2DC0286,0xA8E405ED,0x1D00F1A,0xF8B405EB,0xC6E405EB,0xEA98034A,0xC6BC01B6,0xB6CC034A,0xDE7805EB,0xC4900154,0xB49C01C5,0xAAAC05ED,0x6DF80F1A,
-0xC43805EB,0xB61C034A,0xA80005ED,0x9A000F1E,0xFF2007D6,0xFF2C0C62,0xFF2C0D3B,0xFF000242,0xFCE40003,0xDAE40002,0xC6EC0023,0xC0E00025,0xFF100782,0xFEE801CC,0xCAD8015B,0xB49C01C5,0x45FC0F1A,0x15405EA,0xFF3C019A,0xDB380152,0xC5380153,0xFF2401B2,0xE11C0001,0xC728002A,0xCB1C01A6,0xC11C004B,0xB71C01A6,0x1F805EA,0xEAEC0153,0xC5100153,0xDED001A5,0xC4E80002,
-0xB6F801A5,0x81FC05EA,0xC4900153,0xB67801A5,0xA80005ED,0x1F805EA,0xEAEC0153,0xC5100153,0xDED001A5,0xC4E80002,0xB6F801A5,0x81FC05EA,0xC4900153,0xB67801A5,0xA80005ED,0x81FC05EA,0xC4900153,0xB67801A5,0xA80005ED,0xA80005ED,0xFF340333,0xFF4C04BE,0xFF4C04BE,0xFF140109,0xFCE40003,0xDAE40002,0xC6F80002,0xC4D0000B,0xFF240356,0xFD0000DD,0xCCC80152,0xB67801A5,
-0x5FFC05EA,0x11C05EA,0x11C05EA,0x11C05EA,0x11C05EA,0xFD0001A5,0xFD0001A5,0xFD0001A5,0xBD0001A5,0xBD0001A5,0xA90001A5,0xF0E40152,0xF0E40152,0xF0E40152,0xC2E40005,0xC2E40005,0xAAF0004C,0xB0E40152,0xB0E40152,0xA4E40029,0x9AE40154,0x3A405EA,0x3A405EA,0x3A405EA,0xCEB401A5,0xCEB401A5,0xA8D801A5,0xC2980153,0xC2980153,0xA8AC0002,0x9ABC0154,0x57FC05EA,
-0x57FC05EA,0xA85801A5,0x9A3C0154,0x8C0005ED,0xFF0402D2,0xF5180491,0x11C05EA,0xFEF800C9,0xFAE40002,0xDAE40002,0xD0E8000C,0xBCE40001,0xFEF80289,0xFEE00099,0xC6D80152,0xA8AC0002,0x2BFC05EA,0x1380152,0x1380152,0x1380152,0x1380152,0xDB200001,0xDB200001,0xDB200001,0xB5200001,0xB5200001,0xA91C0001,0x1D00152,0x1D00152,0x1D00152,0xBEF00001,0xBEF00001,
-0xA9040000,0x6DF80152,0x6DF80152,0xA8B40000,0x9A000154,0x1D00152,0x1D00152,0x1D00152,0xBEF00001,0xBEF00001,0xA9040000,0x6DF80152,0x6DF80152,0xA8B40000,0x9A000154,0x6DF80152,0x6DF80152,0xA8B40000,0x9A000154,0x9A000154,0xFF200091,0xFF2C00C1,0x1380152,0xFD040034,0xF2EC0000,0xD4EC0001,0xC8F40000,0xBCE00000,0xFD1000A2,0xFCF00029,0x45FC0152,0xA8B40000,
-0x45FC0152,0x17001A5,0xFF540001,0xD3540001,0xC5500002,0x25FC01A5,0xE11C0000,0xC5380001,0x95F801A5,0xC4E00001,0xB60001A5,0x25FC01A5,0xE11C0000,0xC5380001,0x95F801A5,0xC4E00001,0xB60001A5,0x95F801A5,0xC4E00001,0xB60001A5,0xB60001A5,0x25FC01A5,0xE11C0000,0xC5380001,0x95F801A5,0xC4E00001,0xB60001A5,0x95F801A5,0xC4E00001,0xB60001A5,0xB60001A5,0x95F801A5,
-0xC4E00001,0xB60001A5,0xB60001A5,0xB60001A5,0xFF500109,0x18801A5,0xFD680122,0xFF200061,0xFCE40002,0xDCDC0000,0xC5000001,0xC4B40001,0xF5480109,0xFF100048,0xCB040000,0xB60001A5,0x79FC01A5,0x10001A5,0x10001A5,0x10001A5,0x10001A5,0x10001A5,0x10001A5,0x10001A5,0x10001A5,0x10001A5,0x10001A5,0xC8E40000,0xC8E40000,0xC8E40000,0xC8E40000,0xC8E40000,
-0xC8E40000,0x9CE40000,0x9CE40000,0x9CE40000,0x8EE40000,0x17C01A5,0x17C01A5,0x17C01A5,0x17C01A5,0x17C01A5,0x17C01A5,0xAAAC0000,0xAAAC0000,0xAAAC0000,0x8EC80000,0x43F801A5,0x43F801A5,0x43F801A5,0x8E6C0000,0x800001A5,0xF4F800DD,0x10001A5,0x10001A5,0xFAEC0034,0xFEE40000,0xDEE40000,0xDEE40000,0xB8E40000,0xFCE400A2,0xFED80022,0xACDC0000,0xAAAC0000,
-0x11FC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table116[] = {
-0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x3BFC0000,
-0x3BFC0000,0x3BFC0000,0x3BFC0000,0x7A000000,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xB040000,0xB040000,0xB040000,0x16C0000,0x7FC0000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1300000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,
-0x1C40000,0x67F80000,0x67F80000,0x67F80000,0x96000001,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x67F80000,0x67F80000,0x67F80000,0x96000001,0x67F80000,0x67F80000,0x67F80000,0x96000001,0x96000001,0x1440000,0x1300000,0x1300000,0x3600000,0x17C0000,0x19C0000,0x19C0000,0x3FC0000,0x3600000,0x17C0000,0x3FF80000,0x67F80000,
-0x3FF80000,0x1640000,0x1640000,0x1640000,0x1640000,0x15FC0000,0x15FC0000,0x15FC0000,0x8DFC0000,0x8DFC0000,0xB0000001,0x15FC0000,0x15FC0000,0x15FC0000,0x8DFC0000,0x8DFC0000,0xB0000001,0x8DFC0000,0x8DFC0000,0xB0000001,0xB0000001,0x15FC0000,0x15FC0000,0x15FC0000,0x8DFC0000,0x8DFC0000,0xB0000001,0x8DFC0000,0x8DFC0000,0xB0000001,0xB0000001,0x8DFC0000,
-0x8DFC0000,0xB0000001,0xB0000001,0xB0000001,0x59C0000,0x17C0000,0x1640000,0x1E40000,0x43FC0000,0x6FFC0000,0x7FF80000,0x97F80000,0x3BC0000,0x15FC0000,0x6FFC0000,0xB0000001,0x6FFC0000,0x19C0001,0x6FFC0000,0xB9F80000,0xCE000000,0x6FFC0000,0xB9F80000,0xCE000000,0xB9F80000,0xCE000000,0xCE000000,0x6FFC0000,0xB9F80000,0xCE000000,0xB9F80000,0xCE000000,
-0xCE000000,0xB9F80000,0xCE000000,0xCE000000,0xCE000000,0x6FFC0000,0xB9F80000,0xCE000000,0xB9F80000,0xCE000000,0xCE000000,0xB9F80000,0xCE000000,0xCE000000,0xCE000000,0xB9F80000,0xCE000000,0xCE000000,0xCE000000,0xCE000000,0x15FC0000,0x5B80000,0x5B80000,0x8BFC0000,0xAFFC0000,0xC3F80000,0xCE000000,0xCE000000,0x4DFC0000,0x99FC0000,0xCDCC0000,0xCE000000,
-0xA5FC0000,0x1480F1E,0xFF340795,0xEB2C05ED,0xCF2C05ED,0xFF2404B6,0xF31801C5,0xD31C0286,0xDB14034A,0xCD1001BD,0xC114034A,0xFF0C06AE,0xF8F80154,0xD508020F,0xE0F001B6,0xCCF80006,0xC0FC01BE,0xCEF405EB,0xC6EC020D,0xBAEC028A,0xB2F405EB,0x3E80F1A,0xFECC05F1,0xCEF805EA,0xF4A8034A,0xD0D001B2,0xC0DC034A,0xE69005EB,0xCEA00153,0xBEB001C3,0xB2C005EA,0x79FC0F1A,
-0xCE4805EA,0xC02C034A,0xB21005EA,0xA4000F1A,0xFF340865,0xFB440CAA,0xFD480D3E,0xFF1402EF,0xFEFC0019,0xE2F80004,0xD1000025,0xCAF40023,0xFF240839,0xFF000256,0xD2E80159,0xBEB001C3,0x57FC0F1A,0x16405ED,0xFF5001C8,0xE34C0154,0xCF480154,0xFF3C01D5,0xE9300002,0xCF380029,0xD33001A5,0xC92C004C,0xC13001A5,0x19FC05EA,0xF4FC0153,0xCF200152,0xE6E401A5,0xCCF80005,
-0xC10801A5,0x8FF805EA,0xCE9C0152,0xC08801A5,0xB20005EA,0x19FC05EA,0xF4FC0153,0xCF200152,0xE6E401A5,0xCCF80005,0xC10801A5,0x8FF805EA,0xCE9C0152,0xC08801A5,0xB20005EA,0x8FF805EA,0xCE9C0152,0xC08801A5,0xB20005EA,0xB20005EA,0xFF500376,0xF96004ED,0xFB6404E4,0xFF2C016D,0xFEFC0010,0xE2F80003,0xCF080001,0xCCE0000C,0xFD40039E,0xFF180122,0xD4DC0152,0xC08801A5,
-0x71FC05EA,0x12C05ED,0x12C05ED,0x12C05ED,0x12C05ED,0xFD1401A9,0xFD1401A9,0xFD1401A9,0xC51401A5,0xC51401A5,0xB11401A6,0xF8F80153,0xF8F80153,0xF8F80153,0xCCF80002,0xCCF80002,0xB300004B,0xB8F80153,0xB8F80153,0xACF4002A,0xA4F40153,0x1C005EA,0x1C005EA,0x1C005EA,0xD8C401A5,0xD8C401A5,0xB0EC01A6,0xCAAC0153,0xCAAC0153,0xB2C00001,0xA4CC0152,0x65F805EA,
-0x65F805EA,0xB06C01A6,0xA4480152,0x960005EA,0xFF2002FE,0xFD280492,0x12C05ED,0xFF080103,0xFEF80003,0xE0F80002,0xD8F8000B,0xC4F40002,0xFF0C02D3,0xFEF400CA,0xCEEC0153,0xB2C00001,0x3DF805EA,0x1480154,0x1480154,0x1480154,0x1480154,0xE7300000,0xE7300000,0xE7300000,0xBF300000,0xBF300000,0xB1300001,0x3E80152,0x3E80152,0x3E80152,0xC9000001,0xC9000001,
-0xB1180001,0x79FC0152,0x79FC0152,0xB0C80001,0xA4000152,0x3E80152,0x3E80152,0x3E80152,0xC9000001,0xC9000001,0xB1180001,0x79FC0152,0x79FC0152,0xB0C80001,0xA4000152,0x79FC0152,0x79FC0152,0xB0C80001,0xA4000152,0xA4000152,0xFB3400A4,0xFB4400C8,0x1480154,0xFF180041,0xFCFC0000,0xDEFC0000,0xD1080000,0xC6F00000,0xF92800B5,0xFF04003A,0x57FC0152,0xB0C80001,
-0x57FC0152,0x18001A5,0xFF680008,0xDD640000,0xCF640000,0x41FC01A5,0xEB2C0000,0xCF480000,0xA1FC01A5,0xCEEC0000,0xC00001A5,0x41FC01A5,0xEB2C0000,0xCF480000,0xA1FC01A5,0xCEEC0000,0xC00001A5,0xA1FC01A5,0xCEEC0000,0xC00001A5,0xC00001A5,0x41FC01A5,0xEB2C0000,0xCF480000,0xA1FC01A5,0xCEEC0000,0xC00001A5,0xA1FC01A5,0xCEEC0000,0xC00001A5,0xC00001A5,0xA1FC01A5,
-0xCEEC0000,0xC00001A5,0xC00001A5,0xC00001A5,0xFD680120,0x19C01A5,0xF77C0139,0xFF400071,0xFEFC0010,0xE4F00000,0xCF100000,0xCEC00000,0xFF5C0109,0xFF2C0064,0xD3180000,0xC00001A5,0x89FC01A5,0x11401A5,0x11401A5,0x11401A5,0x11401A5,0x11401A5,0x11401A5,0x11401A5,0x11401A5,0x11401A5,0x11401A5,0xD0F80001,0xD0F80001,0xD0F80001,0xD0F80001,0xD0F80001,
-0xD0F80001,0xA4F80001,0xA4F80001,0xA4F80001,0x96F40002,0x19801A5,0x19801A5,0x19801A5,0x19801A5,0x19801A5,0x19801A5,0xB2C00000,0xB2C00000,0xB2C00000,0x96DC0001,0x51F801A5,0x51F801A5,0x51F801A5,0x96840001,0x880001A5,0xFF0C00DD,0x11401A5,0x11401A5,0xFD00003D,0xFEF80002,0xE4F80001,0xE4F80001,0xC0F80001,0xFEF400AA,0xFAF00032,0xB4F00001,0xB2C00000,
-0x21FC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table117[] = {
-0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x1840000,0x47FC0000,
-0x47FC0000,0x47FC0000,0x47FC0000,0x82000000,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1040001,0x1180000,0x1180000,0x1180000,0x1840000,0x17FC0000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,
-0x1DC0000,0x73F80000,0x73F80000,0x73F80000,0x9E000001,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x73F80000,0x73F80000,0x73F80000,0x9E000001,0x73F80000,0x73F80000,0x73F80000,0x9E000001,0x9E000001,0x3540000,0x1400000,0x1400000,0x1740000,0x1900000,0x1B40000,0x1B40000,0x17FC0000,0x1740000,0x1900000,0x4DFC0000,0x73F80000,
-0x4DFC0000,0x1740000,0x1740000,0x1740000,0x1740000,0x2FFC0000,0x2FFC0000,0x2FFC0000,0x99FC0000,0x99FC0000,0xB8000001,0x2FFC0000,0x2FFC0000,0x2FFC0000,0x99FC0000,0x99FC0000,0xB8000001,0x99FC0000,0x99FC0000,0xB8000001,0xB8000001,0x2FFC0000,0x2FFC0000,0x2FFC0000,0x99FC0000,0x99FC0000,0xB8000001,0x99FC0000,0x99FC0000,0xB8000001,0xB8000001,0x99FC0000,
-0x99FC0000,0xB8000001,0xB8000001,0xB8000001,0x1B00000,0x18C0000,0x1740000,0x3F80000,0x57FC0000,0x7FF80000,0x8BFC0000,0xA1FC0000,0x5D00000,0x2FFC0000,0x7FF80000,0xB8000001,0x7FF80000,0x1AC0001,0x87FC0000,0xC5F80000,0xD6000000,0x87FC0000,0xC5F80000,0xD6000000,0xC5F80000,0xD6000000,0xD6000000,0x87FC0000,0xC5F80000,0xD6000000,0xC5F80000,0xD6000000,
-0xD6000000,0xC5F80000,0xD6000000,0xD6000000,0xD6000000,0x87FC0000,0xC5F80000,0xD6000000,0xC5F80000,0xD6000000,0xD6000000,0xC5F80000,0xD6000000,0xD6000000,0xD6000000,0xC5F80000,0xD6000000,0xD6000000,0xD6000000,0xD6000000,0x3DFC0000,0xDC80000,0xDC80000,0x9DFC0000,0xBDF80000,0xCDF80000,0xD6000000,0xD6000000,0x6BFC0000,0xABFC0000,0xD5DC0000,0xD6000000,
-0xB5FC0000,0x1580F1E,0xFF4407E9,0xF33C05ED,0xD73C05ED,0xFF300542,0xFB2801C5,0xDB2C0286,0xE324034A,0xD52001BD,0xC924034A,0xFF240716,0xFF080155,0xDD18020F,0xE90001B6,0xD5080006,0xC90C01BE,0xD70405EB,0xCEFC020D,0xC2FC028A,0xBB0405EB,0x7FC0F1A,0xFEE40611,0xD70805EA,0xFCB8034A,0xD8E001B2,0xC8EC034A,0xEEA005EB,0xD6B00153,0xC6C001C3,0xBAD005EA,0x85FC0F1A,
-0xD65805EA,0xC83C034A,0xBA2005EA,0xAC000F1A,0xFF4408FE,0xFF4C0CEA,0xF5580D89,0xFF2C03A6,0xFF10005D,0xEB080004,0xD9100025,0xD3040023,0xFF340886,0xFF180302,0xDAF80159,0xC6C001C3,0x65FC0F1A,0x17405ED,0xFF60020D,0xEB5C0154,0xD7580154,0xFF5001FD,0xF1400002,0xD7480029,0xDB4001A5,0xD13C004C,0xC94001A5,0x31FC05EA,0xFD0C0153,0xD7300152,0xEEF401A5,0xD5080005,
-0xC91801A5,0x9BF805EA,0xD6AC0152,0xC89801A5,0xBA0005EA,0x31FC05EA,0xFD0C0153,0xD7300152,0xEEF401A5,0xD5080005,0xC91801A5,0x9BF805EA,0xD6AC0152,0xC89801A5,0xBA0005EA,0x9BF805EA,0xD6AC0152,0xC89801A5,0xBA0005EA,0xBA0005EA,0xFF5803C9,0xFF6C04F5,0xFF6C0504,0xFF4001AA,0xFF18003B,0xEB080003,0xD7180001,0xD4F0000C,0xFF5403C9,0xFF2C017D,0xDCEC0152,0xC89801A5,
-0x7FFC05EA,0x13C05ED,0x13C05ED,0x13C05ED,0x13C05ED,0xFF2401B5,0xFF2401B5,0xFF2401B5,0xCD2401A5,0xCD2401A5,0xB92401A6,0xFD080155,0xFD080155,0xFD080155,0xD5080002,0xD5080002,0xBB10004B,0xC1080153,0xC1080153,0xB504002A,0xAD040153,0x1D805EA,0x1D805EA,0x1D805EA,0xE0D401A5,0xE0D401A5,0xB8FC01A6,0xD2BC0153,0xD2BC0153,0xBAD00001,0xACDC0152,0x71F805EA,
-0x71F805EA,0xB87C01A6,0xAC580152,0x9E0005EA,0xFF2C032B,0xF53804C1,0x13C05ED,0xFF1C0141,0xFF0C0013,0xE9080002,0xE108000B,0xCD040002,0xFF2002F9,0xFF100109,0xD6FC0153,0xBAD00001,0x4BFC05EA,0x1580154,0x1580154,0x1580154,0x1580154,0xEF400000,0xEF400000,0xEF400000,0xC7400000,0xC7400000,0xB9400001,0x7FC0152,0x7FC0152,0x7FC0152,0xD1100001,0xD1100001,
-0xB9280001,0x85FC0152,0x85FC0152,0xB8D80001,0xAC000152,0x7FC0152,0x7FC0152,0x7FC0152,0xD1100001,0xD1100001,0xB9280001,0x85FC0152,0x85FC0152,0xB8D80001,0xAC000152,0x85FC0152,0x85FC0152,0xB8D80001,0xAC000152,0xAC000152,0xF74800B5,0xF35400DD,0x1580154,0xFD300055,0xFD140002,0xE70C0000,0xD9180000,0xCF000000,0xFF3400B9,0xFD200048,0x65FC0152,0xB8D80001,
-0x65FC0152,0x19001A5,0xFF78001D,0xE5740000,0xD7740000,0x59FC01A5,0xF33C0000,0xD7580000,0xADFC01A5,0xD6FC0000,0xC80001A5,0x59FC01A5,0xF33C0000,0xD7580000,0xADFC01A5,0xD6FC0000,0xC80001A5,0xADFC01A5,0xD6FC0000,0xC80001A5,0xC80001A5,0x59FC01A5,0xF33C0000,0xD7580000,0xADFC01A5,0xD6FC0000,0xC80001A5,0xADFC01A5,0xD6FC0000,0xC80001A5,0xC80001A5,0xADFC01A5,
-0xD6FC0000,0xC80001A5,0xC80001A5,0xC80001A5,0xFF780122,0x1AC01A5,0xFF8C0139,0xFF580091,0xFF240020,0xED000000,0xD7200000,0xD6D00000,0xFF700120,0xFF40007D,0xDB280000,0xC80001A5,0x99FC01A5,0x12401A5,0x12401A5,0x12401A5,0x12401A5,0x12401A5,0x12401A5,0x12401A5,0x12401A5,0x12401A5,0x12401A5,0xD9080001,0xD9080001,0xD9080001,0xD9080001,0xD9080001,
-0xD9080001,0xAD080001,0xAD080001,0xAD080001,0x9F040002,0x1B001A5,0x1B001A5,0x1B001A5,0x1B001A5,0x1B001A5,0x1B001A5,0xBAD00000,0xBAD00000,0xBAD00000,0x9EEC0001,0x5DF401A5,0x5DF401A5,0x5DF401A5,0x9E940001,0x900001A5,0xF71C00F2,0x12401A5,0x12401A5,0xFF10004A,0xFD08000A,0xED080001,0xED080001,0xC9080001,0xFD0C00B5,0xFF00003D,0xBD000001,0xBAD00000,
-0x31FC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table118[] = {
-0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x53FC0000,
-0x53FC0000,0x53FC0000,0x53FC0000,0x8A000000,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1140001,0x1280000,0x1280000,0x1280000,0x19C0000,0x25FC0000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,
-0x1F40000,0x7FF80000,0x7FF80000,0x7FF80000,0xA6000001,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x1F40000,0x7FF80000,0x7FF80000,0x7FF80000,0xA6000001,0x7FF80000,0x7FF80000,0x7FF80000,0xA6000001,0xA6000001,0xB640000,0x1500000,0x1500000,0x7840000,0x1A40000,0x1C80000,0x1C80000,0x2BFC0000,0x7840000,0x1A40000,0x5DF80000,0x7FF80000,
-0x5DF80000,0x1840000,0x1840000,0x1840000,0x1840000,0x47FC0000,0x47FC0000,0x47FC0000,0xA5F80000,0xA5F80000,0xC0000001,0x47FC0000,0x47FC0000,0x47FC0000,0xA5F80000,0xA5F80000,0xC0000001,0xA5F80000,0xA5F80000,0xC0000001,0xC0000001,0x47FC0000,0x47FC0000,0x47FC0000,0xA5F80000,0xA5F80000,0xC0000001,0xA5F80000,0xA5F80000,0xC0000001,0xC0000001,0xA5F80000,
-0xA5F80000,0xC0000001,0xC0000001,0xC0000001,0x1C40000,0x79C0000,0x1840000,0x1BFC0000,0x6BFC0000,0x8DFC0000,0x99FC0000,0xADF80000,0x5E40000,0x47FC0000,0x8DFC0000,0xC0000001,0x8DFC0000,0x1BC0001,0x9FFC0000,0xD1F80000,0xDE000000,0x9FFC0000,0xD1F80000,0xDE000000,0xD1F80000,0xDE000000,0xDE000000,0x9FFC0000,0xD1F80000,0xDE000000,0xD1F80000,0xDE000000,
-0xDE000000,0xD1F80000,0xDE000000,0xDE000000,0xDE000000,0x9FFC0000,0xD1F80000,0xDE000000,0xD1F80000,0xDE000000,0xDE000000,0xD1F80000,0xDE000000,0xDE000000,0xDE000000,0xD1F80000,0xDE000000,0xDE000000,0xDE000000,0xDE000000,0x63FC0000,0x1DC0000,0x1DC0000,0xB1FC0000,0xC9FC0000,0xD7F80000,0xDE000000,0xDE000000,0x89FC0000,0xBBFC0000,0xDDEC0000,0xDE000000,
-0xC3FC0000,0x1680F1E,0xFF5C0861,0xFB4C05ED,0xDF4C05ED,0xFF4405BA,0xFF3801D5,0xE33C0286,0xEB34034A,0xDD3001BD,0xD134034A,0xFF300786,0xFF1C017C,0xE528020F,0xF11001B6,0xDD180006,0xD11C01BE,0xDF1405EB,0xD70C020D,0xCB0C028A,0xC31405EB,0x1FFC0F1A,0xFEFC0651,0xDF1805EA,0xFED4035A,0xE0F001B2,0xD0FC034A,0xF6B005EB,0xDEC00153,0xCED001C3,0xC2E005EA,0x91FC0F1A,
-0xDE6805EA,0xD04C034A,0xC23005EA,0xB4000F1A,0xFF58097A,0xFB640D0E,0xFD680D89,0xFF400463,0xFF2400D1,0xF3180004,0xE1200025,0xDB140023,0xFF440933,0xFF3003D3,0xE3080159,0xCED001C3,0x75FC0F1A,0x18405ED,0xFF740248,0xF36C0154,0xDF680154,0xFF5C0239,0xF9500002,0xDF580029,0xE35001A5,0xD94C004C,0xD15001A5,0x49FC05EA,0xFF280163,0xDF400152,0xF70401A5,0xDD180005,
-0xD12801A5,0xA7F805EA,0xDEBC0152,0xD0A801A5,0xC20005EA,0x49FC05EA,0xFF280163,0xDF400152,0xF70401A5,0xDD180005,0xD12801A5,0xA7F805EA,0xDEBC0152,0xD0A801A5,0xC20005EA,0xA7F805EA,0xDEBC0152,0xD0A801A5,0xC20005EA,0xC20005EA,0xFD7403F6,0xF980051D,0xFB840515,0xFF540209,0xFF30007D,0xF3180003,0xDF280001,0xDD00000C,0xFF5C040A,0xFF4801C4,0xE4FC0152,0xD0A801A5,
-0x8FFC05EA,0x14C05ED,0x14C05ED,0x14C05ED,0x14C05ED,0xFD3801D5,0xFD3801D5,0xFD3801D5,0xD53401A5,0xD53401A5,0xC13401A6,0xFF1C0163,0xFF1C0163,0xFF1C0163,0xDD180002,0xDD180002,0xC320004B,0xC9180153,0xC9180153,0xBD14002A,0xB5140153,0x1F005EA,0x1F005EA,0x1F005EA,0xE8E401A5,0xE8E401A5,0xC10C01A6,0xDACC0153,0xDACC0153,0xC2E00001,0xB4EC0152,0x7DF805EA,
-0x7DF805EA,0xC08C01A6,0xB4680152,0xA60005EA,0xFF3C035D,0xFD4804C1,0x14C05ED,0xFF2C0182,0xFF200033,0xF1180002,0xE918000B,0xD5140002,0xFF340322,0xFF1C014E,0xDF0C0153,0xC2E00001,0x5BFC05EA,0x1680154,0x1680154,0x1680154,0x1680154,0xF7500000,0xF7500000,0xF7500000,0xCF500000,0xCF500000,0xC1500001,0x1FFC0152,0x1FFC0152,0x1FFC0152,0xD9200001,0xD9200001,
-0xC1380001,0x91FC0152,0x91FC0152,0xC0E80001,0xB4000152,0x1FFC0152,0x1FFC0152,0x1FFC0152,0xD9200001,0xD9200001,0xC1380001,0x91FC0152,0x91FC0152,0xC0E80001,0xB4000152,0x91FC0152,0x91FC0152,0xC0E80001,0xB4000152,0xB4000152,0xFF5800B5,0xFB6400DD,0x1680154,0xFF440062,0xFD28000A,0xEF1C0000,0xE1280000,0xD7100000,0xFD4C00C8,0xFF300059,0x75FC0152,0xC0E80001,
-0x75FC0152,0x1A001A5,0xFF8C0034,0xED840000,0xDF840000,0x71FC01A5,0xFB4C0000,0xDF680000,0xB9FC01A5,0xDF0C0000,0xD00001A5,0x71FC01A5,0xFB4C0000,0xDF680000,0xB9FC01A5,0xDF0C0000,0xD00001A5,0xB9FC01A5,0xDF0C0000,0xD00001A5,0xD00001A5,0x71FC01A5,0xFB4C0000,0xDF680000,0xB9FC01A5,0xDF0C0000,0xD00001A5,0xB9FC01A5,0xDF0C0000,0xD00001A5,0xD00001A5,0xB9FC01A5,
-0xDF0C0000,0xD00001A5,0xD00001A5,0xD00001A5,0xFD900139,0x1BC01A5,0xF79C0154,0xFF6C00AA,0xFF3C003A,0xF5100000,0xDF300000,0xDEE00000,0xF7880139,0xFF6400A2,0xE3380000,0xD00001A5,0xA7FC01A5,0x13401A5,0x13401A5,0x13401A5,0x13401A5,0x13401A5,0x13401A5,0x13401A5,0x13401A5,0x13401A5,0x13401A5,0xE1180001,0xE1180001,0xE1180001,0xE1180001,0xE1180001,
-0xE1180001,0xB5180001,0xB5180001,0xB5180001,0xA7140002,0x1C801A5,0x1C801A5,0x1C801A5,0x1C801A5,0x1C801A5,0x1C801A5,0xC2E00000,0xC2E00000,0xC2E00000,0xA6FC0001,0x67FC01A5,0x67FC01A5,0x67FC01A5,0xA6A40001,0x980001A5,0xFF2C00F2,0x13401A5,0x13401A5,0xFF200059,0xFD1C0012,0xF5180001,0xF5180001,0xD1180001,0xFD1C00C8,0xFF140048,0xC5100001,0xC2E00000,
-0x3FFC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table119[] = {
-0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x5FF80000,
-0x5FF80000,0x5FF80000,0x5FF80000,0x92000000,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x5380000,0x5380000,0x5380000,0x1B40000,0x35FC0000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0x1600000,0xFFC0000,0xFFC0000,0xFFC0000,0xFFC0000,0xFFC0000,
-0xFFC0000,0x8BF80000,0x8BF80000,0x8BF80000,0xAE000001,0xFFC0000,0xFFC0000,0xFFC0000,0xFFC0000,0xFFC0000,0xFFC0000,0x8BF80000,0x8BF80000,0x8BF80000,0xAE000001,0x8BF80000,0x8BF80000,0x8BF80000,0xAE000001,0xAE000001,0x1780000,0x1600000,0x1600000,0x3980000,0x1B80000,0x3DC0000,0x3DC0000,0x3DFC0000,0x3980000,0x1B80000,0x6BFC0000,0x8BF80000,
-0x6BFC0000,0x1940000,0x1940000,0x1940000,0x1940000,0x5FFC0000,0x5FFC0000,0x5FFC0000,0xB1F80000,0xB1F80000,0xC8000001,0x5FFC0000,0x5FFC0000,0x5FFC0000,0xB1F80000,0xB1F80000,0xC8000001,0xB1F80000,0xB1F80000,0xC8000001,0xC8000001,0x5FFC0000,0x5FFC0000,0x5FFC0000,0xB1F80000,0xB1F80000,0xC8000001,0xB1F80000,0xB1F80000,0xC8000001,0xC8000001,0xB1F80000,
-0xB1F80000,0xC8000001,0xC8000001,0xC8000001,0x3D40000,0xFAC0000,0x1940000,0x39FC0000,0x7DFC0000,0x9DF80000,0xA7F80000,0xB7FC0000,0x5F80000,0x5FFC0000,0x9DF80000,0xC8000001,0x9DF80000,0x1CC0001,0xB7FC0000,0xDDF40000,0xE6000000,0xB7FC0000,0xDDF40000,0xE6000000,0xDDF40000,0xE6000000,0xE6000000,0xB7FC0000,0xDDF40000,0xE6000000,0xDDF40000,0xE6000000,
-0xE6000000,0xDDF40000,0xE6000000,0xE6000000,0xE6000000,0xB7FC0000,0xDDF40000,0xE6000000,0xDDF40000,0xE6000000,0xE6000000,0xDDF40000,0xE6000000,0xE6000000,0xE6000000,0xDDF40000,0xE6000000,0xE6000000,0xE6000000,0xE6000000,0x8BFC0000,0x1EC0000,0x1EC0000,0xC5FC0000,0xD7FC0000,0xE1FC0000,0xE6000000,0xE6000000,0xA7FC0000,0xCDFC0000,0xE5FC0000,0xE6000000,
-0xD3FC0000,0x1780F1E,0xFF6808D9,0xFF6005F1,0xE75C05ED,0xFF5C0662,0xFF480215,0xEB4C0286,0xF344034A,0xE54001BD,0xD944034A,0xFF4407F7,0xFF3401DC,0xED38020F,0xF92001B6,0xE5280006,0xD92C01BE,0xE72405EB,0xDF1C020D,0xD31C028A,0xCB2405EB,0x37FC0F1A,0xFF1406B1,0xE72805EA,0xFEF00392,0xE90001B2,0xD90C034A,0xFEC005EB,0xE6D00153,0xD6E001C3,0xCAF005EA,0x9DFC0F1A,
-0xE67805EA,0xD85C034A,0xCA4005EA,0xBC000F1A,0xFF6409F4,0xFF6C0D5E,0xF5780DD6,0xFF54052A,0xFF380175,0xFB280004,0xE9300025,0xE3240023,0xFF5C09AA,0xFF40048F,0xEB180159,0xD6E001C3,0x83FC0F1A,0x19405ED,0xFF8402A5,0xFB7C0154,0xE7780154,0xFF740279,0xFF600004,0xE7680029,0xEB6001A5,0xE15C004C,0xD96001A5,0x63FC05EA,0xFF40018B,0xE7500152,0xFF1401A5,0xE5280005,
-0xD93801A5,0xB3F805EA,0xE6CC0152,0xD8B801A5,0xCA0005EA,0x63FC05EA,0xFF40018B,0xE7500152,0xFF1401A5,0xE5280005,0xD93801A5,0xB3F805EA,0xE6CC0152,0xD8B801A5,0xCA0005EA,0xB3F805EA,0xE6CC0152,0xD8B801A5,0xCA0005EA,0xCA0005EA,0xFF800435,0xFF8C052D,0xFF8C053D,0xFF6C026A,0xFF4800CE,0xFB280003,0xE7380001,0xE510000C,0xFF78042A,0xFF5C022E,0xED0C0152,0xD8B801A5,
-0x9FF805EA,0x15C05ED,0x15C05ED,0x15C05ED,0x15C05ED,0xFF4801F1,0xFF4801F1,0xFF4801F1,0xDD4401A5,0xDD4401A5,0xC94401A6,0xFF30017D,0xFF30017D,0xFF30017D,0xE5280002,0xE5280002,0xCB30004B,0xD1280153,0xD1280153,0xC524002A,0xBD240153,0xDFC05EA,0xDFC05EA,0xDFC05EA,0xF0F401A5,0xF0F401A5,0xC91C01A6,0xE2DC0153,0xE2DC0153,0xCAF00001,0xBCFC0152,0x89F805EA,
-0x89F805EA,0xC89C01A6,0xBC780152,0xAE0005EA,0xFF4C038A,0xF75C04EE,0x15C05ED,0xFF4401C3,0xFF300062,0xF9280002,0xF128000B,0xDD240002,0xFF3C0371,0xFF300182,0xE71C0153,0xCAF00001,0x69FC05EA,0x1780154,0x1780154,0x1780154,0x1780154,0xFF600000,0xFF600000,0xFF600000,0xD7600000,0xD7600000,0xC9600001,0x37FC0152,0x37FC0152,0x37FC0152,0xE1300001,0xE1300001,
-0xC9480001,0x9DFC0152,0x9DFC0152,0xC8F80001,0xBC000152,0x37FC0152,0x37FC0152,0x37FC0152,0xE1300001,0xE1300001,0xC9480001,0x9DFC0152,0x9DFC0152,0xC8F80001,0xBC000152,0x9DFC0152,0x9DFC0152,0xC8F80001,0xBC000152,0xBC000152,0xFB6C00C8,0xF37400F4,0x1780154,0xFD580071,0xFF400012,0xF72C0000,0xE9380000,0xDF200000,0xF56400DD,0xFF480064,0x83FC0152,0xC8F80001,
-0x83FC0152,0x1B001A5,0xFF9C0061,0xF5940000,0xE7940000,0x89FC01A5,0xFF640002,0xE7780000,0xC5FC01A5,0xE71C0000,0xD80001A5,0x89FC01A5,0xFF640002,0xE7780000,0xC5FC01A5,0xE71C0000,0xD80001A5,0xC5FC01A5,0xE71C0000,0xD80001A5,0xD80001A5,0x89FC01A5,0xFF640002,0xE7780000,0xC5FC01A5,0xE71C0000,0xD80001A5,0xC5FC01A5,0xE71C0000,0xD80001A5,0xD80001A5,0xC5FC01A5,
-0xE71C0000,0xD80001A5,0xD80001A5,0xD80001A5,0xF7A40152,0x1CC01A5,0xFFAC0154,0xFF8400D0,0xFF640062,0xFD200000,0xE7400000,0xE6F00000,0xFF980139,0xFD8000C8,0xEB480000,0xD80001A5,0xB7FC01A5,0x14401A5,0x14401A5,0x14401A5,0x14401A5,0x14401A5,0x14401A5,0x14401A5,0x14401A5,0x14401A5,0x14401A5,0xE9280001,0xE9280001,0xE9280001,0xE9280001,0xE9280001,
-0xE9280001,0xBD280001,0xBD280001,0xBD280001,0xAF240002,0x1E001A5,0x1E001A5,0x1E001A5,0x1E001A5,0x1E001A5,0x1E001A5,0xCAF00000,0xCAF00000,0xCAF00000,0xAF0C0001,0x73FC01A5,0x73FC01A5,0x73FC01A5,0xAEB40001,0xA00001A5,0xF73C0109,0x14401A5,0x14401A5,0xFB340071,0xFB2C0022,0xFD280001,0xFD280001,0xD9280001,0xF93000DD,0xFF200061,0xCD200001,0xCAF00000,
-0x4FFC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table120[] = {
-0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x6DF80000,
-0x6DF80000,0x6DF80000,0x6DF80000,0x9A000001,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x14C0000,0x14C0000,0x14C0000,0x1D00000,0x45FC0000,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x1700001,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,
-0x2BFC0000,0x97FC0000,0x97FC0000,0x97FC0000,0xB8000000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x2BFC0000,0x97FC0000,0x97FC0000,0x97FC0000,0xB8000000,0x97FC0000,0x97FC0000,0x97FC0000,0xB8000000,0xB8000000,0xD880000,0x1700001,0x1700001,0x5AC0000,0x1D00000,0x1F80000,0x1F80000,0x53FC0000,0x5AC0000,0x1D00000,0x7DF80000,0x97FC0000,
-0x7DF80000,0x1A40001,0x1A40001,0x1A40001,0x1A40001,0x7BFC0000,0x7BFC0000,0x7BFC0000,0xBFF80000,0xBFF80000,0xD2000000,0x7BFC0000,0x7BFC0000,0x7BFC0000,0xBFF80000,0xBFF80000,0xD2000000,0xBFF80000,0xBFF80000,0xD2000000,0xD2000000,0x7BFC0000,0x7BFC0000,0x7BFC0000,0xBFF80000,0xBFF80000,0xD2000000,0xBFF80000,0xBFF80000,0xD2000000,0xD2000000,0xBFF80000,
-0xBFF80000,0xD2000000,0xD2000000,0xD2000000,0x7E80000,0x9C00000,0x1A40001,0x5BFC0000,0x93FC0000,0xADFC0000,0xB5FC0000,0xC3FC0000,0x29FC0000,0x7BFC0000,0xADFC0000,0xD2000000,0xADFC0000,0x1E00000,0xD3FC0000,0xE9FC0000,0xEE000001,0xD3FC0000,0xE9FC0000,0xEE000001,0xE9FC0000,0xEE000001,0xEE000001,0xD3FC0000,0xE9FC0000,0xEE000001,0xE9FC0000,0xEE000001,
-0xEE000001,0xE9FC0000,0xEE000001,0xEE000001,0xEE000001,0xD3FC0000,0xE9FC0000,0xEE000001,0xE9FC0000,0xEE000001,0xEE000001,0xE9FC0000,0xEE000001,0xEE000001,0xEE000001,0xE9FC0000,0xEE000001,0xEE000001,0xEE000001,0xEE000001,0xB7FC0000,0x17FC0000,0x17FC0000,0xDBFC0000,0xE7F80000,0xEDF40000,0xEE000001,0xEE000001,0xC9FC0000,0xE1FC0000,0xEFF00000,0xEE000001,
-0xE3FC0000,0x18C0F1A,0xFF800983,0xFF70062A,0xEF7005EB,0xFF680746,0xFF6002AB,0xF35C028A,0xFD54034A,0xED5401BE,0xE154034A,0xFF5C0899,0xFF4C028C,0xF548020D,0xFF3801BA,0xEF380006,0xE33C01BD,0xEF3805EA,0xE72C020F,0xDD300286,0xD33805ED,0x53FC0F1A,0xFF38073B,0xF13805EB,0xFF140416,0xF11001B6,0xE120034A,0xFEE40615,0xEEE40154,0xDEF001C5,0xD50005ED,0xABF80F1A,
-0xEE8C05EB,0xE070034A,0xD25405ED,0xC4000F1E,0xFF780A99,0xFD880D72,0xFD880DDA,0xFF6C0649,0xFF500261,0xFF3C001F,0xF1400023,0xEB340025,0xFF700A53,0xFF54059A,0xF52C015B,0xDEF001C5,0x95FC0F1A,0x1A805EA,0xFF980303,0xFF8C0162,0xEF8C0153,0xFF8C02DE,0xFF78003B,0xF17C002A,0xF57001A6,0xEB70004B,0xE17001A6,0x7DFC05EA,0xFF5801E4,0xEF640153,0xFF3801BA,0xEF3C0002,
-0xE14C01A5,0xBFFC05EA,0xEEE40153,0xE0CC01A5,0xD20005ED,0x7DFC05EA,0xFF5801E4,0xEF640153,0xFF3801BA,0xEF3C0002,0xE14C01A5,0xBFFC05EA,0xEEE40153,0xE0CC01A5,0xD20005ED,0xBFFC05EA,0xEEE40153,0xE0CC01A5,0xD20005ED,0xD20005ED,0xFF94046D,0xFBA4054E,0xFBA4054B,0xFF8002E8,0xFF680146,0xFF400011,0xF14C0002,0xEF24000B,0xFD940481,0xFF7402C9,0xF71C0152,0xE0CC01A5,
-0xAFFC05EA,0x17005EA,0x17005EA,0x17005EA,0x17005EA,0xFF5C0221,0xFF5C0221,0xFF5C0221,0xE75401A5,0xE75401A5,0xD35401A5,0xFF4401A8,0xFF4401A8,0xFF4401A8,0xED380005,0xED380005,0xD544004C,0xDB380152,0xDB380152,0xCF380029,0xC5380154,0x29FC05EA,0x29FC05EA,0x29FC05EA,0xF90801A5,0xF90801A5,0xD32C01A5,0xECEC0153,0xECEC0153,0xD3000002,0xC5100154,0x97F805EA,
-0x97F805EA,0xD2AC01A5,0xC4900154,0xB60005ED,0xFD6403CC,0xFF6C04ED,0x17005EA,0xFF540211,0xFF4400AD,0xFF3C0006,0xFB3C000C,0xE7380001,0xFF58039E,0xFD4C01E2,0xF12C0152,0xD3000002,0x7BFC05EA,0x18C0152,0x18C0152,0x18C0152,0x18C0152,0xFF740005,0xFF740005,0xFF740005,0xDF740001,0xDF740001,0xD3700001,0x53FC0152,0x53FC0152,0x53FC0152,0xE9440001,0xE9440001,
-0xD3580000,0xABF80152,0xABF80152,0xD3080000,0xC4000154,0x53FC0152,0x53FC0152,0x53FC0152,0xE9440001,0xE9440001,0xD3580000,0xABF80152,0xABF80152,0xD3080000,0xC4000154,0xABF80152,0xABF80152,0xD3080000,0xC4000154,0xC4000154,0xF78000DD,0xFD8800F2,0x18C0152,0xFB700091,0xFF540028,0xFF400001,0xF3480000,0xE7340000,0xFD7400DD,0xFF5C007D,0x95FC0152,0xD3080000,
-0x95FC0152,0x1C401A5,0xFFB00092,0xFDA80001,0xEFA40002,0xA5FC01A5,0xFF880020,0xEF8C0001,0xD3FC01A5,0xEF340001,0xE00001A5,0xA5FC01A5,0xFF880020,0xEF8C0001,0xD3FC01A5,0xEF340001,0xE00001A5,0xD3FC01A5,0xEF340001,0xE00001A5,0xE00001A5,0xA5FC01A5,0xFF880020,0xEF8C0001,0xD3FC01A5,0xEF340001,0xE00001A5,0xD3FC01A5,0xEF340001,0xE00001A5,0xE00001A5,0xD3FC01A5,
-0xEF340001,0xE00001A5,0xE00001A5,0xE00001A5,0xFFB40154,0x1E001A5,0xF9C0016D,0xFFA000FA,0xFF7C0092,0xFF48000A,0xEF540001,0xEF080001,0xFFAC015A,0xFF9400E9,0xF5580000,0xE00001A5,0xC7FC01A5,0x15401A5,0x15401A5,0x15401A5,0x15401A5,0x15401A5,0x15401A5,0x15401A5,0x15401A5,0x15401A5,0x15401A5,0xF3380000,0xF3380000,0xF3380000,0xF3380000,0xF3380000,
-0xF3380000,0xC7380000,0xC7380000,0xC7380000,0xB9380000,0x1F801A5,0x1F801A5,0x1F801A5,0x1F801A5,0x1F801A5,0x1F801A5,0xD5000000,0xD5000000,0xD5000000,0xB91C0000,0x81FC01A5,0x81FC01A5,0x81FC01A5,0xB8C00000,0xAA0001A5,0xFF4C010D,0x15401A5,0x15401A5,0xFD480080,0xFD400034,0xFF3C0005,0xFF3C0005,0xE3380000,0xFF3C00E9,0xFF3C0071,0xD7300000,0xD5000000,
-0x5FFC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table121[] = {
-0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0x79F80000,
-0x79F80000,0x79F80000,0x79F80000,0xA2000001,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x1480000,0x75C0000,0x75C0000,0x75C0000,0x1E80000,0x55FC0000,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x1800001,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,
-0x43FC0000,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xC0000000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0x43FC0000,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xC0000000,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xC0000000,0xC0000000,0x19C0000,0x1800001,0x1800001,0x1C00000,0x1E40000,0x17FC0000,0x17FC0000,0x67FC0000,0x1C00000,0x1E40000,0x8BFC0000,0xA3FC0000,
-0x8BFC0000,0x1B40001,0x1B40001,0x1B40001,0x1B40001,0x93FC0000,0x93FC0000,0x93FC0000,0xCBF80000,0xCBF80000,0xDA000000,0x93FC0000,0x93FC0000,0x93FC0000,0xCBF80000,0xCBF80000,0xDA000000,0xCBF80000,0xCBF80000,0xDA000000,0xDA000000,0x93FC0000,0x93FC0000,0x93FC0000,0xCBF80000,0xCBF80000,0xDA000000,0xCBF80000,0xCBF80000,0xDA000000,0xDA000000,0xCBF80000,
-0xCBF80000,0xDA000000,0xDA000000,0xDA000000,0x3FC0000,0x1D40000,0x1B40001,0x79FC0000,0xA7FC0000,0xBDF80000,0xC3FC0000,0xCFF80000,0x51FC0000,0x93FC0000,0xBDF80000,0xDA000000,0xBDF80000,0x1F00000,0xEBFC0000,0xF5FC0000,0xF6000001,0xEBFC0000,0xF5FC0000,0xF6000001,0xF5FC0000,0xF6000001,0xF6000001,0xEBFC0000,0xF5FC0000,0xF6000001,0xF5FC0000,0xF6000001,
-0xF6000001,0xF5FC0000,0xF6000001,0xF6000001,0xF6000001,0xEBFC0000,0xF5FC0000,0xF6000001,0xF5FC0000,0xF6000001,0xF6000001,0xF5FC0000,0xF6000001,0xF6000001,0xF6000001,0xF5FC0000,0xF6000001,0xF6000001,0xF6000001,0xF6000001,0xDFFC0000,0x97FC0000,0x97FC0000,0xEFFC0000,0xF5F80000,0xF7F40000,0xF6000001,0xF6000001,0xE7FC0000,0xF1FC0000,0xF9C40000,0xF6000001,
-0xF3FC0000,0x19C0F1A,0xFF8C0A17,0xFF84069F,0xF78005EB,0xFF8007FE,0xFF700371,0xFB6C028A,0xFF640362,0xF56401BE,0xE964034A,0xFF740939,0xFF60036B,0xFD58020D,0xFF4C021D,0xF7480006,0xEB4C01BD,0xF74805EA,0xEF3C020F,0xE5400286,0xDB4805ED,0x6BFC0F1A,0xFF4C07E9,0xF94805EB,0xFF2C04BE,0xF92001B6,0xE930034A,0xFF080675,0xF6F40154,0xE70001C5,0xDD1005ED,0xB7F80F1A,
-0xF69C05EB,0xE880034A,0xDA6405ED,0xCC000F1E,0xFF8C0B22,0xF5980DDA,0xF79C0E27,0xFF800738,0xFF680366,0xFF540098,0xF9500023,0xF3440025,0xFF800AF5,0xFF7006AA,0xFD3C015B,0xE70001C5,0xA3FC0F1A,0x1B805EA,0xFFA8037E,0xFFA0019A,0xF79C0153,0xFF980356,0xFF8800A9,0xF98C002A,0xFD8001A6,0xF380004B,0xE98001A6,0x95FC05EA,0xFF7C0248,0xF7740153,0xFF580205,0xF74C0002,
-0xE95C01A5,0xCBFC05EA,0xF6F40153,0xE8DC01A5,0xDA0005ED,0x95FC05EA,0xFF7C0248,0xF7740153,0xFF580205,0xF74C0002,0xE95C01A5,0xCBFC05EA,0xF6F40153,0xE8DC01A5,0xDA0005ED,0xCBFC05EA,0xF6F40153,0xE8DC01A5,0xDA0005ED,0xDA0005ED,0xFBAC04B5,0xFFAC057E,0xF5B8057E,0xFF940349,0xFF7C01D6,0xFF5C005E,0xF95C0002,0xF734000B,0xFFA404B5,0xFF900329,0xFF2C0152,0xE8DC01A5,
-0xBFF805EA,0x18005EA,0x18005EA,0x18005EA,0x18005EA,0xFF6C0266,0xFF6C0266,0xFF6C0266,0xEF6401A5,0xEF6401A5,0xDB6401A5,0xFF5C01E8,0xFF5C01E8,0xFF5C01E8,0xF5480005,0xF5480005,0xDD54004C,0xE3480152,0xE3480152,0xD7480029,0xCD480154,0x41FC05EA,0x41FC05EA,0x41FC05EA,0xFF1C01A6,0xFF1C01A6,0xDB3C01A5,0xF4FC0153,0xF4FC0153,0xDB100002,0xCD200154,0xA1FC05EA,
-0xA1FC05EA,0xDABC01A5,0xCCA00154,0xBE0005ED,0xFF7403FE,0xF77C051E,0x18005EA,0xFF68026D,0xFF5800F9,0xFF50002D,0xFF4C000D,0xEF480001,0xFF6403EA,0xFF5C022E,0xF93C0152,0xDB100002,0x89FC05EA,0x19C0152,0x19C0152,0x19C0152,0x19C0152,0xFD880019,0xFD880019,0xFD880019,0xE7840001,0xE7840001,0xDB800001,0x6BFC0152,0x6BFC0152,0x6BFC0152,0xF1540001,0xF1540001,
-0xDB680000,0xB7F80152,0xB7F80152,0xDB180000,0xCC000154,0x6BFC0152,0x6BFC0152,0x6BFC0152,0xF1540001,0xF1540001,0xDB680000,0xB7F80152,0xB7F80152,0xDB180000,0xCC000154,0xB7F80152,0xB7F80152,0xDB180000,0xCC000154,0xCC000154,0xFF9000DD,0xF5980109,0x19C0152,0xFD8400A2,0xFF70003D,0xFF58000A,0xFB580000,0xEF440000,0xFD8800F2,0xFF740095,0xA3FC0152,0xDB180000,
-0xA3FC0152,0x1D401A5,0xFFC400C1,0xFFB80011,0xF7B40002,0xBDFC01A5,0xFFA00050,0xF79C0001,0xDFF801A5,0xF7440001,0xE80001A5,0xBDFC01A5,0xFFA00050,0xF79C0001,0xDFF801A5,0xF7440001,0xE80001A5,0xDFF801A5,0xF7440001,0xE80001A5,0xE80001A5,0xBDFC01A5,0xFFA00050,0xF79C0001,0xDFF801A5,0xF7440001,0xE80001A5,0xDFF801A5,0xF7440001,0xE80001A5,0xE80001A5,0xDFF801A5,
-0xF7440001,0xE80001A5,0xE80001A5,0xE80001A5,0xFDCC016D,0x1F001A5,0xFFCC0179,0xFDBC0122,0xFFA800C8,0xFF70003A,0xF7640001,0xF7180001,0xF7CC016D,0xFFB80120,0xFD680000,0xE80001A5,0xD7FC01A5,0x16401A5,0x16401A5,0x16401A5,0x16401A5,0x16401A5,0x16401A5,0x16401A5,0x16401A5,0x16401A5,0x16401A5,0xFB480000,0xFB480000,0xFB480000,0xFB480000,0xFB480000,
-0xFB480000,0xCF480000,0xCF480000,0xCF480000,0xC1480000,0x15FC01A5,0x15FC01A5,0x15FC01A5,0x15FC01A5,0x15FC01A5,0x15FC01A5,0xDD100000,0xDD100000,0xDD100000,0xC12C0000,0x8DFC01A5,0x8DFC01A5,0x8DFC01A5,0xC0D00000,0xB20001A5,0xF9600120,0x16401A5,0x16401A5,0xFF580091,0xFF500041,0xFF4C000D,0xFF4C000D,0xEB480000,0xFD5400F2,0xFD4C0082,0xDF400000,0xDD100000,
-0x6FFC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table122[] = {
-0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x3FC0000,0x85F80000,
-0x85F80000,0x85F80000,0x85F80000,0xAA000001,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0xF6C0000,0xF6C0000,0xF6C0000,0x3FC0000,0x63FC0000,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x1900001,0x5BFC0000,0x5BFC0000,0x5BFC0000,0x5BFC0000,0x5BFC0000,
-0x5BFC0000,0xAFFC0000,0xAFFC0000,0xAFFC0000,0xC8000000,0x5BFC0000,0x5BFC0000,0x5BFC0000,0x5BFC0000,0x5BFC0000,0x5BFC0000,0xAFFC0000,0xAFFC0000,0xAFFC0000,0xC8000000,0xAFFC0000,0xAFFC0000,0xAFFC0000,0xC8000000,0xC8000000,0x1AC0000,0x1900001,0x1900001,0x1D40000,0x1F80000,0x35FC0000,0x35FC0000,0x7BFC0000,0x1D40000,0x1F80000,0x9BFC0000,0xAFFC0000,
-0x9BFC0000,0x1C40001,0x1C40001,0x1C40001,0x1C40001,0xABFC0000,0xABFC0000,0xABFC0000,0xD7F80000,0xD7F80000,0xE2000000,0xABFC0000,0xABFC0000,0xABFC0000,0xD7F80000,0xD7F80000,0xE2000000,0xD7F80000,0xD7F80000,0xE2000000,0xE2000000,0xABFC0000,0xABFC0000,0xABFC0000,0xD7F80000,0xD7F80000,0xE2000000,0xD7F80000,0xD7F80000,0xE2000000,0xE2000000,0xD7F80000,
-0xD7F80000,0xE2000000,0xE2000000,0xE2000000,0x3BFC0000,0x1E40000,0x1C40001,0x97FC0000,0xBBFC0000,0xCBFC0000,0xD1FC0000,0xD9FC0000,0x77FC0000,0xABFC0000,0xCBFC0000,0xE2000000,0xCBFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1AC0EC7,0xFF9C0A97,0xFF940717,0xFF9005EA,0xFF9808B1,0xFF84044E,0xFF8002A5,0xFF7C03A7,0xFD7401B9,0xF174032D,0xFF8C09AC,0xFF700455,0xFF680234,0xFF6402A2,0xFF580005,0xF35C01A4,0xFF5805B3,0xF74C01FE,0xED500261,0xE35805B4,0x83FC0EC7,0xFF640876,0xFF5805ED,0xFF4C057F,0xFF3801B9,0xF140032D,0xFF2C06C8,0xFF040153,0xEF1001A4,0xE32005B5,0xC3F80EC7,
-0xFEAC05EA,0xF090032D,0xE27405B4,0xD4000EC9,0xFFA00B5D,0xFDA80D89,0xFDA80DDA,0xFF8807F3,0xFF7C0465,0xFF680153,0xFF600030,0xFB54001C,0xFF980B2F,0xFF800755,0xFF50016C,0xEF1001A4,0xB3FC0EC7,0x1C805B3,0xFFBC03B6,0xFFAC01FB,0xFFAC0152,0xFFB00389,0xFFA00122,0xFF98002D,0xFF94019B,0xFB900042,0xF1900189,0xAFFC05B3,0xFF9402A5,0xFF840152,0xFF70024E,0xFF5C0001,
-0xF16C0188,0xD7FC05B3,0xFF040152,0xF0EC0188,0xE20005B4,0xAFFC05B3,0xFF9402A5,0xFF840152,0xFF70024E,0xFF5C0001,0xF16C0188,0xD7FC05B3,0xFF040152,0xF0EC0188,0xE20005B4,0xD7FC05B3,0xFF040152,0xF0EC0188,0xE20005B4,0xE20005B4,0xFFBC04B5,0xFBC4054B,0xFBC4054B,0xFFB003A2,0xFF900261,0xFF7C00D1,0xFF6C0004,0xFD480009,0xFFB404BE,0xFFA40388,0xFF50016B,0xF0EC0188,
-0xCDFC05B3,0x19005EA,0x19005EA,0x19005EA,0x19005EA,0xFF8002A5,0xFF8002A5,0xFF8002A5,0xF77401A5,0xF77401A5,0xE37401A5,0xFF680234,0xFF680234,0xFF680234,0xFD580005,0xFD580005,0xE564004C,0xEB580152,0xEB580152,0xDF580029,0xD5580154,0x59FC05EA,0x59FC05EA,0x59FC05EA,0xFF3801B9,0xFF3801B9,0xE34C01A5,0xFD0C0153,0xFD0C0153,0xE3200002,0xD5300154,0xADFC05EA,
-0xADFC05EA,0xE2CC01A5,0xD4B00154,0xC60005ED,0xFF84042D,0xFF8C051E,0x19005EA,0xFF7802C9,0xFF6C0155,0xFF64006D,0xFF600030,0xF7580001,0xFF780411,0xFF740289,0xFF500153,0xE3200002,0x99FC05EA,0x1AC0152,0x1AC0152,0x1AC0152,0x1AC0152,0xFF98002D,0xFF98002D,0xFF98002D,0xEF940001,0xEF940001,0xE3900001,0x83FC0152,0x83FC0152,0x83FC0152,0xF9640001,0xF9640001,
-0xE3780000,0xC3F80152,0xC3F80152,0xE3280000,0xD4000154,0x83FC0152,0x83FC0152,0x83FC0152,0xF9640001,0xF9640001,0xE3780000,0xC3F80152,0xC3F80152,0xE3280000,0xD4000154,0xC3F80152,0xC3F80152,0xE3280000,0xD4000154,0xD4000154,0xFFA000F4,0xFDA80109,0x1AC0152,0xFF9800B5,0xFF840059,0xFF740019,0xFF6C0004,0xF7540000,0xFF940104,0xFB9000B5,0xB3FC0152,0xE3280000,
-0xB3FC0152,0x1E0018A,0xFFDC00F2,0xFFCC0049,0xFFC40001,0xD5FC0188,0xFFB80089,0xFFAC0000,0xEBF80188,0xFF540000,0xF0000188,0xD5FC0188,0xFFB80089,0xFFAC0000,0xEBF80188,0xFF540000,0xF0000188,0xEBF80188,0xFF540000,0xF0000188,0xF0000188,0xD5FC0188,0xFFB80089,0xFFAC0000,0xEBF80188,0xFF540000,0xF0000188,0xEBF80188,0xFF540000,0xF0000188,0xF0000188,0xEBF80188,
-0xFF540000,0xF0000188,0xF0000188,0xF0000188,0xF3E0016D,0x27FC0188,0xF9E0016D,0xFDD40139,0xFFBC00E9,0xFF980074,0xFF740000,0xFF280000,0xFDD80154,0xFFCC0122,0xFF90000D,0xF0000188,0xE5FC0188,0x17401A5,0x17401A5,0x17401A5,0x17401A5,0x17401A5,0x17401A5,0x17401A5,0x17401A5,0x17401A5,0x17401A5,0xFD580004,0xFD580004,0xFD580004,0xFD580004,0xFD580004,
-0xFD580004,0xD7580000,0xD7580000,0xD7580000,0xC9580000,0x2FFC01A5,0x2FFC01A5,0x2FFC01A5,0x2FFC01A5,0x2FFC01A5,0x2FFC01A5,0xE5200000,0xE5200000,0xE5200000,0xC93C0000,0x99FC01A5,0x99FC01A5,0x99FC01A5,0xC8E00000,0xBA0001A5,0xFF6C0128,0x17401A5,0x17401A5,0xFF6800A4,0xFF640055,0xFF5C001D,0xFF5C001D,0xF3580000,0xF9680109,0xFD6000A2,0xE7500000,0xE5200000,
-0x7FF801A5,};
-static const uint32_t g_etc1_to_bc7_m6_table123[] = {
-0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x91F80000,
-0x91F80000,0x91F80000,0x91F80000,0xB2000001,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1800000,0x1800000,0x1800000,0x1BFC0000,0x73FC0000,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x1A00001,0x75FC0000,0x75FC0000,0x75FC0000,0x75FC0000,0x75FC0000,
-0x75FC0000,0xBBFC0000,0xBBFC0000,0xBBFC0000,0xD0000000,0x75FC0000,0x75FC0000,0x75FC0000,0x75FC0000,0x75FC0000,0x75FC0000,0xBBFC0000,0xBBFC0000,0xBBFC0000,0xD0000000,0xBBFC0000,0xBBFC0000,0xBBFC0000,0xD0000000,0xD0000000,0x7BC0000,0x1A00001,0x1A00001,0x5E40000,0x1FFC0000,0x53FC0000,0x53FC0000,0x8FFC0000,0x5E40000,0x1FFC0000,0xA9FC0000,0xBBFC0000,
-0xA9FC0000,0x1D40001,0x1D40001,0x1D40001,0x1D40001,0xC3FC0000,0xC3FC0000,0xC3FC0000,0xE1FC0000,0xE1FC0000,0xEA000000,0xC3FC0000,0xC3FC0000,0xC3FC0000,0xE1FC0000,0xE1FC0000,0xEA000000,0xE1FC0000,0xE1FC0000,0xEA000000,0xEA000000,0xC3FC0000,0xC3FC0000,0xC3FC0000,0xE1FC0000,0xE1FC0000,0xEA000000,0xE1FC0000,0xE1FC0000,0xEA000000,0xEA000000,0xE1FC0000,
-0xE1FC0000,0xEA000000,0xEA000000,0xEA000000,0x75FC0000,0x3F40000,0x1D40001,0xB5FC0000,0xCFFC0000,0xDBFC0000,0xDFF80000,0xE5F40000,0x9FFC0000,0xC3FC0000,0xDBFC0000,0xEA000000,0xDBFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1B80C63,0xFFB0094E,0xFFA006CB,0xFFA005EA,0xFFA4076D,0xFF940436,0xFF8C0301,0xFF880313,0xFF8401A5,0xF584026D,0xFF980818,0xFF88041D,0xFF800284,0xFF7C0222,0xFF6C001D,0xF56C00F0,0xFF6C0438,0xFB600192,0xF1640165,0xE9680428,0x95FC0C63,0xFF7C07BE,0xFF7005ED,0xFF6404BF,0xFF4C01F6,0xF554026D,0xFF380594,0xFF280163,0xF32400D8,0xE9340428,0xCBFC0C63,
-0xFEE005EA,0xF4B4026D,0xE88C0428,0xDA000C65,0xFFA809C9,0xFFAC0B85,0xF5B80BDB,0xFF9806E9,0xFF8C041A,0xFF7C0175,0xFF78007A,0xFF680001,0xFFA409B3,0xFF90067F,0xFF640186,0xF32400D8,0xBFF80C63,0x1D0042B,0xFFC402DB,0xFFC001BE,0xFFBC0152,0xFFC4028B,0xFFB400FA,0xFFB00055,0xFFA800F1,0xFDA0000E,0xF5A000C9,0xBDFC0428,0xFFAC022D,0xFF9C0152,0xFF88018E,0xFF780005,
-0xF58000C8,0xDFF80428,0xFF340152,0xF50C00C8,0xE8000428,0xBDFC0428,0xFFAC022D,0xFF9C0152,0xFF88018E,0xFF780005,0xF58000C8,0xDFF80428,0xFF340152,0xF50C00C8,0xE8000428,0xDFF80428,0xFF340152,0xF50C00C8,0xE8000428,0xE8000428,0xFDCC0378,0xFFCC03D3,0xFFCC03E3,0xFFC002B6,0xFFA801D5,0xFF9000C1,0xFF880019,0xFF640000,0xFFC4037B,0xFDBC02B6,0xFF700162,0xF50C00C8,
-0xD7FC0428,0x1A005EA,0x1A005EA,0x1A005EA,0x1A005EA,0xFF8C0301,0xFF8C0301,0xFF8C0301,0xFF8401A5,0xFF8401A5,0xEB8401A5,0xFF800284,0xFF800284,0xFF800284,0xFF6C001D,0xFF6C001D,0xED74004C,0xF3680152,0xF3680152,0xE7680029,0xDD680154,0x71FC05EA,0x71FC05EA,0x71FC05EA,0xFF4C01F6,0xFF4C01F6,0xEB5C01A5,0xFF280163,0xFF280163,0xEB300002,0xDD400154,0xB9FC05EA,
-0xB9FC05EA,0xEADC01A5,0xDCC00154,0xCE0005ED,0xFB980484,0xF79C0551,0x1A005EA,0xFF900321,0xFF8001C1,0xFF7800C2,0xFF78007A,0xFF680001,0xFF900452,0xFF8002F4,0xFF64016D,0xEB300002,0xA7FC05EA,0x1BC0152,0x1BC0152,0x1BC0152,0x1BC0152,0xFFB00055,0xFFB00055,0xFFB00055,0xF7A40001,0xF7A40001,0xEBA00001,0x9BFC0152,0x9BFC0152,0x9BFC0152,0xFF780005,0xFF780005,
-0xEB880000,0xCFF80152,0xCFF80152,0xEB380000,0xDC000154,0x9BFC0152,0x9BFC0152,0x9BFC0152,0xFF780005,0xFF780005,0xEB880000,0xCFF80152,0xCFF80152,0xEB380000,0xDC000154,0xCFF80152,0xCFF80152,0xEB380000,0xDC000154,0xDC000154,0xFBB40109,0xF5B80122,0x1BC0152,0xFFA400DA,0xFF98007D,0xFF8C0041,0xFF880019,0xFF640000,0xFDB00109,0xFFA400C8,0xC1FC0152,0xEB380000,
-0xC1FC0152,0x1E800CA,0xFFE0007D,0xFFD80025,0xFFD40001,0xE3FC00C8,0xFFCC0049,0xFFC00001,0xF1F800C8,0xFF840000,0xF40000C8,0xE3FC00C8,0xFFCC0049,0xFFC00001,0xF1F800C8,0xFF840000,0xF40000C8,0xF1F800C8,0xFF840000,0xF40000C8,0xF40000C8,0xE3FC00C8,0xFFCC0049,0xFFC00001,0xF1F800C8,0xFF840000,0xF40000C8,0xF1F800C8,0xFF840000,0xF40000C8,0xF40000C8,0xF1F800C8,
-0xFF840000,0xF40000C8,0xF40000C8,0xF40000C8,0xF7E800B5,0x67FC00C8,0xFDE800B5,0xFFD8009D,0xFFD00075,0xFFC0003D,0xFF9C0000,0xFF640000,0xFFDC00B4,0xFFD80095,0xFFB00008,0xF40000C8,0xEDFC00C8,0x18401A5,0x18401A5,0x18401A5,0x18401A5,0x18401A5,0x18401A5,0x18401A5,0x18401A5,0x18401A5,0x18401A5,0xFF6C000D,0xFF6C000D,0xFF6C000D,0xFF6C000D,0xFF6C000D,
-0xFF6C000D,0xDF680000,0xDF680000,0xDF680000,0xD1680000,0x47FC01A5,0x47FC01A5,0x47FC01A5,0x47FC01A5,0x47FC01A5,0x47FC01A5,0xED300000,0xED300000,0xED300000,0xD14C0000,0xA5F801A5,0xA5F801A5,0xA5F801A5,0xD0F00000,0xC20001A5,0xF9800139,0x18401A5,0x18401A5,0xFB7C00C8,0xFF780071,0xFF700034,0xFF700034,0xFB680000,0xFF74010D,0xFD7400B5,0xEF600000,0xED300000,
-0x8DFC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table124[] = {
-0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x9DFC0000,
-0x9DFC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1940000,0x1940000,0x1940000,0x37FC0000,0x83FC0000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,
-0x8FFC0000,0xC9F80000,0xC9F80000,0xC9F80000,0xD8000001,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0x8FFC0000,0xC9F80000,0xC9F80000,0xC9F80000,0xD8000001,0xC9F80000,0xC9F80000,0xC9F80000,0xD8000001,0xD8000001,0x1D00000,0x1B40000,0x1B40000,0x1FC0000,0x4BFC0000,0x75FC0000,0x75FC0000,0xA5FC0000,0x1FC0000,0x4BFC0000,0xBBFC0000,0xC9F80000,
-0xBBFC0000,0x1E80000,0x1E80000,0x1E80000,0x1E80000,0xDFFC0000,0xDFFC0000,0xDFFC0000,0xEFFC0000,0xEFFC0000,0xF2000001,0xDFFC0000,0xDFFC0000,0xDFFC0000,0xEFFC0000,0xEFFC0000,0xF2000001,0xEFFC0000,0xEFFC0000,0xF2000001,0xF2000001,0xDFFC0000,0xDFFC0000,0xDFFC0000,0xEFFC0000,0xEFFC0000,0xF2000001,0xEFFC0000,0xEFFC0000,0xF2000001,0xF2000001,0xEFFC0000,
-0xEFFC0000,0xF2000001,0xF2000001,0xF2000001,0xB5FC0000,0x57FC0000,0x1E80000,0xD7FC0000,0xE5FC0000,0xEBFC0000,0xEDFC0000,0xF1F80000,0xCBFC0000,0xDFFC0000,0xEBFC0000,0xF2000001,0xEBFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1C40A26,0xFFBC0819,0xFFB4067D,0xFFB005ED,0xFFB00662,0xFFA8043D,0xFFA40362,0xFFA002BE,0xFF9801C9,0xF99801E2,0xFFA406D7,0xFF9C0415,0xFF9802FB,0xFF8801E3,0xFF84007A,0xFB840073,0xFF84031B,0xFD780159,0xF77000A2,0xEF7802D3,0xA9FC0A26,0xFF940717,0xFF8C05EA,0xFF7C0432,0xFF70024D,0xF96801E2,0xFF640489,0xFF4C01A8,0xF93C003F,0xEF4802D2,0xD5F80A26,
-0xFF1405EA,0xF8D801E2,0xEEAC02D2,0xE2000A26,0xFFBC082A,0xFBC40972,0xFBC409B6,0xFFAC061E,0xFFA003F3,0xFF9001DC,0xFF8C00FA,0xFF7C0029,0xFFB407F7,0xFFA405EA,0xFF7C01C3,0xF93C003F,0xC9FC0A26,0x1DC02D5,0xFFD40228,0xFFCC0194,0xFFCC0154,0xFFD001B5,0xFFC400E4,0xFFC40080,0xFFB8007D,0xFFB40001,0xF9B4003D,0xCFFC02D2,0xFFC001C8,0xFFB80152,0xFFAC00FE,0xFF940025,
-0xF994003E,0xE7FC02D2,0xFF6C0152,0xF934003D,0xEE0002D2,0xCFFC02D2,0xFFC001C8,0xFFB80152,0xFFAC00FE,0xFF940025,0xF994003E,0xE7FC02D2,0xFF6C0152,0xF934003D,0xEE0002D2,0xE7FC02D2,0xFF6C0152,0xF934003D,0xEE0002D2,0xEE0002D2,0xFFD80263,0xF7DC02A9,0xF7DC02B4,0xFDD00209,0xFFC0016A,0xFFAC00B1,0xFFA8003D,0xFF8C0019,0xFDD8026D,0xFFC801D6,0xFF98015B,0xF934003D,
-0xE1FC02D2,0x1B005ED,0x1B005ED,0x1B005ED,0x1B005ED,0xFFA40362,0xFFA40362,0xFFA40362,0xFF9801C9,0xFF9801C9,0xF39801A6,0xFF9802FB,0xFF9802FB,0xFF9802FB,0xFF84007A,0xFF84007A,0xF584004B,0xFB7C0153,0xFB7C0153,0xEF78002A,0xE7780153,0x8DFC05EA,0x8DFC05EA,0x8DFC05EA,0xFF70024D,0xFF70024D,0xF37001A6,0xFF4C01A8,0xFF4C01A8,0xF5440001,0xE7500152,0xC7FC05EA,
-0xC7FC05EA,0xF2F001A6,0xE6CC0152,0xD80005EA,0xFFAC04B2,0xFFAC055A,0x1B005ED,0xFFA403A1,0xFF940252,0xFF900163,0xFF8C00FA,0xFF7C0029,0xFFA00491,0xFF980365,0xFF7C01B3,0xF5440001,0xB9FC05EA,0x1CC0154,0x1CC0154,0x1CC0154,0x1CC0154,0xFFC40080,0xFFC40080,0xFFC40080,0xFFB40001,0xFFB40001,0xF3B40001,0xB7FC0152,0xB7FC0152,0xB7FC0152,0xFF940025,0xFF940025,
-0xF39C0001,0xDDF40152,0xDDF40152,0xF34C0001,0xE6000152,0xB7FC0152,0xB7FC0152,0xB7FC0152,0xFF940025,0xFF940025,0xF39C0001,0xDDF40152,0xDDF40152,0xF34C0001,0xE6000152,0xDDF40152,0xDDF40152,0xF34C0001,0xE6000152,0xE6000152,0xFDC80120,0xFFCC0120,0x1CC0154,0xFDC000F4,0xFFB000B4,0xFFA8006A,0xFFA8003D,0xFF8C0019,0xFFC40120,0xFBC000F2,0xD3FC0152,0xF34C0001,
-0xD3FC0152,0x1F4003D,0xFFEC0028,0xFFEC000D,0xFFE80000,0xEFFC003D,0xFFE40014,0xFFDC0000,0xF7F8003D,0xFFB80000,0xF800003D,0xEFFC003D,0xFFE40014,0xFFDC0000,0xF7F8003D,0xFFB80000,0xF800003D,0xF7F8003D,0xFFB80000,0xF800003D,0xF800003D,0xEFFC003D,0xFFE40014,0xFFDC0000,0xF7F8003D,0xFFB80000,0xF800003D,0xF7F8003D,0xFFB80000,0xF800003D,0xF800003D,0xF7F8003D,
-0xFFB80000,0xF800003D,0xF800003D,0xF800003D,0xFBF00034,0xA7FC003D,0xF3F4003D,0xFFEC0029,0xFFE80020,0xFFD40011,0xFFC80000,0xFFA80000,0xFFF00032,0xFFEC0032,0xFFD00001,0xF800003D,0xF5FC003D,0x19801A5,0x19801A5,0x19801A5,0x19801A5,0x19801A5,0x19801A5,0x19801A5,0x19801A5,0x19801A5,0x19801A5,0xFF800022,0xFF800022,0xFF800022,0xFF800022,0xFF800022,
-0xFF800022,0xE77C0001,0xE77C0001,0xE77C0001,0xD9780002,0x63FC01A5,0x63FC01A5,0x63FC01A5,0x63FC01A5,0x63FC01A5,0x63FC01A5,0xF5440000,0xF5440000,0xF5440000,0xD9600001,0xB3F801A5,0xB3F801A5,0xB3F801A5,0xD9080001,0xCA0001A5,0xFF8C0151,0x19801A5,0x19801A5,0xFF9000DD,0xFF8C0091,0xFF880055,0xFF880055,0xFD7C0005,0xFD8C0120,0xFF8000DA,0xF7740001,0xF5440000,
-0x9FF801A5,};
-static const uint32_t g_etc1_to_bc7_m6_table125[] = {
-0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0xA9FC0000,
-0xA9FC0000,0xA9FC0000,0xA9FC0000,0xC4000000,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1880001,0x1A40000,0x1A40000,0x1A40000,0x4FFC0000,0x93FC0000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0x1C40000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,
-0xA9FC0000,0xD5F80000,0xD5F80000,0xD5F80000,0xE0000001,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xA9FC0000,0xD5F80000,0xD5F80000,0xD5F80000,0xE0000001,0xD5F80000,0xD5F80000,0xD5F80000,0xE0000001,0xE0000001,0x9E00000,0x1C40000,0x1C40000,0x35FC0000,0x73FC0000,0x93FC0000,0x93FC0000,0xB9FC0000,0x35FC0000,0x73FC0000,0xC9FC0000,0xD5F80000,
-0xC9FC0000,0x1F80000,0x1F80000,0x1F80000,0x1F80000,0xF7FC0000,0xF7FC0000,0xF7FC0000,0xFBFC0000,0xFBFC0000,0xFA000001,0xF7FC0000,0xF7FC0000,0xF7FC0000,0xFBFC0000,0xFBFC0000,0xFA000001,0xFBFC0000,0xFBFC0000,0xFA000001,0xFA000001,0xF7FC0000,0xF7FC0000,0xF7FC0000,0xFBFC0000,0xFBFC0000,0xFA000001,0xFBFC0000,0xFBFC0000,0xFA000001,0xFA000001,0xFBFC0000,
-0xFBFC0000,0xFA000001,0xFA000001,0xFA000001,0xEDFC0000,0xD7FC0000,0x1F80000,0xF5FC0000,0xF9FC0000,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xF3FC0000,0xF7FC0000,0xFBFC0000,0xFA000001,0xFBFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1D0088E,0xFFC80749,0xFFC00651,0xFFC005ED,0xFFC405B2,0xFFBC0463,0xFFB403DD,0xFFAC02BE,0xFFAC0215,0xFDA801AA,0xFFBC05EF,0xFFB0042C,0xFFA40383,0xFFA001F3,0xFF9C010A,0xFD94004F,0xFF94028E,0xFF900163,0xFB84003E,0xF58801FF,0xBBFC088E,0xFFAC069F,0xFFA405EA,0xFF9403FA,0xFF8802BD,0xFD7C01AA,0xFF7C0401,0xFF640218,0xFD540005,0xF55C01FE,0xDDFC088E,
-0xFF4805EA,0xFCF801AA,0xF4C401FE,0xE800088E,0xFFCC0739,0xFFCC07F2,0xFFCC0846,0xFFC005B1,0xFFB003FD,0xFFA4024E,0xFFA4019A,0xFF940096,0xFFC4071A,0xFFB40585,0xFF94023D,0xFD540005,0xD5FC088E,0x1E801FD,0xFDE401B5,0xFFE0016D,0xFFDC0154,0xFFDC0149,0xFFD400EA,0xFFD000B4,0xFFCC0069,0xFFC80028,0xFDC40005,0xDFFC01FD,0xFFD80188,0xFFCC0154,0xFFB800D2,0xFFB80059,
-0xFDA80006,0xEFFC01FD,0xFF9C0152,0xFD540005,0xF40001FE,0xDFFC01FD,0xFFD80188,0xFFCC0154,0xFFB800D2,0xFFB80059,0xFDA80006,0xEFFC01FD,0xFF9C0152,0xFD540005,0xF40001FE,0xEFFC01FD,0xFF9C0152,0xFD540005,0xF40001FE,0xF40001FE,0xFFE401C5,0xFDE801D9,0xFDE801E8,0xFFDC0179,0xFFD40132,0xFFC800CE,0xFFBC007D,0xFFA80049,0xFFE001CA,0xFFDC0172,0xFFB80156,0xFD540005,
-0xEBFC01FD,0x1C005ED,0x1C005ED,0x1C005ED,0x1C005ED,0xFFB403DD,0xFFB403DD,0xFFB403DD,0xFFAC0215,0xFFAC0215,0xFBA801A6,0xFFA40383,0xFFA40383,0xFFA40383,0xFF9C010A,0xFF9C010A,0xFD94004B,0xFF900163,0xFF900163,0xF788002A,0xEF880153,0xA5FC05EA,0xA5FC05EA,0xA5FC05EA,0xFF8802BD,0xFF8802BD,0xFB8001A6,0xFF640218,0xFF640218,0xFD540001,0xEF600152,0xD3FC05EA,
-0xD3FC05EA,0xFB0001A6,0xEEDC0152,0xE00005EA,0xFFBC04E6,0xF9C00581,0x1C005ED,0xFFB40402,0xFFAC02EA,0xFFA401FD,0xFFA4019A,0xFF940096,0xFFB404BE,0xFFB003CE,0xFF940234,0xFD540001,0xC7FC05EA,0x1DC0154,0x1DC0154,0x1DC0154,0x1DC0154,0xFFD000B4,0xFFD000B4,0xFFD000B4,0xFFC80028,0xFFC80028,0xFBC40001,0xCFFC0152,0xCFFC0152,0xCFFC0152,0xFFB80059,0xFFB80059,
-0xFBAC0001,0xE7FC0152,0xE7FC0152,0xFB5C0001,0xEE000152,0xCFFC0152,0xCFFC0152,0xCFFC0152,0xFFB80059,0xFFB80059,0xFBAC0001,0xE7FC0152,0xE7FC0152,0xFB5C0001,0xEE000152,0xE7FC0152,0xE7FC0152,0xFB5C0001,0xEE000152,0xEE000152,0xFFD80122,0xF7DC0139,0x1DC0154,0xFDD80109,0xFFC800DA,0xFFBC00A9,0xFFBC007D,0xFFA80049,0xFFD00132,0xFBD40109,0xE1FC0152,0xFB5C0001,
-0xE1FC0152,0x1FC0005,0xFFF80004,0xFFF80001,0xFFF80000,0xFBFC0005,0xFFF80002,0xFFF40000,0xFDF80005,0xFFEC0000,0xFC000005,0xFBFC0005,0xFFF80002,0xFFF40000,0xFDF80005,0xFFEC0000,0xFC000005,0xFDF80005,0xFFEC0000,0xFC000005,0xFC000005,0xFBFC0005,0xFFF80002,0xFFF40000,0xFDF80005,0xFFEC0000,0xFC000005,0xFDF80005,0xFFEC0000,0xFC000005,0xFC000005,0xFDF80005,
-0xFFEC0000,0xFC000005,0xFC000005,0xFC000005,0xFFF80004,0xE7FC0005,0xF7FC0005,0xFBFC0005,0xFFF80002,0xFFF00001,0xFFF00000,0xFFE40000,0xF9FC0005,0xFBFC0005,0xFFF00000,0xFC000005,0xFDF80005,0x1A801A5,0x1A801A5,0x1A801A5,0x1A801A5,0x1A801A5,0x1A801A5,0x1A801A5,0x1A801A5,0x1A801A5,0x1A801A5,0xFF900049,0xFF900049,0xFF900049,0xFF900049,0xFF900049,
-0xFF900049,0xEF8C0001,0xEF8C0001,0xEF8C0001,0xE1880002,0x7BFC01A5,0x7BFC01A5,0x7BFC01A5,0x7BFC01A5,0x7BFC01A5,0x7BFC01A5,0xFD540000,0xFD540000,0xFD540000,0xE1700001,0xBFF801A5,0xBFF801A5,0xBFF801A5,0xE1180001,0xD20001A5,0xFBA40152,0x1A801A5,0x1A801A5,0xFFA000F2,0xFD9C00B5,0xFF980071,0xFF980071,0xFD900019,0xFD9C0139,0xFF9400E9,0xFF840001,0xFD540000,
-0xADFC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table126[] = {
-0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0x69FC0000,0xB5FC0000,
-0xB5FC0000,0xB5FC0000,0xB5FC0000,0xCC000000,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x1980001,0x3B40000,0x3B40000,0x3B40000,0x69FC0000,0xA1FC0000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0x1D40000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,
-0xC1FC0000,0xE1F80000,0xE1F80000,0xE1F80000,0xE8000001,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xE1F80000,0xE1F80000,0xE1F80000,0xE8000001,0xE1F80000,0xE1F80000,0xE1F80000,0xE8000001,0xE8000001,0x1F40000,0x1D40000,0x1D40000,0x6DFC0000,0x9BFC0000,0xB1FC0000,0xB1FC0000,0xCDFC0000,0x6DFC0000,0x9BFC0000,0xD9FC0000,0xE1F80000,
-0xD9FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1DC0693,0xFFD405C6,0xFFD0052E,0xFFD004EE,0xFFD0049F,0xFFC403C6,0xFFC40362,0xFFC00295,0xFFB8021E,0xFFB801A5,0xFFC4048F,0xFFBC037F,0xFFBC0306,0xFFAC01D4,0xFFAC012B,0xFFA4006A,0xFFAC01E3,0xFFA0010E,0xFF980011,0xF798012A,0xC9FC0691,0xFFB80566,0xFFB804ED,0xFFAC0367,0xFFA0029E,0xFF9401A5,0xFF940316,0xFF8801D1,0xFF700008,0xF7700129,0xE5F80691,
-0xFF6C04ED,0xFF2001A5,0xF6EC0129,0xEC000691,0xFFD805AB,0xF5D8064D,0xF5D80672,0xFFCC0496,0xFFC00366,0xFFB8022B,0xFFB401AE,0xFFA800C3,0xFFD00576,0xFFC4045F,0xFFB001FA,0xFF700008,0xDFF80691,0x1F00126,0xFFEC0105,0xFFEC00EA,0xFFE800DD,0xFFE800C6,0xFFE000A1,0xFFE00088,0xFFD8004C,0xFFD80028,0xFFD40000,0xEBFC0126,0xFFE400F1,0xFFDC00DD,0xFFD80088,0xFFCC0050,
-0xFFC00000,0xF5FC0126,0xFFB800DD,0xFF7C0000,0xF6000129,0xEBFC0126,0xFFE400F1,0xFFDC00DD,0xFFD80088,0xFFCC0050,0xFFC00000,0xF5FC0126,0xFFB800DD,0xFF7C0000,0xF6000129,0xF5FC0126,0xFFB800DD,0xFF7C0000,0xF6000129,0xF6000129,0xFDF0010C,0xFFEC0110,0xFFEC0121,0xFFEC00F3,0xFFDC00C6,0xFFD80092,0xFFD00061,0xFFC00049,0xFFEC010B,0xFFE800E5,0xFFD000DE,0xFF7C0000,
-0xF3FC0126,0x1D004EE,0x1D004EE,0x1D004EE,0x1D004EE,0xFFC40362,0xFFC40362,0xFFC40362,0xFFB8021E,0xFFB8021E,0xFFB801A5,0xFFBC0306,0xFFBC0306,0xFFBC0306,0xFFAC012B,0xFFAC012B,0xFFA4006A,0xFFA0010E,0xFFA0010E,0xFD98000E,0xF59800DE,0xB7FC04ED,0xB7FC04ED,0xB7FC04ED,0xFFA0029E,0xFFA0029E,0xFF9401A5,0xFF8801D1,0xFF8801D1,0xFF700008,0xF57400DD,0xDDF404ED,
-0xDDF404ED,0xFF2001A5,0xF4F400DD,0xE60004ED,0xFFCC042E,0xFFCC0492,0x1D004EE,0xFFC40382,0xFFC002BD,0xFFB401EE,0xFFB401AE,0xFFA800C3,0xFBC8042D,0xFFBC0366,0xFFA801F5,0xFF700008,0xD3FC04ED,0x1E800DD,0x1E800DD,0x1E800DD,0x1E800DD,0xFFE00088,0xFFE00088,0xFFE00088,0xFFD80028,0xFFD80028,0xFFD40000,0xDFFC00DD,0xDFFC00DD,0xDFFC00DD,0xFFCC0050,0xFFCC0050,
-0xFFC00000,0xEFFC00DD,0xEFFC00DD,0xFF7C0000,0xF40000DD,0xDFFC00DD,0xDFFC00DD,0xDFFC00DD,0xFFCC0050,0xFFCC0050,0xFFC00000,0xEFFC00DD,0xEFFC00DD,0xFF7C0000,0xF40000DD,0xEFFC00DD,0xEFFC00DD,0xFF7C0000,0xF40000DD,0xF40000DD,0xF9E800C8,0xFDE800C8,0x1E800DD,0xFFDC00B4,0xFFDC0095,0xFFD80082,0xFFD00061,0xFFC00049,0xF7E800C8,0xFFDC00AA,0xEBFC00DD,0xFF7C0000,
-0xEBFC00DD,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1B801A5,0x1B801A5,0x1B801A5,0x1B801A5,0x1B801A5,0x1B801A5,0x1B801A5,0x1B801A5,0x1B801A5,0x1B801A5,0xFFA4006A,0xFFA4006A,0xFFA4006A,0xFFA4006A,0xFFA4006A,
-0xFFA4006A,0xF79C0001,0xF79C0001,0xF79C0001,0xE9980002,0x93FC01A5,0x93FC01A5,0x93FC01A5,0x93FC01A5,0x93FC01A5,0x93FC01A5,0xFF700008,0xFF700008,0xFF700008,0xE9800001,0xCBF801A5,0xCBF801A5,0xCBF801A5,0xE9280001,0xDA0001A5,0xF3B4016D,0x1B801A5,0x1B801A5,0xFFAC0115,0xFFA800DA,0xFFAC00A2,0xFFAC00A2,0xFFA0003A,0xF9B00152,0xFBAC0109,0xFF98000D,0xFF700008,
-0xBDF801A5,};
-static const uint32_t g_etc1_to_bc7_m6_table127[] = {
-0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0xC1FC0000,
-0xC1FC0000,0xC1FC0000,0xC1FC0000,0xD4000000,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0xBC40000,0xBC40000,0xBC40000,0x81FC0000,0xB1FC0000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,
-0xD9FC0000,0xEDF80000,0xEDF80000,0xEDF80000,0xF0000001,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xEDF80000,0xEDF80000,0xEDF80000,0xF0000001,0xEDF80000,0xEDF80000,0xEDF80000,0xF0000001,0xF0000001,0x37FC0000,0x1E40000,0x1E40000,0xA7FC0000,0xC1FC0000,0xCFFC0000,0xCFFC0000,0xE1FC0000,0xA7FC0000,0xC1FC0000,0xE7FC0000,0xEDF80000,
-0xE7FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1E4049B,0xFFDC041B,0xFFD803C2,0xFFD8039E,0xFFDC0373,0xFFD002EE,0xFFD002AE,0xFFCC0231,0xFFCC01F1,0xFFC801A5,0xFFD0032F,0xFFD0028E,0xFFC40236,0xFFC00181,0xFFBC011B,0xFFBC00A2,0xFFB80127,0xFFAC00AA,0xFFAC0001,0xFBA80072,0xD5FC0499,0xFFCC03E2,0xFFC8039D,0xFFB802AF,0xFFB80236,0xFFAC01A5,0xFFAC0216,0xFFA00149,0xFF880028,0xFB840071,0xEBF80499,
-0xFF90039D,0xFF5401A5,0xFB0C0071,0xF0000499,0xFFD8040B,0xF9E00465,0xF9E00482,0xFFD40343,0xFFCC0297,0xFFC401D1,0xFFBC0173,0xFFB800C2,0xFFD803EE,0xFFD0031A,0xFFB8015E,0xFF880028,0xE5FC0499,0x1F40072,0xFFF40062,0xFFF00059,0xFFF00055,0xFFF40052,0xFFEC003D,0xFFEC0034,0xFFE40020,0xFFE40010,0xFFE40000,0xF5FC0071,0xFFF0005D,0xFFE80055,0xFFE40030,0xFFE40020,
-0xFFD80000,0xF9FC0071,0xFFD40055,0xFFAC0000,0xFA000071,0xF5FC0071,0xFFF0005D,0xFFE80055,0xFFE40030,0xFFE40020,0xFFD80000,0xF9FC0071,0xFFD40055,0xFFAC0000,0xFA000071,0xF9FC0071,0xFFD40055,0xFFAC0000,0xFA000071,0xFA000071,0xFFF40060,0xF3F40072,0xF3F40072,0xFFF0005A,0xFFF0004A,0xFFE40036,0xFFE40022,0xFFD8001D,0xFDF40060,0xFFF0005A,0xFFE00056,0xFFAC0000,
-0xF9FC0071,0x1D8039E,0x1D8039E,0x1D8039E,0x1D8039E,0xFFD002AE,0xFFD002AE,0xFFD002AE,0xFFCC01F1,0xFFCC01F1,0xFFC801A5,0xFFC40236,0xFFC40236,0xFFC40236,0xFFBC011B,0xFFBC011B,0xFFBC00A2,0xFFAC00AA,0xFFAC00AA,0xFFAC0001,0xF9A80056,0xC9FC039D,0xC9FC039D,0xC9FC039D,0xFFB80236,0xFFB80236,0xFFAC01A5,0xFFA00149,0xFFA00149,0xFF880028,0xF9880055,0xE5F8039D,
-0xE5F8039D,0xFF5401A5,0xF9140055,0xEC00039D,0xFFD8032A,0xF5D80379,0x1D8039E,0xFFCC02A5,0xFFC4022E,0xFFBC01AB,0xFFBC0173,0xFFB800C2,0xFFD00305,0xFFD0028A,0xFFB8015A,0xFF880028,0xDFF8039D,0x1F00055,0x1F00055,0x1F00055,0x1F00055,0xFFEC0034,0xFFEC0034,0xFFEC0034,0xFFE40010,0xFFE40010,0xFFE40000,0xEBFC0055,0xEBFC0055,0xEBFC0055,0xFFE40020,0xFFE40020,
-0xFFD80000,0xF5FC0055,0xF5FC0055,0xFFAC0000,0xF8000055,0xEBFC0055,0xEBFC0055,0xEBFC0055,0xFFE40020,0xFFE40020,0xFFD80000,0xF5FC0055,0xF5FC0055,0xFFAC0000,0xF8000055,0xF5FC0055,0xF5FC0055,0xFFAC0000,0xF8000055,0xF8000055,0xFDF00048,0xFFEC0050,0x1F00055,0xFBF00048,0xFDEC003D,0xFFE4002D,0xFFE40022,0xFFD8001D,0xFBF00048,0xFFE80041,0xF3FC0055,0xFFAC0000,
-0xF3FC0055,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1C801A5,0x1C801A5,0x1C801A5,0x1C801A5,0x1C801A5,0x1C801A5,0x1C801A5,0x1C801A5,0x1C801A5,0x1C801A5,0xFFBC00A2,0xFFBC00A2,0xFFBC00A2,0xFFBC00A2,0xFFBC00A2,
-0xFFBC00A2,0xFFAC0001,0xFFAC0001,0xFFAC0001,0xF1A80002,0xABFC01A5,0xABFC01A5,0xABFC01A5,0xABFC01A5,0xABFC01A5,0xABFC01A5,0xFF880028,0xFF880028,0xFF880028,0xF1900001,0xD7F801A5,0xD7F801A5,0xD7F801A5,0xF1380001,0xE20001A5,0xFBC4016D,0x1C801A5,0x1C801A5,0xFFBC0132,0xFFBC00FA,0xFFBC00CA,0xFFBC00CA,0xFFB4006A,0xFFBC015A,0xFFBC0122,0xFFB00032,0xFF880028,
-0xCBFC01A5,};
-static const uint32_t g_etc1_to_bc7_m6_table128[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x240000,0x240000,0x240000,0x240000,0x340000,0x340000,0x340000,0x680000,0x680000,0x10000001,0x340000,0x340000,0x340000,0x680000,0x680000,0x10000001,0x680000,0x680000,0x10000001,0x10000001,0x340000,0x340000,0x340000,0x680000,0x680000,0x10000001,0x680000,0x680000,0x10000001,0x10000001,0x680000,
-0x680000,0x10000001,0x10000001,0x10000001,0x2280000,0xA240000,0x240000,0x300000,0x3C0000,0x4C0000,0x540000,0x800000,0x2C0000,0x340000,0x4C0000,0x10000001,0x4C0000,0x780000,0x2B00000,0x1680000,0x3A000001,0x2B00000,0x1680000,0x3A000001,0x1680000,0x3A000001,0x3A000001,0x2B00000,0x1680000,0x3A000001,0x1680000,0x3A000001,
-0x3A000001,0x1680000,0x3A000001,0x3A000001,0x3A000001,0x2B00000,0x1680000,0x3A000001,0x1680000,0x3A000001,0x3A000001,0x1680000,0x3A000001,0x3A000001,0x3A000001,0x1680000,0x3A000001,0x3A000001,0x3A000001,0x3A000001,0x2940000,0x800000,0x800000,0xC80000,0x1240000,0xBF40000,0x3A000001,0x3A000001,0xA40000,0xE00000,0x2FF00000,0x3A000001,
-0xFC0000,0x280964,0xAA0C00D8,0x560C00D8,0x3A0C00D9,0x76000372,0x52000061,0x3A000002,0x38000374,0x32000151,0x26000372,0x4E000768,0x460002BA,0x34000153,0x340004A5,0x2E00024E,0x2400040A,0x26000768,0x2600049D,0x2000059E,0x1800076B,0x380964,0x3A000463,0x2E000274,0x2E000596,0x2800031F,0x22000484,0x220007ED,0x24000543,0x1C000607,0x180007AB,0x700964,
-0x1C000694,0x1C00070C,0x16000864,0x12000964,0xE4000231,0xF41805B2,0xF820054D,0x74000239,0x4A000252,0x3C00023D,0x3000019B,0x2A000306,0x90000413,0x5E000317,0x2E0003AB,0x1C000607,0x500964,0x340768,0xA01400A4,0x541000A4,0x3A1000A5,0x76000372,0x52000061,0x3A000002,0x38000374,0x32000151,0x26000372,0x4C0768,0x460002BA,0x34000153,0x340004A5,0x2E00024E,
-0x2400040A,0x980768,0x2600049D,0x2000059E,0x1800076B,0x4C0768,0x460002BA,0x34000153,0x340004A5,0x2E00024E,0x2400040A,0x980768,0x2600049D,0x2000059E,0x1800076B,0x980768,0x2600049D,0x2000059E,0x1800076B,0x1800076B,0xE4000231,0xF82004F2,0xFC280405,0x74000239,0x4A000252,0x3C00023D,0x3000019B,0x2A000306,0x900003C2,0x5E0002F3,0x2E0003A2,0x2000059E,
-0x6C0768,0xC00D8,0xC00D8,0xC00D8,0xC00D8,0x36000000,0x36000000,0x36000000,0x1A000000,0x1A000000,0x10000001,0x1A0000A2,0x1A0000A2,0x1A0000A2,0x1200003D,0x1200003D,0xE000022,0xC0000A2,0xC0000A2,0xA000062,0x80000A2,0x1000D8,0x1000D8,0x1000D8,0x12000061,0x12000061,0xC000039,0xC0000B2,0xC0000B2,0xA000072,0x80000AB,0x2000D8,
-0x2000D8,0xA000093,0x60000C3,0x40000DB,0x76000032,0xF8000004,0xC00D8,0x32000041,0x1E00003D,0x1A000041,0x16000034,0x12000050,0x3400006B,0x2600005D,0x100000A3,0xA000072,0x1800D8,0x1000A4,0x1000A4,0x1000A4,0x1000A4,0x36000000,0x36000000,0x36000000,0x1A000000,0x1A000000,0x10000001,0x21800A2,0x21800A2,0x21800A2,0x1200003D,0x1200003D,
-0xE000022,0x3000A2,0x3000A2,0xA000062,0x80000A2,0x21800A2,0x21800A2,0x21800A2,0x1200003D,0x1200003D,0xE000022,0x3000A2,0x3000A2,0xA000062,0x80000A2,0x3000A2,0x3000A2,0xA000062,0x80000A2,0x80000A2,0x76000032,0xF8000004,0x1000A4,0x32000041,0x1E00003D,0x1A000041,0x16000034,0x12000050,0x42000061,0x26000059,0x2400A2,0xA000062,
-0x2400A2,0x4C0374,0x90240000,0x50240000,0x3A240001,0x740372,0x52000061,0x3A000002,0xE80372,0x32000151,0x26000372,0x740372,0x52000061,0x3A000002,0xE80372,0x32000151,0x26000372,0xE80372,0x32000151,0x26000372,0x26000372,0x740372,0x52000061,0x3A000002,0xE80372,0x32000151,0x26000372,0xE80372,0x32000151,0x26000372,0x26000372,0xE80372,
-0x32000151,0x26000372,0x26000372,0x26000372,0xF4000164,0x540372,0xF8400188,0x7C000132,0x56000161,0x3C00013D,0x340000DA,0x320001BA,0xB20001D4,0x68000179,0x360000B9,0x26000372,0xA40372,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table129[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x340000,0x340000,0x340000,0x340000,0x4C0000,0x4C0000,0x4C0000,0x980000,0x980000,0x18000001,0x4C0000,0x4C0000,0x4C0000,0x980000,0x980000,0x18000001,0x980000,0x980000,0x18000001,0x18000001,0x4C0000,0x4C0000,0x4C0000,0x980000,0x980000,0x18000001,0x980000,0x980000,0x18000001,0x18000001,0x980000,
-0x980000,0x18000001,0x18000001,0x18000001,0x3C0000,0x380000,0x340000,0x2440000,0x2540000,0x6C0000,0x7C0000,0xBC0000,0x400000,0x4C0000,0x6C0000,0x18000001,0x6C0000,0x880000,0xC80000,0x1980000,0x42000001,0xC80000,0x1980000,0x42000001,0x1980000,0x42000001,0x42000001,0xC80000,0x1980000,0x42000001,0x1980000,0x42000001,
-0x42000001,0x1980000,0x42000001,0x42000001,0x42000001,0xC80000,0x1980000,0x42000001,0x1980000,0x42000001,0x42000001,0x1980000,0x42000001,0x42000001,0x42000001,0x1980000,0x42000001,0x42000001,0x42000001,0x42000001,0x2A80000,0x900000,0x900000,0xE40000,0x14C0000,0x15F40000,0x42000001,0x42000001,0xB80000,0x1000000,0x39C40000,0x42000001,
-0x1200000,0x300C14,0xBE1001C4,0x601001C4,0x421001C5,0x8E000372,0x62000025,0x4400000A,0x44000374,0x38000109,0x2E000372,0x5C000933,0x5200036A,0x400001DB,0x3A00053D,0x34000266,0x2E000453,0x2E000934,0x2C0005A5,0x26000696,0x1E000933,0x440C14,0x460005BB,0x3A000354,0x340006A6,0x34000387,0x2800050C,0x280009FD,0x2C000686,0x2400073B,0x1E000997,0x880C14,
-0x26000891,0x200008C2,0x1C000AAC,0x16000C14,0xFE000264,0xF8200772,0xFC280785,0x8800025D,0x5A000281,0x44000266,0x3C000195,0x36000351,0xB20004DE,0x68000393,0x3600045B,0x2400073B,0x600C14,0x400934,0xB21C0154,0x5E180154,0x42180155,0x8E000372,0x62000025,0x44040009,0x44000374,0x38000109,0x2E000372,0x5C0933,0x5200036A,0x400001DB,0x3A00053D,0x34000266,
-0x2E000453,0xB80933,0x2C0005A5,0x26000696,0x1E000933,0x5C0933,0x5200036A,0x400001DB,0x3A00053D,0x34000266,0x2E000453,0xB80933,0x2C0005A5,0x26000696,0x1E000933,0xB80933,0x2C0005A5,0x26000696,0x1E000933,0x1E000933,0xFE000264,0xFE2C061E,0xF23405B4,0x8800025D,0x5A000281,0x44000266,0x3C000195,0x36000351,0xB2000465,0x68000362,0x36000452,0x26000696,
-0x800933,0x1001C4,0x1001C4,0x1001C4,0x1001C4,0x4E000000,0x4E000000,0x4E000000,0x26000000,0x26000000,0x18000001,0x26000152,0x26000152,0x26000152,0x1E00007D,0x1E00007D,0x18000041,0x12000152,0x12000152,0x100000CA,0xC000152,0x21801C3,0x21801C3,0x21801C3,0x180000D1,0x180000D1,0x12000079,0x12000176,0x12000176,0x100000EE,0xC000162,0x3001C3,
-0x3001C3,0xE000141,0xA00018B,0x80001C3,0x9200006A,0xFC080044,0x1001C4,0x50000089,0x3200007D,0x2600007D,0x2200006A,0x1A00009D,0x560000E9,0x320000BE,0x16000155,0x100000EE,0x2401C3,0x180154,0x180154,0x180154,0x180154,0x4E000000,0x4E000000,0x4E000000,0x26000000,0x26000000,0x18000001,0x2240152,0x2240152,0x2240152,0x1E00007D,0x1E00007D,
-0x18000041,0x4C0152,0x4C0152,0x100000CA,0xC000152,0x2240152,0x2240152,0x2240152,0x1E00007D,0x1E00007D,0x18000041,0x4C0152,0x4C0152,0x100000CA,0xC000152,0x4C0152,0x4C0152,0x100000CA,0xC000152,0xC000152,0x9200006A,0xFC080034,0x180154,0x50000089,0x3200007D,0x2600007D,0x2200006A,0x1A00009D,0x560000D0,0x3C0000B4,0x340152,0x100000CA,
-0x340152,0x5C0374,0x98340000,0x58340000,0x42340001,0x8C0372,0x62000025,0x420C0001,0x1180372,0x38000109,0x2E000372,0x8C0372,0x62000025,0x420C0001,0x1180372,0x38000109,0x2E000372,0x1180372,0x38000109,0x2E000372,0x2E000372,0x8C0372,0x62000025,0x420C0001,0x1180372,0x38000109,0x2E000372,0x1180372,0x38000109,0x2E000372,0x2E000372,0x1180372,
-0x38000109,0x2E000372,0x2E000372,0x2E000372,0xFC080152,0x640372,0xFE4C0190,0x920000E9,0x6000010D,0x4A000104,0x3E000092,0x3600016D,0xD0000190,0x7A000128,0x4200007D,0x2E000372,0xC80372,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table130[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x440000,0x440000,0x440000,0x440000,0x640000,0x640000,0x640000,0xCC0000,0xCC0000,0x20000001,0x640000,0x640000,0x640000,0xCC0000,0xCC0000,0x20000001,0xCC0000,0xCC0000,0x20000001,0x20000001,0x640000,0x640000,0x640000,0xCC0000,0xCC0000,0x20000001,0xCC0000,0xCC0000,0x20000001,0x20000001,0xCC0000,
-0xCC0000,0x20000001,0x20000001,0x20000001,0x64C0000,0x480000,0x440000,0x5C0000,0x700000,0x900000,0xA40000,0xF80000,0x540000,0x640000,0x900000,0x20000001,0x900000,0x980000,0xE00000,0x1CC0000,0x4A000001,0xE00000,0x1CC0000,0x4A000001,0x1CC0000,0x4A000001,0x4A000001,0xE00000,0x1CC0000,0x4A000001,0x1CC0000,0x4A000001,
-0x4A000001,0x1CC0000,0x4A000001,0x4A000001,0x4A000001,0xE00000,0x1CC0000,0x4A000001,0x1CC0000,0x4A000001,0x4A000001,0x1CC0000,0x4A000001,0x4A000001,0x4A000001,0x1CC0000,0x4A000001,0x4A000001,0x4A000001,0x4A000001,0x2BC0000,0x8A00000,0x8A00000,0x1000000,0x1740000,0x1FF80000,0x4A000001,0x4A000001,0x2CC0000,0x11C0000,0x41D40000,0x4A000001,
-0x1400000,0x380F44,0xCE180304,0x6A180304,0x4A180305,0xA6000372,0x6E000005,0x4C04003A,0x50000374,0x440000C1,0x36000372,0x70000B53,0x62000455,0x460002A3,0x460005E5,0x40000296,0x3400049B,0x36000B53,0x320006F5,0x2C0007BE,0x24000B53,0x500F44,0x4C000773,0x40000494,0x400007D6,0x3A000417,0x2E0005B4,0x2E000C75,0x32000816,0x2A00089F,0x22000BD4,0xA00F44,
-0x2C000AD9,0x26000ABA,0x20000D5F,0x1A000F44,0xFE000344,0xFC2809B2,0xFE2C0A49,0x9E00029D,0x6C0002C1,0x4C0002A2,0x440001A6,0x3A0003B2,0xD00005C2,0x7C000403,0x3E000573,0x2A00089F,0x700F44,0x480B54,0xC2240244,0x68200244,0x4A200245,0xA6000372,0x6E000005,0x4E080032,0x50000374,0x440000C1,0x36000372,0x6C0B53,0x62000455,0x460002A3,0x460005E5,0x40000296,
-0x3400049B,0xDC0B53,0x320006F5,0x2C0007BE,0x24000B53,0x6C0B53,0x62000455,0x460002A3,0x460005E5,0x40000296,0x3400049B,0xDC0B53,0x320006F5,0x2C0007BE,0x24000B53,0xDC0B53,0x320006F5,0x2C0007BE,0x24000B53,0x24000B53,0xFE000344,0xF43807D4,0xF8400788,0x9E00029D,0x6C0002C1,0x4C0002A2,0x440001A6,0x3A0003B2,0xD0000519,0x7C0003C3,0x3E000563,0x2C0007BE,
-0x9C0B53,0x180304,0x180304,0x180304,0x180304,0x66000000,0x66000000,0x66000000,0x32000000,0x32000000,0x20000001,0x32000242,0x32000242,0x32000242,0x280000CD,0x280000CD,0x1E00006D,0x18000242,0x18000242,0x1600015A,0x10000242,0x200303,0x200303,0x200303,0x22000156,0x22000156,0x180000D1,0x18000282,0x18000282,0x1600019A,0xE000263,0x3C0303,
-0x3C0303,0x10000213,0xE0002AE,0xA000303,0xC40000B4,0xFE0C00D8,0x180304,0x640000F5,0x460000DD,0x2E0000E1,0x2E0000B4,0x22000104,0x64000191,0x5000014A,0x1E000248,0x1600019A,0x2C0303,0x200244,0x200244,0x200244,0x200244,0x66000000,0x66000000,0x66000000,0x32000000,0x32000000,0x20000001,0x2300242,0x2300242,0x2300242,0x280000CD,0x280000CD,
-0x1E00006D,0x640242,0x640242,0x1600015A,0x10000242,0x2300242,0x2300242,0x2300242,0x280000CD,0x280000CD,0x1E00006D,0x640242,0x640242,0x1600015A,0x10000242,0x640242,0x640242,0x1600015A,0x10000242,0x10000242,0xC40000B4,0xFE0C00B4,0x200244,0x640000F5,0x460000DD,0x2E0000E1,0x2E0000B4,0x22000104,0x74000164,0x50000131,0x480242,0x1600015A,
-0x480242,0x6C0374,0xA0440000,0x60440000,0x4A440001,0xA40372,0x6E000005,0x4A1C0001,0x14C0372,0x440000C1,0x36000372,0xA40372,0x6E000005,0x4A1C0001,0x14C0372,0x440000C1,0x36000372,0x14C0372,0x440000C1,0x36000372,0x36000372,0xA40372,0x6E000005,0x4A1C0001,0x14C0372,0x440000C1,0x36000372,0x14C0372,0x440000C1,0x36000372,0x36000372,0x14C0372,
-0x440000C1,0x36000372,0x36000372,0x36000372,0xFE140164,0x2740372,0xF86001A5,0xA60000A4,0x6C0000DD,0x540000B9,0x46000059,0x42000132,0xF200015A,0x8C0000F4,0x4C000041,0x36000372,0xE80372,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table131[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0x100000,0x100000,0x100000,0x100000,0x100000,
-0x100000,0x200000,0x200000,0x200000,0x4000001,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x200000,0x200000,0x200000,0x4000001,0x200000,0x200000,0x200000,0x4000001,0x4000001,0xC0000,0xC0000,0xC0000,0x20C0000,0x40C0000,0x100000,0x100000,0x140000,0x20C0000,0x40C0000,0x180000,0x200000,
-0x180000,0x540000,0x540000,0x540000,0x540000,0x7C0000,0x7C0000,0x7C0000,0xFC0000,0xFC0000,0x28000001,0x7C0000,0x7C0000,0x7C0000,0xFC0000,0xFC0000,0x28000001,0xFC0000,0xFC0000,0x28000001,0x28000001,0x7C0000,0x7C0000,0x7C0000,0xFC0000,0xFC0000,0x28000001,0xFC0000,0xFC0000,0x28000001,0x28000001,0xFC0000,
-0xFC0000,0x28000001,0x28000001,0x28000001,0x2600000,0x4580000,0x540000,0x2700000,0x8C0000,0xB00000,0xCC0000,0x1340000,0x680000,0x7C0000,0xB00000,0x28000001,0xB00000,0xA80000,0xF80000,0x1FC0000,0x52000001,0xF80000,0x1FC0000,0x52000001,0x1FC0000,0x52000001,0x52000001,0xF80000,0x1FC0000,0x52000001,0x1FC0000,0x52000001,
-0x52000001,0x1FC0000,0x52000001,0x52000001,0x52000001,0xF80000,0x1FC0000,0x52000001,0x1FC0000,0x52000001,0x52000001,0x1FC0000,0x52000001,0x52000001,0x52000001,0x1FC0000,0x52000001,0x52000001,0x52000001,0x52000001,0x4D00000,0xB40000,0xB40000,0x1180000,0x19C0000,0x29F80000,0x52000001,0x52000001,0xE40000,0x13C0000,0x49E40000,0x52000001,
-0x1640000,0x401198,0xDE200408,0x74200408,0x52200409,0xB6080386,0x78080015,0x560C007E,0x5C040386,0x4C0400A9,0x3E040386,0x84000BE8,0x680003F9,0x5200029B,0x5200058D,0x460001EE,0x3A00043B,0x40000BE8,0x3E0006C9,0x320007A2,0x2A000BEB,0x601194,0x62000829,0x4C00052C,0x4C00083E,0x460003FF,0x3A0005A4,0x3A000D81,0x38000852,0x320008C3,0x28000CAC,0xC41194,
-0x32000C15,0x2C000BBE,0x26000ED7,0x20001194,0xFE0C03FE,0xFE2C0B9E,0xF63C0C94,0xB40001F1,0x76000211,0x5A0001E1,0x4C000105,0x4200030B,0xF200058B,0x90000386,0x46000541,0x320008C3,0x8C1194,0x580BE8,0xCE300288,0x70300288,0x52300289,0xB20C0372,0x760C0005,0x54140042,0x5A0C0372,0x4C0400A5,0x3E0C0372,0x2800BE8,0x680003F9,0x5200029B,0x5200058D,0x460001EE,
-0x3A00043B,0x1080BE8,0x3E0006C9,0x320007A2,0x2A000BEB,0x2800BE8,0x680003F9,0x5200029B,0x5200058D,0x460001EE,0x3A00043B,0x1080BE8,0x3E0006C9,0x320007A2,0x2A000BEB,0x1080BE8,0x3E0006C9,0x320007A2,0x2A000BEB,0x2A000BEB,0xFE1403AD,0xFA440844,0xFE4C0810,0xB40001F1,0x76000211,0x5A0001E1,0x4C000105,0x4200030B,0xF20004AA,0x90000335,0x46000531,0x320007A2,
-0xB80BE8,0x200408,0x200408,0x200408,0x200408,0x76080014,0x76080014,0x76080014,0x3C040014,0x3C040014,0x28040015,0x48000288,0x48000288,0x48000288,0x3400009D,0x3400009D,0x28000032,0x22000288,0x22000288,0x20000151,0x1600028A,0x300408,0x300408,0x300408,0x2E000196,0x2E000196,0x220000C3,0x1E0002FE,0x1E0002FE,0x1C0001B6,0x160002CA,0x5C0408,
-0x5C0408,0x1600029B,0x1400035E,0xE00040B,0xF6000082,0xF2140195,0x200408,0x820000C1,0x5A0000A9,0x440000A9,0x40000082,0x2E0000DA,0x960001AB,0x5A000144,0x2C000291,0x1C0001B6,0x400408,0x300288,0x300288,0x300288,0x300288,0x720C0000,0x720C0000,0x720C0000,0x3A0C0000,0x3A0C0000,0x280C0001,0x2440288,0x2440288,0x2440288,0x3400009D,0x3400009D,
-0x28000032,0x8C0288,0x8C0288,0x20000151,0x1600028A,0x2440288,0x2440288,0x2440288,0x3400009D,0x3400009D,0x28000032,0x8C0288,0x8C0288,0x20000151,0x1600028A,0x8C0288,0x8C0288,0x20000151,0x1600028A,0x1600028A,0xF6000082,0xF82000DD,0x300288,0x820000C1,0x5A0000A9,0x440000A9,0x40000082,0x2E0000DA,0x9600015A,0x5A000120,0x640288,0x20000151,
-0x640288,0x7C0374,0xA8540000,0x68540000,0x52540001,0xBC0372,0x78080001,0x522C0001,0x17C0372,0x4A000091,0x3E000372,0xBC0372,0x78080001,0x522C0001,0x17C0372,0x4A000091,0x3E000372,0x17C0372,0x4A000091,0x3E000372,0x3E000372,0xBC0372,0x78080001,0x522C0001,0x17C0372,0x4A000091,0x3E000372,0x17C0372,0x4A000091,0x3E000372,0x3E000372,0x17C0372,
-0x4A000091,0x3E000372,0x3E000372,0x3E000372,0xFC30016D,0xA840372,0xFE6C01B1,0xBC000071,0x80000095,0x5E000080,0x5000002D,0x4A0000FA,0xF80C0152,0x9E0000B5,0x56000014,0x3E000372,0x10C0372,0x40014,0x40014,0x40014,0x40014,0x40014,0x40014,0x40014,0x40014,0x40014,0x40014,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,
-0x10000000,0x8000000,0x8000000,0x8000000,0x4000001,0x80012,0x80012,0x80012,0x80012,0x80012,0x80012,0x6000005,0x6000005,0x6000005,0x4000005,0xC0012,0xC0012,0xC0012,0x400000A,0x2000012,0x58000000,0x40014,0x40014,0x28000000,0x1C000000,0x14000000,0x14000000,0xE000000,0x20000005,0x16000002,0xA000001,0x6000005,
-0xC0012,};
-static const uint32_t g_etc1_to_bc7_m6_table132[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,
-0x2C0000,0x580000,0x580000,0x580000,0xE000000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x580000,0x580000,0x580000,0xE000000,0x580000,0x580000,0x580000,0xE000000,0xE000000,0x200000,0x1C0001,0x1C0001,0x6200000,0x240000,0x280000,0x280000,0x300000,0x6200000,0x240000,0x3C0000,0x580000,
-0x3C0000,0x640001,0x640001,0x640001,0x640001,0x980000,0x980000,0x980000,0x1300000,0x1300000,0x32000000,0x980000,0x980000,0x980000,0x1300000,0x1300000,0x32000000,0x1300000,0x1300000,0x32000000,0x32000000,0x980000,0x980000,0x980000,0x1300000,0x1300000,0x32000000,0x1300000,0x1300000,0x32000000,0x32000000,0x1300000,
-0x1300000,0x32000000,0x32000000,0x32000000,0x4740000,0x6C0000,0x640001,0x2880000,0xAC0000,0xD80000,0xF80000,0x1780000,0x800000,0x980000,0xD80000,0x32000000,0xD80000,0xB80001,0x1140000,0xFF80000,0x5C000000,0x1140000,0xFF80000,0x5C000000,0xFF80000,0x5C000000,0x5C000000,0x1140000,0xFF80000,0x5C000000,0xFF80000,0x5C000000,
-0x5C000000,0xFF80000,0x5C000000,0x5C000000,0x5C000000,0x1140000,0xFF80000,0x5C000000,0xFF80000,0x5C000000,0x5C000000,0xFF80000,0x5C000000,0x5C000000,0x5C000000,0xFF80000,0x5C000000,0x5C000000,0x5C000000,0x5C000000,0xE80000,0xAC40000,0xAC40000,0x1380000,0x1C80000,0x35F00000,0x5C000000,0x5C000000,0xFC0000,0x15C0000,0x53D80000,0x5C000000,
-0x18C0000,0x501423,0xEC2C055E,0x7E2C055E,0x5C2C055E,0xCA1003E3,0x86100072,0x6014011D,0x661003E3,0x560C00EA,0x461003E5,0xA0000BE8,0x7A00034E,0x5C04028E,0x620004C5,0x5200010D,0x460003B4,0x4E000BE8,0x4A00060E,0x3E0006ED,0x34000BE8,0x2741423,0x6E0008EE,0x58000601,0x5800089F,0x4C0003D6,0x400005B1,0x46000E44,0x4400082B,0x3C000898,0x34000D09,0xF01423,
-0x38000D6E,0x32000CD1,0x2C00102C,0x26001425,0xFE200511,0xF8400DDB,0xFC480EE3,0xD000011D,0x8A000126,0x6A00010D,0x5A00005E,0x50000214,0xFE00052B,0xA80002B6,0x5400046A,0x3C000898,0xA81423,0x680BEB,0xD444028A,0x7A40028A,0x5C40028A,0xBA200373,0x821C0002,0x5E280041,0x62200373,0x561800A6,0x461C0375,0x9C0BE8,0x7A00034E,0x5C080288,0x620004C5,0x5200010D,
-0x460003B4,0x13C0BE8,0x4A00060E,0x3E0006ED,0x34000BE8,0x9C0BE8,0x7A00034E,0x5C080288,0x620004C5,0x5200010D,0x460003B4,0x13C0BE8,0x4A00060E,0x3E0006ED,0x34000BE8,0x13C0BE8,0x4A00060E,0x3E0006ED,0x34000BE8,0x34000BE8,0xFA2C0402,0xF458087D,0xF860084A,0xD000011D,0x8A000126,0x6A00010D,0x5A00005E,0x50000214,0xFC040428,0xA800023D,0x54000451,0x3E0006ED,
-0xE00BE8,0x2C055E,0x2C055E,0x2C055E,0x2C055E,0x8A100071,0x8A100071,0x8A100071,0x46100072,0x46100072,0x32100071,0x64000288,0x64000288,0x64000288,0x46000049,0x46000049,0x32000004,0x30000288,0x30000288,0x2A000104,0x20000288,0x40055E,0x40055E,0x40055E,0x3A0001F2,0x3A0001F2,0x2E0000F1,0x28000363,0x28000363,0x260001B2,0x1E0002F4,0x80055E,
-0x80055E,0x20000359,0x1C000411,0x14000561,0xFC0C00AC,0xF8200291,0x2C055E,0xAC00006A,0x72000050,0x56000059,0x4C000032,0x40000082,0xC2000199,0x84000101,0x3E000298,0x260001B2,0x5C055E,0x40028A,0x40028A,0x40028A,0x40028A,0x7A200001,0x7A200001,0x7A200001,0x441C0001,0x441C0001,0x321C0001,0x600288,0x600288,0x600288,0x46000049,0x46000049,
-0x32000004,0xC40288,0xC40288,0x2A000104,0x20000288,0x600288,0x600288,0x600288,0x46000049,0x46000049,0x32000004,0xC40288,0xC40288,0x2A000104,0x20000288,0xC40288,0xC40288,0x2A000104,0x20000288,0x20000288,0xFE100080,0xF23400F2,0x40028A,0xAC00006A,0x72000050,0x56000059,0x4C000032,0x40000082,0xC2000109,0x840000C1,0x8C0288,0x2A000104,
-0x8C0288,0x900372,0xB0680001,0x70680001,0x5C640001,0xD40372,0x82180001,0x5C3C0000,0x1B00372,0x56000055,0x46000374,0xD40372,0x82180001,0x5C3C0000,0x1B00372,0x56000055,0x46000374,0x1B00372,0x56000055,0x46000374,0x46000374,0xD40372,0x82180001,0x5C3C0000,0x1B00372,0x56000055,0x46000374,0x1B00372,0x56000055,0x46000374,0x46000374,0x1B00372,
-0x56000055,0x46000374,0x46000374,0x46000374,0xFE440188,0x4980372,0xFA8401C2,0xDA000041,0x9600006D,0x6C000055,0x5A00000D,0x540000B9,0xFE180164,0xBA00007D,0x62000004,0x46000374,0x1300372,0x100071,0x100071,0x100071,0x100071,0x100071,0x100071,0x100071,0x100071,0x100071,0x100071,0x2C000000,0x2C000000,0x2C000000,0x2C000000,0x2C000000,
-0x2C000000,0x16000000,0x16000000,0x16000000,0xE000000,0x140071,0x140071,0x140071,0x140071,0x140071,0x140071,0x12000028,0x12000028,0x12000028,0xC000014,0x240071,0x240071,0x240071,0xA000041,0x6000071,0xE8000000,0x100071,0x100071,0x68000000,0x48000000,0x36000000,0x36000000,0x24000000,0x52000022,0x42000011,0x1C000004,0x12000028,
-0x1C0071,};
-static const uint32_t g_etc1_to_bc7_m6_table133[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x440000,0x440000,0x440000,0x440000,0x440000,
-0x440000,0x880000,0x880000,0x880000,0x16000000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x880000,0x880000,0x880000,0x16000000,0x880000,0x880000,0x880000,0x16000000,0x16000000,0x300000,0x2C0001,0x2C0001,0x2340000,0x380000,0x23C0000,0x23C0000,0x4C0000,0x2340000,0x380000,0x600000,0x880000,
-0x600000,0x740001,0x740001,0x740001,0x740001,0xB00000,0xB00000,0xB00000,0x1640000,0x1640000,0x3A000000,0xB00000,0xB00000,0xB00000,0x1640000,0x1640000,0x3A000000,0x1640000,0x1640000,0x3A000000,0x3A000000,0xB00000,0xB00000,0xB00000,0x1640000,0x1640000,0x3A000000,0x1640000,0x1640000,0x3A000000,0x3A000000,0x1640000,
-0x1640000,0x3A000000,0x3A000000,0x3A000000,0x880000,0x67C0000,0x740001,0xA00000,0xC40000,0xF80000,0x1200000,0x1B40000,0x940000,0xB00000,0xF80000,0x3A000000,0xF80000,0xC80001,0x12C0000,0x1BF80000,0x64000000,0x12C0000,0x1BF80000,0x64000000,0x1BF80000,0x64000000,0x64000000,0x12C0000,0x1BF80000,0x64000000,0x1BF80000,0x64000000,
-0x64000000,0x1BF80000,0x64000000,0x64000000,0x64000000,0x12C0000,0x1BF80000,0x64000000,0x1BF80000,0x64000000,0x64000000,0x1BF80000,0x64000000,0x64000000,0x64000000,0x1BF80000,0x64000000,0x64000000,0x64000000,0x64000000,0xFC0000,0xD80000,0xD80000,0x1540000,0x1EC0000,0x3FF00000,0x64000000,0x64000000,0x3100000,0x17C0000,0x5BE80000,0x64000000,
-0x1AC0000,0x5C16CF,0xF83806EA,0x883806EA,0x643806EA,0xDA18047B,0x90180112,0x662001F9,0x7018047B,0x6014016E,0x4E18047D,0xB8000BE8,0x8C0002DE,0x660C02C2,0x6E00044D,0x5E00007D,0x4E00037D,0x5A000BE8,0x5000056A,0x44000675,0x3C000BE8,0x8816CF,0x7A000A0E,0x6200072E,0x68000911,0x580003FE,0x4C0005F9,0x52000F0C,0x4C00082B,0x44000886,0x3A000D5D,0x11416CF,
-0x44000EFE,0x3E000E01,0x32001198,0x2C0016D1,0xFE280685,0xFE4C1017,0xFE4C119F,0xE6000086,0x9A0000A1,0x78000083,0x6200000D,0x5800015D,0xFE00061B,0xBC00020A,0x5E0003DE,0x44000886,0xC016CF,0x780BEB,0xDC54028A,0x8250028A,0x6450028A,0xC2300373,0x8A2C0002,0x66380041,0x6A300373,0x5E2800A6,0x4E2C0375,0xB40BE8,0x8C0002DE,0x64180288,0x6E00044D,0x5E00007D,
-0x4E00037D,0x1700BE8,0x5000056A,0x44000675,0x3C000BE8,0xB40BE8,0x8C0002DE,0x64180288,0x6E00044D,0x5E00007D,0x4E00037D,0x1700BE8,0x5000056A,0x44000675,0x3C000BE8,0x1700BE8,0x5000056A,0x44000675,0x3C000BE8,0x3C000BE8,0xFE340432,0xFC68087D,0xFE6C085E,0xE6000086,0x9A0000A1,0x78000083,0x6200000D,0x5800015D,0xFE180455,0xBC00017A,0x5E0003BA,0x44000675,
-0x1000BE8,0x3806EA,0x3806EA,0x3806EA,0x3806EA,0x9A180109,0x9A180109,0x9A180109,0x5018010A,0x5018010A,0x3A180109,0x7C000288,0x7C000288,0x7C000288,0x52000019,0x52000019,0x3A040008,0x3C000288,0x3C000288,0x320000B9,0x28000288,0x5006E9,0x5006E9,0x5006E9,0x4600028A,0x4600028A,0x34000169,0x340003DB,0x340003DB,0x2E0001C2,0x28000331,0xA006E9,
-0xA006E9,0x2600043D,0x200004EC,0x1A0006E9,0xFE100140,0xFE2C03C9,0x3806EA,0xD000002D,0x86000020,0x6A00001D,0x62000009,0x4A000041,0xE40001A5,0x960000E2,0x4C0002A1,0x2E0001C2,0x7006E9,0x50028A,0x50028A,0x50028A,0x50028A,0x82300001,0x82300001,0x82300001,0x4C2C0001,0x4C2C0001,0x3A2C0001,0x780288,0x780288,0x780288,0x52000019,0x52000019,
-0x3A0C0000,0xF40288,0xF40288,0x320000B9,0x28000288,0x780288,0x780288,0x780288,0x52000019,0x52000019,0x3A0C0000,0xF40288,0xF40288,0x320000B9,0x28000288,0xF40288,0xF40288,0x320000B9,0x28000288,0x28000288,0xFE200091,0xFA4400F2,0x50028A,0xD000002D,0x86000020,0x6A00001D,0x62000009,0x4A000041,0xF40000CA,0x9A000080,0xAC0288,0x320000B9,
-0xAC0288,0xA00372,0xB8780001,0x78780001,0x64740001,0xEC0372,0x8A280001,0x644C0000,0x1E40372,0x60000034,0x4E000374,0xEC0372,0x8A280001,0x644C0000,0x1E40372,0x60000034,0x4E000374,0x1E40372,0x60000034,0x4E000374,0x4E000374,0xEC0372,0x8A280001,0x644C0000,0x1E40372,0x60000034,0x4E000374,0x1E40372,0x60000034,0x4E000374,0x4E000374,0x1E40372,
-0x60000034,0x4E000374,0x4E000374,0x4E000374,0xFE50019A,0xCA80372,0xF29401E1,0xEE000020,0xA000003D,0x7A00002D,0x64000001,0x5C000091,0xFE2C0185,0xCC000059,0x6A080000,0x4E000374,0x1540372,0x180109,0x180109,0x180109,0x180109,0x180109,0x180109,0x180109,0x180109,0x180109,0x180109,0x44000000,0x44000000,0x44000000,0x44000000,0x44000000,
-0x44000000,0x20000001,0x20000001,0x20000001,0x16000000,0x200109,0x200109,0x200109,0x200109,0x200109,0x200109,0x18000064,0x18000064,0x18000064,0x12000034,0x3C0109,0x3C0109,0x3C0109,0x1000009D,0xA000109,0xFC080019,0x180109,0x180109,0xA0000000,0x6E000000,0x54000000,0x54000000,0x38000000,0x84000050,0x64000028,0x26000008,0x18000064,
-0x2C0109,};
-static const uint32_t g_etc1_to_bc7_m6_table134[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,
-0x5C0000,0xB80000,0xB80000,0xB80000,0x1E000000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0xB80000,0xB80000,0xB80000,0x1E000000,0xB80000,0xB80000,0xB80000,0x1E000000,0x1E000000,0x8400000,0x3C0001,0x3C0001,0x480000,0x24C0000,0x540000,0x540000,0x680000,0x480000,0x24C0000,0x800000,0xB80000,
-0x800000,0x840001,0x840001,0x840001,0x840001,0x2C40000,0x2C40000,0x2C40000,0x1940000,0x1940000,0x42000000,0x2C40000,0x2C40000,0x2C40000,0x1940000,0x1940000,0x42000000,0x1940000,0x1940000,0x42000000,0x42000000,0x2C40000,0x2C40000,0x2C40000,0x1940000,0x1940000,0x42000000,0x1940000,0x1940000,0x42000000,0x42000000,0x1940000,
-0x1940000,0x42000000,0x42000000,0x42000000,0x9C0000,0xE8C0000,0x840001,0x2B40000,0xE00000,0x11C0000,0x1480000,0x1F00000,0xA80000,0x2C40000,0x11C0000,0x42000000,0x11C0000,0xD80001,0x1440000,0x27F80000,0x6C000000,0x1440000,0x27F80000,0x6C000000,0x27F80000,0x6C000000,0x6C000000,0x1440000,0x27F80000,0x6C000000,0x27F80000,0x6C000000,
-0x6C000000,0x27F80000,0x6C000000,0x6C000000,0x6C000000,0x1440000,0x27F80000,0x6C000000,0x27F80000,0x6C000000,0x6C000000,0x27F80000,0x6C000000,0x6C000000,0x6C000000,0x27F80000,0x6C000000,0x6C000000,0x6C000000,0x6C000000,0x1100000,0xE80000,0xE80000,0x36C0000,0x9FC0000,0x49F00000,0x6C000000,0x6C000000,0x1280000,0x1980000,0x63F80000,0x6C000000,
-0x1D00000,0x6819DB,0xFE4408D2,0x924008CA,0x6C4008CA,0xEA200553,0x9A2001FA,0x70280319,0x7A200553,0x681C0235,0x56200555,0xD0000BE8,0x9E00029E,0x6E10032E,0x800003ED,0x68000029,0x56000378,0x66000BE8,0x5C0004DA,0x500005E5,0x44000BE8,0x29819DB,0x86000B8E,0x6A0008DD,0x740009E9,0x62000465,0x5200068D,0x5E000FF4,0x58000853,0x4C00088E,0x40000DD1,0x13819DB,
-0x4A0010D2,0x44000F69,0x3E001338,0x320019DD,0xFE340856,0xF65C1329,0xF860148A,0xFE000033,0xAC00003D,0x84000029,0x6C040006,0x640000D5,0xFE1007BB,0xD4000193,0x66000384,0x4C00088E,0xDC19DB,0x880BEB,0xE464028A,0x8A60028A,0x6C60028A,0xCA400373,0x923C0002,0x6E480041,0x72400373,0x663800A6,0x563C0375,0xCC0BE8,0x9E00029E,0x6C280288,0x800003ED,0x68000029,
-0x56080374,0x1A00BE8,0x5C0004DA,0x500005E5,0x44000BE8,0xCC0BE8,0x9E00029E,0x6C280288,0x800003ED,0x68000029,0x56080374,0x1A00BE8,0x5C0004DA,0x500005E5,0x44000BE8,0x1A00BE8,0x5C0004DA,0x500005E5,0x44000BE8,0x44000BE8,0xFE50045E,0xF47808BB,0xF880088B,0xFE000033,0xAC00003D,0x84000029,0x6C040002,0x640000D5,0xFE2404A1,0xDA0000E6,0x6A000359,0x500005E5,
-0x1240BE8,0x4008CA,0x4008CA,0x4008CA,0x4008CA,0xAA2001E1,0xAA2001E1,0xAA2001E1,0x5A2001E2,0x5A2001E2,0x422001E1,0x94000288,0x94000288,0x94000288,0x62000001,0x62000001,0x42080034,0x48000288,0x48000288,0x3C000088,0x30000288,0x6008C9,0x6008C9,0x6008C9,0x52000362,0x52000362,0x40000221,0x40000473,0x40000473,0x360001F8,0x2E000371,0xC408C9,
-0xC408C9,0x2C000569,0x260005F4,0x200008C9,0xFE200221,0xF438058A,0x4008CA,0xF200000D,0x9E000005,0x7C000005,0x70000001,0x56000019,0xFE0001FA,0xB60000CE,0x5C0002AC,0x360001F8,0x8C08C9,0x60028A,0x60028A,0x60028A,0x60028A,0x8A400001,0x8A400001,0x8A400001,0x543C0001,0x543C0001,0x423C0001,0x900288,0x900288,0x900288,0x62000001,0x62000001,
-0x421C0000,0x1240288,0x1240288,0x3C000088,0x30000288,0x900288,0x900288,0x900288,0x62000001,0x62000001,0x421C0000,0x1240288,0x1240288,0x3C000088,0x30000288,0x1240288,0x1240288,0x3C000088,0x30000288,0x30000288,0xFA3400A2,0xF2540109,0x60028A,0xF200000D,0x9E000005,0x7C000005,0x6E040000,0x56000019,0xFE0C00C8,0xBC00004A,0xD00288,0x3C000088,
-0xD00288,0xB00372,0xC0880001,0x80880001,0x6C840001,0x1040372,0x92380001,0x6C5C0000,0x7FC0372,0x6A00001D,0x56000374,0x1040372,0x92380001,0x6C5C0000,0x7FC0372,0x6A00001D,0x56000374,0x7FC0372,0x6A00001D,0x56000374,0x56000374,0x1040372,0x92380001,0x6C5C0000,0x7FC0372,0x6A00001D,0x56000374,0x7FC0372,0x6A00001D,0x56000374,0x56000374,0x7FC0372,
-0x6A00001D,0x56000374,0x56000374,0x56000374,0xF86C01A5,0xBC0372,0xFAA401E1,0xFE040014,0xAC040029,0x84000019,0x6C0C0000,0x64000071,0xFA4C0188,0xDE000034,0x72180000,0x56000374,0x1740372,0x2001E1,0x2001E1,0x2001E1,0x2001E1,0x2001E1,0x2001E1,0x2001E1,0x2001E1,0x2001E1,0x2001E1,0x5C000000,0x5C000000,0x5C000000,0x5C000000,0x5C000000,
-0x5C000000,0x2C000001,0x2C000001,0x2C000001,0x1E000000,0x2C01E1,0x2C01E1,0x2C01E1,0x2C01E1,0x2C01E1,0x2C01E1,0x220000AA,0x220000AA,0x220000AA,0x1A000061,0x5801E1,0x5801E1,0x5801E1,0x16000121,0xE0001E1,0xFE0C0075,0x2001E1,0x2001E1,0xD8000000,0x96000000,0x72000000,0x72000000,0x4C000000,0xB6000092,0x82000050,0x3600000D,0x220000AA,
-0x3C01E1,};
-static const uint32_t g_etc1_to_bc7_m6_table135[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x740000,0x740000,0x740000,0x740000,0x740000,
-0x740000,0xE80000,0xE80000,0xE80000,0x26000000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0xE80000,0xE80000,0xE80000,0x26000000,0xE80000,0xE80000,0xE80000,0x26000000,0x26000000,0x540000,0x4C0001,0x4C0001,0x4580000,0x2600000,0x2680000,0x2680000,0x2800000,0x4580000,0x2600000,0xA40000,0xE80000,
-0xA40000,0x940001,0x940001,0x940001,0x940001,0x2DC0000,0x2DC0000,0x2DC0000,0x1C40000,0x1C40000,0x4A000000,0x2DC0000,0x2DC0000,0x2DC0000,0x1C40000,0x1C40000,0x4A000000,0x1C40000,0x1C40000,0x4A000000,0x4A000000,0x2DC0000,0x2DC0000,0x2DC0000,0x1C40000,0x1C40000,0x4A000000,0x1C40000,0x1C40000,0x4A000000,0x4A000000,0x1C40000,
-0x1C40000,0x4A000000,0x4A000000,0x4A000000,0x4AC0000,0xA00000,0x940001,0xCC0000,0xFC0000,0x13C0000,0x16C0000,0xBF80000,0xBC0000,0x2DC0000,0x13C0000,0x4A000000,0x13C0000,0xE80001,0x15C0000,0x33F80000,0x74000000,0x15C0000,0x33F80000,0x74000000,0x33F80000,0x74000000,0x74000000,0x15C0000,0x33F80000,0x74000000,0x33F80000,0x74000000,
-0x74000000,0x33F80000,0x74000000,0x74000000,0x74000000,0x15C0000,0x33F80000,0x74000000,0x33F80000,0x74000000,0x74000000,0x33F80000,0x74000000,0x74000000,0x74000000,0x33F80000,0x74000000,0x74000000,0x74000000,0x74000000,0x1240000,0x4F80000,0x4F80000,0x1880000,0x17FC0000,0x53F00000,0x74000000,0x74000000,0x33C0000,0x1B80000,0x6DCC0000,0x74000000,
-0x1F00000,0x741D47,0xFE500B2E,0x9A4C0AFE,0x744C0AFE,0xFA28066B,0xA62C0322,0x7A340492,0x8428066B,0x6E24033A,0x5E28066D,0xEA000BE8,0xAC000289,0x781803CA,0x8C0003A5,0x72000009,0x60080394,0x72000BE8,0x6600046C,0x5600057D,0x4C000BE8,0xAC1D47,0x92000D6E,0x74000AFE,0x80000B01,0x6800053D,0x5E000775,0x680010D8,0x5E00088F,0x540008B8,0x48000E58,0x15C1D47,
-0x5000130E,0x4A001121,0x440014EC,0x38001D49,0xFE3C0AD7,0xFC68162D,0xFE6C17C2,0xFE0C0095,0xC000000D,0x90000005,0x7608002D,0x6C000072,0xFE180A0E,0xE6000156,0x7600031A,0x540008B8,0xF41D47,0x980BEB,0xEC74028A,0x9270028A,0x7470028A,0xD2500373,0x9A4C0002,0x76580041,0x7A500373,0x6E4800A6,0x5E4C0375,0xE40BE8,0xAA040289,0x74380288,0x8C0003A5,0x72000009,
-0x5E180374,0x1D00BE8,0x6600046C,0x5600057D,0x4C000BE8,0xE40BE8,0xAA040289,0x74380288,0x8C0003A5,0x72000009,0x5E180374,0x1D00BE8,0x6600046C,0x5600057D,0x4C000BE8,0x1D00BE8,0x6600046C,0x5600057D,0x4C000BE8,0x4C000BE8,0xFC6004C1,0xFC8808BB,0xFE8C08A3,0xFE14004A,0xC000000D,0x90000005,0x74140002,0x6C000072,0xFC4004E8,0xEC00007E,0x760002E9,0x5600057D,
-0x1480BE8,0x4C0AFE,0x4C0AFE,0x4C0AFE,0x4C0AFE,0xBA2802F9,0xBA2802F9,0xBA2802F9,0x642802FA,0x642802FA,0x4A2802F9,0xAC000288,0xAC000288,0xAC000288,0x6E040005,0x6E040005,0x4C100084,0x54000288,0x54000288,0x44000055,0x38000288,0x700AFE,0x700AFE,0x700AFE,0x62000471,0x62000471,0x46000321,0x4C00052B,0x4C00052B,0x40000236,0x340003C9,0xE40AFE,
-0xE40AFE,0x320006DD,0x2C00072C,0x24000B01,0xFE2C0378,0xFA440776,0x4C0AFE,0xFE080020,0xB8000001,0x8E000002,0x80040011,0x62000005,0xFE00031A,0xD40000D2,0x660002B4,0x40000236,0xA00AFE,0x70028A,0x70028A,0x70028A,0x70028A,0x92500001,0x92500001,0x92500001,0x5C4C0001,0x5C4C0001,0x4A4C0001,0xA80288,0xA80288,0xA80288,0x6A0C0001,0x6A0C0001,
-0x4A2C0000,0x1580288,0x1580288,0x44000055,0x38000288,0xA80288,0xA80288,0xA80288,0x6A0C0001,0x6A0C0001,0x4A2C0000,0x1580288,0x1580288,0x44000055,0x38000288,0x1580288,0x1580288,0x44000055,0x38000288,0x38000288,0xF64800B5,0xFA640109,0x70028A,0xFA10000D,0xAE0C0001,0x88080000,0x76140000,0x62000005,0xF62400DD,0xDA000022,0xF00288,0x44000055,
-0xF00288,0xC00372,0xC8980001,0x88980001,0x74940001,0x11C0372,0x9A480001,0x746C0000,0x13FC0372,0x72000008,0x5E000374,0x11C0372,0x9A480001,0x746C0000,0x13FC0372,0x72000008,0x5E000374,0x13FC0372,0x72000008,0x5E000374,0x5E000374,0x11C0372,0x9A480001,0x746C0000,0x13FC0372,0x72000008,0x5E000374,0x13FC0372,0x72000008,0x5E000374,0x5E000374,0x13FC0372,
-0x72000008,0x5E000374,0x5E000374,0x5E000374,0xFE7801B1,0xCC0372,0xF2B40202,0xFE200020,0xC000000D,0x90000005,0x741C0000,0x70000050,0xFE5C018A,0xF400001D,0x7A280000,0x5E000374,0x1980372,0x2802F9,0x2802F9,0x2802F9,0x2802F9,0x2802F9,0x2802F9,0x2802F9,0x2802F9,0x2802F9,0x2802F9,0x76000000,0x76000000,0x76000000,0x76000000,0x76000000,
-0x76000000,0x38000001,0x38000001,0x38000001,0x26000000,0x3802F9,0x3802F9,0x3802F9,0x3802F9,0x3802F9,0x3802F9,0x2E000112,0x2E000112,0x2E000112,0x22000089,0x7002F9,0x7002F9,0x7002F9,0x1C0001CD,0x120002F9,0xF4180120,0x2802F9,0x2802F9,0xFE040005,0xBE000000,0x90000000,0x90000000,0x5E000000,0xF60000F1,0xA400007D,0x46000011,0x2E000112,
-0x5002F9,};
-static const uint32_t g_etc1_to_bc7_m6_table136[] = {
-0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x200000,
-0x200000,0x200000,0x200000,0x4000001,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0x100000,0x180000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,
-0x28C0000,0x1200000,0x1200000,0x1200000,0x2E000001,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x1200000,0x1200000,0x1200000,0x2E000001,0x1200000,0x1200000,0x1200000,0x2E000001,0x2E000001,0xA640000,0x600000,0x600000,0x700000,0x780000,0x2800000,0x2800000,0xA00000,0x700000,0x780000,0xCC0000,0x1200000,
-0xCC0000,0xA80000,0xA80000,0xA80000,0xA80000,0xF80000,0xF80000,0xF80000,0x1FC0000,0x1FC0000,0x52000001,0xF80000,0xF80000,0xF80000,0x1FC0000,0x1FC0000,0x52000001,0x1FC0000,0x1FC0000,0x52000001,0x52000001,0xF80000,0xF80000,0xF80000,0x1FC0000,0x1FC0000,0x52000001,0x1FC0000,0x1FC0000,0x52000001,0x52000001,0x1FC0000,
-0x1FC0000,0x52000001,0x52000001,0x52000001,0xC40000,0xB40000,0xA80000,0xE40000,0x1180000,0x1640000,0x19C0000,0x17F80000,0x4D00000,0xF80000,0x1640000,0x52000001,0x1640000,0xFC0000,0x3740000,0x3FFC0000,0x7C000001,0x3740000,0x3FFC0000,0x7C000001,0x3FFC0000,0x7C000001,0x7C000001,0x3740000,0x3FFC0000,0x7C000001,0x3FFC0000,0x7C000001,
-0x7C000001,0x3FFC0000,0x7C000001,0x7C000001,0x7C000001,0x3740000,0x3FFC0000,0x7C000001,0x3FFC0000,0x7C000001,0x7C000001,0x3FFC0000,0x7C000001,0x7C000001,0x7C000001,0x3FFC0000,0x7C000001,0x7C000001,0x7C000001,0x7C000001,0x13C0000,0x10C0000,0x10C0000,0x1A80000,0x27F80000,0x5DFC0000,0x7C000001,0x7C000001,0x3540000,0x1D80000,0x75FC0000,0x7C000001,
-0xDFC0000,0x841EA8,0xFE600C58,0xA45C0BE8,0x7C5C0BE9,0xFC3806F8,0xB23803A1,0x82440531,0x8E3406E6,0x7A3403AE,0x683406E6,0xF80C0BE8,0xB80C028A,0x84240411,0x9608038E,0x7C0C000E,0x6A1403AE,0x7C0C0BE8,0x72000417,0x62040533,0x540C0BEB,0xC41EA8,0xA8000D6B,0x7C100BE9,0x8C000A7E,0x740004CE,0x68000746,0x7400107B,0x6A000782,0x5E0007AB,0x52000DBC,0x18C1EA8,
-0x5C001329,0x560010EE,0x4A0014E3,0x40001EAC,0xFE500C45,0xFE6C17DE,0xF67C1978,0xFE1C0128,0xCA0C0011,0x9A0C0006,0x80140046,0x78040046,0xFE340B52,0xFE000098,0x820002B5,0x5E0007AB,0x1181EA8,0xAC0BE8,0xF8840288,0x9A840288,0x7C840289,0xDC600372,0xA0600005,0x7E680042,0x84600372,0x765800A5,0x68600372,0x1000BE8,0xB4140289,0x7E480289,0x9A00037D,0x7C14000A,
-0x68280372,0x5F80BE8,0x720003F3,0x60000513,0x54000BEB,0x1000BE8,0xB4140289,0x7E480289,0x9A00037D,0x7C14000A,0x68280372,0x5F80BE8,0x720003F3,0x60000513,0x54000BEB,0x5F80BE8,0x720003F3,0x60000513,0x54000BEB,0x54000BEB,0xFE7804ED,0xF69C08F6,0xFAA408C9,0xFE300081,0xCA10000D,0x98100006,0x7E280001,0x7A000031,0xFC580519,0xFE040033,0x820002B1,0x60000513,
-0x16C0BE8,0x5C0BE8,0x5C0BE8,0x5C0BE8,0x5C0BE8,0xC6380374,0xC6380374,0xC6380374,0x6E380374,0x6E380374,0x52340375,0xBC0C0288,0xBC0C0288,0xBC0C0288,0x7A100009,0x7A100009,0x561800A6,0x5E0C0288,0x5E0C0288,0x4E080041,0x400C028A,0x880BE8,0x880BE8,0x880BE8,0x6E000465,0x6E000465,0x52000373,0x580004E1,0x580004E1,0x4C0001AA,0x4000036B,0x1140BE8,
-0x1140BE8,0x3E0006ED,0x3800072A,0x2C000BEB,0xFE3C0434,0xFE4C0864,0x5C0BE8,0xFE180059,0xC80C0005,0x9A0C0005,0x88140021,0x6E0C0002,0xFE1403B9,0xF600005E,0x7C00028C,0x4C0001AA,0xC00BE8,0x840288,0x840288,0x840288,0x840288,0x9C600000,0x9C600000,0x9C600000,0x64600000,0x64600000,0x52600001,0xC40288,0xC40288,0xC40288,0x72200001,0x72200001,
-0x543C0001,0x18C0288,0x18C0288,0x5000002D,0x4000028A,0xC40288,0xC40288,0xC40288,0x72200001,0x72200001,0x543C0001,0x18C0288,0x18C0288,0x5000002D,0x4000028A,0x18C0288,0x18C0288,0x5000002D,0x4000028A,0x4000028A,0xFE5800B5,0xF4780120,0x840288,0xFE240012,0xBC180000,0x92180000,0x7E280000,0x70080000,0xFE3400DD,0xFC00000A,0x1180288,0x5000002D,
-0x1180288,0xD00374,0xD2A80000,0x92A80000,0x7CA80001,0x1380372,0xA25C0001,0x7C800001,0x21F80372,0x7C000001,0x68000372,0x1380372,0xA25C0001,0x7C800001,0x21F80372,0x7C000001,0x68000372,0x21F80372,0x7C000001,0x68000372,0x68000372,0x1380372,0xA25C0001,0x7C800001,0x21F80372,0x7C000001,0x68000372,0x21F80372,0x7C000001,0x68000372,0x68000372,0x21F80372,
-0x7C000001,0x68000372,0x68000372,0x68000372,0xFE9401C2,0xE00372,0xFCC80200,0xFC3C0032,0xCE040005,0x9C040000,0x7C300001,0x7A00002D,0xFE7001B1,0xFE080014,0x84380000,0x68000372,0x1BC0372,0x340374,0x340374,0x340374,0x340374,0x340374,0x340374,0x340374,0x340374,0x340374,0x340374,0x840C0000,0x840C0000,0x840C0000,0x840C0000,0x840C0000,
-0x840C0000,0x440C0000,0x440C0000,0x440C0000,0x2E0C0001,0x500372,0x500372,0x500372,0x500372,0x500372,0x500372,0x3A0000E9,0x3A0000E9,0x3A0000E9,0x2E000052,0xA00372,0xA00372,0xA00372,0x200001E1,0x1A000372,0xFC28016D,0x340374,0x340374,0xFE10001D,0xD20C0000,0xA20C0000,0xA20C0000,0x6C0C0000,0xF80400F2,0xD6000041,0x5A000000,0x3A0000E9,
-0x700372,};
-static const uint32_t g_etc1_to_bc7_m6_table137[] = {
-0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x280000,0x500000,
-0x500000,0x500000,0x500000,0xC000001,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x61C0000,0x61C0000,0x61C0000,0x280000,0x380000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,
-0x2A40000,0x1500000,0x1500000,0x1500000,0x36000001,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x1500000,0x1500000,0x1500000,0x36000001,0x1500000,0x1500000,0x1500000,0x36000001,0x36000001,0x780000,0x700000,0x700000,0x4800000,0x8C0000,0x980000,0x980000,0xBC0000,0x4800000,0x8C0000,0xEC0000,0x1500000,
-0xEC0000,0xB80000,0xB80000,0xB80000,0xB80000,0x1100000,0x1100000,0x1100000,0xDFC0000,0xDFC0000,0x5A000001,0x1100000,0x1100000,0x1100000,0xDFC0000,0xDFC0000,0x5A000001,0xDFC0000,0xDFC0000,0x5A000001,0x5A000001,0x1100000,0x1100000,0x1100000,0xDFC0000,0xDFC0000,0x5A000001,0xDFC0000,0xDFC0000,0x5A000001,0x5A000001,0xDFC0000,
-0xDFC0000,0x5A000001,0x5A000001,0x5A000001,0x2D40000,0xC40000,0xB80000,0x2F80000,0x1340000,0x1880000,0x1C00000,0x21FC0000,0x4E40000,0x1100000,0x1880000,0x5A000001,0x1880000,0x10C0000,0x38C0000,0x4BFC0000,0x84000001,0x38C0000,0x4BFC0000,0x84000001,0x4BFC0000,0x84000001,0x84000001,0x38C0000,0x4BFC0000,0x84000001,0x4BFC0000,0x84000001,
-0x84000001,0x4BFC0000,0x84000001,0x84000001,0x84000001,0x38C0000,0x4BFC0000,0x84000001,0x4BFC0000,0x84000001,0x84000001,0x4BFC0000,0x84000001,0x84000001,0x84000001,0x4BFC0000,0x84000001,0x84000001,0x84000001,0x84000001,0x1500000,0x71C0000,0x71C0000,0x3C00000,0x35F80000,0x67FC0000,0x84000001,0x84000001,0x16C0000,0x1F80000,0x7FD00000,0x84000001,
-0x1DF80000,0x941EA8,0xFE740C91,0xAC6C0BE8,0x846C0BE9,0xFC4C0716,0xBA4803A1,0x8A540531,0x964406E6,0x824403AE,0x704406E6,0xFE1C0BEB,0xC01C028A,0x8C340411,0x9E18038E,0x841C000E,0x722403AE,0x841C0BE8,0x780C0413,0x6A140533,0x5C1C0BEB,0xDC1EA8,0xBA000CBB,0x84200BE9,0x9800096E,0x80000406,0x700006EC,0x86000F87,0x7400061B,0x68000663,0x5A000D03,0x1BC1EA8,
-0x6600124C,0x5C000FB6,0x5600140B,0x48001EAC,0xFE640CCE,0xFC8817E8,0xFE8C1978,0xFE34018E,0xD21C0011,0xA21C0006,0x88240046,0x80140046,0xFE440C0F,0xFE1000C2,0x8A08029D,0x68000663,0x1381EA8,0xBC0BE8,0xFC940289,0xA2940288,0x84940289,0xE4700372,0xA8700005,0x86780042,0x8C700372,0x7E6800A5,0x70700372,0x1180BE8,0xBC240289,0x86580289,0xA6040372,0x8424000A,
-0x70380372,0x11F80BE8,0x78000393,0x6C0004B3,0x5C000BEB,0x1180BE8,0xBC240289,0x86580289,0xA6040372,0x8424000A,0x70380372,0x11F80BE8,0x78000393,0x6C0004B3,0x5C000BEB,0x11F80BE8,0x78000393,0x6C0004B3,0x5C000BEB,0x5C000BEB,0xFE800552,0xFEAC08F6,0xFEAC0901,0xFE4000AB,0xD220000D,0xA0200006,0x86380001,0x82000022,0xFE5C0579,0xFE180059,0x8C00028E,0x6C0004B3,
-0x1900BE8,0x6C0BE8,0x6C0BE8,0x6C0BE8,0x6C0BE8,0xCE480374,0xCE480374,0xCE480374,0x76480374,0x76480374,0x5A440375,0xC41C0288,0xC41C0288,0xC41C0288,0x82200009,0x82200009,0x5E2800A6,0x661C0288,0x661C0288,0x56180041,0x481C028A,0xA00BE8,0xA00BE8,0xA00BE8,0x800003ED,0x800003ED,0x5A100373,0x6800042A,0x6800042A,0x540000F6,0x460002EB,0x1440BE8,
-0x1440BE8,0x4A000655,0x3E00068A,0x34000BEB,0xFE4C0461,0xFA64087D,0x6C0BE8,0xFE2C0081,0xD01C0005,0xA21C0005,0x90240021,0x761C0002,0xFA2C03F9,0xFC080049,0x840C028A,0x540000F6,0xE40BE8,0x940288,0x940288,0x940288,0x940288,0xA4700000,0xA4700000,0xA4700000,0x6C700000,0x6C700000,0x5A700001,0xDC0288,0xDC0288,0xDC0288,0x7A300001,0x7A300001,
-0x5C4C0001,0x1BC0288,0x1BC0288,0x58000019,0x4800028A,0xDC0288,0xDC0288,0xDC0288,0x7A300001,0x7A300001,0x5C4C0001,0x1BC0288,0x1BC0288,0x58000019,0x4800028A,0x1BC0288,0x1BC0288,0x58000019,0x4800028A,0x4800028A,0xFA6C00C8,0xFC880120,0x940288,0xFE34001D,0xC4280000,0x9A280000,0x86380000,0x78180000,0xFA4800F4,0xFC14000D,0x1380288,0x58000019,
-0x1380288,0xE00374,0xDAB80000,0x9AB80000,0x84B80001,0x1500372,0xAA6C0001,0x84900001,0x2DF80372,0x84100001,0x70000372,0x1500372,0xAA6C0001,0x84900001,0x2DF80372,0x84100001,0x70000372,0x2DF80372,0x84100001,0x70000372,0x70000372,0x1500372,0xAA6C0001,0x84900001,0x2DF80372,0x84100001,0x70000372,0x2DF80372,0x84100001,0x70000372,0x70000372,0x2DF80372,
-0x84100001,0x70000372,0x70000372,0x70000372,0xF8A801E1,0xF00372,0xF4D80221,0xFC540048,0xDC080001,0xA4140000,0x84400001,0x82000019,0xFC8C01C2,0xFE200028,0x8C480000,0x70000372,0x1E00372,0x440374,0x440374,0x440374,0x440374,0x440374,0x440374,0x440374,0x440374,0x440374,0x440374,0x8C1C0000,0x8C1C0000,0x8C1C0000,0x8C1C0000,0x8C1C0000,
-0x8C1C0000,0x4C1C0000,0x4C1C0000,0x4C1C0000,0x361C0001,0x680372,0x680372,0x680372,0x680372,0x680372,0x680372,0x4C000089,0x4C000089,0x4C000089,0x36000011,0xD00372,0xD00372,0xD00372,0x2C000179,0x22000372,0xF4380188,0x440374,0x440374,0xFE200028,0xDA1C0000,0xAA1C0000,0xAA1C0000,0x741C0000,0xFE1000FA,0xFE000014,0x62100000,0x4C000089,
-0x940372,};
-static const uint32_t g_etc1_to_bc7_m6_table138[] = {
-0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x400000,0x800000,
-0x800000,0x800000,0x800000,0x14000001,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0xE2C0000,0xE2C0000,0xE2C0000,0x400000,0x5C0000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,
-0x2BC0000,0x1800000,0x1800000,0x1800000,0x3E000001,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x1800000,0x1800000,0x1800000,0x3E000001,0x1800000,0x1800000,0x1800000,0x3E000001,0x3E000001,0x880000,0x800000,0x800000,0x940000,0xA00000,0x2AC0000,0x2AC0000,0x2D40000,0x940000,0xA00000,0x1100000,0x1800000,
-0x1100000,0xC80000,0xC80000,0xC80000,0xC80000,0x1280000,0x1280000,0x1280000,0x19FC0000,0x19FC0000,0x62000001,0x1280000,0x1280000,0x1280000,0x19FC0000,0x19FC0000,0x62000001,0x19FC0000,0x19FC0000,0x62000001,0x62000001,0x1280000,0x1280000,0x1280000,0x19FC0000,0x19FC0000,0x62000001,0x19FC0000,0x19FC0000,0x62000001,0x62000001,0x19FC0000,
-0x19FC0000,0x62000001,0x62000001,0x62000001,0xE80000,0x2D40000,0xC80000,0x1100000,0x1500000,0x1A80000,0x1E80000,0x2DF80000,0x4F80000,0x1280000,0x1A80000,0x62000001,0x1A80000,0x11C0000,0x3A40000,0x57FC0000,0x8C000001,0x3A40000,0x57FC0000,0x8C000001,0x57FC0000,0x8C000001,0x8C000001,0x3A40000,0x57FC0000,0x8C000001,0x57FC0000,0x8C000001,
-0x8C000001,0x57FC0000,0x8C000001,0x8C000001,0x8C000001,0x3A40000,0x57FC0000,0x8C000001,0x57FC0000,0x8C000001,0x8C000001,0x57FC0000,0x8C000001,0x8C000001,0x8C000001,0x57FC0000,0x8C000001,0x8C000001,0x8C000001,0x8C000001,0x1640000,0xF2C0000,0xF2C0000,0x1DC0000,0x41FC0000,0x71FC0000,0x8C000001,0x8C000001,0x3800000,0xFFC0000,0x87E00000,0x8C000001,
-0x2BFC0000,0xA41EA8,0xFE800CD5,0xB47C0BE8,0x8C7C0BE9,0xFE5C073E,0xC25803A1,0x92640531,0x9E5406E6,0x8A5403AE,0x785406E6,0xFE300BF8,0xC82C028A,0x94440411,0xA628038E,0x8C2C000E,0x7A3403AE,0x8C2C0BE8,0x801C0413,0x72240533,0x642C0BEB,0xF41EA8,0xC6000C43,0x8C300BE9,0xA8000866,0x8C00039E,0x780806E6,0x92000EA7,0x800004F3,0x70000563,0x64000C64,0x1F01EA8,
-0x72001164,0x66000EB4,0x5C00131B,0x50001EAC,0xFE780D71,0xF498186E,0xF8A019DD,0xFE440206,0xDA2C0011,0xAA2C0006,0x90340046,0x88240046,0xFE540C9B,0xFE240136,0x9218029D,0x70000563,0x15C1EA8,0xCC0BE8,0xFEA40291,0xAAA40288,0x8CA40289,0xEC800372,0xB0800005,0x8E880042,0x94800372,0x867800A5,0x78800372,0x1300BE8,0xC4340289,0x8E680289,0xAE140372,0x8C34000A,
-0x78480372,0x1DF40BE8,0x8400033B,0x72000463,0x64000BEB,0x1300BE8,0xC4340289,0x8E680289,0xAE140372,0x8C34000A,0x78480372,0x1DF40BE8,0x8400033B,0x72000463,0x64000BEB,0x1DF40BE8,0x8400033B,0x72000463,0x64000BEB,0x64000BEB,0xFE94057B,0xF8C00934,0xFAC4090C,0xFE5400EA,0xDA30000D,0xA8300006,0x8E480001,0x8A100022,0xFE780595,0xFE300095,0x96080288,0x72000463,
-0x1B00BE8,0x7C0BE8,0x7C0BE8,0x7C0BE8,0x7C0BE8,0xD6580374,0xD6580374,0xD6580374,0x7E580374,0x7E580374,0x62540375,0xCC2C0288,0xCC2C0288,0xCC2C0288,0x8A300009,0x8A300009,0x663800A6,0x6E2C0288,0x6E2C0288,0x5E280041,0x502C028A,0xB80BE8,0xB80BE8,0xB80BE8,0x8C00039D,0x8C00039D,0x62200373,0x7400039A,0x7400039A,0x5E00006A,0x500002A3,0x1740BE8,
-0x1740BE8,0x500005CD,0x4A0005FA,0x3C000BEB,0xFE5804B9,0xFE6C08A5,0x7C0BE8,0xFE3C00A8,0xD82C0005,0xAA2C0005,0x98340021,0x7E2C0002,0xFE3C0428,0xFE180062,0x8C1C028A,0x5E00006A,0x1080BE8,0xA40288,0xA40288,0xA40288,0xA40288,0xAC800000,0xAC800000,0xAC800000,0x74800000,0x74800000,0x62800001,0xF40288,0xF40288,0xF40288,0x82400001,0x82400001,
-0x645C0001,0x1F00288,0x1F00288,0x6000000A,0x5000028A,0xF40288,0xF40288,0xF40288,0x82400001,0x82400001,0x645C0001,0x1F00288,0x1F00288,0x6000000A,0x5000028A,0x1F00288,0x1F00288,0x6000000A,0x5000028A,0x5000028A,0xF68000DD,0xF4980139,0xA40288,0xF8500029,0xCC380000,0xA2380000,0x8E480000,0x80280000,0xF2600109,0xFE240014,0x15C0288,0x6000000A,
-0x15C0288,0xF00374,0xE2C80000,0xA2C80000,0x8CC80001,0x1680372,0xB27C0001,0x8CA00001,0x39F80372,0x8C200001,0x78000372,0x1680372,0xB27C0001,0x8CA00001,0x39F80372,0x8C200001,0x78000372,0x39F80372,0x8C200001,0x78000372,0x78000372,0x1680372,0xB27C0001,0x8CA00001,0x39F80372,0x8C200001,0x78000372,0x39F80372,0x8C200001,0x78000372,0x78000372,0x39F80372,
-0x8C200001,0x78000372,0x78000372,0x78000372,0xFEB401ED,0x9000372,0xFCE80221,0xFE6C0055,0xE4180001,0xAC240000,0x8C500001,0x8A00000D,0xFE9801D4,0xFE400032,0x94580000,0x78000372,0x3FC0372,0x540374,0x540374,0x540374,0x540374,0x540374,0x540374,0x540374,0x540374,0x540374,0x540374,0x942C0000,0x942C0000,0x942C0000,0x942C0000,0x942C0000,
-0x942C0000,0x542C0000,0x542C0000,0x542C0000,0x3E2C0001,0x800372,0x800372,0x800372,0x800372,0x800372,0x800372,0x58000041,0x58000041,0x58000041,0x3E040001,0x1000372,0x1000372,0x1000372,0x38000131,0x2A000372,0xFC480188,0x540374,0x540374,0xFA340034,0xE22C0000,0xB22C0000,0xB22C0000,0x7C2C0000,0xFE200115,0xFE140019,0x6A200000,0x58000041,
-0xB40372,};
-static const uint32_t g_etc1_to_bc7_m6_table139[] = {
-0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0x580000,0xB00000,
-0xB00000,0xB00000,0xB00000,0x1C000001,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x3C0000,0x400000,0x400000,0x400000,0x580000,0x7C0000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,
-0xD40000,0x1B00000,0x1B00000,0x1B00000,0x46000001,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0x1B00000,0x1B00000,0x1B00000,0x46000001,0x1B00000,0x1B00000,0x1B00000,0x46000001,0x46000001,0x4980000,0x900000,0x900000,0xA80000,0xB40000,0xC40000,0xC40000,0xF00000,0xA80000,0xB40000,0x1300000,0x1B00000,
-0x1300000,0xD80000,0xD80000,0xD80000,0xD80000,0x1400000,0x1400000,0x1400000,0x25F80000,0x25F80000,0x6A000001,0x1400000,0x1400000,0x1400000,0x25F80000,0x25F80000,0x6A000001,0x25F80000,0x25F80000,0x6A000001,0x6A000001,0x1400000,0x1400000,0x1400000,0x25F80000,0x25F80000,0x6A000001,0x25F80000,0x25F80000,0x6A000001,0x6A000001,0x25F80000,
-0x25F80000,0x6A000001,0x6A000001,0x6A000001,0xFC0000,0xAE40000,0xD80000,0x3240000,0x16C0000,0x1CC0000,0x9F80000,0x37FC0000,0x50C0000,0x1400000,0x1CC0000,0x6A000001,0x1CC0000,0x12C0000,0x3BC0000,0x63FC0000,0x94000001,0x3BC0000,0x63FC0000,0x94000001,0x63FC0000,0x94000001,0x94000001,0x3BC0000,0x63FC0000,0x94000001,0x63FC0000,0x94000001,
-0x94000001,0x63FC0000,0x94000001,0x94000001,0x94000001,0x3BC0000,0x63FC0000,0x94000001,0x63FC0000,0x94000001,0x94000001,0x63FC0000,0x94000001,0x94000001,0x94000001,0x63FC0000,0x94000001,0x94000001,0x94000001,0x94000001,0x1780000,0x1400000,0x1400000,0x1F80000,0x4FFC0000,0x7BFC0000,0x94000001,0x94000001,0x1980000,0x21FC0000,0x8FF00000,0x94000001,
-0x3BFC0000,0xB41EA8,0xFE980D35,0xBC8C0BE8,0x948C0BE9,0xFE74078E,0xCA6803A1,0x9A740531,0xA66406E6,0x926403AE,0x806406E6,0xFE440C13,0xD03C028A,0x9C540411,0xAE38038E,0x943C000E,0x824403AE,0x943C0BE8,0x882C0413,0x7A340533,0x6C3C0BEB,0x10C1EA8,0xD8000BFB,0x94400BE9,0xBA0007BE,0x9608038E,0x801806E6,0x9E000DE7,0x8C00040B,0x7A000497,0x6C000C0F,0xBF81EA8,
-0x7800109C,0x72000DB4,0x6600126C,0x58001EAC,0xFE8C0E18,0xFCA8186E,0xFEAC19E1,0xFE5C0296,0xE23C0011,0xB23C0006,0x98440046,0x90340046,0xFE700D55,0xFE3401B7,0x9A28029D,0x7A000497,0x17C1EA8,0xDC0BE8,0xFCB802A9,0xB2B40288,0x94B40289,0xF4900372,0xB8900005,0x96980042,0x9C900372,0x8E8800A5,0x80900372,0x3440BE8,0xCC440289,0x96780289,0xB6240372,0x9444000A,
-0x80580372,0x27FC0BE8,0x8E000301,0x7C000422,0x6C000BEB,0x3440BE8,0xCC440289,0x96780289,0xB6240372,0x9444000A,0x80580372,0x27FC0BE8,0x8E000301,0x7C000422,0x6C000BEB,0x27FC0BE8,0x8E000301,0x7C000422,0x6C000BEB,0x6C000BEB,0xFCB005BD,0xFECC0938,0xFECC094C,0xFE6C0129,0xE240000D,0xB0400006,0x96580001,0x92200022,0xFE8805E8,0xFE4800B9,0x9E180288,0x7C000422,
-0x1D40BE8,0x8C0BE8,0x8C0BE8,0x8C0BE8,0x8C0BE8,0xDE680374,0xDE680374,0xDE680374,0x86680374,0x86680374,0x6A640375,0xD43C0288,0xD43C0288,0xD43C0288,0x92400009,0x92400009,0x6E4800A6,0x763C0288,0x763C0288,0x66380041,0x583C028A,0xD00BE8,0xD00BE8,0xD00BE8,0x9E000375,0x9E000375,0x6A300373,0x8000032A,0x8000032A,0x6800001A,0x5A00028A,0x1A40BE8,
-0x1A40BE8,0x5C000545,0x5000056A,0x44000BEB,0xFE6804EE,0xFA8408B8,0x8C0BE8,0xFE4C00D9,0xE03C0005,0xB23C0005,0xA0440021,0x863C0002,0xFE500455,0xFE300081,0x942C028A,0x6800001A,0x1280BE8,0xB40288,0xB40288,0xB40288,0xB40288,0xB4900000,0xB4900000,0xB4900000,0x7C900000,0x7C900000,0x6A900001,0x10C0288,0x10C0288,0x10C0288,0x8A500001,0x8A500001,
-0x6C6C0001,0xBF80288,0xBF80288,0x6A000001,0x5800028A,0x10C0288,0x10C0288,0x10C0288,0x8A500001,0x8A500001,0x6C6C0001,0xBF80288,0xBF80288,0x6A000001,0x5800028A,0xBF80288,0xBF80288,0x6A000001,0x5800028A,0x5800028A,0xFE9000DD,0xFCA80139,0xB40288,0xFE5C002D,0xD4480000,0xAA480000,0x96580000,0x88380000,0xFA700109,0xFA400020,0x17C0288,0x6A000001,
-0x17C0288,0x1000374,0xEAD80000,0xAAD80000,0x94D80001,0x1800372,0xBA8C0001,0x94B00001,0x45F80372,0x94300001,0x80000372,0x1800372,0xBA8C0001,0x94B00001,0x45F80372,0x94300001,0x80000372,0x45F80372,0x94300001,0x80000372,0x80000372,0x1800372,0xBA8C0001,0x94B00001,0x45F80372,0x94300001,0x80000372,0x45F80372,0x94300001,0x80000372,0x80000372,0x45F80372,
-0x94300001,0x80000372,0x80000372,0x80000372,0xFCCC0202,0x1140372,0xF4F80244,0xFE800071,0xEC280001,0xB4340000,0x94600001,0x94000002,0xFEAC01F9,0xFE58004A,0x9C680000,0x80000372,0x13FC0372,0x640374,0x640374,0x640374,0x640374,0x640374,0x640374,0x640374,0x640374,0x640374,0x640374,0x9C3C0000,0x9C3C0000,0x9C3C0000,0x9C3C0000,0x9C3C0000,
-0x9C3C0000,0x5C3C0000,0x5C3C0000,0x5C3C0000,0x463C0001,0x980372,0x980372,0x980372,0x980372,0x980372,0x980372,0x68000011,0x68000011,0x68000011,0x46140001,0x1300372,0x1300372,0x1300372,0x3E0000E1,0x32000372,0xF45801A5,0x640374,0x640374,0xFC48003D,0xEA3C0000,0xBA3C0000,0xBA3C0000,0x843C0000,0xFC380120,0xF8280029,0x72300000,0x68000011,
-0xD80372,};
-static const uint32_t g_etc1_to_bc7_m6_table140[] = {
-0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0xE80000,
-0xE80000,0xE80000,0xE80000,0x26000000,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x540000,0x540000,0x540000,0x740000,0xA40000,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xA00001,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,
-0xF00000,0x1E80000,0x1E80000,0x1E80000,0x50000000,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,0xF00000,0x1E80000,0x1E80000,0x1E80000,0x50000000,0x1E80000,0x1E80000,0x1E80000,0x50000000,0x50000000,0xAC0000,0xA00001,0xA00001,0xBC0000,0xCC0000,0xDC0000,0xDC0000,0x1100000,0xBC0000,0xCC0000,0x1580000,0x1E80000,
-0x1580000,0xE80001,0xE80001,0xE80001,0xE80001,0x15C0000,0x15C0000,0x15C0000,0x33F80000,0x33F80000,0x74000000,0x15C0000,0x15C0000,0x15C0000,0x33F80000,0x33F80000,0x74000000,0x33F80000,0x33F80000,0x74000000,0x74000000,0x15C0000,0x15C0000,0x15C0000,0x33F80000,0x33F80000,0x74000000,0x33F80000,0x33F80000,0x74000000,0x74000000,0x33F80000,
-0x33F80000,0x74000000,0x74000000,0x74000000,0x1100000,0x4F80000,0xE80001,0x33C0000,0x1880000,0x1F00000,0x17FC0000,0x43FC0000,0x1240000,0x15C0000,0x1F00000,0x74000000,0x1F00000,0x13C0001,0x1D80000,0x71F80000,0x9E000000,0x1D80000,0x71F80000,0x9E000000,0x71F80000,0x9E000000,0x9E000000,0x1D80000,0x71F80000,0x9E000000,0x71F80000,0x9E000000,
-0x9E000000,0x71F80000,0x9E000000,0x9E000000,0x9E000000,0x1D80000,0x71F80000,0x9E000000,0x71F80000,0x9E000000,0x9E000000,0x71F80000,0x9E000000,0x9E000000,0x9E000000,0x71F80000,0x9E000000,0x9E000000,0x9E000000,0x9E000000,0x58C0000,0x1540000,0x1540000,0x13FC0000,0x5FF80000,0x87F80000,0x9E000000,0x9E000000,0x1B00000,0x33FC0000,0x99E40000,0x9E000000,
-0x4BFC0000,0xC41EAC,0xFEA40D93,0xC4A00BEB,0x9E9C0BEB,0xFE8407F4,0xD47C03A3,0xA2840533,0xAE7806E6,0x9A7403AE,0x887806E6,0xFE5C0C49,0xDA50028A,0xA6680413,0xB84C038E,0x9E4C000E,0x8A5403AE,0x9C500BE9,0x92400411,0x82440531,0x764C0BE9,0x3241EA8,0xE8080BE9,0x9E500BE8,0xC6000736,0xA01C038E,0x882C06E6,0xAE000D2F,0x98000345,0x840003FD,0x76000BE8,0x17FC1EA8,
-0x84000FB8,0x78000C98,0x6C001198,0x62001EA8,0xFEA00EBE,0xF6BC18F4,0xF8C01A44,0xFE70034E,0xF04C000E,0xBC500006,0xA2580046,0x9A480046,0xFE800E11,0xFE500235,0xA438029D,0x840003FD,0x1A41EA8,0xEC0BEB,0xFEC802CA,0xBCC4028A,0x9EC4028A,0xFCA40373,0xC4A00002,0xA0AC0041,0xA4A40373,0x989C00A6,0x88A00375,0x1600BE8,0xD4580289,0x9E8C0288,0xBE380372,0x9C540009,
-0x886C0374,0x35FC0BE8,0x9A0002CA,0x840003E4,0x76000BE8,0x1600BE8,0xD4580289,0x9E8C0288,0xBE380372,0x9C540009,0x886C0374,0x35FC0BE8,0x9A0002CA,0x840003E4,0x76000BE8,0x35FC0BE8,0x9A0002CA,0x840003E4,0x76000BE8,0x76000BE8,0xFEBC0611,0xF8E00975,0xFCE8094E,0xFE800189,0xEA54000D,0xBA540005,0x9E680002,0x9A380021,0xFEA40632,0xFE5C0116,0xA62C0289,0x840003E4,
-0x1F80BE8,0x9C0BEB,0x9C0BEB,0x9C0BEB,0x9C0BEB,0xE8780372,0xE8780372,0xE8780372,0x90780372,0x90780372,0x74780372,0xDA500289,0xDA500289,0xDA500289,0x9A50000A,0x9A50000A,0x785C00A5,0x804C0289,0x804C0289,0x704C0042,0x624C0289,0x2E80BE8,0x2E80BE8,0x2E80BE8,0xAA0C0372,0xAA0C0372,0x74400372,0x8C0002D9,0x8C0002D9,0x74000005,0x62140288,0x1DC0BE8,
-0x1DC0BE8,0x660004D8,0x5C0004E1,0x4E000BE8,0xFE840522,0xF49808F6,0x9C0BEB,0xFE680122,0xE6500006,0xB8500005,0xA8540022,0x904C0001,0xFE6404B5,0xFE4400B9,0x9E3C0289,0x74000005,0x1500BE8,0xC4028A,0xC4028A,0xC4028A,0xC4028A,0xBCA40001,0xBCA40001,0xBCA40001,0x86A00001,0x86A00001,0x74A00001,0x3240288,0x3240288,0x3240288,0x94600001,0x94600001,
-0x74800000,0x17FC0288,0x17FC0288,0x740C0000,0x62000288,0x3240288,0x3240288,0x3240288,0x94600001,0x94600001,0x74800000,0x17FC0288,0x17FC0288,0x740C0000,0x62000288,0x17FC0288,0x17FC0288,0x740C0000,0x62000288,0x62000288,0xFEA000F4,0xF6BC0152,0xC4028A,0xFE78003D,0xD8600001,0xB25C0000,0xA0680000,0x904C0000,0xF8880120,0xFC580029,0x1A40288,0x740C0000,
-0x1A40288,0x1140372,0xF2EC0001,0xB2EC0001,0x9EE80001,0x3980372,0xC49C0001,0x9EC00000,0x51FC0372,0x9E3C0000,0x88000374,0x3980372,0xC49C0001,0x9EC00000,0x51FC0372,0x9E3C0000,0x88000374,0x51FC0372,0x9E3C0000,0x88000374,0x88000374,0x3980372,0xC49C0001,0x9EC00000,0x51FC0372,0x9E3C0000,0x88000374,0x51FC0372,0x9E3C0000,0x88000374,0x88000374,0x51FC0372,
-0x9E3C0000,0x88000374,0x88000374,0x88000374,0xF6E80221,0xB240372,0xFF0C0242,0xFE9C0091,0xF43C0001,0xBE440000,0x9E700000,0x9E000000,0xF8D00200,0xFA7C0071,0xA47C0000,0x88000374,0x23FC0372,0x780372,0x780372,0x780372,0x780372,0x780372,0x780372,0x780372,0x780372,0x780372,0x780372,0xA4500001,0xA4500001,0xA4500001,0xA4500001,0xA4500001,
-0xA4500001,0x64500001,0x64500001,0x64500001,0x504C0001,0x2B00372,0x2B00372,0x2B00372,0x2B00372,0x2B00372,0x2B00372,0x76000001,0x76000001,0x76000001,0x50240000,0x1680372,0x1680372,0x1680372,0x4A00009D,0x3A000374,0xFE6C01A5,0x780372,0x780372,0xFE58004A,0xF0500001,0xC0500001,0xC0500001,0x8C500001,0xF84C0139,0xFE3C0032,0x78440001,0x76000001,
-0xFC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table141[] = {
-0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x8C0000,0x1180000,
-0x1180000,0x1180000,0x1180000,0x2E000000,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x640000,0x640000,0x640000,0x8C0000,0xC80000,0xB00001,0xB00001,0xB00001,0xB00001,0xB00001,0xB00001,0xB00001,0xB00001,0xB00001,0xB00001,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,
-0x1080000,0x9F80000,0x9F80000,0x9F80000,0x58000000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x9F80000,0x9F80000,0x9F80000,0x58000000,0x9F80000,0x9F80000,0x9F80000,0x58000000,0x58000000,0x6BC0000,0xB00001,0xB00001,0x6CC0000,0xE00000,0x2F00000,0x2F00000,0x12C0000,0x6CC0000,0xE00000,0x1780000,0x9F80000,
-0x1780000,0xF80001,0xF80001,0xF80001,0xF80001,0x1740000,0x1740000,0x1740000,0x3FF80000,0x3FF80000,0x7C000000,0x1740000,0x1740000,0x1740000,0x3FF80000,0x3FF80000,0x7C000000,0x3FF80000,0x3FF80000,0x7C000000,0x7C000000,0x1740000,0x1740000,0x1740000,0x3FF80000,0x3FF80000,0x7C000000,0x3FF80000,0x3FF80000,0x7C000000,0x7C000000,0x3FF80000,
-0x3FF80000,0x7C000000,0x7C000000,0x7C000000,0x7200000,0xD080000,0xF80001,0x1540000,0x1A40000,0xBFC0000,0x25FC0000,0x4FF80000,0x1380000,0x1740000,0xBFC0000,0x7C000000,0xBFC0000,0x14C0001,0x1F00000,0x7DF80000,0xA6000000,0x1F00000,0x7DF80000,0xA6000000,0x7DF80000,0xA6000000,0xA6000000,0x1F00000,0x7DF80000,0xA6000000,0x7DF80000,0xA6000000,
-0xA6000000,0x7DF80000,0xA6000000,0xA6000000,0xA6000000,0x1F00000,0x7DF80000,0xA6000000,0x7DF80000,0xA6000000,0xA6000000,0x7DF80000,0xA6000000,0xA6000000,0xA6000000,0x7DF80000,0xA6000000,0xA6000000,0xA6000000,0xA6000000,0x5A00000,0x1640000,0x1640000,0x27FC0000,0x6BFC0000,0x91F80000,0xA6000000,0xA6000000,0x3C40000,0x45FC0000,0xA1F40000,0xA6000000,
-0x5BFC0000,0xD41EAC,0xFEBC0E0B,0xCCB00BEB,0xA6AC0BEB,0xFE980856,0xDC8C03A3,0xAA940533,0xB68806E6,0xA28403AE,0x908806E6,0xFE740C91,0xE260028A,0xAE780413,0xC05C038E,0xA65C000E,0x926403AE,0xA4600BE9,0x9A500411,0x8A540531,0x7E5C0BE9,0x33C1EA8,0xF0180BE9,0xA6600BE8,0xD80006F6,0xA82C038E,0x903C06E6,0xBA000CAF,0xA20002CE,0x8E0003B5,0x7E100BE8,0x23FC1EA8,
-0x90000EF8,0x84000BA8,0x780010D8,0x6A001EA8,0xFEB40F7B,0xFECC18F4,0xFECC1A5C,0xFE8003FA,0xF85C000E,0xC4600006,0xAA680046,0xA2580046,0xFE900EA5,0xFE6002FA,0xAC48029D,0x8E0003B5,0x1C81EA8,0xFC0BEB,0xFEDC02EB,0xC4D4028A,0xA6D4028A,0xFEB4037B,0xCCB00002,0xA8BC0041,0xACB40373,0xA0AC00A6,0x90B00375,0x1780BE8,0xDC680289,0xA69C0288,0xC6480372,0xA4640009,
-0x907C0374,0x41FC0BE8,0xA20002AA,0x900003B4,0x7E000BE8,0x1780BE8,0xDC680289,0xA69C0288,0xC6480372,0xA4640009,0x907C0374,0x41FC0BE8,0xA20002AA,0x900003B4,0x7E000BE8,0x41FC0BE8,0xA20002AA,0x900003B4,0x7E000BE8,0x7E000BE8,0xFED00640,0xFEEC098D,0xF4F80993,0xFE9801D5,0xF264000D,0xC2640005,0xA6780002,0xA2480021,0xFEB40682,0xFC80016E,0xAE3C0289,0x900003B4,
-0xFFC0BE8,0xAC0BEB,0xAC0BEB,0xAC0BEB,0xAC0BEB,0xF0880372,0xF0880372,0xF0880372,0x98880372,0x98880372,0x7C880372,0xE2600289,0xE2600289,0xE2600289,0xA260000A,0xA260000A,0x806C00A5,0x885C0289,0x885C0289,0x785C0042,0x6A5C0289,0x3000BE8,0x3000BE8,0x3000BE8,0xB21C0372,0xB21C0372,0x7C500372,0x9E0002A1,0x9E0002A1,0x7C100005,0x6A240288,0x5FC0BE8,
-0x5FC0BE8,0x72000478,0x64000489,0x56000BE8,0xFE90056E,0xFCA808F6,0xAC0BEB,0xFE780156,0xEE600006,0xC0600005,0xB0640022,0x985C0001,0xFE7804E6,0xFE5C00F5,0xA64C0289,0x7C100005,0x1700BE8,0xD4028A,0xD4028A,0xD4028A,0xD4028A,0xC4B40001,0xC4B40001,0xC4B40001,0x8EB00001,0x8EB00001,0x7CB00001,0x33C0288,0x33C0288,0x33C0288,0x9C700001,0x9C700001,
-0x7C900000,0x23FC0288,0x23FC0288,0x7C1C0000,0x6A000288,0x33C0288,0x33C0288,0x33C0288,0x9C700001,0x9C700001,0x7C900000,0x23FC0288,0x23FC0288,0x7C1C0000,0x6A000288,0x23FC0288,0x23FC0288,0x7C1C0000,0x6A000288,0x6A000288,0xFAB40109,0xFECC0152,0xD4028A,0xFE88004A,0xE0700001,0xBA6C0000,0xA8780000,0x985C0000,0xFE940128,0xFE680034,0x1C80288,0x7C1C0000,
-0x1C80288,0x1240372,0xFAFC0001,0xBAFC0001,0xA6F80001,0x3B00372,0xCCAC0001,0xA6D00000,0x5DFC0372,0xA64C0000,0x90000374,0x3B00372,0xCCAC0001,0xA6D00000,0x5DFC0372,0xA64C0000,0x90000374,0x5DFC0372,0xA64C0000,0x90000374,0x90000374,0x3B00372,0xCCAC0001,0xA6D00000,0x5DFC0372,0xA64C0000,0x90000374,0x5DFC0372,0xA64C0000,0x90000374,0x90000374,0x5DFC0372,
-0xA64C0000,0x90000374,0x90000374,0x90000374,0xFEF80221,0x1380372,0xF71C0265,0xFEB000AA,0xFC4C0001,0xC6540000,0xA6800000,0xA6100000,0xFEDC0208,0xFE940080,0xAC8C0000,0x90000374,0x33FC0372,0x880372,0x880372,0x880372,0x880372,0x880372,0x880372,0x880372,0x880372,0x880372,0x880372,0xAC600001,0xAC600001,0xAC600001,0xAC600001,0xAC600001,
-0xAC600001,0x6C600001,0x6C600001,0x6C600001,0x585C0001,0xC80372,0xC80372,0xC80372,0xC80372,0xC80372,0xC80372,0x7E100001,0x7E100001,0x7E100001,0x58340000,0x1980372,0x1980372,0x1980372,0x50000071,0x42000374,0xF67C01C2,0x880372,0x880372,0xFE680059,0xF8600001,0xC8600001,0xC8600001,0x94600001,0xFE580145,0xFE50003D,0x80540001,0x7E100001,
-0x1200372,};
-static const uint32_t g_etc1_to_bc7_m6_table142[] = {
-0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0x14C0000,
-0x14C0000,0x14C0000,0x14C0000,0x36000000,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0x2740000,0x2740000,0x2740000,0xA40000,0xE80000,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0xC00001,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,
-0x1200000,0x15F80000,0x15F80000,0x15F80000,0x60000000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x1200000,0x15F80000,0x15F80000,0x15F80000,0x60000000,0x15F80000,0x15F80000,0x15F80000,0x60000000,0x60000000,0xECC0000,0xC00001,0xC00001,0x2E00000,0xF40000,0x1080000,0x1080000,0x1440000,0x2E00000,0xF40000,0x19C0000,0x15F80000,
-0x19C0000,0x1080001,0x1080001,0x1080001,0x1080001,0x18C0000,0x18C0000,0x18C0000,0x4BF80000,0x4BF80000,0x84000000,0x18C0000,0x18C0000,0x18C0000,0x4BF80000,0x4BF80000,0x84000000,0x4BF80000,0x4BF80000,0x84000000,0x84000000,0x18C0000,0x18C0000,0x18C0000,0x4BF80000,0x4BF80000,0x84000000,0x4BF80000,0x4BF80000,0x84000000,0x84000000,0x4BF80000,
-0x4BF80000,0x84000000,0x84000000,0x84000000,0x3340000,0x11C0000,0x1080001,0x3680000,0x1C00000,0x1BFC0000,0x33F80000,0x59FC0000,0x34C0000,0x18C0000,0x1BFC0000,0x84000000,0x1BFC0000,0x15C0001,0xDFC0000,0x89F80000,0xAE000000,0xDFC0000,0x89F80000,0xAE000000,0x89F80000,0xAE000000,0xAE000000,0xDFC0000,0x89F80000,0xAE000000,0x89F80000,0xAE000000,
-0xAE000000,0x89F80000,0xAE000000,0xAE000000,0xAE000000,0xDFC0000,0x89F80000,0xAE000000,0x89F80000,0xAE000000,0xAE000000,0x89F80000,0xAE000000,0xAE000000,0xAE000000,0x89F80000,0xAE000000,0xAE000000,0xAE000000,0xAE000000,0x5B40000,0x3740000,0x3740000,0x3BFC0000,0x79FC0000,0x9BF80000,0xAE000000,0xAE000000,0x1DC0000,0x55FC0000,0xABC80000,0xAE000000,
-0x69FC0000,0xE41EAC,0xFEC80E73,0xD4C00BEB,0xAEBC0BEB,0xFEA808EC,0xE49C03A3,0xB2A40533,0xBE9806E6,0xAA9403AE,0x989806E6,0xFE840CF4,0xEA70028A,0xB6880413,0xC86C038E,0xAE6C000E,0x9A7403AE,0xAC700BE9,0xA2600411,0x92640531,0x866C0BE9,0x1541EA8,0xF8280BE9,0xAE700BE8,0xE20406E6,0xB03C038E,0x984C06E6,0xC6000C4F,0xAC000292,0x980403A1,0x86200BE8,0x2FFC1EA8,
-0x9C000E58,0x8A000AE8,0x7E00102C,0x72001EA8,0xFEBC1022,0xF6DC197E,0xF8E01AAF,0xFE9804BE,0xFA70000F,0xCC700006,0xB2780046,0xAA680046,0xFEA40F96,0xFE7403B7,0xB458029D,0x980403A1,0x1E81EA8,0x10C0BEB,0xFEEC032A,0xCCE4028A,0xAEE4028A,0xFEC8038D,0xD4C00002,0xB0CC0041,0xB4C40373,0xA8BC00A6,0x98C00375,0x1900BE8,0xE4780289,0xAEAC0288,0xCE580372,0xAC740009,
-0x988C0374,0x4DFC0BE8,0xAC00028E,0x96000394,0x86000BE8,0x1900BE8,0xE4780289,0xAEAC0288,0xCE580372,0xAC740009,0x988C0374,0x4DFC0BE8,0xAC00028E,0x96000394,0x86000BE8,0x4DFC0BE8,0xAC00028E,0x96000394,0x86000BE8,0x86000BE8,0xFEE406A5,0xFB0409B3,0xFD080993,0xFEB0022E,0xFA74000D,0xCA740005,0xAE880002,0xAA580021,0xFAD406D1,0xFE9001B2,0xB64C0289,0x96000394,
-0x1FF80BE8,0xBC0BEB,0xBC0BEB,0xBC0BEB,0xBC0BEB,0xF8980372,0xF8980372,0xF8980372,0xA0980372,0xA0980372,0x84980372,0xEA700289,0xEA700289,0xEA700289,0xAA70000A,0xAA70000A,0x887C00A5,0x906C0289,0x906C0289,0x806C0042,0x726C0289,0x3180BE8,0x3180BE8,0x3180BE8,0xBA2C0372,0xBA2C0372,0x84600372,0xAA000289,0xAA000289,0x84200005,0x72340288,0x11FC0BE8,
-0x11FC0BE8,0x7C000432,0x6C000414,0x5E000BE8,0xFEA005A5,0xF4B80933,0xBC0BEB,0xFE880193,0xF6700006,0xC8700005,0xB8740022,0xA06C0001,0xFC8C0549,0xFE680138,0xAE5C0289,0x84200005,0x1940BE8,0xE4028A,0xE4028A,0xE4028A,0xE4028A,0xCCC40001,0xCCC40001,0xCCC40001,0x96C00001,0x96C00001,0x84C00001,0x1540288,0x1540288,0x1540288,0xA4800001,0xA4800001,
-0x84A00000,0x2FFC0288,0x2FFC0288,0x842C0000,0x72000288,0x1540288,0x1540288,0x1540288,0xA4800001,0xA4800001,0x84A00000,0x2FFC0288,0x2FFC0288,0x842C0000,0x72000288,0x2FFC0288,0x2FFC0288,0x842C0000,0x72000288,0x72000288,0xF6C80120,0xF6DC016D,0xE4028A,0xFE980061,0xE8800001,0xC27C0000,0xB0880000,0xA06C0000,0xFAAC0139,0xFE800048,0x1E80288,0x842C0000,
-0x1E80288,0x1340372,0xFF0C0002,0xC30C0001,0xAF080001,0x1C80372,0xD4BC0001,0xAEE00000,0x69FC0372,0xAE5C0000,0x98000374,0x1C80372,0xD4BC0001,0xAEE00000,0x69FC0372,0xAE5C0000,0x98000374,0x69FC0372,0xAE5C0000,0x98000374,0x98000374,0x1C80372,0xD4BC0001,0xAEE00000,0x69FC0372,0xAE5C0000,0x98000374,0x69FC0372,0xAE5C0000,0x98000374,0x98000374,0x69FC0372,
-0xAE5C0000,0x98000374,0x98000374,0x98000374,0xFB0C0242,0x1480372,0xFF2C0265,0xFEC800D0,0xFE680005,0xCE640000,0xAE900000,0xAE200000,0xFEF0022D,0xFEAC00A4,0xB49C0000,0x98000374,0x41FC0372,0x980372,0x980372,0x980372,0x980372,0x980372,0x980372,0x980372,0x980372,0x980372,0x980372,0xB4700001,0xB4700001,0xB4700001,0xB4700001,0xB4700001,
-0xB4700001,0x74700001,0x74700001,0x74700001,0x606C0001,0xE00372,0xE00372,0xE00372,0xE00372,0xE00372,0xE00372,0x86200001,0x86200001,0x86200001,0x60440000,0x1CC0372,0x1CC0372,0x1CC0372,0x5C000041,0x4A000374,0xFE8C01C2,0x980372,0x980372,0xFA7C0071,0xFA700002,0xD0700001,0xD0700001,0x9C700001,0xFC700152,0xFC600055,0x88640001,0x86200001,
-0x1400372,};
-static const uint32_t g_etc1_to_bc7_m6_table143[] = {
-0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0xBC0000,0x17C0000,
-0x17C0000,0x17C0000,0x17C0000,0x3E000000,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0xA840000,0xA840000,0xA840000,0xBC0000,0x10C0000,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,
-0x1380000,0x21F80000,0x21F80000,0x21F80000,0x68000000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x21F80000,0x21F80000,0x21F80000,0x68000000,0x21F80000,0x21F80000,0x21F80000,0x68000000,0x68000000,0xE00000,0xD00001,0xD00001,0xF40000,0x1080000,0x11C0000,0x11C0000,0x1600000,0xF40000,0x1080000,0x1BC0000,0x21F80000,
-0x1BC0000,0x1180001,0x1180001,0x1180001,0x1180001,0x1A40000,0x1A40000,0x1A40000,0x57F80000,0x57F80000,0x8C000000,0x1A40000,0x1A40000,0x1A40000,0x57F80000,0x57F80000,0x8C000000,0x57F80000,0x57F80000,0x8C000000,0x8C000000,0x1A40000,0x1A40000,0x1A40000,0x57F80000,0x57F80000,0x8C000000,0x57F80000,0x57F80000,0x8C000000,0x8C000000,0x57F80000,
-0x57F80000,0x8C000000,0x8C000000,0x8C000000,0x1480000,0x12C0000,0x1180001,0x1800000,0x1D80000,0x29FC0000,0x3FFC0000,0x65F40000,0x3600000,0x1A40000,0x29FC0000,0x8C000000,0x29FC0000,0x16C0001,0x25FC0000,0x95F80000,0xB6000000,0x25FC0000,0x95F80000,0xB6000000,0x95F80000,0xB6000000,0xB6000000,0x25FC0000,0x95F80000,0xB6000000,0x95F80000,0xB6000000,
-0xB6000000,0x95F80000,0xB6000000,0xB6000000,0xB6000000,0x25FC0000,0x95F80000,0xB6000000,0x95F80000,0xB6000000,0xB6000000,0x95F80000,0xB6000000,0xB6000000,0xB6000000,0x95F80000,0xB6000000,0xB6000000,0xB6000000,0xB6000000,0x1CC0000,0xB840000,0xB840000,0x4FFC0000,0x87F80000,0xA5F80000,0xB6000000,0xB6000000,0x3F00000,0x67FC0000,0xB3D80000,0xB6000000,
-0x79FC0000,0xF41EAC,0xFEDC0EEC,0xDCD00BEB,0xB6CC0BEB,0xFEBC096E,0xECAC03A3,0xBAB40533,0xC6A806E6,0xB2A403AE,0xA0A806E6,0xFE980D51,0xF280028A,0xBE980413,0xD07C038E,0xB67C000E,0xA28403AE,0xB4800BE9,0xAA700411,0x9A740531,0x8E7C0BE9,0x16C1EA8,0xFE380BEF,0xB6800BE8,0xEA1406E6,0xB84C038E,0xA05C06E6,0xD2000C0F,0xB608028A,0xA01403A1,0x8E300BE8,0x3BFC1EA8,
-0xA6000DDB,0x96000A18,0x8A000F9C,0x7A001EA8,0xFED010D1,0xFEEC197E,0xFEEC1ACB,0xFEAC059E,0xFE840027,0xD4800006,0xBA880046,0xB2780046,0xFEB4101B,0xFE900462,0xBC68029D,0xA01403A1,0x7FC1EA8,0x11C0BEB,0xFF000363,0xD4F4028A,0xB6F4028A,0xFEDC03AB,0xDCD00002,0xB8DC0041,0xBCD40373,0xB0CC00A6,0xA0D00375,0x1A80BE8,0xEC880289,0xB6BC0288,0xD6680372,0xB4840009,
-0xA09C0374,0x59FC0BE8,0xB6000288,0xA000037D,0x8E000BE8,0x1A80BE8,0xEC880289,0xB6BC0288,0xD6680372,0xB4840009,0xA09C0374,0x59FC0BE8,0xB6000288,0xA000037D,0x8E000BE8,0x59FC0BE8,0xB6000288,0xA000037D,0x8E000BE8,0x8E000BE8,0xFEF806DA,0xFF0C09DB,0xF51809DA,0xFEC00296,0xFE88001A,0xD2840005,0xB6980002,0xB2680021,0xFEDC06F9,0xFEA40224,0xBE5C0289,0xA000037D,
-0x2DFC0BE8,0xCC0BEB,0xCC0BEB,0xCC0BEB,0xCC0BEB,0xFEA80373,0xFEA80373,0xFEA80373,0xA8A80372,0xA8A80372,0x8CA80372,0xF2800289,0xF2800289,0xF2800289,0xB280000A,0xB280000A,0x908C00A5,0x987C0289,0x987C0289,0x887C0042,0x7A7C0289,0x3300BE8,0x3300BE8,0x3300BE8,0xC23C0372,0xC23C0372,0x8C700372,0xB2100289,0xB2100289,0x8C300005,0x7A440288,0x1DFC0BE8,
-0x1DFC0BE8,0x840003E4,0x760003C9,0x66000BE8,0xFCB805F6,0xFCC80933,0xCC0BEB,0xFE9801DA,0xFE800006,0xD0800005,0xC0840022,0xA87C0001,0xFC9C0581,0xFE800171,0xB66C0289,0x8C300005,0x1B40BE8,0xF4028A,0xF4028A,0xF4028A,0xF4028A,0xD4D40001,0xD4D40001,0xD4D40001,0x9ED00001,0x9ED00001,0x8CD00001,0x16C0288,0x16C0288,0x16C0288,0xAC900001,0xAC900001,
-0x8CB00000,0x3BFC0288,0x3BFC0288,0x8C3C0000,0x7A000288,0x16C0288,0x16C0288,0x16C0288,0xAC900001,0xAC900001,0x8CB00000,0x3BFC0288,0x3BFC0288,0x8C3C0000,0x7A000288,0x3BFC0288,0x3BFC0288,0x8C3C0000,0x7A000288,0x7A000288,0xFED80120,0xFEEC016D,0xF4028A,0xFEB40071,0xF0900001,0xCA8C0000,0xB8980000,0xA87C0000,0xFCC00152,0xFE980055,0x7FC0288,0x8C3C0000,
-0x7FC0288,0x1440372,0xFF1C0011,0xCB1C0001,0xB7180001,0x1E00372,0xDCCC0001,0xB6F00000,0x75FC0372,0xB66C0000,0xA0000374,0x1E00372,0xDCCC0001,0xB6F00000,0x75FC0372,0xB66C0000,0xA0000374,0x75FC0372,0xB66C0000,0xA0000374,0xA0000374,0x1E00372,0xDCCC0001,0xB6F00000,0x75FC0372,0xB66C0000,0xA0000374,0x75FC0372,0xB66C0000,0xA0000374,0xA0000374,0x75FC0372,
-0xB66C0000,0xA0000374,0xA0000374,0xA0000374,0xFF140262,0x5580372,0xF73C028A,0xFCE800F2,0xFC8C0019,0xD6740000,0xB6A00000,0xB6300000,0xFD0C0242,0xFEC000C1,0xBCAC0000,0xA0000374,0x51FC0372,0xA80372,0xA80372,0xA80372,0xA80372,0xA80372,0xA80372,0xA80372,0xA80372,0xA80372,0xA80372,0xBC800001,0xBC800001,0xBC800001,0xBC800001,0xBC800001,
-0xBC800001,0x7C800001,0x7C800001,0x7C800001,0x687C0001,0xF80372,0xF80372,0xF80372,0xF80372,0xF80372,0xF80372,0x8E300001,0x8E300001,0x8E300001,0x68540000,0x1FC0372,0x1FC0372,0x1FC0372,0x66000028,0x52000374,0xF69C01E1,0xA80372,0xA80372,0xFC8C0082,0xFE800005,0xD8800001,0xD8800001,0xA4800001,0xF884016D,0xFC740062,0x90740001,0x8E300001,
-0x1640372,};
-static const uint32_t g_etc1_to_bc7_m6_table144[] = {
-0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0x1B00000,
-0x1B00000,0x1B00000,0x1B00000,0x46000001,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x4980000,0x4980000,0x4980000,0xD40000,0x1300000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0xE40000,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,
-0x3500000,0x2DFC0000,0x2DFC0000,0x2DFC0000,0x70000001,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,0x3500000,0x2DFC0000,0x2DFC0000,0x2DFC0000,0x70000001,0x2DFC0000,0x2DFC0000,0x2DFC0000,0x70000001,0x70000001,0xF40000,0xE40000,0xE40000,0x1080000,0x31C0000,0x3340000,0x3340000,0x1800000,0x1080000,0x31C0000,0x1E40000,0x2DFC0000,
-0x1E40000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x3BC0000,0x3BC0000,0x3BC0000,0x63FC0000,0x63FC0000,0x94000001,0x3BC0000,0x3BC0000,0x3BC0000,0x63FC0000,0x63FC0000,0x94000001,0x63FC0000,0x63FC0000,0x94000001,0x94000001,0x3BC0000,0x3BC0000,0x3BC0000,0x63FC0000,0x63FC0000,0x94000001,0x63FC0000,0x63FC0000,0x94000001,0x94000001,0x63FC0000,
-0x63FC0000,0x94000001,0x94000001,0x94000001,0x15C0000,0x1400000,0x12C0000,0x1980000,0x1F80000,0x3BFC0000,0x4FFC0000,0x71F80000,0x1780000,0x3BC0000,0x3BFC0000,0x94000001,0x3BFC0000,0x1800000,0x41FC0000,0xA1FC0000,0xBE000001,0x41FC0000,0xA1FC0000,0xBE000001,0xA1FC0000,0xBE000001,0xBE000001,0x41FC0000,0xA1FC0000,0xBE000001,0xA1FC0000,0xBE000001,
-0xBE000001,0xA1FC0000,0xBE000001,0xBE000001,0xBE000001,0x41FC0000,0xA1FC0000,0xBE000001,0xA1FC0000,0xBE000001,0xBE000001,0xA1FC0000,0xBE000001,0xBE000001,0xBE000001,0xA1FC0000,0xBE000001,0xBE000001,0xBE000001,0xBE000001,0x3E00000,0x5980000,0x5980000,0x65FC0000,0x95FC0000,0xB1F40000,0xBE000001,0xBE000001,0x13FC0000,0x79FC0000,0xBDCC0000,0xBE000001,
-0x89FC0000,0x1081EA8,0xFEE80F9C,0xE6E00BE8,0xBEE00BE9,0xFED00A18,0xF4BC03A1,0xC4C80531,0xD0B806E6,0xBCB803AE,0xAAB806E6,0xFEB00DDB,0xFA90028A,0xC6A80411,0xD88C038E,0xBE90000E,0xAC9803AE,0xBE900BE8,0xB2800413,0xA4880533,0x96900BEB,0x1881EA8,0xFE580C0F,0xBE940BE9,0xF22806E6,0xC05C038E,0xAA6C06E6,0xE0000BEF,0xBE18028A,0xA82403A3,0x96440BEB,0x49F81EA8,
-0xB2000D51,0xA000096E,0x90000EEC,0x82001EAC,0xFEE41196,0xF9001A08,0xFB041B18,0xFEC006A1,0xFE9C0075,0xDC900006,0xC2980046,0xBA880046,0xFED410EA,0xFEA40584,0xC47C029D,0xA82403A3,0x19FC1EA8,0x1300BE8,0xFF1003C9,0xDD080288,0xBF080289,0xFEF403E4,0xE2E40005,0xC0EC0042,0xC6E40372,0xB8DC00A5,0xAAE40372,0x1C40BE8,0xF6980289,0xC0CC0289,0xE0780372,0xBE98000A,
-0xAAAC0372,0x67F80BE8,0xBE140289,0xAA000373,0x96000BEB,0x1C40BE8,0xF6980289,0xC0CC0289,0xE0780372,0xBE98000A,0xAAAC0372,0x67F80BE8,0xBE140289,0xAA000373,0x96000BEB,0x67F80BE8,0xBE140289,0xAA000373,0x96000BEB,0x96000BEB,0xFD10074D,0xFD2809F6,0xFF2C09D9,0xFEDC0312,0xFEA4003E,0xDA940006,0xC0AC0001,0xBC740022,0xFEF80752,0xFEC00281,0xC86C0288,0xAA000373,
-0x3FF80BE8,0xE00BE8,0xE00BE8,0xE00BE8,0xE00BE8,0xFEBC037D,0xFEBC037D,0xFEBC037D,0xB0BC0374,0xB0BC0374,0x94B80375,0xFE900288,0xFE900288,0xFE900288,0xBC940009,0xBC940009,0x989C00A6,0xA0900288,0xA0900288,0x908C0041,0x8290028A,0x14C0BE8,0x14C0BE8,0x14C0BE8,0xCA500372,0xCA500372,0x94840373,0xBA240289,0xBA240289,0x96440002,0x8454028A,0x2BF80BE8,
-0x2BF80BE8,0x900003AB,0x7E000363,0x6E000BEB,0xFECC062C,0xF4D80975,0xE00BE8,0xFEAC023D,0xFE940011,0xDC900005,0xCA980021,0xB0900002,0xFEB405B5,0xFE9801C6,0xBE80028A,0x96440002,0x1DC0BE8,0x1080288,0x1080288,0x1080288,0x1080288,0xDEE40000,0xDEE40000,0xDEE40000,0xA6E40000,0xA6E40000,0x94E40001,0x1880288,0x1880288,0x1880288,0xB4A40001,0xB4A40001,
-0x96C00001,0x49F80288,0x49F80288,0x94540001,0x8200028A,0x1880288,0x1880288,0x1880288,0xB4A40001,0xB4A40001,0x96C00001,0x49F80288,0x49F80288,0x94540001,0x8200028A,0x49F80288,0x49F80288,0x94540001,0x8200028A,0x8200028A,0xFAEC0139,0xF9000188,0x1080288,0xFEC40088,0xFE9C0000,0xD49C0000,0xC0AC0000,0xB28C0000,0xFED0015A,0xFEB00071,0x19FC0288,0x94540001,
-0x19FC0288,0x1540374,0xFF300028,0xD52C0000,0xBF2C0001,0x1FC0372,0xE4E00001,0xBF040001,0x83F80372,0xBE840001,0xAA000372,0x1FC0372,0xE4E00001,0xBF040001,0x83F80372,0xBE840001,0xAA000372,0x83F80372,0xBE840001,0xAA000372,0xAA000372,0x1FC0372,0xE4E00001,0xBF040001,0x83F80372,0xBE840001,0xAA000372,0x83F80372,0xBE840001,0xAA000372,0xAA000372,0x83F80372,
-0xBE840001,0xAA000372,0xAA000372,0xAA000372,0xFF340265,0x16C0372,0xFF4C0290,0xFF000120,0xFEA8002D,0xDE880000,0xBEB40001,0xBE480001,0xFF180262,0xFEE400F4,0xC6BC0000,0xAA000372,0x61FC0372,0xB80374,0xB80374,0xB80374,0xB80374,0xB80374,0xB80374,0xB80374,0xB80374,0xB80374,0xB80374,0xC6900000,0xC6900000,0xC6900000,0xC6900000,0xC6900000,
-0xC6900000,0x86900000,0x86900000,0x86900000,0x70900001,0x1140372,0x1140372,0x1140372,0x1140372,0x1140372,0x1140372,0x96440001,0x96440001,0x96440001,0x70680001,0xFF80372,0xFF80372,0xFF80372,0x70000011,0x5C000372,0xFEAC01E5,0xB80374,0xB80374,0xFEA00091,0xFE94000D,0xE4900000,0xE4900000,0xAE900000,0xFE900179,0xFC880080,0x9C840000,0x96440001,
-0x18C0372,};
-static const uint32_t g_etc1_to_bc7_m6_table145[] = {
-0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0x1E40000,
-0x1E40000,0x1E40000,0x1E40000,0x4E000001,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xA00000,0xCA80000,0xCA80000,0xCA80000,0xEC0000,0x1540000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0x3680000,0x3680000,0x3680000,0x3680000,0x3680000,
-0x3680000,0x39FC0000,0x39FC0000,0x39FC0000,0x78000001,0x3680000,0x3680000,0x3680000,0x3680000,0x3680000,0x3680000,0x39FC0000,0x39FC0000,0x39FC0000,0x78000001,0x39FC0000,0x39FC0000,0x39FC0000,0x78000001,0x78000001,0x1040000,0xF40000,0xF40000,0x11C0000,0x3300000,0x14C0000,0x14C0000,0x1980000,0x11C0000,0x3300000,0x5FC0000,0x39FC0000,
-0x5FC0000,0x13C0000,0x13C0000,0x13C0000,0x13C0000,0x1D40000,0x1D40000,0x1D40000,0x6FFC0000,0x6FFC0000,0x9C000001,0x1D40000,0x1D40000,0x1D40000,0x6FFC0000,0x6FFC0000,0x9C000001,0x6FFC0000,0x6FFC0000,0x9C000001,0x9C000001,0x1D40000,0x1D40000,0x1D40000,0x6FFC0000,0x6FFC0000,0x9C000001,0x6FFC0000,0x6FFC0000,0x9C000001,0x9C000001,0x6FFC0000,
-0x6FFC0000,0x9C000001,0x9C000001,0x9C000001,0x1700000,0x1500000,0x13C0000,0x3AC0000,0x11FC0000,0x49FC0000,0x5DF80000,0x7BFC0000,0x18C0000,0x1D40000,0x49FC0000,0x9C000001,0x49FC0000,0x1900000,0x59FC0000,0xADFC0000,0xC6000001,0x59FC0000,0xADFC0000,0xC6000001,0xADFC0000,0xC6000001,0xC6000001,0x59FC0000,0xADFC0000,0xC6000001,0xADFC0000,0xC6000001,
-0xC6000001,0xADFC0000,0xC6000001,0xC6000001,0xC6000001,0x59FC0000,0xADFC0000,0xC6000001,0xADFC0000,0xC6000001,0xC6000001,0xADFC0000,0xC6000001,0xC6000001,0xC6000001,0xADFC0000,0xC6000001,0xC6000001,0xC6000001,0xC6000001,0x3F40000,0xDA80000,0xDA80000,0x79FC0000,0xA3FC0000,0xBBF40000,0xC6000001,0xC6000001,0x31FC0000,0x8BFC0000,0xC5DC0000,0xC6000001,
-0x99FC0000,0x1181EA8,0xFF00102C,0xEEF00BE8,0xC6F00BE9,0xFEE80AE8,0xFCCC03A1,0xCCD80531,0xD8C806E6,0xC4C803AE,0xB2C806E6,0xFEC40E58,0xFEA40292,0xCEB80411,0xE09C038E,0xC6A0000E,0xB4A803AE,0xC6A00BE8,0xBA900413,0xAC980533,0x9EA00BEB,0x1A01EA8,0xFE700C4F,0xC6A40BE9,0xFA3806E6,0xC86C038E,0xB27C06E6,0xEA0C0BE9,0xC628028A,0xB03403A3,0x9E540BEB,0x55F81EA8,
-0xBC000CF4,0xAA0008EC,0x9A000E73,0x8A001EAC,0xFEF81255,0xFF0C1A18,0xFF0C1B58,0xFED4078E,0xFEB000ED,0xE4A00006,0xCAA80046,0xC2980046,0xFEDC11C3,0xFEC00675,0xCC8C029D,0xB03403A3,0x27FC1EA8,0x1400BE8,0xFF240414,0xE5180288,0xC7180289,0xFF040432,0xEAF40005,0xC8FC0042,0xCEF40372,0xC0EC00A5,0xB2F40372,0x1DC0BE8,0xFEA80289,0xC8DC0289,0xE8880372,0xC6A8000A,
-0xB2BC0372,0x73F80BE8,0xC6240289,0xB2080372,0x9E000BEB,0x1DC0BE8,0xFEA80289,0xC8DC0289,0xE8880372,0xC6A8000A,0xB2BC0372,0x73F80BE8,0xC6240289,0xB2080372,0x9E000BEB,0x73F80BE8,0xC6240289,0xB2080372,0x9E000BEB,0x9E000BEB,0xFF20078E,0xF5380A38,0xF73C0A20,0xFEEC0395,0xFEBC007E,0xE2A40006,0xC8BC0001,0xC4840022,0xFF0807A3,0xFEDC0305,0xD07C0288,0xB2080372,
-0x4DFC0BE8,0xF00BE8,0xF00BE8,0xF00BE8,0xF00BE8,0xFED00394,0xFED00394,0xFED00394,0xB8CC0374,0xB8CC0374,0x9CC80375,0xFEA4028E,0xFEA4028E,0xFEA4028E,0xC4A40009,0xC4A40009,0xA0AC00A6,0xA8A00288,0xA8A00288,0x989C0041,0x8AA0028A,0x1640BE8,0x1640BE8,0x1640BE8,0xD2600372,0xD2600372,0x9C940373,0xC2340289,0xC2340289,0x9E540002,0x8C64028A,0x37F80BE8,
-0x37F80BE8,0x9A00038D,0x8800032A,0x76000BEB,0xFED80672,0xFCE80975,0xF00BE8,0xFEC4028C,0xFEAC0031,0xE4A00005,0xD2A80021,0xB8A00002,0xFEBC061A,0xFCAC0225,0xC690028A,0x9E540002,0x1FC0BE8,0x1180288,0x1180288,0x1180288,0x1180288,0xE6F40000,0xE6F40000,0xE6F40000,0xAEF40000,0xAEF40000,0x9CF40001,0x1A00288,0x1A00288,0x1A00288,0xBCB40001,0xBCB40001,
-0x9ED00001,0x55F80288,0x55F80288,0x9C640001,0x8A00028A,0x1A00288,0x1A00288,0x1A00288,0xBCB40001,0xBCB40001,0x9ED00001,0x55F80288,0x55F80288,0x9C640001,0x8A00028A,0x55F80288,0x55F80288,0x9C640001,0x8A00028A,0x8A00028A,0xF7000152,0xFF0C0190,0x1180288,0xFEDC0091,0xFEB00004,0xDCAC0000,0xC8BC0000,0xBA9C0000,0xF8EC016D,0xFEC40080,0x27FC0288,0x9C640001,
-0x27FC0288,0x1640374,0xFF440041,0xDD3C0000,0xC73C0001,0x19FC0372,0xECF00001,0xC7140001,0x8FF80372,0xC6940001,0xB2000372,0x19FC0372,0xECF00001,0xC7140001,0x8FF80372,0xC6940001,0xB2000372,0x8FF80372,0xC6940001,0xB2000372,0xB2000372,0x19FC0372,0xECF00001,0xC7140001,0x8FF80372,0xC6940001,0xB2000372,0x8FF80372,0xC6940001,0xB2000372,0xB2000372,0x8FF80372,
-0xC6940001,0xB2000372,0xB2000372,0xB2000372,0xFB480288,0x77C0372,0xF96002AD,0xFF14013D,0xFECC0055,0xE6980000,0xC6C40001,0xC6580001,0xF1400288,0xFD040120,0xCECC0000,0xB2000372,0x71FC0372,0xC80374,0xC80374,0xC80374,0xC80374,0xC80374,0xC80374,0xC80374,0xC80374,0xC80374,0xC80374,0xCEA00000,0xCEA00000,0xCEA00000,0xCEA00000,0xCEA00000,
-0xCEA00000,0x8EA00000,0x8EA00000,0x8EA00000,0x78A00001,0x12C0372,0x12C0372,0x12C0372,0x12C0372,0x12C0372,0x12C0372,0x9E540001,0x9E540001,0x9E540001,0x78780001,0x1BF80372,0x1BF80372,0x1BF80372,0x78000002,0x64000372,0xF8C00200,0xC80374,0xC80374,0xFEAC00B4,0xFEA80019,0xECA00000,0xECA00000,0xB6A00000,0xFEA0019A,0xFC9C0091,0xA4940000,0x9E540001,
-0x1AC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table146[] = {
-0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x7FC0000,
-0x7FC0000,0x7FC0000,0x7FC0000,0x56000001,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xBC0000,0xBC0000,0xBC0000,0x1040000,0x1740000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x1040000,0x3800000,0x3800000,0x3800000,0x3800000,0x3800000,
-0x3800000,0x45FC0000,0x45FC0000,0x45FC0000,0x80000001,0x3800000,0x3800000,0x3800000,0x3800000,0x3800000,0x3800000,0x45FC0000,0x45FC0000,0x45FC0000,0x80000001,0x45FC0000,0x45FC0000,0x45FC0000,0x80000001,0x80000001,0x3140000,0x1040000,0x1040000,0x52C0000,0x3440000,0x1600000,0x1600000,0x1B40000,0x52C0000,0x3440000,0x15FC0000,0x45FC0000,
-0x15FC0000,0x14C0000,0x14C0000,0x14C0000,0x14C0000,0x1EC0000,0x1EC0000,0x1EC0000,0x7BFC0000,0x7BFC0000,0xA4000001,0x1EC0000,0x1EC0000,0x1EC0000,0x7BFC0000,0x7BFC0000,0xA4000001,0x7BFC0000,0x7BFC0000,0xA4000001,0xA4000001,0x1EC0000,0x1EC0000,0x1EC0000,0x7BFC0000,0x7BFC0000,0xA4000001,0x7BFC0000,0x7BFC0000,0xA4000001,0xA4000001,0x7BFC0000,
-0x7BFC0000,0xA4000001,0xA4000001,0xA4000001,0x5800000,0x9600000,0x14C0000,0x1C40000,0x25FC0000,0x59FC0000,0x69FC0000,0x87F40000,0x1A00000,0x1EC0000,0x59FC0000,0xA4000001,0x59FC0000,0x1A00000,0x71FC0000,0xB9FC0000,0xCE000001,0x71FC0000,0xB9FC0000,0xCE000001,0xB9FC0000,0xCE000001,0xCE000001,0x71FC0000,0xB9FC0000,0xCE000001,0xB9FC0000,0xCE000001,
-0xCE000001,0xB9FC0000,0xCE000001,0xCE000001,0xCE000001,0x71FC0000,0xB9FC0000,0xCE000001,0xB9FC0000,0xCE000001,0xCE000001,0xB9FC0000,0xCE000001,0xCE000001,0xCE000001,0xB9FC0000,0xCE000001,0xCE000001,0xCE000001,0xCE000001,0x1BFC0000,0x1BC0000,0x1BC0000,0x8DFC0000,0xB1FC0000,0xC5F40000,0xCE000001,0xCE000001,0x4FFC0000,0x9BFC0000,0xCDEC0000,0xCE000001,
-0xA7FC0000,0x1281EA8,0xFF0C10D8,0xF7000BE8,0xCF000BE9,0xFEF40BA8,0xFEDC03B5,0xD4E80531,0xE0D806E6,0xCCD803AE,0xBAD806E6,0xFEDC0EF8,0xFEB802CE,0xD6C80411,0xE8AC038E,0xCEB0000E,0xBCB803AE,0xCEB00BE8,0xC2A00413,0xB4A80533,0xA6B00BEB,0x1B81EA8,0xFE880CAF,0xCEB40BE9,0xFE4C06F6,0xD07C038E,0xBA8C06E6,0xF21C0BE9,0xCE38028A,0xB84403A3,0xA6640BEB,0x61F81EA8,
-0xC4000C91,0xB2000856,0xA0000E0B,0x92001EAC,0xFF0C1316,0xF9201A96,0xFB241B85,0xFEEC08C9,0xFEC40195,0xECB00006,0xD2B80046,0xCAA80046,0xFEF81262,0xFED0075B,0xD49C029D,0xB84403A3,0x37FC1EA8,0x1500BE8,0xFF340489,0xED280288,0xCF280289,0xFF180478,0xF3040005,0xD10C0042,0xD7040372,0xC8FC00A5,0xBB040372,0x1F40BE8,0xFEC002A1,0xD0EC0289,0xF0980372,0xCEB8000A,
-0xBACC0372,0x7FF80BE8,0xCE340289,0xBA180372,0xA6000BEB,0x1F40BE8,0xFEC002A1,0xD0EC0289,0xF0980372,0xCEB8000A,0xBACC0372,0x7FF80BE8,0xCE340289,0xBA180372,0xA6000BEB,0x7FF80BE8,0xCE340289,0xBA180372,0xA6000BEB,0xA6000BEB,0xFF3407C9,0xFD480A38,0xFF4C0A20,0xFF08040E,0xFED000DE,0xEAB40006,0xD0CC0001,0xCC940022,0xFF180806,0xFEF00396,0xD88C0288,0xBA180372,
-0x5DF80BE8,0x1000BE8,0x1000BE8,0x1000BE8,0x1000BE8,0xFEDC03B4,0xFEDC03B4,0xFEDC03B4,0xC0DC0374,0xC0DC0374,0xA4D80375,0xFCB802AA,0xFCB802AA,0xFCB802AA,0xCCB40009,0xCCB40009,0xA8BC00A6,0xB0B00288,0xB0B00288,0xA0AC0041,0x92B0028A,0x17C0BE8,0x17C0BE8,0x17C0BE8,0xDA700372,0xDA700372,0xA4A40373,0xCA440289,0xCA440289,0xA6640002,0x9474028A,0x43F80BE8,
-0x43F80BE8,0xA400037B,0x900002EB,0x7E000BEB,0xFEE806AD,0xF6FC09B4,0x1000BE8,0xFED402DD,0xFEC0005D,0xECB00005,0xDAB80021,0xC0B00002,0xFED0064B,0xFEBC0272,0xCEA0028A,0xA6640002,0x11FC0BE8,0x1280288,0x1280288,0x1280288,0x1280288,0xEF040000,0xEF040000,0xEF040000,0xB7040000,0xB7040000,0xA5040001,0x1B80288,0x1B80288,0x1B80288,0xC4C40001,0xC4C40001,
-0xA6E00001,0x61F80288,0x61F80288,0xA4740001,0x9200028A,0x1B80288,0x1B80288,0x1B80288,0xC4C40001,0xC4C40001,0xA6E00001,0x61F80288,0x61F80288,0xA4740001,0x9200028A,0x61F80288,0x61F80288,0xA4740001,0x9200028A,0x9200028A,0xFF100152,0xF92001A5,0x1280288,0xFCF400B5,0xFEC8000A,0xE4BC0000,0xD0CC0000,0xC2AC0000,0xFEF80171,0xFEDC0091,0x37FC0288,0xA4740001,
-0x37FC0288,0x1740374,0xFF5C0071,0xE54C0000,0xCF4C0001,0x31FC0372,0xF5000001,0xCF240001,0x9BF80372,0xCEA40001,0xBA000372,0x31FC0372,0xF5000001,0xCF240001,0x9BF80372,0xCEA40001,0xBA000372,0x9BF80372,0xCEA40001,0xBA000372,0xBA000372,0x31FC0372,0xF5000001,0xCF240001,0x9BF80372,0xCEA40001,0xBA000372,0x9BF80372,0xCEA40001,0xBA000372,0xBA000372,0x9BF80372,
-0xCEA40001,0xBA000372,0xBA000372,0xBA000372,0xFF5002A8,0xF8C0372,0xFF6C02B9,0xFF30016D,0xFEE80075,0xEEA80000,0xCED40001,0xCE680001,0xF9500288,0xFF140145,0xD6DC0000,0xBA000372,0x7FFC0372,0xD80374,0xD80374,0xD80374,0xD80374,0xD80374,0xD80374,0xD80374,0xD80374,0xD80374,0xD80374,0xD6B00000,0xD6B00000,0xD6B00000,0xD6B00000,0xD6B00000,
-0xD6B00000,0x96B00000,0x96B00000,0x96B00000,0x80B00001,0x1440372,0x1440372,0x1440372,0x1440372,0x1440372,0x1440372,0xA6640001,0xA6640001,0xA6640001,0x80880001,0x27F80372,0x27F80372,0x27F80372,0x80080001,0x6C000372,0xFECC0208,0xD80374,0xD80374,0xFAC400C8,0xFEB40028,0xF4B00000,0xF4B00000,0xBEB00000,0xFCB801A5,0xFAAC00A4,0xACA40000,0xA6640001,
-0x1D00372,};
-static const uint32_t g_etc1_to_bc7_m6_table147[] = {
-0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x13FC0000,
-0x13FC0000,0x13FC0000,0x13FC0000,0x5E000001,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xC00000,0xCC0000,0xCC0000,0xCC0000,0x11C0000,0x1980000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,
-0x3980000,0x51FC0000,0x51FC0000,0x51FC0000,0x88000001,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,0x51FC0000,0x51FC0000,0x51FC0000,0x88000001,0x51FC0000,0x51FC0000,0x51FC0000,0x88000001,0x88000001,0xB240000,0x1140000,0x1140000,0x1400000,0x3580000,0x1780000,0x1780000,0x1D00000,0x1400000,0x3580000,0x23FC0000,0x51FC0000,
-0x23FC0000,0x15C0000,0x15C0000,0x15C0000,0x15C0000,0x9FC0000,0x9FC0000,0x9FC0000,0x87FC0000,0x87FC0000,0xAC000001,0x9FC0000,0x9FC0000,0x9FC0000,0x87FC0000,0x87FC0000,0xAC000001,0x87FC0000,0x87FC0000,0xAC000001,0xAC000001,0x9FC0000,0x9FC0000,0x9FC0000,0x87FC0000,0x87FC0000,0xAC000001,0x87FC0000,0x87FC0000,0xAC000001,0xAC000001,0x87FC0000,
-0x87FC0000,0xAC000001,0xAC000001,0xAC000001,0x1940000,0x1740000,0x15C0000,0x1D80000,0x39FC0000,0x67FC0000,0x77FC0000,0x91FC0000,0x1B40000,0x9FC0000,0x67FC0000,0xAC000001,0x67FC0000,0x1B00000,0x89FC0000,0xC5FC0000,0xD6000001,0x89FC0000,0xC5FC0000,0xD6000001,0xC5FC0000,0xD6000001,0xD6000001,0x89FC0000,0xC5FC0000,0xD6000001,0xC5FC0000,0xD6000001,
-0xD6000001,0xC5FC0000,0xD6000001,0xD6000001,0xD6000001,0x89FC0000,0xC5FC0000,0xD6000001,0xC5FC0000,0xD6000001,0xD6000001,0xC5FC0000,0xD6000001,0xD6000001,0xD6000001,0xC5FC0000,0xD6000001,0xD6000001,0xD6000001,0xD6000001,0x41FC0000,0x1CC0000,0x1CC0000,0xA1FC0000,0xBFF80000,0xCFF40000,0xD6000001,0xD6000001,0x6FFC0000,0xADFC0000,0xD5FC0000,0xD6000001,
-0xB7FC0000,0x1381EA8,0xFF241198,0xFF100BE8,0xD7100BE9,0xFF0C0C98,0xFEF403FD,0xDCF80531,0xE8E806E6,0xD4E803AE,0xC2E806E6,0xFEF40FB8,0xFECC0345,0xDED80411,0xF0BC038E,0xD6C0000E,0xC4C803AE,0xD6C00BE8,0xCAB00413,0xBCB80533,0xAEC00BEB,0x1D01EA8,0xFEA00D2F,0xD6C40BE9,0xFE700736,0xD88C038E,0xC29C06E6,0xFA2C0BE9,0xD648028A,0xC05403A3,0xAE740BEB,0x6DF81EA8,
-0xD0000C49,0xBC0007F4,0xAC000D93,0x9A001EAC,0xFF2013CE,0xFF2C1AAE,0xFF2C1BCD,0xFF0009E0,0xFED8026D,0xF4C00006,0xDAC80046,0xD2B80046,0xFF101346,0xFEE008B4,0xDCAC029D,0xC05403A3,0x45FC1EA8,0x1600BE8,0xFF4404E1,0xF5380288,0xD7380289,0xFF3004D8,0xFB140005,0xD91C0042,0xDF140372,0xD10C00A5,0xC3140372,0xFFC0BE8,0xFED802D9,0xD8FC0289,0xF8A80372,0xD6C8000A,
-0xC2DC0372,0x8BF80BE8,0xD6440289,0xC2280372,0xAE000BEB,0xFFC0BE8,0xFED802D9,0xD8FC0289,0xF8A80372,0xD6C8000A,0xC2DC0372,0x8BF80BE8,0xD6440289,0xC2280372,0xAE000BEB,0x8BF80BE8,0xD6440289,0xC2280372,0xAE000BEB,0xAE000BEB,0xFB480849,0xF5580A7E,0xF75C0A69,0xFF180496,0xFEE80149,0xF2C40006,0xD8DC0001,0xD4A40022,0xFF34084E,0xFF040403,0xE09C0288,0xC2280372,
-0x6BFC0BE8,0x1100BE8,0x1100BE8,0x1100BE8,0x1100BE8,0xFEF403E4,0xFEF403E4,0xFEF403E4,0xC8EC0374,0xC8EC0374,0xACE80375,0xFEC802CA,0xFEC802CA,0xFEC802CA,0xD4C40009,0xD4C40009,0xB0CC00A6,0xB8C00288,0xB8C00288,0xA8BC0041,0x9AC0028A,0x1940BE8,0x1940BE8,0x1940BE8,0xE2800372,0xE2800372,0xACB40373,0xD2540289,0xD2540289,0xAE740002,0x9C84028A,0x4FF80BE8,
-0x4FF80BE8,0xAC040373,0x9A0002CA,0x86000BEB,0xFD000714,0xFF0C09B4,0x1100BE8,0xFEE8034D,0xFED40099,0xF4C00005,0xE2C80021,0xC8C00002,0xFEE406AA,0xFED002BA,0xD6B0028A,0xAE740002,0x1FFC0BE8,0x1380288,0x1380288,0x1380288,0x1380288,0xF7140000,0xF7140000,0xF7140000,0xBF140000,0xBF140000,0xAD140001,0x1D00288,0x1D00288,0x1D00288,0xCCD40001,0xCCD40001,
-0xAEF00001,0x6DF80288,0x6DF80288,0xAC840001,0x9A00028A,0x1D00288,0x1D00288,0x1D00288,0xCCD40001,0xCCD40001,0xAEF00001,0x6DF80288,0x6DF80288,0xAC840001,0x9A00028A,0x6DF80288,0x6DF80288,0xAC840001,0x9A00028A,0x9A00028A,0xFF20016D,0xFF2C01B1,0x1380288,0xFD0400CA,0xFEE00019,0xECCC0000,0xD8DC0000,0xCABC0000,0xFD100188,0xFEE800B4,0x45FC0288,0xAC840001,
-0x45FC0288,0x1840374,0xFF68009D,0xED5C0000,0xD75C0001,0x49FC0372,0xFD100001,0xD7340001,0xA7F80372,0xD6B40001,0xC2000372,0x49FC0372,0xFD100001,0xD7340001,0xA7F80372,0xD6B40001,0xC2000372,0xA7F80372,0xD6B40001,0xC2000372,0xC2000372,0x49FC0372,0xFD100001,0xD7340001,0xA7F80372,0xD6B40001,0xC2000372,0xA7F80372,0xD6B40001,0xC2000372,0xC2000372,0xA7F80372,
-0xD6B40001,0xC2000372,0xC2000372,0xC2000372,0xFB7002AD,0x1A00372,0xF98002D4,0xFF40019A,0xFF0C00B5,0xF6B80000,0xD6E40001,0xD6780001,0xFF5C0290,0xFF2C0185,0xDEEC0000,0xC2000372,0x8FFC0372,0xE80374,0xE80374,0xE80374,0xE80374,0xE80374,0xE80374,0xE80374,0xE80374,0xE80374,0xE80374,0xDEC00000,0xDEC00000,0xDEC00000,0xDEC00000,0xDEC00000,
-0xDEC00000,0x9EC00000,0x9EC00000,0x9EC00000,0x88C00001,0x15C0372,0x15C0372,0x15C0372,0x15C0372,0x15C0372,0x15C0372,0xAE740001,0xAE740001,0xAE740001,0x88980001,0x33F80372,0x33F80372,0x33F80372,0x88180001,0x74000372,0xF8E00221,0xE80374,0xE80374,0xFCD400DD,0xFCCC003D,0xFCC00000,0xFCC00000,0xC6C00000,0xF8CC01C2,0xFEBC00B9,0xB4B40000,0xAE740001,
-0x1F00372,};
-static const uint32_t g_etc1_to_bc7_m6_table148[] = {
-0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x21F80000,
-0x21F80000,0x21F80000,0x21F80000,0x68000000,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xD00001,0xE00000,0xE00000,0xE00000,0x1380000,0x1BC0000,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1240001,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,
-0x1B40000,0x5FF80000,0x5FF80000,0x5FF80000,0x92000000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x1B40000,0x5FF80000,0x5FF80000,0x5FF80000,0x92000000,0x5FF80000,0x5FF80000,0x5FF80000,0x92000000,0x92000000,0x5380000,0x1240001,0x1240001,0x3540000,0x1700000,0x1900000,0x1900000,0x3EC0000,0x3540000,0x1700000,0x35FC0000,0x5FF80000,
-0x35FC0000,0x16C0001,0x16C0001,0x16C0001,0x16C0001,0x25FC0000,0x25FC0000,0x25FC0000,0x95F80000,0x95F80000,0xB6000000,0x25FC0000,0x25FC0000,0x25FC0000,0x95F80000,0x95F80000,0xB6000000,0x95F80000,0x95F80000,0xB6000000,0xB6000000,0x25FC0000,0x25FC0000,0x25FC0000,0x95F80000,0x95F80000,0xB6000000,0x95F80000,0x95F80000,0xB6000000,0xB6000000,0x95F80000,
-0x95F80000,0xB6000000,0xB6000000,0xB6000000,0x3A80000,0xB840000,0x16C0001,0x3F00000,0x4FFC0000,0x79FC0000,0x87F80000,0x9DFC0000,0x1CC0000,0x25FC0000,0x79FC0000,0xB6000000,0x79FC0000,0x1C00001,0xA5FC0000,0xD3FC0000,0xE0000000,0xA5FC0000,0xD3FC0000,0xE0000000,0xD3FC0000,0xE0000000,0xE0000000,0xA5FC0000,0xD3FC0000,0xE0000000,0xD3FC0000,0xE0000000,
-0xE0000000,0xD3FC0000,0xE0000000,0xE0000000,0xE0000000,0xA5FC0000,0xD3FC0000,0xE0000000,0xD3FC0000,0xE0000000,0xE0000000,0xD3FC0000,0xE0000000,0xE0000000,0xE0000000,0xD3FC0000,0xE0000000,0xE0000000,0xE0000000,0xE0000000,0x6DFC0000,0x1E00000,0x1E00000,0xB7FC0000,0xCDFC0000,0xD9FC0000,0xE0000000,0xE0000000,0x8FFC0000,0xC1FC0000,0xDFF00000,0xE0000000,
-0xC7FC0000,0x1481EAC,0xFF30126C,0xFF200C0F,0xE1200BEB,0xFF180DB4,0xFF080497,0xE5080533,0xF0FC06E6,0xDCF803AE,0xCAFC06E6,0xFF00109C,0xFEE4040B,0xE8EC0413,0xFAD0038E,0xE0D0000E,0xCCD803AE,0xDED40BE9,0xD4C40411,0xC4C80531,0xB8D00BE9,0x3E81EA8,0xFEC00DE7,0xE0D40BE8,0xFE8807BE,0xE2A0038E,0xCAB006E6,0xFE4C0BFB,0xE05C028A,0xCA6803A1,0xB8840BE8,0x79FC1EA8,
-0xDC000C13,0xC400078E,0xB2000D35,0xA4001EA8,0xFF3414AF,0xFB441B24,0xFD481BF4,0xFF140B27,0xFEF00392,0xFED40006,0xE4DC0046,0xDCCC0046,0xFF181429,0xFF0009F4,0xE6BC029D,0xCA6803A1,0x57FC1EA8,0x1700BEB,0xFF5C056A,0xFF48028A,0xE148028A,0xFF440545,0xFF28001A,0xE3300041,0xE7280373,0xDB2000A6,0xCB240375,0x2BFC0BE8,0xFEFC032A,0xE1100288,0xFEC00375,0xDED80009,
-0xCAF00374,0x97FC0BE8,0xE0540288,0xCA400374,0xB8000BE8,0x2BFC0BE8,0xFEFC032A,0xE1100288,0xFEC00375,0xDED80009,0xCAF00374,0x97FC0BE8,0xE0540288,0xCA400374,0xB8000BE8,0x97FC0BE8,0xE0540288,0xCA400374,0xB8000BE8,0xB8000BE8,0xFF580895,0xFF6C0A7D,0xFF6C0A6E,0xFF30053A,0xFF1001EE,0xFCD80005,0xE0EC0002,0xDCBC0021,0xFF4408B8,0xFF2404CA,0xE8B00289,0xCA400374,
-0x7DF80BE8,0x1200BEB,0x1200BEB,0x1200BEB,0x1200BEB,0xFF040422,0xFF040422,0xFF040422,0xD2FC0372,0xD2FC0372,0xB6FC0372,0xFEE00301,0xFEE00301,0xFEE00301,0xDCD4000A,0xDCD4000A,0xBAE000A5,0xC2D00289,0xC2D00289,0xB2D00042,0xA4D00289,0x1B00BE8,0x1B00BE8,0x1B00BE8,0xEC900372,0xEC900372,0xB6C40372,0xDC640289,0xDC640289,0xB6840005,0xA4980288,0x5DF40BE8,
-0x5DF40BE8,0xB6100372,0xA20002A9,0x90000BE8,0xFF100755,0xF71C09F6,0x1200BEB,0xFEF803C2,0xFEE400F1,0xFAD40005,0xEAD80022,0xD2D00001,0xFEF806F2,0xFEE80352,0xE0C00289,0xB6840005,0x31FC0BE8,0x148028A,0x148028A,0x148028A,0x148028A,0xFF280001,0xFF280001,0xFF280001,0xC9240001,0xC9240001,0xB7240001,0x3E80288,0x3E80288,0x3E80288,0xD6E40001,0xD6E40001,
-0xB7040000,0x79FC0288,0x79FC0288,0xB6900000,0xA4000288,0x3E80288,0x3E80288,0x3E80288,0xD6E40001,0xD6E40001,0xB7040000,0x79FC0288,0x79FC0288,0xB6900000,0xA4000288,0x79FC0288,0x79FC0288,0xB6900000,0xA4000288,0xA4000288,0xFB34018A,0xFB4401C2,0x148028A,0xFF1800E1,0xFCFC0032,0xF4E00000,0xE2EC0000,0xD2D00000,0xF92801A5,0xFF0400D0,0x57FC0288,0xB6900000,
-0x57FC0288,0x1980372,0xFF8000E1,0xF5700001,0xE16C0001,0x65FC0372,0xFF2C0011,0xE1440000,0xB3FC0372,0xE0C00000,0xCA000374,0x65FC0372,0xFF2C0011,0xE1440000,0xB3FC0372,0xE0C00000,0xCA000374,0xB3FC0372,0xE0C00000,0xCA000374,0xCA000374,0x65FC0372,0xFF2C0011,0xE1440000,0xB3FC0372,0xE0C00000,0xCA000374,0xB3FC0372,0xE0C00000,0xCA000374,0xCA000374,0xB3FC0372,
-0xE0C00000,0xCA000374,0xCA000374,0xCA000374,0xFB8402D2,0x1B40372,0xFF8C02F2,0xFD6801E1,0xFF2800E9,0xFECC0001,0xE0F40000,0xE0840000,0xFF7002C5,0xFF4C01B1,0xE7000000,0xCA000374,0x9FFC0372,0xFC0372,0xFC0372,0xFC0372,0xFC0372,0xFC0372,0xFC0372,0xFC0372,0xFC0372,0xFC0372,0xFC0372,0xE6D40001,0xE6D40001,0xE6D40001,0xE6D40001,0xE6D40001,
-0xE6D40001,0xA6D40001,0xA6D40001,0xA6D40001,0x92D00001,0x3740372,0x3740372,0x3740372,0x3740372,0x3740372,0x3740372,0xB8840001,0xB8840001,0xB8840001,0x92A80000,0x3FFC0372,0x3FFC0372,0x3FFC0372,0x92240000,0x7C000374,0xFEEC0239,0xFC0372,0xFC0372,0xFEE800F2,0xFCE00055,0xFED40002,0xFED40002,0xCED40001,0xFED801D4,0xFED000D0,0xBAC80001,0xB8840001,
-0xDFC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table149[] = {
-0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x1500000,0x2DF80000,
-0x2DF80000,0x2DF80000,0x2DF80000,0x70000000,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xE00001,0xF00000,0xF00000,0xF00000,0x1500000,0x1E00000,0x1340001,0x1340001,0x1340001,0x1340001,0x1340001,0x1340001,0x1340001,0x1340001,0x1340001,0x1340001,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,
-0x1CC0000,0x6BF80000,0x6BF80000,0x6BF80000,0x9A000000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x6BF80000,0x6BF80000,0x6BF80000,0x9A000000,0x6BF80000,0x6BF80000,0x6BF80000,0x9A000000,0x9A000000,0xD480000,0x1340001,0x1340001,0x1680000,0x1840000,0x3A40000,0x3A40000,0xBFC0000,0x1680000,0x1840000,0x43FC0000,0x6BF80000,
-0x43FC0000,0x17C0001,0x17C0001,0x17C0001,0x17C0001,0x3DFC0000,0x3DFC0000,0x3DFC0000,0xA1F80000,0xA1F80000,0xBE000000,0x3DFC0000,0x3DFC0000,0x3DFC0000,0xA1F80000,0xA1F80000,0xBE000000,0xA1F80000,0xA1F80000,0xBE000000,0xBE000000,0x3DFC0000,0x3DFC0000,0x3DFC0000,0xA1F80000,0xA1F80000,0xBE000000,0xA1F80000,0xA1F80000,0xBE000000,0xBE000000,0xA1F80000,
-0xA1F80000,0xBE000000,0xBE000000,0xBE000000,0x1BC0000,0x1980000,0x17C0001,0xFFC0000,0x63FC0000,0x87FC0000,0x95F80000,0xA9F40000,0x1E00000,0x3DFC0000,0x87FC0000,0xBE000000,0x87FC0000,0x1D00001,0xBDFC0000,0xDFF80000,0xE8000000,0xBDFC0000,0xDFF80000,0xE8000000,0xDFF80000,0xE8000000,0xE8000000,0xBDFC0000,0xDFF80000,0xE8000000,0xDFF80000,0xE8000000,
-0xE8000000,0xDFF80000,0xE8000000,0xE8000000,0xE8000000,0xBDFC0000,0xDFF80000,0xE8000000,0xDFF80000,0xE8000000,0xE8000000,0xDFF80000,0xE8000000,0xE8000000,0xE8000000,0xDFF80000,0xE8000000,0xE8000000,0xE8000000,0xE8000000,0x95FC0000,0x1F00000,0x1F00000,0xCBFC0000,0xDBFC0000,0xE5F00000,0xE8000000,0xE8000000,0xAFFC0000,0xD1FC0000,0xE9C40000,0xE8000000,
-0xD7FC0000,0x1581EAC,0xFF44131B,0xFF340C64,0xE9300BEB,0xFF300EB4,0xFF180563,0xED180533,0xF90C06E6,0xE50803AE,0xD30C06E6,0xFF181164,0xFEFC04F3,0xF0FC0413,0xFEE4039E,0xE8E0000E,0xD4E803AE,0xE6E40BE9,0xDCD40411,0xCCD80531,0xC0E00BE9,0x7FC1EA8,0xFED80EA7,0xE8E40BE8,0xFEAC0866,0xEAB0038E,0xD2C006E6,0xFE640C43,0xE86C028A,0xD27803A1,0xC0940BE8,0x85FC1EA8,
-0xE6000BF8,0xD000073E,0xBE000CD5,0xAC001EA8,0xFF3C1574,0xFF4C1B64,0xF5581C63,0xFF240C9E,0xFF0404CE,0xFEE80032,0xECEC0046,0xE4DC0046,0xFF3414DA,0xFF100B2E,0xEECC029D,0xD27803A1,0x65FC1EA8,0x1800BEB,0xFF6805FA,0xFF5802A3,0xE958028A,0xFF5C05CD,0xFF40006A,0xEB400041,0xEF380373,0xE33000A6,0xD3340375,0x43FC0BE8,0xFF14039A,0xE9200288,0xFEE4039D,0xE6E80009,
-0xD3000374,0xA3FC0BE8,0xE8640288,0xD2500374,0xC0000BE8,0x43FC0BE8,0xFF14039A,0xE9200288,0xFEE4039D,0xE6E80009,0xD3000374,0xA3FC0BE8,0xE8640288,0xD2500374,0xC0000BE8,0xA3FC0BE8,0xE8640288,0xD2500374,0xC0000BE8,0xC0000BE8,0xFF640905,0xF77C0AC3,0xF9800AB3,0xFF4405E1,0xFF24028E,0xFEF0001B,0xE8FC0002,0xE4CC0021,0xFF5C08DE,0xFF400550,0xF0C00289,0xD2500374,
-0x8BFC0BE8,0x1300BEB,0x1300BEB,0x1300BEB,0x1300BEB,0xFF180463,0xFF180463,0xFF180463,0xDB0C0372,0xDB0C0372,0xBF0C0372,0xFEF4033B,0xFEF4033B,0xFEF4033B,0xE4E4000A,0xE4E4000A,0xC2F000A5,0xCAE00289,0xCAE00289,0xBAE00042,0xACE00289,0x3C40BE8,0x3C40BE8,0x3C40BE8,0xF4A00372,0xF4A00372,0xBED40372,0xE4740289,0xE4740289,0xBE940005,0xACA80288,0x67FC0BE8,
-0x67FC0BE8,0xBE200372,0xAC000291,0x98000BE8,0xFF200792,0xFF2C09F6,0x1300BEB,0xFF100426,0xFEF8014D,0xFEE8000E,0xF2E80022,0xDAE00001,0xFF100749,0xFEF403B6,0xE8D00289,0xBE940005,0x3FFC0BE8,0x158028A,0x158028A,0x158028A,0x158028A,0xFD38000A,0xFD38000A,0xFD38000A,0xD1340001,0xD1340001,0xBF340001,0x7FC0288,0x7FC0288,0x7FC0288,0xDEF40001,0xDEF40001,
-0xBF140000,0x85FC0288,0x85FC0288,0xBEA00000,0xAC000288,0x7FC0288,0x7FC0288,0x7FC0288,0xDEF40001,0xDEF40001,0xBF140000,0x85FC0288,0x85FC0288,0xBEA00000,0xAC000288,0x85FC0288,0x85FC0288,0xBEA00000,0xAC000288,0xAC000288,0xF74801A5,0xF35401E1,0x158028A,0xFD300109,0xFD140048,0xFCF00000,0xEAFC0000,0xDAE00000,0xFF3401A9,0xFF1800E9,0x65FC0288,0xBEA00000,
-0x65FC0288,0x1A80372,0xFF8C0131,0xFD800001,0xE97C0001,0x7DFC0372,0xFF4C0041,0xE9540000,0xBFFC0372,0xE8D00000,0xD2000374,0x7DFC0372,0xFF4C0041,0xE9540000,0xBFFC0372,0xE8D00000,0xD2000374,0xBFFC0372,0xE8D00000,0xD2000374,0xD2000374,0x7DFC0372,0xFF4C0041,0xE9540000,0xBFFC0372,0xE8D00000,0xD2000374,0xBFFC0372,0xE8D00000,0xD2000374,0xD2000374,0xBFFC0372,
-0xE8D00000,0xD2000374,0xD2000374,0xD2000374,0xFF9402D4,0x1C40372,0xFBA402F9,0xFF740212,0xFF500139,0xFEF0001A,0xE9040000,0xE8940000,0xFB9002D2,0xFF6401F9,0xEF100000,0xD2000374,0xAFFC0372,0x10C0372,0x10C0372,0x10C0372,0x10C0372,0x10C0372,0x10C0372,0x10C0372,0x10C0372,0x10C0372,0x10C0372,0xEEE40001,0xEEE40001,0xEEE40001,0xEEE40001,0xEEE40001,
-0xEEE40001,0xAEE40001,0xAEE40001,0xAEE40001,0x9AE00001,0x38C0372,0x38C0372,0x38C0372,0x38C0372,0x38C0372,0x38C0372,0xC0940001,0xC0940001,0xC0940001,0x9AB80000,0x4BFC0372,0x4BFC0372,0x4BFC0372,0x9A340000,0x84000374,0xFB040242,0x10C0372,0x10C0372,0xFEF40115,0xFEEC006A,0xFEE8000D,0xFEE8000D,0xD6E40001,0xFCF001E1,0xFEE400F4,0xC2D80001,0xC0940001,
-0x1DF80372,};
-static const uint32_t g_etc1_to_bc7_m6_table150[] = {
-0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x39F80000,
-0x39F80000,0x39F80000,0x39F80000,0x78000000,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0xF00001,0x9000000,0x9000000,0x9000000,0x1680000,0x3FC0000,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1440001,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,
-0x1E40000,0x77F80000,0x77F80000,0x77F80000,0xA2000000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x1E40000,0x77F80000,0x77F80000,0x77F80000,0xA2000000,0x77F80000,0x77F80000,0x77F80000,0xA2000000,0xA2000000,0x15C0000,0x1440001,0x1440001,0x17C0000,0x1980000,0x1BC0000,0x1BC0000,0x1DFC0000,0x17C0000,0x1980000,0x53FC0000,0x77F80000,
-0x53FC0000,0x18C0001,0x18C0001,0x18C0001,0x18C0001,0x55FC0000,0x55FC0000,0x55FC0000,0xADF80000,0xADF80000,0xC6000000,0x55FC0000,0x55FC0000,0x55FC0000,0xADF80000,0xADF80000,0xC6000000,0xADF80000,0xADF80000,0xC6000000,0xC6000000,0x55FC0000,0x55FC0000,0x55FC0000,0xADF80000,0xADF80000,0xC6000000,0xADF80000,0xADF80000,0xC6000000,0xC6000000,0xADF80000,
-0xADF80000,0xC6000000,0xC6000000,0xC6000000,0x7CC0000,0x1A80000,0x18C0001,0x2FFC0000,0x77FC0000,0x97FC0000,0xA1FC0000,0xB3FC0000,0x1F40000,0x55FC0000,0x97FC0000,0xC6000000,0x97FC0000,0x1E00001,0xD5FC0000,0xEBF80000,0xF0000000,0xD5FC0000,0xEBF80000,0xF0000000,0xEBF80000,0xF0000000,0xF0000000,0xD5FC0000,0xEBF80000,0xF0000000,0xEBF80000,0xF0000000,
-0xF0000000,0xEBF80000,0xF0000000,0xF0000000,0xF0000000,0xD5FC0000,0xEBF80000,0xF0000000,0xEBF80000,0xF0000000,0xF0000000,0xEBF80000,0xF0000000,0xF0000000,0xF0000000,0xEBF80000,0xF0000000,0xF0000000,0xF0000000,0xF0000000,0xBDFC0000,0x27FC0000,0x27FC0000,0xDDFC0000,0xE9F80000,0xEFF00000,0xF0000000,0xF0000000,0xCDFC0000,0xE3FC0000,0xF1D40000,0xF0000000,
-0xE5FC0000,0x1681EAC,0xFF50140B,0xFF480D03,0xF1400BEB,0xFF440FB6,0xFF2C0663,0xF5280533,0xFF1C06EC,0xED1803AE,0xDB1C06E6,0xFF30124C,0xFF14061B,0xF90C0413,0xFEFC0406,0xF0F0000E,0xDCF803AE,0xEEF40BE9,0xE4E40411,0xD4E80531,0xC8F00BE9,0x1FFC1EA8,0xFEF00F87,0xF0F40BE8,0xFEC0096E,0xF2C0038E,0xDAD006E6,0xFE880CBB,0xF07C028A,0xDA8803A1,0xC8A40BE8,0x91FC1EA8,
-0xF0000BEB,0xD8000716,0xC4000C91,0xB4001EA8,0xFF50163F,0xFB641BB6,0xFD681C63,0xFF340DE2,0xFF1C0636,0xFEFC00C2,0xF4FC0046,0xECEC0046,0xFF4415D9,0xFF240CCA,0xF6DC029D,0xDA8803A1,0x75FC1EA8,0x1900BEB,0xFF80068A,0xFF7002EB,0xF168028A,0xFF680655,0xFF5400F6,0xF3500041,0xF7480373,0xEB4000A6,0xDB440375,0x5BFC0BE8,0xFF2C042A,0xF1300288,0xFEFC03ED,0xEEF80009,
-0xDB100374,0xAFFC0BE8,0xF0740288,0xDA600374,0xC8000BE8,0x5BFC0BE8,0xFF2C042A,0xF1300288,0xFEFC03ED,0xEEF80009,0xDB100374,0xAFFC0BE8,0xF0740288,0xDA600374,0xC8000BE8,0xAFFC0BE8,0xF0740288,0xDA600374,0xC8000BE8,0xC8000BE8,0xFF78093E,0xFF8C0AC3,0xFF8C0ABB,0xFF5C0671,0xFF380356,0xFF10007D,0xF10C0002,0xECDC0021,0xFF780956,0xFF540602,0xF8D00289,0xDA600374,
-0x9BFC0BE8,0x1400BEB,0x1400BEB,0x1400BEB,0x1400BEB,0xFF2404B3,0xFF2404B3,0xFF2404B3,0xE31C0372,0xE31C0372,0xC71C0372,0xFF0C0393,0xFF0C0393,0xFF0C0393,0xECF4000A,0xECF4000A,0xCB0000A5,0xD2F00289,0xD2F00289,0xC2F00042,0xB4F00289,0x3DC0BE8,0x3DC0BE8,0x3DC0BE8,0xFCB00372,0xFCB00372,0xC6E40372,0xEC840289,0xEC840289,0xC6A40005,0xB4B80288,0x73FC0BE8,
-0x73FC0BE8,0xC6300372,0xB4000289,0xA0000BE8,0xFF2C07F1,0xF73C0A3B,0x1400BEB,0xFF1804AA,0xFF0C01B9,0xFEF80032,0xFAF80022,0xE2F00001,0xFF20078D,0xFF10042D,0xF0E00289,0xC6A40005,0x4FFC0BE8,0x168028A,0x168028A,0x168028A,0x168028A,0xFD4C0019,0xFD4C0019,0xFD4C0019,0xD9440001,0xD9440001,0xC7440001,0x1FFC0288,0x1FFC0288,0x1FFC0288,0xE7040001,0xE7040001,
-0xC7240000,0x91FC0288,0x91FC0288,0xC6B00000,0xB4000288,0x1FFC0288,0x1FFC0288,0x1FFC0288,0xE7040001,0xE7040001,0xC7240000,0x91FC0288,0x91FC0288,0xC6B00000,0xB4000288,0x91FC0288,0x91FC0288,0xC6B00000,0xB4000288,0xB4000288,0xFF5801A5,0xFB6401E1,0x168028A,0xFF440120,0xFD280064,0xFF080008,0xF30C0000,0xE2F00000,0xFD4C01C2,0xFF30010D,0x75FC0288,0xC6B00000,
-0x75FC0288,0x1B80372,0xFFA40179,0xFF900011,0xF18C0001,0x95FC0372,0xFF640089,0xF1640000,0xCBFC0372,0xF0E00000,0xDA000374,0x95FC0372,0xFF640089,0xF1640000,0xCBFC0372,0xF0E00000,0xDA000374,0xCBFC0372,0xF0E00000,0xDA000374,0xDA000374,0x95FC0372,0xFF640089,0xF1640000,0xCBFC0372,0xF0E00000,0xDA000374,0xCBFC0372,0xF0E00000,0xDA000374,0xDA000374,0xCBFC0372,
-0xF0E00000,0xDA000374,0xDA000374,0xDA000374,0xFBAC02F9,0x3D40372,0xFFAC0321,0xFF940242,0xFF680179,0xFF180055,0xF1140000,0xF0A40000,0xFF9802F2,0xFF880221,0xF7200000,0xDA000374,0xBFF80372,0x11C0372,0x11C0372,0x11C0372,0x11C0372,0x11C0372,0x11C0372,0x11C0372,0x11C0372,0x11C0372,0x11C0372,0xF6F40001,0xF6F40001,0xF6F40001,0xF6F40001,0xF6F40001,
-0xF6F40001,0xB6F40001,0xB6F40001,0xB6F40001,0xA2F00001,0x3A40372,0x3A40372,0x3A40372,0x3A40372,0x3A40372,0x3A40372,0xC8A40001,0xC8A40001,0xC8A40001,0xA2C80000,0x57FC0372,0x57FC0372,0x57FC0372,0xA2440000,0x8C000374,0xFF0C0262,0x11C0372,0x11C0372,0xFF040132,0xFF000082,0xFEF80019,0xFEF80019,0xDEF40001,0xF9040200,0xFEF80109,0xCAE80001,0xC8A40001,
-0x2BFC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table151[] = {
-0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x45F80000,
-0x45F80000,0x45F80000,0x45F80000,0x80000000,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1000001,0x1140000,0x1140000,0x1140000,0x1800000,0x13FC0000,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,
-0x1FC0000,0x83F80000,0x83F80000,0x83F80000,0xAA000000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x83F80000,0x83F80000,0x83F80000,0xAA000000,0x83F80000,0x83F80000,0x83F80000,0xAA000000,0xAA000000,0x16C0000,0x1540001,0x1540001,0x38C0000,0x1AC0000,0x1D00000,0x1D00000,0x31FC0000,0x38C0000,0x1AC0000,0x61FC0000,0x83F80000,
-0x61FC0000,0x19C0001,0x19C0001,0x19C0001,0x19C0001,0x6FFC0000,0x6FFC0000,0x6FFC0000,0xB9F80000,0xB9F80000,0xCE000000,0x6FFC0000,0x6FFC0000,0x6FFC0000,0xB9F80000,0xB9F80000,0xCE000000,0xB9F80000,0xB9F80000,0xCE000000,0xCE000000,0x6FFC0000,0x6FFC0000,0x6FFC0000,0xB9F80000,0xB9F80000,0xCE000000,0xB9F80000,0xB9F80000,0xCE000000,0xCE000000,0xB9F80000,
-0xB9F80000,0xCE000000,0xCE000000,0xCE000000,0x3E00000,0x5B80000,0x19C0001,0x4DFC0000,0x8BFC0000,0xA5FC0000,0xAFFC0000,0xBFF40000,0x15FC0000,0x6FFC0000,0xA5FC0000,0xCE000000,0xA5FC0000,0x1F00001,0xEFFC0000,0xF7F80000,0xF8000000,0xEFFC0000,0xF7F80000,0xF8000000,0xF7F80000,0xF8000000,0xF8000000,0xEFFC0000,0xF7F80000,0xF8000000,0xF7F80000,0xF8000000,
-0xF8000000,0xF7F80000,0xF8000000,0xF8000000,0xF8000000,0xEFFC0000,0xF7F80000,0xF8000000,0xF7F80000,0xF8000000,0xF8000000,0xF7F80000,0xF8000000,0xF8000000,0xF8000000,0xF7F80000,0xF8000000,0xF8000000,0xF8000000,0xF8000000,0xE3FC0000,0xA7FC0000,0xA7FC0000,0xF1FC0000,0xF5FC0000,0xF9F00000,0xF8000000,0xF8000000,0xEBFC0000,0xF3FC0000,0xF9E40000,0xF8000000,
-0xF5FC0000,0x1781EAC,0xFF6814E3,0xFF580DBC,0xF9500BEB,0xFF5010EE,0xFF4007AB,0xFD380533,0xFF2C0746,0xF52803AE,0xE32C06E6,0xFF441329,0xFF280782,0xFF180417,0xFF0804CE,0xF900000E,0xE50803AE,0xF7040BE9,0xECF40411,0xDCF80531,0xD1000BE9,0x37FC1EA8,0xFF14107B,0xF9040BE8,0xFEE40A7E,0xFAD0038E,0xE2E006E6,0xFEAC0D6B,0xF88C028A,0xE29803A1,0xD0B40BE8,0x9DFC1EA8,
-0xF8080BE8,0xE00006F8,0xCE000C58,0xBC001EA8,0xFF641706,0xFF6C1C06,0xF5781CD4,0xFF440F42,0xFF2807C3,0xFF1001BE,0xFD0C0046,0xF4FC0046,0xFF54168D,0xFF400E29,0xFEEC029D,0xE29803A1,0x83FC1EA8,0x1A00BEB,0xFF8C072A,0xFF7C036B,0xF978028A,0xFF8006ED,0xFF6401AA,0xFB600041,0xFF580373,0xF35000A6,0xE3540375,0x75FC0BE8,0xFF4C04E1,0xF9400288,0xFF200465,0xF7080009,
-0xE3200374,0xBBFC0BE8,0xF8840288,0xE2700374,0xD0000BE8,0x75FC0BE8,0xFF4C04E1,0xF9400288,0xFF200465,0xF7080009,0xE3200374,0xBBFC0BE8,0xF8840288,0xE2700374,0xD0000BE8,0xBBFC0BE8,0xF8840288,0xE2700374,0xD0000BE8,0xD0000BE8,0xFF940998,0xF79C0B0D,0xF9A00AFE,0xFF780729,0xFF50043A,0xFF2C0113,0xF91C0002,0xF4EC0021,0xFF88099B,0xFF6806C8,0xFEE40291,0xE2700374,
-0xA9FC0BE8,0x1500BEB,0x1500BEB,0x1500BEB,0x1500BEB,0xFF3C0513,0xFF3C0513,0xFF3C0513,0xEB2C0372,0xEB2C0372,0xCF2C0372,0xFF1803F3,0xFF1803F3,0xFF1803F3,0xF504000A,0xF504000A,0xD31000A5,0xDB000289,0xDB000289,0xCB000042,0xBD000289,0x3F40BE8,0x3F40BE8,0x3F40BE8,0xFEC8037D,0xFEC8037D,0xCEF40372,0xF4940289,0xF4940289,0xCEB40005,0xBCC80288,0x7FFC0BE8,
-0x7FFC0BE8,0xCE400372,0xBC0C0288,0xA8000BE8,0xFF3C0843,0xFF4C0A3B,0x1500BEB,0xFF34051E,0xFF200235,0xFF10007A,0xFF080031,0xEB000001,0xFF3407CA,0xFF2404BA,0xF8F00289,0xCEB40005,0x5FF80BE8,0x178028A,0x178028A,0x178028A,0x178028A,0xFF5C002D,0xFF5C002D,0xFF5C002D,0xE1540001,0xE1540001,0xCF540001,0x37FC0288,0x37FC0288,0x37FC0288,0xEF140001,0xEF140001,
-0xCF340000,0x9DFC0288,0x9DFC0288,0xCEC00000,0xBC000288,0x37FC0288,0x37FC0288,0x37FC0288,0xEF140001,0xEF140001,0xCF340000,0x9DFC0288,0x9DFC0288,0xCEC00000,0xBC000288,0x9DFC0288,0x9DFC0288,0xCEC00000,0xBC000288,0xBC000288,0xFB6C01C2,0xF3740202,0x178028A,0xFD580139,0xFF400080,0xFF200014,0xFB1C0000,0xEB000000,0xF56401E1,0xFF480122,0x83FC0288,0xCEC00000,
-0x83FC0288,0x1C80372,0xFFB001E1,0xFFA00052,0xF99C0001,0xAFFC0372,0xFF8800E9,0xF9740000,0xD7FC0372,0xF8F00000,0xE2000374,0xAFFC0372,0xFF8800E9,0xF9740000,0xD7FC0372,0xF8F00000,0xE2000374,0xD7FC0372,0xF8F00000,0xE2000374,0xE2000374,0xAFFC0372,0xFF8800E9,0xF9740000,0xD7FC0372,0xF8F00000,0xE2000374,0xD7FC0372,0xF8F00000,0xE2000374,0xE2000374,0xD7FC0372,
-0xF8F00000,0xE2000374,0xE2000374,0xE2000374,0xFFB40311,0xBE40372,0xFBC40322,0xFFAC0288,0xFF7C01E1,0xFF4800A9,0xF9240000,0xF8B40000,0xF1C00320,0xFFA00269,0xFF300000,0xE2000374,0xCDFC0372,0x12C0372,0x12C0372,0x12C0372,0x12C0372,0x12C0372,0x12C0372,0x12C0372,0x12C0372,0x12C0372,0x12C0372,0xFF040001,0xFF040001,0xFF040001,0xFF040001,0xFF040001,
-0xFF040001,0xBF040001,0xBF040001,0xBF040001,0xAB000001,0x3BC0372,0x3BC0372,0x3BC0372,0x3BC0372,0x3BC0372,0x3BC0372,0xD0B40001,0xD0B40001,0xD0B40001,0xAAD80000,0x63FC0372,0x63FC0372,0x63FC0372,0xAA540000,0x94000374,0xFB240265,0x12C0372,0x12C0372,0xFD1C0152,0xFF1400A2,0xFF08002D,0xFF08002D,0xE7040001,0xFF100208,0xFB0C0139,0xD2F80001,0xD0B40001,
-0x3BFC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table152[] = {
-0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,0x3980000,0x51FC0000,
-0x51FC0000,0x51FC0000,0x51FC0000,0x88000001,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0xB240000,0xB240000,0xB240000,0x3980000,0x23FC0000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1680000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,
-0x1BFC0000,0x91F80000,0x91F80000,0x91F80000,0xB2000001,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x91F80000,0x91F80000,0x91F80000,0xB2000001,0x91F80000,0x91F80000,0x91F80000,0xB2000001,0xB2000001,0x1800000,0x1680000,0x1680000,0x7A00000,0x1C40000,0x3E80000,0x3E80000,0x47FC0000,0x7A00000,0x1C40000,0x73FC0000,0x91F80000,
-0x73FC0000,0x1B00000,0x1B00000,0x1B00000,0x1B00000,0x89FC0000,0x89FC0000,0x89FC0000,0xC5FC0000,0xC5FC0000,0xD6000001,0x89FC0000,0x89FC0000,0x89FC0000,0xC5FC0000,0xC5FC0000,0xD6000001,0xC5FC0000,0xC5FC0000,0xD6000001,0xD6000001,0x89FC0000,0x89FC0000,0x89FC0000,0xC5FC0000,0xC5FC0000,0xD6000001,0xC5FC0000,0xC5FC0000,0xD6000001,0xD6000001,0xC5FC0000,
-0xC5FC0000,0xD6000001,0xD6000001,0xD6000001,0x5F40000,0x1CC0000,0x1B00000,0x6FFC0000,0xA1FC0000,0xB7FC0000,0xBFF80000,0xCBF80000,0x41FC0000,0x89FC0000,0xB7FC0000,0xD6000001,0xB7FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x18C1D49,0xFF7414EC,0xFF6C0E58,0xFF640BE8,0xFF681121,0xFF5408B8,0xFF50057D,0xFF400775,0xFB3C0394,0xEB3C066D,0xFF5C130E,0xFF40088F,0xFF30046C,0xFF20053D,0xFF180009,0xEB1C033A,0xFF140AFE,0xF30C03CA,0xE5080492,0xD9140AFE,0x4FFC1D47,0xFF2C10D8,0xFF180BE8,0xFEFC0B01,0xFEE403A5,0xEAF4066B,0xFED80D6E,0xFEA00289,0xE8B00322,0xD8C80AFE,0xA9FC1D47,
-0xFE280BE8,0xEA04066B,0xD6000B2E,0xC4001D47,0xFF7816B6,0xFD881AF5,0xFD881B85,0xFF5C0FB9,0xFF4808E2,0xFF2C02B1,0xFF240072,0xFB10002D,0xFF70165C,0xFF500E9A,0xFF0802CE,0xE8B00322,0x93FC1D47,0x1B00B01,0xFFA4072C,0xFF9403C9,0xFF8C0288,0xFF9806DD,0xFF7C0236,0xFF740055,0xFF700321,0xF7640084,0xEB6802F9,0x8DFC0AFE,0xFF64052B,0xFF540288,0xFF380471,0xFD200005,
-0xEB3002FA,0xC7FC0AFE,0xFEA00288,0xEA8402F9,0xD8000AFE,0x8DFC0AFE,0xFF64052B,0xFF540288,0xFF380471,0xFD200005,0xEB3002FA,0xC7FC0AFE,0xFEA00288,0xEA8402F9,0xD8000AFE,0xC7FC0AFE,0xFEA00288,0xEA8402F9,0xD8000AFE,0xD8000AFE,0xFFA0091B,0xFFAC0A29,0xFFAC0A2C,0xFF94070A,0xFF680489,0xFF480194,0xFF340005,0xFCFC0011,0xFF98091E,0xFF8406A8,0xFF1002BB,0xEA8402F9,
-0xB9FC0AFE,0x1640BE8,0x1640BE8,0x1640BE8,0x1640BE8,0xFF50057D,0xFF50057D,0xFF50057D,0xF3400374,0xF3400374,0xD73C0375,0xFF30046C,0xFF30046C,0xFF30046C,0xFF180009,0xFF180009,0xDB2000A6,0xE3140288,0xE3140288,0xD3100041,0xC514028A,0x15FC0BE8,0x15FC0BE8,0x15FC0BE8,0xFEE403A5,0xFEE403A5,0xD7080373,0xFCA80289,0xFCA80289,0xD8C80002,0xC6D8028A,0x8DFC0BE8,
-0x8DFC0BE8,0xD6580373,0xC420028A,0xB0000BEB,0xFF58088D,0xF9600A7D,0x1640BE8,0xFF4405A2,0xFF3402D2,0xFF2400E9,0xFF240072,0xF3140002,0xFD4C0845,0xFF300545,0xFF08028E,0xD8C80002,0x6FFC0BE8,0x18C0288,0x18C0288,0x18C0288,0x18C0288,0xFF740055,0xFF740055,0xFF740055,0xE9680000,0xE9680000,0xD7680001,0x53FC0288,0x53FC0288,0x53FC0288,0xF7280001,0xF7280001,
-0xD9440001,0xABF80288,0xABF80288,0xD6D80001,0xC400028A,0x53FC0288,0x53FC0288,0x53FC0288,0xF7280001,0xF7280001,0xD9440001,0xABF80288,0xABF80288,0xD6D80001,0xC400028A,0xABF80288,0xABF80288,0xD6D80001,0xC400028A,0xC400028A,0xF78001E1,0xFD880200,0x18C0288,0xFB70016D,0xFF5400AA,0xFF3C0034,0xFF340005,0xF5100000,0xFD7401E1,0xFF5C0145,0x95FC0288,0xD6D80001,
-0x95FC0288,0x1D802F9,0xFFC401CD,0xFFB80089,0xFFB00000,0xC3FC02F9,0xFFA00112,0xFF880001,0xE1FC02F9,0xFF100000,0xEA0002F9,0xC3FC02F9,0xFFA00112,0xFF880001,0xE1FC02F9,0xFF100000,0xEA0002F9,0xE1FC02F9,0xFF100000,0xEA0002F9,0xEA0002F9,0xC3FC02F9,0xFFA00112,0xFF880001,0xE1FC02F9,0xFF100000,0xEA0002F9,0xE1FC02F9,0xFF100000,0xEA0002F9,0xEA0002F9,0xE1FC02F9,
-0xFF100000,0xEA0002F9,0xEA0002F9,0xEA0002F9,0xFFD002AD,0x1F802F9,0xF3D402D4,0xFFC00244,0xFFA801CA,0xFF7000E8,0xFF3C0000,0xFED80000,0xF9D002AD,0xFDBC0244,0xFF580019,0xEA0002F9,0xDBFC02F9,0x13C0374,0x13C0374,0x13C0374,0x13C0374,0x13C0374,0x13C0374,0x13C0374,0x13C0374,0x13C0374,0x13C0374,0xFF180008,0xFF180008,0xFF180008,0xFF180008,0xFF180008,
-0xFF180008,0xC9140000,0xC9140000,0xC9140000,0xB3140001,0x1D80372,0x1D80372,0x1D80372,0x1D80372,0x1D80372,0x1D80372,0xD8C80001,0xD8C80001,0xD8C80001,0xB2EC0001,0x71F80372,0x71F80372,0x71F80372,0xB26C0001,0x9E000372,0xF5380288,0x13C0374,0x13C0374,0xFF2C0171,0xFF2800C8,0xFF1C0050,0xFF1C0050,0xF1140000,0xFF200239,0xFF200152,0xDF080000,0xD8C80001,
-0x4BFC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table153[] = {
-0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x3B00000,0x5DFC0000,
-0x5DFC0000,0x5DFC0000,0x5DFC0000,0x90000001,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1240000,0x1380000,0x1380000,0x1380000,0x3B00000,0x33FC0000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x1780000,0x35FC0000,0x35FC0000,0x35FC0000,0x35FC0000,0x35FC0000,
-0x35FC0000,0x9DF40000,0x9DF40000,0x9DF40000,0xBA000001,0x35FC0000,0x35FC0000,0x35FC0000,0x35FC0000,0x35FC0000,0x35FC0000,0x9DF40000,0x9DF40000,0x9DF40000,0xBA000001,0x9DF40000,0x9DF40000,0x9DF40000,0xBA000001,0xBA000001,0x1900000,0x1780000,0x1780000,0x3B40000,0x1D80000,0x5FC0000,0x5FC0000,0x5BFC0000,0x3B40000,0x1D80000,0x81FC0000,0x9DF40000,
-0x81FC0000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xD1FC0000,0xD1FC0000,0xDE000001,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xD1FC0000,0xD1FC0000,0xDE000001,0xD1FC0000,0xD1FC0000,0xDE000001,0xDE000001,0xA3FC0000,0xA3FC0000,0xA3FC0000,0xD1FC0000,0xD1FC0000,0xDE000001,0xD1FC0000,0xD1FC0000,0xDE000001,0xDE000001,0xD1FC0000,
-0xD1FC0000,0xDE000001,0xDE000001,0xDE000001,0x27FC0000,0x7DC0000,0x1C00000,0x8DFC0000,0xB3FC0000,0xC5FC0000,0xCBFC0000,0xD5FC0000,0x69FC0000,0xA3FC0000,0xC5FC0000,0xDE000001,0xC5FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x19819DD,0xFF801338,0xFF7C0DD1,0xFF740BE8,0xFF740F69,0xFF64088E,0xFF5C05E5,0xFF58068D,0xFD4C0378,0xEF4C0555,0xFF6810D2,0xFF4C0853,0xFF4404DA,0xFF380465,0xFF2C0029,0xF12C0235,0xFF2808DD,0xF51C032E,0xEB1C0319,0xDF2408CA,0x63FC19DB,0xFF380FF4,0xFF300BE8,0xFF1409E9,0xFEFC03ED,0xEF080553,0xFEF00B8E,0xFEC0029E,0xECC401FA,0xDED808CA,0xB3F819DB,
-0xFE580BE8,0xEE280553,0xDC0008D2,0xCA0019DB,0xFF801459,0xFF8C17D1,0xFF8C1891,0xFF700E65,0xFF50086A,0xFF3C02F4,0xFF3400D5,0xFD240006,0xFF7813DA,0xFF5C0D8F,0xFF1C02E2,0xECC401FA,0x9FF819DB,0x1BC08C9,0xFFB005F4,0xFFA00371,0xFF9C0288,0xFFA40569,0xFF9001F8,0xFF840088,0xFF7C0221,0xFB780034,0xEF7801E1,0x9BFC08C9,0xFF7C0473,0xFF6C0288,0xFF580362,0xFF380001,
-0xEF4401E2,0xCFF808C9,0xFED40288,0xEEA801E1,0xDE0008CA,0x9BFC08C9,0xFF7C0473,0xFF6C0288,0xFF580362,0xFF380001,0xEF4401E2,0xCFF808C9,0xFED40288,0xEEA801E1,0xDE0008CA,0xCFF808C9,0xFED40288,0xEEA801E1,0xDE0008CA,0xDE0008CA,0xFFB4074A,0xF5B80845,0xF7BC0849,0xFF9805B9,0xFF7C03C5,0xFF5C0171,0xFF500019,0xFF180001,0xFFA4076A,0xFF90057E,0xFF3002AE,0xEEA801E1,
-0xC1FC08C9,0x1740BE8,0x1740BE8,0x1740BE8,0x1740BE8,0xFF5C05E5,0xFF5C05E5,0xFF5C05E5,0xFB500374,0xFB500374,0xDF4C0375,0xFF4404DA,0xFF4404DA,0xFF4404DA,0xFF2C0029,0xFF2C0029,0xE33000A6,0xEB240288,0xEB240288,0xDB200041,0xCD24028A,0x2FFC0BE8,0x2FFC0BE8,0x2FFC0BE8,0xFEFC03ED,0xFEFC03ED,0xDF180373,0xFEC0029E,0xFEC0029E,0xE0D80002,0xCEE8028A,0x99FC0BE8,
-0x99FC0BE8,0xDE680373,0xCC30028A,0xB8000BEB,0xFF6808CE,0xFF6C0A8D,0x1740BE8,0xFF540625,0xFF440371,0xFF3C0164,0xFF3400D5,0xFB240002,0xFF58089A,0xFF5005B6,0xFF1C02B1,0xE0D80002,0x7FF80BE8,0x19C0288,0x19C0288,0x19C0288,0x19C0288,0xFF840088,0xFF840088,0xFF840088,0xF1780000,0xF1780000,0xDF780001,0x6BFC0288,0x6BFC0288,0x6BFC0288,0xFF380001,0xFF380001,
-0xE1540001,0xB7F80288,0xB7F80288,0xDEE80001,0xCC00028A,0x6BFC0288,0x6BFC0288,0x6BFC0288,0xFF380001,0xFF380001,0xE1540001,0xB7F80288,0xB7F80288,0xDEE80001,0xCC00028A,0xB7F80288,0xB7F80288,0xDEE80001,0xCC00028A,0xCC00028A,0xFF9001E1,0xF5980221,0x19C0288,0xFD840188,0xFF7000DD,0xFF580064,0xFF500019,0xFD200000,0xFD880200,0xFF740171,0xA3FC0288,0xDEE80001,
-0xA3FC0288,0x1E001E1,0xFFD00121,0xFFC80061,0xFFC00000,0xCFFC01E1,0xFFB800AA,0xFFA00001,0xE7FC01E1,0xFF400000,0xEE0001E1,0xCFFC01E1,0xFFB800AA,0xFFA00001,0xE7FC01E1,0xFF400000,0xEE0001E1,0xE7FC01E1,0xFF400000,0xEE0001E1,0xEE0001E1,0xCFFC01E1,0xFFB800AA,0xFFA00001,0xE7FC01E1,0xFF400000,0xEE0001E1,0xE7FC01E1,0xFF400000,0xEE0001E1,0xEE0001E1,0xE7FC01E1,
-0xFF400000,0xEE0001E1,0xEE0001E1,0xEE0001E1,0xFFD001BD,0x7FC01E1,0xF7DC01C4,0xFFC80179,0xFFBC0122,0xFF900092,0xFF640000,0xFF140000,0xFDD801A5,0xFFC00164,0xFF780010,0xEE0001E1,0xE1FC01E1,0x14C0374,0x14C0374,0x14C0374,0x14C0374,0x14C0374,0x14C0374,0x14C0374,0x14C0374,0x14C0374,0x14C0374,0xFF28001D,0xFF28001D,0xFF28001D,0xFF28001D,0xFF28001D,
-0xFF28001D,0xD1240000,0xD1240000,0xD1240000,0xBB240001,0x1F00372,0x1F00372,0x1F00372,0x1F00372,0x1F00372,0x1F00372,0xE0D80001,0xE0D80001,0xE0D80001,0xBAFC0001,0x7DF80372,0x7DF80372,0x7DF80372,0xBA7C0001,0xA6000372,0xFD480288,0x14C0374,0x14C0374,0xFF3C0190,0xFF3400E9,0xFF340071,0xFF340071,0xF9240000,0xFD380244,0xFF34016D,0xE7180000,0xE0D80001,
-0x5BFC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table154[] = {
-0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0x69FC0000,
-0x69FC0000,0x69FC0000,0x69FC0000,0x98000001,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1340000,0x1480000,0x1480000,0x1480000,0x1C80000,0x41FC0000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x4DFC0000,
-0x4DFC0000,0xA7FC0000,0xA7FC0000,0xA7FC0000,0xC2000001,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0x4DFC0000,0xA7FC0000,0xA7FC0000,0xA7FC0000,0xC2000001,0xA7FC0000,0xA7FC0000,0xA7FC0000,0xC2000001,0xC2000001,0x9A00000,0x1880000,0x1880000,0x1C80000,0x1EC0000,0x23FC0000,0x23FC0000,0x6FFC0000,0x1C80000,0x1EC0000,0x91FC0000,0xA7FC0000,
-0x91FC0000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0xBBFC0000,0xBBFC0000,0xBBFC0000,0xDDFC0000,0xDDFC0000,0xE6000001,0xBBFC0000,0xBBFC0000,0xBBFC0000,0xDDFC0000,0xDDFC0000,0xE6000001,0xDDFC0000,0xDDFC0000,0xE6000001,0xE6000001,0xBBFC0000,0xBBFC0000,0xBBFC0000,0xDDFC0000,0xDDFC0000,0xE6000001,0xDDFC0000,0xDDFC0000,0xE6000001,0xE6000001,0xDDFC0000,
-0xDDFC0000,0xE6000001,0xE6000001,0xE6000001,0x5FFC0000,0xFEC0000,0x1D00000,0xABFC0000,0xC7FC0000,0xD5FC0000,0xD9FC0000,0xE1F40000,0x91FC0000,0xBBFC0000,0xD5FC0000,0xE6000001,0xD5FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1A416D1,0xFF981198,0xFF880D5D,0xFF840BE8,0xFF800E01,0xFF740886,0xFF740675,0xFF6405F9,0xFF60037D,0xF35C047D,0xFF740EFE,0xFF64082B,0xFF5C056A,0xFF4C03FE,0xFF40007D,0xF53C016E,0xFF38072E,0xF93002C2,0xEF3001F9,0xE33406EA,0x75FC16CF,0xFF580F0C,0xFF480BE8,0xFF2C0911,0xFF20044D,0xF31C047B,0xFF080A0E,0xFEE402DE,0xF2DC0112,0xE2EC06EA,0xBBFC16CF,
-0xFE880BE8,0xF248047B,0xE20806EA,0xD00016CF,0xFF8C1241,0xF9A0153D,0xF9A015C4,0xFF800D27,0xFF68080D,0xFF54034B,0xFF4C015D,0xFF38000D,0xFF9011EA,0xFF740C8A,0xFF340318,0xF2DC0112,0xA9FC16CF,0x1C806E9,0xFFBC04EC,0xFFAC0331,0xFFAC0288,0xFFB0043D,0xFFA001C2,0xFF9800B9,0xFF940169,0xFD880008,0xF3880109,0xAFFC06E9,0xFF9403DB,0xFF840288,0xFF70028A,0xFF580019,
-0xF358010A,0xD7FC06E9,0xFF040288,0xF2C80109,0xE20006EA,0xAFFC06E9,0xFF9403DB,0xFF840288,0xFF70028A,0xFF580019,0xF358010A,0xD7FC06E9,0xFF040288,0xF2C80109,0xE20006EA,0xD7FC06E9,0xFF040288,0xF2C80109,0xE20006EA,0xE20006EA,0xFFBC05CD,0xFBC4066D,0xFBC40681,0xFFB004A6,0xFF900329,0xFF7C0153,0xFF680041,0xFF380009,0xFFB405D6,0xFFA40482,0xFF5002A1,0xF2C80109,
-0xCDFC06E9,0x1840BE8,0x1840BE8,0x1840BE8,0x1840BE8,0xFF740675,0xFF740675,0xFF740675,0xFF60037D,0xFF60037D,0xE75C0375,0xFF5C056A,0xFF5C056A,0xFF5C056A,0xFF40007D,0xFF40007D,0xEB4000A6,0xF3340288,0xF3340288,0xE3300041,0xD534028A,0x47FC0BE8,0x47FC0BE8,0x47FC0BE8,0xFF20044D,0xFF20044D,0xE7280373,0xFEE402DE,0xFEE402DE,0xE8E80002,0xD6F8028A,0xA5F80BE8,
-0xA5F80BE8,0xE6780373,0xD440028A,0xC0000BEB,0xFF740934,0xF9800AC4,0x1840BE8,0xFF6806BD,0xFF580419,0xFF4C021D,0xFF4C015D,0xFF38000D,0xFD70090C,0xFF5C0656,0xFF3402F4,0xE8E80002,0x8DFC0BE8,0x1AC0288,0x1AC0288,0x1AC0288,0x1AC0288,0xFF9800B9,0xFF9800B9,0xFF9800B9,0xF9880000,0xF9880000,0xE7880001,0x83FC0288,0x83FC0288,0x83FC0288,0xFF580019,0xFF580019,
-0xE9640001,0xC3F80288,0xC3F80288,0xE6F80001,0xD400028A,0x83FC0288,0x83FC0288,0x83FC0288,0xFF580019,0xFF580019,0xE9640001,0xC3F80288,0xC3F80288,0xE6F80001,0xD400028A,0xC3F80288,0xC3F80288,0xE6F80001,0xD400028A,0xD400028A,0xFFA00202,0xFDA80221,0x1AC0288,0xFF9801A5,0xFF84010D,0xFF740091,0xFF680041,0xFF380009,0xFF940212,0xFB9001A5,0xB3FC0288,0xE6F80001,
-0xB3FC0288,0x1E80109,0xFFDC009D,0xFFD80034,0xFFD00000,0xDBFC0109,0xFFCC0064,0xFFB80001,0xEDFC0109,0xFF700000,0xF2000109,0xDBFC0109,0xFFCC0064,0xFFB80001,0xEDFC0109,0xFF700000,0xF2000109,0xEDFC0109,0xFF700000,0xF2000109,0xF2000109,0xDBFC0109,0xFFCC0064,0xFFB80001,0xEDFC0109,0xFF700000,0xF2000109,0xEDFC0109,0xFF700000,0xF2000109,0xF2000109,0xEDFC0109,
-0xFF700000,0xF2000109,0xF2000109,0xF2000109,0xFBE400F2,0x47FC0109,0xFBE400F4,0xFFD800CA,0xFFD000A2,0xFFAC0050,0xFF8C0000,0xFF500000,0xFFDC00E1,0xFFD800C8,0xFF9C0009,0xF2000109,0xE9FC0109,0x15C0374,0x15C0374,0x15C0374,0x15C0374,0x15C0374,0x15C0374,0x15C0374,0x15C0374,0x15C0374,0x15C0374,0xFF3C0034,0xFF3C0034,0xFF3C0034,0xFF3C0034,0xFF3C0034,
-0xFF3C0034,0xD9340000,0xD9340000,0xD9340000,0xC3340001,0xDFC0372,0xDFC0372,0xDFC0372,0xDFC0372,0xDFC0372,0xDFC0372,0xE8E80001,0xE8E80001,0xE8E80001,0xC30C0001,0x89F80372,0x89F80372,0x89F80372,0xC28C0001,0xAE000372,0xF55802AD,0x15C0374,0x15C0374,0xFF4C01B1,0xFD4C0120,0xFF440091,0xFF440091,0xFF340001,0xF94C0265,0xFB4801A5,0xEF280000,0xE8E80001,
-0x69FC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table155[] = {
-0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1E00000,0x1E00000,0x1E00000,0x1E00000,0x1E00000,0x1E00000,0x1E00000,0x1E00000,0x1E00000,0x1E00000,0x75FC0000,
-0x75FC0000,0x75FC0000,0x75FC0000,0xA0000001,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x5580000,0x5580000,0x5580000,0x1E00000,0x51FC0000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x1980000,0x65FC0000,0x65FC0000,0x65FC0000,0x65FC0000,0x65FC0000,
-0x65FC0000,0xB3FC0000,0xB3FC0000,0xB3FC0000,0xCA000001,0x65FC0000,0x65FC0000,0x65FC0000,0x65FC0000,0x65FC0000,0x65FC0000,0xB3FC0000,0xB3FC0000,0xB3FC0000,0xCA000001,0xB3FC0000,0xB3FC0000,0xB3FC0000,0xCA000001,0xCA000001,0x1B40000,0x1980000,0x1980000,0x5D80000,0x7FC0000,0x41FC0000,0x41FC0000,0x83FC0000,0x5D80000,0x7FC0000,0x9FFC0000,0xB3FC0000,
-0x9FFC0000,0x1E00000,0x1E00000,0x1E00000,0x1E00000,0xD3FC0000,0xD3FC0000,0xD3FC0000,0xE9FC0000,0xE9FC0000,0xEE000001,0xD3FC0000,0xD3FC0000,0xD3FC0000,0xE9FC0000,0xE9FC0000,0xEE000001,0xE9FC0000,0xE9FC0000,0xEE000001,0xEE000001,0xD3FC0000,0xD3FC0000,0xD3FC0000,0xE9FC0000,0xE9FC0000,0xEE000001,0xE9FC0000,0xE9FC0000,0xEE000001,0xEE000001,0xE9FC0000,
-0xE9FC0000,0xEE000001,0xEE000001,0xEE000001,0x97FC0000,0x17FC0000,0x1E00000,0xC9FC0000,0xDBFC0000,0xE3FC0000,0xE7F80000,0xEBF80000,0xB7FC0000,0xD3FC0000,0xE3FC0000,0xEE000001,0xE3FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1B01425,0xFFA4102C,0xFF940D09,0xFF940BE8,0xFF980CD1,0xFF840898,0xFF8006ED,0xFF7C05B1,0xFF7003B4,0xF76C03E5,0xFF8C0D6E,0xFF74082B,0xFF68060E,0xFF6403D6,0xFF54010D,0xF95000EA,0xFF4C0601,0xFD44028E,0xF53C011D,0xE944055E,0x87FC1423,0xFF700E44,0xFF600BE8,0xFF4C089F,0xFF3804C5,0xF73003E3,0xFF2008EE,0xFEFC034E,0xF6F00072,0xE900055E,0xC5F81423,
-0xFEB80BE8,0xF66803E3,0xE820055E,0xD6001423,0xFFA0103F,0xFFAC12A9,0xFFAC133C,0xFF940C5A,0xFF7807F2,0xFF6803C5,0xFF5C0214,0xFF48005E,0xFF981017,0xFF800B9F,0xFF50039A,0xF6F00072,0xB5FC1423,0x1D00561,0xFFC40411,0xFFC002F4,0xFFBC0288,0xFFBC0359,0xFFB001B2,0xFFA80104,0xFFA000F1,0xFF980004,0xF7980071,0xBDFC055E,0xFFAC0363,0xFF9C0288,0xFF8801F2,0xFF700049,
-0xF76C0072,0xDFF8055E,0xFF340288,0xF6E80071,0xE800055E,0xBDFC055E,0xFFAC0363,0xFF9C0288,0xFF8801F2,0xFF700049,0xF76C0072,0xDFF8055E,0xFF340288,0xF6E80071,0xE800055E,0xDFF8055E,0xFF340288,0xF6E80071,0xE800055E,0xE800055E,0xFDCC049A,0xFFCC04F5,0xFFCC0519,0xFFC003C4,0xFFA402B5,0xFF90016B,0xFF7C0082,0xFF640032,0xFFC4049D,0xFFB003C2,0xFF700298,0xF6E80071,
-0xD7FC055E,0x1940BE8,0x1940BE8,0x1940BE8,0x1940BE8,0xFF8006ED,0xFF8006ED,0xFF8006ED,0xFF7003B4,0xFF7003B4,0xEF6C0375,0xFF68060E,0xFF68060E,0xFF68060E,0xFF54010D,0xFF54010D,0xF35000A6,0xFB440288,0xFB440288,0xEB400041,0xDD44028A,0x5FFC0BE8,0x5FFC0BE8,0x5FFC0BE8,0xFF3804C5,0xFF3804C5,0xEF380373,0xFEFC034E,0xFEFC034E,0xF0F80002,0xDF08028A,0xB1F80BE8,
-0xB1F80BE8,0xEE880373,0xDC50028A,0xC8000BEB,0xFF84097D,0xFF8C0AD8,0x1940BE8,0xFF80074E,0xFF6C04D1,0xFF6002D9,0xFF5C0214,0xFF48005E,0xFF800956,0xFF7406E1,0xFF500381,0xF0F80002,0x9DF80BE8,0x1BC0288,0x1BC0288,0x1BC0288,0x1BC0288,0xFFA80104,0xFFA80104,0xFFA80104,0xFF980004,0xFF980004,0xEF980001,0x9BFC0288,0x9BFC0288,0x9BFC0288,0xFF700049,0xFF700049,
-0xF1740001,0xCFF80288,0xCFF80288,0xEF080001,0xDC00028A,0x9BFC0288,0x9BFC0288,0x9BFC0288,0xFF700049,0xFF700049,0xF1740001,0xCFF80288,0xCFF80288,0xEF080001,0xDC00028A,0xCFF80288,0xCFF80288,0xEF080001,0xDC00028A,0xDC00028A,0xFBB40221,0xF5B80244,0x1BC0288,0xFFA401D4,0xFF980145,0xFF8C00E1,0xFF7C0082,0xFF640032,0xFDB00221,0xFFA401C2,0xC1FC0288,0xEF080001,
-0xC1FC0288,0x1F00071,0xFFE80041,0xFFE40014,0xFFE00000,0xE9FC0071,0xFFD80028,0xFFD00000,0xF3FC0071,0xFFA00000,0xF6000071,0xE9FC0071,0xFFD80028,0xFFD00000,0xF3FC0071,0xFFA00000,0xF6000071,0xF3FC0071,0xFFA00000,0xF6000071,0xF6000071,0xE9FC0071,0xFFD80028,0xFFD00000,0xF3FC0071,0xFFA00000,0xF6000071,0xF3FC0071,0xFFA00000,0xF6000071,0xF6000071,0xF3FC0071,
-0xFFA00000,0xF6000071,0xF6000071,0xF6000071,0xFFEC0062,0x87FC0071,0xFFEC0064,0xFDE80055,0xFDE40048,0xFFC8001D,0xFFB40000,0xFF8C0000,0xFDEC0062,0xFFE40055,0xFFBC0004,0xF6000071,0xF1FC0071,0x16C0374,0x16C0374,0x16C0374,0x16C0374,0x16C0374,0x16C0374,0x16C0374,0x16C0374,0x16C0374,0x16C0374,0xFF500055,0xFF500055,0xFF500055,0xFF500055,0xFF500055,
-0xFF500055,0xE1440000,0xE1440000,0xE1440000,0xCB440001,0x25FC0372,0x25FC0372,0x25FC0372,0x25FC0372,0x25FC0372,0x25FC0372,0xF0F80001,0xF0F80001,0xF0F80001,0xCB1C0001,0x95F80372,0x95F80372,0x95F80372,0xCA9C0001,0xB6000372,0xFD6802AD,0x16C0374,0x16C0374,0xFD6401E1,0xFF580145,0xFF5400B9,0xFF5400B9,0xFF48000D,0xFF580271,0xFF5001BD,0xF7380000,0xF0F80001,
-0x79FC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table156[] = {
-0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x1FC0000,0x83F80000,
-0x83F80000,0x83F80000,0x83F80000,0xAA000000,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x1540001,0x16C0000,0x16C0000,0x16C0000,0x1FC0000,0x61FC0000,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,
-0x81FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xD4000000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0x81FC0000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xD4000000,0xC1FC0000,0xC1FC0000,0xC1FC0000,0xD4000000,0xD4000000,0xBC40000,0x1A80001,0x1A80001,0x1F00000,0x33FC0000,0x63FC0000,0x63FC0000,0x99FC0000,0x1F00000,0x33FC0000,0xB1FC0000,0xC1FC0000,
-0xB1FC0000,0x1F00001,0x1F00001,0x1F00001,0x1F00001,0xEFFC0000,0xEFFC0000,0xEFFC0000,0xF7F80000,0xF7F80000,0xF8000000,0xEFFC0000,0xEFFC0000,0xEFFC0000,0xF7F80000,0xF7F80000,0xF8000000,0xF7F80000,0xF7F80000,0xF8000000,0xF8000000,0xEFFC0000,0xEFFC0000,0xEFFC0000,0xF7F80000,0xF7F80000,0xF8000000,0xF7F80000,0xF7F80000,0xF8000000,0xF8000000,0xF7F80000,
-0xF7F80000,0xF8000000,0xF8000000,0xF8000000,0xD7FC0000,0xA7FC0000,0x1F00001,0xEBFC0000,0xF1FC0000,0xF5FC0000,0xF5FC0000,0xF7FC0000,0xE3FC0000,0xEFFC0000,0xF5FC0000,0xF8000000,0xF5FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1BC1194,0xFFB00ED7,0xFFAC0CAC,0xFFA40BEB,0xFFA40BBE,0xFF9808C3,0xFF9807A2,0xFF8805A4,0xFF88043B,0xFB800386,0xFF980C15,0xFF8C0852,0xFF8006C9,0xFF7003FF,0xFF6C01EE,0xFD6400A9,0xFF64052C,0xFF58029B,0xF950007E,0xEF540409,0x9BFC1194,0xFF880D81,0xFF7C0BE8,0xFF64083E,0xFF58058D,0xFD440386,0xFF380829,0xFF2003F9,0xFB080015,0xEF140408,0xCFF81194,
-0xFEF00BE8,0xFA8C0386,0xEE400408,0xDC001198,0xFFB40EBF,0xF5B810AC,0xF7BC1114,0xFF980B8A,0xFF8C0803,0xFF7C0476,0xFF78030B,0xFF640105,0xFDB00E9B,0xFF980AFA,0xFF640451,0xFB080015,0xC1FC1194,0x1DC040B,0xFFD4035E,0xFFCC02CA,0xFFCC028A,0xFFD0029B,0xFFC401B6,0xFFBC0151,0xFFB800C3,0xFFAC0032,0xFBA80015,0xCFFC0408,0xFFC002FE,0xFFB80288,0xFFA00196,0xFF94009D,
-0xFB840014,0xE7FC0408,0xFF6C0288,0xFB0C0014,0xEE000408,0xCFFC0408,0xFFC002FE,0xFFB80288,0xFFA00196,0xFF94009D,0xFB840014,0xE7FC0408,0xFF6C0288,0xFB0C0014,0xEE000408,0xE7FC0408,0xFF6C0288,0xFB0C0014,0xEE000408,0xEE000408,0xFFD80385,0xF7DC03D5,0xF7DC03EA,0xFDD00321,0xFFC0025A,0xFFA80179,0xFFA000DA,0xFF7C0082,0xFFD00395,0xFFC802E4,0xFF980291,0xFB0C0014,
-0xE1FC0408,0x1A40BEB,0x1A40BEB,0x1A40BEB,0x1A40BEB,0xFF9807A2,0xFF9807A2,0xFF9807A2,0xFF88043B,0xFF88043B,0xF9800372,0xFF8006C9,0xFF8006C9,0xFF8006C9,0xFF6C01EE,0xFF6C01EE,0xFD6400A5,0xFF58029B,0xFF58029B,0xF5540042,0xE7540289,0x7BFC0BE8,0x7BFC0BE8,0x7BFC0BE8,0xFF58058D,0xFF58058D,0xF9480372,0xFF2003F9,0xFF2003F9,0xF9080005,0xE71C0288,0xBFF80BE8,
-0xBFF80BE8,0xF8940372,0xE6600288,0xD2000BE8,0xFFA009E1,0xFBA40B0A,0x1A40BEB,0xFF9007E6,0xFF8005BA,0xFF7803C3,0xFF78030B,0xFF640105,0xFF9409A4,0xFF8007C1,0xFF640438,0xF9080005,0xADFC0BE8,0x1CC028A,0x1CC028A,0x1CC028A,0x1CC028A,0xFFBC0151,0xFFBC0151,0xFFBC0151,0xFFAC0032,0xFFAC0032,0xF9A80001,0xB7FC0288,0xB7FC0288,0xB7FC0288,0xFF94009D,0xFF94009D,
-0xF9880000,0xDDF40288,0xDDF40288,0xF9140000,0xE6000288,0xB7FC0288,0xB7FC0288,0xB7FC0288,0xFF94009D,0xFF94009D,0xF9880000,0xDDF40288,0xDDF40288,0xF9140000,0xE6000288,0xDDF40288,0xDDF40288,0xF9140000,0xE6000288,0xE6000288,0xFDC80242,0xFFCC0242,0x1CC028A,0xFDC00202,0xFFAC0195,0xFFA80128,0xFFA000DA,0xFF7C0082,0xFFC40242,0xFBC00200,0xD3FC0288,0xF9140000,
-0xD3FC0288,0x1F80012,0xFFF4000A,0xFFF00005,0xFFF00001,0xF7FC0012,0xFFF00005,0xFFEC0000,0xFBFC0012,0xFFD80000,0xFA000014,0xF7FC0012,0xFFF00005,0xFFEC0000,0xFBFC0012,0xFFD80000,0xFA000014,0xFBFC0012,0xFFD80000,0xFA000014,0xFA000014,0xF7FC0012,0xFFF00005,0xFFEC0000,0xFBFC0012,0xFFD80000,0xFA000014,0xFBFC0012,0xFFD80000,0xFA000014,0xFA000014,0xFBFC0012,
-0xFFD80000,0xFA000014,0xFA000014,0xFA000014,0xFFF8000D,0xD7FC0012,0xF5F80012,0xFFF4000D,0xFDF4000D,0xFFE80005,0xFFE00000,0xFFD00000,0xF5FC0012,0xFFF00011,0xFFE40001,0xFA000014,0xFBFC0012,0x1800372,0x1800372,0x1800372,0x1800372,0x1800372,0x1800372,0x1800372,0x1800372,0x1800372,0x1800372,0xFF680091,0xFF680091,0xFF680091,0xFF680091,0xFF680091,
-0xFF680091,0xE9580001,0xE9580001,0xE9580001,0xD5540001,0x41FC0372,0x41FC0372,0x41FC0372,0x41FC0372,0x41FC0372,0x41FC0372,0xFB080001,0xFB080001,0xFB080001,0xD52C0000,0xA1FC0372,0xA1FC0372,0xA1FC0372,0xD4A80000,0xBE000374,0xF77C02D2,0x1800372,0x1800372,0xFF740202,0xFF6C0179,0xFF6800FA,0xFF6800FA,0xFF5C002D,0xFD70028A,0xFF6401F9,0xFD4C0001,0xFB080001,
-0x89FC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table157[] = {
-0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x19FC0000,0x8FF80000,
-0x8FF80000,0x8FF80000,0x8FF80000,0xB2000000,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x1640001,0x77C0000,0x77C0000,0x77C0000,0x19FC0000,0x71FC0000,0x1B80001,0x1B80001,0x1B80001,0x1B80001,0x1B80001,0x1B80001,0x1B80001,0x1B80001,0x1B80001,0x1B80001,0x99FC0000,0x99FC0000,0x99FC0000,0x99FC0000,0x99FC0000,
-0x99FC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xDC000000,0x99FC0000,0x99FC0000,0x99FC0000,0x99FC0000,0x99FC0000,0x99FC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xDC000000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xDC000000,0xDC000000,0x1D80000,0x1B80001,0x1B80001,0x11FC0000,0x5BFC0000,0x81FC0000,0x81FC0000,0xADFC0000,0x11FC0000,0x5BFC0000,0xBFFC0000,0xCDFC0000,
-0xBFFC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1C80F44,0xFFBC0D5F,0xFFB80BD4,0xFFB40B53,0xFFB00ABA,0xFFA4089F,0xFFA407BE,0xFFA005B4,0xFF94049B,0xFF900372,0xFFA40AD9,0xFF980816,0xFF9806F5,0xFF880417,0xFF7C0296,0xFF7400C1,0xFF7C0494,0xFF7002A3,0xFD64003A,0xF3640305,0xABFC0F44,0xFF940C75,0xFF900B53,0xFF7C07D6,0xFF7005E5,0xFF580374,0xFF580773,0xFF380455,0xFF200005,0xF3280304,0xD7F80F44,
-0xFF1C0B53,0xFEAC0372,0xF2600304,0xE2000F44,0xFFBC0CF6,0xFBC40E6C,0xFBC40EDC,0xFFAC0A8E,0xFF9C07CB,0xFF9004FA,0xFF8803B2,0xFF7401A6,0xFFB40CB7,0xFFA40A4C,0xFF780483,0xFF200005,0xCBFC0F44,0x1E80303,0xFFE002AE,0xFFE00263,0xFFDC0242,0xFFDC0213,0xFFD0019A,0xFFD0015A,0xFFC000D1,0xFFC0006D,0xFFB80001,0xDFFC0303,0xFFCC0282,0xFFCC0242,0xFFB80156,0xFFAC00CD,
-0xFF980000,0xEFFC0303,0xFF940242,0xFF2C0000,0xF2000304,0xDFFC0303,0xFFCC0282,0xFFCC0242,0xFFB80156,0xFFAC00CD,0xFF980000,0xEFFC0303,0xFF940242,0xFF2C0000,0xF2000304,0xEFFC0303,0xFF940242,0xFF2C0000,0xF2000304,0xF2000304,0xFFE402C1,0xFBE402D9,0xFDE802EE,0xFFDC025D,0xFFD40202,0xFFB80171,0xFFB80104,0xFFA000B4,0xFFDC02BD,0xFFDC025A,0xFFB40246,0xFF2C0000,
-0xEBFC0303,0x1B40B53,0x1B40B53,0x1B40B53,0x1B40B53,0xFFA407BE,0xFFA407BE,0xFFA407BE,0xFF94049B,0xFF94049B,0xFF900372,0xFF9806F5,0xFF9806F5,0xFF9806F5,0xFF7C0296,0xFF7C0296,0xFF7400C1,0xFF7002A3,0xFF7002A3,0xFB600032,0xED640245,0x8FFC0B53,0x8FFC0B53,0x8FFC0B53,0xFF7005E5,0xFF7005E5,0xFF580374,0xFF380455,0xFF380455,0xFF200005,0xED2C0244,0xC9F80B53,
-0xC9F80B53,0xFEAC0372,0xEC780244,0xDA000B54,0xFFAC09A2,0xFFAC0A9E,0x1B40B53,0xFFA4081B,0xFF940612,0xFF900481,0xFF8803B2,0xFF7401A6,0xFFA0097D,0xFF9807C5,0xFF780473,0xFF200005,0xBBFC0B53,0x1DC0242,0x1DC0242,0x1DC0242,0x1DC0242,0xFFD0015A,0xFFD0015A,0xFFD0015A,0xFFC0006D,0xFFC0006D,0xFFB80001,0xCDFC0242,0xCDFC0242,0xCDFC0242,0xFFAC00CD,0xFFAC00CD,
-0xFF980000,0xE7F80242,0xE7F80242,0xFF2C0000,0xEC000244,0xCDFC0242,0xCDFC0242,0xCDFC0242,0xFFAC00CD,0xFFAC00CD,0xFF980000,0xE7F80242,0xE7F80242,0xFF2C0000,0xEC000244,0xE7F80242,0xE7F80242,0xFF2C0000,0xEC000244,0xEC000244,0xFFD80200,0xF7DC0221,0x1DC0242,0xFBD401E1,0xFFC80190,0xFFB80140,0xFFB80104,0xFFA000B4,0xFFD00208,0xFFC801D4,0xDFFC0242,0xFF2C0000,
-0xDFFC0242,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1900372,0x1900372,0x1900372,0x1900372,0x1900372,0x1900372,0x1900372,0x1900372,0x1900372,0x1900372,0xFF7400C1,0xFF7400C1,0xFF7400C1,0xFF7400C1,0xFF7400C1,
-0xFF7400C1,0xF1680001,0xF1680001,0xF1680001,0xDD640001,0x59FC0372,0x59FC0372,0x59FC0372,0x59FC0372,0x59FC0372,0x59FC0372,0xFF200005,0xFF200005,0xFF200005,0xDD3C0000,0xADFC0372,0xADFC0372,0xADFC0372,0xDCB80000,0xC6000374,0xFF8C02D2,0x1900372,0x1900372,0xFF840225,0xFF8001A9,0xFF780132,0xFF780132,0xFF700059,0xF98402AD,0xFF780212,0xFF60000D,0xFF200005,
-0x99FC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table158[] = {
-0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x31FC0000,0x9BF80000,
-0x9BF80000,0x9BF80000,0x9BF80000,0xBA000000,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0x1740001,0xF8C0000,0xF8C0000,0xF8C0000,0x31FC0000,0x7FFC0000,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0x1C80001,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xB1FC0000,
-0xB1FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xE4000000,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xB1FC0000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xE4000000,0xD9FC0000,0xD9FC0000,0xD9FC0000,0xE4000000,0xE4000000,0x1E80000,0x1C80001,0x1C80001,0x49FC0000,0x81FC0000,0x9FFC0000,0x9FFC0000,0xC1FC0000,0x49FC0000,0x81FC0000,0xCFFC0000,0xD9FC0000,
-0xCFFC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1D00C14,0xFFC40AAC,0xFFC00997,0xFFC00933,0xFFBC08C2,0xFFB4073B,0xFFB00696,0xFFAC050C,0xFFA00453,0xFFA00372,0xFFB00891,0xFFA40686,0xFFA405A5,0xFF940387,0xFF900266,0xFF8C0109,0xFF880354,0xFF7C01DB,0xFF74000A,0xF77401C5,0xB7FC0C14,0xFFAC09FD,0xFFA00934,0xFF8806A6,0xFF7C053D,0xFF700374,0xFF7005BB,0xFF58036A,0xFF380025,0xF73C01C4,0xDDF40C14,
-0xFF400933,0xFEE00372,0xF68001C4,0xE6000C14,0xFFC40A74,0xFFCC0B5C,0xFFCC0BBC,0xFFBC089D,0xFFAC066B,0xFF98043E,0xFF900351,0xFF840195,0xFFBC0A41,0xFFB00837,0xFF9003AD,0xFF380025,0xD3FC0C14,0x1EC01C3,0xFFE8018B,0xFFE40162,0xFFE40152,0xFFE00141,0xFFDC00EE,0xFFDC00CA,0xFFD80079,0xFFCC0041,0xFFC80001,0xE5FC01C3,0xFFD80176,0xFFD80152,0xFFCC00D1,0xFFB8007D,
-0xFFB00000,0xF3F801C3,0xFFAC0152,0xFF600000,0xF60001C4,0xE5FC01C3,0xFFD80176,0xFFD80152,0xFFCC00D1,0xFFB8007D,0xFFB00000,0xF3F801C3,0xFFAC0152,0xFF600000,0xF60001C4,0xF3F801C3,0xFFAC0152,0xFF600000,0xF60001C4,0xF60001C4,0xFBEC01A1,0xFFEC01A1,0xFFEC01B2,0xFFDC016D,0xFFDC0125,0xFFD000E3,0xFFC8009D,0xFFB8006A,0xF9EC01A1,0xFFDC015A,0xFFC80156,0xFF600000,
-0xEFFC01C3,0x1C00933,0x1C00933,0x1C00933,0x1C00933,0xFFB00696,0xFFB00696,0xFFB00696,0xFFA00453,0xFFA00453,0xFFA00372,0xFFA405A5,0xFFA405A5,0xFFA405A5,0xFF900266,0xFF900266,0xFF8C0109,0xFF7C01DB,0xFF7C01DB,0xFD740009,0xF1740155,0xA3FC0933,0xA3FC0933,0xA3FC0933,0xFF7C053D,0xFF7C053D,0xFF700374,0xFF58036A,0xFF58036A,0xFF380025,0xF1400154,0xD1FC0933,
-0xD1FC0933,0xFEE00372,0xF0980154,0xDE000934,0xFFBC07F2,0xF7BC08BB,0x1C00933,0xFFAC06AE,0xFFA00542,0xFF9803DA,0xFF900351,0xFF840195,0xFFB407AE,0xFFB0067E,0xFF9003A4,0xFF380025,0xC5FC0933,0x1E40152,0x1E40152,0x1E40152,0x1E40152,0xFFDC00CA,0xFFDC00CA,0xFFDC00CA,0xFFCC0041,0xFFCC0041,0xFFC80001,0xD9FC0152,0xD9FC0152,0xD9FC0152,0xFFB8007D,0xFFB8007D,
-0xFFB00000,0xEDF80152,0xEDF80152,0xFF600000,0xF0000154,0xD9FC0152,0xD9FC0152,0xD9FC0152,0xFFB8007D,0xFFB8007D,0xFFB00000,0xEDF80152,0xEDF80152,0xFF600000,0xF0000154,0xEDF80152,0xEDF80152,0xFF600000,0xF0000154,0xF0000154,0xF7E40139,0xFBE40139,0x1E40152,0xFFDC0109,0xFFD400E1,0xFFD000CA,0xFFC8009D,0xFFB8006A,0xF5E40139,0xFFDC0109,0xE7FC0152,0xFF600000,
-0xE7FC0152,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1A00372,0x1A00372,0x1A00372,0x1A00372,0x1A00372,0x1A00372,0x1A00372,0x1A00372,0x1A00372,0x1A00372,0xFF8C0109,0xFF8C0109,0xFF8C0109,0xFF8C0109,0xFF8C0109,
-0xFF8C0109,0xF9780001,0xF9780001,0xF9780001,0xE5740001,0x71FC0372,0x71FC0372,0x71FC0372,0x71FC0372,0x71FC0372,0x71FC0372,0xFF380025,0xFF380025,0xFF380025,0xE54C0000,0xB9FC0372,0xB9FC0372,0xB9FC0372,0xE4C80000,0xCE000374,0xF79C02F9,0x1A00372,0x1A00372,0xFF900262,0xFF9401E1,0xFF90016D,0xFF90016D,0xFF800092,0xFF9002B9,0xFD900244,0xFF74002D,0xFF380025,
-0xA7FC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table159[] = {
-0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x49FC0000,0x49FC0000,0x49FC0000,0x49FC0000,0x49FC0000,0x49FC0000,0x49FC0000,0x49FC0000,0x49FC0000,0x49FC0000,0xA7F80000,
-0xA7F80000,0xA7F80000,0xA7F80000,0xC2000000,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1840001,0x1A00000,0x1A00000,0x1A00000,0x49FC0000,0x8FFC0000,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0x1D80001,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xC9FC0000,
-0xC9FC0000,0xE5F80000,0xE5F80000,0xE5F80000,0xEC000000,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xC9FC0000,0xE5F80000,0xE5F80000,0xE5F80000,0xEC000000,0xE5F80000,0xE5F80000,0xE5F80000,0xEC000000,0xEC000000,0x5F80000,0x1D80001,0x1D80001,0x83FC0000,0xA9FC0000,0xBDFC0000,0xBDFC0000,0xD3FC0000,0x83FC0000,0xA9FC0000,0xDFF80000,0xE5F80000,
-0xDFF80000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1D80964,0xFFD00864,0xFFCC07AB,0xFFC8076B,0xFFC4070C,0xFFC40607,0xFFBC059E,0xFFB80484,0xFFB4040A,0xFFB00372,0xFFC40694,0xFFB40543,0xFFB0049D,0xFFAC031F,0xFFA0024E,0xFF980151,0xFF940274,0xFF940153,0xFF880002,0xF98400D9,0xC3FC0964,0xFFB807ED,0xFFB00768,0xFFA00596,0xFF9404A5,0xFF880374,0xFF880463,0xFF7002BA,0xFF580061,0xF95000D8,0xE1FC0964,
-0xFF600768,0xFF100372,0xF8A800D8,0xEA000964,0xFFCC082B,0xF3D4091A,0xF5D8093F,0xFFC406CC,0xFFB4054F,0xFFAC03A2,0xFFA40306,0xFF9C019B,0xFFD0080D,0xFFC406A4,0xFF9C02F7,0xFF580061,0xDBFC0964,0x1F000DB,0xFDF000C3,0xFFEC00AB,0xFFEC00A2,0xFFE80093,0xFFE80072,0xFFE80062,0xFFE40039,0xFFE00022,0xFFD80001,0xEFFC00D8,0xFFE400B2,0xFFE400A2,0xFFD80061,0xFFD8003D,
-0xFFC80000,0xF7F800D8,0xFFC800A2,0xFF900000,0xF80000D8,0xEFFC00D8,0xFFE400B2,0xFFE400A2,0xFFD80061,0xFFD8003D,0xFFC80000,0xF7F800D8,0xFFC800A2,0xFF900000,0xF80000D8,0xF7F800D8,0xFFC800A2,0xFF900000,0xF80000D8,0xF80000D8,0xFDF000C1,0xFFEC00D1,0xF1F000DB,0xFFEC00AE,0xFFE80092,0xFFE0006B,0xFFD80050,0xFFD00034,0xFBF000C1,0xFFE800A6,0xFFD800A3,0xFF900000,
-0xF5FC00D8,0x1C8076B,0x1C8076B,0x1C8076B,0x1C8076B,0xFFBC059E,0xFFBC059E,0xFFBC059E,0xFFB4040A,0xFFB4040A,0xFFB00372,0xFFB0049D,0xFFB0049D,0xFFB0049D,0xFFA0024E,0xFFA0024E,0xFF980151,0xFF940153,0xFF940153,0xFF880002,0xF58400A5,0xB1FC0768,0xB1FC0768,0xB1FC0768,0xFF9404A5,0xFF9404A5,0xFF880374,0xFF7002BA,0xFF7002BA,0xFF580061,0xF55400A4,0xD9FC0768,
-0xD9FC0768,0xFF100372,0xF4B800A4,0xE4000768,0xFBC40683,0xFDC80703,0x1C8076B,0xFFBC057D,0xFFB4046E,0xFFAC0362,0xFFA40306,0xFF9C019B,0xFFBC0651,0xFFB4055B,0xFF9C02EE,0xFF580061,0xCFFC0768,0x1EC00A2,0x1EC00A2,0x1EC00A2,0x1EC00A2,0xFFE80062,0xFFE80062,0xFFE80062,0xFFE00022,0xFFE00022,0xFFD80001,0xE5FC00A2,0xE5FC00A2,0xE5FC00A2,0xFFD8003D,0xFFD8003D,
-0xFFC80000,0xF3F800A2,0xF3F800A2,0xFF900000,0xF40000A4,0xE5FC00A2,0xE5FC00A2,0xE5FC00A2,0xFFD8003D,0xFFD8003D,0xFFC80000,0xF3F800A2,0xF3F800A2,0xFF900000,0xF40000A4,0xF3F800A2,0xF3F800A2,0xFF900000,0xF40000A4,0xF40000A4,0xFBEC0091,0xFFEC0091,0x1EC00A2,0xF9EC0091,0xFFDC0074,0xFFD80061,0xFFD80050,0xFFD00034,0xF9EC0091,0xFDE40082,0xEFFC00A2,0xFF900000,
-0xEFFC00A2,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1B00372,0x1B00372,0x1B00372,0x1B00372,0x1B00372,0x1B00372,0x1B00372,0x1B00372,0x1B00372,0x1B00372,0xFF980151,0xFF980151,0xFF980151,0xFF980151,0xFF980151,
-0xFF980151,0xFF880002,0xFF880002,0xFF880002,0xED840001,0x89FC0372,0x89FC0372,0x89FC0372,0x89FC0372,0x89FC0372,0x89FC0372,0xFF580061,0xFF580061,0xFF580061,0xED5C0000,0xC5FC0372,0xC5FC0372,0xC5FC0372,0xECD80000,0xD6000374,0xFFAC02F9,0x1B00372,0x1B00372,0xFDA8028A,0xFFA00212,0xFF9801BA,0xFF9801BA,0xFF9400DA,0xFFA002E4,0xFFA00269,0xFF88007D,0xFF580061,
-0xB7FC0372,};
-static const uint32_t g_etc1_to_bc7_m6_table160[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x300000,0x300000,0x300000,0x300000,0x2440000,0x2440000,0x2440000,0x8C0000,0x8C0000,0x16000001,0x2440000,0x2440000,0x2440000,0x8C0000,0x8C0000,0x16000001,0x8C0000,0x8C0000,0x16000001,0x16000001,0x2440000,0x2440000,0x2440000,0x8C0000,0x8C0000,0x16000001,0x8C0000,0x8C0000,0x16000001,0x16000001,0x8C0000,
-0x8C0000,0x16000001,0x16000001,0x16000001,0x380000,0x340000,0x300000,0x400000,0x500000,0x640000,0x740000,0xAC0000,0x3C0000,0x2440000,0x640000,0x16000001,0x640000,0xA00000,0xEC0000,0x1E40000,0x4E000001,0xEC0000,0x1E40000,0x4E000001,0x1E40000,0x4E000001,0x4E000001,0xEC0000,0x1E40000,0x4E000001,0x1E40000,0x4E000001,
-0x4E000001,0x1E40000,0x4E000001,0x4E000001,0x4E000001,0xEC0000,0x1E40000,0x4E000001,0x1E40000,0x4E000001,0x4E000001,0x1E40000,0x4E000001,0x4E000001,0x4E000001,0x1E40000,0x4E000001,0x4E000001,0x4E000001,0x4E000001,0xC80000,0xCA80000,0xCA80000,0x10C0000,0x1880000,0x25F00000,0x4E000001,0x4E000001,0xD80000,0x12C0000,0x45DC0000,0x4E000001,
-0x1540000,0x3410B0,0xE2100180,0x72100180,0x4E100181,0x9C000620,0x6E0000A9,0x4E000005,0x4C000620,0x4400025D,0x32000622,0x6A000D2B,0x620004E9,0x46000263,0x46000851,0x3C00041A,0x30000732,0x32000D2C,0x32000831,0x2C000A06,0x22000D2B,0x4C10B0,0x4C0007F3,0x4000045C,0x3A000A12,0x3A00058B,0x2E000814,0x2E000E21,0x2C000952,0x26000ABF,0x22000DA4,0x9810B0,
-0x26000BDD,0x20000CBA,0x1C000EF4,0x180010B4,0xFE0004A0,0xFA240B7A,0xFE2C0B05,0x9E000409,0x62000449,0x4C00041A,0x440002DE,0x36000555,0xD0000776,0x7C00058B,0x3E00065B,0x26000ABF,0x6C10B0,0x440D2C,0xDA180120,0x70180120,0x4E180121,0x9C000620,0x6E0000A9,0x4E000005,0x4C000620,0x4400025D,0x32000622,0x680D2B,0x620004E9,0x46000263,0x46000851,0x3C00041A,
-0x30000732,0xD00D2B,0x32000831,0x2C000A06,0x22000D2B,0x680D2B,0x620004E9,0x46000263,0x46000851,0x3C00041A,0x30000732,0xD00D2B,0x32000831,0x2C000A06,0x22000D2B,0xD00D2B,0x32000831,0x2C000A06,0x22000D2B,0x22000D2B,0xFE0004A0,0xFE2C09C6,0xF63C08B8,0x9E000409,0x62000449,0x4C00041A,0x440002DE,0x36000555,0xD00006CD,0x7C00054B,0x3E00064B,0x2C000A06,
-0x940D2B,0x100180,0x100180,0x100180,0x100180,0x48000000,0x48000000,0x48000000,0x22000000,0x22000000,0x16000001,0x24000120,0x24000120,0x24000120,0x1E00006D,0x1E00006D,0x1400003A,0x10000122,0x10000122,0x100000AA,0xA000122,0x180180,0x180180,0x180180,0x180000B1,0x180000B1,0x12000061,0xE000141,0xE000141,0xE0000CE,0xA000132,0x2C0180,
-0x2C0180,0xA00010B,0xA000153,0x6000183,0x84000059,0xFA04002C,0x100180,0x42000075,0x3200006D,0x2200006A,0x2200005A,0x16000082,0x420000C5,0x3200009E,0x16000121,0xE0000CE,0x200180,0x180120,0x180120,0x180120,0x180120,0x48000000,0x48000000,0x48000000,0x22000000,0x22000000,0x16000001,0x240120,0x240120,0x240120,0x1E00006D,0x1E00006D,
-0x1400003A,0x440120,0x440120,0x100000AA,0xA000122,0x240120,0x240120,0x240120,0x1E00006D,0x1E00006D,0x1400003A,0x440120,0x440120,0x100000AA,0xA000122,0x440120,0x440120,0x100000AA,0xA000122,0xA000122,0x84000059,0xFC080020,0x180120,0x42000075,0x3200006D,0x2200006A,0x2200005A,0x16000082,0x560000B4,0x32000095,0x300120,0x100000AA,
-0x300120,0x680620,0xC2300000,0x6A300000,0x4E300001,0x2980620,0x6E0000A9,0x4E000005,0x1380620,0x4400025D,0x32000622,0x2980620,0x6E0000A9,0x4E000005,0x1380620,0x4400025D,0x32000622,0x1380620,0x4400025D,0x32000622,0x32000622,0x2980620,0x6E0000A9,0x4E000005,0x1380620,0x4400025D,0x32000622,0x1380620,0x4400025D,0x32000622,0x32000622,0x1380620,
-0x4400025D,0x32000622,0x32000622,0x32000622,0xFE140320,0xE6C0620,0xF65C039D,0xA6000220,0x6A000269,0x54000249,0x46000195,0x3E000305,0xF2000352,0x8C0002A8,0x4C000161,0x32000622,0xDC0620,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table161[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x400000,0x400000,0x400000,0x400000,0x25C0000,0x25C0000,0x25C0000,0xBC0000,0xBC0000,0x1E000001,0x25C0000,0x25C0000,0x25C0000,0xBC0000,0xBC0000,0x1E000001,0xBC0000,0xBC0000,0x1E000001,0x1E000001,0x25C0000,0x25C0000,0x25C0000,0xBC0000,0xBC0000,0x1E000001,0xBC0000,0xBC0000,0x1E000001,0x1E000001,0xBC0000,
-0xBC0000,0x1E000001,0x1E000001,0x1E000001,0x4480000,0x440000,0x400000,0x2540000,0x6C0000,0x880000,0x9C0000,0xE80000,0x500000,0x25C0000,0x880000,0x1E000001,0x880000,0xB00000,0x1040000,0x7FC0000,0x56000001,0x1040000,0x7FC0000,0x56000001,0x7FC0000,0x56000001,0x56000001,0x1040000,0x7FC0000,0x56000001,0x7FC0000,0x56000001,
-0x56000001,0x7FC0000,0x56000001,0x56000001,0x56000001,0x1040000,0x7FC0000,0x56000001,0x7FC0000,0x56000001,0x56000001,0x7FC0000,0x56000001,0x56000001,0x56000001,0x7FC0000,0x56000001,0x56000001,0x56000001,0x56000001,0xDC0000,0xBC0000,0xBC0000,0x1280000,0x1AC0000,0x2FF00000,0x56000001,0x56000001,0xF00000,0x1480000,0x4DEC0000,0x56000001,
-0x1740000,0x3C1430,0xF61402AC,0x7C1402AD,0x561402AD,0xB6000620,0x7A000059,0x5600000A,0x58000620,0x4A0001ED,0x3A000622,0x78000F80,0x680005A9,0x5200030B,0x4C000911,0x46000432,0x3A00078B,0x3A000F80,0x38000989,0x32000B46,0x26000F83,0x581430,0x580009AB,0x4C00058C,0x46000B62,0x40000613,0x340008C4,0x340010D1,0x38000AF2,0x2C000C47,0x2400102B,0xB01430,
-0x2C000E45,0x26000EDA,0x200011F7,0x1C001434,0xFC080612,0xFE2C0E0A,0xFE2C0E55,0xA6000431,0x76000461,0x5A000421,0x480002C3,0x420005B3,0xD0000856,0x8600061A,0x46000791,0x2C000C47,0x7C1430,0x500F80,0xEA200200,0x7A200200,0x56200201,0xB6000620,0x7A000059,0x58040006,0x58000620,0x4A0001ED,0x3A000622,0x2740F80,0x680005A9,0x5200030B,0x4C000911,0x46000432,
-0x3A00078B,0xF00F80,0x38000989,0x32000B46,0x26000F83,0x2740F80,0x680005A9,0x5200030B,0x4C000911,0x46000432,0x3A00078B,0xF00F80,0x38000989,0x32000B46,0x26000F83,0xF00F80,0x38000989,0x32000B46,0x26000F83,0x26000F83,0xFE0C05F6,0xF63C0BA4,0xFC480AC4,0xA6000431,0x76000461,0x5A000421,0x480002C3,0x420005B3,0xD00007AD,0x900005D9,0x46000781,0x32000B46,
-0xA80F80,0x1402AC,0x1402AC,0x1402AC,0x1402AC,0x60000000,0x60000000,0x60000000,0x2E000000,0x2E000000,0x1E000001,0x30000200,0x30000200,0x30000200,0x220000B9,0x220000B9,0x1E000065,0x16000202,0x16000202,0x16000132,0xE000202,0x2002AB,0x2002AB,0x2002AB,0x22000132,0x22000132,0x180000B1,0x12000236,0x12000236,0x1400016E,0xE00021B,0x3C02AB,
-0x3C02AB,0x100001D3,0xA000263,0xA0002AB,0xB600009D,0xFE0C00AC,0x1402AC,0x5C0000DA,0x3C0000C1,0x2E0000C1,0x2A00009D,0x220000E8,0x64000161,0x44000125,0x1E000204,0x1400016E,0x2C02AB,0x200200,0x200200,0x200200,0x200200,0x60000000,0x60000000,0x60000000,0x2E000000,0x2E000000,0x1E000001,0x300200,0x300200,0x300200,0x220000B9,0x220000B9,
-0x1E000065,0x5C0200,0x5C0200,0x16000132,0xE000202,0x300200,0x300200,0x300200,0x220000B9,0x220000B9,0x1E000065,0x5C0200,0x5C0200,0x16000132,0xE000202,0x5C0200,0x5C0200,0x16000132,0xE000202,0xE000202,0xB600009D,0xFE0C0088,0x200200,0x5C0000DA,0x3C0000C1,0x2E0000C1,0x2A00009D,0x220000E8,0x6400013D,0x4A000112,0x400200,0x16000132,
-0x400200,0x780620,0xCA400000,0x72400000,0x56400001,0x2B00620,0x7A000059,0x58080001,0x1680620,0x4A0001ED,0x3A000622,0x2B00620,0x7A000059,0x58080001,0x1680620,0x4A0001ED,0x3A000622,0x1680620,0x4A0001ED,0x3A000622,0x3A000622,0x2B00620,0x7A000059,0x58080001,0x1680620,0x4A0001ED,0x3A000622,0x1680620,0x4A0001ED,0x3A000622,0x3A000622,0x1680620,
-0x4A0001ED,0x3A000622,0x3A000622,0x3A000622,0xF8280349,0x800620,0xFE6C039D,0xBC0001BD,0x80000209,0x5E0001D4,0x50000131,0x460002B1,0xF8040320,0x9E000239,0x560000E8,0x3A000622,0xFC0620,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table162[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x500000,0x500000,0x500000,0x500000,0x2740000,0x2740000,0x2740000,0xF00000,0xF00000,0x26000001,0x2740000,0x2740000,0x2740000,0xF00000,0xF00000,0x26000001,0xF00000,0xF00000,0x26000001,0x26000001,0x2740000,0x2740000,0x2740000,0xF00000,0xF00000,0x26000001,0xF00000,0xF00000,0x26000001,0x26000001,0xF00000,
-0xF00000,0x26000001,0x26000001,0x26000001,0x5C0000,0x2540000,0x500000,0x6C0000,0x840000,0xA80000,0xC00000,0x1240000,0x640000,0x2740000,0xA80000,0x26000001,0xA80000,0xC00000,0x11C0000,0x13FC0000,0x5E000001,0x11C0000,0x13FC0000,0x5E000001,0x13FC0000,0x5E000001,0x5E000001,0x11C0000,0x13FC0000,0x5E000001,0x13FC0000,0x5E000001,
-0x5E000001,0x13FC0000,0x5E000001,0x5E000001,0x5E000001,0x11C0000,0x13FC0000,0x5E000001,0x13FC0000,0x5E000001,0x5E000001,0x13FC0000,0x5E000001,0x5E000001,0x5E000001,0x13FC0000,0x5E000001,0x5E000001,0x5E000001,0x5E000001,0xF00000,0xCC0000,0xCC0000,0x3400000,0x1D40000,0x39F00000,0x5E000001,0x5E000001,0x1040000,0x1680000,0x55FC0000,0x5E000001,
-0x1980000,0x441830,0xFE1C0435,0x861C042D,0x5E1C042D,0xCE000620,0x8C000025,0x62040035,0x64000620,0x56000195,0x42000622,0x8800122B,0x740006C9,0x580003F3,0x580009E9,0x4C00046A,0x400007EB,0x4200122B,0x3E000B29,0x38000CB6,0x2C00122B,0x641830,0x62000B89,0x52000704,0x52000CF2,0x460006D3,0x3A000994,0x3A0013E9,0x3E000CE2,0x32000E07,0x2A0012FF,0xCC1830,
-0x32001115,0x2C00114A,0x26001547,0x20001834,0xFE1407F5,0xFE2C116A,0xF63C11FC,0xC800047D,0x8000049D,0x5E000465,0x520002DE,0x4A00061E,0xF2000977,0x9E0006AD,0x4E0008E5,0x32000E07,0x901830,0x5C122C,0xFA280320,0x84280320,0x5E280321,0xCE000620,0x8C000025,0x6008002A,0x64000620,0x56000195,0x42000622,0x84122B,0x740006C9,0x580003F3,0x580009E9,0x4C00046A,
-0x400007EB,0x10C122B,0x3E000B29,0x38000CB6,0x2C00122B,0x84122B,0x740006C9,0x580003F3,0x580009E9,0x4C00046A,0x400007EB,0x10C122B,0x3E000B29,0x38000CB6,0x2C00122B,0x10C122B,0x3E000B29,0x38000CB6,0x2C00122B,0x2C00122B,0xFE140791,0xFC480DB8,0xFE4C0D38,0xC800047D,0x8000049D,0x5E000465,0x520002DE,0x4A00061E,0xFA00088B,0x9E000649,0x4E0008CC,0x38000CB6,
-0xBC122B,0x1C042C,0x1C042C,0x1C042C,0x1C042C,0x78000000,0x78000000,0x78000000,0x3A000000,0x3A000000,0x26000001,0x3C000320,0x3C000320,0x3C000320,0x2E000121,0x2E000121,0x22000092,0x1C000322,0x1C000322,0x1C0001E2,0x12000322,0x224042B,0x224042B,0x224042B,0x280001E2,0x280001E2,0x2200010B,0x18000372,0x18000372,0x1A00023E,0x12000346,0x4C042B,
-0x4C042B,0x160002E3,0x100003AB,0xC00042B,0xF60000FA,0xFE0C018C,0x1C042C,0x72000151,0x50000131,0x4000013A,0x38000105,0x2A000161,0x8200022D,0x500001C2,0x24000324,0x1A00023E,0x34042B,0x280320,0x280320,0x280320,0x280320,0x78000000,0x78000000,0x78000000,0x3A000000,0x3A000000,0x26000001,0x3C0320,0x3C0320,0x3C0320,0x2E000121,0x2E000121,
-0x22000092,0x740320,0x740320,0x1C0001E2,0x12000322,0x3C0320,0x3C0320,0x3C0320,0x2E000121,0x2E000121,0x22000092,0x740320,0x740320,0x1C0001E2,0x12000322,0x740320,0x740320,0x1C0001E2,0x12000322,0x12000322,0xF60000FA,0xF4180139,0x280320,0x72000151,0x50000131,0x4000013A,0x38000105,0x2A000161,0x820001ED,0x5A0001A8,0x540320,0x1C0001E2,
-0x540320,0x880620,0xD2500000,0x7A500000,0x5E500001,0xC80620,0x8C000025,0x60180001,0x1980620,0x56000195,0x42000622,0xC80620,0x8C000025,0x60180001,0x1980620,0x56000195,0x42000622,0x1980620,0x56000195,0x42000622,0x42000622,0xC80620,0x8C000025,0x60180001,0x1980620,0x56000195,0x42000622,0x1980620,0x56000195,0x42000622,0x42000622,0x1980620,
-0x56000195,0x42000622,0x42000622,0x42000622,0xFE340355,0x900620,0xF67C03C8,0xD2000164,0x8A0001A9,0x68000190,0x580000DA,0x5000024A,0xFC140322,0xB40001E2,0x5E000095,0x42000622,0x1200620,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table163[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x600000,0x600000,0x600000,0x600000,0x28C0000,0x28C0000,0x28C0000,0x1200000,0x1200000,0x2E000001,0x28C0000,0x28C0000,0x28C0000,0x1200000,0x1200000,0x2E000001,0x1200000,0x1200000,0x2E000001,0x2E000001,0x28C0000,0x28C0000,0x28C0000,0x1200000,0x1200000,0x2E000001,0x1200000,0x1200000,0x2E000001,0x2E000001,0x1200000,
-0x1200000,0x2E000001,0x2E000001,0x2E000001,0x700000,0xA640000,0x600000,0x2800000,0xA00000,0xCC0000,0xE80000,0x1640000,0x780000,0x28C0000,0xCC0000,0x2E000001,0xCC0000,0xD00000,0x1340000,0x1FF80000,0x66000001,0x1340000,0x1FF80000,0x66000001,0x1FF80000,0x66000001,0x66000001,0x1340000,0x1FF80000,0x66000001,0x1FF80000,0x66000001,
-0x66000001,0x1FF80000,0x66000001,0x66000001,0x66000001,0x1340000,0x1FF80000,0x66000001,0x1FF80000,0x66000001,0x66000001,0x1FF80000,0x66000001,0x66000001,0x66000001,0x1FF80000,0x66000001,0x66000001,0x66000001,0x66000001,0x1040000,0x6DC0000,0x6DC0000,0x15C0000,0x1FC0000,0x43F00000,0x66000001,0x66000001,0x3180000,0x1840000,0x5FD00000,0x66000001,
-0x1B80000,0x4C1CB0,0xFE24064C,0x92200600,0x66200601,0xE6000620,0x98000005,0x6A08008D,0x70000620,0x5C00013D,0x4A000622,0x9A00152B,0x80000829,0x62000519,0x62000AC2,0x580004BA,0x46000863,0x4A00152C,0x44000D11,0x3E000E56,0x3200152B,0x701CB0,0x6E000DF9,0x580008DC,0x58000EB2,0x520007AB,0x46000A74,0x46001751,0x44000F22,0x38000FFF,0x30001633,0xE41CB0,
-0x3800144D,0x3200140A,0x2C00190F,0x24001CB4,0xFE140A75,0xF63C1528,0xFA44160C,0xDE0004E3,0x90000506,0x6E0004C2,0x5E000302,0x500006CB,0xFA000B2B,0xB2000792,0x56000A45,0x38000FFF,0xA01CB0,0x64152C,0xFE300490,0x8E300480,0x66300481,0xE6000620,0x98000005,0x6A08007D,0x70000620,0x5C00013D,0x4A000622,0x98152B,0x80000829,0x62000519,0x62000AC2,0x580004BA,
-0x46000863,0x130152B,0x44000D11,0x3E000E56,0x3200152B,0x98152B,0x80000829,0x62000519,0x62000AC2,0x580004BA,0x46000863,0x130152B,0x44000D11,0x3E000E56,0x3200152B,0x130152B,0x44000D11,0x3E000E56,0x3200152B,0x3200152B,0xFE2009B6,0xFE4C1044,0xF65C1031,0xDE0004E3,0x90000506,0x6E0004C2,0x5E000302,0x500006CB,0xFA000A2B,0xB2000719,0x56000A2C,0x3E000E56,
-0xD8152B,0x200600,0x200600,0x200600,0x200600,0x90000000,0x90000000,0x90000000,0x46000000,0x46000000,0x2E000001,0x48000480,0x48000480,0x48000480,0x3A0001A9,0x3A0001A9,0x280000DA,0x22000480,0x22000480,0x200002C5,0x16000482,0x300600,0x300600,0x300600,0x2E0002C2,0x2E0002C2,0x28000183,0x1E0004F6,0x1E0004F6,0x1C000336,0x160004C2,0x5C0600,
-0x5C0600,0x16000433,0x14000556,0xE000603,0xF600018A,0xF21402D9,0x200600,0x900001E1,0x5E0001BA,0x480001BA,0x40000172,0x2E000212,0x9600032B,0x660002A1,0x2C000489,0x1C000336,0x400600,0x300480,0x300480,0x300480,0x300480,0x90000000,0x90000000,0x90000000,0x46000000,0x46000000,0x2E000001,0x2440480,0x2440480,0x2440480,0x3A0001A9,0x3A0001A9,
-0x280000DA,0x8C0480,0x8C0480,0x200002C5,0x16000482,0x2440480,0x2440480,0x2440480,0x3A0001A9,0x3A0001A9,0x280000DA,0x8C0480,0x8C0480,0x200002C5,0x16000482,0x8C0480,0x8C0480,0x200002C5,0x16000482,0x16000482,0xF600018A,0xF8200221,0x300480,0x900001E1,0x5E0001BA,0x480001BA,0x40000172,0x2E000212,0xA40002D5,0x6C000274,0x640480,0x200002C5,
-0x640480,0x980620,0xDA600000,0x82600000,0x66600001,0xE00620,0x98000005,0x68280001,0x1CC0620,0x5C00013D,0x4A000622,0xE00620,0x98000005,0x68280001,0x1CC0620,0x5C00013D,0x4A000622,0x1CC0620,0x5C00013D,0x4A000622,0x4A000622,0xE00620,0x98000005,0x68280001,0x1CC0620,0x5C00013D,0x4A000622,0x1CC0620,0x5C00013D,0x4A000622,0x4A000622,0x1CC0620,
-0x5C00013D,0x4A000622,0x4A000622,0x4A000622,0xFC4C0374,0x8A00620,0xFE8C03C8,0xE600010D,0xA0000161,0x76000132,0x5E000091,0x58000202,0xFE2C0349,0xC600019A,0x6A000061,0x4A000622,0x1400620,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table164[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x2180000,0x2180000,0x2180000,0x2180000,0x2180000,
-0x2180000,0x300000,0x300000,0x300000,0x8000000,0x2180000,0x2180000,0x2180000,0x2180000,0x2180000,0x2180000,0x300000,0x300000,0x300000,0x8000000,0x300000,0x300000,0x300000,0x8000000,0x8000000,0x140000,0x100001,0x100001,0x140000,0x2140000,0x180000,0x180000,0x1C0000,0x140000,0x2140000,0x240000,0x300000,
-0x240000,0x700001,0x700001,0x700001,0x700001,0xA80000,0xA80000,0xA80000,0x1580000,0x1580000,0x38000000,0xA80000,0xA80000,0xA80000,0x1580000,0x1580000,0x38000000,0x1580000,0x1580000,0x38000000,0x38000000,0xA80000,0xA80000,0xA80000,0x1580000,0x1580000,0x38000000,0x1580000,0x1580000,0x38000000,0x38000000,0x1580000,
-0x1580000,0x38000000,0x38000000,0x38000000,0x840000,0x4780000,0x700001,0x2980000,0xC00000,0xF00000,0x1140000,0x1A40000,0x48C0000,0xA80000,0xF00000,0x38000000,0xF00000,0xE00001,0x1500000,0x2DF80000,0x70000000,0x1500000,0x2DF80000,0x70000000,0x2DF80000,0x70000000,0x70000000,0x1500000,0x2DF80000,0x70000000,0x2DF80000,0x70000000,
-0x70000000,0x2DF80000,0x70000000,0x70000000,0x70000000,0x1500000,0x2DF80000,0x70000000,0x2DF80000,0x70000000,0x70000000,0x2DF80000,0x70000000,0x70000000,0x70000000,0x2DF80000,0x70000000,0x70000000,0x70000000,0x70000000,0x11C0000,0xF00000,0xF00000,0x17C0000,0x11FC0000,0x4DF80000,0x70000000,0x70000000,0x1340000,0x1A80000,0x69C40000,0x70000000,
-0x1E00000,0x581F9B,0xFE30080B,0x9C2C0756,0x702C0756,0xFA080649,0xA408002A,0x741000FA,0x7C080649,0x68040139,0x54080649,0xB600152B,0x92000706,0x6E000496,0x740009B1,0x62000339,0x5200076C,0x5800152B,0x50000BF2,0x44000D79,0x3A00152C,0x841F99,0x7A000EA6,0x62000946,0x68000E9D,0x5E00071A,0x4C000A11,0x5200182C,0x4E000EC8,0x44000F8A,0x3A001695,0x10C1F99,
-0x440015A6,0x3E00150D,0x32001A90,0x2C001F99,0xFE200C15,0xFE4C178F,0xFE4C18DF,0xF400035A,0xA2000391,0x7C00033A,0x660001B8,0x60000548,0xFE000BDB,0xC6000621,0x5E000926,0x44000F8A,0xBC1F99,0x78152B,0xFE4404A6,0x96440482,0x70400482,0xEE140621,0xA0100006,0x741C007A,0x78140621,0x660C0131,0x54100621,0x2B0152B,0x92000706,0x6E000496,0x740009B1,0x62000339,
-0x5200076C,0x168152B,0x50000BF2,0x44000D79,0x3A00152C,0x2B0152B,0x92000706,0x6E000496,0x740009B1,0x62000339,0x5200076C,0x168152B,0x50000BF2,0x44000D79,0x3A00152C,0x168152B,0x50000BF2,0x44000D79,0x3A00152C,0x3A00152C,0xFE340A02,0xFA641079,0xFE6C1036,0xF400035A,0xA2000391,0x7C00033A,0x660001B8,0x60000548,0xFE080A6C,0xC6000591,0x5E000902,0x44000D79,
-0xFC152B,0x2C0756,0x2C0756,0x2C0756,0x2C0756,0xA4080029,0xA4080029,0xA4080029,0x52080029,0x52080029,0x38080029,0x64000480,0x64000480,0x64000480,0x46000115,0x46000115,0x34000050,0x30000480,0x30000480,0x2C000249,0x20000480,0x400756,0x400756,0x400756,0x3A0002EE,0x3A0002EE,0x2E000169,0x2800055B,0x2800055B,0x2600030E,0x1E0004EC,0x800756,
-0x800756,0x200004CD,0x1C000609,0x14000759,0xFC0C01B4,0xF82003D5,0x2C0756,0xB2000151,0x7C000124,0x5E000131,0x560000DD,0x40000172,0xC20002F5,0x8400022D,0x3E000490,0x2600030E,0x5C0756,0x400482,0x400482,0x400482,0x400482,0x98140001,0x98140001,0x98140001,0x50100001,0x50100001,0x38100001,0x600480,0x600480,0x600480,0x46000115,0x46000115,
-0x34000050,0xC40480,0xC40480,0x2C000249,0x20000480,0x600480,0x600480,0x600480,0x46000115,0x46000115,0x34000050,0xC40480,0xC40480,0x2C000249,0x20000480,0xC40480,0xC40480,0x2C000249,0x20000480,0x20000480,0xFE100188,0xFE2C0239,0x400482,0xB2000151,0x7C000124,0x5E000131,0x560000DD,0x40000172,0xD6000262,0x900001E1,0x8C0480,0x2C000249,
-0x8C0480,0xA80622,0xE0740001,0x8C700001,0x70700001,0xFC0620,0xA4080001,0x703C0000,0x3F80620,0x660000F4,0x54000620,0xFC0620,0xA4080001,0x703C0000,0x3F80620,0x660000F4,0x54000620,0x3F80620,0x660000F4,0x54000620,0x54000620,0xFC0620,0xA4080001,0x703C0000,0x3F80620,0x660000F4,0x54000620,0x3F80620,0x660000F4,0x54000620,0x54000620,0x3F80620,
-0x660000F4,0x54000620,0x54000620,0x54000620,0xF668039D,0x2B40620,0xF8A003F5,0xFC0000C8,0xAA000109,0x7E0400F2,0x6C000050,0x640001B1,0xF4480372,0xD800013D,0x74000022,0x54000620,0x1680620,0x80029,0x80029,0x80029,0x80029,0x80029,0x80029,0x80029,0x80029,0x80029,0x80029,0x1A000000,0x1A000000,0x1A000000,0x1A000000,0x1A000000,
-0x1A000000,0xC000000,0xC000000,0xC000000,0x8000000,0xC0029,0xC0029,0xC0029,0xC0029,0xC0029,0xC0029,0xC000010,0xC000010,0xC000010,0x6000008,0x140029,0x140029,0x140029,0x4000019,0x4000029,0x88000000,0x80029,0x80029,0x3C000000,0x2A000000,0x20000000,0x20000000,0x14000000,0x3600000A,0x24000005,0x10000001,0xC000010,
-0x100029,};
-static const uint32_t g_etc1_to_bc7_m6_table165[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x2300000,0x2300000,0x2300000,0x2300000,0x2300000,
-0x2300000,0x640000,0x640000,0x640000,0x10000000,0x2300000,0x2300000,0x2300000,0x2300000,0x2300000,0x2300000,0x640000,0x640000,0x640000,0x10000000,0x640000,0x640000,0x640000,0x10000000,0x10000000,0x240000,0x200001,0x200001,0x280000,0x2280000,0x22C0000,0x22C0000,0x380000,0x280000,0x2280000,0x480000,0x640000,
-0x480000,0x800001,0x800001,0x800001,0x800001,0xC00000,0xC00000,0xC00000,0x1880000,0x1880000,0x40000000,0xC00000,0xC00000,0xC00000,0x1880000,0x1880000,0x40000000,0x1880000,0x1880000,0x40000000,0x40000000,0xC00000,0xC00000,0xC00000,0x1880000,0x1880000,0x40000000,0x1880000,0x1880000,0x40000000,0x40000000,0x1880000,
-0x1880000,0x40000000,0x40000000,0x40000000,0x980000,0xC880000,0x800001,0xB00000,0xD80000,0x1140000,0x13C0000,0x1E40000,0x4A00000,0xC00000,0x1140000,0x40000000,0x1140000,0xF00001,0x1680000,0x39F80000,0x78000000,0x1680000,0x39F80000,0x78000000,0x39F80000,0x78000000,0x78000000,0x1680000,0x39F80000,0x78000000,0x39F80000,0x78000000,
-0x78000000,0x39F80000,0x78000000,0x78000000,0x78000000,0x1680000,0x39F80000,0x78000000,0x39F80000,0x78000000,0x78000000,0x39F80000,0x78000000,0x78000000,0x78000000,0x39F80000,0x78000000,0x78000000,0x78000000,0x78000000,0x1300000,0x9000000,0x9000000,0x3940000,0x1FF80000,0x57F80000,0x78000000,0x78000000,0x1480000,0x1C40000,0x71D40000,0x78000000,
-0x3FC0000,0x642297,0xFE3C0A17,0xA63808E2,0x783808E2,0xFC1406C7,0xAE100096,0x7E1801AE,0x861006B1,0x6E100185,0x5C1006B1,0xCE00152B,0xA2000619,0x78000482,0x800008D9,0x6E000231,0x580006D0,0x6400152B,0x5C000B02,0x50000C99,0x4200152C,0x982295,0x8C000F9A,0x6E000A26,0x74000F05,0x620006C9,0x58000A19,0x5E001914,0x56000E8F,0x4A000F5A,0x400016F9,0x1302295,
-0x4A00172A,0x4400162D,0x38001C24,0x32002295,0xFE340DE6,0xFE4C1A9F,0xF8601BF2,0xFE000293,0xB6000271,0x88000239,0x740000E4,0x64000421,0xFE100D87,0xDA000512,0x6E00085A,0x4A000F5A,0xD82295,0x88152B,0xFC5804D2,0x9E540482,0x78500482,0xF6240621,0xA8200006,0x7C2C007A,0x80240621,0x6E1C0131,0x5C200621,0xC8152B,0xA2000619,0x78040480,0x800008D9,0x6E000231,
-0x580006D0,0x198152B,0x5C000B02,0x50000C99,0x4200152C,0xC8152B,0xA2000619,0x78040480,0x800008D9,0x6E000231,0x580006D0,0x198152B,0x5C000B02,0x50000C99,0x4200152C,0x198152B,0x5C000B02,0x50000C99,0x4200152C,0x4200152C,0xFC4C0A7E,0xFE6C10C1,0xF880108B,0xFE000293,0xB6000271,0x88000239,0x740000E4,0x64000421,0xFE240AC5,0xDA00044E,0x6E000829,0x50000C99,
-0x120152B,0x3808E2,0x3808E2,0x3808E2,0x3808E2,0xB4100091,0xB4100091,0xB4100091,0x5C100091,0x5C100091,0x40100091,0x7C000480,0x7C000480,0x7C000480,0x580000A9,0x580000A9,0x40000010,0x3C000480,0x3C000480,0x320001E5,0x28000480,0x5008E1,0x5008E1,0x5008E1,0x46000356,0x46000356,0x3A000191,0x340005D3,0x340005D3,0x30000300,0x28000529,0xA008E1,
-0xA008E1,0x26000599,0x200006E4,0x1A0008E1,0xFE100248,0xFE2C050D,0x3808E2,0xD00000E1,0x900000B4,0x6E0000B4,0x66000074,0x4C000104,0xF40002E3,0xA60001E9,0x4C000499,0x30000300,0x7008E1,0x500482,0x500482,0x500482,0x500482,0xA0240001,0xA0240001,0xA0240001,0x58200001,0x58200001,0x40200001,0x780480,0x780480,0x780480,0x580000A9,0x580000A9,
-0x40000010,0xF40480,0xF40480,0x320001E5,0x28000480,0x780480,0x780480,0x780480,0x580000A9,0x580000A9,0x40000010,0xF40480,0xF40480,0x320001E5,0x28000480,0xF40480,0xF40480,0x320001E5,0x28000480,0x28000480,0xFE2001A5,0xFA440242,0x500482,0xD00000E1,0x900000B4,0x6E0000B4,0x66000074,0x4C000104,0xF4000202,0xAC000184,0xAC0480,0x320001E5,
-0xAC0480,0xB80622,0xE8840001,0x94800001,0x78800001,0x1140620,0xAC180001,0x784C0000,0xFF80620,0x720000B4,0x5C000620,0x1140620,0xAC180001,0x784C0000,0xFF80620,0x720000B4,0x5C000620,0xFF80620,0x720000B4,0x5C000620,0x5C000620,0x1140620,0xAC180001,0x784C0000,0xFF80620,0x720000B4,0x5C000620,0xFF80620,0x720000B4,0x5C000620,0x5C000620,0xFF80620,
-0x720000B4,0x5C000620,0x5C000620,0x5C000620,0xFE78039D,0xAC40620,0xFEAC03F9,0xFE1400DD,0xC00000CD,0x900000A9,0x74000020,0x6C000171,0xFC580372,0xEE0000FA,0x7E000008,0x5C000620,0x18C0620,0x100091,0x100091,0x100091,0x100091,0x100091,0x100091,0x100091,0x100091,0x100091,0x100091,0x32000000,0x32000000,0x32000000,0x32000000,0x32000000,
-0x32000000,0x18000000,0x18000000,0x18000000,0x10000000,0x180091,0x180091,0x180091,0x180091,0x180091,0x180091,0x12000034,0x12000034,0x12000034,0xE00001D,0x2C0091,0x2C0091,0x2C0091,0xA000055,0x8000091,0xF8000001,0x100091,0x100091,0x76000000,0x52000000,0x3E000000,0x3E000000,0x28000000,0x6000002D,0x42000019,0x1E000005,0x12000034,
-0x200091,};
-static const uint32_t g_etc1_to_bc7_m6_table166[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x300001,0x480000,0x480000,0x480000,0x480000,0x480000,
-0x480000,0x940000,0x940000,0x940000,0x18000000,0x480000,0x480000,0x480000,0x480000,0x480000,0x480000,0x940000,0x940000,0x940000,0x18000000,0x940000,0x940000,0x940000,0x18000000,0x18000000,0x2340000,0x300001,0x300001,0x4380000,0x23C0000,0x440000,0x440000,0x540000,0x4380000,0x23C0000,0x680000,0x940000,
-0x680000,0x900001,0x900001,0x900001,0x900001,0xD80000,0xD80000,0xD80000,0x1B80000,0x1B80000,0x48000000,0xD80000,0xD80000,0xD80000,0x1B80000,0x1B80000,0x48000000,0x1B80000,0x1B80000,0x48000000,0x48000000,0xD80000,0xD80000,0xD80000,0x1B80000,0x1B80000,0x48000000,0x1B80000,0x1B80000,0x48000000,0x48000000,0x1B80000,
-0x1B80000,0x48000000,0x48000000,0x48000000,0x2A80000,0x9C0000,0x900001,0x2C40000,0xF40000,0x1340000,0x1640000,0x7FC0000,0x4B40000,0xD80000,0x1340000,0x48000000,0x1340000,0x1000001,0x1800000,0x45F80000,0x80000000,0x1800000,0x45F80000,0x80000000,0x45F80000,0x80000000,0x80000000,0x1800000,0x45F80000,0x80000000,0x45F80000,0x80000000,
-0x80000000,0x45F80000,0x80000000,0x80000000,0x80000000,0x1800000,0x45F80000,0x80000000,0x45F80000,0x80000000,0x80000000,0x45F80000,0x80000000,0x80000000,0x80000000,0x45F80000,0x80000000,0x80000000,0x80000000,0x80000000,0x1440000,0x1140000,0x1140000,0x1B00000,0x2BFC0000,0x61FC0000,0x80000000,0x80000000,0x35C0000,0x1E40000,0x79E40000,0x80000000,
-0x13FC0000,0x7025F3,0xFE480C9B,0xB0400AC2,0x80400AC2,0xFE2407C7,0xBA1C0142,0x842402A6,0x90180759,0x78180209,0x64180759,0xE600152B,0xAE000579,0x820804A6,0x8C000821,0x76000159,0x62000659,0x7000152B,0x66000A44,0x56000BE9,0x4A00152C,0xA825F1,0x980010EA,0x7A000B86,0x80000FAD,0x6E0006D1,0x5E000A4D,0x680019F0,0x60000E80,0x54000F30,0x4600177D,0x15825F1,
-0x50001916,0x4A00179D,0x3E001DF0,0x380025F1,0xFE3C105F,0xFA641D9D,0xFE6C1F1A,0xFE0802E9,0xCA000191,0x96000163,0x7C000051,0x7000031D,0xFE180FB2,0xF2000433,0x7600075A,0x54000F30,0xF025F1,0x98152B,0xFE6804F6,0xA6640482,0x80600482,0xFE340621,0xB0300006,0x843C007A,0x88340621,0x762C0131,0x64300621,0xE0152B,0xAE000579,0x80140480,0x8C000821,0x76000159,
-0x62000659,0x1CC152B,0x66000A44,0x56000BE9,0x4A00152C,0xE0152B,0xAE000579,0x80140480,0x8C000821,0x76000159,0x62000659,0x1CC152B,0x66000A44,0x56000BE9,0x4A00152C,0x1CC152B,0x66000A44,0x56000BE9,0x4A00152C,0x4A00152C,0xFE580AE5,0xFC8810CB,0xFE8C1093,0xFE1402D6,0xCA000191,0x96000163,0x7C000051,0x7000031D,0xFE340B25,0xF2000352,0x76000729,0x56000BE9,
-0x140152B,0x400AC2,0x400AC2,0x400AC2,0x400AC2,0xC4180139,0xC4180139,0xC4180139,0x66180139,0x66180139,0x48180139,0x94000480,0x94000480,0x94000480,0x62000055,0x62000055,0x48000001,0x48000480,0x48000480,0x3E000185,0x30000480,0x600AC1,0x600AC1,0x600AC1,0x520003FE,0x520003FE,0x40000209,0x4000066B,0x4000066B,0x3A00030E,0x2E000569,0xC40AC1,
-0xC40AC1,0x2C0006AD,0x260007EC,0x20000AC1,0xFE200335,0xF43806DA,0x400AC2,0xFA000088,0xA8000061,0x80000061,0x78000032,0x5A0000B4,0xFE000332,0xC40001B1,0x5C0004A4,0x3A00030E,0x8C0AC1,0x600482,0x600482,0x600482,0x600482,0xA8340001,0xA8340001,0xA8340001,0x60300001,0x60300001,0x48300001,0x900480,0x900480,0x900480,0x62000055,0x62000055,
-0x48040000,0x1240480,0x1240480,0x3E000185,0x30000480,0x900480,0x900480,0x900480,0x62000055,0x62000055,0x48040000,0x1240480,0x1240480,0x3E000185,0x30000480,0x1240480,0x1240480,0x3E000185,0x30000480,0x30000480,0xFA3401C2,0xFE4C0262,0x600482,0xFA000088,0xA8000061,0x80000061,0x78000032,0x5A0000B4,0xFE0C0200,0xC4000121,0xD00480,0x3E000185,
-0xD00480,0xC80622,0xF0940001,0x9C900001,0x80900001,0x12C0620,0xB4280001,0x805C0000,0x1BF80620,0x78000080,0x64000620,0x12C0620,0xB4280001,0x805C0000,0x1BF80620,0x78000080,0x64000620,0x1BF80620,0x78000080,0x64000620,0x64000620,0x12C0620,0xB4280001,0x805C0000,0x1BF80620,0x78000080,0x64000620,0x1BF80620,0x78000080,0x64000620,0x64000620,0x1BF80620,
-0x78000080,0x64000620,0x64000620,0x64000620,0xFA8C03C8,0xD80620,0xF8C00422,0xFE2C0109,0xCA000091,0x9A00006A,0x7E000008,0x76000128,0xFC6C039D,0xFC0000C8,0x88000001,0x64000620,0x1AC0620,0x180139,0x180139,0x180139,0x180139,0x180139,0x180139,0x180139,0x180139,0x180139,0x180139,0x4A000000,0x4A000000,0x4A000000,0x4A000000,0x4A000000,
-0x4A000000,0x24000000,0x24000000,0x24000000,0x18000000,0x240139,0x240139,0x240139,0x240139,0x240139,0x240139,0x1E000074,0x1E000074,0x1E000074,0x18000040,0x440139,0x440139,0x440139,0x100000B9,0xC000139,0xFC080029,0x180139,0x180139,0xAE000000,0x78000000,0x5C000000,0x5C000000,0x3C000000,0x92000061,0x74000032,0x2E000009,0x1E000074,
-0x300139,};
-static const uint32_t g_etc1_to_bc7_m6_table167[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x600000,0x600000,0x600000,0x600000,0x600000,
-0x600000,0xC40000,0xC40000,0xC40000,0x20000000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0xC40000,0xC40000,0xC40000,0x20000000,0xC40000,0xC40000,0xC40000,0x20000000,0x20000000,0xA440000,0x400001,0x400001,0x4C0000,0x4500000,0x580000,0x580000,0x26C0000,0x4C0000,0x4500000,0x8C0000,0xC40000,
-0x8C0000,0xA00001,0xA00001,0xA00001,0xA00001,0xF00000,0xF00000,0xF00000,0x1E80000,0x1E80000,0x50000000,0xF00000,0xF00000,0xF00000,0x1E80000,0x1E80000,0x50000000,0x1E80000,0x1E80000,0x50000000,0x50000000,0xF00000,0xF00000,0xF00000,0x1E80000,0x1E80000,0x50000000,0x1E80000,0x1E80000,0x50000000,0x50000000,0x1E80000,
-0x1E80000,0x50000000,0x50000000,0x50000000,0xBC0000,0xAC0000,0xA00001,0xDC0000,0x1100000,0x1580000,0x18C0000,0x13F80000,0xCC0000,0xF00000,0x1580000,0x50000000,0x1580000,0x1100001,0x1980000,0x51F80000,0x88000000,0x1980000,0x51F80000,0x88000000,0x51F80000,0x88000000,0x88000000,0x1980000,0x51F80000,0x88000000,0x51F80000,0x88000000,
-0x88000000,0x51F80000,0x88000000,0x88000000,0x88000000,0x1980000,0x51F80000,0x88000000,0x51F80000,0x88000000,0x88000000,0x51F80000,0x88000000,0x88000000,0x88000000,0x51F80000,0x88000000,0x88000000,0x88000000,0x88000000,0x1580000,0x1240000,0x1240000,0x1CC0000,0x39FC0000,0x6BFC0000,0x88000000,0x88000000,0x1740000,0x5FC0000,0x81F40000,0x88000000,
-0x21FC0000,0x7C29AF,0xFE540F97,0xB84C0CF6,0x884C0CF6,0xFE300953,0xC4240236,0x8E2C03EA,0x9A200841,0x801C02D1,0x6C200841,0xFE00152B,0xC00004F9,0x8C100502,0x98000789,0x800000B5,0x6C000629,0x7C00152B,0x72000984,0x60000B40,0x5200152C,0xBC29AD,0xA800126A,0x82000D65,0x8C001095,0x7A000739,0x68000AC5,0x74001B10,0x68000E8C,0x5C000F2A,0x52001805,0x17C29AD,
-0x5C001B46,0x5000195D,0x4A001FD0,0x3E0029AD,0xFE501342,0xFE6C2105,0xFE6C231A,0xFE1403DA,0xD80000EA,0xA20000B9,0x88000009,0x7A000236,0xFE2412A6,0xFC00038C,0x7E0006CC,0x5C000F2A,0x10C29AD,0xA8152B,0xFE78053B,0xAE740482,0x88700482,0xFE440629,0xB8400006,0x8C4C007A,0x90440621,0x7E3C0131,0x6C400621,0xF8152B,0xC00004F9,0x88240480,0x98000789,0x800000B5,
-0x6C000629,0x1FC152B,0x72000984,0x60000B40,0x5200152C,0xF8152B,0xC00004F9,0x88240480,0x98000789,0x800000B5,0x6C000629,0x1FC152B,0x72000984,0x60000B40,0x5200152C,0x1FC152B,0x72000984,0x60000B40,0x5200152C,0x5200152C,0xFC740B5A,0xF4981121,0xF8A010E6,0xFE240355,0xD80000EA,0xA20000B9,0x88000009,0x7A000236,0xFE440B94,0xFC00028C,0x7E00068C,0x60000B40,
-0x164152B,0x4C0CF6,0x4C0CF6,0x4C0CF6,0x4C0CF6,0xD4200221,0xD4200221,0xD4200221,0x70200221,0x70200221,0x50200221,0xAC000480,0xAC000480,0xAC000480,0x7400001D,0x7400001D,0x52040018,0x54000480,0x54000480,0x44000139,0x38000480,0x700CF6,0x700CF6,0x700CF6,0x620004C5,0x620004C5,0x4C0002C1,0x4C000723,0x4C000723,0x40000332,0x340005C1,0xE40CF6,
-0xE40CF6,0x380007FD,0x2C000924,0x24000CF9,0xFE2C0498,0xFA4408C6,0x4C0CF6,0xFE080098,0xBC000029,0x9200002D,0x84000008,0x6A000068,0xFE000452,0xD4000186,0x660004AC,0x40000332,0xA00CF6,0x700482,0x700482,0x700482,0x700482,0xB0440001,0xB0440001,0xB0440001,0x68400001,0x68400001,0x50400001,0xA80480,0xA80480,0xA80480,0x7400001D,0x7400001D,
-0x50140000,0x1580480,0x1580480,0x44000139,0x38000480,0xA80480,0xA80480,0xA80480,0x7400001D,0x7400001D,0x50140000,0x1580480,0x1580480,0x44000139,0x38000480,0x1580480,0x1580480,0x44000139,0x38000480,0x38000480,0xF64801E1,0xFA640265,0x700482,0xFE080088,0xBC000029,0x9200002D,0x84000008,0x6A000068,0xF6240221,0xDA0000CA,0xF00480,0x44000139,
-0xF00480,0xD80622,0xF8A40001,0xA4A00001,0x88A00001,0x1440620,0xBC380001,0x886C0000,0x27F80620,0x84000050,0x6C000620,0x1440620,0xBC380001,0x886C0000,0x27F80620,0x84000050,0x6C000620,0x27F80620,0x84000050,0x6C000620,0x6C000620,0x1440620,0xBC380001,0x886C0000,0x27F80620,0x84000050,0x6C000620,0x27F80620,0x84000050,0x6C000620,0x6C000620,0x27F80620,
-0x84000050,0x6C000620,0x6C000620,0x6C000620,0xFE9403E8,0xE80620,0xFECC042A,0xFE400128,0xE000006D,0xA6000050,0x88000000,0x7E0000F4,0xF88403C8,0xFE1400E1,0x90100001,0x6C000620,0x1D00620,0x200221,0x200221,0x200221,0x200221,0x200221,0x200221,0x200221,0x200221,0x200221,0x200221,0x64000000,0x64000000,0x64000000,0x64000000,0x64000000,
-0x64000000,0x30000000,0x30000000,0x30000000,0x20000000,0x300221,0x300221,0x300221,0x300221,0x300221,0x300221,0x280000C2,0x280000C2,0x280000C2,0x1E000068,0x5C0221,0x5C0221,0x5C0221,0x16000145,0x10000221,0xFE0C009D,0x200221,0x200221,0xE8000000,0xA0000000,0x7A000000,0x7A000000,0x50000000,0xC40000A9,0x96000055,0x3E000010,0x280000C2,
-0x400221,};
-static const uint32_t g_etc1_to_bc7_m6_table168[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,
-0x7C0000,0xFC0000,0xFC0000,0xFC0000,0x28000001,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0xFC0000,0xFC0000,0xFC0000,0x28000001,0xFC0000,0xFC0000,0xFC0000,0x28000001,0x28000001,0x4580000,0x540000,0x540000,0x2600000,0x680000,0x2700000,0x2700000,0x8C0000,0x2600000,0x680000,0xB00000,0xFC0000,
-0xB00000,0xB40000,0xB40000,0xB40000,0xB40000,0x10C0000,0x10C0000,0x10C0000,0xBF80000,0xBF80000,0x58000001,0x10C0000,0x10C0000,0x10C0000,0xBF80000,0xBF80000,0x58000001,0xBF80000,0xBF80000,0x58000001,0x58000001,0x10C0000,0x10C0000,0x10C0000,0xBF80000,0xBF80000,0x58000001,0xBF80000,0xBF80000,0x58000001,0x58000001,0xBF80000,
-0xBF80000,0x58000001,0x58000001,0x58000001,0xD00000,0xC00000,0xB40000,0xF40000,0x32C0000,0x17C0000,0x1B80000,0x1FF80000,0x2E00000,0x10C0000,0x17C0000,0x58000001,0x17C0000,0x1240000,0x3B00000,0x5DFC0000,0x90000001,0x3B00000,0x5DFC0000,0x90000001,0x5DFC0000,0x90000001,0x90000001,0x3B00000,0x5DFC0000,0x90000001,0x5DFC0000,0x90000001,
-0x90000001,0x5DFC0000,0x90000001,0x90000001,0x90000001,0x3B00000,0x5DFC0000,0x90000001,0x5DFC0000,0x90000001,0x90000001,0x5DFC0000,0x90000001,0x90000001,0x90000001,0x5DFC0000,0x90000001,0x90000001,0x90000001,0x90000001,0x36C0000,0x1380000,0x1380000,0x1EC0000,0x49F80000,0x77F40000,0x90000001,0x90000001,0x18C0000,0x17FC0000,0x8BE80000,0x90000001,
-0x33FC0000,0x8C2E54,0xFE681371,0xC2580FD9,0x90580FD9,0xFE3C0BBC,0xD42C039D,0x9A3805B5,0xA42C0994,0x8A240406,0x74280996,0xFE0C1590,0xD20004A2,0x961805A9,0xA80006E9,0x8C000042,0x7404062A,0x8A00152B,0x780008B3,0x6C000A83,0x5C00152B,0xCC2E54,0xB40014BB,0x8E000FFC,0x980011E6,0x8000080E,0x6E000BB6,0x80001C6F,0x74000EBF,0x66000F3F,0x5800189C,0x1A02E54,
-0x60001E64,0x5C001B96,0x50002227,0x44002E54,0xFE58170A,0xF88025CC,0xFA842794,0xFE2405E6,0xEA000061,0xB0000042,0x9204000A,0x86000173,0xFE3415FA,0xFE00042C,0x90000627,0x66000F3F,0x1242E54,0xB8152C,0xFE8C0581,0xB8840480,0x90840481,0xFE5C0642,0xC2540005,0x945C007D,0x9A540620,0x864C0132,0x74540622,0x114152B,0xD20004A2,0x90380481,0xA80006E9,0x8C000042,
-0x740C0622,0xFF8152B,0x780008B3,0x6C000A83,0x5C00152B,0x114152B,0xD20004A2,0x90380481,0xA80006E9,0x8C000042,0x740C0622,0xFF8152B,0x780008B3,0x6C000A83,0x5C00152B,0xFF8152B,0x780008B3,0x6C000A83,0x5C00152B,0x5C00152B,0xFE800BBE,0xFEAC1122,0xFEAC1101,0xFE4003CB,0xEA000061,0xB0000042,0x92080002,0x86000173,0xFE5C0BD5,0xFE1002E5,0x900005D6,0x6C000A83,
-0x18C152B,0x580FD8,0x580FD8,0x580FD8,0x580FD8,0xE42C0374,0xE42C0374,0xE42C0374,0x7A2C0374,0x7A2C0374,0x58280375,0xC8000480,0xC8000480,0xC8000480,0x82000005,0x82000005,0x5C0C005E,0x60000482,0x60000482,0x500000E1,0x40000482,0x2800FD8,0x2800FD8,0x2800FD8,0x6E000615,0x6E000615,0x520003EB,0x58000811,0x58000811,0x4C00037E,0x4000063B,0x1080FD8,
-0x1080FD8,0x3E0009BD,0x32000AC6,0x2A000FDB,0xFC380694,0xFE4C0B58,0x580FD8,0xFE100141,0xDA000005,0xA6000005,0x98000002,0x7600002D,0xFE1405F9,0xF6000172,0x7C0004C0,0x4C00037E,0xB80FD8,0x840480,0x840480,0x840480,0x840480,0xBA540000,0xBA540000,0xBA540000,0x70540000,0x70540000,0x58540001,0xC40480,0xC40480,0xC40480,0x82000005,0x82000005,
-0x5A240001,0x18C0480,0x18C0480,0x500000E1,0x40000482,0xC40480,0xC40480,0xC40480,0x82000005,0x82000005,0x5A240001,0x18C0480,0x18C0480,0x500000E1,0x40000482,0x18C0480,0x18C0480,0x500000E1,0x40000482,0x40000482,0xFE5801E1,0xF4780288,0x840480,0xFE2400A2,0xDA000005,0xA6000005,0x96040000,0x7600002D,0xFE340221,0xFC000082,0x1180480,0x500000E1,
-0x1180480,0xEC0620,0xFEB40004,0xACB40000,0x90B40001,0x35C0620,0xC44C0001,0x927C0001,0x33FC0620,0x8E00002D,0x74000622,0x35C0620,0xC44C0001,0x927C0001,0x33FC0620,0x8E00002D,0x74000622,0x33FC0620,0x8E00002D,0x74000622,0x74000622,0x35C0620,0xC44C0001,0x927C0001,0x33FC0620,0x8E00002D,0x74000622,0x33FC0620,0x8E00002D,0x74000622,0x74000622,0x33FC0620,
-0x8E00002D,0x74000622,0x74000622,0x74000622,0xFEB403F5,0xFC0620,0xFAE40451,0xFE580164,0xEA00003D,0xB2000022,0x90140001,0x8A0000C1,0xFE9803C8,0xFE380120,0x9A200000,0x74000622,0x1F40620,0x280374,0x280374,0x280374,0x280374,0x280374,0x280374,0x280374,0x280374,0x280374,0x280374,0x7E000000,0x7E000000,0x7E000000,0x7E000000,0x7E000000,
-0x7E000000,0x3E000000,0x3E000000,0x3E000000,0x28000001,0x23C0372,0x23C0372,0x23C0372,0x23C0372,0x23C0372,0x23C0372,0x2E000145,0x2E000145,0x2E000145,0x240000A9,0x7C0372,0x7C0372,0x7C0372,0x1C000212,0x14000372,0xF61C016D,0x280374,0x280374,0xFE040014,0xCC000000,0x9C000000,0x9C000000,0x66000000,0xF6000112,0xB4000092,0x4E000019,0x2E000145,
-0x580372,};
-static const uint32_t g_etc1_to_bc7_m6_table169[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x940000,0x940000,0x940000,0x940000,0x940000,
-0x940000,0x12C0000,0x12C0000,0x12C0000,0x30000001,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x12C0000,0x12C0000,0x12C0000,0x30000001,0x12C0000,0x12C0000,0x12C0000,0x30000001,0x30000001,0xC680000,0x640000,0x640000,0x740000,0x7C0000,0x880000,0x880000,0xA80000,0x740000,0x7C0000,0xD40000,0x12C0000,
-0xD40000,0xC40000,0xC40000,0xC40000,0xC40000,0x1240000,0x1240000,0x1240000,0x17F80000,0x17F80000,0x60000001,0x1240000,0x1240000,0x1240000,0x17F80000,0x17F80000,0x60000001,0x17F80000,0x17F80000,0x60000001,0x60000001,0x1240000,0x1240000,0x1240000,0x17F80000,0x17F80000,0x60000001,0x17F80000,0x17F80000,0x60000001,0x60000001,0x17F80000,
-0x17F80000,0x60000001,0x60000001,0x60000001,0xE40000,0xD00000,0xC40000,0x3080000,0x1480000,0x1A00000,0x1E00000,0x29FC0000,0x2F40000,0x1240000,0x1A00000,0x60000001,0x1A00000,0x1340000,0x1C80000,0x69FC0000,0x98000001,0x1C80000,0x69FC0000,0x98000001,0x69FC0000,0x98000001,0x98000001,0x1C80000,0x69FC0000,0x98000001,0x69FC0000,0x98000001,
-0x98000001,0x69FC0000,0x98000001,0x98000001,0x98000001,0x1C80000,0x69FC0000,0x98000001,0x69FC0000,0x98000001,0x98000001,0x69FC0000,0x98000001,0x98000001,0x98000001,0x69FC0000,0x98000001,0x98000001,0x98000001,0x98000001,0x3800000,0x1480000,0x1480000,0x7FC0000,0x55FC0000,0x81F40000,0x98000001,0x98000001,0x1A40000,0x29FC0000,0x93F80000,0x98000001,
-0x41FC0000,0x9832DC,0xFE741765,0xCC6412C4,0x986412C5,0xFE440E76,0xDE340525,0xA0440799,0xAE340B04,0x942C055E,0x7C300B06,0xFE18169C,0xE2000481,0xA0200679,0xB4000691,0x96000012,0x7C080656,0x9600152B,0x840007FB,0x720009EB,0x6400152B,0xE032DC,0xC0001733,0x980012C5,0xA2001322,0x8C000906,0x7A000CD6,0x8C001DCF,0x7C000F22,0x6E000F63,0x62001933,0x1C432DC,
-0x6C00213C,0x60001E14,0x5600247F,0x4A0032DC,0xFE641ADA,0xFE8C29F4,0xFE8C2C04,0xFE2C081A,0xFA00002A,0xBC00000D,0x9C08003B,0x900000E2,0xFE4419D3,0xFE100626,0x960005A9,0x6E000F63,0x13C32DC,0xC8152C,0xFEA405E1,0xC0940480,0x98940481,0xFE740672,0xCA640005,0x9C6C007D,0xA2640620,0x8E5C0132,0x7C640622,0x12C152B,0xE2000481,0x98480481,0xB4000691,0x96000012,
-0x7C1C0622,0x1BF8152B,0x840007FB,0x720009EB,0x6400152B,0x12C152B,0xE2000481,0x98480481,0xB4000691,0x96000012,0x7C1C0622,0x1BF8152B,0x840007FB,0x720009EB,0x6400152B,0x1BF8152B,0x840007FB,0x720009EB,0x6400152B,0x6400152B,0xFE940C03,0xF6BC1178,0xFAC41144,0xFE540456,0xFA00002A,0xBC00000D,0x9A180002,0x900000E2,0xFE780C41,0xFE240375,0x9A000551,0x720009EB,
-0x1AC152B,0x6412C4,0x6412C4,0x6412C4,0x6412C4,0xF43404E4,0xF43404E4,0xF43404E4,0x843404E4,0x843404E4,0x603004E5,0xE0000480,0xE0000480,0xE0000480,0x90000005,0x90000005,0x641000C2,0x6C000482,0x6C000482,0x5C0000A9,0x48000482,0x9012C3,0x9012C3,0x9012C3,0x7A000785,0x7A000785,0x5E000533,0x620008E2,0x620008E2,0x520003DE,0x460006A3,0x12412C3,
-0x12412C3,0x44000B9D,0x3E000C56,0x300012C3,0xFE3C08B8,0xF4580E45,0x6412C4,0xFE1C0258,0xF0000001,0xB8000001,0xA6040018,0x8000000D,0xFE200802,0xFE0001C8,0x860004C8,0x520003DE,0xD012C3,0x940480,0x940480,0x940480,0x940480,0xC2640000,0xC2640000,0xC2640000,0x78640000,0x78640000,0x60640001,0xDC0480,0xDC0480,0xDC0480,0x8C0C0001,0x8C0C0001,
-0x62340001,0x1BC0480,0x1BC0480,0x5C0000A9,0x48000482,0xDC0480,0xDC0480,0xDC0480,0x8C0C0001,0x8C0C0001,0x62340001,0x1BC0480,0x1BC0480,0x5C0000A9,0x48000482,0x1BC0480,0x1BC0480,0x5C0000A9,0x48000482,0x48000482,0xFA6C0200,0xFC880288,0x940480,0xFE3400B9,0xEE040000,0xB6040000,0x9E140000,0x8000000D,0xFA480244,0xFC140091,0x1380480,0x5C0000A9,
-0x1380480,0xFC0620,0xFEC8000D,0xB4C40000,0x98C40001,0x3740620,0xCC5C0001,0x9A8C0001,0x3FFC0620,0x96000012,0x7C000622,0x3740620,0xCC5C0001,0x9A8C0001,0x3FFC0620,0x96000012,0x7C000622,0x3FFC0620,0x96000012,0x7C000622,0x7C000622,0x3740620,0xCC5C0001,0x9A8C0001,0x3FFC0620,0x96000012,0x7C000622,0x3FFC0620,0x96000012,0x7C000622,0x7C000622,0x3FFC0620,
-0x96000012,0x7C000622,0x7C000622,0x7C000622,0xFAC80422,0x10C0620,0xFEEC0469,0xFE740190,0xF8040029,0xBC00000D,0x98240001,0x90000091,0xFEAC03F5,0xFE4C013D,0xA2300000,0x7C000622,0xDFC0620,0x3004E4,0x3004E4,0x3004E4,0x3004E4,0x3004E4,0x3004E4,0x3004E4,0x3004E4,0x3004E4,0x3004E4,0x96000000,0x96000000,0x96000000,0x96000000,0x96000000,
-0x96000000,0x4A000000,0x4A000000,0x4A000000,0x30000001,0x4804E2,0x4804E2,0x4804E2,0x4804E2,0x4804E2,0x4804E2,0x3A0001CD,0x3A0001CD,0x3A0001CD,0x2E0000EA,0x9404E2,0x9404E2,0x9404E2,0x20000305,0x180004E2,0xFA240265,0x3004E4,0x3004E4,0xFE100071,0xF4000000,0xBA000000,0xBA000000,0x7A000000,0xF60001C2,0xD60000CD,0x5E000024,0x3A0001CD,
-0x6804E2,};
-static const uint32_t g_etc1_to_bc7_m6_table170[] = {
-0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x80000,
-0x80000,0x80000,0x80000,0x1,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x80000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,
-0xAC0000,0x15C0000,0x15C0000,0x15C0000,0x38000001,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0xAC0000,0x15C0000,0x15C0000,0x15C0000,0x38000001,0x15C0000,0x15C0000,0x15C0000,0x38000001,0x38000001,0x7C0000,0x740000,0x740000,0x6840000,0x900000,0x9C0000,0x9C0000,0x2C00000,0x6840000,0x900000,0xF40000,0x15C0000,
-0xF40000,0xD40000,0xD40000,0xD40000,0xD40000,0x13C0000,0x13C0000,0x13C0000,0x21FC0000,0x21FC0000,0x68000001,0x13C0000,0x13C0000,0x13C0000,0x21FC0000,0x21FC0000,0x68000001,0x21FC0000,0x21FC0000,0x68000001,0x68000001,0x13C0000,0x13C0000,0x13C0000,0x21FC0000,0x21FC0000,0x68000001,0x21FC0000,0x21FC0000,0x68000001,0x68000001,0x21FC0000,
-0x21FC0000,0x68000001,0x68000001,0x68000001,0x4F40000,0x8E00000,0xD40000,0x1200000,0x1640000,0x1C00000,0x5FC0000,0x35F80000,0x3080000,0x13C0000,0x1C00000,0x68000001,0x1C00000,0x1440000,0x1E00000,0x75FC0000,0xA0000001,0x1E00000,0x75FC0000,0xA0000001,0x75FC0000,0xA0000001,0xA0000001,0x1E00000,0x75FC0000,0xA0000001,0x75FC0000,0xA0000001,
-0xA0000001,0x75FC0000,0xA0000001,0xA0000001,0xA0000001,0x1E00000,0x75FC0000,0xA0000001,0x75FC0000,0xA0000001,0xA0000001,0x75FC0000,0xA0000001,0xA0000001,0xA0000001,0x75FC0000,0xA0000001,0xA0000001,0xA0000001,0xA0000001,0x3940000,0x5580000,0x5580000,0x1BFC0000,0x63FC0000,0x8BF40000,0xA0000001,0xA0000001,0x1B80000,0x39FC0000,0x9DCC0000,0xA0000001,
-0x51FC0000,0xA43680,0xFE801AD5,0xD470152D,0xA070152D,0xFE5C1112,0xE440067D,0xAA4C0931,0xB83C0C40,0x9A38068A,0x843C0C42,0xFE3017F0,0xF0080485,0xAA280735,0xC6000655,0xA0080012,0x86100686,0xA004152B,0x90000767,0x7E00095F,0x6C04152B,0xF43680,0xD20018EB,0xA204152C,0xAE0013F2,0x9800099A,0x80000D92,0x92001E87,0x86000EDF,0x76000F1F,0x68001953,0x1F03680,
-0x7200234C,0x6C001F94,0x5C00261B,0x50003684,0xFE781E55,0xFE8C2DE0,0xF8A02FFD,0xFE400A6F,0xFE0C0052,0xC804000E,0xA4100086,0x98000089,0xFE541CF7,0xFE18084E,0xA4000539,0x76000F1F,0x15C3680,0xD8152C,0xFEB00631,0xC8A40480,0xA0A40481,0xFE8006A6,0xD2740005,0xA47C007D,0xAA740620,0x966C0132,0x84740622,0x144152B,0xEA100481,0xA0580481,0xC6000651,0xA008000E,
-0x842C0622,0x27F8152B,0x90000763,0x7E00095B,0x6C00152B,0x144152B,0xEA100481,0xA0580481,0xC6000651,0xA008000E,0x842C0622,0x27F8152B,0x90000763,0x7E00095B,0x6C00152B,0x27F8152B,0x90000763,0x7E00095B,0x6C00152B,0x6C00152B,0xFEA00C86,0xFECC1178,0xFECC1164,0xFE6C04E5,0xFE100035,0xC410000D,0xA2280002,0x98000085,0xFE880CA0,0xFE4003DB,0xA40004F9,0x7E00095B,
-0x1D0152B,0x70152C,0x70152C,0x70152C,0x70152C,0xFE3C0624,0xFE3C0624,0xFE3C0624,0x8E3C0620,0x8E3C0620,0x683C0621,0xF4040480,0xF4040480,0xF4040480,0x9E040011,0x9E040011,0x6C180131,0x78040480,0x78040480,0x64000081,0x50040482,0xA4152B,0xA4152B,0xA4152B,0x86000889,0x86000889,0x68000641,0x6E000966,0x6E000966,0x5E0003E6,0x4C0006C3,0x14C152B,
-0x14C152B,0x4A000D01,0x44000D62,0x3600152B,0xFE4C0A8D,0xFA641079,0x70152C,0xFE2C037D,0xFE08000D,0xC608000C,0xB6080038,0x8E040001,0xFC3009DD,0xFE0002CC,0x960004B9,0x5E0003E6,0xE8152B,0xA40480,0xA40480,0xA40480,0xA40480,0xCA740000,0xCA740000,0xCA740000,0x80740000,0x80740000,0x68740001,0xF40480,0xF40480,0xF40480,0x941C0001,0x941C0001,
-0x6A440001,0x1F00480,0x1F00480,0x6400007D,0x50000482,0xF40480,0xF40480,0xF40480,0x941C0001,0x941C0001,0x6A440001,0x1F00480,0x1F00480,0x6400007D,0x50000482,0x1F00480,0x1F00480,0x6400007D,0x50000482,0x50000482,0xFE740220,0xF49802AD,0xA40480,0xFE4400DA,0xF6140000,0xBE140000,0xA6240000,0x8E000001,0xF2600265,0xFE2400A4,0x15C0480,0x6400007D,
-0x15C0480,0x10C0620,0xFEDC0020,0xBCD40000,0xA0D40001,0x38C0620,0xD46C0001,0xA29C0001,0x4BFC0620,0xA0000005,0x84000622,0x38C0620,0xD46C0001,0xA29C0001,0x4BFC0620,0xA0000005,0x84000622,0x4BFC0620,0xA0000005,0x84000622,0x84000622,0x38C0620,0xD46C0001,0xA29C0001,0x4BFC0620,0xA0000005,0x84000622,0x4BFC0620,0xA0000005,0x84000622,0x84000622,0x4BFC0620,
-0xA0000005,0x84000622,0x84000622,0x84000622,0xFED00442,0x71C0620,0xFB040480,0xFC9001C4,0xFE100035,0xCA000004,0xA0340001,0x9C00006A,0xF4C80422,0xFE640179,0xAA400000,0x84000622,0x1DF80620,0x3C0620,0x3C0620,0x3C0620,0x3C0620,0x3C0620,0x3C0620,0x3C0620,0x3C0620,0x3C0620,0x3C0620,0xAC040000,0xAC040000,0xAC040000,0xAC040000,0xAC040000,
-0xAC040000,0x54040000,0x54040000,0x54040000,0x38040001,0x580620,0x580620,0x580620,0x580620,0x580620,0x580620,0x4600021D,0x4600021D,0x4600021D,0x340000FA,0xB00620,0xB00620,0xB00620,0x260003A9,0x1C000622,0xFE2C0349,0x3C0620,0x3C0620,0xFA1800F4,0xFC08000D,0xD2040000,0xD2040000,0x8A040000,0xFA08028A,0xFE0000E8,0x66000019,0x4600021D,
-0x7C0620,};
-static const uint32_t g_etc1_to_bc7_m6_table171[] = {
-0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x380000,
-0x380000,0x380000,0x380000,0x8000001,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x2140000,0x2140000,0x2140000,0x1C0000,0x280000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,
-0xC40000,0x18C0000,0x18C0000,0x18C0000,0x40000001,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0x18C0000,0x18C0000,0x18C0000,0x40000001,0x18C0000,0x18C0000,0x18C0000,0x40000001,0x40000001,0x8C0000,0x840000,0x840000,0x2980000,0xA40000,0xB40000,0xB40000,0xDC0000,0x2980000,0xA40000,0x1180000,0x18C0000,
-0x1180000,0xE40000,0xE40000,0xE40000,0xE40000,0x3500000,0x3500000,0x3500000,0x2DFC0000,0x2DFC0000,0x70000001,0x3500000,0x3500000,0x3500000,0x2DFC0000,0x2DFC0000,0x70000001,0x2DFC0000,0x2DFC0000,0x70000001,0x70000001,0x3500000,0x3500000,0x3500000,0x2DFC0000,0x2DFC0000,0x70000001,0x2DFC0000,0x2DFC0000,0x70000001,0x70000001,0x2DFC0000,
-0x2DFC0000,0x70000001,0x70000001,0x70000001,0x1080000,0xF40000,0xE40000,0x3340000,0x1800000,0x1E40000,0x13F80000,0x3FFC0000,0x31C0000,0x3500000,0x1E40000,0x70000001,0x1E40000,0x1540000,0x1F80000,0x81FC0000,0xA8000001,0x1F80000,0x81FC0000,0xA8000001,0x81FC0000,0xA8000001,0xA8000001,0x1F80000,0x81FC0000,0xA8000001,0x81FC0000,0xA8000001,
-0xA8000001,0x81FC0000,0xA8000001,0xA8000001,0xA8000001,0x1F80000,0x81FC0000,0xA8000001,0x81FC0000,0xA8000001,0xA8000001,0x81FC0000,0xA8000001,0xA8000001,0xA8000001,0x81FC0000,0xA8000001,0xA8000001,0xA8000001,0xA8000001,0x3A80000,0xD680000,0xD680000,0x2FFC0000,0x71FC0000,0x95F40000,0xA8000001,0xA8000001,0x3CC0000,0x4BFC0000,0xA5DC0000,0xA8000001,
-0x5FFC0000,0xB43680,0xFE8C1BA1,0xDC80152D,0xA880152D,0xFE6811EA,0xEC50067D,0xB25C0931,0xC04C0C40,0xA248068A,0x8C4C0C42,0xFE441883,0xF8180485,0xB2380735,0xCC0C0651,0xA8180012,0x8E200686,0xA814152B,0x98040733,0x86040933,0x7414152B,0x10C3680,0xE20017A1,0xAA14152C,0xC0001242,0xA2000823,0x8C000CC2,0xA2001CE9,0x92000CD7,0x80000D2B,0x7000182C,0xBF83680,
-0x7E0021E4,0x72001DD4,0x660024F4,0x58003684,0xFE8C1F58,0xFCA82E0A,0xFEAC3001,0xFE540B96,0xFE2000B6,0xD014000E,0xAC200086,0xA20C0082,0xFE701E35,0xFE300991,0xB00004B1,0x80000D2B,0x17C3680,0xE8152C,0xFEC40690,0xD0B40480,0xA8B40481,0xFE9806E6,0xDA840005,0xAC8C007D,0xB2840620,0x9E7C0132,0x8C840622,0x15C152B,0xF2200481,0xA8680481,0xD2000629,0xA818000E,
-0x8C3C0622,0x33F8152B,0x960006DB,0x840008D3,0x7400152B,0x15C152B,0xF2200481,0xA8680481,0xD2000629,0xA818000E,0x8C3C0622,0x33F8152B,0x960006DB,0x840008D3,0x7400152B,0x33F8152B,0x960006DB,0x840008D3,0x7400152B,0x7400152B,0xFEB40CC9,0xF6DC11D2,0xFAE411A1,0xFE78057E,0xFE280069,0xCC20000D,0xAA380002,0xA400004B,0xFE980D11,0xFE54047D,0xB00004B0,0x840008D3,
-0x1F0152B,0x80152C,0x80152C,0x80152C,0x80152C,0xFE500631,0xFE500631,0xFE500631,0x964C0620,0x964C0620,0x704C0621,0xFC140480,0xFC140480,0xFC140480,0xA6140011,0xA6140011,0x74280131,0x80140480,0x80140480,0x6C0C007A,0x58140482,0xBC152B,0xBC152B,0xBC152B,0x980007B9,0x980007B9,0x70040621,0x7A000866,0x7A000866,0x680002AA,0x580005EB,0x17C152B,
-0x17C152B,0x56000C19,0x4A000C82,0x3E00152B,0xFC640B12,0xFE6C10C1,0x80152C,0xFE3C03E0,0xFE1C001D,0xCE18000C,0xBE180038,0x96140001,0xFE3C0A38,0xFE18031E,0xA8000481,0x680002AA,0x10C152B,0xB40480,0xB40480,0xB40480,0xB40480,0xD2840000,0xD2840000,0xD2840000,0x88840000,0x88840000,0x70840001,0x10C0480,0x10C0480,0x10C0480,0x9C2C0001,0x9C2C0001,
-0x72540001,0xBF80480,0xBF80480,0x6C00004A,0x58000482,0x10C0480,0x10C0480,0x10C0480,0x9C2C0001,0x9C2C0001,0x72540001,0xBF80480,0xBF80480,0x6C00004A,0x58000482,0xBF80480,0xBF80480,0x6C00004A,0x58000482,0x58000482,0xFE900221,0xFCA802AD,0xB40480,0xFE5C00E1,0xFE240000,0xC6240000,0xAE340000,0x980C0000,0xFA700265,0xFA4000C8,0x17C0480,0x6C00004A,
-0x17C0480,0x11C0620,0xFEEC0041,0xC4E40000,0xA8E40001,0x3A40620,0xDC7C0001,0xAAAC0001,0x57FC0620,0xA8000001,0x8C000622,0x3A40620,0xDC7C0001,0xAAAC0001,0x57FC0620,0xA8000001,0x8C000622,0x57FC0620,0xA8000001,0x8C000622,0x8C000622,0x3A40620,0xDC7C0001,0xAAAC0001,0x57FC0620,0xA8000001,0x8C000622,0x57FC0620,0xA8000001,0x8C000622,0x8C000622,0x57FC0620,
-0xA8000001,0x8C000622,0x8C000622,0x8C000622,0xFAF00451,0xF2C0620,0xFF0C04A0,0xFEA001F9,0xFE380055,0xD4040000,0xA8440001,0xA400004A,0xFCD80422,0xFE8401A5,0xB2500000,0x8C000622,0x2BFC0620,0x4C0620,0x4C0620,0x4C0620,0x4C0620,0x4C0620,0x4C0620,0x4C0620,0x4C0620,0x4C0620,0x4C0620,0xB4140000,0xB4140000,0xB4140000,0xB4140000,0xB4140000,
-0xB4140000,0x5C140000,0x5C140000,0x5C140000,0x40140001,0x700620,0x700620,0x700620,0x700620,0x700620,0x700620,0x52000185,0x52000185,0x52000185,0x4000007A,0xE40620,0xE40620,0xE40620,0x32000321,0x24000622,0xF63C0374,0x4C0620,0x4C0620,0xFE2C0109,0xFC1C0019,0xDA140000,0xDA140000,0x92140000,0xFC1C02AD,0xFA0C00DD,0x7A040000,0x52000185,
-0xA00620,};
-static const uint32_t g_etc1_to_bc7_m6_table172[] = {
-0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x700000,
-0x700000,0x700000,0x700000,0x12000000,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x280000,0x280000,0x280000,0x380000,0x500000,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,
-0x2DC0000,0x1C40000,0x1C40000,0x1C40000,0x4A000000,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x1C40000,0x1C40000,0x1C40000,0x4A000000,0x1C40000,0x1C40000,0x1C40000,0x4A000000,0x4A000000,0xA00000,0x940001,0x940001,0x4AC0000,0xBC0000,0xCC0000,0xCC0000,0xFC0000,0x4AC0000,0xBC0000,0x13C0000,0x1C40000,
-0x13C0000,0xF40001,0xF40001,0xF40001,0xF40001,0x16C0000,0x16C0000,0x16C0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x16C0000,0x16C0000,0x16C0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x3BFC0000,0x3BFC0000,0x7A000000,0x7A000000,0x16C0000,0x16C0000,0x16C0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x3BFC0000,0x3BFC0000,0x7A000000,0x7A000000,0x3BFC0000,
-0x3BFC0000,0x7A000000,0x7A000000,0x7A000000,0x51C0000,0xB040000,0xF40001,0x34C0000,0x19C0000,0x7FC0000,0x21FC0000,0x4BFC0000,0x1340000,0x16C0000,0x7FC0000,0x7A000000,0x7FC0000,0x1640001,0x19FC0000,0x8FF80000,0xB2000000,0x19FC0000,0x8FF80000,0xB2000000,0x8FF80000,0xB2000000,0xB2000000,0x19FC0000,0x8FF80000,0xB2000000,0x8FF80000,0xB2000000,
-0xB2000000,0x8FF80000,0xB2000000,0xB2000000,0xB2000000,0x19FC0000,0x8FF80000,0xB2000000,0x8FF80000,0xB2000000,0xB2000000,0x8FF80000,0xB2000000,0xB2000000,0xB2000000,0x8FF80000,0xB2000000,0xB2000000,0xB2000000,0xB2000000,0x1C00000,0x77C0000,0x77C0000,0x45FC0000,0x7FFC0000,0xA1F00000,0xB2000000,0xB2000000,0x1E80000,0x5DFC0000,0xAFD00000,0xB2000000,
-0x71FC0000,0xC43684,0xFEA41C83,0xE690152B,0xB290152B,0xFE801302,0xF664067B,0xBA6C0933,0xC8600C42,0xAC5C0686,0x965C0C42,0xFE5C1959,0xFE28048A,0xBA480733,0xD620064F,0xB0280012,0x9630068A,0xB224152C,0xA0140735,0x8E140931,0x7C24152D,0x3243680,0xF400169F,0xB228152B,0xD20010AA,0xAE000711,0x94000C50,0xAE001B7F,0x9E000AD1,0x8C000B51,0x7A0016F9,0x17FC3680,
-0x8A00206C,0x7E001C08,0x720023A4,0x62003680,0xFEA0204E,0xF6BC2EC4,0xF8C0308C,0xFE6C0D33,0xFE38015B,0xDA28000E,0xB6340082,0xAA1C0086,0xFE781F23,0xFE440AEA,0xBA0C049F,0x8C000B51,0x1A43680,0xFC152B,0xFED40722,0xD8C80482,0xB2C40482,0xFEB00749,0xE2940006,0xB6A0007A,0xBA980621,0xA8900131,0x96940621,0x374152B,0xFC300481,0xB2780480,0xDE080621,0xB0280011,
-0x964C0620,0x3FFC152B,0xA6000662,0x9000084C,0x7C00152C,0x374152B,0xFC300481,0xB2780480,0xDE080621,0xB0280011,0x964C0620,0x3FFC152B,0xA6000662,0x9000084C,0x7C00152C,0x3FFC152B,0xA6000662,0x9000084C,0x7C00152C,0x7C00152C,0xFED00D38,0xFEEC11D9,0xFEEC11E2,0xFE940602,0xFE4800C6,0xD630000D,0xB24C0001,0xAE04003D,0xFEB40D8E,0xFE700541,0xBC000486,0x9000084C,
-0xDFC152B,0x90152B,0x90152B,0x90152B,0x90152B,0xFE600653,0xFE600653,0xFE600653,0x9E600622,0x9E600622,0x7A5C0622,0xFE280489,0xFE280489,0xFE280489,0xB028000E,0xB028000E,0x7E3C0132,0x88280481,0x88280481,0x741C007D,0x62240481,0xD4152B,0xD4152B,0xD4152B,0xA80006F1,0xA80006F1,0x7A140620,0x86000771,0x86000771,0x7400019D,0x62000529,0x1B0152B,
-0x1B0152B,0x60000B4C,0x56000B91,0x4800152C,0xFE740B63,0xFC8810CB,0x90152B,0xFE54045A,0xFE300042,0xD628000B,0xC628003B,0x9E240002,0xFE500A8E,0xFE30038A,0xB2100480,0x7400019D,0x130152B,0xC40482,0xC40482,0xC40482,0xC40482,0xDA980001,0xDA980001,0xDA980001,0x92940001,0x92940001,0x7A940001,0x3240480,0x3240480,0x3240480,0xA63C0001,0xA63C0001,
-0x7A680000,0x17FC0480,0x17FC0480,0x78000028,0x62000480,0x3240480,0x3240480,0x3240480,0xA63C0001,0xA63C0001,0x7A680000,0x17FC0480,0x17FC0480,0x78000028,0x62000480,0x17FC0480,0x17FC0480,0x78000028,0x62000480,0x62000480,0xFEA00244,0xF6BC02D2,0xC40482,0xFE780109,0xFC3C0004,0xD0340000,0xB6480000,0xA21C0000,0xF8880288,0xFC5800DD,0x1A40480,0x78000028,
-0x1A40480,0x12C0622,0xFF00006A,0xCEF40001,0xB2F40001,0x1C00620,0xE68C0001,0xB2C00000,0x65F80620,0xB2100000,0x96000620,0x1C00620,0xE68C0001,0xB2C00000,0x65F80620,0xB2100000,0x96000620,0x65F80620,0xB2100000,0x96000620,0x96000620,0x1C00620,0xE68C0001,0xB2C00000,0x65F80620,0xB2100000,0x96000620,0x65F80620,0xB2100000,0x96000620,0x96000620,0x65F80620,
-0xB2100000,0x96000620,0x96000620,0x96000620,0xFEF80479,0x9400620,0xFD2804B1,0xFEC00225,0xFE500089,0xDC180000,0xB2500000,0xAC000034,0xFEF00451,0xFEA001E5,0xBA640001,0x96000620,0x3DF80620,0x5C0622,0x5C0622,0x5C0622,0x5C0622,0x5C0622,0x5C0622,0x5C0622,0x5C0622,0x5C0622,0x5C0622,0xBA280001,0xBA280001,0xBA280001,0xBA280001,0xBA280001,
-0xBA280001,0x66240001,0x66240001,0x66240001,0x4A240001,0x8C0620,0x8C0620,0x8C0620,0x8C0620,0x8C0620,0x8C0620,0x620000E9,0x620000E9,0x620000E9,0x4800001D,0x1180620,0x1180620,0x1180620,0x3E0002A1,0x2E000620,0xFE4C037A,0x5C0622,0x5C0622,0xFE3C0122,0xFC300029,0xE2280001,0xE2280001,0x9A280001,0xF83002D2,0xFC1C00F4,0x82180000,0x620000E9,
-0xC80620,};
-static const uint32_t g_etc1_to_bc7_m6_table173[] = {
-0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0xA00000,
-0xA00000,0xA00000,0xA00000,0x1A000000,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x4380000,0x4380000,0x4380000,0x500000,0x700000,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x2F40000,
-0x2F40000,0x1F40000,0x1F40000,0x1F40000,0x52000000,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x1F40000,0x1F40000,0x1F40000,0x52000000,0x1F40000,0x1F40000,0x1F40000,0x52000000,0x52000000,0xB00000,0xA40001,0xA40001,0xC00000,0xD00000,0xE00000,0xE00000,0x3140000,0xC00000,0xD00000,0x1600000,0x1F40000,
-0x1600000,0x1040001,0x1040001,0x1040001,0x1040001,0x1840000,0x1840000,0x1840000,0x47FC0000,0x47FC0000,0x82000000,0x1840000,0x1840000,0x1840000,0x47FC0000,0x47FC0000,0x82000000,0x47FC0000,0x47FC0000,0x82000000,0x82000000,0x1840000,0x1840000,0x1840000,0x47FC0000,0x47FC0000,0x82000000,0x47FC0000,0x47FC0000,0x82000000,0x82000000,0x47FC0000,
-0x47FC0000,0x82000000,0x82000000,0x82000000,0x1300000,0x1180000,0x1040001,0x1640000,0x1B80000,0x17FC0000,0x2FFC0000,0x57F80000,0x1480000,0x1840000,0x17FC0000,0x82000000,0x17FC0000,0x1740001,0x31FC0000,0x9BF80000,0xBA000000,0x31FC0000,0x9BF80000,0xBA000000,0x9BF80000,0xBA000000,0xBA000000,0x31FC0000,0x9BF80000,0xBA000000,0x9BF80000,0xBA000000,
-0xBA000000,0x9BF80000,0xBA000000,0xBA000000,0xBA000000,0x31FC0000,0x9BF80000,0xBA000000,0x9BF80000,0xBA000000,0xBA000000,0x9BF80000,0xBA000000,0xBA000000,0xBA000000,0x9BF80000,0xBA000000,0xBA000000,0xBA000000,0xBA000000,0x1D40000,0xF8C0000,0xF8C0000,0x59FC0000,0x8DFC0000,0xABF00000,0xBA000000,0xBA000000,0x1FC0000,0x6FFC0000,0xB7E00000,0xBA000000,
-0x7FFC0000,0xD43684,0xFEB01D6B,0xEEA0152B,0xBAA0152B,0xFE8C1422,0xFE74067B,0xC27C0933,0xD0700C42,0xB46C0686,0x9E6C0C42,0xFE681A21,0xFE4004BA,0xC2580733,0xDE30064F,0xB8380012,0x9E40068A,0xBA34152C,0xA8240735,0x96240931,0x8434152D,0x33C3680,0xFE04164D,0xBA38152B,0xE2000F5A,0xBA000681,0x9E080C40,0xBA001A5F,0xA8000936,0x940009ED,0x82001640,0x23FC3680,
-0x96001F3C,0x84001A90,0x78002270,0x6A003680,0xFEA82162,0xFECC2EC4,0xFECC30A4,0xFE800E82,0xFE4C0223,0xE238000E,0xBE440082,0xB22C0086,0xFE902009,0xFE5C0C52,0xC21C049F,0x940009ED,0x1C83680,0x10C152B,0xFEE80793,0xE0D80482,0xBAD40482,0xFEC407A3,0xEAA40006,0xBEB0007A,0xC2A80621,0xB0A00131,0x9EA40621,0x38C152B,0xFE4C0491,0xBA880480,0xE6180621,0xB8380011,
-0x9E5C0620,0x4BFC152B,0xAC0005E6,0x960007E4,0x8400152C,0x38C152B,0xFE4C0491,0xBA880480,0xE6180621,0xB8380011,0x9E5C0620,0x4BFC152B,0xAC0005E6,0x960007E4,0x8400152C,0x4BFC152B,0xAC0005E6,0x960007E4,0x8400152C,0x8400152C,0xFEE40DD9,0xF900122B,0xFB041203,0xFEB006D2,0xFE680131,0xDE40000D,0xBA5C0001,0xB80C0038,0xFEC40DFB,0xFE8405C2,0xC6040480,0x960007E4,
-0x1DF8152B,0xA0152B,0xA0152B,0xA0152B,0xA0152B,0xFE740672,0xFE740672,0xFE740672,0xA6700622,0xA6700622,0x826C0622,0xFE3C049B,0xFE3C049B,0xFE3C049B,0xB838000E,0xB838000E,0x864C0132,0x90380481,0x90380481,0x7C2C007D,0x6A340481,0xEC152B,0xEC152B,0xEC152B,0xBA000681,0xBA000681,0x82240620,0x980006B1,0x980006B1,0x7A0000E9,0x680004B9,0x1E4152B,
-0x1E4152B,0x6C000A8C,0x5C000AD1,0x5000152C,0xFE840BAE,0xF4981122,0xA0152B,0xFE6804E6,0xFE440072,0xDE38000B,0xCE38003B,0xA6340002,0xFE640B11,0xFE440409,0xBA200480,0x7A0000E9,0x154152B,0xD40482,0xD40482,0xD40482,0xD40482,0xE2A80001,0xE2A80001,0xE2A80001,0x9AA40001,0x9AA40001,0x82A40001,0x33C0480,0x33C0480,0x33C0480,0xAE4C0001,0xAE4C0001,
-0x82780000,0x23FC0480,0x23FC0480,0x7E000014,0x6A000480,0x33C0480,0x33C0480,0x33C0480,0xAE4C0001,0xAE4C0001,0x82780000,0x23FC0480,0x23FC0480,0x7E000014,0x6A000480,0x23FC0480,0x23FC0480,0x7E000014,0x6A000480,0x6A000480,0xFAB40265,0xFECC02D2,0xD40482,0xFE880122,0xFE540008,0xD8440000,0xBE580000,0xAA2C0000,0xFE940290,0xFE6800F4,0x1C80480,0x7E000014,
-0x1C80480,0x13C0622,0xFF1800A2,0xD7040001,0xBB040001,0x1D80620,0xEE9C0001,0xBAD00000,0x71F80620,0xBA200000,0x9E000620,0x1D80620,0xEE9C0001,0xBAD00000,0x71F80620,0xBA200000,0x9E000620,0x71F80620,0xBA200000,0x9E000620,0x9E000620,0x1D80620,0xEE9C0001,0xBAD00000,0x71F80620,0xBA200000,0x9E000620,0x71F80620,0xBA200000,0x9E000620,0x9E000620,0x71F80620,
-0xBA200000,0x9E000620,0x9E000620,0x9E000620,0xFF140482,0x1540620,0xF53804E2,0xFED80269,0xFE7C00B5,0xE4280000,0xBA600000,0xB6000019,0xF7080480,0xFEC00221,0xC2740001,0x9E000620,0x4BFC0620,0x6C0622,0x6C0622,0x6C0622,0x6C0622,0x6C0622,0x6C0622,0x6C0622,0x6C0622,0x6C0622,0x6C0622,0xC2380001,0xC2380001,0xC2380001,0xC2380001,0xC2380001,
-0xC2380001,0x6E340001,0x6E340001,0x6E340001,0x52340001,0xA40620,0xA40620,0xA40620,0xA40620,0xA40620,0xA40620,0x74000089,0x74000089,0x74000089,0x52000000,0x14C0620,0x14C0620,0x14C0620,0x4400022D,0x36000620,0xF860039D,0x6C0622,0x6C0622,0xFE4C013D,0xFE3C003A,0xEA380001,0xEA380001,0xA2380001,0xFE3C02DA,0xFC300109,0x8A280000,0x74000089,
-0xE80620,};
-static const uint32_t g_etc1_to_bc7_m6_table174[] = {
-0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0xD00000,
-0xD00000,0xD00000,0xD00000,0x22000000,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0xC480000,0xC480000,0xC480000,0x680000,0x940000,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0xB40001,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0x30C0000,
-0x30C0000,0xBFC0000,0xBFC0000,0xBFC0000,0x5A000000,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0x30C0000,0xBFC0000,0xBFC0000,0xBFC0000,0x5A000000,0xBFC0000,0xBFC0000,0xBFC0000,0x5A000000,0x5A000000,0x8C00000,0xB40001,0xB40001,0xD40000,0xE40000,0xF80000,0xF80000,0x1300000,0xD40000,0xE40000,0x1800000,0xBFC0000,
-0x1800000,0x1140001,0x1140001,0x1140001,0x1140001,0x19C0000,0x19C0000,0x19C0000,0x53FC0000,0x53FC0000,0x8A000000,0x19C0000,0x19C0000,0x19C0000,0x53FC0000,0x53FC0000,0x8A000000,0x53FC0000,0x53FC0000,0x8A000000,0x8A000000,0x19C0000,0x19C0000,0x19C0000,0x53FC0000,0x53FC0000,0x8A000000,0x53FC0000,0x53FC0000,0x8A000000,0x8A000000,0x53FC0000,
-0x53FC0000,0x8A000000,0x8A000000,0x8A000000,0x1440000,0x1280000,0x1140001,0x3780000,0x1D40000,0x25FC0000,0x3DF80000,0x61FC0000,0x15C0000,0x19C0000,0x25FC0000,0x8A000000,0x25FC0000,0x1840001,0x49FC0000,0xA7F80000,0xC2000000,0x49FC0000,0xA7F80000,0xC2000000,0xA7F80000,0xC2000000,0xC2000000,0x49FC0000,0xA7F80000,0xC2000000,0xA7F80000,0xC2000000,
-0xC2000000,0xA7F80000,0xC2000000,0xC2000000,0xC2000000,0x49FC0000,0xA7F80000,0xC2000000,0xA7F80000,0xC2000000,0xC2000000,0xA7F80000,0xC2000000,0xC2000000,0xC2000000,0xA7F80000,0xC2000000,0xC2000000,0xC2000000,0xC2000000,0x1E80000,0x1A00000,0x1A00000,0x6DFC0000,0x9BFC0000,0xB5F00000,0xC2000000,0xC2000000,0x1FFC0000,0x81FC0000,0xBFF00000,0xC2000000,
-0x8FFC0000,0xE43684,0xFEC41E2C,0xF6B0152B,0xC2B0152B,0xFEA41532,0xFE8406AF,0xCA8C0933,0xD8800C42,0xBC7C0686,0xA67C0C42,0xFE801AF9,0xFE540527,0xCA680733,0xE640064F,0xC0480012,0xA650068A,0xC244152C,0xB0340735,0x9E340931,0x8C44152D,0x1543680,0xFE1416C3,0xC248152B,0xEE000E4A,0xC6000651,0xA6180C40,0xCC001953,0xB40007E6,0x9E0008C1,0x8C0015A5,0x2FFC3680,
-0x9C001E10,0x90001910,0x84002170,0x72003680,0xFEBC2236,0xF6DC2F82,0xF8E0311F,0xFE940FF3,0xFE640317,0xEA48000E,0xC6540082,0xBA3C0086,0xFEA42172,0xFE700DE2,0xCA2C049F,0x9E0008C1,0x1E83680,0x11C152B,0xFEF4082B,0xE8E80482,0xC2E40482,0xFED0081B,0xF2B40006,0xC6C0007A,0xCAB80621,0xB8B00131,0xA6B40621,0x3A4152B,0xFE6404B9,0xC2980480,0xEE280621,0xC0480011,
-0xA66C0620,0x57FC152B,0xB8000586,0xA0000789,0x8C00152C,0x3A4152B,0xFE6404B9,0xC2980480,0xEE280621,0xC0480011,0xA66C0620,0x57FC152B,0xB8000586,0xA0000789,0x8C00152C,0x57FC152B,0xB8000586,0xA0000789,0x8C00152C,0x8C00152C,0xFEF80E2A,0xFF0C123B,0xFF0C124B,0xFEC0075E,0xFE7C01A9,0xE650000D,0xC26C0001,0xC01C0038,0xFEDC0E35,0xFE980692,0xCE140480,0xA0000789,
-0x2BFC152B,0xB0152B,0xB0152B,0xB0152B,0xB0152B,0xFE8406AB,0xFE8406AB,0xFE8406AB,0xAE800622,0xAE800622,0x8A7C0622,0xFE5004B9,0xFE5004B9,0xFE5004B9,0xC048000E,0xC048000E,0x8E5C0132,0x98480481,0x98480481,0x843C007D,0x72440481,0x104152B,0x104152B,0x104152B,0xC6000641,0xC6000641,0x8A340620,0xA20005F6,0xA20005F6,0x86000061,0x72000489,0x7FC152B,
-0x7FC152B,0x720009E8,0x66000A24,0x5800152C,0xFE900C2A,0xFCA81122,0xB0152B,0xFE78055A,0xFE5800B2,0xE648000B,0xD648003B,0xAE440002,0xFE780B5A,0xFE500485,0xC2300480,0x86000061,0x174152B,0xE40482,0xE40482,0xE40482,0xE40482,0xEAB80001,0xEAB80001,0xEAB80001,0xA2B40001,0xA2B40001,0x8AB40001,0x1540480,0x1540480,0x1540480,0xB65C0001,0xB65C0001,
-0x8A880000,0x2FFC0480,0x2FFC0480,0x8A000004,0x72000480,0x1540480,0x1540480,0x1540480,0xB65C0001,0xB65C0001,0x8A880000,0x2FFC0480,0x2FFC0480,0x8A000004,0x72000480,0x2FFC0480,0x2FFC0480,0x8A000004,0x72000480,0x72000480,0xF6C80288,0xF6DC02F9,0xE40482,0xFE980145,0xFC6C0019,0xE0540000,0xC6680000,0xB23C0000,0xFAAC02AD,0xFE800120,0x1E80480,0x8A000004,
-0x1E80480,0x14C0622,0xFF2400DA,0xDF140001,0xC3140001,0x1F00620,0xF6AC0001,0xC2E00000,0x7DF80620,0xC2300000,0xA6000620,0x1F00620,0xF6AC0001,0xC2E00000,0x7DF80620,0xC2300000,0xA6000620,0x7DF80620,0xC2300000,0xA6000620,0xA6000620,0x1F00620,0xF6AC0001,0xC2E00000,0x7DF80620,0xC2300000,0xA6000620,0x7DF80620,0xC2300000,0xA6000620,0xA6000620,0x7DF80620,
-0xC2300000,0xA6000620,0xA6000620,0xA6000620,0xFB2C04B1,0x1640620,0xFD4804E2,0xFEEC029A,0xFE9000F5,0xEC380000,0xC2700000,0xC000000D,0xFF180480,0xFECC0262,0xCA840001,0xA6000620,0x5BFC0620,0x7C0622,0x7C0622,0x7C0622,0x7C0622,0x7C0622,0x7C0622,0x7C0622,0x7C0622,0x7C0622,0x7C0622,0xCA480001,0xCA480001,0xCA480001,0xCA480001,0xCA480001,
-0xCA480001,0x76440001,0x76440001,0x76440001,0x5A440001,0xBC0620,0xBC0620,0xBC0620,0xBC0620,0xBC0620,0xBC0620,0x80000041,0x80000041,0x80000041,0x5A100000,0x17C0620,0x17C0620,0x17C0620,0x500001CD,0x3E000620,0xFE6C03A9,0x7C0622,0x7C0622,0xFA60016D,0xFE50004A,0xF2480001,0xF2480001,0xAA480001,0xFC5402F9,0xFE3C0132,0x92380000,0x80000041,
-0x10C0620,};
-static const uint32_t g_etc1_to_bc7_m6_table175[] = {
-0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x1000000,
-0x1000000,0x1000000,0x1000000,0x2A000000,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x5C0000,0x5C0000,0x5C0000,0x800000,0xB40000,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,
-0x3240000,0x17FC0000,0x17FC0000,0x17FC0000,0x62000000,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,0x17FC0000,0x17FC0000,0x17FC0000,0x62000000,0x17FC0000,0x17FC0000,0x17FC0000,0x62000000,0x62000000,0xD40000,0xC40001,0xC40001,0x4E40000,0xF80000,0x10C0000,0x10C0000,0x14C0000,0x4E40000,0xF80000,0x1A40000,0x17FC0000,
-0x1A40000,0x1240001,0x1240001,0x1240001,0x1240001,0x1B40000,0x1B40000,0x1B40000,0x5FF80000,0x5FF80000,0x92000000,0x1B40000,0x1B40000,0x1B40000,0x5FF80000,0x5FF80000,0x92000000,0x5FF80000,0x5FF80000,0x92000000,0x92000000,0x1B40000,0x1B40000,0x1B40000,0x5FF80000,0x5FF80000,0x92000000,0x5FF80000,0x5FF80000,0x92000000,0x92000000,0x5FF80000,
-0x5FF80000,0x92000000,0x92000000,0x92000000,0x3540000,0x5380000,0x1240001,0x1900000,0x3EC0000,0x35FC0000,0x49FC0000,0x6DF80000,0x1700000,0x1B40000,0x35FC0000,0x92000000,0x35FC0000,0x1940001,0x63FC0000,0xB3F80000,0xCA000000,0x63FC0000,0xB3F80000,0xCA000000,0xB3F80000,0xCA000000,0xCA000000,0x63FC0000,0xB3F80000,0xCA000000,0xB3F80000,0xCA000000,
-0xCA000000,0xB3F80000,0xCA000000,0xCA000000,0xCA000000,0x63FC0000,0xB3F80000,0xCA000000,0xB3F80000,0xCA000000,0xCA000000,0xB3F80000,0xCA000000,0xCA000000,0xCA000000,0xB3F80000,0xCA000000,0xCA000000,0xCA000000,0xCA000000,0x1FC0000,0x1B00000,0x1B00000,0x81FC0000,0xA9F80000,0xBFF00000,0xCA000000,0xCA000000,0x3DFC0000,0x91FC0000,0xC9C40000,0xCA000000,
-0x9FF80000,0xF43684,0xFED01F3C,0xFEC0152B,0xCAC0152B,0xFEB01682,0xFE980713,0xD29C0933,0xE0900C42,0xC48C0686,0xAE8C0C42,0xFE981BF1,0xFE6C05CF,0xD2780733,0xEE50064F,0xC8580012,0xAE60068A,0xCA54152C,0xB8440735,0xA6440931,0x9454152D,0x16C3680,0xFE38176F,0xCA58152B,0xFA000D7A,0xCE100651,0xAE280C40,0xD8001863,0xBC0006CD,0xA60007D9,0x94001550,0x3BFC3680,
-0xA6001D1B,0x960017C8,0x8A002044,0x7A003680,0xFED02341,0xFEEC2F82,0xFEEC313B,0xFEAC11B2,0xFE78043B,0xF258000E,0xCE640082,0xC24C0086,0xFEB4221F,0xFE800F42,0xD23C049F,0xA60007D9,0x7FC3680,0x12C152B,0xFF0C08BB,0xF0F80482,0xCAF40482,0xFEE80893,0xFAC40006,0xCED0007A,0xD2C80621,0xC0C00131,0xAEC40621,0x3BC152B,0xFE7C0501,0xCAA80480,0xF6380621,0xC8580011,
-0xAE7C0620,0x63FC152B,0xC2000540,0xAA000740,0x9400152C,0x3BC152B,0xFE7C0501,0xCAA80480,0xF6380621,0xC8580011,0xAE7C0620,0x63FC152B,0xC2000540,0xAA000740,0x9400152C,0x63FC152B,0xC2000540,0xAA000740,0x9400152C,0x9400152C,0xFF000EBB,0xF9201289,0xFD281262,0xFED40821,0xFE900249,0xEE60000D,0xCA7C0001,0xC82C0038,0xFCF40ED9,0xFEC0074A,0xD6240480,0xAA000740,
-0x3BFC152B,0xC0152B,0xC0152B,0xC0152B,0xC0152B,0xFE9806E2,0xFE9806E2,0xFE9806E2,0xB6900622,0xB6900622,0x928C0622,0xFE6804F1,0xFE6804F1,0xFE6804F1,0xC858000E,0xC858000E,0x966C0132,0xA0580481,0xA0580481,0x8C4C007D,0x7A540481,0x11C152B,0x11C152B,0x11C152B,0xD8000621,0xD8000621,0x92440620,0xAE000576,0xAE000576,0x92000019,0x7A080480,0x13FC152B,
-0x13FC152B,0x7E000938,0x72000984,0x6000152C,0xFEA00C7D,0xF4B8117B,0xC0152B,0xFE8805D3,0xFE6C0102,0xEE58000B,0xDE58003B,0xB6540002,0xFE900BE5,0xFE680518,0xCA400480,0x92000019,0x198152B,0xF40482,0xF40482,0xF40482,0xF40482,0xF2C80001,0xF2C80001,0xF2C80001,0xAAC40001,0xAAC40001,0x92C40001,0x16C0480,0x16C0480,0x16C0480,0xBE6C0001,0xBE6C0001,
-0x92980000,0x3BFC0480,0x3BFC0480,0x92000000,0x7A000480,0x16C0480,0x16C0480,0x16C0480,0xBE6C0001,0xBE6C0001,0x92980000,0x3BFC0480,0x3BFC0480,0x92000000,0x7A000480,0x3BFC0480,0x3BFC0480,0x92000000,0x7A000480,0x7A000480,0xFED80288,0xFEEC02F9,0xF40482,0xFEB4016D,0xFE800029,0xE8640000,0xCE780000,0xBA4C0000,0xFCC002D2,0xFE980139,0x7FC0480,0x92000000,
-0x7FC0480,0x15C0622,0xFF3C0122,0xE7240001,0xCB240001,0xDFC0620,0xFEBC0001,0xCAF00000,0x89F80620,0xCA400000,0xAE000620,0xDFC0620,0xFEBC0001,0xCAF00000,0x89F80620,0xCA400000,0xAE000620,0x89F80620,0xCA400000,0xAE000620,0xAE000620,0xDFC0620,0xFEBC0001,0xCAF00000,0x89F80620,0xCA400000,0xAE000620,0x89F80620,0xCA400000,0xAE000620,0xAE000620,0x89F80620,
-0xCA400000,0xAE000620,0xAE000620,0xAE000620,0xFF3404C9,0x3740620,0xF5580515,0xFF0402E4,0xFEBC0139,0xF4480000,0xCA800000,0xCA000004,0xFF2C04B1,0xFEF002B1,0xD2940001,0xAE000620,0x69FC0620,0x8C0622,0x8C0622,0x8C0622,0x8C0622,0x8C0622,0x8C0622,0x8C0622,0x8C0622,0x8C0622,0x8C0622,0xD2580001,0xD2580001,0xD2580001,0xD2580001,0xD2580001,
-0xD2580001,0x7E540001,0x7E540001,0x7E540001,0x62540001,0x2D00620,0x2D00620,0x2D00620,0x2D00620,0x2D00620,0x2D00620,0x8C000019,0x8C000019,0x8C000019,0x62200000,0x1AC0620,0x1AC0620,0x1AC0620,0x56000171,0x46000620,0xF88003CA,0x8C0622,0x8C0622,0xFC70018A,0xFE640062,0xFA580001,0xFA580001,0xB2580001,0xFC640320,0xFE500145,0x9A480000,0x8C000019,
-0x12C0620,};
-static const uint32_t g_etc1_to_bc7_m6_table176[] = {
-0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,0x1380000,
-0x1380000,0x1380000,0x1380000,0x32000001,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0xE6C0000,0xE6C0000,0xE6C0000,0x2980000,0xDC0000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,
-0x1400000,0x25F80000,0x25F80000,0x25F80000,0x6A000001,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x25F80000,0x25F80000,0x25F80000,0x6A000001,0x25F80000,0x25F80000,0x25F80000,0x6A000001,0x6A000001,0xAE40000,0xD80000,0xD80000,0xFC0000,0x50C0000,0x3240000,0x3240000,0x16C0000,0xFC0000,0x50C0000,0x1CC0000,0x25F80000,
-0x1CC0000,0x1380000,0x1380000,0x1380000,0x1380000,0x1D00000,0x1D00000,0x1D00000,0x6DF80000,0x6DF80000,0x9A000001,0x1D00000,0x1D00000,0x1D00000,0x6DF80000,0x6DF80000,0x9A000001,0x6DF80000,0x6DF80000,0x9A000001,0x9A000001,0x1D00000,0x1D00000,0x1D00000,0x6DF80000,0x6DF80000,0x9A000001,0x6DF80000,0x6DF80000,0x9A000001,0x9A000001,0x6DF80000,
-0x6DF80000,0x9A000001,0x9A000001,0x9A000001,0x7680000,0x14C0000,0x1380000,0x1A80000,0xDFC0000,0x45FC0000,0x59FC0000,0x79F80000,0x1880000,0x1D00000,0x45FC0000,0x9A000001,0x45FC0000,0x1A80000,0x7DFC0000,0xBFFC0000,0xD2000001,0x7DFC0000,0xBFFC0000,0xD2000001,0xBFFC0000,0xD2000001,0xD2000001,0x7DFC0000,0xBFFC0000,0xD2000001,0xBFFC0000,0xD2000001,
-0xD2000001,0xBFFC0000,0xD2000001,0xD2000001,0xD2000001,0x7DFC0000,0xBFFC0000,0xD2000001,0xBFFC0000,0xD2000001,0xD2000001,0xBFFC0000,0xD2000001,0xD2000001,0xD2000001,0xBFFC0000,0xD2000001,0xD2000001,0xD2000001,0xD2000001,0x2DFC0000,0x1C40000,0x1C40000,0x97FC0000,0xB7FC0000,0xC9FC0000,0xD2000001,0xD2000001,0x5FFC0000,0xA5FC0000,0xD1F40000,0xD2000001,
-0xAFFC0000,0x1083680,0xFEE82044,0xFED41550,0xD2D4152D,0xFED017C8,0xFEAC07D9,0xDCB00931,0xEAA00C40,0xCC9C068A,0xB6A00C42,0xFEB01D1B,0xFE8406CD,0xDC8C0735,0xF6600651,0xD26C0012,0xB8740686,0xD268152B,0xC2580733,0xB0580933,0x9E68152B,0x1883680,0xFE4C1863,0xD468152C,0xFE080D7A,0xD620064F,0xB63C0C42,0xE200176F,0xC80005CF,0xB2000713,0x9E00152B,0x49F83680,
-0xB2001BF1,0xA0001682,0x96001F3C,0x82003684,0xFEE42462,0xF9003040,0xFB0431B0,0xFEC01361,0xFE9005B6,0xFA68000E,0xD6740086,0xCC600082,0xFED02373,0xFE981122,0xDC4C049F,0xB2000713,0x19FC3680,0x13C152C,0xFF180984,0xFB080480,0xD3080481,0xFF000938,0xFED80019,0xD6E0007D,0xDCD80620,0xC8D00132,0xB6D80622,0x1D8152B,0xFEA00576,0xD2BC0481,0xFE4C0621,0xD26C000E,
-0xB6900622,0x71F8152B,0xCA0004F1,0xB20006E2,0x9E00152B,0x1D8152B,0xFEA00576,0xD2BC0481,0xFE4C0621,0xD26C000E,0xB6900622,0x71F8152B,0xCA0004F1,0xB20006E2,0x9E00152B,0x71F8152B,0xCA0004F1,0xB20006E2,0x9E00152B,0x9E00152B,0xFF140F21,0xFF2C12B6,0xF53812C4,0xFEEC08F1,0xFEA80326,0xF674000D,0xD48C0002,0xD03C003B,0xFF080F33,0xFEC8081B,0xDE380481,0xB20006E2,
-0x4BFC152B,0xD4152C,0xD4152C,0xD4152C,0xD4152C,0xFEA80740,0xFEA80740,0xFEA80740,0xC0A00620,0xC0A00620,0x9AA00621,0xFE780540,0xFE780540,0xFE780540,0xD0680011,0xD0680011,0x9E7C0131,0xAA680480,0xAA680480,0x9660007A,0x82680482,0x138152B,0x138152B,0x138152B,0xE2100621,0xE2100621,0x9A580621,0xC0000501,0xC0000501,0x9C040006,0x821C0482,0x21F8152B,
-0x21F8152B,0x8A000893,0x780008BB,0x6800152B,0xFEBC0CE5,0xFECC1178,0xD4152C,0xFE980671,0xFE80016D,0xF86C000C,0xE86C0038,0xC0680001,0xFEA00C3A,0xFE8005A2,0xD2540481,0x9C040006,0x1BC152B,0x1080480,0x1080480,0x1080480,0x1080480,0xFCD80000,0xFCD80000,0xFCD80000,0xB2D80000,0xB2D80000,0x9AD80001,0x1880480,0x1880480,0x1880480,0xC6800001,0xC6800001,
-0x9CA80001,0x49F80480,0x49F80480,0x9A180001,0x82000482,0x1880480,0x1880480,0x1880480,0xC6800001,0xC6800001,0x9CA80001,0x49F80480,0x49F80480,0x9A180001,0x82000482,0x49F80480,0x49F80480,0x9A180001,0x82000482,0x82000482,0xFAEC02AD,0xF9000320,0x1080480,0xFEC40190,0xFE980041,0xF0780000,0xD8880000,0xC2600000,0xFED002DA,0xFEB0016D,0x19FC0480,0x9A180001,
-0x19FC0480,0x1700620,0xFF500171,0xEF380000,0xD3380001,0x29FC0620,0xFED80019,0xD5000001,0x97F80620,0xD2540001,0xB6000622,0x29FC0620,0xFED80019,0xD5000001,0x97F80620,0xD2540001,0xB6000622,0x97F80620,0xD2540001,0xB6000622,0xB6000622,0x29FC0620,0xFED80019,0xD5000001,0x97F80620,0xD2540001,0xB6000622,0x97F80620,0xD2540001,0xB6000622,0xB6000622,0x97F80620,
-0xD2540001,0xB6000622,0xB6000622,0xB6000622,0xFF5004E4,0x1880620,0xFF6C0515,0xFF200332,0xFED00195,0xFE580000,0xD2980001,0xD2080001,0xF94804E2,0xFF0802E4,0xDCA40000,0xB6000622,0x7BFC0620,0xA00620,0xA00620,0xA00620,0xA00620,0xA00620,0xA00620,0xA00620,0xA00620,0xA00620,0xA00620,0xDE680000,0xDE680000,0xDE680000,0xDE680000,0xDE680000,
-0xDE680000,0x86680000,0x86680000,0x86680000,0x6A680001,0xEC0620,0xEC0620,0xEC0620,0xEC0620,0xEC0620,0xEC0620,0x9E000001,0x9E000001,0x9E000001,0x6C300001,0x1E40620,0x1E40620,0x1E40620,0x60000122,0x4E000622,0xFE8C03E8,0xA00620,0xA00620,0xFE8401A5,0xFE780080,0xFE680004,0xFE680004,0xBC680000,0xFE740328,0xFE640179,0xA4580000,0x9E000001,
-0x1540620,};
-static const uint32_t g_etc1_to_bc7_m6_table177[] = {
-0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x1680000,
-0x1680000,0x1680000,0x1680000,0x3A000001,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x800000,0x800000,0x800000,0x2B00000,0xFC0000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,
-0x1580000,0x31F80000,0x31F80000,0x31F80000,0x72000001,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x31F80000,0x31F80000,0x31F80000,0x72000001,0x31F80000,0x31F80000,0x31F80000,0x72000001,0x72000001,0xF80000,0xE80000,0xE80000,0x30C0000,0x5200000,0x13C0000,0x13C0000,0x1840000,0x30C0000,0x5200000,0x1EC0000,0x31F80000,
-0x1EC0000,0x1480000,0x1480000,0x1480000,0x1480000,0x1E80000,0x1E80000,0x1E80000,0x79F80000,0x79F80000,0xA2000001,0x1E80000,0x1E80000,0x1E80000,0x79F80000,0x79F80000,0xA2000001,0x79F80000,0x79F80000,0xA2000001,0xA2000001,0x1E80000,0x1E80000,0x1E80000,0x79F80000,0x79F80000,0xA2000001,0x79F80000,0x79F80000,0xA2000001,0xA2000001,0x79F80000,
-0x79F80000,0xA2000001,0xA2000001,0xA2000001,0x37C0000,0x75C0000,0x1480000,0x3BC0000,0x21FC0000,0x55FC0000,0x67F80000,0x83FC0000,0x19C0000,0x1E80000,0x55FC0000,0xA2000001,0x55FC0000,0x1B80000,0x95FC0000,0xCBFC0000,0xDA000001,0x95FC0000,0xCBFC0000,0xDA000001,0xCBFC0000,0xDA000001,0xDA000001,0x95FC0000,0xCBFC0000,0xDA000001,0xCBFC0000,0xDA000001,
-0xDA000001,0xCBFC0000,0xDA000001,0xDA000001,0xDA000001,0x95FC0000,0xCBFC0000,0xDA000001,0xCBFC0000,0xDA000001,0xDA000001,0xCBFC0000,0xDA000001,0xDA000001,0xDA000001,0xCBFC0000,0xDA000001,0xDA000001,0xDA000001,0xDA000001,0x55FC0000,0x3D40000,0x3D40000,0xABFC0000,0xC5FC0000,0xD3FC0000,0xDA000001,0xDA000001,0x7DFC0000,0xB5FC0000,0xDBC80000,0xDA000001,
-0xBFF80000,0x1183680,0xFEF42170,0xFEE415A5,0xDAE4152D,0xFEDC1910,0xFEC008C1,0xE4C00931,0xF2B00C40,0xD4AC068A,0xBEB00C42,0xFEC41E10,0xFE9407E6,0xE49C0735,0xFE700651,0xDA7C0012,0xC0840686,0xDA78152B,0xCA680733,0xB8680933,0xA678152B,0x1A03680,0xFE641953,0xDC78152C,0xFE200E4A,0xDE30064F,0xBE4C0C42,0xF40016C3,0xD4000527,0xBC0006AF,0xA610152B,0x55F83680,
-0xBE001AF9,0xAC001532,0x9C001E2C,0x8A003684,0xFEF8257D,0xFF0C3050,0xFF0C31F0,0xFED414FA,0xFEA4073E,0xFE7C001E,0xDE840086,0xD4700082,0xFEDC247F,0xFEB012E5,0xE45C049F,0xBC0006AF,0x27FC3680,0x14C152C,0xFF300A24,0xFF180489,0xDB180481,0xFF1809E8,0xFEF00061,0xDEF0007D,0xE4E80620,0xD0E00132,0xBEE80622,0x1F0152B,0xFEB805F6,0xDACC0481,0xFE640641,0xDA7C000E,
-0xBEA00622,0x7DF8152B,0xD60004B9,0xBC0006AB,0xA600152B,0x1F0152B,0xFEB805F6,0xDACC0481,0xFE640641,0xDA7C000E,0xBEA00622,0x7DF8152B,0xD60004B9,0xBC0006AB,0xA600152B,0x7DF8152B,0xD60004B9,0xBC0006AB,0xA600152B,0xA600152B,0xFD300F89,0xFB4412E4,0xFD4812C4,0xFF0009C8,0xFEC803F2,0xFE84000D,0xDC9C0002,0xD84C003B,0xFF180FA2,0xFEE80905,0xE6480481,0xBC0006AB,
-0x5BFC152B,0xE4152C,0xE4152C,0xE4152C,0xE4152C,0xFEBC0789,0xFEBC0789,0xFEBC0789,0xC8B00620,0xC8B00620,0xA2B00621,0xFE8C0586,0xFE8C0586,0xFE8C0586,0xD8780011,0xD8780011,0xA68C0131,0xB2780480,0xB2780480,0x9E70007A,0x8A780482,0x150152B,0x150152B,0x150152B,0xEA200621,0xEA200621,0xA2680621,0xCC0004B9,0xCC0004B9,0xA4140006,0x8A2C0482,0x2DF8152B,
-0x2DF8152B,0x9600081B,0x8400082B,0x7000152B,0xFECC0D34,0xF6DC11D1,0xE4152C,0xFEAC0709,0xFE9401DD,0xFC7C000E,0xF07C0038,0xC8780001,0xFEB40C89,0xFE980632,0xDA640481,0xA4140006,0x1E0152B,0x1180480,0x1180480,0x1180480,0x1180480,0xFEE80004,0xFEE80004,0xFEE80004,0xBAE80000,0xBAE80000,0xA2E80001,0x1A00480,0x1A00480,0x1A00480,0xCE900001,0xCE900001,
-0xA4B80001,0x55F80480,0x55F80480,0xA2280001,0x8A000482,0x1A00480,0x1A00480,0x1A00480,0xCE900001,0xCE900001,0xA4B80001,0x55F80480,0x55F80480,0xA2280001,0x8A000482,0x55F80480,0x55F80480,0xA2280001,0x8A000482,0x8A000482,0xF70002D2,0xFF0C0328,0x1180480,0xFEDC01A5,0xFEAC0061,0xF8880000,0xE0980000,0xCA700000,0xF8EC02F9,0xFEC40188,0x27FC0480,0xA2280001,
-0x27FC0480,0x1800620,0xFF5C01CD,0xF7480000,0xDB480001,0x41FC0620,0xFEFC0041,0xDD100001,0xA1FC0620,0xDA640001,0xBE000622,0x41FC0620,0xFEFC0041,0xDD100001,0xA1FC0620,0xDA640001,0xBE000622,0xA1FC0620,0xDA640001,0xBE000622,0xBE000622,0x41FC0620,0xFEFC0041,0xDD100001,0xA1FC0620,0xDA640001,0xBE000622,0xA1FC0620,0xDA640001,0xBE000622,0xBE000622,0xA1FC0620,
-0xDA640001,0xBE000622,0xBE000622,0xBE000622,0xF7680515,0x5980620,0xF77C0548,0xFF400372,0xFEFC01E5,0xFE84000D,0xDAA80001,0xDA180001,0xFD5804E4,0xFF200340,0xE4B40000,0xBE000622,0x89FC0620,0xB00620,0xB00620,0xB00620,0xB00620,0xB00620,0xB00620,0xB00620,0xB00620,0xB00620,0xB00620,0xE6780000,0xE6780000,0xE6780000,0xE6780000,0xE6780000,
-0xE6780000,0x8E780000,0x8E780000,0x8E780000,0x72780001,0x1040620,0x1040620,0x1040620,0x1040620,0x1040620,0x1040620,0xA6100001,0xA6100001,0xA6100001,0x74400001,0x7FC0620,0x7FC0620,0x7FC0620,0x6C0000DA,0x56000622,0xFAA403F5,0xB00620,0xB00620,0xFE9001D4,0xFC8800A4,0xFC7C000D,0xFC7C000D,0xC4780000,0xFC8C0349,0xFE780190,0xAC680000,0xA6100001,
-0x1740620,};
-static const uint32_t g_etc1_to_bc7_m6_table178[] = {
-0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0x1980000,
-0x1980000,0x1980000,0x1980000,0x42000001,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x900000,0x900000,0x900000,0xC80000,0x1200000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0xF80000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,
-0x1700000,0x3DF80000,0x3DF80000,0x3DF80000,0x7A000001,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x3DF80000,0x3DF80000,0x3DF80000,0x7A000001,0x3DF80000,0x3DF80000,0x3DF80000,0x7A000001,0x7A000001,0x1080000,0xF80000,0xF80000,0x1200000,0x5340000,0x1500000,0x1500000,0x1A00000,0x1200000,0x5340000,0x9FC0000,0x3DF80000,
-0x9FC0000,0x1580000,0x1580000,0x1580000,0x1580000,0x3FC0000,0x3FC0000,0x3FC0000,0x85F80000,0x85F80000,0xAA000001,0x3FC0000,0x3FC0000,0x3FC0000,0x85F80000,0x85F80000,0xAA000001,0x85F80000,0x85F80000,0xAA000001,0xAA000001,0x3FC0000,0x3FC0000,0x3FC0000,0x85F80000,0x85F80000,0xAA000001,0x85F80000,0x85F80000,0xAA000001,0xAA000001,0x85F80000,
-0x85F80000,0xAA000001,0xAA000001,0xAA000001,0x1900000,0xF6C0000,0x1580000,0x1D40000,0x33FC0000,0x63FC0000,0x75F80000,0x8FF80000,0x1B00000,0x3FC0000,0x63FC0000,0xAA000001,0x63FC0000,0x1C80000,0xAFFC0000,0xD7FC0000,0xE2000001,0xAFFC0000,0xD7FC0000,0xE2000001,0xD7FC0000,0xE2000001,0xE2000001,0xAFFC0000,0xD7FC0000,0xE2000001,0xD7FC0000,0xE2000001,
-0xE2000001,0xD7FC0000,0xE2000001,0xE2000001,0xE2000001,0xAFFC0000,0xD7FC0000,0xE2000001,0xD7FC0000,0xE2000001,0xE2000001,0xD7FC0000,0xE2000001,0xE2000001,0xE2000001,0xD7FC0000,0xE2000001,0xE2000001,0xE2000001,0xE2000001,0x7DFC0000,0xBE40000,0xBE40000,0xBDFC0000,0xD3F80000,0xDDFC0000,0xE2000001,0xE2000001,0x9BFC0000,0xC7FC0000,0xE3D80000,0xE2000001,
-0xCDFC0000,0x1283680,0xFF0C2270,0xFEF81640,0xE2F4152D,0xFEF41A90,0xFED409ED,0xECD00931,0xFAC00C40,0xDCBC068A,0xC6C00C42,0xFED01F3C,0xFEAC0936,0xECAC0735,0xFE880681,0xE28C0012,0xC8940686,0xE288152B,0xD2780733,0xC0780933,0xAE88152B,0x1B83680,0xFE881A5F,0xE488152C,0xFE380F5A,0xE640064F,0xC65C0C42,0xFC00164D,0xDE0004BA,0xC400067B,0xAE20152B,0x61F83680,
-0xCA001A21,0xB8001422,0xA6001D6B,0x92003684,0xFF0C269A,0xF9203102,0xFB243245,0xFEDC16B2,0xFEB808F6,0xFE900086,0xE6940086,0xDC800082,0xFEF82596,0xFEC41488,0xEC6C049F,0xC400067B,0x37FC3680,0x15C152C,0xFF440AD1,0xFF2C04B9,0xE3280481,0xFF240A8C,0xFF0400E9,0xE700007D,0xECF80620,0xD8F00132,0xC6F80622,0xDFC152B,0xFECC06B1,0xE2DC0481,0xFE880681,0xE28C000E,
-0xC6B00622,0x89F8152B,0xE000049B,0xC4000672,0xAE00152B,0xDFC152B,0xFECC06B1,0xE2DC0481,0xFE880681,0xE28C000E,0xC6B00622,0x89F8152B,0xE000049B,0xC4000672,0xAE00152B,0x89F8152B,0xE000049B,0xC4000672,0xAE00152B,0xAE00152B,0xFF3C1004,0xFF4C1324,0xF5581329,0xFF140A71,0xFEE804D9,0xFE980052,0xE4AC0002,0xE05C003B,0xFF34103A,0xFF0409B3,0xEE580481,0xC4000672,
-0x69FC152B,0xF4152C,0xF4152C,0xF4152C,0xF4152C,0xFED007E4,0xFED007E4,0xFED007E4,0xD0C00620,0xD0C00620,0xAAC00621,0xFEA405E6,0xFEA405E6,0xFEA405E6,0xE0880011,0xE0880011,0xAE9C0131,0xBA880480,0xBA880480,0xA680007A,0x92880482,0x168152B,0x168152B,0x168152B,0xF2300621,0xF2300621,0xAA780621,0xD8000491,0xD8000491,0xAC240006,0x923C0482,0x39F8152B,
-0x39F8152B,0x9C0007A3,0x8A000793,0x7800152B,0xFED80DAA,0xFEEC11D1,0xF4152C,0xFEC40794,0xFEAC0275,0xFE900022,0xF88C0038,0xD0880001,0xFEBC0D2A,0xFEB006D1,0xE2740481,0xAC240006,0x3FC152B,0x1280480,0x1280480,0x1280480,0x1280480,0xFCFC0014,0xFCFC0014,0xFCFC0014,0xC2F80000,0xC2F80000,0xAAF80001,0x1B80480,0x1B80480,0x1B80480,0xD6A00001,0xD6A00001,
-0xACC80001,0x61F80480,0x61F80480,0xAA380001,0x92000482,0x1B80480,0x1B80480,0x1B80480,0xD6A00001,0xD6A00001,0xACC80001,0x61F80480,0x61F80480,0xAA380001,0x92000482,0x61F80480,0x61F80480,0xAA380001,0x92000482,0x92000482,0xFF1002D2,0xF9200349,0x1280480,0xFCF401E1,0xFEC80082,0xFC9C0001,0xE8A80000,0xD2800000,0xFEF802FD,0xFEDC01A5,0x37FC0480,0xAA380001,
-0x37FC0480,0x1900620,0xFF74022D,0xFF580000,0xE3580001,0x59FC0620,0xFF140089,0xE5200001,0xADFC0620,0xE2740001,0xC6000622,0x59FC0620,0xFF140089,0xE5200001,0xADFC0620,0xE2740001,0xC6000622,0xADFC0620,0xE2740001,0xC6000622,0xC6000622,0x59FC0620,0xFF140089,0xE5200001,0xADFC0620,0xE2740001,0xC6000622,0xADFC0620,0xE2740001,0xC6000622,0xC6000622,0xADFC0620,
-0xE2740001,0xC6000622,0xC6000622,0xC6000622,0xFF780515,0xDA80620,0xFF8C0548,0xFF5803C8,0xFF100249,0xFEAC0041,0xE2B80001,0xE2280001,0xFF700515,0xFF40037A,0xECC40000,0xC6000622,0x99FC0620,0xC00620,0xC00620,0xC00620,0xC00620,0xC00620,0xC00620,0xC00620,0xC00620,0xC00620,0xC00620,0xEE880000,0xEE880000,0xEE880000,0xEE880000,0xEE880000,
-0xEE880000,0x96880000,0x96880000,0x96880000,0x7A880001,0x11C0620,0x11C0620,0x11C0620,0x11C0620,0x11C0620,0x11C0620,0xAE200001,0xAE200001,0xAE200001,0x7C500001,0x13FC0620,0x13FC0620,0x13FC0620,0x720000A2,0x5E000622,0xFEAC041D,0xC00620,0xC00620,0xFEA001F9,0xFC9C00C8,0xFE900019,0xFE900019,0xCC880000,0xFC9C0372,0xFC9001C2,0xB4780000,0xAE200001,
-0x1980620,};
-static const uint32_t g_etc1_to_bc7_m6_table179[] = {
-0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0xE00000,0xE00000,0xE00000,0xE00000,0xE00000,0xE00000,0xE00000,0xE00000,0xE00000,0xE00000,0x1CC0000,
-0x1CC0000,0x1CC0000,0x1CC0000,0x4A000001,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x8A00000,0x8A00000,0x8A00000,0xE00000,0x1400000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,
-0x1880000,0x49F80000,0x49F80000,0x49F80000,0x82000001,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x49F80000,0x49F80000,0x49F80000,0x82000001,0x49F80000,0x49F80000,0x49F80000,0x82000001,0x82000001,0x5180000,0x1080000,0x1080000,0x1340000,0x14C0000,0x1680000,0x1680000,0x1BC0000,0x1340000,0x14C0000,0x19FC0000,0x49F80000,
-0x19FC0000,0x1680000,0x1680000,0x1680000,0x1680000,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x91F80000,0x91F80000,0xB2000001,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x91F80000,0x91F80000,0xB2000001,0x91F80000,0x91F80000,0xB2000001,0xB2000001,0x1BFC0000,0x1BFC0000,0x1BFC0000,0x91F80000,0x91F80000,0xB2000001,0x91F80000,0x91F80000,0xB2000001,0xB2000001,0x91F80000,
-0x91F80000,0xB2000001,0xB2000001,0xB2000001,0x7A00000,0x1800000,0x1680000,0x3E80000,0x47FC0000,0x73FC0000,0x81FC0000,0x99FC0000,0x1C40000,0x1BFC0000,0x73FC0000,0xB2000001,0x73FC0000,0x1D80000,0xC7FC0000,0xE3FC0000,0xEA000001,0xC7FC0000,0xE3FC0000,0xEA000001,0xE3FC0000,0xEA000001,0xEA000001,0xC7FC0000,0xE3FC0000,0xEA000001,0xE3FC0000,0xEA000001,
-0xEA000001,0xE3FC0000,0xEA000001,0xEA000001,0xEA000001,0xC7FC0000,0xE3FC0000,0xEA000001,0xE3FC0000,0xEA000001,0xEA000001,0xE3FC0000,0xEA000001,0xEA000001,0xEA000001,0xE3FC0000,0xEA000001,0xEA000001,0xEA000001,0xEA000001,0xA3FC0000,0x1F80000,0x1F80000,0xD1FC0000,0xDFFC0000,0xE7FC0000,0xEA000001,0xEA000001,0xB9FC0000,0xD7FC0000,0xEBE80000,0xEA000001,
-0xDDF80000,0x1383680,0xFF1823A4,0xFF0816F9,0xEB04152D,0xFF001C08,0xFEE40B51,0xF4E00931,0xFED40C50,0xE4CC068A,0xCED00C42,0xFEE8206C,0xFEC00AD1,0xF4BC0735,0xFEA00711,0xEA9C0012,0xD0A40686,0xEA98152B,0xDA880733,0xC8880933,0xB698152B,0x1D03680,0xFEA01B7F,0xEC98152C,0xFE5810AA,0xEE50064F,0xCE6C0C42,0xFE14169F,0xEA00048A,0xCC10067B,0xB630152B,0x6DF83680,
-0xD0001959,0xBE001302,0xAC001C83,0x9A003684,0xFF2027A2,0xFF2C311A,0xFF2C328D,0xFEF0188A,0xFECC0ADE,0xFEAC0156,0xEEA40086,0xE4900082,0xFF0026DC,0xFEDC1672,0xF47C049F,0xCC10067B,0x45FC3680,0x16C152C,0xFF500B91,0xFF380529,0xEB380481,0xFF3C0B4C,0xFF14019D,0xEF10007D,0xF5080620,0xE1000132,0xCF080622,0x25FC152B,0xFEF00771,0xEAEC0481,0xFEAC06F1,0xEA9C000E,
-0xCEC00622,0x95F8152B,0xEA000489,0xCE000653,0xB600152B,0x25FC152B,0xFEF00771,0xEAEC0481,0xFEAC06F1,0xEA9C000E,0xCEC00622,0x95F8152B,0xEA000489,0xCE000653,0xB600152B,0x95F8152B,0xEA000489,0xCE000653,0xB600152B,0xB600152B,0xFF501055,0xFD681342,0xFD681329,0xFF300B69,0xFEFC05D5,0xFEC000CD,0xECBC0002,0xE86C003B,0xFF44109B,0xFF180AA9,0xF6680481,0xCE000653,
-0x79FC152B,0x104152C,0x104152C,0x104152C,0x104152C,0xFEDC084C,0xFEDC084C,0xFEDC084C,0xD8D00620,0xD8D00620,0xB2D00621,0xFEB00662,0xFEB00662,0xFEB00662,0xE8980011,0xE8980011,0xB6AC0131,0xC2980480,0xC2980480,0xAE90007A,0x9A980482,0x180152B,0x180152B,0x180152B,0xFA400621,0xFA400621,0xB2880621,0xE6040481,0xE6040481,0xB4340006,0x9A4C0482,0x45F8152B,
-0x45F8152B,0xA6000749,0x94000722,0x8000152B,0xFEE80E01,0xF6FC122C,0x104152C,0xFED40821,0xFEC00309,0xFEA40058,0xFCA0003D,0xD8980001,0xFED00D73,0xFEBC076A,0xEA840481,0xB4340006,0x13FC152B,0x1380480,0x1380480,0x1380480,0x1380480,0xFF0C0028,0xFF0C0028,0xFF0C0028,0xCB080000,0xCB080000,0xB3080001,0x1D00480,0x1D00480,0x1D00480,0xDEB00001,0xDEB00001,
-0xB4D80001,0x6DF80480,0x6DF80480,0xB2480001,0x9A000482,0x1D00480,0x1D00480,0x1D00480,0xDEB00001,0xDEB00001,0xB4D80001,0x6DF80480,0x6DF80480,0xB2480001,0x9A000482,0x6DF80480,0x6DF80480,0xB2480001,0x9A000482,0x9A000482,0xFF2002F9,0xFF2C0355,0x1380480,0xFD040202,0xFEDC00AA,0xFEB40008,0xF0B80000,0xDA900000,0xFD100320,0xFEE801D4,0x45FC0480,0xB2480001,
-0x45FC0480,0x1A00620,0xFF8002A1,0xFF6C001D,0xEB680001,0x71FC0620,0xFF3800E9,0xED300001,0xB9FC0620,0xEA840001,0xCE000622,0x71FC0620,0xFF3800E9,0xED300001,0xB9FC0620,0xEA840001,0xCE000622,0xB9FC0620,0xEA840001,0xCE000622,0xCE000622,0x71FC0620,0xFF3800E9,0xED300001,0xB9FC0620,0xEA840001,0xCE000622,0xB9FC0620,0xEA840001,0xCE000622,0xCE000622,0xB9FC0620,
-0xEA840001,0xCE000622,0xCE000622,0xCE000622,0xFF8C0548,0x1BC0620,0xF79C057D,0xFF6C03F9,0xFF3C02B1,0xFED40092,0xEAC80001,0xEA380001,0xF7880548,0xFF5803DA,0xF4D40000,0xCE000622,0xA7FC0620,0xD00620,0xD00620,0xD00620,0xD00620,0xD00620,0xD00620,0xD00620,0xD00620,0xD00620,0xD00620,0xF6980000,0xF6980000,0xF6980000,0xF6980000,0xF6980000,
-0xF6980000,0x9E980000,0x9E980000,0x9E980000,0x82980001,0x1340620,0x1340620,0x1340620,0x1340620,0x1340620,0x1340620,0xB6300001,0xB6300001,0xB6300001,0x84600001,0x1FF80620,0x1FF80620,0x1FF80620,0x7E00006A,0x66000622,0xFAC40424,0xD00620,0xD00620,0xFCB80221,0xFEA800E9,0xFCA00034,0xFCA00034,0xD4980000,0xF8B0039D,0xFEA001E1,0xBC880000,0xB6300001,
-0x1B80620,};
-static const uint32_t g_etc1_to_bc7_m6_table180[] = {
-0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0x3F80000,
-0x3F80000,0x3F80000,0x3F80000,0x54000000,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0x2B40000,0x2B40000,0x2B40000,0xFC0000,0x1680000,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,
-0x1A40000,0x57F80000,0x57F80000,0x57F80000,0x8C000000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x57F80000,0x57F80000,0x57F80000,0x8C000000,0x57F80000,0x57F80000,0x57F80000,0x8C000000,0x8C000000,0x12C0000,0x1180001,0x1180001,0x1480000,0x3600000,0x1800000,0x1800000,0x1D80000,0x1480000,0x3600000,0x29FC0000,0x57F80000,
-0x29FC0000,0x1780001,0x1780001,0x1780001,0x1780001,0x37FC0000,0x37FC0000,0x37FC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x37FC0000,0x37FC0000,0x37FC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x9DFC0000,0x9DFC0000,0xBC000000,0xBC000000,0x37FC0000,0x37FC0000,0x37FC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x9DFC0000,0x9DFC0000,0xBC000000,0xBC000000,0x9DFC0000,
-0x9DFC0000,0xBC000000,0xBC000000,0xBC000000,0x1B80000,0x1940000,0x1780001,0x9FC0000,0x5DFC0000,0x83FC0000,0x91FC0000,0xA5FC0000,0x3D80000,0x37FC0000,0x83FC0000,0xBC000000,0x83FC0000,0x1E80001,0xE3FC0000,0xF1F80000,0xF4000000,0xE3FC0000,0xF1F80000,0xF4000000,0xF1F80000,0xF4000000,0xF4000000,0xE3FC0000,0xF1F80000,0xF4000000,0xF1F80000,0xF4000000,
-0xF4000000,0xF1F80000,0xF4000000,0xF4000000,0xF4000000,0xE3FC0000,0xF1F80000,0xF4000000,0xF1F80000,0xF4000000,0xF4000000,0xF1F80000,0xF4000000,0xF4000000,0xF4000000,0xF1F80000,0xF4000000,0xF4000000,0xF4000000,0xF4000000,0xD1FC0000,0x67FC0000,0x67FC0000,0xE7FC0000,0xEFFC0000,0xF3F80000,0xF4000000,0xF4000000,0xDBFC0000,0xEBFC0000,0xF5DC0000,0xF4000000,
-0xEDFC0000,0x1483684,0xFF3024F4,0xFF1C182C,0xF514152B,0xFF181DD4,0xFEFC0D2B,0xFCF00933,0xFEE40CC2,0xEEE00686,0xD8E00C42,0xFF0021E4,0xFED80CD7,0xFCCC0733,0xFEB80823,0xF2AC0012,0xD8B4068A,0xF4A8152C,0xE2980735,0xD0980931,0xBEA8152D,0x3E83680,0xFEB81CE9,0xF4AC152B,0xFE7C1242,0xF8640651,0xD87C0C40,0xFE3817A1,0xF20C0485,0xD618067D,0xBE40152D,0x79FC3680,
-0xDC001883,0xCA0011EA,0xB8001BA1,0xA4003680,0xFF3428DF,0xFB4431C4,0xFD4832DC,0xFF081AA2,0xFEE80D2F,0xFEC002B7,0xF8B80082,0xECA00086,0xFF1827ED,0xFEF418C3,0xFC90049F,0xD618067D,0x57FC3680,0x180152B,0xFF680C82,0xFF4C05EB,0xF5480482,0xFF500C19,0xFF2C02AA,0xF924007A,0xFD1C0621,0xEB140131,0xD9180621,0x41FC152B,0xFF080866,0xF4FC0480,0xFECC07B9,0xF2AC0011,
-0xD8D00620,0xA1FC152B,0xF4000480,0xD6000631,0xBE00152C,0x41FC152B,0xFF080866,0xF4FC0480,0xFECC07B9,0xF2AC0011,0xD8D00620,0xA1FC152B,0xF4000480,0xD6000631,0xBE00152C,0xA1FC152B,0xF4000480,0xD6000631,0xBE00152C,0xBE00152C,0xFF64110D,0xF57813A3,0xF77C138B,0xFF400C54,0xFF100726,0xFEDC01AD,0xF4D00001,0xF2800038,0xFF5C10F2,0xFF2C0BE1,0xFE7C0484,0xD6000631,
-0x89FC152B,0x114152B,0x114152B,0x114152B,0x114152B,0xFEF408D3,0xFEF408D3,0xFEF408D3,0xE0E40622,0xE0E40622,0xBCE00622,0xFED006DB,0xFED006DB,0xFED006DB,0xF2AC000E,0xF2AC000E,0xC0C00132,0xCAAC0481,0xCAAC0481,0xB6A0007D,0xA4A80481,0x398152B,0x398152B,0x398152B,0xFE580629,0xFE580629,0xBC980620,0xEE180481,0xEE180481,0xBC480005,0xA45C0480,0x51FC152B,
-0x51FC152B,0xB20006E6,0x9C000690,0x8A00152C,0xFF040E83,0xFF0C1233,0x114152B,0xFEE808EA,0xFED403B6,0xFEBC00B2,0xFEB4004B,0xE0A80002,0xFEE40E19,0xFED007FD,0xF4940480,0xBC480005,0x23FC152B,0x1480482,0x1480482,0x1480482,0x1480482,0xFF24004A,0xFF24004A,0xFF24004A,0xD5180001,0xD5180001,0xBD180001,0x3E80480,0x3E80480,0x3E80480,0xE8C00001,0xE8C00001,
-0xBCEC0000,0x79FC0480,0x79FC0480,0xBC540000,0xA4000480,0x3E80480,0x3E80480,0x3E80480,0xE8C00001,0xE8C00001,0xBCEC0000,0x79FC0480,0x79FC0480,0xBC540000,0xA4000480,0x79FC0480,0x79FC0480,0xBC540000,0xA4000480,0xA4000480,0xFB340322,0xFB440372,0x1480482,0xFF180225,0xFEF000E8,0xFED00022,0xF8CC0000,0xE4A00000,0xF9280349,0xFF040208,0x57FC0480,0xBC540000,
-0x57FC0480,0x1B00622,0xFF980321,0xFF7C007A,0xF5780001,0x8DFC0620,0xFF580185,0xF5440000,0xC7FC0620,0xF4940000,0xD8000620,0x8DFC0620,0xFF580185,0xF5440000,0xC7FC0620,0xF4940000,0xD8000620,0xC7FC0620,0xF4940000,0xD8000620,0xD8000620,0x8DFC0620,0xFF580185,0xF5440000,0xC7FC0620,0xF4940000,0xD8000620,0xC7FC0620,0xF4940000,0xD8000620,0xD8000620,0xC7FC0620,
-0xF4940000,0xD8000620,0xD8000620,0xD8000620,0xF7A4057D,0xFCC0620,0xFFAC0581,0xFF84045D,0xFF500335,0xFF040112,0xF4D40000,0xF4440000,0xFF98054A,0xFD800451,0xFCE80001,0xD8000620,0xB9FC0620,0xE00622,0xE00622,0xE00622,0xE00622,0xE00622,0xE00622,0xE00622,0xE00622,0xE00622,0xE00622,0xFCAC0001,0xFCAC0001,0xFCAC0001,0xFCAC0001,0xFCAC0001,
-0xFCAC0001,0xA8A80001,0xA8A80001,0xA8A80001,0x8CA80001,0x1500620,0x1500620,0x1500620,0x1500620,0x1500620,0x1500620,0xC0400001,0xC0400001,0xC0400001,0x8C740000,0x2DF80620,0x2DF80620,0x2DF80620,0x88000041,0x70000620,0xF4D80451,0xE00622,0xE00622,0xFECC0242,0xFEBC0115,0xFEB4004A,0xFEB4004A,0xDCAC0001,0xFEBC03A9,0xFEB40202,0xC49C0000,0xC0400001,
-0x1E00620,};
-static const uint32_t g_etc1_to_bc7_m6_table181[] = {
-0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0xFF80000,
-0xFF80000,0xFF80000,0xFF80000,0x5C000000,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xAC40000,0xAC40000,0xAC40000,0x1140000,0x18C0000,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,
-0x1BC0000,0x61FC0000,0x61FC0000,0x61FC0000,0x94000000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x61FC0000,0x61FC0000,0x61FC0000,0x94000000,0x61FC0000,0x61FC0000,0x61FC0000,0x94000000,0x94000000,0x73C0000,0x1280001,0x1280001,0x5580000,0x3740000,0x1940000,0x1940000,0x1F40000,0x5580000,0x3740000,0x39FC0000,0x61FC0000,
-0x39FC0000,0x1880001,0x1880001,0x1880001,0x1880001,0x4FFC0000,0x4FFC0000,0x4FFC0000,0xA9FC0000,0xA9FC0000,0xC4000000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0xA9FC0000,0xA9FC0000,0xC4000000,0xA9FC0000,0xA9FC0000,0xC4000000,0xC4000000,0x4FFC0000,0x4FFC0000,0x4FFC0000,0xA9FC0000,0xA9FC0000,0xC4000000,0xA9FC0000,0xA9FC0000,0xC4000000,0xC4000000,0xA9FC0000,
-0xA9FC0000,0xC4000000,0xC4000000,0xC4000000,0x5C80000,0x1A40000,0x1880001,0x27FC0000,0x71FC0000,0x93FC0000,0x9FF80000,0xB1F80000,0x3EC0000,0x4FFC0000,0x93FC0000,0xC4000000,0x93FC0000,0x1F80001,0xFBFC0000,0xFDF80000,0xFC000000,0xFBFC0000,0xFDF80000,0xFC000000,0xFDF80000,0xFC000000,0xFC000000,0xFBFC0000,0xFDF80000,0xFC000000,0xFDF80000,0xFC000000,
-0xFC000000,0xFDF80000,0xFC000000,0xFC000000,0xFC000000,0xFBFC0000,0xFDF80000,0xFC000000,0xFDF80000,0xFC000000,0xFC000000,0xFDF80000,0xFC000000,0xFC000000,0xFC000000,0xFDF80000,0xFC000000,0xFC000000,0xFC000000,0xFC000000,0xF7FC0000,0xE7FC0000,0xE7FC0000,0xFBFC0000,0xFDF80000,0xFDF80000,0xFC000000,0xFC000000,0xF9FC0000,0xFBFC0000,0xFDEC0000,0xFC000000,
-0xFDF80000,0x1583684,0xFF44261B,0xFF2C1953,0xFD24152B,0xFF241F94,0xFF100F1F,0xFF00095F,0xFEFC0D92,0xF6F00686,0xE0F00C42,0xFF18234C,0xFEF00EDF,0xFEDC0767,0xFECC099A,0xFABC0012,0xE0C4068A,0xFCB8152C,0xEAA80735,0xD8A80931,0xC6B8152D,0x7FC3680,0xFED81E87,0xFCBC152B,0xFE9413F2,0xFE700655,0xE08C0C40,0xFE5818EB,0xFA1C0485,0xDE28067D,0xC650152D,0x85FC3680,
-0xE60017F0,0xD0001112,0xBE001AD5,0xAC003680,0xFF3C29CC,0xFF4C3204,0xFF4C3354,0xFF181C7A,0xFEFC0F77,0xFED40452,0xFECC0089,0xF4B00086,0xFF342916,0xFF101AAA,0xFEA404D3,0xDE28067D,0x65FC3680,0x190152B,0xFF740D62,0xFF6406C3,0xFD580482,0xFF680D01,0xFF4003E6,0xFF340081,0xFF2C0641,0xF3240131,0xE1280621,0x59FC152B,0xFF200966,0xFD0C0480,0xFEF00889,0xFABC0011,
-0xE0E00620,0xADFC152B,0xFC100480,0xE0000624,0xC600152C,0x59FC152B,0xFF200966,0xFD0C0480,0xFEF00889,0xFABC0011,0xE0E00620,0xADFC152B,0xFC100480,0xE0000624,0xC600152C,0xADFC152B,0xFC100480,0xE0000624,0xC600152C,0xC600152C,0xFF781162,0xFD8813A3,0xFF8C138B,0xFF540D51,0xFF28086E,0xFEF002BB,0xFCE00001,0xFA900038,0xFD7411AE,0xFF480C8E,0xFEA004D1,0xE0000624,
-0x99FC152B,0x124152B,0x124152B,0x124152B,0x124152B,0xFF00095B,0xFF00095B,0xFF00095B,0xE8F40622,0xE8F40622,0xC4F00622,0xFEDC0763,0xFEDC0763,0xFEDC0763,0xFABC000E,0xFABC000E,0xC8D00132,0xD2BC0481,0xD2BC0481,0xBEB0007D,0xACB80481,0x3B0152B,0x3B0152B,0x3B0152B,0xFE700651,0xFE700651,0xC4A80620,0xF6280481,0xF6280481,0xC4580005,0xAC6C0480,0x5DFC152B,
-0x5DFC152B,0xBE0006A6,0xA6000631,0x9200152C,0xFF100EED,0xF9201286,0x124152B,0xFEF80996,0xFEE40481,0xFECC0139,0xFECC0085,0xE8B80002,0xFEF80E66,0xFEE808E2,0xFCA40480,0xC4580005,0x33FC152B,0x1580482,0x1580482,0x1580482,0x1580482,0xFF34007D,0xFF34007D,0xFF34007D,0xDD280001,0xDD280001,0xC5280001,0x7FC0480,0x7FC0480,0x7FC0480,0xF0D00001,0xF0D00001,
-0xC4FC0000,0x85FC0480,0x85FC0480,0xC4640000,0xAC000480,0x7FC0480,0x7FC0480,0x7FC0480,0xF0D00001,0xF0D00001,0xC4FC0000,0x85FC0480,0x85FC0480,0xC4640000,0xAC000480,0x85FC0480,0x85FC0480,0xC4640000,0xAC000480,0xAC000480,0xF7480349,0xFF4C0392,0x1580482,0xFD300265,0xFD140120,0xFEEC003D,0xFCE00001,0xECB00000,0xFF34034D,0xFF18022D,0x65FC0480,0xC4640000,
-0x65FC0480,0x1C00622,0xFFB003A9,0xFF9400FA,0xFD880001,0xA5FC0620,0xFF70021D,0xFD540000,0xD3FC0620,0xFCA40000,0xE0000620,0xA5FC0620,0xFF70021D,0xFD540000,0xD3FC0620,0xFCA40000,0xE0000620,0xD3FC0620,0xFCA40000,0xE0000620,0xE0000620,0xA5FC0620,0xFF70021D,0xFD540000,0xD3FC0620,0xFCA40000,0xE0000620,0xD3FC0620,0xFCA40000,0xE0000620,0xE0000620,0xD3FC0620,
-0xFCA40000,0xE0000620,0xE0000620,0xE0000620,0xFFB4057D,0x1E00620,0xF9C005B2,0xFF9404B2,0xFF7C03A9,0xFF2C01BA,0xFCE40000,0xFC540000,0xFFAC0581,0xFF940488,0xFF10001D,0xE0000620,0xC7FC0620,0xF00622,0xF00622,0xF00622,0xF00622,0xF00622,0xF00622,0xF00622,0xF00622,0xF00622,0xF00622,0xFEBC0005,0xFEBC0005,0xFEBC0005,0xFEBC0005,0xFEBC0005,
-0xFEBC0005,0xB0B80001,0xB0B80001,0xB0B80001,0x94B80001,0x1680620,0x1680620,0x1680620,0x1680620,0x1680620,0x1680620,0xC8500001,0xC8500001,0xC8500001,0x94840000,0x39F80620,0x39F80620,0x39F80620,0x90000020,0x78000620,0xFCE80451,0xF00622,0xF00622,0xFED80271,0xFED0013D,0xFEC4006A,0xFEC4006A,0xE4BC0001,0xFCD403C8,0xFAC80244,0xCCAC0000,0xC8500001,
-0x3FC0620,};
-static const uint32_t g_etc1_to_bc7_m6_table182[] = {
-0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x1BF80000,
-0x1BF80000,0x1BF80000,0x1BF80000,0x64000000,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xD80000,0xD80000,0xD80000,0x12C0000,0x1AC0000,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x1380001,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x3D00000,
-0x3D00000,0x6DFC0000,0x6DFC0000,0x6DFC0000,0x9C000000,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x3D00000,0x6DFC0000,0x6DFC0000,0x6DFC0000,0x9C000000,0x6DFC0000,0x6DFC0000,0x6DFC0000,0x9C000000,0x9C000000,0xF4C0000,0x1380001,0x1380001,0x16C0000,0x3880000,0x1AC0000,0x1AC0000,0xFFC0000,0x16C0000,0x3880000,0x47FC0000,0x6DFC0000,
-0x47FC0000,0x1980001,0x1980001,0x1980001,0x1980001,0x69FC0000,0x69FC0000,0x69FC0000,0xB5FC0000,0xB5FC0000,0xCC000000,0x69FC0000,0x69FC0000,0x69FC0000,0xB5FC0000,0xB5FC0000,0xCC000000,0xB5FC0000,0xB5FC0000,0xCC000000,0xCC000000,0x69FC0000,0x69FC0000,0x69FC0000,0xB5FC0000,0xB5FC0000,0xCC000000,0xB5FC0000,0xB5FC0000,0xCC000000,0xCC000000,0xB5FC0000,
-0xB5FC0000,0xCC000000,0xCC000000,0xCC000000,0x1DC0000,0x3B40000,0x1980001,0x45FC0000,0x85FC0000,0xA1FC0000,0xABFC0000,0xBBFC0000,0xBFC0000,0x69FC0000,0xA1FC0000,0xCC000000,0xA1FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x16832DC,0xFF50247F,0xFF381933,0xFF34152B,0xFF3C1E14,0xFF200F63,0xFF1809EB,0xFF080CD6,0xF9000656,0xE5000B06,0xFF24213C,0xFF040F22,0xFEF407FB,0xFEE40906,0xFED00012,0xE8D4055E,0xFECC12C5,0xEEBC0679,0xDCBC0799,0xCCC812C5,0x19FC32DC,0xFEE41DCF,0xFED0152B,0xFEB81322,0xFE940691,0xE4A00B04,0xFE701733,0xFE380481,0xE4400525,0xCC6412C4,0x8FF832DC,
-0xF200169C,0xDC000E76,0xC4001765,0xB20032DC,0xFF502793,0xF9602F06,0xFB642FFB,0xFF2C1B7E,0xFF0C0F8A,0xFEE804E2,0xFEDC00E2,0xFAC4003B,0xFF3C26EC,0xFF1819CA,0xFEB804ED,0xE4400525,0x71FC32DC,0x19C12C3,0xFF800C56,0xFF7006A3,0xFF680482,0xFF740B9D,0xFF5803DE,0xFF4400A9,0xFF400533,0xF73400C2,0xE53804E5,0x6BFC12C3,0xFF3808E2,0xFF200482,0xFF080785,0xFCD80005,
-0xE4F404E4,0xB7F812C3,0xFE380480,0xE41404E4,0xCC0012C4,0x6BFC12C3,0xFF3808E2,0xFF200482,0xFF080785,0xFCD80005,0xE4F404E4,0xB7F812C3,0xFE380480,0xE41404E4,0xCC0012C4,0xB7F812C3,0xFE380480,0xE41404E4,0xCC0012C4,0xCC0012C4,0xFF800FC5,0xFF8C1193,0xF59811A2,0xFF6C0C12,0xFF4807DA,0xFF1002DD,0xFEF8000D,0xFCB00018,0xFF780FAA,0xFF5C0B8A,0xFED004E3,0xE41404E4,
-0xA3FC12C3,0x134152B,0x134152B,0x134152B,0x134152B,0xFF1809EB,0xFF1809EB,0xFF1809EB,0xF1040622,0xF1040622,0xCD000622,0xFEF407FB,0xFEF407FB,0xFEF407FB,0xFED00012,0xFED00012,0xD0E00132,0xDACC0481,0xDACC0481,0xC6C0007D,0xB4C80481,0x1C8152B,0x1C8152B,0x1C8152B,0xFE940691,0xFE940691,0xCCB80620,0xFE380481,0xFE380481,0xCC680005,0xB47C0480,0x69FC152B,
-0x69FC152B,0xC4000672,0xAC0005E1,0x9A00152C,0xFF200F46,0xFF2C1292,0x134152B,0xFF100A32,0xFEF40542,0xFEE001CB,0xFEDC00E2,0xF0C80002,0xFF140ED2,0xFEF4097A,0xFEB80489,0xCC680005,0x41FC152B,0x1680482,0x1680482,0x1680482,0x1680482,0xFF4400A9,0xFF4400A9,0xFF4400A9,0xE5380001,0xE5380001,0xCD380001,0x1FFC0480,0x1FFC0480,0x1FFC0480,0xF8E00001,0xF8E00001,
-0xCD0C0000,0x91FC0480,0x91FC0480,0xCC740000,0xB4000480,0x1FFC0480,0x1FFC0480,0x1FFC0480,0xF8E00001,0xF8E00001,0xCD0C0000,0x91FC0480,0x91FC0480,0xCC740000,0xB4000480,0x91FC0480,0x91FC0480,0xCC740000,0xB4000480,0xB4000480,0xFF580349,0xFB64039D,0x1680482,0xFF440288,0xFD280154,0xFEFC006D,0xFEF8000D,0xF4C00000,0xFD4C0372,0xFF300269,0x75FC0480,0xCC740000,
-0x75FC0480,0x1CC04E2,0xFFBC0305,0xFFA000EA,0xFF980001,0xB5FC04E2,0xFF8801CD,0xFF680000,0xDBF804E2,0xFECC0000,0xE40004E4,0xB5FC04E2,0xFF8801CD,0xFF680000,0xDBF804E2,0xFECC0000,0xE40004E4,0xDBF804E2,0xFECC0000,0xE40004E4,0xE40004E4,0xB5FC04E2,0xFF8801CD,0xFF680000,0xDBF804E2,0xFECC0000,0xE40004E4,0xDBF804E2,0xFECC0000,0xE40004E4,0xE40004E4,0xDBF804E2,
-0xFECC0000,0xE40004E4,0xE40004E4,0xE40004E4,0xF9C40480,0xDE804E2,0xFDC80482,0xFFB003CA,0xFF900305,0xFF480175,0xFF080000,0xFE840000,0xF3C40480,0xFFA003B5,0xFF300028,0xE40004E4,0xD1FC04E2,0x1000622,0x1000622,0x1000622,0x1000622,0x1000622,0x1000622,0x1000622,0x1000622,0x1000622,0x1000622,0xFED00012,0xFED00012,0xFED00012,0xFED00012,0xFED00012,
-0xFED00012,0xB8C80001,0xB8C80001,0xB8C80001,0x9CC80001,0x1800620,0x1800620,0x1800620,0x1800620,0x1800620,0x1800620,0xD0600001,0xD0600001,0xD0600001,0x9C940000,0x45F80620,0x45F80620,0x45F80620,0x9A00000D,0x80000620,0xF4F80482,0x1000622,0x1000622,0xFEE8029A,0xFEE4016D,0xFEDC0091,0xFEDC0091,0xECCC0001,0xF8E803F5,0xFED80269,0xD4BC0000,0xD0600001,
-0x13FC0620,};
-static const uint32_t g_etc1_to_bc7_m6_table183[] = {
-0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x27F80000,
-0x27F80000,0x27F80000,0x27F80000,0x6C000000,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xE80000,0xE80000,0xE80000,0x1440000,0x1D00000,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,
-0x3E80000,0x79FC0000,0x79FC0000,0x79FC0000,0xA4000000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x79FC0000,0x79FC0000,0x79FC0000,0xA4000000,0x79FC0000,0x79FC0000,0x79FC0000,0xA4000000,0xA4000000,0x1600000,0x1480001,0x1480001,0x1800000,0x39C0000,0x1C00000,0x1C00000,0x23FC0000,0x1800000,0x39C0000,0x57FC0000,0x79FC0000,
-0x57FC0000,0x1A80001,0x1A80001,0x1A80001,0x1A80001,0x81FC0000,0x81FC0000,0x81FC0000,0xC1FC0000,0xC1FC0000,0xD4000000,0x81FC0000,0x81FC0000,0x81FC0000,0xC1FC0000,0xC1FC0000,0xD4000000,0xC1FC0000,0xC1FC0000,0xD4000000,0xD4000000,0x81FC0000,0x81FC0000,0x81FC0000,0xC1FC0000,0xC1FC0000,0xD4000000,0xC1FC0000,0xC1FC0000,0xD4000000,0xD4000000,0xC1FC0000,
-0xC1FC0000,0xD4000000,0xD4000000,0xD4000000,0x1F00000,0xBC40000,0x1A80001,0x63FC0000,0x99FC0000,0xB1FC0000,0xB9FC0000,0xC7F40000,0x33FC0000,0x81FC0000,0xB1FC0000,0xD4000000,0xB1FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1742E54,0xFF5C2227,0xFF4C189C,0xFF44152B,0xFF441B96,0xFF2C0F3F,0xFF240A83,0xFF200BB6,0xFD10062A,0xE9100996,0xFF301E64,0xFF140EBF,0xFF0C08B3,0xFEF0080E,0xFEE40042,0xEAE40406,0xFEE00FFC,0xF2D005A9,0xE2C805B5,0xD2D80FD9,0x2BFC2E54,0xFEFC1C6F,0xFEE8152B,0xFECC11E6,0xFEAC06E9,0xE8B40994,0xFE9414BB,0xFE5804A2,0xE854039D,0xD2740FD9,0x97FC2E54,
-0xF8001590,0xE0000BBC,0xCA001371,0xB8002E54,0xFF58245E,0xFF6C2AA6,0xFF6C2BC3,0xFF4019B9,0xFF1C0EF6,0xFEFC0522,0xFEF00173,0xFCD8000A,0xFF5023BA,0xFF30184B,0xFED00513,0xE854039D,0x7DF82E54,0x1A40FDB,0xFF8C0AC6,0xFF7C063B,0xFF780482,0xFF8009BD,0xFF64037E,0xFF5C00E1,0xFF5803EB,0xF944005E,0xE9480375,0x7BFC0FD8,0xFF4C0811,0xFF380482,0xFF200615,0xFEF00005,
-0xE9080374,0xBFF80FD8,0xFE6C0480,0xE8340374,0xD2000FD8,0x7BFC0FD8,0xFF4C0811,0xFF380482,0xFF200615,0xFEF00005,0xE9080374,0xBFF80FD8,0xFE6C0480,0xE8340374,0xD2000FD8,0xBFF80FD8,0xFE6C0480,0xE8340374,0xD2000FD8,0xD2000FD8,0xFF940D34,0xF9A00ECD,0xFBA40ED6,0xFF780A71,0xFF5C06D6,0xFF2C0293,0xFF10002D,0xFECC0002,0xFF880D43,0xFF680A04,0xFEE404D1,0xE8340374,
-0xADFC0FD8,0x144152B,0x144152B,0x144152B,0x144152B,0xFF240A83,0xFF240A83,0xFF240A83,0xF9140622,0xF9140622,0xD5100622,0xFF0C08B3,0xFF0C08B3,0xFF0C08B3,0xFEE40042,0xFEE40042,0xD8F00132,0xE2DC0481,0xE2DC0481,0xCED0007D,0xBCD80481,0x1E0152B,0x1E0152B,0x1E0152B,0xFEAC06E9,0xFEAC06E9,0xD4C80620,0xFE5804A2,0xFE5804A2,0xD4780005,0xBC8C0480,0x75FC152B,
-0x75FC152B,0xD0000642,0xB8000581,0xA200152C,0xFF2C0FD1,0xF94012E3,0x144152B,0xFF180AF6,0xFF080612,0xFEF8026E,0xFEF00173,0xF8D80002,0xFF200F41,0xFF100A41,0xFED004C2,0xD4780005,0x51FC152B,0x1780482,0x1780482,0x1780482,0x1780482,0xFF5C00E1,0xFF5C00E1,0xFF5C00E1,0xED480001,0xED480001,0xD5480001,0x37FC0480,0x37FC0480,0x37FC0480,0xFCF80005,0xFCF80005,
-0xD51C0000,0x9DFC0480,0x9DFC0480,0xD4840000,0xBC000480,0x37FC0480,0x37FC0480,0x37FC0480,0xFCF80005,0xFCF80005,0xD51C0000,0x9DFC0480,0x9DFC0480,0xD4840000,0xBC000480,0x9DFC0480,0x9DFC0480,0xD4840000,0xBC000480,0xBC000480,0xFB6C0372,0xFF6C03C5,0x1780482,0xFD5802AD,0xFF400188,0xFF2000A4,0xFF10002D,0xFCD00000,0xF564039D,0xFF48028A,0x83FC0480,0xD4840000,
-0x83FC0480,0x1D40372,0xFFC40212,0xFFB400A9,0xFFA80001,0xC1FC0372,0xFF940145,0xFF800000,0xE1F80372,0xFEFC0000,0xE8000374,0xC1FC0372,0xFF940145,0xFF800000,0xE1F80372,0xFEFC0000,0xE8000374,0xE1F80372,0xFEFC0000,0xE8000374,0xE8000374,0xC1FC0372,0xFF940145,0xFF800000,0xE1F80372,0xFEFC0000,0xE8000374,0xE1F80372,0xFEFC0000,0xE8000374,0xE8000374,0xE1F80372,
-0xFEFC0000,0xE8000374,0xE8000374,0xE8000374,0xFDCC0320,0x1F40372,0xFFCC0332,0xFFC002AD,0xFFA80221,0xFF5C0110,0xFF300000,0xFEC00000,0xF7CC0320,0xFFAC02A8,0xFF50001A,0xE8000374,0xD9FC0372,0x1100622,0x1100622,0x1100622,0x1100622,0x1100622,0x1100622,0x1100622,0x1100622,0x1100622,0x1100622,0xFEE0002D,0xFEE0002D,0xFEE0002D,0xFEE0002D,0xFEE0002D,
-0xFEE0002D,0xC0D80001,0xC0D80001,0xC0D80001,0xA4D80001,0x1980620,0x1980620,0x1980620,0x1980620,0x1980620,0x1980620,0xD8700001,0xD8700001,0xD8700001,0xA4A40000,0x51F80620,0x51F80620,0x51F80620,0xA4000004,0x88000620,0xFD080482,0x1100622,0x1100622,0xFD0002D2,0xFEF801A5,0xFEE800C1,0xFEE800C1,0xF4DC0001,0xFEF403F9,0xFEE402A8,0xDCCC0000,0xD8700001,
-0x21FC0620,};
-static const uint32_t g_etc1_to_bc7_m6_table184[] = {
-0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x33FC0000,
-0x33FC0000,0x33FC0000,0x33FC0000,0x74000001,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xFC0000,0xFC0000,0xFC0000,0x35C0000,0x1F40000,0x15C0000,0x15C0000,0x15C0000,0x15C0000,0x15C0000,0x15C0000,0x15C0000,0x15C0000,0x15C0000,0x15C0000,0x9FC0000,0x9FC0000,0x9FC0000,0x9FC0000,0x9FC0000,
-0x9FC0000,0x87FC0000,0x87FC0000,0x87FC0000,0xAC000001,0x9FC0000,0x9FC0000,0x9FC0000,0x9FC0000,0x9FC0000,0x9FC0000,0x87FC0000,0x87FC0000,0x87FC0000,0xAC000001,0x87FC0000,0x87FC0000,0x87FC0000,0xAC000001,0xAC000001,0x1740000,0x15C0000,0x15C0000,0x1940000,0x1B40000,0x1D80000,0x1D80000,0x39FC0000,0x1940000,0x1B40000,0x67FC0000,0x87FC0000,
-0x67FC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0xCFF80000,0xCFF80000,0xDC000001,0x9BFC0000,0x9BFC0000,0x9BFC0000,0xCFF80000,0xCFF80000,0xDC000001,0xCFF80000,0xCFF80000,0xDC000001,0xDC000001,0x9BFC0000,0x9BFC0000,0x9BFC0000,0xCFF80000,0xCFF80000,0xDC000001,0xCFF80000,0xCFF80000,0xDC000001,0xDC000001,0xCFF80000,
-0xCFF80000,0xDC000001,0xDC000001,0xDC000001,0x17FC0000,0x5D80000,0x1BC0000,0x85FC0000,0xAFFC0000,0xC1FC0000,0xC9F80000,0xD3F80000,0x5FFC0000,0x9BFC0000,0xC1FC0000,0xDC000001,0xC1FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x18029AD,0xFF681FD0,0xFF581805,0xFF58152C,0xFF5C195D,0xFF400F2A,0xFF3C0B40,0xFF2C0AC5,0xFF240629,0xEF240841,0xFF441B46,0xFF2C0E8C,0xFF180984,0xFF080739,0xFEFC00B5,0xF0FC02D1,0xFEF80D65,0xF6E40502,0xE8E003EA,0xD8EC0CF6,0x41FC29AD,0xFF141B10,0xFF04152B,0xFEE41095,0xFECC0789,0xEEC80841,0xFEAC126A,0xFE7C04F9,0xEC740236,0xD88C0CF6,0xA1FC29AD,
-0xFE00152B,0xE6000953,0xD4000F97,0xC00029AF,0xFF64212B,0xF77C26D9,0xF98027C5,0xFF5417DD,0xFF300E79,0xFF1805B7,0xFF080236,0xFEEC0009,0xFF5C209B,0xFF40169E,0xFEF0056C,0xEC740236,0x89FC29AD,0x1B00CF9,0xFFA40924,0xFF9405C1,0xFF8C0480,0xFF8C07FD,0xFF7C0332,0xFF740139,0xFF6402C1,0xFD580018,0xEF5C0221,0x8DFC0CF6,0xFF640723,0xFF540480,0xFF3804C5,0xFF14001D,
-0xEF1C0221,0xC7FC0CF6,0xFEA00480,0xEE500221,0xD8000CF6,0x8DFC0CF6,0xFF640723,0xFF540480,0xFF3804C5,0xFF14001D,0xEF1C0221,0xC7FC0CF6,0xFEA00480,0xEE500221,0xD8000CF6,0xC7FC0CF6,0xFEA00480,0xEE500221,0xD8000CF6,0xD8000CF6,0xFFA00AE3,0xFFAC0BFD,0xFFAC0C24,0xFF9408AE,0xFF6805CD,0xFF48026C,0xFF280068,0xFEF40008,0xFF980AF2,0xFF840840,0xFF1004B3,0xEE500221,
-0xB9FC0CF6,0x158152C,0x158152C,0x158152C,0x158152C,0xFF3C0B40,0xFF3C0B40,0xFF3C0B40,0xFF240629,0xFF240629,0xDD240621,0xFF180984,0xFF180984,0xFF180984,0xFEFC00B5,0xFEFC00B5,0xE1000131,0xECEC0480,0xECEC0480,0xD8E4007A,0xC4EC0482,0x1FC152B,0x1FC152B,0x1FC152B,0xFECC0789,0xFECC0789,0xDCDC0621,0xFE7C04F9,0xFE7C04F9,0xDE880006,0xC4A00482,0x83F8152B,
-0x83F8152B,0xDC000629,0xC200053B,0xAA00152B,0xFD48103D,0xFF4C1304,0x158152C,0xFF340BC5,0xFF1C0715,0xFF100379,0xFF080236,0xFEEC0009,0xFF340FA9,0xFF240B2D,0xFEF0052C,0xDE880006,0x61FC152B,0x18C0480,0x18C0480,0x18C0480,0x18C0480,0xFF740139,0xFF740139,0xFF740139,0xF55C0000,0xF55C0000,0xDD5C0001,0x53FC0480,0x53FC0480,0x53FC0480,0xFF14001D,0xFF14001D,
-0xDF2C0001,0xABF80480,0xABF80480,0xDC9C0001,0xC4000482,0x53FC0480,0x53FC0480,0x53FC0480,0xFF14001D,0xFF14001D,0xDF2C0001,0xABF80480,0xABF80480,0xDC9C0001,0xC4000482,0xABF80480,0xABF80480,0xDC9C0001,0xC4000482,0xC4000482,0xF780039D,0xFD8803C8,0x18C0480,0xFB7002F9,0xFF5401CA,0xFF3800E9,0xFF280068,0xFEF40008,0xFD74039D,0xFF5C02B9,0x95FC0480,0xDC9C0001,
-0x95FC0480,0x1DC0221,0xFFD00145,0xFFC00068,0xFFBC0000,0xCDFC0221,0xFFAC00C2,0xFF9C0000,0xE7F80221,0xFF340000,0xEE000221,0xCDFC0221,0xFFAC00C2,0xFF9C0000,0xE7F80221,0xFF340000,0xEE000221,0xE7F80221,0xFF340000,0xEE000221,0xEE000221,0xCDFC0221,0xFFAC00C2,0xFF9C0000,0xE7F80221,0xFF340000,0xEE000221,0xE7F80221,0xFF340000,0xEE000221,0xEE000221,0xE7F80221,
-0xFF340000,0xEE000221,0xEE000221,0xEE000221,0xFFD001ED,0x1FC0221,0xF7DC0200,0xFFC001A8,0xFFA80152,0xFF8400A0,0xFF5C0000,0xFF040000,0xFBD401E1,0xFFC00190,0xFF700010,0xEE000221,0xDFFC0221,0x1240620,0x1240620,0x1240620,0x1240620,0x1240620,0x1240620,0x1240620,0x1240620,0x1240620,0x1240620,0xFEF40050,0xFEF40050,0xFEF40050,0xFEF40050,0xFEF40050,
-0xFEF40050,0xC8EC0000,0xC8EC0000,0xC8EC0000,0xACEC0001,0x3B00620,0x3B00620,0x3B00620,0x3B00620,0x3B00620,0x3B00620,0xE0840001,0xE0840001,0xE0840001,0xAEB40001,0x5DFC0620,0x5DFC0620,0x5DFC0620,0xAC080001,0x90000622,0xF71C04B1,0x1240620,0x1240620,0xFF1002FD,0xFF0C01E1,0xFF0000F4,0xFF0000F4,0xFEEC0000,0xFD0C0422,0xFF0002D4,0xE6DC0000,0xE0840001,
-0x33FC0620,};
-static const uint32_t g_etc1_to_bc7_m6_table185[] = {
-0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0x3740000,0x3740000,0x3740000,0x3740000,0x3740000,0x3740000,0x3740000,0x3740000,0x3740000,0x3740000,0x3FFC0000,
-0x3FFC0000,0x3FFC0000,0x3FFC0000,0x7C000001,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0x10C0000,0x10C0000,0x10C0000,0x3740000,0xDFC0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x23FC0000,0x23FC0000,0x23FC0000,0x23FC0000,0x23FC0000,
-0x23FC0000,0x93FC0000,0x93FC0000,0x93FC0000,0xB4000001,0x23FC0000,0x23FC0000,0x23FC0000,0x23FC0000,0x23FC0000,0x23FC0000,0x93FC0000,0x93FC0000,0x93FC0000,0xB4000001,0x93FC0000,0x93FC0000,0x93FC0000,0xB4000001,0xB4000001,0x1840000,0x16C0000,0x16C0000,0x1A80000,0x1C80000,0x1F00000,0x1F00000,0x4DFC0000,0x1A80000,0x1C80000,0x77FC0000,0x93FC0000,
-0x77FC0000,0x1CC0000,0x1CC0000,0x1CC0000,0x1CC0000,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xDBF80000,0xDBF80000,0xE4000001,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xDBF80000,0xDBF80000,0xE4000001,0xDBF80000,0xDBF80000,0xE4000001,0xE4000001,0xB5FC0000,0xB5FC0000,0xB5FC0000,0xDBF80000,0xDBF80000,0xE4000001,0xDBF80000,0xDBF80000,0xE4000001,0xE4000001,0xDBF80000,
-0xDBF80000,0xE4000001,0xE4000001,0xE4000001,0x51FC0000,0xDE80000,0x1CC0000,0xA3FC0000,0xC3FC0000,0xD1FC0000,0xD5FC0000,0xDDFC0000,0x87FC0000,0xB5FC0000,0xD1FC0000,0xE4000001,0xD1FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x18C25F1,0xFF801DF0,0xFF70177D,0xFF68152C,0xFF68179D,0xFF540F30,0xFF500BE9,0xFF400A4D,0xFF380659,0xF3340759,0xFF5C1916,0xFF3C0E80,0xFF300A44,0xFF2006D1,0xFF100159,0xF30C0209,0xFF080B86,0xFAF804A6,0xECF402A6,0xDEFC0AC2,0x53FC25F1,0xFF2C19F0,0xFF1C152B,0xFEFC0FAD,0xFEE40821,0xF2DC0759,0xFECC10EA,0xFE940579,0xF0880142,0xDE9C0AC2,0xABF825F1,
-0xFE2C152B,0xEC0007C7,0xDA000C9B,0xC60025F3,0xFF781EA2,0xFD88233D,0xFF8C2439,0xFF5C168D,0xFF440E39,0xFF240649,0xFF1C031D,0xFF040051,0xFF701E24,0xFF501536,0xFEFC05F2,0xF0880142,0x95FC25F1,0x1BC0AC1,0xFFB007EC,0xFFA00569,0xFF9C0480,0xFFA406AD,0xFF88030E,0xFF800185,0xFF7C0209,0xFF6C0001,0xF36C0139,0x9BFC0AC1,0xFF7C066B,0xFF6C0480,0xFF5803FE,0xFF2C0055,
-0xF3300139,0xCFF80AC1,0xFED40480,0xF2700139,0xDE000AC2,0x9BFC0AC1,0xFF7C066B,0xFF6C0480,0xFF5803FE,0xFF2C0055,0xF3300139,0xCFF80AC1,0xFED40480,0xF2700139,0xDE000AC2,0xCFF80AC1,0xFED40480,0xF2700139,0xDE000AC2,0xDE000AC2,0xFFB4091E,0xF5B80A25,0xF7BC0A41,0xFF98075D,0xFF7C0521,0xFF5C026D,0xFF4800B4,0xFF0C0032,0xFFA4093E,0xFF900722,0xFF3004A6,0xF2700139,
-0xC1FC0AC1,0x168152C,0x168152C,0x168152C,0x168152C,0xFF500BE9,0xFF500BE9,0xFF500BE9,0xFF380659,0xFF380659,0xE5340621,0xFF300A44,0xFF300A44,0xFF300A44,0xFF100159,0xFF100159,0xE9100131,0xF4FC0480,0xF4FC0480,0xE0F4007A,0xCCFC0482,0x19FC152B,0x19FC152B,0x19FC152B,0xFEE40821,0xFEE40821,0xE4EC0621,0xFE940579,0xFE940579,0xE6980006,0xCCB00482,0x8FF8152B,
-0x8FF8152B,0xE4000621,0xCA0004F6,0xB200152B,0xFF5810A1,0xFB641341,0x168152C,0xFF440C7A,0xFF300805,0xFF240465,0xFF1C031D,0xFF040051,0xFF501035,0xFF300BE1,0xFEFC05B2,0xE6980006,0x71FC152B,0x19C0480,0x19C0480,0x19C0480,0x19C0480,0xFF800185,0xFF800185,0xFF800185,0xFD6C0000,0xFD6C0000,0xE56C0001,0x6BFC0480,0x6BFC0480,0x6BFC0480,0xFF2C0055,0xFF2C0055,
-0xE73C0001,0xB7F80480,0xB7F80480,0xE4AC0001,0xCC000482,0x6BFC0480,0x6BFC0480,0x6BFC0480,0xFF2C0055,0xFF2C0055,0xE73C0001,0xB7F80480,0xB7F80480,0xE4AC0001,0xCC000482,0xB7F80480,0xB7F80480,0xE4AC0001,0xCC000482,0xCC000482,0xFF90039D,0xF59803F5,0x19C0480,0xFD840320,0xFF700221,0xFF500151,0xFF4800B4,0xFF0C0032,0xFD8803C8,0xFF7402FD,0xA3FC0480,0xE4AC0001,
-0xA3FC0480,0x1E40139,0xFFDC00B9,0xFFCC0040,0xFFCC0000,0xD9FC0139,0xFFC00074,0xFFB40000,0xEDF80139,0xFF640000,0xF2000139,0xD9FC0139,0xFFC00074,0xFFB40000,0xEDF80139,0xFF640000,0xF2000139,0xEDF80139,0xFF640000,0xF2000139,0xF2000139,0xD9FC0139,0xFFC00074,0xFFB40000,0xEDF80139,0xFF640000,0xF2000139,0xEDF80139,0xFF640000,0xF2000139,0xF2000139,0xEDF80139,
-0xFF640000,0xF2000139,0xF2000139,0xF2000139,0xF5E40120,0x37FC0139,0xFBE40120,0xFFD800F2,0xFFBC00C2,0xFFA40061,0xFF840000,0xFF400000,0xFFDC0109,0xFFCC00E9,0xFF940009,0xF2000139,0xE7FC0139,0x1340620,0x1340620,0x1340620,0x1340620,0x1340620,0x1340620,0x1340620,0x1340620,0x1340620,0x1340620,0xFF0C0080,0xFF0C0080,0xFF0C0080,0xFF0C0080,0xFF0C0080,
-0xFF0C0080,0xD0FC0000,0xD0FC0000,0xD0FC0000,0xB4FC0001,0x1C80620,0x1C80620,0x1C80620,0x1C80620,0x1C80620,0x1C80620,0xE8940001,0xE8940001,0xE8940001,0xB6C40001,0x69FC0620,0x69FC0620,0x69FC0620,0xB4180001,0x98000622,0xFF2C04B1,0x1340620,0x1340620,0xFF200328,0xFF140220,0xFF100128,0xFF100128,0xFF000008,0xFD1C0451,0xFF1402F9,0xEEEC0000,0xE8940001,
-0x41FC0620,};
-static const uint32_t g_etc1_to_bc7_m6_table186[] = {
-0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x4BFC0000,
-0x4BFC0000,0x4BFC0000,0x4BFC0000,0x84000001,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x71C0000,0x71C0000,0x71C0000,0x38C0000,0x1DF80000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x17C0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,
-0x3BFC0000,0x9FF80000,0x9FF80000,0x9FF80000,0xBC000001,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x9FF80000,0x9FF80000,0x9FF80000,0xBC000001,0x9FF80000,0x9FF80000,0x9FF80000,0xBC000001,0xBC000001,0x3940000,0x17C0000,0x17C0000,0x5B80000,0x1DC0000,0xDFC0000,0xDFC0000,0x61FC0000,0x5B80000,0x1DC0000,0x85FC0000,0x9FF80000,
-0x85FC0000,0x1DC0000,0x1DC0000,0x1DC0000,0x1DC0000,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xE7F80000,0xE7F80000,0xEC000001,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xE7F80000,0xE7F80000,0xEC000001,0xE7F80000,0xE7F80000,0xEC000001,0xEC000001,0xCDFC0000,0xCDFC0000,0xCDFC0000,0xE7F80000,0xE7F80000,0xEC000001,0xE7F80000,0xE7F80000,0xEC000001,0xEC000001,0xE7F80000,
-0xE7F80000,0xEC000001,0xEC000001,0xEC000001,0x89FC0000,0x1FC0000,0x1DC0000,0xC1FC0000,0xD7FC0000,0xDFFC0000,0xE3FC0000,0xE9F40000,0xADFC0000,0xCDFC0000,0xDFFC0000,0xEC000001,0xDFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1982295,0xFF8C1C24,0xFF7C16F9,0xFF78152C,0xFF74162D,0xFF640F5A,0xFF5C0C99,0xFF4C0A19,0xFF4C06D0,0xF74406B1,0xFF68172A,0xFF500E8F,0xFF440B02,0xFF2C06C9,0xFF200231,0xF7200185,0xFF200A26,0xFF0C0482,0xF30001AE,0xE30C08E2,0x65FC2295,0xFF401914,0xFF34152B,0xFF140F05,0xFEFC08D9,0xF6F006B1,0xFEE40F9A,0xFEB80619,0xF49C0096,0xE2B008E2,0xB3FC2295,
-0xFE60152B,0xF40006C7,0xE0000A17,0xCC002297,0xFF801C65,0xFF8C2049,0xF598216C,0xFF701581,0xFF540E23,0xFF3806FD,0xFF340421,0xFF1400E4,0xFF781BC6,0xFF5C147B,0xFF1806AC,0xF49C0096,0x9FFC2295,0x1C808E1,0xFFBC06E4,0xFFAC0529,0xFFAC0480,0xFFB00599,0xFF9C0300,0xFF9801E5,0xFF880191,0xFF7C0010,0xF77C0091,0xAFFC08E1,0xFF9405D3,0xFF840480,0xFF700356,0xFF4C00A9,
-0xF7440091,0xD7FC08E1,0xFF040480,0xF6900091,0xE20008E2,0xAFFC08E1,0xFF9405D3,0xFF840480,0xFF700356,0xFF4C00A9,0xF7440091,0xD7FC08E1,0xFF040480,0xF6900091,0xE20008E2,0xD7FC08E1,0xFF040480,0xF6900091,0xE20008E2,0xE20008E2,0xFFBC07A1,0xFBC4084D,0xFBC40879,0xFFB00662,0xFF90049D,0xFF740269,0xFF640104,0xFF300074,0xFFB407AA,0xFFA40632,0xFF500499,0xF6900091,
-0xCDFC08E1,0x178152C,0x178152C,0x178152C,0x178152C,0xFF5C0C99,0xFF5C0C99,0xFF5C0C99,0xFF4C06D0,0xFF4C06D0,0xED440621,0xFF440B02,0xFF440B02,0xFF440B02,0xFF200231,0xFF200231,0xF1200131,0xFD0C0480,0xFD0C0480,0xE904007A,0xD50C0482,0x31FC152B,0x31FC152B,0x31FC152B,0xFEFC08D9,0xFEFC08D9,0xECFC0621,0xFEB80619,0xFEB80619,0xEEA80006,0xD4C00482,0x9BF8152B,
-0x9BF8152B,0xEC100621,0xD20004D2,0xBA00152B,0xFF6810FE,0xFF6C1369,0x178152C,0xFF540D39,0xFF440905,0xFF340565,0xFF340421,0xFF1400E4,0xFF5810BE,0xFF500C92,0xFF18067B,0xEEA80006,0x7FFC152B,0x1AC0480,0x1AC0480,0x1AC0480,0x1AC0480,0xFF9801E5,0xFF9801E5,0xFF9801E5,0xFF7C0010,0xFF7C0010,0xED7C0001,0x83FC0480,0x83FC0480,0x83FC0480,0xFF4C00A9,0xFF4C00A9,
-0xEF4C0001,0xC3F80480,0xC3F80480,0xECBC0001,0xD4000482,0x83FC0480,0x83FC0480,0x83FC0480,0xFF4C00A9,0xFF4C00A9,0xEF4C0001,0xC3F80480,0xC3F80480,0xECBC0001,0xD4000482,0xC3F80480,0xC3F80480,0xECBC0001,0xD4000482,0xD4000482,0xFFA003CA,0xFDA803F5,0x1AC0480,0xFF980349,0xFF840269,0xFF6C019A,0xFF640104,0xFF300074,0xFF9403DA,0xFF840340,0xB3FC0480,0xECBC0001,
-0xB3FC0480,0x1EC0091,0xFFE80055,0xFFE0001D,0xFFDC0000,0xE5FC0091,0xFFD80034,0xFFCC0000,0xF3F80091,0xFF940000,0xF6000091,0xE5FC0091,0xFFD80034,0xFFCC0000,0xF3F80091,0xFF940000,0xF6000091,0xF3F80091,0xFF940000,0xF6000091,0xF6000091,0xE5FC0091,0xFFD80034,0xFFCC0000,0xF3F80091,0xFF940000,0xF6000091,0xF3F80091,0xFF940000,0xF6000091,0xF6000091,0xF3F80091,
-0xFF940000,0xF6000091,0xF6000091,0xF6000091,0xF9EC0080,0x77FC0091,0xFFEC0080,0xFDE80071,0xFFD0005A,0xFFC00028,0xFFA80000,0xFF7C0000,0xFFE80080,0xFFE00071,0xFFB40004,0xF6000091,0xEFFC0091,0x1440620,0x1440620,0x1440620,0x1440620,0x1440620,0x1440620,0x1440620,0x1440620,0x1440620,0x1440620,0xFF1800B4,0xFF1800B4,0xFF1800B4,0xFF1800B4,0xFF1800B4,
-0xFF1800B4,0xD90C0000,0xD90C0000,0xD90C0000,0xBD0C0001,0x1E00620,0x1E00620,0x1E00620,0x1E00620,0x1E00620,0x1E00620,0xF0A40001,0xF0A40001,0xF0A40001,0xBED40001,0x75FC0620,0x75FC0620,0x75FC0620,0xBC280001,0xA0000622,0xF73C04E4,0x1440620,0x1440620,0xFF2C0371,0xFF280254,0xFF240171,0xFF240171,0xFF140020,0xF9300480,0xFF200332,0xF6FC0000,0xF0A40001,
-0x51FC0620,};
-static const uint32_t g_etc1_to_bc7_m6_table187[] = {
-0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x57FC0000,
-0x57FC0000,0x57FC0000,0x57FC0000,0x8C000001,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0xF2C0000,0xF2C0000,0xF2C0000,0x3A40000,0x2BFC0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,
-0x53FC0000,0xABF80000,0xABF80000,0xABF80000,0xC4000001,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0xABF80000,0xABF80000,0xABF80000,0xC4000001,0xABF80000,0xABF80000,0xABF80000,0xC4000001,0xC4000001,0xBA40000,0x18C0000,0x18C0000,0x1CC0000,0x1F00000,0x2BFC0000,0x2BFC0000,0x73FC0000,0x1CC0000,0x1F00000,0x95FC0000,0xABF80000,
-0x95FC0000,0x1EC0000,0x1EC0000,0x1EC0000,0x1EC0000,0xE5FC0000,0xE5FC0000,0xE5FC0000,0xF3F80000,0xF3F80000,0xF4000001,0xE5FC0000,0xE5FC0000,0xE5FC0000,0xF3F80000,0xF3F80000,0xF4000001,0xF3F80000,0xF3F80000,0xF4000001,0xF4000001,0xE5FC0000,0xE5FC0000,0xE5FC0000,0xF3F80000,0xF3F80000,0xF4000001,0xF3F80000,0xF3F80000,0xF4000001,0xF4000001,0xF3F80000,
-0xF3F80000,0xF4000001,0xF4000001,0xF4000001,0xC3FC0000,0x77FC0000,0x1EC0000,0xDFFC0000,0xEBFC0000,0xEFFC0000,0xF1FC0000,0xF3FC0000,0xD5FC0000,0xE5FC0000,0xEFFC0000,0xF4000001,0xEFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1A41F99,0xFF981A90,0xFF881695,0xFF88152C,0xFF80150D,0xFF740F8A,0xFF680D79,0xFF640A11,0xFF58076C,0xFB540649,0xFF7415A6,0xFF600EC8,0xFF5C0BF2,0xFF40071A,0xFF380339,0xFD2C0139,0xFF2C0946,0xFF200496,0xF71400FA,0xE91C0756,0x77FC1F99,0xFF58182C,0xFF4C152B,0xFF2C0E9D,0xFF1409B1,0xFB040649,0xFF080EA6,0xFED80706,0xFAB0002A,0xE8C40756,0xBDF81F99,
-0xFE90152B,0xFA080649,0xE600080B,0xD2001F9B,0xFF901A71,0xF9A01DC1,0xFBA41E94,0xFF80147F,0xFF640E3A,0xFF4C0805,0xFF3C0548,0xFF3001B8,0xFF9019F6,0xFF7413B6,0xFF300766,0xFAB0002A,0xABFC1F99,0x1D00759,0xFFC40609,0xFFC004EC,0xFFBC0480,0xFFBC04CD,0xFFB0030E,0xFFA40249,0xFFA00169,0xFF940050,0xFB8C0029,0xBDFC0756,0xFFAC055B,0xFF9C0480,0xFF8802EE,0xFF700115,
-0xFB580029,0xDFF80756,0xFF340480,0xFAB00029,0xE8000756,0xBDFC0756,0xFFAC055B,0xFF9C0480,0xFF8802EE,0xFF700115,0xFB580029,0xDFF80756,0xFF340480,0xFAB00029,0xE8000756,0xDFF80756,0xFF340480,0xFAB00029,0xE8000756,0xE8000756,0xFDCC067A,0xFFCC06D5,0xFFCC0711,0xFFC0058C,0xFFA40441,0xFF8402B0,0xFF7C0172,0xFF5000DD,0xFFC4067D,0xFFB0057E,0xFF700490,0xFAB00029,
-0xD7FC0756,0x188152C,0x188152C,0x188152C,0x188152C,0xFF680D79,0xFF680D79,0xFF680D79,0xFF58076C,0xFF58076C,0xF5540621,0xFF5C0BF2,0xFF5C0BF2,0xFF5C0BF2,0xFF380339,0xFF380339,0xF9300131,0xFF200496,0xFF200496,0xF114007A,0xDD1C0482,0x49FC152B,0x49FC152B,0x49FC152B,0xFF1409B1,0xFF1409B1,0xF50C0621,0xFED80706,0xFED80706,0xF6B80006,0xDCD00482,0xA7F8152B,
-0xA7F8152B,0xF4200621,0xDC0004A6,0xC200152B,0xFF741194,0xFB8413A0,0x188152C,0xFF680E19,0xFF580A15,0xFF4C06C1,0xFF3C0548,0xFF3001B8,0xFF741148,0xFF5C0D82,0xFF300742,0xF6B80006,0x8FFC152B,0x1BC0480,0x1BC0480,0x1BC0480,0x1BC0480,0xFFA40249,0xFFA40249,0xFFA40249,0xFF940050,0xFF940050,0xF58C0001,0x9BFC0480,0x9BFC0480,0x9BFC0480,0xFF700115,0xFF700115,
-0xF75C0001,0xCFF80480,0xCFF80480,0xF4CC0001,0xDC000482,0x9BFC0480,0x9BFC0480,0x9BFC0480,0xFF700115,0xFF700115,0xF75C0001,0xCFF80480,0xCFF80480,0xF4CC0001,0xDC000482,0xCFF80480,0xCFF80480,0xF4CC0001,0xDC000482,0xDC000482,0xFBB403F5,0xF5B80424,0x1BC0480,0xFFA40384,0xFF9802B9,0xFF7C020A,0xFF7C0172,0xFF5000DD,0xFDB003F5,0xFF980371,0xC1FC0480,0xF4CC0001,
-0xC1FC0480,0x1F40029,0xFFF40019,0xFFF00008,0xFFEC0000,0xF1FC0029,0xFFE40010,0xFFE40000,0xF9F80029,0xFFC80000,0xFA000029,0xF1FC0029,0xFFE40010,0xFFE40000,0xF9F80029,0xFFC80000,0xFA000029,0xF9F80029,0xFFC80000,0xFA000029,0xFA000029,0xF1FC0029,0xFFE40010,0xFFE40000,0xF9F80029,0xFFC80000,0xFA000029,0xF9F80029,0xFFC80000,0xFA000029,0xFA000029,0xF9F80029,
-0xFFC80000,0xFA000029,0xFA000029,0xFA000029,0xFDF40020,0xB7FC0029,0xF3F40029,0xFFEC001D,0xFFE80014,0xFFDC000A,0xFFD00000,0xFFB80000,0xFFF00022,0xFFF00020,0xFFD80001,0xFA000029,0xF7FC0029,0x1540620,0x1540620,0x1540620,0x1540620,0x1540620,0x1540620,0x1540620,0x1540620,0x1540620,0x1540620,0xFF3000F4,0xFF3000F4,0xFF3000F4,0xFF3000F4,0xFF3000F4,
-0xFF3000F4,0xE11C0000,0xE11C0000,0xE11C0000,0xC51C0001,0x1F80620,0x1F80620,0x1F80620,0x1F80620,0x1F80620,0x1F80620,0xF8B40001,0xF8B40001,0xF8B40001,0xC6E40001,0x81FC0620,0x81FC0620,0x81FC0620,0xC4380001,0xA8000622,0xFF4C04E4,0x1540620,0x1540620,0xFD48039D,0xFF3C0290,0xFF3401B1,0xFF3401B1,0xFF240050,0xFF3C0488,0xFF340355,0xFF0C0000,0xF8B40001,
-0x5FFC0620,};
-static const uint32_t g_etc1_to_bc7_m6_table188[] = {
-0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x65F80000,
-0x65F80000,0x65F80000,0x65F80000,0x96000000,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x9400000,0x9400000,0x9400000,0x1C00000,0x3DF80000,0x19C0001,0x19C0001,0x19C0001,0x19C0001,0x19C0001,0x19C0001,0x19C0001,0x19C0001,0x19C0001,0x19C0001,0x6FFC0000,0x6FFC0000,0x6FFC0000,0x6FFC0000,0x6FFC0000,
-0x6FFC0000,0xB9F80000,0xB9F80000,0xB9F80000,0xCE000000,0x6FFC0000,0x6FFC0000,0x6FFC0000,0x6FFC0000,0x6FFC0000,0x6FFC0000,0xB9F80000,0xB9F80000,0xB9F80000,0xCE000000,0xB9F80000,0xB9F80000,0xB9F80000,0xCE000000,0xCE000000,0x5B80000,0x19C0001,0x19C0001,0x3E00000,0x15FC0000,0x4DFC0000,0x4DFC0000,0x8BFC0000,0x3E00000,0x15FC0000,0xA5FC0000,0xB9F80000,
-0xA5FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1B01CB4,0xFFA4190F,0xFF9C1633,0xFF98152B,0xFF98140A,0xFF8C0FFF,0xFF800E56,0xFF700A74,0xFF700863,0xFF640622,0xFF8C144D,0xFF740F22,0xFF680D11,0xFF5807AB,0xFF4C04BA,0xFF44013D,0xFF4C08DC,0xFF380519,0xFB28008D,0xEF2C0601,0x8DFC1CB0,0xFF701751,0xFF68152C,0xFF4C0EB2,0xFF380AC2,0xFF1C0620,0xFF200DF9,0xFEFC0829,0xFECC0005,0xEED80600,0xC7FC1CB0,
-0xFEC8152B,0xFE2C0620,0xEC00064C,0xD8001CB0,0xFFA0185A,0xFFAC1AFA,0xFFAC1BE7,0xFF9413DF,0xFF780E8B,0xFF680924,0xFF5C06CB,0xFF400302,0xFF98183A,0xFF801312,0xFF3C08BF,0xFECC0005,0xB9FC1CB0,0x1DC0603,0xFFD40556,0xFFCC04C2,0xFFCC0482,0xFFD00433,0xFFC40336,0xFFBC02C5,0xFFAC0183,0xFFAC00DA,0xFF9C0001,0xCFFC0600,0xFFC004F6,0xFFB80480,0xFFA002C2,0xFF8801A9,
-0xFF700000,0xE7FC0600,0xFF6C0480,0xFED80000,0xEE000600,0xCFFC0600,0xFFC004F6,0xFFB80480,0xFFA002C2,0xFF8801A9,0xFF700000,0xE7FC0600,0xFF6C0480,0xFED80000,0xEE000600,0xE7FC0600,0xFF6C0480,0xFED80000,0xEE000600,0xEE000600,0xFFD80565,0xF7DC05C1,0xF7DC05E2,0xFFC404EB,0xFFC003FE,0xFFA802E1,0xFFA00212,0xFF7C0172,0xFFD00575,0xFFC804AC,0xFF980489,0xFED80000,
-0xE1FC0600,0x198152B,0x198152B,0x198152B,0x198152B,0xFF800E56,0xFF800E56,0xFF800E56,0xFF700863,0xFF700863,0xFF640622,0xFF680D11,0xFF680D11,0xFF680D11,0xFF4C04BA,0xFF4C04BA,0xFF44013D,0xFF380519,0xFF380519,0xF924007D,0xE72C0481,0x65FC152B,0x65FC152B,0x65FC152B,0xFF380AC2,0xFF380AC2,0xFF1C0620,0xFEFC0829,0xFEFC0829,0xFECC0005,0xE6E00480,0xB3FC152B,
-0xB3FC152B,0xFE2C0620,0xE6000490,0xCC00152C,0xFF901212,0xFF8C13EB,0x198152B,0xFF800EF9,0xFF6C0B5E,0xFF5C082E,0xFF5C06CB,0xFF400302,0xFF8011D1,0xFF740E66,0xFF3C089B,0xFECC0005,0x9FFC152B,0x1CC0482,0x1CC0482,0x1CC0482,0x1CC0482,0xFFBC02C5,0xFFBC02C5,0xFFBC02C5,0xFFAC00DA,0xFFAC00DA,0xFF9C0001,0xB7FC0480,0xB7FC0480,0xB7FC0480,0xFF8801A9,0xFF8801A9,
-0xFF700000,0xDDF40480,0xDDF40480,0xFED80000,0xE6000480,0xB7FC0480,0xB7FC0480,0xB7FC0480,0xFF8801A9,0xFF8801A9,0xFF700000,0xDDF40480,0xDDF40480,0xFED80000,0xE6000480,0xDDF40480,0xDDF40480,0xFED80000,0xE6000480,0xE6000480,0xFDC80422,0xFFCC0422,0x1CC0482,0xFDC003CA,0xFFAC0321,0xFFA0028D,0xFFA00212,0xFF7C0172,0xFFC40422,0xFFB003C5,0xD3FC0480,0xFED80000,
-0xD3FC0480,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1640622,0x1640622,0x1640622,0x1640622,0x1640622,0x1640622,0x1640622,0x1640622,0x1640622,0x1640622,0xFF44013D,0xFF44013D,0xFF44013D,0xFF44013D,0xFF44013D,
-0xFF44013D,0xEB2C0001,0xEB2C0001,0xEB2C0001,0xCF2C0001,0x19FC0620,0x19FC0620,0x19FC0620,0x19FC0620,0x19FC0620,0x19FC0620,0xFECC0005,0xFECC0005,0xFECC0005,0xCEF80000,0x8FF80620,0x8FF80620,0x8FF80620,0xCE480000,0xB2000620,0xF9600515,0x1640622,0x1640622,0xFF5803CA,0xFF5002DA,0xFF4C0202,0xFF4C0202,0xFF400091,0xFD5404B1,0xFF50039D,0xFF24000D,0xFECC0005,
-0x71FC0620,};
-static const uint32_t g_etc1_to_bc7_m6_table189[] = {
-0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x71F80000,
-0x71F80000,0x71F80000,0x71F80000,0x9E000000,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x1540000,0x1540000,0x1540000,0x1D80000,0x4BFC0000,0x1AC0001,0x1AC0001,0x1AC0001,0x1AC0001,0x1AC0001,0x1AC0001,0x1AC0001,0x1AC0001,0x1AC0001,0x1AC0001,0x87FC0000,0x87FC0000,0x87FC0000,0x87FC0000,0x87FC0000,
-0x87FC0000,0xC5F80000,0xC5F80000,0xC5F80000,0xD6000000,0x87FC0000,0x87FC0000,0x87FC0000,0x87FC0000,0x87FC0000,0x87FC0000,0xC5F80000,0xC5F80000,0xC5F80000,0xD6000000,0xC5F80000,0xC5F80000,0xC5F80000,0xD6000000,0xD6000000,0xDC80000,0x1AC0001,0x1AC0001,0x1F40000,0x3DFC0000,0x6BFC0000,0x6BFC0000,0x9DFC0000,0x1F40000,0x3DFC0000,0xB5FC0000,0xC5F80000,
-0xB5FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1B81834,0xFFB01547,0xFFA812FF,0xFFA4122B,0xFFA4114A,0xFF980E07,0xFF8C0CB6,0xFF880994,0xFF7C07EB,0xFF740622,0xFF981115,0xFF800CE2,0xFF800B29,0xFF7006D3,0xFF64046A,0xFF500195,0xFF580704,0xFF4C03F3,0xFD380035,0xF13C042D,0x99FC1830,0xFF7C13E9,0xFF78122B,0xFF580CF2,0xFF4C09E9,0xFF340620,0xFF380B89,0xFF1406C9,0xFEE40025,0xF0EC042D,0xCDFC1830,
-0xFEEC122B,0xFE600620,0xF0000435,0xDC001830,0xFFA814D6,0xFFAC171A,0xF5B817AC,0xFF9810D6,0xFF880C93,0xFF700806,0xFF68061E,0xFF5802DE,0xFFA014B2,0xFF901042,0xFF58074F,0xFEE40025,0xBFFC1830,0x1E4042B,0xFFDC03AB,0xFFD80346,0xFFD40322,0xFFD002E3,0xFFC8023E,0xFFC401E2,0xFFB8010B,0xFFB80092,0xFFAC0001,0xD9FC042B,0xFFCC0372,0xFFC00322,0xFFAC01E2,0xFFA00121,
-0xFF880000,0xEDF8042B,0xFF840320,0xFF080000,0xF000042C,0xD9FC042B,0xFFCC0372,0xFFC00322,0xFFAC01E2,0xFFA00121,0xFF880000,0xEDF8042B,0xFF840320,0xFF080000,0xF000042C,0xEDF8042B,0xFF840320,0xFF080000,0xF000042C,0xF000042C,0xFFD803C5,0xF9E003F9,0xFBE40412,0xFFD40355,0xFFC802BD,0xFFB801F5,0xFFA80161,0xFF8C0105,0xFFDC03C5,0xFFC8034C,0xFFA80329,0xFF080000,
-0xE7FC042B,0x1A4122B,0x1A4122B,0x1A4122B,0x1A4122B,0xFF8C0CB6,0xFF8C0CB6,0xFF8C0CB6,0xFF7C07EB,0xFF7C07EB,0xFF740622,0xFF800B29,0xFF800B29,0xFF800B29,0xFF64046A,0xFF64046A,0xFF500195,0xFF4C03F3,0xFF4C03F3,0xFB3C002A,0xEB3C0321,0x77FC122B,0x77FC122B,0x77FC122B,0xFF4C09E9,0xFF4C09E9,0xFF340620,0xFF1406C9,0xFF1406C9,0xFEE40025,0xEAF40320,0xBDF8122B,
-0xBDF8122B,0xFE600620,0xEA040320,0xD000122C,0xFD9C0FA9,0xF9A01122,0x1A4122B,0xFF900D02,0xFF8009FE,0xFF700742,0xFF68061E,0xFF5802DE,0xFF940F4C,0xFF800CA1,0xFF580736,0xFEE40025,0xABFC122B,0x1D40322,0x1D40322,0x1D40322,0x1D40322,0xFFC401E2,0xFFC401E2,0xFFC401E2,0xFFB80092,0xFFB80092,0xFFAC0001,0xC3FC0320,0xC3FC0320,0xC3FC0320,0xFFA00121,0xFFA00121,
-0xFF880000,0xE1FC0320,0xE1FC0320,0xFF080000,0xEA000320,0xC3FC0320,0xC3FC0320,0xC3FC0320,0xFFA00121,0xFFA00121,0xFF880000,0xE1FC0320,0xE1FC0320,0xFF080000,0xEA000320,0xE1FC0320,0xE1FC0320,0xFF080000,0xEA000320,0xEA000320,0xFBD002D4,0xFFCC02F2,0x1D40322,0xFFC4029A,0xFFC00225,0xFFB001BD,0xFFA80161,0xFF8C0105,0xFDCC02D4,0xFFC80288,0xDBFC0320,0xFF080000,
-0xDBFC0320,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1740622,0x1740622,0x1740622,0x1740622,0x1740622,0x1740622,0x1740622,0x1740622,0x1740622,0x1740622,0xFF500195,0xFF500195,0xFF500195,0xFF500195,0xFF500195,
-0xFF500195,0xF33C0001,0xF33C0001,0xF33C0001,0xD73C0001,0x31FC0620,0x31FC0620,0x31FC0620,0x31FC0620,0x31FC0620,0x31FC0620,0xFEE40025,0xFEE40025,0xFEE40025,0xD7080000,0x9BF80620,0x9BF80620,0x9BF80620,0xD6580000,0xBA000620,0xFF6C0521,0x1740622,0x1740622,0xFF6803F9,0xFF640322,0xFF5C024A,0xFF5C024A,0xFF4C00DA,0xF96804E2,0xFF5803E8,0xFF38002D,0xFEE40025,
-0x7FFC0620,};
-static const uint32_t g_etc1_to_bc7_m6_table190[] = {
-0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x7DF80000,
-0x7DF80000,0x7DF80000,0x7DF80000,0xA6000000,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x1640000,0x1640000,0x1640000,0x1F00000,0x5BFC0000,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x1BC0001,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,
-0x9FFC0000,0xD1F80000,0xD1F80000,0xD1F80000,0xDE000000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0x9FFC0000,0xD1F80000,0xD1F80000,0xD1F80000,0xDE000000,0xD1F80000,0xD1F80000,0xD1F80000,0xDE000000,0xDE000000,0x1DC0000,0x1BC0001,0x1BC0001,0x1FFC0000,0x63FC0000,0x89FC0000,0x89FC0000,0xB1FC0000,0x1FFC0000,0x63FC0000,0xC3FC0000,0xD1F80000,
-0xC3FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1C01434,0xFFBC11F7,0xFFB4102B,0xFFAC0F83,0xFFB00EDA,0xFFA40C47,0xFF980B46,0xFF9408C4,0xFF88078B,0xFF840622,0xFFA40E45,0xFF8C0AF2,0xFF8C0989,0xFF7C0613,0xFF700432,0xFF6801ED,0xFF64058C,0xFF58030B,0xFD4C000A,0xF54C02AD,0xA5FC1430,0xFF9410D1,0xFF880F80,0xFF700B62,0xFF640911,0xFF4C0620,0xFF4C09AB,0xFF2C05A9,0xFF080059,0xF50002AD,0xD3FC1430,
-0xFF080F80,0xFE900620,0xF40C02AC,0xE0001430,0xFFB4117B,0xF9C01344,0xF9C013BC,0xFFAC0E6E,0xFF940AD2,0xFF7C073E,0xFF7805B3,0xFF6C02C3,0xFFB4111B,0xFF980DEE,0xFF70060B,0xFF080059,0xC7FC1430,0x1E802AB,0xFDE40263,0xFFE0021B,0xFFDC0202,0xFFDC01D3,0xFFD4016E,0xFFD00132,0xFFCC00B1,0xFFC00065,0xFFBC0001,0xDFFC02AB,0xFFD80236,0xFFCC0202,0xFFB80132,0xFFAC00B9,
-0xFFA00000,0xEFFC02AB,0xFF9C0200,0xFF380000,0xF40002AC,0xDFFC02AB,0xFFD80236,0xFFCC0202,0xFFB80132,0xFFAC00B9,0xFFA00000,0xEFFC02AB,0xFF9C0200,0xFF380000,0xF40002AC,0xEFFC02AB,0xFF9C0200,0xFF380000,0xF40002AC,0xF40002AC,0xFFE4026D,0xFDE80281,0xFDE80296,0xFFDC0215,0xFFD401C2,0xFFBC0152,0xFFB800E8,0xFFA8009D,0xFFE00272,0xFFDC020E,0xFFB80204,0xFF380000,
-0xEBFC02AB,0x1AC0F83,0x1AC0F83,0x1AC0F83,0x1AC0F83,0xFF980B46,0xFF980B46,0xFF980B46,0xFF88078B,0xFF88078B,0xFF840622,0xFF8C0989,0xFF8C0989,0xFF8C0989,0xFF700432,0xFF700432,0xFF6801ED,0xFF58030B,0xFF58030B,0xFD4C0006,0xEF4C0201,0x87FC0F80,0x87FC0F80,0x87FC0F80,0xFF640911,0xFF640911,0xFF4C0620,0xFF2C05A9,0xFF2C05A9,0xFF080059,0xEF080200,0xC5F80F80,
-0xC5F80F80,0xFE900620,0xEE280200,0xD6000F80,0xFFA00D61,0xFFAC0E96,0x1AC0F83,0xFF980B42,0xFF8C08EE,0xFF7C0695,0xFF7805B3,0xFF6C02C3,0xFFA00D29,0xFF900AF9,0xFF7005FB,0xFF080059,0xB5FC0F80,0x1DC0202,0x1DC0202,0x1DC0202,0x1DC0202,0xFFD00132,0xFFD00132,0xFFD00132,0xFFC00065,0xFFC00065,0xFFBC0001,0xCFFC0200,0xCFFC0200,0xCFFC0200,0xFFAC00B9,0xFFAC00B9,
-0xFFA00000,0xE7FC0200,0xE7FC0200,0xFF380000,0xEE000200,0xCFFC0200,0xCFFC0200,0xCFFC0200,0xFFAC00B9,0xFFAC00B9,0xFFA00000,0xE7FC0200,0xE7FC0200,0xFF380000,0xEE000200,0xE7FC0200,0xE7FC0200,0xFF380000,0xEE000200,0xEE000200,0xFFD801C4,0xF7DC01E1,0x1DC0202,0xFDD801A5,0xFFC80164,0xFFBC0121,0xFFB800E8,0xFFA8009D,0xFFD001D4,0xFBD401A5,0xE1FC0200,0xFF380000,
-0xE1FC0200,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1840622,0x1840622,0x1840622,0x1840622,0x1840622,0x1840622,0x1840622,0x1840622,0x1840622,0x1840622,0xFF6801ED,0xFF6801ED,0xFF6801ED,0xFF6801ED,0xFF6801ED,
-0xFF6801ED,0xFB4C0001,0xFB4C0001,0xFB4C0001,0xDF4C0001,0x49FC0620,0x49FC0620,0x49FC0620,0x49FC0620,0x49FC0620,0x49FC0620,0xFF080059,0xFF080059,0xFF080059,0xDF180000,0xA7F80620,0xA7F80620,0xA7F80620,0xDE680000,0xC2000620,0xF980054A,0x1840622,0x1840622,0xFF740442,0xFF780372,0xFF7002B1,0xFF7002B1,0xFF5C0131,0xFF7404EA,0xFD740422,0xFF500075,0xFF080059,
-0x8FFC0620,};
-static const uint32_t g_etc1_to_bc7_m6_table191[] = {
-0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0x89F80000,
-0x89F80000,0x89F80000,0x89F80000,0xAE000000,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x3740000,0x3740000,0x3740000,0xDFC0000,0x69FC0000,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,
-0xB7FC0000,0xDDF40000,0xDDF40000,0xDDF40000,0xE6000000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xDDF40000,0xDDF40000,0xDDF40000,0xE6000000,0xDDF40000,0xDDF40000,0xDDF40000,0xE6000000,0xE6000000,0x1EC0000,0x1CC0001,0x1CC0001,0x57FC0000,0x8BFC0000,0xA7FC0000,0xA7FC0000,0xC5FC0000,0x57FC0000,0x8BFC0000,0xD3FC0000,0xDDF40000,
-0xD3FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1C810B4,0xFFC40EF4,0xFFB80DA4,0xFFB80D2B,0xFFB00CBA,0xFFB00ABF,0xFFA40A06,0xFFA00814,0xFF9C0732,0xFF940622,0xFFB00BDD,0xFF980952,0xFF980831,0xFF88058B,0xFF84041A,0xFF74025D,0xFF7C045C,0xFF700263,0xFF600005,0xF75C0181,0xB1FC10B0,0xFFA00E21,0xFF980D2C,0xFF7C0A12,0xFF700851,0xFF640620,0xFF6407F3,0xFF3804E9,0xFF2000A9,0xF7180180,0xD9FC10B0,
-0xFF280D2B,0xFEC00620,0xF6380180,0xE40010B0,0xFFBC0E86,0xFDC80FE4,0xFDC8104C,0xFFAC0C2E,0xFFA00963,0xFF90068E,0xFF900555,0xFF7402DE,0xFFB40E4B,0xFFB00BC7,0xFF7C0521,0xFF2000A9,0xCFFC10B0,0x1EC0183,0xFFE80153,0xFFE40132,0xFFE40122,0xFFE8010B,0xFFDC00CE,0xFFDC00AA,0xFFD80061,0xFFD4003A,0xFFCC0001,0xE9FC0180,0xFFE00141,0xFFD80122,0xFFCC00B1,0xFFC0006D,
-0xFFB80000,0xF3FC0180,0xFFB40120,0xFF6C0000,0xF6000180,0xE9FC0180,0xFFE00141,0xFFD80122,0xFFCC00B1,0xFFC0006D,0xFFB80000,0xF3FC0180,0xFFB40120,0xFF6C0000,0xF6000180,0xF3FC0180,0xFFB40120,0xFF6C0000,0xF6000180,0xF6000180,0xFBEC0161,0xFFEC0161,0xFFEC0172,0xFFE00143,0xFFDC00F9,0xFFD000C3,0xFFD00082,0xFFB8005A,0xF9EC0161,0xFFDC012E,0xFFD00123,0xFF6C0000,
-0xF1FC0180,0x1B80D2B,0x1B80D2B,0x1B80D2B,0x1B80D2B,0xFFA40A06,0xFFA40A06,0xFFA40A06,0xFF9C0732,0xFF9C0732,0xFF940622,0xFF980831,0xFF980831,0xFF980831,0xFF84041A,0xFF84041A,0xFF74025D,0xFF700263,0xFF700263,0xFF600005,0xF35C0121,0x95FC0D2B,0x95FC0D2B,0x95FC0D2B,0xFF700851,0xFF700851,0xFF640620,0xFF3804E9,0xFF3804E9,0xFF2000A9,0xF31C0120,0xCBFC0D2B,
-0xCBFC0D2B,0xFEC00620,0xF2480120,0xDC000D2C,0xFFAC0B7E,0xF5B80CA3,0x1B80D2B,0xFFA409EB,0xFF9407DE,0xFF900615,0xFF900555,0xFF7402DE,0xFDB00B5E,0xFF9809A5,0xFF7C0511,0xFF2000A9,0xBFF80D2B,0x1E40122,0x1E40122,0x1E40122,0x1E40122,0xFFDC00AA,0xFFDC00AA,0xFFDC00AA,0xFFD4003A,0xFFD4003A,0xFFCC0001,0xDBFC0120,0xDBFC0120,0xDBFC0120,0xFFC0006D,0xFFC0006D,
-0xFFB80000,0xEDFC0120,0xEDFC0120,0xFF6C0000,0xF2000120,0xDBFC0120,0xDBFC0120,0xDBFC0120,0xFFC0006D,0xFFC0006D,0xFFB80000,0xEDFC0120,0xEDFC0120,0xFF6C0000,0xF2000120,0xEDFC0120,0xEDFC0120,0xFF6C0000,0xF2000120,0xF2000120,0xF7E40109,0xFBE40109,0x1E40122,0xFFDC00E1,0xFFD400C1,0xFFD000AA,0xFFD00082,0xFFB8005A,0xF5E40109,0xFFDC00DD,0xE9FC0120,0xFF6C0000,
-0xE9FC0120,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1940622,0x1940622,0x1940622,0x1940622,0x1940622,0x1940622,0x1940622,0x1940622,0x1940622,0x1940622,0xFF74025D,0xFF74025D,0xFF74025D,0xFF74025D,0xFF74025D,
-0xFF74025D,0xFF600005,0xFF600005,0xFF600005,0xE75C0001,0x63FC0620,0x63FC0620,0x63FC0620,0x63FC0620,0x63FC0620,0x63FC0620,0xFF2000A9,0xFF2000A9,0xFF2000A9,0xE7280000,0xB3F80620,0xB3F80620,0xB3F80620,0xE6780000,0xCA000620,0xFF8C055A,0x1940622,0x1940622,0xFF840479,0xFF8003C5,0xFF800305,0xFF800305,0xFF700195,0xFD8C0515,0xFF80045D,0xFF6000CD,0xFF2000A9,
-0x9FF80620,};
-static const uint32_t g_etc1_to_bc7_m6_table192[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x400001,0x400001,0x400001,0x400001,0x600000,0x600000,0x600000,0xC40000,0xC40000,0x20000000,0x600000,0x600000,0x600000,0xC40000,0xC40000,0x20000000,0xC40000,0xC40000,0x20000000,0x20000000,0x600000,0x600000,0x600000,0xC40000,0xC40000,0x20000000,0xC40000,0xC40000,0x20000000,0x20000000,0xC40000,
-0xC40000,0x20000000,0x20000000,0x20000000,0x4C0000,0xA440000,0x400001,0x580000,0x26C0000,0x8C0000,0xA00000,0xF00000,0x4500000,0x600000,0x8C0000,0x20000000,0x8C0000,0xD40000,0x13C0000,0x21FC0000,0x68000001,0x13C0000,0x21FC0000,0x68000001,0x21FC0000,0x68000001,0x68000001,0x13C0000,0x21FC0000,0x68000001,0x21FC0000,0x68000001,
-0x68000001,0x21FC0000,0x68000001,0x68000001,0x68000001,0x13C0000,0x21FC0000,0x68000001,0x21FC0000,0x68000001,0x68000001,0x21FC0000,0x68000001,0x68000001,0x68000001,0x21FC0000,0x68000001,0x68000001,0x68000001,0x68000001,0x3080000,0x8E00000,0x8E00000,0x1640000,0x5FC0000,0x45F40000,0x68000001,0x68000001,0x1200000,0x18C0000,0x61D40000,0x68000001,
-0x1C00000,0x441D49,0xFE1C039A,0x981402D9,0x681402DA,0xD0000A69,0x92000112,0x68000002,0x66000A69,0x560003DA,0x44000A69,0x8A0016FD,0x7A000882,0x62000432,0x58000E66,0x520006FB,0x40000C4A,0x440016FD,0x44000E46,0x38001145,0x2E0016FE,0x681D47,0x68000DD2,0x580007C3,0x52001187,0x4C000994,0x40000E03,0x400018C6,0x3E001027,0x360012AA,0x2E0017DF,0xD01D47,
-0x380014C2,0x3200161D,0x26001A42,0x22001D47,0xFE140B92,0xF4381671,0xF8401611,0xC80006E0,0x8A000732,0x660006FD,0x5A0004DA,0x4A000929,0xF2000CF6,0x9E00098E,0x52000B32,0x360012AA,0x941D47,0x5C16FD,0xFE240289,0x94200222,0x68200222,0xD0000A69,0x92000112,0x68000002,0x66000A69,0x560003DA,0x44000A69,0x8816FD,0x7A000882,0x62000432,0x58000E66,0x520006FB,
-0x40000C4A,0x11416FD,0x44000E46,0x38001145,0x2E0016FE,0x8816FD,0x7A000882,0x62000432,0x58000E66,0x520006FB,0x40000C4A,0x11416FD,0x44000E46,0x38001145,0x2E0016FE,0x11416FD,0x44000E46,0x38001145,0x2E0016FE,0x2E0016FE,0xFE140B2E,0xFC481271,0xFE4C1121,0xC80006E0,0x8A000732,0x660006FD,0x5A0004DA,0x4A000929,0xFA000BFE,0x9E00092A,0x52000B19,0x38001145,
-0xC016FD,0x1402D9,0x1402D9,0x1402D9,0x1402D9,0x64000000,0x64000000,0x64000000,0x30000000,0x30000000,0x20000000,0x30000221,0x30000221,0x30000221,0x280000C2,0x280000C2,0x1E000068,0x18000221,0x18000221,0x16000145,0x10000221,0x2002D6,0x2002D6,0x2002D6,0x22000143,0x22000143,0x180000C0,0x1200025D,0x1200025D,0x14000185,0xE00023E,0x3C02D6,
-0x3C02D6,0x100001F2,0xE000289,0xA0002D6,0xC40000A9,0xFE0C00C1,0x1402D9,0x640000E8,0x3C0000D0,0x2E0000D0,0x2E0000A9,0x220000F5,0x64000178,0x44000138,0x1E000225,0x14000185,0x2C02D6,0x200221,0x200221,0x200221,0x200221,0x64000000,0x64000000,0x64000000,0x30000000,0x30000000,0x20000000,0x300221,0x300221,0x300221,0x280000C2,0x280000C2,
-0x1E000068,0x5C0221,0x5C0221,0x16000145,0x10000221,0x300221,0x300221,0x300221,0x280000C2,0x280000C2,0x1E000068,0x5C0221,0x5C0221,0x16000145,0x10000221,0x5C0221,0x5C0221,0x16000145,0x10000221,0x10000221,0xC40000A9,0xFE0C009D,0x200221,0x640000E8,0x3C0000D0,0x2E0000D0,0x2E0000A9,0x220000F5,0x74000151,0x4A000121,0x400221,0x16000145,
-0x400221,0x8C0A69,0xFC440001,0x8C440001,0x68400002,0xCC0A69,0x92000112,0x68000002,0x1A00A69,0x560003DA,0x44000A69,0xCC0A69,0x92000112,0x68000002,0x1A00A69,0x560003DA,0x44000A69,0x1A00A69,0x560003DA,0x44000A69,0x44000A69,0xCC0A69,0x92000112,0x68000002,0x1A00A69,0x560003DA,0x44000A69,0x1A00A69,0x560003DA,0x44000A69,0x44000A69,0x1A00A69,
-0x560003DA,0x44000A69,0x44000A69,0x44000A69,0xFE3406B2,0x940A69,0xF8800745,0xDE000385,0x96000410,0x720003D4,0x5E00028A,0x54000502,0xFE180659,0xBA000454,0x64000232,0x44000A69,0x1240A69,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table193[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x500001,0x500001,0x500001,0x500001,0x780000,0x780000,0x780000,0xF40000,0xF40000,0x28000000,0x780000,0x780000,0x780000,0xF40000,0xF40000,0x28000000,0xF40000,0xF40000,0x28000000,0x28000000,0x780000,0x780000,0x780000,0xF40000,0xF40000,0x28000000,0xF40000,0xF40000,0x28000000,0x28000000,0xF40000,
-0xF40000,0x28000000,0x28000000,0x28000000,0x600000,0x580000,0x500001,0x700000,0x880000,0xAC0000,0xC80000,0x12C0000,0x4640000,0x780000,0xAC0000,0x28000000,0xAC0000,0xE40000,0x3500000,0x2DFC0000,0x70000001,0x3500000,0x2DFC0000,0x70000001,0x2DFC0000,0x70000001,0x70000001,0x3500000,0x2DFC0000,0x70000001,0x2DFC0000,0x70000001,
-0x70000001,0x2DFC0000,0x70000001,0x70000001,0x70000001,0x3500000,0x2DFC0000,0x70000001,0x2DFC0000,0x70000001,0x70000001,0x2DFC0000,0x70000001,0x70000001,0x70000001,0x2DFC0000,0x70000001,0x70000001,0x70000001,0x70000001,0x31C0000,0xF40000,0xF40000,0x1800000,0x13F80000,0x4FF40000,0x70000001,0x70000001,0x3340000,0x1AC0000,0x69E40000,0x70000001,
-0x1E40000,0x4C21E1,0xFE2405DD,0xA21C0461,0x701C0462,0xEA000A69,0xA20000A0,0x7200000A,0x72000A69,0x60000361,0x4C000A69,0x9C001A0D,0x860009AA,0x68000506,0x68000F41,0x58000723,0x46000CCE,0x4C001A0D,0x4A001006,0x3E0012F1,0x32001A0E,0x7421DF,0x7400101A,0x62000932,0x62001345,0x52000A54,0x46000EDF,0x46001C46,0x44001257,0x3C0014AA,0x30001B22,0xE821DF,
-0x3E0017F2,0x320018ED,0x2C001E16,0x260021DF,0xFE140E42,0xF8401A29,0xFC481A39,0xDE000716,0x9A000789,0x7000072D,0x5E0004BB,0x560009B3,0xFE000ECD,0xB6000A4B,0x56000C76,0x3C0014AA,0xA421DF,0x681A0D,0xFE300425,0x9E28034A,0x7028034A,0xEA000A69,0xA20000A0,0x72040009,0x72000A69,0x60000361,0x4C000A69,0x2981A0D,0x860009AA,0x68000506,0x68000F41,0x58000723,
-0x46000CCE,0x1381A0D,0x4A001006,0x3E0012F1,0x32001A0E,0x2981A0D,0x860009AA,0x68000506,0x68000F41,0x58000723,0x46000CCE,0x1381A0D,0x4A001006,0x3E0012F1,0x32001A0E,0x1381A0D,0x4A001006,0x3E0012F1,0x32001A0E,0x32001A0E,0xFE200D73,0xFE4C1521,0xF860142A,0xDE000716,0x9A000789,0x7000072D,0x5E0004BB,0x560009B3,0xFE000DCD,0xBC0009CE,0x56000C5D,0x3E0012F1,
-0xDC1A0D,0x1C0461,0x1C0461,0x1C0461,0x1C0461,0x7C000000,0x7C000000,0x7C000000,0x3C000000,0x3C000000,0x28000000,0x3C000349,0x3C000349,0x3C000349,0x2E000132,0x2E000132,0x2200009D,0x1E000349,0x1E000349,0x1C0001F9,0x14000349,0x280461,0x280461,0x280461,0x280001FB,0x280001FB,0x22000116,0x180003A1,0x180003A1,0x1A000259,0x12000371,0x500461,
-0x500461,0x16000306,0x100003DA,0xC000462,0xF6000105,0xFE0C01B1,0x1C0461,0x7A000161,0x50000140,0x40000145,0x38000112,0x2A000172,0x82000248,0x500001DD,0x2400034D,0x1A000259,0x380461,0x280349,0x280349,0x280349,0x280349,0x7C000000,0x7C000000,0x7C000000,0x3C000000,0x3C000000,0x28000000,0x3C0349,0x3C0349,0x3C0349,0x2E000132,0x2E000132,
-0x2200009D,0x740349,0x740349,0x1C0001F9,0x14000349,0x3C0349,0x3C0349,0x3C0349,0x2E000132,0x2E000132,0x2200009D,0x740349,0x740349,0x1C0001F9,0x14000349,0x740349,0x740349,0x1C0001F9,0x14000349,0x14000349,0xF6000105,0xF4180154,0x280349,0x7A000161,0x50000140,0x40000145,0x38000112,0x2A000172,0x82000208,0x5A0001BD,0x540349,0x1C0001F9,
-0x540349,0x9C0A69,0xFE540005,0x94540001,0x70500002,0xE40A69,0xA20000A0,0x700C0001,0x1D00A69,0x60000361,0x4C000A69,0xE40A69,0xA20000A0,0x700C0001,0x1D00A69,0x60000361,0x4C000A69,0x1D00A69,0x60000361,0x4C000A69,0x4C000A69,0xE40A69,0xA20000A0,0x700C0001,0x1D00A69,0x60000361,0x4C000A69,0x1D00A69,0x60000361,0x4C000A69,0x4C000A69,0x1D00A69,
-0x60000361,0x4C000A69,0x4C000A69,0x4C000A69,0xFE5006CD,0xA40A69,0xFE8C0749,0xF4000304,0xA0000384,0x7C000335,0x66000209,0x5C000492,0xFE2C0694,0xCC0003E8,0x6E0001A8,0x4C000A69,0x1480A69,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table194[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x600001,0x600001,0x600001,0x600001,0x900000,0x900000,0x900000,0x1240000,0x1240000,0x30000000,0x900000,0x900000,0x900000,0x1240000,0x1240000,0x30000000,0x1240000,0x1240000,0x30000000,0x30000000,0x900000,0x900000,0x900000,0x1240000,0x1240000,0x30000000,0x1240000,0x1240000,0x30000000,0x30000000,0x1240000,
-0x1240000,0x30000000,0x30000000,0x30000000,0x2700000,0x680000,0x600001,0x840000,0xA40000,0xD00000,0xEC0000,0x1680000,0x4780000,0x900000,0xD00000,0x30000000,0xD00000,0xF40000,0x3680000,0x39FC0000,0x78000001,0x3680000,0x39FC0000,0x78000001,0x39FC0000,0x78000001,0x78000001,0x3680000,0x39FC0000,0x78000001,0x39FC0000,0x78000001,
-0x78000001,0x39FC0000,0x78000001,0x78000001,0x78000001,0x3680000,0x39FC0000,0x78000001,0x39FC0000,0x78000001,0x78000001,0x39FC0000,0x78000001,0x78000001,0x78000001,0x39FC0000,0x78000001,0x78000001,0x78000001,0x78000001,0x3300000,0x1040000,0x1040000,0x1980000,0x1FFC0000,0x59F40000,0x78000001,0x78000001,0x14C0000,0x1C80000,0x71F40000,0x78000001,
-0x5FC0000,0x5426F9,0xFE3008D5,0xAC200642,0x78200642,0xFE000A6D,0xAE000050,0x7A04003A,0x7E000A69,0x6C0002E9,0x54000A69,0xAC001D72,0x92000B12,0x6E000632,0x6E001055,0x62000755,0x52000D4E,0x54001D72,0x5000120E,0x440014CD,0x38001D72,0x8026F7,0x7A0012C2,0x68000B0A,0x62001515,0x5E000B3C,0x4C000FDB,0x4C00202E,0x4A0014D7,0x440016DE,0x36001EC2,0x10026F7,
-0x44001B8A,0x38001C09,0x32002262,0x2A0026F7,0xFE201173,0xFC481E61,0xFE4C1EE5,0xF4000768,0xA20007D3,0x7C000746,0x660004D2,0x60000A46,0xFE00117D,0xC6000B19,0x5E000E2A,0x440016DE,0xB426F7,0x701D75,0xFE3C0631,0xA83004B2,0x783004B2,0xFE000A6D,0xAE000050,0x7C080032,0x7E000A69,0x6C0002E9,0x54000A69,0xA81D72,0x92000B12,0x6E000632,0x6E001055,0x62000755,
-0x52000D4E,0x1581D72,0x5000120E,0x440014CD,0x38001D72,0xA81D72,0x92000B12,0x6E000632,0x6E001055,0x62000755,0x52000D4E,0x1581D72,0x5000120E,0x440014CD,0x38001D72,0x1581D72,0x5000120E,0x440014CD,0x38001D72,0x38001D72,0xFE340FF2,0xF8601819,0xFC68174A,0xF4000768,0xA20007D3,0x7C000746,0x660004D2,0x60000A46,0xFE08103E,0xC6000A89,0x5E000E06,0x440014CD,
-0xF01D72,0x200641,0x200641,0x200641,0x200641,0x94000000,0x94000000,0x94000000,0x48000000,0x48000000,0x30000000,0x480004B1,0x480004B1,0x480004B1,0x3A0001BA,0x3A0001BA,0x2E0000E5,0x220004B1,0x220004B1,0x200002E4,0x180004B1,0x300641,0x300641,0x300641,0x2E0002E3,0x2E0002E3,0x28000192,0x2200052A,0x2200052A,0x1C00035D,0x180004F1,0x5C0641,
-0x5C0641,0x1C000462,0x1400058D,0x10000642,0xF60001A5,0xF4180304,0x200641,0x900001F4,0x5E0001CD,0x480001CD,0x44000184,0x2E00022D,0x9600034E,0x720002BB,0x2C0004BA,0x1C00035D,0x400641,0x3004B1,0x3004B1,0x3004B1,0x3004B1,0x94000000,0x94000000,0x94000000,0x48000000,0x48000000,0x30000000,0x4804B1,0x4804B1,0x4804B1,0x3A0001BA,0x3A0001BA,
-0x2E0000E5,0x8C04B1,0x8C04B1,0x200002E4,0x180004B1,0x4804B1,0x4804B1,0x4804B1,0x3A0001BA,0x3A0001BA,0x2E0000E5,0x8C04B1,0x8C04B1,0x200002E4,0x180004B1,0x8C04B1,0x8C04B1,0x200002E4,0x180004B1,0x180004B1,0xF60001A5,0xF8200244,0x3004B1,0x900001F4,0x5E0001CD,0x480001CD,0x44000184,0x2E00022D,0xA40002F2,0x7200028A,0x6404B1,0x200002E4,
-0x6404B1,0xAC0A69,0xFE680012,0x9C640001,0x78600002,0xFC0A69,0xAE000050,0x781C0001,0x3F80A69,0x6C0002E9,0x54000A69,0xFC0A69,0xAE000050,0x781C0001,0x3F80A69,0x6C0002E9,0x54000A69,0x3F80A69,0x6C0002E9,0x54000A69,0x54000A69,0xFC0A69,0xAE000050,0x781C0001,0x3F80A69,0x6C0002E9,0x54000A69,0x3F80A69,0x6C0002E9,0x54000A69,0x54000A69,0x3F80A69,
-0x6C0002E9,0x54000A69,0x54000A69,0x54000A69,0xF6680708,0xB80A69,0xF8A00782,0xFC0002AD,0xB600031A,0x860002D5,0x70000195,0x6400042A,0xF44806CD,0xDE000361,0x76000128,0x54000A69,0x1680A69,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table195[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x700001,0x700001,0x700001,0x700001,0xA80000,0xA80000,0xA80000,0x1580000,0x1580000,0x38000000,0xA80000,0xA80000,0xA80000,0x1580000,0x1580000,0x38000000,0x1580000,0x1580000,0x38000000,0x38000000,0xA80000,0xA80000,0xA80000,0x1580000,0x1580000,0x38000000,0x1580000,0x1580000,0x38000000,0x38000000,0x1580000,
-0x1580000,0x38000000,0x38000000,0x38000000,0x840000,0x4780000,0x700001,0x2980000,0xC00000,0xF00000,0x1140000,0x1A40000,0x48C0000,0xA80000,0xF00000,0x38000000,0xF00000,0x1040000,0x3800000,0x45FC0000,0x80000001,0x3800000,0x45FC0000,0x80000001,0x45FC0000,0x80000001,0x80000001,0x3800000,0x45FC0000,0x80000001,0x45FC0000,0x80000001,
-0x80000001,0x45FC0000,0x80000001,0x80000001,0x80000001,0x3800000,0x45FC0000,0x80000001,0x45FC0000,0x80000001,0x80000001,0x45FC0000,0x80000001,0x80000001,0x80000001,0x45FC0000,0x80000001,0x80000001,0x80000001,0x80000001,0x3440000,0x3140000,0x3140000,0x1B40000,0x2DFC0000,0x63F40000,0x80000001,0x80000001,0x1600000,0x1E80000,0x7BC80000,0x80000001,
-0x15FC0000,0x5C2C91,0xFE300C45,0xB6280879,0x8024087A,0xFE0C0AED,0xBA000020,0x8208009A,0x8A000A69,0x72000271,0x5C000A69,0xBC00212D,0xA2000C99,0x7A000792,0x7A001185,0x680007B9,0x58000DDA,0x5C00212D,0x5600145E,0x4A0016D9,0x3E00212E,0x8C2C8F,0x860015BA,0x6E000D42,0x6E001735,0x62000C25,0x520010F7,0x5200247E,0x500017A7,0x4A00194A,0x3A0022B7,0x1182C8F,
-0x44001F8A,0x3E001F75,0x38002726,0x2E002C8F,0xFE28156D,0xFE4C2325,0xFE4C2475,0xFE00082D,0xB6000833,0x880007C9,0x740004FA,0x60000AF6,0xFE08151E,0xDA000C0E,0x6600103A,0x4A00194A,0xC82C8F,0x7C212D,0xFE4408A6,0xB238065A,0x8038065A,0xFE0C0AC9,0xBA000020,0x840C007E,0x8A000A69,0x72000271,0x5C000A69,0xB8212D,0xA2000C99,0x7A000792,0x7A001185,0x680007B9,
-0x58000DDA,0x174212D,0x5600145E,0x4A0016D9,0x3E00212E,0xB8212D,0xA2000C99,0x7A000792,0x7A001185,0x680007B9,0x58000DDA,0x174212D,0x5600145E,0x4A0016D9,0x3E00212E,0x174212D,0x5600145E,0x4A0016D9,0x3E00212E,0x3E00212E,0xFE3412F2,0xFE6C1B49,0xFE6C1AEE,0xFE00082D,0xB6000833,0x880007C9,0x740004FA,0x60000AF6,0xFE18134D,0xDA000B4A,0x66001016,0x4A0016D9,
-0x108212D,0x240879,0x240879,0x240879,0x240879,0xAC000000,0xAC000000,0xAC000000,0x54000000,0x54000000,0x38000000,0x54000659,0x54000659,0x54000659,0x40000262,0x40000262,0x34000131,0x28000659,0x28000659,0x260003E8,0x1C000659,0x380876,0x380876,0x380876,0x3A0003F3,0x3A0003F3,0x2E000226,0x220006FA,0x220006FA,0x24000491,0x1A0006AE,0x700876,
-0x700876,0x1C0005E2,0x16000776,0x12000876,0xFE0402B1,0xF61C0498,0x240879,0xAC0002B9,0x72000275,0x5600028A,0x4C000209,0x380002F2,0xB400047A,0x720003AB,0x34000662,0x24000491,0x500876,0x380659,0x380659,0x380659,0x380659,0xAC000000,0xAC000000,0xAC000000,0x54000000,0x54000000,0x38000000,0x540659,0x540659,0x540659,0x40000262,0x40000262,
-0x34000131,0xA40659,0xA40659,0x260003E8,0x1C000659,0x540659,0x540659,0x540659,0x40000262,0x40000262,0x34000131,0xA40659,0xA40659,0x260003E8,0x1C000659,0xA40659,0xA40659,0x260003E8,0x1C000659,0x1C000659,0xFA0802AD,0xFC280374,0x380659,0xAC0002B9,0x72000275,0x5600028A,0x4C000209,0x380002F2,0xC20003FA,0x7C000371,0x740659,0x260003E8,
-0x740659,0xBC0A69,0xFE78002D,0xA4740001,0x80700002,0x1140A69,0xBA000020,0x802C0001,0xFF80A69,0x72000271,0x5C000A69,0x1140A69,0xBA000020,0x802C0001,0xFF80A69,0x72000271,0x5C000A69,0xFF80A69,0x72000271,0x5C000A69,0x5C000A69,0x1140A69,0xBA000020,0x802C0001,0xFF80A69,0x72000271,0x5C000A69,0xFF80A69,0x72000271,0x5C000A69,0x5C000A69,0xFF80A69,
-0x72000271,0x5C000A69,0x5C000A69,0x5C000A69,0xFE780708,0xC80A69,0xFEAC078A,0xFE1402D4,0xC000029A,0x90000254,0x7A000131,0x720003BA,0xFC5806CD,0xF40002F2,0x820000DA,0x5C000A69,0x18C0A69,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table196[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x840000,0x840000,0x840000,0x840000,0xC40000,0xC40000,0xC40000,0x18C0000,0x18C0000,0x40000001,0xC40000,0xC40000,0xC40000,0x18C0000,0x18C0000,0x40000001,0x18C0000,0x18C0000,0x40000001,0x40000001,0xC40000,0xC40000,0xC40000,0x18C0000,0x18C0000,0x40000001,0x18C0000,0x18C0000,0x40000001,0x40000001,0x18C0000,
-0x18C0000,0x40000001,0x40000001,0x40000001,0x2980000,0x8C0000,0x840000,0xB40000,0xDC0000,0x1180000,0x1400000,0x1E80000,0xA40000,0xC40000,0x1180000,0x40000001,0x1180000,0x1140001,0x19C0000,0x53FC0000,0x8A000000,0x19C0000,0x53FC0000,0x8A000000,0x53FC0000,0x8A000000,0x8A000000,0x19C0000,0x53FC0000,0x8A000000,0x53FC0000,0x8A000000,
-0x8A000000,0x53FC0000,0x8A000000,0x8A000000,0x8A000000,0x19C0000,0x53FC0000,0x8A000000,0x53FC0000,0x8A000000,0x8A000000,0x53FC0000,0x8A000000,0x8A000000,0x8A000000,0x53FC0000,0x8A000000,0x8A000000,0x8A000000,0x8A000000,0x15C0000,0x1280000,0x1280000,0x1D40000,0x3DF80000,0x6FF00000,0x8A000000,0x8A000000,0x3780000,0x9FC0000,0x83F80000,0x8A000000,
-0x25FC0000,0x683375,0xFE3C10E1,0xC22C0B59,0x8A2C0B58,0xFE0C0C55,0xCC000002,0x8E080130,0x98000A69,0x7E0001F9,0x66000A69,0xCE0025C5,0xA8000EBB,0x86000984,0x86001301,0x74000831,0x62000E81,0x640025C5,0x5C001758,0x50001969,0x440025C6,0x983373,0x92001984,0x7A001024,0x7A0019E1,0x6E000D81,0x5E00125B,0x5E0029BE,0x5C001B19,0x50001C42,0x4000279F,0x1303373,
-0x5000247C,0x440023B5,0x38002CEA,0x32003373,0xFE341A28,0xFE4C299D,0xF8602B08,0xFE0009DD,0xC00008C1,0x92000865,0x7C000545,0x6C000BD8,0xFE081A0A,0xDE000D62,0x7400128E,0x50001C42,0xD83373,0x8825C5,0xFE500BF4,0xBE400884,0x8A400884,0xFE180BD5,0xCC000002,0x8E140104,0x98000A69,0x7E0001F9,0x66000A69,0xC825C5,0xA8000EBB,0x86000984,0x86001301,0x74000831,
-0x62000E81,0x19825C5,0x5C001758,0x50001969,0x440025C6,0xC825C5,0xA8000EBB,0x86000984,0x86001301,0x74000831,0x62000E81,0x19825C5,0x5C001758,0x50001969,0x440025C6,0x19825C5,0x5C001758,0x50001969,0x440025C6,0x440025C6,0xFE5016DA,0xFE6C1FA5,0xF8801F85,0xFE0009DD,0xC00008C1,0x92000865,0x7C000545,0x6C000BD8,0xFE24174D,0xE8000C89,0x7400125D,0x50001969,
-0x12025C5,0x2C0B58,0x2C0B58,0x2C0B58,0x2C0B58,0xC8000000,0xC8000000,0xC8000000,0x60000001,0x60000001,0x40000001,0x64000882,0x64000882,0x64000882,0x4C000335,0x4C000335,0x3A00019A,0x30000882,0x30000882,0x2C00053D,0x20000882,0x400B58,0x400B58,0x400B58,0x40000556,0x40000556,0x340002EB,0x2800095D,0x2800095D,0x2A00061E,0x1E0008EE,0x800B58,
-0x800B58,0x20000809,0x1C000A0B,0x14000B5B,0xFC0C044E,0xF82006C9,0x2C0B58,0xC200039D,0x7C000352,0x6200034D,0x5A0002D0,0x400003E8,0xC200060D,0x900004DE,0x3E000892,0x2A00061E,0x5C0B58,0x400884,0x400884,0x400884,0x400884,0xC8000000,0xC8000000,0xC8000000,0x60000001,0x60000001,0x40000001,0x600882,0x600882,0x600882,0x4C000335,0x4C000335,
-0x3A00019A,0xC40882,0xC40882,0x2C00053D,0x20000882,0x600882,0x600882,0x600882,0x4C000335,0x4C000335,0x3A00019A,0xC40882,0xC40882,0x2C00053D,0x20000882,0xC40882,0xC40882,0x2C00053D,0x20000882,0x20000882,0xFE100422,0xFE2C052D,0x400884,0xC200039D,0x7C000352,0x6200034D,0x5A0002D0,0x400003E8,0xD6000568,0x9000048D,0x8C0882,0x2C00053D,
-0x8C0882,0xCC0A69,0xFE8C0050,0xAE840000,0x8A840000,0x1300A69,0xCC000002,0x8A3C0000,0x1DF40A69,0x7E0001F9,0x66000A69,0x1300A69,0xCC000002,0x8A3C0000,0x1DF40A69,0x7E0001F9,0x66000A69,0x1DF40A69,0x7E0001F9,0x66000A69,0x66000A69,0x1300A69,0xCC000002,0x8A3C0000,0x1DF40A69,0x7E0001F9,0x66000A69,0x1DF40A69,0x7E0001F9,0x66000A69,0x66000A69,0x1DF40A69,
-0x7E0001F9,0x66000A69,0x66000A69,0x66000A69,0xFC900745,0xDC0A69,0xFAC407C1,0xFE300322,0xD6000232,0x9E0001D4,0x840000CD,0x7A000340,0xFE700708,0xFC0402AD,0x8E00007D,0x66000A69,0x1B00A69,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table197[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x180000,0x180000,0x180000,0x180000,0x180000,
-0x180000,0x2C0000,0x2C0000,0x2C0000,0x6000001,0x180000,0x180000,0x180000,0x180000,0x180000,0x180000,0x2C0000,0x2C0000,0x2C0000,0x6000001,0x2C0000,0x2C0000,0x2C0000,0x6000001,0x6000001,0x100000,0x100000,0x100000,0x4100000,0x140000,0x140000,0x140000,0x180000,0x4100000,0x140000,0x200000,0x2C0000,
-0x200000,0x940000,0x940000,0x940000,0x940000,0xDC0000,0xDC0000,0xDC0000,0x1BC0000,0x1BC0000,0x48000001,0xDC0000,0xDC0000,0xDC0000,0x1BC0000,0x1BC0000,0x48000001,0x1BC0000,0x1BC0000,0x48000001,0x48000001,0xDC0000,0xDC0000,0xDC0000,0x1BC0000,0x1BC0000,0x48000001,0x1BC0000,0x1BC0000,0x48000001,0x48000001,0x1BC0000,
-0x1BC0000,0x48000001,0x48000001,0x48000001,0xAC0000,0x69C0000,0x940000,0xC80000,0xF80000,0x1380000,0x1680000,0x9F80000,0xB80000,0xDC0000,0x1380000,0x48000001,0x1380000,0x1240001,0x1B40000,0x5FF80000,0x92000000,0x1B40000,0x5FF80000,0x92000000,0x5FF80000,0x92000000,0x92000000,0x1B40000,0x5FF80000,0x92000000,0x5FF80000,0x92000000,
-0x92000000,0x5FF80000,0x92000000,0x92000000,0x92000000,0x1B40000,0x5FF80000,0x92000000,0x5FF80000,0x92000000,0x92000000,0x5FF80000,0x92000000,0x92000000,0x92000000,0x5FF80000,0x92000000,0x92000000,0x92000000,0x92000000,0x1700000,0x5380000,0x5380000,0x3EC0000,0x49FC0000,0x79F00000,0x92000000,0x92000000,0x1900000,0x19FC0000,0x8DCC0000,0x92000000,
-0x35FC0000,0x7436D9,0xFE4413A8,0xCC380CE4,0x92380CE4,0xFE180DB5,0xD8080020,0x981001A8,0xA2080A89,0x860401D9,0x6E080A89,0xE60025C5,0xBA000D5B,0x8C0008D8,0x920011B1,0x80000671,0x68000D49,0x700025C5,0x6C001626,0x5C001831,0x4C0025C6,0xA836D7,0xA20019F4,0x800010AC,0x86001A01,0x74000CC5,0x620011B1,0x68002A9E,0x66001AB6,0x56001BC6,0x48002826,0x15836D7,
-0x560025F8,0x500024DD,0x44002EAA,0x380036D7,0xFE3C1CD5,0xFA642CB1,0xFE6C2E38,0xFE080A6B,0xD000070E,0x9E000678,0x880003A5,0x760009F9,0xFE181C4A,0xFC000B9A,0x7E00111A,0x56001BC6,0xF036D7,0x9825C5,0xFE680C84,0xC6500884,0x92500884,0xFE300C45,0xD4100002,0x96240104,0xA0100A69,0x860401D5,0x6E100A69,0xE025C5,0xBA000D5B,0x8C0008D8,0x920011B1,0x80000671,
-0x68000D49,0x1CC25C5,0x6C001626,0x5C001831,0x4C0025C6,0xE025C5,0xBA000D5B,0x8C0008D8,0x920011B1,0x80000671,0x68000D49,0x1CC25C5,0x6C001626,0x5C001831,0x4C0025C6,0x1CC25C5,0x6C001626,0x5C001831,0x4C0025C6,0x4C0025C6,0xFE581771,0xFC881FBD,0xFE8C1F95,0xFE080A5B,0xD000070E,0x9E000678,0x880003A5,0x760009F9,0xFE3417D5,0xFC000A9A,0x7E0010DA,0x5C001831,
-0x14025C5,0x380CE4,0x380CE4,0x380CE4,0x380CE4,0xD8080020,0xD8080020,0xD8080020,0x6A080021,0x6A080021,0x48080021,0x7C000882,0x7C000882,0x7C000882,0x62000271,0x62000271,0x460000EA,0x3C000882,0x3C000882,0x380004A5,0x28000882,0x500CE3,0x500CE3,0x500CE3,0x4C000576,0x4C000576,0x400002B3,0x340009D5,0x340009D5,0x320005D6,0x2800092B,0xA00CE3,
-0xA00CE3,0x260008B1,0x20000AE6,0x1A000CE3,0xFE1004E2,0xFE2C0801,0x380CE4,0xE40002E9,0x9A00028A,0x6E00029A,0x6A0001F4,0x4C000332,0xF40005C5,0xB200046A,0x4C00089B,0x320005D6,0x700CE3,0x500884,0x500884,0x500884,0x500884,0xD0100000,0xD0100000,0xD0100000,0x68100001,0x68100001,0x48100001,0x780882,0x780882,0x780882,0x62000271,0x62000271,
-0x460000EA,0xF40882,0xF40882,0x380004A5,0x28000882,0x780882,0x780882,0x780882,0x62000271,0x62000271,0x460000EA,0xF40882,0xF40882,0x380004A5,0x28000882,0xF40882,0xF40882,0x380004A5,0x28000882,0x28000882,0xFE200451,0xFA440548,0x500884,0xE40002E9,0x9A00028A,0x6E00029A,0x6A0001F4,0x4C000332,0xF40004E4,0xB20003F1,0xAC0882,0x380004A5,
-0xAC0882,0xDC0A69,0xFEA40080,0xB6940000,0x92940000,0x1480A69,0xD8080000,0x924C0000,0x27FC0A69,0x840001A5,0x6E000A69,0x1480A69,0xD8080000,0x924C0000,0x27FC0A69,0x840001A5,0x6E000A69,0x27FC0A69,0x840001A5,0x6E000A69,0x6E000A69,0x1480A69,0xD8080000,0x924C0000,0x27FC0A69,0x840001A5,0x6E000A69,0x27FC0A69,0x840001A5,0x6E000A69,0x6E000A69,0x27FC0A69,
-0x840001A5,0x6E000A69,0x6E000A69,0x6E000A69,0xFE940781,0xEC0A69,0xFECC07D9,0xFE400361,0xE00001CA,0xA8000190,0x8C000088,0x820002E4,0xF6880745,0xFE1402E4,0x9600003D,0x6E000A69,0x1D40A69,0x80020,0x80020,0x80020,0x80020,0x80020,0x80020,0x80020,0x80020,0x80020,0x80020,0x16000000,0x16000000,0x16000000,0x16000000,0x16000000,
-0x16000000,0xA000001,0xA000001,0xA000001,0x6000001,0xC0020,0xC0020,0xC0020,0xC0020,0xC0020,0xC0020,0x600000D,0x600000D,0x600000D,0x6000005,0x140020,0x140020,0x140020,0x4000012,0x2000022,0x78000000,0x80020,0x80020,0x36000000,0x24000000,0x1C000000,0x1C000000,0x12000000,0x36000009,0x24000004,0xE000001,0x600000D,
-0x100020,};
-static const uint32_t g_etc1_to_bc7_m6_table198[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x200000,0x300000,0x300000,0x300000,0x300000,0x300000,
-0x300000,0x5C0000,0x5C0000,0x5C0000,0xE000001,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x5C0000,0x5C0000,0x5C0000,0xE000001,0x5C0000,0x5C0000,0x5C0000,0xE000001,0xE000001,0x8200000,0x200000,0x200000,0x240000,0x280000,0x2C0000,0x2C0000,0x340000,0x240000,0x280000,0x400000,0x5C0000,
-0x400000,0xA40000,0xA40000,0xA40000,0xA40000,0xF40000,0xF40000,0xF40000,0x1F00000,0x1F00000,0x50000001,0xF40000,0xF40000,0xF40000,0x1F00000,0x1F00000,0x50000001,0x1F00000,0x1F00000,0x50000001,0x50000001,0xF40000,0xF40000,0xF40000,0x1F00000,0x1F00000,0x50000001,0x1F00000,0x1F00000,0x50000001,0x50000001,0x1F00000,
-0x1F00000,0x50000001,0x50000001,0x50000001,0x6BC0000,0xEAC0000,0xA40000,0x2DC0000,0x1140000,0x15C0000,0x1900000,0x15F40000,0x2CC0000,0xF40000,0x15C0000,0x50000001,0x15C0000,0x1340001,0x1CC0000,0x6BF80000,0x9A000000,0x1CC0000,0x6BF80000,0x9A000000,0x6BF80000,0x9A000000,0x9A000000,0x1CC0000,0x6BF80000,0x9A000000,0x6BF80000,0x9A000000,
-0x9A000000,0x6BF80000,0x9A000000,0x9A000000,0x9A000000,0x1CC0000,0x6BF80000,0x9A000000,0x6BF80000,0x9A000000,0x9A000000,0x6BF80000,0x9A000000,0x9A000000,0x9A000000,0x6BF80000,0x9A000000,0x9A000000,0x9A000000,0x9A000000,0x1840000,0xD480000,0xD480000,0xBFC0000,0x57FC0000,0x83F00000,0x9A000000,0x9A000000,0x3A40000,0x2BFC0000,0x95DC0000,0x9A000000,
-0x43FC0000,0x803A9D,0xFE5016F4,0xD6400EC4,0x9A400EC4,0xFE300F95,0xE4100082,0x9E1C0268,0xAA100AE9,0x900C020D,0x76100AE9,0xFE0025C5,0xCC000C2B,0x98000888,0xA2001052,0x860004F1,0x74000C51,0x7C0025C5,0x720014E2,0x66001742,0x540025C6,0xBC3A9B,0xAE001B0C,0x8C00119C,0x92001A61,0x80000C45,0x6E001179,0x74002BBE,0x6C001A56,0x60001B66,0x520028A3,0x17C3A9B,
-0x5C0027DC,0x56002631,0x4A00308E,0x3E003A9B,0xFE501FDA,0xFE6C3029,0xFE6C3258,0xFE140B8E,0xE2000578,0xAE0004FD,0x9200026A,0x8000085D,0xFE241F6E,0xFC000ADA,0x86000FF4,0x60001B66,0x10C3A9B,0xA825C5,0xFE740D24,0xCE600884,0x9A600884,0xFE440CB5,0xDC200002,0x9E340104,0xA8200A69,0x8E1401D5,0x76200A69,0xF825C5,0xCC000C2B,0x98000888,0xA2001052,0x860004F1,
-0x74000C51,0x1FC25C5,0x720014E2,0x66001742,0x540025C6,0xF825C5,0xCC000C2B,0x98000888,0xA2001052,0x860004F1,0x74000C51,0x1FC25C5,0x720014E2,0x66001742,0x540025C6,0x1FC25C5,0x720014E2,0x66001742,0x540025C6,0x540025C6,0xFC74181E,0xFE8C2035,0xF8A02004,0xFE140B2A,0xE2000578,0xAE0004FD,0x9200026A,0x8000085D,0xFE44186E,0xFC0009DA,0x86000FB4,0x66001742,
-0x16425C5,0x400EC4,0x400EC4,0x400EC4,0x400EC4,0xE8100080,0xE8100080,0xE8100080,0x74100081,0x74100081,0x50100081,0x94000882,0x94000882,0x94000882,0x680001BD,0x680001BD,0x4C00006A,0x48000882,0x48000882,0x3E00040D,0x30000882,0x600EC3,0x600EC3,0x600EC3,0x580005D6,0x580005D6,0x460002BB,0x40000A6D,0x40000A6D,0x3A0005BA,0x2E00096B,0xC40EC3,
-0xC40EC3,0x32000989,0x26000BEE,0x20000EC3,0xFE2005E1,0xF43809E0,0x400EC4,0xFA00024A,0xB20001E1,0x880001E1,0x8000015D,0x6000028A,0xFE000614,0xC40003F1,0x5C0008A6,0x3A0005BA,0x8C0EC3,0x600884,0x600884,0x600884,0x600884,0xD8200000,0xD8200000,0xD8200000,0x70200001,0x70200001,0x50200001,0x900882,0x900882,0x900882,0x680001BD,0x680001BD,
-0x4C00006A,0x1240882,0x1240882,0x3E00040D,0x30000882,0x900882,0x900882,0x900882,0x680001BD,0x680001BD,0x4C00006A,0x1240882,0x1240882,0x3E00040D,0x30000882,0x1240882,0x1240882,0x3E00040D,0x30000882,0x30000882,0xFA340480,0xFE4C0568,0x600884,0xFA00024A,0xB20001E1,0x880001E1,0x8000015D,0x6000028A,0xFE0C04E2,0xD000034D,0xD00882,0x3E00040D,
-0xD00882,0xEC0A69,0xFEB000B4,0xBEA40000,0x9AA40000,0x1600A69,0xE0180000,0x9A5C0000,0x33FC0A69,0x90000145,0x76000A69,0x1600A69,0xE0180000,0x9A5C0000,0x33FC0A69,0x90000145,0x76000A69,0x33FC0A69,0x90000145,0x76000A69,0x76000A69,0x1600A69,0xE0180000,0x9A5C0000,0x33FC0A69,0x90000145,0x76000A69,0x33FC0A69,0x90000145,0x76000A69,0x76000A69,0x33FC0A69,
-0x90000145,0x76000A69,0x76000A69,0x76000A69,0xFEB40782,0xFC0A69,0xFAE40800,0xFE5803B5,0xF6000184,0xB6000132,0x94000048,0x8A000290,0xFE980745,0xFE2C0340,0xA200001D,0x76000A69,0x1F40A69,0x100080,0x100080,0x100080,0x100080,0x100080,0x100080,0x100080,0x100080,0x100080,0x100080,0x30000000,0x30000000,0x30000000,0x30000000,0x30000000,
-0x30000000,0x16000001,0x16000001,0x16000001,0xE000001,0x180080,0x180080,0x180080,0x180080,0x180080,0x180080,0x1200002D,0x1200002D,0x1200002D,0xC000019,0x2C0080,0x2C0080,0x2C0080,0xA00004A,0x6000082,0xF8000000,0x100080,0x100080,0x6E000000,0x4C000000,0x3A000000,0x3A000000,0x26000000,0x60000028,0x42000014,0x1E000004,0x1200002D,
-0x200080,};
-static const uint32_t g_etc1_to_bc7_m6_table199[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x300000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,
-0x2440000,0x8C0000,0x8C0000,0x8C0000,0x16000001,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x2440000,0x8C0000,0x8C0000,0x8C0000,0x16000001,0x8C0000,0x8C0000,0x8C0000,0x16000001,0x16000001,0x340000,0x300000,0x300000,0x380000,0x3C0000,0x400000,0x400000,0x500000,0x380000,0x3C0000,0x640000,0x8C0000,
-0x640000,0xB40000,0xB40000,0xB40000,0xB40000,0x10C0000,0x10C0000,0x10C0000,0xBF80000,0xBF80000,0x58000001,0x10C0000,0x10C0000,0x10C0000,0xBF80000,0xBF80000,0x58000001,0xBF80000,0xBF80000,0x58000001,0x58000001,0x10C0000,0x10C0000,0x10C0000,0xBF80000,0xBF80000,0x58000001,0xBF80000,0xBF80000,0x58000001,0x58000001,0xBF80000,
-0xBF80000,0x58000001,0x58000001,0x58000001,0xD00000,0xC00000,0xB40000,0xF40000,0x32C0000,0x17C0000,0x1B80000,0x1FF80000,0x2E00000,0x10C0000,0x17C0000,0x58000001,0x17C0000,0x1440001,0x1E40000,0x77F80000,0xA2000000,0x1E40000,0x77F80000,0xA2000000,0x77F80000,0xA2000000,0xA2000000,0x1E40000,0x77F80000,0xA2000000,0x77F80000,0xA2000000,
-0xA2000000,0x77F80000,0xA2000000,0xA2000000,0xA2000000,0x1E40000,0x77F80000,0xA2000000,0x77F80000,0xA2000000,0xA2000000,0x77F80000,0xA2000000,0xA2000000,0xA2000000,0x77F80000,0xA2000000,0xA2000000,0xA2000000,0xA2000000,0x1980000,0x15C0000,0x15C0000,0x1DFC0000,0x65FC0000,0x8DF00000,0xA2000000,0xA2000000,0x1BC0000,0x3BFC0000,0x9DEC0000,0xA2000000,
-0x53FC0000,0x8C3EC1,0xFE5C1AB8,0xDE4C10F9,0xA24C10F8,0xFE3C1205,0xEC180130,0xA8240370,0xB4180B89,0x98100285,0x7E180B89,0xFE0C2621,0xE2000B28,0xA204088E,0xAE000F3A,0x92000391,0x7A000B81,0x880025C5,0x7E0013B2,0x6C00162E,0x5C0025C6,0xCC3EBF,0xBA001C84,0x9800130C,0xA2001ACB,0x8C000C25,0x74001185,0x80002CFE,0x76001A25,0x66001B26,0x5800292F,0x1A03EBF,
-0x66002A4B,0x5C0027D5,0x500032AA,0x44003EBF,0xFE582361,0xF8803495,0xFA843661,0xFE180DAD,0xF6000408,0xBC000398,0x9E000164,0x8A0006D0,0xFE342275,0xFE000B6D,0x94000EAC,0x66001B26,0x1243EBF,0xB825C5,0xFE8C0DD4,0xD6700884,0xA2700884,0xFE500D49,0xE4300002,0xA6440104,0xB0300A69,0x962401D5,0x7E300A69,0x11025C5,0xE2000B28,0xA2080884,0xAE000F3A,0x92000391,
-0x7A000B81,0xDFC25C5,0x7E0013B2,0x6C00162E,0x5C0025C6,0x11025C5,0xE2000B28,0xA2080884,0xAE000F3A,0x92000391,0x7A000B81,0xDFC25C5,0x7E0013B2,0x6C00162E,0x5C0025C6,0xDFC25C5,0x7E0013B2,0x6C00162E,0x5C0025C6,0x5C0025C6,0xFE78188A,0xFCA82039,0xFEAC2018,0xFE300C02,0xF6000408,0xBC000398,0x9E000164,0x8A0006D0,0xFE5C18B6,0xFE040A46,0x94000E5B,0x6C00162E,
-0x18825C5,0x4C10F8,0x4C10F8,0x4C10F8,0x4C10F8,0xF8180120,0xF8180120,0xF8180120,0x7E180121,0x7E180121,0x58180121,0xAC000882,0xAC000882,0xAC000882,0x7A000131,0x7A000131,0x5800001A,0x54000882,0x54000882,0x4A000385,0x38000882,0x7010F8,0x7010F8,0x7010F8,0x62000651,0x62000651,0x52000313,0x4C000B25,0x4C000B25,0x420005AE,0x340009C3,0xE410F8,
-0xE410F8,0x38000AA9,0x2C000D26,0x240010FB,0xFE2C0756,0xFA440BCC,0x4C10F8,0xFE08025A,0xC6000151,0x9A000161,0x8C0000CD,0x6A0001E2,0xFE000734,0xDA000398,0x660008AE,0x420005AE,0xA010F8,0x700884,0x700884,0x700884,0x700884,0xE0300000,0xE0300000,0xE0300000,0x78300001,0x78300001,0x58300001,0xA80882,0xA80882,0xA80882,0x7A000131,0x7A000131,
-0x5800001A,0x1580882,0x1580882,0x4A000385,0x38000882,0xA80882,0xA80882,0xA80882,0x7A000131,0x7A000131,0x5800001A,0x1580882,0x1580882,0x4A000385,0x38000882,0x1580882,0x1580882,0x4A000385,0x38000882,0x38000882,0xFE3C04A0,0xFA64057D,0x700884,0xFE08024A,0xC6000151,0x9A000161,0x8C0000CD,0x6A0001E2,0xFE140514,0xEC0002D0,0xF00882,0x4A000385,
-0xF00882,0xFC0A69,0xFEC400E9,0xC6B40000,0xA2B40000,0x1780A69,0xE8280000,0xA26C0000,0x3FFC0A69,0x9A000104,0x7E000A69,0x1780A69,0xE8280000,0xA26C0000,0x3FFC0A69,0x9A000104,0x7E000A69,0x3FFC0A69,0x9A000104,0x7E000A69,0x7E000A69,0x1780A69,0xE8280000,0xA26C0000,0x3FFC0A69,0x9A000104,0x7E000A69,0x3FFC0A69,0x9A000104,0x7E000A69,0x7E000A69,0x3FFC0A69,
-0x9A000104,0x7E000A69,0x7E000A69,0x7E000A69,0xFAC807C1,0x10C0A69,0xFEEC0820,0xFE6C03FA,0xFA040152,0xBE0000F2,0x9E000020,0x9400022D,0xFEAC0784,0xFE4C037A,0xAC000005,0x7E000A69,0xDFC0A69,0x180120,0x180120,0x180120,0x180120,0x180120,0x180120,0x180120,0x180120,0x180120,0x180120,0x48000000,0x48000000,0x48000000,0x48000000,0x48000000,
-0x48000000,0x22000000,0x22000000,0x22000000,0x16000001,0x240120,0x240120,0x240120,0x240120,0x240120,0x240120,0x1E00006D,0x1E00006D,0x1E00006D,0x1400003A,0x440120,0x440120,0x440120,0x100000AA,0xA000122,0xFC080020,0x180120,0x180120,0xA8000000,0x74000000,0x58000000,0x58000000,0x3A000000,0x84000059,0x6400002D,0x2C000009,0x1E00006D,
-0x300120,};
-static const uint32_t g_etc1_to_bc7_m6_table200[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x400001,0x600000,0x600000,0x600000,0x600000,0x600000,
-0x600000,0xC40000,0xC40000,0xC40000,0x20000000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0xC40000,0xC40000,0xC40000,0x20000000,0xC40000,0xC40000,0xC40000,0x20000000,0x20000000,0xA440000,0x400001,0x400001,0x4C0000,0x4500000,0x580000,0x580000,0x26C0000,0x4C0000,0x4500000,0x8C0000,0xC40000,
-0x8C0000,0xC40001,0xC40001,0xC40001,0xC40001,0x3240000,0x3240000,0x3240000,0x17FC0000,0x17FC0000,0x62000000,0x3240000,0x3240000,0x3240000,0x17FC0000,0x17FC0000,0x62000000,0x17FC0000,0x17FC0000,0x62000000,0x62000000,0x3240000,0x3240000,0x3240000,0x17FC0000,0x17FC0000,0x62000000,0x17FC0000,0x17FC0000,0x62000000,0x62000000,0x17FC0000,
-0x17FC0000,0x62000000,0x62000000,0x62000000,0x4E40000,0xD40000,0xC40001,0x10C0000,0x14C0000,0x1A40000,0x1E40000,0x2BF80000,0xF80000,0x3240000,0x1A40000,0x62000000,0x1A40000,0x1580000,0x3FC0000,0x85F80000,0xAA000001,0x3FC0000,0x85F80000,0xAA000001,0x85F80000,0xAA000001,0xAA000001,0x3FC0000,0x85F80000,0xAA000001,0x85F80000,0xAA000001,
-0xAA000001,0x85F80000,0xAA000001,0xAA000001,0xAA000001,0x3FC0000,0x85F80000,0xAA000001,0x85F80000,0xAA000001,0xAA000001,0x85F80000,0xAA000001,0xAA000001,0xAA000001,0x85F80000,0xAA000001,0xAA000001,0xAA000001,0xAA000001,0x1B00000,0xF6C0000,0xF6C0000,0x33FC0000,0x75F80000,0x97F80000,0xAA000001,0xAA000001,0x1D40000,0x4FFC0000,0xA7E00000,0xAA000001,
-0x63FC0000,0x9843DA,0xFE741F87,0xEA5813DA,0xAA5813DB,0xFE441546,0xF824023F,0xB43004F3,0xC0200C8A,0xA020035E,0x86200C8A,0xFE1C2759,0xEE000A1B,0xAC0C08D9,0xC0000E29,0x9E000252,0x86000AE2,0x960025C5,0x8A001275,0x7800150D,0x640025C5,0xE043DA,0xCC001E91,0xA200151E,0xA8001BBA,0x92000C52,0x800011F2,0x8C002E81,0x80001A11,0x72001AE5,0x620029D5,0x1CC43DA,
-0x6C002D36,0x66002A52,0x56003551,0x4A0043DE,0xFE6427D8,0xFE8C3942,0xFE8C3B6A,0xFE301079,0xFC000338,0xC8000260,0xA6000092,0x96000559,0xFE4426F1,0xFE040DC1,0x9E000D7F,0x72001AE5,0x14043DA,0xCC25C6,0xFE980EA3,0xDE840883,0xAA840883,0xFE680DF2,0xEE400003,0xAE540103,0xB8400A6A,0xA03801D6,0x86400A6A,0x12C25C5,0xEE000A1B,0xAA1C0883,0xC0000E29,0x9E000252,
-0x86000AE2,0x1BF825C5,0x8A001275,0x7800150D,0x640025C5,0x12C25C5,0xEE000A1B,0xAA1C0883,0xC0000E29,0x9E000252,0x86000AE2,0x1BF825C5,0x8A001275,0x7800150D,0x640025C5,0x1BF825C5,0x8A001275,0x7800150D,0x640025C5,0x640025C5,0xFE941919,0xF6BC20B2,0xFAC42082,0xFE440D24,0xFC000338,0xC8000260,0xA6000092,0x96000559,0xFE781975,0xFE240B83,0x9E000D1B,0x7800150D,
-0x1AC25C5,0x5813DA,0x5813DA,0x5813DA,0x5813DA,0xFE24022E,0xFE24022E,0xFE24022E,0x8A200221,0x8A200221,0x62200221,0xC8000882,0xC8000882,0xC8000882,0x860000B9,0x860000B9,0x62000001,0x60000884,0x60000884,0x500002FD,0x40000884,0x28013DA,0x28013DA,0x28013DA,0x7400074D,0x7400074D,0x580003BD,0x58000C13,0x58000C13,0x4C0005BE,0x40000A3D,0x10813DA,
-0x10813DA,0x3E000C45,0x32000EC8,0x2A0013DD,0xFC380952,0xFE4C0E5E,0x5813DA,0xFE100315,0xDE0000D0,0xAE0000CD,0xA2000068,0x78000164,0xFE1408DB,0xFC000344,0x7C0008C2,0x4C0005BE,0xB813DA,0x840882,0x840882,0x840882,0x840882,0xE6440001,0xE6440001,0xE6440001,0x82400001,0x82400001,0x62400001,0xC40882,0xC40882,0xC40882,0x860000B9,0x860000B9,
-0x62000001,0x18C0882,0x18C0882,0x500002FD,0x40000884,0xC40882,0xC40882,0xC40882,0x860000B9,0x860000B9,0x62000001,0x18C0882,0x18C0882,0x500002FD,0x40000884,0x18C0882,0x18C0882,0x500002FD,0x40000884,0x40000884,0xFE5804B1,0xF47805B2,0x840882,0xFE240288,0xDE0000D0,0xAE0000CD,0xA2000068,0x78000164,0xFE340515,0xFC000244,0x1180882,0x500002FD,
-0x1180882,0x1100A69,0xFEDC013D,0xCEC80001,0xAAC40002,0x1900A69,0xF03C0000,0xAA800001,0x4DFC0A69,0xA40000C1,0x86000A69,0x1900A69,0xF03C0000,0xAA800001,0x4DFC0A69,0xA40000C1,0x86000A69,0x4DFC0A69,0xA40000C1,0x86000A69,0x86000A69,0x1900A69,0xF03C0000,0xAA800001,0x4DFC0A69,0xA40000C1,0x86000A69,0x4DFC0A69,0xA40000C1,0x86000A69,0x86000A69,0x4DFC0A69,
-0xA40000C1,0x86000A69,0x86000A69,0x86000A69,0xFED007FD,0x1200A69,0xFD080841,0xFE940451,0xFE100172,0xD00000A9,0xA800000A,0x9C0001E1,0xF6CC07C1,0xFE6403E8,0xB6080000,0x86000A69,0x1FF80A69,0x200221,0x200221,0x200221,0x200221,0x200221,0x200221,0x200221,0x200221,0x200221,0x200221,0x64000000,0x64000000,0x64000000,0x64000000,0x64000000,
-0x64000000,0x30000000,0x30000000,0x30000000,0x20000000,0x300221,0x300221,0x300221,0x300221,0x300221,0x300221,0x280000C2,0x280000C2,0x280000C2,0x1E000068,0x5C0221,0x5C0221,0x5C0221,0x16000145,0x10000221,0xFE0C009D,0x200221,0x200221,0xE8000000,0xA0000000,0x7A000000,0x7A000000,0x50000000,0xC40000A9,0x96000055,0x3E000010,0x280000C2,
-0x400221,};
-static const uint32_t g_etc1_to_bc7_m6_table201[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x500001,0x780000,0x780000,0x780000,0x780000,0x780000,
-0x780000,0xF40000,0xF40000,0xF40000,0x28000000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0xF40000,0xF40000,0xF40000,0x28000000,0xF40000,0xF40000,0xF40000,0x28000000,0x28000000,0x580000,0x500001,0x500001,0x600000,0x4640000,0x700000,0x700000,0x880000,0x600000,0x4640000,0xAC0000,0xF40000,
-0xAC0000,0xD40001,0xD40001,0xD40001,0xD40001,0x33C0000,0x33C0000,0x33C0000,0x23FC0000,0x23FC0000,0x6A000000,0x33C0000,0x33C0000,0x33C0000,0x23FC0000,0x23FC0000,0x6A000000,0x23FC0000,0x23FC0000,0x6A000000,0x6A000000,0x33C0000,0x33C0000,0x33C0000,0x23FC0000,0x23FC0000,0x6A000000,0x23FC0000,0x23FC0000,0x6A000000,0x6A000000,0x23FC0000,
-0x23FC0000,0x6A000000,0x6A000000,0x6A000000,0xF80000,0xE40000,0xD40001,0x1240000,0x1680000,0x1C80000,0x7F80000,0x37F40000,0x10C0000,0x33C0000,0x1C80000,0x6A000000,0x1C80000,0x1680000,0x1BFC0000,0x91F80000,0xB2000001,0x1BFC0000,0x91F80000,0xB2000001,0x91F80000,0xB2000001,0xB2000001,0x1BFC0000,0x91F80000,0xB2000001,0x91F80000,0xB2000001,
-0xB2000001,0x91F80000,0xB2000001,0xB2000001,0xB2000001,0x1BFC0000,0x91F80000,0xB2000001,0x91F80000,0xB2000001,0xB2000001,0x91F80000,0xB2000001,0xB2000001,0xB2000001,0x91F80000,0xB2000001,0xB2000001,0xB2000001,0xB2000001,0x1C40000,0x1800000,0x1800000,0x47FC0000,0x81FC0000,0xA1FC0000,0xB2000001,0xB2000001,0x3E80000,0x61FC0000,0xAFF00000,0xB2000001,
-0x73FC0000,0xA448CA,0xFE802443,0xF26416C6,0xB26416C7,0xFE5018EA,0xFE300393,0xBA3C069F,0xCA280DB2,0xA824045E,0x8E280DB2,0xFE30290A,0xFA00097B,0xB6140951,0xCC000D49,0xA800016E,0x8E000A8D,0xA20025C6,0x9000116D,0x7E001419,0x6C0025C5,0xF448CA,0xE20020BF,0xAE00178E,0xB4001CE2,0xA2000CB3,0x86001292,0x98003001,0x8A001A29,0x7A001AD5,0x68002A81,0x1F048CA,
-0x7800301E,0x6C002C86,0x5C0037E9,0x500048CE,0xFE782C61,0xFE8C3E62,0xF8A040BB,0xFE401395,0xFE0403A8,0xD6000182,0xB0000031,0xA0000422,0xFE542B17,0xFE1810AE,0xA6000CB9,0x7A001AD5,0x15C48CA,0xDC25C6,0xFEB00F63,0xE6940883,0xB2940883,0xFE800E9A,0xF6500003,0xB6640103,0xC0500A6A,0xA84801D6,0x8E500A6A,0x14425C5,0xFA00097B,0xB22C0883,0xCC000D49,0xA800016E,
-0x8E000A8D,0x27F825C5,0x9000116D,0x7E001419,0x6C0025C5,0x14425C5,0xFA00097B,0xB22C0883,0xCC000D49,0xA800016E,0x8E000A8D,0x27F825C5,0x9000116D,0x7E001419,0x6C0025C5,0x27F825C5,0x9000116D,0x7E001419,0x6C0025C5,0x6C0025C5,0xFEA019C8,0xFECC20B2,0xFECC20B2,0xFE5C0DFE,0xFE100393,0xD6000182,0xB0000031,0xA0000422,0xFE8819FE,0xFE400C4D,0xAC000C4E,0x7E001419,
-0x1D025C5,0x6416C6,0x6416C6,0x6416C6,0x6416C6,0xFE300392,0xFE300392,0xFE300392,0x94280349,0x94280349,0x6A280349,0xE0000882,0xE0000882,0xE0000882,0x98000061,0x98000061,0x6C040018,0x6C000884,0x6C000884,0x5C00027D,0x48000884,0x9016C5,0x9016C5,0x9016C5,0x80000875,0x80000875,0x62000491,0x62000CE4,0x62000CE4,0x540005F4,0x46000AA5,0x12416C5,
-0x12416C5,0x44000E01,0x3E001058,0x300016C5,0xFE3C0B76,0xF458115D,0x6416C6,0xFE18042D,0xFC000074,0xC0000074,0xAE000022,0x840000FA,0xFE200AF6,0xFE00038A,0x860008CA,0x540005F4,0xD016C5,0x940882,0x940882,0x940882,0x940882,0xEE540001,0xEE540001,0xEE540001,0x8A500001,0x8A500001,0x6A500001,0xDC0882,0xDC0882,0xDC0882,0x98000061,0x98000061,
-0x6A100001,0x1BC0882,0x1BC0882,0x5C00027D,0x48000884,0xDC0882,0xDC0882,0xDC0882,0x98000061,0x98000061,0x6A100001,0x1BC0882,0x1BC0882,0x5C00027D,0x48000884,0x1BC0882,0x1BC0882,0x5C00027D,0x48000884,0x48000884,0xFA6C04E2,0xFC8805B2,0x940882,0xFE3402B1,0xFC000074,0xC0000074,0xAE000022,0x840000FA,0xFA48054A,0xFC140265,0x1380882,0x5C00027D,
-0x1380882,0x1200A69,0xFEE80195,0xD6D80001,0xB2D40002,0x1A80A69,0xF84C0000,0xB2900001,0x59FC0A69,0xAC000082,0x8E000A69,0x1A80A69,0xF84C0000,0xB2900001,0x59FC0A69,0xAC000082,0x8E000A69,0x59FC0A69,0xAC000082,0x8E000A69,0x8E000A69,0x1A80A69,0xF84C0000,0xB2900001,0x59FC0A69,0xAC000082,0x8E000A69,0x59FC0A69,0xAC000082,0x8E000A69,0x8E000A69,0x59FC0A69,
-0xAC000082,0x8E000A69,0x8E000A69,0x8E000A69,0xFAF00802,0x1300A69,0xFF0C087D,0xFEAC04B1,0xFE3C01C4,0xDA00006A,0xB2040001,0xA800019A,0xFEDC07C1,0xFE880424,0xBE180000,0x8E000A69,0x2DFC0A69,0x280349,0x280349,0x280349,0x280349,0x280349,0x280349,0x280349,0x280349,0x280349,0x280349,0x7C000000,0x7C000000,0x7C000000,0x7C000000,0x7C000000,
-0x7C000000,0x3C000000,0x3C000000,0x3C000000,0x28000000,0x3C0349,0x3C0349,0x3C0349,0x3C0349,0x3C0349,0x3C0349,0x2E000132,0x2E000132,0x2E000132,0x2200009D,0x740349,0x740349,0x740349,0x1C0001F9,0x14000349,0xF4180154,0x280349,0x280349,0xFE04000D,0xC8000000,0x98000000,0x98000000,0x64000000,0xF6000105,0xB4000089,0x46000019,0x2E000132,
-0x540349,};
-static const uint32_t g_etc1_to_bc7_m6_table202[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x600001,0x900000,0x900000,0x900000,0x900000,0x900000,
-0x900000,0x1240000,0x1240000,0x1240000,0x30000000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x1240000,0x1240000,0x1240000,0x30000000,0x1240000,0x1240000,0x1240000,0x30000000,0x30000000,0x680000,0x600001,0x600001,0x2700000,0x4780000,0x840000,0x840000,0xA40000,0x2700000,0x4780000,0xD00000,0x1240000,
-0xD00000,0xE40001,0xE40001,0xE40001,0xE40001,0x1540000,0x1540000,0x1540000,0x2FFC0000,0x2FFC0000,0x72000000,0x1540000,0x1540000,0x1540000,0x2FFC0000,0x2FFC0000,0x72000000,0x2FFC0000,0x2FFC0000,0x72000000,0x72000000,0x1540000,0x1540000,0x1540000,0x2FFC0000,0x2FFC0000,0x72000000,0x2FFC0000,0x2FFC0000,0x72000000,0x72000000,0x2FFC0000,
-0x2FFC0000,0x72000000,0x72000000,0x72000000,0x10C0000,0x2F40000,0xE40001,0x1380000,0x3800000,0x1E80000,0x15F80000,0x41F80000,0x1200000,0x1540000,0x1E80000,0x72000000,0x1E80000,0x1780000,0x35FC0000,0x9DF40000,0xBA000001,0x35FC0000,0x9DF40000,0xBA000001,0x9DF40000,0xBA000001,0xBA000001,0x35FC0000,0x9DF40000,0xBA000001,0x9DF40000,0xBA000001,
-0xBA000001,0x9DF40000,0xBA000001,0xBA000001,0xBA000001,0x35FC0000,0x9DF40000,0xBA000001,0x9DF40000,0xBA000001,0xBA000001,0x9DF40000,0xBA000001,0xBA000001,0xBA000001,0x9DF40000,0xBA000001,0xBA000001,0xBA000001,0xBA000001,0x1D80000,0x1900000,0x1900000,0x5BFC0000,0x8FFC0000,0xABFC0000,0xBA000001,0xBA000001,0x5FC0000,0x71FC0000,0xB9C40000,0xBA000001,
-0x81FC0000,0xB04E1A,0xFE8C2977,0xFC6C1A06,0xBA6C1A07,0xFE5C1D1E,0xFE3C0597,0xC24408A6,0xD4300F1A,0xB22C059E,0x96300F1A,0xFE3C2B5E,0xFE080993,0xC01C0A01,0xD8000C89,0xB40000C6,0x96000A6A,0xAE0025C6,0x9C001065,0x8A001331,0x740025C5,0x1044E1A,0xE800231B,0xB4001A6E,0xC0001E4A,0xA8000D5F,0x8C001392,0xA200315F,0x92001A55,0x82001ADB,0x6E002B4D,0x7FC4E1A,
-0x7E003356,0x72002F0A,0x66003AC6,0x56004E1E,0xFE803152,0xFAA443AA,0xFEAC45DF,0xFE441768,0xFE100503,0xE20000CE,0xBC00000B,0xAA00032A,0xFE5C2FFA,0xFE241464,0xB6000BBD,0x82001ADB,0x1744E1A,0xEC25C6,0xFEC41026,0xEEA40883,0xBAA40883,0xFE980F62,0xFE600003,0xBE740103,0xC8600A6A,0xB05801D6,0x96600A6A,0x15C25C5,0xFE080983,0xBA3C0883,0xD8000C89,0xB40000C6,
-0x96000A6A,0x33F825C5,0x9C001065,0x8A001331,0x740025C5,0x15C25C5,0xFE080983,0xBA3C0883,0xD8000C89,0xB40000C6,0x96000A6A,0x33F825C5,0x9C001065,0x8A001331,0x740025C5,0x33F825C5,0x9C001065,0x8A001331,0x740025C5,0x740025C5,0xFEB41A2D,0xF8E0212E,0xFAE42103,0xFE780F0E,0xFE24046B,0xE20000CE,0xBC00000B,0xAA00032A,0xFE981A99,0xFE480D53,0xB6000B44,0x8A001331,
-0x1F025C5,0x6C1A06,0x6C1A06,0x6C1A06,0x6C1A06,0xFE3C0566,0xFE3C0566,0xFE3C0566,0x9E3004B1,0x9E3004B1,0x723004B1,0xF8000882,0xF8000882,0xF8000882,0xA8000025,0xA8000025,0x76080051,0x78000884,0x78000884,0x66000220,0x50000884,0xA41A05,0xA41A05,0xA41A05,0x8C0009DD,0x8C0009DD,0x680005C9,0x6E000DF4,0x6E000DF4,0x5E000632,0x4C000B25,0x14C1A05,
-0x14C1A05,0x50001001,0x44001218,0x36001A05,0xFE4C0DF1,0xFA641455,0x6C1A06,0xFE2C05C9,0xFE040078,0xD200003A,0xC0000004,0x960000A0,0xFC300D65,0xFE0004CA,0x960008DB,0x5E000632,0xE81A05,0xA40882,0xA40882,0xA40882,0xA40882,0xF6640001,0xF6640001,0xF6640001,0x92600001,0x92600001,0x72600001,0xF40882,0xF40882,0xF40882,0xA8000025,0xA8000025,
-0x72200001,0x1F00882,0x1F00882,0x66000220,0x50000884,0xF40882,0xF40882,0xF40882,0xA8000025,0xA8000025,0x72200001,0x1F00882,0x1F00882,0x66000220,0x50000884,0x1F00882,0x1F00882,0x66000220,0x50000884,0x50000884,0xFE740502,0xF49805E9,0xA40882,0xFE4402E4,0xFE040074,0xD200003A,0xC0000004,0x960000A0,0xFE50057A,0xFE24028A,0x15C0882,0x66000220,
-0x15C0882,0x1300A69,0xFF0001ED,0xDEE80001,0xBAE40002,0x1C00A69,0xFE600002,0xBAA00001,0x65F80A69,0xB6000059,0x96000A69,0x1C00A69,0xFE600002,0xBAA00001,0x65F80A69,0xB6000059,0x96000A69,0x65F80A69,0xB6000059,0x96000A69,0x96000A69,0x1C00A69,0xFE600002,0xBAA00001,0x65F80A69,0xB6000059,0x96000A69,0x65F80A69,0xB6000059,0x96000A69,0x96000A69,0x65F80A69,
-0xB6000059,0x96000A69,0x96000A69,0x96000A69,0xFEF80832,0x1440A69,0xFD280882,0xFEC004EA,0xFE500220,0xE6000050,0xBA140001,0xB2000151,0xFEF00800,0xFEA00488,0xC6280000,0x96000A69,0x3DF80A69,0x3004B1,0x3004B1,0x3004B1,0x3004B1,0x3004B1,0x3004B1,0x3004B1,0x3004B1,0x3004B1,0x3004B1,0x94000000,0x94000000,0x94000000,0x94000000,0x94000000,
-0x94000000,0x48000000,0x48000000,0x48000000,0x30000000,0x4804B1,0x4804B1,0x4804B1,0x4804B1,0x4804B1,0x4804B1,0x3A0001BA,0x3A0001BA,0x3A0001BA,0x2E0000E5,0x8C04B1,0x8C04B1,0x8C04B1,0x200002E4,0x180004B1,0xF8200244,0x3004B1,0x3004B1,0xFC0C0064,0xEE000000,0xB6000000,0xB6000000,0x78000000,0xF60001A5,0xD60000C2,0x56000022,0x3A0001BA,
-0x6404B1,};
-static const uint32_t g_etc1_to_bc7_m6_table203[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0x700001,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,
-0xA80000,0x1580000,0x1580000,0x1580000,0x38000000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0xA80000,0x1580000,0x1580000,0x1580000,0x38000000,0x1580000,0x1580000,0x1580000,0x38000000,0x38000000,0x4780000,0x700001,0x700001,0x840000,0x48C0000,0x2980000,0x2980000,0xC00000,0x840000,0x48C0000,0xF00000,0x1580000,
-0xF00000,0xF40001,0xF40001,0xF40001,0xF40001,0x16C0000,0x16C0000,0x16C0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x16C0000,0x16C0000,0x16C0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x3BFC0000,0x3BFC0000,0x7A000000,0x7A000000,0x16C0000,0x16C0000,0x16C0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x3BFC0000,0x3BFC0000,0x7A000000,0x7A000000,0x3BFC0000,
-0x3BFC0000,0x7A000000,0x7A000000,0x7A000000,0x51C0000,0xB040000,0xF40001,0x34C0000,0x19C0000,0x7FC0000,0x21FC0000,0x4BFC0000,0x1340000,0x16C0000,0x7FC0000,0x7A000000,0x7FC0000,0x1880000,0x4DFC0000,0xA7FC0000,0xC2000001,0x4DFC0000,0xA7FC0000,0xC2000001,0xA7FC0000,0xC2000001,0xC2000001,0x4DFC0000,0xA7FC0000,0xC2000001,0xA7FC0000,0xC2000001,
-0xC2000001,0xA7FC0000,0xC2000001,0xC2000001,0xC2000001,0x4DFC0000,0xA7FC0000,0xC2000001,0xA7FC0000,0xC2000001,0xC2000001,0xA7FC0000,0xC2000001,0xC2000001,0xC2000001,0xA7FC0000,0xC2000001,0xC2000001,0xC2000001,0xC2000001,0x1EC0000,0x9A00000,0x9A00000,0x6FFC0000,0x9DF80000,0xB5FC0000,0xC2000001,0xC2000001,0x23FC0000,0x83FC0000,0xC1D40000,0xC2000001,
-0x91FC0000,0xBC53CA,0xFE982F23,0xFE781DB3,0xC2781D9B,0xFE6821E2,0xFE480853,0xCC4C0AE2,0xDE3810C2,0xBA34072F,0x9E3810C2,0xFE442E39,0xFE140A9F,0xCA240AE9,0xE2000BDE,0xBE000056,0x9E040A76,0xBA0025C6,0xA6000F93,0x9000124D,0x7C0025C5,0x11853CA,0xF400260B,0xC0001DBE,0xCC001FF2,0xB4000E7F,0x980014B2,0xA8003317,0x9E001AAD,0x8C001AFD,0x7A002C15,0x11F853CA,
-0x840036F6,0x780031DE,0x6C003DB6,0x5C0053CE,0xFE8C36AE,0xFEAC491A,0xFEAC4BCF,0xFE541B8E,0xFE24073F,0xEE000058,0xC6080023,0xB6000243,0xFE703553,0xFE301879,0xBE000B25,0x8C001AFD,0x19053CA,0xFC25C6,0xFED010EE,0xF6B40883,0xC2B40883,0xFEA41022,0xFE780023,0xC6840103,0xD0700A6A,0xB86801D6,0x9E700A6A,0x17425C5,0xFE200A0B,0xC24C0883,0xE2000BDE,0xBE000056,
-0x9E0C0A6A,0x3FF825C5,0xA6000F93,0x9000124D,0x7C0025C5,0x17425C5,0xFE200A0B,0xC24C0883,0xE2000BDE,0xBE000056,0x9E0C0A6A,0x3FF825C5,0xA6000F93,0x9000124D,0x7C0025C5,0x3FF825C5,0xA6000F93,0x9000124D,0x7C0025C5,0x7C0025C5,0xFED01ACD,0xFEEC2132,0xFEEC213B,0xFE940FE5,0xFE38056B,0xEE000058,0xC410000B,0xB6000243,0xFEB41B45,0xFE680E81,0xBE000A95,0x9000124D,
-0xBFC25C5,0x781D9A,0x781D9A,0x781D9A,0x781D9A,0xFE440795,0xFE440795,0xFE440795,0xA8380659,0xA8380659,0x7A380659,0xFE0C08AE,0xFE0C08AE,0xFE0C08AE,0xB4000005,0xB4000005,0x7E0C00AD,0x84000884,0x84000884,0x6C0001C4,0x58000884,0x2B01D9A,0x2B01D9A,0x2B01D9A,0x98000B85,0x98000B85,0x74000731,0x74000F18,0x74000F18,0x6800068C,0x52000BBD,0x1681D9A,
-0x1681D9A,0x56001235,0x4A001408,0x3A001D9D,0xFE5810F1,0xFE6C17AD,0x781D9A,0xFE3407B5,0xFE140116,0xE200000D,0xD0000002,0xA0000059,0xFE341005,0xFE100696,0xA60008E8,0x6800068C,0xFC1D9A,0xB40882,0xB40882,0xB40882,0xB40882,0xFE740001,0xFE740001,0xFE740001,0x9A700001,0x9A700001,0x7A700001,0x10C0882,0x10C0882,0x10C0882,0xB4000005,0xB4000005,
-0x7A300001,0xBF80882,0xBF80882,0x6C0001C4,0x58000884,0x10C0882,0x10C0882,0x10C0882,0xB4000005,0xB4000005,0x7A300001,0xBF80882,0xBF80882,0x6C0001C4,0x58000884,0xBF80882,0xBF80882,0x6C0001C4,0x58000884,0x58000884,0xFE900515,0xFCA805E9,0xB40882,0xFE5C02FD,0xFE1C009D,0xE200000D,0xCC080000,0xA0000059,0xFA70057D,0xFA4002D2,0x17C0882,0x6C0001C4,
-0x17C0882,0x1400A69,0xFF0C025D,0xE6F80001,0xC2F40002,0x1D80A69,0xFE7C0014,0xC2B00001,0x71F80A69,0xBE000032,0x9E000A69,0x1D80A69,0xFE7C0014,0xC2B00001,0x71F80A69,0xBE000032,0x9E000A69,0x71F80A69,0xBE000032,0x9E000A69,0x9E000A69,0x1D80A69,0xFE7C0014,0xC2B00001,0x71F80A69,0xBE000032,0x9E000A69,0x71F80A69,0xBE000032,0x9E000A69,0x9E000A69,0x71F80A69,
-0xBE000032,0x9E000A69,0x9E000A69,0x9E000A69,0xFF140845,0x1540A69,0xF53808C5,0xFED80550,0xFE68028A,0xF2000028,0xC2240001,0xBA000115,0xF7080841,0xFEC004E2,0xCE380000,0x9E000A69,0x4BFC0A69,0x380659,0x380659,0x380659,0x380659,0x380659,0x380659,0x380659,0x380659,0x380659,0x380659,0xAC000000,0xAC000000,0xAC000000,0xAC000000,0xAC000000,
-0xAC000000,0x54000000,0x54000000,0x54000000,0x38000000,0x540659,0x540659,0x540659,0x540659,0x540659,0x540659,0x40000262,0x40000262,0x40000262,0x34000131,0xA40659,0xA40659,0xA40659,0x260003E8,0x1C000659,0xFC280374,0x380659,0x380659,0xFE100104,0xFA040014,0xD4000000,0xD4000000,0x8C000000,0xFA0802AD,0xF4000112,0x66000028,0x40000262,
-0x740659,};
-static const uint32_t g_etc1_to_bc7_m6_table204[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0x840000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,
-0xC40000,0x18C0000,0x18C0000,0x18C0000,0x40000001,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0xC40000,0x18C0000,0x18C0000,0x18C0000,0x40000001,0x18C0000,0x18C0000,0x18C0000,0x40000001,0x40000001,0x8C0000,0x840000,0x840000,0x2980000,0xA40000,0xB40000,0xB40000,0xDC0000,0x2980000,0xA40000,0x1180000,0x18C0000,
-0x1180000,0x1080000,0x1080000,0x1080000,0x1080000,0x1880000,0x1880000,0x1880000,0x49F80000,0x49F80000,0x82000001,0x1880000,0x1880000,0x1880000,0x49F80000,0x49F80000,0x82000001,0x49F80000,0x49F80000,0x82000001,0x82000001,0x1880000,0x1880000,0x1880000,0x49F80000,0x49F80000,0x82000001,0x49F80000,0x49F80000,0x82000001,0x82000001,0x49F80000,
-0x49F80000,0x82000001,0x82000001,0x82000001,0x1340000,0x5180000,0x1080000,0x1680000,0x1BC0000,0x19FC0000,0x31FC0000,0x59F40000,0x14C0000,0x1880000,0x19FC0000,0x82000001,0x19FC0000,0x1980001,0x69FC0000,0xB5FC0000,0xCC000000,0x69FC0000,0xB5FC0000,0xCC000000,0xB5FC0000,0xCC000000,0xCC000000,0x69FC0000,0xB5FC0000,0xCC000000,0xB5FC0000,0xCC000000,
-0xCC000000,0xB5FC0000,0xCC000000,0xCC000000,0xCC000000,0x69FC0000,0xB5FC0000,0xCC000000,0xB5FC0000,0xCC000000,0xCC000000,0xB5FC0000,0xCC000000,0xCC000000,0xCC000000,0xB5FC0000,0xCC000000,0xCC000000,0xCC000000,0xCC000000,0xBFC0000,0x3B40000,0x3B40000,0x85FC0000,0xABFC0000,0xC1F40000,0xCC000000,0xCC000000,0x45FC0000,0x95FC0000,0xCBC80000,0xCC000000,
-0xA1FC0000,0xC85AA5,0xFEA4360C,0xFE88228D,0xCC842208,0xFE8027E1,0xFE540C44,0xD8580DC5,0xE84412ED,0xC43C0938,0xA84012ED,0xFE503266,0xFE200CC4,0xD6240C2A,0xF4000B45,0xCA000015,0xAA080AB6,0xC60025C5,0xB2000E98,0x9C001162,0x860025C6,0x12C5AA3,0xFA002A18,0xCC00220B,0xE20021ED,0xBA00100A,0xA2001647,0xBA00351E,0xA8001B25,0x92001B46,0x80002CFE,0x1BF85AA3,
-0x90003B5B,0x84003543,0x7200414F,0x64005AA3,0xFEA03D3B,0xF8C05071,0xFAC452C9,0xFE6C216E,0xFE280A9E,0xFC00000E,0xD00C0071,0xC0000184,0xFE783BC2,0xFE441DA3,0xCE000A96,0x92001B46,0x1AC5AA3,0x10C25C5,0xFEE811FD,0xFEC80885,0xCCC40884,0xFEBC1115,0xFE880086,0xD0980104,0xDA840A69,0xC07801D5,0xA8840A69,0x38C25C5,0xFE380AD4,0xCC5C0884,0xF4000B45,0xCA000015,
-0xA8200A69,0x4BFC25C5,0xB2000E98,0x9C001162,0x860025C6,0x38C25C5,0xFE380AD4,0xCC5C0884,0xF4000B45,0xCA000015,0xA8200A69,0x4BFC25C5,0xB2000E98,0x9C001162,0x860025C6,0x4BFC25C5,0xB2000E98,0x9C001162,0x860025C6,0x860025C6,0xFEE41BB9,0xF90021AD,0xFD082185,0xFE981149,0xFE5C06AE,0xFC00000E,0xCE24000C,0xC0000184,0xFEC41BE9,0xFE840F78,0xCE0009ED,0x9C001162,
-0x1DF825C5,0x842208,0x842208,0x842208,0x842208,0xFE500A9D,0xFE500A9D,0xFE500A9D,0xB4400884,0xB4400884,0x82400885,0xFE180974,0xFE180974,0xFE180974,0xC4000001,0xC4000001,0x88140141,0x92000882,0x92000882,0x7800015A,0x62000882,0xC42208,0xC42208,0xC42208,0xA2000D86,0xA2000D86,0x8000092D,0x80001086,0x80001086,0x6E00071A,0x5E000C63,0x18C2208,
-0x18C2208,0x5C001505,0x5000166E,0x4000220B,0xFE6814BA,0xF67C1C38,0x842208,0xFE440A76,0xFE1C025D,0xF8000000,0xDE04001E,0xAE000022,0xFE3C13E0,0xFE180932,0xB6000903,0x6E00071A,0x1182208,0xC40884,0xC40884,0xC40884,0xC40884,0xFC88000D,0xFC88000D,0xFC88000D,0xA2840001,0xA2840001,0x82840001,0x3240882,0x3240882,0x3240882,0xC0080001,0xC0080001,
-0x82440001,0x17FC0882,0x17FC0882,0x7800015A,0x62000882,0x3240882,0x3240882,0x3240882,0xC0080001,0xC0080001,0x82440001,0x17FC0882,0x17FC0882,0x7800015A,0x62000882,0x17FC0882,0x17FC0882,0x7800015A,0x62000882,0x62000882,0xFEA0054A,0xF6BC0620,0xC40884,0xFE780349,0xFC3C00CA,0xF8000000,0xD21C0001,0xAE000022,0xF88805B2,0xFC5802F9,0x1A40882,0x7800015A,
-0x1A40882,0x1500A69,0xFF2402D5,0xF1080000,0xCD080000,0x1F40A69,0xFEA0004A,0xCCC00000,0x7FF80A69,0xCA000014,0xA8000A69,0x1F40A69,0xFEA0004A,0xCCC00000,0x7FF80A69,0xCA000014,0xA8000A69,0x7FF80A69,0xCA000014,0xA8000A69,0xA8000A69,0x1F40A69,0xFEA0004A,0xCCC00000,0x7FF80A69,0xCA000014,0xA8000A69,0x7FF80A69,0xCA000014,0xA8000A69,0xA8000A69,0x7FF80A69,
-0xCA000014,0xA8000A69,0xA8000A69,0xA8000A69,0xFB2C0884,0x1680A69,0xFF4C08C5,0xFEEC05A5,0xFE900304,0xFC00000D,0xCC340000,0xC20000DD,0xFF180845,0xFED80550,0xD64C0001,0xA8000A69,0x5DF80A69,0x400884,0x400884,0x400884,0x400884,0x400884,0x400884,0x400884,0x400884,0x400884,0x400884,0xC8000000,0xC8000000,0xC8000000,0xC8000000,0xC8000000,
-0xC8000000,0x60000001,0x60000001,0x60000001,0x40000001,0x600882,0x600882,0x600882,0x600882,0x600882,0x600882,0x4C000335,0x4C000335,0x4C000335,0x3A00019A,0xC40882,0xC40882,0xC40882,0x2C00053D,0x20000882,0xFE2C052D,0x400884,0x400884,0xFE200200,0xFE0C0075,0xF6000000,0xF6000000,0xA2000000,0xFE100422,0xFE0001C4,0x7600003A,0x4C000335,
-0x8C0882,};
-static const uint32_t g_etc1_to_bc7_m6_table205[] = {
-0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x2000000,0x0,
-0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x8000000,0x8000000,0x8000000,0x2000000,0x0,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,
-0xDC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x48000001,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0xDC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x48000001,0x1BC0000,0x1BC0000,0x1BC0000,0x48000001,0x48000001,0x69C0000,0x940000,0x940000,0xAC0000,0xB80000,0xC80000,0xC80000,0xF80000,0xAC0000,0xB80000,0x1380000,0x1BC0000,
-0x1380000,0x1180000,0x1180000,0x1180000,0x1180000,0x1A00000,0x1A00000,0x1A00000,0x55F80000,0x55F80000,0x8A000001,0x1A00000,0x1A00000,0x1A00000,0x55F80000,0x55F80000,0x8A000001,0x55F80000,0x55F80000,0x8A000001,0x8A000001,0x1A00000,0x1A00000,0x1A00000,0x55F80000,0x55F80000,0x8A000001,0x55F80000,0x55F80000,0x8A000001,0x8A000001,0x55F80000,
-0x55F80000,0x8A000001,0x8A000001,0x8A000001,0x3440000,0xD280000,0x1180000,0x17C0000,0x3D40000,0x27FC0000,0x3FF80000,0x63F80000,0x1600000,0x1A00000,0x27FC0000,0x8A000001,0x27FC0000,0x1A80001,0x81FC0000,0xC1FC0000,0xD4000000,0x81FC0000,0xC1FC0000,0xD4000000,0xC1FC0000,0xD4000000,0xD4000000,0x81FC0000,0xC1FC0000,0xD4000000,0xC1FC0000,0xD4000000,
-0xD4000000,0xC1FC0000,0xD4000000,0xD4000000,0xD4000000,0x81FC0000,0xC1FC0000,0xD4000000,0xC1FC0000,0xD4000000,0xD4000000,0xC1FC0000,0xD4000000,0xD4000000,0xD4000000,0xC1FC0000,0xD4000000,0xD4000000,0xD4000000,0xD4000000,0x33FC0000,0xBC40000,0xBC40000,0x99FC0000,0xB9FC0000,0xCBF40000,0xD4000000,0xD4000000,0x63FC0000,0xA7FC0000,0xD3D80000,0xD4000000,
-0xB1FC0000,0xD4604E,0xFEB03C09,0xFE9426F6,0xD49025C5,0xFE8C2D3E,0xFE641023,0xDE641046,0xF24C14D2,0xCE440B09,0xB04C14D2,0xFE68364F,0xFE2C0F61,0xE02C0D53,0xFC040B0A,0xD2040012,0xB20C0B07,0xD20025C6,0xB8000DD5,0xA60010C2,0x8E0025C7,0x33C604A,0xFE042E6B,0xD40425C6,0xE800235E,0xC6001139,0xA80017A6,0xC0003691,0xAE001B58,0x9E001B37,0x86002D9F,0x23FC604A,
-0x96003EDE,0x8A0037DE,0x7E004416,0x6A00604A,0xFEA0430C,0xFECC55D2,0xFECC5866,0xFE702686,0xFE3C0E17,0xFE08006C,0xDA1400D9,0xCA0000F6,0xFE904155,0xFE50227D,0xD60009ED,0x9E001B37,0x1C8604A,0x11C25C5,0xFEF412E5,0xFED808A8,0xD4D40884,0xFED011E1,0xFEA0010E,0xD8A80104,0xE2940A69,0xC88801D5,0xB0940A69,0x3A425C5,0xFE580BA3,0xD46C0884,0xFC040B09,0xD2040011,
-0xB0300A69,0x57FC25C5,0xB8000DD4,0xA60010C1,0x8E0025C6,0x3A425C5,0xFE580BA3,0xD46C0884,0xFC040B09,0xD2040011,0xB0300A69,0x57FC25C5,0xB8000DD4,0xA60010C1,0x8E0025C6,0x57FC25C5,0xB8000DD4,0xA60010C1,0x8E0025C6,0x8E0025C6,0xFEF81C2C,0xFF0C21C5,0xFF0C21E5,0xFEC01224,0xFE6807CD,0xFE18003B,0xD634000C,0xCA0000F5,0xFEDC1C41,0xFE9810B6,0xD600095D,0xA60010C1,
-0x2BFC25C5,0x9025C5,0x9025C5,0x9025C5,0x9025C5,0xFE5C0D6A,0xFE5C0D6A,0xFE5C0D6A,0xBC4C0A6A,0xBC4C0A6A,0x8A4C0A6A,0xFE240A95,0xFE240A95,0xFE240A95,0xD204000E,0xD204000E,0x901801D6,0x9E000883,0x9E000883,0x84000113,0x6A000883,0xD425C5,0xD425C5,0xD425C5,0xAE000F45,0xAE000F45,0x86000AD6,0x8C00118B,0x8C00118B,0x7A000763,0x62000CC3,0x1B025C5,
-0x1B025C5,0x66001782,0x56001853,0x460025C6,0xFE681813,0xFC881FBD,0x9025C5,0xFE4C0D02,0xFE2C03E3,0xFE08001B,0xEC08004D,0xBC00000B,0xFE5016E0,0xFE300BA2,0xC60008FD,0x7A000763,0x13025C5,0xD40884,0xD40884,0xD40884,0xD40884,0xFE98001D,0xFE98001D,0xFE98001D,0xAA940001,0xAA940001,0x8A940001,0x33C0882,0x33C0882,0x33C0882,0xC8180001,0xC8180001,
-0x8A540001,0x23FC0882,0x23FC0882,0x84000112,0x6A000882,0x33C0882,0x33C0882,0x33C0882,0xC8180001,0xC8180001,0x8A540001,0x23FC0882,0x23FC0882,0x84000112,0x6A000882,0x23FC0882,0x23FC0882,0x84000112,0x6A000882,0x6A000882,0xFAB4057D,0xFECC0620,0xD40884,0xFE880374,0xFE5400F2,0xFE100001,0xDA2C0001,0xBC00000A,0xFE9405BA,0xFE680322,0x1C80882,0x84000112,
-0x1C80882,0x1600A69,0xFF3C0355,0xF9180000,0xD5180000,0xFFC0A69,0xFEB80092,0xD4D00000,0x8BF80A69,0xD2000008,0xB0000A69,0xFFC0A69,0xFEB80092,0xD4D00000,0x8BF80A69,0xD2000008,0xB0000A69,0x8BF80A69,0xD2000008,0xB0000A69,0xB0000A69,0xFFC0A69,0xFEB80092,0xD4D00000,0x8BF80A69,0xD2000008,0xB0000A69,0x8BF80A69,0xD2000008,0xB0000A69,0xB0000A69,0x8BF80A69,
-0xD2000008,0xB0000A69,0xB0000A69,0xB0000A69,0xFF3408B4,0x1780A69,0xF75C0908,0xFF040611,0xFEBC037A,0xFE180032,0xD4440000,0xCE0000B4,0xFF2C088A,0xFEF005C4,0xDE5C0001,0xB0000A69,0x6BFC0A69,0x4C0A69,0x4C0A69,0x4C0A69,0x4C0A69,0x4C0A69,0x4C0A69,0x4C0A69,0x4C0A69,0x4C0A69,0x4C0A69,0xDC040001,0xDC040001,0xDC040001,0xDC040001,0xDC040001,
-0xDC040001,0x6C040001,0x6C040001,0x6C040001,0x48000002,0x6C0A69,0x6C0A69,0x6C0A69,0x6C0A69,0x6C0A69,0x6C0A69,0x580003D4,0x580003D4,0x580003D4,0x400001E1,0xDC0A69,0xDC0A69,0xDC0A69,0x32000652,0x24000A69,0xF63C06CD,0x4C0A69,0x4C0A69,0xFE200321,0xFE140115,0xFE080012,0xFE080012,0xB2040001,0xFE1005A5,0xFE0002C5,0x86000035,0x580003D4,
-0x9C0A69,};
-static const uint32_t g_etc1_to_bc7_m6_table206[] = {
-0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x2180000,0x2180000,0x2180000,0x2180000,0x2180000,0x2180000,0x2180000,0x2180000,0x2180000,0x2180000,0x300000,
-0x300000,0x300000,0x300000,0x8000000,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x100001,0x140000,0x140000,0x140000,0x2180000,0x240000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xA40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,
-0xF40000,0x1F00000,0x1F00000,0x1F00000,0x50000001,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0xF40000,0x1F00000,0x1F00000,0x1F00000,0x50000001,0x1F00000,0x1F00000,0x1F00000,0x50000001,0x50000001,0xEAC0000,0xA40000,0xA40000,0x6BC0000,0x2CC0000,0x2DC0000,0x2DC0000,0x1140000,0x6BC0000,0x2CC0000,0x15C0000,0x1F00000,
-0x15C0000,0x1280000,0x1280000,0x1280000,0x1280000,0x1B80000,0x1B80000,0x1B80000,0x61F80000,0x61F80000,0x92000001,0x1B80000,0x1B80000,0x1B80000,0x61F80000,0x61F80000,0x92000001,0x61F80000,0x61F80000,0x92000001,0x92000001,0x1B80000,0x1B80000,0x1B80000,0x61F80000,0x61F80000,0x92000001,0x61F80000,0x61F80000,0x92000001,0x92000001,0x61F80000,
-0x61F80000,0x92000001,0x92000001,0x92000001,0x1580000,0x13C0000,0x1280000,0x3900000,0x1F00000,0x37FC0000,0x4BFC0000,0x6DFC0000,0x1740000,0x1B80000,0x37FC0000,0x92000001,0x37FC0000,0x1B80001,0x99FC0000,0xCDFC0000,0xDC000000,0x99FC0000,0xCDFC0000,0xDC000000,0xCDFC0000,0xDC000000,0xDC000000,0x99FC0000,0xCDFC0000,0xDC000000,0xCDFC0000,0xDC000000,
-0xDC000000,0xCDFC0000,0xDC000000,0xDC000000,0xDC000000,0x99FC0000,0xCDFC0000,0xDC000000,0xCDFC0000,0xDC000000,0xDC000000,0xCDFC0000,0xDC000000,0xDC000000,0xDC000000,0xCDFC0000,0xDC000000,0xDC000000,0xDC000000,0xDC000000,0x5BFC0000,0x1D80000,0x1D80000,0xADFC0000,0xC7F80000,0xD5F40000,0xDC000000,0xDC000000,0x81FC0000,0xB7FC0000,0xDBE80000,0xDC000000,
-0xBFFC0000,0xE4604E,0xFEC43D66,0xFEA027D6,0xDCA025C5,0xFE982F3A,0xFE7811D1,0xE6741046,0xFA5C14D2,0xD6540B09,0xB85C14D2,0xFE7437E7,0xFE40114C,0xE83C0D53,0xFE140B5E,0xDA140012,0xBA1C0B07,0xDA1025C6,0xC4000D55,0xAC001046,0x961025C7,0x154604A,0xFE082F3D,0xDC1425C6,0xF4002116,0xD2000F41,0xB4001656,0xD20034A5,0xBA001888,0xA800188D,0x92002BD7,0x2FFC604A,
-0xA0003D3D,0x960035A6,0x8400424A,0x7200604A,0xFEBC4462,0xFECC56D2,0xF8E05915,0xFE8028C4,0xFE501077,0xFE240126,0xE22400D9,0xD40800DB,0xFE9842FE,0xFE5C2552,0xE4000921,0xA800188D,0x1E8604A,0x12C25C5,0xFF0C13F5,0xFEEC090D,0xDCE40884,0xFEE812E1,0xFEB801D6,0xE0B80104,0xEAA40A69,0xD09801D5,0xB8A40A69,0x3BC25C5,0xFE700C8B,0xDC7C0884,0xFE140B5D,0xDA140011,
-0xB8400A69,0x63FC25C5,0xC4000D04,0xAC000FF5,0x960025C6,0x3BC25C5,0xFE700C8B,0xDC7C0884,0xFE140B5D,0xDA140011,0xB8400A69,0x63FC25C5,0xC4000D04,0xAC000FF5,0x960025C6,0x63FC25C5,0xC4000D04,0xAC000FF5,0x960025C6,0x960025C6,0xFF001CF1,0xFB242229,0xFD282208,0xFED41351,0xFE90091D,0xFE2C00B1,0xDE44000C,0xD4000099,0xFEF81D1D,0xFEC01208,0xE4000908,0xAC000FF5,
-0x3BFC25C5,0xA025C5,0xA025C5,0xA025C5,0xA025C5,0xFE680E06,0xFE680E06,0xFE680E06,0xC45C0A6A,0xC45C0A6A,0x925C0A6A,0xFE300B25,0xFE300B25,0xFE300B25,0xDA14000E,0xDA14000E,0x982801D6,0xA6100883,0xA6100883,0x8A0C0103,0x72100883,0xEC25C5,0xEC25C5,0xEC25C5,0xC0000E11,0xC0000E11,0x92000A76,0x98001033,0x98001033,0x800005C3,0x6E000B7B,0x1E425C5,
-0x1E425C5,0x6C001642,0x5C001743,0x4E0025C6,0xFE841892,0xFE8C201D,0xA025C5,0xFE5C0DCE,0xFE40049B,0xFE1C004D,0xF418004D,0xC410000B,0xFE6417AD,0xFE3C0C7D,0xD6000894,0x800005C3,0x15425C5,0xE40884,0xE40884,0xE40884,0xE40884,0xFEB0003D,0xFEB0003D,0xFEB0003D,0xB2A40001,0xB2A40001,0x92A40001,0x1540882,0x1540882,0x1540882,0xD0280001,0xD0280001,
-0x92640001,0x2FFC0882,0x2FFC0882,0x8A0000CA,0x72000882,0x1540882,0x1540882,0x1540882,0xD0280001,0xD0280001,0x92640001,0x2FFC0882,0x2FFC0882,0x8A0000CA,0x72000882,0x2FFC0882,0x2FFC0882,0x8A0000CA,0x72000882,0x72000882,0xFEBC05A5,0xF6DC0659,0xE40884,0xFE9803A9,0xFC6C0139,0xFE2C0008,0xE23C0001,0xC8000000,0xFAAC05E9,0xFE740371,0x1E80882,0x8A0000CA,
-0x1E80882,0x1700A69,0xFF5003D0,0xFF280001,0xDD280000,0x29FC0A69,0xFED80104,0xDCE00000,0x97F80A69,0xDC000000,0xB8000A69,0x29FC0A69,0xFED80104,0xDCE00000,0x97F80A69,0xDC000000,0xB8000A69,0x97F80A69,0xDC000000,0xB8000A69,0xB8000A69,0x29FC0A69,0xFED80104,0xDCE00000,0x97F80A69,0xDC000000,0xB8000A69,0x97F80A69,0xDC000000,0xB8000A69,0xB8000A69,0x97F80A69,
-0xDC000000,0xB8000A69,0xB8000A69,0xB8000A69,0xFF5008C9,0x1880A69,0xFF6C0908,0xFF200671,0xFED003FA,0xFE480074,0xDC540000,0xD4000080,0xF74C08C5,0xFF080601,0xE66C0001,0xB8000A69,0x7BFC0A69,0x5C0A69,0x5C0A69,0x5C0A69,0x5C0A69,0x5C0A69,0x5C0A69,0x5C0A69,0x5C0A69,0x5C0A69,0x5C0A69,0xE4140001,0xE4140001,0xE4140001,0xE4140001,0xE4140001,
-0xE4140001,0x74140001,0x74140001,0x74140001,0x50100002,0x840A69,0x840A69,0x840A69,0x840A69,0x840A69,0x840A69,0x680002EA,0x680002EA,0x680002EA,0x4C000119,0x10C0A69,0x10C0A69,0x10C0A69,0x3E0005AA,0x2C000A69,0xFE4C06CD,0x5C0A69,0x5C0A69,0xFE3C0349,0xFE28013D,0xFE180022,0xFE180022,0xBA140001,0xFE2005E4,0xFE1402E4,0x9A000001,0x680002EA,
-0xBC0A69,};
-static const uint32_t g_etc1_to_bc7_m6_table207[] = {
-0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x2300000,0x2300000,0x2300000,0x2300000,0x2300000,0x2300000,0x2300000,0x2300000,0x2300000,0x2300000,0x640000,
-0x640000,0x640000,0x640000,0x10000000,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x200001,0x240000,0x240000,0x240000,0x2300000,0x480000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0xB40000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,
-0x10C0000,0xBF80000,0xBF80000,0xBF80000,0x58000001,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0xBF80000,0xBF80000,0xBF80000,0x58000001,0xBF80000,0xBF80000,0xBF80000,0x58000001,0x58000001,0xC00000,0xB40000,0xB40000,0xD00000,0x2E00000,0xF40000,0xF40000,0x32C0000,0xD00000,0x2E00000,0x17C0000,0xBF80000,
-0x17C0000,0x1380000,0x1380000,0x1380000,0x1380000,0x1D00000,0x1D00000,0x1D00000,0x6DF80000,0x6DF80000,0x9A000001,0x1D00000,0x1D00000,0x1D00000,0x6DF80000,0x6DF80000,0x9A000001,0x6DF80000,0x6DF80000,0x9A000001,0x9A000001,0x1D00000,0x1D00000,0x1D00000,0x6DF80000,0x6DF80000,0x9A000001,0x6DF80000,0x6DF80000,0x9A000001,0x9A000001,0x6DF80000,
-0x6DF80000,0x9A000001,0x9A000001,0x9A000001,0x7680000,0x14C0000,0x1380000,0x1A80000,0xDFC0000,0x45FC0000,0x59FC0000,0x79F80000,0x1880000,0x1D00000,0x45FC0000,0x9A000001,0x45FC0000,0x1C80001,0xB1FC0000,0xD9FC0000,0xE4000000,0xB1FC0000,0xD9FC0000,0xE4000000,0xD9FC0000,0xE4000000,0xE4000000,0xB1FC0000,0xD9FC0000,0xE4000000,0xD9FC0000,0xE4000000,
-0xE4000000,0xD9FC0000,0xE4000000,0xE4000000,0xE4000000,0xB1FC0000,0xD9FC0000,0xE4000000,0xD9FC0000,0xE4000000,0xE4000000,0xD9FC0000,0xE4000000,0xE4000000,0xE4000000,0xD9FC0000,0xE4000000,0xE4000000,0xE4000000,0xE4000000,0x81FC0000,0x1E80000,0x1E80000,0xC1FC0000,0xD5F80000,0xDFF80000,0xE4000000,0xE4000000,0x9FFC0000,0xC9FC0000,0xE3F80000,0xE4000000,
-0xCFFC0000,0xF4604E,0xFED03EDE,0xFEB828D6,0xE4B025C5,0xFEB03142,0xFE8813AF,0xEE841046,0xFE6C14EA,0xDE640B09,0xC06C14D2,0xFE8C397F,0xFE58135C,0xF04C0D53,0xFE2C0C2E,0xE2240012,0xC22C0B07,0xE22025C6,0xCE080D51,0xB4101046,0x9E2025C7,0x16C604A,0xFE2C30C9,0xE42425C6,0xFA001F7A,0xDE000DA9,0xBC00157A,0xE20032CB,0xC60015F8,0xAE00161D,0x98002A5B,0x3BFC604A,
-0xAC003B6D,0x9C003362,0x8A0040B6,0x7A00604A,0xFED045E7,0xFEEC56D6,0xFEEC5931,0xFE982B12,0xFE6812F6,0xFE38023E,0xEA3400D9,0xDC1800DB,0xFEB4443B,0xFE802784,0xEE0008BF,0xAE00161D,0x7FC604A,0x13C25C5,0xFF1814ED,0xFEFC0994,0xE4F40884,0xFEF413E5,0xFECC02E0,0xE8C80104,0xF2B40A69,0xD8A801D5,0xC0B40A69,0x1D425C5,0xFE940D8B,0xE48C0884,0xFE380C01,0xE2240011,
-0xC0500A69,0x6FFC25C5,0xD0000C54,0xB2000F59,0x9E0025C6,0x1D425C5,0xFE940D8B,0xE48C0884,0xFE380C01,0xE2240011,0xC0500A69,0x6FFC25C5,0xD0000C54,0xB2000F59,0x9E0025C6,0x6FFC25C5,0xD0000C54,0xB2000F59,0x9E0025C6,0x9E0025C6,0xFF141D5E,0xFF2C2251,0xFF2C2274,0xFEEC1476,0xFEA40A79,0xFE480164,0xE654000C,0xE0000062,0xFF081D9A,0xFEC812EA,0xEE0008BB,0xB2000F59,
-0x49FC25C5,0xB025C5,0xB025C5,0xB025C5,0xB025C5,0xFE800E8E,0xFE800E8E,0xFE800E8E,0xCC6C0A6A,0xCC6C0A6A,0x9A6C0A6A,0xFE440BA3,0xFE440BA3,0xFE440BA3,0xE224000E,0xE224000E,0xA03801D6,0xAE200883,0xAE200883,0x921C0103,0x7A200883,0x10425C5,0x10425C5,0x10425C5,0xD2000D0D,0xD2000D0D,0x9A080A6A,0xA8000EC8,0xA8000EC8,0x8C000443,0x74000A83,0x7FC25C5,
-0x7FC25C5,0x7800151A,0x66001632,0x560025C6,0xFE901926,0xFCA82036,0xB025C5,0xFE700EB6,0xFE540563,0xFE34009A,0xFC28004D,0xCC20000B,0xFE78181A,0xFE500D1D,0xE4040883,0x8C000443,0x17425C5,0xF40884,0xF40884,0xF40884,0xF40884,0xFEBC0061,0xFEBC0061,0xFEBC0061,0xBAB40001,0xBAB40001,0x9AB40001,0x16C0882,0x16C0882,0x16C0882,0xD8380001,0xD8380001,
-0x9A740001,0x3BFC0882,0x3BFC0882,0x96000092,0x7A000882,0x16C0882,0x16C0882,0x16C0882,0xD8380001,0xD8380001,0x9A740001,0x3BFC0882,0x3BFC0882,0x96000092,0x7A000882,0x3BFC0882,0x3BFC0882,0x96000092,0x7A000882,0x7A000882,0xFED805B2,0xFEEC0659,0xF40884,0xFEB403F5,0xFE80016D,0xFE480020,0xEA4C0001,0xD0100000,0xFEB40611,0xFE98039D,0x7FC0882,0x96000092,
-0x7FC0882,0x1800A69,0xFF5C0454,0xFF380024,0xE5380000,0x41FC0A69,0xFEF00184,0xE4F00000,0xA1FC0A69,0xE40C0000,0xC0000A69,0x41FC0A69,0xFEF00184,0xE4F00000,0xA1FC0A69,0xE40C0000,0xC0000A69,0xA1FC0A69,0xE40C0000,0xC0000A69,0xC0000A69,0x41FC0A69,0xFEF00184,0xE4F00000,0xA1FC0A69,0xE40C0000,0xC0000A69,0xA1FC0A69,0xE40C0000,0xC0000A69,0xC0000A69,0xA1FC0A69,
-0xE40C0000,0xC0000A69,0xC0000A69,0xC0000A69,0xFD680908,0x19C0A69,0xF77C094D,0xFF4006CD,0xFEE80484,0xFE7000E8,0xE4640000,0xE0000061,0xFF5C08C5,0xFF200681,0xEE7C0001,0xC0000A69,0x89FC0A69,0x6C0A69,0x6C0A69,0x6C0A69,0x6C0A69,0x6C0A69,0x6C0A69,0x6C0A69,0x6C0A69,0x6C0A69,0x6C0A69,0xEC240001,0xEC240001,0xEC240001,0xEC240001,0xEC240001,
-0xEC240001,0x7C240001,0x7C240001,0x7C240001,0x58200002,0x9C0A69,0x9C0A69,0x9C0A69,0x9C0A69,0x9C0A69,0x9C0A69,0x74000232,0x74000232,0x74000232,0x58000091,0x13C0A69,0x13C0A69,0x13C0A69,0x44000502,0x34000A69,0xF65C070A,0x6C0A69,0x6C0A69,0xFE4C0372,0xFE3C016D,0xFE2C003D,0xFE2C003D,0xC2240001,0xFE3C05E9,0xFA2C0322,0xA2100001,0x74000232,
-0xE00A69,};
-static const uint32_t g_etc1_to_bc7_m6_table208[] = {
-0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x4C0000,0x4C0000,0x4C0000,0x4C0000,0x4C0000,0x4C0000,0x4C0000,0x4C0000,0x4C0000,0x4C0000,0x980000,
-0x980000,0x980000,0x980000,0x18000001,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x340000,0x380000,0x380000,0x380000,0x4C0000,0x6C0000,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0xC40001,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,
-0x3240000,0x17FC0000,0x17FC0000,0x17FC0000,0x62000000,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,0x3240000,0x17FC0000,0x17FC0000,0x17FC0000,0x62000000,0x17FC0000,0x17FC0000,0x17FC0000,0x62000000,0x62000000,0xD40000,0xC40001,0xC40001,0x4E40000,0xF80000,0x10C0000,0x10C0000,0x14C0000,0x4E40000,0xF80000,0x1A40000,0x17FC0000,
-0x1A40000,0x1480001,0x1480001,0x1480001,0x1480001,0x3E80000,0x3E80000,0x3E80000,0x79FC0000,0x79FC0000,0xA4000000,0x3E80000,0x3E80000,0x3E80000,0x79FC0000,0x79FC0000,0xA4000000,0x79FC0000,0x79FC0000,0xA4000000,0xA4000000,0x3E80000,0x3E80000,0x3E80000,0x79FC0000,0x79FC0000,0xA4000000,0x79FC0000,0x79FC0000,0xA4000000,0xA4000000,0x79FC0000,
-0x79FC0000,0xA4000000,0xA4000000,0xA4000000,0x1800000,0x1600000,0x1480001,0x1C00000,0x23FC0000,0x57FC0000,0x69F80000,0x85F80000,0x39C0000,0x3E80000,0x57FC0000,0xA4000000,0x57FC0000,0x1DC0000,0xCDFC0000,0xE7F80000,0xEC000001,0xCDFC0000,0xE7F80000,0xEC000001,0xE7F80000,0xEC000001,0xEC000001,0xCDFC0000,0xE7F80000,0xEC000001,0xE7F80000,0xEC000001,
-0xEC000001,0xE7F80000,0xEC000001,0xEC000001,0xEC000001,0xCDFC0000,0xE7F80000,0xEC000001,0xE7F80000,0xEC000001,0xEC000001,0xE7F80000,0xEC000001,0xEC000001,0xEC000001,0xE7F80000,0xEC000001,0xEC000001,0xEC000001,0xEC000001,0xADFC0000,0x1FC0000,0x1FC0000,0xD7FC0000,0xE3FC0000,0xEBF00000,0xEC000001,0xEC000001,0xC1FC0000,0xDBFC0000,0xEDEC0000,0xEC000001,
-0xDFFC0000,0x108604A,0xFEE840B6,0xFECC2A5B,0xECC025C7,0xFEC43362,0xFEA0161D,0xF6941046,0xFE84157A,0xE8780B07,0xC87C14D2,0xFEA43B6D,0xFE7015F8,0xFA600D51,0xFE400DA9,0xEC380012,0xCC400B09,0xEC3425C6,0xD81C0D53,0xBC201046,0xA63425C5,0x188604A,0xFE3832CB,0xEC3825C6,0xFE081F7A,0xE8000C2E,0xC60014EA,0xE80030C9,0xD200135C,0xBA0013AF,0xA20028D6,0x49F8604A,
-0xB800397F,0xA6003142,0x96003EDE,0x8200604E,0xFEE44782,0xF90057DA,0xFB0459DA,0xFEAC2DF6,0xFE7C160E,0xFE4803FF,0xF24400DB,0xE42800D9,0xFED0463D,0xFE902A56,0xF81008BB,0xBA0013AF,0x19FC604A,0x15025C6,0xFF301632,0xFF140A83,0xED080883,0xFF0C151A,0xFEE40443,0xF0D80103,0xFAC40A6A,0xE2BC01D6,0xC8C40A6A,0x1F025C5,0xFEAC0EC8,0xECA00883,0xFE580D0D,0xEC38000E,
-0xC8600A6A,0x7DF825C5,0xDC000BA3,0xBE000E8E,0xA60025C5,0x1F025C5,0xFEAC0EC8,0xECA00883,0xFE580D0D,0xEC38000E,0xC8600A6A,0x7DF825C5,0xDC000BA3,0xBE000E8E,0xA60025C5,0x7DF825C5,0xDC000BA3,0xBE000E8E,0xA60025C5,0xA60025C5,0xFF341E13,0xFD4822AA,0xFF4C228E,0xFF0015CE,0xFEBC0C34,0xFE70027E,0xEE64000B,0xE800004D,0xFF181E3E,0xFEDC1481,0xFC00088B,0xBE000E8E,
-0x5BFC25C5,0xC025C6,0xC025C6,0xC025C6,0xC025C6,0xFE980F59,0xFE980F59,0xFE980F59,0xD67C0A69,0xD67C0A69,0xA47C0A69,0xFE5C0C54,0xFE5C0C54,0xFE5C0C54,0xEA340011,0xEA340011,0xAA4C01D5,0xB6340884,0xB6340884,0x9A2C0104,0x82340884,0x12025C5,0x12025C5,0x12025C5,0xE2000C01,0xE2000C01,0xA4180A69,0xB4000D8B,0xB4000D8B,0x980002E0,0x80000994,0x15F825C5,
-0x15F825C5,0x840013E5,0x720014ED,0x600025C5,0xFEA019B4,0xF6BC20B2,0xC025C6,0xFE880F9E,0xFE6C0669,0xFE480126,0xFE3C0062,0xD430000C,0xFE9018F2,0xFE680E59,0xEC180882,0x980002E0,0x19C25C5,0x1080882,0x1080882,0x1080882,0x1080882,0xFED00092,0xFED00092,0xFED00092,0xC4C40001,0xC4C40001,0xA4C40001,0x1880882,0x1880882,0x1880882,0xE04C0001,0xE04C0001,
-0xA4840001,0x49F80882,0x49F80882,0xA0000061,0x82000884,0x1880882,0x1880882,0x1880882,0xE04C0001,0xE04C0001,0xA4840001,0x49F80882,0x49F80882,0xA0000061,0x82000884,0x49F80882,0x49F80882,0xA0000061,0x82000884,0x82000884,0xFAEC05E9,0xF9000692,0x1080882,0xFEC4042A,0xFE9801A9,0xFE64003D,0xF65C0000,0xD8240001,0xFED00628,0xFEA403E8,0x19FC0882,0xA0000061,
-0x19FC0882,0x1940A69,0xFF740502,0xFF4C0091,0xED480002,0x5BFC0A69,0xFF140232,0xED040001,0xAFFC0A69,0xEC240001,0xC8000A69,0x5BFC0A69,0xFF140232,0xED040001,0xAFFC0A69,0xEC240001,0xC8000A69,0xAFFC0A69,0xEC240001,0xC8000A69,0xC8000A69,0x5BFC0A69,0xFF140232,0xED040001,0xAFFC0A69,0xEC240001,0xC8000A69,0xAFFC0A69,0xEC240001,0xC8000A69,0xC8000A69,0xAFFC0A69,
-0xEC240001,0xC8000A69,0xC8000A69,0xC8000A69,0xFF780910,0x1AC0A69,0xFF8C0951,0xFF580749,0xFF10052A,0xFE98018D,0xEC780001,0xE800003D,0xFF70090A,0xFF4006E5,0xF88C0000,0xC8000A69,0x9BFC0A69,0x7C0A69,0x7C0A69,0x7C0A69,0x7C0A69,0x7C0A69,0x7C0A69,0x7C0A69,0x7C0A69,0x7C0A69,0x7C0A69,0xF6340000,0xF6340000,0xF6340000,0xF6340000,0xF6340000,
-0xF6340000,0x86340000,0x86340000,0x86340000,0x62340000,0xB80A69,0xB80A69,0xB80A69,0xB80A69,0xB80A69,0xB80A69,0x86000184,0x86000184,0x86000184,0x62000024,0x1740A69,0x1740A69,0x1740A69,0x50000454,0x3E000A69,0xFE6C0710,0x7C0A69,0x7C0A69,0xFE5803B5,0xFE5001A5,0xFE3C0061,0xFE3C0061,0xCC340000,0xFA500622,0xFE3C0355,0xAC200000,0x86000184,
-0x1080A69,};
-static const uint32_t g_etc1_to_bc7_m6_table209[] = {
-0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0xCC0000,
-0xCC0000,0xCC0000,0xCC0000,0x20000001,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x480000,0x480000,0x480000,0x640000,0x900000,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0xD40001,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x33C0000,
-0x33C0000,0x23FC0000,0x23FC0000,0x23FC0000,0x6A000000,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x33C0000,0x23FC0000,0x23FC0000,0x23FC0000,0x6A000000,0x23FC0000,0x23FC0000,0x23FC0000,0x6A000000,0x6A000000,0xE40000,0xD40001,0xD40001,0xF80000,0x10C0000,0x1240000,0x1240000,0x1680000,0xF80000,0x10C0000,0x1C80000,0x23FC0000,
-0x1C80000,0x1580001,0x1580001,0x1580001,0x1580001,0x7FC0000,0x7FC0000,0x7FC0000,0x85FC0000,0x85FC0000,0xAC000000,0x7FC0000,0x7FC0000,0x7FC0000,0x85FC0000,0x85FC0000,0xAC000000,0x85FC0000,0x85FC0000,0xAC000000,0xAC000000,0x7FC0000,0x7FC0000,0x7FC0000,0x85FC0000,0x85FC0000,0xAC000000,0x85FC0000,0x85FC0000,0xAC000000,0xAC000000,0x85FC0000,
-0x85FC0000,0xAC000000,0xAC000000,0xAC000000,0x5900000,0x1700000,0x1580001,0x3D40000,0x37FC0000,0x65FC0000,0x75FC0000,0x91F40000,0x3B00000,0x7FC0000,0x65FC0000,0xAC000000,0x65FC0000,0x1EC0000,0xE5FC0000,0xF3F80000,0xF4000001,0xE5FC0000,0xF3F80000,0xF4000001,0xF3F80000,0xF4000001,0xF4000001,0xE5FC0000,0xF3F80000,0xF4000001,0xF3F80000,0xF4000001,
-0xF4000001,0xF3F80000,0xF4000001,0xF4000001,0xF4000001,0xE5FC0000,0xF3F80000,0xF4000001,0xF3F80000,0xF4000001,0xF4000001,0xF3F80000,0xF4000001,0xF4000001,0xF4000001,0xF3F80000,0xF4000001,0xF4000001,0xF4000001,0xF4000001,0xD5FC0000,0x77FC0000,0x77FC0000,0xEBFC0000,0xF1FC0000,0xF5F00000,0xF4000001,0xF4000001,0xDFFC0000,0xEDFC0000,0xF5FC0000,0xF4000001,
-0xEFFC0000,0x118604A,0xFEF4424A,0xFED82BD7,0xF4D025C7,0xFED035A6,0xFEAC188D,0xFEA41046,0xFE941656,0xF0880B07,0xD08C14D2,0xFEBC3D3D,0xFE881888,0xFE740D55,0xFE580F41,0xF4480012,0xD4500B09,0xF44425C6,0xE02C0D53,0xC4301046,0xAE4425C5,0x1A0604A,0xFE5834A5,0xF44825C6,0xFE142116,0xF4000B5E,0xD00414D2,0xFA002F3D,0xDE00114C,0xC20011D1,0xAE0027D6,0x55F8604A,
-0xC40037E7,0xB2002F3A,0x9C003D66,0x8A00604E,0xFEF44912,0xFF0C57EA,0xFF0C5A1A,0xFEC4307A,0xFE901902,0xFE5C05EA,0xFA5400DB,0xEC3800D9,0xFEDC478F,0xFEB02D65,0xFE2008C1,0xC20011D1,0x27FC604A,0x16025C6,0xFF441743,0xFF200B7B,0xF5180883,0xFF241642,0xFEF005C3,0xF8E80103,0xFED80A76,0xEACC01D6,0xD0D40A6A,0xDFC25C5,0xFECC1033,0xF4B00883,0xFE7C0E11,0xF448000E,
-0xD0700A6A,0x89F825C5,0xE6000B25,0xCA000E06,0xAE0025C5,0xDFC25C5,0xFECC1033,0xF4B00883,0xFE7C0E11,0xF448000E,0xD0700A6A,0x89F825C5,0xE6000B25,0xCA000E06,0xAE0025C5,0x89F825C5,0xE6000B25,0xCA000E06,0xAE0025C5,0xAE0025C5,0xFF3C1EC2,0xFF4C22FE,0xF75C2313,0xFF1416C1,0xFEDC0DD4,0xFE8403CB,0xF674000B,0xF010004D,0xFF341F0E,0xFF0415B5,0xFE1408A6,0xCA000E06,
-0x69FC25C5,0xD025C6,0xD025C6,0xD025C6,0xD025C6,0xFEA40FF5,0xFEA40FF5,0xFEA40FF5,0xDE8C0A69,0xDE8C0A69,0xAC8C0A69,0xFE740D04,0xFE740D04,0xFE740D04,0xF2440011,0xF2440011,0xB25C01D5,0xBE440884,0xBE440884,0xA23C0104,0x8A440884,0x13825C5,0x13825C5,0x13825C5,0xF4000B5D,0xF4000B5D,0xAC280A69,0xC6000C8B,0xC6000C8B,0xA20001D6,0x8800090D,0x21F825C5,
-0x21F825C5,0x8A0012E1,0x780013F5,0x680025C5,0xFEBC1A59,0xFECC20B2,0xD025C6,0xFE981069,0xFE800755,0xFE5C01A9,0xFE540099,0xDC40000C,0xFEA01966,0xFE740F25,0xF4280882,0xA20001D6,0x1BC25C5,0x1180882,0x1180882,0x1180882,0x1180882,0xFEE800CA,0xFEE800CA,0xFEE800CA,0xCCD40001,0xCCD40001,0xACD40001,0x1A00882,0x1A00882,0x1A00882,0xE85C0001,0xE85C0001,
-0xAC940001,0x55F80882,0x55F80882,0xA600003D,0x8A000884,0x1A00882,0x1A00882,0x1A00882,0xE85C0001,0xE85C0001,0xAC940001,0x55F80882,0x55F80882,0xA600003D,0x8A000884,0x55F80882,0x55F80882,0xA600003D,0x8A000884,0x8A000884,0xFEF40611,0xFF0C069A,0x1180882,0xFEDC0451,0xFEAC01ED,0xFE7C0064,0xFE6C0000,0xE0340001,0xF8EC0659,0xFEC40422,0x27FC0882,0xA600003D,
-0x27FC0882,0x1A40A69,0xFF8005AA,0xFF640119,0xF5580002,0x75FC0A69,0xFF2C02EA,0xF5140001,0xBBFC0A69,0xF4340001,0xD0000A69,0x75FC0A69,0xFF2C02EA,0xF5140001,0xBBFC0A69,0xF4340001,0xD0000A69,0xBBFC0A69,0xF4340001,0xD0000A69,0xD0000A69,0x75FC0A69,0xFF2C02EA,0xF5140001,0xBBFC0A69,0xF4340001,0xD0000A69,0xBBFC0A69,0xF4340001,0xD0000A69,0xD0000A69,0xBBFC0A69,
-0xF4340001,0xD0000A69,0xD0000A69,0xD0000A69,0xFD90094D,0x1C00A69,0xF9A00992,0xFF6C0794,0xFF3C05C4,0xFEC80235,0xF4880001,0xF2000022,0xF98C094D,0xFF58076D,0xFEA00004,0xD0000A69,0xA9FC0A69,0x8C0A69,0x8C0A69,0x8C0A69,0x8C0A69,0x8C0A69,0x8C0A69,0x8C0A69,0x8C0A69,0x8C0A69,0x8C0A69,0xFE440000,0xFE440000,0xFE440000,0xFE440000,0xFE440000,
-0xFE440000,0x8E440000,0x8E440000,0x8E440000,0x6A440000,0xD00A69,0xD00A69,0xD00A69,0xD00A69,0xD00A69,0xD00A69,0x92000104,0x92000104,0x92000104,0x6A000001,0x1A40A69,0x1A40A69,0x1A40A69,0x560003D0,0x46000A69,0xF8800745,0x8C0A69,0x8C0A69,0xFE6803E8,0xFE6401E1,0xFE540080,0xFE540080,0xD4440000,0xFE580652,0xFE50037A,0xB4300000,0x92000104,
-0x1280A69,};
-static const uint32_t g_etc1_to_bc7_m6_table210[] = {
-0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0x7C0000,0xFC0000,
-0xFC0000,0xFC0000,0xFC0000,0x28000001,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x540000,0x4580000,0x4580000,0x4580000,0x7C0000,0xB00000,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0xE40001,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,
-0x1540000,0x2FFC0000,0x2FFC0000,0x2FFC0000,0x72000000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x1540000,0x2FFC0000,0x2FFC0000,0x2FFC0000,0x72000000,0x2FFC0000,0x2FFC0000,0x2FFC0000,0x72000000,0x72000000,0x2F40000,0xE40001,0xE40001,0x10C0000,0x1200000,0x1380000,0x1380000,0x3800000,0x10C0000,0x1200000,0x1E80000,0x2FFC0000,
-0x1E80000,0x1680001,0x1680001,0x1680001,0x1680001,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x91FC0000,0x91FC0000,0xB4000000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x91FC0000,0x91FC0000,0xB4000000,0x91FC0000,0x91FC0000,0xB4000000,0xB4000000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x91FC0000,0x91FC0000,0xB4000000,0x91FC0000,0x91FC0000,0xB4000000,0xB4000000,0x91FC0000,
-0x91FC0000,0xB4000000,0xB4000000,0xB4000000,0x1A40000,0x9800000,0x1680001,0x1EC0000,0x4BFC0000,0x75FC0000,0x83FC0000,0x9BF80000,0x3C40000,0x1FFC0000,0x75FC0000,0xB4000000,0x75FC0000,0x1FC0000,0xFDFC0000,0xFFF80000,0xFC000001,0xFDFC0000,0xFFF80000,0xFC000001,0xFFF80000,0xFC000001,0xFC000001,0xFDFC0000,0xFFF80000,0xFC000001,0xFFF80000,0xFC000001,
-0xFC000001,0xFFF80000,0xFC000001,0xFC000001,0xFC000001,0xFDFC0000,0xFFF80000,0xFC000001,0xFFF80000,0xFC000001,0xFC000001,0xFFF80000,0xFC000001,0xFC000001,0xFC000001,0xFFF80000,0xFC000001,0xFC000001,0xFC000001,0xFC000001,0xFDFC0000,0xF7FC0000,0xF7FC0000,0xFDFC0000,0xFFF80000,0xFFF00000,0xFC000001,0xFC000001,0xFDFC0000,0xFDFC0000,0xFFD00000,0xFC000001,
-0xFFF80000,0x128604A,0xFF004416,0xFEF02D9F,0xFCE025C7,0xFEE837DE,0xFEC01B37,0xFEB010C2,0xFEAC17A6,0xF8980B07,0xD89C14D2,0xFED03EDE,0xFEA01B58,0xFE8C0DD5,0xFE701139,0xFC580012,0xDC600B09,0xFC5425C6,0xE83C0D53,0xCC401046,0xB65425C5,0x1B8604A,0xFE7C3691,0xFC5825C6,0xFE2C235E,0xFC040B0A,0xD81414D2,0xFC002E6B,0xE8000F61,0xCC001023,0xB40026F6,0x61F8604A,
-0xCA00364F,0xB8002D3E,0xA6003C09,0x9200604E,0xFF004A76,0xF92058E2,0xFB245AA3,0xFED432EA,0xFEA81C14,0xFE7C0838,0xFE6800F6,0xF44800D9,0xFEF0492C,0xFEC02FD3,0xFE38092D,0xCC001023,0x37FC604A,0x17025C6,0xFF501853,0xFF380CC3,0xFD280883,0xFF301782,0xFF080763,0xFEF40113,0xFEF00AD6,0xF2DC01D6,0xD8E40A6A,0x25FC25C5,0xFEE4118B,0xFCC00883,0xFEA00F45,0xFC58000E,
-0xD8800A6A,0x95F825C5,0xEC000A95,0xD0000D6A,0xB60025C5,0x25FC25C5,0xFEE4118B,0xFCC00883,0xFEA00F45,0xFC58000E,0xD8800A6A,0x95F825C5,0xEC000A95,0xD0000D6A,0xB60025C5,0x95F825C5,0xEC000A95,0xD0000D6A,0xB60025C5,0xB60025C5,0xFF501F35,0xFD68232A,0xFF6C2313,0xFF30183D,0xFEE80F6B,0xFEAC055A,0xFE84000B,0xF820004D,0xFF441F99,0xFF101711,0xFE34092B,0xD0000D6A,
-0x79FC25C5,0xE025C6,0xE025C6,0xE025C6,0xE025C6,0xFEB010C1,0xFEB010C1,0xFEB010C1,0xE69C0A69,0xE69C0A69,0xB49C0A69,0xFE8C0DD4,0xFE8C0DD4,0xFE8C0DD4,0xFA540011,0xFA540011,0xBA6C01D5,0xC6540884,0xC6540884,0xAA4C0104,0x92540884,0x15025C5,0x15025C5,0x15025C5,0xFC040B09,0xFC040B09,0xB4380A69,0xD2000BA3,0xD2000BA3,0xAE00010E,0x920008A8,0x2DF825C5,
-0x2DF825C5,0x960011E1,0x840012E5,0x700025C5,0xFECC1ACA,0xF6DC212D,0xE025C6,0xFEAC116D,0xFE88084E,0xFE700251,0xFE6800F5,0xE450000C,0xFEB419D9,0xFE901016,0xFC380882,0xAE00010E,0x1E025C5,0x1280882,0x1280882,0x1280882,0x1280882,0xFEF40112,0xFEF40112,0xFEF40112,0xD4E40001,0xD4E40001,0xB4E40001,0x1B80882,0x1B80882,0x1B80882,0xF06C0001,0xF06C0001,
-0xB4A40001,0x61F80882,0x61F80882,0xB200001D,0x92000884,0x1B80882,0x1B80882,0x1B80882,0xF06C0001,0xF06C0001,0xB4A40001,0x61F80882,0x61F80882,0xB200001D,0x92000884,0x61F80882,0x61F80882,0xB200001D,0x92000884,0x92000884,0xFF100620,0xF92006CD,0x1280882,0xFCF404B1,0xFEC00239,0xFE9400AA,0xFE84000A,0xE8440001,0xFEF8065D,0xFEDC0451,0x37FC0882,0xB200001D,
-0x37FC0882,0x1B40A69,0xFF980652,0xFF7C01E1,0xFD680002,0x8DFC0A69,0xFF4C03D4,0xFD240001,0xC7FC0A69,0xFC440001,0xD8000A69,0x8DFC0A69,0xFF4C03D4,0xFD240001,0xC7FC0A69,0xFC440001,0xD8000A69,0xC7FC0A69,0xFC440001,0xD8000A69,0xD8000A69,0x8DFC0A69,0xFF4C03D4,0xFD240001,0xC7FC0A69,0xFC440001,0xD8000A69,0xC7FC0A69,0xFC440001,0xD8000A69,0xD8000A69,0xC7FC0A69,
-0xFC440001,0xD8000A69,0xD8000A69,0xD8000A69,0xFDA40992,0x1D00A69,0xFFAC099A,0xFF840812,0xFF500668,0xFEF0031D,0xFC980001,0xFA000012,0xFF980951,0xFF7007FD,0xFED00049,0xD8000A69,0xB9FC0A69,0x9C0A69,0x9C0A69,0x9C0A69,0x9C0A69,0x9C0A69,0x9C0A69,0x9C0A69,0x9C0A69,0x9C0A69,0x9C0A69,0xFC580008,0xFC580008,0xFC580008,0xFC580008,0xFC580008,
-0xFC580008,0x96540000,0x96540000,0x96540000,0x72540000,0xE80A69,0xE80A69,0xE80A69,0xE80A69,0xE80A69,0xE80A69,0xA2000092,0xA2000092,0xA2000092,0x720C0000,0x1D80A69,0x1D80A69,0x1D80A69,0x60000355,0x4E000A69,0xFE8C0751,0x9C0A69,0x9C0A69,0xFC800424,0xFE6C0220,0xFE6000B4,0xFE6000B4,0xDC540000,0xFE740659,0xFE6403CA,0xBC400000,0xA2000092,
-0x14C0A69,};
-static const uint32_t g_etc1_to_bc7_m6_table211[] = {
-0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x940000,0x12C0000,
-0x12C0000,0x12C0000,0x12C0000,0x30000001,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0x640000,0xC680000,0xC680000,0xC680000,0x940000,0xD40000,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0xF40001,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,
-0x16C0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x16C0000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x3BFC0000,0x3BFC0000,0x3BFC0000,0x7A000000,0x7A000000,0xB040000,0xF40001,0xF40001,0x51C0000,0x1340000,0x34C0000,0x34C0000,0x19C0000,0x51C0000,0x1340000,0x7FC0000,0x3BFC0000,
-0x7FC0000,0x1780001,0x1780001,0x1780001,0x1780001,0x37FC0000,0x37FC0000,0x37FC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x37FC0000,0x37FC0000,0x37FC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x9DFC0000,0x9DFC0000,0xBC000000,0xBC000000,0x37FC0000,0x37FC0000,0x37FC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x9DFC0000,0x9DFC0000,0xBC000000,0xBC000000,0x9DFC0000,
-0x9DFC0000,0xBC000000,0xBC000000,0xBC000000,0x1B80000,0x1940000,0x1780001,0x9FC0000,0x5DFC0000,0x83FC0000,0x91FC0000,0xA5FC0000,0x3D80000,0x37FC0000,0x83FC0000,0xBC000000,0x83FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1345AA3,0xFF18414F,0xFEFC2CFE,0xFEF025C6,0xFEF43543,0xFED41B46,0xFEC41162,0xFEB81647,0xFAA80AB6,0xDCAC12ED,0xFEDC3B5B,0xFEAC1B25,0xFE980E98,0xFE88100A,0xFE680015,0xDE700938,0xFE64220B,0xEA4C0C2A,0xD24C0DC5,0xBC642208,0x1C85AA3,0xFE88351E,0xFE7025C5,0xFE3821ED,0xFE140B45,0xDC2812ED,0xFE082A18,0xEE000CC4,0xD4000C44,0xBA00228D,0x69FC5AA3,
-0xD6003266,0xBE0027E1,0xAC00360C,0x9A005AA5,0xFF0C469D,0xFF2C536D,0xFF2C555E,0xFEEC313E,0xFEBC1BA5,0xFE9008D1,0xFE7C0184,0xF85C0071,0xFEF84551,0xFED02DDA,0xFE50093C,0xD4000C44,0x41FC5AA3,0x178220B,0xFF5C166E,0xFF400C63,0xFF380882,0xFF441505,0xFF20071A,0xFF0C015A,0xFEFC092D,0xF4EC0141,0xDCF40885,0x37FC2208,0xFEFC1086,0xFED80882,0xFEB80D86,0xFE740001,
-0xDE940884,0x9DFC2208,0xF2000974,0xD6000A9D,0xBC002208,0x37FC2208,0xFEFC1086,0xFED80882,0xFEB80D86,0xFE740001,0xDE940884,0x9DFC2208,0xF2000974,0xD6000A9D,0xBC002208,0x9DFC2208,0xF2000974,0xD6000A9D,0xBC002208,0xBC002208,0xFF581C81,0xFF6C1FAD,0xFF6C1FDA,0xFF401614,0xFEFC0E52,0xFEC00532,0xFEA00022,0xFC40001E,0xFD581C9A,0xFF24153E,0xFE58092B,0xD6000A9D,
-0x83FC2208,0xF025C6,0xF025C6,0xF025C6,0xF025C6,0xFEC41162,0xFEC41162,0xFEC41162,0xEEAC0A69,0xEEAC0A69,0xBCAC0A69,0xFE980E98,0xFE980E98,0xFE980E98,0xFE680015,0xFE680015,0xC27C01D5,0xCE640884,0xCE640884,0xB25C0104,0x9A640884,0x16825C5,0x16825C5,0x16825C5,0xFE140B45,0xFE140B45,0xBC480A69,0xE2000AD4,0xE2000AD4,0xBA000086,0x9A000885,0x39F825C5,
-0x39F825C5,0x9C001115,0x8A0011FD,0x780025C5,0xFED81B58,0xFEEC212D,0xF025C6,0xFEBC1244,0xFE9C0952,0xFE7C0334,0xFE7C0184,0xEC60000C,0xFEBC1A8C,0xFEA41121,0xFE500893,0xBA000086,0x3FC25C5,0x1380882,0x1380882,0x1380882,0x1380882,0xFF0C015A,0xFF0C015A,0xFF0C015A,0xDCF40001,0xDCF40001,0xBCF40001,0x1D00882,0x1D00882,0x1D00882,0xF87C0001,0xF87C0001,
-0xBCB40001,0x6DF80882,0x6DF80882,0xBA00000D,0x9A000884,0x1D00882,0x1D00882,0x1D00882,0xF87C0001,0xF87C0001,0xBCB40001,0x6DF80882,0x6DF80882,0xBA00000D,0x9A000884,0x6DF80882,0x6DF80882,0xBA00000D,0x9A000884,0x9A000884,0xFF200659,0xFF2C06D9,0x1380882,0xFD0404E4,0xFED4028D,0xFEB000E1,0xFEA00022,0xF0540001,0xFD100692,0xFEE80492,0x45FC0882,0xBA00000D,
-0x45FC0882,0x1BC0882,0xFFA4053D,0xFF88019A,0xFF780001,0x9BFC0882,0xFF640335,0xFF380001,0xCFF80882,0xFE6C0000,0xDC000884,0x9BFC0882,0xFF640335,0xFF380001,0xCFF80882,0xFE6C0000,0xDC000884,0xCFF80882,0xFE6C0000,0xDC000884,0xDC000884,0x9BFC0882,0xFF640335,0xFF380001,0xCFF80882,0xFE6C0000,0xDC000884,0xCFF80882,0xFE6C0000,0xDC000884,0xDC000884,0xCFF80882,
-0xFE6C0000,0xDC000884,0xDC000884,0xDC000884,0xFDB007C1,0x5D80882,0xF5B80802,0xFF94069A,0xFF68053D,0xFF1802A1,0xFEB80000,0xFE0C0000,0xFDA807C1,0xFF880665,0xFEF00049,0xDC000884,0xC1FC0882,0xAC0A69,0xAC0A69,0xAC0A69,0xAC0A69,0xAC0A69,0xAC0A69,0xAC0A69,0xAC0A69,0xAC0A69,0xAC0A69,0xFE680014,0xFE680014,0xFE680014,0xFE680014,0xFE680014,
-0xFE680014,0x9E640000,0x9E640000,0x9E640000,0x7A640000,0x1000A69,0x1000A69,0x1000A69,0x1000A69,0x1000A69,0x1000A69,0xAE00004A,0xAE00004A,0xAE00004A,0x7A1C0000,0x5F80A69,0x5F80A69,0x5F80A69,0x6C0002D5,0x56000A69,0xF8A00784,0xAC0A69,0xAC0A69,0xFE900455,0xFE800254,0xFE7800DD,0xFE7800DD,0xE4640000,0xFA880692,0xFE7803F5,0xC4500000,0xAE00004A,
-0x16C0A69,};
-static const uint32_t g_etc1_to_bc7_m6_table212[] = {
-0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0xB00000,0x1640000,
-0x1640000,0x1640000,0x1640000,0x3A000000,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x740001,0x67C0000,0x67C0000,0x67C0000,0xB00000,0xF80000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1080000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,
-0x1880000,0x49F80000,0x49F80000,0x49F80000,0x82000001,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x1880000,0x49F80000,0x49F80000,0x49F80000,0x82000001,0x49F80000,0x49F80000,0x49F80000,0x82000001,0x82000001,0x5180000,0x1080000,0x1080000,0x1340000,0x14C0000,0x1680000,0x1680000,0x1BC0000,0x1340000,0x14C0000,0x19FC0000,0x49F80000,
-0x19FC0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x53FC0000,0x53FC0000,0x53FC0000,0xABF80000,0xABF80000,0xC4000001,0x53FC0000,0x53FC0000,0x53FC0000,0xABF80000,0xABF80000,0xC4000001,0xABF80000,0xABF80000,0xC4000001,0xC4000001,0x53FC0000,0x53FC0000,0x53FC0000,0xABF80000,0xABF80000,0xC4000001,0xABF80000,0xABF80000,0xC4000001,0xC4000001,0xABF80000,
-0xABF80000,0xC4000001,0xC4000001,0xC4000001,0x1CC0000,0xBA40000,0x18C0000,0x2BFC0000,0x73FC0000,0x95FC0000,0x9FFC0000,0xB3F40000,0x1F00000,0x53FC0000,0x95FC0000,0xC4000001,0x95FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x14053CE,0xFF243DB6,0xFF082C15,0xFF0425C5,0xFF0C31DE,0xFEE41AFD,0xFEDC124D,0xFECC14B2,0xFCC00A76,0xE2C010C2,0xFEF436F6,0xFEC01AAD,0xFEB00F93,0xFE940E7F,0xFE800056,0xE488072F,0xFE7C1DBE,0xEC680AE9,0xD8640AE2,0xC2741D9B,0x3DC53CA,0xFEA03317,0xFE8825C6,0xFE641FF2,0xFE2C0BDE,0xE23C10C2,0xFE14260B,0xF4000A9F,0xDA000853,0xC2001DB3,0x73FC53CA,
-0xDC002E39,0xCA0021E2,0xB2002F23,0xA00053CA,0xFF204186,0xFF2C4DB2,0xF9404F7E,0xFF002E66,0xFED01ABC,0xFEA4092A,0xFE900243,0xFA700023,0xFF10407E,0xFEDC2BAA,0xFE700975,0xDA000853,0x4FFC53CA,0x1841D9D,0xFF681408,0xFF580BBD,0xFF480884,0xFF501235,0xFF2C068C,0xFF2401C4,0xFF140731,0xF90000AD,0xE3080659,0x49FC1D9A,0xFF140F18,0xFEF00884,0xFECC0B85,0xFE940005,
-0xE2AC0659,0xA7F81D9A,0xF80008AE,0xDC000795,0xC2001D9A,0x49FC1D9A,0xFF140F18,0xFEF00884,0xFECC0B85,0xFE940005,0xE2AC0659,0xA7F81D9A,0xF80008AE,0xDC000795,0xC2001D9A,0xA7F81D9A,0xF80008AE,0xDC000795,0xC2001D9A,0xC2001D9A,0xFF7418F9,0xF9801BAD,0xFB841BC5,0xFF40137A,0xFF100CD4,0xFEDC04E3,0xFEBC0059,0xFE5C0002,0xFF5C18D2,0xFF401296,0xFE7C0912,0xDC000795,
-0x8FFC1D9A,0x10425C5,0x10425C5,0x10425C5,0x10425C5,0xFEDC124D,0xFEDC124D,0xFEDC124D,0xF6C00A6A,0xF6C00A6A,0xC4C00A6A,0xFEB00F93,0xFEB00F93,0xFEB00F93,0xFE800056,0xFE800056,0xCA8C01D6,0xD8740883,0xD8740883,0xBC700103,0xA4740883,0x38025C5,0x38025C5,0x38025C5,0xFE2C0BDE,0xFE2C0BDE,0xC45C0A6A,0xEE000A0B,0xEE000A0B,0xC2000023,0xA40C0883,0x45FC25C5,
-0x45FC25C5,0xAC001022,0x960010EE,0x800025C6,0xFEE81BE6,0xF6FC21AD,0x10425C5,0xFECC134A,0xFEB00A91,0xFE98043A,0xFE900243,0xF674000B,0xFED01B16,0xFEB01226,0xFE6808D8,0xC2000023,0x15FC25C5,0x1480884,0x1480884,0x1480884,0x1480884,0xFF2401C4,0xFF2401C4,0xFF2401C4,0xE5080001,0xE5080001,0xC5080001,0x3E80882,0x3E80882,0x3E80882,0xFE940005,0xFE940005,
-0xC4C80001,0x79FC0882,0x79FC0882,0xC4000001,0xA4000882,0x3E80882,0x3E80882,0x3E80882,0xFE940005,0xFE940005,0xC4C80001,0x79FC0882,0x79FC0882,0xC4000001,0xA4000882,0x79FC0882,0x79FC0882,0xC4000001,0xA4000882,0xA4000882,0xFB340694,0xFB440708,0x1480884,0xFF180519,0xFEF002F2,0xFEC80151,0xFEBC0059,0xFA640000,0xF92806CD,0xFF0404EA,0x57FC0882,0xC4000001,
-0x57FC0882,0x1C40659,0xFFB003E8,0xFF940131,0xFF8C0000,0xA9FC0659,0xFF700262,0xFF540000,0xD5F80659,0xFEA00000,0xE2000659,0xA9FC0659,0xFF700262,0xFF540000,0xD5F80659,0xFEA00000,0xE2000659,0xD5F80659,0xFEA00000,0xE2000659,0xE2000659,0xA9FC0659,0xFF700262,0xFF540000,0xD5F80659,0xFEA00000,0xE2000659,0xD5F80659,0xFEA00000,0xE2000659,0xE2000659,0xD5F80659,
-0xFEA00000,0xE2000659,0xE2000659,0xE2000659,0xFFB405BA,0x1E40659,0xFBC405E9,0xFFA004F4,0xFF7C03E8,0xFF2C01F9,0xFEE40000,0xFE500000,0xFFAC05C4,0xFF9404C9,0xFF100032,0xE2000659,0xC9FC0659,0xC00A69,0xC00A69,0xC00A69,0xC00A69,0xC00A69,0xC00A69,0xC00A69,0xC00A69,0xC00A69,0xC00A69,0xFE800032,0xFE800032,0xFE800032,0xFE800032,0xFE800032,
-0xFE800032,0xA6780001,0xA6780001,0xA6780001,0x82740002,0x11C0A69,0x11C0A69,0x11C0A69,0x11C0A69,0x11C0A69,0x11C0A69,0xC0000014,0xC0000014,0xC0000014,0x82300001,0x11FC0A69,0x11FC0A69,0x11FC0A69,0x7800025D,0x5E000A69,0xFEAC07A2,0xC00A69,0xC00A69,0xFEA00492,0xFE94029A,0xFE880115,0xFE880115,0xEC780001,0xFE9006C4,0xFC900451,0xCC640001,0xC0000014,
-0x1940A69,};
-static const uint32_t g_etc1_to_bc7_m6_table213[] = {
-0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x2C40000,0x2C40000,0x2C40000,0x2C40000,0x2C40000,0x2C40000,0x2C40000,0x2C40000,0x2C40000,0x2C40000,0x1940000,
-0x1940000,0x1940000,0x1940000,0x42000000,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0x840001,0xE8C0000,0xE8C0000,0xE8C0000,0x2C40000,0x11C0000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1180000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,
-0x1A00000,0x55F80000,0x55F80000,0x55F80000,0x8A000001,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x55F80000,0x55F80000,0x55F80000,0x8A000001,0x55F80000,0x55F80000,0x55F80000,0x8A000001,0x8A000001,0xD280000,0x1180000,0x1180000,0x3440000,0x1600000,0x17C0000,0x17C0000,0x3D40000,0x3440000,0x1600000,0x27FC0000,0x55F80000,
-0x27FC0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0xB7F80000,0xB7F80000,0xCC000001,0x6BFC0000,0x6BFC0000,0x6BFC0000,0xB7F80000,0xB7F80000,0xCC000001,0xB7F80000,0xB7F80000,0xCC000001,0xCC000001,0x6BFC0000,0x6BFC0000,0x6BFC0000,0xB7F80000,0xB7F80000,0xCC000001,0xB7F80000,0xB7F80000,0xCC000001,0xCC000001,0xB7F80000,
-0xB7F80000,0xCC000001,0xCC000001,0xCC000001,0x1E00000,0x1B80000,0x19C0000,0x49FC0000,0x87FC0000,0xA3FC0000,0xADFC0000,0xBDF80000,0x11FC0000,0x6BFC0000,0xA3FC0000,0xCC000001,0xA3FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x14C4E1E,0xFF303AC6,0xFF202B4D,0xFF1425C5,0xFF182F0A,0xFEF81ADB,0xFEE81331,0xFED81392,0xFED00A6A,0xE6D00F1A,0xFF003356,0xFED81A55,0xFEC41065,0xFEAC0D5F,0xFE9400C6,0xE898059E,0xFE941A6E,0xF07C0A01,0xDC7808A6,0xC8841A07,0x1F04E1A,0xFEB8315F,0xFEA025C6,0xFE7C1E4A,0xFE4C0C89,0xE6500F1A,0xFE2C231B,0xFA000993,0xE0000597,0xC8041A06,0x7DF84E1A,
-0xE0002B5E,0xD0001D1E,0xB8002977,0xA6004E1A,0xFF343DC5,0xFD48484A,0xFF4C4A16,0xFF082C34,0xFEE01A1E,0xFEB809A4,0xFEA4032A,0xFE84000B,0xFF183CC9,0xFEF429C3,0xFE7C09C3,0xE0000597,0x5BFC4E1A,0x1901A05,0xFF741218,0xFF640B25,0xFF580884,0xFF5C1001,0xFF400632,0xFF300220,0xFF2005C9,0xFB100051,0xE71804B1,0x59FC1A05,0xFF200DF4,0xFF080884,0xFEE409DD,0xFEAC0025,
-0xE6C004B1,0xADFC1A05,0xFE080882,0xE0000566,0xC8001A06,0x59FC1A05,0xFF200DF4,0xFF080884,0xFEE409DD,0xFEAC0025,0xE6C004B1,0xADFC1A05,0xFE080882,0xE0000566,0xC8001A06,0xADFC1A05,0xFE080882,0xE0000566,0xC8001A06,0xC8001A06,0xFF7815DA,0xFF8C182D,0xFF8C185D,0xFF5C114D,0xFF280B9E,0xFEF0049D,0xFED000A0,0xFE7C0004,0xFD74161E,0xFF481074,0xFEA008FB,0xE0000566,
-0x99FC1A05,0x11425C5,0x11425C5,0x11425C5,0x11425C5,0xFEE81331,0xFEE81331,0xFEE81331,0xFED00A6A,0xFED00A6A,0xCCD00A6A,0xFEC41065,0xFEC41065,0xFEC41065,0xFE9400C6,0xFE9400C6,0xD29C01D6,0xE0840883,0xE0840883,0xC4800103,0xAC840883,0x39825C5,0x39825C5,0x39825C5,0xFE4C0C89,0xFE4C0C89,0xCC6C0A6A,0xFA000983,0xFA000983,0xCE000003,0xAC1C0883,0x51FC25C5,
-0x51FC25C5,0xB2000F62,0x9C001026,0x880025C6,0xFD001CA9,0xFF0C21AD,0x11425C5,0xFEDC144E,0xFEC40BB5,0xFEAC053E,0xFEA4032A,0xFE84000B,0xFEE41BE5,0xFED012ED,0xFE7C0933,0xCE000003,0x23FC25C5,0x1580884,0x1580884,0x1580884,0x1580884,0xFF300220,0xFF300220,0xFF300220,0xED180001,0xED180001,0xCD180001,0x7FC0882,0x7FC0882,0x7FC0882,0xFEAC0025,0xFEAC0025,
-0xCCD80001,0x85FC0882,0x85FC0882,0xCC0C0001,0xAC000882,0x7FC0882,0x7FC0882,0x7FC0882,0xFEAC0025,0xFEAC0025,0xCCD80001,0x85FC0882,0x85FC0882,0xCC0C0001,0xAC000882,0x85FC0882,0x85FC0882,0xCC0C0001,0xAC000882,0xAC000882,0xFF3C06C4,0xFF4C0728,0x1580884,0xFF24057A,0xFF040352,0xFEE4019A,0xFED000A0,0xFE7C0004,0xFF3406D1,0xFF180521,0x65FC0882,0xCC0C0001,
-0x65FC0882,0x1CC04B1,0xFFBC02E4,0xFFA000E5,0xFF9C0000,0xB5FC04B1,0xFF8801BA,0xFF6C0000,0xDBF804B1,0xFED40000,0xE60004B1,0xB5FC04B1,0xFF8801BA,0xFF6C0000,0xDBF804B1,0xFED40000,0xE60004B1,0xDBF804B1,0xFED40000,0xE60004B1,0xE60004B1,0xB5FC04B1,0xFF8801BA,0xFF6C0000,0xDBF804B1,0xFED40000,0xE60004B1,0xDBF804B1,0xFED40000,0xE60004B1,0xE60004B1,0xDBF804B1,
-0xFED40000,0xE60004B1,0xE60004B1,0xE60004B1,0xF9C40451,0x1EC04B1,0xFFCC0451,0xFFB003A1,0xFF9002E4,0xFF480168,0xFF0C0000,0xFE8C0000,0xF3C40451,0xFFA00392,0xFF300025,0xE60004B1,0xD1FC04B1,0xD00A69,0xD00A69,0xD00A69,0xD00A69,0xD00A69,0xD00A69,0xD00A69,0xD00A69,0xD00A69,0xD00A69,0xFE900059,0xFE900059,0xFE900059,0xFE900059,0xFE900059,
-0xFE900059,0xAE880001,0xAE880001,0xAE880001,0x8A840002,0x1340A69,0x1340A69,0x1340A69,0x1340A69,0x1340A69,0x1340A69,0xCE000002,0xCE000002,0xCE000002,0x8A400001,0x1DFC0A69,0x1DFC0A69,0x1DFC0A69,0x7E0001ED,0x66000A69,0xFAC407C1,0xD00A69,0xD00A69,0xFCB804E2,0xFEA802DA,0xFE980151,0xFE980151,0xF4880001,0xFEAC0708,0xFEA00480,0xD4740001,0xCE000002,
-0x1B40A69,};
-static const uint32_t g_etc1_to_bc7_m6_table214[] = {
-0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x2DC0000,0x1C40000,
-0x1C40000,0x1C40000,0x1C40000,0x4A000000,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0x940001,0xA00000,0xA00000,0xA00000,0x2DC0000,0x13C0000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,
-0x1B80000,0x61F80000,0x61F80000,0x61F80000,0x92000001,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x61F80000,0x61F80000,0x61F80000,0x92000001,0x61F80000,0x61F80000,0x61F80000,0x92000001,0x92000001,0x13C0000,0x1280000,0x1280000,0x1580000,0x1740000,0x3900000,0x3900000,0x1F00000,0x1580000,0x1740000,0x37FC0000,0x61F80000,
-0x37FC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x83FC0000,0x83FC0000,0x83FC0000,0xC3F80000,0xC3F80000,0xD4000001,0x83FC0000,0x83FC0000,0x83FC0000,0xC3F80000,0xC3F80000,0xD4000001,0xC3F80000,0xC3F80000,0xD4000001,0xD4000001,0x83FC0000,0x83FC0000,0x83FC0000,0xC3F80000,0xC3F80000,0xD4000001,0xC3F80000,0xC3F80000,0xD4000001,0xD4000001,0xC3F80000,
-0xC3F80000,0xD4000001,0xD4000001,0xD4000001,0x3F00000,0x1C80000,0x1AC0000,0x67FC0000,0x9BFC0000,0xB3FC0000,0xBBFC0000,0xC7FC0000,0x37FC0000,0x83FC0000,0xB3FC0000,0xD4000001,0xB3FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x15848CE,0xFF4437E9,0xFF2C2A81,0xFF2425C5,0xFF242C86,0xFF081AD5,0xFF001419,0xFEF01292,0xFEE00A8D,0xEAE00DB2,0xFF0C301E,0xFEE41A29,0xFEDC116D,0xFEB80CB3,0xFEAC016E,0xEAA8045E,0xFEA0178E,0xF4900951,0xE088069F,0xCC9416C7,0x7FC48CA,0xFECC3001,0xFEB825C6,0xFE941CE2,0xFE640D49,0xEA640DB2,0xFE3820BF,0xFE08097B,0xE6000393,0xCC1816C6,0x85FC48CA,
-0xE600290A,0xD60018EA,0xBE002443,0xAC0048CA,0xFF3C39F6,0xFF4C436A,0xFF4C4586,0xFF182A0A,0xFEF419AA,0xFEC80A63,0xFEBC0422,0xFE9C0031,0xFF34391E,0xFF0027C6,0xFE940A51,0xE6000393,0x65FC48CA,0x19C16C5,0xFF801058,0xFF700AA5,0xFF680884,0xFF740E01,0xFF5405F4,0xFF44027D,0xFF380491,0xFD240018,0xEB280349,0x6BFC16C5,0xFF380CE4,0xFF200884,0xFEFC0875,0xFECC0061,
-0xEAD40349,0xB7F816C5,0xFE380882,0xE6000392,0xCC0016C6,0x6BFC16C5,0xFF380CE4,0xFF200884,0xFEFC0875,0xFECC0061,0xEAD40349,0xB7F816C5,0xFE380882,0xE6000392,0xCC0016C6,0xB7F816C5,0xFE380882,0xE6000392,0xCC0016C6,0xCC0016C6,0xFF80136D,0xFF8C154D,0xF59815A4,0xFF6C0F72,0xFF480A86,0xFF040496,0xFEE800FA,0xFEA00022,0xFF781352,0xFF5C0EC6,0xFED008E5,0xE6000392,
-0xA3FC16C5,0x12425C5,0x12425C5,0x12425C5,0x12425C5,0xFF001419,0xFF001419,0xFF001419,0xFEE00A8D,0xFEE00A8D,0xD4E00A6A,0xFEDC116D,0xFEDC116D,0xFEDC116D,0xFEAC016E,0xFEAC016E,0xDAAC01D6,0xE8940883,0xE8940883,0xCC900103,0xB4940883,0x3B025C5,0x3B025C5,0x3B025C5,0xFE640D49,0xFE640D49,0xD47C0A6A,0xFE08097B,0xFE08097B,0xD6100003,0xB42C0883,0x5DFC25C5,
-0x5DFC25C5,0xBE000E9A,0xA6000F63,0x900025C6,0xFF101D2B,0xF920222A,0x12425C5,0xFEF81556,0xFED80CE9,0xFEBC0666,0xFEBC0422,0xFE9C0031,0xFEF81C56,0xFEDC1421,0xFE9409D8,0xD6100003,0x33FC25C5,0x1680884,0x1680884,0x1680884,0x1680884,0xFF44027D,0xFF44027D,0xFF44027D,0xF5280001,0xF5280001,0xD5280001,0x1FFC0882,0x1FFC0882,0x1FFC0882,0xFECC0061,0xFECC0061,
-0xD4E80001,0x91FC0882,0x91FC0882,0xD41C0001,0xB4000882,0x1FFC0882,0x1FFC0882,0x1FFC0882,0xFECC0061,0xFECC0061,0xD4E80001,0x91FC0882,0x91FC0882,0xD41C0001,0xB4000882,0x91FC0882,0x91FC0882,0xD41C0001,0xB4000882,0xB4000882,0xFF5806CD,0xFB640745,0x1680884,0xFF4405B2,0xFF1803BA,0xFEFC01F9,0xFEE800FA,0xFEA00022,0xFD4C0708,0xFF300581,0x75FC0882,0xD41C0001,
-0x75FC0882,0x1D40349,0xFFC401F9,0xFFB8009D,0xFFAC0000,0xC1FC0349,0xFFA00132,0xFF840000,0xE1F80349,0xFF040000,0xEA000349,0xC1FC0349,0xFFA00132,0xFF840000,0xE1F80349,0xFF040000,0xEA000349,0xE1F80349,0xFF040000,0xEA000349,0xEA000349,0xC1FC0349,0xFFA00132,0xFF840000,0xE1F80349,0xFF040000,0xEA000349,0xE1F80349,0xFF040000,0xEA000349,0xEA000349,0xE1F80349,
-0xFF040000,0xEA000349,0xEA000349,0xEA000349,0xFDCC02F9,0x1F40349,0xFFCC0311,0xFFC00288,0xFFA80202,0xFF700104,0xFF340000,0xFEC80000,0xF7CC02F9,0xFDBC0288,0xFF500019,0xEA000349,0xD9FC0349,0xE00A69,0xE00A69,0xE00A69,0xE00A69,0xE00A69,0xE00A69,0xE00A69,0xE00A69,0xE00A69,0xE00A69,0xFEA40082,0xFEA40082,0xFEA40082,0xFEA40082,0xFEA40082,
-0xFEA40082,0xB6980001,0xB6980001,0xB6980001,0x92940002,0x1480A69,0x1480A69,0x1480A69,0x1480A69,0x1480A69,0x1480A69,0xD80C0000,0xD80C0000,0xD80C0000,0x92500001,0x29FC0A69,0x29FC0A69,0x29FC0A69,0x8A000195,0x6E000A69,0xFECC07E9,0xE00A69,0xE00A69,0xFCC80515,0xFEB40321,0xFEAC019A,0xFEAC019A,0xFC980001,0xFEBC070A,0xFEB404B1,0xDC840001,0xD80C0000,
-0x1D80A69,};
-static const uint32_t g_etc1_to_bc7_m6_table215[] = {
-0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x2F40000,0x1F40000,
-0x1F40000,0x1F40000,0x1F40000,0x52000000,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xA40001,0xB00000,0xB00000,0xB00000,0x2F40000,0x1600000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1380000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,
-0x1D00000,0x6DF80000,0x6DF80000,0x6DF80000,0x9A000001,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x1D00000,0x6DF80000,0x6DF80000,0x6DF80000,0x9A000001,0x6DF80000,0x6DF80000,0x6DF80000,0x9A000001,0x9A000001,0x14C0000,0x1380000,0x1380000,0x7680000,0x1880000,0x1A80000,0x1A80000,0xDFC0000,0x7680000,0x1880000,0x45FC0000,0x6DF80000,
-0x45FC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0xCFF80000,0xCFF80000,0xDC000001,0x9BFC0000,0x9BFC0000,0x9BFC0000,0xCFF80000,0xCFF80000,0xDC000001,0xCFF80000,0xCFF80000,0xDC000001,0xDC000001,0x9BFC0000,0x9BFC0000,0x9BFC0000,0xCFF80000,0xCFF80000,0xDC000001,0xCFF80000,0xCFF80000,0xDC000001,0xDC000001,0xCFF80000,
-0xCFF80000,0xDC000001,0xDC000001,0xDC000001,0x17FC0000,0x5D80000,0x1BC0000,0x85FC0000,0xAFFC0000,0xC1FC0000,0xC9F80000,0xD3F80000,0x5FFC0000,0x9BFC0000,0xC1FC0000,0xDC000001,0xC1FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x16443DE,0xFF503551,0xFF3829D5,0xFF3425C5,0xFF302A52,0xFF181AE5,0xFF0C150D,0xFEFC11F2,0xFEF00AE2,0xEEF00C8A,0xFF242D36,0xFEFC1A11,0xFEE81275,0xFED80C52,0xFEC00252,0xEEBC035E,0xFEB8151E,0xF8A408D9,0xE69404F3,0xD2A413DB,0x19FC43DA,0xFEE42E81,0xFED025C5,0xFEAC1BBA,0xFE7C0E29,0xEE780C8A,0xFE641E91,0xFE200A1B,0xEC0C023F,0xD22813DA,0x8FF843DA,
-0xF0002759,0xDC001546,0xC4001F87,0xB20043DA,0xFF4C36D3,0xF9603F4E,0xFB6440F5,0xFF2C286E,0xFF04195C,0xFEDC0B1C,0xFED00559,0xFEB00092,0xFF3435BE,0xFF102642,0xFEB00AE7,0xEC0C023F,0x71FC43DA,0x1A413DD,0xFF8C0EC8,0xFF7C0A3D,0xFF780884,0xFF800C45,0xFF6405BE,0xFF5C02FD,0xFF4C03BD,0xFF380001,0xEF380221,0x7BFC13DA,0xFF4C0C13,0xFF380884,0xFF14074D,0xFEE400B9,
-0xEEE80221,0xBFF813DA,0xFE6C0882,0xEC00022E,0xD20013DA,0x7BFC13DA,0xFF4C0C13,0xFF380884,0xFF14074D,0xFEE400B9,0xEEE80221,0xBFF813DA,0xFE6C0882,0xEC00022E,0xD20013DA,0xBFF813DA,0xFE6C0882,0xEC00022E,0xD20013DA,0xD20013DA,0xFF9410EE,0xF9A01299,0xFBA412D8,0xFF780DD1,0xFF5C09A6,0xFF240491,0xFF0C0164,0xFEB80068,0xFF8810FD,0xFF680D52,0xFEE408D3,0xEC00022E,
-0xADFC13DA,0x13425C5,0x13425C5,0x13425C5,0x13425C5,0xFF0C150D,0xFF0C150D,0xFF0C150D,0xFEF00AE2,0xFEF00AE2,0xDCF00A6A,0xFEE81275,0xFEE81275,0xFEE81275,0xFEC00252,0xFEC00252,0xE2BC01D6,0xF0A40883,0xF0A40883,0xD4A00103,0xBCA40883,0x1C825C5,0x1C825C5,0x1C825C5,0xFE7C0E29,0xFE7C0E29,0xDC8C0A6A,0xFE200A1B,0xFE200A1B,0xDE200003,0xBC3C0883,0x69FC25C5,
-0x69FC25C5,0xCA000DF2,0xB2000EA3,0x980025C6,0xFF201DA6,0xFF2C222E,0x13425C5,0xFF081643,0xFEEC0E2D,0xFED407CE,0xFED00559,0xFEB00092,0xFF141D18,0xFEF41512,0xFEB00A83,0xDE200003,0x41FC25C5,0x1780884,0x1780884,0x1780884,0x1780884,0xFF5C02FD,0xFF5C02FD,0xFF5C02FD,0xFD380001,0xFD380001,0xDD380001,0x37FC0882,0x37FC0882,0x37FC0882,0xFEE400B9,0xFEE400B9,
-0xDCF80001,0x9DFC0882,0x9DFC0882,0xDC2C0001,0xBC000882,0x37FC0882,0x37FC0882,0x37FC0882,0xFEE400B9,0xFEE400B9,0xDCF80001,0x9DFC0882,0x9DFC0882,0xDC2C0001,0xBC000882,0x9DFC0882,0x9DFC0882,0xDC2C0001,0xBC000882,0xBC000882,0xFB6C0708,0xFF6C076D,0x1780884,0xFD5805E9,0xFF400422,0xFF20028A,0xFF0C0164,0xFEB80068,0xF5640745,0xFF4805B4,0x83FC0882,0xDC2C0001,
-0x83FC0882,0x1DC0221,0xFFD00145,0xFFC00068,0xFFBC0000,0xCDFC0221,0xFFAC00C2,0xFF9C0000,0xE7F80221,0xFF340000,0xEE000221,0xCDFC0221,0xFFAC00C2,0xFF9C0000,0xE7F80221,0xFF340000,0xEE000221,0xE7F80221,0xFF340000,0xEE000221,0xEE000221,0xCDFC0221,0xFFAC00C2,0xFF9C0000,0xE7F80221,0xFF340000,0xEE000221,0xE7F80221,0xFF340000,0xEE000221,0xEE000221,0xE7F80221,
-0xFF340000,0xEE000221,0xEE000221,0xEE000221,0xFFD001ED,0x1FC0221,0xF7DC0200,0xFFC001A8,0xFFA80152,0xFF8400A0,0xFF5C0000,0xFF040000,0xFBD401E1,0xFFC00190,0xFF700010,0xEE000221,0xDFFC0221,0xF00A69,0xF00A69,0xF00A69,0xF00A69,0xF00A69,0xF00A69,0xF00A69,0xF00A69,0xF00A69,0xF00A69,0xFEB400C1,0xFEB400C1,0xFEB400C1,0xFEB400C1,0xFEB400C1,
-0xFEB400C1,0xBEA80001,0xBEA80001,0xBEA80001,0x9AA40002,0x1600A69,0x1600A69,0x1600A69,0x1600A69,0x1600A69,0x1600A69,0xE01C0000,0xE01C0000,0xE01C0000,0x9A600001,0x35FC0A69,0x35FC0A69,0x35FC0A69,0x9000013D,0x76000A69,0xFAE40802,0xF00A69,0xF00A69,0xFED8054A,0xFED00372,0xFEC401E1,0xFEC401E1,0xFCA8000A,0xFAD00745,0xFEBC0502,0xE4940001,0xE01C0000,
-0x1F80A69,};
-static const uint32_t g_etc1_to_bc7_m6_table216[] = {
-0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0x1100000,0xDFC0000,
-0xDFC0000,0xDFC0000,0xDFC0000,0x5A000001,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xB80000,0xC40000,0xC40000,0xC40000,0x1100000,0x1880000,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x1480001,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,
-0x3E80000,0x79FC0000,0x79FC0000,0x79FC0000,0xA4000000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x3E80000,0x79FC0000,0x79FC0000,0x79FC0000,0xA4000000,0x79FC0000,0x79FC0000,0x79FC0000,0xA4000000,0xA4000000,0x1600000,0x1480001,0x1480001,0x1800000,0x39C0000,0x1C00000,0x1C00000,0x23FC0000,0x1800000,0x39C0000,0x57FC0000,0x79FC0000,
-0x57FC0000,0x1CC0001,0x1CC0001,0x1CC0001,0x1CC0001,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xDDF40000,0xDDF40000,0xE6000000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xDDF40000,0xDDF40000,0xE6000000,0xDDF40000,0xDDF40000,0xE6000000,0xE6000000,0xB7FC0000,0xB7FC0000,0xB7FC0000,0xDDF40000,0xDDF40000,0xE6000000,0xDDF40000,0xDDF40000,0xE6000000,0xE6000000,0xDDF40000,
-0xDDF40000,0xE6000000,0xE6000000,0xE6000000,0x57FC0000,0x1EC0000,0x1CC0001,0xA7FC0000,0xC5FC0000,0xD3FC0000,0xD7FC0000,0xDFF80000,0x8BFC0000,0xB7FC0000,0xD3FC0000,0xE6000000,0xD3FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1743EBF,0xFF5C32AA,0xFF4C292F,0xFF4425C6,0xFF4427D5,0xFF301B26,0xFF24162E,0xFF141185,0xFF080B81,0xF3000B89,0xFF302A4B,0xFF101A25,0xFF0013B2,0xFEE40C25,0xFED80391,0xF6CC0285,0xFECC130C,0xFCB8088E,0xEAA80370,0xD8B810F8,0x2FFC3EBF,0xFEFC2CFE,0xFEEC25C5,0xFEB81ACB,0xFEA00F3A,0xF2900B89,0xFE881C84,0xFE380B28,0xF0200130,0xD83C10F9,0x99FC3EBF,
-0xF8002621,0xE0001205,0xD0001AB8,0xB8003EC1,0xFF583335,0xFF6C3A65,0xFF6C3C36,0xFF4026D4,0xFF181935,0xFEF00C2B,0xFEE806D0,0xFEC00164,0xFF50326B,0xFF3024FE,0xFEBC0BFE,0xF0200130,0x7FF83EBF,0x1B010FB,0xFFA40D26,0xFF9409C3,0xFF8C0882,0xFF8C0AA9,0xFF7405AE,0xFF680385,0xFF580313,0xFF4C001A,0xF3480121,0x8DFC10F8,0xFF640B25,0xFF540882,0xFF2C0651,0xFF080131,
-0xF2FC0121,0xC7FC10F8,0xFEA00882,0xF2080120,0xD80010F8,0x8DFC10F8,0xFF640B25,0xFF540882,0xFF2C0651,0xFF080131,0xF2FC0121,0xC7FC10F8,0xFEA00882,0xF2080120,0xD80010F8,0xC7FC10F8,0xFEA00882,0xF2080120,0xD80010F8,0xD80010F8,0xFFA00E9D,0xFFAC0FC9,0xFFAC1026,0xFF880C23,0xFF6808C1,0xFF380495,0xFF2801E2,0xFEE400CD,0xFF980EBE,0xFF840BB2,0xFF1008B5,0xF2080120,
-0xB9FC10F8,0x14425C6,0x14425C6,0x14425C6,0x14425C6,0xFF24162E,0xFF24162E,0xFF24162E,0xFF080B81,0xFF080B81,0xE7000A69,0xFF0013B2,0xFF0013B2,0xFF0013B2,0xFED80391,0xFED80391,0xECD001D5,0xF8B80884,0xF8B80884,0xDCB00104,0xC4B80884,0x1E425C5,0x1E425C5,0x1E425C5,0xFEA00F3A,0xFEA00F3A,0xE69C0A69,0xFE380B28,0xFE380B28,0xE6340002,0xC4500884,0x77F825C5,
-0x77F825C5,0xD6000D49,0xB8000DD4,0xA20025C5,0xFF2C1E68,0xF94022AA,0x14425C6,0xFF181761,0xFF000FB2,0xFEF00952,0xFEE806D0,0xFEC00164,0xFF201DB2,0xFF101682,0xFEBC0B9A,0xE6340002,0x53FC25C5,0x18C0882,0x18C0882,0x18C0882,0x18C0882,0xFF680385,0xFF680385,0xFF680385,0xFF4C001A,0xFF4C001A,0xE7480001,0x53FC0882,0x53FC0882,0x53FC0882,0xFF080131,0xFF080131,
-0xE7080001,0xABF80882,0xABF80882,0xE63C0000,0xC4000884,0x53FC0882,0x53FC0882,0x53FC0882,0xFF080131,0xFF080131,0xE7080001,0xABF80882,0xABF80882,0xE63C0000,0xC4000884,0xABF80882,0xABF80882,0xE63C0000,0xC4000884,0xC4000884,0xFF74073A,0xFD880782,0x18C0882,0xFB700659,0xFF540488,0xFF300304,0xFF2801E2,0xFEE400CD,0xFD740745,0xFF5C05F5,0x95FC0882,0xE63C0000,
-0x95FC0882,0x1E40122,0xFFDC00AA,0xFFD4003A,0xFFCC0001,0xDBFC0120,0xFFC0006D,0xFFB80000,0xEDFC0120,0xFF6C0000,0xF2000120,0xDBFC0120,0xFFC0006D,0xFFB80000,0xEDFC0120,0xFF6C0000,0xF2000120,0xEDFC0120,0xFF6C0000,0xF2000120,0xF2000120,0xDBFC0120,0xFFC0006D,0xFFB80000,0xEDFC0120,0xFF6C0000,0xF2000120,0xEDFC0120,0xFF6C0000,0xF2000120,0xF2000120,0xEDFC0120,
-0xFF6C0000,0xF2000120,0xF2000120,0xF2000120,0xF5E40109,0x47FC0120,0xFBE40109,0xFFD800DD,0xFFCC00B5,0xFFAC0059,0xFF880000,0xFF480000,0xFFDC00F4,0xFFCC00DA,0xFF980009,0xF2000120,0xE9FC0120,0x1000A69,0x1000A69,0x1000A69,0x1000A69,0x1000A69,0x1000A69,0x1000A69,0x1000A69,0x1000A69,0x1000A69,0xFEC80104,0xFEC80104,0xFEC80104,0xFEC80104,0xFEC80104,
-0xFEC80104,0xC8B80000,0xC8B80000,0xC8B80000,0xA4B80000,0x17C0A69,0x17C0A69,0x17C0A69,0x17C0A69,0x17C0A69,0x17C0A69,0xEA2C0000,0xEA2C0000,0xEA2C0000,0xA4700000,0x43F80A69,0x43F80A69,0x43F80A69,0x9C0000E9,0x80000A69,0xF4F80841,0x1000A69,0x1000A69,0xFEE80589,0xFEE403C8,0xFED4022D,0xFED4022D,0xFEC00020,0xFED80781,0xFED0053D,0xEEA40000,0xEA2C0000,
-0x11FC0A69,};
-static const uint32_t g_etc1_to_bc7_m6_table217[] = {
-0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x1280000,0x19FC0000,
-0x19FC0000,0x19FC0000,0x19FC0000,0x62000001,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0x2D40000,0x2D40000,0x2D40000,0x1280000,0x1A80000,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x1580001,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,
-0x7FC0000,0x85FC0000,0x85FC0000,0x85FC0000,0xAC000000,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x7FC0000,0x85FC0000,0x85FC0000,0x85FC0000,0xAC000000,0x85FC0000,0x85FC0000,0x85FC0000,0xAC000000,0xAC000000,0x1700000,0x1580001,0x1580001,0x5900000,0x3B00000,0x3D40000,0x3D40000,0x37FC0000,0x5900000,0x3B00000,0x65FC0000,0x85FC0000,
-0x65FC0000,0x1DC0001,0x1DC0001,0x1DC0001,0x1DC0001,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xE7FC0000,0xE7FC0000,0xEE000000,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xE7FC0000,0xE7FC0000,0xEE000000,0xE7FC0000,0xE7FC0000,0xEE000000,0xEE000000,0xCFFC0000,0xCFFC0000,0xCFFC0000,0xE7FC0000,0xE7FC0000,0xEE000000,0xE7FC0000,0xE7FC0000,0xEE000000,0xEE000000,0xE7FC0000,
-0xE7FC0000,0xEE000000,0xEE000000,0xEE000000,0x91FC0000,0x7FC0000,0x1DC0001,0xC5FC0000,0xD9FC0000,0xE1FC0000,0xE5FC0000,0xE9FC0000,0xB3FC0000,0xCFFC0000,0xE1FC0000,0xEE000000,0xE1FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1803A9B,0xFF68308E,0xFF5828A3,0xFF5425C6,0xFF502631,0xFF3C1B66,0xFF301742,0xFF201179,0xFF140C51,0xF7100AE9,0xFF4427DC,0xFF241A56,0xFF1814E2,0xFEFC0C45,0xFEE404F1,0xF8DC020D,0xFEE4119C,0xFECC0888,0xEEBC0268,0xDEC80EC4,0x41FC3A9B,0xFF142BBE,0xFF0425C5,0xFED81A61,0xFEB81052,0xF6A40AE9,0xFEA01B0C,0xFE640C2B,0xF6340082,0xDE500EC4,0xA1FC3A9B,
-0xFE0025C5,0xE6000F95,0xD60016F4,0xBE003A9D,0xFF643075,0xFF6C3735,0xF77C38AF,0xFF442569,0xFF281942,0xFEFC0D81,0xFEF8085D,0xFED8026A,0xFF542FDE,0xFF4023EC,0xFEDC0D0E,0xF6340082,0x89FC3A9B,0x1BC0EC3,0xFFB00BEE,0xFFA0096B,0xFF9C0882,0xFF980989,0xFF8405BA,0xFF80040D,0xFF7002BB,0xFF64006A,0xF7580081,0x9BFC0EC3,0xFF7C0A6D,0xFF6C0882,0xFF4C05D6,0xFF2C01BD,
-0xF7100081,0xCFF80EC3,0xFED40882,0xF6280080,0xDE000EC4,0x9BFC0EC3,0xFF7C0A6D,0xFF6C0882,0xFF4C05D6,0xFF2C01BD,0xF7100081,0xCFF80EC3,0xFED40882,0xF6280080,0xDE000EC4,0xCFF80EC3,0xFED40882,0xF6280080,0xDE000EC4,0xDE000EC4,0xFFB40CEA,0xF5B80E03,0xF7BC0E43,0xFF980AE1,0xFF7C0839,0xFF5804EB,0xFF3C028A,0xFEFC015D,0xFFA40D0A,0xFF900AA6,0xFF3008A8,0xF6280080,
-0xC1FC0EC3,0x15425C6,0x15425C6,0x15425C6,0x15425C6,0xFF301742,0xFF301742,0xFF301742,0xFF140C51,0xFF140C51,0xEF100A69,0xFF1814E2,0xFF1814E2,0xFF1814E2,0xFEE404F1,0xFEE404F1,0xF4E001D5,0xFECC0888,0xFECC0888,0xE4C00104,0xCCC80884,0x1FC25C5,0x1FC25C5,0x1FC25C5,0xFEB81052,0xFEB81052,0xEEAC0A69,0xFE640C2B,0xFE640C2B,0xEE440002,0xCC600884,0x83F825C5,
-0x83F825C5,0xDC000CB5,0xC4000D24,0xAA0025C5,0xFF3C1EFE,0xFF4C22BE,0x15425C6,0xFF2C188D,0xFF141116,0xFEFC0ADD,0xFEF8085D,0xFED8026A,0xFF341E29,0xFF18178E,0xFEDC0CBD,0xEE440002,0x61FC25C5,0x19C0882,0x19C0882,0x19C0882,0x19C0882,0xFF80040D,0xFF80040D,0xFF80040D,0xFF64006A,0xFF64006A,0xEF580001,0x6BFC0882,0x6BFC0882,0x6BFC0882,0xFF2C01BD,0xFF2C01BD,
-0xEF180001,0xB7F80882,0xB7F80882,0xEE4C0000,0xCC000884,0x6BFC0882,0x6BFC0882,0x6BFC0882,0xFF2C01BD,0xFF2C01BD,0xEF180001,0xB7F80882,0xB7F80882,0xEE4C0000,0xCC000884,0xB7F80882,0xB7F80882,0xEE4C0000,0xCC000884,0xCC000884,0xFF900745,0xF59807C1,0x19C0882,0xFF780681,0xFF700515,0xFF5003B5,0xFF3C028A,0xFEFC015D,0xFD880782,0xFF74065D,0xA3FC0882,0xEE4C0000,
-0xA3FC0882,0x1EC0082,0xFFE8004A,0xFFE40019,0xFFDC0001,0xE9FC0080,0xFFD8002D,0xFFCC0001,0xF3FC0080,0xFF9C0000,0xF6000080,0xE9FC0080,0xFFD8002D,0xFFCC0001,0xF3FC0080,0xFF9C0000,0xF6000080,0xF3FC0080,0xFF9C0000,0xF6000080,0xF6000080,0xE9FC0080,0xFFD8002D,0xFFCC0001,0xF3FC0080,0xFF9C0000,0xF6000080,0xF3FC0080,0xFF9C0000,0xF6000080,0xF6000080,0xF3FC0080,
-0xFF9C0000,0xF6000080,0xF6000080,0xF6000080,0xF9EC0071,0x87FC0080,0xFFEC0071,0xFDE80062,0xFDE00055,0xFFC80022,0xFFB00000,0xFF840000,0xFDEC0071,0xFFE40062,0xFFB80004,0xF6000080,0xF1FC0080,0x1100A69,0x1100A69,0x1100A69,0x1100A69,0x1100A69,0x1100A69,0x1100A69,0x1100A69,0x1100A69,0x1100A69,0xFEDC0145,0xFEDC0145,0xFEDC0145,0xFEDC0145,0xFEDC0145,
-0xFEDC0145,0xD0C80000,0xD0C80000,0xD0C80000,0xACC80000,0x1940A69,0x1940A69,0x1940A69,0x1940A69,0x1940A69,0x1940A69,0xF23C0000,0xF23C0000,0xF23C0000,0xAC800000,0x4FF80A69,0x4FF80A69,0x4FF80A69,0xA60000B4,0x88000A69,0xFD080841,0x1100A69,0x1100A69,0xFEF405E4,0xFEEC041D,0xFEE80290,0xFEE80290,0xFED40048,0xFEF40784,0xFEE40595,0xF6B40000,0xF23C0000,
-0x1FFC0A69,};
-static const uint32_t g_etc1_to_bc7_m6_table218[] = {
-0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x1400000,0x25F80000,
-0x25F80000,0x25F80000,0x25F80000,0x6A000001,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xD80000,0xAE40000,0xAE40000,0xAE40000,0x1400000,0x1CC0000,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1680001,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,
-0x1FFC0000,0x91FC0000,0x91FC0000,0x91FC0000,0xB4000000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x1FFC0000,0x91FC0000,0x91FC0000,0x91FC0000,0xB4000000,0x91FC0000,0x91FC0000,0x91FC0000,0xB4000000,0xB4000000,0x9800000,0x1680001,0x1680001,0x1A40000,0x3C40000,0x1EC0000,0x1EC0000,0x4BFC0000,0x1A40000,0x3C40000,0x75FC0000,0x91FC0000,
-0x75FC0000,0x1EC0001,0x1EC0001,0x1EC0001,0x1EC0001,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xF3FC0000,0xF3FC0000,0xF6000000,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xF3FC0000,0xF3FC0000,0xF6000000,0xF3FC0000,0xF3FC0000,0xF6000000,0xF6000000,0xE9FC0000,0xE9FC0000,0xE9FC0000,0xF3FC0000,0xF3FC0000,0xF6000000,0xF3FC0000,0xF3FC0000,0xF6000000,0xF6000000,0xF3FC0000,
-0xF3FC0000,0xF6000000,0xF6000000,0xF6000000,0xC9FC0000,0x87FC0000,0x1EC0001,0xE3FC0000,0xEDFC0000,0xF1FC0000,0xF3F80000,0xF5F80000,0xDBFC0000,0xE9FC0000,0xF1FC0000,0xF6000000,0xF1FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x18C36D7,0xFF742EAA,0xFF6C2826,0xFF6425C6,0xFF5C24DD,0xFF501BC6,0xFF441831,0xFF3811B1,0xFF2C0D49,0xFB200A89,0xFF5025F8,0xFF301AB6,0xFF241626,0xFF140CC5,0xFEFC0671,0xFCF001D9,0xFEFC10AC,0xFEE408D8,0xF4C801A8,0xE2D80CE4,0x53FC36D7,0xFF2C2A9E,0xFF1C25C5,0xFEF01A01,0xFED811B1,0xFAB80A89,0xFEB819F4,0xFE880D5B,0xFA4C0020,0xE2640CE4,0xABF836D7,
-0xFE2C25C5,0xEC000DB5,0xDC0013A8,0xC40036D9,0xFF742E0F,0xFD883393,0xFD88351B,0xFF54242D,0xFF381982,0xFF180EB9,0xFF1009F9,0xFEEC03A5,0xFF702D9A,0xFF5022A2,0xFEF40E18,0xFA4C0020,0x95FC36D7,0x1C80CE3,0xFFBC0AE6,0xFFAC092B,0xFFAC0882,0xFFA408B1,0xFF9805D6,0xFF8C04A5,0xFF7C02B3,0xFF7000EA,0xFB680021,0xAFFC0CE3,0xFF9409D5,0xFF840882,0xFF640576,0xFF380271,
-0xFB240021,0xD7FC0CE3,0xFF040882,0xFA4C0020,0xE2000CE4,0xAFFC0CE3,0xFF9409D5,0xFF840882,0xFF640576,0xFF380271,0xFB240021,0xD7FC0CE3,0xFF040882,0xFA4C0020,0xE2000CE4,0xD7FC0CE3,0xFF040882,0xFA4C0020,0xE2000CE4,0xE2000CE4,0xFFBC0B6D,0xFBC40C2B,0xFBC40C7B,0xFFB00A0A,0xFF9007D9,0xFF6C0515,0xFF640332,0xFF2801F4,0xFFB40B76,0xFF9809BE,0xFF50089B,0xFA4C0020,
-0xCDFC0CE3,0x16425C6,0x16425C6,0x16425C6,0x16425C6,0xFF441831,0xFF441831,0xFF441831,0xFF2C0D49,0xFF2C0D49,0xF7200A69,0xFF241626,0xFF241626,0xFF241626,0xFEFC0671,0xFEFC0671,0xFCF001D5,0xFEE408D8,0xFEE408D8,0xECD00104,0xD4D80884,0x19FC25C5,0x19FC25C5,0x19FC25C5,0xFED811B1,0xFED811B1,0xF6BC0A69,0xFE880D5B,0xFE880D5B,0xF6540002,0xD4700884,0x8FF825C5,
-0x8FF825C5,0xE6000C45,0xCA000C84,0xB20025C5,0xFF4C1F85,0xF960232D,0x16425C6,0xFF3C1996,0xFF2C12AC,0xFF180CA8,0xFF1009F9,0xFEEC03A5,0xFD4C1F0B,0xFF30188D,0xFEF40DD8,0xF6540002,0x71FC25C5,0x1AC0882,0x1AC0882,0x1AC0882,0x1AC0882,0xFF8C04A5,0xFF8C04A5,0xFF8C04A5,0xFF7000EA,0xFF7000EA,0xF7680001,0x83FC0882,0x83FC0882,0x83FC0882,0xFF380271,0xFF380271,
-0xF7280001,0xC3F80882,0xC3F80882,0xF65C0000,0xD4000884,0x83FC0882,0x83FC0882,0x83FC0882,0xFF380271,0xFF380271,0xF7280001,0xC3F80882,0xC3F80882,0xF65C0000,0xD4000884,0xC3F80882,0xC3F80882,0xF65C0000,0xD4000884,0xD4000884,0xFFA00784,0xFDA807C1,0x1AC0882,0xFF9806CD,0xFF840581,0xFF640431,0xFF640332,0xFF2801F4,0xFF940794,0xFF8406B2,0xB3FC0882,0xF65C0000,
-0xB3FC0882,0x1F40022,0xFFF40012,0xFFF00005,0xFFEC0001,0xF5FC0020,0xFFEC000D,0xFFE40001,0xF9FC0020,0xFFCC0000,0xFA000020,0xF5FC0020,0xFFEC000D,0xFFE40001,0xF9FC0020,0xFFCC0000,0xFA000020,0xF9FC0020,0xFFCC0000,0xFA000020,0xFA000020,0xF5FC0020,0xFFEC000D,0xFFE40001,0xF9FC0020,0xFFCC0000,0xFA000020,0xF9FC0020,0xFFCC0000,0xFA000020,0xFA000020,0xF9FC0020,
-0xFFCC0000,0xFA000020,0xFA000020,0xFA000020,0xFDF40019,0xC7FC0020,0xF3F40022,0xFFF00019,0xFFE80011,0xFFDC0009,0xFFD80000,0xFFC00000,0xFFF0001D,0xFFF00019,0xFFDC0001,0xFA000020,0xF9FC0020,0x1200A69,0x1200A69,0x1200A69,0x1200A69,0x1200A69,0x1200A69,0x1200A69,0x1200A69,0x1200A69,0x1200A69,0xFEF401A5,0xFEF401A5,0xFEF401A5,0xFEF401A5,0xFEF401A5,
-0xFEF401A5,0xD8D80000,0xD8D80000,0xD8D80000,0xB4D80000,0x1AC0A69,0x1AC0A69,0x1AC0A69,0x1AC0A69,0x1AC0A69,0x1AC0A69,0xFA4C0000,0xFA4C0000,0xFA4C0000,0xB4900000,0x5BF80A69,0x5BF80A69,0x5BF80A69,0xAC000080,0x90000A69,0xF5180884,0x1200A69,0x1200A69,0xFF100620,0xFF000469,0xFEF802E4,0xFEF802E4,0xFEE40088,0xFB0807C1,0xFEF805C4,0xFEC40000,0xFA4C0000,
-0x2FFC0A69,};
-static const uint32_t g_etc1_to_bc7_m6_table219[] = {
-0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x1580000,0x31F80000,
-0x31F80000,0x31F80000,0x31F80000,0x72000001,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xE80000,0xF80000,0xF80000,0xF80000,0x1580000,0x1EC0000,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x1780001,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,
-0x37FC0000,0x9DFC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x37FC0000,0x9DFC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0x9DFC0000,0x9DFC0000,0x9DFC0000,0xBC000000,0xBC000000,0x1940000,0x1780001,0x1780001,0x1B80000,0x3D80000,0x9FC0000,0x9FC0000,0x5DFC0000,0x1B80000,0x3D80000,0x83FC0000,0x9DFC0000,
-0x83FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1983373,0xFF8C2CEA,0xFF7C279F,0xFF7425C6,0xFF7423B5,0xFF5C1C42,0xFF5C1969,0xFF40125B,0xFF380E81,0xFF300A69,0xFF5C247C,0xFF441B19,0xFF441758,0xFF200D81,0xFF140831,0xFF0001F9,0xFF081024,0xFEF00984,0xF8DC0130,0xE8E80B58,0x65FC3373,0xFF4029BE,0xFF3425C5,0xFF0819E1,0xFEF01301,0xFECC0A69,0xFED81984,0xFEA00EBB,0xFE640002,0xE8740B59,0xB3FC3373,
-0xFE6025C5,0xF6000C55,0xE00010E1,0xCA003375,0xFF802BE9,0xFF8C3087,0xFF8C323F,0xFF70239D,0xFF4C19E6,0xFF2C1017,0xFF240BD8,0xFF040545,0xFF782B2A,0xFF5C221F,0xFF100FAE,0xFE640002,0x9FFC3373,0x1D00B5B,0xFFC40A0B,0xFFC008EE,0xFFBC0882,0xFFBC0809,0xFFA4061E,0xFFA4053D,0xFF9402EB,0xFF88019A,0xFF780001,0xBDFC0B58,0xFFAC095D,0xFF9C0882,0xFF7C0556,0xFF640335,
-0xFF380001,0xDFF80B58,0xFF340882,0xFE6C0000,0xE8000B58,0xBDFC0B58,0xFFAC095D,0xFF9C0882,0xFF7C0556,0xFF640335,0xFF380001,0xDFF80B58,0xFF340882,0xFE6C0000,0xE8000B58,0xDFF80B58,0xFF340882,0xFE6C0000,0xE8000B58,0xE8000B58,0xFDCC0A58,0xFFCC0AB3,0xFFCC0B13,0xFFB40941,0xFFA407A1,0xFF7C0571,0xFF7C03E8,0xFF4802D0,0xFFC40A5B,0xFFB00926,0xFF700892,0xFE6C0000,
-0xD7FC0B58,0x17425C6,0x17425C6,0x17425C6,0x17425C6,0xFF5C1969,0xFF5C1969,0xFF5C1969,0xFF380E81,0xFF380E81,0xFF300A69,0xFF441758,0xFF441758,0xFF441758,0xFF140831,0xFF140831,0xFF0001F9,0xFEF00984,0xFEF00984,0xF4E00104,0xDCE80884,0x31FC25C5,0x31FC25C5,0x31FC25C5,0xFEF01301,0xFEF01301,0xFECC0A69,0xFEA00EBB,0xFEA00EBB,0xFE640002,0xDC800884,0x9BF825C5,
-0x9BF825C5,0xF2000BD5,0xD6000BF4,0xBA0025C5,0xFF682010,0xFF6C2345,0x17425C6,0xFF541A99,0xFF401434,0xFF2C0E5E,0xFF240BD8,0xFF040545,0xFF501F9B,0xFF4419D4,0xFEFC0F78,0xFE640002,0x7FFC25C5,0x1BC0882,0x1BC0882,0x1BC0882,0x1BC0882,0xFFA4053D,0xFFA4053D,0xFFA4053D,0xFF88019A,0xFF88019A,0xFF780001,0x9BFC0882,0x9BFC0882,0x9BFC0882,0xFF640335,0xFF640335,
-0xFF380001,0xCFF80882,0xCFF80882,0xFE6C0000,0xDC000884,0x9BFC0882,0x9BFC0882,0x9BFC0882,0xFF640335,0xFF640335,0xFF380001,0xCFF80882,0xCFF80882,0xFE6C0000,0xDC000884,0xCFF80882,0xCFF80882,0xFE6C0000,0xDC000884,0xDC000884,0xFBB407C1,0xF5B80802,0x1BC0882,0xFFA4071A,0xFF9805F5,0xFF7C04C8,0xFF7C03E8,0xFF4802D0,0xFDB007C1,0xFF9806F5,0xC1FC0882,0xFE6C0000,
-0xC1FC0882,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1300A69,0x1300A69,0x1300A69,0x1300A69,0x1300A69,0x1300A69,0x1300A69,0x1300A69,0x1300A69,0x1300A69,0xFF0001F9,0xFF0001F9,0xFF0001F9,0xFF0001F9,0xFF0001F9,
-0xFF0001F9,0xE0E80000,0xE0E80000,0xE0E80000,0xBCE80000,0x1C40A69,0x1C40A69,0x1C40A69,0x1C40A69,0x1C40A69,0x1C40A69,0xFE640002,0xFE640002,0xFE640002,0xBCA00000,0x67F80A69,0x67F80A69,0x67F80A69,0xB8000050,0x98000A69,0xFD280884,0x1300A69,0x1300A69,0xFF200659,0xFF1404BD,0xFF080340,0xFF080340,0xFEF400CD,0xFF1007E9,0xFD100622,0xFED8000A,0xFE640002,
-0x3FF80A69,};
-static const uint32_t g_etc1_to_bc7_m6_table220[] = {
-0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0x1740000,0x1740000,0x1740000,0x1740000,0x1740000,0x1740000,0x1740000,0x1740000,0x1740000,0x1740000,0x3FF80000,
-0x3FF80000,0x3FF80000,0x3FF80000,0x7C000000,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xF80001,0xD080000,0xD080000,0xD080000,0x1740000,0xBFC0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,
-0x53FC0000,0xABF80000,0xABF80000,0xABF80000,0xC4000001,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0x53FC0000,0xABF80000,0xABF80000,0xABF80000,0xC4000001,0xABF80000,0xABF80000,0xABF80000,0xC4000001,0xC4000001,0xBA40000,0x18C0000,0x18C0000,0x1CC0000,0x1F00000,0x2BFC0000,0x2BFC0000,0x73FC0000,0x1CC0000,0x1F00000,0x95FC0000,0xABF80000,
-0x95FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1A02C8F,0xFF8C2726,0xFF8822B7,0xFF80212E,0xFF801F75,0xFF68194A,0xFF6816D9,0xFF5810F7,0xFF4C0DDA,0xFF440A69,0xFF681F8A,0xFF5017A7,0xFF50145E,0xFF380C25,0xFF2C07B9,0xFF180271,0xFF200D42,0xFF080792,0xFAF8009A,0xEAF8087A,0x71FC2C8F,0xFF58247E,0xFF44212D,0xFF201735,0xFF081185,0xFEE80A69,0xFEF015BA,0xFEB80C99,0xFE880020,0xEA900879,0xB9FC2C8F,
-0xFE84212D,0xF8000AED,0xE6000C45,0xD0002C91,0xFF8C262B,0xF79C2A69,0xF9A02B7E,0xFF701F1D,0xFF5816D7,0xFF3C0E7E,0xFF3C0AF6,0xFF1404FA,0xFF8025C2,0xFF681E1D,0xFF1C0D7A,0xFE880020,0xA7FC2C8F,0x1D80876,0xFFD00776,0xFFC806AE,0xFFC40659,0xFFC405E2,0xFFB00491,0xFFB003E8,0xFFA00226,0xFF940131,0xFF8C0000,0xC7FC0876,0xFFB806FA,0xFFA80659,0xFF8803F3,0xFF700262,
-0xFF540000,0xE3FC0876,0xFF4C0659,0xFEA00000,0xEA000879,0xC7FC0876,0xFFB806FA,0xFFA80659,0xFF8803F3,0xFF700262,0xFF540000,0xE3FC0876,0xFF4C0659,0xFEA00000,0xEA000879,0xE3FC0876,0xFF4C0659,0xFEA00000,0xEA000879,0xEA000879,0xFFD0079D,0xFFCC0822,0xF5D80851,0xFFC006D9,0xFFAC05A1,0xFFA0042C,0xFF8C02F2,0xFF640209,0xFFD007BE,0xFFC006B9,0xFF840669,0xFEA00000,
-0xDDF80876,0x180212E,0x180212E,0x180212E,0x180212E,0xFF6816D9,0xFF6816D9,0xFF6816D9,0xFF4C0DDA,0xFF4C0DDA,0xFF440A69,0xFF50145E,0xFF50145E,0xFF50145E,0xFF2C07B9,0xFF2C07B9,0xFF180271,0xFF080792,0xFF080792,0xF8F4007E,0xE2F8065A,0x43FC212D,0x43FC212D,0x43FC212D,0xFF081185,0xFF081185,0xFEE80A69,0xFEB80C99,0xFEB80C99,0xFE880020,0xE294065A,0xA3FC212D,
-0xA3FC212D,0xF8000AC9,0xDC0008A6,0xC000212D,0xFF741C62,0xF9801F46,0x180212E,0xFF5C17A3,0xFF541226,0xFF3C0CEE,0xFF3C0AF6,0xFF1404FA,0xFF641BFE,0xFF5016B4,0xFF1C0D49,0xFE880020,0x8BFC212D,0x1C40659,0x1C40659,0x1C40659,0x1C40659,0xFFB003E8,0xFFB003E8,0xFFB003E8,0xFF940131,0xFF940131,0xFF8C0000,0xA9FC0659,0xA9FC0659,0xA9FC0659,0xFF700262,0xFF700262,
-0xFF540000,0xD5F80659,0xD5F80659,0xFEA00000,0xE2000659,0xA9FC0659,0xA9FC0659,0xA9FC0659,0xFF700262,0xFF700262,0xFF540000,0xD5F80659,0xD5F80659,0xFEA00000,0xE2000659,0xD5F80659,0xD5F80659,0xFEA00000,0xE2000659,0xE2000659,0xFFBC05B4,0xFBC405E9,0x1C40659,0xFFB4054A,0xFFAC0480,0xFF9403B5,0xFF8C02F2,0xFF640209,0xFFB405BA,0xFFA4053D,0xC9FC0659,0xFEA00000,
-0xC9FC0659,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1440A69,0x1440A69,0x1440A69,0x1440A69,0x1440A69,0x1440A69,0x1440A69,0x1440A69,0x1440A69,0x1440A69,0xFF180271,0xFF180271,0xFF180271,0xFF180271,0xFF180271,
-0xFF180271,0xE8FC0001,0xE8FC0001,0xE8FC0001,0xC4F80002,0x1E00A69,0x1E00A69,0x1E00A69,0x1E00A69,0x1E00A69,0x1E00A69,0xFE880020,0xFE880020,0xFE880020,0xC4B40001,0x73FC0A69,0x73FC0A69,0x73FC0A69,0xC200002D,0xA0000A69,0xF73C08C5,0x1440A69,0x1440A69,0xFF2C06B2,0xFF280521,0xFF1803BA,0xFF1803BA,0xFF080131,0xF9300841,0xFF200665,0xFEF0002D,0xFE880020,
-0x4FFC0A69,};
-static const uint32_t g_etc1_to_bc7_m6_table221[] = {
-0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x18C0000,0x4BF80000,
-0x4BF80000,0x4BF80000,0x4BF80000,0x84000000,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x1080001,0x11C0000,0x11C0000,0x11C0000,0x18C0000,0x1BFC0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x19C0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,
-0x6BFC0000,0xB7F80000,0xB7F80000,0xB7F80000,0xCC000001,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0x6BFC0000,0xB7F80000,0xB7F80000,0xB7F80000,0xCC000001,0xB7F80000,0xB7F80000,0xB7F80000,0xCC000001,0xCC000001,0x1B80000,0x19C0000,0x19C0000,0x1E00000,0x11FC0000,0x49FC0000,0x49FC0000,0x87FC0000,0x1E00000,0x11FC0000,0xA3FC0000,0xB7F80000,
-0xA3FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1A826F7,0xFF982262,0xFF901EC2,0xFF8C1D72,0xFF8C1C09,0xFF7416DE,0xFF7414CD,0xFF640FDB,0xFF580D4E,0xFF540A69,0xFF741B8A,0xFF6814D7,0xFF5C120E,0xFF400B3C,0xFF380755,0xFF2402E9,0xFF2C0B0A,0xFF200632,0xFD08003A,0xEF080642,0x7DFC26F7,0xFF64202E,0xFF541D72,0xFF2C1515,0xFF201055,0xFF000A69,0xFEFC12C2,0xFED80B12,0xFEA00050,0xEEA00642,0xBFFC26F7,
-0xFEA01D72,0xFE000A6D,0xE60008D5,0xD40026F9,0xFFA021AB,0xFBA42501,0xFDA825FE,0xFF801B4F,0xFF6C146F,0xFF540D63,0xFF3C0A46,0xFF2804D2,0xFF9020F8,0xFF741A72,0xFF300B96,0xFEA00050,0xAFFC26F7,0x1DC0642,0xFFD4058D,0xFFCC04F1,0xFFCC04B1,0xFFC40462,0xFFBC035D,0xFFBC02E4,0xFFAC0192,0xFFA000E5,0xFF9C0000,0xCFFC0641,0xFFB8052A,0xFFB404B1,0xFFA002E3,0xFF8801BA,
-0xFF6C0000,0xE7FC0641,0xFF6404B1,0xFED40000,0xEE000641,0xCFFC0641,0xFFB8052A,0xFFB404B1,0xFFA002E3,0xFF8801BA,0xFF6C0000,0xE7FC0641,0xFF6404B1,0xFED40000,0xEE000641,0xE7FC0641,0xFF6404B1,0xFED40000,0xEE000641,0xEE000641,0xFFD805A2,0xF7DC0600,0xF7DC0621,0xFFC4051A,0xFFC0042D,0xFFA80302,0xFFA0022D,0xFF740184,0xFFD005AE,0xFFC804E1,0xFF9404BA,0xFED40000,
-0xE1FC0641,0x18C1D72,0x18C1D72,0x18C1D72,0x18C1D72,0xFF7414CD,0xFF7414CD,0xFF7414CD,0xFF580D4E,0xFF580D4E,0xFF540A69,0xFF5C120E,0xFF5C120E,0xFF5C120E,0xFF380755,0xFF380755,0xFF2402E9,0xFF200632,0xFF200632,0xFB040032,0xE70804B2,0x53FC1D72,0x53FC1D72,0x53FC1D72,0xFF201055,0xFF201055,0xFF000A69,0xFED80B12,0xFED80B12,0xFEA00050,0xE6A804B2,0xABF81D72,
-0xABF81D72,0xFC000A6D,0xE0000631,0xC4001D75,0xFF841959,0xFD881BB6,0x18C1D72,0xFF701549,0xFF581073,0xFF4C0C25,0xFF3C0A46,0xFF2804D2,0xFF7818E3,0xFF5C14A8,0xFF300B72,0xFEA00050,0x95FC1D72,0x1CC04B1,0x1CC04B1,0x1CC04B1,0x1CC04B1,0xFFBC02E4,0xFFBC02E4,0xFFBC02E4,0xFFA000E5,0xFFA000E5,0xFF9C0000,0xB5FC04B1,0xB5FC04B1,0xB5FC04B1,0xFF8801BA,0xFF8801BA,
-0xFF6C0000,0xDBF804B1,0xDBF804B1,0xFED40000,0xE60004B1,0xB5FC04B1,0xB5FC04B1,0xB5FC04B1,0xFF8801BA,0xFF8801BA,0xFF6C0000,0xDBF804B1,0xDBF804B1,0xFED40000,0xE60004B1,0xDBF804B1,0xDBF804B1,0xFED40000,0xE60004B1,0xE60004B1,0xF7C80451,0xFFCC0451,0x1CC04B1,0xFDC003F5,0xFFAC0340,0xFFA002A8,0xFFA0022D,0xFF740184,0xF9C40451,0xFFB003E8,0xD1FC04B1,0xFED40000,
-0xD1FC04B1,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1540A69,0x1540A69,0x1540A69,0x1540A69,0x1540A69,0x1540A69,0x1540A69,0x1540A69,0x1540A69,0x1540A69,0xFF2402E9,0xFF2402E9,0xFF2402E9,0xFF2402E9,0xFF2402E9,
-0xFF2402E9,0xF10C0001,0xF10C0001,0xF10C0001,0xCD080002,0x1F80A69,0x1F80A69,0x1F80A69,0x1F80A69,0x1F80A69,0x1F80A69,0xFEA00050,0xFEA00050,0xFEA00050,0xCCC40001,0x7FFC0A69,0x7FFC0A69,0x7FFC0A69,0xCA000012,0xA8000A69,0xFF4C08C5,0x1540A69,0x1540A69,0xFF3C06F5,0xFF34057A,0xFF34042A,0xFF34042A,0xFF1C0195,0xFF3C0845,0xFF34069A,0xFEFC007A,0xFEA00050,
-0x5FF80A69,};
-static const uint32_t g_etc1_to_bc7_m6_table222[] = {
-0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x1A40000,0x57F80000,
-0x57F80000,0x57F80000,0x57F80000,0x8C000000,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x1180001,0x12C0000,0x12C0000,0x12C0000,0x1A40000,0x29FC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x1AC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,
-0x83FC0000,0xC3F80000,0xC3F80000,0xC3F80000,0xD4000001,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0x83FC0000,0xC3F80000,0xC3F80000,0xC3F80000,0xD4000001,0xC3F80000,0xC3F80000,0xC3F80000,0xD4000001,0xD4000001,0x1C80000,0x1AC0000,0x1AC0000,0x3F00000,0x37FC0000,0x67FC0000,0x67FC0000,0x9BFC0000,0x3F00000,0x37FC0000,0xB3FC0000,0xC3F80000,
-0xB3FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1B021DF,0xFFA41E16,0xFF9C1B22,0xFF981A0E,0xFF9818ED,0xFF8014AA,0xFF8012F1,0xFF700EDF,0xFF700CCE,0xFF640A69,0xFF8017F2,0xFF741257,0xFF681006,0xFF580A54,0xFF4C0723,0xFF3C0361,0xFF380932,0xFF2C0506,0xFF18000A,0xF1180462,0x89FC21DF,0xFF701C46,0xFF641A0D,0xFF381345,0xFF2C0F41,0xFF180A69,0xFF14101A,0xFEF009AA,0xFEB800A0,0xF0B80461,0xC5FC21DF,
-0xFEC01A0D,0xFE200A69,0xEC0005DD,0xD80021E1,0xFFA01D2B,0xFFAC2019,0xFFAC2106,0xFF881837,0xFF78124A,0xFF5C0C29,0xFF5009B3,0xFF4004BB,0xFF941CEE,0xFF801747,0xFF3C0A2E,0xFEB800A0,0xB7FC21DF,0x1E40462,0xFFDC03DA,0xFFD80371,0xFFD40349,0xFFD00306,0xFFC80259,0xFFC401F9,0xFFB80116,0xFFB8009D,0xFFAC0000,0xD5FC0461,0xFFCC03A1,0xFFC00349,0xFFAC01FB,0xFFA00132,
-0xFF840000,0xEBF80461,0xFF7C0349,0xFF040000,0xF0000461,0xD5FC0461,0xFFCC03A1,0xFFC00349,0xFFAC01FB,0xFFA00132,0xFF840000,0xEBF80461,0xFF7C0349,0xFF040000,0xF0000461,0xEBF80461,0xFF7C0349,0xFF040000,0xF0000461,0xF0000461,0xFFD803F2,0xF9E0042C,0xF9E00449,0xFFD40382,0xFFC802E2,0xFFB80212,0xFFA80172,0xFF8C0112,0xFFDC03F8,0xFFC80371,0xFFA40352,0xFF040000,
-0xE5FC0461,0x1981A0E,0x1981A0E,0x1981A0E,0x1981A0E,0xFF8012F1,0xFF8012F1,0xFF8012F1,0xFF700CCE,0xFF700CCE,0xFF640A69,0xFF681006,0xFF681006,0xFF681006,0xFF4C0723,0xFF4C0723,0xFF3C0361,0xFF2C0506,0xFF2C0506,0xFD180009,0xEB18034A,0x63FC1A0D,0x63FC1A0D,0x63FC1A0D,0xFF2C0F41,0xFF2C0F41,0xFF180A69,0xFEF009AA,0xFEF009AA,0xFEB800A0,0xEABC034A,0xB3F81A0D,
-0xB3F81A0D,0xFE200A69,0xE6000425,0xCA001A0D,0xFF841689,0xFF8C18AA,0x1981A0E,0xFF801316,0xFF6C0EEB,0xFF5C0B29,0xFF5009B3,0xFF4004BB,0xFF80163E,0xFF741269,0xFF3C0A0A,0xFEB800A0,0x9FF81A0D,0x1D40349,0x1D40349,0x1D40349,0x1D40349,0xFFC401F9,0xFFC401F9,0xFFC401F9,0xFFB8009D,0xFFB8009D,0xFFAC0000,0xC1FC0349,0xC1FC0349,0xC1FC0349,0xFFA00132,0xFFA00132,
-0xFF840000,0xE1F80349,0xE1F80349,0xFF040000,0xEA000349,0xC1FC0349,0xC1FC0349,0xC1FC0349,0xFFA00132,0xFFA00132,0xFF840000,0xE1F80349,0xE1F80349,0xFF040000,0xEA000349,0xE1F80349,0xE1F80349,0xFF040000,0xEA000349,0xEA000349,0xFBD002F9,0xFFCC0311,0x1D40349,0xFFC402B9,0xFFC00244,0xFFB001D4,0xFFA80172,0xFF8C0112,0xFDCC02F9,0xFFC402AD,0xD9FC0349,0xFF040000,
-0xD9FC0349,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1640A69,0x1640A69,0x1640A69,0x1640A69,0x1640A69,0x1640A69,0x1640A69,0x1640A69,0x1640A69,0x1640A69,0xFF3C0361,0xFF3C0361,0xFF3C0361,0xFF3C0361,0xFF3C0361,
-0xFF3C0361,0xF91C0001,0xF91C0001,0xF91C0001,0xD5180002,0x13FC0A69,0x13FC0A69,0x13FC0A69,0x13FC0A69,0x13FC0A69,0x13FC0A69,0xFEB800A0,0xFEB800A0,0xFEB800A0,0xD4D40001,0x8BFC0A69,0x8BFC0A69,0x8BFC0A69,0xD4000005,0xB0000A69,0xF75C090A,0x1640A69,0x1640A69,0xFF4C073A,0xFF5005E9,0xFF440492,0xFF440492,0xFF300209,0xFB500884,0xFD4C0708,0xFF1800CD,0xFEB800A0,
-0x6DFC0A69,};
-static const uint32_t g_etc1_to_bc7_m6_table223[] = {
-0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x61FC0000,
-0x61FC0000,0x61FC0000,0x61FC0000,0x94000000,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x1280001,0x73C0000,0x73C0000,0x73C0000,0x1BC0000,0x39FC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x1BC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,
-0x9BFC0000,0xCFF80000,0xCFF80000,0xCFF80000,0xDC000001,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0x9BFC0000,0xCFF80000,0xCFF80000,0xCFF80000,0xDC000001,0xCFF80000,0xCFF80000,0xCFF80000,0xDC000001,0xDC000001,0x5D80000,0x1BC0000,0x1BC0000,0x17FC0000,0x5FFC0000,0x85FC0000,0x85FC0000,0xAFFC0000,0x17FC0000,0x5FFC0000,0xC1FC0000,0xCFF80000,
-0xC1FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1B81D47,0xFFB01A42,0xFFA017DF,0xFFA016FE,0xFF98161D,0xFF9012AA,0xFF8C1145,0xFF7C0E03,0xFF7C0C4A,0xFF740A69,0xFF8C14C2,0xFF801027,0xFF740E46,0xFF640994,0xFF5806FB,0xFF5003DA,0xFF4C07C3,0xFF380432,0xFF2C0002,0xF32802DA,0x95FC1D47,0xFF7C18C6,0xFF7416FD,0xFF581187,0xFF400E66,0xFF300A69,0xFF2C0DD2,0xFF080882,0xFED80112,0xF4CC02D9,0xCBFC1D47,
-0xFEE416FD,0xFE540A69,0xF000039A,0xDC001D49,0xFFA8198F,0xFFAC1C09,0xF5B81CBF,0xFF981527,0xFF801057,0xFF700B37,0xFF680929,0xFF4804DA,0xFFA01957,0xFF90147F,0xFF50092A,0xFED80112,0xBFF81D47,0x1E802D6,0xFFE00289,0xFFE0023E,0xFFDC0221,0xFFDC01F2,0xFFD00185,0xFFD00145,0xFFCC00C0,0xFFC00068,0xFFBC0000,0xDFFC02D6,0xFFD8025D,0xFFCC0221,0xFFB80143,0xFFAC00C2,
-0xFF9C0000,0xEFFC02D6,0xFF940221,0xFF340000,0xF20002D9,0xDFFC02D6,0xFFD8025D,0xFFCC0221,0xFFB80143,0xFFAC00C2,0xFF9C0000,0xEFFC02D6,0xFF940221,0xFF340000,0xF20002D9,0xEFFC02D6,0xFF940221,0xFF340000,0xF20002D9,0xF20002D9,0xFFE40296,0xFDE802AC,0xFDE802C1,0xFFDC0238,0xFFD401E1,0xFFB80162,0xFFB800F5,0xFFA000A9,0xFFDC0298,0xFFDC0233,0xFFB40225,0xFF340000,
-0xEBFC02D6,0x1A016FE,0x1A016FE,0x1A016FE,0x1A016FE,0xFF8C1145,0xFF8C1145,0xFF8C1145,0xFF7C0C4A,0xFF7C0C4A,0xFF740A69,0xFF740E46,0xFF740E46,0xFF740E46,0xFF5806FB,0xFF5806FB,0xFF5003DA,0xFF380432,0xFF380432,0xFF2C0002,0xEF280222,0x75FC16FD,0x75FC16FD,0x75FC16FD,0xFF400E66,0xFF400E66,0xFF300A69,0xFF080882,0xFF080882,0xFED80112,0xEED00222,0xBBFC16FD,
-0xBBFC16FD,0xFE540A69,0xEC000289,0xD00016FD,0xFF901433,0xF9A015ED,0x1A016FE,0xFF88111E,0xFF800DB3,0xFF680A6E,0xFF680929,0xFF4804DA,0xFF9013B8,0xFF8010A6,0xFF500911,0xFED80112,0xA9FC16FD,0x1DC0221,0x1DC0221,0x1DC0221,0x1DC0221,0xFFD00145,0xFFD00145,0xFFD00145,0xFFC00068,0xFFC00068,0xFFBC0000,0xCDFC0221,0xCDFC0221,0xCDFC0221,0xFFAC00C2,0xFFAC00C2,
-0xFF9C0000,0xE7F80221,0xE7F80221,0xFF340000,0xEE000221,0xCDFC0221,0xCDFC0221,0xCDFC0221,0xFFAC00C2,0xFFAC00C2,0xFF9C0000,0xE7F80221,0xE7F80221,0xFF340000,0xEE000221,0xE7F80221,0xE7F80221,0xFF340000,0xEE000221,0xEE000221,0xFFD801E1,0xF7DC0200,0x1DC0221,0xFFD401C2,0xFFC80179,0xFFB80131,0xFFB800F5,0xFFA000A9,0xFFD001ED,0xFFC801BD,0xDFFC0221,0xFF340000,
-0xDFFC0221,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1740A69,0x1740A69,0x1740A69,0x1740A69,0x1740A69,0x1740A69,0x1740A69,0x1740A69,0x1740A69,0x1740A69,0xFF5003DA,0xFF5003DA,0xFF5003DA,0xFF5003DA,0xFF5003DA,
-0xFF5003DA,0xFF2C0002,0xFF2C0002,0xFF2C0002,0xDD280002,0x2BFC0A69,0x2BFC0A69,0x2BFC0A69,0x2BFC0A69,0x2BFC0A69,0x2BFC0A69,0xFED80112,0xFED80112,0xFED80112,0xDCE40001,0x97FC0A69,0x97FC0A69,0x97FC0A69,0xDC040001,0xB8000A69,0xFF6C090A,0x1740A69,0x1740A69,0xFF680782,0xFF580652,0xFF540502,0xFF540502,0xFF40028A,0xFF5808B4,0xFF500750,0xFF300132,0xFED80112,
-0x7DF80A69,};
-static const uint32_t g_etc1_to_bc7_m6_table224[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x5C0001,0x5C0001,0x5C0001,0x5C0001,0x8C0000,0x8C0000,0x8C0000,0x1180000,0x1180000,0x2E000000,0x8C0000,0x8C0000,0x8C0000,0x1180000,0x1180000,0x2E000000,0x1180000,0x1180000,0x2E000000,0x2E000000,0x8C0000,0x8C0000,0x8C0000,0x1180000,0x1180000,0x2E000000,0x1180000,0x1180000,0x2E000000,0x2E000000,0x1180000,
-0x1180000,0x2E000000,0x2E000000,0x2E000000,0x6C0000,0x640000,0x5C0001,0x800000,0x9C0000,0xC80000,0xE40000,0x15C0000,0x2740000,0x8C0000,0xC80000,0x2E000000,0xC80000,0x16C0001,0x25FC0000,0x95F80000,0xB6000000,0x25FC0000,0x95F80000,0xB6000000,0x95F80000,0xB6000000,0xB6000000,0x25FC0000,0x95F80000,0xB6000000,0x95F80000,0xB6000000,
-0xB6000000,0x95F80000,0xB6000000,0xB6000000,0xB6000000,0x25FC0000,0x95F80000,0xB6000000,0x95F80000,0xB6000000,0xB6000000,0x95F80000,0xB6000000,0xB6000000,0xB6000000,0x95F80000,0xB6000000,0xB6000000,0xB6000000,0xB6000000,0x1CC0000,0xB840000,0xB840000,0x4FFC0000,0x87F80000,0xA5F80000,0xB6000000,0xB6000000,0x3F00000,0x67FC0000,0xB3D80000,0xB6000000,
-0x79FC0000,0x7457CA,0xFE442041,0xFE2005E5,0xB62005C1,0xFE182962,0xF4000585,0xB4000094,0xAA002420,0x96000F64,0x72002420,0xEA004691,0xCC001B02,0xA2000CAD,0x98002F04,0x88001816,0x6E002950,0x72004691,0x72002CBD,0x5C0036EC,0x4C004691,0xA857CA,0xAE002A47,0x92001711,0x860037C0,0x80001F6C,0x68002DF0,0x68004B75,0x6C0031E9,0x56003AAD,0x480048F9,0x15857CA,
-0x5C003E8D,0x500043F0,0x44004F85,0x380057CA,0xFE3438A1,0xFA644CC8,0xFE6C4B89,0xFE001F2A,0xE200192D,0xAC001816,0x92001141,0x82001EEA,0xFE1837C5,0xFC002039,0x86002331,0x56003AAD,0xF057CA,0x984692,0xFE5C1A55,0xFE300461,0xB6300451,0xFE302822,0xF4000585,0xB4000094,0xAA002420,0x96000F64,0x72002420,0xE44691,0xCC001B02,0xA2000CAD,0x98002F04,0x88001816,
-0x6E002950,0x1D04691,0x72002CBD,0x5C0036EC,0x4C004691,0xE44691,0xCC001B02,0xA2000CAD,0x98002F04,0x88001816,0x6E002950,0x1D04691,0x72002CBD,0x5C0036EC,0x4C004691,0x1D04691,0x72002CBD,0x5C0036EC,0x4C004691,0x4C004691,0xFE503353,0xFC883FC2,0xFE8C3D0E,0xFE001F2A,0xE200192D,0xAC001816,0x92001141,0x82001EEA,0xFE3433C8,0xFC001F39,0x860022F1,0x5C0036EC,
-0x1484691,0x2005C1,0x2005C1,0x2005C1,0x2005C1,0x8E000000,0x8E000000,0x8E000000,0x44000001,0x44000001,0x2E000000,0x44000451,0x44000451,0x44000451,0x3400019A,0x3400019A,0x280000CD,0x22000451,0x22000451,0x200002A8,0x16000451,0x3005C1,0x3005C1,0x3005C1,0x2E0002A3,0x2E0002A3,0x28000176,0x1E0004C1,0x1E0004C1,0x1C000311,0x1400048E,0x5C05C1,
-0x5C05C1,0x16000402,0x1000051E,0xE0005C2,0xF6000171,0xF21402AC,0x2005C1,0x900001D0,0x5A0001A8,0x440001A8,0x40000161,0x2E0001F9,0x9600030A,0x66000286,0x2A00045A,0x1C000311,0x4005C1,0x300451,0x300451,0x300451,0x300451,0x8E000000,0x8E000000,0x8E000000,0x44000001,0x44000001,0x2E000000,0x440451,0x440451,0x440451,0x3400019A,0x3400019A,
-0x280000CD,0x880451,0x880451,0x200002A8,0x16000451,0x440451,0x440451,0x440451,0x3400019A,0x3400019A,0x280000CD,0x880451,0x880451,0x200002A8,0x16000451,0x880451,0x880451,0x200002A8,0x16000451,0x16000451,0xF6000171,0xF8200200,0x300451,0x900001D0,0x5A0001A8,0x440001A8,0x40000161,0x2E0001F9,0x960002B9,0x6C00025D,0x600451,0x200002A8,
-0x600451,0xE42422,0xFE980C49,0xF8600001,0xB65C0001,0x1542420,0xF4000585,0xB4000094,0x2FFC2420,0x96000F64,0x72002420,0x1542420,0xF4000585,0xB4000094,0x2FFC2420,0x96000F64,0x72002420,0x2FFC2420,0x96000F64,0x72002420,0x72002420,0x1542420,0xF4000585,0xB4000094,0x2FFC2420,0x96000F64,0x72002420,0x2FFC2420,0x96000F64,0x72002420,0x72002420,0x2FFC2420,
-0x96000F64,0x72002420,0x72002420,0x72002420,0xFAAC1E85,0x2F42420,0xF6DC1F81,0xFE4015A0,0xF6001009,0xBC000EF9,0x9E000AE1,0x9000133D,0xFE901E08,0xFE14145D,0xA6000988,0x72002420,0x1E82420,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table225[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x6C0001,0x6C0001,0x6C0001,0x6C0001,0xA40000,0xA40000,0xA40000,0x14C0000,0x14C0000,0x36000000,0xA40000,0xA40000,0xA40000,0x14C0000,0x14C0000,0x36000000,0x14C0000,0x14C0000,0x36000000,0x36000000,0xA40000,0xA40000,0xA40000,0x14C0000,0x14C0000,0x36000000,0x14C0000,0x14C0000,0x36000000,0x36000000,0x14C0000,
-0x14C0000,0x36000000,0x36000000,0x36000000,0x800000,0x2740000,0x6C0001,0x940000,0xB80000,0xE80000,0x10C0000,0x1980000,0x2880000,0xA40000,0xE80000,0x36000000,0xE80000,0x17C0001,0x3DFC0000,0xA1F80000,0xBE000000,0x3DFC0000,0xA1F80000,0xBE000000,0xA1F80000,0xBE000000,0xBE000000,0x3DFC0000,0xA1F80000,0xBE000000,0xA1F80000,0xBE000000,
-0xBE000000,0xA1F80000,0xBE000000,0xBE000000,0xBE000000,0x3DFC0000,0xA1F80000,0xBE000000,0xA1F80000,0xBE000000,0xBE000000,0xA1F80000,0xBE000000,0xBE000000,0xBE000000,0xA1F80000,0xBE000000,0xBE000000,0xBE000000,0xBE000000,0x1E00000,0x1980000,0x1980000,0x63FC0000,0x95F80000,0xAFF80000,0xBE000000,0xBE000000,0xFFC0000,0x77FC0000,0xBBE80000,0xBE000000,
-0x87FC0000,0x7C5F3A,0xFE442651,0xFE280892,0xBE2407E1,0xFE242C5A,0xFA0004BD,0xBA000034,0xB6002420,0x9C000E48,0x7A002420,0xF8004B86,0xE2001C71,0xA8000DB5,0xA200306B,0x92001820,0x74002A0C,0x78004B89,0x78002F69,0x660039D9,0x50004B89,0xB45F3A,0xBA002DB7,0xA2001906,0x92003AA0,0x86002070,0x6E002F60,0x6E005129,0x72003541,0x60003DE9,0x4C004E42,0x1705F3A,
-0x5C0043BD,0x56004888,0x440055C5,0x3C005F3A,0xFE503ED3,0xFE6C5368,0xFE6C52D9,0xFE142325,0xF600193D,0xBC0017ED,0x9E0010D5,0x8A001F71,0xFE183E05,0xFC002279,0x9400251B,0x60003DE9,0x1005F3A,0xA44B86,0xFE681ED9,0xFE38064D,0xBE3805E9,0xFE3C2A76,0xFA0004BD,0xBA000034,0xB6002420,0x9C000E48,0x7A002420,0xF44B86,0xE2001C71,0xA8000DB5,0xA200306B,0x92001820,
-0x74002A0C,0x1F04B86,0x78002F69,0x660039D9,0x50004B89,0xF44B86,0xE2001C71,0xA8000DB5,0xA200306B,0x92001820,0x74002A0C,0x1F04B86,0x78002F69,0x660039D9,0x50004B89,0x1F04B86,0x78002F69,0x660039D9,0x50004B89,0x50004B89,0xFE64380A,0xFE8C4466,0xFE8C426E,0xFE1422C1,0xF600193D,0xBC0017ED,0x9E0010D5,0x8A001F71,0xFE443845,0xFC002179,0x940024CA,0x660039D9,
-0x15C4B86,0x2407E1,0x2407E1,0x2407E1,0x2407E1,0xA6000000,0xA6000000,0xA6000000,0x50000001,0x50000001,0x36000000,0x500005E9,0x500005E9,0x500005E9,0x40000232,0x40000232,0x2E000121,0x280005E9,0x280005E9,0x260003A4,0x1A0005E9,0x3407E1,0x3407E1,0x3407E1,0x340003AB,0x340003AB,0x2E000202,0x2200067A,0x2200067A,0x20000441,0x18000635,0x6807E1,
-0x6807E1,0x1C000576,0x160006F2,0x120007E2,0xF8040269,0xF61C042C,0x2407E1,0xA400028A,0x68000249,0x4C000254,0x4C0001E1,0x380002BA,0xA400042E,0x72000363,0x320005F2,0x20000441,0x4C07E1,0x3805E9,0x3805E9,0x3805E9,0x3805E9,0xA6000000,0xA6000000,0xA6000000,0x50000001,0x50000001,0x36000000,0x5005E9,0x5005E9,0x5005E9,0x40000232,0x40000232,
-0x2E000121,0xA005E9,0xA005E9,0x260003A4,0x1A0005E9,0x5005E9,0x5005E9,0x5005E9,0x40000232,0x40000232,0x2E000121,0xA005E9,0xA005E9,0x260003A4,0x1A0005E9,0xA005E9,0xA005E9,0x260003A4,0x1A0005E9,0x1A0005E9,0xF8040265,0xFC280320,0x3805E9,0xA400028A,0x68000249,0x4C000254,0x4C0001E1,0x380002BA,0xB40003B5,0x72000332,0x7005E9,0x260003A4,
-0x7005E9,0xF42422,0xFEB00D41,0xFE700002,0xBE6C0001,0x16C2420,0xFA0004BD,0xBA000034,0x3BFC2420,0x9C000E48,0x7A002420,0x16C2420,0xFA0004BD,0xBA000034,0x3BFC2420,0x9C000E48,0x7A002420,0x3BFC2420,0x9C000E48,0x7A002420,0x7A002420,0x16C2420,0xFA0004BD,0xBA000034,0x3BFC2420,0x9C000E48,0x7A002420,0x3BFC2420,0x9C000E48,0x7A002420,0x7A002420,0x3BFC2420,
-0x9C000E48,0x7A002420,0x7A002420,0x7A002420,0xFEB41EAD,0xB042420,0xFEEC1F81,0xFE6C1661,0xF6000F79,0xBC000E29,0xA80009CD,0x94001248,0xFE981E3A,0xFE401528,0xB400084A,0x7A002420,0x7FC2420,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table226[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x7C0001,0x7C0001,0x7C0001,0x7C0001,0xBC0000,0xBC0000,0xBC0000,0x17C0000,0x17C0000,0x3E000000,0xBC0000,0xBC0000,0xBC0000,0x17C0000,0x17C0000,0x3E000000,0x17C0000,0x17C0000,0x3E000000,0x3E000000,0xBC0000,0xBC0000,0xBC0000,0x17C0000,0x17C0000,0x3E000000,0x17C0000,0x17C0000,0x3E000000,0x3E000000,0x17C0000,
-0x17C0000,0x3E000000,0x3E000000,0x3E000000,0x4900000,0xA840000,0x7C0001,0xAC0000,0xD40000,0x10C0000,0x1340000,0x1D40000,0x29C0000,0xBC0000,0x10C0000,0x3E000000,0x10C0000,0x18C0001,0x55FC0000,0xADF80000,0xC6000000,0x55FC0000,0xADF80000,0xC6000000,0xADF80000,0xC6000000,0xC6000000,0x55FC0000,0xADF80000,0xC6000000,0xADF80000,0xC6000000,
-0xC6000000,0xADF80000,0xC6000000,0xC6000000,0xC6000000,0x55FC0000,0xADF80000,0xC6000000,0xADF80000,0xC6000000,0xC6000000,0xADF80000,0xC6000000,0xC6000000,0xC6000000,0xADF80000,0xC6000000,0xC6000000,0xC6000000,0xC6000000,0x1F40000,0x1A80000,0x1A80000,0x77FC0000,0xA1FC0000,0xB9F80000,0xC6000000,0xC6000000,0x2FFC0000,0x89FC0000,0xC3F80000,0xC6000000,
-0x97FC0000,0x84672A,0xFE502CD1,0xFE2C0BE9,0xC6280A59,0xFE303022,0xFE0404C5,0xC6000004,0xC2002420,0xA6000D61,0x82002420,0xFE0450E5,0xE8001E1D,0xB4000EED,0xAE003223,0x98001848,0x7A002AE0,0x800050D1,0x7E00325D,0x6C003CB9,0x560050D1,0xC0672A,0xC6003187,0xA2001B66,0xA2003D84,0x920021A0,0x740030F0,0x74005745,0x780038E9,0x6600415D,0x520053E2,0x188672A,
-0x66004956,0x5C004D70,0x4A005C5D,0x4000672A,0xFE504513,0xFE6C5AE8,0xF67C5B12,0xFE142775,0xF60019AD,0xBC00181D,0xA60010A0,0x90002036,0xFE3444C8,0xFE0025AA,0x96002723,0x6600415D,0x114672A,0xB050D2,0xFE7423CD,0xFE4008E2,0xC64007C1,0xFE442D24,0xFE0404C1,0xC6000004,0xC2002420,0xA6000D61,0x82002420,0x30050D1,0xE8001E1D,0xB4000EED,0xAE003223,0x98001848,
-0x7A002AE0,0x5FC50D1,0x7E00325D,0x6C003CB9,0x560050D1,0x30050D1,0xE8001E1D,0xB4000EED,0xAE003223,0x98001848,0x7A002AE0,0x5FC50D1,0x7E00325D,0x6C003CB9,0x560050D1,0x5FC50D1,0x7E00325D,0x6C003CB9,0x560050D1,0x560050D1,0xFE783CC9,0xF8A049A0,0xFCA84789,0xFE142711,0xF60019AD,0xBC00181D,0xA60010A0,0x90002036,0xFC583D2B,0xFE0424A1,0x960026D2,0x6C003CB9,
-0x17050D1,0x280A59,0x280A59,0x280A59,0x280A59,0xBE000000,0xBE000000,0xBE000000,0x5C000001,0x5C000001,0x3E000000,0x5C0007C1,0x5C0007C1,0x5C0007C1,0x4C0002EA,0x4C0002EA,0x3A000179,0x2E0007C1,0x2E0007C1,0x2C0004C8,0x1E0007C1,0x23C0A56,0x23C0A56,0x23C0A56,0x400004DB,0x400004DB,0x340002A6,0x28000882,0x28000882,0x2600058D,0x1E000825,0x7C0A56,
-0x7C0A56,0x2000074C,0x1A00092D,0x14000A56,0xFA0803B9,0xF8200600,0x280A59,0xBA00034D,0x7C000301,0x62000308,0x5600028A,0x40000385,0xC200057A,0x9000047B,0x3A0007D1,0x2600058D,0x580A56,0x4007C1,0x4007C1,0x4007C1,0x4007C1,0xBE000000,0xBE000000,0xBE000000,0x5C000001,0x5C000001,0x3E000000,0x5C07C1,0x5C07C1,0x5C07C1,0x4C0002EA,0x4C0002EA,
-0x3A000179,0xB807C1,0xB807C1,0x2C0004C8,0x1E0007C1,0x5C07C1,0x5C07C1,0x5C07C1,0x4C0002EA,0x4C0002EA,0x3A000179,0xB807C1,0xB807C1,0x2C0004C8,0x1E0007C1,0xB807C1,0xB807C1,0x2C0004C8,0x1E0007C1,0x1E0007C1,0xFC0C039D,0xFE2C0488,0x4007C1,0xBA00034D,0x7C000301,0x62000308,0x5600028A,0x40000385,0xC20004EA,0x9000042A,0x8007C1,0x2C0004C8,
-0x8007C1,0x1042422,0xFEC40E2A,0xFE84002D,0xC67C0001,0x1842420,0xFE0804B5,0xC6000004,0x47FC2420,0xA6000D61,0x82002420,0x1842420,0xFE0804B5,0xC6000004,0x47FC2420,0xA6000D61,0x82002420,0x47FC2420,0xA6000D61,0x82002420,0x82002420,0x1842420,0xFE0804B5,0xC6000004,0x47FC2420,0xA6000D61,0x82002420,0x47FC2420,0xA6000D61,0x82002420,0x82002420,0x47FC2420,
-0xA6000D61,0x82002420,0x82002420,0x82002420,0xFED01F04,0x1182420,0xF6FC2002,0xFE6C1711,0xFE0C0F79,0xD0000D00,0xB00008C8,0x9C001174,0xFEAC1EC1,0xFE4C15DD,0xBE000734,0x82002420,0x17FC2420,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table227[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0x8C0001,0x8C0001,0x8C0001,0x8C0001,0x2D00000,0x2D00000,0x2D00000,0x1AC0000,0x1AC0000,0x46000000,0x2D00000,0x2D00000,0x2D00000,0x1AC0000,0x1AC0000,0x46000000,0x1AC0000,0x1AC0000,0x46000000,0x46000000,0x2D00000,0x2D00000,0x2D00000,0x1AC0000,0x1AC0000,0x46000000,0x1AC0000,0x1AC0000,0x46000000,0x46000000,0x1AC0000,
-0x1AC0000,0x46000000,0x46000000,0x46000000,0xA40000,0x980000,0x8C0001,0xC00000,0x2EC0000,0x12C0000,0x15C0000,0x5F80000,0x2B00000,0x2D00000,0x12C0000,0x46000000,0x12C0000,0x19C0001,0x6FFC0000,0xB9F80000,0xCE000000,0x6FFC0000,0xB9F80000,0xCE000000,0xB9F80000,0xCE000000,0xCE000000,0x6FFC0000,0xB9F80000,0xCE000000,0xB9F80000,0xCE000000,
-0xCE000000,0xB9F80000,0xCE000000,0xCE000000,0xCE000000,0x6FFC0000,0xB9F80000,0xCE000000,0xB9F80000,0xCE000000,0xCE000000,0xB9F80000,0xCE000000,0xCE000000,0xCE000000,0xB9F80000,0xCE000000,0xCE000000,0xCE000000,0xCE000000,0x15FC0000,0x5B80000,0x5B80000,0x8BFC0000,0xAFFC0000,0xC3F80000,0xCE000000,0xCE000000,0x4DFC0000,0x99FC0000,0xCDCC0000,0xCE000000,
-0xA5FC0000,0x8C6F9A,0xFE5C3409,0xFE380FFD,0xCE300D21,0xFE303482,0xFE080585,0xD0000008,0xCE002420,0xAC000C6D,0x8A002420,0xFE0C56D6,0xF4002035,0xBA00107D,0xB40033FB,0xA200187A,0x80002BCC,0x8A005671,0x84003599,0x72003FC9,0x5C005671,0xCC6F9A,0xD20035B7,0xAE001E26,0xA20040A4,0x980022EC,0x7A0032A0,0x80005DB5,0x7E003CE1,0x6C004509,0x580059E2,0x1A06F9A,
-0x6C004F2A,0x5C0052B0,0x5000636D,0x44006F9A,0xFE504C53,0xF8806322,0xFA846322,0xFE142CC5,0xFC001ADA,0xCC001898,0xAE001085,0x980020F9,0xFE344BA8,0xFE0029CA,0x9E0029C1,0x6C004509,0x1246F9A,0xB85672,0xFE802931,0xFE4C0BF6,0xCE4809D9,0xFE503080,0xFE080575,0xCE040008,0xCE002420,0xAC000C6D,0x8A002420,0x1145671,0xF4002035,0xBA00107D,0xB40033FB,0xA200187A,
-0x80002BCC,0xFF85671,0x84003599,0x72003FC9,0x5C005671,0x1145671,0xF4002035,0xBA00107D,0xB40033FB,0xA200187A,0x80002BCC,0xFF85671,0x84003599,0x72003FC9,0x5C005671,0xFF85671,0x84003599,0x72003FC9,0x5C005671,0x5C005671,0xFE7841F9,0xFEAC4ECC,0xFEAC4D09,0xFE302BF5,0xFC001ADA,0xCC001898,0xAE001085,0x980020F9,0xFE5C422B,0xFE0428A1,0x9E00295D,0x72003FC9,
-0x18C5671,0x300D21,0x300D21,0x300D21,0x300D21,0xD6000000,0xD6000000,0xD6000000,0x68000000,0x68000000,0x46000000,0x6A0009D9,0x6A0009D9,0x6A0009D9,0x520003BA,0x520003BA,0x400001DD,0x340009D9,0x340009D9,0x32000614,0x220009D9,0x2440D21,0x2440D21,0x2440D21,0x46000633,0x46000633,0x3A000362,0x2E000AD2,0x2E000AD2,0x2C000709,0x22000A52,0x8C0D21,
-0x8C0D21,0x26000948,0x1C000B96,0x16000D22,0xFC0C0561,0xFA24082C,0x300D21,0xD000042A,0x860003D9,0x6A0003D4,0x62000334,0x4A000484,0xE4000704,0x900005AB,0x400009E9,0x2C000709,0x640D21,0x4809D9,0x4809D9,0x4809D9,0x4809D9,0xD6000000,0xD6000000,0xD6000000,0x68000000,0x68000000,0x46000000,0x6809D9,0x6809D9,0x6809D9,0x520003BA,0x520003BA,
-0x400001DD,0xD009D9,0xD009D9,0x32000614,0x220009D9,0x6809D9,0x6809D9,0x6809D9,0x520003BA,0x520003BA,0x400001DD,0xD009D9,0xD009D9,0x32000614,0x220009D9,0xD009D9,0xD009D9,0x32000614,0x220009D9,0x220009D9,0xFE100521,0xF4380659,0x4809D9,0xD000042A,0x860003D9,0x6A0003D4,0x62000334,0x4A000484,0xF400063D,0x9A000551,0x9409D9,0x32000614,
-0x9409D9,0x1142422,0xFED00F3A,0xFE940082,0xCE8C0001,0x19C2420,0xFE080565,0xCE080000,0x53FC2420,0xAC000C6D,0x8A002420,0x19C2420,0xFE080565,0xCE080000,0x53FC2420,0xAC000C6D,0x8A002420,0x53FC2420,0xAC000C6D,0x8A002420,0x8A002420,0x19C2420,0xFE080565,0xCE080000,0x53FC2420,0xAC000C6D,0x8A002420,0x53FC2420,0xAC000C6D,0x8A002420,0x8A002420,0x53FC2420,
-0xAC000C6D,0x8A002420,0x8A002420,0x8A002420,0xF6E81F81,0x1282420,0xFF0C2002,0xFE9417C2,0xFE100FE9,0xDA000BE9,0xB40007B4,0xA800109D,0xFCD01F02,0xFE6416CD,0xC6000659,0x8A002420,0x25FC2420,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table228[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0xA00000,0xA00000,0xA00000,0xA00000,0xEC0000,0xEC0000,0xEC0000,0x1E40000,0x1E40000,0x4E000001,0xEC0000,0xEC0000,0xEC0000,0x1E40000,0x1E40000,0x4E000001,0x1E40000,0x1E40000,0x4E000001,0x4E000001,0xEC0000,0xEC0000,0xEC0000,0x1E40000,0x1E40000,0x4E000001,0x1E40000,0x1E40000,0x4E000001,0x4E000001,0x1E40000,
-0x1E40000,0x4E000001,0x4E000001,0x4E000001,0x4B80000,0xCA80000,0xA00000,0xD80000,0x10C0000,0x1540000,0x1880000,0x11FC0000,0xC80000,0xEC0000,0x1540000,0x4E000001,0x1540000,0x1B00000,0x89FC0000,0xC5FC0000,0xD6000001,0x89FC0000,0xC5FC0000,0xD6000001,0xC5FC0000,0xD6000001,0xD6000001,0x89FC0000,0xC5FC0000,0xD6000001,0xC5FC0000,0xD6000001,
-0xD6000001,0xC5FC0000,0xD6000001,0xD6000001,0xD6000001,0x89FC0000,0xC5FC0000,0xD6000001,0xC5FC0000,0xD6000001,0xD6000001,0xC5FC0000,0xD6000001,0xD6000001,0xD6000001,0xC5FC0000,0xD6000001,0xD6000001,0xD6000001,0xD6000001,0x41FC0000,0x1CC0000,0x1CC0000,0xA1FC0000,0xBFF80000,0xCFF40000,0xD6000001,0xD6000001,0x6FFC0000,0xADFC0000,0xD5FC0000,0xD6000001,
-0xB7FC0000,0x9479B0,0xFE5C3CE5,0xFE381579,0xD63410AD,0xFE3C3A48,0xFE08077D,0xD804003A,0xDC002420,0xB8000B51,0x92002422,0xFE185E40,0xFA0022E9,0xC6001283,0xC0003629,0xAE0018E6,0x8C002CC6,0x92005D2B,0x90003993,0x78004373,0x62005D2B,0xDC79B0,0xE2003A6D,0xB40021B4,0xAE00448A,0xA200246F,0x86003492,0x8600656B,0x840041BB,0x7200496F,0x5E006114,0x1BC79B0,
-0x72005634,0x66005924,0x56006BE7,0x480079B4,0xFE645556,0xFC886C60,0xFE8C6CD0,0xFE1833EE,0xFC001D3E,0xDA0018C5,0xBC00109D,0xA00021F6,0xFE345496,0xFE042F97,0xA6002D3F,0x7200496F,0x13879B0,0xC45D2C,0xFE8C2FC1,0xFE581024,0xD6500C81,0xFE5C34E6,0xFE140759,0xDA080032,0xDC002420,0xB8000B51,0x92002422,0x3245D2B,0xFA0022E9,0xC6001283,0xC0003629,0xAE0018E6,
-0x8C002CC6,0x17FC5D2B,0x90003993,0x78004373,0x62005D2B,0x3245D2B,0xFA0022E9,0xC6001283,0xC0003629,0xAE0018E6,0x8C002CC6,0x17FC5D2B,0x90003993,0x78004373,0x62005D2B,0x17FC5D2B,0x90003993,0x78004373,0x62005D2B,0x62005D2B,0xFE9448B3,0xFEAC5556,0xF8C05444,0xFE4031C3,0xFC001D3E,0xDA0018C5,0xBC00109D,0xA00021F6,0xFE5C48FD,0xFE042E53,0xA6002CDB,0x78004373,
-0x1A45D2B,0x3410AC,0x3410AC,0x3410AC,0x3410AC,0xF2000000,0xF2000000,0xF2000000,0x76000000,0x76000000,0x4E000001,0x78000C80,0x78000C80,0x78000C80,0x620004A9,0x620004A9,0x46000262,0x3A000C80,0x3A000C80,0x380007B5,0x26000C82,0x5010AB,0x5010AB,0x5010AB,0x4C0007F2,0x4C0007F2,0x40000453,0x34000DC1,0x34000DC1,0x320008EE,0x24000D22,0xA010AB,
-0xA010AB,0x2C000BD1,0x20000EC6,0x1A0010AB,0xFE1007AA,0xFE2C0B01,0x3410AC,0xEC000562,0x9E0004E1,0x800004FD,0x6E00040D,0x560005C9,0xF40008E9,0xB2000742,0x46000C98,0x320008EE,0x7010AB,0x500C80,0x500C80,0x500C80,0x500C80,0xF2000000,0xF2000000,0xF2000000,0x76000000,0x76000000,0x4E000001,0x2740C80,0x2740C80,0x2740C80,0x620004A9,0x620004A9,
-0x46000262,0xF00C80,0xF00C80,0x380007B5,0x26000C82,0x2740C80,0x2740C80,0x2740C80,0x620004A9,0x620004A9,0x46000262,0xF00C80,0xF00C80,0x380007B5,0x26000C82,0xF00C80,0xF00C80,0x380007B5,0x26000C82,0x26000C82,0xFE200745,0xF8400884,0x500C80,0xEC000562,0x9E0004E1,0x800004FD,0x6E00040D,0x560005C9,0xF4000808,0xB20006C9,0xA80C80,0x380007B5,
-0xA80C80,0x1282420,0xFEE81074,0xFEAC0124,0xD6A00001,0x1B82420,0xFE2C069D,0xD61C0001,0x61F82420,0xB8000B51,0x92002422,0x1B82420,0xFE2C069D,0xD61C0001,0x61F82420,0xB8000B51,0x92002422,0x61F82420,0xB8000B51,0x92002422,0x92002422,0x1B82420,0xFE2C069D,0xD61C0001,0x61F82420,0xB8000B51,0x92002422,0x61F82420,0xB8000B51,0x92002422,0x92002422,0x61F82420,
-0xB8000B51,0x92002422,0x92002422,0x92002422,0xFEF81F85,0x13C2420,0xF9202081,0xFEB018A0,0xFE281109,0xE8000B14,0xBE0006B2,0xB2000F82,0xFEDC1F22,0xFE881771,0xD4000541,0x92002422,0x37FC2420,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table229[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x1,0xB00000,0xB00000,0xB00000,0xB00000,0x1040000,0x1040000,0x1040000,0x7FC0000,0x7FC0000,0x56000001,0x1040000,0x1040000,0x1040000,0x7FC0000,0x7FC0000,0x56000001,0x7FC0000,0x7FC0000,0x56000001,0x56000001,0x1040000,0x1040000,0x1040000,0x7FC0000,0x7FC0000,0x56000001,0x7FC0000,0x7FC0000,0x56000001,0x56000001,0x7FC0000,
-0x7FC0000,0x56000001,0x56000001,0x56000001,0xCC0000,0xBC0000,0xB00000,0xF00000,0x1280000,0x1740000,0x1AC0000,0x1DF40000,0xDC0000,0x1040000,0x1740000,0x56000001,0x1740000,0x1C00000,0xA3FC0000,0xD1FC0000,0xDE000001,0xA3FC0000,0xD1FC0000,0xDE000001,0xD1FC0000,0xDE000001,0xDE000001,0xA3FC0000,0xD1FC0000,0xDE000001,0xD1FC0000,0xDE000001,
-0xDE000001,0xD1FC0000,0xDE000001,0xDE000001,0xDE000001,0xA3FC0000,0xD1FC0000,0xDE000001,0xD1FC0000,0xDE000001,0xDE000001,0xD1FC0000,0xDE000001,0xDE000001,0xDE000001,0xD1FC0000,0xDE000001,0xDE000001,0xDE000001,0xDE000001,0x69FC0000,0x7DC0000,0x7DC0000,0xB3FC0000,0xCBFC0000,0xD9F40000,0xDE000001,0xDE000001,0x8DFC0000,0xBDFC0000,0xDFD00000,0xDE000001,
-0xC5FC0000,0x9C8330,0xFE684541,0xFE401B24,0xDE3C142D,0xFE443FEA,0xFE140A2D,0xE008009A,0xE6002422,0xC4000A69,0x9A002422,0xFE246584,0xFA002639,0xCC0014AB,0xCC003831,0xB4001956,0x92002DC2,0x9A006380,0x96003D53,0x7E0046EB,0x66006383,0xE88330,0xE8003F39,0xC0002534,0xBA00483A,0xA8002617,0x8C00366A,0x8C006CB7,0x8A00465F,0x78004D93,0x620067CB,0x1D88330,
-0x78005CE4,0x6C005F04,0x5C0073EF,0x4C008334,0xFE645DA6,0xFE8C7530,0xFE8C7650,0xFE303A6D,0xFE04205E,0xDE001961,0xC40010B2,0xAA002336,0xFE445CDB,0xFE0435B7,0xB600301B,0x78004D93,0x14C8330,0xD06380,0xFE983611,0xFE641478,0xDE580F21,0xFE683962,0xFE2009C5,0xE20C007E,0xE6002422,0xC4000A69,0x9A002422,0x1346380,0xFA002639,0xCC0014AB,0xCC003831,0xB4001956,
-0x92002DC2,0x1FF86380,0x96003D53,0x7E0046EB,0x66006383,0x1346380,0xFA002639,0xCC0014AB,0xCC003831,0xB4001956,0x92002DC2,0x1FF86380,0x96003D53,0x7E0046EB,0x66006383,0x1FF86380,0x96003D53,0x7E0046EB,0x66006383,0x66006383,0xFE944E93,0xFAC45BA4,0xFCC85A64,0xFE403763,0xFE04205A,0xDE001961,0xC40010B2,0xAA002336,0xFE784F21,0xFE18341D,0xB6002FA2,0x7E0046EB,
-0x1B86380,0x3C142C,0x3C142C,0x3C142C,0x3C142C,0xFE000010,0xFE000010,0xFE000010,0x82000000,0x82000000,0x56000001,0x84000F20,0x84000F20,0x84000F20,0x680005A5,0x680005A5,0x4C0002EA,0x40000F20,0x40000F20,0x3E000955,0x2A000F22,0x54142B,0x54142B,0x54142B,0x580009A2,0x580009A2,0x46000543,0x3A0010A9,0x3A0010A9,0x38000ACE,0x28000FDB,0xAC142B,
-0xAC142B,0x2C000E41,0x240011F3,0x1C00142B,0xFE100A3A,0xFE2C0DF1,0x3C142C,0xFA000682,0xA80005ED,0x840005EA,0x800004FD,0x56000709,0xF4000B09,0xB20008D2,0x52000F39,0x38000ACE,0x78142B,0x580F20,0x580F20,0x580F20,0x580F20,0xFE04000D,0xFE04000D,0xFE04000D,0x82000000,0x82000000,0x56000001,0x2800F20,0x2800F20,0x2800F20,0x680005A5,0x680005A5,
-0x4C0002EA,0x1080F20,0x1080F20,0x3E000955,0x2A000F22,0x2800F20,0x2800F20,0x2800F20,0x680005A5,0x680005A5,0x4C0002EA,0x1080F20,0x1080F20,0x3E000955,0x2A000F22,0x1080F20,0x1080F20,0x3E000955,0x2A000F22,0x2A000F22,0xFE200965,0xFC480AB4,0x580F20,0xFA000682,0xA80005ED,0x840005EA,0x800004FD,0x56000709,0xF6040A20,0xBC000848,0xB80F20,0x3E000955,
-0xB80F20,0x1382420,0xFF0011A4,0xFEB801F4,0xDEB00001,0x1D02420,0xFE4C07F9,0xDE2C0001,0x6DF82420,0xC4000A69,0x9A002422,0x1D02420,0xFE4C07F9,0xDE2C0001,0x6DF82420,0xC4000A69,0x9A002422,0x6DF82420,0xC4000A69,0x9A002422,0x9A002422,0x1D02420,0xFE4C07F9,0xDE2C0001,0x6DF82420,0xC4000A69,0x9A002422,0x6DF82420,0xC4000A69,0x9A002422,0x9A002422,0x6DF82420,
-0xC4000A69,0x9A002422,0x9A002422,0x9A002422,0xFD102000,0x14C2420,0xFF2C208D,0xFEC01945,0xFE501231,0xF6000A12,0xC80005D2,0xBA000EBA,0xFEF01FA9,0xFEA01865,0xDE000465,0x9A002422,0x45FC2420,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
-0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table230[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,
-0x40000,0x80000,0x80000,0x80000,0x1,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x80000,0x80000,0x80000,0x1,0x80000,0x80000,0x80000,0x1,0x1,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x40000,0x80000,0x80000,
-0x80000,0xC00000,0xC00000,0xC00000,0xC00000,0x11C0000,0x11C0000,0x11C0000,0x13FC0000,0x13FC0000,0x5E000001,0x11C0000,0x11C0000,0x11C0000,0x13FC0000,0x13FC0000,0x5E000001,0x13FC0000,0x13FC0000,0x5E000001,0x5E000001,0x11C0000,0x11C0000,0x11C0000,0x13FC0000,0x13FC0000,0x5E000001,0x13FC0000,0x13FC0000,0x5E000001,0x5E000001,0x13FC0000,
-0x13FC0000,0x5E000001,0x5E000001,0x5E000001,0xE00000,0xCC0000,0xC00000,0x1040000,0x3400000,0x1980000,0x1D40000,0x27F80000,0xF00000,0x11C0000,0x1980000,0x5E000001,0x1980000,0x1D00000,0xBBFC0000,0xDDFC0000,0xE6000001,0xBBFC0000,0xDDFC0000,0xE6000001,0xDDFC0000,0xE6000001,0xE6000001,0xBBFC0000,0xDDFC0000,0xE6000001,0xDDFC0000,0xE6000001,
-0xE6000001,0xDDFC0000,0xE6000001,0xE6000001,0xE6000001,0xBBFC0000,0xDDFC0000,0xE6000001,0xDDFC0000,0xE6000001,0xE6000001,0xDDFC0000,0xE6000001,0xE6000001,0xE6000001,0xDDFC0000,0xE6000001,0xE6000001,0xE6000001,0xE6000001,0x91FC0000,0xFEC0000,0xFEC0000,0xC7FC0000,0xD9FC0000,0xE3F40000,0xE6000001,0xE6000001,0xABFC0000,0xCFFC0000,0xE7E00000,0xE6000001,
-0xD5FC0000,0xA48BEC,0xFE744D71,0xFE4C20D8,0xE6401785,0xFE5045F6,0xFE140D79,0xEC0C0111,0xF2042424,0xCA00098D,0xA2002426,0xFE306BE4,0xFA002945,0xD80015EB,0xD8003941,0xC00018FE,0x98002E12,0xA2006878,0x9C003FBB,0x84004933,0x6C00687B,0xF48BEC,0xEE004349,0xC6002804,0xC6004B2A,0xAE002717,0x920037A6,0x980072CF,0x960049C7,0x7E00509F,0x68006D47,0x1F08BEC,
-0x7E0062AC,0x72006404,0x5C007ADF,0x52008BEC,0xFE786595,0xFE8C7DDC,0xF8A07F6D,0xFE3040E1,0xFE04237E,0xEE00192E,0xC8000FFB,0xB6002345,0xFE546487,0xFE043C07,0xB60031CB,0x7E00509F,0x15C8BEC,0xDC6878,0xFEA43B8D,0xFE701888,0xE6601145,0xFE743D82,0xFE2C0C8D,0xEA1400D9,0xF2042420,0xCA00098D,0xA2042422,0x3446878,0xFA002945,0xD80015EB,0xD8003941,0xC00018FE,
-0x98002E12,0x27FC6878,0x9C003FBB,0x84004933,0x6C00687B,0x3446878,0xFA002945,0xD80015EB,0xD8003941,0xC00018FE,0x98002E12,0x27FC6878,0x9C003FBB,0x84004933,0x6C00687B,0x27FC6878,0x9C003FBB,0x84004933,0x6C00687B,0x6C00687B,0xFEA053D2,0xFECC6050,0xFECC5F74,0xFE543C9E,0xFE04237A,0xEE00192E,0xC8000FFB,0xB6002345,0xFE885438,0xFE2C3966,0xB6003152,0x84004933,
-0x1D46878,0x401784,0x401784,0x401784,0x401784,0xFE0C0074,0xFE0C0074,0xFE0C0074,0x8E000004,0x8E000004,0x5E000005,0x94001142,0x94001142,0x94001142,0x74000631,0x74000631,0x5800030A,0x48001142,0x48001142,0x44000A69,0x30001142,0x601783,0x601783,0x601783,0x62000ACD,0x62000ACD,0x4C0005EB,0x4000132D,0x4000132D,0x3E000C3A,0x2E00122B,0xC41783,
-0xC41783,0x3200106D,0x260014AE,0x20001783,0xFE200C8D,0xFE2C110D,0x401784,0xFA00078A,0xBC000679,0x8C000682,0x8C000559,0x6A0007B2,0xFE000D14,0xD00009C2,0x5C001166,0x3E000C3A,0x8C1783,0x601144,0x601144,0x601144,0x601144,0xFE0C0050,0xFE0C0050,0xFE0C0050,0x8C040001,0x8C040001,0x5E040001,0x901142,0x901142,0x901142,0x74000631,0x74000631,
-0x5800030A,0x1241142,0x1241142,0x44000A69,0x30001142,0x901142,0x901142,0x901142,0x74000631,0x74000631,0x5800030A,0x1241142,0x1241142,0x44000A69,0x30001142,0x1241142,0x1241142,0x44000A69,0x30001142,0x30001142,0xFA340B48,0xFE4C0CA0,0x601144,0xFA00078A,0xBC000679,0x8C000682,0x8C000559,0x6A0007B2,0xFE0C0BE2,0xD0000919,0xD01142,0x44000A69,
-0xD01142,0x1482420,0xFF0C12C8,0xFECC02FD,0xE6C00001,0x1E82420,0xFE640949,0xE63C0001,0x79F82420,0xCA000989,0xA2002422,0x1E82420,0xFE640949,0xE63C0001,0x79F82420,0xCA000989,0xA2002422,0x79F82420,0xCA000989,0xA2002422,0xA2002422,0x1E82420,0xFE640949,0xE63C0001,0x79F82420,0xCA000989,0xA2002422,0x79F82420,0xCA000989,0xA2002422,0xA2002422,0x79F82420,
-0xCA000989,0xA2002422,0xA2002422,0xA2002422,0xFF142048,0x75C2420,0xF9402104,0xFED81A29,0xFE68133D,0xFC000928,0xD40004ED,0xC2000DFA,0xFF102000,0xFEC01919,0xE60003BA,0xA2002422,0x55FC2420,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4000000,0x4000000,0x4000000,0x4000000,0x4000000,
-0x4000000,0x2000000,0x2000000,0x2000000,0x1,0x2000002,0x2000002,0x2000002,0x2000002,0x2000002,0x2000002,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x18000000,0x4,0x4,0xA000000,0x8000000,0x6000000,0x6000000,0x4000000,0x4000001,0x2000001,0x2000000,0x1,
-0x2,};
-static const uint32_t g_etc1_to_bc7_m6_table231[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x140000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,
-0x1C0000,0x380000,0x380000,0x380000,0x8000001,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x1C0000,0x380000,0x380000,0x380000,0x8000001,0x380000,0x380000,0x380000,0x8000001,0x8000001,0x2140000,0x140000,0x140000,0x180000,0x180000,0x2180000,0x2180000,0x200000,0x180000,0x180000,0x280000,0x380000,
-0x280000,0xD00000,0xD00000,0xD00000,0xD00000,0x1340000,0x1340000,0x1340000,0x1FF80000,0x1FF80000,0x66000001,0x1340000,0x1340000,0x1340000,0x1FF80000,0x1FF80000,0x66000001,0x1FF80000,0x1FF80000,0x66000001,0x66000001,0x1340000,0x1340000,0x1340000,0x1FF80000,0x1FF80000,0x66000001,0x1FF80000,0x1FF80000,0x66000001,0x66000001,0x1FF80000,
-0x1FF80000,0x66000001,0x66000001,0x66000001,0x2F00000,0x6DC0000,0xD00000,0x3180000,0x15C0000,0x1B80000,0x1FC0000,0x33F40000,0x1040000,0x1340000,0x1B80000,0x66000001,0x1B80000,0x1E00000,0xD3FC0000,0xE9FC0000,0xEE000001,0xD3FC0000,0xE9FC0000,0xEE000001,0xE9FC0000,0xEE000001,0xEE000001,0xD3FC0000,0xE9FC0000,0xEE000001,0xE9FC0000,0xEE000001,
-0xEE000001,0xE9FC0000,0xEE000001,0xEE000001,0xEE000001,0xD3FC0000,0xE9FC0000,0xEE000001,0xE9FC0000,0xEE000001,0xEE000001,0xE9FC0000,0xEE000001,0xEE000001,0xEE000001,0xE9FC0000,0xEE000001,0xEE000001,0xEE000001,0xEE000001,0xB7FC0000,0x17FC0000,0x17FC0000,0xDBFC0000,0xE7F80000,0xEDF40000,0xEE000001,0xEE000001,0xC9FC0000,0xE1FC0000,0xEFF00000,0xEE000001,
-0xE3FC0000,0xB09144,0xFE805385,0xFE582588,0xEE4C19B9,0xFE5C4AD6,0xFE201109,0xF6140195,0xFC0C2454,0xD6000915,0xAA082456,0xFE3C6E48,0xFE08296D,0xE200142D,0xE80036E6,0xC60015E6,0xA2002BFB,0xAE006878,0xA6003DB5,0x90004763,0x7400687B,0x1049144,0xFA004419,0xD2002844,0xD2004B5A,0xBA00258F,0x9E0036E6,0xA2007431,0x9C0048BB,0x8A004FCF,0x6E006E1B,0x7FC9144,
-0x840064EC,0x780065C4,0x66007DB4,0x58009144,0xFE786AC5,0xFAA48366,0xFEAC8499,0xFE40451B,0xFE04257E,0xFC0015D9,0xD2000D46,0xB6002035,0xFE5C697E,0xFE184056,0xBE002F7B,0x8A004FCF,0x1749144,0xEC6878,0xFEB03D85,0xFE7C1A74,0xEE701145,0xFE8C3F52,0xFE380EE1,0xF22400D9,0xFA142420,0xD6000915,0xAA142422,0x35C6878,0xFE08295D,0xE200142D,0xE80036E6,0xC60015E6,
-0xA2002BFB,0x33FC6878,0xA6003DB5,0x90004763,0x7400687B,0x35C6878,0xFE08295D,0xE200142D,0xE80036E6,0xC60015E6,0xA2002BFB,0x33FC6878,0xA6003DB5,0x90004763,0x7400687B,0x33FC6878,0xA6003DB5,0x90004763,0x7400687B,0x7400687B,0xFEB45485,0xF8E06116,0xFAE4601D,0xFE6C3E89,0xFE102549,0xFC0015D9,0xD2000D46,0xB6002035,0xFE985529,0xFE403AFB,0xBE002EEB,0x90004763,
-0x1F46878,0x4C19B8,0x4C19B8,0x4C19B8,0x4C19B8,0xFE180124,0xFE180124,0xFE180124,0x98080034,0x98080034,0x66080035,0xAC001142,0xAC001142,0xAC001142,0x80000521,0x80000521,0x620001FD,0x54001142,0x54001142,0x4A000989,0x38001142,0x7019B8,0x7019B8,0x7019B8,0x6E000AFD,0x6E000AFD,0x58000593,0x4C0013E5,0x4C0013E5,0x44000BEA,0x34001283,0xE419B8,
-0xE419B8,0x38001155,0x2C0015E6,0x240019BB,0xFE200E1D,0xFA441304,0x4C19B8,0xFE08079A,0xD4000562,0xA2000562,0x96000448,0x6E0006AD,0xFE000E34,0xF2000912,0x6600116E,0x44000BEA,0xA019B8,0x701144,0x701144,0x701144,0x701144,0xFE240080,0xFE240080,0xFE240080,0x94140001,0x94140001,0x66140001,0xA81142,0xA81142,0xA81142,0x80000521,0x80000521,
-0x620001FD,0x1581142,0x1581142,0x4A000989,0x38001142,0xA81142,0xA81142,0xA81142,0x80000521,0x80000521,0x620001FD,0x1581142,0x1581142,0x4A000989,0x38001142,0x1581142,0x1581142,0x4A000989,0x38001142,0x38001142,0xFE3C0B68,0xFA640CD1,0x701144,0xFE08078A,0xD4000562,0xA2000562,0x96000448,0x6E0006AD,0xFE140C14,0xF2000831,0xF01142,0x4A000989,
-0xF01142,0x1582420,0xFF241408,0xFEE40425,0xEED00001,0x3FC2420,0xFE880AB5,0xEE4C0001,0x85F82420,0xD60008B1,0xAA002422,0x3FC2420,0xFE880AB5,0xEE4C0001,0x85F82420,0xD60008B1,0xAA002422,0x85F82420,0xD60008B1,0xAA002422,0xAA002422,0x3FC2420,0xFE880AB5,0xEE4C0001,0x85F82420,0xD60008B1,0xAA002422,0x85F82420,0xD60008B1,0xAA002422,0xAA002422,0x85F82420,
-0xD60008B1,0xAA002422,0xAA002422,0xAA002422,0xFF342081,0xF6C2420,0xFF4C2114,0xFEEC1AC8,0xFE90147D,0xFE040910,0xDE000431,0xD0000D22,0xFF182032,0xFECC1A04,0xF2000301,0xAA002422,0x63FC2420,0x80034,0x80034,0x80034,0x80034,0x80034,0x80034,0x80034,0x80034,0x80034,0x80034,0x1C000000,0x1C000000,0x1C000000,0x1C000000,0x1C000000,
-0x1C000000,0xE000000,0xE000000,0xE000000,0x8000001,0x20C0032,0x20C0032,0x20C0032,0x20C0032,0x20C0032,0x20C0032,0xC000011,0xC000011,0xC000011,0x800000A,0x180032,0x180032,0x180032,0x4000022,0x4000032,0x98000000,0x80034,0x80034,0x44000000,0x2E000000,0x24000000,0x24000000,0x18000000,0x3600000D,0x24000008,0x12000001,0xC000011,
-0x140032,};
-static const uint32_t g_etc1_to_bc7_m6_table232[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x240001,0x380000,0x380000,0x380000,0x380000,0x380000,
-0x380000,0x700000,0x700000,0x700000,0x12000000,0x380000,0x380000,0x380000,0x380000,0x380000,0x380000,0x700000,0x700000,0x700000,0x12000000,0x700000,0x700000,0x700000,0x12000000,0x12000000,0x280000,0x240001,0x240001,0x2C0000,0x300000,0x340000,0x340000,0x400000,0x2C0000,0x300000,0x500000,0x700000,
-0x500000,0xE00001,0xE00001,0xE00001,0xE00001,0x1500000,0x1500000,0x1500000,0x2DF80000,0x2DF80000,0x70000000,0x1500000,0x1500000,0x1500000,0x2DF80000,0x2DF80000,0x70000000,0x2DF80000,0x2DF80000,0x70000000,0x70000000,0x1500000,0x1500000,0x1500000,0x2DF80000,0x2DF80000,0x70000000,0x2DF80000,0x2DF80000,0x70000000,0x70000000,0x2DF80000,
-0x2DF80000,0x70000000,0x70000000,0x70000000,0x7040000,0xF00000,0xE00001,0x1340000,0x17C0000,0x1E00000,0x11FC0000,0x3FF40000,0x11C0000,0x1500000,0x1E00000,0x70000000,0x1E00000,0x1F00001,0xEFFC0000,0xF7F80000,0xF8000000,0xEFFC0000,0xF7F80000,0xF8000000,0xF7F80000,0xF8000000,0xF8000000,0xEFFC0000,0xF7F80000,0xF8000000,0xF7F80000,0xF8000000,
-0xF8000000,0xF7F80000,0xF8000000,0xF8000000,0xF8000000,0xEFFC0000,0xF7F80000,0xF8000000,0xF7F80000,0xF8000000,0xF8000000,0xF7F80000,0xF8000000,0xF8000000,0xF8000000,0xF7F80000,0xF8000000,0xF8000000,0xF8000000,0xF8000000,0xE3FC0000,0xA7FC0000,0xA7FC0000,0xF1FC0000,0xF5FC0000,0xF9F00000,0xF8000000,0xF8000000,0xEBFC0000,0xF3FC0000,0xF9E40000,0xF8000000,
-0xF5FC0000,0xC097BB,0xFE8C5AEA,0xFE642B8F,0xF8581C9A,0xFE6850F9,0xFE3815EA,0xFC200282,0xFE14251D,0xDE040922,0xB41424D5,0xFE4471AC,0xFE082B02,0xEE0012C6,0xF40034A9,0xD20012B1,0xAE002A0C,0xBC006878,0xB2003B2E,0x9600456C,0x7E006878,0x31897B9,0xFA004686,0xE200290A,0xE2004B75,0xC6002442,0xA8003621,0xAE00761C,0xA60047DF,0x90004F04,0x7A006EE8,0x11FC97B9,
-0x900067C5,0x7E006825,0x6C008115,0x5E0097B9,0xFE8C716F,0xFEAC89AD,0xFEAC8B86,0xFE544AE1,0xFE1028CE,0xFC00135A,0xDE000A4D,0xCA001CD5,0xFE707042,0xFE244643,0xD6002C8C,0x90004F04,0x19497B9,0xFC687B,0xFEC43F8B,0xFE941CBB,0xF8841142,0xFE984159,0xFE5811F2,0xFC3800DA,0xFE2C2431,0xDE10090E,0xB4242421,0x1786878,0xFE082AF2,0xEE0012C6,0xF40034A9,0xD20012B1,
-0xAE002A0C,0x41FC6878,0xB2003B2E,0x9600456C,0x7E006878,0x1786878,0xFE082AF2,0xEE0012C6,0xF40034A9,0xD20012B1,0xAE002A0C,0x41FC6878,0xB2003B2E,0x9600456C,0x7E006878,0x41FC6878,0xB2003B2E,0x9600456C,0x7E006878,0x7E006878,0xFED055D8,0xFEEC6131,0xFEEC6086,0xFE8040FD,0xFE242846,0xFC00135A,0xDE000A4D,0xCA001CD5,0xFEB456A6,0xFE5C3DAE,0xD6002BE3,0x9600456C,
-0xFFC6878,0x581C9A,0x581C9A,0x581C9A,0x581C9A,0xFE240266,0xFE240266,0xFE240266,0xA21400B5,0xA21400B5,0x701400B5,0xC8001142,0xC8001142,0xC8001142,0x9200040D,0x9200040D,0x68000121,0x60001144,0x60001144,0x56000895,0x40001144,0x2801C9A,0x2801C9A,0x2801C9A,0x7A000B7D,0x7A000B7D,0x6200056D,0x580014D3,0x580014D3,0x50000BA2,0x400012FD,0x1081C9A,
-0x1081C9A,0x440012AD,0x32001788,0x2A001C9D,0xFC38101A,0xFE4C1596,0x581C9A,0xFE100871,0xF2000448,0xC0000464,0xAA00031D,0x80000585,0xFE140FDB,0xFC000884,0x7C001182,0x50000BA2,0xB81C9A,0x841142,0x841142,0x841142,0x841142,0xFE3400C1,0xFE3400C1,0xFE3400C1,0x9E240001,0x9E240001,0x70240001,0xC41142,0xC41142,0xC41142,0x9200040D,0x9200040D,
-0x68000121,0x18C1142,0x18C1142,0x56000895,0x40001144,0xC41142,0xC41142,0xC41142,0x9200040D,0x9200040D,0x68000121,0x18C1142,0x18C1142,0x56000895,0x40001144,0x18C1142,0x18C1142,0x56000895,0x40001144,0x40001144,0xFE580B95,0xFE6C0D0D,0x841142,0xFE1807E9,0xF2000448,0xC0000464,0xAA00031D,0x80000585,0xFE340C31,0xFC000784,0x1181142,0x56000895,
-0x1181142,0x1682422,0xFF301572,0xFEFC05B9,0xF8E00001,0x1FFC2420,0xFEA00C69,0xF85C0000,0x91FC2420,0xDC0007D9,0xB4002420,0x1FFC2420,0xFEA00C69,0xF85C0000,0x91FC2420,0xDC0007D9,0xB4002420,0x91FC2420,0xDC0007D9,0xB4002420,0xB4002420,0x1FFC2420,0xFEA00C69,0xF85C0000,0x91FC2420,0xDC0007D9,0xB4002420,0x91FC2420,0xDC0007D9,0xB4002420,0xB4002420,0x91FC2420,
-0xDC0007D9,0xB4002420,0xB4002420,0xB4002420,0xFD4C2102,0x9802420,0xFB642185,0xFF141BC1,0xFEA815C1,0xFE0409FA,0xE8000371,0xD8000C44,0xFF2C20D5,0xFEF01B2D,0xFE000248,0xB4002420,0x75FC2420,0x1400B5,0x1400B5,0x1400B5,0x1400B5,0x1400B5,0x1400B5,0x1400B5,0x1400B5,0x1400B5,0x1400B5,0x38000000,0x38000000,0x38000000,0x38000000,0x38000000,
-0x38000000,0x1C000000,0x1C000000,0x1C000000,0x12000000,0x1C00B5,0x1C00B5,0x1C00B5,0x1C00B5,0x1C00B5,0x1C00B5,0x18000044,0x18000044,0x18000044,0x12000024,0x3000B5,0x3000B5,0x3000B5,0xA000071,0x80000B5,0xFA040005,0x1400B5,0x1400B5,0x84000000,0x5C000000,0x46000000,0x46000000,0x2E000000,0x76000035,0x5600001A,0x22000004,0x18000044,
-0x2400B5,};
-static const uint32_t g_etc1_to_bc7_m6_table233[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x340001,0x500000,0x500000,0x500000,0x500000,0x500000,
-0x500000,0xA00000,0xA00000,0xA00000,0x1A000000,0x500000,0x500000,0x500000,0x500000,0x500000,0x500000,0xA00000,0xA00000,0xA00000,0x1A000000,0xA00000,0xA00000,0xA00000,0x1A000000,0x1A000000,0x4380000,0x340001,0x340001,0x63C0000,0x440000,0x480000,0x480000,0x580000,0x63C0000,0x440000,0x700000,0xA00000,
-0x700000,0xF00001,0xF00001,0xF00001,0xF00001,0x1680000,0x1680000,0x1680000,0x39F80000,0x39F80000,0x78000000,0x1680000,0x1680000,0x1680000,0x39F80000,0x39F80000,0x78000000,0x39F80000,0x39F80000,0x78000000,0x78000000,0x1680000,0x1680000,0x1680000,0x39F80000,0x39F80000,0x78000000,0x39F80000,0x39F80000,0x78000000,0x78000000,0x39F80000,
-0x39F80000,0x78000000,0x78000000,0x78000000,0x3180000,0x9000000,0xF00001,0x1480000,0x3940000,0x3FC0000,0x1FF80000,0x49F80000,0x1300000,0x1680000,0x3FC0000,0x78000000,0x3FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0xC89B73,0xFE98601A,0xFE70308B,0xFE641F86,0xFE7454F9,0xFE3819DE,0xFE280401,0xFE20257D,0xE4100916,0xBA1C2481,0xFE507334,0xFE142CA6,0xFA0011D2,0xFA0031B5,0xDE000F8D,0xB4002774,0xC6006693,0xB80037EE,0x9C004258,0x86006694,0x12C9B71,0xFA0048EA,0xE20029B6,0xE8004A85,0xCC0022AE,0xAE003499,0xBA0075EC,0xB20045F3,0x9A004CE6,0x80006DCC,0x1BF89B71,
-0x9600690D,0x8A0068A1,0x7200821D,0x64009B71,0xFE94756C,0xF8C08E33,0xFAC48FAF,0xFE544EB5,0xFE242B66,0xFC0011E2,0xEA0007C2,0xD0001968,0xFE7873EA,0xFE40496C,0xD6002964,0x9A004CE6,0x1AC9B71,0x10C6693,0xFED04023,0xFEAC1E33,0xFE941142,0xFEB0416D,0xFE6413AA,0xFE4400F5,0xFE402373,0xE41C08A6,0xBA342315,0x38C6693,0xFE202C26,0xFA0011D2,0xFA0031B5,0xDE000F8D,
-0xB4002774,0x4BFC6693,0xB80037EE,0x9C004258,0x86006694,0x38C6693,0xFE202C26,0xFA0011D2,0xFA0031B5,0xDE000F8D,0xB4002774,0x4BFC6693,0xB80037EE,0x9C004258,0x86006694,0x4BFC6693,0xB80037EE,0x9C004258,0x86006694,0x86006694,0xFED05534,0xF900600B,0xFD085F33,0xFE9440FA,0xFE3829B2,0xFC0011E2,0xEA0007C2,0xD0001968,0xFEC455C3,0xFE843E6A,0xDE0028A6,0x9C004258,
-0x1DF86693,0x641F86,0x641F86,0x641F86,0x641F86,0xFE280401,0xFE280401,0xFE280401,0xAC1C016D,0xAC1C016D,0x781C016D,0xE0001142,0xE0001142,0xE0001142,0xA200031D,0xA200031D,0x74000089,0x6C001144,0x6C001144,0x5C0007D9,0x48001144,0x901F85,0x901F85,0x901F85,0x86000C35,0x86000C35,0x680005B5,0x620015A4,0x620015A4,0x58000B8A,0x46001365,0x1241F85,
-0x1241F85,0x4A001419,0x3E001918,0x30001F85,0xFE3C123E,0xF45818B1,0x641F86,0xFE180989,0xFC000384,0xC8000368,0xB800025D,0x8C0004A5,0xFE201212,0xFE0008CA,0x8600118A,0x58000B8A,0xD01F85,0x941142,0x941142,0x941142,0x941142,0xFE4400F5,0xFE4400F5,0xFE4400F5,0xA6340001,0xA6340001,0x78340001,0xDC1142,0xDC1142,0xDC1142,0xA200031D,0xA200031D,
-0x74000089,0x1BC1142,0x1BC1142,0x5C0007D9,0x48001144,0xDC1142,0xDC1142,0xDC1142,0xA200031D,0xA200031D,0x74000089,0x1BC1142,0x1BC1142,0x5C0007D9,0x48001144,0x1BC1142,0x1BC1142,0x5C0007D9,0x48001144,0x48001144,0xFA6C0BE2,0xFC880D22,0x941142,0xFE340845,0xFC000384,0xC8000368,0xB800025D,0x8C0004A5,0xFA480C82,0xFE0407B4,0x1381142,0x5C0007D9,
-0x1381142,0x1782312,0xFF441595,0xFF0806B9,0xFEF00001,0x35FC2312,0xFEB80D39,0xFE700000,0x9DF42312,0xE60006C4,0xBA002314,0x35FC2312,0xFEB80D39,0xFE700000,0x9DF42312,0xE60006C4,0xBA002314,0x9DF42312,0xE60006C4,0xBA002314,0xBA002314,0x35FC2312,0xFEB80D39,0xFE700000,0x9DF42312,0xE60006C4,0xBA002314,0x9DF42312,0xE60006C4,0xBA002314,0xBA002314,0x9DF42312,
-0xE60006C4,0xBA002314,0xBA002314,0xBA002314,0xFF502032,0x1902312,0xFF6C2099,0xFF201B94,0xFED01619,0xFE180AF1,0xF20002A1,0xE0000B14,0xFD502000,0xFF081AAA,0xFE0001C4,0xBA002314,0x81FC2312,0x1C016D,0x1C016D,0x1C016D,0x1C016D,0x1C016D,0x1C016D,0x1C016D,0x1C016D,0x1C016D,0x1C016D,0x50000000,0x50000000,0x50000000,0x50000000,0x50000000,
-0x50000000,0x26000001,0x26000001,0x26000001,0x1A000000,0x28016D,0x28016D,0x28016D,0x28016D,0x28016D,0x28016D,0x22000082,0x22000082,0x22000082,0x18000044,0x4C016D,0x4C016D,0x4C016D,0x100000DD,0xC00016D,0xFE0C003D,0x1C016D,0x1C016D,0xBC000000,0x82000000,0x64000000,0x64000000,0x42000000,0xA0000074,0x7400003A,0x32000009,0x22000082,
-0x34016D,};
-static const uint32_t g_etc1_to_bc7_m6_table234[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x440001,0x680000,0x680000,0x680000,0x680000,0x680000,
-0x680000,0xD00000,0xD00000,0xD00000,0x22000000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0xD00000,0xD00000,0xD00000,0x22000000,0xD00000,0xD00000,0xD00000,0x22000000,0x22000000,0xC480000,0x440001,0x440001,0x500000,0x580000,0x25C0000,0x25C0000,0x740000,0x500000,0x580000,0x940000,0xD00000,
-0x940000,0x1000001,0x1000001,0x1000001,0x1000001,0x1800000,0x1800000,0x1800000,0x45F80000,0x45F80000,0x80000000,0x1800000,0x1800000,0x1800000,0x45F80000,0x45F80000,0x80000000,0x45F80000,0x45F80000,0x80000000,0x80000000,0x1800000,0x1800000,0x1800000,0x45F80000,0x45F80000,0x80000000,0x45F80000,0x45F80000,0x80000000,0x80000000,0x45F80000,
-0x45F80000,0x80000000,0x80000000,0x80000000,0x12C0000,0x1140000,0x1000001,0x35C0000,0x1B00000,0x13FC0000,0x2BFC0000,0x55F40000,0x1440000,0x1800000,0x13FC0000,0x80000000,0x13FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0xD0985B,0xFEA46016,0xFE7C32E7,0xFE6C22C6,0xFE80534D,0xFE4C1AEE,0xFE300602,0xFE2C22E1,0xE8180846,0xBE242169,0xFE5C6E98,0xFE142B26,0xFC001148,0xFA002BC5,0xE2000B41,0xBA0021D8,0xD0005F33,0xBE0031CA,0xA6003B0D,0x8A005F34,0x1389859,0xFC004866,0xE80029FE,0xEE004581,0xD2001F56,0xB4002FCD,0xC0006FCC,0xB20040B3,0x9C004648,0x86006704,0x21F89859,
-0x9C0065F9,0x8A0063E1,0x78007CE9,0x68009859,0xFEA072F9,0xFCC88B1B,0xFECC8CE7,0xFE6C4D3A,0xFE2829D6,0xFE040EE2,0xEE0004B9,0xD6001419,0xFE7871FA,0xFE4047CC,0xDE00246A,0x9C004648,0x1BC9859,0x1185F33,0xFEE83C13,0xFEB81D03,0xFEA41142,0xFEC43C4B,0xFE7C126A,0xFE5C013D,0xFE4C1F8B,0xE8300726,0xBE441F05,0x1A05F33,0xFE3829C6,0xFC001148,0xFA002BC5,0xE2000B41,
-0xBA0021D8,0x55F85F33,0xBE0031CA,0xA6003B0D,0x8A005F34,0x1A05F33,0xFE3829C6,0xFC001148,0xFA002BC5,0xE2000B41,0xBA0021D8,0x55F85F33,0xBE0031CA,0xA6003B0D,0x8A005F34,0x55F85F33,0xBE0031CA,0xA6003B0D,0x8A005F34,0x8A005F34,0xFEE44F59,0xFF0C58D3,0xFF0C5843,0xFEB03CE2,0xFE4826EA,0xFE040EDE,0xEE0004B9,0xD6001419,0xFEDC4F89,0xFE8439AA,0xDE0023A6,0xA6003B0D,
-0x27FC5F33,0x6C22C6,0x6C22C6,0x6C22C6,0x6C22C6,0xFE300602,0xFE300602,0xFE300602,0xB6240265,0xB6240265,0x80240265,0xF8001142,0xF8001142,0xF8001142,0xAE00025D,0xAE00025D,0x80000031,0x78001144,0x78001144,0x66000728,0x50001144,0xA422C5,0xA422C5,0xA422C5,0x92000D2D,0x92000D2D,0x7400063D,0x6E0016B4,0x6E0016B4,0x60000B84,0x4C0013E5,0x14C22C5,
-0x14C22C5,0x500015CD,0x44001AD8,0x360022C5,0xFE4C14D5,0xFA641BA9,0x6C22C6,0xFE240B44,0xFE040388,0xE20002B1,0xCC00019A,0x960003E8,0xFC301481,0xFE000A0A,0x9600119B,0x60000B84,0xE822C5,0xA41142,0xA41142,0xA41142,0xA41142,0xFE5C013D,0xFE5C013D,0xFE5C013D,0xAE440001,0xAE440001,0x80440001,0xF41142,0xF41142,0xF41142,0xAE00025D,0xAE00025D,
-0x80000031,0x1F01142,0x1F01142,0x66000728,0x50001144,0xF41142,0xF41142,0xF41142,0xAE00025D,0xAE00025D,0x80000031,0x1F01142,0x1F01142,0x66000728,0x50001144,0x1F01142,0x1F01142,0x66000728,0x50001144,0x50001144,0xFE740C02,0xFE8C0D6A,0xA41142,0xFE440894,0xFE040384,0xE20002B1,0xCC00019A,0x960003E8,0xFE500CB2,0xFE1807FD,0x15C1142,0x66000728,
-0x15C1142,0x1801F02,0xFF501315,0xFF2005F1,0xFF000001,0x41FC1F02,0xFECC0BD5,0xFE880000,0xA1FC1F02,0xEC0004C8,0xBE001F04,0x41FC1F02,0xFECC0BD5,0xFE880000,0xA1FC1F02,0xEC0004C8,0xBE001F04,0xA1FC1F02,0xEC0004C8,0xBE001F04,0xBE001F04,0x41FC1F02,0xFECC0BD5,0xFE880000,0xA1FC1F02,0xEC0004C8,0xBE001F04,0xA1FC1F02,0xEC0004C8,0xBE001F04,0xBE001F04,0xA1FC1F02,
-0xEC0004C8,0xBE001F04,0xBE001F04,0xBE001F04,0xF7681C99,0x5981F02,0xFF6C1D09,0xFF30184D,0xFEE81379,0xFE4809A1,0xF4000164,0xE0000894,0xFD581C22,0xFF1417A5,0xFE000124,0xBE001F04,0x89FC1F02,0x240265,0x240265,0x240265,0x240265,0x240265,0x240265,0x240265,0x240265,0x240265,0x240265,0x6A000000,0x6A000000,0x6A000000,0x6A000000,0x6A000000,
-0x6A000000,0x32000001,0x32000001,0x32000001,0x22000000,0x340265,0x340265,0x340265,0x340265,0x340265,0x340265,0x280000DA,0x280000DA,0x280000DA,0x1E000074,0x640265,0x640265,0x640265,0x16000171,0x10000265,0xF21400C8,0x240265,0x240265,0xF6000000,0xAA000000,0x82000000,0x82000000,0x54000000,0xC40000C1,0x96000061,0x40000010,0x280000DA,
-0x480265,};
-static const uint32_t g_etc1_to_bc7_m6_table235[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x540001,0x800000,0x800000,0x800000,0x800000,0x800000,
-0x800000,0x1000000,0x1000000,0x1000000,0x2A000000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x1000000,0x1000000,0x1000000,0x2A000000,0x1000000,0x1000000,0x1000000,0x2A000000,0x2A000000,0x5C0000,0x540001,0x540001,0x640000,0x6C0000,0x740000,0x740000,0x900000,0x640000,0x6C0000,0xB40000,0x1000000,
-0xB40000,0x1100001,0x1100001,0x1100001,0x1100001,0x1980000,0x1980000,0x1980000,0x51F80000,0x51F80000,0x88000000,0x1980000,0x1980000,0x1980000,0x51F80000,0x51F80000,0x88000000,0x51F80000,0x51F80000,0x88000000,0x88000000,0x1980000,0x1980000,0x1980000,0x51F80000,0x51F80000,0x88000000,0x51F80000,0x51F80000,0x88000000,0x88000000,0x51F80000,
-0x51F80000,0x88000000,0x88000000,0x88000000,0x73C0000,0x1240000,0x1100001,0x1740000,0x1CC0000,0x21FC0000,0x39FC0000,0x5FF80000,0x1580000,0x1980000,0x21FC0000,0x88000000,0x21FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0xD895C3,0xFEB0608A,0xFE8835A3,0xFE78265A,0xFE80521D,0xFE581C6A,0xFE440859,0xFE3820E5,0xEC2007F6,0xC22C1ED1,0xFE686AA4,0xFE202A26,0xFE0C116E,0xFE04269A,0xE80007B5,0xC0001CD4,0xD600582B,0xC4002C2E,0xAC003425,0x90005828,0x14495C1,0xFE08488A,0xEE002B26,0xF400410D,0xD8001CB6,0xB4002B8D,0xC6006A14,0xB8003BF7,0xA4004028,0x8C00609C,0x27F895C1,
-0x9C006399,0x90005FA9,0x7E00782D,0x6C0095C1,0xFEA07179,0xFECC888F,0xFECC8AE7,0xFE6C4C2A,0xFE382902,0xFE040CD2,0xF4000288,0xD8000F71,0xFE906FEE,0xFE5046F2,0xE600202C,0xA4004028,0x1D095C1,0x120582B,0xFEF43833,0xFEC01C1A,0xFEB41142,0xFED03783,0xFE88113A,0xFE680195,0xFE641BE3,0xEA4005CA,0xC2541B35,0x1B05828,0xFE4C27C5,0xFE141142,0xFE08268D,0xE80007B5,
-0xC0001CD4,0x5DF45828,0xC4002C2E,0xAC003425,0x90005828,0x1B05828,0xFE4C27C5,0xFE141142,0xFE08268D,0xE80007B5,0xC0001CD4,0x5DF45828,0xC4002C2E,0xAC003425,0x90005828,0x5DF45828,0xC4002C2E,0xAC003425,0x90005828,0x90005828,0xFEF8494A,0xFF0C5253,0xFF0C5243,0xFEB03872,0xFE682411,0xFE040CCE,0xF4000288,0xD8000F71,0xFEDC4979,0xFE9035DE,0xE6001F68,0xAC003425,
-0x31FC5828,0x78265A,0x78265A,0x78265A,0x78265A,0xFE440859,0xFE440859,0xFE440859,0xC02C039D,0xC02C039D,0x882C039D,0xFE0C116E,0xFE0C116E,0xFE0C116E,0xBA0001BD,0xBA0001BD,0x88000004,0x84001144,0x84001144,0x72000668,0x58001144,0x2B0265A,0x2B0265A,0x2B0265A,0xA2000E36,0xA2000E36,0x7A00070D,0x740017D8,0x740017D8,0x68000B94,0x5200147D,0x168265A,
-0x168265A,0x560017C9,0x4A001CC8,0x3A00265D,0xFE5817D5,0xFE6C1F01,0x78265A,0xFE340D49,0xFE14045E,0xEE0001F4,0xDA000112,0xAA00031D,0xFE341721,0xFE100BF2,0xA60011A8,0x68000B94,0xFC265A,0xB41142,0xB41142,0xB41142,0xB41142,0xFE680195,0xFE680195,0xFE680195,0xB6540001,0xB6540001,0x88540001,0x10C1142,0x10C1142,0x10C1142,0xBA0001BD,0xBA0001BD,
-0x88000004,0xBF81142,0xBF81142,0x72000668,0x58001144,0x10C1142,0x10C1142,0x10C1142,0xBA0001BD,0xBA0001BD,0x88000004,0xBF81142,0xBF81142,0x72000668,0x58001144,0xBF81142,0xBF81142,0x72000668,0x58001144,0x58001144,0xFE900C31,0xFCA80D75,0xB41142,0xFE5C08C9,0xFE1803E8,0xEE0001F4,0xDA000112,0xAA00031D,0xFA700CD1,0xFE300869,0x17C1142,0x72000668,
-0x17C1142,0x1881B32,0xFF5C10BD,0xFF2C052D,0xFF100001,0x4DFC1B32,0xFEE40A55,0xFEA00000,0xA7FC1B32,0xEC000328,0xC2001B34,0x4DFC1B32,0xFEE40A55,0xFEA00000,0xA7FC1B32,0xEC000328,0xC2001B34,0xA7FC1B32,0xEC000328,0xC2001B34,0xC2001B34,0x4DFC1B32,0xFEE40A55,0xFEA00000,0xA7FC1B32,0xEC000328,0xC2001B34,0xA7FC1B32,0xEC000328,0xC2001B34,0xC2001B34,0xA7FC1B32,
-0xEC000328,0xC2001B34,0xC2001B34,0xC2001B34,0xFB7018F1,0x9A01B32,0xFB841962,0xFF401540,0xFEE81109,0xFE480871,0xF800009D,0xE4000665,0xFF5C1892,0xFF2014D2,0xFE1000E5,0xC2001B34,0x91FC1B32,0x2C039D,0x2C039D,0x2C039D,0x2C039D,0x2C039D,0x2C039D,0x2C039D,0x2C039D,0x2C039D,0x2C039D,0x82000000,0x82000000,0x82000000,0x82000000,0x82000000,
-0x82000000,0x3E000001,0x3E000001,0x3E000001,0x2A000000,0x40039D,0x40039D,0x40039D,0x40039D,0x40039D,0x40039D,0x34000152,0x34000152,0x34000152,0x280000AD,0x7C039D,0x7C039D,0x7C039D,0x1C00022D,0x1400039D,0xF61C0188,0x2C039D,0x2C039D,0xFE04001D,0xD2000000,0xA0000000,0xA0000000,0x68000000,0xF6000121,0xC2000099,0x50000019,0x34000152,
-0x58039D,};
-static const uint32_t g_etc1_to_bc7_m6_table236[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x680000,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,
-0x2980000,0x1380000,0x1380000,0x1380000,0x32000001,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,0x2980000,0x1380000,0x1380000,0x1380000,0x32000001,0x1380000,0x1380000,0x1380000,0x32000001,0x32000001,0xE6C0000,0x680000,0x680000,0x780000,0x2800000,0x8C0000,0x8C0000,0x2AC0000,0x780000,0x2800000,0xDC0000,0x1380000,
-0xDC0000,0x1240000,0x1240000,0x1240000,0x1240000,0x3B00000,0x3B00000,0x3B00000,0x5DFC0000,0x5DFC0000,0x90000001,0x3B00000,0x3B00000,0x3B00000,0x5DFC0000,0x5DFC0000,0x90000001,0x5DFC0000,0x5DFC0000,0x90000001,0x90000001,0x3B00000,0x3B00000,0x3B00000,0x5DFC0000,0x5DFC0000,0x90000001,0x5DFC0000,0x5DFC0000,0x90000001,0x90000001,0x5DFC0000,
-0x5DFC0000,0x90000001,0x90000001,0x90000001,0x1540000,0x1380000,0x1240000,0x18C0000,0x1EC0000,0x33FC0000,0x49F80000,0x6BF80000,0x36C0000,0x3B00000,0x33FC0000,0x90000001,0x33FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0xE49371,0xFEB06174,0xFE943921,0xFE842AC8,0xFE8C5159,0xFE641E9A,0xFE500B99,0xFE401F71,0xEE300834,0xC8341C7D,0xFE7466F6,0xFE2C29B8,0xFE181234,0xFE0821B1,0xEE000485,0xC60017E2,0xE00050A2,0xCA002684,0xB2002CE1,0x960050A2,0x150936F,0xFE0849BC,0xEE002D78,0xFA003CBD,0xE2001A89,0xBA00277B,0xCC006426,0xC0003749,0xAA0039C2,0x920059D2,0x2DF8936F,
-0xA60061D4,0x96005B93,0x8400735F,0x7000936F,0xFEB46FEE,0xFECC86CD,0xF6DC89B8,0xFE804B93,0xFE3C288E,0xFE040BB2,0xF80000EC,0xE0000ADE,0xFE986E7F,0xFE544677,0xF0001BFE,0xAA0039C2,0x1E0936F,0x12C50A5,0xFF00340D,0xFED81AE4,0xFEC41144,0xFEDC3275,0xFEA01012,0xFE8001F9,0xFE701821,0xEA580474,0xC8681735,0x1C050A2,0xFE642553,0xFE2C1144,0xFE0821A1,0xEE000485,
-0xC60017E2,0x65F850A2,0xCA002684,0xB2002CE1,0x960050A2,0x1C050A2,0xFE642553,0xFE2C1144,0xFE0821A1,0xEE000485,0xC60017E2,0x65F850A2,0xCA002684,0xB2002CE1,0x960050A2,0x65F850A2,0xCA002684,0xB2002CE1,0x960050A2,0x960050A2,0xFEF84350,0xFB244B59,0xFD284B14,0xFEC033C8,0xFE7C2149,0xFE040BAE,0xF80000EC,0xE0000ADE,0xFEF843BD,0xFEA431C2,0xF0001B1D,0xB2002CE1,
-0x3DF850A2,0x842AC8,0x842AC8,0x842AC8,0x842AC8,0xFE500B99,0xFE500B99,0xFE500B99,0xCC340548,0xCC340548,0x90340549,0xFE181234,0xFE181234,0xFE181234,0xCC000121,0xCC000121,0x92040009,0x92001142,0x92001142,0x7E0005AA,0x62001142,0xC42AC8,0xC42AC8,0xC42AC8,0xA8000FDA,0xA8000FDA,0x86000849,0x80001946,0x80001946,0x74000BC6,0x5E001523,0x18C2AC8,
-0x18C2AC8,0x5C001A61,0x50001F2E,0x40002ACB,0xFE681BBA,0xF67C23A8,0x842AC8,0xFE441026,0xFE1805AA,0xFC000171,0xEA000088,0xB6000274,0xFE3C1B18,0xFE180E8E,0xB60011C3,0x74000BC6,0x1182AC8,0xC41144,0xC41144,0xC41144,0xC41144,0xFE8001F9,0xFE8001F9,0xFE8001F9,0xBE680001,0xBE680001,0x90680001,0x3241142,0x3241142,0x3241142,0xCC000121,0xCC000121,
-0x900C0001,0x17FC1142,0x17FC1142,0x7E0005AA,0x62001142,0x3241142,0x3241142,0x3241142,0xCC000121,0xCC000121,0x900C0001,0x17FC1142,0x17FC1142,0x7E0005AA,0x62001142,0x17FC1142,0x17FC1142,0x7E0005AA,0x62001142,0x62001142,0xFEA00C82,0xF6BC0DC8,0xC41144,0xFE78094D,0xFE2C046A,0xFC000171,0xEA000088,0xB6000274,0xFE780D0D,0xFE4808B4,0x1A41142,0x7E0005AA,
-0x1A41142,0x1901735,0xFF680E48,0xFF380464,0xFF240000,0x59FC1735,0xFEFC08C8,0xFEB80001,0xADFC1735,0xF20001B1,0xC8001735,0x59FC1735,0xFEFC08C8,0xFEB80001,0xADFC1735,0xF20001B1,0xC8001735,0xADFC1735,0xF20001B1,0xC8001735,0xC8001735,0x59FC1735,0xFEFC08C8,0xFEB80001,0xADFC1735,0xF20001B1,0xC8001735,0xADFC1735,0xF20001B1,0xC8001735,0xC8001735,0xADFC1735,
-0xF20001B1,0xC8001735,0xC8001735,0xC8001735,0xFF781522,0x1AC1735,0xFF8C1589,0xFF401231,0xFEFC0E90,0xFE840734,0xFC000014,0xEC000454,0xFF701520,0xFF4011AD,0xFE3000C5,0xC8001735,0x99FC1735,0x340548,0x340548,0x340548,0x340548,0x340548,0x340548,0x340548,0x340548,0x340548,0x340548,0x9C000000,0x9C000000,0x9C000000,0x9C000000,0x9C000000,
-0x9C000000,0x4C000000,0x4C000000,0x4C000000,0x32000001,0x4C0548,0x4C0548,0x4C0548,0x4C0548,0x4C0548,0x4C0548,0x3A0001F9,0x3A0001F9,0x3A0001F9,0x2E0000FA,0x980548,0x980548,0x980548,0x2000034D,0x1800054A,0xFA2402AD,0x340548,0x340548,0xFE100091,0xFE000000,0xC2000000,0xC2000000,0x7E000000,0xFC000200,0xE40000DD,0x60000024,0x3A0001F9,
-0x6C0548,};
-static const uint32_t g_etc1_to_bc7_m6_table237[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x780000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,
-0x2B00000,0x1680000,0x1680000,0x1680000,0x3A000001,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x2B00000,0x1680000,0x1680000,0x1680000,0x3A000001,0x1680000,0x1680000,0x1680000,0x3A000001,0x3A000001,0x800000,0x780000,0x780000,0x8C0000,0x2940000,0xA40000,0xA40000,0xC80000,0x8C0000,0x2940000,0xFC0000,0x1680000,
-0xFC0000,0x1340000,0x1340000,0x1340000,0x1340000,0x1C80000,0x1C80000,0x1C80000,0x69FC0000,0x69FC0000,0x98000001,0x1C80000,0x1C80000,0x1C80000,0x69FC0000,0x69FC0000,0x98000001,0x69FC0000,0x69FC0000,0x98000001,0x98000001,0x1C80000,0x1C80000,0x1C80000,0x69FC0000,0x69FC0000,0x98000001,0x69FC0000,0x69FC0000,0x98000001,0x98000001,0x69FC0000,
-0x69FC0000,0x98000001,0x98000001,0x98000001,0x5640000,0x1480000,0x1340000,0x1A40000,0x7FC0000,0x41FC0000,0x55FC0000,0x77F40000,0x3800000,0x1C80000,0x41FC0000,0x98000001,0x41FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0xEC91E9,0xFEC46279,0xFEA03CA5,0xFE902F14,0xFE985139,0xFE64210A,0xFE5C0EF9,0xFE4C1EBD,0xF23808E4,0xCC3C1AF5,0xFE806462,0xFE3829E8,0xFE241378,0xFE081E61,0xF000026D,0xCC00141E,0xE8004A4E,0xD0002208,0xB80026E5,0x9C004A4E,0x15C91E7,0xFE084BDC,0xF4003058,0xFA0039ED,0xE2001939,0xC000247F,0xD8005F3E,0xC60033B5,0xAE00348E,0x98005432,0x33F891E7,
-0xA60060B4,0x9C005887,0x8A006F9B,0x740091E7,0xFEBC6F6D,0xF8E085F5,0xFAE48878,0xFE804B93,0xFE4C28D8,0xFE100BA9,0xFC000045,0xE40007A9,0xFE986E0F,0xFE5C46BB,0xF60018B4,0xAE00348E,0x1F091E7,0x1384A4D,0xFF0C3095,0xFEE419E8,0xFED41144,0xFEE82E49,0xFEAC0F1E,0xFE980269,0xFE881509,0xEE6C0364,0xCC7813ED,0x1D04A4D,0xFE70234B,0xFE441142,0xFE141E3D,0xF000026D,
-0xCC00141E,0x6DF84A4D,0xD0002208,0xB80026E5,0x9C004A4E,0x1D04A4D,0xFE70234B,0xFE441142,0xFE141E3D,0xF000026D,0xCC00141E,0x6DF84A4D,0xD0002208,0xB80026E5,0x9C004A4E,0x6DF84A4D,0xD0002208,0xB80026E5,0x9C004A4E,0x9C004A4E,0xFF143E02,0xFF2C4531,0xFF2C4538,0xFED43009,0xFE901F05,0xFE240B1D,0xFC000045,0xE40007A9,0xFEF83E4D,0xFEC02DC4,0xF60017D3,0xB80026E5,
-0x45FC4A4D,0x902F14,0x902F14,0x902F14,0x902F14,0xFE5C0EF9,0xFE5C0EF9,0xFE5C0EF9,0xD63C0708,0xD63C0708,0x983C0709,0xFE241378,0xFE241378,0xFE241378,0xD80000B9,0xD80000B9,0x9A080035,0x9E001142,0x9E001142,0x84000502,0x6A001142,0x2D02F13,0x2D02F13,0x2D02F13,0xB400119A,0xB400119A,0x8C0009B1,0x8C001AA6,0x8C001AA6,0x7A000C12,0x620015C2,0x1AC2F13,
-0x1AC2F13,0x66001D13,0x56002186,0x46002F13,0xFE681F7A,0xFC8827B4,0x902F14,0xFE4C1319,0xFE2C078E,0xFE040199,0xFC000041,0xC00001D4,0xFE501E81,0xFE301181,0xC60011D4,0x7A000C12,0x12C2F13,0xD41144,0xD41144,0xD41144,0xD41144,0xFE980269,0xFE980269,0xFE980269,0xC6780001,0xC6780001,0x98780001,0x33C1142,0x33C1142,0x33C1142,0xD80000B9,0xD80000B9,
-0x981C0001,0x23FC1142,0x23FC1142,0x84000502,0x6A001142,0x33C1142,0x33C1142,0x33C1142,0xD80000B9,0xD80000B9,0x981C0001,0x23FC1142,0x23FC1142,0x84000502,0x6A001142,0x23FC1142,0x23FC1142,0x84000502,0x6A001142,0x6A001142,0xFAB40CD1,0xFECC0DC8,0xD41144,0xFE880994,0xFE4804D9,0xFE0C0190,0xFC000041,0xC00001D4,0xFE940D2A,0xFE5C0901,0x1C81142,0x84000502,
-0x1C81142,0x19813ED,0xFF740C44,0xFF4C03D9,0xFF340000,0x65FC13ED,0xFF080784,0xFED00000,0xB3FC13ED,0xF80000CD,0xCC0013ED,0x65FC13ED,0xFF080784,0xFED00000,0xB3FC13ED,0xF80000CD,0xCC0013ED,0xB3FC13ED,0xF80000CD,0xCC0013ED,0xCC0013ED,0x65FC13ED,0xFF080784,0xFED00000,0xB3FC13ED,0xF80000CD,0xCC0013ED,0xB3FC13ED,0xF80000CD,0xCC0013ED,0xCC0013ED,0xB3FC13ED,
-0xF80000CD,0xCC0013ED,0xCC0013ED,0xCC0013ED,0xFF781232,0x1B413ED,0xFF8C1289,0xFF580FA1,0xFF100C84,0xFE980631,0xFE0C0000,0xF20002D0,0xFF701220,0xFF400F1D,0xFE5000A9,0xCC0013ED,0x9FFC13ED,0x3C0708,0x3C0708,0x3C0708,0x3C0708,0x3C0708,0x3C0708,0x3C0708,0x3C0708,0x3C0708,0x3C0708,0xB6000000,0xB6000000,0xB6000000,0xB6000000,0xB6000000,
-0xB6000000,0x58000000,0x58000000,0x58000000,0x3A000001,0x580708,0x580708,0x580708,0x580708,0x580708,0x580708,0x460002A1,0x460002A1,0x460002A1,0x34000152,0xB00708,0xB00708,0xB00708,0x2600045D,0x1C00070A,0xFE2C03F5,0x3C0708,0x3C0708,0xFA180154,0xFC080029,0xE0000000,0xE0000000,0x92000000,0xFA080322,0xFE000140,0x70000031,0x460002A1,
-0x7C0708,};
-static const uint32_t g_etc1_to_bc7_m6_table238[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0x880000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,
-0xC80000,0x1980000,0x1980000,0x1980000,0x42000001,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0xC80000,0x1980000,0x1980000,0x1980000,0x42000001,0x1980000,0x1980000,0x1980000,0x42000001,0x42000001,0x900000,0x880000,0x880000,0x49C0000,0x2A80000,0xB80000,0xB80000,0xE40000,0x49C0000,0x2A80000,0x1200000,0x1980000,
-0x1200000,0x1440000,0x1440000,0x1440000,0x1440000,0x1E00000,0x1E00000,0x1E00000,0x75FC0000,0x75FC0000,0xA0000001,0x1E00000,0x1E00000,0x1E00000,0x75FC0000,0x75FC0000,0xA0000001,0x75FC0000,0x75FC0000,0xA0000001,0xA0000001,0x1E00000,0x1E00000,0x1E00000,0x75FC0000,0x75FC0000,0xA0000001,0x75FC0000,0x75FC0000,0xA0000001,0xA0000001,0x75FC0000,
-0x75FC0000,0xA0000001,0xA0000001,0xA0000001,0x1780000,0x5580000,0x1440000,0x1B80000,0x1BFC0000,0x51FC0000,0x63FC0000,0x81F80000,0x3940000,0x1E00000,0x51FC0000,0xA0000001,0x51FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0xF490E1,0xFEC46419,0xFEA04085,0xFE9833B4,0xFEA451A9,0xFE7023E2,0xFE5C12C9,0xFE581EA9,0xF6400A14,0xD04419ED,0xFE806262,0xFE402ADB,0xFE301544,0xFE141BF1,0xF60000F9,0xD00010E6,0xF000444D,0xD6001E14,0xBE002159,0xA000444E,0x16890DF,0xFE144EC8,0xFA003418,0xFA00381D,0xE80018CD,0xC6002223,0xE2005A92,0xCC0030B1,0xB4002FCA,0x98004EF2,0x39F890DF,
-0xAC006018,0x9C005607,0x8A006C1B,0x780090DF,0xFEBC6F7D,0xFCE884ED,0xFEEC87B8,0xFE944C1E,0xFE50299A,0xFE180BFB,0xFE040069,0xEA0004E2,0xFEB46DCE,0xFE704795,0xF6001634,0xB4002FCA,0x3FC90DF,0x144444D,0xFF182D4D,0xFEF01904,0xFEE41144,0xFEF42A65,0xFEB80E5A,0xFEA402D5,0xFE941241,0xF07C0278,0xD08810E5,0x1E0444D,0xFE882153,0xFE5C1142,0xFE2C1B35,0xF60000F9,
-0xD00010E6,0x75FC444D,0xD6001E14,0xBE002159,0xA000444E,0x1E0444D,0xFE882153,0xFE5C1142,0xFE2C1B35,0xF60000F9,0xD00010E6,0x75FC444D,0xD6001E14,0xBE002159,0xA000444E,0x75FC444D,0xD6001E14,0xBE002159,0xA000444E,0xA000444E,0xFF20392D,0xFF2C3FE1,0xF9404005,0xFEEC2C7A,0xFEA41CE9,0xFE380A7D,0xFE0C0050,0xEA0004E2,0xFF08395E,0xFEC82A3E,0xF6001553,0xBE002159,
-0x51FC444D,0x9833B4,0x9833B4,0x9833B4,0x9833B4,0xFE5C12C9,0xFE5C12C9,0xFE5C12C9,0xE0440908,0xE0440908,0xA0440909,0xFE301544,0xFE301544,0xFE301544,0xE8000059,0xE8000059,0xA20C0089,0xAA001142,0xAA001142,0x9000046A,0x72001142,0xE433B3,0xE433B3,0xE433B3,0xC000139A,0xC000139A,0x98000B59,0x98001C26,0x98001C26,0x86000C7A,0x6E001672,0x1D033B3,
-0x1D033B3,0x6C001FE3,0x5C00240E,0x4C0033B3,0xFE7423B8,0xFE8C2C28,0x9833B4,0xFE541675,0xFE2C09CE,0xFE0C0274,0xFE040069,0xCC00015A,0xFE5022C1,0xFE3014B1,0xD60011ED,0x86000C7A,0x14833B3,0xE41144,0xE41144,0xE41144,0xE41144,0xFEA402D5,0xFEA402D5,0xFEA402D5,0xCE880001,0xCE880001,0xA0880001,0x1541142,0x1541142,0x1541142,0xE8000059,0xE8000059,
-0xA02C0001,0x2FFC1142,0x2FFC1142,0x9000046A,0x72001142,0x1541142,0x1541142,0x1541142,0xE8000059,0xE8000059,0xA02C0001,0x2FFC1142,0x2FFC1142,0x9000046A,0x72001142,0x2FFC1142,0x2FFC1142,0x9000046A,0x72001142,0x72001142,0xFEBC0CF9,0xF6DC0E1D,0xE41144,0xFE9809E5,0xFE5C0551,0xFE2001E2,0xFE0C0050,0xCC00015A,0xFAAC0D75,0xFE740975,0x1E81142,0x9000046A,
-0x1E81142,0x1A010E5,0xFF800A68,0xFF58033D,0xFF440000,0x71FC10E5,0xFF200654,0xFEE80000,0xB9FC10E5,0xF800003D,0xD00010E5,0x71FC10E5,0xFF200654,0xFEE80000,0xB9FC10E5,0xF800003D,0xD00010E5,0xB9FC10E5,0xF800003D,0xD00010E5,0xD00010E5,0x71FC10E5,0xFF200654,0xFEE80000,0xB9FC10E5,0xF800003D,0xD00010E5,0xB9FC10E5,0xF800003D,0xD00010E5,0xD00010E5,0xB9FC10E5,
-0xF800003D,0xD00010E5,0xD00010E5,0xD00010E5,0xFD900F79,0x1BC10E5,0xF79C0FD4,0xFF6C0D2A,0xFF280A82,0xFEC00544,0xFE340000,0xF2000190,0xF7880F79,0xFF4C0CE2,0xFE700090,0xD00010E5,0xA7FC10E5,0x440908,0x440908,0x440908,0x440908,0x440908,0x440908,0x440908,0x440908,0x440908,0x440908,0xCE000000,0xCE000000,0xCE000000,0xCE000000,0xCE000000,
-0xCE000000,0x64000000,0x64000000,0x64000000,0x42000001,0x640908,0x640908,0x640908,0x640908,0x640908,0x640908,0x52000369,0x52000369,0x52000369,0x3A0001BA,0xCC0908,0xCC0908,0xCC0908,0x2C000595,0x2000090A,0xFE2C05A5,0x440908,0x440908,0xFE200244,0xFE0C009D,0xFE000000,0xFE000000,0xA6000000,0xFE100482,0xFE000200,0x7E000041,0x52000369,
-0x900908,};
-static const uint32_t g_etc1_to_bc7_m6_table239[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0x980000,0xE00000,0xE00000,0xE00000,0xE00000,0xE00000,
-0xE00000,0x1CC0000,0x1CC0000,0x1CC0000,0x4A000001,0xE00000,0xE00000,0xE00000,0xE00000,0xE00000,0xE00000,0x1CC0000,0x1CC0000,0x1CC0000,0x4A000001,0x1CC0000,0x1CC0000,0x1CC0000,0x4A000001,0x4A000001,0x8A00000,0x980000,0x980000,0xB00000,0x2BC0000,0x2CC0000,0x2CC0000,0x1000000,0xB00000,0x2BC0000,0x1400000,0x1CC0000,
-0x1400000,0x1540000,0x1540000,0x1540000,0x1540000,0x1F80000,0x1F80000,0x1F80000,0x81FC0000,0x81FC0000,0xA8000001,0x1F80000,0x1F80000,0x1F80000,0x81FC0000,0x81FC0000,0xA8000001,0x81FC0000,0x81FC0000,0xA8000001,0xA8000001,0x1F80000,0x1F80000,0x1F80000,0x81FC0000,0x81FC0000,0xA8000001,0x81FC0000,0x81FC0000,0xA8000001,0xA8000001,0x81FC0000,
-0x81FC0000,0xA8000001,0xA8000001,0xA8000001,0x18C0000,0xD680000,0x1540000,0x3CC0000,0x2FFC0000,0x5FFC0000,0x71FC0000,0x8BFC0000,0x3A80000,0x1F80000,0x5FFC0000,0xA8000001,0x5FFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0xFC9059,0xFED0662D,0xFEAC44A9,0xFEA438A8,0xFEB052A9,0xFE7C2732,0xFE6816F9,0xFE581F29,0xFA480BC4,0xD44C1965,0xFE8C60F6,0xFE4C2C1F,0xFE3C1798,0xFE201A39,0xFA000035,0xD4080E36,0xF8003EA2,0xDC001AA8,0xC4001C3D,0xA6003EA2,0x1749057,0xFE20521C,0xFC0038AF,0xFA00374D,0xEE001919,0xCC002067,0xE2005652,0xD2002E3D,0xBA002B7E,0xA20049CB,0x3FF89057,
-0xB2006024,0xA6005459,0x9000690F,0x7C009057,0xFED06FC2,0xFEEC8481,0xFEEC87D8,0xFE984D29,0xFE602AF8,0xFE240D01,0xFE100125,0xF00002D9,0xFEB46DDE,0xFE80487B,0xFE001462,0xBA002B7E,0xBFC9057,0x14C3EA5,0xFF242A35,0xFF081824,0xFEF41144,0xFF0026C9,0xFECC0DAC,0xFEBC0355,0xFEAC0FB9,0xF28C01B4,0xD4980E1D,0x1F03EA2,0xFEA01F7B,0xFE741142,0xFE381881,0xFA000035,
-0xD4100E1E,0x7DF83EA2,0xDC001AA8,0xC4001C3D,0xA6003EA2,0x1F03EA2,0xFEA01F7B,0xFE741142,0xFE381881,0xFA000035,0xD4100E1E,0x7DF83EA2,0xDC001AA8,0xC4001C3D,0xA6003EA2,0x7DF83EA2,0xDC001AA8,0xC4001C3D,0xA6003EA2,0xA6003EA2,0xFF343494,0xFB443A79,0xFD483A9D,0xFEEC292A,0xFEA81AF3,0xFE480A18,0xFE280088,0xF00002D9,0xFF1834C1,0xFEDC273A,0xFE001362,0xC4001C3D,
-0x5BFC3EA2,0xA438A8,0xA438A8,0xA438A8,0xA438A8,0xFE6816F9,0xFE6816F9,0xFE6816F9,0xEA4C0B48,0xEA4C0B48,0xA84C0B49,0xFE3C1798,0xFE3C1798,0xFE3C1798,0xFA000025,0xFA000025,0xAE100102,0xB6001142,0xB6001142,0x960003DA,0x7A001142,0xF438A8,0xF438A8,0xF438A8,0xCC0015DA,0xCC0015DA,0xA2000D3B,0xA2001D8D,0xA2001D8D,0x8C000CF6,0x7400172E,0x1F038A8,
-0x1F038A8,0x720022FB,0x660026FB,0x500038AB,0xFE842831,0xF69C3169,0xA438A8,0xFE5C1A55,0xFE400CA2,0xFE1C03D8,0xFE100125,0xDA0000FA,0xFE64274E,0xFE44188A,0xE6001206,0x8C000CF6,0x15C38A8,0xF41144,0xF41144,0xF41144,0xF41144,0xFEBC0355,0xFEBC0355,0xFEBC0355,0xD6980001,0xD6980001,0xA8980001,0x16C1142,0x16C1142,0x16C1142,0xFA000025,0xFA000025,
-0xA83C0001,0x3BFC1142,0x3BFC1142,0x960003DA,0x7A001142,0x16C1142,0x16C1142,0x16C1142,0xFA000025,0xFA000025,0xA83C0001,0x3BFC1142,0x3BFC1142,0x960003DA,0x7A001142,0x3BFC1142,0x3BFC1142,0x960003DA,0x7A001142,0x7A001142,0xFED80D22,0xFEEC0E1D,0xF41144,0xFEA40A68,0xFE7005D1,0xFE380249,0xFE280088,0xDA0000FA,0xFEB40D9D,0xFE9809D9,0x7FC1142,0x960003DA,
-0x7FC1142,0x1A80E1D,0xFF8C08B4,0xFF6402B1,0xFF540000,0x7DFC0E1D,0xFF380544,0xFF000000,0xBFFC0E1D,0xFE000001,0xD4000E1D,0x7DFC0E1D,0xFF380544,0xFF000000,0xBFFC0E1D,0xFE000001,0xD4000E1D,0xBFFC0E1D,0xFE000001,0xD4000E1D,0xD4000E1D,0x7DFC0E1D,0xFF380544,0xFF000000,0xBFFC0E1D,0xFE000001,0xD4000E1D,0xBFFC0E1D,0xFE000001,0xD4000E1D,0xD4000E1D,0xBFFC0E1D,
-0xFE000001,0xD4000E1D,0xD4000E1D,0xD4000E1D,0xFF940CD5,0x1C40E1D,0xFBA40D24,0xFF6C0AFA,0xFF3C08CA,0xFEC80451,0xFE5C0000,0xF60000B9,0xFB900CD1,0xFF640AD2,0xFE940079,0xD4000E1D,0xAFFC0E1D,0x4C0B48,0x4C0B48,0x4C0B48,0x4C0B48,0x4C0B48,0x4C0B48,0x4C0B48,0x4C0B48,0x4C0B48,0x4C0B48,0xE6000000,0xE6000000,0xE6000000,0xE6000000,0xE6000000,
-0xE6000000,0x70000000,0x70000000,0x70000000,0x4A000001,0x700B48,0x700B48,0x700B48,0x700B48,0x700B48,0x700B48,0x58000449,0x58000449,0x58000449,0x4600022A,0xE40B48,0xE40B48,0xE40B48,0x320006F5,0x24000B4A,0xF63C0784,0x4C0B48,0x4C0B48,0xFE2C039D,0xFE140164,0xFE080029,0xFE080029,0xBA000000,0xFE100652,0xFE000340,0x86000050,0x58000449,
-0xA00B48,};
-static const uint32_t g_etc1_to_bc7_m6_table240[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xA80001,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,
-0xFC0000,0x3F80000,0x3F80000,0x3F80000,0x54000000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0x3F80000,0x3F80000,0x3F80000,0x54000000,0x3F80000,0x3F80000,0x3F80000,0x54000000,0x54000000,0x2B40000,0xA80001,0xA80001,0x2C40000,0xD40000,0xE80000,0xE80000,0x11C0000,0x2C40000,0xD40000,0x1680000,0x3F80000,
-0x1680000,0x1640001,0x1640001,0x1640001,0x1640001,0x19FC0000,0x19FC0000,0x19FC0000,0x8FF80000,0x8FF80000,0xB2000000,0x19FC0000,0x19FC0000,0x19FC0000,0x8FF80000,0x8FF80000,0xB2000000,0x8FF80000,0x8FF80000,0xB2000000,0xB2000000,0x19FC0000,0x19FC0000,0x19FC0000,0x8FF80000,0x8FF80000,0xB2000000,0x8FF80000,0x8FF80000,0xB2000000,0xB2000000,0x8FF80000,
-0x8FF80000,0xB2000000,0xB2000000,0xB2000000,0x1A00000,0x77C0000,0x1640001,0x1E80000,0x45FC0000,0x71FC0000,0x7FFC0000,0x99F40000,0x1C00000,0x19FC0000,0x71FC0000,0xB2000000,0x71FC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1049057,0xFEDC690F,0xFEB849CB,0xFEB03EA2,0xFEB05459,0xFE882B7E,0xFE741C3D,0xFE642067,0xFA540E36,0xD8541965,0xFE986024,0xFE582E3D,0xFE441AA8,0xFE201919,0xFE040035,0xDA080BC4,0xFE0438AF,0xE0001798,0xCA0016F9,0xAC0038A8,0x3809057,0xFE385652,0xFE0C3EA2,0xFE08374D,0xEE001A39,0xD2001F29,0xEE00521C,0xD8002C1F,0xC0002732,0xA80044A9,0x45FC9057,
-0xB80060F6,0xA60052A9,0x9600662D,0x80009059,0xFED870CD,0xFEEC8535,0xF90088B3,0xFE984F45,0xFE682CFD,0xFE2C0EC7,0xFE1C02D9,0xF6000125,0xFEB46F22,0xFE804A3D,0xFE001354,0xC0002732,0x15FC9057,0x15838AB,0xFF3026FB,0xFF14172E,0xFF081142,0xFF1822FB,0xFEE40CF6,0xFED003DA,0xFEB80D3B,0xF6A00102,0xD8A80B49,0x7FC38A8,0xFEB81D8D,0xFE901142,0xFE5815DA,0xFE080025,
-0xD8280B48,0x85FC38A8,0xE0001798,0xCA0016F9,0xAC0038A8,0x7FC38A8,0xFEB81D8D,0xFE901142,0xFE5815DA,0xFE080025,0xD8280B48,0x85FC38A8,0xE0001798,0xCA0016F9,0xAC0038A8,0x85FC38A8,0xE0001798,0xCA0016F9,0xAC0038A8,0xAC0038A8,0xFF342F72,0xFF4C34BB,0xFF4C3533,0xFF082595,0xFEC818C5,0xFE7009A1,0xFE3C00FA,0xF6000125,0xFF243009,0xFEE8241E,0xFE001254,0xCA0016F9,
-0x65FC38A8,0xB03EA2,0xB03EA2,0xB03EA2,0xB03EA2,0xFE741C3D,0xFE741C3D,0xFE741C3D,0xF4540E1E,0xF4540E1E,0xB2540E1D,0xFE441AA8,0xFE441AA8,0xFE441AA8,0xFE040035,0xFE040035,0xB81801B4,0xC4001142,0xC4001142,0xA0000355,0x82001144,0x1043EA2,0x1043EA2,0x1043EA2,0xE2001881,0xE2001881,0xA8000FB9,0xAE001F7B,0xAE001F7B,0x98000DAC,0x7A001824,0x7FC3EA2,
-0x7FC3EA2,0x7E0026C9,0x6C002A35,0x56003EA5,0xFE902DE5,0xFCA83721,0xB03EA2,0xFE701F65,0xFE441079,0xFE24061D,0xFE1C02D9,0xEA000088,0xFE782CA5,0xFE501D0A,0xF6001225,0x98000DAC,0x1743EA2,0x1081142,0x1081142,0x1081142,0x1081142,0xFED003DA,0xFED003DA,0xFED003DA,0xE0A80001,0xE0A80001,0xB2A80001,0x1881142,0x1881142,0x1881142,0xFE080025,0xFE080025,
-0xB24C0001,0x49F81142,0x49F81142,0xA0000355,0x82001144,0x1881142,0x1881142,0x1881142,0xFE080025,0xFE080025,0xB24C0001,0x49F81142,0x49F81142,0xA0000355,0x82001144,0x49F81142,0x49F81142,0xA0000355,0x82001144,0x82001144,0xFAEC0D75,0xF9000E72,0x1081142,0xFEC40ABA,0xFE98065D,0xFE5802F2,0xFE3C00FA,0xEA000088,0xFED00DD0,0xFEA40A40,0x19FC1142,0xA0000355,
-0x19FC1142,0x1B00B4A,0xFF9806F5,0xFF70022A,0xFF640001,0x8DFC0B48,0xFF4C0449,0xFF1C0000,0xC7FC0B48,0xFE2C0000,0xD8000B48,0x8DFC0B48,0xFF4C0449,0xFF1C0000,0xC7FC0B48,0xFE2C0000,0xD8000B48,0xC7FC0B48,0xFE2C0000,0xD8000B48,0xD8000B48,0x8DFC0B48,0xFF4C0449,0xFF1C0000,0xC7FC0B48,0xFE2C0000,0xD8000B48,0xC7FC0B48,0xFE2C0000,0xD8000B48,0xD8000B48,0xC7FC0B48,
-0xFE2C0000,0xD8000B48,0xD8000B48,0xD8000B48,0xFF940A68,0xFCC0B48,0xFFAC0A6D,0xFF8408D1,0xFF500709,0xFEF00382,0xFE880000,0xFA000029,0xFF980A22,0xFF7008B4,0xFEB80064,0xD8000B48,0xB9FC0B48,0x540E1D,0x540E1D,0x540E1D,0x540E1D,0x540E1D,0x540E1D,0x540E1D,0x540E1D,0x540E1D,0x540E1D,0xFE000001,0xFE000001,0xFE000001,0xFE000001,0xFE000001,
-0xFE000001,0x7E000000,0x7E000000,0x7E000000,0x54000000,0x7C0E1D,0x7C0E1D,0x7C0E1D,0x7C0E1D,0x7C0E1D,0x7C0E1D,0x62000544,0x62000544,0x62000544,0x4C0002B1,0xFC0E1D,0xFC0E1D,0xFC0E1D,0x380008B4,0x2A000E1D,0xFC4809D9,0x540E1D,0x540E1D,0xFE2C0568,0xFE200290,0xFE1000B9,0xFE1000B9,0xD0000000,0xFE20088A,0xFE1404E2,0x9E000065,0x62000544,
-0xB00E1D,};
-static const uint32_t g_etc1_to_bc7_m6_table241[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0xB80001,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,
-0x1140000,0xFF80000,0xFF80000,0xFF80000,0x5C000000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0x1140000,0xFF80000,0xFF80000,0xFF80000,0x5C000000,0xFF80000,0xFF80000,0xFF80000,0x5C000000,0x5C000000,0xAC40000,0xB80001,0xB80001,0xD80000,0xE80000,0xFC0000,0xFC0000,0x1380000,0xD80000,0xE80000,0x18C0000,0xFF80000,
-0x18C0000,0x1740001,0x1740001,0x1740001,0x1740001,0x31FC0000,0x31FC0000,0x31FC0000,0x9BF80000,0x9BF80000,0xBA000000,0x31FC0000,0x31FC0000,0x31FC0000,0x9BF80000,0x9BF80000,0xBA000000,0x9BF80000,0x9BF80000,0xBA000000,0xBA000000,0x31FC0000,0x31FC0000,0x31FC0000,0x9BF80000,0x9BF80000,0xBA000000,0x9BF80000,0x9BF80000,0xBA000000,0xBA000000,0x9BF80000,
-0x9BF80000,0xBA000000,0xBA000000,0xBA000000,0x1B40000,0xF8C0000,0x1740001,0x1FC0000,0x59FC0000,0x7FFC0000,0x8DFC0000,0xA3F80000,0x1D40000,0x31FC0000,0x7FFC0000,0xBA000000,0x7FFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x10C90DF,0xFEE86C1B,0xFEC04EF2,0xFEBC444E,0xFEC45607,0xFE942FCA,0xFE802159,0xFE702223,0xFE5C10E6,0xDC5C19ED,0xFEA46018,0xFE6430B1,0xFE501E14,0xFE2C18CD,0xFE1000F9,0xDE100A14,0xFE083418,0xE6001544,0xCA0012C9,0xB20033B4,0x38C90DF,0xFE385A92,0xFE1C444D,0xFE08381D,0xF4001BF1,0xD2001EA9,0xF4004EC8,0xDE002ADB,0xC60023E2,0xAE004085,0x4BFC90DF,
-0xBE006262,0xAC0051A9,0x9C006419,0x840090E1,0xFEE47241,0xFB048637,0xFD08897B,0xFEAC5155,0xFE742F9E,0xFE381111,0xFE2804E2,0xFC000069,0xFED07092,0xFE904C7B,0xFE001374,0xC60023E2,0x1DF890DF,0x16433B3,0xFF44240E,0xFF201672,0xFF181142,0xFF241FE3,0xFEF00C7A,0xFEDC046A,0xFECC0B59,0xF6B40089,0xDCB80909,0x15FC33B3,0xFECC1C26,0xFEA81142,0xFE70139A,0xFE2C0059,
-0xDC3C0908,0x8DFC33B3,0xE6001544,0xCA0012C9,0xB20033B4,0x15FC33B3,0xFECC1C26,0xFEA81142,0xFE70139A,0xFE2C0059,0xDC3C0908,0x8DFC33B3,0xE6001544,0xCA0012C9,0xB20033B4,0x8DFC33B3,0xE6001544,0xCA0012C9,0xB20033B4,0xB20033B4,0xFF3C2BBB,0xF75C3071,0xF96030C6,0xFF142266,0xFEDC1721,0xFE7C0965,0xFE64015A,0xFC000069,0xFF342BED,0xFF042108,0xFE141223,0xCA0012C9,
-0x6FFC33B3,0xBC444E,0xBC444E,0xBC444E,0xBC444E,0xFE802159,0xFE802159,0xFE802159,0xFE5C10E6,0xFE5C10E6,0xBA5C10E5,0xFE501E14,0xFE501E14,0xFE501E14,0xFE1000F9,0xFE1000F9,0xC01C0278,0xD0001142,0xD0001142,0xAC0002D5,0x8A001144,0x114444D,0x114444D,0x114444D,0xE8001B35,0xE8001B35,0xB4001241,0xBA002153,0xBA002153,0xA2000E5A,0x86001904,0xFF8444D,
-0xFF8444D,0x84002A65,0x72002D4D,0x5C00444D,0xFEA03348,0xFEAC3CB9,0xBC444E,0xFE78242D,0xFE541448,0xFE3408B9,0xFE2804E2,0xF8000050,0xFE7831F5,0xFE5021DA,0xFE001274,0xA2000E5A,0x18C444D,0x1181142,0x1181142,0x1181142,0x1181142,0xFEDC046A,0xFEDC046A,0xFEDC046A,0xE8B80001,0xE8B80001,0xBAB80001,0x1A01142,0x1A01142,0x1A01142,0xFE2C0059,0xFE2C0059,
-0xBA5C0001,0x55F81142,0x55F81142,0xAC0002D5,0x8A001144,0x1A01142,0x1A01142,0x1A01142,0xFE2C0059,0xFE2C0059,0xBA5C0001,0x55F81142,0x55F81142,0xAC0002D5,0x8A001144,0x55F81142,0x55F81142,0xAC0002D5,0x8A001144,0x8A001144,0xFEF40D9D,0xFF0C0E7A,0x1181142,0xFEDC0AFD,0xFEAC06D9,0xFE740361,0xFE64015A,0xF8000050,0xF8EC0E1D,0xFEC40AB2,0x27FC1142,0xAC0002D5,
-0x27FC1142,0x1B8090A,0xFFA40595,0xFF8801BA,0xFF740001,0x99FC0908,0xFF580369,0xFF340000,0xCDFC0908,0xFE600000,0xDC000908,0x99FC0908,0xFF580369,0xFF340000,0xCDFC0908,0xFE600000,0xDC000908,0xCDFC0908,0xFE600000,0xDC000908,0xDC000908,0x99FC0908,0xFF580369,0xFF340000,0xCDFC0908,0xFE600000,0xDC000908,0xCDFC0908,0xFE600000,0xDC000908,0xDC000908,0xCDFC0908,
-0xFE600000,0xDC000908,0xDC000908,0xDC000908,0xFBAC0841,0x1D80908,0xFFAC087D,0xFF94070A,0xFF680595,0xFF0402C2,0xFEB00000,0xFE000000,0xFF980832,0xFF8806D1,0xFEDC0051,0xDC000908,0xBFFC0908,0x5C10E5,0x5C10E5,0x5C10E5,0x5C10E5,0x5C10E5,0x5C10E5,0x5C10E5,0x5C10E5,0x5C10E5,0x5C10E5,0xFE0C003D,0xFE0C003D,0xFE0C003D,0xFE0C003D,0xFE0C003D,
-0xFE0C003D,0x8A000000,0x8A000000,0x8A000000,0x5C000000,0x8810E5,0x8810E5,0x8810E5,0x8810E5,0x8810E5,0x8810E5,0x6E000654,0x6E000654,0x6E000654,0x5200033D,0x11410E5,0x11410E5,0x11410E5,0x3E000A68,0x2E0010E5,0xFE4C0C35,0x5C10E5,0x5C10E5,0xFE3C0745,0xFE280401,0xFE180190,0xFE180190,0xE4000000,0xFE200AFA,0xFE1406B2,0xA6000074,0x6E000654,
-0xC010E5,};
-static const uint32_t g_etc1_to_bc7_m6_table242[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0xC80001,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,
-0x12C0000,0x1BF80000,0x1BF80000,0x1BF80000,0x64000000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x12C0000,0x1BF80000,0x1BF80000,0x1BF80000,0x64000000,0x1BF80000,0x1BF80000,0x1BF80000,0x64000000,0x64000000,0xD80000,0xC80001,0xC80001,0x6E80000,0xFC0000,0x3100000,0x3100000,0x1540000,0x6E80000,0xFC0000,0x1AC0000,0x1BF80000,
-0x1AC0000,0x1840001,0x1840001,0x1840001,0x1840001,0x49FC0000,0x49FC0000,0x49FC0000,0xA7F80000,0xA7F80000,0xC2000000,0x49FC0000,0x49FC0000,0x49FC0000,0xA7F80000,0xA7F80000,0xC2000000,0xA7F80000,0xA7F80000,0xC2000000,0xC2000000,0x49FC0000,0x49FC0000,0x49FC0000,0xA7F80000,0xA7F80000,0xC2000000,0xA7F80000,0xA7F80000,0xC2000000,0xC2000000,0xA7F80000,
-0xA7F80000,0xC2000000,0xC2000000,0xC2000000,0x3C40000,0x1A00000,0x1840001,0x1FFC0000,0x6DFC0000,0x8FFC0000,0x9BFC0000,0xADFC0000,0x1E80000,0x49FC0000,0x8FFC0000,0xC2000000,0x8FFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x11491E7,0xFEE86F9B,0xFECC5432,0xFEC44A4E,0xFEC45887,0xFEA0348E,0xFE8C26E5,0xFE7C247F,0xFE64141E,0xE0641AF5,0xFEB060B4,0xFE7033B5,0xFE5C2208,0xFE381939,0xFE14026D,0xE21808E4,0xFE143058,0xEC001378,0xD0000EF9,0xB6002F14,0x39891E7,0xFE4C5F3E,0xFE2C4A4E,0xFE0839ED,0xFA001E61,0xD8001EBD,0xFA004BDC,0xE20029E8,0xCC00210A,0xAE003CA5,0x51FC91E7,
-0xBE006462,0xB2005139,0x9C006279,0x880091E9,0xFEE47431,0xFF0C873F,0xFF0C8ACF,0xFEB45441,0xFE7C3299,0xFE48140A,0xFE3407A9,0xFE040045,0xFED4724F,0xFE984F5B,0xFE001494,0xCC00210A,0x23FC91E7,0x1702F13,0xFF502186,0xFF3815C2,0xFF281142,0xFF301D13,0xFF080C12,0xFEF40502,0xFEE409B1,0xFAC80035,0xE0C80709,0x29FC2F13,0xFEE41AA6,0xFEC01142,0xFE88119A,0xFE4000B9,
-0xE0500708,0x97F82F13,0xEC001378,0xD0000EF9,0xB6002F14,0x29FC2F13,0xFEE41AA6,0xFEC01142,0xFE88119A,0xFE4000B9,0xE0500708,0x97F82F13,0xEC001378,0xD0000EF9,0xB6002F14,0x97F82F13,0xEC001378,0xD0000EF9,0xB6002F14,0xB6002F14,0xFF5027BA,0xFD682BE9,0xFF6C2C5A,0xFF30200A,0xFEE8158A,0xFEA4095B,0xFE7C01D4,0xFE040041,0xFF442838,0xFF041EA8,0xFE341206,0xD0000EF9,
-0x7BFC2F13,0xC44A4E,0xC44A4E,0xC44A4E,0xC44A4E,0xFE8C26E5,0xFE8C26E5,0xFE8C26E5,0xFE64141E,0xFE64141E,0xC26413ED,0xFE5C2208,0xFE5C2208,0xFE5C2208,0xFE14026D,0xFE14026D,0xC8200364,0xDC001142,0xDC001142,0xB2000269,0x92001144,0x3244A4D,0x3244A4D,0x3244A4D,0xF4001E3D,0xF4001E3D,0xBA001509,0xC000234B,0xC000234B,0xA8000F1E,0x8C0019E8,0x17FC4A4D,
-0x17FC4A4D,0x8A002E49,0x78003095,0x62004A4D,0xFEA03908,0xF8C0430A,0xC44A4E,0xFE802964,0xFE5818D5,0xFE3C0BE6,0xFE3407A9,0xFE040045,0xFE9437CD,0xFE5C2742,0xFE001394,0xA8000F1E,0x1A44A4D,0x1281142,0x1281142,0x1281142,0x1281142,0xFEF40502,0xFEF40502,0xFEF40502,0xF0C80001,0xF0C80001,0xC2C80001,0x1B81142,0x1B81142,0x1B81142,0xFE4000B9,0xFE4000B9,
-0xC26C0001,0x61F81142,0x61F81142,0xB2000269,0x92001144,0x1B81142,0x1B81142,0x1B81142,0xFE4000B9,0xFE4000B9,0xC26C0001,0x61F81142,0x61F81142,0xB2000269,0x92001144,0x61F81142,0x61F81142,0xB2000269,0x92001144,0x92001144,0xFF100DC8,0xF9200EC9,0x1281142,0xFEDC0B8D,0xFEC0075D,0xFE7C0414,0xFE7C01D4,0xFE040041,0xFEF80E21,0xFEDC0AFD,0x37FC1142,0xB2000269,
-0x37FC1142,0x1C0070A,0xFFB0045D,0xFF940152,0xFF840001,0xA5FC0708,0xFF7002A1,0xFF4C0000,0xD3FC0708,0xFE900000,0xE0000708,0xA5FC0708,0xFF7002A1,0xFF4C0000,0xD3FC0708,0xFE900000,0xE0000708,0xD3FC0708,0xFE900000,0xE0000708,0xE0000708,0xA5FC0708,0xFF7002A1,0xFF4C0000,0xD3FC0708,0xFE900000,0xE0000708,0xD3FC0708,0xFE900000,0xE0000708,0xE0000708,0xD3FC0708,
-0xFE900000,0xE0000708,0xE0000708,0xE0000708,0xFFB40659,0x1E00708,0xF9C00692,0xFF94057A,0xFF7C045D,0xFF2C0232,0xFED80000,0xFE380000,0xFFAC065D,0xFF940550,0xFEFC0040,0xE0000708,0xC7FC0708,0x6413ED,0x6413ED,0x6413ED,0x6413ED,0x6413ED,0x6413ED,0x6413ED,0x6413ED,0x6413ED,0x6413ED,0xFE0C00CD,0xFE0C00CD,0xFE0C00CD,0xFE0C00CD,0xFE0C00CD,
-0xFE0C00CD,0x96000000,0x96000000,0x96000000,0x64000000,0x9413ED,0x9413ED,0x9413ED,0x9413ED,0x9413ED,0x9413ED,0x7A000784,0x7A000784,0x7A000784,0x580003D9,0x12C13ED,0x12C13ED,0x12C13ED,0x44000C44,0x320013ED,0xFE4C0F05,0x6413ED,0x6413ED,0xFE3C0975,0xFE3405B4,0xFE1802D0,0xFE1802D0,0xF8000000,0xFC380D75,0xFE2008D1,0xB6000089,0x7A000784,
-0xD413ED,};
-static const uint32_t g_etc1_to_bc7_m6_table243[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0xD80001,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,
-0x1440000,0x27F80000,0x27F80000,0x27F80000,0x6C000000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x1440000,0x27F80000,0x27F80000,0x27F80000,0x6C000000,0x27F80000,0x27F80000,0x27F80000,0x6C000000,0x6C000000,0xE80000,0xD80001,0xD80001,0x2FC0000,0x1100000,0x1280000,0x1280000,0x36C0000,0x2FC0000,0x1100000,0x1D00000,0x27F80000,
-0x1D00000,0x1940001,0x1940001,0x1940001,0x1940001,0x63FC0000,0x63FC0000,0x63FC0000,0xB3F80000,0xB3F80000,0xCA000000,0x63FC0000,0x63FC0000,0x63FC0000,0xB3F80000,0xB3F80000,0xCA000000,0xB3F80000,0xB3F80000,0xCA000000,0xCA000000,0x63FC0000,0x63FC0000,0x63FC0000,0xB3F80000,0xB3F80000,0xCA000000,0xB3F80000,0xB3F80000,0xCA000000,0xCA000000,0xB3F80000,
-0xB3F80000,0xCA000000,0xCA000000,0xCA000000,0x1D80000,0x1B00000,0x1940001,0x3DFC0000,0x81FC0000,0x9FF80000,0xA9F80000,0xB9F80000,0x1FC0000,0x63FC0000,0x9FF80000,0xCA000000,0x9FF80000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x11C936F,0xFEF4735F,0xFED859D2,0xFED050A2,0xFED05B93,0xFEA839C2,0xFE982CE1,0xFE88277B,0xFE7017E2,0xE46C1C7D,0xFEB061D4,0xFE7C3749,0xFE682684,0xFE381A89,0xFE200485,0xE6200834,0xFE142D78,0xF2001234,0xD6000B99,0xBC002AC8,0x3A4936F,0xFE646426,0xFE3C50A2,0xFE083CBD,0xFA0021B1,0xDE001F71,0xFA0049BC,0xE80029B8,0xCC001E9A,0xB4003921,0x57FC936F,
-0xC40066F6,0xB8005159,0xA6006174,0x8C009371,0xFEF476C5,0xFF0C88FF,0xFF0C8D0F,0xFEC45747,0xFE883642,0xFE541781,0xFE3C0ADE,0xFE0C00EC,0xFED474DF,0xFE9852EB,0xFE101676,0xCC001E9A,0x2BFC936F,0x1782ACB,0xFF5C1F2E,0xFF401523,0xFF381142,0xFF441A61,0xFF140BC6,0xFF0005AA,0xFEF00849,0xFCD80009,0xE4D80549,0x37FC2AC8,0xFEFC1946,0xFED81142,0xFEA00FDA,0xFE640121,
-0xE4640548,0x9DFC2AC8,0xF2001234,0xD6000B99,0xBC002AC8,0x37FC2AC8,0xFEFC1946,0xFED81142,0xFEA00FDA,0xFE640121,0xE4640548,0x9DFC2AC8,0xF2001234,0xD6000B99,0xBC002AC8,0x9DFC2AC8,0xF2001234,0xD6000B99,0xBC002AC8,0xBC002AC8,0xFF58247D,0xFF6C27E1,0xFF6C289A,0xFF301D7A,0xFEFC143A,0xFEB80925,0xFE900274,0xFE280088,0xFD5824CE,0xFF181C5E,0xFE5811EB,0xD6000B99,
-0x83FC2AC8,0xD050A2,0xD050A2,0xD050A2,0xD050A2,0xFE982CE1,0xFE982CE1,0xFE982CE1,0xFE7017E2,0xFE7017E2,0xCA6C1735,0xFE682684,0xFE682684,0xFE682684,0xFE200485,0xFE200485,0xD2280474,0xE6001144,0xE6001144,0xBE0001F9,0x9A001144,0x13450A2,0x13450A2,0x13450A2,0xFA0021A1,0xFA0021A1,0xC6001821,0xCC002553,0xCC002553,0xAE001012,0x92001AE4,0x1FF850A2,
-0x1FF850A2,0x90003275,0x7E00340D,0x660050A5,0xFEAC3F3D,0xFCC8492A,0xD050A2,0xFE902EFD,0xFE6C1DB1,0xFE3C0FE6,0xFE3C0ADE,0xFE0C00EC,0xFE943DAD,0xFE742C9D,0xFE101595,0xAE001012,0x1B850A2,0x1381142,0x1381142,0x1381142,0x1381142,0xFF0005AA,0xFF0005AA,0xFF0005AA,0xF8D80001,0xF8D80001,0xCAD80001,0x1D01142,0x1D01142,0x1D01142,0xFE640121,0xFE640121,
-0xCA7C0001,0x6DF81142,0x6DF81142,0xBE0001F9,0x9A001144,0x1D01142,0x1D01142,0x1D01142,0xFE640121,0xFE640121,0xCA7C0001,0x6DF81142,0x6DF81142,0xBE0001F9,0x9A001144,0x6DF81142,0x6DF81142,0xBE0001F9,0x9A001144,0x9A001144,0xFF200E1D,0xFF2C0ED5,0x1381142,0xFEF80BD1,0xFED407E9,0xFEA804A0,0xFE900274,0xFE280088,0xFD100E72,0xFEE80B5A,0x45FC1142,0xBE0001F9,
-0x45FC1142,0x1C8054A,0xFFB0034D,0xFFA000FA,0xFF940001,0xB1FC0548,0xFF7C01F9,0xFF640000,0xD9FC0548,0xFEC00000,0xE4000548,0xB1FC0548,0xFF7C01F9,0xFF640000,0xD9FC0548,0xFEC00000,0xE4000548,0xD9FC0548,0xFEC00000,0xE4000548,0xE4000548,0xB1FC0548,0xFF7C01F9,0xFF640000,0xD9FC0548,0xFEC00000,0xE4000548,0xD9FC0548,0xFEC00000,0xE4000548,0xE4000548,0xD9FC0548,
-0xFEC00000,0xE4000548,0xE4000548,0xE4000548,0xFFB404D9,0x1E80548,0xFDC804E2,0xFFB00422,0xFF7C034D,0xFF480195,0xFEFC0000,0xFE740000,0xF5C004E2,0xFFA00401,0xFF200031,0xE4000548,0xCFFC0548,0x6C1735,0x6C1735,0x6C1735,0x6C1735,0x6C1735,0x6C1735,0x6C1735,0x6C1735,0x6C1735,0x6C1735,0xFE1801B1,0xFE1801B1,0xFE1801B1,0xFE1801B1,0xFE1801B1,
-0xFE1801B1,0xA0000001,0xA0000001,0xA0000001,0x6C000000,0xA01735,0xA01735,0xA01735,0xA01735,0xA01735,0xA01735,0x800008C8,0x800008C8,0x800008C8,0x62000464,0x1441735,0x1441735,0x1441735,0x4A000E48,0x36001735,0xF8601200,0x6C1735,0x6C1735,0xFE4C0BE4,0xFE3407B4,0xFE240454,0xFE240454,0xFE040014,0xFE3C1031,0xFC300B48,0xC6000099,0x800008C8,
-0xE41735,};
-static const uint32_t g_etc1_to_bc7_m6_table244[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0xEC0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,
-0x35C0000,0x33FC0000,0x33FC0000,0x33FC0000,0x74000001,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x35C0000,0x33FC0000,0x33FC0000,0x33FC0000,0x74000001,0x33FC0000,0x33FC0000,0x33FC0000,0x74000001,0x74000001,0xFC0000,0xEC0000,0xEC0000,0x5100000,0x1280000,0x1400000,0x1400000,0x18C0000,0x5100000,0x1280000,0x1F40000,0x33FC0000,
-0x1F40000,0x1A80000,0x1A80000,0x1A80000,0x1A80000,0x7DFC0000,0x7DFC0000,0x7DFC0000,0xBFFC0000,0xBFFC0000,0xD2000001,0x7DFC0000,0x7DFC0000,0x7DFC0000,0xBFFC0000,0xBFFC0000,0xD2000001,0xBFFC0000,0xBFFC0000,0xD2000001,0xD2000001,0x7DFC0000,0x7DFC0000,0x7DFC0000,0xBFFC0000,0xBFFC0000,0xD2000001,0xBFFC0000,0xBFFC0000,0xD2000001,0xD2000001,0xBFFC0000,
-0xBFFC0000,0xD2000001,0xD2000001,0xD2000001,0x1EC0000,0x1C40000,0x1A80000,0x5FFC0000,0x97FC0000,0xAFFC0000,0xB7FC0000,0xC5F80000,0x2DFC0000,0x7DFC0000,0xAFFC0000,0xD2000001,0xAFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x12495C1,0xFF00782D,0xFEE4609C,0xFEDC5828,0xFEDC5FA9,0xFEB44028,0xFEA43425,0xFE942B8D,0xFE7C1CD4,0xE8741ED1,0xFEC46399,0xFE8C3BF7,0xFE742C2E,0xFE4C1CB6,0xFE2C07B5,0xEE2407F6,0xFE202B26,0xF800116E,0xDC000859,0xC200265A,0x3B095C1,0xFE706A14,0xFE4C582B,0xFE14410D,0xFC00269A,0xE20020E5,0xFA00488A,0xEE002A26,0xD2001C6A,0xBA0035A3,0x5DFC95C1,
-0xCA006AA4,0xBE00521D,0xA600608A,0x920095C3,0xFF007A21,0xFF0C8C29,0xF9208FF4,0xFED45B79,0xFE903AF9,0xFE5C1BF9,0xFE4C0F71,0xFE140288,0xFEF07883,0xFEB0571E,0xFE141976,0xD2001C6A,0x33FC95C1,0x184265D,0xFF681CC8,0xFF58147D,0xFF481144,0xFF5017C9,0xFF2C0B94,0xFF180668,0xFF08070D,0xFEEC0004,0xE8EC039D,0x49FC265A,0xFF1417D8,0xFEF01144,0xFEB80E36,0xFE8801BD,
-0xE87C039D,0xA7F8265A,0xF800116E,0xDC000859,0xC200265A,0x49FC265A,0xFF1417D8,0xFEF01144,0xFEB80E36,0xFE8801BD,0xE87C039D,0xA7F8265A,0xF800116E,0xDC000859,0xC200265A,0xA7F8265A,0xF800116E,0xDC000859,0xC200265A,0xC200265A,0xFF742111,0xF98023FD,0xFB842485,0xFF401AEA,0xFF1012F4,0xFEC80956,0xFEA8031D,0xFE480112,0xFF5C2106,0xFF401A06,0xFE7C11D2,0xDC000859,
-0x8FFC265A,0xDC5828,0xDC5828,0xDC5828,0xDC5828,0xFEA43425,0xFEA43425,0xFEA43425,0xFE7C1CD4,0xFE7C1CD4,0xD2741B35,0xFE742C2E,0xFE742C2E,0xFE742C2E,0xFE2C07B5,0xFE2C07B5,0xDE2805CA,0xF4001142,0xF4001142,0xCA000195,0xA4001142,0x3445828,0x3445828,0x3445828,0xFA00268D,0xFA00268D,0xCC001BE3,0xD80027C5,0xD80027C5,0xBA00113A,0x9E001C1A,0x27FC5828,
-0x27FC5828,0x96003783,0x84003833,0x6C00582B,0xFEBC4689,0xFECC50B4,0xDC5828,0xFE9835F1,0xFE6C2405,0xFE5414FE,0xFE4C0F71,0xFE140288,0xFEA04502,0xFE7433A5,0xFE141895,0xBA00113A,0x1D45828,0x1481144,0x1481144,0x1481144,0x1481144,0xFF180668,0xFF180668,0xFF180668,0xFEEC0004,0xFEEC0004,0xD2EC0001,0x3E81142,0x3E81142,0x3E81142,0xFE8801BD,0xFE8801BD,
-0xD2900001,0x79FC1142,0x79FC1142,0xCA000195,0xA4001142,0x3E81142,0x3E81142,0x3E81142,0xFE8801BD,0xFE8801BD,0xD2900001,0x79FC1142,0x79FC1142,0xCA000195,0xA4001142,0x79FC1142,0x79FC1142,0xCA000195,0xA4001142,0xA4001142,0xFB340E74,0xFB440F20,0x1481144,0xFF180C35,0xFEF008A2,0xFEB80562,0xFEA8031D,0xFE480112,0xF9280EC9,0xFF040BEA,0x57FC1142,0xCA000195,
-0x57FC1142,0x1D4039D,0xFFC4022D,0xFFAC00AD,0xFFA80000,0xBDFC039D,0xFF940152,0xFF7C0001,0xDFF8039D,0xFEF80000,0xE800039D,0xBDFC039D,0xFF940152,0xFF7C0001,0xDFF8039D,0xFEF80000,0xE800039D,0xDFF8039D,0xFEF80000,0xE800039D,0xE800039D,0xBDFC039D,0xFF940152,0xFF7C0001,0xDFF8039D,0xFEF80000,0xE800039D,0xDFF8039D,0xFEF80000,0xE800039D,0xE800039D,0xDFF8039D,
-0xFEF80000,0xE800039D,0xE800039D,0xE800039D,0xFDCC0349,0x1F0039D,0xFFCC0355,0xFDBC02D4,0xFFA80242,0xFF5C0119,0xFF280000,0xFEB80000,0xF7CC0349,0xFFAC02C5,0xFF50001D,0xE800039D,0xD7FC039D,0x741B34,0x741B34,0x741B34,0x741B34,0x741B34,0x741B34,0x741B34,0x741B34,0x741B34,0x741B34,0xFE240328,0xFE240328,0xFE240328,0xFE240328,0xFE240328,
-0xFE240328,0xAE000000,0xAE000000,0xAE000000,0x74000001,0xB01B32,0xB01B32,0xB01B32,0xB01B32,0xB01B32,0xB01B32,0x8C000A55,0x8C000A55,0x8C000A55,0x6800052D,0x1641B32,0x1641B32,0x1641B32,0x500010BD,0x3A001B32,0xFC681589,0x741B34,0x741B34,0xFE4C0F05,0xFE3C0A68,0xFE340665,0xFE340665,0xFE0C009D,0xFE3C13D0,0xFE340E29,0xD60000B9,0x8C000A55,
-0xF81B32,};
-static const uint32_t g_etc1_to_bc7_m6_table245[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0xFC0000,0x3740000,0x3740000,0x3740000,0x3740000,0x3740000,
-0x3740000,0x3FFC0000,0x3FFC0000,0x3FFC0000,0x7C000001,0x3740000,0x3740000,0x3740000,0x3740000,0x3740000,0x3740000,0x3FFC0000,0x3FFC0000,0x3FFC0000,0x7C000001,0x3FFC0000,0x3FFC0000,0x3FFC0000,0x7C000001,0x7C000001,0x10C0000,0xFC0000,0xFC0000,0x1240000,0x13C0000,0x3540000,0x3540000,0x1A80000,0x1240000,0x13C0000,0xDFC0000,0x3FFC0000,
-0xDFC0000,0x1B80000,0x1B80000,0x1B80000,0x1B80000,0x95FC0000,0x95FC0000,0x95FC0000,0xCBFC0000,0xCBFC0000,0xDA000001,0x95FC0000,0x95FC0000,0x95FC0000,0xCBFC0000,0xCBFC0000,0xDA000001,0xCBFC0000,0xCBFC0000,0xDA000001,0xDA000001,0x95FC0000,0x95FC0000,0x95FC0000,0xCBFC0000,0xCBFC0000,0xDA000001,0xCBFC0000,0xCBFC0000,0xDA000001,0xDA000001,0xCBFC0000,
-0xCBFC0000,0xDA000001,0xDA000001,0xDA000001,0x9FC0000,0x3D40000,0x1B80000,0x7DFC0000,0xABFC0000,0xBFF80000,0xC5FC0000,0xD1F40000,0x55FC0000,0x95FC0000,0xBFF80000,0xDA000001,0xBFF80000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x12C9859,0xFF0C7CE9,0xFEF06704,0xFEE85F34,0xFEE863E1,0xFEC44648,0xFEB03B0D,0xFE942FCD,0xFE8821D8,0xEC7C2169,0xFEC465F9,0xFE9840B3,0xFE8031CA,0xFE581F56,0xFE380B41,0xF22C0846,0xFE2C29FE,0xFE041148,0xE6000602,0xC80022C6,0x3BC9859,0xFE7C6FCC,0xFE5C5F33,0xFE204581,0xFE082BC5,0xE80022E1,0xFE044866,0xEE002B26,0xD8001AEE,0xC00032E7,0x63FC9859,
-0xD0006E98,0xBE00534D,0xAC006016,0x9600985B,0xFF007DA1,0xFB248F01,0xFD2892C4,0xFED45F89,0xFEA03FAE,0xFE6820C1,0xFE501419,0xFE2004B9,0xFEF87BA9,0xFEC45BAD,0xFE201CEC,0xD8001AEE,0x3BFC9859,0x19022C5,0xFF741AD8,0xFF6413E5,0xFF581144,0xFF5C15CD,0xFF380B84,0xFF300728,0xFF14063D,0xFEFC0031,0xECFC0265,0x59FC22C5,0xFF2016B4,0xFF081144,0xFED80D2D,0xFEA0025D,
-0xEC900265,0xADFC22C5,0xFE081142,0xE6000602,0xC80022C6,0x59FC22C5,0xFF2016B4,0xFF081144,0xFED80D2D,0xFEA0025D,0xEC900265,0xADFC22C5,0xFE081142,0xE6000602,0xC80022C6,0xADFC22C5,0xFE081142,0xE6000602,0xC80022C6,0xC80022C6,0xFF781E0E,0xFF8C207D,0xFF8C211D,0xFF5C18D9,0xFF2411F8,0xFEEC0969,0xFED003E8,0xFE64019A,0xFD741E52,0xFF4817E4,0xFEA011BB,0xE6000602,
-0x99FC22C5,0xE85F34,0xE85F34,0xE85F34,0xE85F34,0xFEB03B0D,0xFEB03B0D,0xFEB03B0D,0xFE8821D8,0xFE8821D8,0xDA7C1F05,0xFE8031CA,0xFE8031CA,0xFE8031CA,0xFE380B41,0xFE380B41,0xE62C0726,0xFE041148,0xFE041148,0xD000013D,0xAC001142,0x1545F33,0x1545F33,0x1545F33,0xFE082BC5,0xFE082BC5,0xD8001F8B,0xE20029C6,0xE20029C6,0xC000126A,0xA2001D03,0x2FFC5F33,
-0x2FFC5F33,0x9C003C4B,0x8A003C13,0x72005F33,0xFECC4D68,0xF8E0580D,0xE85F34,0xFEAC3CD5,0xFE8029D5,0xFE5C1A05,0xFE501419,0xFE2004B9,0xFEB44BB9,0xFE903A4A,0xFE201C0B,0xC000126A,0x1E85F33,0x1581144,0x1581144,0x1581144,0x1581144,0xFF300728,0xFF300728,0xFF300728,0xFEFC0031,0xFEFC0031,0xDAFC0001,0x7FC1142,0x7FC1142,0x7FC1142,0xFEA0025D,0xFEA0025D,
-0xDAA00001,0x85FC1142,0x85FC1142,0xD000013D,0xAC001142,0x7FC1142,0x7FC1142,0x7FC1142,0xFEA0025D,0xFEA0025D,0xDAA00001,0x85FC1142,0x85FC1142,0xD000013D,0xAC001142,0x85FC1142,0x85FC1142,0xD000013D,0xAC001142,0xAC001142,0xFF3C0EA4,0xFF4C0F40,0x1581144,0xFF240CB2,0xFF04093A,0xFEE40632,0xFED003E8,0xFE64019A,0xFF340ECD,0xFF180C3D,0x65FC1142,0xD000013D,
-0x65FC1142,0x1DC0265,0xFFD00171,0xFFC00074,0xFFB80000,0xC9FC0265,0xFFAC00DA,0xFF940001,0xE5F80265,0xFF280000,0xEC000265,0xC9FC0265,0xFFAC00DA,0xFF940001,0xE5F80265,0xFF280000,0xEC000265,0xE5F80265,0xFF280000,0xEC000265,0xEC000265,0xC9FC0265,0xFFAC00DA,0xFF940001,0xE5F80265,0xFF280000,0xEC000265,0xE5F80265,0xFF280000,0xEC000265,0xEC000265,0xE5F80265,
-0xFF280000,0xEC000265,0xEC000265,0xEC000265,0xFFD00225,0x1FC0265,0xF5D80244,0xFFC001D4,0xFFA80172,0xFF8400B4,0xFF500000,0xFEF40000,0xFBD40221,0xFFC001C4,0xFF700014,0xEC000265,0xDFF80265,0x7C1F04,0x7C1F04,0x7C1F04,0x7C1F04,0x7C1F04,0x7C1F04,0x7C1F04,0x7C1F04,0x7C1F04,0x7C1F04,0xFE2404C8,0xFE2404C8,0xFE2404C8,0xFE2404C8,0xFE2404C8,
-0xFE2404C8,0xBA000000,0xBA000000,0xBA000000,0x7C000001,0xBC1F02,0xBC1F02,0xBC1F02,0xBC1F02,0xBC1F02,0xBC1F02,0x98000BD5,0x98000BD5,0x98000BD5,0x6E0005F1,0x17C1F02,0x17C1F02,0x17C1F02,0x56001315,0x3E001F02,0xFE6C18FD,0x7C1F04,0x7C1F04,0xFE581220,0xFE500D24,0xFE3C0894,0xFE3C0894,0xFE140164,0xFC541735,0xFE341139,0xE60000CD,0x98000BD5,
-0x10C1F02,};
-static const uint32_t g_etc1_to_bc7_m6_table246[] = {
-0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,
-0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x10C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,
-0x38C0000,0x4BFC0000,0x4BFC0000,0x4BFC0000,0x84000001,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x38C0000,0x4BFC0000,0x4BFC0000,0x4BFC0000,0x84000001,0x4BFC0000,0x4BFC0000,0x4BFC0000,0x84000001,0x84000001,0x71C0000,0x10C0000,0x10C0000,0x1380000,0x1500000,0x16C0000,0x16C0000,0x3C00000,0x1380000,0x1500000,0x1DF80000,0x4BFC0000,
-0x1DF80000,0x1C80000,0x1C80000,0x1C80000,0x1C80000,0xAFFC0000,0xAFFC0000,0xAFFC0000,0xD7FC0000,0xD7FC0000,0xE2000001,0xAFFC0000,0xAFFC0000,0xAFFC0000,0xD7FC0000,0xD7FC0000,0xE2000001,0xD7FC0000,0xD7FC0000,0xE2000001,0xE2000001,0xAFFC0000,0xAFFC0000,0xAFFC0000,0xD7FC0000,0xD7FC0000,0xE2000001,0xD7FC0000,0xD7FC0000,0xE2000001,0xE2000001,0xD7FC0000,
-0xD7FC0000,0xE2000001,0xE2000001,0xE2000001,0x43FC0000,0xBE40000,0x1C80000,0x9BFC0000,0xBDFC0000,0xCDFC0000,0xD3F80000,0xDBF80000,0x7DFC0000,0xAFFC0000,0xCDFC0000,0xE2000001,0xCDFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1349B71,0xFF18821D,0xFEFC6DCC,0xFEF06694,0xFEE868A1,0xFEC84CE6,0xFEC44258,0xFEA03499,0xFE942774,0xF0842481,0xFED0690D,0xFE9845F3,0xFE8C37EE,0xFE6422AE,0xFE400F8D,0xF6340916,0xFE3829B6,0xFE0811D2,0xEA000401,0xCC001F86,0x1C89B71,0xFE8875EC,0xFE706693,0xFE2C4A85,0xFE0831B5,0xEE00257D,0xFE0848EA,0xF4002CA6,0xE20019DE,0xC600308B,0x69FC9B71,
-0xD6007334,0xC40054F9,0xB200601A,0x9A009B73,0xFF0C818D,0xFF2C9219,0xFF2C962C,0xFED46499,0xFEA84503,0xFE7025F5,0xFE5C1968,0xFE2807C2,0xFEF87F79,0xFED06046,0xFE3020B2,0xE20019DE,0x41FC9B71,0x19C1F85,0xFF801918,0xFF701365,0xFF681144,0xFF681419,0xFF4C0B8A,0xFF4407D9,0xFF2C05B5,0xFF140089,0xF10C016D,0x6BFC1F85,0xFF3815A4,0xFF201144,0xFEF00C35,0xFEB8031D,
-0xF0A4016D,0xB7F81F85,0xFE381142,0xEA000401,0xCC001F86,0x6BFC1F85,0xFF3815A4,0xFF201144,0xFEF00C35,0xFEB8031D,0xF0A4016D,0xB7F81F85,0xFE381142,0xEA000401,0xCC001F86,0xB7F81F85,0xFE381142,0xEA000401,0xCC001F86,0xCC001F86,0xFF801BA1,0xFF8C1D9D,0xF5981E64,0xFF5C1729,0xFF401123,0xFEFC0989,0xFEE404A5,0xFE8C025D,0xFF781B86,0xFF5C1652,0xFED011A5,0xEA000401,
-0xA3FC1F85,0xF06694,0xF06694,0xF06694,0xF06694,0xFEC44258,0xFEC44258,0xFEC44258,0xFE942774,0xFE942774,0xE2842315,0xFE8C37EE,0xFE8C37EE,0xFE8C37EE,0xFE400F8D,0xFE400F8D,0xF03408A6,0xFE0811D2,0xFE0811D2,0xDC0000F5,0xB4001142,0x1686693,0x1686693,0x1686693,0xFE0831B5,0xFE0831B5,0xDE002373,0xEE002C26,0xEE002C26,0xCC0013AA,0xA8001E33,0x39F86693,
-0x39F86693,0xA600416D,0x90004023,0x78006693,0xFECC54C8,0xFEEC5F3D,0xF06694,0xFEB443E1,0xFE943075,0xFE681FB0,0xFE5C1968,0xFE2807C2,0xFEB45309,0xFE98413E,0xFE301FEE,0xCC0013AA,0x3FC6693,0x1681144,0x1681144,0x1681144,0x1681144,0xFF4407D9,0xFF4407D9,0xFF4407D9,0xFF140089,0xFF140089,0xE30C0001,0x1FFC1142,0x1FFC1142,0x1FFC1142,0xFEB8031D,0xFEB8031D,
-0xE2B00001,0x91FC1142,0x91FC1142,0xDC0000F5,0xB4001142,0x1FFC1142,0x1FFC1142,0x1FFC1142,0xFEB8031D,0xFEB8031D,0xE2B00001,0x91FC1142,0x91FC1142,0xDC0000F5,0xB4001142,0x91FC1142,0x91FC1142,0xDC0000F5,0xB4001142,0xB4001142,0xFF580EC9,0xFB640F79,0x1681144,0xFF440D22,0xFF1809DA,0xFEF406DA,0xFEE404A5,0xFE8C025D,0xFD4C0F20,0xFF240CC8,0x75FC1142,0xDC0000F5,
-0x75FC1142,0x1E4016D,0xFFDC00DD,0xFFCC0044,0xFFC80000,0xD5FC016D,0xFFB80082,0xFFAC0001,0xEBF8016D,0xFF580000,0xF000016D,0xD5FC016D,0xFFB80082,0xFFAC0001,0xEBF8016D,0xFF580000,0xF000016D,0xEBF8016D,0xFF580000,0xF000016D,0xF000016D,0xD5FC016D,0xFFB80082,0xFFAC0001,0xEBF8016D,0xFF580000,0xF000016D,0xEBF8016D,0xFF580000,0xF000016D,0xF000016D,0xEBF8016D,
-0xFF580000,0xF000016D,0xF000016D,0xF000016D,0xF9E00152,0x27FC016D,0xF9E00154,0xFFD40120,0xFFBC00DA,0xFF98006D,0xFF780000,0xFF300000,0xFFDC0139,0xFFCC010D,0xFF90000A,0xF000016D,0xE5FC016D,0x842314,0x842314,0x842314,0x842314,0x842314,0x842314,0x842314,0x842314,0x842314,0x842314,0xFE3006C4,0xFE3006C4,0xFE3006C4,0xFE3006C4,0xFE3006C4,
-0xFE3006C4,0xC6000000,0xC6000000,0xC6000000,0x84000001,0x2C42312,0x2C42312,0x2C42312,0x2C42312,0x2C42312,0x2C42312,0xA2000D39,0xA2000D39,0xA2000D39,0x7A0006B9,0x1942312,0x1942312,0x1942312,0x5C001595,0x42002312,0xFE6C1CED,0x842314,0x842314,0xFE681589,0xFE501004,0xFE3C0B14,0xFE3C0B14,0xFE1802A1,0xFE581AC1,0xFE3C14B4,0xF60000EA,0xA2000D39,
-0x11C2312,};
-static const uint32_t g_etc1_to_bc7_m6_table247[] = {
-0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x100000,0x200000,
-0x200000,0x200000,0x200000,0x4000001,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0xC0000,0x100000,0x180000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x11C0000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,
-0x3A40000,0x57FC0000,0x57FC0000,0x57FC0000,0x8C000001,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x3A40000,0x57FC0000,0x57FC0000,0x57FC0000,0x8C000001,0x57FC0000,0x57FC0000,0x57FC0000,0x8C000001,0x8C000001,0xF2C0000,0x11C0000,0x11C0000,0x5480000,0x1640000,0x3800000,0x3800000,0x1DC0000,0x5480000,0x1640000,0x2BFC0000,0x57FC0000,
-0x2BFC0000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0xC7FC0000,0xC7FC0000,0xC7FC0000,0xE3FC0000,0xE3FC0000,0xEA000001,0xC7FC0000,0xC7FC0000,0xC7FC0000,0xE3FC0000,0xE3FC0000,0xEA000001,0xE3FC0000,0xE3FC0000,0xEA000001,0xEA000001,0xC7FC0000,0xC7FC0000,0xC7FC0000,0xE3FC0000,0xE3FC0000,0xEA000001,0xE3FC0000,0xE3FC0000,0xEA000001,0xEA000001,0xE3FC0000,
-0xE3FC0000,0xEA000001,0xEA000001,0xEA000001,0x7BFC0000,0x1F80000,0x1D80000,0xB9FC0000,0xD1FC0000,0xDDF80000,0xDFFC0000,0xE5FC0000,0xA3FC0000,0xC7FC0000,0xDDF80000,0xEA000001,0xDDF80000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x14097B9,0xFF248115,0xFF086EE8,0xFF006878,0xFF006825,0xFEDC4F04,0xFED0456C,0xFEAC3621,0xFEA02A0C,0xF49424D5,0xFEDC67C5,0xFEB047DF,0xFE983B2E,0xFE702442,0xFE5812B1,0xFA3C0922,0xFE38290A,0xFE2012C6,0xEE040282,0xD20C1C9A,0x1DC97B9,0xFEA0761C,0xFE846878,0xFE384B75,0xFE1434A9,0xF400251D,0xFE084686,0xFA002B02,0xE20015EA,0xCC002B8F,0x73F897B9,
-0xDC0071AC,0xCA0050F9,0xB8005AEA,0x9E0097BB,0xFF207F85,0xFF2C8F25,0xF73C935D,0xFEF064CD,0xFEB446BE,0xFE7C292B,0xFE681CD5,0xFE400A4D,0xFF107DEB,0xFED0602E,0xFE3C238C,0xE20015EA,0x4DFC97B9,0x1A41C9D,0xFF8C1788,0xFF7C12FD,0xFF781144,0xFF7412AD,0xFF5C0BA2,0xFF500895,0xFF38056D,0xFF2C0121,0xF51C00B5,0x7BFC1C9A,0xFF4C14D3,0xFF381144,0xFF080B7D,0xFED8040D,
-0xF4B800B5,0xBFF81C9A,0xFE6C1142,0xEC000266,0xD2001C9A,0x7BFC1C9A,0xFF4C14D3,0xFF381144,0xFF080B7D,0xFED8040D,0xF4B800B5,0xBFF81C9A,0xFE6C1142,0xEC000266,0xD2001C9A,0xBFF81C9A,0xFE6C1142,0xEC000266,0xD2001C9A,0xD2001C9A,0xFF901929,0xF9A01B05,0xFBA41B98,0xFF781595,0xFF481062,0xFF200A13,0xFEFC0585,0xFEA8031D,0xFF88194D,0xFF6814FA,0xFEE41193,0xEC000266,
-0xADFC1C9A,0x1006878,0x1006878,0x1006878,0x1006878,0xFED0456C,0xFED0456C,0xFED0456C,0xFEA02A0C,0xFEA02A0C,0xEA942421,0xFE983B2E,0xFE983B2E,0xFE983B2E,0xFE5812B1,0xFE5812B1,0xF640090E,0xFE2012C6,0xFE2012C6,0xE20400DA,0xBC0C1142,0x17C6878,0x17C6878,0x17C6878,0xFE1434A9,0xFE1434A9,0xE8002431,0xFA002AF2,0xFA002AF2,0xD20011F2,0xB4001CBB,0x43F86878,
-0x43F86878,0xB2004159,0x9C003F8B,0x7E00687B,0xFEE85775,0xFEEC61A9,0x1006878,0xFEC446F4,0xFE943411,0xFE782328,0xFE681CD5,0xFE400A4D,0xFED055B3,0xFEB04469,0xFE3C22C8,0xD20011F2,0x11FC6878,0x1781144,0x1781144,0x1781144,0x1781144,0xFF500895,0xFF500895,0xFF500895,0xFF2C0121,0xFF2C0121,0xEB1C0001,0x37FC1142,0x37FC1142,0x37FC1142,0xFED8040D,0xFED8040D,
-0xEAC00001,0x9DFC1142,0x9DFC1142,0xE40000C1,0xBC001142,0x37FC1142,0x37FC1142,0x37FC1142,0xFED8040D,0xFED8040D,0xEAC00001,0x9DFC1142,0x9DFC1142,0xE40000C1,0xBC001142,0x9DFC1142,0x9DFC1142,0xE40000C1,0xBC001142,0xBC001142,0xFB6C0F20,0xFF6C0FA1,0x1781144,0xFD580D75,0xFF2C0A82,0xFEFC07D5,0xFEFC0585,0xFEA8031D,0xFF500F68,0xFF480D24,0x83FC1142,0xE40000C1,
-0x83FC1142,0x1EC00B5,0xFFE80071,0xFFD80024,0xFFD80000,0xE3FC00B5,0xFFCC0044,0xFFC40000,0xF1F800B5,0xFF880000,0xF40000B5,0xE3FC00B5,0xFFCC0044,0xFFC40000,0xF1F800B5,0xFF880000,0xF40000B5,0xF1F800B5,0xFF880000,0xF40000B5,0xF40000B5,0xE3FC00B5,0xFFCC0044,0xFFC40000,0xF1F800B5,0xFF880000,0xF40000B5,0xF1F800B5,0xFF880000,0xF40000B5,0xF40000B5,0xF1F800B5,
-0xFF880000,0xF40000B5,0xF40000B5,0xF40000B5,0xFDE800A2,0x67FC00B5,0xFDE800A4,0xFBE40091,0xFFD0006A,0xFFC00034,0xFFA00000,0xFF6C0000,0xFBE800A2,0xFFD80088,0xFFB00005,0xF40000B5,0xEDFC00B5,0x942420,0x942420,0x942420,0x942420,0x942420,0x942420,0x942420,0x942420,0x942420,0x942420,0xFE4407D9,0xFE4407D9,0xFE4407D9,0xFE4407D9,0xFE4407D9,
-0xFE4407D9,0xD00C0000,0xD00C0000,0xD00C0000,0x8C0C0001,0xDC2420,0xDC2420,0xDC2420,0xDC2420,0xDC2420,0xDC2420,0xAE000C69,0xAE000C69,0xAE000C69,0x800005B9,0x1BC2420,0x1BC2420,0x1BC2420,0x66001572,0x48002422,0xFC881E08,0x942420,0x942420,0xFE6816CD,0xFE641154,0xFE4C0C44,0xFE4C0C44,0xFE2C0371,0xFA6C1C20,0xFE5015C5,0xFE000095,0xAE000C69,
-0x1382420,};
-static const uint32_t g_etc1_to_bc7_m6_table248[] = {
-0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x2C0000,0x580000,
-0x580000,0x580000,0x580000,0xE000000,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x1C0001,0x200000,0x200000,0x200000,0x2C0000,0x3C0000,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x12C0001,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,
-0x1C00000,0x65F80000,0x65F80000,0x65F80000,0x96000000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x1C00000,0x65F80000,0x65F80000,0x65F80000,0x96000000,0x65F80000,0x65F80000,0x65F80000,0x96000000,0x96000000,0x9400000,0x12C0001,0x12C0001,0x1600000,0x5780000,0x3980000,0x3980000,0x1FC0000,0x1600000,0x5780000,0x3DF80000,0x65F80000,
-0x3DF80000,0x1E80001,0x1E80001,0x1E80001,0x1E80001,0xE3FC0000,0xE3FC0000,0xE3FC0000,0xF1F80000,0xF1F80000,0xF4000000,0xE3FC0000,0xE3FC0000,0xE3FC0000,0xF1F80000,0xF1F80000,0xF4000000,0xF1F80000,0xF1F80000,0xF4000000,0xF4000000,0xE3FC0000,0xE3FC0000,0xE3FC0000,0xF1F80000,0xF1F80000,0xF4000000,0xF1F80000,0xF1F80000,0xF4000000,0xF4000000,0xF1F80000,
-0xF1F80000,0xF4000000,0xF4000000,0xF4000000,0xBBFC0000,0x67FC0000,0x1E80001,0xDBFC0000,0xE7FC0000,0xEDFC0000,0xEFFC0000,0xF3F40000,0xD1FC0000,0xE3FC0000,0xEDFC0000,0xF4000000,0xEDFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x14C9144,0xFF307DB4,0xFF206E1B,0xFF10687B,0xFF0C65C4,0xFEE84FCF,0xFEDC4763,0xFEC036E6,0xFEB82BFB,0xF8A42456,0xFEF464EC,0xFEC448BB,0xFEB03DB5,0xFE88258F,0xFE7015E6,0xFE500915,0xFE582844,0xFE38142D,0xF4100195,0xD81C19B9,0x1EC9144,0xFEB87431,0xFEA06878,0xFE584B5A,0xFE2C36E6,0xF8042454,0xFE084419,0xFA00296D,0xEE001109,0xD2002588,0x7BFC9144,
-0xE0006E48,0xD0004AD6,0xBE005385,0xA6009144,0xFF207B7A,0xFD488994,0xFD488D3C,0xFF0062DC,0xFECC477A,0xFE982BD6,0xFE902035,0xFE580D46,0xFF1079CE,0xFEDC5F8A,0xFE582697,0xEE001109,0x59FC9144,0x1B019BB,0xFFA415E6,0xFF941283,0xFF8C1142,0xFF8C1155,0xFF740BEA,0xFF680989,0xFF4C0593,0xFF3801FD,0xF92C0035,0x8DFC19B8,0xFF6413E5,0xFF541142,0xFF200AFD,0xFEFC0521,
-0xFACC0034,0xC7FC19B8,0xFEA01142,0xF2000124,0xD80019B8,0x8DFC19B8,0xFF6413E5,0xFF541142,0xFF200AFD,0xFEFC0521,0xFACC0034,0xC7FC19B8,0xFEA01142,0xF2000124,0xD80019B8,0xC7FC19B8,0xFEA01142,0xF2000124,0xD80019B8,0xD80019B8,0xFFA016ED,0xFFAC1835,0xFFAC18E6,0xFF881403,0xFF5C0FD6,0xFF380A61,0xFF2006AD,0xFED00448,0xFF941715,0xFF841392,0xFF101175,0xF2000124,
-0xB9FC19B8,0x110687B,0x110687B,0x110687B,0x110687B,0xFEDC4763,0xFEDC4763,0xFEDC4763,0xFEB82BFB,0xFEB82BFB,0xF4A42422,0xFEB03DB5,0xFEB03DB5,0xFEB03DB5,0xFE7015E6,0xFE7015E6,0xFE500915,0xFE38142D,0xFE38142D,0xEC1800D9,0xC41C1145,0x1986878,0x1986878,0x1986878,0xFE2C36E6,0xFE2C36E6,0xF4082420,0xFA00295D,0xFA00295D,0xE2000EE1,0xC0001A74,0x51F86878,
-0x51F86878,0xB8003F52,0xA6003D85,0x88006878,0xFEF458B2,0xFF0C61E3,0x110687B,0xFED448E2,0xFEB0370B,0xFE9026C5,0xFE902035,0xFE580D46,0xFED85741,0xFEBC46B5,0xFE5825EE,0xE2000EE1,0x21FC6878,0x18C1142,0x18C1142,0x18C1142,0x18C1142,0xFF680989,0xFF680989,0xFF680989,0xFF3801FD,0xFF3801FD,0xF52C0001,0x53FC1142,0x53FC1142,0x53FC1142,0xFEFC0521,0xFEFC0521,
-0xF4D00001,0xABF81142,0xABF81142,0xEC000080,0xC4001144,0x53FC1142,0x53FC1142,0x53FC1142,0xFEFC0521,0xFEFC0521,0xF4D00001,0xABF81142,0xABF81142,0xEC000080,0xC4001144,0xABF81142,0xABF81142,0xEC000080,0xC4001144,0xC4001144,0xFF740F52,0xFD880FD2,0x18C1142,0xFF5C0DE5,0xFF540B50,0xFF2808B1,0xFF2006AD,0xFED00448,0xFD740F79,0xFF5C0D81,0x95FC1142,0xEC000080,
-0x95FC1142,0x1F40032,0xFDF00022,0xFFEC000A,0xFFE80001,0xF1FC0032,0xFFE40011,0xFFE00000,0xF9F80032,0xFFC00000,0xF8000034,0xF1FC0032,0xFFE40011,0xFFE00000,0xF9F80032,0xFFC00000,0xF8000034,0xF9F80032,0xFFC00000,0xF8000034,0xF8000034,0xF1FC0032,0xFFE40011,0xFFE00000,0xF9F80032,0xFFC00000,0xF8000034,0xF9F80032,0xFFC00000,0xF8000034,0xF8000034,0xF9F80032,
-0xFFC00000,0xF8000034,0xF8000034,0xF8000034,0xFDF40029,0xB7FC0032,0xF3F40032,0xFFEC0022,0xFFE80019,0xFFDC000D,0xFFCC0000,0xFFB00000,0xFFF00029,0xFFEC0029,0xFFD40001,0xF8000034,0xF7FC0032,0xA42422,0xA42422,0xA42422,0xA42422,0xA42422,0xA42422,0xA42422,0xA42422,0xA42422,0xA42422,0xFE5008B1,0xFE5008B1,0xFE5008B1,0xFE5008B1,0xFE5008B1,
-0xFE5008B1,0xD8200001,0xD8200001,0xD8200001,0x961C0001,0x2F42420,0x2F42420,0x2F42420,0x2F42420,0x2F42420,0x2F42420,0xBA000AB5,0xBA000AB5,0xBA000AB5,0x8C000425,0x1F42420,0x1F42420,0x1F42420,0x6C001408,0x52002420,0xFE8C1E6A,0xA42422,0xA42422,0xFE84174D,0xFE781212,0xFE5C0D22,0xFE5C0D22,0xFE400431,0xFE741C52,0xFE641699,0xFE1000D0,0xBA000AB5,
-0x1602420,};
-static const uint32_t g_etc1_to_bc7_m6_table249[] = {
-0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x440000,0x880000,
-0x880000,0x880000,0x880000,0x16000000,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x2C0001,0x300000,0x300000,0x300000,0x440000,0x600000,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x13C0001,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,
-0x1D80000,0x71F80000,0x71F80000,0x71F80000,0x9E000000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x1D80000,0x71F80000,0x71F80000,0x71F80000,0x9E000000,0x71F80000,0x71F80000,0x71F80000,0x9E000000,0x9E000000,0x1540000,0x13C0001,0x13C0001,0x3700000,0x58C0000,0x1B00000,0x1B00000,0x13FC0000,0x3700000,0x58C0000,0x4BFC0000,0x71F80000,
-0x4BFC0000,0x1F80001,0x1F80001,0x1F80001,0x1F80001,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xFDF80000,0xFDF80000,0xFC000000,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xFDF80000,0xFDF80000,0xFC000000,0xFDF80000,0xFDF80000,0xFC000000,0xFC000000,0xFBFC0000,0xFBFC0000,0xFBFC0000,0xFDF80000,0xFDF80000,0xFC000000,0xFDF80000,0xFDF80000,0xFC000000,0xFC000000,0xFDF80000,
-0xFDF80000,0xFC000000,0xFC000000,0xFC000000,0xF5FC0000,0xE7FC0000,0x1F80001,0xF9FC0000,0xFBFC0000,0xFDF80000,0xFDF80000,0xFDF80000,0xF7FC0000,0xFBFC0000,0xFDF80000,0xFC000000,0xFDF80000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1588BEC,0xFF447ADF,0xFF2C6D47,0xFF20687B,0xFF186404,0xFF00509F,0xFEF44933,0xFED837A6,0xFECC2E12,0xFCB42426,0xFF0062AC,0xFED049C7,0xFEC43FBB,0xFE942717,0xFE7C18FE,0xFE68098D,0xFE702804,0xFE4C15EB,0xF8240111,0xDE2C1785,0x3FC8BEC,0xFECC72CF,0xFEB86878,0xFE704B2A,0xFE4C3941,0xFC182424,0xFE204349,0xFE082945,0xF4000D79,0xD80020D8,0x85F88BEC,
-0xE6006BE4,0xD60045F6,0xC4004D71,0xAC008BEC,0xFF3C7814,0xFF4C849C,0xFF4C888C,0xFF1861D6,0xFED8483B,0xFEAC2E3E,0xFE902345,0xFE6C0FFB,0xFF3476CA,0xFEF45E5F,0xFE7028DB,0xF4000D79,0x63FC8BEC,0x1BC1783,0xFFB014AE,0xFFA0122B,0xFF9C1142,0xFF98106D,0xFF800C3A,0xFF740A69,0xFF6405EB,0xFF4C030A,0xFD3C0005,0x9BFC1783,0xFF7C132D,0xFF6C1142,0xFF380ACD,0xFF140631,
-0xFEE00004,0xCFF81783,0xFED41142,0xF8000074,0xDE001784,0x9BFC1783,0xFF7C132D,0xFF6C1142,0xFF380ACD,0xFF140631,0xFEE00004,0xCFF81783,0xFED41142,0xF8000074,0xDE001784,0xCFF81783,0xFED41142,0xF8000074,0xDE001784,0xDE001784,0xFFB41556,0xFFAC1685,0xF7BC1703,0xFF9812DD,0xFF700F7A,0xFF480B1E,0xFF2807B2,0xFEE40559,0xFFA41576,0xFF841292,0xFF301168,0xF8000074,
-0xC1FC1783,0x120687B,0x120687B,0x120687B,0x120687B,0xFEF44933,0xFEF44933,0xFEF44933,0xFECC2E12,0xFECC2E12,0xFCB42422,0xFEC43FBB,0xFEC43FBB,0xFEC43FBB,0xFE7C18FE,0xFE7C18FE,0xFE68098D,0xFE4C15EB,0xFE4C15EB,0xF42800D9,0xCC2C1145,0x1B06878,0x1B06878,0x1B06878,0xFE4C3941,0xFE4C3941,0xFC182420,0xFE082945,0xFE082945,0xE8000C8D,0xC6001888,0x5DF46878,
-0x5DF46878,0xC4003D82,0xAC003B8D,0x90006878,0xFF045983,0xF71C62B2,0x120687B,0xFEE84AEA,0xFEC4399B,0xFEAC29BA,0xFE902345,0xFE6C0FFB,0xFEF8582E,0xFED0482D,0xFE70284B,0xE8000C8D,0x31FC6878,0x19C1142,0x19C1142,0x19C1142,0x19C1142,0xFF740A69,0xFF740A69,0xFF740A69,0xFF4C030A,0xFF4C030A,0xFD3C0001,0x6BFC1142,0x6BFC1142,0x6BFC1142,0xFF140631,0xFF140631,
-0xFCE00001,0xB7F81142,0xB7F81142,0xF8000050,0xCC001144,0x6BFC1142,0x6BFC1142,0x6BFC1142,0xFF140631,0xFF140631,0xFCE00001,0xB7F81142,0xB7F81142,0xF8000050,0xCC001144,0xB7F81142,0xB7F81142,0xF8000050,0xCC001144,0xCC001144,0xFF900F79,0xFF8C101A,0x19C1142,0xFF780E45,0xFF5C0C05,0xFF3809A1,0xFF2807B2,0xFEE40559,0xFF780FCD,0xFF680E10,0xA3FC1142,0xF8000050,
-0xA3FC1142,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFF80001,0xFDFC0002,0xFFF80001,0xFFF80000,0xFFF80002,0xFFF00000,0xFC000004,0xFDFC0002,0xFFF80001,0xFFF80000,0xFFF80002,0xFFF00000,0xFC000004,0xFFF80002,0xFFF00000,0xFC000004,0xFC000004,0xFDFC0002,0xFFF80001,0xFFF80000,0xFFF80002,0xFFF00000,0xFC000004,0xFFF80002,0xFFF00000,0xFC000004,0xFC000004,0xFFF80002,
-0xFFF00000,0xFC000004,0xFC000004,0xFC000004,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFF80001,0xFFF40001,0xFFF40000,0xFFEC0000,0xFDFC0002,0xFDFC0002,0xFFF40000,0xFC000004,0xFFF80002,0xB42422,0xB42422,0xB42422,0xB42422,0xB42422,0xB42422,0xB42422,0xB42422,0xB42422,0xB42422,0xFE680989,0xFE680989,0xFE680989,0xFE680989,0xFE680989,
-0xFE680989,0xE0300001,0xE0300001,0xE0300001,0x9E2C0001,0x30C2420,0x30C2420,0x30C2420,0x30C2420,0x30C2420,0x30C2420,0xCC000949,0xCC000949,0xCC000949,0x980002FD,0xBFC2420,0xBFC2420,0xBFC2420,0x780012C8,0x5A002420,0xFEAC1E85,0xB42422,0xB42422,0xFE9017EA,0xFE8C12CA,0xFE780DFA,0xFE780DFA,0xFE5404ED,0xFE901C99,0xFE7816FA,0xFE200140,0xCC000949,
-0x1802420,};
-static const uint32_t g_etc1_to_bc7_m6_table250[] = {
-0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0x5C0000,0xB80000,
-0xB80000,0xB80000,0xB80000,0x1E000000,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x3C0001,0x8400000,0x8400000,0x8400000,0x5C0000,0x800000,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x14C0001,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,
-0x1F00000,0x7DF80000,0x7DF80000,0x7DF80000,0xA6000000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x1F00000,0x7DF80000,0x7DF80000,0x7DF80000,0xA6000000,0x7DF80000,0x7DF80000,0x7DF80000,0xA6000000,0xA6000000,0x1640000,0x14C0001,0x14C0001,0x1840000,0x5A00000,0x3C40000,0x3C40000,0x27FC0000,0x1840000,0x5A00000,0x5BFC0000,0x7DF80000,
-0x5BFC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1608334,0xFF4473EF,0xFF3867CB,0xFF2C6383,0xFF245F04,0xFF0C4D93,0xFF0046EB,0xFEE4366A,0xFED82DC2,0xFEC42422,0xFF0C5CE4,0xFEE8465F,0xFED03D53,0xFEAC2617,0xFE941956,0xFE740A69,0xFE7C2534,0xFE5814AB,0xFA3C009A,0xE03C142D,0x13FC8330,0xFEE46CB7,0xFEC86380,0xFE88483A,0xFE643831,0xFE2C2422,0xFE2C3F39,0xFE082639,0xF4000A2D,0xDE001B24,0x8BFC8330,
-0xEC006584,0xDC003FEA,0xCA004541,0xB0008330,0xFF3C711C,0xFF4C7D04,0xF9608037,0xFF185C82,0xFEEC452B,0xFEBC2D3F,0xFEA82336,0xFE7410B2,0xFF346F66,0xFF00597C,0xFE7C2771,0xF4000A2D,0x6DFC8330,0x1C4142B,0xFFB411F3,0xFFAC0FDB,0xFFA40F22,0xFFA40E41,0xFF8C0ACE,0xFF800955,0xFF700543,0xFF6402EA,0xFF4C0001,0xA9FC142B,0xFF8810A9,0xFF7C0F20,0xFF4C09A2,0xFF2C05A5,
-0xFEF80000,0xD5F8142B,0xFEF00F20,0xFE000010,0xE000142C,0xA9FC142B,0xFF8810A9,0xFF7C0F20,0xFF4C09A2,0xFF2C05A5,0xFEF80000,0xD5F8142B,0xFEF00F20,0xFE000010,0xE000142C,0xD5F8142B,0xFEF00F20,0xFE000010,0xE000142C,0xE000142C,0xFFB41242,0xF9C01343,0xF9C013BB,0xFF98106D,0xFF840D72,0xFF6409D1,0xFF500709,0xFEFC04FD,0xFFB41262,0xFF980FFE,0xFF440F44,0xFE000010,
-0xC9FC142B,0x12C6383,0x12C6383,0x12C6383,0x12C6383,0xFF0046EB,0xFF0046EB,0xFF0046EB,0xFED82DC2,0xFED82DC2,0xFEC42422,0xFED03D53,0xFED03D53,0xFED03D53,0xFE941956,0xFE941956,0xFE740A69,0xFE5814AB,0xFE5814AB,0xF838007E,0xD23C0F21,0x1C06380,0x1C06380,0x1C06380,0xFE643831,0xFE643831,0xFE2C2422,0xFE082639,0xFE082639,0xEE0009C5,0xCC001478,0x65F86380,
-0x65F86380,0xCA003962,0xB2003611,0x96006380,0xFF1055F5,0xFD285DF2,0x12C6383,0xFEF8483A,0xFED437FA,0xFEBC28FE,0xFEA82336,0xFE7410B2,0xFEF8548A,0xFEDC4611,0xFE7C26E1,0xEE0009C5,0x3DF86380,0x1A40F22,0x1A40F22,0x1A40F22,0x1A40F22,0xFF800955,0xFF800955,0xFF800955,0xFF6402EA,0xFF6402EA,0xFF4C0001,0x7BFC0F20,0x7BFC0F20,0x7BFC0F20,0xFF2C05A5,0xFF2C05A5,
-0xFEF80000,0xBFF80F20,0xBFF80F20,0xFC00000D,0xD2000F20,0x7BFC0F20,0x7BFC0F20,0x7BFC0F20,0xFF2C05A5,0xFF2C05A5,0xFEF80000,0xBFF80F20,0xBFF80F20,0xFC00000D,0xD2000F20,0xBFF80F20,0xBFF80F20,0xFC00000D,0xD2000F20,0xD2000F20,0xFF900DB1,0xFBA40E1D,0x1A40F22,0xFF880C92,0xFF700AA5,0xFF5808CA,0xFF500709,0xFEFC04FD,0xFF940DC8,0xFF840C82,0xADFC0F20,0xFC00000D,
-0xADFC0F20,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0xC42422,0xC42422,0xC42422,0xC42422,0xC42422,0xC42422,0xC42422,0xC42422,0xC42422,0xC42422,0xFE740A69,0xFE740A69,0xFE740A69,0xFE740A69,0xFE740A69,
-0xFE740A69,0xE8400001,0xE8400001,0xE8400001,0xA63C0001,0x3242420,0x3242420,0x3242420,0x3242420,0x3242420,0x3242420,0xD80007F9,0xD80007F9,0xD80007F9,0xA20001F4,0x17FC2420,0x17FC2420,0x17FC2420,0x7E0011A4,0x62002420,0xFEAC1EF5,0xC42422,0xC42422,0xFEA01865,0xFE941379,0xFE880EBA,0xFE880EBA,0xFE6C05D2,0xFEA01D14,0xFE9417A4,0xFE3401BA,0xD80007F9,
-0x1A42420,};
-static const uint32_t g_etc1_to_bc7_m6_table251[] = {
-0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0x740000,0xE80000,
-0xE80000,0xE80000,0xE80000,0x26000000,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x4C0001,0x540000,0x540000,0x540000,0x740000,0xA40000,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0x15C0001,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,
-0xDFC0000,0x89F80000,0x89F80000,0x89F80000,0xAE000000,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0xDFC0000,0x89F80000,0x89F80000,0x89F80000,0xAE000000,0x89F80000,0x89F80000,0x89F80000,0xAE000000,0xAE000000,0x3740000,0x15C0001,0x15C0001,0x1980000,0x5B40000,0x1DC0000,0x1DC0000,0x3BFC0000,0x1980000,0x5B40000,0x69FC0000,0x89F80000,
-0x69FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x16879B4,0xFF506BE7,0xFF406114,0xFF385D2B,0xFF305924,0xFF18496F,0xFF0C4373,0xFEF03492,0xFEE42CC6,0xFED42422,0xFF185634,0xFEF441BB,0xFEDC3993,0xFEB8246F,0xFEA018E6,0xFE8C0B51,0xFE9421B4,0xFE701283,0xFC4C003A,0xE44C10AD,0x1FFC79B0,0xFEF0656B,0xFED85D2B,0xFEA0448A,0xFE703629,0xFE442420,0xFE383A6D,0xFE0822E9,0xFA00077D,0xE2001579,0x91FC79B0,
-0xF2005E40,0xE0003A48,0xD0003CE5,0xB40079B0,0xFF4C694B,0xFB647402,0xFD6876DF,0xFF2C56B2,0xFF004133,0xFED42B7A,0xFEBC21F6,0xFE84109D,0xFF3467C6,0xFF1053A2,0xFE94250F,0xFA00077D,0x75FC79B0,0x1C810AB,0xFFBC0EC6,0xFFB40D22,0xFFAC0C82,0xFFA40BD1,0xFF9808EE,0xFF8C07B5,0xFF7C0453,0xFF700262,0xFF5C0001,0xAFFC10AB,0xFF940DC1,0xFF880C80,0xFF5807F2,0xFF3804A9,
-0xFF100000,0xD7FC10AB,0xFF080C80,0xFE140000,0xE40010AC,0xAFFC10AB,0xFF940DC1,0xFF880C80,0xFF5807F2,0xFF3804A9,0xFF100000,0xD7FC10AB,0xFF080C80,0xFE140000,0xE40010AC,0xD7FC10AB,0xFF080C80,0xFE140000,0xE40010AC,0xE40010AC,0xFFBC0F15,0xFBC40FDB,0xFDC81043,0xFFB00D9E,0xFF980B2E,0xFF6C0809,0xFF5005C9,0xFF20040D,0xFFB40F22,0xFF980D4E,0xFF540C99,0xFE140000,
-0xCDFC10AB,0x1385D2B,0x1385D2B,0x1385D2B,0x1385D2B,0xFF0C4373,0xFF0C4373,0xFF0C4373,0xFEE42CC6,0xFEE42CC6,0xFED42422,0xFEDC3993,0xFEDC3993,0xFEDC3993,0xFEA018E6,0xFEA018E6,0xFE8C0B51,0xFE701283,0xFE701283,0xFA480032,0xD64C0C81,0x1D05D2B,0x1D05D2B,0x1D05D2B,0xFE703629,0xFE703629,0xFE442420,0xFE0822E9,0xFE0822E9,0xF4000759,0xD2001024,0x6DF85D2B,
-0x6DF85D2B,0xD00034E6,0xB8002FC1,0x9C005D2C,0xFF205092,0xFF2C5816,0x1385D2B,0xFF004403,0xFEEC354B,0xFEBC276E,0xFEBC21F6,0xFE84109D,0xFF104F65,0xFEF441EE,0xFE942496,0xF4000759,0x45FC5D2B,0x1AC0C82,0x1AC0C82,0x1AC0C82,0x1AC0C82,0xFF8C07B5,0xFF8C07B5,0xFF8C07B5,0xFF700262,0xFF700262,0xFF5C0001,0x87FC0C80,0x87FC0C80,0x87FC0C80,0xFF3804A9,0xFF3804A9,
-0xFF100000,0xC5F80C80,0xC5F80C80,0xFE140000,0xD6000C80,0x87FC0C80,0x87FC0C80,0x87FC0C80,0xFF3804A9,0xFF3804A9,0xFF100000,0xC5F80C80,0xC5F80C80,0xFE140000,0xD6000C80,0xC5F80C80,0xC5F80C80,0xFE140000,0xD6000C80,0xD6000C80,0xFFA00B50,0xFFAC0B95,0x1AC0C82,0xFF980A69,0xFF8408D1,0xFF640721,0xFF5005C9,0xFF20040D,0xFF940B68,0xFF840A52,0xB5FC0C80,0xFE140000,
-0xB5FC0C80,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0xD42422,0xD42422,0xD42422,0xD42422,0xD42422,0xD42422,0xD42422,0xD42422,0xD42422,0xD42422,0xFE8C0B51,0xFE8C0B51,0xFE8C0B51,0xFE8C0B51,0xFE8C0B51,
-0xFE8C0B51,0xF0500001,0xF0500001,0xF0500001,0xAE4C0001,0x33C2420,0x33C2420,0x33C2420,0x33C2420,0x33C2420,0x33C2420,0xE800069D,0xE800069D,0xE800069D,0xA8000124,0x23FC2420,0x23FC2420,0x23FC2420,0x8A001074,0x6A002420,0xFECC1F02,0xD42422,0xD42422,0xFEBC18F5,0xFEA81429,0xFE980F82,0xFE980F82,0xFE8006B2,0xFAB41D8D,0xFEA01829,0xFE50027D,0xE800069D,
-0x1C82420,};
-static const uint32_t g_etc1_to_bc7_m6_table252[] = {
-0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x28C0000,0x1200000,
-0x1200000,0x1200000,0x1200000,0x2E000001,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0x600000,0xA640000,0xA640000,0xA640000,0x28C0000,0xCC0000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x1700000,0x29FC0000,0x29FC0000,0x29FC0000,0x29FC0000,0x29FC0000,
-0x29FC0000,0x97F80000,0x97F80000,0x97F80000,0xB6000001,0x29FC0000,0x29FC0000,0x29FC0000,0x29FC0000,0x29FC0000,0x29FC0000,0x97F80000,0x97F80000,0x97F80000,0xB6000001,0x97F80000,0x97F80000,0x97F80000,0xB6000001,0xB6000001,0x1880000,0x1700000,0x1700000,0x1AC0000,0x3CC0000,0x1F40000,0x1F40000,0x51FC0000,0x1AC0000,0x3CC0000,0x7BFC0000,0x97F80000,
-0x7BFC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1746F9A,0xFF5C636D,0xFF4C59E2,0xFF445671,0xFF4452B0,0xFF244509,0xFF183FC9,0xFF0832A0,0xFEFC2BCC,0xFEE82420,0xFF244F2A,0xFF003CE1,0xFEF43599,0xFECC22EC,0xFEB8187A,0xFEA40C6D,0xFEA01E26,0xFE88107D,0xFE5C0008,0xE6600D21,0x2BFC6F9A,0xFEFC5DB5,0xFEE85671,0xFEAC40A4,0xFE8833FB,0xFE602420,0xFE5835B7,0xFE142035,0xFA000585,0xE2000FFD,0x97FC6F9A,
-0xF80056D6,0xE6003482,0xD0003409,0xB8006F9A,0xFF5860F6,0xFF6C6A48,0xFF6C6D09,0xFF2C503A,0xFF0C3CF6,0xFEDC2926,0xFECC20F9,0xFEA01085,0xFF505FB2,0xFF184DB4,0xFEB0221D,0xFA000585,0x7DF86F9A,0x1D00D22,0xFFC40B96,0xFFB80A52,0xFFB809D9,0xFFB00948,0xFFA40709,0xFF980614,0xFF880362,0xFF7C01DD,0xFF700000,0xB7FC0D21,0xFFA00AD2,0xFF9409D9,0xFF700633,0xFF5803BA,
-0xFF2C0000,0xDDF40D21,0xFF2009D9,0xFE4C0000,0xE6000D21,0xB7FC0D21,0xFFA00AD2,0xFF9409D9,0xFF700633,0xFF5803BA,0xFF2C0000,0xDDF40D21,0xFF2009D9,0xFE4C0000,0xE6000D21,0xDDF40D21,0xFF2009D9,0xFE4C0000,0xE6000D21,0xE6000D21,0xFFBC0BF4,0xFFCC0C66,0xFFCC0CC6,0xFFB40AAE,0xFF9808C1,0xFF7C063E,0xFF680484,0xFF380334,0xFFC40C0E,0xFFA40A8D,0xFF6409F2,0xFE4C0000,
-0xD3FC0D21,0x1445671,0x1445671,0x1445671,0x1445671,0xFF183FC9,0xFF183FC9,0xFF183FC9,0xFEFC2BCC,0xFEFC2BCC,0xFEE82420,0xFEF43599,0xFEF43599,0xFEF43599,0xFEB8187A,0xFEB8187A,0xFEA40C6D,0xFE88107D,0xFE88107D,0xFC600008,0xDA6009D9,0x1E05671,0x1E05671,0x1E05671,0xFE8833FB,0xFE8833FB,0xFE602420,0xFE142035,0xFE142035,0xFA000575,0xD8000BF6,0x75FC5671,
-0x75FC5671,0xD6003080,0xBE002931,0xA2005672,0xFF2C4B21,0xF9405231,0x1445671,0xFF103F92,0xFEEC3269,0xFEDC25DD,0xFECC20F9,0xFEA01085,0xFF2049F1,0xFF003DFD,0xFEB021B9,0xFA000575,0x51FC5671,0x1B809D9,0x1B809D9,0x1B809D9,0x1B809D9,0xFF980614,0xFF980614,0xFF980614,0xFF7C01DD,0xFF7C01DD,0xFF700000,0x93FC09D9,0x93FC09D9,0x93FC09D9,0xFF5803BA,0xFF5803BA,
-0xFF2C0000,0xCBF809D9,0xCBF809D9,0xFE4C0000,0xDA0009D9,0x93FC09D9,0x93FC09D9,0x93FC09D9,0xFF5803BA,0xFF5803BA,0xFF2C0000,0xCBF809D9,0xCBF809D9,0xFE4C0000,0xDA0009D9,0xCBF809D9,0xCBF809D9,0xFE4C0000,0xDA0009D9,0xDA0009D9,0xF9B00908,0xFFAC0928,0x1B809D9,0xFF980832,0xFF8406F4,0xFF740590,0xFF680484,0xFF380334,0xFFA80908,0xFF980808,0xBDF809D9,0xFE4C0000,
-0xBDF809D9,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0xE82420,0xE82420,0xE82420,0xE82420,0xE82420,0xE82420,0xE82420,0xE82420,0xE82420,0xE82420,0xFEA40C6D,0xFEA40C6D,0xFEA40C6D,0xFEA40C6D,0xFEA40C6D,
-0xFEA40C6D,0xFA600000,0xFA600000,0xFA600000,0xB6600001,0x1582420,0x1582420,0x1582420,0x1582420,0x1582420,0x1582420,0xFA000565,0xFA000565,0xFA000565,0xB4000082,0x31F82420,0x31F82420,0x31F82420,0x96000F3A,0x72002422,0xF8E01F81,0xE82420,0xE82420,0xFECC1974,0xFEB414F4,0xFEAC109D,0xFEAC109D,0xFE9407B4,0xFEBC1DC9,0xFEB418A0,0xFE60034D,0xFA000565,
-0x1EC2420,};
-static const uint32_t g_etc1_to_bc7_m6_table253[] = {
-0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x2A40000,0x1500000,
-0x1500000,0x1500000,0x1500000,0x36000001,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x700000,0x780000,0x780000,0x780000,0x2A40000,0xEC0000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x1800000,0x41FC0000,0x41FC0000,0x41FC0000,0x41FC0000,0x41FC0000,
-0x41FC0000,0xA1FC0000,0xA1FC0000,0xA1FC0000,0xBE000001,0x41FC0000,0x41FC0000,0x41FC0000,0x41FC0000,0x41FC0000,0x41FC0000,0xA1FC0000,0xA1FC0000,0xA1FC0000,0xBE000001,0xA1FC0000,0xA1FC0000,0xA1FC0000,0xBE000001,0xBE000001,0x5980000,0x1800000,0x1800000,0x7BC0000,0x3E00000,0x13FC0000,0x13FC0000,0x65FC0000,0x7BC0000,0x3E00000,0x89FC0000,0xA1FC0000,
-0x89FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x17C672A,0xFF685C5D,0xFF5853E2,0xFF5050D1,0xFF444D70,0xFF30415D,0xFF243CB9,0xFF1430F0,0xFF082AE0,0xFEF82420,0xFF304956,0xFF0C38E9,0xFF00325D,0xFED821A0,0xFECC1848,0xFEB00D61,0xFEAC1B66,0xFE940EED,0xFE700004,0xE8700A59,0x37FC672A,0xFF145745,0xFEFC50D1,0xFEB83D84,0xFEA03223,0xFE782420,0xFE703187,0xFE2C1E1D,0xFC0004C5,0xE8000BE9,0x9DFC672A,
-0xFC0050E5,0xE6003022,0xD6002CD1,0xBC00672A,0xFF645A02,0xFF6C6288,0xF578652A,0xFF444AE6,0xFF143961,0xFEF0276A,0xFEDC2036,0xFEB010A0,0xFF5058A2,0xFF304877,0xFEB41FE1,0xFC0004C5,0x83FC672A,0x1D40A56,0xFFC8092D,0xFFC00825,0xFFC007C1,0xFFBC074C,0xFFB0058D,0xFFA404C8,0xFF9402A6,0xFF880179,0xFF800000,0xC1FC0A56,0xFFAC0882,0xFFA007C1,0xFF7C04DB,0xFF6402EA,
-0xFF400001,0xE1F80A56,0xFF3807C1,0xFE7C0000,0xE8000A59,0xC1FC0A56,0xFFAC0882,0xFFA007C1,0xFF7C04DB,0xFF6402EA,0xFF400001,0xE1F80A56,0xFF3807C1,0xFE7C0000,0xE8000A59,0xE1F80A56,0xFF3807C1,0xFE7C0000,0xE8000A59,0xE8000A59,0xFDCC0965,0xFFCC09C6,0xFFCC0A26,0xFFC00865,0xFFAC06E5,0xFF7C050E,0xFF7C0385,0xFF50028A,0xFFC4096E,0xFFB0085D,0xFF7407D1,0xFE7C0000,
-0xD9FC0A56,0x15050D1,0x15050D1,0x15050D1,0x15050D1,0xFF243CB9,0xFF243CB9,0xFF243CB9,0xFF082AE0,0xFF082AE0,0xFEF82420,0xFF00325D,0xFF00325D,0xFF00325D,0xFECC1848,0xFECC1848,0xFEB00D61,0xFE940EED,0xFE940EED,0xFE700004,0xDE7007C1,0x1F450D1,0x1F450D1,0x1F450D1,0xFEA03223,0xFEA03223,0xFE782420,0xFE2C1E1D,0xFE2C1E1D,0xFC0004C1,0xDE0008E2,0x7FF850D1,
-0x7FF850D1,0xDC002D24,0xC40023CD,0xA60050D2,0xFF3C469D,0xFF4C4CD1,0x15050D1,0xFF183C30,0xFF002FDD,0xFEE82482,0xFEDC2036,0xFEB010A0,0xFF344580,0xFF103A91,0xFEB41F7D,0xFC0004C1,0x5DF850D1,0x1C007C1,0x1C007C1,0x1C007C1,0x1C007C1,0xFFA404C8,0xFFA404C8,0xFFA404C8,0xFF880179,0xFF880179,0xFF800000,0x9FFC07C1,0x9FFC07C1,0x9FFC07C1,0xFF6402EA,0xFF6402EA,
-0xFF400001,0xD1F807C1,0xD1F807C1,0xFE7C0000,0xDE0007C1,0x9FFC07C1,0x9FFC07C1,0x9FFC07C1,0xFF6402EA,0xFF6402EA,0xFF400001,0xD1F807C1,0xD1F807C1,0xFE7C0000,0xDE0007C1,0xD1F807C1,0xD1F807C1,0xFE7C0000,0xDE0007C1,0xDE0007C1,0xFDB80708,0xF7BC0745,0x1C007C1,0xFFA40681,0xFF980568,0xFF7C0465,0xFF7C0385,0xFF50028A,0xFDB0070A,0xFFA4065D,0xC3FC07C1,0xFE7C0000,
-0xC3FC07C1,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0xF82420,0xF82420,0xF82420,0xF82420,0xF82420,0xF82420,0xF82420,0xF82420,0xF82420,0xF82420,0xFEB00D61,0xFEB00D61,0xFEB00D61,0xFEB00D61,0xFEB00D61,
-0xFEB00D61,0xFE700004,0xFE700004,0xFE700004,0xBE700001,0x1702420,0x1702420,0x1702420,0x1702420,0x1702420,0x1702420,0xFA0004B5,0xFA0004B5,0xFA0004B5,0xBC00002D,0x3DF82420,0x3DF82420,0x3DF82420,0x9C000E2A,0x7A002422,0xFEEC1F85,0xF82420,0xF82420,0xFED81A11,0xFED015B1,0xFEC41174,0xFEC41174,0xFE9C08C8,0xFED81E0A,0xFED01962,0xFE74040D,0xFA0004B5,
-0x9FC2420,};
-static const uint32_t g_etc1_to_bc7_m6_table254[] = {
-0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x2BC0000,0x1800000,
-0x1800000,0x1800000,0x1800000,0x3E000001,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x800000,0x880000,0x880000,0x880000,0x2BC0000,0x1100000,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,0x1900000,0x59FC0000,0x59FC0000,0x59FC0000,0x59FC0000,0x59FC0000,
-0x59FC0000,0xADFC0000,0xADFC0000,0xADFC0000,0xC6000001,0x59FC0000,0x59FC0000,0x59FC0000,0x59FC0000,0x59FC0000,0x59FC0000,0xADFC0000,0xADFC0000,0xADFC0000,0xC6000001,0xADFC0000,0xADFC0000,0xADFC0000,0xC6000001,0xC6000001,0xDA80000,0x1900000,0x1900000,0x1D00000,0x3F40000,0x31FC0000,0x31FC0000,0x79FC0000,0x1D00000,0x3F40000,0x99FC0000,0xADFC0000,
-0x99FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x1845F3A,0xFF7455C5,0xFF644E42,0xFF584B89,0xFF504888,0xFF3C3DE9,0xFF3039D9,0xFF202F60,0xFF142A0C,0xFF082420,0xFF4443BD,0xFF183541,0xFF0C2F69,0xFEF02070,0xFED81820,0xFEC40E48,0xFEB81906,0xFEA00DB5,0xFE880034,0xEC8007E1,0x43FC5F3A,0xFF205129,0xFF084B89,0xFED83AA0,0xFEB8306B,0xFE902420,0xFE882DB7,0xFE381C71,0xFE0804BD,0xEA000892,0xA3FC5F3A,
-0xFE084B86,0xEC002C5A,0xDC002651,0xC0005F3A,0xFF645372,0xF9805B72,0xF9805D5A,0xFF4445D6,0xFF20362E,0xFEFC25F8,0xFEE81F71,0xFEC010D5,0xFF58526E,0xFF3043C7,0xFEBC1E2D,0xFE0804BD,0x8BFC5F3A,0x1D807E2,0xFFD006F2,0xFFCC0635,0xFFC805E9,0xFFC40576,0xFFBC0441,0xFFB003A4,0xFFA00202,0xFFA00121,0xFF900000,0xC9FC07E1,0xFFB8067A,0xFFAC05E9,0xFF9403AB,0xFF7C0232,
-0xFF580001,0xE5F807E1,0xFF5405E9,0xFEAC0000,0xEC0007E1,0xC9FC07E1,0xFFB8067A,0xFFAC05E9,0xFF9403AB,0xFF7C0232,0xFF580001,0xE5F807E1,0xFF5405E9,0xFEAC0000,0xEC0007E1,0xE5F807E1,0xFF5405E9,0xFEAC0000,0xEC0007E1,0xEC0007E1,0xFFD00715,0xF5D80798,0xF5D807BD,0xFFC4065E,0xFFAC0545,0xFFA003D8,0xFF8C02BA,0xFF6401E1,0xFFD0072E,0xFFC0063D,0xFF9005F6,0xFEAC0000,
-0xDFF807E1,0x1584B89,0x1584B89,0x1584B89,0x1584B89,0xFF3039D9,0xFF3039D9,0xFF3039D9,0xFF142A0C,0xFF142A0C,0xFF082420,0xFF0C2F69,0xFF0C2F69,0xFF0C2F69,0xFED81820,0xFED81820,0xFEC40E48,0xFEA00DB5,0xFEA00DB5,0xFE880034,0xE28005E9,0x7FC4B86,0x7FC4B86,0x7FC4B86,0xFEB8306B,0xFEB8306B,0xFE902420,0xFE381C71,0xFE381C71,0xFE0804BD,0xE200064D,0x85FC4B86,
-0x85FC4B86,0xE0002A76,0xCA001ED9,0xAC004B86,0xFF4C4244,0xFF4C4811,0x1584B89,0xFF2C38D6,0xFF142DA1,0xFEF8232A,0xFEE81F71,0xFEC010D5,0xFF344100,0xFF18376B,0xFEBC1DC9,0xFE0804BD,0x65FC4B86,0x1C805E9,0x1C805E9,0x1C805E9,0x1C805E9,0xFFB003A4,0xFFB003A4,0xFFB003A4,0xFFA00121,0xFFA00121,0xFF900000,0xABFC05E9,0xABFC05E9,0xABFC05E9,0xFF7C0232,0xFF7C0232,
-0xFF580001,0xD7F805E9,0xD7F805E9,0xFEAC0000,0xE20005E9,0xABFC05E9,0xABFC05E9,0xABFC05E9,0xFF7C0232,0xFF7C0232,0xFF580001,0xD7F805E9,0xD7F805E9,0xFEAC0000,0xE20005E9,0xD7F805E9,0xD7F805E9,0xFEAC0000,0xE20005E9,0xE20005E9,0xFFBC0550,0xFBC4057D,0x1C805E9,0xFFB404EA,0xFFAC0424,0xFF940371,0xFF8C02BA,0xFF6401E1,0xFFB4055A,0xFFB004E4,0xCBFC05E9,0xFEAC0000,
-0xCBFC05E9,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1082420,0x1082420,0x1082420,0x1082420,0x1082420,0x1082420,0x1082420,0x1082420,0x1082420,0x1082420,0xFEC40E48,0xFEC40E48,0xFEC40E48,0xFEC40E48,0xFEC40E48,
-0xFEC40E48,0xFE880034,0xFE880034,0xFE880034,0xC6800001,0x1882420,0x1882420,0x1882420,0x1882420,0x1882420,0x1882420,0xFE0804BD,0xFE0804BD,0xFE0804BD,0xC6000002,0x49F82420,0x49F82420,0x49F82420,0xA6000D41,0x82002422,0xF9002000,0x1082420,0x1082420,0xFEE81A90,0xFEE41675,0xFED41248,0xFED41248,0xFEAC09CD,0xFAEC1E85,0xFED019E2,0xFE90052A,0xFE0804BD,
-0x19FC2420,};
-static const uint32_t g_etc1_to_bc7_m6_table255[] = {
-0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0xD40000,0x1B00000,
-0x1B00000,0x1B00000,0x1B00000,0x46000001,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x900000,0x4980000,0x4980000,0x4980000,0xD40000,0x1300000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x1A00000,0x71FC0000,0x71FC0000,0x71FC0000,0x71FC0000,0x71FC0000,
-0x71FC0000,0xB9FC0000,0xB9FC0000,0xB9FC0000,0xCE000001,0x71FC0000,0x71FC0000,0x71FC0000,0x71FC0000,0x71FC0000,0x71FC0000,0xB9FC0000,0xB9FC0000,0xB9FC0000,0xCE000001,0xB9FC0000,0xB9FC0000,0xB9FC0000,0xCE000001,0xCE000001,0x1BC0000,0x1A00000,0x1A00000,0x1E40000,0x1BFC0000,0x4FFC0000,0x4FFC0000,0x8DFC0000,0x1E40000,0x1BFC0000,0xA7FC0000,0xB9FC0000,
-0xA7FC0000,0x1FC0001,0x1FC0001,0x1FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFBFC0001,0xF7FC0001,0x1FC0001,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0x1FC0001,0xFDFC0001,0xFFFC0000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,
-0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xFFFC0000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0001,0xF7FC0001,0xF7FC0001,0xFDFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0001,0xFDFC0001,0xFFF00000,0xFE000000,
-0xFFFC0000,0x18C57CA,0xFF744F85,0xFF6C48F9,0xFF644691,0xFF5C43F0,0xFF443AAD,0xFF4436EC,0xFF2C2DF0,0xFF202950,0xFF182420,0xFF443E8D,0xFF2431E9,0xFF182CBD,0xFEFC1F6C,0xFEEC1816,0xFED00F64,0xFED81711,0xFEB80CAD,0xFE940094,0xEE9005C1,0x4FFC57CA,0xFF2C4B75,0xFF184691,0xFEF037C0,0xFECC2F04,0xFEA82420,0xFEA02A47,0xFE641B02,0xFE140585,0xEE0005E5,0xA9FC57CA,
-0xFE284691,0xF2002962,0xDC002041,0xC40057CA,0xFF744D72,0xFD885442,0xFD88560A,0xFF5440F0,0xFF343326,0xFF1024C0,0xFEF81EEA,0xFED81141,0xFF704C95,0xFF503F25,0xFED81CB7,0xFE140585,0x93FC57CA,0x1E005C2,0xFFDC051E,0xFFD4048E,0xFFD00451,0xFFD00402,0xFFC40311,0xFFBC02A8,0xFFAC0176,0xFFAC00CD,0xFFA00000,0xCFFC05C1,0xFFC004C1,0xFFB80451,0xFFA002A3,0xFF88019A,
-0xFF700001,0xE7FC05C1,0xFF6C0451,0xFEE00000,0xEE0005C1,0xCFFC05C1,0xFFC004C1,0xFFB80451,0xFFA002A3,0xFF88019A,0xFF700001,0xE7FC05C1,0xFF6C0451,0xFEE00000,0xEE0005C1,0xE7FC05C1,0xFF6C0451,0xFEE00000,0xEE0005C1,0xEE0005C1,0xFFD8052A,0xF7DC0584,0xF7DC05A5,0xFFD404BA,0xFFC003D1,0xFFA802C2,0xFFA001F9,0xFF7C0161,0xFFD0053E,0xFFC80479,0xFF98045A,0xFEE00000,
-0xE1FC05C1,0x1644691,0x1644691,0x1644691,0x1644691,0xFF4436EC,0xFF4436EC,0xFF4436EC,0xFF202950,0xFF202950,0xFF182420,0xFF182CBD,0xFF182CBD,0xFF182CBD,0xFEEC1816,0xFEEC1816,0xFED00F64,0xFEB80CAD,0xFEB80CAD,0xFE940094,0xE6900451,0x15FC4691,0x15FC4691,0x15FC4691,0xFECC2F04,0xFECC2F04,0xFEA82420,0xFE641B02,0xFE641B02,0xFE140585,0xE6000461,0x8DFC4691,
-0x8DFC4691,0xE6002822,0xD0001A55,0xB2004692,0xFF4C3E24,0xF96043A4,0x1644691,0xFF3C35A5,0xFF202BD5,0xFF08226D,0xFEF81EEA,0xFED81141,0xFF3C3D49,0xFF303446,0xFED81C66,0xFE140585,0x6FFC4691,0x1D00451,0x1D00451,0x1D00451,0x1D00451,0xFFBC02A8,0xFFBC02A8,0xFFBC02A8,0xFFAC00CD,0xFFAC00CD,0xFFA00000,0xB7FC0451,0xB7FC0451,0xB7FC0451,0xFF88019A,0xFF88019A,
-0xFF700001,0xDDF40451,0xDDF40451,0xFEE00000,0xE6000451,0xB7FC0451,0xB7FC0451,0xB7FC0451,0xFF88019A,0xFF88019A,0xFF700001,0xDDF40451,0xDDF40451,0xFEE00000,0xE6000451,0xDDF40451,0xDDF40451,0xFEE00000,0xE6000451,0xE6000451,0xF9CC03F5,0xFFCC03F5,0x1D00451,0xFFC4039D,0xFFAC0304,0xFFA80271,0xFFA001F9,0xFF7C0161,0xFBC803F5,0xFBC0039D,0xD3FC0451,0xFEE00000,
-0xD3FC0451,0x1FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFDFC0002,0xFFFC0001,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFE000000,0xFFFC0000,0xFFFC0000,0xFE000000,0xFE000000,0xFFFC0000,
-0xFFFC0000,0xFE000000,0xFE000000,0xFE000000,0xFDFC0002,0xF7FC0002,0xF7FC0002,0xFDFC0002,0xFFFC0001,0xFFFC0000,0xFFFC0000,0xFFFC0000,0xFDFC0002,0xFDFC0002,0xFFFC0000,0xFE000000,0xFFFC0000,0x1182420,0x1182420,0x1182420,0x1182420,0x1182420,0x1182420,0x1182420,0x1182420,0x1182420,0x1182420,0xFED00F64,0xFED00F64,0xFED00F64,0xFED00F64,0xFED00F64,
-0xFED00F64,0xFE940094,0xFE940094,0xFE940094,0xCE900001,0x1A02420,0x1A02420,0x1A02420,0x1A02420,0x1A02420,0x1A02420,0xFE140585,0xFE140585,0xFE140585,0xCE0C0001,0x55F82420,0x55F82420,0x55F82420,0xB2000C49,0x8A002422,0xFF0C2008,0x1182420,0x1182420,0xFF041B34,0xFEF81741,0xFEDC133D,0xFEDC133D,0xFEC00AE1,0xFEF41EAD,0xFEE41AAA,0xFE9C0631,0xFE140585,
-0x27FC2420,};
-const uint32_t *g_etc1_to_bc7_m6_table[] = {
-g_etc1_to_bc7_m6_table0, g_etc1_to_bc7_m6_table1, g_etc1_to_bc7_m6_table2, g_etc1_to_bc7_m6_table3, g_etc1_to_bc7_m6_table4, g_etc1_to_bc7_m6_table5, g_etc1_to_bc7_m6_table6, g_etc1_to_bc7_m6_table7, g_etc1_to_bc7_m6_table8, g_etc1_to_bc7_m6_table9, g_etc1_to_bc7_m6_table10, g_etc1_to_bc7_m6_table11, g_etc1_to_bc7_m6_table12, g_etc1_to_bc7_m6_table13, g_etc1_to_bc7_m6_table14, g_etc1_to_bc7_m6_table15,
-g_etc1_to_bc7_m6_table16, g_etc1_to_bc7_m6_table17, g_etc1_to_bc7_m6_table18, g_etc1_to_bc7_m6_table19, g_etc1_to_bc7_m6_table20, g_etc1_to_bc7_m6_table21, g_etc1_to_bc7_m6_table22, g_etc1_to_bc7_m6_table23, g_etc1_to_bc7_m6_table24, g_etc1_to_bc7_m6_table25, g_etc1_to_bc7_m6_table26, g_etc1_to_bc7_m6_table27, g_etc1_to_bc7_m6_table28, g_etc1_to_bc7_m6_table29, g_etc1_to_bc7_m6_table30, g_etc1_to_bc7_m6_table31,
-g_etc1_to_bc7_m6_table32, g_etc1_to_bc7_m6_table33, g_etc1_to_bc7_m6_table34, g_etc1_to_bc7_m6_table35, g_etc1_to_bc7_m6_table36, g_etc1_to_bc7_m6_table37, g_etc1_to_bc7_m6_table38, g_etc1_to_bc7_m6_table39, g_etc1_to_bc7_m6_table40, g_etc1_to_bc7_m6_table41, g_etc1_to_bc7_m6_table42, g_etc1_to_bc7_m6_table43, g_etc1_to_bc7_m6_table44, g_etc1_to_bc7_m6_table45, g_etc1_to_bc7_m6_table46, g_etc1_to_bc7_m6_table47,
-g_etc1_to_bc7_m6_table48, g_etc1_to_bc7_m6_table49, g_etc1_to_bc7_m6_table50, g_etc1_to_bc7_m6_table51, g_etc1_to_bc7_m6_table52, g_etc1_to_bc7_m6_table53, g_etc1_to_bc7_m6_table54, g_etc1_to_bc7_m6_table55, g_etc1_to_bc7_m6_table56, g_etc1_to_bc7_m6_table57, g_etc1_to_bc7_m6_table58, g_etc1_to_bc7_m6_table59, g_etc1_to_bc7_m6_table60, g_etc1_to_bc7_m6_table61, g_etc1_to_bc7_m6_table62, g_etc1_to_bc7_m6_table63,
-g_etc1_to_bc7_m6_table64, g_etc1_to_bc7_m6_table65, g_etc1_to_bc7_m6_table66, g_etc1_to_bc7_m6_table67, g_etc1_to_bc7_m6_table68, g_etc1_to_bc7_m6_table69, g_etc1_to_bc7_m6_table70, g_etc1_to_bc7_m6_table71, g_etc1_to_bc7_m6_table72, g_etc1_to_bc7_m6_table73, g_etc1_to_bc7_m6_table74, g_etc1_to_bc7_m6_table75, g_etc1_to_bc7_m6_table76, g_etc1_to_bc7_m6_table77, g_etc1_to_bc7_m6_table78, g_etc1_to_bc7_m6_table79,
-g_etc1_to_bc7_m6_table80, g_etc1_to_bc7_m6_table81, g_etc1_to_bc7_m6_table82, g_etc1_to_bc7_m6_table83, g_etc1_to_bc7_m6_table84, g_etc1_to_bc7_m6_table85, g_etc1_to_bc7_m6_table86, g_etc1_to_bc7_m6_table87, g_etc1_to_bc7_m6_table88, g_etc1_to_bc7_m6_table89, g_etc1_to_bc7_m6_table90, g_etc1_to_bc7_m6_table91, g_etc1_to_bc7_m6_table92, g_etc1_to_bc7_m6_table93, g_etc1_to_bc7_m6_table94, g_etc1_to_bc7_m6_table95,
-g_etc1_to_bc7_m6_table96, g_etc1_to_bc7_m6_table97, g_etc1_to_bc7_m6_table98, g_etc1_to_bc7_m6_table99, g_etc1_to_bc7_m6_table100, g_etc1_to_bc7_m6_table101, g_etc1_to_bc7_m6_table102, g_etc1_to_bc7_m6_table103, g_etc1_to_bc7_m6_table104, g_etc1_to_bc7_m6_table105, g_etc1_to_bc7_m6_table106, g_etc1_to_bc7_m6_table107, g_etc1_to_bc7_m6_table108, g_etc1_to_bc7_m6_table109, g_etc1_to_bc7_m6_table110, g_etc1_to_bc7_m6_table111,
-g_etc1_to_bc7_m6_table112, g_etc1_to_bc7_m6_table113, g_etc1_to_bc7_m6_table114, g_etc1_to_bc7_m6_table115, g_etc1_to_bc7_m6_table116, g_etc1_to_bc7_m6_table117, g_etc1_to_bc7_m6_table118, g_etc1_to_bc7_m6_table119, g_etc1_to_bc7_m6_table120, g_etc1_to_bc7_m6_table121, g_etc1_to_bc7_m6_table122, g_etc1_to_bc7_m6_table123, g_etc1_to_bc7_m6_table124, g_etc1_to_bc7_m6_table125, g_etc1_to_bc7_m6_table126, g_etc1_to_bc7_m6_table127,
-g_etc1_to_bc7_m6_table128, g_etc1_to_bc7_m6_table129, g_etc1_to_bc7_m6_table130, g_etc1_to_bc7_m6_table131, g_etc1_to_bc7_m6_table132, g_etc1_to_bc7_m6_table133, g_etc1_to_bc7_m6_table134, g_etc1_to_bc7_m6_table135, g_etc1_to_bc7_m6_table136, g_etc1_to_bc7_m6_table137, g_etc1_to_bc7_m6_table138, g_etc1_to_bc7_m6_table139, g_etc1_to_bc7_m6_table140, g_etc1_to_bc7_m6_table141, g_etc1_to_bc7_m6_table142, g_etc1_to_bc7_m6_table143,
-g_etc1_to_bc7_m6_table144, g_etc1_to_bc7_m6_table145, g_etc1_to_bc7_m6_table146, g_etc1_to_bc7_m6_table147, g_etc1_to_bc7_m6_table148, g_etc1_to_bc7_m6_table149, g_etc1_to_bc7_m6_table150, g_etc1_to_bc7_m6_table151, g_etc1_to_bc7_m6_table152, g_etc1_to_bc7_m6_table153, g_etc1_to_bc7_m6_table154, g_etc1_to_bc7_m6_table155, g_etc1_to_bc7_m6_table156, g_etc1_to_bc7_m6_table157, g_etc1_to_bc7_m6_table158, g_etc1_to_bc7_m6_table159,
-g_etc1_to_bc7_m6_table160, g_etc1_to_bc7_m6_table161, g_etc1_to_bc7_m6_table162, g_etc1_to_bc7_m6_table163, g_etc1_to_bc7_m6_table164, g_etc1_to_bc7_m6_table165, g_etc1_to_bc7_m6_table166, g_etc1_to_bc7_m6_table167, g_etc1_to_bc7_m6_table168, g_etc1_to_bc7_m6_table169, g_etc1_to_bc7_m6_table170, g_etc1_to_bc7_m6_table171, g_etc1_to_bc7_m6_table172, g_etc1_to_bc7_m6_table173, g_etc1_to_bc7_m6_table174, g_etc1_to_bc7_m6_table175,
-g_etc1_to_bc7_m6_table176, g_etc1_to_bc7_m6_table177, g_etc1_to_bc7_m6_table178, g_etc1_to_bc7_m6_table179, g_etc1_to_bc7_m6_table180, g_etc1_to_bc7_m6_table181, g_etc1_to_bc7_m6_table182, g_etc1_to_bc7_m6_table183, g_etc1_to_bc7_m6_table184, g_etc1_to_bc7_m6_table185, g_etc1_to_bc7_m6_table186, g_etc1_to_bc7_m6_table187, g_etc1_to_bc7_m6_table188, g_etc1_to_bc7_m6_table189, g_etc1_to_bc7_m6_table190, g_etc1_to_bc7_m6_table191,
-g_etc1_to_bc7_m6_table192, g_etc1_to_bc7_m6_table193, g_etc1_to_bc7_m6_table194, g_etc1_to_bc7_m6_table195, g_etc1_to_bc7_m6_table196, g_etc1_to_bc7_m6_table197, g_etc1_to_bc7_m6_table198, g_etc1_to_bc7_m6_table199, g_etc1_to_bc7_m6_table200, g_etc1_to_bc7_m6_table201, g_etc1_to_bc7_m6_table202, g_etc1_to_bc7_m6_table203, g_etc1_to_bc7_m6_table204, g_etc1_to_bc7_m6_table205, g_etc1_to_bc7_m6_table206, g_etc1_to_bc7_m6_table207,
-g_etc1_to_bc7_m6_table208, g_etc1_to_bc7_m6_table209, g_etc1_to_bc7_m6_table210, g_etc1_to_bc7_m6_table211, g_etc1_to_bc7_m6_table212, g_etc1_to_bc7_m6_table213, g_etc1_to_bc7_m6_table214, g_etc1_to_bc7_m6_table215, g_etc1_to_bc7_m6_table216, g_etc1_to_bc7_m6_table217, g_etc1_to_bc7_m6_table218, g_etc1_to_bc7_m6_table219, g_etc1_to_bc7_m6_table220, g_etc1_to_bc7_m6_table221, g_etc1_to_bc7_m6_table222, g_etc1_to_bc7_m6_table223,
-g_etc1_to_bc7_m6_table224, g_etc1_to_bc7_m6_table225, g_etc1_to_bc7_m6_table226, g_etc1_to_bc7_m6_table227, g_etc1_to_bc7_m6_table228, g_etc1_to_bc7_m6_table229, g_etc1_to_bc7_m6_table230, g_etc1_to_bc7_m6_table231, g_etc1_to_bc7_m6_table232, g_etc1_to_bc7_m6_table233, g_etc1_to_bc7_m6_table234, g_etc1_to_bc7_m6_table235, g_etc1_to_bc7_m6_table236, g_etc1_to_bc7_m6_table237, g_etc1_to_bc7_m6_table238, g_etc1_to_bc7_m6_table239,
-g_etc1_to_bc7_m6_table240, g_etc1_to_bc7_m6_table241, g_etc1_to_bc7_m6_table242, g_etc1_to_bc7_m6_table243, g_etc1_to_bc7_m6_table244, g_etc1_to_bc7_m6_table245, g_etc1_to_bc7_m6_table246, g_etc1_to_bc7_m6_table247, g_etc1_to_bc7_m6_table248, g_etc1_to_bc7_m6_table249, g_etc1_to_bc7_m6_table250, g_etc1_to_bc7_m6_table251, g_etc1_to_bc7_m6_table252, g_etc1_to_bc7_m6_table253, g_etc1_to_bc7_m6_table254, g_etc1_to_bc7_m6_table255,
-};
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_dxt1_5.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_dxt1_5.inc
index 3e7610ff53..8244550959 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_dxt1_5.inc
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_dxt1_5.inc
@@ -491,4 +491,4 @@
{17,31,10897},{16,31,12077},{13,31,6285},{13,31,6285},{8,31,68},{4,31,7686},{0,31,1341},{27,31,968},{27,31,968},{27,31,968},{25,31,325},{31,21,1513},{23,31,605},{23,31,605},{11,31,0},{31,26,1513},{11,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{0,31,0},{31,31,0},{0,31,0},{16,0,9248},{16,0,9248},{16,0,9248},{16,0,9248},{12,31,3626},
{12,31,3626},{12,31,3626},{8,31,68},{0,31,1341},{0,31,1341},{21,31,17476},{20,31,14998},{20,31,14098},{18,31,10672},{20,31,16018},{15,31,8154},{15,31,6218},{9,31,200},{10,31,11338},{0,31,1613},{28,31,1041},{27,31,801},{27,31,680},{26,31,232},{29,29,1473},{26,31,753},{24,31,442},{14,31,0},{31,28,1473},{14,31,0},{20,31,14098},{20,31,14098},{20,31,14098},{18,31,10672},{17,31,11453},{15,31,6218},{15,31,6218},
{9,31,200},{6,31,7270},{0,31,1613},{27,31,680},{27,31,680},{27,31,680},{26,31,232},{28,28,1105},{24,31,442},{24,31,442},{14,31,0},{28,28,1105},{14,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{0,31,0},{31,31,0},{0,31,0},{17,0,9248},{17,0,9248},{17,0,9248},{17,0,9248},{13,31,3929},{13,31,3929},{13,31,3929},{9,31,200},{0,31,1613},
-{0,31,1613}, \ No newline at end of file
+{0,31,1613},
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_dxt1_6.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_dxt1_6.inc
index 2441fbe859..fad45fe22d 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_dxt1_6.inc
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_dxt1_6.inc
@@ -491,4 +491,4 @@
{34,63,10841},{34,63,12089},{26,63,6206},{26,63,6206},{17,63,74},{9,63,7678},{0,63,1341},{54,63,937},{54,63,937},{54,63,937},{51,63,305},{63,43,1513},{47,63,605},{47,63,605},{22,63,1},{62,53,1513},{22,63,1},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{0,63,0},{63,63,0},{0,63,0},{32,0,9256},{32,0,9256},{32,0,9256},{32,0,9256},{23,63,3650},
{23,63,3650},{23,63,3650},{17,63,74},{0,63,1341},{0,63,1341},{43,63,17392},{40,63,15021},{40,63,14060},{37,63,10673},{40,63,16013},{32,63,8261},{29,63,6166},{19,63,194},{20,63,11338},{1,63,1594},{57,63,1041},{56,63,822},{54,63,697},{52,63,234},{63,51,1473},{51,63,737},{49,63,442},{28,63,1},{63,57,1473},{28,63,1},{40,63,14060},{40,63,14060},{40,63,14060},{37,63,10673},{34,63,11401},{29,63,6166},{29,63,6166},
{19,63,194},{12,63,7270},{1,63,1594},{54,63,697},{54,63,697},{54,63,697},{52,63,234},{63,46,1105},{49,63,442},{49,63,442},{28,63,1},{63,54,1105},{28,63,1},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{0,63,0},{63,63,0},{0,63,0},{34,0,9256},{34,0,9256},{34,0,9256},{34,0,9256},{26,63,3898},{26,63,3898},{26,63,3898},{19,63,194},{1,63,1594},
-{1,63,1594}, \ No newline at end of file
+{1,63,1594},
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_pvrtc2_45.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_pvrtc2_45.inc
index 0bca0bbddc..fbaf988d78 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_pvrtc2_45.inc
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_pvrtc2_45.inc
@@ -478,4 +478,4 @@
{8,31,11312},{8,31,11249},{7,31,6499},{7,31,6499},{4,31,260},{3,31,10457},{0,31,2642},{13,31,925},{13,31,925},{13,31,925},{12,31,397},{15,22,1513},{11,31,794},{11,31,794},{7,31,4},{14,27,1513},{7,31,4},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{0,31,0},{15,31,0},{0,31,0},{8,0,9376},{8,0,9376},{8,0,9376},{8,0,9376},{6,31,3074},
{6,31,3074},{6,31,3074},{4,31,260},{0,31,2642},{0,31,2642},{8,31,58848},{7,31,39683},{6,31,25130},{6,31,19007},{8,31,54849},{6,31,27132},{5,31,8569},{4,31,756},{4,31,51302},{0,31,5046},{13,31,1078},{13,31,806},{13,31,637},{12,31,365},{15,26,1473},{12,31,978},{12,31,617},{8,31,9},{14,29,1473},{8,31,9},{9,31,13604},{9,31,13604},{9,31,13604},{8,31,11184},{8,31,10433},{7,31,6339},{7,31,6339},
{5,31,424},{4,31,9713},{0,31,2930},{13,31,637},{13,31,637},{13,31,637},{12,31,365},{14,27,1105},{12,31,617},{12,31,617},{8,31,9},{13,29,1105},{8,31,9},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{0,31,0},{15,31,0},{0,31,0},{8,0,9248},{8,0,9248},{8,0,9248},{8,0,9248},{6,31,3330},{6,31,3330},{6,31,3330},{5,31,424},{0,31,2930},
-{0,31,2930}, \ No newline at end of file
+{0,31,2930},
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_pvrtc2_alpha_33.inc b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_pvrtc2_alpha_33.inc
index 10c94153ad..3b9d7022e7 100644
--- a/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_pvrtc2_alpha_33.inc
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_tables_pvrtc2_alpha_33.inc
@@ -478,4 +478,4 @@
{4,7,11305},{4,7,11209},{3,7,6489},{3,7,6489},{2,7,272},{1,7,10377},{0,7,2642},{6,7,1040},{6,7,1040},{6,7,1040},{6,7,416},{7,6,1537},{6,7,929},{6,7,929},{3,7,9},{7,6,1513},{3,7,9},{7,7,242},{7,7,170},{7,7,121},{7,7,49},{7,7,242},{7,7,98},{7,7,49},{0,7,0},{7,7,98},{0,7,0},{4,0,9280},{4,0,9280},{4,0,9280},{4,0,9280},{3,7,3125},
{3,7,3125},{3,7,3125},{2,7,272},{0,7,2642},{0,7,2642},{4,7,59414},{4,7,41414},{3,7,24952},{3,7,19100},{4,7,55014},{3,7,27085},{2,7,10021},{2,7,656},{1,7,52310},{0,7,5046},{7,7,1142},{7,7,1070},{7,7,1021},{6,7,416},{7,7,1538},{6,7,1025},{6,7,625},{4,7,4},{6,7,1529},{4,7,4},{5,7,13964},{5,7,13964},{5,7,13964},{4,7,11305},{4,7,10505},{3,7,6665},{3,7,6665},
{2,7,592},{2,7,9973},{0,7,2930},{7,7,1021},{7,7,1021},{7,7,1021},{6,7,416},{7,6,1105},{6,7,625},{6,7,625},{4,7,4},{6,7,1129},{4,7,4},{7,7,242},{7,7,170},{7,7,121},{7,7,49},{7,7,242},{7,7,98},{7,7,49},{0,7,0},{7,7,98},{0,7,0},{4,0,9280},{4,0,9280},{4,0,9280},{4,0,9280},{3,7,3301},{3,7,3301},{3,7,3301},{2,7,592},{0,7,2930},
-{0,7,2930}, \ No newline at end of file
+{0,7,2930},
diff --git a/thirdparty/basis_universal/transcoder/basisu_transcoder_uastc.h b/thirdparty/basis_universal/transcoder/basisu_transcoder_uastc.h
new file mode 100644
index 0000000000..d501a2af6e
--- /dev/null
+++ b/thirdparty/basis_universal/transcoder/basisu_transcoder_uastc.h
@@ -0,0 +1,297 @@
+// basisu_transcoder_uastc.h
+#pragma once
+#include "basisu_transcoder_internal.h"
+
+namespace basist
+{
+ struct color_quad_u8
+ {
+ uint8_t m_c[4];
+ };
+
+ const uint32_t TOTAL_UASTC_MODES = 19;
+ const uint32_t UASTC_MODE_INDEX_SOLID_COLOR = 8;
+
+ const uint32_t TOTAL_ASTC_BC7_COMMON_PARTITIONS2 = 30;
+ const uint32_t TOTAL_ASTC_BC7_COMMON_PARTITIONS3 = 11;
+ const uint32_t TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS = 19;
+
+ extern const uint8_t g_uastc_mode_weight_bits[TOTAL_UASTC_MODES];
+ extern const uint8_t g_uastc_mode_weight_ranges[TOTAL_UASTC_MODES];
+ extern const uint8_t g_uastc_mode_endpoint_ranges[TOTAL_UASTC_MODES];
+ extern const uint8_t g_uastc_mode_subsets[TOTAL_UASTC_MODES];
+ extern const uint8_t g_uastc_mode_planes[TOTAL_UASTC_MODES];
+ extern const uint8_t g_uastc_mode_comps[TOTAL_UASTC_MODES];
+ extern const uint8_t g_uastc_mode_has_etc1_bias[TOTAL_UASTC_MODES];
+ extern const uint8_t g_uastc_mode_has_bc1_hint0[TOTAL_UASTC_MODES];
+ extern const uint8_t g_uastc_mode_has_bc1_hint1[TOTAL_UASTC_MODES];
+ extern const uint8_t g_uastc_mode_has_alpha[TOTAL_UASTC_MODES];
+ extern const uint8_t g_uastc_mode_is_la[TOTAL_UASTC_MODES];
+
+ struct astc_bc7_common_partition2_desc
+ {
+ uint8_t m_bc7;
+ uint16_t m_astc;
+ bool m_invert;
+ };
+
+ extern const astc_bc7_common_partition2_desc g_astc_bc7_common_partitions2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2];
+
+ struct bc73_astc2_common_partition_desc
+ {
+ uint8_t m_bc73;
+ uint16_t m_astc2;
+ uint8_t k; // 0-5 - how to modify the BC7 3-subset pattern to match the ASTC pattern (LSB=invert)
+ };
+
+ extern const bc73_astc2_common_partition_desc g_bc7_3_astc2_common_partitions[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS];
+
+ struct astc_bc7_common_partition3_desc
+ {
+ uint8_t m_bc7;
+ uint16_t m_astc;
+ uint8_t m_astc_to_bc7_perm; // converts ASTC to BC7 partition using g_astc_bc7_partition_index_perm_tables[][]
+ };
+
+ extern const astc_bc7_common_partition3_desc g_astc_bc7_common_partitions3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3];
+
+ extern const uint8_t g_astc_bc7_patterns2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][16];
+ extern const uint8_t g_astc_bc7_patterns3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][16];
+ extern const uint8_t g_bc7_3_astc2_patterns2[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][16];
+
+ extern const uint8_t g_astc_bc7_pattern2_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][3];
+ extern const uint8_t g_astc_bc7_pattern3_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][3];
+ extern const uint8_t g_bc7_3_astc2_patterns2_anchors[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][3];
+
+ extern const uint32_t g_uastc_mode_huff_codes[TOTAL_UASTC_MODES + 1][2];
+
+ extern const uint8_t g_astc_to_bc7_partition_index_perm_tables[6][3];
+ extern const uint8_t g_bc7_to_astc_partition_index_perm_tables[6][3]; // inverse of g_astc_to_bc7_partition_index_perm_tables
+
+ extern const uint8_t* s_uastc_to_bc1_weights[6];
+
+ uint32_t bc7_convert_partition_index_3_to_2(uint32_t p, uint32_t k);
+
+ inline uint32_t astc_interpolate(uint32_t l, uint32_t h, uint32_t w, bool srgb)
+ {
+ if (srgb)
+ {
+ l = (l << 8) | 0x80;
+ h = (h << 8) | 0x80;
+ }
+ else
+ {
+ l = (l << 8) | l;
+ h = (h << 8) | h;
+ }
+
+ uint32_t k = (l * (64 - w) + h * w + 32) >> 6;
+
+ return k >> 8;
+ }
+
+ struct astc_block_desc
+ {
+ int m_weight_range; // weight BISE range
+
+ int m_subsets; // number of ASTC partitions
+ int m_partition_seed; // partition pattern seed
+ int m_cem; // color endpoint mode used by all subsets
+
+ int m_ccs; // color component selector (dual plane only)
+ bool m_dual_plane; // true if dual plane
+
+ // Weight and endpoint BISE values.
+ // Note these values are NOT linear, they must be BISE encoded. See Table 97 and Table 107.
+ uint8_t m_endpoints[18]; // endpoint values, in RR GG BB etc. order
+ uint8_t m_weights[64]; // weight index values, raster order, in P0 P1, P0 P1, etc. or P0, P0, P0, P0, etc. order
+ };
+
+ const uint32_t BC7ENC_TOTAL_ASTC_RANGES = 21;
+
+ // See tables 81, 93, 18.13.Endpoint Unquantization
+ const uint32_t TOTAL_ASTC_RANGES = 21;
+ extern const int g_astc_bise_range_table[TOTAL_ASTC_RANGES][3];
+
+ struct astc_quant_bin
+ {
+ uint8_t m_unquant; // unquantized value
+ uint8_t m_index; // sorted index
+ };
+
+ extern astc_quant_bin g_astc_unquant[BC7ENC_TOTAL_ASTC_RANGES][256]; // [ASTC encoded endpoint index]
+
+ int astc_get_levels(int range);
+ bool astc_is_valid_endpoint_range(uint32_t range);
+ uint32_t unquant_astc_endpoint(uint32_t packed_bits, uint32_t packed_trits, uint32_t packed_quints, uint32_t range);
+ uint32_t unquant_astc_endpoint_val(uint32_t packed_val, uint32_t range);
+
+ const uint8_t* get_anchor_indices(uint32_t subsets, uint32_t mode, uint32_t common_pattern, const uint8_t*& pPartition_pattern);
+
+ // BC7
+ const uint32_t BC7ENC_BLOCK_SIZE = 16;
+
+ struct bc7_block
+ {
+ uint64_t m_qwords[2];
+ };
+
+ struct bc7_optimization_results
+ {
+ uint32_t m_mode;
+ uint32_t m_partition;
+ uint8_t m_selectors[16];
+ uint8_t m_alpha_selectors[16];
+ color_quad_u8 m_low[3];
+ color_quad_u8 m_high[3];
+ uint32_t m_pbits[3][2];
+ uint32_t m_index_selector;
+ uint32_t m_rotation;
+ };
+
+ extern const uint32_t g_bc7_weights1[2];
+ extern const uint32_t g_bc7_weights2[4];
+ extern const uint32_t g_bc7_weights3[8];
+ extern const uint32_t g_bc7_weights4[16];
+ extern const uint32_t g_astc_weights4[16];
+ extern const uint32_t g_astc_weights5[32];
+ extern const uint32_t g_astc_weights_3levels[3];
+ extern const uint8_t g_bc7_partition1[16];
+ extern const uint8_t g_bc7_partition2[64 * 16];
+ extern const uint8_t g_bc7_partition3[64 * 16];
+ extern const uint8_t g_bc7_table_anchor_index_second_subset[64];
+ extern const uint8_t g_bc7_table_anchor_index_third_subset_1[64];
+ extern const uint8_t g_bc7_table_anchor_index_third_subset_2[64];
+ extern const uint8_t g_bc7_num_subsets[8];
+ extern const uint8_t g_bc7_partition_bits[8];
+ extern const uint8_t g_bc7_color_index_bitcount[8];
+ extern const uint8_t g_bc7_mode_has_p_bits[8];
+ extern const uint8_t g_bc7_mode_has_shared_p_bits[8];
+ extern const uint8_t g_bc7_color_precision_table[8];
+ extern const int8_t g_bc7_alpha_precision_table[8];
+ extern const uint8_t g_bc7_alpha_index_bitcount[8];
+
+ inline bool get_bc7_mode_has_seperate_alpha_selectors(int mode) { return (mode == 4) || (mode == 5); }
+ inline int get_bc7_color_index_size(int mode, int index_selection_bit) { return g_bc7_color_index_bitcount[mode] + index_selection_bit; }
+ inline int get_bc7_alpha_index_size(int mode, int index_selection_bit) { return g_bc7_alpha_index_bitcount[mode] - index_selection_bit; }
+
+ struct endpoint_err
+ {
+ uint16_t m_error; uint8_t m_lo; uint8_t m_hi;
+ };
+
+ extern endpoint_err g_bc7_mode_6_optimal_endpoints[256][2]; // [c][pbit]
+ const uint32_t BC7ENC_MODE_6_OPTIMAL_INDEX = 5;
+
+ extern endpoint_err g_bc7_mode_5_optimal_endpoints[256]; // [c]
+ const uint32_t BC7ENC_MODE_5_OPTIMAL_INDEX = 1;
+
+ // Packs a BC7 block from a high-level description. Handles all BC7 modes.
+ void encode_bc7_block(void* pBlock, const bc7_optimization_results* pResults);
+
+ // Packs an ASTC block
+ // Constraints: Always 4x4, all subset CEM's must be equal, only tested with LDR CEM's.
+ bool pack_astc_block(uint32_t* pDst, const astc_block_desc* pBlock, uint32_t mode);
+
+ void pack_astc_solid_block(void* pDst_block, const color32& color);
+
+#ifdef _DEBUG
+ int astc_compute_texel_partition(int seed, int x, int y, int z, int partitioncount, bool small_block);
+#endif
+
+ struct uastc_block
+ {
+ union
+ {
+ uint8_t m_bytes[16];
+ uint32_t m_dwords[4];
+
+#ifndef __EMSCRIPTEN__
+ uint64_t m_qwords[2];
+#endif
+ };
+ };
+
+ struct unpacked_uastc_block
+ {
+ astc_block_desc m_astc;
+
+ uint32_t m_mode;
+ uint32_t m_common_pattern;
+
+ color32 m_solid_color;
+
+ bool m_bc1_hint0;
+ bool m_bc1_hint1;
+
+ bool m_etc1_flip;
+ bool m_etc1_diff;
+ uint32_t m_etc1_inten0;
+ uint32_t m_etc1_inten1;
+
+ uint32_t m_etc1_bias;
+
+ uint32_t m_etc2_hints;
+
+ uint32_t m_etc1_selector;
+ uint32_t m_etc1_r, m_etc1_g, m_etc1_b;
+ };
+
+ color32 apply_etc1_bias(const color32 &block_color, uint32_t bias, uint32_t limit, uint32_t subblock);
+
+ struct decoder_etc_block;
+ struct eac_block;
+
+ bool unpack_uastc(uint32_t mode, uint32_t common_pattern, const color32& solid_color, const astc_block_desc& astc, color32* pPixels, bool srgb);
+ bool unpack_uastc(const unpacked_uastc_block& unpacked_blk, color32* pPixels, bool srgb);
+
+ bool unpack_uastc(const uastc_block& blk, color32* pPixels, bool srgb);
+ bool unpack_uastc(const uastc_block& blk, unpacked_uastc_block& unpacked, bool undo_blue_contract, bool read_hints = true);
+
+ bool transcode_uastc_to_astc(const uastc_block& src_blk, void* pDst);
+
+ bool transcode_uastc_to_bc7(const unpacked_uastc_block& unpacked_src_blk, bc7_optimization_results& dst_blk);
+ bool transcode_uastc_to_bc7(const uastc_block& src_blk, bc7_optimization_results& dst_blk);
+ bool transcode_uastc_to_bc7(const uastc_block& src_blk, void* pDst);
+
+ void transcode_uastc_to_etc1(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst);
+ bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst);
+ bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst, uint32_t channel);
+
+ void transcode_uastc_to_etc2_eac_a8(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst);
+ bool transcode_uastc_to_etc2_rgba(const uastc_block& src_blk, void* pDst);
+
+ // Packs 16 scalar values to BC4. Same PSNR as stb_dxt's BC4 encoder, around 13% faster.
+ void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride);
+
+ void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb);
+
+ enum
+ {
+ cEncodeBC1HighQuality = 1,
+ cEncodeBC1HigherQuality = 2,
+ cEncodeBC1UseSelectors = 4,
+ };
+ void encode_bc1(void* pDst, const uint8_t* pPixels, uint32_t flags);
+
+ // Alternate PCA-free encoder, around 15% faster, same (or slightly higher) avg. PSNR
+ void encode_bc1_alt(void* pDst, const uint8_t* pPixels, uint32_t flags);
+
+ void transcode_uastc_to_bc1_hint0(const unpacked_uastc_block& unpacked_src_blk, void* pDst);
+ void transcode_uastc_to_bc1_hint1(const unpacked_uastc_block& unpacked_src_blk, const color32 block_pixels[4][4], void* pDst, bool high_quality);
+
+ bool transcode_uastc_to_bc1(const uastc_block& src_blk, void* pDst, bool high_quality);
+ bool transcode_uastc_to_bc3(const uastc_block& src_blk, void* pDst, bool high_quality);
+ bool transcode_uastc_to_bc4(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0);
+ bool transcode_uastc_to_bc5(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1);
+
+ bool transcode_uastc_to_etc2_eac_r11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0);
+ bool transcode_uastc_to_etc2_eac_rg11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1);
+
+ bool transcode_uastc_to_pvrtc1_4_rgb(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality, bool from_alpha);
+ bool transcode_uastc_to_pvrtc1_4_rgba(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality);
+
+ // uastc_init() MUST be called before using this module.
+ void uastc_init();
+
+} // namespace basist
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
index 6873a95d90..c79623bd57 100644
--- a/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
@@ -80,7 +80,6 @@ struct ClipVertex
btVector3 v;
int id;
//b2ContactID id;
- //b2ContactID id;
};
#define b2Dot(a, b) (a).dot(b)
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
index fec9b03213..4372489fa1 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
@@ -43,7 +43,6 @@ void btMultiBodyJointMotor::finalizeMultiDof()
unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF);
// row 0: the lower bound
- // row 0: the lower bound
jacobianA(0)[offset] = 1;
m_numDofsFinalized = m_jacSizeBoth;
diff --git a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp
index 25ddd539bf..5c20d2a0d4 100644
--- a/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp
+++ b/thirdparty/bullet/BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp
@@ -45,7 +45,6 @@ void btMultiBodySphericalJointMotor::finalizeMultiDof()
unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF);
// row 0: the lower bound
- // row 0: the lower bound
jacobianA(0)[offset] = 1;
m_numDofsFinalized = m_jacSizeBoth;
diff --git a/thirdparty/embree/common/algorithms/parallel_any_of.h b/thirdparty/embree/common/algorithms/parallel_any_of.h
new file mode 100644
index 0000000000..a64e4a1889
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_any_of.h
@@ -0,0 +1,55 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <functional>
+#include "parallel_reduce.h"
+
+namespace embree
+{
+
+ template<typename Index, class UnaryPredicate>
+ __forceinline bool parallel_any_of (Index first, Index last, UnaryPredicate pred)
+ {
+ bool ret = false;
+
+#if defined(TASKING_TBB)
+#if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ tbb::parallel_for(tbb::blocked_range<size_t>{first, last}, [&ret,pred,&context](const tbb::blocked_range<size_t>& r) {
+ if (context.is_group_execution_cancelled()) return;
+ for (size_t i = r.begin(); i != r.end(); ++i) {
+ if (pred(i)) {
+ ret = true;
+ context.cancel_group_execution();
+ }
+ }
+ });
+#else
+ tbb::parallel_for(tbb::blocked_range<size_t>{first, last}, [&ret,pred](const tbb::blocked_range<size_t>& r) {
+ if (tbb::task::self().is_cancelled()) return;
+ for (size_t i = r.begin(); i != r.end(); ++i) {
+ if (pred(i)) {
+ ret = true;
+ tbb::task::self().cancel_group_execution();
+ }
+ }
+ });
+#endif
+#else
+ ret = parallel_reduce (first, last, false, [pred](const range<size_t>& r)->bool {
+ bool localret = false;
+ for (auto i=r.begin(); i<r.end(); ++i) {
+ localret |= pred(i);
+ }
+ return localret;
+ },
+ std::bit_or<bool>()
+ );
+#endif
+
+ return ret;
+ }
+
+} // end namespace
diff --git a/thirdparty/embree/common/algorithms/parallel_filter.h b/thirdparty/embree/common/algorithms/parallel_filter.h
new file mode 100644
index 0000000000..090ef164c2
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_filter.h
@@ -0,0 +1,93 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for.h"
+
+namespace embree
+{
+ template<typename Ty, typename Index, typename Predicate>
+ inline Index sequential_filter( Ty* data, const Index first, const Index last, const Predicate& predicate)
+ {
+ Index j = first;
+ for (Index i=first; i<last; i++)
+ if (predicate(data[i]))
+ data[j++] = data[i];
+
+ return j;
+ }
+
+ template<typename Ty, typename Index, typename Predicate>
+ inline Index parallel_filter( Ty* data, const Index begin, const Index end, const Index minStepSize, const Predicate& predicate)
+ {
+ /* sequential fallback */
+ if (end-begin <= minStepSize)
+ return sequential_filter(data,begin,end,predicate);
+
+ /* calculate number of tasks to use */
+ enum { MAX_TASKS = 64 };
+ const Index numThreads = TaskScheduler::threadCount();
+ const Index numBlocks = (end-begin+minStepSize-1)/minStepSize;
+ const Index taskCount = min(numThreads,numBlocks,(Index)MAX_TASKS);
+
+ /* filter blocks */
+ Index nused[MAX_TASKS];
+ Index nfree[MAX_TASKS];
+ parallel_for(taskCount, [&](const Index taskIndex)
+ {
+ const Index i0 = begin+(taskIndex+0)*(end-begin)/taskCount;
+ const Index i1 = begin+(taskIndex+1)*(end-begin)/taskCount;
+ const Index i2 = sequential_filter(data,i0,i1,predicate);
+ nused[taskIndex] = i2-i0;
+ nfree[taskIndex] = i1-i2;
+ });
+
+ /* calculate offsets */
+ Index sused=0;
+ Index sfree=0;
+ Index pfree[MAX_TASKS];
+ for (Index i=0; i<taskCount; i++)
+ {
+ sused+=nused[i];
+ Index cfree = nfree[i]; pfree[i] = sfree; sfree+=cfree;
+ }
+
+ /* return if we did not filter out any element */
+ assert(sfree <= end-begin);
+ assert(sused <= end-begin);
+ if (sused == end-begin)
+ return end;
+
+ /* otherwise we have to copy misplaced elements around */
+ parallel_for(taskCount, [&](const Index taskIndex)
+ {
+ /* destination to write elements to */
+ Index dst = begin+(taskIndex+0)*(end-begin)/taskCount+nused[taskIndex];
+ Index dst_end = min(dst+nfree[taskIndex],begin+sused);
+ if (dst_end <= dst) return;
+
+ /* range of misplaced elements to copy to destination */
+ Index r0 = pfree[taskIndex];
+ Index r1 = r0+dst_end-dst;
+
+ /* find range in misplaced elements in back to front order */
+ Index k0=0;
+ for (Index i=taskCount-1; i>0; i--)
+ {
+ if (k0 > r1) break;
+ Index k1 = k0+nused[i];
+ Index src = begin+(i+0)*(end-begin)/taskCount+nused[i];
+ for (Index i=max(r0,k0); i<min(r1,k1); i++) {
+ Index isrc = src-i+k0-1;
+ assert(dst >= begin && dst < end);
+ assert(isrc >= begin && isrc < end);
+ data[dst++] = data[isrc];
+ }
+ k0 = k1;
+ }
+ });
+
+ return begin+sused;
+ }
+}
diff --git a/thirdparty/embree/common/algorithms/parallel_for.h b/thirdparty/embree/common/algorithms/parallel_for.h
new file mode 100644
index 0000000000..645681ac63
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_for.h
@@ -0,0 +1,186 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../tasking/taskscheduler.h"
+#include "../sys/array.h"
+#include "../math/math.h"
+#include "../math/range.h"
+
+namespace embree
+{
+ /* parallel_for without range */
+ template<typename Index, typename Func>
+ __forceinline void parallel_for( const Index N, const Func& func)
+ {
+#if defined(TASKING_INTERNAL)
+ if (N) {
+ TaskScheduler::spawn(Index(0),N,Index(1),[&] (const range<Index>& r) {
+ assert(r.size() == 1);
+ func(r.begin());
+ });
+ if (!TaskScheduler::wait())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ }
+
+#elif defined(TASKING_TBB)
+ #if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },context);
+ if (context.is_group_execution_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ });
+ if (tbb::task::self().is_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #endif
+
+#elif defined(TASKING_PPL)
+ concurrency::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ });
+#else
+# error "no tasking system enabled"
+#endif
+ }
+
+ /* parallel for with range and granulatity */
+ template<typename Index, typename Func>
+ __forceinline void parallel_for( const Index first, const Index last, const Index minStepSize, const Func& func)
+ {
+ assert(first <= last);
+#if defined(TASKING_INTERNAL)
+ TaskScheduler::spawn(first,last,minStepSize,func);
+ if (!TaskScheduler::wait())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+
+#elif defined(TASKING_TBB)
+ #if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
+ func(range<Index>(r.begin(),r.end()));
+ },context);
+ if (context.is_group_execution_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #else
+ tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
+ func(range<Index>(r.begin(),r.end()));
+ });
+ if (tbb::task::self().is_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #endif
+
+#elif defined(TASKING_PPL)
+ concurrency::parallel_for(first, last, Index(1) /*minStepSize*/, [&](Index i) {
+ func(range<Index>(i,i+1));
+ });
+
+#else
+# error "no tasking system enabled"
+#endif
+ }
+
+ /* parallel for with range */
+ template<typename Index, typename Func>
+ __forceinline void parallel_for( const Index first, const Index last, const Func& func)
+ {
+ assert(first <= last);
+ parallel_for(first,last,(Index)1,func);
+ }
+
+#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION > 4001)
+
+ template<typename Index, typename Func>
+ __forceinline void parallel_for_static( const Index N, const Func& func)
+ {
+ #if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },tbb::simple_partitioner(),context);
+ if (context.is_group_execution_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },tbb::simple_partitioner());
+ if (tbb::task::self().is_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #endif
+ }
+
+ typedef tbb::affinity_partitioner affinity_partitioner;
+
+ template<typename Index, typename Func>
+ __forceinline void parallel_for_affinity( const Index N, const Func& func, tbb::affinity_partitioner& ap)
+ {
+ #if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },ap,context);
+ if (context.is_group_execution_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },ap);
+ if (tbb::task::self().is_cancelled())
+ // -- GODOT start --
+ // throw std::runtime_error("task cancelled");
+ abort();
+ // -- GODOT end --
+ #endif
+ }
+
+#else
+
+ template<typename Index, typename Func>
+ __forceinline void parallel_for_static( const Index N, const Func& func)
+ {
+ parallel_for(N,func);
+ }
+
+ struct affinity_partitioner {
+ };
+
+ template<typename Index, typename Func>
+ __forceinline void parallel_for_affinity( const Index N, const Func& func, affinity_partitioner& ap)
+ {
+ parallel_for(N,func);
+ }
+
+#endif
+}
diff --git a/thirdparty/embree/common/algorithms/parallel_for_for.h b/thirdparty/embree/common/algorithms/parallel_for_for.h
new file mode 100644
index 0000000000..92c37a4a38
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_for_for.h
@@ -0,0 +1,149 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for.h"
+
+namespace embree
+{
+ template<typename ArrayArray, typename Func>
+ __forceinline void sequential_for_for( ArrayArray& array2, const size_t minStepSize, const Func& func )
+ {
+ size_t k=0;
+ for (size_t i=0; i!=array2.size(); ++i) {
+ const size_t N = array2[i]->size();
+ if (N) func(array2[i],range<size_t>(0,N),k);
+ k+=N;
+ }
+ }
+
+ class ParallelForForState
+ {
+ public:
+
+ enum { MAX_TASKS = 64 };
+
+ __forceinline ParallelForForState ()
+ : taskCount(0) {}
+
+ template<typename ArrayArray>
+ __forceinline ParallelForForState (ArrayArray& array2, const size_t minStepSize) {
+ init(array2,minStepSize);
+ }
+
+ template<typename ArrayArray>
+ __forceinline void init ( ArrayArray& array2, const size_t minStepSize )
+ {
+ /* first calculate total number of elements */
+ size_t N = 0;
+ for (size_t i=0; i<array2.size(); i++) {
+ N += array2[i] ? array2[i]->size() : 0;
+ }
+ this->N = N;
+
+ /* calculate number of tasks to use */
+ const size_t numThreads = TaskScheduler::threadCount();
+ const size_t numBlocks = (N+minStepSize-1)/minStepSize;
+ taskCount = max(size_t(1),min(numThreads,numBlocks,size_t(ParallelForForState::MAX_TASKS)));
+
+ /* calculate start (i,j) for each task */
+ size_t taskIndex = 0;
+ i0[taskIndex] = 0;
+ j0[taskIndex] = 0;
+ size_t k0 = (++taskIndex)*N/taskCount;
+ for (size_t i=0, k=0; taskIndex < taskCount; i++)
+ {
+ assert(i<array2.size());
+ size_t j=0, M = array2[i] ? array2[i]->size() : 0;
+ while (j<M && k+M-j >= k0 && taskIndex < taskCount) {
+ assert(taskIndex<taskCount);
+ i0[taskIndex] = i;
+ j0[taskIndex] = j += k0-k;
+ k=k0;
+ k0 = (++taskIndex)*N/taskCount;
+ }
+ k+=M-j;
+ }
+ }
+
+ __forceinline size_t size() const {
+ return N;
+ }
+
+ public:
+ size_t i0[MAX_TASKS];
+ size_t j0[MAX_TASKS];
+ size_t taskCount;
+ size_t N;
+ };
+
+ template<typename ArrayArray, typename Func>
+ __forceinline void parallel_for_for( ArrayArray& array2, const size_t minStepSize, const Func& func )
+ {
+ ParallelForForState state(array2,minStepSize);
+
+ parallel_for(state.taskCount, [&](const size_t taskIndex)
+ {
+ /* calculate range */
+ const size_t k0 = (taskIndex+0)*state.size()/state.taskCount;
+ const size_t k1 = (taskIndex+1)*state.size()/state.taskCount;
+ size_t i0 = state.i0[taskIndex];
+ size_t j0 = state.j0[taskIndex];
+
+ /* iterate over arrays */
+ size_t k=k0;
+ for (size_t i=i0; k<k1; i++) {
+ const size_t N = array2[i] ? array2[i]->size() : 0;
+ const size_t r0 = j0, r1 = min(N,r0+k1-k);
+ if (r1 > r0) func(array2[i],range<size_t>(r0,r1),k);
+ k+=r1-r0; j0 = 0;
+ }
+ });
+ }
+
+ template<typename ArrayArray, typename Func>
+ __forceinline void parallel_for_for( ArrayArray& array2, const Func& func )
+ {
+ parallel_for_for(array2,1,func);
+ }
+
+ template<typename ArrayArray, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_reduce( ArrayArray& array2, const size_t minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ ParallelForForState state(array2,minStepSize);
+ Value temp[ParallelForForState::MAX_TASKS];
+
+ for (size_t i=0; i<state.taskCount; i++)
+ temp[i] = identity;
+
+ parallel_for(state.taskCount, [&](const size_t taskIndex)
+ {
+ /* calculate range */
+ const size_t k0 = (taskIndex+0)*state.size()/state.taskCount;
+ const size_t k1 = (taskIndex+1)*state.size()/state.taskCount;
+ size_t i0 = state.i0[taskIndex];
+ size_t j0 = state.j0[taskIndex];
+
+ /* iterate over arrays */
+ size_t k=k0;
+ for (size_t i=i0; k<k1; i++) {
+ const size_t N = array2[i] ? array2[i]->size() : 0;
+ const size_t r0 = j0, r1 = min(N,r0+k1-k);
+ if (r1 > r0) temp[taskIndex] = reduction(temp[taskIndex],func(array2[i],range<size_t>(r0,r1),k));
+ k+=r1-r0; j0 = 0;
+ }
+ });
+
+ Value ret = identity;
+ for (size_t i=0; i<state.taskCount; i++)
+ ret = reduction(ret,temp[i]);
+ return ret;
+ }
+
+ template<typename ArrayArray, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_reduce( ArrayArray& array2, const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ return parallel_for_for_reduce(array2,1,identity,func,reduction);
+ }
+}
diff --git a/thirdparty/embree/common/algorithms/parallel_for_for_prefix_sum.h b/thirdparty/embree/common/algorithms/parallel_for_for_prefix_sum.h
new file mode 100644
index 0000000000..b15b44a991
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_for_for_prefix_sum.h
@@ -0,0 +1,112 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for_for.h"
+#include "parallel_prefix_sum.h"
+
+namespace embree
+{
+ template<typename Value>
+ struct ParallelForForPrefixSumState : public ParallelForForState
+ {
+ __forceinline ParallelForForPrefixSumState () {}
+
+ template<typename ArrayArray>
+ __forceinline ParallelForForPrefixSumState (ArrayArray& array2, const size_t minStepSize)
+ : ParallelForForState(array2,minStepSize) {}
+
+ ParallelPrefixSumState<Value> prefix_state;
+ };
+
+ template<typename ArrayArray, typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_prefix_sum0( ParallelForForPrefixSumState<Value>& state, ArrayArray& array2, Index minStepSize,
+ const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ /* calculate number of tasks to use */
+ const size_t taskCount = state.taskCount;
+ /* perform parallel prefix sum */
+ parallel_for(taskCount, [&](const size_t taskIndex)
+ {
+ const size_t k0 = (taskIndex+0)*state.size()/taskCount;
+ const size_t k1 = (taskIndex+1)*state.size()/taskCount;
+ size_t i0 = state.i0[taskIndex];
+ size_t j0 = state.j0[taskIndex];
+
+ /* iterate over arrays */
+ size_t k=k0;
+ Value N=identity;
+ for (size_t i=i0; k<k1; i++) {
+ const size_t size = array2[i] ? array2[i]->size() : 0;
+ const size_t r0 = j0, r1 = min(size,r0+k1-k);
+ if (r1 > r0) N = reduction(N, func(array2[i],range<Index>((Index)r0,(Index)r1),(Index)k,(Index)i));
+ k+=r1-r0; j0 = 0;
+ }
+ state.prefix_state.counts[taskIndex] = N;
+ });
+
+ /* calculate prefix sum */
+ Value sum=identity;
+ for (size_t i=0; i<taskCount; i++)
+ {
+ const Value c = state.prefix_state.counts[i];
+ state.prefix_state.sums[i] = sum;
+ sum=reduction(sum,c);
+ }
+
+ return sum;
+ }
+
+ template<typename ArrayArray, typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_prefix_sum1( ParallelForForPrefixSumState<Value>& state, ArrayArray& array2, Index minStepSize,
+ const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ /* calculate number of tasks to use */
+ const size_t taskCount = state.taskCount;
+ /* perform parallel prefix sum */
+ parallel_for(taskCount, [&](const size_t taskIndex)
+ {
+ const size_t k0 = (taskIndex+0)*state.size()/taskCount;
+ const size_t k1 = (taskIndex+1)*state.size()/taskCount;
+ size_t i0 = state.i0[taskIndex];
+ size_t j0 = state.j0[taskIndex];
+
+ /* iterate over arrays */
+ size_t k=k0;
+ Value N=identity;
+ for (size_t i=i0; k<k1; i++) {
+ const size_t size = array2[i] ? array2[i]->size() : 0;
+ const size_t r0 = j0, r1 = min(size,r0+k1-k);
+ if (r1 > r0) N = reduction(N, func(array2[i],range<Index>((Index)r0,(Index)r1),(Index)k,(Index)i,reduction(state.prefix_state.sums[taskIndex],N)));
+ k+=r1-r0; j0 = 0;
+ }
+ state.prefix_state.counts[taskIndex] = N;
+ });
+
+ /* calculate prefix sum */
+ Value sum=identity;
+ for (size_t i=0; i<taskCount; i++)
+ {
+ const Value c = state.prefix_state.counts[i];
+ state.prefix_state.sums[i] = sum;
+ sum=reduction(sum,c);
+ }
+
+ return sum;
+ }
+
+ template<typename ArrayArray, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_prefix_sum0( ParallelForForPrefixSumState<Value>& state, ArrayArray& array2,
+ const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ return parallel_for_for_prefix_sum0(state,array2,size_t(1),identity,func,reduction);
+ }
+
+ template<typename ArrayArray, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_for_for_prefix_sum1( ParallelForForPrefixSumState<Value>& state, ArrayArray& array2,
+ const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ return parallel_for_for_prefix_sum1(state,array2,size_t(1),identity,func,reduction);
+ }
+}
diff --git a/thirdparty/embree/common/algorithms/parallel_map.h b/thirdparty/embree/common/algorithms/parallel_map.h
new file mode 100644
index 0000000000..15c098fe20
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_map.h
@@ -0,0 +1,85 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_sort.h"
+
+namespace embree
+{
+ /*! implementation of a key/value map with parallel construction */
+ template<typename Key, typename Val>
+ class parallel_map
+ {
+ /* key/value pair to build the map */
+ struct KeyValue
+ {
+ __forceinline KeyValue () {}
+
+ __forceinline KeyValue (const Key key, const Val val)
+ : key(key), val(val) {}
+
+ __forceinline operator Key() const {
+ return key;
+ }
+
+ public:
+ Key key;
+ Val val;
+ };
+
+ public:
+
+ /*! parallel map constructors */
+ parallel_map () {}
+
+ /*! construction from pair of vectors */
+ template<typename KeyVector, typename ValVector>
+ parallel_map (const KeyVector& keys, const ValVector& values) { init(keys,values); }
+
+ /*! initialized the parallel map from a vector with keys and values */
+ template<typename KeyVector, typename ValVector>
+ void init(const KeyVector& keys, const ValVector& values)
+ {
+ /* reserve sufficient space for all data */
+ assert(keys.size() == values.size());
+ vec.resize(keys.size());
+
+ /* generate key/value pairs */
+ parallel_for( size_t(0), keys.size(), size_t(4*4096), [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ vec[i] = KeyValue((Key)keys[i],values[i]);
+ });
+
+ /* perform parallel radix sort of the key/value pairs */
+ std::vector<KeyValue> temp(keys.size());
+ radix_sort<KeyValue,Key>(vec.data(),temp.data(),keys.size());
+ }
+
+ /*! Returns a pointer to the value associated with the specified key. The pointer will be nullptr of the key is not contained in the map. */
+ __forceinline const Val* lookup(const Key& key) const
+ {
+ typename std::vector<KeyValue>::const_iterator i = std::lower_bound(vec.begin(), vec.end(), key);
+ if (i == vec.end()) return nullptr;
+ if (i->key != key) return nullptr;
+ return &i->val;
+ }
+
+ /*! If the key is in the map, the function returns the value associated with the key, otherwise it returns the default value. */
+ __forceinline Val lookup(const Key& key, const Val& def) const
+ {
+ typename std::vector<KeyValue>::const_iterator i = std::lower_bound(vec.begin(), vec.end(), key);
+ if (i == vec.end()) return def;
+ if (i->key != key) return def;
+ return i->val;
+ }
+
+ /*! clears all state */
+ void clear() {
+ vec.clear();
+ }
+
+ private:
+ std::vector<KeyValue> vec; //!< vector containing sorted elements
+ };
+}
diff --git a/thirdparty/embree/common/algorithms/parallel_partition.h b/thirdparty/embree/common/algorithms/parallel_partition.h
new file mode 100644
index 0000000000..a1cbdc8e04
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_partition.h
@@ -0,0 +1,283 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for.h"
+#include "../math/range.h"
+
+namespace embree
+{
+ /* serial partitioning */
+ template<typename T, typename V, typename IsLeft, typename Reduction_T>
+ __forceinline size_t serial_partitioning(T* array,
+ const size_t begin,
+ const size_t end,
+ V& leftReduction,
+ V& rightReduction,
+ const IsLeft& is_left,
+ const Reduction_T& reduction_t)
+ {
+ T* l = array + begin;
+ T* r = array + end - 1;
+
+ while(1)
+ {
+ /* *l < pivot */
+ while (likely(l <= r && is_left(*l) ))
+ {
+ //prefetchw(l+4); // FIXME: enable?
+ reduction_t(leftReduction,*l);
+ ++l;
+ }
+ /* *r >= pivot) */
+ while (likely(l <= r && !is_left(*r)))
+ {
+ //prefetchw(r-4); FIXME: enable?
+ reduction_t(rightReduction,*r);
+ --r;
+ }
+ if (r<l) break;
+
+ reduction_t(leftReduction ,*r);
+ reduction_t(rightReduction,*l);
+ xchg(*l,*r);
+ l++; r--;
+ }
+
+ return l - array;
+ }
+
+ template<typename T, typename V, typename Vi, typename IsLeft, typename Reduction_T, typename Reduction_V>
+ class __aligned(64) parallel_partition_task
+ {
+ ALIGNED_CLASS_(64);
+ private:
+
+ static const size_t MAX_TASKS = 64;
+
+ T* array;
+ size_t N;
+ const IsLeft& is_left;
+ const Reduction_T& reduction_t;
+ const Reduction_V& reduction_v;
+ const Vi& identity;
+
+ size_t numTasks;
+ __aligned(64) size_t counter_start[MAX_TASKS+1];
+ __aligned(64) size_t counter_left[MAX_TASKS+1];
+ __aligned(64) range<ssize_t> leftMisplacedRanges[MAX_TASKS];
+ __aligned(64) range<ssize_t> rightMisplacedRanges[MAX_TASKS];
+ __aligned(64) V leftReductions[MAX_TASKS];
+ __aligned(64) V rightReductions[MAX_TASKS];
+
+ public:
+
+ __forceinline parallel_partition_task(T* array,
+ const size_t N,
+ const Vi& identity,
+ const IsLeft& is_left,
+ const Reduction_T& reduction_t,
+ const Reduction_V& reduction_v,
+ const size_t BLOCK_SIZE)
+
+ : array(array), N(N), is_left(is_left), reduction_t(reduction_t), reduction_v(reduction_v), identity(identity),
+ numTasks(min((N+BLOCK_SIZE-1)/BLOCK_SIZE,min(TaskScheduler::threadCount(),MAX_TASKS))) {}
+
+ __forceinline const range<ssize_t>* findStartRange(size_t& index, const range<ssize_t>* const r, const size_t numRanges)
+ {
+ size_t i = 0;
+ while(index >= (size_t)r[i].size())
+ {
+ assert(i < numRanges);
+ index -= (size_t)r[i].size();
+ i++;
+ }
+ return &r[i];
+ }
+
+ __forceinline void swapItemsInMisplacedRanges(const size_t numLeftMisplacedRanges,
+ const size_t numRightMisplacedRanges,
+ const size_t startID,
+ const size_t endID)
+ {
+ size_t leftLocalIndex = startID;
+ size_t rightLocalIndex = startID;
+ const range<ssize_t>* l_range = findStartRange(leftLocalIndex,leftMisplacedRanges,numLeftMisplacedRanges);
+ const range<ssize_t>* r_range = findStartRange(rightLocalIndex,rightMisplacedRanges,numRightMisplacedRanges);
+
+ size_t l_left = l_range->size() - leftLocalIndex;
+ size_t r_left = r_range->size() - rightLocalIndex;
+ T *__restrict__ l = &array[l_range->begin() + leftLocalIndex];
+ T *__restrict__ r = &array[r_range->begin() + rightLocalIndex];
+ size_t size = endID - startID;
+ size_t items = min(size,min(l_left,r_left));
+
+ while (size)
+ {
+ if (unlikely(l_left == 0))
+ {
+ l_range++;
+ l_left = l_range->size();
+ l = &array[l_range->begin()];
+ items = min(size,min(l_left,r_left));
+ }
+
+ if (unlikely(r_left == 0))
+ {
+ r_range++;
+ r_left = r_range->size();
+ r = &array[r_range->begin()];
+ items = min(size,min(l_left,r_left));
+ }
+
+ size -= items;
+ l_left -= items;
+ r_left -= items;
+
+ while(items) {
+ items--;
+ xchg(*l++,*r++);
+ }
+ }
+ }
+
+ __forceinline size_t partition(V& leftReduction, V& rightReduction)
+ {
+ /* partition the individual ranges for each task */
+ parallel_for(numTasks,[&] (const size_t taskID) {
+ const size_t startID = (taskID+0)*N/numTasks;
+ const size_t endID = (taskID+1)*N/numTasks;
+ V local_left(identity);
+ V local_right(identity);
+ const size_t mid = serial_partitioning(array,startID,endID,local_left,local_right,is_left,reduction_t);
+ counter_start[taskID] = startID;
+ counter_left [taskID] = mid-startID;
+ leftReductions[taskID] = local_left;
+ rightReductions[taskID] = local_right;
+ });
+ counter_start[numTasks] = N;
+ counter_left[numTasks] = 0;
+
+ /* finalize the reductions */
+ for (size_t i=0; i<numTasks; i++) {
+ reduction_v(leftReduction,leftReductions[i]);
+ reduction_v(rightReduction,rightReductions[i]);
+ }
+
+ /* calculate mid point for partitioning */
+ size_t mid = counter_left[0];
+ for (size_t i=1; i<numTasks; i++)
+ mid += counter_left[i];
+ const range<ssize_t> globalLeft (0,mid);
+ const range<ssize_t> globalRight(mid,N);
+
+ /* calculate all left and right ranges that are on the wrong global side */
+ size_t numMisplacedRangesLeft = 0;
+ size_t numMisplacedRangesRight = 0;
+ size_t numMisplacedItemsLeft = 0;
+ size_t numMisplacedItemsRight = 0;
+
+ for (size_t i=0; i<numTasks; i++)
+ {
+ const range<ssize_t> left_range (counter_start[i], counter_start[i] + counter_left[i]);
+ const range<ssize_t> right_range(counter_start[i] + counter_left[i], counter_start[i+1]);
+ const range<ssize_t> left_misplaced = globalLeft. intersect(right_range);
+ const range<ssize_t> right_misplaced = globalRight.intersect(left_range);
+
+ if (!left_misplaced.empty())
+ {
+ numMisplacedItemsLeft += left_misplaced.size();
+ leftMisplacedRanges[numMisplacedRangesLeft++] = left_misplaced;
+ }
+
+ if (!right_misplaced.empty())
+ {
+ numMisplacedItemsRight += right_misplaced.size();
+ rightMisplacedRanges[numMisplacedRangesRight++] = right_misplaced;
+ }
+ }
+ assert( numMisplacedItemsLeft == numMisplacedItemsRight );
+
+ /* if no items are misplaced we are done */
+ if (numMisplacedItemsLeft == 0)
+ return mid;
+
+ /* otherwise we copy the items to the right place in parallel */
+ parallel_for(numTasks,[&] (const size_t taskID) {
+ const size_t startID = (taskID+0)*numMisplacedItemsLeft/numTasks;
+ const size_t endID = (taskID+1)*numMisplacedItemsLeft/numTasks;
+ swapItemsInMisplacedRanges(numMisplacedRangesLeft,numMisplacedRangesRight,startID,endID);
+ });
+
+ return mid;
+ }
+ };
+
+ template<typename T, typename V, typename Vi, typename IsLeft, typename Reduction_T, typename Reduction_V>
+ __noinline size_t parallel_partitioning(T* array,
+ const size_t begin,
+ const size_t end,
+ const Vi &identity,
+ V &leftReduction,
+ V &rightReduction,
+ const IsLeft& is_left,
+ const Reduction_T& reduction_t,
+ const Reduction_V& reduction_v,
+ size_t BLOCK_SIZE = 128)
+ {
+ /* fall back to single threaded partitioning for small N */
+ if (unlikely(end-begin < BLOCK_SIZE))
+ return serial_partitioning(array,begin,end,leftReduction,rightReduction,is_left,reduction_t);
+
+ /* otherwise use parallel code */
+ else {
+ typedef parallel_partition_task<T,V,Vi,IsLeft,Reduction_T,Reduction_V> partition_task;
+ std::unique_ptr<partition_task> p(new partition_task(&array[begin],end-begin,identity,is_left,reduction_t,reduction_v,BLOCK_SIZE));
+ return begin+p->partition(leftReduction,rightReduction);
+ }
+ }
+
+ template<typename T, typename V, typename Vi, typename IsLeft, typename Reduction_T, typename Reduction_V>
+ __noinline size_t parallel_partitioning(T* array,
+ const size_t begin,
+ const size_t end,
+ const Vi &identity,
+ V &leftReduction,
+ V &rightReduction,
+ const IsLeft& is_left,
+ const Reduction_T& reduction_t,
+ const Reduction_V& reduction_v,
+ size_t BLOCK_SIZE,
+ size_t PARALLEL_THRESHOLD)
+ {
+ /* fall back to single threaded partitioning for small N */
+ if (unlikely(end-begin < PARALLEL_THRESHOLD))
+ return serial_partitioning(array,begin,end,leftReduction,rightReduction,is_left,reduction_t);
+
+ /* otherwise use parallel code */
+ else {
+ typedef parallel_partition_task<T,V,Vi,IsLeft,Reduction_T,Reduction_V> partition_task;
+ std::unique_ptr<partition_task> p(new partition_task(&array[begin],end-begin,identity,is_left,reduction_t,reduction_v,BLOCK_SIZE));
+ return begin+p->partition(leftReduction,rightReduction);
+ }
+ }
+
+
+ template<typename T, typename IsLeft>
+ inline size_t parallel_partitioning(T* array,
+ const size_t begin,
+ const size_t end,
+ const IsLeft& is_left,
+ size_t BLOCK_SIZE = 128)
+ {
+ size_t leftReduction = 0;
+ size_t rightReduction = 0;
+ return parallel_partitioning(
+ array,begin,end,0,leftReduction,rightReduction,is_left,
+ [] (size_t& t,const T& ref) { },
+ [] (size_t& t0,size_t& t1) { },
+ BLOCK_SIZE);
+ }
+
+}
diff --git a/thirdparty/embree/common/algorithms/parallel_prefix_sum.h b/thirdparty/embree/common/algorithms/parallel_prefix_sum.h
new file mode 100644
index 0000000000..208bb4e480
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_prefix_sum.h
@@ -0,0 +1,85 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for.h"
+
+namespace embree
+{
+ template<typename Value>
+ struct ParallelPrefixSumState
+ {
+ enum { MAX_TASKS = 64 };
+ Value counts[MAX_TASKS];
+ Value sums [MAX_TASKS];
+ };
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_prefix_sum( ParallelPrefixSumState<Value>& state, Index first, Index last, Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction)
+ {
+ /* calculate number of tasks to use */
+ const size_t numThreads = TaskScheduler::threadCount();
+ const size_t numBlocks = (last-first+minStepSize-1)/minStepSize;
+ const size_t taskCount = min(numThreads,numBlocks,size_t(ParallelPrefixSumState<Value>::MAX_TASKS));
+
+ /* perform parallel prefix sum */
+ parallel_for(taskCount, [&](const size_t taskIndex)
+ {
+ const size_t i0 = first+(taskIndex+0)*(last-first)/taskCount;
+ const size_t i1 = first+(taskIndex+1)*(last-first)/taskCount;
+ state.counts[taskIndex] = func(range<size_t>(i0,i1),state.sums[taskIndex]);
+ });
+
+ /* calculate prefix sum */
+ Value sum=identity;
+ for (size_t i=0; i<taskCount; i++)
+ {
+ const Value c = state.counts[i];
+ state.sums[i] = sum;
+ sum=reduction(sum,c);
+ }
+
+ return sum;
+ }
+
+ /*! parallel calculation of prefix sums */
+ template<typename SrcArray, typename DstArray, typename Value, typename Add>
+ __forceinline Value parallel_prefix_sum(const SrcArray& src, DstArray& dst, size_t N, const Value& identity, const Add& add, const size_t SINGLE_THREAD_THRESHOLD = 4096)
+ {
+ /* perform single threaded prefix operation for small N */
+ if (N < SINGLE_THREAD_THRESHOLD)
+ {
+ Value sum=identity;
+ for (size_t i=0; i<N; sum=add(sum,src[i++])) dst[i] = sum;
+ return sum;
+ }
+
+ /* perform parallel prefix operation for large N */
+ else
+ {
+ ParallelPrefixSumState<Value> state;
+
+ /* initial run just sets up start values for subtasks */
+ parallel_prefix_sum( state, size_t(0), size_t(N), size_t(1024), identity, [&](const range<size_t>& r, const Value& sum) -> Value {
+
+ Value s = identity;
+ for (size_t i=r.begin(); i<r.end(); i++) s = add(s,src[i]);
+ return s;
+
+ }, add);
+
+ /* final run calculates prefix sum */
+ return parallel_prefix_sum( state, size_t(0), size_t(N), size_t(1024), identity, [&](const range<size_t>& r, const Value& sum) -> Value {
+
+ Value s = identity;
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ dst[i] = add(sum,s);
+ s = add(s,src[i]);
+ }
+ return s;
+
+ }, add);
+ }
+ }
+}
diff --git a/thirdparty/embree/common/algorithms/parallel_reduce.h b/thirdparty/embree/common/algorithms/parallel_reduce.h
new file mode 100644
index 0000000000..8271372ea4
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_reduce.h
@@ -0,0 +1,150 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_for.h"
+
+namespace embree
+{
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value sequential_reduce( const Index first, const Index last, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ return func(range<Index>(first,last));
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value sequential_reduce( const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ return func(range<Index>(first,last));
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __noinline Value parallel_reduce_internal( Index taskCount, const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ const Index maxTasks = 512;
+ const Index threadCount = (Index) TaskScheduler::threadCount();
+ taskCount = min(taskCount,threadCount,maxTasks);
+
+ /* parallel invokation of all tasks */
+ dynamic_large_stack_array(Value,values,taskCount,8192); // consumes at most 8192 bytes on the stack
+ parallel_for(taskCount, [&](const Index taskIndex) {
+ const Index k0 = first+(taskIndex+0)*(last-first)/taskCount;
+ const Index k1 = first+(taskIndex+1)*(last-first)/taskCount;
+ values[taskIndex] = func(range<Index>(k0,k1));
+ });
+
+ /* perform reduction over all tasks */
+ Value v = identity;
+ for (Index i=0; i<taskCount; i++) v = reduction(v,values[i]);
+ return v;
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_reduce( const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+#if defined(TASKING_INTERNAL)
+
+ /* fast path for small number of iterations */
+ Index taskCount = (last-first+minStepSize-1)/minStepSize;
+ if (likely(taskCount == 1)) {
+ return func(range<Index>(first,last));
+ }
+ return parallel_reduce_internal(taskCount,first,last,minStepSize,identity,func,reduction);
+
+#elif defined(TASKING_TBB)
+ #if TBB_INTERFACE_VERSION >= 12002
+ tbb::task_group_context context;
+ const Value v = tbb::parallel_reduce(tbb::blocked_range<Index>(first,last,minStepSize),identity,
+ [&](const tbb::blocked_range<Index>& r, const Value& start) { return reduction(start,func(range<Index>(r.begin(),r.end()))); },
+ reduction,context);
+ // -- GODOT start --
+ // if (context.is_group_execution_cancelled())
+ // throw std::runtime_error("task cancelled");
+ // -- GODOT end --
+ return v;
+ #else
+ const Value v = tbb::parallel_reduce(tbb::blocked_range<Index>(first,last,minStepSize),identity,
+ [&](const tbb::blocked_range<Index>& r, const Value& start) { return reduction(start,func(range<Index>(r.begin(),r.end()))); },
+ reduction);
+ // -- GODOT start --
+ // if (tbb::task::self().is_cancelled())
+ // throw std::runtime_error("task cancelled");
+ // -- GODOT end --
+ return v;
+ #endif
+#else // TASKING_PPL
+ struct AlignedValue
+ {
+ char storage[__alignof(Value)+sizeof(Value)];
+ static uintptr_t alignUp(uintptr_t p, size_t a) { return p + (~(p - 1) % a); };
+ Value* getValuePtr() { return reinterpret_cast<Value*>(alignUp(uintptr_t(storage), __alignof(Value))); }
+ const Value* getValuePtr() const { return reinterpret_cast<Value*>(alignUp(uintptr_t(storage), __alignof(Value))); }
+ AlignedValue(const Value& v) { new(getValuePtr()) Value(v); }
+ AlignedValue(const AlignedValue& v) { new(getValuePtr()) Value(*v.getValuePtr()); }
+ AlignedValue(const AlignedValue&& v) { new(getValuePtr()) Value(*v.getValuePtr()); };
+ AlignedValue& operator = (const AlignedValue& v) { *getValuePtr() = *v.getValuePtr(); return *this; };
+ AlignedValue& operator = (const AlignedValue&& v) { *getValuePtr() = *v.getValuePtr(); return *this; };
+ operator Value() const { return *getValuePtr(); }
+ };
+
+ struct Iterator_Index
+ {
+ Index v;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef AlignedValue value_type;
+ typedef Index difference_type;
+ typedef Index distance_type;
+ typedef AlignedValue* pointer;
+ typedef AlignedValue& reference;
+ __forceinline Iterator_Index() {}
+ __forceinline Iterator_Index(Index v) : v(v) {}
+ __forceinline bool operator== (Iterator_Index other) { return v == other.v; }
+ __forceinline bool operator!= (Iterator_Index other) { return v != other.v; }
+ __forceinline Iterator_Index operator++() { return Iterator_Index(++v); }
+ __forceinline Iterator_Index operator++(int) { return Iterator_Index(v++); }
+ };
+
+ auto range_reduction = [&](Iterator_Index begin, Iterator_Index end, const AlignedValue& start) {
+ assert(begin.v < end.v);
+ return reduction(start, func(range<Index>(begin.v, end.v)));
+ };
+ const Value v = concurrency::parallel_reduce(Iterator_Index(first), Iterator_Index(last), AlignedValue(identity), range_reduction, reduction);
+ return v;
+#endif
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_reduce( const Index first, const Index last, const Index minStepSize, const Index parallel_threshold, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ if (likely(last-first < parallel_threshold)) {
+ return func(range<Index>(first,last));
+ } else {
+ return parallel_reduce(first,last,minStepSize,identity,func,reduction);
+ }
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_reduce( const range<Index> range, const Index minStepSize, const Index parallel_threshold, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ return parallel_reduce(range.begin(),range.end(),minStepSize,parallel_threshold,identity,func,reduction);
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_reduce( const Index first, const Index last, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ auto funcr = [&] ( const range<Index> r ) {
+ Value v = identity;
+ for (Index i=r.begin(); i<r.end(); i++)
+ v = reduction(v,func(i));
+ return v;
+ };
+ return parallel_reduce(first,last,Index(1),identity,funcr,reduction);
+ }
+
+ template<typename Index, typename Value, typename Func, typename Reduction>
+ __forceinline Value parallel_reduce( const range<Index> range, const Value& identity, const Func& func, const Reduction& reduction )
+ {
+ return parallel_reduce(range.begin(),range.end(),Index(1),identity,func,reduction);
+ }
+}
diff --git a/thirdparty/embree/common/algorithms/parallel_set.h b/thirdparty/embree/common/algorithms/parallel_set.h
new file mode 100644
index 0000000000..7eae577457
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_set.h
@@ -0,0 +1,52 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "parallel_sort.h"
+
+namespace embree
+{
+ /* implementation of a set of values with parallel construction */
+ template<typename T>
+ class parallel_set
+ {
+ public:
+
+ /*! default constructor for the parallel set */
+ parallel_set () {}
+
+ /*! construction from vector */
+ template<typename Vector>
+ parallel_set (const Vector& in) { init(in); }
+
+ /*! initialized the parallel set from a vector */
+ template<typename Vector>
+ void init(const Vector& in)
+ {
+ /* copy data to internal vector */
+ vec.resize(in.size());
+ parallel_for( size_t(0), in.size(), size_t(4*4096), [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ vec[i] = in[i];
+ });
+
+ /* sort the data */
+ std::vector<T> temp(in.size());
+ radix_sort<T>(vec.data(),temp.data(),vec.size());
+ }
+
+ /*! tests if some element is in the set */
+ __forceinline bool lookup(const T& elt) const {
+ return std::binary_search(vec.begin(), vec.end(), elt);
+ }
+
+ /*! clears all state */
+ void clear() {
+ vec.clear();
+ }
+
+ private:
+ std::vector<T> vec; //!< vector containing sorted elements
+ };
+}
diff --git a/thirdparty/embree/common/algorithms/parallel_sort.h b/thirdparty/embree/common/algorithms/parallel_sort.h
new file mode 100644
index 0000000000..30e56c2bfc
--- /dev/null
+++ b/thirdparty/embree/common/algorithms/parallel_sort.h
@@ -0,0 +1,454 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../simd/simd.h"
+#include "parallel_for.h"
+#include <algorithm>
+
+namespace embree
+{
+ template<class T>
+ __forceinline void insertionsort_ascending(T *__restrict__ array, const size_t length)
+ {
+ for(size_t i = 1;i<length;++i)
+ {
+ T v = array[i];
+ size_t j = i;
+ while(j > 0 && v < array[j-1])
+ {
+ array[j] = array[j-1];
+ --j;
+ }
+ array[j] = v;
+ }
+ }
+
+ template<class T>
+ __forceinline void insertionsort_decending(T *__restrict__ array, const size_t length)
+ {
+ for(size_t i = 1;i<length;++i)
+ {
+ T v = array[i];
+ size_t j = i;
+ while(j > 0 && v > array[j-1])
+ {
+ array[j] = array[j-1];
+ --j;
+ }
+ array[j] = v;
+ }
+ }
+
+ template<class T>
+ void quicksort_ascending(T *__restrict__ t,
+ const ssize_t begin,
+ const ssize_t end)
+ {
+ if (likely(begin < end))
+ {
+ const T pivotvalue = t[begin];
+ ssize_t left = begin - 1;
+ ssize_t right = end + 1;
+
+ while(1)
+ {
+ while (t[--right] > pivotvalue);
+ while (t[++left] < pivotvalue);
+
+ if (left >= right) break;
+
+ const T temp = t[right];
+ t[right] = t[left];
+ t[left] = temp;
+ }
+
+ const int pivot = right;
+ quicksort_ascending(t, begin, pivot);
+ quicksort_ascending(t, pivot + 1, end);
+ }
+ }
+
+ template<class T>
+ void quicksort_decending(T *__restrict__ t,
+ const ssize_t begin,
+ const ssize_t end)
+ {
+ if (likely(begin < end))
+ {
+ const T pivotvalue = t[begin];
+ ssize_t left = begin - 1;
+ ssize_t right = end + 1;
+
+ while(1)
+ {
+ while (t[--right] < pivotvalue);
+ while (t[++left] > pivotvalue);
+
+ if (left >= right) break;
+
+ const T temp = t[right];
+ t[right] = t[left];
+ t[left] = temp;
+ }
+
+ const int pivot = right;
+ quicksort_decending(t, begin, pivot);
+ quicksort_decending(t, pivot + 1, end);
+ }
+ }
+
+
+ template<class T, ssize_t THRESHOLD>
+ void quicksort_insertionsort_ascending(T *__restrict__ t,
+ const ssize_t begin,
+ const ssize_t end)
+ {
+ if (likely(begin < end))
+ {
+ const ssize_t size = end-begin+1;
+ if (likely(size <= THRESHOLD))
+ {
+ insertionsort_ascending<T>(&t[begin],size);
+ }
+ else
+ {
+ const T pivotvalue = t[begin];
+ ssize_t left = begin - 1;
+ ssize_t right = end + 1;
+
+ while(1)
+ {
+ while (t[--right] > pivotvalue);
+ while (t[++left] < pivotvalue);
+
+ if (left >= right) break;
+
+ const T temp = t[right];
+ t[right] = t[left];
+ t[left] = temp;
+ }
+
+ const ssize_t pivot = right;
+ quicksort_insertionsort_ascending<T,THRESHOLD>(t, begin, pivot);
+ quicksort_insertionsort_ascending<T,THRESHOLD>(t, pivot + 1, end);
+ }
+ }
+ }
+
+
+ template<class T, ssize_t THRESHOLD>
+ void quicksort_insertionsort_decending(T *__restrict__ t,
+ const ssize_t begin,
+ const ssize_t end)
+ {
+ if (likely(begin < end))
+ {
+ const ssize_t size = end-begin+1;
+ if (likely(size <= THRESHOLD))
+ {
+ insertionsort_decending<T>(&t[begin],size);
+ }
+ else
+ {
+
+ const T pivotvalue = t[begin];
+ ssize_t left = begin - 1;
+ ssize_t right = end + 1;
+
+ while(1)
+ {
+ while (t[--right] < pivotvalue);
+ while (t[++left] > pivotvalue);
+
+ if (left >= right) break;
+
+ const T temp = t[right];
+ t[right] = t[left];
+ t[left] = temp;
+ }
+
+ const ssize_t pivot = right;
+ quicksort_insertionsort_decending<T,THRESHOLD>(t, begin, pivot);
+ quicksort_insertionsort_decending<T,THRESHOLD>(t, pivot + 1, end);
+ }
+ }
+ }
+
+ template<typename T>
+ static void radixsort32(T* const morton, const size_t num, const unsigned int shift = 3*8)
+ {
+ static const unsigned int BITS = 8;
+ static const unsigned int BUCKETS = (1 << BITS);
+ static const unsigned int CMP_SORT_THRESHOLD = 16;
+
+ __aligned(64) unsigned int count[BUCKETS];
+
+ /* clear buckets */
+ for (size_t i=0;i<BUCKETS;i++) count[i] = 0;
+
+ /* count buckets */
+#if defined(__INTEL_COMPILER)
+#pragma nounroll
+#endif
+ for (size_t i=0;i<num;i++)
+ count[(unsigned(morton[i]) >> shift) & (BUCKETS-1)]++;
+
+ /* prefix sums */
+ __aligned(64) unsigned int head[BUCKETS];
+ __aligned(64) unsigned int tail[BUCKETS];
+
+ head[0] = 0;
+ for (size_t i=1; i<BUCKETS; i++)
+ head[i] = head[i-1] + count[i-1];
+
+ for (size_t i=0; i<BUCKETS-1; i++)
+ tail[i] = head[i+1];
+
+ tail[BUCKETS-1] = head[BUCKETS-1] + count[BUCKETS-1];
+
+ assert(tail[BUCKETS-1] == head[BUCKETS-1] + count[BUCKETS-1]);
+ assert(tail[BUCKETS-1] == num);
+
+ /* in-place swap */
+ for (size_t i=0;i<BUCKETS;i++)
+ {
+ /* process bucket */
+ while(head[i] < tail[i])
+ {
+ T v = morton[head[i]];
+ while(1)
+ {
+ const size_t b = (unsigned(v) >> shift) & (BUCKETS-1);
+ if (b == i) break;
+ std::swap(v,morton[head[b]++]);
+ }
+ assert((unsigned(v) >> shift & (BUCKETS-1)) == i);
+ morton[head[i]++] = v;
+ }
+ }
+ if (shift == 0) return;
+
+ size_t offset = 0;
+ for (size_t i=0;i<BUCKETS;i++)
+ if (count[i])
+ {
+
+ for (size_t j=offset;j<offset+count[i]-1;j++)
+ assert(((unsigned(morton[j]) >> shift) & (BUCKETS-1)) == i);
+
+ if (unlikely(count[i] < CMP_SORT_THRESHOLD))
+ insertionsort_ascending(morton + offset, count[i]);
+ else
+ radixsort32(morton + offset, count[i], shift-BITS);
+
+ for (size_t j=offset;j<offset+count[i]-1;j++)
+ assert(morton[j] <= morton[j+1]);
+
+ offset += count[i];
+ }
+ }
+
+ template<typename Ty, typename Key>
+ class ParallelRadixSort
+ {
+ static const size_t MAX_TASKS = 64;
+ static const size_t BITS = 8;
+ static const size_t BUCKETS = (1 << BITS);
+ typedef unsigned int TyRadixCount[BUCKETS];
+
+ template<typename T>
+ static bool compare(const T& v0, const T& v1) {
+ return (Key)v0 < (Key)v1;
+ }
+
+ private:
+ ParallelRadixSort (const ParallelRadixSort& other) DELETED; // do not implement
+ ParallelRadixSort& operator= (const ParallelRadixSort& other) DELETED; // do not implement
+
+
+ public:
+ ParallelRadixSort (Ty* const src, Ty* const tmp, const size_t N)
+ : radixCount(nullptr), src(src), tmp(tmp), N(N) {}
+
+ void sort(const size_t blockSize)
+ {
+ assert(blockSize > 0);
+
+ /* perform single threaded sort for small N */
+ if (N<=blockSize) // handles also special case of 0!
+ {
+ /* do inplace sort inside destination array */
+ std::sort(src,src+N,compare<Ty>);
+ }
+
+ /* perform parallel sort for large N */
+ else
+ {
+ const size_t numThreads = min((N+blockSize-1)/blockSize,TaskScheduler::threadCount(),size_t(MAX_TASKS));
+ tbbRadixSort(numThreads);
+ }
+ }
+
+ ~ParallelRadixSort()
+ {
+ alignedFree(radixCount);
+ radixCount = nullptr;
+ }
+
+ private:
+
+ void tbbRadixIteration0(const Key shift,
+ const Ty* __restrict const src,
+ Ty* __restrict const dst,
+ const size_t threadIndex, const size_t threadCount)
+ {
+ const size_t startID = (threadIndex+0)*N/threadCount;
+ const size_t endID = (threadIndex+1)*N/threadCount;
+
+ /* mask to extract some number of bits */
+ const Key mask = BUCKETS-1;
+
+ /* count how many items go into the buckets */
+ for (size_t i=0; i<BUCKETS; i++)
+ radixCount[threadIndex][i] = 0;
+
+ /* iterate over src array and count buckets */
+ unsigned int * __restrict const count = radixCount[threadIndex];
+#if defined(__INTEL_COMPILER)
+#pragma nounroll
+#endif
+ for (size_t i=startID; i<endID; i++) {
+#if defined(__64BIT__)
+ const size_t index = ((size_t)(Key)src[i] >> (size_t)shift) & (size_t)mask;
+#else
+ const Key index = ((Key)src[i] >> shift) & mask;
+#endif
+ count[index]++;
+ }
+ }
+
+ void tbbRadixIteration1(const Key shift,
+ const Ty* __restrict const src,
+ Ty* __restrict const dst,
+ const size_t threadIndex, const size_t threadCount)
+ {
+ const size_t startID = (threadIndex+0)*N/threadCount;
+ const size_t endID = (threadIndex+1)*N/threadCount;
+
+ /* mask to extract some number of bits */
+ const Key mask = BUCKETS-1;
+
+ /* calculate total number of items for each bucket */
+ __aligned(64) unsigned int total[BUCKETS];
+ /*
+ for (size_t i=0; i<BUCKETS; i++)
+ total[i] = 0;
+ */
+ for (size_t i=0; i<BUCKETS; i+=VSIZEX)
+ vintx::store(&total[i], zero);
+
+ for (size_t i=0; i<threadCount; i++)
+ {
+ /*
+ for (size_t j=0; j<BUCKETS; j++)
+ total[j] += radixCount[i][j];
+ */
+ for (size_t j=0; j<BUCKETS; j+=VSIZEX)
+ vintx::store(&total[j], vintx::load(&total[j]) + vintx::load(&radixCount[i][j]));
+ }
+
+ /* calculate start offset of each bucket */
+ __aligned(64) unsigned int offset[BUCKETS];
+ offset[0] = 0;
+ for (size_t i=1; i<BUCKETS; i++)
+ offset[i] = offset[i-1] + total[i-1];
+
+ /* calculate start offset of each bucket for this thread */
+ for (size_t i=0; i<threadIndex; i++)
+ {
+ /*
+ for (size_t j=0; j<BUCKETS; j++)
+ offset[j] += radixCount[i][j];
+ */
+ for (size_t j=0; j<BUCKETS; j+=VSIZEX)
+ vintx::store(&offset[j], vintx::load(&offset[j]) + vintx::load(&radixCount[i][j]));
+ }
+
+ /* copy items into their buckets */
+#if defined(__INTEL_COMPILER)
+#pragma nounroll
+#endif
+ for (size_t i=startID; i<endID; i++) {
+ const Ty elt = src[i];
+#if defined(__64BIT__)
+ const size_t index = ((size_t)(Key)src[i] >> (size_t)shift) & (size_t)mask;
+#else
+ const size_t index = ((Key)src[i] >> shift) & mask;
+#endif
+ dst[offset[index]++] = elt;
+ }
+ }
+
+ void tbbRadixIteration(const Key shift, const bool last,
+ const Ty* __restrict src, Ty* __restrict dst,
+ const size_t numTasks)
+ {
+ affinity_partitioner ap;
+ parallel_for_affinity(numTasks,[&] (size_t taskIndex) { tbbRadixIteration0(shift,src,dst,taskIndex,numTasks); },ap);
+ parallel_for_affinity(numTasks,[&] (size_t taskIndex) { tbbRadixIteration1(shift,src,dst,taskIndex,numTasks); },ap);
+ }
+
+ void tbbRadixSort(const size_t numTasks)
+ {
+ radixCount = (TyRadixCount*) alignedMalloc(MAX_TASKS*sizeof(TyRadixCount),64);
+
+ if (sizeof(Key) == sizeof(uint32_t)) {
+ tbbRadixIteration(0*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(1*BITS,0,tmp,src,numTasks);
+ tbbRadixIteration(2*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(3*BITS,1,tmp,src,numTasks);
+ }
+ else if (sizeof(Key) == sizeof(uint64_t))
+ {
+ tbbRadixIteration(0*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(1*BITS,0,tmp,src,numTasks);
+ tbbRadixIteration(2*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(3*BITS,0,tmp,src,numTasks);
+ tbbRadixIteration(4*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(5*BITS,0,tmp,src,numTasks);
+ tbbRadixIteration(6*BITS,0,src,tmp,numTasks);
+ tbbRadixIteration(7*BITS,1,tmp,src,numTasks);
+ }
+ }
+
+ private:
+ TyRadixCount* radixCount;
+ Ty* const src;
+ Ty* const tmp;
+ const size_t N;
+ };
+
+ template<typename Ty>
+ void radix_sort(Ty* const src, Ty* const tmp, const size_t N, const size_t blockSize = 8192)
+ {
+ ParallelRadixSort<Ty,Ty>(src,tmp,N).sort(blockSize);
+ }
+
+ template<typename Ty, typename Key>
+ void radix_sort(Ty* const src, Ty* const tmp, const size_t N, const size_t blockSize = 8192)
+ {
+ ParallelRadixSort<Ty,Key>(src,tmp,N).sort(blockSize);
+ }
+
+ template<typename Ty>
+ void radix_sort_u32(Ty* const src, Ty* const tmp, const size_t N, const size_t blockSize = 8192) {
+ radix_sort<Ty,uint32_t>(src,tmp,N,blockSize);
+ }
+
+ template<typename Ty>
+ void radix_sort_u64(Ty* const src, Ty* const tmp, const size_t N, const size_t blockSize = 8192) {
+ radix_sort<Ty,uint64_t>(src,tmp,N,blockSize);
+ }
+}
diff --git a/thirdparty/embree/common/lexers/parsestream.h b/thirdparty/embree/common/lexers/parsestream.h
new file mode 100644
index 0000000000..f65a52cb47
--- /dev/null
+++ b/thirdparty/embree/common/lexers/parsestream.h
@@ -0,0 +1,101 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "stringstream.h"
+#include "../sys/filename.h"
+#include "../math/vec2.h"
+#include "../math/vec3.h"
+#include "../math/col3.h"
+#include "../math/color.h"
+
+namespace embree
+{
+ /*! helper class for simple command line parsing */
+ class ParseStream : public Stream<std::string>
+ {
+ public:
+ ParseStream (const Ref<Stream<std::string> >& cin) : cin(cin) {}
+
+ ParseStream (const Ref<Stream<int> >& cin, const std::string& seps = "\n\t\r ",
+ const std::string& endl = "", bool multiLine = false)
+ : cin(new StringStream(cin,seps,endl,multiLine)) {}
+
+ public:
+ ParseLocation location() { return cin->loc(); }
+ std::string next() { return cin->get(); }
+
+ void force(const std::string& next) {
+ std::string token = getString();
+ if (token != next)
+ THROW_RUNTIME_ERROR("token \""+next+"\" expected but token \""+token+"\" found");
+ }
+
+ std::string getString() {
+ return get();
+ }
+
+ FileName getFileName() {
+ return FileName(get());
+ }
+
+ int getInt () {
+ return atoi(get().c_str());
+ }
+
+ Vec2i getVec2i() {
+ int x = atoi(get().c_str());
+ int y = atoi(get().c_str());
+ return Vec2i(x,y);
+ }
+
+ Vec3ia getVec3ia() {
+ int x = atoi(get().c_str());
+ int y = atoi(get().c_str());
+ int z = atoi(get().c_str());
+ return Vec3ia(x,y,z);
+ }
+
+ float getFloat() {
+ return (float)atof(get().c_str());
+ }
+
+ Vec2f getVec2f() {
+ float x = (float)atof(get().c_str());
+ float y = (float)atof(get().c_str());
+ return Vec2f(x,y);
+ }
+
+ Vec3f getVec3f() {
+ float x = (float)atof(get().c_str());
+ float y = (float)atof(get().c_str());
+ float z = (float)atof(get().c_str());
+ return Vec3f(x,y,z);
+ }
+
+ Vec3fa getVec3fa() {
+ float x = (float)atof(get().c_str());
+ float y = (float)atof(get().c_str());
+ float z = (float)atof(get().c_str());
+ return Vec3fa(x,y,z);
+ }
+
+ Col3f getCol3f() {
+ float x = (float)atof(get().c_str());
+ float y = (float)atof(get().c_str());
+ float z = (float)atof(get().c_str());
+ return Col3f(x,y,z);
+ }
+
+ Color getColor() {
+ float r = (float)atof(get().c_str());
+ float g = (float)atof(get().c_str());
+ float b = (float)atof(get().c_str());
+ return Color(r,g,b);
+ }
+
+ private:
+ Ref<Stream<std::string> > cin;
+ };
+}
diff --git a/thirdparty/embree/common/lexers/stream.h b/thirdparty/embree/common/lexers/stream.h
new file mode 100644
index 0000000000..a40c15f8eb
--- /dev/null
+++ b/thirdparty/embree/common/lexers/stream.h
@@ -0,0 +1,215 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/ref.h"
+#include "../sys/filename.h"
+#include "../sys/string.h"
+
+#include <vector>
+#include <iostream>
+#include <cstdio>
+#include <string.h>
+
+namespace embree
+{
+ /*! stores the location of a stream element in the source */
+ class ParseLocation
+ {
+ public:
+ ParseLocation () : lineNumber(-1), colNumber(-1) {}
+ ParseLocation (std::shared_ptr<std::string> fileName, ssize_t lineNumber, ssize_t colNumber, ssize_t /*charNumber*/)
+ : fileName(fileName), lineNumber(lineNumber), colNumber(colNumber) {}
+
+ std::string str() const
+ {
+ std::string str = "unknown";
+ if (fileName) str = *fileName;
+ if (lineNumber >= 0) str += " line " + toString(lineNumber);
+ if (lineNumber >= 0 && colNumber >= 0) str += " character " + toString(colNumber);
+ return str;
+ }
+
+ private:
+ std::shared_ptr<std::string> fileName; /// name of the file (or stream) the token is from
+ ssize_t lineNumber; /// the line number the token is from
+ ssize_t colNumber; /// the character number in the current line
+ };
+
+ /*! a stream class templated over the stream elements */
+ template<typename T> class Stream : public RefCount
+ {
+ enum { BUF_SIZE = 1024 };
+
+ private:
+ virtual T next() = 0;
+ virtual ParseLocation location() = 0;
+ __forceinline std::pair<T,ParseLocation> nextHelper() {
+ ParseLocation l = location();
+ T v = next();
+ return std::pair<T,ParseLocation>(v,l);
+ }
+ __forceinline void push_back(const std::pair<T,ParseLocation>& v) {
+ if (past+future == BUF_SIZE) pop_front();
+ size_t end = (start+past+future++)%BUF_SIZE;
+ buffer[end] = v;
+ }
+ __forceinline void pop_front() {
+ if (past == 0) THROW_RUNTIME_ERROR("stream buffer empty");
+ start = (start+1)%BUF_SIZE; past--;
+ }
+ public:
+ Stream () : start(0), past(0), future(0), buffer(BUF_SIZE) {}
+ virtual ~Stream() {}
+
+ public:
+
+ const ParseLocation& loc() {
+ if (future == 0) push_back(nextHelper());
+ return buffer[(start+past)%BUF_SIZE].second;
+ }
+ T get() {
+ if (future == 0) push_back(nextHelper());
+ T t = buffer[(start+past)%BUF_SIZE].first;
+ past++; future--;
+ return t;
+ }
+ const T& peek() {
+ if (future == 0) push_back(nextHelper());
+ return buffer[(start+past)%BUF_SIZE].first;
+ }
+ const T& unget(size_t n = 1) {
+ if (past < n) THROW_RUNTIME_ERROR ("cannot unget that many items");
+ past -= n; future += n;
+ return peek();
+ }
+ void drop() {
+ if (future == 0) push_back(nextHelper());
+ past++; future--;
+ }
+ private:
+ size_t start,past,future;
+ std::vector<std::pair<T,ParseLocation> > buffer;
+ };
+
+ /*! warps an iostream stream */
+ class StdStream : public Stream<int>
+ {
+ public:
+ StdStream (std::istream& cin, const std::string& name = "std::stream")
+ : cin(cin), lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) {}
+ ~StdStream() {}
+ ParseLocation location() {
+ return ParseLocation(name,lineNumber,colNumber,charNumber);
+ }
+ int next() {
+ int c = cin.get();
+ if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
+ charNumber++;
+ return c;
+ }
+ private:
+ std::istream& cin;
+ ssize_t lineNumber; /// the line number the token is from
+ ssize_t colNumber; /// the character number in the current line
+ ssize_t charNumber; /// the character in the file
+ std::shared_ptr<std::string> name; /// name of buffer
+ };
+
+ /*! creates a stream from a file */
+ class FileStream : public Stream<int>
+ {
+ public:
+
+ FileStream (FILE* file, const std::string& name = "file")
+ : file(file), lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) {}
+
+ FileStream (const FileName& fileName)
+ : lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(fileName.str())))
+ {
+ file = fopen(fileName.c_str(),"r");
+ if (file == nullptr) THROW_RUNTIME_ERROR("cannot open file " + fileName.str());
+ }
+ ~FileStream() { if (file) fclose(file); }
+
+ public:
+ ParseLocation location() {
+ return ParseLocation(name,lineNumber,colNumber,charNumber);
+ }
+
+ int next() {
+ int c = fgetc(file);
+ if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
+ charNumber++;
+ return c;
+ }
+
+ private:
+ FILE* file;
+ ssize_t lineNumber; /// the line number the token is from
+ ssize_t colNumber; /// the character number in the current line
+ ssize_t charNumber; /// the character in the file
+ std::shared_ptr<std::string> name; /// name of buffer
+ };
+
+ /*! creates a stream from a string */
+ class StrStream : public Stream<int>
+ {
+ public:
+
+ StrStream (const char* str)
+ : str(str), lineNumber(1), colNumber(0), charNumber(0) {}
+
+ public:
+ ParseLocation location() {
+ return ParseLocation(std::shared_ptr<std::string>(),lineNumber,colNumber,charNumber);
+ }
+
+ int next() {
+ int c = str[charNumber];
+ if (c == 0) return EOF;
+ if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
+ charNumber++;
+ return c;
+ }
+
+ private:
+ const char* str;
+ ssize_t lineNumber; /// the line number the token is from
+ ssize_t colNumber; /// the character number in the current line
+ ssize_t charNumber; /// the character in the file
+ };
+
+ /*! creates a character stream from a command line */
+ class CommandLineStream : public Stream<int>
+ {
+ public:
+ CommandLineStream (int argc, char** argv, const std::string& name = "command line")
+ : i(0), j(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name)))
+ {
+ if (argc > 0) {
+ for (size_t i=0; argv[0][i] && i<1024; i++) charNumber++;
+ charNumber++;
+ }
+ for (ssize_t k=1; k<argc; k++) args.push_back(argv[k]);
+ }
+ ~CommandLineStream() {}
+ public:
+ ParseLocation location() {
+ return ParseLocation(name,0,charNumber,charNumber);
+ }
+ int next() {
+ if (i == args.size()) return EOF;
+ if (j == args[i].size()) { i++; j=0; charNumber++; return ' '; }
+ charNumber++;
+ return args[i][j++];
+ }
+ private:
+ size_t i,j;
+ std::vector<std::string> args;
+ ssize_t charNumber; /// the character in the file
+ std::shared_ptr<std::string> name; /// name of buffer
+ };
+}
diff --git a/thirdparty/embree/common/lexers/streamfilters.h b/thirdparty/embree/common/lexers/streamfilters.h
new file mode 100644
index 0000000000..3592b77b03
--- /dev/null
+++ b/thirdparty/embree/common/lexers/streamfilters.h
@@ -0,0 +1,39 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "stream.h"
+
+namespace embree
+{
+ /* removes all line comments from a stream */
+ class LineCommentFilter : public Stream<int>
+ {
+ public:
+ LineCommentFilter (const FileName& fileName, const std::string& lineComment)
+ : cin(new FileStream(fileName)), lineComment(lineComment) {}
+ LineCommentFilter (Ref<Stream<int> > cin, const std::string& lineComment)
+ : cin(cin), lineComment(lineComment) {}
+
+ ParseLocation location() { return cin->loc(); }
+
+ int next()
+ {
+ /* look if the line comment starts here */
+ for (size_t j=0; j<lineComment.size(); j++) {
+ if (cin->peek() != lineComment[j]) { cin->unget(j); goto not_found; }
+ cin->get();
+ }
+ /* eat all characters until the end of the line (or file) */
+ while (cin->peek() != '\n' && cin->peek() != EOF) cin->get();
+
+ not_found:
+ return cin->get();
+ }
+
+ private:
+ Ref<Stream<int> > cin;
+ std::string lineComment;
+ };
+}
diff --git a/thirdparty/embree/common/lexers/stringstream.cpp b/thirdparty/embree/common/lexers/stringstream.cpp
new file mode 100644
index 0000000000..a037869506
--- /dev/null
+++ b/thirdparty/embree/common/lexers/stringstream.cpp
@@ -0,0 +1,51 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "stringstream.h"
+
+namespace embree
+{
+ static const std::string stringChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 _.,+-=:/*\\";
+
+ /* creates map for fast categorization of characters */
+ static void createCharMap(bool map[256], const std::string& chrs) {
+ for (size_t i=0; i<256; i++) map[i] = false;
+ for (size_t i=0; i<chrs.size(); i++) map[uint8_t(chrs[i])] = true;
+ }
+
+ /* simple tokenizer */
+ StringStream::StringStream(const Ref<Stream<int> >& cin, const std::string& seps, const std::string& endl, bool multiLine)
+ : cin(cin), endl(endl), multiLine(multiLine)
+ {
+ createCharMap(isSepMap,seps);
+ createCharMap(isValidCharMap,stringChars);
+ }
+
+ std::string StringStream::next()
+ {
+ /* skip separators */
+ while (cin->peek() != EOF) {
+ if (endl != "" && cin->peek() == '\n') { cin->drop(); return endl; }
+ if (multiLine && cin->peek() == '\\') {
+ cin->drop();
+ if (cin->peek() == '\n') { cin->drop(); continue; }
+ cin->unget();
+ }
+ if (!isSeparator(cin->peek())) break;
+ cin->drop();
+ }
+
+ /* parse everything until the next separator */
+ std::vector<char> str; str.reserve(64);
+ while (cin->peek() != EOF && !isSeparator(cin->peek())) {
+ int c = cin->get();
+ // -- GODOT start --
+ // if (!isValidChar(c)) throw std::runtime_error("invalid character "+std::string(1,c)+" in input");
+ if (!isValidChar(c)) abort();
+ // -- GODOT end --
+ str.push_back((char)c);
+ }
+ str.push_back(0);
+ return std::string(str.data());
+ }
+}
diff --git a/thirdparty/embree/common/lexers/stringstream.h b/thirdparty/embree/common/lexers/stringstream.h
new file mode 100644
index 0000000000..6d9c27e3cd
--- /dev/null
+++ b/thirdparty/embree/common/lexers/stringstream.h
@@ -0,0 +1,29 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "stream.h"
+
+namespace embree
+{
+ /*! simple tokenizer that produces a string stream */
+ class StringStream : public Stream<std::string>
+ {
+ public:
+ StringStream(const Ref<Stream<int> >& cin, const std::string& seps = "\n\t\r ",
+ const std::string& endl = "", bool multiLine = false);
+ public:
+ ParseLocation location() { return cin->loc(); }
+ std::string next();
+ private:
+ __forceinline bool isSeparator(unsigned int c) const { return c<256 && isSepMap[c]; }
+ __forceinline bool isValidChar(unsigned int c) const { return c<256 && isValidCharMap[c]; }
+ private:
+ Ref<Stream<int> > cin; /*! source character stream */
+ bool isSepMap[256]; /*! map for fast classification of separators */
+ bool isValidCharMap[256]; /*! map for valid characters */
+ std::string endl; /*! the token of the end of line */
+ bool multiLine; /*! whether to parse lines wrapped with \ */
+ };
+}
diff --git a/thirdparty/embree/common/lexers/tokenstream.cpp b/thirdparty/embree/common/lexers/tokenstream.cpp
new file mode 100644
index 0000000000..6ed6f2045a
--- /dev/null
+++ b/thirdparty/embree/common/lexers/tokenstream.cpp
@@ -0,0 +1,181 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "tokenstream.h"
+#include "../math/math.h"
+
+namespace embree
+{
+ /* shorthands for common sets of characters */
+ const std::string TokenStream::alpha = "abcdefghijklmnopqrstuvwxyz";
+ const std::string TokenStream::ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ const std::string TokenStream::numbers = "0123456789";
+ const std::string TokenStream::separators = "\n\t\r ";
+ const std::string TokenStream::stringChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 _.,+-=:/*\\";
+
+ /* creates map for fast categorization of characters */
+ static void createCharMap(bool map[256], const std::string& chrs) {
+ for (size_t i=0; i<256; i++) map[i] = false;
+ for (size_t i=0; i<chrs.size(); i++) map[uint8_t(chrs[i])] = true;
+ }
+
+ /* build full tokenizer that takes list of valid characters and keywords */
+ TokenStream::TokenStream(const Ref<Stream<int> >& cin, //< stream to read from
+ const std::string& alpha, //< valid characters for identifiers
+ const std::string& seps, //< characters that act as separators
+ const std::vector<std::string>& symbols) //< symbols
+ : cin(cin), symbols(symbols)
+ {
+ createCharMap(isAlphaMap,alpha);
+ createCharMap(isSepMap,seps);
+ createCharMap(isStringCharMap,stringChars);
+ }
+
+ bool TokenStream::decDigits(std::string& str_o)
+ {
+ bool ok = false;
+ std::string str;
+ if (cin->peek() == '+' || cin->peek() == '-') str += (char)cin->get();
+ while (isDigit(cin->peek())) { ok = true; str += (char)cin->get(); }
+ if (ok) str_o += str;
+ else cin->unget(str.size());
+ return ok;
+ }
+
+ bool TokenStream::decDigits1(std::string& str_o)
+ {
+ bool ok = false;
+ std::string str;
+ while (isDigit(cin->peek())) { ok = true; str += (char)cin->get(); }
+ if (ok) str_o += str; else cin->unget(str.size());
+ return ok;
+ }
+
+ bool TokenStream::trySymbol(const std::string& symbol)
+ {
+ size_t pos = 0;
+ while (pos < symbol.size()) {
+ if (symbol[pos] != cin->peek()) { cin->unget(pos); return false; }
+ cin->drop(); pos++;
+ }
+ return true;
+ }
+
+ bool TokenStream::trySymbols(Token& token, const ParseLocation& loc)
+ {
+ for (size_t i=0; i<symbols.size(); i++) {
+ if (!trySymbol(symbols[i])) continue;
+ token = Token(symbols[i],Token::TY_SYMBOL,loc);
+ return true;
+ }
+ return false;
+ }
+
+ bool TokenStream::tryFloat(Token& token, const ParseLocation& loc)
+ {
+ bool ok = false;
+ std::string str;
+ if (trySymbol("nan")) {
+ token = Token(float(nan));
+ return true;
+ }
+ if (trySymbol("+inf")) {
+ token = Token(float(pos_inf));
+ return true;
+ }
+ if (trySymbol("-inf")) {
+ token = Token(float(neg_inf));
+ return true;
+ }
+
+ if (decDigits(str))
+ {
+ if (cin->peek() == '.') {
+ str += (char)cin->get();
+ decDigits(str);
+ if (cin->peek() == 'e' || cin->peek() == 'E') {
+ str += (char)cin->get();
+ if (decDigits(str)) ok = true; // 1.[2]E2
+ }
+ else ok = true; // 1.[2]
+ }
+ else if (cin->peek() == 'e' || cin->peek() == 'E') {
+ str += (char)cin->get();
+ if (decDigits(str)) ok = true; // 1E2
+ }
+ }
+ else
+ {
+ if (cin->peek() == '.') {
+ str += (char)cin->get();
+ if (decDigits(str)) {
+ if (cin->peek() == 'e' || cin->peek() == 'E') {
+ str += (char)cin->get();
+ if (decDigits(str)) ok = true; // .3E2
+ }
+ else ok = true; // .3
+ }
+ }
+ }
+ if (ok) {
+ token = Token((float)atof(str.c_str()),loc);
+ }
+ else cin->unget(str.size());
+ return ok;
+ }
+
+ bool TokenStream::tryInt(Token& token, const ParseLocation& loc) {
+ std::string str;
+ if (decDigits(str)) {
+ token = Token(atoi(str.c_str()),loc);
+ return true;
+ }
+ return false;
+ }
+
+ bool TokenStream::tryString(Token& token, const ParseLocation& loc)
+ {
+ std::string str;
+ if (cin->peek() != '\"') return false;
+ cin->drop();
+ while (cin->peek() != '\"') {
+ const int c = cin->get();
+ if (!isStringChar(c)) THROW_RUNTIME_ERROR("invalid string character "+std::string(1,c)+" at "+loc.str());
+ str += (char)c;
+ }
+ cin->drop();
+ token = Token(str,Token::TY_STRING,loc);
+ return true;
+ }
+
+ bool TokenStream::tryIdentifier(Token& token, const ParseLocation& loc)
+ {
+ std::string str;
+ if (!isAlpha(cin->peek())) return false;
+ str += (char)cin->get();
+ while (isAlphaNum(cin->peek())) str += (char)cin->get();
+ token = Token(str,Token::TY_IDENTIFIER,loc);
+ return true;
+ }
+
+ void TokenStream::skipSeparators()
+ {
+ /* skip separators */
+ while (cin->peek() != EOF && isSeparator(cin->peek()))
+ cin->drop();
+ }
+
+ Token TokenStream::next()
+ {
+ Token token;
+ skipSeparators();
+ ParseLocation loc = cin->loc();
+ if (trySymbols (token,loc)) return token; /**< try to parse a symbol */
+ if (tryFloat (token,loc)) return token; /**< try to parse float */
+ if (tryInt (token,loc)) return token; /**< try to parse integer */
+ if (tryString (token,loc)) return token; /**< try to parse string */
+ if (tryIdentifier(token,loc)) return token; /**< try to parse identifier */
+ if (cin->peek() == EOF ) return Token(loc); /**< return EOF token */
+ return Token((char)cin->get(),loc); /**< return invalid character token */
+ }
+}
diff --git a/thirdparty/embree/common/lexers/tokenstream.h b/thirdparty/embree/common/lexers/tokenstream.h
new file mode 100644
index 0000000000..6e49dd0b39
--- /dev/null
+++ b/thirdparty/embree/common/lexers/tokenstream.h
@@ -0,0 +1,164 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "stream.h"
+#include <string>
+#include <vector>
+
+namespace embree
+{
+ /*! token class */
+ class Token
+ {
+ public:
+
+ enum Type { TY_EOF, TY_CHAR, TY_INT, TY_FLOAT, TY_IDENTIFIER, TY_STRING, TY_SYMBOL };
+
+ Token ( const ParseLocation& loc = ParseLocation()) : ty(TY_EOF ), loc(loc) {}
+ Token (char c, const ParseLocation& loc = ParseLocation()) : ty(TY_CHAR ), c(c), loc(loc) {}
+ Token (int i, const ParseLocation& loc = ParseLocation()) : ty(TY_INT ), i(i), loc(loc) {}
+ Token (float f,const ParseLocation& loc = ParseLocation()) : ty(TY_FLOAT), f(f), loc(loc) {}
+ Token (std::string str, Type ty, const ParseLocation& loc = ParseLocation()) : ty(ty), str(str), loc(loc) {}
+
+ static Token Eof() { return Token(); }
+ static Token Sym(std::string str) { return Token(str,TY_SYMBOL); }
+ static Token Str(std::string str) { return Token(str,TY_STRING); }
+ static Token Id (std::string str) { return Token(str,TY_IDENTIFIER); }
+
+ char Char() const {
+ if (ty == TY_CHAR) return c;
+ THROW_RUNTIME_ERROR(loc.str()+": character expected");
+ }
+
+ int Int() const {
+ if (ty == TY_INT) return i;
+ THROW_RUNTIME_ERROR(loc.str()+": integer expected");
+ }
+
+ float Float(bool cast = true) const {
+ if (ty == TY_FLOAT) return f;
+ if (ty == TY_INT && cast) return (float)i;
+ THROW_RUNTIME_ERROR(loc.str()+": float expected");
+ }
+
+ std::string Identifier() const {
+ if (ty == TY_IDENTIFIER) return str;
+ THROW_RUNTIME_ERROR(loc.str()+": identifier expected");
+ }
+
+ std::string String() const {
+ if (ty == TY_STRING) return str;
+ THROW_RUNTIME_ERROR(loc.str()+": string expected");
+ }
+
+ std::string Symbol() const {
+ if (ty == TY_SYMBOL) return str;
+ THROW_RUNTIME_ERROR(loc.str()+": symbol expected");
+ }
+
+ const ParseLocation& Location() const { return loc; }
+
+ friend bool operator==(const Token& a, const Token& b)
+ {
+ if (a.ty != b.ty) return false;
+ if (a.ty == TY_CHAR) return a.c == b.c;
+ if (a.ty == TY_INT) return a.i == b.i;
+ if (a.ty == TY_FLOAT) return a.f == b.f;
+ if (a.ty == TY_IDENTIFIER) return a.str == b.str;
+ if (a.ty == TY_STRING) return a.str == b.str;
+ if (a.ty == TY_SYMBOL) return a.str == b.str;
+ return true;
+ }
+
+ friend bool operator!=(const Token& a, const Token& b) {
+ return !(a == b);
+ }
+
+ friend bool operator <( const Token& a, const Token& b ) {
+ if (a.ty != b.ty) return (int)a.ty < (int)b.ty;
+ if (a.ty == TY_CHAR) return a.c < b.c;
+ if (a.ty == TY_INT) return a.i < b.i;
+ if (a.ty == TY_FLOAT) return a.f < b.f;
+ if (a.ty == TY_IDENTIFIER) return a.str < b.str;
+ if (a.ty == TY_STRING) return a.str < b.str;
+ if (a.ty == TY_SYMBOL) return a.str < b.str;
+ return false;
+ }
+
+ friend std::ostream& operator<<(std::ostream& cout, const Token& t)
+ {
+ if (t.ty == TY_EOF) return cout << "eof";
+ if (t.ty == TY_CHAR) return cout << "Char(" << t.c << ")";
+ if (t.ty == TY_INT) return cout << "Int(" << t.i << ")";
+ if (t.ty == TY_FLOAT) return cout << "Float(" << t.f << ")";
+ if (t.ty == TY_IDENTIFIER) return cout << "Id(" << t.str << ")";
+ if (t.ty == TY_STRING) return cout << "String(" << t.str << ")";
+ if (t.ty == TY_SYMBOL) return cout << "Symbol(" << t.str << ")";
+ return cout << "unknown";
+ }
+
+ private:
+ Type ty; //< the type of the token
+ union {
+ char c; //< data for char tokens
+ int i; //< data for int tokens
+ float f; //< data for float tokens
+ };
+ std::string str; //< data for string and identifier tokens
+ ParseLocation loc; //< the location the token is from
+ };
+
+ /*! build full tokenizer that takes list of valid characters and keywords */
+ class TokenStream : public Stream<Token>
+ {
+ public:
+
+ /*! shorthands for common sets of characters */
+ static const std::string alpha;
+ static const std::string ALPHA;
+ static const std::string numbers;
+ static const std::string separators;
+ static const std::string stringChars;
+
+ public:
+ TokenStream(const Ref<Stream<int> >& cin,
+ const std::string& alpha, //< valid characters for identifiers
+ const std::string& seps, //< characters that act as separators
+ const std::vector<std::string>& symbols = std::vector<std::string>()); //< symbols
+ public:
+ ParseLocation location() { return cin->loc(); }
+ Token next();
+ bool trySymbol(const std::string& symbol);
+
+ private:
+ void skipSeparators();
+ bool decDigits(std::string& str);
+ bool decDigits1(std::string& str);
+ bool trySymbols(Token& token, const ParseLocation& loc);
+ bool tryFloat(Token& token, const ParseLocation& loc);
+ bool tryInt(Token& token, const ParseLocation& loc);
+ bool tryString(Token& token, const ParseLocation& loc);
+ bool tryIdentifier(Token& token, const ParseLocation& loc);
+
+ Ref<Stream<int> > cin;
+ bool isSepMap[256];
+ bool isAlphaMap[256];
+ bool isStringCharMap[256];
+ std::vector<std::string> symbols;
+
+ /*! checks if a character is a separator */
+ __forceinline bool isSeparator(unsigned int c) const { return c<256 && isSepMap[c]; }
+
+ /*! checks if a character is a number */
+ __forceinline bool isDigit(unsigned int c) const { return c >= '0' && c <= '9'; }
+
+ /*! checks if a character is valid inside a string */
+ __forceinline bool isStringChar(unsigned int c) const { return c<256 && isStringCharMap[c]; }
+
+ /*! checks if a character is legal for an identifier */
+ __forceinline bool isAlpha(unsigned int c) const { return c<256 && isAlphaMap[c]; }
+ __forceinline bool isAlphaNum(unsigned int c) const { return isAlpha(c) || isDigit(c); }
+ };
+}
diff --git a/thirdparty/embree/common/math/affinespace.h b/thirdparty/embree/common/math/affinespace.h
new file mode 100644
index 0000000000..9d4a0f0846
--- /dev/null
+++ b/thirdparty/embree/common/math/affinespace.h
@@ -0,0 +1,361 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "linearspace2.h"
+#include "linearspace3.h"
+#include "quaternion.h"
+#include "bbox.h"
+#include "vec4.h"
+
+namespace embree
+{
+ #define VectorT typename L::Vector
+ #define ScalarT typename L::Vector::Scalar
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Affine Space
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L>
+ struct AffineSpaceT
+ {
+ L l; /*< linear part of affine space */
+ VectorT p; /*< affine part of affine space */
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Constructors, Assignment, Cast, Copy Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline AffineSpaceT ( ) { }
+ __forceinline AffineSpaceT ( const AffineSpaceT& other ) { l = other.l; p = other.p; }
+ __forceinline AffineSpaceT ( const L & other ) { l = other ; p = VectorT(zero); }
+ __forceinline AffineSpaceT& operator=( const AffineSpaceT& other ) { l = other.l; p = other.p; return *this; }
+
+ __forceinline AffineSpaceT( const VectorT& vx, const VectorT& vy, const VectorT& vz, const VectorT& p ) : l(vx,vy,vz), p(p) {}
+ __forceinline AffineSpaceT( const L& l, const VectorT& p ) : l(l), p(p) {}
+
+ template<typename L1> __forceinline AffineSpaceT( const AffineSpaceT<L1>& s ) : l(s.l), p(s.p) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline AffineSpaceT( ZeroTy ) : l(zero), p(zero) {}
+ __forceinline AffineSpaceT( OneTy ) : l(one), p(zero) {}
+
+ /*! return matrix for scaling */
+ static __forceinline AffineSpaceT scale(const VectorT& s) { return L::scale(s); }
+
+ /*! return matrix for translation */
+ static __forceinline AffineSpaceT translate(const VectorT& p) { return AffineSpaceT(one,p); }
+
+ /*! return matrix for rotation, only in 2D */
+ static __forceinline AffineSpaceT rotate(const ScalarT& r) { return L::rotate(r); }
+
+ /*! return matrix for rotation around arbitrary point (2D) or axis (3D) */
+ static __forceinline AffineSpaceT rotate(const VectorT& u, const ScalarT& r) { return L::rotate(u,r); }
+
+ /*! return matrix for rotation around arbitrary axis and point, only in 3D */
+ static __forceinline AffineSpaceT rotate(const VectorT& p, const VectorT& u, const ScalarT& r) { return translate(+p) * rotate(u,r) * translate(-p); }
+
+ /*! return matrix for looking at given point, only in 3D */
+ static __forceinline AffineSpaceT lookat(const VectorT& eye, const VectorT& point, const VectorT& up) {
+ VectorT Z = normalize(point-eye);
+ VectorT U = normalize(cross(up,Z));
+ VectorT V = normalize(cross(Z,U));
+ return AffineSpaceT(L(U,V,Z),eye);
+ }
+
+ };
+
+ // template specialization to get correct identity matrix for type AffineSpace3fa
+ template<>
+ __forceinline AffineSpaceT<LinearSpace3ff>::AffineSpaceT( OneTy ) : l(one), p(0.f, 0.f, 0.f, 1.f) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L> __forceinline AffineSpaceT<L> operator -( const AffineSpaceT<L>& a ) { return AffineSpaceT<L>(-a.l,-a.p); }
+ template<typename L> __forceinline AffineSpaceT<L> operator +( const AffineSpaceT<L>& a ) { return AffineSpaceT<L>(+a.l,+a.p); }
+ template<typename L> __forceinline AffineSpaceT<L> rcp( const AffineSpaceT<L>& a ) { L il = rcp(a.l); return AffineSpaceT<L>(il,-(il*a.p)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L> __forceinline const AffineSpaceT<L> operator +( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return AffineSpaceT<L>(a.l+b.l,a.p+b.p); }
+ template<typename L> __forceinline const AffineSpaceT<L> operator -( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return AffineSpaceT<L>(a.l-b.l,a.p-b.p); }
+
+ template<typename L> __forceinline const AffineSpaceT<L> operator *( const ScalarT & a, const AffineSpaceT<L>& b ) { return AffineSpaceT<L>(a*b.l,a*b.p); }
+ template<typename L> __forceinline const AffineSpaceT<L> operator *( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return AffineSpaceT<L>(a.l*b.l,a.l*b.p+a.p); }
+ template<typename L> __forceinline const AffineSpaceT<L> operator /( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return a * rcp(b); }
+ template<typename L> __forceinline const AffineSpaceT<L> operator /( const AffineSpaceT<L>& a, const ScalarT & b ) { return a * rcp(b); }
+
+ template<typename L> __forceinline AffineSpaceT<L>& operator *=( AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return a = a * b; }
+ template<typename L> __forceinline AffineSpaceT<L>& operator *=( AffineSpaceT<L>& a, const ScalarT & b ) { return a = a * b; }
+ template<typename L> __forceinline AffineSpaceT<L>& operator /=( AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return a = a / b; }
+ template<typename L> __forceinline AffineSpaceT<L>& operator /=( AffineSpaceT<L>& a, const ScalarT & b ) { return a = a / b; }
+
+ template<typename L> __forceinline VectorT xfmPoint (const AffineSpaceT<L>& m, const VectorT& p) { return madd(VectorT(p.x),m.l.vx,madd(VectorT(p.y),m.l.vy,madd(VectorT(p.z),m.l.vz,m.p))); }
+ template<typename L> __forceinline VectorT xfmVector(const AffineSpaceT<L>& m, const VectorT& v) { return xfmVector(m.l,v); }
+ template<typename L> __forceinline VectorT xfmNormal(const AffineSpaceT<L>& m, const VectorT& n) { return xfmNormal(m.l,n); }
+
+ __forceinline const BBox<Vec3fa> xfmBounds(const AffineSpaceT<LinearSpace3<Vec3fa> >& m, const BBox<Vec3fa>& b)
+ {
+ BBox3fa dst = empty;
+ const Vec3fa p0(b.lower.x,b.lower.y,b.lower.z); dst.extend(xfmPoint(m,p0));
+ const Vec3fa p1(b.lower.x,b.lower.y,b.upper.z); dst.extend(xfmPoint(m,p1));
+ const Vec3fa p2(b.lower.x,b.upper.y,b.lower.z); dst.extend(xfmPoint(m,p2));
+ const Vec3fa p3(b.lower.x,b.upper.y,b.upper.z); dst.extend(xfmPoint(m,p3));
+ const Vec3fa p4(b.upper.x,b.lower.y,b.lower.z); dst.extend(xfmPoint(m,p4));
+ const Vec3fa p5(b.upper.x,b.lower.y,b.upper.z); dst.extend(xfmPoint(m,p5));
+ const Vec3fa p6(b.upper.x,b.upper.y,b.lower.z); dst.extend(xfmPoint(m,p6));
+ const Vec3fa p7(b.upper.x,b.upper.y,b.upper.z); dst.extend(xfmPoint(m,p7));
+ return dst;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L> __forceinline bool operator ==( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return a.l == b.l && a.p == b.p; }
+ template<typename L> __forceinline bool operator !=( const AffineSpaceT<L>& a, const AffineSpaceT<L>& b ) { return a.l != b.l || a.p != b.p; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L> __forceinline AffineSpaceT<L> select ( const typename L::Vector::Scalar::Bool& s, const AffineSpaceT<L>& t, const AffineSpaceT<L>& f ) {
+ return AffineSpaceT<L>(select(s,t.l,f.l),select(s,t.p,f.p));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename L> static embree_ostream operator<<(embree_ostream cout, const AffineSpaceT<L>& m) {
+ return cout << "{ l = " << m.l << ", p = " << m.p << " }";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Template Instantiations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ typedef AffineSpaceT<LinearSpace2f> AffineSpace2f;
+ typedef AffineSpaceT<LinearSpace3f> AffineSpace3f;
+ typedef AffineSpaceT<LinearSpace3fa> AffineSpace3fa;
+ typedef AffineSpaceT<LinearSpace3fx> AffineSpace3fx;
+ typedef AffineSpaceT<LinearSpace3ff> AffineSpace3ff;
+ typedef AffineSpaceT<Quaternion3f > OrthonormalSpace3f;
+
+ template<int N> using AffineSpace3vf = AffineSpaceT<LinearSpace3<Vec3<vfloat<N>>>>;
+ typedef AffineSpaceT<LinearSpace3<Vec3<vfloat<4>>>> AffineSpace3vf4;
+ typedef AffineSpaceT<LinearSpace3<Vec3<vfloat<8>>>> AffineSpace3vf8;
+ typedef AffineSpaceT<LinearSpace3<Vec3<vfloat<16>>>> AffineSpace3vf16;
+
+ template<int N> using AffineSpace3vff = AffineSpaceT<LinearSpace3<Vec4<vfloat<N>>>>;
+ typedef AffineSpaceT<LinearSpace3<Vec4<vfloat<4>>>> AffineSpace3vfa4;
+ typedef AffineSpaceT<LinearSpace3<Vec4<vfloat<8>>>> AffineSpace3vfa8;
+ typedef AffineSpaceT<LinearSpace3<Vec4<vfloat<16>>>> AffineSpace3vfa16;
+
+ //////////////////////////////////////////////////////////////////////////////
+ /// Interpolation
+ //////////////////////////////////////////////////////////////////////////////
+ template<typename T, typename R>
+ __forceinline AffineSpaceT<T> lerp(const AffineSpaceT<T>& M0,
+ const AffineSpaceT<T>& M1,
+ const R& t)
+ {
+ return AffineSpaceT<T>(lerp(M0.l,M1.l,t),lerp(M0.p,M1.p,t));
+ }
+
+ // slerp interprets the 16 floats of the matrix M = D * R * S as components of
+ // three matrizes (D, R, S) that are interpolated individually.
+ template<typename T> __forceinline AffineSpaceT<LinearSpace3<Vec3<T>>>
+ slerp(const AffineSpaceT<LinearSpace3<Vec4<T>>>& M0,
+ const AffineSpaceT<LinearSpace3<Vec4<T>>>& M1,
+ const T& t)
+ {
+ QuaternionT<T> q0(M0.p.w, M0.l.vx.w, M0.l.vy.w, M0.l.vz.w);
+ QuaternionT<T> q1(M1.p.w, M1.l.vx.w, M1.l.vy.w, M1.l.vz.w);
+ QuaternionT<T> q = slerp(q0, q1, t);
+
+ AffineSpaceT<LinearSpace3<Vec3<T>>> S = lerp(M0, M1, t);
+ AffineSpaceT<LinearSpace3<Vec3<T>>> D(one);
+ D.p.x = S.l.vx.y;
+ D.p.y = S.l.vx.z;
+ D.p.z = S.l.vy.z;
+ S.l.vx.y = 0;
+ S.l.vx.z = 0;
+ S.l.vy.z = 0;
+
+ AffineSpaceT<LinearSpace3<Vec3<T>>> R = LinearSpace3<Vec3<T>>(q);
+ return D * R * S;
+ }
+
+ // this is a specialized version for Vec3fa because that does
+ // not play along nicely with the other templated Vec3/Vec4 types
+ __forceinline AffineSpace3fa slerp(const AffineSpace3ff& M0,
+ const AffineSpace3ff& M1,
+ const float& t)
+ {
+ Quaternion3f q0(M0.p.w, M0.l.vx.w, M0.l.vy.w, M0.l.vz.w);
+ Quaternion3f q1(M1.p.w, M1.l.vx.w, M1.l.vy.w, M1.l.vz.w);
+ Quaternion3f q = slerp(q0, q1, t);
+
+ AffineSpace3fa S = lerp(M0, M1, t);
+ AffineSpace3fa D(one);
+ D.p.x = S.l.vx.y;
+ D.p.y = S.l.vx.z;
+ D.p.z = S.l.vy.z;
+ S.l.vx.y = 0;
+ S.l.vx.z = 0;
+ S.l.vy.z = 0;
+
+ AffineSpace3fa R = LinearSpace3fa(q);
+ return D * R * S;
+ }
+
+ __forceinline AffineSpace3fa quaternionDecompositionToAffineSpace(const AffineSpace3ff& qd)
+ {
+ // compute affine transform from quaternion decomposition
+ Quaternion3f q(qd.p.w, qd.l.vx.w, qd.l.vy.w, qd.l.vz.w);
+ AffineSpace3fa M = qd;
+ AffineSpace3fa D(one);
+ D.p.x = M.l.vx.y;
+ D.p.y = M.l.vx.z;
+ D.p.z = M.l.vy.z;
+ M.l.vx.y = 0;
+ M.l.vx.z = 0;
+ M.l.vy.z = 0;
+ AffineSpace3fa R = LinearSpace3fa(q);
+ return D * R * M;
+ }
+
+ __forceinline void quaternionDecomposition(const AffineSpace3ff& qd, Vec3fa& T, Quaternion3f& q, AffineSpace3fa& S)
+ {
+ q = Quaternion3f(qd.p.w, qd.l.vx.w, qd.l.vy.w, qd.l.vz.w);
+ S = qd;
+ T.x = qd.l.vx.y;
+ T.y = qd.l.vx.z;
+ T.z = qd.l.vy.z;
+ S.l.vx.y = 0;
+ S.l.vx.z = 0;
+ S.l.vy.z = 0;
+ }
+
+ __forceinline AffineSpace3fx quaternionDecomposition(Vec3fa const& T, Quaternion3f const& q, AffineSpace3fa const& S)
+ {
+ AffineSpace3ff M = S;
+ M.l.vx.w = q.i;
+ M.l.vy.w = q.j;
+ M.l.vz.w = q.k;
+ M.p.w = q.r;
+ M.l.vx.y = T.x;
+ M.l.vx.z = T.y;
+ M.l.vy.z = T.z;
+ return M;
+ }
+
+ struct __aligned(16) QuaternionDecomposition
+ {
+ float scale_x = 1.f;
+ float scale_y = 1.f;
+ float scale_z = 1.f;
+ float skew_xy = 0.f;
+ float skew_xz = 0.f;
+ float skew_yz = 0.f;
+ float shift_x = 0.f;
+ float shift_y = 0.f;
+ float shift_z = 0.f;
+ float quaternion_r = 1.f;
+ float quaternion_i = 0.f;
+ float quaternion_j = 0.f;
+ float quaternion_k = 0.f;
+ float translation_x = 0.f;
+ float translation_y = 0.f;
+ float translation_z = 0.f;
+ };
+
+ __forceinline QuaternionDecomposition quaternionDecomposition(AffineSpace3ff const& M)
+ {
+ QuaternionDecomposition qd;
+ qd.scale_x = M.l.vx.x;
+ qd.scale_y = M.l.vy.y;
+ qd.scale_z = M.l.vz.z;
+ qd.shift_x = M.p.x;
+ qd.shift_y = M.p.y;
+ qd.shift_z = M.p.z;
+ qd.translation_x = M.l.vx.y;
+ qd.translation_y = M.l.vx.z;
+ qd.translation_z = M.l.vy.z;
+ qd.skew_xy = M.l.vy.x;
+ qd.skew_xz = M.l.vz.x;
+ qd.skew_yz = M.l.vz.y;
+ qd.quaternion_r = M.p.w;
+ qd.quaternion_i = M.l.vx.w;
+ qd.quaternion_j = M.l.vy.w;
+ qd.quaternion_k = M.l.vz.w;
+ return qd;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /*
+ * ! Template Specialization for 2D: return matrix for rotation around point
+ * (rotation around arbitrarty vector is not meaningful in 2D)
+ */
+ template<> __forceinline
+ AffineSpace2f AffineSpace2f::rotate(const Vec2f& p, const float& r) {
+ return translate(+p)*AffineSpace2f(LinearSpace2f::rotate(r))*translate(-p);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Similarity Transform
+ //
+ // checks, if M is a similarity transformation, i.e if there exists a factor D
+ // such that for all x,y: distance(Mx, My) = D * distance(x, y)
+ ////////////////////////////////////////////////////////////////////////////////
+ __forceinline bool similarityTransform(const AffineSpace3fa& M, float* D)
+ {
+ if (D) *D = 0.f;
+ if (abs(dot(M.l.vx, M.l.vy)) > 1e-5f) return false;
+ if (abs(dot(M.l.vx, M.l.vz)) > 1e-5f) return false;
+ if (abs(dot(M.l.vy, M.l.vz)) > 1e-5f) return false;
+
+ const float D_x = dot(M.l.vx, M.l.vx);
+ const float D_y = dot(M.l.vy, M.l.vy);
+ const float D_z = dot(M.l.vz, M.l.vz);
+
+ if (abs(D_x - D_y) > 1e-5f ||
+ abs(D_x - D_z) > 1e-5f ||
+ abs(D_y - D_z) > 1e-5f)
+ return false;
+
+ if (D) *D = sqrtf(D_x);
+ return true;
+ }
+
+ __forceinline void AffineSpace3fa_store_unaligned(const AffineSpace3fa &source, AffineSpace3fa* ptr)
+ {
+ Vec3fa::storeu(&ptr->l.vx, source.l.vx);
+ Vec3fa::storeu(&ptr->l.vy, source.l.vy);
+ Vec3fa::storeu(&ptr->l.vz, source.l.vz);
+ Vec3fa::storeu(&ptr->p, source.p);
+ }
+
+ __forceinline AffineSpace3fa AffineSpace3fa_load_unaligned(AffineSpace3fa* ptr)
+ {
+ AffineSpace3fa space;
+ space.l.vx = Vec3fa::loadu(&ptr->l.vx);
+ space.l.vy = Vec3fa::loadu(&ptr->l.vy);
+ space.l.vz = Vec3fa::loadu(&ptr->l.vz);
+ space.p = Vec3fa::loadu(&ptr->p);
+ return space;
+ }
+
+ #undef VectorT
+ #undef ScalarT
+}
diff --git a/thirdparty/embree/common/math/bbox.h b/thirdparty/embree/common/math/bbox.h
new file mode 100644
index 0000000000..bc43155358
--- /dev/null
+++ b/thirdparty/embree/common/math/bbox.h
@@ -0,0 +1,331 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "vec2.h"
+#include "vec3.h"
+
+namespace embree
+{
+ namespace internal {
+
+ template <typename T> __forceinline T divideByTwo(const T& v) { return v / T(2); }
+ template <> __forceinline float divideByTwo<float>(const float& v) { return v * 0.5f; }
+ template <> __forceinline double divideByTwo<double>(const double& v) { return v * 0.5; }
+
+ } // namespace internal
+ template<typename T>
+ struct BBox
+ {
+ T lower, upper;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline BBox ( ) { }
+ template<typename T1>
+ __forceinline BBox ( const BBox<T1>& other ) : lower(other.lower), upper(other.upper) {}
+ __forceinline BBox& operator=( const BBox& other ) { lower = other.lower; upper = other.upper; return *this; }
+
+ __forceinline BBox ( const T& v ) : lower(v), upper(v) {}
+ __forceinline BBox ( const T& lower, const T& upper ) : lower(lower), upper(upper) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Extending Bounds
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const BBox& extend(const BBox& other) { lower = min(lower,other.lower); upper = max(upper,other.upper); return *this; }
+ __forceinline const BBox& extend(const T & other) { lower = min(lower,other ); upper = max(upper,other ); return *this; }
+
+ /*! tests if box is empty */
+ __forceinline bool empty() const { for (int i=0; i<T::N; i++) if (lower[i] > upper[i]) return true; return false; }
+
+ /*! computes the size of the box */
+ __forceinline T size() const { return upper - lower; }
+
+ /*! computes the center of the box */
+ __forceinline T center() const { return internal::divideByTwo<T>(lower+upper); }
+
+ /*! computes twice the center of the box */
+ __forceinline T center2() const { return lower+upper; }
+
+ /*! merges two boxes */
+ __forceinline static const BBox merge (const BBox& a, const BBox& b) {
+ return BBox(min(a.lower, b.lower), max(a.upper, b.upper));
+ }
+
+ /*! enlarge box by some scaling factor */
+ __forceinline BBox enlarge_by(const float a) const {
+ return BBox(lower - T(a)*abs(lower), upper + T(a)*abs(upper));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline BBox( EmptyTy ) : lower(pos_inf), upper(neg_inf) {}
+ __forceinline BBox( FullTy ) : lower(neg_inf), upper(pos_inf) {}
+ __forceinline BBox( FalseTy ) : lower(pos_inf), upper(neg_inf) {}
+ __forceinline BBox( TrueTy ) : lower(neg_inf), upper(pos_inf) {}
+ __forceinline BBox( NegInfTy ): lower(pos_inf), upper(neg_inf) {}
+ __forceinline BBox( PosInfTy ): lower(neg_inf), upper(pos_inf) {}
+ };
+
+ template<> __forceinline bool BBox<float>::empty() const {
+ return lower > upper;
+ }
+
+#if defined(__SSE__)
+ template<> __forceinline bool BBox<Vec3fa>::empty() const {
+ return !all(le_mask(lower,upper));
+ }
+ template<> __forceinline bool BBox<Vec3fx>::empty() const {
+ return !all(le_mask(lower,upper));
+ }
+#endif
+
+ /*! tests if box is finite */
+ __forceinline bool isvalid( const BBox<Vec3fa>& v ) {
+ return all(gt_mask(v.lower,Vec3fa_t(-FLT_LARGE)) & lt_mask(v.upper,Vec3fa_t(+FLT_LARGE)));
+ }
+
+ /*! tests if box is finite and non-empty*/
+ __forceinline bool isvalid_non_empty( const BBox<Vec3fa>& v ) {
+ return all(gt_mask(v.lower,Vec3fa_t(-FLT_LARGE)) & lt_mask(v.upper,Vec3fa_t(+FLT_LARGE)) & le_mask(v.lower,v.upper));
+ }
+
+ /*! tests if box has finite entries */
+ __forceinline bool is_finite( const BBox<Vec3fa>& b) {
+ return is_finite(b.lower) && is_finite(b.upper);
+ }
+
+ /*! test if point contained in box */
+ __forceinline bool inside ( const BBox<Vec3fa>& b, const Vec3fa& p ) { return all(ge_mask(p,b.lower) & le_mask(p,b.upper)); }
+
+ /*! computes the center of the box */
+ template<typename T> __forceinline const T center2(const BBox<T>& box) { return box.lower + box.upper; }
+ template<typename T> __forceinline const T center (const BBox<T>& box) { return internal::divideByTwo<T>(center2(box)); }
+
+ /*! computes the volume of a bounding box */
+ __forceinline float volume ( const BBox<Vec3fa>& b ) { return reduce_mul(b.size()); }
+ __forceinline float safeVolume( const BBox<Vec3fa>& b ) { if (b.empty()) return 0.0f; else return volume(b); }
+
+ /*! computes the volume of a bounding box */
+ __forceinline float volume( const BBox<Vec3f>& b ) { return reduce_mul(b.size()); }
+
+ /*! computes the surface area of a bounding box */
+ template<typename T> __forceinline const T area( const BBox<Vec2<T> >& b ) { const Vec2<T> d = b.size(); return d.x*d.y; }
+
+ template<typename T> __forceinline const T halfArea( const BBox<Vec3<T> >& b ) { return halfArea(b.size()); }
+ template<typename T> __forceinline const T area( const BBox<Vec3<T> >& b ) { return T(2)*halfArea(b); }
+
+ __forceinline float halfArea( const BBox<Vec3fa>& b ) { return halfArea(b.size()); }
+ __forceinline float area( const BBox<Vec3fa>& b ) { return 2.0f*halfArea(b); }
+
+ __forceinline float halfArea( const BBox<Vec3fx>& b ) { return halfArea(b.size()); }
+ __forceinline float area( const BBox<Vec3fx>& b ) { return 2.0f*halfArea(b); }
+
+ template<typename Vec> __forceinline float safeArea( const BBox<Vec>& b ) { if (b.empty()) return 0.0f; else return area(b); }
+
+ template<typename T> __forceinline float expectedApproxHalfArea(const BBox<T>& box) {
+ return halfArea(box);
+ }
+
+ /*! merges bounding boxes and points */
+ template<typename T> __forceinline const BBox<T> merge( const BBox<T>& a, const T& b ) { return BBox<T>(min(a.lower, b ), max(a.upper, b )); }
+ template<typename T> __forceinline const BBox<T> merge( const T& a, const BBox<T>& b ) { return BBox<T>(min(a , b.lower), max(a , b.upper)); }
+ template<typename T> __forceinline const BBox<T> merge( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(min(a.lower, b.lower), max(a.upper, b.upper)); }
+
+ /*! Merges three boxes. */
+ template<typename T> __forceinline const BBox<T> merge( const BBox<T>& a, const BBox<T>& b, const BBox<T>& c ) { return merge(a,merge(b,c)); }
+
+ /*! Merges four boxes. */
+ template<typename T> __forceinline BBox<T> merge(const BBox<T>& a, const BBox<T>& b, const BBox<T>& c, const BBox<T>& d) {
+ return merge(merge(a,b),merge(c,d));
+ }
+
+ /*! Comparison Operators */
+ template<typename T> __forceinline bool operator==( const BBox<T>& a, const BBox<T>& b ) { return a.lower == b.lower && a.upper == b.upper; }
+ template<typename T> __forceinline bool operator!=( const BBox<T>& a, const BBox<T>& b ) { return a.lower != b.lower || a.upper != b.upper; }
+
+ /*! scaling */
+ template<typename T> __forceinline BBox<T> operator *( const float& a, const BBox<T>& b ) { return BBox<T>(a*b.lower,a*b.upper); }
+ template<typename T> __forceinline BBox<T> operator *( const T& a, const BBox<T>& b ) { return BBox<T>(a*b.lower,a*b.upper); }
+
+ /*! translations */
+ template<typename T> __forceinline BBox<T> operator +( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(a.lower+b.lower,a.upper+b.upper); }
+ template<typename T> __forceinline BBox<T> operator -( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(a.lower-b.lower,a.upper-b.upper); }
+ template<typename T> __forceinline BBox<T> operator +( const BBox<T>& a, const T & b ) { return BBox<T>(a.lower+b ,a.upper+b ); }
+ template<typename T> __forceinline BBox<T> operator -( const BBox<T>& a, const T & b ) { return BBox<T>(a.lower-b ,a.upper-b ); }
+
+ /*! extension */
+ template<typename T> __forceinline BBox<T> enlarge(const BBox<T>& a, const T& b) { return BBox<T>(a.lower-b, a.upper+b); }
+
+ /*! intersect bounding boxes */
+ template<typename T> __forceinline const BBox<T> intersect( const BBox<T>& a, const BBox<T>& b ) { return BBox<T>(max(a.lower, b.lower), min(a.upper, b.upper)); }
+ template<typename T> __forceinline const BBox<T> intersect( const BBox<T>& a, const BBox<T>& b, const BBox<T>& c ) { return intersect(a,intersect(b,c)); }
+ template<typename T> __forceinline const BBox<T> intersect( const BBox<T>& a, const BBox<T>& b, const BBox<T>& c, const BBox<T>& d ) { return intersect(intersect(a,b),intersect(c,d)); }
+
+ /*! subtract bounds from each other */
+ template<typename T> __forceinline void subtract(const BBox<T>& a, const BBox<T>& b, BBox<T>& c, BBox<T>& d)
+ {
+ c.lower = a.lower;
+ c.upper = min(a.upper,b.lower);
+ d.lower = max(a.lower,b.upper);
+ d.upper = a.upper;
+ }
+
+ /*! tests if bounding boxes (and points) are disjoint (empty intersection) */
+ template<typename T> __inline bool disjoint( const BBox<T>& a, const BBox<T>& b ) { return intersect(a,b).empty(); }
+ template<typename T> __inline bool disjoint( const BBox<T>& a, const T& b ) { return disjoint(a,BBox<T>(b)); }
+ template<typename T> __inline bool disjoint( const T& a, const BBox<T>& b ) { return disjoint(BBox<T>(a),b); }
+
+ /*! tests if bounding boxes (and points) are conjoint (non-empty intersection) */
+ template<typename T> __inline bool conjoint( const BBox<T>& a, const BBox<T>& b ) { return !intersect(a,b).empty(); }
+ template<typename T> __inline bool conjoint( const BBox<T>& a, const T& b ) { return conjoint(a,BBox<T>(b)); }
+ template<typename T> __inline bool conjoint( const T& a, const BBox<T>& b ) { return conjoint(BBox<T>(a),b); }
+
+ /*! subset relation */
+ template<typename T> __inline bool subset( const BBox<T>& a, const BBox<T>& b )
+ {
+ for ( size_t i = 0; i < T::N; i++ ) if ( a.lower[i] < b.lower[i] ) return false;
+ for ( size_t i = 0; i < T::N; i++ ) if ( a.upper[i] > b.upper[i] ) return false;
+ return true;
+ }
+
+ template<> __inline bool subset( const BBox<Vec3fa>& a, const BBox<Vec3fa>& b ) {
+ return all(ge_mask(a.lower,b.lower)) & all(le_mask(a.upper,b.upper));
+ }
+
+ template<> __inline bool subset( const BBox<Vec3fx>& a, const BBox<Vec3fx>& b ) {
+ return all(ge_mask(a.lower,b.lower)) & all(le_mask(a.upper,b.upper));
+ }
+
+ /*! blending */
+ template<typename T>
+ __forceinline BBox<T> lerp(const BBox<T>& b0, const BBox<T>& b1, const float t) {
+ return BBox<T>(lerp(b0.lower,b1.lower,t),lerp(b0.upper,b1.upper,t));
+ }
+
+ /*! output operator */
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const BBox<T>& box) {
+ return cout << "[" << box.lower << "; " << box.upper << "]";
+ }
+
+ /*! default template instantiations */
+ typedef BBox<float> BBox1f;
+ typedef BBox<Vec2f> BBox2f;
+ typedef BBox<Vec2fa> BBox2fa;
+ typedef BBox<Vec3f> BBox3f;
+ typedef BBox<Vec3fa> BBox3fa;
+ typedef BBox<Vec3fx> BBox3fx;
+ typedef BBox<Vec3ff> BBox3ff;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// SSE / AVX / MIC specializations
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined __SSE__
+#include "../simd/sse.h"
+#endif
+
+#if defined __AVX__
+#include "../simd/avx.h"
+#endif
+
+#if defined(__AVX512F__)
+#include "../simd/avx512.h"
+#endif
+
+namespace embree
+{
+ template<int N>
+ __forceinline BBox<Vec3<vfloat<N>>> transpose(const BBox3fa* bounds);
+
+ template<>
+ __forceinline BBox<Vec3<vfloat4>> transpose<4>(const BBox3fa* bounds)
+ {
+ BBox<Vec3<vfloat4>> dest;
+
+ transpose((vfloat4&)bounds[0].lower,
+ (vfloat4&)bounds[1].lower,
+ (vfloat4&)bounds[2].lower,
+ (vfloat4&)bounds[3].lower,
+ dest.lower.x,
+ dest.lower.y,
+ dest.lower.z);
+
+ transpose((vfloat4&)bounds[0].upper,
+ (vfloat4&)bounds[1].upper,
+ (vfloat4&)bounds[2].upper,
+ (vfloat4&)bounds[3].upper,
+ dest.upper.x,
+ dest.upper.y,
+ dest.upper.z);
+
+ return dest;
+ }
+
+#if defined(__AVX__)
+ template<>
+ __forceinline BBox<Vec3<vfloat8>> transpose<8>(const BBox3fa* bounds)
+ {
+ BBox<Vec3<vfloat8>> dest;
+
+ transpose((vfloat4&)bounds[0].lower,
+ (vfloat4&)bounds[1].lower,
+ (vfloat4&)bounds[2].lower,
+ (vfloat4&)bounds[3].lower,
+ (vfloat4&)bounds[4].lower,
+ (vfloat4&)bounds[5].lower,
+ (vfloat4&)bounds[6].lower,
+ (vfloat4&)bounds[7].lower,
+ dest.lower.x,
+ dest.lower.y,
+ dest.lower.z);
+
+ transpose((vfloat4&)bounds[0].upper,
+ (vfloat4&)bounds[1].upper,
+ (vfloat4&)bounds[2].upper,
+ (vfloat4&)bounds[3].upper,
+ (vfloat4&)bounds[4].upper,
+ (vfloat4&)bounds[5].upper,
+ (vfloat4&)bounds[6].upper,
+ (vfloat4&)bounds[7].upper,
+ dest.upper.x,
+ dest.upper.y,
+ dest.upper.z);
+
+ return dest;
+ }
+#endif
+
+ template<int N>
+ __forceinline BBox3fa merge(const BBox3fa* bounds);
+
+ template<>
+ __forceinline BBox3fa merge<4>(const BBox3fa* bounds)
+ {
+ const Vec3fa lower = min(min(bounds[0].lower,bounds[1].lower),
+ min(bounds[2].lower,bounds[3].lower));
+ const Vec3fa upper = max(max(bounds[0].upper,bounds[1].upper),
+ max(bounds[2].upper,bounds[3].upper));
+ return BBox3fa(lower,upper);
+ }
+
+#if defined(__AVX__)
+ template<>
+ __forceinline BBox3fa merge<8>(const BBox3fa* bounds)
+ {
+ const Vec3fa lower = min(min(min(bounds[0].lower,bounds[1].lower),min(bounds[2].lower,bounds[3].lower)),
+ min(min(bounds[4].lower,bounds[5].lower),min(bounds[6].lower,bounds[7].lower)));
+ const Vec3fa upper = max(max(max(bounds[0].upper,bounds[1].upper),max(bounds[2].upper,bounds[3].upper)),
+ max(max(bounds[4].upper,bounds[5].upper),max(bounds[6].upper,bounds[7].upper)));
+ return BBox3fa(lower,upper);
+ }
+#endif
+}
+
diff --git a/thirdparty/embree/common/math/col3.h b/thirdparty/embree/common/math/col3.h
new file mode 100644
index 0000000000..3f50c04393
--- /dev/null
+++ b/thirdparty/embree/common/math/col3.h
@@ -0,0 +1,47 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "math.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// RGB Color Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct Col3
+ {
+ T r, g, b;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Col3 ( ) { }
+ __forceinline Col3 ( const Col3& other ) { r = other.r; g = other.g; b = other.b; }
+ __forceinline Col3& operator=( const Col3& other ) { r = other.r; g = other.g; b = other.b; return *this; }
+
+ __forceinline explicit Col3 (const T& v) : r(v), g(v), b(v) {}
+ __forceinline Col3 (const T& r, const T& g, const T& b) : r(r), g(g), b(b) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Col3 (ZeroTy) : r(zero) , g(zero) , b(zero) {}
+ __forceinline Col3 (OneTy) : r(one) , g(one) , b(one) {}
+ __forceinline Col3 (PosInfTy) : r(pos_inf), g(pos_inf), b(pos_inf) {}
+ __forceinline Col3 (NegInfTy) : r(neg_inf), g(neg_inf), b(neg_inf) {}
+ };
+
+ /*! output operator */
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const Col3<T>& a) {
+ return cout << "(" << a.r << ", " << a.g << ", " << a.b << ")";
+ }
+
+ /*! default template instantiations */
+ typedef Col3<unsigned char> Col3uc;
+ typedef Col3<float > Col3f;
+}
diff --git a/thirdparty/embree/common/math/col4.h b/thirdparty/embree/common/math/col4.h
new file mode 100644
index 0000000000..788508516b
--- /dev/null
+++ b/thirdparty/embree/common/math/col4.h
@@ -0,0 +1,47 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "math.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// RGBA Color Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct Col4
+ {
+ T r, g, b, a;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Col4 ( ) { }
+ __forceinline Col4 ( const Col4& other ) { r = other.r; g = other.g; b = other.b; a = other.a; }
+ __forceinline Col4& operator=( const Col4& other ) { r = other.r; g = other.g; b = other.b; a = other.a; return *this; }
+
+ __forceinline explicit Col4 (const T& v) : r(v), g(v), b(v), a(v) {}
+ __forceinline Col4 (const T& r, const T& g, const T& b, const T& a) : r(r), g(g), b(b), a(a) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Col4 (ZeroTy) : r(zero) , g(zero) , b(zero) , a(zero) {}
+ __forceinline Col4 (OneTy) : r(one) , g(one) , b(one) , a(one) {}
+ __forceinline Col4 (PosInfTy) : r(pos_inf), g(pos_inf), b(pos_inf), a(pos_inf) {}
+ __forceinline Col4 (NegInfTy) : r(neg_inf), g(neg_inf), b(neg_inf), a(neg_inf) {}
+ };
+
+ /*! output operator */
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const Col4<T>& a) {
+ return cout << "(" << a.r << ", " << a.g << ", " << a.b << ", " << a.a << ")";
+ }
+
+ /*! default template instantiations */
+ typedef Col4<unsigned char> Col4uc;
+ typedef Col4<float > Col4f;
+}
diff --git a/thirdparty/embree/common/math/color.h b/thirdparty/embree/common/math/color.h
new file mode 100644
index 0000000000..529584ea16
--- /dev/null
+++ b/thirdparty/embree/common/math/color.h
@@ -0,0 +1,241 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "constants.h"
+#include "col3.h"
+#include "col4.h"
+
+#include "../simd/sse.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE RGBA Color Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct Color4
+ {
+ union {
+ __m128 m128;
+ struct { float r,g,b,a; };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Color4 () {}
+ __forceinline Color4 ( const __m128 a ) : m128(a) {}
+
+ __forceinline explicit Color4 (const float v) : m128(_mm_set1_ps(v)) {}
+ __forceinline Color4 (const float r, const float g, const float b, const float a) : m128(_mm_set_ps(a,b,g,r)) {}
+
+ __forceinline explicit Color4 ( const Col3uc& other ) { m128 = _mm_mul_ps(_mm_set_ps(255.0f,other.b,other.g,other.r),_mm_set1_ps(one_over_255)); }
+ __forceinline explicit Color4 ( const Col3f& other ) { m128 = _mm_set_ps(1.0f,other.b,other.g,other.r); }
+ __forceinline explicit Color4 ( const Col4uc& other ) { m128 = _mm_mul_ps(_mm_set_ps(other.a,other.b,other.g,other.r),_mm_set1_ps(one_over_255)); }
+ __forceinline explicit Color4 ( const Col4f& other ) { m128 = _mm_set_ps(other.a,other.b,other.g,other.r); }
+
+ __forceinline Color4 ( const Color4& other ) : m128(other.m128) {}
+ __forceinline Color4& operator=( const Color4& other ) { m128 = other.m128; return *this; }
+
+ __forceinline operator const __m128&() const { return m128; }
+ __forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Set
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline void set(Col3f& d) const { d.r = r; d.g = g; d.b = b; }
+ __forceinline void set(Col4f& d) const { d.r = r; d.g = g; d.b = b; d.a = a; }
+ __forceinline void set(Col3uc& d) const
+ {
+ vfloat4 s = clamp(vfloat4(m128))*255.0f;
+ d.r = (unsigned char)(s[0]);
+ d.g = (unsigned char)(s[1]);
+ d.b = (unsigned char)(s[2]);
+ }
+ __forceinline void set(Col4uc& d) const
+ {
+ vfloat4 s = clamp(vfloat4(m128))*255.0f;
+ d.r = (unsigned char)(s[0]);
+ d.g = (unsigned char)(s[1]);
+ d.b = (unsigned char)(s[2]);
+ d.a = (unsigned char)(s[3]);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Color4( ZeroTy ) : m128(_mm_set1_ps(0.0f)) {}
+ __forceinline Color4( OneTy ) : m128(_mm_set1_ps(1.0f)) {}
+ __forceinline Color4( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {}
+ __forceinline Color4( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {}
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE RGB Color Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct Color
+ {
+ union {
+ __m128 m128;
+ struct { float r,g,b; };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Color () {}
+ __forceinline Color ( const __m128 a ) : m128(a) {}
+
+ __forceinline explicit Color (const float v) : m128(_mm_set1_ps(v)) {}
+ __forceinline Color (const float r, const float g, const float b) : m128(_mm_set_ps(0.0f,b,g,r)) {}
+
+ __forceinline Color ( const Color& other ) : m128(other.m128) {}
+ __forceinline Color& operator=( const Color& other ) { m128 = other.m128; return *this; }
+
+ __forceinline Color ( const Color4& other ) : m128(other.m128) {}
+ __forceinline Color& operator=( const Color4& other ) { m128 = other.m128; return *this; }
+
+ __forceinline operator const __m128&() const { return m128; }
+ __forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Set
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline void set(Col3f& d) const { d.r = r; d.g = g; d.b = b; }
+ __forceinline void set(Col4f& d) const { d.r = r; d.g = g; d.b = b; d.a = 1.0f; }
+ __forceinline void set(Col3uc& d) const
+ {
+ vfloat4 s = clamp(vfloat4(m128))*255.0f;
+ d.r = (unsigned char)(s[0]);
+ d.g = (unsigned char)(s[1]);
+ d.b = (unsigned char)(s[2]);
+ }
+ __forceinline void set(Col4uc& d) const
+ {
+ vfloat4 s = clamp(vfloat4(m128))*255.0f;
+ d.r = (unsigned char)(s[0]);
+ d.g = (unsigned char)(s[1]);
+ d.b = (unsigned char)(s[2]);
+ d.a = 255;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Color( ZeroTy ) : m128(_mm_set1_ps(0.0f)) {}
+ __forceinline Color( OneTy ) : m128(_mm_set1_ps(1.0f)) {}
+ __forceinline Color( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {}
+ __forceinline Color( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {}
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const Color operator +( const Color& a ) { return a; }
+ __forceinline const Color operator -( const Color& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+ return _mm_xor_ps(a.m128, mask);
+ }
+ __forceinline const Color abs ( const Color& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
+ return _mm_and_ps(a.m128, mask);
+ }
+ __forceinline const Color rcp ( const Color& a )
+ {
+#if defined(__AVX512VL__)
+ const Color r = _mm_rcp14_ps(a.m128);
+#else
+ const Color r = _mm_rcp_ps(a.m128);
+#endif
+ return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
+ }
+ __forceinline const Color rsqrt( const Color& a )
+ {
+#if defined(__AVX512VL__)
+ __m128 r = _mm_rsqrt14_ps(a.m128);
+#else
+ __m128 r = _mm_rsqrt_ps(a.m128);
+#endif
+ return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+ }
+ __forceinline const Color sqrt ( const Color& a ) { return _mm_sqrt_ps(a.m128); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const Color operator +( const Color& a, const Color& b ) { return _mm_add_ps(a.m128, b.m128); }
+ __forceinline const Color operator -( const Color& a, const Color& b ) { return _mm_sub_ps(a.m128, b.m128); }
+ __forceinline const Color operator *( const Color& a, const Color& b ) { return _mm_mul_ps(a.m128, b.m128); }
+ __forceinline const Color operator *( const Color& a, const float b ) { return a * Color(b); }
+ __forceinline const Color operator *( const float a, const Color& b ) { return Color(a) * b; }
+ __forceinline const Color operator /( const Color& a, const Color& b ) { return a * rcp(b); }
+ __forceinline const Color operator /( const Color& a, const float b ) { return a * rcp(b); }
+
+ __forceinline const Color min( const Color& a, const Color& b ) { return _mm_min_ps(a.m128,b.m128); }
+ __forceinline const Color max( const Color& a, const Color& b ) { return _mm_max_ps(a.m128,b.m128); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const Color operator+=(Color& a, const Color& b) { return a = a + b; }
+ __forceinline const Color operator-=(Color& a, const Color& b) { return a = a - b; }
+ __forceinline const Color operator*=(Color& a, const Color& b) { return a = a * b; }
+ __forceinline const Color operator/=(Color& a, const Color& b) { return a = a / b; }
+ __forceinline const Color operator*=(Color& a, const float b ) { return a = a * b; }
+ __forceinline const Color operator/=(Color& a, const float b ) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float reduce_add(const Color& v) { return v.r+v.g+v.b; }
+ __forceinline float reduce_mul(const Color& v) { return v.r*v.g*v.b; }
+ __forceinline float reduce_min(const Color& v) { return min(v.r,v.g,v.b); }
+ __forceinline float reduce_max(const Color& v) { return max(v.r,v.g,v.b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Color& a, const Color& b ) { return (_mm_movemask_ps(_mm_cmpeq_ps (a.m128, b.m128)) & 7) == 7; }
+ __forceinline bool operator !=( const Color& a, const Color& b ) { return (_mm_movemask_ps(_mm_cmpneq_ps(a.m128, b.m128)) & 7) != 0; }
+ __forceinline bool operator < ( const Color& a, const Color& b ) {
+ if (a.r != b.r) return a.r < b.r;
+ if (a.g != b.g) return a.g < b.g;
+ if (a.b != b.b) return a.b < b.b;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const Color select( bool s, const Color& t, const Color& f ) {
+ __m128 mask = s ? _mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())) : _mm_setzero_ps();
+ return blendv_ps(f, t, mask);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Special Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ /*! computes luminance of a color */
+ __forceinline float luminance (const Color& a) { return madd(0.212671f,a.r,madd(0.715160f,a.g,0.072169f*a.b)); }
+
+ /*! output operator */
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Color& a) {
+ return cout << "(" << a.r << ", " << a.g << ", " << a.b << ")";
+ }
+}
diff --git a/thirdparty/embree/common/math/constants.cpp b/thirdparty/embree/common/math/constants.cpp
new file mode 100644
index 0000000000..03919ae20c
--- /dev/null
+++ b/thirdparty/embree/common/math/constants.cpp
@@ -0,0 +1,27 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "constants.h"
+
+namespace embree
+{
+ TrueTy True;
+ FalseTy False;
+ ZeroTy zero;
+ OneTy one;
+ NegInfTy neg_inf;
+ PosInfTy inf;
+ PosInfTy pos_inf;
+ NaNTy nan;
+ UlpTy ulp;
+ PiTy pi;
+ OneOverPiTy one_over_pi;
+ TwoPiTy two_pi;
+ OneOverTwoPiTy one_over_two_pi;
+ FourPiTy four_pi;
+ OneOverFourPiTy one_over_four_pi;
+ StepTy step;
+ ReverseStepTy reverse_step;
+ EmptyTy empty;
+ UndefinedTy undefined;
+}
diff --git a/thirdparty/embree/common/math/constants.h b/thirdparty/embree/common/math/constants.h
new file mode 100644
index 0000000000..578473a8ab
--- /dev/null
+++ b/thirdparty/embree/common/math/constants.h
@@ -0,0 +1,197 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+
+#include <limits>
+
+#define _USE_MATH_DEFINES
+#include <math.h> // using cmath causes issues under Windows
+#include <cfloat>
+#include <climits>
+
+namespace embree
+{
+ static MAYBE_UNUSED const float one_over_255 = 1.0f/255.0f;
+ static MAYBE_UNUSED const float min_rcp_input = 1E-18f; // for abs(x) >= min_rcp_input the newton raphson rcp calculation does not fail
+
+ /* we consider floating point numbers in that range as valid input numbers */
+ static MAYBE_UNUSED float FLT_LARGE = 1.844E18f;
+
+ struct TrueTy {
+ __forceinline operator bool( ) const { return true; }
+ };
+
+ extern MAYBE_UNUSED TrueTy True;
+
+ struct FalseTy {
+ __forceinline operator bool( ) const { return false; }
+ };
+
+ extern MAYBE_UNUSED FalseTy False;
+
+ struct ZeroTy
+ {
+ __forceinline operator double ( ) const { return 0; }
+ __forceinline operator float ( ) const { return 0; }
+ __forceinline operator long long( ) const { return 0; }
+ __forceinline operator unsigned long long( ) const { return 0; }
+ __forceinline operator long ( ) const { return 0; }
+ __forceinline operator unsigned long ( ) const { return 0; }
+ __forceinline operator int ( ) const { return 0; }
+ __forceinline operator unsigned int ( ) const { return 0; }
+ __forceinline operator short ( ) const { return 0; }
+ __forceinline operator unsigned short ( ) const { return 0; }
+ __forceinline operator char ( ) const { return 0; }
+ __forceinline operator unsigned char ( ) const { return 0; }
+ };
+
+ extern MAYBE_UNUSED ZeroTy zero;
+
+ struct OneTy
+ {
+ __forceinline operator double ( ) const { return 1; }
+ __forceinline operator float ( ) const { return 1; }
+ __forceinline operator long long( ) const { return 1; }
+ __forceinline operator unsigned long long( ) const { return 1; }
+ __forceinline operator long ( ) const { return 1; }
+ __forceinline operator unsigned long ( ) const { return 1; }
+ __forceinline operator int ( ) const { return 1; }
+ __forceinline operator unsigned int ( ) const { return 1; }
+ __forceinline operator short ( ) const { return 1; }
+ __forceinline operator unsigned short ( ) const { return 1; }
+ __forceinline operator char ( ) const { return 1; }
+ __forceinline operator unsigned char ( ) const { return 1; }
+ };
+
+ extern MAYBE_UNUSED OneTy one;
+
+ struct NegInfTy
+ {
+ __forceinline operator double ( ) const { return -std::numeric_limits<double>::infinity(); }
+ __forceinline operator float ( ) const { return -std::numeric_limits<float>::infinity(); }
+ __forceinline operator long long( ) const { return std::numeric_limits<long long>::min(); }
+ __forceinline operator unsigned long long( ) const { return std::numeric_limits<unsigned long long>::min(); }
+ __forceinline operator long ( ) const { return std::numeric_limits<long>::min(); }
+ __forceinline operator unsigned long ( ) const { return std::numeric_limits<unsigned long>::min(); }
+ __forceinline operator int ( ) const { return std::numeric_limits<int>::min(); }
+ __forceinline operator unsigned int ( ) const { return std::numeric_limits<unsigned int>::min(); }
+ __forceinline operator short ( ) const { return std::numeric_limits<short>::min(); }
+ __forceinline operator unsigned short ( ) const { return std::numeric_limits<unsigned short>::min(); }
+ __forceinline operator char ( ) const { return std::numeric_limits<char>::min(); }
+ __forceinline operator unsigned char ( ) const { return std::numeric_limits<unsigned char>::min(); }
+
+ };
+
+ extern MAYBE_UNUSED NegInfTy neg_inf;
+
+ struct PosInfTy
+ {
+ __forceinline operator double ( ) const { return std::numeric_limits<double>::infinity(); }
+ __forceinline operator float ( ) const { return std::numeric_limits<float>::infinity(); }
+ __forceinline operator long long( ) const { return std::numeric_limits<long long>::max(); }
+ __forceinline operator unsigned long long( ) const { return std::numeric_limits<unsigned long long>::max(); }
+ __forceinline operator long ( ) const { return std::numeric_limits<long>::max(); }
+ __forceinline operator unsigned long ( ) const { return std::numeric_limits<unsigned long>::max(); }
+ __forceinline operator int ( ) const { return std::numeric_limits<int>::max(); }
+ __forceinline operator unsigned int ( ) const { return std::numeric_limits<unsigned int>::max(); }
+ __forceinline operator short ( ) const { return std::numeric_limits<short>::max(); }
+ __forceinline operator unsigned short ( ) const { return std::numeric_limits<unsigned short>::max(); }
+ __forceinline operator char ( ) const { return std::numeric_limits<char>::max(); }
+ __forceinline operator unsigned char ( ) const { return std::numeric_limits<unsigned char>::max(); }
+ };
+
+ extern MAYBE_UNUSED PosInfTy inf;
+ extern MAYBE_UNUSED PosInfTy pos_inf;
+
+ struct NaNTy
+ {
+ __forceinline operator double( ) const { return std::numeric_limits<double>::quiet_NaN(); }
+ __forceinline operator float ( ) const { return std::numeric_limits<float>::quiet_NaN(); }
+ };
+
+ extern MAYBE_UNUSED NaNTy nan;
+
+ struct UlpTy
+ {
+ __forceinline operator double( ) const { return std::numeric_limits<double>::epsilon(); }
+ __forceinline operator float ( ) const { return std::numeric_limits<float>::epsilon(); }
+ };
+
+ extern MAYBE_UNUSED UlpTy ulp;
+
+ struct PiTy
+ {
+ __forceinline operator double( ) const { return double(M_PI); }
+ __forceinline operator float ( ) const { return float(M_PI); }
+ };
+
+ extern MAYBE_UNUSED PiTy pi;
+
+ struct OneOverPiTy
+ {
+ __forceinline operator double( ) const { return double(M_1_PI); }
+ __forceinline operator float ( ) const { return float(M_1_PI); }
+ };
+
+ extern MAYBE_UNUSED OneOverPiTy one_over_pi;
+
+ struct TwoPiTy
+ {
+ __forceinline operator double( ) const { return double(2.0*M_PI); }
+ __forceinline operator float ( ) const { return float(2.0*M_PI); }
+ };
+
+ extern MAYBE_UNUSED TwoPiTy two_pi;
+
+ struct OneOverTwoPiTy
+ {
+ __forceinline operator double( ) const { return double(0.5*M_1_PI); }
+ __forceinline operator float ( ) const { return float(0.5*M_1_PI); }
+ };
+
+ extern MAYBE_UNUSED OneOverTwoPiTy one_over_two_pi;
+
+ struct FourPiTy
+ {
+ __forceinline operator double( ) const { return double(4.0*M_PI); }
+ __forceinline operator float ( ) const { return float(4.0*M_PI); }
+ };
+
+ extern MAYBE_UNUSED FourPiTy four_pi;
+
+ struct OneOverFourPiTy
+ {
+ __forceinline operator double( ) const { return double(0.25*M_1_PI); }
+ __forceinline operator float ( ) const { return float(0.25*M_1_PI); }
+ };
+
+ extern MAYBE_UNUSED OneOverFourPiTy one_over_four_pi;
+
+ struct StepTy {
+ };
+
+ extern MAYBE_UNUSED StepTy step;
+
+ struct ReverseStepTy {
+ };
+
+ extern MAYBE_UNUSED ReverseStepTy reverse_step;
+
+ struct EmptyTy {
+ };
+
+ extern MAYBE_UNUSED EmptyTy empty;
+
+ struct FullTy {
+ };
+
+ extern MAYBE_UNUSED FullTy full;
+
+ struct UndefinedTy {
+ };
+
+ extern MAYBE_UNUSED UndefinedTy undefined;
+}
diff --git a/thirdparty/embree/common/math/interval.h b/thirdparty/embree/common/math/interval.h
new file mode 100644
index 0000000000..310add2129
--- /dev/null
+++ b/thirdparty/embree/common/math/interval.h
@@ -0,0 +1,161 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "vec2.h"
+#include "vec3.h"
+#include "bbox.h"
+
+namespace embree
+{
+ template<typename V>
+ struct Interval
+ {
+ V lower, upper;
+
+ __forceinline Interval() {}
+ __forceinline Interval ( const Interval& other ) { lower = other.lower; upper = other.upper; }
+ __forceinline Interval& operator=( const Interval& other ) { lower = other.lower; upper = other.upper; return *this; }
+
+ __forceinline Interval(const V& a) : lower(a), upper(a) {}
+ __forceinline Interval(const V& lower, const V& upper) : lower(lower), upper(upper) {}
+ __forceinline Interval(const BBox<V>& a) : lower(a.lower), upper(a.upper) {}
+
+ /*! tests if box is empty */
+ //__forceinline bool empty() const { return lower > upper; }
+
+ /*! computes the size of the interval */
+ __forceinline V size() const { return upper - lower; }
+
+ __forceinline V center() const { return 0.5f*(lower+upper); }
+
+ __forceinline const Interval& extend(const Interval& other) { lower = min(lower,other.lower); upper = max(upper,other.upper); return *this; }
+ __forceinline const Interval& extend(const V & other) { lower = min(lower,other ); upper = max(upper,other ); return *this; }
+
+ __forceinline friend Interval operator +( const Interval& a, const Interval& b ) {
+ return Interval(a.lower+b.lower,a.upper+b.upper);
+ }
+
+ __forceinline friend Interval operator -( const Interval& a, const Interval& b ) {
+ return Interval(a.lower-b.upper,a.upper-b.lower);
+ }
+
+ __forceinline friend Interval operator -( const Interval& a, const V& b ) {
+ return Interval(a.lower-b,a.upper-b);
+ }
+
+ __forceinline friend Interval operator *( const Interval& a, const Interval& b )
+ {
+ const V ll = a.lower*b.lower;
+ const V lu = a.lower*b.upper;
+ const V ul = a.upper*b.lower;
+ const V uu = a.upper*b.upper;
+ return Interval(min(ll,lu,ul,uu),max(ll,lu,ul,uu));
+ }
+
+ __forceinline friend Interval merge( const Interval& a, const Interval& b) {
+ return Interval(min(a.lower,b.lower),max(a.upper,b.upper));
+ }
+
+ __forceinline friend Interval merge( const Interval& a, const Interval& b, const Interval& c) {
+ return merge(merge(a,b),c);
+ }
+
+ __forceinline friend Interval merge( const Interval& a, const Interval& b, const Interval& c, const Interval& d) {
+ return merge(merge(a,b),merge(c,d));
+ }
+
+ /*! intersect bounding boxes */
+ __forceinline friend const Interval intersect( const Interval& a, const Interval& b ) { return Interval(max(a.lower, b.lower), min(a.upper, b.upper)); }
+ __forceinline friend const Interval intersect( const Interval& a, const Interval& b, const Interval& c ) { return intersect(a,intersect(b,c)); }
+ __forceinline friend const Interval intersect( const Interval& a, const Interval& b, const Interval& c, const Interval& d ) { return intersect(intersect(a,b),intersect(c,d)); }
+
+ friend embree_ostream operator<<(embree_ostream cout, const Interval& a) {
+ return cout << "[" << a.lower << ", " << a.upper << "]";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Interval( EmptyTy ) : lower(pos_inf), upper(neg_inf) {}
+ __forceinline Interval( FullTy ) : lower(neg_inf), upper(pos_inf) {}
+ };
+
+ __forceinline bool isEmpty(const Interval<float>& v) {
+ return v.lower > v.upper;
+ }
+
+ __forceinline vboolx isEmpty(const Interval<vfloatx>& v) {
+ return v.lower > v.upper;
+ }
+
+ /*! subset relation */
+ template<typename T> __forceinline bool subset( const Interval<T>& a, const Interval<T>& b ) {
+ return (a.lower > b.lower) && (a.upper < b.upper);
+ }
+
+ template<typename T> __forceinline bool subset( const Vec2<Interval<T>>& a, const Vec2<Interval<T>>& b ) {
+ return subset(a.x,b.x) && subset(a.y,b.y);
+ }
+
+ template<typename T> __forceinline const Vec2<Interval<T>> intersect( const Vec2<Interval<T>>& a, const Vec2<Interval<T>>& b ) {
+ return Vec2<Interval<T>>(intersect(a.x,b.x),intersect(a.y,b.y));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Interval<T> select ( bool s, const Interval<T>& t, const Interval<T>& f ) {
+ return Interval<T>(select(s,t.lower,f.lower),select(s,t.upper,f.upper));
+ }
+
+ template<typename T> __forceinline Interval<T> select ( const typename T::Bool& s, const Interval<T>& t, const Interval<T>& f ) {
+ return Interval<T>(select(s,t.lower,f.lower),select(s,t.upper,f.upper));
+ }
+
+ __forceinline int numRoots(const Interval<float>& p0, const Interval<float>& p1)
+ {
+ float eps = 1E-4f;
+ bool neg0 = p0.lower < eps; bool pos0 = p0.upper > -eps;
+ bool neg1 = p1.lower < eps; bool pos1 = p1.upper > -eps;
+ return (neg0 && pos1) || (pos0 && neg1) || (neg0 && pos0) || (neg1 && pos1);
+ }
+
+ typedef Interval<float> Interval1f;
+ typedef Vec2<Interval<float>> Interval2f;
+ typedef Vec3<Interval<float>> Interval3f;
+
+inline void swap(float& a, float& b) { float tmp = a; a = b; b = tmp; }
+
+inline Interval1f shift(const Interval1f& v, float shift) { return Interval1f(v.lower + shift, v.upper + shift); }
+
+#define TWO_PI (2.0*M_PI)
+inline Interval1f sin(Interval1f interval)
+{
+ if (interval.upper-interval.lower >= M_PI) { return Interval1f(-1.0, 1.0); }
+ if (interval.upper > TWO_PI) { interval = shift(interval, -TWO_PI*floor(interval.upper/TWO_PI)); }
+ if (interval.lower < 0) { interval = shift(interval, -TWO_PI*floor(interval.lower/TWO_PI)); }
+ float sinLower = sin(interval.lower);
+ float sinUpper = sin(interval.upper);
+ if (sinLower > sinUpper) swap(sinLower, sinUpper);
+ if (interval.lower < M_PI / 2.0 && interval.upper > M_PI / 2.0) sinUpper = 1.0;
+ if (interval.lower < 3.0 * M_PI / 2.0 && interval.upper > 3.0 * M_PI / 2.0) sinLower = -1.0;
+ return Interval1f(sinLower, sinUpper);
+}
+
+inline Interval1f cos(Interval1f interval)
+{
+ if (interval.upper-interval.lower >= M_PI) { return Interval1f(-1.0, 1.0); }
+ if (interval.upper > TWO_PI) { interval = shift(interval, -TWO_PI*floor(interval.upper/TWO_PI)); }
+ if (interval.lower < 0) { interval = shift(interval, -TWO_PI*floor(interval.lower/TWO_PI)); }
+ float cosLower = cos(interval.lower);
+ float cosUpper = cos(interval.upper);
+ if (cosLower > cosUpper) swap(cosLower, cosUpper);
+ if (interval.lower < M_PI && interval.upper > M_PI) cosLower = -1.0;
+ return Interval1f(cosLower, cosUpper);
+}
+#undef TWO_PI
+}
diff --git a/thirdparty/embree/common/math/lbbox.h b/thirdparty/embree/common/math/lbbox.h
new file mode 100644
index 0000000000..2b397a05c8
--- /dev/null
+++ b/thirdparty/embree/common/math/lbbox.h
@@ -0,0 +1,289 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bbox.h"
+#include "range.h"
+
+namespace embree
+{
+ template<typename T>
+ __forceinline std::pair<T,T> globalLinear(const std::pair<T,T>& v, const BBox1f& dt)
+ {
+ const float rcp_dt_size = float(1.0f)/dt.size();
+ const T g0 = lerp(v.first,v.second,-dt.lower*rcp_dt_size);
+ const T g1 = lerp(v.first,v.second,(1.0f-dt.lower)*rcp_dt_size);
+ return std::make_pair(g0,g1);
+ }
+
+ template<typename T>
+ struct LBBox
+ {
+ public:
+ __forceinline LBBox () {}
+
+ template<typename T1>
+ __forceinline LBBox ( const LBBox<T1>& other )
+ : bounds0(other.bounds0), bounds1(other.bounds1) {}
+
+ __forceinline LBBox& operator= ( const LBBox& other ) {
+ bounds0 = other.bounds0; bounds1 = other.bounds1; return *this;
+ }
+
+ __forceinline LBBox (EmptyTy)
+ : bounds0(EmptyTy()), bounds1(EmptyTy()) {}
+
+ __forceinline explicit LBBox ( const BBox<T>& bounds)
+ : bounds0(bounds), bounds1(bounds) { }
+
+ __forceinline LBBox ( const BBox<T>& bounds0, const BBox<T>& bounds1)
+ : bounds0(bounds0), bounds1(bounds1) { }
+
+ LBBox ( const avector<BBox<T>>& bounds )
+ {
+ assert(bounds.size());
+ BBox<T> b0 = bounds.front();
+ BBox<T> b1 = bounds.back();
+ for (size_t i=1; i<bounds.size()-1; i++) {
+ const float f = float(i)/float(bounds.size()-1);
+ const BBox<T> bt = lerp(b0,b1,f);
+ const T dlower = min(bounds[i].lower-bt.lower,T(zero));
+ const T dupper = max(bounds[i].upper-bt.upper,T(zero));
+ b0.lower += dlower; b1.lower += dlower;
+ b0.upper += dupper; b1.upper += dupper;
+ }
+ bounds0 = b0;
+ bounds1 = b1;
+ }
+
+ /*! calculates the linear bounds of a primitive for the specified time range */
+ template<typename BoundsFunc>
+ __forceinline LBBox(const BoundsFunc& bounds, const BBox1f& time_range, float numTimeSegments)
+ {
+ const float lower = time_range.lower*numTimeSegments;
+ const float upper = time_range.upper*numTimeSegments;
+ const float ilowerf = floor(lower);
+ const float iupperf = ceil(upper);
+ const int ilower = (int)ilowerf;
+ const int iupper = (int)iupperf;
+
+ const BBox<T> blower0 = bounds(ilower);
+ const BBox<T> bupper1 = bounds(iupper);
+
+ if (iupper-ilower == 1) {
+ bounds0 = lerp(blower0, bupper1, lower-ilowerf);
+ bounds1 = lerp(bupper1, blower0, iupperf-upper);
+ return;
+ }
+
+ const BBox<T> blower1 = bounds(ilower+1);
+ const BBox<T> bupper0 = bounds(iupper-1);
+ BBox<T> b0 = lerp(blower0, blower1, lower-ilowerf);
+ BBox<T> b1 = lerp(bupper1, bupper0, iupperf-upper);
+
+ for (int i = ilower+1; i < iupper; i++)
+ {
+ const float f = (float(i)/numTimeSegments - time_range.lower) / time_range.size();
+ const BBox<T> bt = lerp(b0, b1, f);
+ const BBox<T> bi = bounds(i);
+ const T dlower = min(bi.lower-bt.lower, T(zero));
+ const T dupper = max(bi.upper-bt.upper, T(zero));
+ b0.lower += dlower; b1.lower += dlower;
+ b0.upper += dupper; b1.upper += dupper;
+ }
+
+ bounds0 = b0;
+ bounds1 = b1;
+ }
+
+ /*! calculates the linear bounds of a primitive for the specified time range */
+ template<typename BoundsFunc>
+ __forceinline LBBox(const BoundsFunc& bounds, const BBox1f& time_range_in, const BBox1f& geom_time_range, float geom_time_segments)
+ {
+ /* normalize global time_range_in to local geom_time_range */
+ const BBox1f time_range((time_range_in.lower-geom_time_range.lower)/geom_time_range.size(),
+ (time_range_in.upper-geom_time_range.lower)/geom_time_range.size());
+
+ const float lower = time_range.lower*geom_time_segments;
+ const float upper = time_range.upper*geom_time_segments;
+ const float ilowerf = floor(lower);
+ const float iupperf = ceil(upper);
+ const float ilowerfc = max(0.0f,ilowerf);
+ const float iupperfc = min(iupperf,geom_time_segments);
+ const int ilowerc = (int)ilowerfc;
+ const int iupperc = (int)iupperfc;
+ assert(iupperc-ilowerc > 0);
+
+ /* this larger iteration range guarantees that we process borders of geom_time_range is (partially) inside time_range_in */
+ const int ilower_iter = max(-1,(int)ilowerf);
+ const int iupper_iter = min((int)iupperf,(int)geom_time_segments+1);
+
+ const BBox<T> blower0 = bounds(ilowerc);
+ const BBox<T> bupper1 = bounds(iupperc);
+ if (iupper_iter-ilower_iter == 1) {
+ bounds0 = lerp(blower0, bupper1, max(0.0f,lower-ilowerfc));
+ bounds1 = lerp(bupper1, blower0, max(0.0f,iupperfc-upper));
+ return;
+ }
+
+ const BBox<T> blower1 = bounds(ilowerc+1);
+ const BBox<T> bupper0 = bounds(iupperc-1);
+ BBox<T> b0 = lerp(blower0, blower1, max(0.0f,lower-ilowerfc));
+ BBox<T> b1 = lerp(bupper1, bupper0, max(0.0f,iupperfc-upper));
+
+ for (int i = ilower_iter+1; i < iupper_iter; i++)
+ {
+ const float f = (float(i)/geom_time_segments - time_range.lower) / time_range.size();
+ const BBox<T> bt = lerp(b0, b1, f);
+ const BBox<T> bi = bounds(i);
+ const T dlower = min(bi.lower-bt.lower, T(zero));
+ const T dupper = max(bi.upper-bt.upper, T(zero));
+ b0.lower += dlower; b1.lower += dlower;
+ b0.upper += dupper; b1.upper += dupper;
+ }
+
+ bounds0 = b0;
+ bounds1 = b1;
+ }
+
+ /*! calculates the linear bounds of a primitive for the specified time range */
+ template<typename BoundsFunc>
+ __forceinline LBBox(const BoundsFunc& bounds, const range<int>& time_range, int numTimeSegments)
+ {
+ const int ilower = time_range.begin();
+ const int iupper = time_range.end();
+
+ BBox<T> b0 = bounds(ilower);
+ BBox<T> b1 = bounds(iupper);
+
+ if (iupper-ilower == 1)
+ {
+ bounds0 = b0;
+ bounds1 = b1;
+ return;
+ }
+
+ for (int i = ilower+1; i<iupper; i++)
+ {
+ const float f = float(i - time_range.begin()) / float(time_range.size());
+ const BBox<T> bt = lerp(b0, b1, f);
+ const BBox<T> bi = bounds(i);
+ const T dlower = min(bi.lower-bt.lower, T(zero));
+ const T dupper = max(bi.upper-bt.upper, T(zero));
+ b0.lower += dlower; b1.lower += dlower;
+ b0.upper += dupper; b1.upper += dupper;
+ }
+
+ bounds0 = b0;
+ bounds1 = b1;
+ }
+
+ public:
+
+ __forceinline bool empty() const {
+ return bounds().empty();
+ }
+
+ __forceinline BBox<T> bounds () const {
+ return merge(bounds0,bounds1);
+ }
+
+ __forceinline BBox<T> interpolate( const float t ) const {
+ return lerp(bounds0,bounds1,t);
+ }
+
+ __forceinline LBBox<T> interpolate( const BBox1f& dt ) const {
+ return LBBox<T>(interpolate(dt.lower),interpolate(dt.upper));
+ }
+
+ __forceinline void extend( const LBBox& other ) {
+ bounds0.extend(other.bounds0);
+ bounds1.extend(other.bounds1);
+ }
+
+ __forceinline float expectedHalfArea() const;
+
+ __forceinline float expectedHalfArea(const BBox1f& dt) const {
+ return interpolate(dt).expectedHalfArea();
+ }
+
+ __forceinline float expectedApproxHalfArea() const {
+ return 0.5f*(halfArea(bounds0) + halfArea(bounds1));
+ }
+
+ /* calculates bounds for [0,1] time range from bounds in dt time range */
+ __forceinline LBBox global(const BBox1f& dt) const
+ {
+ const float rcp_dt_size = 1.0f/dt.size();
+ const BBox<T> b0 = interpolate(-dt.lower*rcp_dt_size);
+ const BBox<T> b1 = interpolate((1.0f-dt.lower)*rcp_dt_size);
+ return LBBox(b0,b1);
+ }
+
+ /*! Comparison Operators */
+ //template<typename TT> friend __forceinline bool operator==( const LBBox<TT>& a, const LBBox<TT>& b ) { return a.bounds0 == b.bounds0 && a.bounds1 == b.bounds1; }
+ //template<typename TT> friend __forceinline bool operator!=( const LBBox<TT>& a, const LBBox<TT>& b ) { return a.bounds0 != b.bounds0 || a.bounds1 != b.bounds1; }
+ friend __forceinline bool operator==( const LBBox& a, const LBBox& b ) { return a.bounds0 == b.bounds0 && a.bounds1 == b.bounds1; }
+ friend __forceinline bool operator!=( const LBBox& a, const LBBox& b ) { return a.bounds0 != b.bounds0 || a.bounds1 != b.bounds1; }
+
+ /*! output operator */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const LBBox& box) {
+ return cout << "LBBox { " << box.bounds0 << "; " << box.bounds1 << " }";
+ }
+
+ public:
+ BBox<T> bounds0, bounds1;
+ };
+
+ /*! tests if box is finite */
+ template<typename T>
+ __forceinline bool isvalid( const LBBox<T>& v ) {
+ return isvalid(v.bounds0) && isvalid(v.bounds1);
+ }
+
+ template<typename T>
+ __forceinline bool isvalid_non_empty( const LBBox<T>& v ) {
+ return isvalid_non_empty(v.bounds0) && isvalid_non_empty(v.bounds1);
+ }
+
+ template<typename T>
+ __forceinline T expectedArea(const T& a0, const T& a1, const T& b0, const T& b1)
+ {
+ const T da = a1-a0;
+ const T db = b1-b0;
+ return a0*b0+(a0*db+da*b0)*T(0.5f) + da*db*T(1.0f/3.0f);
+ }
+
+ template<> __forceinline float LBBox<Vec3fa>::expectedHalfArea() const
+ {
+ const Vec3fa d0 = bounds0.size();
+ const Vec3fa d1 = bounds1.size();
+ return reduce_add(expectedArea(Vec3fa(d0.x,d0.y,d0.z),
+ Vec3fa(d1.x,d1.y,d1.z),
+ Vec3fa(d0.y,d0.z,d0.x),
+ Vec3fa(d1.y,d1.z,d1.x)));
+ }
+
+ template<typename T>
+ __forceinline float expectedApproxHalfArea(const LBBox<T>& box) {
+ return box.expectedApproxHalfArea();
+ }
+
+ template<typename T>
+ __forceinline LBBox<T> merge(const LBBox<T>& a, const LBBox<T>& b) {
+ return LBBox<T>(merge(a.bounds0, b.bounds0), merge(a.bounds1, b.bounds1));
+ }
+
+ /*! subset relation */
+ template<typename T> __inline bool subset( const LBBox<T>& a, const LBBox<T>& b ) {
+ return subset(a.bounds0,b.bounds0) && subset(a.bounds1,b.bounds1);
+ }
+
+ /*! default template instantiations */
+ typedef LBBox<float> LBBox1f;
+ typedef LBBox<Vec2f> LBBox2f;
+ typedef LBBox<Vec3f> LBBox3f;
+ typedef LBBox<Vec3fa> LBBox3fa;
+ typedef LBBox<Vec3fx> LBBox3fx;
+}
diff --git a/thirdparty/embree/common/math/linearspace2.h b/thirdparty/embree/common/math/linearspace2.h
new file mode 100644
index 0000000000..184ee695fb
--- /dev/null
+++ b/thirdparty/embree/common/math/linearspace2.h
@@ -0,0 +1,148 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "vec2.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// 2D Linear Transform (2x2 Matrix)
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct LinearSpace2
+ {
+ typedef T Vector;
+ typedef typename T::Scalar Scalar;
+
+ /*! default matrix constructor */
+ __forceinline LinearSpace2 ( ) {}
+ __forceinline LinearSpace2 ( const LinearSpace2& other ) { vx = other.vx; vy = other.vy; }
+ __forceinline LinearSpace2& operator=( const LinearSpace2& other ) { vx = other.vx; vy = other.vy; return *this; }
+
+ template<typename L1> __forceinline LinearSpace2( const LinearSpace2<L1>& s ) : vx(s.vx), vy(s.vy) {}
+
+ /*! matrix construction from column vectors */
+ __forceinline LinearSpace2(const Vector& vx, const Vector& vy)
+ : vx(vx), vy(vy) {}
+
+ /*! matrix construction from row mayor data */
+ __forceinline LinearSpace2(const Scalar& m00, const Scalar& m01,
+ const Scalar& m10, const Scalar& m11)
+ : vx(m00,m10), vy(m01,m11) {}
+
+ /*! compute the determinant of the matrix */
+ __forceinline const Scalar det() const { return vx.x*vy.y - vx.y*vy.x; }
+
+ /*! compute adjoint matrix */
+ __forceinline const LinearSpace2 adjoint() const { return LinearSpace2(vy.y,-vy.x,-vx.y,vx.x); }
+
+ /*! compute inverse matrix */
+ __forceinline const LinearSpace2 inverse() const { return adjoint()/det(); }
+
+ /*! compute transposed matrix */
+ __forceinline const LinearSpace2 transposed() const { return LinearSpace2(vx.x,vx.y,vy.x,vy.y); }
+
+ /*! returns first row of matrix */
+ __forceinline Vector row0() const { return Vector(vx.x,vy.x); }
+
+ /*! returns second row of matrix */
+ __forceinline Vector row1() const { return Vector(vx.y,vy.y); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline LinearSpace2( ZeroTy ) : vx(zero), vy(zero) {}
+ __forceinline LinearSpace2( OneTy ) : vx(one, zero), vy(zero, one) {}
+
+ /*! return matrix for scaling */
+ static __forceinline LinearSpace2 scale(const Vector& s) {
+ return LinearSpace2(s.x, 0,
+ 0 , s.y);
+ }
+
+ /*! return matrix for rotation */
+ static __forceinline LinearSpace2 rotate(const Scalar& r) {
+ Scalar s = sin(r), c = cos(r);
+ return LinearSpace2(c, -s,
+ s, c);
+ }
+
+ /*! return closest orthogonal matrix (i.e. a general rotation including reflection) */
+ LinearSpace2 orthogonal() const
+ {
+ LinearSpace2 m = *this;
+
+ // mirrored?
+ Scalar mirror(one);
+ if (m.det() < Scalar(zero)) {
+ m.vx = -m.vx;
+ mirror = -mirror;
+ }
+
+ // rotation
+ for (int i = 0; i < 99; i++) {
+ const LinearSpace2 m_next = 0.5 * (m + m.transposed().inverse());
+ const LinearSpace2 d = m_next - m;
+ m = m_next;
+ // norm^2 of difference small enough?
+ if (max(dot(d.vx, d.vx), dot(d.vy, d.vy)) < 1e-8)
+ break;
+ }
+
+ // rotation * mirror_x
+ return LinearSpace2(mirror*m.vx, m.vy);
+ }
+
+ public:
+
+ /*! the column vectors of the matrix */
+ Vector vx,vy;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline LinearSpace2<T> operator -( const LinearSpace2<T>& a ) { return LinearSpace2<T>(-a.vx,-a.vy); }
+ template<typename T> __forceinline LinearSpace2<T> operator +( const LinearSpace2<T>& a ) { return LinearSpace2<T>(+a.vx,+a.vy); }
+ template<typename T> __forceinline LinearSpace2<T> rcp ( const LinearSpace2<T>& a ) { return a.inverse(); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline LinearSpace2<T> operator +( const LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return LinearSpace2<T>(a.vx+b.vx,a.vy+b.vy); }
+ template<typename T> __forceinline LinearSpace2<T> operator -( const LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return LinearSpace2<T>(a.vx-b.vx,a.vy-b.vy); }
+
+ template<typename T> __forceinline LinearSpace2<T> operator*(const typename T::Scalar & a, const LinearSpace2<T>& b) { return LinearSpace2<T>(a*b.vx, a*b.vy); }
+ template<typename T> __forceinline T operator*(const LinearSpace2<T>& a, const T & b) { return b.x*a.vx + b.y*a.vy; }
+ template<typename T> __forceinline LinearSpace2<T> operator*(const LinearSpace2<T>& a, const LinearSpace2<T>& b) { return LinearSpace2<T>(a*b.vx, a*b.vy); }
+
+ template<typename T> __forceinline LinearSpace2<T> operator/(const LinearSpace2<T>& a, const typename T::Scalar & b) { return LinearSpace2<T>(a.vx/b, a.vy/b); }
+ template<typename T> __forceinline LinearSpace2<T> operator/(const LinearSpace2<T>& a, const LinearSpace2<T>& b) { return a * rcp(b); }
+
+ template<typename T> __forceinline LinearSpace2<T>& operator *=( LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return a = a * b; }
+ template<typename T> __forceinline LinearSpace2<T>& operator /=( LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return a.vx == b.vx && a.vy == b.vy; }
+ template<typename T> __forceinline bool operator !=( const LinearSpace2<T>& a, const LinearSpace2<T>& b ) { return a.vx != b.vx || a.vy != b.vy; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> static embree_ostream operator<<(embree_ostream cout, const LinearSpace2<T>& m) {
+ return cout << "{ vx = " << m.vx << ", vy = " << m.vy << "}";
+ }
+
+ /*! Shortcuts for common linear spaces. */
+ typedef LinearSpace2<Vec2f> LinearSpace2f;
+ typedef LinearSpace2<Vec2fa> LinearSpace2fa;
+}
diff --git a/thirdparty/embree/common/math/linearspace3.h b/thirdparty/embree/common/math/linearspace3.h
new file mode 100644
index 0000000000..9eaa2cc2bb
--- /dev/null
+++ b/thirdparty/embree/common/math/linearspace3.h
@@ -0,0 +1,213 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "vec3.h"
+#include "quaternion.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// 3D Linear Transform (3x3 Matrix)
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct LinearSpace3
+ {
+ typedef T Vector;
+ typedef typename T::Scalar Scalar;
+
+ /*! default matrix constructor */
+ __forceinline LinearSpace3 ( ) {}
+ __forceinline LinearSpace3 ( const LinearSpace3& other ) { vx = other.vx; vy = other.vy; vz = other.vz; }
+ __forceinline LinearSpace3& operator=( const LinearSpace3& other ) { vx = other.vx; vy = other.vy; vz = other.vz; return *this; }
+
+ template<typename L1> __forceinline LinearSpace3( const LinearSpace3<L1>& s ) : vx(s.vx), vy(s.vy), vz(s.vz) {}
+
+ /*! matrix construction from column vectors */
+ __forceinline LinearSpace3(const Vector& vx, const Vector& vy, const Vector& vz)
+ : vx(vx), vy(vy), vz(vz) {}
+
+ /*! construction from quaternion */
+ __forceinline LinearSpace3( const QuaternionT<Scalar>& q )
+ : vx((q.r*q.r + q.i*q.i - q.j*q.j - q.k*q.k), 2.0f*(q.i*q.j + q.r*q.k), 2.0f*(q.i*q.k - q.r*q.j))
+ , vy(2.0f*(q.i*q.j - q.r*q.k), (q.r*q.r - q.i*q.i + q.j*q.j - q.k*q.k), 2.0f*(q.j*q.k + q.r*q.i))
+ , vz(2.0f*(q.i*q.k + q.r*q.j), 2.0f*(q.j*q.k - q.r*q.i), (q.r*q.r - q.i*q.i - q.j*q.j + q.k*q.k)) {}
+
+ /*! matrix construction from row mayor data */
+ __forceinline LinearSpace3(const Scalar& m00, const Scalar& m01, const Scalar& m02,
+ const Scalar& m10, const Scalar& m11, const Scalar& m12,
+ const Scalar& m20, const Scalar& m21, const Scalar& m22)
+ : vx(m00,m10,m20), vy(m01,m11,m21), vz(m02,m12,m22) {}
+
+ /*! compute the determinant of the matrix */
+ __forceinline const Scalar det() const { return dot(vx,cross(vy,vz)); }
+
+ /*! compute adjoint matrix */
+ __forceinline const LinearSpace3 adjoint() const { return LinearSpace3(cross(vy,vz),cross(vz,vx),cross(vx,vy)).transposed(); }
+
+ /*! compute inverse matrix */
+ __forceinline const LinearSpace3 inverse() const { return adjoint()/det(); }
+
+ /*! compute transposed matrix */
+ __forceinline const LinearSpace3 transposed() const { return LinearSpace3(vx.x,vx.y,vx.z,vy.x,vy.y,vy.z,vz.x,vz.y,vz.z); }
+
+ /*! returns first row of matrix */
+ __forceinline Vector row0() const { return Vector(vx.x,vy.x,vz.x); }
+
+ /*! returns second row of matrix */
+ __forceinline Vector row1() const { return Vector(vx.y,vy.y,vz.y); }
+
+ /*! returns third row of matrix */
+ __forceinline Vector row2() const { return Vector(vx.z,vy.z,vz.z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline LinearSpace3( ZeroTy ) : vx(zero), vy(zero), vz(zero) {}
+ __forceinline LinearSpace3( OneTy ) : vx(one, zero, zero), vy(zero, one, zero), vz(zero, zero, one) {}
+
+ /*! return matrix for scaling */
+ static __forceinline LinearSpace3 scale(const Vector& s) {
+ return LinearSpace3(s.x, 0, 0,
+ 0 , s.y, 0,
+ 0 , 0, s.z);
+ }
+
+ /*! return matrix for rotation around arbitrary axis */
+ static __forceinline LinearSpace3 rotate(const Vector& _u, const Scalar& r) {
+ Vector u = normalize(_u);
+ Scalar s = sin(r), c = cos(r);
+ return LinearSpace3(u.x*u.x+(1-u.x*u.x)*c, u.x*u.y*(1-c)-u.z*s, u.x*u.z*(1-c)+u.y*s,
+ u.x*u.y*(1-c)+u.z*s, u.y*u.y+(1-u.y*u.y)*c, u.y*u.z*(1-c)-u.x*s,
+ u.x*u.z*(1-c)-u.y*s, u.y*u.z*(1-c)+u.x*s, u.z*u.z+(1-u.z*u.z)*c);
+ }
+
+ public:
+
+ /*! the column vectors of the matrix */
+ Vector vx,vy,vz;
+ };
+
+ /*! compute transposed matrix */
+ template<> __forceinline const LinearSpace3<Vec3fa> LinearSpace3<Vec3fa>::transposed() const {
+ vfloat4 rx,ry,rz; transpose((vfloat4&)vx,(vfloat4&)vy,(vfloat4&)vz,vfloat4(zero),rx,ry,rz);
+ return LinearSpace3<Vec3fa>(Vec3fa(rx),Vec3fa(ry),Vec3fa(rz));
+ }
+
+ template<typename T>
+ __forceinline const LinearSpace3<T> transposed(const LinearSpace3<T>& xfm) {
+ return xfm.transposed();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline LinearSpace3<T> operator -( const LinearSpace3<T>& a ) { return LinearSpace3<T>(-a.vx,-a.vy,-a.vz); }
+ template<typename T> __forceinline LinearSpace3<T> operator +( const LinearSpace3<T>& a ) { return LinearSpace3<T>(+a.vx,+a.vy,+a.vz); }
+ template<typename T> __forceinline LinearSpace3<T> rcp ( const LinearSpace3<T>& a ) { return a.inverse(); }
+
+ /* constructs a coordinate frame form a normalized normal */
+ template<typename T> __forceinline LinearSpace3<T> frame(const T& N)
+ {
+ const T dx0(0,N.z,-N.y);
+ const T dx1(-N.z,0,N.x);
+ const T dx = normalize(select(dot(dx0,dx0) > dot(dx1,dx1),dx0,dx1));
+ const T dy = normalize(cross(N,dx));
+ return LinearSpace3<T>(dx,dy,N);
+ }
+
+ /* constructs a coordinate frame from a normal and approximate x-direction */
+ template<typename T> __forceinline LinearSpace3<T> frame(const T& N, const T& dxi)
+ {
+ if (abs(dot(dxi,N)) > 0.99f) return frame(N); // fallback in case N and dxi are very parallel
+ const T dx = normalize(cross(dxi,N));
+ const T dy = normalize(cross(N,dx));
+ return LinearSpace3<T>(dx,dy,N);
+ }
+
+ /* clamps linear space to range -1 to +1 */
+ template<typename T> __forceinline LinearSpace3<T> clamp(const LinearSpace3<T>& space) {
+ return LinearSpace3<T>(clamp(space.vx,T(-1.0f),T(1.0f)),
+ clamp(space.vy,T(-1.0f),T(1.0f)),
+ clamp(space.vz,T(-1.0f),T(1.0f)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline LinearSpace3<T> operator +( const LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return LinearSpace3<T>(a.vx+b.vx,a.vy+b.vy,a.vz+b.vz); }
+ template<typename T> __forceinline LinearSpace3<T> operator -( const LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return LinearSpace3<T>(a.vx-b.vx,a.vy-b.vy,a.vz-b.vz); }
+
+ template<typename T> __forceinline LinearSpace3<T> operator*(const typename T::Scalar & a, const LinearSpace3<T>& b) { return LinearSpace3<T>(a*b.vx, a*b.vy, a*b.vz); }
+ template<typename T> __forceinline T operator*(const LinearSpace3<T>& a, const T & b) { return madd(T(b.x),a.vx,madd(T(b.y),a.vy,T(b.z)*a.vz)); }
+ template<typename T> __forceinline LinearSpace3<T> operator*(const LinearSpace3<T>& a, const LinearSpace3<T>& b) { return LinearSpace3<T>(a*b.vx, a*b.vy, a*b.vz); }
+
+ template<typename T> __forceinline LinearSpace3<T> operator/(const LinearSpace3<T>& a, const typename T::Scalar & b) { return LinearSpace3<T>(a.vx/b, a.vy/b, a.vz/b); }
+ template<typename T> __forceinline LinearSpace3<T> operator/(const LinearSpace3<T>& a, const LinearSpace3<T>& b) { return a * rcp(b); }
+
+ template<typename T> __forceinline LinearSpace3<T>& operator *=( LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return a = a * b; }
+ template<typename T> __forceinline LinearSpace3<T>& operator /=( LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return a = a / b; }
+
+ template<typename T> __forceinline T xfmPoint (const LinearSpace3<T>& s, const T & a) { return madd(T(a.x),s.vx,madd(T(a.y),s.vy,T(a.z)*s.vz)); }
+ template<typename T> __forceinline T xfmVector(const LinearSpace3<T>& s, const T & a) { return madd(T(a.x),s.vx,madd(T(a.y),s.vy,T(a.z)*s.vz)); }
+ template<typename T> __forceinline T xfmNormal(const LinearSpace3<T>& s, const T & a) { return xfmVector(s.inverse().transposed(),a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return a.vx == b.vx && a.vy == b.vy && a.vz == b.vz; }
+ template<typename T> __forceinline bool operator !=( const LinearSpace3<T>& a, const LinearSpace3<T>& b ) { return a.vx != b.vx || a.vy != b.vy || a.vz != b.vz; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline LinearSpace3<T> select ( const typename T::Scalar::Bool& s, const LinearSpace3<T>& t, const LinearSpace3<T>& f ) {
+ return LinearSpace3<T>(select(s,t.vx,f.vx),select(s,t.vy,f.vy),select(s,t.vz,f.vz));
+ }
+
+ /*! blending */
+ template<typename T>
+ __forceinline LinearSpace3<T> lerp(const LinearSpace3<T>& l0, const LinearSpace3<T>& l1, const float t)
+ {
+ return LinearSpace3<T>(lerp(l0.vx,l1.vx,t),
+ lerp(l0.vy,l1.vy,t),
+ lerp(l0.vz,l1.vz,t));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> static embree_ostream operator<<(embree_ostream cout, const LinearSpace3<T>& m) {
+ return cout << "{ vx = " << m.vx << ", vy = " << m.vy << ", vz = " << m.vz << "}";
+ }
+
+ /*! Shortcuts for common linear spaces. */
+ typedef LinearSpace3<Vec3f> LinearSpace3f;
+ typedef LinearSpace3<Vec3fa> LinearSpace3fa;
+ typedef LinearSpace3<Vec3fx> LinearSpace3fx;
+ typedef LinearSpace3<Vec3ff> LinearSpace3ff;
+
+ template<int N> using LinearSpace3vf = LinearSpace3<Vec3<vfloat<N>>>;
+ typedef LinearSpace3<Vec3<vfloat<4>>> LinearSpace3vf4;
+ typedef LinearSpace3<Vec3<vfloat<8>>> LinearSpace3vf8;
+ typedef LinearSpace3<Vec3<vfloat<16>>> LinearSpace3vf16;
+
+ /*! blending */
+ template<typename T, typename S>
+ __forceinline LinearSpace3<T> lerp(const LinearSpace3<T>& l0,
+ const LinearSpace3<T>& l1,
+ const S& t)
+ {
+ return LinearSpace3<T>(lerp(l0.vx,l1.vx,t),
+ lerp(l0.vy,l1.vy,t),
+ lerp(l0.vz,l1.vz,t));
+ }
+
+}
diff --git a/thirdparty/embree/common/math/math.h b/thirdparty/embree/common/math/math.h
new file mode 100644
index 0000000000..4bc54c1a6a
--- /dev/null
+++ b/thirdparty/embree/common/math/math.h
@@ -0,0 +1,369 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/intrinsics.h"
+#include "constants.h"
+#include <cmath>
+
+#if defined(__ARM_NEON)
+#include "../simd/arm/emulation.h"
+#else
+#include <emmintrin.h>
+#include <xmmintrin.h>
+#include <immintrin.h>
+#endif
+
+#if defined(__WIN32__)
+#if defined(_MSC_VER) && (_MSC_VER <= 1700)
+namespace std
+{
+ __forceinline bool isinf ( const float x ) { return _finite(x) == 0; }
+ __forceinline bool isnan ( const float x ) { return _isnan(x) != 0; }
+ __forceinline bool isfinite (const float x) { return _finite(x) != 0; }
+}
+#endif
+#endif
+
+namespace embree
+{
+ __forceinline bool isvalid ( const float& v ) {
+ return (v > -FLT_LARGE) & (v < +FLT_LARGE);
+ }
+
+ __forceinline int cast_f2i(float f) {
+ union { float f; int i; } v; v.f = f; return v.i;
+ }
+
+ __forceinline float cast_i2f(int i) {
+ union { float f; int i; } v; v.i = i; return v.f;
+ }
+
+ __forceinline int toInt (const float& a) { return int(a); }
+ __forceinline float toFloat(const int& a) { return float(a); }
+
+#if defined(__WIN32__)
+ __forceinline bool finite ( const float x ) { return _finite(x) != 0; }
+#endif
+
+ __forceinline float sign ( const float x ) { return x<0?-1.0f:1.0f; }
+ __forceinline float sqr ( const float x ) { return x*x; }
+
+ __forceinline float rcp ( const float x )
+ {
+ const __m128 a = _mm_set_ss(x);
+
+#if defined(__AVX512VL__)
+ const __m128 r = _mm_rcp14_ss(_mm_set_ss(0.0f),a);
+#else
+ const __m128 r = _mm_rcp_ss(a);
+#endif
+
+#if defined(__AVX2__)
+ return _mm_cvtss_f32(_mm_mul_ss(r,_mm_fnmadd_ss(r, a, _mm_set_ss(2.0f))));
+#else
+ return _mm_cvtss_f32(_mm_mul_ss(r,_mm_sub_ss(_mm_set_ss(2.0f), _mm_mul_ss(r, a))));
+#endif
+ }
+
+ __forceinline float signmsk ( const float x ) {
+ return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(0x80000000))));
+ }
+ __forceinline float xorf( const float x, const float y ) {
+ return _mm_cvtss_f32(_mm_xor_ps(_mm_set_ss(x),_mm_set_ss(y)));
+ }
+ __forceinline float andf( const float x, const unsigned y ) {
+ return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(y))));
+ }
+ __forceinline float rsqrt( const float x )
+ {
+ const __m128 a = _mm_set_ss(x);
+#if defined(__AVX512VL__)
+ __m128 r = _mm_rsqrt14_ss(_mm_set_ss(0.0f),a);
+#else
+ __m128 r = _mm_rsqrt_ss(a);
+#endif
+ r = _mm_add_ss(_mm_mul_ss(_mm_set_ss(1.5f), r), _mm_mul_ss(_mm_mul_ss(_mm_mul_ss(a, _mm_set_ss(-0.5f)), r), _mm_mul_ss(r, r)));
+#if defined(__ARM_NEON)
+ r = _mm_add_ss(_mm_mul_ss(_mm_set_ss(1.5f), r), _mm_mul_ss(_mm_mul_ss(_mm_mul_ss(a, _mm_set_ss(-0.5f)), r), _mm_mul_ss(r, r)));
+#endif
+ return _mm_cvtss_f32(r);
+ }
+
+#if defined(__WIN32__) && defined(_MSC_VER) && (_MSC_VER <= 1700)
+ __forceinline float nextafter(float x, float y) { if ((x<y) == (x>0)) return x*(1.1f+float(ulp)); else return x*(0.9f-float(ulp)); }
+ __forceinline double nextafter(double x, double y) { return _nextafter(x, y); }
+ __forceinline int roundf(float f) { return (int)(f + 0.5f); }
+#else
+ __forceinline float nextafter(float x, float y) { return ::nextafterf(x, y); }
+ __forceinline double nextafter(double x, double y) { return ::nextafter(x, y); }
+#endif
+
+ __forceinline float abs ( const float x ) { return ::fabsf(x); }
+ __forceinline float acos ( const float x ) { return ::acosf (x); }
+ __forceinline float asin ( const float x ) { return ::asinf (x); }
+ __forceinline float atan ( const float x ) { return ::atanf (x); }
+ __forceinline float atan2( const float y, const float x ) { return ::atan2f(y, x); }
+ __forceinline float cos ( const float x ) { return ::cosf (x); }
+ __forceinline float cosh ( const float x ) { return ::coshf (x); }
+ __forceinline float exp ( const float x ) { return ::expf (x); }
+ __forceinline float fmod ( const float x, const float y ) { return ::fmodf (x, y); }
+ __forceinline float log ( const float x ) { return ::logf (x); }
+ __forceinline float log10( const float x ) { return ::log10f(x); }
+ __forceinline float pow ( const float x, const float y ) { return ::powf (x, y); }
+ __forceinline float sin ( const float x ) { return ::sinf (x); }
+ __forceinline float sinh ( const float x ) { return ::sinhf (x); }
+ __forceinline float sqrt ( const float x ) { return ::sqrtf (x); }
+ __forceinline float tan ( const float x ) { return ::tanf (x); }
+ __forceinline float tanh ( const float x ) { return ::tanhf (x); }
+ __forceinline float floor( const float x ) { return ::floorf (x); }
+ __forceinline float ceil ( const float x ) { return ::ceilf (x); }
+ __forceinline float frac ( const float x ) { return x-floor(x); }
+
+ __forceinline double abs ( const double x ) { return ::fabs(x); }
+ __forceinline double sign ( const double x ) { return x<0?-1.0:1.0; }
+ __forceinline double acos ( const double x ) { return ::acos (x); }
+ __forceinline double asin ( const double x ) { return ::asin (x); }
+ __forceinline double atan ( const double x ) { return ::atan (x); }
+ __forceinline double atan2( const double y, const double x ) { return ::atan2(y, x); }
+ __forceinline double cos ( const double x ) { return ::cos (x); }
+ __forceinline double cosh ( const double x ) { return ::cosh (x); }
+ __forceinline double exp ( const double x ) { return ::exp (x); }
+ __forceinline double fmod ( const double x, const double y ) { return ::fmod (x, y); }
+ __forceinline double log ( const double x ) { return ::log (x); }
+ __forceinline double log10( const double x ) { return ::log10(x); }
+ __forceinline double pow ( const double x, const double y ) { return ::pow (x, y); }
+ __forceinline double rcp ( const double x ) { return 1.0/x; }
+ __forceinline double rsqrt( const double x ) { return 1.0/::sqrt(x); }
+ __forceinline double sin ( const double x ) { return ::sin (x); }
+ __forceinline double sinh ( const double x ) { return ::sinh (x); }
+ __forceinline double sqr ( const double x ) { return x*x; }
+ __forceinline double sqrt ( const double x ) { return ::sqrt (x); }
+ __forceinline double tan ( const double x ) { return ::tan (x); }
+ __forceinline double tanh ( const double x ) { return ::tanh (x); }
+ __forceinline double floor( const double x ) { return ::floor (x); }
+ __forceinline double ceil ( const double x ) { return ::ceil (x); }
+
+#if defined(__SSE4_1__)
+ __forceinline float mini(float a, float b) {
+ const __m128i ai = _mm_castps_si128(_mm_set_ss(a));
+ const __m128i bi = _mm_castps_si128(_mm_set_ss(b));
+ const __m128i ci = _mm_min_epi32(ai,bi);
+ return _mm_cvtss_f32(_mm_castsi128_ps(ci));
+ }
+#endif
+
+#if defined(__SSE4_1__)
+ __forceinline float maxi(float a, float b) {
+ const __m128i ai = _mm_castps_si128(_mm_set_ss(a));
+ const __m128i bi = _mm_castps_si128(_mm_set_ss(b));
+ const __m128i ci = _mm_max_epi32(ai,bi);
+ return _mm_cvtss_f32(_mm_castsi128_ps(ci));
+ }
+#endif
+
+ template<typename T>
+ __forceinline T twice(const T& a) { return a+a; }
+
+ __forceinline int min(int a, int b) { return a<b ? a:b; }
+ __forceinline unsigned min(unsigned a, unsigned b) { return a<b ? a:b; }
+ __forceinline int64_t min(int64_t a, int64_t b) { return a<b ? a:b; }
+ __forceinline float min(float a, float b) { return a<b ? a:b; }
+ __forceinline double min(double a, double b) { return a<b ? a:b; }
+#if defined(__64BIT__)
+ __forceinline size_t min(size_t a, size_t b) { return a<b ? a:b; }
+#endif
+
+ template<typename T> __forceinline T min(const T& a, const T& b, const T& c) { return min(min(a,b),c); }
+ template<typename T> __forceinline T min(const T& a, const T& b, const T& c, const T& d) { return min(min(a,b),min(c,d)); }
+ template<typename T> __forceinline T min(const T& a, const T& b, const T& c, const T& d, const T& e) { return min(min(min(a,b),min(c,d)),e); }
+
+ template<typename T> __forceinline T mini(const T& a, const T& b, const T& c) { return mini(mini(a,b),c); }
+ template<typename T> __forceinline T mini(const T& a, const T& b, const T& c, const T& d) { return mini(mini(a,b),mini(c,d)); }
+ template<typename T> __forceinline T mini(const T& a, const T& b, const T& c, const T& d, const T& e) { return mini(mini(mini(a,b),mini(c,d)),e); }
+
+ __forceinline int max(int a, int b) { return a<b ? b:a; }
+ __forceinline unsigned max(unsigned a, unsigned b) { return a<b ? b:a; }
+ __forceinline int64_t max(int64_t a, int64_t b) { return a<b ? b:a; }
+ __forceinline float max(float a, float b) { return a<b ? b:a; }
+ __forceinline double max(double a, double b) { return a<b ? b:a; }
+#if defined(__64BIT__)
+ __forceinline size_t max(size_t a, size_t b) { return a<b ? b:a; }
+#endif
+
+ template<typename T> __forceinline T max(const T& a, const T& b, const T& c) { return max(max(a,b),c); }
+ template<typename T> __forceinline T max(const T& a, const T& b, const T& c, const T& d) { return max(max(a,b),max(c,d)); }
+ template<typename T> __forceinline T max(const T& a, const T& b, const T& c, const T& d, const T& e) { return max(max(max(a,b),max(c,d)),e); }
+
+ template<typename T> __forceinline T maxi(const T& a, const T& b, const T& c) { return maxi(maxi(a,b),c); }
+ template<typename T> __forceinline T maxi(const T& a, const T& b, const T& c, const T& d) { return maxi(maxi(a,b),maxi(c,d)); }
+ template<typename T> __forceinline T maxi(const T& a, const T& b, const T& c, const T& d, const T& e) { return maxi(maxi(maxi(a,b),maxi(c,d)),e); }
+
+#if defined(__MACOSX__)
+ __forceinline ssize_t min(ssize_t a, ssize_t b) { return a<b ? a:b; }
+ __forceinline ssize_t max(ssize_t a, ssize_t b) { return a<b ? b:a; }
+#endif
+
+#if defined(__MACOSX__) && !defined(__INTEL_COMPILER)
+ __forceinline void sincosf(float x, float *sin, float *cos) {
+ __sincosf(x,sin,cos);
+ }
+#endif
+
+#if defined(__WIN32__) || defined(__FreeBSD__)
+ __forceinline void sincosf(float x, float *s, float *c) {
+ *s = sinf(x); *c = cosf(x);
+ }
+#endif
+
+ template<typename T> __forceinline T clamp(const T& x, const T& lower = T(zero), const T& upper = T(one)) { return max(min(x,upper),lower); }
+ template<typename T> __forceinline T clampz(const T& x, const T& upper) { return max(T(zero), min(x,upper)); }
+
+ template<typename T> __forceinline T deg2rad ( const T& x ) { return x * T(1.74532925199432957692e-2f); }
+ template<typename T> __forceinline T rad2deg ( const T& x ) { return x * T(5.72957795130823208768e1f); }
+ template<typename T> __forceinline T sin2cos ( const T& x ) { return sqrt(max(T(zero),T(one)-x*x)); }
+ template<typename T> __forceinline T cos2sin ( const T& x ) { return sin2cos(x); }
+
+#if defined(__AVX2__)
+ __forceinline float madd ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fmadd_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
+ __forceinline float msub ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fmsub_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
+ __forceinline float nmadd ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fnmadd_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
+ __forceinline float nmsub ( const float a, const float b, const float c) { return _mm_cvtss_f32(_mm_fnmsub_ss(_mm_set_ss(a),_mm_set_ss(b),_mm_set_ss(c))); }
+#else
+ __forceinline float madd ( const float a, const float b, const float c) { return a*b+c; }
+ __forceinline float msub ( const float a, const float b, const float c) { return a*b-c; }
+ __forceinline float nmadd ( const float a, const float b, const float c) { return -a*b+c;}
+ __forceinline float nmsub ( const float a, const float b, const float c) { return -a*b-c; }
+#endif
+
+ /*! random functions */
+ template<typename T> T random() { return T(0); }
+#if defined(_WIN32)
+ template<> __forceinline int random() { return int(rand()) ^ (int(rand()) << 8) ^ (int(rand()) << 16); }
+ template<> __forceinline uint32_t random() { return uint32_t(rand()) ^ (uint32_t(rand()) << 8) ^ (uint32_t(rand()) << 16); }
+#else
+ template<> __forceinline int random() { return int(rand()); }
+ template<> __forceinline uint32_t random() { return uint32_t(rand()) ^ (uint32_t(rand()) << 16); }
+#endif
+ template<> __forceinline float random() { return rand()/float(RAND_MAX); }
+ template<> __forceinline double random() { return rand()/double(RAND_MAX); }
+
+#if _WIN32
+ __forceinline double drand48() {
+ return double(rand())/double(RAND_MAX);
+ }
+
+ __forceinline void srand48(long seed) {
+ return srand(seed);
+ }
+#endif
+
+ /*! selects */
+ __forceinline bool select(bool s, bool t , bool f) { return s ? t : f; }
+ __forceinline int select(bool s, int t, int f) { return s ? t : f; }
+ __forceinline float select(bool s, float t, float f) { return s ? t : f; }
+
+ __forceinline bool all(bool s) { return s; }
+
+ __forceinline float lerp(const float v0, const float v1, const float t) {
+ return madd(1.0f-t,v0,t*v1);
+ }
+
+ template<typename T>
+ __forceinline T lerp2(const float x0, const float x1, const float x2, const float x3, const T& u, const T& v) {
+ return madd((1.0f-u),madd((1.0f-v),T(x0),v*T(x2)),u*madd((1.0f-v),T(x1),v*T(x3)));
+ }
+
+ /*! exchange */
+ template<typename T> __forceinline void xchg ( T& a, T& b ) { const T tmp = a; a = b; b = tmp; }
+
+ /* load/store */
+ template<typename Ty> struct mem;
+
+ template<> struct mem<float> {
+ static __forceinline float load (bool mask, const void* ptr) { return mask ? *(float*)ptr : 0.0f; }
+ static __forceinline float loadu(bool mask, const void* ptr) { return mask ? *(float*)ptr : 0.0f; }
+
+ static __forceinline void store (bool mask, void* ptr, const float v) { if (mask) *(float*)ptr = v; }
+ static __forceinline void storeu(bool mask, void* ptr, const float v) { if (mask) *(float*)ptr = v; }
+ };
+
+ /*! bit reverse operation */
+ template<class T>
+ __forceinline T bitReverse(const T& vin)
+ {
+ T v = vin;
+ v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
+ v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
+ v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
+ v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
+ v = ( v >> 16 ) | ( v << 16);
+ return v;
+ }
+
+ /*! bit interleave operation */
+ template<class T>
+ __forceinline T bitInterleave(const T& xin, const T& yin, const T& zin)
+ {
+ T x = xin, y = yin, z = zin;
+ x = (x | (x << 16)) & 0x030000FF;
+ x = (x | (x << 8)) & 0x0300F00F;
+ x = (x | (x << 4)) & 0x030C30C3;
+ x = (x | (x << 2)) & 0x09249249;
+
+ y = (y | (y << 16)) & 0x030000FF;
+ y = (y | (y << 8)) & 0x0300F00F;
+ y = (y | (y << 4)) & 0x030C30C3;
+ y = (y | (y << 2)) & 0x09249249;
+
+ z = (z | (z << 16)) & 0x030000FF;
+ z = (z | (z << 8)) & 0x0300F00F;
+ z = (z | (z << 4)) & 0x030C30C3;
+ z = (z | (z << 2)) & 0x09249249;
+
+ return x | (y << 1) | (z << 2);
+ }
+
+#if defined(__AVX2__)
+
+ template<>
+ __forceinline unsigned int bitInterleave(const unsigned int &xi, const unsigned int& yi, const unsigned int& zi)
+ {
+ const unsigned int xx = pdep(xi,0x49249249 /* 0b01001001001001001001001001001001 */ );
+ const unsigned int yy = pdep(yi,0x92492492 /* 0b10010010010010010010010010010010 */);
+ const unsigned int zz = pdep(zi,0x24924924 /* 0b00100100100100100100100100100100 */);
+ return xx | yy | zz;
+ }
+
+#endif
+
+ /*! bit interleave operation for 64bit data types*/
+ template<class T>
+ __forceinline T bitInterleave64(const T& xin, const T& yin, const T& zin){
+ T x = xin & 0x1fffff;
+ T y = yin & 0x1fffff;
+ T z = zin & 0x1fffff;
+
+ x = (x | x << 32) & 0x1f00000000ffff;
+ x = (x | x << 16) & 0x1f0000ff0000ff;
+ x = (x | x << 8) & 0x100f00f00f00f00f;
+ x = (x | x << 4) & 0x10c30c30c30c30c3;
+ x = (x | x << 2) & 0x1249249249249249;
+
+ y = (y | y << 32) & 0x1f00000000ffff;
+ y = (y | y << 16) & 0x1f0000ff0000ff;
+ y = (y | y << 8) & 0x100f00f00f00f00f;
+ y = (y | y << 4) & 0x10c30c30c30c30c3;
+ y = (y | y << 2) & 0x1249249249249249;
+
+ z = (z | z << 32) & 0x1f00000000ffff;
+ z = (z | z << 16) & 0x1f0000ff0000ff;
+ z = (z | z << 8) & 0x100f00f00f00f00f;
+ z = (z | z << 4) & 0x10c30c30c30c30c3;
+ z = (z | z << 2) & 0x1249249249249249;
+
+ return x | (y << 1) | (z << 2);
+ }
+}
diff --git a/thirdparty/embree/common/math/obbox.h b/thirdparty/embree/common/math/obbox.h
new file mode 100644
index 0000000000..2fe8bbf071
--- /dev/null
+++ b/thirdparty/embree/common/math/obbox.h
@@ -0,0 +1,39 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bbox.h"
+#include "linearspace3.h"
+
+namespace embree
+{
+ /*! Oriented bounding box */
+ template<typename T>
+ struct OBBox
+ {
+ public:
+
+ __forceinline OBBox () {}
+
+ __forceinline OBBox (EmptyTy)
+ : space(one), bounds(empty) {}
+
+ __forceinline OBBox (const BBox<T>& bounds)
+ : space(one), bounds(bounds) {}
+
+ __forceinline OBBox (const LinearSpace3<T>& space, const BBox<T>& bounds)
+ : space(space), bounds(bounds) {}
+
+ friend embree_ostream operator<<(embree_ostream cout, const OBBox& p) {
+ return cout << "{ space = " << p.space << ", bounds = " << p.bounds << "}";
+ }
+
+ public:
+ LinearSpace3<T> space; //!< orthonormal transformation
+ BBox<T> bounds; //!< bounds in transformed space
+ };
+
+ typedef OBBox<Vec3f> OBBox3f;
+ typedef OBBox<Vec3fa> OBBox3fa;
+}
diff --git a/thirdparty/embree/common/math/quaternion.h b/thirdparty/embree/common/math/quaternion.h
new file mode 100644
index 0000000000..080800efcd
--- /dev/null
+++ b/thirdparty/embree/common/math/quaternion.h
@@ -0,0 +1,254 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "vec3.h"
+#include "vec4.h"
+
+#include "transcendental.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////
+ // Quaternion Struct
+ ////////////////////////////////////////////////////////////////
+
+ template<typename T>
+ struct QuaternionT
+ {
+ typedef Vec3<T> Vector;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline QuaternionT () { }
+ __forceinline QuaternionT ( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; }
+ __forceinline QuaternionT& operator=( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; return *this; }
+
+ __forceinline QuaternionT( const T& r ) : r(r), i(zero), j(zero), k(zero) {}
+ __forceinline explicit QuaternionT( const Vec3<T>& v ) : r(zero), i(v.x), j(v.y), k(v.z) {}
+ __forceinline explicit QuaternionT( const Vec4<T>& v ) : r(v.x), i(v.y), j(v.z), k(v.w) {}
+ __forceinline QuaternionT( const T& r, const T& i, const T& j, const T& k ) : r(r), i(i), j(j), k(k) {}
+ __forceinline QuaternionT( const T& r, const Vec3<T>& v ) : r(r), i(v.x), j(v.y), k(v.z) {}
+
+ __inline QuaternionT( const Vec3<T>& vx, const Vec3<T>& vy, const Vec3<T>& vz );
+ __inline QuaternionT( const T& yaw, const T& pitch, const T& roll );
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline QuaternionT( ZeroTy ) : r(zero), i(zero), j(zero), k(zero) {}
+ __forceinline QuaternionT( OneTy ) : r( one), i(zero), j(zero), k(zero) {}
+
+ /*! return quaternion for rotation around arbitrary axis */
+ static __forceinline QuaternionT rotate(const Vec3<T>& u, const T& r) {
+ return QuaternionT<T>(cos(T(0.5)*r),sin(T(0.5)*r)*normalize(u));
+ }
+
+ /*! returns the rotation axis of the quaternion as a vector */
+ __forceinline Vec3<T> v( ) const { return Vec3<T>(i, j, k); }
+
+ public:
+ T r, i, j, k;
+ };
+
+ template<typename T> __forceinline QuaternionT<T> operator *( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a * b.r, a * b.i, a * b.j, a * b.k); }
+ template<typename T> __forceinline QuaternionT<T> operator *( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r * b, a.i * b, a.j * b, a.k * b); }
+
+ ////////////////////////////////////////////////////////////////
+ // Unary Operators
+ ////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a ) { return QuaternionT<T>(+a.r, +a.i, +a.j, +a.k); }
+ template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a ) { return QuaternionT<T>(-a.r, -a.i, -a.j, -a.k); }
+ template<typename T> __forceinline QuaternionT<T> conj ( const QuaternionT<T>& a ) { return QuaternionT<T>(a.r, -a.i, -a.j, -a.k); }
+ template<typename T> __forceinline T abs ( const QuaternionT<T>& a ) { return sqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }
+ template<typename T> __forceinline QuaternionT<T> rcp ( const QuaternionT<T>& a ) { return conj(a)*rcp(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }
+ template<typename T> __forceinline QuaternionT<T> normalize ( const QuaternionT<T>& a ) { return a*rsqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }
+
+ // evaluates a*q-r
+ template<typename T> __forceinline QuaternionT<T>
+ msub(const T& a, const QuaternionT<T>& q, const QuaternionT<T>& p)
+ {
+ return QuaternionT<T>(msub(a, q.r, p.r),
+ msub(a, q.i, p.i),
+ msub(a, q.j, p.j),
+ msub(a, q.k, p.k));
+ }
+ // evaluates a*q-r
+ template<typename T> __forceinline QuaternionT<T>
+ madd (const T& a, const QuaternionT<T>& q, const QuaternionT<T>& p)
+ {
+ return QuaternionT<T>(madd(a, q.r, p.r),
+ madd(a, q.i, p.i),
+ madd(a, q.j, p.j),
+ madd(a, q.k, p.k));
+ }
+
+ ////////////////////////////////////////////////////////////////
+ // Binary Operators
+ ////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline QuaternionT<T> operator +( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a + b.r, b.i, b.j, b.k); }
+ template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r + b, a.i, a.j, a.k); }
+ template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return QuaternionT<T>(a.r + b.r, a.i + b.i, a.j + b.j, a.k + b.k); }
+ template<typename T> __forceinline QuaternionT<T> operator -( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a - b.r, -b.i, -b.j, -b.k); }
+ template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r - b, a.i, a.j, a.k); }
+ template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return QuaternionT<T>(a.r - b.r, a.i - b.i, a.j - b.j, a.k - b.k); }
+
+ template<typename T> __forceinline Vec3<T> operator *( const QuaternionT<T>& a, const Vec3<T> & b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }
+ template<typename T> __forceinline QuaternionT<T> operator *( const QuaternionT<T>& a, const QuaternionT<T>& b ) {
+ return QuaternionT<T>(a.r*b.r - a.i*b.i - a.j*b.j - a.k*b.k,
+ a.r*b.i + a.i*b.r + a.j*b.k - a.k*b.j,
+ a.r*b.j - a.i*b.k + a.j*b.r + a.k*b.i,
+ a.r*b.k + a.i*b.j - a.j*b.i + a.k*b.r);
+ }
+ template<typename T> __forceinline QuaternionT<T> operator /( const T & a, const QuaternionT<T>& b ) { return a*rcp(b); }
+ template<typename T> __forceinline QuaternionT<T> operator /( const QuaternionT<T>& a, const T & b ) { return a*rcp(b); }
+ template<typename T> __forceinline QuaternionT<T> operator /( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a*rcp(b); }
+
+ template<typename T> __forceinline QuaternionT<T>& operator +=( QuaternionT<T>& a, const T & b ) { return a = a+b; }
+ template<typename T> __forceinline QuaternionT<T>& operator +=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a+b; }
+ template<typename T> __forceinline QuaternionT<T>& operator -=( QuaternionT<T>& a, const T & b ) { return a = a-b; }
+ template<typename T> __forceinline QuaternionT<T>& operator -=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a-b; }
+ template<typename T> __forceinline QuaternionT<T>& operator *=( QuaternionT<T>& a, const T & b ) { return a = a*b; }
+ template<typename T> __forceinline QuaternionT<T>& operator *=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a*b; }
+ template<typename T> __forceinline QuaternionT<T>& operator /=( QuaternionT<T>& a, const T & b ) { return a = a*rcp(b); }
+ template<typename T> __forceinline QuaternionT<T>& operator /=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a*rcp(b); }
+
+ template<typename T, typename M> __forceinline QuaternionT<T>
+ select(const M& m, const QuaternionT<T>& q, const QuaternionT<T>& p)
+ {
+ return QuaternionT<T>(select(m, q.r, p.r),
+ select(m, q.i, p.i),
+ select(m, q.j, p.j),
+ select(m, q.k, p.k));
+ }
+
+
+ template<typename T> __forceinline Vec3<T> xfmPoint ( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }
+ template<typename T> __forceinline Vec3<T> xfmVector( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }
+ template<typename T> __forceinline Vec3<T> xfmNormal( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }
+
+ template<typename T> __forceinline T dot(const QuaternionT<T>& a, const QuaternionT<T>& b) { return a.r*b.r + a.i*b.i + a.j*b.j + a.k*b.k; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a.r == b.r && a.i == b.i && a.j == b.j && a.k == b.k; }
+ template<typename T> __forceinline bool operator !=( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a.r != b.r || a.i != b.i || a.j != b.j || a.k != b.k; }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Orientation Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> QuaternionT<T>::QuaternionT( const Vec3<T>& vx, const Vec3<T>& vy, const Vec3<T>& vz )
+ {
+ if ( vx.x + vy.y + vz.z >= T(zero) )
+ {
+ const T t = T(one) + (vx.x + vy.y + vz.z);
+ const T s = rsqrt(t)*T(0.5f);
+ r = t*s;
+ i = (vy.z - vz.y)*s;
+ j = (vz.x - vx.z)*s;
+ k = (vx.y - vy.x)*s;
+ }
+ else if ( vx.x >= max(vy.y, vz.z) )
+ {
+ const T t = (T(one) + vx.x) - (vy.y + vz.z);
+ const T s = rsqrt(t)*T(0.5f);
+ r = (vy.z - vz.y)*s;
+ i = t*s;
+ j = (vx.y + vy.x)*s;
+ k = (vz.x + vx.z)*s;
+ }
+ else if ( vy.y >= vz.z ) // if ( vy.y >= max(vz.z, vx.x) )
+ {
+ const T t = (T(one) + vy.y) - (vz.z + vx.x);
+ const T s = rsqrt(t)*T(0.5f);
+ r = (vz.x - vx.z)*s;
+ i = (vx.y + vy.x)*s;
+ j = t*s;
+ k = (vy.z + vz.y)*s;
+ }
+ else //if ( vz.z >= max(vy.y, vx.x) )
+ {
+ const T t = (T(one) + vz.z) - (vx.x + vy.y);
+ const T s = rsqrt(t)*T(0.5f);
+ r = (vx.y - vy.x)*s;
+ i = (vz.x + vx.z)*s;
+ j = (vy.z + vz.y)*s;
+ k = t*s;
+ }
+ }
+
+ template<typename T> QuaternionT<T>::QuaternionT( const T& yaw, const T& pitch, const T& roll )
+ {
+ const T cya = cos(yaw *T(0.5f));
+ const T cpi = cos(pitch*T(0.5f));
+ const T cro = cos(roll *T(0.5f));
+ const T sya = sin(yaw *T(0.5f));
+ const T spi = sin(pitch*T(0.5f));
+ const T sro = sin(roll *T(0.5f));
+ r = cro*cya*cpi + sro*sya*spi;
+ i = cro*cya*spi + sro*sya*cpi;
+ j = cro*sya*cpi - sro*cya*spi;
+ k = sro*cya*cpi - cro*sya*spi;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ //////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> static embree_ostream operator<<(embree_ostream cout, const QuaternionT<T>& q) {
+ return cout << "{ r = " << q.r << ", i = " << q.i << ", j = " << q.j << ", k = " << q.k << " }";
+ }
+
+ /*! default template instantiations */
+ typedef QuaternionT<float> Quaternion3f;
+ typedef QuaternionT<double> Quaternion3d;
+
+ template<int N> using Quaternion3vf = QuaternionT<vfloat<N>>;
+ typedef QuaternionT<vfloat<4>> Quaternion3vf4;
+ typedef QuaternionT<vfloat<8>> Quaternion3vf8;
+ typedef QuaternionT<vfloat<16>> Quaternion3vf16;
+
+ //////////////////////////////////////////////////////////////////////////////
+ /// Interpolation
+ //////////////////////////////////////////////////////////////////////////////
+ template<typename T>
+ __forceinline QuaternionT<T>lerp(const QuaternionT<T>& q0,
+ const QuaternionT<T>& q1,
+ const T& factor)
+ {
+ QuaternionT<T> q;
+ q.r = lerp(q0.r, q1.r, factor);
+ q.i = lerp(q0.i, q1.i, factor);
+ q.j = lerp(q0.j, q1.j, factor);
+ q.k = lerp(q0.k, q1.k, factor);
+ return q;
+ }
+
+ template<typename T>
+ __forceinline QuaternionT<T> slerp(const QuaternionT<T>& q0,
+ const QuaternionT<T>& q1_,
+ const T& t)
+ {
+ T cosTheta = dot(q0, q1_);
+ QuaternionT<T> q1 = select(cosTheta < 0.f, -q1_, q1_);
+ cosTheta = select(cosTheta < 0.f, -cosTheta, cosTheta);
+ if (unlikely(all(cosTheta > 0.9995f))) {
+ return normalize(lerp(q0, q1, t));
+ }
+ const T phi = t * fastapprox::acos(cosTheta);
+ T sinPhi, cosPhi;
+ fastapprox::sincos(phi, sinPhi, cosPhi);
+ QuaternionT<T> qperp = sinPhi * normalize(msub(cosTheta, q0, q1));
+ return msub(cosPhi, q0, qperp);
+ }
+}
diff --git a/thirdparty/embree/common/math/range.h b/thirdparty/embree/common/math/range.h
new file mode 100644
index 0000000000..909fadb995
--- /dev/null
+++ b/thirdparty/embree/common/math/range.h
@@ -0,0 +1,137 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../math/math.h"
+
+namespace embree
+{
+ template<typename Ty>
+ struct range
+ {
+ __forceinline range() {}
+
+ __forceinline range(const Ty& begin)
+ : _begin(begin), _end(begin+1) {}
+
+ __forceinline range(const Ty& begin, const Ty& end)
+ : _begin(begin), _end(end) {}
+
+ __forceinline range(const range& other)
+ : _begin(other._begin), _end(other._end) {}
+
+ template<typename T1>
+ __forceinline range(const range<T1>& other)
+ : _begin(Ty(other._begin)), _end(Ty(other._end)) {}
+
+ template<typename T1>
+ __forceinline range& operator =(const range<T1>& other) {
+ _begin = other._begin;
+ _end = other._end;
+ return *this;
+ }
+
+ __forceinline Ty begin() const {
+ return _begin;
+ }
+
+ __forceinline Ty end() const {
+ return _end;
+ }
+
+ __forceinline range intersect(const range& r) const {
+ return range (max(_begin,r._begin),min(_end,r._end));
+ }
+
+ __forceinline Ty size() const {
+ return _end - _begin;
+ }
+
+ __forceinline bool empty() const {
+ return _end <= _begin;
+ }
+
+ __forceinline Ty center() const {
+ return (_begin + _end)/2;
+ }
+
+ __forceinline std::pair<range,range> split() const
+ {
+ const Ty _center = center();
+ return std::make_pair(range(_begin,_center),range(_center,_end));
+ }
+
+ __forceinline void split(range& left_o, range& right_o) const
+ {
+ const Ty _center = center();
+ left_o = range(_begin,_center);
+ right_o = range(_center,_end);
+ }
+
+ __forceinline friend bool operator< (const range& r0, const range& r1) {
+ return r0.size() < r1.size();
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const range& r) {
+ return cout << "range [" << r.begin() << ", " << r.end() << "]";
+ }
+
+ Ty _begin, _end;
+ };
+
+ template<typename Ty>
+ range<Ty> make_range(const Ty& begin, const Ty& end) {
+ return range<Ty>(begin,end);
+ }
+
+ template<typename Ty>
+ struct extended_range : public range<Ty>
+ {
+ __forceinline extended_range () {}
+
+ __forceinline extended_range (const Ty& begin)
+ : range<Ty>(begin), _ext_end(begin+1) {}
+
+ __forceinline extended_range (const Ty& begin, const Ty& end)
+ : range<Ty>(begin,end), _ext_end(end) {}
+
+ __forceinline extended_range (const Ty& begin, const Ty& end, const Ty& ext_end)
+ : range<Ty>(begin,end), _ext_end(ext_end) {}
+
+ __forceinline Ty ext_end() const {
+ return _ext_end;
+ }
+
+ __forceinline Ty ext_size() const {
+ return _ext_end - range<Ty>::_begin;
+ }
+
+ __forceinline Ty ext_range_size() const {
+ return _ext_end - range<Ty>::_end;
+ }
+
+ __forceinline bool has_ext_range() const {
+ assert(_ext_end >= range<Ty>::_end);
+ return (_ext_end - range<Ty>::_end) > 0;
+ }
+
+ __forceinline void set_ext_range(const size_t ext_end){
+ assert(ext_end >= range<Ty>::_end);
+ _ext_end = ext_end;
+ }
+
+ __forceinline void move_right(const size_t plus){
+ range<Ty>::_begin += plus;
+ range<Ty>::_end += plus;
+ _ext_end += plus;
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const extended_range& r) {
+ return cout << "extended_range [" << r.begin() << ", " << r.end() << " (" << r.ext_end() << ")]";
+ }
+
+ Ty _ext_end;
+ };
+}
diff --git a/thirdparty/embree/common/math/transcendental.h b/thirdparty/embree/common/math/transcendental.h
new file mode 100644
index 0000000000..fd16c26e81
--- /dev/null
+++ b/thirdparty/embree/common/math/transcendental.h
@@ -0,0 +1,525 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+// Transcendental functions from "ispc": https://github.com/ispc/ispc/
+// Most of the transcendental implementations in ispc code come from
+// Solomon Boulos's "syrah": https://github.com/boulos/syrah/
+
+#include "../simd/simd.h"
+
+namespace embree
+{
+
+namespace fastapprox
+{
+
+template <typename T>
+__forceinline T sin(const T &v)
+{
+ static const float piOverTwoVec = 1.57079637050628662109375;
+ static const float twoOverPiVec = 0.636619746685028076171875;
+ auto scaled = v * twoOverPiVec;
+ auto kReal = floor(scaled);
+ auto k = toInt(kReal);
+
+ // Reduced range version of x
+ auto x = v - kReal * piOverTwoVec;
+ auto kMod4 = k & 3;
+ auto sinUseCos = (kMod4 == 1 | kMod4 == 3);
+ auto flipSign = (kMod4 > 1);
+
+ // These coefficients are from sollya with fpminimax(sin(x)/x, [|0, 2,
+ // 4, 6, 8, 10|], [|single...|], [0;Pi/2]);
+ static const float sinC2 = -0.16666667163372039794921875;
+ static const float sinC4 = +8.333347737789154052734375e-3;
+ static const float sinC6 = -1.9842604524455964565277099609375e-4;
+ static const float sinC8 = +2.760012648650445044040679931640625e-6;
+ static const float sinC10 = -2.50293279435709337121807038784027099609375e-8;
+
+ static const float cosC2 = -0.5;
+ static const float cosC4 = +4.166664183139801025390625e-2;
+ static const float cosC6 = -1.388833043165504932403564453125e-3;
+ static const float cosC8 = +2.47562347794882953166961669921875e-5;
+ static const float cosC10 = -2.59630184018533327616751194000244140625e-7;
+
+ auto outside = select(sinUseCos, 1., x);
+ auto c2 = select(sinUseCos, T(cosC2), T(sinC2));
+ auto c4 = select(sinUseCos, T(cosC4), T(sinC4));
+ auto c6 = select(sinUseCos, T(cosC6), T(sinC6));
+ auto c8 = select(sinUseCos, T(cosC8), T(sinC8));
+ auto c10 = select(sinUseCos, T(cosC10), T(sinC10));
+
+ auto x2 = x * x;
+ auto formula = x2 * c10 + c8;
+ formula = x2 * formula + c6;
+ formula = x2 * formula + c4;
+ formula = x2 * formula + c2;
+ formula = x2 * formula + 1.;
+ formula *= outside;
+
+ formula = select(flipSign, -formula, formula);
+ return formula;
+}
+
+template <typename T>
+__forceinline T cos(const T &v)
+{
+ static const float piOverTwoVec = 1.57079637050628662109375;
+ static const float twoOverPiVec = 0.636619746685028076171875;
+ auto scaled = v * twoOverPiVec;
+ auto kReal = floor(scaled);
+ auto k = toInt(kReal);
+
+ // Reduced range version of x
+ auto x = v - kReal * piOverTwoVec;
+
+ auto kMod4 = k & 3;
+ auto cosUseCos = (kMod4 == 0 | kMod4 == 2);
+ auto flipSign = (kMod4 == 1 | kMod4 == 2);
+
+ const float sinC2 = -0.16666667163372039794921875;
+ const float sinC4 = +8.333347737789154052734375e-3;
+ const float sinC6 = -1.9842604524455964565277099609375e-4;
+ const float sinC8 = +2.760012648650445044040679931640625e-6;
+ const float sinC10 = -2.50293279435709337121807038784027099609375e-8;
+
+ const float cosC2 = -0.5;
+ const float cosC4 = +4.166664183139801025390625e-2;
+ const float cosC6 = -1.388833043165504932403564453125e-3;
+ const float cosC8 = +2.47562347794882953166961669921875e-5;
+ const float cosC10 = -2.59630184018533327616751194000244140625e-7;
+
+ auto outside = select(cosUseCos, 1., x);
+ auto c2 = select(cosUseCos, T(cosC2), T(sinC2));
+ auto c4 = select(cosUseCos, T(cosC4), T(sinC4));
+ auto c6 = select(cosUseCos, T(cosC6), T(sinC6));
+ auto c8 = select(cosUseCos, T(cosC8), T(sinC8));
+ auto c10 = select(cosUseCos, T(cosC10), T(sinC10));
+
+ auto x2 = x * x;
+ auto formula = x2 * c10 + c8;
+ formula = x2 * formula + c6;
+ formula = x2 * formula + c4;
+ formula = x2 * formula + c2;
+ formula = x2 * formula + 1.;
+ formula *= outside;
+
+ formula = select(flipSign, -formula, formula);
+ return formula;
+}
+
+template <typename T>
+__forceinline void sincos(const T &v, T &sinResult, T &cosResult)
+{
+ const float piOverTwoVec = 1.57079637050628662109375;
+ const float twoOverPiVec = 0.636619746685028076171875;
+ auto scaled = v * twoOverPiVec;
+ auto kReal = floor(scaled);
+ auto k = toInt(kReal);
+
+ // Reduced range version of x
+ auto x = v - kReal * piOverTwoVec;
+ auto kMod4 = k & 3;
+ auto cosUseCos = ((kMod4 == 0) | (kMod4 == 2));
+ auto sinUseCos = ((kMod4 == 1) | (kMod4 == 3));
+ auto sinFlipSign = (kMod4 > 1);
+ auto cosFlipSign = ((kMod4 == 1) | (kMod4 == 2));
+
+ const float oneVec = +1.;
+ const float sinC2 = -0.16666667163372039794921875;
+ const float sinC4 = +8.333347737789154052734375e-3;
+ const float sinC6 = -1.9842604524455964565277099609375e-4;
+ const float sinC8 = +2.760012648650445044040679931640625e-6;
+ const float sinC10 = -2.50293279435709337121807038784027099609375e-8;
+
+ const float cosC2 = -0.5;
+ const float cosC4 = +4.166664183139801025390625e-2;
+ const float cosC6 = -1.388833043165504932403564453125e-3;
+ const float cosC8 = +2.47562347794882953166961669921875e-5;
+ const float cosC10 = -2.59630184018533327616751194000244140625e-7;
+
+ auto x2 = x * x;
+
+ auto sinFormula = x2 * sinC10 + sinC8;
+ auto cosFormula = x2 * cosC10 + cosC8;
+ sinFormula = x2 * sinFormula + sinC6;
+ cosFormula = x2 * cosFormula + cosC6;
+
+ sinFormula = x2 * sinFormula + sinC4;
+ cosFormula = x2 * cosFormula + cosC4;
+
+ sinFormula = x2 * sinFormula + sinC2;
+ cosFormula = x2 * cosFormula + cosC2;
+
+ sinFormula = x2 * sinFormula + oneVec;
+ cosFormula = x2 * cosFormula + oneVec;
+
+ sinFormula *= x;
+
+ sinResult = select(sinUseCos, cosFormula, sinFormula);
+ cosResult = select(cosUseCos, cosFormula, sinFormula);
+
+ sinResult = select(sinFlipSign, -sinResult, sinResult);
+ cosResult = select(cosFlipSign, -cosResult, cosResult);
+}
+
+template <typename T>
+__forceinline T tan(const T &v)
+{
+ const float piOverFourVec = 0.785398185253143310546875;
+ const float fourOverPiVec = 1.27323949337005615234375;
+
+ auto xLt0 = v < 0.;
+ auto y = select(xLt0, -v, v);
+ auto scaled = y * fourOverPiVec;
+
+ auto kReal = floor(scaled);
+ auto k = toInt(kReal);
+
+ auto x = y - kReal * piOverFourVec;
+
+ // If k & 1, x -= Pi/4
+ auto needOffset = (k & 1) != 0;
+ x = select(needOffset, x - piOverFourVec, x);
+
+ // If k & 3 == (0 or 3) let z = tan_In...(y) otherwise z = -cot_In0To...
+ auto kMod4 = k & 3;
+ auto useCotan = (kMod4 == 1) | (kMod4 == 2);
+
+ const float oneVec = 1.0;
+
+ const float tanC2 = +0.33333075046539306640625;
+ const float tanC4 = +0.13339905440807342529296875;
+ const float tanC6 = +5.3348250687122344970703125e-2;
+ const float tanC8 = +2.46033705770969390869140625e-2;
+ const float tanC10 = +2.892402000725269317626953125e-3;
+ const float tanC12 = +9.500005282461643218994140625e-3;
+
+ const float cotC2 = -0.3333333432674407958984375;
+ const float cotC4 = -2.222204394638538360595703125e-2;
+ const float cotC6 = -2.11752182804048061370849609375e-3;
+ const float cotC8 = -2.0846328698098659515380859375e-4;
+ const float cotC10 = -2.548247357481159269809722900390625e-5;
+ const float cotC12 = -3.5257363606433500535786151885986328125e-7;
+
+ auto x2 = x * x;
+ T z;
+ if (any(useCotan))
+ {
+ auto cotVal = x2 * cotC12 + cotC10;
+ cotVal = x2 * cotVal + cotC8;
+ cotVal = x2 * cotVal + cotC6;
+ cotVal = x2 * cotVal + cotC4;
+ cotVal = x2 * cotVal + cotC2;
+ cotVal = x2 * cotVal + oneVec;
+ // The equation is for x * cot(x) but we need -x * cot(x) for the tan part.
+ cotVal /= -x;
+ z = cotVal;
+ }
+ auto useTan = !useCotan;
+ if (any(useTan))
+ {
+ auto tanVal = x2 * tanC12 + tanC10;
+ tanVal = x2 * tanVal + tanC8;
+ tanVal = x2 * tanVal + tanC6;
+ tanVal = x2 * tanVal + tanC4;
+ tanVal = x2 * tanVal + tanC2;
+ tanVal = x2 * tanVal + oneVec;
+ // Equation was for tan(x)/x
+ tanVal *= x;
+ z = select(useTan, tanVal, z);
+ }
+ return select(xLt0, -z, z);
+}
+
+template <typename T>
+__forceinline T asin(const T &x0)
+{
+ auto isneg = (x0 < 0.f);
+ auto x = abs(x0);
+ auto isnan = (x > 1.f);
+
+ // sollya
+ // fpminimax(((asin(x)-pi/2)/-sqrt(1-x)), [|0,1,2,3,4,5|],[|single...|],
+ // [1e-20;.9999999999999999]);
+ // avg error: 1.1105439e-06, max error 1.3187528e-06
+ auto v = 1.57079517841339111328125f +
+ x * (-0.21450997889041900634765625f +
+ x * (8.78556668758392333984375e-2f +
+ x * (-4.489909112453460693359375e-2f +
+ x * (1.928029954433441162109375e-2f +
+ x * (-4.3095736764371395111083984375e-3f)))));
+
+ v *= -sqrt(1.f - x);
+ v = v + 1.57079637050628662109375f;
+
+ v = select(v < 0.f, T(0.f), v);
+ v = select(isneg, -v, v);
+ v = select(isnan, T(cast_i2f(0x7fc00000)), v);
+
+ return v;
+}
+
+template <typename T>
+__forceinline T acos(const T &v)
+{
+ return 1.57079637050628662109375f - asin(v);
+}
+
+template <typename T>
+__forceinline T atan(const T &v)
+{
+ const float piOverTwoVec = 1.57079637050628662109375;
+ // atan(-x) = -atan(x) (so flip from negative to positive first)
+ // If x > 1 -> atan(x) = Pi/2 - atan(1/x)
+ auto xNeg = v < 0.f;
+ auto xFlipped = select(xNeg, -v, v);
+
+ auto xGt1 = xFlipped > 1.;
+ auto x = select(xGt1, rcpSafe(xFlipped), xFlipped);
+
+ // These coefficients approximate atan(x)/x
+ const float atanC0 = +0.99999988079071044921875;
+ const float atanC2 = -0.3333191573619842529296875;
+ const float atanC4 = +0.199689209461212158203125;
+ const float atanC6 = -0.14015688002109527587890625;
+ const float atanC8 = +9.905083477497100830078125e-2;
+ const float atanC10 = -5.93664981424808502197265625e-2;
+ const float atanC12 = +2.417283318936824798583984375e-2;
+ const float atanC14 = -4.6721356920897960662841796875e-3;
+
+ auto x2 = x * x;
+ auto result = x2 * atanC14 + atanC12;
+ result = x2 * result + atanC10;
+ result = x2 * result + atanC8;
+ result = x2 * result + atanC6;
+ result = x2 * result + atanC4;
+ result = x2 * result + atanC2;
+ result = x2 * result + atanC0;
+ result *= x;
+
+ result = select(xGt1, piOverTwoVec - result, result);
+ result = select(xNeg, -result, result);
+ return result;
+}
+
+template <typename T>
+__forceinline T atan2(const T &y, const T &x)
+{
+ const float piVec = 3.1415926536;
+ // atan2(y, x) =
+ //
+ // atan2(y > 0, x = +-0) -> Pi/2
+ // atan2(y < 0, x = +-0) -> -Pi/2
+ // atan2(y = +-0, x < +0) -> +-Pi
+ // atan2(y = +-0, x >= +0) -> +-0
+ //
+ // atan2(y >= 0, x < 0) -> Pi + atan(y/x)
+ // atan2(y < 0, x < 0) -> -Pi + atan(y/x)
+ // atan2(y, x > 0) -> atan(y/x)
+ //
+ // and then a bunch of code for dealing with infinities.
+ auto yOverX = y * rcpSafe(x);
+ auto atanArg = atan(yOverX);
+ auto xLt0 = x < 0.f;
+ auto yLt0 = y < 0.f;
+ auto offset = select(xLt0,
+ select(yLt0, T(-piVec), T(piVec)), 0.f);
+ return offset + atanArg;
+}
+
+template <typename T>
+__forceinline T exp(const T &v)
+{
+ const float ln2Part1 = 0.6931457519;
+ const float ln2Part2 = 1.4286067653e-6;
+ const float oneOverLn2 = 1.44269502162933349609375;
+
+ auto scaled = v * oneOverLn2;
+ auto kReal = floor(scaled);
+ auto k = toInt(kReal);
+
+ // Reduced range version of x
+ auto x = v - kReal * ln2Part1;
+ x -= kReal * ln2Part2;
+
+ // These coefficients are for e^x in [0, ln(2)]
+ const float one = 1.;
+ const float c2 = 0.4999999105930328369140625;
+ const float c3 = 0.166668415069580078125;
+ const float c4 = 4.16539050638675689697265625e-2;
+ const float c5 = 8.378830738365650177001953125e-3;
+ const float c6 = 1.304379315115511417388916015625e-3;
+ const float c7 = 2.7555381529964506626129150390625e-4;
+
+ auto result = x * c7 + c6;
+ result = x * result + c5;
+ result = x * result + c4;
+ result = x * result + c3;
+ result = x * result + c2;
+ result = x * result + one;
+ result = x * result + one;
+
+ // Compute 2^k (should differ for float and double, but I'll avoid
+ // it for now and just do floats)
+ const int fpbias = 127;
+ auto biasedN = k + fpbias;
+ auto overflow = kReal > fpbias;
+ // Minimum exponent is -126, so if k is <= -127 (k + 127 <= 0)
+ // we've got underflow. -127 * ln(2) -> -88.02. So the most
+ // negative float input that doesn't result in zero is like -88.
+ auto underflow = kReal <= -fpbias;
+ const int infBits = 0x7f800000;
+ biasedN <<= 23;
+ // Reinterpret this thing as float
+ auto twoToTheN = asFloat(biasedN);
+ // Handle both doubles and floats (hopefully eliding the copy for float)
+ auto elemtype2n = twoToTheN;
+ result *= elemtype2n;
+ result = select(overflow, cast_i2f(infBits), result);
+ result = select(underflow, 0., result);
+ return result;
+}
+
+// Range reduction for logarithms takes log(x) -> log(2^n * y) -> n
+// * log(2) + log(y) where y is the reduced range (usually in [1/2, 1)).
+template <typename T, typename R>
+__forceinline void __rangeReduceLog(const T &input,
+ T &reduced,
+ R &exponent)
+{
+ auto intVersion = asInt(input);
+ // single precision = SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
+ // exponent mask = 0111 1111 1000 0000 0000 0000 0000 0000
+ // 0x7 0xF 0x8 0x0 0x0 0x0 0x0 0x0
+ // non-exponent = 1000 0000 0111 1111 1111 1111 1111 1111
+ // = 0x8 0x0 0x7 0xF 0xF 0xF 0xF 0xF
+
+ //const int exponentMask(0x7F800000)
+ static const int nonexponentMask = 0x807FFFFF;
+
+ // We want the reduced version to have an exponent of -1 which is
+ // -1 + 127 after biasing or 126
+ static const int exponentNeg1 = (126l << 23);
+ // NOTE(boulos): We don't need to mask anything out since we know
+ // the sign bit has to be 0. If it's 1, we need to return infinity/nan
+ // anyway (log(x), x = +-0 -> infinity, x < 0 -> NaN).
+ auto biasedExponent = intVersion >> 23; // This number is [0, 255] but it means [-127, 128]
+
+ auto offsetExponent = biasedExponent + 1; // Treat the number as if it were 2^{e+1} * (1.m)/2
+ exponent = offsetExponent - 127; // get the real value
+
+ // Blend the offset_exponent with the original input (do this in
+ // int for now, until I decide if float can have & and &not)
+ auto blended = (intVersion & nonexponentMask) | (exponentNeg1);
+ reduced = asFloat(blended);
+}
+
+template <typename T> struct ExponentType { };
+template <int N> struct ExponentType<vfloat_impl<N>> { typedef vint<N> Ty; };
+template <> struct ExponentType<float> { typedef int Ty; };
+
+template <typename T>
+__forceinline T log(const T &v)
+{
+ T reduced;
+ typename ExponentType<T>::Ty exponent;
+
+ const int nanBits = 0x7fc00000;
+ const int negInfBits = 0xFF800000;
+ const float nan = cast_i2f(nanBits);
+ const float negInf = cast_i2f(negInfBits);
+ auto useNan = v < 0.;
+ auto useInf = v == 0.;
+ auto exceptional = useNan | useInf;
+ const float one = 1.0;
+
+ auto patched = select(exceptional, one, v);
+ __rangeReduceLog(patched, reduced, exponent);
+
+ const float ln2 = 0.693147182464599609375;
+
+ auto x1 = one - reduced;
+ const float c1 = +0.50000095367431640625;
+ const float c2 = +0.33326041698455810546875;
+ const float c3 = +0.2519190013408660888671875;
+ const float c4 = +0.17541764676570892333984375;
+ const float c5 = +0.3424419462680816650390625;
+ const float c6 = -0.599632322788238525390625;
+ const float c7 = +1.98442304134368896484375;
+ const float c8 = -2.4899270534515380859375;
+ const float c9 = +1.7491014003753662109375;
+
+ auto result = x1 * c9 + c8;
+ result = x1 * result + c7;
+ result = x1 * result + c6;
+ result = x1 * result + c5;
+ result = x1 * result + c4;
+ result = x1 * result + c3;
+ result = x1 * result + c2;
+ result = x1 * result + c1;
+ result = x1 * result + one;
+
+ // Equation was for -(ln(red)/(1-red))
+ result *= -x1;
+ result += toFloat(exponent) * ln2;
+
+ return select(exceptional,
+ select(useNan, T(nan), T(negInf)),
+ result);
+}
+
+template <typename T>
+__forceinline T pow(const T &x, const T &y)
+{
+ auto x1 = abs(x);
+ auto z = exp(y * log(x1));
+
+ // Handle special cases
+ const float twoOver23 = 8388608.0f;
+ auto yInt = y == round(y);
+ auto yOddInt = select(yInt, asInt(abs(y) + twoOver23) << 31, 0); // set sign bit
+
+ // x == 0
+ z = select(x == 0.0f,
+ select(y < 0.0f, T(inf) | signmsk(x),
+ select(y == 0.0f, T(1.0f), asFloat(yOddInt) & x)), z);
+
+ // x < 0
+ auto xNegative = x < 0.0f;
+ if (any(xNegative))
+ {
+ auto z1 = z | asFloat(yOddInt);
+ z1 = select(yInt, z1, std::numeric_limits<float>::quiet_NaN());
+ z = select(xNegative, z1, z);
+ }
+
+ auto xFinite = isfinite(x);
+ auto yFinite = isfinite(y);
+ if (all(xFinite & yFinite))
+ return z;
+
+ // x finite and y infinite
+ z = select(andn(xFinite, yFinite),
+ select(x1 == 1.0f, 1.0f,
+ select((x1 > 1.0f) ^ (y < 0.0f), inf, T(0.0f))), z);
+
+ // x infinite
+ z = select(xFinite, z,
+ select(y == 0.0f, 1.0f,
+ select(y < 0.0f, T(0.0f), inf) | (asFloat(yOddInt) & x)));
+
+ return z;
+}
+
+template <typename T>
+__forceinline T pow(const T &x, float y)
+{
+ return pow(x, T(y));
+}
+
+} // namespace fastapprox
+
+} // namespace embree
diff --git a/thirdparty/embree/common/math/vec2.h b/thirdparty/embree/common/math/vec2.h
new file mode 100644
index 0000000000..d62aef51f3
--- /dev/null
+++ b/thirdparty/embree/common/math/vec2.h
@@ -0,0 +1,235 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "math.h"
+
+namespace embree
+{
+ struct Vec2fa;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Generic 2D vector Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct Vec2
+ {
+ enum { N = 2 };
+ union {
+ struct { T x, y; };
+#if !(defined(__WIN32__) && _MSC_VER == 1800) // workaround for older VS 2013 compiler
+ T components[N];
+#endif
+ };
+
+ typedef T Scalar;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2( ) {}
+ __forceinline explicit Vec2( const T& a ) : x(a), y(a) {}
+ __forceinline Vec2( const T& x, const T& y ) : x(x), y(y) {}
+
+ __forceinline Vec2( const Vec2& other ) { x = other.x; y = other.y; }
+ __forceinline Vec2( const Vec2fa& other );
+
+ template<typename T1> __forceinline Vec2( const Vec2<T1>& a ) : x(T(a.x)), y(T(a.y)) {}
+ template<typename T1> __forceinline Vec2& operator =( const Vec2<T1>& other ) { x = other.x; y = other.y; return *this; }
+
+ __forceinline Vec2& operator =( const Vec2& other ) { x = other.x; y = other.y; return *this; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2( ZeroTy ) : x(zero), y(zero) {}
+ __forceinline Vec2( OneTy ) : x(one), y(one) {}
+ __forceinline Vec2( PosInfTy ) : x(pos_inf), y(pos_inf) {}
+ __forceinline Vec2( NegInfTy ) : x(neg_inf), y(neg_inf) {}
+
+#if defined(__WIN32__) && _MSC_VER == 1800 // workaround for older VS 2013 compiler
+ __forceinline const T& operator [](const size_t axis) const { assert(axis < 2); return (&x)[axis]; }
+ __forceinline T& operator [](const size_t axis) { assert(axis < 2); return (&x)[axis]; }
+#else
+ __forceinline const T& operator [](const size_t axis) const { assert(axis < 2); return components[axis]; }
+ __forceinline T& operator [](const size_t axis ) { assert(axis < 2); return components[axis]; }
+#endif
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T> operator +( const Vec2<T>& a ) { return Vec2<T>(+a.x, +a.y); }
+ template<typename T> __forceinline Vec2<T> operator -( const Vec2<T>& a ) { return Vec2<T>(-a.x, -a.y); }
+ template<typename T> __forceinline Vec2<T> abs ( const Vec2<T>& a ) { return Vec2<T>(abs (a.x), abs (a.y)); }
+ template<typename T> __forceinline Vec2<T> rcp ( const Vec2<T>& a ) { return Vec2<T>(rcp (a.x), rcp (a.y)); }
+ template<typename T> __forceinline Vec2<T> rsqrt ( const Vec2<T>& a ) { return Vec2<T>(rsqrt(a.x), rsqrt(a.y)); }
+ template<typename T> __forceinline Vec2<T> sqrt ( const Vec2<T>& a ) { return Vec2<T>(sqrt (a.x), sqrt (a.y)); }
+ template<typename T> __forceinline Vec2<T> frac ( const Vec2<T>& a ) { return Vec2<T>(frac (a.x), frac (a.y)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T> operator +( const Vec2<T>& a, const Vec2<T>& b ) { return Vec2<T>(a.x + b.x, a.y + b.y); }
+ template<typename T> __forceinline Vec2<T> operator +( const Vec2<T>& a, const T& b ) { return Vec2<T>(a.x + b , a.y + b ); }
+ template<typename T> __forceinline Vec2<T> operator +( const T& a, const Vec2<T>& b ) { return Vec2<T>(a + b.x, a + b.y); }
+ template<typename T> __forceinline Vec2<T> operator -( const Vec2<T>& a, const Vec2<T>& b ) { return Vec2<T>(a.x - b.x, a.y - b.y); }
+ template<typename T> __forceinline Vec2<T> operator -( const Vec2<T>& a, const T& b ) { return Vec2<T>(a.x - b , a.y - b ); }
+ template<typename T> __forceinline Vec2<T> operator -( const T& a, const Vec2<T>& b ) { return Vec2<T>(a - b.x, a - b.y); }
+ template<typename T> __forceinline Vec2<T> operator *( const Vec2<T>& a, const Vec2<T>& b ) { return Vec2<T>(a.x * b.x, a.y * b.y); }
+ template<typename T> __forceinline Vec2<T> operator *( const T& a, const Vec2<T>& b ) { return Vec2<T>(a * b.x, a * b.y); }
+ template<typename T> __forceinline Vec2<T> operator *( const Vec2<T>& a, const T& b ) { return Vec2<T>(a.x * b , a.y * b ); }
+ template<typename T> __forceinline Vec2<T> operator /( const Vec2<T>& a, const Vec2<T>& b ) { return Vec2<T>(a.x / b.x, a.y / b.y); }
+ template<typename T> __forceinline Vec2<T> operator /( const Vec2<T>& a, const T& b ) { return Vec2<T>(a.x / b , a.y / b ); }
+ template<typename T> __forceinline Vec2<T> operator /( const T& a, const Vec2<T>& b ) { return Vec2<T>(a / b.x, a / b.y); }
+
+ template<typename T> __forceinline Vec2<T> min(const Vec2<T>& a, const Vec2<T>& b) { return Vec2<T>(min(a.x, b.x), min(a.y, b.y)); }
+ template<typename T> __forceinline Vec2<T> max(const Vec2<T>& a, const Vec2<T>& b) { return Vec2<T>(max(a.x, b.x), max(a.y, b.y)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T> madd ( const Vec2<T>& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>( madd(a.x,b.x,c.x), madd(a.y,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> msub ( const Vec2<T>& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>( msub(a.x,b.x,c.x), msub(a.y,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> nmadd ( const Vec2<T>& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>(nmadd(a.x,b.x,c.x),nmadd(a.y,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> nmsub ( const Vec2<T>& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>(nmsub(a.x,b.x,c.x),nmsub(a.y,b.y,c.y) ); }
+
+ template<typename T> __forceinline Vec2<T> madd ( const T& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>( madd(a,b.x,c.x), madd(a,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> msub ( const T& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>( msub(a,b.x,c.x), msub(a,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> nmadd ( const T& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>(nmadd(a,b.x,c.x),nmadd(a,b.y,c.y) ); }
+ template<typename T> __forceinline Vec2<T> nmsub ( const T& a, const Vec2<T>& b, const Vec2<T>& c) { return Vec2<T>(nmsub(a,b.x,c.x),nmsub(a,b.y,c.y) ); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T>& operator +=( Vec2<T>& a, const Vec2<T>& b ) { a.x += b.x; a.y += b.y; return a; }
+ template<typename T> __forceinline Vec2<T>& operator -=( Vec2<T>& a, const Vec2<T>& b ) { a.x -= b.x; a.y -= b.y; return a; }
+ template<typename T> __forceinline Vec2<T>& operator *=( Vec2<T>& a, const T& b ) { a.x *= b ; a.y *= b ; return a; }
+ template<typename T> __forceinline Vec2<T>& operator /=( Vec2<T>& a, const T& b ) { a.x /= b ; a.y /= b ; return a; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T reduce_add( const Vec2<T>& a ) { return a.x + a.y; }
+ template<typename T> __forceinline T reduce_mul( const Vec2<T>& a ) { return a.x * a.y; }
+ template<typename T> __forceinline T reduce_min( const Vec2<T>& a ) { return min(a.x, a.y); }
+ template<typename T> __forceinline T reduce_max( const Vec2<T>& a ) { return max(a.x, a.y); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const Vec2<T>& a, const Vec2<T>& b ) { return a.x == b.x && a.y == b.y; }
+ template<typename T> __forceinline bool operator !=( const Vec2<T>& a, const Vec2<T>& b ) { return a.x != b.x || a.y != b.y; }
+ template<typename T> __forceinline bool operator < ( const Vec2<T>& a, const Vec2<T>& b ) {
+ if (a.x != b.x) return a.x < b.x;
+ if (a.y != b.y) return a.y < b.y;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Shift Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T> shift_right_1( const Vec2<T>& a ) {
+ return Vec2<T>(shift_right_1(a.x),shift_right_1(a.y));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T dot ( const Vec2<T>& a, const Vec2<T>& b ) { return madd(a.x,b.x,a.y*b.y); }
+ template<typename T> __forceinline Vec2<T> cross ( const Vec2<T>& a ) { return Vec2<T>(-a.y,a.x); }
+ template<typename T> __forceinline T length ( const Vec2<T>& a ) { return sqrt(dot(a,a)); }
+ template<typename T> __forceinline Vec2<T> normalize( const Vec2<T>& a ) { return a*rsqrt(dot(a,a)); }
+ template<typename T> __forceinline T distance ( const Vec2<T>& a, const Vec2<T>& b ) { return length(a-b); }
+ template<typename T> __forceinline T det ( const Vec2<T>& a, const Vec2<T>& b ) { return a.x*b.y - a.y*b.x; }
+
+ template<typename T> __forceinline Vec2<T> normalize_safe( const Vec2<T>& a ) {
+ const T d = dot(a,a); return select(d == T( zero ),a, a*rsqrt(d) );
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec2<T> select ( bool s, const Vec2<T>& t, const Vec2<T>& f ) {
+ return Vec2<T>(select(s,t.x,f.x),select(s,t.y,f.y));
+ }
+
+ template<typename T> __forceinline Vec2<T> select ( const Vec2<bool>& s, const Vec2<T>& t, const Vec2<T>& f ) {
+ return Vec2<T>(select(s.x,t.x,f.x),select(s.y,t.y,f.y));
+ }
+
+ template<typename T> __forceinline Vec2<T> select ( const typename T::Bool& s, const Vec2<T>& t, const Vec2<T>& f ) {
+ return Vec2<T>(select(s,t.x,f.x),select(s,t.y,f.y));
+ }
+
+ template<typename T>
+ __forceinline Vec2<T> lerp(const Vec2<T>& v0, const Vec2<T>& v1, const T& t) {
+ return madd(Vec2<T>(T(1.0f)-t),v0,t*v1);
+ }
+
+ template<typename T> __forceinline int maxDim ( const Vec2<T>& a )
+ {
+ const Vec2<T> b = abs(a);
+ if (b.x > b.y) return 0;
+ else return 1;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const Vec2<T>& a) {
+ return cout << "(" << a.x << ", " << a.y << ")";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Default template instantiations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ typedef Vec2<bool > Vec2b;
+ typedef Vec2<int > Vec2i;
+ typedef Vec2<float> Vec2f;
+}
+
+#include "vec2fa.h"
+
+#if defined __SSE__
+#include "../simd/sse.h"
+#endif
+
+#if defined __AVX__
+#include "../simd/avx.h"
+#endif
+
+#if defined(__AVX512F__)
+#include "../simd/avx512.h"
+#endif
+
+namespace embree
+{
+ template<> __forceinline Vec2<float>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
+
+#if defined(__SSE__)
+ template<> __forceinline Vec2<vfloat4>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
+#endif
+
+#if defined(__AVX__)
+ template<> __forceinline Vec2<vfloat8>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
+#endif
+
+#if defined(__AVX512F__)
+ template<> __forceinline Vec2<vfloat16>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {}
+#endif
+}
diff --git a/thirdparty/embree/common/math/vec2fa.h b/thirdparty/embree/common/math/vec2fa.h
new file mode 100644
index 0000000000..a51fb68fd0
--- /dev/null
+++ b/thirdparty/embree/common/math/vec2fa.h
@@ -0,0 +1,301 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/alloc.h"
+#include "math.h"
+#include "../simd/sse.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE Vec2fa Type
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(16) Vec2fa
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef float Scalar;
+ enum { N = 2 };
+ union {
+ __m128 m128;
+ struct { float x,y,az,aw; };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa( ) {}
+ __forceinline Vec2fa( const __m128 a ) : m128(a) {}
+
+ __forceinline Vec2fa ( const Vec2<float>& other ) { x = other.x; y = other.y; }
+ __forceinline Vec2fa& operator =( const Vec2<float>& other ) { x = other.x; y = other.y; return *this; }
+
+ __forceinline Vec2fa ( const Vec2fa& other ) { m128 = other.m128; }
+ __forceinline Vec2fa& operator =( const Vec2fa& other ) { m128 = other.m128; return *this; }
+
+ __forceinline explicit Vec2fa( const float a ) : m128(_mm_set1_ps(a)) {}
+ __forceinline Vec2fa( const float x, const float y) : m128(_mm_set_ps(y, y, y, x)) {}
+
+ __forceinline explicit Vec2fa( const __m128i a ) : m128(_mm_cvtepi32_ps(a)) {}
+
+ __forceinline operator const __m128&() const { return m128; }
+ __forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline Vec2fa load( const void* const a ) {
+ return Vec2fa(_mm_and_ps(_mm_load_ps((float*)a),_mm_castsi128_ps(_mm_set_epi32(0, 0, -1, -1))));
+ }
+
+ static __forceinline Vec2fa loadu( const void* const a ) {
+ return Vec2fa(_mm_and_ps(_mm_loadu_ps((float*)a),_mm_castsi128_ps(_mm_set_epi32(0, 0, -1, -1))));
+ }
+
+ static __forceinline void storeu ( void* ptr, const Vec2fa& v ) {
+ _mm_storeu_ps((float*)ptr,v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa( ZeroTy ) : m128(_mm_setzero_ps()) {}
+ __forceinline Vec2fa( OneTy ) : m128(_mm_set1_ps(1.0f)) {}
+ __forceinline Vec2fa( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {}
+ __forceinline Vec2fa( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float& operator []( const size_t index ) const { assert(index < 2); return (&x)[index]; }
+ __forceinline float& operator []( const size_t index ) { assert(index < 2); return (&x)[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa operator +( const Vec2fa& a ) { return a; }
+ __forceinline Vec2fa operator -( const Vec2fa& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+ return _mm_xor_ps(a.m128, mask);
+ }
+ __forceinline Vec2fa abs ( const Vec2fa& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
+ return _mm_and_ps(a.m128, mask);
+ }
+ __forceinline Vec2fa sign ( const Vec2fa& a ) {
+ return blendv_ps(Vec2fa(one), -Vec2fa(one), _mm_cmplt_ps (a,Vec2fa(zero)));
+ }
+
+ __forceinline Vec2fa rcp ( const Vec2fa& a )
+ {
+#if defined(__AVX512VL__)
+ const Vec2fa r = _mm_rcp14_ps(a.m128);
+#else
+ const Vec2fa r = _mm_rcp_ps(a.m128);
+#endif
+
+#if defined(__AVX2__)
+ const Vec2fa res = _mm_mul_ps(r,_mm_fnmadd_ps(r, a, vfloat4(2.0f)));
+#else
+ const Vec2fa res = _mm_mul_ps(r,_mm_sub_ps(vfloat4(2.0f), _mm_mul_ps(r, a)));
+ //return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
+#endif
+
+ return res;
+ }
+
+ __forceinline Vec2fa sqrt ( const Vec2fa& a ) { return _mm_sqrt_ps(a.m128); }
+ __forceinline Vec2fa sqr ( const Vec2fa& a ) { return _mm_mul_ps(a,a); }
+
+ __forceinline Vec2fa rsqrt( const Vec2fa& a )
+ {
+#if defined(__AVX512VL__)
+ __m128 r = _mm_rsqrt14_ps(a.m128);
+#else
+ __m128 r = _mm_rsqrt_ps(a.m128);
+#endif
+ return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+ }
+
+ __forceinline Vec2fa zero_fix(const Vec2fa& a) {
+ return blendv_ps(a, _mm_set1_ps(min_rcp_input), _mm_cmplt_ps (abs(a).m128, _mm_set1_ps(min_rcp_input)));
+ }
+ __forceinline Vec2fa rcp_safe(const Vec2fa& a) {
+ return rcp(zero_fix(a));
+ }
+ __forceinline Vec2fa log ( const Vec2fa& a ) {
+ return Vec2fa(logf(a.x),logf(a.y));
+ }
+
+ __forceinline Vec2fa exp ( const Vec2fa& a ) {
+ return Vec2fa(expf(a.x),expf(a.y));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa operator +( const Vec2fa& a, const Vec2fa& b ) { return _mm_add_ps(a.m128, b.m128); }
+ __forceinline Vec2fa operator -( const Vec2fa& a, const Vec2fa& b ) { return _mm_sub_ps(a.m128, b.m128); }
+ __forceinline Vec2fa operator *( const Vec2fa& a, const Vec2fa& b ) { return _mm_mul_ps(a.m128, b.m128); }
+ __forceinline Vec2fa operator *( const Vec2fa& a, const float b ) { return a * Vec2fa(b); }
+ __forceinline Vec2fa operator *( const float a, const Vec2fa& b ) { return Vec2fa(a) * b; }
+ __forceinline Vec2fa operator /( const Vec2fa& a, const Vec2fa& b ) { return _mm_div_ps(a.m128,b.m128); }
+ __forceinline Vec2fa operator /( const Vec2fa& a, const float b ) { return _mm_div_ps(a.m128,_mm_set1_ps(b)); }
+ __forceinline Vec2fa operator /( const float a, const Vec2fa& b ) { return _mm_div_ps(_mm_set1_ps(a),b.m128); }
+
+ __forceinline Vec2fa min( const Vec2fa& a, const Vec2fa& b ) { return _mm_min_ps(a.m128,b.m128); }
+ __forceinline Vec2fa max( const Vec2fa& a, const Vec2fa& b ) { return _mm_max_ps(a.m128,b.m128); }
+
+#if defined(__SSE4_1__)
+ __forceinline Vec2fa mini(const Vec2fa& a, const Vec2fa& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_min_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+#if defined(__SSE4_1__)
+ __forceinline Vec2fa maxi(const Vec2fa& a, const Vec2fa& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_max_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+ __forceinline Vec2fa pow ( const Vec2fa& a, const float& b ) {
+ return Vec2fa(powf(a.x,b),powf(a.y,b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ __forceinline Vec2fa madd ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return _mm_fmadd_ps(a,b,c); }
+ __forceinline Vec2fa msub ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return _mm_fmsub_ps(a,b,c); }
+ __forceinline Vec2fa nmadd ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return _mm_fnmadd_ps(a,b,c); }
+ __forceinline Vec2fa nmsub ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return _mm_fnmsub_ps(a,b,c); }
+#else
+ __forceinline Vec2fa madd ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return a*b+c; }
+ __forceinline Vec2fa msub ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return a*b-c; }
+ __forceinline Vec2fa nmadd ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return -a*b+c;}
+ __forceinline Vec2fa nmsub ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return -a*b-c; }
+#endif
+
+ __forceinline Vec2fa madd ( const float a, const Vec2fa& b, const Vec2fa& c) { return madd(Vec2fa(a),b,c); }
+ __forceinline Vec2fa msub ( const float a, const Vec2fa& b, const Vec2fa& c) { return msub(Vec2fa(a),b,c); }
+ __forceinline Vec2fa nmadd ( const float a, const Vec2fa& b, const Vec2fa& c) { return nmadd(Vec2fa(a),b,c); }
+ __forceinline Vec2fa nmsub ( const float a, const Vec2fa& b, const Vec2fa& c) { return nmsub(Vec2fa(a),b,c); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa& operator +=( Vec2fa& a, const Vec2fa& b ) { return a = a + b; }
+ __forceinline Vec2fa& operator -=( Vec2fa& a, const Vec2fa& b ) { return a = a - b; }
+ __forceinline Vec2fa& operator *=( Vec2fa& a, const Vec2fa& b ) { return a = a * b; }
+ __forceinline Vec2fa& operator *=( Vec2fa& a, const float b ) { return a = a * b; }
+ __forceinline Vec2fa& operator /=( Vec2fa& a, const Vec2fa& b ) { return a = a / b; }
+ __forceinline Vec2fa& operator /=( Vec2fa& a, const float b ) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float reduce_add(const Vec2fa& v) { return v.x+v.y; }
+ __forceinline float reduce_mul(const Vec2fa& v) { return v.x*v.y; }
+ __forceinline float reduce_min(const Vec2fa& v) { return min(v.x,v.y); }
+ __forceinline float reduce_max(const Vec2fa& v) { return max(v.x,v.y); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Vec2fa& a, const Vec2fa& b ) { return (_mm_movemask_ps(_mm_cmpeq_ps (a.m128, b.m128)) & 3) == 3; }
+ __forceinline bool operator !=( const Vec2fa& a, const Vec2fa& b ) { return (_mm_movemask_ps(_mm_cmpneq_ps(a.m128, b.m128)) & 3) != 0; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SSE4_1__)
+ __forceinline float dot ( const Vec2fa& a, const Vec2fa& b ) {
+ return _mm_cvtss_f32(_mm_dp_ps(a,b,0x3F));
+ }
+#else
+ __forceinline float dot ( const Vec2fa& a, const Vec2fa& b ) {
+ return reduce_add(a*b);
+ }
+#endif
+
+ __forceinline Vec2fa cross ( const Vec2fa& a ) {
+ return Vec2fa(-a.y,a.x);
+ }
+
+ __forceinline float sqr_length ( const Vec2fa& a ) { return dot(a,a); }
+ __forceinline float rcp_length ( const Vec2fa& a ) { return rsqrt(dot(a,a)); }
+ __forceinline float rcp_length2( const Vec2fa& a ) { return rcp(dot(a,a)); }
+ __forceinline float length ( const Vec2fa& a ) { return sqrt(dot(a,a)); }
+ __forceinline Vec2fa normalize( const Vec2fa& a ) { return a*rsqrt(dot(a,a)); }
+ __forceinline float distance ( const Vec2fa& a, const Vec2fa& b ) { return length(a-b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec2fa select( bool s, const Vec2fa& t, const Vec2fa& f ) {
+ __m128 mask = s ? _mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())) : _mm_setzero_ps();
+ return blendv_ps(f, t, mask);
+ }
+
+ __forceinline Vec2fa lerp(const Vec2fa& v0, const Vec2fa& v1, const float t) {
+ return madd(1.0f-t,v0,t*v1);
+ }
+
+ __forceinline int maxDim ( const Vec2fa& a )
+ {
+ const Vec2fa b = abs(a);
+ if (b.x > b.y) return 0;
+ else return 1;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__aarch64__)
+ //__forceinline Vec2fa trunc(const Vec2fa& a) { return vrndq_f32(a); }
+ __forceinline Vec2fa floor(const Vec2fa& a) { return vrndmq_f32(a); }
+ __forceinline Vec2fa ceil (const Vec2fa& a) { return vrndpq_f32(a); }
+#elif defined (__SSE4_1__)
+ //__forceinline Vec2fa trunc( const Vec2fa& a ) { return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT); }
+ __forceinline Vec2fa floor( const Vec2fa& a ) { return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF ); }
+ __forceinline Vec2fa ceil ( const Vec2fa& a ) { return _mm_round_ps(a, _MM_FROUND_TO_POS_INF ); }
+#else
+ //__forceinline Vec2fa trunc( const Vec2fa& a ) { return Vec2fa(truncf(a.x),truncf(a.y),truncf(a.z)); }
+ __forceinline Vec2fa floor( const Vec2fa& a ) { return Vec2fa(floorf(a.x),floorf(a.y)); }
+ __forceinline Vec2fa ceil ( const Vec2fa& a ) { return Vec2fa(ceilf (a.x),ceilf (a.y)); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Vec2fa& a) {
+ return cout << "(" << a.x << ", " << a.y << ")";
+ }
+
+ typedef Vec2fa Vec2fa_t;
+}
diff --git a/thirdparty/embree/common/math/vec3.h b/thirdparty/embree/common/math/vec3.h
new file mode 100644
index 0000000000..ce94eff327
--- /dev/null
+++ b/thirdparty/embree/common/math/vec3.h
@@ -0,0 +1,337 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "math.h"
+
+namespace embree
+{
+ struct Vec3fa;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Generic 3D vector Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct Vec3
+ {
+ enum { N = 3 };
+
+ union {
+ struct {
+ T x, y, z;
+ };
+#if !(defined(__WIN32__) && _MSC_VER == 1800) // workaround for older VS 2013 compiler
+ T components[N];
+#endif
+ };
+
+ typedef T Scalar;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3( ) {}
+ __forceinline explicit Vec3( const T& a ) : x(a), y(a), z(a) {}
+ __forceinline Vec3( const T& x, const T& y, const T& z ) : x(x), y(y), z(z) {}
+
+ __forceinline Vec3( const Vec3& other ) { x = other.x; y = other.y; z = other.z; }
+ __forceinline Vec3( const Vec3fa& other );
+
+ template<typename T1> __forceinline Vec3( const Vec3<T1>& a ) : x(T(a.x)), y(T(a.y)), z(T(a.z)) {}
+ template<typename T1> __forceinline Vec3& operator =(const Vec3<T1>& other) { x = other.x; y = other.y; z = other.z; return *this; }
+
+ __forceinline Vec3& operator =(const Vec3& other) { x = other.x; y = other.y; z = other.z; return *this; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3( ZeroTy ) : x(zero), y(zero), z(zero) {}
+ __forceinline Vec3( OneTy ) : x(one), y(one), z(one) {}
+ __forceinline Vec3( PosInfTy ) : x(pos_inf), y(pos_inf), z(pos_inf) {}
+ __forceinline Vec3( NegInfTy ) : x(neg_inf), y(neg_inf), z(neg_inf) {}
+
+#if defined(__WIN32__) && (_MSC_VER == 1800) // workaround for older VS 2013 compiler
+ __forceinline const T& operator []( const size_t axis ) const { assert(axis < 3); return (&x)[axis]; }
+ __forceinline T& operator []( const size_t axis ) { assert(axis < 3); return (&x)[axis]; }
+#else
+ __forceinline const T& operator [](const size_t axis) const { assert(axis < 3); return components[axis]; }
+ __forceinline T& operator [](const size_t axis) { assert(axis < 3); return components[axis]; }
+#endif
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T> operator +( const Vec3<T>& a ) { return Vec3<T>(+a.x, +a.y, +a.z); }
+ template<typename T> __forceinline Vec3<T> operator -( const Vec3<T>& a ) { return Vec3<T>(-a.x, -a.y, -a.z); }
+ template<typename T> __forceinline Vec3<T> abs ( const Vec3<T>& a ) { return Vec3<T>(abs (a.x), abs (a.y), abs (a.z)); }
+ template<typename T> __forceinline Vec3<T> rcp ( const Vec3<T>& a ) { return Vec3<T>(rcp (a.x), rcp (a.y), rcp (a.z)); }
+ template<typename T> __forceinline Vec3<T> rsqrt ( const Vec3<T>& a ) { return Vec3<T>(rsqrt(a.x), rsqrt(a.y), rsqrt(a.z)); }
+ template<typename T> __forceinline Vec3<T> sqrt ( const Vec3<T>& a ) { return Vec3<T>(sqrt (a.x), sqrt (a.y), sqrt (a.z)); }
+
+ template<typename T> __forceinline Vec3<T> zero_fix( const Vec3<T>& a )
+ {
+ return Vec3<T>(select(abs(a.x)<min_rcp_input,T(min_rcp_input),a.x),
+ select(abs(a.y)<min_rcp_input,T(min_rcp_input),a.y),
+ select(abs(a.z)<min_rcp_input,T(min_rcp_input),a.z));
+ }
+ template<typename T> __forceinline Vec3<T> rcp_safe(const Vec3<T>& a) { return rcp(zero_fix(a)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T> operator +( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(a.x + b.x, a.y + b.y, a.z + b.z); }
+ template<typename T> __forceinline Vec3<T> operator -( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(a.x - b.x, a.y - b.y, a.z - b.z); }
+ template<typename T> __forceinline Vec3<T> operator *( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(a.x * b.x, a.y * b.y, a.z * b.z); }
+ template<typename T> __forceinline Vec3<T> operator *( const T& a, const Vec3<T>& b ) { return Vec3<T>(a * b.x, a * b.y, a * b.z); }
+ template<typename T> __forceinline Vec3<T> operator *( const Vec3<T>& a, const T& b ) { return Vec3<T>(a.x * b , a.y * b , a.z * b ); }
+ template<typename T> __forceinline Vec3<T> operator /( const Vec3<T>& a, const T& b ) { return Vec3<T>(a.x / b , a.y / b , a.z / b ); }
+ template<typename T> __forceinline Vec3<T> operator /( const T& a, const Vec3<T>& b ) { return Vec3<T>(a / b.x, a / b.y, a / b.z); }
+ template<typename T> __forceinline Vec3<T> operator /( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(a.x / b.x, a.y / b.y, a.z / b.z); }
+
+ template<typename T> __forceinline Vec3<T> min(const Vec3<T>& a, const Vec3<T>& b) { return Vec3<T>(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)); }
+ template<typename T> __forceinline Vec3<T> max(const Vec3<T>& a, const Vec3<T>& b) { return Vec3<T>(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)); }
+
+ template<typename T> __forceinline Vec3<T> operator >>( const Vec3<T>& a, const int b ) { return Vec3<T>(a.x >> b, a.y >> b, a.z >> b); }
+ template<typename T> __forceinline Vec3<T> operator <<( const Vec3<T>& a, const int b ) { return Vec3<T>(a.x << b, a.y << b, a.z << b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T> madd ( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>( madd(a.x,b.x,c.x), madd(a.y,b.y,c.y), madd(a.z,b.z,c.z)); }
+ template<typename T> __forceinline Vec3<T> msub ( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>( msub(a.x,b.x,c.x), msub(a.y,b.y,c.y), msub(a.z,b.z,c.z)); }
+ template<typename T> __forceinline Vec3<T> nmadd ( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>(nmadd(a.x,b.x,c.x),nmadd(a.y,b.y,c.y),nmadd(a.z,b.z,c.z));}
+ template<typename T> __forceinline Vec3<T> nmsub ( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>(nmsub(a.x,b.x,c.x),nmsub(a.y,b.y,c.y),nmsub(a.z,b.z,c.z)); }
+
+ template<typename T> __forceinline Vec3<T> madd ( const T& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>( madd(a,b.x,c.x), madd(a,b.y,c.y), madd(a,b.z,c.z)); }
+ template<typename T> __forceinline Vec3<T> msub ( const T& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>( msub(a,b.x,c.x), msub(a,b.y,c.y), msub(a,b.z,c.z)); }
+ template<typename T> __forceinline Vec3<T> nmadd ( const T& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>(nmadd(a,b.x,c.x),nmadd(a,b.y,c.y),nmadd(a,b.z,c.z));}
+ template<typename T> __forceinline Vec3<T> nmsub ( const T& a, const Vec3<T>& b, const Vec3<T>& c) { return Vec3<T>(nmsub(a,b.x,c.x),nmsub(a,b.y,c.y),nmsub(a,b.z,c.z)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T>& operator +=( Vec3<T>& a, const T b ) { a.x += b; a.y += b; a.z += b; return a; }
+ template<typename T> __forceinline Vec3<T>& operator +=( Vec3<T>& a, const Vec3<T>& b ) { a.x += b.x; a.y += b.y; a.z += b.z; return a; }
+ template<typename T> __forceinline Vec3<T>& operator -=( Vec3<T>& a, const Vec3<T>& b ) { a.x -= b.x; a.y -= b.y; a.z -= b.z; return a; }
+ template<typename T> __forceinline Vec3<T>& operator *=( Vec3<T>& a, const T& b ) { a.x *= b ; a.y *= b ; a.z *= b ; return a; }
+ template<typename T> __forceinline Vec3<T>& operator /=( Vec3<T>& a, const T& b ) { a.x /= b ; a.y /= b ; a.z /= b ; return a; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T reduce_add( const Vec3<T>& a ) { return a.x + a.y + a.z; }
+ template<typename T> __forceinline T reduce_mul( const Vec3<T>& a ) { return a.x * a.y * a.z; }
+ template<typename T> __forceinline T reduce_min( const Vec3<T>& a ) { return min(a.x, a.y, a.z); }
+ template<typename T> __forceinline T reduce_max( const Vec3<T>& a ) { return max(a.x, a.y, a.z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const Vec3<T>& a, const Vec3<T>& b ) { return a.x == b.x && a.y == b.y && a.z == b.z; }
+ template<typename T> __forceinline bool operator !=( const Vec3<T>& a, const Vec3<T>& b ) { return a.x != b.x || a.y != b.y || a.z != b.z; }
+ template<typename T> __forceinline bool operator < ( const Vec3<T>& a, const Vec3<T>& b ) {
+ if (a.x != b.x) return a.x < b.x;
+ if (a.y != b.y) return a.y < b.y;
+ if (a.z != b.z) return a.z < b.z;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Shift Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T> shift_right_1( const Vec3<T>& a ) {
+ return Vec3<T>(shift_right_1(a.x),shift_right_1(a.y),shift_right_1(a.z));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<T> select ( bool s, const Vec3<T>& t, const Vec3<T>& f ) {
+ return Vec3<T>(select(s,t.x,f.x),select(s,t.y,f.y),select(s,t.z,f.z));
+ }
+
+ template<typename T> __forceinline Vec3<T> select ( const Vec3<bool>& s, const Vec3<T>& t, const Vec3<T>& f ) {
+ return Vec3<T>(select(s.x,t.x,f.x),select(s.y,t.y,f.y),select(s.z,t.z,f.z));
+ }
+
+ template<typename T> __forceinline Vec3<T> select ( const typename T::Bool& s, const Vec3<T>& t, const Vec3<T>& f ) {
+ return Vec3<T>(select(s,t.x,f.x),select(s,t.y,f.y),select(s,t.z,f.z));
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> lerp(const Vec3<T>& v0, const Vec3<T>& v1, const T& t) {
+ return madd(Vec3<T>(T(1.0f)-t),v0,t*v1);
+ }
+
+ template<typename T> __forceinline int maxDim ( const Vec3<T>& a )
+ {
+ const Vec3<T> b = abs(a);
+ if (b.x > b.y) {
+ if (b.x > b.z) return 0; else return 2;
+ } else {
+ if (b.y > b.z) return 1; else return 2;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec3<bool> eq_mask( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x==b.x,a.y==b.y,a.z==b.z); }
+ template<typename T> __forceinline Vec3<bool> neq_mask(const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x!=b.x,a.y!=b.y,a.z!=b.z); }
+ template<typename T> __forceinline Vec3<bool> lt_mask( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x< b.x,a.y< b.y,a.z< b.z); }
+ template<typename T> __forceinline Vec3<bool> le_mask( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x<=b.x,a.y<=b.y,a.z<=b.z); }
+ template<typename T> __forceinline Vec3<bool> gt_mask( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x> b.x,a.y> b.y,a.z> b.z); }
+ template<typename T> __forceinline Vec3<bool> ge_mask( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<bool>(a.x>=b.x,a.y>=b.y,a.z>=b.z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T sqr ( const Vec3<T>& a ) { return dot(a,a); }
+ template<typename T> __forceinline T dot ( const Vec3<T>& a, const Vec3<T>& b ) { return madd(a.x,b.x,madd(a.y,b.y,a.z*b.z)); }
+ template<typename T> __forceinline T length ( const Vec3<T>& a ) { return sqrt(sqr(a)); }
+ template<typename T> __forceinline T rcp_length( const Vec3<T>& a ) { return rsqrt(sqr(a)); }
+ template<typename T> __forceinline Vec3<T> normalize( const Vec3<T>& a ) { return a*rsqrt(sqr(a)); }
+ template<typename T> __forceinline T distance ( const Vec3<T>& a, const Vec3<T>& b ) { return length(a-b); }
+ template<typename T> __forceinline Vec3<T> cross ( const Vec3<T>& a, const Vec3<T>& b ) { return Vec3<T>(msub(a.y,b.z,a.z*b.y), msub(a.z,b.x,a.x*b.z), msub(a.x,b.y,a.y*b.x)); }
+
+ template<typename T> __forceinline Vec3<T> stable_triangle_normal( const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c )
+ {
+ const T ab_x = a.z*b.y, ab_y = a.x*b.z, ab_z = a.y*b.x;
+ const T bc_x = b.z*c.y, bc_y = b.x*c.z, bc_z = b.y*c.x;
+ const Vec3<T> cross_ab(msub(a.y,b.z,ab_x), msub(a.z,b.x,ab_y), msub(a.x,b.y,ab_z));
+ const Vec3<T> cross_bc(msub(b.y,c.z,bc_x), msub(b.z,c.x,bc_y), msub(b.x,c.y,bc_z));
+ const auto sx = abs(ab_x) < abs(bc_x);
+ const auto sy = abs(ab_y) < abs(bc_y);
+ const auto sz = abs(ab_z) < abs(bc_z);
+ return Vec3<T>(select(sx,cross_ab.x,cross_bc.x),
+ select(sy,cross_ab.y,cross_bc.y),
+ select(sz,cross_ab.z,cross_bc.z));
+ }
+
+ template<typename T> __forceinline T sum ( const Vec3<T>& a ) { return a.x+a.y+a.z; }
+
+ template<typename T> __forceinline T halfArea ( const Vec3<T>& d ) { return madd(d.x,(d.y+d.z),d.y*d.z); }
+ template<typename T> __forceinline T area ( const Vec3<T>& d ) { return 2.0f*halfArea(d); }
+
+ template<typename T> __forceinline Vec3<T> normalize_safe( const Vec3<T>& a ) {
+ const T d = dot(a,a); return select(d == T( zero ), a , a*rsqrt(d) );
+ }
+
+ template<typename T> __forceinline T sqr_point_to_line_distance(const Vec3<T>& P, const Vec3<T>& Q0, const Vec3<T>& Q1)
+ {
+ const Vec3<T> N = cross(P-Q0,Q1-Q0);
+ const Vec3<T> D = Q1-Q0;
+ return dot(N,N)*rcp(dot(D,D));
+ }
+
+ template<typename T> __forceinline T sqr_point_to_line_distance(const Vec3<T>& PmQ0, const Vec3<T>& Q1mQ0)
+ {
+ const Vec3<T> N = cross(PmQ0,Q1mQ0);
+ const Vec3<T> D = Q1mQ0;
+ return dot(N,N)*rcp(dot(D,D));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const Vec3<T>& a) {
+ return cout << "(" << a.x << ", " << a.y << ", " << a.z << ")";
+ }
+
+ typedef Vec3<bool > Vec3b;
+ typedef Vec3<int > Vec3i;
+ typedef Vec3<float> Vec3f;
+}
+
+#include "vec3ba.h"
+#include "vec3ia.h"
+#include "vec3fa.h"
+
+////////////////////////////////////////////////////////////////////////////////
+/// SSE / AVX / MIC specializations
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined __SSE__
+#include "../simd/sse.h"
+#endif
+
+#if defined __AVX__
+#include "../simd/avx.h"
+#endif
+
+#if defined(__AVX512F__)
+#include "../simd/avx512.h"
+#endif
+
+namespace embree
+{
+ template<typename Out, typename In>
+ __forceinline Vec3<Out> broadcast(const Vec3<In>& a, const size_t k) {
+ return Vec3<Out>(Out(a.x[k]), Out(a.y[k]), Out(a.z[k]));
+ }
+
+ template<> __forceinline Vec3<float>::Vec3(const Vec3fa& a) { x = a.x; y = a.y; z = a.z; }
+
+#if defined(__AVX__)
+ template<> __forceinline Vec3<vfloat4>::Vec3(const Vec3fa& a) {
+ x = a.x; y = a.y; z = a.z;
+ }
+#elif defined(__SSE__)
+ template<>
+ __forceinline Vec3<vfloat4>::Vec3(const Vec3fa& a) {
+ const vfloat4 v = vfloat4(a.m128); x = shuffle<0,0,0,0>(v); y = shuffle<1,1,1,1>(v); z = shuffle<2,2,2,2>(v);
+ }
+#endif
+
+#if defined(__SSE__)
+ template<>
+ __forceinline Vec3<vfloat4> broadcast<vfloat4,vfloat4>(const Vec3<vfloat4>& a, const size_t k) {
+ return Vec3<vfloat4>(vfloat4::broadcast(&a.x[k]), vfloat4::broadcast(&a.y[k]), vfloat4::broadcast(&a.z[k]));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline Vec3<vfloat4> shuffle(const Vec3<vfloat4>& b) {
+ return Vec3<vfloat4>(shuffle<i0,i1,i2,i3>(b.x), shuffle<i0,i1,i2,i3>(b.y), shuffle<i0,i1,i2,i3>(b.z));
+ }
+#endif
+
+#if defined(__AVX__)
+ template<>
+ __forceinline Vec3<vfloat8>::Vec3(const Vec3fa& a) {
+ x = a.x; y = a.y; z = a.z;
+ }
+
+ template<>
+ __forceinline Vec3<vfloat8> broadcast<vfloat8,vfloat4>(const Vec3<vfloat4>& a, const size_t k) {
+ return Vec3<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]));
+ }
+ template<>
+ __forceinline Vec3<vfloat8> broadcast<vfloat8,vfloat8>(const Vec3<vfloat8>& a, const size_t k) {
+ return Vec3<vfloat8>(vfloat8::broadcast(&a.x[k]), vfloat8::broadcast(&a.y[k]), vfloat8::broadcast(&a.z[k]));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline Vec3<vfloat8> shuffle(const Vec3<vfloat8>& b) {
+ return Vec3<vfloat8>(shuffle<i0,i1,i2,i3>(b.x), shuffle<i0,i1,i2,i3>(b.y), shuffle<i0,i1,i2,i3>(b.z));
+ }
+#endif
+
+#if defined(__AVX512F__)
+ template<> __forceinline Vec3<vfloat16>::Vec3(const Vec3fa& a) : x(a.x), y(a.y), z(a.z) {}
+#endif
+}
diff --git a/thirdparty/embree/common/math/vec3ba.h b/thirdparty/embree/common/math/vec3ba.h
new file mode 100644
index 0000000000..a021b522dc
--- /dev/null
+++ b/thirdparty/embree/common/math/vec3ba.h
@@ -0,0 +1,120 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/alloc.h"
+#include "math.h"
+#include "../simd/sse.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE Vec3ba Type
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(16) Vec3ba
+ {
+ ALIGNED_STRUCT_(16);
+
+ union {
+ __m128 m128;
+ struct { int x,y,z; };
+ };
+
+ typedef int Scalar;
+ enum { N = 3 };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ba( ) {}
+ __forceinline Vec3ba( const __m128 input ) : m128(input) {}
+ __forceinline Vec3ba( const Vec3ba& other ) : m128(other.m128) {}
+ __forceinline Vec3ba& operator =(const Vec3ba& other) { m128 = other.m128; return *this; }
+
+ __forceinline explicit Vec3ba( bool a )
+ : m128(mm_lookupmask_ps[(size_t(a) << 3) | (size_t(a) << 2) | (size_t(a) << 1) | size_t(a)]) {}
+ __forceinline Vec3ba( bool a, bool b, bool c)
+ : m128(mm_lookupmask_ps[(size_t(c) << 2) | (size_t(b) << 1) | size_t(a)]) {}
+
+ __forceinline operator const __m128&() const { return m128; }
+ __forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ba( FalseTy ) : m128(_mm_setzero_ps()) {}
+ __forceinline Vec3ba( TrueTy ) : m128(_mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()))) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const int& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; }
+ __forceinline int& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; }
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ba operator !( const Vec3ba& a ) { return _mm_xor_ps(a.m128, Vec3ba(embree::True)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ba operator &( const Vec3ba& a, const Vec3ba& b ) { return _mm_and_ps(a.m128, b.m128); }
+ __forceinline Vec3ba operator |( const Vec3ba& a, const Vec3ba& b ) { return _mm_or_ps (a.m128, b.m128); }
+ __forceinline Vec3ba operator ^( const Vec3ba& a, const Vec3ba& b ) { return _mm_xor_ps(a.m128, b.m128); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ba& operator &=( Vec3ba& a, const Vec3ba& b ) { return a = a & b; }
+ __forceinline Vec3ba& operator |=( Vec3ba& a, const Vec3ba& b ) { return a = a | b; }
+ __forceinline Vec3ba& operator ^=( Vec3ba& a, const Vec3ba& b ) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Vec3ba& a, const Vec3ba& b ) {
+ return (_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpeq_epi32(_mm_castps_si128(a.m128), _mm_castps_si128(b.m128)))) & 7) == 7;
+ }
+ __forceinline bool operator !=( const Vec3ba& a, const Vec3ba& b ) {
+ return (_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpeq_epi32(_mm_castps_si128(a.m128), _mm_castps_si128(b.m128)))) & 7) != 7;
+ }
+ __forceinline bool operator < ( const Vec3ba& a, const Vec3ba& b ) {
+ if (a.x != b.x) return a.x < b.x;
+ if (a.y != b.y) return a.y < b.y;
+ if (a.z != b.z) return a.z < b.z;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool reduce_and( const Vec3ba& a ) { return (_mm_movemask_ps(a) & 0x7) == 0x7; }
+ __forceinline bool reduce_or ( const Vec3ba& a ) { return (_mm_movemask_ps(a) & 0x7) != 0x0; }
+
+ __forceinline bool all ( const Vec3ba& b ) { return (_mm_movemask_ps(b) & 0x7) == 0x7; }
+ __forceinline bool any ( const Vec3ba& b ) { return (_mm_movemask_ps(b) & 0x7) != 0x0; }
+ __forceinline bool none ( const Vec3ba& b ) { return (_mm_movemask_ps(b) & 0x7) == 0x0; }
+
+ __forceinline size_t movemask(const Vec3ba& a) { return _mm_movemask_ps(a) & 0x7; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Vec3ba& a) {
+ return cout << "(" << (a.x ? "1" : "0") << ", " << (a.y ? "1" : "0") << ", " << (a.z ? "1" : "0") << ")";
+ }
+}
diff --git a/thirdparty/embree/common/math/vec3fa.h b/thirdparty/embree/common/math/vec3fa.h
new file mode 100644
index 0000000000..586039741d
--- /dev/null
+++ b/thirdparty/embree/common/math/vec3fa.h
@@ -0,0 +1,727 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/alloc.h"
+#include "math.h"
+#include "../simd/sse.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE Vec3fa Type
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(16) Vec3fa
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef float Scalar;
+ enum { N = 3 };
+ union {
+ __m128 m128;
+ struct { float x,y,z; };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa( ) {}
+ __forceinline Vec3fa( const __m128 a ) : m128(a) {}
+
+ __forceinline Vec3fa ( const Vec3<float>& other ) { m128 = _mm_set_ps(0, other.z, other.y, other.x); }
+ //__forceinline Vec3fa& operator =( const Vec3<float>& other ) { m128 = _mm_set_ps(0, other.z, other.y, other.x); return *this; }
+
+ __forceinline Vec3fa ( const Vec3fa& other ) { m128 = other.m128; }
+ __forceinline Vec3fa& operator =( const Vec3fa& other ) { m128 = other.m128; return *this; }
+
+ __forceinline explicit Vec3fa( const float a ) : m128(_mm_set1_ps(a)) {}
+ __forceinline Vec3fa( const float x, const float y, const float z) : m128(_mm_set_ps(0, z, y, x)) {}
+
+ __forceinline explicit Vec3fa( const __m128i a ) : m128(_mm_cvtepi32_ps(a)) {}
+
+ __forceinline explicit operator const vfloat4() const { return vfloat4(m128); }
+ __forceinline explicit operator const vint4() const { return vint4(_mm_cvtps_epi32(m128)); }
+ __forceinline explicit operator const Vec2fa() const { return Vec2fa(m128); }
+ __forceinline explicit operator const Vec3ia() const { return Vec3ia(_mm_cvtps_epi32(m128)); }
+
+ //__forceinline operator const __m128&() const { return m128; }
+ //__forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline Vec3fa load( const void* const a ) {
+ return Vec3fa(_mm_and_ps(_mm_load_ps((float*)a),_mm_castsi128_ps(_mm_set_epi32(0, -1, -1, -1))));
+ }
+
+ static __forceinline Vec3fa loadu( const void* const a ) {
+ return Vec3fa(_mm_loadu_ps((float*)a));
+ }
+
+ static __forceinline void storeu ( void* ptr, const Vec3fa& v ) {
+ _mm_storeu_ps((float*)ptr,v.m128);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa( ZeroTy ) : m128(_mm_setzero_ps()) {}
+ __forceinline Vec3fa( OneTy ) : m128(_mm_set1_ps(1.0f)) {}
+ __forceinline Vec3fa( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {}
+ __forceinline Vec3fa( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; }
+ __forceinline float& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa operator +( const Vec3fa& a ) { return a; }
+ __forceinline Vec3fa operator -( const Vec3fa& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+ return _mm_xor_ps(a.m128, mask);
+ }
+ __forceinline Vec3fa abs ( const Vec3fa& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
+ return _mm_and_ps(a.m128, mask);
+ }
+ __forceinline Vec3fa sign ( const Vec3fa& a ) {
+ return blendv_ps(Vec3fa(one).m128, (-Vec3fa(one)).m128, _mm_cmplt_ps (a.m128,Vec3fa(zero).m128));
+ }
+
+ __forceinline Vec3fa rcp ( const Vec3fa& a )
+ {
+#if defined(__AVX512VL__)
+ const Vec3fa r = _mm_rcp14_ps(a.m128);
+#else
+ const Vec3fa r = _mm_rcp_ps(a.m128);
+#endif
+
+#if defined(__AVX2__)
+ const Vec3fa res = _mm_mul_ps(r.m128,_mm_fnmadd_ps(r.m128, a.m128, vfloat4(2.0f)));
+#else
+ const Vec3fa res = _mm_mul_ps(r.m128,_mm_sub_ps(vfloat4(2.0f), _mm_mul_ps(r.m128, a.m128)));
+ //return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
+#endif
+
+ return res;
+ }
+
+ __forceinline Vec3fa sqrt ( const Vec3fa& a ) { return _mm_sqrt_ps(a.m128); }
+ __forceinline Vec3fa sqr ( const Vec3fa& a ) { return _mm_mul_ps(a.m128,a.m128); }
+
+ __forceinline Vec3fa rsqrt( const Vec3fa& a )
+ {
+#if defined(__AVX512VL__)
+ __m128 r = _mm_rsqrt14_ps(a.m128);
+#else
+ __m128 r = _mm_rsqrt_ps(a.m128);
+#endif
+ return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a.m128, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+ }
+
+ __forceinline Vec3fa zero_fix(const Vec3fa& a) {
+ return blendv_ps(a.m128, _mm_set1_ps(min_rcp_input), _mm_cmplt_ps (abs(a).m128, _mm_set1_ps(min_rcp_input)));
+ }
+ __forceinline Vec3fa rcp_safe(const Vec3fa& a) {
+ return rcp(zero_fix(a));
+ }
+ __forceinline Vec3fa log ( const Vec3fa& a ) {
+ return Vec3fa(logf(a.x),logf(a.y),logf(a.z));
+ }
+
+ __forceinline Vec3fa exp ( const Vec3fa& a ) {
+ return Vec3fa(expf(a.x),expf(a.y),expf(a.z));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa operator +( const Vec3fa& a, const Vec3fa& b ) { return _mm_add_ps(a.m128, b.m128); }
+ __forceinline Vec3fa operator -( const Vec3fa& a, const Vec3fa& b ) { return _mm_sub_ps(a.m128, b.m128); }
+ __forceinline Vec3fa operator *( const Vec3fa& a, const Vec3fa& b ) { return _mm_mul_ps(a.m128, b.m128); }
+ __forceinline Vec3fa operator *( const Vec3fa& a, const float b ) { return a * Vec3fa(b); }
+ __forceinline Vec3fa operator *( const float a, const Vec3fa& b ) { return Vec3fa(a) * b; }
+ __forceinline Vec3fa operator /( const Vec3fa& a, const Vec3fa& b ) { return _mm_div_ps(a.m128,b.m128); }
+ __forceinline Vec3fa operator /( const Vec3fa& a, const float b ) { return _mm_div_ps(a.m128,_mm_set1_ps(b)); }
+ __forceinline Vec3fa operator /( const float a, const Vec3fa& b ) { return _mm_div_ps(_mm_set1_ps(a),b.m128); }
+
+ __forceinline Vec3fa min( const Vec3fa& a, const Vec3fa& b ) { return _mm_min_ps(a.m128,b.m128); }
+ __forceinline Vec3fa max( const Vec3fa& a, const Vec3fa& b ) { return _mm_max_ps(a.m128,b.m128); }
+
+#if defined(__SSE4_1__)
+ __forceinline Vec3fa mini(const Vec3fa& a, const Vec3fa& b) {
+ const vint4 ai = _mm_castps_si128(a.m128);
+ const vint4 bi = _mm_castps_si128(b.m128);
+ const vint4 ci = _mm_min_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+#if defined(__SSE4_1__)
+ __forceinline Vec3fa maxi(const Vec3fa& a, const Vec3fa& b) {
+ const vint4 ai = _mm_castps_si128(a.m128);
+ const vint4 bi = _mm_castps_si128(b.m128);
+ const vint4 ci = _mm_max_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+ __forceinline Vec3fa pow ( const Vec3fa& a, const float& b ) {
+ return Vec3fa(powf(a.x,b),powf(a.y,b),powf(a.z,b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ __forceinline Vec3fa madd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fmadd_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fa msub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fmsub_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fnmadd_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fa nmsub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return _mm_fnmsub_ps(a.m128,b.m128,c.m128); }
+#else
+ __forceinline Vec3fa madd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return a*b+c; }
+ __forceinline Vec3fa msub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return a*b-c; }
+ __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return -a*b+c;}
+ __forceinline Vec3fa nmsub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return -a*b-c; }
+#endif
+
+ __forceinline Vec3fa madd ( const float a, const Vec3fa& b, const Vec3fa& c) { return madd(Vec3fa(a),b,c); }
+ __forceinline Vec3fa msub ( const float a, const Vec3fa& b, const Vec3fa& c) { return msub(Vec3fa(a),b,c); }
+ __forceinline Vec3fa nmadd ( const float a, const Vec3fa& b, const Vec3fa& c) { return nmadd(Vec3fa(a),b,c); }
+ __forceinline Vec3fa nmsub ( const float a, const Vec3fa& b, const Vec3fa& c) { return nmsub(Vec3fa(a),b,c); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa& operator +=( Vec3fa& a, const Vec3fa& b ) { return a = a + b; }
+ __forceinline Vec3fa& operator -=( Vec3fa& a, const Vec3fa& b ) { return a = a - b; }
+ __forceinline Vec3fa& operator *=( Vec3fa& a, const Vec3fa& b ) { return a = a * b; }
+ __forceinline Vec3fa& operator *=( Vec3fa& a, const float b ) { return a = a * b; }
+ __forceinline Vec3fa& operator /=( Vec3fa& a, const Vec3fa& b ) { return a = a / b; }
+ __forceinline Vec3fa& operator /=( Vec3fa& a, const float b ) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float reduce_add(const Vec3fa& v) {
+ const vfloat4 a(v.m128);
+ const vfloat4 b = shuffle<1>(a);
+ const vfloat4 c = shuffle<2>(a);
+ return _mm_cvtss_f32(a+b+c);
+ }
+
+ __forceinline float reduce_mul(const Vec3fa& v) { return v.x*v.y*v.z; }
+ __forceinline float reduce_min(const Vec3fa& v) { return min(v.x,v.y,v.z); }
+ __forceinline float reduce_max(const Vec3fa& v) { return max(v.x,v.y,v.z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Vec3fa& a, const Vec3fa& b ) { return (_mm_movemask_ps(_mm_cmpeq_ps (a.m128, b.m128)) & 7) == 7; }
+ __forceinline bool operator !=( const Vec3fa& a, const Vec3fa& b ) { return (_mm_movemask_ps(_mm_cmpneq_ps(a.m128, b.m128)) & 7) != 0; }
+
+ __forceinline Vec3ba eq_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpeq_ps (a.m128, b.m128); }
+ __forceinline Vec3ba neq_mask(const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpneq_ps(a.m128, b.m128); }
+ __forceinline Vec3ba lt_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmplt_ps (a.m128, b.m128); }
+ __forceinline Vec3ba le_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmple_ps (a.m128, b.m128); }
+ __forceinline Vec3ba gt_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpnle_ps(a.m128, b.m128); }
+ __forceinline Vec3ba ge_mask( const Vec3fa& a, const Vec3fa& b ) { return _mm_cmpnlt_ps(a.m128, b.m128); }
+
+ __forceinline bool isvalid ( const Vec3fa& v ) {
+ return all(gt_mask(v,Vec3fa(-FLT_LARGE)) & lt_mask(v,Vec3fa(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite ( const Vec3fa& a ) {
+ return all(ge_mask(a,Vec3fa(-FLT_MAX)) & le_mask(a,Vec3fa(+FLT_MAX)));
+ }
+
+ __forceinline bool isvalid4 ( const Vec3fa& v ) {
+ return all((vfloat4(v.m128) > vfloat4(-FLT_LARGE)) & (vfloat4(v.m128) < vfloat4(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite4 ( const Vec3fa& a ) {
+ return all((vfloat4(a.m128) >= vfloat4(-FLT_MAX)) & (vfloat4(a.m128) <= vfloat4(+FLT_MAX)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SSE4_1__)
+ __forceinline float dot ( const Vec3fa& a, const Vec3fa& b ) {
+ return _mm_cvtss_f32(_mm_dp_ps(a.m128,b.m128,0x7F));
+ }
+#else
+ __forceinline float dot ( const Vec3fa& a, const Vec3fa& b ) {
+ return reduce_add(a*b);
+ }
+#endif
+
+ __forceinline Vec3fa cross ( const Vec3fa& a, const Vec3fa& b )
+ {
+ vfloat4 a0 = vfloat4(a.m128);
+ vfloat4 b0 = shuffle<1,2,0,3>(vfloat4(b.m128));
+ vfloat4 a1 = shuffle<1,2,0,3>(vfloat4(a.m128));
+ vfloat4 b1 = vfloat4(b.m128);
+ return Vec3fa(shuffle<1,2,0,3>(msub(a0,b0,a1*b1)));
+ }
+
+ __forceinline float sqr_length ( const Vec3fa& a ) { return dot(a,a); }
+ __forceinline float rcp_length ( const Vec3fa& a ) { return rsqrt(dot(a,a)); }
+ __forceinline float rcp_length2( const Vec3fa& a ) { return rcp(dot(a,a)); }
+ __forceinline float length ( const Vec3fa& a ) { return sqrt(dot(a,a)); }
+ __forceinline Vec3fa normalize( const Vec3fa& a ) { return a*rsqrt(dot(a,a)); }
+ __forceinline float distance ( const Vec3fa& a, const Vec3fa& b ) { return length(a-b); }
+ __forceinline float halfArea ( const Vec3fa& d ) { return madd(d.x,(d.y+d.z),d.y*d.z); }
+ __forceinline float area ( const Vec3fa& d ) { return 2.0f*halfArea(d); }
+
+ __forceinline Vec3fa normalize_safe( const Vec3fa& a ) {
+ const float d = dot(a,a); if (unlikely(d == 0.0f)) return a; else return a*rsqrt(d);
+ }
+
+ /*! differentiated normalization */
+ __forceinline Vec3fa dnormalize(const Vec3fa& p, const Vec3fa& dp)
+ {
+ const float pp = dot(p,p);
+ const float pdp = dot(p,dp);
+ return (pp*dp-pdp*p)*rcp(pp)*rsqrt(pp);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fa select( bool s, const Vec3fa& t, const Vec3fa& f ) {
+ __m128 mask = s ? _mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())) : _mm_setzero_ps();
+ return blendv_ps(f.m128, t.m128, mask);
+ }
+
+ __forceinline Vec3fa select( const Vec3ba& s, const Vec3fa& t, const Vec3fa& f ) {
+ return blendv_ps(f.m128, t.m128, s);
+ }
+
+ __forceinline Vec3fa lerp(const Vec3fa& v0, const Vec3fa& v1, const float t) {
+ return madd(1.0f-t,v0,t*v1);
+ }
+
+ __forceinline int maxDim ( const Vec3fa& a )
+ {
+ const Vec3fa b = abs(a);
+ if (b.x > b.y) {
+ if (b.x > b.z) return 0; else return 2;
+ } else {
+ if (b.y > b.z) return 1; else return 2;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined (__SSE4_1__)
+ __forceinline Vec3fa trunc( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEAREST_INT); }
+ __forceinline Vec3fa floor( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEG_INF ); }
+ __forceinline Vec3fa ceil ( const Vec3fa& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_POS_INF ); }
+#else
+ __forceinline Vec3fa trunc( const Vec3fa& a ) { return Vec3fa(truncf(a.x),truncf(a.y),truncf(a.z)); }
+ __forceinline Vec3fa floor( const Vec3fa& a ) { return Vec3fa(floorf(a.x),floorf(a.y),floorf(a.z)); }
+ __forceinline Vec3fa ceil ( const Vec3fa& a ) { return Vec3fa(ceilf (a.x),ceilf (a.y),ceilf (a.z)); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Vec3fa& a) {
+ return cout << "(" << a.x << ", " << a.y << ", " << a.z << ")";
+ }
+
+ typedef Vec3fa Vec3fa_t;
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE Vec3fx Type
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(16) Vec3fx
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef float Scalar;
+ enum { N = 3 };
+ union {
+ __m128 m128;
+ struct { float x,y,z; union { int a; unsigned u; float w; }; };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx( ) {}
+ __forceinline Vec3fx( const __m128 a ) : m128(a) {}
+
+ __forceinline explicit Vec3fx(const Vec3fa& v) : m128(v.m128) {}
+ __forceinline operator Vec3fa () const { return Vec3fa(m128); }
+
+ __forceinline explicit Vec3fx ( const Vec3<float>& other ) { m128 = _mm_set_ps(0, other.z, other.y, other.x); }
+ //__forceinline Vec3fx& operator =( const Vec3<float>& other ) { m128 = _mm_set_ps(0, other.z, other.y, other.x); return *this; }
+
+ __forceinline Vec3fx ( const Vec3fx& other ) { m128 = other.m128; }
+
+ __forceinline Vec3fx& operator =( const Vec3fx& other ) { m128 = other.m128; return *this; }
+
+ __forceinline explicit Vec3fx( const float a ) : m128(_mm_set1_ps(a)) {}
+ __forceinline Vec3fx( const float x, const float y, const float z) : m128(_mm_set_ps(0, z, y, x)) {}
+
+ __forceinline Vec3fx( const Vec3fa& other, const int a1) { m128 = other.m128; a = a1; }
+ __forceinline Vec3fx( const Vec3fa& other, const unsigned a1) { m128 = other.m128; u = a1; }
+ __forceinline Vec3fx( const Vec3fa& other, const float w1) {
+#if defined (__SSE4_1__)
+ m128 = _mm_insert_ps(other.m128, _mm_set_ss(w1),3 << 4);
+#else
+ const vint4 mask(-1,-1,-1,0);
+ m128 = select(vboolf4(_mm_castsi128_ps(mask)),vfloat4(other.m128),vfloat4(w1));
+#endif
+ }
+ //__forceinline Vec3fx( const float x, const float y, const float z, const int a) : x(x), y(y), z(z), a(a) {} // not working properly!
+ //__forceinline Vec3fx( const float x, const float y, const float z, const unsigned a) : x(x), y(y), z(z), u(a) {} // not working properly!
+ __forceinline Vec3fx( const float x, const float y, const float z, const float w) : m128(_mm_set_ps(w, z, y, x)) {}
+
+ //__forceinline explicit Vec3fx( const __m128i a ) : m128(_mm_cvtepi32_ps(a)) {}
+
+ __forceinline explicit operator const vfloat4() const { return vfloat4(m128); }
+ __forceinline explicit operator const vint4() const { return vint4(_mm_cvtps_epi32(m128)); }
+ __forceinline explicit operator const Vec2fa() const { return Vec2fa(m128); }
+ __forceinline explicit operator const Vec3ia() const { return Vec3ia(_mm_cvtps_epi32(m128)); }
+
+ //__forceinline operator const __m128&() const { return m128; }
+ //__forceinline operator __m128&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline Vec3fx load( const void* const a ) {
+ return Vec3fx(_mm_and_ps(_mm_load_ps((float*)a),_mm_castsi128_ps(_mm_set_epi32(0, -1, -1, -1))));
+ }
+
+ static __forceinline Vec3fx loadu( const void* const a ) {
+ return Vec3fx(_mm_loadu_ps((float*)a));
+ }
+
+ static __forceinline void storeu ( void* ptr, const Vec3fx& v ) {
+ _mm_storeu_ps((float*)ptr,v.m128);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx( ZeroTy ) : m128(_mm_setzero_ps()) {}
+ __forceinline Vec3fx( OneTy ) : m128(_mm_set1_ps(1.0f)) {}
+ __forceinline Vec3fx( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {}
+ __forceinline Vec3fx( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; }
+ __forceinline float& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx operator +( const Vec3fx& a ) { return a; }
+ __forceinline Vec3fx operator -( const Vec3fx& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+ return _mm_xor_ps(a.m128, mask);
+ }
+ __forceinline Vec3fx abs ( const Vec3fx& a ) {
+ const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
+ return _mm_and_ps(a.m128, mask);
+ }
+ __forceinline Vec3fx sign ( const Vec3fx& a ) {
+ return blendv_ps(Vec3fx(one).m128, (-Vec3fx(one)).m128, _mm_cmplt_ps (a.m128,Vec3fx(zero).m128));
+ }
+
+ __forceinline Vec3fx rcp ( const Vec3fx& a )
+ {
+#if defined(__AVX512VL__)
+ const Vec3fx r = _mm_rcp14_ps(a.m128);
+#else
+ const Vec3fx r = _mm_rcp_ps(a.m128);
+#endif
+
+#if defined(__AVX2__)
+ const Vec3fx res = _mm_mul_ps(r.m128,_mm_fnmadd_ps(r.m128, a.m128, vfloat4(2.0f)));
+#else
+ const Vec3fx res = _mm_mul_ps(r.m128,_mm_sub_ps(vfloat4(2.0f), _mm_mul_ps(r.m128, a.m128)));
+ //return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
+#endif
+
+ return res;
+ }
+
+ __forceinline Vec3fx sqrt ( const Vec3fx& a ) { return _mm_sqrt_ps(a.m128); }
+ __forceinline Vec3fx sqr ( const Vec3fx& a ) { return _mm_mul_ps(a.m128,a.m128); }
+
+ __forceinline Vec3fx rsqrt( const Vec3fx& a )
+ {
+#if defined(__AVX512VL__)
+ __m128 r = _mm_rsqrt14_ps(a.m128);
+#else
+ __m128 r = _mm_rsqrt_ps(a.m128);
+#endif
+ return _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f),r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a.m128, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+ }
+
+ __forceinline Vec3fx zero_fix(const Vec3fx& a) {
+ return blendv_ps(a.m128, _mm_set1_ps(min_rcp_input), _mm_cmplt_ps (abs(a).m128, _mm_set1_ps(min_rcp_input)));
+ }
+ __forceinline Vec3fx rcp_safe(const Vec3fx& a) {
+ return rcp(zero_fix(a));
+ }
+ __forceinline Vec3fx log ( const Vec3fx& a ) {
+ return Vec3fx(logf(a.x),logf(a.y),logf(a.z));
+ }
+
+ __forceinline Vec3fx exp ( const Vec3fx& a ) {
+ return Vec3fx(expf(a.x),expf(a.y),expf(a.z));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx operator +( const Vec3fx& a, const Vec3fx& b ) { return _mm_add_ps(a.m128, b.m128); }
+ __forceinline Vec3fx operator -( const Vec3fx& a, const Vec3fx& b ) { return _mm_sub_ps(a.m128, b.m128); }
+ __forceinline Vec3fx operator *( const Vec3fx& a, const Vec3fx& b ) { return _mm_mul_ps(a.m128, b.m128); }
+ __forceinline Vec3fx operator *( const Vec3fx& a, const float b ) { return a * Vec3fx(b); }
+ __forceinline Vec3fx operator *( const float a, const Vec3fx& b ) { return Vec3fx(a) * b; }
+ __forceinline Vec3fx operator /( const Vec3fx& a, const Vec3fx& b ) { return _mm_div_ps(a.m128,b.m128); }
+ __forceinline Vec3fx operator /( const Vec3fx& a, const float b ) { return _mm_div_ps(a.m128,_mm_set1_ps(b)); }
+ __forceinline Vec3fx operator /( const float a, const Vec3fx& b ) { return _mm_div_ps(_mm_set1_ps(a),b.m128); }
+
+ __forceinline Vec3fx min( const Vec3fx& a, const Vec3fx& b ) { return _mm_min_ps(a.m128,b.m128); }
+ __forceinline Vec3fx max( const Vec3fx& a, const Vec3fx& b ) { return _mm_max_ps(a.m128,b.m128); }
+
+#if defined(__SSE4_1__)
+ __forceinline Vec3fx mini(const Vec3fx& a, const Vec3fx& b) {
+ const vint4 ai = _mm_castps_si128(a.m128);
+ const vint4 bi = _mm_castps_si128(b.m128);
+ const vint4 ci = _mm_min_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+#if defined(__SSE4_1__)
+ __forceinline Vec3fx maxi(const Vec3fx& a, const Vec3fx& b) {
+ const vint4 ai = _mm_castps_si128(a.m128);
+ const vint4 bi = _mm_castps_si128(b.m128);
+ const vint4 ci = _mm_max_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#endif
+
+ __forceinline Vec3fx pow ( const Vec3fx& a, const float& b ) {
+ return Vec3fx(powf(a.x,b),powf(a.y,b),powf(a.z,b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ __forceinline Vec3fx madd ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return _mm_fmadd_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fx msub ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return _mm_fmsub_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fx nmadd ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return _mm_fnmadd_ps(a.m128,b.m128,c.m128); }
+ __forceinline Vec3fx nmsub ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return _mm_fnmsub_ps(a.m128,b.m128,c.m128); }
+#else
+ __forceinline Vec3fx madd ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return a*b+c; }
+ __forceinline Vec3fx msub ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return a*b-c; }
+ __forceinline Vec3fx nmadd ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return -a*b+c;}
+ __forceinline Vec3fx nmsub ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return -a*b-c; }
+#endif
+
+ __forceinline Vec3fx madd ( const float a, const Vec3fx& b, const Vec3fx& c) { return madd(Vec3fx(a),b,c); }
+ __forceinline Vec3fx msub ( const float a, const Vec3fx& b, const Vec3fx& c) { return msub(Vec3fx(a),b,c); }
+ __forceinline Vec3fx nmadd ( const float a, const Vec3fx& b, const Vec3fx& c) { return nmadd(Vec3fx(a),b,c); }
+ __forceinline Vec3fx nmsub ( const float a, const Vec3fx& b, const Vec3fx& c) { return nmsub(Vec3fx(a),b,c); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx& operator +=( Vec3fx& a, const Vec3fx& b ) { return a = a + b; }
+ __forceinline Vec3fx& operator -=( Vec3fx& a, const Vec3fx& b ) { return a = a - b; }
+ __forceinline Vec3fx& operator *=( Vec3fx& a, const Vec3fx& b ) { return a = a * b; }
+ __forceinline Vec3fx& operator *=( Vec3fx& a, const float b ) { return a = a * b; }
+ __forceinline Vec3fx& operator /=( Vec3fx& a, const Vec3fx& b ) { return a = a / b; }
+ __forceinline Vec3fx& operator /=( Vec3fx& a, const float b ) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float reduce_add(const Vec3fx& v) {
+ const vfloat4 a(v.m128);
+ const vfloat4 b = shuffle<1>(a);
+ const vfloat4 c = shuffle<2>(a);
+ return _mm_cvtss_f32(a+b+c);
+ }
+
+ __forceinline float reduce_mul(const Vec3fx& v) { return v.x*v.y*v.z; }
+ __forceinline float reduce_min(const Vec3fx& v) { return min(v.x,v.y,v.z); }
+ __forceinline float reduce_max(const Vec3fx& v) { return max(v.x,v.y,v.z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Vec3fx& a, const Vec3fx& b ) { return (_mm_movemask_ps(_mm_cmpeq_ps (a.m128, b.m128)) & 7) == 7; }
+ __forceinline bool operator !=( const Vec3fx& a, const Vec3fx& b ) { return (_mm_movemask_ps(_mm_cmpneq_ps(a.m128, b.m128)) & 7) != 0; }
+
+ __forceinline Vec3ba eq_mask( const Vec3fx& a, const Vec3fx& b ) { return _mm_cmpeq_ps (a.m128, b.m128); }
+ __forceinline Vec3ba neq_mask(const Vec3fx& a, const Vec3fx& b ) { return _mm_cmpneq_ps(a.m128, b.m128); }
+ __forceinline Vec3ba lt_mask( const Vec3fx& a, const Vec3fx& b ) { return _mm_cmplt_ps (a.m128, b.m128); }
+ __forceinline Vec3ba le_mask( const Vec3fx& a, const Vec3fx& b ) { return _mm_cmple_ps (a.m128, b.m128); }
+ __forceinline Vec3ba gt_mask( const Vec3fx& a, const Vec3fx& b ) { return _mm_cmpnle_ps(a.m128, b.m128); }
+ __forceinline Vec3ba ge_mask( const Vec3fx& a, const Vec3fx& b ) { return _mm_cmpnlt_ps(a.m128, b.m128); }
+
+ __forceinline bool isvalid ( const Vec3fx& v ) {
+ return all(gt_mask(v,Vec3fx(-FLT_LARGE)) & lt_mask(v,Vec3fx(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite ( const Vec3fx& a ) {
+ return all(ge_mask(a,Vec3fx(-FLT_MAX)) & le_mask(a,Vec3fx(+FLT_MAX)));
+ }
+
+ __forceinline bool isvalid4 ( const Vec3fx& v ) {
+ return all((vfloat4(v.m128) > vfloat4(-FLT_LARGE)) & (vfloat4(v.m128) < vfloat4(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite4 ( const Vec3fx& a ) {
+ return all((vfloat4(a.m128) >= vfloat4(-FLT_MAX)) & (vfloat4(a.m128) <= vfloat4(+FLT_MAX)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SSE4_1__)
+ __forceinline float dot ( const Vec3fx& a, const Vec3fx& b ) {
+ return _mm_cvtss_f32(_mm_dp_ps(a.m128,b.m128,0x7F));
+ }
+#else
+ __forceinline float dot ( const Vec3fx& a, const Vec3fx& b ) {
+ return reduce_add(a*b);
+ }
+#endif
+
+ __forceinline Vec3fx cross ( const Vec3fx& a, const Vec3fx& b )
+ {
+ vfloat4 a0 = vfloat4(a.m128);
+ vfloat4 b0 = shuffle<1,2,0,3>(vfloat4(b.m128));
+ vfloat4 a1 = shuffle<1,2,0,3>(vfloat4(a.m128));
+ vfloat4 b1 = vfloat4(b.m128);
+ return Vec3fx(shuffle<1,2,0,3>(msub(a0,b0,a1*b1)));
+ }
+
+ __forceinline float sqr_length ( const Vec3fx& a ) { return dot(a,a); }
+ __forceinline float rcp_length ( const Vec3fx& a ) { return rsqrt(dot(a,a)); }
+ __forceinline float rcp_length2( const Vec3fx& a ) { return rcp(dot(a,a)); }
+ __forceinline float length ( const Vec3fx& a ) { return sqrt(dot(a,a)); }
+ __forceinline Vec3fx normalize( const Vec3fx& a ) { return a*rsqrt(dot(a,a)); }
+ __forceinline float distance ( const Vec3fx& a, const Vec3fx& b ) { return length(a-b); }
+ __forceinline float halfArea ( const Vec3fx& d ) { return madd(d.x,(d.y+d.z),d.y*d.z); }
+ __forceinline float area ( const Vec3fx& d ) { return 2.0f*halfArea(d); }
+
+ __forceinline Vec3fx normalize_safe( const Vec3fx& a ) {
+ const float d = dot(a,a); if (unlikely(d == 0.0f)) return a; else return a*rsqrt(d);
+ }
+
+ /*! differentiated normalization */
+ __forceinline Vec3fx dnormalize(const Vec3fx& p, const Vec3fx& dp)
+ {
+ const float pp = dot(p,p);
+ const float pdp = dot(p,dp);
+ return (pp*dp-pdp*p)*rcp(pp)*rsqrt(pp);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3fx select( bool s, const Vec3fx& t, const Vec3fx& f ) {
+ __m128 mask = s ? _mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())) : _mm_setzero_ps();
+ return blendv_ps(f.m128, t.m128, mask);
+ }
+
+ __forceinline Vec3fx select( const Vec3ba& s, const Vec3fx& t, const Vec3fx& f ) {
+ return blendv_ps(f.m128, t.m128, s);
+ }
+
+ __forceinline Vec3fx lerp(const Vec3fx& v0, const Vec3fx& v1, const float t) {
+ return madd(1.0f-t,v0,t*v1);
+ }
+
+ __forceinline int maxDim ( const Vec3fx& a )
+ {
+ const Vec3fx b = abs(a);
+ if (b.x > b.y) {
+ if (b.x > b.z) return 0; else return 2;
+ } else {
+ if (b.y > b.z) return 1; else return 2;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__aarch64__)
+ __forceinline Vec3fx trunc(const Vec3fx& a) { return vrndq_f32(a.m128); }
+ __forceinline Vec3fx floor(const Vec3fx& a) { return vrndmq_f32(a.m128); }
+ __forceinline Vec3fx ceil (const Vec3fx& a) { return vrndpq_f32(a.m128); }
+#elif defined (__SSE4_1__)
+ __forceinline Vec3fx trunc( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEAREST_INT); }
+ __forceinline Vec3fx floor( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_NEG_INF ); }
+ __forceinline Vec3fx ceil ( const Vec3fx& a ) { return _mm_round_ps(a.m128, _MM_FROUND_TO_POS_INF ); }
+#else
+ __forceinline Vec3fx trunc( const Vec3fx& a ) { return Vec3fx(truncf(a.x),truncf(a.y),truncf(a.z)); }
+ __forceinline Vec3fx floor( const Vec3fx& a ) { return Vec3fx(floorf(a.x),floorf(a.y),floorf(a.z)); }
+ __forceinline Vec3fx ceil ( const Vec3fx& a ) { return Vec3fx(ceilf (a.x),ceilf (a.y),ceilf (a.z)); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Vec3fx& a) {
+ return cout << "(" << a.x << ", " << a.y << ", " << a.z << ")";
+ }
+
+
+ typedef Vec3fx Vec3ff;
+}
diff --git a/thirdparty/embree/common/math/vec3ia.h b/thirdparty/embree/common/math/vec3ia.h
new file mode 100644
index 0000000000..694804c40d
--- /dev/null
+++ b/thirdparty/embree/common/math/vec3ia.h
@@ -0,0 +1,186 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/alloc.h"
+#include "math.h"
+#include "../simd/sse.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// SSE Vec3ia Type
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(16) Vec3ia
+ {
+ ALIGNED_STRUCT_(16);
+
+ union {
+ __m128i m128;
+ struct { int x,y,z; };
+ };
+
+ typedef int Scalar;
+ enum { N = 3 };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia( ) {}
+ __forceinline Vec3ia( const __m128i a ) : m128(a) {}
+ __forceinline Vec3ia( const Vec3ia& other ) : m128(other.m128) {}
+ __forceinline Vec3ia& operator =(const Vec3ia& other) { m128 = other.m128; return *this; }
+
+ __forceinline explicit Vec3ia( const int a ) : m128(_mm_set1_epi32(a)) {}
+ __forceinline Vec3ia( const int x, const int y, const int z) : m128(_mm_set_epi32(z, z, y, x)) {}
+ __forceinline explicit Vec3ia( const __m128 a ) : m128(_mm_cvtps_epi32(a)) {}
+
+ __forceinline operator const __m128i&() const { return m128; }
+ __forceinline operator __m128i&() { return m128; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia( ZeroTy ) : m128(_mm_setzero_si128()) {}
+ __forceinline Vec3ia( OneTy ) : m128(_mm_set1_epi32(1)) {}
+ __forceinline Vec3ia( PosInfTy ) : m128(_mm_set1_epi32(pos_inf)) {}
+ __forceinline Vec3ia( NegInfTy ) : m128(_mm_set1_epi32(neg_inf)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const int& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; }
+ __forceinline int& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; }
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia operator +( const Vec3ia& a ) { return a; }
+ __forceinline Vec3ia operator -( const Vec3ia& a ) { return _mm_sub_epi32(_mm_setzero_si128(), a.m128); }
+#if defined(__SSSE3__)
+ __forceinline Vec3ia abs ( const Vec3ia& a ) { return _mm_abs_epi32(a.m128); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia operator +( const Vec3ia& a, const Vec3ia& b ) { return _mm_add_epi32(a.m128, b.m128); }
+ __forceinline Vec3ia operator +( const Vec3ia& a, const int b ) { return a+Vec3ia(b); }
+ __forceinline Vec3ia operator +( const int a, const Vec3ia& b ) { return Vec3ia(a)+b; }
+
+ __forceinline Vec3ia operator -( const Vec3ia& a, const Vec3ia& b ) { return _mm_sub_epi32(a.m128, b.m128); }
+ __forceinline Vec3ia operator -( const Vec3ia& a, const int b ) { return a-Vec3ia(b); }
+ __forceinline Vec3ia operator -( const int a, const Vec3ia& b ) { return Vec3ia(a)-b; }
+
+#if defined(__SSE4_1__)
+ __forceinline Vec3ia operator *( const Vec3ia& a, const Vec3ia& b ) { return _mm_mullo_epi32(a.m128, b.m128); }
+ __forceinline Vec3ia operator *( const Vec3ia& a, const int b ) { return a * Vec3ia(b); }
+ __forceinline Vec3ia operator *( const int a, const Vec3ia& b ) { return Vec3ia(a) * b; }
+#endif
+
+ __forceinline Vec3ia operator &( const Vec3ia& a, const Vec3ia& b ) { return _mm_and_si128(a.m128, b.m128); }
+ __forceinline Vec3ia operator &( const Vec3ia& a, const int b ) { return a & Vec3ia(b); }
+ __forceinline Vec3ia operator &( const int a, const Vec3ia& b ) { return Vec3ia(a) & b; }
+
+ __forceinline Vec3ia operator |( const Vec3ia& a, const Vec3ia& b ) { return _mm_or_si128(a.m128, b.m128); }
+ __forceinline Vec3ia operator |( const Vec3ia& a, const int b ) { return a | Vec3ia(b); }
+ __forceinline Vec3ia operator |( const int a, const Vec3ia& b ) { return Vec3ia(a) | b; }
+
+ __forceinline Vec3ia operator ^( const Vec3ia& a, const Vec3ia& b ) { return _mm_xor_si128(a.m128, b.m128); }
+ __forceinline Vec3ia operator ^( const Vec3ia& a, const int b ) { return a ^ Vec3ia(b); }
+ __forceinline Vec3ia operator ^( const int a, const Vec3ia& b ) { return Vec3ia(a) ^ b; }
+
+ __forceinline Vec3ia operator <<( const Vec3ia& a, const int n ) { return _mm_slli_epi32(a.m128, n); }
+ __forceinline Vec3ia operator >>( const Vec3ia& a, const int n ) { return _mm_srai_epi32(a.m128, n); }
+
+ __forceinline Vec3ia sll ( const Vec3ia& a, const int b ) { return _mm_slli_epi32(a.m128, b); }
+ __forceinline Vec3ia sra ( const Vec3ia& a, const int b ) { return _mm_srai_epi32(a.m128, b); }
+ __forceinline Vec3ia srl ( const Vec3ia& a, const int b ) { return _mm_srli_epi32(a.m128, b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia& operator +=( Vec3ia& a, const Vec3ia& b ) { return a = a + b; }
+ __forceinline Vec3ia& operator +=( Vec3ia& a, const int& b ) { return a = a + b; }
+
+ __forceinline Vec3ia& operator -=( Vec3ia& a, const Vec3ia& b ) { return a = a - b; }
+ __forceinline Vec3ia& operator -=( Vec3ia& a, const int& b ) { return a = a - b; }
+
+#if defined(__SSE4_1__)
+ __forceinline Vec3ia& operator *=( Vec3ia& a, const Vec3ia& b ) { return a = a * b; }
+ __forceinline Vec3ia& operator *=( Vec3ia& a, const int& b ) { return a = a * b; }
+#endif
+
+ __forceinline Vec3ia& operator &=( Vec3ia& a, const Vec3ia& b ) { return a = a & b; }
+ __forceinline Vec3ia& operator &=( Vec3ia& a, const int& b ) { return a = a & b; }
+
+ __forceinline Vec3ia& operator |=( Vec3ia& a, const Vec3ia& b ) { return a = a | b; }
+ __forceinline Vec3ia& operator |=( Vec3ia& a, const int& b ) { return a = a | b; }
+
+ __forceinline Vec3ia& operator <<=( Vec3ia& a, const int& b ) { return a = a << b; }
+ __forceinline Vec3ia& operator >>=( Vec3ia& a, const int& b ) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int reduce_add(const Vec3ia& v) { return v.x+v.y+v.z; }
+ __forceinline int reduce_mul(const Vec3ia& v) { return v.x*v.y*v.z; }
+ __forceinline int reduce_min(const Vec3ia& v) { return min(v.x,v.y,v.z); }
+ __forceinline int reduce_max(const Vec3ia& v) { return max(v.x,v.y,v.z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator ==( const Vec3ia& a, const Vec3ia& b ) { return (_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpeq_epi32(a.m128, b.m128))) & 7) == 7; }
+ __forceinline bool operator !=( const Vec3ia& a, const Vec3ia& b ) { return (_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpeq_epi32(a.m128, b.m128))) & 7) != 7; }
+ __forceinline bool operator < ( const Vec3ia& a, const Vec3ia& b ) {
+ if (a.x != b.x) return a.x < b.x;
+ if (a.y != b.y) return a.y < b.y;
+ if (a.z != b.z) return a.z < b.z;
+ return false;
+ }
+
+ __forceinline Vec3ba eq_mask( const Vec3ia& a, const Vec3ia& b ) { return _mm_castsi128_ps(_mm_cmpeq_epi32 (a.m128, b.m128)); }
+ __forceinline Vec3ba lt_mask( const Vec3ia& a, const Vec3ia& b ) { return _mm_castsi128_ps(_mm_cmplt_epi32 (a.m128, b.m128)); }
+ __forceinline Vec3ba gt_mask( const Vec3ia& a, const Vec3ia& b ) { return _mm_castsi128_ps(_mm_cmpgt_epi32 (a.m128, b.m128)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3ia select( const Vec3ba& m, const Vec3ia& t, const Vec3ia& f ) {
+#if defined(__SSE4_1__)
+ return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), m));
+#else
+ return _mm_or_si128(_mm_and_si128(_mm_castps_si128(m), t), _mm_andnot_si128(_mm_castps_si128(m), f));
+#endif
+ }
+
+#if defined(__SSE4_1__)
+ __forceinline Vec3ia min( const Vec3ia& a, const Vec3ia& b ) { return _mm_min_epi32(a.m128,b.m128); }
+ __forceinline Vec3ia max( const Vec3ia& a, const Vec3ia& b ) { return _mm_max_epi32(a.m128,b.m128); }
+#else
+ __forceinline Vec3ia min( const Vec3ia& a, const Vec3ia& b ) { return select(lt_mask(a,b),a,b); }
+ __forceinline Vec3ia max( const Vec3ia& a, const Vec3ia& b ) { return select(gt_mask(a,b),a,b); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator<<(embree_ostream cout, const Vec3ia& a) {
+ return cout << "(" << a.x << ", " << a.y << ", " << a.z << ")";
+ }
+}
diff --git a/thirdparty/embree/common/math/vec4.h b/thirdparty/embree/common/math/vec4.h
new file mode 100644
index 0000000000..0ed107928a
--- /dev/null
+++ b/thirdparty/embree/common/math/vec4.h
@@ -0,0 +1,243 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "math.h"
+#include "vec3.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Generic 4D vector Class
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> struct Vec4
+ {
+ enum { N = 4 };
+ union {
+ struct { T x, y, z, w; };
+#if !(defined(__WIN32__) && _MSC_VER == 1800) // workaround for older VS 2013 compiler
+ T components[N];
+#endif
+ };
+
+ typedef T Scalar;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Construction
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec4( ) {}
+ __forceinline explicit Vec4( const T& a ) : x(a), y(a), z(a), w(a) {}
+ __forceinline Vec4( const T& x, const T& y, const T& z, const T& w ) : x(x), y(y), z(z), w(w) {}
+ __forceinline Vec4( const Vec3<T>& xyz, const T& w ) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
+
+ __forceinline Vec4( const Vec4& other ) { x = other.x; y = other.y; z = other.z; w = other.w; }
+ __forceinline Vec4( const Vec3fx& other );
+
+ template<typename T1> __forceinline Vec4( const Vec4<T1>& a ) : x(T(a.x)), y(T(a.y)), z(T(a.z)), w(T(a.w)) {}
+ template<typename T1> __forceinline Vec4& operator =(const Vec4<T1>& other) { x = other.x; y = other.y; z = other.z; w = other.w; return *this; }
+
+ __forceinline Vec4& operator =(const Vec4& other) { x = other.x; y = other.y; z = other.z; w = other.w; return *this; }
+
+ __forceinline operator Vec3<T> () const { return Vec3<T>(x,y,z); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec4( ZeroTy ) : x(zero), y(zero), z(zero), w(zero) {}
+ __forceinline Vec4( OneTy ) : x(one), y(one), z(one), w(one) {}
+ __forceinline Vec4( PosInfTy ) : x(pos_inf), y(pos_inf), z(pos_inf), w(pos_inf) {}
+ __forceinline Vec4( NegInfTy ) : x(neg_inf), y(neg_inf), z(neg_inf), w(neg_inf) {}
+
+#if defined(__WIN32__) && (_MSC_VER == 1800) // workaround for older VS 2013 compiler
+ __forceinline const T& operator [](const size_t axis) const { assert(axis < 4); return (&x)[axis]; }
+ __forceinline T& operator [](const size_t axis) { assert(axis < 4); return (&x)[axis]; }
+#else
+ __forceinline const T& operator [](const size_t axis ) const { assert(axis < 4); return components[axis]; }
+ __forceinline T& operator [](const size_t axis) { assert(axis < 4); return components[axis]; }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Swizzles
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Vec3<T> xyz() const { return Vec3<T>(x, y, z); }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T> operator +( const Vec4<T>& a ) { return Vec4<T>(+a.x, +a.y, +a.z, +a.w); }
+ template<typename T> __forceinline Vec4<T> operator -( const Vec4<T>& a ) { return Vec4<T>(-a.x, -a.y, -a.z, -a.w); }
+ template<typename T> __forceinline Vec4<T> abs ( const Vec4<T>& a ) { return Vec4<T>(abs (a.x), abs (a.y), abs (a.z), abs (a.w)); }
+ template<typename T> __forceinline Vec4<T> rcp ( const Vec4<T>& a ) { return Vec4<T>(rcp (a.x), rcp (a.y), rcp (a.z), rcp (a.w)); }
+ template<typename T> __forceinline Vec4<T> rsqrt ( const Vec4<T>& a ) { return Vec4<T>(rsqrt(a.x), rsqrt(a.y), rsqrt(a.z), rsqrt(a.w)); }
+ template<typename T> __forceinline Vec4<T> sqrt ( const Vec4<T>& a ) { return Vec4<T>(sqrt (a.x), sqrt (a.y), sqrt (a.z), sqrt (a.w)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T> operator +( const Vec4<T>& a, const Vec4<T>& b ) { return Vec4<T>(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); }
+ template<typename T> __forceinline Vec4<T> operator -( const Vec4<T>& a, const Vec4<T>& b ) { return Vec4<T>(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); }
+ template<typename T> __forceinline Vec4<T> operator *( const Vec4<T>& a, const Vec4<T>& b ) { return Vec4<T>(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); }
+ template<typename T> __forceinline Vec4<T> operator *( const T& a, const Vec4<T>& b ) { return Vec4<T>(a * b.x, a * b.y, a * b.z, a * b.w); }
+ template<typename T> __forceinline Vec4<T> operator *( const Vec4<T>& a, const T& b ) { return Vec4<T>(a.x * b , a.y * b , a.z * b , a.w * b ); }
+ template<typename T> __forceinline Vec4<T> operator /( const Vec4<T>& a, const Vec4<T>& b ) { return Vec4<T>(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); }
+ template<typename T> __forceinline Vec4<T> operator /( const Vec4<T>& a, const T& b ) { return Vec4<T>(a.x / b , a.y / b , a.z / b , a.w / b ); }
+ template<typename T> __forceinline Vec4<T> operator /( const T& a, const Vec4<T>& b ) { return Vec4<T>(a / b.x, a / b.y, a / b.z, a / b.w); }
+
+ template<typename T> __forceinline Vec4<T> min(const Vec4<T>& a, const Vec4<T>& b) { return Vec4<T>(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); }
+ template<typename T> __forceinline Vec4<T> max(const Vec4<T>& a, const Vec4<T>& b) { return Vec4<T>(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T> madd ( const Vec4<T>& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>( madd(a.x,b.x,c.x), madd(a.y,b.y,c.y), madd(a.z,b.z,c.z), madd(a.w,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> msub ( const Vec4<T>& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>( msub(a.x,b.x,c.x), msub(a.y,b.y,c.y), msub(a.z,b.z,c.z), msub(a.w,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> nmadd ( const Vec4<T>& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>(nmadd(a.x,b.x,c.x),nmadd(a.y,b.y,c.y),nmadd(a.z,b.z,c.z),nmadd(a.w,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> nmsub ( const Vec4<T>& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>(nmsub(a.x,b.x,c.x),nmsub(a.y,b.y,c.y),nmsub(a.z,b.z,c.z),nmsub(a.w,b.w,c.w)); }
+
+ template<typename T> __forceinline Vec4<T> madd ( const T& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>( madd(a,b.x,c.x), madd(a,b.y,c.y), madd(a,b.z,c.z), madd(a,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> msub ( const T& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>( msub(a,b.x,c.x), msub(a,b.y,c.y), msub(a,b.z,c.z), msub(a,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> nmadd ( const T& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>(nmadd(a,b.x,c.x),nmadd(a,b.y,c.y),nmadd(a,b.z,c.z),nmadd(a,b.w,c.w)); }
+ template<typename T> __forceinline Vec4<T> nmsub ( const T& a, const Vec4<T>& b, const Vec4<T>& c) { return Vec4<T>(nmsub(a,b.x,c.x),nmsub(a,b.y,c.y),nmsub(a,b.z,c.z),nmsub(a,b.w,c.w)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T>& operator +=( Vec4<T>& a, const Vec4<T>& b ) { a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; return a; }
+ template<typename T> __forceinline Vec4<T>& operator -=( Vec4<T>& a, const Vec4<T>& b ) { a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; return a; }
+ template<typename T> __forceinline Vec4<T>& operator *=( Vec4<T>& a, const T& b ) { a.x *= b ; a.y *= b ; a.z *= b ; a.w *= b ; return a; }
+ template<typename T> __forceinline Vec4<T>& operator /=( Vec4<T>& a, const T& b ) { a.x /= b ; a.y /= b ; a.z /= b ; a.w /= b ; return a; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T reduce_add( const Vec4<T>& a ) { return a.x + a.y + a.z + a.w; }
+ template<typename T> __forceinline T reduce_mul( const Vec4<T>& a ) { return a.x * a.y * a.z * a.w; }
+ template<typename T> __forceinline T reduce_min( const Vec4<T>& a ) { return min(a.x, a.y, a.z, a.w); }
+ template<typename T> __forceinline T reduce_max( const Vec4<T>& a ) { return max(a.x, a.y, a.z, a.w); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline bool operator ==( const Vec4<T>& a, const Vec4<T>& b ) { return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; }
+ template<typename T> __forceinline bool operator !=( const Vec4<T>& a, const Vec4<T>& b ) { return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; }
+ template<typename T> __forceinline bool operator < ( const Vec4<T>& a, const Vec4<T>& b ) {
+ if (a.x != b.x) return a.x < b.x;
+ if (a.y != b.y) return a.y < b.y;
+ if (a.z != b.z) return a.z < b.z;
+ if (a.w != b.w) return a.w < b.w;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Shift Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T> shift_right_1( const Vec4<T>& a ) {
+ return Vec4<T>(shift_right_1(a.x),shift_right_1(a.y),shift_right_1(a.z),shift_right_1(a.w));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline T dot ( const Vec4<T>& a, const Vec4<T>& b ) { return madd(a.x,b.x,madd(a.y,b.y,madd(a.z,b.z,a.w*b.w))); }
+
+ template<typename T> __forceinline T length ( const Vec4<T>& a ) { return sqrt(dot(a,a)); }
+ template<typename T> __forceinline Vec4<T> normalize( const Vec4<T>& a ) { return a*rsqrt(dot(a,a)); }
+ template<typename T> __forceinline T distance ( const Vec4<T>& a, const Vec4<T>& b ) { return length(a-b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline Vec4<T> select ( bool s, const Vec4<T>& t, const Vec4<T>& f ) {
+ return Vec4<T>(select(s,t.x,f.x),select(s,t.y,f.y),select(s,t.z,f.z),select(s,t.w,f.w));
+ }
+
+ template<typename T> __forceinline Vec4<T> select ( const Vec4<bool>& s, const Vec4<T>& t, const Vec4<T>& f ) {
+ return Vec4<T>(select(s.x,t.x,f.x),select(s.y,t.y,f.y),select(s.z,t.z,f.z),select(s.w,t.w,f.w));
+ }
+
+ template<typename T> __forceinline Vec4<T> select ( const typename T::Bool& s, const Vec4<T>& t, const Vec4<T>& f ) {
+ return Vec4<T>(select(s,t.x,f.x),select(s,t.y,f.y),select(s,t.z,f.z),select(s,t.w,f.w));
+ }
+
+ template<typename T>
+ __forceinline Vec4<T> lerp(const Vec4<T>& v0, const Vec4<T>& v1, const T& t) {
+ return madd(Vec4<T>(T(1.0f)-t),v0,t*v1);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T> __forceinline embree_ostream operator<<(embree_ostream cout, const Vec4<T>& a) {
+ return cout << "(" << a.x << ", " << a.y << ", " << a.z << ", " << a.w << ")";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Default template instantiations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ typedef Vec4<bool > Vec4b;
+ typedef Vec4<unsigned char> Vec4uc;
+ typedef Vec4<int > Vec4i;
+ typedef Vec4<float > Vec4f;
+}
+
+#include "vec3ba.h"
+#include "vec3ia.h"
+#include "vec3fa.h"
+
+////////////////////////////////////////////////////////////////////////////////
+/// SSE / AVX / MIC specializations
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined __SSE__
+#include "../simd/sse.h"
+#endif
+
+#if defined __AVX__
+#include "../simd/avx.h"
+#endif
+
+#if defined __AVX512F__
+#include "../simd/avx512.h"
+#endif
+
+namespace embree
+{
+ template<> __forceinline Vec4<float>::Vec4( const Vec3fx& a ) { x = a.x; y = a.y; z = a.z; w = a.w; }
+
+#if defined(__AVX__)
+ template<> __forceinline Vec4<vfloat4>::Vec4( const Vec3fx& a ) {
+ x = a.x; y = a.y; z = a.z; w = a.w;
+ }
+#elif defined(__SSE__)
+ template<> __forceinline Vec4<vfloat4>::Vec4( const Vec3fx& a ) {
+ const vfloat4 v = vfloat4(a.m128); x = shuffle<0,0,0,0>(v); y = shuffle<1,1,1,1>(v); z = shuffle<2,2,2,2>(v); w = shuffle<3,3,3,3>(v);
+ }
+#endif
+
+#if defined(__AVX__)
+ template<> __forceinline Vec4<vfloat8>::Vec4( const Vec3fx& a ) {
+ x = a.x; y = a.y; z = a.z; w = a.w;
+ }
+#endif
+
+#if defined(__AVX512F__)
+ template<> __forceinline Vec4<vfloat16>::Vec4( const Vec3fx& a ) : x(a.x), y(a.y), z(a.z), w(a.w) {}
+#endif
+}
diff --git a/thirdparty/embree/common/simd/arm/emulation.h b/thirdparty/embree/common/simd/arm/emulation.h
new file mode 100644
index 0000000000..1c3875fb27
--- /dev/null
+++ b/thirdparty/embree/common/simd/arm/emulation.h
@@ -0,0 +1,50 @@
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+/* Make precision match SSE, at the cost of some performance */
+#if !defined(__aarch64__)
+# define SSE2NEON_PRECISE_DIV 1
+# define SSE2NEON_PRECISE_SQRT 1
+#endif
+
+#include "sse2neon.h"
+
+__forceinline __m128 _mm_fmsub_ps(__m128 a, __m128 b, __m128 c) {
+ __m128 neg_c = vreinterpretq_m128_f32(vnegq_f32(vreinterpretq_f32_m128(c)));
+ return _mm_fmadd_ps(a, b, neg_c);
+}
+
+__forceinline __m128 _mm_fnmadd_ps(__m128 a, __m128 b, __m128 c) {
+#if defined(__aarch64__)
+ return vreinterpretq_m128_f32(vfmsq_f32(vreinterpretq_f32_m128(c),
+ vreinterpretq_f32_m128(b),
+ vreinterpretq_f32_m128(a)));
+#else
+ return _mm_sub_ps(c, _mm_mul_ps(a, b));
+#endif
+}
+
+__forceinline __m128 _mm_fnmsub_ps(__m128 a, __m128 b, __m128 c) {
+ return vreinterpretq_m128_f32(vnegq_f32(vreinterpretq_f32_m128(_mm_fmadd_ps(a,b,c))));
+}
+
+
+/* Dummy defines for floating point control */
+#define _MM_MASK_MASK 0x1f80
+#define _MM_MASK_DIV_ZERO 0x200
+#define _MM_FLUSH_ZERO_ON 0x8000
+#define _MM_MASK_DENORM 0x100
+#define _MM_SET_EXCEPTION_MASK(x)
+#define _MM_SET_FLUSH_ZERO_MODE(x)
+
+__forceinline int _mm_getcsr()
+{
+ return 0;
+}
+
+__forceinline void _mm_mfence()
+{
+ __sync_synchronize();
+}
diff --git a/thirdparty/embree/common/simd/arm/sse2neon.h b/thirdparty/embree/common/simd/arm/sse2neon.h
new file mode 100644
index 0000000000..7eb25cf2c5
--- /dev/null
+++ b/thirdparty/embree/common/simd/arm/sse2neon.h
@@ -0,0 +1,6996 @@
+#ifndef SSE2NEON_H
+#define SSE2NEON_H
+
+// This header file provides a simple API translation layer
+// between SSE intrinsics to their corresponding Arm/Aarch64 NEON versions
+//
+// This header file does not yet translate all of the SSE intrinsics.
+//
+// Contributors to this work are:
+// John W. Ratcliff <jratcliffscarab@gmail.com>
+// Brandon Rowlett <browlett@nvidia.com>
+// Ken Fast <kfast@gdeb.com>
+// Eric van Beurden <evanbeurden@nvidia.com>
+// Alexander Potylitsin <apotylitsin@nvidia.com>
+// Hasindu Gamaarachchi <hasindu2008@gmail.com>
+// Jim Huang <jserv@biilabs.io>
+// Mark Cheng <marktwtn@biilabs.io>
+// Malcolm James MacLeod <malcolm@gulden.com>
+// Devin Hussey (easyaspi314) <husseydevin@gmail.com>
+// Sebastian Pop <spop@amazon.com>
+// Developer Ecosystem Engineering <DeveloperEcosystemEngineering@apple.com>
+// Danila Kutenin <danilak@google.com>
+// François Turban (JishinMaster) <francois.turban@gmail.com>
+// Pei-Hsuan Hung <afcidk@gmail.com>
+// Yang-Hao Yuan <yanghau@biilabs.io>
+// Syoyo Fujita <syoyo@lighttransport.com>
+// Brecht Van Lommel <brecht@blender.org>
+
+/*
+ * sse2neon is freely redistributable under the MIT License.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* Tunable configurations */
+
+/* Enable precise implementation of math operations
+ * This would slow down the computation a bit, but gives consistent result with
+ * x86 SSE2. (e.g. would solve a hole or NaN pixel in the rendering result)
+ */
+/* _mm_min_ps and _mm_max_ps */
+#ifndef SSE2NEON_PRECISE_MINMAX
+#define SSE2NEON_PRECISE_MINMAX (0)
+#endif
+/* _mm_rcp_ps and _mm_div_ps */
+#ifndef SSE2NEON_PRECISE_DIV
+#define SSE2NEON_PRECISE_DIV (0)
+#endif
+/* _mm_sqrt_ps and _mm_rsqrt_ps */
+#ifndef SSE2NEON_PRECISE_SQRT
+#define SSE2NEON_PRECISE_SQRT (0)
+#endif
+#ifndef SSE2NEON_PRECISE_RSQRT
+#define SSE2NEON_PRECISE_RSQRT (0)
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma push_macro("FORCE_INLINE")
+#pragma push_macro("ALIGN_STRUCT")
+#define FORCE_INLINE static inline __attribute__((always_inline))
+#define ALIGN_STRUCT(x) __attribute__((aligned(x)))
+#ifndef likely
+#define likely(x) __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#else
+#error "Macro name collisions may happen with unsupported compiler."
+#ifdef FORCE_INLINE
+#undef FORCE_INLINE
+#endif
+#define FORCE_INLINE static inline
+#ifndef ALIGN_STRUCT
+#define ALIGN_STRUCT(x) __declspec(align(x))
+#endif
+#endif
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/* Architecture-specific build options */
+/* FIXME: #pragma GCC push_options is only available on GCC */
+#if defined(__GNUC__)
+#if defined(__arm__) && __ARM_ARCH == 7
+/* According to ARM C Language Extensions Architecture specification,
+ * __ARM_NEON is defined to a value indicating the Advanced SIMD (NEON)
+ * architecture supported.
+ */
+#if !defined(__ARM_NEON) || !defined(__ARM_NEON__)
+#error "You must enable NEON instructions (e.g. -mfpu=neon) to use SSE2NEON."
+#endif
+#if !defined(__clang__)
+#pragma GCC push_options
+#pragma GCC target("fpu=neon")
+#endif
+#elif defined(__aarch64__)
+#if !defined(__clang__)
+#pragma GCC push_options
+#pragma GCC target("+simd")
+#endif
+#else
+#error "Unsupported target. Must be either ARMv7-A+NEON or ARMv8-A."
+#endif
+#endif
+
+#include <arm_neon.h>
+
+/* Rounding functions require either Aarch64 instructions or libm failback */
+#if !defined(__aarch64__)
+#include <math.h>
+#endif
+
+/* "__has_builtin" can be used to query support for built-in functions
+ * provided by gcc/clang and other compilers that support it.
+ */
+#ifndef __has_builtin /* GCC prior to 10 or non-clang compilers */
+/* Compatibility with gcc <= 9 */
+#if __GNUC__ <= 9
+#define __has_builtin(x) HAS##x
+#define HAS__builtin_popcount 1
+#define HAS__builtin_popcountll 1
+#else
+#define __has_builtin(x) 0
+#endif
+#endif
+
+/**
+ * MACRO for shuffle parameter for _mm_shuffle_ps().
+ * Argument fp3 is a digit[0123] that represents the fp from argument "b"
+ * of mm_shuffle_ps that will be placed in fp3 of result. fp2 is the same
+ * for fp2 in result. fp1 is a digit[0123] that represents the fp from
+ * argument "a" of mm_shuffle_ps that will be places in fp1 of result.
+ * fp0 is the same for fp0 of result.
+ */
+#define _MM_SHUFFLE(fp3, fp2, fp1, fp0) \
+ (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | ((fp0)))
+
+/* Rounding mode macros. */
+#define _MM_FROUND_TO_NEAREST_INT 0x00
+#define _MM_FROUND_TO_NEG_INF 0x01
+#define _MM_FROUND_TO_POS_INF 0x02
+#define _MM_FROUND_TO_ZERO 0x03
+#define _MM_FROUND_CUR_DIRECTION 0x04
+#define _MM_FROUND_NO_EXC 0x08
+#define _MM_ROUND_NEAREST 0x0000
+#define _MM_ROUND_DOWN 0x2000
+#define _MM_ROUND_UP 0x4000
+#define _MM_ROUND_TOWARD_ZERO 0x6000
+
+/* indicate immediate constant argument in a given range */
+#define __constrange(a, b) const
+
+/* A few intrinsics accept traditional data types like ints or floats, but
+ * most operate on data types that are specific to SSE.
+ * If a vector type ends in d, it contains doubles, and if it does not have
+ * a suffix, it contains floats. An integer vector type can contain any type
+ * of integer, from chars to shorts to unsigned long longs.
+ */
+typedef int64x1_t __m64;
+typedef float32x4_t __m128; /* 128-bit vector containing 4 floats */
+// On ARM 32-bit architecture, the float64x2_t is not supported.
+// The data type __m128d should be represented in a different way for related
+// intrinsic conversion.
+#if defined(__aarch64__)
+typedef float64x2_t __m128d; /* 128-bit vector containing 2 doubles */
+#else
+typedef float32x4_t __m128d;
+#endif
+typedef int64x2_t __m128i; /* 128-bit vector containing integers */
+
+/* type-safe casting between types */
+
+#define vreinterpretq_m128_f16(x) vreinterpretq_f32_f16(x)
+#define vreinterpretq_m128_f32(x) (x)
+#define vreinterpretq_m128_f64(x) vreinterpretq_f32_f64(x)
+
+#define vreinterpretq_m128_u8(x) vreinterpretq_f32_u8(x)
+#define vreinterpretq_m128_u16(x) vreinterpretq_f32_u16(x)
+#define vreinterpretq_m128_u32(x) vreinterpretq_f32_u32(x)
+#define vreinterpretq_m128_u64(x) vreinterpretq_f32_u64(x)
+
+#define vreinterpretq_m128_s8(x) vreinterpretq_f32_s8(x)
+#define vreinterpretq_m128_s16(x) vreinterpretq_f32_s16(x)
+#define vreinterpretq_m128_s32(x) vreinterpretq_f32_s32(x)
+#define vreinterpretq_m128_s64(x) vreinterpretq_f32_s64(x)
+
+#define vreinterpretq_f16_m128(x) vreinterpretq_f16_f32(x)
+#define vreinterpretq_f32_m128(x) (x)
+#define vreinterpretq_f64_m128(x) vreinterpretq_f64_f32(x)
+
+#define vreinterpretq_u8_m128(x) vreinterpretq_u8_f32(x)
+#define vreinterpretq_u16_m128(x) vreinterpretq_u16_f32(x)
+#define vreinterpretq_u32_m128(x) vreinterpretq_u32_f32(x)
+#define vreinterpretq_u64_m128(x) vreinterpretq_u64_f32(x)
+
+#define vreinterpretq_s8_m128(x) vreinterpretq_s8_f32(x)
+#define vreinterpretq_s16_m128(x) vreinterpretq_s16_f32(x)
+#define vreinterpretq_s32_m128(x) vreinterpretq_s32_f32(x)
+#define vreinterpretq_s64_m128(x) vreinterpretq_s64_f32(x)
+
+#define vreinterpretq_m128i_s8(x) vreinterpretq_s64_s8(x)
+#define vreinterpretq_m128i_s16(x) vreinterpretq_s64_s16(x)
+#define vreinterpretq_m128i_s32(x) vreinterpretq_s64_s32(x)
+#define vreinterpretq_m128i_s64(x) (x)
+
+#define vreinterpretq_m128i_u8(x) vreinterpretq_s64_u8(x)
+#define vreinterpretq_m128i_u16(x) vreinterpretq_s64_u16(x)
+#define vreinterpretq_m128i_u32(x) vreinterpretq_s64_u32(x)
+#define vreinterpretq_m128i_u64(x) vreinterpretq_s64_u64(x)
+
+#define vreinterpretq_f32_m128i(x) vreinterpretq_f32_s64(x)
+#define vreinterpretq_f64_m128i(x) vreinterpretq_f64_s64(x)
+
+#define vreinterpretq_s8_m128i(x) vreinterpretq_s8_s64(x)
+#define vreinterpretq_s16_m128i(x) vreinterpretq_s16_s64(x)
+#define vreinterpretq_s32_m128i(x) vreinterpretq_s32_s64(x)
+#define vreinterpretq_s64_m128i(x) (x)
+
+#define vreinterpretq_u8_m128i(x) vreinterpretq_u8_s64(x)
+#define vreinterpretq_u16_m128i(x) vreinterpretq_u16_s64(x)
+#define vreinterpretq_u32_m128i(x) vreinterpretq_u32_s64(x)
+#define vreinterpretq_u64_m128i(x) vreinterpretq_u64_s64(x)
+
+#define vreinterpret_m64_s8(x) vreinterpret_s64_s8(x)
+#define vreinterpret_m64_s16(x) vreinterpret_s64_s16(x)
+#define vreinterpret_m64_s32(x) vreinterpret_s64_s32(x)
+#define vreinterpret_m64_s64(x) (x)
+
+#define vreinterpret_m64_u8(x) vreinterpret_s64_u8(x)
+#define vreinterpret_m64_u16(x) vreinterpret_s64_u16(x)
+#define vreinterpret_m64_u32(x) vreinterpret_s64_u32(x)
+#define vreinterpret_m64_u64(x) vreinterpret_s64_u64(x)
+
+#define vreinterpret_m64_f16(x) vreinterpret_s64_f16(x)
+#define vreinterpret_m64_f32(x) vreinterpret_s64_f32(x)
+#define vreinterpret_m64_f64(x) vreinterpret_s64_f64(x)
+
+#define vreinterpret_u8_m64(x) vreinterpret_u8_s64(x)
+#define vreinterpret_u16_m64(x) vreinterpret_u16_s64(x)
+#define vreinterpret_u32_m64(x) vreinterpret_u32_s64(x)
+#define vreinterpret_u64_m64(x) vreinterpret_u64_s64(x)
+
+#define vreinterpret_s8_m64(x) vreinterpret_s8_s64(x)
+#define vreinterpret_s16_m64(x) vreinterpret_s16_s64(x)
+#define vreinterpret_s32_m64(x) vreinterpret_s32_s64(x)
+#define vreinterpret_s64_m64(x) (x)
+
+#define vreinterpret_f32_m64(x) vreinterpret_f32_s64(x)
+
+#if defined(__aarch64__)
+#define vreinterpretq_m128d_s32(x) vreinterpretq_f64_s32(x)
+#define vreinterpretq_m128d_s64(x) vreinterpretq_f64_s64(x)
+
+#define vreinterpretq_m128d_u64(x) vreinterpretq_f64_u64(x)
+
+#define vreinterpretq_m128d_f32(x) vreinterpretq_f64_f32(x)
+#define vreinterpretq_m128d_f64(x) (x)
+
+#define vreinterpretq_s64_m128d(x) vreinterpretq_s64_f64(x)
+
+#define vreinterpretq_u64_m128d(x) vreinterpretq_u64_f64(x)
+
+#define vreinterpretq_f64_m128d(x) (x)
+#define vreinterpretq_f32_m128d(x) vreinterpretq_f32_f64(x)
+#else
+#define vreinterpretq_m128d_s32(x) vreinterpretq_f32_s32(x)
+#define vreinterpretq_m128d_s64(x) vreinterpretq_f32_s64(x)
+
+#define vreinterpretq_m128d_u32(x) vreinterpretq_f32_u32(x)
+#define vreinterpretq_m128d_u64(x) vreinterpretq_f32_u64(x)
+
+#define vreinterpretq_m128d_f32(x) (x)
+
+#define vreinterpretq_s64_m128d(x) vreinterpretq_s64_f32(x)
+
+#define vreinterpretq_u32_m128d(x) vreinterpretq_u32_f32(x)
+#define vreinterpretq_u64_m128d(x) vreinterpretq_u64_f32(x)
+
+#define vreinterpretq_f32_m128d(x) (x)
+#endif
+
+// A struct is defined in this header file called 'SIMDVec' which can be used
+// by applications which attempt to access the contents of an _m128 struct
+// directly. It is important to note that accessing the __m128 struct directly
+// is bad coding practice by Microsoft: @see:
+// https://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx
+//
+// However, some legacy source code may try to access the contents of an __m128
+// struct directly so the developer can use the SIMDVec as an alias for it. Any
+// casting must be done manually by the developer, as you cannot cast or
+// otherwise alias the base NEON data type for intrinsic operations.
+//
+// union intended to allow direct access to an __m128 variable using the names
+// that the MSVC compiler provides. This union should really only be used when
+// trying to access the members of the vector as integer values. GCC/clang
+// allow native access to the float members through a simple array access
+// operator (in C since 4.6, in C++ since 4.8).
+//
+// Ideally direct accesses to SIMD vectors should not be used since it can cause
+// a performance hit. If it really is needed however, the original __m128
+// variable can be aliased with a pointer to this union and used to access
+// individual components. The use of this union should be hidden behind a macro
+// that is used throughout the codebase to access the members instead of always
+// declaring this type of variable.
+typedef union ALIGN_STRUCT(16) SIMDVec {
+ float m128_f32[4]; // as floats - DON'T USE. Added for convenience.
+ int8_t m128_i8[16]; // as signed 8-bit integers.
+ int16_t m128_i16[8]; // as signed 16-bit integers.
+ int32_t m128_i32[4]; // as signed 32-bit integers.
+ int64_t m128_i64[2]; // as signed 64-bit integers.
+ uint8_t m128_u8[16]; // as unsigned 8-bit integers.
+ uint16_t m128_u16[8]; // as unsigned 16-bit integers.
+ uint32_t m128_u32[4]; // as unsigned 32-bit integers.
+ uint64_t m128_u64[2]; // as unsigned 64-bit integers.
+} SIMDVec;
+
+// casting using SIMDVec
+#define vreinterpretq_nth_u64_m128i(x, n) (((SIMDVec *) &x)->m128_u64[n])
+#define vreinterpretq_nth_u32_m128i(x, n) (((SIMDVec *) &x)->m128_u32[n])
+#define vreinterpretq_nth_u8_m128i(x, n) (((SIMDVec *) &x)->m128_u8[n])
+
+/* Backwards compatibility for compilers with lack of specific type support */
+
+// Older gcc does not define vld1q_u8_x4 type
+#if defined(__GNUC__) && !defined(__clang__) && \
+ ((__GNUC__ == 10 && (__GNUC_MINOR__ <= 1)) || \
+ (__GNUC__ == 9 && (__GNUC_MINOR__ <= 3)) || \
+ (__GNUC__ == 8 && (__GNUC_MINOR__ <= 4)) || __GNUC__ <= 7)
+FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p)
+{
+ uint8x16x4_t ret;
+ ret.val[0] = vld1q_u8(p + 0);
+ ret.val[1] = vld1q_u8(p + 16);
+ ret.val[2] = vld1q_u8(p + 32);
+ ret.val[3] = vld1q_u8(p + 48);
+ return ret;
+}
+#else
+// Wraps vld1q_u8_x4
+FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p)
+{
+ return vld1q_u8_x4(p);
+}
+#endif
+
+/* Function Naming Conventions
+ * The naming convention of SSE intrinsics is straightforward. A generic SSE
+ * intrinsic function is given as follows:
+ * _mm_<name>_<data_type>
+ *
+ * The parts of this format are given as follows:
+ * 1. <name> describes the operation performed by the intrinsic
+ * 2. <data_type> identifies the data type of the function's primary arguments
+ *
+ * This last part, <data_type>, is a little complicated. It identifies the
+ * content of the input values, and can be set to any of the following values:
+ * + ps - vectors contain floats (ps stands for packed single-precision)
+ * + pd - vectors cantain doubles (pd stands for packed double-precision)
+ * + epi8/epi16/epi32/epi64 - vectors contain 8-bit/16-bit/32-bit/64-bit
+ * signed integers
+ * + epu8/epu16/epu32/epu64 - vectors contain 8-bit/16-bit/32-bit/64-bit
+ * unsigned integers
+ * + si128 - unspecified 128-bit vector or 256-bit vector
+ * + m128/m128i/m128d - identifies input vector types when they are different
+ * than the type of the returned vector
+ *
+ * For example, _mm_setzero_ps. The _mm implies that the function returns
+ * a 128-bit vector. The _ps at the end implies that the argument vectors
+ * contain floats.
+ *
+ * A complete example: Byte Shuffle - pshufb (_mm_shuffle_epi8)
+ * // Set packed 16-bit integers. 128 bits, 8 short, per 16 bits
+ * __m128i v_in = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8);
+ * // Set packed 8-bit integers
+ * // 128 bits, 16 chars, per 8 bits
+ * __m128i v_perm = _mm_setr_epi8(1, 0, 2, 3, 8, 9, 10, 11,
+ * 4, 5, 12, 13, 6, 7, 14, 15);
+ * // Shuffle packed 8-bit integers
+ * __m128i v_out = _mm_shuffle_epi8(v_in, v_perm); // pshufb
+ *
+ * Data (Number, Binary, Byte Index):
+ +------+------+-------------+------+------+-------------+
+ | 1 | 2 | 3 | 4 | Number
+ +------+------+------+------+------+------+------+------+
+ | 0000 | 0001 | 0000 | 0010 | 0000 | 0011 | 0000 | 0100 | Binary
+ +------+------+------+------+------+------+------+------+
+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Index
+ +------+------+------+------+------+------+------+------+
+
+ +------+------+------+------+------+------+------+------+
+ | 5 | 6 | 7 | 8 | Number
+ +------+------+------+------+------+------+------+------+
+ | 0000 | 0101 | 0000 | 0110 | 0000 | 0111 | 0000 | 1000 | Binary
+ +------+------+------+------+------+------+------+------+
+ | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Index
+ +------+------+------+------+------+------+------+------+
+ * Index (Byte Index):
+ +------+------+------+------+------+------+------+------+
+ | 1 | 0 | 2 | 3 | 8 | 9 | 10 | 11 |
+ +------+------+------+------+------+------+------+------+
+
+ +------+------+------+------+------+------+------+------+
+ | 4 | 5 | 12 | 13 | 6 | 7 | 14 | 15 |
+ +------+------+------+------+------+------+------+------+
+ * Result:
+ +------+------+------+------+------+------+------+------+
+ | 1 | 0 | 2 | 3 | 8 | 9 | 10 | 11 | Index
+ +------+------+------+------+------+------+------+------+
+ | 0001 | 0000 | 0000 | 0010 | 0000 | 0101 | 0000 | 0110 | Binary
+ +------+------+------+------+------+------+------+------+
+ | 256 | 2 | 5 | 6 | Number
+ +------+------+------+------+------+------+------+------+
+
+ +------+------+------+------+------+------+------+------+
+ | 4 | 5 | 12 | 13 | 6 | 7 | 14 | 15 | Index
+ +------+------+------+------+------+------+------+------+
+ | 0000 | 0011 | 0000 | 0111 | 0000 | 0100 | 0000 | 1000 | Binary
+ +------+------+------+------+------+------+------+------+
+ | 3 | 7 | 4 | 8 | Number
+ +------+------+------+------+------+------+-------------+
+ */
+
+/* Set/get methods */
+
+/* Constants for use with _mm_prefetch. */
+enum _mm_hint {
+ _MM_HINT_NTA = 0, /* load data to L1 and L2 cache, mark it as NTA */
+ _MM_HINT_T0 = 1, /* load data to L1 and L2 cache */
+ _MM_HINT_T1 = 2, /* load data to L2 cache only */
+ _MM_HINT_T2 = 3, /* load data to L2 cache only, mark it as NTA */
+ _MM_HINT_ENTA = 4, /* exclusive version of _MM_HINT_NTA */
+ _MM_HINT_ET0 = 5, /* exclusive version of _MM_HINT_T0 */
+ _MM_HINT_ET1 = 6, /* exclusive version of _MM_HINT_T1 */
+ _MM_HINT_ET2 = 7 /* exclusive version of _MM_HINT_T2 */
+};
+
+// Loads one cache line of data from address p to a location closer to the
+// processor. https://msdn.microsoft.com/en-us/library/84szxsww(v=vs.100).aspx
+FORCE_INLINE void _mm_prefetch(const void *p, int i)
+{
+ (void) i;
+ __builtin_prefetch(p);
+}
+
+// Pause the processor. This is typically used in spin-wait loops and depending
+// on the x86 processor typical values are in the 40-100 cycle range. The
+// 'yield' instruction isn't a good fit beacuse it's effectively a nop on most
+// Arm cores. Experience with several databases has shown has shown an 'isb' is
+// a reasonable approximation.
+FORCE_INLINE void _mm_pause()
+{
+ __asm__ __volatile__("isb\n");
+}
+
+// Copy the lower single-precision (32-bit) floating-point element of a to dst.
+//
+// dst[31:0] := a[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_f32
+FORCE_INLINE float _mm_cvtss_f32(__m128 a)
+{
+ return vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+}
+
+// Convert the lower single-precision (32-bit) floating-point element in b to a
+// double-precision (64-bit) floating-point element, store the result in the
+// lower element of dst, and copy the upper element from a to the upper element
+// of dst.
+//
+// dst[63:0] := Convert_FP32_To_FP64(b[31:0])
+// dst[127:64] := a[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_sd
+FORCE_INLINE __m128d _mm_cvtss_sd(__m128d a, __m128 b)
+{
+ double d = (double) vgetq_lane_f32(vreinterpretq_f32_m128(b), 0);
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vsetq_lane_f64(d, vreinterpretq_f64_m128d(a), 0));
+#else
+ return vreinterpretq_m128d_s64(
+ vsetq_lane_s64(*(int64_t *) &d, vreinterpretq_s64_m128d(a), 0));
+#endif
+}
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 32-bit integer, and store the result in dst.
+//
+// dst[31:0] := Convert_FP32_To_Int32(a[31:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si32
+#define _mm_cvtss_si32(a) _mm_cvt_ss2si(a)
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 64-bit integer, and store the result in dst.
+//
+// dst[63:0] := Convert_FP32_To_Int64(a[31:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si64
+FORCE_INLINE int _mm_cvtss_si64(__m128 a)
+{
+#if defined(__aarch64__)
+ return vgetq_lane_s64(
+ vreinterpretq_s64_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a))), 0);
+#else
+ float32_t data = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+ float32_t diff = data - floor(data);
+ if (diff > 0.5)
+ return (int64_t) ceil(data);
+ if (unlikely(diff == 0.5)) {
+ int64_t f = (int64_t) floor(data);
+ int64_t c = (int64_t) ceil(data);
+ return c & 1 ? f : c;
+ }
+ return (int64_t) floor(data);
+#endif
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed 32-bit integers with truncation, and store the results in dst.
+//
+// FOR j := 0 to 1
+// i := 32*j
+// dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ps2pi
+FORCE_INLINE __m64 _mm_cvtt_ps2pi(__m128 a)
+{
+ return vreinterpret_m64_s32(
+ vget_low_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a))));
+}
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 32-bit integer with truncation, and store the result in dst.
+//
+// dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ss2si
+FORCE_INLINE int _mm_cvtt_ss2si(__m128 a)
+{
+ return vgetq_lane_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)), 0);
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed 32-bit integers with truncation, and store the results in dst.
+//
+// FOR j := 0 to 1
+// i := 32*j
+// dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttps_pi32
+#define _mm_cvttps_pi32(a) _mm_cvtt_ps2pi(a)
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 32-bit integer with truncation, and store the result in dst.
+//
+// dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si32
+#define _mm_cvttss_si32(a) _mm_cvtt_ss2si(a)
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 64-bit integer with truncation, and store the result in dst.
+//
+// dst[63:0] := Convert_FP32_To_Int64_Truncate(a[31:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si64
+FORCE_INLINE int64_t _mm_cvttss_si64(__m128 a)
+{
+ return vgetq_lane_s64(
+ vmovl_s32(vget_low_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)))), 0);
+}
+
+// Sets the 128-bit value to zero
+// https://msdn.microsoft.com/en-us/library/vstudio/ys7dw0kh(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_setzero_si128(void)
+{
+ return vreinterpretq_m128i_s32(vdupq_n_s32(0));
+}
+
+// Clears the four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/tk1t2tbz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_setzero_ps(void)
+{
+ return vreinterpretq_m128_f32(vdupq_n_f32(0));
+}
+
+// Return vector of type __m128d with all elements set to zero.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setzero_pd
+FORCE_INLINE __m128d _mm_setzero_pd(void)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(vdupq_n_f64(0));
+#else
+ return vreinterpretq_m128d_f32(vdupq_n_f32(0));
+#endif
+}
+
+// Sets the four single-precision, floating-point values to w.
+//
+// r0 := r1 := r2 := r3 := w
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set1_ps(float _w)
+{
+ return vreinterpretq_m128_f32(vdupq_n_f32(_w));
+}
+
+// Sets the four single-precision, floating-point values to w.
+// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set_ps1(float _w)
+{
+ return vreinterpretq_m128_f32(vdupq_n_f32(_w));
+}
+
+// Sets the four single-precision, floating-point values to the four inputs.
+// https://msdn.microsoft.com/en-us/library/vstudio/afh0zf75(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_set_ps(float w, float z, float y, float x)
+{
+ float ALIGN_STRUCT(16) data[4] = {x, y, z, w};
+ return vreinterpretq_m128_f32(vld1q_f32(data));
+}
+
+// Copy single-precision (32-bit) floating-point element a to the lower element
+// of dst, and zero the upper 3 elements.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_ss
+FORCE_INLINE __m128 _mm_set_ss(float a)
+{
+ float ALIGN_STRUCT(16) data[4] = {a, 0, 0, 0};
+ return vreinterpretq_m128_f32(vld1q_f32(data));
+}
+
+// Sets the four single-precision, floating-point values to the four inputs in
+// reverse order.
+// https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_setr_ps(float w, float z, float y, float x)
+{
+ float ALIGN_STRUCT(16) data[4] = {w, z, y, x};
+ return vreinterpretq_m128_f32(vld1q_f32(data));
+}
+
+// Sets the 8 signed 16-bit integer values in reverse order.
+//
+// Return Value
+// r0 := w0
+// r1 := w1
+// ...
+// r7 := w7
+FORCE_INLINE __m128i _mm_setr_epi16(short w0,
+ short w1,
+ short w2,
+ short w3,
+ short w4,
+ short w5,
+ short w6,
+ short w7)
+{
+ int16_t ALIGN_STRUCT(16) data[8] = {w0, w1, w2, w3, w4, w5, w6, w7};
+ return vreinterpretq_m128i_s16(vld1q_s16((int16_t *) data));
+}
+
+// Sets the 4 signed 32-bit integer values in reverse order
+// https://technet.microsoft.com/en-us/library/security/27yb3ee5(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_setr_epi32(int i3, int i2, int i1, int i0)
+{
+ int32_t ALIGN_STRUCT(16) data[4] = {i3, i2, i1, i0};
+ return vreinterpretq_m128i_s32(vld1q_s32(data));
+}
+
+// Set packed 64-bit integers in dst with the supplied values in reverse order.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_epi64
+FORCE_INLINE __m128i _mm_setr_epi64(__m64 e1, __m64 e0)
+{
+ return vreinterpretq_m128i_s64(vcombine_s64(e1, e0));
+}
+
+// Sets the 16 signed 8-bit integer values to b.
+//
+// r0 := b
+// r1 := b
+// ...
+// r15 := b
+//
+// https://msdn.microsoft.com/en-us/library/6e14xhyf(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set1_epi8(signed char w)
+{
+ return vreinterpretq_m128i_s8(vdupq_n_s8(w));
+}
+
+// Broadcast double-precision (64-bit) floating-point value a to all elements of
+// dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_pd
+FORCE_INLINE __m128d _mm_set1_pd(double d)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(vdupq_n_f64(d));
+#else
+ return vreinterpretq_m128d_s64(vdupq_n_s64(*(int64_t *) &d));
+#endif
+}
+
+// Sets the 8 signed 16-bit integer values to w.
+//
+// r0 := w
+// r1 := w
+// ...
+// r7 := w
+//
+// https://msdn.microsoft.com/en-us/library/k0ya3x0e(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_set1_epi16(short w)
+{
+ return vreinterpretq_m128i_s16(vdupq_n_s16(w));
+}
+
+// Sets the 16 signed 8-bit integer values.
+// https://msdn.microsoft.com/en-us/library/x0cx8zd3(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_set_epi8(signed char b15,
+ signed char b14,
+ signed char b13,
+ signed char b12,
+ signed char b11,
+ signed char b10,
+ signed char b9,
+ signed char b8,
+ signed char b7,
+ signed char b6,
+ signed char b5,
+ signed char b4,
+ signed char b3,
+ signed char b2,
+ signed char b1,
+ signed char b0)
+{
+ int8_t ALIGN_STRUCT(16)
+ data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3,
+ (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7,
+ (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11,
+ (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15};
+ return (__m128i) vld1q_s8(data);
+}
+
+// Sets the 8 signed 16-bit integer values.
+// https://msdn.microsoft.com/en-au/library/3e0fek84(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_set_epi16(short i7,
+ short i6,
+ short i5,
+ short i4,
+ short i3,
+ short i2,
+ short i1,
+ short i0)
+{
+ int16_t ALIGN_STRUCT(16) data[8] = {i0, i1, i2, i3, i4, i5, i6, i7};
+ return vreinterpretq_m128i_s16(vld1q_s16(data));
+}
+
+// Sets the 16 signed 8-bit integer values in reverse order.
+// https://msdn.microsoft.com/en-us/library/2khb9c7k(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_setr_epi8(signed char b0,
+ signed char b1,
+ signed char b2,
+ signed char b3,
+ signed char b4,
+ signed char b5,
+ signed char b6,
+ signed char b7,
+ signed char b8,
+ signed char b9,
+ signed char b10,
+ signed char b11,
+ signed char b12,
+ signed char b13,
+ signed char b14,
+ signed char b15)
+{
+ int8_t ALIGN_STRUCT(16)
+ data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3,
+ (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7,
+ (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11,
+ (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15};
+ return (__m128i) vld1q_s8(data);
+}
+
+// Sets the 4 signed 32-bit integer values to i.
+//
+// r0 := i
+// r1 := i
+// r2 := i
+// r3 := I
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set1_epi32(int _i)
+{
+ return vreinterpretq_m128i_s32(vdupq_n_s32(_i));
+}
+
+// Sets the 2 signed 64-bit integer values to i.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/whtfzhzk(v=vs.100)
+FORCE_INLINE __m128i _mm_set1_epi64(__m64 _i)
+{
+ return vreinterpretq_m128i_s64(vdupq_n_s64((int64_t) _i));
+}
+
+// Sets the 2 signed 64-bit integer values to i.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_epi64x
+FORCE_INLINE __m128i _mm_set1_epi64x(int64_t _i)
+{
+ return vreinterpretq_m128i_s64(vdupq_n_s64(_i));
+}
+
+// Sets the 4 signed 32-bit integer values.
+// https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0)
+{
+ int32_t ALIGN_STRUCT(16) data[4] = {i0, i1, i2, i3};
+ return vreinterpretq_m128i_s32(vld1q_s32(data));
+}
+
+// Returns the __m128i structure with its two 64-bit integer values
+// initialized to the values of the two 64-bit integers passed in.
+// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx
+FORCE_INLINE __m128i _mm_set_epi64x(int64_t i1, int64_t i2)
+{
+ return vreinterpretq_m128i_s64(
+ vcombine_s64(vcreate_s64(i2), vcreate_s64(i1)));
+}
+
+// Returns the __m128i structure with its two 64-bit integer values
+// initialized to the values of the two 64-bit integers passed in.
+// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx
+FORCE_INLINE __m128i _mm_set_epi64(__m64 i1, __m64 i2)
+{
+ return _mm_set_epi64x((int64_t) i1, (int64_t) i2);
+}
+
+// Set packed double-precision (64-bit) floating-point elements in dst with the
+// supplied values.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd
+FORCE_INLINE __m128d _mm_set_pd(double e1, double e0)
+{
+ double ALIGN_STRUCT(16) data[2] = {e0, e1};
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(vld1q_f64((float64_t *) data));
+#else
+ return vreinterpretq_m128d_f32(vld1q_f32((float32_t *) data));
+#endif
+}
+
+// Set packed double-precision (64-bit) floating-point elements in dst with the
+// supplied values in reverse order.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_pd
+FORCE_INLINE __m128d _mm_setr_pd(double e1, double e0)
+{
+ return _mm_set_pd(e0, e1);
+}
+
+// Copy double-precision (64-bit) floating-point element a to the lower element
+// of dst, and zero the upper element.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_sd
+FORCE_INLINE __m128d _mm_set_sd(double a)
+{
+ return _mm_set_pd(0, a);
+}
+
+// Broadcast double-precision (64-bit) floating-point value a to all elements of
+// dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd1
+#define _mm_set_pd1 _mm_set1_pd
+
+// Stores four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/s3h4ay6y(v=vs.100).aspx
+FORCE_INLINE void _mm_store_ps(float *p, __m128 a)
+{
+ vst1q_f32(p, vreinterpretq_f32_m128(a));
+}
+
+// Store the lower single-precision (32-bit) floating-point element from a into
+// 4 contiguous elements in memory. mem_addr must be aligned on a 16-byte
+// boundary or a general-protection exception may be generated.
+//
+// MEM[mem_addr+31:mem_addr] := a[31:0]
+// MEM[mem_addr+63:mem_addr+32] := a[31:0]
+// MEM[mem_addr+95:mem_addr+64] := a[31:0]
+// MEM[mem_addr+127:mem_addr+96] := a[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_ps1
+FORCE_INLINE void _mm_store_ps1(float *p, __m128 a)
+{
+ float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+ vst1q_f32(p, vdupq_n_f32(a0));
+}
+
+// Store the lower single-precision (32-bit) floating-point element from a into
+// 4 contiguous elements in memory. mem_addr must be aligned on a 16-byte
+// boundary or a general-protection exception may be generated.
+//
+// MEM[mem_addr+31:mem_addr] := a[31:0]
+// MEM[mem_addr+63:mem_addr+32] := a[31:0]
+// MEM[mem_addr+95:mem_addr+64] := a[31:0]
+// MEM[mem_addr+127:mem_addr+96] := a[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store1_ps
+#define _mm_store1_ps _mm_store_ps1
+
+// Store 4 single-precision (32-bit) floating-point elements from a into memory
+// in reverse order. mem_addr must be aligned on a 16-byte boundary or a
+// general-protection exception may be generated.
+//
+// MEM[mem_addr+31:mem_addr] := a[127:96]
+// MEM[mem_addr+63:mem_addr+32] := a[95:64]
+// MEM[mem_addr+95:mem_addr+64] := a[63:32]
+// MEM[mem_addr+127:mem_addr+96] := a[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_ps
+FORCE_INLINE void _mm_storer_ps(float *p, __m128 a)
+{
+ float32x4_t tmp = vrev64q_f32(vreinterpretq_f32_m128(a));
+ float32x4_t rev = vextq_f32(tmp, tmp, 2);
+ vst1q_f32(p, rev);
+}
+
+// Stores four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/44e30x22(v=vs.100).aspx
+FORCE_INLINE void _mm_storeu_ps(float *p, __m128 a)
+{
+ vst1q_f32(p, vreinterpretq_f32_m128(a));
+}
+
+// Stores four 32-bit integer values as (as a __m128i value) at the address p.
+// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx
+FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a)
+{
+ vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a));
+}
+
+// Stores four 32-bit integer values as (as a __m128i value) at the address p.
+// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx
+FORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a)
+{
+ vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a));
+}
+
+// Stores the lower single - precision, floating - point value.
+// https://msdn.microsoft.com/en-us/library/tzz10fbx(v=vs.100).aspx
+FORCE_INLINE void _mm_store_ss(float *p, __m128 a)
+{
+ vst1q_lane_f32(p, vreinterpretq_f32_m128(a), 0);
+}
+
+// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point
+// elements) from a into memory. mem_addr must be aligned on a 16-byte boundary
+// or a general-protection exception may be generated.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd
+FORCE_INLINE void _mm_store_pd(double *mem_addr, __m128d a)
+{
+#if defined(__aarch64__)
+ vst1q_f64((float64_t *) mem_addr, vreinterpretq_f64_m128d(a));
+#else
+ vst1q_f32((float32_t *) mem_addr, vreinterpretq_f32_m128d(a));
+#endif
+}
+
+// Store the upper double-precision (64-bit) floating-point element from a into
+// memory.
+//
+// MEM[mem_addr+63:mem_addr] := a[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeh_pd
+FORCE_INLINE void _mm_storeh_pd(double *mem_addr, __m128d a)
+{
+#if defined(__aarch64__)
+ vst1_f64((float64_t *) mem_addr, vget_high_f64(vreinterpretq_f64_m128d(a)));
+#else
+ vst1_f32((float32_t *) mem_addr, vget_high_f32(vreinterpretq_f32_m128d(a)));
+#endif
+}
+
+// Store the lower double-precision (64-bit) floating-point element from a into
+// memory.
+//
+// MEM[mem_addr+63:mem_addr] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storel_pd
+FORCE_INLINE void _mm_storel_pd(double *mem_addr, __m128d a)
+{
+#if defined(__aarch64__)
+ vst1_f64((float64_t *) mem_addr, vget_low_f64(vreinterpretq_f64_m128d(a)));
+#else
+ vst1_f32((float32_t *) mem_addr, vget_low_f32(vreinterpretq_f32_m128d(a)));
+#endif
+}
+
+// Store 2 double-precision (64-bit) floating-point elements from a into memory
+// in reverse order. mem_addr must be aligned on a 16-byte boundary or a
+// general-protection exception may be generated.
+//
+// MEM[mem_addr+63:mem_addr] := a[127:64]
+// MEM[mem_addr+127:mem_addr+64] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_pd
+FORCE_INLINE void _mm_storer_pd(double *mem_addr, __m128d a)
+{
+ float32x4_t f = vreinterpretq_f32_m128d(a);
+ _mm_store_pd(mem_addr, vreinterpretq_m128d_f32(vextq_f32(f, f, 2)));
+}
+
+// Store the lower double-precision (64-bit) floating-point element from a into
+// 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte
+// boundary or a general-protection exception may be generated.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd1
+FORCE_INLINE void _mm_store_pd1(double *mem_addr, __m128d a)
+{
+#if defined(__aarch64__)
+ float64x1_t a_low = vget_low_f64(vreinterpretq_f64_m128d(a));
+ vst1q_f64((float64_t *) mem_addr,
+ vreinterpretq_f64_m128d(vcombine_f64(a_low, a_low)));
+#else
+ float32x2_t a_low = vget_low_f32(vreinterpretq_f32_m128d(a));
+ vst1q_f32((float32_t *) mem_addr,
+ vreinterpretq_f32_m128d(vcombine_f32(a_low, a_low)));
+#endif
+}
+
+// Store the lower double-precision (64-bit) floating-point element from a into
+// 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte
+// boundary or a general-protection exception may be generated.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=9,526,5601&text=_mm_store1_pd
+#define _mm_store1_pd _mm_store_pd1
+
+// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point
+// elements) from a into memory. mem_addr does not need to be aligned on any
+// particular boundary.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_pd
+FORCE_INLINE void _mm_storeu_pd(double *mem_addr, __m128d a)
+{
+ _mm_store_pd(mem_addr, a);
+}
+
+// Reads the lower 64 bits of b and stores them into the lower 64 bits of a.
+// https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_storel_epi64(__m128i *a, __m128i b)
+{
+ uint64x1_t hi = vget_high_u64(vreinterpretq_u64_m128i(*a));
+ uint64x1_t lo = vget_low_u64(vreinterpretq_u64_m128i(b));
+ *a = vreinterpretq_m128i_u64(vcombine_u64(lo, hi));
+}
+
+// Stores the lower two single-precision floating point values of a to the
+// address p.
+//
+// *p0 := a0
+// *p1 := a1
+//
+// https://msdn.microsoft.com/en-us/library/h54t98ks(v=vs.90).aspx
+FORCE_INLINE void _mm_storel_pi(__m64 *p, __m128 a)
+{
+ *p = vreinterpret_m64_f32(vget_low_f32(a));
+}
+
+// Stores the upper two single-precision, floating-point values of a to the
+// address p.
+//
+// *p0 := a2
+// *p1 := a3
+//
+// https://msdn.microsoft.com/en-us/library/a7525fs8(v%3dvs.90).aspx
+FORCE_INLINE void _mm_storeh_pi(__m64 *p, __m128 a)
+{
+ *p = vreinterpret_m64_f32(vget_high_f32(a));
+}
+
+// Loads a single single-precision, floating-point value, copying it into all
+// four words
+// https://msdn.microsoft.com/en-us/library/vstudio/5cdkf716(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_load1_ps(const float *p)
+{
+ return vreinterpretq_m128_f32(vld1q_dup_f32(p));
+}
+
+// Load a single-precision (32-bit) floating-point element from memory into all
+// elements of dst.
+//
+// dst[31:0] := MEM[mem_addr+31:mem_addr]
+// dst[63:32] := MEM[mem_addr+31:mem_addr]
+// dst[95:64] := MEM[mem_addr+31:mem_addr]
+// dst[127:96] := MEM[mem_addr+31:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_ps1
+#define _mm_load_ps1 _mm_load1_ps
+
+// Sets the lower two single-precision, floating-point values with 64
+// bits of data loaded from the address p; the upper two values are passed
+// through from a.
+//
+// Return Value
+// r0 := *p0
+// r1 := *p1
+// r2 := a2
+// r3 := a3
+//
+// https://msdn.microsoft.com/en-us/library/s57cyak2(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_loadl_pi(__m128 a, __m64 const *p)
+{
+ return vreinterpretq_m128_f32(
+ vcombine_f32(vld1_f32((const float32_t *) p), vget_high_f32(a)));
+}
+
+// Load 4 single-precision (32-bit) floating-point elements from memory into dst
+// in reverse order. mem_addr must be aligned on a 16-byte boundary or a
+// general-protection exception may be generated.
+//
+// dst[31:0] := MEM[mem_addr+127:mem_addr+96]
+// dst[63:32] := MEM[mem_addr+95:mem_addr+64]
+// dst[95:64] := MEM[mem_addr+63:mem_addr+32]
+// dst[127:96] := MEM[mem_addr+31:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_ps
+FORCE_INLINE __m128 _mm_loadr_ps(const float *p)
+{
+ float32x4_t v = vrev64q_f32(vld1q_f32(p));
+ return vreinterpretq_m128_f32(vextq_f32(v, v, 2));
+}
+
+// Sets the upper two single-precision, floating-point values with 64
+// bits of data loaded from the address p; the lower two values are passed
+// through from a.
+//
+// r0 := a0
+// r1 := a1
+// r2 := *p0
+// r3 := *p1
+//
+// https://msdn.microsoft.com/en-us/library/w92wta0x(v%3dvs.100).aspx
+FORCE_INLINE __m128 _mm_loadh_pi(__m128 a, __m64 const *p)
+{
+ return vreinterpretq_m128_f32(
+ vcombine_f32(vget_low_f32(a), vld1_f32((const float32_t *) p)));
+}
+
+// Loads four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/zzd50xxt(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_load_ps(const float *p)
+{
+ return vreinterpretq_m128_f32(vld1q_f32(p));
+}
+
+// Loads four single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/x1b16s7z%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_loadu_ps(const float *p)
+{
+ // for neon, alignment doesn't matter, so _mm_load_ps and _mm_loadu_ps are
+ // equivalent for neon
+ return vreinterpretq_m128_f32(vld1q_f32(p));
+}
+
+// Load unaligned 16-bit integer from memory into the first element of dst.
+//
+// dst[15:0] := MEM[mem_addr+15:mem_addr]
+// dst[MAX:16] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si16
+FORCE_INLINE __m128i _mm_loadu_si16(const void *p)
+{
+ return vreinterpretq_m128i_s16(
+ vsetq_lane_s16(*(const int16_t *) p, vdupq_n_s16(0), 0));
+}
+
+// Load unaligned 64-bit integer from memory into the first element of dst.
+//
+// dst[63:0] := MEM[mem_addr+63:mem_addr]
+// dst[MAX:64] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si64
+FORCE_INLINE __m128i _mm_loadu_si64(const void *p)
+{
+ return vreinterpretq_m128i_s64(
+ vcombine_s64(vld1_s64((const int64_t *) p), vdup_n_s64(0)));
+}
+
+// Load a double-precision (64-bit) floating-point element from memory into the
+// lower of dst, and zero the upper element. mem_addr does not need to be
+// aligned on any particular boundary.
+//
+// dst[63:0] := MEM[mem_addr+63:mem_addr]
+// dst[127:64] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_sd
+FORCE_INLINE __m128d _mm_load_sd(const double *p)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(vsetq_lane_f64(*p, vdupq_n_f64(0), 0));
+#else
+ const float *fp = (const float *) p;
+ float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], 0, 0};
+ return vreinterpretq_m128d_f32(vld1q_f32(data));
+#endif
+}
+
+// Loads two double-precision from 16-byte aligned memory, floating-point
+// values.
+//
+// dst[127:0] := MEM[mem_addr+127:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd
+FORCE_INLINE __m128d _mm_load_pd(const double *p)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(vld1q_f64(p));
+#else
+ const float *fp = (const float *) p;
+ float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], fp[2], fp[3]};
+ return vreinterpretq_m128d_f32(vld1q_f32(data));
+#endif
+}
+
+// Loads two double-precision from unaligned memory, floating-point values.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_pd
+FORCE_INLINE __m128d _mm_loadu_pd(const double *p)
+{
+ return _mm_load_pd(p);
+}
+
+// Loads an single - precision, floating - point value into the low word and
+// clears the upper three words.
+// https://msdn.microsoft.com/en-us/library/548bb9h4%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_load_ss(const float *p)
+{
+ return vreinterpretq_m128_f32(vsetq_lane_f32(*p, vdupq_n_f32(0), 0));
+}
+
+// Load 64-bit integer from memory into the first element of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_epi64
+FORCE_INLINE __m128i _mm_loadl_epi64(__m128i const *p)
+{
+ /* Load the lower 64 bits of the value pointed to by p into the
+ * lower 64 bits of the result, zeroing the upper 64 bits of the result.
+ */
+ return vreinterpretq_m128i_s32(
+ vcombine_s32(vld1_s32((int32_t const *) p), vcreate_s32(0)));
+}
+
+// Load a double-precision (64-bit) floating-point element from memory into the
+// lower element of dst, and copy the upper element from a to dst. mem_addr does
+// not need to be aligned on any particular boundary.
+//
+// dst[63:0] := MEM[mem_addr+63:mem_addr]
+// dst[127:64] := a[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_pd
+FORCE_INLINE __m128d _mm_loadl_pd(__m128d a, const double *p)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vcombine_f64(vld1_f64(p), vget_high_f64(vreinterpretq_f64_m128d(a))));
+#else
+ return vreinterpretq_m128d_f32(
+ vcombine_f32(vld1_f32((const float *) p),
+ vget_high_f32(vreinterpretq_f32_m128d(a))));
+#endif
+}
+
+// Load 2 double-precision (64-bit) floating-point elements from memory into dst
+// in reverse order. mem_addr must be aligned on a 16-byte boundary or a
+// general-protection exception may be generated.
+//
+// dst[63:0] := MEM[mem_addr+127:mem_addr+64]
+// dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_pd
+FORCE_INLINE __m128d _mm_loadr_pd(const double *p)
+{
+#if defined(__aarch64__)
+ float64x2_t v = vld1q_f64(p);
+ return vreinterpretq_m128d_f64(vextq_f64(v, v, 1));
+#else
+ int64x2_t v = vld1q_s64((const int64_t *) p);
+ return vreinterpretq_m128d_s64(vextq_s64(v, v, 1));
+#endif
+}
+
+// Sets the low word to the single-precision, floating-point value of b
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/35hdzazd(v=vs.100)
+FORCE_INLINE __m128 _mm_move_ss(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32(vgetq_lane_f32(vreinterpretq_f32_m128(b), 0),
+ vreinterpretq_f32_m128(a), 0));
+}
+
+// Move the lower double-precision (64-bit) floating-point element from b to the
+// lower element of dst, and copy the upper element from a to the upper element
+// of dst.
+//
+// dst[63:0] := b[63:0]
+// dst[127:64] := a[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_sd
+FORCE_INLINE __m128d _mm_move_sd(__m128d a, __m128d b)
+{
+ return vreinterpretq_m128d_f32(
+ vcombine_f32(vget_low_f32(vreinterpretq_f32_m128d(b)),
+ vget_high_f32(vreinterpretq_f32_m128d(a))));
+}
+
+// Copy the lower 64-bit integer in a to the lower element of dst, and zero the
+// upper element.
+//
+// dst[63:0] := a[63:0]
+// dst[127:64] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_epi64
+FORCE_INLINE __m128i _mm_move_epi64(__m128i a)
+{
+ return vreinterpretq_m128i_s64(
+ vsetq_lane_s64(0, vreinterpretq_s64_m128i(a), 1));
+}
+
+// Return vector of type __m128 with undefined elements.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_undefined_ps
+FORCE_INLINE __m128 _mm_undefined_ps(void)
+{
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
+ __m128 a;
+ return a;
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+}
+
+/* Logic/Binary operations */
+
+// Computes the bitwise AND-NOT of the four single-precision, floating-point
+// values of a and b.
+//
+// r0 := ~a0 & b0
+// r1 := ~a1 & b1
+// r2 := ~a2 & b2
+// r3 := ~a3 & b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/68h7wd02(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_s32(
+ vbicq_s32(vreinterpretq_s32_m128(b),
+ vreinterpretq_s32_m128(a))); // *NOTE* argument swap
+}
+
+// Compute the bitwise NOT of packed double-precision (64-bit) floating-point
+// elements in a and then AND with b, and store the results in dst.
+//
+// FOR j := 0 to 1
+// i := j*64
+// dst[i+63:i] := ((NOT a[i+63:i]) AND b[i+63:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_andnot_pd
+FORCE_INLINE __m128d _mm_andnot_pd(__m128d a, __m128d b)
+{
+ // *NOTE* argument swap
+ return vreinterpretq_m128d_s64(
+ vbicq_s64(vreinterpretq_s64_m128d(b), vreinterpretq_s64_m128d(a)));
+}
+
+// Computes the bitwise AND of the 128-bit value in b and the bitwise NOT of the
+// 128-bit value in a.
+//
+// r := (~a) & b
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/1beaceh8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vbicq_s32(vreinterpretq_s32_m128i(b),
+ vreinterpretq_s32_m128i(a))); // *NOTE* argument swap
+}
+
+// Computes the bitwise AND of the 128-bit value in a and the 128-bit value in
+// b.
+//
+// r := a & b
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/6d1txsa8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vandq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Computes the bitwise AND of the four single-precision, floating-point values
+// of a and b.
+//
+// r0 := a0 & b0
+// r1 := a1 & b1
+// r2 := a2 & b2
+// r3 := a3 & b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/73ck1xc5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_s32(
+ vandq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));
+}
+
+// Compute the bitwise AND of packed double-precision (64-bit) floating-point
+// elements in a and b, and store the results in dst.
+//
+// FOR j := 0 to 1
+// i := j*64
+// dst[i+63:i] := a[i+63:i] AND b[i+63:i]
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_and_pd
+FORCE_INLINE __m128d _mm_and_pd(__m128d a, __m128d b)
+{
+ return vreinterpretq_m128d_s64(
+ vandq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b)));
+}
+
+// Computes the bitwise OR of the four single-precision, floating-point values
+// of a and b.
+// https://msdn.microsoft.com/en-us/library/vstudio/7ctdsyy0(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_s32(
+ vorrq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));
+}
+
+// Computes bitwise EXOR (exclusive-or) of the four single-precision,
+// floating-point values of a and b.
+// https://msdn.microsoft.com/en-us/library/ss6k3wk8(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_s32(
+ veorq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b)));
+}
+
+// Compute the bitwise XOR of packed double-precision (64-bit) floating-point
+// elements in a and b, and store the results in dst.
+//
+// FOR j := 0 to 1
+// i := j*64
+// dst[i+63:i] := a[i+63:i] XOR b[i+63:i]
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_xor_pd
+FORCE_INLINE __m128d _mm_xor_pd(__m128d a, __m128d b)
+{
+ return vreinterpretq_m128d_s64(
+ veorq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b)));
+}
+
+// Compute the bitwise OR of packed double-precision (64-bit) floating-point
+// elements in a and b, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_or_pd
+FORCE_INLINE __m128d _mm_or_pd(__m128d a, __m128d b)
+{
+ return vreinterpretq_m128d_s64(
+ vorrq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b)));
+}
+
+// Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b.
+//
+// r := a | b
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/ew8ty0db(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vorrq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Computes the bitwise XOR of the 128-bit value in a and the 128-bit value in
+// b. https://msdn.microsoft.com/en-us/library/fzt08www(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ veorq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Duplicate the low double-precision (64-bit) floating-point element from a,
+// and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movedup_pd
+FORCE_INLINE __m128d _mm_movedup_pd(__m128d a)
+{
+#if (__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vdupq_laneq_f64(vreinterpretq_f64_m128d(a), 0));
+#else
+ return vreinterpretq_m128d_u64(
+ vdupq_n_u64(vgetq_lane_u64(vreinterpretq_u64_m128d(a), 0)));
+#endif
+}
+
+// Duplicate odd-indexed single-precision (32-bit) floating-point elements
+// from a, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movehdup_ps
+FORCE_INLINE __m128 _mm_movehdup_ps(__m128 a)
+{
+#if __has_builtin(__builtin_shufflevector)
+ return vreinterpretq_m128_f32(__builtin_shufflevector(
+ vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 1, 1, 3, 3));
+#else
+ float32_t a1 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 1);
+ float32_t a3 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 3);
+ float ALIGN_STRUCT(16) data[4] = {a1, a1, a3, a3};
+ return vreinterpretq_m128_f32(vld1q_f32(data));
+#endif
+}
+
+// Duplicate even-indexed single-precision (32-bit) floating-point elements
+// from a, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_moveldup_ps
+FORCE_INLINE __m128 _mm_moveldup_ps(__m128 a)
+{
+#if __has_builtin(__builtin_shufflevector)
+ return vreinterpretq_m128_f32(__builtin_shufflevector(
+ vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 0, 0, 2, 2));
+#else
+ float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+ float32_t a2 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 2);
+ float ALIGN_STRUCT(16) data[4] = {a0, a0, a2, a2};
+ return vreinterpretq_m128_f32(vld1q_f32(data));
+#endif
+}
+
+// Moves the upper two values of B into the lower two values of A.
+//
+// r3 := a3
+// r2 := a2
+// r1 := b3
+// r0 := b2
+FORCE_INLINE __m128 _mm_movehl_ps(__m128 __A, __m128 __B)
+{
+ float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(__A));
+ float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(__B));
+ return vreinterpretq_m128_f32(vcombine_f32(b32, a32));
+}
+
+// Moves the lower two values of B into the upper two values of A.
+//
+// r3 := b1
+// r2 := b0
+// r1 := a1
+// r0 := a0
+FORCE_INLINE __m128 _mm_movelh_ps(__m128 __A, __m128 __B)
+{
+ float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(__A));
+ float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(__B));
+ return vreinterpretq_m128_f32(vcombine_f32(a10, b10));
+}
+
+// Compute the absolute value of packed signed 32-bit integers in a, and store
+// the unsigned results in dst.
+//
+// FOR j := 0 to 3
+// i := j*32
+// dst[i+31:i] := ABS(a[i+31:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi32
+FORCE_INLINE __m128i _mm_abs_epi32(__m128i a)
+{
+ return vreinterpretq_m128i_s32(vabsq_s32(vreinterpretq_s32_m128i(a)));
+}
+
+// Compute the absolute value of packed signed 16-bit integers in a, and store
+// the unsigned results in dst.
+//
+// FOR j := 0 to 7
+// i := j*16
+// dst[i+15:i] := ABS(a[i+15:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi16
+FORCE_INLINE __m128i _mm_abs_epi16(__m128i a)
+{
+ return vreinterpretq_m128i_s16(vabsq_s16(vreinterpretq_s16_m128i(a)));
+}
+
+// Compute the absolute value of packed signed 8-bit integers in a, and store
+// the unsigned results in dst.
+//
+// FOR j := 0 to 15
+// i := j*8
+// dst[i+7:i] := ABS(a[i+7:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi8
+FORCE_INLINE __m128i _mm_abs_epi8(__m128i a)
+{
+ return vreinterpretq_m128i_s8(vabsq_s8(vreinterpretq_s8_m128i(a)));
+}
+
+// Compute the absolute value of packed signed 32-bit integers in a, and store
+// the unsigned results in dst.
+//
+// FOR j := 0 to 1
+// i := j*32
+// dst[i+31:i] := ABS(a[i+31:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi32
+FORCE_INLINE __m64 _mm_abs_pi32(__m64 a)
+{
+ return vreinterpret_m64_s32(vabs_s32(vreinterpret_s32_m64(a)));
+}
+
+// Compute the absolute value of packed signed 16-bit integers in a, and store
+// the unsigned results in dst.
+//
+// FOR j := 0 to 3
+// i := j*16
+// dst[i+15:i] := ABS(a[i+15:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi16
+FORCE_INLINE __m64 _mm_abs_pi16(__m64 a)
+{
+ return vreinterpret_m64_s16(vabs_s16(vreinterpret_s16_m64(a)));
+}
+
+// Compute the absolute value of packed signed 8-bit integers in a, and store
+// the unsigned results in dst.
+//
+// FOR j := 0 to 7
+// i := j*8
+// dst[i+7:i] := ABS(a[i+7:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi8
+FORCE_INLINE __m64 _mm_abs_pi8(__m64 a)
+{
+ return vreinterpret_m64_s8(vabs_s8(vreinterpret_s8_m64(a)));
+}
+
+// Concatenate 16-byte blocks in a and b into a 32-byte temporary result, shift
+// the result right by imm8 bytes, and store the low 16 bytes in dst.
+//
+// tmp[255:0] := ((a[127:0] << 128)[255:0] OR b[127:0]) >> (imm8*8)
+// dst[127:0] := tmp[127:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_epi8
+#define _mm_alignr_epi8(a, b, imm) \
+ __extension__({ \
+ __m128i ret; \
+ if (unlikely((imm) >= 32)) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ uint8x16_t tmp_low, tmp_high; \
+ if (imm >= 16) { \
+ const int idx = imm - 16; \
+ tmp_low = vreinterpretq_u8_m128i(a); \
+ tmp_high = vdupq_n_u8(0); \
+ ret = \
+ vreinterpretq_m128i_u8(vextq_u8(tmp_low, tmp_high, idx)); \
+ } else { \
+ const int idx = imm; \
+ tmp_low = vreinterpretq_u8_m128i(b); \
+ tmp_high = vreinterpretq_u8_m128i(a); \
+ ret = \
+ vreinterpretq_m128i_u8(vextq_u8(tmp_low, tmp_high, idx)); \
+ } \
+ } \
+ ret; \
+ })
+
+// Concatenate 8-byte blocks in a and b into a 16-byte temporary result, shift
+// the result right by imm8 bytes, and store the low 8 bytes in dst.
+//
+// tmp[127:0] := ((a[63:0] << 64)[127:0] OR b[63:0]) >> (imm8*8)
+// dst[63:0] := tmp[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_pi8
+#define _mm_alignr_pi8(a, b, imm) \
+ __extension__({ \
+ __m64 ret; \
+ if (unlikely((imm) >= 16)) { \
+ ret = vreinterpret_m64_s8(vdup_n_s8(0)); \
+ } else { \
+ uint8x8_t tmp_low, tmp_high; \
+ if (imm >= 8) { \
+ const int idx = imm - 8; \
+ tmp_low = vreinterpret_u8_m64(a); \
+ tmp_high = vdup_n_u8(0); \
+ ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \
+ } else { \
+ const int idx = imm; \
+ tmp_low = vreinterpret_u8_m64(b); \
+ tmp_high = vreinterpret_u8_m64(a); \
+ ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \
+ } \
+ } \
+ ret; \
+ })
+
+// Takes the upper 64 bits of a and places it in the low end of the result
+// Takes the lower 64 bits of b and places it into the high end of the result.
+FORCE_INLINE __m128 _mm_shuffle_ps_1032(__m128 a, __m128 b)
+{
+ float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(vcombine_f32(a32, b10));
+}
+
+// takes the lower two 32-bit values from a and swaps them and places in high
+// end of result takes the higher two 32 bit values from b and swaps them and
+// places in low end of result.
+FORCE_INLINE __m128 _mm_shuffle_ps_2301(__m128 a, __m128 b)
+{
+ float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+ float32x2_t b23 = vrev64_f32(vget_high_f32(vreinterpretq_f32_m128(b)));
+ return vreinterpretq_m128_f32(vcombine_f32(a01, b23));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0321(__m128 a, __m128 b)
+{
+ float32x2_t a21 = vget_high_f32(
+ vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3));
+ float32x2_t b03 = vget_low_f32(
+ vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3));
+ return vreinterpretq_m128_f32(vcombine_f32(a21, b03));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2103(__m128 a, __m128 b)
+{
+ float32x2_t a03 = vget_low_f32(
+ vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3));
+ float32x2_t b21 = vget_high_f32(
+ vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3));
+ return vreinterpretq_m128_f32(vcombine_f32(a03, b21));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1010(__m128 a, __m128 b)
+{
+ float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(vcombine_f32(a10, b10));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1001(__m128 a, __m128 b)
+{
+ float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+ float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(vcombine_f32(a01, b10));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0101(__m128 a, __m128 b)
+{
+ float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+ float32x2_t b01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(b)));
+ return vreinterpretq_m128_f32(vcombine_f32(a01, b01));
+}
+
+// keeps the low 64 bits of b in the low and puts the high 64 bits of a in the
+// high
+FORCE_INLINE __m128 _mm_shuffle_ps_3210(__m128 a, __m128 b)
+{
+ float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(vcombine_f32(a10, b32));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0011(__m128 a, __m128 b)
+{
+ float32x2_t a11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 1);
+ float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+ return vreinterpretq_m128_f32(vcombine_f32(a11, b00));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_0022(__m128 a, __m128 b)
+{
+ float32x2_t a22 =
+ vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0);
+ float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+ return vreinterpretq_m128_f32(vcombine_f32(a22, b00));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2200(__m128 a, __m128 b)
+{
+ float32x2_t a00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 0);
+ float32x2_t b22 =
+ vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(b)), 0);
+ return vreinterpretq_m128_f32(vcombine_f32(a00, b22));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_3202(__m128 a, __m128 b)
+{
+ float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+ float32x2_t a22 =
+ vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0);
+ float32x2_t a02 = vset_lane_f32(a0, a22, 1); /* TODO: use vzip ?*/
+ float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(vcombine_f32(a02, b32));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_1133(__m128 a, __m128 b)
+{
+ float32x2_t a33 =
+ vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 1);
+ float32x2_t b11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 1);
+ return vreinterpretq_m128_f32(vcombine_f32(a33, b11));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2010(__m128 a, __m128 b)
+{
+ float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+ float32_t b2 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 2);
+ float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+ float32x2_t b20 = vset_lane_f32(b2, b00, 1);
+ return vreinterpretq_m128_f32(vcombine_f32(a10, b20));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2001(__m128 a, __m128 b)
+{
+ float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a)));
+ float32_t b2 = vgetq_lane_f32(b, 2);
+ float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+ float32x2_t b20 = vset_lane_f32(b2, b00, 1);
+ return vreinterpretq_m128_f32(vcombine_f32(a01, b20));
+}
+
+FORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b)
+{
+ float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));
+ float32_t b2 = vgetq_lane_f32(b, 2);
+ float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0);
+ float32x2_t b20 = vset_lane_f32(b2, b00, 1);
+ return vreinterpretq_m128_f32(vcombine_f32(a32, b20));
+}
+
+// NEON does not support a general purpose permute intrinsic
+// Selects four specific single-precision, floating-point values from a and b,
+// based on the mask i.
+//
+// C equivalent:
+// __m128 _mm_shuffle_ps_default(__m128 a, __m128 b,
+// __constrange(0, 255) int imm) {
+// __m128 ret;
+// ret[0] = a[imm & 0x3]; ret[1] = a[(imm >> 2) & 0x3];
+// ret[2] = b[(imm >> 4) & 0x03]; ret[3] = b[(imm >> 6) & 0x03];
+// return ret;
+// }
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/5f0858x0(v=vs.100).aspx
+#define _mm_shuffle_ps_default(a, b, imm) \
+ __extension__({ \
+ float32x4_t ret; \
+ ret = vmovq_n_f32( \
+ vgetq_lane_f32(vreinterpretq_f32_m128(a), (imm) & (0x3))); \
+ ret = vsetq_lane_f32( \
+ vgetq_lane_f32(vreinterpretq_f32_m128(a), ((imm) >> 2) & 0x3), \
+ ret, 1); \
+ ret = vsetq_lane_f32( \
+ vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 4) & 0x3), \
+ ret, 2); \
+ ret = vsetq_lane_f32( \
+ vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 6) & 0x3), \
+ ret, 3); \
+ vreinterpretq_m128_f32(ret); \
+ })
+
+// FORCE_INLINE __m128 _mm_shuffle_ps(__m128 a, __m128 b, __constrange(0,255)
+// int imm)
+#if __has_builtin(__builtin_shufflevector)
+#define _mm_shuffle_ps(a, b, imm) \
+ __extension__({ \
+ float32x4_t _input1 = vreinterpretq_f32_m128(a); \
+ float32x4_t _input2 = vreinterpretq_f32_m128(b); \
+ float32x4_t _shuf = __builtin_shufflevector( \
+ _input1, _input2, (imm) & (0x3), ((imm) >> 2) & 0x3, \
+ (((imm) >> 4) & 0x3) + 4, (((imm) >> 6) & 0x3) + 4); \
+ vreinterpretq_m128_f32(_shuf); \
+ })
+#else // generic
+#define _mm_shuffle_ps(a, b, imm) \
+ __extension__({ \
+ __m128 ret; \
+ switch (imm) { \
+ case _MM_SHUFFLE(1, 0, 3, 2): \
+ ret = _mm_shuffle_ps_1032((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 3, 0, 1): \
+ ret = _mm_shuffle_ps_2301((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(0, 3, 2, 1): \
+ ret = _mm_shuffle_ps_0321((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 1, 0, 3): \
+ ret = _mm_shuffle_ps_2103((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(1, 0, 1, 0): \
+ ret = _mm_movelh_ps((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(1, 0, 0, 1): \
+ ret = _mm_shuffle_ps_1001((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(0, 1, 0, 1): \
+ ret = _mm_shuffle_ps_0101((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(3, 2, 1, 0): \
+ ret = _mm_shuffle_ps_3210((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(0, 0, 1, 1): \
+ ret = _mm_shuffle_ps_0011((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(0, 0, 2, 2): \
+ ret = _mm_shuffle_ps_0022((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 2, 0, 0): \
+ ret = _mm_shuffle_ps_2200((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(3, 2, 0, 2): \
+ ret = _mm_shuffle_ps_3202((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(3, 2, 3, 2): \
+ ret = _mm_movehl_ps((b), (a)); \
+ break; \
+ case _MM_SHUFFLE(1, 1, 3, 3): \
+ ret = _mm_shuffle_ps_1133((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 0, 1, 0): \
+ ret = _mm_shuffle_ps_2010((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 0, 0, 1): \
+ ret = _mm_shuffle_ps_2001((a), (b)); \
+ break; \
+ case _MM_SHUFFLE(2, 0, 3, 2): \
+ ret = _mm_shuffle_ps_2032((a), (b)); \
+ break; \
+ default: \
+ ret = _mm_shuffle_ps_default((a), (b), (imm)); \
+ break; \
+ } \
+ ret; \
+ })
+#endif
+
+// Takes the upper 64 bits of a and places it in the low end of the result
+// Takes the lower 64 bits of a and places it into the high end of the result.
+FORCE_INLINE __m128i _mm_shuffle_epi_1032(__m128i a)
+{
+ int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a));
+ int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a));
+ return vreinterpretq_m128i_s32(vcombine_s32(a32, a10));
+}
+
+// takes the lower two 32-bit values from a and swaps them and places in low end
+// of result takes the higher two 32 bit values from a and swaps them and places
+// in high end of result.
+FORCE_INLINE __m128i _mm_shuffle_epi_2301(__m128i a)
+{
+ int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+ int32x2_t a23 = vrev64_s32(vget_high_s32(vreinterpretq_s32_m128i(a)));
+ return vreinterpretq_m128i_s32(vcombine_s32(a01, a23));
+}
+
+// rotates the least significant 32 bits into the most signficant 32 bits, and
+// shifts the rest down
+FORCE_INLINE __m128i _mm_shuffle_epi_0321(__m128i a)
+{
+ return vreinterpretq_m128i_s32(
+ vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 1));
+}
+
+// rotates the most significant 32 bits into the least signficant 32 bits, and
+// shifts the rest up
+FORCE_INLINE __m128i _mm_shuffle_epi_2103(__m128i a)
+{
+ return vreinterpretq_m128i_s32(
+ vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 3));
+}
+
+// gets the lower 64 bits of a, and places it in the upper 64 bits
+// gets the lower 64 bits of a and places it in the lower 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_1010(__m128i a)
+{
+ int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a));
+ return vreinterpretq_m128i_s32(vcombine_s32(a10, a10));
+}
+
+// gets the lower 64 bits of a, swaps the 0 and 1 elements, and places it in the
+// lower 64 bits gets the lower 64 bits of a, and places it in the upper 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_1001(__m128i a)
+{
+ int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+ int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a));
+ return vreinterpretq_m128i_s32(vcombine_s32(a01, a10));
+}
+
+// gets the lower 64 bits of a, swaps the 0 and 1 elements and places it in the
+// upper 64 bits gets the lower 64 bits of a, swaps the 0 and 1 elements, and
+// places it in the lower 64 bits
+FORCE_INLINE __m128i _mm_shuffle_epi_0101(__m128i a)
+{
+ int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+ return vreinterpretq_m128i_s32(vcombine_s32(a01, a01));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_2211(__m128i a)
+{
+ int32x2_t a11 = vdup_lane_s32(vget_low_s32(vreinterpretq_s32_m128i(a)), 1);
+ int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0);
+ return vreinterpretq_m128i_s32(vcombine_s32(a11, a22));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_0122(__m128i a)
+{
+ int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0);
+ int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a)));
+ return vreinterpretq_m128i_s32(vcombine_s32(a22, a01));
+}
+
+FORCE_INLINE __m128i _mm_shuffle_epi_3332(__m128i a)
+{
+ int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a));
+ int32x2_t a33 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 1);
+ return vreinterpretq_m128i_s32(vcombine_s32(a32, a33));
+}
+
+// Shuffle packed 8-bit integers in a according to shuffle control mask in the
+// corresponding 8-bit element of b, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_epi8
+FORCE_INLINE __m128i _mm_shuffle_epi8(__m128i a, __m128i b)
+{
+ int8x16_t tbl = vreinterpretq_s8_m128i(a); // input a
+ uint8x16_t idx = vreinterpretq_u8_m128i(b); // input b
+ uint8x16_t idx_masked =
+ vandq_u8(idx, vdupq_n_u8(0x8F)); // avoid using meaningless bits
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_s8(vqtbl1q_s8(tbl, idx_masked));
+#elif defined(__GNUC__)
+ int8x16_t ret;
+ // %e and %f represent the even and odd D registers
+ // respectively.
+ __asm__ __volatile__(
+ "vtbl.8 %e[ret], {%e[tbl], %f[tbl]}, %e[idx]\n"
+ "vtbl.8 %f[ret], {%e[tbl], %f[tbl]}, %f[idx]\n"
+ : [ret] "=&w"(ret)
+ : [tbl] "w"(tbl), [idx] "w"(idx_masked));
+ return vreinterpretq_m128i_s8(ret);
+#else
+ // use this line if testing on aarch64
+ int8x8x2_t a_split = {vget_low_s8(tbl), vget_high_s8(tbl)};
+ return vreinterpretq_m128i_s8(
+ vcombine_s8(vtbl2_s8(a_split, vget_low_u8(idx_masked)),
+ vtbl2_s8(a_split, vget_high_u8(idx_masked))));
+#endif
+}
+
+// C equivalent:
+// __m128i _mm_shuffle_epi32_default(__m128i a,
+// __constrange(0, 255) int imm) {
+// __m128i ret;
+// ret[0] = a[imm & 0x3]; ret[1] = a[(imm >> 2) & 0x3];
+// ret[2] = a[(imm >> 4) & 0x03]; ret[3] = a[(imm >> 6) & 0x03];
+// return ret;
+// }
+#define _mm_shuffle_epi32_default(a, imm) \
+ __extension__({ \
+ int32x4_t ret; \
+ ret = vmovq_n_s32( \
+ vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm) & (0x3))); \
+ ret = vsetq_lane_s32( \
+ vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 2) & 0x3), \
+ ret, 1); \
+ ret = vsetq_lane_s32( \
+ vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 4) & 0x3), \
+ ret, 2); \
+ ret = vsetq_lane_s32( \
+ vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 6) & 0x3), \
+ ret, 3); \
+ vreinterpretq_m128i_s32(ret); \
+ })
+
+// FORCE_INLINE __m128i _mm_shuffle_epi32_splat(__m128i a, __constrange(0,255)
+// int imm)
+#if defined(__aarch64__)
+#define _mm_shuffle_epi32_splat(a, imm) \
+ __extension__({ \
+ vreinterpretq_m128i_s32( \
+ vdupq_laneq_s32(vreinterpretq_s32_m128i(a), (imm))); \
+ })
+#else
+#define _mm_shuffle_epi32_splat(a, imm) \
+ __extension__({ \
+ vreinterpretq_m128i_s32( \
+ vdupq_n_s32(vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)))); \
+ })
+#endif
+
+// Shuffles the 4 signed or unsigned 32-bit integers in a as specified by imm.
+// https://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx
+// FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i a,
+// __constrange(0,255) int imm)
+#if __has_builtin(__builtin_shufflevector)
+#define _mm_shuffle_epi32(a, imm) \
+ __extension__({ \
+ int32x4_t _input = vreinterpretq_s32_m128i(a); \
+ int32x4_t _shuf = __builtin_shufflevector( \
+ _input, _input, (imm) & (0x3), ((imm) >> 2) & 0x3, \
+ ((imm) >> 4) & 0x3, ((imm) >> 6) & 0x3); \
+ vreinterpretq_m128i_s32(_shuf); \
+ })
+#else // generic
+#define _mm_shuffle_epi32(a, imm) \
+ __extension__({ \
+ __m128i ret; \
+ switch (imm) { \
+ case _MM_SHUFFLE(1, 0, 3, 2): \
+ ret = _mm_shuffle_epi_1032((a)); \
+ break; \
+ case _MM_SHUFFLE(2, 3, 0, 1): \
+ ret = _mm_shuffle_epi_2301((a)); \
+ break; \
+ case _MM_SHUFFLE(0, 3, 2, 1): \
+ ret = _mm_shuffle_epi_0321((a)); \
+ break; \
+ case _MM_SHUFFLE(2, 1, 0, 3): \
+ ret = _mm_shuffle_epi_2103((a)); \
+ break; \
+ case _MM_SHUFFLE(1, 0, 1, 0): \
+ ret = _mm_shuffle_epi_1010((a)); \
+ break; \
+ case _MM_SHUFFLE(1, 0, 0, 1): \
+ ret = _mm_shuffle_epi_1001((a)); \
+ break; \
+ case _MM_SHUFFLE(0, 1, 0, 1): \
+ ret = _mm_shuffle_epi_0101((a)); \
+ break; \
+ case _MM_SHUFFLE(2, 2, 1, 1): \
+ ret = _mm_shuffle_epi_2211((a)); \
+ break; \
+ case _MM_SHUFFLE(0, 1, 2, 2): \
+ ret = _mm_shuffle_epi_0122((a)); \
+ break; \
+ case _MM_SHUFFLE(3, 3, 3, 2): \
+ ret = _mm_shuffle_epi_3332((a)); \
+ break; \
+ case _MM_SHUFFLE(0, 0, 0, 0): \
+ ret = _mm_shuffle_epi32_splat((a), 0); \
+ break; \
+ case _MM_SHUFFLE(1, 1, 1, 1): \
+ ret = _mm_shuffle_epi32_splat((a), 1); \
+ break; \
+ case _MM_SHUFFLE(2, 2, 2, 2): \
+ ret = _mm_shuffle_epi32_splat((a), 2); \
+ break; \
+ case _MM_SHUFFLE(3, 3, 3, 3): \
+ ret = _mm_shuffle_epi32_splat((a), 3); \
+ break; \
+ default: \
+ ret = _mm_shuffle_epi32_default((a), (imm)); \
+ break; \
+ } \
+ ret; \
+ })
+#endif
+
+// Shuffles the lower 4 signed or unsigned 16-bit integers in a as specified
+// by imm.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/y41dkk37(v=vs.100)
+// FORCE_INLINE __m128i _mm_shufflelo_epi16_function(__m128i a,
+// __constrange(0,255) int
+// imm)
+#define _mm_shufflelo_epi16_function(a, imm) \
+ __extension__({ \
+ int16x8_t ret = vreinterpretq_s16_m128i(a); \
+ int16x4_t lowBits = vget_low_s16(ret); \
+ ret = vsetq_lane_s16(vget_lane_s16(lowBits, (imm) & (0x3)), ret, 0); \
+ ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 2) & 0x3), ret, \
+ 1); \
+ ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 4) & 0x3), ret, \
+ 2); \
+ ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 6) & 0x3), ret, \
+ 3); \
+ vreinterpretq_m128i_s16(ret); \
+ })
+
+// FORCE_INLINE __m128i _mm_shufflelo_epi16(__m128i a,
+// __constrange(0,255) int imm)
+#if __has_builtin(__builtin_shufflevector)
+#define _mm_shufflelo_epi16(a, imm) \
+ __extension__({ \
+ int16x8_t _input = vreinterpretq_s16_m128i(a); \
+ int16x8_t _shuf = __builtin_shufflevector( \
+ _input, _input, ((imm) & (0x3)), (((imm) >> 2) & 0x3), \
+ (((imm) >> 4) & 0x3), (((imm) >> 6) & 0x3), 4, 5, 6, 7); \
+ vreinterpretq_m128i_s16(_shuf); \
+ })
+#else // generic
+#define _mm_shufflelo_epi16(a, imm) _mm_shufflelo_epi16_function((a), (imm))
+#endif
+
+// Shuffles the upper 4 signed or unsigned 16-bit integers in a as specified
+// by imm.
+// https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx
+// FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a,
+// __constrange(0,255) int
+// imm)
+#define _mm_shufflehi_epi16_function(a, imm) \
+ __extension__({ \
+ int16x8_t ret = vreinterpretq_s16_m128i(a); \
+ int16x4_t highBits = vget_high_s16(ret); \
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, (imm) & (0x3)), ret, 4); \
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 2) & 0x3), ret, \
+ 5); \
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 4) & 0x3), ret, \
+ 6); \
+ ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 6) & 0x3), ret, \
+ 7); \
+ vreinterpretq_m128i_s16(ret); \
+ })
+
+// FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a,
+// __constrange(0,255) int imm)
+#if __has_builtin(__builtin_shufflevector)
+#define _mm_shufflehi_epi16(a, imm) \
+ __extension__({ \
+ int16x8_t _input = vreinterpretq_s16_m128i(a); \
+ int16x8_t _shuf = __builtin_shufflevector( \
+ _input, _input, 0, 1, 2, 3, ((imm) & (0x3)) + 4, \
+ (((imm) >> 2) & 0x3) + 4, (((imm) >> 4) & 0x3) + 4, \
+ (((imm) >> 6) & 0x3) + 4); \
+ vreinterpretq_m128i_s16(_shuf); \
+ })
+#else // generic
+#define _mm_shufflehi_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm))
+#endif
+
+// Shuffle double-precision (64-bit) floating-point elements using the control
+// in imm8, and store the results in dst.
+//
+// dst[63:0] := (imm8[0] == 0) ? a[63:0] : a[127:64]
+// dst[127:64] := (imm8[1] == 0) ? b[63:0] : b[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pd
+#if __has_builtin(__builtin_shufflevector)
+#define _mm_shuffle_pd(a, b, imm8) \
+ vreinterpretq_m128d_s64(__builtin_shufflevector( \
+ vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b), imm8 & 0x1, \
+ ((imm8 & 0x2) >> 1) + 2))
+#else
+#define _mm_shuffle_pd(a, b, imm8) \
+ _mm_castsi128_pd(_mm_set_epi64x( \
+ vgetq_lane_s64(vreinterpretq_s64_m128d(b), (imm8 & 0x2) >> 1), \
+ vgetq_lane_s64(vreinterpretq_s64_m128d(a), imm8 & 0x1)))
+#endif
+
+// Blend packed 16-bit integers from a and b using control mask imm8, and store
+// the results in dst.
+//
+// FOR j := 0 to 7
+// i := j*16
+// IF imm8[j]
+// dst[i+15:i] := b[i+15:i]
+// ELSE
+// dst[i+15:i] := a[i+15:i]
+// FI
+// ENDFOR
+// FORCE_INLINE __m128i _mm_blend_epi16(__m128i a, __m128i b,
+// __constrange(0,255) int imm)
+#define _mm_blend_epi16(a, b, imm) \
+ __extension__({ \
+ const uint16_t _mask[8] = {((imm) & (1 << 0)) ? 0xFFFF : 0x0000, \
+ ((imm) & (1 << 1)) ? 0xFFFF : 0x0000, \
+ ((imm) & (1 << 2)) ? 0xFFFF : 0x0000, \
+ ((imm) & (1 << 3)) ? 0xFFFF : 0x0000, \
+ ((imm) & (1 << 4)) ? 0xFFFF : 0x0000, \
+ ((imm) & (1 << 5)) ? 0xFFFF : 0x0000, \
+ ((imm) & (1 << 6)) ? 0xFFFF : 0x0000, \
+ ((imm) & (1 << 7)) ? 0xFFFF : 0x0000}; \
+ uint16x8_t _mask_vec = vld1q_u16(_mask); \
+ uint16x8_t _a = vreinterpretq_u16_m128i(a); \
+ uint16x8_t _b = vreinterpretq_u16_m128i(b); \
+ vreinterpretq_m128i_u16(vbslq_u16(_mask_vec, _b, _a)); \
+ })
+
+// Blend packed 8-bit integers from a and b using mask, and store the results in
+// dst.
+//
+// FOR j := 0 to 15
+// i := j*8
+// IF mask[i+7]
+// dst[i+7:i] := b[i+7:i]
+// ELSE
+// dst[i+7:i] := a[i+7:i]
+// FI
+// ENDFOR
+FORCE_INLINE __m128i _mm_blendv_epi8(__m128i _a, __m128i _b, __m128i _mask)
+{
+ // Use a signed shift right to create a mask with the sign bit
+ uint8x16_t mask =
+ vreinterpretq_u8_s8(vshrq_n_s8(vreinterpretq_s8_m128i(_mask), 7));
+ uint8x16_t a = vreinterpretq_u8_m128i(_a);
+ uint8x16_t b = vreinterpretq_u8_m128i(_b);
+ return vreinterpretq_m128i_u8(vbslq_u8(mask, b, a));
+}
+
+/* Shifts */
+
+
+// Shift packed 16-bit integers in a right by imm while shifting in sign
+// bits, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi16
+FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int imm)
+{
+ const int count = (imm & ~15) ? 15 : imm;
+ return (__m128i) vshlq_s16((int16x8_t) a, vdupq_n_s16(-count));
+}
+
+// Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while
+// shifting in zeros.
+//
+// r0 := a0 << count
+// r1 := a1 << count
+// ...
+// r7 := a7 << count
+//
+// https://msdn.microsoft.com/en-us/library/es73bcsy(v=vs.90).aspx
+#define _mm_slli_epi16(a, imm) \
+ __extension__({ \
+ __m128i ret; \
+ if (unlikely((imm)) <= 0) { \
+ ret = a; \
+ } \
+ if (unlikely((imm) > 15)) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_s16( \
+ vshlq_n_s16(vreinterpretq_s16_m128i(a), (imm))); \
+ } \
+ ret; \
+ })
+
+// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while
+// shifting in zeros. :
+// https://msdn.microsoft.com/en-us/library/z2k3bbtb%28v=vs.90%29.aspx
+// FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, __constrange(0,255) int imm)
+FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, int imm)
+{
+ if (unlikely(imm <= 0)) /* TODO: add constant range macro: [0, 255] */
+ return a;
+ if (unlikely(imm > 31))
+ return _mm_setzero_si128();
+ return vreinterpretq_m128i_s32(
+ vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(imm)));
+}
+
+// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and
+// store the results in dst.
+FORCE_INLINE __m128i _mm_slli_epi64(__m128i a, int imm)
+{
+ if (unlikely(imm <= 0)) /* TODO: add constant range macro: [0, 255] */
+ return a;
+ if (unlikely(imm > 63))
+ return _mm_setzero_si128();
+ return vreinterpretq_m128i_s64(
+ vshlq_s64(vreinterpretq_s64_m128i(a), vdupq_n_s64(imm)));
+}
+
+// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and
+// store the results in dst.
+//
+// FOR j := 0 to 7
+// i := j*16
+// IF imm8[7:0] > 15
+// dst[i+15:i] := 0
+// ELSE
+// dst[i+15:i] := ZeroExtend16(a[i+15:i] >> imm8[7:0])
+// FI
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi16
+#define _mm_srli_epi16(a, imm) \
+ __extension__({ \
+ __m128i ret; \
+ if (unlikely(imm) == 0) { \
+ ret = a; \
+ } \
+ if (likely(0 < (imm) && (imm) < 16)) { \
+ ret = vreinterpretq_m128i_u16( \
+ vshlq_u16(vreinterpretq_u16_m128i(a), vdupq_n_s16(-imm))); \
+ } else { \
+ ret = _mm_setzero_si128(); \
+ } \
+ ret; \
+ })
+
+// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and
+// store the results in dst.
+//
+// FOR j := 0 to 3
+// i := j*32
+// IF imm8[7:0] > 31
+// dst[i+31:i] := 0
+// ELSE
+// dst[i+31:i] := ZeroExtend32(a[i+31:i] >> imm8[7:0])
+// FI
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi32
+// FORCE_INLINE __m128i _mm_srli_epi32(__m128i a, __constrange(0,255) int imm)
+#define _mm_srli_epi32(a, imm) \
+ __extension__({ \
+ __m128i ret; \
+ if (unlikely((imm) == 0)) { \
+ ret = a; \
+ } \
+ if (likely(0 < (imm) && (imm) < 32)) { \
+ ret = vreinterpretq_m128i_u32( \
+ vshlq_u32(vreinterpretq_u32_m128i(a), vdupq_n_s32(-imm))); \
+ } else { \
+ ret = _mm_setzero_si128(); \
+ } \
+ ret; \
+ })
+
+// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and
+// store the results in dst.
+//
+// FOR j := 0 to 1
+// i := j*64
+// IF imm8[7:0] > 63
+// dst[i+63:i] := 0
+// ELSE
+// dst[i+63:i] := ZeroExtend64(a[i+63:i] >> imm8[7:0])
+// FI
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi64
+#define _mm_srli_epi64(a, imm) \
+ __extension__({ \
+ __m128i ret; \
+ if (unlikely((imm) == 0)) { \
+ ret = a; \
+ } \
+ if (likely(0 < (imm) && (imm) < 64)) { \
+ ret = vreinterpretq_m128i_u64( \
+ vshlq_u64(vreinterpretq_u64_m128i(a), vdupq_n_s64(-imm))); \
+ } else { \
+ ret = _mm_setzero_si128(); \
+ } \
+ ret; \
+ })
+
+// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits,
+// and store the results in dst.
+//
+// FOR j := 0 to 3
+// i := j*32
+// IF imm8[7:0] > 31
+// dst[i+31:i] := (a[i+31] ? 0xFFFFFFFF : 0x0)
+// ELSE
+// dst[i+31:i] := SignExtend32(a[i+31:i] >> imm8[7:0])
+// FI
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi32
+// FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, __constrange(0,255) int imm)
+#define _mm_srai_epi32(a, imm) \
+ __extension__({ \
+ __m128i ret; \
+ if (unlikely((imm) == 0)) { \
+ ret = a; \
+ } \
+ if (likely(0 < (imm) && (imm) < 32)) { \
+ ret = vreinterpretq_m128i_s32( \
+ vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(-imm))); \
+ } else { \
+ ret = vreinterpretq_m128i_s32( \
+ vshrq_n_s32(vreinterpretq_s32_m128i(a), 31)); \
+ } \
+ ret; \
+ })
+
+// Shifts the 128 - bit value in a right by imm bytes while shifting in
+// zeros.imm must be an immediate.
+//
+// r := srl(a, imm*8)
+//
+// https://msdn.microsoft.com/en-us/library/305w28yz(v=vs.100).aspx
+// FORCE_INLINE _mm_srli_si128(__m128i a, __constrange(0,255) int imm)
+#define _mm_srli_si128(a, imm) \
+ __extension__({ \
+ __m128i ret; \
+ if (unlikely((imm) <= 0)) { \
+ ret = a; \
+ } \
+ if (unlikely((imm) > 15)) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_s8( \
+ vextq_s8(vreinterpretq_s8_m128i(a), vdupq_n_s8(0), (imm))); \
+ } \
+ ret; \
+ })
+
+// Shifts the 128-bit value in a left by imm bytes while shifting in zeros. imm
+// must be an immediate.
+//
+// r := a << (imm * 8)
+//
+// https://msdn.microsoft.com/en-us/library/34d3k2kt(v=vs.100).aspx
+// FORCE_INLINE __m128i _mm_slli_si128(__m128i a, __constrange(0,255) int imm)
+#define _mm_slli_si128(a, imm) \
+ __extension__({ \
+ __m128i ret; \
+ if (unlikely((imm) <= 0)) { \
+ ret = a; \
+ } \
+ if (unlikely((imm) > 15)) { \
+ ret = _mm_setzero_si128(); \
+ } else { \
+ ret = vreinterpretq_m128i_s8(vextq_s8( \
+ vdupq_n_s8(0), vreinterpretq_s8_m128i(a), 16 - (imm))); \
+ } \
+ ret; \
+ })
+
+// Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while
+// shifting in zeros.
+//
+// r0 := a0 << count
+// r1 := a1 << count
+// ...
+// r7 := a7 << count
+//
+// https://msdn.microsoft.com/en-us/library/c79w388h(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_sll_epi16(__m128i a, __m128i count)
+{
+ uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+ if (unlikely(c > 15))
+ return _mm_setzero_si128();
+
+ int16x8_t vc = vdupq_n_s16((int16_t) c);
+ return vreinterpretq_m128i_s16(vshlq_s16(vreinterpretq_s16_m128i(a), vc));
+}
+
+// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while
+// shifting in zeros.
+//
+// r0 := a0 << count
+// r1 := a1 << count
+// r2 := a2 << count
+// r3 := a3 << count
+//
+// https://msdn.microsoft.com/en-us/library/6fe5a6s9(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_sll_epi32(__m128i a, __m128i count)
+{
+ uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+ if (unlikely(c > 31))
+ return _mm_setzero_si128();
+
+ int32x4_t vc = vdupq_n_s32((int32_t) c);
+ return vreinterpretq_m128i_s32(vshlq_s32(vreinterpretq_s32_m128i(a), vc));
+}
+
+// Shifts the 2 signed or unsigned 64-bit integers in a left by count bits while
+// shifting in zeros.
+//
+// r0 := a0 << count
+// r1 := a1 << count
+//
+// https://msdn.microsoft.com/en-us/library/6ta9dffd(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_sll_epi64(__m128i a, __m128i count)
+{
+ uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+ if (unlikely(c > 63))
+ return _mm_setzero_si128();
+
+ int64x2_t vc = vdupq_n_s64((int64_t) c);
+ return vreinterpretq_m128i_s64(vshlq_s64(vreinterpretq_s64_m128i(a), vc));
+}
+
+// Shifts the 8 signed or unsigned 16-bit integers in a right by count bits
+// while shifting in zeros.
+//
+// r0 := srl(a0, count)
+// r1 := srl(a1, count)
+// ...
+// r7 := srl(a7, count)
+//
+// https://msdn.microsoft.com/en-us/library/wd5ax830(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_srl_epi16(__m128i a, __m128i count)
+{
+ uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+ if (unlikely(c > 15))
+ return _mm_setzero_si128();
+
+ int16x8_t vc = vdupq_n_s16(-(int16_t) c);
+ return vreinterpretq_m128i_u16(vshlq_u16(vreinterpretq_u16_m128i(a), vc));
+}
+
+// Shifts the 4 signed or unsigned 32-bit integers in a right by count bits
+// while shifting in zeros.
+//
+// r0 := srl(a0, count)
+// r1 := srl(a1, count)
+// r2 := srl(a2, count)
+// r3 := srl(a3, count)
+//
+// https://msdn.microsoft.com/en-us/library/a9cbttf4(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_srl_epi32(__m128i a, __m128i count)
+{
+ uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+ if (unlikely(c > 31))
+ return _mm_setzero_si128();
+
+ int32x4_t vc = vdupq_n_s32(-(int32_t) c);
+ return vreinterpretq_m128i_u32(vshlq_u32(vreinterpretq_u32_m128i(a), vc));
+}
+
+// Shifts the 2 signed or unsigned 64-bit integers in a right by count bits
+// while shifting in zeros.
+//
+// r0 := srl(a0, count)
+// r1 := srl(a1, count)
+//
+// https://msdn.microsoft.com/en-us/library/yf6cf9k8(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count)
+{
+ uint64_t c = vreinterpretq_nth_u64_m128i(count, 0);
+ if (unlikely(c > 63))
+ return _mm_setzero_si128();
+
+ int64x2_t vc = vdupq_n_s64(-(int64_t) c);
+ return vreinterpretq_m128i_u64(vshlq_u64(vreinterpretq_u64_m128i(a), vc));
+}
+
+// NEON does not provide a version of this function.
+// Creates a 16-bit mask from the most significant bits of the 16 signed or
+// unsigned 8-bit integers in a and zero extends the upper bits.
+// https://msdn.microsoft.com/en-us/library/vstudio/s090c8fk(v=vs.100).aspx
+FORCE_INLINE int _mm_movemask_epi8(__m128i a)
+{
+ // Use increasingly wide shifts+adds to collect the sign bits
+ // together.
+ // Since the widening shifts would be rather confusing to follow in little
+ // endian, everything will be illustrated in big endian order instead. This
+ // has a different result - the bits would actually be reversed on a big
+ // endian machine.
+
+ // Starting input (only half the elements are shown):
+ // 89 ff 1d c0 00 10 99 33
+ uint8x16_t input = vreinterpretq_u8_m128i(a);
+
+ // Shift out everything but the sign bits with an unsigned shift right.
+ //
+ // Bytes of the vector::
+ // 89 ff 1d c0 00 10 99 33
+ // \ \ \ \ \ \ \ \ high_bits = (uint16x4_t)(input >> 7)
+ // | | | | | | | |
+ // 01 01 00 01 00 00 01 00
+ //
+ // Bits of first important lane(s):
+ // 10001001 (89)
+ // \______
+ // |
+ // 00000001 (01)
+ uint16x8_t high_bits = vreinterpretq_u16_u8(vshrq_n_u8(input, 7));
+
+ // Merge the even lanes together with a 16-bit unsigned shift right + add.
+ // 'xx' represents garbage data which will be ignored in the final result.
+ // In the important bytes, the add functions like a binary OR.
+ //
+ // 01 01 00 01 00 00 01 00
+ // \_ | \_ | \_ | \_ | paired16 = (uint32x4_t)(input + (input >> 7))
+ // \| \| \| \|
+ // xx 03 xx 01 xx 00 xx 02
+ //
+ // 00000001 00000001 (01 01)
+ // \_______ |
+ // \|
+ // xxxxxxxx xxxxxx11 (xx 03)
+ uint32x4_t paired16 =
+ vreinterpretq_u32_u16(vsraq_n_u16(high_bits, high_bits, 7));
+
+ // Repeat with a wider 32-bit shift + add.
+ // xx 03 xx 01 xx 00 xx 02
+ // \____ | \____ | paired32 = (uint64x1_t)(paired16 + (paired16 >>
+ // 14))
+ // \| \|
+ // xx xx xx 0d xx xx xx 02
+ //
+ // 00000011 00000001 (03 01)
+ // \\_____ ||
+ // '----.\||
+ // xxxxxxxx xxxx1101 (xx 0d)
+ uint64x2_t paired32 =
+ vreinterpretq_u64_u32(vsraq_n_u32(paired16, paired16, 14));
+
+ // Last, an even wider 64-bit shift + add to get our result in the low 8 bit
+ // lanes. xx xx xx 0d xx xx xx 02
+ // \_________ | paired64 = (uint8x8_t)(paired32 + (paired32 >>
+ // 28))
+ // \|
+ // xx xx xx xx xx xx xx d2
+ //
+ // 00001101 00000010 (0d 02)
+ // \ \___ | |
+ // '---. \| |
+ // xxxxxxxx 11010010 (xx d2)
+ uint8x16_t paired64 =
+ vreinterpretq_u8_u64(vsraq_n_u64(paired32, paired32, 28));
+
+ // Extract the low 8 bits from each 64-bit lane with 2 8-bit extracts.
+ // xx xx xx xx xx xx xx d2
+ // || return paired64[0]
+ // d2
+ // Note: Little endian would return the correct value 4b (01001011) instead.
+ return vgetq_lane_u8(paired64, 0) | ((int) vgetq_lane_u8(paired64, 8) << 8);
+}
+
+// Copy the lower 64-bit integer in a to dst.
+//
+// dst[63:0] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movepi64_pi64
+FORCE_INLINE __m64 _mm_movepi64_pi64(__m128i a)
+{
+ return vreinterpret_m64_s64(vget_low_s64(vreinterpretq_s64_m128i(a)));
+}
+
+// Copy the 64-bit integer a to the lower element of dst, and zero the upper
+// element.
+//
+// dst[63:0] := a[63:0]
+// dst[127:64] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movpi64_epi64
+FORCE_INLINE __m128i _mm_movpi64_epi64(__m64 a)
+{
+ return vreinterpretq_m128i_s64(
+ vcombine_s64(vreinterpret_s64_m64(a), vdup_n_s64(0)));
+}
+
+// NEON does not provide this method
+// Creates a 4-bit mask from the most significant bits of the four
+// single-precision, floating-point values.
+// https://msdn.microsoft.com/en-us/library/vstudio/4490ys29(v=vs.100).aspx
+FORCE_INLINE int _mm_movemask_ps(__m128 a)
+{
+ uint32x4_t input = vreinterpretq_u32_m128(a);
+#if defined(__aarch64__)
+ static const int32x4_t shift = {0, 1, 2, 3};
+ uint32x4_t tmp = vshrq_n_u32(input, 31);
+ return vaddvq_u32(vshlq_u32(tmp, shift));
+#else
+ // Uses the exact same method as _mm_movemask_epi8, see that for details.
+ // Shift out everything but the sign bits with a 32-bit unsigned shift
+ // right.
+ uint64x2_t high_bits = vreinterpretq_u64_u32(vshrq_n_u32(input, 31));
+ // Merge the two pairs together with a 64-bit unsigned shift right + add.
+ uint8x16_t paired =
+ vreinterpretq_u8_u64(vsraq_n_u64(high_bits, high_bits, 31));
+ // Extract the result.
+ return vgetq_lane_u8(paired, 0) | (vgetq_lane_u8(paired, 8) << 2);
+#endif
+}
+
+// Compute the bitwise NOT of a and then AND with a 128-bit vector containing
+// all 1's, and return 1 if the result is zero, otherwise return 0.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_ones
+FORCE_INLINE int _mm_test_all_ones(__m128i a)
+{
+ return (uint64_t)(vgetq_lane_s64(a, 0) & vgetq_lane_s64(a, 1)) ==
+ ~(uint64_t) 0;
+}
+
+// Compute the bitwise AND of 128 bits (representing integer data) in a and
+// mask, and return 1 if the result is zero, otherwise return 0.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_zeros
+FORCE_INLINE int _mm_test_all_zeros(__m128i a, __m128i mask)
+{
+ int64x2_t a_and_mask =
+ vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(mask));
+ return (vgetq_lane_s64(a_and_mask, 0) | vgetq_lane_s64(a_and_mask, 1)) ? 0
+ : 1;
+}
+
+/* Math operations */
+
+// Subtracts the four single-precision, floating-point values of a and b.
+//
+// r0 := a0 - b0
+// r1 := a1 - b1
+// r2 := a2 - b2
+// r3 := a3 - b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/1zad2k61(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_f32(
+ vsubq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Subtract the lower single-precision (32-bit) floating-point element in b from
+// the lower single-precision (32-bit) floating-point element in a, store the
+// result in the lower element of dst, and copy the upper 3 packed elements from
+// a to the upper elements of dst.
+//
+// dst[31:0] := a[31:0] - b[31:0]
+// dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_ss
+FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(a, _mm_sub_ps(a, b));
+}
+
+// Subtract 2 packed 64-bit integers in b from 2 packed 64-bit integers in a,
+// and store the results in dst.
+// r0 := a0 - b0
+// r1 := a1 - b1
+FORCE_INLINE __m128i _mm_sub_epi64(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s64(
+ vsubq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b)));
+}
+
+// Subtracts the 4 signed or unsigned 32-bit integers of b from the 4 signed or
+// unsigned 32-bit integers of a.
+//
+// r0 := a0 - b0
+// r1 := a1 - b1
+// r2 := a2 - b2
+// r3 := a3 - b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/fhh866h0(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_sub_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vsubq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Subtract packed 16-bit integers in b from packed 16-bit integers in a, and
+// store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_epi16
+FORCE_INLINE __m128i _mm_sub_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Subtract packed 8-bit integers in b from packed 8-bit integers in a, and
+// store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_epi8
+FORCE_INLINE __m128i _mm_sub_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s8(
+ vsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Subtract 64-bit integer b from 64-bit integer a, and store the result in dst.
+//
+// dst[63:0] := a[63:0] - b[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_si64
+FORCE_INLINE __m64 _mm_sub_si64(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_s64(
+ vsub_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b)));
+}
+
+// Subtracts the 8 unsigned 16-bit integers of bfrom the 8 unsigned 16-bit
+// integers of a and saturates..
+// https://technet.microsoft.com/en-us/subscriptions/index/f44y0s19(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_subs_epu16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vqsubq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));
+}
+
+// Subtracts the 16 unsigned 8-bit integers of b from the 16 unsigned 8-bit
+// integers of a and saturates.
+//
+// r0 := UnsignedSaturate(a0 - b0)
+// r1 := UnsignedSaturate(a1 - b1)
+// ...
+// r15 := UnsignedSaturate(a15 - b15)
+//
+// https://technet.microsoft.com/en-us/subscriptions/yadkxc18(v=vs.90)
+FORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vqsubq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Subtracts the 16 signed 8-bit integers of b from the 16 signed 8-bit integers
+// of a and saturates.
+//
+// r0 := SignedSaturate(a0 - b0)
+// r1 := SignedSaturate(a1 - b1)
+// ...
+// r15 := SignedSaturate(a15 - b15)
+//
+// https://technet.microsoft.com/en-us/subscriptions/by7kzks1(v=vs.90)
+FORCE_INLINE __m128i _mm_subs_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s8(
+ vqsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Subtracts the 8 signed 16-bit integers of b from the 8 signed 16-bit integers
+// of a and saturates.
+//
+// r0 := SignedSaturate(a0 - b0)
+// r1 := SignedSaturate(a1 - b1)
+// ...
+// r7 := SignedSaturate(a7 - b7)
+//
+// https://technet.microsoft.com/en-us/subscriptions/3247z5b8(v=vs.90)
+FORCE_INLINE __m128i _mm_subs_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vqsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Subtract packed double-precision (64-bit) floating-point elements in b from
+// packed double-precision (64-bit) floating-point elements in a, and store the
+// results in dst.
+//
+// FOR j := 0 to 1
+// i := j*64
+// dst[i+63:i] := a[i+63:i] - b[i+63:i]
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_sub_pd
+FORCE_INLINE __m128d _mm_sub_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vsubq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+ double *da = (double *) &a;
+ double *db = (double *) &b;
+ double c[2];
+ c[0] = da[0] - db[0];
+ c[1] = da[1] - db[1];
+ return vld1q_f32((float32_t *) c);
+#endif
+}
+
+// Subtract the lower double-precision (64-bit) floating-point element in b from
+// the lower double-precision (64-bit) floating-point element in a, store the
+// result in the lower element of dst, and copy the upper element from a to the
+// upper element of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_sd
+FORCE_INLINE __m128d _mm_sub_sd(__m128d a, __m128d b)
+{
+ return _mm_move_sd(a, _mm_sub_pd(a, b));
+}
+
+// Add packed unsigned 16-bit integers in a and b using saturation, and store
+// the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epu16
+FORCE_INLINE __m128i _mm_adds_epu16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vqaddq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));
+}
+
+// Negate packed 8-bit integers in a when the corresponding signed
+// 8-bit integer in b is negative, and store the results in dst.
+// Element in dst are zeroed out when the corresponding element
+// in b is zero.
+//
+// for i in 0..15
+// if b[i] < 0
+// r[i] := -a[i]
+// else if b[i] == 0
+// r[i] := 0
+// else
+// r[i] := a[i]
+// fi
+// done
+FORCE_INLINE __m128i _mm_sign_epi8(__m128i _a, __m128i _b)
+{
+ int8x16_t a = vreinterpretq_s8_m128i(_a);
+ int8x16_t b = vreinterpretq_s8_m128i(_b);
+
+ // signed shift right: faster than vclt
+ // (b < 0) ? 0xFF : 0
+ uint8x16_t ltMask = vreinterpretq_u8_s8(vshrq_n_s8(b, 7));
+
+ // (b == 0) ? 0xFF : 0
+#if defined(__aarch64__)
+ int8x16_t zeroMask = vreinterpretq_s8_u8(vceqzq_s8(b));
+#else
+ int8x16_t zeroMask = vreinterpretq_s8_u8(vceqq_s8(b, vdupq_n_s8(0)));
+#endif
+
+ // bitwise select either a or nagative 'a' (vnegq_s8(a) return nagative 'a')
+ // based on ltMask
+ int8x16_t masked = vbslq_s8(ltMask, vnegq_s8(a), a);
+ // res = masked & (~zeroMask)
+ int8x16_t res = vbicq_s8(masked, zeroMask);
+
+ return vreinterpretq_m128i_s8(res);
+}
+
+// Negate packed 16-bit integers in a when the corresponding signed
+// 16-bit integer in b is negative, and store the results in dst.
+// Element in dst are zeroed out when the corresponding element
+// in b is zero.
+//
+// for i in 0..7
+// if b[i] < 0
+// r[i] := -a[i]
+// else if b[i] == 0
+// r[i] := 0
+// else
+// r[i] := a[i]
+// fi
+// done
+FORCE_INLINE __m128i _mm_sign_epi16(__m128i _a, __m128i _b)
+{
+ int16x8_t a = vreinterpretq_s16_m128i(_a);
+ int16x8_t b = vreinterpretq_s16_m128i(_b);
+
+ // signed shift right: faster than vclt
+ // (b < 0) ? 0xFFFF : 0
+ uint16x8_t ltMask = vreinterpretq_u16_s16(vshrq_n_s16(b, 15));
+ // (b == 0) ? 0xFFFF : 0
+#if defined(__aarch64__)
+ int16x8_t zeroMask = vreinterpretq_s16_u16(vceqzq_s16(b));
+#else
+ int16x8_t zeroMask = vreinterpretq_s16_u16(vceqq_s16(b, vdupq_n_s16(0)));
+#endif
+
+ // bitwise select either a or negative 'a' (vnegq_s16(a) equals to negative
+ // 'a') based on ltMask
+ int16x8_t masked = vbslq_s16(ltMask, vnegq_s16(a), a);
+ // res = masked & (~zeroMask)
+ int16x8_t res = vbicq_s16(masked, zeroMask);
+ return vreinterpretq_m128i_s16(res);
+}
+
+// Negate packed 32-bit integers in a when the corresponding signed
+// 32-bit integer in b is negative, and store the results in dst.
+// Element in dst are zeroed out when the corresponding element
+// in b is zero.
+//
+// for i in 0..3
+// if b[i] < 0
+// r[i] := -a[i]
+// else if b[i] == 0
+// r[i] := 0
+// else
+// r[i] := a[i]
+// fi
+// done
+FORCE_INLINE __m128i _mm_sign_epi32(__m128i _a, __m128i _b)
+{
+ int32x4_t a = vreinterpretq_s32_m128i(_a);
+ int32x4_t b = vreinterpretq_s32_m128i(_b);
+
+ // signed shift right: faster than vclt
+ // (b < 0) ? 0xFFFFFFFF : 0
+ uint32x4_t ltMask = vreinterpretq_u32_s32(vshrq_n_s32(b, 31));
+
+ // (b == 0) ? 0xFFFFFFFF : 0
+#if defined(__aarch64__)
+ int32x4_t zeroMask = vreinterpretq_s32_u32(vceqzq_s32(b));
+#else
+ int32x4_t zeroMask = vreinterpretq_s32_u32(vceqq_s32(b, vdupq_n_s32(0)));
+#endif
+
+ // bitwise select either a or negative 'a' (vnegq_s32(a) equals to negative
+ // 'a') based on ltMask
+ int32x4_t masked = vbslq_s32(ltMask, vnegq_s32(a), a);
+ // res = masked & (~zeroMask)
+ int32x4_t res = vbicq_s32(masked, zeroMask);
+ return vreinterpretq_m128i_s32(res);
+}
+
+// Negate packed 16-bit integers in a when the corresponding signed 16-bit
+// integer in b is negative, and store the results in dst. Element in dst are
+// zeroed out when the corresponding element in b is zero.
+//
+// FOR j := 0 to 3
+// i := j*16
+// IF b[i+15:i] < 0
+// dst[i+15:i] := -(a[i+15:i])
+// ELSE IF b[i+15:i] == 0
+// dst[i+15:i] := 0
+// ELSE
+// dst[i+15:i] := a[i+15:i]
+// FI
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi16
+FORCE_INLINE __m64 _mm_sign_pi16(__m64 _a, __m64 _b)
+{
+ int16x4_t a = vreinterpret_s16_m64(_a);
+ int16x4_t b = vreinterpret_s16_m64(_b);
+
+ // signed shift right: faster than vclt
+ // (b < 0) ? 0xFFFF : 0
+ uint16x4_t ltMask = vreinterpret_u16_s16(vshr_n_s16(b, 15));
+
+ // (b == 0) ? 0xFFFF : 0
+#if defined(__aarch64__)
+ int16x4_t zeroMask = vreinterpret_s16_u16(vceqz_s16(b));
+#else
+ int16x4_t zeroMask = vreinterpret_s16_u16(vceq_s16(b, vdup_n_s16(0)));
+#endif
+
+ // bitwise select either a or nagative 'a' (vneg_s16(a) return nagative 'a')
+ // based on ltMask
+ int16x4_t masked = vbsl_s16(ltMask, vneg_s16(a), a);
+ // res = masked & (~zeroMask)
+ int16x4_t res = vbic_s16(masked, zeroMask);
+
+ return vreinterpret_m64_s16(res);
+}
+
+// Negate packed 32-bit integers in a when the corresponding signed 32-bit
+// integer in b is negative, and store the results in dst. Element in dst are
+// zeroed out when the corresponding element in b is zero.
+//
+// FOR j := 0 to 1
+// i := j*32
+// IF b[i+31:i] < 0
+// dst[i+31:i] := -(a[i+31:i])
+// ELSE IF b[i+31:i] == 0
+// dst[i+31:i] := 0
+// ELSE
+// dst[i+31:i] := a[i+31:i]
+// FI
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi32
+FORCE_INLINE __m64 _mm_sign_pi32(__m64 _a, __m64 _b)
+{
+ int32x2_t a = vreinterpret_s32_m64(_a);
+ int32x2_t b = vreinterpret_s32_m64(_b);
+
+ // signed shift right: faster than vclt
+ // (b < 0) ? 0xFFFFFFFF : 0
+ uint32x2_t ltMask = vreinterpret_u32_s32(vshr_n_s32(b, 31));
+
+ // (b == 0) ? 0xFFFFFFFF : 0
+#if defined(__aarch64__)
+ int32x2_t zeroMask = vreinterpret_s32_u32(vceqz_s32(b));
+#else
+ int32x2_t zeroMask = vreinterpret_s32_u32(vceq_s32(b, vdup_n_s32(0)));
+#endif
+
+ // bitwise select either a or nagative 'a' (vneg_s32(a) return nagative 'a')
+ // based on ltMask
+ int32x2_t masked = vbsl_s32(ltMask, vneg_s32(a), a);
+ // res = masked & (~zeroMask)
+ int32x2_t res = vbic_s32(masked, zeroMask);
+
+ return vreinterpret_m64_s32(res);
+}
+
+// Negate packed 8-bit integers in a when the corresponding signed 8-bit integer
+// in b is negative, and store the results in dst. Element in dst are zeroed out
+// when the corresponding element in b is zero.
+//
+// FOR j := 0 to 7
+// i := j*8
+// IF b[i+7:i] < 0
+// dst[i+7:i] := -(a[i+7:i])
+// ELSE IF b[i+7:i] == 0
+// dst[i+7:i] := 0
+// ELSE
+// dst[i+7:i] := a[i+7:i]
+// FI
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi8
+FORCE_INLINE __m64 _mm_sign_pi8(__m64 _a, __m64 _b)
+{
+ int8x8_t a = vreinterpret_s8_m64(_a);
+ int8x8_t b = vreinterpret_s8_m64(_b);
+
+ // signed shift right: faster than vclt
+ // (b < 0) ? 0xFF : 0
+ uint8x8_t ltMask = vreinterpret_u8_s8(vshr_n_s8(b, 7));
+
+ // (b == 0) ? 0xFF : 0
+#if defined(__aarch64__)
+ int8x8_t zeroMask = vreinterpret_s8_u8(vceqz_s8(b));
+#else
+ int8x8_t zeroMask = vreinterpret_s8_u8(vceq_s8(b, vdup_n_s8(0)));
+#endif
+
+ // bitwise select either a or nagative 'a' (vneg_s8(a) return nagative 'a')
+ // based on ltMask
+ int8x8_t masked = vbsl_s8(ltMask, vneg_s8(a), a);
+ // res = masked & (~zeroMask)
+ int8x8_t res = vbic_s8(masked, zeroMask);
+
+ return vreinterpret_m64_s8(res);
+}
+
+// Average packed unsigned 16-bit integers in a and b, and store the results in
+// dst.
+//
+// FOR j := 0 to 3
+// i := j*16
+// dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu16
+FORCE_INLINE __m64 _mm_avg_pu16(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_u16(
+ vrhadd_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b)));
+}
+
+// Average packed unsigned 8-bit integers in a and b, and store the results in
+// dst.
+//
+// FOR j := 0 to 7
+// i := j*8
+// dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu8
+FORCE_INLINE __m64 _mm_avg_pu8(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_u8(
+ vrhadd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b)));
+}
+
+// Average packed unsigned 8-bit integers in a and b, and store the results in
+// dst.
+//
+// FOR j := 0 to 7
+// i := j*8
+// dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgb
+#define _m_pavgb(a, b) _mm_avg_pu8(a, b)
+
+// Average packed unsigned 16-bit integers in a and b, and store the results in
+// dst.
+//
+// FOR j := 0 to 3
+// i := j*16
+// dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgw
+#define _m_pavgw(a, b) _mm_avg_pu16(a, b)
+
+// Extract a 16-bit integer from a, selected with imm8, and store the result in
+// the lower element of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pextrw
+#define _m_pextrw(a, imm) _mm_extract_pi16(a, imm)
+
+// Copy a to dst, and insert the 16-bit integer i into dst at the location
+// specified by imm8.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=m_pinsrw
+#define _m_pinsrw(a, i, imm) _mm_insert_pi16(a, i, imm)
+
+// Compare packed signed 16-bit integers in a and b, and store packed maximum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxsw
+#define _m_pmaxsw(a, b) _mm_max_pi16(a, b)
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed maximum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxub
+#define _m_pmaxub(a, b) _mm_max_pu8(a, b)
+
+// Compare packed signed 16-bit integers in a and b, and store packed minimum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminsw
+#define _m_pminsw(a, b) _mm_min_pi16(a, b)
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed minimum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminub
+#define _m_pminub(a, b) _mm_min_pu8(a, b)
+
+// Computes the average of the 16 unsigned 8-bit integers in a and the 16
+// unsigned 8-bit integers in b and rounds.
+//
+// r0 := (a0 + b0) / 2
+// r1 := (a1 + b1) / 2
+// ...
+// r15 := (a15 + b15) / 2
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/8zwh554a(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_avg_epu8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vrhaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Computes the average of the 8 unsigned 16-bit integers in a and the 8
+// unsigned 16-bit integers in b and rounds.
+//
+// r0 := (a0 + b0) / 2
+// r1 := (a1 + b1) / 2
+// ...
+// r7 := (a7 + b7) / 2
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/y13ca3c8(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_avg_epu16(__m128i a, __m128i b)
+{
+ return (__m128i) vrhaddq_u16(vreinterpretq_u16_m128i(a),
+ vreinterpretq_u16_m128i(b));
+}
+
+// Adds the four single-precision, floating-point values of a and b.
+//
+// r0 := a0 + b0
+// r1 := a1 + b1
+// r2 := a2 + b2
+// r3 := a3 + b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/c9848chc(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_f32(
+ vaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Add packed double-precision (64-bit) floating-point elements in a and b, and
+// store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_pd
+FORCE_INLINE __m128d _mm_add_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+ double *da = (double *) &a;
+ double *db = (double *) &b;
+ double c[2];
+ c[0] = da[0] + db[0];
+ c[1] = da[1] + db[1];
+ return vld1q_f32((float32_t *) c);
+#endif
+}
+
+// Add the lower double-precision (64-bit) floating-point element in a and b,
+// store the result in the lower element of dst, and copy the upper element from
+// a to the upper element of dst.
+//
+// dst[63:0] := a[63:0] + b[63:0]
+// dst[127:64] := a[127:64]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_sd
+FORCE_INLINE __m128d _mm_add_sd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+ return _mm_move_sd(a, _mm_add_pd(a, b));
+#else
+ double *da = (double *) &a;
+ double *db = (double *) &b;
+ double c[2];
+ c[0] = da[0] + db[0];
+ c[1] = da[1];
+ return vld1q_f32((float32_t *) c);
+#endif
+}
+
+// Add 64-bit integers a and b, and store the result in dst.
+//
+// dst[63:0] := a[63:0] + b[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_si64
+FORCE_INLINE __m64 _mm_add_si64(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_s64(
+ vadd_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b)));
+}
+
+// adds the scalar single-precision floating point values of a and b.
+// https://msdn.microsoft.com/en-us/library/be94x2y6(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_add_ss(__m128 a, __m128 b)
+{
+ float32_t b0 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 0);
+ float32x4_t value = vsetq_lane_f32(b0, vdupq_n_f32(0), 0);
+ // the upper values in the result must be the remnants of <a>.
+ return vreinterpretq_m128_f32(vaddq_f32(a, value));
+}
+
+// Adds the 4 signed or unsigned 64-bit integers in a to the 4 signed or
+// unsigned 32-bit integers in b.
+// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi64(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s64(
+ vaddq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b)));
+}
+
+// Adds the 4 signed or unsigned 32-bit integers in a to the 4 signed or
+// unsigned 32-bit integers in b.
+//
+// r0 := a0 + b0
+// r1 := a1 + b1
+// r2 := a2 + b2
+// r3 := a3 + b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vaddq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or
+// unsigned 16-bit integers in b.
+// https://msdn.microsoft.com/en-us/library/fceha5k4(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Adds the 16 signed or unsigned 8-bit integers in a to the 16 signed or
+// unsigned 8-bit integers in b.
+// https://technet.microsoft.com/en-us/subscriptions/yc7tcyzs(v=vs.90)
+FORCE_INLINE __m128i _mm_add_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s8(
+ vaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Adds the 8 signed 16-bit integers in a to the 8 signed 16-bit integers in b
+// and saturates.
+//
+// r0 := SignedSaturate(a0 + b0)
+// r1 := SignedSaturate(a1 + b1)
+// ...
+// r7 := SignedSaturate(a7 + b7)
+//
+// https://msdn.microsoft.com/en-us/library/1a306ef8(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_adds_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vqaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Add packed signed 8-bit integers in a and b using saturation, and store the
+// results in dst.
+//
+// FOR j := 0 to 15
+// i := j*8
+// dst[i+7:i] := Saturate8( a[i+7:i] + b[i+7:i] )
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epi8
+FORCE_INLINE __m128i _mm_adds_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s8(
+ vqaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Adds the 16 unsigned 8-bit integers in a to the 16 unsigned 8-bit integers in
+// b and saturates..
+// https://msdn.microsoft.com/en-us/library/9hahyddy(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_adds_epu8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vqaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Multiplies the 8 signed or unsigned 16-bit integers from a by the 8 signed or
+// unsigned 16-bit integers from b.
+//
+// r0 := (a0 * b0)[15:0]
+// r1 := (a1 * b1)[15:0]
+// ...
+// r7 := (a7 * b7)[15:0]
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/9ks1472s(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vmulq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Multiplies the 4 signed or unsigned 32-bit integers from a by the 4 signed or
+// unsigned 32-bit integers from b.
+// https://msdn.microsoft.com/en-us/library/vstudio/bb531409(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mullo_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vmulq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Multiply the packed unsigned 16-bit integers in a and b, producing
+// intermediate 32-bit integers, and store the high 16 bits of the intermediate
+// integers in dst.
+//
+// FOR j := 0 to 3
+// i := j*16
+// tmp[31:0] := a[i+15:i] * b[i+15:i]
+// dst[i+15:i] := tmp[31:16]
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmulhuw
+#define _m_pmulhuw(a, b) _mm_mulhi_pu16(a, b)
+
+// Multiplies the four single-precision, floating-point values of a and b.
+//
+// r0 := a0 * b0
+// r1 := a1 * b1
+// r2 := a2 * b2
+// r3 := a3 * b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/22kbk6t9(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_f32(
+ vmulq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Multiply packed double-precision (64-bit) floating-point elements in a and b,
+// and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_pd
+FORCE_INLINE __m128d _mm_mul_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vmulq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+ double *da = (double *) &a;
+ double *db = (double *) &b;
+ double c[2];
+ c[0] = da[0] * db[0];
+ c[1] = da[1] * db[1];
+ return vld1q_f32((float32_t *) c);
+#endif
+}
+
+// Multiply the lower double-precision (64-bit) floating-point element in a and
+// b, store the result in the lower element of dst, and copy the upper element
+// from a to the upper element of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mul_sd
+FORCE_INLINE __m128d _mm_mul_sd(__m128d a, __m128d b)
+{
+ return _mm_move_sd(a, _mm_mul_pd(a, b));
+}
+
+// Multiply the lower single-precision (32-bit) floating-point element in a and
+// b, store the result in the lower element of dst, and copy the upper 3 packed
+// elements from a to the upper elements of dst.
+//
+// dst[31:0] := a[31:0] * b[31:0]
+// dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_ss
+FORCE_INLINE __m128 _mm_mul_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(a, _mm_mul_ps(a, b));
+}
+
+// Multiply the low unsigned 32-bit integers from each packed 64-bit element in
+// a and b, and store the unsigned 64-bit results in dst.
+//
+// r0 := (a0 & 0xFFFFFFFF) * (b0 & 0xFFFFFFFF)
+// r1 := (a2 & 0xFFFFFFFF) * (b2 & 0xFFFFFFFF)
+FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b)
+{
+ // vmull_u32 upcasts instead of masking, so we downcast.
+ uint32x2_t a_lo = vmovn_u64(vreinterpretq_u64_m128i(a));
+ uint32x2_t b_lo = vmovn_u64(vreinterpretq_u64_m128i(b));
+ return vreinterpretq_m128i_u64(vmull_u32(a_lo, b_lo));
+}
+
+// Multiply the low unsigned 32-bit integers from a and b, and store the
+// unsigned 64-bit result in dst.
+//
+// dst[63:0] := a[31:0] * b[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_su32
+FORCE_INLINE __m64 _mm_mul_su32(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_u64(vget_low_u64(
+ vmull_u32(vreinterpret_u32_m64(a), vreinterpret_u32_m64(b))));
+}
+
+// Multiply the low signed 32-bit integers from each packed 64-bit element in
+// a and b, and store the signed 64-bit results in dst.
+//
+// r0 := (int64_t)(int32_t)a0 * (int64_t)(int32_t)b0
+// r1 := (int64_t)(int32_t)a2 * (int64_t)(int32_t)b2
+FORCE_INLINE __m128i _mm_mul_epi32(__m128i a, __m128i b)
+{
+ // vmull_s32 upcasts instead of masking, so we downcast.
+ int32x2_t a_lo = vmovn_s64(vreinterpretq_s64_m128i(a));
+ int32x2_t b_lo = vmovn_s64(vreinterpretq_s64_m128i(b));
+ return vreinterpretq_m128i_s64(vmull_s32(a_lo, b_lo));
+}
+
+// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit
+// integers from b.
+//
+// r0 := (a0 * b0) + (a1 * b1)
+// r1 := (a2 * b2) + (a3 * b3)
+// r2 := (a4 * b4) + (a5 * b5)
+// r3 := (a6 * b6) + (a7 * b7)
+// https://msdn.microsoft.com/en-us/library/yht36sa6(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b)
+{
+ int32x4_t low = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)),
+ vget_low_s16(vreinterpretq_s16_m128i(b)));
+ int32x4_t high = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)),
+ vget_high_s16(vreinterpretq_s16_m128i(b)));
+
+ int32x2_t low_sum = vpadd_s32(vget_low_s32(low), vget_high_s32(low));
+ int32x2_t high_sum = vpadd_s32(vget_low_s32(high), vget_high_s32(high));
+
+ return vreinterpretq_m128i_s32(vcombine_s32(low_sum, high_sum));
+}
+
+// Multiply packed signed 16-bit integers in a and b, producing intermediate
+// signed 32-bit integers. Shift right by 15 bits while rounding up, and store
+// the packed 16-bit integers in dst.
+//
+// r0 := Round(((int32_t)a0 * (int32_t)b0) >> 15)
+// r1 := Round(((int32_t)a1 * (int32_t)b1) >> 15)
+// r2 := Round(((int32_t)a2 * (int32_t)b2) >> 15)
+// ...
+// r7 := Round(((int32_t)a7 * (int32_t)b7) >> 15)
+FORCE_INLINE __m128i _mm_mulhrs_epi16(__m128i a, __m128i b)
+{
+ // Has issues due to saturation
+ // return vreinterpretq_m128i_s16(vqrdmulhq_s16(a, b));
+
+ // Multiply
+ int32x4_t mul_lo = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)),
+ vget_low_s16(vreinterpretq_s16_m128i(b)));
+ int32x4_t mul_hi = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)),
+ vget_high_s16(vreinterpretq_s16_m128i(b)));
+
+ // Rounding narrowing shift right
+ // narrow = (int16_t)((mul + 16384) >> 15);
+ int16x4_t narrow_lo = vrshrn_n_s32(mul_lo, 15);
+ int16x4_t narrow_hi = vrshrn_n_s32(mul_hi, 15);
+
+ // Join together
+ return vreinterpretq_m128i_s16(vcombine_s16(narrow_lo, narrow_hi));
+}
+
+// Vertically multiply each unsigned 8-bit integer from a with the corresponding
+// signed 8-bit integer from b, producing intermediate signed 16-bit integers.
+// Horizontally add adjacent pairs of intermediate signed 16-bit integers,
+// and pack the saturated results in dst.
+//
+// FOR j := 0 to 7
+// i := j*16
+// dst[i+15:i] := Saturate_To_Int16( a[i+15:i+8]*b[i+15:i+8] +
+// a[i+7:i]*b[i+7:i] )
+// ENDFOR
+FORCE_INLINE __m128i _mm_maddubs_epi16(__m128i _a, __m128i _b)
+{
+#if defined(__aarch64__)
+ uint8x16_t a = vreinterpretq_u8_m128i(_a);
+ int8x16_t b = vreinterpretq_s8_m128i(_b);
+ int16x8_t tl = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(a))),
+ vmovl_s8(vget_low_s8(b)));
+ int16x8_t th = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(a))),
+ vmovl_s8(vget_high_s8(b)));
+ return vreinterpretq_m128i_s16(
+ vqaddq_s16(vuzp1q_s16(tl, th), vuzp2q_s16(tl, th)));
+#else
+ // This would be much simpler if x86 would choose to zero extend OR sign
+ // extend, not both. This could probably be optimized better.
+ uint16x8_t a = vreinterpretq_u16_m128i(_a);
+ int16x8_t b = vreinterpretq_s16_m128i(_b);
+
+ // Zero extend a
+ int16x8_t a_odd = vreinterpretq_s16_u16(vshrq_n_u16(a, 8));
+ int16x8_t a_even = vreinterpretq_s16_u16(vbicq_u16(a, vdupq_n_u16(0xff00)));
+
+ // Sign extend by shifting left then shifting right.
+ int16x8_t b_even = vshrq_n_s16(vshlq_n_s16(b, 8), 8);
+ int16x8_t b_odd = vshrq_n_s16(b, 8);
+
+ // multiply
+ int16x8_t prod1 = vmulq_s16(a_even, b_even);
+ int16x8_t prod2 = vmulq_s16(a_odd, b_odd);
+
+ // saturated add
+ return vreinterpretq_m128i_s16(vqaddq_s16(prod1, prod2));
+#endif
+}
+
+// Computes the fused multiple add product of 32-bit floating point numbers.
+//
+// Return Value
+// Multiplies A and B, and adds C to the temporary result before returning it.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd
+FORCE_INLINE __m128 _mm_fmadd_ps(__m128 a, __m128 b, __m128 c)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128_f32(vfmaq_f32(vreinterpretq_f32_m128(c),
+ vreinterpretq_f32_m128(b),
+ vreinterpretq_f32_m128(a)));
+#else
+ return _mm_add_ps(_mm_mul_ps(a, b), c);
+#endif
+}
+
+// Alternatively add and subtract packed single-precision (32-bit)
+// floating-point elements in a to/from packed elements in b, and store the
+// results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=addsub_ps
+FORCE_INLINE __m128 _mm_addsub_ps(__m128 a, __m128 b)
+{
+ __m128 mask = {-1.0f, 1.0f, -1.0f, 1.0f};
+ return _mm_fmadd_ps(b, mask, a);
+}
+
+// Horizontally add adjacent pairs of double-precision (64-bit) floating-point
+// elements in a and b, and pack the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pd
+FORCE_INLINE __m128d _mm_hadd_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vpaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+ double *da = (double *) &a;
+ double *db = (double *) &b;
+ double c[] = {da[0] + da[1], db[0] + db[1]};
+ return vreinterpretq_m128d_u64(vld1q_u64((uint64_t *) c));
+#endif
+}
+
+// Compute the absolute differences of packed unsigned 8-bit integers in a and
+// b, then horizontally sum each consecutive 8 differences to produce two
+// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low
+// 16 bits of 64-bit elements in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_epu8
+FORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b)
+{
+ uint16x8_t t = vpaddlq_u8(vabdq_u8((uint8x16_t) a, (uint8x16_t) b));
+ uint16_t r0 = t[0] + t[1] + t[2] + t[3];
+ uint16_t r4 = t[4] + t[5] + t[6] + t[7];
+ uint16x8_t r = vsetq_lane_u16(r0, vdupq_n_u16(0), 0);
+ return (__m128i) vsetq_lane_u16(r4, r, 4);
+}
+
+// Compute the absolute differences of packed unsigned 8-bit integers in a and
+// b, then horizontally sum each consecutive 8 differences to produce four
+// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low
+// 16 bits of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_pu8
+FORCE_INLINE __m64 _mm_sad_pu8(__m64 a, __m64 b)
+{
+ uint16x4_t t =
+ vpaddl_u8(vabd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b)));
+ uint16_t r0 = t[0] + t[1] + t[2] + t[3];
+ return vreinterpret_m64_u16(vset_lane_u16(r0, vdup_n_u16(0), 0));
+}
+
+// Compute the absolute differences of packed unsigned 8-bit integers in a and
+// b, then horizontally sum each consecutive 8 differences to produce four
+// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low
+// 16 bits of dst.
+//
+// FOR j := 0 to 7
+// i := j*8
+// tmp[i+7:i] := ABS(a[i+7:i] - b[i+7:i])
+// ENDFOR
+// dst[15:0] := tmp[7:0] + tmp[15:8] + tmp[23:16] + tmp[31:24] + tmp[39:32] +
+// tmp[47:40] + tmp[55:48] + tmp[63:56] dst[63:16] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_psadbw
+#define _m_psadbw(a, b) _mm_sad_pu8(a, b)
+
+// Divides the four single-precision, floating-point values of a and b.
+//
+// r0 := a0 / b0
+// r1 := a1 / b1
+// r2 := a2 / b2
+// r3 := a3 / b3
+//
+// https://msdn.microsoft.com/en-us/library/edaw8147(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b)
+{
+#if defined(__aarch64__) && !SSE2NEON_PRECISE_DIV
+ return vreinterpretq_m128_f32(
+ vdivq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#else
+ float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(b));
+ recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(b)));
+#if SSE2NEON_PRECISE_DIV
+ // Additional Netwon-Raphson iteration for accuracy
+ recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(b)));
+#endif
+ return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(a), recip));
+#endif
+}
+
+// Divides the scalar single-precision floating point value of a by b.
+// https://msdn.microsoft.com/en-us/library/4y73xa49(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b)
+{
+ float32_t value =
+ vgetq_lane_f32(vreinterpretq_f32_m128(_mm_div_ps(a, b)), 0);
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));
+}
+
+// Divide packed double-precision (64-bit) floating-point elements in a by
+// packed elements in b, and store the results in dst.
+//
+// FOR j := 0 to 1
+// i := 64*j
+// dst[i+63:i] := a[i+63:i] / b[i+63:i]
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_pd
+FORCE_INLINE __m128d _mm_div_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vdivq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+ double *da = (double *) &a;
+ double *db = (double *) &b;
+ double c[2];
+ c[0] = da[0] / db[0];
+ c[1] = da[1] / db[1];
+ return vld1q_f32((float32_t *) c);
+#endif
+}
+
+// Divide the lower double-precision (64-bit) floating-point element in a by the
+// lower double-precision (64-bit) floating-point element in b, store the result
+// in the lower element of dst, and copy the upper element from a to the upper
+// element of dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_sd
+FORCE_INLINE __m128d _mm_div_sd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+ float64x2_t tmp =
+ vdivq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b));
+ return vreinterpretq_m128d_f64(
+ vsetq_lane_f64(vgetq_lane_f64(vreinterpretq_f64_m128d(a), 1), tmp, 1));
+#else
+ return _mm_move_sd(a, _mm_div_pd(a, b));
+#endif
+}
+
+// Compute the approximate reciprocal of packed single-precision (32-bit)
+// floating-point elements in a, and store the results in dst. The maximum
+// relative error for this approximation is less than 1.5*2^-12.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ps
+FORCE_INLINE __m128 _mm_rcp_ps(__m128 in)
+{
+ float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in));
+ recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in)));
+#if SSE2NEON_PRECISE_DIV
+ // Additional Netwon-Raphson iteration for accuracy
+ recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in)));
+#endif
+ return vreinterpretq_m128_f32(recip);
+}
+
+// Compute the approximate reciprocal of the lower single-precision (32-bit)
+// floating-point element in a, store the result in the lower element of dst,
+// and copy the upper 3 packed elements from a to the upper elements of dst. The
+// maximum relative error for this approximation is less than 1.5*2^-12.
+//
+// dst[31:0] := (1.0 / a[31:0])
+// dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ss
+FORCE_INLINE __m128 _mm_rcp_ss(__m128 a)
+{
+ return _mm_move_ss(a, _mm_rcp_ps(a));
+}
+
+// Computes the approximations of square roots of the four single-precision,
+// floating-point values of a. First computes reciprocal square roots and then
+// reciprocals of the four values.
+//
+// r0 := sqrt(a0)
+// r1 := sqrt(a1)
+// r2 := sqrt(a2)
+// r3 := sqrt(a3)
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/8z67bwwk(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sqrt_ps(__m128 in)
+{
+#if SSE2NEON_PRECISE_SQRT
+ float32x4_t recip = vrsqrteq_f32(vreinterpretq_f32_m128(in));
+
+ // Test for vrsqrteq_f32(0) -> positive infinity case.
+ // Change to zero, so that s * 1/sqrt(s) result is zero too.
+ const uint32x4_t pos_inf = vdupq_n_u32(0x7F800000);
+ const uint32x4_t div_by_zero =
+ vceqq_u32(pos_inf, vreinterpretq_u32_f32(recip));
+ recip = vreinterpretq_f32_u32(
+ vandq_u32(vmvnq_u32(div_by_zero), vreinterpretq_u32_f32(recip)));
+
+ // Additional Netwon-Raphson iteration for accuracy
+ recip = vmulq_f32(
+ vrsqrtsq_f32(vmulq_f32(recip, recip), vreinterpretq_f32_m128(in)),
+ recip);
+ recip = vmulq_f32(
+ vrsqrtsq_f32(vmulq_f32(recip, recip), vreinterpretq_f32_m128(in)),
+ recip);
+
+ // sqrt(s) = s * 1/sqrt(s)
+ return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(in), recip));
+#elif defined(__aarch64__)
+ return vreinterpretq_m128_f32(vsqrtq_f32(vreinterpretq_f32_m128(in)));
+#else
+ float32x4_t recipsq = vrsqrteq_f32(vreinterpretq_f32_m128(in));
+ float32x4_t sq = vrecpeq_f32(recipsq);
+ return vreinterpretq_m128_f32(sq);
+#endif
+}
+
+// Computes the approximation of the square root of the scalar single-precision
+// floating point value of in.
+// https://msdn.microsoft.com/en-us/library/ahfsc22d(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_sqrt_ss(__m128 in)
+{
+ float32_t value =
+ vgetq_lane_f32(vreinterpretq_f32_m128(_mm_sqrt_ps(in)), 0);
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32(value, vreinterpretq_f32_m128(in), 0));
+}
+
+// Computes the approximations of the reciprocal square roots of the four
+// single-precision floating point values of in.
+// https://msdn.microsoft.com/en-us/library/22hfsh53(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in)
+{
+ float32x4_t out = vrsqrteq_f32(vreinterpretq_f32_m128(in));
+#if SSE2NEON_PRECISE_RSQRT
+ // Additional Netwon-Raphson iteration for accuracy
+ out = vmulq_f32(
+ out, vrsqrtsq_f32(vmulq_f32(vreinterpretq_f32_m128(in), out), out));
+ out = vmulq_f32(
+ out, vrsqrtsq_f32(vmulq_f32(vreinterpretq_f32_m128(in), out), out));
+#endif
+ return vreinterpretq_m128_f32(out);
+}
+
+// Compute the approximate reciprocal square root of the lower single-precision
+// (32-bit) floating-point element in a, store the result in the lower element
+// of dst, and copy the upper 3 packed elements from a to the upper elements of
+// dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt_ss
+FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 in)
+{
+ return vsetq_lane_f32(vgetq_lane_f32(_mm_rsqrt_ps(in), 0), in, 0);
+}
+
+// Compare packed signed 16-bit integers in a and b, and store packed maximum
+// values in dst.
+//
+// FOR j := 0 to 3
+// i := j*16
+// dst[i+15:i] := MAX(a[i+15:i], b[i+15:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16
+FORCE_INLINE __m64 _mm_max_pi16(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_s16(
+ vmax_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b)));
+}
+
+// Compare packed signed 16-bit integers in a and b, and store packed maximum
+// values in dst.
+//
+// FOR j := 0 to 3
+// i := j*16
+// dst[i+15:i] := MAX(a[i+15:i], b[i+15:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16
+#define _m_pmaxsw(a, b) _mm_max_pi16(a, b)
+
+// Computes the maximums of the four single-precision, floating-point values of
+// a and b.
+// https://msdn.microsoft.com/en-us/library/vstudio/ff5d607a(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b)
+{
+#if SSE2NEON_PRECISE_MINMAX
+ float32x4_t _a = vreinterpretq_f32_m128(a);
+ float32x4_t _b = vreinterpretq_f32_m128(b);
+ return vbslq_f32(vcltq_f32(_b, _a), _a, _b);
+#else
+ return vreinterpretq_m128_f32(
+ vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#endif
+}
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed maximum
+// values in dst.
+//
+// FOR j := 0 to 7
+// i := j*8
+// dst[i+7:i] := MAX(a[i+7:i], b[i+7:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8
+FORCE_INLINE __m64 _mm_max_pu8(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_u8(
+ vmax_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b)));
+}
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed maximum
+// values in dst.
+//
+// FOR j := 0 to 7
+// i := j*8
+// dst[i+7:i] := MAX(a[i+7:i], b[i+7:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8
+#define _m_pmaxub(a, b) _mm_max_pu8(a, b)
+
+// Compare packed signed 16-bit integers in a and b, and store packed minimum
+// values in dst.
+//
+// FOR j := 0 to 3
+// i := j*16
+// dst[i+15:i] := MIN(a[i+15:i], b[i+15:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16
+FORCE_INLINE __m64 _mm_min_pi16(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_s16(
+ vmin_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b)));
+}
+
+// Compare packed signed 16-bit integers in a and b, and store packed minimum
+// values in dst.
+//
+// FOR j := 0 to 3
+// i := j*16
+// dst[i+15:i] := MIN(a[i+15:i], b[i+15:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16
+#define _m_pminsw(a, b) _mm_min_pi16(a, b)
+
+// Computes the minima of the four single-precision, floating-point values of a
+// and b.
+// https://msdn.microsoft.com/en-us/library/vstudio/wh13kadz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b)
+{
+#if SSE2NEON_PRECISE_MINMAX
+ float32x4_t _a = vreinterpretq_f32_m128(a);
+ float32x4_t _b = vreinterpretq_f32_m128(b);
+ return vbslq_f32(vcltq_f32(_a, _b), _a, _b);
+#else
+ return vreinterpretq_m128_f32(
+ vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#endif
+}
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed minimum
+// values in dst.
+//
+// FOR j := 0 to 7
+// i := j*8
+// dst[i+7:i] := MIN(a[i+7:i], b[i+7:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8
+FORCE_INLINE __m64 _mm_min_pu8(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_u8(
+ vmin_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b)));
+}
+
+// Compare packed unsigned 8-bit integers in a and b, and store packed minimum
+// values in dst.
+//
+// FOR j := 0 to 7
+// i := j*8
+// dst[i+7:i] := MIN(a[i+7:i], b[i+7:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8
+#define _m_pminub(a, b) _mm_min_pu8(a, b)
+
+// Computes the maximum of the two lower scalar single-precision floating point
+// values of a and b.
+// https://msdn.microsoft.com/en-us/library/s6db5esz(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b)
+{
+ float32_t value = vgetq_lane_f32(_mm_max_ps(a, b), 0);
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));
+}
+
+// Computes the minimum of the two lower scalar single-precision floating point
+// values of a and b.
+// https://msdn.microsoft.com/en-us/library/0a9y7xaa(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_min_ss(__m128 a, __m128 b)
+{
+ float32_t value = vgetq_lane_f32(_mm_min_ps(a, b), 0);
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0));
+}
+
+// Computes the pairwise maxima of the 16 unsigned 8-bit integers from a and the
+// 16 unsigned 8-bit integers from b.
+// https://msdn.microsoft.com/en-us/library/st6634za(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vmaxq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Computes the pairwise minima of the 16 unsigned 8-bit integers from a and the
+// 16 unsigned 8-bit integers from b.
+// https://msdn.microsoft.com/ko-kr/library/17k8cf58(v=vs.100).aspxx
+FORCE_INLINE __m128i _mm_min_epu8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vminq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)));
+}
+
+// Computes the pairwise minima of the 8 signed 16-bit integers from a and the 8
+// signed 16-bit integers from b.
+// https://msdn.microsoft.com/en-us/library/vstudio/6te997ew(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_min_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vminq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Compare packed signed 8-bit integers in a and b, and store packed maximum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epi8
+FORCE_INLINE __m128i _mm_max_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s8(
+ vmaxq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compare packed unsigned 16-bit integers in a and b, and store packed maximum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu16
+FORCE_INLINE __m128i _mm_max_epu16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vmaxq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));
+}
+
+// Compare packed signed 8-bit integers in a and b, and store packed minimum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epi8
+FORCE_INLINE __m128i _mm_min_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s8(
+ vminq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compare packed unsigned 16-bit integers in a and b, and store packed minimum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epu16
+FORCE_INLINE __m128i _mm_min_epu16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vminq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)));
+}
+
+// Computes the pairwise maxima of the 8 signed 16-bit integers from a and the 8
+// signed 16-bit integers from b.
+// https://msdn.microsoft.com/en-us/LIBRary/3x060h7c(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_max_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vmaxq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// epi versions of min/max
+// Computes the pariwise maximums of the four signed 32-bit integer values of a
+// and b.
+//
+// A 128-bit parameter that can be defined with the following equations:
+// r0 := (a0 > b0) ? a0 : b0
+// r1 := (a1 > b1) ? a1 : b1
+// r2 := (a2 > b2) ? a2 : b2
+// r3 := (a3 > b3) ? a3 : b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/bb514055(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vmaxq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Computes the pariwise minima of the four signed 32-bit integer values of a
+// and b.
+//
+// A 128-bit parameter that can be defined with the following equations:
+// r0 := (a0 < b0) ? a0 : b0
+// r1 := (a1 < b1) ? a1 : b1
+// r2 := (a2 < b2) ? a2 : b2
+// r3 := (a3 < b3) ? a3 : b3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/bb531476(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s32(
+ vminq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compare packed unsigned 32-bit integers in a and b, and store packed maximum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32
+FORCE_INLINE __m128i _mm_max_epu32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u32(
+ vmaxq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b)));
+}
+
+// Compare packed unsigned 32-bit integers in a and b, and store packed minimum
+// values in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32
+FORCE_INLINE __m128i _mm_min_epu32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u32(
+ vminq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b)));
+}
+
+// Multiply the packed unsigned 16-bit integers in a and b, producing
+// intermediate 32-bit integers, and store the high 16 bits of the intermediate
+// integers in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_pu16
+FORCE_INLINE __m64 _mm_mulhi_pu16(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_u16(vshrn_n_u32(
+ vmull_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b)), 16));
+}
+
+// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit
+// integers from b.
+//
+// r0 := (a0 * b0)[31:16]
+// r1 := (a1 * b1)[31:16]
+// ...
+// r7 := (a7 * b7)[31:16]
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/59hddw1d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b)
+{
+ /* FIXME: issue with large values because of result saturation */
+ // int16x8_t ret = vqdmulhq_s16(vreinterpretq_s16_m128i(a),
+ // vreinterpretq_s16_m128i(b)); /* =2*a*b */ return
+ // vreinterpretq_m128i_s16(vshrq_n_s16(ret, 1));
+ int16x4_t a3210 = vget_low_s16(vreinterpretq_s16_m128i(a));
+ int16x4_t b3210 = vget_low_s16(vreinterpretq_s16_m128i(b));
+ int32x4_t ab3210 = vmull_s16(a3210, b3210); /* 3333222211110000 */
+ int16x4_t a7654 = vget_high_s16(vreinterpretq_s16_m128i(a));
+ int16x4_t b7654 = vget_high_s16(vreinterpretq_s16_m128i(b));
+ int32x4_t ab7654 = vmull_s16(a7654, b7654); /* 7777666655554444 */
+ uint16x8x2_t r =
+ vuzpq_u16(vreinterpretq_u16_s32(ab3210), vreinterpretq_u16_s32(ab7654));
+ return vreinterpretq_m128i_u16(r.val[1]);
+}
+
+// Multiply the packed unsigned 16-bit integers in a and b, producing
+// intermediate 32-bit integers, and store the high 16 bits of the intermediate
+// integers in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_epu16
+FORCE_INLINE __m128i _mm_mulhi_epu16(__m128i a, __m128i b)
+{
+ uint16x4_t a3210 = vget_low_u16(vreinterpretq_u16_m128i(a));
+ uint16x4_t b3210 = vget_low_u16(vreinterpretq_u16_m128i(b));
+ uint32x4_t ab3210 = vmull_u16(a3210, b3210);
+#if defined(__aarch64__)
+ uint32x4_t ab7654 =
+ vmull_high_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b));
+ uint16x8_t r = vuzp2q_u16(vreinterpretq_u16_u32(ab3210),
+ vreinterpretq_u16_u32(ab7654));
+ return vreinterpretq_m128i_u16(r);
+#else
+ uint16x4_t a7654 = vget_high_u16(vreinterpretq_u16_m128i(a));
+ uint16x4_t b7654 = vget_high_u16(vreinterpretq_u16_m128i(b));
+ uint32x4_t ab7654 = vmull_u16(a7654, b7654);
+ uint16x8x2_t r =
+ vuzpq_u16(vreinterpretq_u16_u32(ab3210), vreinterpretq_u16_u32(ab7654));
+ return vreinterpretq_m128i_u16(r.val[1]);
+#endif
+}
+
+// Computes pairwise add of each argument as single-precision, floating-point
+// values a and b.
+// https://msdn.microsoft.com/en-us/library/yd9wecaa.aspx
+FORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128_f32(
+ vpaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#else
+ float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a));
+ float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b));
+ float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_f32(
+ vcombine_f32(vpadd_f32(a10, a32), vpadd_f32(b10, b32)));
+#endif
+}
+
+// Computes pairwise add of each argument as a 16-bit signed or unsigned integer
+// values a and b.
+FORCE_INLINE __m128i _mm_hadd_epi16(__m128i _a, __m128i _b)
+{
+ int16x8_t a = vreinterpretq_s16_m128i(_a);
+ int16x8_t b = vreinterpretq_s16_m128i(_b);
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_s16(vpaddq_s16(a, b));
+#else
+ return vreinterpretq_m128i_s16(
+ vcombine_s16(vpadd_s16(vget_low_s16(a), vget_high_s16(a)),
+ vpadd_s16(vget_low_s16(b), vget_high_s16(b))));
+#endif
+}
+
+// Horizontally substract adjacent pairs of single-precision (32-bit)
+// floating-point elements in a and b, and pack the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_ps
+FORCE_INLINE __m128 _mm_hsub_ps(__m128 _a, __m128 _b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128_f32(vsubq_f32(
+ vuzp1q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)),
+ vuzp2q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b))));
+#else
+ float32x4x2_t c =
+ vuzpq_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b));
+ return vreinterpretq_m128_f32(vsubq_f32(c.val[0], c.val[1]));
+#endif
+}
+
+// Horizontally add adjacent pairs of 16-bit integers in a and b, and pack the
+// signed 16-bit results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi16
+FORCE_INLINE __m64 _mm_hadd_pi16(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_s16(
+ vpadd_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b)));
+}
+
+// Horizontally add adjacent pairs of 32-bit integers in a and b, and pack the
+// signed 32-bit results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi32
+FORCE_INLINE __m64 _mm_hadd_pi32(__m64 a, __m64 b)
+{
+ return vreinterpret_m64_s32(
+ vpadd_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b)));
+}
+
+// Computes pairwise difference of each argument as a 16-bit signed or unsigned
+// integer values a and b.
+FORCE_INLINE __m128i _mm_hsub_epi16(__m128i _a, __m128i _b)
+{
+ int32x4_t a = vreinterpretq_s32_m128i(_a);
+ int32x4_t b = vreinterpretq_s32_m128i(_b);
+ // Interleave using vshrn/vmovn
+ // [a0|a2|a4|a6|b0|b2|b4|b6]
+ // [a1|a3|a5|a7|b1|b3|b5|b7]
+ int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b));
+ int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16));
+ // Subtract
+ return vreinterpretq_m128i_s16(vsubq_s16(ab0246, ab1357));
+}
+
+// Computes saturated pairwise sub of each argument as a 16-bit signed
+// integer values a and b.
+FORCE_INLINE __m128i _mm_hadds_epi16(__m128i _a, __m128i _b)
+{
+#if defined(__aarch64__)
+ int16x8_t a = vreinterpretq_s16_m128i(_a);
+ int16x8_t b = vreinterpretq_s16_m128i(_b);
+ return vreinterpretq_s64_s16(
+ vqaddq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b)));
+#else
+ int32x4_t a = vreinterpretq_s32_m128i(_a);
+ int32x4_t b = vreinterpretq_s32_m128i(_b);
+ // Interleave using vshrn/vmovn
+ // [a0|a2|a4|a6|b0|b2|b4|b6]
+ // [a1|a3|a5|a7|b1|b3|b5|b7]
+ int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b));
+ int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16));
+ // Saturated add
+ return vreinterpretq_m128i_s16(vqaddq_s16(ab0246, ab1357));
+#endif
+}
+
+// Computes saturated pairwise difference of each argument as a 16-bit signed
+// integer values a and b.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsubs_epi16
+FORCE_INLINE __m128i _mm_hsubs_epi16(__m128i _a, __m128i _b)
+{
+#if defined(__aarch64__)
+ int16x8_t a = vreinterpretq_s16_m128i(_a);
+ int16x8_t b = vreinterpretq_s16_m128i(_b);
+ return vreinterpretq_s64_s16(
+ vqsubq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b)));
+#else
+ int32x4_t a = vreinterpretq_s32_m128i(_a);
+ int32x4_t b = vreinterpretq_s32_m128i(_b);
+ // Interleave using vshrn/vmovn
+ // [a0|a2|a4|a6|b0|b2|b4|b6]
+ // [a1|a3|a5|a7|b1|b3|b5|b7]
+ int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b));
+ int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16));
+ // Saturated subtract
+ return vreinterpretq_m128i_s16(vqsubq_s16(ab0246, ab1357));
+#endif
+}
+
+// Computes pairwise add of each argument as a 32-bit signed or unsigned integer
+// values a and b.
+FORCE_INLINE __m128i _mm_hadd_epi32(__m128i _a, __m128i _b)
+{
+ int32x4_t a = vreinterpretq_s32_m128i(_a);
+ int32x4_t b = vreinterpretq_s32_m128i(_b);
+ return vreinterpretq_m128i_s32(
+ vcombine_s32(vpadd_s32(vget_low_s32(a), vget_high_s32(a)),
+ vpadd_s32(vget_low_s32(b), vget_high_s32(b))));
+}
+
+// Computes pairwise difference of each argument as a 32-bit signed or unsigned
+// integer values a and b.
+FORCE_INLINE __m128i _mm_hsub_epi32(__m128i _a, __m128i _b)
+{
+ int64x2_t a = vreinterpretq_s64_m128i(_a);
+ int64x2_t b = vreinterpretq_s64_m128i(_b);
+ // Interleave using vshrn/vmovn
+ // [a0|a2|b0|b2]
+ // [a1|a2|b1|b3]
+ int32x4_t ab02 = vcombine_s32(vmovn_s64(a), vmovn_s64(b));
+ int32x4_t ab13 = vcombine_s32(vshrn_n_s64(a, 32), vshrn_n_s64(b, 32));
+ // Subtract
+ return vreinterpretq_m128i_s32(vsubq_s32(ab02, ab13));
+}
+
+// Kahan summation for accurate summation of floating-point numbers.
+// http://blog.zachbjornson.com/2019/08/11/fast-float-summation.html
+FORCE_INLINE void _sse2neon_kadd_f32(float *sum, float *c, float y)
+{
+ y -= *c;
+ float t = *sum + y;
+ *c = (t - *sum) - y;
+ *sum = t;
+}
+
+// Conditionally multiply the packed single-precision (32-bit) floating-point
+// elements in a and b using the high 4 bits in imm8, sum the four products,
+// and conditionally store the sum in dst using the low 4 bits of imm.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_dp_ps
+FORCE_INLINE __m128 _mm_dp_ps(__m128 a, __m128 b, const int imm)
+{
+#if defined(__aarch64__)
+ /* shortcuts */
+ if (imm == 0xFF) {
+ return _mm_set1_ps(vaddvq_f32(_mm_mul_ps(a, b)));
+ }
+ if (imm == 0x7F) {
+ float32x4_t m = _mm_mul_ps(a, b);
+ m[3] = 0;
+ return _mm_set1_ps(vaddvq_f32(m));
+ }
+#endif
+
+ float s = 0, c = 0;
+ float32x4_t f32a = vreinterpretq_f32_m128(a);
+ float32x4_t f32b = vreinterpretq_f32_m128(b);
+
+ /* To improve the accuracy of floating-point summation, Kahan algorithm
+ * is used for each operation.
+ */
+ if (imm & (1 << 4))
+ _sse2neon_kadd_f32(&s, &c, f32a[0] * f32b[0]);
+ if (imm & (1 << 5))
+ _sse2neon_kadd_f32(&s, &c, f32a[1] * f32b[1]);
+ if (imm & (1 << 6))
+ _sse2neon_kadd_f32(&s, &c, f32a[2] * f32b[2]);
+ if (imm & (1 << 7))
+ _sse2neon_kadd_f32(&s, &c, f32a[3] * f32b[3]);
+ s += c;
+
+ float32x4_t res = {
+ (imm & 0x1) ? s : 0,
+ (imm & 0x2) ? s : 0,
+ (imm & 0x4) ? s : 0,
+ (imm & 0x8) ? s : 0,
+ };
+ return vreinterpretq_m128_f32(res);
+}
+
+/* Compare operations */
+
+// Compares for less than
+// https://msdn.microsoft.com/en-us/library/vstudio/f330yhc8(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmplt_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(
+ vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for less than
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fy94wye7(v=vs.100)
+FORCE_INLINE __m128 _mm_cmplt_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(a, _mm_cmplt_ps(a, b));
+}
+
+// Compares for greater than.
+//
+// r0 := (a0 > b0) ? 0xffffffff : 0x0
+// r1 := (a1 > b1) ? 0xffffffff : 0x0
+// r2 := (a2 > b2) ? 0xffffffff : 0x0
+// r3 := (a3 > b3) ? 0xffffffff : 0x0
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/11dy102s(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(
+ vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for greater than.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/1xyyyy9e(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpgt_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(a, _mm_cmpgt_ps(a, b));
+}
+
+// Compares for greater than or equal.
+// https://msdn.microsoft.com/en-us/library/vstudio/fs813y2t(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpge_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(
+ vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for greater than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/kesh3ddc(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpge_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(a, _mm_cmpge_ps(a, b));
+}
+
+// Compares for less than or equal.
+//
+// r0 := (a0 <= b0) ? 0xffffffff : 0x0
+// r1 := (a1 <= b1) ? 0xffffffff : 0x0
+// r2 := (a2 <= b2) ? 0xffffffff : 0x0
+// r3 := (a3 <= b3) ? 0xffffffff : 0x0
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/1s75w83z(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmple_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(
+ vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for less than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/a7x0hbhw(v=vs.100)
+FORCE_INLINE __m128 _mm_cmple_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(a, _mm_cmple_ps(a, b));
+}
+
+// Compares for equality.
+// https://msdn.microsoft.com/en-us/library/vstudio/36aectz5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+}
+
+// Compares for equality.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/k423z28e(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpeq_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(a, _mm_cmpeq_ps(a, b));
+}
+
+// Compares for inequality.
+// https://msdn.microsoft.com/en-us/library/sf44thbx(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cmpneq_ps(__m128 a, __m128 b)
+{
+ return vreinterpretq_m128_u32(vmvnq_u32(
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))));
+}
+
+// Compares for inequality.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/ekya8fh4(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpneq_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(a, _mm_cmpneq_ps(a, b));
+}
+
+// Compares for not greater than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/wsexys62(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnge_ps(__m128 a, __m128 b)
+{
+ return _mm_cmplt_ps(a, b);
+}
+
+// Compares for not greater than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fk2y80s8(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnge_ss(__m128 a, __m128 b)
+{
+ return _mm_cmplt_ss(a, b);
+}
+
+// Compares for not greater than.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/d0xh7w0s(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpngt_ps(__m128 a, __m128 b)
+{
+ return _mm_cmple_ps(a, b);
+}
+
+// Compares for not greater than.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpngt_ss(__m128 a, __m128 b)
+{
+ return _mm_cmple_ss(a, b);
+}
+
+// Compares for not less than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/6a330kxw(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnle_ps(__m128 a, __m128 b)
+{
+ return _mm_cmpgt_ps(a, b);
+}
+
+// Compares for not less than or equal.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnle_ss(__m128 a, __m128 b)
+{
+ return _mm_cmpgt_ss(a, b);
+}
+
+// Compares for not less than.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/4686bbdw(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnlt_ps(__m128 a, __m128 b)
+{
+ return _mm_cmpge_ps(a, b);
+}
+
+// Compares for not less than.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/56b9z2wf(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpnlt_ss(__m128 a, __m128 b)
+{
+ return _mm_cmpge_ss(a, b);
+}
+
+// Compares the 16 signed or unsigned 8-bit integers in a and the 16 signed or
+// unsigned 8-bit integers in b for equality.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/bz5xk21a(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_cmpeq_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vceqq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compare packed double-precision (64-bit) floating-point elements in a and b
+// for equality, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpeq_pd
+FORCE_INLINE __m128d _mm_cmpeq_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_u64(
+ vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+ // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi)
+ uint32x4_t cmp =
+ vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b));
+ uint32x4_t swapped = vrev64q_u32(cmp);
+ return vreinterpretq_m128d_u32(vandq_u32(cmp, swapped));
+#endif
+}
+
+// Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or
+// unsigned 16-bit integers in b for equality.
+// https://msdn.microsoft.com/en-us/library/2ay060te(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpeq_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vceqq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Compare packed 32-bit integers in a and b for equality, and store the results
+// in dst
+FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u32(
+ vceqq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compare packed 64-bit integers in a and b for equality, and store the results
+// in dst
+FORCE_INLINE __m128i _mm_cmpeq_epi64(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_u64(
+ vceqq_u64(vreinterpretq_u64_m128i(a), vreinterpretq_u64_m128i(b)));
+#else
+ // ARMv7 lacks vceqq_u64
+ // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi)
+ uint32x4_t cmp =
+ vceqq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b));
+ uint32x4_t swapped = vrev64q_u32(cmp);
+ return vreinterpretq_m128i_u32(vandq_u32(cmp, swapped));
+#endif
+}
+
+// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers
+// in b for lesser than.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/9s46csht(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_cmplt_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vcltq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers
+// in b for greater than.
+//
+// r0 := (a0 > b0) ? 0xff : 0x0
+// r1 := (a1 > b1) ? 0xff : 0x0
+// ...
+// r15 := (a15 > b15) ? 0xff : 0x0
+//
+// https://msdn.microsoft.com/zh-tw/library/wf45zt2b(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpgt_epi8(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vcgtq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+}
+
+// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers
+// in b for less than.
+//
+// r0 := (a0 < b0) ? 0xffff : 0x0
+// r1 := (a1 < b1) ? 0xffff : 0x0
+// ...
+// r7 := (a7 < b7) ? 0xffff : 0x0
+//
+// https://technet.microsoft.com/en-us/library/t863edb2(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmplt_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vcltq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers
+// in b for greater than.
+//
+// r0 := (a0 > b0) ? 0xffff : 0x0
+// r1 := (a1 > b1) ? 0xffff : 0x0
+// ...
+// r7 := (a7 > b7) ? 0xffff : 0x0
+//
+// https://technet.microsoft.com/en-us/library/xd43yfsa(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpgt_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vcgtq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+}
+
+
+// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers
+// in b for less than.
+// https://msdn.microsoft.com/en-us/library/vstudio/4ak0bf5d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u32(
+ vcltq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers
+// in b for greater than.
+// https://msdn.microsoft.com/en-us/library/vstudio/1s9f2z0y(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u32(
+ vcgtq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+}
+
+// Compares the 2 signed 64-bit integers in a and the 2 signed 64-bit integers
+// in b for greater than.
+FORCE_INLINE __m128i _mm_cmpgt_epi64(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_u64(
+ vcgtq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b)));
+#else
+ // ARMv7 lacks vcgtq_s64.
+ // This is based off of Clang's SSE2 polyfill:
+ // (a > b) -> ((a_hi > b_hi) || (a_lo > b_lo && a_hi == b_hi))
+
+ // Mask the sign bit out since we need a signed AND an unsigned comparison
+ // and it is ugly to try and split them.
+ int32x4_t mask = vreinterpretq_s32_s64(vdupq_n_s64(0x80000000ull));
+ int32x4_t a_mask = veorq_s32(vreinterpretq_s32_m128i(a), mask);
+ int32x4_t b_mask = veorq_s32(vreinterpretq_s32_m128i(b), mask);
+ // Check if a > b
+ int64x2_t greater = vreinterpretq_s64_u32(vcgtq_s32(a_mask, b_mask));
+ // Copy upper mask to lower mask
+ // a_hi > b_hi
+ int64x2_t gt_hi = vshrq_n_s64(greater, 63);
+ // Copy lower mask to upper mask
+ // a_lo > b_lo
+ int64x2_t gt_lo = vsliq_n_s64(greater, greater, 32);
+ // Compare for equality
+ int64x2_t equal = vreinterpretq_s64_u32(vceqq_s32(a_mask, b_mask));
+ // Copy upper mask to lower mask
+ // a_hi == b_hi
+ int64x2_t eq_hi = vshrq_n_s64(equal, 63);
+ // a_hi > b_hi || (a_lo > b_lo && a_hi == b_hi)
+ int64x2_t ret = vorrq_s64(gt_hi, vandq_s64(gt_lo, eq_hi));
+ return vreinterpretq_m128i_s64(ret);
+#endif
+}
+
+// Compares the four 32-bit floats in a and b to check if any values are NaN.
+// Ordered compare between each value returns true for "orderable" and false for
+// "not orderable" (NaN).
+// https://msdn.microsoft.com/en-us/library/vstudio/0h9w00fx(v=vs.100).aspx see
+// also:
+// http://stackoverflow.com/questions/8627331/what-does-ordered-unordered-comparison-mean
+// http://stackoverflow.com/questions/29349621/neon-isnanval-intrinsics
+FORCE_INLINE __m128 _mm_cmpord_ps(__m128 a, __m128 b)
+{
+ // Note: NEON does not have ordered compare builtin
+ // Need to compare a eq a and b eq b to check for NaN
+ // Do AND of results to get final
+ uint32x4_t ceqaa =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t ceqbb =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_u32(vandq_u32(ceqaa, ceqbb));
+}
+
+// Compares for ordered.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/343t62da(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpord_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(a, _mm_cmpord_ps(a, b));
+}
+
+// Compares for unordered.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/khy6fk1t(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpunord_ps(__m128 a, __m128 b)
+{
+ uint32x4_t f32a =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t f32b =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ return vreinterpretq_m128_u32(vmvnq_u32(vandq_u32(f32a, f32b)));
+}
+
+// Compares for unordered.
+// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/2as2387b(v=vs.100)
+FORCE_INLINE __m128 _mm_cmpunord_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(a, _mm_cmpunord_ps(a, b));
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a less than operation. :
+// https://msdn.microsoft.com/en-us/library/2kwe606b(v=vs.90).aspx Important
+// note!! The documentation on MSDN is incorrect! If either of the values is a
+// NAN the docs say you will get a one, but in fact, it will return a zero!!
+FORCE_INLINE int _mm_comilt_ss(__m128 a, __m128 b)
+{
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+ uint32x4_t a_lt_b =
+ vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+ return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_lt_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a greater than operation. :
+// https://msdn.microsoft.com/en-us/library/b0738e0t(v=vs.100).aspx
+FORCE_INLINE int _mm_comigt_ss(__m128 a, __m128 b)
+{
+ // return vgetq_lane_u32(vcgtq_f32(vreinterpretq_f32_m128(a),
+ // vreinterpretq_f32_m128(b)), 0);
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+ uint32x4_t a_gt_b =
+ vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+ return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_gt_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a less than or equal operation. :
+// https://msdn.microsoft.com/en-us/library/1w4t7c57(v=vs.90).aspx
+FORCE_INLINE int _mm_comile_ss(__m128 a, __m128 b)
+{
+ // return vgetq_lane_u32(vcleq_f32(vreinterpretq_f32_m128(a),
+ // vreinterpretq_f32_m128(b)), 0);
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+ uint32x4_t a_le_b =
+ vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+ return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_le_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using a greater than or equal operation. :
+// https://msdn.microsoft.com/en-us/library/8t80des6(v=vs.100).aspx
+FORCE_INLINE int _mm_comige_ss(__m128 a, __m128 b)
+{
+ // return vgetq_lane_u32(vcgeq_f32(vreinterpretq_f32_m128(a),
+ // vreinterpretq_f32_m128(b)), 0);
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+ uint32x4_t a_ge_b =
+ vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+ return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_ge_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using an equality operation. :
+// https://msdn.microsoft.com/en-us/library/93yx2h2b(v=vs.100).aspx
+FORCE_INLINE int _mm_comieq_ss(__m128 a, __m128 b)
+{
+ // return vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a),
+ // vreinterpretq_f32_m128(b)), 0);
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan);
+ uint32x4_t a_eq_b =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b));
+ return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_eq_b), 0) != 0) ? 1 : 0;
+}
+
+// Compares the lower single-precision floating point scalar values of a and b
+// using an inequality operation. :
+// https://msdn.microsoft.com/en-us/library/bafh5e0a(v=vs.90).aspx
+FORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b)
+{
+ // return !vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a),
+ // vreinterpretq_f32_m128(b)), 0);
+ uint32x4_t a_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a));
+ uint32x4_t b_not_nan =
+ vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b));
+ uint32x4_t a_or_b_nan = vmvnq_u32(vandq_u32(a_not_nan, b_not_nan));
+ uint32x4_t a_neq_b = vmvnq_u32(
+ vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+ return (vgetq_lane_u32(vorrq_u32(a_or_b_nan, a_neq_b), 0) != 0) ? 1 : 0;
+}
+
+// according to the documentation, these intrinsics behave the same as the
+// non-'u' versions. We'll just alias them here.
+#define _mm_ucomieq_ss _mm_comieq_ss
+#define _mm_ucomige_ss _mm_comige_ss
+#define _mm_ucomigt_ss _mm_comigt_ss
+#define _mm_ucomile_ss _mm_comile_ss
+#define _mm_ucomilt_ss _mm_comilt_ss
+#define _mm_ucomineq_ss _mm_comineq_ss
+
+/* Conversions */
+
+// Convert packed signed 32-bit integers in b to packed single-precision
+// (32-bit) floating-point elements, store the results in the lower 2 elements
+// of dst, and copy the upper 2 packed elements from a to the upper elements of
+// dst.
+//
+// dst[31:0] := Convert_Int32_To_FP32(b[31:0])
+// dst[63:32] := Convert_Int32_To_FP32(b[63:32])
+// dst[95:64] := a[95:64]
+// dst[127:96] := a[127:96]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_pi2ps
+FORCE_INLINE __m128 _mm_cvt_pi2ps(__m128 a, __m64 b)
+{
+ return vreinterpretq_m128_f32(
+ vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)),
+ vget_high_f32(vreinterpretq_f32_m128(a))));
+}
+
+// Convert the signed 32-bit integer b to a single-precision (32-bit)
+// floating-point element, store the result in the lower element of dst, and
+// copy the upper 3 packed elements from a to the upper elements of dst.
+//
+// dst[31:0] := Convert_Int32_To_FP32(b[31:0])
+// dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_si2ss
+FORCE_INLINE __m128 _mm_cvt_si2ss(__m128 a, int b)
+{
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0));
+}
+
+// Convert the signed 32-bit integer b to a single-precision (32-bit)
+// floating-point element, store the result in the lower element of dst, and
+// copy the upper 3 packed elements from a to the upper elements of dst.
+//
+// dst[31:0] := Convert_Int32_To_FP32(b[31:0])
+// dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_ss
+#define _mm_cvtsi32_ss(a, b) _mm_cvt_si2ss(a, b)
+
+// Convert the signed 64-bit integer b to a single-precision (32-bit)
+// floating-point element, store the result in the lower element of dst, and
+// copy the upper 3 packed elements from a to the upper elements of dst.
+//
+// dst[31:0] := Convert_Int64_To_FP32(b[63:0])
+// dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64_ss
+FORCE_INLINE __m128 _mm_cvtsi64_ss(__m128 a, int64_t b)
+{
+ return vreinterpretq_m128_f32(
+ vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0));
+}
+
+// Convert the lower single-precision (32-bit) floating-point element in a to a
+// 32-bit integer, and store the result in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ss2si
+FORCE_INLINE int _mm_cvt_ss2si(__m128 a)
+{
+#if defined(__aarch64__)
+ return vgetq_lane_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a)), 0);
+#else
+ float32_t data = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+ float32_t diff = data - floor(data);
+ if (diff > 0.5)
+ return (int32_t) ceil(data);
+ if (unlikely(diff == 0.5)) {
+ int32_t f = (int32_t) floor(data);
+ int32_t c = (int32_t) ceil(data);
+ return c & 1 ? f : c;
+ }
+ return (int32_t) floor(data);
+#endif
+}
+
+// Convert packed 16-bit integers in a to packed single-precision (32-bit)
+// floating-point elements, and store the results in dst.
+//
+// FOR j := 0 to 3
+// i := j*16
+// m := j*32
+// dst[m+31:m] := Convert_Int16_To_FP32(a[i+15:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi16_ps
+FORCE_INLINE __m128 _mm_cvtpi16_ps(__m64 a)
+{
+ return vreinterpretq_m128_f32(
+ vcvtq_f32_s32(vmovl_s16(vreinterpret_s16_m64(a))));
+}
+
+// Convert packed 32-bit integers in b to packed single-precision (32-bit)
+// floating-point elements, store the results in the lower 2 elements of dst,
+// and copy the upper 2 packed elements from a to the upper elements of dst.
+//
+// dst[31:0] := Convert_Int32_To_FP32(b[31:0])
+// dst[63:32] := Convert_Int32_To_FP32(b[63:32])
+// dst[95:64] := a[95:64]
+// dst[127:96] := a[127:96]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_ps
+FORCE_INLINE __m128 _mm_cvtpi32_ps(__m128 a, __m64 b)
+{
+ return vreinterpretq_m128_f32(
+ vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)),
+ vget_high_f32(vreinterpretq_f32_m128(a))));
+}
+
+// Convert packed signed 32-bit integers in a to packed single-precision
+// (32-bit) floating-point elements, store the results in the lower 2 elements
+// of dst, then covert the packed signed 32-bit integers in b to
+// single-precision (32-bit) floating-point element, and store the results in
+// the upper 2 elements of dst.
+//
+// dst[31:0] := Convert_Int32_To_FP32(a[31:0])
+// dst[63:32] := Convert_Int32_To_FP32(a[63:32])
+// dst[95:64] := Convert_Int32_To_FP32(b[31:0])
+// dst[127:96] := Convert_Int32_To_FP32(b[63:32])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32x2_ps
+FORCE_INLINE __m128 _mm_cvtpi32x2_ps(__m64 a, __m64 b)
+{
+ return vreinterpretq_m128_f32(vcvtq_f32_s32(
+ vcombine_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b))));
+}
+
+// Convert the lower packed 8-bit integers in a to packed single-precision
+// (32-bit) floating-point elements, and store the results in dst.
+//
+// FOR j := 0 to 3
+// i := j*8
+// m := j*32
+// dst[m+31:m] := Convert_Int8_To_FP32(a[i+7:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi8_ps
+FORCE_INLINE __m128 _mm_cvtpi8_ps(__m64 a)
+{
+ return vreinterpretq_m128_f32(vcvtq_f32_s32(
+ vmovl_s16(vget_low_s16(vmovl_s8(vreinterpret_s8_m64(a))))));
+}
+
+// Convert packed unsigned 16-bit integers in a to packed single-precision
+// (32-bit) floating-point elements, and store the results in dst.
+//
+// FOR j := 0 to 3
+// i := j*16
+// m := j*32
+// dst[m+31:m] := Convert_UInt16_To_FP32(a[i+15:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu16_ps
+FORCE_INLINE __m128 _mm_cvtpu16_ps(__m64 a)
+{
+ return vreinterpretq_m128_f32(
+ vcvtq_f32_u32(vmovl_u16(vreinterpret_u16_m64(a))));
+}
+
+// Convert the lower packed unsigned 8-bit integers in a to packed
+// single-precision (32-bit) floating-point elements, and store the results in
+// dst.
+//
+// FOR j := 0 to 3
+// i := j*8
+// m := j*32
+// dst[m+31:m] := Convert_UInt8_To_FP32(a[i+7:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu8_ps
+FORCE_INLINE __m128 _mm_cvtpu8_ps(__m64 a)
+{
+ return vreinterpretq_m128_f32(vcvtq_f32_u32(
+ vmovl_u16(vget_low_u16(vmovl_u8(vreinterpret_u8_m64(a))))));
+}
+
+// Converts the four single-precision, floating-point values of a to signed
+// 32-bit integer values using truncate.
+// https://msdn.microsoft.com/en-us/library/vstudio/1h005y6x(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a)
+{
+ return vreinterpretq_m128i_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)));
+}
+
+// Convert the lower double-precision (64-bit) floating-point element in a to a
+// 64-bit integer with truncation, and store the result in dst.
+//
+// dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64
+FORCE_INLINE int64_t _mm_cvttsd_si64(__m128d a)
+{
+#if defined(__aarch64__)
+ return vgetq_lane_s64(vcvtq_s64_f64(vreinterpretq_f64_m128d(a)), 0);
+#else
+ double ret = *((double *) &a);
+ return (int64_t) ret;
+#endif
+}
+
+// Convert the lower double-precision (64-bit) floating-point element in a to a
+// 64-bit integer with truncation, and store the result in dst.
+//
+// dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64x
+#define _mm_cvttsd_si64x(a) _mm_cvttsd_si64(a)
+
+// Converts the four signed 32-bit integer values of a to single-precision,
+// floating-point values
+// https://msdn.microsoft.com/en-us/library/vstudio/36bwxcx5(v=vs.100).aspx
+FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a)
+{
+ return vreinterpretq_m128_f32(vcvtq_f32_s32(vreinterpretq_s32_m128i(a)));
+}
+
+// Converts the four unsigned 8-bit integers in the lower 16 bits to four
+// unsigned 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepu8_epi16(__m128i a)
+{
+ uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx DCBA */
+ uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0D0C 0B0A */
+ return vreinterpretq_m128i_u16(u16x8);
+}
+
+// Converts the four unsigned 8-bit integers in the lower 32 bits to four
+// unsigned 32-bit integers.
+// https://msdn.microsoft.com/en-us/library/bb531467%28v=vs.100%29.aspx
+FORCE_INLINE __m128i _mm_cvtepu8_epi32(__m128i a)
+{
+ uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx DCBA */
+ uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0D0C 0B0A */
+ uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000D 000C 000B 000A */
+ return vreinterpretq_m128i_u32(u32x4);
+}
+
+// Converts the two unsigned 8-bit integers in the lower 16 bits to two
+// unsigned 64-bit integers.
+FORCE_INLINE __m128i _mm_cvtepu8_epi64(__m128i a)
+{
+ uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx xxBA */
+ uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0x0x 0B0A */
+ uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */
+ uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */
+ return vreinterpretq_m128i_u64(u64x2);
+}
+
+// Converts the four unsigned 8-bit integers in the lower 16 bits to four
+// unsigned 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi8_epi16(__m128i a)
+{
+ int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx DCBA */
+ int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */
+ return vreinterpretq_m128i_s16(s16x8);
+}
+
+// Converts the four unsigned 8-bit integers in the lower 32 bits to four
+// unsigned 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi8_epi32(__m128i a)
+{
+ int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx DCBA */
+ int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */
+ int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000D 000C 000B 000A */
+ return vreinterpretq_m128i_s32(s32x4);
+}
+
+// Converts the two signed 8-bit integers in the lower 32 bits to four
+// signed 64-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi8_epi64(__m128i a)
+{
+ int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx xxBA */
+ int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0x0x 0B0A */
+ int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */
+ int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */
+ return vreinterpretq_m128i_s64(s64x2);
+}
+
+// Converts the four signed 16-bit integers in the lower 64 bits to four signed
+// 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi16_epi32(__m128i a)
+{
+ return vreinterpretq_m128i_s32(
+ vmovl_s16(vget_low_s16(vreinterpretq_s16_m128i(a))));
+}
+
+// Converts the two signed 16-bit integers in the lower 32 bits two signed
+// 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi16_epi64(__m128i a)
+{
+ int16x8_t s16x8 = vreinterpretq_s16_m128i(a); /* xxxx xxxx xxxx 0B0A */
+ int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */
+ int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */
+ return vreinterpretq_m128i_s64(s64x2);
+}
+
+// Converts the four unsigned 16-bit integers in the lower 64 bits to four
+// unsigned 32-bit integers.
+FORCE_INLINE __m128i _mm_cvtepu16_epi32(__m128i a)
+{
+ return vreinterpretq_m128i_u32(
+ vmovl_u16(vget_low_u16(vreinterpretq_u16_m128i(a))));
+}
+
+// Converts the two unsigned 16-bit integers in the lower 32 bits to two
+// unsigned 64-bit integers.
+FORCE_INLINE __m128i _mm_cvtepu16_epi64(__m128i a)
+{
+ uint16x8_t u16x8 = vreinterpretq_u16_m128i(a); /* xxxx xxxx xxxx 0B0A */
+ uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */
+ uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */
+ return vreinterpretq_m128i_u64(u64x2);
+}
+
+// Converts the two unsigned 32-bit integers in the lower 64 bits to two
+// unsigned 64-bit integers.
+FORCE_INLINE __m128i _mm_cvtepu32_epi64(__m128i a)
+{
+ return vreinterpretq_m128i_u64(
+ vmovl_u32(vget_low_u32(vreinterpretq_u32_m128i(a))));
+}
+
+// Converts the two signed 32-bit integers in the lower 64 bits to two signed
+// 64-bit integers.
+FORCE_INLINE __m128i _mm_cvtepi32_epi64(__m128i a)
+{
+ return vreinterpretq_m128i_s64(
+ vmovl_s32(vget_low_s32(vreinterpretq_s32_m128i(a))));
+}
+
+// Converts the four single-precision, floating-point values of a to signed
+// 32-bit integer values.
+//
+// r0 := (int) a0
+// r1 := (int) a1
+// r2 := (int) a2
+// r3 := (int) a3
+//
+// https://msdn.microsoft.com/en-us/library/vstudio/xdc42k5e(v=vs.100).aspx
+// *NOTE*. The default rounding mode on SSE is 'round to even', which ARMv7-A
+// does not support! It is supported on ARMv8-A however.
+FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_s32(vcvtnq_s32_f32(a));
+#else
+ uint32x4_t signmask = vdupq_n_u32(0x80000000);
+ float32x4_t half = vbslq_f32(signmask, vreinterpretq_f32_m128(a),
+ vdupq_n_f32(0.5f)); /* +/- 0.5 */
+ int32x4_t r_normal = vcvtq_s32_f32(vaddq_f32(
+ vreinterpretq_f32_m128(a), half)); /* round to integer: [a + 0.5]*/
+ int32x4_t r_trunc =
+ vcvtq_s32_f32(vreinterpretq_f32_m128(a)); /* truncate to integer: [a] */
+ int32x4_t plusone = vreinterpretq_s32_u32(vshrq_n_u32(
+ vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */
+ int32x4_t r_even = vbicq_s32(vaddq_s32(r_trunc, plusone),
+ vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */
+ float32x4_t delta = vsubq_f32(
+ vreinterpretq_f32_m128(a),
+ vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */
+ uint32x4_t is_delta_half = vceqq_f32(delta, half); /* delta == +/- 0.5 */
+ return vreinterpretq_m128i_s32(vbslq_s32(is_delta_half, r_even, r_normal));
+#endif
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed 16-bit integers, and store the results in dst. Note: this intrinsic
+// will generate 0x7FFF, rather than 0x8000, for input values between 0x7FFF and
+// 0x7FFFFFFF.
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi16
+FORCE_INLINE __m64 _mm_cvtps_pi16(__m128 a)
+{
+ return vreinterpret_m64_s16(
+ vmovn_s32(vreinterpretq_s32_m128i(_mm_cvtps_epi32(a))));
+}
+
+// Copy the lower 32-bit integer in a to dst.
+//
+// dst[31:0] := a[31:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si32
+FORCE_INLINE int _mm_cvtsi128_si32(__m128i a)
+{
+ return vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0);
+}
+
+// Copy the lower 64-bit integer in a to dst.
+//
+// dst[63:0] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64
+FORCE_INLINE int64_t _mm_cvtsi128_si64(__m128i a)
+{
+ return vgetq_lane_s64(vreinterpretq_s64_m128i(a), 0);
+}
+
+// Copy the lower 64-bit integer in a to dst.
+//
+// dst[63:0] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64x
+#define _mm_cvtsi128_si64x(a) _mm_cvtsi128_si64(a)
+
+// Moves 32-bit integer a to the least significant 32 bits of an __m128 object,
+// zero extending the upper bits.
+//
+// r0 := a
+// r1 := 0x0
+// r2 := 0x0
+// r3 := 0x0
+//
+// https://msdn.microsoft.com/en-us/library/ct3539ha%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_cvtsi32_si128(int a)
+{
+ return vreinterpretq_m128i_s32(vsetq_lane_s32(a, vdupq_n_s32(0), 0));
+}
+
+// Moves 64-bit integer a to the least significant 64 bits of an __m128 object,
+// zero extending the upper bits.
+//
+// r0 := a
+// r1 := 0x0
+FORCE_INLINE __m128i _mm_cvtsi64_si128(int64_t a)
+{
+ return vreinterpretq_m128i_s64(vsetq_lane_s64(a, vdupq_n_s64(0), 0));
+}
+
+// Cast vector of type __m128 to type __m128d. This intrinsic is only used for
+// compilation and does not generate any instructions, thus it has zero latency.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castps_pd
+FORCE_INLINE __m128d _mm_castps_pd(__m128 a)
+{
+ return vreinterpretq_m128d_s32(vreinterpretq_s32_m128(a));
+}
+
+// Applies a type cast to reinterpret four 32-bit floating point values passed
+// in as a 128-bit parameter as packed 32-bit integers.
+// https://msdn.microsoft.com/en-us/library/bb514099.aspx
+FORCE_INLINE __m128i _mm_castps_si128(__m128 a)
+{
+ return vreinterpretq_m128i_s32(vreinterpretq_s32_m128(a));
+}
+
+// Cast vector of type __m128i to type __m128d. This intrinsic is only used for
+// compilation and does not generate any instructions, thus it has zero latency.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castsi128_pd
+FORCE_INLINE __m128d _mm_castsi128_pd(__m128i a)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(vreinterpretq_f64_m128i(a));
+#else
+ return vreinterpretq_m128d_f32(vreinterpretq_f32_m128i(a));
+#endif
+}
+
+// Applies a type cast to reinterpret four 32-bit integers passed in as a
+// 128-bit parameter as packed 32-bit floating point values.
+// https://msdn.microsoft.com/en-us/library/bb514029.aspx
+FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a)
+{
+ return vreinterpretq_m128_s32(vreinterpretq_s32_m128i(a));
+}
+
+// Loads 128-bit value. :
+// https://msdn.microsoft.com/en-us/library/atzzad1h(v=vs.80).aspx
+FORCE_INLINE __m128i _mm_load_si128(const __m128i *p)
+{
+ return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p));
+}
+
+// Load a double-precision (64-bit) floating-point element from memory into both
+// elements of dst.
+//
+// dst[63:0] := MEM[mem_addr+63:mem_addr]
+// dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load1_pd
+FORCE_INLINE __m128d _mm_load1_pd(const double *p)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(vld1q_dup_f64(p));
+#else
+ return vreinterpretq_m128d_s64(vdupq_n_s64(*(const int64_t *) p));
+#endif
+}
+
+// Load a double-precision (64-bit) floating-point element from memory into both
+// elements of dst.
+//
+// dst[63:0] := MEM[mem_addr+63:mem_addr]
+// dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd1
+#define _mm_load_pd1 _mm_load1_pd
+
+// Load a double-precision (64-bit) floating-point element from memory into the
+// upper element of dst, and copy the lower element from a to dst. mem_addr does
+// not need to be aligned on any particular boundary.
+//
+// dst[63:0] := a[63:0]
+// dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadh_pd
+FORCE_INLINE __m128d _mm_loadh_pd(__m128d a, const double *p)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vcombine_f64(vget_low_f64(vreinterpretq_f64_m128d(a)), vld1_f64(p)));
+#else
+ return vreinterpretq_m128d_f32(vcombine_f32(
+ vget_low_f32(vreinterpretq_f32_m128d(a)), vld1_f32((const float *) p)));
+#endif
+}
+
+// Load a double-precision (64-bit) floating-point element from memory into both
+// elements of dst.
+//
+// dst[63:0] := MEM[mem_addr+63:mem_addr]
+// dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd1
+#define _mm_load_pd1 _mm_load1_pd
+
+// Load a double-precision (64-bit) floating-point element from memory into both
+// elements of dst.
+//
+// dst[63:0] := MEM[mem_addr+63:mem_addr]
+// dst[127:64] := MEM[mem_addr+63:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loaddup_pd
+#define _mm_loaddup_pd _mm_load1_pd
+
+// Loads 128-bit value. :
+// https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx
+FORCE_INLINE __m128i _mm_loadu_si128(const __m128i *p)
+{
+ return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p));
+}
+
+// Load unaligned 32-bit integer from memory into the first element of dst.
+//
+// dst[31:0] := MEM[mem_addr+31:mem_addr]
+// dst[MAX:32] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si32
+FORCE_INLINE __m128i _mm_loadu_si32(const void *p)
+{
+ return vreinterpretq_m128i_s32(
+ vsetq_lane_s32(*(const int32_t *) p, vdupq_n_s32(0), 0));
+}
+
+// Convert packed double-precision (64-bit) floating-point elements in a to
+// packed single-precision (32-bit) floating-point elements, and store the
+// results in dst.
+//
+// FOR j := 0 to 1
+// i := 32*j
+// k := 64*j
+// dst[i+31:i] := Convert_FP64_To_FP32(a[k+64:k])
+// ENDFOR
+// dst[127:64] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_ps
+FORCE_INLINE __m128 _mm_cvtpd_ps(__m128d a)
+{
+#if defined(__aarch64__)
+ float32x2_t tmp = vcvt_f32_f64(vreinterpretq_f64_m128d(a));
+ return vreinterpretq_m128_f32(vcombine_f32(tmp, vdup_n_f32(0)));
+#else
+ float a0 = (float) ((double *) &a)[0];
+ float a1 = (float) ((double *) &a)[1];
+ return _mm_set_ps(0, 0, a1, a0);
+#endif
+}
+
+// Copy the lower double-precision (64-bit) floating-point element of a to dst.
+//
+// dst[63:0] := a[63:0]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_f64
+FORCE_INLINE double _mm_cvtsd_f64(__m128d a)
+{
+#if defined(__aarch64__)
+ return (double) vgetq_lane_f64(vreinterpretq_f64_m128d(a), 0);
+#else
+ return ((double *) &a)[0];
+#endif
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed double-precision (64-bit) floating-point elements, and store the
+// results in dst.
+//
+// FOR j := 0 to 1
+// i := 64*j
+// k := 32*j
+// dst[i+63:i] := Convert_FP32_To_FP64(a[k+31:k])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pd
+FORCE_INLINE __m128d _mm_cvtps_pd(__m128 a)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vcvt_f64_f32(vget_low_f32(vreinterpretq_f32_m128(a))));
+#else
+ double a0 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 0);
+ double a1 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 1);
+ return _mm_set_pd(a1, a0);
+#endif
+}
+
+// Cast vector of type __m128d to type __m128i. This intrinsic is only used for
+// compilation and does not generate any instructions, thus it has zero latency.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_si128
+FORCE_INLINE __m128i _mm_castpd_si128(__m128d a)
+{
+ return vreinterpretq_m128i_s64(vreinterpretq_s64_m128d(a));
+}
+
+// Cast vector of type __m128d to type __m128. This intrinsic is only used for
+// compilation and does not generate any instructions, thus it has zero latency.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_ps
+FORCE_INLINE __m128 _mm_castpd_ps(__m128d a)
+{
+ return vreinterpretq_m128_s64(vreinterpretq_s64_m128d(a));
+}
+
+// Blend packed single-precision (32-bit) floating-point elements from a and b
+// using mask, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_ps
+FORCE_INLINE __m128 _mm_blendv_ps(__m128 _a, __m128 _b, __m128 _mask)
+{
+ // Use a signed shift right to create a mask with the sign bit
+ uint32x4_t mask =
+ vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_m128(_mask), 31));
+ float32x4_t a = vreinterpretq_f32_m128(_a);
+ float32x4_t b = vreinterpretq_f32_m128(_b);
+ return vreinterpretq_m128_f32(vbslq_f32(mask, b, a));
+}
+
+// Blend packed single-precision (32-bit) floating-point elements from a and b
+// using mask, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blend_ps
+FORCE_INLINE __m128 _mm_blend_ps(__m128 _a, __m128 _b, const char imm8)
+{
+ const uint32_t ALIGN_STRUCT(16)
+ data[4] = {((imm8) & (1 << 0)) ? UINT32_MAX : 0,
+ ((imm8) & (1 << 1)) ? UINT32_MAX : 0,
+ ((imm8) & (1 << 2)) ? UINT32_MAX : 0,
+ ((imm8) & (1 << 3)) ? UINT32_MAX : 0};
+ uint32x4_t mask = vld1q_u32(data);
+ float32x4_t a = vreinterpretq_f32_m128(_a);
+ float32x4_t b = vreinterpretq_f32_m128(_b);
+ return vreinterpretq_m128_f32(vbslq_f32(mask, b, a));
+}
+
+// Blend packed double-precision (64-bit) floating-point elements from a and b
+// using mask, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_pd
+FORCE_INLINE __m128d _mm_blendv_pd(__m128d _a, __m128d _b, __m128d _mask)
+{
+ uint64x2_t mask =
+ vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_m128d(_mask), 63));
+#if defined(__aarch64__)
+ float64x2_t a = vreinterpretq_f64_m128d(_a);
+ float64x2_t b = vreinterpretq_f64_m128d(_b);
+ return vreinterpretq_m128d_f64(vbslq_f64(mask, b, a));
+#else
+ uint64x2_t a = vreinterpretq_u64_m128d(_a);
+ uint64x2_t b = vreinterpretq_u64_m128d(_b);
+ return vreinterpretq_m128d_u64(vbslq_u64(mask, b, a));
+#endif
+}
+
+typedef struct {
+ uint16_t res0;
+ uint8_t res1 : 6;
+ uint8_t bit22 : 1;
+ uint8_t bit23 : 1;
+ uint8_t res2;
+#if defined(__aarch64__)
+ uint32_t res3;
+#endif
+} fpcr_bitfield;
+
+// Macro: Set the rounding mode bits of the MXCSR control and status register to
+// the value in unsigned 32-bit integer a. The rounding mode may contain any of
+// the following flags: _MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP,
+// _MM_ROUND_TOWARD_ZERO
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_SET_ROUNDING_MODE
+FORCE_INLINE void _MM_SET_ROUNDING_MODE(int rounding)
+{
+ union {
+ fpcr_bitfield field;
+#if defined(__aarch64__)
+ uint64_t value;
+#else
+ uint32_t value;
+#endif
+ } r;
+
+#if defined(__aarch64__)
+ asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */
+#else
+ asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */
+#endif
+
+ switch (rounding) {
+ case _MM_ROUND_TOWARD_ZERO:
+ r.field.bit22 = 1;
+ r.field.bit23 = 1;
+ break;
+ case _MM_ROUND_DOWN:
+ r.field.bit22 = 0;
+ r.field.bit23 = 1;
+ break;
+ case _MM_ROUND_UP:
+ r.field.bit22 = 1;
+ r.field.bit23 = 0;
+ break;
+ default: //_MM_ROUND_NEAREST
+ r.field.bit22 = 0;
+ r.field.bit23 = 0;
+ }
+
+#if defined(__aarch64__)
+ asm volatile("msr FPCR, %0" ::"r"(r)); /* write */
+#else
+ asm volatile("vmsr FPSCR, %0" ::"r"(r)); /* write */
+#endif
+}
+
+FORCE_INLINE void _mm_setcsr(unsigned int a)
+{
+ _MM_SET_ROUNDING_MODE(a);
+}
+
+// Round the packed single-precision (32-bit) floating-point elements in a using
+// the rounding parameter, and store the results as packed single-precision
+// floating-point elements in dst.
+// software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_ps
+FORCE_INLINE __m128 _mm_round_ps(__m128 a, int rounding)
+{
+#if defined(__aarch64__)
+ switch (rounding) {
+ case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC):
+ return vreinterpretq_m128_f32(vrndnq_f32(vreinterpretq_f32_m128(a)));
+ case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC):
+ return vreinterpretq_m128_f32(vrndmq_f32(vreinterpretq_f32_m128(a)));
+ case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC):
+ return vreinterpretq_m128_f32(vrndpq_f32(vreinterpretq_f32_m128(a)));
+ case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC):
+ return vreinterpretq_m128_f32(vrndq_f32(vreinterpretq_f32_m128(a)));
+ default: //_MM_FROUND_CUR_DIRECTION
+ return vreinterpretq_m128_f32(vrndiq_f32(vreinterpretq_f32_m128(a)));
+ }
+#else
+ float *v_float = (float *) &a;
+ __m128 zero, neg_inf, pos_inf;
+
+ switch (rounding) {
+ case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC):
+ return _mm_cvtepi32_ps(_mm_cvtps_epi32(a));
+ case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC):
+ return (__m128){floorf(v_float[0]), floorf(v_float[1]),
+ floorf(v_float[2]), floorf(v_float[3])};
+ case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC):
+ return (__m128){ceilf(v_float[0]), ceilf(v_float[1]), ceilf(v_float[2]),
+ ceilf(v_float[3])};
+ case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC):
+ zero = _mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f);
+ neg_inf = _mm_set_ps(floorf(v_float[0]), floorf(v_float[1]),
+ floorf(v_float[2]), floorf(v_float[3]));
+ pos_inf = _mm_set_ps(ceilf(v_float[0]), ceilf(v_float[1]),
+ ceilf(v_float[2]), ceilf(v_float[3]));
+ return _mm_blendv_ps(pos_inf, neg_inf, _mm_cmple_ps(a, zero));
+ default: //_MM_FROUND_CUR_DIRECTION
+ return (__m128){roundf(v_float[0]), roundf(v_float[1]),
+ roundf(v_float[2]), roundf(v_float[3])};
+ }
+#endif
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed 32-bit integers, and store the results in dst.
+//
+// FOR j := 0 to 1
+// i := 32*j
+// dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ps2pi
+FORCE_INLINE __m64 _mm_cvt_ps2pi(__m128 a)
+{
+#if defined(__aarch64__)
+ return vreinterpret_m64_s32(
+ vget_low_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a))));
+#else
+ return vreinterpret_m64_s32(
+ vcvt_s32_f32(vget_low_f32(vreinterpretq_f32_m128(
+ _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)))));
+#endif
+}
+
+// Convert packed single-precision (32-bit) floating-point elements in a to
+// packed 32-bit integers, and store the results in dst.
+//
+// FOR j := 0 to 1
+// i := 32*j
+// dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i])
+// ENDFOR
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi32
+#define _mm_cvtps_pi32(a) _mm_cvt_ps2pi(a)
+
+// Round the packed single-precision (32-bit) floating-point elements in a up to
+// an integer value, and store the results as packed single-precision
+// floating-point elements in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ps
+FORCE_INLINE __m128 _mm_ceil_ps(__m128 a)
+{
+ return _mm_round_ps(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC);
+}
+
+// Round the lower single-precision (32-bit) floating-point element in b up to
+// an integer value, store the result as a single-precision floating-point
+// element in the lower element of dst, and copy the upper 3 packed elements
+// from a to the upper elements of dst.
+//
+// dst[31:0] := CEIL(b[31:0])
+// dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ss
+FORCE_INLINE __m128 _mm_ceil_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(
+ a, _mm_round_ps(b, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC));
+}
+
+// Round the packed single-precision (32-bit) floating-point elements in a down
+// to an integer value, and store the results as packed single-precision
+// floating-point elements in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ps
+FORCE_INLINE __m128 _mm_floor_ps(__m128 a)
+{
+ return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC);
+}
+
+// Round the lower single-precision (32-bit) floating-point element in b down to
+// an integer value, store the result as a single-precision floating-point
+// element in the lower element of dst, and copy the upper 3 packed elements
+// from a to the upper elements of dst.
+//
+// dst[31:0] := FLOOR(b[31:0])
+// dst[127:32] := a[127:32]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ss
+FORCE_INLINE __m128 _mm_floor_ss(__m128 a, __m128 b)
+{
+ return _mm_move_ss(
+ a, _mm_round_ps(b, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC));
+}
+
+// Load 128-bits of integer data from unaligned memory into dst. This intrinsic
+// may perform better than _mm_loadu_si128 when the data crosses a cache line
+// boundary.
+//
+// dst[127:0] := MEM[mem_addr+127:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lddqu_si128
+#define _mm_lddqu_si128 _mm_loadu_si128
+
+/* Miscellaneous Operations */
+
+// Shifts the 8 signed 16-bit integers in a right by count bits while shifting
+// in the sign bit.
+//
+// r0 := a0 >> count
+// r1 := a1 >> count
+// ...
+// r7 := a7 >> count
+//
+// https://msdn.microsoft.com/en-us/library/3c9997dk(v%3dvs.90).aspx
+FORCE_INLINE __m128i _mm_sra_epi16(__m128i a, __m128i count)
+{
+ int64_t c = (int64_t) vget_low_s64((int64x2_t) count);
+ if (unlikely(c > 15))
+ return _mm_cmplt_epi16(a, _mm_setzero_si128());
+ return vreinterpretq_m128i_s16(vshlq_s16((int16x8_t) a, vdupq_n_s16(-c)));
+}
+
+// Shifts the 4 signed 32-bit integers in a right by count bits while shifting
+// in the sign bit.
+//
+// r0 := a0 >> count
+// r1 := a1 >> count
+// r2 := a2 >> count
+// r3 := a3 >> count
+//
+// https://msdn.microsoft.com/en-us/library/ce40009e(v%3dvs.100).aspx
+FORCE_INLINE __m128i _mm_sra_epi32(__m128i a, __m128i count)
+{
+ int64_t c = (int64_t) vget_low_s64((int64x2_t) count);
+ if (unlikely(c > 31))
+ return _mm_cmplt_epi32(a, _mm_setzero_si128());
+ return vreinterpretq_m128i_s32(vshlq_s32((int32x4_t) a, vdupq_n_s32(-c)));
+}
+
+// Packs the 16 signed 16-bit integers from a and b into 8-bit integers and
+// saturates.
+// https://msdn.microsoft.com/en-us/library/k4y4f7w5%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s8(
+ vcombine_s8(vqmovn_s16(vreinterpretq_s16_m128i(a)),
+ vqmovn_s16(vreinterpretq_s16_m128i(b))));
+}
+
+// Packs the 16 signed 16 - bit integers from a and b into 8 - bit unsigned
+// integers and saturates.
+//
+// r0 := UnsignedSaturate(a0)
+// r1 := UnsignedSaturate(a1)
+// ...
+// r7 := UnsignedSaturate(a7)
+// r8 := UnsignedSaturate(b0)
+// r9 := UnsignedSaturate(b1)
+// ...
+// r15 := UnsignedSaturate(b7)
+//
+// https://msdn.microsoft.com/en-us/library/07ad1wx4(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vcombine_u8(vqmovun_s16(vreinterpretq_s16_m128i(a)),
+ vqmovun_s16(vreinterpretq_s16_m128i(b))));
+}
+
+// Packs the 8 signed 32-bit integers from a and b into signed 16-bit integers
+// and saturates.
+//
+// r0 := SignedSaturate(a0)
+// r1 := SignedSaturate(a1)
+// r2 := SignedSaturate(a2)
+// r3 := SignedSaturate(a3)
+// r4 := SignedSaturate(b0)
+// r5 := SignedSaturate(b1)
+// r6 := SignedSaturate(b2)
+// r7 := SignedSaturate(b3)
+//
+// https://msdn.microsoft.com/en-us/library/393t56f9%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_s16(
+ vcombine_s16(vqmovn_s32(vreinterpretq_s32_m128i(a)),
+ vqmovn_s32(vreinterpretq_s32_m128i(b))));
+}
+
+// Packs the 8 unsigned 32-bit integers from a and b into unsigned 16-bit
+// integers and saturates.
+//
+// r0 := UnsignedSaturate(a0)
+// r1 := UnsignedSaturate(a1)
+// r2 := UnsignedSaturate(a2)
+// r3 := UnsignedSaturate(a3)
+// r4 := UnsignedSaturate(b0)
+// r5 := UnsignedSaturate(b1)
+// r6 := UnsignedSaturate(b2)
+// r7 := UnsignedSaturate(b3)
+FORCE_INLINE __m128i _mm_packus_epi32(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u16(
+ vcombine_u16(vqmovun_s32(vreinterpretq_s32_m128i(a)),
+ vqmovun_s32(vreinterpretq_s32_m128i(b))));
+}
+
+// Interleaves the lower 8 signed or unsigned 8-bit integers in a with the lower
+// 8 signed or unsigned 8-bit integers in b.
+//
+// r0 := a0
+// r1 := b0
+// r2 := a1
+// r3 := b1
+// ...
+// r14 := a7
+// r15 := b7
+//
+// https://msdn.microsoft.com/en-us/library/xf7k860c%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_s8(
+ vzip1q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+#else
+ int8x8_t a1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(a)));
+ int8x8_t b1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(b)));
+ int8x8x2_t result = vzip_s8(a1, b1);
+ return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the lower 4 signed or unsigned 16-bit integers in a with the
+// lower 4 signed or unsigned 16-bit integers in b.
+//
+// r0 := a0
+// r1 := b0
+// r2 := a1
+// r3 := b1
+// r4 := a2
+// r5 := b2
+// r6 := a3
+// r7 := b3
+//
+// https://msdn.microsoft.com/en-us/library/btxb17bw%28v=vs.90%29.aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_s16(
+ vzip1q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+#else
+ int16x4_t a1 = vget_low_s16(vreinterpretq_s16_m128i(a));
+ int16x4_t b1 = vget_low_s16(vreinterpretq_s16_m128i(b));
+ int16x4x2_t result = vzip_s16(a1, b1);
+ return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the lower 2 signed or unsigned 32 - bit integers in a with the
+// lower 2 signed or unsigned 32 - bit integers in b.
+//
+// r0 := a0
+// r1 := b0
+// r2 := a1
+// r3 := b1
+//
+// https://msdn.microsoft.com/en-us/library/x8atst9d(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_s32(
+ vzip1q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+#else
+ int32x2_t a1 = vget_low_s32(vreinterpretq_s32_m128i(a));
+ int32x2_t b1 = vget_low_s32(vreinterpretq_s32_m128i(b));
+ int32x2x2_t result = vzip_s32(a1, b1);
+ return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1]));
+#endif
+}
+
+FORCE_INLINE __m128i _mm_unpacklo_epi64(__m128i a, __m128i b)
+{
+ int64x1_t a_l = vget_low_s64(vreinterpretq_s64_m128i(a));
+ int64x1_t b_l = vget_low_s64(vreinterpretq_s64_m128i(b));
+ return vreinterpretq_m128i_s64(vcombine_s64(a_l, b_l));
+}
+
+// Selects and interleaves the lower two single-precision, floating-point values
+// from a and b.
+//
+// r0 := a0
+// r1 := b0
+// r2 := a1
+// r3 := b1
+//
+// https://msdn.microsoft.com/en-us/library/25st103b%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_unpacklo_ps(__m128 a, __m128 b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128_f32(
+ vzip1q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#else
+ float32x2_t a1 = vget_low_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b1 = vget_low_f32(vreinterpretq_f32_m128(b));
+ float32x2x2_t result = vzip_f32(a1, b1);
+ return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1]));
+#endif
+}
+
+// Unpack and interleave double-precision (64-bit) floating-point elements from
+// the low half of a and b, and store the results in dst.
+//
+// DEFINE INTERLEAVE_QWORDS(src1[127:0], src2[127:0]) {
+// dst[63:0] := src1[63:0]
+// dst[127:64] := src2[63:0]
+// RETURN dst[127:0]
+// }
+// dst[127:0] := INTERLEAVE_QWORDS(a[127:0], b[127:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpacklo_pd
+FORCE_INLINE __m128d _mm_unpacklo_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vzip1q_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+ return vreinterpretq_m128d_s64(
+ vcombine_s64(vget_low_s64(vreinterpretq_s64_m128d(a)),
+ vget_low_s64(vreinterpretq_s64_m128d(b))));
+#endif
+}
+
+// Unpack and interleave double-precision (64-bit) floating-point elements from
+// the high half of a and b, and store the results in dst.
+//
+// DEFINE INTERLEAVE_HIGH_QWORDS(src1[127:0], src2[127:0]) {
+// dst[63:0] := src1[127:64]
+// dst[127:64] := src2[127:64]
+// RETURN dst[127:0]
+// }
+// dst[127:0] := INTERLEAVE_HIGH_QWORDS(a[127:0], b[127:0])
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpackhi_pd
+FORCE_INLINE __m128d _mm_unpackhi_pd(__m128d a, __m128d b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128d_f64(
+ vzip2q_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)));
+#else
+ return vreinterpretq_m128d_s64(
+ vcombine_s64(vget_high_s64(vreinterpretq_s64_m128d(a)),
+ vget_high_s64(vreinterpretq_s64_m128d(b))));
+#endif
+}
+
+// Selects and interleaves the upper two single-precision, floating-point values
+// from a and b.
+//
+// r0 := a2
+// r1 := b2
+// r2 := a3
+// r3 := b3
+//
+// https://msdn.microsoft.com/en-us/library/skccxx7d%28v=vs.90%29.aspx
+FORCE_INLINE __m128 _mm_unpackhi_ps(__m128 a, __m128 b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128_f32(
+ vzip2q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)));
+#else
+ float32x2_t a1 = vget_high_f32(vreinterpretq_f32_m128(a));
+ float32x2_t b1 = vget_high_f32(vreinterpretq_f32_m128(b));
+ float32x2x2_t result = vzip_f32(a1, b1);
+ return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the upper 8 signed or unsigned 8-bit integers in a with the upper
+// 8 signed or unsigned 8-bit integers in b.
+//
+// r0 := a8
+// r1 := b8
+// r2 := a9
+// r3 := b9
+// ...
+// r14 := a15
+// r15 := b15
+//
+// https://msdn.microsoft.com/en-us/library/t5h7783k(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_s8(
+ vzip2q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b)));
+#else
+ int8x8_t a1 =
+ vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(a)));
+ int8x8_t b1 =
+ vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(b)));
+ int8x8x2_t result = vzip_s8(a1, b1);
+ return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the upper 4 signed or unsigned 16-bit integers in a with the
+// upper 4 signed or unsigned 16-bit integers in b.
+//
+// r0 := a4
+// r1 := b4
+// r2 := a5
+// r3 := b5
+// r4 := a6
+// r5 := b6
+// r6 := a7
+// r7 := b7
+//
+// https://msdn.microsoft.com/en-us/library/03196cz7(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_s16(
+ vzip2q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)));
+#else
+ int16x4_t a1 = vget_high_s16(vreinterpretq_s16_m128i(a));
+ int16x4_t b1 = vget_high_s16(vreinterpretq_s16_m128i(b));
+ int16x4x2_t result = vzip_s16(a1, b1);
+ return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the upper 2 signed or unsigned 32-bit integers in a with the
+// upper 2 signed or unsigned 32-bit integers in b.
+// https://msdn.microsoft.com/en-us/library/65sa7cbs(v=vs.100).aspx
+FORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b)
+{
+#if defined(__aarch64__)
+ return vreinterpretq_m128i_s32(
+ vzip2q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b)));
+#else
+ int32x2_t a1 = vget_high_s32(vreinterpretq_s32_m128i(a));
+ int32x2_t b1 = vget_high_s32(vreinterpretq_s32_m128i(b));
+ int32x2x2_t result = vzip_s32(a1, b1);
+ return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1]));
+#endif
+}
+
+// Interleaves the upper signed or unsigned 64-bit integer in a with the
+// upper signed or unsigned 64-bit integer in b.
+//
+// r0 := a1
+// r1 := b1
+FORCE_INLINE __m128i _mm_unpackhi_epi64(__m128i a, __m128i b)
+{
+ int64x1_t a_h = vget_high_s64(vreinterpretq_s64_m128i(a));
+ int64x1_t b_h = vget_high_s64(vreinterpretq_s64_m128i(b));
+ return vreinterpretq_m128i_s64(vcombine_s64(a_h, b_h));
+}
+
+// Horizontally compute the minimum amongst the packed unsigned 16-bit integers
+// in a, store the minimum and index in dst, and zero the remaining bits in dst.
+//
+// index[2:0] := 0
+// min[15:0] := a[15:0]
+// FOR j := 0 to 7
+// i := j*16
+// IF a[i+15:i] < min[15:0]
+// index[2:0] := j
+// min[15:0] := a[i+15:i]
+// FI
+// ENDFOR
+// dst[15:0] := min[15:0]
+// dst[18:16] := index[2:0]
+// dst[127:19] := 0
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_minpos_epu16
+FORCE_INLINE __m128i _mm_minpos_epu16(__m128i a)
+{
+ __m128i dst;
+ uint16_t min, idx = 0;
+ // Find the minimum value
+#if defined(__aarch64__)
+ min = vminvq_u16(vreinterpretq_u16_m128i(a));
+#else
+ __m64 tmp;
+ tmp = vreinterpret_m64_u16(
+ vmin_u16(vget_low_u16(vreinterpretq_u16_m128i(a)),
+ vget_high_u16(vreinterpretq_u16_m128i(a))));
+ tmp = vreinterpret_m64_u16(
+ vpmin_u16(vreinterpret_u16_m64(tmp), vreinterpret_u16_m64(tmp)));
+ tmp = vreinterpret_m64_u16(
+ vpmin_u16(vreinterpret_u16_m64(tmp), vreinterpret_u16_m64(tmp)));
+ min = vget_lane_u16(vreinterpret_u16_m64(tmp), 0);
+#endif
+ // Get the index of the minimum value
+ int i;
+ for (i = 0; i < 8; i++) {
+ if (min == vgetq_lane_u16(vreinterpretq_u16_m128i(a), 0)) {
+ idx = (uint16_t) i;
+ break;
+ }
+ a = _mm_srli_si128(a, 2);
+ }
+ // Generate result
+ dst = _mm_setzero_si128();
+ dst = vreinterpretq_m128i_u16(
+ vsetq_lane_u16(min, vreinterpretq_u16_m128i(dst), 0));
+ dst = vreinterpretq_m128i_u16(
+ vsetq_lane_u16(idx, vreinterpretq_u16_m128i(dst), 1));
+ return dst;
+}
+
+// Compute the bitwise AND of 128 bits (representing integer data) in a and b,
+// and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the
+// bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero,
+// otherwise set CF to 0. Return the CF value.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testc_si128
+FORCE_INLINE int _mm_testc_si128(__m128i a, __m128i b)
+{
+ int64x2_t s64 =
+ vandq_s64(vreinterpretq_s64_s32(vmvnq_s32(vreinterpretq_s32_m128i(a))),
+ vreinterpretq_s64_m128i(b));
+ return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1));
+}
+
+// Compute the bitwise AND of 128 bits (representing integer data) in a and b,
+// and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the
+// bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero,
+// otherwise set CF to 0. Return the ZF value.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testz_si128
+FORCE_INLINE int _mm_testz_si128(__m128i a, __m128i b)
+{
+ int64x2_t s64 =
+ vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b));
+ return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1));
+}
+
+// Extracts the selected signed or unsigned 8-bit integer from a and zero
+// extends.
+// FORCE_INLINE int _mm_extract_epi8(__m128i a, __constrange(0,16) int imm)
+#define _mm_extract_epi8(a, imm) vgetq_lane_u8(vreinterpretq_u8_m128i(a), (imm))
+
+// Inserts the least significant 8 bits of b into the selected 8-bit integer
+// of a.
+// FORCE_INLINE __m128i _mm_insert_epi8(__m128i a, int b,
+// __constrange(0,16) int imm)
+#define _mm_insert_epi8(a, b, imm) \
+ __extension__({ \
+ vreinterpretq_m128i_s8( \
+ vsetq_lane_s8((b), vreinterpretq_s8_m128i(a), (imm))); \
+ })
+
+// Extracts the selected signed or unsigned 16-bit integer from a and zero
+// extends.
+// https://msdn.microsoft.com/en-us/library/6dceta0c(v=vs.100).aspx
+// FORCE_INLINE int _mm_extract_epi16(__m128i a, __constrange(0,8) int imm)
+#define _mm_extract_epi16(a, imm) \
+ vgetq_lane_u16(vreinterpretq_u16_m128i(a), (imm))
+
+// Inserts the least significant 16 bits of b into the selected 16-bit integer
+// of a.
+// https://msdn.microsoft.com/en-us/library/kaze8hz1%28v=vs.100%29.aspx
+// FORCE_INLINE __m128i _mm_insert_epi16(__m128i a, int b,
+// __constrange(0,8) int imm)
+#define _mm_insert_epi16(a, b, imm) \
+ __extension__({ \
+ vreinterpretq_m128i_s16( \
+ vsetq_lane_s16((b), vreinterpretq_s16_m128i(a), (imm))); \
+ })
+
+// Copy a to dst, and insert the 16-bit integer i into dst at the location
+// specified by imm8.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_insert_pi16
+#define _mm_insert_pi16(a, b, imm) \
+ __extension__({ \
+ vreinterpret_m64_s16( \
+ vset_lane_s16((b), vreinterpret_s16_m64(a), (imm))); \
+ })
+
+// Extracts the selected signed or unsigned 32-bit integer from a and zero
+// extends.
+// FORCE_INLINE int _mm_extract_epi32(__m128i a, __constrange(0,4) int imm)
+#define _mm_extract_epi32(a, imm) \
+ vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm))
+
+// Extracts the selected single-precision (32-bit) floating-point from a.
+// FORCE_INLINE int _mm_extract_ps(__m128 a, __constrange(0,4) int imm)
+#define _mm_extract_ps(a, imm) vgetq_lane_s32(vreinterpretq_s32_m128(a), (imm))
+
+// Inserts the least significant 32 bits of b into the selected 32-bit integer
+// of a.
+// FORCE_INLINE __m128i _mm_insert_epi32(__m128i a, int b,
+// __constrange(0,4) int imm)
+#define _mm_insert_epi32(a, b, imm) \
+ __extension__({ \
+ vreinterpretq_m128i_s32( \
+ vsetq_lane_s32((b), vreinterpretq_s32_m128i(a), (imm))); \
+ })
+
+// Extracts the selected signed or unsigned 64-bit integer from a and zero
+// extends.
+// FORCE_INLINE __int64 _mm_extract_epi64(__m128i a, __constrange(0,2) int imm)
+#define _mm_extract_epi64(a, imm) \
+ vgetq_lane_s64(vreinterpretq_s64_m128i(a), (imm))
+
+// Inserts the least significant 64 bits of b into the selected 64-bit integer
+// of a.
+// FORCE_INLINE __m128i _mm_insert_epi64(__m128i a, __int64 b,
+// __constrange(0,2) int imm)
+#define _mm_insert_epi64(a, b, imm) \
+ __extension__({ \
+ vreinterpretq_m128i_s64( \
+ vsetq_lane_s64((b), vreinterpretq_s64_m128i(a), (imm))); \
+ })
+
+// Count the number of bits set to 1 in unsigned 32-bit integer a, and
+// return that count in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u32
+FORCE_INLINE int _mm_popcnt_u32(unsigned int a)
+{
+#if defined(__aarch64__)
+#if __has_builtin(__builtin_popcount)
+ return __builtin_popcount(a);
+#else
+ return (int) vaddlv_u8(vcnt_u8(vcreate_u8((uint64_t) a)));
+#endif
+#else
+ uint32_t count = 0;
+ uint8x8_t input_val, count8x8_val;
+ uint16x4_t count16x4_val;
+ uint32x2_t count32x2_val;
+
+ input_val = vld1_u8((uint8_t *) &a);
+ count8x8_val = vcnt_u8(input_val);
+ count16x4_val = vpaddl_u8(count8x8_val);
+ count32x2_val = vpaddl_u16(count16x4_val);
+
+ vst1_u32(&count, count32x2_val);
+ return count;
+#endif
+}
+
+// Count the number of bits set to 1 in unsigned 64-bit integer a, and
+// return that count in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u64
+FORCE_INLINE int64_t _mm_popcnt_u64(uint64_t a)
+{
+#if defined(__aarch64__)
+#if __has_builtin(__builtin_popcountll)
+ return __builtin_popcountll(a);
+#else
+ return (int64_t) vaddlv_u8(vcnt_u8(vcreate_u8(a)));
+#endif
+#else
+ uint64_t count = 0;
+ uint8x8_t input_val, count8x8_val;
+ uint16x4_t count16x4_val;
+ uint32x2_t count32x2_val;
+ uint64x1_t count64x1_val;
+
+ input_val = vld1_u8((uint8_t *) &a);
+ count8x8_val = vcnt_u8(input_val);
+ count16x4_val = vpaddl_u8(count8x8_val);
+ count32x2_val = vpaddl_u16(count16x4_val);
+ count64x1_val = vpaddl_u32(count32x2_val);
+ vst1_u64(&count, count64x1_val);
+ return count;
+#endif
+}
+
+// Macro: Transpose the 4x4 matrix formed by the 4 rows of single-precision
+// (32-bit) floating-point elements in row0, row1, row2, and row3, and store the
+// transposed matrix in these vectors (row0 now contains column 0, etc.).
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=MM_TRANSPOSE4_PS
+#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \
+ do { \
+ float32x4x2_t ROW01 = vtrnq_f32(row0, row1); \
+ float32x4x2_t ROW23 = vtrnq_f32(row2, row3); \
+ row0 = vcombine_f32(vget_low_f32(ROW01.val[0]), \
+ vget_low_f32(ROW23.val[0])); \
+ row1 = vcombine_f32(vget_low_f32(ROW01.val[1]), \
+ vget_low_f32(ROW23.val[1])); \
+ row2 = vcombine_f32(vget_high_f32(ROW01.val[0]), \
+ vget_high_f32(ROW23.val[0])); \
+ row3 = vcombine_f32(vget_high_f32(ROW01.val[1]), \
+ vget_high_f32(ROW23.val[1])); \
+ } while (0)
+
+/* Crypto Extensions */
+
+#if defined(__ARM_FEATURE_CRYPTO)
+// Wraps vmull_p64
+FORCE_INLINE uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b)
+{
+ poly64_t a = vget_lane_p64(vreinterpret_p64_u64(_a), 0);
+ poly64_t b = vget_lane_p64(vreinterpret_p64_u64(_b), 0);
+ return vreinterpretq_u64_p128(vmull_p64(a, b));
+}
+#else // ARMv7 polyfill
+// ARMv7/some A64 lacks vmull_p64, but it has vmull_p8.
+//
+// vmull_p8 calculates 8 8-bit->16-bit polynomial multiplies, but we need a
+// 64-bit->128-bit polynomial multiply.
+//
+// It needs some work and is somewhat slow, but it is still faster than all
+// known scalar methods.
+//
+// Algorithm adapted to C from
+// https://www.workofard.com/2017/07/ghash-for-low-end-cores/, which is adapted
+// from "Fast Software Polynomial Multiplication on ARM Processors Using the
+// NEON Engine" by Danilo Camara, Conrado Gouvea, Julio Lopez and Ricardo Dahab
+// (https://hal.inria.fr/hal-01506572)
+static uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b)
+{
+ poly8x8_t a = vreinterpret_p8_u64(_a);
+ poly8x8_t b = vreinterpret_p8_u64(_b);
+
+ // Masks
+ uint8x16_t k48_32 = vcombine_u8(vcreate_u8(0x0000ffffffffffff),
+ vcreate_u8(0x00000000ffffffff));
+ uint8x16_t k16_00 = vcombine_u8(vcreate_u8(0x000000000000ffff),
+ vcreate_u8(0x0000000000000000));
+
+ // Do the multiplies, rotating with vext to get all combinations
+ uint8x16_t d = vreinterpretq_u8_p16(vmull_p8(a, b)); // D = A0 * B0
+ uint8x16_t e =
+ vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 1))); // E = A0 * B1
+ uint8x16_t f =
+ vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 1), b)); // F = A1 * B0
+ uint8x16_t g =
+ vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 2))); // G = A0 * B2
+ uint8x16_t h =
+ vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 2), b)); // H = A2 * B0
+ uint8x16_t i =
+ vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 3))); // I = A0 * B3
+ uint8x16_t j =
+ vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 3), b)); // J = A3 * B0
+ uint8x16_t k =
+ vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 4))); // L = A0 * B4
+
+ // Add cross products
+ uint8x16_t l = veorq_u8(e, f); // L = E + F
+ uint8x16_t m = veorq_u8(g, h); // M = G + H
+ uint8x16_t n = veorq_u8(i, j); // N = I + J
+
+ // Interleave. Using vzip1 and vzip2 prevents Clang from emitting TBL
+ // instructions.
+#if defined(__aarch64__)
+ uint8x16_t lm_p0 = vreinterpretq_u8_u64(
+ vzip1q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m)));
+ uint8x16_t lm_p1 = vreinterpretq_u8_u64(
+ vzip2q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m)));
+ uint8x16_t nk_p0 = vreinterpretq_u8_u64(
+ vzip1q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k)));
+ uint8x16_t nk_p1 = vreinterpretq_u8_u64(
+ vzip2q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k)));
+#else
+ uint8x16_t lm_p0 = vcombine_u8(vget_low_u8(l), vget_low_u8(m));
+ uint8x16_t lm_p1 = vcombine_u8(vget_high_u8(l), vget_high_u8(m));
+ uint8x16_t nk_p0 = vcombine_u8(vget_low_u8(n), vget_low_u8(k));
+ uint8x16_t nk_p1 = vcombine_u8(vget_high_u8(n), vget_high_u8(k));
+#endif
+ // t0 = (L) (P0 + P1) << 8
+ // t1 = (M) (P2 + P3) << 16
+ uint8x16_t t0t1_tmp = veorq_u8(lm_p0, lm_p1);
+ uint8x16_t t0t1_h = vandq_u8(lm_p1, k48_32);
+ uint8x16_t t0t1_l = veorq_u8(t0t1_tmp, t0t1_h);
+
+ // t2 = (N) (P4 + P5) << 24
+ // t3 = (K) (P6 + P7) << 32
+ uint8x16_t t2t3_tmp = veorq_u8(nk_p0, nk_p1);
+ uint8x16_t t2t3_h = vandq_u8(nk_p1, k16_00);
+ uint8x16_t t2t3_l = veorq_u8(t2t3_tmp, t2t3_h);
+
+ // De-interleave
+#if defined(__aarch64__)
+ uint8x16_t t0 = vreinterpretq_u8_u64(
+ vuzp1q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h)));
+ uint8x16_t t1 = vreinterpretq_u8_u64(
+ vuzp2q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h)));
+ uint8x16_t t2 = vreinterpretq_u8_u64(
+ vuzp1q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h)));
+ uint8x16_t t3 = vreinterpretq_u8_u64(
+ vuzp2q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h)));
+#else
+ uint8x16_t t1 = vcombine_u8(vget_high_u8(t0t1_l), vget_high_u8(t0t1_h));
+ uint8x16_t t0 = vcombine_u8(vget_low_u8(t0t1_l), vget_low_u8(t0t1_h));
+ uint8x16_t t3 = vcombine_u8(vget_high_u8(t2t3_l), vget_high_u8(t2t3_h));
+ uint8x16_t t2 = vcombine_u8(vget_low_u8(t2t3_l), vget_low_u8(t2t3_h));
+#endif
+ // Shift the cross products
+ uint8x16_t t0_shift = vextq_u8(t0, t0, 15); // t0 << 8
+ uint8x16_t t1_shift = vextq_u8(t1, t1, 14); // t1 << 16
+ uint8x16_t t2_shift = vextq_u8(t2, t2, 13); // t2 << 24
+ uint8x16_t t3_shift = vextq_u8(t3, t3, 12); // t3 << 32
+
+ // Accumulate the products
+ uint8x16_t cross1 = veorq_u8(t0_shift, t1_shift);
+ uint8x16_t cross2 = veorq_u8(t2_shift, t3_shift);
+ uint8x16_t mix = veorq_u8(d, cross1);
+ uint8x16_t r = veorq_u8(mix, cross2);
+ return vreinterpretq_u64_u8(r);
+}
+#endif // ARMv7 polyfill
+
+// Perform a carry-less multiplication of two 64-bit integers, selected from a
+// and b according to imm8, and store the results in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_clmulepi64_si128
+FORCE_INLINE __m128i _mm_clmulepi64_si128(__m128i _a, __m128i _b, const int imm)
+{
+ uint64x2_t a = vreinterpretq_u64_m128i(_a);
+ uint64x2_t b = vreinterpretq_u64_m128i(_b);
+ switch (imm & 0x11) {
+ case 0x00:
+ return vreinterpretq_m128i_u64(
+ _sse2neon_vmull_p64(vget_low_u64(a), vget_low_u64(b)));
+ case 0x01:
+ return vreinterpretq_m128i_u64(
+ _sse2neon_vmull_p64(vget_high_u64(a), vget_low_u64(b)));
+ case 0x10:
+ return vreinterpretq_m128i_u64(
+ _sse2neon_vmull_p64(vget_low_u64(a), vget_high_u64(b)));
+ case 0x11:
+ return vreinterpretq_m128i_u64(
+ _sse2neon_vmull_p64(vget_high_u64(a), vget_high_u64(b)));
+ default:
+ abort();
+ }
+}
+
+#if !defined(__ARM_FEATURE_CRYPTO)
+/* clang-format off */
+#define SSE2NEON_AES_DATA(w) \
+ { \
+ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), \
+ w(0xc5), w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), \
+ w(0xab), w(0x76), w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), \
+ w(0x59), w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), \
+ w(0x9c), w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), \
+ w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), \
+ w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), w(0x04), \
+ w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), \
+ w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), \
+ w(0x75), w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), \
+ w(0x5a), w(0xa0), w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), \
+ w(0xe3), w(0x2f), w(0x84), w(0x53), w(0xd1), w(0x00), w(0xed), \
+ w(0x20), w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), \
+ w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), \
+ w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), \
+ w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), \
+ w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), \
+ w(0xf5), w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), \
+ w(0xf3), w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), \
+ w(0x97), w(0x44), w(0x17), w(0xc4), w(0xa7), w(0x7e), w(0x3d), \
+ w(0x64), w(0x5d), w(0x19), w(0x73), w(0x60), w(0x81), w(0x4f), \
+ w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), \
+ w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), \
+ w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), \
+ w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), \
+ w(0x79), w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), \
+ w(0x4e), w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), \
+ w(0x7a), w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), \
+ w(0x1c), w(0xa6), w(0xb4), w(0xc6), w(0xe8), w(0xdd), w(0x74), \
+ w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a), w(0x70), w(0x3e), \
+ w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), \
+ w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), \
+ w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), \
+ w(0x94), w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), \
+ w(0x28), w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), \
+ w(0xe6), w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), \
+ w(0xb0), w(0x54), w(0xbb), w(0x16) \
+ }
+/* clang-format on */
+
+/* X Macro trick. See https://en.wikipedia.org/wiki/X_Macro */
+#define SSE2NEON_AES_H0(x) (x)
+static const uint8_t SSE2NEON_sbox[256] = SSE2NEON_AES_DATA(SSE2NEON_AES_H0);
+#undef SSE2NEON_AES_H0
+
+// In the absence of crypto extensions, implement aesenc using regular neon
+// intrinsics instead. See:
+// https://www.workofard.com/2017/01/accelerated-aes-for-the-arm64-linux-kernel/
+// https://www.workofard.com/2017/07/ghash-for-low-end-cores/ and
+// https://github.com/ColinIanKing/linux-next-mirror/blob/b5f466091e130caaf0735976648f72bd5e09aa84/crypto/aegis128-neon-inner.c#L52
+// for more information Reproduced with permission of the author.
+FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey)
+{
+#if defined(__aarch64__)
+ static const uint8_t shift_rows[] = {0x0, 0x5, 0xa, 0xf, 0x4, 0x9,
+ 0xe, 0x3, 0x8, 0xd, 0x2, 0x7,
+ 0xc, 0x1, 0x6, 0xb};
+ static const uint8_t ror32by8[] = {0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4,
+ 0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc};
+
+ uint8x16_t v;
+ uint8x16_t w = vreinterpretq_u8_m128i(EncBlock);
+
+ // shift rows
+ w = vqtbl1q_u8(w, vld1q_u8(shift_rows));
+
+ // sub bytes
+ v = vqtbl4q_u8(_sse2neon_vld1q_u8_x4(SSE2NEON_sbox), w);
+ v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0x40), w - 0x40);
+ v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0x80), w - 0x80);
+ v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0xc0), w - 0xc0);
+
+ // mix columns
+ w = (v << 1) ^ (uint8x16_t)(((int8x16_t) v >> 7) & 0x1b);
+ w ^= (uint8x16_t) vrev32q_u16((uint16x8_t) v);
+ w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8));
+
+ // add round key
+ return vreinterpretq_m128i_u8(w) ^ RoundKey;
+
+#else /* ARMv7-A NEON implementation */
+#define SSE2NEON_AES_B2W(b0, b1, b2, b3) \
+ (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | \
+ (b0))
+#define SSE2NEON_AES_F2(x) ((x << 1) ^ (((x >> 7) & 1) * 0x011b /* WPOLY */))
+#define SSE2NEON_AES_F3(x) (SSE2NEON_AES_F2(x) ^ x)
+#define SSE2NEON_AES_U0(p) \
+ SSE2NEON_AES_B2W(SSE2NEON_AES_F2(p), p, p, SSE2NEON_AES_F3(p))
+#define SSE2NEON_AES_U1(p) \
+ SSE2NEON_AES_B2W(SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p), p, p)
+#define SSE2NEON_AES_U2(p) \
+ SSE2NEON_AES_B2W(p, SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p), p)
+#define SSE2NEON_AES_U3(p) \
+ SSE2NEON_AES_B2W(p, p, SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p))
+ static const uint32_t ALIGN_STRUCT(16) aes_table[4][256] = {
+ SSE2NEON_AES_DATA(SSE2NEON_AES_U0),
+ SSE2NEON_AES_DATA(SSE2NEON_AES_U1),
+ SSE2NEON_AES_DATA(SSE2NEON_AES_U2),
+ SSE2NEON_AES_DATA(SSE2NEON_AES_U3),
+ };
+#undef SSE2NEON_AES_B2W
+#undef SSE2NEON_AES_F2
+#undef SSE2NEON_AES_F3
+#undef SSE2NEON_AES_U0
+#undef SSE2NEON_AES_U1
+#undef SSE2NEON_AES_U2
+#undef SSE2NEON_AES_U3
+
+ uint32_t x0 = _mm_cvtsi128_si32(EncBlock);
+ uint32_t x1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0x55));
+ uint32_t x2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0xAA));
+ uint32_t x3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0xFF));
+
+ __m128i out = _mm_set_epi32(
+ (aes_table[0][x3 & 0xff] ^ aes_table[1][(x0 >> 8) & 0xff] ^
+ aes_table[2][(x1 >> 16) & 0xff] ^ aes_table[3][x2 >> 24]),
+ (aes_table[0][x2 & 0xff] ^ aes_table[1][(x3 >> 8) & 0xff] ^
+ aes_table[2][(x0 >> 16) & 0xff] ^ aes_table[3][x1 >> 24]),
+ (aes_table[0][x1 & 0xff] ^ aes_table[1][(x2 >> 8) & 0xff] ^
+ aes_table[2][(x3 >> 16) & 0xff] ^ aes_table[3][x0 >> 24]),
+ (aes_table[0][x0 & 0xff] ^ aes_table[1][(x1 >> 8) & 0xff] ^
+ aes_table[2][(x2 >> 16) & 0xff] ^ aes_table[3][x3 >> 24]));
+
+ return _mm_xor_si128(out, RoundKey);
+#endif
+}
+
+// Perform the last round of an AES encryption flow on data (state) in a using
+// the round key in RoundKey, and store the result in dst.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_aesenclast_si128
+FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey)
+{
+ /* FIXME: optimized for NEON */
+ uint8_t v[4][4] = {
+ [0] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 0)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 5)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 10)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 15)]},
+ [1] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 4)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 9)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 14)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 3)]},
+ [2] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 8)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 13)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 2)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 7)]},
+ [3] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 12)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 1)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 6)],
+ SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 11)]},
+ };
+ for (int i = 0; i < 16; i++)
+ vreinterpretq_nth_u8_m128i(a, i) =
+ v[i / 4][i % 4] ^ vreinterpretq_nth_u8_m128i(RoundKey, i);
+ return a;
+}
+
+// Emits the Advanced Encryption Standard (AES) instruction aeskeygenassist.
+// This instruction generates a round key for AES encryption. See
+// https://kazakov.life/2017/11/01/cryptocurrency-mining-on-ios-devices/
+// for details.
+//
+// https://msdn.microsoft.com/en-us/library/cc714138(v=vs.120).aspx
+FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i key, const int rcon)
+{
+ uint32_t X1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0x55));
+ uint32_t X3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0xFF));
+ for (int i = 0; i < 4; ++i) {
+ ((uint8_t *) &X1)[i] = SSE2NEON_sbox[((uint8_t *) &X1)[i]];
+ ((uint8_t *) &X3)[i] = SSE2NEON_sbox[((uint8_t *) &X3)[i]];
+ }
+ return _mm_set_epi32(((X3 >> 8) | (X3 << 24)) ^ rcon, X3,
+ ((X1 >> 8) | (X1 << 24)) ^ rcon, X1);
+}
+#undef SSE2NEON_AES_DATA
+
+#else /* __ARM_FEATURE_CRYPTO */
+// Implements equivalent of 'aesenc' by combining AESE (with an empty key) and
+// AESMC and then manually applying the real key as an xor operation. This
+// unfortunately means an additional xor op; the compiler should be able to
+// optimize this away for repeated calls however. See
+// https://blog.michaelbrase.com/2018/05/08/emulating-x86-aes-intrinsics-on-armv8-a
+// for more details.
+FORCE_INLINE __m128i _mm_aesenc_si128(__m128i a, __m128i b)
+{
+ return vreinterpretq_m128i_u8(
+ vaesmcq_u8(vaeseq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0))) ^
+ vreinterpretq_u8_m128i(b));
+}
+
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_aesenclast_si128
+FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey)
+{
+ return _mm_xor_si128(vreinterpretq_m128i_u8(vaeseq_u8(
+ vreinterpretq_u8_m128i(a), vdupq_n_u8(0))),
+ RoundKey);
+}
+
+FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon)
+{
+ // AESE does ShiftRows and SubBytes on A
+ uint8x16_t u8 = vaeseq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0));
+
+ uint8x16_t dest = {
+ // Undo ShiftRows step from AESE and extract X1 and X3
+ u8[0x4], u8[0x1], u8[0xE], u8[0xB], // SubBytes(X1)
+ u8[0x1], u8[0xE], u8[0xB], u8[0x4], // ROT(SubBytes(X1))
+ u8[0xC], u8[0x9], u8[0x6], u8[0x3], // SubBytes(X3)
+ u8[0x9], u8[0x6], u8[0x3], u8[0xC], // ROT(SubBytes(X3))
+ };
+ uint32x4_t r = {0, (unsigned) rcon, 0, (unsigned) rcon};
+ return vreinterpretq_m128i_u8(dest) ^ vreinterpretq_m128i_u32(r);
+}
+#endif
+
+/* Streaming Extensions */
+
+// Guarantees that every preceding store is globally visible before any
+// subsequent store.
+// https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_sfence(void)
+{
+ __sync_synchronize();
+}
+
+// Store 128-bits (composed of 4 packed single-precision (32-bit) floating-
+// point elements) from a into memory using a non-temporal memory hint.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_ps
+FORCE_INLINE void _mm_stream_ps(float *p, __m128 a)
+{
+#if __has_builtin(__builtin_nontemporal_store)
+ __builtin_nontemporal_store(a, (float32x4_t *) p);
+#else
+ vst1q_f32(p, vreinterpretq_f32_m128(a));
+#endif
+}
+
+// Stores the data in a to the address p without polluting the caches. If the
+// cache line containing address p is already in the cache, the cache will be
+// updated.
+// https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx
+FORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a)
+{
+#if __has_builtin(__builtin_nontemporal_store)
+ __builtin_nontemporal_store(a, p);
+#else
+ vst1q_s64((int64_t *) p, vreinterpretq_s64_m128i(a));
+#endif
+}
+
+// Load 128-bits of integer data from memory into dst using a non-temporal
+// memory hint. mem_addr must be aligned on a 16-byte boundary or a
+// general-protection exception may be generated.
+//
+// dst[127:0] := MEM[mem_addr+127:mem_addr]
+//
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_load_si128
+FORCE_INLINE __m128i _mm_stream_load_si128(__m128i *p)
+{
+#if __has_builtin(__builtin_nontemporal_store)
+ return __builtin_nontemporal_load(p);
+#else
+ return vreinterpretq_m128i_s64(vld1q_s64((int64_t *) p));
+#endif
+}
+
+// Cache line containing p is flushed and invalidated from all caches in the
+// coherency domain. :
+// https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx
+FORCE_INLINE void _mm_clflush(void const *p)
+{
+ (void) p;
+ // no corollary for Neon?
+}
+
+// Allocate aligned blocks of memory.
+// https://software.intel.com/en-us/
+// cpp-compiler-developer-guide-and-reference-allocating-and-freeing-aligned-memory-blocks
+FORCE_INLINE void *_mm_malloc(size_t size, size_t align)
+{
+ void *ptr;
+ if (align == 1)
+ return malloc(size);
+ if (align == 2 || (sizeof(void *) == 8 && align == 4))
+ align = sizeof(void *);
+ if (!posix_memalign(&ptr, align, size))
+ return ptr;
+ return NULL;
+}
+
+// Free aligned memory that was allocated with _mm_malloc.
+// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_free
+FORCE_INLINE void _mm_free(void *addr)
+{
+ free(addr);
+}
+
+// Starting with the initial value in crc, accumulates a CRC32 value for
+// unsigned 8-bit integer v.
+// https://msdn.microsoft.com/en-us/library/bb514036(v=vs.100)
+FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t crc, uint8_t v)
+{
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
+ __asm__ __volatile__("crc32cb %w[c], %w[c], %w[v]\n\t"
+ : [c] "+r"(crc)
+ : [v] "r"(v));
+#else
+ crc ^= v;
+ for (int bit = 0; bit < 8; bit++) {
+ if (crc & 1)
+ crc = (crc >> 1) ^ UINT32_C(0x82f63b78);
+ else
+ crc = (crc >> 1);
+ }
+#endif
+ return crc;
+}
+
+// Starting with the initial value in crc, accumulates a CRC32 value for
+// unsigned 16-bit integer v.
+// https://msdn.microsoft.com/en-us/library/bb531411(v=vs.100)
+FORCE_INLINE uint32_t _mm_crc32_u16(uint32_t crc, uint16_t v)
+{
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
+ __asm__ __volatile__("crc32ch %w[c], %w[c], %w[v]\n\t"
+ : [c] "+r"(crc)
+ : [v] "r"(v));
+#else
+ crc = _mm_crc32_u8(crc, v & 0xff);
+ crc = _mm_crc32_u8(crc, (v >> 8) & 0xff);
+#endif
+ return crc;
+}
+
+// Starting with the initial value in crc, accumulates a CRC32 value for
+// unsigned 32-bit integer v.
+// https://msdn.microsoft.com/en-us/library/bb531394(v=vs.100)
+FORCE_INLINE uint32_t _mm_crc32_u32(uint32_t crc, uint32_t v)
+{
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
+ __asm__ __volatile__("crc32cw %w[c], %w[c], %w[v]\n\t"
+ : [c] "+r"(crc)
+ : [v] "r"(v));
+#else
+ crc = _mm_crc32_u16(crc, v & 0xffff);
+ crc = _mm_crc32_u16(crc, (v >> 16) & 0xffff);
+#endif
+ return crc;
+}
+
+// Starting with the initial value in crc, accumulates a CRC32 value for
+// unsigned 64-bit integer v.
+// https://msdn.microsoft.com/en-us/library/bb514033(v=vs.100)
+FORCE_INLINE uint64_t _mm_crc32_u64(uint64_t crc, uint64_t v)
+{
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
+ __asm__ __volatile__("crc32cx %w[c], %w[c], %x[v]\n\t"
+ : [c] "+r"(crc)
+ : [v] "r"(v));
+#else
+ crc = _mm_crc32_u32((uint32_t)(crc), v & 0xffffffff);
+ crc = _mm_crc32_u32((uint32_t)(crc), (v >> 32) & 0xffffffff);
+#endif
+ return crc;
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma pop_macro("ALIGN_STRUCT")
+#pragma pop_macro("FORCE_INLINE")
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC pop_options
+#endif
+
+#endif
diff --git a/thirdparty/embree/common/simd/avx.h b/thirdparty/embree/common/simd/avx.h
new file mode 100644
index 0000000000..d3100306ee
--- /dev/null
+++ b/thirdparty/embree/common/simd/avx.h
@@ -0,0 +1,34 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "sse.h"
+
+#if defined(__AVX512VL__)
+#include "vboolf8_avx512.h"
+#include "vboold4_avx512.h"
+#else
+#include "vboolf8_avx.h"
+#include "vboold4_avx.h"
+#endif
+
+#if defined(__AVX2__)
+#include "vint8_avx2.h"
+#include "vuint8_avx2.h"
+#if defined(__X86_64__)
+#include "vllong4_avx2.h"
+#endif
+#else
+#include "vint8_avx.h"
+#include "vuint8_avx.h"
+#endif
+#include "vfloat8_avx.h"
+#if defined(__X86_64__)
+#include "vdouble4_avx.h"
+#endif
+
+#if defined(__AVX512F__)
+#include "avx512.h"
+#endif
+
diff --git a/thirdparty/embree/common/simd/avx512.h b/thirdparty/embree/common/simd/avx512.h
new file mode 100644
index 0000000000..d43bbacea1
--- /dev/null
+++ b/thirdparty/embree/common/simd/avx512.h
@@ -0,0 +1,41 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/intrinsics.h"
+#include "../math/constants.h"
+#include "../sys/alloc.h"
+#include "varying.h"
+
+#include "vboolf16_avx512.h"
+#include "vint16_avx512.h"
+#include "vuint16_avx512.h"
+#include "vfloat16_avx512.h"
+
+#include "vboold8_avx512.h"
+#include "vllong8_avx512.h"
+#include "vdouble8_avx512.h"
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Prefetching
+ ////////////////////////////////////////////////////////////////////////////////
+
+#define PFHINT_L1 0
+#define PFHINT_L2 1
+#define PFHINT_NT 2
+
+ template<const unsigned int mode>
+ __forceinline void prefetch(const void * __restrict__ const m)
+ {
+ if (mode == PFHINT_L1)
+ _mm_prefetch((const char*)m,_MM_HINT_T0);
+ else if (mode == PFHINT_L2)
+ _mm_prefetch((const char*)m,_MM_HINT_T1);
+ else if (mode == PFHINT_NT)
+ _mm_prefetch((const char*)m,_MM_HINT_NTA);
+ }
+}
diff --git a/thirdparty/embree/common/simd/simd.h b/thirdparty/embree/common/simd/simd.h
new file mode 100644
index 0000000000..195506b530
--- /dev/null
+++ b/thirdparty/embree/common/simd/simd.h
@@ -0,0 +1,110 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../math/math.h"
+
+/* include SSE wrapper classes */
+#if defined(__SSE__)
+# include "sse.h"
+#endif
+
+/* include AVX wrapper classes */
+#if defined(__AVX__)
+# include "avx.h"
+#endif
+
+/* include AVX512 wrapper classes */
+#if defined (__AVX512F__)
+# include "avx512.h"
+#endif
+
+namespace embree
+{
+ template <int N>
+ __forceinline vbool<N> isfinite(const vfloat<N>& v)
+ {
+ return (v >= vfloat<N>(-std::numeric_limits<float>::max()))
+ & (v <= vfloat<N>( std::numeric_limits<float>::max()));
+ }
+
+ /* foreach unique */
+ template<typename vbool, typename vint, typename Closure>
+ __forceinline void foreach_unique(const vbool& valid0, const vint& vi, const Closure& closure)
+ {
+ vbool valid1 = valid0;
+ while (any(valid1)) {
+ const int j = int(bsf(movemask(valid1)));
+ const int i = vi[j];
+ const vbool valid2 = valid1 & (i == vi);
+ valid1 = andn(valid1, valid2);
+ closure(valid2, i);
+ }
+ }
+
+ /* returns the next unique value i in vi and the corresponding valid_i mask */
+ template<typename vbool, typename vint>
+ __forceinline int next_unique(vbool& valid, const vint& vi, /*out*/ vbool& valid_i)
+ {
+ assert(any(valid));
+ const int j = int(bsf(movemask(valid)));
+ const int i = vi[j];
+ valid_i = valid & (i == vi);
+ valid = andn(valid, valid_i);
+ return i;
+ }
+
+ /* foreach unique index */
+ template<typename vbool, typename vint, typename Closure>
+ __forceinline void foreach_unique_index(const vbool& valid0, const vint& vi, const Closure& closure)
+ {
+ vbool valid1 = valid0;
+ while (any(valid1)) {
+ const int j = int(bsf(movemask(valid1)));
+ const int i = vi[j];
+ const vbool valid2 = valid1 & (i == vi);
+ valid1 = andn(valid1, valid2);
+ closure(valid2, i, j);
+ }
+ }
+
+ /* returns the index of the next unique value i in vi and the corresponding valid_i mask */
+ template<typename vbool, typename vint>
+ __forceinline int next_unique_index(vbool& valid, const vint& vi, /*out*/ vbool& valid_i)
+ {
+ assert(any(valid));
+ const int j = int(bsf(movemask(valid)));
+ const int i = vi[j];
+ valid_i = valid & (i == vi);
+ valid = andn(valid, valid_i);
+ return j;
+ }
+
+ template<typename Closure>
+ __forceinline void foreach2(int x0, int x1, int y0, int y1, const Closure& closure)
+ {
+ __aligned(64) int U[2*VSIZEX];
+ __aligned(64) int V[2*VSIZEX];
+ int index = 0;
+ for (int y=y0; y<y1; y++) {
+ const bool lasty = y+1>=y1;
+ const vintx vy = y;
+ for (int x=x0; x<x1; ) { //x+=VSIZEX) {
+ const bool lastx = x+VSIZEX >= x1;
+ vintx vx = x+vintx(step);
+ vintx::storeu(&U[index], vx);
+ vintx::storeu(&V[index], vy);
+ const int dx = min(x1-x,VSIZEX);
+ index += dx;
+ x += dx;
+ if (index >= VSIZEX || (lastx && lasty)) {
+ const vboolx valid = vintx(step) < vintx(index);
+ closure(valid, vintx::load(U), vintx::load(V));
+ x-= max(0, index-VSIZEX);
+ index = 0;
+ }
+ }
+ }
+ }
+}
diff --git a/thirdparty/embree/common/simd/sse.cpp b/thirdparty/embree/common/simd/sse.cpp
new file mode 100644
index 0000000000..535d6943d8
--- /dev/null
+++ b/thirdparty/embree/common/simd/sse.cpp
@@ -0,0 +1,34 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sse.h"
+
+namespace embree
+{
+ const __m128 mm_lookupmask_ps[16] = {
+ _mm_castsi128_ps(_mm_set_epi32( 0, 0, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32( 0, 0, 0,-1)),
+ _mm_castsi128_ps(_mm_set_epi32( 0, 0,-1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32( 0, 0,-1,-1)),
+ _mm_castsi128_ps(_mm_set_epi32( 0,-1, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32( 0,-1, 0,-1)),
+ _mm_castsi128_ps(_mm_set_epi32( 0,-1,-1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32( 0,-1,-1,-1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0, 0,-1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0,-1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1, 0,-1,-1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1,-1, 0, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1,-1, 0,-1)),
+ _mm_castsi128_ps(_mm_set_epi32(-1,-1,-1, 0)),
+ _mm_castsi128_ps(_mm_set_epi32(-1,-1,-1,-1))
+ };
+
+ const __m128d mm_lookupmask_pd[4] = {
+ _mm_castsi128_pd(_mm_set_epi32( 0, 0, 0, 0)),
+ _mm_castsi128_pd(_mm_set_epi32( 0, 0,-1,-1)),
+ _mm_castsi128_pd(_mm_set_epi32(-1,-1, 0, 0)),
+ _mm_castsi128_pd(_mm_set_epi32(-1,-1,-1,-1))
+ };
+
+}
diff --git a/thirdparty/embree/common/simd/sse.h b/thirdparty/embree/common/simd/sse.h
new file mode 100644
index 0000000000..1465fb4fb0
--- /dev/null
+++ b/thirdparty/embree/common/simd/sse.h
@@ -0,0 +1,35 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/intrinsics.h"
+#include "../sys/alloc.h"
+#include "../math/constants.h"
+#include "varying.h"
+
+namespace embree
+{
+#if defined(__SSE4_1__)
+ __forceinline __m128 blendv_ps(__m128 f, __m128 t, __m128 mask) {
+ return _mm_blendv_ps(f,t,mask);
+ }
+#else
+ __forceinline __m128 blendv_ps(__m128 f, __m128 t, __m128 mask) {
+ return _mm_or_ps(_mm_and_ps(mask, t), _mm_andnot_ps(mask, f));
+ }
+#endif
+
+ extern const __m128 mm_lookupmask_ps[16];
+ extern const __m128d mm_lookupmask_pd[4];
+}
+
+#if defined(__AVX512VL__)
+#include "vboolf4_avx512.h"
+#else
+#include "vboolf4_sse2.h"
+#endif
+#include "vint4_sse2.h"
+#include "vuint4_sse2.h"
+#include "vfloat4_sse2.h"
diff --git a/thirdparty/embree/common/simd/varying.h b/thirdparty/embree/common/simd/varying.h
new file mode 100644
index 0000000000..9b98d326be
--- /dev/null
+++ b/thirdparty/embree/common/simd/varying.h
@@ -0,0 +1,145 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+
+namespace embree
+{
+ /* Varying numeric types */
+ template<int N>
+ struct vfloat_impl
+ {
+ union { float f[N]; int i[N]; };
+ __forceinline const float& operator [](size_t index) const { assert(index < N); return f[index]; }
+ __forceinline float& operator [](size_t index) { assert(index < N); return f[index]; }
+ };
+
+ template<int N>
+ struct vdouble_impl
+ {
+ union { double f[N]; long long i[N]; };
+ __forceinline const double& operator [](size_t index) const { assert(index < N); return f[index]; }
+ __forceinline double& operator [](size_t index) { assert(index < N); return f[index]; }
+ };
+
+ template<int N>
+ struct vint_impl
+ {
+ int i[N];
+ __forceinline const int& operator [](size_t index) const { assert(index < N); return i[index]; }
+ __forceinline int& operator [](size_t index) { assert(index < N); return i[index]; }
+ };
+
+ template<int N>
+ struct vuint_impl
+ {
+ unsigned int i[N];
+ __forceinline const unsigned int& operator [](size_t index) const { assert(index < N); return i[index]; }
+ __forceinline unsigned int& operator [](size_t index) { assert(index < N); return i[index]; }
+ };
+
+ template<int N>
+ struct vllong_impl
+ {
+ long long i[N];
+ __forceinline const long long& operator [](size_t index) const { assert(index < N); return i[index]; }
+ __forceinline long long& operator [](size_t index) { assert(index < N); return i[index]; }
+ };
+
+ /* Varying bool types */
+ template<int N> struct vboolf_impl { int i[N]; }; // for float/int
+ template<int N> struct vboold_impl { long long i[N]; }; // for double/long long
+
+ /* Varying size constants */
+#if defined(__AVX512VL__) // SKX
+ const int VSIZEX = 8; // default size
+ const int VSIZEL = 16; // large size
+#elif defined(__AVX__)
+ const int VSIZEX = 8;
+ const int VSIZEL = 8;
+#else
+ const int VSIZEX = 4;
+ const int VSIZEL = 4;
+#endif
+
+ template<int N>
+ struct vtypes {
+ using vbool = vboolf_impl<N>;
+ using vboolf = vboolf_impl<N>;
+ using vboold = vboold_impl<N>;
+ using vint = vint_impl<N>;
+ using vuint = vuint_impl<N>;
+ using vllong = vllong_impl<N>;
+ using vfloat = vfloat_impl<N>;
+ using vdouble = vdouble_impl<N>;
+ };
+
+ template<>
+ struct vtypes<1> {
+ using vbool = bool;
+ using vboolf = bool;
+ using vboold = bool;
+ using vint = int;
+ using vuint = unsigned int;
+ using vllong = long long;
+ using vfloat = float;
+ using vdouble = double;
+ };
+
+ /* Aliases to default types */
+ template<int N> using vbool = typename vtypes<N>::vbool;
+ template<int N> using vboolf = typename vtypes<N>::vboolf;
+ template<int N> using vboold = typename vtypes<N>::vboold;
+ template<int N> using vint = typename vtypes<N>::vint;
+ template<int N> using vuint = typename vtypes<N>::vuint;
+ template<int N> using vllong = typename vtypes<N>::vllong;
+ template<int N> using vreal = typename vtypes<N>::vfloat;
+ template<int N> using vfloat = typename vtypes<N>::vfloat;
+ template<int N> using vdouble = typename vtypes<N>::vdouble;
+
+ /* 4-wide shortcuts */
+ typedef vfloat<4> vfloat4;
+ typedef vdouble<4> vdouble4;
+ typedef vreal<4> vreal4;
+ typedef vint<4> vint4;
+ typedef vuint<4> vuint4;
+ typedef vllong<4> vllong4;
+ typedef vbool<4> vbool4;
+ typedef vboolf<4> vboolf4;
+ typedef vboold<4> vboold4;
+
+ /* 8-wide shortcuts */
+ typedef vfloat<8> vfloat8;
+ typedef vdouble<8> vdouble8;
+ typedef vreal<8> vreal8;
+ typedef vint<8> vint8;
+ typedef vuint<8> vuint8;
+ typedef vllong<8> vllong8;
+ typedef vbool<8> vbool8;
+ typedef vboolf<8> vboolf8;
+ typedef vboold<8> vboold8;
+
+ /* 16-wide shortcuts */
+ typedef vfloat<16> vfloat16;
+ typedef vdouble<16> vdouble16;
+ typedef vreal<16> vreal16;
+ typedef vint<16> vint16;
+ typedef vuint<16> vuint16;
+ typedef vllong<16> vllong16;
+ typedef vbool<16> vbool16;
+ typedef vboolf<16> vboolf16;
+ typedef vboold<16> vboold16;
+
+ /* Default shortcuts */
+ typedef vfloat<VSIZEX> vfloatx;
+ typedef vdouble<VSIZEX> vdoublex;
+ typedef vreal<VSIZEX> vrealx;
+ typedef vint<VSIZEX> vintx;
+ typedef vuint<VSIZEX> vuintx;
+ typedef vllong<VSIZEX> vllongx;
+ typedef vbool<VSIZEX> vboolx;
+ typedef vboolf<VSIZEX> vboolfx;
+ typedef vboold<VSIZEX> vbooldx;
+}
diff --git a/thirdparty/embree/common/simd/vboold4_avx.h b/thirdparty/embree/common/simd/vboold4_avx.h
new file mode 100644
index 0000000000..7db0d1c5c1
--- /dev/null
+++ b/thirdparty/embree/common/simd/vboold4_avx.h
@@ -0,0 +1,169 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 4-wide AVX bool type for 64bit data types*/
+ template<>
+ struct vboold<4>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboold4 Bool;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { // data
+ __m256d v;
+ struct { __m128d vl,vh; };
+ long long i[4];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold() {}
+ __forceinline vboold(const vboold4& a) { v = a.v; }
+ __forceinline vboold4& operator =(const vboold4& a) { v = a.v; return *this; }
+
+ __forceinline vboold(__m256d a) : v(a) {}
+ __forceinline vboold(__m256i a) : v(_mm256_castsi256_pd(a)) {}
+
+ __forceinline operator const __m256() const { return _mm256_castpd_ps(v); }
+ __forceinline operator const __m256i() const { return _mm256_castpd_si256(v); }
+ __forceinline operator const __m256d() const { return v; }
+
+ __forceinline vboold(int a)
+ {
+ assert(a >= 0 && a <= 255);
+#if defined (__AVX2__)
+ const __m256i mask = _mm256_set_epi64x(0x8, 0x4, 0x2, 0x1);
+ const __m256i b = _mm256_set1_epi64x(a);
+ const __m256i c = _mm256_and_si256(b,mask);
+ v = _mm256_castsi256_pd(_mm256_cmpeq_epi64(c,mask));
+#else
+ vl = mm_lookupmask_pd[a & 0x3];
+ vh = mm_lookupmask_pd[a >> 2];
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold(FalseTy) : v(_mm256_setzero_pd()) {}
+ __forceinline vboold(TrueTy) : v(_mm256_cmp_pd(_mm256_setzero_pd(), _mm256_setzero_pd(), _CMP_EQ_OQ)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const { assert(index < 4); return (_mm256_movemask_pd(v) >> index) & 1; }
+ __forceinline long long& operator [](size_t index) { assert(index < 4); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator !(const vboold4& a) { return _mm256_xor_pd(a, vboold4(embree::True)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator &(const vboold4& a, const vboold4& b) { return _mm256_and_pd(a, b); }
+ __forceinline vboold4 operator |(const vboold4& a, const vboold4& b) { return _mm256_or_pd (a, b); }
+ __forceinline vboold4 operator ^(const vboold4& a, const vboold4& b) { return _mm256_xor_pd(a, b); }
+
+ __forceinline vboold4 andn(const vboold4& a, const vboold4& b) { return _mm256_andnot_pd(b, a); }
+
+ __forceinline vboold4& operator &=(vboold4& a, const vboold4& b) { return a = a & b; }
+ __forceinline vboold4& operator |=(vboold4& a, const vboold4& b) { return a = a | b; }
+ __forceinline vboold4& operator ^=(vboold4& a, const vboold4& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator !=(const vboold4& a, const vboold4& b) { return _mm256_xor_pd(a, b); }
+ __forceinline vboold4 operator ==(const vboold4& a, const vboold4& b) { return _mm256_xor_pd(_mm256_xor_pd(a,b),vboold4(embree::True)); }
+
+ __forceinline vboold4 select(const vboold4& mask, const vboold4& t, const vboold4& f) {
+ return _mm256_blendv_pd(f, t, mask);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 unpacklo(const vboold4& a, const vboold4& b) { return _mm256_unpacklo_pd(a, b); }
+ __forceinline vboold4 unpackhi(const vboold4& a, const vboold4& b) { return _mm256_unpackhi_pd(a, b); }
+
+
+#if defined(__AVX2__)
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboold4 shuffle(const vboold4& v) {
+ return _mm256_permute4x64_pd(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i>
+ __forceinline vboold4 shuffle(const vboold4& v) {
+ return _mm256_permute4x64_pd(v, _MM_SHUFFLE(i, i, i, i));
+ }
+#endif
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool reduce_and(const vboold4& a) { return _mm256_movemask_pd(a) == (unsigned int)0xf; }
+ __forceinline bool reduce_or (const vboold4& a) { return !_mm256_testz_pd(a,a); }
+
+ __forceinline bool all (const vboold4& a) { return _mm256_movemask_pd(a) == (unsigned int)0xf; }
+ __forceinline bool any (const vboold4& a) { return !_mm256_testz_pd(a,a); }
+ __forceinline bool none(const vboold4& a) { return _mm256_testz_pd(a,a) != 0; }
+
+ __forceinline bool all (const vboold4& valid, const vboold4& b) { return all((!valid) | b); }
+ __forceinline bool any (const vboold4& valid, const vboold4& b) { return any(valid & b); }
+ __forceinline bool none(const vboold4& valid, const vboold4& b) { return none(valid & b); }
+
+ __forceinline unsigned int movemask(const vboold4& a) { return _mm256_movemask_pd(a); }
+ __forceinline size_t popcnt (const vboold4& a) { return popcnt((size_t)_mm256_movemask_pd(a)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboold4& a, size_t index) { return a[index]; }
+ __forceinline void set (vboold4& a, size_t index) { a[index] = -1; }
+ __forceinline void clear(vboold4& a, size_t index) { a[index] = 0; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboold4& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", "
+ << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vboold4_avx512.h b/thirdparty/embree/common/simd/vboold4_avx512.h
new file mode 100644
index 0000000000..ceaad7bba5
--- /dev/null
+++ b/thirdparty/embree/common/simd/vboold4_avx512.h
@@ -0,0 +1,156 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 4-wide AVX-512 bool type */
+ template<>
+ struct vboold<4>
+ {
+ typedef vboold4 Bool;
+ typedef vint4 Int;
+
+ enum { size = 4 }; // number of SIMD elements
+ __mmask8 v; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold() {}
+ __forceinline vboold(const vboold4& t) { v = t.v; }
+ __forceinline vboold4& operator =(const vboold4& f) { v = f.v; return *this; }
+
+ __forceinline vboold(const __mmask8 &t) { v = t; }
+ __forceinline operator __mmask8() const { return v; }
+
+ __forceinline vboold(bool b) { v = b ? 0xf : 0x0; }
+ __forceinline vboold(int t) { v = (__mmask8)t; }
+ __forceinline vboold(unsigned int t) { v = (__mmask8)t; }
+
+ /* return int8 mask */
+ __forceinline __m128i mask8() const {
+ return _mm_movm_epi8(v);
+ }
+
+ /* return int32 mask */
+ __forceinline __m128i mask32() const {
+ return _mm_movm_epi32(v);
+ }
+
+ /* return int64 mask */
+ __forceinline __m256i mask64() const {
+ return _mm256_movm_epi64(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold(FalseTy) : v(0x0) {}
+ __forceinline vboold(TrueTy) : v(0xf) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const {
+ assert(index < 4); return (mm512_mask2int(v) >> index) & 1;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator !(const vboold4& a) { return _mm512_kandn(a, 0xf); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator &(const vboold4& a, const vboold4& b) { return _mm512_kand(a, b); }
+ __forceinline vboold4 operator |(const vboold4& a, const vboold4& b) { return _mm512_kor(a, b); }
+ __forceinline vboold4 operator ^(const vboold4& a, const vboold4& b) { return _mm512_kxor(a, b); }
+
+ __forceinline vboold4 andn(const vboold4& a, const vboold4& b) { return _mm512_kandn(b, a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4& operator &=(vboold4& a, const vboold4& b) { return a = a & b; }
+ __forceinline vboold4& operator |=(vboold4& a, const vboold4& b) { return a = a | b; }
+ __forceinline vboold4& operator ^=(vboold4& a, const vboold4& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold4 operator !=(const vboold4& a, const vboold4& b) { return _mm512_kxor(a, b); }
+ __forceinline vboold4 operator ==(const vboold4& a, const vboold4& b) { return _mm512_kand(_mm512_kxnor(a, b), 0xf); }
+
+ __forceinline vboold4 select(const vboold4& s, const vboold4& a, const vboold4& b) {
+ return _mm512_kor(_mm512_kand(s, a), _mm512_kandn(s, b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int all (const vboold4& a) { return a.v == 0xf; }
+ __forceinline int any (const vboold4& a) { return _mm512_kortestz(a, a) == 0; }
+ __forceinline int none(const vboold4& a) { return _mm512_kortestz(a, a) != 0; }
+
+ __forceinline int all (const vboold4& valid, const vboold4& b) { return all((!valid) | b); }
+ __forceinline int any (const vboold4& valid, const vboold4& b) { return any(valid & b); }
+ __forceinline int none(const vboold4& valid, const vboold4& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboold4& a) { return _mm512_kmov(a); }
+ __forceinline size_t popcnt (const vboold4& a) { return popcnt(a.v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Conversion Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int toInt(const vboold4& a) { return mm512_mask2int(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboold4& a, size_t index) { assert(index < 4); return (toInt(a) >> index) & 1; }
+ __forceinline void set(vboold4& a, size_t index) { assert(index < 4); a |= 1 << index; }
+ __forceinline void clear(vboold4& a, size_t index) { assert(index < 4); a = andn(a, 1 << index); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboold4& a)
+ {
+ cout << "<";
+ for (size_t i=0; i<4; i++) {
+ if ((a.v >> i) & 1) cout << "1"; else cout << "0";
+ }
+ return cout << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vboold8_avx512.h b/thirdparty/embree/common/simd/vboold8_avx512.h
new file mode 100644
index 0000000000..66d2054872
--- /dev/null
+++ b/thirdparty/embree/common/simd/vboold8_avx512.h
@@ -0,0 +1,151 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 8-wide AVX-512 bool type */
+ template<>
+ struct vboold<8>
+ {
+ typedef vboold8 Bool;
+ typedef vint8 Int;
+
+ enum { size = 8 }; // number of SIMD elements
+ __mmask8 v; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold() {}
+ __forceinline vboold(const vboold8& t) { v = t.v; }
+ __forceinline vboold8& operator =(const vboold8& f) { v = f.v; return *this; }
+
+ __forceinline vboold(const __mmask8& t) { v = t; }
+ __forceinline operator __mmask8() const { return v; }
+
+ __forceinline vboold(bool b) { v = b ? 0xff : 0x00; }
+ __forceinline vboold(int t) { v = (__mmask8)t; }
+ __forceinline vboold(unsigned int t) { v = (__mmask8)t; }
+
+ /* return int8 mask */
+ __forceinline __m128i mask8() const {
+ return _mm_movm_epi8(v);
+ }
+
+ /* return int64 mask */
+ __forceinline __m512i mask64() const {
+ return _mm512_movm_epi64(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold(FalseTy) : v(0x00) {}
+ __forceinline vboold(TrueTy) : v(0xff) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const {
+ assert(index < 8); return (mm512_mask2int(v) >> index) & 1;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 operator !(const vboold8& a) { return _mm512_knot(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 operator &(const vboold8& a, const vboold8& b) { return _mm512_kand(a, b); }
+ __forceinline vboold8 operator |(const vboold8& a, const vboold8& b) { return _mm512_kor(a, b); }
+ __forceinline vboold8 operator ^(const vboold8& a, const vboold8& b) { return _mm512_kxor(a, b); }
+
+ __forceinline vboold8 andn(const vboold8& a, const vboold8& b) { return _mm512_kandn(b, a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8& operator &=(vboold8& a, const vboold8& b) { return a = a & b; }
+ __forceinline vboold8& operator |=(vboold8& a, const vboold8& b) { return a = a | b; }
+ __forceinline vboold8& operator ^=(vboold8& a, const vboold8& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 operator !=(const vboold8& a, const vboold8& b) { return _mm512_kxor(a, b); }
+ __forceinline vboold8 operator ==(const vboold8& a, const vboold8& b) { return _mm512_kxnor(a, b); }
+
+ __forceinline vboold8 select(const vboold8& s, const vboold8& a, const vboold8& b) {
+ return _mm512_kor(_mm512_kand(s, a), _mm512_kandn(s, b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int all (const vboold8& a) { return a.v == 0xff; }
+ __forceinline int any (const vboold8& a) { return _mm512_kortestz(a, a) == 0; }
+ __forceinline int none(const vboold8& a) { return _mm512_kortestz(a, a) != 0; }
+
+ __forceinline int all (const vboold8& valid, const vboold8& b) { return all((!valid) | b); }
+ __forceinline int any (const vboold8& valid, const vboold8& b) { return any(valid & b); }
+ __forceinline int none(const vboold8& valid, const vboold8& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboold8& a) { return _mm512_kmov(a); }
+ __forceinline size_t popcnt (const vboold8& a) { return popcnt(a.v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Conversion Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int toInt(const vboold8& a) { return mm512_mask2int(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboold8& a, size_t index) { assert(index < 8); return (toInt(a) >> index) & 1; }
+ __forceinline void set(vboold8& a, size_t index) { assert(index < 8); a |= 1 << index; }
+ __forceinline void clear(vboold8& a, size_t index) { assert(index < 8); a = andn(a, 1 << index); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboold8& a)
+ {
+ cout << "<";
+ for (size_t i=0; i<8; i++) {
+ if ((a.v >> i) & 1) cout << "1"; else cout << "0";
+ }
+ return cout << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vboolf16_avx512.h b/thirdparty/embree/common/simd/vboolf16_avx512.h
new file mode 100644
index 0000000000..19841dcea8
--- /dev/null
+++ b/thirdparty/embree/common/simd/vboolf16_avx512.h
@@ -0,0 +1,153 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 16-wide AVX-512 bool type */
+ template<>
+ struct vboolf<16>
+ {
+ typedef vboolf16 Bool;
+ typedef vint16 Int;
+ typedef vfloat16 Float;
+
+ enum { size = 16 }; // number of SIMD elements
+ __mmask16 v; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf() {}
+ __forceinline vboolf(const vboolf16& t) { v = t.v; }
+ __forceinline vboolf16& operator =(const vboolf16& f) { v = f.v; return *this; }
+
+ __forceinline vboolf(const __mmask16& t) { v = t; }
+ __forceinline operator __mmask16() const { return v; }
+
+ __forceinline vboolf(bool b) { v = b ? 0xFFFF : 0x0000; }
+ __forceinline vboolf(int t) { v = (__mmask16)t; }
+ __forceinline vboolf(unsigned int t) { v = (__mmask16)t; }
+
+ /* return int8 mask */
+ __forceinline __m128i mask8() const {
+ return _mm_movm_epi8(v);
+ }
+
+ /* return int32 mask */
+ __forceinline __m512i mask32() const {
+ return _mm512_movm_epi32(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf(FalseTy) : v(0x0000) {}
+ __forceinline vboolf(TrueTy) : v(0xffff) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const {
+ assert(index < 16); return (mm512_mask2int(v) >> index) & 1;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator !(const vboolf16& a) { return _mm512_knot(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator &(const vboolf16& a, const vboolf16& b) { return _mm512_kand(a,b); }
+ __forceinline vboolf16 operator |(const vboolf16& a, const vboolf16& b) { return _mm512_kor(a,b); }
+ __forceinline vboolf16 operator ^(const vboolf16& a, const vboolf16& b) { return _mm512_kxor(a,b); }
+
+ __forceinline vboolf16 andn(const vboolf16& a, const vboolf16& b) { return _mm512_kandn(b,a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16& operator &=(vboolf16& a, const vboolf16& b) { return a = a & b; }
+ __forceinline vboolf16& operator |=(vboolf16& a, const vboolf16& b) { return a = a | b; }
+ __forceinline vboolf16& operator ^=(vboolf16& a, const vboolf16& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator !=(const vboolf16& a, const vboolf16& b) { return _mm512_kxor(a, b); }
+ __forceinline vboolf16 operator ==(const vboolf16& a, const vboolf16& b) { return _mm512_kxnor(a, b); }
+
+ __forceinline vboolf16 select(const vboolf16& s, const vboolf16& a, const vboolf16& b) {
+ return _mm512_kor(_mm512_kand(s,a),_mm512_kandn(s,b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int all (const vboolf16& a) { return _mm512_kortestc(a,a) != 0; }
+ __forceinline int any (const vboolf16& a) { return _mm512_kortestz(a,a) == 0; }
+ __forceinline int none(const vboolf16& a) { return _mm512_kortestz(a,a) != 0; }
+
+ __forceinline int all (const vboolf16& valid, const vboolf16& b) { return all((!valid) | b); }
+ __forceinline int any (const vboolf16& valid, const vboolf16& b) { return any(valid & b); }
+ __forceinline int none(const vboolf16& valid, const vboolf16& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboolf16& a) { return _mm512_kmov(a); }
+ __forceinline size_t popcnt (const vboolf16& a) { return popcnt(a.v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Convertion Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int toInt (const vboolf16& a) { return mm512_mask2int(a); }
+ __forceinline vboolf16 toMask(const int& a) { return mm512_int2mask(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboolf16& a, size_t index) { assert(index < 16); return (toInt(a) >> index) & 1; }
+ __forceinline void set(vboolf16& a, size_t index) { assert(index < 16); a |= 1 << index; }
+ __forceinline void clear(vboolf16& a, size_t index) { assert(index < 16); a = andn(a, 1 << index); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboolf16& a)
+ {
+ cout << "<";
+ for (size_t i=0; i<16; i++) {
+ if ((a.v >> i) & 1) cout << "1"; else cout << "0";
+ }
+ return cout << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vboolf4_avx512.h b/thirdparty/embree/common/simd/vboolf4_avx512.h
new file mode 100644
index 0000000000..e65f66b025
--- /dev/null
+++ b/thirdparty/embree/common/simd/vboolf4_avx512.h
@@ -0,0 +1,159 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 4-wide AVX-512 bool type */
+ template<>
+ struct vboolf<4>
+ {
+ typedef vboolf4 Bool;
+ typedef vint4 Int;
+
+ enum { size = 4 }; // number of SIMD elements
+ __mmask8 v; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf() {}
+ __forceinline vboolf(const vboolf4& t) { v = t.v; }
+ __forceinline vboolf4& operator =(const vboolf4& f) { v = f.v; return *this; }
+
+ __forceinline vboolf(const __mmask8 &t) { v = t; }
+ __forceinline operator __mmask8() const { return v; }
+
+ __forceinline vboolf(bool b) { v = b ? 0xf : 0x0; }
+ __forceinline vboolf(int t) { v = (__mmask8)t; }
+ __forceinline vboolf(unsigned int t) { v = (__mmask8)t; }
+
+ __forceinline vboolf(bool a, bool b, bool c, bool d)
+ : v((__mmask8)((int(d) << 3) | (int(c) << 2) | (int(b) << 1) | int(a))) {}
+
+ /* return int8 mask */
+ __forceinline __m128i mask8() const {
+ return _mm_movm_epi8(v);
+ }
+
+ /* return int32 mask */
+ __forceinline __m128i mask32() const {
+ return _mm_movm_epi32(v);
+ }
+
+ /* return int64 mask */
+ __forceinline __m256i mask64() const {
+ return _mm256_movm_epi64(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf(FalseTy) : v(0x0) {}
+ __forceinline vboolf(TrueTy) : v(0xf) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const {
+ assert(index < 4); return (mm512_mask2int(v) >> index) & 1;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator !(const vboolf4& a) { return _mm512_kandn(a, 0xf); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator &(const vboolf4& a, const vboolf4& b) { return _mm512_kand(a, b); }
+ __forceinline vboolf4 operator |(const vboolf4& a, const vboolf4& b) { return _mm512_kor(a, b); }
+ __forceinline vboolf4 operator ^(const vboolf4& a, const vboolf4& b) { return _mm512_kxor(a, b); }
+
+ __forceinline vboolf4 andn(const vboolf4& a, const vboolf4& b) { return _mm512_kandn(b, a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4& operator &=(vboolf4& a, const vboolf4& b) { return a = a & b; }
+ __forceinline vboolf4& operator |=(vboolf4& a, const vboolf4& b) { return a = a | b; }
+ __forceinline vboolf4& operator ^=(vboolf4& a, const vboolf4& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator !=(const vboolf4& a, const vboolf4& b) { return _mm512_kxor(a, b); }
+ __forceinline vboolf4 operator ==(const vboolf4& a, const vboolf4& b) { return _mm512_kand(_mm512_kxnor(a, b), 0xf); }
+
+ __forceinline vboolf4 select(const vboolf4& s, const vboolf4& a, const vboolf4& b) {
+ return _mm512_kor(_mm512_kand(s, a), _mm512_kandn(s, b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int all (const vboolf4& a) { return a.v == 0xf; }
+ __forceinline int any (const vboolf4& a) { return _mm512_kortestz(a, a) == 0; }
+ __forceinline int none(const vboolf4& a) { return _mm512_kortestz(a, a) != 0; }
+
+ __forceinline int all (const vboolf4& valid, const vboolf4& b) { return all((!valid) | b); }
+ __forceinline int any (const vboolf4& valid, const vboolf4& b) { return any(valid & b); }
+ __forceinline int none(const vboolf4& valid, const vboolf4& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboolf4& a) { return _mm512_kmov(a); }
+ __forceinline size_t popcnt (const vboolf4& a) { return popcnt(a.v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Conversion Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int toInt(const vboolf4& a) { return mm512_mask2int(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboolf4& a, size_t index) { assert(index < 4); return (toInt(a) >> index) & 1; }
+ __forceinline void set(vboolf4& a, size_t index) { assert(index < 4); a |= 1 << index; }
+ __forceinline void clear(vboolf4& a, size_t index) { assert(index < 4); a = andn(a, 1 << index); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboolf4& a)
+ {
+ cout << "<";
+ for (size_t i=0; i<4; i++) {
+ if ((a.v >> i) & 1) cout << "1"; else cout << "0";
+ }
+ return cout << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vboolf4_sse2.h b/thirdparty/embree/common/simd/vboolf4_sse2.h
new file mode 100644
index 0000000000..fa84b1b6ee
--- /dev/null
+++ b/thirdparty/embree/common/simd/vboolf4_sse2.h
@@ -0,0 +1,189 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 4-wide SSE bool type */
+ template<>
+ struct vboolf<4>
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef vboolf4 Bool;
+ typedef vint4 Int;
+ typedef vfloat4 Float;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { __m128 v; int i[4]; }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf() {}
+ __forceinline vboolf(const vboolf4& other) { v = other.v; }
+ __forceinline vboolf4& operator =(const vboolf4& other) { v = other.v; return *this; }
+
+ __forceinline vboolf(__m128 input) : v(input) {}
+ __forceinline operator const __m128&() const { return v; }
+ __forceinline operator const __m128i() const { return _mm_castps_si128(v); }
+ __forceinline operator const __m128d() const { return _mm_castps_pd(v); }
+
+ __forceinline vboolf(bool a)
+ : v(mm_lookupmask_ps[(size_t(a) << 3) | (size_t(a) << 2) | (size_t(a) << 1) | size_t(a)]) {}
+ __forceinline vboolf(bool a, bool b)
+ : v(mm_lookupmask_ps[(size_t(b) << 3) | (size_t(a) << 2) | (size_t(b) << 1) | size_t(a)]) {}
+ __forceinline vboolf(bool a, bool b, bool c, bool d)
+ : v(mm_lookupmask_ps[(size_t(d) << 3) | (size_t(c) << 2) | (size_t(b) << 1) | size_t(a)]) {}
+ __forceinline vboolf(int mask) { assert(mask >= 0 && mask < 16); v = mm_lookupmask_ps[mask]; }
+ __forceinline vboolf(unsigned int mask) { assert(mask < 16); v = mm_lookupmask_ps[mask]; }
+
+ /* return int32 mask */
+ __forceinline __m128i mask32() const {
+ return _mm_castps_si128(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf(FalseTy) : v(_mm_setzero_ps()) {}
+ __forceinline vboolf(TrueTy) : v(_mm_castsi128_ps(_mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()))) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const { assert(index < 4); return (_mm_movemask_ps(v) >> index) & 1; }
+ __forceinline int& operator [](size_t index) { assert(index < 4); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator !(const vboolf4& a) { return _mm_xor_ps(a, vboolf4(embree::True)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator &(const vboolf4& a, const vboolf4& b) { return _mm_and_ps(a, b); }
+ __forceinline vboolf4 operator |(const vboolf4& a, const vboolf4& b) { return _mm_or_ps (a, b); }
+ __forceinline vboolf4 operator ^(const vboolf4& a, const vboolf4& b) { return _mm_xor_ps(a, b); }
+
+ __forceinline vboolf4 andn(const vboolf4& a, const vboolf4& b) { return _mm_andnot_ps(b, a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4& operator &=(vboolf4& a, const vboolf4& b) { return a = a & b; }
+ __forceinline vboolf4& operator |=(vboolf4& a, const vboolf4& b) { return a = a | b; }
+ __forceinline vboolf4& operator ^=(vboolf4& a, const vboolf4& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 operator !=(const vboolf4& a, const vboolf4& b) { return _mm_xor_ps(a, b); }
+ __forceinline vboolf4 operator ==(const vboolf4& a, const vboolf4& b) { return _mm_castsi128_ps(_mm_cmpeq_epi32(a, b)); }
+
+ __forceinline vboolf4 select(const vboolf4& m, const vboolf4& t, const vboolf4& f) {
+#if defined(__SSE4_1__)
+ return _mm_blendv_ps(f, t, m);
+#else
+ return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf4 unpacklo(const vboolf4& a, const vboolf4& b) { return _mm_unpacklo_ps(a, b); }
+ __forceinline vboolf4 unpackhi(const vboolf4& a, const vboolf4& b) { return _mm_unpackhi_ps(a, b); }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboolf4 shuffle(const vboolf4& v) {
+ return _mm_castsi128_ps(_mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboolf4 shuffle(const vboolf4& a, const vboolf4& b) {
+ return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0>
+ __forceinline vboolf4 shuffle(const vboolf4& v) {
+ return shuffle<i0,i0,i0,i0>(v);
+ }
+
+#if defined(__SSE3__)
+ template<> __forceinline vboolf4 shuffle<0, 0, 2, 2>(const vboolf4& v) { return _mm_moveldup_ps(v); }
+ template<> __forceinline vboolf4 shuffle<1, 1, 3, 3>(const vboolf4& v) { return _mm_movehdup_ps(v); }
+ template<> __forceinline vboolf4 shuffle<0, 1, 0, 1>(const vboolf4& v) { return _mm_castpd_ps(_mm_movedup_pd(v)); }
+#endif
+
+#if defined(__SSE4_1__)
+ template<int dst, int src, int clr> __forceinline vboolf4 insert(const vboolf4& a, const vboolf4& b) { return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr); }
+ template<int dst, int src> __forceinline vboolf4 insert(const vboolf4& a, const vboolf4& b) { return insert<dst, src, 0>(a, b); }
+ template<int dst> __forceinline vboolf4 insert(const vboolf4& a, const bool b) { return insert<dst, 0>(a, vboolf4(b)); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool reduce_and(const vboolf4& a) { return _mm_movemask_ps(a) == 0xf; }
+ __forceinline bool reduce_or (const vboolf4& a) { return _mm_movemask_ps(a) != 0x0; }
+
+ __forceinline bool all (const vboolf4& b) { return _mm_movemask_ps(b) == 0xf; }
+ __forceinline bool any (const vboolf4& b) { return _mm_movemask_ps(b) != 0x0; }
+ __forceinline bool none(const vboolf4& b) { return _mm_movemask_ps(b) == 0x0; }
+
+ __forceinline bool all (const vboolf4& valid, const vboolf4& b) { return all((!valid) | b); }
+ __forceinline bool any (const vboolf4& valid, const vboolf4& b) { return any(valid & b); }
+ __forceinline bool none(const vboolf4& valid, const vboolf4& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboolf4& a) { return _mm_movemask_ps(a); }
+#if defined(__SSE4_2__)
+ __forceinline size_t popcnt(const vboolf4& a) { return popcnt((size_t)_mm_movemask_ps(a)); }
+#else
+ __forceinline size_t popcnt(const vboolf4& a) { return bool(a[0])+bool(a[1])+bool(a[2])+bool(a[3]); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboolf4& a, size_t index) { return a[index]; }
+ __forceinline void set(vboolf4& a, size_t index) { a[index] = -1; }
+ __forceinline void clear(vboolf4& a, size_t index) { a[index] = 0; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboolf4& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vboolf8_avx.h b/thirdparty/embree/common/simd/vboolf8_avx.h
new file mode 100644
index 0000000000..ba77cc3c5e
--- /dev/null
+++ b/thirdparty/embree/common/simd/vboolf8_avx.h
@@ -0,0 +1,202 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 8-wide AVX bool type */
+ template<>
+ struct vboolf<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m256 v;
+ struct { __m128 vl,vh; };
+ int i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf() {}
+ __forceinline vboolf(const vboolf8& a) { v = a.v; }
+ __forceinline vboolf8& operator =(const vboolf8& a) { v = a.v; return *this; }
+
+ __forceinline vboolf(__m256 a) : v(a) {}
+ __forceinline operator const __m256&() const { return v; }
+ __forceinline operator const __m256i() const { return _mm256_castps_si256(v); }
+ __forceinline operator const __m256d() const { return _mm256_castps_pd(v); }
+
+ __forceinline vboolf(int a)
+ {
+ assert(a >= 0 && a <= 255);
+#if defined (__AVX2__)
+ const __m256i mask = _mm256_set_epi32(0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1);
+ const __m256i b = _mm256_set1_epi32(a);
+ const __m256i c = _mm256_and_si256(b,mask);
+ v = _mm256_castsi256_ps(_mm256_cmpeq_epi32(c,mask));
+#else
+ vl = mm_lookupmask_ps[a & 0xF];
+ vh = mm_lookupmask_ps[a >> 4];
+#endif
+ }
+
+ __forceinline vboolf(const vboolf4& a) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),a,1)) {}
+ __forceinline vboolf(const vboolf4& a, const vboolf4& b) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),b,1)) {}
+ __forceinline vboolf(__m128 a, __m128 b) : vl(a), vh(b) {}
+
+ __forceinline vboolf(bool a) : v(vboolf8(vboolf4(a), vboolf4(a))) {}
+ __forceinline vboolf(bool a, bool b) : v(vboolf8(vboolf4(a), vboolf4(b))) {}
+ __forceinline vboolf(bool a, bool b, bool c, bool d) : v(vboolf8(vboolf4(a,b), vboolf4(c,d))) {}
+ __forceinline vboolf(bool a, bool b, bool c, bool d, bool e, bool f, bool g, bool h) : v(vboolf8(vboolf4(a,b,c,d), vboolf4(e,f,g,h))) {}
+
+ /* return int32 mask */
+ __forceinline __m256i mask32() const {
+ return _mm256_castps_si256(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf(FalseTy) : v(_mm256_setzero_ps()) {}
+ __forceinline vboolf(TrueTy) : v(_mm256_cmp_ps(_mm256_setzero_ps(), _mm256_setzero_ps(), _CMP_EQ_OQ)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const { assert(index < 8); return (_mm256_movemask_ps(v) >> index) & 1; }
+ __forceinline int& operator [](size_t index) { assert(index < 8); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator !(const vboolf8& a) { return _mm256_xor_ps(a, vboolf8(embree::True)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator &(const vboolf8& a, const vboolf8& b) { return _mm256_and_ps(a, b); }
+ __forceinline vboolf8 operator |(const vboolf8& a, const vboolf8& b) { return _mm256_or_ps (a, b); }
+ __forceinline vboolf8 operator ^(const vboolf8& a, const vboolf8& b) { return _mm256_xor_ps(a, b); }
+
+ __forceinline vboolf8 andn(const vboolf8& a, const vboolf8& b) { return _mm256_andnot_ps(b, a); }
+
+ __forceinline vboolf8& operator &=(vboolf8& a, const vboolf8& b) { return a = a & b; }
+ __forceinline vboolf8& operator |=(vboolf8& a, const vboolf8& b) { return a = a | b; }
+ __forceinline vboolf8& operator ^=(vboolf8& a, const vboolf8& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator !=(const vboolf8& a, const vboolf8& b) { return _mm256_xor_ps(a, b); }
+ __forceinline vboolf8 operator ==(const vboolf8& a, const vboolf8& b) { return _mm256_xor_ps(_mm256_xor_ps(a,b),vboolf8(embree::True)); }
+
+ __forceinline vboolf8 select(const vboolf8& mask, const vboolf8& t, const vboolf8& f) {
+ return _mm256_blendv_ps(f, t, mask);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 unpacklo(const vboolf8& a, const vboolf8& b) { return _mm256_unpacklo_ps(a, b); }
+ __forceinline vboolf8 unpackhi(const vboolf8& a, const vboolf8& b) { return _mm256_unpackhi_ps(a, b); }
+
+ template<int i>
+ __forceinline vboolf8 shuffle(const vboolf8& v) {
+ return _mm256_permute_ps(v, _MM_SHUFFLE(i, i, i, i));
+ }
+
+ template<int i0, int i1>
+ __forceinline vboolf8 shuffle4(const vboolf8& v) {
+ return _mm256_permute2f128_ps(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vboolf8 shuffle4(const vboolf8& a, const vboolf8& b) {
+ return _mm256_permute2f128_ps(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboolf8 shuffle(const vboolf8& v) {
+ return _mm256_permute_ps(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vboolf8 shuffle(const vboolf8& a, const vboolf8& b) {
+ return _mm256_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<> __forceinline vboolf8 shuffle<0, 0, 2, 2>(const vboolf8& v) { return _mm256_moveldup_ps(v); }
+ template<> __forceinline vboolf8 shuffle<1, 1, 3, 3>(const vboolf8& v) { return _mm256_movehdup_ps(v); }
+ template<> __forceinline vboolf8 shuffle<0, 1, 0, 1>(const vboolf8& v) { return _mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(v))); }
+
+ template<int i> __forceinline vboolf8 insert4(const vboolf8& a, const vboolf4& b) { return _mm256_insertf128_ps(a, b, i); }
+ template<int i> __forceinline vboolf4 extract4 (const vboolf8& a) { return _mm256_extractf128_ps(a, i); }
+ template<> __forceinline vboolf4 extract4<0>(const vboolf8& a) { return _mm256_castps256_ps128(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool reduce_and(const vboolf8& a) { return _mm256_movemask_ps(a) == (unsigned int)0xff; }
+ __forceinline bool reduce_or (const vboolf8& a) { return !_mm256_testz_ps(a,a); }
+
+ __forceinline bool all (const vboolf8& a) { return _mm256_movemask_ps(a) == (unsigned int)0xff; }
+ __forceinline bool any (const vboolf8& a) { return !_mm256_testz_ps(a,a); }
+ __forceinline bool none(const vboolf8& a) { return _mm256_testz_ps(a,a) != 0; }
+
+ __forceinline bool all (const vboolf8& valid, const vboolf8& b) { return all((!valid) | b); }
+ __forceinline bool any (const vboolf8& valid, const vboolf8& b) { return any(valid & b); }
+ __forceinline bool none(const vboolf8& valid, const vboolf8& b) { return none(valid & b); }
+
+ __forceinline unsigned int movemask(const vboolf8& a) { return _mm256_movemask_ps(a); }
+ __forceinline size_t popcnt (const vboolf8& a) { return popcnt((size_t)_mm256_movemask_ps(a)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboolf8& a, size_t index) { return a[index]; }
+ __forceinline void set(vboolf8& a, size_t index) { a[index] = -1; }
+ __forceinline void clear(vboolf8& a, size_t index) { a[index] = 0; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboolf8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", "
+ << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vboolf8_avx512.h b/thirdparty/embree/common/simd/vboolf8_avx512.h
new file mode 100644
index 0000000000..73ff5666e1
--- /dev/null
+++ b/thirdparty/embree/common/simd/vboolf8_avx512.h
@@ -0,0 +1,159 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 8-wide AVX-512 bool type */
+ template<>
+ struct vboolf<8>
+ {
+ typedef vboolf8 Bool;
+ typedef vint8 Int;
+
+ enum { size = 8 }; // number of SIMD elements
+ __mmask8 v; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf() {}
+ __forceinline vboolf(const vboolf8& t) { v = t.v; }
+ __forceinline vboolf8& operator =(const vboolf8& f) { v = f.v; return *this; }
+
+ __forceinline vboolf(const __mmask8 &t) { v = t; }
+ __forceinline operator __mmask8() const { return v; }
+
+ __forceinline vboolf(bool b) { v = b ? 0xff : 0x00; }
+ __forceinline vboolf(int t) { v = (__mmask8)t; }
+ __forceinline vboolf(unsigned int t) { v = (__mmask8)t; }
+
+ __forceinline vboolf(bool a, bool b, bool c, bool d, bool e, bool f, bool g, bool h)
+ : v((__mmask8)((int(h) << 7) | (int(g) << 6) | (int(f) << 5) | (int(e) << 4) | (int(d) << 3) | (int(c) << 2) | (int(b) << 1) | int(a))) {}
+
+ /* return int8 mask */
+ __forceinline __m128i mask8() const {
+ return _mm_movm_epi8(v);
+ }
+
+ /* return int32 mask */
+ __forceinline __m256i mask32() const {
+ return _mm256_movm_epi32(v);
+ }
+
+ /* return int64 mask */
+ __forceinline __m512i mask64() const {
+ return _mm512_movm_epi64(v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf(FalseTy) : v(0x00) {}
+ __forceinline vboolf(TrueTy) : v(0xff) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool operator [](size_t index) const {
+ assert(index < 8); return (mm512_mask2int(v) >> index) & 1;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator !(const vboolf8& a) { return _mm512_knot(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator &(const vboolf8& a, const vboolf8& b) { return _mm512_kand(a, b); }
+ __forceinline vboolf8 operator |(const vboolf8& a, const vboolf8& b) { return _mm512_kor(a, b); }
+ __forceinline vboolf8 operator ^(const vboolf8& a, const vboolf8& b) { return _mm512_kxor(a, b); }
+
+ __forceinline vboolf8 andn(const vboolf8& a, const vboolf8& b) { return _mm512_kandn(b, a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8& operator &=(vboolf8& a, const vboolf8& b) { return a = a & b; }
+ __forceinline vboolf8& operator |=(vboolf8& a, const vboolf8& b) { return a = a | b; }
+ __forceinline vboolf8& operator ^=(vboolf8& a, const vboolf8& b) { return a = a ^ b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator !=(const vboolf8& a, const vboolf8& b) { return _mm512_kxor(a, b); }
+ __forceinline vboolf8 operator ==(const vboolf8& a, const vboolf8& b) { return _mm512_kxnor(a, b); }
+
+ __forceinline vboolf8 select(const vboolf8& s, const vboolf8& a, const vboolf8& b) {
+ return _mm512_kor(_mm512_kand(s, a), _mm512_kandn(s, b));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reduction Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int all (const vboolf8& a) { return a.v == 0xff; }
+ __forceinline int any (const vboolf8& a) { return _mm512_kortestz(a, a) == 0; }
+ __forceinline int none(const vboolf8& a) { return _mm512_kortestz(a, a) != 0; }
+
+ __forceinline int all (const vboolf8& valid, const vboolf8& b) { return all((!valid) | b); }
+ __forceinline int any (const vboolf8& valid, const vboolf8& b) { return any(valid & b); }
+ __forceinline int none(const vboolf8& valid, const vboolf8& b) { return none(valid & b); }
+
+ __forceinline size_t movemask(const vboolf8& a) { return _mm512_kmov(a); }
+ __forceinline size_t popcnt (const vboolf8& a) { return popcnt(a.v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Conversion Operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int toInt(const vboolf8& a) { return mm512_mask2int(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Get/Set Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline bool get(const vboolf8& a, size_t index) { assert(index < 8); return (toInt(a) >> index) & 1; }
+ __forceinline void set(vboolf8& a, size_t index) { assert(index < 8); a |= 1 << index; }
+ __forceinline void clear(vboolf8& a, size_t index) { assert(index < 8); a = andn(a, 1 << index); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vboolf8& a)
+ {
+ cout << "<";
+ for (size_t i=0; i<8; i++) {
+ if ((a.v >> i) & 1) cout << "1"; else cout << "0";
+ }
+ return cout << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vdouble4_avx.h b/thirdparty/embree/common/simd/vdouble4_avx.h
new file mode 100644
index 0000000000..55326de7dd
--- /dev/null
+++ b/thirdparty/embree/common/simd/vdouble4_avx.h
@@ -0,0 +1,321 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 4-wide AVX 64-bit double type */
+ template<>
+ struct vdouble<4>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboold4 Bool;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { // data
+ __m256d v;
+ double i[4];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble() {}
+ __forceinline vdouble(const vdouble4& t) { v = t.v; }
+ __forceinline vdouble4& operator =(const vdouble4& f) { v = f.v; return *this; }
+
+ __forceinline vdouble(const __m256d& t) { v = t; }
+ __forceinline operator __m256d() const { return v; }
+
+ __forceinline vdouble(double i) {
+ v = _mm256_set1_pd(i);
+ }
+
+ __forceinline vdouble(double a, double b, double c, double d) {
+ v = _mm256_set_pd(d,c,b,a);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble(ZeroTy) : v(_mm256_setzero_pd()) {}
+ __forceinline vdouble(OneTy) : v(_mm256_set1_pd(1)) {}
+ __forceinline vdouble(StepTy) : v(_mm256_set_pd(3.0,2.0,1.0,0.0)) {}
+ __forceinline vdouble(ReverseStepTy) : v(_mm256_setr_pd(3.0,2.0,1.0,0.0)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline void store_nt(double *__restrict__ ptr, const vdouble4& a) {
+ _mm256_stream_pd(ptr, a);
+ }
+
+ static __forceinline vdouble4 loadu(const double* addr) {
+ return _mm256_loadu_pd(addr);
+ }
+
+ static __forceinline vdouble4 load(const vdouble4* addr) {
+ return _mm256_load_pd((double*)addr);
+ }
+
+ static __forceinline vdouble4 load(const double* addr) {
+ return _mm256_load_pd(addr);
+ }
+
+ static __forceinline void store(double* ptr, const vdouble4& v) {
+ _mm256_store_pd(ptr, v);
+ }
+
+ static __forceinline void storeu(double* ptr, const vdouble4& v) {
+ _mm256_storeu_pd(ptr, v);
+ }
+
+ static __forceinline vdouble4 broadcast(const void* a) { return _mm256_set1_pd(*(double*)a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline double& operator [](size_t index) { assert(index < 4); return i[index]; }
+ __forceinline const double& operator [](size_t index) const { assert(index < 4); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ __forceinline vdouble4 asDouble(const vllong4& a) { return _mm256_castsi256_pd(a); }
+ __forceinline vllong4 asLLong (const vdouble4& a) { return _mm256_castpd_si256(a); }
+#endif
+
+ __forceinline vdouble4 operator +(const vdouble4& a) { return a; }
+ __forceinline vdouble4 operator -(const vdouble4& a) { return _mm256_sub_pd(_mm256_setzero_pd(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble4 operator +(const vdouble4& a, const vdouble4& b) { return _mm256_add_pd(a, b); }
+ __forceinline vdouble4 operator +(const vdouble4& a, double b) { return a + vdouble4(b); }
+ __forceinline vdouble4 operator +(double a, const vdouble4& b) { return vdouble4(a) + b; }
+
+ __forceinline vdouble4 operator -(const vdouble4& a, const vdouble4& b) { return _mm256_sub_pd(a, b); }
+ __forceinline vdouble4 operator -(const vdouble4& a, double b) { return a - vdouble4(b); }
+ __forceinline vdouble4 operator -(double a, const vdouble4& b) { return vdouble4(a) - b; }
+
+ __forceinline vdouble4 operator *(const vdouble4& a, const vdouble4& b) { return _mm256_mul_pd(a, b); }
+ __forceinline vdouble4 operator *(const vdouble4& a, double b) { return a * vdouble4(b); }
+ __forceinline vdouble4 operator *(double a, const vdouble4& b) { return vdouble4(a) * b; }
+
+ __forceinline vdouble4 operator &(const vdouble4& a, const vdouble4& b) { return _mm256_and_pd(a, b); }
+ __forceinline vdouble4 operator &(const vdouble4& a, double b) { return a & vdouble4(b); }
+ __forceinline vdouble4 operator &(double a, const vdouble4& b) { return vdouble4(a) & b; }
+
+ __forceinline vdouble4 operator |(const vdouble4& a, const vdouble4& b) { return _mm256_or_pd(a, b); }
+ __forceinline vdouble4 operator |(const vdouble4& a, double b) { return a | vdouble4(b); }
+ __forceinline vdouble4 operator |(double a, const vdouble4& b) { return vdouble4(a) | b; }
+
+ __forceinline vdouble4 operator ^(const vdouble4& a, const vdouble4& b) { return _mm256_xor_pd(a, b); }
+ __forceinline vdouble4 operator ^(const vdouble4& a, double b) { return a ^ vdouble4(b); }
+ __forceinline vdouble4 operator ^(double a, const vdouble4& b) { return vdouble4(a) ^ b; }
+
+ __forceinline vdouble4 min(const vdouble4& a, const vdouble4& b) { return _mm256_min_pd(a, b); }
+ __forceinline vdouble4 min(const vdouble4& a, double b) { return min(a,vdouble4(b)); }
+ __forceinline vdouble4 min(double a, const vdouble4& b) { return min(vdouble4(a),b); }
+
+ __forceinline vdouble4 max(const vdouble4& a, const vdouble4& b) { return _mm256_max_pd(a, b); }
+ __forceinline vdouble4 max(const vdouble4& a, double b) { return max(a,vdouble4(b)); }
+ __forceinline vdouble4 max(double a, const vdouble4& b) { return max(vdouble4(a),b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__FMA__)
+ __forceinline vdouble4 madd (const vdouble4& a, const vdouble4& b, const vdouble4& c) { return _mm256_fmadd_pd(a,b,c); }
+ __forceinline vdouble4 msub (const vdouble4& a, const vdouble4& b, const vdouble4& c) { return _mm256_fmsub_pd(a,b,c); }
+ __forceinline vdouble4 nmadd(const vdouble4& a, const vdouble4& b, const vdouble4& c) { return _mm256_fnmadd_pd(a,b,c); }
+ __forceinline vdouble4 nmsub(const vdouble4& a, const vdouble4& b, const vdouble4& c) { return _mm256_fnmsub_pd(a,b,c); }
+#else
+ __forceinline vdouble4 madd (const vdouble4& a, const vdouble4& b, const vdouble4& c) { return a*b+c; }
+ __forceinline vdouble4 msub (const vdouble4& a, const vdouble4& b, const vdouble4& c) { return a*b-c; }
+ __forceinline vdouble4 nmadd(const vdouble4& a, const vdouble4& b, const vdouble4& c) { return -a*b+c;}
+ __forceinline vdouble4 nmsub(const vdouble4& a, const vdouble4& b, const vdouble4& c) { return -a*b-c; }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble4& operator +=(vdouble4& a, const vdouble4& b) { return a = a + b; }
+ __forceinline vdouble4& operator +=(vdouble4& a, double b) { return a = a + b; }
+
+ __forceinline vdouble4& operator -=(vdouble4& a, const vdouble4& b) { return a = a - b; }
+ __forceinline vdouble4& operator -=(vdouble4& a, double b) { return a = a - b; }
+
+ __forceinline vdouble4& operator *=(vdouble4& a, const vdouble4& b) { return a = a * b; }
+ __forceinline vdouble4& operator *=(vdouble4& a, double b) { return a = a * b; }
+
+ __forceinline vdouble4& operator &=(vdouble4& a, const vdouble4& b) { return a = a & b; }
+ __forceinline vdouble4& operator &=(vdouble4& a, double b) { return a = a & b; }
+
+ __forceinline vdouble4& operator |=(vdouble4& a, const vdouble4& b) { return a = a | b; }
+ __forceinline vdouble4& operator |=(vdouble4& a, double b) { return a = a | b; }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboold4 operator ==(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_EQ); }
+ __forceinline vboold4 operator !=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_NE); }
+ __forceinline vboold4 operator < (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_LT); }
+ __forceinline vboold4 operator >=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_GE); }
+ __forceinline vboold4 operator > (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_GT); }
+ __forceinline vboold4 operator <=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd_mask(a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboold4 operator ==(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_EQ_OQ); }
+ __forceinline vboold4 operator !=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NEQ_UQ); }
+ __forceinline vboold4 operator < (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_LT_OS); }
+ __forceinline vboold4 operator >=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NLT_US); }
+ __forceinline vboold4 operator > (const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_NLE_US); }
+ __forceinline vboold4 operator <=(const vdouble4& a, const vdouble4& b) { return _mm256_cmp_pd(a, b, _CMP_LE_OS); }
+#endif
+
+ __forceinline vboold4 operator ==(const vdouble4& a, double b) { return a == vdouble4(b); }
+ __forceinline vboold4 operator ==(double a, const vdouble4& b) { return vdouble4(a) == b; }
+
+ __forceinline vboold4 operator !=(const vdouble4& a, double b) { return a != vdouble4(b); }
+ __forceinline vboold4 operator !=(double a, const vdouble4& b) { return vdouble4(a) != b; }
+
+ __forceinline vboold4 operator < (const vdouble4& a, double b) { return a < vdouble4(b); }
+ __forceinline vboold4 operator < (double a, const vdouble4& b) { return vdouble4(a) < b; }
+
+ __forceinline vboold4 operator >=(const vdouble4& a, double b) { return a >= vdouble4(b); }
+ __forceinline vboold4 operator >=(double a, const vdouble4& b) { return vdouble4(a) >= b; }
+
+ __forceinline vboold4 operator > (const vdouble4& a, double b) { return a > vdouble4(b); }
+ __forceinline vboold4 operator > (double a, const vdouble4& b) { return vdouble4(a) > b; }
+
+ __forceinline vboold4 operator <=(const vdouble4& a, double b) { return a <= vdouble4(b); }
+ __forceinline vboold4 operator <=(double a, const vdouble4& b) { return vdouble4(a) <= b; }
+
+ __forceinline vboold4 eq(const vdouble4& a, const vdouble4& b) { return a == b; }
+ __forceinline vboold4 ne(const vdouble4& a, const vdouble4& b) { return a != b; }
+ __forceinline vboold4 lt(const vdouble4& a, const vdouble4& b) { return a < b; }
+ __forceinline vboold4 ge(const vdouble4& a, const vdouble4& b) { return a >= b; }
+ __forceinline vboold4 gt(const vdouble4& a, const vdouble4& b) { return a > b; }
+ __forceinline vboold4 le(const vdouble4& a, const vdouble4& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboold4 eq(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboold4 ne(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_NE); }
+ __forceinline vboold4 lt(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_LT); }
+ __forceinline vboold4 ge(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_GE); }
+ __forceinline vboold4 gt(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_GT); }
+ __forceinline vboold4 le(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return _mm256_mask_cmp_pd_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboold4 eq(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a == b); }
+ __forceinline vboold4 ne(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a != b); }
+ __forceinline vboold4 lt(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a < b); }
+ __forceinline vboold4 ge(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a >= b); }
+ __forceinline vboold4 gt(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a > b); }
+ __forceinline vboold4 le(const vboold4& mask, const vdouble4& a, const vdouble4& b) { return mask & (a <= b); }
+#endif
+
+ __forceinline vdouble4 select(const vboold4& m, const vdouble4& t, const vdouble4& f) {
+#if defined(__AVX512VL__)
+ return _mm256_mask_blend_pd(m, f, t);
+#else
+ return _mm256_blendv_pd(f, t, m);
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int i0, int i1>
+ __forceinline vdouble4 shuffle(const vdouble4& v) {
+ return _mm256_permute_pd(v, (i1 << 3) | (i0 << 2) | (i1 << 1) | i0);
+ }
+
+ template<int i>
+ __forceinline vdouble4 shuffle(const vdouble4& v) {
+ return shuffle<i, i>(v);
+ }
+
+ template<int i0, int i1>
+ __forceinline vdouble4 shuffle2(const vdouble4& v) {
+ return _mm256_permute2f128_pd(v, v, (i1 << 4) | i0);
+ }
+
+ __forceinline double toScalar(const vdouble4& v) {
+ return _mm_cvtsd_f64(_mm256_castpd256_pd128(v));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble4 vreduce_min2(const vdouble4& x) { return min(x, shuffle<1,0>(x)); }
+ __forceinline vdouble4 vreduce_min (const vdouble4& y) { const vdouble4 x = vreduce_min2(y); return min(x, shuffle2<1,0>(x)); }
+
+ __forceinline vdouble4 vreduce_max2(const vdouble4& x) { return max(x,shuffle<1,0>(x)); }
+ __forceinline vdouble4 vreduce_max (const vdouble4& y) { const vdouble4 x = vreduce_max2(y); return max(x, shuffle2<1,0>(x)); }
+
+ __forceinline vdouble4 vreduce_and2(const vdouble4& x) { return x & shuffle<1,0>(x); }
+ __forceinline vdouble4 vreduce_and (const vdouble4& y) { const vdouble4 x = vreduce_and2(y); return x & shuffle2<1,0>(x); }
+
+ __forceinline vdouble4 vreduce_or2(const vdouble4& x) { return x | shuffle<1,0>(x); }
+ __forceinline vdouble4 vreduce_or (const vdouble4& y) { const vdouble4 x = vreduce_or2(y); return x | shuffle2<1,0>(x); }
+
+ __forceinline vdouble4 vreduce_add2(const vdouble4& x) { return x + shuffle<1,0>(x); }
+ __forceinline vdouble4 vreduce_add (const vdouble4& y) { const vdouble4 x = vreduce_add2(y); return x + shuffle2<1,0>(x); }
+
+ __forceinline double reduce_add(const vdouble4& a) { return toScalar(vreduce_add(a)); }
+ __forceinline double reduce_min(const vdouble4& a) { return toScalar(vreduce_min(a)); }
+ __forceinline double reduce_max(const vdouble4& a) { return toScalar(vreduce_max(a)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vdouble4& v)
+ {
+ cout << "<" << v[0];
+ for (size_t i=1; i<4; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vdouble8_avx512.h b/thirdparty/embree/common/simd/vdouble8_avx512.h
new file mode 100644
index 0000000000..98d21bfe4a
--- /dev/null
+++ b/thirdparty/embree/common/simd/vdouble8_avx512.h
@@ -0,0 +1,351 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 8-wide AVX-512 64-bit double type */
+ template<>
+ struct vdouble<8>
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef vboold8 Bool;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m512d v;
+ double i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble() {}
+ __forceinline vdouble(const vdouble8& t) { v = t.v; }
+ __forceinline vdouble8& operator =(const vdouble8& f) { v = f.v; return *this; }
+
+ __forceinline vdouble(const __m512d& t) { v = t; }
+ __forceinline operator __m512d() const { return v; }
+ __forceinline operator __m256d() const { return _mm512_castpd512_pd256(v); }
+
+ __forceinline vdouble(double i) {
+ v = _mm512_set1_pd(i);
+ }
+
+ __forceinline vdouble(double a, double b, double c, double d) {
+ v = _mm512_set4_pd(d,c,b,a);
+ }
+
+ __forceinline vdouble(double a0, double a1, double a2, double a3,
+ double a4, double a5, double a6, double a7)
+ {
+ v = _mm512_set_pd(a7,a6,a5,a4,a3,a2,a1,a0);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble(ZeroTy) : v(_mm512_setzero_pd()) {}
+ __forceinline vdouble(OneTy) : v(_mm512_set1_pd(1)) {}
+ __forceinline vdouble(StepTy) : v(_mm512_set_pd(7.0,6.0,5.0,4.0,3.0,2.0,1.0,0.0)) {}
+ __forceinline vdouble(ReverseStepTy) : v(_mm512_setr_pd(7.0,6.0,5.0,4.0,3.0,2.0,1.0,0.0)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline void store_nt(void *__restrict__ ptr, const vdouble8& a) {
+ _mm512_stream_pd((double*)ptr, a);
+ }
+
+ static __forceinline vdouble8 loadu(const void* addr) {
+ return _mm512_loadu_pd((double*)addr);
+ }
+
+ static __forceinline vdouble8 load(const vdouble8* addr) {
+ return _mm512_load_pd((double*)addr);
+ }
+
+ static __forceinline vdouble8 load(const double* addr) {
+ return _mm512_load_pd(addr);
+ }
+
+ static __forceinline void store(void* ptr, const vdouble8& v) {
+ _mm512_store_pd(ptr, v);
+ }
+
+ static __forceinline void storeu(void* ptr, const vdouble8& v) {
+ _mm512_storeu_pd(ptr, v);
+ }
+
+ static __forceinline void storeu(const vboold8& mask, double* ptr, const vdouble8& f) {
+ _mm512_mask_storeu_pd(ptr, mask, f);
+ }
+
+ static __forceinline void store(const vboold8& mask, void* addr, const vdouble8& v2) {
+ _mm512_mask_store_pd(addr, mask, v2);
+ }
+
+ static __forceinline vdouble8 compact(const vboold8& mask, vdouble8& v) {
+ return _mm512_mask_compress_pd(v, mask, v);
+ }
+
+ static __forceinline vdouble8 compact(const vboold8& mask, const vdouble8& a, vdouble8& b) {
+ return _mm512_mask_compress_pd(a, mask, b);
+ }
+
+ static __forceinline vdouble8 broadcast(const void* a) { return _mm512_set1_pd(*(double*)a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline double& operator [](size_t index) { assert(index < 8); return i[index]; }
+ __forceinline const double& operator [](size_t index) const { assert(index < 8); return i[index]; }
+
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8 asDouble(const vllong8& a) { return _mm512_castsi512_pd(a); }
+ __forceinline vllong8 asLLong (const vdouble8& a) { return _mm512_castpd_si512(a); }
+
+ __forceinline vdouble8 operator +(const vdouble8& a) { return a; }
+ __forceinline vdouble8 operator -(const vdouble8& a) { return _mm512_sub_pd(_mm512_setzero_pd(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8 operator +(const vdouble8& a, const vdouble8& b) { return _mm512_add_pd(a, b); }
+ __forceinline vdouble8 operator +(const vdouble8& a, double b) { return a + vdouble8(b); }
+ __forceinline vdouble8 operator +(double a, const vdouble8& b) { return vdouble8(a) + b; }
+
+ __forceinline vdouble8 operator -(const vdouble8& a, const vdouble8& b) { return _mm512_sub_pd(a, b); }
+ __forceinline vdouble8 operator -(const vdouble8& a, double b) { return a - vdouble8(b); }
+ __forceinline vdouble8 operator -(double a, const vdouble8& b) { return vdouble8(a) - b; }
+
+ __forceinline vdouble8 operator *(const vdouble8& a, const vdouble8& b) { return _mm512_mul_pd(a, b); }
+ __forceinline vdouble8 operator *(const vdouble8& a, double b) { return a * vdouble8(b); }
+ __forceinline vdouble8 operator *(double a, const vdouble8& b) { return vdouble8(a) * b; }
+
+ __forceinline vdouble8 operator &(const vdouble8& a, const vdouble8& b) { return _mm512_and_pd(a, b); }
+ __forceinline vdouble8 operator &(const vdouble8& a, double b) { return a & vdouble8(b); }
+ __forceinline vdouble8 operator &(double a, const vdouble8& b) { return vdouble8(a) & b; }
+
+ __forceinline vdouble8 operator |(const vdouble8& a, const vdouble8& b) { return _mm512_or_pd(a, b); }
+ __forceinline vdouble8 operator |(const vdouble8& a, double b) { return a | vdouble8(b); }
+ __forceinline vdouble8 operator |(double a, const vdouble8& b) { return vdouble8(a) | b; }
+
+ __forceinline vdouble8 operator ^(const vdouble8& a, const vdouble8& b) { return _mm512_xor_pd(a, b); }
+ __forceinline vdouble8 operator ^(const vdouble8& a, double b) { return a ^ vdouble8(b); }
+ __forceinline vdouble8 operator ^(double a, const vdouble8& b) { return vdouble8(a) ^ b; }
+
+ __forceinline vdouble8 operator <<(const vdouble8& a, const unsigned int n) { return _mm512_castsi512_pd(_mm512_slli_epi64(_mm512_castpd_si512(a), n)); }
+ __forceinline vdouble8 operator >>(const vdouble8& a, const unsigned int n) { return _mm512_castsi512_pd(_mm512_srai_epi64(_mm512_castpd_si512(a), n)); }
+
+ __forceinline vdouble8 operator <<(const vdouble8& a, const vllong8& n) { return _mm512_castsi512_pd(_mm512_sllv_epi64(_mm512_castpd_si512(a), n)); }
+ __forceinline vdouble8 operator >>(const vdouble8& a, const vllong8& n) { return _mm512_castsi512_pd(_mm512_srav_epi64(_mm512_castpd_si512(a), n)); }
+
+ __forceinline vdouble8 sll (const vdouble8& a, const unsigned int b) { return _mm512_castsi512_pd(_mm512_slli_epi64(_mm512_castpd_si512(a), b)); }
+ __forceinline vdouble8 sra (const vdouble8& a, const unsigned int b) { return _mm512_castsi512_pd(_mm512_srai_epi64(_mm512_castpd_si512(a), b)); }
+ __forceinline vdouble8 srl (const vdouble8& a, const unsigned int b) { return _mm512_castsi512_pd(_mm512_srli_epi64(_mm512_castpd_si512(a), b)); }
+
+ __forceinline vdouble8 min(const vdouble8& a, const vdouble8& b) { return _mm512_min_pd(a, b); }
+ __forceinline vdouble8 min(const vdouble8& a, double b) { return min(a,vdouble8(b)); }
+ __forceinline vdouble8 min(double a, const vdouble8& b) { return min(vdouble8(a),b); }
+
+ __forceinline vdouble8 max(const vdouble8& a, const vdouble8& b) { return _mm512_max_pd(a, b); }
+ __forceinline vdouble8 max(const vdouble8& a, double b) { return max(a,vdouble8(b)); }
+ __forceinline vdouble8 max(double a, const vdouble8& b) { return max(vdouble8(a),b); }
+
+ __forceinline vdouble8 mask_add(const vboold8& mask, vdouble8& c, const vdouble8& a, const vdouble8& b) { return _mm512_mask_add_pd(c,mask,a,b); }
+ __forceinline vdouble8 mask_sub(const vboold8& mask, vdouble8& c, const vdouble8& a, const vdouble8& b) { return _mm512_mask_sub_pd(c,mask,a,b); }
+
+ __forceinline vdouble8 mask_and(const vboold8& m,vdouble8& c, const vdouble8& a, const vdouble8& b) { return _mm512_mask_and_pd(c,m,a,b); }
+ __forceinline vdouble8 mask_or (const vboold8& m,vdouble8& c, const vdouble8& a, const vdouble8& b) { return _mm512_mask_or_pd(c,m,a,b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8 madd (const vdouble8& a, const vdouble8& b, const vdouble8& c) { return _mm512_fmadd_pd(a,b,c); }
+ __forceinline vdouble8 msub (const vdouble8& a, const vdouble8& b, const vdouble8& c) { return _mm512_fmsub_pd(a,b,c); }
+ __forceinline vdouble8 nmadd(const vdouble8& a, const vdouble8& b, const vdouble8& c) { return _mm512_fnmadd_pd(a,b,c); }
+ __forceinline vdouble8 nmsub(const vdouble8& a, const vdouble8& b, const vdouble8& c) { return _mm512_fnmsub_pd(a,b,c); }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8& operator +=(vdouble8& a, const vdouble8& b) { return a = a + b; }
+ __forceinline vdouble8& operator +=(vdouble8& a, double b) { return a = a + b; }
+
+ __forceinline vdouble8& operator -=(vdouble8& a, const vdouble8& b) { return a = a - b; }
+ __forceinline vdouble8& operator -=(vdouble8& a, double b) { return a = a - b; }
+
+ __forceinline vdouble8& operator *=(vdouble8& a, const vdouble8& b) { return a = a * b; }
+ __forceinline vdouble8& operator *=(vdouble8& a, double b) { return a = a * b; }
+
+ __forceinline vdouble8& operator &=(vdouble8& a, const vdouble8& b) { return a = a & b; }
+ __forceinline vdouble8& operator &=(vdouble8& a, double b) { return a = a & b; }
+
+ __forceinline vdouble8& operator |=(vdouble8& a, const vdouble8& b) { return a = a | b; }
+ __forceinline vdouble8& operator |=(vdouble8& a, double b) { return a = a | b; }
+
+ __forceinline vdouble8& operator <<=(vdouble8& a, const double b) { return a = a << b; }
+ __forceinline vdouble8& operator >>=(vdouble8& a, const double b) { return a = a >> b; }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 operator ==(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 operator ==(const vdouble8& a, double b) { return a == vdouble8(b); }
+ __forceinline vboold8 operator ==(double a, const vdouble8& b) { return vdouble8(a) == b; }
+
+ __forceinline vboold8 operator !=(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 operator !=(const vdouble8& a, double b) { return a != vdouble8(b); }
+ __forceinline vboold8 operator !=(double a, const vdouble8& b) { return vdouble8(a) != b; }
+
+ __forceinline vboold8 operator < (const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 operator < (const vdouble8& a, double b) { return a < vdouble8(b); }
+ __forceinline vboold8 operator < (double a, const vdouble8& b) { return vdouble8(a) < b; }
+
+ __forceinline vboold8 operator >=(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 operator >=(const vdouble8& a, double b) { return a >= vdouble8(b); }
+ __forceinline vboold8 operator >=(double a, const vdouble8& b) { return vdouble8(a) >= b; }
+
+ __forceinline vboold8 operator > (const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 operator > (const vdouble8& a, double b) { return a > vdouble8(b); }
+ __forceinline vboold8 operator > (double a, const vdouble8& b) { return vdouble8(a) > b; }
+
+ __forceinline vboold8 operator <=(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboold8 operator <=(const vdouble8& a, double b) { return a <= vdouble8(b); }
+ __forceinline vboold8 operator <=(double a, const vdouble8& b) { return vdouble8(a) <= b; }
+
+ __forceinline vboold8 eq(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 ne(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 lt(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 ge(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 gt(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 le(const vdouble8& a, const vdouble8& b) { return _mm512_cmp_pd_mask(a,b,_MM_CMPINT_LE); }
+
+ __forceinline vboold8 eq(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 ne(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 lt(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 ge(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 gt(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 le(const vboold8 mask, const vdouble8& a, const vdouble8& b) { return _mm512_mask_cmp_pd_mask(mask,a,b,_MM_CMPINT_LE); }
+
+ __forceinline vdouble8 select(const vboold8& m, const vdouble8& t, const vdouble8& f) {
+ return _mm512_mask_or_pd(f,m,t,t);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int i0, int i1>
+ __forceinline vdouble8 shuffle(const vdouble8& v) {
+ return _mm512_permute_pd(v, (i1 << 7) | (i0 << 6) | (i1 << 5) | (i0 << 4) | (i1 << 3) | (i0 << 2) | (i1 << 1) | i0);
+ }
+
+ template<int i>
+ __forceinline vdouble8 shuffle(const vdouble8& v) {
+ return shuffle<i, i>(v);
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vdouble8 shuffle(const vdouble8& v) {
+ return _mm512_permutex_pd(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vdouble8 shuffle4(const vdouble8& v) {
+ return _mm512_shuffle_f64x2(v, v, _MM_SHUFFLE(i1*2+1, i1*2, i0*2+1, i0*2));
+ }
+
+ template<int i>
+ __forceinline vdouble8 shuffle4(const vdouble8& v) {
+ return shuffle4<i, i>(v);
+ }
+
+ template<int i>
+ __forceinline vdouble8 align_shift_right(const vdouble8& a, const vdouble8& b) {
+ return _mm512_castsi512_pd(_mm512_alignr_epi64(_mm512_castpd_si512(a), _mm512_castpd_si512(b), i));
+ }
+
+ __forceinline double toScalar(const vdouble8& v) {
+ return _mm_cvtsd_f64(_mm512_castpd512_pd128(v));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8 vreduce_add2(vdouble8 x) { return x + shuffle<1,0,3,2>(x); }
+ __forceinline vdouble8 vreduce_add4(vdouble8 x) { x = vreduce_add2(x); return x + shuffle<2,3,0,1>(x); }
+ __forceinline vdouble8 vreduce_add (vdouble8 x) { x = vreduce_add4(x); return x + shuffle4<1,0>(x); }
+
+ __forceinline vdouble8 vreduce_min2(vdouble8 x) { return min(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vdouble8 vreduce_min4(vdouble8 x) { x = vreduce_min2(x); return min(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vdouble8 vreduce_min (vdouble8 x) { x = vreduce_min4(x); return min(x, shuffle4<1,0>(x)); }
+
+ __forceinline vdouble8 vreduce_max2(vdouble8 x) { return max(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vdouble8 vreduce_max4(vdouble8 x) { x = vreduce_max2(x); return max(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vdouble8 vreduce_max (vdouble8 x) { x = vreduce_max4(x); return max(x, shuffle4<1,0>(x)); }
+
+ __forceinline double reduce_add(const vdouble8& v) { return toScalar(vreduce_add(v)); }
+ __forceinline double reduce_min(const vdouble8& v) { return toScalar(vreduce_min(v)); }
+ __forceinline double reduce_max(const vdouble8& v) { return toScalar(vreduce_max(v)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vdouble8 permute(const vdouble8& v, const vllong8& index) {
+ return _mm512_permutexvar_pd(index, v);
+ }
+
+ __forceinline vdouble8 reverse(const vdouble8& a) {
+ return permute(a, vllong8(reverse_step));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vdouble8& v)
+ {
+ cout << "<" << v[0];
+ for (size_t i=1; i<8; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vfloat16_avx512.h b/thirdparty/embree/common/simd/vfloat16_avx512.h
new file mode 100644
index 0000000000..9f1e2459c4
--- /dev/null
+++ b/thirdparty/embree/common/simd/vfloat16_avx512.h
@@ -0,0 +1,615 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 16-wide AVX-512 float type */
+ template<>
+ struct vfloat<16>
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef vboolf16 Bool;
+ typedef vint16 Int;
+ typedef vfloat16 Float;
+
+ enum { size = 16 }; // number of SIMD elements
+ union { // data
+ __m512 v;
+ float f[16];
+ int i[16];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat() {}
+ __forceinline vfloat(const vfloat16& t) { v = t; }
+ __forceinline vfloat16& operator =(const vfloat16& f) { v = f.v; return *this; }
+
+ __forceinline vfloat(const __m512& t) { v = t; }
+ __forceinline operator __m512() const { return v; }
+ __forceinline operator __m256() const { return _mm512_castps512_ps256(v); }
+ __forceinline operator __m128() const { return _mm512_castps512_ps128(v); }
+
+ __forceinline vfloat(float f) {
+ v = _mm512_set1_ps(f);
+ }
+
+ __forceinline vfloat(float a, float b, float c, float d) {
+ v = _mm512_set4_ps(a, b, c, d);
+ }
+
+ __forceinline vfloat(const vfloat4& i) {
+ v = _mm512_broadcast_f32x4(i);
+ }
+
+ __forceinline vfloat(const vfloat4& a, const vfloat4& b, const vfloat4& c, const vfloat4& d) {
+ v = _mm512_castps128_ps512(a);
+ v = _mm512_insertf32x4(v, b, 1);
+ v = _mm512_insertf32x4(v, c, 2);
+ v = _mm512_insertf32x4(v, d, 3);
+ }
+
+ __forceinline vfloat(const vboolf16& mask, const vfloat4& a, const vfloat4& b) {
+ v = _mm512_broadcast_f32x4(a);
+ v = _mm512_mask_broadcast_f32x4(v,mask,b);
+ }
+
+ __forceinline vfloat(const vfloat8& i) {
+ v = _mm512_castpd_ps(_mm512_broadcast_f64x4(_mm256_castps_pd(i)));
+ }
+
+ __forceinline vfloat(const vfloat8& a, const vfloat8& b) {
+ v = _mm512_castps256_ps512(a);
+#if defined(__AVX512DQ__)
+ v = _mm512_insertf32x8(v, b, 1);
+#else
+ v = _mm512_castpd_ps(_mm512_insertf64x4(_mm512_castps_pd(v), _mm256_castps_pd(b), 1));
+#endif
+ }
+
+ /* WARNING: due to f64x4 the mask is considered as an 8bit mask */
+ /*__forceinline vfloat(const vboolf16& mask, const vfloat8& a, const vfloat8& b) {
+ __m512d aa = _mm512_broadcast_f64x4(_mm256_castps_pd(a));
+ aa = _mm512_mask_broadcast_f64x4(aa,mask,_mm256_castps_pd(b));
+ v = _mm512_castpd_ps(aa);
+ }*/
+
+ __forceinline explicit vfloat(const vint16& a) {
+ v = _mm512_cvtepi32_ps(a);
+ }
+
+ __forceinline explicit vfloat(const vuint16& a) {
+ v = _mm512_cvtepu32_ps(a);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat(ZeroTy) : v(_mm512_setzero_ps()) {}
+ __forceinline vfloat(OneTy) : v(_mm512_set1_ps(1.0f)) {}
+ __forceinline vfloat(PosInfTy) : v(_mm512_set1_ps(pos_inf)) {}
+ __forceinline vfloat(NegInfTy) : v(_mm512_set1_ps(neg_inf)) {}
+ __forceinline vfloat(StepTy) : v(_mm512_set_ps(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) {}
+ __forceinline vfloat(NaNTy) : v(_mm512_set1_ps(nan)) {}
+ __forceinline vfloat(UndefinedTy) : v(_mm512_undefined_ps()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vfloat16 load (const void* ptr) { return _mm512_load_ps((float*)ptr); }
+ static __forceinline vfloat16 loadu(const void* ptr) { return _mm512_loadu_ps((float*)ptr); }
+
+ static __forceinline vfloat16 load (const vboolf16& mask, const void* ptr) { return _mm512_mask_load_ps (_mm512_setzero_ps(),mask,(float*)ptr); }
+ static __forceinline vfloat16 loadu(const vboolf16& mask, const void* ptr) { return _mm512_mask_loadu_ps(_mm512_setzero_ps(),mask,(float*)ptr); }
+
+ static __forceinline void store (void* ptr, const vfloat16& v) { _mm512_store_ps ((float*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vfloat16& v) { _mm512_storeu_ps((float*)ptr,v); }
+
+ static __forceinline void store (const vboolf16& mask, void* ptr, const vfloat16& v) { _mm512_mask_store_ps ((float*)ptr,mask,v); }
+ static __forceinline void storeu(const vboolf16& mask, void* ptr, const vfloat16& v) { _mm512_mask_storeu_ps((float*)ptr,mask,v); }
+
+ static __forceinline void store_nt(void* __restrict__ ptr, const vfloat16& a) {
+ _mm512_stream_ps((float*)ptr,a);
+ }
+
+ static __forceinline vfloat16 broadcast(const float* f) {
+ return _mm512_set1_ps(*f);
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat16 gather(const float* ptr, const vint16& index) {
+ return _mm512_i32gather_ps(index, ptr, scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat16 gather(const vboolf16& mask, const float* ptr, const vint16& index) {
+ vfloat16 r = zero;
+ return _mm512_mask_i32gather_ps(r, mask, index, ptr, scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(float* ptr, const vint16& index, const vfloat16& v) {
+ _mm512_i32scatter_ps(ptr, index, v, scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf16& mask, float* ptr, const vint16& index, const vfloat16& v) {
+ _mm512_mask_i32scatter_ps(ptr, mask, index, v, scale);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float& operator [](size_t index) { assert(index < 16); return f[index]; }
+ __forceinline const float& operator [](size_t index) const { assert(index < 16); return f[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 asFloat(const vint16& a) { return _mm512_castsi512_ps(a); }
+ __forceinline vint16 asInt (const vfloat16& a) { return _mm512_castps_si512(a); }
+ __forceinline vuint16 asUInt (const vfloat16& a) { return _mm512_castps_si512(a); }
+
+ __forceinline vint16 toInt (const vfloat16& a) { return vint16(a); }
+ __forceinline vfloat16 toFloat(const vint16& a) { return vfloat16(a); }
+
+ __forceinline vfloat16 operator +(const vfloat16& a) { return a; }
+ __forceinline vfloat16 operator -(const vfloat16& a) { return _mm512_mul_ps(a,vfloat16(-1)); }
+
+ __forceinline vfloat16 abs (const vfloat16& a) { return _mm512_castsi512_ps(_mm512_and_epi32(_mm512_castps_si512(a),_mm512_set1_epi32(0x7FFFFFFF))); }
+ __forceinline vfloat16 signmsk(const vfloat16& a) { return _mm512_castsi512_ps(_mm512_and_epi32(_mm512_castps_si512(a),_mm512_set1_epi32(0x80000000))); }
+
+ __forceinline vfloat16 rcp(const vfloat16& a) {
+ const vfloat16 r = _mm512_rcp14_ps(a);
+ return _mm512_mul_ps(r, _mm512_fnmadd_ps(r, a, vfloat16(2.0f)));
+ }
+
+ __forceinline vfloat16 sqr (const vfloat16& a) { return _mm512_mul_ps(a,a); }
+ __forceinline vfloat16 sqrt(const vfloat16& a) { return _mm512_sqrt_ps(a); }
+
+ __forceinline vfloat16 rsqrt(const vfloat16& a)
+ {
+ const vfloat16 r = _mm512_rsqrt14_ps(a);
+ return _mm512_fmadd_ps(_mm512_set1_ps(1.5f), r,
+ _mm512_mul_ps(_mm512_mul_ps(_mm512_mul_ps(a, _mm512_set1_ps(-0.5f)), r), _mm512_mul_ps(r, r)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 operator +(const vfloat16& a, const vfloat16& b) { return _mm512_add_ps(a, b); }
+ __forceinline vfloat16 operator +(const vfloat16& a, float b) { return a + vfloat16(b); }
+ __forceinline vfloat16 operator +(float a, const vfloat16& b) { return vfloat16(a) + b; }
+
+ __forceinline vfloat16 operator -(const vfloat16& a, const vfloat16& b) { return _mm512_sub_ps(a, b); }
+ __forceinline vfloat16 operator -(const vfloat16& a, float b) { return a - vfloat16(b); }
+ __forceinline vfloat16 operator -(float a, const vfloat16& b) { return vfloat16(a) - b; }
+
+ __forceinline vfloat16 operator *(const vfloat16& a, const vfloat16& b) { return _mm512_mul_ps(a, b); }
+ __forceinline vfloat16 operator *(const vfloat16& a, float b) { return a * vfloat16(b); }
+ __forceinline vfloat16 operator *(float a, const vfloat16& b) { return vfloat16(a) * b; }
+
+ __forceinline vfloat16 operator /(const vfloat16& a, const vfloat16& b) { return _mm512_div_ps(a,b); }
+ __forceinline vfloat16 operator /(const vfloat16& a, float b) { return a/vfloat16(b); }
+ __forceinline vfloat16 operator /(float a, const vfloat16& b) { return vfloat16(a)/b; }
+
+ __forceinline vfloat16 operator &(const vfloat16& a, const vfloat16& b) { return _mm512_and_ps(a,b); }
+ __forceinline vfloat16 operator |(const vfloat16& a, const vfloat16& b) { return _mm512_or_ps(a,b); }
+ __forceinline vfloat16 operator ^(const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_xor_epi32(_mm512_castps_si512(a),_mm512_castps_si512(b)));
+ }
+
+ __forceinline vfloat16 min(const vfloat16& a, const vfloat16& b) { return _mm512_min_ps(a,b); }
+ __forceinline vfloat16 min(const vfloat16& a, float b) { return _mm512_min_ps(a,vfloat16(b)); }
+ __forceinline vfloat16 min(const float& a, const vfloat16& b) { return _mm512_min_ps(vfloat16(a),b); }
+
+ __forceinline vfloat16 max(const vfloat16& a, const vfloat16& b) { return _mm512_max_ps(a,b); }
+ __forceinline vfloat16 max(const vfloat16& a, float b) { return _mm512_max_ps(a,vfloat16(b)); }
+ __forceinline vfloat16 max(const float& a, const vfloat16& b) { return _mm512_max_ps(vfloat16(a),b); }
+
+ __forceinline vfloat16 mini(const vfloat16& a, const vfloat16& b) {
+ const vint16 ai = _mm512_castps_si512(a);
+ const vint16 bi = _mm512_castps_si512(b);
+ const vint16 ci = _mm512_min_epi32(ai,bi);
+ return _mm512_castsi512_ps(ci);
+ }
+
+ __forceinline vfloat16 maxi(const vfloat16& a, const vfloat16& b) {
+ const vint16 ai = _mm512_castps_si512(a);
+ const vint16 bi = _mm512_castps_si512(b);
+ const vint16 ci = _mm512_max_epi32(ai,bi);
+ return _mm512_castsi512_ps(ci);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 madd (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmadd_ps(a,b,c); }
+ __forceinline vfloat16 msub (const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fmsub_ps(a,b,c); }
+ __forceinline vfloat16 nmadd(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fnmadd_ps(a,b,c); }
+ __forceinline vfloat16 nmsub(const vfloat16& a, const vfloat16& b, const vfloat16& c) { return _mm512_fnmsub_ps(a,b,c); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16& operator +=(vfloat16& a, const vfloat16& b) { return a = a + b; }
+ __forceinline vfloat16& operator +=(vfloat16& a, float b) { return a = a + b; }
+
+ __forceinline vfloat16& operator -=(vfloat16& a, const vfloat16& b) { return a = a - b; }
+ __forceinline vfloat16& operator -=(vfloat16& a, float b) { return a = a - b; }
+
+ __forceinline vfloat16& operator *=(vfloat16& a, const vfloat16& b) { return a = a * b; }
+ __forceinline vfloat16& operator *=(vfloat16& a, float b) { return a = a * b; }
+
+ __forceinline vfloat16& operator /=(vfloat16& a, const vfloat16& b) { return a = a / b; }
+ __forceinline vfloat16& operator /=(vfloat16& a, float b) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator ==(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 operator ==(const vfloat16& a, float b) { return a == vfloat16(b); }
+ __forceinline vboolf16 operator ==(float a, const vfloat16& b) { return vfloat16(a) == b; }
+
+ __forceinline vboolf16 operator !=(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 operator !=(const vfloat16& a, float b) { return a != vfloat16(b); }
+ __forceinline vboolf16 operator !=(float a, const vfloat16& b) { return vfloat16(a) != b; }
+
+ __forceinline vboolf16 operator < (const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 operator < (const vfloat16& a, float b) { return a < vfloat16(b); }
+ __forceinline vboolf16 operator < (float a, const vfloat16& b) { return vfloat16(a) < b; }
+
+ __forceinline vboolf16 operator >=(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 operator >=(const vfloat16& a, float b) { return a >= vfloat16(b); }
+ __forceinline vboolf16 operator >=(float a, const vfloat16& b) { return vfloat16(a) >= b; }
+
+ __forceinline vboolf16 operator > (const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 operator > (const vfloat16& a, float b) { return a > vfloat16(b); }
+ __forceinline vboolf16 operator > (float a, const vfloat16& b) { return vfloat16(a) > b; }
+
+ __forceinline vboolf16 operator <=(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 operator <=(const vfloat16& a, float b) { return a <= vfloat16(b); }
+ __forceinline vboolf16 operator <=(float a, const vfloat16& b) { return vfloat16(a) <= b; }
+
+ __forceinline vboolf16 eq(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vfloat16& a, const vfloat16& b) { return _mm512_cmp_ps_mask(a,b,_MM_CMPINT_LE); }
+
+ __forceinline vboolf16 eq(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vboolf16& mask, const vfloat16& a, const vfloat16& b) { return _mm512_mask_cmp_ps_mask(mask,a,b,_MM_CMPINT_LE); }
+
+ __forceinline vfloat16 select(const vboolf16& s, const vfloat16& t, const vfloat16& f) {
+ return _mm512_mask_blend_ps(s, f, t);
+ }
+
+ __forceinline vfloat16 lerp(const vfloat16& a, const vfloat16& b, const vfloat16& t) {
+ return madd(t,b-a,a);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 floor(const vfloat16& a) {
+ return _mm512_floor_ps(a);
+ }
+ __forceinline vfloat16 ceil (const vfloat16& a) {
+ return _mm512_ceil_ps(a);
+ }
+ __forceinline vfloat16 round (const vfloat16& a) {
+ return _mm512_roundscale_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
+ }
+ __forceinline vint16 floori (const vfloat16& a) {
+ return _mm512_cvt_roundps_epi32(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 unpacklo(const vfloat16& a, const vfloat16& b) { return _mm512_unpacklo_ps(a, b); }
+ __forceinline vfloat16 unpackhi(const vfloat16& a, const vfloat16& b) { return _mm512_unpackhi_ps(a, b); }
+
+ template<int i>
+ __forceinline vfloat16 shuffle(const vfloat16& v) {
+ return _mm512_permute_ps(v, _MM_SHUFFLE(i, i, i, i));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat16 shuffle(const vfloat16& v) {
+ return _mm512_permute_ps(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i>
+ __forceinline vfloat16 shuffle4(const vfloat16& v) {
+ return _mm512_shuffle_f32x4(v, v ,_MM_SHUFFLE(i, i, i, i));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat16 shuffle4(const vfloat16& v) {
+ return _mm512_shuffle_f32x4(v, v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ __forceinline vfloat16 interleave4_even(const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_mask_permutex_epi64(_mm512_castps_si512(a), mm512_int2mask(0xcc), _mm512_castps_si512(b), (_MM_PERM_ENUM)0x4e));
+ }
+
+ __forceinline vfloat16 interleave4_odd(const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_mask_permutex_epi64(_mm512_castps_si512(b), mm512_int2mask(0x33), _mm512_castps_si512(a), (_MM_PERM_ENUM)0x4e));
+ }
+
+ __forceinline vfloat16 permute(vfloat16 v, __m512i index) {
+ return _mm512_castsi512_ps(_mm512_permutexvar_epi32(index, _mm512_castps_si512(v)));
+ }
+
+ __forceinline vfloat16 reverse(const vfloat16& v) {
+ return permute(v,_mm512_setr_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0));
+ }
+
+ template<int i>
+ __forceinline vfloat16 align_shift_right(const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_alignr_epi32(_mm512_castps_si512(a),_mm512_castps_si512(b),i));
+ };
+
+ template<int i>
+ __forceinline vfloat16 mask_align_shift_right(const vboolf16& mask, vfloat16& c, const vfloat16& a, const vfloat16& b) {
+ return _mm512_castsi512_ps(_mm512_mask_alignr_epi32(_mm512_castps_si512(c),mask,_mm512_castps_si512(a),_mm512_castps_si512(b),i));
+ };
+
+ __forceinline vfloat16 shift_left_1(const vfloat16& a) {
+ vfloat16 z = zero;
+ return mask_align_shift_right<15>(0xfffe,z,a,a);
+ }
+
+ __forceinline vfloat16 shift_right_1(const vfloat16& x) {
+ return align_shift_right<1>(zero,x);
+ }
+
+ __forceinline float toScalar(const vfloat16& v) { return mm512_cvtss_f32(v); }
+
+
+ template<int i> __forceinline vfloat16 insert4(const vfloat16& a, const vfloat4& b) { return _mm512_insertf32x4(a, b, i); }
+
+ template<int N, int i>
+ vfloat<N> extractN(const vfloat16& v);
+
+ template<> __forceinline vfloat4 extractN<4,0>(const vfloat16& v) { return _mm512_castps512_ps128(v); }
+ template<> __forceinline vfloat4 extractN<4,1>(const vfloat16& v) { return _mm512_extractf32x4_ps(v, 1); }
+ template<> __forceinline vfloat4 extractN<4,2>(const vfloat16& v) { return _mm512_extractf32x4_ps(v, 2); }
+ template<> __forceinline vfloat4 extractN<4,3>(const vfloat16& v) { return _mm512_extractf32x4_ps(v, 3); }
+
+ template<> __forceinline vfloat8 extractN<8,0>(const vfloat16& v) { return _mm512_castps512_ps256(v); }
+ template<> __forceinline vfloat8 extractN<8,1>(const vfloat16& v) { return _mm512_extractf32x8_ps(v, 1); }
+
+ template<int i> __forceinline vfloat4 extract4 (const vfloat16& v) { return _mm512_extractf32x4_ps(v, i); }
+ template<> __forceinline vfloat4 extract4<0>(const vfloat16& v) { return _mm512_castps512_ps128(v); }
+
+ template<int i> __forceinline vfloat8 extract8 (const vfloat16& v) { return _mm512_extractf32x8_ps(v, i); }
+ template<> __forceinline vfloat8 extract8<0>(const vfloat16& v) { return _mm512_castps512_ps256(v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Transpose
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline void transpose(const vfloat16& r0, const vfloat16& r1, const vfloat16& r2, const vfloat16& r3,
+ vfloat16& c0, vfloat16& c1, vfloat16& c2, vfloat16& c3)
+ {
+ vfloat16 a0a2_b0b2 = unpacklo(r0, r2);
+ vfloat16 c0c2_d0d2 = unpackhi(r0, r2);
+ vfloat16 a1a3_b1b3 = unpacklo(r1, r3);
+ vfloat16 c1c3_d1d3 = unpackhi(r1, r3);
+
+ c0 = unpacklo(a0a2_b0b2, a1a3_b1b3);
+ c1 = unpackhi(a0a2_b0b2, a1a3_b1b3);
+ c2 = unpacklo(c0c2_d0d2, c1c3_d1d3);
+ c3 = unpackhi(c0c2_d0d2, c1c3_d1d3);
+ }
+
+ __forceinline void transpose(const vfloat4& r0, const vfloat4& r1, const vfloat4& r2, const vfloat4& r3,
+ const vfloat4& r4, const vfloat4& r5, const vfloat4& r6, const vfloat4& r7,
+ const vfloat4& r8, const vfloat4& r9, const vfloat4& r10, const vfloat4& r11,
+ const vfloat4& r12, const vfloat4& r13, const vfloat4& r14, const vfloat4& r15,
+ vfloat16& c0, vfloat16& c1, vfloat16& c2, vfloat16& c3)
+ {
+ return transpose(vfloat16(r0, r4, r8, r12), vfloat16(r1, r5, r9, r13), vfloat16(r2, r6, r10, r14), vfloat16(r3, r7, r11, r15),
+ c0, c1, c2, c3);
+ }
+
+ __forceinline void transpose(const vfloat16& r0, const vfloat16& r1, const vfloat16& r2, const vfloat16& r3,
+ const vfloat16& r4, const vfloat16& r5, const vfloat16& r6, const vfloat16& r7,
+ vfloat16& c0, vfloat16& c1, vfloat16& c2, vfloat16& c3,
+ vfloat16& c4, vfloat16& c5, vfloat16& c6, vfloat16& c7)
+ {
+ vfloat16 a0a1a2a3_e0e1e2e3, b0b1b2b3_f0f1f2f3, c0c1c2c3_g0g1g2g3, d0d1d2d3_h0h1h2h3;
+ transpose(r0, r1, r2, r3, a0a1a2a3_e0e1e2e3, b0b1b2b3_f0f1f2f3, c0c1c2c3_g0g1g2g3, d0d1d2d3_h0h1h2h3);
+
+ vfloat16 a4a5a6a7_e4e5e6e7, b4b5b6b7_f4f5f6f7, c4c5c6c7_g4g5g6g7, d4d5d6d7_h4h5h6h7;
+ transpose(r4, r5, r6, r7, a4a5a6a7_e4e5e6e7, b4b5b6b7_f4f5f6f7, c4c5c6c7_g4g5g6g7, d4d5d6d7_h4h5h6h7);
+
+ c0 = interleave4_even(a0a1a2a3_e0e1e2e3, a4a5a6a7_e4e5e6e7);
+ c1 = interleave4_even(b0b1b2b3_f0f1f2f3, b4b5b6b7_f4f5f6f7);
+ c2 = interleave4_even(c0c1c2c3_g0g1g2g3, c4c5c6c7_g4g5g6g7);
+ c3 = interleave4_even(d0d1d2d3_h0h1h2h3, d4d5d6d7_h4h5h6h7);
+ c4 = interleave4_odd (a0a1a2a3_e0e1e2e3, a4a5a6a7_e4e5e6e7);
+ c5 = interleave4_odd (b0b1b2b3_f0f1f2f3, b4b5b6b7_f4f5f6f7);
+ c6 = interleave4_odd (c0c1c2c3_g0g1g2g3, c4c5c6c7_g4g5g6g7);
+ c7 = interleave4_odd (d0d1d2d3_h0h1h2h3, d4d5d6d7_h4h5h6h7);
+ }
+
+ __forceinline void transpose(const vfloat8& r0, const vfloat8& r1, const vfloat8& r2, const vfloat8& r3,
+ const vfloat8& r4, const vfloat8& r5, const vfloat8& r6, const vfloat8& r7,
+ const vfloat8& r8, const vfloat8& r9, const vfloat8& r10, const vfloat8& r11,
+ const vfloat8& r12, const vfloat8& r13, const vfloat8& r14, const vfloat8& r15,
+ vfloat16& c0, vfloat16& c1, vfloat16& c2, vfloat16& c3,
+ vfloat16& c4, vfloat16& c5, vfloat16& c6, vfloat16& c7)
+ {
+ return transpose(vfloat16(r0, r8), vfloat16(r1, r9), vfloat16(r2, r10), vfloat16(r3, r11),
+ vfloat16(r4, r12), vfloat16(r5, r13), vfloat16(r6, r14), vfloat16(r7, r15),
+ c0, c1, c2, c3, c4, c5, c6, c7);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat16 vreduce_add2(vfloat16 x) { return x + shuffle<1,0,3,2>(x); }
+ __forceinline vfloat16 vreduce_add4(vfloat16 x) { x = vreduce_add2(x); return x + shuffle<2,3,0,1>(x); }
+ __forceinline vfloat16 vreduce_add8(vfloat16 x) { x = vreduce_add4(x); return x + shuffle4<1,0,3,2>(x); }
+ __forceinline vfloat16 vreduce_add (vfloat16 x) { x = vreduce_add8(x); return x + shuffle4<2,3,0,1>(x); }
+
+ __forceinline vfloat16 vreduce_min2(vfloat16 x) { return min(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vfloat16 vreduce_min4(vfloat16 x) { x = vreduce_min2(x); return min(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vfloat16 vreduce_min8(vfloat16 x) { x = vreduce_min4(x); return min(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vfloat16 vreduce_min (vfloat16 x) { x = vreduce_min8(x); return min(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline vfloat16 vreduce_max2(vfloat16 x) { return max(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vfloat16 vreduce_max4(vfloat16 x) { x = vreduce_max2(x); return max(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vfloat16 vreduce_max8(vfloat16 x) { x = vreduce_max4(x); return max(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vfloat16 vreduce_max (vfloat16 x) { x = vreduce_max8(x); return max(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline float reduce_add(const vfloat16& v) { return toScalar(vreduce_add(v)); }
+ __forceinline float reduce_min(const vfloat16& v) { return toScalar(vreduce_min(v)); }
+ __forceinline float reduce_max(const vfloat16& v) { return toScalar(vreduce_max(v)); }
+
+ __forceinline size_t select_min(const vfloat16& v) {
+ return bsf(_mm512_kmov(_mm512_cmp_epi32_mask(_mm512_castps_si512(v),_mm512_castps_si512(vreduce_min(v)),_MM_CMPINT_EQ)));
+ }
+
+ __forceinline size_t select_max(const vfloat16& v) {
+ return bsf(_mm512_kmov(_mm512_cmp_epi32_mask(_mm512_castps_si512(v),_mm512_castps_si512(vreduce_max(v)),_MM_CMPINT_EQ)));
+ }
+
+ __forceinline size_t select_min(const vboolf16& valid, const vfloat16& v)
+ {
+ const vfloat16 a = select(valid,v,vfloat16(pos_inf));
+ const vbool16 valid_min = valid & (a == vreduce_min(a));
+ return bsf(movemask(any(valid_min) ? valid_min : valid));
+ }
+
+ __forceinline size_t select_max(const vboolf16& valid, const vfloat16& v)
+ {
+ const vfloat16 a = select(valid,v,vfloat16(neg_inf));
+ const vbool16 valid_max = valid & (a == vreduce_max(a));
+ return bsf(movemask(any(valid_max) ? valid_max : valid));
+ }
+
+ __forceinline vfloat16 prefix_sum(const vfloat16& a)
+ {
+ const vfloat16 z(zero);
+ vfloat16 v = a;
+ v = v + align_shift_right<16-1>(v,z);
+ v = v + align_shift_right<16-2>(v,z);
+ v = v + align_shift_right<16-4>(v,z);
+ v = v + align_shift_right<16-8>(v,z);
+ return v;
+ }
+
+ __forceinline vfloat16 reverse_prefix_sum(const vfloat16& a)
+ {
+ const vfloat16 z(zero);
+ vfloat16 v = a;
+ v = v + align_shift_right<1>(z,v);
+ v = v + align_shift_right<2>(z,v);
+ v = v + align_shift_right<4>(z,v);
+ v = v + align_shift_right<8>(z,v);
+ return v;
+ }
+
+ __forceinline vfloat16 prefix_min(const vfloat16& a)
+ {
+ const vfloat16 z(pos_inf);
+ vfloat16 v = a;
+ v = min(v,align_shift_right<16-1>(v,z));
+ v = min(v,align_shift_right<16-2>(v,z));
+ v = min(v,align_shift_right<16-4>(v,z));
+ v = min(v,align_shift_right<16-8>(v,z));
+ return v;
+ }
+
+ __forceinline vfloat16 prefix_max(const vfloat16& a)
+ {
+ const vfloat16 z(neg_inf);
+ vfloat16 v = a;
+ v = max(v,align_shift_right<16-1>(v,z));
+ v = max(v,align_shift_right<16-2>(v,z));
+ v = max(v,align_shift_right<16-4>(v,z));
+ v = max(v,align_shift_right<16-8>(v,z));
+ return v;
+ }
+
+
+ __forceinline vfloat16 reverse_prefix_min(const vfloat16& a)
+ {
+ const vfloat16 z(pos_inf);
+ vfloat16 v = a;
+ v = min(v,align_shift_right<1>(z,v));
+ v = min(v,align_shift_right<2>(z,v));
+ v = min(v,align_shift_right<4>(z,v));
+ v = min(v,align_shift_right<8>(z,v));
+ return v;
+ }
+
+ __forceinline vfloat16 reverse_prefix_max(const vfloat16& a)
+ {
+ const vfloat16 z(neg_inf);
+ vfloat16 v = a;
+ v = max(v,align_shift_right<1>(z,v));
+ v = max(v,align_shift_right<2>(z,v));
+ v = max(v,align_shift_right<4>(z,v));
+ v = max(v,align_shift_right<8>(z,v));
+ return v;
+ }
+
+ __forceinline vfloat16 rcp_safe(const vfloat16& a) {
+ return rcp(select(a != vfloat16(zero), a, vfloat16(min_rcp_input)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vfloat16& v)
+ {
+ cout << "<" << v[0];
+ for (int i=1; i<16; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vfloat4_sse2.h b/thirdparty/embree/common/simd/vfloat4_sse2.h
new file mode 100644
index 0000000000..5215bf9730
--- /dev/null
+++ b/thirdparty/embree/common/simd/vfloat4_sse2.h
@@ -0,0 +1,722 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 4-wide SSE float type */
+ template<>
+ struct vfloat<4>
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef vboolf4 Bool;
+ typedef vint4 Int;
+ typedef vfloat4 Float;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { __m128 v; float f[4]; int i[4]; }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat() {}
+ __forceinline vfloat(const vfloat4& other) { v = other.v; }
+ __forceinline vfloat4& operator =(const vfloat4& other) { v = other.v; return *this; }
+
+ __forceinline vfloat(__m128 a) : v(a) {}
+ __forceinline operator const __m128&() const { return v; }
+ __forceinline operator __m128&() { return v; }
+
+ __forceinline vfloat(float a) : v(_mm_set1_ps(a)) {}
+ __forceinline vfloat(float a, float b, float c, float d) : v(_mm_set_ps(d, c, b, a)) {}
+
+ __forceinline explicit vfloat(const vint4& a) : v(_mm_cvtepi32_ps(a)) {}
+ __forceinline explicit vfloat(const vuint4& x) {
+ const __m128i a = _mm_and_si128(x,_mm_set1_epi32(0x7FFFFFFF));
+ const __m128i b = _mm_and_si128(_mm_srai_epi32(x,31),_mm_set1_epi32(0x4F000000)); //0x4F000000 = 2^31
+ const __m128 af = _mm_cvtepi32_ps(a);
+ const __m128 bf = _mm_castsi128_ps(b);
+ v = _mm_add_ps(af,bf);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat(ZeroTy) : v(_mm_setzero_ps()) {}
+ __forceinline vfloat(OneTy) : v(_mm_set1_ps(1.0f)) {}
+ __forceinline vfloat(PosInfTy) : v(_mm_set1_ps(pos_inf)) {}
+ __forceinline vfloat(NegInfTy) : v(_mm_set1_ps(neg_inf)) {}
+ __forceinline vfloat(StepTy) : v(_mm_set_ps(3.0f, 2.0f, 1.0f, 0.0f)) {}
+ __forceinline vfloat(NaNTy) : v(_mm_set1_ps(nan)) {}
+ __forceinline vfloat(UndefinedTy) : v(_mm_undefined_ps()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vfloat4 load (const void* a) { return _mm_load_ps((float*)a); }
+ static __forceinline vfloat4 loadu(const void* a) { return _mm_loadu_ps((float*)a); }
+
+ static __forceinline void store (void* ptr, const vfloat4& v) { _mm_store_ps((float*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vfloat4& v) { _mm_storeu_ps((float*)ptr,v); }
+
+#if defined(__AVX512VL__)
+
+ static __forceinline vfloat4 load (const vboolf4& mask, const void* ptr) { return _mm_mask_load_ps (_mm_setzero_ps(),mask,(float*)ptr); }
+ static __forceinline vfloat4 loadu(const vboolf4& mask, const void* ptr) { return _mm_mask_loadu_ps(_mm_setzero_ps(),mask,(float*)ptr); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vfloat4& v) { _mm_mask_store_ps ((float*)ptr,mask,v); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vfloat4& v) { _mm_mask_storeu_ps((float*)ptr,mask,v); }
+#elif defined(__AVX__)
+ static __forceinline vfloat4 load (const vboolf4& mask, const void* ptr) { return _mm_maskload_ps((float*)ptr,mask); }
+ static __forceinline vfloat4 loadu(const vboolf4& mask, const void* ptr) { return _mm_maskload_ps((float*)ptr,mask); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vfloat4& v) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,v); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vfloat4& v) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,v); }
+#else
+ static __forceinline vfloat4 load (const vboolf4& mask, const void* ptr) { return _mm_and_ps(_mm_load_ps ((float*)ptr),mask); }
+ static __forceinline vfloat4 loadu(const vboolf4& mask, const void* ptr) { return _mm_and_ps(_mm_loadu_ps((float*)ptr),mask); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vfloat4& v) { store (ptr,select(mask,v,load (ptr))); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vfloat4& v) { storeu(ptr,select(mask,v,loadu(ptr))); }
+#endif
+
+#if defined(__AVX__)
+ static __forceinline vfloat4 broadcast(const void* a) { return _mm_broadcast_ss((float*)a); }
+#else
+ static __forceinline vfloat4 broadcast(const void* a) { return _mm_set1_ps(*(float*)a); }
+#endif
+
+ static __forceinline vfloat4 load_nt (const float* ptr) {
+#if defined (__SSE4_1__)
+ return _mm_castsi128_ps(_mm_stream_load_si128((__m128i*)ptr));
+#else
+ return _mm_load_ps(ptr);
+#endif
+ }
+
+#if defined(__SSE4_1__)
+ static __forceinline vfloat4 load(const char* ptr) {
+ return _mm_cvtepi32_ps(_mm_cvtepi8_epi32(_mm_loadu_si128((__m128i*)ptr)));
+ }
+#else
+ static __forceinline vfloat4 load(const char* ptr) {
+ return vfloat4(ptr[0],ptr[1],ptr[2],ptr[3]);
+ }
+#endif
+
+#if defined(__SSE4_1__)
+ static __forceinline vfloat4 load(const unsigned char* ptr) {
+ return _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)));
+ }
+#else
+ static __forceinline vfloat4 load(const unsigned char* ptr) {
+ //return _mm_cvtpu8_ps(*(__m64*)ptr); // don't enable, will use MMX instructions
+ return vfloat4(ptr[0],ptr[1],ptr[2],ptr[3]);
+ }
+#endif
+
+#if defined(__SSE4_1__)
+ static __forceinline vfloat4 load(const short* ptr) {
+ return _mm_cvtepi32_ps(_mm_cvtepi16_epi32(_mm_loadu_si128((__m128i*)ptr)));
+ }
+#else
+ static __forceinline vfloat4 load(const short* ptr) {
+ return vfloat4(ptr[0],ptr[1],ptr[2],ptr[3]);
+ }
+#endif
+
+ static __forceinline vfloat4 load(const unsigned short* ptr) {
+ return _mm_mul_ps(vfloat4(vint4::load(ptr)),vfloat4(1.0f/65535.0f));
+ }
+
+ static __forceinline void store_nt(void* ptr, const vfloat4& v)
+ {
+#if defined (__SSE4_1__)
+ _mm_stream_ps((float*)ptr,v);
+#else
+ _mm_store_ps((float*)ptr,v);
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat4 gather(const float* ptr, const vint4& index) {
+#if defined(__AVX2__)
+ return _mm_i32gather_ps(ptr, index, scale);
+#else
+ return vfloat4(
+ *(float*)(((char*)ptr)+scale*index[0]),
+ *(float*)(((char*)ptr)+scale*index[1]),
+ *(float*)(((char*)ptr)+scale*index[2]),
+ *(float*)(((char*)ptr)+scale*index[3]));
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat4 gather(const vboolf4& mask, const float* ptr, const vint4& index) {
+ vfloat4 r = zero;
+#if defined(__AVX512VL__)
+ return _mm_mmask_i32gather_ps(r, mask, index, ptr, scale);
+#elif defined(__AVX2__)
+ return _mm_mask_i32gather_ps(r, ptr, index, mask, scale);
+#else
+ if (likely(mask[0])) r[0] = *(float*)(((char*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(float*)(((char*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(float*)(((char*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(float*)(((char*)ptr)+scale*index[3]);
+ return r;
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint4& index, const vfloat4& v)
+ {
+#if defined(__AVX512VL__)
+ _mm_i32scatter_ps((float*)ptr, index, v, scale);
+#else
+ *(float*)(((char*)ptr)+scale*index[0]) = v[0];
+ *(float*)(((char*)ptr)+scale*index[1]) = v[1];
+ *(float*)(((char*)ptr)+scale*index[2]) = v[2];
+ *(float*)(((char*)ptr)+scale*index[3]) = v[3];
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf4& mask, void* ptr, const vint4& index, const vfloat4& v)
+ {
+#if defined(__AVX512VL__)
+ _mm_mask_i32scatter_ps((float*)ptr ,mask, index, v, scale);
+#else
+ if (likely(mask[0])) *(float*)(((char*)ptr)+scale*index[0]) = v[0];
+ if (likely(mask[1])) *(float*)(((char*)ptr)+scale*index[1]) = v[1];
+ if (likely(mask[2])) *(float*)(((char*)ptr)+scale*index[2]) = v[2];
+ if (likely(mask[3])) *(float*)(((char*)ptr)+scale*index[3]) = v[3];
+#endif
+ }
+
+ static __forceinline void store(const vboolf4& mask, char* ptr, const vint4& ofs, const vfloat4& v) {
+ scatter<1>(mask,ptr,ofs,v);
+ }
+ static __forceinline void store(const vboolf4& mask, float* ptr, const vint4& ofs, const vfloat4& v) {
+ scatter<4>(mask,ptr,ofs,v);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float& operator [](size_t index) const { assert(index < 4); return f[index]; }
+ __forceinline float& operator [](size_t index) { assert(index < 4); return f[index]; }
+
+ friend __forceinline vfloat4 select(const vboolf4& m, const vfloat4& t, const vfloat4& f) {
+#if defined(__AVX512VL__)
+ return _mm_mask_blend_ps(m, f, t);
+#elif defined(__SSE4_1__)
+ return _mm_blendv_ps(f, t, m);
+#else
+ return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
+#endif
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Load/Store
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<> struct mem<vfloat4>
+ {
+ static __forceinline vfloat4 load (const vboolf4& mask, const void* ptr) { return vfloat4::load (mask,ptr); }
+ static __forceinline vfloat4 loadu(const vboolf4& mask, const void* ptr) { return vfloat4::loadu(mask,ptr); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vfloat4& v) { vfloat4::store (mask,ptr,v); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vfloat4& v) { vfloat4::storeu(mask,ptr,v); }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4 asFloat(const vint4& a) { return _mm_castsi128_ps(a); }
+ __forceinline vint4 asInt (const vfloat4& a) { return _mm_castps_si128(a); }
+ __forceinline vuint4 asUInt (const vfloat4& a) { return _mm_castps_si128(a); }
+
+ __forceinline vint4 toInt (const vfloat4& a) { return vint4(a); }
+ __forceinline vfloat4 toFloat(const vint4& a) { return vfloat4(a); }
+
+ __forceinline vfloat4 operator +(const vfloat4& a) { return a; }
+ __forceinline vfloat4 operator -(const vfloat4& a) { return _mm_xor_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x80000000))); }
+
+ __forceinline vfloat4 abs(const vfloat4& a) { return _mm_and_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))); }
+#if defined(__AVX512VL__)
+ __forceinline vfloat4 sign(const vfloat4& a) { return _mm_mask_blend_ps(_mm_cmp_ps_mask(a, vfloat4(zero), _CMP_LT_OQ), vfloat4(one), -vfloat4(one)); }
+#else
+ __forceinline vfloat4 sign(const vfloat4& a) { return blendv_ps(vfloat4(one), -vfloat4(one), _mm_cmplt_ps(a, vfloat4(zero))); }
+#endif
+ __forceinline vfloat4 signmsk(const vfloat4& a) { return _mm_and_ps(a,_mm_castsi128_ps(_mm_set1_epi32(0x80000000))); }
+
+ __forceinline vfloat4 rcp(const vfloat4& a)
+ {
+#if defined(__AVX512VL__)
+ const vfloat4 r = _mm_rcp14_ps(a);
+#else
+ const vfloat4 r = _mm_rcp_ps(a);
+#endif
+
+#if defined(__AVX2__)
+ return _mm_mul_ps(r,_mm_fnmadd_ps(r, a, vfloat4(2.0f)));
+#else
+ return _mm_mul_ps(r,_mm_sub_ps(vfloat4(2.0f), _mm_mul_ps(r, a)));
+#endif
+ }
+ __forceinline vfloat4 sqr (const vfloat4& a) { return _mm_mul_ps(a,a); }
+ __forceinline vfloat4 sqrt(const vfloat4& a) { return _mm_sqrt_ps(a); }
+
+ __forceinline vfloat4 rsqrt(const vfloat4& a)
+ {
+#if defined(__AVX512VL__)
+ vfloat4 r = _mm_rsqrt14_ps(a);
+#else
+ vfloat4 r = _mm_rsqrt_ps(a);
+#endif
+
+#if defined(__ARM_NEON)
+ r = _mm_fmadd_ps(_mm_set1_ps(1.5f), r, _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+ r = _mm_fmadd_ps(_mm_set1_ps(1.5f), r, _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+#elif defined(__AVX2__)
+ r = _mm_fmadd_ps(_mm_set1_ps(1.5f), r, _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+#else
+ r = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f), r), _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+#endif
+ return r;
+ }
+
+ __forceinline vboolf4 isnan(const vfloat4& a) {
+ const vfloat4 b = _mm_and_ps(a, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)));
+#if defined(__AVX512VL__)
+ return _mm_cmp_epi32_mask(_mm_castps_si128(b), _mm_set1_epi32(0x7f800000), _MM_CMPINT_GT);
+#else
+ return _mm_castsi128_ps(_mm_cmpgt_epi32(_mm_castps_si128(b), _mm_set1_epi32(0x7f800000)));
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4 operator +(const vfloat4& a, const vfloat4& b) { return _mm_add_ps(a, b); }
+ __forceinline vfloat4 operator +(const vfloat4& a, float b) { return a + vfloat4(b); }
+ __forceinline vfloat4 operator +(float a, const vfloat4& b) { return vfloat4(a) + b; }
+
+ __forceinline vfloat4 operator -(const vfloat4& a, const vfloat4& b) { return _mm_sub_ps(a, b); }
+ __forceinline vfloat4 operator -(const vfloat4& a, float b) { return a - vfloat4(b); }
+ __forceinline vfloat4 operator -(float a, const vfloat4& b) { return vfloat4(a) - b; }
+
+ __forceinline vfloat4 operator *(const vfloat4& a, const vfloat4& b) { return _mm_mul_ps(a, b); }
+ __forceinline vfloat4 operator *(const vfloat4& a, float b) { return a * vfloat4(b); }
+ __forceinline vfloat4 operator *(float a, const vfloat4& b) { return vfloat4(a) * b; }
+
+ __forceinline vfloat4 operator /(const vfloat4& a, const vfloat4& b) { return _mm_div_ps(a,b); }
+ __forceinline vfloat4 operator /(const vfloat4& a, float b) { return a/vfloat4(b); }
+ __forceinline vfloat4 operator /(float a, const vfloat4& b) { return vfloat4(a)/b; }
+
+ __forceinline vfloat4 operator &(const vfloat4& a, const vfloat4& b) { return _mm_and_ps(a,b); }
+ __forceinline vfloat4 operator |(const vfloat4& a, const vfloat4& b) { return _mm_or_ps(a,b); }
+ __forceinline vfloat4 operator ^(const vfloat4& a, const vfloat4& b) { return _mm_xor_ps(a,b); }
+ __forceinline vfloat4 operator ^(const vfloat4& a, const vint4& b) { return _mm_xor_ps(a,_mm_castsi128_ps(b)); }
+
+ __forceinline vfloat4 min(const vfloat4& a, const vfloat4& b) { return _mm_min_ps(a,b); }
+ __forceinline vfloat4 min(const vfloat4& a, float b) { return _mm_min_ps(a,vfloat4(b)); }
+ __forceinline vfloat4 min(float a, const vfloat4& b) { return _mm_min_ps(vfloat4(a),b); }
+
+ __forceinline vfloat4 max(const vfloat4& a, const vfloat4& b) { return _mm_max_ps(a,b); }
+ __forceinline vfloat4 max(const vfloat4& a, float b) { return _mm_max_ps(a,vfloat4(b)); }
+ __forceinline vfloat4 max(float a, const vfloat4& b) { return _mm_max_ps(vfloat4(a),b); }
+
+#if defined(__SSE4_1__)
+ __forceinline vfloat4 mini(const vfloat4& a, const vfloat4& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_min_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+
+ __forceinline vfloat4 maxi(const vfloat4& a, const vfloat4& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_max_epi32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+
+ __forceinline vfloat4 minui(const vfloat4& a, const vfloat4& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_min_epu32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+
+ __forceinline vfloat4 maxui(const vfloat4& a, const vfloat4& b) {
+ const vint4 ai = _mm_castps_si128(a);
+ const vint4 bi = _mm_castps_si128(b);
+ const vint4 ci = _mm_max_epu32(ai,bi);
+ return _mm_castsi128_ps(ci);
+ }
+#else
+ __forceinline vfloat4 mini(const vfloat4& a, const vfloat4& b) {
+ return min(a,b);
+ }
+
+ __forceinline vfloat4 maxi(const vfloat4& a, const vfloat4& b) {
+ return max(a,b);
+ }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ __forceinline vfloat4 madd (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fmadd_ps(a,b,c); }
+ __forceinline vfloat4 msub (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fmsub_ps(a,b,c); }
+ __forceinline vfloat4 nmadd(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fnmadd_ps(a,b,c); }
+ __forceinline vfloat4 nmsub(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return _mm_fnmsub_ps(a,b,c); }
+#else
+ __forceinline vfloat4 madd (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return a*b+c; }
+ __forceinline vfloat4 msub (const vfloat4& a, const vfloat4& b, const vfloat4& c) { return a*b-c; }
+ __forceinline vfloat4 nmadd(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return -a*b+c;}
+ __forceinline vfloat4 nmsub(const vfloat4& a, const vfloat4& b, const vfloat4& c) { return -a*b-c; }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4& operator +=(vfloat4& a, const vfloat4& b) { return a = a + b; }
+ __forceinline vfloat4& operator +=(vfloat4& a, float b) { return a = a + b; }
+
+ __forceinline vfloat4& operator -=(vfloat4& a, const vfloat4& b) { return a = a - b; }
+ __forceinline vfloat4& operator -=(vfloat4& a, float b) { return a = a - b; }
+
+ __forceinline vfloat4& operator *=(vfloat4& a, const vfloat4& b) { return a = a * b; }
+ __forceinline vfloat4& operator *=(vfloat4& a, float b) { return a = a * b; }
+
+ __forceinline vfloat4& operator /=(vfloat4& a, const vfloat4& b) { return a = a / b; }
+ __forceinline vfloat4& operator /=(vfloat4& a, float b) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 operator ==(const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_EQ); }
+ __forceinline vboolf4 operator !=(const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_NE); }
+ __forceinline vboolf4 operator < (const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_LT); }
+ __forceinline vboolf4 operator >=(const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_GE); }
+ __forceinline vboolf4 operator > (const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_GT); }
+ __forceinline vboolf4 operator <=(const vfloat4& a, const vfloat4& b) { return _mm_cmp_ps_mask(a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 operator ==(const vfloat4& a, const vfloat4& b) { return _mm_cmpeq_ps (a, b); }
+ __forceinline vboolf4 operator !=(const vfloat4& a, const vfloat4& b) { return _mm_cmpneq_ps(a, b); }
+ __forceinline vboolf4 operator < (const vfloat4& a, const vfloat4& b) { return _mm_cmplt_ps (a, b); }
+ __forceinline vboolf4 operator >=(const vfloat4& a, const vfloat4& b) { return _mm_cmpnlt_ps(a, b); }
+ __forceinline vboolf4 operator > (const vfloat4& a, const vfloat4& b) { return _mm_cmpnle_ps(a, b); }
+ __forceinline vboolf4 operator <=(const vfloat4& a, const vfloat4& b) { return _mm_cmple_ps (a, b); }
+#endif
+
+ __forceinline vboolf4 operator ==(const vfloat4& a, float b) { return a == vfloat4(b); }
+ __forceinline vboolf4 operator ==(float a, const vfloat4& b) { return vfloat4(a) == b; }
+
+ __forceinline vboolf4 operator !=(const vfloat4& a, float b) { return a != vfloat4(b); }
+ __forceinline vboolf4 operator !=(float a, const vfloat4& b) { return vfloat4(a) != b; }
+
+ __forceinline vboolf4 operator < (const vfloat4& a, float b) { return a < vfloat4(b); }
+ __forceinline vboolf4 operator < (float a, const vfloat4& b) { return vfloat4(a) < b; }
+
+ __forceinline vboolf4 operator >=(const vfloat4& a, float b) { return a >= vfloat4(b); }
+ __forceinline vboolf4 operator >=(float a, const vfloat4& b) { return vfloat4(a) >= b; }
+
+ __forceinline vboolf4 operator > (const vfloat4& a, float b) { return a > vfloat4(b); }
+ __forceinline vboolf4 operator > (float a, const vfloat4& b) { return vfloat4(a) > b; }
+
+ __forceinline vboolf4 operator <=(const vfloat4& a, float b) { return a <= vfloat4(b); }
+ __forceinline vboolf4 operator <=(float a, const vfloat4& b) { return vfloat4(a) <= b; }
+
+ __forceinline vboolf4 eq(const vfloat4& a, const vfloat4& b) { return a == b; }
+ __forceinline vboolf4 ne(const vfloat4& a, const vfloat4& b) { return a != b; }
+ __forceinline vboolf4 lt(const vfloat4& a, const vfloat4& b) { return a < b; }
+ __forceinline vboolf4 ge(const vfloat4& a, const vfloat4& b) { return a >= b; }
+ __forceinline vboolf4 gt(const vfloat4& a, const vfloat4& b) { return a > b; }
+ __forceinline vboolf4 le(const vfloat4& a, const vfloat4& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 eq(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_NE); }
+ __forceinline vboolf4 lt(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_LT); }
+ __forceinline vboolf4 ge(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_GE); }
+ __forceinline vboolf4 gt(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_GT); }
+ __forceinline vboolf4 le(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return _mm_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 eq(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a == b); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a != b); }
+ __forceinline vboolf4 lt(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a < b); }
+ __forceinline vboolf4 ge(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a >= b); }
+ __forceinline vboolf4 gt(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a > b); }
+ __forceinline vboolf4 le(const vboolf4& mask, const vfloat4& a, const vfloat4& b) { return mask & (a <= b); }
+#endif
+
+ template<int mask>
+ __forceinline vfloat4 select(const vfloat4& t, const vfloat4& f)
+ {
+#if defined(__SSE4_1__)
+ return _mm_blend_ps(f, t, mask);
+#else
+ return select(vboolf4(mask), t, f);
+#endif
+ }
+
+ __forceinline vfloat4 lerp(const vfloat4& a, const vfloat4& b, const vfloat4& t) {
+ return madd(t,b-a,a);
+ }
+
+ __forceinline bool isvalid(const vfloat4& v) {
+ return all((v > vfloat4(-FLT_LARGE)) & (v < vfloat4(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite(const vfloat4& a) {
+ return all((a >= vfloat4(-FLT_MAX)) & (a <= vfloat4(+FLT_MAX)));
+ }
+
+ __forceinline bool is_finite(const vboolf4& valid, const vfloat4& a) {
+ return all(valid, (a >= vfloat4(-FLT_MAX)) & (a <= vfloat4(+FLT_MAX)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__aarch64__)
+ __forceinline vfloat4 floor(const vfloat4& a) { return vrndmq_f32(a.v); }
+ __forceinline vfloat4 ceil (const vfloat4& a) { return vrndpq_f32(a.v); }
+ __forceinline vfloat4 trunc(const vfloat4& a) { return vrndq_f32(a.v); }
+ __forceinline vfloat4 round(const vfloat4& a) { return vrndnq_f32(a.v); }
+#elif defined (__SSE4_1__)
+ __forceinline vfloat4 floor(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF ); }
+ __forceinline vfloat4 ceil (const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_POS_INF ); }
+ __forceinline vfloat4 trunc(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_ZERO ); }
+ __forceinline vfloat4 round(const vfloat4& a) { return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT); }
+#else
+ __forceinline vfloat4 floor(const vfloat4& a) { return vfloat4(floorf(a[0]),floorf(a[1]),floorf(a[2]),floorf(a[3])); }
+ __forceinline vfloat4 ceil (const vfloat4& a) { return vfloat4(ceilf (a[0]),ceilf (a[1]),ceilf (a[2]),ceilf (a[3])); }
+ __forceinline vfloat4 trunc(const vfloat4& a) { return vfloat4(truncf(a[0]),truncf(a[1]),truncf(a[2]),truncf(a[3])); }
+ __forceinline vfloat4 round(const vfloat4& a) { return vfloat4(roundf(a[0]),roundf(a[1]),roundf(a[2]),roundf(a[3])); }
+#endif
+ __forceinline vfloat4 frac(const vfloat4& a) { return a-floor(a); }
+
+ __forceinline vint4 floori(const vfloat4& a) {
+#if defined(__SSE4_1__)
+ return vint4(floor(a));
+#else
+ return vint4(a-vfloat4(0.5f));
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4 unpacklo(const vfloat4& a, const vfloat4& b) { return _mm_unpacklo_ps(a, b); }
+ __forceinline vfloat4 unpackhi(const vfloat4& a, const vfloat4& b) { return _mm_unpackhi_ps(a, b); }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat4 shuffle(const vfloat4& v) {
+ return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat4 shuffle(const vfloat4& a, const vfloat4& b) {
+ return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+#if defined(__SSE3__)
+ template<> __forceinline vfloat4 shuffle<0, 0, 2, 2>(const vfloat4& v) { return _mm_moveldup_ps(v); }
+ template<> __forceinline vfloat4 shuffle<1, 1, 3, 3>(const vfloat4& v) { return _mm_movehdup_ps(v); }
+ template<> __forceinline vfloat4 shuffle<0, 1, 0, 1>(const vfloat4& v) { return _mm_castpd_ps(_mm_movedup_pd(_mm_castps_pd(v))); }
+#endif
+
+ template<int i>
+ __forceinline vfloat4 shuffle(const vfloat4& v) {
+ return shuffle<i,i,i,i>(v);
+ }
+
+ template<int i> __forceinline float extract (const vfloat4& a) { return _mm_cvtss_f32(shuffle<i>(a)); }
+ template<> __forceinline float extract<0>(const vfloat4& a) { return _mm_cvtss_f32(a); }
+
+#if defined (__SSE4_1__)
+ template<int dst, int src, int clr> __forceinline vfloat4 insert(const vfloat4& a, const vfloat4& b) { return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr); }
+ template<int dst, int src> __forceinline vfloat4 insert(const vfloat4& a, const vfloat4& b) { return insert<dst, src, 0>(a, b); }
+ template<int dst> __forceinline vfloat4 insert(const vfloat4& a, const float b) { return insert<dst, 0>(a, _mm_set_ss(b)); }
+#else
+ template<int dst, int src> __forceinline vfloat4 insert(const vfloat4& a, const vfloat4& b) { vfloat4 c = a; c[dst&3] = b[src&3]; return c; }
+ template<int dst> __forceinline vfloat4 insert(const vfloat4& a, float b) { vfloat4 c = a; c[dst&3] = b; return c; }
+#endif
+
+ __forceinline float toScalar(const vfloat4& v) { return _mm_cvtss_f32(v); }
+
+ __forceinline vfloat4 shift_right_1(const vfloat4& x) {
+ return _mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(x), 4));
+ }
+
+#if defined (__AVX2__)
+ __forceinline vfloat4 permute(const vfloat4 &a, const __m128i &index) {
+ return _mm_permutevar_ps(a,index);
+ }
+
+ __forceinline vfloat4 broadcast1f(const void* a) { return _mm_broadcast_ss((float*)a); }
+
+#endif
+
+#if defined(__AVX512VL__)
+ template<int i>
+ __forceinline vfloat4 align_shift_right(const vfloat4& a, const vfloat4& b) {
+ return _mm_castsi128_ps(_mm_alignr_epi32(_mm_castps_si128(a), _mm_castps_si128(b), i));
+ }
+#endif
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Sorting Network
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4 sort_ascending(const vfloat4& v)
+ {
+ const vfloat4 a0 = v;
+ const vfloat4 b0 = shuffle<1,0,3,2>(a0);
+ const vfloat4 c0 = min(a0,b0);
+ const vfloat4 d0 = max(a0,b0);
+ const vfloat4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vfloat4 b1 = shuffle<2,3,0,1>(a1);
+ const vfloat4 c1 = min(a1,b1);
+ const vfloat4 d1 = max(a1,b1);
+ const vfloat4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vfloat4 b2 = shuffle<0,2,1,3>(a2);
+ const vfloat4 c2 = min(a2,b2);
+ const vfloat4 d2 = max(a2,b2);
+ const vfloat4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3;
+ }
+
+ __forceinline vfloat4 sort_descending(const vfloat4& v)
+ {
+ const vfloat4 a0 = v;
+ const vfloat4 b0 = shuffle<1,0,3,2>(a0);
+ const vfloat4 c0 = max(a0,b0);
+ const vfloat4 d0 = min(a0,b0);
+ const vfloat4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vfloat4 b1 = shuffle<2,3,0,1>(a1);
+ const vfloat4 c1 = max(a1,b1);
+ const vfloat4 d1 = min(a1,b1);
+ const vfloat4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vfloat4 b2 = shuffle<0,2,1,3>(a2);
+ const vfloat4 c2 = max(a2,b2);
+ const vfloat4 d2 = min(a2,b2);
+ const vfloat4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Transpose
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline void transpose(const vfloat4& r0, const vfloat4& r1, const vfloat4& r2, const vfloat4& r3, vfloat4& c0, vfloat4& c1, vfloat4& c2, vfloat4& c3)
+ {
+ vfloat4 l02 = unpacklo(r0,r2);
+ vfloat4 h02 = unpackhi(r0,r2);
+ vfloat4 l13 = unpacklo(r1,r3);
+ vfloat4 h13 = unpackhi(r1,r3);
+ c0 = unpacklo(l02,l13);
+ c1 = unpackhi(l02,l13);
+ c2 = unpacklo(h02,h13);
+ c3 = unpackhi(h02,h13);
+ }
+
+ __forceinline void transpose(const vfloat4& r0, const vfloat4& r1, const vfloat4& r2, const vfloat4& r3, vfloat4& c0, vfloat4& c1, vfloat4& c2)
+ {
+ vfloat4 l02 = unpacklo(r0,r2);
+ vfloat4 h02 = unpackhi(r0,r2);
+ vfloat4 l13 = unpacklo(r1,r3);
+ vfloat4 h13 = unpackhi(r1,r3);
+ c0 = unpacklo(l02,l13);
+ c1 = unpackhi(l02,l13);
+ c2 = unpacklo(h02,h13);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat4 vreduce_min(const vfloat4& v) { vfloat4 h = min(shuffle<1,0,3,2>(v),v); return min(shuffle<2,3,0,1>(h),h); }
+ __forceinline vfloat4 vreduce_max(const vfloat4& v) { vfloat4 h = max(shuffle<1,0,3,2>(v),v); return max(shuffle<2,3,0,1>(h),h); }
+ __forceinline vfloat4 vreduce_add(const vfloat4& v) { vfloat4 h = shuffle<1,0,3,2>(v) + v ; return shuffle<2,3,0,1>(h) + h ; }
+
+ __forceinline float reduce_min(const vfloat4& v) { return _mm_cvtss_f32(vreduce_min(v)); }
+ __forceinline float reduce_max(const vfloat4& v) { return _mm_cvtss_f32(vreduce_max(v)); }
+ __forceinline float reduce_add(const vfloat4& v) { return _mm_cvtss_f32(vreduce_add(v)); }
+
+ __forceinline size_t select_min(const vboolf4& valid, const vfloat4& v)
+ {
+ const vfloat4 a = select(valid,v,vfloat4(pos_inf));
+ const vbool4 valid_min = valid & (a == vreduce_min(a));
+ return bsf(movemask(any(valid_min) ? valid_min : valid));
+ }
+ __forceinline size_t select_max(const vboolf4& valid, const vfloat4& v)
+ {
+ const vfloat4 a = select(valid,v,vfloat4(neg_inf));
+ const vbool4 valid_max = valid & (a == vreduce_max(a));
+ return bsf(movemask(any(valid_max) ? valid_max : valid));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline float dot(const vfloat4& a, const vfloat4& b) {
+ return reduce_add(a*b);
+ }
+
+ __forceinline vfloat4 cross(const vfloat4& a, const vfloat4& b)
+ {
+ const vfloat4 a0 = a;
+ const vfloat4 b0 = shuffle<1,2,0,3>(b);
+ const vfloat4 a1 = shuffle<1,2,0,3>(a);
+ const vfloat4 b1 = b;
+ return shuffle<1,2,0,3>(msub(a0,b0,a1*b1));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vfloat4& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ">";
+ }
+
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vfloat8_avx.h b/thirdparty/embree/common/simd/vfloat8_avx.h
new file mode 100644
index 0000000000..13446454e8
--- /dev/null
+++ b/thirdparty/embree/common/simd/vfloat8_avx.h
@@ -0,0 +1,758 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 8-wide AVX float type */
+ template<>
+ struct vfloat<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { __m256 v; float f[8]; int i[8]; }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat() {}
+ __forceinline vfloat(const vfloat8& other) { v = other.v; }
+ __forceinline vfloat8& operator =(const vfloat8& other) { v = other.v; return *this; }
+
+ __forceinline vfloat(__m256 a) : v(a) {}
+ __forceinline operator const __m256&() const { return v; }
+ __forceinline operator __m256&() { return v; }
+
+ __forceinline explicit vfloat(const vfloat4& a) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),a,1)) {}
+ __forceinline vfloat(const vfloat4& a, const vfloat4& b) : v(_mm256_insertf128_ps(_mm256_castps128_ps256(a),b,1)) {}
+
+ __forceinline explicit vfloat(const char* a) : v(_mm256_loadu_ps((const float*)a)) {}
+ __forceinline vfloat(float a) : v(_mm256_set1_ps(a)) {}
+ __forceinline vfloat(float a, float b) : v(_mm256_set_ps(b, a, b, a, b, a, b, a)) {}
+ __forceinline vfloat(float a, float b, float c, float d) : v(_mm256_set_ps(d, c, b, a, d, c, b, a)) {}
+ __forceinline vfloat(float a, float b, float c, float d, float e, float f, float g, float h) : v(_mm256_set_ps(h, g, f, e, d, c, b, a)) {}
+
+ __forceinline explicit vfloat(__m256i a) : v(_mm256_cvtepi32_ps(a)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat(ZeroTy) : v(_mm256_setzero_ps()) {}
+ __forceinline vfloat(OneTy) : v(_mm256_set1_ps(1.0f)) {}
+ __forceinline vfloat(PosInfTy) : v(_mm256_set1_ps(pos_inf)) {}
+ __forceinline vfloat(NegInfTy) : v(_mm256_set1_ps(neg_inf)) {}
+ __forceinline vfloat(StepTy) : v(_mm256_set_ps(7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 0.0f)) {}
+ __forceinline vfloat(NaNTy) : v(_mm256_set1_ps(nan)) {}
+ __forceinline vfloat(UndefinedTy) : v(_mm256_undefined_ps()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vfloat8 broadcast(const void* a) {
+ return _mm256_broadcast_ss((float*)a);
+ }
+
+ static __forceinline vfloat8 load(const char* ptr) {
+#if defined(__AVX2__)
+ return _mm256_cvtepi32_ps(_mm256_cvtepi8_epi32(_mm_loadu_si128((__m128i*)ptr)));
+#else
+ return vfloat8(vfloat4::load(ptr),vfloat4::load(ptr+4));
+#endif
+ }
+
+ static __forceinline vfloat8 load(const unsigned char* ptr) {
+#if defined(__AVX2__)
+ return _mm256_cvtepi32_ps(_mm256_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)));
+#else
+ return vfloat8(vfloat4::load(ptr),vfloat4::load(ptr+4));
+#endif
+ }
+
+ static __forceinline vfloat8 load(const short* ptr) {
+#if defined(__AVX2__)
+ return _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm_loadu_si128((__m128i*)ptr)));
+#else
+ return vfloat8(vfloat4::load(ptr),vfloat4::load(ptr+4));
+#endif
+ }
+
+ static __forceinline vfloat8 load (const void* ptr) { return _mm256_load_ps((float*)ptr); }
+ static __forceinline vfloat8 loadu(const void* ptr) { return _mm256_loadu_ps((float*)ptr); }
+
+ static __forceinline void store (void* ptr, const vfloat8& v) { return _mm256_store_ps((float*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vfloat8& v) { return _mm256_storeu_ps((float*)ptr,v); }
+
+#if defined(__AVX512VL__)
+
+ static __forceinline vfloat8 load (const vboolf8& mask, const void* ptr) { return _mm256_mask_load_ps (_mm256_setzero_ps(),mask,(float*)ptr); }
+ static __forceinline vfloat8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_mask_loadu_ps(_mm256_setzero_ps(),mask,(float*)ptr); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_mask_store_ps ((float*)ptr,mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_mask_storeu_ps((float*)ptr,mask,v); }
+#else
+ static __forceinline vfloat8 load (const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask); }
+ static __forceinline vfloat8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_maskload_ps((float*)ptr,(__m256i)mask); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vfloat8& v) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,v); }
+#endif
+
+#if defined(__AVX2__)
+ static __forceinline vfloat8 load_nt(void* ptr) {
+ return _mm256_castsi256_ps(_mm256_stream_load_si256((__m256i*)ptr));
+ }
+#endif
+
+ static __forceinline void store_nt(void* ptr, const vfloat8& v) {
+ _mm256_stream_ps((float*)ptr,v);
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat8 gather(const float* ptr, const vint8& index) {
+#if defined(__AVX2__)
+ return _mm256_i32gather_ps(ptr, index ,scale);
+#else
+ return vfloat8(
+ *(float*)(((char*)ptr)+scale*index[0]),
+ *(float*)(((char*)ptr)+scale*index[1]),
+ *(float*)(((char*)ptr)+scale*index[2]),
+ *(float*)(((char*)ptr)+scale*index[3]),
+ *(float*)(((char*)ptr)+scale*index[4]),
+ *(float*)(((char*)ptr)+scale*index[5]),
+ *(float*)(((char*)ptr)+scale*index[6]),
+ *(float*)(((char*)ptr)+scale*index[7]));
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vfloat8 gather(const vboolf8& mask, const float* ptr, const vint8& index) {
+ vfloat8 r = zero;
+#if defined(__AVX512VL__)
+ return _mm256_mmask_i32gather_ps(r, mask, index, ptr, scale);
+#elif defined(__AVX2__)
+ return _mm256_mask_i32gather_ps(r, ptr, index, mask, scale);
+#else
+ if (likely(mask[0])) r[0] = *(float*)(((char*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(float*)(((char*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(float*)(((char*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(float*)(((char*)ptr)+scale*index[3]);
+ if (likely(mask[4])) r[4] = *(float*)(((char*)ptr)+scale*index[4]);
+ if (likely(mask[5])) r[5] = *(float*)(((char*)ptr)+scale*index[5]);
+ if (likely(mask[6])) r[6] = *(float*)(((char*)ptr)+scale*index[6]);
+ if (likely(mask[7])) r[7] = *(float*)(((char*)ptr)+scale*index[7]);
+ return r;
+ #endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint8& ofs, const vfloat8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_i32scatter_ps((float*)ptr, ofs, v, scale);
+#else
+ *(float*)(((char*)ptr)+scale*ofs[0]) = v[0];
+ *(float*)(((char*)ptr)+scale*ofs[1]) = v[1];
+ *(float*)(((char*)ptr)+scale*ofs[2]) = v[2];
+ *(float*)(((char*)ptr)+scale*ofs[3]) = v[3];
+ *(float*)(((char*)ptr)+scale*ofs[4]) = v[4];
+ *(float*)(((char*)ptr)+scale*ofs[5]) = v[5];
+ *(float*)(((char*)ptr)+scale*ofs[6]) = v[6];
+ *(float*)(((char*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vfloat8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_mask_i32scatter_ps((float*)ptr, mask, ofs, v, scale);
+#else
+ if (likely(mask[0])) *(float*)(((char*)ptr)+scale*ofs[0]) = v[0];
+ if (likely(mask[1])) *(float*)(((char*)ptr)+scale*ofs[1]) = v[1];
+ if (likely(mask[2])) *(float*)(((char*)ptr)+scale*ofs[2]) = v[2];
+ if (likely(mask[3])) *(float*)(((char*)ptr)+scale*ofs[3]) = v[3];
+ if (likely(mask[4])) *(float*)(((char*)ptr)+scale*ofs[4]) = v[4];
+ if (likely(mask[5])) *(float*)(((char*)ptr)+scale*ofs[5]) = v[5];
+ if (likely(mask[6])) *(float*)(((char*)ptr)+scale*ofs[6]) = v[6];
+ if (likely(mask[7])) *(float*)(((char*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const float& operator [](size_t index) const { assert(index < 8); return f[index]; }
+ __forceinline float& operator [](size_t index) { assert(index < 8); return f[index]; }
+ };
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8 asFloat(const vint8& a) { return _mm256_castsi256_ps(a); }
+ __forceinline vint8 asInt (const vfloat8& a) { return _mm256_castps_si256(a); }
+
+ __forceinline vint8 toInt (const vfloat8& a) { return vint8(a); }
+ __forceinline vfloat8 toFloat(const vint8& a) { return vfloat8(a); }
+
+ __forceinline vfloat8 operator +(const vfloat8& a) { return a; }
+ __forceinline vfloat8 operator -(const vfloat8& a) {
+ const __m256 mask = _mm256_castsi256_ps(_mm256_set1_epi32(0x80000000));
+ return _mm256_xor_ps(a, mask);
+ }
+ __forceinline vfloat8 abs(const vfloat8& a) {
+ const __m256 mask = _mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff));
+ return _mm256_and_ps(a, mask);
+ }
+ __forceinline vfloat8 sign (const vfloat8& a) { return _mm256_blendv_ps(vfloat8(one), -vfloat8(one), _mm256_cmp_ps(a, vfloat8(zero), _CMP_NGE_UQ)); }
+ __forceinline vfloat8 signmsk(const vfloat8& a) { return _mm256_and_ps(a,_mm256_castsi256_ps(_mm256_set1_epi32(0x80000000))); }
+
+
+ static __forceinline vfloat8 rcp(const vfloat8& a)
+ {
+#if defined(__AVX512VL__)
+ const vfloat8 r = _mm256_rcp14_ps(a);
+#else
+ const vfloat8 r = _mm256_rcp_ps(a);
+#endif
+
+#if defined(__AVX2__)
+ return _mm256_mul_ps(r, _mm256_fnmadd_ps(r, a, vfloat8(2.0f)));
+#else
+ return _mm256_mul_ps(r, _mm256_sub_ps(vfloat8(2.0f), _mm256_mul_ps(r, a)));
+#endif
+ }
+ __forceinline vfloat8 sqr (const vfloat8& a) { return _mm256_mul_ps(a,a); }
+ __forceinline vfloat8 sqrt(const vfloat8& a) { return _mm256_sqrt_ps(a); }
+
+ static __forceinline vfloat8 rsqrt(const vfloat8& a)
+ {
+#if defined(__AVX512VL__)
+ const vfloat8 r = _mm256_rsqrt14_ps(a);
+#else
+ const vfloat8 r = _mm256_rsqrt_ps(a);
+#endif
+
+#if defined(__AVX2__)
+ return _mm256_fmadd_ps(_mm256_set1_ps(1.5f), r,
+ _mm256_mul_ps(_mm256_mul_ps(_mm256_mul_ps(a, _mm256_set1_ps(-0.5f)), r), _mm256_mul_ps(r, r)));
+#else
+ return _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(1.5f), r),
+ _mm256_mul_ps(_mm256_mul_ps(_mm256_mul_ps(a, _mm256_set1_ps(-0.5f)), r), _mm256_mul_ps(r, r)));
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8 operator +(const vfloat8& a, const vfloat8& b) { return _mm256_add_ps(a, b); }
+ __forceinline vfloat8 operator +(const vfloat8& a, float b) { return a + vfloat8(b); }
+ __forceinline vfloat8 operator +(float a, const vfloat8& b) { return vfloat8(a) + b; }
+
+ __forceinline vfloat8 operator -(const vfloat8& a, const vfloat8& b) { return _mm256_sub_ps(a, b); }
+ __forceinline vfloat8 operator -(const vfloat8& a, float b) { return a - vfloat8(b); }
+ __forceinline vfloat8 operator -(float a, const vfloat8& b) { return vfloat8(a) - b; }
+
+ __forceinline vfloat8 operator *(const vfloat8& a, const vfloat8& b) { return _mm256_mul_ps(a, b); }
+ __forceinline vfloat8 operator *(const vfloat8& a, float b) { return a * vfloat8(b); }
+ __forceinline vfloat8 operator *(float a, const vfloat8& b) { return vfloat8(a) * b; }
+
+ __forceinline vfloat8 operator /(const vfloat8& a, const vfloat8& b) { return _mm256_div_ps(a, b); }
+ __forceinline vfloat8 operator /(const vfloat8& a, float b) { return a / vfloat8(b); }
+ __forceinline vfloat8 operator /(float a, const vfloat8& b) { return vfloat8(a) / b; }
+
+ __forceinline vfloat8 operator &(const vfloat8& a, const vfloat8& b) { return _mm256_and_ps(a,b); }
+ __forceinline vfloat8 operator |(const vfloat8& a, const vfloat8& b) { return _mm256_or_ps(a,b); }
+ __forceinline vfloat8 operator ^(const vfloat8& a, const vfloat8& b) { return _mm256_xor_ps(a,b); }
+ __forceinline vfloat8 operator ^(const vfloat8& a, const vint8& b) { return _mm256_xor_ps(a,_mm256_castsi256_ps(b)); }
+
+ __forceinline vfloat8 min(const vfloat8& a, const vfloat8& b) { return _mm256_min_ps(a, b); }
+ __forceinline vfloat8 min(const vfloat8& a, float b) { return _mm256_min_ps(a, vfloat8(b)); }
+ __forceinline vfloat8 min(float a, const vfloat8& b) { return _mm256_min_ps(vfloat8(a), b); }
+
+ __forceinline vfloat8 max(const vfloat8& a, const vfloat8& b) { return _mm256_max_ps(a, b); }
+ __forceinline vfloat8 max(const vfloat8& a, float b) { return _mm256_max_ps(a, vfloat8(b)); }
+ __forceinline vfloat8 max(float a, const vfloat8& b) { return _mm256_max_ps(vfloat8(a), b); }
+
+ /* need "static __forceinline for MSVC, otherwise we'll link the wrong version in debug mode */
+#if defined(__AVX2__)
+
+ static __forceinline vfloat8 mini(const vfloat8& a, const vfloat8& b) {
+ const vint8 ai = _mm256_castps_si256(a);
+ const vint8 bi = _mm256_castps_si256(b);
+ const vint8 ci = _mm256_min_epi32(ai,bi);
+ return _mm256_castsi256_ps(ci);
+ }
+
+ static __forceinline vfloat8 maxi(const vfloat8& a, const vfloat8& b) {
+ const vint8 ai = _mm256_castps_si256(a);
+ const vint8 bi = _mm256_castps_si256(b);
+ const vint8 ci = _mm256_max_epi32(ai,bi);
+ return _mm256_castsi256_ps(ci);
+ }
+
+ static __forceinline vfloat8 minui(const vfloat8& a, const vfloat8& b) {
+ const vint8 ai = _mm256_castps_si256(a);
+ const vint8 bi = _mm256_castps_si256(b);
+ const vint8 ci = _mm256_min_epu32(ai,bi);
+ return _mm256_castsi256_ps(ci);
+ }
+
+ static __forceinline vfloat8 maxui(const vfloat8& a, const vfloat8& b) {
+ const vint8 ai = _mm256_castps_si256(a);
+ const vint8 bi = _mm256_castps_si256(b);
+ const vint8 ci = _mm256_max_epu32(ai,bi);
+ return _mm256_castsi256_ps(ci);
+ }
+
+#else
+
+ static __forceinline vfloat8 mini(const vfloat8& a, const vfloat8& b) {
+ return asFloat(min(asInt(a),asInt(b)));
+ }
+
+ static __forceinline vfloat8 maxi(const vfloat8& a, const vfloat8& b) {
+ return asFloat(max(asInt(a),asInt(b)));
+ }
+
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Ternary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX2__)
+ static __forceinline vfloat8 madd (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return _mm256_fmadd_ps(a,b,c); }
+ static __forceinline vfloat8 msub (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return _mm256_fmsub_ps(a,b,c); }
+ static __forceinline vfloat8 nmadd (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return _mm256_fnmadd_ps(a,b,c); }
+ static __forceinline vfloat8 nmsub (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return _mm256_fnmsub_ps(a,b,c); }
+#else
+ static __forceinline vfloat8 madd (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return a*b+c; }
+ static __forceinline vfloat8 msub (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return a*b-c; }
+ static __forceinline vfloat8 nmadd (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return -a*b+c;}
+ static __forceinline vfloat8 nmsub (const vfloat8& a, const vfloat8& b, const vfloat8& c) { return -a*b-c; }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8& operator +=(vfloat8& a, const vfloat8& b) { return a = a + b; }
+ __forceinline vfloat8& operator +=(vfloat8& a, float b) { return a = a + b; }
+
+ __forceinline vfloat8& operator -=(vfloat8& a, const vfloat8& b) { return a = a - b; }
+ __forceinline vfloat8& operator -=(vfloat8& a, float b) { return a = a - b; }
+
+ __forceinline vfloat8& operator *=(vfloat8& a, const vfloat8& b) { return a = a * b; }
+ __forceinline vfloat8& operator *=(vfloat8& a, float b) { return a = a * b; }
+
+ __forceinline vfloat8& operator /=(vfloat8& a, const vfloat8& b) { return a = a / b; }
+ __forceinline vfloat8& operator /=(vfloat8& a, float b) { return a = a / b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ static __forceinline vboolf8 operator ==(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_EQ); }
+ static __forceinline vboolf8 operator !=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_NE); }
+ static __forceinline vboolf8 operator < (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_LT); }
+ static __forceinline vboolf8 operator >=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_GE); }
+ static __forceinline vboolf8 operator > (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_GT); }
+ static __forceinline vboolf8 operator <=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps_mask(a, b, _MM_CMPINT_LE); }
+
+ static __forceinline vfloat8 select(const vboolf8& m, const vfloat8& t, const vfloat8& f) {
+ return _mm256_mask_blend_ps(m, f, t);
+ }
+#else
+ static __forceinline vboolf8 operator ==(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_EQ_OQ); }
+ static __forceinline vboolf8 operator !=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NEQ_UQ); }
+ static __forceinline vboolf8 operator < (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_LT_OS); }
+ static __forceinline vboolf8 operator >=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NLT_US); }
+ static __forceinline vboolf8 operator > (const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_NLE_US); }
+ static __forceinline vboolf8 operator <=(const vfloat8& a, const vfloat8& b) { return _mm256_cmp_ps(a, b, _CMP_LE_OS); }
+
+ static __forceinline vfloat8 select(const vboolf8& m, const vfloat8& t, const vfloat8& f) {
+ return _mm256_blendv_ps(f, t, m);
+ }
+#endif
+
+ template<int mask>
+ __forceinline vfloat8 select(const vfloat8& t, const vfloat8& f) {
+ return _mm256_blend_ps(f, t, mask);
+ }
+
+ __forceinline vboolf8 operator ==(const vfloat8& a, const float& b) { return a == vfloat8(b); }
+ __forceinline vboolf8 operator ==(const float& a, const vfloat8& b) { return vfloat8(a) == b; }
+
+ __forceinline vboolf8 operator !=(const vfloat8& a, const float& b) { return a != vfloat8(b); }
+ __forceinline vboolf8 operator !=(const float& a, const vfloat8& b) { return vfloat8(a) != b; }
+
+ __forceinline vboolf8 operator < (const vfloat8& a, const float& b) { return a < vfloat8(b); }
+ __forceinline vboolf8 operator < (const float& a, const vfloat8& b) { return vfloat8(a) < b; }
+
+ __forceinline vboolf8 operator >=(const vfloat8& a, const float& b) { return a >= vfloat8(b); }
+ __forceinline vboolf8 operator >=(const float& a, const vfloat8& b) { return vfloat8(a) >= b; }
+
+ __forceinline vboolf8 operator > (const vfloat8& a, const float& b) { return a > vfloat8(b); }
+ __forceinline vboolf8 operator > (const float& a, const vfloat8& b) { return vfloat8(a) > b; }
+
+ __forceinline vboolf8 operator <=(const vfloat8& a, const float& b) { return a <= vfloat8(b); }
+ __forceinline vboolf8 operator <=(const float& a, const vfloat8& b) { return vfloat8(a) <= b; }
+
+ __forceinline vboolf8 eq(const vfloat8& a, const vfloat8& b) { return a == b; }
+ __forceinline vboolf8 ne(const vfloat8& a, const vfloat8& b) { return a != b; }
+ __forceinline vboolf8 lt(const vfloat8& a, const vfloat8& b) { return a < b; }
+ __forceinline vboolf8 ge(const vfloat8& a, const vfloat8& b) { return a >= b; }
+ __forceinline vboolf8 gt(const vfloat8& a, const vfloat8& b) { return a > b; }
+ __forceinline vboolf8 le(const vfloat8& a, const vfloat8& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ static __forceinline vboolf8 eq(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_EQ); }
+ static __forceinline vboolf8 ne(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_NE); }
+ static __forceinline vboolf8 lt(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_LT); }
+ static __forceinline vboolf8 ge(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_GE); }
+ static __forceinline vboolf8 gt(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_GT); }
+ static __forceinline vboolf8 le(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return _mm256_mask_cmp_ps_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ static __forceinline vboolf8 eq(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a == b); }
+ static __forceinline vboolf8 ne(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a != b); }
+ static __forceinline vboolf8 lt(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a < b); }
+ static __forceinline vboolf8 ge(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a >= b); }
+ static __forceinline vboolf8 gt(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a > b); }
+ static __forceinline vboolf8 le(const vboolf8& mask, const vfloat8& a, const vfloat8& b) { return mask & (a <= b); }
+#endif
+
+ __forceinline vfloat8 lerp(const vfloat8& a, const vfloat8& b, const vfloat8& t) {
+ return madd(t,b-a,a);
+ }
+
+ __forceinline bool isvalid (const vfloat8& v) {
+ return all((v > vfloat8(-FLT_LARGE)) & (v < vfloat8(+FLT_LARGE)));
+ }
+
+ __forceinline bool is_finite (const vfloat8& a) {
+ return all((a >= vfloat8(-FLT_MAX)) & (a <= vfloat8(+FLT_MAX)));
+ }
+
+ __forceinline bool is_finite (const vboolf8& valid, const vfloat8& a) {
+ return all(valid, (a >= vfloat8(-FLT_MAX)) & (a <= vfloat8(+FLT_MAX)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Rounding Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8 floor(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_NEG_INF ); }
+ __forceinline vfloat8 ceil (const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_POS_INF ); }
+ __forceinline vfloat8 trunc(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_ZERO ); }
+ __forceinline vfloat8 round(const vfloat8& a) { return _mm256_round_ps(a, _MM_FROUND_TO_NEAREST_INT); }
+ __forceinline vfloat8 frac (const vfloat8& a) { return a-floor(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8 unpacklo(const vfloat8& a, const vfloat8& b) { return _mm256_unpacklo_ps(a, b); }
+ __forceinline vfloat8 unpackhi(const vfloat8& a, const vfloat8& b) { return _mm256_unpackhi_ps(a, b); }
+
+ template<int i>
+ __forceinline vfloat8 shuffle(const vfloat8& v) {
+ return _mm256_permute_ps(v, _MM_SHUFFLE(i, i, i, i));
+ }
+
+ template<int i0, int i1>
+ __forceinline vfloat8 shuffle4(const vfloat8& v) {
+ return _mm256_permute2f128_ps(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vfloat8 shuffle4(const vfloat8& a, const vfloat8& b) {
+ return _mm256_permute2f128_ps(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat8 shuffle(const vfloat8& v) {
+ return _mm256_permute_ps(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vfloat8 shuffle(const vfloat8& a, const vfloat8& b) {
+ return _mm256_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<> __forceinline vfloat8 shuffle<0, 0, 2, 2>(const vfloat8& v) { return _mm256_moveldup_ps(v); }
+ template<> __forceinline vfloat8 shuffle<1, 1, 3, 3>(const vfloat8& v) { return _mm256_movehdup_ps(v); }
+ template<> __forceinline vfloat8 shuffle<0, 1, 0, 1>(const vfloat8& v) { return _mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(v))); }
+
+ __forceinline vfloat8 broadcast(const float* ptr) { return _mm256_broadcast_ss(ptr); }
+ template<size_t i> __forceinline vfloat8 insert4(const vfloat8& a, const vfloat4& b) { return _mm256_insertf128_ps(a, b, i); }
+ template<size_t i> __forceinline vfloat4 extract4 (const vfloat8& a) { return _mm256_extractf128_ps(a, i); }
+ template<> __forceinline vfloat4 extract4<0>(const vfloat8& a) { return _mm256_castps256_ps128(a); }
+
+ __forceinline float toScalar(const vfloat8& v) { return _mm_cvtss_f32(_mm256_castps256_ps128(v)); }
+
+#if defined (__AVX2__)
+ static __forceinline vfloat8 permute(const vfloat8& a, const __m256i& index) {
+ return _mm256_permutevar8x32_ps(a, index);
+ }
+#endif
+
+#if defined(__AVX512VL__)
+ template<int i>
+ static __forceinline vfloat8 align_shift_right(const vfloat8& a, const vfloat8& b) {
+ return _mm256_castsi256_ps(_mm256_alignr_epi32(_mm256_castps_si256(a), _mm256_castps_si256(b), i));
+ }
+#endif
+
+#if defined (__AVX_I__)
+ template<const int mode>
+ static __forceinline vint4 convert_to_hf16(const vfloat8& a) {
+ return _mm256_cvtps_ph(a, mode);
+ }
+
+ static __forceinline vfloat8 convert_from_hf16(const vint4& a) {
+ return _mm256_cvtph_ps(a);
+ }
+#endif
+
+#if defined(__AVX512VL__)
+ static __forceinline vfloat8 shift_right_1(const vfloat8& x) {
+ return align_shift_right<1>(zero,x);
+ }
+#else
+ static __forceinline vfloat8 shift_right_1(const vfloat8& x) {
+ const vfloat8 t0 = shuffle<1,2,3,0>(x);
+ const vfloat8 t1 = shuffle4<1,0>(t0);
+ return _mm256_blend_ps(t0,t1,0x88);
+ }
+#endif
+
+ __forceinline vint8 floori(const vfloat8& a) {
+ return vint8(floor(a));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Transpose
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline void transpose(const vfloat8& r0, const vfloat8& r1, const vfloat8& r2, const vfloat8& r3, vfloat8& c0, vfloat8& c1, vfloat8& c2, vfloat8& c3)
+ {
+ vfloat8 l02 = unpacklo(r0,r2);
+ vfloat8 h02 = unpackhi(r0,r2);
+ vfloat8 l13 = unpacklo(r1,r3);
+ vfloat8 h13 = unpackhi(r1,r3);
+ c0 = unpacklo(l02,l13);
+ c1 = unpackhi(l02,l13);
+ c2 = unpacklo(h02,h13);
+ c3 = unpackhi(h02,h13);
+ }
+
+ __forceinline void transpose(const vfloat8& r0, const vfloat8& r1, const vfloat8& r2, const vfloat8& r3, vfloat8& c0, vfloat8& c1, vfloat8& c2)
+ {
+ vfloat8 l02 = unpacklo(r0,r2);
+ vfloat8 h02 = unpackhi(r0,r2);
+ vfloat8 l13 = unpacklo(r1,r3);
+ vfloat8 h13 = unpackhi(r1,r3);
+ c0 = unpacklo(l02,l13);
+ c1 = unpackhi(l02,l13);
+ c2 = unpacklo(h02,h13);
+ }
+
+ __forceinline void transpose(const vfloat8& r0, const vfloat8& r1, const vfloat8& r2, const vfloat8& r3, const vfloat8& r4, const vfloat8& r5, const vfloat8& r6, const vfloat8& r7,
+ vfloat8& c0, vfloat8& c1, vfloat8& c2, vfloat8& c3, vfloat8& c4, vfloat8& c5, vfloat8& c6, vfloat8& c7)
+ {
+ vfloat8 h0,h1,h2,h3; transpose(r0,r1,r2,r3,h0,h1,h2,h3);
+ vfloat8 h4,h5,h6,h7; transpose(r4,r5,r6,r7,h4,h5,h6,h7);
+ c0 = shuffle4<0,2>(h0,h4);
+ c1 = shuffle4<0,2>(h1,h5);
+ c2 = shuffle4<0,2>(h2,h6);
+ c3 = shuffle4<0,2>(h3,h7);
+ c4 = shuffle4<1,3>(h0,h4);
+ c5 = shuffle4<1,3>(h1,h5);
+ c6 = shuffle4<1,3>(h2,h6);
+ c7 = shuffle4<1,3>(h3,h7);
+ }
+
+ __forceinline void transpose(const vfloat4& r0, const vfloat4& r1, const vfloat4& r2, const vfloat4& r3, const vfloat4& r4, const vfloat4& r5, const vfloat4& r6, const vfloat4& r7,
+ vfloat8& c0, vfloat8& c1, vfloat8& c2, vfloat8& c3)
+ {
+ transpose(vfloat8(r0,r4), vfloat8(r1,r5), vfloat8(r2,r6), vfloat8(r3,r7), c0, c1, c2, c3);
+ }
+
+ __forceinline void transpose(const vfloat4& r0, const vfloat4& r1, const vfloat4& r2, const vfloat4& r3, const vfloat4& r4, const vfloat4& r5, const vfloat4& r6, const vfloat4& r7,
+ vfloat8& c0, vfloat8& c1, vfloat8& c2)
+ {
+ transpose(vfloat8(r0,r4), vfloat8(r1,r5), vfloat8(r2,r6), vfloat8(r3,r7), c0, c1, c2);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8 vreduce_min2(const vfloat8& v) { return min(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vfloat8 vreduce_min4(const vfloat8& v) { vfloat8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vfloat8 vreduce_min (const vfloat8& v) { vfloat8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vfloat8 vreduce_max2(const vfloat8& v) { return max(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vfloat8 vreduce_max4(const vfloat8& v) { vfloat8 v1 = vreduce_max2(v); return max(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vfloat8 vreduce_max (const vfloat8& v) { vfloat8 v1 = vreduce_max4(v); return max(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vfloat8 vreduce_add2(const vfloat8& v) { return v + shuffle<1,0,3,2>(v); }
+ __forceinline vfloat8 vreduce_add4(const vfloat8& v) { vfloat8 v1 = vreduce_add2(v); return v1 + shuffle<2,3,0,1>(v1); }
+ __forceinline vfloat8 vreduce_add (const vfloat8& v) { vfloat8 v1 = vreduce_add4(v); return v1 + shuffle4<1,0>(v1); }
+
+ __forceinline float reduce_min(const vfloat8& v) { return toScalar(vreduce_min(v)); }
+ __forceinline float reduce_max(const vfloat8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline float reduce_add(const vfloat8& v) { return toScalar(vreduce_add(v)); }
+
+ __forceinline size_t select_min(const vboolf8& valid, const vfloat8& v)
+ {
+ const vfloat8 a = select(valid,v,vfloat8(pos_inf));
+ const vbool8 valid_min = valid & (a == vreduce_min(a));
+ return bsf(movemask(any(valid_min) ? valid_min : valid));
+ }
+
+ __forceinline size_t select_max(const vboolf8& valid, const vfloat8& v)
+ {
+ const vfloat8 a = select(valid,v,vfloat8(neg_inf));
+ const vbool8 valid_max = valid & (a == vreduce_max(a));
+ return bsf(movemask(any(valid_max) ? valid_max : valid));
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Euclidian Space Operators (pairs of Vec3fa's)
+ ////////////////////////////////////////////////////////////////////////////////
+
+ //__forceinline vfloat8 dot(const vfloat8& a, const vfloat8& b) {
+ // return vreduce_add4(a*b);
+ //}
+
+ __forceinline vfloat8 dot(const vfloat8& a, const vfloat8& b) {
+ return _mm256_dp_ps(a,b,0x7F);
+ }
+
+ __forceinline vfloat8 cross(const vfloat8& a, const vfloat8& b)
+ {
+ const vfloat8 a0 = a;
+ const vfloat8 b0 = shuffle<1,2,0,3>(b);
+ const vfloat8 a1 = shuffle<1,2,0,3>(a);
+ const vfloat8 b1 = b;
+ return shuffle<1,2,0,3>(msub(a0,b0,a1*b1));
+ }
+
+ //__forceinline float sqr_length (const vfloat<8>& a) { return dot(a,a); }
+ //__forceinline float rcp_length (const vfloat<8>& a) { return rsqrt(dot(a,a)); }
+ //__forceinline float rcp_length2(const vfloat<8>& a) { return rcp(dot(a,a)); }
+ //__forceinline float length (const vfloat<8>& a) { return sqrt(dot(a,a)); }
+ __forceinline vfloat<8> normalize(const vfloat<8>& a) { return a*rsqrt(dot(a,a)); }
+ //__forceinline float distance(const vfloat<8>& a, const vfloat<8>& b) { return length(a-b); }
+ //__forceinline float halfArea(const vfloat<8>& d) { return madd(d.x,(d.y+d.z),d.y*d.z); }
+ //__forceinline float area (const vfloat<8>& d) { return 2.0f*halfArea(d); }
+ //__forceinline vfloat<8> reflect(const vfloat<8>& V, const vfloat<8>& N) { return 2.0f*dot(V,N)*N-V; }
+
+ //__forceinline vfloat<8> normalize_safe(const vfloat<8>& a) {
+ // const float d = dot(a,a); if (unlikely(d == 0.0f)) return a; else return a*rsqrt(d);
+ //}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// In Register Sorting
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vfloat8 sort_ascending(const vfloat8& v)
+ {
+ const vfloat8 a0 = v;
+ const vfloat8 b0 = shuffle<1,0,3,2>(a0);
+ const vfloat8 c0 = min(a0,b0);
+ const vfloat8 d0 = max(a0,b0);
+ const vfloat8 a1 = select<0x99 /* 0b10011001 */>(c0,d0);
+ const vfloat8 b1 = shuffle<2,3,0,1>(a1);
+ const vfloat8 c1 = min(a1,b1);
+ const vfloat8 d1 = max(a1,b1);
+ const vfloat8 a2 = select<0xc3 /* 0b11000011 */>(c1,d1);
+ const vfloat8 b2 = shuffle<1,0,3,2>(a2);
+ const vfloat8 c2 = min(a2,b2);
+ const vfloat8 d2 = max(a2,b2);
+ const vfloat8 a3 = select<0xa5 /* 0b10100101 */>(c2,d2);
+ const vfloat8 b3 = shuffle4<1,0>(a3);
+ const vfloat8 c3 = min(a3,b3);
+ const vfloat8 d3 = max(a3,b3);
+ const vfloat8 a4 = select<0xf /* 0b00001111 */>(c3,d3);
+ const vfloat8 b4 = shuffle<2,3,0,1>(a4);
+ const vfloat8 c4 = min(a4,b4);
+ const vfloat8 d4 = max(a4,b4);
+ const vfloat8 a5 = select<0x33 /* 0b00110011 */>(c4,d4);
+ const vfloat8 b5 = shuffle<1,0,3,2>(a5);
+ const vfloat8 c5 = min(a5,b5);
+ const vfloat8 d5 = max(a5,b5);
+ const vfloat8 a6 = select<0x55 /* 0b01010101 */>(c5,d5);
+ return a6;
+ }
+
+ __forceinline vfloat8 sort_descending(const vfloat8& v)
+ {
+ const vfloat8 a0 = v;
+ const vfloat8 b0 = shuffle<1,0,3,2>(a0);
+ const vfloat8 c0 = max(a0,b0);
+ const vfloat8 d0 = min(a0,b0);
+ const vfloat8 a1 = select<0x99 /* 0b10011001 */>(c0,d0);
+ const vfloat8 b1 = shuffle<2,3,0,1>(a1);
+ const vfloat8 c1 = max(a1,b1);
+ const vfloat8 d1 = min(a1,b1);
+ const vfloat8 a2 = select<0xc3 /* 0b11000011 */>(c1,d1);
+ const vfloat8 b2 = shuffle<1,0,3,2>(a2);
+ const vfloat8 c2 = max(a2,b2);
+ const vfloat8 d2 = min(a2,b2);
+ const vfloat8 a3 = select<0xa5 /* 0b10100101 */>(c2,d2);
+ const vfloat8 b3 = shuffle4<1,0>(a3);
+ const vfloat8 c3 = max(a3,b3);
+ const vfloat8 d3 = min(a3,b3);
+ const vfloat8 a4 = select<0xf /* 0b00001111 */>(c3,d3);
+ const vfloat8 b4 = shuffle<2,3,0,1>(a4);
+ const vfloat8 c4 = max(a4,b4);
+ const vfloat8 d4 = min(a4,b4);
+ const vfloat8 a5 = select<0x33 /* 0b00110011 */>(c4,d4);
+ const vfloat8 b5 = shuffle<1,0,3,2>(a5);
+ const vfloat8 c5 = max(a5,b5);
+ const vfloat8 d5 = min(a5,b5);
+ const vfloat8 a6 = select<0x55 /* 0b01010101 */>(c5,d5);
+ return a6;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vfloat8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vint16_avx512.h b/thirdparty/embree/common/simd/vint16_avx512.h
new file mode 100644
index 0000000000..3720c3c9d6
--- /dev/null
+++ b/thirdparty/embree/common/simd/vint16_avx512.h
@@ -0,0 +1,472 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 16-wide AVX-512 integer type */
+ template<>
+ struct vint<16>
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef vboolf16 Bool;
+ typedef vint16 Int;
+ typedef vfloat16 Float;
+
+ enum { size = 16 }; // number of SIMD elements
+ union { // data
+ __m512i v;
+ int i[16];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint() {}
+ __forceinline vint(const vint16& t) { v = t.v; }
+ __forceinline vint16& operator =(const vint16& f) { v = f.v; return *this; }
+
+ __forceinline vint(const __m512i& t) { v = t; }
+ __forceinline operator __m512i() const { return v; }
+ __forceinline operator __m256i() const { return _mm512_castsi512_si256(v); }
+
+ __forceinline vint(int i) {
+ v = _mm512_set1_epi32(i);
+ }
+
+ __forceinline vint(int a, int b, int c, int d) {
+ v = _mm512_set4_epi32(d,c,b,a);
+ }
+
+ __forceinline vint(int a0 , int a1 , int a2 , int a3,
+ int a4 , int a5 , int a6 , int a7,
+ int a8 , int a9 , int a10, int a11,
+ int a12, int a13, int a14, int a15)
+ {
+ v = _mm512_set_epi32(a15,a14,a13,a12,a11,a10,a9,a8,a7,a6,a5,a4,a3,a2,a1,a0);
+ }
+
+ __forceinline vint(const vint4& i) {
+ v = _mm512_broadcast_i32x4(i);
+ }
+
+ __forceinline vint(const vint4& a, const vint4& b, const vint4& c, const vint4& d) {
+ v = _mm512_castsi128_si512(a);
+ v = _mm512_inserti32x4(v, b, 1);
+ v = _mm512_inserti32x4(v, c, 2);
+ v = _mm512_inserti32x4(v, d, 3);
+ }
+
+ __forceinline vint(const vint8& i) {
+ v = _mm512_castps_si512(_mm512_castpd_ps(_mm512_broadcast_f64x4(_mm256_castsi256_pd(i))));
+ }
+
+ __forceinline vint(const vint8& a, const vint8& b) {
+ v = _mm512_castsi256_si512(a);
+ v = _mm512_inserti64x4(v, b, 1);
+ }
+
+ __forceinline explicit vint(const __m512& f) {
+ v = _mm512_cvtps_epi32(f);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint(ZeroTy) : v(_mm512_setzero_epi32()) {}
+ __forceinline vint(OneTy) : v(_mm512_set1_epi32(1)) {}
+ __forceinline vint(PosInfTy) : v(_mm512_set1_epi32(pos_inf)) {}
+ __forceinline vint(NegInfTy) : v(_mm512_set1_epi32(neg_inf)) {}
+ __forceinline vint(StepTy) : v(_mm512_set_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) {}
+ __forceinline vint(ReverseStepTy) : v(_mm512_setr_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vint16 load (const void* addr) { return _mm512_load_si512((int*)addr); }
+
+ static __forceinline vint16 load(const unsigned char* ptr) { return _mm512_cvtepu8_epi32(_mm_load_si128((__m128i*)ptr)); }
+ static __forceinline vint16 load(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_load_si256((__m256i*)ptr)); }
+
+ static __forceinline vint16 loadu(const unsigned char* ptr) { return _mm512_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)); }
+ static __forceinline vint16 loadu(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_loadu_si256((__m256i*)ptr)); }
+
+ static __forceinline vint16 loadu(const void* addr) { return _mm512_loadu_si512(addr); }
+
+ static __forceinline vint16 load (const vboolf16& mask, const void* addr) { return _mm512_mask_load_epi32 (_mm512_setzero_epi32(),mask,addr); }
+ static __forceinline vint16 loadu(const vboolf16& mask, const void* addr) { return _mm512_mask_loadu_epi32(_mm512_setzero_epi32(),mask,addr); }
+
+ static __forceinline void store (void* ptr, const vint16& v) { _mm512_store_si512 (ptr,v); }
+ static __forceinline void storeu(void* ptr, const vint16& v) { _mm512_storeu_si512(ptr,v); }
+
+ static __forceinline void store (const vboolf16& mask, void* addr, const vint16& v2) { _mm512_mask_store_epi32(addr,mask,v2); }
+ static __forceinline void storeu(const vboolf16& mask, void* ptr, const vint16& f) { _mm512_mask_storeu_epi32((int*)ptr,mask,f); }
+
+ static __forceinline void store_nt(void* __restrict__ ptr, const vint16& a) { _mm512_stream_si512((__m512i*)ptr,a); }
+
+ static __forceinline vint16 compact(const vboolf16& mask, vint16 &v) {
+ return _mm512_mask_compress_epi32(v,mask,v);
+ }
+
+ static __forceinline vint16 compact(const vboolf16& mask, const vint16 &a, vint16 &b) {
+ return _mm512_mask_compress_epi32(a,mask,b);
+ }
+
+ static __forceinline vint16 expand(const vboolf16& mask, const vint16& a, vint16& b) {
+ return _mm512_mask_expand_epi32(b,mask,a);
+ }
+
+ template<int scale = 4>
+ static __forceinline vint16 gather(const int* ptr, const vint16& index) {
+ return _mm512_i32gather_epi32(index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vint16 gather(const vboolf16& mask, const int* ptr, const vint16& index) {
+ return _mm512_mask_i32gather_epi32(_mm512_undefined_epi32(),mask,index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vint16 gather(const vboolf16& mask, vint16& dest, const int* ptr, const vint16& index) {
+ return _mm512_mask_i32gather_epi32(dest,mask,index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(int* ptr, const vint16& index, const vint16& v) {
+ _mm512_i32scatter_epi32((int*)ptr,index,v,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf16& mask, int* ptr, const vint16& index, const vint16& v) {
+ _mm512_mask_i32scatter_epi32((int*)ptr,mask,index,v,scale);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline int& operator [](size_t index) { assert(index < 16); return i[index]; }
+ __forceinline const int& operator [](size_t index) const { assert(index < 16); return i[index]; }
+
+ __forceinline unsigned int uint (size_t index) const { assert(index < 16); return ((unsigned int*)i)[index]; }
+ __forceinline size_t& uint64_t(size_t index) const { assert(index < 8); return ((size_t*)i)[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 asBool(const vint16& a) { return _mm512_movepi32_mask(a); }
+
+ __forceinline vint16 operator +(const vint16& a) { return a; }
+ __forceinline vint16 operator -(const vint16& a) { return _mm512_sub_epi32(_mm512_setzero_epi32(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint16 operator +(const vint16& a, const vint16& b) { return _mm512_add_epi32(a, b); }
+ __forceinline vint16 operator +(const vint16& a, int b) { return a + vint16(b); }
+ __forceinline vint16 operator +(int a, const vint16& b) { return vint16(a) + b; }
+
+ __forceinline vint16 operator -(const vint16& a, const vint16& b) { return _mm512_sub_epi32(a, b); }
+ __forceinline vint16 operator -(const vint16& a, int b) { return a - vint16(b); }
+ __forceinline vint16 operator -(int a, const vint16& b) { return vint16(a) - b; }
+
+ __forceinline vint16 operator *(const vint16& a, const vint16& b) { return _mm512_mullo_epi32(a, b); }
+ __forceinline vint16 operator *(const vint16& a, int b) { return a * vint16(b); }
+ __forceinline vint16 operator *(int a, const vint16& b) { return vint16(a) * b; }
+
+ __forceinline vint16 operator &(const vint16& a, const vint16& b) { return _mm512_and_epi32(a, b); }
+ __forceinline vint16 operator &(const vint16& a, int b) { return a & vint16(b); }
+ __forceinline vint16 operator &(int a, const vint16& b) { return vint16(a) & b; }
+
+ __forceinline vint16 operator |(const vint16& a, const vint16& b) { return _mm512_or_epi32(a, b); }
+ __forceinline vint16 operator |(const vint16& a, int b) { return a | vint16(b); }
+ __forceinline vint16 operator |(int a, const vint16& b) { return vint16(a) | b; }
+
+ __forceinline vint16 operator ^(const vint16& a, const vint16& b) { return _mm512_xor_epi32(a, b); }
+ __forceinline vint16 operator ^(const vint16& a, int b) { return a ^ vint16(b); }
+ __forceinline vint16 operator ^(int a, const vint16& b) { return vint16(a) ^ b; }
+
+ __forceinline vint16 operator <<(const vint16& a, int n) { return _mm512_slli_epi32(a, n); }
+ __forceinline vint16 operator >>(const vint16& a, int n) { return _mm512_srai_epi32(a, n); }
+
+ __forceinline vint16 operator <<(const vint16& a, const vint16& n) { return _mm512_sllv_epi32(a, n); }
+ __forceinline vint16 operator >>(const vint16& a, const vint16& n) { return _mm512_srav_epi32(a, n); }
+
+ __forceinline vint16 sll (const vint16& a, int b) { return _mm512_slli_epi32(a, b); }
+ __forceinline vint16 sra (const vint16& a, int b) { return _mm512_srai_epi32(a, b); }
+ __forceinline vint16 srl (const vint16& a, int b) { return _mm512_srli_epi32(a, b); }
+
+ __forceinline vint16 min(const vint16& a, const vint16& b) { return _mm512_min_epi32(a, b); }
+ __forceinline vint16 min(const vint16& a, int b) { return min(a,vint16(b)); }
+ __forceinline vint16 min(int a, const vint16& b) { return min(vint16(a),b); }
+
+ __forceinline vint16 max(const vint16& a, const vint16& b) { return _mm512_max_epi32(a, b); }
+ __forceinline vint16 max(const vint16& a, int b) { return max(a,vint16(b)); }
+ __forceinline vint16 max(int a, const vint16& b) { return max(vint16(a),b); }
+
+ __forceinline vint16 umin(const vint16& a, const vint16& b) { return _mm512_min_epu32(a, b); }
+ __forceinline vint16 umax(const vint16& a, const vint16& b) { return _mm512_max_epu32(a, b); }
+
+ __forceinline vint16 mask_add(const vboolf16& mask, vint16& c, const vint16& a, const vint16& b) { return _mm512_mask_add_epi32(c,mask,a,b); }
+ __forceinline vint16 mask_sub(const vboolf16& mask, vint16& c, const vint16& a, const vint16& b) { return _mm512_mask_sub_epi32(c,mask,a,b); }
+
+ __forceinline vint16 mask_and(const vboolf16& m, vint16& c, const vint16& a, const vint16& b) { return _mm512_mask_and_epi32(c,m,a,b); }
+ __forceinline vint16 mask_or (const vboolf16& m, vint16& c, const vint16& a, const vint16& b) { return _mm512_mask_or_epi32(c,m,a,b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint16& operator +=(vint16& a, const vint16& b) { return a = a + b; }
+ __forceinline vint16& operator +=(vint16& a, int b) { return a = a + b; }
+
+ __forceinline vint16& operator -=(vint16& a, const vint16& b) { return a = a - b; }
+ __forceinline vint16& operator -=(vint16& a, int b) { return a = a - b; }
+
+ __forceinline vint16& operator *=(vint16& a, const vint16& b) { return a = a * b; }
+ __forceinline vint16& operator *=(vint16& a, int b) { return a = a * b; }
+
+ __forceinline vint16& operator &=(vint16& a, const vint16& b) { return a = a & b; }
+ __forceinline vint16& operator &=(vint16& a, int b) { return a = a & b; }
+
+ __forceinline vint16& operator |=(vint16& a, const vint16& b) { return a = a | b; }
+ __forceinline vint16& operator |=(vint16& a, int b) { return a = a | b; }
+
+ __forceinline vint16& operator <<=(vint16& a, int b) { return a = a << b; }
+ __forceinline vint16& operator >>=(vint16& a, int b) { return a = a >> b; }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator ==(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 operator ==(const vint16& a, int b) { return a == vint16(b); }
+ __forceinline vboolf16 operator ==(int a, const vint16& b) { return vint16(a) == b; }
+
+ __forceinline vboolf16 operator !=(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 operator !=(const vint16& a, int b) { return a != vint16(b); }
+ __forceinline vboolf16 operator !=(int a, const vint16& b) { return vint16(a) != b; }
+
+ __forceinline vboolf16 operator < (const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 operator < (const vint16& a, int b) { return a < vint16(b); }
+ __forceinline vboolf16 operator < (int a, const vint16& b) { return vint16(a) < b; }
+
+ __forceinline vboolf16 operator >=(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 operator >=(const vint16& a, int b) { return a >= vint16(b); }
+ __forceinline vboolf16 operator >=(int a, const vint16& b) { return vint16(a) >= b; }
+
+ __forceinline vboolf16 operator > (const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 operator > (const vint16& a, int b) { return a > vint16(b); }
+ __forceinline vboolf16 operator > (int a, const vint16& b) { return vint16(a) > b; }
+
+ __forceinline vboolf16 operator <=(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 operator <=(const vint16& a, int b) { return a <= vint16(b); }
+ __forceinline vboolf16 operator <=(int a, const vint16& b) { return vint16(a) <= b; }
+
+ __forceinline vboolf16 eq(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vint16& a, const vint16& b) { return _mm512_cmp_epi32_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 uint_le(const vint16& a, const vint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 uint_gt(const vint16& a, const vint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_GT); }
+
+ __forceinline vboolf16 eq(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epi32_mask(mask,a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 uint_le(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 uint_gt(const vboolf16 mask, const vint16& a, const vint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_GT); }
+
+
+ __forceinline vint16 select(const vboolf16& m, const vint16& t, const vint16& f) {
+ return _mm512_mask_or_epi32(f,m,t,t);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint16 unpacklo(const vint16& a, const vint16& b) { return _mm512_unpacklo_epi32(a, b); }
+ __forceinline vint16 unpackhi(const vint16& a, const vint16& b) { return _mm512_unpackhi_epi32(a, b); }
+
+ template<int i>
+ __forceinline vint16 shuffle(const vint16& v) {
+ return _mm512_castps_si512(_mm512_permute_ps(_mm512_castsi512_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint16 shuffle(const vint16& v) {
+ return _mm512_castps_si512(_mm512_permute_ps(_mm512_castsi512_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i>
+ __forceinline vint16 shuffle4(const vint16& v) {
+ return _mm512_castps_si512(_mm512_shuffle_f32x4(_mm512_castsi512_ps(v), _mm512_castsi512_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint16 shuffle4(const vint16& v) {
+ return _mm512_castps_si512(_mm512_shuffle_f32x4(_mm512_castsi512_ps(v), _mm512_castsi512_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i>
+ __forceinline vint16 align_shift_right(const vint16& a, const vint16& b) {
+ return _mm512_alignr_epi32(a, b, i);
+ };
+
+ __forceinline int toScalar(const vint16& v) {
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(v));
+ }
+
+ template<int i> __forceinline vint16 insert4(const vint16& a, const vint4& b) { return _mm512_inserti32x4(a, b, i); }
+
+ template<int N, int i>
+ vint<N> extractN(const vint16& v);
+
+ template<> __forceinline vint4 extractN<4,0>(const vint16& v) { return _mm512_castsi512_si128(v); }
+ template<> __forceinline vint4 extractN<4,1>(const vint16& v) { return _mm512_extracti32x4_epi32(v, 1); }
+ template<> __forceinline vint4 extractN<4,2>(const vint16& v) { return _mm512_extracti32x4_epi32(v, 2); }
+ template<> __forceinline vint4 extractN<4,3>(const vint16& v) { return _mm512_extracti32x4_epi32(v, 3); }
+
+ template<> __forceinline vint8 extractN<8,0>(const vint16& v) { return _mm512_castsi512_si256(v); }
+ template<> __forceinline vint8 extractN<8,1>(const vint16& v) { return _mm512_extracti32x8_epi32(v, 1); }
+
+ template<int i> __forceinline vint4 extract4 (const vint16& v) { return _mm512_extracti32x4_epi32(v, i); }
+ template<> __forceinline vint4 extract4<0>(const vint16& v) { return _mm512_castsi512_si128(v); }
+
+ template<int i> __forceinline vint8 extract8 (const vint16& v) { return _mm512_extracti32x8_epi32(v, i); }
+ template<> __forceinline vint8 extract8<0>(const vint16& v) { return _mm512_castsi512_si256(v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint16 vreduce_min2(vint16 x) { return min(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vint16 vreduce_min4(vint16 x) { x = vreduce_min2(x); return min(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vint16 vreduce_min8(vint16 x) { x = vreduce_min4(x); return min(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vint16 vreduce_min (vint16 x) { x = vreduce_min8(x); return min(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline vint16 vreduce_max2(vint16 x) { return max(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vint16 vreduce_max4(vint16 x) { x = vreduce_max2(x); return max(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vint16 vreduce_max8(vint16 x) { x = vreduce_max4(x); return max(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vint16 vreduce_max (vint16 x) { x = vreduce_max8(x); return max(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline vint16 vreduce_and2(vint16 x) { return x & shuffle<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_and4(vint16 x) { x = vreduce_and2(x); return x & shuffle<2,3,0,1>(x); }
+ __forceinline vint16 vreduce_and8(vint16 x) { x = vreduce_and4(x); return x & shuffle4<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_and (vint16 x) { x = vreduce_and8(x); return x & shuffle4<2,3,0,1>(x); }
+
+ __forceinline vint16 vreduce_or2(vint16 x) { return x | shuffle<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_or4(vint16 x) { x = vreduce_or2(x); return x | shuffle<2,3,0,1>(x); }
+ __forceinline vint16 vreduce_or8(vint16 x) { x = vreduce_or4(x); return x | shuffle4<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_or (vint16 x) { x = vreduce_or8(x); return x | shuffle4<2,3,0,1>(x); }
+
+ __forceinline vint16 vreduce_add2(vint16 x) { return x + shuffle<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_add4(vint16 x) { x = vreduce_add2(x); return x + shuffle<2,3,0,1>(x); }
+ __forceinline vint16 vreduce_add8(vint16 x) { x = vreduce_add4(x); return x + shuffle4<1,0,3,2>(x); }
+ __forceinline vint16 vreduce_add (vint16 x) { x = vreduce_add8(x); return x + shuffle4<2,3,0,1>(x); }
+
+ __forceinline int reduce_min(const vint16& v) { return toScalar(vreduce_min(v)); }
+ __forceinline int reduce_max(const vint16& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_and(const vint16& v) { return toScalar(vreduce_and(v)); }
+ __forceinline int reduce_or (const vint16& v) { return toScalar(vreduce_or (v)); }
+ __forceinline int reduce_add(const vint16& v) { return toScalar(vreduce_add(v)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint16 conflict(const vint16& index)
+ {
+ return _mm512_conflict_epi32(index);
+ }
+
+ __forceinline vint16 conflict(const vboolf16& mask, vint16& dest, const vint16& index)
+ {
+ return _mm512_mask_conflict_epi32(dest,mask,index);
+ }
+
+ __forceinline vint16 convert_uint32_t(const __m512& f) {
+ return _mm512_cvtps_epu32(f);
+ }
+
+ __forceinline vint16 permute(vint16 v, vint16 index) {
+ return _mm512_permutexvar_epi32(index,v);
+ }
+
+ __forceinline vint16 reverse(const vint16 &a) {
+ return permute(a,vint16(reverse_step));
+ }
+
+ __forceinline vint16 prefix_sum(const vint16& a)
+ {
+ const vint16 z(zero);
+ vint16 v = a;
+ v = v + align_shift_right<16-1>(v,z);
+ v = v + align_shift_right<16-2>(v,z);
+ v = v + align_shift_right<16-4>(v,z);
+ v = v + align_shift_right<16-8>(v,z);
+ return v;
+ }
+
+ __forceinline vint16 reverse_prefix_sum(const vint16& a)
+ {
+ const vint16 z(zero);
+ vint16 v = a;
+ v = v + align_shift_right<1>(z,v);
+ v = v + align_shift_right<2>(z,v);
+ v = v + align_shift_right<4>(z,v);
+ v = v + align_shift_right<8>(z,v);
+ return v;
+ }
+
+ /* this should use a vbool8 and a vint8_64...*/
+ template<int scale = 1, int hint = _MM_HINT_T0>
+ __forceinline void gather_prefetch64(const void* base_addr, const vbool16& mask, const vint16& offset)
+ {
+#if defined(__AVX512PF__)
+ _mm512_mask_prefetch_i64gather_pd(offset, mask, base_addr, scale, hint);
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vint16& v)
+ {
+ cout << "<" << v[0];
+ for (int i=1; i<16; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vint4_sse2.h b/thirdparty/embree/common/simd/vint4_sse2.h
new file mode 100644
index 0000000000..9814d5c71c
--- /dev/null
+++ b/thirdparty/embree/common/simd/vint4_sse2.h
@@ -0,0 +1,598 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../math/math.h"
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 4-wide SSE integer type */
+ template<>
+ struct vint<4>
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef vboolf4 Bool;
+ typedef vint4 Int;
+ typedef vfloat4 Float;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { __m128i v; int i[4]; }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint() {}
+ __forceinline vint(const vint4& a) { v = a.v; }
+ __forceinline vint4& operator =(const vint4& a) { v = a.v; return *this; }
+
+ __forceinline vint(__m128i a) : v(a) {}
+ __forceinline operator const __m128i&() const { return v; }
+ __forceinline operator __m128i&() { return v; }
+
+ __forceinline vint(int a) : v(_mm_set1_epi32(a)) {}
+ __forceinline vint(int a, int b, int c, int d) : v(_mm_set_epi32(d, c, b, a)) {}
+
+ __forceinline explicit vint(__m128 a) : v(_mm_cvtps_epi32(a)) {}
+#if defined(__AVX512VL__)
+ __forceinline explicit vint(const vboolf4& a) : v(_mm_movm_epi32(a)) {}
+#else
+ __forceinline explicit vint(const vboolf4& a) : v(_mm_castps_si128((__m128)a)) {}
+#endif
+
+ __forceinline vint(long long a, long long b) : v(_mm_set_epi64x(b,a)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint(ZeroTy) : v(_mm_setzero_si128()) {}
+ __forceinline vint(OneTy) : v(_mm_set_epi32(1, 1, 1, 1)) {}
+ __forceinline vint(PosInfTy) : v(_mm_set_epi32(pos_inf, pos_inf, pos_inf, pos_inf)) {}
+ __forceinline vint(NegInfTy) : v(_mm_set_epi32(neg_inf, neg_inf, neg_inf, neg_inf)) {}
+ __forceinline vint(StepTy) : v(_mm_set_epi32(3, 2, 1, 0)) {}
+ __forceinline vint(ReverseStepTy) : v(_mm_set_epi32(0, 1, 2, 3)) {}
+
+ __forceinline vint(TrueTy) { v = _mm_cmpeq_epi32(v,v); }
+ __forceinline vint(UndefinedTy) : v(_mm_castps_si128(_mm_undefined_ps())) {}
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vint4 load (const void* a) { return _mm_load_si128((__m128i*)a); }
+ static __forceinline vint4 loadu(const void* a) { return _mm_loadu_si128((__m128i*)a); }
+
+ static __forceinline void store (void* ptr, const vint4& v) { _mm_store_si128((__m128i*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vint4& v) { _mm_storeu_si128((__m128i*)ptr,v); }
+
+#if defined(__AVX512VL__)
+
+ static __forceinline vint4 compact(const vboolf4& mask, vint4 &v) {
+ return _mm_mask_compress_epi32(v, mask, v);
+ }
+ static __forceinline vint4 compact(const vboolf4& mask, vint4 &a, const vint4& b) {
+ return _mm_mask_compress_epi32(a, mask, b);
+ }
+
+ static __forceinline vint4 load (const vboolf4& mask, const void* ptr) { return _mm_mask_load_epi32 (_mm_setzero_si128(),mask,ptr); }
+ static __forceinline vint4 loadu(const vboolf4& mask, const void* ptr) { return _mm_mask_loadu_epi32(_mm_setzero_si128(),mask,ptr); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vint4& v) { _mm_mask_store_epi32 (ptr,mask,v); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vint4& v) { _mm_mask_storeu_epi32(ptr,mask,v); }
+#elif defined(__AVX__)
+ static __forceinline vint4 load (const vbool4& mask, const void* a) { return _mm_castps_si128(_mm_maskload_ps((float*)a,mask)); }
+ static __forceinline vint4 loadu(const vbool4& mask, const void* a) { return _mm_castps_si128(_mm_maskload_ps((float*)a,mask)); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vint4& i) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,_mm_castsi128_ps(i)); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vint4& i) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,_mm_castsi128_ps(i)); }
+#else
+ static __forceinline vint4 load (const vbool4& mask, const void* a) { return _mm_and_si128(_mm_load_si128 ((__m128i*)a),mask); }
+ static __forceinline vint4 loadu(const vbool4& mask, const void* a) { return _mm_and_si128(_mm_loadu_si128((__m128i*)a),mask); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vint4& i) { store (ptr,select(mask,i,load (ptr))); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vint4& i) { storeu(ptr,select(mask,i,loadu(ptr))); }
+#endif
+
+
+#if defined(__SSE4_1__)
+ static __forceinline vint4 load(const unsigned char* ptr) {
+ return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
+ }
+
+ static __forceinline vint4 loadu(const unsigned char* ptr) {
+ return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
+ }
+#else
+
+ static __forceinline vint4 load(const unsigned char* ptr) {
+ return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
+ }
+
+ static __forceinline vint4 loadu(const unsigned char* ptr) {
+ return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
+ }
+
+#endif
+
+ static __forceinline vint4 load(const unsigned short* ptr) {
+#if defined (__SSE4_1__)
+ return _mm_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr));
+#else
+ return vint4(ptr[0],ptr[1],ptr[2],ptr[3]);
+#endif
+ }
+
+ static __forceinline void store(unsigned char* ptr, const vint4& v) {
+#if defined(__SSE4_1__)
+ __m128i x = v;
+ x = _mm_packus_epi32(x, x);
+ x = _mm_packus_epi16(x, x);
+ *(int*)ptr = _mm_cvtsi128_si32(x);
+#else
+ for (size_t i=0;i<4;i++)
+ ptr[i] = (unsigned char)v[i];
+#endif
+ }
+
+ static __forceinline void store(unsigned short* ptr, const vint4& v) {
+ for (size_t i=0;i<4;i++)
+ ptr[i] = (unsigned short)v[i];
+ }
+
+ static __forceinline vint4 load_nt(void* ptr) {
+#if defined(__SSE4_1__)
+ return _mm_stream_load_si128((__m128i*)ptr);
+#else
+ return _mm_load_si128((__m128i*)ptr);
+#endif
+ }
+
+ static __forceinline void store_nt(void* ptr, const vint4& v) {
+#if defined(__SSE4_1__)
+ _mm_stream_ps((float*)ptr, _mm_castsi128_ps(v));
+#else
+ _mm_store_si128((__m128i*)ptr,v);
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vint4 gather(const int* ptr, const vint4& index) {
+#if defined(__AVX2__)
+ return _mm_i32gather_epi32(ptr, index, scale);
+#else
+ return vint4(
+ *(int*)(((char*)ptr)+scale*index[0]),
+ *(int*)(((char*)ptr)+scale*index[1]),
+ *(int*)(((char*)ptr)+scale*index[2]),
+ *(int*)(((char*)ptr)+scale*index[3]));
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vint4 gather(const vboolf4& mask, const int* ptr, const vint4& index) {
+ vint4 r = zero;
+#if defined(__AVX512VL__)
+ return _mm_mmask_i32gather_epi32(r, mask, index, ptr, scale);
+#elif defined(__AVX2__)
+ return _mm_mask_i32gather_epi32(r, ptr, index, mask, scale);
+#else
+ if (likely(mask[0])) r[0] = *(int*)(((char*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(int*)(((char*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(int*)(((char*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(int*)(((char*)ptr)+scale*index[3]);
+ return r;
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint4& index, const vint4& v)
+ {
+#if defined(__AVX512VL__)
+ _mm_i32scatter_epi32((int*)ptr, index, v, scale);
+#else
+ *(int*)(((char*)ptr)+scale*index[0]) = v[0];
+ *(int*)(((char*)ptr)+scale*index[1]) = v[1];
+ *(int*)(((char*)ptr)+scale*index[2]) = v[2];
+ *(int*)(((char*)ptr)+scale*index[3]) = v[3];
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf4& mask, void* ptr, const vint4& index, const vint4& v)
+ {
+#if defined(__AVX512VL__)
+ _mm_mask_i32scatter_epi32((int*)ptr, mask, index, v, scale);
+#else
+ if (likely(mask[0])) *(int*)(((char*)ptr)+scale*index[0]) = v[0];
+ if (likely(mask[1])) *(int*)(((char*)ptr)+scale*index[1]) = v[1];
+ if (likely(mask[2])) *(int*)(((char*)ptr)+scale*index[2]) = v[2];
+ if (likely(mask[3])) *(int*)(((char*)ptr)+scale*index[3]) = v[3];
+#endif
+ }
+
+#if defined(__x86_64__)
+ static __forceinline vint4 broadcast64(long long a) { return _mm_set1_epi64x(a); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const int& operator [](size_t index) const { assert(index < 4); return i[index]; }
+ __forceinline int& operator [](size_t index) { assert(index < 4); return i[index]; }
+
+ friend __forceinline vint4 select(const vboolf4& m, const vint4& t, const vint4& f) {
+#if defined(__AVX512VL__)
+ return _mm_mask_blend_epi32(m, (__m128i)f, (__m128i)t);
+#elif defined(__SSE4_1__)
+ return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), m));
+#else
+ return _mm_or_si128(_mm_and_si128(m, t), _mm_andnot_si128(m, f));
+#endif
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 asBool(const vint4& a) { return _mm_movepi32_mask(a); }
+#else
+ __forceinline vboolf4 asBool(const vint4& a) { return _mm_castsi128_ps(a); }
+#endif
+
+ __forceinline vint4 operator +(const vint4& a) { return a; }
+ __forceinline vint4 operator -(const vint4& a) { return _mm_sub_epi32(_mm_setzero_si128(), a); }
+#if defined(__SSSE3__)
+ __forceinline vint4 abs(const vint4& a) { return _mm_abs_epi32(a); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint4 operator +(const vint4& a, const vint4& b) { return _mm_add_epi32(a, b); }
+ __forceinline vint4 operator +(const vint4& a, int b) { return a + vint4(b); }
+ __forceinline vint4 operator +(int a, const vint4& b) { return vint4(a) + b; }
+
+ __forceinline vint4 operator -(const vint4& a, const vint4& b) { return _mm_sub_epi32(a, b); }
+ __forceinline vint4 operator -(const vint4& a, int b) { return a - vint4(b); }
+ __forceinline vint4 operator -(int a, const vint4& b) { return vint4(a) - b; }
+
+#if defined(__SSE4_1__)
+ __forceinline vint4 operator *(const vint4& a, const vint4& b) { return _mm_mullo_epi32(a, b); }
+#else
+ __forceinline vint4 operator *(const vint4& a, const vint4& b) { return vint4(a[0]*b[0],a[1]*b[1],a[2]*b[2],a[3]*b[3]); }
+#endif
+ __forceinline vint4 operator *(const vint4& a, int b) { return a * vint4(b); }
+ __forceinline vint4 operator *(int a, const vint4& b) { return vint4(a) * b; }
+
+ __forceinline vint4 operator &(const vint4& a, const vint4& b) { return _mm_and_si128(a, b); }
+ __forceinline vint4 operator &(const vint4& a, int b) { return a & vint4(b); }
+ __forceinline vint4 operator &(int a, const vint4& b) { return vint4(a) & b; }
+
+ __forceinline vint4 operator |(const vint4& a, const vint4& b) { return _mm_or_si128(a, b); }
+ __forceinline vint4 operator |(const vint4& a, int b) { return a | vint4(b); }
+ __forceinline vint4 operator |(int a, const vint4& b) { return vint4(a) | b; }
+
+ __forceinline vint4 operator ^(const vint4& a, const vint4& b) { return _mm_xor_si128(a, b); }
+ __forceinline vint4 operator ^(const vint4& a, int b) { return a ^ vint4(b); }
+ __forceinline vint4 operator ^(int a, const vint4& b) { return vint4(a) ^ b; }
+
+ __forceinline vint4 operator <<(const vint4& a, int n) { return _mm_slli_epi32(a, n); }
+ __forceinline vint4 operator >>(const vint4& a, int n) { return _mm_srai_epi32(a, n); }
+
+ __forceinline vint4 sll (const vint4& a, int b) { return _mm_slli_epi32(a, b); }
+ __forceinline vint4 sra (const vint4& a, int b) { return _mm_srai_epi32(a, b); }
+ __forceinline vint4 srl (const vint4& a, int b) { return _mm_srli_epi32(a, b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint4& operator +=(vint4& a, const vint4& b) { return a = a + b; }
+ __forceinline vint4& operator +=(vint4& a, int b) { return a = a + b; }
+
+ __forceinline vint4& operator -=(vint4& a, const vint4& b) { return a = a - b; }
+ __forceinline vint4& operator -=(vint4& a, int b) { return a = a - b; }
+
+#if defined(__SSE4_1__)
+ __forceinline vint4& operator *=(vint4& a, const vint4& b) { return a = a * b; }
+ __forceinline vint4& operator *=(vint4& a, int b) { return a = a * b; }
+#endif
+
+ __forceinline vint4& operator &=(vint4& a, const vint4& b) { return a = a & b; }
+ __forceinline vint4& operator &=(vint4& a, int b) { return a = a & b; }
+
+ __forceinline vint4& operator |=(vint4& a, const vint4& b) { return a = a | b; }
+ __forceinline vint4& operator |=(vint4& a, int b) { return a = a | b; }
+
+ __forceinline vint4& operator <<=(vint4& a, int b) { return a = a << b; }
+ __forceinline vint4& operator >>=(vint4& a, int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 operator ==(const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf4 operator !=(const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf4 operator < (const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf4 operator >=(const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf4 operator > (const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf4 operator <=(const vint4& a, const vint4& b) { return _mm_cmp_epi32_mask(a,b,_MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 operator ==(const vint4& a, const vint4& b) { return _mm_castsi128_ps(_mm_cmpeq_epi32(a, b)); }
+ __forceinline vboolf4 operator !=(const vint4& a, const vint4& b) { return !(a == b); }
+ __forceinline vboolf4 operator < (const vint4& a, const vint4& b) { return _mm_castsi128_ps(_mm_cmplt_epi32(a, b)); }
+ __forceinline vboolf4 operator >=(const vint4& a, const vint4& b) { return !(a < b); }
+ __forceinline vboolf4 operator > (const vint4& a, const vint4& b) { return _mm_castsi128_ps(_mm_cmpgt_epi32(a, b)); }
+ __forceinline vboolf4 operator <=(const vint4& a, const vint4& b) { return !(a > b); }
+#endif
+
+ __forceinline vboolf4 operator ==(const vint4& a, int b) { return a == vint4(b); }
+ __forceinline vboolf4 operator ==(int a, const vint4& b) { return vint4(a) == b; }
+
+ __forceinline vboolf4 operator !=(const vint4& a, int b) { return a != vint4(b); }
+ __forceinline vboolf4 operator !=(int a, const vint4& b) { return vint4(a) != b; }
+
+ __forceinline vboolf4 operator < (const vint4& a, int b) { return a < vint4(b); }
+ __forceinline vboolf4 operator < (int a, const vint4& b) { return vint4(a) < b; }
+
+ __forceinline vboolf4 operator >=(const vint4& a, int b) { return a >= vint4(b); }
+ __forceinline vboolf4 operator >=(int a, const vint4& b) { return vint4(a) >= b; }
+
+ __forceinline vboolf4 operator > (const vint4& a, int b) { return a > vint4(b); }
+ __forceinline vboolf4 operator > (int a, const vint4& b) { return vint4(a) > b; }
+
+ __forceinline vboolf4 operator <=(const vint4& a, int b) { return a <= vint4(b); }
+ __forceinline vboolf4 operator <=(int a, const vint4& b) { return vint4(a) <= b; }
+
+ __forceinline vboolf4 eq(const vint4& a, const vint4& b) { return a == b; }
+ __forceinline vboolf4 ne(const vint4& a, const vint4& b) { return a != b; }
+ __forceinline vboolf4 lt(const vint4& a, const vint4& b) { return a < b; }
+ __forceinline vboolf4 ge(const vint4& a, const vint4& b) { return a >= b; }
+ __forceinline vboolf4 gt(const vint4& a, const vint4& b) { return a > b; }
+ __forceinline vboolf4 le(const vint4& a, const vint4& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 eq(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_NE); }
+ __forceinline vboolf4 lt(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LT); }
+ __forceinline vboolf4 ge(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_GE); }
+ __forceinline vboolf4 gt(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_GT); }
+ __forceinline vboolf4 le(const vboolf4& mask, const vint4& a, const vint4& b) { return _mm_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 eq(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a == b); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a != b); }
+ __forceinline vboolf4 lt(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a < b); }
+ __forceinline vboolf4 ge(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a >= b); }
+ __forceinline vboolf4 gt(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a > b); }
+ __forceinline vboolf4 le(const vboolf4& mask, const vint4& a, const vint4& b) { return mask & (a <= b); }
+#endif
+
+ template<int mask>
+ __forceinline vint4 select(const vint4& t, const vint4& f) {
+#if defined(__SSE4_1__)
+ return _mm_castps_si128(_mm_blend_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), mask));
+#else
+ return select(vboolf4(mask), t, f);
+#endif
+ }
+
+#if defined(__SSE4_1__)
+ __forceinline vint4 min(const vint4& a, const vint4& b) { return _mm_min_epi32(a, b); }
+ __forceinline vint4 max(const vint4& a, const vint4& b) { return _mm_max_epi32(a, b); }
+
+ __forceinline vint4 umin(const vint4& a, const vint4& b) { return _mm_min_epu32(a, b); }
+ __forceinline vint4 umax(const vint4& a, const vint4& b) { return _mm_max_epu32(a, b); }
+
+#else
+ __forceinline vint4 min(const vint4& a, const vint4& b) { return select(a < b,a,b); }
+ __forceinline vint4 max(const vint4& a, const vint4& b) { return select(a < b,b,a); }
+#endif
+
+ __forceinline vint4 min(const vint4& a, int b) { return min(a,vint4(b)); }
+ __forceinline vint4 min(int a, const vint4& b) { return min(vint4(a),b); }
+ __forceinline vint4 max(const vint4& a, int b) { return max(a,vint4(b)); }
+ __forceinline vint4 max(int a, const vint4& b) { return max(vint4(a),b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint4 unpacklo(const vint4& a, const vint4& b) { return _mm_castps_si128(_mm_unpacklo_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
+ __forceinline vint4 unpackhi(const vint4& a, const vint4& b) { return _mm_castps_si128(_mm_unpackhi_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint4 shuffle(const vint4& v) {
+ return _mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint4 shuffle(const vint4& a, const vint4& b) {
+ return _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+#if defined(__SSE3__)
+ template<> __forceinline vint4 shuffle<0, 0, 2, 2>(const vint4& v) { return _mm_castps_si128(_mm_moveldup_ps(_mm_castsi128_ps(v))); }
+ template<> __forceinline vint4 shuffle<1, 1, 3, 3>(const vint4& v) { return _mm_castps_si128(_mm_movehdup_ps(_mm_castsi128_ps(v))); }
+ template<> __forceinline vint4 shuffle<0, 1, 0, 1>(const vint4& v) { return _mm_castpd_si128(_mm_movedup_pd (_mm_castsi128_pd(v))); }
+#endif
+
+ template<int i>
+ __forceinline vint4 shuffle(const vint4& v) {
+ return shuffle<i,i,i,i>(v);
+ }
+
+#if defined(__SSE4_1__)
+ template<int src> __forceinline int extract(const vint4& b) { return _mm_extract_epi32(b, src); }
+ template<int dst> __forceinline vint4 insert(const vint4& a, const int b) { return _mm_insert_epi32(a, b, dst); }
+#else
+ template<int src> __forceinline int extract(const vint4& b) { return b[src&3]; }
+ template<int dst> __forceinline vint4 insert(const vint4& a, int b) { vint4 c = a; c[dst&3] = b; return c; }
+#endif
+
+
+ template<> __forceinline int extract<0>(const vint4& b) { return _mm_cvtsi128_si32(b); }
+
+ __forceinline int toScalar(const vint4& v) { return _mm_cvtsi128_si32(v); }
+
+ __forceinline size_t toSizeT(const vint4& v) {
+#if defined(__WIN32__) && !defined(__X86_64__) // win32 workaround
+ return toScalar(v);
+#else
+ return _mm_cvtsi128_si64(v);
+#endif
+ }
+
+#if defined(__AVX512VL__)
+
+ __forceinline vint4 permute(const vint4 &a, const vint4 &index) {
+ return _mm_castps_si128(_mm_permutevar_ps(_mm_castsi128_ps(a),index));
+ }
+
+ template<int i>
+ __forceinline vint4 align_shift_right(const vint4& a, const vint4& b) {
+ return _mm_alignr_epi32(a, b, i);
+ }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SSE4_1__)
+ __forceinline vint4 vreduce_min(const vint4& v) { vint4 h = min(shuffle<1,0,3,2>(v),v); return min(shuffle<2,3,0,1>(h),h); }
+ __forceinline vint4 vreduce_max(const vint4& v) { vint4 h = max(shuffle<1,0,3,2>(v),v); return max(shuffle<2,3,0,1>(h),h); }
+ __forceinline vint4 vreduce_add(const vint4& v) { vint4 h = shuffle<1,0,3,2>(v) + v ; return shuffle<2,3,0,1>(h) + h ; }
+
+ __forceinline int reduce_min(const vint4& v) { return toScalar(vreduce_min(v)); }
+ __forceinline int reduce_max(const vint4& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_add(const vint4& v) { return toScalar(vreduce_add(v)); }
+
+ __forceinline size_t select_min(const vint4& v) { return bsf(movemask(v == vreduce_min(v))); }
+ __forceinline size_t select_max(const vint4& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ __forceinline size_t select_min(const vboolf4& valid, const vint4& v) { const vint4 a = select(valid,v,vint4(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ __forceinline size_t select_max(const vboolf4& valid, const vint4& v) { const vint4 a = select(valid,v,vint4(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+#else
+
+ __forceinline int reduce_min(const vint4& v) { return min(v[0],v[1],v[2],v[3]); }
+ __forceinline int reduce_max(const vint4& v) { return max(v[0],v[1],v[2],v[3]); }
+ __forceinline int reduce_add(const vint4& v) { return v[0]+v[1]+v[2]+v[3]; }
+
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Sorting networks
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SSE4_1__)
+
+ __forceinline vint4 usort_ascending(const vint4& v)
+ {
+ const vint4 a0 = v;
+ const vint4 b0 = shuffle<1,0,3,2>(a0);
+ const vint4 c0 = umin(a0,b0);
+ const vint4 d0 = umax(a0,b0);
+ const vint4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vint4 b1 = shuffle<2,3,0,1>(a1);
+ const vint4 c1 = umin(a1,b1);
+ const vint4 d1 = umax(a1,b1);
+ const vint4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vint4 b2 = shuffle<0,2,1,3>(a2);
+ const vint4 c2 = umin(a2,b2);
+ const vint4 d2 = umax(a2,b2);
+ const vint4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3;
+ }
+
+ __forceinline vint4 usort_descending(const vint4& v)
+ {
+ const vint4 a0 = v;
+ const vint4 b0 = shuffle<1,0,3,2>(a0);
+ const vint4 c0 = umax(a0,b0);
+ const vint4 d0 = umin(a0,b0);
+ const vint4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vint4 b1 = shuffle<2,3,0,1>(a1);
+ const vint4 c1 = umax(a1,b1);
+ const vint4 d1 = umin(a1,b1);
+ const vint4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vint4 b2 = shuffle<0,2,1,3>(a2);
+ const vint4 c2 = umax(a2,b2);
+ const vint4 d2 = umin(a2,b2);
+ const vint4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3;
+ }
+
+#else
+
+ __forceinline vint4 usort_ascending(const vint4& v)
+ {
+ const vint4 a0 = v-vint4(0x80000000);
+ const vint4 b0 = shuffle<1,0,3,2>(a0);
+ const vint4 c0 = min(a0,b0);
+ const vint4 d0 = max(a0,b0);
+ const vint4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vint4 b1 = shuffle<2,3,0,1>(a1);
+ const vint4 c1 = min(a1,b1);
+ const vint4 d1 = max(a1,b1);
+ const vint4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vint4 b2 = shuffle<0,2,1,3>(a2);
+ const vint4 c2 = min(a2,b2);
+ const vint4 d2 = max(a2,b2);
+ const vint4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3+vint4(0x80000000);
+ }
+
+ __forceinline vint4 usort_descending(const vint4& v)
+ {
+ const vint4 a0 = v-vint4(0x80000000);
+ const vint4 b0 = shuffle<1,0,3,2>(a0);
+ const vint4 c0 = max(a0,b0);
+ const vint4 d0 = min(a0,b0);
+ const vint4 a1 = select<0x5 /* 0b0101 */>(c0,d0);
+ const vint4 b1 = shuffle<2,3,0,1>(a1);
+ const vint4 c1 = max(a1,b1);
+ const vint4 d1 = min(a1,b1);
+ const vint4 a2 = select<0x3 /* 0b0011 */>(c1,d1);
+ const vint4 b2 = shuffle<0,2,1,3>(a2);
+ const vint4 c2 = max(a2,b2);
+ const vint4 d2 = min(a2,b2);
+ const vint4 a3 = select<0x2 /* 0b0010 */>(c2,d2);
+ return a3+vint4(0x80000000);
+ }
+
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vint4& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vint8_avx.h b/thirdparty/embree/common/simd/vint8_avx.h
new file mode 100644
index 0000000000..f43e9a8c22
--- /dev/null
+++ b/thirdparty/embree/common/simd/vint8_avx.h
@@ -0,0 +1,470 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 8-wide AVX integer type */
+ template<>
+ struct vint<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m256i v;
+ struct { __m128i vl,vh; };
+ int i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint() {}
+ __forceinline vint(const vint8& a) { v = a.v; }
+ __forceinline vint8& operator =(const vint8& a) { v = a.v; return *this; }
+
+ __forceinline vint(__m256i a) : v(a) {}
+ __forceinline operator const __m256i&() const { return v; }
+ __forceinline operator __m256i&() { return v; }
+
+ __forceinline explicit vint(const vint4& a) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),a,1)) {}
+ __forceinline vint(const vint4& a, const vint4& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+ __forceinline vint(const __m128i& a, const __m128i& b) : vl(a), vh(b) {}
+
+ __forceinline explicit vint(const int* a) : v(_mm256_castps_si256(_mm256_loadu_ps((const float*)a))) {}
+ __forceinline vint(int a) : v(_mm256_set1_epi32(a)) {}
+ __forceinline vint(int a, int b) : v(_mm256_set_epi32(b, a, b, a, b, a, b, a)) {}
+ __forceinline vint(int a, int b, int c, int d) : v(_mm256_set_epi32(d, c, b, a, d, c, b, a)) {}
+ __forceinline vint(int a, int b, int c, int d, int e, int f, int g, int vh) : v(_mm256_set_epi32(vh, g, f, e, d, c, b, a)) {}
+
+ __forceinline explicit vint(__m256 a) : v(_mm256_cvtps_epi32(a)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint(ZeroTy) : v(_mm256_setzero_si256()) {}
+ __forceinline vint(OneTy) : v(_mm256_set_epi32(1,1,1,1,1,1,1,1)) {}
+ __forceinline vint(PosInfTy) : v(_mm256_set_epi32(pos_inf,pos_inf,pos_inf,pos_inf,pos_inf,pos_inf,pos_inf,pos_inf)) {}
+ __forceinline vint(NegInfTy) : v(_mm256_set_epi32(neg_inf,neg_inf,neg_inf,neg_inf,neg_inf,neg_inf,neg_inf,neg_inf)) {}
+ __forceinline vint(StepTy) : v(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0)) {}
+ __forceinline vint(ReverseStepTy) : v(_mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7)) {}
+ __forceinline vint(UndefinedTy) : v(_mm256_undefined_si256()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vint8 load (const void* a) { return _mm256_castps_si256(_mm256_load_ps((float*)a)); }
+ static __forceinline vint8 loadu(const void* a) { return _mm256_castps_si256(_mm256_loadu_ps((float*)a)); }
+
+ static __forceinline vint8 load (const vboolf8& mask, const void* a) { return _mm256_castps_si256(_mm256_maskload_ps((float*)a,mask)); }
+ static __forceinline vint8 loadu(const vboolf8& mask, const void* a) { return _mm256_castps_si256(_mm256_maskload_ps((float*)a,mask)); }
+
+ static __forceinline void store (void* ptr, const vint8& f) { _mm256_store_ps((float*)ptr,_mm256_castsi256_ps(f)); }
+ static __forceinline void storeu(void* ptr, const vint8& f) { _mm256_storeu_ps((float*)ptr,_mm256_castsi256_ps(f)); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
+
+ static __forceinline void store_nt(void* ptr, const vint8& v) {
+ _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
+ }
+
+ static __forceinline vint8 load(const unsigned char* ptr) {
+ vint4 il = vint4::load(ptr+0);
+ vint4 ih = vint4::load(ptr+4);
+ return vint8(il,ih);
+ }
+
+ static __forceinline vint8 loadu(const unsigned char* ptr) {
+ vint4 il = vint4::loadu(ptr+0);
+ vint4 ih = vint4::loadu(ptr+4);
+ return vint8(il,ih);
+ }
+
+ static __forceinline vint8 load(const unsigned short* ptr) {
+ vint4 il = vint4::load(ptr+0);
+ vint4 ih = vint4::load(ptr+4);
+ return vint8(il,ih);
+ }
+
+ static __forceinline vint8 loadu(const unsigned short* ptr) {
+ vint4 il = vint4::loadu(ptr+0);
+ vint4 ih = vint4::loadu(ptr+4);
+ return vint8(il,ih);
+ }
+
+ static __forceinline void store(unsigned char* ptr, const vint8& i) {
+ vint4 il(i.vl);
+ vint4 ih(i.vh);
+ vint4::store(ptr + 0,il);
+ vint4::store(ptr + 4,ih);
+ }
+
+ static __forceinline void store(unsigned short* ptr, const vint8& v) {
+ for (size_t i=0;i<8;i++)
+ ptr[i] = (unsigned short)v[i];
+ }
+
+ template<int scale = 4>
+ static __forceinline vint8 gather(const int* ptr, const vint8& index) {
+ return vint8(
+ *(int*)(((char*)ptr)+scale*index[0]),
+ *(int*)(((char*)ptr)+scale*index[1]),
+ *(int*)(((char*)ptr)+scale*index[2]),
+ *(int*)(((char*)ptr)+scale*index[3]),
+ *(int*)(((char*)ptr)+scale*index[4]),
+ *(int*)(((char*)ptr)+scale*index[5]),
+ *(int*)(((char*)ptr)+scale*index[6]),
+ *(int*)(((char*)ptr)+scale*index[7]));
+ }
+
+ template<int scale = 4>
+ static __forceinline vint8 gather(const vboolf8& mask, const int* ptr, const vint8& index) {
+ vint8 r = zero;
+ if (likely(mask[0])) r[0] = *(int*)(((char*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(int*)(((char*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(int*)(((char*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(int*)(((char*)ptr)+scale*index[3]);
+ if (likely(mask[4])) r[4] = *(int*)(((char*)ptr)+scale*index[4]);
+ if (likely(mask[5])) r[5] = *(int*)(((char*)ptr)+scale*index[5]);
+ if (likely(mask[6])) r[6] = *(int*)(((char*)ptr)+scale*index[6]);
+ if (likely(mask[7])) r[7] = *(int*)(((char*)ptr)+scale*index[7]);
+ return r;
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint8& ofs, const vint8& v)
+ {
+ *(int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+ *(int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+ *(int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+ *(int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+ *(int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+ *(int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+ *(int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+ *(int*)(((char*)ptr)+scale*ofs[7]) = v[7];
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vint8& v)
+ {
+ if (likely(mask[0])) *(int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+ if (likely(mask[1])) *(int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+ if (likely(mask[2])) *(int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+ if (likely(mask[3])) *(int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+ if (likely(mask[4])) *(int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+ if (likely(mask[5])) *(int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+ if (likely(mask[6])) *(int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+ if (likely(mask[7])) *(int*)(((char*)ptr)+scale*ofs[7]) = v[7];
+ }
+
+
+ static __forceinline vint8 broadcast64(const long long& a) { return _mm256_set1_epi64x(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const int& operator [](size_t index) const { assert(index < 8); return i[index]; }
+ __forceinline int& operator [](size_t index) { assert(index < 8); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 asBool(const vint8& a) { return _mm256_castsi256_ps(a); }
+
+ __forceinline vint8 operator +(const vint8& a) { return a; }
+ __forceinline vint8 operator -(const vint8& a) { return vint8(_mm_sub_epi32(_mm_setzero_si128(), a.vl), _mm_sub_epi32(_mm_setzero_si128(), a.vh)); }
+ __forceinline vint8 abs (const vint8& a) { return vint8(_mm_abs_epi32(a.vl), _mm_abs_epi32(a.vh)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 operator +(const vint8& a, const vint8& b) { return vint8(_mm_add_epi32(a.vl, b.vl), _mm_add_epi32(a.vh, b.vh)); }
+ __forceinline vint8 operator +(const vint8& a, int b) { return a + vint8(b); }
+ __forceinline vint8 operator +(int a, const vint8& b) { return vint8(a) + b; }
+
+ __forceinline vint8 operator -(const vint8& a, const vint8& b) { return vint8(_mm_sub_epi32(a.vl, b.vl), _mm_sub_epi32(a.vh, b.vh)); }
+ __forceinline vint8 operator -(const vint8& a, int b) { return a - vint8(b); }
+ __forceinline vint8 operator -(int a, const vint8& b) { return vint8(a) - b; }
+
+ __forceinline vint8 operator *(const vint8& a, const vint8& b) { return vint8(_mm_mullo_epi32(a.vl, b.vl), _mm_mullo_epi32(a.vh, b.vh)); }
+ __forceinline vint8 operator *(const vint8& a, int b) { return a * vint8(b); }
+ __forceinline vint8 operator *(int a, const vint8& b) { return vint8(a) * b; }
+
+ __forceinline vint8 operator &(const vint8& a, const vint8& b) { return _mm256_castps_si256(_mm256_and_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vint8 operator &(const vint8& a, int b) { return a & vint8(b); }
+ __forceinline vint8 operator &(int a, const vint8& b) { return vint8(a) & b; }
+
+ __forceinline vint8 operator |(const vint8& a, const vint8& b) { return _mm256_castps_si256(_mm256_or_ps (_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vint8 operator |(const vint8& a, int b) { return a | vint8(b); }
+ __forceinline vint8 operator |(int a, const vint8& b) { return vint8(a) | b; }
+
+ __forceinline vint8 operator ^(const vint8& a, const vint8& b) { return _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vint8 operator ^(const vint8& a, int b) { return a ^ vint8(b); }
+ __forceinline vint8 operator ^(int a, const vint8& b) { return vint8(a) ^ b; }
+
+ __forceinline vint8 operator <<(const vint8& a, int n) { return vint8(_mm_slli_epi32(a.vl, n), _mm_slli_epi32(a.vh, n)); }
+ __forceinline vint8 operator >>(const vint8& a, int n) { return vint8(_mm_srai_epi32(a.vl, n), _mm_srai_epi32(a.vh, n)); }
+
+ __forceinline vint8 sll (const vint8& a, int b) { return vint8(_mm_slli_epi32(a.vl, b), _mm_slli_epi32(a.vh, b)); }
+ __forceinline vint8 sra (const vint8& a, int b) { return vint8(_mm_srai_epi32(a.vl, b), _mm_srai_epi32(a.vh, b)); }
+ __forceinline vint8 srl (const vint8& a, int b) { return vint8(_mm_srli_epi32(a.vl, b), _mm_srli_epi32(a.vh, b)); }
+
+ __forceinline vint8 min(const vint8& a, const vint8& b) { return vint8(_mm_min_epi32(a.vl, b.vl), _mm_min_epi32(a.vh, b.vh)); }
+ __forceinline vint8 min(const vint8& a, int b) { return min(a,vint8(b)); }
+ __forceinline vint8 min(int a, const vint8& b) { return min(vint8(a),b); }
+
+ __forceinline vint8 max(const vint8& a, const vint8& b) { return vint8(_mm_max_epi32(a.vl, b.vl), _mm_max_epi32(a.vh, b.vh)); }
+ __forceinline vint8 max(const vint8& a, int b) { return max(a,vint8(b)); }
+ __forceinline vint8 max(int a, const vint8& b) { return max(vint8(a),b); }
+
+ __forceinline vint8 umin(const vint8& a, const vint8& b) { return vint8(_mm_min_epu32(a.vl, b.vl), _mm_min_epu32(a.vh, b.vh)); }
+ __forceinline vint8 umin(const vint8& a, int b) { return umin(a,vint8(b)); }
+ __forceinline vint8 umin(int a, const vint8& b) { return umin(vint8(a),b); }
+
+ __forceinline vint8 umax(const vint8& a, const vint8& b) { return vint8(_mm_max_epu32(a.vl, b.vl), _mm_max_epu32(a.vh, b.vh)); }
+ __forceinline vint8 umax(const vint8& a, int b) { return umax(a,vint8(b)); }
+ __forceinline vint8 umax(int a, const vint8& b) { return umax(vint8(a),b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8& operator +=(vint8& a, const vint8& b) { return a = a + b; }
+ __forceinline vint8& operator +=(vint8& a, int b) { return a = a + b; }
+
+ __forceinline vint8& operator -=(vint8& a, const vint8& b) { return a = a - b; }
+ __forceinline vint8& operator -=(vint8& a, int b) { return a = a - b; }
+
+ __forceinline vint8& operator *=(vint8& a, const vint8& b) { return a = a * b; }
+ __forceinline vint8& operator *=(vint8& a, int b) { return a = a * b; }
+
+ __forceinline vint8& operator &=(vint8& a, const vint8& b) { return a = a & b; }
+ __forceinline vint8& operator &=(vint8& a, int b) { return a = a & b; }
+
+ __forceinline vint8& operator |=(vint8& a, const vint8& b) { return a = a | b; }
+ __forceinline vint8& operator |=(vint8& a, int b) { return a = a | b; }
+
+ __forceinline vint8& operator <<=(vint8& a, int b) { return a = a << b; }
+ __forceinline vint8& operator >>=(vint8& a, int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator ==(const vint8& a, const vint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmpeq_epi32 (a.vl, b.vl)),
+ _mm_castsi128_ps(_mm_cmpeq_epi32 (a.vh, b.vh))); }
+ __forceinline vboolf8 operator ==(const vint8& a, int b) { return a == vint8(b); }
+ __forceinline vboolf8 operator ==(int a, const vint8& b) { return vint8(a) == b; }
+
+ __forceinline vboolf8 operator !=(const vint8& a, const vint8& b) { return !(a == b); }
+ __forceinline vboolf8 operator !=(const vint8& a, int b) { return a != vint8(b); }
+ __forceinline vboolf8 operator !=(int a, const vint8& b) { return vint8(a) != b; }
+
+ __forceinline vboolf8 operator < (const vint8& a, const vint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmplt_epi32 (a.vl, b.vl)),
+ _mm_castsi128_ps(_mm_cmplt_epi32 (a.vh, b.vh))); }
+ __forceinline vboolf8 operator < (const vint8& a, int b) { return a < vint8(b); }
+ __forceinline vboolf8 operator < (int a, const vint8& b) { return vint8(a) < b; }
+
+ __forceinline vboolf8 operator >=(const vint8& a, const vint8& b) { return !(a < b); }
+ __forceinline vboolf8 operator >=(const vint8& a, int b) { return a >= vint8(b); }
+ __forceinline vboolf8 operator >=(int a, const vint8& b) { return vint8(a) >= b; }
+
+ __forceinline vboolf8 operator > (const vint8& a, const vint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmpgt_epi32 (a.vl, b.vl)),
+ _mm_castsi128_ps(_mm_cmpgt_epi32 (a.vh, b.vh))); }
+ __forceinline vboolf8 operator > (const vint8& a, int b) { return a > vint8(b); }
+ __forceinline vboolf8 operator > (int a, const vint8& b) { return vint8(a) > b; }
+
+ __forceinline vboolf8 operator <=(const vint8& a, const vint8& b) { return !(a > b); }
+ __forceinline vboolf8 operator <=(const vint8& a, int b) { return a <= vint8(b); }
+ __forceinline vboolf8 operator <=(int a, const vint8& b) { return vint8(a) <= b; }
+
+ __forceinline vboolf8 eq(const vint8& a, const vint8& b) { return a == b; }
+ __forceinline vboolf8 ne(const vint8& a, const vint8& b) { return a != b; }
+ __forceinline vboolf8 lt(const vint8& a, const vint8& b) { return a < b; }
+ __forceinline vboolf8 ge(const vint8& a, const vint8& b) { return a >= b; }
+ __forceinline vboolf8 gt(const vint8& a, const vint8& b) { return a > b; }
+ __forceinline vboolf8 le(const vint8& a, const vint8& b) { return a <= b; }
+
+ __forceinline vboolf8 eq(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a == b); }
+ __forceinline vboolf8 ne(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a != b); }
+ __forceinline vboolf8 lt(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a < b); }
+ __forceinline vboolf8 ge(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a >= b); }
+ __forceinline vboolf8 gt(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a > b); }
+ __forceinline vboolf8 le(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a <= b); }
+
+ __forceinline vint8 select(const vboolf8& m, const vint8& t, const vint8& f) {
+ return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(f), _mm256_castsi256_ps(t), m));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 unpacklo(const vint8& a, const vint8& b) { return _mm256_castps_si256(_mm256_unpacklo_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vint8 unpackhi(const vint8& a, const vint8& b) { return _mm256_castps_si256(_mm256_unpackhi_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+
+ template<int i>
+ __forceinline vint8 shuffle(const vint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1>
+ __forceinline vint8 shuffle4(const vint8& v) {
+ return _mm256_permute2f128_si256(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vint8 shuffle4(const vint8& a, const vint8& b) {
+ return _mm256_permute2f128_si256(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint8 shuffle(const vint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint8 shuffle(const vint8& a, const vint8& b) {
+ return _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<> __forceinline vint8 shuffle<0, 0, 2, 2>(const vint8& v) { return _mm256_castps_si256(_mm256_moveldup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vint8 shuffle<1, 1, 3, 3>(const vint8& v) { return _mm256_castps_si256(_mm256_movehdup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vint8 shuffle<0, 1, 0, 1>(const vint8& v) { return _mm256_castps_si256(_mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(_mm256_castsi256_ps(v))))); }
+
+ __forceinline vint8 broadcast(const int* ptr) { return _mm256_castps_si256(_mm256_broadcast_ss((const float*)ptr)); }
+ template<int i> __forceinline vint8 insert4(const vint8& a, const vint4& b) { return _mm256_insertf128_si256(a, b, i); }
+ template<int i> __forceinline vint4 extract4(const vint8& a) { return _mm256_extractf128_si256(a, i); }
+ template<> __forceinline vint4 extract4<0>(const vint8& a) { return _mm256_castsi256_si128(a); }
+
+ __forceinline int toScalar(const vint8& v) { return _mm_cvtsi128_si32(_mm256_castsi256_si128(v)); }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 vreduce_min2(const vint8& v) { return min(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vint8 vreduce_min4(const vint8& v) { vint8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vint8 vreduce_min (const vint8& v) { vint8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vint8 vreduce_max2(const vint8& v) { return max(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vint8 vreduce_max4(const vint8& v) { vint8 v1 = vreduce_max2(v); return max(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vint8 vreduce_max (const vint8& v) { vint8 v1 = vreduce_max4(v); return max(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vint8 vreduce_add2(const vint8& v) { return v + shuffle<1,0,3,2>(v); }
+ __forceinline vint8 vreduce_add4(const vint8& v) { vint8 v1 = vreduce_add2(v); return v1 + shuffle<2,3,0,1>(v1); }
+ __forceinline vint8 vreduce_add (const vint8& v) { vint8 v1 = vreduce_add4(v); return v1 + shuffle4<1,0>(v1); }
+
+ __forceinline int reduce_min(const vint8& v) { return toScalar(vreduce_min(v)); }
+ __forceinline int reduce_max(const vint8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_add(const vint8& v) { return toScalar(vreduce_add(v)); }
+
+ __forceinline size_t select_min(const vint8& v) { return bsf(movemask(v == vreduce_min(v))); }
+ __forceinline size_t select_max(const vint8& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ __forceinline size_t select_min(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ __forceinline size_t select_max(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Sorting networks
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 usort_ascending(const vint8& v)
+ {
+ const vint8 a0 = v;
+ const vint8 b0 = shuffle<1,0,3,2>(a0);
+ const vint8 c0 = umin(a0,b0);
+ const vint8 d0 = umax(a0,b0);
+ const vint8 a1 = select(0x99 /* 0b10011001 */,c0,d0);
+ const vint8 b1 = shuffle<2,3,0,1>(a1);
+ const vint8 c1 = umin(a1,b1);
+ const vint8 d1 = umax(a1,b1);
+ const vint8 a2 = select(0xc3 /* 0b11000011 */,c1,d1);
+ const vint8 b2 = shuffle<1,0,3,2>(a2);
+ const vint8 c2 = umin(a2,b2);
+ const vint8 d2 = umax(a2,b2);
+ const vint8 a3 = select(0xa5 /* 0b10100101 */,c2,d2);
+ const vint8 b3 = shuffle4<1,0>(a3);
+ const vint8 c3 = umin(a3,b3);
+ const vint8 d3 = umax(a3,b3);
+ const vint8 a4 = select(0xf /* 0b00001111 */,c3,d3);
+ const vint8 b4 = shuffle<2,3,0,1>(a4);
+ const vint8 c4 = umin(a4,b4);
+ const vint8 d4 = umax(a4,b4);
+ const vint8 a5 = select(0x33 /* 0b00110011 */,c4,d4);
+ const vint8 b5 = shuffle<1,0,3,2>(a5);
+ const vint8 c5 = umin(a5,b5);
+ const vint8 d5 = umax(a5,b5);
+ const vint8 a6 = select(0x55 /* 0b01010101 */,c5,d5);
+ return a6;
+ }
+
+ __forceinline vint8 usort_descending(const vint8& v)
+ {
+ const vint8 a0 = v;
+ const vint8 b0 = shuffle<1,0,3,2>(a0);
+ const vint8 c0 = umax(a0,b0);
+ const vint8 d0 = umin(a0,b0);
+ const vint8 a1 = select(0x99 /* 0b10011001 */,c0,d0);
+ const vint8 b1 = shuffle<2,3,0,1>(a1);
+ const vint8 c1 = umax(a1,b1);
+ const vint8 d1 = umin(a1,b1);
+ const vint8 a2 = select(0xc3 /* 0b11000011 */,c1,d1);
+ const vint8 b2 = shuffle<1,0,3,2>(a2);
+ const vint8 c2 = umax(a2,b2);
+ const vint8 d2 = umin(a2,b2);
+ const vint8 a3 = select(0xa5 /* 0b10100101 */,c2,d2);
+ const vint8 b3 = shuffle4<1,0>(a3);
+ const vint8 c3 = umax(a3,b3);
+ const vint8 d3 = umin(a3,b3);
+ const vint8 a4 = select(0xf /* 0b00001111 */,c3,d3);
+ const vint8 b4 = shuffle<2,3,0,1>(a4);
+ const vint8 c4 = umax(a4,b4);
+ const vint8 d4 = umin(a4,b4);
+ const vint8 a5 = select(0x33 /* 0b00110011 */,c4,d4);
+ const vint8 b5 = shuffle<1,0,3,2>(a5);
+ const vint8 c5 = umax(a5,b5);
+ const vint8 d5 = umin(a5,b5);
+ const vint8 a6 = select(0x55 /* 0b01010101 */,c5,d5);
+ return a6;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vint8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vint8_avx2.h b/thirdparty/embree/common/simd/vint8_avx2.h
new file mode 100644
index 0000000000..e04737ffbe
--- /dev/null
+++ b/thirdparty/embree/common/simd/vint8_avx2.h
@@ -0,0 +1,518 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 8-wide AVX integer type */
+ template<>
+ struct vint<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m256i v;
+ int i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint() {}
+ __forceinline vint(const vint8& a) { v = a.v; }
+ __forceinline vint8& operator =(const vint8& a) { v = a.v; return *this; }
+
+ __forceinline vint(__m256i a) : v(a) {}
+ __forceinline operator const __m256i&() const { return v; }
+ __forceinline operator __m256i&() { return v; }
+
+ __forceinline explicit vint(const vint4& a) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),a,1)) {}
+ __forceinline vint(const vint4& a, const vint4& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+ __forceinline vint(const __m128i& a, const __m128i& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+
+ __forceinline explicit vint(const int* a) : v(_mm256_castps_si256(_mm256_loadu_ps((const float*)a))) {}
+ __forceinline vint(int a) : v(_mm256_set1_epi32(a)) {}
+ __forceinline vint(int a, int b) : v(_mm256_set_epi32(b, a, b, a, b, a, b, a)) {}
+ __forceinline vint(int a, int b, int c, int d) : v(_mm256_set_epi32(d, c, b, a, d, c, b, a)) {}
+ __forceinline vint(int a, int b, int c, int d, int e, int f, int g, int h) : v(_mm256_set_epi32(h, g, f, e, d, c, b, a)) {}
+
+ __forceinline explicit vint(__m256 a) : v(_mm256_cvtps_epi32(a)) {}
+
+#if defined(__AVX512VL__)
+ __forceinline explicit vint(const vboolf8& a) : v(_mm256_movm_epi32(a)) {}
+#else
+ __forceinline explicit vint(const vboolf8& a) : v(_mm256_castps_si256((__m256)a)) {}
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint(ZeroTy) : v(_mm256_setzero_si256()) {}
+ __forceinline vint(OneTy) : v(_mm256_set1_epi32(1)) {}
+ __forceinline vint(PosInfTy) : v(_mm256_set1_epi32(pos_inf)) {}
+ __forceinline vint(NegInfTy) : v(_mm256_set1_epi32(neg_inf)) {}
+ __forceinline vint(StepTy) : v(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0)) {}
+ __forceinline vint(ReverseStepTy) : v(_mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7)) {}
+ __forceinline vint(UndefinedTy) : v(_mm256_undefined_si256()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vint8 load(const unsigned char* ptr) { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
+ static __forceinline vint8 loadu(const unsigned char* ptr) { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
+ static __forceinline vint8 load(const unsigned short* ptr) { return _mm256_cvtepu16_epi32(_mm_load_si128((__m128i*)ptr)); }
+ static __forceinline vint8 loadu(const unsigned short* ptr) { return _mm256_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr)); }
+
+ static __forceinline vint8 load(const void* ptr) { return _mm256_load_si256((__m256i*)ptr); }
+ static __forceinline vint8 loadu(const void* ptr) { return _mm256_loadu_si256((__m256i*)ptr); }
+
+ static __forceinline void store (void* ptr, const vint8& v) { _mm256_store_si256((__m256i*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vint8& v) { _mm256_storeu_ps((float*)ptr,_mm256_castsi256_ps(v)); }
+
+#if defined(__AVX512VL__)
+
+ static __forceinline vint8 compact(const vboolf8& mask, vint8 &v) {
+ return _mm256_mask_compress_epi32(v, mask, v);
+ }
+ static __forceinline vint8 compact(const vboolf8& mask, vint8 &a, const vint8& b) {
+ return _mm256_mask_compress_epi32(a, mask, b);
+ }
+
+ static __forceinline vint8 load (const vboolf8& mask, const void* ptr) { return _mm256_mask_load_epi32 (_mm256_setzero_si256(),mask,ptr); }
+ static __forceinline vint8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_mask_loadu_epi32(_mm256_setzero_si256(),mask,ptr); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vint8& v) { _mm256_mask_store_epi32 (ptr,mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vint8& v) { _mm256_mask_storeu_epi32(ptr,mask,v); }
+#else
+ static __forceinline vint8 load (const vboolf8& mask, const void* ptr) { return _mm256_castps_si256(_mm256_maskload_ps((float*)ptr,mask)); }
+ static __forceinline vint8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_castps_si256(_mm256_maskload_ps((float*)ptr,mask)); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vint8& v) { _mm256_maskstore_epi32((int*)ptr,mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vint8& v) { _mm256_maskstore_epi32((int*)ptr,mask,v); }
+#endif
+
+ static __forceinline vint8 load_nt(void* ptr) {
+ return _mm256_stream_load_si256((__m256i*)ptr);
+ }
+
+ static __forceinline void store_nt(void* ptr, const vint8& v) {
+ _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
+ }
+
+ static __forceinline void store(unsigned char* ptr, const vint8& i)
+ {
+ for (size_t j=0; j<8; j++)
+ ptr[j] = i[j];
+ }
+
+ static __forceinline void store(unsigned short* ptr, const vint8& v) {
+ for (size_t i=0;i<8;i++)
+ ptr[i] = (unsigned short)v[i];
+ }
+
+ template<int scale = 4>
+ static __forceinline vint8 gather(const int *const ptr, const vint8& index) {
+ return _mm256_i32gather_epi32(ptr, index, scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vint8 gather(const vboolf8& mask, const int *const ptr, const vint8& index) {
+ vint8 r = zero;
+#if defined(__AVX512VL__)
+ return _mm256_mmask_i32gather_epi32(r, mask, index, ptr, scale);
+#else
+ return _mm256_mask_i32gather_epi32(r, ptr, index, mask, scale);
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint8& ofs, const vint8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_i32scatter_epi32((int*)ptr, ofs, v, scale);
+#else
+ *(int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+ *(int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+ *(int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+ *(int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+ *(int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+ *(int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+ *(int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+ *(int*)(((char*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vint8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_mask_i32scatter_epi32((int*)ptr, mask, ofs, v, scale);
+#else
+ if (likely(mask[0])) *(int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+ if (likely(mask[1])) *(int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+ if (likely(mask[2])) *(int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+ if (likely(mask[3])) *(int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+ if (likely(mask[4])) *(int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+ if (likely(mask[5])) *(int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+ if (likely(mask[6])) *(int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+ if (likely(mask[7])) *(int*)(((char*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ static __forceinline vint8 broadcast64(const long long &a) { return _mm256_set1_epi64x(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const int& operator [](size_t index) const { assert(index < 8); return i[index]; }
+ __forceinline int& operator [](size_t index) { assert(index < 8); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ static __forceinline vboolf8 asBool(const vint8& a) { return _mm256_movepi32_mask(a); }
+#else
+ static __forceinline vboolf8 asBool(const vint8& a) { return _mm256_castsi256_ps(a); }
+#endif
+
+ __forceinline vint8 operator +(const vint8& a) { return a; }
+ __forceinline vint8 operator -(const vint8& a) { return _mm256_sub_epi32(_mm256_setzero_si256(), a); }
+ __forceinline vint8 abs (const vint8& a) { return _mm256_abs_epi32(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 operator +(const vint8& a, const vint8& b) { return _mm256_add_epi32(a, b); }
+ __forceinline vint8 operator +(const vint8& a, int b) { return a + vint8(b); }
+ __forceinline vint8 operator +(int a, const vint8& b) { return vint8(a) + b; }
+
+ __forceinline vint8 operator -(const vint8& a, const vint8& b) { return _mm256_sub_epi32(a, b); }
+ __forceinline vint8 operator -(const vint8& a, int b) { return a - vint8(b); }
+ __forceinline vint8 operator -(int a, const vint8& b) { return vint8(a) - b; }
+
+ __forceinline vint8 operator *(const vint8& a, const vint8& b) { return _mm256_mullo_epi32(a, b); }
+ __forceinline vint8 operator *(const vint8& a, int b) { return a * vint8(b); }
+ __forceinline vint8 operator *(int a, const vint8& b) { return vint8(a) * b; }
+
+ __forceinline vint8 operator &(const vint8& a, const vint8& b) { return _mm256_and_si256(a, b); }
+ __forceinline vint8 operator &(const vint8& a, int b) { return a & vint8(b); }
+ __forceinline vint8 operator &(int a, const vint8& b) { return vint8(a) & b; }
+
+ __forceinline vint8 operator |(const vint8& a, const vint8& b) { return _mm256_or_si256(a, b); }
+ __forceinline vint8 operator |(const vint8& a, int b) { return a | vint8(b); }
+ __forceinline vint8 operator |(int a, const vint8& b) { return vint8(a) | b; }
+
+ __forceinline vint8 operator ^(const vint8& a, const vint8& b) { return _mm256_xor_si256(a, b); }
+ __forceinline vint8 operator ^(const vint8& a, int b) { return a ^ vint8(b); }
+ __forceinline vint8 operator ^(int a, const vint8& b) { return vint8(a) ^ b; }
+
+ __forceinline vint8 operator <<(const vint8& a, int n) { return _mm256_slli_epi32(a, n); }
+ __forceinline vint8 operator >>(const vint8& a, int n) { return _mm256_srai_epi32(a, n); }
+
+ __forceinline vint8 operator <<(const vint8& a, const vint8& n) { return _mm256_sllv_epi32(a, n); }
+ __forceinline vint8 operator >>(const vint8& a, const vint8& n) { return _mm256_srav_epi32(a, n); }
+
+ __forceinline vint8 sll(const vint8& a, int b) { return _mm256_slli_epi32(a, b); }
+ __forceinline vint8 sra(const vint8& a, int b) { return _mm256_srai_epi32(a, b); }
+ __forceinline vint8 srl(const vint8& a, int b) { return _mm256_srli_epi32(a, b); }
+
+ __forceinline vint8 sll(const vint8& a, const vint8& b) { return _mm256_sllv_epi32(a, b); }
+ __forceinline vint8 sra(const vint8& a, const vint8& b) { return _mm256_srav_epi32(a, b); }
+ __forceinline vint8 srl(const vint8& a, const vint8& b) { return _mm256_srlv_epi32(a, b); }
+
+ __forceinline vint8 min(const vint8& a, const vint8& b) { return _mm256_min_epi32(a, b); }
+ __forceinline vint8 min(const vint8& a, int b) { return min(a,vint8(b)); }
+ __forceinline vint8 min(int a, const vint8& b) { return min(vint8(a),b); }
+
+ __forceinline vint8 max(const vint8& a, const vint8& b) { return _mm256_max_epi32(a, b); }
+ __forceinline vint8 max(const vint8& a, int b) { return max(a,vint8(b)); }
+ __forceinline vint8 max(int a, const vint8& b) { return max(vint8(a),b); }
+
+ __forceinline vint8 umin(const vint8& a, const vint8& b) { return _mm256_min_epu32(a, b); }
+ __forceinline vint8 umax(const vint8& a, const vint8& b) { return _mm256_max_epu32(a, b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8& operator +=(vint8& a, const vint8& b) { return a = a + b; }
+ __forceinline vint8& operator +=(vint8& a, int b) { return a = a + b; }
+
+ __forceinline vint8& operator -=(vint8& a, const vint8& b) { return a = a - b; }
+ __forceinline vint8& operator -=(vint8& a, int b) { return a = a - b; }
+
+ __forceinline vint8& operator *=(vint8& a, const vint8& b) { return a = a * b; }
+ __forceinline vint8& operator *=(vint8& a, int b) { return a = a * b; }
+
+ __forceinline vint8& operator &=(vint8& a, const vint8& b) { return a = a & b; }
+ __forceinline vint8& operator &=(vint8& a, int b) { return a = a & b; }
+
+ __forceinline vint8& operator |=(vint8& a, const vint8& b) { return a = a | b; }
+ __forceinline vint8& operator |=(vint8& a, int b) { return a = a | b; }
+
+ __forceinline vint8& operator <<=(vint8& a, const int b) { return a = a << b; }
+ __forceinline vint8& operator >>=(vint8& a, const int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ static __forceinline vboolf8 operator ==(const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_EQ); }
+ static __forceinline vboolf8 operator !=(const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_NE); }
+ static __forceinline vboolf8 operator < (const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_LT); }
+ static __forceinline vboolf8 operator >=(const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_GE); }
+ static __forceinline vboolf8 operator > (const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_GT); }
+ static __forceinline vboolf8 operator <=(const vint8& a, const vint8& b) { return _mm256_cmp_epi32_mask(a,b,_MM_CMPINT_LE); }
+
+ static __forceinline vint8 select(const vboolf8& m, const vint8& t, const vint8& f) {
+ return _mm256_mask_blend_epi32(m, (__m256i)f, (__m256i)t);
+ }
+#else
+ static __forceinline vboolf8 operator ==(const vint8& a, const vint8& b) { return _mm256_castsi256_ps(_mm256_cmpeq_epi32(a, b)); }
+ static __forceinline vboolf8 operator !=(const vint8& a, const vint8& b) { return !(a == b); }
+ static __forceinline vboolf8 operator < (const vint8& a, const vint8& b) { return _mm256_castsi256_ps(_mm256_cmpgt_epi32(b, a)); }
+ static __forceinline vboolf8 operator >=(const vint8& a, const vint8& b) { return !(a < b); }
+ static __forceinline vboolf8 operator > (const vint8& a, const vint8& b) { return _mm256_castsi256_ps(_mm256_cmpgt_epi32(a, b)); }
+ static __forceinline vboolf8 operator <=(const vint8& a, const vint8& b) { return !(a > b); }
+
+ static __forceinline vint8 select(const vboolf8& m, const vint8& t, const vint8& f) {
+ return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(f), _mm256_castsi256_ps(t), m));
+ }
+#endif
+
+ template<int mask>
+ __forceinline vint8 select(const vint8& t, const vint8& f) {
+ return _mm256_blend_epi32(f, t, mask);
+ }
+
+ __forceinline vboolf8 operator ==(const vint8& a, int b) { return a == vint8(b); }
+ __forceinline vboolf8 operator ==(int a, const vint8& b) { return vint8(a) == b; }
+
+ __forceinline vboolf8 operator !=(const vint8& a, int b) { return a != vint8(b); }
+ __forceinline vboolf8 operator !=(int a, const vint8& b) { return vint8(a) != b; }
+
+ __forceinline vboolf8 operator < (const vint8& a, int b) { return a < vint8(b); }
+ __forceinline vboolf8 operator < (int a, const vint8& b) { return vint8(a) < b; }
+
+ __forceinline vboolf8 operator >=(const vint8& a, int b) { return a >= vint8(b); }
+ __forceinline vboolf8 operator >=(int a, const vint8& b) { return vint8(a) >= b; }
+
+ __forceinline vboolf8 operator > (const vint8& a, int b) { return a > vint8(b); }
+ __forceinline vboolf8 operator > (int a, const vint8& b) { return vint8(a) > b; }
+
+ __forceinline vboolf8 operator <=(const vint8& a, int b) { return a <= vint8(b); }
+ __forceinline vboolf8 operator <=(int a, const vint8& b) { return vint8(a) <= b; }
+
+ __forceinline vboolf8 eq(const vint8& a, const vint8& b) { return a == b; }
+ __forceinline vboolf8 ne(const vint8& a, const vint8& b) { return a != b; }
+ __forceinline vboolf8 lt(const vint8& a, const vint8& b) { return a < b; }
+ __forceinline vboolf8 ge(const vint8& a, const vint8& b) { return a >= b; }
+ __forceinline vboolf8 gt(const vint8& a, const vint8& b) { return a > b; }
+ __forceinline vboolf8 le(const vint8& a, const vint8& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ static __forceinline vboolf8 eq(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_EQ); }
+ static __forceinline vboolf8 ne(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_NE); }
+ static __forceinline vboolf8 lt(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LT); }
+ static __forceinline vboolf8 ge(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_GE); }
+ static __forceinline vboolf8 gt(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_GT); }
+ static __forceinline vboolf8 le(const vboolf8& mask, const vint8& a, const vint8& b) { return _mm256_mask_cmp_epi32_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ static __forceinline vboolf8 eq(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a == b); }
+ static __forceinline vboolf8 ne(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a != b); }
+ static __forceinline vboolf8 lt(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a < b); }
+ static __forceinline vboolf8 ge(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a >= b); }
+ static __forceinline vboolf8 gt(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a > b); }
+ static __forceinline vboolf8 le(const vboolf8& mask, const vint8& a, const vint8& b) { return mask & (a <= b); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 unpacklo(const vint8& a, const vint8& b) { return _mm256_unpacklo_epi32(a, b); }
+ __forceinline vint8 unpackhi(const vint8& a, const vint8& b) { return _mm256_unpackhi_epi32(a, b); }
+
+ template<int i>
+ __forceinline vint8 shuffle(const vint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1>
+ __forceinline vint8 shuffle4(const vint8& v) {
+ return _mm256_permute2f128_si256(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vint8 shuffle4(const vint8& a, const vint8& b) {
+ return _mm256_permute2f128_si256(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint8 shuffle(const vint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vint8 shuffle(const vint8& a, const vint8& b) {
+ return _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<> __forceinline vint8 shuffle<0, 0, 2, 2>(const vint8& v) { return _mm256_castps_si256(_mm256_moveldup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vint8 shuffle<1, 1, 3, 3>(const vint8& v) { return _mm256_castps_si256(_mm256_movehdup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vint8 shuffle<0, 1, 0, 1>(const vint8& v) { return _mm256_castps_si256(_mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(_mm256_castsi256_ps(v))))); }
+
+ __forceinline vint8 broadcast(const int* ptr) { return _mm256_castps_si256(_mm256_broadcast_ss((const float*)ptr)); }
+
+ template<int i> __forceinline vint8 insert4(const vint8& a, const vint4& b) { return _mm256_insertf128_si256(a, b, i); }
+ template<int i> __forceinline vint4 extract4(const vint8& a) { return _mm256_extractf128_si256(a, i); }
+ template<> __forceinline vint4 extract4<0>(const vint8& a) { return _mm256_castsi256_si128(a); }
+
+ __forceinline int toScalar(const vint8& v) { return _mm_cvtsi128_si32(_mm256_castsi256_si128(v)); }
+
+ __forceinline vint8 permute(const vint8& v, const __m256i& index) {
+ return _mm256_permutevar8x32_epi32(v, index);
+ }
+
+ __forceinline vint8 shuffle(const vint8& v, const __m256i& index) {
+ return _mm256_castps_si256(_mm256_permutevar_ps(_mm256_castsi256_ps(v), index));
+ }
+
+ template<int i>
+ static __forceinline vint8 align_shift_right(const vint8& a, const vint8& b) {
+#if defined(__AVX512VL__)
+ return _mm256_alignr_epi32(a, b, i);
+#else
+ return _mm256_alignr_epi8(a, b, 4*i);
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 vreduce_min2(const vint8& v) { return min(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vint8 vreduce_min4(const vint8& v) { vint8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vint8 vreduce_min (const vint8& v) { vint8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vint8 vreduce_max2(const vint8& v) { return max(v,shuffle<1,0,3,2>(v)); }
+ __forceinline vint8 vreduce_max4(const vint8& v) { vint8 v1 = vreduce_max2(v); return max(v1,shuffle<2,3,0,1>(v1)); }
+ __forceinline vint8 vreduce_max (const vint8& v) { vint8 v1 = vreduce_max4(v); return max(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vint8 vreduce_add2(const vint8& v) { return v + shuffle<1,0,3,2>(v); }
+ __forceinline vint8 vreduce_add4(const vint8& v) { vint8 v1 = vreduce_add2(v); return v1 + shuffle<2,3,0,1>(v1); }
+ __forceinline vint8 vreduce_add (const vint8& v) { vint8 v1 = vreduce_add4(v); return v1 + shuffle4<1,0>(v1); }
+
+ __forceinline int reduce_min(const vint8& v) { return toScalar(vreduce_min(v)); }
+ __forceinline int reduce_max(const vint8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_add(const vint8& v) { return toScalar(vreduce_add(v)); }
+
+ __forceinline size_t select_min(const vint8& v) { return bsf(movemask(v == vreduce_min(v))); }
+ __forceinline size_t select_max(const vint8& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ __forceinline size_t select_min(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ __forceinline size_t select_max(const vboolf8& valid, const vint8& v) { const vint8 a = select(valid,v,vint8(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Sorting networks
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vint8 usort_ascending(const vint8& v)
+ {
+ const vint8 a0 = v;
+ const vint8 b0 = shuffle<1,0,3,2>(a0);
+ const vint8 c0 = umin(a0,b0);
+ const vint8 d0 = umax(a0,b0);
+ const vint8 a1 = select<0x99 /* 0b10011001 */>(c0,d0);
+ const vint8 b1 = shuffle<2,3,0,1>(a1);
+ const vint8 c1 = umin(a1,b1);
+ const vint8 d1 = umax(a1,b1);
+ const vint8 a2 = select<0xc3 /* 0b11000011 */>(c1,d1);
+ const vint8 b2 = shuffle<1,0,3,2>(a2);
+ const vint8 c2 = umin(a2,b2);
+ const vint8 d2 = umax(a2,b2);
+ const vint8 a3 = select<0xa5 /* 0b10100101 */>(c2,d2);
+ const vint8 b3 = shuffle4<1,0>(a3);
+ const vint8 c3 = umin(a3,b3);
+ const vint8 d3 = umax(a3,b3);
+ const vint8 a4 = select<0xf /* 0b00001111 */>(c3,d3);
+ const vint8 b4 = shuffle<2,3,0,1>(a4);
+ const vint8 c4 = umin(a4,b4);
+ const vint8 d4 = umax(a4,b4);
+ const vint8 a5 = select<0x33 /* 0b00110011 */>(c4,d4);
+ const vint8 b5 = shuffle<1,0,3,2>(a5);
+ const vint8 c5 = umin(a5,b5);
+ const vint8 d5 = umax(a5,b5);
+ const vint8 a6 = select<0x55 /* 0b01010101 */>(c5,d5);
+ return a6;
+ }
+
+ __forceinline vint8 usort_descending(const vint8& v)
+ {
+ const vint8 a0 = v;
+ const vint8 b0 = shuffle<1,0,3,2>(a0);
+ const vint8 c0 = umax(a0,b0);
+ const vint8 d0 = umin(a0,b0);
+ const vint8 a1 = select<0x99 /* 0b10011001 */>(c0,d0);
+ const vint8 b1 = shuffle<2,3,0,1>(a1);
+ const vint8 c1 = umax(a1,b1);
+ const vint8 d1 = umin(a1,b1);
+ const vint8 a2 = select<0xc3 /* 0b11000011 */>(c1,d1);
+ const vint8 b2 = shuffle<1,0,3,2>(a2);
+ const vint8 c2 = umax(a2,b2);
+ const vint8 d2 = umin(a2,b2);
+ const vint8 a3 = select<0xa5 /* 0b10100101 */>(c2,d2);
+ const vint8 b3 = shuffle4<1,0>(a3);
+ const vint8 c3 = umax(a3,b3);
+ const vint8 d3 = umin(a3,b3);
+ const vint8 a4 = select<0xf /* 0b00001111 */>(c3,d3);
+ const vint8 b4 = shuffle<2,3,0,1>(a4);
+ const vint8 c4 = umax(a4,b4);
+ const vint8 d4 = umin(a4,b4);
+ const vint8 a5 = select<0x33 /* 0b00110011 */>(c4,d4);
+ const vint8 b5 = shuffle<1,0,3,2>(a5);
+ const vint8 c5 = umax(a5,b5);
+ const vint8 d5 = umin(a5,b5);
+ const vint8 a6 = select<0x55 /* 0b01010101 */>(c5,d5);
+ return a6;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vint8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vllong4_avx2.h b/thirdparty/embree/common/simd/vllong4_avx2.h
new file mode 100644
index 0000000000..6c86845877
--- /dev/null
+++ b/thirdparty/embree/common/simd/vllong4_avx2.h
@@ -0,0 +1,352 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 4-wide AVX2 64-bit long long type */
+ template<>
+ struct vllong<4>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboold4 Bool;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { // data
+ __m256i v;
+ long long i[4];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong() {}
+ __forceinline vllong(const vllong4& t) { v = t.v; }
+ __forceinline vllong4& operator =(const vllong4& f) { v = f.v; return *this; }
+
+ __forceinline vllong(const __m256i& t) { v = t; }
+ __forceinline operator __m256i() const { return v; }
+ __forceinline operator __m256d() const { return _mm256_castsi256_pd(v); }
+
+
+ __forceinline vllong(long long i) {
+ v = _mm256_set1_epi64x(i);
+ }
+
+ __forceinline vllong(long long a, long long b, long long c, long long d) {
+ v = _mm256_set_epi64x(d,c,b,a);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong(ZeroTy) : v(_mm256_setzero_si256()) {}
+ __forceinline vllong(OneTy) : v(_mm256_set1_epi64x(1)) {}
+ __forceinline vllong(StepTy) : v(_mm256_set_epi64x(3,2,1,0)) {}
+ __forceinline vllong(ReverseStepTy) : v(_mm256_set_epi64x(0,1,2,3)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline void store_nt(void* __restrict__ ptr, const vllong4& a) {
+ _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(a));
+ }
+
+ static __forceinline vllong4 loadu(const void* addr)
+ {
+ return _mm256_loadu_si256((__m256i*)addr);
+ }
+
+ static __forceinline vllong4 load(const vllong4* addr) {
+ return _mm256_load_si256((__m256i*)addr);
+ }
+
+ static __forceinline vllong4 load(const long long* addr) {
+ return _mm256_load_si256((__m256i*)addr);
+ }
+
+ static __forceinline void store(void* ptr, const vllong4& v) {
+ _mm256_store_si256((__m256i*)ptr,v);
+ }
+
+ static __forceinline void storeu(void* ptr, const vllong4& v) {
+ _mm256_storeu_si256((__m256i*)ptr,v);
+ }
+
+ static __forceinline void storeu(const vboold4& mask, long long* ptr, const vllong4& f) {
+#if defined(__AVX512VL__)
+ _mm256_mask_storeu_epi64(ptr,mask,f);
+#else
+ _mm256_maskstore_pd((double*)ptr,mask,_mm256_castsi256_pd(f));
+#endif
+ }
+
+ static __forceinline void store(const vboold4& mask, void* ptr, const vllong4& f) {
+#if defined(__AVX512VL__)
+ _mm256_mask_store_epi64(ptr,mask,f);
+#else
+ _mm256_maskstore_pd((double*)ptr,mask,_mm256_castsi256_pd(f));
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline long long& operator [](size_t index) { assert(index < 4); return i[index]; }
+ __forceinline const long long& operator [](size_t index) const { assert(index < 4); return i[index]; }
+
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong4 select(const vboold4& m, const vllong4& t, const vllong4& f) {
+ #if defined(__AVX512VL__)
+ return _mm256_mask_blend_epi64(m, f, t);
+ #else
+ return _mm256_castpd_si256(_mm256_blendv_pd(_mm256_castsi256_pd(f), _mm256_castsi256_pd(t), m));
+ #endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboold4 asBool(const vllong4& a) { return _mm256_movepi64_mask(a); }
+#else
+ __forceinline vboold4 asBool(const vllong4& a) { return _mm256_castsi256_pd(a); }
+#endif
+
+ __forceinline vllong4 operator +(const vllong4& a) { return a; }
+ __forceinline vllong4 operator -(const vllong4& a) { return _mm256_sub_epi64(_mm256_setzero_si256(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong4 operator +(const vllong4& a, const vllong4& b) { return _mm256_add_epi64(a, b); }
+ __forceinline vllong4 operator +(const vllong4& a, long long b) { return a + vllong4(b); }
+ __forceinline vllong4 operator +(long long a, const vllong4& b) { return vllong4(a) + b; }
+
+ __forceinline vllong4 operator -(const vllong4& a, const vllong4& b) { return _mm256_sub_epi64(a, b); }
+ __forceinline vllong4 operator -(const vllong4& a, long long b) { return a - vllong4(b); }
+ __forceinline vllong4 operator -(long long a, const vllong4& b) { return vllong4(a) - b; }
+
+ /* only low 32bit part */
+ __forceinline vllong4 operator *(const vllong4& a, const vllong4& b) { return _mm256_mul_epi32(a, b); }
+ __forceinline vllong4 operator *(const vllong4& a, long long b) { return a * vllong4(b); }
+ __forceinline vllong4 operator *(long long a, const vllong4& b) { return vllong4(a) * b; }
+
+ __forceinline vllong4 operator &(const vllong4& a, const vllong4& b) { return _mm256_and_si256(a, b); }
+ __forceinline vllong4 operator &(const vllong4& a, long long b) { return a & vllong4(b); }
+ __forceinline vllong4 operator &(long long a, const vllong4& b) { return vllong4(a) & b; }
+
+ __forceinline vllong4 operator |(const vllong4& a, const vllong4& b) { return _mm256_or_si256(a, b); }
+ __forceinline vllong4 operator |(const vllong4& a, long long b) { return a | vllong4(b); }
+ __forceinline vllong4 operator |(long long a, const vllong4& b) { return vllong4(a) | b; }
+
+ __forceinline vllong4 operator ^(const vllong4& a, const vllong4& b) { return _mm256_xor_si256(a, b); }
+ __forceinline vllong4 operator ^(const vllong4& a, long long b) { return a ^ vllong4(b); }
+ __forceinline vllong4 operator ^(long long a, const vllong4& b) { return vllong4(a) ^ b; }
+
+ __forceinline vllong4 operator <<(const vllong4& a, long long n) { return _mm256_slli_epi64(a, (int)n); }
+ //__forceinline vllong4 operator >>(const vllong4& a, long long n) { return _mm256_srai_epi64(a, n); }
+
+ __forceinline vllong4 operator <<(const vllong4& a, const vllong4& n) { return _mm256_sllv_epi64(a, n); }
+ //__forceinline vllong4 operator >>(const vllong4& a, const vllong4& n) { return _mm256_srav_epi64(a, n); }
+ //__forceinline vllong4 sra(const vllong4& a, long long b) { return _mm256_srai_epi64(a, b); }
+
+ __forceinline vllong4 srl(const vllong4& a, long long b) { return _mm256_srli_epi64(a, (int)b); }
+
+ //__forceinline vllong4 min(const vllong4& a, const vllong4& b) { return _mm256_min_epi64(a, b); }
+ //__forceinline vllong4 min(const vllong4& a, long long b) { return min(a,vllong4(b)); }
+ //__forceinline vllong4 min(long long a, const vllong4& b) { return min(vllong4(a),b); }
+
+ //__forceinline vllong4 max(const vllong4& a, const vllong4& b) { return _mm256_max_epi64(a, b); }
+ //__forceinline vllong4 max(const vllong4& a, long long b) { return max(a,vllong4(b)); }
+ //__forceinline vllong4 max(long long a, const vllong4& b) { return max(vllong4(a),b); }
+
+#if defined(__AVX512VL__)
+ __forceinline vllong4 mask_and(const vboold4& m, const vllong4& c, const vllong4& a, const vllong4& b) { return _mm256_mask_and_epi64(c,m,a,b); }
+ __forceinline vllong4 mask_or (const vboold4& m, const vllong4& c, const vllong4& a, const vllong4& b) { return _mm256_mask_or_epi64(c,m,a,b); }
+#else
+ __forceinline vllong4 mask_and(const vboold4& m, const vllong4& c, const vllong4& a, const vllong4& b) { return select(m, a & b, c); }
+ __forceinline vllong4 mask_or (const vboold4& m, const vllong4& c, const vllong4& a, const vllong4& b) { return select(m, a | b, c); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong4& operator +=(vllong4& a, const vllong4& b) { return a = a + b; }
+ __forceinline vllong4& operator +=(vllong4& a, long long b) { return a = a + b; }
+
+ __forceinline vllong4& operator -=(vllong4& a, const vllong4& b) { return a = a - b; }
+ __forceinline vllong4& operator -=(vllong4& a, long long b) { return a = a - b; }
+
+ __forceinline vllong4& operator *=(vllong4& a, const vllong4& b) { return a = a * b; }
+ __forceinline vllong4& operator *=(vllong4& a, long long b) { return a = a * b; }
+
+ __forceinline vllong4& operator &=(vllong4& a, const vllong4& b) { return a = a & b; }
+ __forceinline vllong4& operator &=(vllong4& a, long long b) { return a = a & b; }
+
+ __forceinline vllong4& operator |=(vllong4& a, const vllong4& b) { return a = a | b; }
+ __forceinline vllong4& operator |=(vllong4& a, long long b) { return a = a | b; }
+
+ __forceinline vllong4& operator <<=(vllong4& a, long long b) { return a = a << b; }
+ //__forceinline vllong4& operator >>=(vllong4& a, long long b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboold4 operator ==(const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold4 operator !=(const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboold4 operator < (const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboold4 operator >=(const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboold4 operator > (const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboold4 operator <=(const vllong4& a, const vllong4& b) { return _mm256_cmp_epi64_mask(a,b,_MM_CMPINT_LE); }
+#else
+ __forceinline vboold4 operator ==(const vllong4& a, const vllong4& b) { return _mm256_cmpeq_epi64(a,b); }
+ __forceinline vboold4 operator !=(const vllong4& a, const vllong4& b) { return !(a == b); }
+ __forceinline vboold4 operator > (const vllong4& a, const vllong4& b) { return _mm256_cmpgt_epi64(a,b); }
+ __forceinline vboold4 operator < (const vllong4& a, const vllong4& b) { return _mm256_cmpgt_epi64(b,a); }
+ __forceinline vboold4 operator >=(const vllong4& a, const vllong4& b) { return !(a < b); }
+ __forceinline vboold4 operator <=(const vllong4& a, const vllong4& b) { return !(a > b); }
+#endif
+
+ __forceinline vboold4 operator ==(const vllong4& a, long long b) { return a == vllong4(b); }
+ __forceinline vboold4 operator ==(long long a, const vllong4& b) { return vllong4(a) == b; }
+
+ __forceinline vboold4 operator !=(const vllong4& a, long long b) { return a != vllong4(b); }
+ __forceinline vboold4 operator !=(long long a, const vllong4& b) { return vllong4(a) != b; }
+
+ __forceinline vboold4 operator > (const vllong4& a, long long b) { return a > vllong4(b); }
+ __forceinline vboold4 operator > (long long a, const vllong4& b) { return vllong4(a) > b; }
+
+ __forceinline vboold4 operator < (const vllong4& a, long long b) { return a < vllong4(b); }
+ __forceinline vboold4 operator < (long long a, const vllong4& b) { return vllong4(a) < b; }
+
+ __forceinline vboold4 operator >=(const vllong4& a, long long b) { return a >= vllong4(b); }
+ __forceinline vboold4 operator >=(long long a, const vllong4& b) { return vllong4(a) >= b; }
+
+ __forceinline vboold4 operator <=(const vllong4& a, long long b) { return a <= vllong4(b); }
+ __forceinline vboold4 operator <=(long long a, const vllong4& b) { return vllong4(a) <= b; }
+
+ __forceinline vboold4 eq(const vllong4& a, const vllong4& b) { return a == b; }
+ __forceinline vboold4 ne(const vllong4& a, const vllong4& b) { return a != b; }
+ __forceinline vboold4 lt(const vllong4& a, const vllong4& b) { return a < b; }
+ __forceinline vboold4 ge(const vllong4& a, const vllong4& b) { return a >= b; }
+ __forceinline vboold4 gt(const vllong4& a, const vllong4& b) { return a > b; }
+ __forceinline vboold4 le(const vllong4& a, const vllong4& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboold4 eq(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboold4 ne(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_NE); }
+ __forceinline vboold4 lt(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_LT); }
+ __forceinline vboold4 ge(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_GE); }
+ __forceinline vboold4 gt(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_GT); }
+ __forceinline vboold4 le(const vboold4& mask, const vllong4& a, const vllong4& b) { return _mm256_mask_cmp_epi64_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboold4 eq(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a == b); }
+ __forceinline vboold4 ne(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a != b); }
+ __forceinline vboold4 lt(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a < b); }
+ __forceinline vboold4 ge(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a >= b); }
+ __forceinline vboold4 gt(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a > b); }
+ __forceinline vboold4 le(const vboold4& mask, const vllong4& a, const vllong4& b) { return mask & (a <= b); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int i0, int i1>
+ __forceinline vllong4 shuffle(const vllong4& v) {
+ return _mm256_castpd_si256(_mm256_permute_pd(_mm256_castsi256_pd(v), (i1 << 3) | (i0 << 2) | (i1 << 1) | i0));
+ }
+
+ template<int i>
+ __forceinline vllong4 shuffle(const vllong4& v) {
+ return shuffle<i, i>(v);
+ }
+
+ template<int i0, int i1>
+ __forceinline vllong4 shuffle2(const vllong4& v) {
+ return _mm256_castpd_si256(_mm256_permute2f128_pd(_mm256_castsi256_pd(v), _mm256_castsi256_pd(v), (i1 << 4) | i0));
+ }
+
+ __forceinline long long toScalar(const vllong4& v) {
+ return _mm_cvtsi128_si64(_mm256_castsi256_si128(v));
+ }
+
+#if defined(__AVX512VL__)
+ __forceinline vllong4 permute(const vllong4& a, const __m256i& index) {
+ // workaround for GCC 7.x
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
+ return _mm256_permutex2var_epi64(a,index,a);
+#else
+ return _mm256_permutexvar_epi64(index,a);
+#endif
+ }
+
+ __forceinline vllong4 permutex2var(const vllong4& index, const vllong4& a, const vllong4& b) {
+ return _mm256_permutex2var_epi64(a,index,b);
+ }
+
+#endif
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ __forceinline vllong4 vreduce_and2(const vllong4& x) { return x & shuffle<1,0>(x); }
+ __forceinline vllong4 vreduce_and (const vllong4& y) { const vllong4 x = vreduce_and2(y); return x & shuffle2<1,0>(x); }
+
+ __forceinline vllong4 vreduce_or2(const vllong4& x) { return x | shuffle<1,0>(x); }
+ __forceinline vllong4 vreduce_or (const vllong4& y) { const vllong4 x = vreduce_or2(y); return x | shuffle2<1,0>(x); }
+
+ __forceinline vllong4 vreduce_add2(const vllong4& x) { return x + shuffle<1,0>(x); }
+ __forceinline vllong4 vreduce_add (const vllong4& y) { const vllong4 x = vreduce_add2(y); return x + shuffle2<1,0>(x); }
+
+ __forceinline long long reduce_add(const vllong4& a) { return toScalar(vreduce_add(a)); }
+ __forceinline long long reduce_or (const vllong4& a) { return toScalar(vreduce_or(a)); }
+ __forceinline long long reduce_and(const vllong4& a) { return toScalar(vreduce_and(a)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vllong4& v)
+ {
+ cout << "<" << v[0];
+ for (size_t i=1; i<4; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vllong8_avx512.h b/thirdparty/embree/common/simd/vllong8_avx512.h
new file mode 100644
index 0000000000..ee69411637
--- /dev/null
+++ b/thirdparty/embree/common/simd/vllong8_avx512.h
@@ -0,0 +1,358 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 8-wide AVX-512 64-bit long long type */
+ template<>
+ struct vllong<8>
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef vboold8 Bool;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m512i v;
+ long long i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong() {}
+ __forceinline vllong(const vllong8& t) { v = t.v; }
+ __forceinline vllong8& operator =(const vllong8& f) { v = f.v; return *this; }
+
+ __forceinline vllong(const __m512i& t) { v = t; }
+ __forceinline operator __m512i() const { return v; }
+ __forceinline operator __m256i() const { return _mm512_castsi512_si256(v); }
+
+ __forceinline vllong(long long i) {
+ v = _mm512_set1_epi64(i);
+ }
+
+ __forceinline vllong(long long a, long long b, long long c, long long d) {
+ v = _mm512_set4_epi64(d,c,b,a);
+ }
+
+ __forceinline vllong(long long a0, long long a1, long long a2, long long a3,
+ long long a4, long long a5, long long a6, long long a7)
+ {
+ v = _mm512_set_epi64(a7,a6,a5,a4,a3,a2,a1,a0);
+ }
+
+ __forceinline vllong(const vllong<4>& i) {
+ v = _mm512_broadcast_i64x4(i);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong(ZeroTy) : v(_mm512_setzero_epi32()) {}
+ __forceinline vllong(OneTy) : v(_mm512_set1_epi64(1)) {}
+ __forceinline vllong(StepTy) : v(_mm512_set_epi64(7,6,5,4,3,2,1,0)) {}
+ __forceinline vllong(ReverseStepTy) : v(_mm512_setr_epi64(7,6,5,4,3,2,1,0)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline void store_nt(void* __restrict__ ptr, const vllong8& a) {
+ _mm512_stream_si512((__m512i*)ptr,a);
+ }
+
+ static __forceinline vllong8 loadu(const void* addr) {
+ return _mm512_loadu_si512(addr);
+ }
+
+ static __forceinline vllong8 load(const vllong8* addr) {
+ return _mm512_load_si512(addr);
+ }
+
+ static __forceinline vllong8 load(const long long* addr) {
+ return _mm512_load_si512(addr);
+ }
+
+ static __forceinline vllong8 load(const unsigned char* ptr) {
+ return _mm512_cvtepu8_epi64(*(__m128i*)ptr);
+ }
+
+ static __forceinline void store(void* ptr, const vllong8& v) {
+ _mm512_store_si512(ptr,v);
+ }
+
+ static __forceinline void storeu(void* ptr, const vllong8& v) {
+ _mm512_storeu_si512(ptr,v);
+ }
+
+ static __forceinline void storeu(const vboold8& mask, long long* ptr, const vllong8& f) {
+ _mm512_mask_storeu_epi64(ptr,mask,f);
+ }
+
+ static __forceinline void store(const vboold8& mask, void* addr, const vllong8& v2) {
+ _mm512_mask_store_epi64(addr,mask,v2);
+ }
+
+ static __forceinline vllong8 compact(const vboold8& mask, vllong8& v) {
+ return _mm512_mask_compress_epi64(v,mask,v);
+ }
+
+ static __forceinline vllong8 compact(const vboold8& mask, const vllong8& a, vllong8& b) {
+ return _mm512_mask_compress_epi64(a,mask,b);
+ }
+
+ static __forceinline vllong8 expand(const vboold8& mask, const vllong8& a, vllong8& b) {
+ return _mm512_mask_expand_epi64(b,mask,a);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline long long& operator [](size_t index) { assert(index < 8); return i[index]; }
+ __forceinline const long long& operator [](size_t index) const { assert(index < 8); return i[index]; }
+
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 asBool(const vllong8& a) { return _mm512_movepi64_mask(a); }
+
+ __forceinline vllong8 operator +(const vllong8& a) { return a; }
+ __forceinline vllong8 operator -(const vllong8& a) { return _mm512_sub_epi64(_mm512_setzero_epi32(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong8 operator +(const vllong8& a, const vllong8& b) { return _mm512_add_epi64(a, b); }
+ __forceinline vllong8 operator +(const vllong8& a, long long b) { return a + vllong8(b); }
+ __forceinline vllong8 operator +(long long a, const vllong8& b) { return vllong8(a) + b; }
+
+ __forceinline vllong8 operator -(const vllong8& a, const vllong8& b) { return _mm512_sub_epi64(a, b); }
+ __forceinline vllong8 operator -(const vllong8& a, long long b) { return a - vllong8(b); }
+ __forceinline vllong8 operator -(long long a, const vllong8& b) { return vllong8(a) - b; }
+
+ __forceinline vllong8 operator *(const vllong8& a, const vllong8& b) { return _mm512_mullo_epi64(a, b); }
+ __forceinline vllong8 operator *(const vllong8& a, long long b) { return a * vllong8(b); }
+ __forceinline vllong8 operator *(long long a, const vllong8& b) { return vllong8(a) * b; }
+
+ __forceinline vllong8 operator &(const vllong8& a, const vllong8& b) { return _mm512_and_epi64(a, b); }
+ __forceinline vllong8 operator &(const vllong8& a, long long b) { return a & vllong8(b); }
+ __forceinline vllong8 operator &(long long a, const vllong8& b) { return vllong8(a) & b; }
+
+ __forceinline vllong8 operator |(const vllong8& a, const vllong8& b) { return _mm512_or_epi64(a, b); }
+ __forceinline vllong8 operator |(const vllong8& a, long long b) { return a | vllong8(b); }
+ __forceinline vllong8 operator |(long long a, const vllong8& b) { return vllong8(a) | b; }
+
+ __forceinline vllong8 operator ^(const vllong8& a, const vllong8& b) { return _mm512_xor_epi64(a, b); }
+ __forceinline vllong8 operator ^(const vllong8& a, long long b) { return a ^ vllong8(b); }
+ __forceinline vllong8 operator ^(long long a, const vllong8& b) { return vllong8(a) ^ b; }
+
+ __forceinline vllong8 operator <<(const vllong8& a, long long n) { return _mm512_slli_epi64(a, n); }
+ __forceinline vllong8 operator >>(const vllong8& a, long long n) { return _mm512_srai_epi64(a, n); }
+
+ __forceinline vllong8 operator <<(const vllong8& a, const vllong8& n) { return _mm512_sllv_epi64(a, n); }
+ __forceinline vllong8 operator >>(const vllong8& a, const vllong8& n) { return _mm512_srav_epi64(a, n); }
+
+ __forceinline vllong8 sll (const vllong8& a, long long b) { return _mm512_slli_epi64(a, b); }
+ __forceinline vllong8 sra (const vllong8& a, long long b) { return _mm512_srai_epi64(a, b); }
+ __forceinline vllong8 srl (const vllong8& a, long long b) { return _mm512_srli_epi64(a, b); }
+
+ __forceinline vllong8 min(const vllong8& a, const vllong8& b) { return _mm512_min_epi64(a, b); }
+ __forceinline vllong8 min(const vllong8& a, long long b) { return min(a,vllong8(b)); }
+ __forceinline vllong8 min(long long a, const vllong8& b) { return min(vllong8(a),b); }
+
+ __forceinline vllong8 max(const vllong8& a, const vllong8& b) { return _mm512_max_epi64(a, b); }
+ __forceinline vllong8 max(const vllong8& a, long long b) { return max(a,vllong8(b)); }
+ __forceinline vllong8 max(long long a, const vllong8& b) { return max(vllong8(a),b); }
+
+ __forceinline vllong8 mask_add(const vboold8& m, const vllong8& c, const vllong8& a, const vllong8& b) { return _mm512_mask_add_epi64(c,m,a,b); }
+ __forceinline vllong8 mask_sub(const vboold8& m, const vllong8& c, const vllong8& a, const vllong8& b) { return _mm512_mask_sub_epi64(c,m,a,b); }
+
+ __forceinline vllong8 mask_and(const vboold8& m, const vllong8& c, const vllong8& a, const vllong8& b) { return _mm512_mask_and_epi64(c,m,a,b); }
+ __forceinline vllong8 mask_or (const vboold8& m, const vllong8& c, const vllong8& a, const vllong8& b) { return _mm512_mask_or_epi64(c,m,a,b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong8& operator +=(vllong8& a, const vllong8& b) { return a = a + b; }
+ __forceinline vllong8& operator +=(vllong8& a, long long b) { return a = a + b; }
+
+ __forceinline vllong8& operator -=(vllong8& a, const vllong8& b) { return a = a - b; }
+ __forceinline vllong8& operator -=(vllong8& a, long long b) { return a = a - b; }
+
+ __forceinline vllong8& operator *=(vllong8& a, const vllong8& b) { return a = a * b; }
+ __forceinline vllong8& operator *=(vllong8& a, long long b) { return a = a * b; }
+
+ __forceinline vllong8& operator &=(vllong8& a, const vllong8& b) { return a = a & b; }
+ __forceinline vllong8& operator &=(vllong8& a, long long b) { return a = a & b; }
+
+ __forceinline vllong8& operator |=(vllong8& a, const vllong8& b) { return a = a | b; }
+ __forceinline vllong8& operator |=(vllong8& a, long long b) { return a = a | b; }
+
+ __forceinline vllong8& operator <<=(vllong8& a, long long b) { return a = a << b; }
+ __forceinline vllong8& operator >>=(vllong8& a, long long b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboold8 operator ==(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 operator ==(const vllong8& a, long long b) { return a == vllong8(b); }
+ __forceinline vboold8 operator ==(long long a, const vllong8& b) { return vllong8(a) == b; }
+
+ __forceinline vboold8 operator !=(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 operator !=(const vllong8& a, long long b) { return a != vllong8(b); }
+ __forceinline vboold8 operator !=(long long a, const vllong8& b) { return vllong8(a) != b; }
+
+ __forceinline vboold8 operator < (const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 operator < (const vllong8& a, long long b) { return a < vllong8(b); }
+ __forceinline vboold8 operator < (long long a, const vllong8& b) { return vllong8(a) < b; }
+
+ __forceinline vboold8 operator >=(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 operator >=(const vllong8& a, long long b) { return a >= vllong8(b); }
+ __forceinline vboold8 operator >=(long long a, const vllong8& b) { return vllong8(a) >= b; }
+
+ __forceinline vboold8 operator > (const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 operator > (const vllong8& a, long long b) { return a > vllong8(b); }
+ __forceinline vboold8 operator > (long long a, const vllong8& b) { return vllong8(a) > b; }
+
+ __forceinline vboold8 operator <=(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboold8 operator <=(const vllong8& a, long long b) { return a <= vllong8(b); }
+ __forceinline vboold8 operator <=(long long a, const vllong8& b) { return vllong8(a) <= b; }
+
+ __forceinline vboold8 eq(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 ne(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 lt(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 ge(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 gt(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 le(const vllong8& a, const vllong8& b) { return _mm512_cmp_epi64_mask(a,b,_MM_CMPINT_LE); }
+
+ __forceinline vboold8 eq(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_EQ); }
+ __forceinline vboold8 ne(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_NE); }
+ __forceinline vboold8 lt(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_LT); }
+ __forceinline vboold8 ge(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_GE); }
+ __forceinline vboold8 gt(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_GT); }
+ __forceinline vboold8 le(const vboold8 mask, const vllong8& a, const vllong8& b) { return _mm512_mask_cmp_epi64_mask(mask,a,b,_MM_CMPINT_LE); }
+
+ __forceinline vllong8 select(const vboold8& m, const vllong8& t, const vllong8& f) {
+ return _mm512_mask_or_epi64(f,m,t,t);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int i0, int i1>
+ __forceinline vllong8 shuffle(const vllong8& v) {
+ return _mm512_castpd_si512(_mm512_permute_pd(_mm512_castsi512_pd(v), (i1 << 7) | (i0 << 6) | (i1 << 5) | (i0 << 4) | (i1 << 3) | (i0 << 2) | (i1 << 1) | i0));
+ }
+
+ template<int i>
+ __forceinline vllong8 shuffle(const vllong8& v) {
+ return shuffle<i, i>(v);
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vllong8 shuffle(const vllong8& v) {
+ return _mm512_permutex_epi64(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vllong8 shuffle4(const vllong8& v) {
+ return _mm512_shuffle_i64x2(v, v, _MM_SHUFFLE(i1*2+1, i1*2, i0*2+1, i0*2));
+ }
+
+ template<int i>
+ __forceinline vllong8 shuffle4(const vllong8& v) {
+ return shuffle4<i, i>(v);
+ }
+
+ template<int i>
+ __forceinline vllong8 align_shift_right(const vllong8& a, const vllong8& b) {
+ return _mm512_alignr_epi64(a, b, i);
+ };
+
+ __forceinline long long toScalar(const vllong8& v) {
+ return _mm_cvtsi128_si64(_mm512_castsi512_si128(v));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong8 vreduce_min2(vllong8 x) { return min(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vllong8 vreduce_min4(vllong8 x) { x = vreduce_min2(x); return min(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vllong8 vreduce_min (vllong8 x) { x = vreduce_min4(x); return min(x, shuffle4<1,0>(x)); }
+
+ __forceinline vllong8 vreduce_max2(vllong8 x) { return max(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vllong8 vreduce_max4(vllong8 x) { x = vreduce_max2(x); return max(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vllong8 vreduce_max (vllong8 x) { x = vreduce_max4(x); return max(x, shuffle4<1,0>(x)); }
+
+ __forceinline vllong8 vreduce_and2(vllong8 x) { return x & shuffle<1,0,3,2>(x); }
+ __forceinline vllong8 vreduce_and4(vllong8 x) { x = vreduce_and2(x); return x & shuffle<2,3,0,1>(x); }
+ __forceinline vllong8 vreduce_and (vllong8 x) { x = vreduce_and4(x); return x & shuffle4<1,0>(x); }
+
+ __forceinline vllong8 vreduce_or2(vllong8 x) { return x | shuffle<1,0,3,2>(x); }
+ __forceinline vllong8 vreduce_or4(vllong8 x) { x = vreduce_or2(x); return x | shuffle<2,3,0,1>(x); }
+ __forceinline vllong8 vreduce_or (vllong8 x) { x = vreduce_or4(x); return x | shuffle4<1,0>(x); }
+
+ __forceinline vllong8 vreduce_add2(vllong8 x) { return x + shuffle<1,0,3,2>(x); }
+ __forceinline vllong8 vreduce_add4(vllong8 x) { x = vreduce_add2(x); return x + shuffle<2,3,0,1>(x); }
+ __forceinline vllong8 vreduce_add (vllong8 x) { x = vreduce_add4(x); return x + shuffle4<1,0>(x); }
+
+ __forceinline long long reduce_min(const vllong8& v) { return toScalar(vreduce_min(v)); }
+ __forceinline long long reduce_max(const vllong8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline long long reduce_and(const vllong8& v) { return toScalar(vreduce_and(v)); }
+ __forceinline long long reduce_or (const vllong8& v) { return toScalar(vreduce_or (v)); }
+ __forceinline long long reduce_add(const vllong8& v) { return toScalar(vreduce_add(v)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vllong8 permute(const vllong8& v, const vllong8& index) {
+ return _mm512_permutexvar_epi64(index,v);
+ }
+
+ __forceinline vllong8 reverse(const vllong8& a) {
+ return permute(a,vllong8(reverse_step));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vllong8& v)
+ {
+ cout << "<" << v[0];
+ for (size_t i=1; i<8; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vuint16_avx512.h b/thirdparty/embree/common/simd/vuint16_avx512.h
new file mode 100644
index 0000000000..c9eb6682ff
--- /dev/null
+++ b/thirdparty/embree/common/simd/vuint16_avx512.h
@@ -0,0 +1,424 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 16-wide AVX-512 unsigned integer type */
+ template<>
+ struct vuint<16>
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef vboolf16 Bool;
+ typedef vuint16 UInt;
+ typedef vfloat16 Float;
+
+ enum { size = 16 }; // number of SIMD elements
+ union { // data
+ __m512i v;
+ unsigned int i[16];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint() {}
+ __forceinline vuint(const vuint16& t) { v = t.v; }
+ __forceinline vuint16& operator =(const vuint16& f) { v = f.v; return *this; }
+
+ __forceinline vuint(const __m512i& t) { v = t; }
+ __forceinline operator __m512i() const { return v; }
+ __forceinline operator __m256i() const { return _mm512_castsi512_si256(v); }
+
+ __forceinline vuint(unsigned int i) {
+ v = _mm512_set1_epi32(i);
+ }
+
+ __forceinline vuint(const vuint4& i) {
+ v = _mm512_broadcast_i32x4(i);
+ }
+
+ __forceinline vuint(const vuint8& i) {
+ v = _mm512_castps_si512(_mm512_castpd_ps(_mm512_broadcast_f64x4(_mm256_castsi256_pd(i))));
+ }
+
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d) {
+ v = _mm512_set4_epi32(d,c,b,a);
+ }
+
+ __forceinline vuint(unsigned int a0 , unsigned int a1 , unsigned int a2 , unsigned int a3,
+ unsigned int a4 , unsigned int a5 , unsigned int a6 , unsigned int a7,
+ unsigned int a8 , unsigned int a9 , unsigned int a10, unsigned int a11,
+ unsigned int a12, unsigned int a13, unsigned int a14, unsigned int a15)
+ {
+ v = _mm512_set_epi32(a15,a14,a13,a12,a11,a10,a9,a8,a7,a6,a5,a4,a3,a2,a1,a0);
+ }
+
+ __forceinline explicit vuint(const __m512& f) {
+ v = _mm512_cvtps_epu32(f);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint(ZeroTy) : v(_mm512_setzero_epi32()) {}
+ __forceinline vuint(OneTy) : v(_mm512_set1_epi32(1)) {}
+ __forceinline vuint(StepTy) : v(_mm512_set_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) {}
+ __forceinline vuint(ReverseStepTy) : v(_mm512_setr_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline void store_nt(void* __restrict__ ptr, const vuint16& a) {
+ _mm512_stream_si512((__m512i*)ptr,a);
+ }
+
+ static __forceinline vuint16 loadu(const void* addr)
+ {
+ return _mm512_loadu_si512(addr);
+ }
+
+ static __forceinline vuint16 loadu(const unsigned char* ptr) { return _mm512_cvtepu8_epi32(_mm_loadu_si128((__m128i*)ptr)); }
+ static __forceinline vuint16 loadu(const unsigned short* ptr) { return _mm512_cvtepu16_epi32(_mm256_loadu_si256((__m256i*)ptr)); }
+
+ static __forceinline vuint16 load(const vuint16* addr) {
+ return _mm512_load_si512(addr);
+ }
+
+ static __forceinline vuint16 load(const unsigned int* addr) {
+ return _mm512_load_si512(addr);
+ }
+
+ static __forceinline vuint16 load(unsigned short* ptr) { return _mm512_cvtepu16_epi32(*(__m256i*)ptr); }
+
+
+ static __forceinline void store(void* ptr, const vuint16& v) {
+ _mm512_store_si512(ptr,v);
+ }
+
+ static __forceinline void storeu(void* ptr, const vuint16& v) {
+ _mm512_storeu_si512(ptr,v);
+ }
+
+ static __forceinline void storeu(const vboolf16& mask, void* ptr, const vuint16& f) {
+ _mm512_mask_storeu_epi32(ptr,mask,f);
+ }
+
+ static __forceinline void store(const vboolf16& mask, void* addr, const vuint16& v2) {
+ _mm512_mask_store_epi32(addr,mask,v2);
+ }
+
+ static __forceinline vuint16 compact(const vboolf16& mask, vuint16& v) {
+ return _mm512_mask_compress_epi32(v,mask,v);
+ }
+
+ static __forceinline vuint16 compact(const vboolf16& mask, const vuint16& a, vuint16& b) {
+ return _mm512_mask_compress_epi32(a,mask,b);
+ }
+
+ static __forceinline vuint16 expand(const vboolf16& mask, const vuint16& a, vuint16& b) {
+ return _mm512_mask_expand_epi32(b,mask,a);
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint16 gather(const unsigned int* ptr, const vint16& index) {
+ return _mm512_i32gather_epi32(index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint16 gather(const vboolf16& mask, const unsigned int* ptr, const vint16& index) {
+ return _mm512_mask_i32gather_epi32(_mm512_undefined_epi32(),mask,index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint16 gather(const vboolf16& mask, vuint16& dest, const unsigned int* ptr, const vint16& index) {
+ return _mm512_mask_i32gather_epi32(dest,mask,index,ptr,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(unsigned int* ptr, const vint16& index, const vuint16& v) {
+ _mm512_i32scatter_epi32((int*)ptr,index,v,scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf16& mask, unsigned int* ptr, const vint16& index, const vuint16& v) {
+ _mm512_mask_i32scatter_epi32((int*)ptr,mask,index,v,scale);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline unsigned int& operator [](size_t index) { assert(index < 16); return i[index]; }
+ __forceinline const unsigned int& operator [](size_t index) const { assert(index < 16); return i[index]; }
+
+ __forceinline unsigned int uint (size_t index) const { assert(index < 16); return ((unsigned int*)i)[index]; }
+ __forceinline size_t& uint64_t(size_t index) const { assert(index < 8); return ((size_t*)i)[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 asBool(const vuint16& a) { return _mm512_movepi32_mask(a); }
+
+ __forceinline vuint16 operator +(const vuint16& a) { return a; }
+ __forceinline vuint16 operator -(const vuint16& a) { return _mm512_sub_epi32(_mm512_setzero_epi32(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint16 operator +(const vuint16& a, const vuint16& b) { return _mm512_add_epi32(a, b); }
+ __forceinline vuint16 operator +(const vuint16& a, unsigned int b) { return a + vuint16(b); }
+ __forceinline vuint16 operator +(unsigned int a, const vuint16& b) { return vuint16(a) + b; }
+
+ __forceinline vuint16 operator -(const vuint16& a, const vuint16& b) { return _mm512_sub_epi32(a, b); }
+ __forceinline vuint16 operator -(const vuint16& a, unsigned int b) { return a - vuint16(b); }
+ __forceinline vuint16 operator -(unsigned int a, const vuint16& b) { return vuint16(a) - b; }
+
+ __forceinline vuint16 operator *(const vuint16& a, const vuint16& b) { return _mm512_mul_epu32(a, b); }
+ __forceinline vuint16 operator *(const vuint16& a, unsigned int b) { return a * vuint16(b); }
+ __forceinline vuint16 operator *(unsigned int a, const vuint16& b) { return vuint16(a) * b; }
+
+ __forceinline vuint16 operator &(const vuint16& a, const vuint16& b) { return _mm512_and_epi32(a, b); }
+ __forceinline vuint16 operator &(const vuint16& a, unsigned int b) { return a & vuint16(b); }
+ __forceinline vuint16 operator &(unsigned int a, const vuint16& b) { return vuint16(a) & b; }
+
+ __forceinline vuint16 operator |(const vuint16& a, const vuint16& b) { return _mm512_or_epi32(a, b); }
+ __forceinline vuint16 operator |(const vuint16& a, unsigned int b) { return a | vuint16(b); }
+ __forceinline vuint16 operator |(unsigned int a, const vuint16& b) { return vuint16(a) | b; }
+
+ __forceinline vuint16 operator ^(const vuint16& a, const vuint16& b) { return _mm512_xor_epi32(a, b); }
+ __forceinline vuint16 operator ^(const vuint16& a, unsigned int b) { return a ^ vuint16(b); }
+ __forceinline vuint16 operator ^(unsigned int a, const vuint16& b) { return vuint16(a) ^ b; }
+
+ __forceinline vuint16 operator <<(const vuint16& a, unsigned int n) { return _mm512_slli_epi32(a, n); }
+ __forceinline vuint16 operator >>(const vuint16& a, unsigned int n) { return _mm512_srli_epi32(a, n); }
+
+ __forceinline vuint16 operator <<(const vuint16& a, const vuint16& n) { return _mm512_sllv_epi32(a, n); }
+ __forceinline vuint16 operator >>(const vuint16& a, const vuint16& n) { return _mm512_srlv_epi32(a, n); }
+
+ __forceinline vuint16 sll (const vuint16& a, unsigned int b) { return _mm512_slli_epi32(a, b); }
+ __forceinline vuint16 sra (const vuint16& a, unsigned int b) { return _mm512_srai_epi32(a, b); }
+ __forceinline vuint16 srl (const vuint16& a, unsigned int b) { return _mm512_srli_epi32(a, b); }
+
+ __forceinline vuint16 min(const vuint16& a, const vuint16& b) { return _mm512_min_epu32(a, b); }
+ __forceinline vuint16 min(const vuint16& a, unsigned int b) { return min(a,vuint16(b)); }
+ __forceinline vuint16 min(unsigned int a, const vuint16& b) { return min(vuint16(a),b); }
+
+ __forceinline vuint16 max(const vuint16& a, const vuint16& b) { return _mm512_max_epu32(a, b); }
+ __forceinline vuint16 max(const vuint16& a, unsigned int b) { return max(a,vuint16(b)); }
+ __forceinline vuint16 max(unsigned int a, const vuint16& b) { return max(vuint16(a),b); }
+
+ __forceinline vuint16 mask_add(const vboolf16& mask, vuint16& c, const vuint16& a, const vuint16& b) { return _mm512_mask_add_epi32(c,mask,a,b); }
+ __forceinline vuint16 mask_sub(const vboolf16& mask, vuint16& c, const vuint16& a, const vuint16& b) { return _mm512_mask_sub_epi32(c,mask,a,b); }
+
+ __forceinline vuint16 mask_and(const vboolf16& m, vuint16& c, const vuint16& a, const vuint16& b) { return _mm512_mask_and_epi32(c,m,a,b); }
+ __forceinline vuint16 mask_or (const vboolf16& m, vuint16& c, const vuint16& a, const vuint16& b) { return _mm512_mask_or_epi32(c,m,a,b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint16& operator +=(vuint16& a, const vuint16& b) { return a = a + b; }
+ __forceinline vuint16& operator +=(vuint16& a, unsigned int b) { return a = a + b; }
+
+ __forceinline vuint16& operator -=(vuint16& a, const vuint16& b) { return a = a - b; }
+ __forceinline vuint16& operator -=(vuint16& a, unsigned int b) { return a = a - b; }
+
+ __forceinline vuint16& operator *=(vuint16& a, const vuint16& b) { return a = a * b; }
+ __forceinline vuint16& operator *=(vuint16& a, unsigned int b) { return a = a * b; }
+
+ __forceinline vuint16& operator &=(vuint16& a, const vuint16& b) { return a = a & b; }
+ __forceinline vuint16& operator &=(vuint16& a, unsigned int b) { return a = a & b; }
+
+ __forceinline vuint16& operator |=(vuint16& a, const vuint16& b) { return a = a | b; }
+ __forceinline vuint16& operator |=(vuint16& a, unsigned int b) { return a = a | b; }
+
+ __forceinline vuint16& operator <<=(vuint16& a, unsigned int b) { return a = a << b; }
+ __forceinline vuint16& operator >>=(vuint16& a, unsigned int b) { return a = a >> b; }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf16 operator ==(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 operator ==(const vuint16& a, unsigned int b) { return a == vuint16(b); }
+ __forceinline vboolf16 operator ==(unsigned int a, const vuint16& b) { return vuint16(a) == b; }
+
+ __forceinline vboolf16 operator !=(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 operator !=(const vuint16& a, unsigned int b) { return a != vuint16(b); }
+ __forceinline vboolf16 operator !=(unsigned int a, const vuint16& b) { return vuint16(a) != b; }
+
+ __forceinline vboolf16 operator < (const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 operator < (const vuint16& a, unsigned int b) { return a < vuint16(b); }
+ __forceinline vboolf16 operator < (unsigned int a, const vuint16& b) { return vuint16(a) < b; }
+
+ __forceinline vboolf16 operator >=(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 operator >=(const vuint16& a, unsigned int b) { return a >= vuint16(b); }
+ __forceinline vboolf16 operator >=(unsigned int a, const vuint16& b) { return vuint16(a) >= b; }
+
+ __forceinline vboolf16 operator > (const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 operator > (const vuint16& a, unsigned int b) { return a > vuint16(b); }
+ __forceinline vboolf16 operator > (unsigned int a, const vuint16& b) { return vuint16(a) > b; }
+
+ __forceinline vboolf16 operator <=(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_LE); }
+ __forceinline vboolf16 operator <=(const vuint16& a, unsigned int b) { return a <= vuint16(b); }
+ __forceinline vboolf16 operator <=(unsigned int a, const vuint16& b) { return vuint16(a) <= b; }
+
+ __forceinline vboolf16 eq(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vuint16& a, const vuint16& b) { return _mm512_cmp_epu32_mask(a,b,_MM_CMPINT_LE); }
+
+ __forceinline vboolf16 eq(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf16 ne(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf16 lt(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf16 ge(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf16 gt(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf16 le(const vboolf16 mask, const vuint16& a, const vuint16& b) { return _mm512_mask_cmp_epu32_mask(mask,a,b,_MM_CMPINT_LE); }
+
+
+ __forceinline vuint16 select(const vboolf16& m, const vuint16& t, const vuint16& f) {
+ return _mm512_mask_or_epi32(f,m,t,t);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int i>
+ __forceinline vuint16 shuffle(const vuint16& v) {
+ return _mm512_castps_si512(_mm512_permute_ps(_mm512_castsi512_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint16 shuffle(const vuint16& v) {
+ return _mm512_castps_si512(_mm512_permute_ps(_mm512_castsi512_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i>
+ __forceinline vuint16 shuffle4(const vuint16& v) {
+ return _mm512_castps_si512(_mm512_shuffle_f32x4(_mm512_castsi512_ps(v), _mm512_castsi512_ps(v) ,_MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint16 shuffle4(const vuint16& v) {
+ return _mm512_castps_si512(_mm512_shuffle_f32x4(_mm512_castsi512_ps(v), _mm512_castsi512_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i>
+ __forceinline vuint16 align_shift_right(const vuint16& a, const vuint16& b) {
+ return _mm512_alignr_epi32(a, b, i);
+ };
+
+ __forceinline unsigned int toScalar(const vuint16& v) {
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(v));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint16 vreduce_min2(vuint16 x) { return min(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vuint16 vreduce_min4(vuint16 x) { x = vreduce_min2(x); return min(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vuint16 vreduce_min8(vuint16 x) { x = vreduce_min4(x); return min(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vuint16 vreduce_min (vuint16 x) { x = vreduce_min8(x); return min(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline vuint16 vreduce_max2(vuint16 x) { return max(x, shuffle<1,0,3,2>(x)); }
+ __forceinline vuint16 vreduce_max4(vuint16 x) { x = vreduce_max2(x); return max(x, shuffle<2,3,0,1>(x)); }
+ __forceinline vuint16 vreduce_max8(vuint16 x) { x = vreduce_max4(x); return max(x, shuffle4<1,0,3,2>(x)); }
+ __forceinline vuint16 vreduce_max (vuint16 x) { x = vreduce_max8(x); return max(x, shuffle4<2,3,0,1>(x)); }
+
+ __forceinline vuint16 vreduce_and2(vuint16 x) { return x & shuffle<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_and4(vuint16 x) { x = vreduce_and2(x); return x & shuffle<2,3,0,1>(x); }
+ __forceinline vuint16 vreduce_and8(vuint16 x) { x = vreduce_and4(x); return x & shuffle4<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_and (vuint16 x) { x = vreduce_and8(x); return x & shuffle4<2,3,0,1>(x); }
+
+ __forceinline vuint16 vreduce_or2(vuint16 x) { return x | shuffle<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_or4(vuint16 x) { x = vreduce_or2(x); return x | shuffle<2,3,0,1>(x); }
+ __forceinline vuint16 vreduce_or8(vuint16 x) { x = vreduce_or4(x); return x | shuffle4<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_or (vuint16 x) { x = vreduce_or8(x); return x | shuffle4<2,3,0,1>(x); }
+
+ __forceinline vuint16 vreduce_add2(vuint16 x) { return x + shuffle<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_add4(vuint16 x) { x = vreduce_add2(x); return x + shuffle<2,3,0,1>(x); }
+ __forceinline vuint16 vreduce_add8(vuint16 x) { x = vreduce_add4(x); return x + shuffle4<1,0,3,2>(x); }
+ __forceinline vuint16 vreduce_add (vuint16 x) { x = vreduce_add8(x); return x + shuffle4<2,3,0,1>(x); }
+
+ __forceinline unsigned int reduce_min(const vuint16& v) { return toScalar(vreduce_min(v)); }
+ __forceinline unsigned int reduce_max(const vuint16& v) { return toScalar(vreduce_max(v)); }
+ __forceinline unsigned int reduce_and(const vuint16& v) { return toScalar(vreduce_and(v)); }
+ __forceinline unsigned int reduce_or (const vuint16& v) { return toScalar(vreduce_or (v)); }
+ __forceinline unsigned int reduce_add(const vuint16& v) { return toScalar(vreduce_add(v)); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Memory load and store operations
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint16 permute(vuint16 v, vuint16 index) {
+ return _mm512_permutexvar_epi32(index,v);
+ }
+
+ __forceinline vuint16 reverse(const vuint16& a) {
+ return permute(a,vuint16(reverse_step));
+ }
+
+ __forceinline vuint16 prefix_sum(const vuint16& a)
+ {
+ const vuint16 z(zero);
+ vuint16 v = a;
+ v = v + align_shift_right<16-1>(v,z);
+ v = v + align_shift_right<16-2>(v,z);
+ v = v + align_shift_right<16-4>(v,z);
+ v = v + align_shift_right<16-8>(v,z);
+ return v;
+ }
+
+ __forceinline vuint16 reverse_prefix_sum(const vuint16& a)
+ {
+ const vuint16 z(zero);
+ vuint16 v = a;
+ v = v + align_shift_right<1>(z,v);
+ v = v + align_shift_right<2>(z,v);
+ v = v + align_shift_right<4>(z,v);
+ v = v + align_shift_right<8>(z,v);
+ return v;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vuint16& v)
+ {
+ cout << "<" << v[0];
+ for (int i=1; i<16; i++) cout << ", " << v[i];
+ cout << ">";
+ return cout;
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vuint4_sse2.h b/thirdparty/embree/common/simd/vuint4_sse2.h
new file mode 100644
index 0000000000..0601b9ab80
--- /dev/null
+++ b/thirdparty/embree/common/simd/vuint4_sse2.h
@@ -0,0 +1,426 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../math/math.h"
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 4-wide SSE integer type */
+ template<>
+ struct vuint<4>
+ {
+ ALIGNED_STRUCT_(16);
+
+ typedef vboolf4 Bool;
+ typedef vuint4 Int;
+ typedef vfloat4 Float;
+
+ enum { size = 4 }; // number of SIMD elements
+ union { __m128i v; unsigned int i[4]; }; // data
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint() {}
+ __forceinline vuint(const vuint4& a) { v = a.v; }
+ __forceinline vuint4& operator =(const vuint4& a) { v = a.v; return *this; }
+
+ __forceinline vuint(const __m128i a) : v(a) {}
+ __forceinline operator const __m128i&() const { return v; }
+ __forceinline operator __m128i&() { return v; }
+
+
+ __forceinline vuint(unsigned int a) : v(_mm_set1_epi32(a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d) : v(_mm_set_epi32(d, c, b, a)) {}
+
+#if defined(__AVX512VL__)
+ __forceinline explicit vuint(__m128 a) : v(_mm_cvtps_epu32(a)) {}
+#endif
+
+#if defined(__AVX512VL__)
+ __forceinline explicit vuint(const vboolf4& a) : v(_mm_movm_epi32(a)) {}
+#else
+ __forceinline explicit vuint(const vboolf4& a) : v(_mm_castps_si128((__m128)a)) {}
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint(ZeroTy) : v(_mm_setzero_si128()) {}
+ __forceinline vuint(OneTy) : v(_mm_set1_epi32(1)) {}
+ __forceinline vuint(PosInfTy) : v(_mm_set1_epi32(unsigned(pos_inf))) {}
+ __forceinline vuint(StepTy) : v(_mm_set_epi32(3, 2, 1, 0)) {}
+ __forceinline vuint(TrueTy) { v = _mm_cmpeq_epi32(v,v); }
+ __forceinline vuint(UndefinedTy) : v(_mm_castps_si128(_mm_undefined_ps())) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vuint4 load (const void* a) { return _mm_load_si128((__m128i*)a); }
+ static __forceinline vuint4 loadu(const void* a) { return _mm_loadu_si128((__m128i*)a); }
+
+ static __forceinline void store (void* ptr, const vuint4& v) { _mm_store_si128((__m128i*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vuint4& v) { _mm_storeu_si128((__m128i*)ptr,v); }
+
+#if defined(__AVX512VL__)
+ static __forceinline vuint4 load (const vboolf4& mask, const void* ptr) { return _mm_mask_load_epi32 (_mm_setzero_si128(),mask,ptr); }
+ static __forceinline vuint4 loadu(const vboolf4& mask, const void* ptr) { return _mm_mask_loadu_epi32(_mm_setzero_si128(),mask,ptr); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vuint4& v) { _mm_mask_store_epi32 (ptr,mask,v); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vuint4& v) { _mm_mask_storeu_epi32(ptr,mask,v); }
+#elif defined(__AVX__)
+ static __forceinline vuint4 load (const vbool4& mask, const void* a) { return _mm_castps_si128(_mm_maskload_ps((float*)a,mask)); }
+ static __forceinline vuint4 loadu(const vbool4& mask, const void* a) { return _mm_castps_si128(_mm_maskload_ps((float*)a,mask)); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vuint4& i) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,_mm_castsi128_ps(i)); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vuint4& i) { _mm_maskstore_ps((float*)ptr,(__m128i)mask,_mm_castsi128_ps(i)); }
+#else
+ static __forceinline vuint4 load (const vbool4& mask, const void* a) { return _mm_and_si128(_mm_load_si128 ((__m128i*)a),mask); }
+ static __forceinline vuint4 loadu(const vbool4& mask, const void* a) { return _mm_and_si128(_mm_loadu_si128((__m128i*)a),mask); }
+
+ static __forceinline void store (const vboolf4& mask, void* ptr, const vuint4& i) { store (ptr,select(mask,i,load (ptr))); }
+ static __forceinline void storeu(const vboolf4& mask, void* ptr, const vuint4& i) { storeu(ptr,select(mask,i,loadu(ptr))); }
+#endif
+
+#if defined(__SSE4_1__)
+ static __forceinline vuint4 load(const unsigned char* ptr) {
+ return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
+ }
+
+ static __forceinline vuint4 loadu(const unsigned char* ptr) {
+ return _mm_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr));
+ }
+
+#endif
+
+ static __forceinline vuint4 load(const unsigned short* ptr) {
+#if defined (__SSE4_1__)
+ return _mm_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr));
+#else
+ return vuint4(ptr[0],ptr[1],ptr[2],ptr[3]);
+#endif
+ }
+
+ static __forceinline vuint4 load_nt(void* ptr) {
+#if defined(__SSE4_1__)
+ return _mm_stream_load_si128((__m128i*)ptr);
+#else
+ return _mm_load_si128((__m128i*)ptr);
+#endif
+ }
+
+ static __forceinline void store_nt(void* ptr, const vuint4& v) {
+#if defined(__SSE4_1__)
+ _mm_stream_ps((float*)ptr,_mm_castsi128_ps(v));
+#else
+ _mm_store_si128((__m128i*)ptr,v);
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint4 gather(const unsigned int* ptr, const vint4& index) {
+#if defined(__AVX2__)
+ return _mm_i32gather_epi32((const int*)ptr, index, scale);
+#else
+ return vuint4(
+ *(unsigned int*)(((char*)ptr)+scale*index[0]),
+ *(unsigned int*)(((char*)ptr)+scale*index[1]),
+ *(unsigned int*)(((char*)ptr)+scale*index[2]),
+ *(unsigned int*)(((char*)ptr)+scale*index[3]));
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint4 gather(const vboolf4& mask, const unsigned int* ptr, const vint4& index) {
+ vuint4 r = zero;
+#if defined(__AVX512VL__)
+ return _mm_mmask_i32gather_epi32(r, mask, index, ptr, scale);
+#elif defined(__AVX2__)
+ return _mm_mask_i32gather_epi32(r, (const int*)ptr, index, mask, scale);
+#else
+ if (likely(mask[0])) r[0] = *(unsigned int*)(((char*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(unsigned int*)(((char*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(unsigned int*)(((char*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(unsigned int*)(((char*)ptr)+scale*index[3]);
+ return r;
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const unsigned int& operator [](size_t index) const { assert(index < 4); return i[index]; }
+ __forceinline unsigned int& operator [](size_t index) { assert(index < 4); return i[index]; }
+
+ friend __forceinline vuint4 select(const vboolf4& m, const vuint4& t, const vuint4& f) {
+#if defined(__AVX512VL__)
+ return _mm_mask_blend_epi32(m, (__m128i)f, (__m128i)t);
+#elif defined(__SSE4_1__)
+ return _mm_castps_si128(_mm_blendv_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), m));
+#else
+ return _mm_or_si128(_mm_and_si128(m, t), _mm_andnot_si128(m, f));
+#endif
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 asBool(const vuint4& a) { return _mm_movepi32_mask(a); }
+#else
+ __forceinline vboolf4 asBool(const vuint4& a) { return _mm_castsi128_ps(a); }
+#endif
+
+ __forceinline vuint4 operator +(const vuint4& a) { return a; }
+ __forceinline vuint4 operator -(const vuint4& a) { return _mm_sub_epi32(_mm_setzero_si128(), a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint4 operator +(const vuint4& a, const vuint4& b) { return _mm_add_epi32(a, b); }
+ __forceinline vuint4 operator +(const vuint4& a, unsigned int b) { return a + vuint4(b); }
+ __forceinline vuint4 operator +(unsigned int a, const vuint4& b) { return vuint4(a) + b; }
+
+ __forceinline vuint4 operator -(const vuint4& a, const vuint4& b) { return _mm_sub_epi32(a, b); }
+ __forceinline vuint4 operator -(const vuint4& a, unsigned int b) { return a - vuint4(b); }
+ __forceinline vuint4 operator -(unsigned int a, const vuint4& b) { return vuint4(a) - b; }
+
+//#if defined(__SSE4_1__)
+// __forceinline vuint4 operator *(const vuint4& a, const vuint4& b) { return _mm_mullo_epu32(a, b); }
+//#else
+// __forceinline vuint4 operator *(const vuint4& a, const vuint4& b) { return vuint4(a[0]*b[0],a[1]*b[1],a[2]*b[2],a[3]*b[3]); }
+//#endif
+// __forceinline vuint4 operator *(const vuint4& a, unsigned int b) { return a * vuint4(b); }
+// __forceinline vuint4 operator *(unsigned int a, const vuint4& b) { return vuint4(a) * b; }
+
+ __forceinline vuint4 operator &(const vuint4& a, const vuint4& b) { return _mm_and_si128(a, b); }
+ __forceinline vuint4 operator &(const vuint4& a, unsigned int b) { return a & vuint4(b); }
+ __forceinline vuint4 operator &(unsigned int a, const vuint4& b) { return vuint4(a) & b; }
+
+ __forceinline vuint4 operator |(const vuint4& a, const vuint4& b) { return _mm_or_si128(a, b); }
+ __forceinline vuint4 operator |(const vuint4& a, unsigned int b) { return a | vuint4(b); }
+ __forceinline vuint4 operator |(unsigned int a, const vuint4& b) { return vuint4(a) | b; }
+
+ __forceinline vuint4 operator ^(const vuint4& a, const vuint4& b) { return _mm_xor_si128(a, b); }
+ __forceinline vuint4 operator ^(const vuint4& a, unsigned int b) { return a ^ vuint4(b); }
+ __forceinline vuint4 operator ^(unsigned int a, const vuint4& b) { return vuint4(a) ^ b; }
+
+ __forceinline vuint4 operator <<(const vuint4& a, unsigned int n) { return _mm_slli_epi32(a, n); }
+ __forceinline vuint4 operator >>(const vuint4& a, unsigned int n) { return _mm_srli_epi32(a, n); }
+
+ __forceinline vuint4 sll (const vuint4& a, unsigned int b) { return _mm_slli_epi32(a, b); }
+ __forceinline vuint4 sra (const vuint4& a, unsigned int b) { return _mm_srai_epi32(a, b); }
+ __forceinline vuint4 srl (const vuint4& a, unsigned int b) { return _mm_srli_epi32(a, b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint4& operator +=(vuint4& a, const vuint4& b) { return a = a + b; }
+ __forceinline vuint4& operator +=(vuint4& a, unsigned int b) { return a = a + b; }
+
+ __forceinline vuint4& operator -=(vuint4& a, const vuint4& b) { return a = a - b; }
+ __forceinline vuint4& operator -=(vuint4& a, unsigned int b) { return a = a - b; }
+
+//#if defined(__SSE4_1__)
+// __forceinline vuint4& operator *=(vuint4& a, const vuint4& b) { return a = a * b; }
+// __forceinline vuint4& operator *=(vuint4& a, unsigned int b) { return a = a * b; }
+//#endif
+
+ __forceinline vuint4& operator &=(vuint4& a, const vuint4& b) { return a = a & b; }
+ __forceinline vuint4& operator &=(vuint4& a, unsigned int b) { return a = a & b; }
+
+ __forceinline vuint4& operator |=(vuint4& a, const vuint4& b) { return a = a | b; }
+ __forceinline vuint4& operator |=(vuint4& a, unsigned int b) { return a = a | b; }
+
+ __forceinline vuint4& operator <<=(vuint4& a, unsigned int b) { return a = a << b; }
+ __forceinline vuint4& operator >>=(vuint4& a, unsigned int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 operator ==(const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf4 operator !=(const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_NE); }
+ //__forceinline vboolf4 operator < (const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_LT); }
+ //__forceinline vboolf4 operator >=(const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_GE); }
+ //__forceinline vboolf4 operator > (const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_GT); }
+ //__forceinline vboolf4 operator <=(const vuint4& a, const vuint4& b) { return _mm_cmp_epu32_mask(a,b,_MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 operator ==(const vuint4& a, const vuint4& b) { return _mm_castsi128_ps(_mm_cmpeq_epi32(a, b)); }
+ __forceinline vboolf4 operator !=(const vuint4& a, const vuint4& b) { return !(a == b); }
+ //__forceinline vboolf4 operator < (const vuint4& a, const vuint4& b) { return _mm_castsi128_ps(_mm_cmplt_epu32(a, b)); }
+ //__forceinline vboolf4 operator >=(const vuint4& a, const vuint4& b) { return !(a < b); }
+ //__forceinline vboolf4 operator > (const vuint4& a, const vuint4& b) { return _mm_castsi128_ps(_mm_cmpgt_epu32(a, b)); }
+ //__forceinline vboolf4 operator <=(const vuint4& a, const vuint4& b) { return !(a > b); }
+#endif
+
+ __forceinline vboolf4 operator ==(const vuint4& a, unsigned int b) { return a == vuint4(b); }
+ __forceinline vboolf4 operator ==(unsigned int a, const vuint4& b) { return vuint4(a) == b; }
+
+ __forceinline vboolf4 operator !=(const vuint4& a, unsigned int b) { return a != vuint4(b); }
+ __forceinline vboolf4 operator !=(unsigned int a, const vuint4& b) { return vuint4(a) != b; }
+
+ //__forceinline vboolf4 operator < (const vuint4& a, unsigned int b) { return a < vuint4(b); }
+ //__forceinline vboolf4 operator < (unsigned int a, const vuint4& b) { return vuint4(a) < b; }
+
+ //__forceinline vboolf4 operator >=(const vuint4& a, unsigned int b) { return a >= vuint4(b); }
+ //__forceinline vboolf4 operator >=(unsigned int a, const vuint4& b) { return vuint4(a) >= b; }
+
+ //__forceinline vboolf4 operator > (const vuint4& a, unsigned int b) { return a > vuint4(b); }
+ //__forceinline vboolf4 operator > (unsigned int a, const vuint4& b) { return vuint4(a) > b; }
+
+ //__forceinline vboolf4 operator <=(const vuint4& a, unsigned int b) { return a <= vuint4(b); }
+ //__forceinline vboolf4 operator <=(unsigned int a, const vuint4& b) { return vuint4(a) <= b; }
+
+ __forceinline vboolf4 eq(const vuint4& a, const vuint4& b) { return a == b; }
+ __forceinline vboolf4 ne(const vuint4& a, const vuint4& b) { return a != b; }
+ //__forceinline vboolf4 lt(const vuint4& a, const vuint4& b) { return a < b; }
+ //__forceinline vboolf4 ge(const vuint4& a, const vuint4& b) { return a >= b; }
+ //__forceinline vboolf4 gt(const vuint4& a, const vuint4& b) { return a > b; }
+ //__forceinline vboolf4 le(const vuint4& a, const vuint4& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf4 eq(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_NE); }
+ //__forceinline vboolf4 lt(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LT); }
+ //__forceinline vboolf4 ge(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_GE); }
+ //__forceinline vboolf4 gt(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_GT); }
+ //__forceinline vboolf4 le(const vboolf4& mask, const vuint4& a, const vuint4& b) { return _mm_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboolf4 eq(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a == b); }
+ __forceinline vboolf4 ne(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a != b); }
+ //__forceinline vboolf4 lt(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a < b); }
+ //__forceinline vboolf4 ge(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a >= b); }
+ //__forceinline vboolf4 gt(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a > b); }
+ //__forceinline vboolf4 le(const vboolf4& mask, const vuint4& a, const vuint4& b) { return mask & (a <= b); }
+#endif
+
+ template<int mask>
+ __forceinline vuint4 select(const vuint4& t, const vuint4& f) {
+#if defined(__SSE4_1__)
+ return _mm_castps_si128(_mm_blend_ps(_mm_castsi128_ps(f), _mm_castsi128_ps(t), mask));
+#else
+ return select(vboolf4(mask), t, f);
+#endif
+ }
+
+/*#if defined(__SSE4_1__)
+ __forceinline vuint4 min(const vuint4& a, const vuint4& b) { return _mm_min_epu32(a, b); }
+ __forceinline vuint4 max(const vuint4& a, const vuint4& b) { return _mm_max_epu32(a, b); }
+
+#else
+ __forceinline vuint4 min(const vuint4& a, const vuint4& b) { return select(a < b,a,b); }
+ __forceinline vuint4 max(const vuint4& a, const vuint4& b) { return select(a < b,b,a); }
+#endif
+
+ __forceinline vuint4 min(const vuint4& a, unsigned int b) { return min(a,vuint4(b)); }
+ __forceinline vuint4 min(unsigned int a, const vuint4& b) { return min(vuint4(a),b); }
+ __forceinline vuint4 max(const vuint4& a, unsigned int b) { return max(a,vuint4(b)); }
+ __forceinline vuint4 max(unsigned int a, const vuint4& b) { return max(vuint4(a),b); }*/
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint4 unpacklo(const vuint4& a, const vuint4& b) { return _mm_castps_si128(_mm_unpacklo_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
+ __forceinline vuint4 unpackhi(const vuint4& a, const vuint4& b) { return _mm_castps_si128(_mm_unpackhi_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b))); }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint4 shuffle(const vuint4& v) {
+ return _mm_shuffle_epi32(v, _MM_SHUFFLE(i3, i2, i1, i0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint4 shuffle(const vuint4& a, const vuint4& b) {
+ return _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+#if defined(__SSE3__)
+ template<> __forceinline vuint4 shuffle<0, 0, 2, 2>(const vuint4& v) { return _mm_castps_si128(_mm_moveldup_ps(_mm_castsi128_ps(v))); }
+ template<> __forceinline vuint4 shuffle<1, 1, 3, 3>(const vuint4& v) { return _mm_castps_si128(_mm_movehdup_ps(_mm_castsi128_ps(v))); }
+ template<> __forceinline vuint4 shuffle<0, 1, 0, 1>(const vuint4& v) { return _mm_castpd_si128(_mm_movedup_pd (_mm_castsi128_pd(v))); }
+#endif
+
+ template<int i>
+ __forceinline vuint4 shuffle(const vuint4& v) {
+ return shuffle<i,i,i,i>(v);
+ }
+
+#if defined(__SSE4_1__)
+ template<int src> __forceinline unsigned int extract(const vuint4& b) { return _mm_extract_epi32(b, src); }
+ template<int dst> __forceinline vuint4 insert(const vuint4& a, const unsigned b) { return _mm_insert_epi32(a, b, dst); }
+#else
+ template<int src> __forceinline unsigned int extract(const vuint4& b) { return b[src&3]; }
+ template<int dst> __forceinline vuint4 insert(const vuint4& a, const unsigned b) { vuint4 c = a; c[dst&3] = b; return c; }
+#endif
+
+
+ template<> __forceinline unsigned int extract<0>(const vuint4& b) { return _mm_cvtsi128_si32(b); }
+
+ __forceinline unsigned int toScalar(const vuint4& v) { return _mm_cvtsi128_si32(v); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if 0
+#if defined(__SSE4_1__)
+
+ __forceinline vuint4 vreduce_min(const vuint4& v) { vuint4 h = min(shuffle<1,0,3,2>(v),v); return min(shuffle<2,3,0,1>(h),h); }
+ __forceinline vuint4 vreduce_max(const vuint4& v) { vuint4 h = max(shuffle<1,0,3,2>(v),v); return max(shuffle<2,3,0,1>(h),h); }
+ __forceinline vuint4 vreduce_add(const vuint4& v) { vuint4 h = shuffle<1,0,3,2>(v) + v ; return shuffle<2,3,0,1>(h) + h ; }
+
+ __forceinline unsigned int reduce_min(const vuint4& v) { return toScalar(vreduce_min(v)); }
+ __forceinline unsigned int reduce_max(const vuint4& v) { return toScalar(vreduce_max(v)); }
+ __forceinline unsigned int reduce_add(const vuint4& v) { return toScalar(vreduce_add(v)); }
+
+ __forceinline size_t select_min(const vuint4& v) { return bsf(movemask(v == vreduce_min(v))); }
+ __forceinline size_t select_max(const vuint4& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ //__forceinline size_t select_min(const vboolf4& valid, const vuint4& v) { const vuint4 a = select(valid,v,vuint4(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ //__forceinline size_t select_max(const vboolf4& valid, const vuint4& v) { const vuint4 a = select(valid,v,vuint4(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+#else
+
+ __forceinline unsigned int reduce_min(const vuint4& v) { return min(v[0],v[1],v[2],v[3]); }
+ __forceinline unsigned int reduce_max(const vuint4& v) { return max(v[0],v[1],v[2],v[3]); }
+ __forceinline unsigned int reduce_add(const vuint4& v) { return v[0]+v[1]+v[2]+v[3]; }
+
+#endif
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vuint4& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vuint8_avx.h b/thirdparty/embree/common/simd/vuint8_avx.h
new file mode 100644
index 0000000000..589cd9d731
--- /dev/null
+++ b/thirdparty/embree/common/simd/vuint8_avx.h
@@ -0,0 +1,386 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 8-wide AVX integer type */
+ template<>
+ struct vuint<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vuint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m256i v;
+ struct { __m128i vl,vh; };
+ unsigned int i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint() {}
+ __forceinline vuint(const vuint8& a) { v = a.v; }
+ __forceinline vuint8& operator =(const vuint8& a) { v = a.v; return *this; }
+
+ __forceinline vuint(__m256i a) : v(a) {}
+ __forceinline operator const __m256i&() const { return v; }
+ __forceinline operator __m256i&() { return v; }
+
+ __forceinline explicit vuint(const vuint4& a) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),a,1)) {}
+ __forceinline vuint(const vuint4& a, const vuint4& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+ __forceinline vuint(const __m128i& a, const __m128i& b) : vl(a), vh(b) {}
+
+ __forceinline explicit vuint(const unsigned int* a) : v(_mm256_castps_si256(_mm256_loadu_ps((const float*)a))) {}
+ __forceinline vuint(unsigned int a) : v(_mm256_set1_epi32(a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b) : v(_mm256_set_epi32(b, a, b, a, b, a, b, a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d) : v(_mm256_set_epi32(d, c, b, a, d, c, b, a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e, unsigned int f, unsigned int g, unsigned int vh) : v(_mm256_set_epi32(vh, g, f, e, d, c, b, a)) {}
+
+ __forceinline explicit vuint(__m256 a) : v(_mm256_cvtps_epi32(a)) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint(ZeroTy) : v(_mm256_setzero_si256()) {}
+ __forceinline vuint(OneTy) : v(_mm256_set1_epi32(1)) {}
+ __forceinline vuint(PosInfTy) : v(_mm256_set1_epi32(0xFFFFFFFF)) {}
+ __forceinline vuint(StepTy) : v(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0)) {}
+ __forceinline vuint(UndefinedTy) : v(_mm256_undefined_si256()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vuint8 load (const void* a) { return _mm256_castps_si256(_mm256_load_ps((float*)a)); }
+ static __forceinline vuint8 loadu(const void* a) { return _mm256_castps_si256(_mm256_loadu_ps((float*)a)); }
+
+ static __forceinline vuint8 load (const vboolf8& mask, const void* a) { return _mm256_castps_si256(_mm256_maskload_ps((float*)a,mask)); }
+ static __forceinline vuint8 loadu(const vboolf8& mask, const void* a) { return _mm256_castps_si256(_mm256_maskload_ps((float*)a,mask)); }
+
+ static __forceinline void store (void* ptr, const vuint8& f) { _mm256_store_ps((float*)ptr,_mm256_castsi256_ps(f)); }
+ static __forceinline void storeu(void* ptr, const vuint8& f) { _mm256_storeu_ps((float*)ptr,_mm256_castsi256_ps(f)); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vuint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vuint8& f) { _mm256_maskstore_ps((float*)ptr,(__m256i)mask,_mm256_castsi256_ps(f)); }
+
+ static __forceinline void store_nt(void* ptr, const vuint8& v) {
+ _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
+ }
+
+ static __forceinline vuint8 load(const unsigned char* ptr) {
+ vuint4 il = vuint4::load(ptr+0);
+ vuint4 ih = vuint4::load(ptr+4);
+ return vuint8(il,ih);
+ }
+
+ static __forceinline vuint8 loadu(const unsigned char* ptr) {
+ vuint4 il = vuint4::loadu(ptr+0);
+ vuint4 ih = vuint4::loadu(ptr+4);
+ return vuint8(il,ih);
+ }
+
+ static __forceinline vuint8 load(const unsigned short* ptr) {
+ vuint4 il = vuint4::load(ptr+0);
+ vuint4 ih = vuint4::load(ptr+4);
+ return vuint8(il,ih);
+ }
+
+ static __forceinline vuint8 loadu(const unsigned short* ptr) {
+ vuint4 il = vuint4::loadu(ptr+0);
+ vuint4 ih = vuint4::loadu(ptr+4);
+ return vuint8(il,ih);
+ }
+
+ static __forceinline void store(unsigned char* ptr, const vuint8& i) {
+ vuint4 il(i.vl);
+ vuint4 ih(i.vh);
+ vuint4::store(ptr + 0,il);
+ vuint4::store(ptr + 4,ih);
+ }
+
+ static __forceinline void store(unsigned short* ptr, const vuint8& v) {
+ for (size_t i=0;i<8;i++)
+ ptr[i] = (unsigned short)v[i];
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint8 gather(const unsigned int* ptr, const vint8& index) {
+ return vuint8(
+ *(unsigned int*)(((char*)ptr)+scale*index[0]),
+ *(unsigned int*)(((char*)ptr)+scale*index[1]),
+ *(unsigned int*)(((char*)ptr)+scale*index[2]),
+ *(unsigned int*)(((char*)ptr)+scale*index[3]),
+ *(unsigned int*)(((char*)ptr)+scale*index[4]),
+ *(unsigned int*)(((char*)ptr)+scale*index[5]),
+ *(unsigned int*)(((char*)ptr)+scale*index[6]),
+ *(unsigned int*)(((char*)ptr)+scale*index[7]));
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint8 gather(const vboolf8& mask, const unsigned int* ptr, const vint8& index) {
+ vuint8 r = zero;
+ if (likely(mask[0])) r[0] = *(unsigned int*)(((char*)ptr)+scale*index[0]);
+ if (likely(mask[1])) r[1] = *(unsigned int*)(((char*)ptr)+scale*index[1]);
+ if (likely(mask[2])) r[2] = *(unsigned int*)(((char*)ptr)+scale*index[2]);
+ if (likely(mask[3])) r[3] = *(unsigned int*)(((char*)ptr)+scale*index[3]);
+ if (likely(mask[4])) r[4] = *(unsigned int*)(((char*)ptr)+scale*index[4]);
+ if (likely(mask[5])) r[5] = *(unsigned int*)(((char*)ptr)+scale*index[5]);
+ if (likely(mask[6])) r[6] = *(unsigned int*)(((char*)ptr)+scale*index[6]);
+ if (likely(mask[7])) r[7] = *(unsigned int*)(((char*)ptr)+scale*index[7]);
+ return r;
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint8& ofs, const vuint8& v)
+ {
+ *(unsigned int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[7]) = v[7];
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vuint8& v)
+ {
+ if (likely(mask[0])) *(unsigned int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+ if (likely(mask[1])) *(unsigned int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+ if (likely(mask[2])) *(unsigned int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+ if (likely(mask[3])) *(unsigned int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+ if (likely(mask[4])) *(unsigned int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+ if (likely(mask[5])) *(unsigned int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+ if (likely(mask[6])) *(unsigned int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+ if (likely(mask[7])) *(unsigned int*)(((char*)ptr)+scale*ofs[7]) = v[7];
+ }
+
+
+ static __forceinline vuint8 broadcast64(const long long& a) { return _mm256_set1_epi64x(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const unsigned int& operator [](size_t index) const { assert(index < 8); return i[index]; }
+ __forceinline unsigned int& operator [](size_t index) { assert(index < 8); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 asBool(const vuint8& a) { return _mm256_castsi256_ps(a); }
+
+ __forceinline vuint8 operator +(const vuint8& a) { return a; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8 operator +(const vuint8& a, const vuint8& b) { return vuint8(_mm_add_epi32(a.vl, b.vl), _mm_add_epi32(a.vh, b.vh)); }
+ __forceinline vuint8 operator +(const vuint8& a, unsigned int b) { return a + vuint8(b); }
+ __forceinline vuint8 operator +(unsigned int a, const vuint8& b) { return vuint8(a) + b; }
+
+ __forceinline vuint8 operator -(const vuint8& a, const vuint8& b) { return vuint8(_mm_sub_epi32(a.vl, b.vl), _mm_sub_epi32(a.vh, b.vh)); }
+ __forceinline vuint8 operator -(const vuint8& a, unsigned int b) { return a - vuint8(b); }
+ __forceinline vuint8 operator -(unsigned int a, const vuint8& b) { return vuint8(a) - b; }
+
+ //__forceinline vuint8 operator *(const vuint8& a, const vuint8& b) { return vuint8(_mm_mullo_epu32(a.vl, b.vl), _mm_mullo_epu32(a.vh, b.vh)); }
+ //__forceinline vuint8 operator *(const vuint8& a, unsigned int b) { return a * vuint8(b); }
+ //__forceinline vuint8 operator *(unsigned int a, const vuint8& b) { return vuint8(a) * b; }
+
+ __forceinline vuint8 operator &(const vuint8& a, const vuint8& b) { return _mm256_castps_si256(_mm256_and_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vuint8 operator &(const vuint8& a, unsigned int b) { return a & vuint8(b); }
+ __forceinline vuint8 operator &(unsigned int a, const vuint8& b) { return vuint8(a) & b; }
+
+ __forceinline vuint8 operator |(const vuint8& a, const vuint8& b) { return _mm256_castps_si256(_mm256_or_ps (_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vuint8 operator |(const vuint8& a, unsigned int b) { return a | vuint8(b); }
+ __forceinline vuint8 operator |(unsigned int a, const vuint8& b) { return vuint8(a) | b; }
+
+ __forceinline vuint8 operator ^(const vuint8& a, const vuint8& b) { return _mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vuint8 operator ^(const vuint8& a, unsigned int b) { return a ^ vuint8(b); }
+ __forceinline vuint8 operator ^(unsigned int a, const vuint8& b) { return vuint8(a) ^ b; }
+
+ __forceinline vuint8 operator <<(const vuint8& a, unsigned int n) { return vuint8(_mm_slli_epi32(a.vl, n), _mm_slli_epi32(a.vh, n)); }
+ __forceinline vuint8 operator >>(const vuint8& a, unsigned int n) { return vuint8(_mm_srai_epi32(a.vl, n), _mm_srli_epi32(a.vh, n)); }
+
+ __forceinline vuint8 sll (const vuint8& a, unsigned int b) { return vuint8(_mm_slli_epi32(a.vl, b), _mm_slli_epi32(a.vh, b)); }
+ __forceinline vuint8 sra (const vuint8& a, unsigned int b) { return vuint8(_mm_srai_epi32(a.vl, b), _mm_srai_epi32(a.vh, b)); }
+ __forceinline vuint8 srl (const vuint8& a, unsigned int b) { return vuint8(_mm_srli_epi32(a.vl, b), _mm_srli_epi32(a.vh, b)); }
+
+ __forceinline vuint8 min(const vuint8& a, const vuint8& b) { return vuint8(_mm_min_epu32(a.vl, b.vl), _mm_min_epu32(a.vh, b.vh)); }
+ __forceinline vuint8 min(const vuint8& a, unsigned int b) { return min(a,vuint8(b)); }
+ __forceinline vuint8 min(unsigned int a, const vuint8& b) { return min(vuint8(a),b); }
+
+ __forceinline vuint8 max(const vuint8& a, const vuint8& b) { return vuint8(_mm_max_epu32(a.vl, b.vl), _mm_max_epu32(a.vh, b.vh)); }
+ __forceinline vuint8 max(const vuint8& a, unsigned int b) { return max(a,vuint8(b)); }
+ __forceinline vuint8 max(unsigned int a, const vuint8& b) { return max(vuint8(a),b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8& operator +=(vuint8& a, const vuint8& b) { return a = a + b; }
+ __forceinline vuint8& operator +=(vuint8& a, unsigned int b) { return a = a + b; }
+
+ __forceinline vuint8& operator -=(vuint8& a, const vuint8& b) { return a = a - b; }
+ __forceinline vuint8& operator -=(vuint8& a, unsigned int b) { return a = a - b; }
+
+ //__forceinline vuint8& operator *=(vuint8& a, const vuint8& b) { return a = a * b; }
+ //__forceinline vuint8& operator *=(vuint8& a, unsigned int b) { return a = a * b; }
+
+ __forceinline vuint8& operator &=(vuint8& a, const vuint8& b) { return a = a & b; }
+ __forceinline vuint8& operator &=(vuint8& a, unsigned int b) { return a = a & b; }
+
+ __forceinline vuint8& operator |=(vuint8& a, const vuint8& b) { return a = a | b; }
+ __forceinline vuint8& operator |=(vuint8& a, unsigned int b) { return a = a | b; }
+
+ __forceinline vuint8& operator <<=(vuint8& a, unsigned int b) { return a = a << b; }
+ __forceinline vuint8& operator >>=(vuint8& a, unsigned int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vboolf8 operator ==(const vuint8& a, const vuint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmpeq_epi32 (a.vl, b.vl)),
+ _mm_castsi128_ps(_mm_cmpeq_epi32 (a.vh, b.vh))); }
+ __forceinline vboolf8 operator ==(const vuint8& a, unsigned int b) { return a == vuint8(b); }
+ __forceinline vboolf8 operator ==(unsigned int a, const vuint8& b) { return vuint8(a) == b; }
+
+ __forceinline vboolf8 operator !=(const vuint8& a, const vuint8& b) { return !(a == b); }
+ __forceinline vboolf8 operator !=(const vuint8& a, unsigned int b) { return a != vuint8(b); }
+ __forceinline vboolf8 operator !=(unsigned int a, const vuint8& b) { return vuint8(a) != b; }
+
+ //__forceinline vboolf8 operator < (const vuint8& a, const vuint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmplt_epu32 (a.vl, b.vl)),
+ // _mm_castsi128_ps(_mm_cmplt_epu32 (a.vh, b.vh))); }
+ //__forceinline vboolf8 operator < (const vuint8& a, unsigned int b) { return a < vuint8(b); }
+ //__forceinline vboolf8 operator < (unsigned int a, const vuint8& b) { return vuint8(a) < b; }
+
+ //__forceinline vboolf8 operator >=(const vuint8& a, const vuint8& b) { return !(a < b); }
+ //__forceinline vboolf8 operator >=(const vuint8& a, unsigned int b) { return a >= vuint8(b); }
+ //__forceinline vboolf8 operator >=(unsigned int a, const vuint8& b) { return vuint8(a) >= b; }
+
+ //__forceinline vboolf8 operator > (const vuint8& a, const vuint8& b) { return vboolf8(_mm_castsi128_ps(_mm_cmpgt_epu32 (a.vl, b.vl)),
+ // _mm_castsi128_ps(_mm_cmpgt_epu32 (a.vh, b.vh))); }
+ //__forceinline vboolf8 operator > (const vuint8& a, unsigned int b) { return a > vuint8(b); }
+ //__forceinline vboolf8 operator > (unsigned int a, const vuint8& b) { return vuint8(a) > b; }
+
+ //__forceinline vboolf8 operator <=(const vuint8& a, const vuint8& b) { return !(a > b); }
+ //__forceinline vboolf8 operator <=(const vuint8& a, unsigned int b) { return a <= vuint8(b); }
+ //__forceinline vboolf8 operator <=(unsigned int a, const vuint8& b) { return vuint8(a) <= b; }
+
+ __forceinline vboolf8 eq(const vuint8& a, const vuint8& b) { return a == b; }
+ __forceinline vboolf8 ne(const vuint8& a, const vuint8& b) { return a != b; }
+
+ __forceinline vboolf8 eq(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a == b); }
+ __forceinline vboolf8 ne(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a != b); }
+
+ __forceinline vuint8 select(const vboolf8& m, const vuint8& t, const vuint8& f) {
+ return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(f), _mm256_castsi256_ps(t), m));
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8 unpacklo(const vuint8& a, const vuint8& b) { return _mm256_castps_si256(_mm256_unpacklo_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+ __forceinline vuint8 unpackhi(const vuint8& a, const vuint8& b) { return _mm256_castps_si256(_mm256_unpackhi_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b))); }
+
+ template<int i>
+ __forceinline vuint8 shuffle(const vuint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1>
+ __forceinline vuint8 shuffle4(const vuint8& v) {
+ return _mm256_permute2f128_si256(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vuint8 shuffle4(const vuint8& a, const vuint8& b) {
+ return _mm256_permute2f128_si256(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint8 shuffle(const vuint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint8 shuffle(const vuint8& a, const vuint8& b) {
+ return _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<> __forceinline vuint8 shuffle<0, 0, 2, 2>(const vuint8& v) { return _mm256_castps_si256(_mm256_moveldup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vuint8 shuffle<1, 1, 3, 3>(const vuint8& v) { return _mm256_castps_si256(_mm256_movehdup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vuint8 shuffle<0, 1, 0, 1>(const vuint8& v) { return _mm256_castps_si256(_mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(_mm256_castsi256_ps(v))))); }
+
+ template<int i> __forceinline vuint8 insert4(const vuint8& a, const vuint4& b) { return _mm256_insertf128_si256(a, b, i); }
+ template<int i> __forceinline vuint4 extract4(const vuint8& a) { return _mm256_extractf128_si256(a, i); }
+ template<> __forceinline vuint4 extract4<0>(const vuint8& a) { return _mm256_castsi256_si128(a); }
+
+ __forceinline int toScalar(const vuint8& v) { return _mm_cvtsi128_si32(_mm256_castsi256_si128(v)); }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ //__forceinline vuint8 vreduce_min2(const vuint8& v) { return min(v,shuffle<1,0,3,2>(v)); }
+ //__forceinline vuint8 vreduce_min4(const vuint8& v) { vuint8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
+ //__forceinline vuint8 vreduce_min (const vuint8& v) { vuint8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
+
+ //__forceinline vuint8 vreduce_max2(const vuint8& v) { return max(v,shuffle<1,0,3,2>(v)); }
+ //__forceinline vuint8 vreduce_max4(const vuint8& v) { vuint8 v1 = vreduce_max2(v); return max(v1,shuffle<2,3,0,1>(v1)); }
+ //__forceinline vuint8 vreduce_max (const vuint8& v) { vuint8 v1 = vreduce_max4(v); return max(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vuint8 vreduce_add2(const vuint8& v) { return v + shuffle<1,0,3,2>(v); }
+ __forceinline vuint8 vreduce_add4(const vuint8& v) { vuint8 v1 = vreduce_add2(v); return v1 + shuffle<2,3,0,1>(v1); }
+ __forceinline vuint8 vreduce_add (const vuint8& v) { vuint8 v1 = vreduce_add4(v); return v1 + shuffle4<1,0>(v1); }
+
+ //__forceinline int reduce_min(const vuint8& v) { return toScalar(vreduce_min(v)); }
+ //__forceinline int reduce_max(const vuint8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_add(const vuint8& v) { return toScalar(vreduce_add(v)); }
+
+ //__forceinline size_t select_min(const vuint8& v) { return bsf(movemask(v == vreduce_min(v))); }
+ //__forceinline size_t select_max(const vuint8& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ //__forceinline size_t select_min(const vboolf8& valid, const vuint8& v) { const vuint8 a = select(valid,v,vuint8(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ //__forceinline size_t select_max(const vboolf8& valid, const vuint8& v) { const vuint8 a = select(valid,v,vuint8(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vuint8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/simd/vuint8_avx2.h b/thirdparty/embree/common/simd/vuint8_avx2.h
new file mode 100644
index 0000000000..17b994522f
--- /dev/null
+++ b/thirdparty/embree/common/simd/vuint8_avx2.h
@@ -0,0 +1,446 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define vboolf vboolf_impl
+#define vboold vboold_impl
+#define vint vint_impl
+#define vuint vuint_impl
+#define vllong vllong_impl
+#define vfloat vfloat_impl
+#define vdouble vdouble_impl
+
+namespace embree
+{
+ /* 8-wide AVX integer type */
+ template<>
+ struct vuint<8>
+ {
+ ALIGNED_STRUCT_(32);
+
+ typedef vboolf8 Bool;
+ typedef vuint8 Int;
+ typedef vfloat8 Float;
+
+ enum { size = 8 }; // number of SIMD elements
+ union { // data
+ __m256i v;
+ unsigned int i[8];
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint() {}
+ __forceinline vuint(const vuint8& a) { v = a.v; }
+ __forceinline vuint8& operator =(const vuint8& a) { v = a.v; return *this; }
+
+ __forceinline vuint(__m256i a) : v(a) {}
+ __forceinline operator const __m256i&() const { return v; }
+ __forceinline operator __m256i&() { return v; }
+
+ __forceinline explicit vuint(const vuint4& a) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),a,1)) {}
+ __forceinline vuint(const vuint4& a, const vuint4& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+ __forceinline vuint(const __m128i& a, const __m128i& b) : v(_mm256_insertf128_si256(_mm256_castsi128_si256(a),b,1)) {}
+
+ __forceinline explicit vuint(const unsigned int* a) : v(_mm256_castps_si256(_mm256_loadu_ps((const float*)a))) {}
+ __forceinline vuint(unsigned int a) : v(_mm256_set1_epi32(a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b) : v(_mm256_set_epi32(b, a, b, a, b, a, b, a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d) : v(_mm256_set_epi32(d, c, b, a, d, c, b, a)) {}
+ __forceinline vuint(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e, unsigned int f, unsigned int g, unsigned int h) : v(_mm256_set_epi32(h, g, f, e, d, c, b, a)) {}
+
+ __forceinline explicit vuint(__m256 a) : v(_mm256_cvtps_epi32(a)) {}
+
+#if defined(__AVX512VL__)
+ __forceinline explicit vuint(const vboolf8& a) : v(_mm256_movm_epi32(a)) {}
+#else
+ __forceinline explicit vuint(const vboolf8& a) : v(_mm256_castps_si256((__m256)a)) {}
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint(ZeroTy) : v(_mm256_setzero_si256()) {}
+ __forceinline vuint(OneTy) : v(_mm256_set1_epi32(1)) {}
+ __forceinline vuint(PosInfTy) : v(_mm256_set1_epi32(pos_inf)) {}
+ __forceinline vuint(NegInfTy) : v(_mm256_set1_epi32(neg_inf)) {}
+ __forceinline vuint(StepTy) : v(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0)) {}
+ __forceinline vuint(UndefinedTy) : v(_mm256_undefined_si256()) {}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Loads and Stores
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static __forceinline vuint8 load(const unsigned char* ptr) { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
+ static __forceinline vuint8 loadu(const unsigned char* ptr) { return _mm256_cvtepu8_epi32(_mm_loadl_epi64((__m128i*)ptr)); }
+ static __forceinline vuint8 load(const unsigned short* ptr) { return _mm256_cvtepu16_epi32(_mm_load_si128((__m128i*)ptr)); }
+ static __forceinline vuint8 loadu(const unsigned short* ptr) { return _mm256_cvtepu16_epi32(_mm_loadu_si128((__m128i*)ptr)); }
+
+ static __forceinline vuint8 load(const void* ptr) { return _mm256_load_si256((__m256i*)ptr); }
+ static __forceinline vuint8 loadu(const void* ptr) { return _mm256_loadu_si256((__m256i*)ptr); }
+
+ static __forceinline void store (void* ptr, const vuint8& v) { _mm256_store_si256((__m256i*)ptr,v); }
+ static __forceinline void storeu(void* ptr, const vuint8& v) { _mm256_storeu_ps((float*)ptr,_mm256_castsi256_ps(v)); }
+
+#if defined(__AVX512VL__)
+
+ static __forceinline vuint8 compact(const vboolf8& mask, vuint8 &v) {
+ return _mm256_mask_compress_epi32(v, mask, v);
+ }
+ static __forceinline vuint8 compact(const vboolf8& mask, vuint8 &a, const vuint8& b) {
+ return _mm256_mask_compress_epi32(a, mask, b);
+ }
+
+ static __forceinline vuint8 load (const vboolf8& mask, const void* ptr) { return _mm256_mask_load_epi32 (_mm256_setzero_si256(),mask,ptr); }
+ static __forceinline vuint8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_mask_loadu_epi32(_mm256_setzero_si256(),mask,ptr); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vuint8& v) { _mm256_mask_store_epi32 (ptr,mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vuint8& v) { _mm256_mask_storeu_epi32(ptr,mask,v); }
+#else
+ static __forceinline vuint8 load (const vboolf8& mask, const void* ptr) { return _mm256_castps_si256(_mm256_maskload_ps((float*)ptr,mask)); }
+ static __forceinline vuint8 loadu(const vboolf8& mask, const void* ptr) { return _mm256_castps_si256(_mm256_maskload_ps((float*)ptr,mask)); }
+
+ static __forceinline void store (const vboolf8& mask, void* ptr, const vuint8& v) { _mm256_maskstore_epi32((int*)ptr,mask,v); }
+ static __forceinline void storeu(const vboolf8& mask, void* ptr, const vuint8& v) { _mm256_maskstore_epi32((int*)ptr,mask,v); }
+#endif
+
+ static __forceinline vuint8 load_nt(void* ptr) {
+ return _mm256_stream_load_si256((__m256i*)ptr);
+ }
+
+ static __forceinline void store_nt(void* ptr, const vuint8& v) {
+ _mm256_stream_ps((float*)ptr,_mm256_castsi256_ps(v));
+ }
+
+ static __forceinline void store(unsigned char* ptr, const vuint8& i)
+ {
+ for (size_t j=0; j<8; j++)
+ ptr[j] = i[j];
+ }
+
+ static __forceinline void store(unsigned short* ptr, const vuint8& v) {
+ for (size_t i=0;i<8;i++)
+ ptr[i] = (unsigned short)v[i];
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint8 gather(const unsigned int *const ptr, const vint8& index) {
+ return _mm256_i32gather_epi32((const int*) ptr, index, scale);
+ }
+
+ template<int scale = 4>
+ static __forceinline vuint8 gather(const vboolf8& mask, const unsigned int *const ptr, const vint8& index) {
+ vuint8 r = zero;
+#if defined(__AVX512VL__)
+ return _mm256_mmask_i32gather_epi32(r, mask, index, (const int*) ptr, scale);
+#else
+ return _mm256_mask_i32gather_epi32(r, (const int*) ptr, index, mask, scale);
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(void* ptr, const vint8& ofs, const vuint8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_i32scatter_epi32((int*)ptr, ofs, v, scale);
+#else
+ *(unsigned int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+ *(unsigned int*)(((char*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ template<int scale = 4>
+ static __forceinline void scatter(const vboolf8& mask, void* ptr, const vint8& ofs, const vuint8& v)
+ {
+#if defined(__AVX512VL__)
+ _mm256_mask_i32scatter_epi32((int*)ptr, mask, ofs, v, scale);
+#else
+ if (likely(mask[0])) *(unsigned int*)(((char*)ptr)+scale*ofs[0]) = v[0];
+ if (likely(mask[1])) *(unsigned int*)(((char*)ptr)+scale*ofs[1]) = v[1];
+ if (likely(mask[2])) *(unsigned int*)(((char*)ptr)+scale*ofs[2]) = v[2];
+ if (likely(mask[3])) *(unsigned int*)(((char*)ptr)+scale*ofs[3]) = v[3];
+ if (likely(mask[4])) *(unsigned int*)(((char*)ptr)+scale*ofs[4]) = v[4];
+ if (likely(mask[5])) *(unsigned int*)(((char*)ptr)+scale*ofs[5]) = v[5];
+ if (likely(mask[6])) *(unsigned int*)(((char*)ptr)+scale*ofs[6]) = v[6];
+ if (likely(mask[7])) *(unsigned int*)(((char*)ptr)+scale*ofs[7]) = v[7];
+#endif
+ }
+
+ static __forceinline vuint8 broadcast64(const long long &a) { return _mm256_set1_epi64x(a); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Array Access
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline const unsigned int& operator [](size_t index) const { assert(index < 8); return i[index]; }
+ __forceinline unsigned int& operator [](size_t index) { assert(index < 8); return i[index]; }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Unary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf8 asBool(const vuint8& a) { return _mm256_movepi32_mask(a); }
+#else
+ __forceinline vboolf8 asBool(const vuint8& a) { return _mm256_castsi256_ps(a); }
+#endif
+
+ __forceinline vuint8 operator +(const vuint8& a) { return a; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Binary Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8 operator +(const vuint8& a, const vuint8& b) { return _mm256_add_epi32(a, b); }
+ __forceinline vuint8 operator +(const vuint8& a, unsigned int b) { return a + vuint8(b); }
+ __forceinline vuint8 operator +(unsigned int a, const vuint8& b) { return vuint8(a) + b; }
+
+ __forceinline vuint8 operator -(const vuint8& a, const vuint8& b) { return _mm256_sub_epi32(a, b); }
+ __forceinline vuint8 operator -(const vuint8& a, unsigned int b) { return a - vuint8(b); }
+ __forceinline vuint8 operator -(unsigned int a, const vuint8& b) { return vuint8(a) - b; }
+
+ //__forceinline vuint8 operator *(const vuint8& a, const vuint8& b) { return _mm256_mullo_epu32(a, b); }
+ //__forceinline vuint8 operator *(const vuint8& a, unsigned int b) { return a * vuint8(b); }
+ //__forceinline vuint8 operator *(unsigned int a, const vuint8& b) { return vuint8(a) * b; }
+
+ __forceinline vuint8 operator &(const vuint8& a, const vuint8& b) { return _mm256_and_si256(a, b); }
+ __forceinline vuint8 operator &(const vuint8& a, unsigned int b) { return a & vuint8(b); }
+ __forceinline vuint8 operator &(unsigned int a, const vuint8& b) { return vuint8(a) & b; }
+
+ __forceinline vuint8 operator |(const vuint8& a, const vuint8& b) { return _mm256_or_si256(a, b); }
+ __forceinline vuint8 operator |(const vuint8& a, unsigned int b) { return a | vuint8(b); }
+ __forceinline vuint8 operator |(unsigned int a, const vuint8& b) { return vuint8(a) | b; }
+
+ __forceinline vuint8 operator ^(const vuint8& a, const vuint8& b) { return _mm256_xor_si256(a, b); }
+ __forceinline vuint8 operator ^(const vuint8& a, unsigned int b) { return a ^ vuint8(b); }
+ __forceinline vuint8 operator ^(unsigned int a, const vuint8& b) { return vuint8(a) ^ b; }
+
+ __forceinline vuint8 operator <<(const vuint8& a, unsigned int n) { return _mm256_slli_epi32(a, n); }
+ __forceinline vuint8 operator >>(const vuint8& a, unsigned int n) { return _mm256_srli_epi32(a, n); }
+
+ __forceinline vuint8 operator <<(const vuint8& a, const vuint8& n) { return _mm256_sllv_epi32(a, n); }
+ __forceinline vuint8 operator >>(const vuint8& a, const vuint8& n) { return _mm256_srlv_epi32(a, n); }
+
+ __forceinline vuint8 sll(const vuint8& a, unsigned int b) { return _mm256_slli_epi32(a, b); }
+ __forceinline vuint8 sra(const vuint8& a, unsigned int b) { return _mm256_srai_epi32(a, b); }
+ __forceinline vuint8 srl(const vuint8& a, unsigned int b) { return _mm256_srli_epi32(a, b); }
+
+ __forceinline vuint8 sll(const vuint8& a, const vuint8& b) { return _mm256_sllv_epi32(a, b); }
+ __forceinline vuint8 sra(const vuint8& a, const vuint8& b) { return _mm256_srav_epi32(a, b); }
+ __forceinline vuint8 srl(const vuint8& a, const vuint8& b) { return _mm256_srlv_epi32(a, b); }
+
+ __forceinline vuint8 min(const vuint8& a, const vuint8& b) { return _mm256_min_epu32(a, b); }
+ __forceinline vuint8 min(const vuint8& a, unsigned int b) { return min(a,vuint8(b)); }
+ __forceinline vuint8 min(unsigned int a, const vuint8& b) { return min(vuint8(a),b); }
+
+ __forceinline vuint8 max(const vuint8& a, const vuint8& b) { return _mm256_max_epu32(a, b); }
+ __forceinline vuint8 max(const vuint8& a, unsigned int b) { return max(a,vuint8(b)); }
+ __forceinline vuint8 max(unsigned int a, const vuint8& b) { return max(vuint8(a),b); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Assignment Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8& operator +=(vuint8& a, const vuint8& b) { return a = a + b; }
+ __forceinline vuint8& operator +=(vuint8& a, unsigned int b) { return a = a + b; }
+
+ __forceinline vuint8& operator -=(vuint8& a, const vuint8& b) { return a = a - b; }
+ __forceinline vuint8& operator -=(vuint8& a, unsigned int b) { return a = a - b; }
+
+ //__forceinline vuint8& operator *=(vuint8& a, const vuint8& b) { return a = a * b; }
+ //__forceinline vuint8& operator *=(vuint8& a, unsigned int b) { return a = a * b; }
+
+ __forceinline vuint8& operator &=(vuint8& a, const vuint8& b) { return a = a & b; }
+ __forceinline vuint8& operator &=(vuint8& a, unsigned int b) { return a = a & b; }
+
+ __forceinline vuint8& operator |=(vuint8& a, const vuint8& b) { return a = a | b; }
+ __forceinline vuint8& operator |=(vuint8& a, unsigned int b) { return a = a | b; }
+
+ __forceinline vuint8& operator <<=(vuint8& a, const unsigned int b) { return a = a << b; }
+ __forceinline vuint8& operator >>=(vuint8& a, const unsigned int b) { return a = a >> b; }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Comparison Operators + Select
+ ////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf8 operator ==(const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_EQ); }
+ __forceinline vboolf8 operator !=(const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_NE); }
+ __forceinline vboolf8 operator < (const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_LT); }
+ __forceinline vboolf8 operator >=(const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_GE); }
+ __forceinline vboolf8 operator > (const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_GT); }
+ __forceinline vboolf8 operator <=(const vuint8& a, const vuint8& b) { return _mm256_cmp_epu32_mask(a,b,_MM_CMPINT_LE); }
+
+ __forceinline vuint8 select(const vboolf8& m, const vuint8& t, const vuint8& f) {
+ return _mm256_mask_blend_epi32(m, (__m256i)f, (__m256i)t);
+ }
+#else
+ __forceinline vboolf8 operator ==(const vuint8& a, const vuint8& b) { return _mm256_castsi256_ps(_mm256_cmpeq_epi32(a, b)); }
+ __forceinline vboolf8 operator !=(const vuint8& a, const vuint8& b) { return !(a == b); }
+ //__forceinline vboolf8 operator < (const vuint8& a, const vuint8& b) { return _mm256_castsi256_ps(_mm256_cmpgt_epu32(b, a)); }
+ //__forceinline vboolf8 operator >=(const vuint8& a, const vuint8& b) { return !(a < b); }
+ //__forceinline vboolf8 operator > (const vuint8& a, const vuint8& b) { return _mm256_castsi256_ps(_mm256_cmpgt_epu32(a, b)); }
+ //__forceinline vboolf8 operator <=(const vuint8& a, const vuint8& b) { return !(a > b); }
+
+ __forceinline vuint8 select(const vboolf8& m, const vuint8& t, const vuint8& f) {
+ return _mm256_castps_si256(_mm256_blendv_ps(_mm256_castsi256_ps(f), _mm256_castsi256_ps(t), m));
+ }
+#endif
+
+ template<int mask>
+ __forceinline vuint8 select(const vuint8& t, const vuint8& f) {
+ return _mm256_blend_epi32(f, t, mask);
+ }
+
+ __forceinline vboolf8 operator ==(const vuint8& a, unsigned int b) { return a == vuint8(b); }
+ __forceinline vboolf8 operator ==(unsigned int a, const vuint8& b) { return vuint8(a) == b; }
+
+ __forceinline vboolf8 operator !=(const vuint8& a, unsigned int b) { return a != vuint8(b); }
+ __forceinline vboolf8 operator !=(unsigned int a, const vuint8& b) { return vuint8(a) != b; }
+
+ //__forceinline vboolf8 operator < (const vuint8& a, unsigned int b) { return a < vuint8(b); }
+ //__forceinline vboolf8 operator < (unsigned int a, const vuint8& b) { return vuint8(a) < b; }
+
+ //__forceinline vboolf8 operator >=(const vuint8& a, unsigned int b) { return a >= vuint8(b); }
+ //__forceinline vboolf8 operator >=(unsigned int a, const vuint8& b) { return vuint8(a) >= b; }
+
+ //__forceinline vboolf8 operator > (const vuint8& a, unsigned int b) { return a > vuint8(b); }
+ //__forceinline vboolf8 operator > (unsigned int a, const vuint8& b) { return vuint8(a) > b; }
+
+ //__forceinline vboolf8 operator <=(const vuint8& a, unsigned int b) { return a <= vuint8(b); }
+ //__forceinline vboolf8 operator <=(unsigned int a, const vuint8& b) { return vuint8(a) <= b; }
+
+ __forceinline vboolf8 eq(const vuint8& a, const vuint8& b) { return a == b; }
+ __forceinline vboolf8 ne(const vuint8& a, const vuint8& b) { return a != b; }
+ //__forceinline vboolf8 lt(const vuint8& a, const vuint8& b) { return a < b; }
+ //__forceinline vboolf8 ge(const vuint8& a, const vuint8& b) { return a >= b; }
+ //__forceinline vboolf8 gt(const vuint8& a, const vuint8& b) { return a > b; }
+ //__forceinline vboolf8 le(const vuint8& a, const vuint8& b) { return a <= b; }
+
+#if defined(__AVX512VL__)
+ __forceinline vboolf8 eq(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_EQ); }
+ __forceinline vboolf8 ne(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_NE); }
+ __forceinline vboolf8 lt(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LT); }
+ __forceinline vboolf8 ge(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_GE); }
+ __forceinline vboolf8 gt(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_GT); }
+ __forceinline vboolf8 le(const vboolf8& mask, const vuint8& a, const vuint8& b) { return _mm256_mask_cmp_epu32_mask(mask, a, b, _MM_CMPINT_LE); }
+#else
+ __forceinline vboolf8 eq(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a == b); }
+ __forceinline vboolf8 ne(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a != b); }
+ //__forceinline vboolf8 lt(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a < b); }
+ //__forceinline vboolf8 ge(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a >= b); }
+ //__forceinline vboolf8 gt(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a > b); }
+ //__forceinline vboolf8 le(const vboolf8& mask, const vuint8& a, const vuint8& b) { return mask & (a <= b); }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Movement/Shifting/Shuffling Functions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline vuint8 unpacklo(const vuint8& a, const vuint8& b) { return _mm256_unpacklo_epi32(a, b); }
+ __forceinline vuint8 unpackhi(const vuint8& a, const vuint8& b) { return _mm256_unpackhi_epi32(a, b); }
+
+ template<int i>
+ __forceinline vuint8 shuffle(const vuint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i, i, i, i)));
+ }
+
+ template<int i0, int i1>
+ __forceinline vuint8 shuffle4(const vuint8& v) {
+ return _mm256_permute2f128_si256(v, v, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1>
+ __forceinline vuint8 shuffle4(const vuint8& a, const vuint8& b) {
+ return _mm256_permute2f128_si256(a, b, (i1 << 4) | (i0 << 0));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint8 shuffle(const vuint8& v) {
+ return _mm256_castps_si256(_mm256_permute_ps(_mm256_castsi256_ps(v), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<int i0, int i1, int i2, int i3>
+ __forceinline vuint8 shuffle(const vuint8& a, const vuint8& b) {
+ return _mm256_castps_si256(_mm256_shuffle_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(b), _MM_SHUFFLE(i3, i2, i1, i0)));
+ }
+
+ template<> __forceinline vuint8 shuffle<0, 0, 2, 2>(const vuint8& v) { return _mm256_castps_si256(_mm256_moveldup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vuint8 shuffle<1, 1, 3, 3>(const vuint8& v) { return _mm256_castps_si256(_mm256_movehdup_ps(_mm256_castsi256_ps(v))); }
+ template<> __forceinline vuint8 shuffle<0, 1, 0, 1>(const vuint8& v) { return _mm256_castps_si256(_mm256_castpd_ps(_mm256_movedup_pd(_mm256_castps_pd(_mm256_castsi256_ps(v))))); }
+
+ template<int i> __forceinline vuint8 insert4(const vuint8& a, const vuint4& b) { return _mm256_insertf128_si256(a, b, i); }
+ template<int i> __forceinline vuint4 extract4(const vuint8& a) { return _mm256_extractf128_si256(a, i); }
+ template<> __forceinline vuint4 extract4<0>(const vuint8& a) { return _mm256_castsi256_si128(a); }
+
+ __forceinline int toScalar(const vuint8& v) { return _mm_cvtsi128_si32(_mm256_castsi256_si128(v)); }
+
+ __forceinline vuint8 permute(const vuint8& v, const __m256i& index) {
+ return _mm256_permutevar8x32_epi32(v, index);
+ }
+
+ __forceinline vuint8 shuffle(const vuint8& v, const __m256i& index) {
+ return _mm256_castps_si256(_mm256_permutevar_ps(_mm256_castsi256_ps(v), index));
+ }
+
+ template<int i>
+ __forceinline vuint8 align_shift_right(const vuint8& a, const vuint8& b) {
+#if defined(__AVX512VL__)
+ return _mm256_alignr_epi32(a, b, i);
+#else
+ return _mm256_alignr_epi8(a, b, 4*i);
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reductions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ //__forceinline vuint8 vreduce_min2(const vuint8& v) { return min(v,shuffle<1,0,3,2>(v)); }
+ //__forceinline vuint8 vreduce_min4(const vuint8& v) { vuint8 v1 = vreduce_min2(v); return min(v1,shuffle<2,3,0,1>(v1)); }
+ //__forceinline vuint8 vreduce_min (const vuint8& v) { vuint8 v1 = vreduce_min4(v); return min(v1,shuffle4<1,0>(v1)); }
+
+ //__forceinline vuint8 vreduce_max2(const vuint8& v) { return max(v,shuffle<1,0,3,2>(v)); }
+ //__forceinline vuint8 vreduce_max4(const vuint8& v) { vuint8 v1 = vreduce_max2(v); return max(v1,shuffle<2,3,0,1>(v1)); }
+ //__forceinline vuint8 vreduce_max (const vuint8& v) { vuint8 v1 = vreduce_max4(v); return max(v1,shuffle4<1,0>(v1)); }
+
+ __forceinline vuint8 vreduce_add2(const vuint8& v) { return v + shuffle<1,0,3,2>(v); }
+ __forceinline vuint8 vreduce_add4(const vuint8& v) { vuint8 v1 = vreduce_add2(v); return v1 + shuffle<2,3,0,1>(v1); }
+ __forceinline vuint8 vreduce_add (const vuint8& v) { vuint8 v1 = vreduce_add4(v); return v1 + shuffle4<1,0>(v1); }
+
+ //__forceinline int reduce_min(const vuint8& v) { return toScalar(vreduce_min(v)); }
+ //__forceinline int reduce_max(const vuint8& v) { return toScalar(vreduce_max(v)); }
+ __forceinline int reduce_add(const vuint8& v) { return toScalar(vreduce_add(v)); }
+
+ //__forceinline size_t select_min(const vuint8& v) { return bsf(movemask(v == vreduce_min(v))); }
+ //__forceinline size_t select_max(const vuint8& v) { return bsf(movemask(v == vreduce_max(v))); }
+
+ //__forceinline size_t select_min(const vboolf8& valid, const vuint8& v) { const vuint8 a = select(valid,v,vuint8(pos_inf)); return bsf(movemask(valid & (a == vreduce_min(a)))); }
+ //__forceinline size_t select_max(const vboolf8& valid, const vuint8& v) { const vuint8 a = select(valid,v,vuint8(neg_inf)); return bsf(movemask(valid & (a == vreduce_max(a)))); }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Output Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline embree_ostream operator <<(embree_ostream cout, const vuint8& a) {
+ return cout << "<" << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << ", " << a[5] << ", " << a[6] << ", " << a[7] << ">";
+ }
+}
+
+#undef vboolf
+#undef vboold
+#undef vint
+#undef vuint
+#undef vllong
+#undef vfloat
+#undef vdouble
diff --git a/thirdparty/embree/common/sys/alloc.cpp b/thirdparty/embree/common/sys/alloc.cpp
new file mode 100644
index 0000000000..abdd269069
--- /dev/null
+++ b/thirdparty/embree/common/sys/alloc.cpp
@@ -0,0 +1,327 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "alloc.h"
+#include "intrinsics.h"
+#include "sysinfo.h"
+#include "mutex.h"
+
+////////////////////////////////////////////////////////////////////////////////
+/// All Platforms
+////////////////////////////////////////////////////////////////////////////////
+
+namespace embree
+{
+ void* alignedMalloc(size_t size, size_t align)
+ {
+ if (size == 0)
+ return nullptr;
+
+ assert((align & (align-1)) == 0);
+ void* ptr = _mm_malloc(size,align);
+
+ if (size != 0 && ptr == nullptr)
+ // -- GODOT start --
+ // throw std::bad_alloc();
+ abort();
+ // -- GODOT end --
+
+ return ptr;
+ }
+
+ void alignedFree(void* ptr)
+ {
+ if (ptr)
+ _mm_free(ptr);
+ }
+
+ static bool huge_pages_enabled = false;
+ static MutexSys os_init_mutex;
+
+ __forceinline bool isHugePageCandidate(const size_t bytes)
+ {
+ if (!huge_pages_enabled)
+ return false;
+
+ /* use huge pages only when memory overhead is low */
+ const size_t hbytes = (bytes+PAGE_SIZE_2M-1) & ~size_t(PAGE_SIZE_2M-1);
+ return 66*(hbytes-bytes) < bytes; // at most 1.5% overhead
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Windows Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <malloc.h>
+
+namespace embree
+{
+ bool win_enable_selockmemoryprivilege (bool verbose)
+ {
+ HANDLE hToken;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) {
+ if (verbose) std::cout << "WARNING: OpenProcessToken failed while trying to enable SeLockMemoryPrivilege: " << GetLastError() << std::endl;
+ return false;
+ }
+
+ TOKEN_PRIVILEGES tp;
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (!LookupPrivilegeValueW(nullptr, L"SeLockMemoryPrivilege", &tp.Privileges[0].Luid)) {
+ if (verbose) std::cout << "WARNING: LookupPrivilegeValue failed while trying to enable SeLockMemoryPrivilege: " << GetLastError() << std::endl;
+ return false;
+ }
+
+ SetLastError(ERROR_SUCCESS);
+ if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), nullptr, 0)) {
+ if (verbose) std::cout << "WARNING: AdjustTokenPrivileges failed while trying to enable SeLockMemoryPrivilege" << std::endl;
+ return false;
+ }
+
+ if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
+ if (verbose) std::cout << "WARNING: AdjustTokenPrivileges failed to enable SeLockMemoryPrivilege: Add SeLockMemoryPrivilege for current user and run process in elevated mode (Run as administrator)." << std::endl;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool os_init(bool hugepages, bool verbose)
+ {
+ Lock<MutexSys> lock(os_init_mutex);
+
+ if (!hugepages) {
+ huge_pages_enabled = false;
+ return true;
+ }
+
+ if (GetLargePageMinimum() != PAGE_SIZE_2M) {
+ huge_pages_enabled = false;
+ return false;
+ }
+
+ huge_pages_enabled = true;
+ return true;
+ }
+
+ void* os_malloc(size_t bytes, bool& hugepages)
+ {
+ if (bytes == 0) {
+ hugepages = false;
+ return nullptr;
+ }
+
+ /* try direct huge page allocation first */
+ if (isHugePageCandidate(bytes))
+ {
+ int flags = MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES;
+ char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE);
+ if (ptr != nullptr) {
+ hugepages = true;
+ return ptr;
+ }
+ }
+
+ /* fall back to 4k pages */
+ int flags = MEM_COMMIT | MEM_RESERVE;
+ char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE);
+ // -- GODOT start --
+ // if (ptr == nullptr) throw std::bad_alloc();
+ if (ptr == nullptr) abort();
+ // -- GODOT end --
+ hugepages = false;
+ return ptr;
+ }
+
+ size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld, bool hugepages)
+ {
+ if (hugepages) // decommitting huge pages seems not to work under Windows
+ return bytesOld;
+
+ const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;
+ bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1);
+ bytesOld = (bytesOld+pageSize-1) & ~(pageSize-1);
+ if (bytesNew >= bytesOld)
+ return bytesOld;
+
+ if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT))
+ // -- GODOT start --
+ // throw std::bad_alloc();
+ abort();
+ // -- GODOT end --
+
+ return bytesNew;
+ }
+
+ void os_free(void* ptr, size_t bytes, bool hugepages)
+ {
+ if (bytes == 0)
+ return;
+
+ if (!VirtualFree(ptr,0,MEM_RELEASE))
+ // -- GODOT start --
+ // throw std::bad_alloc();
+ abort();
+ // -- GODOT end --
+ }
+
+ void os_advise(void *ptr, size_t bytes)
+ {
+ }
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unix Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__UNIX__)
+
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sstream>
+
+#if defined(__MACOSX__)
+#include <mach/vm_statistics.h>
+#endif
+
+namespace embree
+{
+ bool os_init(bool hugepages, bool verbose)
+ {
+ Lock<MutexSys> lock(os_init_mutex);
+
+ if (!hugepages) {
+ huge_pages_enabled = false;
+ return true;
+ }
+
+#if defined(__LINUX__)
+
+ int hugepagesize = 0;
+
+ std::ifstream file;
+ file.open("/proc/meminfo",std::ios::in);
+ if (!file.is_open()) {
+ if (verbose) std::cout << "WARNING: Could not open /proc/meminfo. Huge page support cannot get enabled!" << std::endl;
+ huge_pages_enabled = false;
+ return false;
+ }
+
+ std::string line;
+ while (getline(file,line))
+ {
+ std::stringstream sline(line);
+ while (!sline.eof() && sline.peek() == ' ') sline.ignore();
+ std::string tag; getline(sline,tag,' ');
+ while (!sline.eof() && sline.peek() == ' ') sline.ignore();
+ std::string val; getline(sline,val,' ');
+ while (!sline.eof() && sline.peek() == ' ') sline.ignore();
+ std::string unit; getline(sline,unit,' ');
+ if (tag == "Hugepagesize:" && unit == "kB") {
+ hugepagesize = std::stoi(val)*1024;
+ break;
+ }
+ }
+
+ if (hugepagesize != PAGE_SIZE_2M)
+ {
+ if (verbose) std::cout << "WARNING: Only 2MB huge pages supported. Huge page support cannot get enabled!" << std::endl;
+ huge_pages_enabled = false;
+ return false;
+ }
+#endif
+
+ huge_pages_enabled = true;
+ return true;
+ }
+
+ void* os_malloc(size_t bytes, bool& hugepages)
+ {
+ if (bytes == 0) {
+ hugepages = false;
+ return nullptr;
+ }
+
+ /* try direct huge page allocation first */
+ if (isHugePageCandidate(bytes))
+ {
+#if defined(__MACOSX__)
+ void* ptr = mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
+ if (ptr != MAP_FAILED) {
+ hugepages = true;
+ return ptr;
+ }
+#elif defined(MAP_HUGETLB)
+ void* ptr = mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_HUGETLB, -1, 0);
+ if (ptr != MAP_FAILED) {
+ hugepages = true;
+ return ptr;
+ }
+#endif
+ }
+
+ /* fallback to 4k pages */
+ void* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ // -- GODOT start --
+ // if (ptr == MAP_FAILED) throw std::bad_alloc();
+ if (ptr == MAP_FAILED) abort();
+ // -- GODOT end --
+ hugepages = false;
+
+ /* advise huge page hint for THP */
+ os_advise(ptr,bytes);
+ return ptr;
+ }
+
+ size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld, bool hugepages)
+ {
+ const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;
+ bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1);
+ bytesOld = (bytesOld+pageSize-1) & ~(pageSize-1);
+ if (bytesNew >= bytesOld)
+ return bytesOld;
+
+ if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1)
+ // -- GODOT start --
+ // throw std::bad_alloc();
+ abort();
+ // -- GODOT end --
+
+ return bytesNew;
+ }
+
+ void os_free(void* ptr, size_t bytes, bool hugepages)
+ {
+ if (bytes == 0)
+ return;
+
+ /* for hugepages we need to also align the size */
+ const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;
+ bytes = (bytes+pageSize-1) & ~(pageSize-1);
+ if (munmap(ptr,bytes) == -1)
+ // -- GODOT start --
+ // throw std::bad_alloc();
+ abort();
+ // -- GODOT end --
+ }
+
+ /* hint for transparent huge pages (THP) */
+ void os_advise(void* pptr, size_t bytes)
+ {
+#if defined(MADV_HUGEPAGE)
+ madvise(pptr,bytes,MADV_HUGEPAGE);
+#endif
+ }
+}
+
+#endif
diff --git a/thirdparty/embree/common/sys/alloc.h b/thirdparty/embree/common/sys/alloc.h
new file mode 100644
index 0000000000..4fa474ec1d
--- /dev/null
+++ b/thirdparty/embree/common/sys/alloc.h
@@ -0,0 +1,164 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+#include <vector>
+#include <set>
+
+namespace embree
+{
+#define ALIGNED_STRUCT_(align) \
+ void* operator new(size_t size) { return alignedMalloc(size,align); } \
+ void operator delete(void* ptr) { alignedFree(ptr); } \
+ void* operator new[](size_t size) { return alignedMalloc(size,align); } \
+ void operator delete[](void* ptr) { alignedFree(ptr); }
+
+#define ALIGNED_CLASS_(align) \
+ public: \
+ ALIGNED_STRUCT_(align) \
+ private:
+
+ /*! aligned allocation */
+ void* alignedMalloc(size_t size, size_t align);
+ void alignedFree(void* ptr);
+
+ /*! allocator that performs aligned allocations */
+ template<typename T, size_t alignment>
+ struct aligned_allocator
+ {
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ __forceinline pointer allocate( size_type n ) {
+ return (pointer) alignedMalloc(n*sizeof(value_type),alignment);
+ }
+
+ __forceinline void deallocate( pointer p, size_type n ) {
+ return alignedFree(p);
+ }
+
+ __forceinline void construct( pointer p, const_reference val ) {
+ new (p) T(val);
+ }
+
+ __forceinline void destroy( pointer p ) {
+ p->~T();
+ }
+ };
+
+ /*! allocates pages directly from OS */
+ bool win_enable_selockmemoryprivilege(bool verbose);
+ bool os_init(bool hugepages, bool verbose);
+ void* os_malloc (size_t bytes, bool& hugepages);
+ size_t os_shrink (void* ptr, size_t bytesNew, size_t bytesOld, bool hugepages);
+ void os_free (void* ptr, size_t bytes, bool hugepages);
+ void os_advise (void* ptr, size_t bytes);
+
+ /*! allocator that performs OS allocations */
+ template<typename T>
+ struct os_allocator
+ {
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ __forceinline os_allocator ()
+ : hugepages(false) {}
+
+ __forceinline pointer allocate( size_type n ) {
+ return (pointer) os_malloc(n*sizeof(value_type),hugepages);
+ }
+
+ __forceinline void deallocate( pointer p, size_type n ) {
+ return os_free(p,n*sizeof(value_type),hugepages);
+ }
+
+ __forceinline void construct( pointer p, const_reference val ) {
+ new (p) T(val);
+ }
+
+ __forceinline void destroy( pointer p ) {
+ p->~T();
+ }
+
+ bool hugepages;
+ };
+
+ /*! allocator for IDs */
+ template<typename T, size_t max_id>
+ struct IDPool
+ {
+ typedef T value_type;
+
+ IDPool ()
+ : nextID(0) {}
+
+ T allocate()
+ {
+ /* return ID from list */
+ if (!IDs.empty())
+ {
+ T id = *IDs.begin();
+ IDs.erase(IDs.begin());
+ return id;
+ }
+
+ /* allocate new ID */
+ else
+ {
+ if (size_t(nextID)+1 > max_id)
+ return -1;
+
+ return nextID++;
+ }
+ }
+
+ /* adds an ID provided by the user */
+ bool add(T id)
+ {
+ if (id > max_id)
+ return false;
+
+ /* check if ID should be in IDs set */
+ if (id < nextID) {
+ auto p = IDs.find(id);
+ if (p == IDs.end()) return false;
+ IDs.erase(p);
+ return true;
+ }
+
+ /* otherwise increase ID set */
+ else
+ {
+ for (T i=nextID; i<id; i++) {
+ IDs.insert(i);
+ }
+ nextID = id+1;
+ return true;
+ }
+ }
+
+ void deallocate( T id )
+ {
+ assert(id < nextID);
+ MAYBE_UNUSED auto done = IDs.insert(id).second;
+ assert(done);
+ }
+
+ private:
+ std::set<T> IDs; //!< stores deallocated IDs to be reused
+ T nextID; //!< next ID to use when IDs vector is empty
+ };
+}
+
diff --git a/thirdparty/embree/common/sys/array.h b/thirdparty/embree/common/sys/array.h
new file mode 100644
index 0000000000..dd9190c52a
--- /dev/null
+++ b/thirdparty/embree/common/sys/array.h
@@ -0,0 +1,222 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+#include "alloc.h"
+
+namespace embree
+{
+ /*! static array with static size */
+ template<typename T, size_t N>
+ class array_t
+ {
+ public:
+
+ /********************** Iterators ****************************/
+
+ __forceinline T* begin() const { return items; };
+ __forceinline T* end () const { return items+N; };
+
+
+ /********************** Capacity ****************************/
+
+ __forceinline bool empty () const { return N == 0; }
+ __forceinline size_t size () const { return N; }
+ __forceinline size_t max_size () const { return N; }
+
+
+ /******************** Element access **************************/
+
+ __forceinline T& operator[](size_t i) { assert(i < N); return items[i]; }
+ __forceinline const T& operator[](size_t i) const { assert(i < N); return items[i]; }
+
+ __forceinline T& at(size_t i) { assert(i < N); return items[i]; }
+ __forceinline const T& at(size_t i) const { assert(i < N); return items[i]; }
+
+ __forceinline T& front() const { assert(N > 0); return items[0]; };
+ __forceinline T& back () const { assert(N > 0); return items[N-1]; };
+
+ __forceinline T* data() { return items; };
+ __forceinline const T* data() const { return items; };
+
+ private:
+ T items[N];
+ };
+
+ /*! static array with dynamic size */
+ template<typename T, size_t N>
+ class darray_t
+ {
+ public:
+
+ __forceinline darray_t () : M(0) {}
+
+ __forceinline darray_t (const T& v) : M(0) {
+ for (size_t i=0; i<N; i++) items[i] = v;
+ }
+
+ /********************** Iterators ****************************/
+
+ __forceinline T* begin() const { return items; };
+ __forceinline T* end () const { return items+M; };
+
+
+ /********************** Capacity ****************************/
+
+ __forceinline bool empty () const { return M == 0; }
+ __forceinline size_t size () const { return M; }
+ __forceinline size_t capacity () const { return N; }
+ __forceinline size_t max_size () const { return N; }
+
+ void resize(size_t new_size) {
+ assert(new_size < max_size());
+ M = new_size;
+ }
+
+ /******************** Modifiers **************************/
+
+ __forceinline void push_back(const T& v)
+ {
+ assert(M+1 < max_size());
+ items[M++] = v;
+ }
+
+ __forceinline void pop_back()
+ {
+ assert(!empty());
+ M--;
+ }
+
+ __forceinline void clear() {
+ M = 0;
+ }
+
+ /******************** Element access **************************/
+
+ __forceinline T& operator[](size_t i) { assert(i < M); return items[i]; }
+ __forceinline const T& operator[](size_t i) const { assert(i < M); return items[i]; }
+
+ __forceinline T& at(size_t i) { assert(i < M); return items[i]; }
+ __forceinline const T& at(size_t i) const { assert(i < M); return items[i]; }
+
+ __forceinline T& front() const { assert(M > 0); return items[0]; };
+ __forceinline T& back () const { assert(M > 0); return items[M-1]; };
+
+ __forceinline T* data() { return items; };
+ __forceinline const T* data() const { return items; };
+
+ private:
+ size_t M;
+ T items[N];
+ };
+
+ /*! dynamic sized array that is allocated on the stack */
+#define dynamic_large_stack_array(Ty,Name,N,max_stack_bytes) StackArray<Ty,max_stack_bytes> Name(N)
+ template<typename Ty, size_t max_stack_bytes>
+ struct __aligned(64) StackArray
+ {
+ __forceinline StackArray (const size_t N)
+ : N(N)
+ {
+ if (N*sizeof(Ty) <= max_stack_bytes)
+ data = &arr[0];
+ else
+ data = (Ty*) alignedMalloc(N*sizeof(Ty),64);
+ }
+
+ __forceinline ~StackArray () {
+ if (data != &arr[0]) alignedFree(data);
+ }
+
+ __forceinline operator Ty* () { return data; }
+ __forceinline operator const Ty* () const { return data; }
+
+ __forceinline Ty& operator[](const int i) { assert(i>=0 && i<N); return data[i]; }
+ __forceinline const Ty& operator[](const int i) const { assert(i>=0 && i<N); return data[i]; }
+
+ __forceinline Ty& operator[](const unsigned i) { assert(i<N); return data[i]; }
+ __forceinline const Ty& operator[](const unsigned i) const { assert(i<N); return data[i]; }
+
+#if defined(__64BIT__)
+ __forceinline Ty& operator[](const size_t i) { assert(i<N); return data[i]; }
+ __forceinline const Ty& operator[](const size_t i) const { assert(i<N); return data[i]; }
+#endif
+
+ private:
+ Ty arr[max_stack_bytes/sizeof(Ty)];
+ Ty* data;
+ size_t N;
+
+ private:
+ StackArray (const StackArray& other) DELETED; // do not implement
+ StackArray& operator= (const StackArray& other) DELETED; // do not implement
+
+ };
+
+ /*! dynamic sized array that is allocated on the stack */
+ template<typename Ty, size_t max_stack_elements, size_t max_total_elements>
+ struct __aligned(64) DynamicStackArray
+ {
+ __forceinline DynamicStackArray ()
+ : data(&arr[0]) {}
+
+ __forceinline ~DynamicStackArray ()
+ {
+ if (!isStackAllocated())
+ delete[] data;
+ }
+
+ __forceinline bool isStackAllocated() const {
+ return data == &arr[0];
+ }
+
+ __forceinline size_t size() const
+ {
+ if (isStackAllocated()) return max_stack_elements;
+ else return max_total_elements;
+ }
+
+ __forceinline void resize(size_t M)
+ {
+ assert(M <= max_total_elements);
+ if (likely(M <= max_stack_elements)) return;
+ if (likely(!isStackAllocated())) return;
+
+ data = new Ty[max_total_elements];
+
+ for (size_t i=0; i<max_stack_elements; i++)
+ data[i] = arr[i];
+ }
+
+ __forceinline operator Ty* () { return data; }
+ __forceinline operator const Ty* () const { return data; }
+
+ __forceinline Ty& operator[](const int i) { assert(i>=0 && i<max_total_elements); resize(i+1); return data[i]; }
+ __forceinline Ty& operator[](const unsigned i) { assert(i<max_total_elements); resize(i+1); return data[i]; }
+
+#if defined(__64BIT__)
+ __forceinline Ty& operator[](const size_t i) { assert(i<max_total_elements); resize(i+1); return data[i]; }
+#endif
+
+ __forceinline DynamicStackArray (const DynamicStackArray& other)
+ : data(&arr[0])
+ {
+ for (size_t i=0; i<other.size(); i++)
+ this->operator[] (i) = other[i];
+ }
+
+ DynamicStackArray& operator= (const DynamicStackArray& other)
+ {
+ for (size_t i=0; i<other.size(); i++)
+ this->operator[] (i) = other[i];
+
+ return *this;
+ }
+
+ private:
+ Ty arr[max_stack_elements];
+ Ty* data;
+ };
+}
diff --git a/thirdparty/embree/common/sys/atomic.h b/thirdparty/embree/common/sys/atomic.h
new file mode 100644
index 0000000000..67af254f36
--- /dev/null
+++ b/thirdparty/embree/common/sys/atomic.h
@@ -0,0 +1,59 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <atomic>
+#include "intrinsics.h"
+
+namespace embree
+{
+/* compiler memory barriers */
+#if defined(__INTEL_COMPILER)
+//#define __memory_barrier() __memory_barrier()
+#elif defined(__GNUC__) || defined(__clang__)
+# define __memory_barrier() asm volatile("" ::: "memory")
+#elif defined(_MSC_VER)
+# define __memory_barrier() _ReadWriteBarrier()
+#endif
+
+ template <typename T>
+ struct atomic : public std::atomic<T>
+ {
+ atomic () {}
+
+ atomic (const T& a)
+ : std::atomic<T>(a) {}
+
+ atomic (const atomic<T>& a) {
+ this->store(a.load());
+ }
+
+ atomic& operator=(const atomic<T>& other) {
+ this->store(other.load());
+ return *this;
+ }
+ };
+
+ template<typename T>
+ __forceinline void atomic_min(std::atomic<T>& aref, const T& bref)
+ {
+ const T b = bref.load();
+ while (true) {
+ T a = aref.load();
+ if (a <= b) break;
+ if (aref.compare_exchange_strong(a,b)) break;
+ }
+ }
+
+ template<typename T>
+ __forceinline void atomic_max(std::atomic<T>& aref, const T& bref)
+ {
+ const T b = bref.load();
+ while (true) {
+ T a = aref.load();
+ if (a >= b) break;
+ if (aref.compare_exchange_strong(a,b)) break;
+ }
+ }
+}
diff --git a/thirdparty/embree/common/sys/barrier.cpp b/thirdparty/embree/common/sys/barrier.cpp
new file mode 100644
index 0000000000..0c0e39d92d
--- /dev/null
+++ b/thirdparty/embree/common/sys/barrier.cpp
@@ -0,0 +1,289 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "barrier.h"
+#include "condition.h"
+#include "regression.h"
+#include "thread.h"
+
+#if defined (__WIN32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace embree
+{
+ struct BarrierSysImplementation
+ {
+ __forceinline BarrierSysImplementation (size_t N)
+ : i(0), enterCount(0), exitCount(0), barrierSize(0)
+ {
+ events[0] = CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ events[1] = CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ init(N);
+ }
+
+ __forceinline ~BarrierSysImplementation ()
+ {
+ CloseHandle(events[0]);
+ CloseHandle(events[1]);
+ }
+
+ __forceinline void init(size_t N)
+ {
+ barrierSize = N;
+ enterCount.store(N);
+ exitCount.store(N);
+ }
+
+ __forceinline void wait()
+ {
+ /* every thread entering the barrier decrements this count */
+ size_t i0 = i;
+ size_t cnt0 = enterCount--;
+
+ /* all threads except the last one are wait in the barrier */
+ if (cnt0 > 1)
+ {
+ if (WaitForSingleObject(events[i0], INFINITE) != WAIT_OBJECT_0)
+ THROW_RUNTIME_ERROR("WaitForSingleObjects failed");
+ }
+
+ /* the last thread starts all threads waiting at the barrier */
+ else
+ {
+ i = 1-i;
+ enterCount.store(barrierSize);
+ if (SetEvent(events[i0]) == 0)
+ THROW_RUNTIME_ERROR("SetEvent failed");
+ }
+
+ /* every thread leaving the barrier decrements this count */
+ size_t cnt1 = exitCount--;
+
+ /* the last thread that left the barrier resets the event again */
+ if (cnt1 == 1)
+ {
+ exitCount.store(barrierSize);
+ if (ResetEvent(events[i0]) == 0)
+ THROW_RUNTIME_ERROR("ResetEvent failed");
+ }
+ }
+
+ public:
+ HANDLE events[2];
+ atomic<size_t> i;
+ atomic<size_t> enterCount;
+ atomic<size_t> exitCount;
+ size_t barrierSize;
+ };
+}
+
+#else
+
+namespace embree
+{
+ struct BarrierSysImplementation
+ {
+ __forceinline BarrierSysImplementation (size_t N)
+ : count(0), barrierSize(0)
+ {
+ init(N);
+ }
+
+ __forceinline void init(size_t N)
+ {
+ assert(count == 0);
+ count = 0;
+ barrierSize = N;
+ }
+
+ __forceinline void wait()
+ {
+ mutex.lock();
+ count++;
+
+ if (count == barrierSize) {
+ count = 0;
+ cond.notify_all();
+ mutex.unlock();
+ return;
+ }
+
+ cond.wait(mutex);
+ mutex.unlock();
+ return;
+ }
+
+ public:
+ MutexSys mutex;
+ ConditionSys cond;
+ volatile size_t count;
+ volatile size_t barrierSize;
+ };
+}
+
+#endif
+
+namespace embree
+{
+ BarrierSys::BarrierSys (size_t N) {
+ opaque = new BarrierSysImplementation(N);
+ }
+
+ BarrierSys::~BarrierSys () {
+ delete (BarrierSysImplementation*) opaque;
+ }
+
+ void BarrierSys::init(size_t count) {
+ ((BarrierSysImplementation*) opaque)->init(count);
+ }
+
+ void BarrierSys::wait() {
+ ((BarrierSysImplementation*) opaque)->wait();
+ }
+
+ LinearBarrierActive::LinearBarrierActive (size_t N)
+ : count0(nullptr), count1(nullptr), mode(0), flag0(0), flag1(0), threadCount(0)
+ {
+ if (N == 0) N = getNumberOfLogicalThreads();
+ init(N);
+ }
+
+ LinearBarrierActive::~LinearBarrierActive()
+ {
+ delete[] count0;
+ delete[] count1;
+ }
+
+ void LinearBarrierActive::init(size_t N)
+ {
+ if (threadCount != N) {
+ threadCount = N;
+ if (count0) delete[] count0; count0 = new unsigned char[N];
+ if (count1) delete[] count1; count1 = new unsigned char[N];
+ }
+ mode = 0;
+ flag0 = 0;
+ flag1 = 0;
+ for (size_t i=0; i<N; i++) count0[i] = 0;
+ for (size_t i=0; i<N; i++) count1[i] = 0;
+ }
+
+ void LinearBarrierActive::wait (const size_t threadIndex)
+ {
+ if (mode == 0)
+ {
+ if (threadIndex == 0)
+ {
+ for (size_t i=0; i<threadCount; i++)
+ count1[i] = 0;
+
+ for (size_t i=1; i<threadCount; i++)
+ {
+ while (likely(count0[i] == 0))
+ pause_cpu();
+ }
+ mode = 1;
+ flag1 = 0;
+ __memory_barrier();
+ flag0 = 1;
+ }
+ else
+ {
+ count0[threadIndex] = 1;
+ {
+ while (likely(flag0 == 0))
+ pause_cpu();
+ }
+
+ }
+ }
+ else
+ {
+ if (threadIndex == 0)
+ {
+ for (size_t i=0; i<threadCount; i++)
+ count0[i] = 0;
+
+ for (size_t i=1; i<threadCount; i++)
+ {
+ while (likely(count1[i] == 0))
+ pause_cpu();
+ }
+
+ mode = 0;
+ flag0 = 0;
+ __memory_barrier();
+ flag1 = 1;
+ }
+ else
+ {
+ count1[threadIndex] = 1;
+ {
+ while (likely(flag1 == 0))
+ pause_cpu();
+ }
+ }
+ }
+ }
+
+ struct barrier_sys_regression_test : public RegressionTest
+ {
+ BarrierSys barrier;
+ std::atomic<size_t> threadID;
+ std::atomic<size_t> numFailed;
+ std::vector<size_t> threadResults;
+
+ barrier_sys_regression_test()
+ : RegressionTest("barrier_sys_regression_test"), threadID(0), numFailed(0)
+ {
+ registerRegressionTest(this);
+ }
+
+ static void thread_alloc(barrier_sys_regression_test* This)
+ {
+ size_t tid = This->threadID++;
+ for (size_t j=0; j<1000; j++)
+ {
+ This->barrier.wait();
+ This->threadResults[tid] = tid;
+ This->barrier.wait();
+ }
+ }
+
+ bool run ()
+ {
+ threadID.store(0);
+ numFailed.store(0);
+
+ size_t numThreads = getNumberOfLogicalThreads();
+ threadResults.resize(numThreads);
+ barrier.init(numThreads+1);
+
+ /* create threads */
+ std::vector<thread_t> threads;
+ for (size_t i=0; i<numThreads; i++)
+ threads.push_back(createThread((thread_func)thread_alloc,this));
+
+ /* run test */
+ for (size_t i=0; i<1000; i++)
+ {
+ for (size_t i=0; i<numThreads; i++) threadResults[i] = 0;
+ barrier.wait();
+ barrier.wait();
+ for (size_t i=0; i<numThreads; i++) numFailed += threadResults[i] != i;
+ }
+
+ /* destroy threads */
+ for (size_t i=0; i<numThreads; i++)
+ join(threads[i]);
+
+ return numFailed == 0;
+ }
+ };
+
+ barrier_sys_regression_test barrier_sys_regression_test;
+}
+
+
diff --git a/thirdparty/embree/common/sys/barrier.h b/thirdparty/embree/common/sys/barrier.h
new file mode 100644
index 0000000000..37fc036291
--- /dev/null
+++ b/thirdparty/embree/common/sys/barrier.h
@@ -0,0 +1,112 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "intrinsics.h"
+#include "sysinfo.h"
+#include "atomic.h"
+
+namespace embree
+{
+ /*! system barrier using operating system */
+ class BarrierSys
+ {
+ public:
+
+ /*! construction / destruction */
+ BarrierSys (size_t N = 0);
+ ~BarrierSys ();
+
+ private:
+ /*! class in non-copyable */
+ BarrierSys (const BarrierSys& other) DELETED; // do not implement
+ BarrierSys& operator= (const BarrierSys& other) DELETED; // do not implement
+
+ public:
+ /*! intializes the barrier with some number of threads */
+ void init(size_t count);
+
+ /*! lets calling thread wait in barrier */
+ void wait();
+
+ private:
+ void* opaque;
+ };
+
+ /*! fast active barrier using atomitc counter */
+ struct BarrierActive
+ {
+ public:
+ BarrierActive ()
+ : cntr(0) {}
+
+ void reset() {
+ cntr.store(0);
+ }
+
+ void wait (size_t numThreads)
+ {
+ cntr++;
+ while (cntr.load() != numThreads)
+ pause_cpu();
+ }
+
+ private:
+ std::atomic<size_t> cntr;
+ };
+
+ /*! fast active barrier that does not require initialization to some number of threads */
+ struct BarrierActiveAutoReset
+ {
+ public:
+ BarrierActiveAutoReset ()
+ : cntr0(0), cntr1(0) {}
+
+ void wait (size_t threadCount)
+ {
+ cntr0.fetch_add(1);
+ while (cntr0 != threadCount) pause_cpu();
+ cntr1.fetch_add(1);
+ while (cntr1 != threadCount) pause_cpu();
+ cntr0.fetch_add(-1);
+ while (cntr0 != 0) pause_cpu();
+ cntr1.fetch_add(-1);
+ while (cntr1 != 0) pause_cpu();
+ }
+
+ private:
+ std::atomic<size_t> cntr0;
+ std::atomic<size_t> cntr1;
+ };
+
+ class LinearBarrierActive
+ {
+ public:
+
+ /*! construction and destruction */
+ LinearBarrierActive (size_t threadCount = 0);
+ ~LinearBarrierActive();
+
+ private:
+ /*! class in non-copyable */
+ LinearBarrierActive (const LinearBarrierActive& other) DELETED; // do not implement
+ LinearBarrierActive& operator= (const LinearBarrierActive& other) DELETED; // do not implement
+
+ public:
+ /*! intializes the barrier with some number of threads */
+ void init(size_t threadCount);
+
+ /*! thread with threadIndex waits in the barrier */
+ void wait (const size_t threadIndex);
+
+ private:
+ volatile unsigned char* count0;
+ volatile unsigned char* count1;
+ volatile unsigned int mode;
+ volatile unsigned int flag0;
+ volatile unsigned int flag1;
+ volatile size_t threadCount;
+ };
+}
+
diff --git a/thirdparty/embree/common/sys/condition.cpp b/thirdparty/embree/common/sys/condition.cpp
new file mode 100644
index 0000000000..606a1d0b04
--- /dev/null
+++ b/thirdparty/embree/common/sys/condition.cpp
@@ -0,0 +1,85 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "condition.h"
+
+#if defined(__WIN32__) && !defined(PTHREADS_WIN32)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace embree
+{
+ struct ConditionImplementation
+ {
+ __forceinline ConditionImplementation () {
+ InitializeConditionVariable(&cond);
+ }
+
+ __forceinline ~ConditionImplementation () {
+ }
+
+ __forceinline void wait(MutexSys& mutex_in) {
+ SleepConditionVariableCS(&cond, (LPCRITICAL_SECTION)mutex_in.mutex, INFINITE);
+ }
+
+ __forceinline void notify_all() {
+ WakeAllConditionVariable(&cond);
+ }
+
+ public:
+ CONDITION_VARIABLE cond;
+ };
+}
+#endif
+
+#if defined(__UNIX__) || defined(PTHREADS_WIN32)
+#include <pthread.h>
+namespace embree
+{
+ struct ConditionImplementation
+ {
+ __forceinline ConditionImplementation () {
+ if (pthread_cond_init(&cond,nullptr) != 0)
+ THROW_RUNTIME_ERROR("pthread_cond_init failed");
+ }
+
+ __forceinline ~ConditionImplementation() {
+ MAYBE_UNUSED bool ok = pthread_cond_destroy(&cond) == 0;
+ assert(ok);
+ }
+
+ __forceinline void wait(MutexSys& mutex) {
+ if (pthread_cond_wait(&cond, (pthread_mutex_t*)mutex.mutex) != 0)
+ THROW_RUNTIME_ERROR("pthread_cond_wait failed");
+ }
+
+ __forceinline void notify_all() {
+ if (pthread_cond_broadcast(&cond) != 0)
+ THROW_RUNTIME_ERROR("pthread_cond_broadcast failed");
+ }
+
+ public:
+ pthread_cond_t cond;
+ };
+}
+#endif
+
+namespace embree
+{
+ ConditionSys::ConditionSys () {
+ cond = new ConditionImplementation;
+ }
+
+ ConditionSys::~ConditionSys() {
+ delete (ConditionImplementation*) cond;
+ }
+
+ void ConditionSys::wait(MutexSys& mutex) {
+ ((ConditionImplementation*) cond)->wait(mutex);
+ }
+
+ void ConditionSys::notify_all() {
+ ((ConditionImplementation*) cond)->notify_all();
+ }
+}
diff --git a/thirdparty/embree/common/sys/condition.h b/thirdparty/embree/common/sys/condition.h
new file mode 100644
index 0000000000..557c6e3482
--- /dev/null
+++ b/thirdparty/embree/common/sys/condition.h
@@ -0,0 +1,31 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "mutex.h"
+
+namespace embree
+{
+ class ConditionSys
+ {
+ public:
+ ConditionSys();
+ ~ConditionSys();
+ void wait( class MutexSys& mutex );
+ void notify_all();
+
+ template<typename Predicate>
+ __forceinline void wait( class MutexSys& mutex, const Predicate& pred )
+ {
+ while (!pred()) wait(mutex);
+ }
+
+ private:
+ ConditionSys (const ConditionSys& other) DELETED; // do not implement
+ ConditionSys& operator= (const ConditionSys& other) DELETED; // do not implement
+
+ protected:
+ void* cond;
+ };
+}
diff --git a/thirdparty/embree/common/sys/filename.cpp b/thirdparty/embree/common/sys/filename.cpp
new file mode 100644
index 0000000000..f55b224302
--- /dev/null
+++ b/thirdparty/embree/common/sys/filename.cpp
@@ -0,0 +1,138 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "filename.h"
+#include "sysinfo.h"
+
+namespace embree
+{
+#ifdef __WIN32__
+ const char path_sep = '\\';
+#else
+ const char path_sep = '/';
+#endif
+
+ /*! create an empty filename */
+ FileName::FileName () {}
+
+ /*! create a valid filename from a string */
+ FileName::FileName (const char* in) {
+ filename = in;
+ for (size_t i=0; i<filename.size(); i++)
+ if (filename[i] == '\\' || filename[i] == '/')
+ filename[i] = path_sep;
+ while (!filename.empty() && filename[filename.size()-1] == path_sep)
+ filename.resize(filename.size()-1);
+ }
+
+ /*! create a valid filename from a string */
+ FileName::FileName (const std::string& in) {
+ filename = in;
+ for (size_t i=0; i<filename.size(); i++)
+ if (filename[i] == '\\' || filename[i] == '/')
+ filename[i] = path_sep;
+ while (!filename.empty() && filename[filename.size()-1] == path_sep)
+ filename.resize(filename.size()-1);
+ }
+
+ /*! returns path to home folder */
+ FileName FileName::homeFolder()
+ {
+#ifdef __WIN32__
+ const char* home = getenv("UserProfile");
+#else
+ const char* home = getenv("HOME");
+#endif
+ if (home) return home;
+ return "";
+ }
+
+ /*! returns path to executable */
+ FileName FileName::executableFolder() {
+ return FileName(getExecutableFileName()).path();
+ }
+
+ /*! returns the path */
+ FileName FileName::path() const {
+ size_t pos = filename.find_last_of(path_sep);
+ if (pos == std::string::npos) return FileName();
+ return filename.substr(0,pos);
+ }
+
+ /*! returns the basename */
+ std::string FileName::base() const {
+ size_t pos = filename.find_last_of(path_sep);
+ if (pos == std::string::npos) return filename;
+ return filename.substr(pos+1);
+ }
+
+ /*! returns the extension */
+ std::string FileName::ext() const {
+ size_t pos = filename.find_last_of('.');
+ if (pos == std::string::npos) return "";
+ return filename.substr(pos+1);
+ }
+
+ /*! returns the extension */
+ FileName FileName::dropExt() const {
+ size_t pos = filename.find_last_of('.');
+ if (pos == std::string::npos) return filename;
+ return filename.substr(0,pos);
+ }
+
+ /*! returns the basename without extension */
+ std::string FileName::name() const {
+ size_t start = filename.find_last_of(path_sep);
+ if (start == std::string::npos) start = 0; else start++;
+ size_t end = filename.find_last_of('.');
+ if (end == std::string::npos || end < start) end = filename.size();
+ return filename.substr(start, end - start);
+ }
+
+ /*! replaces the extension */
+ FileName FileName::setExt(const std::string& ext) const {
+ size_t start = filename.find_last_of(path_sep);
+ if (start == std::string::npos) start = 0; else start++;
+ size_t end = filename.find_last_of('.');
+ if (end == std::string::npos || end < start) return FileName(filename+ext);
+ return FileName(filename.substr(0,end)+ext);
+ }
+
+ /*! adds the extension */
+ FileName FileName::addExt(const std::string& ext) const {
+ return FileName(filename+ext);
+ }
+
+ /*! concatenates two filenames to this/other */
+ FileName FileName::operator +( const FileName& other ) const {
+ if (filename == "") return FileName(other);
+ else return FileName(filename + path_sep + other.filename);
+ }
+
+ /*! concatenates two filenames to this/other */
+ FileName FileName::operator +( const std::string& other ) const {
+ return operator+(FileName(other));
+ }
+
+ /*! removes the base from a filename (if possible) */
+ FileName FileName::operator -( const FileName& base ) const {
+ size_t pos = filename.find_first_of(base);
+ if (pos == std::string::npos) return *this;
+ return FileName(filename.substr(pos+1));
+ }
+
+ /*! == operator */
+ bool operator== (const FileName& a, const FileName& b) {
+ return a.filename == b.filename;
+ }
+
+ /*! != operator */
+ bool operator!= (const FileName& a, const FileName& b) {
+ return a.filename != b.filename;
+ }
+
+ /*! output operator */
+ std::ostream& operator<<(std::ostream& cout, const FileName& filename) {
+ return cout << filename.filename;
+ }
+}
diff --git a/thirdparty/embree/common/sys/filename.h b/thirdparty/embree/common/sys/filename.h
new file mode 100644
index 0000000000..d5929cd836
--- /dev/null
+++ b/thirdparty/embree/common/sys/filename.h
@@ -0,0 +1,81 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+
+namespace embree
+{
+ /*! Convenience class for handling file names and paths. */
+ class FileName
+ {
+ public:
+
+ /*! create an empty filename */
+ FileName ();
+
+ /*! create a valid filename from a string */
+ FileName (const char* filename);
+
+ /*! create a valid filename from a string */
+ FileName (const std::string& filename);
+
+ /*! returns path to home folder */
+ static FileName homeFolder();
+
+ /*! returns path to executable */
+ static FileName executableFolder();
+
+ /*! auto convert into a string */
+ operator std::string() const { return filename; }
+
+ /*! returns a string of the filename */
+ const std::string str() const { return filename; }
+
+ /*! returns a c-string of the filename */
+ const char* c_str() const { return filename.c_str(); }
+
+ /*! returns the path of a filename */
+ FileName path() const;
+
+ /*! returns the file of a filename */
+ std::string base() const;
+
+ /*! returns the base of a filename without extension */
+ std::string name() const;
+
+ /*! returns the file extension */
+ std::string ext() const;
+
+ /*! drops the file extension */
+ FileName dropExt() const;
+
+ /*! replaces the file extension */
+ FileName setExt(const std::string& ext = "") const;
+
+ /*! adds file extension */
+ FileName addExt(const std::string& ext = "") const;
+
+ /*! concatenates two filenames to this/other */
+ FileName operator +( const FileName& other ) const;
+
+ /*! concatenates two filenames to this/other */
+ FileName operator +( const std::string& other ) const;
+
+ /*! removes the base from a filename (if possible) */
+ FileName operator -( const FileName& base ) const;
+
+ /*! == operator */
+ friend bool operator==(const FileName& a, const FileName& b);
+
+ /*! != operator */
+ friend bool operator!=(const FileName& a, const FileName& b);
+
+ /*! output operator */
+ friend std::ostream& operator<<(std::ostream& cout, const FileName& filename);
+
+ private:
+ std::string filename;
+ };
+}
diff --git a/thirdparty/embree/common/sys/intrinsics.h b/thirdparty/embree/common/sys/intrinsics.h
new file mode 100644
index 0000000000..ed8dd7d40a
--- /dev/null
+++ b/thirdparty/embree/common/sys/intrinsics.h
@@ -0,0 +1,525 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+
+#if defined(__WIN32__)
+#include <intrin.h>
+#endif
+
+#if defined(__ARM_NEON)
+#include "../simd/arm/emulation.h"
+#else
+#include <immintrin.h>
+#endif
+
+#if defined(__BMI__) && defined(__GNUC__) && !defined(__INTEL_COMPILER)
+ #if !defined(_tzcnt_u32)
+ #define _tzcnt_u32 __tzcnt_u32
+ #endif
+ #if !defined(_tzcnt_u64)
+ #define _tzcnt_u64 __tzcnt_u64
+ #endif
+#endif
+
+#if defined(__LZCNT__)
+ #if !defined(_lzcnt_u32)
+ #define _lzcnt_u32 __lzcnt32
+ #endif
+ #if !defined(_lzcnt_u64)
+ #define _lzcnt_u64 __lzcnt64
+ #endif
+#endif
+
+#if defined(__WIN32__)
+// -- GODOT start --
+#if !defined(NOMINMAX)
+// -- GODOT end --
+#define NOMINMAX
+// -- GODOT start --
+#endif
+#include "windows.h"
+// -- GODOT end --
+#endif
+
+/* normally defined in pmmintrin.h, but we always need this */
+#if !defined(_MM_SET_DENORMALS_ZERO_MODE)
+#define _MM_DENORMALS_ZERO_ON (0x0040)
+#define _MM_DENORMALS_ZERO_OFF (0x0000)
+#define _MM_DENORMALS_ZERO_MASK (0x0040)
+#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x)))
+#endif
+
+namespace embree
+{
+
+////////////////////////////////////////////////////////////////////////////////
+/// Windows Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__WIN32__)
+
+ __forceinline size_t read_tsc()
+ {
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ return (size_t)li.QuadPart;
+ }
+
+ __forceinline int bsf(int v) {
+#if defined(__AVX2__)
+ return _tzcnt_u32(v);
+#else
+ unsigned long r = 0; _BitScanForward(&r,v); return r;
+#endif
+ }
+
+ __forceinline unsigned bsf(unsigned v) {
+#if defined(__AVX2__)
+ return _tzcnt_u32(v);
+#else
+ unsigned long r = 0; _BitScanForward(&r,v); return r;
+#endif
+ }
+
+#if defined(__X86_64__)
+ __forceinline size_t bsf(size_t v) {
+#if defined(__AVX2__)
+ return _tzcnt_u64(v);
+#else
+ unsigned long r = 0; _BitScanForward64(&r,v); return r;
+#endif
+ }
+#endif
+
+ __forceinline int bscf(int& v)
+ {
+ int i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+
+ __forceinline unsigned bscf(unsigned& v)
+ {
+ unsigned i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+
+#if defined(__X86_64__)
+ __forceinline size_t bscf(size_t& v)
+ {
+ size_t i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+#endif
+
+ __forceinline int bsr(int v) {
+#if defined(__AVX2__)
+ return 31 - _lzcnt_u32(v);
+#else
+ unsigned long r = 0; _BitScanReverse(&r,v); return r;
+#endif
+ }
+
+ __forceinline unsigned bsr(unsigned v) {
+#if defined(__AVX2__)
+ return 31 - _lzcnt_u32(v);
+#else
+ unsigned long r = 0; _BitScanReverse(&r,v); return r;
+#endif
+ }
+
+#if defined(__X86_64__)
+ __forceinline size_t bsr(size_t v) {
+#if defined(__AVX2__)
+ return 63 -_lzcnt_u64(v);
+#else
+ unsigned long r = 0; _BitScanReverse64(&r, v); return r;
+#endif
+ }
+#endif
+
+ __forceinline int lzcnt(const int x)
+ {
+#if defined(__AVX2__)
+ return _lzcnt_u32(x);
+#else
+ if (unlikely(x == 0)) return 32;
+ return 31 - bsr(x);
+#endif
+ }
+
+ __forceinline int btc(int v, int i) {
+ long r = v; _bittestandcomplement(&r,i); return r;
+ }
+
+ __forceinline int bts(int v, int i) {
+ long r = v; _bittestandset(&r,i); return r;
+ }
+
+ __forceinline int btr(int v, int i) {
+ long r = v; _bittestandreset(&r,i); return r;
+ }
+
+#if defined(__X86_64__)
+
+ __forceinline size_t btc(size_t v, size_t i) {
+ size_t r = v; _bittestandcomplement64((__int64*)&r,i); return r;
+ }
+
+ __forceinline size_t bts(size_t v, size_t i) {
+ __int64 r = v; _bittestandset64(&r,i); return r;
+ }
+
+ __forceinline size_t btr(size_t v, size_t i) {
+ __int64 r = v; _bittestandreset64(&r,i); return r;
+ }
+
+#endif
+
+ __forceinline int32_t atomic_cmpxchg(volatile int32_t* p, const int32_t c, const int32_t v) {
+ return _InterlockedCompareExchange((volatile long*)p,v,c);
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unix Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#else
+
+#if defined(__i386__) && defined(__PIC__)
+
+ __forceinline void __cpuid(int out[4], int op)
+ {
+ asm volatile ("xchg{l}\t{%%}ebx, %1\n\t"
+ "cpuid\n\t"
+ "xchg{l}\t{%%}ebx, %1\n\t"
+ : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3])
+ : "0"(op));
+ }
+
+ __forceinline void __cpuid_count(int out[4], int op1, int op2)
+ {
+ asm volatile ("xchg{l}\t{%%}ebx, %1\n\t"
+ "cpuid\n\t"
+ "xchg{l}\t{%%}ebx, %1\n\t"
+ : "=a" (out[0]), "=r" (out[1]), "=c" (out[2]), "=d" (out[3])
+ : "0" (op1), "2" (op2));
+ }
+
+#elif defined(__X86_ASM__)
+
+ __forceinline void __cpuid(int out[4], int op) {
+ asm volatile ("cpuid" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(op));
+ }
+
+ __forceinline void __cpuid_count(int out[4], int op1, int op2) {
+ asm volatile ("cpuid" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(op1), "c"(op2));
+ }
+
+#endif
+
+ __forceinline uint64_t read_tsc() {
+#if defined(__X86_ASM__)
+ uint32_t high,low;
+ asm volatile ("rdtsc" : "=d"(high), "=a"(low));
+ return (((uint64_t)high) << 32) + (uint64_t)low;
+#else
+ /* Not supported yet, meaning measuring traversal cost per pixel does not work. */
+ return 0;
+#endif
+ }
+
+ __forceinline int bsf(int v) {
+#if defined(__AVX2__)
+ return _tzcnt_u32(v);
+#elif defined(__X86_ASM__)
+ int r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r;
+#else
+ return __builtin_ctz(v);
+#endif
+ }
+
+#if defined(__64BIT__)
+ __forceinline unsigned bsf(unsigned v)
+ {
+#if defined(__AVX2__)
+ return _tzcnt_u32(v);
+#elif defined(__X86_ASM__)
+ unsigned r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r;
+#else
+ return __builtin_ctz(v);
+#endif
+ }
+#endif
+
+ __forceinline size_t bsf(size_t v) {
+#if defined(__AVX2__)
+#if defined(__X86_64__)
+ return _tzcnt_u64(v);
+#else
+ return _tzcnt_u32(v);
+#endif
+#elif defined(__X86_ASM__)
+ size_t r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r;
+#else
+ return __builtin_ctzl(v);
+#endif
+ }
+
+ __forceinline int bscf(int& v)
+ {
+ int i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+
+#if defined(__64BIT__)
+ __forceinline unsigned int bscf(unsigned int& v)
+ {
+ unsigned int i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+#endif
+
+ __forceinline size_t bscf(size_t& v)
+ {
+ size_t i = bsf(v);
+ v &= v-1;
+ return i;
+ }
+
+ __forceinline int bsr(int v) {
+#if defined(__AVX2__)
+ return 31 - _lzcnt_u32(v);
+#elif defined(__X86_ASM__)
+ int r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r;
+#else
+ return __builtin_clz(v) ^ 31;
+#endif
+ }
+
+#if defined(__64BIT__)
+ __forceinline unsigned bsr(unsigned v) {
+#if defined(__AVX2__)
+ return 31 - _lzcnt_u32(v);
+#elif defined(__X86_ASM__)
+ unsigned r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r;
+#else
+ return __builtin_clz(v) ^ 31;
+#endif
+ }
+#endif
+
+ __forceinline size_t bsr(size_t v) {
+#if defined(__AVX2__)
+#if defined(__X86_64__)
+ return 63 - _lzcnt_u64(v);
+#else
+ return 31 - _lzcnt_u32(v);
+#endif
+#elif defined(__X86_ASM__)
+ size_t r = 0; asm ("bsr %1,%0" : "=r"(r) : "r"(v)); return r;
+#else
+ return (sizeof(v) * 8 - 1) - __builtin_clzl(v);
+#endif
+ }
+
+ __forceinline int lzcnt(const int x)
+ {
+#if defined(__AVX2__)
+ return _lzcnt_u32(x);
+#else
+ if (unlikely(x == 0)) return 32;
+ return 31 - bsr(x);
+#endif
+ }
+
+ __forceinline size_t blsr(size_t v) {
+#if defined(__AVX2__)
+#if defined(__INTEL_COMPILER)
+ return _blsr_u64(v);
+#else
+#if defined(__X86_64__)
+ return __blsr_u64(v);
+#else
+ return __blsr_u32(v);
+#endif
+#endif
+#else
+ return v & (v-1);
+#endif
+ }
+
+ __forceinline int btc(int v, int i) {
+#if defined(__X86_ASM__)
+ int r = 0; asm ("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags" ); return r;
+#else
+ return (v ^ (1 << i));
+#endif
+ }
+
+ __forceinline int bts(int v, int i) {
+#if defined(__X86_ASM__)
+ int r = 0; asm ("bts %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r;
+#else
+ return (v | (v << i));
+#endif
+ }
+
+ __forceinline int btr(int v, int i) {
+#if defined(__X86_ASM__)
+ int r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r;
+#else
+ return (v & ~(v << i));
+#endif
+ }
+
+ __forceinline size_t btc(size_t v, size_t i) {
+#if defined(__X86_ASM__)
+ size_t r = 0; asm ("btc %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags" ); return r;
+#else
+ return (v ^ (1 << i));
+#endif
+ }
+
+ __forceinline size_t bts(size_t v, size_t i) {
+#if defined(__X86_ASM__)
+ size_t r = 0; asm ("bts %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r;
+#else
+ return (v | (v << i));
+#endif
+ }
+
+ __forceinline size_t btr(size_t v, size_t i) {
+#if defined(__X86_ASM__)
+ size_t r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r;
+#else
+ return (v & ~(v << i));
+#endif
+ }
+
+ __forceinline int32_t atomic_cmpxchg(int32_t volatile* value, int32_t comparand, const int32_t input) {
+ return __sync_val_compare_and_swap(value, comparand, input);
+ }
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// All Platforms
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__clang__) || defined(__GNUC__)
+#if !defined(_mm_undefined_ps)
+ __forceinline __m128 _mm_undefined_ps() { return _mm_setzero_ps(); }
+#endif
+#if !defined(_mm_undefined_si128)
+ __forceinline __m128i _mm_undefined_si128() { return _mm_setzero_si128(); }
+#endif
+#if !defined(_mm256_undefined_ps) && defined(__AVX__)
+ __forceinline __m256 _mm256_undefined_ps() { return _mm256_setzero_ps(); }
+#endif
+#if !defined(_mm256_undefined_si256) && defined(__AVX__)
+ __forceinline __m256i _mm256_undefined_si256() { return _mm256_setzero_si256(); }
+#endif
+#if !defined(_mm512_undefined_ps) && defined(__AVX512F__)
+ __forceinline __m512 _mm512_undefined_ps() { return _mm512_setzero_ps(); }
+#endif
+#if !defined(_mm512_undefined_epi32) && defined(__AVX512F__)
+ __forceinline __m512i _mm512_undefined_epi32() { return _mm512_setzero_si512(); }
+#endif
+#endif
+
+#if defined(__SSE4_2__)
+
+ __forceinline int popcnt(int in) {
+ return _mm_popcnt_u32(in);
+ }
+
+ __forceinline unsigned popcnt(unsigned in) {
+ return _mm_popcnt_u32(in);
+ }
+
+#if defined(__64BIT__)
+ __forceinline size_t popcnt(size_t in) {
+ return _mm_popcnt_u64(in);
+ }
+#endif
+
+#endif
+
+#if defined(__X86_ASM__)
+ __forceinline uint64_t rdtsc()
+ {
+ int dummy[4];
+ __cpuid(dummy,0);
+ uint64_t clock = read_tsc();
+ __cpuid(dummy,0);
+ return clock;
+ }
+#endif
+
+ __forceinline void pause_cpu(const size_t N = 8)
+ {
+ for (size_t i=0; i<N; i++)
+ _mm_pause();
+ }
+
+ /* prefetches */
+ __forceinline void prefetchL1 (const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_T0); }
+ __forceinline void prefetchL2 (const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_T1); }
+ __forceinline void prefetchL3 (const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_T2); }
+ __forceinline void prefetchNTA(const void* ptr) { _mm_prefetch((const char*)ptr,_MM_HINT_NTA); }
+ __forceinline void prefetchEX (const void* ptr) {
+#if defined(__INTEL_COMPILER)
+ _mm_prefetch((const char*)ptr,_MM_HINT_ET0);
+#else
+ _mm_prefetch((const char*)ptr,_MM_HINT_T0);
+#endif
+ }
+
+ __forceinline void prefetchL1EX(const void* ptr) {
+ prefetchEX(ptr);
+ }
+
+ __forceinline void prefetchL2EX(const void* ptr) {
+ prefetchEX(ptr);
+ }
+#if defined(__AVX2__)
+ __forceinline unsigned int pext(unsigned int a, unsigned int b) { return _pext_u32(a, b); }
+ __forceinline unsigned int pdep(unsigned int a, unsigned int b) { return _pdep_u32(a, b); }
+#if defined(__X86_64__)
+ __forceinline size_t pext(size_t a, size_t b) { return _pext_u64(a, b); }
+ __forceinline size_t pdep(size_t a, size_t b) { return _pdep_u64(a, b); }
+#endif
+#endif
+
+#if defined(__AVX512F__)
+#if defined(__INTEL_COMPILER)
+ __forceinline float mm512_cvtss_f32(__m512 v) {
+ return _mm512_cvtss_f32(v);
+ }
+ __forceinline int mm512_mask2int(__mmask16 k1) {
+ return _mm512_mask2int(k1);
+ }
+ __forceinline __mmask16 mm512_int2mask(int mask) {
+ return _mm512_int2mask(mask);
+ }
+#else
+ __forceinline float mm512_cvtss_f32(__m512 v) { // FIXME: _mm512_cvtss_f32 neither supported by clang v4.0.0 nor GCC 6.3
+ return _mm_cvtss_f32(_mm512_castps512_ps128(v));
+ }
+ __forceinline int mm512_mask2int(__mmask16 k1) { // FIXME: _mm512_mask2int not yet supported by GCC 6.3
+ return (int)k1;
+ }
+ __forceinline __mmask16 mm512_int2mask(int mask) { // FIXME: _mm512_int2mask not yet supported by GCC 6.3
+ return (__mmask16)mask;
+ }
+#endif
+#endif
+}
diff --git a/thirdparty/embree/common/sys/library.cpp b/thirdparty/embree/common/sys/library.cpp
new file mode 100644
index 0000000000..fc983dffd5
--- /dev/null
+++ b/thirdparty/embree/common/sys/library.cpp
@@ -0,0 +1,83 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "library.h"
+#include "sysinfo.h"
+#include "filename.h"
+
+////////////////////////////////////////////////////////////////////////////////
+/// Windows Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__WIN32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace embree
+{
+ /* opens a shared library */
+ lib_t openLibrary(const std::string& file)
+ {
+ std::string fullName = file+".dll";
+ FileName executable = getExecutableFileName();
+ HANDLE handle = LoadLibrary((executable.path() + fullName).c_str());
+ return lib_t(handle);
+ }
+
+ /* returns address of a symbol from the library */
+ void* getSymbol(lib_t lib, const std::string& sym) {
+ return (void*)GetProcAddress(HMODULE(lib),sym.c_str());
+ }
+
+ /* closes the shared library */
+ void closeLibrary(lib_t lib) {
+ FreeLibrary(HMODULE(lib));
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unix Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__UNIX__)
+
+#include <dlfcn.h>
+
+namespace embree
+{
+ /* opens a shared library */
+ lib_t openLibrary(const std::string& file)
+ {
+#if defined(__MACOSX__)
+ std::string fullName = "lib"+file+".dylib";
+#else
+ std::string fullName = "lib"+file+".so";
+#endif
+ void* lib = dlopen(fullName.c_str(), RTLD_NOW);
+ if (lib) return lib_t(lib);
+ FileName executable = getExecutableFileName();
+ lib = dlopen((executable.path() + fullName).c_str(),RTLD_NOW);
+ if (lib == nullptr) {
+ const char* error = dlerror();
+ if (error) {
+ THROW_RUNTIME_ERROR(error);
+ } else {
+ THROW_RUNTIME_ERROR("could not load library "+executable.str());
+ }
+ }
+ return lib_t(lib);
+ }
+
+ /* returns address of a symbol from the library */
+ void* getSymbol(lib_t lib, const std::string& sym) {
+ return dlsym(lib,sym.c_str());
+ }
+
+ /* closes the shared library */
+ void closeLibrary(lib_t lib) {
+ dlclose(lib);
+ }
+}
+#endif
diff --git a/thirdparty/embree/common/sys/library.h b/thirdparty/embree/common/sys/library.h
new file mode 100644
index 0000000000..67e14d2420
--- /dev/null
+++ b/thirdparty/embree/common/sys/library.h
@@ -0,0 +1,21 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+
+namespace embree
+{
+ /*! type for shared library */
+ typedef struct opaque_lib_t* lib_t;
+
+ /*! loads a shared library */
+ lib_t openLibrary(const std::string& file);
+
+ /*! returns address of a symbol from the library */
+ void* getSymbol(lib_t lib, const std::string& sym);
+
+ /*! unloads a shared library */
+ void closeLibrary(lib_t lib);
+}
diff --git a/thirdparty/embree/common/sys/mutex.cpp b/thirdparty/embree/common/sys/mutex.cpp
new file mode 100644
index 0000000000..789feaf2d8
--- /dev/null
+++ b/thirdparty/embree/common/sys/mutex.cpp
@@ -0,0 +1,57 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "mutex.h"
+#include "regression.h"
+
+#if defined(__WIN32__) && !defined(PTHREADS_WIN32)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace embree
+{
+ MutexSys::MutexSys() { mutex = new CRITICAL_SECTION; InitializeCriticalSection((CRITICAL_SECTION*)mutex); }
+ MutexSys::~MutexSys() { DeleteCriticalSection((CRITICAL_SECTION*)mutex); delete (CRITICAL_SECTION*)mutex; }
+ void MutexSys::lock() { EnterCriticalSection((CRITICAL_SECTION*)mutex); }
+ bool MutexSys::try_lock() { return TryEnterCriticalSection((CRITICAL_SECTION*)mutex) != 0; }
+ void MutexSys::unlock() { LeaveCriticalSection((CRITICAL_SECTION*)mutex); }
+}
+#endif
+
+#if defined(__UNIX__) || defined(PTHREADS_WIN32)
+#include <pthread.h>
+namespace embree
+{
+ /*! system mutex using pthreads */
+ MutexSys::MutexSys()
+ {
+ mutex = new pthread_mutex_t;
+ if (pthread_mutex_init((pthread_mutex_t*)mutex, nullptr) != 0)
+ THROW_RUNTIME_ERROR("pthread_mutex_init failed");
+ }
+
+ MutexSys::~MutexSys()
+ {
+ MAYBE_UNUSED bool ok = pthread_mutex_destroy((pthread_mutex_t*)mutex) == 0;
+ assert(ok);
+ delete (pthread_mutex_t*)mutex;
+ }
+
+ void MutexSys::lock()
+ {
+ if (pthread_mutex_lock((pthread_mutex_t*)mutex) != 0)
+ THROW_RUNTIME_ERROR("pthread_mutex_lock failed");
+ }
+
+ bool MutexSys::try_lock() {
+ return pthread_mutex_trylock((pthread_mutex_t*)mutex) == 0;
+ }
+
+ void MutexSys::unlock()
+ {
+ if (pthread_mutex_unlock((pthread_mutex_t*)mutex) != 0)
+ THROW_RUNTIME_ERROR("pthread_mutex_unlock failed");
+ }
+};
+#endif
diff --git a/thirdparty/embree/common/sys/mutex.h b/thirdparty/embree/common/sys/mutex.h
new file mode 100644
index 0000000000..4cb3626d92
--- /dev/null
+++ b/thirdparty/embree/common/sys/mutex.h
@@ -0,0 +1,98 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+#include "intrinsics.h"
+#include "atomic.h"
+
+namespace embree
+{
+ /*! system mutex */
+ class MutexSys {
+ friend struct ConditionImplementation;
+ public:
+ MutexSys();
+ ~MutexSys();
+
+ private:
+ MutexSys (const MutexSys& other) DELETED; // do not implement
+ MutexSys& operator= (const MutexSys& other) DELETED; // do not implement
+
+ public:
+ void lock();
+ bool try_lock();
+ void unlock();
+
+ protected:
+ void* mutex;
+ };
+
+ /*! spinning mutex */
+ class SpinLock
+ {
+ public:
+
+ SpinLock ()
+ : flag(false) {}
+
+ __forceinline bool isLocked() {
+ return flag.load();
+ }
+
+ __forceinline void lock()
+ {
+ while (true)
+ {
+ while (flag.load())
+ {
+ _mm_pause();
+ _mm_pause();
+ }
+
+ bool expected = false;
+ if (flag.compare_exchange_strong(expected,true,std::memory_order_acquire))
+ break;
+ }
+ }
+
+ __forceinline bool try_lock()
+ {
+ bool expected = false;
+ if (flag.load() != expected) {
+ return false;
+ }
+ return flag.compare_exchange_strong(expected,true,std::memory_order_acquire);
+ }
+
+ __forceinline void unlock() {
+ flag.store(false,std::memory_order_release);
+ }
+
+ __forceinline void wait_until_unlocked()
+ {
+ while(flag.load())
+ {
+ _mm_pause();
+ _mm_pause();
+ }
+ }
+
+ public:
+ atomic<bool> flag;
+ };
+
+ /*! safe mutex lock and unlock helper */
+ template<typename Mutex> class Lock {
+ public:
+ Lock (Mutex& mutex) : mutex(mutex), locked(true) { mutex.lock(); }
+ Lock (Mutex& mutex, bool locked) : mutex(mutex), locked(locked) {}
+ ~Lock() { if (locked) mutex.unlock(); }
+ __forceinline void lock() { assert(!locked); locked = true; mutex.lock(); }
+ __forceinline bool isLocked() const { return locked; }
+ protected:
+ Mutex& mutex;
+ bool locked;
+ };
+}
diff --git a/thirdparty/embree/common/sys/platform.h b/thirdparty/embree/common/sys/platform.h
new file mode 100644
index 0000000000..697e07bb86
--- /dev/null
+++ b/thirdparty/embree/common/sys/platform.h
@@ -0,0 +1,392 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <cstddef>
+#include <cassert>
+#include <cstdlib>
+#include <cstdio>
+#include <memory>
+#include <stdexcept>
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <string>
+#include <cstring>
+#include <stdint.h>
+#include <functional>
+
+////////////////////////////////////////////////////////////////////////////////
+/// detect platform
+////////////////////////////////////////////////////////////////////////////////
+
+/* detect 32 or 64 Intel platform */
+#if defined(__x86_64__) || defined(__ia64__) || defined(_M_X64)
+#define __X86_64__
+#define __X86_ASM__
+#elif defined(__i386__) || defined(_M_IX86)
+#define __X86_ASM__
+#endif
+
+/* detect 64 bit platform */
+#if defined(__X86_64__) || defined(__aarch64__)
+#define __64BIT__
+#endif
+
+/* detect Linux platform */
+#if defined(linux) || defined(__linux__) || defined(__LINUX__)
+# if !defined(__LINUX__)
+# define __LINUX__
+# endif
+# if !defined(__UNIX__)
+# define __UNIX__
+# endif
+#endif
+
+/* detect FreeBSD platform */
+#if defined(__FreeBSD__) || defined(__FREEBSD__)
+# if !defined(__FREEBSD__)
+# define __FREEBSD__
+# endif
+# if !defined(__UNIX__)
+# define __UNIX__
+# endif
+#endif
+
+/* detect Windows 95/98/NT/2000/XP/Vista/7/8/10 platform */
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) && !defined(__CYGWIN__)
+# if !defined(__WIN32__)
+# define __WIN32__
+# endif
+#endif
+
+/* detect Cygwin platform */
+#if defined(__CYGWIN__)
+# if !defined(__UNIX__)
+# define __UNIX__
+# endif
+#endif
+
+/* detect MAC OS X platform */
+#if defined(__APPLE__) || defined(MACOSX) || defined(__MACOSX__)
+# if !defined(__MACOSX__)
+# define __MACOSX__
+# endif
+# if !defined(__UNIX__)
+# define __UNIX__
+# endif
+#endif
+
+/* try to detect other Unix systems */
+#if defined(__unix__) || defined (unix) || defined(__unix) || defined(_unix)
+# if !defined(__UNIX__)
+# define __UNIX__
+# endif
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Macros
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __WIN32__
+#define dll_export __declspec(dllexport)
+#define dll_import __declspec(dllimport)
+#else
+#define dll_export __attribute__ ((visibility ("default")))
+#define dll_import
+#endif
+
+// -- GODOT start --
+#if defined(__WIN32__) && !defined(__MINGW32__)
+// -- GODOT end --
+#if !defined(__noinline)
+#define __noinline __declspec(noinline)
+#endif
+//#define __forceinline __forceinline
+//#define __restrict __restrict
+#if defined(__INTEL_COMPILER)
+#define __restrict__ __restrict
+#else
+#define __restrict__ //__restrict // causes issues with MSVC
+#endif
+#if !defined(__thread)
+#define __thread __declspec(thread)
+#endif
+#if !defined(__aligned)
+#define __aligned(...) __declspec(align(__VA_ARGS__))
+#endif
+//#define __FUNCTION__ __FUNCTION__
+#define debugbreak() __debugbreak()
+
+#else
+#if !defined(__noinline)
+#define __noinline __attribute__((noinline))
+#endif
+#if !defined(__forceinline)
+#define __forceinline inline __attribute__((always_inline))
+#endif
+//#define __restrict __restrict
+//#define __thread __thread
+#if !defined(__aligned)
+#define __aligned(...) __attribute__((aligned(__VA_ARGS__)))
+#endif
+#if !defined(__FUNCTION__)
+#define __FUNCTION__ __PRETTY_FUNCTION__
+#endif
+#define debugbreak() asm ("int $3")
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+ #define MAYBE_UNUSED __attribute__((unused))
+#else
+ #define MAYBE_UNUSED
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900) // before VS2015 deleted functions are not supported properly
+ #define DELETED
+#else
+ #define DELETED = delete
+#endif
+
+// -- GODOT start --
+#if !defined(likely)
+// -- GODOT end --
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+#define likely(expr) (expr)
+#define unlikely(expr) (expr)
+#else
+#define likely(expr) __builtin_expect((bool)(expr),true )
+#define unlikely(expr) __builtin_expect((bool)(expr),false)
+#endif
+// -- GODOT start --
+#endif
+// -- GODOT end --
+
+////////////////////////////////////////////////////////////////////////////////
+/// Error handling and debugging
+////////////////////////////////////////////////////////////////////////////////
+
+/* debug printing macros */
+#define STRING(x) #x
+#define TOSTRING(x) STRING(x)
+#define PING embree_cout << __FILE__ << " (" << __LINE__ << "): " << __FUNCTION__ << embree_endl
+#define PRINT(x) embree_cout << STRING(x) << " = " << (x) << embree_endl
+#define PRINT2(x,y) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << embree_endl
+#define PRINT3(x,y,z) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << embree_endl
+#define PRINT4(x,y,z,w) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << ", " << STRING(w) << " = " << (w) << embree_endl
+
+#if defined(DEBUG) // only report file and line in debug mode
+ // -- GODOT start --
+ // #define THROW_RUNTIME_ERROR(str)
+ // throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
+ #define THROW_RUNTIME_ERROR(str) \
+ printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
+ // -- GODOT end --
+#else
+ // -- GODOT start --
+ // #define THROW_RUNTIME_ERROR(str)
+ // throw std::runtime_error(str);
+ #define THROW_RUNTIME_ERROR(str) \
+ abort();
+ // -- GODOT end --
+#endif
+
+#define FATAL(x) THROW_RUNTIME_ERROR(x)
+#define WARNING(x) { std::cerr << "Warning: " << x << embree_endl << std::flush; }
+
+#define NOT_IMPLEMENTED FATAL(std::string(__FUNCTION__) + " not implemented")
+
+////////////////////////////////////////////////////////////////////////////////
+/// Basic types
+////////////////////////////////////////////////////////////////////////////////
+
+/* default floating-point type */
+namespace embree {
+ typedef float real;
+}
+
+/* windows does not have ssize_t */
+#if defined(__WIN32__)
+#if defined(__64BIT__)
+typedef int64_t ssize_t;
+#else
+typedef int32_t ssize_t;
+#endif
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Basic utility functions
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline std::string toString(long long value) {
+ return std::to_string(value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Disable some compiler warnings
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__INTEL_COMPILER)
+//#pragma warning(disable:265 ) // floating-point operation result is out of range
+//#pragma warning(disable:383 ) // value copied to temporary, reference to temporary used
+//#pragma warning(disable:869 ) // parameter was never referenced
+//#pragma warning(disable:981 ) // operands are evaluated in unspecified order
+//#pragma warning(disable:1418) // external function definition with no prior declaration
+//#pragma warning(disable:1419) // external declaration in primary source file
+//#pragma warning(disable:1572) // floating-point equality and inequality comparisons are unreliable
+//#pragma warning(disable:94 ) // the size of an array must be greater than zero
+//#pragma warning(disable:1599) // declaration hides parameter
+//#pragma warning(disable:424 ) // extra ";" ignored
+#pragma warning(disable:2196) // routine is both "inline" and "noinline"
+//#pragma warning(disable:177 ) // label was declared but never referenced
+//#pragma warning(disable:114 ) // function was referenced but not defined
+//#pragma warning(disable:819 ) // template nesting depth does not match the previous declaration of function
+#pragma warning(disable:15335) // was not vectorized: vectorization possible but seems inefficient
+#endif
+
+#if defined(_MSC_VER)
+//#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union
+#pragma warning(disable:4800) // forcing value to bool 'true' or 'false' (performance warning)
+//#pragma warning(disable:4267) // '=' : conversion from 'size_t' to 'unsigned long', possible loss of data
+#pragma warning(disable:4244) // 'argument' : conversion from 'ssize_t' to 'unsigned int', possible loss of data
+//#pragma warning(disable:4355) // 'this' : used in base member initializer list
+//#pragma warning(disable:391 ) // '<=' : signed / unsigned mismatch
+//#pragma warning(disable:4018) // '<' : signed / unsigned mismatch
+//#pragma warning(disable:4305) // 'initializing' : truncation from 'double' to 'float'
+//#pragma warning(disable:4068) // unknown pragma
+//#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
+//#pragma warning(disable:4838) // conversion from 'unsigned int' to 'const int' requires a narrowing conversion)
+//#pragma warning(disable:4227) // anachronism used : qualifiers on reference are ignored
+#pragma warning(disable:4503) // decorated name length exceeded, name was truncated
+#pragma warning(disable:4180) // qualifier applied to function type has no meaning; ignored
+#pragma warning(disable:4258) // definition from the for loop is ignored; the definition from the enclosing scope is used
+
+# if _MSC_VER < 1910 // prior to Visual studio 2017 (V141)
+# pragma warning(disable:4101) // warning C4101: 'x': unreferenced local variable // a compiler bug issues wrong warnings
+# pragma warning(disable:4789) // buffer '' of size 8 bytes will be overrun; 32 bytes will be written starting at offset 0
+# endif
+
+#endif
+
+#if defined(__clang__) && !defined(__INTEL_COMPILER)
+//#pragma clang diagnostic ignored "-Wunknown-pragmas"
+//#pragma clang diagnostic ignored "-Wunused-variable"
+//#pragma clang diagnostic ignored "-Wreorder"
+//#pragma clang diagnostic ignored "-Wmicrosoft"
+//#pragma clang diagnostic ignored "-Wunused-private-field"
+//#pragma clang diagnostic ignored "-Wunused-local-typedef"
+//#pragma clang diagnostic ignored "-Wunused-function"
+//#pragma clang diagnostic ignored "-Wnarrowing"
+//#pragma clang diagnostic ignored "-Wc++11-narrowing"
+//#pragma clang diagnostic ignored "-Wdeprecated-register"
+//#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
+#pragma GCC diagnostic ignored "-Wpragmas"
+//#pragma GCC diagnostic ignored "-Wnarrowing"
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+//#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+//#pragma GCC diagnostic ignored "-Warray-bounds"
+#pragma GCC diagnostic ignored "-Wattributes"
+#pragma GCC diagnostic ignored "-Wmisleading-indentation"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wparentheses"
+#endif
+
+#if defined(__clang__) && defined(__WIN32__)
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wmicrosoft-cast"
+#pragma clang diagnostic ignored "-Wmicrosoft-enum-value"
+#pragma clang diagnostic ignored "-Wmicrosoft-include"
+#pragma clang diagnostic ignored "-Wunused-function"
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#endif
+
+/* disabling deprecated warning, please use only where use of deprecated Embree API functions is desired */
+#if defined(__WIN32__) && defined(__INTEL_COMPILER)
+#define DISABLE_DEPRECATED_WARNING __pragma(warning (disable: 1478)) // warning: function was declared deprecated
+#define ENABLE_DEPRECATED_WARNING __pragma(warning (enable: 1478)) // warning: function was declared deprecated
+#elif defined(__INTEL_COMPILER)
+#define DISABLE_DEPRECATED_WARNING _Pragma("warning (disable: 1478)") // warning: function was declared deprecated
+#define ENABLE_DEPRECATED_WARNING _Pragma("warning (enable : 1478)") // warning: function was declared deprecated
+#elif defined(__clang__)
+#define DISABLE_DEPRECATED_WARNING _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") // warning: xxx is deprecated
+#define ENABLE_DEPRECATED_WARNING _Pragma("clang diagnostic warning \"-Wdeprecated-declarations\"") // warning: xxx is deprecated
+#elif defined(__GNUC__)
+#define DISABLE_DEPRECATED_WARNING _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") // warning: xxx is deprecated
+#define ENABLE_DEPRECATED_WARNING _Pragma("GCC diagnostic warning \"-Wdeprecated-declarations\"") // warning: xxx is deprecated
+#elif defined(_MSC_VER)
+#define DISABLE_DEPRECATED_WARNING __pragma(warning (disable: 4996)) // warning: function was declared deprecated
+#define ENABLE_DEPRECATED_WARNING __pragma(warning (enable : 4996)) // warning: function was declared deprecated
+#endif
+
+/* embree output stream */
+#define embree_ostream std::ostream&
+#define embree_cout std::cout
+#define embree_cout_uniform std::cout
+#define embree_endl std::endl
+
+////////////////////////////////////////////////////////////////////////////////
+/// Some macros for static profiling
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined (__GNUC__)
+#define IACA_SSC_MARK( MARK_ID ) \
+__asm__ __volatile__ ( \
+ "\n\t movl $"#MARK_ID", %%ebx" \
+ "\n\t .byte 0x64, 0x67, 0x90" \
+ : : : "memory" );
+
+#define IACA_UD_BYTES __asm__ __volatile__ ("\n\t .byte 0x0F, 0x0B");
+
+#else
+#define IACA_UD_BYTES {__asm _emit 0x0F \
+ __asm _emit 0x0B}
+
+#define IACA_SSC_MARK(x) {__asm mov ebx, x\
+ __asm _emit 0x64 \
+ __asm _emit 0x67 \
+ __asm _emit 0x90 }
+
+#define IACA_VC64_START __writegsbyte(111, 111);
+#define IACA_VC64_END __writegsbyte(222, 222);
+
+#endif
+
+#define IACA_START {IACA_UD_BYTES \
+ IACA_SSC_MARK(111)}
+#define IACA_END {IACA_SSC_MARK(222) \
+ IACA_UD_BYTES}
+
+namespace embree
+{
+ template<typename Closure>
+ struct OnScopeExitHelper
+ {
+ OnScopeExitHelper (const Closure f) : active(true), f(f) {}
+ ~OnScopeExitHelper() { if (active) f(); }
+ void deactivate() { active = false; }
+ bool active;
+ const Closure f;
+ };
+
+ template <typename Closure>
+ OnScopeExitHelper<Closure> OnScopeExit(const Closure f) {
+ return OnScopeExitHelper<Closure>(f);
+ }
+
+#define STRING_JOIN2(arg1, arg2) DO_STRING_JOIN2(arg1, arg2)
+#define DO_STRING_JOIN2(arg1, arg2) arg1 ## arg2
+#define ON_SCOPE_EXIT(code) \
+ auto STRING_JOIN2(on_scope_exit_, __LINE__) = OnScopeExit([&](){code;})
+
+ template<typename Ty>
+ std::unique_ptr<Ty> make_unique(Ty* ptr) {
+ return std::unique_ptr<Ty>(ptr);
+ }
+
+}
diff --git a/thirdparty/embree/common/sys/ref.h b/thirdparty/embree/common/sys/ref.h
new file mode 100644
index 0000000000..c2b56c1908
--- /dev/null
+++ b/thirdparty/embree/common/sys/ref.h
@@ -0,0 +1,122 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "atomic.h"
+
+namespace embree
+{
+ struct NullTy {
+ };
+
+ extern MAYBE_UNUSED NullTy null;
+
+ class RefCount
+ {
+ public:
+ RefCount(int val = 0) : refCounter(val) {}
+ virtual ~RefCount() {};
+
+ virtual RefCount* refInc() { refCounter.fetch_add(1); return this; }
+ virtual void refDec() { if (refCounter.fetch_add(-1) == 1) delete this; }
+ private:
+ std::atomic<size_t> refCounter;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Reference to single object
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<typename Type>
+ class Ref
+ {
+ public:
+ Type* ptr;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Constructors, Assignment & Cast Operators
+ ////////////////////////////////////////////////////////////////////////////////
+
+ __forceinline Ref() : ptr(nullptr) {}
+ __forceinline Ref(NullTy) : ptr(nullptr) {}
+ __forceinline Ref(const Ref& input) : ptr(input.ptr) { if (ptr) ptr->refInc(); }
+ __forceinline Ref(Ref&& input) : ptr(input.ptr) { input.ptr = nullptr; }
+
+ __forceinline Ref(Type* const input) : ptr(input)
+ {
+ if (ptr)
+ ptr->refInc();
+ }
+
+ __forceinline ~Ref()
+ {
+ if (ptr)
+ ptr->refDec();
+ }
+
+ __forceinline Ref& operator =(const Ref& input)
+ {
+ if (input.ptr)
+ input.ptr->refInc();
+ if (ptr)
+ ptr->refDec();
+ ptr = input.ptr;
+ return *this;
+ }
+
+ __forceinline Ref& operator =(Ref&& input)
+ {
+ if (ptr)
+ ptr->refDec();
+ ptr = input.ptr;
+ input.ptr = nullptr;
+ return *this;
+ }
+
+ __forceinline Ref& operator =(Type* const input)
+ {
+ if (input)
+ input->refInc();
+ if (ptr)
+ ptr->refDec();
+ ptr = input;
+ return *this;
+ }
+
+ __forceinline Ref& operator =(NullTy)
+ {
+ if (ptr)
+ ptr->refDec();
+ ptr = nullptr;
+ return *this;
+ }
+
+ __forceinline operator bool() const { return ptr != nullptr; }
+
+ __forceinline const Type& operator *() const { return *ptr; }
+ __forceinline Type& operator *() { return *ptr; }
+ __forceinline const Type* operator ->() const { return ptr; }
+ __forceinline Type* operator ->() { return ptr; }
+
+ template<typename TypeOut>
+ __forceinline Ref<TypeOut> cast() { return Ref<TypeOut>(static_cast<TypeOut*>(ptr)); }
+ template<typename TypeOut>
+ __forceinline const Ref<TypeOut> cast() const { return Ref<TypeOut>(static_cast<TypeOut*>(ptr)); }
+
+ template<typename TypeOut>
+ __forceinline Ref<TypeOut> dynamicCast() { return Ref<TypeOut>(dynamic_cast<TypeOut*>(ptr)); }
+ template<typename TypeOut>
+ __forceinline const Ref<TypeOut> dynamicCast() const { return Ref<TypeOut>(dynamic_cast<TypeOut*>(ptr)); }
+ };
+
+ template<typename Type> __forceinline bool operator < (const Ref<Type>& a, const Ref<Type>& b) { return a.ptr < b.ptr; }
+
+ template<typename Type> __forceinline bool operator ==(const Ref<Type>& a, NullTy ) { return a.ptr == nullptr; }
+ template<typename Type> __forceinline bool operator ==(NullTy , const Ref<Type>& b) { return nullptr == b.ptr; }
+ template<typename Type> __forceinline bool operator ==(const Ref<Type>& a, const Ref<Type>& b) { return a.ptr == b.ptr; }
+
+ template<typename Type> __forceinline bool operator !=(const Ref<Type>& a, NullTy ) { return a.ptr != nullptr; }
+ template<typename Type> __forceinline bool operator !=(NullTy , const Ref<Type>& b) { return nullptr != b.ptr; }
+ template<typename Type> __forceinline bool operator !=(const Ref<Type>& a, const Ref<Type>& b) { return a.ptr != b.ptr; }
+}
diff --git a/thirdparty/embree/common/sys/regression.cpp b/thirdparty/embree/common/sys/regression.cpp
new file mode 100644
index 0000000000..45315b1105
--- /dev/null
+++ b/thirdparty/embree/common/sys/regression.cpp
@@ -0,0 +1,30 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "regression.h"
+
+namespace embree
+{
+ /* registerRegressionTest is invoked from static initializers, thus
+ * we cannot have the regression_tests variable as global static
+ * variable due to issues with static variable initialization
+ * order. */
+ std::vector<RegressionTest*>& get_regression_tests()
+ {
+ static std::vector<RegressionTest*> regression_tests;
+ return regression_tests;
+ }
+
+ void registerRegressionTest(RegressionTest* test)
+ {
+ get_regression_tests().push_back(test);
+ }
+
+ RegressionTest* getRegressionTest(size_t index)
+ {
+ if (index >= get_regression_tests().size())
+ return nullptr;
+
+ return get_regression_tests()[index];
+ }
+}
diff --git a/thirdparty/embree/common/sys/regression.h b/thirdparty/embree/common/sys/regression.h
new file mode 100644
index 0000000000..bb0bb94006
--- /dev/null
+++ b/thirdparty/embree/common/sys/regression.h
@@ -0,0 +1,25 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+
+#include <vector>
+
+namespace embree
+{
+ /*! virtual interface for all regression tests */
+ struct RegressionTest
+ {
+ RegressionTest (std::string name) : name(name) {}
+ virtual bool run() = 0;
+ std::string name;
+ };
+
+ /*! registers a regression test */
+ void registerRegressionTest(RegressionTest* test);
+
+ /*! run all regression tests */
+ RegressionTest* getRegressionTest(size_t index);
+}
diff --git a/thirdparty/embree/common/sys/string.cpp b/thirdparty/embree/common/sys/string.cpp
new file mode 100644
index 0000000000..f42fdc8536
--- /dev/null
+++ b/thirdparty/embree/common/sys/string.cpp
@@ -0,0 +1,42 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "string.h"
+
+#include <algorithm>
+#include <ctype.h>
+
+namespace embree
+{
+ char to_lower(char c) { return char(tolower(int(c))); }
+ char to_upper(char c) { return char(toupper(int(c))); }
+ std::string toLowerCase(const std::string& s) { std::string dst(s); std::transform(dst.begin(), dst.end(), dst.begin(), to_lower); return dst; }
+ std::string toUpperCase(const std::string& s) { std::string dst(s); std::transform(dst.begin(), dst.end(), dst.begin(), to_upper); return dst; }
+
+ Vec2f string_to_Vec2f ( std::string str )
+ {
+ size_t next = 0;
+ const float x = std::stof(str,&next); str = str.substr(next+1);
+ const float y = std::stof(str,&next);
+ return Vec2f(x,y);
+ }
+
+ Vec3f string_to_Vec3f ( std::string str )
+ {
+ size_t next = 0;
+ const float x = std::stof(str,&next); str = str.substr(next+1);
+ const float y = std::stof(str,&next); str = str.substr(next+1);
+ const float z = std::stof(str,&next);
+ return Vec3f(x,y,z);
+ }
+
+ Vec4f string_to_Vec4f ( std::string str )
+ {
+ size_t next = 0;
+ const float x = std::stof(str,&next); str = str.substr(next+1);
+ const float y = std::stof(str,&next); str = str.substr(next+1);
+ const float z = std::stof(str,&next); str = str.substr(next+1);
+ const float w = std::stof(str,&next);
+ return Vec4f(x,y,z,w);
+ }
+}
diff --git a/thirdparty/embree/common/sys/string.h b/thirdparty/embree/common/sys/string.h
new file mode 100644
index 0000000000..820076b21c
--- /dev/null
+++ b/thirdparty/embree/common/sys/string.h
@@ -0,0 +1,37 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+#include "../math/vec2.h"
+#include "../math/vec3.h"
+#include "../math/vec4.h"
+
+namespace embree
+{
+ class IOStreamStateRestorer
+ {
+ public:
+ IOStreamStateRestorer(std::ostream& iostream)
+ : iostream(iostream), flags(iostream.flags()), precision(iostream.precision()) {
+ }
+
+ ~IOStreamStateRestorer() {
+ iostream.flags(flags);
+ iostream.precision(precision);
+ }
+
+ private:
+ std::ostream& iostream;
+ std::ios::fmtflags flags;
+ std::streamsize precision;
+ };
+
+ std::string toLowerCase(const std::string& s);
+ std::string toUpperCase(const std::string& s);
+
+ Vec2f string_to_Vec2f ( std::string str );
+ Vec3f string_to_Vec3f ( std::string str );
+ Vec4f string_to_Vec4f ( std::string str );
+}
diff --git a/thirdparty/embree/common/sys/sysinfo.cpp b/thirdparty/embree/common/sys/sysinfo.cpp
new file mode 100644
index 0000000000..f1a59e511e
--- /dev/null
+++ b/thirdparty/embree/common/sys/sysinfo.cpp
@@ -0,0 +1,656 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sysinfo.h"
+#include "intrinsics.h"
+#include "string.h"
+#include "ref.h"
+#if defined(__FREEBSD__)
+#include <sys/cpuset.h>
+#include <pthread_np.h>
+typedef cpuset_t cpu_set_t;
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// All Platforms
+////////////////////////////////////////////////////////////////////////////////
+
+namespace embree
+{
+ NullTy null;
+
+ std::string getPlatformName()
+ {
+#if defined(__LINUX__) && !defined(__64BIT__)
+ return "Linux (32bit)";
+#elif defined(__LINUX__) && defined(__64BIT__)
+ return "Linux (64bit)";
+#elif defined(__FREEBSD__) && !defined(__64BIT__)
+ return "FreeBSD (32bit)";
+#elif defined(__FREEBSD__) && defined(__64BIT__)
+ return "FreeBSD (64bit)";
+#elif defined(__CYGWIN__) && !defined(__64BIT__)
+ return "Cygwin (32bit)";
+#elif defined(__CYGWIN__) && defined(__64BIT__)
+ return "Cygwin (64bit)";
+#elif defined(__WIN32__) && !defined(__64BIT__)
+ return "Windows (32bit)";
+#elif defined(__WIN32__) && defined(__64BIT__)
+ return "Windows (64bit)";
+#elif defined(__MACOSX__) && !defined(__64BIT__)
+ return "Mac OS X (32bit)";
+#elif defined(__MACOSX__) && defined(__64BIT__)
+ return "Mac OS X (64bit)";
+#elif defined(__UNIX__) && !defined(__64BIT__)
+ return "Unix (32bit)";
+#elif defined(__UNIX__) && defined(__64BIT__)
+ return "Unix (64bit)";
+#else
+ return "Unknown";
+#endif
+ }
+
+ std::string getCompilerName()
+ {
+#if defined(__INTEL_COMPILER)
+ int icc_mayor = __INTEL_COMPILER / 100 % 100;
+ int icc_minor = __INTEL_COMPILER % 100;
+ std::string version = "Intel Compiler ";
+ version += toString(icc_mayor);
+ version += "." + toString(icc_minor);
+#if defined(__INTEL_COMPILER_UPDATE)
+ version += "." + toString(__INTEL_COMPILER_UPDATE);
+#endif
+ return version;
+#elif defined(__clang__)
+ return "CLANG " __clang_version__;
+#elif defined (__GNUC__)
+ return "GCC " __VERSION__;
+#elif defined(_MSC_VER)
+ std::string version = toString(_MSC_FULL_VER);
+ version.insert(4,".");
+ version.insert(9,".");
+ version.insert(2,".");
+ return "Visual C++ Compiler " + version;
+#else
+ return "Unknown Compiler";
+#endif
+ }
+
+ std::string getCPUVendor()
+ {
+#if defined(__X86_ASM__)
+ int cpuinfo[4];
+ __cpuid (cpuinfo, 0);
+ int name[4];
+ name[0] = cpuinfo[1];
+ name[1] = cpuinfo[3];
+ name[2] = cpuinfo[2];
+ name[3] = 0;
+ return (char*)name;
+#elif defined(__ARM_NEON)
+ return "ARM";
+#else
+ return "Unknown";
+#endif
+ }
+
+ CPU getCPUModel()
+ {
+#if defined(__X86_ASM__)
+ if (getCPUVendor() != "GenuineIntel")
+ return CPU::UNKNOWN;
+
+ int out[4];
+ __cpuid(out, 0);
+ if (out[0] < 1) return CPU::UNKNOWN;
+ __cpuid(out, 1);
+
+ /* please see CPUID documentation for these formulas */
+ uint32_t family_ID = (out[0] >> 8) & 0x0F;
+ uint32_t extended_family_ID = (out[0] >> 20) & 0xFF;
+
+ uint32_t model_ID = (out[0] >> 4) & 0x0F;
+ uint32_t extended_model_ID = (out[0] >> 16) & 0x0F;
+
+ uint32_t DisplayFamily = family_ID;
+ if (family_ID == 0x0F)
+ DisplayFamily += extended_family_ID;
+
+ uint32_t DisplayModel = model_ID;
+ if (family_ID == 0x06 || family_ID == 0x0F)
+ DisplayModel += extended_model_ID << 4;
+
+ uint32_t DisplayFamily_DisplayModel = (DisplayFamily << 8) + (DisplayModel << 0);
+
+ // Data from Intel® 64 and IA-32 Architectures, Volume 4, Chapter 2, Table 2-1 (CPUID Signature Values of DisplayFamily_DisplayModel)
+ if (DisplayFamily_DisplayModel == 0x067D) return CPU::CORE_ICE_LAKE;
+ if (DisplayFamily_DisplayModel == 0x067E) return CPU::CORE_ICE_LAKE;
+ if (DisplayFamily_DisplayModel == 0x068C) return CPU::CORE_TIGER_LAKE;
+ if (DisplayFamily_DisplayModel == 0x06A5) return CPU::CORE_COMET_LAKE;
+ if (DisplayFamily_DisplayModel == 0x06A6) return CPU::CORE_COMET_LAKE;
+ if (DisplayFamily_DisplayModel == 0x0666) return CPU::CORE_CANNON_LAKE;
+ if (DisplayFamily_DisplayModel == 0x068E) return CPU::CORE_KABY_LAKE;
+ if (DisplayFamily_DisplayModel == 0x069E) return CPU::CORE_KABY_LAKE;
+ if (DisplayFamily_DisplayModel == 0x066A) return CPU::XEON_ICE_LAKE;
+ if (DisplayFamily_DisplayModel == 0x066C) return CPU::XEON_ICE_LAKE;
+ if (DisplayFamily_DisplayModel == 0x0655) return CPU::XEON_SKY_LAKE;
+ if (DisplayFamily_DisplayModel == 0x064E) return CPU::CORE_SKY_LAKE;
+ if (DisplayFamily_DisplayModel == 0x065E) return CPU::CORE_SKY_LAKE;
+ if (DisplayFamily_DisplayModel == 0x0656) return CPU::XEON_BROADWELL;
+ if (DisplayFamily_DisplayModel == 0x064F) return CPU::XEON_BROADWELL;
+ if (DisplayFamily_DisplayModel == 0x0647) return CPU::CORE_BROADWELL;
+ if (DisplayFamily_DisplayModel == 0x063D) return CPU::CORE_BROADWELL;
+ if (DisplayFamily_DisplayModel == 0x063F) return CPU::XEON_HASWELL;
+ if (DisplayFamily_DisplayModel == 0x063C) return CPU::CORE_HASWELL;
+ if (DisplayFamily_DisplayModel == 0x0645) return CPU::CORE_HASWELL;
+ if (DisplayFamily_DisplayModel == 0x0646) return CPU::CORE_HASWELL;
+ if (DisplayFamily_DisplayModel == 0x063E) return CPU::XEON_IVY_BRIDGE;
+ if (DisplayFamily_DisplayModel == 0x063A) return CPU::CORE_IVY_BRIDGE;
+ if (DisplayFamily_DisplayModel == 0x062D) return CPU::SANDY_BRIDGE;
+ if (DisplayFamily_DisplayModel == 0x062F) return CPU::SANDY_BRIDGE;
+ if (DisplayFamily_DisplayModel == 0x062A) return CPU::SANDY_BRIDGE;
+ if (DisplayFamily_DisplayModel == 0x062E) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x0625) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x062C) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x061E) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x061F) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x061A) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x061D) return CPU::NEHALEM;
+ if (DisplayFamily_DisplayModel == 0x0617) return CPU::CORE2;
+ if (DisplayFamily_DisplayModel == 0x060F) return CPU::CORE2;
+ if (DisplayFamily_DisplayModel == 0x060E) return CPU::CORE1;
+
+ if (DisplayFamily_DisplayModel == 0x0685) return CPU::XEON_PHI_KNIGHTS_MILL;
+ if (DisplayFamily_DisplayModel == 0x0657) return CPU::XEON_PHI_KNIGHTS_LANDING;
+
+#elif defined(__ARM_NEON)
+ return CPU::ARM;
+#endif
+
+ return CPU::UNKNOWN;
+ }
+
+ std::string stringOfCPUModel(CPU model)
+ {
+ switch (model) {
+ case CPU::XEON_ICE_LAKE : return "Xeon Ice Lake";
+ case CPU::CORE_ICE_LAKE : return "Core Ice Lake";
+ case CPU::CORE_TIGER_LAKE : return "Core Tiger Lake";
+ case CPU::CORE_COMET_LAKE : return "Core Comet Lake";
+ case CPU::CORE_CANNON_LAKE : return "Core Cannon Lake";
+ case CPU::CORE_KABY_LAKE : return "Core Kaby Lake";
+ case CPU::XEON_SKY_LAKE : return "Xeon Sky Lake";
+ case CPU::CORE_SKY_LAKE : return "Core Sky Lake";
+ case CPU::XEON_PHI_KNIGHTS_MILL : return "Xeon Phi Knights Mill";
+ case CPU::XEON_PHI_KNIGHTS_LANDING: return "Xeon Phi Knights Landing";
+ case CPU::XEON_BROADWELL : return "Xeon Broadwell";
+ case CPU::CORE_BROADWELL : return "Core Broadwell";
+ case CPU::XEON_HASWELL : return "Xeon Haswell";
+ case CPU::CORE_HASWELL : return "Core Haswell";
+ case CPU::XEON_IVY_BRIDGE : return "Xeon Ivy Bridge";
+ case CPU::CORE_IVY_BRIDGE : return "Core Ivy Bridge";
+ case CPU::SANDY_BRIDGE : return "Sandy Bridge";
+ case CPU::NEHALEM : return "Nehalem";
+ case CPU::CORE2 : return "Core2";
+ case CPU::CORE1 : return "Core";
+ case CPU::ARM : return "ARM";
+ case CPU::UNKNOWN : return "Unknown CPU";
+ }
+ return "Unknown CPU (error)";
+ }
+
+#if defined(__X86_ASM__)
+ /* constants to access destination registers of CPUID instruction */
+ static const int EAX = 0;
+ static const int EBX = 1;
+ static const int ECX = 2;
+ static const int EDX = 3;
+
+ /* cpuid[eax=1].ecx */
+ static const int CPU_FEATURE_BIT_SSE3 = 1 << 0;
+ static const int CPU_FEATURE_BIT_SSSE3 = 1 << 9;
+ static const int CPU_FEATURE_BIT_FMA3 = 1 << 12;
+ static const int CPU_FEATURE_BIT_SSE4_1 = 1 << 19;
+ static const int CPU_FEATURE_BIT_SSE4_2 = 1 << 20;
+ //static const int CPU_FEATURE_BIT_MOVBE = 1 << 22;
+ static const int CPU_FEATURE_BIT_POPCNT = 1 << 23;
+ //static const int CPU_FEATURE_BIT_XSAVE = 1 << 26;
+ static const int CPU_FEATURE_BIT_OXSAVE = 1 << 27;
+ static const int CPU_FEATURE_BIT_AVX = 1 << 28;
+ static const int CPU_FEATURE_BIT_F16C = 1 << 29;
+ static const int CPU_FEATURE_BIT_RDRAND = 1 << 30;
+
+ /* cpuid[eax=1].edx */
+ static const int CPU_FEATURE_BIT_SSE = 1 << 25;
+ static const int CPU_FEATURE_BIT_SSE2 = 1 << 26;
+
+ /* cpuid[eax=0x80000001].ecx */
+ static const int CPU_FEATURE_BIT_LZCNT = 1 << 5;
+
+ /* cpuid[eax=7,ecx=0].ebx */
+ static const int CPU_FEATURE_BIT_BMI1 = 1 << 3;
+ static const int CPU_FEATURE_BIT_AVX2 = 1 << 5;
+ static const int CPU_FEATURE_BIT_BMI2 = 1 << 8;
+ static const int CPU_FEATURE_BIT_AVX512F = 1 << 16; // AVX512F (foundation)
+ static const int CPU_FEATURE_BIT_AVX512DQ = 1 << 17; // AVX512DQ (doubleword and quadword instructions)
+ static const int CPU_FEATURE_BIT_AVX512PF = 1 << 26; // AVX512PF (prefetch gather/scatter instructions)
+ static const int CPU_FEATURE_BIT_AVX512ER = 1 << 27; // AVX512ER (exponential and reciprocal instructions)
+ static const int CPU_FEATURE_BIT_AVX512CD = 1 << 28; // AVX512CD (conflict detection instructions)
+ static const int CPU_FEATURE_BIT_AVX512BW = 1 << 30; // AVX512BW (byte and word instructions)
+ static const int CPU_FEATURE_BIT_AVX512VL = 1 << 31; // AVX512VL (vector length extensions)
+ static const int CPU_FEATURE_BIT_AVX512IFMA = 1 << 21; // AVX512IFMA (integer fused multiple-add instructions)
+
+ /* cpuid[eax=7,ecx=0].ecx */
+ static const int CPU_FEATURE_BIT_AVX512VBMI = 1 << 1; // AVX512VBMI (vector bit manipulation instructions)
+#endif
+
+#if defined(__X86_ASM__)
+ __noinline int64_t get_xcr0()
+ {
+// -- GODOT start --
+#if defined (__WIN32__) && !defined (__MINGW32__)
+// -- GODOT end --
+ int64_t xcr0 = 0; // int64_t is workaround for compiler bug under VS2013, Win32
+ xcr0 = _xgetbv(0);
+ return xcr0;
+#else
+ int xcr0 = 0;
+ __asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx" );
+ return xcr0;
+#endif
+ }
+#endif
+
+ int getCPUFeatures()
+ {
+#if defined(__X86_ASM__)
+ /* cache CPU features access */
+ static int cpu_features = 0;
+ if (cpu_features)
+ return cpu_features;
+
+ /* get number of CPUID leaves */
+ int cpuid_leaf0[4];
+ __cpuid(cpuid_leaf0, 0x00000000);
+ unsigned nIds = cpuid_leaf0[EAX];
+
+ /* get number of extended CPUID leaves */
+ int cpuid_leafe[4];
+ __cpuid(cpuid_leafe, 0x80000000);
+ unsigned nExIds = cpuid_leafe[EAX];
+
+ /* get CPUID leaves for EAX = 1,7, and 0x80000001 */
+ int cpuid_leaf_1[4] = { 0,0,0,0 };
+ int cpuid_leaf_7[4] = { 0,0,0,0 };
+ int cpuid_leaf_e1[4] = { 0,0,0,0 };
+ if (nIds >= 1) __cpuid (cpuid_leaf_1,0x00000001);
+#if _WIN32
+#if _MSC_VER && (_MSC_FULL_VER < 160040219)
+#else
+ if (nIds >= 7) __cpuidex(cpuid_leaf_7,0x00000007,0);
+#endif
+#else
+ if (nIds >= 7) __cpuid_count(cpuid_leaf_7,0x00000007,0);
+#endif
+ if (nExIds >= 0x80000001) __cpuid(cpuid_leaf_e1,0x80000001);
+
+ /* detect if OS saves XMM, YMM, and ZMM states */
+ bool xmm_enabled = true;
+ bool ymm_enabled = false;
+ bool zmm_enabled = false;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_OXSAVE) {
+ int64_t xcr0 = get_xcr0();
+ xmm_enabled = ((xcr0 & 0x02) == 0x02); /* checks if xmm are enabled in XCR0 */
+ ymm_enabled = xmm_enabled && ((xcr0 & 0x04) == 0x04); /* checks if ymm state are enabled in XCR0 */
+ zmm_enabled = ymm_enabled && ((xcr0 & 0xE0) == 0xE0); /* checks if OPMASK state, upper 256-bit of ZMM0-ZMM15 and ZMM16-ZMM31 state are enabled in XCR0 */
+ }
+ if (xmm_enabled) cpu_features |= CPU_FEATURE_XMM_ENABLED;
+ if (ymm_enabled) cpu_features |= CPU_FEATURE_YMM_ENABLED;
+ if (zmm_enabled) cpu_features |= CPU_FEATURE_ZMM_ENABLED;
+
+ if (cpuid_leaf_1[EDX] & CPU_FEATURE_BIT_SSE ) cpu_features |= CPU_FEATURE_SSE;
+ if (cpuid_leaf_1[EDX] & CPU_FEATURE_BIT_SSE2 ) cpu_features |= CPU_FEATURE_SSE2;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE3 ) cpu_features |= CPU_FEATURE_SSE3;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSSE3 ) cpu_features |= CPU_FEATURE_SSSE3;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE4_1) cpu_features |= CPU_FEATURE_SSE41;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE4_2) cpu_features |= CPU_FEATURE_SSE42;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_POPCNT) cpu_features |= CPU_FEATURE_POPCNT;
+
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_AVX ) cpu_features |= CPU_FEATURE_AVX;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_F16C ) cpu_features |= CPU_FEATURE_F16C;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_RDRAND) cpu_features |= CPU_FEATURE_RDRAND;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX2 ) cpu_features |= CPU_FEATURE_AVX2;
+ if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_FMA3 ) cpu_features |= CPU_FEATURE_FMA3;
+ if (cpuid_leaf_e1[ECX] & CPU_FEATURE_BIT_LZCNT) cpu_features |= CPU_FEATURE_LZCNT;
+ if (cpuid_leaf_7 [EBX] & CPU_FEATURE_BIT_BMI1 ) cpu_features |= CPU_FEATURE_BMI1;
+ if (cpuid_leaf_7 [EBX] & CPU_FEATURE_BIT_BMI2 ) cpu_features |= CPU_FEATURE_BMI2;
+
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512F ) cpu_features |= CPU_FEATURE_AVX512F;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512DQ ) cpu_features |= CPU_FEATURE_AVX512DQ;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512PF ) cpu_features |= CPU_FEATURE_AVX512PF;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512ER ) cpu_features |= CPU_FEATURE_AVX512ER;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512CD ) cpu_features |= CPU_FEATURE_AVX512CD;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512BW ) cpu_features |= CPU_FEATURE_AVX512BW;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512IFMA) cpu_features |= CPU_FEATURE_AVX512IFMA;
+ if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512VL ) cpu_features |= CPU_FEATURE_AVX512VL;
+ if (cpuid_leaf_7[ECX] & CPU_FEATURE_BIT_AVX512VBMI) cpu_features |= CPU_FEATURE_AVX512VBMI;
+
+ return cpu_features;
+#elif defined(__ARM_NEON)
+ /* emulated features with sse2neon */
+ return CPU_FEATURE_SSE|CPU_FEATURE_SSE2|CPU_FEATURE_XMM_ENABLED;
+#else
+ /* Unknown CPU. */
+ return 0;
+#endif
+ }
+
+ std::string stringOfCPUFeatures(int features)
+ {
+ std::string str;
+ if (features & CPU_FEATURE_XMM_ENABLED) str += "XMM ";
+ if (features & CPU_FEATURE_YMM_ENABLED) str += "YMM ";
+ if (features & CPU_FEATURE_ZMM_ENABLED) str += "ZMM ";
+ if (features & CPU_FEATURE_SSE ) str += "SSE ";
+ if (features & CPU_FEATURE_SSE2 ) str += "SSE2 ";
+ if (features & CPU_FEATURE_SSE3 ) str += "SSE3 ";
+ if (features & CPU_FEATURE_SSSE3 ) str += "SSSE3 ";
+ if (features & CPU_FEATURE_SSE41 ) str += "SSE4.1 ";
+ if (features & CPU_FEATURE_SSE42 ) str += "SSE4.2 ";
+ if (features & CPU_FEATURE_POPCNT) str += "POPCNT ";
+ if (features & CPU_FEATURE_AVX ) str += "AVX ";
+ if (features & CPU_FEATURE_F16C ) str += "F16C ";
+ if (features & CPU_FEATURE_RDRAND) str += "RDRAND ";
+ if (features & CPU_FEATURE_AVX2 ) str += "AVX2 ";
+ if (features & CPU_FEATURE_FMA3 ) str += "FMA3 ";
+ if (features & CPU_FEATURE_LZCNT ) str += "LZCNT ";
+ if (features & CPU_FEATURE_BMI1 ) str += "BMI1 ";
+ if (features & CPU_FEATURE_BMI2 ) str += "BMI2 ";
+ if (features & CPU_FEATURE_AVX512F) str += "AVX512F ";
+ if (features & CPU_FEATURE_AVX512DQ) str += "AVX512DQ ";
+ if (features & CPU_FEATURE_AVX512PF) str += "AVX512PF ";
+ if (features & CPU_FEATURE_AVX512ER) str += "AVX512ER ";
+ if (features & CPU_FEATURE_AVX512CD) str += "AVX512CD ";
+ if (features & CPU_FEATURE_AVX512BW) str += "AVX512BW ";
+ if (features & CPU_FEATURE_AVX512VL) str += "AVX512VL ";
+ if (features & CPU_FEATURE_AVX512IFMA) str += "AVX512IFMA ";
+ if (features & CPU_FEATURE_AVX512VBMI) str += "AVX512VBMI ";
+ return str;
+ }
+
+ std::string stringOfISA (int isa)
+ {
+ if (isa == SSE) return "SSE";
+ if (isa == SSE2) return "SSE2";
+ if (isa == SSE3) return "SSE3";
+ if (isa == SSSE3) return "SSSE3";
+ if (isa == SSE41) return "SSE4.1";
+ if (isa == SSE42) return "SSE4.2";
+ if (isa == AVX) return "AVX";
+ if (isa == AVX2) return "AVX2";
+ if (isa == AVX512) return "AVX512";
+ return "UNKNOWN";
+ }
+
+ bool hasISA(int features, int isa) {
+ return (features & isa) == isa;
+ }
+
+ std::string supportedTargetList (int features)
+ {
+ std::string v;
+ if (hasISA(features,SSE)) v += "SSE ";
+ if (hasISA(features,SSE2)) v += "SSE2 ";
+ if (hasISA(features,SSE3)) v += "SSE3 ";
+ if (hasISA(features,SSSE3)) v += "SSSE3 ";
+ if (hasISA(features,SSE41)) v += "SSE4.1 ";
+ if (hasISA(features,SSE42)) v += "SSE4.2 ";
+ if (hasISA(features,AVX)) v += "AVX ";
+ if (hasISA(features,AVXI)) v += "AVXI ";
+ if (hasISA(features,AVX2)) v += "AVX2 ";
+ if (hasISA(features,AVX512)) v += "AVX512 ";
+ return v;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Windows Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__WIN32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <psapi.h>
+
+namespace embree
+{
+ std::string getExecutableFileName() {
+ char filename[1024];
+ if (!GetModuleFileName(nullptr, filename, sizeof(filename)))
+ return std::string();
+ return std::string(filename);
+ }
+
+ unsigned int getNumberOfLogicalThreads()
+ {
+ static int nThreads = -1;
+ if (nThreads != -1) return nThreads;
+
+ typedef WORD (WINAPI *GetActiveProcessorGroupCountFunc)();
+ typedef DWORD (WINAPI *GetActiveProcessorCountFunc)(WORD);
+ HMODULE hlib = LoadLibrary("Kernel32");
+ GetActiveProcessorGroupCountFunc pGetActiveProcessorGroupCount = (GetActiveProcessorGroupCountFunc)GetProcAddress(hlib, "GetActiveProcessorGroupCount");
+ GetActiveProcessorCountFunc pGetActiveProcessorCount = (GetActiveProcessorCountFunc) GetProcAddress(hlib, "GetActiveProcessorCount");
+
+ if (pGetActiveProcessorGroupCount && pGetActiveProcessorCount)
+ {
+ int groups = pGetActiveProcessorGroupCount();
+ int totalProcessors = 0;
+ for (int i = 0; i < groups; i++)
+ totalProcessors += pGetActiveProcessorCount(i);
+ nThreads = totalProcessors;
+ }
+ else
+ {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ nThreads = sysinfo.dwNumberOfProcessors;
+ }
+ assert(nThreads);
+ return nThreads;
+ }
+
+ int getTerminalWidth()
+ {
+ HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (handle == INVALID_HANDLE_VALUE) return 80;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ memset(&info,0,sizeof(info));
+ GetConsoleScreenBufferInfo(handle, &info);
+ return info.dwSize.X;
+ }
+
+ double getSeconds()
+ {
+ LARGE_INTEGER freq, val;
+ QueryPerformanceFrequency(&freq);
+ QueryPerformanceCounter(&val);
+ return (double)val.QuadPart / (double)freq.QuadPart;
+ }
+
+ void sleepSeconds(double t) {
+ Sleep(DWORD(1000.0*t));
+ }
+
+ size_t getVirtualMemoryBytes()
+ {
+ PROCESS_MEMORY_COUNTERS info;
+ GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
+ return (size_t)info.QuotaPeakPagedPoolUsage;
+ }
+
+ size_t getResidentMemoryBytes()
+ {
+ PROCESS_MEMORY_COUNTERS info;
+ GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
+ return (size_t)info.WorkingSetSize;
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Linux Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__LINUX__)
+
+#include <stdio.h>
+#include <unistd.h>
+
+namespace embree
+{
+ std::string getExecutableFileName()
+ {
+ std::string pid = "/proc/" + toString(getpid()) + "/exe";
+ char buf[4096];
+ memset(buf,0,sizeof(buf));
+ if (readlink(pid.c_str(), buf, sizeof(buf)-1) == -1)
+ return std::string();
+ return std::string(buf);
+ }
+
+ size_t getVirtualMemoryBytes()
+ {
+ size_t virt, resident, shared;
+ std::ifstream buffer("/proc/self/statm");
+ buffer >> virt >> resident >> shared;
+ return virt*sysconf(_SC_PAGE_SIZE);
+ }
+
+ size_t getResidentMemoryBytes()
+ {
+ size_t virt, resident, shared;
+ std::ifstream buffer("/proc/self/statm");
+ buffer >> virt >> resident >> shared;
+ return resident*sysconf(_SC_PAGE_SIZE);
+ }
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// FreeBSD Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined (__FreeBSD__)
+
+#include <sys/sysctl.h>
+
+namespace embree
+{
+ std::string getExecutableFileName()
+ {
+ const int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+ char buf[4096];
+ memset(buf,0,sizeof(buf));
+ size_t len = sizeof(buf)-1;
+ if (sysctl(mib, 4, buf, &len, 0x0, 0) == -1)
+ return std::string();
+ return std::string(buf);
+ }
+
+ size_t getVirtualMemoryBytes() {
+ return 0;
+ }
+
+ size_t getResidentMemoryBytes() {
+ return 0;
+ }
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Mac OS X Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__MACOSX__)
+
+#include <mach-o/dyld.h>
+
+namespace embree
+{
+ std::string getExecutableFileName()
+ {
+ char buf[4096];
+ uint32_t size = sizeof(buf);
+ if (_NSGetExecutablePath(buf, &size) != 0)
+ return std::string();
+ return std::string(buf);
+ }
+
+ size_t getVirtualMemoryBytes() {
+ return 0;
+ }
+
+ size_t getResidentMemoryBytes() {
+ return 0;
+ }
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unix Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__UNIX__)
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+namespace embree
+{
+ unsigned int getNumberOfLogicalThreads()
+ {
+ static int nThreads = -1;
+ if (nThreads != -1) return nThreads;
+
+// -- GODOT start --
+// #if defined(__MACOSX__)
+#if defined(__MACOSX__) || defined(__ANDROID__)
+// -- GODOT end --
+ nThreads = sysconf(_SC_NPROCESSORS_ONLN); // does not work in Linux LXC container
+ assert(nThreads);
+#else
+ cpu_set_t set;
+ if (pthread_getaffinity_np(pthread_self(), sizeof(set), &set) == 0)
+ nThreads = CPU_COUNT(&set);
+#endif
+
+ assert(nThreads);
+ return nThreads;
+ }
+
+ int getTerminalWidth()
+ {
+ struct winsize info;
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &info) < 0) return 80;
+ return info.ws_col;
+ }
+
+ double getSeconds() {
+ struct timeval tp; gettimeofday(&tp,nullptr);
+ return double(tp.tv_sec) + double(tp.tv_usec)/1E6;
+ }
+
+ void sleepSeconds(double t) {
+ usleep(1000000.0*t);
+ }
+}
+#endif
+
diff --git a/thirdparty/embree/common/sys/sysinfo.h b/thirdparty/embree/common/sys/sysinfo.h
new file mode 100644
index 0000000000..72351d12e4
--- /dev/null
+++ b/thirdparty/embree/common/sys/sysinfo.h
@@ -0,0 +1,178 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define CACHELINE_SIZE 64
+
+#if !defined(PAGE_SIZE)
+ #define PAGE_SIZE 4096
+#endif
+
+#define PAGE_SIZE_2M (2*1024*1024)
+#define PAGE_SIZE_4K (4*1024)
+
+#include "platform.h"
+
+/* define isa namespace and ISA bitvector */
+#if defined (__AVX512VL__)
+# define isa avx512
+# define ISA AVX512
+# define ISA_STR "AVX512"
+#elif defined (__AVX2__)
+# define isa avx2
+# define ISA AVX2
+# define ISA_STR "AVX2"
+#elif defined(__AVXI__)
+# define isa avxi
+# define ISA AVXI
+# define ISA_STR "AVXI"
+#elif defined(__AVX__)
+# define isa avx
+# define ISA AVX
+# define ISA_STR "AVX"
+#elif defined (__SSE4_2__)
+# define isa sse42
+# define ISA SSE42
+# define ISA_STR "SSE4.2"
+//#elif defined (__SSE4_1__) // we demote this to SSE2, MacOSX code compiles with SSE41 by default with XCode 11
+//# define isa sse41
+//# define ISA SSE41
+//# define ISA_STR "SSE4.1"
+//#elif defined(__SSSE3__) // we demote this to SSE2, MacOSX code compiles with SSSE3 by default with ICC
+//# define isa ssse3
+//# define ISA SSSE3
+//# define ISA_STR "SSSE3"
+//#elif defined(__SSE3__) // we demote this to SSE2, MacOSX code compiles with SSE3 by default with clang
+//# define isa sse3
+//# define ISA SSE3
+//# define ISA_STR "SSE3"
+#elif defined(__SSE2__) || defined(__SSE3__) || defined(__SSSE3__)
+# define isa sse2
+# define ISA SSE2
+# define ISA_STR "SSE2"
+#elif defined(__SSE__)
+# define isa sse
+# define ISA SSE
+# define ISA_STR "SSE"
+#else
+#error Unknown ISA
+#endif
+
+namespace embree
+{
+ enum class CPU
+ {
+ XEON_ICE_LAKE,
+ CORE_ICE_LAKE,
+ CORE_TIGER_LAKE,
+ CORE_COMET_LAKE,
+ CORE_CANNON_LAKE,
+ CORE_KABY_LAKE,
+ XEON_SKY_LAKE,
+ CORE_SKY_LAKE,
+ XEON_PHI_KNIGHTS_MILL,
+ XEON_PHI_KNIGHTS_LANDING,
+ XEON_BROADWELL,
+ CORE_BROADWELL,
+ XEON_HASWELL,
+ CORE_HASWELL,
+ XEON_IVY_BRIDGE,
+ CORE_IVY_BRIDGE,
+ SANDY_BRIDGE,
+ NEHALEM,
+ CORE2,
+ CORE1,
+ ARM,
+ UNKNOWN,
+ };
+
+ /*! get the full path to the running executable */
+ std::string getExecutableFileName();
+
+ /*! return platform name */
+ std::string getPlatformName();
+
+ /*! get the full name of the compiler */
+ std::string getCompilerName();
+
+ /*! return the name of the CPU */
+ std::string getCPUVendor();
+
+ /*! get microprocessor model */
+ CPU getCPUModel();
+
+ /*! converts CPU model into string */
+ std::string stringOfCPUModel(CPU model);
+
+ /*! CPU features */
+ static const int CPU_FEATURE_SSE = 1 << 0;
+ static const int CPU_FEATURE_SSE2 = 1 << 1;
+ static const int CPU_FEATURE_SSE3 = 1 << 2;
+ static const int CPU_FEATURE_SSSE3 = 1 << 3;
+ static const int CPU_FEATURE_SSE41 = 1 << 4;
+ static const int CPU_FEATURE_SSE42 = 1 << 5;
+ static const int CPU_FEATURE_POPCNT = 1 << 6;
+ static const int CPU_FEATURE_AVX = 1 << 7;
+ static const int CPU_FEATURE_F16C = 1 << 8;
+ static const int CPU_FEATURE_RDRAND = 1 << 9;
+ static const int CPU_FEATURE_AVX2 = 1 << 10;
+ static const int CPU_FEATURE_FMA3 = 1 << 11;
+ static const int CPU_FEATURE_LZCNT = 1 << 12;
+ static const int CPU_FEATURE_BMI1 = 1 << 13;
+ static const int CPU_FEATURE_BMI2 = 1 << 14;
+ static const int CPU_FEATURE_AVX512F = 1 << 16;
+ static const int CPU_FEATURE_AVX512DQ = 1 << 17;
+ static const int CPU_FEATURE_AVX512PF = 1 << 18;
+ static const int CPU_FEATURE_AVX512ER = 1 << 19;
+ static const int CPU_FEATURE_AVX512CD = 1 << 20;
+ static const int CPU_FEATURE_AVX512BW = 1 << 21;
+ static const int CPU_FEATURE_AVX512VL = 1 << 22;
+ static const int CPU_FEATURE_AVX512IFMA = 1 << 23;
+ static const int CPU_FEATURE_AVX512VBMI = 1 << 24;
+ static const int CPU_FEATURE_XMM_ENABLED = 1 << 25;
+ static const int CPU_FEATURE_YMM_ENABLED = 1 << 26;
+ static const int CPU_FEATURE_ZMM_ENABLED = 1 << 27;
+
+ /*! get CPU features */
+ int getCPUFeatures();
+
+ /*! convert CPU features into a string */
+ std::string stringOfCPUFeatures(int features);
+
+ /*! creates a string of all supported targets that are supported */
+ std::string supportedTargetList (int isa);
+
+ /*! ISAs */
+ static const int SSE = CPU_FEATURE_SSE | CPU_FEATURE_XMM_ENABLED;
+ static const int SSE2 = SSE | CPU_FEATURE_SSE2;
+ static const int SSE3 = SSE2 | CPU_FEATURE_SSE3;
+ static const int SSSE3 = SSE3 | CPU_FEATURE_SSSE3;
+ static const int SSE41 = SSSE3 | CPU_FEATURE_SSE41;
+ static const int SSE42 = SSE41 | CPU_FEATURE_SSE42 | CPU_FEATURE_POPCNT;
+ static const int AVX = SSE42 | CPU_FEATURE_AVX | CPU_FEATURE_YMM_ENABLED;
+ static const int AVXI = AVX | CPU_FEATURE_F16C | CPU_FEATURE_RDRAND;
+ static const int AVX2 = AVXI | CPU_FEATURE_AVX2 | CPU_FEATURE_FMA3 | CPU_FEATURE_BMI1 | CPU_FEATURE_BMI2 | CPU_FEATURE_LZCNT;
+ static const int AVX512 = AVX2 | CPU_FEATURE_AVX512F | CPU_FEATURE_AVX512DQ | CPU_FEATURE_AVX512CD | CPU_FEATURE_AVX512BW | CPU_FEATURE_AVX512VL | CPU_FEATURE_ZMM_ENABLED;
+
+ /*! converts ISA bitvector into a string */
+ std::string stringOfISA(int features);
+
+ /*! return the number of logical threads of the system */
+ unsigned int getNumberOfLogicalThreads();
+
+ /*! returns the size of the terminal window in characters */
+ int getTerminalWidth();
+
+ /*! returns performance counter in seconds */
+ double getSeconds();
+
+ /*! sleeps the specified number of seconds */
+ void sleepSeconds(double t);
+
+ /*! returns virtual address space occupied by process */
+ size_t getVirtualMemoryBytes();
+
+ /*! returns resident memory required by process */
+ size_t getResidentMemoryBytes();
+}
diff --git a/thirdparty/embree/common/sys/thread.cpp b/thirdparty/embree/common/sys/thread.cpp
new file mode 100644
index 0000000000..f4014be89b
--- /dev/null
+++ b/thirdparty/embree/common/sys/thread.cpp
@@ -0,0 +1,474 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "thread.h"
+#include "sysinfo.h"
+#include "string.h"
+
+#include <iostream>
+#if defined(__ARM_NEON)
+#include "../simd/arm/emulation.h"
+#else
+#include <xmmintrin.h>
+#endif
+
+#if defined(PTHREADS_WIN32)
+#pragma comment (lib, "pthreadVC.lib")
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Windows Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__WIN32__)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace embree
+{
+ /*! set the affinity of a given thread */
+ void setAffinity(HANDLE thread, ssize_t affinity)
+ {
+ typedef WORD (WINAPI *GetActiveProcessorGroupCountFunc)();
+ typedef DWORD (WINAPI *GetActiveProcessorCountFunc)(WORD);
+ typedef BOOL (WINAPI *SetThreadGroupAffinityFunc)(HANDLE, const GROUP_AFFINITY *, PGROUP_AFFINITY);
+ typedef BOOL (WINAPI *SetThreadIdealProcessorExFunc)(HANDLE, PPROCESSOR_NUMBER, PPROCESSOR_NUMBER);
+ HMODULE hlib = LoadLibrary("Kernel32");
+ GetActiveProcessorGroupCountFunc pGetActiveProcessorGroupCount = (GetActiveProcessorGroupCountFunc)GetProcAddress(hlib, "GetActiveProcessorGroupCount");
+ GetActiveProcessorCountFunc pGetActiveProcessorCount = (GetActiveProcessorCountFunc)GetProcAddress(hlib, "GetActiveProcessorCount");
+ SetThreadGroupAffinityFunc pSetThreadGroupAffinity = (SetThreadGroupAffinityFunc)GetProcAddress(hlib, "SetThreadGroupAffinity");
+ SetThreadIdealProcessorExFunc pSetThreadIdealProcessorEx = (SetThreadIdealProcessorExFunc)GetProcAddress(hlib, "SetThreadIdealProcessorEx");
+ if (pGetActiveProcessorGroupCount && pGetActiveProcessorCount && pSetThreadGroupAffinity && pSetThreadIdealProcessorEx)
+ {
+ int groups = pGetActiveProcessorGroupCount();
+ int totalProcessors = 0, group = 0, number = 0;
+ for (int i = 0; i<groups; i++) {
+ int processors = pGetActiveProcessorCount(i);
+ if (totalProcessors + processors > affinity) {
+ group = i;
+ number = (int)affinity - totalProcessors;
+ break;
+ }
+ totalProcessors += processors;
+ }
+
+ GROUP_AFFINITY groupAffinity;
+ groupAffinity.Group = (WORD)group;
+ groupAffinity.Mask = (KAFFINITY)(uint64_t(1) << number);
+ groupAffinity.Reserved[0] = 0;
+ groupAffinity.Reserved[1] = 0;
+ groupAffinity.Reserved[2] = 0;
+ if (!pSetThreadGroupAffinity(thread, &groupAffinity, nullptr))
+ WARNING("SetThreadGroupAffinity failed"); // on purpose only a warning
+
+ PROCESSOR_NUMBER processorNumber;
+ processorNumber.Group = group;
+ processorNumber.Number = number;
+ processorNumber.Reserved = 0;
+ if (!pSetThreadIdealProcessorEx(thread, &processorNumber, nullptr))
+ WARNING("SetThreadIdealProcessorEx failed"); // on purpose only a warning
+ }
+ else
+ {
+ if (!SetThreadAffinityMask(thread, DWORD_PTR(uint64_t(1) << affinity)))
+ WARNING("SetThreadAffinityMask failed"); // on purpose only a warning
+ if (SetThreadIdealProcessor(thread, (DWORD)affinity) == (DWORD)-1)
+ WARNING("SetThreadIdealProcessor failed"); // on purpose only a warning
+ }
+ }
+
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity) {
+ setAffinity(GetCurrentThread(), affinity);
+ }
+
+ struct ThreadStartupData
+ {
+ public:
+ ThreadStartupData (thread_func f, void* arg)
+ : f(f), arg(arg) {}
+ public:
+ thread_func f;
+ void* arg;
+ };
+
+ DWORD WINAPI threadStartup(LPVOID ptr)
+ {
+ ThreadStartupData* parg = (ThreadStartupData*) ptr;
+ _mm_setcsr(_mm_getcsr() | /*FTZ:*/ (1<<15) | /*DAZ:*/ (1<<6));
+ parg->f(parg->arg);
+ delete parg;
+ return 0;
+ }
+
+#if !defined(PTHREADS_WIN32)
+
+ /*! creates a hardware thread running on specific core */
+ thread_t createThread(thread_func f, void* arg, size_t stack_size, ssize_t threadID)
+ {
+ HANDLE thread = CreateThread(nullptr, stack_size, threadStartup, new ThreadStartupData(f,arg), 0, nullptr);
+ if (thread == nullptr) FATAL("CreateThread failed");
+ if (threadID >= 0) setAffinity(thread, threadID);
+ return thread_t(thread);
+ }
+
+ /*! the thread calling this function gets yielded */
+ void yield() {
+ SwitchToThread();
+ }
+
+ /*! waits until the given thread has terminated */
+ void join(thread_t tid) {
+ WaitForSingleObject(HANDLE(tid), INFINITE);
+ CloseHandle(HANDLE(tid));
+ }
+
+ /*! destroy a hardware thread by its handle */
+ void destroyThread(thread_t tid) {
+ TerminateThread(HANDLE(tid),0);
+ CloseHandle(HANDLE(tid));
+ }
+
+ /*! creates thread local storage */
+ tls_t createTls() {
+ return tls_t(size_t(TlsAlloc()));
+ }
+
+ /*! set the thread local storage pointer */
+ void setTls(tls_t tls, void* const ptr) {
+ TlsSetValue(DWORD(size_t(tls)), ptr);
+ }
+
+ /*! return the thread local storage pointer */
+ void* getTls(tls_t tls) {
+ return TlsGetValue(DWORD(size_t(tls)));
+ }
+
+ /*! destroys thread local storage identifier */
+ void destroyTls(tls_t tls) {
+ TlsFree(DWORD(size_t(tls)));
+ }
+#endif
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Linux Platform
+////////////////////////////////////////////////////////////////////////////////
+
+// -- GODOT start --
+#if defined(__LINUX__) && !defined(__ANDROID__)
+// -- GODOT end --
+
+#include <fstream>
+#include <sstream>
+#include <algorithm>
+
+namespace embree
+{
+ static MutexSys mutex;
+ static std::vector<size_t> threadIDs;
+
+ /* changes thread ID mapping such that we first fill up all thread on one core */
+ size_t mapThreadID(size_t threadID)
+ {
+ Lock<MutexSys> lock(mutex);
+
+ if (threadIDs.size() == 0)
+ {
+ /* parse thread/CPU topology */
+ for (size_t cpuID=0;;cpuID++)
+ {
+ std::fstream fs;
+ std::string cpu = std::string("/sys/devices/system/cpu/cpu") + std::to_string((long long)cpuID) + std::string("/topology/thread_siblings_list");
+ fs.open (cpu.c_str(), std::fstream::in);
+ if (fs.fail()) break;
+
+ int i;
+ while (fs >> i)
+ {
+ if (std::none_of(threadIDs.begin(),threadIDs.end(),[&] (int id) { return id == i; }))
+ threadIDs.push_back(i);
+ if (fs.peek() == ',')
+ fs.ignore();
+ }
+ fs.close();
+ }
+
+#if 0
+ for (size_t i=0;i<threadIDs.size();i++)
+ std::cout << i << " -> " << threadIDs[i] << std::endl;
+#endif
+
+ /* verify the mapping and do not use it if the mapping has errors */
+ for (size_t i=0;i<threadIDs.size();i++) {
+ for (size_t j=0;j<threadIDs.size();j++) {
+ if (i != j && threadIDs[i] == threadIDs[j]) {
+ threadIDs.clear();
+ }
+ }
+ }
+ }
+
+ /* re-map threadIDs if mapping is available */
+ size_t ID = threadID;
+ if (threadID < threadIDs.size())
+ ID = threadIDs[threadID];
+
+ /* find correct thread to affinitize to */
+ cpu_set_t set;
+ if (pthread_getaffinity_np(pthread_self(), sizeof(set), &set) == 0)
+ {
+ for (int i=0, j=0; i<CPU_SETSIZE; i++)
+ {
+ if (!CPU_ISSET(i,&set)) continue;
+
+ if (j == ID) {
+ ID = i;
+ break;
+ }
+ j++;
+ }
+ }
+
+ return ID;
+ }
+
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity)
+ {
+ cpu_set_t cset;
+ CPU_ZERO(&cset);
+ size_t threadID = mapThreadID(affinity);
+ CPU_SET(threadID, &cset);
+
+ pthread_setaffinity_np(pthread_self(), sizeof(cset), &cset);
+ }
+}
+#endif
+
+// -- GODOT start --
+////////////////////////////////////////////////////////////////////////////////
+/// Android Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__ANDROID__)
+
+namespace embree
+{
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity)
+ {
+ cpu_set_t cset;
+ CPU_ZERO(&cset);
+ CPU_SET(affinity, &cset);
+
+ sched_setaffinity(0, sizeof(cset), &cset);
+ }
+}
+#endif
+// -- GODOT end --
+
+////////////////////////////////////////////////////////////////////////////////
+/// FreeBSD Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__FreeBSD__)
+
+#include <pthread_np.h>
+
+namespace embree
+{
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity)
+ {
+ cpuset_t cset;
+ CPU_ZERO(&cset);
+ CPU_SET(affinity, &cset);
+
+ pthread_setaffinity_np(pthread_self(), sizeof(cset), &cset);
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// MacOSX Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__MACOSX__)
+
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+#include <mach/mach_init.h>
+
+namespace embree
+{
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity)
+ {
+#if !defined(__ARM_NEON) // affinity seems not supported on M1 chip
+
+ thread_affinity_policy ap;
+ ap.affinity_tag = affinity;
+ if (thread_policy_set(mach_thread_self(),THREAD_AFFINITY_POLICY,(thread_policy_t)&ap,THREAD_AFFINITY_POLICY_COUNT) != KERN_SUCCESS)
+ WARNING("setting thread affinity failed"); // on purpose only a warning
+
+#endif
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/// Unix Platform
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__UNIX__) || defined(PTHREADS_WIN32)
+
+#include <pthread.h>
+#include <sched.h>
+
+#if defined(__USE_NUMA__)
+#include <numa.h>
+#endif
+
+namespace embree
+{
+ struct ThreadStartupData
+ {
+ public:
+ ThreadStartupData (thread_func f, void* arg, int affinity)
+ : f(f), arg(arg), affinity(affinity) {}
+ public:
+ thread_func f;
+ void* arg;
+ ssize_t affinity;
+ };
+
+ static void* threadStartup(ThreadStartupData* parg)
+ {
+ _mm_setcsr(_mm_getcsr() | /*FTZ:*/ (1<<15) | /*DAZ:*/ (1<<6));
+
+ /*! Mac OS X does not support setting affinity at thread creation time */
+#if defined(__MACOSX__)
+ if (parg->affinity >= 0)
+ setAffinity(parg->affinity);
+#endif
+
+ parg->f(parg->arg);
+ delete parg;
+ return nullptr;
+ }
+
+ /*! creates a hardware thread running on specific core */
+ thread_t createThread(thread_func f, void* arg, size_t stack_size, ssize_t threadID)
+ {
+ /* set stack size */
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ if (stack_size > 0) pthread_attr_setstacksize (&attr, stack_size);
+
+ /* create thread */
+ pthread_t* tid = new pthread_t;
+ if (pthread_create(tid,&attr,(void*(*)(void*))threadStartup,new ThreadStartupData(f,arg,threadID)) != 0) {
+ pthread_attr_destroy(&attr);
+ delete tid;
+ FATAL("pthread_create failed");
+ }
+ pthread_attr_destroy(&attr);
+
+ /* set affinity */
+// -- GODOT start --
+#if defined(__LINUX__) && !defined(__ANDROID__)
+// -- GODOT end --
+ if (threadID >= 0) {
+ cpu_set_t cset;
+ CPU_ZERO(&cset);
+ threadID = mapThreadID(threadID);
+ CPU_SET(threadID, &cset);
+ pthread_setaffinity_np(*tid, sizeof(cset), &cset);
+ }
+#elif defined(__FreeBSD__)
+ if (threadID >= 0) {
+ cpuset_t cset;
+ CPU_ZERO(&cset);
+ CPU_SET(threadID, &cset);
+ pthread_setaffinity_np(*tid, sizeof(cset), &cset);
+ }
+// -- GODOT start --
+#elif defined(__ANDROID__)
+ if (threadID >= 0) {
+ cpu_set_t cset;
+ CPU_ZERO(&cset);
+ CPU_SET(threadID, &cset);
+ sched_setaffinity(pthread_gettid_np(*tid), sizeof(cset), &cset);
+ }
+#endif
+// -- GODOT end --
+
+ return thread_t(tid);
+ }
+
+ /*! the thread calling this function gets yielded */
+ void yield() {
+ sched_yield();
+ }
+
+ /*! waits until the given thread has terminated */
+ void join(thread_t tid) {
+ if (pthread_join(*(pthread_t*)tid, nullptr) != 0)
+ FATAL("pthread_join failed");
+ delete (pthread_t*)tid;
+ }
+
+ /*! destroy a hardware thread by its handle */
+ void destroyThread(thread_t tid) {
+// -- GODOT start --
+#if defined(__ANDROID__)
+ FATAL("Can't destroy threads on Android.");
+#else
+ pthread_cancel(*(pthread_t*)tid);
+ delete (pthread_t*)tid;
+#endif
+// -- GODOT end --
+ }
+
+ /*! creates thread local storage */
+ tls_t createTls()
+ {
+ pthread_key_t* key = new pthread_key_t;
+ if (pthread_key_create(key,nullptr) != 0) {
+ delete key;
+ FATAL("pthread_key_create failed");
+ }
+
+ return tls_t(key);
+ }
+
+ /*! return the thread local storage pointer */
+ void* getTls(tls_t tls)
+ {
+ assert(tls);
+ return pthread_getspecific(*(pthread_key_t*)tls);
+ }
+
+ /*! set the thread local storage pointer */
+ void setTls(tls_t tls, void* const ptr)
+ {
+ assert(tls);
+ if (pthread_setspecific(*(pthread_key_t*)tls, ptr) != 0)
+ FATAL("pthread_setspecific failed");
+ }
+
+ /*! destroys thread local storage identifier */
+ void destroyTls(tls_t tls)
+ {
+ assert(tls);
+ if (pthread_key_delete(*(pthread_key_t*)tls) != 0)
+ FATAL("pthread_key_delete failed");
+ delete (pthread_key_t*)tls;
+ }
+}
+
+#endif
diff --git a/thirdparty/embree/common/sys/thread.h b/thirdparty/embree/common/sys/thread.h
new file mode 100644
index 0000000000..92a10d5c5d
--- /dev/null
+++ b/thirdparty/embree/common/sys/thread.h
@@ -0,0 +1,49 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "platform.h"
+#include "mutex.h"
+#include "alloc.h"
+#include "vector.h"
+#include <vector>
+
+namespace embree
+{
+ /*! type for thread */
+ typedef struct opaque_thread_t* thread_t;
+
+ /*! signature of thread start function */
+ typedef void (*thread_func)(void*);
+
+ /*! creates a hardware thread running on specific logical thread */
+ thread_t createThread(thread_func f, void* arg, size_t stack_size = 0, ssize_t threadID = -1);
+
+ /*! set affinity of the calling thread */
+ void setAffinity(ssize_t affinity);
+
+ /*! the thread calling this function gets yielded */
+ void yield();
+
+ /*! waits until the given thread has terminated */
+ void join(thread_t tid);
+
+ /*! destroy handle of a thread */
+ void destroyThread(thread_t tid);
+
+ /*! type for handle to thread local storage */
+ typedef struct opaque_tls_t* tls_t;
+
+ /*! creates thread local storage */
+ tls_t createTls();
+
+ /*! set the thread local storage pointer */
+ void setTls(tls_t tls, void* const ptr);
+
+ /*! return the thread local storage pointer */
+ void* getTls(tls_t tls);
+
+ /*! destroys thread local storage identifier */
+ void destroyTls(tls_t tls);
+}
diff --git a/thirdparty/embree/common/sys/vector.h b/thirdparty/embree/common/sys/vector.h
new file mode 100644
index 0000000000..f832626789
--- /dev/null
+++ b/thirdparty/embree/common/sys/vector.h
@@ -0,0 +1,242 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "alloc.h"
+#include <algorithm>
+
+namespace embree
+{
+ template<typename T, typename allocator>
+ class vector_t
+ {
+ public:
+ typedef T value_type;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+ __forceinline vector_t ()
+ : size_active(0), size_alloced(0), items(nullptr) {}
+
+ __forceinline explicit vector_t (size_t sz)
+ : size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); }
+
+ template<typename M>
+ __forceinline explicit vector_t (M alloc, size_t sz)
+ : alloc(alloc), size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); }
+
+ __forceinline ~vector_t() {
+ clear();
+ }
+
+ __forceinline vector_t (const vector_t& other)
+ {
+ size_active = other.size_active;
+ size_alloced = other.size_alloced;
+ items = alloc.allocate(size_alloced);
+ for (size_t i=0; i<size_active; i++)
+ ::new (&items[i]) value_type(other.items[i]);
+ }
+
+ __forceinline vector_t (vector_t&& other)
+ : alloc(std::move(other.alloc))
+ {
+ size_active = other.size_active; other.size_active = 0;
+ size_alloced = other.size_alloced; other.size_alloced = 0;
+ items = other.items; other.items = nullptr;
+ }
+
+ __forceinline vector_t& operator=(const vector_t& other)
+ {
+ resize(other.size_active);
+ for (size_t i=0; i<size_active; i++)
+ items[i] = value_type(other.items[i]);
+ return *this;
+ }
+
+ __forceinline vector_t& operator=(vector_t&& other)
+ {
+ clear();
+ alloc = std::move(other.alloc);
+ size_active = other.size_active; other.size_active = 0;
+ size_alloced = other.size_alloced; other.size_alloced = 0;
+ items = other.items; other.items = nullptr;
+ return *this;
+ }
+
+ /********************** Iterators ****************************/
+
+ __forceinline iterator begin() { return items; };
+ __forceinline const_iterator begin() const { return items; };
+
+ __forceinline iterator end () { return items+size_active; };
+ __forceinline const_iterator end () const { return items+size_active; };
+
+
+ /********************** Capacity ****************************/
+
+ __forceinline bool empty () const { return size_active == 0; }
+ __forceinline size_t size () const { return size_active; }
+ __forceinline size_t capacity () const { return size_alloced; }
+
+
+ __forceinline void resize(size_t new_size) {
+ internal_resize(new_size,internal_grow_size(new_size));
+ }
+
+ __forceinline void reserve(size_t new_alloced)
+ {
+ /* do nothing if container already large enough */
+ if (new_alloced <= size_alloced)
+ return;
+
+ /* resize exact otherwise */
+ internal_resize(size_active,new_alloced);
+ }
+
+ __forceinline void shrink_to_fit() {
+ internal_resize(size_active,size_active);
+ }
+
+ /******************** Element access **************************/
+
+ __forceinline T& operator[](size_t i) { assert(i < size_active); return items[i]; }
+ __forceinline const T& operator[](size_t i) const { assert(i < size_active); return items[i]; }
+
+ __forceinline T& at(size_t i) { assert(i < size_active); return items[i]; }
+ __forceinline const T& at(size_t i) const { assert(i < size_active); return items[i]; }
+
+ __forceinline T& front() const { assert(size_active > 0); return items[0]; };
+ __forceinline T& back () const { assert(size_active > 0); return items[size_active-1]; };
+
+ __forceinline T* data() { return items; };
+ __forceinline const T* data() const { return items; };
+
+
+ /******************** Modifiers **************************/
+
+ __forceinline void push_back(const T& nt)
+ {
+ const T v = nt; // need local copy as input reference could point to this vector
+ internal_resize(size_active,internal_grow_size(size_active+1));
+ ::new (&items[size_active++]) T(v);
+ }
+
+ __forceinline void pop_back()
+ {
+ assert(!empty());
+ size_active--;
+ alloc.destroy(&items[size_active]);
+ }
+
+ __forceinline void clear()
+ {
+ /* destroy elements */
+ for (size_t i=0; i<size_active; i++)
+ alloc.destroy(&items[i]);
+
+ /* free memory */
+ alloc.deallocate(items,size_alloced);
+ items = nullptr;
+ size_active = size_alloced = 0;
+ }
+
+ /******************** Comparisons **************************/
+
+ friend bool operator== (const vector_t& a, const vector_t& b)
+ {
+ if (a.size() != b.size()) return false;
+ for (size_t i=0; i<a.size(); i++)
+ if (a[i] != b[i])
+ return false;
+ return true;
+ }
+
+ friend bool operator!= (const vector_t& a, const vector_t& b) {
+ return !(a==b);
+ }
+
+ private:
+
+ __forceinline void internal_resize_init(size_t new_active)
+ {
+ assert(size_active == 0);
+ assert(size_alloced == 0);
+ assert(items == nullptr);
+ if (new_active == 0) return;
+ items = alloc.allocate(new_active);
+ for (size_t i=0; i<new_active; i++) ::new (&items[i]) T();
+ size_active = new_active;
+ size_alloced = new_active;
+ }
+
+ __forceinline void internal_resize(size_t new_active, size_t new_alloced)
+ {
+ assert(new_active <= new_alloced);
+
+ /* destroy elements */
+ if (new_active < size_active)
+ {
+ for (size_t i=new_active; i<size_active; i++)
+ alloc.destroy(&items[i]);
+ size_active = new_active;
+ }
+
+ /* only reallocate if necessary */
+ if (new_alloced == size_alloced) {
+ for (size_t i=size_active; i<new_active; i++) ::new (&items[i]) T;
+ size_active = new_active;
+ return;
+ }
+
+ /* reallocate and copy items */
+ T* old_items = items;
+ items = alloc.allocate(new_alloced);
+ for (size_t i=0; i<size_active; i++) {
+ ::new (&items[i]) T(std::move(old_items[i]));
+ alloc.destroy(&old_items[i]);
+ }
+
+ for (size_t i=size_active; i<new_active; i++) {
+ ::new (&items[i]) T;
+ }
+
+ alloc.deallocate(old_items,size_alloced);
+ size_active = new_active;
+ size_alloced = new_alloced;
+ }
+
+ __forceinline size_t internal_grow_size(size_t new_alloced)
+ {
+ /* do nothing if container already large enough */
+ if (new_alloced <= size_alloced)
+ return size_alloced;
+
+ /* resize to next power of 2 otherwise */
+ size_t new_size_alloced = size_alloced;
+ while (new_size_alloced < new_alloced) {
+ new_size_alloced = std::max(size_t(1),2*new_size_alloced);
+ }
+ return new_size_alloced;
+ }
+
+ private:
+ allocator alloc;
+ size_t size_active; // number of valid items
+ size_t size_alloced; // number of items allocated
+ T* items; // data array
+ };
+
+ /*! vector class that performs standard allocations */
+ template<typename T>
+ using vector = vector_t<T,std::allocator<T>>;
+
+ /*! vector class that performs aligned allocations */
+ template<typename T>
+ using avector = vector_t<T,aligned_allocator<T,std::alignment_of<T>::value> >;
+
+ /*! vector class that performs OS allocations */
+ template<typename T>
+ using ovector = vector_t<T,os_allocator<T> >;
+}
diff --git a/thirdparty/embree/common/tasking/taskscheduler.h b/thirdparty/embree/common/tasking/taskscheduler.h
new file mode 100644
index 0000000000..8f3dd87689
--- /dev/null
+++ b/thirdparty/embree/common/tasking/taskscheduler.h
@@ -0,0 +1,15 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#if defined(TASKING_INTERNAL)
+# include "taskschedulerinternal.h"
+#elif defined(TASKING_TBB)
+# include "taskschedulertbb.h"
+#elif defined(TASKING_PPL)
+# include "taskschedulerppl.h"
+#else
+# error "no tasking system enabled"
+#endif
+
diff --git a/thirdparty/embree/common/tasking/taskschedulerinternal.cpp b/thirdparty/embree/common/tasking/taskschedulerinternal.cpp
new file mode 100644
index 0000000000..ad438588a3
--- /dev/null
+++ b/thirdparty/embree/common/tasking/taskschedulerinternal.cpp
@@ -0,0 +1,420 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "taskschedulerinternal.h"
+#include "../math/math.h"
+#include "../sys/sysinfo.h"
+#include <algorithm>
+
+namespace embree
+{
+ RTC_NAMESPACE_BEGIN
+
+ static MutexSys g_mutex;
+ size_t TaskScheduler::g_numThreads = 0;
+ __thread TaskScheduler* TaskScheduler::g_instance = nullptr;
+ std::vector<Ref<TaskScheduler>> g_instance_vector;
+ __thread TaskScheduler::Thread* TaskScheduler::thread_local_thread = nullptr;
+ TaskScheduler::ThreadPool* TaskScheduler::threadPool = nullptr;
+
+ template<typename Predicate, typename Body>
+ __forceinline void TaskScheduler::steal_loop(Thread& thread, const Predicate& pred, const Body& body)
+ {
+ while (true)
+ {
+ /*! some rounds that yield */
+ for (size_t i=0; i<32; i++)
+ {
+ /*! some spinning rounds */
+ const size_t threadCount = thread.threadCount();
+ for (size_t j=0; j<1024; j+=threadCount)
+ {
+ if (!pred()) return;
+ if (thread.scheduler->steal_from_other_threads(thread)) {
+ i=j=0;
+ body();
+ }
+ }
+ yield();
+ }
+ }
+ }
+
+ /*! run this task */
+ void TaskScheduler::Task::run_internal (Thread& thread) // FIXME: avoid as many dll_exports as possible
+ {
+ /* try to run if not already stolen */
+ if (try_switch_state(INITIALIZED,DONE))
+ {
+ Task* prevTask = thread.task;
+ thread.task = this;
+ // -- GODOT start --
+ // try {
+ // if (thread.scheduler->cancellingException == nullptr)
+ closure->execute();
+ // } catch (...) {
+ // if (thread.scheduler->cancellingException == nullptr)
+ // thread.scheduler->cancellingException = std::current_exception();
+ // }
+ // -- GODOT end --
+ thread.task = prevTask;
+ add_dependencies(-1);
+ }
+
+ /* steal until all dependencies have completed */
+ steal_loop(thread,
+ [&] () { return dependencies>0; },
+ [&] () { while (thread.tasks.execute_local_internal(thread,this)); });
+
+ /* now signal our parent task that we are finished */
+ if (parent)
+ parent->add_dependencies(-1);
+ }
+
+ /*! run this task */
+ dll_export void TaskScheduler::Task::run (Thread& thread) {
+ run_internal(thread);
+ }
+
+ bool TaskScheduler::TaskQueue::execute_local_internal(Thread& thread, Task* parent)
+ {
+ /* stop if we run out of local tasks or reach the waiting task */
+ if (right == 0 || &tasks[right-1] == parent)
+ return false;
+
+ /* execute task */
+ size_t oldRight = right;
+ tasks[right-1].run_internal(thread);
+ if (right != oldRight) {
+ THROW_RUNTIME_ERROR("you have to wait for spawned subtasks");
+ }
+
+ /* pop task and closure from stack */
+ right--;
+ if (tasks[right].stackPtr != size_t(-1))
+ stackPtr = tasks[right].stackPtr;
+
+ /* also move left pointer */
+ if (left >= right) left.store(right.load());
+
+ return right != 0;
+ }
+
+ dll_export bool TaskScheduler::TaskQueue::execute_local(Thread& thread, Task* parent) {
+ return execute_local_internal(thread,parent);
+ }
+
+ bool TaskScheduler::TaskQueue::steal(Thread& thread)
+ {
+ size_t l = left;
+ size_t r = right;
+ if (l < r)
+ {
+ l = left++;
+ if (l >= r)
+ return false;
+ }
+ else
+ return false;
+
+ if (!tasks[l].try_steal(thread.tasks.tasks[thread.tasks.right]))
+ return false;
+
+ thread.tasks.right++;
+ return true;
+ }
+
+ /* we steal from the left */
+ size_t TaskScheduler::TaskQueue::getTaskSizeAtLeft()
+ {
+ if (left >= right) return 0;
+ return tasks[left].N;
+ }
+
+ void threadPoolFunction(std::pair<TaskScheduler::ThreadPool*,size_t>* pair)
+ {
+ TaskScheduler::ThreadPool* pool = pair->first;
+ size_t threadIndex = pair->second;
+ delete pair;
+ pool->thread_loop(threadIndex);
+ }
+
+ TaskScheduler::ThreadPool::ThreadPool(bool set_affinity)
+ : numThreads(0), numThreadsRunning(0), set_affinity(set_affinity), running(false) {}
+
+ dll_export void TaskScheduler::ThreadPool::startThreads()
+ {
+ if (running) return;
+ setNumThreads(numThreads,true);
+ }
+
+ void TaskScheduler::ThreadPool::setNumThreads(size_t newNumThreads, bool startThreads)
+ {
+ Lock<MutexSys> lock(g_mutex);
+ assert(newNumThreads);
+ newNumThreads = min(newNumThreads, (size_t) getNumberOfLogicalThreads());
+
+ numThreads = newNumThreads;
+ if (!startThreads && !running) return;
+ running = true;
+ size_t numThreadsActive = numThreadsRunning;
+
+ mutex.lock();
+ numThreadsRunning = newNumThreads;
+ mutex.unlock();
+ condition.notify_all();
+
+ /* start new threads */
+ for (size_t t=numThreadsActive; t<numThreads; t++)
+ {
+ if (t == 0) continue;
+ auto pair = new std::pair<TaskScheduler::ThreadPool*,size_t>(this,t);
+ threads.push_back(createThread((thread_func)threadPoolFunction,pair,4*1024*1024,set_affinity ? t : -1));
+ }
+
+ /* stop some threads if we reduce the number of threads */
+ for (ssize_t t=numThreadsActive-1; t>=ssize_t(numThreadsRunning); t--) {
+ if (t == 0) continue;
+ embree::join(threads.back());
+ threads.pop_back();
+ }
+ }
+
+ TaskScheduler::ThreadPool::~ThreadPool()
+ {
+ /* leave all taskschedulers */
+ mutex.lock();
+ numThreadsRunning = 0;
+ mutex.unlock();
+ condition.notify_all();
+
+ /* wait for threads to terminate */
+ for (size_t i=0; i<threads.size(); i++)
+ embree::join(threads[i]);
+ }
+
+ dll_export void TaskScheduler::ThreadPool::add(const Ref<TaskScheduler>& scheduler)
+ {
+ mutex.lock();
+ schedulers.push_back(scheduler);
+ mutex.unlock();
+ condition.notify_all();
+ }
+
+ dll_export void TaskScheduler::ThreadPool::remove(const Ref<TaskScheduler>& scheduler)
+ {
+ Lock<MutexSys> lock(mutex);
+ for (std::list<Ref<TaskScheduler> >::iterator it = schedulers.begin(); it != schedulers.end(); it++) {
+ if (scheduler == *it) {
+ schedulers.erase(it);
+ return;
+ }
+ }
+ }
+
+ void TaskScheduler::ThreadPool::thread_loop(size_t globalThreadIndex)
+ {
+ while (globalThreadIndex < numThreadsRunning)
+ {
+ Ref<TaskScheduler> scheduler = NULL;
+ ssize_t threadIndex = -1;
+ {
+ Lock<MutexSys> lock(mutex);
+ condition.wait(mutex, [&] () { return globalThreadIndex >= numThreadsRunning || !schedulers.empty(); });
+ if (globalThreadIndex >= numThreadsRunning) break;
+ scheduler = schedulers.front();
+ threadIndex = scheduler->allocThreadIndex();
+ }
+ scheduler->thread_loop(threadIndex);
+ }
+ }
+
+ TaskScheduler::TaskScheduler()
+ : threadCounter(0), anyTasksRunning(0), hasRootTask(false)
+ {
+ threadLocal.resize(2*getNumberOfLogicalThreads()); // FIXME: this has to be 2x as in the compatibility join mode with rtcCommitScene the worker threads also join. When disallowing rtcCommitScene to join a build we can remove the 2x.
+ for (size_t i=0; i<threadLocal.size(); i++)
+ threadLocal[i].store(nullptr);
+ }
+
+ TaskScheduler::~TaskScheduler()
+ {
+ assert(threadCounter == 0);
+ }
+
+ dll_export size_t TaskScheduler::threadID()
+ {
+ Thread* thread = TaskScheduler::thread();
+ if (thread) return thread->threadIndex;
+ else return 0;
+ }
+
+ dll_export size_t TaskScheduler::threadIndex()
+ {
+ Thread* thread = TaskScheduler::thread();
+ if (thread) return thread->threadIndex;
+ else return 0;
+ }
+
+ dll_export size_t TaskScheduler::threadCount() {
+ return threadPool->size();
+ }
+
+ dll_export TaskScheduler* TaskScheduler::instance()
+ {
+ if (g_instance == NULL) {
+ Lock<MutexSys> lock(g_mutex);
+ g_instance = new TaskScheduler;
+ g_instance_vector.push_back(g_instance);
+ }
+ return g_instance;
+ }
+
+ void TaskScheduler::create(size_t numThreads, bool set_affinity, bool start_threads)
+ {
+ if (!threadPool) threadPool = new TaskScheduler::ThreadPool(set_affinity);
+ threadPool->setNumThreads(numThreads,start_threads);
+ }
+
+ void TaskScheduler::destroy() {
+ delete threadPool; threadPool = nullptr;
+ }
+
+ dll_export ssize_t TaskScheduler::allocThreadIndex()
+ {
+ size_t threadIndex = threadCounter++;
+ assert(threadIndex < threadLocal.size());
+ return threadIndex;
+ }
+
+ void TaskScheduler::join()
+ {
+ mutex.lock();
+ size_t threadIndex = allocThreadIndex();
+ condition.wait(mutex, [&] () { return hasRootTask.load(); });
+ mutex.unlock();
+ // -- GODOT start --
+ // std::exception_ptr except = thread_loop(threadIndex);
+ // if (except != nullptr) std::rethrow_exception(except);
+ thread_loop(threadIndex);
+ // -- GODOT end --
+ }
+
+ void TaskScheduler::reset() {
+ hasRootTask = false;
+ }
+
+ void TaskScheduler::wait_for_threads(size_t threadCount)
+ {
+ while (threadCounter < threadCount-1)
+ pause_cpu();
+ }
+
+ dll_export TaskScheduler::Thread* TaskScheduler::thread() {
+ return thread_local_thread;
+ }
+
+ dll_export TaskScheduler::Thread* TaskScheduler::swapThread(Thread* thread)
+ {
+ Thread* old = thread_local_thread;
+ thread_local_thread = thread;
+ return old;
+ }
+
+ dll_export bool TaskScheduler::wait()
+ {
+ Thread* thread = TaskScheduler::thread();
+ if (thread == nullptr) return true;
+ while (thread->tasks.execute_local_internal(*thread,thread->task)) {};
+ return thread->scheduler->cancellingException == nullptr;
+ }
+
+// -- GODOT start --
+// std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex)
+ void TaskScheduler::thread_loop(size_t threadIndex)
+// -- GODOT end --
+ {
+ /* allocate thread structure */
+ std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation
+ Thread& thread = *mthread;
+ threadLocal[threadIndex].store(&thread);
+ Thread* oldThread = swapThread(&thread);
+
+ /* main thread loop */
+ while (anyTasksRunning)
+ {
+ steal_loop(thread,
+ [&] () { return anyTasksRunning > 0; },
+ [&] () {
+ anyTasksRunning++;
+ while (thread.tasks.execute_local_internal(thread,nullptr));
+ anyTasksRunning--;
+ });
+ }
+ threadLocal[threadIndex].store(nullptr);
+ swapThread(oldThread);
+
+ /* remember exception to throw */
+ // -- GODOT start --
+ // std::exception_ptr except = nullptr;
+ // if (cancellingException != nullptr) except = cancellingException;
+ // -- GODOT end --
+ /* wait for all threads to terminate */
+ threadCounter--;
+#if defined(__WIN32__)
+ size_t loopIndex = 1;
+#endif
+#define LOOP_YIELD_THRESHOLD (4096)
+ while (threadCounter > 0) {
+#if defined(__WIN32__)
+ if ((loopIndex % LOOP_YIELD_THRESHOLD) == 0)
+ yield();
+ else
+ _mm_pause();
+ loopIndex++;
+#else
+ yield();
+#endif
+ }
+ // -- GODOT start --
+ // return except;
+ return;
+ // -- GODOT end --
+ }
+
+ bool TaskScheduler::steal_from_other_threads(Thread& thread)
+ {
+ const size_t threadIndex = thread.threadIndex;
+ const size_t threadCount = this->threadCounter;
+
+ for (size_t i=1; i<threadCount; i++)
+ {
+ pause_cpu(32);
+ size_t otherThreadIndex = threadIndex+i;
+ if (otherThreadIndex >= threadCount) otherThreadIndex -= threadCount;
+
+ Thread* othread = threadLocal[otherThreadIndex].load();
+ if (!othread)
+ continue;
+
+ if (othread->tasks.steal(thread))
+ return true;
+ }
+
+ return false;
+ }
+
+ dll_export void TaskScheduler::startThreads() {
+ threadPool->startThreads();
+ }
+
+ dll_export void TaskScheduler::addScheduler(const Ref<TaskScheduler>& scheduler) {
+ threadPool->add(scheduler);
+ }
+
+ dll_export void TaskScheduler::removeScheduler(const Ref<TaskScheduler>& scheduler) {
+ threadPool->remove(scheduler);
+ }
+
+ RTC_NAMESPACE_END
+}
diff --git a/thirdparty/embree/common/tasking/taskschedulerinternal.h b/thirdparty/embree/common/tasking/taskschedulerinternal.h
new file mode 100644
index 0000000000..8fa6bb12fa
--- /dev/null
+++ b/thirdparty/embree/common/tasking/taskschedulerinternal.h
@@ -0,0 +1,385 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/alloc.h"
+#include "../sys/barrier.h"
+#include "../sys/thread.h"
+#include "../sys/mutex.h"
+#include "../sys/condition.h"
+#include "../sys/ref.h"
+#include "../sys/atomic.h"
+#include "../math/range.h"
+#include "../../include/embree3/rtcore.h"
+
+#include <list>
+
+namespace embree
+{
+
+ /* The tasking system exports some symbols to be used by the tutorials. Thus we
+ hide is also in the API namespace when requested. */
+ RTC_NAMESPACE_BEGIN
+
+ struct TaskScheduler : public RefCount
+ {
+ ALIGNED_STRUCT_(64);
+ friend class Device;
+
+ static const size_t TASK_STACK_SIZE = 4*1024; //!< task structure stack
+ static const size_t CLOSURE_STACK_SIZE = 512*1024; //!< stack for task closures
+
+ struct Thread;
+
+ /*! virtual interface for all tasks */
+ struct TaskFunction {
+ virtual void execute() = 0;
+ };
+
+ /*! builds a task interface from a closure */
+ template<typename Closure>
+ struct ClosureTaskFunction : public TaskFunction
+ {
+ Closure closure;
+ __forceinline ClosureTaskFunction (const Closure& closure) : closure(closure) {}
+ void execute() { closure(); };
+ };
+
+ struct __aligned(64) Task
+ {
+ /*! states a task can be in */
+ enum { DONE, INITIALIZED };
+
+ /*! switch from one state to another */
+ __forceinline void switch_state(int from, int to)
+ {
+ __memory_barrier();
+ MAYBE_UNUSED bool success = state.compare_exchange_strong(from,to);
+ assert(success);
+ }
+
+ /*! try to switch from one state to another */
+ __forceinline bool try_switch_state(int from, int to) {
+ __memory_barrier();
+ return state.compare_exchange_strong(from,to);
+ }
+
+ /*! increment/decrement dependency counter */
+ void add_dependencies(int n) {
+ dependencies+=n;
+ }
+
+ /*! initialize all tasks to DONE state by default */
+ __forceinline Task()
+ : state(DONE) {}
+
+ /*! construction of new task */
+ __forceinline Task (TaskFunction* closure, Task* parent, size_t stackPtr, size_t N)
+ : dependencies(1), stealable(true), closure(closure), parent(parent), stackPtr(stackPtr), N(N)
+ {
+ if (parent) parent->add_dependencies(+1);
+ switch_state(DONE,INITIALIZED);
+ }
+
+ /*! construction of stolen task, stealing thread will decrement initial dependency */
+ __forceinline Task (TaskFunction* closure, Task* parent)
+ : dependencies(1), stealable(false), closure(closure), parent(parent), stackPtr(-1), N(1)
+ {
+ switch_state(DONE,INITIALIZED);
+ }
+
+ /*! try to steal this task */
+ bool try_steal(Task& child)
+ {
+ if (!stealable) return false;
+ if (!try_switch_state(INITIALIZED,DONE)) return false;
+ new (&child) Task(closure, this);
+ return true;
+ }
+
+ /*! run this task */
+ dll_export void run(Thread& thread);
+
+ void run_internal(Thread& thread);
+
+ public:
+ std::atomic<int> state; //!< state this task is in
+ std::atomic<int> dependencies; //!< dependencies to wait for
+ std::atomic<bool> stealable; //!< true if task can be stolen
+ TaskFunction* closure; //!< the closure to execute
+ Task* parent; //!< parent task to signal when we are finished
+ size_t stackPtr; //!< stack location where closure is stored
+ size_t N; //!< approximative size of task
+ };
+
+ struct TaskQueue
+ {
+ TaskQueue ()
+ : left(0), right(0), stackPtr(0) {}
+
+ __forceinline void* alloc(size_t bytes, size_t align = 64)
+ {
+ size_t ofs = bytes + ((align - stackPtr) & (align-1));
+ if (stackPtr + ofs > CLOSURE_STACK_SIZE)
+ // -- GODOT start --
+ // throw std::runtime_error("closure stack overflow");
+ abort();
+ // -- GODOT end --
+ stackPtr += ofs;
+ return &stack[stackPtr-bytes];
+ }
+
+ template<typename Closure>
+ __forceinline void push_right(Thread& thread, const size_t size, const Closure& closure)
+ {
+ if (right >= TASK_STACK_SIZE)
+ // -- GODOT start --
+ // throw std::runtime_error("task stack overflow");
+ abort();
+ // -- GODOT end --
+
+ /* allocate new task on right side of stack */
+ size_t oldStackPtr = stackPtr;
+ TaskFunction* func = new (alloc(sizeof(ClosureTaskFunction<Closure>))) ClosureTaskFunction<Closure>(closure);
+ new (&tasks[right]) Task(func,thread.task,oldStackPtr,size);
+ right++;
+
+ /* also move left pointer */
+ if (left >= right-1) left = right-1;
+ }
+
+ dll_export bool execute_local(Thread& thread, Task* parent);
+ bool execute_local_internal(Thread& thread, Task* parent);
+ bool steal(Thread& thread);
+ size_t getTaskSizeAtLeft();
+
+ bool empty() { return right == 0; }
+
+ public:
+
+ /* task stack */
+ Task tasks[TASK_STACK_SIZE];
+ __aligned(64) std::atomic<size_t> left; //!< threads steal from left
+ __aligned(64) std::atomic<size_t> right; //!< new tasks are added to the right
+
+ /* closure stack */
+ __aligned(64) char stack[CLOSURE_STACK_SIZE];
+ size_t stackPtr;
+ };
+
+ /*! thread local structure for each thread */
+ struct Thread
+ {
+ ALIGNED_STRUCT_(64);
+
+ Thread (size_t threadIndex, const Ref<TaskScheduler>& scheduler)
+ : threadIndex(threadIndex), task(nullptr), scheduler(scheduler) {}
+
+ __forceinline size_t threadCount() {
+ return scheduler->threadCounter;
+ }
+
+ size_t threadIndex; //!< ID of this thread
+ TaskQueue tasks; //!< local task queue
+ Task* task; //!< current active task
+ Ref<TaskScheduler> scheduler; //!< pointer to task scheduler
+ };
+
+ /*! pool of worker threads */
+ struct ThreadPool
+ {
+ ThreadPool (bool set_affinity);
+ ~ThreadPool ();
+
+ /*! starts the threads */
+ dll_export void startThreads();
+
+ /*! sets number of threads to use */
+ void setNumThreads(size_t numThreads, bool startThreads = false);
+
+ /*! adds a task scheduler object for scheduling */
+ dll_export void add(const Ref<TaskScheduler>& scheduler);
+
+ /*! remove the task scheduler object again */
+ dll_export void remove(const Ref<TaskScheduler>& scheduler);
+
+ /*! returns number of threads of the thread pool */
+ size_t size() const { return numThreads; }
+
+ /*! main loop for all threads */
+ void thread_loop(size_t threadIndex);
+
+ private:
+ std::atomic<size_t> numThreads;
+ std::atomic<size_t> numThreadsRunning;
+ bool set_affinity;
+ std::atomic<bool> running;
+ std::vector<thread_t> threads;
+
+ private:
+ MutexSys mutex;
+ ConditionSys condition;
+ std::list<Ref<TaskScheduler> > schedulers;
+ };
+
+ TaskScheduler ();
+ ~TaskScheduler ();
+
+ /*! initializes the task scheduler */
+ static void create(size_t numThreads, bool set_affinity, bool start_threads);
+
+ /*! destroys the task scheduler again */
+ static void destroy();
+
+ /*! lets new worker threads join the tasking system */
+ void join();
+ void reset();
+
+ /*! let a worker thread allocate a thread index */
+ dll_export ssize_t allocThreadIndex();
+
+ /*! wait for some number of threads available (threadCount includes main thread) */
+ void wait_for_threads(size_t threadCount);
+
+ /*! thread loop for all worker threads */
+ // -- GODOT start --
+ // std::exception_ptr thread_loop(size_t threadIndex);
+ void thread_loop(size_t threadIndex);
+ // -- GODOT end --
+
+ /*! steals a task from a different thread */
+ bool steal_from_other_threads(Thread& thread);
+
+ template<typename Predicate, typename Body>
+ static void steal_loop(Thread& thread, const Predicate& pred, const Body& body);
+
+ /* spawn a new task at the top of the threads task stack */
+ template<typename Closure>
+ void spawn_root(const Closure& closure, size_t size = 1, bool useThreadPool = true)
+ {
+ if (useThreadPool) startThreads();
+
+ size_t threadIndex = allocThreadIndex();
+ std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation
+ Thread& thread = *mthread;
+ assert(threadLocal[threadIndex].load() == nullptr);
+ threadLocal[threadIndex] = &thread;
+ Thread* oldThread = swapThread(&thread);
+ thread.tasks.push_right(thread,size,closure);
+ {
+ Lock<MutexSys> lock(mutex);
+ anyTasksRunning++;
+ hasRootTask = true;
+ condition.notify_all();
+ }
+
+ if (useThreadPool) addScheduler(this);
+
+ while (thread.tasks.execute_local(thread,nullptr));
+ anyTasksRunning--;
+ if (useThreadPool) removeScheduler(this);
+
+ threadLocal[threadIndex] = nullptr;
+ swapThread(oldThread);
+
+ /* remember exception to throw */
+ std::exception_ptr except = nullptr;
+ if (cancellingException != nullptr) except = cancellingException;
+
+ /* wait for all threads to terminate */
+ threadCounter--;
+ while (threadCounter > 0) yield();
+ cancellingException = nullptr;
+
+ /* re-throw proper exception */
+ if (except != nullptr)
+ std::rethrow_exception(except);
+ }
+
+ /* spawn a new task at the top of the threads task stack */
+ template<typename Closure>
+ static __forceinline void spawn(size_t size, const Closure& closure)
+ {
+ Thread* thread = TaskScheduler::thread();
+ if (likely(thread != nullptr)) thread->tasks.push_right(*thread,size,closure);
+ else instance()->spawn_root(closure,size);
+ }
+
+ /* spawn a new task at the top of the threads task stack */
+ template<typename Closure>
+ static __forceinline void spawn(const Closure& closure) {
+ spawn(1,closure);
+ }
+
+ /* spawn a new task set */
+ template<typename Index, typename Closure>
+ static void spawn(const Index begin, const Index end, const Index blockSize, const Closure& closure)
+ {
+ spawn(end-begin, [=]()
+ {
+ if (end-begin <= blockSize) {
+ return closure(range<Index>(begin,end));
+ }
+ const Index center = (begin+end)/2;
+ spawn(begin,center,blockSize,closure);
+ spawn(center,end ,blockSize,closure);
+ wait();
+ });
+ }
+
+ /* work on spawned subtasks and wait until all have finished */
+ dll_export static bool wait();
+
+ /* returns the ID of the current thread */
+ dll_export static size_t threadID();
+
+ /* returns the index (0..threadCount-1) of the current thread */
+ dll_export static size_t threadIndex();
+
+ /* returns the total number of threads */
+ dll_export static size_t threadCount();
+
+ private:
+
+ /* returns the thread local task list of this worker thread */
+ dll_export static Thread* thread();
+
+ /* sets the thread local task list of this worker thread */
+ dll_export static Thread* swapThread(Thread* thread);
+
+ /*! returns the taskscheduler object to be used by the master thread */
+ dll_export static TaskScheduler* instance();
+
+ /*! starts the threads */
+ dll_export static void startThreads();
+
+ /*! adds a task scheduler object for scheduling */
+ dll_export static void addScheduler(const Ref<TaskScheduler>& scheduler);
+
+ /*! remove the task scheduler object again */
+ dll_export static void removeScheduler(const Ref<TaskScheduler>& scheduler);
+
+ private:
+ std::vector<atomic<Thread*>> threadLocal;
+ std::atomic<size_t> threadCounter;
+ std::atomic<size_t> anyTasksRunning;
+ std::atomic<bool> hasRootTask;
+ std::exception_ptr cancellingException;
+ MutexSys mutex;
+ ConditionSys condition;
+
+ private:
+ static size_t g_numThreads;
+ static __thread TaskScheduler* g_instance;
+ static __thread Thread* thread_local_thread;
+ static ThreadPool* threadPool;
+ };
+
+ RTC_NAMESPACE_END
+
+#if defined(RTC_NAMESPACE)
+ using RTC_NAMESPACE::TaskScheduler;
+#endif
+}
diff --git a/thirdparty/embree/common/tasking/taskschedulerppl.h b/thirdparty/embree/common/tasking/taskschedulerppl.h
new file mode 100644
index 0000000000..cbc2ecdbb8
--- /dev/null
+++ b/thirdparty/embree/common/tasking/taskschedulerppl.h
@@ -0,0 +1,46 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/alloc.h"
+#include "../sys/barrier.h"
+#include "../sys/thread.h"
+#include "../sys/mutex.h"
+#include "../sys/condition.h"
+#include "../sys/ref.h"
+
+#if !defined(__WIN32__)
+#error PPL tasking system only available under windows
+#endif
+
+#include <ppl.h>
+
+namespace embree
+{
+ struct TaskScheduler
+ {
+ /*! initializes the task scheduler */
+ static void create(size_t numThreads, bool set_affinity, bool start_threads);
+
+ /*! destroys the task scheduler again */
+ static void destroy();
+
+ /* returns the ID of the current thread */
+ static __forceinline size_t threadID() {
+ return GetCurrentThreadId();
+ }
+
+ /* returns the index (0..threadCount-1) of the current thread */
+ /* FIXME: threadIndex is NOT supported by PPL! */
+ static __forceinline size_t threadIndex() {
+ return 0;
+ }
+
+ /* returns the total number of threads */
+ static __forceinline size_t threadCount() {
+ return GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS) + 1;
+ }
+ };
+};
diff --git a/thirdparty/embree/common/tasking/taskschedulertbb.h b/thirdparty/embree/common/tasking/taskschedulertbb.h
new file mode 100644
index 0000000000..35bd49849f
--- /dev/null
+++ b/thirdparty/embree/common/tasking/taskschedulertbb.h
@@ -0,0 +1,73 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../sys/platform.h"
+#include "../sys/alloc.h"
+#include "../sys/barrier.h"
+#include "../sys/thread.h"
+#include "../sys/mutex.h"
+#include "../sys/condition.h"
+#include "../sys/ref.h"
+
+#if defined(__WIN32__)
+// -- GODOT start --
+#if !defined(NOMINMAX)
+// -- GODOT end --
+# define NOMINMAX
+// -- GODOT start --
+#endif
+// -- GODOT end --
+#endif
+
+// We need to define these to avoid implicit linkage against
+// tbb_debug.lib under Windows. When removing these lines debug build
+// under Windows fails.
+#define __TBB_NO_IMPLICIT_LINKAGE 1
+#define __TBBMALLOC_NO_IMPLICIT_LINKAGE 1
+#define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
+#define TBB_PREVIEW_ISOLATED_TASK_GROUP 1
+#include "tbb/tbb.h"
+#include "tbb/parallel_sort.h"
+
+namespace embree
+{
+ struct TaskScheduler
+ {
+ /*! initializes the task scheduler */
+ static void create(size_t numThreads, bool set_affinity, bool start_threads);
+
+ /*! destroys the task scheduler again */
+ static void destroy();
+
+ /* returns the ID of the current thread */
+ static __forceinline size_t threadID()
+ {
+ return threadIndex();
+ }
+
+ /* returns the index (0..threadCount-1) of the current thread */
+ static __forceinline size_t threadIndex()
+ {
+#if TBB_INTERFACE_VERSION >= 9100
+ return tbb::this_task_arena::current_thread_index();
+#elif TBB_INTERFACE_VERSION >= 9000
+ return tbb::task_arena::current_thread_index();
+#else
+ return 0;
+#endif
+ }
+
+ /* returns the total number of threads */
+ static __forceinline size_t threadCount() {
+#if TBB_INTERFACE_VERSION >= 9100
+ return tbb::this_task_arena::max_concurrency();
+#else
+ return tbb::task_scheduler_init::default_num_threads();
+#endif
+ }
+
+ };
+
+};
diff --git a/thirdparty/embree/include/embree3/rtcore.h b/thirdparty/embree/include/embree3/rtcore.h
new file mode 100644
index 0000000000..450ab4c535
--- /dev/null
+++ b/thirdparty/embree/include/embree3/rtcore.h
@@ -0,0 +1,14 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_config.h"
+#include "rtcore_common.h"
+#include "rtcore_device.h"
+#include "rtcore_buffer.h"
+#include "rtcore_ray.h"
+#include "rtcore_geometry.h"
+#include "rtcore_scene.h"
+#include "rtcore_builder.h"
+#include "rtcore_quaternion.h"
diff --git a/thirdparty/embree/include/embree3/rtcore_buffer.h b/thirdparty/embree/include/embree3/rtcore_buffer.h
new file mode 100644
index 0000000000..6b8eba9769
--- /dev/null
+++ b/thirdparty/embree/include/embree3/rtcore_buffer.h
@@ -0,0 +1,51 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_device.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Types of buffers */
+enum RTCBufferType
+{
+ RTC_BUFFER_TYPE_INDEX = 0,
+ RTC_BUFFER_TYPE_VERTEX = 1,
+ RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE = 2,
+ RTC_BUFFER_TYPE_NORMAL = 3,
+ RTC_BUFFER_TYPE_TANGENT = 4,
+ RTC_BUFFER_TYPE_NORMAL_DERIVATIVE = 5,
+
+ RTC_BUFFER_TYPE_GRID = 8,
+
+ RTC_BUFFER_TYPE_FACE = 16,
+ RTC_BUFFER_TYPE_LEVEL = 17,
+ RTC_BUFFER_TYPE_EDGE_CREASE_INDEX = 18,
+ RTC_BUFFER_TYPE_EDGE_CREASE_WEIGHT = 19,
+ RTC_BUFFER_TYPE_VERTEX_CREASE_INDEX = 20,
+ RTC_BUFFER_TYPE_VERTEX_CREASE_WEIGHT = 21,
+ RTC_BUFFER_TYPE_HOLE = 22,
+
+ RTC_BUFFER_TYPE_FLAGS = 32
+};
+
+/* Opaque buffer type */
+typedef struct RTCBufferTy* RTCBuffer;
+
+/* Creates a new buffer. */
+RTC_API RTCBuffer rtcNewBuffer(RTCDevice device, size_t byteSize);
+
+/* Creates a new shared buffer. */
+RTC_API RTCBuffer rtcNewSharedBuffer(RTCDevice device, void* ptr, size_t byteSize);
+
+/* Returns a pointer to the buffer data. */
+RTC_API void* rtcGetBufferData(RTCBuffer buffer);
+
+/* Retains the buffer (increments the reference count). */
+RTC_API void rtcRetainBuffer(RTCBuffer buffer);
+
+/* Releases the buffer (decrements the reference count). */
+RTC_API void rtcReleaseBuffer(RTCBuffer buffer);
+
+RTC_NAMESPACE_END
diff --git a/thirdparty/embree/include/embree3/rtcore_builder.h b/thirdparty/embree/include/embree3/rtcore_builder.h
new file mode 100644
index 0000000000..4bff999fed
--- /dev/null
+++ b/thirdparty/embree/include/embree3/rtcore_builder.h
@@ -0,0 +1,125 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_scene.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Opaque BVH type */
+typedef struct RTCBVHTy* RTCBVH;
+
+/* Input build primitives for the builder */
+struct RTC_ALIGN(32) RTCBuildPrimitive
+{
+ float lower_x, lower_y, lower_z;
+ unsigned int geomID;
+ float upper_x, upper_y, upper_z;
+ unsigned int primID;
+};
+
+/* Opaque thread local allocator type */
+typedef struct RTCThreadLocalAllocatorTy* RTCThreadLocalAllocator;
+
+/* Callback to create a node */
+typedef void* (*RTCCreateNodeFunction) (RTCThreadLocalAllocator allocator, unsigned int childCount, void* userPtr);
+
+/* Callback to set the pointer to all children */
+typedef void (*RTCSetNodeChildrenFunction) (void* nodePtr, void** children, unsigned int childCount, void* userPtr);
+
+/* Callback to set the bounds of all children */
+typedef void (*RTCSetNodeBoundsFunction) (void* nodePtr, const struct RTCBounds** bounds, unsigned int childCount, void* userPtr);
+
+/* Callback to create a leaf node */
+typedef void* (*RTCCreateLeafFunction) (RTCThreadLocalAllocator allocator, const struct RTCBuildPrimitive* primitives, size_t primitiveCount, void* userPtr);
+
+/* Callback to split a build primitive */
+typedef void (*RTCSplitPrimitiveFunction) (const struct RTCBuildPrimitive* primitive, unsigned int dimension, float position, struct RTCBounds* leftBounds, struct RTCBounds* rightBounds, void* userPtr);
+
+/* Build flags */
+enum RTCBuildFlags
+{
+ RTC_BUILD_FLAG_NONE = 0,
+ RTC_BUILD_FLAG_DYNAMIC = (1 << 0),
+};
+
+enum RTCBuildConstants
+{
+ RTC_BUILD_MAX_PRIMITIVES_PER_LEAF = 32
+};
+
+/* Input for builders */
+struct RTCBuildArguments
+{
+ size_t byteSize;
+
+ enum RTCBuildQuality buildQuality;
+ enum RTCBuildFlags buildFlags;
+ unsigned int maxBranchingFactor;
+ unsigned int maxDepth;
+ unsigned int sahBlockSize;
+ unsigned int minLeafSize;
+ unsigned int maxLeafSize;
+ float traversalCost;
+ float intersectionCost;
+
+ RTCBVH bvh;
+ struct RTCBuildPrimitive* primitives;
+ size_t primitiveCount;
+ size_t primitiveArrayCapacity;
+
+ RTCCreateNodeFunction createNode;
+ RTCSetNodeChildrenFunction setNodeChildren;
+ RTCSetNodeBoundsFunction setNodeBounds;
+ RTCCreateLeafFunction createLeaf;
+ RTCSplitPrimitiveFunction splitPrimitive;
+ RTCProgressMonitorFunction buildProgress;
+ void* userPtr;
+};
+
+/* Returns the default build settings. */
+RTC_FORCEINLINE struct RTCBuildArguments rtcDefaultBuildArguments()
+{
+ struct RTCBuildArguments args;
+ args.byteSize = sizeof(args);
+ args.buildQuality = RTC_BUILD_QUALITY_MEDIUM;
+ args.buildFlags = RTC_BUILD_FLAG_NONE;
+ args.maxBranchingFactor = 2;
+ args.maxDepth = 32;
+ args.sahBlockSize = 1;
+ args.minLeafSize = 1;
+ args.maxLeafSize = RTC_BUILD_MAX_PRIMITIVES_PER_LEAF;
+ args.traversalCost = 1.0f;
+ args.intersectionCost = 1.0f;
+ args.bvh = NULL;
+ args.primitives = NULL;
+ args.primitiveCount = 0;
+ args.primitiveArrayCapacity = 0;
+ args.createNode = NULL;
+ args.setNodeChildren = NULL;
+ args.setNodeBounds = NULL;
+ args.createLeaf = NULL;
+ args.splitPrimitive = NULL;
+ args.buildProgress = NULL;
+ args.userPtr = NULL;
+ return args;
+}
+
+/* Creates a new BVH. */
+RTC_API RTCBVH rtcNewBVH(RTCDevice device);
+
+/* Builds a BVH. */
+RTC_API void* rtcBuildBVH(const struct RTCBuildArguments* args);
+
+/* Allocates memory using the thread local allocator. */
+RTC_API void* rtcThreadLocalAlloc(RTCThreadLocalAllocator allocator, size_t bytes, size_t align);
+
+/* Retains the BVH (increments reference count). */
+RTC_API void rtcRetainBVH(RTCBVH bvh);
+
+/* Releases the BVH (decrements reference count). */
+RTC_API void rtcReleaseBVH(RTCBVH bvh);
+
+RTC_NAMESPACE_END
+
diff --git a/thirdparty/embree/include/embree3/rtcore_common.h b/thirdparty/embree/include/embree3/rtcore_common.h
new file mode 100644
index 0000000000..4857e1e05e
--- /dev/null
+++ b/thirdparty/embree/include/embree3/rtcore_common.h
@@ -0,0 +1,328 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+#include "rtcore_config.h"
+
+RTC_NAMESPACE_BEGIN
+
+#if defined(_WIN32)
+#if defined(_M_X64)
+typedef long long ssize_t;
+#else
+typedef int ssize_t;
+#endif
+#endif
+
+// -- GODOT start --
+#if defined(_WIN32) && defined(_MSC_VER)
+// -- GODOT end --
+# define RTC_ALIGN(...) __declspec(align(__VA_ARGS__))
+#else
+# define RTC_ALIGN(...) __attribute__((aligned(__VA_ARGS__)))
+#endif
+
+#if !defined (RTC_DEPRECATED)
+#ifdef __GNUC__
+ #define RTC_DEPRECATED __attribute__((deprecated))
+#elif defined(_MSC_VER)
+ #define RTC_DEPRECATED __declspec(deprecated)
+#else
+ #define RTC_DEPRECATED
+#endif
+#endif
+
+#if defined(_WIN32)
+# define RTC_FORCEINLINE __forceinline
+#else
+# define RTC_FORCEINLINE inline __attribute__((always_inline))
+#endif
+
+/* Invalid geometry ID */
+#define RTC_INVALID_GEOMETRY_ID ((unsigned int)-1)
+
+/* Maximum number of time steps */
+#define RTC_MAX_TIME_STEP_COUNT 129
+
+/* Formats of buffers and other data structures */
+enum RTCFormat
+{
+ RTC_FORMAT_UNDEFINED = 0,
+
+ /* 8-bit unsigned integer */
+ RTC_FORMAT_UCHAR = 0x1001,
+ RTC_FORMAT_UCHAR2,
+ RTC_FORMAT_UCHAR3,
+ RTC_FORMAT_UCHAR4,
+
+ /* 8-bit signed integer */
+ RTC_FORMAT_CHAR = 0x2001,
+ RTC_FORMAT_CHAR2,
+ RTC_FORMAT_CHAR3,
+ RTC_FORMAT_CHAR4,
+
+ /* 16-bit unsigned integer */
+ RTC_FORMAT_USHORT = 0x3001,
+ RTC_FORMAT_USHORT2,
+ RTC_FORMAT_USHORT3,
+ RTC_FORMAT_USHORT4,
+
+ /* 16-bit signed integer */
+ RTC_FORMAT_SHORT = 0x4001,
+ RTC_FORMAT_SHORT2,
+ RTC_FORMAT_SHORT3,
+ RTC_FORMAT_SHORT4,
+
+ /* 32-bit unsigned integer */
+ RTC_FORMAT_UINT = 0x5001,
+ RTC_FORMAT_UINT2,
+ RTC_FORMAT_UINT3,
+ RTC_FORMAT_UINT4,
+
+ /* 32-bit signed integer */
+ RTC_FORMAT_INT = 0x6001,
+ RTC_FORMAT_INT2,
+ RTC_FORMAT_INT3,
+ RTC_FORMAT_INT4,
+
+ /* 64-bit unsigned integer */
+ RTC_FORMAT_ULLONG = 0x7001,
+ RTC_FORMAT_ULLONG2,
+ RTC_FORMAT_ULLONG3,
+ RTC_FORMAT_ULLONG4,
+
+ /* 64-bit signed integer */
+ RTC_FORMAT_LLONG = 0x8001,
+ RTC_FORMAT_LLONG2,
+ RTC_FORMAT_LLONG3,
+ RTC_FORMAT_LLONG4,
+
+ /* 32-bit float */
+ RTC_FORMAT_FLOAT = 0x9001,
+ RTC_FORMAT_FLOAT2,
+ RTC_FORMAT_FLOAT3,
+ RTC_FORMAT_FLOAT4,
+ RTC_FORMAT_FLOAT5,
+ RTC_FORMAT_FLOAT6,
+ RTC_FORMAT_FLOAT7,
+ RTC_FORMAT_FLOAT8,
+ RTC_FORMAT_FLOAT9,
+ RTC_FORMAT_FLOAT10,
+ RTC_FORMAT_FLOAT11,
+ RTC_FORMAT_FLOAT12,
+ RTC_FORMAT_FLOAT13,
+ RTC_FORMAT_FLOAT14,
+ RTC_FORMAT_FLOAT15,
+ RTC_FORMAT_FLOAT16,
+
+ /* 32-bit float matrix (row-major order) */
+ RTC_FORMAT_FLOAT2X2_ROW_MAJOR = 0x9122,
+ RTC_FORMAT_FLOAT2X3_ROW_MAJOR = 0x9123,
+ RTC_FORMAT_FLOAT2X4_ROW_MAJOR = 0x9124,
+ RTC_FORMAT_FLOAT3X2_ROW_MAJOR = 0x9132,
+ RTC_FORMAT_FLOAT3X3_ROW_MAJOR = 0x9133,
+ RTC_FORMAT_FLOAT3X4_ROW_MAJOR = 0x9134,
+ RTC_FORMAT_FLOAT4X2_ROW_MAJOR = 0x9142,
+ RTC_FORMAT_FLOAT4X3_ROW_MAJOR = 0x9143,
+ RTC_FORMAT_FLOAT4X4_ROW_MAJOR = 0x9144,
+
+ /* 32-bit float matrix (column-major order) */
+ RTC_FORMAT_FLOAT2X2_COLUMN_MAJOR = 0x9222,
+ RTC_FORMAT_FLOAT2X3_COLUMN_MAJOR = 0x9223,
+ RTC_FORMAT_FLOAT2X4_COLUMN_MAJOR = 0x9224,
+ RTC_FORMAT_FLOAT3X2_COLUMN_MAJOR = 0x9232,
+ RTC_FORMAT_FLOAT3X3_COLUMN_MAJOR = 0x9233,
+ RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR = 0x9234,
+ RTC_FORMAT_FLOAT4X2_COLUMN_MAJOR = 0x9242,
+ RTC_FORMAT_FLOAT4X3_COLUMN_MAJOR = 0x9243,
+ RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR = 0x9244,
+
+ /* special 12-byte format for grids */
+ RTC_FORMAT_GRID = 0xA001
+};
+
+/* Build quality levels */
+enum RTCBuildQuality
+{
+ RTC_BUILD_QUALITY_LOW = 0,
+ RTC_BUILD_QUALITY_MEDIUM = 1,
+ RTC_BUILD_QUALITY_HIGH = 2,
+ RTC_BUILD_QUALITY_REFIT = 3,
+};
+
+/* Axis-aligned bounding box representation */
+struct RTC_ALIGN(16) RTCBounds
+{
+ float lower_x, lower_y, lower_z, align0;
+ float upper_x, upper_y, upper_z, align1;
+};
+
+/* Linear axis-aligned bounding box representation */
+struct RTC_ALIGN(16) RTCLinearBounds
+{
+ struct RTCBounds bounds0;
+ struct RTCBounds bounds1;
+};
+
+/* Intersection context flags */
+enum RTCIntersectContextFlags
+{
+ RTC_INTERSECT_CONTEXT_FLAG_NONE = 0,
+ RTC_INTERSECT_CONTEXT_FLAG_INCOHERENT = (0 << 0), // optimize for incoherent rays
+ RTC_INTERSECT_CONTEXT_FLAG_COHERENT = (1 << 0) // optimize for coherent rays
+};
+
+/* Arguments for RTCFilterFunctionN */
+struct RTCFilterFunctionNArguments
+{
+ int* valid;
+ void* geometryUserPtr;
+ struct RTCIntersectContext* context;
+ struct RTCRayN* ray;
+ struct RTCHitN* hit;
+ unsigned int N;
+};
+
+/* Filter callback function */
+typedef void (*RTCFilterFunctionN)(const struct RTCFilterFunctionNArguments* args);
+
+/* Intersection context passed to intersect/occluded calls */
+struct RTCIntersectContext
+{
+ enum RTCIntersectContextFlags flags; // intersection flags
+ RTCFilterFunctionN filter; // filter function to execute
+
+#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1
+ unsigned int instStackSize; // Number of instances currently on the stack.
+#endif
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // The current stack of instance ids.
+
+#if RTC_MIN_WIDTH
+ float minWidthDistanceFactor; // curve radius is set to this factor times distance to ray origin
+#endif
+};
+
+/* Initializes an intersection context. */
+RTC_FORCEINLINE void rtcInitIntersectContext(struct RTCIntersectContext* context)
+{
+ unsigned l = 0;
+ context->flags = RTC_INTERSECT_CONTEXT_FLAG_INCOHERENT;
+ context->filter = NULL;
+
+#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1
+ context->instStackSize = 0;
+#endif
+ for (; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ context->instID[l] = RTC_INVALID_GEOMETRY_ID;
+
+#if RTC_MIN_WIDTH
+ context->minWidthDistanceFactor = 0.0f;
+#endif
+}
+
+/* Point query structure for closest point query */
+struct RTC_ALIGN(16) RTCPointQuery
+{
+ float x; // x coordinate of the query point
+ float y; // y coordinate of the query point
+ float z; // z coordinate of the query point
+ float time; // time of the point query
+ float radius; // radius of the point query
+};
+
+/* Structure of a packet of 4 query points */
+struct RTC_ALIGN(16) RTCPointQuery4
+{
+ float x[4]; // x coordinate of the query point
+ float y[4]; // y coordinate of the query point
+ float z[4]; // z coordinate of the query point
+ float time[4]; // time of the point query
+ float radius[4]; // radius of the point query
+};
+
+/* Structure of a packet of 8 query points */
+struct RTC_ALIGN(32) RTCPointQuery8
+{
+ float x[8]; // x coordinate of the query point
+ float y[8]; // y coordinate of the query point
+ float z[8]; // z coordinate of the query point
+ float time[8]; // time of the point query
+ float radius[8]; // radius ofr the point query
+};
+
+/* Structure of a packet of 16 query points */
+struct RTC_ALIGN(64) RTCPointQuery16
+{
+ float x[16]; // x coordinate of the query point
+ float y[16]; // y coordinate of the query point
+ float z[16]; // z coordinate of the query point
+ float time[16]; // time of the point quey
+ float radius[16]; // radius of the point query
+};
+
+struct RTCPointQueryN;
+
+struct RTC_ALIGN(16) RTCPointQueryContext
+{
+ // accumulated 4x4 column major matrices from world space to instance space.
+ // undefined if size == 0.
+ float world2inst[RTC_MAX_INSTANCE_LEVEL_COUNT][16];
+
+ // accumulated 4x4 column major matrices from instance space to world space.
+ // undefined if size == 0.
+ float inst2world[RTC_MAX_INSTANCE_LEVEL_COUNT][16];
+
+ // instance ids.
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT];
+
+ // number of instances currently on the stack.
+ unsigned int instStackSize;
+};
+
+/* Initializes an intersection context. */
+RTC_FORCEINLINE void rtcInitPointQueryContext(struct RTCPointQueryContext* context)
+{
+ context->instStackSize = 0;
+ context->instID[0] = RTC_INVALID_GEOMETRY_ID;
+}
+
+struct RTC_ALIGN(16) RTCPointQueryFunctionArguments
+{
+ // The (world space) query object that was passed as an argument of rtcPointQuery. The
+ // radius of the query can be decreased inside the callback to shrink the
+ // search domain. Increasing the radius or modifying the time or position of
+ // the query results in undefined behaviour.
+ struct RTCPointQuery* query;
+
+ // Used for user input/output data. Will not be read or modified internally.
+ void* userPtr;
+
+ // primitive and geometry ID of primitive
+ unsigned int primID;
+ unsigned int geomID;
+
+ // the context with transformation and instance ID stack
+ struct RTCPointQueryContext* context;
+
+ // If the current instance transform M (= context->world2inst[context->instStackSize])
+ // is a similarity matrix, i.e there is a constant factor similarityScale such that,
+ // for all x,y: dist(Mx, My) = similarityScale * dist(x, y),
+ // The similarity scale is 0, if the current instance transform is not a
+ // similarity transform and vice versa. The similarity scale allows to compute
+ // distance information in instance space and scale the distances into world
+ // space by dividing with the similarity scale, for example, to update the
+ // query radius. If the current instance transform is not a similarity
+ // transform (similarityScale = 0), the distance computation has to be
+ // performed in world space to ensure correctness. if there is no instance
+ // transform (context->instStackSize == 0), the similarity scale is 1.
+ float similarityScale;
+};
+
+typedef bool (*RTCPointQueryFunction)(struct RTCPointQueryFunctionArguments* args);
+
+RTC_NAMESPACE_END
diff --git a/thirdparty/embree/include/embree3/rtcore_config.h b/thirdparty/embree/include/embree3/rtcore_config.h
new file mode 100644
index 0000000000..3a9819c9f1
--- /dev/null
+++ b/thirdparty/embree/include/embree3/rtcore_config.h
@@ -0,0 +1,57 @@
+
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define RTC_VERSION_MAJOR 3
+#define RTC_VERSION_MINOR 13
+#define RTC_VERSION_PATCH 0
+#define RTC_VERSION 31300
+#define RTC_VERSION_STRING "3.13.0"
+
+#define RTC_MAX_INSTANCE_LEVEL_COUNT 1
+
+#define EMBREE_MIN_WIDTH 0
+#define RTC_MIN_WIDTH EMBREE_MIN_WIDTH
+
+#define EMBREE_STATIC_LIB
+/* #undef EMBREE_API_NAMESPACE */
+
+#if defined(EMBREE_API_NAMESPACE)
+# define RTC_NAMESPACE
+# define RTC_NAMESPACE_BEGIN namespace {
+# define RTC_NAMESPACE_END }
+# define RTC_NAMESPACE_USE using namespace ;
+# define RTC_API_EXTERN_C
+# undef EMBREE_API_NAMESPACE
+#else
+# define RTC_NAMESPACE_BEGIN
+# define RTC_NAMESPACE_END
+# define RTC_NAMESPACE_USE
+# if defined(__cplusplus)
+# define RTC_API_EXTERN_C extern "C"
+# else
+# define RTC_API_EXTERN_C
+# endif
+#endif
+
+#if defined(ISPC)
+# define RTC_API_IMPORT extern "C" unmasked
+# define RTC_API_EXPORT extern "C" unmasked
+#elif defined(EMBREE_STATIC_LIB)
+# define RTC_API_IMPORT RTC_API_EXTERN_C
+# define RTC_API_EXPORT RTC_API_EXTERN_C
+#elif defined(_WIN32)
+# define RTC_API_IMPORT RTC_API_EXTERN_C __declspec(dllimport)
+# define RTC_API_EXPORT RTC_API_EXTERN_C __declspec(dllexport)
+#else
+# define RTC_API_IMPORT RTC_API_EXTERN_C
+# define RTC_API_EXPORT RTC_API_EXTERN_C __attribute__ ((visibility ("default")))
+#endif
+
+#if defined(RTC_EXPORT_API)
+# define RTC_API RTC_API_EXPORT
+#else
+# define RTC_API RTC_API_IMPORT
+#endif
diff --git a/thirdparty/embree/include/embree3/rtcore_device.h b/thirdparty/embree/include/embree3/rtcore_device.h
new file mode 100644
index 0000000000..2dd3047603
--- /dev/null
+++ b/thirdparty/embree/include/embree3/rtcore_device.h
@@ -0,0 +1,87 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_common.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Opaque device type */
+typedef struct RTCDeviceTy* RTCDevice;
+
+/* Creates a new Embree device. */
+RTC_API RTCDevice rtcNewDevice(const char* config);
+
+/* Retains the Embree device (increments the reference count). */
+RTC_API void rtcRetainDevice(RTCDevice device);
+
+/* Releases an Embree device (decrements the reference count). */
+RTC_API void rtcReleaseDevice(RTCDevice device);
+
+/* Device properties */
+enum RTCDeviceProperty
+{
+ RTC_DEVICE_PROPERTY_VERSION = 0,
+ RTC_DEVICE_PROPERTY_VERSION_MAJOR = 1,
+ RTC_DEVICE_PROPERTY_VERSION_MINOR = 2,
+ RTC_DEVICE_PROPERTY_VERSION_PATCH = 3,
+
+ RTC_DEVICE_PROPERTY_NATIVE_RAY4_SUPPORTED = 32,
+ RTC_DEVICE_PROPERTY_NATIVE_RAY8_SUPPORTED = 33,
+ RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED = 34,
+ RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED = 35,
+
+ RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED = 63,
+ RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED = 64,
+ RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED = 65,
+ RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED = 66,
+ RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED = 67,
+ RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED = 68,
+
+ RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED = 96,
+ RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED = 97,
+ RTC_DEVICE_PROPERTY_SUBDIVISION_GEOMETRY_SUPPORTED = 98,
+ RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED = 99,
+ RTC_DEVICE_PROPERTY_USER_GEOMETRY_SUPPORTED = 100,
+ RTC_DEVICE_PROPERTY_POINT_GEOMETRY_SUPPORTED = 101,
+
+ RTC_DEVICE_PROPERTY_TASKING_SYSTEM = 128,
+ RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED = 129,
+ RTC_DEVICE_PROPERTY_PARALLEL_COMMIT_SUPPORTED = 130
+};
+
+/* Gets a device property. */
+RTC_API ssize_t rtcGetDeviceProperty(RTCDevice device, enum RTCDeviceProperty prop);
+
+/* Sets a device property. */
+RTC_API void rtcSetDeviceProperty(RTCDevice device, const enum RTCDeviceProperty prop, ssize_t value);
+
+/* Error codes */
+enum RTCError
+{
+ RTC_ERROR_NONE = 0,
+ RTC_ERROR_UNKNOWN = 1,
+ RTC_ERROR_INVALID_ARGUMENT = 2,
+ RTC_ERROR_INVALID_OPERATION = 3,
+ RTC_ERROR_OUT_OF_MEMORY = 4,
+ RTC_ERROR_UNSUPPORTED_CPU = 5,
+ RTC_ERROR_CANCELLED = 6
+};
+
+/* Returns the error code. */
+RTC_API enum RTCError rtcGetDeviceError(RTCDevice device);
+
+/* Error callback function */
+typedef void (*RTCErrorFunction)(void* userPtr, enum RTCError code, const char* str);
+
+/* Sets the error callback function. */
+RTC_API void rtcSetDeviceErrorFunction(RTCDevice device, RTCErrorFunction error, void* userPtr);
+
+/* Memory monitor callback function */
+typedef bool (*RTCMemoryMonitorFunction)(void* ptr, ssize_t bytes, bool post);
+
+/* Sets the memory monitor callback function. */
+RTC_API void rtcSetDeviceMemoryMonitorFunction(RTCDevice device, RTCMemoryMonitorFunction memoryMonitor, void* userPtr);
+
+RTC_NAMESPACE_END
diff --git a/thirdparty/embree/include/embree3/rtcore_geometry.h b/thirdparty/embree/include/embree3/rtcore_geometry.h
new file mode 100644
index 0000000000..d1de17491c
--- /dev/null
+++ b/thirdparty/embree/include/embree3/rtcore_geometry.h
@@ -0,0 +1,383 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_buffer.h"
+#include "rtcore_quaternion.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Opaque scene type */
+typedef struct RTCSceneTy* RTCScene;
+
+/* Opaque geometry type */
+typedef struct RTCGeometryTy* RTCGeometry;
+
+/* Types of geometries */
+enum RTCGeometryType
+{
+ RTC_GEOMETRY_TYPE_TRIANGLE = 0, // triangle mesh
+ RTC_GEOMETRY_TYPE_QUAD = 1, // quad (triangle pair) mesh
+ RTC_GEOMETRY_TYPE_GRID = 2, // grid mesh
+
+ RTC_GEOMETRY_TYPE_SUBDIVISION = 8, // Catmull-Clark subdivision surface
+
+ RTC_GEOMETRY_TYPE_CONE_LINEAR_CURVE = 15, // Cone linear curves - discontinuous at edge boundaries
+ RTC_GEOMETRY_TYPE_ROUND_LINEAR_CURVE = 16, // Round (rounded cone like) linear curves
+ RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE = 17, // flat (ribbon-like) linear curves
+
+ RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE = 24, // round (tube-like) Bezier curves
+ RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE = 25, // flat (ribbon-like) Bezier curves
+ RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BEZIER_CURVE = 26, // flat normal-oriented Bezier curves
+
+ RTC_GEOMETRY_TYPE_ROUND_BSPLINE_CURVE = 32, // round (tube-like) B-spline curves
+ RTC_GEOMETRY_TYPE_FLAT_BSPLINE_CURVE = 33, // flat (ribbon-like) B-spline curves
+ RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BSPLINE_CURVE = 34, // flat normal-oriented B-spline curves
+
+ RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE = 40, // round (tube-like) Hermite curves
+ RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE = 41, // flat (ribbon-like) Hermite curves
+ RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_HERMITE_CURVE = 42, // flat normal-oriented Hermite curves
+
+ RTC_GEOMETRY_TYPE_SPHERE_POINT = 50,
+ RTC_GEOMETRY_TYPE_DISC_POINT = 51,
+ RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT = 52,
+
+ RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE = 58, // round (tube-like) Catmull-Rom curves
+ RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE = 59, // flat (ribbon-like) Catmull-Rom curves
+ RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_CATMULL_ROM_CURVE = 60, // flat normal-oriented Catmull-Rom curves
+
+ RTC_GEOMETRY_TYPE_USER = 120, // user-defined geometry
+ RTC_GEOMETRY_TYPE_INSTANCE = 121 // scene instance
+};
+
+/* Interpolation modes for subdivision surfaces */
+enum RTCSubdivisionMode
+{
+ RTC_SUBDIVISION_MODE_NO_BOUNDARY = 0,
+ RTC_SUBDIVISION_MODE_SMOOTH_BOUNDARY = 1,
+ RTC_SUBDIVISION_MODE_PIN_CORNERS = 2,
+ RTC_SUBDIVISION_MODE_PIN_BOUNDARY = 3,
+ RTC_SUBDIVISION_MODE_PIN_ALL = 4,
+};
+
+/* Curve segment flags */
+enum RTCCurveFlags
+{
+ RTC_CURVE_FLAG_NEIGHBOR_LEFT = (1 << 0), // left segments exists
+ RTC_CURVE_FLAG_NEIGHBOR_RIGHT = (1 << 1) // right segment exists
+};
+
+/* Arguments for RTCBoundsFunction */
+struct RTCBoundsFunctionArguments
+{
+ void* geometryUserPtr;
+ unsigned int primID;
+ unsigned int timeStep;
+ struct RTCBounds* bounds_o;
+};
+
+/* Bounding callback function */
+typedef void (*RTCBoundsFunction)(const struct RTCBoundsFunctionArguments* args);
+
+/* Arguments for RTCIntersectFunctionN */
+struct RTCIntersectFunctionNArguments
+{
+ int* valid;
+ void* geometryUserPtr;
+ unsigned int primID;
+ struct RTCIntersectContext* context;
+ struct RTCRayHitN* rayhit;
+ unsigned int N;
+ unsigned int geomID;
+};
+
+/* Intersection callback function */
+typedef void (*RTCIntersectFunctionN)(const struct RTCIntersectFunctionNArguments* args);
+
+/* Arguments for RTCOccludedFunctionN */
+struct RTCOccludedFunctionNArguments
+{
+ int* valid;
+ void* geometryUserPtr;
+ unsigned int primID;
+ struct RTCIntersectContext* context;
+ struct RTCRayN* ray;
+ unsigned int N;
+ unsigned int geomID;
+};
+
+/* Occlusion callback function */
+typedef void (*RTCOccludedFunctionN)(const struct RTCOccludedFunctionNArguments* args);
+
+/* Arguments for RTCDisplacementFunctionN */
+struct RTCDisplacementFunctionNArguments
+{
+ void* geometryUserPtr;
+ RTCGeometry geometry;
+ unsigned int primID;
+ unsigned int timeStep;
+ const float* u;
+ const float* v;
+ const float* Ng_x;
+ const float* Ng_y;
+ const float* Ng_z;
+ float* P_x;
+ float* P_y;
+ float* P_z;
+ unsigned int N;
+};
+
+/* Displacement mapping callback function */
+typedef void (*RTCDisplacementFunctionN)(const struct RTCDisplacementFunctionNArguments* args);
+
+/* Creates a new geometry of specified type. */
+RTC_API RTCGeometry rtcNewGeometry(RTCDevice device, enum RTCGeometryType type);
+
+/* Retains the geometry (increments the reference count). */
+RTC_API void rtcRetainGeometry(RTCGeometry geometry);
+
+/* Releases the geometry (decrements the reference count) */
+RTC_API void rtcReleaseGeometry(RTCGeometry geometry);
+
+/* Commits the geometry. */
+RTC_API void rtcCommitGeometry(RTCGeometry geometry);
+
+
+/* Enables the geometry. */
+RTC_API void rtcEnableGeometry(RTCGeometry geometry);
+
+/* Disables the geometry. */
+RTC_API void rtcDisableGeometry(RTCGeometry geometry);
+
+
+/* Sets the number of motion blur time steps of the geometry. */
+RTC_API void rtcSetGeometryTimeStepCount(RTCGeometry geometry, unsigned int timeStepCount);
+
+/* Sets the motion blur time range of the geometry. */
+RTC_API void rtcSetGeometryTimeRange(RTCGeometry geometry, float startTime, float endTime);
+
+/* Sets the number of vertex attributes of the geometry. */
+RTC_API void rtcSetGeometryVertexAttributeCount(RTCGeometry geometry, unsigned int vertexAttributeCount);
+
+/* Sets the ray mask of the geometry. */
+RTC_API void rtcSetGeometryMask(RTCGeometry geometry, unsigned int mask);
+
+/* Sets the build quality of the geometry. */
+RTC_API void rtcSetGeometryBuildQuality(RTCGeometry geometry, enum RTCBuildQuality quality);
+
+/* Sets the maximal curve or point radius scale allowed by min-width feature. */
+RTC_API void rtcSetGeometryMaxRadiusScale(RTCGeometry geometry, float maxRadiusScale);
+
+
+/* Sets a geometry buffer. */
+RTC_API void rtcSetGeometryBuffer(RTCGeometry geometry, enum RTCBufferType type, unsigned int slot, enum RTCFormat format, RTCBuffer buffer, size_t byteOffset, size_t byteStride, size_t itemCount);
+
+/* Sets a shared geometry buffer. */
+RTC_API void rtcSetSharedGeometryBuffer(RTCGeometry geometry, enum RTCBufferType type, unsigned int slot, enum RTCFormat format, const void* ptr, size_t byteOffset, size_t byteStride, size_t itemCount);
+
+/* Creates and sets a new geometry buffer. */
+RTC_API void* rtcSetNewGeometryBuffer(RTCGeometry geometry, enum RTCBufferType type, unsigned int slot, enum RTCFormat format, size_t byteStride, size_t itemCount);
+
+/* Returns the pointer to the data of a buffer. */
+RTC_API void* rtcGetGeometryBufferData(RTCGeometry geometry, enum RTCBufferType type, unsigned int slot);
+
+/* Updates a geometry buffer. */
+RTC_API void rtcUpdateGeometryBuffer(RTCGeometry geometry, enum RTCBufferType type, unsigned int slot);
+
+
+/* Sets the intersection filter callback function of the geometry. */
+RTC_API void rtcSetGeometryIntersectFilterFunction(RTCGeometry geometry, RTCFilterFunctionN filter);
+
+/* Sets the occlusion filter callback function of the geometry. */
+RTC_API void rtcSetGeometryOccludedFilterFunction(RTCGeometry geometry, RTCFilterFunctionN filter);
+
+/* Sets the user-defined data pointer of the geometry. */
+RTC_API void rtcSetGeometryUserData(RTCGeometry geometry, void* ptr);
+
+/* Gets the user-defined data pointer of the geometry. */
+RTC_API void* rtcGetGeometryUserData(RTCGeometry geometry);
+
+/* Set the point query callback function of a geometry. */
+RTC_API void rtcSetGeometryPointQueryFunction(RTCGeometry geometry, RTCPointQueryFunction pointQuery);
+
+/* Sets the number of primitives of a user geometry. */
+RTC_API void rtcSetGeometryUserPrimitiveCount(RTCGeometry geometry, unsigned int userPrimitiveCount);
+
+/* Sets the bounding callback function to calculate bounding boxes for user primitives. */
+RTC_API void rtcSetGeometryBoundsFunction(RTCGeometry geometry, RTCBoundsFunction bounds, void* userPtr);
+
+/* Set the intersect callback function of a user geometry. */
+RTC_API void rtcSetGeometryIntersectFunction(RTCGeometry geometry, RTCIntersectFunctionN intersect);
+
+/* Set the occlusion callback function of a user geometry. */
+RTC_API void rtcSetGeometryOccludedFunction(RTCGeometry geometry, RTCOccludedFunctionN occluded);
+
+/* Invokes the intersection filter from the intersection callback function. */
+RTC_API void rtcFilterIntersection(const struct RTCIntersectFunctionNArguments* args, const struct RTCFilterFunctionNArguments* filterArgs);
+
+/* Invokes the occlusion filter from the occlusion callback function. */
+RTC_API void rtcFilterOcclusion(const struct RTCOccludedFunctionNArguments* args, const struct RTCFilterFunctionNArguments* filterArgs);
+
+
+/* Sets the instanced scene of an instance geometry. */
+RTC_API void rtcSetGeometryInstancedScene(RTCGeometry geometry, RTCScene scene);
+
+/* Sets the transformation of an instance for the specified time step. */
+RTC_API void rtcSetGeometryTransform(RTCGeometry geometry, unsigned int timeStep, enum RTCFormat format, const void* xfm);
+
+/* Sets the transformation quaternion of an instance for the specified time step. */
+RTC_API void rtcSetGeometryTransformQuaternion(RTCGeometry geometry, unsigned int timeStep, const struct RTCQuaternionDecomposition* qd);
+
+/* Returns the interpolated transformation of an instance for the specified time. */
+RTC_API void rtcGetGeometryTransform(RTCGeometry geometry, float time, enum RTCFormat format, void* xfm);
+
+
+/* Sets the uniform tessellation rate of the geometry. */
+RTC_API void rtcSetGeometryTessellationRate(RTCGeometry geometry, float tessellationRate);
+
+/* Sets the number of topologies of a subdivision surface. */
+RTC_API void rtcSetGeometryTopologyCount(RTCGeometry geometry, unsigned int topologyCount);
+
+/* Sets the subdivision interpolation mode. */
+RTC_API void rtcSetGeometrySubdivisionMode(RTCGeometry geometry, unsigned int topologyID, enum RTCSubdivisionMode mode);
+
+/* Binds a vertex attribute to a topology of the geometry. */
+RTC_API void rtcSetGeometryVertexAttributeTopology(RTCGeometry geometry, unsigned int vertexAttributeID, unsigned int topologyID);
+
+/* Sets the displacement callback function of a subdivision surface. */
+RTC_API void rtcSetGeometryDisplacementFunction(RTCGeometry geometry, RTCDisplacementFunctionN displacement);
+
+/* Returns the first half edge of a face. */
+RTC_API unsigned int rtcGetGeometryFirstHalfEdge(RTCGeometry geometry, unsigned int faceID);
+
+/* Returns the face the half edge belongs to. */
+RTC_API unsigned int rtcGetGeometryFace(RTCGeometry geometry, unsigned int edgeID);
+
+/* Returns next half edge. */
+RTC_API unsigned int rtcGetGeometryNextHalfEdge(RTCGeometry geometry, unsigned int edgeID);
+
+/* Returns previous half edge. */
+RTC_API unsigned int rtcGetGeometryPreviousHalfEdge(RTCGeometry geometry, unsigned int edgeID);
+
+/* Returns opposite half edge. */
+RTC_API unsigned int rtcGetGeometryOppositeHalfEdge(RTCGeometry geometry, unsigned int topologyID, unsigned int edgeID);
+
+
+/* Arguments for rtcInterpolate */
+struct RTCInterpolateArguments
+{
+ RTCGeometry geometry;
+ unsigned int primID;
+ float u;
+ float v;
+ enum RTCBufferType bufferType;
+ unsigned int bufferSlot;
+ float* P;
+ float* dPdu;
+ float* dPdv;
+ float* ddPdudu;
+ float* ddPdvdv;
+ float* ddPdudv;
+ unsigned int valueCount;
+};
+
+/* Interpolates vertex data to some u/v location and optionally calculates all derivatives. */
+RTC_API void rtcInterpolate(const struct RTCInterpolateArguments* args);
+
+/* Interpolates vertex data to some u/v location. */
+RTC_FORCEINLINE void rtcInterpolate0(RTCGeometry geometry, unsigned int primID, float u, float v, enum RTCBufferType bufferType, unsigned int bufferSlot, float* P, unsigned int valueCount)
+{
+ struct RTCInterpolateArguments args;
+ args.geometry = geometry;
+ args.primID = primID;
+ args.u = u;
+ args.v = v;
+ args.bufferType = bufferType;
+ args.bufferSlot = bufferSlot;
+ args.P = P;
+ args.dPdu = NULL;
+ args.dPdv = NULL;
+ args.ddPdudu = NULL;
+ args.ddPdvdv = NULL;
+ args.ddPdudv = NULL;
+ args.valueCount = valueCount;
+ rtcInterpolate(&args);
+}
+
+/* Interpolates vertex data to some u/v location and calculates first order derivatives. */
+RTC_FORCEINLINE void rtcInterpolate1(RTCGeometry geometry, unsigned int primID, float u, float v, enum RTCBufferType bufferType, unsigned int bufferSlot,
+ float* P, float* dPdu, float* dPdv, unsigned int valueCount)
+{
+ struct RTCInterpolateArguments args;
+ args.geometry = geometry;
+ args.primID = primID;
+ args.u = u;
+ args.v = v;
+ args.bufferType = bufferType;
+ args.bufferSlot = bufferSlot;
+ args.P = P;
+ args.dPdu = dPdu;
+ args.dPdv = dPdv;
+ args.ddPdudu = NULL;
+ args.ddPdvdv = NULL;
+ args.ddPdudv = NULL;
+ args.valueCount = valueCount;
+ rtcInterpolate(&args);
+}
+
+/* Interpolates vertex data to some u/v location and calculates first and second order derivatives. */
+RTC_FORCEINLINE void rtcInterpolate2(RTCGeometry geometry, unsigned int primID, float u, float v, enum RTCBufferType bufferType, unsigned int bufferSlot,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, unsigned int valueCount)
+{
+ struct RTCInterpolateArguments args;
+ args.geometry = geometry;
+ args.primID = primID;
+ args.u = u;
+ args.v = v;
+ args.bufferType = bufferType;
+ args.bufferSlot = bufferSlot;
+ args.P = P;
+ args.dPdu = dPdu;
+ args.dPdv = dPdv;
+ args.ddPdudu = ddPdudu;
+ args.ddPdvdv = ddPdvdv;
+ args.ddPdudv = ddPdudv;
+ args.valueCount = valueCount;
+ rtcInterpolate(&args);
+}
+
+/* Arguments for rtcInterpolateN */
+struct RTCInterpolateNArguments
+{
+ RTCGeometry geometry;
+ const void* valid;
+ const unsigned int* primIDs;
+ const float* u;
+ const float* v;
+ unsigned int N;
+ enum RTCBufferType bufferType;
+ unsigned int bufferSlot;
+ float* P;
+ float* dPdu;
+ float* dPdv;
+ float* ddPdudu;
+ float* ddPdvdv;
+ float* ddPdudv;
+ unsigned int valueCount;
+};
+
+/* Interpolates vertex data to an array of u/v locations. */
+RTC_API void rtcInterpolateN(const struct RTCInterpolateNArguments* args);
+
+/* RTCGrid primitive for grid mesh */
+struct RTCGrid
+{
+ unsigned int startVertexID;
+ unsigned int stride;
+ unsigned short width,height; // max is a 32k x 32k grid
+};
+
+RTC_NAMESPACE_END
+
+
diff --git a/thirdparty/embree/include/embree3/rtcore_quaternion.h b/thirdparty/embree/include/embree3/rtcore_quaternion.h
new file mode 100644
index 0000000000..6489fa3467
--- /dev/null
+++ b/thirdparty/embree/include/embree3/rtcore_quaternion.h
@@ -0,0 +1,101 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_common.h"
+
+RTC_NAMESPACE_BEGIN
+
+/*
+ * Structure for transformation respresentation as a matrix decomposition using
+ * a quaternion
+ */
+struct RTC_ALIGN(16) RTCQuaternionDecomposition
+{
+ float scale_x;
+ float scale_y;
+ float scale_z;
+ float skew_xy;
+ float skew_xz;
+ float skew_yz;
+ float shift_x;
+ float shift_y;
+ float shift_z;
+ float quaternion_r;
+ float quaternion_i;
+ float quaternion_j;
+ float quaternion_k;
+ float translation_x;
+ float translation_y;
+ float translation_z;
+};
+
+RTC_FORCEINLINE void rtcInitQuaternionDecomposition(struct RTCQuaternionDecomposition* qdecomp)
+{
+ qdecomp->scale_x = 1.f;
+ qdecomp->scale_y = 1.f;
+ qdecomp->scale_z = 1.f;
+ qdecomp->skew_xy = 0.f;
+ qdecomp->skew_xz = 0.f;
+ qdecomp->skew_yz = 0.f;
+ qdecomp->shift_x = 0.f;
+ qdecomp->shift_y = 0.f;
+ qdecomp->shift_z = 0.f;
+ qdecomp->quaternion_r = 1.f;
+ qdecomp->quaternion_i = 0.f;
+ qdecomp->quaternion_j = 0.f;
+ qdecomp->quaternion_k = 0.f;
+ qdecomp->translation_x = 0.f;
+ qdecomp->translation_y = 0.f;
+ qdecomp->translation_z = 0.f;
+}
+
+RTC_FORCEINLINE void rtcQuaternionDecompositionSetQuaternion(
+ struct RTCQuaternionDecomposition* qdecomp,
+ float r, float i, float j, float k)
+{
+ qdecomp->quaternion_r = r;
+ qdecomp->quaternion_i = i;
+ qdecomp->quaternion_j = j;
+ qdecomp->quaternion_k = k;
+}
+
+RTC_FORCEINLINE void rtcQuaternionDecompositionSetScale(
+ struct RTCQuaternionDecomposition* qdecomp,
+ float scale_x, float scale_y, float scale_z)
+{
+ qdecomp->scale_x = scale_x;
+ qdecomp->scale_y = scale_y;
+ qdecomp->scale_z = scale_z;
+}
+
+RTC_FORCEINLINE void rtcQuaternionDecompositionSetSkew(
+ struct RTCQuaternionDecomposition* qdecomp,
+ float skew_xy, float skew_xz, float skew_yz)
+{
+ qdecomp->skew_xy = skew_xy;
+ qdecomp->skew_xz = skew_xz;
+ qdecomp->skew_yz = skew_yz;
+}
+
+RTC_FORCEINLINE void rtcQuaternionDecompositionSetShift(
+ struct RTCQuaternionDecomposition* qdecomp,
+ float shift_x, float shift_y, float shift_z)
+{
+ qdecomp->shift_x = shift_x;
+ qdecomp->shift_y = shift_y;
+ qdecomp->shift_z = shift_z;
+}
+
+RTC_FORCEINLINE void rtcQuaternionDecompositionSetTranslation(
+ struct RTCQuaternionDecomposition* qdecomp,
+ float translation_x, float translation_y, float translation_z)
+{
+ qdecomp->translation_x = translation_x;
+ qdecomp->translation_y = translation_y;
+ qdecomp->translation_z = translation_z;
+}
+
+RTC_NAMESPACE_END
+
diff --git a/thirdparty/embree/include/embree3/rtcore_ray.h b/thirdparty/embree/include/embree3/rtcore_ray.h
new file mode 100644
index 0000000000..a2ee6dabbb
--- /dev/null
+++ b/thirdparty/embree/include/embree3/rtcore_ray.h
@@ -0,0 +1,378 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_common.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Ray structure for a single ray */
+struct RTC_ALIGN(16) RTCRay
+{
+ float org_x; // x coordinate of ray origin
+ float org_y; // y coordinate of ray origin
+ float org_z; // z coordinate of ray origin
+ float tnear; // start of ray segment
+
+ float dir_x; // x coordinate of ray direction
+ float dir_y; // y coordinate of ray direction
+ float dir_z; // z coordinate of ray direction
+ float time; // time of this ray for motion blur
+
+ float tfar; // end of ray segment (set to hit distance)
+ unsigned int mask; // ray mask
+ unsigned int id; // ray ID
+ unsigned int flags; // ray flags
+};
+
+/* Hit structure for a single ray */
+struct RTC_ALIGN(16) RTCHit
+{
+ float Ng_x; // x coordinate of geometry normal
+ float Ng_y; // y coordinate of geometry normal
+ float Ng_z; // z coordinate of geometry normal
+
+ float u; // barycentric u coordinate of hit
+ float v; // barycentric v coordinate of hit
+
+ unsigned int primID; // primitive ID
+ unsigned int geomID; // geometry ID
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID
+};
+
+/* Combined ray/hit structure for a single ray */
+struct RTCRayHit
+{
+ struct RTCRay ray;
+ struct RTCHit hit;
+};
+
+/* Ray structure for a packet of 4 rays */
+struct RTC_ALIGN(16) RTCRay4
+{
+ float org_x[4];
+ float org_y[4];
+ float org_z[4];
+ float tnear[4];
+
+ float dir_x[4];
+ float dir_y[4];
+ float dir_z[4];
+ float time[4];
+
+ float tfar[4];
+ unsigned int mask[4];
+ unsigned int id[4];
+ unsigned int flags[4];
+};
+
+/* Hit structure for a packet of 4 rays */
+struct RTC_ALIGN(16) RTCHit4
+{
+ float Ng_x[4];
+ float Ng_y[4];
+ float Ng_z[4];
+
+ float u[4];
+ float v[4];
+
+ unsigned int primID[4];
+ unsigned int geomID[4];
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][4];
+};
+
+/* Combined ray/hit structure for a packet of 4 rays */
+struct RTCRayHit4
+{
+ struct RTCRay4 ray;
+ struct RTCHit4 hit;
+};
+
+/* Ray structure for a packet of 8 rays */
+struct RTC_ALIGN(32) RTCRay8
+{
+ float org_x[8];
+ float org_y[8];
+ float org_z[8];
+ float tnear[8];
+
+ float dir_x[8];
+ float dir_y[8];
+ float dir_z[8];
+ float time[8];
+
+ float tfar[8];
+ unsigned int mask[8];
+ unsigned int id[8];
+ unsigned int flags[8];
+};
+
+/* Hit structure for a packet of 8 rays */
+struct RTC_ALIGN(32) RTCHit8
+{
+ float Ng_x[8];
+ float Ng_y[8];
+ float Ng_z[8];
+
+ float u[8];
+ float v[8];
+
+ unsigned int primID[8];
+ unsigned int geomID[8];
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][8];
+};
+
+/* Combined ray/hit structure for a packet of 8 rays */
+struct RTCRayHit8
+{
+ struct RTCRay8 ray;
+ struct RTCHit8 hit;
+};
+
+/* Ray structure for a packet of 16 rays */
+struct RTC_ALIGN(64) RTCRay16
+{
+ float org_x[16];
+ float org_y[16];
+ float org_z[16];
+ float tnear[16];
+
+ float dir_x[16];
+ float dir_y[16];
+ float dir_z[16];
+ float time[16];
+
+ float tfar[16];
+ unsigned int mask[16];
+ unsigned int id[16];
+ unsigned int flags[16];
+};
+
+/* Hit structure for a packet of 16 rays */
+struct RTC_ALIGN(64) RTCHit16
+{
+ float Ng_x[16];
+ float Ng_y[16];
+ float Ng_z[16];
+
+ float u[16];
+ float v[16];
+
+ unsigned int primID[16];
+ unsigned int geomID[16];
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][16];
+};
+
+/* Combined ray/hit structure for a packet of 16 rays */
+struct RTCRayHit16
+{
+ struct RTCRay16 ray;
+ struct RTCHit16 hit;
+};
+
+/* Ray structure for a packet/stream of N rays in pointer SOA layout */
+struct RTCRayNp
+{
+ float* org_x;
+ float* org_y;
+ float* org_z;
+ float* tnear;
+
+ float* dir_x;
+ float* dir_y;
+ float* dir_z;
+ float* time;
+
+ float* tfar;
+ unsigned int* mask;
+ unsigned int* id;
+ unsigned int* flags;
+};
+
+/* Hit structure for a packet/stream of N rays in pointer SOA layout */
+struct RTCHitNp
+{
+ float* Ng_x;
+ float* Ng_y;
+ float* Ng_z;
+
+ float* u;
+ float* v;
+
+ unsigned int* primID;
+ unsigned int* geomID;
+ unsigned int* instID[RTC_MAX_INSTANCE_LEVEL_COUNT];
+};
+
+/* Combined ray/hit structure for a packet/stream of N rays in pointer SOA layout */
+struct RTCRayHitNp
+{
+ struct RTCRayNp ray;
+ struct RTCHitNp hit;
+};
+
+struct RTCRayN;
+struct RTCHitN;
+struct RTCRayHitN;
+
+#if defined(__cplusplus)
+
+/* Helper functions to access ray packets of runtime size N */
+RTC_FORCEINLINE float& RTCRayN_org_x(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[0*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_org_y(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[1*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_org_z(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[2*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_tnear(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[3*N+i]; }
+
+RTC_FORCEINLINE float& RTCRayN_dir_x(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[4*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_dir_y(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[5*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_dir_z(RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[6*N+i]; }
+RTC_FORCEINLINE float& RTCRayN_time (RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[7*N+i]; }
+
+RTC_FORCEINLINE float& RTCRayN_tfar (RTCRayN* ray, unsigned int N, unsigned int i) { return ((float*)ray)[8*N+i]; }
+RTC_FORCEINLINE unsigned int& RTCRayN_mask (RTCRayN* ray, unsigned int N, unsigned int i) { return ((unsigned*)ray)[9*N+i]; }
+RTC_FORCEINLINE unsigned int& RTCRayN_id (RTCRayN* ray, unsigned int N, unsigned int i) { return ((unsigned*)ray)[10*N+i]; }
+RTC_FORCEINLINE unsigned int& RTCRayN_flags(RTCRayN* ray, unsigned int N, unsigned int i) { return ((unsigned*)ray)[11*N+i]; }
+
+/* Helper functions to access hit packets of runtime size N */
+RTC_FORCEINLINE float& RTCHitN_Ng_x(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[0*N+i]; }
+RTC_FORCEINLINE float& RTCHitN_Ng_y(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[1*N+i]; }
+RTC_FORCEINLINE float& RTCHitN_Ng_z(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[2*N+i]; }
+
+RTC_FORCEINLINE float& RTCHitN_u(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[3*N+i]; }
+RTC_FORCEINLINE float& RTCHitN_v(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[4*N+i]; }
+
+RTC_FORCEINLINE unsigned int& RTCHitN_primID(RTCHitN* hit, unsigned int N, unsigned int i) { return ((unsigned*)hit)[5*N+i]; }
+RTC_FORCEINLINE unsigned int& RTCHitN_geomID(RTCHitN* hit, unsigned int N, unsigned int i) { return ((unsigned*)hit)[6*N+i]; }
+RTC_FORCEINLINE unsigned int& RTCHitN_instID(RTCHitN* hit, unsigned int N, unsigned int i, unsigned int l) { return ((unsigned*)hit)[7*N+i+N*l]; }
+
+/* Helper functions to extract RTCRayN and RTCHitN from RTCRayHitN */
+RTC_FORCEINLINE RTCRayN* RTCRayHitN_RayN(RTCRayHitN* rayhit, unsigned int N) { return (RTCRayN*)&((float*)rayhit)[0*N]; }
+RTC_FORCEINLINE RTCHitN* RTCRayHitN_HitN(RTCRayHitN* rayhit, unsigned int N) { return (RTCHitN*)&((float*)rayhit)[12*N]; }
+
+/* Helper structure for a ray packet of compile-time size N */
+template<int N>
+struct RTCRayNt
+{
+ float org_x[N];
+ float org_y[N];
+ float org_z[N];
+ float tnear[N];
+
+ float dir_x[N];
+ float dir_y[N];
+ float dir_z[N];
+ float time[N];
+
+ float tfar[N];
+ unsigned int mask[N];
+ unsigned int id[N];
+ unsigned int flags[N];
+};
+
+/* Helper structure for a hit packet of compile-time size N */
+template<int N>
+struct RTCHitNt
+{
+ float Ng_x[N];
+ float Ng_y[N];
+ float Ng_z[N];
+
+ float u[N];
+ float v[N];
+
+ unsigned int primID[N];
+ unsigned int geomID[N];
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][N];
+};
+
+/* Helper structure for a combined ray/hit packet of compile-time size N */
+template<int N>
+struct RTCRayHitNt
+{
+ RTCRayNt<N> ray;
+ RTCHitNt<N> hit;
+};
+
+RTC_FORCEINLINE RTCRay rtcGetRayFromRayN(RTCRayN* rayN, unsigned int N, unsigned int i)
+{
+ RTCRay ray;
+ ray.org_x = RTCRayN_org_x(rayN,N,i);
+ ray.org_y = RTCRayN_org_y(rayN,N,i);
+ ray.org_z = RTCRayN_org_z(rayN,N,i);
+ ray.tnear = RTCRayN_tnear(rayN,N,i);
+ ray.dir_x = RTCRayN_dir_x(rayN,N,i);
+ ray.dir_y = RTCRayN_dir_y(rayN,N,i);
+ ray.dir_z = RTCRayN_dir_z(rayN,N,i);
+ ray.time = RTCRayN_time(rayN,N,i);
+ ray.tfar = RTCRayN_tfar(rayN,N,i);
+ ray.mask = RTCRayN_mask(rayN,N,i);
+ ray.id = RTCRayN_id(rayN,N,i);
+ ray.flags = RTCRayN_flags(rayN,N,i);
+ return ray;
+}
+
+RTC_FORCEINLINE RTCHit rtcGetHitFromHitN(RTCHitN* hitN, unsigned int N, unsigned int i)
+{
+ RTCHit hit;
+ hit.Ng_x = RTCHitN_Ng_x(hitN,N,i);
+ hit.Ng_y = RTCHitN_Ng_y(hitN,N,i);
+ hit.Ng_z = RTCHitN_Ng_z(hitN,N,i);
+ hit.u = RTCHitN_u(hitN,N,i);
+ hit.v = RTCHitN_v(hitN,N,i);
+ hit.primID = RTCHitN_primID(hitN,N,i);
+ hit.geomID = RTCHitN_geomID(hitN,N,i);
+ for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++)
+ hit.instID[l] = RTCHitN_instID(hitN,N,i,l);
+ return hit;
+}
+
+RTC_FORCEINLINE void rtcCopyHitToHitN(RTCHitN* hitN, const RTCHit* hit, unsigned int N, unsigned int i)
+{
+ RTCHitN_Ng_x(hitN,N,i) = hit->Ng_x;
+ RTCHitN_Ng_y(hitN,N,i) = hit->Ng_y;
+ RTCHitN_Ng_z(hitN,N,i) = hit->Ng_z;
+ RTCHitN_u(hitN,N,i) = hit->u;
+ RTCHitN_v(hitN,N,i) = hit->v;
+ RTCHitN_primID(hitN,N,i) = hit->primID;
+ RTCHitN_geomID(hitN,N,i) = hit->geomID;
+ for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++)
+ RTCHitN_instID(hitN,N,i,l) = hit->instID[l];
+}
+
+RTC_FORCEINLINE RTCRayHit rtcGetRayHitFromRayHitN(RTCRayHitN* rayhitN, unsigned int N, unsigned int i)
+{
+ RTCRayHit rh;
+
+ RTCRayN* ray = RTCRayHitN_RayN(rayhitN,N);
+ rh.ray.org_x = RTCRayN_org_x(ray,N,i);
+ rh.ray.org_y = RTCRayN_org_y(ray,N,i);
+ rh.ray.org_z = RTCRayN_org_z(ray,N,i);
+ rh.ray.tnear = RTCRayN_tnear(ray,N,i);
+ rh.ray.dir_x = RTCRayN_dir_x(ray,N,i);
+ rh.ray.dir_y = RTCRayN_dir_y(ray,N,i);
+ rh.ray.dir_z = RTCRayN_dir_z(ray,N,i);
+ rh.ray.time = RTCRayN_time(ray,N,i);
+ rh.ray.tfar = RTCRayN_tfar(ray,N,i);
+ rh.ray.mask = RTCRayN_mask(ray,N,i);
+ rh.ray.id = RTCRayN_id(ray,N,i);
+ rh.ray.flags = RTCRayN_flags(ray,N,i);
+
+ RTCHitN* hit = RTCRayHitN_HitN(rayhitN,N);
+ rh.hit.Ng_x = RTCHitN_Ng_x(hit,N,i);
+ rh.hit.Ng_y = RTCHitN_Ng_y(hit,N,i);
+ rh.hit.Ng_z = RTCHitN_Ng_z(hit,N,i);
+ rh.hit.u = RTCHitN_u(hit,N,i);
+ rh.hit.v = RTCHitN_v(hit,N,i);
+ rh.hit.primID = RTCHitN_primID(hit,N,i);
+ rh.hit.geomID = RTCHitN_geomID(hit,N,i);
+ for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++)
+ rh.hit.instID[l] = RTCHitN_instID(hit,N,i,l);
+
+ return rh;
+}
+
+#endif
+
+RTC_NAMESPACE_END
+
diff --git a/thirdparty/embree/include/embree3/rtcore_scene.h b/thirdparty/embree/include/embree3/rtcore_scene.h
new file mode 100644
index 0000000000..5878a3d402
--- /dev/null
+++ b/thirdparty/embree/include/embree3/rtcore_scene.h
@@ -0,0 +1,160 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore_device.h"
+
+RTC_NAMESPACE_BEGIN
+
+/* Forward declarations for ray structures */
+struct RTCRayHit;
+struct RTCRayHit4;
+struct RTCRayHit8;
+struct RTCRayHit16;
+struct RTCRayHitNp;
+
+/* Scene flags */
+enum RTCSceneFlags
+{
+ RTC_SCENE_FLAG_NONE = 0,
+ RTC_SCENE_FLAG_DYNAMIC = (1 << 0),
+ RTC_SCENE_FLAG_COMPACT = (1 << 1),
+ RTC_SCENE_FLAG_ROBUST = (1 << 2),
+ RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION = (1 << 3)
+};
+
+/* Creates a new scene. */
+RTC_API RTCScene rtcNewScene(RTCDevice device);
+
+/* Returns the device the scene got created in. The reference count of
+ * the device is incremented by this function. */
+RTC_API RTCDevice rtcGetSceneDevice(RTCScene hscene);
+
+/* Retains the scene (increments the reference count). */
+RTC_API void rtcRetainScene(RTCScene scene);
+
+/* Releases the scene (decrements the reference count). */
+RTC_API void rtcReleaseScene(RTCScene scene);
+
+
+/* Attaches the geometry to a scene. */
+RTC_API unsigned int rtcAttachGeometry(RTCScene scene, RTCGeometry geometry);
+
+/* Attaches the geometry to a scene using the specified geometry ID. */
+RTC_API void rtcAttachGeometryByID(RTCScene scene, RTCGeometry geometry, unsigned int geomID);
+
+/* Detaches the geometry from the scene. */
+RTC_API void rtcDetachGeometry(RTCScene scene, unsigned int geomID);
+
+/* Gets a geometry handle from the scene. */
+RTC_API RTCGeometry rtcGetGeometry(RTCScene scene, unsigned int geomID);
+
+
+/* Commits the scene. */
+RTC_API void rtcCommitScene(RTCScene scene);
+
+/* Commits the scene from multiple threads. */
+RTC_API void rtcJoinCommitScene(RTCScene scene);
+
+
+/* Progress monitor callback function */
+typedef bool (*RTCProgressMonitorFunction)(void* ptr, double n);
+
+/* Sets the progress monitor callback function of the scene. */
+RTC_API void rtcSetSceneProgressMonitorFunction(RTCScene scene, RTCProgressMonitorFunction progress, void* ptr);
+
+/* Sets the build quality of the scene. */
+RTC_API void rtcSetSceneBuildQuality(RTCScene scene, enum RTCBuildQuality quality);
+
+/* Sets the scene flags. */
+RTC_API void rtcSetSceneFlags(RTCScene scene, enum RTCSceneFlags flags);
+
+/* Returns the scene flags. */
+RTC_API enum RTCSceneFlags rtcGetSceneFlags(RTCScene scene);
+
+/* Returns the axis-aligned bounds of the scene. */
+RTC_API void rtcGetSceneBounds(RTCScene scene, struct RTCBounds* bounds_o);
+
+/* Returns the linear axis-aligned bounds of the scene. */
+RTC_API void rtcGetSceneLinearBounds(RTCScene scene, struct RTCLinearBounds* bounds_o);
+
+
+/* Perform a closest point query of the scene. */
+RTC_API bool rtcPointQuery(RTCScene scene, struct RTCPointQuery* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void* userPtr);
+
+/* Perform a closest point query with a packet of 4 points with the scene. */
+RTC_API bool rtcPointQuery4(const int* valid, RTCScene scene, struct RTCPointQuery4* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr);
+
+/* Perform a closest point query with a packet of 4 points with the scene. */
+RTC_API bool rtcPointQuery8(const int* valid, RTCScene scene, struct RTCPointQuery8* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr);
+
+/* Perform a closest point query with a packet of 4 points with the scene. */
+RTC_API bool rtcPointQuery16(const int* valid, RTCScene scene, struct RTCPointQuery16* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr);
+
+/* Intersects a single ray with the scene. */
+RTC_API void rtcIntersect1(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit* rayhit);
+
+/* Intersects a packet of 4 rays with the scene. */
+RTC_API void rtcIntersect4(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit4* rayhit);
+
+/* Intersects a packet of 8 rays with the scene. */
+RTC_API void rtcIntersect8(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit8* rayhit);
+
+/* Intersects a packet of 16 rays with the scene. */
+RTC_API void rtcIntersect16(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit16* rayhit);
+
+/* Intersects a stream of M rays with the scene. */
+RTC_API void rtcIntersect1M(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit* rayhit, unsigned int M, size_t byteStride);
+
+/* Intersects a stream of pointers to M rays with the scene. */
+RTC_API void rtcIntersect1Mp(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit** rayhit, unsigned int M);
+
+/* Intersects a stream of M ray packets of size N in SOA format with the scene. */
+RTC_API void rtcIntersectNM(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHitN* rayhit, unsigned int N, unsigned int M, size_t byteStride);
+
+/* Intersects a stream of M ray packets of size N in SOA format with the scene. */
+RTC_API void rtcIntersectNp(RTCScene scene, struct RTCIntersectContext* context, const struct RTCRayHitNp* rayhit, unsigned int N);
+
+/* Tests a single ray for occlusion with the scene. */
+RTC_API void rtcOccluded1(RTCScene scene, struct RTCIntersectContext* context, struct RTCRay* ray);
+
+/* Tests a packet of 4 rays for occlusion occluded with the scene. */
+RTC_API void rtcOccluded4(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRay4* ray);
+
+/* Tests a packet of 8 rays for occlusion with the scene. */
+RTC_API void rtcOccluded8(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRay8* ray);
+
+/* Tests a packet of 16 rays for occlusion with the scene. */
+RTC_API void rtcOccluded16(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRay16* ray);
+
+/* Tests a stream of M rays for occlusion with the scene. */
+RTC_API void rtcOccluded1M(RTCScene scene, struct RTCIntersectContext* context, struct RTCRay* ray, unsigned int M, size_t byteStride);
+
+/* Tests a stream of pointers to M rays for occlusion with the scene. */
+RTC_API void rtcOccluded1Mp(RTCScene scene, struct RTCIntersectContext* context, struct RTCRay** ray, unsigned int M);
+
+/* Tests a stream of M ray packets of size N in SOA format for occlusion with the scene. */
+RTC_API void rtcOccludedNM(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayN* ray, unsigned int N, unsigned int M, size_t byteStride);
+
+/* Tests a stream of M ray packets of size N in SOA format for occlusion with the scene. */
+RTC_API void rtcOccludedNp(RTCScene scene, struct RTCIntersectContext* context, const struct RTCRayNp* ray, unsigned int N);
+
+/*! collision callback */
+struct RTCCollision { unsigned int geomID0; unsigned int primID0; unsigned int geomID1; unsigned int primID1; };
+typedef void (*RTCCollideFunc) (void* userPtr, struct RTCCollision* collisions, unsigned int num_collisions);
+
+/*! Performs collision detection of two scenes */
+RTC_API void rtcCollide (RTCScene scene0, RTCScene scene1, RTCCollideFunc callback, void* userPtr);
+
+#if defined(__cplusplus)
+
+/* Helper for easily combining scene flags */
+inline RTCSceneFlags operator|(RTCSceneFlags a, RTCSceneFlags b) {
+ return (RTCSceneFlags)((size_t)a | (size_t)b);
+}
+
+#endif
+
+RTC_NAMESPACE_END
+
diff --git a/thirdparty/embree/kernels/builders/bvh_builder_hair.h b/thirdparty/embree/kernels/builders/bvh_builder_hair.h
new file mode 100644
index 0000000000..d83e8918a1
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/bvh_builder_hair.h
@@ -0,0 +1,411 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../bvh/bvh.h"
+#include "../geometry/primitive.h"
+#include "../builders/bvh_builder_sah.h"
+#include "../builders/heuristic_binning_array_aligned.h"
+#include "../builders/heuristic_binning_array_unaligned.h"
+#include "../builders/heuristic_strand_array.h"
+
+#define NUM_HAIR_OBJECT_BINS 32
+
+namespace embree
+{
+ namespace isa
+ {
+ struct BVHBuilderHair
+ {
+ /*! settings for builder */
+ struct Settings
+ {
+ /*! default settings */
+ Settings ()
+ : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(7), finished_range_threshold(inf) {}
+
+ public:
+ size_t branchingFactor; //!< branching factor of BVH to build
+ size_t maxDepth; //!< maximum depth of BVH to build
+ size_t logBlockSize; //!< log2 of blocksize for SAH heuristic
+ size_t minLeafSize; //!< minimum size of a leaf
+ size_t maxLeafSize; //!< maximum size of a leaf
+ size_t finished_range_threshold; //!< finished range threshold
+ };
+
+ template<typename NodeRef,
+ typename CreateAllocFunc,
+ typename CreateAABBNodeFunc,
+ typename SetAABBNodeFunc,
+ typename CreateOBBNodeFunc,
+ typename SetOBBNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor,
+ typename ReportFinishedRangeFunc>
+
+ class BuilderT
+ {
+ ALIGNED_CLASS_(16);
+ friend struct BVHBuilderHair;
+
+ typedef FastAllocator::CachedAllocator Allocator;
+ typedef HeuristicArrayBinningSAH<PrimRef,NUM_HAIR_OBJECT_BINS> HeuristicBinningSAH;
+ typedef UnalignedHeuristicArrayBinningSAH<PrimRef,NUM_HAIR_OBJECT_BINS> UnalignedHeuristicBinningSAH;
+ typedef HeuristicStrandSplit HeuristicStrandSplitSAH;
+
+ static const size_t MAX_BRANCHING_FACTOR = 8; //!< maximum supported BVH branching factor
+ static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree if we are that many levels before the maximum tree depth
+ static const size_t SINGLE_THREADED_THRESHOLD = 4096; //!< threshold to switch to single threaded build
+
+ static const size_t travCostAligned = 1;
+ static const size_t travCostUnaligned = 5;
+ static const size_t intCost = 6;
+
+ BuilderT (Scene* scene,
+ PrimRef* prims,
+ const CreateAllocFunc& createAlloc,
+ const CreateAABBNodeFunc& createAABBNode,
+ const SetAABBNodeFunc& setAABBNode,
+ const CreateOBBNodeFunc& createOBBNode,
+ const SetOBBNodeFunc& setOBBNode,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ const ReportFinishedRangeFunc& reportFinishedRange,
+ const Settings settings)
+
+ : cfg(settings),
+ prims(prims),
+ createAlloc(createAlloc),
+ createAABBNode(createAABBNode),
+ setAABBNode(setAABBNode),
+ createOBBNode(createOBBNode),
+ setOBBNode(setOBBNode),
+ createLeaf(createLeaf),
+ progressMonitor(progressMonitor),
+ reportFinishedRange(reportFinishedRange),
+ alignedHeuristic(prims), unalignedHeuristic(scene,prims), strandHeuristic(scene,prims) {}
+
+ /*! checks if all primitives are from the same geometry */
+ __forceinline bool sameGeometry(const PrimInfoRange& range)
+ {
+ if (range.size() == 0) return true;
+ unsigned int firstGeomID = prims[range.begin()].geomID();
+ for (size_t i=range.begin()+1; i<range.end(); i++) {
+ if (prims[i].geomID() != firstGeomID){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*! creates a large leaf that could be larger than supported by the BVH */
+ NodeRef createLargeLeaf(size_t depth, const PrimInfoRange& pinfo, Allocator alloc)
+ {
+ /* this should never occur but is a fatal error */
+ if (depth > cfg.maxDepth)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");
+
+ /* create leaf for few primitives */
+ if (pinfo.size() <= cfg.maxLeafSize && sameGeometry(pinfo))
+ return createLeaf(prims,pinfo,alloc);
+
+ /* fill all children by always splitting the largest one */
+ PrimInfoRange children[MAX_BRANCHING_FACTOR];
+ unsigned numChildren = 1;
+ children[0] = pinfo;
+
+ do {
+
+ /* find best child with largest bounding box area */
+ int bestChild = -1;
+ size_t bestSize = 0;
+ for (unsigned i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= cfg.maxLeafSize && sameGeometry(children[i]))
+ continue;
+
+ /* remember child with largest size */
+ if (children[i].size() > bestSize) {
+ bestSize = children[i].size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /*! split best child into left and right child */
+ __aligned(64) PrimInfoRange left, right;
+ if (!sameGeometry(children[bestChild])) {
+ alignedHeuristic.splitByGeometry(children[bestChild],left,right);
+ } else {
+ alignedHeuristic.splitFallback(children[bestChild],left,right);
+ }
+
+ /* add new children left and right */
+ children[bestChild] = children[numChildren-1];
+ children[numChildren-1] = left;
+ children[numChildren+0] = right;
+ numChildren++;
+
+ } while (numChildren < cfg.branchingFactor);
+
+ /* create node */
+ auto node = createAABBNode(alloc);
+
+ for (size_t i=0; i<numChildren; i++) {
+ const NodeRef child = createLargeLeaf(depth+1,children[i],alloc);
+ setAABBNode(node,i,child,children[i].geomBounds);
+ }
+
+ return node;
+ }
+
+ /*! performs split */
+ __noinline void split(const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo, bool& aligned) // FIXME: not inlined as ICC otherwise uses much stack
+ {
+ /* variable to track the SAH of the best splitting approach */
+ float bestSAH = inf;
+ const size_t blocks = (pinfo.size()+(1ull<<cfg.logBlockSize)-1ull) >> cfg.logBlockSize;
+ const float leafSAH = intCost*float(blocks)*halfArea(pinfo.geomBounds);
+
+ /* try standard binning in aligned space */
+ float alignedObjectSAH = inf;
+ HeuristicBinningSAH::Split alignedObjectSplit;
+ if (aligned) {
+ alignedObjectSplit = alignedHeuristic.find(pinfo,cfg.logBlockSize);
+ alignedObjectSAH = travCostAligned*halfArea(pinfo.geomBounds) + intCost*alignedObjectSplit.splitSAH();
+ bestSAH = min(alignedObjectSAH,bestSAH);
+ }
+
+ /* try standard binning in unaligned space */
+ UnalignedHeuristicBinningSAH::Split unalignedObjectSplit;
+ LinearSpace3fa uspace;
+ float unalignedObjectSAH = inf;
+ if (bestSAH > 0.7f*leafSAH) {
+ uspace = unalignedHeuristic.computeAlignedSpace(pinfo);
+ const PrimInfoRange sinfo = unalignedHeuristic.computePrimInfo(pinfo,uspace);
+ unalignedObjectSplit = unalignedHeuristic.find(sinfo,cfg.logBlockSize,uspace);
+ unalignedObjectSAH = travCostUnaligned*halfArea(pinfo.geomBounds) + intCost*unalignedObjectSplit.splitSAH();
+ bestSAH = min(unalignedObjectSAH,bestSAH);
+ }
+
+ /* try splitting into two strands */
+ HeuristicStrandSplitSAH::Split strandSplit;
+ float strandSAH = inf;
+ if (bestSAH > 0.7f*leafSAH && pinfo.size() <= 256) {
+ strandSplit = strandHeuristic.find(pinfo,cfg.logBlockSize);
+ strandSAH = travCostUnaligned*halfArea(pinfo.geomBounds) + intCost*strandSplit.splitSAH();
+ bestSAH = min(strandSAH,bestSAH);
+ }
+
+ /* fallback if SAH heuristics failed */
+ if (unlikely(!std::isfinite(bestSAH)))
+ {
+ alignedHeuristic.deterministic_order(pinfo);
+ alignedHeuristic.splitFallback(pinfo,linfo,rinfo);
+ }
+
+ /* perform aligned split if this is best */
+ else if (bestSAH == alignedObjectSAH) {
+ alignedHeuristic.split(alignedObjectSplit,pinfo,linfo,rinfo);
+ }
+
+ /* perform unaligned split if this is best */
+ else if (bestSAH == unalignedObjectSAH) {
+ unalignedHeuristic.split(unalignedObjectSplit,uspace,pinfo,linfo,rinfo);
+ aligned = false;
+ }
+
+ /* perform strand split if this is best */
+ else if (bestSAH == strandSAH) {
+ strandHeuristic.split(strandSplit,pinfo,linfo,rinfo);
+ aligned = false;
+ }
+
+ /* can never happen */
+ else
+ assert(false);
+ }
+
+ /*! recursive build */
+ NodeRef recurse(size_t depth, const PrimInfoRange& pinfo, Allocator alloc, bool toplevel, bool alloc_barrier)
+ {
+ /* get thread local allocator */
+ if (!alloc)
+ alloc = createAlloc();
+
+ /* call memory monitor function to signal progress */
+ if (toplevel && pinfo.size() <= SINGLE_THREADED_THRESHOLD)
+ progressMonitor(pinfo.size());
+
+ PrimInfoRange children[MAX_BRANCHING_FACTOR];
+
+ /* create leaf node */
+ if (depth+MIN_LARGE_LEAF_LEVELS >= cfg.maxDepth || pinfo.size() <= cfg.minLeafSize) {
+ alignedHeuristic.deterministic_order(pinfo);
+ return createLargeLeaf(depth,pinfo,alloc);
+ }
+
+ /* fill all children by always splitting the one with the largest surface area */
+ size_t numChildren = 1;
+ children[0] = pinfo;
+ bool aligned = true;
+
+ do {
+
+ /* find best child with largest bounding box area */
+ ssize_t bestChild = -1;
+ float bestArea = neg_inf;
+ for (size_t i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= cfg.minLeafSize)
+ continue;
+
+ /* remember child with largest area */
+ if (area(children[i].geomBounds) > bestArea) {
+ bestArea = area(children[i].geomBounds);
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /*! split best child into left and right child */
+ PrimInfoRange left, right;
+ split(children[bestChild],left,right,aligned);
+
+ /* add new children left and right */
+ children[bestChild] = children[numChildren-1];
+ children[numChildren-1] = left;
+ children[numChildren+0] = right;
+ numChildren++;
+
+ } while (numChildren < cfg.branchingFactor);
+
+ NodeRef node;
+
+ /* create aligned node */
+ if (aligned)
+ {
+ node = createAABBNode(alloc);
+
+ /* spawn tasks or ... */
+ if (pinfo.size() > SINGLE_THREADED_THRESHOLD)
+ {
+ parallel_for(size_t(0), numChildren, [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold;
+ setAABBNode(node,i,recurse(depth+1,children[i],nullptr,true,child_alloc_barrier),children[i].geomBounds);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+ }
+ /* ... continue sequentially */
+ else {
+ for (size_t i=0; i<numChildren; i++) {
+ const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold;
+ setAABBNode(node,i,recurse(depth+1,children[i],alloc,false,child_alloc_barrier),children[i].geomBounds);
+ }
+ }
+ }
+
+ /* create unaligned node */
+ else
+ {
+ node = createOBBNode(alloc);
+
+ /* spawn tasks or ... */
+ if (pinfo.size() > SINGLE_THREADED_THRESHOLD)
+ {
+ parallel_for(size_t(0), numChildren, [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpace(children[i]);
+ const PrimInfoRange sinfo = unalignedHeuristic.computePrimInfo(children[i],space);
+ const OBBox3fa obounds(space,sinfo.geomBounds);
+ const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold;
+ setOBBNode(node,i,recurse(depth+1,children[i],nullptr,true,child_alloc_barrier),obounds);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+ }
+ /* ... continue sequentially */
+ else
+ {
+ for (size_t i=0; i<numChildren; i++) {
+ const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpace(children[i]);
+ const PrimInfoRange sinfo = unalignedHeuristic.computePrimInfo(children[i],space);
+ const OBBox3fa obounds(space,sinfo.geomBounds);
+ const bool child_alloc_barrier = pinfo.size() > cfg.finished_range_threshold && children[i].size() <= cfg.finished_range_threshold;
+ setOBBNode(node,i,recurse(depth+1,children[i],alloc,false,child_alloc_barrier),obounds);
+ }
+ }
+ }
+
+ /* reports a finished range of primrefs */
+ if (unlikely(alloc_barrier))
+ reportFinishedRange(pinfo);
+
+ return node;
+ }
+
+ private:
+ Settings cfg;
+ PrimRef* prims;
+ const CreateAllocFunc& createAlloc;
+ const CreateAABBNodeFunc& createAABBNode;
+ const SetAABBNodeFunc& setAABBNode;
+ const CreateOBBNodeFunc& createOBBNode;
+ const SetOBBNodeFunc& setOBBNode;
+ const CreateLeafFunc& createLeaf;
+ const ProgressMonitor& progressMonitor;
+ const ReportFinishedRangeFunc& reportFinishedRange;
+
+ private:
+ HeuristicBinningSAH alignedHeuristic;
+ UnalignedHeuristicBinningSAH unalignedHeuristic;
+ HeuristicStrandSplitSAH strandHeuristic;
+ };
+
+ template<typename NodeRef,
+ typename CreateAllocFunc,
+ typename CreateAABBNodeFunc,
+ typename SetAABBNodeFunc,
+ typename CreateOBBNodeFunc,
+ typename SetOBBNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor,
+ typename ReportFinishedRangeFunc>
+
+ static NodeRef build (const CreateAllocFunc& createAlloc,
+ const CreateAABBNodeFunc& createAABBNode,
+ const SetAABBNodeFunc& setAABBNode,
+ const CreateOBBNodeFunc& createOBBNode,
+ const SetOBBNodeFunc& setOBBNode,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ const ReportFinishedRangeFunc& reportFinishedRange,
+ Scene* scene,
+ PrimRef* prims,
+ const PrimInfo& pinfo,
+ const Settings settings)
+ {
+ typedef BuilderT<NodeRef,
+ CreateAllocFunc,
+ CreateAABBNodeFunc,SetAABBNodeFunc,
+ CreateOBBNodeFunc,SetOBBNodeFunc,
+ CreateLeafFunc,ProgressMonitor,
+ ReportFinishedRangeFunc> Builder;
+
+ Builder builder(scene,prims,createAlloc,
+ createAABBNode,setAABBNode,
+ createOBBNode,setOBBNode,
+ createLeaf,progressMonitor,reportFinishedRange,settings);
+
+ NodeRef root = builder.recurse(1,pinfo,nullptr,true,false);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return root;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/bvh_builder_morton.h b/thirdparty/embree/kernels/builders/bvh_builder_morton.h
new file mode 100644
index 0000000000..8f21e3254f
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/bvh_builder_morton.h
@@ -0,0 +1,501 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/builder.h"
+#include "../../common/algorithms/parallel_reduce.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct BVHBuilderMorton
+ {
+ static const size_t MAX_BRANCHING_FACTOR = 8; //!< maximum supported BVH branching factor
+ static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree of we are that many levels before the maximum tree depth
+
+ /*! settings for morton builder */
+ struct Settings
+ {
+ /*! default settings */
+ Settings ()
+ : branchingFactor(2), maxDepth(32), minLeafSize(1), maxLeafSize(7), singleThreadThreshold(1024) {}
+
+ /*! initialize settings from API settings */
+ Settings (const RTCBuildArguments& settings)
+ : branchingFactor(2), maxDepth(32), minLeafSize(1), maxLeafSize(7), singleThreadThreshold(1024)
+ {
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxBranchingFactor)) branchingFactor = settings.maxBranchingFactor;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxDepth )) maxDepth = settings.maxDepth;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,minLeafSize )) minLeafSize = settings.minLeafSize;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxLeafSize )) maxLeafSize = settings.maxLeafSize;
+
+ minLeafSize = min(minLeafSize,maxLeafSize);
+ }
+
+ Settings (size_t branchingFactor, size_t maxDepth, size_t minLeafSize, size_t maxLeafSize, size_t singleThreadThreshold)
+ : branchingFactor(branchingFactor), maxDepth(maxDepth), minLeafSize(minLeafSize), maxLeafSize(maxLeafSize), singleThreadThreshold(singleThreadThreshold)
+ {
+ minLeafSize = min(minLeafSize,maxLeafSize);
+ }
+
+ public:
+ size_t branchingFactor; //!< branching factor of BVH to build
+ size_t maxDepth; //!< maximum depth of BVH to build
+ size_t minLeafSize; //!< minimum size of a leaf
+ size_t maxLeafSize; //!< maximum size of a leaf
+ size_t singleThreadThreshold; //!< threshold when we switch to single threaded build
+ };
+
+ /*! Build primitive consisting of morton code and primitive ID. */
+ struct __aligned(8) BuildPrim
+ {
+ union {
+ struct {
+ unsigned int code; //!< morton code
+ unsigned int index; //!< i'th primitive
+ };
+ uint64_t t;
+ };
+
+ /*! interface for radix sort */
+ __forceinline operator unsigned() const { return code; }
+
+ /*! interface for standard sort */
+ __forceinline bool operator<(const BuildPrim &m) const { return code < m.code; }
+ };
+
+ /*! maps bounding box to morton code */
+ struct MortonCodeMapping
+ {
+ static const size_t LATTICE_BITS_PER_DIM = 10;
+ static const size_t LATTICE_SIZE_PER_DIM = size_t(1) << LATTICE_BITS_PER_DIM;
+
+ vfloat4 base;
+ vfloat4 scale;
+
+ __forceinline MortonCodeMapping(const BBox3fa& bounds)
+ {
+ base = (vfloat4)bounds.lower;
+ const vfloat4 diag = (vfloat4)bounds.upper - (vfloat4)bounds.lower;
+ scale = select(diag > vfloat4(1E-19f), rcp(diag) * vfloat4(LATTICE_SIZE_PER_DIM * 0.99f),vfloat4(0.0f));
+ }
+
+ __forceinline const vint4 bin (const BBox3fa& box) const
+ {
+ const vfloat4 lower = (vfloat4)box.lower;
+ const vfloat4 upper = (vfloat4)box.upper;
+ const vfloat4 centroid = lower+upper;
+ return vint4((centroid-base)*scale);
+ }
+
+ __forceinline unsigned int code (const BBox3fa& box) const
+ {
+ const vint4 binID = bin(box);
+ const unsigned int x = extract<0>(binID);
+ const unsigned int y = extract<1>(binID);
+ const unsigned int z = extract<2>(binID);
+ const unsigned int xyz = bitInterleave(x,y,z);
+ return xyz;
+ }
+ };
+
+#if defined (__AVX2__)
+
+ /*! for AVX2 there is a fast scalar bitInterleave */
+ struct MortonCodeGenerator
+ {
+ __forceinline MortonCodeGenerator(const MortonCodeMapping& mapping, BuildPrim* dest)
+ : mapping(mapping), dest(dest) {}
+
+ __forceinline void operator() (const BBox3fa& b, const unsigned index)
+ {
+ dest->index = index;
+ dest->code = mapping.code(b);
+ dest++;
+ }
+
+ public:
+ const MortonCodeMapping mapping;
+ BuildPrim* dest;
+ size_t currentID;
+ };
+
+#else
+
+ /*! before AVX2 is it better to use the SSE version of bitInterleave */
+ struct MortonCodeGenerator
+ {
+ __forceinline MortonCodeGenerator(const MortonCodeMapping& mapping, BuildPrim* dest)
+ : mapping(mapping), dest(dest), currentID(0), slots(0), ax(0), ay(0), az(0), ai(0) {}
+
+ __forceinline ~MortonCodeGenerator()
+ {
+ if (slots != 0)
+ {
+ const vint4 code = bitInterleave(ax,ay,az);
+ for (size_t i=0; i<slots; i++) {
+ dest[currentID-slots+i].index = ai[i];
+ dest[currentID-slots+i].code = code[i];
+ }
+ }
+ }
+
+ __forceinline void operator() (const BBox3fa& b, const unsigned index)
+ {
+ const vint4 binID = mapping.bin(b);
+ ax[slots] = extract<0>(binID);
+ ay[slots] = extract<1>(binID);
+ az[slots] = extract<2>(binID);
+ ai[slots] = index;
+ slots++;
+ currentID++;
+
+ if (slots == 4)
+ {
+ const vint4 code = bitInterleave(ax,ay,az);
+ vint4::storeu(&dest[currentID-4],unpacklo(code,ai));
+ vint4::storeu(&dest[currentID-2],unpackhi(code,ai));
+ slots = 0;
+ }
+ }
+
+ public:
+ const MortonCodeMapping mapping;
+ BuildPrim* dest;
+ size_t currentID;
+ size_t slots;
+ vint4 ax, ay, az, ai;
+ };
+
+#endif
+
+ template<
+ typename ReductionTy,
+ typename Allocator,
+ typename CreateAllocator,
+ typename CreateNodeFunc,
+ typename SetNodeBoundsFunc,
+ typename CreateLeafFunc,
+ typename CalculateBounds,
+ typename ProgressMonitor>
+
+ class BuilderT : private Settings
+ {
+ ALIGNED_CLASS_(16);
+
+ public:
+
+ BuilderT (CreateAllocator& createAllocator,
+ CreateNodeFunc& createNode,
+ SetNodeBoundsFunc& setBounds,
+ CreateLeafFunc& createLeaf,
+ CalculateBounds& calculateBounds,
+ ProgressMonitor& progressMonitor,
+ const Settings& settings)
+
+ : Settings(settings),
+ createAllocator(createAllocator),
+ createNode(createNode),
+ setBounds(setBounds),
+ createLeaf(createLeaf),
+ calculateBounds(calculateBounds),
+ progressMonitor(progressMonitor),
+ morton(nullptr) {}
+
+ ReductionTy createLargeLeaf(size_t depth, const range<unsigned>& current, Allocator alloc)
+ {
+ /* this should never occur but is a fatal error */
+ if (depth > maxDepth)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");
+
+ /* create leaf for few primitives */
+ if (current.size() <= maxLeafSize)
+ return createLeaf(current,alloc);
+
+ /* fill all children by always splitting the largest one */
+ range<unsigned> children[MAX_BRANCHING_FACTOR];
+ size_t numChildren = 1;
+ children[0] = current;
+
+ do {
+
+ /* find best child with largest number of primitives */
+ size_t bestChild = -1;
+ size_t bestSize = 0;
+ for (size_t i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= maxLeafSize)
+ continue;
+
+ /* remember child with largest size */
+ if (children[i].size() > bestSize) {
+ bestSize = children[i].size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == size_t(-1)) break;
+
+ /*! split best child into left and right child */
+ auto split = children[bestChild].split();
+
+ /* add new children left and right */
+ children[bestChild] = children[numChildren-1];
+ children[numChildren-1] = split.first;
+ children[numChildren+0] = split.second;
+ numChildren++;
+
+ } while (numChildren < branchingFactor);
+
+ /* create node */
+ auto node = createNode(alloc,numChildren);
+
+ /* recurse into each child */
+ ReductionTy bounds[MAX_BRANCHING_FACTOR];
+ for (size_t i=0; i<numChildren; i++)
+ bounds[i] = createLargeLeaf(depth+1,children[i],alloc);
+
+ return setBounds(node,bounds,numChildren);
+ }
+
+ /*! recreates morton codes when reaching a region where all codes are identical */
+ __noinline void recreateMortonCodes(const range<unsigned>& current) const
+ {
+ /* fast path for small ranges */
+ if (likely(current.size() < 1024))
+ {
+ /*! recalculate centroid bounds */
+ BBox3fa centBounds(empty);
+ for (size_t i=current.begin(); i<current.end(); i++)
+ centBounds.extend(center2(calculateBounds(morton[i])));
+
+ /* recalculate morton codes */
+ MortonCodeMapping mapping(centBounds);
+ for (size_t i=current.begin(); i<current.end(); i++)
+ morton[i].code = mapping.code(calculateBounds(morton[i]));
+
+ /* sort morton codes */
+ std::sort(morton+current.begin(),morton+current.end());
+ }
+ else
+ {
+ /*! recalculate centroid bounds */
+ auto calculateCentBounds = [&] ( const range<unsigned>& r ) {
+ BBox3fa centBounds = empty;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ centBounds.extend(center2(calculateBounds(morton[i])));
+ return centBounds;
+ };
+ const BBox3fa centBounds = parallel_reduce(current.begin(), current.end(), unsigned(1024),
+ BBox3fa(empty), calculateCentBounds, BBox3fa::merge);
+
+ /* recalculate morton codes */
+ MortonCodeMapping mapping(centBounds);
+ parallel_for(current.begin(), current.end(), unsigned(1024), [&] ( const range<unsigned>& r ) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ morton[i].code = mapping.code(calculateBounds(morton[i]));
+ }
+ });
+
+ /*! sort morton codes */
+#if defined(TASKING_TBB)
+ tbb::parallel_sort(morton+current.begin(),morton+current.end());
+#else
+ radixsort32(morton+current.begin(),current.size());
+#endif
+ }
+ }
+
+ __forceinline void split(const range<unsigned>& current, range<unsigned>& left, range<unsigned>& right) const
+ {
+ const unsigned int code_start = morton[current.begin()].code;
+ const unsigned int code_end = morton[current.end()-1].code;
+ unsigned int bitpos = lzcnt(code_start^code_end);
+
+ /* if all items mapped to same morton code, then re-create new morton codes for the items */
+ if (unlikely(bitpos == 32))
+ {
+ recreateMortonCodes(current);
+ const unsigned int code_start = morton[current.begin()].code;
+ const unsigned int code_end = morton[current.end()-1].code;
+ bitpos = lzcnt(code_start^code_end);
+
+ /* if the morton code is still the same, goto fall back split */
+ if (unlikely(bitpos == 32)) {
+ current.split(left,right);
+ return;
+ }
+ }
+
+ /* split the items at the topmost different morton code bit */
+ const unsigned int bitpos_diff = 31-bitpos;
+ const unsigned int bitmask = 1 << bitpos_diff;
+
+ /* find location where bit differs using binary search */
+ unsigned begin = current.begin();
+ unsigned end = current.end();
+ while (begin + 1 != end) {
+ const unsigned mid = (begin+end)/2;
+ const unsigned bit = morton[mid].code & bitmask;
+ if (bit == 0) begin = mid; else end = mid;
+ }
+ unsigned center = end;
+#if defined(DEBUG)
+ for (unsigned int i=begin; i<center; i++) assert((morton[i].code & bitmask) == 0);
+ for (unsigned int i=center; i<end; i++) assert((morton[i].code & bitmask) == bitmask);
+#endif
+
+ left = make_range(current.begin(),center);
+ right = make_range(center,current.end());
+ }
+
+ ReductionTy recurse(size_t depth, const range<unsigned>& current, Allocator alloc, bool toplevel)
+ {
+ /* get thread local allocator */
+ if (!alloc)
+ alloc = createAllocator();
+
+ /* call memory monitor function to signal progress */
+ if (toplevel && current.size() <= singleThreadThreshold)
+ progressMonitor(current.size());
+
+ /* create leaf node */
+ if (unlikely(depth+MIN_LARGE_LEAF_LEVELS >= maxDepth || current.size() <= minLeafSize))
+ return createLargeLeaf(depth,current,alloc);
+
+ /* fill all children by always splitting the one with the largest surface area */
+ range<unsigned> children[MAX_BRANCHING_FACTOR];
+ split(current,children[0],children[1]);
+ size_t numChildren = 2;
+
+ while (numChildren < branchingFactor)
+ {
+ /* find best child with largest number of primitives */
+ int bestChild = -1;
+ unsigned bestItems = 0;
+ for (unsigned int i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= minLeafSize)
+ continue;
+
+ /* remember child with largest area */
+ if (children[i].size() > bestItems) {
+ bestItems = children[i].size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /*! split best child into left and right child */
+ range<unsigned> left, right;
+ split(children[bestChild],left,right);
+
+ /* add new children left and right */
+ children[bestChild] = children[numChildren-1];
+ children[numChildren-1] = left;
+ children[numChildren+0] = right;
+ numChildren++;
+ }
+
+ /* create leaf node if no split is possible */
+ if (unlikely(numChildren == 1))
+ return createLeaf(current,alloc);
+
+ /* allocate node */
+ auto node = createNode(alloc,numChildren);
+
+ /* process top parts of tree parallel */
+ ReductionTy bounds[MAX_BRANCHING_FACTOR];
+ if (current.size() > singleThreadThreshold)
+ {
+ /*! parallel_for is faster than spawing sub-tasks */
+ parallel_for(size_t(0), numChildren, [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ bounds[i] = recurse(depth+1,children[i],nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+ }
+
+ /* finish tree sequentially */
+ else
+ {
+ for (size_t i=0; i<numChildren; i++)
+ bounds[i] = recurse(depth+1,children[i],alloc,false);
+ }
+
+ return setBounds(node,bounds,numChildren);
+ }
+
+ /* build function */
+ ReductionTy build(BuildPrim* src, BuildPrim* tmp, size_t numPrimitives)
+ {
+ /* sort morton codes */
+ morton = src;
+ radix_sort_u32(src,tmp,numPrimitives,singleThreadThreshold);
+
+ /* build BVH */
+ const ReductionTy root = recurse(1, range<unsigned>(0,(unsigned)numPrimitives), nullptr, true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return root;
+ }
+
+ public:
+ CreateAllocator& createAllocator;
+ CreateNodeFunc& createNode;
+ SetNodeBoundsFunc& setBounds;
+ CreateLeafFunc& createLeaf;
+ CalculateBounds& calculateBounds;
+ ProgressMonitor& progressMonitor;
+
+ public:
+ BuildPrim* morton;
+ };
+
+
+ template<
+ typename ReductionTy,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename SetBoundsFunc,
+ typename CreateLeafFunc,
+ typename CalculateBoundsFunc,
+ typename ProgressMonitor>
+
+ static ReductionTy build(CreateAllocFunc createAllocator,
+ CreateNodeFunc createNode,
+ SetBoundsFunc setBounds,
+ CreateLeafFunc createLeaf,
+ CalculateBoundsFunc calculateBounds,
+ ProgressMonitor progressMonitor,
+ BuildPrim* src,
+ BuildPrim* tmp,
+ size_t numPrimitives,
+ const Settings& settings)
+ {
+ typedef BuilderT<
+ ReductionTy,
+ decltype(createAllocator()),
+ CreateAllocFunc,
+ CreateNodeFunc,
+ SetBoundsFunc,
+ CreateLeafFunc,
+ CalculateBoundsFunc,
+ ProgressMonitor> Builder;
+
+ Builder builder(createAllocator,
+ createNode,
+ setBounds,
+ createLeaf,
+ calculateBounds,
+ progressMonitor,
+ settings);
+
+ return builder.build(src,tmp,numPrimitives);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/bvh_builder_msmblur.h b/thirdparty/embree/kernels/builders/bvh_builder_msmblur.h
new file mode 100644
index 0000000000..f9a08d65cd
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/bvh_builder_msmblur.h
@@ -0,0 +1,692 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#define MBLUR_NUM_TEMPORAL_BINS 2
+#define MBLUR_NUM_OBJECT_BINS 32
+
+#include "../bvh/bvh.h"
+#include "../common/primref_mb.h"
+#include "heuristic_binning_array_aligned.h"
+#include "heuristic_timesplit_array.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename T>
+ struct SharedVector
+ {
+ __forceinline SharedVector() {}
+
+ __forceinline SharedVector(T* ptr, size_t refCount = 1)
+ : prims(ptr), refCount(refCount) {}
+
+ __forceinline void incRef() {
+ refCount++;
+ }
+
+ __forceinline void decRef()
+ {
+ if (--refCount == 0)
+ delete prims;
+ }
+
+ T* prims;
+ size_t refCount;
+ };
+
+ template<typename BuildRecord, int MAX_BRANCHING_FACTOR>
+ struct LocalChildListT
+ {
+ typedef SharedVector<mvector<PrimRefMB>> SharedPrimRefVector;
+
+ __forceinline LocalChildListT (const BuildRecord& record)
+ : numChildren(1), numSharedPrimVecs(1)
+ {
+ /* the local root will be freed in the ancestor where it was created (thus refCount is 2) */
+ children[0] = record;
+ primvecs[0] = new (&sharedPrimVecs[0]) SharedPrimRefVector(record.prims.prims, 2);
+ }
+
+ __forceinline ~LocalChildListT()
+ {
+ for (size_t i = 0; i < numChildren; i++)
+ primvecs[i]->decRef();
+ }
+
+ __forceinline BuildRecord& operator[] ( const size_t i ) {
+ return children[i];
+ }
+
+ __forceinline size_t size() const {
+ return numChildren;
+ }
+
+ __forceinline void split(ssize_t bestChild, const BuildRecord& lrecord, const BuildRecord& rrecord, std::unique_ptr<mvector<PrimRefMB>> new_vector)
+ {
+ SharedPrimRefVector* bsharedPrimVec = primvecs[bestChild];
+ if (lrecord.prims.prims == bsharedPrimVec->prims) {
+ primvecs[bestChild] = bsharedPrimVec;
+ bsharedPrimVec->incRef();
+ }
+ else {
+ primvecs[bestChild] = new (&sharedPrimVecs[numSharedPrimVecs++]) SharedPrimRefVector(lrecord.prims.prims);
+ }
+
+ if (rrecord.prims.prims == bsharedPrimVec->prims) {
+ primvecs[numChildren] = bsharedPrimVec;
+ bsharedPrimVec->incRef();
+ }
+ else {
+ primvecs[numChildren] = new (&sharedPrimVecs[numSharedPrimVecs++]) SharedPrimRefVector(rrecord.prims.prims);
+ }
+ bsharedPrimVec->decRef();
+ new_vector.release();
+
+ children[bestChild] = lrecord;
+ children[numChildren] = rrecord;
+ numChildren++;
+ }
+
+ public:
+ array_t<BuildRecord,MAX_BRANCHING_FACTOR> children;
+ array_t<SharedPrimRefVector*,MAX_BRANCHING_FACTOR> primvecs;
+ size_t numChildren;
+
+ array_t<SharedPrimRefVector,2*MAX_BRANCHING_FACTOR> sharedPrimVecs;
+ size_t numSharedPrimVecs;
+ };
+
+ template<typename Mesh>
+ struct RecalculatePrimRef
+ {
+ Scene* scene;
+
+ __forceinline RecalculatePrimRef (Scene* scene)
+ : scene(scene) {}
+
+ __forceinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range) const
+ {
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const Mesh* mesh = scene->get<Mesh>(geomID);
+ const LBBox3fa lbounds = mesh->linearBounds(primID, time_range);
+ const range<int> tbounds = mesh->timeSegmentRange(time_range);
+ return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, mesh->numTimeSegments(), geomID, primID);
+ }
+
+ // __noinline is workaround for ICC16 bug under MacOSX
+ __noinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range, const LinearSpace3fa& space) const
+ {
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const Mesh* mesh = scene->get<Mesh>(geomID);
+ const LBBox3fa lbounds = mesh->linearBounds(space, primID, time_range);
+ const range<int> tbounds = mesh->timeSegmentRange(time_range);
+ return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, mesh->numTimeSegments(), geomID, primID);
+ }
+
+ __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range) const {
+ return scene->get<Mesh>(prim.geomID())->linearBounds(prim.primID(), time_range);
+ }
+
+ // __noinline is workaround for ICC16 bug under MacOSX
+ __noinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range, const LinearSpace3fa& space) const {
+ return scene->get<Mesh>(prim.geomID())->linearBounds(space, prim.primID(), time_range);
+ }
+ };
+
+ struct VirtualRecalculatePrimRef
+ {
+ Scene* scene;
+
+ __forceinline VirtualRecalculatePrimRef (Scene* scene)
+ : scene(scene) {}
+
+ __forceinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range) const
+ {
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const Geometry* mesh = scene->get(geomID);
+ const LBBox3fa lbounds = mesh->vlinearBounds(primID, time_range);
+ const range<int> tbounds = mesh->timeSegmentRange(time_range);
+ return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, mesh->numTimeSegments(), geomID, primID);
+ }
+
+ __forceinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range, const LinearSpace3fa& space) const
+ {
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const Geometry* mesh = scene->get(geomID);
+ const LBBox3fa lbounds = mesh->vlinearBounds(space, primID, time_range);
+ const range<int> tbounds = mesh->timeSegmentRange(time_range);
+ return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, mesh->numTimeSegments(), geomID, primID);
+ }
+
+ __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range) const {
+ return scene->get(prim.geomID())->vlinearBounds(prim.primID(), time_range);
+ }
+
+ __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range, const LinearSpace3fa& space) const {
+ return scene->get(prim.geomID())->vlinearBounds(space, prim.primID(), time_range);
+ }
+ };
+
+ struct BVHBuilderMSMBlur
+ {
+ /*! settings for msmblur builder */
+ struct Settings
+ {
+ /*! default settings */
+ Settings ()
+ : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(8),
+ travCost(1.0f), intCost(1.0f), singleLeafTimeSegment(false),
+ singleThreadThreshold(1024) {}
+
+
+ Settings (size_t sahBlockSize, size_t minLeafSize, size_t maxLeafSize, float travCost, float intCost, size_t singleThreadThreshold)
+ : branchingFactor(2), maxDepth(32), logBlockSize(bsr(sahBlockSize)), minLeafSize(minLeafSize), maxLeafSize(maxLeafSize),
+ travCost(travCost), intCost(intCost), singleThreadThreshold(singleThreadThreshold)
+ {
+ minLeafSize = min(minLeafSize,maxLeafSize);
+ }
+
+ public:
+ size_t branchingFactor; //!< branching factor of BVH to build
+ size_t maxDepth; //!< maximum depth of BVH to build
+ size_t logBlockSize; //!< log2 of blocksize for SAH heuristic
+ size_t minLeafSize; //!< minimum size of a leaf
+ size_t maxLeafSize; //!< maximum size of a leaf
+ float travCost; //!< estimated cost of one traversal step
+ float intCost; //!< estimated cost of one primitive intersection
+ bool singleLeafTimeSegment; //!< split time to single time range
+ size_t singleThreadThreshold; //!< threshold when we switch to single threaded build
+ };
+
+ struct BuildRecord
+ {
+ public:
+ __forceinline BuildRecord () {}
+
+ __forceinline BuildRecord (size_t depth)
+ : depth(depth) {}
+
+ __forceinline BuildRecord (const SetMB& prims, size_t depth)
+ : depth(depth), prims(prims) {}
+
+ __forceinline friend bool operator< (const BuildRecord& a, const BuildRecord& b) {
+ return a.prims.size() < b.prims.size();
+ }
+
+ __forceinline size_t size() const {
+ return prims.size();
+ }
+
+ public:
+ size_t depth; //!< Depth of the root of this subtree.
+ SetMB prims; //!< The list of primitives.
+ };
+
+ struct BuildRecordSplit : public BuildRecord
+ {
+ __forceinline BuildRecordSplit () {}
+
+ __forceinline BuildRecordSplit (size_t depth)
+ : BuildRecord(depth) {}
+
+ __forceinline BuildRecordSplit (const BuildRecord& record, const BinSplit<MBLUR_NUM_OBJECT_BINS>& split)
+ : BuildRecord(record), split(split) {}
+
+ BinSplit<MBLUR_NUM_OBJECT_BINS> split;
+ };
+
+ template<
+ typename NodeRef,
+ typename RecalculatePrimRef,
+ typename Allocator,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename SetNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor>
+
+ class BuilderT
+ {
+ ALIGNED_CLASS_(16);
+ static const size_t MAX_BRANCHING_FACTOR = 16; //!< maximum supported BVH branching factor
+ static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree if we are that many levels before the maximum tree depth
+
+ typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D;
+ typedef BinSplit<MBLUR_NUM_OBJECT_BINS> Split;
+ typedef mvector<PrimRefMB>* PrimRefVector;
+ typedef SharedVector<mvector<PrimRefMB>> SharedPrimRefVector;
+ typedef LocalChildListT<BuildRecord,MAX_BRANCHING_FACTOR> LocalChildList;
+ typedef LocalChildListT<BuildRecordSplit,MAX_BRANCHING_FACTOR> LocalChildListSplit;
+
+ public:
+
+ BuilderT (MemoryMonitorInterface* device,
+ const RecalculatePrimRef recalculatePrimRef,
+ const CreateAllocFunc createAlloc,
+ const CreateNodeFunc createNode,
+ const SetNodeFunc setNode,
+ const CreateLeafFunc createLeaf,
+ const ProgressMonitor progressMonitor,
+ const Settings& settings)
+ : cfg(settings),
+ heuristicObjectSplit(),
+ heuristicTemporalSplit(device, recalculatePrimRef),
+ recalculatePrimRef(recalculatePrimRef), createAlloc(createAlloc), createNode(createNode), setNode(setNode), createLeaf(createLeaf),
+ progressMonitor(progressMonitor)
+ {
+ if (cfg.branchingFactor > MAX_BRANCHING_FACTOR)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large");
+ }
+
+ /*! finds the best split */
+ const Split find(const SetMB& set)
+ {
+ /* first try standard object split */
+ const Split object_split = heuristicObjectSplit.find(set,cfg.logBlockSize);
+ const float object_split_sah = object_split.splitSAH();
+
+ /* test temporal splits only when object split was bad */
+ const float leaf_sah = set.leafSAH(cfg.logBlockSize);
+ if (object_split_sah < 0.50f*leaf_sah)
+ return object_split;
+
+ /* do temporal splits only if the time range is big enough */
+ if (set.time_range.size() > 1.01f/float(set.max_num_time_segments))
+ {
+ const Split temporal_split = heuristicTemporalSplit.find(set,cfg.logBlockSize);
+ const float temporal_split_sah = temporal_split.splitSAH();
+
+ /* take temporal split if it improved SAH */
+ if (temporal_split_sah < object_split_sah)
+ return temporal_split;
+ }
+
+ return object_split;
+ }
+
+ /*! array partitioning */
+ __forceinline std::unique_ptr<mvector<PrimRefMB>> split(const Split& split, const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ /* perform object split */
+ if (likely(split.data == Split::SPLIT_OBJECT)) {
+ heuristicObjectSplit.split(split,set,lset,rset);
+ }
+ /* perform temporal split */
+ else if (likely(split.data == Split::SPLIT_TEMPORAL)) {
+ return heuristicTemporalSplit.split(split,set,lset,rset);
+ }
+ /* perform fallback split */
+ else if (unlikely(split.data == Split::SPLIT_FALLBACK)) {
+ set.deterministic_order();
+ splitFallback(set,lset,rset);
+ }
+ /* split by geometry */
+ else if (unlikely(split.data == Split::SPLIT_GEOMID)) {
+ set.deterministic_order();
+ splitByGeometry(set,lset,rset);
+ }
+ else
+ assert(false);
+
+ return std::unique_ptr<mvector<PrimRefMB>>();
+ }
+
+ /*! finds the best fallback split */
+ __noinline Split findFallback(const SetMB& set)
+ {
+ /* split if primitives are not from same geometry */
+ if (!sameGeometry(set))
+ return Split(0.0f,Split::SPLIT_GEOMID);
+
+ /* if a leaf can only hold a single time-segment, we might have to do additional temporal splits */
+ if (cfg.singleLeafTimeSegment)
+ {
+ /* test if one primitive has more than one time segment in time range, if so split time */
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ const PrimRefMB& prim = (*set.prims)[i];
+ const range<int> itime_range = prim.timeSegmentRange(set.time_range);
+ const int localTimeSegments = itime_range.size();
+ assert(localTimeSegments > 0);
+ if (localTimeSegments > 1) {
+ const int icenter = (itime_range.begin() + itime_range.end())/2;
+ const float splitTime = prim.timeStep(icenter);
+ return Split(0.0f,(unsigned)Split::SPLIT_TEMPORAL,0,splitTime);
+ }
+ }
+ }
+
+ /* otherwise return fallback split */
+ return Split(0.0f,Split::SPLIT_FALLBACK);
+ }
+
+ /*! performs fallback split */
+ void splitFallback(const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ mvector<PrimRefMB>& prims = *set.prims;
+
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ PrimInfoMB linfo = empty;
+ for (size_t i=begin; i<center; i++)
+ linfo.add_primref(prims[i]);
+
+ PrimInfoMB rinfo = empty;
+ for (size_t i=center; i<end; i++)
+ rinfo.add_primref(prims[i]);
+
+ new (&lset) SetMB(linfo,set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(rinfo,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+
+ /*! checks if all primitives are from the same geometry */
+ __forceinline bool sameGeometry(const SetMB& set)
+ {
+ if (set.size() == 0) return true;
+ mvector<PrimRefMB>& prims = *set.prims;
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ unsigned int firstGeomID = prims[begin].geomID();
+ for (size_t i=begin+1; i<end; i++) {
+ if (prims[i].geomID() != firstGeomID){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* split by geometry ID */
+ void splitByGeometry(const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ assert(set.size() > 1);
+
+ mvector<PrimRefMB>& prims = *set.prims;
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+
+ PrimInfoMB left(empty);
+ PrimInfoMB right(empty);
+ unsigned int geomID = prims[begin].geomID();
+ size_t center = serial_partitioning(prims.data(),begin,end,left,right,
+ [&] ( const PrimRefMB& prim ) { return prim.geomID() == geomID; },
+ [ ] ( PrimInfoMB& dst, const PrimRefMB& prim ) { dst.add_primref(prim); });
+
+ new (&lset) SetMB(left, set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(right,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+
+ const NodeRecordMB4D createLargeLeaf(const BuildRecord& in, Allocator alloc)
+ {
+ /* this should never occur but is a fatal error */
+ if (in.depth > cfg.maxDepth)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");
+
+ /* replace already found split by fallback split */
+ const BuildRecordSplit current(BuildRecord(in.prims,in.depth),findFallback(in.prims));
+
+ /* special case when directly creating leaf without any splits that could shrink time_range */
+ bool force_split = false;
+ if (current.depth == 1 && current.size() > 0)
+ {
+ BBox1f c = empty;
+ BBox1f p = current.prims.time_range;
+ for (size_t i=current.prims.begin(); i<current.prims.end(); i++) {
+ mvector<PrimRefMB>& prims = *current.prims.prims;
+ c.extend(prims[i].time_range);
+ }
+
+ force_split = c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* create leaf for few primitives */
+ if (current.size() <= cfg.maxLeafSize && current.split.data < Split::SPLIT_ENFORCE && !force_split)
+ return createLeaf(current,alloc);
+
+ /* fill all children by always splitting the largest one */
+ bool hasTimeSplits = false;
+ NodeRecordMB4D values[MAX_BRANCHING_FACTOR];
+ LocalChildListSplit children(current);
+
+ do {
+ /* find best child with largest bounding box area */
+ size_t bestChild = -1;
+ size_t bestSize = 0;
+ for (size_t i=0; i<children.size(); i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= cfg.maxLeafSize && children[i].split.data < Split::SPLIT_ENFORCE && !force_split)
+ continue;
+
+ force_split = false;
+
+ /* remember child with largest size */
+ if (children[i].size() > bestSize) {
+ bestSize = children[i].size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /* perform best found split */
+ BuildRecordSplit& brecord = children[bestChild];
+ BuildRecordSplit lrecord(current.depth+1);
+ BuildRecordSplit rrecord(current.depth+1);
+ std::unique_ptr<mvector<PrimRefMB>> new_vector = split(brecord.split,brecord.prims,lrecord.prims,rrecord.prims);
+ hasTimeSplits |= new_vector != nullptr;
+
+ /* find new splits */
+ lrecord.split = findFallback(lrecord.prims);
+ rrecord.split = findFallback(rrecord.prims);
+ children.split(bestChild,lrecord,rrecord,std::move(new_vector));
+
+ } while (children.size() < cfg.branchingFactor);
+
+ /* detect time_ranges that have shrunken */
+ for (size_t i=0; i<children.size(); i++) {
+ const BBox1f c = children[i].prims.time_range;
+ const BBox1f p = in.prims.time_range;
+ hasTimeSplits |= c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* create node */
+ auto node = createNode(children.children.data(),children.numChildren,alloc,hasTimeSplits);
+
+ /* recurse into each child and perform reduction */
+ LBBox3fa gbounds = empty;
+ for (size_t i=0; i<children.size(); i++) {
+ values[i] = createLargeLeaf(children[i],alloc);
+ gbounds.extend(values[i].lbounds);
+ }
+
+ setNode(current,children.children.data(),node,values,children.numChildren);
+
+ /* calculate geometry bounds of this node */
+ if (hasTimeSplits)
+ return NodeRecordMB4D(node,current.prims.linearBounds(recalculatePrimRef),current.prims.time_range);
+ else
+ return NodeRecordMB4D(node,gbounds,current.prims.time_range);
+ }
+
+ const NodeRecordMB4D recurse(const BuildRecord& current, Allocator alloc, bool toplevel)
+ {
+ /* get thread local allocator */
+ if (!alloc)
+ alloc = createAlloc();
+
+ /* call memory monitor function to signal progress */
+ if (toplevel && current.size() <= cfg.singleThreadThreshold)
+ progressMonitor(current.size());
+
+ /*! find best split */
+ const Split csplit = find(current.prims);
+
+ /*! compute leaf and split cost */
+ const float leafSAH = cfg.intCost*current.prims.leafSAH(cfg.logBlockSize);
+ const float splitSAH = cfg.travCost*current.prims.halfArea()+cfg.intCost*csplit.splitSAH();
+ assert((current.size() == 0) || ((leafSAH >= 0) && (splitSAH >= 0)));
+
+ /*! create a leaf node when threshold reached or SAH tells us to stop */
+ if (current.size() <= cfg.minLeafSize || current.depth+MIN_LARGE_LEAF_LEVELS >= cfg.maxDepth || (current.size() <= cfg.maxLeafSize && leafSAH <= splitSAH)) {
+ current.prims.deterministic_order();
+ return createLargeLeaf(current,alloc);
+ }
+
+ /*! perform initial split */
+ SetMB lprims,rprims;
+ std::unique_ptr<mvector<PrimRefMB>> new_vector = split(csplit,current.prims,lprims,rprims);
+ bool hasTimeSplits = new_vector != nullptr;
+ NodeRecordMB4D values[MAX_BRANCHING_FACTOR];
+ LocalChildList children(current);
+ {
+ BuildRecord lrecord(lprims,current.depth+1);
+ BuildRecord rrecord(rprims,current.depth+1);
+ children.split(0,lrecord,rrecord,std::move(new_vector));
+ }
+
+ /*! split until node is full or SAH tells us to stop */
+ while (children.size() < cfg.branchingFactor)
+ {
+ /*! find best child to split */
+ float bestArea = neg_inf;
+ ssize_t bestChild = -1;
+ for (size_t i=0; i<children.size(); i++)
+ {
+ if (children[i].size() <= cfg.minLeafSize) continue;
+ if (expectedApproxHalfArea(children[i].prims.geomBounds) > bestArea) {
+ bestChild = i; bestArea = expectedApproxHalfArea(children[i].prims.geomBounds);
+ }
+ }
+ if (bestChild == -1) break;
+
+ /* perform split */
+ BuildRecord& brecord = children[bestChild];
+ BuildRecord lrecord(current.depth+1);
+ BuildRecord rrecord(current.depth+1);
+ Split csplit = find(brecord.prims);
+ std::unique_ptr<mvector<PrimRefMB>> new_vector = split(csplit,brecord.prims,lrecord.prims,rrecord.prims);
+ hasTimeSplits |= new_vector != nullptr;
+ children.split(bestChild,lrecord,rrecord,std::move(new_vector));
+ }
+
+ /* detect time_ranges that have shrunken */
+ for (size_t i=0; i<children.size(); i++) {
+ const BBox1f c = children[i].prims.time_range;
+ const BBox1f p = current.prims.time_range;
+ hasTimeSplits |= c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* sort buildrecords for simpler shadow ray traversal */
+ //std::sort(&children[0],&children[children.size()],std::greater<BuildRecord>()); // FIXME: reduces traversal performance of bvh8.triangle4 (need to verified) !!
+
+ /*! create an inner node */
+ auto node = createNode(children.children.data(), children.numChildren, alloc, hasTimeSplits);
+ LBBox3fa gbounds = empty;
+
+ /* spawn tasks */
+ if (unlikely(current.size() > cfg.singleThreadThreshold))
+ {
+ /*! parallel_for is faster than spawing sub-tasks */
+ parallel_for(size_t(0), children.size(), [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ values[i] = recurse(children[i],nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+
+ /*! merge bounding boxes */
+ for (size_t i=0; i<children.size(); i++)
+ gbounds.extend(values[i].lbounds);
+ }
+ /* recurse into each child */
+ else
+ {
+ //for (size_t i=0; i<children.size(); i++)
+ for (ssize_t i=children.size()-1; i>=0; i--) {
+ values[i] = recurse(children[i],alloc,false);
+ gbounds.extend(values[i].lbounds);
+ }
+ }
+
+ setNode(current,children.children.data(),node,values,children.numChildren);
+
+ /* calculate geometry bounds of this node */
+ if (unlikely(hasTimeSplits))
+ return NodeRecordMB4D(node,current.prims.linearBounds(recalculatePrimRef),current.prims.time_range);
+ else
+ return NodeRecordMB4D(node,gbounds,current.prims.time_range);
+ }
+
+ /*! builder entry function */
+ __forceinline const NodeRecordMB4D operator() (mvector<PrimRefMB>& prims, const PrimInfoMB& pinfo)
+ {
+ const SetMB set(pinfo,&prims);
+ auto ret = recurse(BuildRecord(set,1),nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return ret;
+ }
+
+ private:
+ Settings cfg;
+ HeuristicArrayBinningMB<PrimRefMB,MBLUR_NUM_OBJECT_BINS> heuristicObjectSplit;
+ HeuristicMBlurTemporalSplit<PrimRefMB,RecalculatePrimRef,MBLUR_NUM_TEMPORAL_BINS> heuristicTemporalSplit;
+ const RecalculatePrimRef recalculatePrimRef;
+ const CreateAllocFunc createAlloc;
+ const CreateNodeFunc createNode;
+ const SetNodeFunc setNode;
+ const CreateLeafFunc createLeaf;
+ const ProgressMonitor progressMonitor;
+ };
+
+ template<typename NodeRef,
+ typename RecalculatePrimRef,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename SetNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitorFunc>
+
+ static const BVHNodeRecordMB4D<NodeRef> build(mvector<PrimRefMB>& prims,
+ const PrimInfoMB& pinfo,
+ MemoryMonitorInterface* device,
+ const RecalculatePrimRef recalculatePrimRef,
+ const CreateAllocFunc createAlloc,
+ const CreateNodeFunc createNode,
+ const SetNodeFunc setNode,
+ const CreateLeafFunc createLeaf,
+ const ProgressMonitorFunc progressMonitor,
+ const Settings& settings)
+ {
+ typedef BuilderT<
+ NodeRef,
+ RecalculatePrimRef,
+ decltype(createAlloc()),
+ CreateAllocFunc,
+ CreateNodeFunc,
+ SetNodeFunc,
+ CreateLeafFunc,
+ ProgressMonitorFunc> Builder;
+
+ Builder builder(device,
+ recalculatePrimRef,
+ createAlloc,
+ createNode,
+ setNode,
+ createLeaf,
+ progressMonitor,
+ settings);
+
+
+ return builder(prims,pinfo);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/bvh_builder_msmblur_hair.h b/thirdparty/embree/kernels/builders/bvh_builder_msmblur_hair.h
new file mode 100644
index 0000000000..397e8636b1
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/bvh_builder_msmblur_hair.h
@@ -0,0 +1,526 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../bvh/bvh.h"
+#include "../geometry/primitive.h"
+#include "../builders/bvh_builder_msmblur.h"
+#include "../builders/heuristic_binning_array_aligned.h"
+#include "../builders/heuristic_binning_array_unaligned.h"
+#include "../builders/heuristic_timesplit_array.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct BVHBuilderHairMSMBlur
+ {
+ /*! settings for msmblur builder */
+ struct Settings
+ {
+ /*! default settings */
+ Settings ()
+ : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(8) {}
+
+ public:
+ size_t branchingFactor; //!< branching factor of BVH to build
+ size_t maxDepth; //!< maximum depth of BVH to build
+ size_t logBlockSize; //!< log2 of blocksize for SAH heuristic
+ size_t minLeafSize; //!< minimum size of a leaf
+ size_t maxLeafSize; //!< maximum size of a leaf
+ };
+
+ struct BuildRecord
+ {
+ public:
+ __forceinline BuildRecord () {}
+
+ __forceinline BuildRecord (size_t depth)
+ : depth(depth) {}
+
+ __forceinline BuildRecord (const SetMB& prims, size_t depth)
+ : depth(depth), prims(prims) {}
+
+ __forceinline size_t size() const {
+ return prims.size();
+ }
+
+ public:
+ size_t depth; //!< depth of the root of this subtree
+ SetMB prims; //!< the list of primitives
+ };
+
+ template<typename NodeRef,
+ typename RecalculatePrimRef,
+ typename CreateAllocFunc,
+ typename CreateAABBNodeMBFunc,
+ typename SetAABBNodeMBFunc,
+ typename CreateOBBNodeMBFunc,
+ typename SetOBBNodeMBFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor>
+
+ class BuilderT
+ {
+ ALIGNED_CLASS_(16);
+
+ static const size_t MAX_BRANCHING_FACTOR = 8; //!< maximum supported BVH branching factor
+ static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree if we are that many levels before the maximum tree depth
+ static const size_t SINGLE_THREADED_THRESHOLD = 4096; //!< threshold to switch to single threaded build
+
+ typedef BVHNodeRecordMB<NodeRef> NodeRecordMB;
+ typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D;
+
+ typedef FastAllocator::CachedAllocator Allocator;
+ typedef LocalChildListT<BuildRecord,MAX_BRANCHING_FACTOR> LocalChildList;
+
+ typedef HeuristicMBlurTemporalSplit<PrimRefMB,RecalculatePrimRef,MBLUR_NUM_TEMPORAL_BINS> HeuristicTemporal;
+ typedef HeuristicArrayBinningMB<PrimRefMB,MBLUR_NUM_OBJECT_BINS> HeuristicBinning;
+ typedef UnalignedHeuristicArrayBinningMB<PrimRefMB,MBLUR_NUM_OBJECT_BINS> UnalignedHeuristicBinning;
+
+ public:
+
+ BuilderT (Scene* scene,
+ const RecalculatePrimRef& recalculatePrimRef,
+ const CreateAllocFunc& createAlloc,
+ const CreateAABBNodeMBFunc& createAABBNodeMB,
+ const SetAABBNodeMBFunc& setAABBNodeMB,
+ const CreateOBBNodeMBFunc& createOBBNodeMB,
+ const SetOBBNodeMBFunc& setOBBNodeMB,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ const Settings settings)
+
+ : cfg(settings),
+ scene(scene),
+ recalculatePrimRef(recalculatePrimRef),
+ createAlloc(createAlloc),
+ createAABBNodeMB(createAABBNodeMB), setAABBNodeMB(setAABBNodeMB),
+ createOBBNodeMB(createOBBNodeMB), setOBBNodeMB(setOBBNodeMB),
+ createLeaf(createLeaf),
+ progressMonitor(progressMonitor),
+ unalignedHeuristic(scene),
+ temporalSplitHeuristic(scene->device,recalculatePrimRef) {}
+
+ private:
+
+ /*! checks if all primitives are from the same geometry */
+ __forceinline bool sameGeometry(const SetMB& set)
+ {
+ mvector<PrimRefMB>& prims = *set.prims;
+ unsigned int firstGeomID = prims[set.begin()].geomID();
+ for (size_t i=set.begin()+1; i<set.end(); i++) {
+ if (prims[i].geomID() != firstGeomID){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*! performs some split if SAH approaches fail */
+ void splitFallback(const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ mvector<PrimRefMB>& prims = *set.prims;
+
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ PrimInfoMB linfo = empty;
+ for (size_t i=begin; i<center; i++)
+ linfo.add_primref(prims[i]);
+
+ PrimInfoMB rinfo = empty;
+ for (size_t i=center; i<end; i++)
+ rinfo.add_primref(prims[i]);
+
+ new (&lset) SetMB(linfo,set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(rinfo,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+
+ void splitByGeometry(const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ assert(set.size() > 1);
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfoMB linfo(empty);
+ PrimInfoMB rinfo(empty);
+ unsigned int geomID = (*set.prims)[begin].geomID();
+ size_t center = serial_partitioning(set.prims->data(),begin,end,linfo,rinfo,
+ [&] ( const PrimRefMB& prim ) { return prim.geomID() == geomID; },
+ [ ] ( PrimInfoMB& a, const PrimRefMB& ref ) { a.add_primref(ref); });
+
+ new (&lset) SetMB(linfo,set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(rinfo,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+
+ /*! creates a large leaf that could be larger than supported by the BVH */
+ NodeRecordMB4D createLargeLeaf(BuildRecord& current, Allocator alloc)
+ {
+ /* this should never occur but is a fatal error */
+ if (current.depth > cfg.maxDepth)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");
+
+ /* special case when directly creating leaf without any splits that could shrink time_range */
+ bool force_split = false;
+ if (current.depth == 1 && current.size() > 0)
+ {
+ BBox1f c = empty;
+ BBox1f p = current.prims.time_range;
+ for (size_t i=current.prims.begin(); i<current.prims.end(); i++) {
+ mvector<PrimRefMB>& prims = *current.prims.prims;
+ c.extend(prims[i].time_range);
+ }
+
+ force_split = c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* create leaf for few primitives */
+ if (current.size() <= cfg.maxLeafSize && sameGeometry(current.prims) && !force_split)
+ return createLeaf(current.prims,alloc);
+
+ /* fill all children by always splitting the largest one */
+ LocalChildList children(current);
+ NodeRecordMB4D values[MAX_BRANCHING_FACTOR];
+
+ do {
+
+ /* find best child with largest bounding box area */
+ int bestChild = -1;
+ size_t bestSize = 0;
+ for (unsigned i=0; i<children.size(); i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= cfg.maxLeafSize && sameGeometry(children[i].prims) && !force_split)
+ continue;
+
+ force_split = false;
+
+ /* remember child with largest size */
+ if (children[i].size() > bestSize) {
+ bestSize = children[i].size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /*! split best child into left and right child */
+ BuildRecord left(current.depth+1);
+ BuildRecord right(current.depth+1);
+ if (!sameGeometry(children[bestChild].prims)) {
+ splitByGeometry(children[bestChild].prims,left.prims,right.prims);
+ } else {
+ splitFallback(children[bestChild].prims,left.prims,right.prims);
+ }
+ children.split(bestChild,left,right,std::unique_ptr<mvector<PrimRefMB>>());
+
+ } while (children.size() < cfg.branchingFactor);
+
+
+ /* detect time_ranges that have shrunken */
+ bool timesplit = false;
+ for (size_t i=0; i<children.size(); i++) {
+ const BBox1f c = children[i].prims.time_range;
+ const BBox1f p = current.prims.time_range;
+ timesplit |= c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* create node */
+ NodeRef node = createAABBNodeMB(children.children.data(),children.numChildren,alloc,timesplit);
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<children.size(); i++) {
+ values[i] = createLargeLeaf(children[i],alloc);
+ bounds.extend(values[i].lbounds);
+ }
+
+ setAABBNodeMB(current,children.children.data(),node,values,children.numChildren);
+
+ if (timesplit)
+ bounds = current.prims.linearBounds(recalculatePrimRef);
+
+ return NodeRecordMB4D(node,bounds,current.prims.time_range);
+ }
+
+ /*! performs split */
+ std::unique_ptr<mvector<PrimRefMB>> split(const BuildRecord& current, BuildRecord& lrecord, BuildRecord& rrecord, bool& aligned, bool& timesplit)
+ {
+ /* variable to track the SAH of the best splitting approach */
+ float bestSAH = inf;
+ const float leafSAH = current.prims.leafSAH(cfg.logBlockSize);
+
+ /* perform standard binning in aligned space */
+ HeuristicBinning::Split alignedObjectSplit = alignedHeuristic.find(current.prims,cfg.logBlockSize);
+ float alignedObjectSAH = alignedObjectSplit.splitSAH();
+ bestSAH = min(alignedObjectSAH,bestSAH);
+
+ /* perform standard binning in unaligned space */
+ UnalignedHeuristicBinning::Split unalignedObjectSplit;
+ LinearSpace3fa uspace;
+ float unalignedObjectSAH = inf;
+ if (alignedObjectSAH > 0.7f*leafSAH) {
+ uspace = unalignedHeuristic.computeAlignedSpaceMB(scene,current.prims);
+ const SetMB sset = current.prims.primInfo(recalculatePrimRef,uspace);
+ unalignedObjectSplit = unalignedHeuristic.find(sset,cfg.logBlockSize,uspace);
+ unalignedObjectSAH = 1.3f*unalignedObjectSplit.splitSAH(); // makes unaligned splits more expensive
+ bestSAH = min(unalignedObjectSAH,bestSAH);
+ }
+
+ /* do temporal splits only if previous approaches failed to produce good SAH and the the time range is large enough */
+ float temporal_split_sah = inf;
+ typename HeuristicTemporal::Split temporal_split;
+ if (bestSAH > 0.5f*leafSAH) {
+ if (current.prims.time_range.size() > 1.01f/float(current.prims.max_num_time_segments)) {
+ temporal_split = temporalSplitHeuristic.find(current.prims,cfg.logBlockSize);
+ temporal_split_sah = temporal_split.splitSAH();
+ bestSAH = min(temporal_split_sah,bestSAH);
+ }
+ }
+
+ /* perform fallback split if SAH heuristics failed */
+ if (unlikely(!std::isfinite(bestSAH))) {
+ current.prims.deterministic_order();
+ splitFallback(current.prims,lrecord.prims,rrecord.prims);
+ }
+ /* perform aligned split if this is best */
+ else if (likely(bestSAH == alignedObjectSAH)) {
+ alignedHeuristic.split(alignedObjectSplit,current.prims,lrecord.prims,rrecord.prims);
+ }
+ /* perform unaligned split if this is best */
+ else if (likely(bestSAH == unalignedObjectSAH)) {
+ unalignedHeuristic.split(unalignedObjectSplit,uspace,current.prims,lrecord.prims,rrecord.prims);
+ aligned = false;
+ }
+ /* perform temporal split if this is best */
+ else if (likely(bestSAH == temporal_split_sah)) {
+ timesplit = true;
+ return temporalSplitHeuristic.split(temporal_split,current.prims,lrecord.prims,rrecord.prims);
+ }
+ else
+ assert(false);
+
+ return std::unique_ptr<mvector<PrimRefMB>>();
+ }
+
+ /*! recursive build */
+ NodeRecordMB4D recurse(BuildRecord& current, Allocator alloc, bool toplevel)
+ {
+ /* get thread local allocator */
+ if (!alloc)
+ alloc = createAlloc();
+
+ /* call memory monitor function to signal progress */
+ if (toplevel && current.size() <= SINGLE_THREADED_THRESHOLD)
+ progressMonitor(current.size());
+
+ /* create leaf node */
+ if (current.depth+MIN_LARGE_LEAF_LEVELS >= cfg.maxDepth || current.size() <= cfg.minLeafSize) {
+ current.prims.deterministic_order();
+ return createLargeLeaf(current,alloc);
+ }
+
+ /* fill all children by always splitting the one with the largest surface area */
+ NodeRecordMB4D values[MAX_BRANCHING_FACTOR];
+ LocalChildList children(current);
+ bool aligned = true;
+ bool timesplit = false;
+
+ do {
+
+ /* find best child with largest bounding box area */
+ ssize_t bestChild = -1;
+ float bestArea = neg_inf;
+ for (size_t i=0; i<children.size(); i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].size() <= cfg.minLeafSize)
+ continue;
+
+ /* remember child with largest area */
+ const float A = children[i].prims.halfArea();
+ if (A > bestArea) {
+ bestArea = children[i].prims.halfArea();
+ bestChild = i;
+ }
+ }
+ if (bestChild == -1) break;
+
+ /*! split best child into left and right child */
+ BuildRecord left(current.depth+1);
+ BuildRecord right(current.depth+1);
+ std::unique_ptr<mvector<PrimRefMB>> new_vector = split(children[bestChild],left,right,aligned,timesplit);
+ children.split(bestChild,left,right,std::move(new_vector));
+
+ } while (children.size() < cfg.branchingFactor);
+
+ /* detect time_ranges that have shrunken */
+ for (size_t i=0; i<children.size(); i++) {
+ const BBox1f c = children[i].prims.time_range;
+ const BBox1f p = current.prims.time_range;
+ timesplit |= c.lower > p.lower || c.upper < p.upper;
+ }
+
+ /* create time split node */
+ if (timesplit)
+ {
+ const NodeRef node = createAABBNodeMB(children.children.data(),children.numChildren,alloc,true);
+
+ /* spawn tasks or ... */
+ if (current.size() > SINGLE_THREADED_THRESHOLD)
+ {
+ parallel_for(size_t(0), children.size(), [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ values[i] = recurse(children[i],nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+ }
+ /* ... continue sequential */
+ else {
+ for (size_t i=0; i<children.size(); i++) {
+ values[i] = recurse(children[i],alloc,false);
+ }
+ }
+
+ setAABBNodeMB(current,children.children.data(),node,values,children.numChildren);
+
+ const LBBox3fa bounds = current.prims.linearBounds(recalculatePrimRef);
+ return NodeRecordMB4D(node,bounds,current.prims.time_range);
+ }
+
+ /* create aligned node */
+ else if (aligned)
+ {
+ const NodeRef node = createAABBNodeMB(children.children.data(),children.numChildren,alloc,true);
+
+ /* spawn tasks or ... */
+ if (current.size() > SINGLE_THREADED_THRESHOLD)
+ {
+ LBBox3fa cbounds[MAX_BRANCHING_FACTOR];
+ parallel_for(size_t(0), children.size(), [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ values[i] = recurse(children[i],nullptr,true);
+ cbounds[i] = values[i].lbounds;
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<children.size(); i++)
+ bounds.extend(cbounds[i]);
+ setAABBNodeMB(current,children.children.data(),node,values,children.numChildren);
+ return NodeRecordMB4D(node,bounds,current.prims.time_range);
+ }
+ /* ... continue sequentially */
+ else
+ {
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<children.size(); i++) {
+ values[i] = recurse(children[i],alloc,false);
+ bounds.extend(values[i].lbounds);
+ }
+ setAABBNodeMB(current,children.children.data(),node,values,children.numChildren);
+ return NodeRecordMB4D(node,bounds,current.prims.time_range);
+ }
+ }
+
+ /* create unaligned node */
+ else
+ {
+ const NodeRef node = createOBBNodeMB(alloc);
+
+ /* spawn tasks or ... */
+ if (current.size() > SINGLE_THREADED_THRESHOLD)
+ {
+ parallel_for(size_t(0), children.size(), [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpaceMB(scene,children[i].prims);
+ const LBBox3fa lbounds = children[i].prims.linearBounds(recalculatePrimRef,space);
+ const auto child = recurse(children[i],nullptr,true);
+ setOBBNodeMB(node,i,child.ref,space,lbounds,children[i].prims.time_range);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+ }
+ /* ... continue sequentially */
+ else
+ {
+ for (size_t i=0; i<children.size(); i++) {
+ const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpaceMB(scene,children[i].prims);
+ const LBBox3fa lbounds = children[i].prims.linearBounds(recalculatePrimRef,space);
+ const auto child = recurse(children[i],alloc,false);
+ setOBBNodeMB(node,i,child.ref,space,lbounds,children[i].prims.time_range);
+ }
+ }
+
+ const LBBox3fa bounds = current.prims.linearBounds(recalculatePrimRef);
+ return NodeRecordMB4D(node,bounds,current.prims.time_range);
+ }
+ }
+
+ public:
+
+ /*! entry point into builder */
+ NodeRecordMB4D operator() (mvector<PrimRefMB>& prims, const PrimInfoMB& pinfo)
+ {
+ BuildRecord record(SetMB(pinfo,&prims),1);
+ auto root = recurse(record,nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return root;
+ }
+
+ private:
+ Settings cfg;
+ Scene* scene;
+ const RecalculatePrimRef& recalculatePrimRef;
+ const CreateAllocFunc& createAlloc;
+ const CreateAABBNodeMBFunc& createAABBNodeMB;
+ const SetAABBNodeMBFunc& setAABBNodeMB;
+ const CreateOBBNodeMBFunc& createOBBNodeMB;
+ const SetOBBNodeMBFunc& setOBBNodeMB;
+ const CreateLeafFunc& createLeaf;
+ const ProgressMonitor& progressMonitor;
+
+ private:
+ HeuristicBinning alignedHeuristic;
+ UnalignedHeuristicBinning unalignedHeuristic;
+ HeuristicTemporal temporalSplitHeuristic;
+ };
+
+ template<typename NodeRef,
+ typename RecalculatePrimRef,
+ typename CreateAllocFunc,
+ typename CreateAABBNodeMBFunc,
+ typename SetAABBNodeMBFunc,
+ typename CreateOBBNodeMBFunc,
+ typename SetOBBNodeMBFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor>
+
+ static BVHNodeRecordMB4D<NodeRef> build (Scene* scene, mvector<PrimRefMB>& prims, const PrimInfoMB& pinfo,
+ const RecalculatePrimRef& recalculatePrimRef,
+ const CreateAllocFunc& createAlloc,
+ const CreateAABBNodeMBFunc& createAABBNodeMB,
+ const SetAABBNodeMBFunc& setAABBNodeMB,
+ const CreateOBBNodeMBFunc& createOBBNodeMB,
+ const SetOBBNodeMBFunc& setOBBNodeMB,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ const Settings settings)
+ {
+ typedef BuilderT<NodeRef,RecalculatePrimRef,CreateAllocFunc,
+ CreateAABBNodeMBFunc,SetAABBNodeMBFunc,
+ CreateOBBNodeMBFunc,SetOBBNodeMBFunc,
+ CreateLeafFunc,ProgressMonitor> Builder;
+
+ Builder builder(scene,recalculatePrimRef,createAlloc,
+ createAABBNodeMB,setAABBNodeMB,
+ createOBBNodeMB,setOBBNodeMB,
+ createLeaf,progressMonitor,settings);
+
+ return builder(prims,pinfo);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/bvh_builder_sah.h b/thirdparty/embree/kernels/builders/bvh_builder_sah.h
new file mode 100644
index 0000000000..fff4bf2a35
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/bvh_builder_sah.h
@@ -0,0 +1,669 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "heuristic_binning_array_aligned.h"
+#include "heuristic_spatial_array.h"
+#include "heuristic_openmerge_array.h"
+
+#if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL
+# define NUM_OBJECT_BINS 16
+# define NUM_SPATIAL_BINS 16
+#else
+# define NUM_OBJECT_BINS 32
+# define NUM_SPATIAL_BINS 16
+#endif
+
+namespace embree
+{
+ namespace isa
+ {
+ MAYBE_UNUSED static const float travCost = 1.0f;
+ MAYBE_UNUSED static const size_t DEFAULT_SINGLE_THREAD_THRESHOLD = 1024;
+
+ struct GeneralBVHBuilder
+ {
+ static const size_t MAX_BRANCHING_FACTOR = 16; //!< maximum supported BVH branching factor
+ static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree of we are that many levels before the maximum tree depth
+
+
+ /*! settings for SAH builder */
+ struct Settings
+ {
+ /*! default settings */
+ Settings ()
+ : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(7),
+ travCost(1.0f), intCost(1.0f), singleThreadThreshold(1024), primrefarrayalloc(inf) {}
+
+ /*! initialize settings from API settings */
+ Settings (const RTCBuildArguments& settings)
+ : branchingFactor(2), maxDepth(32), logBlockSize(0), minLeafSize(1), maxLeafSize(7),
+ travCost(1.0f), intCost(1.0f), singleThreadThreshold(1024), primrefarrayalloc(inf)
+ {
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxBranchingFactor)) branchingFactor = settings.maxBranchingFactor;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxDepth )) maxDepth = settings.maxDepth;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,sahBlockSize )) logBlockSize = bsr(settings.sahBlockSize);
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,minLeafSize )) minLeafSize = settings.minLeafSize;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,maxLeafSize )) maxLeafSize = settings.maxLeafSize;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,traversalCost )) travCost = settings.traversalCost;
+ if (RTC_BUILD_ARGUMENTS_HAS(settings,intersectionCost )) intCost = settings.intersectionCost;
+
+ minLeafSize = min(minLeafSize,maxLeafSize);
+ }
+
+ Settings (size_t sahBlockSize, size_t minLeafSize, size_t maxLeafSize, float travCost, float intCost, size_t singleThreadThreshold, size_t primrefarrayalloc = inf)
+ : branchingFactor(2), maxDepth(32), logBlockSize(bsr(sahBlockSize)), minLeafSize(minLeafSize), maxLeafSize(maxLeafSize),
+ travCost(travCost), intCost(intCost), singleThreadThreshold(singleThreadThreshold), primrefarrayalloc(primrefarrayalloc)
+ {
+ minLeafSize = min(minLeafSize,maxLeafSize);
+ }
+
+ public:
+ size_t branchingFactor; //!< branching factor of BVH to build
+ size_t maxDepth; //!< maximum depth of BVH to build
+ size_t logBlockSize; //!< log2 of blocksize for SAH heuristic
+ size_t minLeafSize; //!< minimum size of a leaf
+ size_t maxLeafSize; //!< maximum size of a leaf
+ float travCost; //!< estimated cost of one traversal step
+ float intCost; //!< estimated cost of one primitive intersection
+ size_t singleThreadThreshold; //!< threshold when we switch to single threaded build
+ size_t primrefarrayalloc; //!< builder uses prim ref array to allocate nodes and leaves when a subtree of that size is finished
+ };
+
+ /*! recursive state of builder */
+ template<typename Set, typename Split>
+ struct BuildRecordT
+ {
+ public:
+ __forceinline BuildRecordT () {}
+
+ __forceinline BuildRecordT (size_t depth)
+ : depth(depth), alloc_barrier(false), prims(empty) {}
+
+ __forceinline BuildRecordT (size_t depth, const Set& prims)
+ : depth(depth), alloc_barrier(false), prims(prims) {}
+
+ __forceinline BBox3fa bounds() const { return prims.geomBounds; }
+
+ __forceinline friend bool operator< (const BuildRecordT& a, const BuildRecordT& b) { return a.prims.size() < b.prims.size(); }
+ __forceinline friend bool operator> (const BuildRecordT& a, const BuildRecordT& b) { return a.prims.size() > b.prims.size(); }
+
+ __forceinline size_t size() const { return prims.size(); }
+
+ public:
+ size_t depth; //!< Depth of the root of this subtree.
+ bool alloc_barrier; //!< barrier used to reuse primref-array blocks to allocate nodes
+ Set prims; //!< The list of primitives.
+ };
+
+ template<typename PrimRef, typename Set>
+ struct DefaultCanCreateLeafFunc
+ {
+ __forceinline bool operator()(const PrimRef*, const Set&) const { return true; }
+ };
+
+ template<typename PrimRef, typename Set>
+ struct DefaultCanCreateLeafSplitFunc
+ {
+ __forceinline void operator()(PrimRef*, const Set&, Set&, Set&) const { }
+ };
+
+ template<typename BuildRecord,
+ typename Heuristic,
+ typename Set,
+ typename PrimRef,
+ typename ReductionTy,
+ typename Allocator,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename CanCreateLeafFunc,
+ typename CanCreateLeafSplitFunc,
+ typename ProgressMonitor>
+
+ class BuilderT
+ {
+ friend struct GeneralBVHBuilder;
+
+ BuilderT (PrimRef* prims,
+ Heuristic& heuristic,
+ const CreateAllocFunc& createAlloc,
+ const CreateNodeFunc& createNode,
+ const UpdateNodeFunc& updateNode,
+ const CreateLeafFunc& createLeaf,
+ const CanCreateLeafFunc& canCreateLeaf,
+ const CanCreateLeafSplitFunc& canCreateLeafSplit,
+ const ProgressMonitor& progressMonitor,
+ const Settings& settings) :
+ cfg(settings),
+ prims(prims),
+ heuristic(heuristic),
+ createAlloc(createAlloc),
+ createNode(createNode),
+ updateNode(updateNode),
+ createLeaf(createLeaf),
+ canCreateLeaf(canCreateLeaf),
+ canCreateLeafSplit(canCreateLeafSplit),
+ progressMonitor(progressMonitor)
+ {
+ if (cfg.branchingFactor > MAX_BRANCHING_FACTOR)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"bvh_builder: branching factor too large");
+ }
+
+ const ReductionTy createLargeLeaf(const BuildRecord& current, Allocator alloc)
+ {
+ /* this should never occur but is a fatal error */
+ if (current.depth > cfg.maxDepth)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"depth limit reached");
+
+ /* create leaf for few primitives */
+ if (current.prims.size() <= cfg.maxLeafSize && canCreateLeaf(prims,current.prims))
+ return createLeaf(prims,current.prims,alloc);
+
+ /* fill all children by always splitting the largest one */
+ ReductionTy values[MAX_BRANCHING_FACTOR];
+ BuildRecord children[MAX_BRANCHING_FACTOR];
+ size_t numChildren = 1;
+ children[0] = current;
+ do {
+
+ /* find best child with largest bounding box area */
+ size_t bestChild = -1;
+ size_t bestSize = 0;
+ for (size_t i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].prims.size() <= cfg.maxLeafSize && canCreateLeaf(prims,children[i].prims))
+ continue;
+
+ /* remember child with largest size */
+ if (children[i].prims.size() > bestSize) {
+ bestSize = children[i].prims.size();
+ bestChild = i;
+ }
+ }
+ if (bestChild == (size_t)-1) break;
+
+ /*! split best child into left and right child */
+ BuildRecord left(current.depth+1);
+ BuildRecord right(current.depth+1);
+ if (!canCreateLeaf(prims,children[bestChild].prims)) {
+ canCreateLeafSplit(prims,children[bestChild].prims,left.prims,right.prims);
+ } else {
+ heuristic.splitFallback(children[bestChild].prims,left.prims,right.prims);
+ }
+
+ /* add new children left and right */
+ children[bestChild] = children[numChildren-1];
+ children[numChildren-1] = left;
+ children[numChildren+0] = right;
+ numChildren++;
+
+ } while (numChildren < cfg.branchingFactor);
+
+ /* set barrier for primrefarrayalloc */
+ if (unlikely(current.size() > cfg.primrefarrayalloc))
+ for (size_t i=0; i<numChildren; i++)
+ children[i].alloc_barrier = children[i].size() <= cfg.primrefarrayalloc;
+
+ /* create node */
+ auto node = createNode(children,numChildren,alloc);
+
+ /* recurse into each child and perform reduction */
+ for (size_t i=0; i<numChildren; i++)
+ values[i] = createLargeLeaf(children[i],alloc);
+
+ /* perform reduction */
+ return updateNode(current,children,node,values,numChildren);
+ }
+
+ const ReductionTy recurse(BuildRecord& current, Allocator alloc, bool toplevel)
+ {
+ /* get thread local allocator */
+ if (!alloc)
+ alloc = createAlloc();
+
+ /* call memory monitor function to signal progress */
+ if (toplevel && current.size() <= cfg.singleThreadThreshold)
+ progressMonitor(current.size());
+
+ /*! find best split */
+ auto split = heuristic.find(current.prims,cfg.logBlockSize);
+
+ /*! compute leaf and split cost */
+ const float leafSAH = cfg.intCost*current.prims.leafSAH(cfg.logBlockSize);
+ const float splitSAH = cfg.travCost*halfArea(current.prims.geomBounds)+cfg.intCost*split.splitSAH();
+ assert((current.prims.size() == 0) || ((leafSAH >= 0) && (splitSAH >= 0)));
+
+ /*! create a leaf node when threshold reached or SAH tells us to stop */
+ if (current.prims.size() <= cfg.minLeafSize || current.depth+MIN_LARGE_LEAF_LEVELS >= cfg.maxDepth || (current.prims.size() <= cfg.maxLeafSize && leafSAH <= splitSAH)) {
+ heuristic.deterministic_order(current.prims);
+ return createLargeLeaf(current,alloc);
+ }
+
+ /*! perform initial split */
+ Set lprims,rprims;
+ heuristic.split(split,current.prims,lprims,rprims);
+
+ /*! initialize child list with initial split */
+ ReductionTy values[MAX_BRANCHING_FACTOR];
+ BuildRecord children[MAX_BRANCHING_FACTOR];
+ children[0] = BuildRecord(current.depth+1,lprims);
+ children[1] = BuildRecord(current.depth+1,rprims);
+ size_t numChildren = 2;
+
+ /*! split until node is full or SAH tells us to stop */
+ while (numChildren < cfg.branchingFactor)
+ {
+ /*! find best child to split */
+ float bestArea = neg_inf;
+ ssize_t bestChild = -1;
+ for (size_t i=0; i<numChildren; i++)
+ {
+ /* ignore leaves as they cannot get split */
+ if (children[i].prims.size() <= cfg.minLeafSize) continue;
+
+ /* find child with largest surface area */
+ if (halfArea(children[i].prims.geomBounds) > bestArea) {
+ bestChild = i;
+ bestArea = halfArea(children[i].prims.geomBounds);
+ }
+ }
+ if (bestChild == -1) break;
+
+ /* perform best found split */
+ BuildRecord& brecord = children[bestChild];
+ BuildRecord lrecord(current.depth+1);
+ BuildRecord rrecord(current.depth+1);
+ auto split = heuristic.find(brecord.prims,cfg.logBlockSize);
+ heuristic.split(split,brecord.prims,lrecord.prims,rrecord.prims);
+ children[bestChild ] = lrecord;
+ children[numChildren] = rrecord;
+ numChildren++;
+ }
+
+ /* set barrier for primrefarrayalloc */
+ if (unlikely(current.size() > cfg.primrefarrayalloc))
+ for (size_t i=0; i<numChildren; i++)
+ children[i].alloc_barrier = children[i].size() <= cfg.primrefarrayalloc;
+
+ /* sort buildrecords for faster shadow ray traversal */
+ std::sort(&children[0],&children[numChildren],std::greater<BuildRecord>());
+
+ /*! create an inner node */
+ auto node = createNode(children,numChildren,alloc);
+
+ /* spawn tasks */
+ if (current.size() > cfg.singleThreadThreshold)
+ {
+ /*! parallel_for is faster than spawing sub-tasks */
+ parallel_for(size_t(0), numChildren, [&] (const range<size_t>& r) { // FIXME: no range here
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ values[i] = recurse(children[i],nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ }
+ });
+
+ return updateNode(current,children,node,values,numChildren);
+ }
+ /* recurse into each child */
+ else
+ {
+ for (size_t i=0; i<numChildren; i++)
+ values[i] = recurse(children[i],alloc,false);
+
+ return updateNode(current,children,node,values,numChildren);
+ }
+ }
+
+ private:
+ Settings cfg;
+ PrimRef* prims;
+ Heuristic& heuristic;
+ const CreateAllocFunc& createAlloc;
+ const CreateNodeFunc& createNode;
+ const UpdateNodeFunc& updateNode;
+ const CreateLeafFunc& createLeaf;
+ const CanCreateLeafFunc& canCreateLeaf;
+ const CanCreateLeafSplitFunc& canCreateLeafSplit;
+ const ProgressMonitor& progressMonitor;
+ };
+
+ template<
+ typename ReductionTy,
+ typename Heuristic,
+ typename Set,
+ typename PrimRef,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor>
+
+ __noinline static ReductionTy build(Heuristic& heuristic,
+ PrimRef* prims,
+ const Set& set,
+ CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode, UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ const Settings& settings)
+ {
+ typedef BuildRecordT<Set,typename Heuristic::Split> BuildRecord;
+
+ typedef BuilderT<
+ BuildRecord,
+ Heuristic,
+ Set,
+ PrimRef,
+ ReductionTy,
+ decltype(createAlloc()),
+ CreateAllocFunc,
+ CreateNodeFunc,
+ UpdateNodeFunc,
+ CreateLeafFunc,
+ DefaultCanCreateLeafFunc<PrimRef, Set>,
+ DefaultCanCreateLeafSplitFunc<PrimRef, Set>,
+ ProgressMonitor> Builder;
+
+ /* instantiate builder */
+ Builder builder(prims,
+ heuristic,
+ createAlloc,
+ createNode,
+ updateNode,
+ createLeaf,
+ DefaultCanCreateLeafFunc<PrimRef, Set>(),
+ DefaultCanCreateLeafSplitFunc<PrimRef, Set>(),
+ progressMonitor,
+ settings);
+
+ /* build hierarchy */
+ BuildRecord record(1,set);
+ const ReductionTy root = builder.recurse(record,nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return root;
+ }
+
+ template<
+ typename ReductionTy,
+ typename Heuristic,
+ typename Set,
+ typename PrimRef,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename CanCreateLeafFunc,
+ typename CanCreateLeafSplitFunc,
+ typename ProgressMonitor>
+
+ __noinline static ReductionTy build(Heuristic& heuristic,
+ PrimRef* prims,
+ const Set& set,
+ CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode, UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ const CanCreateLeafFunc& canCreateLeaf,
+ const CanCreateLeafSplitFunc& canCreateLeafSplit,
+ const ProgressMonitor& progressMonitor,
+ const Settings& settings)
+ {
+ typedef BuildRecordT<Set,typename Heuristic::Split> BuildRecord;
+
+ typedef BuilderT<
+ BuildRecord,
+ Heuristic,
+ Set,
+ PrimRef,
+ ReductionTy,
+ decltype(createAlloc()),
+ CreateAllocFunc,
+ CreateNodeFunc,
+ UpdateNodeFunc,
+ CreateLeafFunc,
+ CanCreateLeafFunc,
+ CanCreateLeafSplitFunc,
+ ProgressMonitor> Builder;
+
+ /* instantiate builder */
+ Builder builder(prims,
+ heuristic,
+ createAlloc,
+ createNode,
+ updateNode,
+ createLeaf,
+ canCreateLeaf,
+ canCreateLeafSplit,
+ progressMonitor,
+ settings);
+
+ /* build hierarchy */
+ BuildRecord record(1,set);
+ const ReductionTy root = builder.recurse(record,nullptr,true);
+ _mm_mfence(); // to allow non-temporal stores during build
+ return root;
+ }
+ };
+
+ /* SAH builder that operates on an array of BuildRecords */
+ struct BVHBuilderBinnedSAH
+ {
+ typedef PrimInfoRange Set;
+ typedef HeuristicArrayBinningSAH<PrimRef,NUM_OBJECT_BINS> Heuristic;
+ typedef GeneralBVHBuilder::BuildRecordT<Set,typename Heuristic::Split> BuildRecord;
+ typedef GeneralBVHBuilder::Settings Settings;
+
+ /*! special builder that propagates reduction over the tree */
+ template<
+ typename ReductionTy,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename ProgressMonitor>
+
+ static ReductionTy build(CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode, UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ const ProgressMonitor& progressMonitor,
+ PrimRef* prims, const PrimInfo& pinfo,
+ const Settings& settings)
+ {
+ Heuristic heuristic(prims);
+ return GeneralBVHBuilder::build<ReductionTy,Heuristic,Set,PrimRef>(
+ heuristic,
+ prims,
+ PrimInfoRange(0,pinfo.size(),pinfo),
+ createAlloc,
+ createNode,
+ updateNode,
+ createLeaf,
+ progressMonitor,
+ settings);
+ }
+
+ /*! special builder that propagates reduction over the tree */
+ template<
+ typename ReductionTy,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename CanCreateLeafFunc,
+ typename CanCreateLeafSplitFunc,
+ typename ProgressMonitor>
+
+ static ReductionTy build(CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode, UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ const CanCreateLeafFunc& canCreateLeaf,
+ const CanCreateLeafSplitFunc& canCreateLeafSplit,
+ const ProgressMonitor& progressMonitor,
+ PrimRef* prims, const PrimInfo& pinfo,
+ const Settings& settings)
+ {
+ Heuristic heuristic(prims);
+ return GeneralBVHBuilder::build<ReductionTy,Heuristic,Set,PrimRef>(
+ heuristic,
+ prims,
+ PrimInfoRange(0,pinfo.size(),pinfo),
+ createAlloc,
+ createNode,
+ updateNode,
+ createLeaf,
+ canCreateLeaf,
+ canCreateLeafSplit,
+ progressMonitor,
+ settings);
+ }
+ };
+
+ /* Spatial SAH builder that operates on an double-buffered array of BuildRecords */
+ struct BVHBuilderBinnedFastSpatialSAH
+ {
+ typedef PrimInfoExtRange Set;
+ typedef Split2<BinSplit<NUM_OBJECT_BINS>,SpatialBinSplit<NUM_SPATIAL_BINS> > Split;
+ typedef GeneralBVHBuilder::BuildRecordT<Set,Split> BuildRecord;
+ typedef GeneralBVHBuilder::Settings Settings;
+
+ static const unsigned int GEOMID_MASK = 0xFFFFFFFF >> RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS;
+ static const unsigned int SPLITS_MASK = 0xFFFFFFFF << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS);
+
+ template<typename ReductionTy, typename UserCreateLeaf>
+ struct CreateLeafExt
+ {
+ __forceinline CreateLeafExt (const UserCreateLeaf userCreateLeaf)
+ : userCreateLeaf(userCreateLeaf) {}
+
+ // __noinline is workaround for ICC2016 compiler bug
+ template<typename Allocator>
+ __noinline ReductionTy operator() (PrimRef* prims, const range<size_t>& range, Allocator alloc) const
+ {
+ for (size_t i=range.begin(); i<range.end(); i++)
+ prims[i].lower.u &= GEOMID_MASK;
+
+ return userCreateLeaf(prims,range,alloc);
+ }
+
+ const UserCreateLeaf userCreateLeaf;
+ };
+
+ /*! special builder that propagates reduction over the tree */
+ template<
+ typename ReductionTy,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename SplitPrimitiveFunc,
+ typename ProgressMonitor>
+
+ static ReductionTy build(CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode,
+ UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ SplitPrimitiveFunc splitPrimitive,
+ ProgressMonitor progressMonitor,
+ PrimRef* prims,
+ const size_t extSize,
+ const PrimInfo& pinfo,
+ const Settings& settings)
+ {
+ typedef HeuristicArraySpatialSAH<SplitPrimitiveFunc,PrimRef,NUM_OBJECT_BINS,NUM_SPATIAL_BINS> Heuristic;
+ Heuristic heuristic(splitPrimitive,prims,pinfo);
+
+ /* calculate total surface area */ // FIXME: this sum is not deterministic
+ const float A = (float) parallel_reduce(size_t(0),pinfo.size(),0.0, [&] (const range<size_t>& r) -> double {
+
+ double A = 0.0f;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ PrimRef& prim = prims[i];
+ A += area(prim.bounds());
+ }
+ return A;
+ },std::plus<double>());
+
+
+ /* calculate maximum number of spatial splits per primitive */
+ const unsigned int maxSplits = ((size_t)1 << RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)-1;
+ const float f = 10.0f;
+
+ const float invA = 1.0f / A;
+ parallel_for( size_t(0), pinfo.size(), [&](const range<size_t>& r) {
+
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ PrimRef& prim = prims[i];
+ assert((prim.geomID() & SPLITS_MASK) == 0);
+ // FIXME: is there a better general heuristic ?
+ const float nf = ceilf(f*pinfo.size()*area(prim.bounds()) * invA);
+ unsigned int n = 4+min((int)maxSplits-4, max(1, (int)(nf)));
+ prim.lower.u |= n << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS);
+ }
+ });
+
+ return GeneralBVHBuilder::build<ReductionTy,Heuristic,Set,PrimRef>(
+ heuristic,
+ prims,
+ PrimInfoExtRange(0,pinfo.size(),extSize,pinfo),
+ createAlloc,
+ createNode,
+ updateNode,
+ CreateLeafExt<ReductionTy,CreateLeafFunc>(createLeaf),
+ progressMonitor,
+ settings);
+ }
+ };
+
+ /* Open/Merge SAH builder that operates on an array of BuildRecords */
+ struct BVHBuilderBinnedOpenMergeSAH
+ {
+ static const size_t NUM_OBJECT_BINS_HQ = 32;
+ typedef PrimInfoExtRange Set;
+ typedef BinSplit<NUM_OBJECT_BINS_HQ> Split;
+ typedef GeneralBVHBuilder::BuildRecordT<Set,Split> BuildRecord;
+ typedef GeneralBVHBuilder::Settings Settings;
+
+ /*! special builder that propagates reduction over the tree */
+ template<
+ typename ReductionTy,
+ typename BuildRef,
+ typename CreateAllocFunc,
+ typename CreateNodeFunc,
+ typename UpdateNodeFunc,
+ typename CreateLeafFunc,
+ typename NodeOpenerFunc,
+ typename ProgressMonitor>
+
+ static ReductionTy build(CreateAllocFunc createAlloc,
+ CreateNodeFunc createNode,
+ UpdateNodeFunc updateNode,
+ const CreateLeafFunc& createLeaf,
+ NodeOpenerFunc nodeOpenerFunc,
+ ProgressMonitor progressMonitor,
+ BuildRef* prims,
+ const size_t extSize,
+ const PrimInfo& pinfo,
+ const Settings& settings)
+ {
+ typedef HeuristicArrayOpenMergeSAH<NodeOpenerFunc,BuildRef,NUM_OBJECT_BINS_HQ> Heuristic;
+ Heuristic heuristic(nodeOpenerFunc,prims,settings.branchingFactor);
+
+ return GeneralBVHBuilder::build<ReductionTy,Heuristic,Set,BuildRef>(
+ heuristic,
+ prims,
+ PrimInfoExtRange(0,pinfo.size(),extSize,pinfo),
+ createAlloc,
+ createNode,
+ updateNode,
+ createLeaf,
+ progressMonitor,
+ settings);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/heuristic_binning.h b/thirdparty/embree/kernels/builders/heuristic_binning.h
new file mode 100644
index 0000000000..ee29d09ac9
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/heuristic_binning.h
@@ -0,0 +1,496 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "priminfo.h"
+#include "../../common/algorithms/parallel_reduce.h"
+#include "../../common/algorithms/parallel_partition.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! mapping into bins */
+ template<size_t BINS>
+ struct BinMapping
+ {
+ public:
+ __forceinline BinMapping() {}
+
+ /*! calculates the mapping */
+ __forceinline BinMapping(size_t N, const BBox3fa& centBounds)
+ {
+ num = min(BINS,size_t(4.0f + 0.05f*N));
+ assert(num >= 1);
+ const vfloat4 eps = 1E-34f;
+ const vfloat4 diag = max(eps, (vfloat4) centBounds.size());
+ scale = select(diag > eps,vfloat4(0.99f*num)/diag,vfloat4(0.0f));
+ ofs = (vfloat4) centBounds.lower;
+ }
+
+ /*! calculates the mapping */
+ __forceinline BinMapping(const BBox3fa& centBounds)
+ {
+ num = BINS;
+ const vfloat4 eps = 1E-34f;
+ const vfloat4 diag = max(eps, (vfloat4) centBounds.size());
+ scale = select(diag > eps,vfloat4(0.99f*num)/diag,vfloat4(0.0f));
+ ofs = (vfloat4) centBounds.lower;
+ }
+
+ /*! calculates the mapping */
+ template<typename PrimInfo>
+ __forceinline BinMapping(const PrimInfo& pinfo)
+ {
+ const vfloat4 eps = 1E-34f;
+ num = min(BINS,size_t(4.0f + 0.05f*pinfo.size()));
+ const vfloat4 diag = max(eps,(vfloat4) pinfo.centBounds.size());
+ scale = select(diag > eps,vfloat4(0.99f*num)/diag,vfloat4(0.0f));
+ ofs = (vfloat4) pinfo.centBounds.lower;
+ }
+
+ /*! returns number of bins */
+ __forceinline size_t size() const { return num; }
+
+ /*! slower but safe binning */
+ __forceinline Vec3ia bin(const Vec3fa& p) const
+ {
+ const vint4 i = floori((vfloat4(p)-ofs)*scale);
+#if 1
+ assert(i[0] >= 0 && (size_t)i[0] < num);
+ assert(i[1] >= 0 && (size_t)i[1] < num);
+ assert(i[2] >= 0 && (size_t)i[2] < num);
+ return Vec3ia(i);
+#else
+ return Vec3ia(clamp(i,vint4(0),vint4(num-1)));
+#endif
+ }
+
+ /*! faster but unsafe binning */
+ __forceinline Vec3ia bin_unsafe(const Vec3fa& p) const {
+ return Vec3ia(floori((vfloat4(p)-ofs)*scale));
+ }
+
+ /*! faster but unsafe binning */
+ template<typename PrimRef>
+ __forceinline Vec3ia bin_unsafe(const PrimRef& p) const {
+ return bin_unsafe(p.binCenter());
+ }
+
+ /*! faster but unsafe binning */
+ template<typename PrimRef, typename BinBoundsAndCenter>
+ __forceinline Vec3ia bin_unsafe(const PrimRef& p, const BinBoundsAndCenter& binBoundsAndCenter) const {
+ return bin_unsafe(binBoundsAndCenter.binCenter(p));
+ }
+
+ template<typename PrimRef>
+ __forceinline bool bin_unsafe(const PrimRef& ref,
+ const vint4& vSplitPos,
+ const vbool4& splitDimMask) const // FIXME: rename to isLeft
+ {
+ return any(((vint4)bin_unsafe(center2(ref.bounds())) < vSplitPos) & splitDimMask);
+ }
+ /*! calculates left spatial position of bin */
+ __forceinline float pos(const size_t bin, const size_t dim) const {
+ return madd(float(bin),1.0f / scale[dim],ofs[dim]);
+ }
+
+ /*! returns true if the mapping is invalid in some dimension */
+ __forceinline bool invalid(const size_t dim) const {
+ return scale[dim] == 0.0f;
+ }
+
+ /*! stream output */
+ friend embree_ostream operator<<(embree_ostream cout, const BinMapping& mapping) {
+ return cout << "BinMapping { num = " << mapping.num << ", ofs = " << mapping.ofs << ", scale = " << mapping.scale << "}";
+ }
+
+ public:
+ size_t num;
+ vfloat4 ofs,scale; //!< linear function that maps to bin ID
+ };
+
+ /*! stores all information to perform some split */
+ template<size_t BINS>
+ struct BinSplit
+ {
+ enum
+ {
+ SPLIT_OBJECT = 0,
+ SPLIT_FALLBACK = 1,
+ SPLIT_ENFORCE = 2, // splits with larger ID are enforced in createLargeLeaf even if we could create a leaf already
+ SPLIT_TEMPORAL = 2,
+ SPLIT_GEOMID = 3,
+ };
+
+ /*! construct an invalid split by default */
+ __forceinline BinSplit()
+ : sah(inf), dim(-1), pos(0), data(0) {}
+
+ __forceinline BinSplit(float sah, unsigned data, int dim = 0, float fpos = 0)
+ : sah(sah), dim(dim), fpos(fpos), data(data) {}
+
+ /*! constructs specified split */
+ __forceinline BinSplit(float sah, int dim, int pos, const BinMapping<BINS>& mapping)
+ : sah(sah), dim(dim), pos(pos), data(0), mapping(mapping) {}
+
+ /*! tests if this split is valid */
+ __forceinline bool valid() const { return dim != -1; }
+
+ /*! calculates surface area heuristic for performing the split */
+ __forceinline float splitSAH() const { return sah; }
+
+ /*! stream output */
+ friend embree_ostream operator<<(embree_ostream cout, const BinSplit& split) {
+ return cout << "BinSplit { sah = " << split.sah << ", dim = " << split.dim << ", pos = " << split.pos << "}";
+ }
+
+ public:
+ float sah; //!< SAH cost of the split
+ int dim; //!< split dimension
+ union { int pos; float fpos; }; //!< bin index for splitting
+ unsigned int data; //!< extra optional split data
+ BinMapping<BINS> mapping; //!< mapping into bins
+ };
+
+ /*! stores extended information about the split */
+ template<typename BBox>
+ struct SplitInfoT
+ {
+
+ __forceinline SplitInfoT () {}
+
+ __forceinline SplitInfoT (size_t leftCount, const BBox& leftBounds, size_t rightCount, const BBox& rightBounds)
+ : leftCount(leftCount), rightCount(rightCount), leftBounds(leftBounds), rightBounds(rightBounds) {}
+
+ public:
+ size_t leftCount,rightCount;
+ BBox leftBounds,rightBounds;
+ };
+
+ typedef SplitInfoT<BBox3fa> SplitInfo;
+ typedef SplitInfoT<LBBox3fa> SplitInfo2;
+
+ /*! stores all binning information */
+ template<size_t BINS, typename PrimRef, typename BBox>
+ struct __aligned(64) BinInfoT
+ {
+ typedef BinSplit<BINS> Split;
+ typedef vbool4 vbool;
+ typedef vint4 vint;
+ typedef vfloat4 vfloat;
+
+ __forceinline BinInfoT() {
+ }
+
+ __forceinline BinInfoT(EmptyTy) {
+ clear();
+ }
+
+ /*! bin access function */
+ __forceinline BBox &bounds(const size_t binID, const size_t dimID) { return _bounds[binID][dimID]; }
+ __forceinline const BBox &bounds(const size_t binID, const size_t dimID) const { return _bounds[binID][dimID]; }
+
+ __forceinline unsigned int &counts(const size_t binID, const size_t dimID) { return _counts[binID][dimID]; }
+ __forceinline const unsigned int &counts(const size_t binID, const size_t dimID) const { return _counts[binID][dimID]; }
+
+ __forceinline vuint4 &counts(const size_t binID) { return _counts[binID]; }
+ __forceinline const vuint4 &counts(const size_t binID) const { return _counts[binID]; }
+
+ /*! clears the bin info */
+ __forceinline void clear()
+ {
+ for (size_t i=0; i<BINS; i++) {
+ bounds(i,0) = bounds(i,1) = bounds(i,2) = empty;
+ counts(i) = vuint4(zero);
+ }
+ }
+
+ /*! bins an array of primitives */
+ __forceinline void bin (const PrimRef* prims, size_t N, const BinMapping<BINS>& mapping)
+ {
+ if (unlikely(N == 0)) return;
+ size_t i;
+ for (i=0; i<N-1; i+=2)
+ {
+ /*! map even and odd primitive to bin */
+ BBox prim0; Vec3fa center0;
+ prims[i+0].binBoundsAndCenter(prim0,center0);
+ const vint4 bin0 = (vint4)mapping.bin(center0);
+
+ BBox prim1; Vec3fa center1;
+ prims[i+1].binBoundsAndCenter(prim1,center1);
+ const vint4 bin1 = (vint4)mapping.bin(center1);
+
+ /*! increase bounds for bins for even primitive */
+ const unsigned int b00 = extract<0>(bin0); bounds(b00,0).extend(prim0);
+ const unsigned int b01 = extract<1>(bin0); bounds(b01,1).extend(prim0);
+ const unsigned int b02 = extract<2>(bin0); bounds(b02,2).extend(prim0);
+ const unsigned int s0 = (unsigned int)prims[i+0].size();
+ counts(b00,0)+=s0;
+ counts(b01,1)+=s0;
+ counts(b02,2)+=s0;
+
+ /*! increase bounds of bins for odd primitive */
+ const unsigned int b10 = extract<0>(bin1); bounds(b10,0).extend(prim1);
+ const unsigned int b11 = extract<1>(bin1); bounds(b11,1).extend(prim1);
+ const unsigned int b12 = extract<2>(bin1); bounds(b12,2).extend(prim1);
+ const unsigned int s1 = (unsigned int)prims[i+1].size();
+ counts(b10,0)+=s1;
+ counts(b11,1)+=s1;
+ counts(b12,2)+=s1;
+ }
+ /*! for uneven number of primitives */
+ if (i < N)
+ {
+ /*! map primitive to bin */
+ BBox prim0; Vec3fa center0;
+ prims[i].binBoundsAndCenter(prim0,center0);
+ const vint4 bin0 = (vint4)mapping.bin(center0);
+
+ /*! increase bounds of bins */
+ const unsigned int s0 = (unsigned int)prims[i].size();
+ const int b00 = extract<0>(bin0); counts(b00,0)+=s0; bounds(b00,0).extend(prim0);
+ const int b01 = extract<1>(bin0); counts(b01,1)+=s0; bounds(b01,1).extend(prim0);
+ const int b02 = extract<2>(bin0); counts(b02,2)+=s0; bounds(b02,2).extend(prim0);
+ }
+ }
+
+ /*! bins an array of primitives */
+ template<typename BinBoundsAndCenter>
+ __forceinline void bin (const PrimRef* prims, size_t N, const BinMapping<BINS>& mapping, const BinBoundsAndCenter& binBoundsAndCenter)
+ {
+ if (N == 0) return;
+
+ size_t i;
+ for (i=0; i<N-1; i+=2)
+ {
+ /*! map even and odd primitive to bin */
+ BBox prim0; Vec3fa center0; binBoundsAndCenter.binBoundsAndCenter(prims[i+0],prim0,center0);
+ const vint4 bin0 = (vint4)mapping.bin(center0);
+ BBox prim1; Vec3fa center1; binBoundsAndCenter.binBoundsAndCenter(prims[i+1],prim1,center1);
+ const vint4 bin1 = (vint4)mapping.bin(center1);
+
+ /*! increase bounds for bins for even primitive */
+ const unsigned int s0 = prims[i+0].size();
+ const int b00 = extract<0>(bin0); counts(b00,0)+=s0; bounds(b00,0).extend(prim0);
+ const int b01 = extract<1>(bin0); counts(b01,1)+=s0; bounds(b01,1).extend(prim0);
+ const int b02 = extract<2>(bin0); counts(b02,2)+=s0; bounds(b02,2).extend(prim0);
+
+ /*! increase bounds of bins for odd primitive */
+ const unsigned int s1 = prims[i+1].size();
+ const int b10 = extract<0>(bin1); counts(b10,0)+=s1; bounds(b10,0).extend(prim1);
+ const int b11 = extract<1>(bin1); counts(b11,1)+=s1; bounds(b11,1).extend(prim1);
+ const int b12 = extract<2>(bin1); counts(b12,2)+=s1; bounds(b12,2).extend(prim1);
+ }
+
+ /*! for uneven number of primitives */
+ if (i < N)
+ {
+ /*! map primitive to bin */
+ BBox prim0; Vec3fa center0; binBoundsAndCenter.binBoundsAndCenter(prims[i+0],prim0,center0);
+ const vint4 bin0 = (vint4)mapping.bin(center0);
+
+ /*! increase bounds of bins */
+ const unsigned int s0 = prims[i+0].size();
+ const int b00 = extract<0>(bin0); counts(b00,0)+=s0; bounds(b00,0).extend(prim0);
+ const int b01 = extract<1>(bin0); counts(b01,1)+=s0; bounds(b01,1).extend(prim0);
+ const int b02 = extract<2>(bin0); counts(b02,2)+=s0; bounds(b02,2).extend(prim0);
+ }
+ }
+
+ __forceinline void bin(const PrimRef* prims, size_t begin, size_t end, const BinMapping<BINS>& mapping) {
+ bin(prims+begin,end-begin,mapping);
+ }
+
+ template<typename BinBoundsAndCenter>
+ __forceinline void bin(const PrimRef* prims, size_t begin, size_t end, const BinMapping<BINS>& mapping, const BinBoundsAndCenter& binBoundsAndCenter) {
+ bin<BinBoundsAndCenter>(prims+begin,end-begin,mapping,binBoundsAndCenter);
+ }
+
+ /*! merges in other binning information */
+ __forceinline void merge (const BinInfoT& other, size_t numBins)
+ {
+
+ for (size_t i=0; i<numBins; i++)
+ {
+ counts(i) += other.counts(i);
+ bounds(i,0).extend(other.bounds(i,0));
+ bounds(i,1).extend(other.bounds(i,1));
+ bounds(i,2).extend(other.bounds(i,2));
+ }
+ }
+
+ /*! reduces binning information */
+ static __forceinline const BinInfoT reduce (const BinInfoT& a, const BinInfoT& b, const size_t numBins = BINS)
+ {
+ BinInfoT c;
+ for (size_t i=0; i<numBins; i++)
+ {
+ c.counts(i) = a.counts(i)+b.counts(i);
+ c.bounds(i,0) = embree::merge(a.bounds(i,0),b.bounds(i,0));
+ c.bounds(i,1) = embree::merge(a.bounds(i,1),b.bounds(i,1));
+ c.bounds(i,2) = embree::merge(a.bounds(i,2),b.bounds(i,2));
+ }
+ return c;
+ }
+
+ /*! finds the best split by scanning binning information */
+ __forceinline Split best(const BinMapping<BINS>& mapping, const size_t blocks_shift) const
+ {
+ /* sweep from right to left and compute parallel prefix of merged bounds */
+ vfloat4 rAreas[BINS];
+ vuint4 rCounts[BINS];
+ vuint4 count = 0; BBox bx = empty; BBox by = empty; BBox bz = empty;
+ for (size_t i=mapping.size()-1; i>0; i--)
+ {
+ count += counts(i);
+ rCounts[i] = count;
+ bx.extend(bounds(i,0)); rAreas[i][0] = expectedApproxHalfArea(bx);
+ by.extend(bounds(i,1)); rAreas[i][1] = expectedApproxHalfArea(by);
+ bz.extend(bounds(i,2)); rAreas[i][2] = expectedApproxHalfArea(bz);
+ rAreas[i][3] = 0.0f;
+ }
+ /* sweep from left to right and compute SAH */
+ vuint4 blocks_add = (1 << blocks_shift)-1;
+ vuint4 ii = 1; vfloat4 vbestSAH = pos_inf; vuint4 vbestPos = 0;
+ count = 0; bx = empty; by = empty; bz = empty;
+ for (size_t i=1; i<mapping.size(); i++, ii+=1)
+ {
+ count += counts(i-1);
+ bx.extend(bounds(i-1,0)); float Ax = expectedApproxHalfArea(bx);
+ by.extend(bounds(i-1,1)); float Ay = expectedApproxHalfArea(by);
+ bz.extend(bounds(i-1,2)); float Az = expectedApproxHalfArea(bz);
+ const vfloat4 lArea = vfloat4(Ax,Ay,Az,Az);
+ const vfloat4 rArea = rAreas[i];
+ const vuint4 lCount = (count +blocks_add) >> (unsigned int)(blocks_shift); // if blocks_shift >=1 then lCount < 4B and could be represented with an vint4, which would allow for faster vfloat4 conversions.
+ const vuint4 rCount = (rCounts[i]+blocks_add) >> (unsigned int)(blocks_shift);
+ const vfloat4 sah = madd(lArea,vfloat4(lCount),rArea*vfloat4(rCount));
+ //const vfloat4 sah = madd(lArea,vfloat4(vint4(lCount)),rArea*vfloat4(vint4(rCount)));
+
+ vbestPos = select(sah < vbestSAH,ii ,vbestPos);
+ vbestSAH = select(sah < vbestSAH,sah,vbestSAH);
+ }
+
+ /* find best dimension */
+ float bestSAH = inf;
+ int bestDim = -1;
+ int bestPos = 0;
+ for (int dim=0; dim<3; dim++)
+ {
+ /* ignore zero sized dimensions */
+ if (unlikely(mapping.invalid(dim)))
+ continue;
+
+ /* test if this is a better dimension */
+ if (vbestSAH[dim] < bestSAH && vbestPos[dim] != 0) {
+ bestDim = dim;
+ bestPos = vbestPos[dim];
+ bestSAH = vbestSAH[dim];
+ }
+ }
+ return Split(bestSAH,bestDim,bestPos,mapping);
+ }
+
+ /*! calculates extended split information */
+ __forceinline void getSplitInfo(const BinMapping<BINS>& mapping, const Split& split, SplitInfoT<BBox>& info) const
+ {
+ if (split.dim == -1) {
+ new (&info) SplitInfoT<BBox>(0,empty,0,empty);
+ return;
+ }
+
+ size_t leftCount = 0;
+ BBox leftBounds = empty;
+ for (size_t i=0; i<(size_t)split.pos; i++) {
+ leftCount += counts(i,split.dim);
+ leftBounds.extend(bounds(i,split.dim));
+ }
+ size_t rightCount = 0;
+ BBox rightBounds = empty;
+ for (size_t i=split.pos; i<mapping.size(); i++) {
+ rightCount += counts(i,split.dim);
+ rightBounds.extend(bounds(i,split.dim));
+ }
+ new (&info) SplitInfoT<BBox>(leftCount,leftBounds,rightCount,rightBounds);
+ }
+
+ /*! gets the number of primitives left of the split */
+ __forceinline size_t getLeftCount(const BinMapping<BINS>& mapping, const Split& split) const
+ {
+ if (unlikely(split.dim == -1)) return -1;
+
+ size_t leftCount = 0;
+ for (size_t i = 0; i < (size_t)split.pos; i++) {
+ leftCount += counts(i, split.dim);
+ }
+ return leftCount;
+ }
+
+ /*! gets the number of primitives right of the split */
+ __forceinline size_t getRightCount(const BinMapping<BINS>& mapping, const Split& split) const
+ {
+ if (unlikely(split.dim == -1)) return -1;
+
+ size_t rightCount = 0;
+ for (size_t i = (size_t)split.pos; i<mapping.size(); i++) {
+ rightCount += counts(i, split.dim);
+ }
+ return rightCount;
+ }
+
+ private:
+ BBox _bounds[BINS][3]; //!< geometry bounds for each bin in each dimension
+ vuint4 _counts[BINS]; //!< counts number of primitives that map into the bins
+ };
+ }
+
+ template<typename BinInfoT, typename BinMapping, typename PrimRef>
+ __forceinline void bin_parallel(BinInfoT& binner, const PrimRef* prims, size_t begin, size_t end, size_t blockSize, size_t parallelThreshold, const BinMapping& mapping)
+ {
+ if (likely(end-begin < parallelThreshold)) {
+ binner.bin(prims,begin,end,mapping);
+ } else {
+ binner = parallel_reduce(begin,end,blockSize,binner,
+ [&](const range<size_t>& r) -> BinInfoT { BinInfoT binner(empty); binner.bin(prims + r.begin(), r.size(), mapping); return binner; },
+ [&](const BinInfoT& b0, const BinInfoT& b1) -> BinInfoT { BinInfoT r = b0; r.merge(b1, mapping.size()); return r; });
+ }
+ }
+
+ template<typename BinBoundsAndCenter, typename BinInfoT, typename BinMapping, typename PrimRef>
+ __forceinline void bin_parallel(BinInfoT& binner, const PrimRef* prims, size_t begin, size_t end, size_t blockSize, size_t parallelThreshold, const BinMapping& mapping, const BinBoundsAndCenter& binBoundsAndCenter)
+ {
+ if (likely(end-begin < parallelThreshold)) {
+ binner.bin(prims,begin,end,mapping,binBoundsAndCenter);
+ } else {
+ binner = parallel_reduce(begin,end,blockSize,binner,
+ [&](const range<size_t>& r) -> BinInfoT { BinInfoT binner(empty); binner.bin(prims + r.begin(), r.size(), mapping, binBoundsAndCenter); return binner; },
+ [&](const BinInfoT& b0, const BinInfoT& b1) -> BinInfoT { BinInfoT r = b0; r.merge(b1, mapping.size()); return r; });
+ }
+ }
+
+ template<bool parallel, typename BinInfoT, typename BinMapping, typename PrimRef>
+ __forceinline void bin_serial_or_parallel(BinInfoT& binner, const PrimRef* prims, size_t begin, size_t end, size_t blockSize, const BinMapping& mapping)
+ {
+ if (!parallel) {
+ binner.bin(prims,begin,end,mapping);
+ } else {
+ binner = parallel_reduce(begin,end,blockSize,binner,
+ [&](const range<size_t>& r) -> BinInfoT { BinInfoT binner(empty); binner.bin(prims + r.begin(), r.size(), mapping); return binner; },
+ [&](const BinInfoT& b0, const BinInfoT& b1) -> BinInfoT { BinInfoT r = b0; r.merge(b1, mapping.size()); return r; });
+ }
+ }
+
+ template<bool parallel, typename BinBoundsAndCenter, typename BinInfoT, typename BinMapping, typename PrimRef>
+ __forceinline void bin_serial_or_parallel(BinInfoT& binner, const PrimRef* prims, size_t begin, size_t end, size_t blockSize, const BinMapping& mapping, const BinBoundsAndCenter& binBoundsAndCenter)
+ {
+ if (!parallel) {
+ binner.bin(prims,begin,end,mapping,binBoundsAndCenter);
+ } else {
+ binner = parallel_reduce(begin,end,blockSize,binner,
+ [&](const range<size_t>& r) -> BinInfoT { BinInfoT binner(empty); binner.bin(prims + r.begin(), r.size(), mapping, binBoundsAndCenter); return binner; },
+ [&](const BinInfoT& b0, const BinInfoT& b1) -> BinInfoT { BinInfoT r = b0; r.merge(b1, mapping.size()); return r; });
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/heuristic_binning_array_aligned.h b/thirdparty/embree/kernels/builders/heuristic_binning_array_aligned.h
new file mode 100644
index 0000000000..ab3b97efb9
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/heuristic_binning_array_aligned.h
@@ -0,0 +1,200 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "heuristic_binning.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct PrimInfoRange : public CentGeomBBox3fa, public range<size_t>
+ {
+ __forceinline PrimInfoRange () {
+ }
+
+ __forceinline PrimInfoRange(const PrimInfo& pinfo)
+ : CentGeomBBox3fa(pinfo), range<size_t>(pinfo.begin,pinfo.end) {}
+
+ __forceinline PrimInfoRange(EmptyTy)
+ : CentGeomBBox3fa(EmptyTy()), range<size_t>(0,0) {}
+
+ __forceinline PrimInfoRange (size_t begin, size_t end, const CentGeomBBox3fa& centGeomBounds)
+ : CentGeomBBox3fa(centGeomBounds), range<size_t>(begin,end) {}
+
+ __forceinline float leafSAH() const {
+ return expectedApproxHalfArea(geomBounds)*float(size());
+ }
+
+ __forceinline float leafSAH(size_t block_shift) const {
+ return expectedApproxHalfArea(geomBounds)*float((size()+(size_t(1)<<block_shift)-1) >> block_shift);
+ }
+ };
+
+ /*! Performs standard object binning */
+ template<typename PrimRef, size_t BINS>
+ struct HeuristicArrayBinningSAH
+ {
+ typedef BinSplit<BINS> Split;
+ typedef BinInfoT<BINS,PrimRef,BBox3fa> Binner;
+ typedef range<size_t> Set;
+
+ static const size_t PARALLEL_THRESHOLD = 3 * 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ __forceinline HeuristicArrayBinningSAH ()
+ : prims(nullptr) {}
+
+ /*! remember prim array */
+ __forceinline HeuristicArrayBinningSAH (PrimRef* prims)
+ : prims(prims) {}
+
+ /*! finds the best split */
+ __noinline const Split find(const PrimInfoRange& pinfo, const size_t logBlockSize)
+ {
+ if (likely(pinfo.size() < PARALLEL_THRESHOLD))
+ return find_template<false>(pinfo,logBlockSize);
+ else
+ return find_template<true>(pinfo,logBlockSize);
+ }
+
+ template<bool parallel>
+ __forceinline const Split find_template(const PrimInfoRange& pinfo, const size_t logBlockSize)
+ {
+ Binner binner(empty);
+ const BinMapping<BINS> mapping(pinfo);
+ bin_serial_or_parallel<parallel>(binner,prims,pinfo.begin(),pinfo.end(),PARALLEL_FIND_BLOCK_SIZE,mapping);
+ return binner.best(mapping,logBlockSize);
+ }
+
+ /*! array partitioning */
+ __forceinline void split(const Split& split, const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo)
+ {
+ if (likely(pinfo.size() < PARALLEL_THRESHOLD))
+ split_template<false>(split,pinfo,linfo,rinfo);
+ else
+ split_template<true>(split,pinfo,linfo,rinfo);
+ }
+
+ template<bool parallel>
+ __forceinline void split_template(const Split& split, const PrimInfoRange& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ if (!split.valid()) {
+ deterministic_order(set);
+ return splitFallback(set,lset,rset);
+ }
+
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ CentGeomBBox3fa local_left(empty);
+ CentGeomBBox3fa local_right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ const typename Binner::vint vSplitPos(splitPos);
+ const typename Binner::vbool vSplitMask(splitDimMask);
+ auto isLeft = [&] (const PrimRef &ref) { return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask); };
+
+ size_t center = 0;
+ if (!parallel)
+ center = serial_partitioning(prims,begin,end,local_left,local_right,isLeft,
+ [] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); });
+ else
+ center = parallel_partitioning(
+ prims,begin,end,EmptyTy(),local_left,local_right,isLeft,
+ [] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); },
+ [] (CentGeomBBox3fa& pinfo0,const CentGeomBBox3fa& pinfo1) { pinfo0.merge(pinfo1); },
+ PARALLEL_PARTITION_BLOCK_SIZE);
+
+ new (&lset) PrimInfoRange(begin,center,local_left);
+ new (&rset) PrimInfoRange(center,end,local_right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ }
+
+ void deterministic_order(const PrimInfoRange& pinfo)
+ {
+ /* required as parallel partition destroys original primitive order */
+ std::sort(&prims[pinfo.begin()],&prims[pinfo.end()]);
+ }
+
+ void splitFallback(const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo)
+ {
+ const size_t begin = pinfo.begin();
+ const size_t end = pinfo.end();
+ const size_t center = (begin + end)/2;
+
+ CentGeomBBox3fa left(empty);
+ for (size_t i=begin; i<center; i++)
+ left.extend_center2(prims[i]);
+ new (&linfo) PrimInfoRange(begin,center,left);
+
+ CentGeomBBox3fa right(empty);
+ for (size_t i=center; i<end; i++)
+ right.extend_center2(prims[i]);
+ new (&rinfo) PrimInfoRange(center,end,right);
+ }
+
+ void splitByGeometry(const range<size_t>& range, PrimInfoRange& linfo, PrimInfoRange& rinfo)
+ {
+ assert(range.size() > 1);
+ CentGeomBBox3fa left(empty);
+ CentGeomBBox3fa right(empty);
+ unsigned int geomID = prims[range.begin()].geomID();
+ size_t center = serial_partitioning(prims,range.begin(),range.end(),left,right,
+ [&] ( const PrimRef& prim ) { return prim.geomID() == geomID; },
+ [ ] ( CentGeomBBox3fa& a, const PrimRef& ref ) { a.extend_center2(ref); });
+
+ new (&linfo) PrimInfoRange(range.begin(),center,left);
+ new (&rinfo) PrimInfoRange(center,range.end(),right);
+ }
+
+ private:
+ PrimRef* const prims;
+ };
+
+ /*! Performs standard object binning */
+ template<typename PrimRefMB, size_t BINS>
+ struct HeuristicArrayBinningMB
+ {
+ typedef BinSplit<BINS> Split;
+ typedef typename PrimRefMB::BBox BBox;
+ typedef BinInfoT<BINS,PrimRefMB,BBox> ObjectBinner;
+ static const size_t PARALLEL_THRESHOLD = 3 * 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ /*! finds the best split */
+ const Split find(const SetMB& set, const size_t logBlockSize)
+ {
+ ObjectBinner binner(empty);
+ const BinMapping<BINS> mapping(set.size(),set.centBounds);
+ bin_parallel(binner,set.prims->data(),set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,mapping);
+ Split osplit = binner.best(mapping,logBlockSize);
+ osplit.sah *= set.time_range.size();
+ if (!osplit.valid()) osplit.data = Split::SPLIT_FALLBACK; // use fallback split
+ return osplit;
+ }
+
+ /*! array partitioning */
+ __forceinline void split(const Split& split, const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfoMB left = empty;
+ PrimInfoMB right = empty;
+ const vint4 vSplitPos(split.pos);
+ const vbool4 vSplitMask(1 << split.dim);
+ auto isLeft = [&] (const PrimRefMB &ref) { return any(((vint4)split.mapping.bin_unsafe(ref) < vSplitPos) & vSplitMask); };
+ auto reduction = [] (PrimInfoMB& pinfo, const PrimRefMB& ref) { pinfo.add_primref(ref); };
+ auto reduction2 = [] (PrimInfoMB& pinfo0,const PrimInfoMB& pinfo1) { pinfo0.merge(pinfo1); };
+ size_t center = parallel_partitioning(set.prims->data(),begin,end,EmptyTy(),left,right,isLeft,reduction,reduction2,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD);
+ new (&lset) SetMB(left, set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(right,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/heuristic_binning_array_unaligned.h b/thirdparty/embree/kernels/builders/heuristic_binning_array_unaligned.h
new file mode 100644
index 0000000000..34a7f121bb
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/heuristic_binning_array_unaligned.h
@@ -0,0 +1,302 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "heuristic_binning.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Performs standard object binning */
+ template<typename PrimRef, size_t BINS>
+ struct UnalignedHeuristicArrayBinningSAH
+ {
+ typedef BinSplit<BINS> Split;
+ typedef BinInfoT<BINS,PrimRef,BBox3fa> Binner;
+ typedef range<size_t> Set;
+
+ __forceinline UnalignedHeuristicArrayBinningSAH () // FIXME: required?
+ : scene(nullptr), prims(nullptr) {}
+
+ /*! remember prim array */
+ __forceinline UnalignedHeuristicArrayBinningSAH (Scene* scene, PrimRef* prims)
+ : scene(scene), prims(prims) {}
+
+ const LinearSpace3fa computeAlignedSpace(const range<size_t>& set)
+ {
+ Vec3fa axis(0,0,1);
+ uint64_t bestGeomPrimID = -1;
+
+ /*! find curve with minimum ID that defines valid direction */
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ const unsigned int geomID = prims[i].geomID();
+ const unsigned int primID = prims[i].primID();
+ const uint64_t geomprimID = prims[i].ID64();
+ if (geomprimID >= bestGeomPrimID) continue;
+ const Vec3fa axis1 = scene->get(geomID)->computeDirection(primID);
+ if (sqr_length(axis1) > 1E-18f) {
+ axis = normalize(axis1);
+ bestGeomPrimID = geomprimID;
+ }
+ }
+ return frame(axis).transposed();
+ }
+
+ const PrimInfo computePrimInfo(const range<size_t>& set, const LinearSpace3fa& space)
+ {
+ auto computeBounds = [&](const range<size_t>& r) -> CentGeomBBox3fa
+ {
+ CentGeomBBox3fa bounds(empty);
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ Geometry* mesh = scene->get(prims[i].geomID());
+ bounds.extend(mesh->vbounds(space,prims[i].primID()));
+ }
+ return bounds;
+ };
+
+ const CentGeomBBox3fa bounds = parallel_reduce(set.begin(), set.end(), size_t(1024), size_t(4096),
+ CentGeomBBox3fa(empty), computeBounds, CentGeomBBox3fa::merge2);
+
+ return PrimInfo(set.begin(),set.end(),bounds);
+ }
+
+ struct BinBoundsAndCenter
+ {
+ __forceinline BinBoundsAndCenter(Scene* scene, const LinearSpace3fa& space)
+ : scene(scene), space(space) {}
+
+ /*! returns center for binning */
+ __forceinline Vec3fa binCenter(const PrimRef& ref) const
+ {
+ Geometry* mesh = (Geometry*) scene->get(ref.geomID());
+ BBox3fa bounds = mesh->vbounds(space,ref.primID());
+ return embree::center2(bounds);
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __forceinline void binBoundsAndCenter(const PrimRef& ref, BBox3fa& bounds_o, Vec3fa& center_o) const
+ {
+ Geometry* mesh = (Geometry*) scene->get(ref.geomID());
+ BBox3fa bounds = mesh->vbounds(space,ref.primID());
+ bounds_o = bounds;
+ center_o = embree::center2(bounds);
+ }
+
+ private:
+ Scene* scene;
+ const LinearSpace3fa space;
+ };
+
+ /*! finds the best split */
+ __forceinline const Split find(const PrimInfoRange& pinfo, const size_t logBlockSize, const LinearSpace3fa& space)
+ {
+ if (likely(pinfo.size() < 10000))
+ return find_template<false>(pinfo,logBlockSize,space);
+ else
+ return find_template<true>(pinfo,logBlockSize,space);
+ }
+
+ /*! finds the best split */
+ template<bool parallel>
+ const Split find_template(const PrimInfoRange& set, const size_t logBlockSize, const LinearSpace3fa& space)
+ {
+ Binner binner(empty);
+ const BinMapping<BINS> mapping(set);
+ BinBoundsAndCenter binBoundsAndCenter(scene,space);
+ bin_serial_or_parallel<parallel>(binner,prims,set.begin(),set.end(),size_t(4096),mapping,binBoundsAndCenter);
+ return binner.best(mapping,logBlockSize);
+ }
+
+ /*! array partitioning */
+ __forceinline void split(const Split& split, const LinearSpace3fa& space, const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ if (likely(set.size() < 10000))
+ split_template<false>(split,space,set,lset,rset);
+ else
+ split_template<true>(split,space,set,lset,rset);
+ }
+
+ /*! array partitioning */
+ template<bool parallel>
+ __forceinline void split_template(const Split& split, const LinearSpace3fa& space, const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ if (!split.valid()) {
+ deterministic_order(set);
+ return splitFallback(set,lset,rset);
+ }
+
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ CentGeomBBox3fa local_left(empty);
+ CentGeomBBox3fa local_right(empty);
+ const int splitPos = split.pos;
+ const int splitDim = split.dim;
+ BinBoundsAndCenter binBoundsAndCenter(scene,space);
+
+ size_t center = 0;
+ if (likely(set.size() < 10000))
+ center = serial_partitioning(prims,begin,end,local_left,local_right,
+ [&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,binBoundsAndCenter)[splitDim] < splitPos; },
+ [] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); });
+ else
+ center = parallel_partitioning(prims,begin,end,EmptyTy(),local_left,local_right,
+ [&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,binBoundsAndCenter)[splitDim] < splitPos; },
+ [] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend_center2(ref); },
+ [] (CentGeomBBox3fa& pinfo0,const CentGeomBBox3fa& pinfo1) { pinfo0.merge(pinfo1); },
+ 128);
+
+ new (&lset) PrimInfoRange(begin,center,local_left);
+ new (&rset) PrimInfoRange(center,end,local_right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ }
+
+ void deterministic_order(const range<size_t>& set)
+ {
+ /* required as parallel partition destroys original primitive order */
+ std::sort(&prims[set.begin()],&prims[set.end()]);
+ }
+
+ void splitFallback(const range<size_t>& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ CentGeomBBox3fa left(empty);
+ for (size_t i=begin; i<center; i++)
+ left.extend_center2(prims[i]);
+ new (&lset) PrimInfoRange(begin,center,left);
+
+ CentGeomBBox3fa right(empty);
+ for (size_t i=center; i<end; i++)
+ right.extend_center2(prims[i]);
+ new (&rset) PrimInfoRange(center,end,right);
+ }
+
+ private:
+ Scene* const scene;
+ PrimRef* const prims;
+ };
+
+ /*! Performs standard object binning */
+ template<typename PrimRefMB, size_t BINS>
+ struct UnalignedHeuristicArrayBinningMB
+ {
+ typedef BinSplit<BINS> Split;
+ typedef typename PrimRefMB::BBox BBox;
+ typedef BinInfoT<BINS,PrimRefMB,BBox> ObjectBinner;
+
+ static const size_t PARALLEL_THRESHOLD = 3 * 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ UnalignedHeuristicArrayBinningMB(Scene* scene)
+ : scene(scene) {}
+
+ const LinearSpace3fa computeAlignedSpaceMB(Scene* scene, const SetMB& set)
+ {
+ Vec3fa axis0(0,0,1);
+ uint64_t bestGeomPrimID = -1;
+
+ /*! find curve with minimum ID that defines valid direction */
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ const PrimRefMB& prim = (*set.prims)[i];
+ const unsigned int geomID = prim.geomID();
+ const unsigned int primID = prim.primID();
+ const uint64_t geomprimID = prim.ID64();
+ if (geomprimID >= bestGeomPrimID) continue;
+
+ const Geometry* mesh = scene->get(geomID);
+ const range<int> tbounds = mesh->timeSegmentRange(set.time_range);
+ if (tbounds.size() == 0) continue;
+
+ const size_t t = (tbounds.begin()+tbounds.end())/2;
+ const Vec3fa axis1 = mesh->computeDirection(primID,t);
+ if (sqr_length(axis1) > 1E-18f) {
+ axis0 = normalize(axis1);
+ bestGeomPrimID = geomprimID;
+ }
+ }
+
+ return frame(axis0).transposed();
+ }
+
+ struct BinBoundsAndCenter
+ {
+ __forceinline BinBoundsAndCenter(Scene* scene, BBox1f time_range, const LinearSpace3fa& space)
+ : scene(scene), time_range(time_range), space(space) {}
+
+ /*! returns center for binning */
+ template<typename PrimRef>
+ __forceinline Vec3fa binCenter(const PrimRef& ref) const
+ {
+ Geometry* mesh = scene->get(ref.geomID());
+ LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
+ return center2(lbounds.interpolate(0.5f));
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __noinline void binBoundsAndCenter (const PrimRefMB& ref, BBox3fa& bounds_o, Vec3fa& center_o) const // __noinline is workaround for ICC16 bug under MacOSX
+ {
+ Geometry* mesh = scene->get(ref.geomID());
+ LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
+ bounds_o = lbounds.interpolate(0.5f);
+ center_o = center2(bounds_o);
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __noinline void binBoundsAndCenter (const PrimRefMB& ref, LBBox3fa& bounds_o, Vec3fa& center_o) const // __noinline is workaround for ICC16 bug under MacOSX
+ {
+ Geometry* mesh = scene->get(ref.geomID());
+ LBBox3fa lbounds = mesh->vlinearBounds(space,ref.primID(),time_range);
+ bounds_o = lbounds;
+ center_o = center2(lbounds.interpolate(0.5f));
+ }
+
+ private:
+ Scene* scene;
+ BBox1f time_range;
+ const LinearSpace3fa space;
+ };
+
+ /*! finds the best split */
+ const Split find(const SetMB& set, const size_t logBlockSize, const LinearSpace3fa& space)
+ {
+ BinBoundsAndCenter binBoundsAndCenter(scene,set.time_range,space);
+ ObjectBinner binner(empty);
+ const BinMapping<BINS> mapping(set.size(),set.centBounds);
+ bin_parallel(binner,set.prims->data(),set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,mapping,binBoundsAndCenter);
+ Split osplit = binner.best(mapping,logBlockSize);
+ osplit.sah *= set.time_range.size();
+ if (!osplit.valid()) osplit.data = Split::SPLIT_FALLBACK; // use fallback split
+ return osplit;
+ }
+
+ /*! array partitioning */
+ __forceinline void split(const Split& split, const LinearSpace3fa& space, const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ BinBoundsAndCenter binBoundsAndCenter(scene,set.time_range,space);
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfoMB left = empty;
+ PrimInfoMB right = empty;
+ const vint4 vSplitPos(split.pos);
+ const vbool4 vSplitMask(1 << split.dim);
+ auto isLeft = [&] (const PrimRefMB &ref) { return any(((vint4)split.mapping.bin_unsafe(ref,binBoundsAndCenter) < vSplitPos) & vSplitMask); };
+ auto reduction = [] (PrimInfoMB& pinfo, const PrimRefMB& ref) { pinfo.add_primref(ref); };
+ auto reduction2 = [] (PrimInfoMB& pinfo0,const PrimInfoMB& pinfo1) { pinfo0.merge(pinfo1); };
+ size_t center = parallel_partitioning(set.prims->data(),begin,end,EmptyTy(),left,right,isLeft,reduction,reduction2,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD);
+ new (&lset) SetMB(left,set.prims,range<size_t>(begin,center),set.time_range);
+ new (&rset) SetMB(right,set.prims,range<size_t>(center,end ),set.time_range);
+ }
+
+ private:
+ Scene* scene;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/heuristic_openmerge_array.h b/thirdparty/embree/kernels/builders/heuristic_openmerge_array.h
new file mode 100644
index 0000000000..4249d16ea1
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/heuristic_openmerge_array.h
@@ -0,0 +1,443 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+// TODO:
+// - adjust parallel build thresholds
+// - openNodesBasedOnExtend should consider max extended size
+
+#pragma once
+
+#include "heuristic_binning.h"
+#include "heuristic_spatial.h"
+
+/* stop opening of all bref.geomIDs are the same */
+#define EQUAL_GEOMID_STOP_CRITERIA 1
+
+/* 10% spatial extend threshold */
+#define MAX_EXTEND_THRESHOLD 0.1f
+
+/* maximum is 8 children */
+#define MAX_OPENED_CHILD_NODES 8
+
+/* open until all build refs are below threshold size in one step */
+#define USE_LOOP_OPENING 0
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Performs standard object binning */
+ template<typename NodeOpenerFunc, typename PrimRef, size_t OBJECT_BINS>
+ struct HeuristicArrayOpenMergeSAH
+ {
+ typedef BinSplit<OBJECT_BINS> Split;
+ typedef BinInfoT<OBJECT_BINS,PrimRef,BBox3fa> Binner;
+
+ static const size_t PARALLEL_THRESHOLD = 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 512;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ static const size_t MOVE_STEP_SIZE = 64;
+ static const size_t CREATE_SPLITS_STEP_SIZE = 128;
+
+ __forceinline HeuristicArrayOpenMergeSAH ()
+ : prims0(nullptr) {}
+
+ /*! remember prim array */
+ __forceinline HeuristicArrayOpenMergeSAH (const NodeOpenerFunc& nodeOpenerFunc, PrimRef* prims0, size_t max_open_size)
+ : prims0(prims0), nodeOpenerFunc(nodeOpenerFunc), max_open_size(max_open_size)
+ {
+ assert(max_open_size <= MAX_OPENED_CHILD_NODES);
+ }
+
+ struct OpenHeuristic
+ {
+ __forceinline OpenHeuristic( const PrimInfoExtRange& pinfo )
+ {
+ const Vec3fa diag = pinfo.geomBounds.size();
+ dim = maxDim(diag);
+ assert(diag[dim] > 0.0f);
+ inv_max_extend = 1.0f / diag[dim];
+ }
+
+ __forceinline bool operator () ( PrimRef& prim ) const {
+ return !prim.node.isLeaf() && prim.bounds().size()[dim] * inv_max_extend > MAX_EXTEND_THRESHOLD;
+ }
+
+ private:
+ size_t dim;
+ float inv_max_extend;
+ };
+
+ /*! compute extended ranges */
+ __forceinline void setExtentedRanges(const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset, const size_t lweight, const size_t rweight)
+ {
+ assert(set.ext_range_size() > 0);
+ const float left_factor = (float)lweight / (lweight + rweight);
+ const size_t ext_range_size = set.ext_range_size();
+ const size_t left_ext_range_size = min((size_t)(floorf(left_factor * ext_range_size)),ext_range_size);
+ const size_t right_ext_range_size = ext_range_size - left_ext_range_size;
+ lset.set_ext_range(lset.end() + left_ext_range_size);
+ rset.set_ext_range(rset.end() + right_ext_range_size);
+ }
+
+ /*! move ranges */
+ __forceinline void moveExtentedRange(const PrimInfoExtRange& set, const PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t left_ext_range_size = lset.ext_range_size();
+ const size_t right_size = rset.size();
+
+ /* has the left child an extended range? */
+ if (left_ext_range_size > 0)
+ {
+ /* left extended range smaller than right range ? */
+ if (left_ext_range_size < right_size)
+ {
+ /* only move a small part of the beginning of the right range to the end */
+ parallel_for( rset.begin(), rset.begin()+left_ext_range_size, MOVE_STEP_SIZE, [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ prims0[i+right_size] = prims0[i];
+ });
+ }
+ else
+ {
+ /* no overlap, move entire right range to new location, can be made fully parallel */
+ parallel_for( rset.begin(), rset.end(), MOVE_STEP_SIZE, [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ prims0[i+left_ext_range_size] = prims0[i];
+ });
+ }
+ /* update right range */
+ assert(rset.ext_end() + left_ext_range_size == set.ext_end());
+ rset.move_right(left_ext_range_size);
+ }
+ }
+
+ /* estimates the extra space required when opening, and checks if all primitives are from same geometry */
+ __noinline std::pair<size_t,bool> getProperties(const PrimInfoExtRange& set)
+ {
+ const OpenHeuristic heuristic(set);
+ const unsigned int geomID = prims0[set.begin()].geomID();
+
+ auto body = [&] (const range<size_t>& r) -> std::pair<size_t,bool> {
+ bool commonGeomID = true;
+ size_t opens = 0;
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ commonGeomID &= prims0[i].geomID() == geomID;
+ if (heuristic(prims0[i]))
+ opens += prims0[i].node.getN()-1; // coarse approximation
+ }
+ return std::pair<size_t,bool>(opens,commonGeomID);
+ };
+ auto reduction = [&] (const std::pair<size_t,bool>& b0, const std::pair<size_t,bool>& b1) -> std::pair<size_t,bool> {
+ return std::pair<size_t,bool>(b0.first+b1.first,b0.second && b1.second);
+ };
+ return parallel_reduce(set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,std::pair<size_t,bool>(0,true),body,reduction);
+ }
+
+ // FIXME: should consider maximum available extended size
+ __noinline void openNodesBasedOnExtend(PrimInfoExtRange& set)
+ {
+ const OpenHeuristic heuristic(set);
+ const size_t ext_range_start = set.end();
+
+ if (false && set.size() < PARALLEL_THRESHOLD)
+ {
+ size_t extra_elements = 0;
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ if (heuristic(prims0[i]))
+ {
+ PrimRef tmp[MAX_OPENED_CHILD_NODES];
+ const size_t n = nodeOpenerFunc(prims0[i],tmp);
+ assert(extra_elements + n-1 <= set.ext_range_size());
+ for (size_t j=0; j<n; j++)
+ set.extend_center2(tmp[j]);
+
+ prims0[i] = tmp[0];
+ for (size_t j=1; j<n; j++)
+ prims0[ext_range_start+extra_elements+j-1] = tmp[j];
+ extra_elements += n-1;
+ }
+ }
+ set._end += extra_elements;
+ }
+ else
+ {
+ std::atomic<size_t> ext_elements;
+ ext_elements.store(0);
+ PrimInfo info = parallel_reduce( set.begin(), set.end(), CREATE_SPLITS_STEP_SIZE, PrimInfo(empty), [&](const range<size_t>& r) -> PrimInfo {
+ PrimInfo info(empty);
+ for (size_t i=r.begin(); i<r.end(); i++)
+ if (heuristic(prims0[i]))
+ {
+ PrimRef tmp[MAX_OPENED_CHILD_NODES];
+ const size_t n = nodeOpenerFunc(prims0[i],tmp);
+ const size_t ID = ext_elements.fetch_add(n-1);
+ assert(ID + n-1 <= set.ext_range_size());
+
+ for (size_t j=0; j<n; j++)
+ info.extend_center2(tmp[j]);
+
+ prims0[i] = tmp[0];
+ for (size_t j=1; j<n; j++)
+ prims0[ext_range_start+ID+j-1] = tmp[j];
+ }
+ return info;
+ }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });
+ set.centBounds.extend(info.centBounds);
+ assert(ext_elements.load() <= set.ext_range_size());
+ set._end += ext_elements.load();
+ }
+ }
+
+ __noinline void openNodesBasedOnExtendLoop(PrimInfoExtRange& set, const size_t est_new_elements)
+ {
+ const OpenHeuristic heuristic(set);
+ size_t next_iteration_extra_elements = est_new_elements;
+
+ while (next_iteration_extra_elements <= set.ext_range_size())
+ {
+ next_iteration_extra_elements = 0;
+ size_t extra_elements = 0;
+ const size_t ext_range_start = set.end();
+
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ if (heuristic(prims0[i]))
+ {
+ PrimRef tmp[MAX_OPENED_CHILD_NODES];
+ const size_t n = nodeOpenerFunc(prims0[i],tmp);
+ assert(extra_elements + n-1 <= set.ext_range_size());
+ for (size_t j=0;j<n;j++)
+ set.extend_center2(tmp[j]);
+
+ prims0[i] = tmp[0];
+ for (size_t j=1;j<n;j++)
+ prims0[ext_range_start+extra_elements+j-1] = tmp[j];
+ extra_elements += n-1;
+
+ for (size_t j=0; j<n; j++)
+ if (heuristic(tmp[j]))
+ next_iteration_extra_elements += tmp[j].node.getN()-1; // coarse approximation
+
+ }
+ }
+ assert( extra_elements <= set.ext_range_size());
+ set._end += extra_elements;
+
+ for (size_t i=set.begin();i<set.end();i++)
+ assert(prims0[i].numPrimitives() > 0);
+
+ if (unlikely(next_iteration_extra_elements == 0)) break;
+ }
+ }
+
+ __noinline const Split find(PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ /* single element */
+ if (set.size() <= 1)
+ return Split();
+
+ /* disable opening if there is no overlap */
+ const size_t D = 4;
+ if (unlikely(set.has_ext_range() && set.size() <= D))
+ {
+ bool disjoint = true;
+ for (size_t j=set.begin(); j<set.end()-1; j++) {
+ for (size_t i=set.begin()+1; i<set.end(); i++) {
+ if (conjoint(prims0[j].bounds(),prims0[i].bounds())) {
+ disjoint = false; break;
+ }
+ }
+ }
+ if (disjoint) set.set_ext_range(set.end()); /* disables opening */
+ }
+
+ std::pair<size_t,bool> p(0,false);
+
+ /* disable opening when all primitives are from same geometry */
+ if (unlikely(set.has_ext_range()))
+ {
+ p = getProperties(set);
+#if EQUAL_GEOMID_STOP_CRITERIA == 1
+ if (p.second) set.set_ext_range(set.end()); /* disable opening */
+#endif
+ }
+
+ /* open nodes when we have sufficient space available */
+ if (unlikely(set.has_ext_range()))
+ {
+#if USE_LOOP_OPENING == 1
+ openNodesBasedOnExtendLoop(set,p.first);
+#else
+ if (p.first <= set.ext_range_size())
+ openNodesBasedOnExtend(set);
+#endif
+
+ /* disable opening when unsufficient space for opening a node available */
+ if (set.ext_range_size() < max_open_size-1)
+ set.set_ext_range(set.end()); /* disable opening */
+ }
+
+ /* find best split */
+ return object_find(set,logBlockSize);
+ }
+
+
+ /*! finds the best object split */
+ __forceinline const Split object_find(const PrimInfoExtRange& set,const size_t logBlockSize)
+ {
+ if (set.size() < PARALLEL_THRESHOLD) return sequential_object_find(set,logBlockSize);
+ else return parallel_object_find (set,logBlockSize);
+ }
+
+ /*! finds the best object split */
+ __noinline const Split sequential_object_find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ Binner binner(empty);
+ const BinMapping<OBJECT_BINS> mapping(set.centBounds);
+ binner.bin(prims0,set.begin(),set.end(),mapping);
+ return binner.best(mapping,logBlockSize);
+ }
+
+ /*! finds the best split */
+ __noinline const Split parallel_object_find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ Binner binner(empty);
+ const BinMapping<OBJECT_BINS> mapping(set.centBounds);
+ const BinMapping<OBJECT_BINS>& _mapping = mapping; // CLANG 3.4 parser bug workaround
+ auto body = [&] (const range<size_t>& r) -> Binner {
+ Binner binner(empty); binner.bin(prims0+r.begin(),r.size(),_mapping); return binner;
+ };
+ auto reduction = [&] (const Binner& b0, const Binner& b1) -> Binner {
+ Binner r = b0; r.merge(b1,_mapping.size()); return r;
+ };
+ binner = parallel_reduce(set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,binner,body,reduction);
+ return binner.best(mapping,logBlockSize);
+ }
+
+ /*! array partitioning */
+ __noinline void split(const Split& split, const PrimInfoExtRange& set_i, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ PrimInfoExtRange set = set_i;
+
+ /* valid split */
+ if (unlikely(!split.valid())) {
+ deterministic_order(set);
+ splitFallback(set,lset,rset);
+ return;
+ }
+
+ std::pair<size_t,size_t> ext_weights(0,0);
+
+ /* object split */
+ if (likely(set.size() < PARALLEL_THRESHOLD))
+ ext_weights = sequential_object_split(split,set,lset,rset);
+ else
+ ext_weights = parallel_object_split(split,set,lset,rset);
+
+ /* if we have an extended range, set extended child ranges and move right split range */
+ if (unlikely(set.has_ext_range()))
+ {
+ setExtentedRanges(set,lset,rset,ext_weights.first,ext_weights.second);
+ moveExtentedRange(set,lset,rset);
+ }
+ }
+
+ /*! array partitioning */
+ std::pair<size_t,size_t> sequential_object_split(const Split& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo local_left(empty);
+ PrimInfo local_right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ const vint4 vSplitPos(splitPos);
+ const vbool4 vSplitMask( (int)splitDimMask );
+
+ size_t center = serial_partitioning(prims0,
+ begin,end,local_left,local_right,
+ [&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask); },
+ [] (PrimInfo& pinfo,const PrimRef& ref) { pinfo.add_center2(ref); });
+
+ new (&lset) PrimInfoExtRange(begin,center,center,local_left);
+ new (&rset) PrimInfoExtRange(center,end,end,local_right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ return std::pair<size_t,size_t>(local_left.size(),local_right.size());
+ }
+
+ /*! array partitioning */
+ __noinline std::pair<size_t,size_t> parallel_object_split(const Split& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo left(empty);
+ PrimInfo right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ const vint4 vSplitPos(splitPos);
+ const vbool4 vSplitMask( (int)splitDimMask );
+ auto isLeft = [&] (const PrimRef& ref) { return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask); };
+
+ const size_t center = parallel_partitioning(
+ prims0,begin,end,EmptyTy(),left,right,isLeft,
+ [] (PrimInfo& pinfo,const PrimRef& ref) { pinfo.add_center2(ref); },
+ [] (PrimInfo& pinfo0,const PrimInfo& pinfo1) { pinfo0.merge(pinfo1); },
+ PARALLEL_PARTITION_BLOCK_SIZE);
+
+ new (&lset) PrimInfoExtRange(begin,center,center,left);
+ new (&rset) PrimInfoExtRange(center,end,end,right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+
+ return std::pair<size_t,size_t>(left.size(),right.size());
+ }
+
+ void deterministic_order(const extended_range<size_t>& set)
+ {
+ /* required as parallel partition destroys original primitive order */
+ std::sort(&prims0[set.begin()],&prims0[set.end()]);
+ }
+
+ __forceinline void splitFallback(const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ PrimInfo left(empty);
+ for (size_t i=begin; i<center; i++)
+ left.add_center2(prims0[i]);
+
+ const size_t lweight = left.end;
+
+ PrimInfo right(empty);
+ for (size_t i=center; i<end; i++)
+ right.add_center2(prims0[i]);
+
+ const size_t rweight = right.end;
+ new (&lset) PrimInfoExtRange(begin,center,center,left);
+ new (&rset) PrimInfoExtRange(center,end,end,right);
+
+ /* if we have an extended range */
+ if (set.has_ext_range())
+ {
+ setExtentedRanges(set,lset,rset,lweight,rweight);
+ moveExtentedRange(set,lset,rset);
+ }
+ }
+
+ private:
+ PrimRef* const prims0;
+ const NodeOpenerFunc& nodeOpenerFunc;
+ size_t max_open_size;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/heuristic_spatial.h b/thirdparty/embree/kernels/builders/heuristic_spatial.h
new file mode 100644
index 0000000000..a6939ba258
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/heuristic_spatial.h
@@ -0,0 +1,414 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/scene.h"
+#include "priminfo.h"
+
+namespace embree
+{
+ static const unsigned int RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS = 5;
+
+ namespace isa
+ {
+
+ /*! mapping into bins */
+ template<size_t BINS>
+ struct SpatialBinMapping
+ {
+ public:
+ __forceinline SpatialBinMapping() {}
+
+ /*! calculates the mapping */
+ __forceinline SpatialBinMapping(const CentGeomBBox3fa& pinfo)
+ {
+ const vfloat4 lower = (vfloat4) pinfo.geomBounds.lower;
+ const vfloat4 upper = (vfloat4) pinfo.geomBounds.upper;
+ const vfloat4 eps = 128.0f*vfloat4(ulp)*max(abs(lower),abs(upper));
+ const vfloat4 diag = max(eps,(vfloat4) pinfo.geomBounds.size());
+ scale = select(upper-lower <= eps,vfloat4(0.0f),vfloat4(BINS)/diag);
+ ofs = (vfloat4) pinfo.geomBounds.lower;
+ inv_scale = 1.0f / scale;
+ }
+
+ /*! slower but safe binning */
+ __forceinline vint4 bin(const Vec3fa& p) const
+ {
+ const vint4 i = floori((vfloat4(p)-ofs)*scale);
+ return clamp(i,vint4(0),vint4(BINS-1));
+ }
+
+ __forceinline std::pair<vint4,vint4> bin(const BBox3fa& b) const
+ {
+#if defined(__AVX__)
+ const vfloat8 ofs8(ofs);
+ const vfloat8 scale8(scale);
+ const vint8 lu = floori((vfloat8::loadu(&b)-ofs8)*scale8);
+ const vint8 c_lu = clamp(lu,vint8(zero),vint8(BINS-1));
+ return std::pair<vint4,vint4>(extract4<0>(c_lu),extract4<1>(c_lu));
+#else
+ const vint4 lower = floori((vfloat4(b.lower)-ofs)*scale);
+ const vint4 upper = floori((vfloat4(b.upper)-ofs)*scale);
+ const vint4 c_lower = clamp(lower,vint4(0),vint4(BINS-1));
+ const vint4 c_upper = clamp(upper,vint4(0),vint4(BINS-1));
+ return std::pair<vint4,vint4>(c_lower,c_upper);
+#endif
+ }
+
+
+ /*! calculates left spatial position of bin */
+ __forceinline float pos(const size_t bin, const size_t dim) const {
+ return madd(float(bin),inv_scale[dim],ofs[dim]);
+ }
+
+ /*! calculates left spatial position of bin */
+ template<size_t N>
+ __forceinline vfloat<N> posN(const vfloat<N> bin, const size_t dim) const {
+ return madd(bin,vfloat<N>(inv_scale[dim]),vfloat<N>(ofs[dim]));
+ }
+
+ /*! returns true if the mapping is invalid in some dimension */
+ __forceinline bool invalid(const size_t dim) const {
+ return scale[dim] == 0.0f;
+ }
+
+ public:
+ vfloat4 ofs,scale,inv_scale; //!< linear function that maps to bin ID
+ };
+
+ /*! stores all information required to perform some split */
+ template<size_t BINS>
+ struct SpatialBinSplit
+ {
+ /*! construct an invalid split by default */
+ __forceinline SpatialBinSplit()
+ : sah(inf), dim(-1), pos(0), left(-1), right(-1), factor(1.0f) {}
+
+ /*! constructs specified split */
+ __forceinline SpatialBinSplit(float sah, int dim, int pos, const SpatialBinMapping<BINS>& mapping)
+ : sah(sah), dim(dim), pos(pos), left(-1), right(-1), factor(1.0f), mapping(mapping) {}
+
+ /*! constructs specified split */
+ __forceinline SpatialBinSplit(float sah, int dim, int pos, int left, int right, float factor, const SpatialBinMapping<BINS>& mapping)
+ : sah(sah), dim(dim), pos(pos), left(left), right(right), factor(factor), mapping(mapping) {}
+
+ /*! tests if this split is valid */
+ __forceinline bool valid() const { return dim != -1; }
+
+ /*! calculates surface area heuristic for performing the split */
+ __forceinline float splitSAH() const { return sah; }
+
+ /*! stream output */
+ friend embree_ostream operator<<(embree_ostream cout, const SpatialBinSplit& split) {
+ return cout << "SpatialBinSplit { sah = " << split.sah << ", dim = " << split.dim << ", pos = " << split.pos << ", left = " << split.left << ", right = " << split.right << ", factor = " << split.factor << "}";
+ }
+
+ public:
+ float sah; //!< SAH cost of the split
+ int dim; //!< split dimension
+ int pos; //!< split position
+ int left; //!< number of elements on the left side
+ int right; //!< number of elements on the right side
+ float factor; //!< factor splitting the extended range
+ SpatialBinMapping<BINS> mapping; //!< mapping into bins
+ };
+
+ /*! stores all binning information */
+ template<size_t BINS, typename PrimRef>
+ struct __aligned(64) SpatialBinInfo
+ {
+ SpatialBinInfo() {
+ }
+
+ __forceinline SpatialBinInfo(EmptyTy) {
+ clear();
+ }
+
+ /*! clears the bin info */
+ __forceinline void clear()
+ {
+ for (size_t i=0; i<BINS; i++) {
+ bounds[i][0] = bounds[i][1] = bounds[i][2] = empty;
+ numBegin[i] = numEnd[i] = 0;
+ }
+ }
+
+ /*! adds binning data */
+ __forceinline void add(const size_t dim,
+ const size_t beginID,
+ const size_t endID,
+ const size_t binID,
+ const BBox3fa &b,
+ const size_t n = 1)
+ {
+ assert(beginID < BINS);
+ assert(endID < BINS);
+ assert(binID < BINS);
+
+ numBegin[beginID][dim]+=(unsigned int)n;
+ numEnd [endID][dim]+=(unsigned int)n;
+ bounds [binID][dim].extend(b);
+ }
+
+ /*! extends binning bounds */
+ __forceinline void extend(const size_t dim,
+ const size_t binID,
+ const BBox3fa &b)
+ {
+ assert(binID < BINS);
+ bounds [binID][dim].extend(b);
+ }
+
+ /*! bins an array of triangles */
+ template<typename SplitPrimitive>
+ __forceinline void bin(const SplitPrimitive& splitPrimitive, const PrimRef* prims, size_t N, const SpatialBinMapping<BINS>& mapping)
+ {
+ for (size_t i=0; i<N; i++)
+ {
+ const PrimRef prim = prims[i];
+ unsigned splits = prim.geomID() >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS);
+
+ if (unlikely(splits == 1))
+ {
+ const vint4 bin = mapping.bin(center(prim.bounds()));
+ for (size_t dim=0; dim<3; dim++)
+ {
+ assert(bin[dim] >= (int)0 && bin[dim] < (int)BINS);
+ numBegin[bin[dim]][dim]++;
+ numEnd [bin[dim]][dim]++;
+ bounds [bin[dim]][dim].extend(prim.bounds());
+ }
+ }
+ else
+ {
+ const vint4 bin0 = mapping.bin(prim.bounds().lower);
+ const vint4 bin1 = mapping.bin(prim.bounds().upper);
+
+ for (size_t dim=0; dim<3; dim++)
+ {
+ size_t bin;
+ PrimRef rest = prim;
+ size_t l = bin0[dim];
+ size_t r = bin1[dim];
+
+ // same bin optimization
+ if (likely(l == r))
+ {
+ numBegin[l][dim]++;
+ numEnd [l][dim]++;
+ bounds [l][dim].extend(prim.bounds());
+ continue;
+ }
+
+ for (bin=(size_t)bin0[dim]; bin<(size_t)bin1[dim]; bin++)
+ {
+ const float pos = mapping.pos(bin+1,dim);
+
+ PrimRef left,right;
+ splitPrimitive(rest,(int)dim,pos,left,right);
+ if (unlikely(left.bounds().empty())) l++;
+ bounds[bin][dim].extend(left.bounds());
+ rest = right;
+ }
+ if (unlikely(rest.bounds().empty())) r--;
+ numBegin[l][dim]++;
+ numEnd [r][dim]++;
+ bounds [bin][dim].extend(rest.bounds());
+ }
+ }
+ }
+ }
+
+ /*! bins a range of primitives inside an array */
+ template<typename SplitPrimitive>
+ void bin(const SplitPrimitive& splitPrimitive, const PrimRef* prims, size_t begin, size_t end, const SpatialBinMapping<BINS>& mapping) {
+ bin(splitPrimitive,prims+begin,end-begin,mapping);
+ }
+
+ /*! bins an array of primitives */
+ template<typename PrimitiveSplitterFactory>
+ __forceinline void bin2(const PrimitiveSplitterFactory& splitterFactory, const PrimRef* source, size_t begin, size_t end, const SpatialBinMapping<BINS>& mapping)
+ {
+ for (size_t i=begin; i<end; i++)
+ {
+ const PrimRef &prim = source[i];
+ const vint4 bin0 = mapping.bin(prim.bounds().lower);
+ const vint4 bin1 = mapping.bin(prim.bounds().upper);
+
+ for (size_t dim=0; dim<3; dim++)
+ {
+ if (unlikely(mapping.invalid(dim)))
+ continue;
+
+ size_t bin;
+ size_t l = bin0[dim];
+ size_t r = bin1[dim];
+
+ // same bin optimization
+ if (likely(l == r))
+ {
+ add(dim,l,l,l,prim.bounds());
+ continue;
+ }
+ const size_t bin_start = bin0[dim];
+ const size_t bin_end = bin1[dim];
+ BBox3fa rest = prim.bounds();
+ const auto splitter = splitterFactory(prim);
+ for (bin=bin_start; bin<bin_end; bin++)
+ {
+ const float pos = mapping.pos(bin+1,dim);
+ BBox3fa left,right;
+ splitter(rest,dim,pos,left,right);
+ if (unlikely(left.empty())) l++;
+ extend(dim,bin,left);
+ rest = right;
+ }
+ if (unlikely(rest.empty())) r--;
+ add(dim,l,r,bin,rest);
+ }
+ }
+ }
+
+
+
+ /*! bins an array of primitives */
+ __forceinline void binSubTreeRefs(const PrimRef* source, size_t begin, size_t end, const SpatialBinMapping<BINS>& mapping)
+ {
+ for (size_t i=begin; i<end; i++)
+ {
+ const PrimRef &prim = source[i];
+ const vint4 bin0 = mapping.bin(prim.bounds().lower);
+ const vint4 bin1 = mapping.bin(prim.bounds().upper);
+
+ for (size_t dim=0; dim<3; dim++)
+ {
+ if (unlikely(mapping.invalid(dim)))
+ continue;
+
+ const size_t l = bin0[dim];
+ const size_t r = bin1[dim];
+
+ const unsigned int n = prim.primID();
+
+ // same bin optimization
+ if (likely(l == r))
+ {
+ add(dim,l,l,l,prim.bounds(),n);
+ continue;
+ }
+ const size_t bin_start = bin0[dim];
+ const size_t bin_end = bin1[dim];
+ for (size_t bin=bin_start; bin<bin_end; bin++)
+ add(dim,l,r,bin,prim.bounds(),n);
+ }
+ }
+ }
+
+ /*! merges in other binning information */
+ void merge (const SpatialBinInfo& other)
+ {
+ for (size_t i=0; i<BINS; i++)
+ {
+ numBegin[i] += other.numBegin[i];
+ numEnd [i] += other.numEnd [i];
+ bounds[i][0].extend(other.bounds[i][0]);
+ bounds[i][1].extend(other.bounds[i][1]);
+ bounds[i][2].extend(other.bounds[i][2]);
+ }
+ }
+
+ /*! merges in other binning information */
+ static __forceinline const SpatialBinInfo reduce (const SpatialBinInfo& a, const SpatialBinInfo& b)
+ {
+ SpatialBinInfo c(empty);
+ for (size_t i=0; i<BINS; i++)
+ {
+ c.numBegin[i] += a.numBegin[i]+b.numBegin[i];
+ c.numEnd [i] += a.numEnd [i]+b.numEnd [i];
+ c.bounds[i][0] = embree::merge(a.bounds[i][0],b.bounds[i][0]);
+ c.bounds[i][1] = embree::merge(a.bounds[i][1],b.bounds[i][1]);
+ c.bounds[i][2] = embree::merge(a.bounds[i][2],b.bounds[i][2]);
+ }
+ return c;
+ }
+
+ /*! finds the best split by scanning binning information */
+ SpatialBinSplit<BINS> best(const SpatialBinMapping<BINS>& mapping, const size_t blocks_shift) const
+ {
+ /* sweep from right to left and compute parallel prefix of merged bounds */
+ vfloat4 rAreas[BINS];
+ vuint4 rCounts[BINS];
+ vuint4 count = 0; BBox3fa bx = empty; BBox3fa by = empty; BBox3fa bz = empty;
+ for (size_t i=BINS-1; i>0; i--)
+ {
+ count += numEnd[i];
+ rCounts[i] = count;
+ bx.extend(bounds[i][0]); rAreas[i][0] = halfArea(bx);
+ by.extend(bounds[i][1]); rAreas[i][1] = halfArea(by);
+ bz.extend(bounds[i][2]); rAreas[i][2] = halfArea(bz);
+ rAreas[i][3] = 0.0f;
+ }
+
+ /* sweep from left to right and compute SAH */
+ vuint4 blocks_add = (1 << blocks_shift)-1;
+ vuint4 ii = 1; vfloat4 vbestSAH = pos_inf; vuint4 vbestPos = 0; vuint4 vbestlCount = 0; vuint4 vbestrCount = 0;
+ count = 0; bx = empty; by = empty; bz = empty;
+ for (size_t i=1; i<BINS; i++, ii+=1)
+ {
+ count += numBegin[i-1];
+ bx.extend(bounds[i-1][0]); float Ax = halfArea(bx);
+ by.extend(bounds[i-1][1]); float Ay = halfArea(by);
+ bz.extend(bounds[i-1][2]); float Az = halfArea(bz);
+ const vfloat4 lArea = vfloat4(Ax,Ay,Az,Az);
+ const vfloat4 rArea = rAreas[i];
+ const vuint4 lCount = (count +blocks_add) >> (unsigned int)(blocks_shift);
+ const vuint4 rCount = (rCounts[i]+blocks_add) >> (unsigned int)(blocks_shift);
+ const vfloat4 sah = madd(lArea,vfloat4(lCount),rArea*vfloat4(rCount));
+ // const vfloat4 sah = madd(lArea,vfloat4(vint4(lCount)),rArea*vfloat4(vint4(rCount)));
+ const vbool4 mask = sah < vbestSAH;
+ vbestPos = select(mask,ii ,vbestPos);
+ vbestSAH = select(mask,sah,vbestSAH);
+ vbestlCount = select(mask,count,vbestlCount);
+ vbestrCount = select(mask,rCounts[i],vbestrCount);
+ }
+
+ /* find best dimension */
+ float bestSAH = inf;
+ int bestDim = -1;
+ int bestPos = 0;
+ unsigned int bestlCount = 0;
+ unsigned int bestrCount = 0;
+ for (int dim=0; dim<3; dim++)
+ {
+ /* ignore zero sized dimensions */
+ if (unlikely(mapping.invalid(dim)))
+ continue;
+
+ /* test if this is a better dimension */
+ if (vbestSAH[dim] < bestSAH && vbestPos[dim] != 0) {
+ bestDim = dim;
+ bestPos = vbestPos[dim];
+ bestSAH = vbestSAH[dim];
+ bestlCount = vbestlCount[dim];
+ bestrCount = vbestrCount[dim];
+ }
+ }
+ assert(bestSAH >= 0.0f);
+
+ /* return invalid split if no split found */
+ if (bestDim == -1)
+ return SpatialBinSplit<BINS>(inf,-1,0,mapping);
+
+ /* return best found split */
+ return SpatialBinSplit<BINS>(bestSAH,bestDim,bestPos,bestlCount,bestrCount,1.0f,mapping);
+ }
+
+ private:
+ BBox3fa bounds[BINS][3]; //!< geometry bounds for each bin in each dimension
+ vuint4 numBegin[BINS]; //!< number of primitives starting in bin
+ vuint4 numEnd[BINS]; //!< number of primitives ending in bin
+ };
+ }
+}
+
diff --git a/thirdparty/embree/kernels/builders/heuristic_spatial_array.h b/thirdparty/embree/kernels/builders/heuristic_spatial_array.h
new file mode 100644
index 0000000000..60d235f48d
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/heuristic_spatial_array.h
@@ -0,0 +1,546 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "heuristic_binning.h"
+#include "heuristic_spatial.h"
+
+namespace embree
+{
+ namespace isa
+ {
+#if 0
+#define SPATIAL_ASPLIT_OVERLAP_THRESHOLD 0.2f
+#define SPATIAL_ASPLIT_SAH_THRESHOLD 0.95f
+#define SPATIAL_ASPLIT_AREA_THRESHOLD 0.0f
+#else
+#define SPATIAL_ASPLIT_OVERLAP_THRESHOLD 0.1f
+#define SPATIAL_ASPLIT_SAH_THRESHOLD 0.99f
+#define SPATIAL_ASPLIT_AREA_THRESHOLD 0.000005f
+#endif
+
+ struct PrimInfoExtRange : public CentGeomBBox3fa, public extended_range<size_t>
+ {
+ __forceinline PrimInfoExtRange() {
+ }
+
+ __forceinline PrimInfoExtRange(EmptyTy)
+ : CentGeomBBox3fa(EmptyTy()), extended_range<size_t>(0,0,0) {}
+
+ __forceinline PrimInfoExtRange(size_t begin, size_t end, size_t ext_end, const CentGeomBBox3fa& centGeomBounds)
+ : CentGeomBBox3fa(centGeomBounds), extended_range<size_t>(begin,end,ext_end) {}
+
+ __forceinline float leafSAH() const {
+ return expectedApproxHalfArea(geomBounds)*float(size());
+ }
+
+ __forceinline float leafSAH(size_t block_shift) const {
+ return expectedApproxHalfArea(geomBounds)*float((size()+(size_t(1)<<block_shift)-1) >> block_shift);
+ }
+ };
+
+ template<typename ObjectSplit, typename SpatialSplit>
+ struct Split2
+ {
+ __forceinline Split2 () {}
+
+ __forceinline Split2 (const Split2& other)
+ {
+ spatial = other.spatial;
+ sah = other.sah;
+ if (spatial) spatialSplit() = other.spatialSplit();
+ else objectSplit() = other.objectSplit();
+ }
+
+ __forceinline Split2& operator= (const Split2& other)
+ {
+ spatial = other.spatial;
+ sah = other.sah;
+ if (spatial) spatialSplit() = other.spatialSplit();
+ else objectSplit() = other.objectSplit();
+ return *this;
+ }
+
+ __forceinline ObjectSplit& objectSplit() { return *( ObjectSplit*)data; }
+ __forceinline const ObjectSplit& objectSplit() const { return *(const ObjectSplit*)data; }
+
+ __forceinline SpatialSplit& spatialSplit() { return *( SpatialSplit*)data; }
+ __forceinline const SpatialSplit& spatialSplit() const { return *(const SpatialSplit*)data; }
+
+ __forceinline Split2 (const ObjectSplit& objectSplit, float sah)
+ : spatial(false), sah(sah)
+ {
+ new (data) ObjectSplit(objectSplit);
+ }
+
+ __forceinline Split2 (const SpatialSplit& spatialSplit, float sah)
+ : spatial(true), sah(sah)
+ {
+ new (data) SpatialSplit(spatialSplit);
+ }
+
+ __forceinline float splitSAH() const {
+ return sah;
+ }
+
+ __forceinline bool valid() const {
+ return sah < float(inf);
+ }
+
+ public:
+ __aligned(64) char data[sizeof(ObjectSplit) > sizeof(SpatialSplit) ? sizeof(ObjectSplit) : sizeof(SpatialSplit)];
+ bool spatial;
+ float sah;
+ };
+
+ /*! Performs standard object binning */
+ template<typename PrimitiveSplitterFactory, typename PrimRef, size_t OBJECT_BINS, size_t SPATIAL_BINS>
+ struct HeuristicArraySpatialSAH
+ {
+ typedef BinSplit<OBJECT_BINS> ObjectSplit;
+ typedef BinInfoT<OBJECT_BINS,PrimRef,BBox3fa> ObjectBinner;
+
+ typedef SpatialBinSplit<SPATIAL_BINS> SpatialSplit;
+ typedef SpatialBinInfo<SPATIAL_BINS,PrimRef> SpatialBinner;
+
+ //typedef extended_range<size_t> Set;
+ typedef Split2<ObjectSplit,SpatialSplit> Split;
+
+ static const size_t PARALLEL_THRESHOLD = 3*1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ static const size_t MOVE_STEP_SIZE = 64;
+ static const size_t CREATE_SPLITS_STEP_SIZE = 64;
+
+ __forceinline HeuristicArraySpatialSAH ()
+ : prims0(nullptr) {}
+
+ /*! remember prim array */
+ __forceinline HeuristicArraySpatialSAH (const PrimitiveSplitterFactory& splitterFactory, PrimRef* prims0, const CentGeomBBox3fa& root_info)
+ : prims0(prims0), splitterFactory(splitterFactory), root_info(root_info) {}
+
+
+ /*! compute extended ranges */
+ __noinline void setExtentedRanges(const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset, const size_t lweight, const size_t rweight)
+ {
+ assert(set.ext_range_size() > 0);
+ const float left_factor = (float)lweight / (lweight + rweight);
+ const size_t ext_range_size = set.ext_range_size();
+ const size_t left_ext_range_size = min((size_t)(floorf(left_factor * ext_range_size)),ext_range_size);
+ const size_t right_ext_range_size = ext_range_size - left_ext_range_size;
+ lset.set_ext_range(lset.end() + left_ext_range_size);
+ rset.set_ext_range(rset.end() + right_ext_range_size);
+ }
+
+ /*! move ranges */
+ __noinline void moveExtentedRange(const PrimInfoExtRange& set, const PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t left_ext_range_size = lset.ext_range_size();
+ const size_t right_size = rset.size();
+
+ /* has the left child an extended range? */
+ if (left_ext_range_size > 0)
+ {
+ /* left extended range smaller than right range ? */
+ if (left_ext_range_size < right_size)
+ {
+ /* only move a small part of the beginning of the right range to the end */
+ parallel_for( rset.begin(), rset.begin()+left_ext_range_size, MOVE_STEP_SIZE, [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ prims0[i+right_size] = prims0[i];
+ });
+ }
+ else
+ {
+ /* no overlap, move entire right range to new location, can be made fully parallel */
+ parallel_for( rset.begin(), rset.end(), MOVE_STEP_SIZE, [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ prims0[i+left_ext_range_size] = prims0[i];
+ });
+ }
+ /* update right range */
+ assert(rset.ext_end() + left_ext_range_size == set.ext_end());
+ rset.move_right(left_ext_range_size);
+ }
+ }
+
+ /*! finds the best split */
+ const Split find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ SplitInfo oinfo;
+ const ObjectSplit object_split = object_find(set,logBlockSize,oinfo);
+ const float object_split_sah = object_split.splitSAH();
+
+ if (unlikely(set.has_ext_range()))
+ {
+ const BBox3fa overlap = intersect(oinfo.leftBounds, oinfo.rightBounds);
+
+ /* do only spatial splits if the child bounds overlap */
+ if (safeArea(overlap) >= SPATIAL_ASPLIT_AREA_THRESHOLD*safeArea(root_info.geomBounds) &&
+ safeArea(overlap) >= SPATIAL_ASPLIT_OVERLAP_THRESHOLD*safeArea(set.geomBounds))
+ {
+ const SpatialSplit spatial_split = spatial_find(set, logBlockSize);
+ const float spatial_split_sah = spatial_split.splitSAH();
+
+ /* valid spatial split, better SAH and number of splits do not exceed extended range */
+ if (spatial_split_sah < SPATIAL_ASPLIT_SAH_THRESHOLD*object_split_sah &&
+ spatial_split.left + spatial_split.right - set.size() <= set.ext_range_size())
+ {
+ return Split(spatial_split,spatial_split_sah);
+ }
+ }
+ }
+
+ return Split(object_split,object_split_sah);
+ }
+
+ /*! finds the best object split */
+ __forceinline const ObjectSplit object_find(const PrimInfoExtRange& set, const size_t logBlockSize, SplitInfo &info)
+ {
+ if (set.size() < PARALLEL_THRESHOLD) return sequential_object_find(set,logBlockSize,info);
+ else return parallel_object_find (set,logBlockSize,info);
+ }
+
+ /*! finds the best object split */
+ __noinline const ObjectSplit sequential_object_find(const PrimInfoExtRange& set, const size_t logBlockSize, SplitInfo &info)
+ {
+ ObjectBinner binner(empty);
+ const BinMapping<OBJECT_BINS> mapping(set);
+ binner.bin(prims0,set.begin(),set.end(),mapping);
+ ObjectSplit s = binner.best(mapping,logBlockSize);
+ binner.getSplitInfo(mapping, s, info);
+ return s;
+ }
+
+ /*! finds the best split */
+ __noinline const ObjectSplit parallel_object_find(const PrimInfoExtRange& set, const size_t logBlockSize, SplitInfo &info)
+ {
+ ObjectBinner binner(empty);
+ const BinMapping<OBJECT_BINS> mapping(set);
+ const BinMapping<OBJECT_BINS>& _mapping = mapping; // CLANG 3.4 parser bug workaround
+ binner = parallel_reduce(set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,binner,
+ [&] (const range<size_t>& r) -> ObjectBinner { ObjectBinner binner(empty); binner.bin(prims0+r.begin(),r.size(),_mapping); return binner; },
+ [&] (const ObjectBinner& b0, const ObjectBinner& b1) -> ObjectBinner { ObjectBinner r = b0; r.merge(b1,_mapping.size()); return r; });
+ ObjectSplit s = binner.best(mapping,logBlockSize);
+ binner.getSplitInfo(mapping, s, info);
+ return s;
+ }
+
+ /*! finds the best spatial split */
+ __forceinline const SpatialSplit spatial_find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ if (set.size() < PARALLEL_THRESHOLD) return sequential_spatial_find(set, logBlockSize);
+ else return parallel_spatial_find (set, logBlockSize);
+ }
+
+ /*! finds the best spatial split */
+ __noinline const SpatialSplit sequential_spatial_find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ SpatialBinner binner(empty);
+ const SpatialBinMapping<SPATIAL_BINS> mapping(set);
+ binner.bin2(splitterFactory,prims0,set.begin(),set.end(),mapping);
+ /* todo: best spatial split not exeeding the extended range does not provide any benefit ?*/
+ return binner.best(mapping,logBlockSize); //,set.ext_size());
+ }
+
+ __noinline const SpatialSplit parallel_spatial_find(const PrimInfoExtRange& set, const size_t logBlockSize)
+ {
+ SpatialBinner binner(empty);
+ const SpatialBinMapping<SPATIAL_BINS> mapping(set);
+ const SpatialBinMapping<SPATIAL_BINS>& _mapping = mapping; // CLANG 3.4 parser bug workaround
+ binner = parallel_reduce(set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,binner,
+ [&] (const range<size_t>& r) -> SpatialBinner {
+ SpatialBinner binner(empty);
+ binner.bin2(splitterFactory,prims0,r.begin(),r.end(),_mapping);
+ return binner; },
+ [&] (const SpatialBinner& b0, const SpatialBinner& b1) -> SpatialBinner { return SpatialBinner::reduce(b0,b1); });
+ /* todo: best spatial split not exeeding the extended range does not provide any benefit ?*/
+ return binner.best(mapping,logBlockSize); //,set.ext_size());
+ }
+
+
+ /*! subdivides primitives based on a spatial split */
+ __noinline void create_spatial_splits(PrimInfoExtRange& set, const SpatialSplit& split, const SpatialBinMapping<SPATIAL_BINS> &mapping)
+ {
+ assert(set.has_ext_range());
+ const size_t max_ext_range_size = set.ext_range_size();
+ const size_t ext_range_start = set.end();
+
+ /* atomic counter for number of primref splits */
+ std::atomic<size_t> ext_elements;
+ ext_elements.store(0);
+
+ const float fpos = split.mapping.pos(split.pos,split.dim);
+
+ const unsigned int mask = 0xFFFFFFFF >> RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS;
+
+ parallel_for( set.begin(), set.end(), CREATE_SPLITS_STEP_SIZE, [&](const range<size_t>& r) {
+ for (size_t i=r.begin();i<r.end();i++)
+ {
+ const unsigned int splits = prims0[i].geomID() >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS);
+
+ if (likely(splits <= 1)) continue; /* todo: does this ever happen ? */
+
+ //int bin0 = split.mapping.bin(prims0[i].lower)[split.dim];
+ //int bin1 = split.mapping.bin(prims0[i].upper)[split.dim];
+ //if (unlikely(bin0 < split.pos && bin1 >= split.pos))
+ if (unlikely(prims0[i].lower[split.dim] < fpos && prims0[i].upper[split.dim] > fpos))
+ {
+ assert(splits > 1);
+
+ PrimRef left,right;
+ const auto splitter = splitterFactory(prims0[i]);
+ splitter(prims0[i],split.dim,fpos,left,right);
+
+ // no empty splits
+ if (unlikely(left.bounds().empty() || right.bounds().empty())) continue;
+
+ left.lower.u = (left.lower.u & mask) | ((splits-1) << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
+ right.lower.u = (right.lower.u & mask) | ((splits-1) << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
+
+ const size_t ID = ext_elements.fetch_add(1);
+
+ /* break if the number of subdivided elements are greater than the maximum allowed size */
+ if (unlikely(ID >= max_ext_range_size))
+ break;
+
+ /* only write within the correct bounds */
+ assert(ID < max_ext_range_size);
+ prims0[i] = left;
+ prims0[ext_range_start+ID] = right;
+ }
+ }
+ });
+
+ const size_t numExtElements = min(max_ext_range_size,ext_elements.load());
+ assert(set.end()+numExtElements<=set.ext_end());
+ set._end += numExtElements;
+ }
+
+ /*! array partitioning */
+ void split(const Split& split, const PrimInfoExtRange& set_i, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ PrimInfoExtRange set = set_i;
+
+ /* valid split */
+ if (unlikely(!split.valid())) {
+ deterministic_order(set);
+ return splitFallback(set,lset,rset);
+ }
+
+ std::pair<size_t,size_t> ext_weights(0,0);
+
+ if (unlikely(split.spatial))
+ {
+ create_spatial_splits(set,split.spatialSplit(), split.spatialSplit().mapping);
+
+ /* spatial split */
+ if (likely(set.size() < PARALLEL_THRESHOLD))
+ ext_weights = sequential_spatial_split(split.spatialSplit(),set,lset,rset);
+ else
+ ext_weights = parallel_spatial_split(split.spatialSplit(),set,lset,rset);
+ }
+ else
+ {
+ /* object split */
+ if (likely(set.size() < PARALLEL_THRESHOLD))
+ ext_weights = sequential_object_split(split.objectSplit(),set,lset,rset);
+ else
+ ext_weights = parallel_object_split(split.objectSplit(),set,lset,rset);
+ }
+
+ /* if we have an extended range, set extended child ranges and move right split range */
+ if (unlikely(set.has_ext_range()))
+ {
+ setExtentedRanges(set,lset,rset,ext_weights.first,ext_weights.second);
+ moveExtentedRange(set,lset,rset);
+ }
+ }
+
+ /*! array partitioning */
+ std::pair<size_t,size_t> sequential_object_split(const ObjectSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo local_left(empty);
+ PrimInfo local_right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ const typename ObjectBinner::vint vSplitPos(splitPos);
+ const typename ObjectBinner::vbool vSplitMask(splitDimMask);
+ size_t center = serial_partitioning(prims0,
+ begin,end,local_left,local_right,
+ [&] (const PrimRef& ref) {
+ return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask);
+ },
+ [] (PrimInfo& pinfo,const PrimRef& ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); });
+ const size_t left_weight = local_left.end;
+ const size_t right_weight = local_right.end;
+
+ new (&lset) PrimInfoExtRange(begin,center,center,local_left);
+ new (&rset) PrimInfoExtRange(center,end,end,local_right);
+
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ return std::pair<size_t,size_t>(left_weight,right_weight);
+ }
+
+
+ /*! array partitioning */
+ __noinline std::pair<size_t,size_t> sequential_spatial_split(const SpatialSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo local_left(empty);
+ PrimInfo local_right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ /* init spatial mapping */
+ const SpatialBinMapping<SPATIAL_BINS> &mapping = split.mapping;
+ const vint4 vSplitPos(splitPos);
+ const vbool4 vSplitMask( (int)splitDimMask );
+
+ size_t center = serial_partitioning(prims0,
+ begin,end,local_left,local_right,
+ [&] (const PrimRef& ref) {
+ const Vec3fa c = ref.bounds().center();
+ return any(((vint4)mapping.bin(c) < vSplitPos) & vSplitMask);
+ },
+ [] (PrimInfo& pinfo,const PrimRef& ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); });
+
+ const size_t left_weight = local_left.end;
+ const size_t right_weight = local_right.end;
+
+ new (&lset) PrimInfoExtRange(begin,center,center,local_left);
+ new (&rset) PrimInfoExtRange(center,end,end,local_right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ return std::pair<size_t,size_t>(left_weight,right_weight);
+ }
+
+
+
+ /*! array partitioning */
+ __noinline std::pair<size_t,size_t> parallel_object_split(const ObjectSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo left(empty);
+ PrimInfo right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ const typename ObjectBinner::vint vSplitPos(splitPos);
+ const typename ObjectBinner::vbool vSplitMask(splitDimMask);
+ auto isLeft = [&] (const PrimRef &ref) { return split.mapping.bin_unsafe(ref,vSplitPos,vSplitMask); };
+
+ const size_t center = parallel_partitioning(
+ prims0,begin,end,EmptyTy(),left,right,isLeft,
+ [] (PrimInfo &pinfo,const PrimRef &ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); },
+ [] (PrimInfo &pinfo0,const PrimInfo &pinfo1) { pinfo0.merge(pinfo1); },
+ PARALLEL_PARTITION_BLOCK_SIZE);
+
+ const size_t left_weight = left.end;
+ const size_t right_weight = right.end;
+
+ left.begin = begin; left.end = center;
+ right.begin = center; right.end = end;
+
+ new (&lset) PrimInfoExtRange(begin,center,center,left);
+ new (&rset) PrimInfoExtRange(center,end,end,right);
+
+ assert(area(left.geomBounds) >= 0.0f);
+ assert(area(right.geomBounds) >= 0.0f);
+ return std::pair<size_t,size_t>(left_weight,right_weight);
+ }
+
+ /*! array partitioning */
+ __noinline std::pair<size_t,size_t> parallel_spatial_split(const SpatialSplit& split, const PrimInfoExtRange& set, PrimInfoExtRange& lset, PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ PrimInfo left(empty);
+ PrimInfo right(empty);
+ const unsigned int splitPos = split.pos;
+ const unsigned int splitDim = split.dim;
+ const unsigned int splitDimMask = (unsigned int)1 << splitDim;
+
+ /* init spatial mapping */
+ const SpatialBinMapping<SPATIAL_BINS>& mapping = split.mapping;
+ const vint4 vSplitPos(splitPos);
+ const vbool4 vSplitMask( (int)splitDimMask );
+
+ auto isLeft = [&] (const PrimRef &ref) {
+ const Vec3fa c = ref.bounds().center();
+ return any(((vint4)mapping.bin(c) < vSplitPos) & vSplitMask); };
+
+ const size_t center = parallel_partitioning(
+ prims0,begin,end,EmptyTy(),left,right,isLeft,
+ [] (PrimInfo &pinfo,const PrimRef &ref) { pinfo.add_center2(ref,ref.lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)); },
+ [] (PrimInfo &pinfo0,const PrimInfo &pinfo1) { pinfo0.merge(pinfo1); },
+ PARALLEL_PARTITION_BLOCK_SIZE);
+
+ const size_t left_weight = left.end;
+ const size_t right_weight = right.end;
+
+ left.begin = begin; left.end = center;
+ right.begin = center; right.end = end;
+
+ new (&lset) PrimInfoExtRange(begin,center,center,left);
+ new (&rset) PrimInfoExtRange(center,end,end,right);
+
+ assert(area(left.geomBounds) >= 0.0f);
+ assert(area(right.geomBounds) >= 0.0f);
+ return std::pair<size_t,size_t>(left_weight,right_weight);
+ }
+
+ void deterministic_order(const PrimInfoExtRange& set)
+ {
+ /* required as parallel partition destroys original primitive order */
+ std::sort(&prims0[set.begin()],&prims0[set.end()]);
+ }
+
+ void splitFallback(const PrimInfoExtRange& set,
+ PrimInfoExtRange& lset,
+ PrimInfoExtRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ PrimInfo left(empty);
+ for (size_t i=begin; i<center; i++) {
+ left.add_center2(prims0[i],prims0[i].lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
+ }
+ const size_t lweight = left.end;
+
+ PrimInfo right(empty);
+ for (size_t i=center; i<end; i++) {
+ right.add_center2(prims0[i],prims0[i].lower.u >> (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS));
+ }
+ const size_t rweight = right.end;
+
+ new (&lset) PrimInfoExtRange(begin,center,center,left);
+ new (&rset) PrimInfoExtRange(center,end,end,right);
+
+ /* if we have an extended range */
+ if (set.has_ext_range()) {
+ setExtentedRanges(set,lset,rset,lweight,rweight);
+ moveExtentedRange(set,lset,rset);
+ }
+ }
+
+ private:
+ PrimRef* const prims0;
+ const PrimitiveSplitterFactory& splitterFactory;
+ const CentGeomBBox3fa& root_info;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/heuristic_strand_array.h b/thirdparty/embree/kernels/builders/heuristic_strand_array.h
new file mode 100644
index 0000000000..19c7fcdaa8
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/heuristic_strand_array.h
@@ -0,0 +1,188 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "priminfo.h"
+#include "../../common/algorithms/parallel_reduce.h"
+#include "../../common/algorithms/parallel_partition.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Performs standard object binning */
+ struct HeuristicStrandSplit
+ {
+ typedef range<size_t> Set;
+
+ static const size_t PARALLEL_THRESHOLD = 10000;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 4096;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 64;
+
+ /*! stores all information to perform some split */
+ struct Split
+ {
+ /*! construct an invalid split by default */
+ __forceinline Split()
+ : sah(inf), axis0(zero), axis1(zero) {}
+
+ /*! constructs specified split */
+ __forceinline Split(const float sah, const Vec3fa& axis0, const Vec3fa& axis1)
+ : sah(sah), axis0(axis0), axis1(axis1) {}
+
+ /*! calculates standard surface area heuristic for the split */
+ __forceinline float splitSAH() const { return sah; }
+
+ /*! test if this split is valid */
+ __forceinline bool valid() const { return sah != float(inf); }
+
+ public:
+ float sah; //!< SAH cost of the split
+ Vec3fa axis0, axis1; //!< axis the two strands are aligned into
+ };
+
+ __forceinline HeuristicStrandSplit () // FIXME: required?
+ : scene(nullptr), prims(nullptr) {}
+
+ /*! remember prim array */
+ __forceinline HeuristicStrandSplit (Scene* scene, PrimRef* prims)
+ : scene(scene), prims(prims) {}
+
+ __forceinline const Vec3fa direction(const PrimRef& prim) {
+ return scene->get(prim.geomID())->computeDirection(prim.primID());
+ }
+
+ __forceinline const BBox3fa bounds(const PrimRef& prim) {
+ return scene->get(prim.geomID())->vbounds(prim.primID());
+ }
+
+ __forceinline const BBox3fa bounds(const LinearSpace3fa& space, const PrimRef& prim) {
+ return scene->get(prim.geomID())->vbounds(space,prim.primID());
+ }
+
+ /*! finds the best split */
+ const Split find(const range<size_t>& set, size_t logBlockSize)
+ {
+ Vec3fa axis0(0,0,1);
+ uint64_t bestGeomPrimID = -1;
+
+ /* curve with minimum ID determines first axis */
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ const uint64_t geomprimID = prims[i].ID64();
+ if (geomprimID >= bestGeomPrimID) continue;
+ const Vec3fa axis = direction(prims[i]);
+ if (sqr_length(axis) > 1E-18f) {
+ axis0 = normalize(axis);
+ bestGeomPrimID = geomprimID;
+ }
+ }
+
+ /* find 2nd axis that is most misaligned with first axis and has minimum ID */
+ float bestCos = 1.0f;
+ Vec3fa axis1 = axis0;
+ bestGeomPrimID = -1;
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ const uint64_t geomprimID = prims[i].ID64();
+ Vec3fa axisi = direction(prims[i]);
+ float leni = length(axisi);
+ if (leni == 0.0f) continue;
+ axisi /= leni;
+ float cos = abs(dot(axisi,axis0));
+ if ((cos == bestCos && (geomprimID < bestGeomPrimID)) || cos < bestCos) {
+ bestCos = cos; axis1 = axisi;
+ bestGeomPrimID = geomprimID;
+ }
+ }
+
+ /* partition the two strands */
+ size_t lnum = 0, rnum = 0;
+ BBox3fa lbounds = empty, rbounds = empty;
+ const LinearSpace3fa space0 = frame(axis0).transposed();
+ const LinearSpace3fa space1 = frame(axis1).transposed();
+
+ for (size_t i=set.begin(); i<set.end(); i++)
+ {
+ PrimRef& prim = prims[i];
+ const Vec3fa axisi = normalize(direction(prim));
+ const float cos0 = abs(dot(axisi,axis0));
+ const float cos1 = abs(dot(axisi,axis1));
+
+ if (cos0 > cos1) { lnum++; lbounds.extend(bounds(space0,prim)); }
+ else { rnum++; rbounds.extend(bounds(space1,prim)); }
+ }
+
+ /*! return an invalid split if we do not partition */
+ if (lnum == 0 || rnum == 0)
+ return Split(inf,axis0,axis1);
+
+ /*! calculate sah for the split */
+ const size_t lblocks = (lnum+(1ull<<logBlockSize)-1ull) >> logBlockSize;
+ const size_t rblocks = (rnum+(1ull<<logBlockSize)-1ull) >> logBlockSize;
+ const float sah = madd(float(lblocks),halfArea(lbounds),float(rblocks)*halfArea(rbounds));
+ return Split(sah,axis0,axis1);
+ }
+
+ /*! array partitioning */
+ void split(const Split& split, const PrimInfoRange& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ if (!split.valid()) {
+ deterministic_order(set);
+ return splitFallback(set,lset,rset);
+ }
+
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ CentGeomBBox3fa local_left(empty);
+ CentGeomBBox3fa local_right(empty);
+
+ auto primOnLeftSide = [&] (const PrimRef& prim) -> bool {
+ const Vec3fa axisi = normalize(direction(prim));
+ const float cos0 = abs(dot(axisi,split.axis0));
+ const float cos1 = abs(dot(axisi,split.axis1));
+ return cos0 > cos1;
+ };
+
+ auto mergePrimBounds = [this] (CentGeomBBox3fa& pinfo,const PrimRef& ref) {
+ pinfo.extend(bounds(ref));
+ };
+
+ size_t center = serial_partitioning(prims,begin,end,local_left,local_right,primOnLeftSide,mergePrimBounds);
+
+ new (&lset) PrimInfoRange(begin,center,local_left);
+ new (&rset) PrimInfoRange(center,end,local_right);
+ assert(area(lset.geomBounds) >= 0.0f);
+ assert(area(rset.geomBounds) >= 0.0f);
+ }
+
+ void deterministic_order(const Set& set)
+ {
+ /* required as parallel partition destroys original primitive order */
+ std::sort(&prims[set.begin()],&prims[set.end()]);
+ }
+
+ void splitFallback(const Set& set, PrimInfoRange& lset, PrimInfoRange& rset)
+ {
+ const size_t begin = set.begin();
+ const size_t end = set.end();
+ const size_t center = (begin + end)/2;
+
+ CentGeomBBox3fa left(empty);
+ for (size_t i=begin; i<center; i++)
+ left.extend(bounds(prims[i]));
+ new (&lset) PrimInfoRange(begin,center,left);
+
+ CentGeomBBox3fa right(empty);
+ for (size_t i=center; i<end; i++)
+ right.extend(bounds(prims[i]));
+ new (&rset) PrimInfoRange(center,end,right);
+ }
+
+ private:
+ Scene* const scene;
+ PrimRef* const prims;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/heuristic_timesplit_array.h b/thirdparty/embree/kernels/builders/heuristic_timesplit_array.h
new file mode 100644
index 0000000000..b968e01c90
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/heuristic_timesplit_array.h
@@ -0,0 +1,237 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/primref_mb.h"
+#include "../../common/algorithms/parallel_filter.h"
+
+#define MBLUR_TIME_SPLIT_THRESHOLD 1.25f
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Performs standard object binning */
+ template<typename PrimRefMB, typename RecalculatePrimRef, size_t BINS>
+ struct HeuristicMBlurTemporalSplit
+ {
+ typedef BinSplit<MBLUR_NUM_OBJECT_BINS> Split;
+ typedef mvector<PrimRefMB>* PrimRefVector;
+ typedef typename PrimRefMB::BBox BBox;
+
+ static const size_t PARALLEL_THRESHOLD = 3 * 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ HeuristicMBlurTemporalSplit (MemoryMonitorInterface* device, const RecalculatePrimRef& recalculatePrimRef)
+ : device(device), recalculatePrimRef(recalculatePrimRef) {}
+
+ struct TemporalBinInfo
+ {
+ __forceinline TemporalBinInfo () {
+ }
+
+ __forceinline TemporalBinInfo (EmptyTy)
+ {
+ for (size_t i=0; i<BINS-1; i++)
+ {
+ count0[i] = count1[i] = 0;
+ bounds0[i] = bounds1[i] = empty;
+ }
+ }
+
+ void bin(const PrimRefMB* prims, size_t begin, size_t end, BBox1f time_range, const SetMB& set, const RecalculatePrimRef& recalculatePrimRef)
+ {
+ for (int b=0; b<BINS-1; b++)
+ {
+ const float t = float(b+1)/float(BINS);
+ const float ct = lerp(time_range.lower,time_range.upper,t);
+ const float center_time = set.align_time(ct);
+ if (center_time <= time_range.lower) continue;
+ if (center_time >= time_range.upper) continue;
+ const BBox1f dt0(time_range.lower,center_time);
+ const BBox1f dt1(center_time,time_range.upper);
+
+ /* find linear bounds for both time segments */
+ for (size_t i=begin; i<end; i++)
+ {
+ if (prims[i].time_range_overlap(dt0))
+ {
+ const LBBox3fa bn0 = recalculatePrimRef.linearBounds(prims[i],dt0);
+#if MBLUR_BIN_LBBOX
+ bounds0[b].extend(bn0);
+#else
+ bounds0[b].extend(bn0.interpolate(0.5f));
+#endif
+ count0[b] += prims[i].timeSegmentRange(dt0).size();
+ }
+
+ if (prims[i].time_range_overlap(dt1))
+ {
+ const LBBox3fa bn1 = recalculatePrimRef.linearBounds(prims[i],dt1);
+#if MBLUR_BIN_LBBOX
+ bounds1[b].extend(bn1);
+#else
+ bounds1[b].extend(bn1.interpolate(0.5f));
+#endif
+ count1[b] += prims[i].timeSegmentRange(dt1).size();
+ }
+ }
+ }
+ }
+
+ __forceinline void bin_parallel(const PrimRefMB* prims, size_t begin, size_t end, size_t blockSize, size_t parallelThreshold, BBox1f time_range, const SetMB& set, const RecalculatePrimRef& recalculatePrimRef)
+ {
+ if (likely(end-begin < parallelThreshold)) {
+ bin(prims,begin,end,time_range,set,recalculatePrimRef);
+ }
+ else
+ {
+ auto bin = [&](const range<size_t>& r) -> TemporalBinInfo {
+ TemporalBinInfo binner(empty); binner.bin(prims, r.begin(), r.end(), time_range, set, recalculatePrimRef); return binner;
+ };
+ *this = parallel_reduce(begin,end,blockSize,TemporalBinInfo(empty),bin,merge2);
+ }
+ }
+
+ /*! merges in other binning information */
+ __forceinline void merge (const TemporalBinInfo& other)
+ {
+ for (size_t i=0; i<BINS-1; i++)
+ {
+ count0[i] += other.count0[i];
+ count1[i] += other.count1[i];
+ bounds0[i].extend(other.bounds0[i]);
+ bounds1[i].extend(other.bounds1[i]);
+ }
+ }
+
+ static __forceinline const TemporalBinInfo merge2(const TemporalBinInfo& a, const TemporalBinInfo& b) {
+ TemporalBinInfo r = a; r.merge(b); return r;
+ }
+
+ Split best(int logBlockSize, BBox1f time_range, const SetMB& set)
+ {
+ float bestSAH = inf;
+ float bestPos = 0.0f;
+ for (int b=0; b<BINS-1; b++)
+ {
+ float t = float(b+1)/float(BINS);
+ float ct = lerp(time_range.lower,time_range.upper,t);
+ const float center_time = set.align_time(ct);
+ if (center_time <= time_range.lower) continue;
+ if (center_time >= time_range.upper) continue;
+ const BBox1f dt0(time_range.lower,center_time);
+ const BBox1f dt1(center_time,time_range.upper);
+
+ /* calculate sah */
+ const size_t lCount = (count0[b]+(size_t(1) << logBlockSize)-1) >> int(logBlockSize);
+ const size_t rCount = (count1[b]+(size_t(1) << logBlockSize)-1) >> int(logBlockSize);
+ float sah0 = expectedApproxHalfArea(bounds0[b])*float(lCount)*dt0.size();
+ float sah1 = expectedApproxHalfArea(bounds1[b])*float(rCount)*dt1.size();
+ if (unlikely(lCount == 0)) sah0 = 0.0f; // happens for initial splits when objects not alive over entire shutter time
+ if (unlikely(rCount == 0)) sah1 = 0.0f;
+ const float sah = sah0+sah1;
+ if (sah < bestSAH) {
+ bestSAH = sah;
+ bestPos = center_time;
+ }
+ }
+ return Split(bestSAH*MBLUR_TIME_SPLIT_THRESHOLD,(unsigned)Split::SPLIT_TEMPORAL,0,bestPos);
+ }
+
+ public:
+ size_t count0[BINS-1];
+ size_t count1[BINS-1];
+ BBox bounds0[BINS-1];
+ BBox bounds1[BINS-1];
+ };
+
+ /*! finds the best split */
+ const Split find(const SetMB& set, const size_t logBlockSize)
+ {
+ assert(set.size() > 0);
+ TemporalBinInfo binner(empty);
+ binner.bin_parallel(set.prims->data(),set.begin(),set.end(),PARALLEL_FIND_BLOCK_SIZE,PARALLEL_THRESHOLD,set.time_range,set,recalculatePrimRef);
+ Split tsplit = binner.best((int)logBlockSize,set.time_range,set);
+ if (!tsplit.valid()) tsplit.data = Split::SPLIT_FALLBACK; // use fallback split
+ return tsplit;
+ }
+
+ __forceinline std::unique_ptr<mvector<PrimRefMB>> split(const Split& tsplit, const SetMB& set, SetMB& lset, SetMB& rset)
+ {
+ assert(tsplit.sah != float(inf));
+ assert(tsplit.fpos > set.time_range.lower);
+ assert(tsplit.fpos < set.time_range.upper);
+
+ float center_time = tsplit.fpos;
+ const BBox1f time_range0(set.time_range.lower,center_time);
+ const BBox1f time_range1(center_time,set.time_range.upper);
+ mvector<PrimRefMB>& prims = *set.prims;
+
+ /* calculate primrefs for first time range */
+ std::unique_ptr<mvector<PrimRefMB>> new_vector(new mvector<PrimRefMB>(device, set.size()));
+ PrimRefVector lprims = new_vector.get();
+
+ auto reduction_func0 = [&] (const range<size_t>& r) {
+ PrimInfoMB pinfo = empty;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ if (likely(prims[i].time_range_overlap(time_range0)))
+ {
+ const PrimRefMB& prim = recalculatePrimRef(prims[i],time_range0);
+ (*lprims)[i-set.begin()] = prim;
+ pinfo.add_primref(prim);
+ }
+ else
+ {
+ (*lprims)[i-set.begin()] = prims[i];
+ }
+ }
+ return pinfo;
+ };
+ PrimInfoMB linfo = parallel_reduce(set.object_range,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD,PrimInfoMB(empty),reduction_func0,PrimInfoMB::merge2);
+
+ /* primrefs for first time range are in lprims[0 .. set.size()) */
+ /* some primitives may need to be filtered out */
+ if (linfo.size() != set.size())
+ linfo.object_range._end = parallel_filter(lprims->data(), size_t(0), set.size(), size_t(1024),
+ [&](const PrimRefMB& prim) { return prim.time_range_overlap(time_range0); });
+
+ lset = SetMB(linfo,lprims,time_range0);
+
+ /* calculate primrefs for second time range */
+ auto reduction_func1 = [&] (const range<size_t>& r) {
+ PrimInfoMB pinfo = empty;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ if (likely(prims[i].time_range_overlap(time_range1)))
+ {
+ const PrimRefMB& prim = recalculatePrimRef(prims[i],time_range1);
+ prims[i] = prim;
+ pinfo.add_primref(prim);
+ }
+ }
+ return pinfo;
+ };
+ PrimInfoMB rinfo = parallel_reduce(set.object_range,PARALLEL_PARTITION_BLOCK_SIZE,PARALLEL_THRESHOLD,PrimInfoMB(empty),reduction_func1,PrimInfoMB::merge2);
+ rinfo.object_range = range<size_t>(set.begin(), set.begin() + rinfo.size());
+
+ /* primrefs for second time range are in prims[set.begin() .. set.end()) */
+ /* some primitives may need to be filtered out */
+ if (rinfo.size() != set.size())
+ rinfo.object_range._end = parallel_filter(prims.data(), set.begin(), set.end(), size_t(1024),
+ [&](const PrimRefMB& prim) { return prim.time_range_overlap(time_range1); });
+
+ rset = SetMB(rinfo,&prims,time_range1);
+
+ return new_vector;
+ }
+
+ private:
+ MemoryMonitorInterface* device; // device to report memory usage to
+ const RecalculatePrimRef recalculatePrimRef;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/priminfo.h b/thirdparty/embree/kernels/builders/priminfo.h
new file mode 100644
index 0000000000..fee515247a
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/priminfo.h
@@ -0,0 +1,362 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/primref.h"
+#include "../common/primref_mb.h"
+
+namespace embree
+{
+ // FIXME: maybe there's a better place for this util fct
+ __forceinline float areaProjectedTriangle(const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2)
+ {
+ const Vec3fa e0 = v1-v0;
+ const Vec3fa e1 = v2-v0;
+ const Vec3fa d = cross(e0,e1);
+ return fabs(d.x) + fabs(d.y) + fabs(d.z);
+ }
+
+ //namespace isa
+ //{
+ template<typename BBox>
+ class CentGeom
+ {
+ public:
+ __forceinline CentGeom () {}
+
+ __forceinline CentGeom (EmptyTy)
+ : geomBounds(empty), centBounds(empty) {}
+
+ __forceinline CentGeom (const BBox& geomBounds, const BBox3fa& centBounds)
+ : geomBounds(geomBounds), centBounds(centBounds) {}
+
+ template<typename PrimRef>
+ __forceinline void extend_primref(const PrimRef& prim)
+ {
+ BBox bounds; Vec3fa center;
+ prim.binBoundsAndCenter(bounds,center);
+ geomBounds.extend(bounds);
+ centBounds.extend(center);
+ }
+
+ template<typename PrimRef>
+ __forceinline void extend_center2(const PrimRef& prim)
+ {
+ BBox3fa bounds = prim.bounds();
+ geomBounds.extend(bounds);
+ centBounds.extend(bounds.center2());
+ }
+
+ __forceinline void extend(const BBox& geomBounds_) {
+ geomBounds.extend(geomBounds_);
+ centBounds.extend(center2(geomBounds_));
+ }
+
+ __forceinline void merge(const CentGeom& other)
+ {
+ geomBounds.extend(other.geomBounds);
+ centBounds.extend(other.centBounds);
+ }
+
+ static __forceinline const CentGeom merge2(const CentGeom& a, const CentGeom& b) {
+ CentGeom r = a; r.merge(b); return r;
+ }
+
+ public:
+ BBox geomBounds; //!< geometry bounds of primitives
+ BBox3fa centBounds; //!< centroid bounds of primitives
+ };
+
+ typedef CentGeom<BBox3fa> CentGeomBBox3fa;
+
+ /*! stores bounding information for a set of primitives */
+ template<typename BBox>
+ class PrimInfoT : public CentGeom<BBox>
+ {
+ public:
+ using CentGeom<BBox>::geomBounds;
+ using CentGeom<BBox>::centBounds;
+
+ __forceinline PrimInfoT () {}
+
+ __forceinline PrimInfoT (EmptyTy)
+ : CentGeom<BBox>(empty), begin(0), end(0) {}
+
+ __forceinline PrimInfoT (size_t begin, size_t end, const CentGeomBBox3fa& centGeomBounds)
+ : CentGeom<BBox>(centGeomBounds), begin(begin), end(end) {}
+
+ template<typename PrimRef>
+ __forceinline void add_primref(const PrimRef& prim)
+ {
+ CentGeom<BBox>::extend_primref(prim);
+ end++;
+ }
+
+ template<typename PrimRef>
+ __forceinline void add_center2(const PrimRef& prim) {
+ CentGeom<BBox>::extend_center2(prim);
+ end++;
+ }
+
+ template<typename PrimRef>
+ __forceinline void add_center2(const PrimRef& prim, const size_t i) {
+ CentGeom<BBox>::extend_center2(prim);
+ end+=i;
+ }
+
+ /*__forceinline void add(const BBox& geomBounds_) {
+ CentGeom<BBox>::extend(geomBounds_);
+ end++;
+ }
+
+ __forceinline void add(const BBox& geomBounds_, const size_t i) {
+ CentGeom<BBox>::extend(geomBounds_);
+ end+=i;
+ }*/
+
+ __forceinline void merge(const PrimInfoT& other)
+ {
+ CentGeom<BBox>::merge(other);
+ begin += other.begin;
+ end += other.end;
+ }
+
+ static __forceinline const PrimInfoT merge(const PrimInfoT& a, const PrimInfoT& b) {
+ PrimInfoT r = a; r.merge(b); return r;
+ }
+
+ /*! returns the number of primitives */
+ __forceinline size_t size() const {
+ return end-begin;
+ }
+
+ __forceinline float halfArea() {
+ return expectedApproxHalfArea(geomBounds);
+ }
+
+ __forceinline float leafSAH() const {
+ return expectedApproxHalfArea(geomBounds)*float(size());
+ //return halfArea(geomBounds)*blocks(num);
+ }
+
+ __forceinline float leafSAH(size_t block_shift) const {
+ return expectedApproxHalfArea(geomBounds)*float((size()+(size_t(1)<<block_shift)-1) >> block_shift);
+ //return halfArea(geomBounds)*float((num+3) >> 2);
+ //return halfArea(geomBounds)*blocks(num);
+ }
+
+ /*! stream output */
+ friend embree_ostream operator<<(embree_ostream cout, const PrimInfoT& pinfo) {
+ return cout << "PrimInfo { begin = " << pinfo.begin << ", end = " << pinfo.end << ", geomBounds = " << pinfo.geomBounds << ", centBounds = " << pinfo.centBounds << "}";
+ }
+
+ public:
+ size_t begin,end; //!< number of primitives
+ };
+
+ typedef PrimInfoT<BBox3fa> PrimInfo;
+ //typedef PrimInfoT<LBBox3fa> PrimInfoMB;
+
+ /*! stores bounding information for a set of primitives */
+ template<typename BBox>
+ class PrimInfoMBT : public CentGeom<BBox>
+ {
+ public:
+ using CentGeom<BBox>::geomBounds;
+ using CentGeom<BBox>::centBounds;
+
+ __forceinline PrimInfoMBT () {
+ }
+
+ __forceinline PrimInfoMBT (EmptyTy)
+ : CentGeom<BBox>(empty), object_range(0,0), num_time_segments(0), max_num_time_segments(0), max_time_range(0.0f,1.0f), time_range(1.0f,0.0f) {}
+
+ __forceinline PrimInfoMBT (size_t begin, size_t end)
+ : CentGeom<BBox>(empty), object_range(begin,end), num_time_segments(0), max_num_time_segments(0), max_time_range(0.0f,1.0f), time_range(1.0f,0.0f) {}
+
+ template<typename PrimRef>
+ __forceinline void add_primref(const PrimRef& prim)
+ {
+ CentGeom<BBox>::extend_primref(prim);
+ time_range.extend(prim.time_range);
+ object_range._end++;
+ num_time_segments += prim.size();
+ if (max_num_time_segments < prim.totalTimeSegments()) {
+ max_num_time_segments = prim.totalTimeSegments();
+ max_time_range = prim.time_range;
+ }
+ }
+
+ __forceinline void merge(const PrimInfoMBT& other)
+ {
+ CentGeom<BBox>::merge(other);
+ time_range.extend(other.time_range);
+ object_range._begin += other.object_range.begin();
+ object_range._end += other.object_range.end();
+ num_time_segments += other.num_time_segments;
+ if (max_num_time_segments < other.max_num_time_segments) {
+ max_num_time_segments = other.max_num_time_segments;
+ max_time_range = other.max_time_range;
+ }
+ }
+
+ static __forceinline const PrimInfoMBT merge2(const PrimInfoMBT& a, const PrimInfoMBT& b) {
+ PrimInfoMBT r = a; r.merge(b); return r;
+ }
+
+ __forceinline size_t begin() const {
+ return object_range.begin();
+ }
+
+ __forceinline size_t end() const {
+ return object_range.end();
+ }
+
+ /*! returns the number of primitives */
+ __forceinline size_t size() const {
+ return object_range.size();
+ }
+
+ __forceinline float halfArea() const {
+ return time_range.size()*expectedApproxHalfArea(geomBounds);
+ }
+
+ __forceinline float leafSAH() const {
+ return time_range.size()*expectedApproxHalfArea(geomBounds)*float(num_time_segments);
+ }
+
+ __forceinline float leafSAH(size_t block_shift) const {
+ return time_range.size()*expectedApproxHalfArea(geomBounds)*float((num_time_segments+(size_t(1)<<block_shift)-1) >> block_shift);
+ }
+
+ __forceinline float align_time(float ct) const
+ {
+ //return roundf(ct * float(numTimeSegments)) / float(numTimeSegments);
+ float t0 = (ct-max_time_range.lower)/max_time_range.size();
+ float t1 = roundf(t0 * float(max_num_time_segments)) / float(max_num_time_segments);
+ return t1*max_time_range.size()+max_time_range.lower;
+ }
+
+ /*! stream output */
+ friend embree_ostream operator<<(embree_ostream cout, const PrimInfoMBT& pinfo)
+ {
+ return cout << "PrimInfo { " <<
+ "object_range = " << pinfo.object_range <<
+ ", time_range = " << pinfo.time_range <<
+ ", time_segments = " << pinfo.num_time_segments <<
+ ", geomBounds = " << pinfo.geomBounds <<
+ ", centBounds = " << pinfo.centBounds <<
+ "}";
+ }
+
+ public:
+ range<size_t> object_range; //!< primitive range
+ size_t num_time_segments; //!< total number of time segments of all added primrefs
+ size_t max_num_time_segments; //!< maximum number of time segments of a primitive
+ BBox1f max_time_range; //!< time range of primitive with max_num_time_segments
+ BBox1f time_range; //!< merged time range of primitives when merging prims, or additionally clipped with build time range when used in SetMB
+ };
+
+ typedef PrimInfoMBT<typename PrimRefMB::BBox> PrimInfoMB;
+
+ struct SetMB : public PrimInfoMB
+ {
+ static const size_t PARALLEL_THRESHOLD = 3 * 1024;
+ static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024;
+ static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128;
+
+ typedef mvector<PrimRefMB>* PrimRefVector;
+
+ __forceinline SetMB() {}
+
+ __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims)
+ : PrimInfoMB(pinfo_i), prims(prims) {}
+
+ __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims, range<size_t> object_range_in, BBox1f time_range_in)
+ : PrimInfoMB(pinfo_i), prims(prims)
+ {
+ object_range = object_range_in;
+ time_range = intersect(time_range,time_range_in);
+ }
+
+ __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims, BBox1f time_range_in)
+ : PrimInfoMB(pinfo_i), prims(prims)
+ {
+ time_range = intersect(time_range,time_range_in);
+ }
+
+ void deterministic_order() const
+ {
+ /* required as parallel partition destroys original primitive order */
+ PrimRefMB* prim = prims->data();
+ std::sort(&prim[object_range.begin()],&prim[object_range.end()]);
+ }
+
+ template<typename RecalculatePrimRef>
+ __forceinline LBBox3fa linearBounds(const RecalculatePrimRef& recalculatePrimRef) const
+ {
+ auto reduce = [&](const range<size_t>& r) -> LBBox3fa
+ {
+ LBBox3fa cbounds(empty);
+ for (size_t j = r.begin(); j < r.end(); j++)
+ {
+ PrimRefMB& ref = (*prims)[j];
+ const LBBox3fa bn = recalculatePrimRef.linearBounds(ref, time_range);
+ cbounds.extend(bn);
+ };
+ return cbounds;
+ };
+
+ return parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD, LBBox3fa(empty),
+ reduce,
+ [&](const LBBox3fa& b0, const LBBox3fa& b1) -> LBBox3fa { return embree::merge(b0, b1); });
+ }
+
+ template<typename RecalculatePrimRef>
+ __forceinline LBBox3fa linearBounds(const RecalculatePrimRef& recalculatePrimRef, const LinearSpace3fa& space) const
+ {
+ auto reduce = [&](const range<size_t>& r) -> LBBox3fa
+ {
+ LBBox3fa cbounds(empty);
+ for (size_t j = r.begin(); j < r.end(); j++)
+ {
+ PrimRefMB& ref = (*prims)[j];
+ const LBBox3fa bn = recalculatePrimRef.linearBounds(ref, time_range, space);
+ cbounds.extend(bn);
+ };
+ return cbounds;
+ };
+
+ return parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD, LBBox3fa(empty),
+ reduce,
+ [&](const LBBox3fa& b0, const LBBox3fa& b1) -> LBBox3fa { return embree::merge(b0, b1); });
+ }
+
+ template<typename RecalculatePrimRef>
+ const SetMB primInfo(const RecalculatePrimRef& recalculatePrimRef, const LinearSpace3fa& space) const
+ {
+ auto computePrimInfo = [&](const range<size_t>& r) -> PrimInfoMB
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ PrimRefMB& ref = (*prims)[j];
+ PrimRefMB ref1 = recalculatePrimRef(ref,time_range,space);
+ pinfo.add_primref(ref1);
+ };
+ return pinfo;
+ };
+
+ const PrimInfoMB pinfo = parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD,
+ PrimInfoMB(empty), computePrimInfo, PrimInfoMB::merge2);
+
+ return SetMB(pinfo,prims,object_range,time_range);
+ }
+
+ public:
+ PrimRefVector prims;
+ };
+//}
+}
diff --git a/thirdparty/embree/kernels/builders/primrefgen.cpp b/thirdparty/embree/kernels/builders/primrefgen.cpp
new file mode 100644
index 0000000000..d279dc4993
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/primrefgen.cpp
@@ -0,0 +1,312 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "primrefgen.h"
+#include "primrefgen_presplit.h"
+
+#include "../../common/algorithms/parallel_for_for.h"
+#include "../../common/algorithms/parallel_for_for_prefix_sum.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ PrimInfo createPrimRefArray(Geometry* geometry, unsigned int geomID, const size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor)
+ {
+ ParallelPrefixSumState<PrimInfo> pstate;
+
+ /* first try */
+ progressMonitor(0);
+ PrimInfo pinfo = parallel_prefix_sum( pstate, size_t(0), geometry->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo {
+ return geometry->createPrimRefArray(prims,r,r.begin(),geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != numPrimRefs)
+ {
+ progressMonitor(0);
+ pinfo = parallel_prefix_sum( pstate, size_t(0), geometry->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo {
+ return geometry->createPrimRefArray(prims,r,base.size(),geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArray(Scene* scene, Geometry::GTypeMask types, bool mblur, const size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor)
+ {
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator2 iter(scene,types,mblur);
+
+ /* first try */
+ progressMonitor(0);
+ pstate.init(iter,size_t(1024));
+ PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo {
+ return mesh->createPrimRefArray(prims,r,k,(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != numPrimRefs)
+ {
+ progressMonitor(0);
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo {
+ return mesh->createPrimRefArray(prims,r,base.size(),(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMBlur(Scene* scene, Geometry::GTypeMask types, const size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor, size_t itime)
+ {
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator2 iter(scene,types,true);
+
+ /* first try */
+ progressMonitor(0);
+ pstate.init(iter,size_t(1024));
+ PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo {
+ return mesh->createPrimRefArrayMB(prims,itime,r,k,(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != numPrimRefs)
+ {
+ progressMonitor(0);
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo {
+ return mesh->createPrimRefArrayMB(prims,itime,r,base.size(),(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefArrayMSMBlur(Scene* scene, Geometry::GTypeMask types, const size_t numPrimRefs, mvector<PrimRefMB>& prims, BuildProgressMonitor& progressMonitor, BBox1f t0t1)
+ {
+ ParallelForForPrefixSumState<PrimInfoMB> pstate;
+ Scene::Iterator2 iter(scene,types,true);
+
+ /* first try */
+ progressMonitor(0);
+ pstate.init(iter,size_t(1024));
+ PrimInfoMB pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfoMB(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfoMB {
+ return mesh->createPrimRefMBArray(prims,t0t1,r,k,(unsigned)geomID);
+ }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != numPrimRefs)
+ {
+ progressMonitor(0);
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfoMB(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfoMB& base) -> PrimInfoMB {
+ return mesh->createPrimRefMBArray(prims,t0t1,r,base.size(),(unsigned)geomID);
+ }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); });
+ }
+
+ /* the BVH starts with that time range, even though primitives might have smaller/larger time range */
+ pinfo.time_range = t0t1;
+ return pinfo;
+ }
+
+ template<typename Mesh>
+ size_t createMortonCodeArray(Mesh* mesh, mvector<BVHBuilderMorton::BuildPrim>& morton, BuildProgressMonitor& progressMonitor)
+ {
+ size_t numPrimitives = morton.size();
+
+ /* compute scene bounds */
+ std::pair<size_t,BBox3fa> cb_empty(0,empty);
+ auto cb = parallel_reduce
+ ( size_t(0), numPrimitives, size_t(1024), cb_empty, [&](const range<size_t>& r) -> std::pair<size_t,BBox3fa>
+ {
+ size_t num = 0;
+ BBox3fa bounds = empty;
+
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa prim_bounds = empty;
+ if (unlikely(!mesh->buildBounds(j,&prim_bounds))) continue;
+ bounds.extend(center2(prim_bounds));
+ num++;
+ }
+ return std::make_pair(num,bounds);
+ }, [] (const std::pair<size_t,BBox3fa>& a, const std::pair<size_t,BBox3fa>& b) {
+ return std::make_pair(a.first + b.first,merge(a.second,b.second));
+ });
+
+
+ size_t numPrimitivesGen = cb.first;
+ const BBox3fa centBounds = cb.second;
+
+ /* compute morton codes */
+ if (likely(numPrimitivesGen == numPrimitives))
+ {
+ /* fast path if all primitives were valid */
+ BVHBuilderMorton::MortonCodeMapping mapping(centBounds);
+ parallel_for( size_t(0), numPrimitives, size_t(1024), [&](const range<size_t>& r) -> void {
+ BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton.data()[r.begin()]);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ generator(mesh->bounds(j),unsigned(j));
+ });
+ }
+ else
+ {
+ /* slow path, fallback in case some primitives were invalid */
+ ParallelPrefixSumState<size_t> pstate;
+ BVHBuilderMorton::MortonCodeMapping mapping(centBounds);
+ parallel_prefix_sum( pstate, size_t(0), numPrimitives, size_t(1024), size_t(0), [&](const range<size_t>& r, const size_t base) -> size_t {
+ size_t num = 0;
+ BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton.data()[r.begin()]);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (unlikely(!mesh->buildBounds(j,&bounds))) continue;
+ generator(bounds,unsigned(j));
+ num++;
+ }
+ return num;
+ }, std::plus<size_t>());
+
+ parallel_prefix_sum( pstate, size_t(0), numPrimitives, size_t(1024), size_t(0), [&](const range<size_t>& r, const size_t base) -> size_t {
+ size_t num = 0;
+ BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton.data()[base]);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!mesh->buildBounds(j,&bounds)) continue;
+ generator(bounds,unsigned(j));
+ num++;
+ }
+ return num;
+ }, std::plus<size_t>());
+ }
+ return numPrimitivesGen;
+ }
+
+ // ====================================================================================================
+ // ====================================================================================================
+ // ====================================================================================================
+
+ // special variants for grid meshes
+
+// -- GODOT start --
+#if defined(EMBREE_GEOMETRY_GRID)
+// -- GODOT end --
+ PrimInfo createPrimRefArrayGrids(Scene* scene, mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids)
+ {
+ PrimInfo pinfo(empty);
+ size_t numPrimitives = 0;
+
+ /* first run to get #primitives */
+
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator<GridMesh,false> iter(scene);
+
+ pstate.init(iter,size_t(1024));
+
+ /* iterate over all meshes in the scene */
+ pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j)) continue;
+ BBox3fa bounds = empty;
+ const PrimRef prim(bounds,(unsigned)geomID,(unsigned)j);
+ if (!mesh->valid(j)) continue;
+ pinfo.add_center2(prim,mesh->getNumSubGrids(j));
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ numPrimitives = pinfo.size();
+
+ /* resize arrays */
+ sgrids.resize(numPrimitives);
+ prims.resize(numPrimitives);
+
+ /* second run to fill primrefs and SubGridBuildData arrays */
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo {
+ k = base.size();
+ size_t p_index = k;
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j)) continue;
+ const GridMesh::Grid &g = mesh->grid(j);
+ for (unsigned int y=0; y<g.resY-1u; y+=2)
+ for (unsigned int x=0; x<g.resX-1u; x+=2)
+ {
+ BBox3fa bounds = empty;
+ if (!mesh->buildBounds(g,x,y,bounds)) continue; // get bounds of subgrid
+ const PrimRef prim(bounds,(unsigned)geomID,(unsigned)p_index);
+ pinfo.add_center2(prim);
+ sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j));
+ prims[p_index++] = prim;
+ }
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ assert(pinfo.size() == numPrimitives);
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayGrids(GridMesh* mesh, mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids)
+ {
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max ();
+
+ PrimInfo pinfo(empty);
+ size_t numPrimitives = 0;
+
+ ParallelPrefixSumState<PrimInfo> pstate;
+ /* iterate over all grids in a single mesh */
+ pinfo = parallel_prefix_sum( pstate, size_t(0), mesh->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j)) continue;
+ BBox3fa bounds = empty;
+ const PrimRef prim(bounds,geomID_,unsigned(j));
+ pinfo.add_center2(prim,mesh->getNumSubGrids(j));
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ numPrimitives = pinfo.size();
+ /* resize arrays */
+ sgrids.resize(numPrimitives);
+ prims.resize(numPrimitives);
+
+ /* second run to fill primrefs and SubGridBuildData arrays */
+ pinfo = parallel_prefix_sum( pstate, size_t(0), mesh->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo
+ {
+
+ size_t p_index = base.size();
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j)) continue;
+ const GridMesh::Grid &g = mesh->grid(j);
+ for (unsigned int y=0; y<g.resY-1u; y+=2)
+ for (unsigned int x=0; x<g.resX-1u; x+=2)
+ {
+ BBox3fa bounds = empty;
+ if (!mesh->buildBounds(g,x,y,bounds)) continue; // get bounds of subgrid
+ const PrimRef prim(bounds,geomID_,unsigned(p_index));
+ pinfo.add_center2(prim);
+ sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j));
+ prims[p_index++] = prim;
+ }
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ return pinfo;
+ }
+// -- GODOT start --
+#endif
+// -- GODOT end --
+
+ // ====================================================================================================
+ // ====================================================================================================
+ // ====================================================================================================
+
+ IF_ENABLED_TRIS (template size_t createMortonCodeArray<TriangleMesh>(TriangleMesh* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor));
+ IF_ENABLED_QUADS(template size_t createMortonCodeArray<QuadMesh>(QuadMesh* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor));
+ IF_ENABLED_USER (template size_t createMortonCodeArray<UserGeometry>(UserGeometry* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor));
+ IF_ENABLED_INSTANCE (template size_t createMortonCodeArray<Instance>(Instance* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor));
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/primrefgen.h b/thirdparty/embree/kernels/builders/primrefgen.h
new file mode 100644
index 0000000000..c09a848ba3
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/primrefgen.h
@@ -0,0 +1,34 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/scene.h"
+#include "../common/primref.h"
+#include "../common/primref_mb.h"
+#include "priminfo.h"
+#include "bvh_builder_morton.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ PrimInfo createPrimRefArray(Geometry* geometry, unsigned int geomID, size_t numPrimitives, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor);
+
+ PrimInfo createPrimRefArray(Scene* scene, Geometry::GTypeMask types, bool mblur, size_t numPrimitives, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor);
+
+ PrimInfo createPrimRefArrayMBlur(Scene* scene, Geometry::GTypeMask types, size_t numPrimitives, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor, size_t itime = 0);
+
+ PrimInfoMB createPrimRefArrayMSMBlur(Scene* scene, Geometry::GTypeMask types, size_t numPrimitives, mvector<PrimRefMB>& prims, BuildProgressMonitor& progressMonitor, BBox1f t0t1 = BBox1f(0.0f,1.0f));
+
+ template<typename Mesh>
+ size_t createMortonCodeArray(Mesh* mesh, mvector<BVHBuilderMorton::BuildPrim>& morton, BuildProgressMonitor& progressMonitor);
+
+ /* special variants for grids */
+ PrimInfo createPrimRefArrayGrids(Scene* scene, mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids);
+
+ PrimInfo createPrimRefArrayGrids(GridMesh* mesh, mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids);
+
+ }
+}
+
diff --git a/thirdparty/embree/kernels/builders/primrefgen_presplit.h b/thirdparty/embree/kernels/builders/primrefgen_presplit.h
new file mode 100644
index 0000000000..8cd251ddd2
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/primrefgen_presplit.h
@@ -0,0 +1,371 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../builders/primrefgen.h"
+#include "../builders/heuristic_spatial.h"
+#include "../builders/splitter.h"
+
+#include "../../common/algorithms/parallel_for_for.h"
+#include "../../common/algorithms/parallel_for_for_prefix_sum.h"
+
+#define DBG_PRESPLIT(x)
+#define CHECK_PRESPLIT(x)
+
+#define GRID_SIZE 1024
+#define MAX_PRESPLITS_PER_PRIMITIVE_LOG 5
+#define MAX_PRESPLITS_PER_PRIMITIVE (1<<MAX_PRESPLITS_PER_PRIMITIVE_LOG)
+#define PRIORITY_CUTOFF_THRESHOLD 1.0f
+#define PRIORITY_SPLIT_POS_WEIGHT 1.5f
+
+namespace embree
+{
+ namespace isa
+ {
+
+ struct PresplitItem
+ {
+ union {
+ float priority;
+ unsigned int data;
+ };
+ unsigned int index;
+
+ __forceinline operator unsigned() const
+ {
+ return reinterpret_cast<const unsigned&>(priority);
+ }
+ __forceinline bool operator < (const PresplitItem& item) const
+ {
+ return (priority < item.priority);
+ }
+
+ template<typename Mesh>
+ __forceinline static float compute_priority(const PrimRef &ref, Scene *scene, const Vec2i &mc)
+ {
+ const unsigned int geomID = ref.geomID();
+ const unsigned int primID = ref.primID();
+ const float area_aabb = area(ref.bounds());
+ const float area_prim = ((Mesh*)scene->get(geomID))->projectedPrimitiveArea(primID);
+ const unsigned int diff = 31 - lzcnt(mc.x^mc.y);
+ assert(area_prim <= area_aabb);
+ //const float priority = powf((area_aabb - area_prim) * powf(PRIORITY_SPLIT_POS_WEIGHT,(float)diff),1.0f/4.0f);
+ const float priority = sqrtf(sqrtf( (area_aabb - area_prim) * powf(PRIORITY_SPLIT_POS_WEIGHT,(float)diff) ));
+ assert(priority >= 0.0f && priority < FLT_LARGE);
+ return priority;
+ }
+
+
+ };
+
+ inline std::ostream &operator<<(std::ostream &cout, const PresplitItem& item) {
+ return cout << "index " << item.index << " priority " << item.priority;
+ };
+
+ template<typename SplitterFactory>
+ void splitPrimitive(SplitterFactory &Splitter,
+ const PrimRef &prim,
+ const unsigned int geomID,
+ const unsigned int primID,
+ const unsigned int split_level,
+ const Vec3fa &grid_base,
+ const float grid_scale,
+ const float grid_extend,
+ PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE],
+ unsigned int& numSubPrims)
+ {
+ assert(split_level <= MAX_PRESPLITS_PER_PRIMITIVE_LOG);
+ if (split_level == 0)
+ {
+ assert(numSubPrims < MAX_PRESPLITS_PER_PRIMITIVE);
+ subPrims[numSubPrims++] = prim;
+ }
+ else
+ {
+ const Vec3fa lower = prim.lower;
+ const Vec3fa upper = prim.upper;
+ const Vec3fa glower = (lower-grid_base)*Vec3fa(grid_scale)+Vec3fa(0.2f);
+ const Vec3fa gupper = (upper-grid_base)*Vec3fa(grid_scale)-Vec3fa(0.2f);
+ Vec3ia ilower(floor(glower));
+ Vec3ia iupper(floor(gupper));
+
+ /* this ignores dimensions that are empty */
+ iupper = (Vec3ia)(select(vint4(glower) >= vint4(gupper),vint4(ilower),vint4(iupper)));
+
+ /* compute a morton code for the lower and upper grid coordinates. */
+ const unsigned int lower_code = bitInterleave(ilower.x,ilower.y,ilower.z);
+ const unsigned int upper_code = bitInterleave(iupper.x,iupper.y,iupper.z);
+
+ /* if all bits are equal then we cannot split */
+ if(unlikely(lower_code == upper_code))
+ {
+ assert(numSubPrims < MAX_PRESPLITS_PER_PRIMITIVE);
+ subPrims[numSubPrims++] = prim;
+ return;
+ }
+
+ /* compute octree level and dimension to perform the split in */
+ const unsigned int diff = 31 - lzcnt(lower_code^upper_code);
+ const unsigned int level = diff / 3;
+ const unsigned int dim = diff % 3;
+
+ /* now we compute the grid position of the split */
+ const unsigned int isplit = iupper[dim] & ~((1<<level)-1);
+
+ /* compute world space position of split */
+ const float inv_grid_size = 1.0f / GRID_SIZE;
+ const float fsplit = grid_base[dim] + isplit * inv_grid_size * grid_extend;
+
+ assert(prim.lower[dim] <= fsplit &&
+ prim.upper[dim] >= fsplit);
+
+ /* split primitive */
+ const auto splitter = Splitter(prim);
+ BBox3fa left,right;
+ splitter(prim.bounds(),dim,fsplit,left,right);
+ assert(!left.empty());
+ assert(!right.empty());
+
+
+ splitPrimitive(Splitter,PrimRef(left ,geomID,primID),geomID,primID,split_level-1,grid_base,grid_scale,grid_extend,subPrims,numSubPrims);
+ splitPrimitive(Splitter,PrimRef(right,geomID,primID),geomID,primID,split_level-1,grid_base,grid_scale,grid_extend,subPrims,numSubPrims);
+ }
+ }
+
+
+ template<typename Mesh, typename SplitterFactory>
+ PrimInfo createPrimRefArray_presplit(Geometry* geometry, unsigned int geomID, size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor)
+ {
+ ParallelPrefixSumState<PrimInfo> pstate;
+
+ /* first try */
+ progressMonitor(0);
+ PrimInfo pinfo = parallel_prefix_sum( pstate, size_t(0), geometry->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo {
+ return geometry->createPrimRefArray(prims,r,r.begin(),geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != numPrimRefs)
+ {
+ progressMonitor(0);
+ pinfo = parallel_prefix_sum( pstate, size_t(0), geometry->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo {
+ return geometry->createPrimRefArray(prims,r,base.size(),geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+ return pinfo;
+ }
+
+ __forceinline Vec2i computeMC(const Vec3fa &grid_base, const float grid_scale, const PrimRef &ref)
+ {
+ const Vec3fa lower = ref.lower;
+ const Vec3fa upper = ref.upper;
+ const Vec3fa glower = (lower-grid_base)*Vec3fa(grid_scale)+Vec3fa(0.2f);
+ const Vec3fa gupper = (upper-grid_base)*Vec3fa(grid_scale)-Vec3fa(0.2f);
+ Vec3ia ilower(floor(glower));
+ Vec3ia iupper(floor(gupper));
+
+ /* this ignores dimensions that are empty */
+ iupper = (Vec3ia)select(vint4(glower) >= vint4(gupper),vint4(ilower),vint4(iupper));
+
+ /* compute a morton code for the lower and upper grid coordinates. */
+ const unsigned int lower_code = bitInterleave(ilower.x,ilower.y,ilower.z);
+ const unsigned int upper_code = bitInterleave(iupper.x,iupper.y,iupper.z);
+ return Vec2i(lower_code,upper_code);
+ }
+
+ template<typename Mesh, typename SplitterFactory>
+ PrimInfo createPrimRefArray_presplit(Scene* scene, Geometry::GTypeMask types, bool mblur, size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor)
+ {
+ static const size_t MIN_STEP_SIZE = 128;
+
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator2 iter(scene,types,mblur);
+
+ /* first try */
+ progressMonitor(0);
+ pstate.init(iter,size_t(1024));
+ PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo {
+ return mesh->createPrimRefArray(prims,r,k,(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ /* if we need to filter out geometry, run again */
+ if (pinfo.size() != numPrimRefs)
+ {
+ progressMonitor(0);
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo {
+ return mesh->createPrimRefArray(prims,r,base.size(),(unsigned)geomID);
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+ }
+
+ /* use correct number of primitives */
+ size_t numPrimitives = pinfo.size();
+ const size_t alloc_numPrimitives = prims.size();
+ const size_t numSplitPrimitivesBudget = alloc_numPrimitives - numPrimitives;
+
+ /* set up primitive splitter */
+ SplitterFactory Splitter(scene);
+
+
+ DBG_PRESPLIT(
+ const size_t org_numPrimitives = pinfo.size();
+ PRINT(numPrimitives);
+ PRINT(alloc_numPrimitives);
+ PRINT(numSplitPrimitivesBudget);
+ );
+
+ /* allocate double buffer presplit items */
+ const size_t presplit_allocation_size = sizeof(PresplitItem)*alloc_numPrimitives;
+ PresplitItem *presplitItem = (PresplitItem*)alignedMalloc(presplit_allocation_size,64);
+ PresplitItem *tmp_presplitItem = (PresplitItem*)alignedMalloc(presplit_allocation_size,64);
+
+ /* compute grid */
+ const Vec3fa grid_base = pinfo.geomBounds.lower;
+ const Vec3fa grid_diag = pinfo.geomBounds.size();
+ const float grid_extend = max(grid_diag.x,max(grid_diag.y,grid_diag.z));
+ const float grid_scale = grid_extend == 0.0f ? 0.0f : GRID_SIZE / grid_extend;
+
+ /* init presplit items and get total sum */
+ const float psum = parallel_reduce( size_t(0), numPrimitives, size_t(MIN_STEP_SIZE), 0.0f, [&](const range<size_t>& r) -> float {
+ float sum = 0.0f;
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ presplitItem[i].index = (unsigned int)i;
+ const Vec2i mc = computeMC(grid_base,grid_scale,prims[i]);
+ /* if all bits are equal then we cannot split */
+ presplitItem[i].priority = (mc.x != mc.y) ? PresplitItem::compute_priority<Mesh>(prims[i],scene,mc) : 0.0f;
+ /* FIXME: sum undeterministic */
+ sum += presplitItem[i].priority;
+ }
+ return sum;
+ },[](const float& a, const float& b) -> float { return a+b; });
+
+ /* compute number of splits per primitive */
+ const float inv_psum = 1.0f / psum;
+ parallel_for( size_t(0), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& r) -> void {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ {
+ if (presplitItem[i].priority > 0.0f)
+ {
+ const float rel_p = (float)numSplitPrimitivesBudget * presplitItem[i].priority * inv_psum;
+ if (rel_p >= PRIORITY_CUTOFF_THRESHOLD) // need at least a split budget that generates two sub-prims
+ {
+ presplitItem[i].priority = max(min(ceilf(logf(rel_p)/logf(2.0f)),(float)MAX_PRESPLITS_PER_PRIMITIVE_LOG),1.0f);
+ //presplitItem[i].priority = min(floorf(logf(rel_p)/logf(2.0f)),(float)MAX_PRESPLITS_PER_PRIMITIVE_LOG);
+ assert(presplitItem[i].priority >= 0.0f && presplitItem[i].priority <= (float)MAX_PRESPLITS_PER_PRIMITIVE_LOG);
+ }
+ else
+ presplitItem[i].priority = 0.0f;
+ }
+ }
+ });
+
+ auto isLeft = [&] (const PresplitItem &ref) { return ref.priority < PRIORITY_CUTOFF_THRESHOLD; };
+ size_t center = parallel_partitioning(presplitItem,0,numPrimitives,isLeft,1024);
+
+ /* anything to split ? */
+ if (center < numPrimitives)
+ {
+ const size_t numPrimitivesToSplit = numPrimitives - center;
+ assert(presplitItem[center].priority >= 1.0f);
+
+ /* sort presplit items in ascending order */
+ radix_sort_u32(presplitItem + center,tmp_presplitItem + center,numPrimitivesToSplit,1024);
+
+ CHECK_PRESPLIT(
+ parallel_for( size_t(center+1), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& r) -> void {
+ for (size_t i=r.begin(); i<r.end(); i++)
+ assert(presplitItem[i-1].priority <= presplitItem[i].priority);
+ });
+ );
+
+ unsigned int *const primOffset0 = (unsigned int*)tmp_presplitItem;
+ unsigned int *const primOffset1 = (unsigned int*)tmp_presplitItem + numPrimitivesToSplit;
+
+ /* compute actual number of sub-primitives generated within the [center;numPrimitives-1] range */
+ const size_t totalNumSubPrims = parallel_reduce( size_t(center), numPrimitives, size_t(MIN_STEP_SIZE), size_t(0), [&](const range<size_t>& t) -> size_t {
+ size_t sum = 0;
+ for (size_t i=t.begin(); i<t.end(); i++)
+ {
+ PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE];
+ assert(presplitItem[i].priority >= 1.0f);
+ const unsigned int primrefID = presplitItem[i].index;
+ const float prio = presplitItem[i].priority;
+ const unsigned int geomID = prims[primrefID].geomID();
+ const unsigned int primID = prims[primrefID].primID();
+ const unsigned int split_levels = (unsigned int)prio;
+ unsigned int numSubPrims = 0;
+ splitPrimitive(Splitter,prims[primrefID],geomID,primID,split_levels,grid_base,grid_scale,grid_extend,subPrims,numSubPrims);
+ assert(numSubPrims);
+ numSubPrims--; // can reuse slot
+ sum+=numSubPrims;
+ presplitItem[i].data = (numSubPrims << MAX_PRESPLITS_PER_PRIMITIVE_LOG) | split_levels;
+ primOffset0[i-center] = numSubPrims;
+ }
+ return sum;
+ },[](const size_t& a, const size_t& b) -> size_t { return a+b; });
+
+ /* if we are over budget, need to shrink the range */
+ if (totalNumSubPrims > numSplitPrimitivesBudget)
+ {
+ size_t new_center = numPrimitives-1;
+ size_t sum = 0;
+ for (;new_center>=center;new_center--)
+ {
+ const unsigned int numSubPrims = presplitItem[new_center].data >> MAX_PRESPLITS_PER_PRIMITIVE_LOG;
+ if (unlikely(sum + numSubPrims >= numSplitPrimitivesBudget)) break;
+ sum += numSubPrims;
+ }
+ new_center++;
+ center = new_center;
+ }
+
+ /* parallel prefix sum to compute offsets for storing sub-primitives */
+ const unsigned int offset = parallel_prefix_sum(primOffset0,primOffset1,numPrimitivesToSplit,(unsigned int)0,std::plus<unsigned int>());
+
+ /* iterate over range, and split primitives into sub primitives and append them to prims array */
+ parallel_for( size_t(center), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& rn) -> void {
+ for (size_t j=rn.begin(); j<rn.end(); j++)
+ {
+ PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE];
+ const unsigned int primrefID = presplitItem[j].index;
+ const unsigned int geomID = prims[primrefID].geomID();
+ const unsigned int primID = prims[primrefID].primID();
+ const unsigned int split_levels = presplitItem[j].data & ((unsigned int)(1 << MAX_PRESPLITS_PER_PRIMITIVE_LOG)-1);
+
+ assert(split_levels);
+ assert(split_levels <= MAX_PRESPLITS_PER_PRIMITIVE_LOG);
+ unsigned int numSubPrims = 0;
+ splitPrimitive(Splitter,prims[primrefID],geomID,primID,split_levels,grid_base,grid_scale,grid_extend,subPrims,numSubPrims);
+ const size_t newID = numPrimitives + primOffset1[j-center];
+ assert(newID+numSubPrims <= alloc_numPrimitives);
+ prims[primrefID] = subPrims[0];
+ for (size_t i=1;i<numSubPrims;i++)
+ prims[newID+i-1] = subPrims[i];
+ }
+ });
+
+ numPrimitives += offset;
+ DBG_PRESPLIT(
+ PRINT(pinfo.size());
+ PRINT(numPrimitives);
+ PRINT((float)numPrimitives/org_numPrimitives));
+ }
+
+ /* recompute centroid bounding boxes */
+ pinfo = parallel_reduce(size_t(0),numPrimitives,size_t(MIN_STEP_SIZE),PrimInfo(empty),[&] (const range<size_t>& r) -> PrimInfo {
+ PrimInfo p(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ p.add_center2(prims[j]);
+ return p;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ assert(pinfo.size() == numPrimitives);
+
+ /* free double buffer presplit items */
+ alignedFree(tmp_presplitItem);
+ alignedFree(presplitItem);
+ return pinfo;
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/builders/splitter.h b/thirdparty/embree/kernels/builders/splitter.h
new file mode 100644
index 0000000000..f7720bd284
--- /dev/null
+++ b/thirdparty/embree/kernels/builders/splitter.h
@@ -0,0 +1,191 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/scene.h"
+#include "../common/primref.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<size_t N>
+ __forceinline void splitPolygon(const BBox3fa& bounds,
+ const size_t dim,
+ const float pos,
+ const Vec3fa (&v)[N+1],
+ const Vec3fa (&inv_length)[N],
+ BBox3fa& left_o,
+ BBox3fa& right_o)
+ {
+ BBox3fa left = empty, right = empty;
+ /* clip triangle to left and right box by processing all edges */
+ for (size_t i=0; i<N; i++)
+ {
+ const Vec3fa &v0 = v[i];
+ const Vec3fa &v1 = v[i+1];
+ const float v0d = v0[dim];
+ const float v1d = v1[dim];
+
+ if (v0d <= pos) left. extend(v0); // this point is on left side
+ if (v0d >= pos) right.extend(v0); // this point is on right side
+
+ if ((v0d < pos && pos < v1d) || (v1d < pos && pos < v0d)) // the edge crosses the splitting location
+ {
+ assert((v1d-v0d) != 0.0f);
+ const Vec3fa c = madd(Vec3fa((pos-v0d)*inv_length[i][dim]),v1-v0,v0);
+ left.extend(c);
+ right.extend(c);
+ }
+ }
+
+ /* clip against current bounds */
+ left_o = intersect(left,bounds);
+ right_o = intersect(right,bounds);
+ }
+
+ template<size_t N>
+ __forceinline void splitPolygon(const PrimRef& prim,
+ const size_t dim,
+ const float pos,
+ const Vec3fa (&v)[N+1],
+ PrimRef& left_o,
+ PrimRef& right_o)
+ {
+ BBox3fa left = empty, right = empty;
+ for (size_t i=0; i<N; i++)
+ {
+ const Vec3fa &v0 = v[i];
+ const Vec3fa &v1 = v[i+1];
+ const float v0d = v0[dim];
+ const float v1d = v1[dim];
+
+ if (v0d <= pos) left. extend(v0); // this point is on left side
+ if (v0d >= pos) right.extend(v0); // this point is on right side
+
+ if ((v0d < pos && pos < v1d) || (v1d < pos && pos < v0d)) // the edge crosses the splitting location
+ {
+ assert((v1d-v0d) != 0.0f);
+ const float inv_length = 1.0f/(v1d-v0d);
+ const Vec3fa c = madd(Vec3fa((pos-v0d)*inv_length),v1-v0,v0);
+ left.extend(c);
+ right.extend(c);
+ }
+ }
+
+ /* clip against current bounds */
+ new (&left_o ) PrimRef(intersect(left ,prim.bounds()),prim.geomID(), prim.primID());
+ new (&right_o) PrimRef(intersect(right,prim.bounds()),prim.geomID(), prim.primID());
+ }
+
+ struct TriangleSplitter
+ {
+ __forceinline TriangleSplitter(const Scene* scene, const PrimRef& prim)
+ {
+ const unsigned int mask = 0xFFFFFFFF >> RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS;
+ const TriangleMesh* mesh = (const TriangleMesh*) scene->get(prim.geomID() & mask );
+ TriangleMesh::Triangle tri = mesh->triangle(prim.primID());
+ v[0] = mesh->vertex(tri.v[0]);
+ v[1] = mesh->vertex(tri.v[1]);
+ v[2] = mesh->vertex(tri.v[2]);
+ v[3] = mesh->vertex(tri.v[0]);
+ inv_length[0] = Vec3fa(1.0f) / (v[1]-v[0]);
+ inv_length[1] = Vec3fa(1.0f) / (v[2]-v[1]);
+ inv_length[2] = Vec3fa(1.0f) / (v[0]-v[2]);
+ }
+
+ __forceinline void operator() (const PrimRef& prim, const size_t dim, const float pos, PrimRef& left_o, PrimRef& right_o) const {
+ splitPolygon<3>(prim,dim,pos,v,left_o,right_o);
+ }
+
+ __forceinline void operator() (const BBox3fa& prim, const size_t dim, const float pos, BBox3fa& left_o, BBox3fa& right_o) const {
+ splitPolygon<3>(prim,dim,pos,v,inv_length,left_o,right_o);
+ }
+
+ private:
+ Vec3fa v[4];
+ Vec3fa inv_length[3];
+ };
+
+ struct TriangleSplitterFactory
+ {
+ __forceinline TriangleSplitterFactory(const Scene* scene)
+ : scene(scene) {}
+
+ __forceinline TriangleSplitter operator() (const PrimRef& prim) const {
+ return TriangleSplitter(scene,prim);
+ }
+
+ private:
+ const Scene* scene;
+ };
+
+ struct QuadSplitter
+ {
+ __forceinline QuadSplitter(const Scene* scene, const PrimRef& prim)
+ {
+ const unsigned int mask = 0xFFFFFFFF >> RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS;
+ const QuadMesh* mesh = (const QuadMesh*) scene->get(prim.geomID() & mask );
+ QuadMesh::Quad quad = mesh->quad(prim.primID());
+ v[0] = mesh->vertex(quad.v[0]);
+ v[1] = mesh->vertex(quad.v[1]);
+ v[2] = mesh->vertex(quad.v[2]);
+ v[3] = mesh->vertex(quad.v[3]);
+ v[4] = mesh->vertex(quad.v[0]);
+ inv_length[0] = Vec3fa(1.0f) / (v[1]-v[0]);
+ inv_length[1] = Vec3fa(1.0f) / (v[2]-v[1]);
+ inv_length[2] = Vec3fa(1.0f) / (v[3]-v[2]);
+ inv_length[3] = Vec3fa(1.0f) / (v[0]-v[3]);
+ }
+
+ __forceinline void operator() (const PrimRef& prim, const size_t dim, const float pos, PrimRef& left_o, PrimRef& right_o) const {
+ splitPolygon<4>(prim,dim,pos,v,left_o,right_o);
+ }
+
+ __forceinline void operator() (const BBox3fa& prim, const size_t dim, const float pos, BBox3fa& left_o, BBox3fa& right_o) const {
+ splitPolygon<4>(prim,dim,pos,v,inv_length,left_o,right_o);
+ }
+
+ private:
+ Vec3fa v[5];
+ Vec3fa inv_length[4];
+ };
+
+ struct QuadSplitterFactory
+ {
+ __forceinline QuadSplitterFactory(const Scene* scene)
+ : scene(scene) {}
+
+ __forceinline QuadSplitter operator() (const PrimRef& prim) const {
+ return QuadSplitter(scene,prim);
+ }
+
+ private:
+ const Scene* scene;
+ };
+
+
+ struct DummySplitter
+ {
+ __forceinline DummySplitter(const Scene* scene, const PrimRef& prim)
+ {
+ }
+ };
+
+ struct DummySplitterFactory
+ {
+ __forceinline DummySplitterFactory(const Scene* scene)
+ : scene(scene) {}
+
+ __forceinline DummySplitter operator() (const PrimRef& prim) const {
+ return DummySplitter(scene,prim);
+ }
+
+ private:
+ const Scene* scene;
+ };
+
+ }
+}
+
diff --git a/thirdparty/embree/kernels/bvh/bvh.cpp b/thirdparty/embree/kernels/bvh/bvh.cpp
new file mode 100644
index 0000000000..a84295f0da
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh.cpp
@@ -0,0 +1,190 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "bvh_statistics.h"
+
+namespace embree
+{
+ template<int N>
+ BVHN<N>::BVHN (const PrimitiveType& primTy, Scene* scene)
+ : AccelData((N==4) ? AccelData::TY_BVH4 : (N==8) ? AccelData::TY_BVH8 : AccelData::TY_UNKNOWN),
+ primTy(&primTy), device(scene->device), scene(scene),
+ root(emptyNode), alloc(scene->device,scene->isStaticAccel()), numPrimitives(0), numVertices(0)
+ {
+ }
+
+ template<int N>
+ BVHN<N>::~BVHN ()
+ {
+ for (size_t i=0; i<objects.size(); i++)
+ delete objects[i];
+ }
+
+ template<int N>
+ void BVHN<N>::clear()
+ {
+ set(BVHN::emptyNode,empty,0);
+ alloc.clear();
+ }
+
+ template<int N>
+ void BVHN<N>::set (NodeRef root, const LBBox3fa& bounds, size_t numPrimitives)
+ {
+ this->root = root;
+ this->bounds = bounds;
+ this->numPrimitives = numPrimitives;
+ }
+
+ template<int N>
+ void BVHN<N>::clearBarrier(NodeRef& node)
+ {
+ if (node.isBarrier())
+ node.clearBarrier();
+ else if (!node.isLeaf()) {
+ BaseNode* n = node.baseNode(); // FIXME: flags should be stored in BVH
+ for (size_t c=0; c<N; c++)
+ clearBarrier(n->child(c));
+ }
+ }
+
+ template<int N>
+ void BVHN<N>::layoutLargeNodes(size_t num)
+ {
+#if defined(__64BIT__) // do not use tree rotations on 32 bit platforms, barrier bit in NodeRef will cause issues
+ struct NodeArea
+ {
+ __forceinline NodeArea() {}
+
+ __forceinline NodeArea(NodeRef& node, const BBox3fa& bounds)
+ : node(&node), A(node.isLeaf() ? float(neg_inf) : area(bounds)) {}
+
+ __forceinline bool operator< (const NodeArea& other) const {
+ return this->A < other.A;
+ }
+
+ NodeRef* node;
+ float A;
+ };
+ std::vector<NodeArea> lst;
+ lst.reserve(num);
+ lst.push_back(NodeArea(root,empty));
+
+ while (lst.size() < num)
+ {
+ std::pop_heap(lst.begin(), lst.end());
+ NodeArea n = lst.back(); lst.pop_back();
+ if (!n.node->isAABBNode()) break;
+ AABBNode* node = n.node->getAABBNode();
+ for (size_t i=0; i<N; i++) {
+ if (node->child(i) == BVHN::emptyNode) continue;
+ lst.push_back(NodeArea(node->child(i),node->bounds(i)));
+ std::push_heap(lst.begin(), lst.end());
+ }
+ }
+
+ for (size_t i=0; i<lst.size(); i++)
+ lst[i].node->setBarrier();
+
+ root = layoutLargeNodesRecursion(root,alloc.getCachedAllocator());
+#endif
+ }
+
+ template<int N>
+ typename BVHN<N>::NodeRef BVHN<N>::layoutLargeNodesRecursion(NodeRef& node, const FastAllocator::CachedAllocator& allocator)
+ {
+ if (node.isBarrier()) {
+ node.clearBarrier();
+ return node;
+ }
+ else if (node.isAABBNode())
+ {
+ AABBNode* oldnode = node.getAABBNode();
+ AABBNode* newnode = (BVHN::AABBNode*) allocator.malloc0(sizeof(BVHN::AABBNode),byteNodeAlignment);
+ *newnode = *oldnode;
+ for (size_t c=0; c<N; c++)
+ newnode->child(c) = layoutLargeNodesRecursion(oldnode->child(c),allocator);
+ return encodeNode(newnode);
+ }
+ else return node;
+ }
+
+ template<int N>
+ double BVHN<N>::preBuild(const std::string& builderName)
+ {
+ if (builderName == "")
+ return inf;
+
+ if (device->verbosity(2))
+ {
+ Lock<MutexSys> lock(g_printMutex);
+ std::cout << "building BVH" << N << (builderName.find("MBlur") != std::string::npos ? "MB" : "") << "<" << primTy->name() << "> using " << builderName << " ..." << std::endl << std::flush;
+ }
+
+ double t0 = 0.0;
+ if (device->benchmark || device->verbosity(2)) t0 = getSeconds();
+ return t0;
+ }
+
+ template<int N>
+ void BVHN<N>::postBuild(double t0)
+ {
+ if (t0 == double(inf))
+ return;
+
+ double dt = 0.0;
+ if (device->benchmark || device->verbosity(2))
+ dt = getSeconds()-t0;
+
+ std::unique_ptr<BVHNStatistics<N>> stat;
+
+ /* print statistics */
+ if (device->verbosity(2))
+ {
+ if (!stat) stat.reset(new BVHNStatistics<N>(this));
+ const size_t usedBytes = alloc.getUsedBytes();
+ Lock<MutexSys> lock(g_printMutex);
+ std::cout << "finished BVH" << N << "<" << primTy->name() << "> : " << 1000.0f*dt << "ms, " << 1E-6*double(numPrimitives)/dt << " Mprim/s, " << 1E-9*double(usedBytes)/dt << " GB/s" << std::endl;
+
+ if (device->verbosity(2))
+ std::cout << stat->str();
+
+ if (device->verbosity(2))
+ {
+ FastAllocator::AllStatistics stat(&alloc);
+ for (size_t i=0; i<objects.size(); i++)
+ if (objects[i])
+ stat = stat + FastAllocator::AllStatistics(&objects[i]->alloc);
+
+ stat.print(numPrimitives);
+ }
+
+ if (device->verbosity(3))
+ {
+ alloc.print_blocks();
+ for (size_t i=0; i<objects.size(); i++)
+ if (objects[i])
+ objects[i]->alloc.print_blocks();
+ }
+
+ std::cout << std::flush;
+ }
+
+ /* benchmark mode */
+ if (device->benchmark)
+ {
+ if (!stat) stat.reset(new BVHNStatistics<N>(this));
+ Lock<MutexSys> lock(g_printMutex);
+ std::cout << "BENCHMARK_BUILD " << dt << " " << double(numPrimitives)/dt << " " << stat->sah() << " " << stat->bytesUsed() << " BVH" << N << "<" << primTy->name() << ">" << std::endl << std::flush;
+ }
+ }
+
+#if defined(__AVX__)
+ template class BVHN<8>;
+#endif
+
+#if !defined(__AVX__) || !defined(EMBREE_TARGET_SSE2) && !defined(EMBREE_TARGET_SSE42)
+ template class BVHN<4>;
+#endif
+}
+
diff --git a/thirdparty/embree/kernels/bvh/bvh.h b/thirdparty/embree/kernels/bvh/bvh.h
new file mode 100644
index 0000000000..565eec5a58
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh.h
@@ -0,0 +1,235 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+/* include all node types */
+#include "bvh_node_aabb.h"
+#include "bvh_node_aabb_mb.h"
+#include "bvh_node_aabb_mb4d.h"
+#include "bvh_node_obb.h"
+#include "bvh_node_obb_mb.h"
+#include "bvh_node_qaabb.h"
+
+namespace embree
+{
+ /*! flags used to enable specific node types in intersectors */
+ enum BVHNodeFlags
+ {
+ BVH_FLAG_ALIGNED_NODE = 0x00001,
+ BVH_FLAG_ALIGNED_NODE_MB = 0x00010,
+ BVH_FLAG_UNALIGNED_NODE = 0x00100,
+ BVH_FLAG_UNALIGNED_NODE_MB = 0x01000,
+ BVH_FLAG_QUANTIZED_NODE = 0x100000,
+ BVH_FLAG_ALIGNED_NODE_MB4D = 0x1000000,
+
+ /* short versions */
+ BVH_AN1 = BVH_FLAG_ALIGNED_NODE,
+ BVH_AN2 = BVH_FLAG_ALIGNED_NODE_MB,
+ BVH_AN2_AN4D = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_ALIGNED_NODE_MB4D,
+ BVH_UN1 = BVH_FLAG_UNALIGNED_NODE,
+ BVH_UN2 = BVH_FLAG_UNALIGNED_NODE_MB,
+ BVH_MB = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_UNALIGNED_NODE_MB | BVH_FLAG_ALIGNED_NODE_MB4D,
+ BVH_AN1_UN1 = BVH_FLAG_ALIGNED_NODE | BVH_FLAG_UNALIGNED_NODE,
+ BVH_AN2_UN2 = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_UNALIGNED_NODE_MB,
+ BVH_AN2_AN4D_UN2 = BVH_FLAG_ALIGNED_NODE_MB | BVH_FLAG_ALIGNED_NODE_MB4D | BVH_FLAG_UNALIGNED_NODE_MB,
+ BVH_QN1 = BVH_FLAG_QUANTIZED_NODE
+ };
+
+ /*! Multi BVH with N children. Each node stores the bounding box of
+ * it's N children as well as N child references. */
+ template<int N>
+ class BVHN : public AccelData
+ {
+ ALIGNED_CLASS_(16);
+ public:
+
+ /*! forward declaration of node ref type */
+ typedef NodeRefPtr<N> NodeRef;
+ typedef BaseNode_t<NodeRef,N> BaseNode;
+ typedef AABBNode_t<NodeRef,N> AABBNode;
+ typedef AABBNodeMB_t<NodeRef,N> AABBNodeMB;
+ typedef AABBNodeMB4D_t<NodeRef,N> AABBNodeMB4D;
+ typedef OBBNode_t<NodeRef,N> OBBNode;
+ typedef OBBNodeMB_t<NodeRef,N> OBBNodeMB;
+ typedef QuantizedBaseNode_t<N> QuantizedBaseNode;
+ typedef QuantizedBaseNodeMB_t<N> QuantizedBaseNodeMB;
+ typedef QuantizedNode_t<NodeRef,N> QuantizedNode;
+
+ /*! Number of bytes the nodes and primitives are minimally aligned to.*/
+ static const size_t byteAlignment = 16;
+ static const size_t byteNodeAlignment = 4*N;
+
+ /*! Empty node */
+ static const size_t emptyNode = NodeRef::emptyNode;
+
+ /*! Invalid node, used as marker in traversal */
+ static const size_t invalidNode = NodeRef::invalidNode;
+ static const size_t popRay = NodeRef::popRay;
+
+ /*! Maximum depth of the BVH. */
+ static const size_t maxBuildDepth = 32;
+ static const size_t maxBuildDepthLeaf = maxBuildDepth+8;
+ static const size_t maxDepth = 2*maxBuildDepthLeaf; // 2x because of two level builder
+
+ /*! Maximum number of primitive blocks in a leaf. */
+ static const size_t maxLeafBlocks = NodeRef::maxLeafBlocks;
+
+ public:
+
+ /*! Builder interface to create allocator */
+ struct CreateAlloc : public FastAllocator::Create {
+ __forceinline CreateAlloc (BVHN* bvh) : FastAllocator::Create(&bvh->alloc) {}
+ };
+
+ typedef BVHNodeRecord<NodeRef> NodeRecord;
+ typedef BVHNodeRecordMB<NodeRef> NodeRecordMB;
+ typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D;
+
+ public:
+
+ /*! BVHN default constructor. */
+ BVHN (const PrimitiveType& primTy, Scene* scene);
+
+ /*! BVHN destruction */
+ ~BVHN ();
+
+ /*! clears the acceleration structure */
+ void clear();
+
+ /*! sets BVH members after build */
+ void set (NodeRef root, const LBBox3fa& bounds, size_t numPrimitives);
+
+ /*! Clears the barrier bits of a subtree. */
+ void clearBarrier(NodeRef& node);
+
+ /*! lays out num large nodes of the BVH */
+ void layoutLargeNodes(size_t num);
+ NodeRef layoutLargeNodesRecursion(NodeRef& node, const FastAllocator::CachedAllocator& allocator);
+
+ /*! called by all builders before build starts */
+ double preBuild(const std::string& builderName);
+
+ /*! called by all builders after build ended */
+ void postBuild(double t0);
+
+ /*! allocator class */
+ struct Allocator {
+ BVHN* bvh;
+ Allocator (BVHN* bvh) : bvh(bvh) {}
+ __forceinline void* operator() (size_t bytes) const {
+ return bvh->alloc._threadLocal()->malloc(&bvh->alloc,bytes);
+ }
+ };
+
+ /*! post build cleanup */
+ void cleanup() {
+ alloc.cleanup();
+ }
+
+ public:
+
+ /*! Encodes a node */
+ static __forceinline NodeRef encodeNode(AABBNode* node) { return NodeRef::encodeNode(node); }
+ static __forceinline NodeRef encodeNode(AABBNodeMB* node) { return NodeRef::encodeNode(node); }
+ static __forceinline NodeRef encodeNode(AABBNodeMB4D* node) { return NodeRef::encodeNode(node); }
+ static __forceinline NodeRef encodeNode(OBBNode* node) { return NodeRef::encodeNode(node); }
+ static __forceinline NodeRef encodeNode(OBBNodeMB* node) { return NodeRef::encodeNode(node); }
+ static __forceinline NodeRef encodeLeaf(void* tri, size_t num) { return NodeRef::encodeLeaf(tri,num); }
+ static __forceinline NodeRef encodeTypedLeaf(void* ptr, size_t ty) { return NodeRef::encodeTypedLeaf(ptr,ty); }
+
+ public:
+
+ /*! Prefetches the node this reference points to */
+ __forceinline static void prefetch(const NodeRef ref, int types=0)
+ {
+#if defined(__AVX512PF__) // MIC
+ if (types != BVH_FLAG_QUANTIZED_NODE) {
+ prefetchL2(((char*)ref.ptr)+0*64);
+ prefetchL2(((char*)ref.ptr)+1*64);
+ if ((N >= 8) || (types > BVH_FLAG_ALIGNED_NODE)) {
+ prefetchL2(((char*)ref.ptr)+2*64);
+ prefetchL2(((char*)ref.ptr)+3*64);
+ }
+ if ((N >= 8) && (types > BVH_FLAG_ALIGNED_NODE)) {
+ /* KNL still needs L2 prefetches for large nodes */
+ prefetchL2(((char*)ref.ptr)+4*64);
+ prefetchL2(((char*)ref.ptr)+5*64);
+ prefetchL2(((char*)ref.ptr)+6*64);
+ prefetchL2(((char*)ref.ptr)+7*64);
+ }
+ }
+ else
+ {
+ /* todo: reduce if 32bit offsets are enabled */
+ prefetchL2(((char*)ref.ptr)+0*64);
+ prefetchL2(((char*)ref.ptr)+1*64);
+ prefetchL2(((char*)ref.ptr)+2*64);
+ }
+#else
+ if (types != BVH_FLAG_QUANTIZED_NODE) {
+ prefetchL1(((char*)ref.ptr)+0*64);
+ prefetchL1(((char*)ref.ptr)+1*64);
+ if ((N >= 8) || (types > BVH_FLAG_ALIGNED_NODE)) {
+ prefetchL1(((char*)ref.ptr)+2*64);
+ prefetchL1(((char*)ref.ptr)+3*64);
+ }
+ if ((N >= 8) && (types > BVH_FLAG_ALIGNED_NODE)) {
+ /* deactivate for large nodes on Xeon, as it introduces regressions */
+ //prefetchL1(((char*)ref.ptr)+4*64);
+ //prefetchL1(((char*)ref.ptr)+5*64);
+ //prefetchL1(((char*)ref.ptr)+6*64);
+ //prefetchL1(((char*)ref.ptr)+7*64);
+ }
+ }
+ else
+ {
+ /* todo: reduce if 32bit offsets are enabled */
+ prefetchL1(((char*)ref.ptr)+0*64);
+ prefetchL1(((char*)ref.ptr)+1*64);
+ prefetchL1(((char*)ref.ptr)+2*64);
+ }
+#endif
+ }
+
+ __forceinline static void prefetchW(const NodeRef ref, int types=0)
+ {
+ embree::prefetchEX(((char*)ref.ptr)+0*64);
+ embree::prefetchEX(((char*)ref.ptr)+1*64);
+ if ((N >= 8) || (types > BVH_FLAG_ALIGNED_NODE)) {
+ embree::prefetchEX(((char*)ref.ptr)+2*64);
+ embree::prefetchEX(((char*)ref.ptr)+3*64);
+ }
+ if ((N >= 8) && (types > BVH_FLAG_ALIGNED_NODE)) {
+ embree::prefetchEX(((char*)ref.ptr)+4*64);
+ embree::prefetchEX(((char*)ref.ptr)+5*64);
+ embree::prefetchEX(((char*)ref.ptr)+6*64);
+ embree::prefetchEX(((char*)ref.ptr)+7*64);
+ }
+ }
+
+ /*! bvh type information */
+ public:
+ const PrimitiveType* primTy; //!< primitive type stored in the BVH
+
+ /*! bvh data */
+ public:
+ Device* device; //!< device pointer
+ Scene* scene; //!< scene pointer
+ NodeRef root; //!< root node
+ FastAllocator alloc; //!< allocator used to allocate nodes
+
+ /*! statistics data */
+ public:
+ size_t numPrimitives; //!< number of primitives the BVH is build over
+ size_t numVertices; //!< number of vertices the BVH references
+
+ /*! data arrays for special builders */
+ public:
+ std::vector<BVHN*> objects;
+ vector_t<char,aligned_allocator<char,32>> subdiv_patches;
+ };
+
+ typedef BVHN<4> BVH4;
+ typedef BVHN<8> BVH8;
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh4_factory.cpp b/thirdparty/embree/kernels/bvh/bvh4_factory.cpp
new file mode 100644
index 0000000000..890d5e7b7c
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh4_factory.cpp
@@ -0,0 +1,1325 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh4_factory.h"
+#include "../bvh/bvh.h"
+
+#include "../geometry/curveNv.h"
+#include "../geometry/curveNi.h"
+#include "../geometry/curveNi_mb.h"
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglev_mb.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/subdivpatch1.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+#include "../geometry/subgrid.h"
+#include "../common/accelinstance.h"
+
+namespace embree
+{
+ DECLARE_SYMBOL2(Accel::Collider,BVH4ColliderUserGeom);
+
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector4i,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector8i,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector4v,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector8v,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector4iMB,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector8iMB,void);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersector1MB);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersectorRobust1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersectorRobust1MB);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4Intersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vMBIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iMBIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4vIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4iIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4vIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4iMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4Quad4iMBIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,QBVH4Triangle4iIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,QBVH4Quad4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4SubdivPatch1Intersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4SubdivPatch1MBIntersector1);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4VirtualIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4VirtualMBIntersector1);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4InstanceIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4InstanceMBIntersector1);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4GridMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersector4Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersector4HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersectorRobust4Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersectorRobust4HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4Intersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4Intersector4HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vMBIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iMBIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4iIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4iIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4iMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4Quad4iMBIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4SubdivPatch1Intersector4);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4SubdivPatch1MBIntersector4);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4VirtualIntersector4Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4VirtualMBIntersector4Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4InstanceIntersector4Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4InstanceMBIntersector4Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4GridMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersector8Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersector8HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersectorRobust8Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersectorRobust8HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4Intersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4Intersector8HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vMBIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iMBIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4iIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4iIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4iMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4Quad4iMBIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4SubdivPatch1Intersector8);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4SubdivPatch1MBIntersector8);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4VirtualIntersector8Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4VirtualMBIntersector8Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4InstanceIntersector8Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4InstanceMBIntersector8Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4GridMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersector16Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersector16HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersectorRobust16Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersectorRobust16HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4Intersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4Intersector16HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vMBIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iMBIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4iIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4iIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4iMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4Quad4iMBIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4SubdivPatch1Intersector16);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4SubdivPatch1MBIntersector16);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4VirtualIntersector16Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4VirtualMBIntersector16Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4InstanceIntersector16Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4InstanceMBIntersector16Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4GridMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4IntersectorStreamPacketFallback);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4IntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4IntersectorStreamMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4iIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4vIntersectorStreamPluecker);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4iIntersectorStreamPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4vIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4vIntersectorStreamMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4iIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4vIntersectorStreamPluecker);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4iIntersectorStreamPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4VirtualIntersectorStream);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH4InstanceIntersectorStream);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4MeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4vMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4iMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Curve4vBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Curve4iBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4OBBCurve4iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Curve8iBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4OBBCurve8iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4QuantizedTriangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4QuantizedQuad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4SceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4SubdivPatch1BuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4SubdivPatch1MBBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4MeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vMeshRefitSAH,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualMeshRefitSAH,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+
+ BVH4Factory::BVH4Factory(int bfeatures, int ifeatures)
+ {
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2(ifeatures,BVH4ColliderUserGeom);
+
+ selectBuilders(bfeatures);
+ selectIntersectors(ifeatures);
+ }
+
+ void BVH4Factory::selectBuilders(int features)
+ {
+ IF_ENABLED_TRIS (SELECT_SYMBOL_DEFAULT_AVX(features,BVH4BuilderTwoLevelTriangle4MeshSAH));
+ IF_ENABLED_TRIS (SELECT_SYMBOL_DEFAULT_AVX(features,BVH4BuilderTwoLevelTriangle4iMeshSAH));
+ IF_ENABLED_TRIS (SELECT_SYMBOL_DEFAULT_AVX(features,BVH4BuilderTwoLevelTriangle4vMeshSAH));
+ IF_ENABLED_QUADS (SELECT_SYMBOL_DEFAULT_AVX(features,BVH4BuilderTwoLevelQuadMeshSAH));
+ IF_ENABLED_USER (SELECT_SYMBOL_DEFAULT_AVX(features,BVH4BuilderTwoLevelVirtualSAH));
+ IF_ENABLED_INSTANCE (SELECT_SYMBOL_DEFAULT_AVX(features,BVH4BuilderTwoLevelInstanceSAH));
+
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Curve4vBuilder_OBB_New));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Curve4iBuilder_OBB_New));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4OBBCurve4iMBBuilder_OBB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX(features,BVH4Curve8iBuilder_OBB_New));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX(features,BVH4OBBCurve8iMBBuilder_OBB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4SceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4vSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4iSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4iMBSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4vMBSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4QuantizedTriangle4iSceneBuilderSAH));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Quad4vSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Quad4iSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Quad4iMBSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4QuantizedQuad4iSceneBuilderSAH));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4SceneBuilderFastSpatialSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4vSceneBuilderFastSpatialSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Triangle4iSceneBuilderFastSpatialSAH));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Quad4vSceneBuilderFastSpatialSAH));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4VirtualSceneBuilderSAH));
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4VirtualMBSceneBuilderSAH));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4InstanceSceneBuilderSAH));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4InstanceMBSceneBuilderSAH));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4GridSceneBuilderSAH));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4GridMBSceneBuilderSAH));
+
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4SubdivPatch1BuilderSAH));
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4SubdivPatch1MBBuilderSAH));
+ }
+
+ void BVH4Factory::selectIntersectors(int features)
+ {
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,VirtualCurveIntersector4i));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,VirtualCurveIntersector8i));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,VirtualCurveIntersector4v));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,VirtualCurveIntersector8v));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,VirtualCurveIntersector4iMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,VirtualCurveIntersector8iMB));
+
+ /* select intersectors1 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersector1));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersector1MB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersectorRobust1));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersectorRobust1MB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,BVH4Triangle4Intersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512(features,BVH4Triangle4iIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512(features,BVH4Triangle4vIntersector1Pluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512(features,BVH4Triangle4iIntersector1Pluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4vMBIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4iMBIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4vMBIntersector1Pluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4iMBIntersector1Pluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iIntersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersector1Pluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iIntersector1Pluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iMBIntersector1Pluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iMBIntersector1Moeller));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512(features,QBVH4Triangle4iIntersector1Pluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512(features,QBVH4Quad4iIntersector1Pluecker));
+
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4SubdivPatch1Intersector1));
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4SubdivPatch1MBIntersector1));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4VirtualIntersector1));
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4VirtualMBIntersector1));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceIntersector1));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceMBIntersector1));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4GridIntersector1Moeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4GridMBIntersector1Moeller))
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4GridIntersector1Pluecker));
+
+#if defined (EMBREE_RAY_PACKETS)
+
+ /* select intersectors4 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersector4Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersector4HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersectorRobust4Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersectorRobust4HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4Intersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4Intersector4HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4iIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4vIntersector4HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4iIntersector4HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4vMBIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4iMBIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4vMBIntersector4HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4iMBIntersector4HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersector4HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersector4HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iIntersector4HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iMBIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iMBIntersector4HybridPluecker));
+
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4SubdivPatch1Intersector4));
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4SubdivPatch1MBIntersector4));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4VirtualIntersector4Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4VirtualMBIntersector4Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceIntersector4Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceMBIntersector4Chunk));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersector4HybridMoeller));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4GridIntersector4HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4GridMBIntersector4HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4GridIntersector4HybridPluecker));
+
+ /* select intersectors8 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersector8Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersector8HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersectorRobust8Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4OBBVirtualCurveIntersectorRobust8HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Triangle4Intersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Triangle4Intersector8HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Triangle4iIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Triangle4vIntersector8HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Triangle4iIntersector8HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Triangle4vMBIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Triangle4iMBIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Triangle4vMBIntersector8HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Triangle4iMBIntersector8HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Quad4vIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Quad4vIntersector8HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Quad4iIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Quad4vIntersector8HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Quad4iIntersector8HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Quad4iMBIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4Quad4iMBIntersector8HybridPluecker));
+
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4SubdivPatch1Intersector8));
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4SubdivPatch1MBIntersector8));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4VirtualIntersector8Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4VirtualMBIntersector8Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4InstanceIntersector8Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4InstanceMBIntersector8Chunk));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4GridIntersector8HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4GridMBIntersector8HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4GridIntersector8HybridPluecker));
+
+ /* select intersectors16 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512(features,BVH4OBBVirtualCurveIntersector16Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512(features,BVH4OBBVirtualCurveIntersector16HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512(features,BVH4OBBVirtualCurveIntersectorRobust16Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512(features,BVH4OBBVirtualCurveIntersectorRobust16HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Triangle4Intersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Triangle4Intersector16HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Triangle4iIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Triangle4vIntersector16HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Triangle4iIntersector16HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Triangle4vMBIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Triangle4iMBIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Triangle4vMBIntersector16HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Triangle4iMBIntersector16HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Quad4vIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Quad4vIntersector16HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Quad4iIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Quad4vIntersector16HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Quad4iIntersector16HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Quad4iMBIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH4Quad4iMBIntersector16HybridPluecker));
+
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_INIT_AVX512(features,BVH4SubdivPatch1Intersector16));
+ IF_ENABLED_SUBDIV(SELECT_SYMBOL_INIT_AVX512(features,BVH4SubdivPatch1MBIntersector16));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX512(features,BVH4VirtualIntersector16Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX512(features,BVH4VirtualMBIntersector16Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512(features,BVH4InstanceIntersector16Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512(features,BVH4InstanceMBIntersector16Chunk));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512(features,BVH4GridIntersector16HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512(features,BVH4GridMBIntersector16HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512(features,BVH4GridIntersector16HybridPluecker));
+
+ /* select stream intersectors */
+ SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4IntersectorStreamPacketFallback);
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4IntersectorStreamMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4IntersectorStreamMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4iIntersectorStreamMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4vIntersectorStreamPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4iIntersectorStreamPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersectorStreamMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersectorStreamMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iIntersectorStreamMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersectorStreamPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iIntersectorStreamPluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4VirtualIntersectorStream));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceIntersectorStream));
+
+#endif
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4OBBVirtualCurveIntersectors(BVH4* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH4OBBVirtualCurveIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4OBBVirtualCurveIntersector4Hybrid();
+ intersectors.intersector8 = BVH4OBBVirtualCurveIntersector8Hybrid();
+ intersectors.intersector16 = BVH4OBBVirtualCurveIntersector16Hybrid();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH4OBBVirtualCurveIntersectorRobust1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4OBBVirtualCurveIntersectorRobust4Hybrid();
+ intersectors.intersector8 = BVH4OBBVirtualCurveIntersectorRobust8Hybrid();
+ intersectors.intersector16 = BVH4OBBVirtualCurveIntersectorRobust16Hybrid();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ default: assert(false);
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4OBBVirtualCurveIntersectorsMB(BVH4* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH4OBBVirtualCurveIntersector1MB();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4OBBVirtualCurveIntersector4HybridMB();
+ intersectors.intersector8 = BVH4OBBVirtualCurveIntersector8HybridMB();
+ intersectors.intersector16 = BVH4OBBVirtualCurveIntersector16HybridMB();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH4OBBVirtualCurveIntersectorRobust1MB();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4OBBVirtualCurveIntersectorRobust4HybridMB();
+ intersectors.intersector8 = BVH4OBBVirtualCurveIntersectorRobust8HybridMB();
+ intersectors.intersector16 = BVH4OBBVirtualCurveIntersectorRobust16HybridMB();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ default: assert(false);
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Triangle4Intersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ assert(ivariant == IntersectVariant::FAST);
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4Intersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4_filter = BVH4Triangle4Intersector4HybridMoeller();
+ intersectors.intersector4_nofilter = BVH4Triangle4Intersector4HybridMoellerNoFilter();
+ intersectors.intersector8_filter = BVH4Triangle4Intersector8HybridMoeller();
+ intersectors.intersector8_nofilter = BVH4Triangle4Intersector8HybridMoellerNoFilter();
+ intersectors.intersector16_filter = BVH4Triangle4Intersector16HybridMoeller();
+ intersectors.intersector16_nofilter = BVH4Triangle4Intersector16HybridMoellerNoFilter();
+ intersectors.intersectorN_filter = BVH4Triangle4IntersectorStreamMoeller();
+ intersectors.intersectorN_nofilter = BVH4Triangle4IntersectorStreamMoellerNoFilter();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Triangle4vIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ assert(ivariant == IntersectVariant::ROBUST);
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4vIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4vIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Triangle4vIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4Triangle4vIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4Triangle4vIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Triangle4iIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4iIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4iIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4Triangle4iIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH4Triangle4iIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4Triangle4iIntersectorStreamMoeller();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4iIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4iIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Triangle4iIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4Triangle4iIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4Triangle4iIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Triangle4vMBIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4vMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4vMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4Triangle4vMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH4Triangle4vMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4vMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4vMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Triangle4vMBIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4Triangle4vMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Triangle4iMBIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4iMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4iMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4Triangle4iMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH4Triangle4iMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Triangle4iMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Triangle4iMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Triangle4iMBIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4Triangle4iMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Quad4vIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4vIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4_filter = BVH4Quad4vIntersector4HybridMoeller();
+ intersectors.intersector4_nofilter = BVH4Quad4vIntersector4HybridMoellerNoFilter();
+ intersectors.intersector8_filter = BVH4Quad4vIntersector8HybridMoeller();
+ intersectors.intersector8_nofilter = BVH4Quad4vIntersector8HybridMoellerNoFilter();
+ intersectors.intersector16_filter = BVH4Quad4vIntersector16HybridMoeller();
+ intersectors.intersector16_nofilter = BVH4Quad4vIntersector16HybridMoellerNoFilter();
+ intersectors.intersectorN_filter = BVH4Quad4vIntersectorStreamMoeller();
+ intersectors.intersectorN_nofilter = BVH4Quad4vIntersectorStreamMoellerNoFilter();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4vIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Quad4vIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Quad4vIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4Quad4vIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4Quad4vIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Quad4iIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4iIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Quad4iIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4Quad4iIntersector8HybridMoeller();
+ intersectors.intersector16= BVH4Quad4iIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4Quad4iIntersectorStreamMoeller();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4iIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Quad4iIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Quad4iIntersector8HybridPluecker();
+ intersectors.intersector16= BVH4Quad4iIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4Quad4iIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4Quad4iMBIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4iMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Quad4iMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4Quad4iMBIntersector8HybridMoeller();
+ intersectors.intersector16= BVH4Quad4iMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4Quad4iMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4Quad4iMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4Quad4iMBIntersector8HybridPluecker();
+ intersectors.intersector16= BVH4Quad4iMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH4Factory::QBVH4Triangle4iIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = QBVH4Triangle4iIntersector1Pluecker();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::QBVH4Quad4iIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = QBVH4Quad4iIntersector1Pluecker();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4UserGeometryIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4VirtualIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4VirtualIntersector4Chunk();
+ intersectors.intersector8 = BVH4VirtualIntersector8Chunk();
+ intersectors.intersector16 = BVH4VirtualIntersector16Chunk();
+ intersectors.intersectorN = BVH4VirtualIntersectorStream();
+#endif
+ intersectors.collider = BVH4ColliderUserGeom();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4UserGeometryMBIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4VirtualMBIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4VirtualMBIntersector4Chunk();
+ intersectors.intersector8 = BVH4VirtualMBIntersector8Chunk();
+ intersectors.intersector16 = BVH4VirtualMBIntersector16Chunk();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4InstanceIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4InstanceIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4InstanceIntersector4Chunk();
+ intersectors.intersector8 = BVH4InstanceIntersector8Chunk();
+ intersectors.intersector16 = BVH4InstanceIntersector16Chunk();
+ intersectors.intersectorN = BVH4InstanceIntersectorStream();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4InstanceMBIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4InstanceMBIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4InstanceMBIntersector4Chunk();
+ intersectors.intersector8 = BVH4InstanceMBIntersector8Chunk();
+ intersectors.intersector16 = BVH4InstanceMBIntersector16Chunk();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4SubdivPatch1Intersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4SubdivPatch1Intersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4SubdivPatch1Intersector4();
+ intersectors.intersector8 = BVH4SubdivPatch1Intersector8();
+ intersectors.intersector16 = BVH4SubdivPatch1Intersector16();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4SubdivPatch1MBIntersectors(BVH4* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4SubdivPatch1MBIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4SubdivPatch1MBIntersector4();
+ intersectors.intersector8 = BVH4SubdivPatch1MBIntersector8();
+ intersectors.intersector16 = BVH4SubdivPatch1MBIntersector16();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel* BVH4Factory::BVH4OBBVirtualCurve4i(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Curve4i::type,scene);
+ Accel::Intersectors intersectors = BVH4OBBVirtualCurveIntersectors(accel,VirtualCurveIntersector4i(),ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->hair_builder == "default" ) builder = BVH4Curve4iBuilder_OBB_New(accel,scene,0);
+ else if (scene->device->hair_builder == "sah" ) builder = BVH4Curve4iBuilder_OBB_New(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->hair_builder+" for BVH4OBB<VirtualCurve4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+#if defined(EMBREE_TARGET_SIMD8)
+ Accel* BVH4Factory::BVH4OBBVirtualCurve8i(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Curve8i::type,scene);
+ Accel::Intersectors intersectors = BVH4OBBVirtualCurveIntersectors(accel,VirtualCurveIntersector8i(),ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->hair_builder == "default" ) builder = BVH4Curve8iBuilder_OBB_New(accel,scene,0);
+ else if (scene->device->hair_builder == "sah" ) builder = BVH4Curve8iBuilder_OBB_New(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->hair_builder+" for BVH4OBB<VirtualCurve8i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+#endif
+
+ Accel* BVH4Factory::BVH4OBBVirtualCurve4v(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Curve4v::type,scene);
+ Accel::Intersectors intersectors = BVH4OBBVirtualCurveIntersectors(accel,VirtualCurveIntersector4v(),ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->hair_builder == "default" ) builder = BVH4Curve4vBuilder_OBB_New(accel,scene,0);
+ else if (scene->device->hair_builder == "sah" ) builder = BVH4Curve4vBuilder_OBB_New(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->hair_builder+" for BVH4OBB<VirtualCurve4v>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4OBBVirtualCurve4iMB(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Curve4iMB::type,scene);
+ Accel::Intersectors intersectors = BVH4OBBVirtualCurveIntersectorsMB(accel,VirtualCurveIntersector4iMB(),ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->hair_builder == "default" ) builder = BVH4OBBCurve4iMBBuilder_OBB(accel,scene,0);
+ else if (scene->device->hair_builder == "sah" ) builder = BVH4OBBCurve4iMBBuilder_OBB(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->hair_builder+" for BVH4OBB<VirtualCurve4iMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+#if defined(EMBREE_TARGET_SIMD8)
+ Accel* BVH4Factory::BVH4OBBVirtualCurve8iMB(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Curve8iMB::type,scene);
+ Accel::Intersectors intersectors = BVH4OBBVirtualCurveIntersectorsMB(accel,VirtualCurveIntersector8iMB(), ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->hair_builder == "default" ) builder = BVH4OBBCurve8iMBBuilder_OBB(accel,scene,0);
+ else if (scene->device->hair_builder == "sah" ) builder = BVH4OBBCurve8iMBBuilder_OBB(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->hair_builder+" for BVH4OBB<VirtualCurve8iMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+#endif
+
+ Accel* BVH4Factory::BVH4Triangle4(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Triangle4::type,scene);
+
+ Accel::Intersectors intersectors;
+ if (scene->device->tri_traverser == "default") intersectors = BVH4Triangle4Intersectors(accel,ivariant);
+ else if (scene->device->tri_traverser == "fast" ) intersectors = BVH4Triangle4Intersectors(accel,IntersectVariant::FAST);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown traverser "+scene->device->tri_traverser+" for BVH4<Triangle4>");
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Triangle4SceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelTriangle4MeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH4Triangle4SceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->tri_builder == "sah" ) builder = BVH4Triangle4SceneBuilderSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_fast_spatial" ) builder = BVH4Triangle4SceneBuilderFastSpatialSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_presplit") builder = BVH4Triangle4SceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
+ else if (scene->device->tri_builder == "dynamic" ) builder = BVH4BuilderTwoLevelTriangle4MeshSAH(accel,scene,false);
+ else if (scene->device->tri_builder == "morton" ) builder = BVH4BuilderTwoLevelTriangle4MeshSAH(accel,scene,true);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH4<Triangle4>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Triangle4v(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Triangle4v::type,scene);
+
+ Accel::Intersectors intersectors;
+ if (scene->device->tri_traverser == "default") intersectors = BVH4Triangle4vIntersectors(accel,ivariant);
+ else if (scene->device->tri_traverser == "fast" ) intersectors = BVH4Triangle4vIntersectors(accel,IntersectVariant::FAST);
+ else if (scene->device->tri_traverser == "robust" ) intersectors = BVH4Triangle4vIntersectors(accel,IntersectVariant::ROBUST);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown traverser "+scene->device->tri_traverser+" for BVH4<Triangle4>");
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Triangle4vSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelTriangle4vMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH4Triangle4vSceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->tri_builder == "sah" ) builder = BVH4Triangle4vSceneBuilderSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_fast_spatial" ) builder = BVH4Triangle4vSceneBuilderFastSpatialSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_presplit") builder = BVH4Triangle4vSceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
+ else if (scene->device->tri_builder == "dynamic" ) builder = BVH4BuilderTwoLevelTriangle4vMeshSAH(accel,scene,false);
+ else if (scene->device->tri_builder == "morton" ) builder = BVH4BuilderTwoLevelTriangle4vMeshSAH(accel,scene,true);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH4<Triangle4v>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Triangle4i(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Triangle4i::type,scene);
+
+ Accel::Intersectors intersectors;
+ if (scene->device->tri_traverser == "default") intersectors = BVH4Triangle4iIntersectors(accel,ivariant);
+ else if (scene->device->tri_traverser == "fast" ) intersectors = BVH4Triangle4iIntersectors(accel,IntersectVariant::FAST);
+ else if (scene->device->tri_traverser == "robust" ) intersectors = BVH4Triangle4iIntersectors(accel,IntersectVariant::ROBUST);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown traverser "+scene->device->tri_traverser+" for BVH4<Triangle4i>");
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default" ) {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Triangle4iSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelTriangle4iMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH4Triangle4iSceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->tri_builder == "sah" ) builder = BVH4Triangle4iSceneBuilderSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_fast_spatial" ) builder = BVH4Triangle4iSceneBuilderFastSpatialSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_presplit") builder = BVH4Triangle4iSceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
+ else if (scene->device->tri_builder == "dynamic" ) builder = BVH4BuilderTwoLevelTriangle4iMeshSAH(accel,scene,false);
+ else if (scene->device->tri_builder == "morton" ) builder = BVH4BuilderTwoLevelTriangle4iMeshSAH(accel,scene,true);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH4<Triangle4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Triangle4iMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Triangle4i::type,scene);
+
+ Accel::Intersectors intersectors;
+ if (scene->device->tri_traverser_mb == "default") intersectors = BVH4Triangle4iMBIntersectors(accel,ivariant);
+ else if (scene->device->tri_traverser_mb == "fast" ) intersectors = BVH4Triangle4iMBIntersectors(accel,IntersectVariant::FAST);
+ else if (scene->device->tri_traverser_mb == "robust" ) intersectors = BVH4Triangle4iMBIntersectors(accel,IntersectVariant::ROBUST);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown traverser "+scene->device->tri_traverser_mb+" for BVH4<Triangle4iMB>");
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder_mb == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Triangle4iMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->tri_builder_mb == "internal_time_splits") builder = BVH4Triangle4iMBSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder_mb+" for BVH4<Triangle4iMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Triangle4vMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Triangle4vMB::type,scene);
+
+ Accel::Intersectors intersectors;
+ if (scene->device->tri_traverser_mb == "default") intersectors = BVH4Triangle4vMBIntersectors(accel,ivariant);
+ else if (scene->device->tri_traverser_mb == "fast" ) intersectors = BVH4Triangle4vMBIntersectors(accel,IntersectVariant::FAST);
+ else if (scene->device->tri_traverser_mb == "robust" ) intersectors = BVH4Triangle4vMBIntersectors(accel,IntersectVariant::ROBUST);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown traverser "+scene->device->tri_traverser_mb+" for BVH4<Triangle4vMB>");
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder_mb == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Triangle4vMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->tri_builder_mb == "internal_time_splits") builder = BVH4Triangle4vMBSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder_mb+" for BVH4<Triangle4vMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Quad4v(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Quad4v::type,scene);
+ Accel::Intersectors intersectors = BVH4Quad4vIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Quad4vSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelQuadMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH4Quad4vSceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->quad_builder == "sah" ) builder = BVH4Quad4vSceneBuilderSAH(accel,scene,0);
+ else if (scene->device->quad_builder == "sah_fast_spatial" ) builder = BVH4Quad4vSceneBuilderFastSpatialSAH(accel,scene,0);
+ else if (scene->device->quad_builder == "dynamic" ) builder = BVH4BuilderTwoLevelQuadMeshSAH(accel,scene,false);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder+" for BVH4<Quad4v>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Quad4i(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Quad4i::type,scene);
+ Accel::Intersectors intersectors = BVH4Quad4iIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Quad4iSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break; // FIXME: implement
+ }
+ }
+ else if (scene->device->quad_builder == "sah") builder = BVH4Quad4iSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder+" for BVH4<Quad4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Quad4iMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(Quad4i::type,scene);
+ Accel::Intersectors intersectors = BVH4Quad4iMBIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder_mb == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4Quad4iMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->quad_builder_mb == "sah") builder = BVH4Quad4iMBSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder_mb+" for BVH4<Quad4iMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4QuantizedQuad4i(Scene* scene)
+ {
+ BVH4* accel = new BVH4(Quad4i::type,scene);
+ Builder* builder = BVH4QuantizedQuad4iSceneBuilderSAH(accel,scene,0);
+ Accel::Intersectors intersectors = QBVH4Quad4iIntersectors(accel);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4QuantizedTriangle4i(Scene* scene)
+ {
+ BVH4* accel = new BVH4(Triangle4i::type,scene);
+ Builder* builder = BVH4QuantizedTriangle4iSceneBuilderSAH(accel,scene,0);
+ Accel::Intersectors intersectors = QBVH4Triangle4iIntersectors(accel);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4SubdivPatch1(Scene* scene)
+ {
+ BVH4* accel = new BVH4(SubdivPatch1::type,scene);
+ Accel::Intersectors intersectors = BVH4SubdivPatch1Intersectors(accel);
+ Builder* builder = BVH4SubdivPatch1BuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4SubdivPatch1MB(Scene* scene)
+ {
+ BVH4* accel = new BVH4(SubdivPatch1::type,scene);
+ Accel::Intersectors intersectors = BVH4SubdivPatch1MBIntersectors(accel);
+ Builder* builder = BVH4SubdivPatch1MBBuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4UserGeometry(Scene* scene, BuildVariant bvariant)
+ {
+ BVH4* accel = new BVH4(Object::type,scene);
+ Accel::Intersectors intersectors = BVH4UserGeometryIntersectors(accel);
+
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4VirtualSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelVirtualSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->object_builder == "sah") builder = BVH4VirtualSceneBuilderSAH(accel,scene,0);
+ else if (scene->device->object_builder == "dynamic") builder = BVH4BuilderTwoLevelVirtualSAH(accel,scene,false);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH4<Object>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4UserGeometryMB(Scene* scene)
+ {
+ BVH4* accel = new BVH4(Object::type,scene);
+ Accel::Intersectors intersectors = BVH4UserGeometryMBIntersectors(accel);
+ Builder* builder = BVH4VirtualMBSceneBuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4Instance(Scene* scene, bool isExpensive, BuildVariant bvariant)
+ {
+ BVH4* accel = new BVH4(InstancePrimitive::type,scene);
+ Accel::Intersectors intersectors = BVH4InstanceIntersectors(accel);
+ auto gtype = isExpensive ? Geometry::MTY_INSTANCE_EXPENSIVE : Geometry::MTY_INSTANCE_CHEAP;
+ // Builder* builder = BVH4InstanceSceneBuilderSAH(accel,scene,gtype);
+
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH4InstanceSceneBuilderSAH(accel,scene,gtype); break;
+ case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelInstanceSAH(accel,scene,gtype,false); break;
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->object_builder == "sah") builder = BVH4InstanceSceneBuilderSAH(accel,scene,gtype);
+ else if (scene->device->object_builder == "dynamic") builder = BVH4BuilderTwoLevelInstanceSAH(accel,scene,gtype,false);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH4<Object>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4InstanceMB(Scene* scene, bool isExpensive)
+ {
+ BVH4* accel = new BVH4(InstancePrimitive::type,scene);
+ Accel::Intersectors intersectors = BVH4InstanceMBIntersectors(accel);
+ auto gtype = isExpensive ? Geometry::MTY_INSTANCE_EXPENSIVE : Geometry::MTY_INSTANCE_CHEAP;
+ Builder* builder = BVH4InstanceMBSceneBuilderSAH(accel,scene,gtype);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4GridIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ if (ivariant == IntersectVariant::FAST)
+ {
+ intersectors.intersector1 = BVH4GridIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4GridIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4GridIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH4GridIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ }
+ else /* if (ivariant == IntersectVariant::ROBUST) */
+ {
+ intersectors.intersector1 = BVH4GridIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4GridIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH4GridIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH4GridIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ }
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH4Factory::BVH4GridMBIntersectors(BVH4* bvh, IntersectVariant ivariant)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH4GridMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH4GridMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH4GridMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH4GridMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH4IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel* BVH4Factory::BVH4Grid(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(SubGridQBVH4::type,scene);
+ Accel::Intersectors intersectors = BVH4GridIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ builder = BVH4GridSceneBuilderSAH(accel,scene,0);
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->grid_builder+" for BVH4<GridMesh>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH4Factory::BVH4GridMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH4* accel = new BVH4(SubGridQBVH4::type,scene);
+ Accel::Intersectors intersectors = BVH4GridMBIntersectors(accel,ivariant);
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ builder = BVH4GridMBSceneBuilderSAH(accel,scene,0);
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->grid_builder+" for BVH4MB<GridMesh>");
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh4_factory.h b/thirdparty/embree/kernels/bvh/bvh4_factory.h
new file mode 100644
index 0000000000..30973971a4
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh4_factory.h
@@ -0,0 +1,316 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_factory.h"
+
+namespace embree
+{
+ /*! BVH4 instantiations */
+ class BVH4Factory : public BVHFactory
+ {
+ public:
+ BVH4Factory(int bfeatures, int ifeatures);
+
+ public:
+ Accel* BVH4OBBVirtualCurve4i(Scene* scene, IntersectVariant ivariant);
+ Accel* BVH4OBBVirtualCurve4v(Scene* scene, IntersectVariant ivariant);
+ Accel* BVH4OBBVirtualCurve8i(Scene* scene, IntersectVariant ivariant);
+ Accel* BVH4OBBVirtualCurve4iMB(Scene* scene, IntersectVariant ivariant);
+ Accel* BVH4OBBVirtualCurve8iMB(Scene* scene, IntersectVariant ivariant);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector4i);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector8i);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector4v);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector8v);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector4iMB);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector8iMB);
+
+ Accel* BVH4Triangle4 (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4Triangle4v (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::ROBUST);
+ Accel* BVH4Triangle4i (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4Triangle4vMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4Triangle4iMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ Accel* BVH4Quad4v (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4Quad4i (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4Quad4iMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ Accel* BVH4QuantizedTriangle4i(Scene* scene);
+ Accel* BVH4QuantizedQuad4i(Scene* scene);
+
+ Accel* BVH4SubdivPatch1(Scene* scene);
+ Accel* BVH4SubdivPatch1MB(Scene* scene);
+
+ Accel* BVH4UserGeometry(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC);
+ Accel* BVH4UserGeometryMB(Scene* scene);
+
+ Accel* BVH4Instance(Scene* scene, bool isExpensive, BuildVariant bvariant = BuildVariant::STATIC);
+ Accel* BVH4InstanceMB(Scene* scene, bool isExpensive);
+
+ Accel* BVH4Grid(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH4GridMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ private:
+ void selectBuilders(int features);
+ void selectIntersectors(int features);
+
+ private:
+ Accel::Intersectors BVH4OBBVirtualCurveIntersectors(BVH4* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant);
+ Accel::Intersectors BVH4OBBVirtualCurveIntersectorsMB(BVH4* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant);
+
+ Accel::Intersectors BVH4Triangle4Intersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Triangle4vIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Triangle4iIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Triangle4iMBIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Triangle4vMBIntersectors(BVH4* bvh, IntersectVariant ivariant);
+
+ Accel::Intersectors BVH4Quad4vIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Quad4iIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4Quad4iMBIntersectors(BVH4* bvh, IntersectVariant ivariant);
+
+ Accel::Intersectors QBVH4Quad4iIntersectors(BVH4* bvh);
+ Accel::Intersectors QBVH4Triangle4iIntersectors(BVH4* bvh);
+
+ Accel::Intersectors BVH4UserGeometryIntersectors(BVH4* bvh);
+ Accel::Intersectors BVH4UserGeometryMBIntersectors(BVH4* bvh);
+
+ Accel::Intersectors BVH4InstanceIntersectors(BVH4* bvh);
+ Accel::Intersectors BVH4InstanceMBIntersectors(BVH4* bvh);
+
+ Accel::Intersectors BVH4SubdivPatch1Intersectors(BVH4* bvh);
+ Accel::Intersectors BVH4SubdivPatch1MBIntersectors(BVH4* bvh);
+
+ Accel::Intersectors BVH4GridIntersectors(BVH4* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH4GridMBIntersectors(BVH4* bvh, IntersectVariant ivariant);
+
+ private:
+
+ DEFINE_SYMBOL2(Accel::Collider,BVH4ColliderUserGeom);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersector1MB);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersectorRobust1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4OBBVirtualCurveIntersectorRobust1MB);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4Intersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4vMBIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Triangle4iMBIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4vIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4iIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4vIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4iMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4Quad4iMBIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,QBVH4Triangle4iIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,QBVH4Quad4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4SubdivPatch1Intersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4SubdivPatch1MBIntersector1);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4VirtualIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4VirtualMBIntersector1);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4InstanceIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4InstanceMBIntersector1);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4GridMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersector4Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersector4HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersectorRobust4Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4OBBVirtualCurveIntersectorRobust4HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4Intersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4Intersector4HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4vMBIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Triangle4iMBIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4iIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4vIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4iIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4iMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4Quad4iMBIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4SubdivPatch1Intersector4);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4SubdivPatch1MBIntersector4);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4VirtualIntersector4Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4VirtualMBIntersector4Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4InstanceIntersector4Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4InstanceMBIntersector4Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4GridMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridPluecker);
+
+ // ==============
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersector8Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersector8HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersectorRobust8Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4OBBVirtualCurveIntersectorRobust8HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4Intersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4Intersector8HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4vMBIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Triangle4iMBIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4iIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4vIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4iIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4iMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4Quad4iMBIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4SubdivPatch1Intersector8);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4SubdivPatch1MBIntersector8);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4VirtualIntersector8Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4VirtualMBIntersector8Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4InstanceIntersector8Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4InstanceMBIntersector8Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4GridMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridPluecker);
+
+ // ==============
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersector16Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersector16HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersectorRobust16Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4OBBVirtualCurveIntersectorRobust16HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4Intersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4Intersector16HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4vMBIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Triangle4iMBIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4iIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4vIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4iIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4iMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4Quad4iMBIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4SubdivPatch1Intersector16);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4SubdivPatch1MBIntersector16);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4VirtualIntersector16Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4VirtualMBIntersector16Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4InstanceIntersector16Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4InstanceMBIntersector16Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4GridMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridPluecker);
+
+ // ==============
+
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4IntersectorStreamPacketFallback);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4IntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4IntersectorStreamMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4iIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4vIntersectorStreamPluecker);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4iIntersectorStreamPluecker);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4vIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4vIntersectorStreamMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4iIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4vIntersectorStreamPluecker);
+ DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4iIntersectorStreamPluecker);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH4VirtualIntersectorStream);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH4InstanceIntersectorStream);
+
+ // SAH scene builders
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Curve4vBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Curve4iBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4OBBCurve4iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Curve8iBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4OBBCurve8iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4vMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4QuantizedTriangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Quad4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Quad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Quad4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4QuantizedQuad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4SubdivPatch1BuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4SubdivPatch1MBBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4VirtualSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4VirtualMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH4GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ // spatial scene builder
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4SceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Triangle4iSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4Quad4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+
+ // twolevel scene builders
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4MeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4vMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4iMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool);
+ };
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh8_factory.cpp b/thirdparty/embree/kernels/bvh/bvh8_factory.cpp
new file mode 100644
index 0000000000..d4521af241
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh8_factory.cpp
@@ -0,0 +1,1165 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "../common/isa.h" // to define EMBREE_TARGET_SIMD8
+
+#if defined (EMBREE_TARGET_SIMD8)
+
+#include "bvh8_factory.h"
+#include "../bvh/bvh.h"
+
+#include "../geometry/curveNv.h"
+#include "../geometry/curveNi.h"
+#include "../geometry/curveNi_mb.h"
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglev_mb.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/subdivpatch1.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+#include "../geometry/subgrid.h"
+#include "../common/accelinstance.h"
+
+namespace embree
+{
+ DECLARE_SYMBOL2(Accel::Collider,BVH8ColliderUserGeom);
+
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector8v,void);
+ DECLARE_ISA_FUNCTION(VirtualCurveIntersector*,VirtualCurveIntersector8iMB,void);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersector1MB);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersectorRobust1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersectorRobust1MB);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4Intersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vIntersector1Woop);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vMBIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iMBIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4vIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4iIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4vIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4iMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8Quad4iMBIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,QBVH8Triangle4iIntersector1Pluecker);
+ DECLARE_SYMBOL2(Accel::Intersector1,QBVH8Triangle4Intersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,QBVH8Quad4iIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8VirtualIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8VirtualMBIntersector1);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8InstanceIntersector1);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8InstanceMBIntersector1);
+
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8GridMBIntersector1Moeller);
+ DECLARE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Pluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersector4Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersector4HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersectorRobust4Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersectorRobust4HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4Intersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4Intersector4HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vMBIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iMBIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4iIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4iIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4iMBIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8Quad4iMBIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8VirtualIntersector4Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8VirtualMBIntersector4Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8InstanceIntersector4Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8InstanceMBIntersector4Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersector8Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersector8HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersectorRobust8Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersectorRobust8HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4Intersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4Intersector8HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vMBIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iMBIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4iIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4iIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4iMBIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8Quad4iMBIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8VirtualIntersector8Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8VirtualMBIntersector8Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8InstanceIntersector8Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8InstanceMBIntersector8Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersector16Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersector16HybridMB);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersectorRobust16Hybrid);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersectorRobust16HybridMB);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4Intersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4Intersector16HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vMBIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iMBIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4iIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridPluecker);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4iIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4iMBIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8Quad4iMBIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8VirtualIntersector16Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8VirtualMBIntersector16Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8InstanceIntersector16Chunk);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8InstanceMBIntersector16Chunk);
+
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridMoeller);
+ DECLARE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8IntersectorStreamPacketFallback);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4vIntersectorStreamPluecker);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoellerNoFilter);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamMoeller);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamPluecker);
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamPluecker);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8VirtualIntersectorStream);
+
+ DECLARE_SYMBOL2(Accel::IntersectorN,BVH8InstanceIntersectorStream);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Curve8vBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8OBBCurve8iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8QuantizedTriangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8QuantizedTriangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8QuantizedQuad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8VirtualSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8VirtualMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4SceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4MeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4vMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4iMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool);
+
+ BVH8Factory::BVH8Factory(int bfeatures, int ifeatures)
+ {
+ SELECT_SYMBOL_INIT_AVX(ifeatures,BVH8ColliderUserGeom);
+
+ selectBuilders(bfeatures);
+ selectIntersectors(ifeatures);
+ }
+
+ void BVH8Factory::selectBuilders(int features)
+ {
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX(features,BVH8Curve8vBuilder_OBB_New));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX(features,BVH8OBBCurve8iMBBuilder_OBB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8Triangle4SceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8Triangle4vSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8Triangle4iSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8Triangle4iMBSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8Triangle4vMBSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8QuantizedTriangle4iSceneBuilderSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8QuantizedTriangle4SceneBuilderSAH));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX(features,BVH8Quad4vSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX(features,BVH8Quad4iSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX(features,BVH8Quad4iMBSceneBuilderSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX(features,BVH8QuantizedQuad4iSceneBuilderSAH));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX(features,BVH8VirtualSceneBuilderSAH));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX(features,BVH8VirtualMBSceneBuilderSAH));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX(features,BVH8InstanceSceneBuilderSAH));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX(features,BVH8InstanceMBSceneBuilderSAH));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX(features,BVH8GridSceneBuilderSAH));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX(features,BVH8GridMBSceneBuilderSAH));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8Triangle4SceneBuilderFastSpatialSAH));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX(features,BVH8Triangle4vSceneBuilderFastSpatialSAH));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX(features,BVH8Quad4vSceneBuilderFastSpatialSAH));
+
+ IF_ENABLED_TRIS (SELECT_SYMBOL_INIT_AVX(features,BVH8BuilderTwoLevelTriangle4MeshSAH));
+ IF_ENABLED_TRIS (SELECT_SYMBOL_INIT_AVX(features,BVH8BuilderTwoLevelTriangle4vMeshSAH));
+ IF_ENABLED_TRIS (SELECT_SYMBOL_INIT_AVX(features,BVH8BuilderTwoLevelTriangle4iMeshSAH));
+ IF_ENABLED_QUADS (SELECT_SYMBOL_INIT_AVX(features,BVH8BuilderTwoLevelQuadMeshSAH));
+ IF_ENABLED_USER (SELECT_SYMBOL_INIT_AVX(features,BVH8BuilderTwoLevelVirtualSAH));
+ IF_ENABLED_INSTANCE (SELECT_SYMBOL_INIT_AVX(features,BVH8BuilderTwoLevelInstanceSAH));
+ }
+
+ void BVH8Factory::selectIntersectors(int features)
+ {
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,VirtualCurveIntersector8v));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,VirtualCurveIntersector8iMB));
+
+ /* select intersectors1 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersector1));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersector1MB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersectorRobust1));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersectorRobust1MB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4Intersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vIntersector1Pluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iIntersector1Pluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vIntersector1Woop));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vMBIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iMBIntersector1Moeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vMBIntersector1Pluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iMBIntersector1Pluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iIntersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersector1Pluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iIntersector1Pluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iMBIntersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iMBIntersector1Pluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,QBVH8Triangle4iIntersector1Pluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,QBVH8Triangle4Intersector1Moeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,QBVH8Quad4iIntersector1Pluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8VirtualIntersector1));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8VirtualMBIntersector1));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceIntersector1));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceMBIntersector1));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector1Moeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridMBIntersector1Moeller))
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector1Pluecker));
+
+#if defined (EMBREE_RAY_PACKETS)
+
+ /* select intersectors4 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersector4Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersector4HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersectorRobust4Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersectorRobust4HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4Intersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4Intersector4HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vIntersector4HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iIntersector4HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vMBIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iMBIntersector4HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vMBIntersector4HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iMBIntersector4HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersector4HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersector4HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iIntersector4HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2(features,BVH8Quad4iMBIntersector4HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2(features,BVH8Quad4iMBIntersector4HybridPluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8VirtualIntersector4Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8VirtualMBIntersector4Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceIntersector4Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceMBIntersector4Chunk));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector4HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector4HybridPluecker));
+
+ /* select intersectors8 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersector8Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersector8HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersectorRobust8Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8OBBVirtualCurveIntersectorRobust8HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4Intersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4Intersector8HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vIntersector8HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iIntersector8HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vMBIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iMBIntersector8HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vMBIntersector8HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iMBIntersector8HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersector8HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersector8HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iIntersector8HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2(features,BVH8Quad4iMBIntersector8HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2(features,BVH8Quad4iMBIntersector8HybridPluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8VirtualIntersector8Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8VirtualMBIntersector8Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceIntersector8Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceMBIntersector8Chunk));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector8HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector8HybridPluecker));
+
+ /* select intersectors16 */
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512(features,BVH8OBBVirtualCurveIntersector16Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512(features,BVH8OBBVirtualCurveIntersector16HybridMB));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512(features,BVH8OBBVirtualCurveIntersectorRobust16Hybrid));
+ IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_INIT_AVX512(features,BVH8OBBVirtualCurveIntersectorRobust16HybridMB));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Triangle4Intersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Triangle4Intersector16HybridMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Triangle4iIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Triangle4vIntersector16HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Triangle4iIntersector16HybridPluecker));
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Triangle4vMBIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Triangle4iMBIntersector16HybridMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Triangle4vMBIntersector16HybridPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Triangle4iMBIntersector16HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Quad4vIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Quad4vIntersector16HybridMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Quad4iIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Quad4vIntersector16HybridPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Quad4iIntersector16HybridPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Quad4iMBIntersector16HybridMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX512(features,BVH8Quad4iMBIntersector16HybridPluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX512(features,BVH8VirtualIntersector16Chunk));
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX512(features,BVH8VirtualMBIntersector16Chunk));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512(features,BVH8InstanceIntersector16Chunk));
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512(features,BVH8InstanceMBIntersector16Chunk));
+
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512(features,BVH8GridIntersector16HybridMoeller));
+ IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512(features,BVH8GridIntersector16HybridPluecker));
+
+ /* select stream intersectors */
+
+ SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8IntersectorStreamPacketFallback);
+
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4IntersectorStreamMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4IntersectorStreamMoellerNoFilter));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iIntersectorStreamMoeller));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vIntersectorStreamPluecker));
+ IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iIntersectorStreamPluecker));
+
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersectorStreamMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersectorStreamMoellerNoFilter));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iIntersectorStreamMoeller));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersectorStreamPluecker));
+ IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iIntersectorStreamPluecker));
+
+ IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8VirtualIntersectorStream));
+
+ IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceIntersectorStream));
+
+#endif
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8OBBVirtualCurveIntersectors(BVH8* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH8OBBVirtualCurveIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8OBBVirtualCurveIntersector4Hybrid();
+ intersectors.intersector8 = BVH8OBBVirtualCurveIntersector8Hybrid();
+ intersectors.intersector16 = BVH8OBBVirtualCurveIntersector16Hybrid();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH8OBBVirtualCurveIntersectorRobust1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8OBBVirtualCurveIntersectorRobust4Hybrid();
+ intersectors.intersector8 = BVH8OBBVirtualCurveIntersectorRobust8Hybrid();
+ intersectors.intersector16 = BVH8OBBVirtualCurveIntersectorRobust16Hybrid();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ default: assert(false);
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8OBBVirtualCurveIntersectorsMB(BVH8* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH8OBBVirtualCurveIntersector1MB();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8OBBVirtualCurveIntersector4HybridMB();
+ intersectors.intersector8 = BVH8OBBVirtualCurveIntersector8HybridMB();
+ intersectors.intersector16 = BVH8OBBVirtualCurveIntersector16HybridMB();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.leafIntersector = leafIntersector;
+ intersectors.intersector1 = BVH8OBBVirtualCurveIntersectorRobust1MB();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8OBBVirtualCurveIntersectorRobust4HybridMB();
+ intersectors.intersector8 = BVH8OBBVirtualCurveIntersectorRobust8HybridMB();
+ intersectors.intersector16 = BVH8OBBVirtualCurveIntersectorRobust16HybridMB();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ default: assert(false);
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Triangle4Intersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ assert(ivariant == IntersectVariant::FAST);
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4Intersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4_filter = BVH8Triangle4Intersector4HybridMoeller();
+ intersectors.intersector4_nofilter = BVH8Triangle4Intersector4HybridMoellerNoFilter();
+ intersectors.intersector8_filter = BVH8Triangle4Intersector8HybridMoeller();
+ intersectors.intersector8_nofilter = BVH8Triangle4Intersector8HybridMoellerNoFilter();
+ intersectors.intersector16_filter = BVH8Triangle4Intersector16HybridMoeller();
+ intersectors.intersector16_nofilter = BVH8Triangle4Intersector16HybridMoellerNoFilter();
+ intersectors.intersectorN_filter = BVH8Triangle4IntersectorStreamMoeller();
+ intersectors.intersectorN_nofilter = BVH8Triangle4IntersectorStreamMoellerNoFilter();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Triangle4vIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+#define ENABLE_WOOP_TEST 0
+#if ENABLE_WOOP_TEST == 0
+ //assert(ivariant == IntersectVariant::ROBUST);
+ intersectors.intersector1 = BVH8Triangle4vIntersector1Pluecker();
+#else
+ intersectors.intersector1 = BVH8Triangle4vIntersector1Woop();
+#endif
+
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4vIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Triangle4vIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Triangle4vIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8Triangle4vIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Triangle4iIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4iIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4iIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8Triangle4iIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8Triangle4iIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8Triangle4iIntersectorStreamMoeller();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4iIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4iIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Triangle4iIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Triangle4iIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8Triangle4iIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Triangle4vMBIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4vMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4vMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8Triangle4vMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8Triangle4vMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4vMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4vMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Triangle4vMBIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Triangle4vMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Triangle4iMBIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4iMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4iMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8Triangle4iMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8Triangle4iMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Triangle4iMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Triangle4iMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Triangle4iMBIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Triangle4iMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Quad4vIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4vIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4_filter = BVH8Quad4vIntersector4HybridMoeller();
+ intersectors.intersector4_nofilter = BVH8Quad4vIntersector4HybridMoellerNoFilter();
+ intersectors.intersector8_filter = BVH8Quad4vIntersector8HybridMoeller();
+ intersectors.intersector8_nofilter = BVH8Quad4vIntersector8HybridMoellerNoFilter();
+ intersectors.intersector16_filter = BVH8Quad4vIntersector16HybridMoeller();
+ intersectors.intersector16_nofilter = BVH8Quad4vIntersector16HybridMoellerNoFilter();
+ intersectors.intersectorN_filter = BVH8Quad4vIntersectorStreamMoeller();
+ intersectors.intersectorN_nofilter = BVH8Quad4vIntersectorStreamMoellerNoFilter();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4vIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Quad4vIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Quad4vIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Quad4vIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8Quad4vIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Quad4iIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4iIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Quad4iIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8Quad4iIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8Quad4iIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8Quad4iIntersectorStreamMoeller();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4iIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Quad4iIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Quad4iIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Quad4iIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8Quad4iIntersectorStreamPluecker();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8Quad4iMBIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ switch (ivariant) {
+ case IntersectVariant::FAST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4iMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Quad4iMBIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8Quad4iMBIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8Quad4iMBIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ case IntersectVariant::ROBUST:
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8Quad4iMBIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8Quad4iMBIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8Quad4iMBIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8Quad4iMBIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+ }
+ return Accel::Intersectors();
+ }
+
+ Accel::Intersectors BVH8Factory::QBVH8Triangle4iIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = QBVH8Triangle4iIntersector1Pluecker();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::QBVH8Triangle4Intersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = QBVH8Triangle4Intersector1Moeller();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::QBVH8Quad4iIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = QBVH8Quad4iIntersector1Pluecker();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8UserGeometryIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8VirtualIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8VirtualIntersector4Chunk();
+ intersectors.intersector8 = BVH8VirtualIntersector8Chunk();
+ intersectors.intersector16 = BVH8VirtualIntersector16Chunk();
+ intersectors.intersectorN = BVH8VirtualIntersectorStream();
+#endif
+ intersectors.collider = BVH8ColliderUserGeom();
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8UserGeometryMBIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8VirtualMBIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8VirtualMBIntersector4Chunk();
+ intersectors.intersector8 = BVH8VirtualMBIntersector8Chunk();
+ intersectors.intersector16 = BVH8VirtualMBIntersector16Chunk();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8InstanceIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8InstanceIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8InstanceIntersector4Chunk();
+ intersectors.intersector8 = BVH8InstanceIntersector8Chunk();
+ intersectors.intersector16 = BVH8InstanceIntersector16Chunk();
+ intersectors.intersectorN = BVH8InstanceIntersectorStream();
+#endif
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8InstanceMBIntersectors(BVH8* bvh)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8InstanceMBIntersector1();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8InstanceMBIntersector4Chunk();
+ intersectors.intersector8 = BVH8InstanceMBIntersector8Chunk();
+ intersectors.intersector16 = BVH8InstanceMBIntersector16Chunk();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ return intersectors;
+ }
+
+ Accel* BVH8Factory::BVH8OBBVirtualCurve8v(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Curve8v::type,scene);
+ Accel::Intersectors intersectors = BVH8OBBVirtualCurveIntersectors(accel,VirtualCurveIntersector8v(),ivariant);
+ Builder* builder = BVH8Curve8vBuilder_OBB_New(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8OBBVirtualCurve8iMB(Scene* scene, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Curve8iMB::type,scene);
+ Accel::Intersectors intersectors = BVH8OBBVirtualCurveIntersectorsMB(accel,VirtualCurveIntersector8iMB(),ivariant);
+ Builder* builder = BVH8OBBCurve8iMBBuilder_OBB(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Triangle4(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Triangle4::type,scene);
+ Accel::Intersectors intersectors= BVH8Triangle4Intersectors(accel,ivariant);
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Triangle4SceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelTriangle4MeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH8Triangle4SceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->tri_builder == "sah" ) builder = BVH8Triangle4SceneBuilderSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_fast_spatial") builder = BVH8Triangle4SceneBuilderFastSpatialSAH(accel,scene,0);
+ else if (scene->device->tri_builder == "sah_presplit") builder = BVH8Triangle4SceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
+ else if (scene->device->tri_builder == "dynamic" ) builder = BVH8BuilderTwoLevelTriangle4MeshSAH(accel,scene,false);
+ else if (scene->device->tri_builder == "morton" ) builder = BVH8BuilderTwoLevelTriangle4MeshSAH(accel,scene,true);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH8<Triangle4>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Triangle4v(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Triangle4v::type,scene);
+ Accel::Intersectors intersectors= BVH8Triangle4vIntersectors(accel,ivariant);
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Triangle4vSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelTriangle4vMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH8Triangle4vSceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->tri_builder == "sah_fast_spatial") builder = BVH8Triangle4SceneBuilderFastSpatialSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH8<Triangle4v>");
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Triangle4i(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Triangle4i::type,scene);
+ Accel::Intersectors intersectors = BVH8Triangle4iIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Triangle4iSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelTriangle4iMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: assert(false); break; // FIXME: implement
+ }
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder+" for BVH8<Triangle4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Triangle4iMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Triangle4i::type,scene);
+ Accel::Intersectors intersectors = BVH8Triangle4iMBIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder_mb == "default") { // FIXME: implement
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Triangle4iMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->tri_builder_mb == "internal_time_splits") builder = BVH8Triangle4iMBSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder_mb+" for BVH8<Triangle4iMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Triangle4vMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Triangle4vMB::type,scene);
+ Accel::Intersectors intersectors= BVH8Triangle4vMBIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->tri_builder_mb == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Triangle4vMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->tri_builder_mb == "internal_time_splits") builder = BVH8Triangle4vMBSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->tri_builder_mb+" for BVH8<Triangle4vMB>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8QuantizedTriangle4i(Scene* scene)
+ {
+ BVH8* accel = new BVH8(Triangle4i::type,scene);
+ Accel::Intersectors intersectors = QBVH8Triangle4iIntersectors(accel);
+ Builder* builder = BVH8QuantizedTriangle4iSceneBuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8QuantizedTriangle4(Scene* scene)
+ {
+ BVH8* accel = new BVH8(Triangle4::type,scene);
+ Accel::Intersectors intersectors = QBVH8Triangle4Intersectors(accel);
+ Builder* builder = BVH8QuantizedTriangle4SceneBuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Quad4v(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Quad4v::type,scene);
+ Accel::Intersectors intersectors = BVH8Quad4vIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Quad4vSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelQuadMeshSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: builder = BVH8Quad4vSceneBuilderFastSpatialSAH(accel,scene,0); break;
+ }
+ }
+ else if (scene->device->quad_builder == "dynamic" ) builder = BVH8BuilderTwoLevelQuadMeshSAH(accel,scene,false);
+ else if (scene->device->quad_builder == "morton" ) builder = BVH8BuilderTwoLevelQuadMeshSAH(accel,scene,true);
+ else if (scene->device->quad_builder == "sah_fast_spatial" ) builder = BVH8Quad4vSceneBuilderFastSpatialSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder+" for BVH8<Quad4v>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Quad4i(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Quad4i::type,scene);
+ Accel::Intersectors intersectors = BVH8Quad4iIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Quad4iSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break; // FIXME: implement
+ }
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder+" for BVH8<Quad4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Quad4iMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(Quad4i::type,scene);
+ Accel::Intersectors intersectors = BVH8Quad4iMBIntersectors(accel,ivariant);
+
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder_mb == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8Quad4iMBSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : assert(false); break; // FIXME: implement
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder_mb+" for BVH8<Quad4i>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8QuantizedQuad4i(Scene* scene)
+ {
+ BVH8* accel = new BVH8(Quad4i::type,scene);
+ Accel::Intersectors intersectors = QBVH8Quad4iIntersectors(accel);
+ Builder* builder = nullptr;
+ if (scene->device->quad_builder == "default" ) builder = BVH8QuantizedQuad4iSceneBuilderSAH(accel,scene,0);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->quad_builder+" for QBVH8<Quad4i>");
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8UserGeometry(Scene* scene, BuildVariant bvariant)
+ {
+ BVH8* accel = new BVH8(Object::type,scene);
+ Accel::Intersectors intersectors = BVH8UserGeometryIntersectors(accel);
+
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8VirtualSceneBuilderSAH(accel,scene,0); break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelVirtualSAH(accel,scene,false); break;
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->object_builder == "sah") builder = BVH8VirtualSceneBuilderSAH(accel,scene,0);
+ else if (scene->device->object_builder == "dynamic") builder = BVH8BuilderTwoLevelVirtualSAH(accel,scene,false);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH8<Object>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8UserGeometryMB(Scene* scene)
+ {
+ BVH8* accel = new BVH8(Object::type,scene);
+ Accel::Intersectors intersectors = BVH8UserGeometryMBIntersectors(accel);
+ Builder* builder = BVH8VirtualMBSceneBuilderSAH(accel,scene,0);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8Instance(Scene* scene, bool isExpensive, BuildVariant bvariant)
+ {
+ BVH8* accel = new BVH8(InstancePrimitive::type,scene);
+ Accel::Intersectors intersectors = BVH8InstanceIntersectors(accel);
+ auto gtype = isExpensive ? Geometry::MTY_INSTANCE_EXPENSIVE : Geometry::MTY_INSTANCE;
+ // Builder* builder = BVH8InstanceSceneBuilderSAH(accel,scene,gtype);
+
+ Builder* builder = nullptr;
+ if (scene->device->object_builder == "default") {
+ switch (bvariant) {
+ case BuildVariant::STATIC : builder = BVH8InstanceSceneBuilderSAH(accel,scene,gtype);; break;
+ case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelInstanceSAH(accel,scene,gtype,false); break;
+ case BuildVariant::HIGH_QUALITY: assert(false); break;
+ }
+ }
+ else if (scene->device->object_builder == "sah") builder = BVH8InstanceSceneBuilderSAH(accel,scene,gtype);
+ else if (scene->device->object_builder == "dynamic") builder = BVH8BuilderTwoLevelInstanceSAH(accel,scene,gtype,false);
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH8<Object>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8InstanceMB(Scene* scene, bool isExpensive)
+ {
+ BVH8* accel = new BVH8(InstancePrimitive::type,scene);
+ Accel::Intersectors intersectors = BVH8InstanceMBIntersectors(accel);
+ auto gtype = isExpensive ? Geometry::MTY_INSTANCE_EXPENSIVE : Geometry::MTY_INSTANCE;
+ Builder* builder = BVH8InstanceMBSceneBuilderSAH(accel,scene,gtype);
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8GridIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ if (ivariant == IntersectVariant::FAST)
+ {
+ intersectors.intersector1 = BVH8GridIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8GridIntersector4HybridMoeller();
+ intersectors.intersector8 = BVH8GridIntersector8HybridMoeller();
+ intersectors.intersector16 = BVH8GridIntersector16HybridMoeller();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ }
+ else /* if (ivariant == IntersectVariant::ROBUST) */
+ {
+ intersectors.intersector1 = BVH8GridIntersector1Pluecker();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = BVH8GridIntersector4HybridPluecker();
+ intersectors.intersector8 = BVH8GridIntersector8HybridPluecker();
+ intersectors.intersector16 = BVH8GridIntersector16HybridPluecker();
+ intersectors.intersectorN = BVH8IntersectorStreamPacketFallback();
+#endif
+ }
+ return intersectors;
+ }
+
+ Accel::Intersectors BVH8Factory::BVH8GridMBIntersectors(BVH8* bvh, IntersectVariant ivariant)
+ {
+ Accel::Intersectors intersectors;
+ intersectors.ptr = bvh;
+ intersectors.intersector1 = BVH8GridMBIntersector1Moeller();
+#if defined (EMBREE_RAY_PACKETS)
+ intersectors.intersector4 = nullptr;
+ intersectors.intersector8 = nullptr;
+ intersectors.intersector16 = nullptr;
+ intersectors.intersectorN = nullptr;
+#endif
+ return intersectors;
+ }
+
+ Accel* BVH8Factory::BVH8Grid(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(SubGridQBVH8::type,scene);
+ Accel::Intersectors intersectors = BVH8GridIntersectors(accel,ivariant);
+ Builder* builder = nullptr;
+ if (scene->device->grid_builder == "default") {
+ builder = BVH8GridSceneBuilderSAH(accel,scene,0);
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH4<GridMesh>");
+
+ return new AccelInstance(accel,builder,intersectors);
+ }
+
+ Accel* BVH8Factory::BVH8GridMB(Scene* scene, BuildVariant bvariant, IntersectVariant ivariant)
+ {
+ BVH8* accel = new BVH8(SubGridQBVH8::type,scene);
+ Accel::Intersectors intersectors = BVH8GridMBIntersectors(accel,ivariant);
+ Builder* builder = nullptr;
+ if (scene->device->grid_builder_mb == "default") {
+ builder = BVH8GridMBSceneBuilderSAH(accel,scene,0);
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH8MB<GridMesh>");
+ return new AccelInstance(accel,builder,intersectors);
+ }
+}
+
+#endif
diff --git a/thirdparty/embree/kernels/bvh/bvh8_factory.h b/thirdparty/embree/kernels/bvh/bvh8_factory.h
new file mode 100644
index 0000000000..198d6f1df0
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh8_factory.h
@@ -0,0 +1,280 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_factory.h"
+
+namespace embree
+{
+ /*! BVH8 instantiations */
+ class BVH8Factory : public BVHFactory
+ {
+ public:
+ BVH8Factory(int bfeatures, int ifeatures);
+
+ public:
+ Accel* BVH8OBBVirtualCurve8v(Scene* scene, IntersectVariant ivariant);
+ Accel* BVH8OBBVirtualCurve8iMB(Scene* scene, IntersectVariant ivariant);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector8v);
+ DEFINE_SYMBOL2(VirtualCurveIntersector*,VirtualCurveIntersector8iMB);
+
+ Accel* BVH8Triangle4 (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Triangle4v (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Triangle4i (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Triangle4vMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Triangle4iMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ Accel* BVH8Quad4v (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Quad4i (Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8Quad4iMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ Accel* BVH8QuantizedTriangle4i(Scene* scene);
+ Accel* BVH8QuantizedTriangle4(Scene* scene);
+ Accel* BVH8QuantizedQuad4i(Scene* scene);
+
+ Accel* BVH8UserGeometry(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC);
+ Accel* BVH8UserGeometryMB(Scene* scene);
+
+ Accel* BVH8Instance(Scene* scene, bool isExpensive, BuildVariant bvariant = BuildVariant::STATIC);
+ Accel* BVH8InstanceMB(Scene* scene, bool isExpensive);
+
+ Accel* BVH8Grid(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+ Accel* BVH8GridMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST);
+
+ private:
+ void selectBuilders(int features);
+ void selectIntersectors(int features);
+
+ private:
+ Accel::Intersectors BVH8OBBVirtualCurveIntersectors(BVH8* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant);
+ Accel::Intersectors BVH8OBBVirtualCurveIntersectorsMB(BVH8* bvh, VirtualCurveIntersector* leafIntersector, IntersectVariant ivariant);
+
+ Accel::Intersectors BVH8Triangle4Intersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Triangle4vIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Triangle4iIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Triangle4iMBIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Triangle4vMBIntersectors(BVH8* bvh, IntersectVariant ivariant);
+
+ Accel::Intersectors BVH8Quad4vIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Quad4iIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8Quad4iMBIntersectors(BVH8* bvh, IntersectVariant ivariant);
+
+ Accel::Intersectors QBVH8Triangle4iIntersectors(BVH8* bvh);
+ Accel::Intersectors QBVH8Triangle4Intersectors(BVH8* bvh);
+ Accel::Intersectors QBVH8Quad4iIntersectors(BVH8* bvh);
+
+ Accel::Intersectors BVH8UserGeometryIntersectors(BVH8* bvh);
+ Accel::Intersectors BVH8UserGeometryMBIntersectors(BVH8* bvh);
+
+ Accel::Intersectors BVH8InstanceIntersectors(BVH8* bvh);
+ Accel::Intersectors BVH8InstanceMBIntersectors(BVH8* bvh);
+
+ Accel::Intersectors BVH8GridIntersectors(BVH8* bvh, IntersectVariant ivariant);
+ Accel::Intersectors BVH8GridMBIntersectors(BVH8* bvh, IntersectVariant ivariant);
+
+ private:
+ DEFINE_SYMBOL2(Accel::Collider,BVH8ColliderUserGeom);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersector1MB);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersectorRobust1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8OBBVirtualCurveIntersectorRobust1MB);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4Intersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vMBIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4iMBIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Triangle4vIntersector1Woop);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4vIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4iIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4vIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4iMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8Quad4iMBIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,QBVH8Triangle4iIntersector1Pluecker);
+ DEFINE_SYMBOL2(Accel::Intersector1,QBVH8Triangle4Intersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,QBVH8Quad4iIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8VirtualIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8VirtualMBIntersector1);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8InstanceIntersector1);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8InstanceMBIntersector1);
+
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8GridMBIntersector1Moeller);
+ DEFINE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Pluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersector4Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersector4HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersectorRobust4Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8OBBVirtualCurveIntersectorRobust4HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4Intersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4Intersector4HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4vMBIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Triangle4iMBIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4iIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4vIntersector4HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4iIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4iMBIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8Quad4iMBIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8VirtualIntersector4Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8VirtualMBIntersector4Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8InstanceIntersector4Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8InstanceMBIntersector4Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersector8Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersector8HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersectorRobust8Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8OBBVirtualCurveIntersectorRobust8HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4Intersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4Intersector8HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4vMBIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Triangle4iMBIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4iIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4vIntersector8HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4iIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4iMBIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8Quad4iMBIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8VirtualIntersector8Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8VirtualMBIntersector8Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8InstanceIntersector8Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8InstanceMBIntersector8Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersector16Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersector16HybridMB);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersectorRobust16Hybrid);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersectorRobust16HybridMB);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4Intersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4Intersector16HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4vMBIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Triangle4iMBIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4iIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4vIntersector16HybridPluecker);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4iIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4iMBIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8Quad4iMBIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8VirtualIntersector16Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8VirtualMBIntersector16Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8InstanceIntersector16Chunk);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8InstanceMBIntersector16Chunk);
+
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridMoeller);
+ DEFINE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridPluecker);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8IntersectorStreamPacketFallback);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4vIntersectorStreamPluecker);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamPluecker);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoellerNoFilter);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamMoeller);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamPluecker);
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamPluecker);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8VirtualIntersectorStream);
+
+ DEFINE_SYMBOL2(Accel::IntersectorN,BVH8InstanceIntersectorStream);
+
+ // SAH scene builders
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Curve8vBuilder_OBB_New,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8OBBCurve8iMBBuilder_OBB,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4vMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8QuantizedTriangle4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8QuantizedTriangle4SceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Quad4vSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Quad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Quad4iMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8QuantizedQuad4iSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH8VirtualSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8VirtualMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH8InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask);
+
+ DEFINE_ISA_FUNCTION(Builder*,BVH8GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t);
+
+ // SAH spatial scene builders
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4SceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Triangle4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8Quad4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t);
+
+ // twolevel scene builders
+ private:
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4MeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4vMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelTriangle4iMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool);
+ DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool);
+ };
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_builder.cpp b/thirdparty/embree/kernels/bvh/bvh_builder.cpp
new file mode 100644
index 0000000000..161d01bb5c
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_builder.cpp
@@ -0,0 +1,60 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_builder.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N>
+ typename BVHN<N>::NodeRef BVHNBuilderVirtual<N>::BVHNBuilderV::build(FastAllocator* allocator, BuildProgressMonitor& progressFunc, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings)
+ {
+ auto createLeafFunc = [&] (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) -> NodeRef {
+ return createLeaf(prims,set,alloc);
+ };
+
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ return BVHBuilderBinnedSAH::build<NodeRef>
+ (FastAllocator::Create(allocator),typename BVH::AABBNode::Create2(),typename BVH::AABBNode::Set3(allocator,prims),createLeafFunc,progressFunc,prims,pinfo,settings);
+ }
+
+
+ template<int N>
+ typename BVHN<N>::NodeRef BVHNBuilderQuantizedVirtual<N>::BVHNBuilderV::build(FastAllocator* allocator, BuildProgressMonitor& progressFunc, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings)
+ {
+ auto createLeafFunc = [&] (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) -> NodeRef {
+ return createLeaf(prims,set,alloc);
+ };
+
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ return BVHBuilderBinnedSAH::build<NodeRef>
+ (FastAllocator::Create(allocator),typename BVH::QuantizedNode::Create2(),typename BVH::QuantizedNode::Set2(),createLeafFunc,progressFunc,prims,pinfo,settings);
+ }
+
+ template<int N>
+ typename BVHN<N>::NodeRecordMB BVHNBuilderMblurVirtual<N>::BVHNBuilderV::build(FastAllocator* allocator, BuildProgressMonitor& progressFunc, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings, const BBox1f& timeRange)
+ {
+ auto createLeafFunc = [&] (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) -> NodeRecordMB {
+ return createLeaf(prims,set,alloc);
+ };
+
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ return BVHBuilderBinnedSAH::build<NodeRecordMB>
+ (FastAllocator::Create(allocator),typename BVH::AABBNodeMB::Create(),typename BVH::AABBNodeMB::SetTimeRange(timeRange),createLeafFunc,progressFunc,prims,pinfo,settings);
+ }
+
+ template struct BVHNBuilderVirtual<4>;
+ template struct BVHNBuilderQuantizedVirtual<4>;
+ template struct BVHNBuilderMblurVirtual<4>;
+
+#if defined(__AVX__)
+ template struct BVHNBuilderVirtual<8>;
+ template struct BVHNBuilderQuantizedVirtual<8>;
+ template struct BVHNBuilderMblurVirtual<8>;
+#endif
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_builder.h b/thirdparty/embree/kernels/bvh/bvh_builder.h
new file mode 100644
index 0000000000..e35d052a62
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_builder.h
@@ -0,0 +1,115 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "../builders/bvh_builder_sah.h"
+#include "../builders/bvh_builder_msmblur.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+ template<int N>
+ struct BVHNBuilderVirtual
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef FastAllocator::CachedAllocator Allocator;
+
+ struct BVHNBuilderV {
+ NodeRef build(FastAllocator* allocator, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings);
+ virtual NodeRef createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) = 0;
+ };
+
+ template<typename CreateLeafFunc>
+ struct BVHNBuilderT : public BVHNBuilderV
+ {
+ BVHNBuilderT (CreateLeafFunc createLeafFunc)
+ : createLeafFunc(createLeafFunc) {}
+
+ NodeRef createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) {
+ return createLeafFunc(prims,set,alloc);
+ }
+
+ private:
+ CreateLeafFunc createLeafFunc;
+ };
+
+ template<typename CreateLeafFunc>
+ static NodeRef build(FastAllocator* allocator, CreateLeafFunc createLeaf, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings) {
+ return BVHNBuilderT<CreateLeafFunc>(createLeaf).build(allocator,progress,prims,pinfo,settings);
+ }
+ };
+
+ template<int N>
+ struct BVHNBuilderQuantizedVirtual
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef FastAllocator::CachedAllocator Allocator;
+
+ struct BVHNBuilderV {
+ NodeRef build(FastAllocator* allocator, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings);
+ virtual NodeRef createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) = 0;
+ };
+
+ template<typename CreateLeafFunc>
+ struct BVHNBuilderT : public BVHNBuilderV
+ {
+ BVHNBuilderT (CreateLeafFunc createLeafFunc)
+ : createLeafFunc(createLeafFunc) {}
+
+ NodeRef createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) {
+ return createLeafFunc(prims,set,alloc);
+ }
+
+ private:
+ CreateLeafFunc createLeafFunc;
+ };
+
+ template<typename CreateLeafFunc>
+ static NodeRef build(FastAllocator* allocator, CreateLeafFunc createLeaf, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings) {
+ return BVHNBuilderT<CreateLeafFunc>(createLeaf).build(allocator,progress,prims,pinfo,settings);
+ }
+ };
+
+ template<int N>
+ struct BVHNBuilderMblurVirtual
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNodeMB AABBNodeMB;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecordMB NodeRecordMB;
+ typedef FastAllocator::CachedAllocator Allocator;
+
+ struct BVHNBuilderV {
+ NodeRecordMB build(FastAllocator* allocator, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings, const BBox1f& timeRange);
+ virtual NodeRecordMB createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) = 0;
+ };
+
+ template<typename CreateLeafFunc>
+ struct BVHNBuilderT : public BVHNBuilderV
+ {
+ BVHNBuilderT (CreateLeafFunc createLeafFunc)
+ : createLeafFunc(createLeafFunc) {}
+
+ NodeRecordMB createLeaf (const PrimRef* prims, const range<size_t>& set, const Allocator& alloc) {
+ return createLeafFunc(prims,set,alloc);
+ }
+
+ private:
+ CreateLeafFunc createLeafFunc;
+ };
+
+ template<typename CreateLeafFunc>
+ static NodeRecordMB build(FastAllocator* allocator, CreateLeafFunc createLeaf, BuildProgressMonitor& progress, PrimRef* prims, const PrimInfo& pinfo, GeneralBVHBuilder::Settings settings, const BBox1f& timeRange) {
+ return BVHNBuilderT<CreateLeafFunc>(createLeaf).build(allocator,progress,prims,pinfo,settings,timeRange);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_morton.cpp b/thirdparty/embree/kernels/bvh/bvh_builder_morton.cpp
new file mode 100644
index 0000000000..4a4d8d71df
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_builder_morton.cpp
@@ -0,0 +1,531 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "bvh_statistics.h"
+#include "bvh_rotate.h"
+#include "../common/profile.h"
+#include "../../common/algorithms/parallel_prefix_sum.h"
+
+#include "../builders/primrefgen.h"
+#include "../builders/bvh_builder_morton.h"
+
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+
+#if defined(__64BIT__)
+# define ROTATE_TREE 1 // specifies number of tree rotation rounds to perform
+#else
+# define ROTATE_TREE 0 // do not use tree rotations on 32 bit platforms, barrier bit in NodeRef will cause issues
+#endif
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N>
+ struct SetBVHNBounds
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+ typedef typename BVH::AABBNode AABBNode;
+
+ BVH* bvh;
+ __forceinline SetBVHNBounds (BVH* bvh) : bvh(bvh) {}
+
+ __forceinline NodeRecord operator() (NodeRef ref, const NodeRecord* children, size_t num)
+ {
+ AABBNode* node = ref.getAABBNode();
+
+ BBox3fa res = empty;
+ for (size_t i=0; i<num; i++) {
+ const BBox3fa b = children[i].bounds;
+ res.extend(b);
+ node->setRef(i,children[i].ref);
+ node->setBounds(i,b);
+ }
+
+ BBox3fx result = (BBox3fx&)res;
+#if ROTATE_TREE
+ if (N == 4)
+ {
+ size_t n = 0;
+ for (size_t i=0; i<num; i++)
+ n += children[i].bounds.lower.a;
+
+ if (n >= 4096) {
+ for (size_t i=0; i<num; i++) {
+ if (children[i].bounds.lower.a < 4096) {
+ for (int j=0; j<ROTATE_TREE; j++)
+ BVHNRotate<N>::rotate(node->child(i));
+ node->child(i).setBarrier();
+ }
+ }
+ }
+ result.lower.a = unsigned(n);
+ }
+#endif
+
+ return NodeRecord(ref,result);
+ }
+ };
+
+ template<int N, typename Primitive>
+ struct CreateMortonLeaf;
+
+ template<int N>
+ struct CreateMortonLeaf<N,Triangle4>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (TriangleMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+ assert(items<=4);
+
+ /* allocate leaf node */
+ Triangle4* accel = (Triangle4*) alloc.malloc1(sizeof(Triangle4),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,1);
+ vuint4 vgeomID = -1, vprimID = -1;
+ Vec3vf4 v0 = zero, v1 = zero, v2 = zero;
+ const TriangleMesh* __restrict__ const mesh = this->mesh;
+
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int primID = morton[start+i].index;
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ vgeomID [i] = geomID_;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+
+ Triangle4::store_nt(accel,Triangle4(v0,v1,v2,vgeomID,vprimID));
+ BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = unsigned(current.size());
+#endif
+ return NodeRecord(ref,box_o);
+ }
+
+ private:
+ TriangleMesh* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<int N>
+ struct CreateMortonLeaf<N,Triangle4v>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (TriangleMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+ assert(items<=4);
+
+ /* allocate leaf node */
+ Triangle4v* accel = (Triangle4v*) alloc.malloc1(sizeof(Triangle4v),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,1);
+ vuint4 vgeomID = -1, vprimID = -1;
+ Vec3vf4 v0 = zero, v1 = zero, v2 = zero;
+ const TriangleMesh* __restrict__ mesh = this->mesh;
+
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int primID = morton[start+i].index;
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ vgeomID [i] = geomID_;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+ Triangle4v::store_nt(accel,Triangle4v(v0,v1,v2,vgeomID,vprimID));
+ BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = current.size();
+#endif
+ return NodeRecord(ref,box_o);
+ }
+ private:
+ TriangleMesh* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<int N>
+ struct CreateMortonLeaf<N,Triangle4i>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (TriangleMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+ assert(items<=4);
+
+ /* allocate leaf node */
+ Triangle4i* accel = (Triangle4i*) alloc.malloc1(sizeof(Triangle4i),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,1);
+
+ vuint4 v0 = zero, v1 = zero, v2 = zero;
+ vuint4 vgeomID = -1, vprimID = -1;
+ const TriangleMesh* __restrict__ const mesh = this->mesh;
+
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int primID = morton[start+i].index;
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
+ vgeomID[i] = geomID_;
+ vprimID[i] = primID;
+ unsigned int int_stride = mesh->vertices0.getStride()/4;
+ v0[i] = tri.v[0] * int_stride;
+ v1[i] = tri.v[1] * int_stride;
+ v2[i] = tri.v[2] * int_stride;
+ }
+
+ for (size_t i=items; i<4; i++)
+ {
+ vgeomID[i] = vgeomID[0];
+ vprimID[i] = -1;
+ v0[i] = 0;
+ v1[i] = 0;
+ v2[i] = 0;
+ }
+ Triangle4i::store_nt(accel,Triangle4i(v0,v1,v2,vgeomID,vprimID));
+ BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = current.size();
+#endif
+ return NodeRecord(ref,box_o);
+ }
+ private:
+ TriangleMesh* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<int N>
+ struct CreateMortonLeaf<N,Quad4v>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (QuadMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+ assert(items<=4);
+
+ /* allocate leaf node */
+ Quad4v* accel = (Quad4v*) alloc.malloc1(sizeof(Quad4v),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,1);
+
+ vuint4 vgeomID = -1, vprimID = -1;
+ Vec3vf4 v0 = zero, v1 = zero, v2 = zero, v3 = zero;
+ const QuadMesh* __restrict__ mesh = this->mesh;
+
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int primID = morton[start+i].index;
+ const QuadMesh::Quad& tri = mesh->quad(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ const Vec3fa& p3 = mesh->vertex(tri.v[3]);
+ lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2,(vfloat4)p3);
+ upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2,(vfloat4)p3);
+ vgeomID [i] = geomID_;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ v3.x[i] = p3.x; v3.y[i] = p3.y; v3.z[i] = p3.z;
+ }
+ Quad4v::store_nt(accel,Quad4v(v0,v1,v2,v3,vgeomID,vprimID));
+ BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = current.size();
+#endif
+ return NodeRecord(ref,box_o);
+ }
+ private:
+ QuadMesh* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<int N>
+ struct CreateMortonLeaf<N,Object>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (UserGeometry* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+
+ /* allocate leaf node */
+ Object* accel = (Object*) alloc.malloc1(items*sizeof(Object),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,items);
+ const UserGeometry* mesh = this->mesh;
+
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int index = morton[start+i].index;
+ const unsigned int primID = index;
+ bounds.extend(mesh->bounds(primID));
+ new (&accel[i]) Object(geomID_,primID);
+ }
+
+ BBox3fx box_o = (BBox3fx&)bounds;
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = current.size();
+#endif
+ return NodeRecord(ref,box_o);
+ }
+ private:
+ UserGeometry* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<int N>
+ struct CreateMortonLeaf<N,InstancePrimitive>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ __forceinline CreateMortonLeaf (Instance* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
+ : mesh(mesh), morton(morton), geomID_(geomID) {}
+
+ __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
+ {
+ vfloat4 lower(pos_inf);
+ vfloat4 upper(neg_inf);
+ size_t items = current.size();
+ size_t start = current.begin();
+ assert(items <= 1);
+
+ /* allocate leaf node */
+ InstancePrimitive* accel = (InstancePrimitive*) alloc.malloc1(items*sizeof(InstancePrimitive),BVH::byteAlignment);
+ NodeRef ref = BVH::encodeLeaf((char*)accel,items);
+ const Instance* instance = this->mesh;
+
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<items; i++)
+ {
+ const unsigned int primID = morton[start+i].index;
+ bounds.extend(instance->bounds(primID));
+ new (&accel[i]) InstancePrimitive(instance, geomID_);
+ }
+
+ BBox3fx box_o = (BBox3fx&)bounds;
+#if ROTATE_TREE
+ if (N == 4)
+ box_o.lower.a = current.size();
+#endif
+ return NodeRecord(ref,box_o);
+ }
+ private:
+ Instance* mesh;
+ BVHBuilderMorton::BuildPrim* morton;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ };
+
+ template<typename Mesh>
+ struct CalculateMeshBounds
+ {
+ __forceinline CalculateMeshBounds (Mesh* mesh)
+ : mesh(mesh) {}
+
+ __forceinline const BBox3fa operator() (const BVHBuilderMorton::BuildPrim& morton) {
+ return mesh->bounds(morton.index);
+ }
+
+ private:
+ Mesh* mesh;
+ };
+
+ template<int N, typename Mesh, typename Primitive>
+ class BVHNMeshBuilderMorton : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecord NodeRecord;
+
+ public:
+
+ BVHNMeshBuilderMorton (BVH* bvh, Mesh* mesh, unsigned int geomID, const size_t minLeafSize, const size_t maxLeafSize, const size_t singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD)
+ : bvh(bvh), mesh(mesh), morton(bvh->device,0), settings(N,BVH::maxBuildDepth,minLeafSize,min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks),singleThreadThreshold), geomID_(geomID) {}
+
+ /* build function */
+ void build()
+ {
+ /* we reset the allocator when the mesh size changed */
+ if (mesh->numPrimitives != numPreviousPrimitives) {
+ bvh->alloc.clear();
+ morton.clear();
+ }
+ size_t numPrimitives = mesh->size();
+ numPreviousPrimitives = numPrimitives;
+
+ /* skip build for empty scene */
+ if (numPrimitives == 0) {
+ bvh->set(BVH::emptyNode,empty,0);
+ return;
+ }
+
+ /* preallocate arrays */
+ morton.resize(numPrimitives);
+ size_t bytesEstimated = numPrimitives*sizeof(AABBNode)/(4*N) + size_t(1.2f*Primitive::blocks(numPrimitives)*sizeof(Primitive));
+ size_t bytesMortonCodes = numPrimitives*sizeof(BVHBuilderMorton::BuildPrim);
+ bytesEstimated = max(bytesEstimated,bytesMortonCodes); // the first allocation block is reused to sort the morton codes
+ bvh->alloc.init(bytesMortonCodes,bytesMortonCodes,bytesEstimated);
+
+ /* create morton code array */
+ BVHBuilderMorton::BuildPrim* dest = (BVHBuilderMorton::BuildPrim*) bvh->alloc.specialAlloc(bytesMortonCodes);
+ size_t numPrimitivesGen = createMortonCodeArray<Mesh>(mesh,morton,bvh->scene->progressInterface);
+
+ /* create BVH */
+ SetBVHNBounds<N> setBounds(bvh);
+ CreateMortonLeaf<N,Primitive> createLeaf(mesh,geomID_,morton.data());
+ CalculateMeshBounds<Mesh> calculateBounds(mesh);
+ auto root = BVHBuilderMorton::build<NodeRecord>(
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNode::Create(),
+ setBounds,createLeaf,calculateBounds,bvh->scene->progressInterface,
+ morton.data(),dest,numPrimitivesGen,settings);
+
+ bvh->set(root.ref,LBBox3fa(root.bounds),numPrimitives);
+
+#if ROTATE_TREE
+ if (N == 4)
+ {
+ for (int i=0; i<ROTATE_TREE; i++)
+ BVHNRotate<N>::rotate(bvh->root);
+ bvh->clearBarrier(bvh->root);
+ }
+#endif
+
+ /* clear temporary data for static geometry */
+ if (bvh->scene->isStaticAccel()) {
+ morton.clear();
+ }
+ bvh->cleanup();
+ }
+
+ void clear() {
+ morton.clear();
+ }
+
+ private:
+ BVH* bvh;
+ Mesh* mesh;
+ mvector<BVHBuilderMorton::BuildPrim> morton;
+ BVHBuilderMorton::Settings settings;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ unsigned int numPreviousPrimitives = 0;
+ };
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH4Triangle4MeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4> ((BVH4*)bvh,mesh,geomID,4,4); }
+ Builder* BVH4Triangle4vMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4v>((BVH4*)bvh,mesh,geomID,4,4); }
+ Builder* BVH4Triangle4iMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4i>((BVH4*)bvh,mesh,geomID,4,4); }
+#if defined(__AVX__)
+ Builder* BVH8Triangle4MeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4> ((BVH8*)bvh,mesh,geomID,4,4); }
+ Builder* BVH8Triangle4vMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4v>((BVH8*)bvh,mesh,geomID,4,4); }
+ Builder* BVH8Triangle4iMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4i>((BVH8*)bvh,mesh,geomID,4,4); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4Quad4vMeshBuilderMortonGeneral (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,QuadMesh,Quad4v>((BVH4*)bvh,mesh,geomID,4,4); }
+#if defined(__AVX__)
+ Builder* BVH8Quad4vMeshBuilderMortonGeneral (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,QuadMesh,Quad4v>((BVH8*)bvh,mesh,geomID,4,4); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ Builder* BVH4VirtualMeshBuilderMortonGeneral (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,UserGeometry,Object>((BVH4*)bvh,mesh,geomID,1,BVH4::maxLeafBlocks); }
+#if defined(__AVX__)
+ Builder* BVH8VirtualMeshBuilderMortonGeneral (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,UserGeometry,Object>((BVH8*)bvh,mesh,geomID,1,BVH4::maxLeafBlocks); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH4InstanceMeshBuilderMortonGeneral (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,Instance,InstancePrimitive>((BVH4*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); }
+#if defined(__AVX__)
+ Builder* BVH8InstanceMeshBuilderMortonGeneral (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,Instance,InstancePrimitive>((BVH8*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); }
+#endif
+#endif
+
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_sah.cpp b/thirdparty/embree/kernels/bvh/bvh_builder_sah.cpp
new file mode 100644
index 0000000000..fad02fcc04
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_builder_sah.cpp
@@ -0,0 +1,543 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "bvh_builder.h"
+#include "../builders/primrefgen.h"
+#include "../builders/splitter.h"
+
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglev_mb.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+#include "../geometry/subgrid.h"
+
+#include "../common/state.h"
+#include "../../common/algorithms/parallel_for_for.h"
+#include "../../common/algorithms/parallel_for_for_prefix_sum.h"
+
+#define PROFILE 0
+#define PROFILE_RUNS 20
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, typename Primitive>
+ struct CreateLeaf
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+
+ __forceinline CreateLeaf (BVH* bvh) : bvh(bvh) {}
+
+ __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ size_t n = set.size();
+ size_t items = Primitive::blocks(n);
+ size_t start = set.begin();
+ Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteAlignment);
+ typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,items);
+ for (size_t i=0; i<items; i++) {
+ accel[i].fill(prims,start,set.end(),bvh->scene);
+ }
+ return node;
+ }
+
+ BVH* bvh;
+ };
+
+
+ template<int N, typename Primitive>
+ struct CreateLeafQuantized
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+
+ __forceinline CreateLeafQuantized (BVH* bvh) : bvh(bvh) {}
+
+ __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ size_t n = set.size();
+ size_t items = Primitive::blocks(n);
+ size_t start = set.begin();
+ Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteAlignment);
+ typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,items);
+ for (size_t i=0; i<items; i++) {
+ accel[i].fill(prims,start,set.end(),bvh->scene);
+ }
+ return node;
+ }
+
+ BVH* bvh;
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+ template<int N, typename Primitive>
+ struct BVHNBuilderSAH : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVHN<N>::NodeRef NodeRef;
+
+ BVH* bvh;
+ Scene* scene;
+ Geometry* mesh;
+ mvector<PrimRef> prims;
+ GeneralBVHBuilder::Settings settings;
+ Geometry::GTypeMask gtype_;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max ();
+ bool primrefarrayalloc;
+ unsigned int numPreviousPrimitives = 0;
+
+ BVHNBuilderSAH (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize,
+ const Geometry::GTypeMask gtype, bool primrefarrayalloc = false)
+ : bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device,0),
+ settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype), primrefarrayalloc(primrefarrayalloc) {}
+
+ BVHNBuilderSAH (BVH* bvh, Geometry* mesh, unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype)
+ : bvh(bvh), scene(nullptr), mesh(mesh), prims(bvh->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype), geomID_(geomID), primrefarrayalloc(false) {}
+
+ // FIXME: shrink bvh->alloc in destructor here and in other builders too
+
+ void build()
+ {
+ /* we reset the allocator when the mesh size changed */
+ if (mesh && mesh->numPrimitives != numPreviousPrimitives) {
+ bvh->alloc.clear();
+ }
+
+ /* if we use the primrefarray for allocations we have to take it back from the BVH */
+ if (settings.primrefarrayalloc != size_t(inf))
+ bvh->alloc.unshare(prims);
+
+ /* skip build for empty scene */
+ const size_t numPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(gtype_,false);
+ numPreviousPrimitives = numPrimitives;
+ if (numPrimitives == 0) {
+ bvh->clear();
+ prims.clear();
+ return;
+ }
+
+ double t0 = bvh->preBuild(mesh ? "" : TOSTRING(isa) "::BVH" + toString(N) + "BuilderSAH");
+
+#if PROFILE
+ profile(2,PROFILE_RUNS,numPrimitives,[&] (ProfileTimer& timer) {
+#endif
+
+ /* create primref array */
+ if (primrefarrayalloc) {
+ settings.primrefarrayalloc = numPrimitives/1000;
+ if (settings.primrefarrayalloc < 1000)
+ settings.primrefarrayalloc = inf;
+ }
+
+ /* enable os_malloc for two level build */
+ if (mesh)
+ bvh->alloc.setOSallocation(true);
+
+ /* initialize allocator */
+ const size_t node_bytes = numPrimitives*sizeof(typename BVH::AABBNodeMB)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(numPrimitives)*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,numPrimitives,node_bytes+leaf_bytes);
+ prims.resize(numPrimitives);
+
+ PrimInfo pinfo = mesh ?
+ createPrimRefArray(mesh,geomID_,numPrimitives,prims,bvh->scene->progressInterface) :
+ createPrimRefArray(scene,gtype_,false,numPrimitives,prims,bvh->scene->progressInterface);
+
+ /* pinfo might has zero size due to invalid geometry */
+ if (unlikely(pinfo.size() == 0))
+ {
+ bvh->clear();
+ prims.clear();
+ return;
+ }
+
+ /* call BVH builder */
+ NodeRef root = BVHNBuilderVirtual<N>::build(&bvh->alloc,CreateLeaf<N,Primitive>(bvh),bvh->scene->progressInterface,prims.data(),pinfo,settings);
+ bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size());
+ bvh->layoutLargeNodes(size_t(pinfo.size()*0.005f));
+
+#if PROFILE
+ });
+#endif
+
+ /* if we allocated using the primrefarray we have to keep it alive */
+ if (settings.primrefarrayalloc != size_t(inf))
+ bvh->alloc.share(prims);
+
+ /* for static geometries we can do some cleanups */
+ else if (scene && scene->isStaticAccel()) {
+ prims.clear();
+ }
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+ void clear() {
+ prims.clear();
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+ template<int N, typename Primitive>
+ struct BVHNBuilderSAHQuantized : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVHN<N>::NodeRef NodeRef;
+
+ BVH* bvh;
+ Scene* scene;
+ Geometry* mesh;
+ mvector<PrimRef> prims;
+ GeneralBVHBuilder::Settings settings;
+ Geometry::GTypeMask gtype_;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ unsigned int numPreviousPrimitives = 0;
+
+ BVHNBuilderSAHQuantized (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype)
+ : bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype) {}
+
+ BVHNBuilderSAHQuantized (BVH* bvh, Geometry* mesh, unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype)
+ : bvh(bvh), scene(nullptr), mesh(mesh), prims(bvh->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), gtype_(gtype), geomID_(geomID) {}
+
+ // FIXME: shrink bvh->alloc in destructor here and in other builders too
+
+ void build()
+ {
+ /* we reset the allocator when the mesh size changed */
+ if (mesh && mesh->numPrimitives != numPreviousPrimitives) {
+ bvh->alloc.clear();
+ }
+
+ /* skip build for empty scene */
+ const size_t numPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(gtype_,false);
+ numPreviousPrimitives = numPrimitives;
+ if (numPrimitives == 0) {
+ prims.clear();
+ bvh->clear();
+ return;
+ }
+
+ double t0 = bvh->preBuild(mesh ? "" : TOSTRING(isa) "::QBVH" + toString(N) + "BuilderSAH");
+
+#if PROFILE
+ profile(2,PROFILE_RUNS,numPrimitives,[&] (ProfileTimer& timer) {
+#endif
+ /* create primref array */
+ prims.resize(numPrimitives);
+ PrimInfo pinfo = mesh ?
+ createPrimRefArray(mesh,geomID_,numPrimitives,prims,bvh->scene->progressInterface) :
+ createPrimRefArray(scene,gtype_,false,numPrimitives,prims,bvh->scene->progressInterface);
+
+ /* enable os_malloc for two level build */
+ if (mesh)
+ bvh->alloc.setOSallocation(true);
+
+ /* call BVH builder */
+ const size_t node_bytes = numPrimitives*sizeof(typename BVH::QuantizedNode)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(numPrimitives)*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,numPrimitives,node_bytes+leaf_bytes);
+ NodeRef root = BVHNBuilderQuantizedVirtual<N>::build(&bvh->alloc,CreateLeafQuantized<N,Primitive>(bvh),bvh->scene->progressInterface,prims.data(),pinfo,settings);
+ bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size());
+ //bvh->layoutLargeNodes(pinfo.size()*0.005f); // FIXME: COPY LAYOUT FOR LARGE NODES !!!
+#if PROFILE
+ });
+#endif
+
+ /* clear temporary data for static geometry */
+ if (scene && scene->isStaticAccel()) {
+ prims.clear();
+ }
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+ void clear() {
+ prims.clear();
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+
+ template<int N, typename Primitive>
+ struct CreateLeafGrid
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+
+ __forceinline CreateLeafGrid (BVH* bvh, const SubGridBuildData * const sgrids) : bvh(bvh),sgrids(sgrids) {}
+
+ __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ const size_t items = set.size(); //Primitive::blocks(n);
+ const size_t start = set.begin();
+
+ /* collect all subsets with unique geomIDs */
+ assert(items <= N);
+ unsigned int geomIDs[N];
+ unsigned int num_geomIDs = 1;
+ geomIDs[0] = prims[start].geomID();
+
+ for (size_t i=1;i<items;i++)
+ {
+ bool found = false;
+ const unsigned int new_geomID = prims[start+i].geomID();
+ for (size_t j=0;j<num_geomIDs;j++)
+ if (new_geomID == geomIDs[j])
+ { found = true; break; }
+ if (!found)
+ geomIDs[num_geomIDs++] = new_geomID;
+ }
+
+ /* allocate all leaf memory in one single block */
+ SubGridQBVHN<N>* accel = (SubGridQBVHN<N>*) alloc.malloc1(num_geomIDs*sizeof(SubGridQBVHN<N>),BVH::byteAlignment);
+ typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,num_geomIDs);
+
+ for (size_t g=0;g<num_geomIDs;g++)
+ {
+ unsigned int x[N];
+ unsigned int y[N];
+ unsigned int primID[N];
+ BBox3fa bounds[N];
+ unsigned int pos = 0;
+ for (size_t i=0;i<items;i++)
+ {
+ if (unlikely(prims[start+i].geomID() != geomIDs[g])) continue;
+
+ const SubGridBuildData& sgrid_bd = sgrids[prims[start+i].primID()];
+ x[pos] = sgrid_bd.sx;
+ y[pos] = sgrid_bd.sy;
+ primID[pos] = sgrid_bd.primID;
+ bounds[pos] = prims[start+i].bounds();
+ pos++;
+ }
+ assert(pos <= N);
+ new (&accel[g]) SubGridQBVHN<N>(x,y,primID,bounds,geomIDs[g],pos);
+ }
+
+ return node;
+ }
+
+ BVH* bvh;
+ const SubGridBuildData * const sgrids;
+ };
+
+
+ template<int N>
+ struct BVHNBuilderSAHGrid : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVHN<N>::NodeRef NodeRef;
+
+ BVH* bvh;
+ Scene* scene;
+ GridMesh* mesh;
+ mvector<PrimRef> prims;
+ mvector<SubGridBuildData> sgrids;
+ GeneralBVHBuilder::Settings settings;
+ const unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ unsigned int numPreviousPrimitives = 0;
+
+ BVHNBuilderSAHGrid (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
+ : bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device,0), sgrids(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD) {}
+
+ BVHNBuilderSAHGrid (BVH* bvh, GridMesh* mesh, unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
+ : bvh(bvh), scene(nullptr), mesh(mesh), prims(bvh->device,0), sgrids(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD), geomID_(geomID) {}
+
+ void build()
+ {
+ /* we reset the allocator when the mesh size changed */
+ if (mesh && mesh->numPrimitives != numPreviousPrimitives) {
+ bvh->alloc.clear();
+ }
+
+ /* if we use the primrefarray for allocations we have to take it back from the BVH */
+ if (settings.primrefarrayalloc != size_t(inf))
+ bvh->alloc.unshare(prims);
+
+ const size_t numGridPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(GridMesh::geom_type,false);
+ numPreviousPrimitives = numGridPrimitives;
+
+
+ PrimInfo pinfo = mesh ? createPrimRefArrayGrids(mesh,prims,sgrids) : createPrimRefArrayGrids(scene,prims,sgrids);
+ const size_t numPrimitives = pinfo.size();
+ /* no primitives */
+ if (numPrimitives == 0) {
+ bvh->clear();
+ prims.clear();
+ sgrids.clear();
+ return;
+ }
+
+ double t0 = bvh->preBuild(mesh ? "" : TOSTRING(isa) "::BVH" + toString(N) + "BuilderSAH");
+
+ /* create primref array */
+ settings.primrefarrayalloc = numPrimitives/1000;
+ if (settings.primrefarrayalloc < 1000)
+ settings.primrefarrayalloc = inf;
+
+ /* enable os_malloc for two level build */
+ if (mesh)
+ bvh->alloc.setOSallocation(true);
+
+ /* initialize allocator */
+ const size_t node_bytes = numPrimitives*sizeof(typename BVH::AABBNodeMB)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*(float)numPrimitives/N * sizeof(SubGridQBVHN<N>));
+
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,numPrimitives,node_bytes+leaf_bytes);
+
+ /* pinfo might has zero size due to invalid geometry */
+ if (unlikely(pinfo.size() == 0))
+ {
+ bvh->clear();
+ sgrids.clear();
+ prims.clear();
+ return;
+ }
+
+ /* call BVH builder */
+ NodeRef root = BVHNBuilderVirtual<N>::build(&bvh->alloc,CreateLeafGrid<N,SubGridQBVHN<N>>(bvh,sgrids.data()),bvh->scene->progressInterface,prims.data(),pinfo,settings);
+ bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size());
+ bvh->layoutLargeNodes(size_t(pinfo.size()*0.005f));
+
+ /* clear temporary array */
+ sgrids.clear();
+
+ /* if we allocated using the primrefarray we have to keep it alive */
+ if (settings.primrefarrayalloc != size_t(inf))
+ bvh->alloc.share(prims);
+
+ /* for static geometries we can do some cleanups */
+ else if (scene && scene->isStaticAccel()) {
+ prims.clear();
+ }
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+ void clear() {
+ prims.clear();
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH4Triangle4MeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Triangle4>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH4Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Triangle4v>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH4Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Triangle4i>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+
+ Builder* BVH4Triangle4SceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Triangle4>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH4Triangle4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Triangle4v>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH4Triangle4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Triangle4i>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type,true); }
+
+ Builder* BVH4QuantizedTriangle4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<4,Triangle4i>((BVH4*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+#if defined(__AVX__)
+ Builder* BVH8Triangle4MeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Triangle4>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH8Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Triangle4v>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH8Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Triangle4i>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,TriangleMesh::geom_type); }
+
+ Builder* BVH8Triangle4SceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Triangle4>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH8Triangle4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Triangle4v>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH8Triangle4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Triangle4i>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type,true); }
+ Builder* BVH8QuantizedTriangle4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Triangle4i>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+ Builder* BVH8QuantizedTriangle4SceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Triangle4>((BVH8*)bvh,scene,4,1.0f,4,inf,TriangleMesh::geom_type); }
+
+
+
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4Quad4vMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Quad4v>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH4Quad4iMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,Quad4i>((BVH4*)bvh,mesh,geomID,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH4Quad4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Quad4v>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH4Quad4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<4,Quad4i>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type,true); }
+ Builder* BVH4QuantizedQuad4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<4,Quad4v>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH4QuantizedQuad4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<4,Quad4i>((BVH4*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+
+#if defined(__AVX__)
+ Builder* BVH8Quad4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Quad4v>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH8Quad4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAH<8,Quad4i>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type,true); }
+ Builder* BVH8QuantizedQuad4vSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Quad4v>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH8QuantizedQuad4iSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHQuantized<8,Quad4i>((BVH8*)bvh,scene,4,1.0f,4,inf,QuadMesh::geom_type); }
+ Builder* BVH8Quad4vMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<8,Quad4v>((BVH8*)bvh,mesh,geomID,4,1.0f,4,inf,QuadMesh::geom_type); }
+
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+
+ Builder* BVH4VirtualSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) {
+ int minLeafSize = scene->device->object_accel_min_leaf_size;
+ int maxLeafSize = scene->device->object_accel_max_leaf_size;
+ return new BVHNBuilderSAH<4,Object>((BVH4*)bvh,scene,4,1.0f,minLeafSize,maxLeafSize,UserGeometry::geom_type);
+ }
+
+ Builder* BVH4VirtualMeshBuilderSAH (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) {
+ return new BVHNBuilderSAH<4,Object>((BVH4*)bvh,mesh,geomID,4,1.0f,1,inf,UserGeometry::geom_type);
+ }
+#if defined(__AVX__)
+
+ Builder* BVH8VirtualSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) {
+ int minLeafSize = scene->device->object_accel_min_leaf_size;
+ int maxLeafSize = scene->device->object_accel_max_leaf_size;
+ return new BVHNBuilderSAH<8,Object>((BVH8*)bvh,scene,8,1.0f,minLeafSize,maxLeafSize,UserGeometry::geom_type);
+ }
+
+ Builder* BVH8VirtualMeshBuilderSAH (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) {
+ return new BVHNBuilderSAH<8,Object>((BVH8*)bvh,mesh,geomID,8,1.0f,1,inf,UserGeometry::geom_type);
+ }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH4InstanceSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderSAH<4,InstancePrimitive>((BVH4*)bvh,scene,4,1.0f,1,1,gtype); }
+ Builder* BVH4InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) {
+ return new BVHNBuilderSAH<4,InstancePrimitive>((BVH4*)bvh,mesh,geomID,4,1.0f,1,inf,gtype);
+ }
+#if defined(__AVX__)
+ Builder* BVH8InstanceSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderSAH<8,InstancePrimitive>((BVH8*)bvh,scene,8,1.0f,1,1,gtype); }
+ Builder* BVH8InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) {
+ return new BVHNBuilderSAH<8,InstancePrimitive>((BVH8*)bvh,mesh,geomID,8,1.0f,1,inf,gtype);
+ }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_GRID)
+ Builder* BVH4GridMeshBuilderSAH (void* bvh, GridMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAHGrid<4>((BVH4*)bvh,mesh,geomID,4,1.0f,4,4,mode); }
+ Builder* BVH4GridSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHGrid<4>((BVH4*)bvh,scene,4,1.0f,4,4,mode); } // FIXME: check whether cost factors are correct
+
+#if defined(__AVX__)
+ Builder* BVH8GridMeshBuilderSAH (void* bvh, GridMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNBuilderSAHGrid<8>((BVH8*)bvh,mesh,geomID,8,1.0f,8,8,mode); }
+ Builder* BVH8GridSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderSAHGrid<8>((BVH8*)bvh,scene,8,1.0f,8,8,mode); } // FIXME: check whether cost factors are correct
+#endif
+#endif
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_sah_mb.cpp b/thirdparty/embree/kernels/bvh/bvh_builder_sah_mb.cpp
new file mode 100644
index 0000000000..d163a80ab1
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_builder_sah_mb.cpp
@@ -0,0 +1,705 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "bvh_builder.h"
+#include "../builders/bvh_builder_msmblur.h"
+
+#include "../builders/primrefgen.h"
+#include "../builders/splitter.h"
+
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglev_mb.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+#include "../geometry/subgrid.h"
+
+#include "../common/state.h"
+
+// FIXME: remove after removing BVHNBuilderMBlurRootTimeSplitsSAH
+#include "../../common/algorithms/parallel_for_for.h"
+#include "../../common/algorithms/parallel_for_for_prefix_sum.h"
+
+
+namespace embree
+{
+ namespace isa
+ {
+
+#if 0
+ template<int N, typename Primitive>
+ struct CreateMBlurLeaf
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecordMB NodeRecordMB;
+
+ __forceinline CreateMBlurLeaf (BVH* bvh, PrimRef* prims, size_t time) : bvh(bvh), prims(prims), time(time) {}
+
+ __forceinline NodeRecordMB operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ size_t items = Primitive::blocks(set.size());
+ size_t start = set.begin();
+ for (size_t i=start; i<end; i++) assert((*current.prims.prims)[start].geomID() == (*current.prims.prims)[i].geomID()); // assert that all geomIDs are identical
+ Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteAlignment);
+ NodeRef node = bvh->encodeLeaf((char*)accel,items);
+
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<items; i++)
+ allBounds.extend(accel[i].fillMB(prims, start, set.end(), bvh->scene, time));
+
+ return NodeRecordMB(node,allBounds);
+ }
+
+ BVH* bvh;
+ PrimRef* prims;
+ size_t time;
+ };
+#endif
+
+ template<int N, typename Mesh, typename Primitive>
+ struct CreateMSMBlurLeaf
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecordMB4D NodeRecordMB4D;
+
+ __forceinline CreateMSMBlurLeaf (BVH* bvh) : bvh(bvh) {}
+
+ __forceinline const NodeRecordMB4D operator() (const BVHBuilderMSMBlur::BuildRecord& current, const FastAllocator::CachedAllocator& alloc) const
+ {
+ size_t items = Primitive::blocks(current.prims.size());
+ size_t start = current.prims.begin();
+ size_t end = current.prims.end();
+ for (size_t i=start; i<end; i++) assert((*current.prims.prims)[start].geomID() == (*current.prims.prims)[i].geomID()); // assert that all geomIDs are identical
+ Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteNodeAlignment);
+ NodeRef node = bvh->encodeLeaf((char*)accel,items);
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<items; i++)
+ allBounds.extend(accel[i].fillMB(current.prims.prims->data(), start, current.prims.end(), bvh->scene, current.prims.time_range));
+ return NodeRecordMB4D(node,allBounds,current.prims.time_range);
+ }
+
+ BVH* bvh;
+ };
+
+ /* Motion blur BVH with 4D nodes and internal time splits */
+ template<int N, typename Mesh, typename Primitive>
+ struct BVHNBuilderMBlurSAH : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVHN<N>::NodeRef NodeRef;
+ typedef typename BVHN<N>::NodeRecordMB NodeRecordMB;
+ typedef typename BVHN<N>::AABBNodeMB AABBNodeMB;
+
+ BVH* bvh;
+ Scene* scene;
+ const size_t sahBlockSize;
+ const float intCost;
+ const size_t minLeafSize;
+ const size_t maxLeafSize;
+ const Geometry::GTypeMask gtype_;
+
+ BVHNBuilderMBlurSAH (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const Geometry::GTypeMask gtype)
+ : bvh(bvh), scene(scene), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks)), gtype_(gtype) {}
+
+ void build()
+ {
+ /* skip build for empty scene */
+ const size_t numPrimitives = scene->getNumPrimitives(gtype_,true);
+ if (numPrimitives == 0) { bvh->clear(); return; }
+
+ double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderMBlurSAH");
+
+#if PROFILE
+ profile(2,PROFILE_RUNS,numPrimitives,[&] (ProfileTimer& timer) {
+#endif
+
+ //const size_t numTimeSteps = scene->getNumTimeSteps<typename Mesh::type_t,true>();
+ //const size_t numTimeSegments = numTimeSteps-1; assert(numTimeSteps > 1);
+
+ /*if (numTimeSegments == 1)
+ buildSingleSegment(numPrimitives);
+ else*/
+ buildMultiSegment(numPrimitives);
+
+#if PROFILE
+ });
+#endif
+
+ /* clear temporary data for static geometry */
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+#if 0 // No longer compatible when time_ranges are present for geometries. Would have to create temporal nodes sometimes, and put only a single geometry into leaf.
+ void buildSingleSegment(size_t numPrimitives)
+ {
+ /* create primref array */
+ mvector<PrimRef> prims(scene->device,numPrimitives);
+ const PrimInfo pinfo = createPrimRefArrayMBlur(scene,gtype_,numPrimitives,prims,bvh->scene->progressInterface,0);
+ /* early out if no valid primitives */
+ if (pinfo.size() == 0) { bvh->clear(); return; }
+ /* estimate acceleration structure size */
+ const size_t node_bytes = pinfo.size()*sizeof(AABBNodeMB)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.size())*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+
+ /* settings for BVH build */
+ GeneralBVHBuilder::Settings settings;
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ settings.logBlockSize = bsr(sahBlockSize);
+ settings.minLeafSize = min(minLeafSize,maxLeafSize);
+ settings.maxLeafSize = maxLeafSize;
+ settings.travCost = travCost;
+ settings.intCost = intCost;
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ /* build hierarchy */
+ auto root = BVHBuilderBinnedSAH::build<NodeRecordMB>
+ (typename BVH::CreateAlloc(bvh),typename BVH::AABBNodeMB::Create(),typename BVH::AABBNodeMB::Set(),
+ CreateMBlurLeaf<N,Primitive>(bvh,prims.data(),0),bvh->scene->progressInterface,
+ prims.data(),pinfo,settings);
+
+ bvh->set(root.ref,root.lbounds,pinfo.size());
+ }
+#endif
+
+ void buildMultiSegment(size_t numPrimitives)
+ {
+ /* create primref array */
+ mvector<PrimRefMB> prims(scene->device,numPrimitives);
+ PrimInfoMB pinfo = createPrimRefArrayMSMBlur(scene,gtype_,numPrimitives,prims,bvh->scene->progressInterface);
+
+ /* early out if no valid primitives */
+ if (pinfo.size() == 0) { bvh->clear(); return; }
+
+ /* estimate acceleration structure size */
+ const size_t node_bytes = pinfo.num_time_segments*sizeof(AABBNodeMB)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.num_time_segments)*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+
+ /* settings for BVH build */
+ BVHBuilderMSMBlur::Settings settings;
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxDepth;
+ settings.logBlockSize = bsr(sahBlockSize);
+ settings.minLeafSize = min(minLeafSize,maxLeafSize);
+ settings.maxLeafSize = maxLeafSize;
+ settings.travCost = travCost;
+ settings.intCost = intCost;
+ settings.singleLeafTimeSegment = Primitive::singleTimeSegment;
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ /* build hierarchy */
+ auto root =
+ BVHBuilderMSMBlur::build<NodeRef>(prims,pinfo,scene->device,
+ RecalculatePrimRef<Mesh>(scene),
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNodeMB4D::Create(),
+ typename BVH::AABBNodeMB4D::Set(),
+ CreateMSMBlurLeaf<N,Mesh,Primitive>(bvh),
+ bvh->scene->progressInterface,
+ settings);
+
+ bvh->set(root.ref,root.lbounds,pinfo.num_time_segments);
+ }
+
+ void clear() {
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+ struct GridRecalculatePrimRef
+ {
+ Scene* scene;
+ const SubGridBuildData * const sgrids;
+
+ __forceinline GridRecalculatePrimRef (Scene* scene, const SubGridBuildData * const sgrids)
+ : scene(scene), sgrids(sgrids) {}
+
+ __forceinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range) const
+ {
+ const unsigned int geomID = prim.geomID();
+ const GridMesh* mesh = scene->get<GridMesh>(geomID);
+ const unsigned int buildID = prim.primID();
+ const SubGridBuildData &subgrid = sgrids[buildID];
+ const unsigned int primID = subgrid.primID;
+ const size_t x = subgrid.x();
+ const size_t y = subgrid.y();
+ const LBBox3fa lbounds = mesh->linearBounds(mesh->grid(primID),x,y,time_range);
+ const unsigned num_time_segments = mesh->numTimeSegments();
+ const range<int> tbounds = mesh->timeSegmentRange(time_range);
+ return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, num_time_segments, geomID, buildID);
+ }
+
+ __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range) const {
+ const unsigned int geomID = prim.geomID();
+ const GridMesh* mesh = scene->get<GridMesh>(geomID);
+ const unsigned int buildID = prim.primID();
+ const SubGridBuildData &subgrid = sgrids[buildID];
+ const unsigned int primID = subgrid.primID;
+ const size_t x = subgrid.x();
+ const size_t y = subgrid.y();
+ return mesh->linearBounds(mesh->grid(primID),x,y,time_range);
+ }
+
+ };
+
+ template<int N>
+ struct CreateMSMBlurLeafGrid
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecordMB4D NodeRecordMB4D;
+
+ __forceinline CreateMSMBlurLeafGrid (Scene* scene, BVH* bvh, const SubGridBuildData * const sgrids) : scene(scene), bvh(bvh), sgrids(sgrids) {}
+
+ __forceinline const NodeRecordMB4D operator() (const BVHBuilderMSMBlur::BuildRecord& current, const FastAllocator::CachedAllocator& alloc) const
+ {
+ const size_t items = current.prims.size();
+ const size_t start = current.prims.begin();
+
+ const PrimRefMB* prims = current.prims.prims->data();
+ /* collect all subsets with unique geomIDs */
+ assert(items <= N);
+ unsigned int geomIDs[N];
+ unsigned int num_geomIDs = 1;
+ geomIDs[0] = prims[start].geomID();
+
+ for (size_t i=1;i<items;i++)
+ {
+ bool found = false;
+ const unsigned int new_geomID = prims[start+i].geomID();
+ for (size_t j=0;j<num_geomIDs;j++)
+ if (new_geomID == geomIDs[j])
+ { found = true; break; }
+ if (!found)
+ geomIDs[num_geomIDs++] = new_geomID;
+ }
+
+ /* allocate all leaf memory in one single block */
+ SubGridMBQBVHN<N>* accel = (SubGridMBQBVHN<N>*) alloc.malloc1(num_geomIDs*sizeof(SubGridMBQBVHN<N>),BVH::byteAlignment);
+ typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel,num_geomIDs);
+
+ LBBox3fa allBounds = empty;
+
+ for (size_t g=0;g<num_geomIDs;g++)
+ {
+ const GridMesh* __restrict__ const mesh = scene->get<GridMesh>(geomIDs[g]);
+ unsigned int x[N];
+ unsigned int y[N];
+ unsigned int primID[N];
+ BBox3fa bounds0[N];
+ BBox3fa bounds1[N];
+ unsigned int pos = 0;
+ for (size_t i=0;i<items;i++)
+ {
+ if (unlikely(prims[start+i].geomID() != geomIDs[g])) continue;
+
+ const SubGridBuildData &sgrid_bd = sgrids[prims[start+i].primID()];
+ x[pos] = sgrid_bd.sx;
+ y[pos] = sgrid_bd.sy;
+ primID[pos] = sgrid_bd.primID;
+ const size_t x = sgrid_bd.x();
+ const size_t y = sgrid_bd.y();
+ LBBox3fa newBounds = mesh->linearBounds(mesh->grid(sgrid_bd.primID),x,y,current.prims.time_range);
+ allBounds.extend(newBounds);
+ bounds0[pos] = newBounds.bounds0;
+ bounds1[pos] = newBounds.bounds1;
+ pos++;
+ }
+ assert(pos <= N);
+ new (&accel[g]) SubGridMBQBVHN<N>(x,y,primID,bounds0,bounds1,geomIDs[g],current.prims.time_range.lower,1.0f/current.prims.time_range.size(),pos);
+ }
+ return NodeRecordMB4D(node,allBounds,current.prims.time_range);
+ }
+
+ Scene *scene;
+ BVH* bvh;
+ const SubGridBuildData * const sgrids;
+ };
+
+#if 0
+ template<int N>
+ struct CreateLeafGridMB
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::NodeRecordMB NodeRecordMB;
+
+ __forceinline CreateLeafGridMB (Scene* scene, BVH* bvh, const SubGridBuildData * const sgrids)
+ : scene(scene), bvh(bvh), sgrids(sgrids) {}
+
+ __forceinline NodeRecordMB operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ const size_t items = set.size();
+ const size_t start = set.begin();
+
+ /* collect all subsets with unique geomIDs */
+ assert(items <= N);
+ unsigned int geomIDs[N];
+ unsigned int num_geomIDs = 1;
+ geomIDs[0] = prims[start].geomID();
+
+ for (size_t i=1;i<items;i++)
+ {
+ bool found = false;
+ const unsigned int new_geomID = prims[start+i].geomID();
+ for (size_t j=0;j<num_geomIDs;j++)
+ if (new_geomID == geomIDs[j])
+ { found = true; break; }
+ if (!found)
+ geomIDs[num_geomIDs++] = new_geomID;
+ }
+
+ /* allocate all leaf memory in one single block */
+ SubGridMBQBVHN<N>* accel = (SubGridMBQBVHN<N>*) alloc.malloc1(num_geomIDs*sizeof(SubGridMBQBVHN<N>),BVH::byteAlignment);
+ typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel,num_geomIDs);
+
+ LBBox3fa allBounds = empty;
+
+ for (size_t g=0;g<num_geomIDs;g++)
+ {
+ const GridMesh* __restrict__ const mesh = scene->get<GridMesh>(geomIDs[g]);
+
+ unsigned int x[N];
+ unsigned int y[N];
+ unsigned int primID[N];
+ BBox3fa bounds0[N];
+ BBox3fa bounds1[N];
+ unsigned int pos = 0;
+ for (size_t i=0;i<items;i++)
+ {
+ if (unlikely(prims[start+i].geomID() != geomIDs[g])) continue;
+
+ const SubGridBuildData &sgrid_bd = sgrids[prims[start+i].primID()];
+ x[pos] = sgrid_bd.sx;
+ y[pos] = sgrid_bd.sy;
+ primID[pos] = sgrid_bd.primID;
+ const size_t x = sgrid_bd.x();
+ const size_t y = sgrid_bd.y();
+ bool MAYBE_UNUSED valid0 = mesh->buildBounds(mesh->grid(sgrid_bd.primID),x,y,0,bounds0[pos]);
+ bool MAYBE_UNUSED valid1 = mesh->buildBounds(mesh->grid(sgrid_bd.primID),x,y,1,bounds1[pos]);
+ assert(valid0);
+ assert(valid1);
+ allBounds.extend(LBBox3fa(bounds0[pos],bounds1[pos]));
+ pos++;
+ }
+ new (&accel[g]) SubGridMBQBVHN<N>(x,y,primID,bounds0,bounds1,geomIDs[g],0.0f,1.0f,pos);
+ }
+ return NodeRecordMB(node,allBounds);
+ }
+
+ Scene *scene;
+ BVH* bvh;
+ const SubGridBuildData * const sgrids;
+ };
+#endif
+
+
+ /* Motion blur BVH with 4D nodes and internal time splits */
+ template<int N>
+ struct BVHNBuilderMBlurSAHGrid : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVHN<N>::NodeRef NodeRef;
+ typedef typename BVHN<N>::NodeRecordMB NodeRecordMB;
+ typedef typename BVHN<N>::AABBNodeMB AABBNodeMB;
+
+ BVH* bvh;
+ Scene* scene;
+ const size_t sahBlockSize;
+ const float intCost;
+ const size_t minLeafSize;
+ const size_t maxLeafSize;
+ mvector<SubGridBuildData> sgrids;
+
+
+ BVHNBuilderMBlurSAHGrid (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize)
+ : bvh(bvh), scene(scene), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,BVH::maxLeafBlocks)), sgrids(scene->device,0) {}
+
+
+ PrimInfo createPrimRefArrayMBlurGrid(Scene* scene, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor, size_t itime)
+ {
+ /* first run to get #primitives */
+ ParallelForForPrefixSumState<PrimInfo> pstate;
+ Scene::Iterator<GridMesh,true> iter(scene);
+
+ pstate.init(iter,size_t(1024));
+
+ /* iterate over all meshes in the scene */
+ PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo {
+
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j,range<size_t>(0,1))) continue;
+ BBox3fa bounds = empty;
+ const PrimRef prim(bounds,unsigned(geomID),unsigned(j));
+ pinfo.add_center2(prim,mesh->getNumSubGrids(j));
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ size_t numPrimitives = pinfo.size();
+ if (numPrimitives == 0) return pinfo;
+
+ /* resize arrays */
+ sgrids.resize(numPrimitives);
+ prims.resize(numPrimitives);
+
+ /* second run to fill primrefs and SubGridBuildData arrays */
+ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo {
+
+ k = base.size();
+ size_t p_index = k;
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ const GridMesh::Grid &g = mesh->grid(j);
+ if (!mesh->valid(j,range<size_t>(0,1))) continue;
+
+ for (unsigned int y=0; y<g.resY-1u; y+=2)
+ for (unsigned int x=0; x<g.resX-1u; x+=2)
+ {
+ BBox3fa bounds = empty;
+ if (!mesh->buildBounds(g,x,y,itime,bounds)) continue; // get bounds of subgrid
+ const PrimRef prim(bounds,unsigned(geomID),unsigned(p_index));
+ pinfo.add_center2(prim);
+ sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j));
+ prims[p_index++] = prim;
+ }
+ }
+ return pinfo;
+ }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); });
+
+ assert(pinfo.size() == numPrimitives);
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefArrayMSMBlurGrid(Scene* scene, mvector<PrimRefMB>& prims, BuildProgressMonitor& progressMonitor, BBox1f t0t1 = BBox1f(0.0f,1.0f))
+ {
+ /* first run to get #primitives */
+ ParallelForForPrefixSumState<PrimInfoMB> pstate;
+ Scene::Iterator<GridMesh,true> iter(scene);
+
+ pstate.init(iter,size_t(1024));
+ /* iterate over all meshes in the scene */
+ PrimInfoMB pinfoMB = parallel_for_for_prefix_sum0( pstate, iter, PrimInfoMB(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t /*geomID*/) -> PrimInfoMB {
+
+ PrimInfoMB pinfoMB(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j, mesh->timeSegmentRange(t0t1))) continue;
+ LBBox3fa bounds(empty);
+ PrimInfoMB gridMB(0,mesh->getNumSubGrids(j));
+ pinfoMB.merge(gridMB);
+ }
+ return pinfoMB;
+ }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); });
+
+ size_t numPrimitives = pinfoMB.size();
+ if (numPrimitives == 0) return pinfoMB;
+
+ /* resize arrays */
+ sgrids.resize(numPrimitives);
+ prims.resize(numPrimitives);
+ /* second run to fill primrefs and SubGridBuildData arrays */
+ pinfoMB = parallel_for_for_prefix_sum1( pstate, iter, PrimInfoMB(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfoMB& base) -> PrimInfoMB {
+
+ k = base.size();
+ size_t p_index = k;
+ PrimInfoMB pinfoMB(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!mesh->valid(j, mesh->timeSegmentRange(t0t1))) continue;
+ const GridMesh::Grid &g = mesh->grid(j);
+
+ for (unsigned int y=0; y<g.resY-1u; y+=2)
+ for (unsigned int x=0; x<g.resX-1u; x+=2)
+ {
+ const PrimRefMB prim(mesh->linearBounds(g,x,y,t0t1),mesh->numTimeSegments(),mesh->time_range,mesh->numTimeSegments(),unsigned(geomID),unsigned(p_index));
+ pinfoMB.add_primref(prim);
+ sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j));
+ prims[p_index++] = prim;
+ }
+ }
+ return pinfoMB;
+ }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); });
+
+ assert(pinfoMB.size() == numPrimitives);
+ pinfoMB.time_range = t0t1;
+ return pinfoMB;
+ }
+
+ void build()
+ {
+ /* skip build for empty scene */
+ const size_t numPrimitives = scene->getNumPrimitives(GridMesh::geom_type,true);
+ if (numPrimitives == 0) { bvh->clear(); return; }
+
+ double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderMBlurSAHGrid");
+
+ //const size_t numTimeSteps = scene->getNumTimeSteps<GridMesh,true>();
+ //const size_t numTimeSegments = numTimeSteps-1; assert(numTimeSteps > 1);
+ //if (numTimeSegments == 1)
+ // buildSingleSegment(numPrimitives);
+ //else
+ buildMultiSegment(numPrimitives);
+
+ /* clear temporary data for static geometry */
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+#if 0
+ void buildSingleSegment(size_t numPrimitives)
+ {
+ /* create primref array */
+ mvector<PrimRef> prims(scene->device,numPrimitives);
+ const PrimInfo pinfo = createPrimRefArrayMBlurGrid(scene,prims,bvh->scene->progressInterface,0);
+ /* early out if no valid primitives */
+ if (pinfo.size() == 0) { bvh->clear(); return; }
+
+ /* estimate acceleration structure size */
+ const size_t node_bytes = pinfo.size()*sizeof(AABBNodeMB)/(4*N);
+ //TODO: check leaf_bytes
+ const size_t leaf_bytes = size_t(1.2*(float)numPrimitives/N * sizeof(SubGridQBVHN<N>));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+
+ /* settings for BVH build */
+ GeneralBVHBuilder::Settings settings;
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ settings.logBlockSize = bsr(sahBlockSize);
+ settings.minLeafSize = min(minLeafSize,maxLeafSize);
+ settings.maxLeafSize = maxLeafSize;
+ settings.travCost = travCost;
+ settings.intCost = intCost;
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ /* build hierarchy */
+ auto root = BVHBuilderBinnedSAH::build<NodeRecordMB>
+ (typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNodeMB::Create(),
+ typename BVH::AABBNodeMB::Set(),
+ CreateLeafGridMB<N>(scene,bvh,sgrids.data()),
+ bvh->scene->progressInterface,
+ prims.data(),pinfo,settings);
+
+ bvh->set(root.ref,root.lbounds,pinfo.size());
+ }
+#endif
+
+ void buildMultiSegment(size_t numPrimitives)
+ {
+ /* create primref array */
+ mvector<PrimRefMB> prims(scene->device,numPrimitives);
+ PrimInfoMB pinfo = createPrimRefArrayMSMBlurGrid(scene,prims,bvh->scene->progressInterface);
+
+ /* early out if no valid primitives */
+ if (pinfo.size() == 0) { bvh->clear(); return; }
+
+
+
+ GridRecalculatePrimRef recalculatePrimRef(scene,sgrids.data());
+
+ /* estimate acceleration structure size */
+ const size_t node_bytes = pinfo.num_time_segments*sizeof(AABBNodeMB)/(4*N);
+ //FIXME: check leaf_bytes
+ //const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.num_time_segments)*sizeof(SubGridQBVHN<N>));
+ const size_t leaf_bytes = size_t(1.2*(float)numPrimitives/N * sizeof(SubGridQBVHN<N>));
+
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+
+ /* settings for BVH build */
+ BVHBuilderMSMBlur::Settings settings;
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxDepth;
+ settings.logBlockSize = bsr(sahBlockSize);
+ settings.minLeafSize = min(minLeafSize,maxLeafSize);
+ settings.maxLeafSize = maxLeafSize;
+ settings.travCost = travCost;
+ settings.intCost = intCost;
+ settings.singleLeafTimeSegment = false;
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ /* build hierarchy */
+ auto root =
+ BVHBuilderMSMBlur::build<NodeRef>(prims,pinfo,scene->device,
+ recalculatePrimRef,
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNodeMB4D::Create(),
+ typename BVH::AABBNodeMB4D::Set(),
+ CreateMSMBlurLeafGrid<N>(scene,bvh,sgrids.data()),
+ bvh->scene->progressInterface,
+ settings);
+ bvh->set(root.ref,root.lbounds,pinfo.num_time_segments);
+ }
+
+ void clear() {
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH4Triangle4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<4,TriangleMesh,Triangle4i>((BVH4*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); }
+ Builder* BVH4Triangle4vMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<4,TriangleMesh,Triangle4vMB>((BVH4*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); }
+#if defined(__AVX__)
+ Builder* BVH8Triangle4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<8,TriangleMesh,Triangle4i>((BVH8*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); }
+ Builder* BVH8Triangle4vMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<8,TriangleMesh,Triangle4vMB>((BVH8*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_TRIANGLE_MESH); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4Quad4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<4,QuadMesh,Quad4i>((BVH4*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_QUAD_MESH); }
+#if defined(__AVX__)
+ Builder* BVH8Quad4iMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAH<8,QuadMesh,Quad4i>((BVH8*)bvh,scene,4,1.0f,4,inf,Geometry::MTY_QUAD_MESH); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ Builder* BVH4VirtualMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) {
+ int minLeafSize = scene->device->object_accel_mb_min_leaf_size;
+ int maxLeafSize = scene->device->object_accel_mb_max_leaf_size;
+ return new BVHNBuilderMBlurSAH<4,UserGeometry,Object>((BVH4*)bvh,scene,4,1.0f,minLeafSize,maxLeafSize,Geometry::MTY_USER_GEOMETRY);
+ }
+#if defined(__AVX__)
+ Builder* BVH8VirtualMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) {
+ int minLeafSize = scene->device->object_accel_mb_min_leaf_size;
+ int maxLeafSize = scene->device->object_accel_mb_max_leaf_size;
+ return new BVHNBuilderMBlurSAH<8,UserGeometry,Object>((BVH8*)bvh,scene,8,1.0f,minLeafSize,maxLeafSize,Geometry::MTY_USER_GEOMETRY);
+ }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH4InstanceMBSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderMBlurSAH<4,Instance,InstancePrimitive>((BVH4*)bvh,scene,4,1.0f,1,1,gtype); }
+#if defined(__AVX__)
+ Builder* BVH8InstanceMBSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderMBlurSAH<8,Instance,InstancePrimitive>((BVH8*)bvh,scene,8,1.0f,1,1,gtype); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_GRID)
+ Builder* BVH4GridMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAHGrid<4>((BVH4*)bvh,scene,4,1.0f,4,4); }
+#if defined(__AVX__)
+ Builder* BVH8GridMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAHGrid<8>((BVH8*)bvh,scene,8,1.0f,8,8); }
+#endif
+#endif
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_sah_spatial.cpp b/thirdparty/embree/kernels/bvh/bvh_builder_sah_spatial.cpp
new file mode 100644
index 0000000000..a4e55d7484
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_builder_sah_spatial.cpp
@@ -0,0 +1,201 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh.h"
+#include "bvh_builder.h"
+
+#include "../builders/primrefgen.h"
+#include "../builders/primrefgen_presplit.h"
+#include "../builders/splitter.h"
+
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglev_mb.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+#include "../geometry/subgrid.h"
+
+#include "../common/state.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, typename Primitive>
+ struct CreateLeafSpatial
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+
+ __forceinline CreateLeafSpatial (BVH* bvh) : bvh(bvh) {}
+
+ __forceinline NodeRef operator() (const PrimRef* prims, const range<size_t>& set, const FastAllocator::CachedAllocator& alloc) const
+ {
+ size_t n = set.size();
+ size_t items = Primitive::blocks(n);
+ size_t start = set.begin();
+ Primitive* accel = (Primitive*) alloc.malloc1(items*sizeof(Primitive),BVH::byteAlignment);
+ typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,items);
+ for (size_t i=0; i<items; i++) {
+ accel[i].fill(prims,start,set.end(),bvh->scene);
+ }
+ return node;
+ }
+
+ BVH* bvh;
+ };
+
+ template<int N, typename Mesh, typename Primitive, typename Splitter>
+ struct BVHNBuilderFastSpatialSAH : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ BVH* bvh;
+ Scene* scene;
+ Mesh* mesh;
+ mvector<PrimRef> prims0;
+ GeneralBVHBuilder::Settings settings;
+ const float splitFactor;
+ unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
+ unsigned int numPreviousPrimitives = 0;
+
+ BVHNBuilderFastSpatialSAH (BVH* bvh, Scene* scene, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
+ : bvh(bvh), scene(scene), mesh(nullptr), prims0(scene->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD),
+ splitFactor(scene->device->max_spatial_split_replications) {}
+
+ BVHNBuilderFastSpatialSAH (BVH* bvh, Mesh* mesh, const unsigned int geomID, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
+ : bvh(bvh), scene(nullptr), mesh(mesh), prims0(bvh->device,0), settings(sahBlockSize, minLeafSize, min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks), travCost, intCost, DEFAULT_SINGLE_THREAD_THRESHOLD),
+ splitFactor(scene->device->max_spatial_split_replications), geomID_(geomID) {}
+
+ // FIXME: shrink bvh->alloc in destructor here and in other builders too
+
+ void build()
+ {
+ /* we reset the allocator when the mesh size changed */
+ if (mesh && mesh->numPrimitives != numPreviousPrimitives) {
+ bvh->alloc.clear();
+ }
+
+ /* skip build for empty scene */
+ const size_t numOriginalPrimitives = mesh ? mesh->size() : scene->getNumPrimitives(Mesh::geom_type,false);
+ numPreviousPrimitives = numOriginalPrimitives;
+ if (numOriginalPrimitives == 0) {
+ prims0.clear();
+ bvh->clear();
+ return;
+ }
+
+ const unsigned int maxGeomID = mesh ? geomID_ : scene->getMaxGeomID<Mesh,false>();
+ const bool usePreSplits = scene->device->useSpatialPreSplits || (maxGeomID >= ((unsigned int)1 << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS)));
+ double t0 = bvh->preBuild(mesh ? "" : TOSTRING(isa) "::BVH" + toString(N) + (usePreSplits ? "BuilderFastSpatialPresplitSAH" : "BuilderFastSpatialSAH"));
+
+ /* create primref array */
+ const size_t numSplitPrimitives = max(numOriginalPrimitives,size_t(splitFactor*numOriginalPrimitives));
+ prims0.resize(numSplitPrimitives);
+
+ /* enable os_malloc for two level build */
+ if (mesh)
+ bvh->alloc.setOSallocation(true);
+
+ NodeRef root(0);
+ PrimInfo pinfo;
+
+
+ if (likely(usePreSplits))
+ {
+ /* spatial presplit SAH BVH builder */
+ pinfo = mesh ?
+ createPrimRefArray_presplit<Mesh,Splitter>(mesh,maxGeomID,numOriginalPrimitives,prims0,bvh->scene->progressInterface) :
+ createPrimRefArray_presplit<Mesh,Splitter>(scene,Mesh::geom_type,false,numOriginalPrimitives,prims0,bvh->scene->progressInterface);
+
+ const size_t node_bytes = pinfo.size()*sizeof(typename BVH::AABBNode)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.size())*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+
+ /* call BVH builder */
+ root = BVHNBuilderVirtual<N>::build(&bvh->alloc,CreateLeafSpatial<N,Primitive>(bvh),bvh->scene->progressInterface,prims0.data(),pinfo,settings);
+ }
+ else
+ {
+ /* standard spatial split SAH BVH builder */
+ pinfo = mesh ?
+ createPrimRefArray(mesh,geomID_,numSplitPrimitives,prims0,bvh->scene->progressInterface) :
+ createPrimRefArray(scene,Mesh::geom_type,false,numSplitPrimitives,prims0,bvh->scene->progressInterface);
+
+ Splitter splitter(scene);
+
+ const size_t node_bytes = pinfo.size()*sizeof(typename BVH::AABBNode)/(4*N);
+ const size_t leaf_bytes = size_t(1.2*Primitive::blocks(pinfo.size())*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+ settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,pinfo.size(),node_bytes+leaf_bytes);
+
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+
+ /* call BVH builder */
+ root = BVHBuilderBinnedFastSpatialSAH::build<NodeRef>(
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNode::Create2(),
+ typename BVH::AABBNode::Set2(),
+ CreateLeafSpatial<N,Primitive>(bvh),
+ splitter,
+ bvh->scene->progressInterface,
+ prims0.data(),
+ numSplitPrimitives,
+ pinfo,settings);
+
+ /* ==================== */
+ }
+
+ bvh->set(root,LBBox3fa(pinfo.geomBounds),pinfo.size());
+ bvh->layoutLargeNodes(size_t(pinfo.size()*0.005f));
+
+ /* clear temporary data for static geometry */
+ if (scene && scene->isStaticAccel()) {
+ prims0.clear();
+ }
+ bvh->cleanup();
+ bvh->postBuild(t0);
+ }
+
+ void clear() {
+ prims0.clear();
+ }
+ };
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+
+ Builder* BVH4Triangle4SceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<4,TriangleMesh,Triangle4,TriangleSplitterFactory>((BVH4*)bvh,scene,4,1.0f,4,inf,mode); }
+ Builder* BVH4Triangle4vSceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<4,TriangleMesh,Triangle4v,TriangleSplitterFactory>((BVH4*)bvh,scene,4,1.0f,4,inf,mode); }
+ Builder* BVH4Triangle4iSceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<4,TriangleMesh,Triangle4i,TriangleSplitterFactory>((BVH4*)bvh,scene,4,1.0f,4,inf,mode); }
+
+#if defined(__AVX__)
+ Builder* BVH8Triangle4SceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<8,TriangleMesh,Triangle4,TriangleSplitterFactory>((BVH8*)bvh,scene,4,1.0f,4,inf,mode); }
+ Builder* BVH8Triangle4vSceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<8,TriangleMesh,Triangle4v,TriangleSplitterFactory>((BVH8*)bvh,scene,4,1.0f,4,inf,mode); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4Quad4vSceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<4,QuadMesh,Quad4v,QuadSplitterFactory>((BVH4*)bvh,scene,4,1.0f,4,inf,mode); }
+
+#if defined(__AVX__)
+ Builder* BVH8Quad4vSceneBuilderFastSpatialSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderFastSpatialSAH<8,QuadMesh,Quad4v,QuadSplitterFactory>((BVH8*)bvh,scene,4,1.0f,4,inf,mode); }
+#endif
+
+#endif
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.cpp b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.cpp
new file mode 100644
index 0000000000..5d45ed3748
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.cpp
@@ -0,0 +1,369 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_builder_twolevel.h"
+#include "bvh_statistics.h"
+#include "../builders/bvh_builder_sah.h"
+#include "../common/scene_line_segments.h"
+#include "../common/scene_triangle_mesh.h"
+#include "../common/scene_quad_mesh.h"
+
+#define PROFILE 0
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, typename Mesh, typename Primitive>
+ BVHNBuilderTwoLevel<N,Mesh,Primitive>::BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder, const size_t singleThreadThreshold)
+ : bvh(bvh), scene(scene), refs(scene->device,0), prims(scene->device,0), singleThreadThreshold(singleThreadThreshold), gtype(gtype), useMortonBuilder_(useMortonBuilder) {}
+
+ template<int N, typename Mesh, typename Primitive>
+ BVHNBuilderTwoLevel<N,Mesh,Primitive>::~BVHNBuilderTwoLevel () {
+ }
+
+ // ===========================================================================
+ // ===========================================================================
+ // ===========================================================================
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::build()
+ {
+ /* delete some objects */
+ size_t num = scene->size();
+ if (num < bvh->objects.size()) {
+ parallel_for(num, bvh->objects.size(), [&] (const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ builders[i].reset();
+ delete bvh->objects[i]; bvh->objects[i] = nullptr;
+ }
+ });
+ }
+
+#if PROFILE
+ while(1)
+#endif
+ {
+ /* reset memory allocator */
+ bvh->alloc.reset();
+
+ /* skip build for empty scene */
+ const size_t numPrimitives = scene->getNumPrimitives(gtype,false);
+
+ if (numPrimitives == 0) {
+ prims.resize(0);
+ bvh->set(BVH::emptyNode,empty,0);
+ return;
+ }
+
+ /* calculate the size of the entire BVH */
+ const size_t numLeafBlocks = Primitive::blocks(numPrimitives);
+ const size_t node_bytes = 2*numLeafBlocks*sizeof(typename BVH::AABBNode)/N;
+ const size_t leaf_bytes = size_t(1.2*numLeafBlocks*sizeof(Primitive));
+ bvh->alloc.init_estimate(node_bytes+leaf_bytes);
+
+ double t0 = bvh->preBuild(TOSTRING(isa) "::BVH" + toString(N) + "BuilderTwoLevel");
+
+ /* resize object array if scene got larger */
+ if (bvh->objects.size() < num) bvh->objects.resize(num);
+ if (builders.size() < num) builders.resize(num);
+ resizeRefsList ();
+ nextRef.store(0);
+
+ /* create acceleration structures */
+ parallel_for(size_t(0), num, [&] (const range<size_t>& r)
+ {
+ for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
+ {
+ Mesh* mesh = scene->getSafe<Mesh>(objectID);
+
+ /* ignore meshes we do not support */
+ if (mesh == nullptr || mesh->numTimeSteps != 1)
+ continue;
+
+ if (isSmallGeometry(mesh)) {
+ setupSmallBuildRefBuilder (objectID, mesh);
+ } else {
+ setupLargeBuildRefBuilder (objectID, mesh);
+ }
+ }
+ });
+
+ /* parallel build of acceleration structures */
+ parallel_for(size_t(0), num, [&] (const range<size_t>& r)
+ {
+ for (size_t objectID=r.begin(); objectID<r.end(); objectID++)
+ {
+ /* ignore if no triangle mesh or not enabled */
+ Mesh* mesh = scene->getSafe<Mesh>(objectID);
+ if (mesh == nullptr || !mesh->isEnabled() || mesh->numTimeSteps != 1)
+ continue;
+
+ builders[objectID]->attachBuildRefs (this);
+ }
+ });
+
+
+#if PROFILE
+ double d0 = getSeconds();
+#endif
+ /* fast path for single geometry scenes */
+ if (nextRef == 1) {
+ bvh->set(refs[0].node,LBBox3fa(refs[0].bounds()),numPrimitives);
+ }
+
+ else
+ {
+ /* open all large nodes */
+ refs.resize(nextRef);
+
+ /* this probably needs some more tuning */
+ const size_t extSize = max(max((size_t)SPLIT_MIN_EXT_SPACE,refs.size()*SPLIT_MEMORY_RESERVE_SCALE),size_t((float)numPrimitives / SPLIT_MEMORY_RESERVE_FACTOR));
+
+#if !ENABLE_DIRECT_SAH_MERGE_BUILDER
+
+#if ENABLE_OPEN_SEQUENTIAL
+ open_sequential(extSize);
+#endif
+ /* compute PrimRefs */
+ prims.resize(refs.size());
+#endif
+
+ {
+#if ENABLE_DIRECT_SAH_MERGE_BUILDER
+
+ const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(), PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo {
+
+ PrimInfo pinfo(empty);
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ pinfo.add_center2(refs[i]);
+ }
+ return pinfo;
+ }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });
+
+#else
+ const PrimInfo pinfo = parallel_reduce(size_t(0), refs.size(), PrimInfo(empty), [&] (const range<size_t>& r) -> PrimInfo {
+
+ PrimInfo pinfo(empty);
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ pinfo.add_center2(refs[i]);
+ prims[i] = PrimRef(refs[i].bounds(),(size_t)refs[i].node);
+ }
+ return pinfo;
+ }, [] (const PrimInfo& a, const PrimInfo& b) { return PrimInfo::merge(a,b); });
+#endif
+
+ /* skip if all objects where empty */
+ if (pinfo.size() == 0)
+ bvh->set(BVH::emptyNode,empty,0);
+
+ /* otherwise build toplevel hierarchy */
+ else
+ {
+ /* settings for BVH build */
+ GeneralBVHBuilder::Settings settings;
+ settings.branchingFactor = N;
+ settings.maxDepth = BVH::maxBuildDepthLeaf;
+ settings.logBlockSize = bsr(N);
+ settings.minLeafSize = 1;
+ settings.maxLeafSize = 1;
+ settings.travCost = 1.0f;
+ settings.intCost = 1.0f;
+ settings.singleThreadThreshold = singleThreadThreshold;
+
+#if ENABLE_DIRECT_SAH_MERGE_BUILDER
+
+ refs.resize(extSize);
+
+ NodeRef root = BVHBuilderBinnedOpenMergeSAH::build<NodeRef,BuildRef>(
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNode::Create2(),
+ typename BVH::AABBNode::Set2(),
+
+ [&] (const BuildRef* refs, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> NodeRef {
+ assert(range.size() == 1);
+ return (NodeRef) refs[range.begin()].node;
+ },
+ [&] (BuildRef &bref, BuildRef *refs) -> size_t {
+ return openBuildRef(bref,refs);
+ },
+ [&] (size_t dn) { bvh->scene->progressMonitor(0); },
+ refs.data(),extSize,pinfo,settings);
+#else
+ NodeRef root = BVHBuilderBinnedSAH::build<NodeRef>(
+ typename BVH::CreateAlloc(bvh),
+ typename BVH::AABBNode::Create2(),
+ typename BVH::AABBNode::Set2(),
+
+ [&] (const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> NodeRef {
+ assert(range.size() == 1);
+ return (NodeRef) prims[range.begin()].ID();
+ },
+ [&] (size_t dn) { bvh->scene->progressMonitor(0); },
+ prims.data(),pinfo,settings);
+#endif
+
+
+ bvh->set(root,LBBox3fa(pinfo.geomBounds),numPrimitives);
+ }
+ }
+ }
+
+ bvh->alloc.cleanup();
+ bvh->postBuild(t0);
+#if PROFILE
+ double d1 = getSeconds();
+ std::cout << "TOP_LEVEL OPENING/REBUILD TIME " << 1000.0*(d1-d0) << " ms" << std::endl;
+#endif
+ }
+
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::deleteGeometry(size_t geomID)
+ {
+ if (geomID >= bvh->objects.size()) return;
+ if (builders[geomID]) builders[geomID].reset();
+ delete bvh->objects [geomID]; bvh->objects [geomID] = nullptr;
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::clear()
+ {
+ for (size_t i=0; i<bvh->objects.size(); i++)
+ if (bvh->objects[i]) bvh->objects[i]->clear();
+
+ for (size_t i=0; i<builders.size(); i++)
+ if (builders[i]) builders[i].reset();
+
+ refs.clear();
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::open_sequential(const size_t extSize)
+ {
+ if (refs.size() == 0)
+ return;
+
+ refs.reserve(extSize);
+
+#if 1
+ for (size_t i=0;i<refs.size();i++)
+ {
+ NodeRef ref = refs[i].node;
+ if (ref.isAABBNode())
+ BVH::prefetch(ref);
+ }
+#endif
+
+ std::make_heap(refs.begin(),refs.end());
+ while (refs.size()+N-1 <= extSize)
+ {
+ std::pop_heap (refs.begin(),refs.end());
+ NodeRef ref = refs.back().node;
+ if (ref.isLeaf()) break;
+ refs.pop_back();
+
+ AABBNode* node = ref.getAABBNode();
+ for (size_t i=0; i<N; i++) {
+ if (node->child(i) == BVH::emptyNode) continue;
+ refs.push_back(BuildRef(node->bounds(i),node->child(i)));
+
+#if 1
+ NodeRef ref_pre = node->child(i);
+ if (ref_pre.isAABBNode())
+ ref_pre.prefetch();
+#endif
+ std::push_heap (refs.begin(),refs.end());
+ }
+ }
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::setupSmallBuildRefBuilder (size_t objectID, Mesh const * const /*mesh*/)
+ {
+ if (builders[objectID] == nullptr || // new mesh
+ dynamic_cast<RefBuilderSmall*>(builders[objectID].get()) == nullptr) // size change resulted in large->small change
+ {
+ builders[objectID].reset (new RefBuilderSmall(objectID));
+ }
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNBuilderTwoLevel<N,Mesh,Primitive>::setupLargeBuildRefBuilder (size_t objectID, Mesh const * const mesh)
+ {
+ if (bvh->objects[objectID] == nullptr || // new mesh
+ builders[objectID]->meshQualityChanged (mesh->quality) || // changed build quality
+ dynamic_cast<RefBuilderLarge*>(builders[objectID].get()) == nullptr) // size change resulted in small->large change
+ {
+ Builder* builder = nullptr;
+ delete bvh->objects[objectID];
+ createMeshAccel(objectID, builder);
+ builders[objectID].reset (new RefBuilderLarge(objectID, builder, mesh->quality));
+ }
+ }
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH4BuilderTwoLevelTriangle4MeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+ Builder* BVH4BuilderTwoLevelTriangle4vMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4v>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+ Builder* BVH4BuilderTwoLevelTriangle4iMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,TriangleMesh,Triangle4i>((BVH4*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,QuadMesh,Quad4v>((BVH4*)bvh,scene,QuadMesh::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ Builder* BVH4BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,UserGeometry,Object>((BVH4*)bvh,scene,UserGeometry::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH4BuilderTwoLevelInstanceSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<4,Instance,InstancePrimitive>((BVH4*)bvh,scene,gtype,useMortonBuilder);
+ }
+#endif
+
+#if defined(__AVX__)
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH8BuilderTwoLevelTriangle4MeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+ Builder* BVH8BuilderTwoLevelTriangle4vMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4v>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+ Builder* BVH8BuilderTwoLevelTriangle4iMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,TriangleMesh,Triangle4i>((BVH8*)bvh,scene,TriangleMesh::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH8BuilderTwoLevelQuadMeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,QuadMesh,Quad4v>((BVH8*)bvh,scene,QuadMesh::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ Builder* BVH8BuilderTwoLevelVirtualSAH (void* bvh, Scene* scene, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,UserGeometry,Object>((BVH8*)bvh,scene,UserGeometry::geom_type,useMortonBuilder);
+ }
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH8BuilderTwoLevelInstanceSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) {
+ return new BVHNBuilderTwoLevel<8,Instance,InstancePrimitive>((BVH8*)bvh,scene,gtype,useMortonBuilder);
+ }
+#endif
+
+#endif
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h
new file mode 100644
index 0000000000..dc7ec7d278
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h
@@ -0,0 +1,263 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <type_traits>
+
+#include "bvh_builder_twolevel_internal.h"
+#include "bvh.h"
+#include "../common/primref.h"
+#include "../builders/priminfo.h"
+#include "../builders/primrefgen.h"
+
+/* new open/merge builder */
+#define ENABLE_DIRECT_SAH_MERGE_BUILDER 1
+#define ENABLE_OPEN_SEQUENTIAL 0
+#define SPLIT_MEMORY_RESERVE_FACTOR 1000
+#define SPLIT_MEMORY_RESERVE_SCALE 2
+#define SPLIT_MIN_EXT_SPACE 1000
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, typename Mesh, typename Primitive>
+ class BVHNBuilderTwoLevel : public Builder
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::NodeRef NodeRef;
+
+ __forceinline static bool isSmallGeometry(Mesh* mesh) {
+ return mesh->size() <= 4;
+ }
+
+ public:
+
+ typedef void (*createMeshAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);
+
+ struct BuildRef : public PrimRef
+ {
+ public:
+ __forceinline BuildRef () {}
+
+ __forceinline BuildRef (const BBox3fa& bounds, NodeRef node)
+ : PrimRef(bounds,(size_t)node), node(node)
+ {
+ if (node.isLeaf())
+ bounds_area = 0.0f;
+ else
+ bounds_area = area(this->bounds());
+ }
+
+ /* used by the open/merge bvh builder */
+ __forceinline BuildRef (const BBox3fa& bounds, NodeRef node, const unsigned int geomID, const unsigned int numPrimitives)
+ : PrimRef(bounds,geomID,numPrimitives), node(node)
+ {
+ /* important for relative buildref ordering */
+ if (node.isLeaf())
+ bounds_area = 0.0f;
+ else
+ bounds_area = area(this->bounds());
+ }
+
+ __forceinline size_t size() const {
+ return primID();
+ }
+
+ friend bool operator< (const BuildRef& a, const BuildRef& b) {
+ return a.bounds_area < b.bounds_area;
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const BuildRef& ref) {
+ return cout << "{ lower = " << ref.lower << ", upper = " << ref.upper << ", center2 = " << ref.center2() << ", geomID = " << ref.geomID() << ", numPrimitives = " << ref.numPrimitives() << ", bounds_area = " << ref.bounds_area << " }";
+ }
+
+ __forceinline unsigned int numPrimitives() const { return primID(); }
+
+ public:
+ NodeRef node;
+ float bounds_area;
+ };
+
+
+ __forceinline size_t openBuildRef(BuildRef &bref, BuildRef *const refs) {
+ if (bref.node.isLeaf())
+ {
+ refs[0] = bref;
+ return 1;
+ }
+ NodeRef ref = bref.node;
+ unsigned int geomID = bref.geomID();
+ unsigned int numPrims = max((unsigned int)bref.numPrimitives() / N,(unsigned int)1);
+ AABBNode* node = ref.getAABBNode();
+ size_t n = 0;
+ for (size_t i=0; i<N; i++) {
+ if (node->child(i) == BVH::emptyNode) continue;
+ refs[i] = BuildRef(node->bounds(i),node->child(i),geomID,numPrims);
+ n++;
+ }
+ assert(n > 1);
+ return n;
+ }
+
+ /*! Constructor. */
+ BVHNBuilderTwoLevel (BVH* bvh, Scene* scene, Geometry::GTypeMask gtype = Mesh::geom_type, bool useMortonBuilder = false, const size_t singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD);
+
+ /*! Destructor */
+ ~BVHNBuilderTwoLevel ();
+
+ /*! builder entry point */
+ void build();
+ void deleteGeometry(size_t geomID);
+ void clear();
+
+ void open_sequential(const size_t extSize);
+
+ private:
+
+ class RefBuilderBase {
+ public:
+ virtual ~RefBuilderBase () {}
+ virtual void attachBuildRefs (BVHNBuilderTwoLevel* builder) = 0;
+ virtual bool meshQualityChanged (RTCBuildQuality currQuality) = 0;
+ };
+
+ class RefBuilderSmall : public RefBuilderBase {
+ public:
+
+ RefBuilderSmall (size_t objectID)
+ : objectID_ (objectID) {}
+
+ void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder) {
+
+ Mesh* mesh = topBuilder->scene->template getSafe<Mesh>(objectID_);
+ size_t meshSize = mesh->size();
+ assert(isSmallGeometry(mesh));
+
+ mvector<PrimRef> prefs(topBuilder->scene->device, meshSize);
+ auto pinfo = createPrimRefArray(mesh,objectID_,meshSize,prefs,topBuilder->bvh->scene->progressInterface);
+
+ size_t begin=0;
+ while (begin < pinfo.size())
+ {
+ Primitive* accel = (Primitive*) topBuilder->bvh->alloc.getCachedAllocator().malloc1(sizeof(Primitive),BVH::byteAlignment);
+ typename BVH::NodeRef node = BVH::encodeLeaf((char*)accel,1);
+ accel->fill(prefs.data(),begin,pinfo.size(),topBuilder->bvh->scene);
+
+ /* create build primitive */
+#if ENABLE_DIRECT_SAH_MERGE_BUILDER
+ topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node,(unsigned int)objectID_,1);
+#else
+ topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(pinfo.geomBounds,node);
+#endif
+ }
+ assert(begin == pinfo.size());
+ }
+
+ bool meshQualityChanged (RTCBuildQuality /*currQuality*/) {
+ return false;
+ }
+
+ size_t objectID_;
+ };
+
+ class RefBuilderLarge : public RefBuilderBase {
+ public:
+
+ RefBuilderLarge (size_t objectID, const Ref<Builder>& builder, RTCBuildQuality quality)
+ : objectID_ (objectID), builder_ (builder), quality_ (quality) {}
+
+ void attachBuildRefs (BVHNBuilderTwoLevel* topBuilder)
+ {
+ BVH* object = topBuilder->getBVH(objectID_); assert(object);
+
+ /* build object if it got modified */
+ if (topBuilder->isGeometryModified(objectID_))
+ builder_->build();
+
+ /* create build primitive */
+ if (!object->getBounds().empty())
+ {
+#if ENABLE_DIRECT_SAH_MERGE_BUILDER
+ Mesh* mesh = topBuilder->getMesh(objectID_);
+ topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root,(unsigned int)objectID_,(unsigned int)mesh->size());
+#else
+ topBuilder->refs[topBuilder->nextRef++] = BVHNBuilderTwoLevel::BuildRef(object->getBounds(),object->root);
+#endif
+ }
+ }
+
+ bool meshQualityChanged (RTCBuildQuality currQuality) {
+ return currQuality != quality_;
+ }
+
+ private:
+ size_t objectID_;
+ Ref<Builder> builder_;
+ RTCBuildQuality quality_;
+ };
+
+ void setupLargeBuildRefBuilder (size_t objectID, Mesh const * const mesh);
+ void setupSmallBuildRefBuilder (size_t objectID, Mesh const * const mesh);
+
+ BVH* getBVH (size_t objectID) {
+ return this->bvh->objects[objectID];
+ }
+ Mesh* getMesh (size_t objectID) {
+ return this->scene->template getSafe<Mesh>(objectID);
+ }
+ bool isGeometryModified (size_t objectID) {
+ return this->scene->isGeometryModified(objectID);
+ }
+
+ void resizeRefsList ()
+ {
+ size_t num = parallel_reduce (size_t(0), scene->size(), size_t(0),
+ [this](const range<size_t>& r)->size_t {
+ size_t c = 0;
+ for (auto i=r.begin(); i<r.end(); ++i) {
+ Mesh* mesh = scene->getSafe<Mesh>(i);
+ if (mesh == nullptr || mesh->numTimeSteps != 1)
+ continue;
+ size_t meshSize = mesh->size();
+ c += isSmallGeometry(mesh) ? Primitive::blocks(meshSize) : 1;
+ }
+ return c;
+ },
+ std::plus<size_t>()
+ );
+
+ if (refs.size() < num) {
+ refs.resize(num);
+ }
+ }
+
+ void createMeshAccel (size_t geomID, Builder*& builder)
+ {
+ bvh->objects[geomID] = new BVH(Primitive::type,scene);
+ BVH* accel = bvh->objects[geomID];
+ auto mesh = scene->getSafe<Mesh>(geomID);
+ if (nullptr == mesh) {
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"geomID does not return correct type");
+ return;
+ }
+
+ __internal_two_level_builder__::MeshBuilder<N,Mesh,Primitive>()(accel, mesh, geomID, this->gtype, this->useMortonBuilder_, builder);
+ }
+
+ using BuilderList = std::vector<std::unique_ptr<RefBuilderBase>>;
+
+ BuilderList builders;
+ BVH* bvh;
+ Scene* scene;
+ mvector<BuildRef> refs;
+ mvector<PrimRef> prims;
+ std::atomic<int> nextRef;
+ const size_t singleThreadThreshold;
+ Geometry::GTypeMask gtype;
+ bool useMortonBuilder_ = false;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_twolevel_internal.h b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel_internal.h
new file mode 100644
index 0000000000..023b52b780
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel_internal.h
@@ -0,0 +1,267 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/quadi.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+
+namespace embree
+{
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4MeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4MeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4MeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vMeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vMeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4vMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iMeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iMeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Triangle4iMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vMeshBuilderMortonGeneral,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vMeshBuilderSAH,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4Quad4vMeshRefitSAH,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualMeshBuilderMortonGeneral,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualMeshBuilderSAH,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4VirtualMeshRefitSAH,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMeshBuilderMortonGeneral,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMeshBuilderSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMeshRefitSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t)
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4MeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4MeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4MeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vMeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vMeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4iMeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4iMeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4iMeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vMeshBuilderMortonGeneral,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vMeshBuilderSAH,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vMeshRefitSAH,void* COMMA QuadMesh* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8VirtualMeshBuilderMortonGeneral,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8VirtualMeshBuilderSAH,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8VirtualMeshRefitSAH,void* COMMA UserGeometry* COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMeshBuilderMortonGeneral,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMeshBuilderSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t);
+ DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMeshRefitSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t)
+
+ namespace isa
+ {
+
+ namespace __internal_two_level_builder__ {
+
+ template<int N, typename Mesh, typename Primitive>
+ struct MortonBuilder {};
+ template<>
+ struct MortonBuilder<4,TriangleMesh,Triangle4> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4MeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<4,TriangleMesh,Triangle4v> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4vMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<4,TriangleMesh,Triangle4i> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4iMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<4,QuadMesh,Quad4v> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Quad4vMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<4,UserGeometry,Object> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4VirtualMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<4,Instance,InstancePrimitive> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceMeshBuilderMortonGeneral(bvh,mesh,gtype,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,TriangleMesh,Triangle4> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4MeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,TriangleMesh,Triangle4v> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4vMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,TriangleMesh,Triangle4i> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4iMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,QuadMesh,Quad4v> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Quad4vMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,UserGeometry,Object> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8VirtualMeshBuilderMortonGeneral(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct MortonBuilder<8,Instance,InstancePrimitive> {
+ MortonBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceMeshBuilderMortonGeneral(bvh,mesh,gtype,geomID,0);}
+ };
+
+ template<int N, typename Mesh, typename Primitive>
+ struct SAHBuilder {};
+ template<>
+ struct SAHBuilder<4,TriangleMesh,Triangle4> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4MeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<4,TriangleMesh,Triangle4v> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4vMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<4,TriangleMesh,Triangle4i> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4iMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<4,QuadMesh,Quad4v> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Quad4vMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<4,UserGeometry,Object> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4VirtualMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<4,Instance,InstancePrimitive> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceMeshBuilderSAH(bvh,mesh,gtype,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,TriangleMesh,Triangle4> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4MeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,TriangleMesh,Triangle4v> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4vMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,TriangleMesh,Triangle4i> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4iMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,QuadMesh,Quad4v> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Quad4vMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,UserGeometry,Object> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8VirtualMeshBuilderSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct SAHBuilder<8,Instance,InstancePrimitive> {
+ SAHBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceMeshBuilderSAH(bvh,mesh,gtype,geomID,0);}
+ };
+
+ template<int N, typename Mesh, typename Primitive>
+ struct RefitBuilder {};
+ template<>
+ struct RefitBuilder<4,TriangleMesh,Triangle4> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4MeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<4,TriangleMesh,Triangle4v> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4vMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<4,TriangleMesh,Triangle4i> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Triangle4iMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<4,QuadMesh,Quad4v> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4Quad4vMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<4,UserGeometry,Object> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH4VirtualMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<4,Instance,InstancePrimitive> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceMeshRefitSAH(bvh,mesh,gtype,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,TriangleMesh,Triangle4> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4MeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,TriangleMesh,Triangle4v> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4vMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,TriangleMesh,Triangle4i> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4iMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,QuadMesh,Quad4v> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, QuadMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Quad4vMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,UserGeometry,Object> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, UserGeometry* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8VirtualMeshRefitSAH(bvh,mesh,geomID,0);}
+ };
+ template<>
+ struct RefitBuilder<8,Instance,InstancePrimitive> {
+ RefitBuilder () {}
+ Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceMeshRefitSAH(bvh,mesh,gtype,geomID,0);}
+ };
+
+ template<int N, typename Mesh, typename Primitive>
+ struct MeshBuilder {
+ MeshBuilder () {}
+ void operator () (void* bvh, Mesh* mesh, size_t geomID, Geometry::GTypeMask gtype, bool useMortonBuilder, Builder*& builder) {
+ if(useMortonBuilder) {
+ builder = MortonBuilder<N,Mesh,Primitive>()(bvh,mesh,geomID,gtype);
+ return;
+ }
+ switch (mesh->quality) {
+ case RTC_BUILD_QUALITY_LOW: builder = MortonBuilder<N,Mesh,Primitive>()(bvh,mesh,geomID,gtype); break;
+ case RTC_BUILD_QUALITY_MEDIUM:
+ case RTC_BUILD_QUALITY_HIGH: builder = SAHBuilder<N,Mesh,Primitive>()(bvh,mesh,geomID,gtype); break;
+ case RTC_BUILD_QUALITY_REFIT: builder = RefitBuilder<N,Mesh,Primitive>()(bvh,mesh,geomID,gtype); break;
+ default: throw_RTCError(RTC_ERROR_UNKNOWN,"invalid build quality");
+ }
+ }
+ };
+ }
+ }
+} \ No newline at end of file
diff --git a/thirdparty/embree/kernels/bvh/bvh_collider.cpp b/thirdparty/embree/kernels/bvh/bvh_collider.cpp
new file mode 100644
index 0000000000..9428c0b88e
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_collider.cpp
@@ -0,0 +1,375 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_collider.h"
+#include "../geometry/triangle_triangle_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+#define CSTAT(x)
+
+ size_t parallel_depth_threshold = 3;
+ CSTAT(std::atomic<size_t> bvh_collide_traversal_steps(0));
+ CSTAT(std::atomic<size_t> bvh_collide_leaf_pairs(0));
+ CSTAT(std::atomic<size_t> bvh_collide_leaf_iterations(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections1(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections2(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections3(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections4(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections5(0));
+ CSTAT(std::atomic<size_t> bvh_collide_prim_intersections(0));
+
+ struct Collision
+ {
+ __forceinline Collision() {}
+
+ __forceinline Collision (unsigned geomID0, unsigned primID0, unsigned geomID1, unsigned primID1)
+ : geomID0(geomID0), primID0(primID0), geomID1(geomID1), primID1(primID1) {}
+
+ unsigned geomID0;
+ unsigned primID0;
+ unsigned geomID1;
+ unsigned primID1;
+ };
+
+ template<int N>
+ __forceinline size_t overlap(const BBox3fa& box0, const typename BVHN<N>::AABBNode& node1)
+ {
+ const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x),node1.lower_x);
+ const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y),node1.lower_y);
+ const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z),node1.lower_z);
+ const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x),node1.upper_x);
+ const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y),node1.upper_y);
+ const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z),node1.upper_z);
+ return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
+ }
+
+ template<int N>
+ __forceinline size_t overlap(const BBox3fa& box0, const BBox<Vec3<vfloat<N>>>& box1)
+ {
+ const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x),box1.lower.x);
+ const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y),box1.lower.y);
+ const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z),box1.lower.z);
+ const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x),box1.upper.x);
+ const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y),box1.upper.y);
+ const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z),box1.upper.z);
+ return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
+ }
+
+ template<int N>
+ __forceinline size_t overlap(const BBox<Vec3<vfloat<N>>>& box0, size_t i, const BBox<Vec3<vfloat<N>>>& box1)
+ {
+ const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x[i]),box1.lower.x);
+ const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y[i]),box1.lower.y);
+ const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z[i]),box1.lower.z);
+ const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x[i]),box1.upper.x);
+ const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y[i]),box1.upper.y);
+ const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z[i]),box1.upper.z);
+ return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
+ }
+
+ bool intersect_triangle_triangle (Scene* scene0, unsigned geomID0, unsigned primID0, Scene* scene1, unsigned geomID1, unsigned primID1)
+ {
+ CSTAT(bvh_collide_prim_intersections1++);
+ const TriangleMesh* mesh0 = scene0->get<TriangleMesh>(geomID0);
+ const TriangleMesh* mesh1 = scene1->get<TriangleMesh>(geomID1);
+ const TriangleMesh::Triangle& tri0 = mesh0->triangle(primID0);
+ const TriangleMesh::Triangle& tri1 = mesh1->triangle(primID1);
+
+ /* special culling for scene intersection with itself */
+ if (scene0 == scene1 && geomID0 == geomID1)
+ {
+ /* ignore self intersections */
+ if (primID0 == primID1)
+ return false;
+ }
+ CSTAT(bvh_collide_prim_intersections2++);
+
+ if (scene0 == scene1 && geomID0 == geomID1)
+ {
+ /* ignore intersection with topological neighbors */
+ const vint4 t0(tri0.v[0],tri0.v[1],tri0.v[2],tri0.v[2]);
+ if (any(vint4(tri1.v[0]) == t0)) return false;
+ if (any(vint4(tri1.v[1]) == t0)) return false;
+ if (any(vint4(tri1.v[2]) == t0)) return false;
+ }
+ CSTAT(bvh_collide_prim_intersections3++);
+
+ const Vec3fa a0 = mesh0->vertex(tri0.v[0]);
+ const Vec3fa a1 = mesh0->vertex(tri0.v[1]);
+ const Vec3fa a2 = mesh0->vertex(tri0.v[2]);
+ const Vec3fa b0 = mesh1->vertex(tri1.v[0]);
+ const Vec3fa b1 = mesh1->vertex(tri1.v[1]);
+ const Vec3fa b2 = mesh1->vertex(tri1.v[2]);
+
+ return TriangleTriangleIntersector::intersect_triangle_triangle(a0,a1,a2,b0,b1,b2);
+ }
+
+ template<int N>
+ __forceinline void BVHNColliderUserGeom<N>::processLeaf(NodeRef node0, NodeRef node1)
+ {
+ Collision collisions[16];
+ size_t num_collisions = 0;
+
+ size_t N0; Object* leaf0 = (Object*) node0.leaf(N0);
+ size_t N1; Object* leaf1 = (Object*) node1.leaf(N1);
+ for (size_t i=0; i<N0; i++) {
+ for (size_t j=0; j<N1; j++) {
+ const unsigned geomID0 = leaf0[i].geomID();
+ const unsigned primID0 = leaf0[i].primID();
+ const unsigned geomID1 = leaf1[j].geomID();
+ const unsigned primID1 = leaf1[j].primID();
+ if (this->scene0 == this->scene1 && geomID0 == geomID1 && primID0 == primID1) continue;
+ collisions[num_collisions++] = Collision(geomID0,primID0,geomID1,primID1);
+ if (num_collisions == 16) {
+ this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);
+ num_collisions = 0;
+ }
+ }
+ }
+ if (num_collisions)
+ this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);
+ }
+
+ template<int N>
+ void BVHNCollider<N>::collide_recurse(NodeRef ref0, const BBox3fa& bounds0, NodeRef ref1, const BBox3fa& bounds1, size_t depth0, size_t depth1)
+ {
+ CSTAT(bvh_collide_traversal_steps++);
+ if (unlikely(ref0.isLeaf())) {
+ if (unlikely(ref1.isLeaf())) {
+ CSTAT(bvh_collide_leaf_pairs++);
+ processLeaf(ref0,ref1);
+ return;
+ } else goto recurse_node1;
+
+ } else {
+ if (unlikely(ref1.isLeaf())) {
+ goto recurse_node0;
+ } else {
+ if (area(bounds0) > area(bounds1)) {
+ goto recurse_node0;
+ }
+ else {
+ goto recurse_node1;
+ }
+ }
+ }
+
+ {
+ recurse_node0:
+ AABBNode* node0 = ref0.getAABBNode();
+ size_t mask = overlap<N>(bounds1,*node0);
+ //for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ //for (size_t i=0; i<N; i++) {
+#if 0
+ if (depth0 < parallel_depth_threshold)
+ {
+ parallel_for(size_t(N), [&] ( size_t i ) {
+ if (mask & ( 1 << i)) {
+ BVHN<N>::prefetch(node0->child(i),BVH_FLAG_ALIGNED_NODE);
+ collide_recurse(node0->child(i),node0->bounds(i),ref1,bounds1,depth0+1,depth1);
+ }
+ });
+ }
+ else
+#endif
+ {
+ for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ BVHN<N>::prefetch(node0->child(i),BVH_FLAG_ALIGNED_NODE);
+ collide_recurse(node0->child(i),node0->bounds(i),ref1,bounds1,depth0+1,depth1);
+ }
+ }
+ return;
+ }
+
+ {
+ recurse_node1:
+ AABBNode* node1 = ref1.getAABBNode();
+ size_t mask = overlap<N>(bounds0,*node1);
+ //for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ //for (size_t i=0; i<N; i++) {
+#if 0
+ if (depth1 < parallel_depth_threshold)
+ {
+ parallel_for(size_t(N), [&] ( size_t i ) {
+ if (mask & ( 1 << i)) {
+ BVHN<N>::prefetch(node1->child(i),BVH_FLAG_ALIGNED_NODE);
+ collide_recurse(ref0,bounds0,node1->child(i),node1->bounds(i),depth0,depth1+1);
+ }
+ });
+ }
+ else
+#endif
+ {
+ for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ BVHN<N>::prefetch(node1->child(i),BVH_FLAG_ALIGNED_NODE);
+ collide_recurse(ref0,bounds0,node1->child(i),node1->bounds(i),depth0,depth1+1);
+ }
+ }
+ return;
+ }
+ }
+
+ template<int N>
+ void BVHNCollider<N>::split(const CollideJob& job, jobvector& jobs)
+ {
+ if (unlikely(job.ref0.isLeaf())) {
+ if (unlikely(job.ref1.isLeaf())) {
+ jobs.push_back(job);
+ return;
+ } else goto recurse_node1;
+ } else {
+ if (unlikely(job.ref1.isLeaf())) {
+ goto recurse_node0;
+ } else {
+ if (area(job.bounds0) > area(job.bounds1)) {
+ goto recurse_node0;
+ }
+ else {
+ goto recurse_node1;
+ }
+ }
+ }
+
+ {
+ recurse_node0:
+ const AABBNode* node0 = job.ref0.getAABBNode();
+ size_t mask = overlap<N>(job.bounds1,*node0);
+ for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ jobs.push_back(CollideJob(node0->child(i),node0->bounds(i),job.depth0+1,job.ref1,job.bounds1,job.depth1));
+ }
+ return;
+ }
+
+ {
+ recurse_node1:
+ const AABBNode* node1 = job.ref1.getAABBNode();
+ size_t mask = overlap<N>(job.bounds0,*node1);
+ for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
+ jobs.push_back(CollideJob(job.ref0,job.bounds0,job.depth0,node1->child(i),node1->bounds(i),job.depth1+1));
+ }
+ return;
+ }
+ }
+
+ template<int N>
+ void BVHNCollider<N>::collide_recurse_entry(NodeRef ref0, const BBox3fa& bounds0, NodeRef ref1, const BBox3fa& bounds1)
+ {
+ CSTAT(bvh_collide_traversal_steps = 0);
+ CSTAT(bvh_collide_leaf_pairs = 0);
+ CSTAT(bvh_collide_leaf_iterations = 0);
+ CSTAT(bvh_collide_prim_intersections1 = 0);
+ CSTAT(bvh_collide_prim_intersections2 = 0);
+ CSTAT(bvh_collide_prim_intersections3 = 0);
+ CSTAT(bvh_collide_prim_intersections4 = 0);
+ CSTAT(bvh_collide_prim_intersections5 = 0);
+ CSTAT(bvh_collide_prim_intersections = 0);
+#if 0
+ collide_recurse(ref0,bounds0,ref1,bounds1,0,0);
+#else
+ const int M = 2048;
+ jobvector jobs[2];
+ jobs[0].reserve(M);
+ jobs[1].reserve(M);
+ jobs[0].push_back(CollideJob(ref0,bounds0,0,ref1,bounds1,0));
+ int source = 0;
+ int target = 1;
+
+ /* try to split job until job list is full */
+ while (jobs[source].size()+8 <= M)
+ {
+ for (size_t i=0; i<jobs[source].size(); i++)
+ {
+ const CollideJob& job = jobs[source][i];
+ size_t remaining = jobs[source].size()-i;
+ if (jobs[target].size()+remaining+8 > M) {
+ jobs[target].push_back(job);
+ } else {
+ split(job,jobs[target]);
+ }
+ }
+
+ /* stop splitting jobs if we reached only leaves and cannot make progress anymore */
+ if (jobs[target].size() == jobs[source].size())
+ break;
+
+ jobs[source].resize(0);
+ std::swap(source,target);
+ }
+
+ /* parallel processing of all jobs */
+ parallel_for(size_t(jobs[source].size()), [&] ( size_t i ) {
+ CollideJob& j = jobs[source][i];
+ collide_recurse(j.ref0,j.bounds0,j.ref1,j.bounds1,j.depth0,j.depth1);
+ });
+
+
+#endif
+ CSTAT(PRINT(bvh_collide_traversal_steps));
+ CSTAT(PRINT(bvh_collide_leaf_pairs));
+ CSTAT(PRINT(bvh_collide_leaf_iterations));
+ CSTAT(PRINT(bvh_collide_prim_intersections1));
+ CSTAT(PRINT(bvh_collide_prim_intersections2));
+ CSTAT(PRINT(bvh_collide_prim_intersections3));
+ CSTAT(PRINT(bvh_collide_prim_intersections4));
+ CSTAT(PRINT(bvh_collide_prim_intersections5));
+ CSTAT(PRINT(bvh_collide_prim_intersections));
+ }
+
+ template<int N>
+ void BVHNColliderUserGeom<N>::collide(BVH* __restrict__ bvh0, BVH* __restrict__ bvh1, RTCCollideFunc callback, void* userPtr)
+ {
+ BVHNColliderUserGeom<N>(bvh0->scene,bvh1->scene,callback,userPtr).
+ collide_recurse_entry(bvh0->root,bvh0->bounds.bounds(),bvh1->root,bvh1->bounds.bounds());
+ }
+
+#if defined (EMBREE_LOWEST_ISA)
+ struct collision_regression_test : public RegressionTest
+ {
+ collision_regression_test(const char* name) : RegressionTest(name) {
+ registerRegressionTest(this);
+ }
+
+ bool run ()
+ {
+ bool passed = true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(-0.008815f, 0.041848f, -2.49875e-06f), Vec3fa(-0.008276f, 0.053318f, -2.49875e-06f), Vec3fa(0.003023f, 0.048969f, -2.49875e-06f),
+ Vec3fa(0.00245f, 0.037612f, -2.49875e-06f), Vec3fa(0.01434f, 0.042634f, -2.49875e-06f), Vec3fa(0.013499f, 0.031309f, -2.49875e-06f)) == false;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,1),Vec3fa(1,0,1),Vec3fa(0,1,1)) == false;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,1),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,0),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,-0.1f),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(0.5f,0,0),Vec3fa(0,0.5f,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,0),Vec3fa(0.5f,0,0),Vec3fa(0,0.5f,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,0),Vec3fa(0.5f,0.1f,0),Vec3fa(0.1f,0.5f,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,-0.1f,0),Vec3fa(0.5f,0.1f,0),Vec3fa(0.1f,0.5f,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(-0.1f,0.1f,0),Vec3fa(0.5f,0.1f,0),Vec3fa(0.1f,0.5f,0)) == true;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
+ Vec3fa(-1,1,0) + Vec3fa(0,0,0),Vec3fa(-1,1,0) + Vec3fa(0.1f,0,0),Vec3fa(-1,1,0) + Vec3fa(0,0.1f,0)) == false;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
+ Vec3fa( 2,0.5f,0) + Vec3fa(0,0,0),Vec3fa( 2,0.5f,0) + Vec3fa(0.1f,0,0),Vec3fa( 2,0.5f,0) + Vec3fa(0,0.1f,0)) == false;
+ passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
+ Vec3fa(0.5f,-2.0f,0) + Vec3fa(0,0,0),Vec3fa(0.5f,-2.0f,0) + Vec3fa(0.1f,0,0),Vec3fa(0.5f,-2.0f,0) + Vec3fa(0,0.1f,0)) == false;
+ return passed;
+ }
+ };
+
+ collision_regression_test collision_regression("collision_regression_test");
+#endif
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Collider Definitions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ DEFINE_COLLIDER(BVH4ColliderUserGeom,BVHNColliderUserGeom<4>);
+
+#if defined(__AVX__)
+ DEFINE_COLLIDER(BVH8ColliderUserGeom,BVHNColliderUserGeom<8>);
+#endif
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_collider.h b/thirdparty/embree/kernels/bvh/bvh_collider.h
new file mode 100644
index 0000000000..3c42f211c1
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_collider.h
@@ -0,0 +1,72 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/object.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N>
+ class BVHNCollider
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::AABBNode AABBNode;
+
+ struct CollideJob
+ {
+ CollideJob () {}
+
+ CollideJob (NodeRef ref0, const BBox3fa& bounds0, size_t depth0,
+ NodeRef ref1, const BBox3fa& bounds1, size_t depth1)
+ : ref0(ref0), bounds0(bounds0), depth0(depth0), ref1(ref1), bounds1(bounds1), depth1(depth1) {}
+
+ NodeRef ref0;
+ BBox3fa bounds0;
+ size_t depth0;
+ NodeRef ref1;
+ BBox3fa bounds1;
+ size_t depth1;
+ };
+
+ typedef vector_t<CollideJob, aligned_allocator<CollideJob,16>> jobvector;
+
+ void split(const CollideJob& job, jobvector& jobs);
+
+ public:
+ __forceinline BVHNCollider (Scene* scene0, Scene* scene1, RTCCollideFunc callback, void* userPtr)
+ : scene0(scene0), scene1(scene1), callback(callback), userPtr(userPtr) {}
+
+ public:
+ virtual void processLeaf(NodeRef leaf0, NodeRef leaf1) = 0;
+ void collide_recurse(NodeRef node0, const BBox3fa& bounds0, NodeRef node1, const BBox3fa& bounds1, size_t depth0, size_t depth1);
+ void collide_recurse_entry(NodeRef node0, const BBox3fa& bounds0, NodeRef node1, const BBox3fa& bounds1);
+
+ protected:
+ Scene* scene0;
+ Scene* scene1;
+ RTCCollideFunc callback;
+ void* userPtr;
+ };
+
+ template<int N>
+ class BVHNColliderUserGeom : public BVHNCollider<N>
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::AABBNode AABBNode;
+
+ __forceinline BVHNColliderUserGeom (Scene* scene0, Scene* scene1, RTCCollideFunc callback, void* userPtr)
+ : BVHNCollider<N>(scene0,scene1,callback,userPtr) {}
+
+ virtual void processLeaf(NodeRef leaf0, NodeRef leaf1);
+ public:
+ static void collide(BVH* __restrict__ bvh0, BVH* __restrict__ bvh1, RTCCollideFunc callback, void* userPtr);
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_factory.h b/thirdparty/embree/kernels/bvh/bvh_factory.h
new file mode 100644
index 0000000000..453d455bd9
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_factory.h
@@ -0,0 +1,21 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../bvh/bvh.h"
+#include "../common/isa.h"
+#include "../common/accel.h"
+#include "../common/scene.h"
+#include "../geometry/curve_intersector_virtual.h"
+
+namespace embree
+{
+ /*! BVH instantiations */
+ class BVHFactory
+ {
+ public:
+ enum class BuildVariant { STATIC, DYNAMIC, HIGH_QUALITY };
+ enum class IntersectVariant { FAST, ROBUST };
+ };
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector1.cpp b/thirdparty/embree/kernels/bvh/bvh_intersector1.cpp
new file mode 100644
index 0000000000..9594f402c3
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_intersector1.cpp
@@ -0,0 +1,321 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_intersector1.h"
+#include "node_intersector1.h"
+#include "bvh_traverser1.h"
+
+#include "../geometry/intersector_iterators.h"
+#include "../geometry/triangle_intersector.h"
+#include "../geometry/trianglev_intersector.h"
+#include "../geometry/trianglev_mb_intersector.h"
+#include "../geometry/trianglei_intersector.h"
+#include "../geometry/quadv_intersector.h"
+#include "../geometry/quadi_intersector.h"
+#include "../geometry/curveNv_intersector.h"
+#include "../geometry/curveNi_intersector.h"
+#include "../geometry/curveNi_mb_intersector.h"
+#include "../geometry/linei_intersector.h"
+#include "../geometry/subdivpatch1_intersector.h"
+#include "../geometry/object_intersector.h"
+#include "../geometry/instance_intersector.h"
+#include "../geometry/subgrid_intersector.h"
+#include "../geometry/subgrid_mb_intersector.h"
+#include "../geometry/curve_intersector_virtual.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, int types, bool robust, typename PrimitiveIntersector1>
+ void BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::intersect(const Accel::Intersectors* __restrict__ This,
+ RayHit& __restrict__ ray,
+ IntersectContext* __restrict__ context)
+ {
+ const BVH* __restrict__ bvh = (const BVH*)This->ptr;
+
+ /* we may traverse an empty BVH in case all geometry was invalid */
+ if (bvh->root == BVH::emptyNode)
+ return;
+
+ /* perform per ray precalculations required by the primitive intersector */
+ Precalculations pre(ray, bvh);
+
+ /* stack state */
+ StackItemT<NodeRef> stack[stackSize]; // stack of nodes
+ StackItemT<NodeRef>* stackPtr = stack+1; // current stack pointer
+ StackItemT<NodeRef>* stackEnd = stack+stackSize;
+ stack[0].ptr = bvh->root;
+ stack[0].dist = neg_inf;
+
+ if (bvh->root == BVH::emptyNode)
+ return;
+
+ /* filter out invalid rays */
+#if defined(EMBREE_IGNORE_INVALID_RAYS)
+ if (!ray.valid()) return;
+#endif
+ /* verify correct input */
+ assert(ray.valid());
+ assert(ray.tnear() >= 0.0f);
+ assert(!(types & BVH_MB) || (ray.time() >= 0.0f && ray.time() <= 1.0f));
+
+ /* load the ray into SIMD registers */
+ TravRay<N,robust> tray(ray.org, ray.dir, max(ray.tnear(), 0.0f), max(ray.tfar, 0.0f));
+
+ /* initialize the node traverser */
+ BVHNNodeTraverser1Hit<N, types> nodeTraverser;
+
+ /* pop loop */
+ while (true) pop:
+ {
+ /* pop next node */
+ if (unlikely(stackPtr == stack)) break;
+ stackPtr--;
+ NodeRef cur = NodeRef(stackPtr->ptr);
+
+ /* if popped node is too far, pop next one */
+ if (unlikely(*(float*)&stackPtr->dist > ray.tfar))
+ continue;
+
+ /* downtraversal loop */
+ while (true)
+ {
+ /* intersect node */
+ size_t mask; vfloat<N> tNear;
+ STAT3(normal.trav_nodes,1,1,1);
+ bool nodeIntersected = BVHNNodeIntersector1<N, types, robust>::intersect(cur, tray, ray.time(), tNear, mask);
+ if (unlikely(!nodeIntersected)) { STAT3(normal.trav_nodes,-1,-1,-1); break; }
+
+ /* if no child is hit, pop next node */
+ if (unlikely(mask == 0))
+ goto pop;
+
+ /* select next child and push other children */
+ nodeTraverser.traverseClosestHit(cur, mask, tNear, stackPtr, stackEnd);
+ }
+
+ /* this is a leaf node */
+ assert(cur != BVH::emptyNode);
+ STAT3(normal.trav_leaves,1,1,1);
+ size_t num; Primitive* prim = (Primitive*)cur.leaf(num);
+ size_t lazy_node = 0;
+ PrimitiveIntersector1::intersect(This, pre, ray, context, prim, num, tray, lazy_node);
+ tray.tfar = ray.tfar;
+
+ /* push lazy node onto stack */
+ if (unlikely(lazy_node)) {
+ stackPtr->ptr = lazy_node;
+ stackPtr->dist = neg_inf;
+ stackPtr++;
+ }
+ }
+ }
+
+ template<int N, int types, bool robust, typename PrimitiveIntersector1>
+ void BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::occluded(const Accel::Intersectors* __restrict__ This,
+ Ray& __restrict__ ray,
+ IntersectContext* __restrict__ context)
+ {
+ const BVH* __restrict__ bvh = (const BVH*)This->ptr;
+
+ /* we may traverse an empty BVH in case all geometry was invalid */
+ if (bvh->root == BVH::emptyNode)
+ return;
+
+ /* early out for already occluded rays */
+ if (unlikely(ray.tfar < 0.0f))
+ return;
+
+ /* perform per ray precalculations required by the primitive intersector */
+ Precalculations pre(ray, bvh);
+
+ /* stack state */
+ NodeRef stack[stackSize]; // stack of nodes that still need to get traversed
+ NodeRef* stackPtr = stack+1; // current stack pointer
+ NodeRef* stackEnd = stack+stackSize;
+ stack[0] = bvh->root;
+
+ /* filter out invalid rays */
+#if defined(EMBREE_IGNORE_INVALID_RAYS)
+ if (!ray.valid()) return;
+#endif
+
+ /* verify correct input */
+ assert(ray.valid());
+ assert(ray.tnear() >= 0.0f);
+ assert(!(types & BVH_MB) || (ray.time() >= 0.0f && ray.time() <= 1.0f));
+
+ /* load the ray into SIMD registers */
+ TravRay<N,robust> tray(ray.org, ray.dir, max(ray.tnear(), 0.0f), max(ray.tfar, 0.0f));
+
+ /* initialize the node traverser */
+ BVHNNodeTraverser1Hit<N, types> nodeTraverser;
+
+ /* pop loop */
+ while (true) pop:
+ {
+ /* pop next node */
+ if (unlikely(stackPtr == stack)) break;
+ stackPtr--;
+ NodeRef cur = (NodeRef)*stackPtr;
+
+ /* downtraversal loop */
+ while (true)
+ {
+ /* intersect node */
+ size_t mask; vfloat<N> tNear;
+ STAT3(shadow.trav_nodes,1,1,1);
+ bool nodeIntersected = BVHNNodeIntersector1<N, types, robust>::intersect(cur, tray, ray.time(), tNear, mask);
+ if (unlikely(!nodeIntersected)) { STAT3(shadow.trav_nodes,-1,-1,-1); break; }
+
+ /* if no child is hit, pop next node */
+ if (unlikely(mask == 0))
+ goto pop;
+
+ /* select next child and push other children */
+ nodeTraverser.traverseAnyHit(cur, mask, tNear, stackPtr, stackEnd);
+ }
+
+ /* this is a leaf node */
+ assert(cur != BVH::emptyNode);
+ STAT3(shadow.trav_leaves,1,1,1);
+ size_t num; Primitive* prim = (Primitive*)cur.leaf(num);
+ size_t lazy_node = 0;
+ if (PrimitiveIntersector1::occluded(This, pre, ray, context, prim, num, tray, lazy_node)) {
+ ray.tfar = neg_inf;
+ break;
+ }
+
+ /* push lazy node onto stack */
+ if (unlikely(lazy_node)) {
+ *stackPtr = (NodeRef)lazy_node;
+ stackPtr++;
+ }
+ }
+ }
+
+ template<int N, int types, bool robust, typename PrimitiveIntersector1>
+ struct PointQueryDispatch
+ {
+ typedef typename PrimitiveIntersector1::Precalculations Precalculations;
+ typedef typename PrimitiveIntersector1::Primitive Primitive;
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::AABBNodeMB4D AABBNodeMB4D;
+
+ static const size_t stackSize = 1+(N-1)*BVH::maxDepth+3; // +3 due to 16-wide store
+
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context)
+ {
+ const BVH* __restrict__ bvh = (const BVH*)This->ptr;
+
+ /* we may traverse an empty BVH in case all geometry was invalid */
+ if (bvh->root == BVH::emptyNode)
+ return false;
+
+ /* stack state */
+ StackItemT<NodeRef> stack[stackSize]; // stack of nodes
+ StackItemT<NodeRef>* stackPtr = stack+1; // current stack pointer
+ StackItemT<NodeRef>* stackEnd = stack+stackSize;
+ stack[0].ptr = bvh->root;
+ stack[0].dist = neg_inf;
+
+ /* verify correct input */
+ assert(!(types & BVH_MB) || (query->time >= 0.0f && query->time <= 1.0f));
+
+ /* load the point query into SIMD registers */
+ TravPointQuery<N> tquery(query->p, context->query_radius);
+
+ /* initialize the node traverser */
+ BVHNNodeTraverser1Hit<N,types> nodeTraverser;
+
+ bool changed = false;
+ float cull_radius = context->query_type == POINT_QUERY_TYPE_SPHERE
+ ? query->radius * query->radius
+ : dot(context->query_radius, context->query_radius);
+
+ /* pop loop */
+ while (true) pop:
+ {
+ /* pop next node */
+ if (unlikely(stackPtr == stack)) break;
+ stackPtr--;
+ NodeRef cur = NodeRef(stackPtr->ptr);
+
+ /* if popped node is too far, pop next one */
+ if (unlikely(*(float*)&stackPtr->dist > cull_radius))
+ continue;
+
+ /* downtraversal loop */
+ while (true)
+ {
+ /* intersect node */
+ size_t mask; vfloat<N> tNear;
+ STAT3(point_query.trav_nodes,1,1,1);
+ bool nodeIntersected;
+ if (likely(context->query_type == POINT_QUERY_TYPE_SPHERE)) {
+ nodeIntersected = BVHNNodePointQuerySphere1<N, types>::pointQuery(cur, tquery, query->time, tNear, mask);
+ } else {
+ nodeIntersected = BVHNNodePointQueryAABB1 <N, types>::pointQuery(cur, tquery, query->time, tNear, mask);
+ }
+ if (unlikely(!nodeIntersected)) { STAT3(point_query.trav_nodes,-1,-1,-1); break; }
+
+ /* if no child is hit, pop next node */
+ if (unlikely(mask == 0))
+ goto pop;
+
+ /* select next child and push other children */
+ nodeTraverser.traverseClosestHit(cur, mask, tNear, stackPtr, stackEnd);
+ }
+
+ /* this is a leaf node */
+ assert(cur != BVH::emptyNode);
+ STAT3(point_query.trav_leaves,1,1,1);
+ size_t num; Primitive* prim = (Primitive*)cur.leaf(num);
+ size_t lazy_node = 0;
+ if (PrimitiveIntersector1::pointQuery(This, query, context, prim, num, tquery, lazy_node))
+ {
+ changed = true;
+ tquery.rad = context->query_radius;
+ cull_radius = context->query_type == POINT_QUERY_TYPE_SPHERE
+ ? query->radius * query->radius
+ : dot(context->query_radius, context->query_radius);
+ }
+
+ /* push lazy node onto stack */
+ if (unlikely(lazy_node)) {
+ stackPtr->ptr = lazy_node;
+ stackPtr->dist = neg_inf;
+ stackPtr++;
+ }
+ }
+ return changed;
+ }
+ };
+
+ /* disable point queries for not yet supported geometry types */
+ template<int N, int types, bool robust>
+ struct PointQueryDispatch<N, types, robust, VirtualCurveIntersector1> {
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; }
+ };
+
+ template<int N, int types, bool robust>
+ struct PointQueryDispatch<N, types, robust, SubdivPatch1Intersector1> {
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; }
+ };
+
+ template<int N, int types, bool robust>
+ struct PointQueryDispatch<N, types, robust, SubdivPatch1MBIntersector1> {
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; }
+ };
+
+ template<int N, int types, bool robust, typename PrimitiveIntersector1>
+ bool BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::pointQuery(
+ const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context)
+ {
+ return PointQueryDispatch<N, types, robust, PrimitiveIntersector1>::pointQuery(This, query, context);
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector1.h b/thirdparty/embree/kernels/bvh/bvh_intersector1.h
new file mode 100644
index 0000000000..2df3d6eddb
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_intersector1.h
@@ -0,0 +1,34 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "../common/ray.h"
+#include "../common/point_query.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! BVH single ray intersector. */
+ template<int N, int types, bool robust, typename PrimitiveIntersector1>
+ class BVHNIntersector1
+ {
+ /* shortcuts for frequently used types */
+ typedef typename PrimitiveIntersector1::Precalculations Precalculations;
+ typedef typename PrimitiveIntersector1::Primitive Primitive;
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::AABBNodeMB4D AABBNodeMB4D;
+
+ static const size_t stackSize = 1+(N-1)*BVH::maxDepth+3; // +3 due to 16-wide store
+
+ public:
+ static void intersect (const Accel::Intersectors* This, RayHit& ray, IntersectContext* context);
+ static void occluded (const Accel::Intersectors* This, Ray& ray, IntersectContext* context);
+ static bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context);
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector1_bvh4.cpp b/thirdparty/embree/kernels/bvh/bvh_intersector1_bvh4.cpp
new file mode 100644
index 0000000000..831d613367
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_intersector1_bvh4.cpp
@@ -0,0 +1,61 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_intersector1.cpp"
+
+namespace embree
+{
+ namespace isa
+ {
+ int getISA() {
+ return VerifyMultiTargetLinking::getISA();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// BVH4Intersector1 Definitions
+ ////////////////////////////////////////////////////////////////////////////////
+
+ IF_ENABLED_CURVES_OR_POINTS(DEFINE_INTERSECTOR1(BVH4OBBVirtualCurveIntersector1,BVHNIntersector1<4 COMMA BVH_AN1_UN1 COMMA false COMMA VirtualCurveIntersector1 >));
+ IF_ENABLED_CURVES_OR_POINTS(DEFINE_INTERSECTOR1(BVH4OBBVirtualCurveIntersector1MB,BVHNIntersector1<4 COMMA BVH_AN2_AN4D_UN2 COMMA false COMMA VirtualCurveIntersector1 >));
+
+ IF_ENABLED_CURVES_OR_POINTS(DEFINE_INTERSECTOR1(BVH4OBBVirtualCurveIntersectorRobust1,BVHNIntersector1<4 COMMA BVH_AN1_UN1 COMMA true COMMA VirtualCurveIntersector1 >));
+ IF_ENABLED_CURVES_OR_POINTS(DEFINE_INTERSECTOR1(BVH4OBBVirtualCurveIntersectorRobust1MB,BVHNIntersector1<4 COMMA BVH_AN2_AN4D_UN2 COMMA true COMMA VirtualCurveIntersector1 >));
+
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4Intersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<TriangleMIntersector1Moeller <4 COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4iIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<TriangleMiIntersector1Moeller <4 COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4vIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA ArrayIntersector1<TriangleMvIntersector1Pluecker<4 COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4iIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA ArrayIntersector1<TriangleMiIntersector1Pluecker<4 COMMA true> > >));
+
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4vMBIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<TriangleMvMBIntersector1Moeller <4 COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4iMBIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<TriangleMiMBIntersector1Moeller <4 COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4vMBIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA true COMMA ArrayIntersector1<TriangleMvMBIntersector1Pluecker<4 COMMA true> > >));
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(BVH4Triangle4iMBIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA true COMMA ArrayIntersector1<TriangleMiMBIntersector1Pluecker<4 COMMA true> > >));
+
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4vIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<QuadMvIntersector1Moeller <4 COMMA true> > >));
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4iIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<QuadMiIntersector1Moeller <4 COMMA true> > >));
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4vIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA ArrayIntersector1<QuadMvIntersector1Pluecker<4 COMMA true> > >));
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4iIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA ArrayIntersector1<QuadMiIntersector1Pluecker<4 COMMA true> > >));
+
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4iMBIntersector1Moeller, BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<QuadMiMBIntersector1Moeller <4 COMMA true> > >));
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(BVH4Quad4iMBIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA true COMMA ArrayIntersector1<QuadMiMBIntersector1Pluecker<4 COMMA true> > >));
+
+ IF_ENABLED_SUBDIV(DEFINE_INTERSECTOR1(BVH4SubdivPatch1Intersector1,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA SubdivPatch1Intersector1>));
+ IF_ENABLED_SUBDIV(DEFINE_INTERSECTOR1(BVH4SubdivPatch1MBIntersector1,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA true COMMA SubdivPatch1MBIntersector1>));
+
+ IF_ENABLED_USER(DEFINE_INTERSECTOR1(BVH4VirtualIntersector1,BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<ObjectIntersector1<false>> >));
+ IF_ENABLED_USER(DEFINE_INTERSECTOR1(BVH4VirtualMBIntersector1,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<ObjectIntersector1<true>> >));
+
+ IF_ENABLED_INSTANCE(DEFINE_INTERSECTOR1(BVH4InstanceIntersector1,BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<InstanceIntersector1> >));
+ IF_ENABLED_INSTANCE(DEFINE_INTERSECTOR1(BVH4InstanceMBIntersector1,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<InstanceIntersector1MB> >));
+
+ IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(QBVH4Triangle4iIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_QN1 COMMA false COMMA ArrayIntersector1<TriangleMiIntersector1Pluecker<4 COMMA true> > >));
+ IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(QBVH4Quad4iIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_QN1 COMMA false COMMA ArrayIntersector1<QuadMiIntersector1Pluecker<4 COMMA true> > >));
+
+ IF_ENABLED_GRIDS(DEFINE_INTERSECTOR1(BVH4GridIntersector1Moeller,BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA SubGridIntersector1Moeller<4 COMMA true> >));
+ IF_ENABLED_GRIDS(DEFINE_INTERSECTOR1(BVH4GridMBIntersector1Moeller,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA true COMMA SubGridMBIntersector1Pluecker<4 COMMA true> >));
+
+ IF_ENABLED_GRIDS(DEFINE_INTERSECTOR1(BVH4GridIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN1 COMMA true COMMA SubGridIntersector1Pluecker<4 COMMA true> >));
+ //IF_ENABLED_GRIDS(DEFINE_INTERSECTOR1(BVH4GridMBIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA SubGridMBIntersector1Pluecker<4 COMMA true> >));
+
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.h b/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.h
new file mode 100644
index 0000000000..50ebf375c4
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.h
@@ -0,0 +1,58 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "../common/ray.h"
+#include "../common/stack_item.h"
+#include "node_intersector_frustum.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int K, bool robust>
+ struct TravRayK;
+
+ /*! BVH hybrid packet intersector. Switches between packet and single ray traversal (optional). */
+ template<int N, int K, int types, bool robust, typename PrimitiveIntersectorK, bool single = true>
+ class BVHNIntersectorKHybrid
+ {
+ /* shortcuts for frequently used types */
+ typedef typename PrimitiveIntersectorK::Precalculations Precalculations;
+ typedef typename PrimitiveIntersectorK::Primitive Primitive;
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::BaseNode BaseNode;
+ typedef typename BVH::AABBNode AABBNode;
+
+ static const size_t stackSizeSingle = 1+(N-1)*BVH::maxDepth+3; // +3 due to 16-wide store
+ static const size_t stackSizeChunk = 1+(N-1)*BVH::maxDepth;
+
+ static const size_t switchThresholdIncoherent = \
+ (K==4) ? 3 :
+ (K==8) ? ((N==4) ? 5 : 7) :
+ (K==16) ? 14 : // 14 seems to work best for KNL due to better ordered chunk traversal
+ 0;
+
+ private:
+ static void intersect1(Accel::Intersectors* This, const BVH* bvh, NodeRef root, size_t k, Precalculations& pre,
+ RayHitK<K>& ray, const TravRayK<K, robust>& tray, IntersectContext* context);
+ static bool occluded1(Accel::Intersectors* This, const BVH* bvh, NodeRef root, size_t k, Precalculations& pre,
+ RayK<K>& ray, const TravRayK<K, robust>& tray, IntersectContext* context);
+
+ public:
+ static void intersect(vint<K>* valid, Accel::Intersectors* This, RayHitK<K>& ray, IntersectContext* context);
+ static void occluded (vint<K>* valid, Accel::Intersectors* This, RayK<K>& ray, IntersectContext* context);
+
+ static void intersectCoherent(vint<K>* valid, Accel::Intersectors* This, RayHitK<K>& ray, IntersectContext* context);
+ static void occludedCoherent (vint<K>* valid, Accel::Intersectors* This, RayK<K>& ray, IntersectContext* context);
+
+ };
+
+ /*! BVH packet intersector. */
+ template<int N, int K, int types, bool robust, typename PrimitiveIntersectorK>
+ class BVHNIntersectorKChunk : public BVHNIntersectorKHybrid<N, K, types, robust, PrimitiveIntersectorK, false> {};
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_stream.h b/thirdparty/embree/kernels/bvh/bvh_intersector_stream.h
new file mode 100644
index 0000000000..717f559677
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_intersector_stream.h
@@ -0,0 +1,270 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "node_intersector_packet_stream.h"
+#include "node_intersector_frustum.h"
+#include "bvh_traverser_stream.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! BVH ray stream intersector. */
+ template<int N, int types, bool robust, typename PrimitiveIntersector>
+ class BVHNIntersectorStream
+ {
+ /* shortcuts for frequently used types */
+ template<int K> using PrimitiveIntersectorK = typename PrimitiveIntersector::template Type<K>;
+ template<int K> using PrimitiveK = typename PrimitiveIntersectorK<K>::PrimitiveK;
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::BaseNode BaseNode;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::AABBNodeMB AABBNodeMB;
+
+ template<int K>
+ __forceinline static size_t initPacketsAndFrustum(RayK<K>** inputPackets, size_t numOctantRays,
+ TravRayKStream<K, robust>* packets, Frustum<robust>& frustum, bool& commonOctant)
+ {
+ const size_t numPackets = (numOctantRays+K-1)/K;
+
+ Vec3vf<K> tmp_min_rdir(pos_inf);
+ Vec3vf<K> tmp_max_rdir(neg_inf);
+ Vec3vf<K> tmp_min_org(pos_inf);
+ Vec3vf<K> tmp_max_org(neg_inf);
+ vfloat<K> tmp_min_dist(pos_inf);
+ vfloat<K> tmp_max_dist(neg_inf);
+
+ size_t m_active = 0;
+ for (size_t i = 0; i < numPackets; i++)
+ {
+ const vfloat<K> tnear = inputPackets[i]->tnear();
+ const vfloat<K> tfar = inputPackets[i]->tfar;
+ vbool<K> m_valid = (tnear <= tfar) & (tnear >= 0.0f);
+
+#if defined(EMBREE_IGNORE_INVALID_RAYS)
+ m_valid &= inputPackets[i]->valid();
+#endif
+
+ m_active |= (size_t)movemask(m_valid) << (i*K);
+
+ vfloat<K> packet_min_dist = max(tnear, 0.0f);
+ vfloat<K> packet_max_dist = select(m_valid, tfar, neg_inf);
+ tmp_min_dist = min(tmp_min_dist, packet_min_dist);
+ tmp_max_dist = max(tmp_max_dist, packet_max_dist);
+
+ const Vec3vf<K>& org = inputPackets[i]->org;
+ const Vec3vf<K>& dir = inputPackets[i]->dir;
+
+ new (&packets[i]) TravRayKStream<K, robust>(org, dir, packet_min_dist, packet_max_dist);
+
+ tmp_min_rdir = min(tmp_min_rdir, select(m_valid, packets[i].rdir, Vec3vf<K>(pos_inf)));
+ tmp_max_rdir = max(tmp_max_rdir, select(m_valid, packets[i].rdir, Vec3vf<K>(neg_inf)));
+ tmp_min_org = min(tmp_min_org , select(m_valid,org , Vec3vf<K>(pos_inf)));
+ tmp_max_org = max(tmp_max_org , select(m_valid,org , Vec3vf<K>(neg_inf)));
+ }
+
+ m_active &= (numOctantRays == (8 * sizeof(size_t))) ? (size_t)-1 : (((size_t)1 << numOctantRays)-1);
+
+
+ const Vec3fa reduced_min_rdir(reduce_min(tmp_min_rdir.x),
+ reduce_min(tmp_min_rdir.y),
+ reduce_min(tmp_min_rdir.z));
+
+ const Vec3fa reduced_max_rdir(reduce_max(tmp_max_rdir.x),
+ reduce_max(tmp_max_rdir.y),
+ reduce_max(tmp_max_rdir.z));
+
+ const Vec3fa reduced_min_origin(reduce_min(tmp_min_org.x),
+ reduce_min(tmp_min_org.y),
+ reduce_min(tmp_min_org.z));
+
+ const Vec3fa reduced_max_origin(reduce_max(tmp_max_org.x),
+ reduce_max(tmp_max_org.y),
+ reduce_max(tmp_max_org.z));
+
+ commonOctant =
+ (reduced_max_rdir.x < 0.0f || reduced_min_rdir.x >= 0.0f) &&
+ (reduced_max_rdir.y < 0.0f || reduced_min_rdir.y >= 0.0f) &&
+ (reduced_max_rdir.z < 0.0f || reduced_min_rdir.z >= 0.0f);
+
+ const float frustum_min_dist = reduce_min(tmp_min_dist);
+ const float frustum_max_dist = reduce_max(tmp_max_dist);
+
+ frustum.init(reduced_min_origin, reduced_max_origin,
+ reduced_min_rdir, reduced_max_rdir,
+ frustum_min_dist, frustum_max_dist,
+ N);
+
+ return m_active;
+ }
+
+ template<int K>
+ __forceinline static size_t intersectAABBNodePacket(size_t m_active,
+ const TravRayKStream<K,robust>* packets,
+ const AABBNode* __restrict__ node,
+ size_t boxID,
+ const NearFarPrecalculations& nf)
+ {
+ assert(m_active);
+ const size_t startPacketID = bsf(m_active) / K;
+ const size_t endPacketID = bsr(m_active) / K;
+ size_t m_trav_active = 0;
+ for (size_t i = startPacketID; i <= endPacketID; i++)
+ {
+ const size_t m_hit = intersectNodeK<N>(node, boxID, packets[i], nf);
+ m_trav_active |= m_hit << (i*K);
+ }
+ return m_trav_active;
+ }
+
+ template<int K>
+ __forceinline static size_t traverseCoherentStream(size_t m_active,
+ TravRayKStream<K, robust>* packets,
+ const AABBNode* __restrict__ node,
+ const Frustum<robust>& frustum,
+ size_t* maskK,
+ vfloat<N>& dist)
+ {
+ size_t m_node_hit = intersectNodeFrustum<N>(node, frustum, dist);
+ const size_t first_index = bsf(m_active);
+ const size_t first_packetID = first_index / K;
+ const size_t first_rayID = first_index % K;
+ size_t m_first_hit = intersectNode1<N>(node, packets[first_packetID], first_rayID, frustum.nf);
+
+ /* this make traversal independent of the ordering of rays */
+ size_t m_node = m_node_hit ^ m_first_hit;
+ while (unlikely(m_node))
+ {
+ const size_t boxID = bscf(m_node);
+ const size_t m_current = m_active & intersectAABBNodePacket(m_active, packets, node, boxID, frustum.nf);
+ m_node_hit ^= m_current ? (size_t)0 : ((size_t)1 << boxID);
+ maskK[boxID] = m_current;
+ }
+ return m_node_hit;
+ }
+
+ // TODO: explicit 16-wide path for KNL
+ template<int K>
+ __forceinline static vint<N> traverseIncoherentStream(size_t m_active,
+ TravRayKStreamFast<K>* __restrict__ packets,
+ const AABBNode* __restrict__ node,
+ const NearFarPrecalculations& nf,
+ const int shiftTable[32])
+ {
+ const vfloat<N> bminX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX));
+ const vfloat<N> bminY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY));
+ const vfloat<N> bminZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ));
+ const vfloat<N> bmaxX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX));
+ const vfloat<N> bmaxY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY));
+ const vfloat<N> bmaxZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ));
+ assert(m_active);
+ vint<N> vmask(zero);
+ do
+ {
+ STAT3(shadow.trav_nodes,1,1,1);
+ const size_t rayID = bscf(m_active);
+ assert(rayID < MAX_INTERNAL_STREAM_SIZE);
+ TravRayKStream<K,robust> &p = packets[rayID / K];
+ const size_t i = rayID % K;
+ const vint<N> bitmask(shiftTable[rayID]);
+ const vfloat<N> tNearX = msub(bminX, p.rdir.x[i], p.org_rdir.x[i]);
+ const vfloat<N> tNearY = msub(bminY, p.rdir.y[i], p.org_rdir.y[i]);
+ const vfloat<N> tNearZ = msub(bminZ, p.rdir.z[i], p.org_rdir.z[i]);
+ const vfloat<N> tFarX = msub(bmaxX, p.rdir.x[i], p.org_rdir.x[i]);
+ const vfloat<N> tFarY = msub(bmaxY, p.rdir.y[i], p.org_rdir.y[i]);
+ const vfloat<N> tFarZ = msub(bmaxZ, p.rdir.z[i], p.org_rdir.z[i]);
+ const vfloat<N> tNear = maxi(tNearX, tNearY, tNearZ, vfloat<N>(p.tnear[i]));
+ const vfloat<N> tFar = mini(tFarX , tFarY , tFarZ, vfloat<N>(p.tfar[i]));
+
+ const vbool<N> hit_mask = tNear <= tFar;
+#if defined(__AVX2__)
+ vmask = vmask | (bitmask & vint<N>(hit_mask));
+#else
+ vmask = select(hit_mask, vmask | bitmask, vmask);
+#endif
+ } while(m_active);
+ return vmask;
+ }
+
+ template<int K>
+ __forceinline static vint<N> traverseIncoherentStream(size_t m_active,
+ TravRayKStreamRobust<K>* __restrict__ packets,
+ const AABBNode* __restrict__ node,
+ const NearFarPrecalculations& nf,
+ const int shiftTable[32])
+ {
+ const vfloat<N> bminX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX));
+ const vfloat<N> bminY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY));
+ const vfloat<N> bminZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ));
+ const vfloat<N> bmaxX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX));
+ const vfloat<N> bmaxY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY));
+ const vfloat<N> bmaxZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ));
+ assert(m_active);
+ vint<N> vmask(zero);
+ do
+ {
+ STAT3(shadow.trav_nodes,1,1,1);
+ const size_t rayID = bscf(m_active);
+ assert(rayID < MAX_INTERNAL_STREAM_SIZE);
+ TravRayKStream<K,robust> &p = packets[rayID / K];
+ const size_t i = rayID % K;
+ const vint<N> bitmask(shiftTable[rayID]);
+ const vfloat<N> tNearX = (bminX - p.org.x[i]) * p.rdir.x[i];
+ const vfloat<N> tNearY = (bminY - p.org.y[i]) * p.rdir.y[i];
+ const vfloat<N> tNearZ = (bminZ - p.org.z[i]) * p.rdir.z[i];
+ const vfloat<N> tFarX = (bmaxX - p.org.x[i]) * p.rdir.x[i];
+ const vfloat<N> tFarY = (bmaxY - p.org.y[i]) * p.rdir.y[i];
+ const vfloat<N> tFarZ = (bmaxZ - p.org.z[i]) * p.rdir.z[i];
+ const vfloat<N> tNear = maxi(tNearX, tNearY, tNearZ, vfloat<N>(p.tnear[i]));
+ const vfloat<N> tFar = mini(tFarX , tFarY , tFarZ, vfloat<N>(p.tfar[i]));
+ const float round_down = 1.0f-2.0f*float(ulp);
+ const float round_up = 1.0f+2.0f*float(ulp);
+ const vbool<N> hit_mask = round_down*tNear <= round_up*tFar;
+#if defined(__AVX2__)
+ vmask = vmask | (bitmask & vint<N>(hit_mask));
+#else
+ vmask = select(hit_mask, vmask | bitmask, vmask);
+#endif
+ } while(m_active);
+ return vmask;
+ }
+
+
+ static const size_t stackSizeSingle = 1+(N-1)*BVH::maxDepth;
+
+ public:
+ static void intersect(Accel::Intersectors* This, RayHitN** inputRays, size_t numRays, IntersectContext* context);
+ static void occluded (Accel::Intersectors* This, RayN** inputRays, size_t numRays, IntersectContext* context);
+
+ private:
+ template<int K>
+ static void intersectCoherent(Accel::Intersectors* This, RayHitK<K>** inputRays, size_t numRays, IntersectContext* context);
+
+ template<int K>
+ static void occludedCoherent(Accel::Intersectors* This, RayK<K>** inputRays, size_t numRays, IntersectContext* context);
+
+ template<int K>
+ static void occludedIncoherent(Accel::Intersectors* This, RayK<K>** inputRays, size_t numRays, IntersectContext* context);
+ };
+
+
+ /*! BVH ray stream intersector with direct fallback to packets. */
+ template<int N>
+ class BVHNIntersectorStreamPacketFallback
+ {
+ public:
+ static void intersect(Accel::Intersectors* This, RayHitN** inputRays, size_t numRays, IntersectContext* context);
+ static void occluded (Accel::Intersectors* This, RayN** inputRays, size_t numRays, IntersectContext* context);
+
+ private:
+ template<int K>
+ static void intersectK(Accel::Intersectors* This, RayHitK<K>** inputRays, size_t numRays, IntersectContext* context);
+
+ template<int K>
+ static void occludedK(Accel::Intersectors* This, RayK<K>** inputRays, size_t numRays, IntersectContext* context);
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_stream_filters.h b/thirdparty/embree/kernels/bvh/bvh_intersector_stream_filters.h
new file mode 100644
index 0000000000..e7df7c2ae2
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_intersector_stream_filters.h
@@ -0,0 +1,41 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/ray.h"
+#include "../common/scene.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ class RayStreamFilter
+ {
+ public:
+ static void intersectAOS(Scene* scene, RTCRayHit* rays, size_t N, size_t stride, IntersectContext* context);
+ static void intersectAOP(Scene* scene, RTCRayHit** rays, size_t N, IntersectContext* context);
+ static void intersectSOA(Scene* scene, char* rays, size_t N, size_t numPackets, size_t stride, IntersectContext* context);
+ static void intersectSOP(Scene* scene, const RTCRayHitNp* rays, size_t N, IntersectContext* context);
+
+ static void occludedAOS(Scene* scene, RTCRay* rays, size_t N, size_t stride, IntersectContext* context);
+ static void occludedAOP(Scene* scene, RTCRay** rays, size_t N, IntersectContext* context);
+ static void occludedSOA(Scene* scene, char* rays, size_t N, size_t numPackets, size_t stride, IntersectContext* context);
+ static void occludedSOP(Scene* scene, const RTCRayNp* rays, size_t N, IntersectContext* context);
+
+ private:
+ template<int K, bool intersect>
+ static void filterAOS(Scene* scene, void* rays, size_t N, size_t stride, IntersectContext* context);
+
+ template<int K, bool intersect>
+ static void filterAOP(Scene* scene, void** rays, size_t N, IntersectContext* context);
+
+ template<int K, bool intersect>
+ static void filterSOA(Scene* scene, char* rays, size_t N, size_t numPackets, size_t stride, IntersectContext* context);
+
+ template<int K, bool intersect>
+ static void filterSOP(Scene* scene, const void* rays, size_t N, IntersectContext* context);
+ };
+ }
+};
diff --git a/thirdparty/embree/kernels/bvh/bvh_node_aabb.h b/thirdparty/embree/kernels/bvh/bvh_node_aabb.h
new file mode 100644
index 0000000000..57530692bc
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_node_aabb.h
@@ -0,0 +1,213 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_base.h"
+
+namespace embree
+{
+ /*! BVHN AABBNode */
+ template<typename NodeRef, int N>
+ struct AABBNode_t : public BaseNode_t<NodeRef, N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+
+ struct Create
+ {
+ __forceinline NodeRef operator() (const FastAllocator::CachedAllocator& alloc, size_t numChildren = 0) const
+ {
+ AABBNode_t* node = (AABBNode_t*) alloc.malloc0(sizeof(AABBNode_t),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ };
+
+ struct Set
+ {
+ __forceinline void operator() (NodeRef node, size_t i, NodeRef child, const BBox3fa& bounds) const {
+ node.getAABBNode()->setRef(i,child);
+ node.getAABBNode()->setBounds(i,bounds);
+ }
+ };
+
+ struct Create2
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (BuildRecord* children, const size_t num, const FastAllocator::CachedAllocator& alloc) const
+ {
+ AABBNode_t* node = (AABBNode_t*) alloc.malloc0(sizeof(AABBNode_t), NodeRef::byteNodeAlignment); node->clear();
+ for (size_t i=0; i<num; i++) node->setBounds(i,children[i].bounds());
+ return NodeRef::encodeNode(node);
+ }
+ };
+
+ struct Set2
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRef* children, const size_t num) const
+ {
+ AABBNode_t* node = ref.getAABBNode();
+ for (size_t i=0; i<num; i++) node->setRef(i,children[i]);
+ return ref;
+ }
+ };
+
+ struct Set3
+ {
+ Set3 (FastAllocator* allocator, PrimRef* prims)
+ : allocator(allocator), prims(prims) {}
+
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRef* children, const size_t num) const
+ {
+ AABBNode_t* node = ref.getAABBNode();
+ for (size_t i=0; i<num; i++) node->setRef(i,children[i]);
+
+ if (unlikely(precord.alloc_barrier))
+ {
+ PrimRef* begin = &prims[precord.prims.begin()];
+ PrimRef* end = &prims[precord.prims.end()]; // FIXME: extended end for spatial split builder!!!!!
+ size_t bytes = (size_t)end - (size_t)begin;
+ allocator->addBlock(begin,bytes);
+ }
+
+ return ref;
+ }
+
+ FastAllocator* const allocator;
+ PrimRef* const prims;
+ };
+
+ /*! Clears the node. */
+ __forceinline void clear() {
+ lower_x = lower_y = lower_z = pos_inf;
+ upper_x = upper_y = upper_z = neg_inf;
+ BaseNode_t<NodeRef,N>::clear();
+ }
+
+ /*! Sets bounding box and ID of child. */
+ __forceinline void setRef(size_t i, const NodeRef& ref) {
+ assert(i < N);
+ children[i] = ref;
+ }
+
+ /*! Sets bounding box of child. */
+ __forceinline void setBounds(size_t i, const BBox3fa& bounds)
+ {
+ assert(i < N);
+ lower_x[i] = bounds.lower.x; lower_y[i] = bounds.lower.y; lower_z[i] = bounds.lower.z;
+ upper_x[i] = bounds.upper.x; upper_y[i] = bounds.upper.y; upper_z[i] = bounds.upper.z;
+ }
+
+ /*! Sets bounding box and ID of child. */
+ __forceinline void set(size_t i, const NodeRef& ref, const BBox3fa& bounds) {
+ setBounds(i,bounds);
+ children[i] = ref;
+ }
+
+ /*! Returns bounds of node. */
+ __forceinline BBox3fa bounds() const {
+ const Vec3fa lower(reduce_min(lower_x),reduce_min(lower_y),reduce_min(lower_z));
+ const Vec3fa upper(reduce_max(upper_x),reduce_max(upper_y),reduce_max(upper_z));
+ return BBox3fa(lower,upper);
+ }
+
+ /*! Returns bounds of specified child. */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ assert(i < N);
+ const Vec3fa lower(lower_x[i],lower_y[i],lower_z[i]);
+ const Vec3fa upper(upper_x[i],upper_y[i],upper_z[i]);
+ return BBox3fa(lower,upper);
+ }
+
+ /*! Returns extent of bounds of specified child. */
+ __forceinline Vec3fa extend(size_t i) const {
+ return bounds(i).size();
+ }
+
+ /*! Returns bounds of all children (implemented later as specializations) */
+ __forceinline void bounds(BBox<vfloat4>& bounds0, BBox<vfloat4>& bounds1, BBox<vfloat4>& bounds2, BBox<vfloat4>& bounds3) const;
+
+ /*! swap two children of the node */
+ __forceinline void swap(size_t i, size_t j)
+ {
+ assert(i<N && j<N);
+ std::swap(children[i],children[j]);
+ std::swap(lower_x[i],lower_x[j]);
+ std::swap(lower_y[i],lower_y[j]);
+ std::swap(lower_z[i],lower_z[j]);
+ std::swap(upper_x[i],upper_x[j]);
+ std::swap(upper_y[i],upper_y[j]);
+ std::swap(upper_z[i],upper_z[j]);
+ }
+
+ /*! swap the children of two nodes */
+ __forceinline static void swap(AABBNode_t* a, size_t i, AABBNode_t* b, size_t j)
+ {
+ assert(i<N && j<N);
+ std::swap(a->children[i],b->children[j]);
+ std::swap(a->lower_x[i],b->lower_x[j]);
+ std::swap(a->lower_y[i],b->lower_y[j]);
+ std::swap(a->lower_z[i],b->lower_z[j]);
+ std::swap(a->upper_x[i],b->upper_x[j]);
+ std::swap(a->upper_y[i],b->upper_y[j]);
+ std::swap(a->upper_z[i],b->upper_z[j]);
+ }
+
+ /*! compacts a node (moves empty children to the end) */
+ __forceinline static void compact(AABBNode_t* a)
+ {
+ /* find right most filled node */
+ ssize_t j=N;
+ for (j=j-1; j>=0; j--)
+ if (a->child(j) != NodeRef::emptyNode)
+ break;
+
+ /* replace empty nodes with filled nodes */
+ for (ssize_t i=0; i<j; i++) {
+ if (a->child(i) == NodeRef::emptyNode) {
+ a->swap(i,j);
+ for (j=j-1; j>i; j--)
+ if (a->child(j) != NodeRef::emptyNode)
+ break;
+ }
+ }
+ }
+
+ /*! Returns reference to specified child */
+ __forceinline NodeRef& child(size_t i) { assert(i<N); return children[i]; }
+ __forceinline const NodeRef& child(size_t i) const { assert(i<N); return children[i]; }
+
+ /*! output operator */
+ friend embree_ostream operator<<(embree_ostream o, const AABBNode_t& n)
+ {
+ o << "AABBNode { " << embree_endl;
+ o << " lower_x " << n.lower_x << embree_endl;
+ o << " upper_x " << n.upper_x << embree_endl;
+ o << " lower_y " << n.lower_y << embree_endl;
+ o << " upper_y " << n.upper_y << embree_endl;
+ o << " lower_z " << n.lower_z << embree_endl;
+ o << " upper_z " << n.upper_z << embree_endl;
+ o << " children = ";
+ for (size_t i=0; i<N; i++) o << n.children[i] << " ";
+ o << embree_endl;
+ o << "}" << embree_endl;
+ return o;
+ }
+
+ public:
+ vfloat<N> lower_x; //!< X dimension of lower bounds of all N children.
+ vfloat<N> upper_x; //!< X dimension of upper bounds of all N children.
+ vfloat<N> lower_y; //!< Y dimension of lower bounds of all N children.
+ vfloat<N> upper_y; //!< Y dimension of upper bounds of all N children.
+ vfloat<N> lower_z; //!< Z dimension of lower bounds of all N children.
+ vfloat<N> upper_z; //!< Z dimension of upper bounds of all N children.
+ };
+
+ template<>
+ __forceinline void AABBNode_t<NodeRefPtr<4>,4>::bounds(BBox<vfloat4>& bounds0, BBox<vfloat4>& bounds1, BBox<vfloat4>& bounds2, BBox<vfloat4>& bounds3) const {
+ transpose(lower_x,lower_y,lower_z,vfloat4(zero),bounds0.lower,bounds1.lower,bounds2.lower,bounds3.lower);
+ transpose(upper_x,upper_y,upper_z,vfloat4(zero),bounds0.upper,bounds1.upper,bounds2.upper,bounds3.upper);
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_node_aabb_mb.h b/thirdparty/embree/kernels/bvh/bvh_node_aabb_mb.h
new file mode 100644
index 0000000000..c4cea7d8ba
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_node_aabb_mb.h
@@ -0,0 +1,247 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_base.h"
+
+namespace embree
+{
+ /*! Motion Blur AABBNode */
+ template<typename NodeRef, int N>
+ struct AABBNodeMB_t : public BaseNode_t<NodeRef, N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+ typedef BVHNodeRecord<NodeRef> NodeRecord;
+ typedef BVHNodeRecordMB<NodeRef> NodeRecordMB;
+ typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D;
+
+ struct Create
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (BuildRecord* children, const size_t num, const FastAllocator::CachedAllocator& alloc) const
+ {
+ AABBNodeMB_t* node = (AABBNodeMB_t*) alloc.malloc0(sizeof(AABBNodeMB_t),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ };
+
+ struct Set
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRecordMB operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRecordMB* children, const size_t num) const
+ {
+ AABBNodeMB_t* node = ref.getAABBNodeMB();
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<num; i++) {
+ node->setRef(i,children[i].ref);
+ node->setBounds(i,children[i].lbounds);
+ bounds.extend(children[i].lbounds);
+ }
+ return NodeRecordMB(ref,bounds);
+ }
+ };
+
+ struct SetTimeRange
+ {
+ __forceinline SetTimeRange(BBox1f tbounds) : tbounds(tbounds) {}
+
+ template<typename BuildRecord>
+ __forceinline NodeRecordMB operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRecordMB* children, const size_t num) const
+ {
+ AABBNodeMB_t* node = ref.getAABBNodeMB();
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<num; i++) {
+ node->setRef(i, children[i].ref);
+ node->setBounds(i, children[i].lbounds, tbounds);
+ bounds.extend(children[i].lbounds);
+ }
+ return NodeRecordMB(ref,bounds);
+ }
+
+ BBox1f tbounds;
+ };
+
+ /*! Clears the node. */
+ __forceinline void clear() {
+ lower_x = lower_y = lower_z = vfloat<N>(pos_inf);
+ upper_x = upper_y = upper_z = vfloat<N>(neg_inf);
+ lower_dx = lower_dy = lower_dz = vfloat<N>(0.0f);
+ upper_dx = upper_dy = upper_dz = vfloat<N>(0.0f);
+ BaseNode_t<NodeRef,N>::clear();
+ }
+
+ /*! Sets ID of child. */
+ __forceinline void setRef(size_t i, NodeRef ref) {
+ children[i] = ref;
+ }
+
+ /*! Sets bounding box of child. */
+ __forceinline void setBounds(size_t i, const BBox3fa& bounds0_i, const BBox3fa& bounds1_i)
+ {
+ /*! for empty bounds we have to avoid inf-inf=nan */
+ BBox3fa bounds0(min(bounds0_i.lower,Vec3fa(+FLT_MAX)),max(bounds0_i.upper,Vec3fa(-FLT_MAX)));
+ BBox3fa bounds1(min(bounds1_i.lower,Vec3fa(+FLT_MAX)),max(bounds1_i.upper,Vec3fa(-FLT_MAX)));
+ bounds0 = bounds0.enlarge_by(4.0f*float(ulp));
+ bounds1 = bounds1.enlarge_by(4.0f*float(ulp));
+ Vec3fa dlower = bounds1.lower-bounds0.lower;
+ Vec3fa dupper = bounds1.upper-bounds0.upper;
+
+ lower_x[i] = bounds0.lower.x; lower_y[i] = bounds0.lower.y; lower_z[i] = bounds0.lower.z;
+ upper_x[i] = bounds0.upper.x; upper_y[i] = bounds0.upper.y; upper_z[i] = bounds0.upper.z;
+
+ lower_dx[i] = dlower.x; lower_dy[i] = dlower.y; lower_dz[i] = dlower.z;
+ upper_dx[i] = dupper.x; upper_dy[i] = dupper.y; upper_dz[i] = dupper.z;
+ }
+
+ /*! Sets bounding box of child. */
+ __forceinline void setBounds(size_t i, const LBBox3fa& bounds) {
+ setBounds(i, bounds.bounds0, bounds.bounds1);
+ }
+
+ /*! Sets bounding box of child. */
+ __forceinline void setBounds(size_t i, const LBBox3fa& bounds, const BBox1f& tbounds) {
+ setBounds(i, bounds.global(tbounds));
+ }
+
+ /*! Sets bounding box and ID of child. */
+ __forceinline void set(size_t i, NodeRef ref, const BBox3fa& bounds) {
+ lower_x[i] = bounds.lower.x; lower_y[i] = bounds.lower.y; lower_z[i] = bounds.lower.z;
+ upper_x[i] = bounds.upper.x; upper_y[i] = bounds.upper.y; upper_z[i] = bounds.upper.z;
+ children[i] = ref;
+ }
+
+ /*! Sets bounding box and ID of child. */
+ __forceinline void set(size_t i, const NodeRecordMB4D& child)
+ {
+ setRef(i, child.ref);
+ setBounds(i, child.lbounds, child.dt);
+ }
+
+ /*! Return bounding box for time 0 */
+ __forceinline BBox3fa bounds0(size_t i) const {
+ return BBox3fa(Vec3fa(lower_x[i],lower_y[i],lower_z[i]),
+ Vec3fa(upper_x[i],upper_y[i],upper_z[i]));
+ }
+
+ /*! Return bounding box for time 1 */
+ __forceinline BBox3fa bounds1(size_t i) const {
+ return BBox3fa(Vec3fa(lower_x[i]+lower_dx[i],lower_y[i]+lower_dy[i],lower_z[i]+lower_dz[i]),
+ Vec3fa(upper_x[i]+upper_dx[i],upper_y[i]+upper_dy[i],upper_z[i]+upper_dz[i]));
+ }
+
+ /*! Returns bounds of node. */
+ __forceinline BBox3fa bounds() const {
+ return BBox3fa(Vec3fa(reduce_min(min(lower_x,lower_x+lower_dx)),
+ reduce_min(min(lower_y,lower_y+lower_dy)),
+ reduce_min(min(lower_z,lower_z+lower_dz))),
+ Vec3fa(reduce_max(max(upper_x,upper_x+upper_dx)),
+ reduce_max(max(upper_y,upper_y+upper_dy)),
+ reduce_max(max(upper_z,upper_z+upper_dz))));
+ }
+
+ /*! Return bounding box of child i */
+ __forceinline BBox3fa bounds(size_t i) const {
+ return merge(bounds0(i),bounds1(i));
+ }
+
+ /*! Return linear bounding box of child i */
+ __forceinline LBBox3fa lbounds(size_t i) const {
+ return LBBox3fa(bounds0(i),bounds1(i));
+ }
+
+ /*! Return bounding box of child i at specified time */
+ __forceinline BBox3fa bounds(size_t i, float time) const {
+ return lerp(bounds0(i),bounds1(i),time);
+ }
+
+ /*! Returns the expected surface area when randomly sampling the time. */
+ __forceinline float expectedHalfArea(size_t i) const {
+ return lbounds(i).expectedHalfArea();
+ }
+
+ /*! Returns the expected surface area when randomly sampling the time. */
+ __forceinline float expectedHalfArea(size_t i, const BBox1f& t0t1) const {
+ return lbounds(i).expectedHalfArea(t0t1);
+ }
+
+ /*! swap two children of the node */
+ __forceinline void swap(size_t i, size_t j)
+ {
+ assert(i<N && j<N);
+ std::swap(children[i],children[j]);
+
+ std::swap(lower_x[i],lower_x[j]);
+ std::swap(upper_x[i],upper_x[j]);
+ std::swap(lower_y[i],lower_y[j]);
+ std::swap(upper_y[i],upper_y[j]);
+ std::swap(lower_z[i],lower_z[j]);
+ std::swap(upper_z[i],upper_z[j]);
+
+ std::swap(lower_dx[i],lower_dx[j]);
+ std::swap(upper_dx[i],upper_dx[j]);
+ std::swap(lower_dy[i],lower_dy[j]);
+ std::swap(upper_dy[i],upper_dy[j]);
+ std::swap(lower_dz[i],lower_dz[j]);
+ std::swap(upper_dz[i],upper_dz[j]);
+ }
+
+ /*! compacts a node (moves empty children to the end) */
+ __forceinline static void compact(AABBNodeMB_t* a)
+ {
+ /* find right most filled node */
+ ssize_t j=N;
+ for (j=j-1; j>=0; j--)
+ if (a->child(j) != NodeRef::emptyNode)
+ break;
+
+ /* replace empty nodes with filled nodes */
+ for (ssize_t i=0; i<j; i++) {
+ if (a->child(i) == NodeRef::emptyNode) {
+ a->swap(i,j);
+ for (j=j-1; j>i; j--)
+ if (a->child(j) != NodeRef::emptyNode)
+ break;
+ }
+ }
+ }
+
+ /*! Returns reference to specified child */
+ __forceinline NodeRef& child(size_t i) { assert(i<N); return children[i]; }
+ __forceinline const NodeRef& child(size_t i) const { assert(i<N); return children[i]; }
+
+ /*! stream output operator */
+ friend embree_ostream operator<<(embree_ostream cout, const AABBNodeMB_t& n)
+ {
+ cout << "AABBNodeMB {" << embree_endl;
+ for (size_t i=0; i<N; i++)
+ {
+ const BBox3fa b0 = n.bounds0(i);
+ const BBox3fa b1 = n.bounds1(i);
+ cout << " child" << i << " { " << embree_endl;
+ cout << " bounds0 = " << b0 << ", " << embree_endl;
+ cout << " bounds1 = " << b1 << ", " << embree_endl;
+ cout << " }";
+ }
+ cout << "}";
+ return cout;
+ }
+
+ public:
+ vfloat<N> lower_x; //!< X dimension of lower bounds of all N children.
+ vfloat<N> upper_x; //!< X dimension of upper bounds of all N children.
+ vfloat<N> lower_y; //!< Y dimension of lower bounds of all N children.
+ vfloat<N> upper_y; //!< Y dimension of upper bounds of all N children.
+ vfloat<N> lower_z; //!< Z dimension of lower bounds of all N children.
+ vfloat<N> upper_z; //!< Z dimension of upper bounds of all N children.
+
+ vfloat<N> lower_dx; //!< X dimension of lower bounds of all N children.
+ vfloat<N> upper_dx; //!< X dimension of upper bounds of all N children.
+ vfloat<N> lower_dy; //!< Y dimension of lower bounds of all N children.
+ vfloat<N> upper_dy; //!< Y dimension of upper bounds of all N children.
+ vfloat<N> lower_dz; //!< Z dimension of lower bounds of all N children.
+ vfloat<N> upper_dz; //!< Z dimension of upper bounds of all N children.
+ };
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_node_aabb_mb4d.h b/thirdparty/embree/kernels/bvh/bvh_node_aabb_mb4d.h
new file mode 100644
index 0000000000..46a81d7581
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_node_aabb_mb4d.h
@@ -0,0 +1,107 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_aabb_mb.h"
+
+namespace embree
+{
+ /*! Aligned 4D Motion Blur Node */
+ template<typename NodeRef, int N>
+ struct AABBNodeMB4D_t : public AABBNodeMB_t<NodeRef, N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+ using AABBNodeMB_t<NodeRef,N>::set;
+
+ typedef BVHNodeRecord<NodeRef> NodeRecord;
+ typedef BVHNodeRecordMB<NodeRef> NodeRecordMB;
+ typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D;
+
+ struct Create
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (BuildRecord*, const size_t, const FastAllocator::CachedAllocator& alloc, bool hasTimeSplits = true) const
+ {
+ if (hasTimeSplits)
+ {
+ AABBNodeMB4D_t* node = (AABBNodeMB4D_t*) alloc.malloc0(sizeof(AABBNodeMB4D_t),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ else
+ {
+ AABBNodeMB_t<NodeRef,N>* node = (AABBNodeMB_t<NodeRef,N>*) alloc.malloc0(sizeof(AABBNodeMB_t<NodeRef,N>),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ }
+ };
+
+ struct Set
+ {
+ template<typename BuildRecord>
+ __forceinline void operator() (const BuildRecord&, const BuildRecord*, NodeRef ref, NodeRecordMB4D* children, const size_t num) const
+ {
+ if (likely(ref.isAABBNodeMB())) {
+ for (size_t i=0; i<num; i++)
+ ref.getAABBNodeMB()->set(i, children[i]);
+ } else {
+ for (size_t i=0; i<num; i++)
+ ref.getAABBNodeMB4D()->set(i, children[i]);
+ }
+ }
+ };
+
+ /*! Clears the node. */
+ __forceinline void clear() {
+ lower_t = vfloat<N>(pos_inf);
+ upper_t = vfloat<N>(neg_inf);
+ AABBNodeMB_t<NodeRef,N>::clear();
+ }
+
+ /*! Sets bounding box of child. */
+ __forceinline void setBounds(size_t i, const LBBox3fa& bounds, const BBox1f& tbounds)
+ {
+ AABBNodeMB_t<NodeRef,N>::setBounds(i, bounds.global(tbounds));
+ lower_t[i] = tbounds.lower;
+ upper_t[i] = tbounds.upper == 1.0f ? 1.0f+float(ulp) : tbounds.upper;
+ }
+
+ /*! Sets bounding box and ID of child. */
+ __forceinline void set(size_t i, const NodeRecordMB4D& child) {
+ AABBNodeMB_t<NodeRef,N>::setRef(i,child.ref);
+ setBounds(i, child.lbounds, child.dt);
+ }
+
+ /*! Returns the expected surface area when randomly sampling the time. */
+ __forceinline float expectedHalfArea(size_t i) const {
+ return AABBNodeMB_t<NodeRef,N>::lbounds(i).expectedHalfArea(timeRange(i));
+ }
+
+ /*! returns time range for specified child */
+ __forceinline BBox1f timeRange(size_t i) const {
+ return BBox1f(lower_t[i],upper_t[i]);
+ }
+
+ /*! stream output operator */
+ friend embree_ostream operator<<(embree_ostream cout, const AABBNodeMB4D_t& n)
+ {
+ cout << "AABBNodeMB4D {" << embree_endl;
+ for (size_t i=0; i<N; i++)
+ {
+ const BBox3fa b0 = n.bounds0(i);
+ const BBox3fa b1 = n.bounds1(i);
+ cout << " child" << i << " { " << embree_endl;
+ cout << " bounds0 = " << lerp(b0,b1,n.lower_t[i]) << ", " << embree_endl;
+ cout << " bounds1 = " << lerp(b0,b1,n.upper_t[i]) << ", " << embree_endl;
+ cout << " time_bounds = " << n.lower_t[i] << ", " << n.upper_t[i] << embree_endl;
+ cout << " }";
+ }
+ cout << "}";
+ return cout;
+ }
+
+ public:
+ vfloat<N> lower_t; //!< time dimension of lower bounds of all N children
+ vfloat<N> upper_t; //!< time dimension of upper bounds of all N children
+ };
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_node_base.h b/thirdparty/embree/kernels/bvh/bvh_node_base.h
new file mode 100644
index 0000000000..a5570a7b9e
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_node_base.h
@@ -0,0 +1,43 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_ref.h"
+
+namespace embree
+{
+
+ /*! BVHN Base Node */
+ template<typename NodeRef, int N>
+ struct BaseNode_t
+ {
+ /*! Clears the node. */
+ __forceinline void clear()
+ {
+ for (size_t i=0; i<N; i++)
+ children[i] = NodeRef::emptyNode;
+ }
+
+ /*! Returns reference to specified child */
+ __forceinline NodeRef& child(size_t i) { assert(i<N); return children[i]; }
+ __forceinline const NodeRef& child(size_t i) const { assert(i<N); return children[i]; }
+
+ /*! verifies the node */
+ __forceinline bool verify() const
+ {
+ for (size_t i=0; i<N; i++) {
+ if (child(i) == NodeRef::emptyNode) {
+ for (; i<N; i++) {
+ if (child(i) != NodeRef::emptyNode)
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+ }
+
+ NodeRef children[N]; //!< Pointer to the N children (can be a node or leaf)
+ };
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_node_obb.h b/thirdparty/embree/kernels/bvh/bvh_node_obb.h
new file mode 100644
index 0000000000..e6b500691e
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_node_obb.h
@@ -0,0 +1,98 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_base.h"
+
+namespace embree
+{
+ /*! Node with unaligned bounds */
+ template<typename NodeRef, int N>
+ struct OBBNode_t : public BaseNode_t<NodeRef, N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+
+ struct Create
+ {
+ __forceinline NodeRef operator() (const FastAllocator::CachedAllocator& alloc) const
+ {
+ OBBNode_t* node = (OBBNode_t*) alloc.malloc0(sizeof(OBBNode_t),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ };
+
+ struct Set
+ {
+ __forceinline void operator() (NodeRef node, size_t i, NodeRef child, const OBBox3fa& bounds) const {
+ node.ungetAABBNode()->setRef(i,child);
+ node.ungetAABBNode()->setBounds(i,bounds);
+ }
+ };
+
+ /*! Clears the node. */
+ __forceinline void clear()
+ {
+ naabb.l.vx = Vec3fa(nan);
+ naabb.l.vy = Vec3fa(nan);
+ naabb.l.vz = Vec3fa(nan);
+ naabb.p = Vec3fa(nan);
+ BaseNode_t<NodeRef,N>::clear();
+ }
+
+ /*! Sets bounding box. */
+ __forceinline void setBounds(size_t i, const OBBox3fa& b)
+ {
+ assert(i < N);
+
+ AffineSpace3fa space = b.space;
+ space.p -= b.bounds.lower;
+ space = AffineSpace3fa::scale(1.0f/max(Vec3fa(1E-19f),b.bounds.upper-b.bounds.lower))*space;
+
+ naabb.l.vx.x[i] = space.l.vx.x;
+ naabb.l.vx.y[i] = space.l.vx.y;
+ naabb.l.vx.z[i] = space.l.vx.z;
+
+ naabb.l.vy.x[i] = space.l.vy.x;
+ naabb.l.vy.y[i] = space.l.vy.y;
+ naabb.l.vy.z[i] = space.l.vy.z;
+
+ naabb.l.vz.x[i] = space.l.vz.x;
+ naabb.l.vz.y[i] = space.l.vz.y;
+ naabb.l.vz.z[i] = space.l.vz.z;
+
+ naabb.p.x[i] = space.p.x;
+ naabb.p.y[i] = space.p.y;
+ naabb.p.z[i] = space.p.z;
+ }
+
+ /*! Sets ID of child. */
+ __forceinline void setRef(size_t i, const NodeRef& ref) {
+ assert(i < N);
+ children[i] = ref;
+ }
+
+ /*! Returns the extent of the bounds of the ith child */
+ __forceinline Vec3fa extent(size_t i) const {
+ assert(i<N);
+ const Vec3fa vx(naabb.l.vx.x[i],naabb.l.vx.y[i],naabb.l.vx.z[i]);
+ const Vec3fa vy(naabb.l.vy.x[i],naabb.l.vy.y[i],naabb.l.vy.z[i]);
+ const Vec3fa vz(naabb.l.vz.x[i],naabb.l.vz.y[i],naabb.l.vz.z[i]);
+ return rsqrt(vx*vx + vy*vy + vz*vz);
+ }
+
+ /*! Returns reference to specified child */
+ __forceinline NodeRef& child(size_t i) { assert(i<N); return children[i]; }
+ __forceinline const NodeRef& child(size_t i) const { assert(i<N); return children[i]; }
+
+ /*! output operator */
+ friend embree_ostream operator<<(embree_ostream o, const OBBNode_t& n)
+ {
+ o << "UnAABBNode { " << n.naabb << " } " << embree_endl;
+ return o;
+ }
+
+ public:
+ AffineSpace3vf<N> naabb; //!< non-axis aligned bounding boxes (bounds are [0,1] in specified space)
+ };
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_node_obb_mb.h b/thirdparty/embree/kernels/bvh/bvh_node_obb_mb.h
new file mode 100644
index 0000000000..c06b1aea5e
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_node_obb_mb.h
@@ -0,0 +1,90 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_base.h"
+
+namespace embree
+{
+ template<typename NodeRef, int N>
+ struct OBBNodeMB_t : public BaseNode_t<NodeRef, N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+
+ struct Create
+ {
+ __forceinline NodeRef operator() (const FastAllocator::CachedAllocator& alloc) const
+ {
+ OBBNodeMB_t* node = (OBBNodeMB_t*) alloc.malloc0(sizeof(OBBNodeMB_t),NodeRef::byteNodeAlignment); node->clear();
+ return NodeRef::encodeNode(node);
+ }
+ };
+
+ struct Set
+ {
+ __forceinline void operator() (NodeRef node, size_t i, NodeRef child, const LinearSpace3fa& space, const LBBox3fa& lbounds, const BBox1f dt) const {
+ node.ungetAABBNodeMB()->setRef(i,child);
+ node.ungetAABBNodeMB()->setBounds(i,space,lbounds.global(dt));
+ }
+ };
+
+ /*! Clears the node. */
+ __forceinline void clear()
+ {
+ space0 = one;
+ //b0.lower = b0.upper = Vec3fa(nan);
+ b1.lower = b1.upper = Vec3fa(nan);
+ BaseNode_t<NodeRef,N>::clear();
+ }
+
+ /*! Sets space and bounding boxes. */
+ __forceinline void setBounds(size_t i, const AffineSpace3fa& space, const LBBox3fa& lbounds) {
+ setBounds(i,space,lbounds.bounds0,lbounds.bounds1);
+ }
+
+ /*! Sets space and bounding boxes. */
+ __forceinline void setBounds(size_t i, const AffineSpace3fa& s0, const BBox3fa& a, const BBox3fa& c)
+ {
+ assert(i < N);
+
+ AffineSpace3fa space = s0;
+ space.p -= a.lower;
+ Vec3fa scale = 1.0f/max(Vec3fa(1E-19f),a.upper-a.lower);
+ space = AffineSpace3fa::scale(scale)*space;
+ BBox3fa a1((a.lower-a.lower)*scale,(a.upper-a.lower)*scale);
+ BBox3fa c1((c.lower-a.lower)*scale,(c.upper-a.lower)*scale);
+
+ space0.l.vx.x[i] = space.l.vx.x; space0.l.vx.y[i] = space.l.vx.y; space0.l.vx.z[i] = space.l.vx.z;
+ space0.l.vy.x[i] = space.l.vy.x; space0.l.vy.y[i] = space.l.vy.y; space0.l.vy.z[i] = space.l.vy.z;
+ space0.l.vz.x[i] = space.l.vz.x; space0.l.vz.y[i] = space.l.vz.y; space0.l.vz.z[i] = space.l.vz.z;
+ space0.p .x[i] = space.p .x; space0.p .y[i] = space.p .y; space0.p .z[i] = space.p .z;
+
+ /*b0.lower.x[i] = a1.lower.x; b0.lower.y[i] = a1.lower.y; b0.lower.z[i] = a1.lower.z;
+ b0.upper.x[i] = a1.upper.x; b0.upper.y[i] = a1.upper.y; b0.upper.z[i] = a1.upper.z;*/
+
+ b1.lower.x[i] = c1.lower.x; b1.lower.y[i] = c1.lower.y; b1.lower.z[i] = c1.lower.z;
+ b1.upper.x[i] = c1.upper.x; b1.upper.y[i] = c1.upper.y; b1.upper.z[i] = c1.upper.z;
+ }
+
+ /*! Sets ID of child. */
+ __forceinline void setRef(size_t i, const NodeRef& ref) {
+ assert(i < N);
+ children[i] = ref;
+ }
+
+ /*! Returns the extent of the bounds of the ith child */
+ __forceinline Vec3fa extent0(size_t i) const {
+ assert(i < N);
+ const Vec3fa vx(space0.l.vx.x[i],space0.l.vx.y[i],space0.l.vx.z[i]);
+ const Vec3fa vy(space0.l.vy.x[i],space0.l.vy.y[i],space0.l.vy.z[i]);
+ const Vec3fa vz(space0.l.vz.x[i],space0.l.vz.y[i],space0.l.vz.z[i]);
+ return rsqrt(vx*vx + vy*vy + vz*vz);
+ }
+
+ public:
+ AffineSpace3vf<N> space0;
+ //BBox3vf<N> b0; // these are the unit bounds
+ BBox3vf<N> b1;
+ };
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_node_qaabb.h b/thirdparty/embree/kernels/bvh/bvh_node_qaabb.h
new file mode 100644
index 0000000000..2afc8c98e7
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_node_qaabb.h
@@ -0,0 +1,265 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh_node_base.h"
+
+namespace embree
+{
+ /*! BVHN Quantized Node */
+ template<int N>
+ struct __aligned(8) QuantizedBaseNode_t
+ {
+ typedef unsigned char T;
+ static const T MIN_QUAN = 0;
+ static const T MAX_QUAN = 255;
+
+ /*! Clears the node. */
+ __forceinline void clear() {
+ for (size_t i=0; i<N; i++) lower_x[i] = lower_y[i] = lower_z[i] = MAX_QUAN;
+ for (size_t i=0; i<N; i++) upper_x[i] = upper_y[i] = upper_z[i] = MIN_QUAN;
+ }
+
+ /*! Returns bounds of specified child. */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ assert(i < N);
+ const Vec3fa lower(madd(scale.x,(float)lower_x[i],start.x),
+ madd(scale.y,(float)lower_y[i],start.y),
+ madd(scale.z,(float)lower_z[i],start.z));
+ const Vec3fa upper(madd(scale.x,(float)upper_x[i],start.x),
+ madd(scale.y,(float)upper_y[i],start.y),
+ madd(scale.z,(float)upper_z[i],start.z));
+ return BBox3fa(lower,upper);
+ }
+
+ /*! Returns extent of bounds of specified child. */
+ __forceinline Vec3fa extent(size_t i) const {
+ return bounds(i).size();
+ }
+
+ static __forceinline void init_dim(const vfloat<N> &lower,
+ const vfloat<N> &upper,
+ T lower_quant[N],
+ T upper_quant[N],
+ float &start,
+ float &scale)
+ {
+ /* quantize bounds */
+ const vbool<N> m_valid = lower != vfloat<N>(pos_inf);
+ const float minF = reduce_min(lower);
+ const float maxF = reduce_max(upper);
+ float diff = (1.0f+2.0f*float(ulp))*(maxF - minF);
+ float decode_scale = diff / float(MAX_QUAN);
+ if (decode_scale == 0.0f) decode_scale = 2.0f*FLT_MIN; // result may have been flushed to zero
+ assert(madd(decode_scale,float(MAX_QUAN),minF) >= maxF);
+ const float encode_scale = diff > 0 ? (float(MAX_QUAN) / diff) : 0.0f;
+ vint<N> ilower = max(vint<N>(floor((lower - vfloat<N>(minF))*vfloat<N>(encode_scale))),MIN_QUAN);
+ vint<N> iupper = min(vint<N>(ceil ((upper - vfloat<N>(minF))*vfloat<N>(encode_scale))),MAX_QUAN);
+
+ /* lower/upper correction */
+ vbool<N> m_lower_correction = (madd(vfloat<N>(ilower),decode_scale,minF)) > lower;
+ vbool<N> m_upper_correction = (madd(vfloat<N>(iupper),decode_scale,minF)) < upper;
+ ilower = max(select(m_lower_correction,ilower-1,ilower),MIN_QUAN);
+ iupper = min(select(m_upper_correction,iupper+1,iupper),MAX_QUAN);
+
+ /* disable invalid lanes */
+ ilower = select(m_valid,ilower,MAX_QUAN);
+ iupper = select(m_valid,iupper,MIN_QUAN);
+
+ /* store as uchar to memory */
+ vint<N>::store(lower_quant,ilower);
+ vint<N>::store(upper_quant,iupper);
+ start = minF;
+ scale = decode_scale;
+
+#if defined(DEBUG)
+ vfloat<N> extract_lower( vint<N>::loadu(lower_quant) );
+ vfloat<N> extract_upper( vint<N>::loadu(upper_quant) );
+ vfloat<N> final_extract_lower = madd(extract_lower,decode_scale,minF);
+ vfloat<N> final_extract_upper = madd(extract_upper,decode_scale,minF);
+ assert( (movemask(final_extract_lower <= lower ) & movemask(m_valid)) == movemask(m_valid));
+ assert( (movemask(final_extract_upper >= upper ) & movemask(m_valid)) == movemask(m_valid));
+#endif
+ }
+
+ __forceinline void init_dim(AABBNode_t<NodeRefPtr<N>,N>& node)
+ {
+ init_dim(node.lower_x,node.upper_x,lower_x,upper_x,start.x,scale.x);
+ init_dim(node.lower_y,node.upper_y,lower_y,upper_y,start.y,scale.y);
+ init_dim(node.lower_z,node.upper_z,lower_z,upper_z,start.z,scale.z);
+ }
+
+ __forceinline vbool<N> validMask() const { return vint<N>::loadu(lower_x) <= vint<N>::loadu(upper_x); }
+
+#if defined(__AVX512F__) // KNL
+ __forceinline vbool16 validMask16() const { return le(0xff,vint<16>::loadu(lower_x),vint<16>::loadu(upper_x)); }
+#endif
+ __forceinline vfloat<N> dequantizeLowerX() const { return madd(vfloat<N>(vint<N>::loadu(lower_x)),scale.x,vfloat<N>(start.x)); }
+
+ __forceinline vfloat<N> dequantizeUpperX() const { return madd(vfloat<N>(vint<N>::loadu(upper_x)),scale.x,vfloat<N>(start.x)); }
+
+ __forceinline vfloat<N> dequantizeLowerY() const { return madd(vfloat<N>(vint<N>::loadu(lower_y)),scale.y,vfloat<N>(start.y)); }
+
+ __forceinline vfloat<N> dequantizeUpperY() const { return madd(vfloat<N>(vint<N>::loadu(upper_y)),scale.y,vfloat<N>(start.y)); }
+
+ __forceinline vfloat<N> dequantizeLowerZ() const { return madd(vfloat<N>(vint<N>::loadu(lower_z)),scale.z,vfloat<N>(start.z)); }
+
+ __forceinline vfloat<N> dequantizeUpperZ() const { return madd(vfloat<N>(vint<N>::loadu(upper_z)),scale.z,vfloat<N>(start.z)); }
+
+ template <int M>
+ __forceinline vfloat<M> dequantize(const size_t offset) const { return vfloat<M>(vint<M>::loadu(all_planes+offset)); }
+
+#if defined(__AVX512F__)
+ __forceinline vfloat16 dequantizeLowerUpperX(const vint16 &p) const { return madd(vfloat16(permute(vint<16>::loadu(lower_x),p)),scale.x,vfloat16(start.x)); }
+ __forceinline vfloat16 dequantizeLowerUpperY(const vint16 &p) const { return madd(vfloat16(permute(vint<16>::loadu(lower_y),p)),scale.y,vfloat16(start.y)); }
+ __forceinline vfloat16 dequantizeLowerUpperZ(const vint16 &p) const { return madd(vfloat16(permute(vint<16>::loadu(lower_z),p)),scale.z,vfloat16(start.z)); }
+#endif
+
+ union {
+ struct {
+ T lower_x[N]; //!< 8bit discretized X dimension of lower bounds of all N children
+ T upper_x[N]; //!< 8bit discretized X dimension of upper bounds of all N children
+ T lower_y[N]; //!< 8bit discretized Y dimension of lower bounds of all N children
+ T upper_y[N]; //!< 8bit discretized Y dimension of upper bounds of all N children
+ T lower_z[N]; //!< 8bit discretized Z dimension of lower bounds of all N children
+ T upper_z[N]; //!< 8bit discretized Z dimension of upper bounds of all N children
+ };
+ T all_planes[6*N];
+ };
+
+ Vec3f start;
+ Vec3f scale;
+
+ friend embree_ostream operator<<(embree_ostream o, const QuantizedBaseNode_t& n)
+ {
+ o << "QuantizedBaseNode { " << embree_endl;
+ o << " start " << n.start << embree_endl;
+ o << " scale " << n.scale << embree_endl;
+ o << " lower_x " << vuint<N>::loadu(n.lower_x) << embree_endl;
+ o << " upper_x " << vuint<N>::loadu(n.upper_x) << embree_endl;
+ o << " lower_y " << vuint<N>::loadu(n.lower_y) << embree_endl;
+ o << " upper_y " << vuint<N>::loadu(n.upper_y) << embree_endl;
+ o << " lower_z " << vuint<N>::loadu(n.lower_z) << embree_endl;
+ o << " upper_z " << vuint<N>::loadu(n.upper_z) << embree_endl;
+ o << "}" << embree_endl;
+ return o;
+ }
+
+ };
+
+ template<typename NodeRef, int N>
+ struct __aligned(8) QuantizedNode_t : public BaseNode_t<NodeRef, N>, QuantizedBaseNode_t<N>
+ {
+ using BaseNode_t<NodeRef,N>::children;
+ using QuantizedBaseNode_t<N>::lower_x;
+ using QuantizedBaseNode_t<N>::upper_x;
+ using QuantizedBaseNode_t<N>::lower_y;
+ using QuantizedBaseNode_t<N>::upper_y;
+ using QuantizedBaseNode_t<N>::lower_z;
+ using QuantizedBaseNode_t<N>::upper_z;
+ using QuantizedBaseNode_t<N>::start;
+ using QuantizedBaseNode_t<N>::scale;
+ using QuantizedBaseNode_t<N>::init_dim;
+
+ __forceinline void setRef(size_t i, const NodeRef& ref) {
+ assert(i < N);
+ children[i] = ref;
+ }
+
+ struct Create2
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (BuildRecord* children, const size_t n, const FastAllocator::CachedAllocator& alloc) const
+ {
+ __aligned(64) AABBNode_t<NodeRef,N> node;
+ node.clear();
+ for (size_t i=0; i<n; i++) {
+ node.setBounds(i,children[i].bounds());
+ }
+ QuantizedNode_t *qnode = (QuantizedNode_t*) alloc.malloc0(sizeof(QuantizedNode_t), NodeRef::byteAlignment);
+ qnode->init(node);
+
+ return (size_t)qnode | NodeRef::tyQuantizedNode;
+ }
+ };
+
+ struct Set2
+ {
+ template<typename BuildRecord>
+ __forceinline NodeRef operator() (const BuildRecord& precord, const BuildRecord* crecords, NodeRef ref, NodeRef* children, const size_t num) const
+ {
+ QuantizedNode_t* node = ref.quantizedNode();
+ for (size_t i=0; i<num; i++) node->setRef(i,children[i]);
+ return ref;
+ }
+ };
+
+ __forceinline void init(AABBNode_t<NodeRef,N>& node)
+ {
+ for (size_t i=0;i<N;i++) children[i] = NodeRef::emptyNode;
+ init_dim(node);
+ }
+
+ };
+
+ /*! BVHN Quantized Node */
+ template<int N>
+ struct __aligned(8) QuantizedBaseNodeMB_t
+ {
+ QuantizedBaseNode_t<N> node0;
+ QuantizedBaseNode_t<N> node1;
+
+ /*! Clears the node. */
+ __forceinline void clear() {
+ node0.clear();
+ node1.clear();
+ }
+
+ /*! Returns bounds of specified child. */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ assert(i < N);
+ BBox3fa bounds0 = node0.bounds(i);
+ BBox3fa bounds1 = node1.bounds(i);
+ bounds0.extend(bounds1);
+ return bounds0;
+ }
+
+ /*! Returns extent of bounds of specified child. */
+ __forceinline Vec3fa extent(size_t i) const {
+ return bounds(i).size();
+ }
+
+ __forceinline vbool<N> validMask() const { return node0.validMask(); }
+
+ template<typename T>
+ __forceinline vfloat<N> dequantizeLowerX(const T t) const { return lerp(node0.dequantizeLowerX(),node1.dequantizeLowerX(),t); }
+ template<typename T>
+ __forceinline vfloat<N> dequantizeUpperX(const T t) const { return lerp(node0.dequantizeUpperX(),node1.dequantizeUpperX(),t); }
+ template<typename T>
+ __forceinline vfloat<N> dequantizeLowerY(const T t) const { return lerp(node0.dequantizeLowerY(),node1.dequantizeLowerY(),t); }
+ template<typename T>
+ __forceinline vfloat<N> dequantizeUpperY(const T t) const { return lerp(node0.dequantizeUpperY(),node1.dequantizeUpperY(),t); }
+ template<typename T>
+ __forceinline vfloat<N> dequantizeLowerZ(const T t) const { return lerp(node0.dequantizeLowerZ(),node1.dequantizeLowerZ(),t); }
+ template<typename T>
+ __forceinline vfloat<N> dequantizeUpperZ(const T t) const { return lerp(node0.dequantizeUpperZ(),node1.dequantizeUpperZ(),t); }
+
+
+ template<int M>
+ __forceinline vfloat<M> dequantizeLowerX(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeLowerX()[i]),vfloat<M>(node1.dequantizeLowerX()[i]),t); }
+ template<int M>
+ __forceinline vfloat<M> dequantizeUpperX(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeUpperX()[i]),vfloat<M>(node1.dequantizeUpperX()[i]),t); }
+ template<int M>
+ __forceinline vfloat<M> dequantizeLowerY(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeLowerY()[i]),vfloat<M>(node1.dequantizeLowerY()[i]),t); }
+ template<int M>
+ __forceinline vfloat<M> dequantizeUpperY(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeUpperY()[i]),vfloat<M>(node1.dequantizeUpperY()[i]),t); }
+ template<int M>
+ __forceinline vfloat<M> dequantizeLowerZ(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeLowerZ()[i]),vfloat<M>(node1.dequantizeLowerZ()[i]),t); }
+ template<int M>
+ __forceinline vfloat<M> dequantizeUpperZ(const size_t i, const vfloat<M> &t) const { return lerp(vfloat<M>(node0.dequantizeUpperZ()[i]),vfloat<M>(node1.dequantizeUpperZ()[i]),t); }
+
+ };
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_node_ref.h b/thirdparty/embree/kernels/bvh/bvh_node_ref.h
new file mode 100644
index 0000000000..6f6da758de
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_node_ref.h
@@ -0,0 +1,242 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/alloc.h"
+#include "../common/accel.h"
+#include "../common/device.h"
+#include "../common/scene.h"
+#include "../geometry/primitive.h"
+#include "../common/ray.h"
+
+namespace embree
+{
+ /* BVH node reference with bounds */
+ template<typename NodeRef>
+ struct BVHNodeRecord
+ {
+ __forceinline BVHNodeRecord() {}
+ __forceinline BVHNodeRecord(NodeRef ref, const BBox3fa& bounds) : ref(ref), bounds((BBox3fx)bounds) {}
+ __forceinline BVHNodeRecord(NodeRef ref, const BBox3fx& bounds) : ref(ref), bounds(bounds) {}
+
+ NodeRef ref;
+ BBox3fx bounds;
+ };
+
+ template<typename NodeRef>
+ struct BVHNodeRecordMB
+ {
+ __forceinline BVHNodeRecordMB() {}
+ __forceinline BVHNodeRecordMB(NodeRef ref, const LBBox3fa& lbounds) : ref(ref), lbounds(lbounds) {}
+
+ NodeRef ref;
+ LBBox3fa lbounds;
+ };
+
+ template<typename NodeRef>
+ struct BVHNodeRecordMB4D
+ {
+ __forceinline BVHNodeRecordMB4D() {}
+ __forceinline BVHNodeRecordMB4D(NodeRef ref, const LBBox3fa& lbounds, const BBox1f& dt) : ref(ref), lbounds(lbounds), dt(dt) {}
+
+ NodeRef ref;
+ LBBox3fa lbounds;
+ BBox1f dt;
+ };
+
+ template<typename NodeRef, int N> struct BaseNode_t;
+ template<typename NodeRef, int N> struct AABBNode_t;
+ template<typename NodeRef, int N> struct AABBNodeMB_t;
+ template<typename NodeRef, int N> struct AABBNodeMB4D_t;
+ template<typename NodeRef, int N> struct OBBNode_t;
+ template<typename NodeRef, int N> struct OBBNodeMB_t;
+ template<typename NodeRef, int N> struct QuantizedNode_t;
+ template<typename NodeRef, int N> struct QuantizedNodeMB_t;
+
+ /*! Pointer that points to a node or a list of primitives */
+ template<int N>
+ struct NodeRefPtr
+ {
+ //template<int NN> friend class BVHN;
+
+ /*! Number of bytes the nodes and primitives are minimally aligned to.*/
+ static const size_t byteAlignment = 16;
+ static const size_t byteNodeAlignment = 4*N;
+
+ /*! highest address bit is used as barrier for some algorithms */
+ static const size_t barrier_mask = (1LL << (8*sizeof(size_t)-1));
+
+ /*! Masks the bits that store the number of items per leaf. */
+ static const size_t align_mask = byteAlignment-1;
+ static const size_t items_mask = byteAlignment-1;
+
+ /*! different supported node types */
+ static const size_t tyAABBNode = 0;
+ static const size_t tyAABBNodeMB = 1;
+ static const size_t tyAABBNodeMB4D = 6;
+ static const size_t tyOBBNode = 2;
+ static const size_t tyOBBNodeMB = 3;
+ static const size_t tyQuantizedNode = 5;
+ static const size_t tyLeaf = 8;
+
+ /*! Empty node */
+ static const size_t emptyNode = tyLeaf;
+
+ /*! Invalid node, used as marker in traversal */
+ static const size_t invalidNode = (((size_t)-1) & (~items_mask)) | (tyLeaf+0);
+ static const size_t popRay = (((size_t)-1) & (~items_mask)) | (tyLeaf+1);
+
+ /*! Maximum number of primitive blocks in a leaf. */
+ static const size_t maxLeafBlocks = items_mask-tyLeaf;
+
+ /*! Default constructor */
+ __forceinline NodeRefPtr () {}
+
+ /*! Construction from integer */
+ __forceinline NodeRefPtr (size_t ptr) : ptr(ptr) {}
+
+ /*! Cast to size_t */
+ __forceinline operator size_t() const { return ptr; }
+
+ /*! Sets the barrier bit. */
+ __forceinline void setBarrier() {
+#if defined(__64BIT__)
+ assert(!isBarrier());
+ ptr |= barrier_mask;
+#else
+ assert(false);
+#endif
+ }
+
+ /*! Clears the barrier bit. */
+ __forceinline void clearBarrier() {
+#if defined(__64BIT__)
+ ptr &= ~barrier_mask;
+#else
+ assert(false);
+#endif
+ }
+
+ /*! Checks if this is an barrier. A barrier tells the top level tree rotations how deep to enter the tree. */
+ __forceinline bool isBarrier() const { return (ptr & barrier_mask) != 0; }
+
+ /*! checks if this is a leaf */
+ __forceinline size_t isLeaf() const { return ptr & tyLeaf; }
+
+ /*! returns node type */
+ __forceinline int type() const { return ptr & (size_t)align_mask; }
+
+ /*! checks if this is a node */
+ __forceinline int isAABBNode() const { return (ptr & (size_t)align_mask) == tyAABBNode; }
+
+ /*! checks if this is a motion blur node */
+ __forceinline int isAABBNodeMB() const { return (ptr & (size_t)align_mask) == tyAABBNodeMB; }
+
+ /*! checks if this is a 4D motion blur node */
+ __forceinline int isAABBNodeMB4D() const { return (ptr & (size_t)align_mask) == tyAABBNodeMB4D; }
+
+ /*! checks if this is a node with unaligned bounding boxes */
+ __forceinline int isOBBNode() const { return (ptr & (size_t)align_mask) == tyOBBNode; }
+
+ /*! checks if this is a motion blur node with unaligned bounding boxes */
+ __forceinline int isOBBNodeMB() const { return (ptr & (size_t)align_mask) == tyOBBNodeMB; }
+
+ /*! checks if this is a quantized node */
+ __forceinline int isQuantizedNode() const { return (ptr & (size_t)align_mask) == tyQuantizedNode; }
+
+ /*! Encodes a node */
+ static __forceinline NodeRefPtr encodeNode(AABBNode_t<NodeRefPtr,N>* node) {
+ assert(!((size_t)node & align_mask));
+ return NodeRefPtr((size_t) node);
+ }
+
+ static __forceinline NodeRefPtr encodeNode(AABBNodeMB_t<NodeRefPtr,N>* node) {
+ assert(!((size_t)node & align_mask));
+ return NodeRefPtr((size_t) node | tyAABBNodeMB);
+ }
+
+ static __forceinline NodeRefPtr encodeNode(AABBNodeMB4D_t<NodeRefPtr,N>* node) {
+ assert(!((size_t)node & align_mask));
+ return NodeRefPtr((size_t) node | tyAABBNodeMB4D);
+ }
+
+ /*! Encodes an unaligned node */
+ static __forceinline NodeRefPtr encodeNode(OBBNode_t<NodeRefPtr,N>* node) {
+ return NodeRefPtr((size_t) node | tyOBBNode);
+ }
+
+ /*! Encodes an unaligned motion blur node */
+ static __forceinline NodeRefPtr encodeNode(OBBNodeMB_t<NodeRefPtr,N>* node) {
+ return NodeRefPtr((size_t) node | tyOBBNodeMB);
+ }
+
+ /*! Encodes a leaf */
+ static __forceinline NodeRefPtr encodeLeaf(void* tri, size_t num) {
+ assert(!((size_t)tri & align_mask));
+ assert(num <= maxLeafBlocks);
+ return NodeRefPtr((size_t)tri | (tyLeaf+min(num,(size_t)maxLeafBlocks)));
+ }
+
+ /*! Encodes a leaf */
+ static __forceinline NodeRefPtr encodeTypedLeaf(void* ptr, size_t ty) {
+ assert(!((size_t)ptr & align_mask));
+ return NodeRefPtr((size_t)ptr | (tyLeaf+ty));
+ }
+
+ /*! returns base node pointer */
+ __forceinline BaseNode_t<NodeRefPtr,N>* baseNode()
+ {
+ assert(!isLeaf());
+ return (BaseNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask);
+ }
+ __forceinline const BaseNode_t<NodeRefPtr,N>* baseNode() const
+ {
+ assert(!isLeaf());
+ return (const BaseNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask);
+ }
+
+ /*! returns node pointer */
+ __forceinline AABBNode_t<NodeRefPtr,N>* getAABBNode() { assert(isAABBNode()); return ( AABBNode_t<NodeRefPtr,N>*)ptr; }
+ __forceinline const AABBNode_t<NodeRefPtr,N>* getAABBNode() const { assert(isAABBNode()); return (const AABBNode_t<NodeRefPtr,N>*)ptr; }
+
+ /*! returns motion blur node pointer */
+ __forceinline AABBNodeMB_t<NodeRefPtr,N>* getAABBNodeMB() { assert(isAABBNodeMB() || isAABBNodeMB4D()); return ( AABBNodeMB_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+ __forceinline const AABBNodeMB_t<NodeRefPtr,N>* getAABBNodeMB() const { assert(isAABBNodeMB() || isAABBNodeMB4D()); return (const AABBNodeMB_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+
+ /*! returns 4D motion blur node pointer */
+ __forceinline AABBNodeMB4D_t<NodeRefPtr,N>* getAABBNodeMB4D() { assert(isAABBNodeMB4D()); return ( AABBNodeMB4D_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+ __forceinline const AABBNodeMB4D_t<NodeRefPtr,N>* getAABBNodeMB4D() const { assert(isAABBNodeMB4D()); return (const AABBNodeMB4D_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+
+ /*! returns unaligned node pointer */
+ __forceinline OBBNode_t<NodeRefPtr,N>* ungetAABBNode() { assert(isOBBNode()); return ( OBBNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+ __forceinline const OBBNode_t<NodeRefPtr,N>* ungetAABBNode() const { assert(isOBBNode()); return (const OBBNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+
+ /*! returns unaligned motion blur node pointer */
+ __forceinline OBBNodeMB_t<NodeRefPtr,N>* ungetAABBNodeMB() { assert(isOBBNodeMB()); return ( OBBNodeMB_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+ __forceinline const OBBNodeMB_t<NodeRefPtr,N>* ungetAABBNodeMB() const { assert(isOBBNodeMB()); return (const OBBNodeMB_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask); }
+
+ /*! returns quantized node pointer */
+ __forceinline QuantizedNode_t<NodeRefPtr,N>* quantizedNode() { assert(isQuantizedNode()); return ( QuantizedNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask ); }
+ __forceinline const QuantizedNode_t<NodeRefPtr,N>* quantizedNode() const { assert(isQuantizedNode()); return (const QuantizedNode_t<NodeRefPtr,N>*)(ptr & ~(size_t)align_mask ); }
+
+ /*! returns leaf pointer */
+ __forceinline char* leaf(size_t& num) const {
+ assert(isLeaf());
+ num = (ptr & (size_t)items_mask)-tyLeaf;
+ return (char*)(ptr & ~(size_t)align_mask);
+ }
+
+ /*! clear all bit flags */
+ __forceinline void clearFlags() {
+ ptr &= ~(size_t)align_mask;
+ }
+
+ /*! returns the wideness */
+ __forceinline size_t getN() const { return N; }
+
+ public:
+ size_t ptr;
+ };
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_refit.cpp b/thirdparty/embree/kernels/bvh/bvh_refit.cpp
new file mode 100644
index 0000000000..bf5c8538ba
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_refit.cpp
@@ -0,0 +1,247 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_refit.h"
+#include "bvh_statistics.h"
+
+#include "../geometry/linei.h"
+#include "../geometry/triangle.h"
+#include "../geometry/trianglev.h"
+#include "../geometry/trianglei.h"
+#include "../geometry/quadv.h"
+#include "../geometry/object.h"
+#include "../geometry/instance.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ static const size_t SINGLE_THREAD_THRESHOLD = 4*1024;
+
+ template<int N>
+ __forceinline bool compare(const typename BVHN<N>::NodeRef* a, const typename BVHN<N>::NodeRef* b)
+ {
+ size_t sa = *(size_t*)&a->node()->lower_x;
+ size_t sb = *(size_t*)&b->node()->lower_x;
+ return sa < sb;
+ }
+
+ template<int N>
+ BVHNRefitter<N>::BVHNRefitter (BVH* bvh, const LeafBoundsInterface& leafBounds)
+ : bvh(bvh), leafBounds(leafBounds), numSubTrees(0)
+ {
+ }
+
+ template<int N>
+ void BVHNRefitter<N>::refit()
+ {
+ if (bvh->numPrimitives <= SINGLE_THREAD_THRESHOLD) {
+ bvh->bounds = LBBox3fa(recurse_bottom(bvh->root));
+ }
+ else
+ {
+ BBox3fa subTreeBounds[MAX_NUM_SUB_TREES];
+ numSubTrees = 0;
+ gather_subtree_refs(bvh->root,numSubTrees,0);
+ if (numSubTrees)
+ parallel_for(size_t(0), numSubTrees, size_t(1), [&](const range<size_t>& r) {
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ NodeRef& ref = subTrees[i];
+ subTreeBounds[i] = recurse_bottom(ref);
+ }
+ });
+
+ numSubTrees = 0;
+ bvh->bounds = LBBox3fa(refit_toplevel(bvh->root,numSubTrees,subTreeBounds,0));
+ }
+ }
+
+ template<int N>
+ void BVHNRefitter<N>::gather_subtree_refs(NodeRef& ref,
+ size_t &subtrees,
+ const size_t depth)
+ {
+ if (depth >= MAX_SUB_TREE_EXTRACTION_DEPTH)
+ {
+ assert(subtrees < MAX_NUM_SUB_TREES);
+ subTrees[subtrees++] = ref;
+ return;
+ }
+
+ if (ref.isAABBNode())
+ {
+ AABBNode* node = ref.getAABBNode();
+ for (size_t i=0; i<N; i++) {
+ NodeRef& child = node->child(i);
+ if (unlikely(child == BVH::emptyNode)) continue;
+ gather_subtree_refs(child,subtrees,depth+1);
+ }
+ }
+ }
+
+ template<int N>
+ BBox3fa BVHNRefitter<N>::refit_toplevel(NodeRef& ref,
+ size_t &subtrees,
+ const BBox3fa *const subTreeBounds,
+ const size_t depth)
+ {
+ if (depth >= MAX_SUB_TREE_EXTRACTION_DEPTH)
+ {
+ assert(subtrees < MAX_NUM_SUB_TREES);
+ assert(subTrees[subtrees] == ref);
+ return subTreeBounds[subtrees++];
+ }
+
+ if (ref.isAABBNode())
+ {
+ AABBNode* node = ref.getAABBNode();
+ BBox3fa bounds[N];
+
+ for (size_t i=0; i<N; i++)
+ {
+ NodeRef& child = node->child(i);
+
+ if (unlikely(child == BVH::emptyNode))
+ bounds[i] = BBox3fa(empty);
+ else
+ bounds[i] = refit_toplevel(child,subtrees,subTreeBounds,depth+1);
+ }
+
+ BBox3vf<N> boundsT = transpose<N>(bounds);
+
+ /* set new bounds */
+ node->lower_x = boundsT.lower.x;
+ node->lower_y = boundsT.lower.y;
+ node->lower_z = boundsT.lower.z;
+ node->upper_x = boundsT.upper.x;
+ node->upper_y = boundsT.upper.y;
+ node->upper_z = boundsT.upper.z;
+
+ return merge<N>(bounds);
+ }
+ else
+ return leafBounds.leafBounds(ref);
+ }
+
+ // =========================================================
+ // =========================================================
+ // =========================================================
+
+
+ template<int N>
+ BBox3fa BVHNRefitter<N>::recurse_bottom(NodeRef& ref)
+ {
+ /* this is a leaf node */
+ if (unlikely(ref.isLeaf()))
+ return leafBounds.leafBounds(ref);
+
+ /* recurse if this is an internal node */
+ AABBNode* node = ref.getAABBNode();
+
+ /* enable exclusive prefetch for >= AVX platforms */
+#if defined(__AVX__)
+ BVH::prefetchW(ref);
+#endif
+ BBox3fa bounds[N];
+
+ for (size_t i=0; i<N; i++)
+ if (unlikely(node->child(i) == BVH::emptyNode))
+ {
+ bounds[i] = BBox3fa(empty);
+ }
+ else
+ bounds[i] = recurse_bottom(node->child(i));
+
+ /* AOS to SOA transform */
+ BBox3vf<N> boundsT = transpose<N>(bounds);
+
+ /* set new bounds */
+ node->lower_x = boundsT.lower.x;
+ node->lower_y = boundsT.lower.y;
+ node->lower_z = boundsT.lower.z;
+ node->upper_x = boundsT.upper.x;
+ node->upper_y = boundsT.upper.y;
+ node->upper_z = boundsT.upper.z;
+
+ return merge<N>(bounds);
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ BVHNRefitT<N,Mesh,Primitive>::BVHNRefitT (BVH* bvh, Builder* builder, Mesh* mesh, size_t mode)
+ : bvh(bvh), builder(builder), refitter(new BVHNRefitter<N>(bvh,*(typename BVHNRefitter<N>::LeafBoundsInterface*)this)), mesh(mesh), topologyVersion(0) {}
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNRefitT<N,Mesh,Primitive>::clear()
+ {
+ if (builder)
+ builder->clear();
+ }
+
+ template<int N, typename Mesh, typename Primitive>
+ void BVHNRefitT<N,Mesh,Primitive>::build()
+ {
+ if (mesh->topologyChanged(topologyVersion)) {
+ topologyVersion = mesh->getTopologyVersion();
+ builder->build();
+ }
+ else
+ refitter->refit();
+ }
+
+ template class BVHNRefitter<4>;
+#if defined(__AVX__)
+ template class BVHNRefitter<8>;
+#endif
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ Builder* BVH4Triangle4MeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH4Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH4Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+
+ Builder* BVH4Triangle4MeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,TriangleMesh,Triangle4> ((BVH4*)accel,BVH4Triangle4MeshBuilderSAH (accel,mesh,geomID,mode),mesh,mode); }
+ Builder* BVH4Triangle4vMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,TriangleMesh,Triangle4v>((BVH4*)accel,BVH4Triangle4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+ Builder* BVH4Triangle4iMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,TriangleMesh,Triangle4i>((BVH4*)accel,BVH4Triangle4iMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+#if defined(__AVX__)
+ Builder* BVH8Triangle4MeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH8Triangle4vMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH8Triangle4iMeshBuilderSAH (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode);
+
+ Builder* BVH8Triangle4MeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,TriangleMesh,Triangle4> ((BVH8*)accel,BVH8Triangle4MeshBuilderSAH (accel,mesh,geomID,mode),mesh,mode); }
+ Builder* BVH8Triangle4vMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,TriangleMesh,Triangle4v>((BVH8*)accel,BVH8Triangle4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+ Builder* BVH8Triangle4iMeshRefitSAH (void* accel, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,TriangleMesh,Triangle4i>((BVH8*)accel,BVH8Triangle4iMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ Builder* BVH4Quad4vMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH4Quad4vMeshRefitSAH (void* accel, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,QuadMesh,Quad4v>((BVH4*)accel,BVH4Quad4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+
+#if defined(__AVX__)
+ Builder* BVH8Quad4vMeshBuilderSAH (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH8Quad4vMeshRefitSAH (void* accel, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,QuadMesh,Quad4v>((BVH8*)accel,BVH8Quad4vMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+#endif
+
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ Builder* BVH4VirtualMeshBuilderSAH (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH4VirtualMeshRefitSAH (void* accel, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,UserGeometry,Object>((BVH4*)accel,BVH4VirtualMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+
+#if defined(__AVX__)
+ Builder* BVH8VirtualMeshBuilderSAH (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode);
+ Builder* BVH8VirtualMeshRefitSAH (void* accel, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,UserGeometry,Object>((BVH8*)accel,BVH8VirtualMeshBuilderSAH(accel,mesh,geomID,mode),mesh,mode); }
+#endif
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ Builder* BVH4InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode);
+ Builder* BVH4InstanceMeshRefitSAH (void* accel, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,Instance,InstancePrimitive>((BVH4*)accel,BVH4InstanceMeshBuilderSAH(accel,mesh,gtype,geomID,mode),mesh,mode); }
+
+#if defined(__AVX__)
+ Builder* BVH8InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode);
+ Builder* BVH8InstanceMeshRefitSAH (void* accel, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,Instance,InstancePrimitive>((BVH8*)accel,BVH8InstanceMeshBuilderSAH(accel,mesh,gtype,geomID,mode),mesh,mode); }
+#endif
+#endif
+
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_refit.h b/thirdparty/embree/kernels/bvh/bvh_refit.h
new file mode 100644
index 0000000000..09bb3d8da5
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_refit.h
@@ -0,0 +1,95 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../bvh/bvh.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N>
+ class BVHNRefitter
+ {
+ public:
+
+ /*! Type shortcuts */
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::NodeRef NodeRef;
+
+ struct LeafBoundsInterface {
+ virtual const BBox3fa leafBounds(NodeRef& ref) const = 0;
+ };
+
+ public:
+
+ /*! Constructor. */
+ BVHNRefitter (BVH* bvh, const LeafBoundsInterface& leafBounds);
+
+ /*! refits the BVH */
+ void refit();
+
+ private:
+ /* single-threaded subtree extraction based on BVH depth */
+ void gather_subtree_refs(NodeRef& ref,
+ size_t &subtrees,
+ const size_t depth = 0);
+
+ /* single-threaded top-level refit */
+ BBox3fa refit_toplevel(NodeRef& ref,
+ size_t &subtrees,
+ const BBox3fa *const subTreeBounds,
+ const size_t depth = 0);
+
+ /* single-threaded subtree refit */
+ BBox3fa recurse_bottom(NodeRef& ref);
+
+ public:
+ BVH* bvh; //!< BVH to refit
+ const LeafBoundsInterface& leafBounds; //!< calculates bounds of leaves
+
+ static const size_t MAX_SUB_TREE_EXTRACTION_DEPTH = (N==4) ? 4 : (N==8) ? 3 : 3;
+ static const size_t MAX_NUM_SUB_TREES = (N==4) ? 256 : (N==8) ? 512 : N*N*N; // N ^ MAX_SUB_TREE_EXTRACTION_DEPTH
+ size_t numSubTrees;
+ NodeRef subTrees[MAX_NUM_SUB_TREES];
+ };
+
+ template<int N, typename Mesh, typename Primitive>
+ class BVHNRefitT : public Builder, public BVHNRefitter<N>::LeafBoundsInterface
+ {
+ public:
+
+ /*! Type shortcuts */
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::NodeRef NodeRef;
+
+ public:
+ BVHNRefitT (BVH* bvh, Builder* builder, Mesh* mesh, size_t mode);
+
+ virtual void build();
+
+ virtual void clear();
+
+ virtual const BBox3fa leafBounds (NodeRef& ref) const
+ {
+ size_t num; char* prim = ref.leaf(num);
+ if (unlikely(ref == BVH::emptyNode)) return empty;
+
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<num; i++)
+ bounds.extend(((Primitive*)prim)[i].update(mesh));
+ return bounds;
+ }
+
+ private:
+ BVH* bvh;
+ std::unique_ptr<Builder> builder;
+ std::unique_ptr<BVHNRefitter<N>> refitter;
+ Mesh* mesh;
+ unsigned int topologyVersion;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_rotate.cpp b/thirdparty/embree/kernels/bvh/bvh_rotate.cpp
new file mode 100644
index 0000000000..460bd60c62
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_rotate.cpp
@@ -0,0 +1,127 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_rotate.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Computes half surface area of box. */
+ __forceinline float halfArea3f(const BBox<vfloat4>& box) {
+ const vfloat4 d = box.size();
+ const vfloat4 a = d*shuffle<1,2,0,3>(d);
+ return a[0]+a[1]+a[2];
+ }
+
+ size_t BVHNRotate<4>::rotate(NodeRef parentRef, size_t depth)
+ {
+ /*! nothing to rotate if we reached a leaf node. */
+ if (parentRef.isBarrier()) return 0;
+ if (parentRef.isLeaf()) return 0;
+ AABBNode* parent = parentRef.getAABBNode();
+
+ /*! rotate all children first */
+ vint4 cdepth;
+ for (size_t c=0; c<4; c++)
+ cdepth[c] = (int)rotate(parent->child(c),depth+1);
+
+ /* compute current areas of all children */
+ vfloat4 sizeX = parent->upper_x-parent->lower_x;
+ vfloat4 sizeY = parent->upper_y-parent->lower_y;
+ vfloat4 sizeZ = parent->upper_z-parent->lower_z;
+ vfloat4 childArea = madd(sizeX,(sizeY + sizeZ),sizeY*sizeZ);
+
+ /*! get node bounds */
+ BBox<vfloat4> child1_0,child1_1,child1_2,child1_3;
+ parent->bounds(child1_0,child1_1,child1_2,child1_3);
+
+ /*! Find best rotation. We pick a first child (child1) and a sub-child
+ (child2child) of a different second child (child2), and swap child1
+ and child2child. We perform the best such swap. */
+ float bestArea = 0;
+ size_t bestChild1 = -1, bestChild2 = -1, bestChild2Child = -1;
+ for (size_t c2=0; c2<4; c2++)
+ {
+ /*! ignore leaf nodes as we cannot descent into them */
+ if (parent->child(c2).isBarrier()) continue;
+ if (parent->child(c2).isLeaf()) continue;
+ AABBNode* child2 = parent->child(c2).getAABBNode();
+
+ /*! transpose child bounds */
+ BBox<vfloat4> child2c0,child2c1,child2c2,child2c3;
+ child2->bounds(child2c0,child2c1,child2c2,child2c3);
+
+ /*! put child1_0 at each child2 position */
+ float cost00 = halfArea3f(merge(child1_0,child2c1,child2c2,child2c3));
+ float cost01 = halfArea3f(merge(child2c0,child1_0,child2c2,child2c3));
+ float cost02 = halfArea3f(merge(child2c0,child2c1,child1_0,child2c3));
+ float cost03 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_0));
+ vfloat4 cost0 = vfloat4(cost00,cost01,cost02,cost03);
+ vfloat4 min0 = vreduce_min(cost0);
+ int pos0 = (int)bsf(movemask(min0 == cost0));
+
+ /*! put child1_1 at each child2 position */
+ float cost10 = halfArea3f(merge(child1_1,child2c1,child2c2,child2c3));
+ float cost11 = halfArea3f(merge(child2c0,child1_1,child2c2,child2c3));
+ float cost12 = halfArea3f(merge(child2c0,child2c1,child1_1,child2c3));
+ float cost13 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_1));
+ vfloat4 cost1 = vfloat4(cost10,cost11,cost12,cost13);
+ vfloat4 min1 = vreduce_min(cost1);
+ int pos1 = (int)bsf(movemask(min1 == cost1));
+
+ /*! put child1_2 at each child2 position */
+ float cost20 = halfArea3f(merge(child1_2,child2c1,child2c2,child2c3));
+ float cost21 = halfArea3f(merge(child2c0,child1_2,child2c2,child2c3));
+ float cost22 = halfArea3f(merge(child2c0,child2c1,child1_2,child2c3));
+ float cost23 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_2));
+ vfloat4 cost2 = vfloat4(cost20,cost21,cost22,cost23);
+ vfloat4 min2 = vreduce_min(cost2);
+ int pos2 = (int)bsf(movemask(min2 == cost2));
+
+ /*! put child1_3 at each child2 position */
+ float cost30 = halfArea3f(merge(child1_3,child2c1,child2c2,child2c3));
+ float cost31 = halfArea3f(merge(child2c0,child1_3,child2c2,child2c3));
+ float cost32 = halfArea3f(merge(child2c0,child2c1,child1_3,child2c3));
+ float cost33 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_3));
+ vfloat4 cost3 = vfloat4(cost30,cost31,cost32,cost33);
+ vfloat4 min3 = vreduce_min(cost3);
+ int pos3 = (int)bsf(movemask(min3 == cost3));
+
+ /*! find best other child */
+ vfloat4 area0123 = vfloat4(extract<0>(min0),extract<0>(min1),extract<0>(min2),extract<0>(min3)) - vfloat4(childArea[c2]);
+ int pos[4] = { pos0,pos1,pos2,pos3 };
+ const size_t mbd = BVH4::maxBuildDepth;
+ vbool4 valid = vint4(int(depth+1))+cdepth <= vint4(mbd); // only select swaps that fulfill depth constraints
+ valid &= vint4(int(c2)) != vint4(step);
+ if (none(valid)) continue;
+ size_t c1 = select_min(valid,area0123);
+ float area = area0123[c1];
+ if (c1 == c2) continue; // can happen if bounds are NANs
+
+ /*! accept a swap when it reduces cost and is not swapping a node with itself */
+ if (area < bestArea) {
+ bestArea = area;
+ bestChild1 = c1;
+ bestChild2 = c2;
+ bestChild2Child = pos[c1];
+ }
+ }
+
+ /*! if we did not find a swap that improves the SAH then do nothing */
+ if (bestChild1 == size_t(-1)) return 1+reduce_max(cdepth);
+
+ /*! perform the best found tree rotation */
+ AABBNode* child2 = parent->child(bestChild2).getAABBNode();
+ AABBNode::swap(parent,bestChild1,child2,bestChild2Child);
+ parent->setBounds(bestChild2,child2->bounds());
+ AABBNode::compact(parent);
+ AABBNode::compact(child2);
+
+ /*! This returned depth is conservative as the child that was
+ * pulled up in the tree could have been on the critical path. */
+ cdepth[bestChild1]++; // bestChild1 was pushed down one level
+ return 1+reduce_max(cdepth);
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_rotate.h b/thirdparty/embree/kernels/bvh/bvh_rotate.h
new file mode 100644
index 0000000000..61ef64a679
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_rotate.h
@@ -0,0 +1,37 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N>
+ class BVHNRotate
+ {
+ typedef typename BVHN<N>::NodeRef NodeRef;
+
+ public:
+ static const bool enabled = false;
+
+ static __forceinline size_t rotate(NodeRef parentRef, size_t depth = 1) { return 0; }
+ static __forceinline void restructure(NodeRef ref, size_t depth = 1) {}
+ };
+
+ /* BVH4 tree rotations */
+ template<>
+ class BVHNRotate<4>
+ {
+ typedef BVH4::AABBNode AABBNode;
+ typedef BVH4::NodeRef NodeRef;
+
+ public:
+ static const bool enabled = true;
+
+ static size_t rotate(NodeRef parentRef, size_t depth = 1);
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_statistics.cpp b/thirdparty/embree/kernels/bvh/bvh_statistics.cpp
new file mode 100644
index 0000000000..d857ff7d95
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_statistics.cpp
@@ -0,0 +1,168 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bvh_statistics.h"
+#include "../../common/algorithms/parallel_reduce.h"
+
+namespace embree
+{
+ template<int N>
+ BVHNStatistics<N>::BVHNStatistics (BVH* bvh) : bvh(bvh)
+ {
+ double A = max(0.0f,bvh->getLinearBounds().expectedHalfArea());
+ stat = statistics(bvh->root,A,BBox1f(0.0f,1.0f));
+ }
+
+ template<int N>
+ std::string BVHNStatistics<N>::str()
+ {
+ std::ostringstream stream;
+ stream.setf(std::ios::fixed, std::ios::floatfield);
+ stream << " primitives = " << bvh->numPrimitives << ", vertices = " << bvh->numVertices << ", depth = " << stat.depth << std::endl;
+ size_t totalBytes = stat.bytes(bvh);
+ double totalSAH = stat.sah(bvh);
+ stream << " total : sah = " << std::setw(7) << std::setprecision(3) << totalSAH << " (100.00%), ";
+ stream << "#bytes = " << std::setw(7) << std::setprecision(2) << totalBytes/1E6 << " MB (100.00%), ";
+ stream << "#nodes = " << std::setw(7) << stat.size() << " (" << std::setw(6) << std::setprecision(2) << 100.0*stat.fillRate(bvh) << "% filled), ";
+ stream << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(totalBytes)/double(bvh->numPrimitives) << std::endl;
+ if (stat.statAABBNodes.numNodes ) stream << " getAABBNodes : " << stat.statAABBNodes.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (stat.statOBBNodes.numNodes ) stream << " ungetAABBNodes : " << stat.statOBBNodes.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (stat.statAABBNodesMB.numNodes ) stream << " getAABBNodesMB : " << stat.statAABBNodesMB.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (stat.statAABBNodesMB4D.numNodes) stream << " getAABBNodesMB4D : " << stat.statAABBNodesMB4D.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (stat.statOBBNodesMB.numNodes) stream << " ungetAABBNodesMB : " << stat.statOBBNodesMB.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (stat.statQuantizedNodes.numNodes ) stream << " quantizedNodes : " << stat.statQuantizedNodes.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (true) stream << " leaves : " << stat.statLeaf.toString(bvh,totalSAH,totalBytes) << std::endl;
+ if (true) stream << " histogram : " << stat.statLeaf.histToString() << std::endl;
+ return stream.str();
+ }
+
+ template<int N>
+ typename BVHNStatistics<N>::Statistics BVHNStatistics<N>::statistics(NodeRef node, const double A, const BBox1f t0t1)
+ {
+ Statistics s;
+ assert(t0t1.size() > 0.0f);
+ double dt = max(0.0f,t0t1.size());
+ if (node.isAABBNode())
+ {
+ AABBNode* n = node.getAABBNode();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const double Ai = max(0.0f,halfArea(n->extend(i)));
+ Statistics s = statistics(n->child(i),Ai,t0t1);
+ s.statAABBNodes.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statAABBNodes.numNodes++;
+ s.statAABBNodes.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isOBBNode())
+ {
+ OBBNode* n = node.ungetAABBNode();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const double Ai = max(0.0f,halfArea(n->extent(i)));
+ Statistics s = statistics(n->child(i),Ai,t0t1);
+ s.statOBBNodes.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statOBBNodes.numNodes++;
+ s.statOBBNodes.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isAABBNodeMB())
+ {
+ AABBNodeMB* n = node.getAABBNodeMB();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const double Ai = max(0.0f,n->expectedHalfArea(i,t0t1));
+ Statistics s = statistics(n->child(i),Ai,t0t1);
+ s.statAABBNodesMB.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statAABBNodesMB.numNodes++;
+ s.statAABBNodesMB.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isAABBNodeMB4D())
+ {
+ AABBNodeMB4D* n = node.getAABBNodeMB4D();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const BBox1f t0t1i = intersect(t0t1,n->timeRange(i));
+ assert(!t0t1i.empty());
+ const double Ai = n->AABBNodeMB::expectedHalfArea(i,t0t1i);
+ Statistics s = statistics(n->child(i),Ai,t0t1i);
+ s.statAABBNodesMB4D.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statAABBNodesMB4D.numNodes++;
+ s.statAABBNodesMB4D.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isOBBNodeMB())
+ {
+ OBBNodeMB* n = node.ungetAABBNodeMB();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const double Ai = max(0.0f,halfArea(n->extent0(i)));
+ Statistics s = statistics(n->child(i),Ai,t0t1);
+ s.statOBBNodesMB.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statOBBNodesMB.numNodes++;
+ s.statOBBNodesMB.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isQuantizedNode())
+ {
+ QuantizedNode* n = node.quantizedNode();
+ s = s + parallel_reduce(0,N,Statistics(),[&] ( const int i ) {
+ if (n->child(i) == BVH::emptyNode) return Statistics();
+ const double Ai = max(0.0f,halfArea(n->extent(i)));
+ Statistics s = statistics(n->child(i),Ai,t0t1);
+ s.statQuantizedNodes.numChildren++;
+ return s;
+ }, Statistics::add);
+ s.statQuantizedNodes.numNodes++;
+ s.statQuantizedNodes.nodeSAH += dt*A;
+ s.depth++;
+ }
+ else if (node.isLeaf())
+ {
+ size_t num; const char* tri = node.leaf(num);
+ if (num)
+ {
+ for (size_t i=0; i<num; i++)
+ {
+ const size_t bytes = bvh->primTy->getBytes(tri);
+ s.statLeaf.numPrimsActive += bvh->primTy->sizeActive(tri);
+ s.statLeaf.numPrimsTotal += bvh->primTy->sizeTotal(tri);
+ s.statLeaf.numBytes += bytes;
+ tri+=bytes;
+ }
+ s.statLeaf.numLeaves++;
+ s.statLeaf.numPrimBlocks += num;
+ s.statLeaf.leafSAH += dt*A*num;
+ if (num-1 < Statistics::LeafStat::NHIST) {
+ s.statLeaf.numPrimBlocksHistogram[num-1]++;
+ }
+ }
+ }
+ else {
+ // -- GODOT start --
+ // throw std::runtime_error("not supported node type in bvh_statistics");
+ abort();
+ // -- GODOT end --
+ }
+ return s;
+ }
+
+#if defined(__AVX__)
+ template class BVHNStatistics<8>;
+#endif
+
+#if !defined(__AVX__) || !defined(EMBREE_TARGET_SSE2) && !defined(EMBREE_TARGET_SSE42)
+ template class BVHNStatistics<4>;
+#endif
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_statistics.h b/thirdparty/embree/kernels/bvh/bvh_statistics.h
new file mode 100644
index 0000000000..a28e115f1c
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_statistics.h
@@ -0,0 +1,285 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include <sstream>
+
+namespace embree
+{
+ template<int N>
+ class BVHNStatistics
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::AABBNode AABBNode;
+ typedef typename BVH::OBBNode OBBNode;
+ typedef typename BVH::AABBNodeMB AABBNodeMB;
+ typedef typename BVH::AABBNodeMB4D AABBNodeMB4D;
+ typedef typename BVH::OBBNodeMB OBBNodeMB;
+ typedef typename BVH::QuantizedNode QuantizedNode;
+
+ typedef typename BVH::NodeRef NodeRef;
+
+ struct Statistics
+ {
+ template<typename Node>
+ struct NodeStat
+ {
+ NodeStat ( double nodeSAH = 0,
+ size_t numNodes = 0,
+ size_t numChildren = 0)
+ : nodeSAH(nodeSAH),
+ numNodes(numNodes),
+ numChildren(numChildren) {}
+
+ double sah(BVH* bvh) const {
+ return nodeSAH/bvh->getLinearBounds().expectedHalfArea();
+ }
+
+ size_t bytes() const {
+ return numNodes*sizeof(Node);
+ }
+
+ size_t size() const {
+ return numNodes;
+ }
+
+ double fillRateNom () const { return double(numChildren); }
+ double fillRateDen () const { return double(numNodes*N); }
+ double fillRate () const { return fillRateNom()/fillRateDen(); }
+
+ __forceinline friend NodeStat operator+ ( const NodeStat& a, const NodeStat& b)
+ {
+ return NodeStat(a.nodeSAH + b.nodeSAH,
+ a.numNodes+b.numNodes,
+ a.numChildren+b.numChildren);
+ }
+
+ std::string toString(BVH* bvh, double sahTotal, size_t bytesTotal) const
+ {
+ std::ostringstream stream;
+ stream.setf(std::ios::fixed, std::ios::floatfield);
+ stream << "sah = " << std::setw(7) << std::setprecision(3) << sah(bvh);
+ stream << " (" << std::setw(6) << std::setprecision(2) << 100.0*sah(bvh)/sahTotal << "%), ";
+ stream << "#bytes = " << std::setw(7) << std::setprecision(2) << bytes()/1E6 << " MB ";
+ stream << "(" << std::setw(6) << std::setprecision(2) << 100.0*double(bytes())/double(bytesTotal) << "%), ";
+ stream << "#nodes = " << std::setw(7) << numNodes << " (" << std::setw(6) << std::setprecision(2) << 100.0*fillRate() << "% filled), ";
+ stream << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytes())/double(bvh->numPrimitives);
+ return stream.str();
+ }
+
+ public:
+ double nodeSAH;
+ size_t numNodes;
+ size_t numChildren;
+ };
+
+ struct LeafStat
+ {
+ static const int NHIST = 8;
+
+ LeafStat ( double leafSAH = 0.0f,
+ size_t numLeaves = 0,
+ size_t numPrimsActive = 0,
+ size_t numPrimsTotal = 0,
+ size_t numPrimBlocks = 0,
+ size_t numBytes = 0)
+ : leafSAH(leafSAH),
+ numLeaves(numLeaves),
+ numPrimsActive(numPrimsActive),
+ numPrimsTotal(numPrimsTotal),
+ numPrimBlocks(numPrimBlocks),
+ numBytes(numBytes)
+ {
+ for (size_t i=0; i<NHIST; i++)
+ numPrimBlocksHistogram[i] = 0;
+ }
+
+ double sah(BVH* bvh) const {
+ return leafSAH/bvh->getLinearBounds().expectedHalfArea();
+ }
+
+ size_t bytes(BVH* bvh) const {
+ return numBytes;
+ }
+
+ size_t size() const {
+ return numLeaves;
+ }
+
+ double fillRateNom (BVH* bvh) const { return double(numPrimsActive); }
+ double fillRateDen (BVH* bvh) const { return double(numPrimsTotal); }
+ double fillRate (BVH* bvh) const { return fillRateNom(bvh)/fillRateDen(bvh); }
+
+ __forceinline friend LeafStat operator+ ( const LeafStat& a, const LeafStat& b)
+ {
+ LeafStat stat(a.leafSAH + b.leafSAH,
+ a.numLeaves+b.numLeaves,
+ a.numPrimsActive+b.numPrimsActive,
+ a.numPrimsTotal+b.numPrimsTotal,
+ a.numPrimBlocks+b.numPrimBlocks,
+ a.numBytes+b.numBytes);
+ for (size_t i=0; i<NHIST; i++) {
+ stat.numPrimBlocksHistogram[i] += a.numPrimBlocksHistogram[i];
+ stat.numPrimBlocksHistogram[i] += b.numPrimBlocksHistogram[i];
+ }
+ return stat;
+ }
+
+ std::string toString(BVH* bvh, double sahTotal, size_t bytesTotal) const
+ {
+ std::ostringstream stream;
+ stream.setf(std::ios::fixed, std::ios::floatfield);
+ stream << "sah = " << std::setw(7) << std::setprecision(3) << sah(bvh);
+ stream << " (" << std::setw(6) << std::setprecision(2) << 100.0*sah(bvh)/sahTotal << "%), ";
+ stream << "#bytes = " << std::setw(7) << std::setprecision(2) << double(bytes(bvh))/1E6 << " MB ";
+ stream << "(" << std::setw(6) << std::setprecision(2) << 100.0*double(bytes(bvh))/double(bytesTotal) << "%), ";
+ stream << "#nodes = " << std::setw(7) << numLeaves << " (" << std::setw(6) << std::setprecision(2) << 100.0*fillRate(bvh) << "% filled), ";
+ stream << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytes(bvh))/double(bvh->numPrimitives);
+ return stream.str();
+ }
+
+ std::string histToString() const
+ {
+ std::ostringstream stream;
+ stream.setf(std::ios::fixed, std::ios::floatfield);
+ for (size_t i=0; i<NHIST; i++)
+ stream << std::setw(6) << std::setprecision(2) << 100.0f*float(numPrimBlocksHistogram[i])/float(numLeaves) << "% ";
+ return stream.str();
+ }
+
+ public:
+ double leafSAH; //!< SAH of the leaves only
+ size_t numLeaves; //!< Number of leaf nodes.
+ size_t numPrimsActive; //!< Number of active primitives (
+ size_t numPrimsTotal; //!< Number of active and inactive primitives
+ size_t numPrimBlocks; //!< Number of primitive blocks.
+ size_t numBytes; //!< Number of bytes of leaves.
+ size_t numPrimBlocksHistogram[8];
+ };
+
+ public:
+ Statistics (size_t depth = 0,
+ LeafStat statLeaf = LeafStat(),
+ NodeStat<AABBNode> statAABBNodes = NodeStat<AABBNode>(),
+ NodeStat<OBBNode> statOBBNodes = NodeStat<OBBNode>(),
+ NodeStat<AABBNodeMB> statAABBNodesMB = NodeStat<AABBNodeMB>(),
+ NodeStat<AABBNodeMB4D> statAABBNodesMB4D = NodeStat<AABBNodeMB4D>(),
+ NodeStat<OBBNodeMB> statOBBNodesMB = NodeStat<OBBNodeMB>(),
+ NodeStat<QuantizedNode> statQuantizedNodes = NodeStat<QuantizedNode>())
+
+ : depth(depth),
+ statLeaf(statLeaf),
+ statAABBNodes(statAABBNodes),
+ statOBBNodes(statOBBNodes),
+ statAABBNodesMB(statAABBNodesMB),
+ statAABBNodesMB4D(statAABBNodesMB4D),
+ statOBBNodesMB(statOBBNodesMB),
+ statQuantizedNodes(statQuantizedNodes) {}
+
+ double sah(BVH* bvh) const
+ {
+ return statLeaf.sah(bvh) +
+ statAABBNodes.sah(bvh) +
+ statOBBNodes.sah(bvh) +
+ statAABBNodesMB.sah(bvh) +
+ statAABBNodesMB4D.sah(bvh) +
+ statOBBNodesMB.sah(bvh) +
+ statQuantizedNodes.sah(bvh);
+ }
+
+ size_t bytes(BVH* bvh) const {
+ return statLeaf.bytes(bvh) +
+ statAABBNodes.bytes() +
+ statOBBNodes.bytes() +
+ statAABBNodesMB.bytes() +
+ statAABBNodesMB4D.bytes() +
+ statOBBNodesMB.bytes() +
+ statQuantizedNodes.bytes();
+ }
+
+ size_t size() const
+ {
+ return statLeaf.size() +
+ statAABBNodes.size() +
+ statOBBNodes.size() +
+ statAABBNodesMB.size() +
+ statAABBNodesMB4D.size() +
+ statOBBNodesMB.size() +
+ statQuantizedNodes.size();
+ }
+
+ double fillRate (BVH* bvh) const
+ {
+ double nom = statLeaf.fillRateNom(bvh) +
+ statAABBNodes.fillRateNom() +
+ statOBBNodes.fillRateNom() +
+ statAABBNodesMB.fillRateNom() +
+ statAABBNodesMB4D.fillRateNom() +
+ statOBBNodesMB.fillRateNom() +
+ statQuantizedNodes.fillRateNom();
+ double den = statLeaf.fillRateDen(bvh) +
+ statAABBNodes.fillRateDen() +
+ statOBBNodes.fillRateDen() +
+ statAABBNodesMB.fillRateDen() +
+ statAABBNodesMB4D.fillRateDen() +
+ statOBBNodesMB.fillRateDen() +
+ statQuantizedNodes.fillRateDen();
+ return nom/den;
+ }
+
+ friend Statistics operator+ ( const Statistics& a, const Statistics& b )
+ {
+ return Statistics(max(a.depth,b.depth),
+ a.statLeaf + b.statLeaf,
+ a.statAABBNodes + b.statAABBNodes,
+ a.statOBBNodes + b.statOBBNodes,
+ a.statAABBNodesMB + b.statAABBNodesMB,
+ a.statAABBNodesMB4D + b.statAABBNodesMB4D,
+ a.statOBBNodesMB + b.statOBBNodesMB,
+ a.statQuantizedNodes + b.statQuantizedNodes);
+ }
+
+ static Statistics add ( const Statistics& a, const Statistics& b ) {
+ return a+b;
+ }
+
+ public:
+ size_t depth;
+ LeafStat statLeaf;
+ NodeStat<AABBNode> statAABBNodes;
+ NodeStat<OBBNode> statOBBNodes;
+ NodeStat<AABBNodeMB> statAABBNodesMB;
+ NodeStat<AABBNodeMB4D> statAABBNodesMB4D;
+ NodeStat<OBBNodeMB> statOBBNodesMB;
+ NodeStat<QuantizedNode> statQuantizedNodes;
+ };
+
+ public:
+
+ /* Constructor gathers statistics. */
+ BVHNStatistics (BVH* bvh);
+
+ /*! Convert statistics into a string */
+ std::string str();
+
+ double sah() const {
+ return stat.sah(bvh);
+ }
+
+ size_t bytesUsed() const {
+ return stat.bytes(bvh);
+ }
+
+ private:
+ Statistics statistics(NodeRef node, const double A, const BBox1f dt);
+
+ private:
+ BVH* bvh;
+ Statistics stat;
+ };
+
+ typedef BVHNStatistics<4> BVH4Statistics;
+ typedef BVHNStatistics<8> BVH8Statistics;
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_traverser1.h b/thirdparty/embree/kernels/bvh/bvh_traverser1.h
new file mode 100644
index 0000000000..8ce01b57f5
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_traverser1.h
@@ -0,0 +1,466 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "node_intersector1.h"
+#include "../common/stack_item.h"
+
+#define NEW_SORTING_CODE 1
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! BVH regular node traversal for single rays. */
+ template<int N, int types>
+ class BVHNNodeTraverser1Hit;
+
+#if defined(__AVX512VL__) // SKX
+
+ template<int N>
+ __forceinline void isort_update(vint<N> &dist, const vint<N> &d)
+ {
+ const vint<N> dist_shift = align_shift_right<N-1>(dist,dist);
+ const vboolf<N> m_geq = d >= dist;
+ const vboolf<N> m_geq_shift = m_geq << 1;
+ dist = select(m_geq,d,dist);
+ dist = select(m_geq_shift,dist_shift,dist);
+ }
+
+ template<int N>
+ __forceinline void isort_quick_update(vint<N> &dist, const vint<N> &d) {
+ dist = align_shift_right<N-1>(dist,permute(d,vint<N>(zero)));
+ }
+
+ __forceinline size_t permuteExtract(const vint8& index, const vllong4& n0, const vllong4& n1) {
+ return toScalar(permutex2var((__m256i)index,n0,n1));
+ }
+
+ __forceinline float permuteExtract(const vint8& index, const vfloat8& n) {
+ return toScalar(permute(n,index));
+ }
+
+#endif
+
+ /* Specialization for BVH4. */
+ template<int types>
+ class BVHNNodeTraverser1Hit<4, types>
+ {
+ typedef BVH4 BVH;
+ typedef BVH4::NodeRef NodeRef;
+ typedef BVH4::BaseNode BaseNode;
+
+
+ public:
+ /* Traverses a node with at least one hit child. Optimized for finding the closest hit (intersection). */
+ static __forceinline void traverseClosestHit(NodeRef& cur,
+ size_t mask,
+ const vfloat4& tNear,
+ StackItemT<NodeRef>*& stackPtr,
+ StackItemT<NodeRef>* stackEnd)
+ {
+ assert(mask != 0);
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ size_t r = bscf(mask);
+ cur = node->child(r);
+ BVH::prefetch(cur,types);
+ if (likely(mask == 0)) {
+ assert(cur != BVH::emptyNode);
+ return;
+ }
+
+ /*! two children are hit, push far child, and continue with closer child */
+ NodeRef c0 = cur;
+ const unsigned int d0 = ((unsigned int*)&tNear)[r];
+ r = bscf(mask);
+ NodeRef c1 = node->child(r);
+ BVH::prefetch(c1,types);
+ const unsigned int d1 = ((unsigned int*)&tNear)[r];
+ assert(c0 != BVH::emptyNode);
+ assert(c1 != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ assert(stackPtr < stackEnd);
+ if (d0 < d1) { stackPtr->ptr = c1; stackPtr->dist = d1; stackPtr++; cur = c0; return; }
+ else { stackPtr->ptr = c0; stackPtr->dist = d0; stackPtr++; cur = c1; return; }
+ }
+
+#if NEW_SORTING_CODE == 1
+ vint4 s0((size_t)c0,(size_t)d0);
+ vint4 s1((size_t)c1,(size_t)d1);
+ r = bscf(mask);
+ NodeRef c2 = node->child(r); BVH::prefetch(c2,types); unsigned int d2 = ((unsigned int*)&tNear)[r];
+ vint4 s2((size_t)c2,(size_t)d2);
+ /* 3 hits */
+ if (likely(mask == 0)) {
+ StackItemT<NodeRef>::sort3(s0,s1,s2);
+ *(vint4*)&stackPtr[0] = s0; *(vint4*)&stackPtr[1] = s1;
+ cur = toSizeT(s2);
+ stackPtr+=2;
+ return;
+ }
+ r = bscf(mask);
+ NodeRef c3 = node->child(r); BVH::prefetch(c3,types); unsigned int d3 = ((unsigned int*)&tNear)[r];
+ vint4 s3((size_t)c3,(size_t)d3);
+ /* 4 hits */
+ StackItemT<NodeRef>::sort4(s0,s1,s2,s3);
+ *(vint4*)&stackPtr[0] = s0; *(vint4*)&stackPtr[1] = s1; *(vint4*)&stackPtr[2] = s2;
+ cur = toSizeT(s3);
+ stackPtr+=3;
+#else
+ /*! Here starts the slow path for 3 or 4 hit children. We push
+ * all nodes onto the stack to sort them there. */
+ assert(stackPtr < stackEnd);
+ stackPtr->ptr = c0; stackPtr->dist = d0; stackPtr++;
+ assert(stackPtr < stackEnd);
+ stackPtr->ptr = c1; stackPtr->dist = d1; stackPtr++;
+
+ /*! three children are hit, push all onto stack and sort 3 stack items, continue with closest child */
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ NodeRef c = node->child(r); BVH::prefetch(c,types); unsigned int d = ((unsigned int*)&tNear)[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++;
+ assert(c != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ sort(stackPtr[-1],stackPtr[-2],stackPtr[-3]);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+ return;
+ }
+
+ /*! four children are hit, push all onto stack and sort 4 stack items, continue with closest child */
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ c = node->child(r); BVH::prefetch(c,types); d = *(unsigned int*)&tNear[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++;
+ assert(c != BVH::emptyNode);
+ sort(stackPtr[-1],stackPtr[-2],stackPtr[-3],stackPtr[-4]);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+#endif
+ }
+
+ /* Traverses a node with at least one hit child. Optimized for finding any hit (occlusion). */
+ static __forceinline void traverseAnyHit(NodeRef& cur,
+ size_t mask,
+ const vfloat4& tNear,
+ NodeRef*& stackPtr,
+ NodeRef* stackEnd)
+ {
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ size_t r = bscf(mask);
+ cur = node->child(r);
+ BVH::prefetch(cur,types);
+
+ /* simpler in sequence traversal order */
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ assert(stackPtr < stackEnd);
+ *stackPtr = cur; stackPtr++;
+
+ for (; ;)
+ {
+ r = bscf(mask);
+ cur = node->child(r); BVH::prefetch(cur,types);
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ assert(stackPtr < stackEnd);
+ *stackPtr = cur; stackPtr++;
+ }
+ }
+ };
+
+ /* Specialization for BVH8. */
+ template<int types>
+ class BVHNNodeTraverser1Hit<8, types>
+ {
+ typedef BVH8 BVH;
+ typedef BVH8::NodeRef NodeRef;
+ typedef BVH8::BaseNode BaseNode;
+
+#if defined(__AVX512VL__)
+ template<class NodeRef, class BaseNode>
+ static __forceinline void traverseClosestHitAVX512VL8(NodeRef& cur,
+ size_t mask,
+ const vfloat8& tNear,
+ StackItemT<NodeRef>*& stackPtr,
+ StackItemT<NodeRef>* stackEnd)
+ {
+ assert(mask != 0);
+ const BaseNode* node = cur.baseNode();
+ const vllong4 n0 = vllong4::loadu((vllong4*)&node->children[0]);
+ const vllong4 n1 = vllong4::loadu((vllong4*)&node->children[4]);
+ vint8 distance_i = (asInt(tNear) & 0xfffffff8) | vint8(step);
+ distance_i = vint8::compact((int)mask,distance_i,distance_i);
+ cur = permuteExtract(distance_i,n0,n1);
+ BVH::prefetch(cur,types);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) return;
+
+ /* 2 hits: order A0 B0 */
+ const vint8 d0(distance_i);
+ const vint8 d1(shuffle<1>(distance_i));
+ cur = permuteExtract(d1,n0,n1);
+ BVH::prefetch(cur,types);
+
+ const vint8 dist_A0 = min(d0, d1);
+ const vint8 dist_B0 = max(d0, d1);
+ assert(dist_A0[0] < dist_B0[0]);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) {
+ cur = permuteExtract(dist_A0,n0,n1);
+ stackPtr[0].ptr = permuteExtract(dist_B0,n0,n1);
+ *(float*)&stackPtr[0].dist = permuteExtract(dist_B0,tNear);
+ stackPtr++;
+ return;
+ }
+
+ /* 3 hits: order A1 B1 C1 */
+
+ const vint8 d2(shuffle<2>(distance_i));
+ cur = permuteExtract(d2,n0,n1);
+ BVH::prefetch(cur,types);
+
+ const vint8 dist_A1 = min(dist_A0,d2);
+ const vint8 dist_tmp_B1 = max(dist_A0,d2);
+ const vint8 dist_B1 = min(dist_B0,dist_tmp_B1);
+ const vint8 dist_C1 = max(dist_B0,dist_tmp_B1);
+ assert(dist_A1[0] < dist_B1[0]);
+ assert(dist_B1[0] < dist_C1[0]);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) {
+ cur = permuteExtract(dist_A1,n0,n1);
+ stackPtr[0].ptr = permuteExtract(dist_C1,n0,n1);
+ *(float*)&stackPtr[0].dist = permuteExtract(dist_C1,tNear);
+ stackPtr[1].ptr = permuteExtract(dist_B1,n0,n1);
+ *(float*)&stackPtr[1].dist = permuteExtract(dist_B1,tNear);
+ stackPtr+=2;
+ return;
+ }
+
+ /* 4 hits: order A2 B2 C2 D2 */
+
+ const vint8 d3(shuffle<3>(distance_i));
+ cur = permuteExtract(d3,n0,n1);
+ BVH::prefetch(cur,types);
+
+ const vint8 dist_A2 = min(dist_A1,d3);
+ const vint8 dist_tmp_B2 = max(dist_A1,d3);
+ const vint8 dist_B2 = min(dist_B1,dist_tmp_B2);
+ const vint8 dist_tmp_C2 = max(dist_B1,dist_tmp_B2);
+ const vint8 dist_C2 = min(dist_C1,dist_tmp_C2);
+ const vint8 dist_D2 = max(dist_C1,dist_tmp_C2);
+ assert(dist_A2[0] < dist_B2[0]);
+ assert(dist_B2[0] < dist_C2[0]);
+ assert(dist_C2[0] < dist_D2[0]);
+
+ mask &= mask-1;
+ if (likely(mask == 0)) {
+ cur = permuteExtract(dist_A2,n0,n1);
+ stackPtr[0].ptr = permuteExtract(dist_D2,n0,n1);
+ *(float*)&stackPtr[0].dist = permuteExtract(dist_D2,tNear);
+ stackPtr[1].ptr = permuteExtract(dist_C2,n0,n1);
+ *(float*)&stackPtr[1].dist = permuteExtract(dist_C2,tNear);
+ stackPtr[2].ptr = permuteExtract(dist_B2,n0,n1);
+ *(float*)&stackPtr[2].dist = permuteExtract(dist_B2,tNear);
+ stackPtr+=3;
+ return;
+ }
+
+ /* >=5 hits: reverse to descending order for writing to stack */
+
+ distance_i = align_shift_right<3>(distance_i,distance_i);
+ const size_t hits = 4 + popcnt(mask);
+ vint8 dist(INT_MIN); // this will work with -0.0f (0x80000000) as distance, isort_update uses >= to insert
+
+ isort_quick_update<8>(dist,dist_A2);
+ isort_quick_update<8>(dist,dist_B2);
+ isort_quick_update<8>(dist,dist_C2);
+ isort_quick_update<8>(dist,dist_D2);
+
+ do {
+
+ distance_i = align_shift_right<1>(distance_i,distance_i);
+ cur = permuteExtract(distance_i,n0,n1);
+ BVH::prefetch(cur,types);
+ const vint8 new_dist(permute(distance_i,vint8(zero)));
+ mask &= mask-1;
+ isort_update<8>(dist,new_dist);
+
+ } while(mask);
+
+ for (size_t i=0; i<7; i++)
+ assert(dist[i+0]>=dist[i+1]);
+
+ for (size_t i=0;i<hits-1;i++)
+ {
+ stackPtr->ptr = permuteExtract(dist,n0,n1);
+ *(float*)&stackPtr->dist = permuteExtract(dist,tNear);
+ dist = align_shift_right<1>(dist,dist);
+ stackPtr++;
+ }
+ cur = permuteExtract(dist,n0,n1);
+ }
+#endif
+
+ public:
+ static __forceinline void traverseClosestHit(NodeRef& cur,
+ size_t mask,
+ const vfloat8& tNear,
+ StackItemT<NodeRef>*& stackPtr,
+ StackItemT<NodeRef>* stackEnd)
+ {
+ assert(mask != 0);
+#if defined(__AVX512VL__)
+ traverseClosestHitAVX512VL8<NodeRef,BaseNode>(cur,mask,tNear,stackPtr,stackEnd);
+#else
+
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ size_t r = bscf(mask);
+ cur = node->child(r);
+ BVH::prefetch(cur,types);
+ if (likely(mask == 0)) {
+ assert(cur != BVH::emptyNode);
+ return;
+ }
+
+ /*! two children are hit, push far child, and continue with closer child */
+ NodeRef c0 = cur;
+ const unsigned int d0 = ((unsigned int*)&tNear)[r];
+ r = bscf(mask);
+ NodeRef c1 = node->child(r);
+ BVH::prefetch(c1,types);
+ const unsigned int d1 = ((unsigned int*)&tNear)[r];
+
+ assert(c0 != BVH::emptyNode);
+ assert(c1 != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ assert(stackPtr < stackEnd);
+ if (d0 < d1) { stackPtr->ptr = c1; stackPtr->dist = d1; stackPtr++; cur = c0; return; }
+ else { stackPtr->ptr = c0; stackPtr->dist = d0; stackPtr++; cur = c1; return; }
+ }
+#if NEW_SORTING_CODE == 1
+ vint4 s0((size_t)c0,(size_t)d0);
+ vint4 s1((size_t)c1,(size_t)d1);
+
+ r = bscf(mask);
+ NodeRef c2 = node->child(r); BVH::prefetch(c2,types); unsigned int d2 = ((unsigned int*)&tNear)[r];
+ vint4 s2((size_t)c2,(size_t)d2);
+ /* 3 hits */
+ if (likely(mask == 0)) {
+ StackItemT<NodeRef>::sort3(s0,s1,s2);
+ *(vint4*)&stackPtr[0] = s0; *(vint4*)&stackPtr[1] = s1;
+ cur = toSizeT(s2);
+ stackPtr+=2;
+ return;
+ }
+ r = bscf(mask);
+ NodeRef c3 = node->child(r); BVH::prefetch(c3,types); unsigned int d3 = ((unsigned int*)&tNear)[r];
+ vint4 s3((size_t)c3,(size_t)d3);
+ /* 4 hits */
+ if (likely(mask == 0)) {
+ StackItemT<NodeRef>::sort4(s0,s1,s2,s3);
+ *(vint4*)&stackPtr[0] = s0; *(vint4*)&stackPtr[1] = s1; *(vint4*)&stackPtr[2] = s2;
+ cur = toSizeT(s3);
+ stackPtr+=3;
+ return;
+ }
+ *(vint4*)&stackPtr[0] = s0; *(vint4*)&stackPtr[1] = s1; *(vint4*)&stackPtr[2] = s2; *(vint4*)&stackPtr[3] = s3;
+ /*! fallback case if more than 4 children are hit */
+ StackItemT<NodeRef>* stackFirst = stackPtr;
+ stackPtr+=4;
+ while (1)
+ {
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ NodeRef c = node->child(r); BVH::prefetch(c,types); unsigned int d = *(unsigned int*)&tNear[r];
+ const vint4 s((size_t)c,(size_t)d);
+ *(vint4*)stackPtr++ = s;
+ assert(c != BVH::emptyNode);
+ if (unlikely(mask == 0)) break;
+ }
+ sort(stackFirst,stackPtr);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+#else
+ /*! Here starts the slow path for 3 or 4 hit children. We push
+ * all nodes onto the stack to sort them there. */
+ assert(stackPtr < stackEnd);
+ stackPtr->ptr = c0; stackPtr->dist = d0; stackPtr++;
+ assert(stackPtr < stackEnd);
+ stackPtr->ptr = c1; stackPtr->dist = d1; stackPtr++;
+
+ /*! three children are hit, push all onto stack and sort 3 stack items, continue with closest child */
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ NodeRef c = node->child(r); BVH::prefetch(c,types); unsigned int d = ((unsigned int*)&tNear)[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++;
+ assert(c != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ sort(stackPtr[-1],stackPtr[-2],stackPtr[-3]);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+ return;
+ }
+
+ /*! four children are hit, push all onto stack and sort 4 stack items, continue with closest child */
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ c = node->child(r); BVH::prefetch(c,types); d = *(unsigned int*)&tNear[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++;
+ assert(c != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ sort(stackPtr[-1],stackPtr[-2],stackPtr[-3],stackPtr[-4]);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+ return;
+ }
+ /*! fallback case if more than 4 children are hit */
+ StackItemT<NodeRef>* stackFirst = stackPtr-4;
+ while (1)
+ {
+ assert(stackPtr < stackEnd);
+ r = bscf(mask);
+ c = node->child(r); BVH::prefetch(c,types); d = *(unsigned int*)&tNear[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++;
+ assert(c != BVH::emptyNode);
+ if (unlikely(mask == 0)) break;
+ }
+ sort(stackFirst,stackPtr);
+ cur = (NodeRef) stackPtr[-1].ptr; stackPtr--;
+#endif
+#endif
+ }
+
+ static __forceinline void traverseAnyHit(NodeRef& cur,
+ size_t mask,
+ const vfloat8& tNear,
+ NodeRef*& stackPtr,
+ NodeRef* stackEnd)
+ {
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ size_t r = bscf(mask);
+ cur = node->child(r);
+ BVH::prefetch(cur,types);
+
+ /* simpler in sequence traversal order */
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ assert(stackPtr < stackEnd);
+ *stackPtr = cur; stackPtr++;
+
+ for (; ;)
+ {
+ r = bscf(mask);
+ cur = node->child(r); BVH::prefetch(cur,types);
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ assert(stackPtr < stackEnd);
+ *stackPtr = cur; stackPtr++;
+ }
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/bvh_traverser_stream.h b/thirdparty/embree/kernels/bvh/bvh_traverser_stream.h
new file mode 100644
index 0000000000..852981e69d
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/bvh_traverser_stream.h
@@ -0,0 +1,149 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+#include "../common/ray.h"
+#include "../common/stack_item.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, int types>
+ class BVHNNodeTraverserStreamHitCoherent
+ {
+ typedef BVHN<N> BVH;
+ typedef typename BVH::NodeRef NodeRef;
+ typedef typename BVH::BaseNode BaseNode;
+
+ public:
+ template<class T>
+ static __forceinline void traverseClosestHit(NodeRef& cur,
+ size_t& m_trav_active,
+ const vbool<N>& vmask,
+ const vfloat<N>& tNear,
+ const T* const tMask,
+ StackItemMaskCoherent*& stackPtr)
+ {
+ const NodeRef parent = cur;
+ size_t mask = movemask(vmask);
+ assert(mask != 0);
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ const size_t r0 = bscf(mask);
+ assert(r0 < 8);
+ cur = node->child(r0);
+ BVHN<N>::prefetch(cur,types);
+ m_trav_active = tMask[r0];
+ assert(cur != BVH::emptyNode);
+ if (unlikely(mask == 0)) return;
+
+ const unsigned int* const tNear_i = (unsigned int*)&tNear;
+
+ /*! two children are hit, push far child, and continue with closer child */
+ NodeRef c0 = cur;
+ unsigned int d0 = tNear_i[r0];
+ const size_t r1 = bscf(mask);
+ assert(r1 < 8);
+ NodeRef c1 = node->child(r1);
+ BVHN<N>::prefetch(c1,types);
+ unsigned int d1 = tNear_i[r1];
+
+ assert(c0 != BVH::emptyNode);
+ assert(c1 != BVH::emptyNode);
+ if (likely(mask == 0)) {
+ if (d0 < d1) {
+ assert(tNear[r1] >= 0.0f);
+ stackPtr->mask = tMask[r1];
+ stackPtr->parent = parent;
+ stackPtr->child = c1;
+ stackPtr++;
+ cur = c0;
+ m_trav_active = tMask[r0];
+ return;
+ }
+ else {
+ assert(tNear[r0] >= 0.0f);
+ stackPtr->mask = tMask[r0];
+ stackPtr->parent = parent;
+ stackPtr->child = c0;
+ stackPtr++;
+ cur = c1;
+ m_trav_active = tMask[r1];
+ return;
+ }
+ }
+
+ /*! slow path for more than two hits */
+ size_t hits = movemask(vmask);
+ const vint<N> dist_i = select(vmask, (asInt(tNear) & 0xfffffff8) | vint<N>(step), 0);
+ const vint<N> dist_i_sorted = usort_descending(dist_i);
+ const vint<N> sorted_index = dist_i_sorted & 7;
+
+ size_t i = 0;
+ for (;;)
+ {
+ const unsigned int index = sorted_index[i];
+ assert(index < 8);
+ cur = node->child(index);
+ m_trav_active = tMask[index];
+ assert(m_trav_active);
+ BVHN<N>::prefetch(cur,types);
+ bscf(hits);
+ if (unlikely(hits==0)) break;
+ i++;
+ assert(cur != BVH::emptyNode);
+ assert(tNear[index] >= 0.0f);
+ stackPtr->mask = m_trav_active;
+ stackPtr->parent = parent;
+ stackPtr->child = cur;
+ stackPtr++;
+ }
+ }
+
+ template<class T>
+ static __forceinline void traverseAnyHit(NodeRef& cur,
+ size_t& m_trav_active,
+ const vbool<N>& vmask,
+ const T* const tMask,
+ StackItemMaskCoherent*& stackPtr)
+ {
+ const NodeRef parent = cur;
+ size_t mask = movemask(vmask);
+ assert(mask != 0);
+ const BaseNode* node = cur.baseNode();
+
+ /*! one child is hit, continue with that child */
+ size_t r = bscf(mask);
+ cur = node->child(r);
+ BVHN<N>::prefetch(cur,types);
+ m_trav_active = tMask[r];
+
+ /* simple in order sequence */
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ stackPtr->mask = m_trav_active;
+ stackPtr->parent = parent;
+ stackPtr->child = cur;
+ stackPtr++;
+
+ for (; ;)
+ {
+ r = bscf(mask);
+ cur = node->child(r);
+ BVHN<N>::prefetch(cur,types);
+ m_trav_active = tMask[r];
+ assert(cur != BVH::emptyNode);
+ if (likely(mask == 0)) return;
+ stackPtr->mask = m_trav_active;
+ stackPtr->parent = parent;
+ stackPtr->child = cur;
+ stackPtr++;
+ }
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/node_intersector.h b/thirdparty/embree/kernels/bvh/node_intersector.h
new file mode 100644
index 0000000000..25edaf295d
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/node_intersector.h
@@ -0,0 +1,31 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bvh.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct NearFarPrecalculations
+ {
+ size_t nearX, nearY, nearZ;
+ size_t farX, farY, farZ;
+
+ __forceinline NearFarPrecalculations() {}
+
+ __forceinline NearFarPrecalculations(const Vec3fa& dir, size_t N)
+ {
+ const size_t size = sizeof(float)*N;
+ nearX = (dir.x < 0.0f) ? 1*size : 0*size;
+ nearY = (dir.y < 0.0f) ? 3*size : 2*size;
+ nearZ = (dir.z < 0.0f) ? 5*size : 4*size;
+ farX = nearX ^ size;
+ farY = nearY ^ size;
+ farZ = nearZ ^ size;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/node_intersector1.h b/thirdparty/embree/kernels/bvh/node_intersector1.h
new file mode 100644
index 0000000000..1ec4fc63fc
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/node_intersector1.h
@@ -0,0 +1,1403 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "node_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Ray structure used in single-ray traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, bool robust>
+ struct TravRayBase;
+
+ /* Base (without tnear and tfar) */
+ template<int N>
+ struct TravRayBase<N,false>
+ {
+ __forceinline TravRayBase() {}
+
+ __forceinline TravRayBase(const Vec3fa& ray_org, const Vec3fa& ray_dir)
+ : org_xyz(ray_org), dir_xyz(ray_dir)
+ {
+ const Vec3fa ray_rdir = rcp_safe(ray_dir);
+ org = Vec3vf<N>(ray_org.x,ray_org.y,ray_org.z);
+ dir = Vec3vf<N>(ray_dir.x,ray_dir.y,ray_dir.z);
+ rdir = Vec3vf<N>(ray_rdir.x,ray_rdir.y,ray_rdir.z);
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ const Vec3fa ray_org_rdir = ray_org*ray_rdir;
+ org_rdir = Vec3vf<N>(ray_org_rdir.x,ray_org_rdir.y,ray_org_rdir.z);
+#endif
+ nearX = ray_rdir.x >= 0.0f ? 0*sizeof(vfloat<N>) : 1*sizeof(vfloat<N>);
+ nearY = ray_rdir.y >= 0.0f ? 2*sizeof(vfloat<N>) : 3*sizeof(vfloat<N>);
+ nearZ = ray_rdir.z >= 0.0f ? 4*sizeof(vfloat<N>) : 5*sizeof(vfloat<N>);
+ farX = nearX ^ sizeof(vfloat<N>);
+ farY = nearY ^ sizeof(vfloat<N>);
+ farZ = nearZ ^ sizeof(vfloat<N>);
+ }
+
+ template<int K>
+ __forceinline void init(size_t k, const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir,
+ const Vec3vf<K>& ray_rdir, const Vec3vi<K>& nearXYZ,
+ size_t flip = sizeof(vfloat<N>))
+ {
+ org = Vec3vf<N>(ray_org.x[k], ray_org.y[k], ray_org.z[k]);
+ dir = Vec3vf<N>(ray_dir.x[k], ray_dir.y[k], ray_dir.z[k]);
+ rdir = Vec3vf<N>(ray_rdir.x[k], ray_rdir.y[k], ray_rdir.z[k]);
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ org_rdir = org*rdir;
+#endif
+ nearX = nearXYZ.x[k];
+ nearY = nearXYZ.y[k];
+ nearZ = nearXYZ.z[k];
+ farX = nearX ^ flip;
+ farY = nearY ^ flip;
+ farZ = nearZ ^ flip;
+ }
+
+ Vec3fa org_xyz, dir_xyz;
+ Vec3vf<N> org, dir, rdir;
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ Vec3vf<N> org_rdir;
+#endif
+ size_t nearX, nearY, nearZ;
+ size_t farX, farY, farZ;
+ };
+
+ /* Base (without tnear and tfar) */
+ template<int N>
+ struct TravRayBase<N,true>
+ {
+ __forceinline TravRayBase() {}
+
+ __forceinline TravRayBase(const Vec3fa& ray_org, const Vec3fa& ray_dir)
+ : org_xyz(ray_org), dir_xyz(ray_dir)
+ {
+ const float round_down = 1.0f-3.0f*float(ulp);
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const Vec3fa ray_rdir = 1.0f/zero_fix(ray_dir);
+ const Vec3fa ray_rdir_near = round_down*ray_rdir;
+ const Vec3fa ray_rdir_far = round_up *ray_rdir;
+ org = Vec3vf<N>(ray_org.x,ray_org.y,ray_org.z);
+ dir = Vec3vf<N>(ray_dir.x,ray_dir.y,ray_dir.z);
+ rdir_near = Vec3vf<N>(ray_rdir_near.x,ray_rdir_near.y,ray_rdir_near.z);
+ rdir_far = Vec3vf<N>(ray_rdir_far .x,ray_rdir_far .y,ray_rdir_far .z);
+
+ nearX = ray_rdir_near.x >= 0.0f ? 0*sizeof(vfloat<N>) : 1*sizeof(vfloat<N>);
+ nearY = ray_rdir_near.y >= 0.0f ? 2*sizeof(vfloat<N>) : 3*sizeof(vfloat<N>);
+ nearZ = ray_rdir_near.z >= 0.0f ? 4*sizeof(vfloat<N>) : 5*sizeof(vfloat<N>);
+ farX = nearX ^ sizeof(vfloat<N>);
+ farY = nearY ^ sizeof(vfloat<N>);
+ farZ = nearZ ^ sizeof(vfloat<N>);
+ }
+
+ template<int K>
+ __forceinline void init(size_t k, const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir,
+ const Vec3vf<K>& ray_rdir, const Vec3vi<K>& nearXYZ,
+ size_t flip = sizeof(vfloat<N>))
+ {
+ const vfloat<N> round_down = 1.0f-3.0f*float(ulp);
+ const vfloat<N> round_up = 1.0f+3.0f*float(ulp);
+ org = Vec3vf<N>(ray_org.x[k], ray_org.y[k], ray_org.z[k]);
+ dir = Vec3vf<N>(ray_dir.x[k], ray_dir.y[k], ray_dir.z[k]);
+ rdir_near = round_down*Vec3vf<N>(ray_rdir.x[k], ray_rdir.y[k], ray_rdir.z[k]);
+ rdir_far = round_up *Vec3vf<N>(ray_rdir.x[k], ray_rdir.y[k], ray_rdir.z[k]);
+
+ nearX = nearXYZ.x[k];
+ nearY = nearXYZ.y[k];
+ nearZ = nearXYZ.z[k];
+ farX = nearX ^ flip;
+ farY = nearY ^ flip;
+ farZ = nearZ ^ flip;
+ }
+
+ Vec3fa org_xyz, dir_xyz;
+ Vec3vf<N> org, dir, rdir_near, rdir_far;
+ size_t nearX, nearY, nearZ;
+ size_t farX, farY, farZ;
+ };
+
+ /* Full (with tnear and tfar) */
+ template<int N, bool robust>
+ struct TravRay : TravRayBase<N,robust>
+ {
+ __forceinline TravRay() {}
+
+ __forceinline TravRay(const Vec3fa& ray_org, const Vec3fa& ray_dir, float ray_tnear, float ray_tfar)
+ : TravRayBase<N,robust>(ray_org, ray_dir),
+ tnear(ray_tnear), tfar(ray_tfar) {}
+
+ template<int K>
+ __forceinline void init(size_t k, const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir,
+ const Vec3vf<K>& ray_rdir, const Vec3vi<K>& nearXYZ,
+ float ray_tnear, float ray_tfar,
+ size_t flip = sizeof(vfloat<N>))
+ {
+ TravRayBase<N,robust>::template init<K>(k, ray_org, ray_dir, ray_rdir, nearXYZ, flip);
+ tnear = ray_tnear; tfar = ray_tfar;
+ }
+
+ vfloat<N> tnear;
+ vfloat<N> tfar;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Point Query structure used in single-ray traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ struct TravPointQuery
+ {
+ __forceinline TravPointQuery() {}
+
+ __forceinline TravPointQuery(const Vec3fa& query_org, const Vec3fa& query_rad)
+ {
+ org = Vec3vf<N>(query_org.x, query_org.y, query_org.z);
+ rad = Vec3vf<N>(query_rad.x, query_rad.y, query_rad.z);
+ }
+
+ __forceinline vfloat<N> const& tfar() const {
+ return rad.x;
+ }
+
+ Vec3vf<N> org, rad;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // point query
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t pointQuerySphereDistAndMask(
+ const TravPointQuery<N>& query, vfloat<N>& dist, vfloat<N> const& minX, vfloat<N> const& maxX,
+ vfloat<N> const& minY, vfloat<N> const& maxY, vfloat<N> const& minZ, vfloat<N> const& maxZ)
+ {
+ const vfloat<N> vX = min(max(query.org.x, minX), maxX) - query.org.x;
+ const vfloat<N> vY = min(max(query.org.y, minY), maxY) - query.org.y;
+ const vfloat<N> vZ = min(max(query.org.z, minZ), maxZ) - query.org.z;
+ dist = vX * vX + vY * vY + vZ * vZ;
+ const vbool<N> vmask = dist <= query.tfar()*query.tfar();
+ const vbool<N> valid = minX <= maxX;
+ return movemask(vmask) & movemask(valid);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::AABBNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ const vfloat<N> minX = vfloat<N>::load((float*)((const char*)&node->lower_x));
+ const vfloat<N> minY = vfloat<N>::load((float*)((const char*)&node->lower_y));
+ const vfloat<N> minZ = vfloat<N>::load((float*)((const char*)&node->lower_z));
+ const vfloat<N> maxX = vfloat<N>::load((float*)((const char*)&node->upper_x));
+ const vfloat<N> maxY = vfloat<N>::load((float*)((const char*)&node->upper_y));
+ const vfloat<N> maxZ = vfloat<N>::load((float*)((const char*)&node->upper_z));
+ return pointQuerySphereDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::AABBNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const vfloat<N>* pMinX = (const vfloat<N>*)((const char*)&node->lower_x);
+ const vfloat<N>* pMinY = (const vfloat<N>*)((const char*)&node->lower_y);
+ const vfloat<N>* pMinZ = (const vfloat<N>*)((const char*)&node->lower_z);
+ const vfloat<N>* pMaxX = (const vfloat<N>*)((const char*)&node->upper_x);
+ const vfloat<N>* pMaxY = (const vfloat<N>*)((const char*)&node->upper_y);
+ const vfloat<N>* pMaxZ = (const vfloat<N>*)((const char*)&node->upper_z);
+ const vfloat<N> minX = madd(time,pMinX[6],vfloat<N>(pMinX[0]));
+ const vfloat<N> minY = madd(time,pMinY[6],vfloat<N>(pMinY[0]));
+ const vfloat<N> minZ = madd(time,pMinZ[6],vfloat<N>(pMinZ[0]));
+ const vfloat<N> maxX = madd(time,pMaxX[6],vfloat<N>(pMaxX[0]));
+ const vfloat<N> maxY = madd(time,pMaxY[6],vfloat<N>(pMaxY[0]));
+ const vfloat<N> maxZ = madd(time,pMaxZ[6],vfloat<N>(pMaxZ[0]));
+ return pointQuerySphereDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphereMB4D(const typename BVHN<N>::NodeRef ref, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+ size_t mask = pointQueryNodeSphere(node, query, time, dist);
+
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ const vbool<N> vmask = (node1->lower_t <= time) & (time < node1->upper_t);
+ mask &= movemask(vmask);
+ }
+
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::QuantizedBaseNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ const vfloat<N> start_x(node->start.x);
+ const vfloat<N> scale_x(node->scale.x);
+ const vfloat<N> minX = madd(node->template dequantize<N>((0*sizeof(vfloat<N>)) >> 2),scale_x,start_x);
+ const vfloat<N> maxX = madd(node->template dequantize<N>((1*sizeof(vfloat<N>)) >> 2),scale_x,start_x);
+ const vfloat<N> start_y(node->start.y);
+ const vfloat<N> scale_y(node->scale.y);
+ const vfloat<N> minY = madd(node->template dequantize<N>((2*sizeof(vfloat<N>)) >> 2),scale_y,start_y);
+ const vfloat<N> maxY = madd(node->template dequantize<N>((3*sizeof(vfloat<N>)) >> 2),scale_y,start_y);
+ const vfloat<N> start_z(node->start.z);
+ const vfloat<N> scale_z(node->scale.z);
+ const vfloat<N> minZ = madd(node->template dequantize<N>((4*sizeof(vfloat<N>)) >> 2),scale_z,start_z);
+ const vfloat<N> maxZ = madd(node->template dequantize<N>((5*sizeof(vfloat<N>)) >> 2),scale_z,start_z);
+ return pointQuerySphereDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ) & movemask(node->validMask());
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const vfloat<N> minX = node->dequantizeLowerX(time);
+ const vfloat<N> maxX = node->dequantizeUpperX(time);
+ const vfloat<N> minY = node->dequantizeLowerY(time);
+ const vfloat<N> maxY = node->dequantizeUpperY(time);
+ const vfloat<N> minZ = node->dequantizeLowerZ(time);
+ const vfloat<N> maxZ = node->dequantizeUpperZ(time);
+ return pointQuerySphereDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ) & movemask(node->validMask());
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::OBBNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ // TODO: point query - implement
+ const vbool<N> vmask = vbool<N>(true);
+ const size_t mask = movemask(vmask) & ((1<<N)-1);
+ dist = vfloat<N>(0.0f);
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeSphere(const typename BVHN<N>::OBBNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ // TODO: point query - implement
+ const vbool<N> vmask = vbool<N>(true);
+ const size_t mask = movemask(vmask) & ((1<<N)-1);
+ dist = vfloat<N>(0.0f);
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryAABBDistAndMask(
+ const TravPointQuery<N>& query, vfloat<N>& dist, vfloat<N> const& minX, vfloat<N> const& maxX,
+ vfloat<N> const& minY, vfloat<N> const& maxY, vfloat<N> const& minZ, vfloat<N> const& maxZ)
+ {
+ const vfloat<N> vX = min(max(query.org.x, minX), maxX) - query.org.x;
+ const vfloat<N> vY = min(max(query.org.y, minY), maxY) - query.org.y;
+ const vfloat<N> vZ = min(max(query.org.z, minZ), maxZ) - query.org.z;
+ dist = vX * vX + vY * vY + vZ * vZ;
+ const vbool<N> valid = minX <= maxX;
+ const vbool<N> vmask = !((maxX < query.org.x - query.rad.x) | (minX > query.org.x + query.rad.x) |
+ (maxY < query.org.y - query.rad.y) | (minY > query.org.y + query.rad.y) |
+ (maxZ < query.org.z - query.rad.z) | (minZ > query.org.z + query.rad.z));
+ return movemask(vmask) & movemask(valid);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::AABBNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ const vfloat<N> minX = vfloat<N>::load((float*)((const char*)&node->lower_x));
+ const vfloat<N> minY = vfloat<N>::load((float*)((const char*)&node->lower_y));
+ const vfloat<N> minZ = vfloat<N>::load((float*)((const char*)&node->lower_z));
+ const vfloat<N> maxX = vfloat<N>::load((float*)((const char*)&node->upper_x));
+ const vfloat<N> maxY = vfloat<N>::load((float*)((const char*)&node->upper_y));
+ const vfloat<N> maxZ = vfloat<N>::load((float*)((const char*)&node->upper_z));
+ return pointQueryAABBDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::AABBNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const vfloat<N>* pMinX = (const vfloat<N>*)((const char*)&node->lower_x);
+ const vfloat<N>* pMinY = (const vfloat<N>*)((const char*)&node->lower_y);
+ const vfloat<N>* pMinZ = (const vfloat<N>*)((const char*)&node->lower_z);
+ const vfloat<N>* pMaxX = (const vfloat<N>*)((const char*)&node->upper_x);
+ const vfloat<N>* pMaxY = (const vfloat<N>*)((const char*)&node->upper_y);
+ const vfloat<N>* pMaxZ = (const vfloat<N>*)((const char*)&node->upper_z);
+ const vfloat<N> minX = madd(time,pMinX[6],vfloat<N>(pMinX[0]));
+ const vfloat<N> minY = madd(time,pMinY[6],vfloat<N>(pMinY[0]));
+ const vfloat<N> minZ = madd(time,pMinZ[6],vfloat<N>(pMinZ[0]));
+ const vfloat<N> maxX = madd(time,pMaxX[6],vfloat<N>(pMaxX[0]));
+ const vfloat<N> maxY = madd(time,pMaxY[6],vfloat<N>(pMaxY[0]));
+ const vfloat<N> maxZ = madd(time,pMaxZ[6],vfloat<N>(pMaxZ[0]));
+ return pointQueryAABBDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ);
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABBMB4D(const typename BVHN<N>::NodeRef ref, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+ size_t mask = pointQueryNodeAABB(node, query, time, dist);
+
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ const vbool<N> vmask = (node1->lower_t <= time) & (time < node1->upper_t);
+ mask &= movemask(vmask);
+ }
+
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::QuantizedBaseNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat<N> start_x(node->start.x);
+ const vfloat<N> scale_x(node->scale.x);
+ const vfloat<N> minX = madd(node->template dequantize<N>((0*sizeof(vfloat<N>)) >> 2),scale_x,start_x);
+ const vfloat<N> maxX = madd(node->template dequantize<N>((1*sizeof(vfloat<N>)) >> 2),scale_x,start_x);
+ const vfloat<N> start_y(node->start.y);
+ const vfloat<N> scale_y(node->scale.y);
+ const vfloat<N> minY = madd(node->template dequantize<N>((2*sizeof(vfloat<N>)) >> 2),scale_y,start_y);
+ const vfloat<N> maxY = madd(node->template dequantize<N>((3*sizeof(vfloat<N>)) >> 2),scale_y,start_y);
+ const vfloat<N> start_z(node->start.z);
+ const vfloat<N> scale_z(node->scale.z);
+ const vfloat<N> minZ = madd(node->template dequantize<N>((4*sizeof(vfloat<N>)) >> 2),scale_z,start_z);
+ const vfloat<N> maxZ = madd(node->template dequantize<N>((5*sizeof(vfloat<N>)) >> 2),scale_z,start_z);
+ return pointQueryAABBDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ) & mvalid;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat<N> minX = node->dequantizeLowerX(time);
+ const vfloat<N> maxX = node->dequantizeUpperX(time);
+ const vfloat<N> minY = node->dequantizeLowerY(time);
+ const vfloat<N> maxY = node->dequantizeUpperY(time);
+ const vfloat<N> minZ = node->dequantizeLowerZ(time);
+ const vfloat<N> maxZ = node->dequantizeUpperZ(time);
+ return pointQueryAABBDistAndMask(query, dist, minX, maxX, minY, maxY, minZ, maxZ) & mvalid;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::OBBNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ // TODO: point query - implement
+ const vbool<N> vmask = vbool<N>(true);
+ const size_t mask = movemask(vmask) & ((1<<N)-1);
+ dist = vfloat<N>(0.0f);
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t pointQueryNodeAABB(const typename BVHN<N>::OBBNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ // TODO: point query - implement
+ const vbool<N> vmask = vbool<N>(true);
+ const size_t mask = movemask(vmask) & ((1<<N)-1);
+ dist = vfloat<N>(0.0f);
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, bool robust>
+ __forceinline size_t intersectNode(const typename BVHN<N>::AABBNode* node, const TravRay<N,robust>& ray, vfloat<N>& dist);
+
+ template<>
+ __forceinline size_t intersectNode<4>(const typename BVH4::AABBNode* node, const TravRay<4,false>& ray, vfloat4& dist)
+ {
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat4 tNearX = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.nearX)), ray.rdir.x, ray.org_rdir.x);
+ const vfloat4 tNearY = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.nearY)), ray.rdir.y, ray.org_rdir.y);
+ const vfloat4 tNearZ = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.nearZ)), ray.rdir.z, ray.org_rdir.z);
+ const vfloat4 tFarX = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.farX )), ray.rdir.x, ray.org_rdir.x);
+ const vfloat4 tFarY = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.farY )), ray.rdir.y, ray.org_rdir.y);
+ const vfloat4 tFarZ = msub(vfloat4::load((float*)((const char*)&node->lower_x+ray.farZ )), ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat4 tNearX = (vfloat4::load((float*)((const char*)&node->lower_x+ray.nearX)) - ray.org.x) * ray.rdir.x;
+ const vfloat4 tNearY = (vfloat4::load((float*)((const char*)&node->lower_x+ray.nearY)) - ray.org.y) * ray.rdir.y;
+ const vfloat4 tNearZ = (vfloat4::load((float*)((const char*)&node->lower_x+ray.nearZ)) - ray.org.z) * ray.rdir.z;
+ const vfloat4 tFarX = (vfloat4::load((float*)((const char*)&node->lower_x+ray.farX )) - ray.org.x) * ray.rdir.x;
+ const vfloat4 tFarY = (vfloat4::load((float*)((const char*)&node->lower_x+ray.farY )) - ray.org.y) * ray.rdir.y;
+ const vfloat4 tFarZ = (vfloat4::load((float*)((const char*)&node->lower_x+ray.farZ )) - ray.org.z) * ray.rdir.z;
+#endif
+
+#if defined(__aarch64__)
+ const vfloat4 tNear = maxi(tNearX, tNearY, tNearZ, ray.tnear);
+ const vfloat4 tFar = mini(tFarX, tFarY, tFarZ, ray.tfar);
+ const vbool4 vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#elif defined(__SSE4_1__) && !defined(__AVX512F__) // up to HSW
+ const vfloat4 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = asInt(tNear) > asInt(tFar);
+ const size_t mask = movemask(vmask) ^ ((1<<4)-1);
+#elif defined(__AVX512F__) // SKX
+ const vfloat4 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#else
+ const vfloat4 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+#endif
+ dist = tNear;
+ return mask;
+ }
+
+#if defined(__AVX__)
+
+ template<>
+ __forceinline size_t intersectNode<8>(const typename BVH8::AABBNode* node, const TravRay<8,false>& ray, vfloat8& dist)
+ {
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat8 tNearX = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.nearX)), ray.rdir.x, ray.org_rdir.x);
+ const vfloat8 tNearY = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.nearY)), ray.rdir.y, ray.org_rdir.y);
+ const vfloat8 tNearZ = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.nearZ)), ray.rdir.z, ray.org_rdir.z);
+ const vfloat8 tFarX = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.farX )), ray.rdir.x, ray.org_rdir.x);
+ const vfloat8 tFarY = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.farY )), ray.rdir.y, ray.org_rdir.y);
+ const vfloat8 tFarZ = msub(vfloat8::load((float*)((const char*)&node->lower_x+ray.farZ )), ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat8 tNearX = (vfloat8::load((float*)((const char*)&node->lower_x+ray.nearX)) - ray.org.x) * ray.rdir.x;
+ const vfloat8 tNearY = (vfloat8::load((float*)((const char*)&node->lower_x+ray.nearY)) - ray.org.y) * ray.rdir.y;
+ const vfloat8 tNearZ = (vfloat8::load((float*)((const char*)&node->lower_x+ray.nearZ)) - ray.org.z) * ray.rdir.z;
+ const vfloat8 tFarX = (vfloat8::load((float*)((const char*)&node->lower_x+ray.farX )) - ray.org.x) * ray.rdir.x;
+ const vfloat8 tFarY = (vfloat8::load((float*)((const char*)&node->lower_x+ray.farY )) - ray.org.y) * ray.rdir.y;
+ const vfloat8 tFarZ = (vfloat8::load((float*)((const char*)&node->lower_x+ray.farZ )) - ray.org.z) * ray.rdir.z;
+#endif
+
+#if defined(__AVX2__) && !defined(__AVX512F__) // HSW
+ const vfloat8 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = asInt(tNear) > asInt(tFar);
+ const size_t mask = movemask(vmask) ^ ((1<<8)-1);
+#elif defined(__AVX512F__) // SKX
+ const vfloat8 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#else
+ const vfloat8 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+#endif
+ dist = tNear;
+ return mask;
+ }
+
+#endif
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNodeRobust(const typename BVHN<N>::AABBNode* node, const TravRay<N,true>& ray, vfloat<N>& dist)
+ {
+ const vfloat<N> tNearX = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearX)) - ray.org.x) * ray.rdir_near.x;
+ const vfloat<N> tNearY = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearY)) - ray.org.y) * ray.rdir_near.y;
+ const vfloat<N> tNearZ = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearZ)) - ray.org.z) * ray.rdir_near.z;
+ const vfloat<N> tFarX = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farX )) - ray.org.x) * ray.rdir_far.x;
+ const vfloat<N> tFarY = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farY )) - ray.org.y) * ray.rdir_far.y;
+ const vfloat<N> tFarZ = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farZ )) - ray.org.z) * ray.rdir_far.z;
+ const vfloat<N> tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat<N> tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool<N> vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNode(const typename BVHN<N>::AABBNodeMB* node, const TravRay<N,false>& ray, const float time, vfloat<N>& dist)
+ {
+ const vfloat<N>* pNearX = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearX);
+ const vfloat<N>* pNearY = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearY);
+ const vfloat<N>* pNearZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearZ);
+ const vfloat<N>* pFarX = (const vfloat<N>*)((const char*)&node->lower_x+ray.farX);
+ const vfloat<N>* pFarY = (const vfloat<N>*)((const char*)&node->lower_x+ray.farY);
+ const vfloat<N>* pFarZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.farZ);
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat<N> tNearX = msub(madd(time,pNearX[6],vfloat<N>(pNearX[0])), ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tNearY = msub(madd(time,pNearY[6],vfloat<N>(pNearY[0])), ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tNearZ = msub(madd(time,pNearZ[6],vfloat<N>(pNearZ[0])), ray.rdir.z, ray.org_rdir.z);
+ const vfloat<N> tFarX = msub(madd(time,pFarX [6],vfloat<N>(pFarX [0])), ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tFarY = msub(madd(time,pFarY [6],vfloat<N>(pFarY [0])), ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tFarZ = msub(madd(time,pFarZ [6],vfloat<N>(pFarZ [0])), ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat<N> tNearX = (madd(time,pNearX[6],vfloat<N>(pNearX[0])) - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tNearY = (madd(time,pNearY[6],vfloat<N>(pNearY[0])) - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tNearZ = (madd(time,pNearZ[6],vfloat<N>(pNearZ[0])) - ray.org.z) * ray.rdir.z;
+ const vfloat<N> tFarX = (madd(time,pFarX [6],vfloat<N>(pFarX [0])) - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tFarY = (madd(time,pFarY [6],vfloat<N>(pFarY [0])) - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tFarZ = (madd(time,pFarZ [6],vfloat<N>(pFarZ [0])) - ray.org.z) * ray.rdir.z;
+#endif
+#if defined(__AVX2__) && !defined(__AVX512F__) // HSW
+ const vfloat<N> tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat<N> tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool<N> vmask = asInt(tNear) > asInt(tFar);
+ const size_t mask = movemask(vmask) ^ ((1<<N)-1);
+#elif defined(__AVX512F__) // SKX
+ const vfloat<N> tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat<N> tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool<N> vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#else
+ const vfloat<N> tNear = max(ray.tnear,tNearX,tNearY,tNearZ);
+ const vfloat<N> tFar = min(ray.tfar, tFarX ,tFarY ,tFarZ );
+ const vbool<N> vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+#endif
+ dist = tNear;
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNodeRobust(const typename BVHN<N>::AABBNodeMB* node, const TravRay<N,true>& ray, const float time, vfloat<N>& dist)
+ {
+ const vfloat<N>* pNearX = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearX);
+ const vfloat<N>* pNearY = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearY);
+ const vfloat<N>* pNearZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearZ);
+ const vfloat<N> tNearX = (madd(time,pNearX[6],vfloat<N>(pNearX[0])) - ray.org.x) * ray.rdir_near.x;
+ const vfloat<N> tNearY = (madd(time,pNearY[6],vfloat<N>(pNearY[0])) - ray.org.y) * ray.rdir_near.y;
+ const vfloat<N> tNearZ = (madd(time,pNearZ[6],vfloat<N>(pNearZ[0])) - ray.org.z) * ray.rdir_near.z;
+ const vfloat<N> tNear = max(ray.tnear,tNearX,tNearY,tNearZ);
+ const vfloat<N>* pFarX = (const vfloat<N>*)((const char*)&node->lower_x+ray.farX);
+ const vfloat<N>* pFarY = (const vfloat<N>*)((const char*)&node->lower_x+ray.farY);
+ const vfloat<N>* pFarZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.farZ);
+ const vfloat<N> tFarX = (madd(time,pFarX[6],vfloat<N>(pFarX[0])) - ray.org.x) * ray.rdir_far.x;
+ const vfloat<N> tFarY = (madd(time,pFarY[6],vfloat<N>(pFarY[0])) - ray.org.y) * ray.rdir_far.y;
+ const vfloat<N> tFarZ = (madd(time,pFarZ[6],vfloat<N>(pFarZ[0])) - ray.org.z) * ray.rdir_far.z;
+ const vfloat<N> tFar = min(ray.tfar,tFarX,tFarY,tFarZ);
+ const size_t mask = movemask(tNear <= tFar);
+ dist = tNear;
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNodeMB4D intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNodeMB4D(const typename BVHN<N>::NodeRef ref, const TravRay<N,false>& ray, const float time, vfloat<N>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+
+ const vfloat<N>* pNearX = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearX);
+ const vfloat<N>* pNearY = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearY);
+ const vfloat<N>* pNearZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearZ);
+ const vfloat<N>* pFarX = (const vfloat<N>*)((const char*)&node->lower_x+ray.farX);
+ const vfloat<N>* pFarY = (const vfloat<N>*)((const char*)&node->lower_x+ray.farY);
+ const vfloat<N>* pFarZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.farZ);
+#if defined (__AVX2__) || defined(__ARM_NEON)
+ const vfloat<N> tNearX = msub(madd(time,pNearX[6],vfloat<N>(pNearX[0])), ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tNearY = msub(madd(time,pNearY[6],vfloat<N>(pNearY[0])), ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tNearZ = msub(madd(time,pNearZ[6],vfloat<N>(pNearZ[0])), ray.rdir.z, ray.org_rdir.z);
+ const vfloat<N> tFarX = msub(madd(time,pFarX [6],vfloat<N>(pFarX [0])), ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tFarY = msub(madd(time,pFarY [6],vfloat<N>(pFarY [0])), ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tFarZ = msub(madd(time,pFarZ [6],vfloat<N>(pFarZ [0])), ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat<N> tNearX = (madd(time,pNearX[6],vfloat<N>(pNearX[0])) - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tNearY = (madd(time,pNearY[6],vfloat<N>(pNearY[0])) - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tNearZ = (madd(time,pNearZ[6],vfloat<N>(pNearZ[0])) - ray.org.z) * ray.rdir.z;
+ const vfloat<N> tFarX = (madd(time,pFarX [6],vfloat<N>(pFarX [0])) - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tFarY = (madd(time,pFarY [6],vfloat<N>(pFarY [0])) - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tFarZ = (madd(time,pFarZ [6],vfloat<N>(pFarZ [0])) - ray.org.z) * ray.rdir.z;
+#endif
+#if defined(__AVX2__) && !defined(__AVX512F__)
+ const vfloat<N> tNear = maxi(maxi(tNearX,tNearY),maxi(tNearZ,ray.tnear));
+ const vfloat<N> tFar = mini(mini(tFarX ,tFarY ),mini(tFarZ ,ray.tfar ));
+#else
+ const vfloat<N> tNear = max(ray.tnear,tNearX,tNearY,tNearZ);
+ const vfloat<N> tFar = min(ray.tfar, tFarX ,tFarY ,tFarZ );
+#endif
+ vbool<N> vmask = tNear <= tFar;
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ vmask &= (node1->lower_t <= time) & (time < node1->upper_t);
+ }
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNodeMB4D intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNodeMB4DRobust(const typename BVHN<N>::NodeRef ref, const TravRay<N,true>& ray, const float time, vfloat<N>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+
+ const vfloat<N>* pNearX = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearX);
+ const vfloat<N>* pNearY = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearY);
+ const vfloat<N>* pNearZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.nearZ);
+ const vfloat<N> tNearX = (madd(time,pNearX[6],vfloat<N>(pNearX[0])) - ray.org.x) * ray.rdir_near.x;
+ const vfloat<N> tNearY = (madd(time,pNearY[6],vfloat<N>(pNearY[0])) - ray.org.y) * ray.rdir_near.y;
+ const vfloat<N> tNearZ = (madd(time,pNearZ[6],vfloat<N>(pNearZ[0])) - ray.org.z) * ray.rdir_near.z;
+ const vfloat<N> tNear = max(ray.tnear,tNearX,tNearY,tNearZ);
+ const vfloat<N>* pFarX = (const vfloat<N>*)((const char*)&node->lower_x+ray.farX);
+ const vfloat<N>* pFarY = (const vfloat<N>*)((const char*)&node->lower_x+ray.farY);
+ const vfloat<N>* pFarZ = (const vfloat<N>*)((const char*)&node->lower_x+ray.farZ);
+ const vfloat<N> tFarX = (madd(time,pFarX[6],vfloat<N>(pFarX[0])) - ray.org.x) * ray.rdir_far.x;
+ const vfloat<N> tFarY = (madd(time,pFarY[6],vfloat<N>(pFarY[0])) - ray.org.y) * ray.rdir_far.y;
+ const vfloat<N> tFarZ = (madd(time,pFarZ[6],vfloat<N>(pFarZ[0])) - ray.org.z) * ray.rdir_far.z;
+ const vfloat<N> tFar = min(ray.tfar,tFarX,tFarY,tFarZ);
+ vbool<N> vmask = tNear <= tFar;
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ vmask &= (node1->lower_t <= time) & (time < node1->upper_t);
+ }
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast QuantizedBaseNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, bool robust>
+ __forceinline size_t intersectNode(const typename BVHN<N>::QuantizedBaseNode* node, const TravRay<N,robust>& ray, vfloat<N>& dist);
+
+ template<>
+ __forceinline size_t intersectNode<4>(const typename BVH4::QuantizedBaseNode* node, const TravRay<4,false>& ray, vfloat4& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat4 start_x(node->start.x);
+ const vfloat4 scale_x(node->scale.x);
+ const vfloat4 lower_x = madd(node->dequantize<4>(ray.nearX >> 2),scale_x,start_x);
+ const vfloat4 upper_x = madd(node->dequantize<4>(ray.farX >> 2),scale_x,start_x);
+ const vfloat4 start_y(node->start.y);
+ const vfloat4 scale_y(node->scale.y);
+ const vfloat4 lower_y = madd(node->dequantize<4>(ray.nearY >> 2),scale_y,start_y);
+ const vfloat4 upper_y = madd(node->dequantize<4>(ray.farY >> 2),scale_y,start_y);
+ const vfloat4 start_z(node->start.z);
+ const vfloat4 scale_z(node->scale.z);
+ const vfloat4 lower_z = madd(node->dequantize<4>(ray.nearZ >> 2),scale_z,start_z);
+ const vfloat4 upper_z = madd(node->dequantize<4>(ray.farZ >> 2),scale_z,start_z);
+
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat4 tNearX = msub(lower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat4 tNearY = msub(lower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat4 tNearZ = msub(lower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat4 tFarX = msub(upper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat4 tFarY = msub(upper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat4 tFarZ = msub(upper_z, ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat4 tNearX = (lower_x - ray.org.x) * ray.rdir.x;
+ const vfloat4 tNearY = (lower_y - ray.org.y) * ray.rdir.y;
+ const vfloat4 tNearZ = (lower_z - ray.org.z) * ray.rdir.z;
+ const vfloat4 tFarX = (upper_x - ray.org.x) * ray.rdir.x;
+ const vfloat4 tFarY = (upper_y - ray.org.y) * ray.rdir.y;
+ const vfloat4 tFarZ = (upper_z - ray.org.z) * ray.rdir.z;
+#endif
+
+#if defined(__SSE4_1__) && !defined(__AVX512F__) // up to HSW
+ const vfloat4 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = asInt(tNear) > asInt(tFar);
+ const size_t mask = movemask(vmask) ^ ((1<<4)-1);
+#elif defined(__AVX512F__) // SKX
+ const vfloat4 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#else
+ const vfloat4 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+#endif
+ dist = tNear;
+ return mask & mvalid;
+ }
+
+ template<>
+ __forceinline size_t intersectNode<4>(const typename BVH4::QuantizedBaseNode* node, const TravRay<4,true>& ray, vfloat4& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat4 start_x(node->start.x);
+ const vfloat4 scale_x(node->scale.x);
+ const vfloat4 lower_x = madd(node->dequantize<4>(ray.nearX >> 2),scale_x,start_x);
+ const vfloat4 upper_x = madd(node->dequantize<4>(ray.farX >> 2),scale_x,start_x);
+ const vfloat4 start_y(node->start.y);
+ const vfloat4 scale_y(node->scale.y);
+ const vfloat4 lower_y = madd(node->dequantize<4>(ray.nearY >> 2),scale_y,start_y);
+ const vfloat4 upper_y = madd(node->dequantize<4>(ray.farY >> 2),scale_y,start_y);
+ const vfloat4 start_z(node->start.z);
+ const vfloat4 scale_z(node->scale.z);
+ const vfloat4 lower_z = madd(node->dequantize<4>(ray.nearZ >> 2),scale_z,start_z);
+ const vfloat4 upper_z = madd(node->dequantize<4>(ray.farZ >> 2),scale_z,start_z);
+
+ const vfloat4 tNearX = (lower_x - ray.org.x) * ray.rdir_near.x;
+ const vfloat4 tNearY = (lower_y - ray.org.y) * ray.rdir_near.y;
+ const vfloat4 tNearZ = (lower_z - ray.org.z) * ray.rdir_near.z;
+ const vfloat4 tFarX = (upper_x - ray.org.x) * ray.rdir_far.x;
+ const vfloat4 tFarY = (upper_y - ray.org.y) * ray.rdir_far.y;
+ const vfloat4 tFarZ = (upper_z - ray.org.z) * ray.rdir_far.z;
+
+ const vfloat4 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat4 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool4 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask & mvalid;
+ }
+
+
+#if defined(__AVX__)
+
+ template<>
+ __forceinline size_t intersectNode<8>(const typename BVH8::QuantizedBaseNode* node, const TravRay<8,false>& ray, vfloat8& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat8 start_x(node->start.x);
+ const vfloat8 scale_x(node->scale.x);
+ const vfloat8 lower_x = madd(node->dequantize<8>(ray.nearX >> 2),scale_x,start_x);
+ const vfloat8 upper_x = madd(node->dequantize<8>(ray.farX >> 2),scale_x,start_x);
+ const vfloat8 start_y(node->start.y);
+ const vfloat8 scale_y(node->scale.y);
+ const vfloat8 lower_y = madd(node->dequantize<8>(ray.nearY >> 2),scale_y,start_y);
+ const vfloat8 upper_y = madd(node->dequantize<8>(ray.farY >> 2),scale_y,start_y);
+ const vfloat8 start_z(node->start.z);
+ const vfloat8 scale_z(node->scale.z);
+ const vfloat8 lower_z = madd(node->dequantize<8>(ray.nearZ >> 2),scale_z,start_z);
+ const vfloat8 upper_z = madd(node->dequantize<8>(ray.farZ >> 2),scale_z,start_z);
+
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat8 tNearX = msub(lower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat8 tNearY = msub(lower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat8 tNearZ = msub(lower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat8 tFarX = msub(upper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat8 tFarY = msub(upper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat8 tFarZ = msub(upper_z, ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat8 tNearX = (lower_x - ray.org.x) * ray.rdir.x;
+ const vfloat8 tNearY = (lower_y - ray.org.y) * ray.rdir.y;
+ const vfloat8 tNearZ = (lower_z - ray.org.z) * ray.rdir.z;
+ const vfloat8 tFarX = (upper_x - ray.org.x) * ray.rdir.x;
+ const vfloat8 tFarY = (upper_y - ray.org.y) * ray.rdir.y;
+ const vfloat8 tFarZ = (upper_z - ray.org.z) * ray.rdir.z;
+#endif
+
+#if defined(__AVX2__) && !defined(__AVX512F__) // HSW
+ const vfloat8 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = asInt(tNear) > asInt(tFar);
+ const size_t mask = movemask(vmask) ^ ((1<<8)-1);
+#elif defined(__AVX512F__) // SKX
+ const vfloat8 tNear = maxi(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = mini(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = asInt(tNear) <= asInt(tFar);
+ const size_t mask = movemask(vmask);
+#else
+ const vfloat8 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+#endif
+ dist = tNear;
+ return mask & mvalid;
+ }
+
+ template<>
+ __forceinline size_t intersectNode<8>(const typename BVH8::QuantizedBaseNode* node, const TravRay<8,true>& ray, vfloat8& dist)
+ {
+ const size_t mvalid = movemask(node->validMask());
+ const vfloat8 start_x(node->start.x);
+ const vfloat8 scale_x(node->scale.x);
+ const vfloat8 lower_x = madd(node->dequantize<8>(ray.nearX >> 2),scale_x,start_x);
+ const vfloat8 upper_x = madd(node->dequantize<8>(ray.farX >> 2),scale_x,start_x);
+ const vfloat8 start_y(node->start.y);
+ const vfloat8 scale_y(node->scale.y);
+ const vfloat8 lower_y = madd(node->dequantize<8>(ray.nearY >> 2),scale_y,start_y);
+ const vfloat8 upper_y = madd(node->dequantize<8>(ray.farY >> 2),scale_y,start_y);
+ const vfloat8 start_z(node->start.z);
+ const vfloat8 scale_z(node->scale.z);
+ const vfloat8 lower_z = madd(node->dequantize<8>(ray.nearZ >> 2),scale_z,start_z);
+ const vfloat8 upper_z = madd(node->dequantize<8>(ray.farZ >> 2),scale_z,start_z);
+
+ const vfloat8 tNearX = (lower_x - ray.org.x) * ray.rdir_near.x;
+ const vfloat8 tNearY = (lower_y - ray.org.y) * ray.rdir_near.y;
+ const vfloat8 tNearZ = (lower_z - ray.org.z) * ray.rdir_near.z;
+ const vfloat8 tFarX = (upper_x - ray.org.x) * ray.rdir_far.x;
+ const vfloat8 tFarY = (upper_y - ray.org.y) * ray.rdir_far.y;
+ const vfloat8 tFarZ = (upper_z - ray.org.z) * ray.rdir_far.z;
+
+ const vfloat8 tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
+ const vfloat8 tFar = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
+ const vbool8 vmask = tNear <= tFar;
+ const size_t mask = movemask(vmask);
+
+ dist = tNear;
+ return mask & mvalid;
+ }
+
+
+#endif
+
+ template<int N>
+ __forceinline size_t intersectNode(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravRay<N,false>& ray, const float time, vfloat<N>& dist)
+ {
+ const vboolf<N> mvalid = node->validMask();
+ const vfloat<N> lower_x = node->dequantizeLowerX(time);
+ const vfloat<N> upper_x = node->dequantizeUpperX(time);
+ const vfloat<N> lower_y = node->dequantizeLowerY(time);
+ const vfloat<N> upper_y = node->dequantizeUpperY(time);
+ const vfloat<N> lower_z = node->dequantizeLowerZ(time);
+ const vfloat<N> upper_z = node->dequantizeUpperZ(time);
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat<N> tNearX = msub(lower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tNearY = msub(lower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tNearZ = msub(lower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat<N> tFarX = msub(upper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<N> tFarY = msub(upper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<N> tFarZ = msub(upper_z, ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat<N> tNearX = (lower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tNearY = (lower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tNearZ = (lower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<N> tFarX = (upper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<N> tFarY = (upper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<N> tFarZ = (upper_z - ray.org.z) * ray.rdir.z;
+#endif
+
+ const vfloat<N> tminX = mini(tNearX,tFarX);
+ const vfloat<N> tmaxX = maxi(tNearX,tFarX);
+ const vfloat<N> tminY = mini(tNearY,tFarY);
+ const vfloat<N> tmaxY = maxi(tNearY,tFarY);
+ const vfloat<N> tminZ = mini(tNearZ,tFarZ);
+ const vfloat<N> tmaxZ = maxi(tNearZ,tFarZ);
+ const vfloat<N> tNear = maxi(tminX,tminY,tminZ,ray.tnear);
+ const vfloat<N> tFar = mini(tmaxX,tmaxY,tmaxZ,ray.tfar);
+#if defined(__AVX512F__) // SKX
+ const vbool<N> vmask = le(mvalid,asInt(tNear),asInt(tFar));
+#else
+ const vbool<N> vmask = (asInt(tNear) <= asInt(tFar)) & mvalid;
+#endif
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ template<int N>
+ __forceinline size_t intersectNode(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravRay<N,true>& ray, const float time, vfloat<N>& dist)
+ {
+ const vboolf<N> mvalid = node->validMask();
+ const vfloat<N> lower_x = node->dequantizeLowerX(time);
+ const vfloat<N> upper_x = node->dequantizeUpperX(time);
+ const vfloat<N> lower_y = node->dequantizeLowerY(time);
+ const vfloat<N> upper_y = node->dequantizeUpperY(time);
+ const vfloat<N> lower_z = node->dequantizeLowerZ(time);
+ const vfloat<N> upper_z = node->dequantizeUpperZ(time);
+ const vfloat<N> tNearX = (lower_x - ray.org.x) * ray.rdir_near.x;
+ const vfloat<N> tNearY = (lower_y - ray.org.y) * ray.rdir_near.y;
+ const vfloat<N> tNearZ = (lower_z - ray.org.z) * ray.rdir_near.z;
+ const vfloat<N> tFarX = (upper_x - ray.org.x) * ray.rdir_far.x;
+ const vfloat<N> tFarY = (upper_y - ray.org.y) * ray.rdir_far.y;
+ const vfloat<N> tFarZ = (upper_z - ray.org.z) * ray.rdir_far.z;
+
+ const vfloat<N> tminX = mini(tNearX,tFarX);
+ const vfloat<N> tmaxX = maxi(tNearX,tFarX);
+ const vfloat<N> tminY = mini(tNearY,tFarY);
+ const vfloat<N> tmaxY = maxi(tNearY,tFarY);
+ const vfloat<N> tminZ = mini(tNearZ,tFarZ);
+ const vfloat<N> tmaxZ = maxi(tNearZ,tFarZ);
+ const vfloat<N> tNear = maxi(tminX,tminY,tminZ,ray.tnear);
+ const vfloat<N> tFar = mini(tmaxX,tmaxY,tmaxZ,ray.tfar);
+#if defined(__AVX512F__) // SKX
+ const vbool<N> vmask = le(mvalid,asInt(tNear),asInt(tFar));
+#else
+ const vbool<N> vmask = (asInt(tNear) <= asInt(tFar)) & mvalid;
+#endif
+ const size_t mask = movemask(vmask);
+ dist = tNear;
+ return mask;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast OBBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, bool robust>
+ __forceinline size_t intersectNode(const typename BVHN<N>::OBBNode* node, const TravRay<N,robust>& ray, vfloat<N>& dist)
+ {
+ const Vec3vf<N> dir = xfmVector(node->naabb,ray.dir);
+ //const Vec3vf<N> nrdir = Vec3vf<N>(vfloat<N>(-1.0f))/dir;
+ const Vec3vf<N> nrdir = Vec3vf<N>(vfloat<N>(-1.0f))*rcp_safe(dir);
+ const Vec3vf<N> org = xfmPoint(node->naabb,ray.org);
+ const Vec3vf<N> tLowerXYZ = org * nrdir; // (Vec3fa(zero) - org) * rdir;
+ const Vec3vf<N> tUpperXYZ = tLowerXYZ - nrdir; // (Vec3fa(one ) - org) * rdir;
+
+ const vfloat<N> tNearX = mini(tLowerXYZ.x,tUpperXYZ.x);
+ const vfloat<N> tNearY = mini(tLowerXYZ.y,tUpperXYZ.y);
+ const vfloat<N> tNearZ = mini(tLowerXYZ.z,tUpperXYZ.z);
+ const vfloat<N> tFarX = maxi(tLowerXYZ.x,tUpperXYZ.x);
+ const vfloat<N> tFarY = maxi(tLowerXYZ.y,tUpperXYZ.y);
+ const vfloat<N> tFarZ = maxi(tLowerXYZ.z,tUpperXYZ.z);
+ vfloat<N> tNear = max(ray.tnear, tNearX,tNearY,tNearZ);
+ vfloat<N> tFar = min(ray.tfar, tFarX ,tFarY ,tFarZ );
+ if (robust) {
+ tNear = tNear*vfloat<N>(1.0f-3.0f*float(ulp));
+ tFar = tFar *vfloat<N>(1.0f+3.0f*float(ulp));
+ }
+ const vbool<N> vmask = tNear <= tFar;
+ dist = tNear;
+ return movemask(vmask);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast OBBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, bool robust>
+ __forceinline size_t intersectNode(const typename BVHN<N>::OBBNodeMB* node, const TravRay<N,robust>& ray, const float time, vfloat<N>& dist)
+ {
+ const AffineSpace3vf<N> xfm = node->space0;
+ const Vec3vf<N> b0_lower = zero;
+ const Vec3vf<N> b0_upper = one;
+ const Vec3vf<N> lower = lerp(b0_lower,node->b1.lower,vfloat<N>(time));
+ const Vec3vf<N> upper = lerp(b0_upper,node->b1.upper,vfloat<N>(time));
+
+ const BBox3vf<N> bounds(lower,upper);
+ const Vec3vf<N> dir = xfmVector(xfm,ray.dir);
+ const Vec3vf<N> rdir = rcp_safe(dir);
+ const Vec3vf<N> org = xfmPoint(xfm,ray.org);
+
+ const Vec3vf<N> tLowerXYZ = (bounds.lower - org) * rdir;
+ const Vec3vf<N> tUpperXYZ = (bounds.upper - org) * rdir;
+
+ const vfloat<N> tNearX = mini(tLowerXYZ.x,tUpperXYZ.x);
+ const vfloat<N> tNearY = mini(tLowerXYZ.y,tUpperXYZ.y);
+ const vfloat<N> tNearZ = mini(tLowerXYZ.z,tUpperXYZ.z);
+ const vfloat<N> tFarX = maxi(tLowerXYZ.x,tUpperXYZ.x);
+ const vfloat<N> tFarY = maxi(tLowerXYZ.y,tUpperXYZ.y);
+ const vfloat<N> tFarZ = maxi(tLowerXYZ.z,tUpperXYZ.z);
+ vfloat<N> tNear = max(ray.tnear, tNearX,tNearY,tNearZ);
+ vfloat<N> tFar = min(ray.tfar, tFarX ,tFarY ,tFarZ );
+ if (robust) {
+ tNear = tNear*vfloat<N>(1.0f-3.0f*float(ulp));
+ tFar = tFar *vfloat<N>(1.0f+3.0f*float(ulp));
+ }
+ const vbool<N> vmask = tNear <= tFar;
+ dist = tNear;
+ return movemask(vmask);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Node intersectors used in point query raversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /*! Computes traversal information for N nodes with 1 point query */
+ template<int N, int types>
+ struct BVHNNodePointQuerySphere1;
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeSphere(node.getAABBNode(), query, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeSphere(node.getAABBNodeMB(), query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN2_AN4D>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeSphereMB4D<N>(node, query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN1_UN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNode())) mask = pointQueryNodeSphere(node.getAABBNode(), query, dist);
+ else if (unlikely(node.isOBBNode())) mask = pointQueryNodeSphere(node.ungetAABBNode(), query, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN2_UN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNodeMB())) mask = pointQueryNodeSphere(node.getAABBNodeMB(), query, time, dist);
+ else if (unlikely(node.isOBBNodeMB())) mask = pointQueryNodeSphere(node.ungetAABBNodeMB(), query, time, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_AN2_AN4D_UN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ if (unlikely(node.isOBBNodeMB())) mask = pointQueryNodeSphere(node.ungetAABBNodeMB(), query, time, dist);
+ else mask = pointQueryNodeSphereMB4D(node, query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQuerySphere1<N, BVH_QN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeSphere((const typename BVHN<N>::QuantizedNode*)node.quantizedNode(), query, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNQuantizedBaseNodePointQuerySphere1
+ {
+ static __forceinline size_t pointQuery(const typename BVHN<N>::QuantizedBaseNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ return pointQueryNodeSphere(node,query,dist);
+ }
+
+ static __forceinline size_t pointQuery(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ return pointQueryNodeSphere(node,query,time,dist);
+ }
+ };
+
+ /*! Computes traversal information for N nodes with 1 point query */
+ template<int N, int types>
+ struct BVHNNodePointQueryAABB1;
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeAABB(node.getAABBNode(), query, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeAABB(node.getAABBNodeMB(), query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN2_AN4D>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeAABBMB4D<N>(node, query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN1_UN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNode())) mask = pointQueryNodeAABB(node.getAABBNode(), query, dist);
+ else if (unlikely(node.isOBBNode())) mask = pointQueryNodeAABB(node.ungetAABBNode(), query, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN2_UN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNodeMB())) mask = pointQueryNodeAABB(node.getAABBNodeMB(), query, time, dist);
+ else if (unlikely(node.isOBBNodeMB())) mask = pointQueryNodeAABB(node.ungetAABBNodeMB(), query, time, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_AN2_AN4D_UN2>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ if (unlikely(node.isOBBNodeMB())) mask = pointQueryNodeAABB(node.ungetAABBNodeMB(), query, time, dist);
+ else mask = pointQueryNodeAABBMB4D(node, query, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodePointQueryAABB1<N, BVH_QN1>
+ {
+ static __forceinline bool pointQuery(const typename BVHN<N>::NodeRef& node, const TravPointQuery<N>& query, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = pointQueryNodeAABB((const typename BVHN<N>::QuantizedNode*)node.quantizedNode(), query, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNQuantizedBaseNodePointQueryAABB1
+ {
+ static __forceinline size_t pointQuery(const typename BVHN<N>::QuantizedBaseNode* node, const TravPointQuery<N>& query, vfloat<N>& dist)
+ {
+ return pointQueryNodeAABB(node,query,dist);
+ }
+
+ static __forceinline size_t pointQuery(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravPointQuery<N>& query, const float time, vfloat<N>& dist)
+ {
+ return pointQueryNodeAABB(node,query,time,dist);
+ }
+ };
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Node intersectors used in ray traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /*! Intersects N nodes with 1 ray */
+ template<int N, int types, bool robust>
+ struct BVHNNodeIntersector1;
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN1, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,false>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNode(node.getAABBNode(), ray, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN1, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,true>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNodeRobust(node.getAABBNode(), ray, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,false>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNode(node.getAABBNodeMB(), ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,true>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNodeRobust(node.getAABBNodeMB(), ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN2_AN4D, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,false>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNodeMB4D<N>(node, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN2_AN4D, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,true>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNodeMB4DRobust<N>(node, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN1_UN1, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,false>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNode())) mask = intersectNode(node.getAABBNode(), ray, dist);
+ else if (unlikely(node.isOBBNode())) mask = intersectNode(node.ungetAABBNode(), ray, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN1_UN1, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,true>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNode())) mask = intersectNodeRobust(node.getAABBNode(), ray, dist);
+ else if (unlikely(node.isOBBNode())) mask = intersectNode(node.ungetAABBNode(), ray, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN2_UN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,false>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNodeMB())) mask = intersectNode(node.getAABBNodeMB(), ray, time, dist);
+ else if (unlikely(node.isOBBNodeMB())) mask = intersectNode(node.ungetAABBNodeMB(), ray, time, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN2_UN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,true>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (likely(node.isAABBNodeMB())) mask = intersectNodeRobust(node.getAABBNodeMB(), ray, time, dist);
+ else if (unlikely(node.isOBBNodeMB())) mask = intersectNode(node.ungetAABBNodeMB(), ray, time, dist);
+ else return false;
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN2_AN4D_UN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,false>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ if (unlikely(node.isOBBNodeMB())) mask = intersectNode(node.ungetAABBNodeMB(), ray, time, dist);
+ else mask = intersectNodeMB4D(node, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_AN2_AN4D_UN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,true>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ if (unlikely(node.isOBBNodeMB())) mask = intersectNode(node.ungetAABBNodeMB(), ray, time, dist);
+ else mask = intersectNodeMB4DRobust(node, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_QN1, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,false>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNode((const typename BVHN<N>::QuantizedNode*)node.quantizedNode(), ray, dist);
+ return true;
+ }
+ };
+
+ template<int N>
+ struct BVHNNodeIntersector1<N, BVH_QN1, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, const TravRay<N,true>& ray, float time, vfloat<N>& dist, size_t& mask)
+ {
+ if (unlikely(node.isLeaf())) return false;
+ mask = intersectNodeRobust((const typename BVHN<N>::QuantizedNode*)node.quantizedNode(), ray, dist);
+ return true;
+ }
+ };
+
+ /*! Intersects N nodes with K rays */
+ template<int N, bool robust>
+ struct BVHNQuantizedBaseNodeIntersector1;
+
+ template<int N>
+ struct BVHNQuantizedBaseNodeIntersector1<N, false>
+ {
+ static __forceinline size_t intersect(const typename BVHN<N>::QuantizedBaseNode* node, const TravRay<N,false>& ray, vfloat<N>& dist)
+ {
+ return intersectNode(node,ray,dist);
+ }
+
+ static __forceinline size_t intersect(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravRay<N,false>& ray, const float time, vfloat<N>& dist)
+ {
+ return intersectNode(node,ray,time,dist);
+ }
+
+ };
+
+ template<int N>
+ struct BVHNQuantizedBaseNodeIntersector1<N, true>
+ {
+ static __forceinline size_t intersect(const typename BVHN<N>::QuantizedBaseNode* node, const TravRay<N,true>& ray, vfloat<N>& dist)
+ {
+ return intersectNode(node,ray,dist);
+ }
+
+ static __forceinline size_t intersect(const typename BVHN<N>::QuantizedBaseNodeMB* node, const TravRay<N,true>& ray, const float time, vfloat<N>& dist)
+ {
+ return intersectNode(node,ray,time,dist);
+ }
+
+ };
+
+
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/node_intersector_frustum.h b/thirdparty/embree/kernels/bvh/node_intersector_frustum.h
new file mode 100644
index 0000000000..1f7215e5df
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/node_intersector_frustum.h
@@ -0,0 +1,241 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "node_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Frustum structure used in hybrid and stream traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /*
+ Optimized frustum test. We calculate t=(p-org)/dir in ray/box
+ intersection. We assume the rays are split by octant, thus
+ dir intervals are either positive or negative in each
+ dimension.
+
+ Case 1: dir.min >= 0 && dir.max >= 0:
+ t_min = (p_min - org_max) / dir_max = (p_min - org_max)*rdir_min = p_min*rdir_min - org_max*rdir_min
+ t_max = (p_max - org_min) / dir_min = (p_max - org_min)*rdir_max = p_max*rdir_max - org_min*rdir_max
+
+ Case 2: dir.min < 0 && dir.max < 0:
+ t_min = (p_max - org_min) / dir_min = (p_max - org_min)*rdir_max = p_max*rdir_max - org_min*rdir_max
+ t_max = (p_min - org_max) / dir_max = (p_min - org_max)*rdir_min = p_min*rdir_min - org_max*rdir_min
+ */
+
+ template<bool robust>
+ struct Frustum;
+
+ /* Fast variant */
+ template<>
+ struct Frustum<false>
+ {
+ __forceinline Frustum() {}
+
+ template<int K>
+ __forceinline void init(const vbool<K>& valid, const Vec3vf<K>& org, const Vec3vf<K>& rdir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar, int N)
+ {
+ const Vec3fa reduced_min_org(reduce_min(select(valid, org.x, pos_inf)),
+ reduce_min(select(valid, org.y, pos_inf)),
+ reduce_min(select(valid, org.z, pos_inf)));
+
+ const Vec3fa reduced_max_org(reduce_max(select(valid, org.x, neg_inf)),
+ reduce_max(select(valid, org.y, neg_inf)),
+ reduce_max(select(valid, org.z, neg_inf)));
+
+ const Vec3fa reduced_min_rdir(reduce_min(select(valid, rdir.x, pos_inf)),
+ reduce_min(select(valid, rdir.y, pos_inf)),
+ reduce_min(select(valid, rdir.z, pos_inf)));
+
+ const Vec3fa reduced_max_rdir(reduce_max(select(valid, rdir.x, neg_inf)),
+ reduce_max(select(valid, rdir.y, neg_inf)),
+ reduce_max(select(valid, rdir.z, neg_inf)));
+
+ const float reduced_min_dist = reduce_min(select(valid, ray_tnear, vfloat<K>(pos_inf)));
+ const float reduced_max_dist = reduce_max(select(valid, ray_tfar , vfloat<K>(neg_inf)));
+
+ init(reduced_min_org, reduced_max_org, reduced_min_rdir, reduced_max_rdir, reduced_min_dist, reduced_max_dist, N);
+ }
+
+ __forceinline void init(const Vec3fa& reduced_min_org,
+ const Vec3fa& reduced_max_org,
+ const Vec3fa& reduced_min_rdir,
+ const Vec3fa& reduced_max_rdir,
+ float reduced_min_dist,
+ float reduced_max_dist,
+ int N)
+ {
+ const Vec3ba pos_rdir = ge_mask(reduced_min_rdir, Vec3fa(zero));
+
+ min_rdir = select(pos_rdir, reduced_min_rdir, reduced_max_rdir);
+ max_rdir = select(pos_rdir, reduced_max_rdir, reduced_min_rdir);
+
+ min_org_rdir = min_rdir * select(pos_rdir, reduced_max_org, reduced_min_org);
+ max_org_rdir = max_rdir * select(pos_rdir, reduced_min_org, reduced_max_org);
+
+ min_dist = reduced_min_dist;
+ max_dist = reduced_max_dist;
+
+ nf = NearFarPrecalculations(min_rdir, N);
+ }
+
+ template<int K>
+ __forceinline void updateMaxDist(const vfloat<K>& ray_tfar)
+ {
+ max_dist = reduce_max(ray_tfar);
+ }
+
+ NearFarPrecalculations nf;
+
+ Vec3fa min_rdir;
+ Vec3fa max_rdir;
+
+ Vec3fa min_org_rdir;
+ Vec3fa max_org_rdir;
+
+ float min_dist;
+ float max_dist;
+ };
+
+ typedef Frustum<false> FrustumFast;
+
+ /* Robust variant */
+ template<>
+ struct Frustum<true>
+ {
+ __forceinline Frustum() {}
+
+ template<int K>
+ __forceinline void init(const vbool<K>& valid, const Vec3vf<K>& org, const Vec3vf<K>& rdir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar, int N)
+ {
+ const Vec3fa reduced_min_org(reduce_min(select(valid, org.x, pos_inf)),
+ reduce_min(select(valid, org.y, pos_inf)),
+ reduce_min(select(valid, org.z, pos_inf)));
+
+ const Vec3fa reduced_max_org(reduce_max(select(valid, org.x, neg_inf)),
+ reduce_max(select(valid, org.y, neg_inf)),
+ reduce_max(select(valid, org.z, neg_inf)));
+
+ const Vec3fa reduced_min_rdir(reduce_min(select(valid, rdir.x, pos_inf)),
+ reduce_min(select(valid, rdir.y, pos_inf)),
+ reduce_min(select(valid, rdir.z, pos_inf)));
+
+ const Vec3fa reduced_max_rdir(reduce_max(select(valid, rdir.x, neg_inf)),
+ reduce_max(select(valid, rdir.y, neg_inf)),
+ reduce_max(select(valid, rdir.z, neg_inf)));
+
+ const float reduced_min_dist = reduce_min(select(valid, ray_tnear, vfloat<K>(pos_inf)));
+ const float reduced_max_dist = reduce_max(select(valid, ray_tfar , vfloat<K>(neg_inf)));
+
+ init(reduced_min_org, reduced_max_org, reduced_min_rdir, reduced_max_rdir, reduced_min_dist, reduced_max_dist, N);
+ }
+
+ __forceinline void init(const Vec3fa& reduced_min_org,
+ const Vec3fa& reduced_max_org,
+ const Vec3fa& reduced_min_rdir,
+ const Vec3fa& reduced_max_rdir,
+ float reduced_min_dist,
+ float reduced_max_dist,
+ int N)
+ {
+ const Vec3ba pos_rdir = ge_mask(reduced_min_rdir, Vec3fa(zero));
+ min_rdir = select(pos_rdir, reduced_min_rdir, reduced_max_rdir);
+ max_rdir = select(pos_rdir, reduced_max_rdir, reduced_min_rdir);
+
+ min_org = select(pos_rdir, reduced_max_org, reduced_min_org);
+ max_org = select(pos_rdir, reduced_min_org, reduced_max_org);
+
+ min_dist = reduced_min_dist;
+ max_dist = reduced_max_dist;
+
+ nf = NearFarPrecalculations(min_rdir, N);
+ }
+
+ template<int K>
+ __forceinline void updateMaxDist(const vfloat<K>& ray_tfar)
+ {
+ max_dist = reduce_max(ray_tfar);
+ }
+
+ NearFarPrecalculations nf;
+
+ Vec3fa min_rdir;
+ Vec3fa max_rdir;
+
+ Vec3fa min_org;
+ Vec3fa max_org;
+
+ float min_dist;
+ float max_dist;
+ };
+
+ typedef Frustum<true> FrustumRobust;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNodeFrustum(const typename BVHN<N>::AABBNode* __restrict__ node,
+ const FrustumFast& frustum, vfloat<N>& dist)
+ {
+ const vfloat<N> bminX = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearX);
+ const vfloat<N> bminY = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearY);
+ const vfloat<N> bminZ = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearZ);
+ const vfloat<N> bmaxX = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farX);
+ const vfloat<N> bmaxY = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farY);
+ const vfloat<N> bmaxZ = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farZ);
+
+ const vfloat<N> fminX = msub(bminX, vfloat<N>(frustum.min_rdir.x), vfloat<N>(frustum.min_org_rdir.x));
+ const vfloat<N> fminY = msub(bminY, vfloat<N>(frustum.min_rdir.y), vfloat<N>(frustum.min_org_rdir.y));
+ const vfloat<N> fminZ = msub(bminZ, vfloat<N>(frustum.min_rdir.z), vfloat<N>(frustum.min_org_rdir.z));
+ const vfloat<N> fmaxX = msub(bmaxX, vfloat<N>(frustum.max_rdir.x), vfloat<N>(frustum.max_org_rdir.x));
+ const vfloat<N> fmaxY = msub(bmaxY, vfloat<N>(frustum.max_rdir.y), vfloat<N>(frustum.max_org_rdir.y));
+ const vfloat<N> fmaxZ = msub(bmaxZ, vfloat<N>(frustum.max_rdir.z), vfloat<N>(frustum.max_org_rdir.z));
+
+ const vfloat<N> fmin = maxi(fminX, fminY, fminZ, vfloat<N>(frustum.min_dist));
+ dist = fmin;
+ const vfloat<N> fmax = mini(fmaxX, fmaxY, fmaxZ, vfloat<N>(frustum.max_dist));
+ const vbool<N> vmask_node_hit = fmin <= fmax;
+ size_t m_node = movemask(vmask_node_hit) & (((size_t)1 << N)-1);
+ return m_node;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N>
+ __forceinline size_t intersectNodeFrustum(const typename BVHN<N>::AABBNode* __restrict__ node,
+ const FrustumRobust& frustum, vfloat<N>& dist)
+ {
+ const vfloat<N> bminX = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearX);
+ const vfloat<N> bminY = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearY);
+ const vfloat<N> bminZ = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.nearZ);
+ const vfloat<N> bmaxX = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farX);
+ const vfloat<N> bmaxY = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farY);
+ const vfloat<N> bmaxZ = *(const vfloat<N>*)((const char*)&node->lower_x + frustum.nf.farZ);
+
+ const vfloat<N> fminX = (bminX - vfloat<N>(frustum.min_org.x)) * vfloat<N>(frustum.min_rdir.x);
+ const vfloat<N> fminY = (bminY - vfloat<N>(frustum.min_org.y)) * vfloat<N>(frustum.min_rdir.y);
+ const vfloat<N> fminZ = (bminZ - vfloat<N>(frustum.min_org.z)) * vfloat<N>(frustum.min_rdir.z);
+ const vfloat<N> fmaxX = (bmaxX - vfloat<N>(frustum.max_org.x)) * vfloat<N>(frustum.max_rdir.x);
+ const vfloat<N> fmaxY = (bmaxY - vfloat<N>(frustum.max_org.y)) * vfloat<N>(frustum.max_rdir.y);
+ const vfloat<N> fmaxZ = (bmaxZ - vfloat<N>(frustum.max_org.z)) * vfloat<N>(frustum.max_rdir.z);
+
+ const float round_down = 1.0f-2.0f*float(ulp); // FIXME: use per instruction rounding for AVX512
+ const float round_up = 1.0f+2.0f*float(ulp);
+ const vfloat<N> fmin = max(fminX, fminY, fminZ, vfloat<N>(frustum.min_dist));
+ dist = fmin;
+ const vfloat<N> fmax = min(fmaxX, fmaxY, fmaxZ, vfloat<N>(frustum.max_dist));
+ const vbool<N> vmask_node_hit = (round_down*fmin <= round_up*fmax);
+ size_t m_node = movemask(vmask_node_hit) & (((size_t)1 << N)-1);
+ return m_node;
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/node_intersector_packet.h b/thirdparty/embree/kernels/bvh/node_intersector_packet.h
new file mode 100644
index 0000000000..d5498fc5db
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/node_intersector_packet.h
@@ -0,0 +1,805 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "node_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Ray packet structure used in hybrid traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int K, bool robust>
+ struct TravRayK;
+
+ /* Fast variant */
+ template<int K>
+ struct TravRayK<K, false>
+ {
+ __forceinline TravRayK() {}
+
+ __forceinline TravRayK(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, int N)
+ {
+ init(ray_org, ray_dir, N);
+ }
+
+ __forceinline TravRayK(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar, int N)
+ {
+ init(ray_org, ray_dir, N);
+ tnear = ray_tnear;
+ tfar = ray_tfar;
+ }
+
+ __forceinline void init(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, int N)
+ {
+ org = ray_org;
+ dir = ray_dir;
+ rdir = rcp_safe(ray_dir);
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ org_rdir = org * rdir;
+#endif
+
+ if (N)
+ {
+ const int size = sizeof(float)*N;
+ nearXYZ.x = select(rdir.x >= 0.0f, vint<K>(0*size), vint<K>(1*size));
+ nearXYZ.y = select(rdir.y >= 0.0f, vint<K>(2*size), vint<K>(3*size));
+ nearXYZ.z = select(rdir.z >= 0.0f, vint<K>(4*size), vint<K>(5*size));
+ }
+ }
+
+ Vec3vf<K> org;
+ Vec3vf<K> dir;
+ Vec3vf<K> rdir;
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ Vec3vf<K> org_rdir;
+#endif
+ Vec3vi<K> nearXYZ;
+ vfloat<K> tnear;
+ vfloat<K> tfar;
+ };
+
+ template<int K>
+ using TravRayKFast = TravRayK<K, false>;
+
+ /* Robust variant */
+ template<int K>
+ struct TravRayK<K, true>
+ {
+ __forceinline TravRayK() {}
+
+ __forceinline TravRayK(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, int N)
+ {
+ init(ray_org, ray_dir, N);
+ }
+
+ __forceinline TravRayK(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar, int N)
+ {
+ init(ray_org, ray_dir, N);
+ tnear = ray_tnear;
+ tfar = ray_tfar;
+ }
+
+ __forceinline void init(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, int N)
+ {
+ org = ray_org;
+ dir = ray_dir;
+ rdir = vfloat<K>(1.0f)/(zero_fix(ray_dir));
+
+ if (N)
+ {
+ const int size = sizeof(float)*N;
+ nearXYZ.x = select(rdir.x >= 0.0f, vint<K>(0*size), vint<K>(1*size));
+ nearXYZ.y = select(rdir.y >= 0.0f, vint<K>(2*size), vint<K>(3*size));
+ nearXYZ.z = select(rdir.z >= 0.0f, vint<K>(4*size), vint<K>(5*size));
+ }
+ }
+
+ Vec3vf<K> org;
+ Vec3vf<K> dir;
+ Vec3vf<K> rdir;
+ Vec3vi<K> nearXYZ;
+ vfloat<K> tnear;
+ vfloat<K> tfar;
+ };
+
+ template<int K>
+ using TravRayKRobust = TravRayK<K, true>;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeK(const typename BVHN<N>::AABBNode* node, size_t i,
+ const TravRayKFast<K>& ray, vfloat<K>& dist)
+
+ {
+ #if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat<K> lclipMinX = msub(node->lower_x[i], ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMinY = msub(node->lower_y[i], ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMinZ = msub(node->lower_z[i], ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> lclipMaxX = msub(node->upper_x[i], ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMaxY = msub(node->upper_y[i], ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMaxZ = msub(node->upper_z[i], ray.rdir.z, ray.org_rdir.z);
+ #else
+ const vfloat<K> lclipMinX = (node->lower_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (node->lower_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (node->lower_z[i] - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (node->upper_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (node->upper_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (node->upper_z[i] - ray.org.z) * ray.rdir.z;
+ #endif
+
+ #if defined(__AVX512F__) // SKX
+ if (K == 16)
+ {
+ /* use mixed float/int min/max */
+ const vfloat<K> lnearP = maxi(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+ dist = lnearP;
+ return lhit;
+ }
+ else
+ #endif
+ {
+ const vfloat<K> lnearP = maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+ #if defined(__AVX512F__) // SKX
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+ #else
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ #endif
+ dist = lnearP;
+ return lhit;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeKRobust(const typename BVHN<N>::AABBNode* node, size_t i,
+ const TravRayKRobust<K>& ray, vfloat<K>& dist)
+ {
+ // FIXME: use per instruction rounding for AVX512
+ const vfloat<K> lclipMinX = (node->lower_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (node->lower_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (node->lower_z[i] - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (node->upper_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (node->upper_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (node->upper_z[i] - ray.org.z) * ray.rdir.z;
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const float round_down = 1.0f-3.0f*float(ulp);
+ const vfloat<K> lnearP = round_down*max(max(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY)), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *min(min(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY)), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = max(lnearP, ray.tnear) <= min(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeK(const typename BVHN<N>::AABBNodeMB* node, const size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ const vfloat<K> vlower_x = madd(time, vfloat<K>(node->lower_dx[i]), vfloat<K>(node->lower_x[i]));
+ const vfloat<K> vlower_y = madd(time, vfloat<K>(node->lower_dy[i]), vfloat<K>(node->lower_y[i]));
+ const vfloat<K> vlower_z = madd(time, vfloat<K>(node->lower_dz[i]), vfloat<K>(node->lower_z[i]));
+ const vfloat<K> vupper_x = madd(time, vfloat<K>(node->upper_dx[i]), vfloat<K>(node->upper_x[i]));
+ const vfloat<K> vupper_y = madd(time, vfloat<K>(node->upper_dy[i]), vfloat<K>(node->upper_y[i]));
+ const vfloat<K> vupper_z = madd(time, vfloat<K>(node->upper_dz[i]), vfloat<K>(node->upper_z[i]));
+
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat<K> lclipMinX = msub(vlower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMinY = msub(vlower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMinZ = msub(vlower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> lclipMaxX = msub(vupper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMaxY = msub(vupper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMaxZ = msub(vupper_z, ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat<K> lclipMinX = (vlower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (vlower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (vlower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (vupper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (vupper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (vupper_z - ray.org.z) * ray.rdir.z;
+#endif
+
+#if defined(__AVX512F__) // SKX
+ if (K == 16)
+ {
+ /* use mixed float/int min/max */
+ const vfloat<K> lnearP = maxi(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+ dist = lnearP;
+ return lhit;
+ }
+ else
+#endif
+ {
+ const vfloat<K> lnearP = maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+#if defined(__AVX512F__) // SKX
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+#else
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+#endif
+ dist = lnearP;
+ return lhit;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeKRobust(const typename BVHN<N>::AABBNodeMB* node, const size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ const vfloat<K> vlower_x = madd(time, vfloat<K>(node->lower_dx[i]), vfloat<K>(node->lower_x[i]));
+ const vfloat<K> vlower_y = madd(time, vfloat<K>(node->lower_dy[i]), vfloat<K>(node->lower_y[i]));
+ const vfloat<K> vlower_z = madd(time, vfloat<K>(node->lower_dz[i]), vfloat<K>(node->lower_z[i]));
+ const vfloat<K> vupper_x = madd(time, vfloat<K>(node->upper_dx[i]), vfloat<K>(node->upper_x[i]));
+ const vfloat<K> vupper_y = madd(time, vfloat<K>(node->upper_dy[i]), vfloat<K>(node->upper_y[i]));
+ const vfloat<K> vupper_z = madd(time, vfloat<K>(node->upper_dz[i]), vfloat<K>(node->upper_z[i]));
+
+ const vfloat<K> lclipMinX = (vlower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (vlower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (vlower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (vupper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (vupper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (vupper_z - ray.org.z) * ray.rdir.z;
+
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const float round_down = 1.0f-3.0f*float(ulp);
+
+#if defined(__AVX512F__) // SKX
+ if (K == 16)
+ {
+ const vfloat<K> lnearP = round_down*maxi(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *mini(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+ else
+#endif
+ {
+ const vfloat<K> lnearP = round_down*maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNodeMB4D intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeKMB4D(const typename BVHN<N>::NodeRef ref, const size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+
+ const vfloat<K> vlower_x = madd(time, vfloat<K>(node->lower_dx[i]), vfloat<K>(node->lower_x[i]));
+ const vfloat<K> vlower_y = madd(time, vfloat<K>(node->lower_dy[i]), vfloat<K>(node->lower_y[i]));
+ const vfloat<K> vlower_z = madd(time, vfloat<K>(node->lower_dz[i]), vfloat<K>(node->lower_z[i]));
+ const vfloat<K> vupper_x = madd(time, vfloat<K>(node->upper_dx[i]), vfloat<K>(node->upper_x[i]));
+ const vfloat<K> vupper_y = madd(time, vfloat<K>(node->upper_dy[i]), vfloat<K>(node->upper_y[i]));
+ const vfloat<K> vupper_z = madd(time, vfloat<K>(node->upper_dz[i]), vfloat<K>(node->upper_z[i]));
+
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat<K> lclipMinX = msub(vlower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMinY = msub(vlower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMinZ = msub(vlower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> lclipMaxX = msub(vupper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMaxY = msub(vupper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMaxZ = msub(vupper_z, ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat<K> lclipMinX = (vlower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (vlower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (vlower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (vupper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (vupper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (vupper_z - ray.org.z) * ray.rdir.z;
+#endif
+
+ const vfloat<K> lnearP = maxi(maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY)), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY)), maxi(lclipMinZ, lclipMaxZ));
+ vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ lhit = lhit & (vfloat<K>(node1->lower_t[i]) <= time) & (time < vfloat<K>(node1->upper_t[i]));
+ }
+ dist = lnearP;
+ return lhit;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNodeMB4D intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectNodeKMB4DRobust(const typename BVHN<N>::NodeRef ref, const size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ const typename BVHN<N>::AABBNodeMB* node = ref.getAABBNodeMB();
+
+ const vfloat<K> vlower_x = madd(time, vfloat<K>(node->lower_dx[i]), vfloat<K>(node->lower_x[i]));
+ const vfloat<K> vlower_y = madd(time, vfloat<K>(node->lower_dy[i]), vfloat<K>(node->lower_y[i]));
+ const vfloat<K> vlower_z = madd(time, vfloat<K>(node->lower_dz[i]), vfloat<K>(node->lower_z[i]));
+ const vfloat<K> vupper_x = madd(time, vfloat<K>(node->upper_dx[i]), vfloat<K>(node->upper_x[i]));
+ const vfloat<K> vupper_y = madd(time, vfloat<K>(node->upper_dy[i]), vfloat<K>(node->upper_y[i]));
+ const vfloat<K> vupper_z = madd(time, vfloat<K>(node->upper_dz[i]), vfloat<K>(node->upper_z[i]));
+
+ const vfloat<K> lclipMinX = (vlower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (vlower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (vlower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (vupper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (vupper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (vupper_z - ray.org.z) * ray.rdir.z;
+
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const float round_down = 1.0f-3.0f*float(ulp);
+ const vfloat<K> lnearP = round_down*maxi(maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY)), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *mini(mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY)), maxi(lclipMinZ, lclipMaxZ));
+ vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+
+ if (unlikely(ref.isAABBNodeMB4D())) {
+ const typename BVHN<N>::AABBNodeMB4D* node1 = (const typename BVHN<N>::AABBNodeMB4D*) node;
+ lhit = lhit & (vfloat<K>(node1->lower_t[i]) <= time) & (time < vfloat<K>(node1->upper_t[i]));
+ }
+ dist = lnearP;
+ return lhit;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast OBBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K, bool robust>
+ __forceinline vbool<K> intersectNodeK(const typename BVHN<N>::OBBNode* node, const size_t i,
+ const TravRayK<K,robust>& ray, vfloat<K>& dist)
+ {
+ const AffineSpace3vf<K> naabb(Vec3f(node->naabb.l.vx.x[i], node->naabb.l.vx.y[i], node->naabb.l.vx.z[i]),
+ Vec3f(node->naabb.l.vy.x[i], node->naabb.l.vy.y[i], node->naabb.l.vy.z[i]),
+ Vec3f(node->naabb.l.vz.x[i], node->naabb.l.vz.y[i], node->naabb.l.vz.z[i]),
+ Vec3f(node->naabb.p .x[i], node->naabb.p .y[i], node->naabb.p .z[i]));
+
+ const Vec3vf<K> dir = xfmVector(naabb, ray.dir);
+ const Vec3vf<K> nrdir = Vec3vf<K>(vfloat<K>(-1.0f)) * rcp_safe(dir); // FIXME: negate instead of mul with -1?
+ const Vec3vf<K> org = xfmPoint(naabb, ray.org);
+
+ const vfloat<K> lclipMinX = org.x * nrdir.x; // (Vec3fa(zero) - org) * rdir;
+ const vfloat<K> lclipMinY = org.y * nrdir.y;
+ const vfloat<K> lclipMinZ = org.z * nrdir.z;
+ const vfloat<K> lclipMaxX = lclipMinX - nrdir.x; // (Vec3fa(one) - org) * rdir;
+ const vfloat<K> lclipMaxY = lclipMinY - nrdir.y;
+ const vfloat<K> lclipMaxZ = lclipMinZ - nrdir.z;
+
+ vfloat<K> lnearP = maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ vfloat<K> lfarP = mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+ if (robust) {
+ lnearP = lnearP*vfloat<K>(1.0f-3.0f*float(ulp));
+ lfarP = lfarP *vfloat<K>(1.0f+3.0f*float(ulp));
+ }
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast OBBNodeMB intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K, bool robust>
+ __forceinline vbool<K> intersectNodeK(const typename BVHN<N>::OBBNodeMB* node, const size_t i,
+ const TravRayK<K,robust>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ const AffineSpace3vf<K> xfm(Vec3f(node->space0.l.vx.x[i], node->space0.l.vx.y[i], node->space0.l.vx.z[i]),
+ Vec3f(node->space0.l.vy.x[i], node->space0.l.vy.y[i], node->space0.l.vy.z[i]),
+ Vec3f(node->space0.l.vz.x[i], node->space0.l.vz.y[i], node->space0.l.vz.z[i]),
+ Vec3f(node->space0.p .x[i], node->space0.p .y[i], node->space0.p .z[i]));
+
+ const Vec3vf<K> b0_lower = zero;
+ const Vec3vf<K> b0_upper = one;
+ const Vec3vf<K> b1_lower(node->b1.lower.x[i], node->b1.lower.y[i], node->b1.lower.z[i]);
+ const Vec3vf<K> b1_upper(node->b1.upper.x[i], node->b1.upper.y[i], node->b1.upper.z[i]);
+ const Vec3vf<K> lower = lerp(b0_lower, b1_lower, time);
+ const Vec3vf<K> upper = lerp(b0_upper, b1_upper, time);
+
+ const Vec3vf<K> dir = xfmVector(xfm, ray.dir);
+ const Vec3vf<K> rdir = rcp_safe(dir);
+ const Vec3vf<K> org = xfmPoint(xfm, ray.org);
+
+ const vfloat<K> lclipMinX = (lower.x - org.x) * rdir.x;
+ const vfloat<K> lclipMinY = (lower.y - org.y) * rdir.y;
+ const vfloat<K> lclipMinZ = (lower.z - org.z) * rdir.z;
+ const vfloat<K> lclipMaxX = (upper.x - org.x) * rdir.x;
+ const vfloat<K> lclipMaxY = (upper.y - org.y) * rdir.y;
+ const vfloat<K> lclipMaxZ = (upper.z - org.z) * rdir.z;
+
+ vfloat<K> lnearP = maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ vfloat<K> lfarP = mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+ if (robust) {
+ lnearP = lnearP*vfloat<K>(1.0f-3.0f*float(ulp));
+ lfarP = lfarP *vfloat<K>(1.0f+3.0f*float(ulp));
+ }
+
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // QuantizedBaseNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectQuantizedNodeK(const typename BVHN<N>::QuantizedBaseNode* node, size_t i,
+ const TravRayK<K,false>& ray, vfloat<K>& dist)
+
+ {
+ assert(movemask(node->validMask()) & ((size_t)1 << i));
+ const vfloat<N> lower_x = node->dequantizeLowerX();
+ const vfloat<N> upper_x = node->dequantizeUpperX();
+ const vfloat<N> lower_y = node->dequantizeLowerY();
+ const vfloat<N> upper_y = node->dequantizeUpperY();
+ const vfloat<N> lower_z = node->dequantizeLowerZ();
+ const vfloat<N> upper_z = node->dequantizeUpperZ();
+
+ #if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat<K> lclipMinX = msub(lower_x[i], ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMinY = msub(lower_y[i], ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMinZ = msub(lower_z[i], ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> lclipMaxX = msub(upper_x[i], ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMaxY = msub(upper_y[i], ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMaxZ = msub(upper_z[i], ray.rdir.z, ray.org_rdir.z);
+ #else
+ const vfloat<K> lclipMinX = (lower_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (lower_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (lower_z[i] - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (upper_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (upper_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (upper_z[i] - ray.org.z) * ray.rdir.z;
+ #endif
+
+ #if defined(__AVX512F__) // SKX
+ if (K == 16)
+ {
+ /* use mixed float/int min/max */
+ const vfloat<K> lnearP = maxi(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+ dist = lnearP;
+ return lhit;
+ }
+ else
+ #endif
+ {
+ const vfloat<K> lnearP = maxi(mini(lclipMinX, lclipMaxX), mini(lclipMinY, lclipMaxY), mini(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = mini(maxi(lclipMinX, lclipMaxX), maxi(lclipMinY, lclipMaxY), maxi(lclipMinZ, lclipMaxZ));
+ #if defined(__AVX512F__) // SKX
+ const vbool<K> lhit = asInt(maxi(lnearP, ray.tnear)) <= asInt(mini(lfarP, ray.tfar));
+ #else
+ const vbool<K> lhit = maxi(lnearP, ray.tnear) <= mini(lfarP, ray.tfar);
+ #endif
+ dist = lnearP;
+ return lhit;
+ }
+ }
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectQuantizedNodeK(const typename BVHN<N>::QuantizedBaseNode* node, size_t i,
+ const TravRayK<K,true>& ray, vfloat<K>& dist)
+
+ {
+ assert(movemask(node->validMask()) & ((size_t)1 << i));
+ const vfloat<N> lower_x = node->dequantizeLowerX();
+ const vfloat<N> upper_x = node->dequantizeUpperX();
+ const vfloat<N> lower_y = node->dequantizeLowerY();
+ const vfloat<N> upper_y = node->dequantizeUpperY();
+ const vfloat<N> lower_z = node->dequantizeLowerZ();
+ const vfloat<N> upper_z = node->dequantizeUpperZ();
+
+ const vfloat<K> lclipMinX = (lower_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (lower_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (lower_z[i] - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (upper_x[i] - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (upper_y[i] - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (upper_z[i] - ray.org.z) * ray.rdir.z;
+
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const float round_down = 1.0f-3.0f*float(ulp);
+
+ const vfloat<K> lnearP = round_down*max(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *min(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = max(lnearP, ray.tnear) <= min(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectQuantizedNodeMBK(const typename BVHN<N>::QuantizedBaseNodeMB* node, const size_t i,
+ const TravRayK<K,false>& ray, const vfloat<K>& time, vfloat<K>& dist)
+
+ {
+ assert(movemask(node->validMask()) & ((size_t)1 << i));
+
+ const vfloat<K> lower_x = node->template dequantizeLowerX<K>(i,time);
+ const vfloat<K> upper_x = node->template dequantizeUpperX<K>(i,time);
+ const vfloat<K> lower_y = node->template dequantizeLowerY<K>(i,time);
+ const vfloat<K> upper_y = node->template dequantizeUpperY<K>(i,time);
+ const vfloat<K> lower_z = node->template dequantizeLowerZ<K>(i,time);
+ const vfloat<K> upper_z = node->template dequantizeUpperZ<K>(i,time);
+
+#if defined(__AVX2__) || defined(__ARM_NEON)
+ const vfloat<K> lclipMinX = msub(lower_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMinY = msub(lower_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMinZ = msub(lower_z, ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> lclipMaxX = msub(upper_x, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> lclipMaxY = msub(upper_y, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> lclipMaxZ = msub(upper_z, ray.rdir.z, ray.org_rdir.z);
+#else
+ const vfloat<K> lclipMinX = (lower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (lower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (lower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (upper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (upper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (upper_z - ray.org.z) * ray.rdir.z;
+ #endif
+ const vfloat<K> lnearP = max(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = min(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = max(lnearP, ray.tnear) <= min(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+
+ template<int N, int K>
+ __forceinline vbool<K> intersectQuantizedNodeMBK(const typename BVHN<N>::QuantizedBaseNodeMB* node, const size_t i,
+ const TravRayK<K,true>& ray, const vfloat<K>& time, vfloat<K>& dist)
+
+ {
+ assert(movemask(node->validMask()) & ((size_t)1 << i));
+
+ const vfloat<K> lower_x = node->template dequantizeLowerX<K>(i,time);
+ const vfloat<K> upper_x = node->template dequantizeUpperX<K>(i,time);
+ const vfloat<K> lower_y = node->template dequantizeLowerY<K>(i,time);
+ const vfloat<K> upper_y = node->template dequantizeUpperY<K>(i,time);
+ const vfloat<K> lower_z = node->template dequantizeLowerZ<K>(i,time);
+ const vfloat<K> upper_z = node->template dequantizeUpperZ<K>(i,time);
+
+ const vfloat<K> lclipMinX = (lower_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMinY = (lower_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMinZ = (lower_z - ray.org.z) * ray.rdir.z;
+ const vfloat<K> lclipMaxX = (upper_x - ray.org.x) * ray.rdir.x;
+ const vfloat<K> lclipMaxY = (upper_y - ray.org.y) * ray.rdir.y;
+ const vfloat<K> lclipMaxZ = (upper_z - ray.org.z) * ray.rdir.z;
+
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const float round_down = 1.0f-3.0f*float(ulp);
+
+ const vfloat<K> lnearP = round_down*max(min(lclipMinX, lclipMaxX), min(lclipMinY, lclipMaxY), min(lclipMinZ, lclipMaxZ));
+ const vfloat<K> lfarP = round_up *min(max(lclipMinX, lclipMaxX), max(lclipMinY, lclipMaxY), max(lclipMinZ, lclipMaxZ));
+ const vbool<K> lhit = max(lnearP, ray.tnear) <= min(lfarP, ray.tfar);
+ dist = lnearP;
+ return lhit;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Node intersectors used in hybrid traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /*! Intersects N nodes with K rays */
+ template<int N, int K, int types, bool robust>
+ struct BVHNNodeIntersectorK;
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN1, false>
+ {
+ /* vmask is both an input and an output parameter! Its initial value should be the parent node
+ hit mask, which is used for correctly computing the current hit mask. The parent hit mask
+ is actually required only for motion blur node intersections (because different rays may
+ have different times), so for regular nodes vmask is simply overwritten. */
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask = intersectNodeK<N,K>(node.getAABBNode(), i, ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN1, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask = intersectNodeKRobust<N,K>(node.getAABBNode(), i, ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask = intersectNodeK<N,K>(node.getAABBNodeMB(), i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask = intersectNodeKRobust<N,K>(node.getAABBNodeMB(), i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN1_UN1, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNode())) vmask = intersectNodeK<N,K>(node.getAABBNode(), i, ray, dist);
+ else /*if (unlikely(node.isOBBNode()))*/ vmask = intersectNodeK<N,K>(node.ungetAABBNode(), i, ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN1_UN1, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNode())) vmask = intersectNodeKRobust<N,K>(node.getAABBNode(), i, ray, dist);
+ else /*if (unlikely(node.isOBBNode()))*/ vmask = intersectNodeK<N,K>(node.ungetAABBNode(), i, ray, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_UN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNodeMB())) vmask = intersectNodeK<N,K>(node.getAABBNodeMB(), i, ray, time, dist);
+ else /*if (unlikely(node.isOBBNodeMB()))*/ vmask = intersectNodeK<N,K>(node.ungetAABBNodeMB(), i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_UN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNodeMB())) vmask = intersectNodeKRobust<N,K>(node.getAABBNodeMB(), i, ray, time, dist);
+ else /*if (unlikely(node.isOBBNodeMB()))*/ vmask = intersectNodeK<N,K>(node.ungetAABBNodeMB(), i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_AN4D, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask &= intersectNodeKMB4D<N,K>(node, i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_AN4D, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ vmask &= intersectNodeKMB4DRobust<N,K>(node, i, ray, time, dist);
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_AN4D_UN2, false>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKFast<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNodeMB() || node.isAABBNodeMB4D())) {
+ vmask &= intersectNodeKMB4D<N,K>(node, i, ray, time, dist);
+ } else /*if (unlikely(node.isOBBNodeMB()))*/ {
+ assert(node.isOBBNodeMB());
+ vmask &= intersectNodeK<N,K>(node.ungetAABBNodeMB(), i, ray, time, dist);
+ }
+ return true;
+ }
+ };
+
+ template<int N, int K>
+ struct BVHNNodeIntersectorK<N, K, BVH_AN2_AN4D_UN2, true>
+ {
+ static __forceinline bool intersect(const typename BVHN<N>::NodeRef& node, size_t i,
+ const TravRayKRobust<K>& ray, const vfloat<K>& time, vfloat<K>& dist, vbool<K>& vmask)
+ {
+ if (likely(node.isAABBNodeMB() || node.isAABBNodeMB4D())) {
+ vmask &= intersectNodeKMB4DRobust<N,K>(node, i, ray, time, dist);
+ } else /*if (unlikely(node.isOBBNodeMB()))*/ {
+ assert(node.isOBBNodeMB());
+ vmask &= intersectNodeK<N,K>(node.ungetAABBNodeMB(), i, ray, time, dist);
+ }
+ return true;
+ }
+ };
+
+
+ /*! Intersects N nodes with K rays */
+ template<int N, int K, bool robust>
+ struct BVHNQuantizedBaseNodeIntersectorK;
+
+ template<int N, int K>
+ struct BVHNQuantizedBaseNodeIntersectorK<N, K, false>
+ {
+ static __forceinline vbool<K> intersectK(const typename BVHN<N>::QuantizedBaseNode* node, const size_t i,
+ const TravRayK<K,false>& ray, vfloat<K>& dist)
+ {
+ return intersectQuantizedNodeK<N,K>(node,i,ray,dist);
+ }
+
+ static __forceinline vbool<K> intersectK(const typename BVHN<N>::QuantizedBaseNodeMB* node, const size_t i,
+ const TravRayK<K,false>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ return intersectQuantizedNodeMBK<N,K>(node,i,ray,time,dist);
+ }
+
+ };
+
+ template<int N, int K>
+ struct BVHNQuantizedBaseNodeIntersectorK<N, K, true>
+ {
+ static __forceinline vbool<K> intersectK(const typename BVHN<N>::QuantizedBaseNode* node, const size_t i,
+ const TravRayK<K,true>& ray, vfloat<K>& dist)
+ {
+ return intersectQuantizedNodeK<N,K>(node,i,ray,dist);
+ }
+
+ static __forceinline vbool<K> intersectK(const typename BVHN<N>::QuantizedBaseNodeMB* node, const size_t i,
+ const TravRayK<K,true>& ray, const vfloat<K>& time, vfloat<K>& dist)
+ {
+ return intersectQuantizedNodeMBK<N,K>(node,i,ray,time,dist);
+ }
+ };
+
+
+ }
+}
diff --git a/thirdparty/embree/kernels/bvh/node_intersector_packet_stream.h b/thirdparty/embree/kernels/bvh/node_intersector_packet_stream.h
new file mode 100644
index 0000000000..55b2c27231
--- /dev/null
+++ b/thirdparty/embree/kernels/bvh/node_intersector_packet_stream.h
@@ -0,0 +1,189 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "node_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Ray packet structure used in stream traversal
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int K, bool robust>
+ struct TravRayKStream;
+
+ /* Fast variant */
+ template<int K>
+ struct TravRayKStream<K, false>
+ {
+ __forceinline TravRayKStream() {}
+
+ __forceinline TravRayKStream(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar)
+ {
+ init(ray_org, ray_dir);
+ tnear = ray_tnear;
+ tfar = ray_tfar;
+ }
+
+ __forceinline void init(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir)
+ {
+ rdir = rcp_safe(ray_dir);
+ org_rdir = ray_org * rdir;
+ }
+
+ Vec3vf<K> rdir;
+ Vec3vf<K> org_rdir;
+ vfloat<K> tnear;
+ vfloat<K> tfar;
+ };
+
+ template<int K>
+ using TravRayKStreamFast = TravRayKStream<K, false>;
+
+ /* Robust variant */
+ template<int K>
+ struct TravRayKStream<K, true>
+ {
+ __forceinline TravRayKStream() {}
+
+ __forceinline TravRayKStream(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar)
+ {
+ init(ray_org, ray_dir);
+ tnear = ray_tnear;
+ tfar = ray_tfar;
+ }
+
+ __forceinline void init(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir)
+ {
+ rdir = vfloat<K>(1.0f)/(zero_fix(ray_dir));
+ org = ray_org;
+ }
+
+ Vec3vf<K> rdir;
+ Vec3vf<K> org;
+ vfloat<K> tnear;
+ vfloat<K> tfar;
+ };
+
+ template<int K>
+ using TravRayKStreamRobust = TravRayKStream<K, true>;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Fast AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline size_t intersectNode1(const typename BVHN<N>::AABBNode* __restrict__ node,
+ const TravRayKStreamFast<K>& ray, size_t k, const NearFarPrecalculations& nf)
+ {
+ const vfloat<N> bminX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX));
+ const vfloat<N> bminY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY));
+ const vfloat<N> bminZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ));
+ const vfloat<N> bmaxX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX));
+ const vfloat<N> bmaxY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY));
+ const vfloat<N> bmaxZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ));
+
+ const vfloat<N> rminX = msub(bminX, vfloat<N>(ray.rdir.x[k]), vfloat<N>(ray.org_rdir.x[k]));
+ const vfloat<N> rminY = msub(bminY, vfloat<N>(ray.rdir.y[k]), vfloat<N>(ray.org_rdir.y[k]));
+ const vfloat<N> rminZ = msub(bminZ, vfloat<N>(ray.rdir.z[k]), vfloat<N>(ray.org_rdir.z[k]));
+ const vfloat<N> rmaxX = msub(bmaxX, vfloat<N>(ray.rdir.x[k]), vfloat<N>(ray.org_rdir.x[k]));
+ const vfloat<N> rmaxY = msub(bmaxY, vfloat<N>(ray.rdir.y[k]), vfloat<N>(ray.org_rdir.y[k]));
+ const vfloat<N> rmaxZ = msub(bmaxZ, vfloat<N>(ray.rdir.z[k]), vfloat<N>(ray.org_rdir.z[k]));
+ const vfloat<N> rmin = maxi(rminX, rminY, rminZ, vfloat<N>(ray.tnear[k]));
+ const vfloat<N> rmax = mini(rmaxX, rmaxY, rmaxZ, vfloat<N>(ray.tfar[k]));
+
+ const vbool<N> vmask_first_hit = rmin <= rmax;
+
+ return movemask(vmask_first_hit) & (((size_t)1 << N)-1);
+ }
+
+ template<int N, int K>
+ __forceinline size_t intersectNodeK(const typename BVHN<N>::AABBNode* __restrict__ node, size_t i,
+ const TravRayKStreamFast<K>& ray, const NearFarPrecalculations& nf)
+ {
+ char* ptr = (char*)&node->lower_x + i*sizeof(float);
+ const vfloat<K> bminX = *(const float*)(ptr + nf.nearX);
+ const vfloat<K> bminY = *(const float*)(ptr + nf.nearY);
+ const vfloat<K> bminZ = *(const float*)(ptr + nf.nearZ);
+ const vfloat<K> bmaxX = *(const float*)(ptr + nf.farX);
+ const vfloat<K> bmaxY = *(const float*)(ptr + nf.farY);
+ const vfloat<K> bmaxZ = *(const float*)(ptr + nf.farZ);
+
+ const vfloat<K> rminX = msub(bminX, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> rminY = msub(bminY, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> rminZ = msub(bminZ, ray.rdir.z, ray.org_rdir.z);
+ const vfloat<K> rmaxX = msub(bmaxX, ray.rdir.x, ray.org_rdir.x);
+ const vfloat<K> rmaxY = msub(bmaxY, ray.rdir.y, ray.org_rdir.y);
+ const vfloat<K> rmaxZ = msub(bmaxZ, ray.rdir.z, ray.org_rdir.z);
+
+ const vfloat<K> rmin = maxi(rminX, rminY, rminZ, ray.tnear);
+ const vfloat<K> rmax = mini(rmaxX, rmaxY, rmaxZ, ray.tfar);
+
+ const vbool<K> vmask_first_hit = rmin <= rmax;
+
+ return movemask(vmask_first_hit);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Robust AABBNode intersection
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ template<int N, int K>
+ __forceinline size_t intersectNode1(const typename BVHN<N>::AABBNode* __restrict__ node,
+ const TravRayKStreamRobust<K>& ray, size_t k, const NearFarPrecalculations& nf)
+ {
+ const vfloat<N> bminX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX));
+ const vfloat<N> bminY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY));
+ const vfloat<N> bminZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ));
+ const vfloat<N> bmaxX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX));
+ const vfloat<N> bmaxY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY));
+ const vfloat<N> bmaxZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ));
+
+ const vfloat<N> rminX = (bminX - vfloat<N>(ray.org.x[k])) * vfloat<N>(ray.rdir.x[k]);
+ const vfloat<N> rminY = (bminY - vfloat<N>(ray.org.y[k])) * vfloat<N>(ray.rdir.y[k]);
+ const vfloat<N> rminZ = (bminZ - vfloat<N>(ray.org.z[k])) * vfloat<N>(ray.rdir.z[k]);
+ const vfloat<N> rmaxX = (bmaxX - vfloat<N>(ray.org.x[k])) * vfloat<N>(ray.rdir.x[k]);
+ const vfloat<N> rmaxY = (bmaxY - vfloat<N>(ray.org.y[k])) * vfloat<N>(ray.rdir.y[k]);
+ const vfloat<N> rmaxZ = (bmaxZ - vfloat<N>(ray.org.z[k])) * vfloat<N>(ray.rdir.z[k]);
+ const float round_up = 1.0f+3.0f*float(ulp); // FIXME: use per instruction rounding for AVX512
+ const vfloat<N> rmin = max(rminX, rminY, rminZ, vfloat<N>(ray.tnear[k]));
+ const vfloat<N> rmax = round_up *min(rmaxX, rmaxY, rmaxZ, vfloat<N>(ray.tfar[k]));
+
+ const vbool<N> vmask_first_hit = rmin <= rmax;
+
+ return movemask(vmask_first_hit) & (((size_t)1 << N)-1);
+ }
+
+ template<int N, int K>
+ __forceinline size_t intersectNodeK(const typename BVHN<N>::AABBNode* __restrict__ node, size_t i,
+ const TravRayKStreamRobust<K>& ray, const NearFarPrecalculations& nf)
+ {
+ char *ptr = (char*)&node->lower_x + i*sizeof(float);
+ const vfloat<K> bminX = *(const float*)(ptr + nf.nearX);
+ const vfloat<K> bminY = *(const float*)(ptr + nf.nearY);
+ const vfloat<K> bminZ = *(const float*)(ptr + nf.nearZ);
+ const vfloat<K> bmaxX = *(const float*)(ptr + nf.farX);
+ const vfloat<K> bmaxY = *(const float*)(ptr + nf.farY);
+ const vfloat<K> bmaxZ = *(const float*)(ptr + nf.farZ);
+
+ const vfloat<K> rminX = (bminX - ray.org.x) * ray.rdir.x;
+ const vfloat<K> rminY = (bminY - ray.org.y) * ray.rdir.y;
+ const vfloat<K> rminZ = (bminZ - ray.org.z) * ray.rdir.z;
+ const vfloat<K> rmaxX = (bmaxX - ray.org.x) * ray.rdir.x;
+ const vfloat<K> rmaxY = (bmaxY - ray.org.y) * ray.rdir.y;
+ const vfloat<K> rmaxZ = (bmaxZ - ray.org.z) * ray.rdir.z;
+
+ const float round_up = 1.0f+3.0f*float(ulp);
+ const vfloat<K> rmin = max(rminX, rminY, rminZ, vfloat<K>(ray.tnear));
+ const vfloat<K> rmax = round_up * min(rmaxX, rmaxY, rmaxZ, vfloat<K>(ray.tfar));
+
+ const vbool<K> vmask_first_hit = rmin <= rmax;
+
+ return movemask(vmask_first_hit);
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/common/accel.h b/thirdparty/embree/kernels/common/accel.h
new file mode 100644
index 0000000000..cc4ea1805b
--- /dev/null
+++ b/thirdparty/embree/kernels/common/accel.h
@@ -0,0 +1,556 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "ray.h"
+#include "point_query.h"
+#include "context.h"
+
+namespace embree
+{
+ class Scene;
+
+ /*! Base class for the acceleration structure data. */
+ class AccelData : public RefCount
+ {
+ ALIGNED_CLASS_(16);
+ public:
+ enum Type { TY_UNKNOWN = 0, TY_ACCELN = 1, TY_ACCEL_INSTANCE = 2, TY_BVH4 = 3, TY_BVH8 = 4 };
+
+ public:
+ AccelData (const Type type)
+ : bounds(empty), type(type) {}
+
+ /*! notifies the acceleration structure about the deletion of some geometry */
+ virtual void deleteGeometry(size_t geomID) {};
+
+ /*! clears the acceleration structure data */
+ virtual void clear() = 0;
+
+ /*! returns normal bounds */
+ __forceinline BBox3fa getBounds() const {
+ return bounds.bounds();
+ }
+
+ /*! returns bounds for some time */
+ __forceinline BBox3fa getBounds(float t) const {
+ return bounds.interpolate(t);
+ }
+
+ /*! returns linear bounds */
+ __forceinline LBBox3fa getLinearBounds() const {
+ return bounds;
+ }
+
+ /*! checks if acceleration structure is empty */
+ __forceinline bool isEmpty() const {
+ return bounds.bounds0.lower.x == float(pos_inf);
+ }
+
+ public:
+ LBBox3fa bounds; // linear bounds
+ Type type;
+ };
+
+ /*! Base class for all intersectable and buildable acceleration structures. */
+ class Accel : public AccelData
+ {
+ ALIGNED_CLASS_(16);
+ public:
+
+ struct Intersectors;
+
+ /*! Type of collide function */
+ typedef void (*CollideFunc)(void* bvh0, void* bvh1, RTCCollideFunc callback, void* userPtr);
+
+ /*! Type of point query function */
+ typedef bool(*PointQueryFunc)(Intersectors* This, /*!< this pointer to accel */
+ PointQuery* query, /*!< point query for lookup */
+ PointQueryContext* context); /*!< point query context */
+
+ /*! Type of intersect function pointer for single rays. */
+ typedef void (*IntersectFunc)(Intersectors* This, /*!< this pointer to accel */
+ RTCRayHit& ray, /*!< ray to intersect */
+ IntersectContext* context);
+
+ /*! Type of intersect function pointer for ray packets of size 4. */
+ typedef void (*IntersectFunc4)(const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRayHit4& ray, /*!< ray packet to intersect */
+ IntersectContext* context);
+
+ /*! Type of intersect function pointer for ray packets of size 8. */
+ typedef void (*IntersectFunc8)(const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRayHit8& ray, /*!< ray packet to intersect */
+ IntersectContext* context);
+
+ /*! Type of intersect function pointer for ray packets of size 16. */
+ typedef void (*IntersectFunc16)(const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRayHit16& ray, /*!< ray packet to intersect */
+ IntersectContext* context);
+
+ /*! Type of intersect function pointer for ray packets of size N. */
+ typedef void (*IntersectFuncN)(Intersectors* This, /*!< this pointer to accel */
+ RTCRayHitN** ray, /*!< ray stream to intersect */
+ const size_t N, /*!< number of rays in stream */
+ IntersectContext* context /*!< layout flags */);
+
+
+ /*! Type of occlusion function pointer for single rays. */
+ typedef void (*OccludedFunc) (Intersectors* This, /*!< this pointer to accel */
+ RTCRay& ray, /*!< ray to test occlusion */
+ IntersectContext* context);
+
+ /*! Type of occlusion function pointer for ray packets of size 4. */
+ typedef void (*OccludedFunc4) (const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRay4& ray, /*!< ray packet to test occlusion. */
+ IntersectContext* context);
+
+ /*! Type of occlusion function pointer for ray packets of size 8. */
+ typedef void (*OccludedFunc8) (const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRay8& ray, /*!< ray packet to test occlusion. */
+ IntersectContext* context);
+
+ /*! Type of occlusion function pointer for ray packets of size 16. */
+ typedef void (*OccludedFunc16) (const void* valid, /*!< pointer to valid mask */
+ Intersectors* This, /*!< this pointer to accel */
+ RTCRay16& ray, /*!< ray packet to test occlusion. */
+ IntersectContext* context);
+
+ /*! Type of intersect function pointer for ray packets of size N. */
+ typedef void (*OccludedFuncN)(Intersectors* This, /*!< this pointer to accel */
+ RTCRayN** ray, /*!< ray stream to test occlusion */
+ const size_t N, /*!< number of rays in stream */
+ IntersectContext* context /*!< layout flags */);
+ typedef void (*ErrorFunc) ();
+
+ struct Collider
+ {
+ Collider (ErrorFunc error = nullptr)
+ : collide((CollideFunc)error), name(nullptr) {}
+
+ Collider (CollideFunc collide, const char* name)
+ : collide(collide), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ CollideFunc collide;
+ const char* name;
+ };
+
+ struct Intersector1
+ {
+ Intersector1 (ErrorFunc error = nullptr)
+ : intersect((IntersectFunc)error), occluded((OccludedFunc)error), name(nullptr) {}
+
+ Intersector1 (IntersectFunc intersect, OccludedFunc occluded, const char* name)
+ : intersect(intersect), occluded(occluded), pointQuery(nullptr), name(name) {}
+
+ Intersector1 (IntersectFunc intersect, OccludedFunc occluded, PointQueryFunc pointQuery, const char* name)
+ : intersect(intersect), occluded(occluded), pointQuery(pointQuery), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFunc intersect;
+ OccludedFunc occluded;
+ PointQueryFunc pointQuery;
+ const char* name;
+ };
+
+ struct Intersector4
+ {
+ Intersector4 (ErrorFunc error = nullptr)
+ : intersect((IntersectFunc4)error), occluded((OccludedFunc4)error), name(nullptr) {}
+
+ Intersector4 (IntersectFunc4 intersect, OccludedFunc4 occluded, const char* name)
+ : intersect(intersect), occluded(occluded), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFunc4 intersect;
+ OccludedFunc4 occluded;
+ const char* name;
+ };
+
+ struct Intersector8
+ {
+ Intersector8 (ErrorFunc error = nullptr)
+ : intersect((IntersectFunc8)error), occluded((OccludedFunc8)error), name(nullptr) {}
+
+ Intersector8 (IntersectFunc8 intersect, OccludedFunc8 occluded, const char* name)
+ : intersect(intersect), occluded(occluded), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFunc8 intersect;
+ OccludedFunc8 occluded;
+ const char* name;
+ };
+
+ struct Intersector16
+ {
+ Intersector16 (ErrorFunc error = nullptr)
+ : intersect((IntersectFunc16)error), occluded((OccludedFunc16)error), name(nullptr) {}
+
+ Intersector16 (IntersectFunc16 intersect, OccludedFunc16 occluded, const char* name)
+ : intersect(intersect), occluded(occluded), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFunc16 intersect;
+ OccludedFunc16 occluded;
+ const char* name;
+ };
+
+ struct IntersectorN
+ {
+ IntersectorN (ErrorFunc error = nullptr)
+ : intersect((IntersectFuncN)error), occluded((OccludedFuncN)error), name(nullptr) {}
+
+ IntersectorN (IntersectFuncN intersect, OccludedFuncN occluded, const char* name)
+ : intersect(intersect), occluded(occluded), name(name) {}
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFuncN intersect;
+ OccludedFuncN occluded;
+ const char* name;
+ };
+
+ struct Intersectors
+ {
+ Intersectors()
+ : ptr(nullptr), leafIntersector(nullptr), collider(nullptr), intersector1(nullptr), intersector4(nullptr), intersector8(nullptr), intersector16(nullptr), intersectorN(nullptr) {}
+
+ Intersectors (ErrorFunc error)
+ : ptr(nullptr), leafIntersector(nullptr), collider(error), intersector1(error), intersector4(error), intersector8(error), intersector16(error), intersectorN(error) {}
+
+ void print(size_t ident)
+ {
+ if (collider.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "collider = " << collider.name << std::endl;
+ }
+ if (intersector1.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "intersector1 = " << intersector1.name << std::endl;
+ }
+ if (intersector4.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "intersector4 = " << intersector4.name << std::endl;
+ }
+ if (intersector8.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "intersector8 = " << intersector8.name << std::endl;
+ }
+ if (intersector16.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "intersector16 = " << intersector16.name << std::endl;
+ }
+ if (intersectorN.name) {
+ for (size_t i=0; i<ident; i++) std::cout << " ";
+ std::cout << "intersectorN = " << intersectorN.name << std::endl;
+ }
+ }
+
+ void select(bool filter)
+ {
+ if (intersector4_filter) {
+ if (filter) intersector4 = intersector4_filter;
+ else intersector4 = intersector4_nofilter;
+ }
+ if (intersector8_filter) {
+ if (filter) intersector8 = intersector8_filter;
+ else intersector8 = intersector8_nofilter;
+ }
+ if (intersector16_filter) {
+ if (filter) intersector16 = intersector16_filter;
+ else intersector16 = intersector16_nofilter;
+ }
+ if (intersectorN_filter) {
+ if (filter) intersectorN = intersectorN_filter;
+ else intersectorN = intersectorN_nofilter;
+ }
+ }
+
+ __forceinline bool pointQuery (PointQuery* query, PointQueryContext* context) {
+ assert(intersector1.pointQuery);
+ return intersector1.pointQuery(this,query,context);
+ }
+
+ /*! collides two scenes */
+ __forceinline void collide (Accel* scene0, Accel* scene1, RTCCollideFunc callback, void* userPtr) {
+ assert(collider.collide);
+ collider.collide(scene0->intersectors.ptr,scene1->intersectors.ptr,callback,userPtr);
+ }
+
+ /*! Intersects a single ray with the scene. */
+ __forceinline void intersect (RTCRayHit& ray, IntersectContext* context) {
+ assert(intersector1.intersect);
+ intersector1.intersect(this,ray,context);
+ }
+
+ /*! Intersects a packet of 4 rays with the scene. */
+ __forceinline void intersect4 (const void* valid, RTCRayHit4& ray, IntersectContext* context) {
+ assert(intersector4.intersect);
+ intersector4.intersect(valid,this,ray,context);
+ }
+
+ /*! Intersects a packet of 8 rays with the scene. */
+ __forceinline void intersect8 (const void* valid, RTCRayHit8& ray, IntersectContext* context) {
+ assert(intersector8.intersect);
+ intersector8.intersect(valid,this,ray,context);
+ }
+
+ /*! Intersects a packet of 16 rays with the scene. */
+ __forceinline void intersect16 (const void* valid, RTCRayHit16& ray, IntersectContext* context) {
+ assert(intersector16.intersect);
+ intersector16.intersect(valid,this,ray,context);
+ }
+
+ /*! Intersects a stream of N rays in SOA layout with the scene. */
+ __forceinline void intersectN (RTCRayHitN** rayN, const size_t N, IntersectContext* context)
+ {
+ assert(intersectorN.intersect);
+ intersectorN.intersect(this,rayN,N,context);
+ }
+
+#if defined(__SSE__)
+ __forceinline void intersect(const vbool4& valid, RayHitK<4>& ray, IntersectContext* context) {
+ const vint<4> mask = valid.mask32();
+ intersect4(&mask,(RTCRayHit4&)ray,context);
+ }
+#endif
+#if defined(__AVX__)
+ __forceinline void intersect(const vbool8& valid, RayHitK<8>& ray, IntersectContext* context) {
+ const vint<8> mask = valid.mask32();
+ intersect8(&mask,(RTCRayHit8&)ray,context);
+ }
+#endif
+#if defined(__AVX512F__)
+ __forceinline void intersect(const vbool16& valid, RayHitK<16>& ray, IntersectContext* context) {
+ const vint<16> mask = valid.mask32();
+ intersect16(&mask,(RTCRayHit16&)ray,context);
+ }
+#endif
+
+ template<int K>
+ __forceinline void intersectN (RayHitK<K>** rayN, const size_t N, IntersectContext* context)
+ {
+ intersectN((RTCRayHitN**)rayN,N,context);
+ }
+
+ /*! Tests if single ray is occluded by the scene. */
+ __forceinline void occluded (RTCRay& ray, IntersectContext* context) {
+ assert(intersector1.occluded);
+ intersector1.occluded(this,ray,context);
+ }
+
+ /*! Tests if a packet of 4 rays is occluded by the scene. */
+ __forceinline void occluded4 (const void* valid, RTCRay4& ray, IntersectContext* context) {
+ assert(intersector4.occluded);
+ intersector4.occluded(valid,this,ray,context);
+ }
+
+ /*! Tests if a packet of 8 rays is occluded by the scene. */
+ __forceinline void occluded8 (const void* valid, RTCRay8& ray, IntersectContext* context) {
+ assert(intersector8.occluded);
+ intersector8.occluded(valid,this,ray,context);
+ }
+
+ /*! Tests if a packet of 16 rays is occluded by the scene. */
+ __forceinline void occluded16 (const void* valid, RTCRay16& ray, IntersectContext* context) {
+ assert(intersector16.occluded);
+ intersector16.occluded(valid,this,ray,context);
+ }
+
+ /*! Tests if a stream of N rays in SOA layout is occluded by the scene. */
+ __forceinline void occludedN (RTCRayN** rayN, const size_t N, IntersectContext* context)
+ {
+ assert(intersectorN.occluded);
+ intersectorN.occluded(this,rayN,N,context);
+ }
+
+#if defined(__SSE__)
+ __forceinline void occluded(const vbool4& valid, RayK<4>& ray, IntersectContext* context) {
+ const vint<4> mask = valid.mask32();
+ occluded4(&mask,(RTCRay4&)ray,context);
+ }
+#endif
+#if defined(__AVX__)
+ __forceinline void occluded(const vbool8& valid, RayK<8>& ray, IntersectContext* context) {
+ const vint<8> mask = valid.mask32();
+ occluded8(&mask,(RTCRay8&)ray,context);
+ }
+#endif
+#if defined(__AVX512F__)
+ __forceinline void occluded(const vbool16& valid, RayK<16>& ray, IntersectContext* context) {
+ const vint<16> mask = valid.mask32();
+ occluded16(&mask,(RTCRay16&)ray,context);
+ }
+#endif
+
+ template<int K>
+ __forceinline void occludedN (RayK<K>** rayN, const size_t N, IntersectContext* context)
+ {
+ occludedN((RTCRayN**)rayN,N,context);
+ }
+
+ /*! Tests if single ray is occluded by the scene. */
+ __forceinline void intersect(RTCRay& ray, IntersectContext* context) {
+ occluded(ray, context);
+ }
+
+ /*! Tests if a packet of K rays is occluded by the scene. */
+ template<int K>
+ __forceinline void intersect(const vbool<K>& valid, RayK<K>& ray, IntersectContext* context) {
+ occluded(valid, ray, context);
+ }
+
+ /*! Tests if a packet of N rays in SOA layout is occluded by the scene. */
+ template<int K>
+ __forceinline void intersectN(RayK<K>** rayN, const size_t N, IntersectContext* context) {
+ occludedN(rayN, N, context);
+ }
+
+ public:
+ AccelData* ptr;
+ void* leafIntersector;
+ Collider collider;
+ Intersector1 intersector1;
+ Intersector4 intersector4;
+ Intersector4 intersector4_filter;
+ Intersector4 intersector4_nofilter;
+ Intersector8 intersector8;
+ Intersector8 intersector8_filter;
+ Intersector8 intersector8_nofilter;
+ Intersector16 intersector16;
+ Intersector16 intersector16_filter;
+ Intersector16 intersector16_nofilter;
+ IntersectorN intersectorN;
+ IntersectorN intersectorN_filter;
+ IntersectorN intersectorN_nofilter;
+ };
+
+ public:
+
+ /*! Construction */
+ Accel (const AccelData::Type type)
+ : AccelData(type) {}
+
+ /*! Construction */
+ Accel (const AccelData::Type type, const Intersectors& intersectors)
+ : AccelData(type), intersectors(intersectors) {}
+
+ /*! Virtual destructor */
+ virtual ~Accel() {}
+
+ /*! makes the acceleration structure immutable */
+ virtual void immutable () {}
+
+ /*! build acceleration structure */
+ virtual void build () = 0;
+
+ public:
+ Intersectors intersectors;
+ };
+
+#define DEFINE_COLLIDER(symbol,collider) \
+ Accel::Collider symbol() { \
+ return Accel::Collider((Accel::CollideFunc)collider::collide, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+#define DEFINE_INTERSECTOR1(symbol,intersector) \
+ Accel::Intersector1 symbol() { \
+ return Accel::Intersector1((Accel::IntersectFunc )intersector::intersect, \
+ (Accel::OccludedFunc )intersector::occluded, \
+ (Accel::PointQueryFunc)intersector::pointQuery,\
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+#define DEFINE_INTERSECTOR4(symbol,intersector) \
+ Accel::Intersector4 symbol() { \
+ return Accel::Intersector4((Accel::IntersectFunc4)intersector::intersect, \
+ (Accel::OccludedFunc4)intersector::occluded, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+#define DEFINE_INTERSECTOR8(symbol,intersector) \
+ Accel::Intersector8 symbol() { \
+ return Accel::Intersector8((Accel::IntersectFunc8)intersector::intersect, \
+ (Accel::OccludedFunc8)intersector::occluded, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+#define DEFINE_INTERSECTOR16(symbol,intersector) \
+ Accel::Intersector16 symbol() { \
+ return Accel::Intersector16((Accel::IntersectFunc16)intersector::intersect, \
+ (Accel::OccludedFunc16)intersector::occluded, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+#define DEFINE_INTERSECTORN(symbol,intersector) \
+ Accel::IntersectorN symbol() { \
+ return Accel::IntersectorN((Accel::IntersectFuncN)intersector::intersect, \
+ (Accel::OccludedFuncN)intersector::occluded, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+
+ /* ray stream filter interface */
+ typedef void (*intersectStreamAOS_func)(Scene* scene, RTCRayHit* _rayN, const size_t N, const size_t stride, IntersectContext* context);
+ typedef void (*intersectStreamAOP_func)(Scene* scene, RTCRayHit** _rayN, const size_t N, IntersectContext* context);
+ typedef void (*intersectStreamSOA_func)(Scene* scene, char* rayN, const size_t N, const size_t streams, const size_t stream_offset, IntersectContext* context);
+ typedef void (*intersectStreamSOP_func)(Scene* scene, const RTCRayHitNp* rayN, const size_t N, IntersectContext* context);
+
+ typedef void (*occludedStreamAOS_func)(Scene* scene, RTCRay* _rayN, const size_t N, const size_t stride, IntersectContext* context);
+ typedef void (*occludedStreamAOP_func)(Scene* scene, RTCRay** _rayN, const size_t N, IntersectContext* context);
+ typedef void (*occludedStreamSOA_func)(Scene* scene, char* rayN, const size_t N, const size_t streams, const size_t stream_offset, IntersectContext* context);
+ typedef void (*occludedStreamSOP_func)(Scene* scene, const RTCRayNp* rayN, const size_t N, IntersectContext* context);
+
+ struct RayStreamFilterFuncs
+ {
+ RayStreamFilterFuncs()
+ : intersectAOS(nullptr), intersectAOP(nullptr), intersectSOA(nullptr), intersectSOP(nullptr),
+ occludedAOS(nullptr), occludedAOP(nullptr), occludedSOA(nullptr), occludedSOP(nullptr) {}
+
+ RayStreamFilterFuncs(void (*ptr) ())
+ : intersectAOS((intersectStreamAOS_func) ptr), intersectAOP((intersectStreamAOP_func) ptr), intersectSOA((intersectStreamSOA_func) ptr), intersectSOP((intersectStreamSOP_func) ptr),
+ occludedAOS((occludedStreamAOS_func) ptr), occludedAOP((occludedStreamAOP_func) ptr), occludedSOA((occludedStreamSOA_func) ptr), occludedSOP((occludedStreamSOP_func) ptr) {}
+
+ RayStreamFilterFuncs(intersectStreamAOS_func intersectAOS, intersectStreamAOP_func intersectAOP, intersectStreamSOA_func intersectSOA, intersectStreamSOP_func intersectSOP,
+ occludedStreamAOS_func occludedAOS, occludedStreamAOP_func occludedAOP, occludedStreamSOA_func occludedSOA, occludedStreamSOP_func occludedSOP)
+ : intersectAOS(intersectAOS), intersectAOP(intersectAOP), intersectSOA(intersectSOA), intersectSOP(intersectSOP),
+ occludedAOS(occludedAOS), occludedAOP(occludedAOP), occludedSOA(occludedSOA), occludedSOP(occludedSOP) {}
+
+ public:
+ intersectStreamAOS_func intersectAOS;
+ intersectStreamAOP_func intersectAOP;
+ intersectStreamSOA_func intersectSOA;
+ intersectStreamSOP_func intersectSOP;
+
+ occludedStreamAOS_func occludedAOS;
+ occludedStreamAOP_func occludedAOP;
+ occludedStreamSOA_func occludedSOA;
+ occludedStreamSOP_func occludedSOP;
+ };
+
+ typedef RayStreamFilterFuncs (*RayStreamFilterFuncsType)();
+}
diff --git a/thirdparty/embree/kernels/common/accelinstance.h b/thirdparty/embree/kernels/common/accelinstance.h
new file mode 100644
index 0000000000..c63ef998bd
--- /dev/null
+++ b/thirdparty/embree/kernels/common/accelinstance.h
@@ -0,0 +1,41 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "accel.h"
+#include "builder.h"
+
+namespace embree
+{
+ class AccelInstance : public Accel
+ {
+ public:
+ AccelInstance (AccelData* accel, Builder* builder, Intersectors& intersectors)
+ : Accel(AccelData::TY_ACCEL_INSTANCE,intersectors), accel(accel), builder(builder) {}
+
+ void immutable () {
+ builder.reset(nullptr);
+ }
+
+ public:
+ void build () {
+ if (builder) builder->build();
+ bounds = accel->bounds;
+ }
+
+ void deleteGeometry(size_t geomID) {
+ if (accel ) accel->deleteGeometry(geomID);
+ if (builder) builder->deleteGeometry(geomID);
+ }
+
+ void clear() {
+ if (accel) accel->clear();
+ if (builder) builder->clear();
+ }
+
+ private:
+ std::unique_ptr<AccelData> accel;
+ std::unique_ptr<Builder> builder;
+ };
+}
diff --git a/thirdparty/embree/kernels/common/acceln.cpp b/thirdparty/embree/kernels/common/acceln.cpp
new file mode 100644
index 0000000000..32a27c560a
--- /dev/null
+++ b/thirdparty/embree/kernels/common/acceln.cpp
@@ -0,0 +1,232 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "acceln.h"
+#include "ray.h"
+#include "../../include/embree3/rtcore_ray.h"
+#include "../../common/algorithms/parallel_for.h"
+
+namespace embree
+{
+ AccelN::AccelN()
+ : Accel(AccelData::TY_ACCELN), accels() {}
+
+ AccelN::~AccelN()
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ delete accels[i];
+ }
+
+ void AccelN::accels_add(Accel* accel)
+ {
+ assert(accel);
+ accels.push_back(accel);
+ }
+
+ void AccelN::accels_init()
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ delete accels[i];
+
+ accels.clear();
+ }
+
+ bool AccelN::pointQuery (Accel::Intersectors* This_in, PointQuery* query, PointQueryContext* context)
+ {
+ bool changed = false;
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ changed |= This->accels[i]->intersectors.pointQuery(query,context);
+ return changed;
+ }
+
+ void AccelN::intersect (Accel::Intersectors* This_in, RTCRayHit& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.intersect(ray,context);
+ }
+
+ void AccelN::intersect4 (const void* valid, Accel::Intersectors* This_in, RTCRayHit4& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.intersect4(valid,ray,context);
+ }
+
+ void AccelN::intersect8 (const void* valid, Accel::Intersectors* This_in, RTCRayHit8& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.intersect8(valid,ray,context);
+ }
+
+ void AccelN::intersect16 (const void* valid, Accel::Intersectors* This_in, RTCRayHit16& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.intersect16(valid,ray,context);
+ }
+
+ void AccelN::intersectN (Accel::Intersectors* This_in, RTCRayHitN** ray, const size_t N, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.intersectN(ray,N,context);
+ }
+
+ void AccelN::occluded (Accel::Intersectors* This_in, RTCRay& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++) {
+ if (This->accels[i]->isEmpty()) continue;
+ This->accels[i]->intersectors.occluded(ray,context);
+ if (ray.tfar < 0.0f) break;
+ }
+ }
+
+ void AccelN::occluded4 (const void* valid, Accel::Intersectors* This_in, RTCRay4& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++) {
+ if (This->accels[i]->isEmpty()) continue;
+ This->accels[i]->intersectors.occluded4(valid,ray,context);
+#if defined(__SSE2__)
+ vbool4 valid0 = asBool(((vint4*)valid)[0]);
+ vbool4 hit0 = ((vfloat4*)ray.tfar)[0] >= vfloat4(zero);
+ if (unlikely(none(valid0 & hit0))) break;
+#endif
+ }
+ }
+
+ void AccelN::occluded8 (const void* valid, Accel::Intersectors* This_in, RTCRay8& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++) {
+ if (This->accels[i]->isEmpty()) continue;
+ This->accels[i]->intersectors.occluded8(valid,ray,context);
+#if defined(__SSE2__) // FIXME: use higher ISA
+ vbool4 valid0 = asBool(((vint4*)valid)[0]);
+ vbool4 hit0 = ((vfloat4*)ray.tfar)[0] >= vfloat4(zero);
+ vbool4 valid1 = asBool(((vint4*)valid)[1]);
+ vbool4 hit1 = ((vfloat4*)ray.tfar)[1] >= vfloat4(zero);
+ if (unlikely((none((valid0 & hit0) | (valid1 & hit1))))) break;
+#endif
+ }
+ }
+
+ void AccelN::occluded16 (const void* valid, Accel::Intersectors* This_in, RTCRay16& ray, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ for (size_t i=0; i<This->accels.size(); i++) {
+ if (This->accels[i]->isEmpty()) continue;
+ This->accels[i]->intersectors.occluded16(valid,ray,context);
+#if defined(__SSE2__) // FIXME: use higher ISA
+ vbool4 valid0 = asBool(((vint4*)valid)[0]);
+ vbool4 hit0 = ((vfloat4*)ray.tfar)[0] >= vfloat4(zero);
+ vbool4 valid1 = asBool(((vint4*)valid)[1]);
+ vbool4 hit1 = ((vfloat4*)ray.tfar)[1] >= vfloat4(zero);
+ vbool4 valid2 = asBool(((vint4*)valid)[2]);
+ vbool4 hit2 = ((vfloat4*)ray.tfar)[2] >= vfloat4(zero);
+ vbool4 valid3 = asBool(((vint4*)valid)[3]);
+ vbool4 hit3 = ((vfloat4*)ray.tfar)[3] >= vfloat4(zero);
+ if (unlikely((none((valid0 & hit0) | (valid1 & hit1) | (valid2 & hit2) | (valid3 & hit3))))) break;
+#endif
+ }
+ }
+
+ void AccelN::occludedN (Accel::Intersectors* This_in, RTCRayN** ray, const size_t N, IntersectContext* context)
+ {
+ AccelN* This = (AccelN*)This_in->ptr;
+ size_t M = N;
+ for (size_t i=0; i<This->accels.size(); i++)
+ if (!This->accels[i]->isEmpty())
+ This->accels[i]->intersectors.occludedN(ray,M,context);
+ }
+
+ void AccelN::accels_print(size_t ident)
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ {
+ for (size_t j=0; j<ident; j++) std::cout << " ";
+ std::cout << "accels[" << i << "]" << std::endl;
+ accels[i]->intersectors.print(ident+2);
+ }
+ }
+
+ void AccelN::accels_immutable()
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ accels[i]->immutable();
+ }
+
+ void AccelN::accels_build ()
+ {
+ /* reduce memory consumption */
+ accels.shrink_to_fit();
+
+ /* build all acceleration structures in parallel */
+ parallel_for (accels.size(), [&] (size_t i) {
+ accels[i]->build();
+ });
+
+ /* create list of non-empty acceleration structures */
+ bool valid1 = true;
+ bool valid4 = true;
+ bool valid8 = true;
+ bool valid16 = true;
+ for (size_t i=0; i<accels.size(); i++) {
+ valid1 &= (bool) accels[i]->intersectors.intersector1;
+ valid4 &= (bool) accels[i]->intersectors.intersector4;
+ valid8 &= (bool) accels[i]->intersectors.intersector8;
+ valid16 &= (bool) accels[i]->intersectors.intersector16;
+ }
+
+ if (accels.size() == 1) {
+ type = accels[0]->type; // FIXME: should just assign entire Accel
+ bounds = accels[0]->bounds;
+ intersectors = accels[0]->intersectors;
+ }
+ else
+ {
+ type = AccelData::TY_ACCELN;
+ intersectors.ptr = this;
+ intersectors.intersector1 = Intersector1(&intersect,&occluded,&pointQuery,valid1 ? "AccelN::intersector1": nullptr);
+ intersectors.intersector4 = Intersector4(&intersect4,&occluded4,valid4 ? "AccelN::intersector4" : nullptr);
+ intersectors.intersector8 = Intersector8(&intersect8,&occluded8,valid8 ? "AccelN::intersector8" : nullptr);
+ intersectors.intersector16 = Intersector16(&intersect16,&occluded16,valid16 ? "AccelN::intersector16": nullptr);
+ intersectors.intersectorN = IntersectorN(&intersectN,&occludedN,"AccelN::intersectorN");
+
+ /*! calculate bounds */
+ bounds = empty;
+ for (size_t i=0; i<accels.size(); i++)
+ bounds.extend(accels[i]->bounds);
+ }
+ }
+
+ void AccelN::accels_select(bool filter)
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ accels[i]->intersectors.select(filter);
+ }
+
+ void AccelN::accels_deleteGeometry(size_t geomID)
+ {
+ for (size_t i=0; i<accels.size(); i++)
+ accels[i]->deleteGeometry(geomID);
+ }
+
+ void AccelN::accels_clear()
+ {
+ for (size_t i=0; i<accels.size(); i++) {
+ accels[i]->clear();
+ }
+ }
+}
+
diff --git a/thirdparty/embree/kernels/common/acceln.h b/thirdparty/embree/kernels/common/acceln.h
new file mode 100644
index 0000000000..0445b2e811
--- /dev/null
+++ b/thirdparty/embree/kernels/common/acceln.h
@@ -0,0 +1,49 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "accel.h"
+
+namespace embree
+{
+ /*! merges N acceleration structures together, by processing them in order */
+ class AccelN : public Accel
+ {
+ public:
+ AccelN ();
+ ~AccelN();
+
+ public:
+ void accels_add(Accel* accel);
+ void accels_init();
+
+ public:
+ static bool pointQuery (Accel::Intersectors* This, PointQuery* query, PointQueryContext* context);
+
+ public:
+ static void intersect (Accel::Intersectors* This, RTCRayHit& ray, IntersectContext* context);
+ static void intersect4 (const void* valid, Accel::Intersectors* This, RTCRayHit4& ray, IntersectContext* context);
+ static void intersect8 (const void* valid, Accel::Intersectors* This, RTCRayHit8& ray, IntersectContext* context);
+ static void intersect16 (const void* valid, Accel::Intersectors* This, RTCRayHit16& ray, IntersectContext* context);
+ static void intersectN (Accel::Intersectors* This, RTCRayHitN** ray, const size_t N, IntersectContext* context);
+
+ public:
+ static void occluded (Accel::Intersectors* This, RTCRay& ray, IntersectContext* context);
+ static void occluded4 (const void* valid, Accel::Intersectors* This, RTCRay4& ray, IntersectContext* context);
+ static void occluded8 (const void* valid, Accel::Intersectors* This, RTCRay8& ray, IntersectContext* context);
+ static void occluded16 (const void* valid, Accel::Intersectors* This, RTCRay16& ray, IntersectContext* context);
+ static void occludedN (Accel::Intersectors* This, RTCRayN** ray, const size_t N, IntersectContext* context);
+
+ public:
+ void accels_print(size_t ident);
+ void accels_immutable();
+ void accels_build ();
+ void accels_select(bool filter);
+ void accels_deleteGeometry(size_t geomID);
+ void accels_clear ();
+
+ public:
+ std::vector<Accel*> accels;
+ };
+}
diff --git a/thirdparty/embree/kernels/common/accelset.cpp b/thirdparty/embree/kernels/common/accelset.cpp
new file mode 100644
index 0000000000..8c18f31776
--- /dev/null
+++ b/thirdparty/embree/kernels/common/accelset.cpp
@@ -0,0 +1,17 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "accelset.h"
+#include "scene.h"
+
+namespace embree
+{
+ AccelSet::AccelSet (Device* device, Geometry::GType gtype, size_t numItems, size_t numTimeSteps)
+ : Geometry(device,gtype,(unsigned int)numItems,(unsigned int)numTimeSteps), boundsFunc(nullptr) {}
+
+ AccelSet::IntersectorN::IntersectorN (ErrorFunc error)
+ : intersect((IntersectFuncN)error), occluded((OccludedFuncN)error), name(nullptr) {}
+
+ AccelSet::IntersectorN::IntersectorN (IntersectFuncN intersect, OccludedFuncN occluded, const char* name)
+ : intersect(intersect), occluded(occluded), name(name) {}
+}
diff --git a/thirdparty/embree/kernels/common/accelset.h b/thirdparty/embree/kernels/common/accelset.h
new file mode 100644
index 0000000000..90b184a07b
--- /dev/null
+++ b/thirdparty/embree/kernels/common/accelset.h
@@ -0,0 +1,248 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "builder.h"
+#include "geometry.h"
+#include "ray.h"
+#include "hit.h"
+
+namespace embree
+{
+ struct IntersectFunctionNArguments;
+ struct OccludedFunctionNArguments;
+
+ typedef void (*ReportIntersectionFunc) (IntersectFunctionNArguments* args, const RTCFilterFunctionNArguments* filter_args);
+ typedef void (*ReportOcclusionFunc) (OccludedFunctionNArguments* args, const RTCFilterFunctionNArguments* filter_args);
+
+ struct IntersectFunctionNArguments : public RTCIntersectFunctionNArguments
+ {
+ IntersectContext* internal_context;
+ Geometry* geometry;
+ ReportIntersectionFunc report;
+ };
+
+ struct OccludedFunctionNArguments : public RTCOccludedFunctionNArguments
+ {
+ IntersectContext* internal_context;
+ Geometry* geometry;
+ ReportOcclusionFunc report;
+ };
+
+ /*! Base class for set of acceleration structures. */
+ class AccelSet : public Geometry
+ {
+ public:
+ typedef RTCIntersectFunctionN IntersectFuncN;
+ typedef RTCOccludedFunctionN OccludedFuncN;
+ typedef void (*ErrorFunc) ();
+
+ struct IntersectorN
+ {
+ IntersectorN (ErrorFunc error = nullptr) ;
+ IntersectorN (IntersectFuncN intersect, OccludedFuncN occluded, const char* name);
+
+ operator bool() const { return name; }
+
+ public:
+ static const char* type;
+ IntersectFuncN intersect;
+ OccludedFuncN occluded;
+ const char* name;
+ };
+
+ public:
+
+ /*! construction */
+ AccelSet (Device* device, Geometry::GType gtype, size_t items, size_t numTimeSteps);
+
+ /*! makes the acceleration structure immutable */
+ virtual void immutable () {}
+
+ /*! build accel */
+ virtual void build () = 0;
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ if (!isvalid_non_empty(bounds(i,itime))) return false;
+
+ return true;
+ }
+
+ /*! Calculates the bounds of an item */
+ __forceinline BBox3fa bounds(size_t i, size_t itime = 0) const
+ {
+ BBox3fa box;
+ assert(i < size());
+ RTCBoundsFunctionArguments args;
+ args.geometryUserPtr = userPtr;
+ args.primID = (unsigned int)i;
+ args.timeStep = (unsigned int)itime;
+ args.bounds_o = (RTCBounds*)&box;
+ boundsFunc(&args);
+ return box;
+ }
+
+ /*! calculates the linear bounds of the i'th item at the itime'th time segment */
+ __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const
+ {
+ BBox3fa box[2];
+ assert(i < size());
+ RTCBoundsFunctionArguments args;
+ args.geometryUserPtr = userPtr;
+ args.primID = (unsigned int)i;
+ args.timeStep = (unsigned int)(itime+0);
+ args.bounds_o = (RTCBounds*)&box[0];
+ boundsFunc(&args);
+ args.timeStep = (unsigned int)(itime+1);
+ args.bounds_o = (RTCBounds*)&box[1];
+ boundsFunc(&args);
+ return LBBox3fa(box[0],box[1]);
+ }
+
+ /*! calculates the build bounds of the i'th item, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
+ {
+ const BBox3fa b = bounds(i);
+ if (bbox) *bbox = b;
+ return isvalid_non_empty(b);
+ }
+
+ /*! calculates the build bounds of the i'th item at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ const LBBox3fa bounds = linearBounds(i,itime);
+ bbox = bounds.bounds0; // use bounding box of first timestep to build BVH
+ return isvalid_non_empty(bounds);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline bool linearBounds(size_t i, const BBox1f& time_range, LBBox3fa& bbox) const {
+ if (!valid(i, timeSegmentRange(time_range))) return false;
+ bbox = linearBounds(i, time_range);
+ return true;
+ }
+
+ /* gets version info of topology */
+ unsigned int getTopologyVersion() const {
+ return numPrimitives;
+ }
+
+ /* returns true if topology changed */
+ bool topologyChanged(unsigned int otherVersion) const {
+ return numPrimitives != otherVersion;
+ }
+
+ public:
+
+ /*! Intersects a single ray with the scene. */
+ __forceinline void intersect (RayHit& ray, unsigned int geomID, unsigned int primID, IntersectContext* context, ReportIntersectionFunc report)
+ {
+ assert(primID < size());
+ assert(intersectorN.intersect);
+
+ int mask = -1;
+ IntersectFunctionNArguments args;
+ args.valid = &mask;
+ args.geometryUserPtr = userPtr;
+ args.context = context->user;
+ args.rayhit = (RTCRayHitN*)&ray;
+ args.N = 1;
+ args.geomID = geomID;
+ args.primID = primID;
+ args.internal_context = context;
+ args.geometry = this;
+ args.report = report;
+
+ intersectorN.intersect(&args);
+ }
+
+ /*! Tests if single ray is occluded by the scene. */
+ __forceinline void occluded (Ray& ray, unsigned int geomID, unsigned int primID, IntersectContext* context, ReportOcclusionFunc report)
+ {
+ assert(primID < size());
+ assert(intersectorN.occluded);
+
+ int mask = -1;
+ OccludedFunctionNArguments args;
+ args.valid = &mask;
+ args.geometryUserPtr = userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.N = 1;
+ args.geomID = geomID;
+ args.primID = primID;
+ args.internal_context = context;
+ args.geometry = this;
+ args.report = report;
+
+ intersectorN.occluded(&args);
+ }
+
+ /*! Intersects a packet of K rays with the scene. */
+ template<int K>
+ __forceinline void intersect (const vbool<K>& valid, RayHitK<K>& ray, unsigned int geomID, unsigned int primID, IntersectContext* context, ReportIntersectionFunc report)
+ {
+ assert(primID < size());
+ assert(intersectorN.intersect);
+
+ vint<K> mask = valid.mask32();
+ IntersectFunctionNArguments args;
+ args.valid = (int*)&mask;
+ args.geometryUserPtr = userPtr;
+ args.context = context->user;
+ args.rayhit = (RTCRayHitN*)&ray;
+ args.N = K;
+ args.geomID = geomID;
+ args.primID = primID;
+ args.internal_context = context;
+ args.geometry = this;
+ args.report = report;
+
+ intersectorN.intersect(&args);
+ }
+
+ /*! Tests if a packet of K rays is occluded by the scene. */
+ template<int K>
+ __forceinline void occluded (const vbool<K>& valid, RayK<K>& ray, unsigned int geomID, unsigned int primID, IntersectContext* context, ReportOcclusionFunc report)
+ {
+ assert(primID < size());
+ assert(intersectorN.occluded);
+
+ vint<K> mask = valid.mask32();
+ OccludedFunctionNArguments args;
+ args.valid = (int*)&mask;
+ args.geometryUserPtr = userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.N = K;
+ args.geomID = geomID;
+ args.primID = primID;
+ args.internal_context = context;
+ args.geometry = this;
+ args.report = report;
+
+ intersectorN.occluded(&args);
+ }
+
+ public:
+ RTCBoundsFunction boundsFunc;
+ IntersectorN intersectorN;
+ };
+
+#define DEFINE_SET_INTERSECTORN(symbol,intersector) \
+ AccelSet::IntersectorN symbol() { \
+ return AccelSet::IntersectorN(intersector::intersect, \
+ intersector::occluded, \
+ TOSTRING(isa) "::" TOSTRING(symbol)); \
+ }
+}
diff --git a/thirdparty/embree/kernels/common/alloc.cpp b/thirdparty/embree/kernels/common/alloc.cpp
new file mode 100644
index 0000000000..1a0e1aeed3
--- /dev/null
+++ b/thirdparty/embree/kernels/common/alloc.cpp
@@ -0,0 +1,79 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "alloc.h"
+#include "../../common/sys/thread.h"
+
+namespace embree
+{
+ __thread FastAllocator::ThreadLocal2* FastAllocator::thread_local_allocator2 = nullptr;
+ SpinLock FastAllocator::s_thread_local_allocators_lock;
+ std::vector<std::unique_ptr<FastAllocator::ThreadLocal2>> FastAllocator::s_thread_local_allocators;
+
+ struct fast_allocator_regression_test : public RegressionTest
+ {
+ BarrierSys barrier;
+ std::atomic<size_t> numFailed;
+ std::unique_ptr<FastAllocator> alloc;
+
+ fast_allocator_regression_test()
+ : RegressionTest("fast_allocator_regression_test"), numFailed(0)
+ {
+ registerRegressionTest(this);
+ }
+
+ static void thread_alloc(fast_allocator_regression_test* This)
+ {
+ FastAllocator::CachedAllocator threadalloc = This->alloc->getCachedAllocator();
+
+ size_t* ptrs[1000];
+ for (size_t j=0; j<1000; j++)
+ {
+ This->barrier.wait();
+ for (size_t i=0; i<1000; i++) {
+ ptrs[i] = (size_t*) threadalloc.malloc0(sizeof(size_t)+(i%32));
+ *ptrs[i] = size_t(threadalloc.talloc0) + i;
+ }
+ for (size_t i=0; i<1000; i++) {
+ if (*ptrs[i] != size_t(threadalloc.talloc0) + i)
+ This->numFailed++;
+ }
+ This->barrier.wait();
+ }
+ }
+
+ bool run ()
+ {
+ alloc = make_unique(new FastAllocator(nullptr,false));
+ numFailed.store(0);
+
+ size_t numThreads = getNumberOfLogicalThreads();
+ barrier.init(numThreads+1);
+
+ /* create threads */
+ std::vector<thread_t> threads;
+ for (size_t i=0; i<numThreads; i++)
+ threads.push_back(createThread((thread_func)thread_alloc,this));
+
+ /* run test */
+ for (size_t i=0; i<1000; i++)
+ {
+ alloc->reset();
+ barrier.wait();
+ barrier.wait();
+ }
+
+ /* destroy threads */
+ for (size_t i=0; i<numThreads; i++)
+ join(threads[i]);
+
+ alloc = nullptr;
+
+ return numFailed == 0;
+ }
+ };
+
+ fast_allocator_regression_test fast_allocator_regression;
+}
+
+
diff --git a/thirdparty/embree/kernels/common/alloc.h b/thirdparty/embree/kernels/common/alloc.h
new file mode 100644
index 0000000000..4458e35c24
--- /dev/null
+++ b/thirdparty/embree/kernels/common/alloc.h
@@ -0,0 +1,958 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "device.h"
+#include "scene.h"
+#include "primref.h"
+
+namespace embree
+{
+ class FastAllocator
+ {
+ /*! maximum supported alignment */
+ static const size_t maxAlignment = 64;
+
+ /*! maximum allocation size */
+
+ /* default settings */
+ //static const size_t defaultBlockSize = 4096;
+#define maxAllocationSize size_t(2*1024*1024-maxAlignment)
+
+ static const size_t MAX_THREAD_USED_BLOCK_SLOTS = 8;
+
+ public:
+
+ struct ThreadLocal2;
+ enum AllocationType { ALIGNED_MALLOC, OS_MALLOC, SHARED, ANY_TYPE };
+
+ /*! Per thread structure holding the current memory block. */
+ struct __aligned(64) ThreadLocal
+ {
+ ALIGNED_CLASS_(64);
+ public:
+
+ /*! Constructor for usage with ThreadLocalData */
+ __forceinline ThreadLocal (ThreadLocal2* parent)
+ : parent(parent), ptr(nullptr), cur(0), end(0), allocBlockSize(0), bytesUsed(0), bytesWasted(0) {}
+
+ /*! initialize allocator */
+ void init(FastAllocator* alloc)
+ {
+ ptr = nullptr;
+ cur = end = 0;
+ bytesUsed = 0;
+ bytesWasted = 0;
+ allocBlockSize = 0;
+ if (alloc) allocBlockSize = alloc->defaultBlockSize;
+ }
+
+ /* Allocate aligned memory from the threads memory block. */
+ __forceinline void* malloc(FastAllocator* alloc, size_t bytes, size_t align = 16)
+ {
+ /* bind the thread local allocator to the proper FastAllocator*/
+ parent->bind(alloc);
+
+ assert(align <= maxAlignment);
+ bytesUsed += bytes;
+
+ /* try to allocate in local block */
+ size_t ofs = (align - cur) & (align-1);
+ cur += bytes + ofs;
+ if (likely(cur <= end)) { bytesWasted += ofs; return &ptr[cur - bytes]; }
+ cur -= bytes + ofs;
+
+ /* if allocation is too large allocate with parent allocator */
+ if (4*bytes > allocBlockSize) {
+ return alloc->malloc(bytes,maxAlignment,false);
+ }
+
+ /* get new partial block if allocation failed */
+ size_t blockSize = allocBlockSize;
+ ptr = (char*) alloc->malloc(blockSize,maxAlignment,true);
+ bytesWasted += end-cur;
+ cur = 0; end = blockSize;
+
+ /* retry allocation */
+ ofs = (align - cur) & (align-1);
+ cur += bytes + ofs;
+ if (likely(cur <= end)) { bytesWasted += ofs; return &ptr[cur - bytes]; }
+ cur -= bytes + ofs;
+
+ /* get new full block if allocation failed */
+ blockSize = allocBlockSize;
+ ptr = (char*) alloc->malloc(blockSize,maxAlignment,false);
+ bytesWasted += end-cur;
+ cur = 0; end = blockSize;
+
+ /* retry allocation */
+ ofs = (align - cur) & (align-1);
+ cur += bytes + ofs;
+ if (likely(cur <= end)) { bytesWasted += ofs; return &ptr[cur - bytes]; }
+ cur -= bytes + ofs;
+
+ /* should never happen as large allocations get handled specially above */
+ assert(false);
+ return nullptr;
+ }
+
+
+ /*! returns amount of used bytes */
+ __forceinline size_t getUsedBytes() const { return bytesUsed; }
+
+ /*! returns amount of free bytes */
+ __forceinline size_t getFreeBytes() const { return end-cur; }
+
+ /*! returns amount of wasted bytes */
+ __forceinline size_t getWastedBytes() const { return bytesWasted; }
+
+ private:
+ ThreadLocal2* parent;
+ char* ptr; //!< pointer to memory block
+ size_t cur; //!< current location of the allocator
+ size_t end; //!< end of the memory block
+ size_t allocBlockSize; //!< block size for allocations
+ size_t bytesUsed; //!< number of total bytes allocated
+ size_t bytesWasted; //!< number of bytes wasted
+ };
+
+ /*! Two thread local structures. */
+ struct __aligned(64) ThreadLocal2
+ {
+ ALIGNED_CLASS_(64);
+ public:
+
+ __forceinline ThreadLocal2()
+ : alloc(nullptr), alloc0(this), alloc1(this) {}
+
+ /*! bind to fast allocator */
+ __forceinline void bind(FastAllocator* alloc_i)
+ {
+ assert(alloc_i);
+ if (alloc.load() == alloc_i) return;
+ Lock<SpinLock> lock(mutex);
+ //if (alloc.load() == alloc_i) return; // not required as only one thread calls bind
+ if (alloc.load()) {
+ alloc.load()->bytesUsed += alloc0.getUsedBytes() + alloc1.getUsedBytes();
+ alloc.load()->bytesFree += alloc0.getFreeBytes() + alloc1.getFreeBytes();
+ alloc.load()->bytesWasted += alloc0.getWastedBytes() + alloc1.getWastedBytes();
+ }
+ alloc0.init(alloc_i);
+ alloc1.init(alloc_i);
+ alloc.store(alloc_i);
+ alloc_i->join(this);
+ }
+
+ /*! unbind to fast allocator */
+ void unbind(FastAllocator* alloc_i)
+ {
+ assert(alloc_i);
+ if (alloc.load() != alloc_i) return;
+ Lock<SpinLock> lock(mutex);
+ if (alloc.load() != alloc_i) return; // required as a different thread calls unbind
+ alloc.load()->bytesUsed += alloc0.getUsedBytes() + alloc1.getUsedBytes();
+ alloc.load()->bytesFree += alloc0.getFreeBytes() + alloc1.getFreeBytes();
+ alloc.load()->bytesWasted += alloc0.getWastedBytes() + alloc1.getWastedBytes();
+ alloc0.init(nullptr);
+ alloc1.init(nullptr);
+ alloc.store(nullptr);
+ }
+
+ public:
+ SpinLock mutex; //!< required as unbind is called from other threads
+ std::atomic<FastAllocator*> alloc; //!< parent allocator
+ ThreadLocal alloc0;
+ ThreadLocal alloc1;
+ };
+
+ FastAllocator (Device* device, bool osAllocation)
+ : device(device), slotMask(0), usedBlocks(nullptr), freeBlocks(nullptr), use_single_mode(false), defaultBlockSize(PAGE_SIZE), estimatedSize(0),
+ growSize(PAGE_SIZE), maxGrowSize(maxAllocationSize), log2_grow_size_scale(0), bytesUsed(0), bytesFree(0), bytesWasted(0), atype(osAllocation ? OS_MALLOC : ALIGNED_MALLOC),
+ primrefarray(device,0)
+ {
+ for (size_t i=0; i<MAX_THREAD_USED_BLOCK_SLOTS; i++)
+ {
+ threadUsedBlocks[i] = nullptr;
+ threadBlocks[i] = nullptr;
+ assert(!slotMutex[i].isLocked());
+ }
+ }
+
+ ~FastAllocator () {
+ clear();
+ }
+
+ /*! returns the device attached to this allocator */
+ Device* getDevice() {
+ return device;
+ }
+
+ void share(mvector<PrimRef>& primrefarray_i) {
+ primrefarray = std::move(primrefarray_i);
+ }
+
+ void unshare(mvector<PrimRef>& primrefarray_o)
+ {
+ reset(); // this removes blocks that are allocated inside the shared primref array
+ primrefarray_o = std::move(primrefarray);
+ }
+
+ /*! returns first fast thread local allocator */
+ __forceinline ThreadLocal* _threadLocal() {
+ return &threadLocal2()->alloc0;
+ }
+
+ void setOSallocation(bool flag)
+ {
+ atype = flag ? OS_MALLOC : ALIGNED_MALLOC;
+ }
+
+ private:
+
+ /*! returns both fast thread local allocators */
+ __forceinline ThreadLocal2* threadLocal2()
+ {
+ ThreadLocal2* alloc = thread_local_allocator2;
+ if (alloc == nullptr) {
+ thread_local_allocator2 = alloc = new ThreadLocal2;
+ Lock<SpinLock> lock(s_thread_local_allocators_lock);
+ s_thread_local_allocators.push_back(make_unique(alloc));
+ }
+ return alloc;
+ }
+
+ public:
+
+ __forceinline void join(ThreadLocal2* alloc)
+ {
+ Lock<SpinLock> lock(thread_local_allocators_lock);
+ thread_local_allocators.push_back(alloc);
+ }
+
+ public:
+
+ struct CachedAllocator
+ {
+ __forceinline CachedAllocator(void* ptr)
+ : alloc(nullptr), talloc0(nullptr), talloc1(nullptr)
+ {
+ assert(ptr == nullptr);
+ }
+
+ __forceinline CachedAllocator(FastAllocator* alloc, ThreadLocal2* talloc)
+ : alloc(alloc), talloc0(&talloc->alloc0), talloc1(alloc->use_single_mode ? &talloc->alloc0 : &talloc->alloc1) {}
+
+ __forceinline operator bool () const {
+ return alloc != nullptr;
+ }
+
+ __forceinline void* operator() (size_t bytes, size_t align = 16) const {
+ return talloc0->malloc(alloc,bytes,align);
+ }
+
+ __forceinline void* malloc0 (size_t bytes, size_t align = 16) const {
+ return talloc0->malloc(alloc,bytes,align);
+ }
+
+ __forceinline void* malloc1 (size_t bytes, size_t align = 16) const {
+ return talloc1->malloc(alloc,bytes,align);
+ }
+
+ public:
+ FastAllocator* alloc;
+ ThreadLocal* talloc0;
+ ThreadLocal* talloc1;
+ };
+
+ __forceinline CachedAllocator getCachedAllocator() {
+ return CachedAllocator(this,threadLocal2());
+ }
+
+ /*! Builder interface to create thread local allocator */
+ struct Create
+ {
+ public:
+ __forceinline Create (FastAllocator* allocator) : allocator(allocator) {}
+ __forceinline CachedAllocator operator() () const { return allocator->getCachedAllocator(); }
+
+ private:
+ FastAllocator* allocator;
+ };
+
+ void internal_fix_used_blocks()
+ {
+ /* move thread local blocks to global block list */
+ for (size_t i = 0; i < MAX_THREAD_USED_BLOCK_SLOTS; i++)
+ {
+ while (threadBlocks[i].load() != nullptr) {
+ Block* nextUsedBlock = threadBlocks[i].load()->next;
+ threadBlocks[i].load()->next = usedBlocks.load();
+ usedBlocks = threadBlocks[i].load();
+ threadBlocks[i] = nextUsedBlock;
+ }
+ threadBlocks[i] = nullptr;
+ }
+ }
+
+ static const size_t threadLocalAllocOverhead = 20; //! 20 means 5% parallel allocation overhead through unfilled thread local blocks
+ static const size_t mainAllocOverheadStatic = 20; //! 20 means 5% allocation overhead through unfilled main alloc blocks
+ static const size_t mainAllocOverheadDynamic = 8; //! 20 means 12.5% allocation overhead through unfilled main alloc blocks
+
+ /* calculates a single threaded threshold for the builders such
+ * that for small scenes the overhead of partly allocated blocks
+ * per thread is low */
+ size_t fixSingleThreadThreshold(size_t branchingFactor, size_t defaultThreshold, size_t numPrimitives, size_t bytesEstimated)
+ {
+ if (numPrimitives == 0 || bytesEstimated == 0)
+ return defaultThreshold;
+
+ /* calculate block size in bytes to fulfill threadLocalAllocOverhead constraint */
+ const size_t single_mode_factor = use_single_mode ? 1 : 2;
+ const size_t threadCount = TaskScheduler::threadCount();
+ const size_t singleThreadBytes = single_mode_factor*threadLocalAllocOverhead*defaultBlockSize;
+
+ /* if we do not have to limit number of threads use optimal thresdhold */
+ if ( (bytesEstimated+(singleThreadBytes-1))/singleThreadBytes >= threadCount)
+ return defaultThreshold;
+
+ /* otherwise limit number of threads by calculating proper single thread threshold */
+ else {
+ double bytesPerPrimitive = double(bytesEstimated)/double(numPrimitives);
+ return size_t(ceil(branchingFactor*singleThreadBytes/bytesPerPrimitive));
+ }
+ }
+
+ __forceinline size_t alignSize(size_t i) {
+ return (i+127)/128*128;
+ }
+
+ /*! initializes the grow size */
+ __forceinline void initGrowSizeAndNumSlots(size_t bytesEstimated, bool fast)
+ {
+ /* we do not need single thread local allocator mode */
+ use_single_mode = false;
+
+ /* calculate growSize such that at most mainAllocationOverhead gets wasted when a block stays unused */
+ size_t mainAllocOverhead = fast ? mainAllocOverheadDynamic : mainAllocOverheadStatic;
+ size_t blockSize = alignSize(bytesEstimated/mainAllocOverhead);
+ growSize = maxGrowSize = clamp(blockSize,size_t(1024),maxAllocationSize);
+
+ /* if we reached the maxAllocationSize for growSize, we can
+ * increase the number of allocation slots by still guaranteeing
+ * the mainAllocationOverhead */
+ slotMask = 0x0;
+
+ if (MAX_THREAD_USED_BLOCK_SLOTS >= 2 && bytesEstimated > 2*mainAllocOverhead*growSize) slotMask = 0x1;
+ if (MAX_THREAD_USED_BLOCK_SLOTS >= 4 && bytesEstimated > 4*mainAllocOverhead*growSize) slotMask = 0x3;
+ if (MAX_THREAD_USED_BLOCK_SLOTS >= 8 && bytesEstimated > 8*mainAllocOverhead*growSize) slotMask = 0x7;
+ if (MAX_THREAD_USED_BLOCK_SLOTS >= 8 && bytesEstimated > 16*mainAllocOverhead*growSize) { growSize *= 2; } /* if the overhead is tiny, double the growSize */
+
+ /* set the thread local alloc block size */
+ size_t defaultBlockSizeSwitch = PAGE_SIZE+maxAlignment;
+
+ /* for sufficiently large scene we can increase the defaultBlockSize over the defaultBlockSizeSwitch size */
+#if 0 // we do not do this as a block size of 4160 if for some reason best for KNL
+ const size_t threadCount = TaskScheduler::threadCount();
+ const size_t single_mode_factor = use_single_mode ? 1 : 2;
+ const size_t singleThreadBytes = single_mode_factor*threadLocalAllocOverhead*defaultBlockSizeSwitch;
+ if (bytesEstimated+(singleThreadBytes-1))/singleThreadBytes >= threadCount)
+ defaultBlockSize = min(max(defaultBlockSizeSwitch,bytesEstimated/(single_mode_factor*threadLocalAllocOverhead*threadCount)),growSize);
+
+ /* otherwise we grow the defaultBlockSize up to defaultBlockSizeSwitch */
+ else
+#endif
+ defaultBlockSize = clamp(blockSize,size_t(1024),defaultBlockSizeSwitch);
+
+ if (bytesEstimated == 0) {
+ maxGrowSize = maxAllocationSize; // special mode if builder cannot estimate tree size
+ defaultBlockSize = defaultBlockSizeSwitch;
+ }
+ log2_grow_size_scale = 0;
+
+ if (device->alloc_main_block_size != 0) growSize = device->alloc_main_block_size;
+ if (device->alloc_num_main_slots >= 1 ) slotMask = 0x0;
+ if (device->alloc_num_main_slots >= 2 ) slotMask = 0x1;
+ if (device->alloc_num_main_slots >= 4 ) slotMask = 0x3;
+ if (device->alloc_num_main_slots >= 8 ) slotMask = 0x7;
+ if (device->alloc_thread_block_size != 0) defaultBlockSize = device->alloc_thread_block_size;
+ if (device->alloc_single_thread_alloc != -1) use_single_mode = device->alloc_single_thread_alloc;
+ }
+
+ /*! initializes the allocator */
+ void init(size_t bytesAllocate, size_t bytesReserve, size_t bytesEstimate)
+ {
+ internal_fix_used_blocks();
+ /* distribute the allocation to multiple thread block slots */
+ slotMask = MAX_THREAD_USED_BLOCK_SLOTS-1; // FIXME: remove
+ if (usedBlocks.load() || freeBlocks.load()) { reset(); return; }
+ if (bytesReserve == 0) bytesReserve = bytesAllocate;
+ freeBlocks = Block::create(device,bytesAllocate,bytesReserve,nullptr,atype);
+ estimatedSize = bytesEstimate;
+ initGrowSizeAndNumSlots(bytesEstimate,true);
+ }
+
+ /*! initializes the allocator */
+ void init_estimate(size_t bytesEstimate)
+ {
+ internal_fix_used_blocks();
+ if (usedBlocks.load() || freeBlocks.load()) { reset(); return; }
+ /* single allocator mode ? */
+ estimatedSize = bytesEstimate;
+ //initGrowSizeAndNumSlots(bytesEstimate,false);
+ initGrowSizeAndNumSlots(bytesEstimate,false);
+
+ }
+
+ /*! frees state not required after build */
+ __forceinline void cleanup()
+ {
+ internal_fix_used_blocks();
+
+ /* unbind all thread local allocators */
+ for (auto alloc : thread_local_allocators) alloc->unbind(this);
+ thread_local_allocators.clear();
+ }
+
+ /*! resets the allocator, memory blocks get reused */
+ void reset ()
+ {
+ internal_fix_used_blocks();
+
+ bytesUsed.store(0);
+ bytesFree.store(0);
+ bytesWasted.store(0);
+
+ /* reset all used blocks and move them to begin of free block list */
+ while (usedBlocks.load() != nullptr) {
+ usedBlocks.load()->reset_block();
+ Block* nextUsedBlock = usedBlocks.load()->next;
+ usedBlocks.load()->next = freeBlocks.load();
+ freeBlocks = usedBlocks.load();
+ usedBlocks = nextUsedBlock;
+ }
+
+ /* remove all shared blocks as they are re-added during build */
+ freeBlocks.store(Block::remove_shared_blocks(freeBlocks.load()));
+
+ for (size_t i=0; i<MAX_THREAD_USED_BLOCK_SLOTS; i++)
+ {
+ threadUsedBlocks[i] = nullptr;
+ threadBlocks[i] = nullptr;
+ }
+
+ /* unbind all thread local allocators */
+ for (auto alloc : thread_local_allocators) alloc->unbind(this);
+ thread_local_allocators.clear();
+ }
+
+ /*! frees all allocated memory */
+ __forceinline void clear()
+ {
+ cleanup();
+ bytesUsed.store(0);
+ bytesFree.store(0);
+ bytesWasted.store(0);
+ if (usedBlocks.load() != nullptr) usedBlocks.load()->clear_list(device); usedBlocks = nullptr;
+ if (freeBlocks.load() != nullptr) freeBlocks.load()->clear_list(device); freeBlocks = nullptr;
+ for (size_t i=0; i<MAX_THREAD_USED_BLOCK_SLOTS; i++) {
+ threadUsedBlocks[i] = nullptr;
+ threadBlocks[i] = nullptr;
+ }
+ primrefarray.clear();
+ }
+
+ __forceinline size_t incGrowSizeScale()
+ {
+ size_t scale = log2_grow_size_scale.fetch_add(1)+1;
+ return size_t(1) << min(size_t(16),scale);
+ }
+
+ /*! thread safe allocation of memory */
+ void* malloc(size_t& bytes, size_t align, bool partial)
+ {
+ assert(align <= maxAlignment);
+
+ while (true)
+ {
+ /* allocate using current block */
+ size_t threadID = TaskScheduler::threadID();
+ size_t slot = threadID & slotMask;
+ Block* myUsedBlocks = threadUsedBlocks[slot];
+ if (myUsedBlocks) {
+ void* ptr = myUsedBlocks->malloc(device,bytes,align,partial);
+ if (ptr) return ptr;
+ }
+
+ /* throw error if allocation is too large */
+ if (bytes > maxAllocationSize)
+ throw_RTCError(RTC_ERROR_UNKNOWN,"allocation is too large");
+
+ /* parallel block creation in case of no freeBlocks, avoids single global mutex */
+ if (likely(freeBlocks.load() == nullptr))
+ {
+ Lock<SpinLock> lock(slotMutex[slot]);
+ if (myUsedBlocks == threadUsedBlocks[slot]) {
+ const size_t alignedBytes = (bytes+(align-1)) & ~(align-1);
+ const size_t allocSize = max(min(growSize,maxGrowSize),alignedBytes);
+ assert(allocSize >= bytes);
+ threadBlocks[slot] = threadUsedBlocks[slot] = Block::create(device,allocSize,allocSize,threadBlocks[slot],atype); // FIXME: a large allocation might throw away a block here!
+ // FIXME: a direct allocation should allocate inside the block here, and not in the next loop! a different thread could do some allocation and make the large allocation fail.
+ }
+ continue;
+ }
+
+ /* if this fails allocate new block */
+ {
+ Lock<SpinLock> lock(mutex);
+ if (myUsedBlocks == threadUsedBlocks[slot])
+ {
+ if (freeBlocks.load() != nullptr) {
+ Block* nextFreeBlock = freeBlocks.load()->next;
+ freeBlocks.load()->next = usedBlocks;
+ __memory_barrier();
+ usedBlocks = freeBlocks.load();
+ threadUsedBlocks[slot] = freeBlocks.load();
+ freeBlocks = nextFreeBlock;
+ } else {
+ const size_t allocSize = min(growSize*incGrowSizeScale(),maxGrowSize);
+ usedBlocks = threadUsedBlocks[slot] = Block::create(device,allocSize,allocSize,usedBlocks,atype); // FIXME: a large allocation should get delivered directly, like above!
+ }
+ }
+ }
+ }
+ }
+
+ /*! add new block */
+ void addBlock(void* ptr, ssize_t bytes)
+ {
+ Lock<SpinLock> lock(mutex);
+ const size_t sizeof_Header = offsetof(Block,data[0]);
+ void* aptr = (void*) ((((size_t)ptr)+maxAlignment-1) & ~(maxAlignment-1));
+ size_t ofs = (size_t) aptr - (size_t) ptr;
+ bytes -= ofs;
+ if (bytes < 4096) return; // ignore empty or very small blocks
+ freeBlocks = new (aptr) Block(SHARED,bytes-sizeof_Header,bytes-sizeof_Header,freeBlocks,ofs);
+ }
+
+ /* special allocation only used from morton builder only a single time for each build */
+ void* specialAlloc(size_t bytes)
+ {
+ assert(freeBlocks.load() != nullptr && freeBlocks.load()->getBlockAllocatedBytes() >= bytes);
+ return freeBlocks.load()->ptr();
+ }
+
+ struct Statistics
+ {
+ Statistics ()
+ : bytesUsed(0), bytesFree(0), bytesWasted(0) {}
+
+ Statistics (size_t bytesUsed, size_t bytesFree, size_t bytesWasted)
+ : bytesUsed(bytesUsed), bytesFree(bytesFree), bytesWasted(bytesWasted) {}
+
+ Statistics (FastAllocator* alloc, AllocationType atype, bool huge_pages = false)
+ : bytesUsed(0), bytesFree(0), bytesWasted(0)
+ {
+ Block* usedBlocks = alloc->usedBlocks.load();
+ Block* freeBlocks = alloc->freeBlocks.load();
+ if (usedBlocks) bytesUsed += usedBlocks->getUsedBytes(atype,huge_pages);
+ if (freeBlocks) bytesFree += freeBlocks->getAllocatedBytes(atype,huge_pages);
+ if (usedBlocks) bytesFree += usedBlocks->getFreeBytes(atype,huge_pages);
+ if (freeBlocks) bytesWasted += freeBlocks->getWastedBytes(atype,huge_pages);
+ if (usedBlocks) bytesWasted += usedBlocks->getWastedBytes(atype,huge_pages);
+ }
+
+ std::string str(size_t numPrimitives)
+ {
+ std::stringstream str;
+ str.setf(std::ios::fixed, std::ios::floatfield);
+ str << "used = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesUsed << " MB, "
+ << "free = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesFree << " MB, "
+ << "wasted = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesWasted << " MB, "
+ << "total = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesAllocatedTotal() << " MB, "
+ << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytesAllocatedTotal())/double(numPrimitives);
+ return str.str();
+ }
+
+ friend Statistics operator+ ( const Statistics& a, const Statistics& b)
+ {
+ return Statistics(a.bytesUsed+b.bytesUsed,
+ a.bytesFree+b.bytesFree,
+ a.bytesWasted+b.bytesWasted);
+ }
+
+ size_t bytesAllocatedTotal() const {
+ return bytesUsed + bytesFree + bytesWasted;
+ }
+
+ public:
+ size_t bytesUsed;
+ size_t bytesFree;
+ size_t bytesWasted;
+ };
+
+ Statistics getStatistics(AllocationType atype, bool huge_pages = false) {
+ return Statistics(this,atype,huge_pages);
+ }
+
+ size_t getUsedBytes() {
+ return bytesUsed;
+ }
+
+ size_t getWastedBytes() {
+ return bytesWasted;
+ }
+
+ struct AllStatistics
+ {
+ AllStatistics (FastAllocator* alloc)
+
+ : bytesUsed(alloc->bytesUsed),
+ bytesFree(alloc->bytesFree),
+ bytesWasted(alloc->bytesWasted),
+ stat_all(alloc,ANY_TYPE),
+ stat_malloc(alloc,ALIGNED_MALLOC),
+ stat_4K(alloc,OS_MALLOC,false),
+ stat_2M(alloc,OS_MALLOC,true),
+ stat_shared(alloc,SHARED) {}
+
+ AllStatistics (size_t bytesUsed,
+ size_t bytesFree,
+ size_t bytesWasted,
+ Statistics stat_all,
+ Statistics stat_malloc,
+ Statistics stat_4K,
+ Statistics stat_2M,
+ Statistics stat_shared)
+
+ : bytesUsed(bytesUsed),
+ bytesFree(bytesFree),
+ bytesWasted(bytesWasted),
+ stat_all(stat_all),
+ stat_malloc(stat_malloc),
+ stat_4K(stat_4K),
+ stat_2M(stat_2M),
+ stat_shared(stat_shared) {}
+
+ friend AllStatistics operator+ (const AllStatistics& a, const AllStatistics& b)
+ {
+ return AllStatistics(a.bytesUsed+b.bytesUsed,
+ a.bytesFree+b.bytesFree,
+ a.bytesWasted+b.bytesWasted,
+ a.stat_all + b.stat_all,
+ a.stat_malloc + b.stat_malloc,
+ a.stat_4K + b.stat_4K,
+ a.stat_2M + b.stat_2M,
+ a.stat_shared + b.stat_shared);
+ }
+
+ void print(size_t numPrimitives)
+ {
+ std::stringstream str0;
+ str0.setf(std::ios::fixed, std::ios::floatfield);
+ str0 << " alloc : "
+ << "used = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesUsed << " MB, "
+ << " "
+ << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytesUsed)/double(numPrimitives);
+ std::cout << str0.str() << std::endl;
+
+ std::stringstream str1;
+ str1.setf(std::ios::fixed, std::ios::floatfield);
+ str1 << " alloc : "
+ << "used = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesUsed << " MB, "
+ << "free = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesFree << " MB, "
+ << "wasted = " << std::setw(7) << std::setprecision(3) << 1E-6f*bytesWasted << " MB, "
+ << "total = " << std::setw(7) << std::setprecision(3) << 1E-6f*(bytesUsed+bytesFree+bytesWasted) << " MB, "
+ << "#bytes/prim = " << std::setw(6) << std::setprecision(2) << double(bytesUsed+bytesFree+bytesWasted)/double(numPrimitives);
+ std::cout << str1.str() << std::endl;
+
+ std::cout << " total : " << stat_all.str(numPrimitives) << std::endl;
+ std::cout << " 4K : " << stat_4K.str(numPrimitives) << std::endl;
+ std::cout << " 2M : " << stat_2M.str(numPrimitives) << std::endl;
+ std::cout << " malloc: " << stat_malloc.str(numPrimitives) << std::endl;
+ std::cout << " shared: " << stat_shared.str(numPrimitives) << std::endl;
+ }
+
+ private:
+ size_t bytesUsed;
+ size_t bytesFree;
+ size_t bytesWasted;
+ Statistics stat_all;
+ Statistics stat_malloc;
+ Statistics stat_4K;
+ Statistics stat_2M;
+ Statistics stat_shared;
+ };
+
+ void print_blocks()
+ {
+ std::cout << " estimatedSize = " << estimatedSize << ", slotMask = " << slotMask << ", use_single_mode = " << use_single_mode << ", maxGrowSize = " << maxGrowSize << ", defaultBlockSize = " << defaultBlockSize << std::endl;
+
+ std::cout << " used blocks = ";
+ if (usedBlocks.load() != nullptr) usedBlocks.load()->print_list();
+ std::cout << "[END]" << std::endl;
+
+ std::cout << " free blocks = ";
+ if (freeBlocks.load() != nullptr) freeBlocks.load()->print_list();
+ std::cout << "[END]" << std::endl;
+ }
+
+ private:
+
+ struct Block
+ {
+ static Block* create(MemoryMonitorInterface* device, size_t bytesAllocate, size_t bytesReserve, Block* next, AllocationType atype)
+ {
+ /* We avoid using os_malloc for small blocks as this could
+ * cause a risk of fragmenting the virtual address space and
+ * reach the limit of vm.max_map_count = 65k under Linux. */
+ if (atype == OS_MALLOC && bytesAllocate < maxAllocationSize)
+ atype = ALIGNED_MALLOC;
+
+ /* we need to additionally allocate some header */
+ const size_t sizeof_Header = offsetof(Block,data[0]);
+ bytesAllocate = sizeof_Header+bytesAllocate;
+ bytesReserve = sizeof_Header+bytesReserve;
+
+ /* consume full 4k pages with using os_malloc */
+ if (atype == OS_MALLOC) {
+ bytesAllocate = ((bytesAllocate+PAGE_SIZE-1) & ~(PAGE_SIZE-1));
+ bytesReserve = ((bytesReserve +PAGE_SIZE-1) & ~(PAGE_SIZE-1));
+ }
+
+ /* either use alignedMalloc or os_malloc */
+ void *ptr = nullptr;
+ if (atype == ALIGNED_MALLOC)
+ {
+ /* special handling for default block size */
+ if (bytesAllocate == (2*PAGE_SIZE_2M))
+ {
+ const size_t alignment = maxAlignment;
+ if (device) device->memoryMonitor(bytesAllocate+alignment,false);
+ ptr = alignedMalloc(bytesAllocate,alignment);
+
+ /* give hint to transparently convert these pages to 2MB pages */
+ const size_t ptr_aligned_begin = ((size_t)ptr) & ~size_t(PAGE_SIZE_2M-1);
+ os_advise((void*)(ptr_aligned_begin + 0),PAGE_SIZE_2M); // may fail if no memory mapped before block
+ os_advise((void*)(ptr_aligned_begin + 1*PAGE_SIZE_2M),PAGE_SIZE_2M);
+ os_advise((void*)(ptr_aligned_begin + 2*PAGE_SIZE_2M),PAGE_SIZE_2M); // may fail if no memory mapped after block
+
+ return new (ptr) Block(ALIGNED_MALLOC,bytesAllocate-sizeof_Header,bytesAllocate-sizeof_Header,next,alignment);
+ }
+ else
+ {
+ const size_t alignment = maxAlignment;
+ if (device) device->memoryMonitor(bytesAllocate+alignment,false);
+ ptr = alignedMalloc(bytesAllocate,alignment);
+ return new (ptr) Block(ALIGNED_MALLOC,bytesAllocate-sizeof_Header,bytesAllocate-sizeof_Header,next,alignment);
+ }
+ }
+ else if (atype == OS_MALLOC)
+ {
+ if (device) device->memoryMonitor(bytesAllocate,false);
+ bool huge_pages; ptr = os_malloc(bytesReserve,huge_pages);
+ return new (ptr) Block(OS_MALLOC,bytesAllocate-sizeof_Header,bytesReserve-sizeof_Header,next,0,huge_pages);
+ }
+ else
+ assert(false);
+
+ return NULL;
+ }
+
+ Block (AllocationType atype, size_t bytesAllocate, size_t bytesReserve, Block* next, size_t wasted, bool huge_pages = false)
+ : cur(0), allocEnd(bytesAllocate), reserveEnd(bytesReserve), next(next), wasted(wasted), atype(atype), huge_pages(huge_pages)
+ {
+ assert((((size_t)&data[0]) & (maxAlignment-1)) == 0);
+ }
+
+ static Block* remove_shared_blocks(Block* head)
+ {
+ Block** prev_next = &head;
+ for (Block* block = head; block; block = block->next) {
+ if (block->atype == SHARED) *prev_next = block->next;
+ else prev_next = &block->next;
+ }
+ return head;
+ }
+
+ void clear_list(MemoryMonitorInterface* device)
+ {
+ Block* block = this;
+ while (block) {
+ Block* next = block->next;
+ block->clear_block(device);
+ block = next;
+ }
+ }
+
+ void clear_block (MemoryMonitorInterface* device)
+ {
+ const size_t sizeof_Header = offsetof(Block,data[0]);
+ const ssize_t sizeof_Alloced = wasted+sizeof_Header+getBlockAllocatedBytes();
+
+ if (atype == ALIGNED_MALLOC) {
+ alignedFree(this);
+ if (device) device->memoryMonitor(-sizeof_Alloced,true);
+ }
+
+ else if (atype == OS_MALLOC) {
+ size_t sizeof_This = sizeof_Header+reserveEnd;
+ os_free(this,sizeof_This,huge_pages);
+ if (device) device->memoryMonitor(-sizeof_Alloced,true);
+ }
+
+ else /* if (atype == SHARED) */ {
+ }
+ }
+
+ void* malloc(MemoryMonitorInterface* device, size_t& bytes_in, size_t align, bool partial)
+ {
+ size_t bytes = bytes_in;
+ assert(align <= maxAlignment);
+ bytes = (bytes+(align-1)) & ~(align-1);
+ if (unlikely(cur+bytes > reserveEnd && !partial)) return nullptr;
+ const size_t i = cur.fetch_add(bytes);
+ if (unlikely(i+bytes > reserveEnd && !partial)) return nullptr;
+ if (unlikely(i > reserveEnd)) return nullptr;
+ bytes_in = bytes = min(bytes,reserveEnd-i);
+
+ if (i+bytes > allocEnd) {
+ if (device) device->memoryMonitor(i+bytes-max(i,allocEnd),true);
+ }
+ return &data[i];
+ }
+
+ void* ptr() {
+ return &data[cur];
+ }
+
+ void reset_block ()
+ {
+ allocEnd = max(allocEnd,(size_t)cur);
+ cur = 0;
+ }
+
+ size_t getBlockUsedBytes() const {
+ return min(size_t(cur),reserveEnd);
+ }
+
+ size_t getBlockFreeBytes() const {
+ return getBlockAllocatedBytes() - getBlockUsedBytes();
+ }
+
+ size_t getBlockAllocatedBytes() const {
+ return min(max(allocEnd,size_t(cur)),reserveEnd);
+ }
+
+ size_t getBlockWastedBytes() const {
+ const size_t sizeof_Header = offsetof(Block,data[0]);
+ return sizeof_Header + wasted;
+ }
+
+ size_t getBlockReservedBytes() const {
+ return reserveEnd;
+ }
+
+ bool hasType(AllocationType atype_i, bool huge_pages_i) const
+ {
+ if (atype_i == ANY_TYPE ) return true;
+ else if (atype == OS_MALLOC) return atype_i == atype && huge_pages_i == huge_pages;
+ else return atype_i == atype;
+ }
+
+ size_t getUsedBytes(AllocationType atype, bool huge_pages = false) const {
+ size_t bytes = 0;
+ for (const Block* block = this; block; block = block->next) {
+ if (!block->hasType(atype,huge_pages)) continue;
+ bytes += block->getBlockUsedBytes();
+ }
+ return bytes;
+ }
+
+ size_t getFreeBytes(AllocationType atype, bool huge_pages = false) const {
+ size_t bytes = 0;
+ for (const Block* block = this; block; block = block->next) {
+ if (!block->hasType(atype,huge_pages)) continue;
+ bytes += block->getBlockFreeBytes();
+ }
+ return bytes;
+ }
+
+ size_t getWastedBytes(AllocationType atype, bool huge_pages = false) const {
+ size_t bytes = 0;
+ for (const Block* block = this; block; block = block->next) {
+ if (!block->hasType(atype,huge_pages)) continue;
+ bytes += block->getBlockWastedBytes();
+ }
+ return bytes;
+ }
+
+ size_t getAllocatedBytes(AllocationType atype, bool huge_pages = false) const {
+ size_t bytes = 0;
+ for (const Block* block = this; block; block = block->next) {
+ if (!block->hasType(atype,huge_pages)) continue;
+ bytes += block->getBlockAllocatedBytes();
+ }
+ return bytes;
+ }
+
+ void print_list ()
+ {
+ for (const Block* block = this; block; block = block->next)
+ block->print_block();
+ }
+
+ void print_block() const
+ {
+ if (atype == ALIGNED_MALLOC) std::cout << "A";
+ else if (atype == OS_MALLOC) std::cout << "O";
+ else if (atype == SHARED) std::cout << "S";
+ if (huge_pages) std::cout << "H";
+ size_t bytesUsed = getBlockUsedBytes();
+ size_t bytesFree = getBlockFreeBytes();
+ size_t bytesWasted = getBlockWastedBytes();
+ std::cout << "[" << bytesUsed << ", " << bytesFree << ", " << bytesWasted << "] ";
+ }
+
+ public:
+ std::atomic<size_t> cur; //!< current location of the allocator
+ std::atomic<size_t> allocEnd; //!< end of the allocated memory region
+ std::atomic<size_t> reserveEnd; //!< end of the reserved memory region
+ Block* next; //!< pointer to next block in list
+ size_t wasted; //!< amount of memory wasted through block alignment
+ AllocationType atype; //!< allocation mode of the block
+ bool huge_pages; //!< whether the block uses huge pages
+ char align[maxAlignment-5*sizeof(size_t)-sizeof(AllocationType)-sizeof(bool)]; //!< align data to maxAlignment
+ char data[1]; //!< here starts memory to use for allocations
+ };
+
+ private:
+ Device* device;
+ SpinLock mutex;
+ size_t slotMask;
+ std::atomic<Block*> threadUsedBlocks[MAX_THREAD_USED_BLOCK_SLOTS];
+ std::atomic<Block*> usedBlocks;
+ std::atomic<Block*> freeBlocks;
+
+ std::atomic<Block*> threadBlocks[MAX_THREAD_USED_BLOCK_SLOTS];
+ SpinLock slotMutex[MAX_THREAD_USED_BLOCK_SLOTS];
+
+ bool use_single_mode;
+ size_t defaultBlockSize;
+ size_t estimatedSize;
+ size_t growSize;
+ size_t maxGrowSize;
+ std::atomic<size_t> log2_grow_size_scale; //!< log2 of scaling factor for grow size // FIXME: remove
+ std::atomic<size_t> bytesUsed;
+ std::atomic<size_t> bytesFree;
+ std::atomic<size_t> bytesWasted;
+ static __thread ThreadLocal2* thread_local_allocator2;
+ static SpinLock s_thread_local_allocators_lock;
+ static std::vector<std::unique_ptr<ThreadLocal2>> s_thread_local_allocators;
+ SpinLock thread_local_allocators_lock;
+ std::vector<ThreadLocal2*> thread_local_allocators;
+ AllocationType atype;
+ mvector<PrimRef> primrefarray; //!< primrefarray used to allocate nodes
+ };
+}
diff --git a/thirdparty/embree/kernels/common/buffer.h b/thirdparty/embree/kernels/common/buffer.h
new file mode 100644
index 0000000000..793012c04d
--- /dev/null
+++ b/thirdparty/embree/kernels/common/buffer.h
@@ -0,0 +1,263 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "device.h"
+
+namespace embree
+{
+ /*! Implements an API data buffer object. This class may or may not own the data. */
+ class Buffer : public RefCount
+ {
+ public:
+ /*! Buffer construction */
+ Buffer()
+ : device(nullptr), ptr(nullptr), numBytes(0), shared(false) {}
+
+ /*! Buffer construction */
+ Buffer(Device* device, size_t numBytes_in, void* ptr_in = nullptr)
+ : device(device), numBytes(numBytes_in)
+ {
+ device->refInc();
+
+ if (ptr_in)
+ {
+ shared = true;
+ ptr = (char*)ptr_in;
+ }
+ else
+ {
+ shared = false;
+ alloc();
+ }
+ }
+
+ /*! Buffer destruction */
+ ~Buffer() {
+ free();
+ device->refDec();
+ }
+
+ /*! this class is not copyable */
+ private:
+ Buffer(const Buffer& other) DELETED; // do not implement
+ Buffer& operator =(const Buffer& other) DELETED; // do not implement
+
+ public:
+ /* inits and allocates the buffer */
+ void create(Device* device_in, size_t numBytes_in)
+ {
+ init(device_in, numBytes_in);
+ alloc();
+ }
+
+ /* inits the buffer */
+ void init(Device* device_in, size_t numBytes_in)
+ {
+ free();
+ device = device_in;
+ ptr = nullptr;
+ numBytes = numBytes_in;
+ shared = false;
+ }
+
+ /*! sets shared buffer */
+ void set(Device* device_in, void* ptr_in, size_t numBytes_in)
+ {
+ free();
+ device = device_in;
+ ptr = (char*)ptr_in;
+ if (numBytes_in != (size_t)-1)
+ numBytes = numBytes_in;
+ shared = true;
+ }
+
+ /*! allocated buffer */
+ void alloc()
+ {
+ if (device)
+ device->memoryMonitor(this->bytes(), false);
+ size_t b = (this->bytes()+15) & ssize_t(-16);
+ ptr = (char*)alignedMalloc(b,16);
+ }
+
+ /*! frees the buffer */
+ void free()
+ {
+ if (shared) return;
+ alignedFree(ptr);
+ if (device)
+ device->memoryMonitor(-ssize_t(this->bytes()), true);
+ ptr = nullptr;
+ }
+
+ /*! gets buffer pointer */
+ void* data()
+ {
+ /* report error if buffer is not existing */
+ if (!device)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer specified");
+
+ /* return buffer */
+ return ptr;
+ }
+
+ /*! returns pointer to first element */
+ __forceinline char* getPtr() const {
+ return ptr;
+ }
+
+ /*! returns the number of bytes of the buffer */
+ __forceinline size_t bytes() const {
+ return numBytes;
+ }
+
+ /*! returns true of the buffer is not empty */
+ __forceinline operator bool() const {
+ return ptr;
+ }
+
+ public:
+ Device* device; //!< device to report memory usage to
+ char* ptr; //!< pointer to buffer data
+ size_t numBytes; //!< number of bytes in the buffer
+ bool shared; //!< set if memory is shared with application
+ };
+
+ /*! An untyped contiguous range of a buffer. This class does not own the buffer content. */
+ class RawBufferView
+ {
+ public:
+ /*! Buffer construction */
+ RawBufferView()
+ : ptr_ofs(nullptr), stride(0), num(0), format(RTC_FORMAT_UNDEFINED), modCounter(1), modified(true), userData(0) {}
+
+ public:
+ /*! sets the buffer view */
+ void set(const Ref<Buffer>& buffer_in, size_t offset_in, size_t stride_in, size_t num_in, RTCFormat format_in)
+ {
+ if ((offset_in + stride_in * num_in) > (stride_in * buffer_in->numBytes))
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "buffer range out of bounds");
+
+ ptr_ofs = buffer_in->ptr + offset_in;
+ stride = stride_in;
+ num = num_in;
+ format = format_in;
+ modCounter++;
+ modified = true;
+ buffer = buffer_in;
+ }
+
+ /*! returns pointer to the first element */
+ __forceinline char* getPtr() const {
+ return ptr_ofs;
+ }
+
+ /*! returns pointer to the i'th element */
+ __forceinline char* getPtr(size_t i) const
+ {
+ assert(i<num);
+ return ptr_ofs + i*stride;
+ }
+
+ /*! returns the number of elements of the buffer */
+ __forceinline size_t size() const {
+ return num;
+ }
+
+ /*! returns the number of bytes of the buffer */
+ __forceinline size_t bytes() const {
+ return num*stride;
+ }
+
+ /*! returns the buffer stride */
+ __forceinline unsigned getStride() const
+ {
+ assert(stride <= unsigned(inf));
+ return unsigned(stride);
+ }
+
+ /*! return the buffer format */
+ __forceinline RTCFormat getFormat() const {
+ return format;
+ }
+
+ /*! mark buffer as modified or unmodified */
+ __forceinline void setModified() {
+ modCounter++;
+ modified = true;
+ }
+
+ /*! mark buffer as modified or unmodified */
+ __forceinline bool isModified(unsigned int otherModCounter) const {
+ return modCounter > otherModCounter;
+ }
+
+ /*! mark buffer as modified or unmodified */
+ __forceinline bool isLocalModified() const {
+ return modified;
+ }
+
+ /*! clear local modified flag */
+ __forceinline void clearLocalModified() {
+ modified = false;
+ }
+
+ /*! returns true of the buffer is not empty */
+ __forceinline operator bool() const {
+ return ptr_ofs;
+ }
+
+ /*! checks padding to 16 byte check, fails hard */
+ __forceinline void checkPadding16() const
+ {
+ if (ptr_ofs && num)
+ volatile int MAYBE_UNUSED w = *((int*)getPtr(size()-1)+3); // FIXME: is failing hard avoidable?
+ }
+
+ public:
+ char* ptr_ofs; //!< base pointer plus offset
+ size_t stride; //!< stride of the buffer in bytes
+ size_t num; //!< number of elements in the buffer
+ RTCFormat format; //!< format of the buffer
+ unsigned int modCounter; //!< version ID of this buffer
+ bool modified; //!< local modified data
+ int userData; //!< special data
+ Ref<Buffer> buffer; //!< reference to the parent buffer
+ };
+
+ /*! A typed contiguous range of a buffer. This class does not own the buffer content. */
+ template<typename T>
+ class BufferView : public RawBufferView
+ {
+ public:
+ typedef T value_type;
+
+ /*! access to the ith element of the buffer */
+ __forceinline T& operator [](size_t i) { assert(i<num); return *(T*)(ptr_ofs + i*stride); }
+ __forceinline const T& operator [](size_t i) const { assert(i<num); return *(T*)(ptr_ofs + i*stride); }
+ };
+
+ template<>
+ class BufferView<Vec3fa> : public RawBufferView
+ {
+ public:
+ typedef Vec3fa value_type;
+
+ /*! access to the ith element of the buffer */
+ __forceinline const Vec3fa operator [](size_t i) const
+ {
+ assert(i<num);
+ return Vec3fa(vfloat4::loadu((float*)(ptr_ofs + i*stride)));
+ }
+
+ /*! writes the i'th element */
+ __forceinline void store(size_t i, const Vec3fa& v)
+ {
+ assert(i<num);
+ vfloat4::storeu((float*)(ptr_ofs + i*stride), (vfloat4)v);
+ }
+ };
+}
diff --git a/thirdparty/embree/kernels/common/builder.h b/thirdparty/embree/kernels/common/builder.h
new file mode 100644
index 0000000000..07fe7b069b
--- /dev/null
+++ b/thirdparty/embree/kernels/common/builder.h
@@ -0,0 +1,60 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "accel.h"
+
+namespace embree
+{
+#define MODE_HIGH_QUALITY (1<<8)
+
+ /*! virtual interface for all hierarchy builders */
+ class Builder : public RefCount {
+ public:
+
+ static const size_t DEFAULT_SINGLE_THREAD_THRESHOLD = 1024;
+
+ /*! initiates the hierarchy builder */
+ virtual void build() = 0;
+
+ /*! notifies the builder about the deletion of some geometry */
+ virtual void deleteGeometry(size_t geomID) {};
+
+ /*! clears internal builder state */
+ virtual void clear() = 0;
+ };
+
+ /*! virtual interface for progress monitor class */
+ struct BuildProgressMonitor {
+ virtual void operator() (size_t dn) const = 0;
+ };
+
+ /*! build the progress monitor interface from a closure */
+ template<typename Closure>
+ struct ProgressMonitorClosure : BuildProgressMonitor
+ {
+ public:
+ ProgressMonitorClosure (const Closure& closure) : closure(closure) {}
+ void operator() (size_t dn) const { closure(dn); }
+ private:
+ const Closure closure;
+ };
+ template<typename Closure> __forceinline const ProgressMonitorClosure<Closure> BuildProgressMonitorFromClosure(const Closure& closure) {
+ return ProgressMonitorClosure<Closure>(closure);
+ }
+
+ struct LineSegments;
+ struct TriangleMesh;
+ struct QuadMesh;
+ struct UserGeometry;
+
+ class Scene;
+
+ typedef void (*createLineSegmentsAccelTy)(Scene* scene, LineSegments* mesh, AccelData*& accel, Builder*& builder);
+ typedef void (*createTriangleMeshAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);
+ typedef void (*createQuadMeshAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);
+ typedef void (*createUserGeometryAccelTy)(Scene* scene, unsigned int geomID, AccelData*& accel, Builder*& builder);
+
+}
diff --git a/thirdparty/embree/kernels/common/context.h b/thirdparty/embree/kernels/common/context.h
new file mode 100644
index 0000000000..ccd88bdeac
--- /dev/null
+++ b/thirdparty/embree/kernels/common/context.h
@@ -0,0 +1,131 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "rtcore.h"
+#include "point_query.h"
+
+namespace embree
+{
+ class Scene;
+
+ struct IntersectContext
+ {
+ public:
+ __forceinline IntersectContext(Scene* scene, RTCIntersectContext* user_context)
+ : scene(scene), user(user_context) {}
+
+ __forceinline bool hasContextFilter() const {
+ return user->filter != nullptr;
+ }
+
+ __forceinline bool isCoherent() const {
+ return embree::isCoherent(user->flags);
+ }
+
+ __forceinline bool isIncoherent() const {
+ return embree::isIncoherent(user->flags);
+ }
+
+ public:
+ Scene* scene;
+ RTCIntersectContext* user;
+ };
+
+ template<int M, typename Geometry>
+ __forceinline Vec4vf<M> enlargeRadiusToMinWidth(const IntersectContext* context, const Geometry* geom, const Vec3vf<M>& ray_org, const Vec4vf<M>& v)
+ {
+#if RTC_MIN_WIDTH
+ const vfloat<M> d = length(Vec3vf<M>(v) - ray_org);
+ const vfloat<M> r = clamp(context->user->minWidthDistanceFactor*d, v.w, geom->maxRadiusScale*v.w);
+ return Vec4vf<M>(v.x,v.y,v.z,r);
+#else
+ return v;
+#endif
+ }
+
+ template<typename Geometry>
+ __forceinline Vec3ff enlargeRadiusToMinWidth(const IntersectContext* context, const Geometry* geom, const Vec3fa& ray_org, const Vec3ff& v)
+ {
+#if RTC_MIN_WIDTH
+ const float d = length(Vec3fa(v) - ray_org);
+ const float r = clamp(context->user->minWidthDistanceFactor*d, v.w, geom->maxRadiusScale*v.w);
+ return Vec3ff(v.x,v.y,v.z,r);
+#else
+ return v;
+#endif
+ }
+
+ enum PointQueryType
+ {
+ POINT_QUERY_TYPE_UNDEFINED = 0,
+ POINT_QUERY_TYPE_SPHERE = 1,
+ POINT_QUERY_TYPE_AABB = 2,
+ };
+
+ typedef bool (*PointQueryFunction)(struct RTCPointQueryFunctionArguments* args);
+
+ struct PointQueryContext
+ {
+ public:
+ __forceinline PointQueryContext(Scene* scene,
+ PointQuery* query_ws,
+ PointQueryType query_type,
+ PointQueryFunction func,
+ RTCPointQueryContext* userContext,
+ float similarityScale,
+ void* userPtr)
+ : scene(scene)
+ , query_ws(query_ws)
+ , query_type(query_type)
+ , func(func)
+ , userContext(userContext)
+ , similarityScale(similarityScale)
+ , userPtr(userPtr)
+ , primID(RTC_INVALID_GEOMETRY_ID)
+ , geomID(RTC_INVALID_GEOMETRY_ID)
+ , query_radius(query_ws->radius)
+ {
+ if (query_type == POINT_QUERY_TYPE_AABB) {
+ assert(similarityScale == 0.f);
+ updateAABB();
+ }
+ if (userContext->instStackSize == 0) {
+ assert(similarityScale == 1.f);
+ }
+ }
+
+ public:
+ __forceinline void updateAABB()
+ {
+ if (likely(query_ws->radius == (float)inf || userContext->instStackSize == 0)) {
+ query_radius = Vec3fa(query_ws->radius);
+ return;
+ }
+
+ const AffineSpace3fa m = AffineSpace3fa_load_unaligned((AffineSpace3fa*)userContext->world2inst[userContext->instStackSize-1]);
+ BBox3fa bbox(Vec3fa(-query_ws->radius), Vec3fa(query_ws->radius));
+ bbox = xfmBounds(m, bbox);
+ query_radius = 0.5f * (bbox.upper - bbox.lower);
+ }
+
+public:
+ Scene* scene;
+
+ PointQuery* query_ws; // the original world space point query
+ PointQueryType query_type;
+ PointQueryFunction func;
+ RTCPointQueryContext* userContext;
+ const float similarityScale;
+
+ void* userPtr;
+
+ unsigned int primID;
+ unsigned int geomID;
+
+ Vec3fa query_radius; // used if the query is converted to an AABB internally
+ };
+}
+
diff --git a/thirdparty/embree/kernels/common/default.h b/thirdparty/embree/kernels/common/default.h
new file mode 100644
index 0000000000..f15d61b768
--- /dev/null
+++ b/thirdparty/embree/kernels/common/default.h
@@ -0,0 +1,268 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../../common/sys/platform.h"
+#include "../../common/sys/sysinfo.h"
+#include "../../common/sys/thread.h"
+#include "../../common/sys/alloc.h"
+#include "../../common/sys/ref.h"
+#include "../../common/sys/intrinsics.h"
+#include "../../common/sys/atomic.h"
+#include "../../common/sys/mutex.h"
+#include "../../common/sys/vector.h"
+#include "../../common/sys/array.h"
+#include "../../common/sys/string.h"
+#include "../../common/sys/regression.h"
+#include "../../common/sys/vector.h"
+
+#include "../../common/math/math.h"
+#include "../../common/math/transcendental.h"
+#include "../../common/simd/simd.h"
+#include "../../common/math/vec2.h"
+#include "../../common/math/vec3.h"
+#include "../../common/math/vec4.h"
+#include "../../common/math/vec2fa.h"
+#include "../../common/math/vec3fa.h"
+#include "../../common/math/interval.h"
+#include "../../common/math/bbox.h"
+#include "../../common/math/obbox.h"
+#include "../../common/math/lbbox.h"
+#include "../../common/math/linearspace2.h"
+#include "../../common/math/linearspace3.h"
+#include "../../common/math/affinespace.h"
+#include "../../common/math/range.h"
+#include "../../common/lexers/tokenstream.h"
+
+#include "../../common/tasking/taskscheduler.h"
+
+#define COMMA ,
+
+#include "../config.h"
+#include "isa.h"
+#include "stat.h"
+#include "profile.h"
+#include "rtcore.h"
+#include "vector.h"
+#include "state.h"
+#include "instance_stack.h"
+
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <sstream>
+
+namespace embree
+{
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Vec2 shortcuts
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int N> using Vec2vf = Vec2<vfloat<N>>;
+ template<int N> using Vec2vd = Vec2<vdouble<N>>;
+ template<int N> using Vec2vr = Vec2<vreal<N>>;
+ template<int N> using Vec2vi = Vec2<vint<N>>;
+ template<int N> using Vec2vl = Vec2<vllong<N>>;
+ template<int N> using Vec2vb = Vec2<vbool<N>>;
+ template<int N> using Vec2vbf = Vec2<vboolf<N>>;
+ template<int N> using Vec2vbd = Vec2<vboold<N>>;
+
+ typedef Vec2<vfloat4> Vec2vf4;
+ typedef Vec2<vdouble4> Vec2vd4;
+ typedef Vec2<vreal4> Vec2vr4;
+ typedef Vec2<vint4> Vec2vi4;
+ typedef Vec2<vllong4> Vec2vl4;
+ typedef Vec2<vbool4> Vec2vb4;
+ typedef Vec2<vboolf4> Vec2vbf4;
+ typedef Vec2<vboold4> Vec2vbd4;
+
+ typedef Vec2<vfloat8> Vec2vf8;
+ typedef Vec2<vdouble8> Vec2vd8;
+ typedef Vec2<vreal8> Vec2vr8;
+ typedef Vec2<vint8> Vec2vi8;
+ typedef Vec2<vllong8> Vec2vl8;
+ typedef Vec2<vbool8> Vec2vb8;
+ typedef Vec2<vboolf8> Vec2vbf8;
+ typedef Vec2<vboold8> Vec2vbd8;
+
+ typedef Vec2<vfloat16> Vec2vf16;
+ typedef Vec2<vdouble16> Vec2vd16;
+ typedef Vec2<vreal16> Vec2vr16;
+ typedef Vec2<vint16> Vec2vi16;
+ typedef Vec2<vllong16> Vec2vl16;
+ typedef Vec2<vbool16> Vec2vb16;
+ typedef Vec2<vboolf16> Vec2vbf16;
+ typedef Vec2<vboold16> Vec2vbd16;
+
+ typedef Vec2<vfloatx> Vec2vfx;
+ typedef Vec2<vdoublex> Vec2vdx;
+ typedef Vec2<vrealx> Vec2vrx;
+ typedef Vec2<vintx> Vec2vix;
+ typedef Vec2<vllongx> Vec2vlx;
+ typedef Vec2<vboolx> Vec2vbx;
+ typedef Vec2<vboolfx> Vec2vbfx;
+ typedef Vec2<vbooldx> Vec2vbdx;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Vec3 shortcuts
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int N> using Vec3vf = Vec3<vfloat<N>>;
+ template<int N> using Vec3vd = Vec3<vdouble<N>>;
+ template<int N> using Vec3vr = Vec3<vreal<N>>;
+ template<int N> using Vec3vi = Vec3<vint<N>>;
+ template<int N> using Vec3vl = Vec3<vllong<N>>;
+ template<int N> using Vec3vb = Vec3<vbool<N>>;
+ template<int N> using Vec3vbf = Vec3<vboolf<N>>;
+ template<int N> using Vec3vbd = Vec3<vboold<N>>;
+
+ typedef Vec3<vfloat4> Vec3vf4;
+ typedef Vec3<vdouble4> Vec3vd4;
+ typedef Vec3<vreal4> Vec3vr4;
+ typedef Vec3<vint4> Vec3vi4;
+ typedef Vec3<vllong4> Vec3vl4;
+ typedef Vec3<vbool4> Vec3vb4;
+ typedef Vec3<vboolf4> Vec3vbf4;
+ typedef Vec3<vboold4> Vec3vbd4;
+
+ typedef Vec3<vfloat8> Vec3vf8;
+ typedef Vec3<vdouble8> Vec3vd8;
+ typedef Vec3<vreal8> Vec3vr8;
+ typedef Vec3<vint8> Vec3vi8;
+ typedef Vec3<vllong8> Vec3vl8;
+ typedef Vec3<vbool8> Vec3vb8;
+ typedef Vec3<vboolf8> Vec3vbf8;
+ typedef Vec3<vboold8> Vec3vbd8;
+
+ typedef Vec3<vfloat16> Vec3vf16;
+ typedef Vec3<vdouble16> Vec3vd16;
+ typedef Vec3<vreal16> Vec3vr16;
+ typedef Vec3<vint16> Vec3vi16;
+ typedef Vec3<vllong16> Vec3vl16;
+ typedef Vec3<vbool16> Vec3vb16;
+ typedef Vec3<vboolf16> Vec3vbf16;
+ typedef Vec3<vboold16> Vec3vbd16;
+
+ typedef Vec3<vfloatx> Vec3vfx;
+ typedef Vec3<vdoublex> Vec3vdx;
+ typedef Vec3<vrealx> Vec3vrx;
+ typedef Vec3<vintx> Vec3vix;
+ typedef Vec3<vllongx> Vec3vlx;
+ typedef Vec3<vboolx> Vec3vbx;
+ typedef Vec3<vboolfx> Vec3vbfx;
+ typedef Vec3<vbooldx> Vec3vbdx;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Vec4 shortcuts
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int N> using Vec4vf = Vec4<vfloat<N>>;
+ template<int N> using Vec4vd = Vec4<vdouble<N>>;
+ template<int N> using Vec4vr = Vec4<vreal<N>>;
+ template<int N> using Vec4vi = Vec4<vint<N>>;
+ template<int N> using Vec4vl = Vec4<vllong<N>>;
+ template<int N> using Vec4vb = Vec4<vbool<N>>;
+ template<int N> using Vec4vbf = Vec4<vboolf<N>>;
+ template<int N> using Vec4vbd = Vec4<vboold<N>>;
+
+ typedef Vec4<vfloat4> Vec4vf4;
+ typedef Vec4<vdouble4> Vec4vd4;
+ typedef Vec4<vreal4> Vec4vr4;
+ typedef Vec4<vint4> Vec4vi4;
+ typedef Vec4<vllong4> Vec4vl4;
+ typedef Vec4<vbool4> Vec4vb4;
+ typedef Vec4<vboolf4> Vec4vbf4;
+ typedef Vec4<vboold4> Vec4vbd4;
+
+ typedef Vec4<vfloat8> Vec4vf8;
+ typedef Vec4<vdouble8> Vec4vd8;
+ typedef Vec4<vreal8> Vec4vr8;
+ typedef Vec4<vint8> Vec4vi8;
+ typedef Vec4<vllong8> Vec4vl8;
+ typedef Vec4<vbool8> Vec4vb8;
+ typedef Vec4<vboolf8> Vec4vbf8;
+ typedef Vec4<vboold8> Vec4vbd8;
+
+ typedef Vec4<vfloat16> Vec4vf16;
+ typedef Vec4<vdouble16> Vec4vd16;
+ typedef Vec4<vreal16> Vec4vr16;
+ typedef Vec4<vint16> Vec4vi16;
+ typedef Vec4<vllong16> Vec4vl16;
+ typedef Vec4<vbool16> Vec4vb16;
+ typedef Vec4<vboolf16> Vec4vbf16;
+ typedef Vec4<vboold16> Vec4vbd16;
+
+ typedef Vec4<vfloatx> Vec4vfx;
+ typedef Vec4<vdoublex> Vec4vdx;
+ typedef Vec4<vrealx> Vec4vrx;
+ typedef Vec4<vintx> Vec4vix;
+ typedef Vec4<vllongx> Vec4vlx;
+ typedef Vec4<vboolx> Vec4vbx;
+ typedef Vec4<vboolfx> Vec4vbfx;
+ typedef Vec4<vbooldx> Vec4vbdx;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Other shortcuts
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template<int N> using BBox3vf = BBox<Vec3vf<N>>;
+ typedef BBox<Vec3vf4> BBox3vf4;
+ typedef BBox<Vec3vf8> BBox3vf8;
+ typedef BBox<Vec3vf16> BBox3vf16;
+
+ /* calculate time segment itime and fractional time ftime */
+ __forceinline int getTimeSegment(float time, float numTimeSegments, float& ftime)
+ {
+ const float timeScaled = time * numTimeSegments;
+ const float itimef = clamp(floorf(timeScaled), 0.0f, numTimeSegments-1.0f);
+ ftime = timeScaled - itimef;
+ return int(itimef);
+ }
+
+ __forceinline int getTimeSegment(float time, float start_time, float end_time, float numTimeSegments, float& ftime)
+ {
+ const float timeScaled = (time-start_time)/(end_time-start_time) * numTimeSegments;
+ const float itimef = clamp(floorf(timeScaled), 0.0f, numTimeSegments-1.0f);
+ ftime = timeScaled - itimef;
+ return int(itimef);
+ }
+
+ template<int N>
+ __forceinline vint<N> getTimeSegment(const vfloat<N>& time, const vfloat<N>& numTimeSegments, vfloat<N>& ftime)
+ {
+ const vfloat<N> timeScaled = time * numTimeSegments;
+ const vfloat<N> itimef = clamp(floor(timeScaled), vfloat<N>(zero), numTimeSegments-1.0f);
+ ftime = timeScaled - itimef;
+ return vint<N>(itimef);
+ }
+
+ template<int N>
+ __forceinline vint<N> getTimeSegment(const vfloat<N>& time, const vfloat<N>& start_time, const vfloat<N>& end_time, const vfloat<N>& numTimeSegments, vfloat<N>& ftime)
+ {
+ const vfloat<N> timeScaled = (time-start_time)/(end_time-start_time) * numTimeSegments;
+ const vfloat<N> itimef = clamp(floor(timeScaled), vfloat<N>(zero), numTimeSegments-1.0f);
+ ftime = timeScaled - itimef;
+ return vint<N>(itimef);
+ }
+
+ /* calculate overlapping time segment range */
+ __forceinline range<int> getTimeSegmentRange(const BBox1f& time_range, float numTimeSegments)
+ {
+ const float round_up = 1.0f+2.0f*float(ulp); // corrects inaccuracies to precisely match time step
+ const float round_down = 1.0f-2.0f*float(ulp);
+ const int itime_lower = (int)max(floor(round_up *time_range.lower*numTimeSegments), 0.0f);
+ const int itime_upper = (int)min(ceil (round_down*time_range.upper*numTimeSegments), numTimeSegments);
+ return make_range(itime_lower, itime_upper);
+ }
+
+ /* calculate overlapping time segment range */
+ __forceinline range<int> getTimeSegmentRange(const BBox1f& range, BBox1f time_range, float numTimeSegments)
+ {
+ const float lower = (range.lower-time_range.lower)/time_range.size();
+ const float upper = (range.upper-time_range.lower)/time_range.size();
+ return getTimeSegmentRange(BBox1f(lower,upper),numTimeSegments);
+ }
+}
diff --git a/thirdparty/embree/kernels/common/device.cpp b/thirdparty/embree/kernels/common/device.cpp
new file mode 100644
index 0000000000..068e0c2983
--- /dev/null
+++ b/thirdparty/embree/kernels/common/device.cpp
@@ -0,0 +1,556 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "device.h"
+#include "../hash.h"
+#include "scene_triangle_mesh.h"
+#include "scene_user_geometry.h"
+#include "scene_instance.h"
+#include "scene_curves.h"
+#include "scene_subdiv_mesh.h"
+
+#include "../subdiv/tessellation_cache.h"
+
+#include "acceln.h"
+#include "geometry.h"
+
+#include "../geometry/cylinder.h"
+
+#include "../bvh/bvh4_factory.h"
+#include "../bvh/bvh8_factory.h"
+
+#include "../../common/tasking/taskscheduler.h"
+#include "../../common/sys/alloc.h"
+
+namespace embree
+{
+ /*! some global variables that can be set via rtcSetParameter1i for debugging purposes */
+ ssize_t Device::debug_int0 = 0;
+ ssize_t Device::debug_int1 = 0;
+ ssize_t Device::debug_int2 = 0;
+ ssize_t Device::debug_int3 = 0;
+
+ DECLARE_SYMBOL2(RayStreamFilterFuncs,rayStreamFilterFuncs);
+
+ static MutexSys g_mutex;
+ static std::map<Device*,size_t> g_cache_size_map;
+ static std::map<Device*,size_t> g_num_threads_map;
+
+ Device::Device (const char* cfg)
+ {
+ /* check that CPU supports lowest ISA */
+ if (!hasISA(ISA)) {
+ throw_RTCError(RTC_ERROR_UNSUPPORTED_CPU,"CPU does not support " ISA_STR);
+ }
+
+ /* set default frequency level for detected CPU */
+ switch (getCPUModel()) {
+ case CPU::UNKNOWN: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::XEON_ICE_LAKE: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::CORE_ICE_LAKE: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::CORE_TIGER_LAKE: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE_COMET_LAKE: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE_CANNON_LAKE:frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE_KABY_LAKE: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::XEON_SKY_LAKE: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE_SKY_LAKE: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::XEON_BROADWELL: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::CORE_BROADWELL: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::XEON_HASWELL: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::CORE_HASWELL: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::XEON_IVY_BRIDGE: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::CORE_IVY_BRIDGE: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::SANDY_BRIDGE: frequency_level = FREQUENCY_SIMD256; break;
+ case CPU::NEHALEM: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE2: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::CORE1: frequency_level = FREQUENCY_SIMD128; break;
+ case CPU::XEON_PHI_KNIGHTS_MILL : frequency_level = FREQUENCY_SIMD512; break;
+ case CPU::XEON_PHI_KNIGHTS_LANDING: frequency_level = FREQUENCY_SIMD512; break;
+ case CPU::ARM: frequency_level = FREQUENCY_SIMD128; break;
+ }
+
+ /* initialize global state */
+#if defined(EMBREE_CONFIG)
+ State::parseString(EMBREE_CONFIG);
+#endif
+ State::parseString(cfg);
+ State::verify();
+
+ /* check whether selected ISA is supported by the HW, as the user could have forced an unsupported ISA */
+ if (!checkISASupport()) {
+ throw_RTCError(RTC_ERROR_UNSUPPORTED_CPU,"CPU does not support selected ISA");
+ }
+
+ /*! do some internal tests */
+ assert(isa::Cylinder::verify());
+
+ /*! enable huge page support if desired */
+#if defined(__WIN32__)
+ if (State::enable_selockmemoryprivilege)
+ State::hugepages_success &= win_enable_selockmemoryprivilege(State::verbosity(3));
+#endif
+ State::hugepages_success &= os_init(State::hugepages,State::verbosity(3));
+
+ /*! set tessellation cache size */
+ setCacheSize( State::tessellation_cache_size );
+
+ /*! enable some floating point exceptions to catch bugs */
+ if (State::float_exceptions)
+ {
+ int exceptions = _MM_MASK_MASK;
+ //exceptions &= ~_MM_MASK_INVALID;
+ exceptions &= ~_MM_MASK_DENORM;
+ exceptions &= ~_MM_MASK_DIV_ZERO;
+ //exceptions &= ~_MM_MASK_OVERFLOW;
+ //exceptions &= ~_MM_MASK_UNDERFLOW;
+ //exceptions &= ~_MM_MASK_INEXACT;
+ _MM_SET_EXCEPTION_MASK(exceptions);
+ }
+
+ /* print info header */
+ if (State::verbosity(1))
+ print();
+ if (State::verbosity(2))
+ State::print();
+
+ /* register all algorithms */
+ bvh4_factory = make_unique(new BVH4Factory(enabled_builder_cpu_features, enabled_cpu_features));
+
+#if defined(EMBREE_TARGET_SIMD8)
+ bvh8_factory = make_unique(new BVH8Factory(enabled_builder_cpu_features, enabled_cpu_features));
+#endif
+
+ /* setup tasking system */
+ initTaskingSystem(numThreads);
+
+ /* ray stream SOA to AOS conversion */
+#if defined(EMBREE_RAY_PACKETS)
+ RayStreamFilterFuncsType rayStreamFilterFuncs;
+ SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(enabled_cpu_features,rayStreamFilterFuncs);
+ rayStreamFilters = rayStreamFilterFuncs();
+#endif
+ }
+
+ Device::~Device ()
+ {
+ setCacheSize(0);
+ exitTaskingSystem();
+ }
+
+ std::string getEnabledTargets()
+ {
+ std::string v;
+#if defined(EMBREE_TARGET_SSE2)
+ v += "SSE2 ";
+#endif
+#if defined(EMBREE_TARGET_SSE42)
+ v += "SSE4.2 ";
+#endif
+#if defined(EMBREE_TARGET_AVX)
+ v += "AVX ";
+#endif
+#if defined(EMBREE_TARGET_AVX2)
+ v += "AVX2 ";
+#endif
+#if defined(EMBREE_TARGET_AVX512)
+ v += "AVX512 ";
+#endif
+ return v;
+ }
+
+ std::string getEmbreeFeatures()
+ {
+ std::string v;
+#if defined(EMBREE_RAY_MASK)
+ v += "raymasks ";
+#endif
+#if defined (EMBREE_BACKFACE_CULLING)
+ v += "backfaceculling ";
+#endif
+#if defined (EMBREE_BACKFACE_CULLING_CURVES)
+ v += "backfacecullingcurves ";
+#endif
+#if defined(EMBREE_FILTER_FUNCTION)
+ v += "intersection_filter ";
+#endif
+#if defined (EMBREE_COMPACT_POLYS)
+ v += "compact_polys ";
+#endif
+ return v;
+ }
+
+ void Device::print()
+ {
+ const int cpu_features = getCPUFeatures();
+ std::cout << std::endl;
+ std::cout << "Embree Ray Tracing Kernels " << RTC_VERSION_STRING << " (" << RTC_HASH << ")" << std::endl;
+ std::cout << " Compiler : " << getCompilerName() << std::endl;
+ std::cout << " Build : ";
+#if defined(DEBUG)
+ std::cout << "Debug " << std::endl;
+#else
+ std::cout << "Release " << std::endl;
+#endif
+ std::cout << " Platform : " << getPlatformName() << std::endl;
+ std::cout << " CPU : " << stringOfCPUModel(getCPUModel()) << " (" << getCPUVendor() << ")" << std::endl;
+ std::cout << " Threads : " << getNumberOfLogicalThreads() << std::endl;
+ std::cout << " ISA : " << stringOfCPUFeatures(cpu_features) << std::endl;
+ std::cout << " Targets : " << supportedTargetList(cpu_features) << std::endl;
+ const bool hasFTZ = _mm_getcsr() & _MM_FLUSH_ZERO_ON;
+ const bool hasDAZ = _mm_getcsr() & _MM_DENORMALS_ZERO_ON;
+ std::cout << " MXCSR : " << "FTZ=" << hasFTZ << ", DAZ=" << hasDAZ << std::endl;
+ std::cout << " Config" << std::endl;
+ std::cout << " Threads : " << (numThreads ? toString(numThreads) : std::string("default")) << std::endl;
+ std::cout << " ISA : " << stringOfCPUFeatures(enabled_cpu_features) << std::endl;
+ std::cout << " Targets : " << supportedTargetList(enabled_cpu_features) << " (supported)" << std::endl;
+ std::cout << " " << getEnabledTargets() << " (compile time enabled)" << std::endl;
+ std::cout << " Features: " << getEmbreeFeatures() << std::endl;
+ std::cout << " Tasking : ";
+#if defined(TASKING_TBB)
+ std::cout << "TBB" << TBB_VERSION_MAJOR << "." << TBB_VERSION_MINOR << " ";
+ #if TBB_INTERFACE_VERSION >= 12002
+ std::cout << "TBB_header_interface_" << TBB_INTERFACE_VERSION << " TBB_lib_interface_" << TBB_runtime_interface_version() << " ";
+ #else
+ std::cout << "TBB_header_interface_" << TBB_INTERFACE_VERSION << " TBB_lib_interface_" << tbb::TBB_runtime_interface_version() << " ";
+ #endif
+#endif
+#if defined(TASKING_INTERNAL)
+ std::cout << "internal_tasking_system ";
+#endif
+#if defined(TASKING_PPL)
+ std::cout << "PPL ";
+#endif
+ std::cout << std::endl;
+
+ /* check of FTZ and DAZ flags are set in CSR */
+ if (!hasFTZ || !hasDAZ)
+ {
+#if !defined(_DEBUG)
+ if (State::verbosity(1))
+#endif
+ {
+ std::cout << std::endl;
+ std::cout << "================================================================================" << std::endl;
+ std::cout << " WARNING: \"Flush to Zero\" or \"Denormals are Zero\" mode not enabled " << std::endl
+ << " in the MXCSR control and status register. This can have a severe " << std::endl
+ << " performance impact. Please enable these modes for each application " << std::endl
+ << " thread the following way:" << std::endl
+ << std::endl
+ << " #include \"xmmintrin.h\"" << std::endl
+ << " #include \"pmmintrin.h\"" << std::endl
+ << std::endl
+ << " _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);" << std::endl
+ << " _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);" << std::endl;
+ std::cout << "================================================================================" << std::endl;
+ std::cout << std::endl;
+ }
+ }
+ std::cout << std::endl;
+ }
+
+ void Device::setDeviceErrorCode(RTCError error)
+ {
+ RTCError* stored_error = errorHandler.error();
+ if (*stored_error == RTC_ERROR_NONE)
+ *stored_error = error;
+ }
+
+ RTCError Device::getDeviceErrorCode()
+ {
+ RTCError* stored_error = errorHandler.error();
+ RTCError error = *stored_error;
+ *stored_error = RTC_ERROR_NONE;
+ return error;
+ }
+
+ void Device::setThreadErrorCode(RTCError error)
+ {
+ RTCError* stored_error = g_errorHandler.error();
+ if (*stored_error == RTC_ERROR_NONE)
+ *stored_error = error;
+ }
+
+ RTCError Device::getThreadErrorCode()
+ {
+ RTCError* stored_error = g_errorHandler.error();
+ RTCError error = *stored_error;
+ *stored_error = RTC_ERROR_NONE;
+ return error;
+ }
+
+ void Device::process_error(Device* device, RTCError error, const char* str)
+ {
+ /* store global error code when device construction failed */
+ if (!device)
+ return setThreadErrorCode(error);
+
+ /* print error when in verbose mode */
+ if (device->verbosity(1))
+ {
+ switch (error) {
+ case RTC_ERROR_NONE : std::cerr << "Embree: No error"; break;
+ case RTC_ERROR_UNKNOWN : std::cerr << "Embree: Unknown error"; break;
+ case RTC_ERROR_INVALID_ARGUMENT : std::cerr << "Embree: Invalid argument"; break;
+ case RTC_ERROR_INVALID_OPERATION: std::cerr << "Embree: Invalid operation"; break;
+ case RTC_ERROR_OUT_OF_MEMORY : std::cerr << "Embree: Out of memory"; break;
+ case RTC_ERROR_UNSUPPORTED_CPU : std::cerr << "Embree: Unsupported CPU"; break;
+ default : std::cerr << "Embree: Invalid error code"; break;
+ };
+ if (str) std::cerr << ", (" << str << ")";
+ std::cerr << std::endl;
+ }
+
+ /* call user specified error callback */
+ if (device->error_function)
+ device->error_function(device->error_function_userptr,error,str);
+
+ /* record error code */
+ device->setDeviceErrorCode(error);
+ }
+
+ void Device::memoryMonitor(ssize_t bytes, bool post)
+ {
+ if (State::memory_monitor_function && bytes != 0) {
+ if (!State::memory_monitor_function(State::memory_monitor_userptr,bytes,post)) {
+ if (bytes > 0) { // only throw exception when we allocate memory to never throw inside a destructor
+ throw_RTCError(RTC_ERROR_OUT_OF_MEMORY,"memory monitor forced termination");
+ }
+ }
+ }
+ }
+
+ size_t getMaxNumThreads()
+ {
+ size_t maxNumThreads = 0;
+ for (std::map<Device*,size_t>::iterator i=g_num_threads_map.begin(); i != g_num_threads_map.end(); i++)
+ maxNumThreads = max(maxNumThreads, (*i).second);
+ if (maxNumThreads == 0)
+ maxNumThreads = std::numeric_limits<size_t>::max();
+ return maxNumThreads;
+ }
+
+ size_t getMaxCacheSize()
+ {
+ size_t maxCacheSize = 0;
+ for (std::map<Device*,size_t>::iterator i=g_cache_size_map.begin(); i!= g_cache_size_map.end(); i++)
+ maxCacheSize = max(maxCacheSize, (*i).second);
+ return maxCacheSize;
+ }
+
+ void Device::setCacheSize(size_t bytes)
+ {
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ Lock<MutexSys> lock(g_mutex);
+ if (bytes == 0) g_cache_size_map.erase(this);
+ else g_cache_size_map[this] = bytes;
+
+ size_t maxCacheSize = getMaxCacheSize();
+ resizeTessellationCache(maxCacheSize);
+#endif
+ }
+
+ void Device::initTaskingSystem(size_t numThreads)
+ {
+ Lock<MutexSys> lock(g_mutex);
+ if (numThreads == 0)
+ g_num_threads_map[this] = std::numeric_limits<size_t>::max();
+ else
+ g_num_threads_map[this] = numThreads;
+
+ /* create task scheduler */
+ size_t maxNumThreads = getMaxNumThreads();
+ TaskScheduler::create(maxNumThreads,State::set_affinity,State::start_threads);
+#if USE_TASK_ARENA
+ const size_t nThreads = min(maxNumThreads,TaskScheduler::threadCount());
+ const size_t uThreads = min(max(numUserThreads,(size_t)1),nThreads);
+ arena = make_unique(new tbb::task_arena((int)nThreads,(unsigned int)uThreads));
+#endif
+ }
+
+ void Device::exitTaskingSystem()
+ {
+ Lock<MutexSys> lock(g_mutex);
+ g_num_threads_map.erase(this);
+
+ /* terminate tasking system */
+ if (g_num_threads_map.size() == 0) {
+ TaskScheduler::destroy();
+ }
+ /* or configure new number of threads */
+ else {
+ size_t maxNumThreads = getMaxNumThreads();
+ TaskScheduler::create(maxNumThreads,State::set_affinity,State::start_threads);
+ }
+#if USE_TASK_ARENA
+ arena.reset();
+#endif
+ }
+
+ void Device::setProperty(const RTCDeviceProperty prop, ssize_t val)
+ {
+ /* hidden internal properties */
+ switch ((size_t)prop)
+ {
+ case 1000000: debug_int0 = val; return;
+ case 1000001: debug_int1 = val; return;
+ case 1000002: debug_int2 = val; return;
+ case 1000003: debug_int3 = val; return;
+ }
+
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown writable property");
+ }
+
+ ssize_t Device::getProperty(const RTCDeviceProperty prop)
+ {
+ size_t iprop = (size_t)prop;
+
+ /* get name of internal regression test */
+ if (iprop >= 2000000 && iprop < 3000000)
+ {
+ RegressionTest* test = getRegressionTest(iprop-2000000);
+ if (test) return (ssize_t) test->name.c_str();
+ else return 0;
+ }
+
+ /* run internal regression test */
+ if (iprop >= 3000000 && iprop < 4000000)
+ {
+ RegressionTest* test = getRegressionTest(iprop-3000000);
+ if (test) return test->run();
+ else return 0;
+ }
+
+ /* documented properties */
+ switch (prop)
+ {
+ case RTC_DEVICE_PROPERTY_VERSION_MAJOR: return RTC_VERSION_MAJOR;
+ case RTC_DEVICE_PROPERTY_VERSION_MINOR: return RTC_VERSION_MINOR;
+ case RTC_DEVICE_PROPERTY_VERSION_PATCH: return RTC_VERSION_PATCH;
+ case RTC_DEVICE_PROPERTY_VERSION : return RTC_VERSION;
+
+#if defined(EMBREE_TARGET_SIMD4) && defined(EMBREE_RAY_PACKETS)
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY4_SUPPORTED: return hasISA(SSE2);
+#else
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY4_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_TARGET_SIMD8) && defined(EMBREE_RAY_PACKETS)
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY8_SUPPORTED: return hasISA(AVX);
+#else
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY8_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_TARGET_SIMD16) && defined(EMBREE_RAY_PACKETS)
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED: return hasISA(AVX512);
+#else
+ case RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_RAY_PACKETS)
+ case RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_RAY_MASK)
+ case RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_BACKFACE_CULLING)
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED: return 0;
+#endif
+
+#if defined(EMBREE_BACKFACE_CULLING_CURVES)
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED: return 0;
+#endif
+
+#if defined(EMBREE_COMPACT_POLYS)
+ case RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED: return 0;
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ case RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_IGNORE_INVALID_RAYS)
+ case RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED: return 0;
+#endif
+
+#if defined(TASKING_INTERNAL)
+ case RTC_DEVICE_PROPERTY_TASKING_SYSTEM: return 0;
+#endif
+
+#if defined(TASKING_TBB)
+ case RTC_DEVICE_PROPERTY_TASKING_SYSTEM: return 1;
+#endif
+
+#if defined(TASKING_PPL)
+ case RTC_DEVICE_PROPERTY_TASKING_SYSTEM: return 2;
+#endif
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ case RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ case RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_GEOMETRY_CURVE)
+ case RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_CURVE_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ case RTC_DEVICE_PROPERTY_SUBDIVISION_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_SUBDIVISION_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ case RTC_DEVICE_PROPERTY_USER_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_USER_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(EMBREE_GEOMETRY_POINT)
+ case RTC_DEVICE_PROPERTY_POINT_GEOMETRY_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_POINT_GEOMETRY_SUPPORTED: return 0;
+#endif
+
+#if defined(TASKING_PPL)
+ case RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED: return 0;
+#elif defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR < 8)
+ case RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED: return 0;
+#else
+ case RTC_DEVICE_PROPERTY_JOIN_COMMIT_SUPPORTED: return 1;
+#endif
+
+#if defined(TASKING_TBB) && TASKING_TBB_USE_TASK_ISOLATION
+ case RTC_DEVICE_PROPERTY_PARALLEL_COMMIT_SUPPORTED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_PARALLEL_COMMIT_SUPPORTED: return 0;
+#endif
+
+ default: throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown readable property"); break;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/common/device.h b/thirdparty/embree/kernels/common/device.h
new file mode 100644
index 0000000000..21c42c654d
--- /dev/null
+++ b/thirdparty/embree/kernels/common/device.h
@@ -0,0 +1,85 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "state.h"
+#include "accel.h"
+
+namespace embree
+{
+ class BVH4Factory;
+ class BVH8Factory;
+
+ class Device : public State, public MemoryMonitorInterface
+ {
+ ALIGNED_CLASS_(16);
+
+ public:
+
+ /*! Device construction */
+ Device (const char* cfg);
+
+ /*! Device destruction */
+ virtual ~Device ();
+
+ /*! prints info about the device */
+ void print();
+
+ /*! sets the error code */
+ void setDeviceErrorCode(RTCError error);
+
+ /*! returns and clears the error code */
+ RTCError getDeviceErrorCode();
+
+ /*! sets the error code */
+ static void setThreadErrorCode(RTCError error);
+
+ /*! returns and clears the error code */
+ static RTCError getThreadErrorCode();
+
+ /*! processes error codes, do not call directly */
+ static void process_error(Device* device, RTCError error, const char* str);
+
+ /*! invokes the memory monitor callback */
+ void memoryMonitor(ssize_t bytes, bool post);
+
+ /*! sets the size of the software cache. */
+ void setCacheSize(size_t bytes);
+
+ /*! sets a property */
+ void setProperty(const RTCDeviceProperty prop, ssize_t val);
+
+ /*! gets a property */
+ ssize_t getProperty(const RTCDeviceProperty prop);
+
+ private:
+
+ /*! initializes the tasking system */
+ void initTaskingSystem(size_t numThreads);
+
+ /*! shuts down the tasking system */
+ void exitTaskingSystem();
+
+ /*! some variables that can be set via rtcSetParameter1i for debugging purposes */
+ public:
+ static ssize_t debug_int0;
+ static ssize_t debug_int1;
+ static ssize_t debug_int2;
+ static ssize_t debug_int3;
+
+ public:
+ std::unique_ptr<BVH4Factory> bvh4_factory;
+#if defined(EMBREE_TARGET_SIMD8)
+ std::unique_ptr<BVH8Factory> bvh8_factory;
+#endif
+
+#if USE_TASK_ARENA
+ std::unique_ptr<tbb::task_arena> arena;
+#endif
+
+ /* ray streams filter */
+ RayStreamFilterFuncs rayStreamFilters;
+ };
+}
diff --git a/thirdparty/embree/kernels/common/geometry.cpp b/thirdparty/embree/kernels/common/geometry.cpp
new file mode 100644
index 0000000000..d8d3f65a5c
--- /dev/null
+++ b/thirdparty/embree/kernels/common/geometry.cpp
@@ -0,0 +1,259 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "geometry.h"
+#include "scene.h"
+
+namespace embree
+{
+ const char* Geometry::gtype_names[Geometry::GTY_END] =
+ {
+ "flat_linear_curve",
+ "round_linear_curve",
+ "oriented_linear_curve",
+ "",
+ "flat_bezier_curve",
+ "round_bezier_curve",
+ "oriented_bezier_curve",
+ "",
+ "flat_bspline_curve",
+ "round_bspline_curve",
+ "oriented_bspline_curve",
+ "",
+ "flat_hermite_curve",
+ "round_hermite_curve",
+ "oriented_hermite_curve",
+ "",
+ "flat_catmull_rom_curve",
+ "round_catmull_rom_curve",
+ "oriented_catmull_rom_curve",
+ "",
+ "triangles",
+ "quads",
+ "grid",
+ "subdivs",
+ "",
+ "sphere",
+ "disc",
+ "oriented_disc",
+ "",
+ "usergeom",
+ "instance_cheap",
+ "instance_expensive",
+ };
+
+ Geometry::Geometry (Device* device, GType gtype, unsigned int numPrimitives, unsigned int numTimeSteps)
+ : device(device), userPtr(nullptr),
+ numPrimitives(numPrimitives), numTimeSteps(unsigned(numTimeSteps)), fnumTimeSegments(float(numTimeSteps-1)), time_range(0.0f,1.0f),
+ mask(-1),
+ gtype(gtype),
+ gsubtype(GTY_SUBTYPE_DEFAULT),
+ quality(RTC_BUILD_QUALITY_MEDIUM),
+ state((unsigned)State::MODIFIED),
+ enabled(true),
+ intersectionFilterN(nullptr), occlusionFilterN(nullptr), pointQueryFunc(nullptr)
+ {
+ device->refInc();
+ }
+
+ Geometry::~Geometry()
+ {
+ device->refDec();
+ }
+
+ void Geometry::setNumPrimitives(unsigned int numPrimitives_in)
+ {
+ if (numPrimitives_in == numPrimitives) return;
+
+ numPrimitives = numPrimitives_in;
+
+ Geometry::update();
+ }
+
+ void Geometry::setNumTimeSteps (unsigned int numTimeSteps_in)
+ {
+ if (numTimeSteps_in == numTimeSteps) {
+ return;
+ }
+
+ numTimeSteps = numTimeSteps_in;
+ fnumTimeSegments = float(numTimeSteps_in-1);
+
+ Geometry::update();
+ }
+
+ void Geometry::setTimeRange (const BBox1f range)
+ {
+ time_range = range;
+ Geometry::update();
+ }
+
+ void Geometry::update()
+ {
+ ++modCounter_; // FIXME: required?
+ state = (unsigned)State::MODIFIED;
+ }
+
+ void Geometry::commit()
+ {
+ ++modCounter_;
+ state = (unsigned)State::COMMITTED;
+ }
+
+ void Geometry::preCommit()
+ {
+ if (State::MODIFIED == (State)state)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"geometry not committed");
+ }
+
+ void Geometry::postCommit()
+ {
+ }
+
+ void Geometry::enable ()
+ {
+ if (isEnabled())
+ return;
+
+ enabled = true;
+ ++modCounter_;
+ }
+
+ void Geometry::disable ()
+ {
+ if (isDisabled())
+ return;
+
+ enabled = false;
+ ++modCounter_;
+ }
+
+ void Geometry::setUserData (void* ptr)
+ {
+ userPtr = ptr;
+ }
+
+ void Geometry::setIntersectionFilterFunctionN (RTCFilterFunctionN filter)
+ {
+ if (!(getTypeMask() & (MTY_TRIANGLE_MESH | MTY_QUAD_MESH | MTY_CURVES | MTY_SUBDIV_MESH | MTY_USER_GEOMETRY | MTY_GRID_MESH)))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"filter functions not supported for this geometry");
+
+ intersectionFilterN = filter;
+ }
+
+ void Geometry::setOcclusionFilterFunctionN (RTCFilterFunctionN filter)
+ {
+ if (!(getTypeMask() & (MTY_TRIANGLE_MESH | MTY_QUAD_MESH | MTY_CURVES | MTY_SUBDIV_MESH | MTY_USER_GEOMETRY | MTY_GRID_MESH)))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"filter functions not supported for this geometry");
+
+ occlusionFilterN = filter;
+ }
+
+ void Geometry::setPointQueryFunction (RTCPointQueryFunction func)
+ {
+ pointQueryFunc = func;
+ }
+
+ void Geometry::interpolateN(const RTCInterpolateNArguments* const args)
+ {
+ const void* valid_i = args->valid;
+ const unsigned* primIDs = args->primIDs;
+ const float* u = args->u;
+ const float* v = args->v;
+ unsigned int N = args->N;
+ RTCBufferType bufferType = args->bufferType;
+ unsigned int bufferSlot = args->bufferSlot;
+ float* P = args->P;
+ float* dPdu = args->dPdu;
+ float* dPdv = args->dPdv;
+ float* ddPdudu = args->ddPdudu;
+ float* ddPdvdv = args->ddPdvdv;
+ float* ddPdudv = args->ddPdudv;
+ unsigned int valueCount = args->valueCount;
+
+ if (valueCount > 256) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"maximally 256 floating point values can be interpolated per vertex");
+ const int* valid = (const int*) valid_i;
+
+ __aligned(64) float P_tmp[256];
+ __aligned(64) float dPdu_tmp[256];
+ __aligned(64) float dPdv_tmp[256];
+ __aligned(64) float ddPdudu_tmp[256];
+ __aligned(64) float ddPdvdv_tmp[256];
+ __aligned(64) float ddPdudv_tmp[256];
+
+ float* Pt = P ? P_tmp : nullptr;
+ float* dPdut = nullptr, *dPdvt = nullptr;
+ if (dPdu) { dPdut = dPdu_tmp; dPdvt = dPdv_tmp; }
+ float* ddPdudut = nullptr, *ddPdvdvt = nullptr, *ddPdudvt = nullptr;
+ if (ddPdudu) { ddPdudut = ddPdudu_tmp; ddPdvdvt = ddPdvdv_tmp; ddPdudvt = ddPdudv_tmp; }
+
+ for (unsigned int i=0; i<N; i++)
+ {
+ if (valid && !valid[i]) continue;
+
+ RTCInterpolateArguments iargs;
+ iargs.primID = primIDs[i];
+ iargs.u = u[i];
+ iargs.v = v[i];
+ iargs.bufferType = bufferType;
+ iargs.bufferSlot = bufferSlot;
+ iargs.P = Pt;
+ iargs.dPdu = dPdut;
+ iargs.dPdv = dPdvt;
+ iargs.ddPdudu = ddPdudut;
+ iargs.ddPdvdv = ddPdvdvt;
+ iargs.ddPdudv = ddPdudvt;
+ iargs.valueCount = valueCount;
+ interpolate(&iargs);
+
+ if (likely(P)) {
+ for (unsigned int j=0; j<valueCount; j++)
+ P[j*N+i] = Pt[j];
+ }
+ if (likely(dPdu))
+ {
+ for (unsigned int j=0; j<valueCount; j++) {
+ dPdu[j*N+i] = dPdut[j];
+ dPdv[j*N+i] = dPdvt[j];
+ }
+ }
+ if (likely(ddPdudu))
+ {
+ for (unsigned int j=0; j<valueCount; j++) {
+ ddPdudu[j*N+i] = ddPdudut[j];
+ ddPdvdv[j*N+i] = ddPdvdvt[j];
+ ddPdudv[j*N+i] = ddPdudvt[j];
+ }
+ }
+ }
+ }
+
+ bool Geometry::pointQuery(PointQuery* query, PointQueryContext* context)
+ {
+ assert(context->primID < size());
+
+ RTCPointQueryFunctionArguments args;
+ args.query = (RTCPointQuery*)context->query_ws;
+ args.userPtr = context->userPtr;
+ args.primID = context->primID;
+ args.geomID = context->geomID;
+ args.context = context->userContext;
+ args.similarityScale = context->similarityScale;
+
+ bool update = false;
+ if(context->func) update |= context->func(&args);
+ if(pointQueryFunc) update |= pointQueryFunc(&args);
+
+ if (update && context->userContext->instStackSize > 0)
+ {
+ // update point query
+ if (context->query_type == POINT_QUERY_TYPE_AABB) {
+ context->updateAABB();
+ } else {
+ assert(context->similarityScale > 0.f);
+ query->radius = context->query_ws->radius * context->similarityScale;
+ }
+ }
+ return update;
+ }
+}
diff --git a/thirdparty/embree/kernels/common/geometry.h b/thirdparty/embree/kernels/common/geometry.h
new file mode 100644
index 0000000000..2f9f2e7c94
--- /dev/null
+++ b/thirdparty/embree/kernels/common/geometry.h
@@ -0,0 +1,582 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "device.h"
+#include "buffer.h"
+#include "../common/point_query.h"
+#include "../builders/priminfo.h"
+
+namespace embree
+{
+ class Scene;
+ class Geometry;
+
+ struct GeometryCounts
+ {
+ __forceinline GeometryCounts()
+ : numFilterFunctions(0),
+ numTriangles(0), numMBTriangles(0),
+ numQuads(0), numMBQuads(0),
+ numBezierCurves(0), numMBBezierCurves(0),
+ numLineSegments(0), numMBLineSegments(0),
+ numSubdivPatches(0), numMBSubdivPatches(0),
+ numUserGeometries(0), numMBUserGeometries(0),
+ numInstancesCheap(0), numMBInstancesCheap(0),
+ numInstancesExpensive(0), numMBInstancesExpensive(0),
+ numGrids(0), numMBGrids(0),
+ numPoints(0), numMBPoints(0) {}
+
+ __forceinline size_t size() const {
+ return numTriangles + numQuads + numBezierCurves + numLineSegments + numSubdivPatches + numUserGeometries + numInstancesCheap + numInstancesExpensive + numGrids + numPoints
+ + numMBTriangles + numMBQuads + numMBBezierCurves + numMBLineSegments + numMBSubdivPatches + numMBUserGeometries + numMBInstancesCheap + numMBInstancesExpensive + numMBGrids + numMBPoints;
+ }
+
+ __forceinline unsigned int enabledGeometryTypesMask() const
+ {
+ unsigned int mask = 0;
+ if (numTriangles) mask |= 1 << 0;
+ if (numQuads) mask |= 1 << 1;
+ if (numBezierCurves+numLineSegments) mask |= 1 << 2;
+ if (numSubdivPatches) mask |= 1 << 3;
+ if (numUserGeometries) mask |= 1 << 4;
+ if (numInstancesCheap) mask |= 1 << 5;
+ if (numInstancesExpensive) mask |= 1 << 6;
+ if (numGrids) mask |= 1 << 7;
+ if (numPoints) mask |= 1 << 8;
+
+ unsigned int maskMB = 0;
+ if (numMBTriangles) maskMB |= 1 << 0;
+ if (numMBQuads) maskMB |= 1 << 1;
+ if (numMBBezierCurves+numMBLineSegments) maskMB |= 1 << 2;
+ if (numMBSubdivPatches) maskMB |= 1 << 3;
+ if (numMBUserGeometries) maskMB |= 1 << 4;
+ if (numMBInstancesCheap) maskMB |= 1 << 5;
+ if (numMBInstancesExpensive) maskMB |= 1 << 6;
+ if (numMBGrids) maskMB |= 1 << 7;
+ if (numMBPoints) maskMB |= 1 << 8;
+
+ return (mask<<8) + maskMB;
+ }
+
+ __forceinline GeometryCounts operator+ (GeometryCounts const & rhs) const
+ {
+ GeometryCounts ret;
+ ret.numFilterFunctions = numFilterFunctions + rhs.numFilterFunctions;
+ ret.numTriangles = numTriangles + rhs.numTriangles;
+ ret.numMBTriangles = numMBTriangles + rhs.numMBTriangles;
+ ret.numQuads = numQuads + rhs.numQuads;
+ ret.numMBQuads = numMBQuads + rhs.numMBQuads;
+ ret.numBezierCurves = numBezierCurves + rhs.numBezierCurves;
+ ret.numMBBezierCurves = numMBBezierCurves + rhs.numMBBezierCurves;
+ ret.numLineSegments = numLineSegments + rhs.numLineSegments;
+ ret.numMBLineSegments = numMBLineSegments + rhs.numMBLineSegments;
+ ret.numSubdivPatches = numSubdivPatches + rhs.numSubdivPatches;
+ ret.numMBSubdivPatches = numMBSubdivPatches + rhs.numMBSubdivPatches;
+ ret.numUserGeometries = numUserGeometries + rhs.numUserGeometries;
+ ret.numMBUserGeometries = numMBUserGeometries + rhs.numMBUserGeometries;
+ ret.numInstancesCheap = numInstancesCheap + rhs.numInstancesCheap;
+ ret.numMBInstancesCheap = numMBInstancesCheap + rhs.numMBInstancesCheap;
+ ret.numInstancesExpensive = numInstancesExpensive + rhs.numInstancesExpensive;
+ ret.numMBInstancesExpensive = numMBInstancesExpensive + rhs.numMBInstancesExpensive;
+ ret.numGrids = numGrids + rhs.numGrids;
+ ret.numMBGrids = numMBGrids + rhs.numMBGrids;
+ ret.numPoints = numPoints + rhs.numPoints;
+ ret.numMBPoints = numMBPoints + rhs.numMBPoints;
+
+ return ret;
+ }
+
+ size_t numFilterFunctions; //!< number of geometries with filter functions enabled
+ size_t numTriangles; //!< number of enabled triangles
+ size_t numMBTriangles; //!< number of enabled motion blured triangles
+ size_t numQuads; //!< number of enabled quads
+ size_t numMBQuads; //!< number of enabled motion blurred quads
+ size_t numBezierCurves; //!< number of enabled curves
+ size_t numMBBezierCurves; //!< number of enabled motion blurred curves
+ size_t numLineSegments; //!< number of enabled line segments
+ size_t numMBLineSegments; //!< number of enabled line motion blurred segments
+ size_t numSubdivPatches; //!< number of enabled subdivision patches
+ size_t numMBSubdivPatches; //!< number of enabled motion blured subdivision patches
+ size_t numUserGeometries; //!< number of enabled user geometries
+ size_t numMBUserGeometries; //!< number of enabled motion blurred user geometries
+ size_t numInstancesCheap; //!< number of enabled cheap instances
+ size_t numMBInstancesCheap; //!< number of enabled motion blurred cheap instances
+ size_t numInstancesExpensive; //!< number of enabled expensive instances
+ size_t numMBInstancesExpensive; //!< number of enabled motion blurred expensive instances
+ size_t numGrids; //!< number of enabled grid geometries
+ size_t numMBGrids; //!< number of enabled motion blurred grid geometries
+ size_t numPoints; //!< number of enabled points
+ size_t numMBPoints; //!< number of enabled motion blurred points
+ };
+
+ /*! Base class all geometries are derived from */
+ class Geometry : public RefCount
+ {
+ friend class Scene;
+ public:
+
+ /*! type of geometry */
+ enum GType
+ {
+ GTY_FLAT_LINEAR_CURVE = 0,
+ GTY_ROUND_LINEAR_CURVE = 1,
+ GTY_ORIENTED_LINEAR_CURVE = 2,
+ GTY_CONE_LINEAR_CURVE = 3,
+
+ GTY_FLAT_BEZIER_CURVE = 4,
+ GTY_ROUND_BEZIER_CURVE = 5,
+ GTY_ORIENTED_BEZIER_CURVE = 6,
+
+ GTY_FLAT_BSPLINE_CURVE = 8,
+ GTY_ROUND_BSPLINE_CURVE = 9,
+ GTY_ORIENTED_BSPLINE_CURVE = 10,
+
+ GTY_FLAT_HERMITE_CURVE = 12,
+ GTY_ROUND_HERMITE_CURVE = 13,
+ GTY_ORIENTED_HERMITE_CURVE = 14,
+
+ GTY_FLAT_CATMULL_ROM_CURVE = 16,
+ GTY_ROUND_CATMULL_ROM_CURVE = 17,
+ GTY_ORIENTED_CATMULL_ROM_CURVE = 18,
+
+ GTY_TRIANGLE_MESH = 20,
+ GTY_QUAD_MESH = 21,
+ GTY_GRID_MESH = 22,
+ GTY_SUBDIV_MESH = 23,
+
+ GTY_SPHERE_POINT = 25,
+ GTY_DISC_POINT = 26,
+ GTY_ORIENTED_DISC_POINT = 27,
+
+ GTY_USER_GEOMETRY = 29,
+ GTY_INSTANCE_CHEAP = 30,
+ GTY_INSTANCE_EXPENSIVE = 31,
+ GTY_END = 32,
+
+ GTY_BASIS_LINEAR = 0,
+ GTY_BASIS_BEZIER = 4,
+ GTY_BASIS_BSPLINE = 8,
+ GTY_BASIS_HERMITE = 12,
+ GTY_BASIS_CATMULL_ROM = 16,
+ GTY_BASIS_MASK = 28,
+
+ GTY_SUBTYPE_FLAT_CURVE = 0,
+ GTY_SUBTYPE_ROUND_CURVE = 1,
+ GTY_SUBTYPE_ORIENTED_CURVE = 2,
+ GTY_SUBTYPE_MASK = 3,
+ };
+
+ enum GSubType
+ {
+ GTY_SUBTYPE_DEFAULT= 0,
+ GTY_SUBTYPE_INSTANCE_LINEAR = 0,
+ GTY_SUBTYPE_INSTANCE_QUATERNION = 1
+ };
+
+ enum GTypeMask
+ {
+ MTY_FLAT_LINEAR_CURVE = 1ul << GTY_FLAT_LINEAR_CURVE,
+ MTY_ROUND_LINEAR_CURVE = 1ul << GTY_ROUND_LINEAR_CURVE,
+ MTY_CONE_LINEAR_CURVE = 1ul << GTY_CONE_LINEAR_CURVE,
+ MTY_ORIENTED_LINEAR_CURVE = 1ul << GTY_ORIENTED_LINEAR_CURVE,
+
+ MTY_FLAT_BEZIER_CURVE = 1ul << GTY_FLAT_BEZIER_CURVE,
+ MTY_ROUND_BEZIER_CURVE = 1ul << GTY_ROUND_BEZIER_CURVE,
+ MTY_ORIENTED_BEZIER_CURVE = 1ul << GTY_ORIENTED_BEZIER_CURVE,
+
+ MTY_FLAT_BSPLINE_CURVE = 1ul << GTY_FLAT_BSPLINE_CURVE,
+ MTY_ROUND_BSPLINE_CURVE = 1ul << GTY_ROUND_BSPLINE_CURVE,
+ MTY_ORIENTED_BSPLINE_CURVE = 1ul << GTY_ORIENTED_BSPLINE_CURVE,
+
+ MTY_FLAT_HERMITE_CURVE = 1ul << GTY_FLAT_HERMITE_CURVE,
+ MTY_ROUND_HERMITE_CURVE = 1ul << GTY_ROUND_HERMITE_CURVE,
+ MTY_ORIENTED_HERMITE_CURVE = 1ul << GTY_ORIENTED_HERMITE_CURVE,
+
+ MTY_FLAT_CATMULL_ROM_CURVE = 1ul << GTY_FLAT_CATMULL_ROM_CURVE,
+ MTY_ROUND_CATMULL_ROM_CURVE = 1ul << GTY_ROUND_CATMULL_ROM_CURVE,
+ MTY_ORIENTED_CATMULL_ROM_CURVE = 1ul << GTY_ORIENTED_CATMULL_ROM_CURVE,
+
+ MTY_CURVE2 = MTY_FLAT_LINEAR_CURVE | MTY_ROUND_LINEAR_CURVE | MTY_CONE_LINEAR_CURVE | MTY_ORIENTED_LINEAR_CURVE,
+
+ MTY_CURVE4 = MTY_FLAT_BEZIER_CURVE | MTY_ROUND_BEZIER_CURVE | MTY_ORIENTED_BEZIER_CURVE |
+ MTY_FLAT_BSPLINE_CURVE | MTY_ROUND_BSPLINE_CURVE | MTY_ORIENTED_BSPLINE_CURVE |
+ MTY_FLAT_HERMITE_CURVE | MTY_ROUND_HERMITE_CURVE | MTY_ORIENTED_HERMITE_CURVE |
+ MTY_FLAT_CATMULL_ROM_CURVE | MTY_ROUND_CATMULL_ROM_CURVE | MTY_ORIENTED_CATMULL_ROM_CURVE,
+
+ MTY_SPHERE_POINT = 1ul << GTY_SPHERE_POINT,
+ MTY_DISC_POINT = 1ul << GTY_DISC_POINT,
+ MTY_ORIENTED_DISC_POINT = 1ul << GTY_ORIENTED_DISC_POINT,
+
+ MTY_POINTS = MTY_SPHERE_POINT | MTY_DISC_POINT | MTY_ORIENTED_DISC_POINT,
+
+ MTY_CURVES = MTY_CURVE2 | MTY_CURVE4 | MTY_POINTS,
+
+ MTY_TRIANGLE_MESH = 1ul << GTY_TRIANGLE_MESH,
+ MTY_QUAD_MESH = 1ul << GTY_QUAD_MESH,
+ MTY_GRID_MESH = 1ul << GTY_GRID_MESH,
+ MTY_SUBDIV_MESH = 1ul << GTY_SUBDIV_MESH,
+ MTY_USER_GEOMETRY = 1ul << GTY_USER_GEOMETRY,
+
+ MTY_INSTANCE_CHEAP = 1ul << GTY_INSTANCE_CHEAP,
+ MTY_INSTANCE_EXPENSIVE = 1ul << GTY_INSTANCE_EXPENSIVE,
+ MTY_INSTANCE = MTY_INSTANCE_CHEAP | MTY_INSTANCE_EXPENSIVE
+ };
+
+ static const char* gtype_names[GTY_END];
+
+ enum class State : unsigned {
+ MODIFIED = 0,
+ COMMITTED = 1,
+ };
+
+ public:
+
+ /*! Geometry constructor */
+ Geometry (Device* device, GType gtype, unsigned int numPrimitives, unsigned int numTimeSteps);
+
+ /*! Geometry destructor */
+ virtual ~Geometry();
+
+ public:
+
+ /*! tests if geometry is enabled */
+ __forceinline bool isEnabled() const { return enabled; }
+
+ /*! tests if geometry is disabled */
+ __forceinline bool isDisabled() const { return !isEnabled(); }
+
+ /*! tests if that geometry has some filter function set */
+ __forceinline bool hasFilterFunctions () const {
+ return (intersectionFilterN != nullptr) || (occlusionFilterN != nullptr);
+ }
+
+ /*! returns geometry type */
+ __forceinline GType getType() const { return gtype; }
+
+ /*! returns curve type */
+ __forceinline GType getCurveType() const { return (GType)(gtype & GTY_SUBTYPE_MASK); }
+
+ /*! returns curve basis */
+ __forceinline GType getCurveBasis() const { return (GType)(gtype & GTY_BASIS_MASK); }
+
+ /*! returns geometry type mask */
+ __forceinline GTypeMask getTypeMask() const { return (GTypeMask)(1 << gtype); }
+
+ /*! returns number of primitives */
+ __forceinline size_t size() const { return numPrimitives; }
+
+ /*! sets the number of primitives */
+ virtual void setNumPrimitives(unsigned int numPrimitives_in);
+
+ /*! sets number of time steps */
+ virtual void setNumTimeSteps (unsigned int numTimeSteps_in);
+
+ /*! sets motion blur time range */
+ void setTimeRange (const BBox1f range);
+
+ /*! sets number of vertex attributes */
+ virtual void setVertexAttributeCount (unsigned int N) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! sets number of topologies */
+ virtual void setTopologyCount (unsigned int N) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! sets the build quality */
+ void setBuildQuality(RTCBuildQuality quality_in)
+ {
+ this->quality = quality_in;
+ Geometry::update();
+ }
+
+ /* calculate time segment itime and fractional time ftime */
+ __forceinline int timeSegment(float time, float& ftime) const {
+ return getTimeSegment(time,time_range.lower,time_range.upper,fnumTimeSegments,ftime);
+ }
+
+ template<int N>
+ __forceinline vint<N> timeSegment(const vfloat<N>& time, vfloat<N>& ftime) const {
+ return getTimeSegment<N>(time,vfloat<N>(time_range.lower),vfloat<N>(time_range.upper),vfloat<N>(fnumTimeSegments),ftime);
+ }
+
+ /* calculate overlapping time segment range */
+ __forceinline range<int> timeSegmentRange(const BBox1f& range) const {
+ return getTimeSegmentRange(range,time_range,fnumTimeSegments);
+ }
+
+ /* returns time that corresponds to time step */
+ __forceinline float timeStep(const int i) const {
+ assert(i>=0 && i<(int)numTimeSteps);
+ return time_range.lower + time_range.size()*float(i)/fnumTimeSegments;
+ }
+
+ /*! for all geometries */
+ public:
+
+ /*! Enable geometry. */
+ virtual void enable();
+
+ /*! Update geometry. */
+ void update();
+
+ /*! commit of geometry */
+ virtual void commit();
+
+ /*! Update geometry buffer. */
+ virtual void updateBuffer(RTCBufferType type, unsigned int slot) {
+ update(); // update everything for geometries not supporting this call
+ }
+
+ /*! Disable geometry. */
+ virtual void disable();
+
+ /*! Verify the geometry */
+ virtual bool verify() { return true; }
+
+ /*! called before every build */
+ virtual void preCommit();
+
+ /*! called after every build */
+ virtual void postCommit();
+
+ virtual void addElementsToCount (GeometryCounts & counts) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ };
+
+ /*! sets constant tessellation rate for the geometry */
+ virtual void setTessellationRate(float N) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Sets the maximal curve radius scale allowed by min-width feature. */
+ virtual void setMaxRadiusScale(float s) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set user data pointer. */
+ virtual void setUserData(void* ptr);
+
+ /*! Get user data pointer. */
+ __forceinline void* getUserData() const {
+ return userPtr;
+ }
+
+ /*! interpolates user data to the specified u/v location */
+ virtual void interpolate(const RTCInterpolateArguments* const args) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! interpolates user data to the specified u/v locations */
+ virtual void interpolateN(const RTCInterpolateNArguments* const args);
+
+ /* point query api */
+ bool pointQuery(PointQuery* query, PointQueryContext* context);
+
+ /*! for subdivision surfaces only */
+ public:
+ virtual void setSubdivisionMode (unsigned topologyID, RTCSubdivisionMode mode) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual void setVertexAttributeTopology(unsigned int vertexBufferSlot, unsigned int indexBufferSlot) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set displacement function. */
+ virtual void setDisplacementFunction (RTCDisplacementFunctionN filter) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual unsigned int getFirstHalfEdge(unsigned int faceID) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual unsigned int getFace(unsigned int edgeID) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual unsigned int getNextHalfEdge(unsigned int edgeID) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual unsigned int getPreviousHalfEdge(unsigned int edgeID) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ virtual unsigned int getOppositeHalfEdge(unsigned int topologyID, unsigned int edgeID) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! get fast access to first vertex buffer if applicable */
+ virtual float * getCompactVertexArray () const {
+ return nullptr;
+ }
+
+ /*! Returns the modified counter - how many times the geo has been modified */
+ __forceinline unsigned int getModCounter () const {
+ return modCounter_;
+ }
+
+ /*! for triangle meshes and bezier curves only */
+ public:
+
+
+ /*! Sets ray mask. */
+ virtual void setMask(unsigned mask) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Sets specified buffer. */
+ virtual void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Gets specified buffer. */
+ virtual void* getBuffer(RTCBufferType type, unsigned int slot) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set intersection filter function for ray packets of size N. */
+ virtual void setIntersectionFilterFunctionN (RTCFilterFunctionN filterN);
+
+ /*! Set occlusion filter function for ray packets of size N. */
+ virtual void setOcclusionFilterFunctionN (RTCFilterFunctionN filterN);
+
+ /*! for instances only */
+ public:
+
+ /*! Sets the instanced scene */
+ virtual void setInstancedScene(const Ref<Scene>& scene) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Sets transformation of the instance */
+ virtual void setTransform(const AffineSpace3fa& transform, unsigned int timeStep) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Sets transformation of the instance */
+ virtual void setQuaternionDecomposition(const AffineSpace3ff& qd, unsigned int timeStep) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Returns the transformation of the instance */
+ virtual AffineSpace3fa getTransform(float time) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! for user geometries only */
+ public:
+
+ /*! Set bounds function. */
+ virtual void setBoundsFunction (RTCBoundsFunction bounds, void* userPtr) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set intersect function for ray packets of size N. */
+ virtual void setIntersectFunctionN (RTCIntersectFunctionN intersect) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set occlusion function for ray packets of size N. */
+ virtual void setOccludedFunctionN (RTCOccludedFunctionN occluded) {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry");
+ }
+
+ /*! Set point query function. */
+ void setPointQueryFunction(RTCPointQueryFunction func);
+
+ /*! returns number of time segments */
+ __forceinline unsigned numTimeSegments () const {
+ return numTimeSteps-1;
+ }
+
+ public:
+
+ virtual PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"createPrimRefArray not implemented for this geometry");
+ }
+
+ virtual PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"createPrimRefMBArray not implemented for this geometry");
+ }
+
+ virtual PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"createPrimRefMBArray not implemented for this geometry");
+ }
+
+ virtual LinearSpace3fa computeAlignedSpace(const size_t primID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"computeAlignedSpace not implemented for this geometry");
+ }
+
+ virtual LinearSpace3fa computeAlignedSpaceMB(const size_t primID, const BBox1f time_range) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"computeAlignedSpace not implemented for this geometry");
+ }
+
+ virtual Vec3fa computeDirection(unsigned int primID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"computeDirection not implemented for this geometry");
+ }
+
+ virtual Vec3fa computeDirection(unsigned int primID, size_t time) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"computeDirection not implemented for this geometry");
+ }
+
+ virtual BBox3fa vbounds(size_t primID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vbounds not implemented for this geometry");
+ }
+
+ virtual BBox3fa vbounds(const LinearSpace3fa& space, size_t primID) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vbounds not implemented for this geometry");
+ }
+
+ virtual BBox3fa vbounds(const Vec3fa& ofs, const float scale, const float r_scale0, const LinearSpace3fa& space, size_t i, size_t itime = 0) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vbounds not implemented for this geometry");
+ }
+
+ virtual LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vlinearBounds not implemented for this geometry");
+ }
+
+ virtual LBBox3fa vlinearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vlinearBounds not implemented for this geometry");
+ }
+
+ virtual LBBox3fa vlinearBounds(const Vec3fa& ofs, const float scale, const float r_scale0, const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const {
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vlinearBounds not implemented for this geometry");
+ }
+
+ public:
+ __forceinline bool hasIntersectionFilter() const { return intersectionFilterN != nullptr; }
+ __forceinline bool hasOcclusionFilter() const { return occlusionFilterN != nullptr; }
+
+ public:
+ Device* device; //!< device this geometry belongs to
+
+ void* userPtr; //!< user pointer
+ unsigned int numPrimitives; //!< number of primitives of this geometry
+
+ unsigned int numTimeSteps; //!< number of time steps
+ float fnumTimeSegments; //!< number of time segments (precalculation)
+ BBox1f time_range; //!< motion blur time range
+
+ unsigned int mask; //!< for masking out geometry
+ unsigned int modCounter_ = 1; //!< counter for every modification - used to rebuild scenes when geo is modified
+
+ struct {
+ GType gtype : 8; //!< geometry type
+ GSubType gsubtype : 8; //!< geometry subtype
+ RTCBuildQuality quality : 3; //!< build quality for geometry
+ unsigned state : 2;
+ bool enabled : 1; //!< true if geometry is enabled
+ };
+
+ RTCFilterFunctionN intersectionFilterN;
+ RTCFilterFunctionN occlusionFilterN;
+ RTCPointQueryFunction pointQueryFunc;
+ };
+}
diff --git a/thirdparty/embree/kernels/common/hit.h b/thirdparty/embree/kernels/common/hit.h
new file mode 100644
index 0000000000..fd1a9d6391
--- /dev/null
+++ b/thirdparty/embree/kernels/common/hit.h
@@ -0,0 +1,114 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "ray.h"
+#include "instance_stack.h"
+
+namespace embree
+{
+ /* Hit structure for K hits */
+ template<int K>
+ struct HitK
+ {
+ /* Default construction does nothing */
+ __forceinline HitK() {}
+
+ /* Constructs a hit */
+ __forceinline HitK(const RTCIntersectContext* context, const vuint<K>& geomID, const vuint<K>& primID, const vfloat<K>& u, const vfloat<K>& v, const Vec3vf<K>& Ng)
+ : Ng(Ng), u(u), v(v), primID(primID), geomID(geomID)
+ {
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ instID[l] = RTC_INVALID_GEOMETRY_ID;
+ instance_id_stack::copy_UV<K>(context->instID, instID);
+ }
+
+ /* Returns the size of the hit */
+ static __forceinline size_t size() { return K; }
+
+ public:
+ Vec3vf<K> Ng; // geometry normal
+ vfloat<K> u; // barycentric u coordinate of hit
+ vfloat<K> v; // barycentric v coordinate of hit
+ vuint<K> primID; // primitive ID
+ vuint<K> geomID; // geometry ID
+ vuint<K> instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID
+ };
+
+ /* Specialization for a single hit */
+ template<>
+ struct __aligned(16) HitK<1>
+ {
+ /* Default construction does nothing */
+ __forceinline HitK() {}
+
+ /* Constructs a hit */
+ __forceinline HitK(const RTCIntersectContext* context, unsigned int geomID, unsigned int primID, float u, float v, const Vec3fa& Ng)
+ : Ng(Ng.x,Ng.y,Ng.z), u(u), v(v), primID(primID), geomID(geomID)
+ {
+ instance_id_stack::copy_UU(context->instID, instID);
+ }
+
+ /* Returns the size of the hit */
+ static __forceinline size_t size() { return 1; }
+
+ public:
+ Vec3<float> Ng; // geometry normal
+ float u; // barycentric u coordinate of hit
+ float v; // barycentric v coordinate of hit
+ unsigned int primID; // primitive ID
+ unsigned int geomID; // geometry ID
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID
+ };
+
+ /* Shortcuts */
+ typedef HitK<1> Hit;
+ typedef HitK<4> Hit4;
+ typedef HitK<8> Hit8;
+ typedef HitK<16> Hit16;
+
+ /* Outputs hit to stream */
+ template<int K>
+ __forceinline embree_ostream operator<<(embree_ostream cout, const HitK<K>& ray)
+ {
+ cout << "{ " << embree_endl
+ << " Ng = " << ray.Ng << embree_endl
+ << " u = " << ray.u << embree_endl
+ << " v = " << ray.v << embree_endl
+ << " primID = " << ray.primID << embree_endl
+ << " geomID = " << ray.geomID << embree_endl
+ << " instID =";
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ {
+ cout << " " << ray.instID[l];
+ }
+ cout << embree_endl;
+ return cout << "}";
+ }
+
+ template<typename Hit>
+ __forceinline void copyHitToRay(RayHit& ray, const Hit& hit)
+ {
+ ray.Ng = hit.Ng;
+ ray.u = hit.u;
+ ray.v = hit.v;
+ ray.primID = hit.primID;
+ ray.geomID = hit.geomID;
+ instance_id_stack::copy_UU(hit.instID, ray.instID);
+ }
+
+ template<int K>
+ __forceinline void copyHitToRay(const vbool<K> &mask, RayHitK<K> &ray, const HitK<K> &hit)
+ {
+ vfloat<K>::storeu(mask,&ray.Ng.x, hit.Ng.x);
+ vfloat<K>::storeu(mask,&ray.Ng.y, hit.Ng.y);
+ vfloat<K>::storeu(mask,&ray.Ng.z, hit.Ng.z);
+ vfloat<K>::storeu(mask,&ray.u, hit.u);
+ vfloat<K>::storeu(mask,&ray.v, hit.v);
+ vuint<K>::storeu(mask,&ray.primID, hit.primID);
+ vuint<K>::storeu(mask,&ray.geomID, hit.geomID);
+ instance_id_stack::copy_VV<K>(hit.instID, ray.instID, mask);
+ }
+}
diff --git a/thirdparty/embree/kernels/common/instance_stack.h b/thirdparty/embree/kernels/common/instance_stack.h
new file mode 100644
index 0000000000..d3c0a643f1
--- /dev/null
+++ b/thirdparty/embree/kernels/common/instance_stack.h
@@ -0,0 +1,179 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "rtcore.h"
+
+namespace embree {
+namespace instance_id_stack {
+
+static_assert(RTC_MAX_INSTANCE_LEVEL_COUNT > 0,
+ "RTC_MAX_INSTANCE_LEVEL_COUNT must be greater than 0.");
+
+/*******************************************************************************
+ * Instance ID stack manipulation.
+ * This is used from the instance intersector.
+ ******************************************************************************/
+
+/*
+ * Push an instance to the stack.
+ */
+RTC_FORCEINLINE bool push(RTCIntersectContext* context,
+ unsigned instanceId)
+{
+#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1
+ const bool spaceAvailable = context->instStackSize < RTC_MAX_INSTANCE_LEVEL_COUNT;
+ /* We assert here because instances are silently dropped when the stack is full.
+ This might be quite hard to find in production. */
+ assert(spaceAvailable);
+ if (likely(spaceAvailable))
+ context->instID[context->instStackSize++] = instanceId;
+ return spaceAvailable;
+#else
+ const bool spaceAvailable = (context->instID[0] == RTC_INVALID_GEOMETRY_ID);
+ assert(spaceAvailable);
+ if (likely(spaceAvailable))
+ context->instID[0] = instanceId;
+ return spaceAvailable;
+#endif
+}
+
+
+/*
+ * Pop the last instance pushed to the stack.
+ * Do not call on an empty stack.
+ */
+RTC_FORCEINLINE void pop(RTCIntersectContext* context)
+{
+ assert(context);
+#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1
+ assert(context->instStackSize > 0);
+ context->instID[--context->instStackSize] = RTC_INVALID_GEOMETRY_ID;
+#else
+ assert(context->instID[0] != RTC_INVALID_GEOMETRY_ID);
+ context->instID[0] = RTC_INVALID_GEOMETRY_ID;
+#endif
+}
+
+/*
+ * Optimized instance id stack copy.
+ * The copy() functions will either copy full
+ * stacks or copy only until the last valid element has been copied, depending
+ * on RTC_MAX_INSTANCE_LEVEL_COUNT.
+ */
+RTC_FORCEINLINE void copy_UU(const unsigned* src, unsigned* tgt)
+{
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT == 1)
+ tgt[0] = src[0];
+
+#else
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) {
+ tgt[l] = src[l];
+ if (RTC_MAX_INSTANCE_LEVEL_COUNT > 4)
+ if (src[l] == RTC_INVALID_GEOMETRY_ID)
+ break;
+ }
+#endif
+}
+
+template <int K>
+RTC_FORCEINLINE void copy_UV(const unsigned* src, vuint<K>* tgt)
+{
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT == 1)
+ tgt[0] = src[0];
+
+#else
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) {
+ tgt[l] = src[l];
+ if (RTC_MAX_INSTANCE_LEVEL_COUNT > 4)
+ if (src[l] == RTC_INVALID_GEOMETRY_ID)
+ break;
+ }
+#endif
+}
+
+template <int K>
+RTC_FORCEINLINE void copy_UV(const unsigned* src, vuint<K>* tgt, size_t j)
+{
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT == 1)
+ tgt[0][j] = src[0];
+
+#else
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) {
+ tgt[l][j] = src[l];
+ if (RTC_MAX_INSTANCE_LEVEL_COUNT > 4)
+ if (src[l] == RTC_INVALID_GEOMETRY_ID)
+ break;
+ }
+#endif
+}
+
+template <int K>
+RTC_FORCEINLINE void copy_UV(const unsigned* src, vuint<K>* tgt, const vbool<K>& mask)
+{
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT == 1)
+ vuint<K>::store(mask, tgt, src[0]);
+
+#else
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) {
+ vuint<K>::store(mask, tgt + l, src[l]);
+ if (RTC_MAX_INSTANCE_LEVEL_COUNT > 4)
+ if (src[l] == RTC_INVALID_GEOMETRY_ID)
+ break;
+ }
+#endif
+}
+
+template <int K>
+RTC_FORCEINLINE void copy_VU(const vuint<K>* src, unsigned* tgt, size_t i)
+{
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT == 1)
+ tgt[0] = src[0][i];
+
+#else
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) {
+ tgt[l] = src[l][i];
+ if (RTC_MAX_INSTANCE_LEVEL_COUNT > 4)
+ if (src[l][i] == RTC_INVALID_GEOMETRY_ID)
+ break;
+ }
+#endif
+}
+
+template <int K>
+RTC_FORCEINLINE void copy_VV(const vuint<K>* src, vuint<K>* tgt, size_t i, size_t j)
+{
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT == 1)
+ tgt[0][j] = src[0][i];
+
+#else
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) {
+ tgt[l][j] = src[l][i];
+ if (RTC_MAX_INSTANCE_LEVEL_COUNT > 4)
+ if (src[l][i] == RTC_INVALID_GEOMETRY_ID)
+ break;
+ }
+#endif
+}
+
+template <int K>
+RTC_FORCEINLINE void copy_VV(const vuint<K>* src, vuint<K>* tgt, const vbool<K>& mask)
+{
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT == 1)
+ vuint<K>::store(mask, tgt, src[0]);
+
+#else
+ vbool<K> done = !mask;
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) {
+ vuint<K>::store(mask, tgt + l, src[l]);
+ if (RTC_MAX_INSTANCE_LEVEL_COUNT > 4) {
+ done |= src[l] == RTC_INVALID_GEOMETRY_ID;
+ if (all(done)) break;
+ }
+ }
+#endif
+}
+
+} // namespace instance_id_stack
+} // namespace embree
diff --git a/thirdparty/embree/kernels/common/isa.h b/thirdparty/embree/kernels/common/isa.h
new file mode 100644
index 0000000000..ae6556336c
--- /dev/null
+++ b/thirdparty/embree/kernels/common/isa.h
@@ -0,0 +1,246 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../../common/sys/platform.h"
+#include "../../common/sys/sysinfo.h"
+
+namespace embree
+{
+#define DEFINE_SYMBOL2(type,name) \
+ typedef type (*name##Func)(); \
+ name##Func name;
+
+#define DECLARE_SYMBOL2(type,name) \
+ namespace sse2 { extern type name(); } \
+ namespace sse42 { extern type name(); } \
+ namespace avx { extern type name(); } \
+ namespace avx2 { extern type name(); } \
+ namespace avx512 { extern type name(); } \
+ void name##_error2() { throw_RTCError(RTC_ERROR_UNKNOWN,"internal error in ISA selection for " TOSTRING(name)); } \
+ type name##_error() { return type(name##_error2); } \
+ type name##_zero() { return type(nullptr); }
+
+#define DECLARE_ISA_FUNCTION(type,symbol,args) \
+ namespace sse2 { extern type symbol(args); } \
+ namespace sse42 { extern type symbol(args); } \
+ namespace avx { extern type symbol(args); } \
+ namespace avx2 { extern type symbol(args); } \
+ namespace avx512 { extern type symbol(args); } \
+ inline type symbol##_error(args) { throw_RTCError(RTC_ERROR_UNSUPPORTED_CPU,"function " TOSTRING(symbol) " not supported by your CPU"); } \
+ typedef type (*symbol##Ty)(args); \
+
+#define DEFINE_ISA_FUNCTION(type,symbol,args) \
+ typedef type (*symbol##Func)(args); \
+ symbol##Func symbol;
+
+#define ZERO_SYMBOL(features,intersector) \
+ intersector = intersector##_zero;
+
+#define INIT_SYMBOL(features,intersector) \
+ intersector = decltype(intersector)(intersector##_error);
+
+#define SELECT_SYMBOL_DEFAULT(features,intersector) \
+ intersector = isa::intersector;
+
+#if defined(__SSE__)
+#if !defined(EMBREE_TARGET_SIMD4)
+#define EMBREE_TARGET_SIMD4
+#endif
+#endif
+
+#if defined(EMBREE_TARGET_SSE42)
+#define SELECT_SYMBOL_SSE42(features,intersector) \
+ if ((features & SSE42) == SSE42) intersector = sse42::intersector;
+#else
+#define SELECT_SYMBOL_SSE42(features,intersector)
+#endif
+
+#if defined(EMBREE_TARGET_AVX) || defined(__AVX__)
+#if !defined(EMBREE_TARGET_SIMD8)
+#define EMBREE_TARGET_SIMD8
+#endif
+#if defined(__AVX__) // if default ISA is >= AVX we treat AVX target as default target
+#define SELECT_SYMBOL_AVX(features,intersector) \
+ if ((features & ISA) == ISA) intersector = isa::intersector;
+#else
+#define SELECT_SYMBOL_AVX(features,intersector) \
+ if ((features & AVX) == AVX) intersector = avx::intersector;
+#endif
+#else
+#define SELECT_SYMBOL_AVX(features,intersector)
+#endif
+
+#if defined(EMBREE_TARGET_AVX2)
+#if !defined(EMBREE_TARGET_SIMD8)
+#define EMBREE_TARGET_SIMD8
+#endif
+#define SELECT_SYMBOL_AVX2(features,intersector) \
+ if ((features & AVX2) == AVX2) intersector = avx2::intersector;
+#else
+#define SELECT_SYMBOL_AVX2(features,intersector)
+#endif
+
+#if defined(EMBREE_TARGET_AVX512)
+#if !defined(EMBREE_TARGET_SIMD16)
+#define EMBREE_TARGET_SIMD16
+#endif
+#define SELECT_SYMBOL_AVX512(features,intersector) \
+ if ((features & AVX512) == AVX512) intersector = avx512::intersector;
+#else
+#define SELECT_SYMBOL_AVX512(features,intersector)
+#endif
+
+#define SELECT_SYMBOL_DEFAULT_SSE42(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_SSE42_AVX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX512(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX2(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX512(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX512(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX2(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_INIT_SSE42_AVX_AVX2(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX512(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX2(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_INIT_SSE42_AVX_AVX2_AVX512(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_ZERO_SSE42_AVX_AVX2_AVX512(features,intersector) \
+ ZERO_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(features,intersector) \
+ SELECT_SYMBOL_DEFAULT(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_INIT_AVX512(features,intersector) \
+ INIT_SYMBOL(features,intersector); \
+ SELECT_SYMBOL_AVX512(features,intersector);
+
+#define SELECT_SYMBOL_SSE42_AVX_AVX2(features,intersector) \
+ SELECT_SYMBOL_SSE42(features,intersector); \
+ SELECT_SYMBOL_AVX(features,intersector); \
+ SELECT_SYMBOL_AVX2(features,intersector);
+
+ struct VerifyMultiTargetLinking {
+ static __noinline int getISA(int depth = 5) {
+ if (depth == 0) return ISA;
+ else return getISA(depth-1);
+ }
+ };
+ namespace sse2 { int getISA(); };
+ namespace sse42 { int getISA(); };
+ namespace avx { int getISA(); };
+ namespace avx2 { int getISA(); };
+ namespace avx512 { int getISA(); };
+}
diff --git a/thirdparty/embree/kernels/common/motion_derivative.h b/thirdparty/embree/kernels/common/motion_derivative.h
new file mode 100644
index 0000000000..c619d6a675
--- /dev/null
+++ b/thirdparty/embree/kernels/common/motion_derivative.h
@@ -0,0 +1,325 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../../common/math/affinespace.h"
+#include "../../common/math/interval.h"
+
+#include <functional>
+
+namespace embree {
+
+#define MOTION_DERIVATIVE_ROOT_EPSILON 1e-4f
+
+static void motion_derivative_coefficients(const float *p, float *coeff);
+
+struct MotionDerivativeCoefficients
+{
+ float theta;
+ float coeffs[3*8*7];
+
+ MotionDerivativeCoefficients() {}
+
+ // xfm0 and xfm1 are interpret as quaternion decomposition
+ MotionDerivativeCoefficients(AffineSpace3ff const& xfm0, AffineSpace3ff const& xfm1)
+ {
+ // cosTheta of the two quaternions
+ const float cosTheta = min(1.f, max(-1.f,
+ xfm0.l.vx.w * xfm1.l.vx.w
+ + xfm0.l.vy.w * xfm1.l.vy.w
+ + xfm0.l.vz.w * xfm1.l.vz.w
+ + xfm0.p.w * xfm1.p.w));
+
+ theta = std::acos(cosTheta);
+ Vec4f qperp(xfm1.p.w, xfm1.l.vx.w, xfm1.l.vy.w, xfm1.l.vz.w);
+ if (cosTheta < 0.995f) {
+ // compute perpendicular quaternion
+ qperp.x = xfm1.p.w - cosTheta * xfm0.p.w;
+ qperp.y = xfm1.l.vx.w - cosTheta * xfm0.l.vx.w;
+ qperp.z = xfm1.l.vy.w - cosTheta * xfm0.l.vy.w;
+ qperp.w = xfm1.l.vz.w - cosTheta * xfm0.l.vz.w;
+ qperp = normalize(qperp);
+ }
+ const float p[33] = {
+ theta,
+ xfm0.l.vx.y, xfm0.l.vx.z, xfm0.l.vy.z, // translation component of xfm0
+ xfm1.l.vx.y, xfm1.l.vx.z, xfm1.l.vy.z, // translation component of xfm1
+ xfm0.p.w, xfm0.l.vx.w, xfm0.l.vy.w, xfm0.l.vz.w, // quaternion of xfm0
+ qperp.x, qperp.y, qperp.z, qperp.w,
+ xfm0.l.vx.x, xfm0.l.vy.x, xfm0.l.vz.x, xfm0.p.x, // scale/skew component of xfm0
+ xfm0.l.vy.y, xfm0.l.vz.y, xfm0.p.y,
+ xfm0.l.vz.z, xfm0.p.z,
+ xfm1.l.vx.x, xfm1.l.vy.x, xfm1.l.vz.x, xfm1.p.x, // scale/skew component of xfm1
+ xfm1.l.vy.y, xfm1.l.vz.y, xfm1.p.y,
+ xfm1.l.vz.z, xfm1.p.z
+ };
+ motion_derivative_coefficients(p, coeffs);
+ }
+};
+
+struct MotionDerivative
+{
+ float twoTheta;
+ float c[8];
+
+ MotionDerivative(MotionDerivativeCoefficients const& mdc,
+ int dim, Vec3fa const& p0, Vec3fa const& p1)
+ : twoTheta(2.f*mdc.theta)
+ {
+ const float p[7] = { 1, p0.x, p0.y, p0.z, p1.x, p1.y, p1.z };
+ for (int i = 0; i < 8; ++i) {
+ c[i] = 0;
+ for (int j = 0; j < 7; ++j) {
+ c[i] += mdc.coeffs[8*7*dim + i*7 + j] * p[j];
+ }
+ }
+ }
+
+ template<typename T>
+ struct EvalMotionDerivative
+ {
+ MotionDerivative const& md;
+ float offset;
+
+ EvalMotionDerivative(MotionDerivative const& md, float offset) : md(md), offset(offset) {}
+
+ T operator()(T const& time) const {
+ return md.c[0] + md.c[1] * time
+ + (md.c[2] + md.c[3] * time + md.c[4] * time * time) * cos(md.twoTheta * time)
+ + (md.c[5] + md.c[6] * time + md.c[7] * time * time) * sin(md.twoTheta * time)
+ + offset;
+ }
+ };
+
+ unsigned int findRoots(
+ Interval1f const& interval,
+ float offset,
+ float* roots,
+ unsigned int maxNumRoots)
+ {
+ unsigned int numRoots = 0;
+ EvalMotionDerivative<Interval1f> eval(*this, offset);
+ findRoots(eval, interval, numRoots, roots, maxNumRoots);
+ return numRoots;
+ }
+
+ template<typename Eval>
+ static void findRoots(
+
+ Eval const& eval,
+ Interval1f const& interval,
+ unsigned int& numRoots,
+ float* roots,
+ unsigned int maxNumRoots)
+ {
+ Interval1f range = eval(interval);
+ if (range.lower > 0 || range.upper < 0 || range.lower >= range.upper) return;
+
+ const float split = 0.5f * (interval.upper + interval.lower);
+ if (interval.upper-interval.lower < 1e-7f || abs(split-interval.lower) < 1e-7f || abs(split-interval.upper) < 1e-7f)
+ {
+ // check if the root already exists
+ for (unsigned int k = 0; k < numRoots && k < maxNumRoots; ++k) {
+ if (abs(roots[k]-split) < MOTION_DERIVATIVE_ROOT_EPSILON)
+ return;
+ }
+ if (numRoots < maxNumRoots) {
+ roots[numRoots++] = split;
+ }
+ if (numRoots > maxNumRoots) {
+ printf("error: more roots than expected\n"); // FIXME: workaround for ICC2019.4 compiler bug under macOS
+ return;
+ }
+ return;
+ }
+
+ findRoots(eval, Interval1f(interval.lower, split), numRoots, roots, maxNumRoots);
+ findRoots(eval, Interval1f(split, interval.upper), numRoots, roots, maxNumRoots);
+ }
+};
+
+/******************************************************************************
+ * Code generated with sympy 1.4 *
+ * See http://www.sympy.org/ for more information. *
+ * *
+ * see *
+ * *
+ * scripts/generate_motion_derivative_coefficients.py *
+ * *
+ * for how this code is generated *
+ * *
+ ******************************************************************************/
+static void motion_derivative_coefficients(const float *p, float *coeff)
+{
+ coeff[0] = -p[1] + p[4] - p[7]*p[9]*p[23] + p[7]*p[9]*p[32] + p[7]*p[10]*p[21] - p[7]*p[10]*p[30] - p[8]*p[9]*p[21] + p[8]*p[9]*p[30] - p[8]*p[10]*p[23] + p[8]*p[10]*p[32] + p[9]*p[9]*p[18] - p[9]*p[9]*p[27] + p[10]*p[10]*p[18] - p[10]*p[10]*p[27] - p[11]*p[13]*p[23] + p[11]*p[13]*p[32] + p[11]*p[14]*p[21] - p[11]*p[14]*p[30] - p[12]*p[13]*p[21] + p[12]*p[13]*p[30] - p[12]*p[14]*p[23] + p[12]*p[14]*p[32] + p[13]*p[13]*p[18] - p[13]*p[13]*p[27] + p[14]*p[14]*p[18] - p[14]*p[14]*p[27] - p[18] + p[27];
+ coeff[1] = 2*p[9]*p[9]*p[15] - p[9]*p[9]*p[24] + 2*p[10]*p[10]*p[15] - p[10]*p[10]*p[24] + 2*p[13]*p[13]*p[15] - p[13]*p[13]*p[24] + 2*p[14]*p[14]*p[15] - p[14]*p[14]*p[24] - 2*p[15] + p[24];
+ coeff[2] = 2*p[7]*p[10]*p[19] - p[7]*p[10]*p[28] - 2*p[8]*p[9]*p[19] + p[8]*p[9]*p[28] + 2*p[9]*p[9]*p[16] - p[9]*p[9]*p[25] + 2*p[10]*p[10]*p[16] - p[10]*p[10]*p[25] + 2*p[11]*p[14]*p[19] - p[11]*p[14]*p[28] - 2*p[12]*p[13]*p[19] + p[12]*p[13]*p[28] + 2*p[13]*p[13]*p[16] - p[13]*p[13]*p[25] + 2*p[14]*p[14]*p[16] - p[14]*p[14]*p[25] - 2*p[16] + p[25];
+ coeff[3] = -2*p[7]*p[9]*p[22] + p[7]*p[9]*p[31] + 2*p[7]*p[10]*p[20] - p[7]*p[10]*p[29] - 2*p[8]*p[9]*p[20] + p[8]*p[9]*p[29] - 2*p[8]*p[10]*p[22] + p[8]*p[10]*p[31] + 2*p[9]*p[9]*p[17] - p[9]*p[9]*p[26] + 2*p[10]*p[10]*p[17] - p[10]*p[10]*p[26] - 2*p[11]*p[13]*p[22] + p[11]*p[13]*p[31] + 2*p[11]*p[14]*p[20] - p[11]*p[14]*p[29] - 2*p[12]*p[13]*p[20] + p[12]*p[13]*p[29] - 2*p[12]*p[14]*p[22] + p[12]*p[14]*p[31] + 2*p[13]*p[13]*p[17] - p[13]*p[13]*p[26] + 2*p[14]*p[14]*p[17] - p[14]*p[14]*p[26] - 2*p[17] + p[26];
+ coeff[4] = (-p[9]*p[9] - p[10]*p[10] - p[13]*p[13] - p[14]*p[14] + 1)*p[15];
+ coeff[5] = -p[7]*p[10]*p[19] + p[8]*p[9]*p[19] - p[9]*p[9]*p[16] - p[10]*p[10]*p[16] - p[11]*p[14]*p[19] + p[12]*p[13]*p[19] - p[13]*p[13]*p[16] - p[14]*p[14]*p[16] + p[16];
+ coeff[6] = p[7]*p[9]*p[22] - p[7]*p[10]*p[20] + p[8]*p[9]*p[20] + p[8]*p[10]*p[22] - p[9]*p[9]*p[17] - p[10]*p[10]*p[17] + p[11]*p[13]*p[22] - p[11]*p[14]*p[20] + p[12]*p[13]*p[20] + p[12]*p[14]*p[22] - p[13]*p[13]*p[17] - p[14]*p[14]*p[17] + p[17];
+ coeff[7] = 0;
+ coeff[8] = -2*p[9]*p[9]*p[15] + 2*p[9]*p[9]*p[24] - 2*p[10]*p[10]*p[15] + 2*p[10]*p[10]*p[24] - 2*p[13]*p[13]*p[15] + 2*p[13]*p[13]*p[24] - 2*p[14]*p[14]*p[15] + 2*p[14]*p[14]*p[24] + 2*p[15] - 2*p[24];
+ coeff[9] = -2*p[7]*p[10]*p[19] + 2*p[7]*p[10]*p[28] + 2*p[8]*p[9]*p[19] - 2*p[8]*p[9]*p[28] - 2*p[9]*p[9]*p[16] + 2*p[9]*p[9]*p[25] - 2*p[10]*p[10]*p[16] + 2*p[10]*p[10]*p[25] - 2*p[11]*p[14]*p[19] + 2*p[11]*p[14]*p[28] + 2*p[12]*p[13]*p[19] - 2*p[12]*p[13]*p[28] - 2*p[13]*p[13]*p[16] + 2*p[13]*p[13]*p[25] - 2*p[14]*p[14]*p[16] + 2*p[14]*p[14]*p[25] + 2*p[16] - 2*p[25];
+ coeff[10] = 2*p[7]*p[9]*p[22] - 2*p[7]*p[9]*p[31] - 2*p[7]*p[10]*p[20] + 2*p[7]*p[10]*p[29] + 2*p[8]*p[9]*p[20] - 2*p[8]*p[9]*p[29] + 2*p[8]*p[10]*p[22] - 2*p[8]*p[10]*p[31] - 2*p[9]*p[9]*p[17] + 2*p[9]*p[9]*p[26] - 2*p[10]*p[10]*p[17] + 2*p[10]*p[10]*p[26] + 2*p[11]*p[13]*p[22] - 2*p[11]*p[13]*p[31] - 2*p[11]*p[14]*p[20] + 2*p[11]*p[14]*p[29] + 2*p[12]*p[13]*p[20] - 2*p[12]*p[13]*p[29] + 2*p[12]*p[14]*p[22] - 2*p[12]*p[14]*p[31] - 2*p[13]*p[13]*p[17] + 2*p[13]*p[13]*p[26] - 2*p[14]*p[14]*p[17] + 2*p[14]*p[14]*p[26] + 2*p[17] - 2*p[26];
+ coeff[11] = 2*p[9]*p[9]*p[15] - 2*p[9]*p[9]*p[24] + 2*p[10]*p[10]*p[15] - 2*p[10]*p[10]*p[24] + 2*p[13]*p[13]*p[15] - 2*p[13]*p[13]*p[24] + 2*p[14]*p[14]*p[15] - 2*p[14]*p[14]*p[24] - 2*p[15] + 2*p[24];
+ coeff[12] = 2*p[7]*p[10]*p[19] - 2*p[7]*p[10]*p[28] - 2*p[8]*p[9]*p[19] + 2*p[8]*p[9]*p[28] + 2*p[9]*p[9]*p[16] - 2*p[9]*p[9]*p[25] + 2*p[10]*p[10]*p[16] - 2*p[10]*p[10]*p[25] + 2*p[11]*p[14]*p[19] - 2*p[11]*p[14]*p[28] - 2*p[12]*p[13]*p[19] + 2*p[12]*p[13]*p[28] + 2*p[13]*p[13]*p[16] - 2*p[13]*p[13]*p[25] + 2*p[14]*p[14]*p[16] - 2*p[14]*p[14]*p[25] - 2*p[16] + 2*p[25];
+ coeff[13] = -2*p[7]*p[9]*p[22] + 2*p[7]*p[9]*p[31] + 2*p[7]*p[10]*p[20] - 2*p[7]*p[10]*p[29] - 2*p[8]*p[9]*p[20] + 2*p[8]*p[9]*p[29] - 2*p[8]*p[10]*p[22] + 2*p[8]*p[10]*p[31] + 2*p[9]*p[9]*p[17] - 2*p[9]*p[9]*p[26] + 2*p[10]*p[10]*p[17] - 2*p[10]*p[10]*p[26] - 2*p[11]*p[13]*p[22] + 2*p[11]*p[13]*p[31] + 2*p[11]*p[14]*p[20] - 2*p[11]*p[14]*p[29] - 2*p[12]*p[13]*p[20] + 2*p[12]*p[13]*p[29] - 2*p[12]*p[14]*p[22] + 2*p[12]*p[14]*p[31] + 2*p[13]*p[13]*p[17] - 2*p[13]*p[13]*p[26] + 2*p[14]*p[14]*p[17] - 2*p[14]*p[14]*p[26] - 2*p[17] + 2*p[26];
+ coeff[14] = 2*p[0]*p[7]*p[11]*p[18] + 2*p[0]*p[7]*p[13]*p[23] - 2*p[0]*p[7]*p[14]*p[21] + 2*p[0]*p[8]*p[12]*p[18] + 2*p[0]*p[8]*p[13]*p[21] + 2*p[0]*p[8]*p[14]*p[23] + 2*p[0]*p[9]*p[11]*p[23] + 2*p[0]*p[9]*p[12]*p[21] - 2*p[0]*p[9]*p[13]*p[18] - 2*p[0]*p[10]*p[11]*p[21] + 2*p[0]*p[10]*p[12]*p[23] - 2*p[0]*p[10]*p[14]*p[18] - p[7]*p[9]*p[23] + p[7]*p[9]*p[32] + p[7]*p[10]*p[21] - p[7]*p[10]*p[30] - p[8]*p[9]*p[21] + p[8]*p[9]*p[30] - p[8]*p[10]*p[23] + p[8]*p[10]*p[32] + p[9]*p[9]*p[18] - p[9]*p[9]*p[27] + p[10]*p[10]*p[18] - p[10]*p[10]*p[27] + p[11]*p[13]*p[23] - p[11]*p[13]*p[32] - p[11]*p[14]*p[21] + p[11]*p[14]*p[30] + p[12]*p[13]*p[21] - p[12]*p[13]*p[30] + p[12]*p[14]*p[23] - p[12]*p[14]*p[32] - p[13]*p[13]*p[18] + p[13]*p[13]*p[27] - p[14]*p[14]*p[18] + p[14]*p[14]*p[27];
+ coeff[15] = 2*p[0]*p[7]*p[11]*p[15] + 2*p[0]*p[8]*p[12]*p[15] - 2*p[0]*p[9]*p[13]*p[15] - 2*p[0]*p[10]*p[14]*p[15] + 2*p[9]*p[9]*p[15] - p[9]*p[9]*p[24] + 2*p[10]*p[10]*p[15] - p[10]*p[10]*p[24] - 2*p[13]*p[13]*p[15] + p[13]*p[13]*p[24] - 2*p[14]*p[14]*p[15] + p[14]*p[14]*p[24];
+ coeff[16] = 2*p[0]*p[7]*p[11]*p[16] - 2*p[0]*p[7]*p[14]*p[19] + 2*p[0]*p[8]*p[12]*p[16] + 2*p[0]*p[8]*p[13]*p[19] + 2*p[0]*p[9]*p[12]*p[19] - 2*p[0]*p[9]*p[13]*p[16] - 2*p[0]*p[10]*p[11]*p[19] - 2*p[0]*p[10]*p[14]*p[16] + 2*p[7]*p[10]*p[19] - p[7]*p[10]*p[28] - 2*p[8]*p[9]*p[19] + p[8]*p[9]*p[28] + 2*p[9]*p[9]*p[16] - p[9]*p[9]*p[25] + 2*p[10]*p[10]*p[16] - p[10]*p[10]*p[25] - 2*p[11]*p[14]*p[19] + p[11]*p[14]*p[28] + 2*p[12]*p[13]*p[19] - p[12]*p[13]*p[28] - 2*p[13]*p[13]*p[16] + p[13]*p[13]*p[25] - 2*p[14]*p[14]*p[16] + p[14]*p[14]*p[25];
+ coeff[17] = 2*p[0]*p[7]*p[11]*p[17] + 2*p[0]*p[7]*p[13]*p[22] - 2*p[0]*p[7]*p[14]*p[20] + 2*p[0]*p[8]*p[12]*p[17] + 2*p[0]*p[8]*p[13]*p[20] + 2*p[0]*p[8]*p[14]*p[22] + 2*p[0]*p[9]*p[11]*p[22] + 2*p[0]*p[9]*p[12]*p[20] - 2*p[0]*p[9]*p[13]*p[17] - 2*p[0]*p[10]*p[11]*p[20] + 2*p[0]*p[10]*p[12]*p[22] - 2*p[0]*p[10]*p[14]*p[17] - 2*p[7]*p[9]*p[22] + p[7]*p[9]*p[31] + 2*p[7]*p[10]*p[20] - p[7]*p[10]*p[29] - 2*p[8]*p[9]*p[20] + p[8]*p[9]*p[29] - 2*p[8]*p[10]*p[22] + p[8]*p[10]*p[31] + 2*p[9]*p[9]*p[17] - p[9]*p[9]*p[26] + 2*p[10]*p[10]*p[17] - p[10]*p[10]*p[26] + 2*p[11]*p[13]*p[22] - p[11]*p[13]*p[31] - 2*p[11]*p[14]*p[20] + p[11]*p[14]*p[29] + 2*p[12]*p[13]*p[20] - p[12]*p[13]*p[29] + 2*p[12]*p[14]*p[22] - p[12]*p[14]*p[31] - 2*p[13]*p[13]*p[17] + p[13]*p[13]*p[26] - 2*p[14]*p[14]*p[17] + p[14]*p[14]*p[26];
+ coeff[18] = (-p[9]*p[9] - p[10]*p[10] + p[13]*p[13] + p[14]*p[14])*p[15];
+ coeff[19] = -p[7]*p[10]*p[19] + p[8]*p[9]*p[19] - p[9]*p[9]*p[16] - p[10]*p[10]*p[16] + p[11]*p[14]*p[19] - p[12]*p[13]*p[19] + p[13]*p[13]*p[16] + p[14]*p[14]*p[16];
+ coeff[20] = p[7]*p[9]*p[22] - p[7]*p[10]*p[20] + p[8]*p[9]*p[20] + p[8]*p[10]*p[22] - p[9]*p[9]*p[17] - p[10]*p[10]*p[17] - p[11]*p[13]*p[22] + p[11]*p[14]*p[20] - p[12]*p[13]*p[20] - p[12]*p[14]*p[22] + p[13]*p[13]*p[17] + p[14]*p[14]*p[17];
+ coeff[21] = 2*(-p[7]*p[11]*p[18] + p[7]*p[11]*p[27] - p[7]*p[13]*p[23] + p[7]*p[13]*p[32] + p[7]*p[14]*p[21] - p[7]*p[14]*p[30] - p[8]*p[12]*p[18] + p[8]*p[12]*p[27] - p[8]*p[13]*p[21] + p[8]*p[13]*p[30] - p[8]*p[14]*p[23] + p[8]*p[14]*p[32] - p[9]*p[11]*p[23] + p[9]*p[11]*p[32] - p[9]*p[12]*p[21] + p[9]*p[12]*p[30] + p[9]*p[13]*p[18] - p[9]*p[13]*p[27] + p[10]*p[11]*p[21] - p[10]*p[11]*p[30] - p[10]*p[12]*p[23] + p[10]*p[12]*p[32] + p[10]*p[14]*p[18] - p[10]*p[14]*p[27])*p[0];
+ coeff[22] = -4*p[0]*p[7]*p[11]*p[15] + 2*p[0]*p[7]*p[11]*p[24] - 4*p[0]*p[8]*p[12]*p[15] + 2*p[0]*p[8]*p[12]*p[24] + 4*p[0]*p[9]*p[13]*p[15] - 2*p[0]*p[9]*p[13]*p[24] + 4*p[0]*p[10]*p[14]*p[15] - 2*p[0]*p[10]*p[14]*p[24] - 2*p[9]*p[9]*p[15] + 2*p[9]*p[9]*p[24] - 2*p[10]*p[10]*p[15] + 2*p[10]*p[10]*p[24] + 2*p[13]*p[13]*p[15] - 2*p[13]*p[13]*p[24] + 2*p[14]*p[14]*p[15] - 2*p[14]*p[14]*p[24];
+ coeff[23] = -4*p[0]*p[7]*p[11]*p[16] + 2*p[0]*p[7]*p[11]*p[25] + 4*p[0]*p[7]*p[14]*p[19] - 2*p[0]*p[7]*p[14]*p[28] - 4*p[0]*p[8]*p[12]*p[16] + 2*p[0]*p[8]*p[12]*p[25] - 4*p[0]*p[8]*p[13]*p[19] + 2*p[0]*p[8]*p[13]*p[28] - 4*p[0]*p[9]*p[12]*p[19] + 2*p[0]*p[9]*p[12]*p[28] + 4*p[0]*p[9]*p[13]*p[16] - 2*p[0]*p[9]*p[13]*p[25] + 4*p[0]*p[10]*p[11]*p[19] - 2*p[0]*p[10]*p[11]*p[28] + 4*p[0]*p[10]*p[14]*p[16] - 2*p[0]*p[10]*p[14]*p[25] - 2*p[7]*p[10]*p[19] + 2*p[7]*p[10]*p[28] + 2*p[8]*p[9]*p[19] - 2*p[8]*p[9]*p[28] - 2*p[9]*p[9]*p[16] + 2*p[9]*p[9]*p[25] - 2*p[10]*p[10]*p[16] + 2*p[10]*p[10]*p[25] + 2*p[11]*p[14]*p[19] - 2*p[11]*p[14]*p[28] - 2*p[12]*p[13]*p[19] + 2*p[12]*p[13]*p[28] + 2*p[13]*p[13]*p[16] - 2*p[13]*p[13]*p[25] + 2*p[14]*p[14]*p[16] - 2*p[14]*p[14]*p[25];
+ coeff[24] = -4*p[0]*p[7]*p[11]*p[17] + 2*p[0]*p[7]*p[11]*p[26] - 4*p[0]*p[7]*p[13]*p[22] + 2*p[0]*p[7]*p[13]*p[31] + 4*p[0]*p[7]*p[14]*p[20] - 2*p[0]*p[7]*p[14]*p[29] - 4*p[0]*p[8]*p[12]*p[17] + 2*p[0]*p[8]*p[12]*p[26] - 4*p[0]*p[8]*p[13]*p[20] + 2*p[0]*p[8]*p[13]*p[29] - 4*p[0]*p[8]*p[14]*p[22] + 2*p[0]*p[8]*p[14]*p[31] - 4*p[0]*p[9]*p[11]*p[22] + 2*p[0]*p[9]*p[11]*p[31] - 4*p[0]*p[9]*p[12]*p[20] + 2*p[0]*p[9]*p[12]*p[29] + 4*p[0]*p[9]*p[13]*p[17] - 2*p[0]*p[9]*p[13]*p[26] + 4*p[0]*p[10]*p[11]*p[20] - 2*p[0]*p[10]*p[11]*p[29] - 4*p[0]*p[10]*p[12]*p[22] + 2*p[0]*p[10]*p[12]*p[31] + 4*p[0]*p[10]*p[14]*p[17] - 2*p[0]*p[10]*p[14]*p[26] + 2*p[7]*p[9]*p[22] - 2*p[7]*p[9]*p[31] - 2*p[7]*p[10]*p[20] + 2*p[7]*p[10]*p[29] + 2*p[8]*p[9]*p[20] - 2*p[8]*p[9]*p[29] + 2*p[8]*p[10]*p[22] - 2*p[8]*p[10]*p[31] - 2*p[9]*p[9]*p[17] + 2*p[9]*p[9]*p[26] - 2*p[10]*p[10]*p[17] + 2*p[10]*p[10]*p[26] - 2*p[11]*p[13]*p[22] + 2*p[11]*p[13]*p[31] + 2*p[11]*p[14]*p[20] - 2*p[11]*p[14]*p[29] - 2*p[12]*p[13]*p[20] + 2*p[12]*p[13]*p[29] - 2*p[12]*p[14]*p[22] + 2*p[12]*p[14]*p[31] + 2*p[13]*p[13]*p[17] - 2*p[13]*p[13]*p[26] + 2*p[14]*p[14]*p[17] - 2*p[14]*p[14]*p[26];
+ coeff[25] = 2*p[0]*p[7]*p[11]*p[15] + 2*p[0]*p[8]*p[12]*p[15] - 2*p[0]*p[9]*p[13]*p[15] - 2*p[0]*p[10]*p[14]*p[15] + 2*p[9]*p[9]*p[15] - 2*p[9]*p[9]*p[24] + 2*p[10]*p[10]*p[15] - 2*p[10]*p[10]*p[24] - 2*p[13]*p[13]*p[15] + 2*p[13]*p[13]*p[24] - 2*p[14]*p[14]*p[15] + 2*p[14]*p[14]*p[24];
+ coeff[26] = 2*p[0]*p[7]*p[11]*p[16] - 2*p[0]*p[7]*p[14]*p[19] + 2*p[0]*p[8]*p[12]*p[16] + 2*p[0]*p[8]*p[13]*p[19] + 2*p[0]*p[9]*p[12]*p[19] - 2*p[0]*p[9]*p[13]*p[16] - 2*p[0]*p[10]*p[11]*p[19] - 2*p[0]*p[10]*p[14]*p[16] + 2*p[7]*p[10]*p[19] - 2*p[7]*p[10]*p[28] - 2*p[8]*p[9]*p[19] + 2*p[8]*p[9]*p[28] + 2*p[9]*p[9]*p[16] - 2*p[9]*p[9]*p[25] + 2*p[10]*p[10]*p[16] - 2*p[10]*p[10]*p[25] - 2*p[11]*p[14]*p[19] + 2*p[11]*p[14]*p[28] + 2*p[12]*p[13]*p[19] - 2*p[12]*p[13]*p[28] - 2*p[13]*p[13]*p[16] + 2*p[13]*p[13]*p[25] - 2*p[14]*p[14]*p[16] + 2*p[14]*p[14]*p[25];
+ coeff[27] = 2*p[0]*p[7]*p[11]*p[17] + 2*p[0]*p[7]*p[13]*p[22] - 2*p[0]*p[7]*p[14]*p[20] + 2*p[0]*p[8]*p[12]*p[17] + 2*p[0]*p[8]*p[13]*p[20] + 2*p[0]*p[8]*p[14]*p[22] + 2*p[0]*p[9]*p[11]*p[22] + 2*p[0]*p[9]*p[12]*p[20] - 2*p[0]*p[9]*p[13]*p[17] - 2*p[0]*p[10]*p[11]*p[20] + 2*p[0]*p[10]*p[12]*p[22] - 2*p[0]*p[10]*p[14]*p[17] - 2*p[7]*p[9]*p[22] + 2*p[7]*p[9]*p[31] + 2*p[7]*p[10]*p[20] - 2*p[7]*p[10]*p[29] - 2*p[8]*p[9]*p[20] + 2*p[8]*p[9]*p[29] - 2*p[8]*p[10]*p[22] + 2*p[8]*p[10]*p[31] + 2*p[9]*p[9]*p[17] - 2*p[9]*p[9]*p[26] + 2*p[10]*p[10]*p[17] - 2*p[10]*p[10]*p[26] + 2*p[11]*p[13]*p[22] - 2*p[11]*p[13]*p[31] - 2*p[11]*p[14]*p[20] + 2*p[11]*p[14]*p[29] + 2*p[12]*p[13]*p[20] - 2*p[12]*p[13]*p[29] + 2*p[12]*p[14]*p[22] - 2*p[12]*p[14]*p[31] - 2*p[13]*p[13]*p[17] + 2*p[13]*p[13]*p[26] - 2*p[14]*p[14]*p[17] + 2*p[14]*p[14]*p[26];
+ coeff[28] = 0;
+ coeff[29] = 2*(p[7]*p[11]*p[15] - p[7]*p[11]*p[24] + p[8]*p[12]*p[15] - p[8]*p[12]*p[24] - p[9]*p[13]*p[15] + p[9]*p[13]*p[24] - p[10]*p[14]*p[15] + p[10]*p[14]*p[24])*p[0];
+ coeff[30] = 2*(p[7]*p[11]*p[16] - p[7]*p[11]*p[25] - p[7]*p[14]*p[19] + p[7]*p[14]*p[28] + p[8]*p[12]*p[16] - p[8]*p[12]*p[25] + p[8]*p[13]*p[19] - p[8]*p[13]*p[28] + p[9]*p[12]*p[19] - p[9]*p[12]*p[28] - p[9]*p[13]*p[16] + p[9]*p[13]*p[25] - p[10]*p[11]*p[19] + p[10]*p[11]*p[28] - p[10]*p[14]*p[16] + p[10]*p[14]*p[25])*p[0];
+ coeff[31] = 2*(p[7]*p[11]*p[17] - p[7]*p[11]*p[26] + p[7]*p[13]*p[22] - p[7]*p[13]*p[31] - p[7]*p[14]*p[20] + p[7]*p[14]*p[29] + p[8]*p[12]*p[17] - p[8]*p[12]*p[26] + p[8]*p[13]*p[20] - p[8]*p[13]*p[29] + p[8]*p[14]*p[22] - p[8]*p[14]*p[31] + p[9]*p[11]*p[22] - p[9]*p[11]*p[31] + p[9]*p[12]*p[20] - p[9]*p[12]*p[29] - p[9]*p[13]*p[17] + p[9]*p[13]*p[26] - p[10]*p[11]*p[20] + p[10]*p[11]*p[29] + p[10]*p[12]*p[22] - p[10]*p[12]*p[31] - p[10]*p[14]*p[17] + p[10]*p[14]*p[26])*p[0];
+ coeff[32] = 2*(-p[7]*p[11]*p[15] + p[7]*p[11]*p[24] - p[8]*p[12]*p[15] + p[8]*p[12]*p[24] + p[9]*p[13]*p[15] - p[9]*p[13]*p[24] + p[10]*p[14]*p[15] - p[10]*p[14]*p[24])*p[0];
+ coeff[33] = 2*(-p[7]*p[11]*p[16] + p[7]*p[11]*p[25] + p[7]*p[14]*p[19] - p[7]*p[14]*p[28] - p[8]*p[12]*p[16] + p[8]*p[12]*p[25] - p[8]*p[13]*p[19] + p[8]*p[13]*p[28] - p[9]*p[12]*p[19] + p[9]*p[12]*p[28] + p[9]*p[13]*p[16] - p[9]*p[13]*p[25] + p[10]*p[11]*p[19] - p[10]*p[11]*p[28] + p[10]*p[14]*p[16] - p[10]*p[14]*p[25])*p[0];
+ coeff[34] = 2*(-p[7]*p[11]*p[17] + p[7]*p[11]*p[26] - p[7]*p[13]*p[22] + p[7]*p[13]*p[31] + p[7]*p[14]*p[20] - p[7]*p[14]*p[29] - p[8]*p[12]*p[17] + p[8]*p[12]*p[26] - p[8]*p[13]*p[20] + p[8]*p[13]*p[29] - p[8]*p[14]*p[22] + p[8]*p[14]*p[31] - p[9]*p[11]*p[22] + p[9]*p[11]*p[31] - p[9]*p[12]*p[20] + p[9]*p[12]*p[29] + p[9]*p[13]*p[17] - p[9]*p[13]*p[26] + p[10]*p[11]*p[20] - p[10]*p[11]*p[29] - p[10]*p[12]*p[22] + p[10]*p[12]*p[31] + p[10]*p[14]*p[17] - p[10]*p[14]*p[26])*p[0];
+ coeff[35] = -2*p[0]*p[7]*p[9]*p[23] + 2*p[0]*p[7]*p[10]*p[21] - 2*p[0]*p[8]*p[9]*p[21] - 2*p[0]*p[8]*p[10]*p[23] + 2*p[0]*p[9]*p[9]*p[18] + 2*p[0]*p[10]*p[10]*p[18] + 2*p[0]*p[11]*p[13]*p[23] - 2*p[0]*p[11]*p[14]*p[21] + 2*p[0]*p[12]*p[13]*p[21] + 2*p[0]*p[12]*p[14]*p[23] - 2*p[0]*p[13]*p[13]*p[18] - 2*p[0]*p[14]*p[14]*p[18] - p[7]*p[11]*p[18] + p[7]*p[11]*p[27] - p[7]*p[13]*p[23] + p[7]*p[13]*p[32] + p[7]*p[14]*p[21] - p[7]*p[14]*p[30] - p[8]*p[12]*p[18] + p[8]*p[12]*p[27] - p[8]*p[13]*p[21] + p[8]*p[13]*p[30] - p[8]*p[14]*p[23] + p[8]*p[14]*p[32] - p[9]*p[11]*p[23] + p[9]*p[11]*p[32] - p[9]*p[12]*p[21] + p[9]*p[12]*p[30] + p[9]*p[13]*p[18] - p[9]*p[13]*p[27] + p[10]*p[11]*p[21] - p[10]*p[11]*p[30] - p[10]*p[12]*p[23] + p[10]*p[12]*p[32] + p[10]*p[14]*p[18] - p[10]*p[14]*p[27];
+ coeff[36] = 2*p[0]*p[9]*p[9]*p[15] + 2*p[0]*p[10]*p[10]*p[15] - 2*p[0]*p[13]*p[13]*p[15] - 2*p[0]*p[14]*p[14]*p[15] - 2*p[7]*p[11]*p[15] + p[7]*p[11]*p[24] - 2*p[8]*p[12]*p[15] + p[8]*p[12]*p[24] + 2*p[9]*p[13]*p[15] - p[9]*p[13]*p[24] + 2*p[10]*p[14]*p[15] - p[10]*p[14]*p[24];
+ coeff[37] = 2*p[0]*p[7]*p[10]*p[19] - 2*p[0]*p[8]*p[9]*p[19] + 2*p[0]*p[9]*p[9]*p[16] + 2*p[0]*p[10]*p[10]*p[16] - 2*p[0]*p[11]*p[14]*p[19] + 2*p[0]*p[12]*p[13]*p[19] - 2*p[0]*p[13]*p[13]*p[16] - 2*p[0]*p[14]*p[14]*p[16] - 2*p[7]*p[11]*p[16] + p[7]*p[11]*p[25] + 2*p[7]*p[14]*p[19] - p[7]*p[14]*p[28] - 2*p[8]*p[12]*p[16] + p[8]*p[12]*p[25] - 2*p[8]*p[13]*p[19] + p[8]*p[13]*p[28] - 2*p[9]*p[12]*p[19] + p[9]*p[12]*p[28] + 2*p[9]*p[13]*p[16] - p[9]*p[13]*p[25] + 2*p[10]*p[11]*p[19] - p[10]*p[11]*p[28] + 2*p[10]*p[14]*p[16] - p[10]*p[14]*p[25];
+ coeff[38] = -2*p[0]*p[7]*p[9]*p[22] + 2*p[0]*p[7]*p[10]*p[20] - 2*p[0]*p[8]*p[9]*p[20] - 2*p[0]*p[8]*p[10]*p[22] + 2*p[0]*p[9]*p[9]*p[17] + 2*p[0]*p[10]*p[10]*p[17] + 2*p[0]*p[11]*p[13]*p[22] - 2*p[0]*p[11]*p[14]*p[20] + 2*p[0]*p[12]*p[13]*p[20] + 2*p[0]*p[12]*p[14]*p[22] - 2*p[0]*p[13]*p[13]*p[17] - 2*p[0]*p[14]*p[14]*p[17] - 2*p[7]*p[11]*p[17] + p[7]*p[11]*p[26] - 2*p[7]*p[13]*p[22] + p[7]*p[13]*p[31] + 2*p[7]*p[14]*p[20] - p[7]*p[14]*p[29] - 2*p[8]*p[12]*p[17] + p[8]*p[12]*p[26] - 2*p[8]*p[13]*p[20] + p[8]*p[13]*p[29] - 2*p[8]*p[14]*p[22] + p[8]*p[14]*p[31] - 2*p[9]*p[11]*p[22] + p[9]*p[11]*p[31] - 2*p[9]*p[12]*p[20] + p[9]*p[12]*p[29] + 2*p[9]*p[13]*p[17] - p[9]*p[13]*p[26] + 2*p[10]*p[11]*p[20] - p[10]*p[11]*p[29] - 2*p[10]*p[12]*p[22] + p[10]*p[12]*p[31] + 2*p[10]*p[14]*p[17] - p[10]*p[14]*p[26];
+ coeff[39] = (p[7]*p[11] + p[8]*p[12] - p[9]*p[13] - p[10]*p[14])*p[15];
+ coeff[40] = p[7]*p[11]*p[16] - p[7]*p[14]*p[19] + p[8]*p[12]*p[16] + p[8]*p[13]*p[19] + p[9]*p[12]*p[19] - p[9]*p[13]*p[16] - p[10]*p[11]*p[19] - p[10]*p[14]*p[16];
+ coeff[41] = p[7]*p[11]*p[17] + p[7]*p[13]*p[22] - p[7]*p[14]*p[20] + p[8]*p[12]*p[17] + p[8]*p[13]*p[20] + p[8]*p[14]*p[22] + p[9]*p[11]*p[22] + p[9]*p[12]*p[20] - p[9]*p[13]*p[17] - p[10]*p[11]*p[20] + p[10]*p[12]*p[22] - p[10]*p[14]*p[17];
+ coeff[42] = 2*(p[7]*p[9]*p[23] - p[7]*p[9]*p[32] - p[7]*p[10]*p[21] + p[7]*p[10]*p[30] + p[8]*p[9]*p[21] - p[8]*p[9]*p[30] + p[8]*p[10]*p[23] - p[8]*p[10]*p[32] - p[9]*p[9]*p[18] + p[9]*p[9]*p[27] - p[10]*p[10]*p[18] + p[10]*p[10]*p[27] - p[11]*p[13]*p[23] + p[11]*p[13]*p[32] + p[11]*p[14]*p[21] - p[11]*p[14]*p[30] - p[12]*p[13]*p[21] + p[12]*p[13]*p[30] - p[12]*p[14]*p[23] + p[12]*p[14]*p[32] + p[13]*p[13]*p[18] - p[13]*p[13]*p[27] + p[14]*p[14]*p[18] - p[14]*p[14]*p[27])*p[0];
+ coeff[43] = -4*p[0]*p[9]*p[9]*p[15] + 2*p[0]*p[9]*p[9]*p[24] - 4*p[0]*p[10]*p[10]*p[15] + 2*p[0]*p[10]*p[10]*p[24] + 4*p[0]*p[13]*p[13]*p[15] - 2*p[0]*p[13]*p[13]*p[24] + 4*p[0]*p[14]*p[14]*p[15] - 2*p[0]*p[14]*p[14]*p[24] + 2*p[7]*p[11]*p[15] - 2*p[7]*p[11]*p[24] + 2*p[8]*p[12]*p[15] - 2*p[8]*p[12]*p[24] - 2*p[9]*p[13]*p[15] + 2*p[9]*p[13]*p[24] - 2*p[10]*p[14]*p[15] + 2*p[10]*p[14]*p[24];
+ coeff[44] = -4*p[0]*p[7]*p[10]*p[19] + 2*p[0]*p[7]*p[10]*p[28] + 4*p[0]*p[8]*p[9]*p[19] - 2*p[0]*p[8]*p[9]*p[28] - 4*p[0]*p[9]*p[9]*p[16] + 2*p[0]*p[9]*p[9]*p[25] - 4*p[0]*p[10]*p[10]*p[16] + 2*p[0]*p[10]*p[10]*p[25] + 4*p[0]*p[11]*p[14]*p[19] - 2*p[0]*p[11]*p[14]*p[28] - 4*p[0]*p[12]*p[13]*p[19] + 2*p[0]*p[12]*p[13]*p[28] + 4*p[0]*p[13]*p[13]*p[16] - 2*p[0]*p[13]*p[13]*p[25] + 4*p[0]*p[14]*p[14]*p[16] - 2*p[0]*p[14]*p[14]*p[25] + 2*p[7]*p[11]*p[16] - 2*p[7]*p[11]*p[25] - 2*p[7]*p[14]*p[19] + 2*p[7]*p[14]*p[28] + 2*p[8]*p[12]*p[16] - 2*p[8]*p[12]*p[25] + 2*p[8]*p[13]*p[19] - 2*p[8]*p[13]*p[28] + 2*p[9]*p[12]*p[19] - 2*p[9]*p[12]*p[28] - 2*p[9]*p[13]*p[16] + 2*p[9]*p[13]*p[25] - 2*p[10]*p[11]*p[19] + 2*p[10]*p[11]*p[28] - 2*p[10]*p[14]*p[16] + 2*p[10]*p[14]*p[25];
+ coeff[45] = 4*p[0]*p[7]*p[9]*p[22] - 2*p[0]*p[7]*p[9]*p[31] - 4*p[0]*p[7]*p[10]*p[20] + 2*p[0]*p[7]*p[10]*p[29] + 4*p[0]*p[8]*p[9]*p[20] - 2*p[0]*p[8]*p[9]*p[29] + 4*p[0]*p[8]*p[10]*p[22] - 2*p[0]*p[8]*p[10]*p[31] - 4*p[0]*p[9]*p[9]*p[17] + 2*p[0]*p[9]*p[9]*p[26] - 4*p[0]*p[10]*p[10]*p[17] + 2*p[0]*p[10]*p[10]*p[26] - 4*p[0]*p[11]*p[13]*p[22] + 2*p[0]*p[11]*p[13]*p[31] + 4*p[0]*p[11]*p[14]*p[20] - 2*p[0]*p[11]*p[14]*p[29] - 4*p[0]*p[12]*p[13]*p[20] + 2*p[0]*p[12]*p[13]*p[29] - 4*p[0]*p[12]*p[14]*p[22] + 2*p[0]*p[12]*p[14]*p[31] + 4*p[0]*p[13]*p[13]*p[17] - 2*p[0]*p[13]*p[13]*p[26] + 4*p[0]*p[14]*p[14]*p[17] - 2*p[0]*p[14]*p[14]*p[26] + 2*p[7]*p[11]*p[17] - 2*p[7]*p[11]*p[26] + 2*p[7]*p[13]*p[22] - 2*p[7]*p[13]*p[31] - 2*p[7]*p[14]*p[20] + 2*p[7]*p[14]*p[29] + 2*p[8]*p[12]*p[17] - 2*p[8]*p[12]*p[26] + 2*p[8]*p[13]*p[20] - 2*p[8]*p[13]*p[29] + 2*p[8]*p[14]*p[22] - 2*p[8]*p[14]*p[31] + 2*p[9]*p[11]*p[22] - 2*p[9]*p[11]*p[31] + 2*p[9]*p[12]*p[20] - 2*p[9]*p[12]*p[29] - 2*p[9]*p[13]*p[17] + 2*p[9]*p[13]*p[26] - 2*p[10]*p[11]*p[20] + 2*p[10]*p[11]*p[29] + 2*p[10]*p[12]*p[22] - 2*p[10]*p[12]*p[31] - 2*p[10]*p[14]*p[17] + 2*p[10]*p[14]*p[26];
+ coeff[46] = 2*p[0]*p[9]*p[9]*p[15] + 2*p[0]*p[10]*p[10]*p[15] - 2*p[0]*p[13]*p[13]*p[15] - 2*p[0]*p[14]*p[14]*p[15] - 2*p[7]*p[11]*p[15] + 2*p[7]*p[11]*p[24] - 2*p[8]*p[12]*p[15] + 2*p[8]*p[12]*p[24] + 2*p[9]*p[13]*p[15] - 2*p[9]*p[13]*p[24] + 2*p[10]*p[14]*p[15] - 2*p[10]*p[14]*p[24];
+ coeff[47] = 2*p[0]*p[7]*p[10]*p[19] - 2*p[0]*p[8]*p[9]*p[19] + 2*p[0]*p[9]*p[9]*p[16] + 2*p[0]*p[10]*p[10]*p[16] - 2*p[0]*p[11]*p[14]*p[19] + 2*p[0]*p[12]*p[13]*p[19] - 2*p[0]*p[13]*p[13]*p[16] - 2*p[0]*p[14]*p[14]*p[16] - 2*p[7]*p[11]*p[16] + 2*p[7]*p[11]*p[25] + 2*p[7]*p[14]*p[19] - 2*p[7]*p[14]*p[28] - 2*p[8]*p[12]*p[16] + 2*p[8]*p[12]*p[25] - 2*p[8]*p[13]*p[19] + 2*p[8]*p[13]*p[28] - 2*p[9]*p[12]*p[19] + 2*p[9]*p[12]*p[28] + 2*p[9]*p[13]*p[16] - 2*p[9]*p[13]*p[25] + 2*p[10]*p[11]*p[19] - 2*p[10]*p[11]*p[28] + 2*p[10]*p[14]*p[16] - 2*p[10]*p[14]*p[25];
+ coeff[48] = -2*p[0]*p[7]*p[9]*p[22] + 2*p[0]*p[7]*p[10]*p[20] - 2*p[0]*p[8]*p[9]*p[20] - 2*p[0]*p[8]*p[10]*p[22] + 2*p[0]*p[9]*p[9]*p[17] + 2*p[0]*p[10]*p[10]*p[17] + 2*p[0]*p[11]*p[13]*p[22] - 2*p[0]*p[11]*p[14]*p[20] + 2*p[0]*p[12]*p[13]*p[20] + 2*p[0]*p[12]*p[14]*p[22] - 2*p[0]*p[13]*p[13]*p[17] - 2*p[0]*p[14]*p[14]*p[17] - 2*p[7]*p[11]*p[17] + 2*p[7]*p[11]*p[26] - 2*p[7]*p[13]*p[22] + 2*p[7]*p[13]*p[31] + 2*p[7]*p[14]*p[20] - 2*p[7]*p[14]*p[29] - 2*p[8]*p[12]*p[17] + 2*p[8]*p[12]*p[26] - 2*p[8]*p[13]*p[20] + 2*p[8]*p[13]*p[29] - 2*p[8]*p[14]*p[22] + 2*p[8]*p[14]*p[31] - 2*p[9]*p[11]*p[22] + 2*p[9]*p[11]*p[31] - 2*p[9]*p[12]*p[20] + 2*p[9]*p[12]*p[29] + 2*p[9]*p[13]*p[17] - 2*p[9]*p[13]*p[26] + 2*p[10]*p[11]*p[20] - 2*p[10]*p[11]*p[29] - 2*p[10]*p[12]*p[22] + 2*p[10]*p[12]*p[31] + 2*p[10]*p[14]*p[17] - 2*p[10]*p[14]*p[26];
+ coeff[49] = 0;
+ coeff[50] = 2*(p[9]*p[9]*p[15] - p[9]*p[9]*p[24] + p[10]*p[10]*p[15] - p[10]*p[10]*p[24] - p[13]*p[13]*p[15] + p[13]*p[13]*p[24] - p[14]*p[14]*p[15] + p[14]*p[14]*p[24])*p[0];
+ coeff[51] = 2*(p[7]*p[10]*p[19] - p[7]*p[10]*p[28] - p[8]*p[9]*p[19] + p[8]*p[9]*p[28] + p[9]*p[9]*p[16] - p[9]*p[9]*p[25] + p[10]*p[10]*p[16] - p[10]*p[10]*p[25] - p[11]*p[14]*p[19] + p[11]*p[14]*p[28] + p[12]*p[13]*p[19] - p[12]*p[13]*p[28] - p[13]*p[13]*p[16] + p[13]*p[13]*p[25] - p[14]*p[14]*p[16] + p[14]*p[14]*p[25])*p[0];
+ coeff[52] = 2*(-p[7]*p[9]*p[22] + p[7]*p[9]*p[31] + p[7]*p[10]*p[20] - p[7]*p[10]*p[29] - p[8]*p[9]*p[20] + p[8]*p[9]*p[29] - p[8]*p[10]*p[22] + p[8]*p[10]*p[31] + p[9]*p[9]*p[17] - p[9]*p[9]*p[26] + p[10]*p[10]*p[17] - p[10]*p[10]*p[26] + p[11]*p[13]*p[22] - p[11]*p[13]*p[31] - p[11]*p[14]*p[20] + p[11]*p[14]*p[29] + p[12]*p[13]*p[20] - p[12]*p[13]*p[29] + p[12]*p[14]*p[22] - p[12]*p[14]*p[31] - p[13]*p[13]*p[17] + p[13]*p[13]*p[26] - p[14]*p[14]*p[17] + p[14]*p[14]*p[26])*p[0];
+ coeff[53] = 2*(-p[9]*p[9]*p[15] + p[9]*p[9]*p[24] - p[10]*p[10]*p[15] + p[10]*p[10]*p[24] + p[13]*p[13]*p[15] - p[13]*p[13]*p[24] + p[14]*p[14]*p[15] - p[14]*p[14]*p[24])*p[0];
+ coeff[54] = 2*(-p[7]*p[10]*p[19] + p[7]*p[10]*p[28] + p[8]*p[9]*p[19] - p[8]*p[9]*p[28] - p[9]*p[9]*p[16] + p[9]*p[9]*p[25] - p[10]*p[10]*p[16] + p[10]*p[10]*p[25] + p[11]*p[14]*p[19] - p[11]*p[14]*p[28] - p[12]*p[13]*p[19] + p[12]*p[13]*p[28] + p[13]*p[13]*p[16] - p[13]*p[13]*p[25] + p[14]*p[14]*p[16] - p[14]*p[14]*p[25])*p[0];
+ coeff[55] = 2*(p[7]*p[9]*p[22] - p[7]*p[9]*p[31] - p[7]*p[10]*p[20] + p[7]*p[10]*p[29] + p[8]*p[9]*p[20] - p[8]*p[9]*p[29] + p[8]*p[10]*p[22] - p[8]*p[10]*p[31] - p[9]*p[9]*p[17] + p[9]*p[9]*p[26] - p[10]*p[10]*p[17] + p[10]*p[10]*p[26] - p[11]*p[13]*p[22] + p[11]*p[13]*p[31] + p[11]*p[14]*p[20] - p[11]*p[14]*p[29] - p[12]*p[13]*p[20] + p[12]*p[13]*p[29] - p[12]*p[14]*p[22] + p[12]*p[14]*p[31] + p[13]*p[13]*p[17] - p[13]*p[13]*p[26] + p[14]*p[14]*p[17] - p[14]*p[14]*p[26])*p[0];
+ coeff[56] = -p[2] + p[5] + p[7]*p[8]*p[23] - p[7]*p[8]*p[32] - p[7]*p[10]*p[18] + p[7]*p[10]*p[27] + p[8]*p[8]*p[21] - p[8]*p[8]*p[30] - p[8]*p[9]*p[18] + p[8]*p[9]*p[27] - p[9]*p[10]*p[23] + p[9]*p[10]*p[32] + p[10]*p[10]*p[21] - p[10]*p[10]*p[30] + p[11]*p[12]*p[23] - p[11]*p[12]*p[32] - p[11]*p[14]*p[18] + p[11]*p[14]*p[27] + p[12]*p[12]*p[21] - p[12]*p[12]*p[30] - p[12]*p[13]*p[18] + p[12]*p[13]*p[27] - p[13]*p[14]*p[23] + p[13]*p[14]*p[32] + p[14]*p[14]*p[21] - p[14]*p[14]*p[30] - p[21] + p[30];
+ coeff[57] = -2*p[7]*p[10]*p[15] + p[7]*p[10]*p[24] - 2*p[8]*p[9]*p[15] + p[8]*p[9]*p[24] - 2*p[11]*p[14]*p[15] + p[11]*p[14]*p[24] - 2*p[12]*p[13]*p[15] + p[12]*p[13]*p[24];
+ coeff[58] = -2*p[7]*p[10]*p[16] + p[7]*p[10]*p[25] + 2*p[8]*p[8]*p[19] - p[8]*p[8]*p[28] - 2*p[8]*p[9]*p[16] + p[8]*p[9]*p[25] + 2*p[10]*p[10]*p[19] - p[10]*p[10]*p[28] - 2*p[11]*p[14]*p[16] + p[11]*p[14]*p[25] + 2*p[12]*p[12]*p[19] - p[12]*p[12]*p[28] - 2*p[12]*p[13]*p[16] + p[12]*p[13]*p[25] + 2*p[14]*p[14]*p[19] - p[14]*p[14]*p[28] - 2*p[19] + p[28];
+ coeff[59] = 2*p[7]*p[8]*p[22] - p[7]*p[8]*p[31] - 2*p[7]*p[10]*p[17] + p[7]*p[10]*p[26] + 2*p[8]*p[8]*p[20] - p[8]*p[8]*p[29] - 2*p[8]*p[9]*p[17] + p[8]*p[9]*p[26] - 2*p[9]*p[10]*p[22] + p[9]*p[10]*p[31] + 2*p[10]*p[10]*p[20] - p[10]*p[10]*p[29] + 2*p[11]*p[12]*p[22] - p[11]*p[12]*p[31] - 2*p[11]*p[14]*p[17] + p[11]*p[14]*p[26] + 2*p[12]*p[12]*p[20] - p[12]*p[12]*p[29] - 2*p[12]*p[13]*p[17] + p[12]*p[13]*p[26] - 2*p[13]*p[14]*p[22] + p[13]*p[14]*p[31] + 2*p[14]*p[14]*p[20] - p[14]*p[14]*p[29] - 2*p[20] + p[29];
+ coeff[60] = (p[7]*p[10] + p[8]*p[9] + p[11]*p[14] + p[12]*p[13])*p[15];
+ coeff[61] = p[7]*p[10]*p[16] - p[8]*p[8]*p[19] + p[8]*p[9]*p[16] - p[10]*p[10]*p[19] + p[11]*p[14]*p[16] - p[12]*p[12]*p[19] + p[12]*p[13]*p[16] - p[14]*p[14]*p[19] + p[19];
+ coeff[62] = -p[7]*p[8]*p[22] + p[7]*p[10]*p[17] - p[8]*p[8]*p[20] + p[8]*p[9]*p[17] + p[9]*p[10]*p[22] - p[10]*p[10]*p[20] - p[11]*p[12]*p[22] + p[11]*p[14]*p[17] - p[12]*p[12]*p[20] + p[12]*p[13]*p[17] + p[13]*p[14]*p[22] - p[14]*p[14]*p[20] + p[20];
+ coeff[63] = 0;
+ coeff[64] = 2*p[7]*p[10]*p[15] - 2*p[7]*p[10]*p[24] + 2*p[8]*p[9]*p[15] - 2*p[8]*p[9]*p[24] + 2*p[11]*p[14]*p[15] - 2*p[11]*p[14]*p[24] + 2*p[12]*p[13]*p[15] - 2*p[12]*p[13]*p[24];
+ coeff[65] = 2*p[7]*p[10]*p[16] - 2*p[7]*p[10]*p[25] - 2*p[8]*p[8]*p[19] + 2*p[8]*p[8]*p[28] + 2*p[8]*p[9]*p[16] - 2*p[8]*p[9]*p[25] - 2*p[10]*p[10]*p[19] + 2*p[10]*p[10]*p[28] + 2*p[11]*p[14]*p[16] - 2*p[11]*p[14]*p[25] - 2*p[12]*p[12]*p[19] + 2*p[12]*p[12]*p[28] + 2*p[12]*p[13]*p[16] - 2*p[12]*p[13]*p[25] - 2*p[14]*p[14]*p[19] + 2*p[14]*p[14]*p[28] + 2*p[19] - 2*p[28];
+ coeff[66] = -2*p[7]*p[8]*p[22] + 2*p[7]*p[8]*p[31] + 2*p[7]*p[10]*p[17] - 2*p[7]*p[10]*p[26] - 2*p[8]*p[8]*p[20] + 2*p[8]*p[8]*p[29] + 2*p[8]*p[9]*p[17] - 2*p[8]*p[9]*p[26] + 2*p[9]*p[10]*p[22] - 2*p[9]*p[10]*p[31] - 2*p[10]*p[10]*p[20] + 2*p[10]*p[10]*p[29] - 2*p[11]*p[12]*p[22] + 2*p[11]*p[12]*p[31] + 2*p[11]*p[14]*p[17] - 2*p[11]*p[14]*p[26] - 2*p[12]*p[12]*p[20] + 2*p[12]*p[12]*p[29] + 2*p[12]*p[13]*p[17] - 2*p[12]*p[13]*p[26] + 2*p[13]*p[14]*p[22] - 2*p[13]*p[14]*p[31] - 2*p[14]*p[14]*p[20] + 2*p[14]*p[14]*p[29] + 2*p[20] - 2*p[29];
+ coeff[67] = -2*p[7]*p[10]*p[15] + 2*p[7]*p[10]*p[24] - 2*p[8]*p[9]*p[15] + 2*p[8]*p[9]*p[24] - 2*p[11]*p[14]*p[15] + 2*p[11]*p[14]*p[24] - 2*p[12]*p[13]*p[15] + 2*p[12]*p[13]*p[24];
+ coeff[68] = -2*p[7]*p[10]*p[16] + 2*p[7]*p[10]*p[25] + 2*p[8]*p[8]*p[19] - 2*p[8]*p[8]*p[28] - 2*p[8]*p[9]*p[16] + 2*p[8]*p[9]*p[25] + 2*p[10]*p[10]*p[19] - 2*p[10]*p[10]*p[28] - 2*p[11]*p[14]*p[16] + 2*p[11]*p[14]*p[25] + 2*p[12]*p[12]*p[19] - 2*p[12]*p[12]*p[28] - 2*p[12]*p[13]*p[16] + 2*p[12]*p[13]*p[25] + 2*p[14]*p[14]*p[19] - 2*p[14]*p[14]*p[28] - 2*p[19] + 2*p[28];
+ coeff[69] = 2*p[7]*p[8]*p[22] - 2*p[7]*p[8]*p[31] - 2*p[7]*p[10]*p[17] + 2*p[7]*p[10]*p[26] + 2*p[8]*p[8]*p[20] - 2*p[8]*p[8]*p[29] - 2*p[8]*p[9]*p[17] + 2*p[8]*p[9]*p[26] - 2*p[9]*p[10]*p[22] + 2*p[9]*p[10]*p[31] + 2*p[10]*p[10]*p[20] - 2*p[10]*p[10]*p[29] + 2*p[11]*p[12]*p[22] - 2*p[11]*p[12]*p[31] - 2*p[11]*p[14]*p[17] + 2*p[11]*p[14]*p[26] + 2*p[12]*p[12]*p[20] - 2*p[12]*p[12]*p[29] - 2*p[12]*p[13]*p[17] + 2*p[12]*p[13]*p[26] - 2*p[13]*p[14]*p[22] + 2*p[13]*p[14]*p[31] + 2*p[14]*p[14]*p[20] - 2*p[14]*p[14]*p[29] - 2*p[20] + 2*p[29];
+ coeff[70] = 2*p[0]*p[7]*p[11]*p[21] - 2*p[0]*p[7]*p[12]*p[23] + 2*p[0]*p[7]*p[14]*p[18] - 2*p[0]*p[8]*p[11]*p[23] - 2*p[0]*p[8]*p[12]*p[21] + 2*p[0]*p[8]*p[13]*p[18] + 2*p[0]*p[9]*p[12]*p[18] + 2*p[0]*p[9]*p[13]*p[21] + 2*p[0]*p[9]*p[14]*p[23] + 2*p[0]*p[10]*p[11]*p[18] + 2*p[0]*p[10]*p[13]*p[23] - 2*p[0]*p[10]*p[14]*p[21] + p[7]*p[8]*p[23] - p[7]*p[8]*p[32] - p[7]*p[10]*p[18] + p[7]*p[10]*p[27] + p[8]*p[8]*p[21] - p[8]*p[8]*p[30] - p[8]*p[9]*p[18] + p[8]*p[9]*p[27] - p[9]*p[10]*p[23] + p[9]*p[10]*p[32] + p[10]*p[10]*p[21] - p[10]*p[10]*p[30] - p[11]*p[12]*p[23] + p[11]*p[12]*p[32] + p[11]*p[14]*p[18] - p[11]*p[14]*p[27] - p[12]*p[12]*p[21] + p[12]*p[12]*p[30] + p[12]*p[13]*p[18] - p[12]*p[13]*p[27] + p[13]*p[14]*p[23] - p[13]*p[14]*p[32] - p[14]*p[14]*p[21] + p[14]*p[14]*p[30];
+ coeff[71] = 2*p[0]*p[7]*p[14]*p[15] + 2*p[0]*p[8]*p[13]*p[15] + 2*p[0]*p[9]*p[12]*p[15] + 2*p[0]*p[10]*p[11]*p[15] - 2*p[7]*p[10]*p[15] + p[7]*p[10]*p[24] - 2*p[8]*p[9]*p[15] + p[8]*p[9]*p[24] + 2*p[11]*p[14]*p[15] - p[11]*p[14]*p[24] + 2*p[12]*p[13]*p[15] - p[12]*p[13]*p[24];
+ coeff[72] = 2*p[0]*p[7]*p[11]*p[19] + 2*p[0]*p[7]*p[14]*p[16] - 2*p[0]*p[8]*p[12]*p[19] + 2*p[0]*p[8]*p[13]*p[16] + 2*p[0]*p[9]*p[12]*p[16] + 2*p[0]*p[9]*p[13]*p[19] + 2*p[0]*p[10]*p[11]*p[16] - 2*p[0]*p[10]*p[14]*p[19] - 2*p[7]*p[10]*p[16] + p[7]*p[10]*p[25] + 2*p[8]*p[8]*p[19] - p[8]*p[8]*p[28] - 2*p[8]*p[9]*p[16] + p[8]*p[9]*p[25] + 2*p[10]*p[10]*p[19] - p[10]*p[10]*p[28] + 2*p[11]*p[14]*p[16] - p[11]*p[14]*p[25] - 2*p[12]*p[12]*p[19] + p[12]*p[12]*p[28] + 2*p[12]*p[13]*p[16] - p[12]*p[13]*p[25] - 2*p[14]*p[14]*p[19] + p[14]*p[14]*p[28];
+ coeff[73] = 2*p[0]*p[7]*p[11]*p[20] - 2*p[0]*p[7]*p[12]*p[22] + 2*p[0]*p[7]*p[14]*p[17] - 2*p[0]*p[8]*p[11]*p[22] - 2*p[0]*p[8]*p[12]*p[20] + 2*p[0]*p[8]*p[13]*p[17] + 2*p[0]*p[9]*p[12]*p[17] + 2*p[0]*p[9]*p[13]*p[20] + 2*p[0]*p[9]*p[14]*p[22] + 2*p[0]*p[10]*p[11]*p[17] + 2*p[0]*p[10]*p[13]*p[22] - 2*p[0]*p[10]*p[14]*p[20] + 2*p[7]*p[8]*p[22] - p[7]*p[8]*p[31] - 2*p[7]*p[10]*p[17] + p[7]*p[10]*p[26] + 2*p[8]*p[8]*p[20] - p[8]*p[8]*p[29] - 2*p[8]*p[9]*p[17] + p[8]*p[9]*p[26] - 2*p[9]*p[10]*p[22] + p[9]*p[10]*p[31] + 2*p[10]*p[10]*p[20] - p[10]*p[10]*p[29] - 2*p[11]*p[12]*p[22] + p[11]*p[12]*p[31] + 2*p[11]*p[14]*p[17] - p[11]*p[14]*p[26] - 2*p[12]*p[12]*p[20] + p[12]*p[12]*p[29] + 2*p[12]*p[13]*p[17] - p[12]*p[13]*p[26] + 2*p[13]*p[14]*p[22] - p[13]*p[14]*p[31] - 2*p[14]*p[14]*p[20] + p[14]*p[14]*p[29];
+ coeff[74] = (p[7]*p[10] + p[8]*p[9] - p[11]*p[14] - p[12]*p[13])*p[15];
+ coeff[75] = p[7]*p[10]*p[16] - p[8]*p[8]*p[19] + p[8]*p[9]*p[16] - p[10]*p[10]*p[19] - p[11]*p[14]*p[16] + p[12]*p[12]*p[19] - p[12]*p[13]*p[16] + p[14]*p[14]*p[19];
+ coeff[76] = -p[7]*p[8]*p[22] + p[7]*p[10]*p[17] - p[8]*p[8]*p[20] + p[8]*p[9]*p[17] + p[9]*p[10]*p[22] - p[10]*p[10]*p[20] + p[11]*p[12]*p[22] - p[11]*p[14]*p[17] + p[12]*p[12]*p[20] - p[12]*p[13]*p[17] - p[13]*p[14]*p[22] + p[14]*p[14]*p[20];
+ coeff[77] = 2*(-p[7]*p[11]*p[21] + p[7]*p[11]*p[30] + p[7]*p[12]*p[23] - p[7]*p[12]*p[32] - p[7]*p[14]*p[18] + p[7]*p[14]*p[27] + p[8]*p[11]*p[23] - p[8]*p[11]*p[32] + p[8]*p[12]*p[21] - p[8]*p[12]*p[30] - p[8]*p[13]*p[18] + p[8]*p[13]*p[27] - p[9]*p[12]*p[18] + p[9]*p[12]*p[27] - p[9]*p[13]*p[21] + p[9]*p[13]*p[30] - p[9]*p[14]*p[23] + p[9]*p[14]*p[32] - p[10]*p[11]*p[18] + p[10]*p[11]*p[27] - p[10]*p[13]*p[23] + p[10]*p[13]*p[32] + p[10]*p[14]*p[21] - p[10]*p[14]*p[30])*p[0];
+ coeff[78] = -4*p[0]*p[7]*p[14]*p[15] + 2*p[0]*p[7]*p[14]*p[24] - 4*p[0]*p[8]*p[13]*p[15] + 2*p[0]*p[8]*p[13]*p[24] - 4*p[0]*p[9]*p[12]*p[15] + 2*p[0]*p[9]*p[12]*p[24] - 4*p[0]*p[10]*p[11]*p[15] + 2*p[0]*p[10]*p[11]*p[24] + 2*p[7]*p[10]*p[15] - 2*p[7]*p[10]*p[24] + 2*p[8]*p[9]*p[15] - 2*p[8]*p[9]*p[24] - 2*p[11]*p[14]*p[15] + 2*p[11]*p[14]*p[24] - 2*p[12]*p[13]*p[15] + 2*p[12]*p[13]*p[24];
+ coeff[79] = -4*p[0]*p[7]*p[11]*p[19] + 2*p[0]*p[7]*p[11]*p[28] - 4*p[0]*p[7]*p[14]*p[16] + 2*p[0]*p[7]*p[14]*p[25] + 4*p[0]*p[8]*p[12]*p[19] - 2*p[0]*p[8]*p[12]*p[28] - 4*p[0]*p[8]*p[13]*p[16] + 2*p[0]*p[8]*p[13]*p[25] - 4*p[0]*p[9]*p[12]*p[16] + 2*p[0]*p[9]*p[12]*p[25] - 4*p[0]*p[9]*p[13]*p[19] + 2*p[0]*p[9]*p[13]*p[28] - 4*p[0]*p[10]*p[11]*p[16] + 2*p[0]*p[10]*p[11]*p[25] + 4*p[0]*p[10]*p[14]*p[19] - 2*p[0]*p[10]*p[14]*p[28] + 2*p[7]*p[10]*p[16] - 2*p[7]*p[10]*p[25] - 2*p[8]*p[8]*p[19] + 2*p[8]*p[8]*p[28] + 2*p[8]*p[9]*p[16] - 2*p[8]*p[9]*p[25] - 2*p[10]*p[10]*p[19] + 2*p[10]*p[10]*p[28] - 2*p[11]*p[14]*p[16] + 2*p[11]*p[14]*p[25] + 2*p[12]*p[12]*p[19] - 2*p[12]*p[12]*p[28] - 2*p[12]*p[13]*p[16] + 2*p[12]*p[13]*p[25] + 2*p[14]*p[14]*p[19] - 2*p[14]*p[14]*p[28];
+ coeff[80] = -4*p[0]*p[7]*p[11]*p[20] + 2*p[0]*p[7]*p[11]*p[29] + 4*p[0]*p[7]*p[12]*p[22] - 2*p[0]*p[7]*p[12]*p[31] - 4*p[0]*p[7]*p[14]*p[17] + 2*p[0]*p[7]*p[14]*p[26] + 4*p[0]*p[8]*p[11]*p[22] - 2*p[0]*p[8]*p[11]*p[31] + 4*p[0]*p[8]*p[12]*p[20] - 2*p[0]*p[8]*p[12]*p[29] - 4*p[0]*p[8]*p[13]*p[17] + 2*p[0]*p[8]*p[13]*p[26] - 4*p[0]*p[9]*p[12]*p[17] + 2*p[0]*p[9]*p[12]*p[26] - 4*p[0]*p[9]*p[13]*p[20] + 2*p[0]*p[9]*p[13]*p[29] - 4*p[0]*p[9]*p[14]*p[22] + 2*p[0]*p[9]*p[14]*p[31] - 4*p[0]*p[10]*p[11]*p[17] + 2*p[0]*p[10]*p[11]*p[26] - 4*p[0]*p[10]*p[13]*p[22] + 2*p[0]*p[10]*p[13]*p[31] + 4*p[0]*p[10]*p[14]*p[20] - 2*p[0]*p[10]*p[14]*p[29] - 2*p[7]*p[8]*p[22] + 2*p[7]*p[8]*p[31] + 2*p[7]*p[10]*p[17] - 2*p[7]*p[10]*p[26] - 2*p[8]*p[8]*p[20] + 2*p[8]*p[8]*p[29] + 2*p[8]*p[9]*p[17] - 2*p[8]*p[9]*p[26] + 2*p[9]*p[10]*p[22] - 2*p[9]*p[10]*p[31] - 2*p[10]*p[10]*p[20] + 2*p[10]*p[10]*p[29] + 2*p[11]*p[12]*p[22] - 2*p[11]*p[12]*p[31] - 2*p[11]*p[14]*p[17] + 2*p[11]*p[14]*p[26] + 2*p[12]*p[12]*p[20] - 2*p[12]*p[12]*p[29] - 2*p[12]*p[13]*p[17] + 2*p[12]*p[13]*p[26] - 2*p[13]*p[14]*p[22] + 2*p[13]*p[14]*p[31] + 2*p[14]*p[14]*p[20] - 2*p[14]*p[14]*p[29];
+ coeff[81] = 2*p[0]*p[7]*p[14]*p[15] + 2*p[0]*p[8]*p[13]*p[15] + 2*p[0]*p[9]*p[12]*p[15] + 2*p[0]*p[10]*p[11]*p[15] - 2*p[7]*p[10]*p[15] + 2*p[7]*p[10]*p[24] - 2*p[8]*p[9]*p[15] + 2*p[8]*p[9]*p[24] + 2*p[11]*p[14]*p[15] - 2*p[11]*p[14]*p[24] + 2*p[12]*p[13]*p[15] - 2*p[12]*p[13]*p[24];
+ coeff[82] = 2*p[0]*p[7]*p[11]*p[19] + 2*p[0]*p[7]*p[14]*p[16] - 2*p[0]*p[8]*p[12]*p[19] + 2*p[0]*p[8]*p[13]*p[16] + 2*p[0]*p[9]*p[12]*p[16] + 2*p[0]*p[9]*p[13]*p[19] + 2*p[0]*p[10]*p[11]*p[16] - 2*p[0]*p[10]*p[14]*p[19] - 2*p[7]*p[10]*p[16] + 2*p[7]*p[10]*p[25] + 2*p[8]*p[8]*p[19] - 2*p[8]*p[8]*p[28] - 2*p[8]*p[9]*p[16] + 2*p[8]*p[9]*p[25] + 2*p[10]*p[10]*p[19] - 2*p[10]*p[10]*p[28] + 2*p[11]*p[14]*p[16] - 2*p[11]*p[14]*p[25] - 2*p[12]*p[12]*p[19] + 2*p[12]*p[12]*p[28] + 2*p[12]*p[13]*p[16] - 2*p[12]*p[13]*p[25] - 2*p[14]*p[14]*p[19] + 2*p[14]*p[14]*p[28];
+ coeff[83] = 2*p[0]*p[7]*p[11]*p[20] - 2*p[0]*p[7]*p[12]*p[22] + 2*p[0]*p[7]*p[14]*p[17] - 2*p[0]*p[8]*p[11]*p[22] - 2*p[0]*p[8]*p[12]*p[20] + 2*p[0]*p[8]*p[13]*p[17] + 2*p[0]*p[9]*p[12]*p[17] + 2*p[0]*p[9]*p[13]*p[20] + 2*p[0]*p[9]*p[14]*p[22] + 2*p[0]*p[10]*p[11]*p[17] + 2*p[0]*p[10]*p[13]*p[22] - 2*p[0]*p[10]*p[14]*p[20] + 2*p[7]*p[8]*p[22] - 2*p[7]*p[8]*p[31] - 2*p[7]*p[10]*p[17] + 2*p[7]*p[10]*p[26] + 2*p[8]*p[8]*p[20] - 2*p[8]*p[8]*p[29] - 2*p[8]*p[9]*p[17] + 2*p[8]*p[9]*p[26] - 2*p[9]*p[10]*p[22] + 2*p[9]*p[10]*p[31] + 2*p[10]*p[10]*p[20] - 2*p[10]*p[10]*p[29] - 2*p[11]*p[12]*p[22] + 2*p[11]*p[12]*p[31] + 2*p[11]*p[14]*p[17] - 2*p[11]*p[14]*p[26] - 2*p[12]*p[12]*p[20] + 2*p[12]*p[12]*p[29] + 2*p[12]*p[13]*p[17] - 2*p[12]*p[13]*p[26] + 2*p[13]*p[14]*p[22] - 2*p[13]*p[14]*p[31] - 2*p[14]*p[14]*p[20] + 2*p[14]*p[14]*p[29];
+ coeff[84] = 0;
+ coeff[85] = 2*(p[7]*p[14]*p[15] - p[7]*p[14]*p[24] + p[8]*p[13]*p[15] - p[8]*p[13]*p[24] + p[9]*p[12]*p[15] - p[9]*p[12]*p[24] + p[10]*p[11]*p[15] - p[10]*p[11]*p[24])*p[0];
+ coeff[86] = 2*(p[7]*p[11]*p[19] - p[7]*p[11]*p[28] + p[7]*p[14]*p[16] - p[7]*p[14]*p[25] - p[8]*p[12]*p[19] + p[8]*p[12]*p[28] + p[8]*p[13]*p[16] - p[8]*p[13]*p[25] + p[9]*p[12]*p[16] - p[9]*p[12]*p[25] + p[9]*p[13]*p[19] - p[9]*p[13]*p[28] + p[10]*p[11]*p[16] - p[10]*p[11]*p[25] - p[10]*p[14]*p[19] + p[10]*p[14]*p[28])*p[0];
+ coeff[87] = 2*(p[7]*p[11]*p[20] - p[7]*p[11]*p[29] - p[7]*p[12]*p[22] + p[7]*p[12]*p[31] + p[7]*p[14]*p[17] - p[7]*p[14]*p[26] - p[8]*p[11]*p[22] + p[8]*p[11]*p[31] - p[8]*p[12]*p[20] + p[8]*p[12]*p[29] + p[8]*p[13]*p[17] - p[8]*p[13]*p[26] + p[9]*p[12]*p[17] - p[9]*p[12]*p[26] + p[9]*p[13]*p[20] - p[9]*p[13]*p[29] + p[9]*p[14]*p[22] - p[9]*p[14]*p[31] + p[10]*p[11]*p[17] - p[10]*p[11]*p[26] + p[10]*p[13]*p[22] - p[10]*p[13]*p[31] - p[10]*p[14]*p[20] + p[10]*p[14]*p[29])*p[0];
+ coeff[88] = 2*(-p[7]*p[14]*p[15] + p[7]*p[14]*p[24] - p[8]*p[13]*p[15] + p[8]*p[13]*p[24] - p[9]*p[12]*p[15] + p[9]*p[12]*p[24] - p[10]*p[11]*p[15] + p[10]*p[11]*p[24])*p[0];
+ coeff[89] = 2*(-p[7]*p[11]*p[19] + p[7]*p[11]*p[28] - p[7]*p[14]*p[16] + p[7]*p[14]*p[25] + p[8]*p[12]*p[19] - p[8]*p[12]*p[28] - p[8]*p[13]*p[16] + p[8]*p[13]*p[25] - p[9]*p[12]*p[16] + p[9]*p[12]*p[25] - p[9]*p[13]*p[19] + p[9]*p[13]*p[28] - p[10]*p[11]*p[16] + p[10]*p[11]*p[25] + p[10]*p[14]*p[19] - p[10]*p[14]*p[28])*p[0];
+ coeff[90] = 2*(-p[7]*p[11]*p[20] + p[7]*p[11]*p[29] + p[7]*p[12]*p[22] - p[7]*p[12]*p[31] - p[7]*p[14]*p[17] + p[7]*p[14]*p[26] + p[8]*p[11]*p[22] - p[8]*p[11]*p[31] + p[8]*p[12]*p[20] - p[8]*p[12]*p[29] - p[8]*p[13]*p[17] + p[8]*p[13]*p[26] - p[9]*p[12]*p[17] + p[9]*p[12]*p[26] - p[9]*p[13]*p[20] + p[9]*p[13]*p[29] - p[9]*p[14]*p[22] + p[9]*p[14]*p[31] - p[10]*p[11]*p[17] + p[10]*p[11]*p[26] - p[10]*p[13]*p[22] + p[10]*p[13]*p[31] + p[10]*p[14]*p[20] - p[10]*p[14]*p[29])*p[0];
+ coeff[91] = 2*p[0]*p[7]*p[8]*p[23] - 2*p[0]*p[7]*p[10]*p[18] + 2*p[0]*p[8]*p[8]*p[21] - 2*p[0]*p[8]*p[9]*p[18] - 2*p[0]*p[9]*p[10]*p[23] + 2*p[0]*p[10]*p[10]*p[21] - 2*p[0]*p[11]*p[12]*p[23] + 2*p[0]*p[11]*p[14]*p[18] - 2*p[0]*p[12]*p[12]*p[21] + 2*p[0]*p[12]*p[13]*p[18] + 2*p[0]*p[13]*p[14]*p[23] - 2*p[0]*p[14]*p[14]*p[21] - p[7]*p[11]*p[21] + p[7]*p[11]*p[30] + p[7]*p[12]*p[23] - p[7]*p[12]*p[32] - p[7]*p[14]*p[18] + p[7]*p[14]*p[27] + p[8]*p[11]*p[23] - p[8]*p[11]*p[32] + p[8]*p[12]*p[21] - p[8]*p[12]*p[30] - p[8]*p[13]*p[18] + p[8]*p[13]*p[27] - p[9]*p[12]*p[18] + p[9]*p[12]*p[27] - p[9]*p[13]*p[21] + p[9]*p[13]*p[30] - p[9]*p[14]*p[23] + p[9]*p[14]*p[32] - p[10]*p[11]*p[18] + p[10]*p[11]*p[27] - p[10]*p[13]*p[23] + p[10]*p[13]*p[32] + p[10]*p[14]*p[21] - p[10]*p[14]*p[30];
+ coeff[92] = -2*p[0]*p[7]*p[10]*p[15] - 2*p[0]*p[8]*p[9]*p[15] + 2*p[0]*p[11]*p[14]*p[15] + 2*p[0]*p[12]*p[13]*p[15] - 2*p[7]*p[14]*p[15] + p[7]*p[14]*p[24] - 2*p[8]*p[13]*p[15] + p[8]*p[13]*p[24] - 2*p[9]*p[12]*p[15] + p[9]*p[12]*p[24] - 2*p[10]*p[11]*p[15] + p[10]*p[11]*p[24];
+ coeff[93] = -2*p[0]*p[7]*p[10]*p[16] + 2*p[0]*p[8]*p[8]*p[19] - 2*p[0]*p[8]*p[9]*p[16] + 2*p[0]*p[10]*p[10]*p[19] + 2*p[0]*p[11]*p[14]*p[16] - 2*p[0]*p[12]*p[12]*p[19] + 2*p[0]*p[12]*p[13]*p[16] - 2*p[0]*p[14]*p[14]*p[19] - 2*p[7]*p[11]*p[19] + p[7]*p[11]*p[28] - 2*p[7]*p[14]*p[16] + p[7]*p[14]*p[25] + 2*p[8]*p[12]*p[19] - p[8]*p[12]*p[28] - 2*p[8]*p[13]*p[16] + p[8]*p[13]*p[25] - 2*p[9]*p[12]*p[16] + p[9]*p[12]*p[25] - 2*p[9]*p[13]*p[19] + p[9]*p[13]*p[28] - 2*p[10]*p[11]*p[16] + p[10]*p[11]*p[25] + 2*p[10]*p[14]*p[19] - p[10]*p[14]*p[28];
+ coeff[94] = 2*p[0]*p[7]*p[8]*p[22] - 2*p[0]*p[7]*p[10]*p[17] + 2*p[0]*p[8]*p[8]*p[20] - 2*p[0]*p[8]*p[9]*p[17] - 2*p[0]*p[9]*p[10]*p[22] + 2*p[0]*p[10]*p[10]*p[20] - 2*p[0]*p[11]*p[12]*p[22] + 2*p[0]*p[11]*p[14]*p[17] - 2*p[0]*p[12]*p[12]*p[20] + 2*p[0]*p[12]*p[13]*p[17] + 2*p[0]*p[13]*p[14]*p[22] - 2*p[0]*p[14]*p[14]*p[20] - 2*p[7]*p[11]*p[20] + p[7]*p[11]*p[29] + 2*p[7]*p[12]*p[22] - p[7]*p[12]*p[31] - 2*p[7]*p[14]*p[17] + p[7]*p[14]*p[26] + 2*p[8]*p[11]*p[22] - p[8]*p[11]*p[31] + 2*p[8]*p[12]*p[20] - p[8]*p[12]*p[29] - 2*p[8]*p[13]*p[17] + p[8]*p[13]*p[26] - 2*p[9]*p[12]*p[17] + p[9]*p[12]*p[26] - 2*p[9]*p[13]*p[20] + p[9]*p[13]*p[29] - 2*p[9]*p[14]*p[22] + p[9]*p[14]*p[31] - 2*p[10]*p[11]*p[17] + p[10]*p[11]*p[26] - 2*p[10]*p[13]*p[22] + p[10]*p[13]*p[31] + 2*p[10]*p[14]*p[20] - p[10]*p[14]*p[29];
+ coeff[95] = (p[7]*p[14] + p[8]*p[13] + p[9]*p[12] + p[10]*p[11])*p[15];
+ coeff[96] = p[7]*p[11]*p[19] + p[7]*p[14]*p[16] - p[8]*p[12]*p[19] + p[8]*p[13]*p[16] + p[9]*p[12]*p[16] + p[9]*p[13]*p[19] + p[10]*p[11]*p[16] - p[10]*p[14]*p[19];
+ coeff[97] = p[7]*p[11]*p[20] - p[7]*p[12]*p[22] + p[7]*p[14]*p[17] - p[8]*p[11]*p[22] - p[8]*p[12]*p[20] + p[8]*p[13]*p[17] + p[9]*p[12]*p[17] + p[9]*p[13]*p[20] + p[9]*p[14]*p[22] + p[10]*p[11]*p[17] + p[10]*p[13]*p[22] - p[10]*p[14]*p[20];
+ coeff[98] = 2*(-p[7]*p[8]*p[23] + p[7]*p[8]*p[32] + p[7]*p[10]*p[18] - p[7]*p[10]*p[27] - p[8]*p[8]*p[21] + p[8]*p[8]*p[30] + p[8]*p[9]*p[18] - p[8]*p[9]*p[27] + p[9]*p[10]*p[23] - p[9]*p[10]*p[32] - p[10]*p[10]*p[21] + p[10]*p[10]*p[30] + p[11]*p[12]*p[23] - p[11]*p[12]*p[32] - p[11]*p[14]*p[18] + p[11]*p[14]*p[27] + p[12]*p[12]*p[21] - p[12]*p[12]*p[30] - p[12]*p[13]*p[18] + p[12]*p[13]*p[27] - p[13]*p[14]*p[23] + p[13]*p[14]*p[32] + p[14]*p[14]*p[21] - p[14]*p[14]*p[30])*p[0];
+ coeff[99] = 4*p[0]*p[7]*p[10]*p[15] - 2*p[0]*p[7]*p[10]*p[24] + 4*p[0]*p[8]*p[9]*p[15] - 2*p[0]*p[8]*p[9]*p[24] - 4*p[0]*p[11]*p[14]*p[15] + 2*p[0]*p[11]*p[14]*p[24] - 4*p[0]*p[12]*p[13]*p[15] + 2*p[0]*p[12]*p[13]*p[24] + 2*p[7]*p[14]*p[15] - 2*p[7]*p[14]*p[24] + 2*p[8]*p[13]*p[15] - 2*p[8]*p[13]*p[24] + 2*p[9]*p[12]*p[15] - 2*p[9]*p[12]*p[24] + 2*p[10]*p[11]*p[15] - 2*p[10]*p[11]*p[24];
+ coeff[100] = 4*p[0]*p[7]*p[10]*p[16] - 2*p[0]*p[7]*p[10]*p[25] - 4*p[0]*p[8]*p[8]*p[19] + 2*p[0]*p[8]*p[8]*p[28] + 4*p[0]*p[8]*p[9]*p[16] - 2*p[0]*p[8]*p[9]*p[25] - 4*p[0]*p[10]*p[10]*p[19] + 2*p[0]*p[10]*p[10]*p[28] - 4*p[0]*p[11]*p[14]*p[16] + 2*p[0]*p[11]*p[14]*p[25] + 4*p[0]*p[12]*p[12]*p[19] - 2*p[0]*p[12]*p[12]*p[28] - 4*p[0]*p[12]*p[13]*p[16] + 2*p[0]*p[12]*p[13]*p[25] + 4*p[0]*p[14]*p[14]*p[19] - 2*p[0]*p[14]*p[14]*p[28] + 2*p[7]*p[11]*p[19] - 2*p[7]*p[11]*p[28] + 2*p[7]*p[14]*p[16] - 2*p[7]*p[14]*p[25] - 2*p[8]*p[12]*p[19] + 2*p[8]*p[12]*p[28] + 2*p[8]*p[13]*p[16] - 2*p[8]*p[13]*p[25] + 2*p[9]*p[12]*p[16] - 2*p[9]*p[12]*p[25] + 2*p[9]*p[13]*p[19] - 2*p[9]*p[13]*p[28] + 2*p[10]*p[11]*p[16] - 2*p[10]*p[11]*p[25] - 2*p[10]*p[14]*p[19] + 2*p[10]*p[14]*p[28];
+ coeff[101] = -4*p[0]*p[7]*p[8]*p[22] + 2*p[0]*p[7]*p[8]*p[31] + 4*p[0]*p[7]*p[10]*p[17] - 2*p[0]*p[7]*p[10]*p[26] - 4*p[0]*p[8]*p[8]*p[20] + 2*p[0]*p[8]*p[8]*p[29] + 4*p[0]*p[8]*p[9]*p[17] - 2*p[0]*p[8]*p[9]*p[26] + 4*p[0]*p[9]*p[10]*p[22] - 2*p[0]*p[9]*p[10]*p[31] - 4*p[0]*p[10]*p[10]*p[20] + 2*p[0]*p[10]*p[10]*p[29] + 4*p[0]*p[11]*p[12]*p[22] - 2*p[0]*p[11]*p[12]*p[31] - 4*p[0]*p[11]*p[14]*p[17] + 2*p[0]*p[11]*p[14]*p[26] + 4*p[0]*p[12]*p[12]*p[20] - 2*p[0]*p[12]*p[12]*p[29] - 4*p[0]*p[12]*p[13]*p[17] + 2*p[0]*p[12]*p[13]*p[26] - 4*p[0]*p[13]*p[14]*p[22] + 2*p[0]*p[13]*p[14]*p[31] + 4*p[0]*p[14]*p[14]*p[20] - 2*p[0]*p[14]*p[14]*p[29] + 2*p[7]*p[11]*p[20] - 2*p[7]*p[11]*p[29] - 2*p[7]*p[12]*p[22] + 2*p[7]*p[12]*p[31] + 2*p[7]*p[14]*p[17] - 2*p[7]*p[14]*p[26] - 2*p[8]*p[11]*p[22] + 2*p[8]*p[11]*p[31] - 2*p[8]*p[12]*p[20] + 2*p[8]*p[12]*p[29] + 2*p[8]*p[13]*p[17] - 2*p[8]*p[13]*p[26] + 2*p[9]*p[12]*p[17] - 2*p[9]*p[12]*p[26] + 2*p[9]*p[13]*p[20] - 2*p[9]*p[13]*p[29] + 2*p[9]*p[14]*p[22] - 2*p[9]*p[14]*p[31] + 2*p[10]*p[11]*p[17] - 2*p[10]*p[11]*p[26] + 2*p[10]*p[13]*p[22] - 2*p[10]*p[13]*p[31] - 2*p[10]*p[14]*p[20] + 2*p[10]*p[14]*p[29];
+ coeff[102] = -2*p[0]*p[7]*p[10]*p[15] - 2*p[0]*p[8]*p[9]*p[15] + 2*p[0]*p[11]*p[14]*p[15] + 2*p[0]*p[12]*p[13]*p[15] - 2*p[7]*p[14]*p[15] + 2*p[7]*p[14]*p[24] - 2*p[8]*p[13]*p[15] + 2*p[8]*p[13]*p[24] - 2*p[9]*p[12]*p[15] + 2*p[9]*p[12]*p[24] - 2*p[10]*p[11]*p[15] + 2*p[10]*p[11]*p[24];
+ coeff[103] = -2*p[0]*p[7]*p[10]*p[16] + 2*p[0]*p[8]*p[8]*p[19] - 2*p[0]*p[8]*p[9]*p[16] + 2*p[0]*p[10]*p[10]*p[19] + 2*p[0]*p[11]*p[14]*p[16] - 2*p[0]*p[12]*p[12]*p[19] + 2*p[0]*p[12]*p[13]*p[16] - 2*p[0]*p[14]*p[14]*p[19] - 2*p[7]*p[11]*p[19] + 2*p[7]*p[11]*p[28] - 2*p[7]*p[14]*p[16] + 2*p[7]*p[14]*p[25] + 2*p[8]*p[12]*p[19] - 2*p[8]*p[12]*p[28] - 2*p[8]*p[13]*p[16] + 2*p[8]*p[13]*p[25] - 2*p[9]*p[12]*p[16] + 2*p[9]*p[12]*p[25] - 2*p[9]*p[13]*p[19] + 2*p[9]*p[13]*p[28] - 2*p[10]*p[11]*p[16] + 2*p[10]*p[11]*p[25] + 2*p[10]*p[14]*p[19] - 2*p[10]*p[14]*p[28];
+ coeff[104] = 2*p[0]*p[7]*p[8]*p[22] - 2*p[0]*p[7]*p[10]*p[17] + 2*p[0]*p[8]*p[8]*p[20] - 2*p[0]*p[8]*p[9]*p[17] - 2*p[0]*p[9]*p[10]*p[22] + 2*p[0]*p[10]*p[10]*p[20] - 2*p[0]*p[11]*p[12]*p[22] + 2*p[0]*p[11]*p[14]*p[17] - 2*p[0]*p[12]*p[12]*p[20] + 2*p[0]*p[12]*p[13]*p[17] + 2*p[0]*p[13]*p[14]*p[22] - 2*p[0]*p[14]*p[14]*p[20] - 2*p[7]*p[11]*p[20] + 2*p[7]*p[11]*p[29] + 2*p[7]*p[12]*p[22] - 2*p[7]*p[12]*p[31] - 2*p[7]*p[14]*p[17] + 2*p[7]*p[14]*p[26] + 2*p[8]*p[11]*p[22] - 2*p[8]*p[11]*p[31] + 2*p[8]*p[12]*p[20] - 2*p[8]*p[12]*p[29] - 2*p[8]*p[13]*p[17] + 2*p[8]*p[13]*p[26] - 2*p[9]*p[12]*p[17] + 2*p[9]*p[12]*p[26] - 2*p[9]*p[13]*p[20] + 2*p[9]*p[13]*p[29] - 2*p[9]*p[14]*p[22] + 2*p[9]*p[14]*p[31] - 2*p[10]*p[11]*p[17] + 2*p[10]*p[11]*p[26] - 2*p[10]*p[13]*p[22] + 2*p[10]*p[13]*p[31] + 2*p[10]*p[14]*p[20] - 2*p[10]*p[14]*p[29];
+ coeff[105] = 0;
+ coeff[106] = 2*(-p[7]*p[10]*p[15] + p[7]*p[10]*p[24] - p[8]*p[9]*p[15] + p[8]*p[9]*p[24] + p[11]*p[14]*p[15] - p[11]*p[14]*p[24] + p[12]*p[13]*p[15] - p[12]*p[13]*p[24])*p[0];
+ coeff[107] = 2*(-p[7]*p[10]*p[16] + p[7]*p[10]*p[25] + p[8]*p[8]*p[19] - p[8]*p[8]*p[28] - p[8]*p[9]*p[16] + p[8]*p[9]*p[25] + p[10]*p[10]*p[19] - p[10]*p[10]*p[28] + p[11]*p[14]*p[16] - p[11]*p[14]*p[25] - p[12]*p[12]*p[19] + p[12]*p[12]*p[28] + p[12]*p[13]*p[16] - p[12]*p[13]*p[25] - p[14]*p[14]*p[19] + p[14]*p[14]*p[28])*p[0];
+ coeff[108] = 2*(p[7]*p[8]*p[22] - p[7]*p[8]*p[31] - p[7]*p[10]*p[17] + p[7]*p[10]*p[26] + p[8]*p[8]*p[20] - p[8]*p[8]*p[29] - p[8]*p[9]*p[17] + p[8]*p[9]*p[26] - p[9]*p[10]*p[22] + p[9]*p[10]*p[31] + p[10]*p[10]*p[20] - p[10]*p[10]*p[29] - p[11]*p[12]*p[22] + p[11]*p[12]*p[31] + p[11]*p[14]*p[17] - p[11]*p[14]*p[26] - p[12]*p[12]*p[20] + p[12]*p[12]*p[29] + p[12]*p[13]*p[17] - p[12]*p[13]*p[26] + p[13]*p[14]*p[22] - p[13]*p[14]*p[31] - p[14]*p[14]*p[20] + p[14]*p[14]*p[29])*p[0];
+ coeff[109] = 2*(p[7]*p[10]*p[15] - p[7]*p[10]*p[24] + p[8]*p[9]*p[15] - p[8]*p[9]*p[24] - p[11]*p[14]*p[15] + p[11]*p[14]*p[24] - p[12]*p[13]*p[15] + p[12]*p[13]*p[24])*p[0];
+ coeff[110] = 2*(p[7]*p[10]*p[16] - p[7]*p[10]*p[25] - p[8]*p[8]*p[19] + p[8]*p[8]*p[28] + p[8]*p[9]*p[16] - p[8]*p[9]*p[25] - p[10]*p[10]*p[19] + p[10]*p[10]*p[28] - p[11]*p[14]*p[16] + p[11]*p[14]*p[25] + p[12]*p[12]*p[19] - p[12]*p[12]*p[28] - p[12]*p[13]*p[16] + p[12]*p[13]*p[25] + p[14]*p[14]*p[19] - p[14]*p[14]*p[28])*p[0];
+ coeff[111] = 2*(-p[7]*p[8]*p[22] + p[7]*p[8]*p[31] + p[7]*p[10]*p[17] - p[7]*p[10]*p[26] - p[8]*p[8]*p[20] + p[8]*p[8]*p[29] + p[8]*p[9]*p[17] - p[8]*p[9]*p[26] + p[9]*p[10]*p[22] - p[9]*p[10]*p[31] - p[10]*p[10]*p[20] + p[10]*p[10]*p[29] + p[11]*p[12]*p[22] - p[11]*p[12]*p[31] - p[11]*p[14]*p[17] + p[11]*p[14]*p[26] + p[12]*p[12]*p[20] - p[12]*p[12]*p[29] - p[12]*p[13]*p[17] + p[12]*p[13]*p[26] - p[13]*p[14]*p[22] + p[13]*p[14]*p[31] + p[14]*p[14]*p[20] - p[14]*p[14]*p[29])*p[0];
+ coeff[112] = -p[3] + p[6] - p[7]*p[8]*p[21] + p[7]*p[8]*p[30] + p[7]*p[9]*p[18] - p[7]*p[9]*p[27] + p[8]*p[8]*p[23] - p[8]*p[8]*p[32] - p[8]*p[10]*p[18] + p[8]*p[10]*p[27] + p[9]*p[9]*p[23] - p[9]*p[9]*p[32] - p[9]*p[10]*p[21] + p[9]*p[10]*p[30] - p[11]*p[12]*p[21] + p[11]*p[12]*p[30] + p[11]*p[13]*p[18] - p[11]*p[13]*p[27] + p[12]*p[12]*p[23] - p[12]*p[12]*p[32] - p[12]*p[14]*p[18] + p[12]*p[14]*p[27] + p[13]*p[13]*p[23] - p[13]*p[13]*p[32] - p[13]*p[14]*p[21] + p[13]*p[14]*p[30] - p[23] + p[32];
+ coeff[113] = 2*p[7]*p[9]*p[15] - p[7]*p[9]*p[24] - 2*p[8]*p[10]*p[15] + p[8]*p[10]*p[24] + 2*p[11]*p[13]*p[15] - p[11]*p[13]*p[24] - 2*p[12]*p[14]*p[15] + p[12]*p[14]*p[24];
+ coeff[114] = -2*p[7]*p[8]*p[19] + p[7]*p[8]*p[28] + 2*p[7]*p[9]*p[16] - p[7]*p[9]*p[25] - 2*p[8]*p[10]*p[16] + p[8]*p[10]*p[25] - 2*p[9]*p[10]*p[19] + p[9]*p[10]*p[28] - 2*p[11]*p[12]*p[19] + p[11]*p[12]*p[28] + 2*p[11]*p[13]*p[16] - p[11]*p[13]*p[25] - 2*p[12]*p[14]*p[16] + p[12]*p[14]*p[25] - 2*p[13]*p[14]*p[19] + p[13]*p[14]*p[28];
+ coeff[115] = -2*p[7]*p[8]*p[20] + p[7]*p[8]*p[29] + 2*p[7]*p[9]*p[17] - p[7]*p[9]*p[26] + 2*p[8]*p[8]*p[22] - p[8]*p[8]*p[31] - 2*p[8]*p[10]*p[17] + p[8]*p[10]*p[26] + 2*p[9]*p[9]*p[22] - p[9]*p[9]*p[31] - 2*p[9]*p[10]*p[20] + p[9]*p[10]*p[29] - 2*p[11]*p[12]*p[20] + p[11]*p[12]*p[29] + 2*p[11]*p[13]*p[17] - p[11]*p[13]*p[26] + 2*p[12]*p[12]*p[22] - p[12]*p[12]*p[31] - 2*p[12]*p[14]*p[17] + p[12]*p[14]*p[26] + 2*p[13]*p[13]*p[22] - p[13]*p[13]*p[31] - 2*p[13]*p[14]*p[20] + p[13]*p[14]*p[29] - 2*p[22] + p[31];
+ coeff[116] = (-p[7]*p[9] + p[8]*p[10] - p[11]*p[13] + p[12]*p[14])*p[15];
+ coeff[117] = p[7]*p[8]*p[19] - p[7]*p[9]*p[16] + p[8]*p[10]*p[16] + p[9]*p[10]*p[19] + p[11]*p[12]*p[19] - p[11]*p[13]*p[16] + p[12]*p[14]*p[16] + p[13]*p[14]*p[19];
+ coeff[118] = p[7]*p[8]*p[20] - p[7]*p[9]*p[17] - p[8]*p[8]*p[22] + p[8]*p[10]*p[17] - p[9]*p[9]*p[22] + p[9]*p[10]*p[20] + p[11]*p[12]*p[20] - p[11]*p[13]*p[17] - p[12]*p[12]*p[22] + p[12]*p[14]*p[17] - p[13]*p[13]*p[22] + p[13]*p[14]*p[20] + p[22];
+ coeff[119] = 0;
+ coeff[120] = -2*p[7]*p[9]*p[15] + 2*p[7]*p[9]*p[24] + 2*p[8]*p[10]*p[15] - 2*p[8]*p[10]*p[24] - 2*p[11]*p[13]*p[15] + 2*p[11]*p[13]*p[24] + 2*p[12]*p[14]*p[15] - 2*p[12]*p[14]*p[24];
+ coeff[121] = 2*p[7]*p[8]*p[19] - 2*p[7]*p[8]*p[28] - 2*p[7]*p[9]*p[16] + 2*p[7]*p[9]*p[25] + 2*p[8]*p[10]*p[16] - 2*p[8]*p[10]*p[25] + 2*p[9]*p[10]*p[19] - 2*p[9]*p[10]*p[28] + 2*p[11]*p[12]*p[19] - 2*p[11]*p[12]*p[28] - 2*p[11]*p[13]*p[16] + 2*p[11]*p[13]*p[25] + 2*p[12]*p[14]*p[16] - 2*p[12]*p[14]*p[25] + 2*p[13]*p[14]*p[19] - 2*p[13]*p[14]*p[28];
+ coeff[122] = 2*p[7]*p[8]*p[20] - 2*p[7]*p[8]*p[29] - 2*p[7]*p[9]*p[17] + 2*p[7]*p[9]*p[26] - 2*p[8]*p[8]*p[22] + 2*p[8]*p[8]*p[31] + 2*p[8]*p[10]*p[17] - 2*p[8]*p[10]*p[26] - 2*p[9]*p[9]*p[22] + 2*p[9]*p[9]*p[31] + 2*p[9]*p[10]*p[20] - 2*p[9]*p[10]*p[29] + 2*p[11]*p[12]*p[20] - 2*p[11]*p[12]*p[29] - 2*p[11]*p[13]*p[17] + 2*p[11]*p[13]*p[26] - 2*p[12]*p[12]*p[22] + 2*p[12]*p[12]*p[31] + 2*p[12]*p[14]*p[17] - 2*p[12]*p[14]*p[26] - 2*p[13]*p[13]*p[22] + 2*p[13]*p[13]*p[31] + 2*p[13]*p[14]*p[20] - 2*p[13]*p[14]*p[29] + 2*p[22] - 2*p[31];
+ coeff[123] = 2*p[7]*p[9]*p[15] - 2*p[7]*p[9]*p[24] - 2*p[8]*p[10]*p[15] + 2*p[8]*p[10]*p[24] + 2*p[11]*p[13]*p[15] - 2*p[11]*p[13]*p[24] - 2*p[12]*p[14]*p[15] + 2*p[12]*p[14]*p[24];
+ coeff[124] = -2*p[7]*p[8]*p[19] + 2*p[7]*p[8]*p[28] + 2*p[7]*p[9]*p[16] - 2*p[7]*p[9]*p[25] - 2*p[8]*p[10]*p[16] + 2*p[8]*p[10]*p[25] - 2*p[9]*p[10]*p[19] + 2*p[9]*p[10]*p[28] - 2*p[11]*p[12]*p[19] + 2*p[11]*p[12]*p[28] + 2*p[11]*p[13]*p[16] - 2*p[11]*p[13]*p[25] - 2*p[12]*p[14]*p[16] + 2*p[12]*p[14]*p[25] - 2*p[13]*p[14]*p[19] + 2*p[13]*p[14]*p[28];
+ coeff[125] = -2*p[7]*p[8]*p[20] + 2*p[7]*p[8]*p[29] + 2*p[7]*p[9]*p[17] - 2*p[7]*p[9]*p[26] + 2*p[8]*p[8]*p[22] - 2*p[8]*p[8]*p[31] - 2*p[8]*p[10]*p[17] + 2*p[8]*p[10]*p[26] + 2*p[9]*p[9]*p[22] - 2*p[9]*p[9]*p[31] - 2*p[9]*p[10]*p[20] + 2*p[9]*p[10]*p[29] - 2*p[11]*p[12]*p[20] + 2*p[11]*p[12]*p[29] + 2*p[11]*p[13]*p[17] - 2*p[11]*p[13]*p[26] + 2*p[12]*p[12]*p[22] - 2*p[12]*p[12]*p[31] - 2*p[12]*p[14]*p[17] + 2*p[12]*p[14]*p[26] + 2*p[13]*p[13]*p[22] - 2*p[13]*p[13]*p[31] - 2*p[13]*p[14]*p[20] + 2*p[13]*p[14]*p[29] - 2*p[22] + 2*p[31];
+ coeff[126] = 2*p[0]*p[7]*p[11]*p[23] + 2*p[0]*p[7]*p[12]*p[21] - 2*p[0]*p[7]*p[13]*p[18] + 2*p[0]*p[8]*p[11]*p[21] - 2*p[0]*p[8]*p[12]*p[23] + 2*p[0]*p[8]*p[14]*p[18] - 2*p[0]*p[9]*p[11]*p[18] - 2*p[0]*p[9]*p[13]*p[23] + 2*p[0]*p[9]*p[14]*p[21] + 2*p[0]*p[10]*p[12]*p[18] + 2*p[0]*p[10]*p[13]*p[21] + 2*p[0]*p[10]*p[14]*p[23] - p[7]*p[8]*p[21] + p[7]*p[8]*p[30] + p[7]*p[9]*p[18] - p[7]*p[9]*p[27] + p[8]*p[8]*p[23] - p[8]*p[8]*p[32] - p[8]*p[10]*p[18] + p[8]*p[10]*p[27] + p[9]*p[9]*p[23] - p[9]*p[9]*p[32] - p[9]*p[10]*p[21] + p[9]*p[10]*p[30] + p[11]*p[12]*p[21] - p[11]*p[12]*p[30] - p[11]*p[13]*p[18] + p[11]*p[13]*p[27] - p[12]*p[12]*p[23] + p[12]*p[12]*p[32] + p[12]*p[14]*p[18] - p[12]*p[14]*p[27] - p[13]*p[13]*p[23] + p[13]*p[13]*p[32] + p[13]*p[14]*p[21] - p[13]*p[14]*p[30];
+ coeff[127] = -2*p[0]*p[7]*p[13]*p[15] + 2*p[0]*p[8]*p[14]*p[15] - 2*p[0]*p[9]*p[11]*p[15] + 2*p[0]*p[10]*p[12]*p[15] + 2*p[7]*p[9]*p[15] - p[7]*p[9]*p[24] - 2*p[8]*p[10]*p[15] + p[8]*p[10]*p[24] - 2*p[11]*p[13]*p[15] + p[11]*p[13]*p[24] + 2*p[12]*p[14]*p[15] - p[12]*p[14]*p[24];
+ coeff[128] = 2*p[0]*p[7]*p[12]*p[19] - 2*p[0]*p[7]*p[13]*p[16] + 2*p[0]*p[8]*p[11]*p[19] + 2*p[0]*p[8]*p[14]*p[16] - 2*p[0]*p[9]*p[11]*p[16] + 2*p[0]*p[9]*p[14]*p[19] + 2*p[0]*p[10]*p[12]*p[16] + 2*p[0]*p[10]*p[13]*p[19] - 2*p[7]*p[8]*p[19] + p[7]*p[8]*p[28] + 2*p[7]*p[9]*p[16] - p[7]*p[9]*p[25] - 2*p[8]*p[10]*p[16] + p[8]*p[10]*p[25] - 2*p[9]*p[10]*p[19] + p[9]*p[10]*p[28] + 2*p[11]*p[12]*p[19] - p[11]*p[12]*p[28] - 2*p[11]*p[13]*p[16] + p[11]*p[13]*p[25] + 2*p[12]*p[14]*p[16] - p[12]*p[14]*p[25] + 2*p[13]*p[14]*p[19] - p[13]*p[14]*p[28];
+ coeff[129] = 2*p[0]*p[7]*p[11]*p[22] + 2*p[0]*p[7]*p[12]*p[20] - 2*p[0]*p[7]*p[13]*p[17] + 2*p[0]*p[8]*p[11]*p[20] - 2*p[0]*p[8]*p[12]*p[22] + 2*p[0]*p[8]*p[14]*p[17] - 2*p[0]*p[9]*p[11]*p[17] - 2*p[0]*p[9]*p[13]*p[22] + 2*p[0]*p[9]*p[14]*p[20] + 2*p[0]*p[10]*p[12]*p[17] + 2*p[0]*p[10]*p[13]*p[20] + 2*p[0]*p[10]*p[14]*p[22] - 2*p[7]*p[8]*p[20] + p[7]*p[8]*p[29] + 2*p[7]*p[9]*p[17] - p[7]*p[9]*p[26] + 2*p[8]*p[8]*p[22] - p[8]*p[8]*p[31] - 2*p[8]*p[10]*p[17] + p[8]*p[10]*p[26] + 2*p[9]*p[9]*p[22] - p[9]*p[9]*p[31] - 2*p[9]*p[10]*p[20] + p[9]*p[10]*p[29] + 2*p[11]*p[12]*p[20] - p[11]*p[12]*p[29] - 2*p[11]*p[13]*p[17] + p[11]*p[13]*p[26] - 2*p[12]*p[12]*p[22] + p[12]*p[12]*p[31] + 2*p[12]*p[14]*p[17] - p[12]*p[14]*p[26] - 2*p[13]*p[13]*p[22] + p[13]*p[13]*p[31] + 2*p[13]*p[14]*p[20] - p[13]*p[14]*p[29];
+ coeff[130] = (-p[7]*p[9] + p[8]*p[10] + p[11]*p[13] - p[12]*p[14])*p[15];
+ coeff[131] = p[7]*p[8]*p[19] - p[7]*p[9]*p[16] + p[8]*p[10]*p[16] + p[9]*p[10]*p[19] - p[11]*p[12]*p[19] + p[11]*p[13]*p[16] - p[12]*p[14]*p[16] - p[13]*p[14]*p[19];
+ coeff[132] = p[7]*p[8]*p[20] - p[7]*p[9]*p[17] - p[8]*p[8]*p[22] + p[8]*p[10]*p[17] - p[9]*p[9]*p[22] + p[9]*p[10]*p[20] - p[11]*p[12]*p[20] + p[11]*p[13]*p[17] + p[12]*p[12]*p[22] - p[12]*p[14]*p[17] + p[13]*p[13]*p[22] - p[13]*p[14]*p[20];
+ coeff[133] = 2*(-p[7]*p[11]*p[23] + p[7]*p[11]*p[32] - p[7]*p[12]*p[21] + p[7]*p[12]*p[30] + p[7]*p[13]*p[18] - p[7]*p[13]*p[27] - p[8]*p[11]*p[21] + p[8]*p[11]*p[30] + p[8]*p[12]*p[23] - p[8]*p[12]*p[32] - p[8]*p[14]*p[18] + p[8]*p[14]*p[27] + p[9]*p[11]*p[18] - p[9]*p[11]*p[27] + p[9]*p[13]*p[23] - p[9]*p[13]*p[32] - p[9]*p[14]*p[21] + p[9]*p[14]*p[30] - p[10]*p[12]*p[18] + p[10]*p[12]*p[27] - p[10]*p[13]*p[21] + p[10]*p[13]*p[30] - p[10]*p[14]*p[23] + p[10]*p[14]*p[32])*p[0];
+ coeff[134] = 4*p[0]*p[7]*p[13]*p[15] - 2*p[0]*p[7]*p[13]*p[24] - 4*p[0]*p[8]*p[14]*p[15] + 2*p[0]*p[8]*p[14]*p[24] + 4*p[0]*p[9]*p[11]*p[15] - 2*p[0]*p[9]*p[11]*p[24] - 4*p[0]*p[10]*p[12]*p[15] + 2*p[0]*p[10]*p[12]*p[24] - 2*p[7]*p[9]*p[15] + 2*p[7]*p[9]*p[24] + 2*p[8]*p[10]*p[15] - 2*p[8]*p[10]*p[24] + 2*p[11]*p[13]*p[15] - 2*p[11]*p[13]*p[24] - 2*p[12]*p[14]*p[15] + 2*p[12]*p[14]*p[24];
+ coeff[135] = -4*p[0]*p[7]*p[12]*p[19] + 2*p[0]*p[7]*p[12]*p[28] + 4*p[0]*p[7]*p[13]*p[16] - 2*p[0]*p[7]*p[13]*p[25] - 4*p[0]*p[8]*p[11]*p[19] + 2*p[0]*p[8]*p[11]*p[28] - 4*p[0]*p[8]*p[14]*p[16] + 2*p[0]*p[8]*p[14]*p[25] + 4*p[0]*p[9]*p[11]*p[16] - 2*p[0]*p[9]*p[11]*p[25] - 4*p[0]*p[9]*p[14]*p[19] + 2*p[0]*p[9]*p[14]*p[28] - 4*p[0]*p[10]*p[12]*p[16] + 2*p[0]*p[10]*p[12]*p[25] - 4*p[0]*p[10]*p[13]*p[19] + 2*p[0]*p[10]*p[13]*p[28] + 2*p[7]*p[8]*p[19] - 2*p[7]*p[8]*p[28] - 2*p[7]*p[9]*p[16] + 2*p[7]*p[9]*p[25] + 2*p[8]*p[10]*p[16] - 2*p[8]*p[10]*p[25] + 2*p[9]*p[10]*p[19] - 2*p[9]*p[10]*p[28] - 2*p[11]*p[12]*p[19] + 2*p[11]*p[12]*p[28] + 2*p[11]*p[13]*p[16] - 2*p[11]*p[13]*p[25] - 2*p[12]*p[14]*p[16] + 2*p[12]*p[14]*p[25] - 2*p[13]*p[14]*p[19] + 2*p[13]*p[14]*p[28];
+ coeff[136] = -4*p[0]*p[7]*p[11]*p[22] + 2*p[0]*p[7]*p[11]*p[31] - 4*p[0]*p[7]*p[12]*p[20] + 2*p[0]*p[7]*p[12]*p[29] + 4*p[0]*p[7]*p[13]*p[17] - 2*p[0]*p[7]*p[13]*p[26] - 4*p[0]*p[8]*p[11]*p[20] + 2*p[0]*p[8]*p[11]*p[29] + 4*p[0]*p[8]*p[12]*p[22] - 2*p[0]*p[8]*p[12]*p[31] - 4*p[0]*p[8]*p[14]*p[17] + 2*p[0]*p[8]*p[14]*p[26] + 4*p[0]*p[9]*p[11]*p[17] - 2*p[0]*p[9]*p[11]*p[26] + 4*p[0]*p[9]*p[13]*p[22] - 2*p[0]*p[9]*p[13]*p[31] - 4*p[0]*p[9]*p[14]*p[20] + 2*p[0]*p[9]*p[14]*p[29] - 4*p[0]*p[10]*p[12]*p[17] + 2*p[0]*p[10]*p[12]*p[26] - 4*p[0]*p[10]*p[13]*p[20] + 2*p[0]*p[10]*p[13]*p[29] - 4*p[0]*p[10]*p[14]*p[22] + 2*p[0]*p[10]*p[14]*p[31] + 2*p[7]*p[8]*p[20] - 2*p[7]*p[8]*p[29] - 2*p[7]*p[9]*p[17] + 2*p[7]*p[9]*p[26] - 2*p[8]*p[8]*p[22] + 2*p[8]*p[8]*p[31] + 2*p[8]*p[10]*p[17] - 2*p[8]*p[10]*p[26] - 2*p[9]*p[9]*p[22] + 2*p[9]*p[9]*p[31] + 2*p[9]*p[10]*p[20] - 2*p[9]*p[10]*p[29] - 2*p[11]*p[12]*p[20] + 2*p[11]*p[12]*p[29] + 2*p[11]*p[13]*p[17] - 2*p[11]*p[13]*p[26] + 2*p[12]*p[12]*p[22] - 2*p[12]*p[12]*p[31] - 2*p[12]*p[14]*p[17] + 2*p[12]*p[14]*p[26] + 2*p[13]*p[13]*p[22] - 2*p[13]*p[13]*p[31] - 2*p[13]*p[14]*p[20] + 2*p[13]*p[14]*p[29];
+ coeff[137] = -2*p[0]*p[7]*p[13]*p[15] + 2*p[0]*p[8]*p[14]*p[15] - 2*p[0]*p[9]*p[11]*p[15] + 2*p[0]*p[10]*p[12]*p[15] + 2*p[7]*p[9]*p[15] - 2*p[7]*p[9]*p[24] - 2*p[8]*p[10]*p[15] + 2*p[8]*p[10]*p[24] - 2*p[11]*p[13]*p[15] + 2*p[11]*p[13]*p[24] + 2*p[12]*p[14]*p[15] - 2*p[12]*p[14]*p[24];
+ coeff[138] = 2*p[0]*p[7]*p[12]*p[19] - 2*p[0]*p[7]*p[13]*p[16] + 2*p[0]*p[8]*p[11]*p[19] + 2*p[0]*p[8]*p[14]*p[16] - 2*p[0]*p[9]*p[11]*p[16] + 2*p[0]*p[9]*p[14]*p[19] + 2*p[0]*p[10]*p[12]*p[16] + 2*p[0]*p[10]*p[13]*p[19] - 2*p[7]*p[8]*p[19] + 2*p[7]*p[8]*p[28] + 2*p[7]*p[9]*p[16] - 2*p[7]*p[9]*p[25] - 2*p[8]*p[10]*p[16] + 2*p[8]*p[10]*p[25] - 2*p[9]*p[10]*p[19] + 2*p[9]*p[10]*p[28] + 2*p[11]*p[12]*p[19] - 2*p[11]*p[12]*p[28] - 2*p[11]*p[13]*p[16] + 2*p[11]*p[13]*p[25] + 2*p[12]*p[14]*p[16] - 2*p[12]*p[14]*p[25] + 2*p[13]*p[14]*p[19] - 2*p[13]*p[14]*p[28];
+ coeff[139] = 2*p[0]*p[7]*p[11]*p[22] + 2*p[0]*p[7]*p[12]*p[20] - 2*p[0]*p[7]*p[13]*p[17] + 2*p[0]*p[8]*p[11]*p[20] - 2*p[0]*p[8]*p[12]*p[22] + 2*p[0]*p[8]*p[14]*p[17] - 2*p[0]*p[9]*p[11]*p[17] - 2*p[0]*p[9]*p[13]*p[22] + 2*p[0]*p[9]*p[14]*p[20] + 2*p[0]*p[10]*p[12]*p[17] + 2*p[0]*p[10]*p[13]*p[20] + 2*p[0]*p[10]*p[14]*p[22] - 2*p[7]*p[8]*p[20] + 2*p[7]*p[8]*p[29] + 2*p[7]*p[9]*p[17] - 2*p[7]*p[9]*p[26] + 2*p[8]*p[8]*p[22] - 2*p[8]*p[8]*p[31] - 2*p[8]*p[10]*p[17] + 2*p[8]*p[10]*p[26] + 2*p[9]*p[9]*p[22] - 2*p[9]*p[9]*p[31] - 2*p[9]*p[10]*p[20] + 2*p[9]*p[10]*p[29] + 2*p[11]*p[12]*p[20] - 2*p[11]*p[12]*p[29] - 2*p[11]*p[13]*p[17] + 2*p[11]*p[13]*p[26] - 2*p[12]*p[12]*p[22] + 2*p[12]*p[12]*p[31] + 2*p[12]*p[14]*p[17] - 2*p[12]*p[14]*p[26] - 2*p[13]*p[13]*p[22] + 2*p[13]*p[13]*p[31] + 2*p[13]*p[14]*p[20] - 2*p[13]*p[14]*p[29];
+ coeff[140] = 0;
+ coeff[141] = 2*(-p[7]*p[13]*p[15] + p[7]*p[13]*p[24] + p[8]*p[14]*p[15] - p[8]*p[14]*p[24] - p[9]*p[11]*p[15] + p[9]*p[11]*p[24] + p[10]*p[12]*p[15] - p[10]*p[12]*p[24])*p[0];
+ coeff[142] = 2*(p[7]*p[12]*p[19] - p[7]*p[12]*p[28] - p[7]*p[13]*p[16] + p[7]*p[13]*p[25] + p[8]*p[11]*p[19] - p[8]*p[11]*p[28] + p[8]*p[14]*p[16] - p[8]*p[14]*p[25] - p[9]*p[11]*p[16] + p[9]*p[11]*p[25] + p[9]*p[14]*p[19] - p[9]*p[14]*p[28] + p[10]*p[12]*p[16] - p[10]*p[12]*p[25] + p[10]*p[13]*p[19] - p[10]*p[13]*p[28])*p[0];
+ coeff[143] = 2*(p[7]*p[11]*p[22] - p[7]*p[11]*p[31] + p[7]*p[12]*p[20] - p[7]*p[12]*p[29] - p[7]*p[13]*p[17] + p[7]*p[13]*p[26] + p[8]*p[11]*p[20] - p[8]*p[11]*p[29] - p[8]*p[12]*p[22] + p[8]*p[12]*p[31] + p[8]*p[14]*p[17] - p[8]*p[14]*p[26] - p[9]*p[11]*p[17] + p[9]*p[11]*p[26] - p[9]*p[13]*p[22] + p[9]*p[13]*p[31] + p[9]*p[14]*p[20] - p[9]*p[14]*p[29] + p[10]*p[12]*p[17] - p[10]*p[12]*p[26] + p[10]*p[13]*p[20] - p[10]*p[13]*p[29] + p[10]*p[14]*p[22] - p[10]*p[14]*p[31])*p[0];
+ coeff[144] = 2*(p[7]*p[13]*p[15] - p[7]*p[13]*p[24] - p[8]*p[14]*p[15] + p[8]*p[14]*p[24] + p[9]*p[11]*p[15] - p[9]*p[11]*p[24] - p[10]*p[12]*p[15] + p[10]*p[12]*p[24])*p[0];
+ coeff[145] = 2*(-p[7]*p[12]*p[19] + p[7]*p[12]*p[28] + p[7]*p[13]*p[16] - p[7]*p[13]*p[25] - p[8]*p[11]*p[19] + p[8]*p[11]*p[28] - p[8]*p[14]*p[16] + p[8]*p[14]*p[25] + p[9]*p[11]*p[16] - p[9]*p[11]*p[25] - p[9]*p[14]*p[19] + p[9]*p[14]*p[28] - p[10]*p[12]*p[16] + p[10]*p[12]*p[25] - p[10]*p[13]*p[19] + p[10]*p[13]*p[28])*p[0];
+ coeff[146] = 2*(-p[7]*p[11]*p[22] + p[7]*p[11]*p[31] - p[7]*p[12]*p[20] + p[7]*p[12]*p[29] + p[7]*p[13]*p[17] - p[7]*p[13]*p[26] - p[8]*p[11]*p[20] + p[8]*p[11]*p[29] + p[8]*p[12]*p[22] - p[8]*p[12]*p[31] - p[8]*p[14]*p[17] + p[8]*p[14]*p[26] + p[9]*p[11]*p[17] - p[9]*p[11]*p[26] + p[9]*p[13]*p[22] - p[9]*p[13]*p[31] - p[9]*p[14]*p[20] + p[9]*p[14]*p[29] - p[10]*p[12]*p[17] + p[10]*p[12]*p[26] - p[10]*p[13]*p[20] + p[10]*p[13]*p[29] - p[10]*p[14]*p[22] + p[10]*p[14]*p[31])*p[0];
+ coeff[147] = -2*p[0]*p[7]*p[8]*p[21] + 2*p[0]*p[7]*p[9]*p[18] + 2*p[0]*p[8]*p[8]*p[23] - 2*p[0]*p[8]*p[10]*p[18] + 2*p[0]*p[9]*p[9]*p[23] - 2*p[0]*p[9]*p[10]*p[21] + 2*p[0]*p[11]*p[12]*p[21] - 2*p[0]*p[11]*p[13]*p[18] - 2*p[0]*p[12]*p[12]*p[23] + 2*p[0]*p[12]*p[14]*p[18] - 2*p[0]*p[13]*p[13]*p[23] + 2*p[0]*p[13]*p[14]*p[21] - p[7]*p[11]*p[23] + p[7]*p[11]*p[32] - p[7]*p[12]*p[21] + p[7]*p[12]*p[30] + p[7]*p[13]*p[18] - p[7]*p[13]*p[27] - p[8]*p[11]*p[21] + p[8]*p[11]*p[30] + p[8]*p[12]*p[23] - p[8]*p[12]*p[32] - p[8]*p[14]*p[18] + p[8]*p[14]*p[27] + p[9]*p[11]*p[18] - p[9]*p[11]*p[27] + p[9]*p[13]*p[23] - p[9]*p[13]*p[32] - p[9]*p[14]*p[21] + p[9]*p[14]*p[30] - p[10]*p[12]*p[18] + p[10]*p[12]*p[27] - p[10]*p[13]*p[21] + p[10]*p[13]*p[30] - p[10]*p[14]*p[23] + p[10]*p[14]*p[32];
+ coeff[148] = 2*p[0]*p[7]*p[9]*p[15] - 2*p[0]*p[8]*p[10]*p[15] - 2*p[0]*p[11]*p[13]*p[15] + 2*p[0]*p[12]*p[14]*p[15] + 2*p[7]*p[13]*p[15] - p[7]*p[13]*p[24] - 2*p[8]*p[14]*p[15] + p[8]*p[14]*p[24] + 2*p[9]*p[11]*p[15] - p[9]*p[11]*p[24] - 2*p[10]*p[12]*p[15] + p[10]*p[12]*p[24];
+ coeff[149] = -2*p[0]*p[7]*p[8]*p[19] + 2*p[0]*p[7]*p[9]*p[16] - 2*p[0]*p[8]*p[10]*p[16] - 2*p[0]*p[9]*p[10]*p[19] + 2*p[0]*p[11]*p[12]*p[19] - 2*p[0]*p[11]*p[13]*p[16] + 2*p[0]*p[12]*p[14]*p[16] + 2*p[0]*p[13]*p[14]*p[19] - 2*p[7]*p[12]*p[19] + p[7]*p[12]*p[28] + 2*p[7]*p[13]*p[16] - p[7]*p[13]*p[25] - 2*p[8]*p[11]*p[19] + p[8]*p[11]*p[28] - 2*p[8]*p[14]*p[16] + p[8]*p[14]*p[25] + 2*p[9]*p[11]*p[16] - p[9]*p[11]*p[25] - 2*p[9]*p[14]*p[19] + p[9]*p[14]*p[28] - 2*p[10]*p[12]*p[16] + p[10]*p[12]*p[25] - 2*p[10]*p[13]*p[19] + p[10]*p[13]*p[28];
+ coeff[150] = -2*p[0]*p[7]*p[8]*p[20] + 2*p[0]*p[7]*p[9]*p[17] + 2*p[0]*p[8]*p[8]*p[22] - 2*p[0]*p[8]*p[10]*p[17] + 2*p[0]*p[9]*p[9]*p[22] - 2*p[0]*p[9]*p[10]*p[20] + 2*p[0]*p[11]*p[12]*p[20] - 2*p[0]*p[11]*p[13]*p[17] - 2*p[0]*p[12]*p[12]*p[22] + 2*p[0]*p[12]*p[14]*p[17] - 2*p[0]*p[13]*p[13]*p[22] + 2*p[0]*p[13]*p[14]*p[20] - 2*p[7]*p[11]*p[22] + p[7]*p[11]*p[31] - 2*p[7]*p[12]*p[20] + p[7]*p[12]*p[29] + 2*p[7]*p[13]*p[17] - p[7]*p[13]*p[26] - 2*p[8]*p[11]*p[20] + p[8]*p[11]*p[29] + 2*p[8]*p[12]*p[22] - p[8]*p[12]*p[31] - 2*p[8]*p[14]*p[17] + p[8]*p[14]*p[26] + 2*p[9]*p[11]*p[17] - p[9]*p[11]*p[26] + 2*p[9]*p[13]*p[22] - p[9]*p[13]*p[31] - 2*p[9]*p[14]*p[20] + p[9]*p[14]*p[29] - 2*p[10]*p[12]*p[17] + p[10]*p[12]*p[26] - 2*p[10]*p[13]*p[20] + p[10]*p[13]*p[29] - 2*p[10]*p[14]*p[22] + p[10]*p[14]*p[31];
+ coeff[151] = (-p[7]*p[13] + p[8]*p[14] - p[9]*p[11] + p[10]*p[12])*p[15];
+ coeff[152] = p[7]*p[12]*p[19] - p[7]*p[13]*p[16] + p[8]*p[11]*p[19] + p[8]*p[14]*p[16] - p[9]*p[11]*p[16] + p[9]*p[14]*p[19] + p[10]*p[12]*p[16] + p[10]*p[13]*p[19];
+ coeff[153] = p[7]*p[11]*p[22] + p[7]*p[12]*p[20] - p[7]*p[13]*p[17] + p[8]*p[11]*p[20] - p[8]*p[12]*p[22] + p[8]*p[14]*p[17] - p[9]*p[11]*p[17] - p[9]*p[13]*p[22] + p[9]*p[14]*p[20] + p[10]*p[12]*p[17] + p[10]*p[13]*p[20] + p[10]*p[14]*p[22];
+ coeff[154] = 2*(p[7]*p[8]*p[21] - p[7]*p[8]*p[30] - p[7]*p[9]*p[18] + p[7]*p[9]*p[27] - p[8]*p[8]*p[23] + p[8]*p[8]*p[32] + p[8]*p[10]*p[18] - p[8]*p[10]*p[27] - p[9]*p[9]*p[23] + p[9]*p[9]*p[32] + p[9]*p[10]*p[21] - p[9]*p[10]*p[30] - p[11]*p[12]*p[21] + p[11]*p[12]*p[30] + p[11]*p[13]*p[18] - p[11]*p[13]*p[27] + p[12]*p[12]*p[23] - p[12]*p[12]*p[32] - p[12]*p[14]*p[18] + p[12]*p[14]*p[27] + p[13]*p[13]*p[23] - p[13]*p[13]*p[32] - p[13]*p[14]*p[21] + p[13]*p[14]*p[30])*p[0];
+ coeff[155] = -4*p[0]*p[7]*p[9]*p[15] + 2*p[0]*p[7]*p[9]*p[24] + 4*p[0]*p[8]*p[10]*p[15] - 2*p[0]*p[8]*p[10]*p[24] + 4*p[0]*p[11]*p[13]*p[15] - 2*p[0]*p[11]*p[13]*p[24] - 4*p[0]*p[12]*p[14]*p[15] + 2*p[0]*p[12]*p[14]*p[24] - 2*p[7]*p[13]*p[15] + 2*p[7]*p[13]*p[24] + 2*p[8]*p[14]*p[15] - 2*p[8]*p[14]*p[24] - 2*p[9]*p[11]*p[15] + 2*p[9]*p[11]*p[24] + 2*p[10]*p[12]*p[15] - 2*p[10]*p[12]*p[24];
+ coeff[156] = 4*p[0]*p[7]*p[8]*p[19] - 2*p[0]*p[7]*p[8]*p[28] - 4*p[0]*p[7]*p[9]*p[16] + 2*p[0]*p[7]*p[9]*p[25] + 4*p[0]*p[8]*p[10]*p[16] - 2*p[0]*p[8]*p[10]*p[25] + 4*p[0]*p[9]*p[10]*p[19] - 2*p[0]*p[9]*p[10]*p[28] - 4*p[0]*p[11]*p[12]*p[19] + 2*p[0]*p[11]*p[12]*p[28] + 4*p[0]*p[11]*p[13]*p[16] - 2*p[0]*p[11]*p[13]*p[25] - 4*p[0]*p[12]*p[14]*p[16] + 2*p[0]*p[12]*p[14]*p[25] - 4*p[0]*p[13]*p[14]*p[19] + 2*p[0]*p[13]*p[14]*p[28] + 2*p[7]*p[12]*p[19] - 2*p[7]*p[12]*p[28] - 2*p[7]*p[13]*p[16] + 2*p[7]*p[13]*p[25] + 2*p[8]*p[11]*p[19] - 2*p[8]*p[11]*p[28] + 2*p[8]*p[14]*p[16] - 2*p[8]*p[14]*p[25] - 2*p[9]*p[11]*p[16] + 2*p[9]*p[11]*p[25] + 2*p[9]*p[14]*p[19] - 2*p[9]*p[14]*p[28] + 2*p[10]*p[12]*p[16] - 2*p[10]*p[12]*p[25] + 2*p[10]*p[13]*p[19] - 2*p[10]*p[13]*p[28];
+ coeff[157] = 4*p[0]*p[7]*p[8]*p[20] - 2*p[0]*p[7]*p[8]*p[29] - 4*p[0]*p[7]*p[9]*p[17] + 2*p[0]*p[7]*p[9]*p[26] - 4*p[0]*p[8]*p[8]*p[22] + 2*p[0]*p[8]*p[8]*p[31] + 4*p[0]*p[8]*p[10]*p[17] - 2*p[0]*p[8]*p[10]*p[26] - 4*p[0]*p[9]*p[9]*p[22] + 2*p[0]*p[9]*p[9]*p[31] + 4*p[0]*p[9]*p[10]*p[20] - 2*p[0]*p[9]*p[10]*p[29] - 4*p[0]*p[11]*p[12]*p[20] + 2*p[0]*p[11]*p[12]*p[29] + 4*p[0]*p[11]*p[13]*p[17] - 2*p[0]*p[11]*p[13]*p[26] + 4*p[0]*p[12]*p[12]*p[22] - 2*p[0]*p[12]*p[12]*p[31] - 4*p[0]*p[12]*p[14]*p[17] + 2*p[0]*p[12]*p[14]*p[26] + 4*p[0]*p[13]*p[13]*p[22] - 2*p[0]*p[13]*p[13]*p[31] - 4*p[0]*p[13]*p[14]*p[20] + 2*p[0]*p[13]*p[14]*p[29] + 2*p[7]*p[11]*p[22] - 2*p[7]*p[11]*p[31] + 2*p[7]*p[12]*p[20] - 2*p[7]*p[12]*p[29] - 2*p[7]*p[13]*p[17] + 2*p[7]*p[13]*p[26] + 2*p[8]*p[11]*p[20] - 2*p[8]*p[11]*p[29] - 2*p[8]*p[12]*p[22] + 2*p[8]*p[12]*p[31] + 2*p[8]*p[14]*p[17] - 2*p[8]*p[14]*p[26] - 2*p[9]*p[11]*p[17] + 2*p[9]*p[11]*p[26] - 2*p[9]*p[13]*p[22] + 2*p[9]*p[13]*p[31] + 2*p[9]*p[14]*p[20] - 2*p[9]*p[14]*p[29] + 2*p[10]*p[12]*p[17] - 2*p[10]*p[12]*p[26] + 2*p[10]*p[13]*p[20] - 2*p[10]*p[13]*p[29] + 2*p[10]*p[14]*p[22] - 2*p[10]*p[14]*p[31];
+ coeff[158] = 2*p[0]*p[7]*p[9]*p[15] - 2*p[0]*p[8]*p[10]*p[15] - 2*p[0]*p[11]*p[13]*p[15] + 2*p[0]*p[12]*p[14]*p[15] + 2*p[7]*p[13]*p[15] - 2*p[7]*p[13]*p[24] - 2*p[8]*p[14]*p[15] + 2*p[8]*p[14]*p[24] + 2*p[9]*p[11]*p[15] - 2*p[9]*p[11]*p[24] - 2*p[10]*p[12]*p[15] + 2*p[10]*p[12]*p[24];
+ coeff[159] = -2*p[0]*p[7]*p[8]*p[19] + 2*p[0]*p[7]*p[9]*p[16] - 2*p[0]*p[8]*p[10]*p[16] - 2*p[0]*p[9]*p[10]*p[19] + 2*p[0]*p[11]*p[12]*p[19] - 2*p[0]*p[11]*p[13]*p[16] + 2*p[0]*p[12]*p[14]*p[16] + 2*p[0]*p[13]*p[14]*p[19] - 2*p[7]*p[12]*p[19] + 2*p[7]*p[12]*p[28] + 2*p[7]*p[13]*p[16] - 2*p[7]*p[13]*p[25] - 2*p[8]*p[11]*p[19] + 2*p[8]*p[11]*p[28] - 2*p[8]*p[14]*p[16] + 2*p[8]*p[14]*p[25] + 2*p[9]*p[11]*p[16] - 2*p[9]*p[11]*p[25] - 2*p[9]*p[14]*p[19] + 2*p[9]*p[14]*p[28] - 2*p[10]*p[12]*p[16] + 2*p[10]*p[12]*p[25] - 2*p[10]*p[13]*p[19] + 2*p[10]*p[13]*p[28];
+ coeff[160] = -2*p[0]*p[7]*p[8]*p[20] + 2*p[0]*p[7]*p[9]*p[17] + 2*p[0]*p[8]*p[8]*p[22] - 2*p[0]*p[8]*p[10]*p[17] + 2*p[0]*p[9]*p[9]*p[22] - 2*p[0]*p[9]*p[10]*p[20] + 2*p[0]*p[11]*p[12]*p[20] - 2*p[0]*p[11]*p[13]*p[17] - 2*p[0]*p[12]*p[12]*p[22] + 2*p[0]*p[12]*p[14]*p[17] - 2*p[0]*p[13]*p[13]*p[22] + 2*p[0]*p[13]*p[14]*p[20] - 2*p[7]*p[11]*p[22] + 2*p[7]*p[11]*p[31] - 2*p[7]*p[12]*p[20] + 2*p[7]*p[12]*p[29] + 2*p[7]*p[13]*p[17] - 2*p[7]*p[13]*p[26] - 2*p[8]*p[11]*p[20] + 2*p[8]*p[11]*p[29] + 2*p[8]*p[12]*p[22] - 2*p[8]*p[12]*p[31] - 2*p[8]*p[14]*p[17] + 2*p[8]*p[14]*p[26] + 2*p[9]*p[11]*p[17] - 2*p[9]*p[11]*p[26] + 2*p[9]*p[13]*p[22] - 2*p[9]*p[13]*p[31] - 2*p[9]*p[14]*p[20] + 2*p[9]*p[14]*p[29] - 2*p[10]*p[12]*p[17] + 2*p[10]*p[12]*p[26] - 2*p[10]*p[13]*p[20] + 2*p[10]*p[13]*p[29] - 2*p[10]*p[14]*p[22] + 2*p[10]*p[14]*p[31];
+ coeff[161] = 0;
+ coeff[162] = 2*(p[7]*p[9]*p[15] - p[7]*p[9]*p[24] - p[8]*p[10]*p[15] + p[8]*p[10]*p[24] - p[11]*p[13]*p[15] + p[11]*p[13]*p[24] + p[12]*p[14]*p[15] - p[12]*p[14]*p[24])*p[0];
+ coeff[163] = 2*(-p[7]*p[8]*p[19] + p[7]*p[8]*p[28] + p[7]*p[9]*p[16] - p[7]*p[9]*p[25] - p[8]*p[10]*p[16] + p[8]*p[10]*p[25] - p[9]*p[10]*p[19] + p[9]*p[10]*p[28] + p[11]*p[12]*p[19] - p[11]*p[12]*p[28] - p[11]*p[13]*p[16] + p[11]*p[13]*p[25] + p[12]*p[14]*p[16] - p[12]*p[14]*p[25] + p[13]*p[14]*p[19] - p[13]*p[14]*p[28])*p[0];
+ coeff[164] = 2*(-p[7]*p[8]*p[20] + p[7]*p[8]*p[29] + p[7]*p[9]*p[17] - p[7]*p[9]*p[26] + p[8]*p[8]*p[22] - p[8]*p[8]*p[31] - p[8]*p[10]*p[17] + p[8]*p[10]*p[26] + p[9]*p[9]*p[22] - p[9]*p[9]*p[31] - p[9]*p[10]*p[20] + p[9]*p[10]*p[29] + p[11]*p[12]*p[20] - p[11]*p[12]*p[29] - p[11]*p[13]*p[17] + p[11]*p[13]*p[26] - p[12]*p[12]*p[22] + p[12]*p[12]*p[31] + p[12]*p[14]*p[17] - p[12]*p[14]*p[26] - p[13]*p[13]*p[22] + p[13]*p[13]*p[31] + p[13]*p[14]*p[20] - p[13]*p[14]*p[29])*p[0];
+ coeff[165] = 2*(-p[7]*p[9]*p[15] + p[7]*p[9]*p[24] + p[8]*p[10]*p[15] - p[8]*p[10]*p[24] + p[11]*p[13]*p[15] - p[11]*p[13]*p[24] - p[12]*p[14]*p[15] + p[12]*p[14]*p[24])*p[0];
+ coeff[166] = 2*(p[7]*p[8]*p[19] - p[7]*p[8]*p[28] - p[7]*p[9]*p[16] + p[7]*p[9]*p[25] + p[8]*p[10]*p[16] - p[8]*p[10]*p[25] + p[9]*p[10]*p[19] - p[9]*p[10]*p[28] - p[11]*p[12]*p[19] + p[11]*p[12]*p[28] + p[11]*p[13]*p[16] - p[11]*p[13]*p[25] - p[12]*p[14]*p[16] + p[12]*p[14]*p[25] - p[13]*p[14]*p[19] + p[13]*p[14]*p[28])*p[0];
+ coeff[167] = 2*(p[7]*p[8]*p[20] - p[7]*p[8]*p[29] - p[7]*p[9]*p[17] + p[7]*p[9]*p[26] - p[8]*p[8]*p[22] + p[8]*p[8]*p[31] + p[8]*p[10]*p[17] - p[8]*p[10]*p[26] - p[9]*p[9]*p[22] + p[9]*p[9]*p[31] + p[9]*p[10]*p[20] - p[9]*p[10]*p[29] - p[11]*p[12]*p[20] + p[11]*p[12]*p[29] + p[11]*p[13]*p[17] - p[11]*p[13]*p[26] + p[12]*p[12]*p[22] - p[12]*p[12]*p[31] - p[12]*p[14]*p[17] + p[12]*p[14]*p[26] + p[13]*p[13]*p[22] - p[13]*p[13]*p[31] - p[13]*p[14]*p[20] + p[13]*p[14]*p[29])*p[0];
+}
+
+} // namespace embree
diff --git a/thirdparty/embree/kernels/common/point_query.h b/thirdparty/embree/kernels/common/point_query.h
new file mode 100644
index 0000000000..7d55c91fff
--- /dev/null
+++ b/thirdparty/embree/kernels/common/point_query.h
@@ -0,0 +1,136 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+namespace embree
+{
+ /* Point query structure for closest point query */
+ template<int K>
+ struct RTC_ALIGN(16) PointQueryK
+ {
+ /* Default construction does nothing */
+ __forceinline PointQueryK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline PointQueryK(const Vec3vf<K>& p, const vfloat<K>& radius = inf, const vfloat<K>& time = zero)
+ : p(p), time(time), radius(radius) {}
+
+ /* Returns the size of the ray */
+ static __forceinline size_t size() { return K; }
+
+ /* Calculates if this is a valid ray that does not cause issues during traversal */
+ __forceinline vbool<K> valid() const
+ {
+ const vbool<K> vx = (abs(p.x) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vy = (abs(p.y) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vz = (abs(p.z) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vn = radius >= vfloat<K>(0);
+ const vbool<K> vf = abs(time) < vfloat<K>(inf);
+ return vx & vy & vz & vn & vf;
+ }
+
+ __forceinline void get(PointQueryK<1>* ray) const;
+ __forceinline void get(size_t i, PointQueryK<1>& ray) const;
+ __forceinline void set(const PointQueryK<1>* ray);
+ __forceinline void set(size_t i, const PointQueryK<1>& ray);
+
+ Vec3vf<K> p; // location of the query point
+ vfloat<K> time; // time for motion blur
+ vfloat<K> radius; // radius for the point query
+ };
+
+ /* Specialization for a single point query */
+ template<>
+ struct RTC_ALIGN(16) PointQueryK<1>
+ {
+ /* Default construction does nothing */
+ __forceinline PointQueryK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline PointQueryK(const Vec3fa& p, float radius = inf, float time = zero)
+ : p(p), time(time), radius(radius) {}
+
+ /* Calculates if this is a valid ray that does not cause issues during traversal */
+ __forceinline bool valid() const {
+ return all(le_mask(abs(Vec3fa(p)), Vec3fa(FLT_LARGE)) & le_mask(Vec3fa(0.f), Vec3fa(radius))) && abs(time) < float(inf);
+ }
+
+ Vec3f p;
+ float time;
+ float radius;
+ };
+
+ /* Converts point query packet to single point query */
+ template<int K>
+ __forceinline void PointQueryK<K>::get(PointQueryK<1>* query) const
+ {
+ for (size_t i = 0; i < K; i++) // FIXME: use SIMD transpose
+ {
+ query[i].p.x = p.x[i];
+ query[i].p.y = p.y[i];
+ query[i].p.z = p.z[i];
+ query[i].time = time[i];
+ query[i].radius = radius[i];
+ }
+ }
+
+ /* Extracts a single point query out of a point query packet*/
+ template<int K>
+ __forceinline void PointQueryK<K>::get(size_t i, PointQueryK<1>& query) const
+ {
+ query.p.x = p.x[i];
+ query.p.y = p.y[i];
+ query.p.z = p.z[i];
+ query.radius = radius[i];
+ query.time = time[i];
+ }
+
+ /* Converts single point query to point query packet */
+ template<int K>
+ __forceinline void PointQueryK<K>::set(const PointQueryK<1>* query)
+ {
+ for (size_t i = 0; i < K; i++)
+ {
+ p.x[i] = query[i].p.x;
+ p.y[i] = query[i].p.y;
+ p.z[i] = query[i].p.z;
+ radius[i] = query[i].radius;
+ time[i] = query[i].time;
+ }
+ }
+
+ /* inserts a single point query into a point query packet element */
+ template<int K>
+ __forceinline void PointQueryK<K>::set(size_t i, const PointQueryK<1>& query)
+ {
+ p.x[i] = query.p.x;
+ p.y[i] = query.p.y;
+ p.z[i] = query.p.z;
+ radius[i] = query.radius;
+ time[i] = query.time;
+ }
+
+ /* Shortcuts */
+ typedef PointQueryK<1> PointQuery;
+ typedef PointQueryK<4> PointQuery4;
+ typedef PointQueryK<8> PointQuery8;
+ typedef PointQueryK<16> PointQuery16;
+ struct PointQueryN;
+
+ /* Outputs point query to stream */
+ template<int K>
+ __forceinline embree_ostream operator <<(embree_ostream cout, const PointQueryK<K>& query)
+ {
+ cout << "{ " << embree_endl
+ << " p = " << query.p << embree_endl
+ << " r = " << query.radius << embree_endl
+ << " time = " << query.time << embree_endl
+ << "}";
+ return cout;
+ }
+}
diff --git a/thirdparty/embree/kernels/common/primref.h b/thirdparty/embree/kernels/common/primref.h
new file mode 100644
index 0000000000..d61763487b
--- /dev/null
+++ b/thirdparty/embree/kernels/common/primref.h
@@ -0,0 +1,138 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+namespace embree
+{
+ /*! A primitive reference stores the bounds of the primitive and its ID. */
+ struct __aligned(32) PrimRef
+ {
+ __forceinline PrimRef () {}
+
+#if defined(__AVX__)
+ __forceinline PrimRef(const PrimRef& v) {
+ vfloat8::store((float*)this,vfloat8::load((float*)&v));
+ }
+ __forceinline PrimRef& operator=(const PrimRef& v) {
+ vfloat8::store((float*)this,vfloat8::load((float*)&v)); return *this;
+ }
+#endif
+
+ __forceinline PrimRef (const BBox3fa& bounds, unsigned int geomID, unsigned int primID)
+ {
+ lower = Vec3fx(bounds.lower, geomID);
+ upper = Vec3fx(bounds.upper, primID);
+ }
+
+ __forceinline PrimRef (const BBox3fa& bounds, size_t id)
+ {
+#if defined(__64BIT__)
+ lower = Vec3fx(bounds.lower, (unsigned)(id & 0xFFFFFFFF));
+ upper = Vec3fx(bounds.upper, (unsigned)((id >> 32) & 0xFFFFFFFF));
+#else
+ lower = Vec3fx(bounds.lower, (unsigned)id);
+ upper = Vec3fx(bounds.upper, (unsigned)0);
+#endif
+ }
+
+ /*! calculates twice the center of the primitive */
+ __forceinline const Vec3fa center2() const {
+ return lower+upper;
+ }
+
+ /*! return the bounding box of the primitive */
+ __forceinline const BBox3fa bounds() const {
+ return BBox3fa(lower,upper);
+ }
+
+ /*! size for bin heuristic is 1 */
+ __forceinline unsigned size() const {
+ return 1;
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __forceinline void binBoundsAndCenter(BBox3fa& bounds_o, Vec3fa& center_o) const
+ {
+ bounds_o = bounds();
+ center_o = embree::center2(bounds_o);
+ }
+
+ __forceinline unsigned& geomIDref() { // FIXME: remove !!!!!!!
+ return lower.u;
+ }
+ __forceinline unsigned& primIDref() { // FIXME: remove !!!!!!!
+ return upper.u;
+ }
+
+ /*! returns the geometry ID */
+ __forceinline unsigned geomID() const {
+ return lower.a;
+ }
+
+ /*! returns the primitive ID */
+ __forceinline unsigned primID() const {
+ return upper.a;
+ }
+
+ /*! returns an size_t sized ID */
+ __forceinline size_t ID() const {
+#if defined(__64BIT__)
+ return size_t(lower.u) + (size_t(upper.u) << 32);
+#else
+ return size_t(lower.u);
+#endif
+ }
+
+ /*! special function for operator< */
+ __forceinline uint64_t ID64() const {
+ return (((uint64_t)primID()) << 32) + (uint64_t)geomID();
+ }
+
+ /*! allows sorting the primrefs by ID */
+ friend __forceinline bool operator<(const PrimRef& p0, const PrimRef& p1) {
+ return p0.ID64() < p1.ID64();
+ }
+
+ /*! Outputs primitive reference to a stream. */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const PrimRef& ref) {
+ return cout << "{ lower = " << ref.lower << ", upper = " << ref.upper << ", geomID = " << ref.geomID() << ", primID = " << ref.primID() << " }";
+ }
+
+ public:
+ Vec3fx lower; //!< lower bounds and geomID
+ Vec3fx upper; //!< upper bounds and primID
+ };
+
+ /*! fast exchange for PrimRefs */
+ __forceinline void xchg(PrimRef& a, PrimRef& b)
+ {
+#if defined(__AVX__)
+ const vfloat8 aa = vfloat8::load((float*)&a);
+ const vfloat8 bb = vfloat8::load((float*)&b);
+ vfloat8::store((float*)&a,bb);
+ vfloat8::store((float*)&b,aa);
+#else
+ std::swap(a,b);
+#endif
+ }
+
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+ /************************************************************************************/
+
+ struct SubGridBuildData {
+ unsigned short sx,sy;
+ unsigned int primID;
+
+ __forceinline SubGridBuildData() {};
+ __forceinline SubGridBuildData(const unsigned int sx, const unsigned int sy, const unsigned int primID) : sx(sx), sy(sy), primID(primID) {};
+
+ __forceinline size_t x() const { return (size_t)sx & 0x7fff; }
+ __forceinline size_t y() const { return (size_t)sy & 0x7fff; }
+
+ };
+}
diff --git a/thirdparty/embree/kernels/common/primref_mb.h b/thirdparty/embree/kernels/common/primref_mb.h
new file mode 100644
index 0000000000..fb08a05003
--- /dev/null
+++ b/thirdparty/embree/kernels/common/primref_mb.h
@@ -0,0 +1,262 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+#define MBLUR_BIN_LBBOX 1
+
+namespace embree
+{
+#if MBLUR_BIN_LBBOX
+
+ /*! A primitive reference stores the bounds of the primitive and its ID. */
+ struct PrimRefMB
+ {
+ typedef LBBox3fa BBox;
+
+ __forceinline PrimRefMB () {}
+
+ __forceinline PrimRefMB (const LBBox3fa& lbounds_i, unsigned int activeTimeSegments, BBox1f time_range, unsigned int totalTimeSegments, unsigned int geomID, unsigned int primID)
+ : lbounds((LBBox3fx)lbounds_i), time_range(time_range)
+ {
+ assert(activeTimeSegments > 0);
+ lbounds.bounds0.lower.a = geomID;
+ lbounds.bounds0.upper.a = primID;
+ lbounds.bounds1.lower.a = activeTimeSegments;
+ lbounds.bounds1.upper.a = totalTimeSegments;
+ }
+
+ __forceinline PrimRefMB (EmptyTy empty, const LBBox3fa& lbounds_i, unsigned int activeTimeSegments, BBox1f time_range, unsigned int totalTimeSegments, size_t id)
+ : lbounds((LBBox3fx)lbounds_i), time_range(time_range)
+ {
+ assert(activeTimeSegments > 0);
+#if defined(__64BIT__)
+ lbounds.bounds0.lower.a = id & 0xFFFFFFFF;
+ lbounds.bounds0.upper.a = (id >> 32) & 0xFFFFFFFF;
+#else
+ lbounds.bounds0.lower.a = id;
+ lbounds.bounds0.upper.a = 0;
+#endif
+ lbounds.bounds1.lower.a = activeTimeSegments;
+ lbounds.bounds1.upper.a = totalTimeSegments;
+ }
+
+ __forceinline PrimRefMB (const LBBox3fa& lbounds_i, unsigned int activeTimeSegments, BBox1f time_range, unsigned int totalTimeSegments, size_t id)
+ : lbounds((LBBox3fx)lbounds_i), time_range(time_range)
+ {
+ assert(activeTimeSegments > 0);
+#if defined(__64BIT__)
+ lbounds.bounds0.lower.u = id & 0xFFFFFFFF;
+ lbounds.bounds0.upper.u = (id >> 32) & 0xFFFFFFFF;
+#else
+ lbounds.bounds0.lower.u = id;
+ lbounds.bounds0.upper.u = 0;
+#endif
+ lbounds.bounds1.lower.a = activeTimeSegments;
+ lbounds.bounds1.upper.a = totalTimeSegments;
+ }
+
+ /*! returns bounds for binning */
+ __forceinline LBBox3fa bounds() const {
+ return lbounds;
+ }
+
+ /*! returns the number of time segments of this primref */
+ __forceinline unsigned size() const {
+ return lbounds.bounds1.lower.a;
+ }
+
+ __forceinline unsigned totalTimeSegments() const {
+ return lbounds.bounds1.upper.a;
+ }
+
+ /* calculate overlapping time segment range */
+ __forceinline range<int> timeSegmentRange(const BBox1f& range) const {
+ return getTimeSegmentRange(range,time_range,float(totalTimeSegments()));
+ }
+
+ /* returns time that corresponds to time step */
+ __forceinline float timeStep(const int i) const {
+ assert(i>=0 && i<=(int)totalTimeSegments());
+ return time_range.lower + time_range.size()*float(i)/float(totalTimeSegments());
+ }
+
+ /*! checks if time range overlaps */
+ __forceinline bool time_range_overlap(const BBox1f& range) const
+ {
+ if (0.9999f*time_range.upper <= range.lower) return false;
+ if (1.0001f*time_range.lower >= range.upper) return false;
+ return true;
+ }
+
+ /*! returns center for binning */
+ __forceinline Vec3fa binCenter() const {
+ return center2(lbounds.interpolate(0.5f));
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __forceinline void binBoundsAndCenter(LBBox3fa& bounds_o, Vec3fa& center_o) const
+ {
+ bounds_o = bounds();
+ center_o = binCenter();
+ }
+
+ /*! returns the geometry ID */
+ __forceinline unsigned geomID() const {
+ return lbounds.bounds0.lower.a;
+ }
+
+ /*! returns the primitive ID */
+ __forceinline unsigned primID() const {
+ return lbounds.bounds0.upper.a;
+ }
+
+ /*! returns an size_t sized ID */
+ __forceinline size_t ID() const {
+#if defined(__64BIT__)
+ return size_t(lbounds.bounds0.lower.u) + (size_t(lbounds.bounds0.upper.u) << 32);
+#else
+ return size_t(lbounds.bounds0.lower.u);
+#endif
+ }
+
+ /*! special function for operator< */
+ __forceinline uint64_t ID64() const {
+ return (((uint64_t)primID()) << 32) + (uint64_t)geomID();
+ }
+
+ /*! allows sorting the primrefs by ID */
+ friend __forceinline bool operator<(const PrimRefMB& p0, const PrimRefMB& p1) {
+ return p0.ID64() < p1.ID64();
+ }
+
+ /*! Outputs primitive reference to a stream. */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const PrimRefMB& ref) {
+ return cout << "{ time_range = " << ref.time_range << ", bounds = " << ref.bounds() << ", geomID = " << ref.geomID() << ", primID = " << ref.primID() << ", active_segments = " << ref.size() << ", total_segments = " << ref.totalTimeSegments() << " }";
+ }
+
+ public:
+ LBBox3fx lbounds;
+ BBox1f time_range; // entire geometry time range
+ };
+
+#else
+
+ /*! A primitive reference stores the bounds of the primitive and its ID. */
+ struct __aligned(16) PrimRefMB
+ {
+ typedef BBox3fa BBox;
+
+ __forceinline PrimRefMB () {}
+
+ __forceinline PrimRefMB (const LBBox3fa& bounds, unsigned int activeTimeSegments, BBox1f time_range, unsigned int totalTimeSegments, unsigned int geomID, unsigned int primID)
+ : bbox(bounds.interpolate(0.5f)), _activeTimeSegments(activeTimeSegments), _totalTimeSegments(totalTimeSegments), time_range(time_range)
+ {
+ assert(activeTimeSegments > 0);
+ bbox.lower.a = geomID;
+ bbox.upper.a = primID;
+ }
+
+ __forceinline PrimRefMB (EmptyTy empty, const LBBox3fa& bounds, unsigned int activeTimeSegments, BBox1f time_range, unsigned int totalTimeSegments, size_t id)
+ : bbox(bounds.interpolate(0.5f)), _activeTimeSegments(activeTimeSegments), _totalTimeSegments(totalTimeSegments), time_range(time_range)
+ {
+ assert(activeTimeSegments > 0);
+#if defined(__64BIT__)
+ bbox.lower.u = id & 0xFFFFFFFF;
+ bbox.upper.u = (id >> 32) & 0xFFFFFFFF;
+#else
+ bbox.lower.u = id;
+ bbox.upper.u = 0;
+#endif
+ }
+
+ /*! returns bounds for binning */
+ __forceinline BBox3fa bounds() const {
+ return bbox;
+ }
+
+ /*! returns the number of time segments of this primref */
+ __forceinline unsigned int size() const {
+ return _activeTimeSegments;
+ }
+
+ __forceinline unsigned int totalTimeSegments() const {
+ return _totalTimeSegments;
+ }
+
+ /* calculate overlapping time segment range */
+ __forceinline range<int> timeSegmentRange(const BBox1f& range) const {
+ return getTimeSegmentRange(range,time_range,float(_totalTimeSegments));
+ }
+
+ /* returns time that corresponds to time step */
+ __forceinline float timeStep(const int i) const {
+ assert(i>=0 && i<=(int)_totalTimeSegments);
+ return time_range.lower + time_range.size()*float(i)/float(_totalTimeSegments);
+ }
+
+ /*! checks if time range overlaps */
+ __forceinline bool time_range_overlap(const BBox1f& range) const
+ {
+ if (0.9999f*time_range.upper <= range.lower) return false;
+ if (1.0001f*time_range.lower >= range.upper) return false;
+ return true;
+ }
+
+ /*! returns center for binning */
+ __forceinline Vec3fa binCenter() const {
+ return center2(bounds());
+ }
+
+ /*! returns bounds and centroid used for binning */
+ __forceinline void binBoundsAndCenter(BBox3fa& bounds_o, Vec3fa& center_o) const
+ {
+ bounds_o = bounds();
+ center_o = center2(bounds());
+ }
+
+ /*! returns the geometry ID */
+ __forceinline unsigned int geomID() const {
+ return bbox.lower.a;
+ }
+
+ /*! returns the primitive ID */
+ __forceinline unsigned int primID() const {
+ return bbox.upper.a;
+ }
+
+ /*! returns an size_t sized ID */
+ __forceinline size_t ID() const {
+#if defined(__64BIT__)
+ return size_t(bbox.lower.u) + (size_t(bbox.upper.u) << 32);
+#else
+ return size_t(bbox.lower.u);
+#endif
+ }
+
+ /*! special function for operator< */
+ __forceinline uint64_t ID64() const {
+ return (((uint64_t)primID()) << 32) + (uint64_t)geomID();
+ }
+
+ /*! allows sorting the primrefs by ID */
+ friend __forceinline bool operator<(const PrimRefMB& p0, const PrimRefMB& p1) {
+ return p0.ID64() < p1.ID64();
+ }
+
+ /*! Outputs primitive reference to a stream. */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const PrimRefMB& ref) {
+ return cout << "{ bounds = " << ref.bounds() << ", geomID = " << ref.geomID() << ", primID = " << ref.primID() << ", active_segments = " << ref.size() << ", total_segments = " << ref.totalTimeSegments() << " }";
+ }
+
+ public:
+ BBox3fa bbox; // bounds, geomID, primID
+ unsigned int _activeTimeSegments;
+ unsigned int _totalTimeSegments;
+ BBox1f time_range; // entire geometry time range
+ };
+
+#endif
+}
diff --git a/thirdparty/embree/kernels/common/profile.h b/thirdparty/embree/kernels/common/profile.h
new file mode 100644
index 0000000000..5ef7f6ec0f
--- /dev/null
+++ b/thirdparty/embree/kernels/common/profile.h
@@ -0,0 +1,159 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+namespace embree
+{
+ /*! helper structure for the implementation of the profile functions below */
+ struct ProfileTimer
+ {
+ static const size_t N = 20;
+
+ ProfileTimer () {}
+
+ ProfileTimer (const size_t numSkip) : i(0), j(0), maxJ(0), numSkip(numSkip), t0(0)
+ {
+ for (size_t i=0; i<N; i++) names[i] = nullptr;
+ for (size_t i=0; i<N; i++) dt_fst[i] = 0.0;
+ for (size_t i=0; i<N; i++) dt_min[i] = pos_inf;
+ for (size_t i=0; i<N; i++) dt_avg[i] = 0.0;
+ for (size_t i=0; i<N; i++) dt_max[i] = neg_inf;
+ }
+
+ __forceinline void begin()
+ {
+ j=0;
+ t0 = tj = getSeconds();
+ }
+
+ __forceinline void end() {
+ absolute("total");
+ i++;
+ }
+
+ __forceinline void operator() (const char* name) {
+ relative(name);
+ }
+
+ __forceinline void absolute (const char* name)
+ {
+ const double t1 = getSeconds();
+ const double dt = t1-t0;
+ assert(names[j] == nullptr || names[j] == name);
+ names[j] = name;
+ if (i == 0) dt_fst[j] = dt;
+ if (i>=numSkip) {
+ dt_min[j] = min(dt_min[j],dt);
+ dt_avg[j] = dt_avg[j] + dt;
+ dt_max[j] = max(dt_max[j],dt);
+ }
+ j++;
+ maxJ = max(maxJ,j);
+ }
+
+ __forceinline void relative (const char* name)
+ {
+ const double t1 = getSeconds();
+ const double dt = t1-tj;
+ tj = t1;
+ assert(names[j] == nullptr || names[j] == name);
+ names[j] = name;
+ if (i == 0) dt_fst[j] = dt;
+ if (i>=numSkip) {
+ dt_min[j] = min(dt_min[j],dt);
+ dt_avg[j] = dt_avg[j] + dt;
+ dt_max[j] = max(dt_max[j],dt);
+ }
+ j++;
+ maxJ = max(maxJ,j);
+ }
+
+ void print(size_t numElements)
+ {
+ for (size_t k=0; k<N; k++)
+ dt_avg[k] /= double(i-numSkip);
+
+ printf(" profile [M/s]:\n");
+ for (size_t j=0; j<maxJ; j++)
+ printf("%20s: fst = %7.2f M/s, min = %7.2f M/s, avg = %7.2f M/s, max = %7.2f M/s\n",
+ names[j],numElements/dt_fst[j]*1E-6,numElements/dt_max[j]*1E-6,numElements/dt_avg[j]*1E-6,numElements/dt_min[j]*1E-6);
+
+ printf(" profile [ms]:\n");
+ for (size_t j=0; j<maxJ; j++)
+ printf("%20s: fst = %7.2f ms, min = %7.2f ms, avg = %7.2f ms, max = %7.2fms\n",
+ names[j],1000.0*dt_fst[j],1000.0*dt_min[j],1000.0*dt_avg[j],1000.0*dt_max[j]);
+ }
+
+ void print()
+ {
+ printf(" profile:\n");
+
+ for (size_t k=0; k<N; k++)
+ dt_avg[k] /= double(i-numSkip);
+
+ for (size_t j=0; j<maxJ; j++) {
+ printf("%20s: fst = %7.2f ms, min = %7.2f ms, avg = %7.2f ms, max = %7.2fms\n",
+ names[j],1000.0*dt_fst[j],1000.0*dt_min[j],1000.0*dt_avg[j],1000.0*dt_max[j]);
+ }
+ }
+
+ double avg() {
+ return dt_avg[maxJ-1]/double(i-numSkip);
+ }
+
+ private:
+ size_t i;
+ size_t j;
+ size_t maxJ;
+ size_t numSkip;
+ double t0;
+ double tj;
+ const char* names[N];
+ double dt_fst[N];
+ double dt_min[N];
+ double dt_avg[N];
+ double dt_max[N];
+ };
+
+ /*! This function executes some code block multiple times and measured sections of it.
+ Use the following way:
+
+ profile(1,10,1000,[&](ProfileTimer& timer) {
+ // code
+ timer("A");
+ // code
+ timer("B");
+ });
+ */
+ template<typename Closure>
+ void profile(const size_t numSkip, const size_t numIter, const size_t numElements, const Closure& closure)
+ {
+ ProfileTimer timer(numSkip);
+
+ for (size_t i=0; i<numSkip+numIter; i++)
+ {
+ timer.begin();
+ closure(timer);
+ timer.end();
+ }
+ timer.print(numElements);
+ }
+
+ /*! similar as the function above, but the timer object comes externally */
+ template<typename Closure>
+ void profile(ProfileTimer& timer, const size_t numSkip, const size_t numIter, const size_t numElements, const Closure& closure)
+ {
+ timer = ProfileTimer(numSkip);
+
+ for (size_t i=0; i<numSkip+numIter; i++)
+ {
+ timer.begin();
+ closure(timer);
+ timer.end();
+ }
+ timer.print(numElements);
+ }
+}
diff --git a/thirdparty/embree/kernels/common/ray.h b/thirdparty/embree/kernels/common/ray.h
new file mode 100644
index 0000000000..7b951cc1e8
--- /dev/null
+++ b/thirdparty/embree/kernels/common/ray.h
@@ -0,0 +1,1517 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "instance_stack.h"
+
+// FIXME: if ray gets seperated into ray* and hit, uload4 needs to be adjusted
+
+namespace embree
+{
+ static const size_t MAX_INTERNAL_STREAM_SIZE = 32;
+
+ /* Ray structure for K rays */
+ template<int K>
+ struct RayK
+ {
+ /* Default construction does nothing */
+ __forceinline RayK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline RayK(const Vec3vf<K>& org, const Vec3vf<K>& dir,
+ const vfloat<K>& tnear = zero, const vfloat<K>& tfar = inf,
+ const vfloat<K>& time = zero, const vint<K>& mask = -1, const vint<K>& id = 0, const vint<K>& flags = 0)
+ : org(org), dir(dir), _tnear(tnear), tfar(tfar), _time(time), mask(mask), id(id), flags(flags) {}
+
+ /* Returns the size of the ray */
+ static __forceinline size_t size() { return K; }
+
+ /* Calculates if this is a valid ray that does not cause issues during traversal */
+ __forceinline vbool<K> valid() const
+ {
+ const vbool<K> vx = (abs(org.x) <= vfloat<K>(FLT_LARGE)) & (abs(dir.x) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vy = (abs(org.y) <= vfloat<K>(FLT_LARGE)) & (abs(dir.y) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vz = (abs(org.z) <= vfloat<K>(FLT_LARGE)) & (abs(dir.z) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vn = abs(tnear()) <= vfloat<K>(inf);
+ const vbool<K> vf = abs(tfar) <= vfloat<K>(inf);
+ return vx & vy & vz & vn & vf;
+ }
+
+ __forceinline void get(RayK<1>* ray) const;
+ __forceinline void get(size_t i, RayK<1>& ray) const;
+ __forceinline void set(const RayK<1>* ray);
+ __forceinline void set(size_t i, const RayK<1>& ray);
+
+ __forceinline void copy(size_t dest, size_t source);
+
+ __forceinline vint<K> octant() const
+ {
+ return select(dir.x < 0.0f, vint<K>(1), vint<K>(zero)) |
+ select(dir.y < 0.0f, vint<K>(2), vint<K>(zero)) |
+ select(dir.z < 0.0f, vint<K>(4), vint<K>(zero));
+ }
+
+ /* Ray data */
+ Vec3vf<K> org; // ray origin
+ vfloat<K> _tnear; // start of ray segment
+ Vec3vf<K> dir; // ray direction
+ vfloat<K> _time; // time of this ray for motion blur
+ vfloat<K> tfar; // end of ray segment
+ vint<K> mask; // used to mask out objects during traversal
+ vint<K> id;
+ vint<K> flags;
+
+ __forceinline vfloat<K>& tnear() { return _tnear; }
+ __forceinline vfloat<K>& time() { return _time; }
+ __forceinline const vfloat<K>& tnear() const { return _tnear; }
+ __forceinline const vfloat<K>& time() const { return _time; }
+ };
+
+ /* Ray+hit structure for K rays */
+ template<int K>
+ struct RayHitK : RayK<K>
+ {
+ using RayK<K>::org;
+ using RayK<K>::_tnear;
+ using RayK<K>::dir;
+ using RayK<K>::_time;
+ using RayK<K>::tfar;
+ using RayK<K>::mask;
+ using RayK<K>::id;
+ using RayK<K>::flags;
+
+ using RayK<K>::tnear;
+ using RayK<K>::time;
+
+ /* Default construction does nothing */
+ __forceinline RayHitK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline RayHitK(const Vec3vf<K>& org, const Vec3vf<K>& dir,
+ const vfloat<K>& tnear = zero, const vfloat<K>& tfar = inf,
+ const vfloat<K>& time = zero, const vint<K>& mask = -1, const vint<K>& id = 0, const vint<K>& flags = 0)
+ : RayK<K>(org, dir, tnear, tfar, time, mask, id, flags),
+ geomID(RTC_INVALID_GEOMETRY_ID)
+ {
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ instID[l] = RTC_INVALID_GEOMETRY_ID;
+ }
+
+ __forceinline RayHitK(const RayK<K>& ray)
+ : RayK<K>(ray),
+ geomID(RTC_INVALID_GEOMETRY_ID)
+ {
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ instID[l] = RTC_INVALID_GEOMETRY_ID;
+ }
+
+ __forceinline RayHitK<K>& operator =(const RayK<K>& ray)
+ {
+ org = ray.org;
+ _tnear = ray._tnear;
+ dir = ray.dir;
+ _time = ray._time;
+ tfar = ray.tfar;
+ mask = ray.mask;
+ id = ray.id;
+ flags = ray.flags;
+
+ geomID = RTC_INVALID_GEOMETRY_ID;
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ instID[l] = RTC_INVALID_GEOMETRY_ID;
+
+ return *this;
+ }
+
+ /* Calculates if the hit is valid */
+ __forceinline void verifyHit(const vbool<K>& valid0) const
+ {
+ vbool<K> valid = valid0 & geomID != vuint<K>(RTC_INVALID_GEOMETRY_ID);
+ const vbool<K> vt = (abs(tfar) <= vfloat<K>(FLT_LARGE)) | (tfar == vfloat<K>(neg_inf));
+ const vbool<K> vu = (abs(u) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vv = (abs(u) <= vfloat<K>(FLT_LARGE));
+ const vbool<K> vnx = abs(Ng.x) <= vfloat<K>(FLT_LARGE);
+ const vbool<K> vny = abs(Ng.y) <= vfloat<K>(FLT_LARGE);
+ const vbool<K> vnz = abs(Ng.z) <= vfloat<K>(FLT_LARGE);
+ if (any(valid & !vt)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid t");
+ if (any(valid & !vu)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid u");
+ if (any(valid & !vv)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid v");
+ if (any(valid & !vnx)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid Ng.x");
+ if (any(valid & !vny)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid Ng.y");
+ if (any(valid & !vnz)) throw_RTCError(RTC_ERROR_UNKNOWN,"invalid Ng.z");
+ }
+
+ __forceinline void get(RayHitK<1>* ray) const;
+ __forceinline void get(size_t i, RayHitK<1>& ray) const;
+ __forceinline void set(const RayHitK<1>* ray);
+ __forceinline void set(size_t i, const RayHitK<1>& ray);
+
+ __forceinline void copy(size_t dest, size_t source);
+
+ /* Hit data */
+ Vec3vf<K> Ng; // geometry normal
+ vfloat<K> u; // barycentric u coordinate of hit
+ vfloat<K> v; // barycentric v coordinate of hit
+ vuint<K> primID; // primitive ID
+ vuint<K> geomID; // geometry ID
+ vuint<K> instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID
+ };
+
+ /* Specialization for a single ray */
+ template<>
+ struct RayK<1>
+ {
+ /* Default construction does nothing */
+ __forceinline RayK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline RayK(const Vec3fa& org, const Vec3fa& dir, float tnear = zero, float tfar = inf, float time = zero, int mask = -1, int id = 0, int flags = 0)
+ : org(org,tnear), dir(dir,time), tfar(tfar), mask(mask), id(id), flags(flags) {}
+
+ /* Calculates if this is a valid ray that does not cause issues during traversal */
+ __forceinline bool valid() const {
+ return all(le_mask(abs(Vec3fa(org)), Vec3fa(FLT_LARGE)) & le_mask(abs(Vec3fa(dir)), Vec3fa(FLT_LARGE))) && abs(tnear()) <= float(inf) && abs(tfar) <= float(inf);
+ }
+
+ /* Ray data */
+ Vec3ff org; // 3 floats for ray origin, 1 float for tnear
+ //float tnear; // start of ray segment
+ Vec3ff dir; // 3 floats for ray direction, 1 float for time
+ // float time;
+ float tfar; // end of ray segment
+ int mask; // used to mask out objects during traversal
+ int id; // ray ID
+ int flags; // ray flags
+
+ __forceinline float& tnear() { return org.w; };
+ __forceinline const float& tnear() const { return org.w; };
+
+ __forceinline float& time() { return dir.w; };
+ __forceinline const float& time() const { return dir.w; };
+
+ };
+
+ template<>
+ struct RayHitK<1> : RayK<1>
+ {
+ /* Default construction does nothing */
+ __forceinline RayHitK() {}
+
+ /* Constructs a ray from origin, direction, and ray segment. Near
+ * has to be smaller than far */
+ __forceinline RayHitK(const Vec3fa& org, const Vec3fa& dir, float tnear = zero, float tfar = inf, float time = zero, int mask = -1, int id = 0, int flags = 0)
+ : RayK<1>(org, dir, tnear, tfar, time, mask, id, flags),
+ geomID(RTC_INVALID_GEOMETRY_ID) {}
+
+ __forceinline RayHitK(const RayK<1>& ray)
+ : RayK<1>(ray),
+ geomID(RTC_INVALID_GEOMETRY_ID) {}
+
+ __forceinline RayHitK<1>& operator =(const RayK<1>& ray)
+ {
+ org = ray.org;
+ dir = ray.dir;
+ tfar = ray.tfar;
+ mask = ray.mask;
+ id = ray.id;
+ flags = ray.flags;
+
+ geomID = RTC_INVALID_GEOMETRY_ID;
+
+ return *this;
+ }
+
+ /* Calculates if the hit is valid */
+ __forceinline void verifyHit() const
+ {
+ if (geomID == RTC_INVALID_GEOMETRY_ID) return;
+ const bool vt = (abs(tfar) <= FLT_LARGE) || (tfar == float(neg_inf));
+ const bool vu = (abs(u) <= FLT_LARGE);
+ const bool vv = (abs(u) <= FLT_LARGE);
+ const bool vnx = abs(Ng.x) <= FLT_LARGE;
+ const bool vny = abs(Ng.y) <= FLT_LARGE;
+ const bool vnz = abs(Ng.z) <= FLT_LARGE;
+ if (!vt) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid t");
+ if (!vu) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid u");
+ if (!vv) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid v");
+ if (!vnx) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid Ng.x");
+ if (!vny) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid Ng.y");
+ if (!vnz) throw_RTCError(RTC_ERROR_UNKNOWN, "invalid Ng.z");
+ }
+
+ /* Hit data */
+ Vec3f Ng; // not normalized geometry normal
+ float u; // barycentric u coordinate of hit
+ float v; // barycentric v coordinate of hit
+ unsigned int primID; // primitive ID
+ unsigned int geomID; // geometry ID
+ unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID
+ };
+
+ /* Converts ray packet to single rays */
+ template<int K>
+ __forceinline void RayK<K>::get(RayK<1>* ray) const
+ {
+ for (size_t i = 0; i < K; i++) // FIXME: use SIMD transpose
+ {
+ ray[i].org.x = org.x[i]; ray[i].org.y = org.y[i]; ray[i].org.z = org.z[i]; ray[i].tnear() = tnear()[i];
+ ray[i].dir.x = dir.x[i]; ray[i].dir.y = dir.y[i]; ray[i].dir.z = dir.z[i]; ray[i].time() = time()[i];
+ ray[i].tfar = tfar[i]; ray[i].mask = mask[i]; ray[i].id = id[i]; ray[i].flags = flags[i];
+ }
+ }
+
+ template<int K>
+ __forceinline void RayHitK<K>::get(RayHitK<1>* ray) const
+ {
+ // FIXME: use SIMD transpose
+ for (size_t i = 0; i < K; i++)
+ get(i, ray[i]);
+ }
+
+ /* Extracts a single ray out of a ray packet*/
+ template<int K>
+ __forceinline void RayK<K>::get(size_t i, RayK<1>& ray) const
+ {
+ ray.org.x = org.x[i]; ray.org.y = org.y[i]; ray.org.z = org.z[i]; ray.tnear() = tnear()[i];
+ ray.dir.x = dir.x[i]; ray.dir.y = dir.y[i]; ray.dir.z = dir.z[i]; ray.time() = time()[i];
+ ray.tfar = tfar[i]; ray.mask = mask[i]; ray.id = id[i]; ray.flags = flags[i];
+ }
+
+ template<int K>
+ __forceinline void RayHitK<K>::get(size_t i, RayHitK<1>& ray) const
+ {
+ ray.org.x = org.x[i]; ray.org.y = org.y[i]; ray.org.z = org.z[i]; ray.tnear() = tnear()[i];
+ ray.dir.x = dir.x[i]; ray.dir.y = dir.y[i]; ray.dir.z = dir.z[i]; ray.tfar = tfar[i]; ray.time() = time()[i];
+ ray.mask = mask[i]; ray.id = id[i]; ray.flags = flags[i];
+ ray.Ng.x = Ng.x[i]; ray.Ng.y = Ng.y[i]; ray.Ng.z = Ng.z[i];
+ ray.u = u[i]; ray.v = v[i];
+ ray.primID = primID[i]; ray.geomID = geomID[i];
+
+ instance_id_stack::copy_VU<K>(instID, ray.instID, i);
+ }
+
+ /* Converts single rays to ray packet */
+ template<int K>
+ __forceinline void RayK<K>::set(const RayK<1>* ray)
+ {
+ // FIXME: use SIMD transpose
+ for (size_t i = 0; i < K; i++)
+ set(i, ray[i]);
+ }
+
+ template<int K>
+ __forceinline void RayHitK<K>::set(const RayHitK<1>* ray)
+ {
+ // FIXME: use SIMD transpose
+ for (size_t i = 0; i < K; i++)
+ set(i, ray[i]);
+ }
+
+ /* inserts a single ray into a ray packet element */
+ template<int K>
+ __forceinline void RayK<K>::set(size_t i, const RayK<1>& ray)
+ {
+ org.x[i] = ray.org.x; org.y[i] = ray.org.y; org.z[i] = ray.org.z; tnear()[i] = ray.tnear();
+ dir.x[i] = ray.dir.x; dir.y[i] = ray.dir.y; dir.z[i] = ray.dir.z; time()[i] = ray.time();
+ tfar[i] = ray.tfar; mask[i] = ray.mask; id[i] = ray.id; flags[i] = ray.flags;
+ }
+
+ template<int K>
+ __forceinline void RayHitK<K>::set(size_t i, const RayHitK<1>& ray)
+ {
+ org.x[i] = ray.org.x; org.y[i] = ray.org.y; org.z[i] = ray.org.z; tnear()[i] = ray.tnear();
+ dir.x[i] = ray.dir.x; dir.y[i] = ray.dir.y; dir.z[i] = ray.dir.z; time()[i] = ray.time();
+ tfar[i] = ray.tfar; mask[i] = ray.mask; id[i] = ray.id; flags[i] = ray.flags;
+ Ng.x[i] = ray.Ng.x; Ng.y[i] = ray.Ng.y; Ng.z[i] = ray.Ng.z;
+ u[i] = ray.u; v[i] = ray.v;
+ primID[i] = ray.primID; geomID[i] = ray.geomID;
+
+ instance_id_stack::copy_UV<K>(ray.instID, instID, i);
+ }
+
+ /* copies a ray packet element into another element*/
+ template<int K>
+ __forceinline void RayK<K>::copy(size_t dest, size_t source)
+ {
+ org.x[dest] = org.x[source]; org.y[dest] = org.y[source]; org.z[dest] = org.z[source]; tnear()[dest] = tnear()[source];
+ dir.x[dest] = dir.x[source]; dir.y[dest] = dir.y[source]; dir.z[dest] = dir.z[source]; time()[dest] = time()[source];
+ tfar [dest] = tfar[source]; mask[dest] = mask[source]; id[dest] = id[source]; flags[dest] = flags[source];
+ }
+
+ template<int K>
+ __forceinline void RayHitK<K>::copy(size_t dest, size_t source)
+ {
+ org.x[dest] = org.x[source]; org.y[dest] = org.y[source]; org.z[dest] = org.z[source]; tnear()[dest] = tnear()[source];
+ dir.x[dest] = dir.x[source]; dir.y[dest] = dir.y[source]; dir.z[dest] = dir.z[source]; time()[dest] = time()[source];
+ tfar [dest] = tfar[source]; mask[dest] = mask[source]; id[dest] = id[source]; flags[dest] = flags[source];
+ Ng.x[dest] = Ng.x[source]; Ng.y[dest] = Ng.y[source]; Ng.z[dest] = Ng.z[source];
+ u[dest] = u[source]; v[dest] = v[source];
+ primID[dest] = primID[source]; geomID[dest] = geomID[source];
+
+ instance_id_stack::copy_VV<K>(instID, instID, source, dest);
+ }
+
+ /* Shortcuts */
+ typedef RayK<1> Ray;
+ typedef RayK<4> Ray4;
+ typedef RayK<8> Ray8;
+ typedef RayK<16> Ray16;
+ struct RayN;
+
+ typedef RayHitK<1> RayHit;
+ typedef RayHitK<4> RayHit4;
+ typedef RayHitK<8> RayHit8;
+ typedef RayHitK<16> RayHit16;
+ struct RayHitN;
+
+ template<int K, bool intersect>
+ struct RayTypeHelper;
+
+ template<int K>
+ struct RayTypeHelper<K, true>
+ {
+ typedef RayHitK<K> Ty;
+ };
+
+ template<int K>
+ struct RayTypeHelper<K, false>
+ {
+ typedef RayK<K> Ty;
+ };
+
+ template<bool intersect>
+ using RayType = typename RayTypeHelper<1, intersect>::Ty;
+
+ template<int K, bool intersect>
+ using RayTypeK = typename RayTypeHelper<K, intersect>::Ty;
+
+ /* Outputs ray to stream */
+ template<int K>
+ __forceinline embree_ostream operator <<(embree_ostream cout, const RayK<K>& ray)
+ {
+ return cout << "{ " << embree_endl
+ << " org = " << ray.org << embree_endl
+ << " dir = " << ray.dir << embree_endl
+ << " near = " << ray.tnear() << embree_endl
+ << " far = " << ray.tfar << embree_endl
+ << " time = " << ray.time() << embree_endl
+ << " mask = " << ray.mask << embree_endl
+ << " id = " << ray.id << embree_endl
+ << " flags = " << ray.flags << embree_endl
+ << "}";
+ }
+
+ template<int K>
+ __forceinline embree_ostream operator <<(embree_ostream cout, const RayHitK<K>& ray)
+ {
+ cout << "{ " << embree_endl
+ << " org = " << ray.org << embree_endl
+ << " dir = " << ray.dir << embree_endl
+ << " near = " << ray.tnear() << embree_endl
+ << " far = " << ray.tfar << embree_endl
+ << " time = " << ray.time() << embree_endl
+ << " mask = " << ray.mask << embree_endl
+ << " id = " << ray.id << embree_endl
+ << " flags = " << ray.flags << embree_endl
+ << " Ng = " << ray.Ng
+ << " u = " << ray.u << embree_endl
+ << " v = " << ray.v << embree_endl
+ << " primID = " << ray.primID << embree_endl
+ << " geomID = " << ray.geomID << embree_endl
+ << " instID =";
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ {
+ cout << " " << ray.instID[l];
+ }
+ cout << embree_endl;
+ return cout << "}";
+ }
+
+ struct RayStreamSOA
+ {
+ __forceinline RayStreamSOA(void* rays, size_t N)
+ : ptr((char*)rays), N(N) {}
+
+ /* ray data access functions */
+ __forceinline float* org_x(size_t offset = 0) { return (float*)&ptr[0*4*N+offset]; } // x coordinate of ray origin
+ __forceinline float* org_y(size_t offset = 0) { return (float*)&ptr[1*4*N+offset]; } // y coordinate of ray origin
+ __forceinline float* org_z(size_t offset = 0) { return (float*)&ptr[2*4*N+offset]; }; // z coordinate of ray origin
+ __forceinline float* tnear(size_t offset = 0) { return (float*)&ptr[3*4*N+offset]; }; // start of ray segment
+
+ __forceinline float* dir_x(size_t offset = 0) { return (float*)&ptr[4*4*N+offset]; }; // x coordinate of ray direction
+ __forceinline float* dir_y(size_t offset = 0) { return (float*)&ptr[5*4*N+offset]; }; // y coordinate of ray direction
+ __forceinline float* dir_z(size_t offset = 0) { return (float*)&ptr[6*4*N+offset]; }; // z coordinate of ray direction
+ __forceinline float* time (size_t offset = 0) { return (float*)&ptr[7*4*N+offset]; }; // time of this ray for motion blur
+
+ __forceinline float* tfar (size_t offset = 0) { return (float*)&ptr[8*4*N+offset]; }; // end of ray segment (set to hit distance)
+ __forceinline int* mask (size_t offset = 0) { return (int*)&ptr[9*4*N+offset]; }; // used to mask out objects during traversal (optional)
+ __forceinline int* id (size_t offset = 0) { return (int*)&ptr[10*4*N+offset]; }; // id
+ __forceinline int* flags(size_t offset = 0) { return (int*)&ptr[11*4*N+offset]; }; // flags
+
+ /* hit data access functions */
+ __forceinline float* Ng_x(size_t offset = 0) { return (float*)&ptr[12*4*N+offset]; }; // x coordinate of geometry normal
+ __forceinline float* Ng_y(size_t offset = 0) { return (float*)&ptr[13*4*N+offset]; }; // y coordinate of geometry normal
+ __forceinline float* Ng_z(size_t offset = 0) { return (float*)&ptr[14*4*N+offset]; }; // z coordinate of geometry normal
+
+ __forceinline float* u(size_t offset = 0) { return (float*)&ptr[15*4*N+offset]; }; // barycentric u coordinate of hit
+ __forceinline float* v(size_t offset = 0) { return (float*)&ptr[16*4*N+offset]; }; // barycentric v coordinate of hit
+
+ __forceinline unsigned int* primID(size_t offset = 0) { return (unsigned int*)&ptr[17*4*N+offset]; }; // primitive ID
+ __forceinline unsigned int* geomID(size_t offset = 0) { return (unsigned int*)&ptr[18*4*N+offset]; }; // geometry ID
+ __forceinline unsigned int* instID(size_t level, size_t offset = 0) { return (unsigned int*)&ptr[19*4*N+level*4*N+offset]; }; // instance ID
+
+ __forceinline Ray getRayByOffset(size_t offset)
+ {
+ Ray ray;
+ ray.org.x = org_x(offset)[0];
+ ray.org.y = org_y(offset)[0];
+ ray.org.z = org_z(offset)[0];
+ ray.tnear() = tnear(offset)[0];
+ ray.dir.x = dir_x(offset)[0];
+ ray.dir.y = dir_y(offset)[0];
+ ray.dir.z = dir_z(offset)[0];
+ ray.time() = time(offset)[0];
+ ray.tfar = tfar(offset)[0];
+ ray.mask = mask(offset)[0];
+ ray.id = id(offset)[0];
+ ray.flags = flags(offset)[0];
+ return ray;
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(size_t offset)
+ {
+ RayK<K> ray;
+ ray.org.x = vfloat<K>::loadu(org_x(offset));
+ ray.org.y = vfloat<K>::loadu(org_y(offset));
+ ray.org.z = vfloat<K>::loadu(org_z(offset));
+ ray.tnear = vfloat<K>::loadu(tnear(offset));
+ ray.dir.x = vfloat<K>::loadu(dir_x(offset));
+ ray.dir.y = vfloat<K>::loadu(dir_y(offset));
+ ray.dir.z = vfloat<K>::loadu(dir_z(offset));
+ ray.time = vfloat<K>::loadu(time(offset));
+ ray.tfar = vfloat<K>::loadu(tfar(offset));
+ ray.mask = vint<K>::loadu(mask(offset));
+ ray.id = vint<K>::loadu(id(offset));
+ ray.flags = vint<K>::loadu(flags(offset));
+ return ray;
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vbool<K>& valid, size_t offset)
+ {
+ RayK<K> ray;
+ ray.org.x = vfloat<K>::loadu(valid, org_x(offset));
+ ray.org.y = vfloat<K>::loadu(valid, org_y(offset));
+ ray.org.z = vfloat<K>::loadu(valid, org_z(offset));
+ ray.tnear() = vfloat<K>::loadu(valid, tnear(offset));
+ ray.dir.x = vfloat<K>::loadu(valid, dir_x(offset));
+ ray.dir.y = vfloat<K>::loadu(valid, dir_y(offset));
+ ray.dir.z = vfloat<K>::loadu(valid, dir_z(offset));
+ ray.time() = vfloat<K>::loadu(valid, time(offset));
+ ray.tfar = vfloat<K>::loadu(valid, tfar(offset));
+
+#if !defined(__AVX__)
+ /* SSE: some ray members must be loaded with scalar instructions to ensure that we don't cause memory faults,
+ because the SSE masked loads always access the entire vector */
+ if (unlikely(!all(valid)))
+ {
+ ray.mask = zero;
+ ray.id = zero;
+ ray.flags = zero;
+
+ for (size_t k = 0; k < K; k++)
+ {
+ if (likely(valid[k]))
+ {
+ ray.mask[k] = mask(offset)[k];
+ ray.id[k] = id(offset)[k];
+ ray.flags[k] = flags(offset)[k];
+ }
+ }
+ }
+ else
+#endif
+ {
+ ray.mask = vint<K>::loadu(valid, mask(offset));
+ ray.id = vint<K>::loadu(valid, id(offset));
+ ray.flags = vint<K>::loadu(valid, flags(offset));
+ }
+
+ return ray;
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, size_t offset, const RayHitK<K>& ray)
+ {
+ /*
+ * valid_i: stores which of the input rays exist (do not access nonexistent rays!)
+ * valid: stores which of the rays actually hit something.
+ */
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+ vfloat<K>::storeu(valid, tfar(offset), ray.tfar);
+ vfloat<K>::storeu(valid, Ng_x(offset), ray.Ng.x);
+ vfloat<K>::storeu(valid, Ng_y(offset), ray.Ng.y);
+ vfloat<K>::storeu(valid, Ng_z(offset), ray.Ng.z);
+ vfloat<K>::storeu(valid, u(offset), ray.u);
+ vfloat<K>::storeu(valid, v(offset), ray.v);
+
+#if !defined(__AVX__)
+ /* SSE: some ray members must be stored with scalar instructions to ensure that we don't cause memory faults,
+ because the SSE masked stores always access the entire vector */
+ if (unlikely(!all(valid_i)))
+ {
+ for (size_t k = 0; k < K; k++)
+ {
+ if (likely(valid[k]))
+ {
+ primID(offset)[k] = ray.primID[k];
+ geomID(offset)[k] = ray.geomID[k];
+
+ instID(0, offset)[k] = ray.instID[0][k];
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l)
+ instID(l, offset)[k] = ray.instID[l][k];
+#endif
+ }
+ }
+ }
+ else
+#endif
+ {
+ vuint<K>::storeu(valid, primID(offset), ray.primID);
+ vuint<K>::storeu(valid, geomID(offset), ray.geomID);
+
+ vuint<K>::storeu(valid, instID(0, offset), ray.instID[0]);
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l)
+ vuint<K>::storeu(valid, instID(l, offset), ray.instID[l]);
+#endif
+ }
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, size_t offset, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ vfloat<K>::storeu(valid, tfar(offset), ray.tfar);
+ }
+
+ __forceinline size_t getOctantByOffset(size_t offset)
+ {
+ const float dx = dir_x(offset)[0];
+ const float dy = dir_y(offset)[0];
+ const float dz = dir_z(offset)[0];
+ const size_t octantID = (dx < 0.0f ? 1 : 0) + (dy < 0.0f ? 2 : 0) + (dz < 0.0f ? 4 : 0);
+ return octantID;
+ }
+
+ __forceinline bool isValidByOffset(size_t offset)
+ {
+ const float nnear = tnear(offset)[0];
+ const float ffar = tfar(offset)[0];
+ return nnear <= ffar;
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vbool<K>& valid, const vint<K>& offset)
+ {
+ RayK<K> ray;
+
+#if defined(__AVX2__)
+ ray.org.x = vfloat<K>::template gather<1>(valid, org_x(), offset);
+ ray.org.y = vfloat<K>::template gather<1>(valid, org_y(), offset);
+ ray.org.z = vfloat<K>::template gather<1>(valid, org_z(), offset);
+ ray.tnear() = vfloat<K>::template gather<1>(valid, tnear(), offset);
+ ray.dir.x = vfloat<K>::template gather<1>(valid, dir_x(), offset);
+ ray.dir.y = vfloat<K>::template gather<1>(valid, dir_y(), offset);
+ ray.dir.z = vfloat<K>::template gather<1>(valid, dir_z(), offset);
+ ray.time() = vfloat<K>::template gather<1>(valid, time(), offset);
+ ray.tfar = vfloat<K>::template gather<1>(valid, tfar(), offset);
+ ray.mask = vint<K>::template gather<1>(valid, mask(), offset);
+ ray.id = vint<K>::template gather<1>(valid, id(), offset);
+ ray.flags = vint<K>::template gather<1>(valid, flags(), offset);
+#else
+ ray.org = zero;
+ ray.tnear() = zero;
+ ray.dir = zero;
+ ray.time() = zero;
+ ray.tfar = zero;
+ ray.mask = zero;
+ ray.id = zero;
+ ray.flags = zero;
+
+ for (size_t k = 0; k < K; k++)
+ {
+ if (likely(valid[k]))
+ {
+ const size_t ofs = offset[k];
+
+ ray.org.x[k] = *org_x(ofs);
+ ray.org.y[k] = *org_y(ofs);
+ ray.org.z[k] = *org_z(ofs);
+ ray.tnear()[k] = *tnear(ofs);
+ ray.dir.x[k] = *dir_x(ofs);
+ ray.dir.y[k] = *dir_y(ofs);
+ ray.dir.z[k] = *dir_z(ofs);
+ ray.time()[k] = *time(ofs);
+ ray.tfar[k] = *tfar(ofs);
+ ray.mask[k] = *mask(ofs);
+ ray.id[k] = *id(ofs);
+ ray.flags[k] = *flags(ofs);
+ }
+ }
+#endif
+
+ return ray;
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayHitK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, tfar(), offset, ray.tfar);
+ vfloat<K>::template scatter<1>(valid, Ng_x(), offset, ray.Ng.x);
+ vfloat<K>::template scatter<1>(valid, Ng_y(), offset, ray.Ng.y);
+ vfloat<K>::template scatter<1>(valid, Ng_z(), offset, ray.Ng.z);
+ vfloat<K>::template scatter<1>(valid, u(), offset, ray.u);
+ vfloat<K>::template scatter<1>(valid, v(), offset, ray.v);
+ vuint<K>::template scatter<1>(valid, primID(), offset, ray.primID);
+ vuint<K>::template scatter<1>(valid, geomID(), offset, ray.geomID);
+
+ vuint<K>::template scatter<1>(valid, instID(0), offset, ray.instID[0]);
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l)
+ vuint<K>::template scatter<1>(valid, instID(l), offset, ray.instID[l]);
+#endif
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ const size_t ofs = offset[k];
+
+ *tfar(ofs) = ray.tfar[k];
+
+ *Ng_x(ofs) = ray.Ng.x[k];
+ *Ng_y(ofs) = ray.Ng.y[k];
+ *Ng_z(ofs) = ray.Ng.z[k];
+ *u(ofs) = ray.u[k];
+ *v(ofs) = ray.v[k];
+ *primID(ofs) = ray.primID[k];
+ *geomID(ofs) = ray.geomID[k];
+
+ *instID(0, ofs) = ray.instID[0][k];
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l)
+ *instID(l, ofs) = ray.instID[l][k];
+#endif
+ }
+#endif
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, tfar(), offset, ray.tfar);
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ const size_t ofs = offset[k];
+
+ *tfar(ofs) = ray.tfar[k];
+ }
+#endif
+ }
+ }
+
+ char* __restrict__ ptr;
+ size_t N;
+ };
+
+ template<size_t MAX_K>
+ struct StackRayStreamSOA : public RayStreamSOA
+ {
+ __forceinline StackRayStreamSOA(size_t K)
+ : RayStreamSOA(data, K) { assert(K <= MAX_K); }
+
+ char data[MAX_K / 4 * sizeof(RayHit4)];
+ };
+
+
+ struct RayStreamSOP
+ {
+ template<class T>
+ __forceinline void init(T& t)
+ {
+ org_x = (float*)&t.org.x;
+ org_y = (float*)&t.org.y;
+ org_z = (float*)&t.org.z;
+ tnear = (float*)&t.tnear;
+ dir_x = (float*)&t.dir.x;
+ dir_y = (float*)&t.dir.y;
+ dir_z = (float*)&t.dir.z;
+ time = (float*)&t.time;
+ tfar = (float*)&t.tfar;
+ mask = (unsigned int*)&t.mask;
+ id = (unsigned int*)&t.id;
+ flags = (unsigned int*)&t.flags;
+
+ Ng_x = (float*)&t.Ng.x;
+ Ng_y = (float*)&t.Ng.y;
+ Ng_z = (float*)&t.Ng.z;
+ u = (float*)&t.u;
+ v = (float*)&t.v;
+ primID = (unsigned int*)&t.primID;
+ geomID = (unsigned int*)&t.geomID;
+
+ for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l)
+ instID[l] = (unsigned int*)&t.instID[l];
+ }
+
+ __forceinline Ray getRayByOffset(size_t offset)
+ {
+ Ray ray;
+ ray.org.x = *(float* __restrict__)((char*)org_x + offset);
+ ray.org.y = *(float* __restrict__)((char*)org_y + offset);
+ ray.org.z = *(float* __restrict__)((char*)org_z + offset);
+ ray.dir.x = *(float* __restrict__)((char*)dir_x + offset);
+ ray.dir.y = *(float* __restrict__)((char*)dir_y + offset);
+ ray.dir.z = *(float* __restrict__)((char*)dir_z + offset);
+ ray.tfar = *(float* __restrict__)((char*)tfar + offset);
+ ray.tnear() = tnear ? *(float* __restrict__)((char*)tnear + offset) : 0.0f;
+ ray.time() = time ? *(float* __restrict__)((char*)time + offset) : 0.0f;
+ ray.mask = mask ? *(unsigned int* __restrict__)((char*)mask + offset) : -1;
+ ray.id = id ? *(unsigned int* __restrict__)((char*)id + offset) : -1;
+ ray.flags = flags ? *(unsigned int* __restrict__)((char*)flags + offset) : -1;
+ return ray;
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vbool<K>& valid, size_t offset)
+ {
+ RayK<K> ray;
+ ray.org.x = vfloat<K>::loadu(valid, (float* __restrict__)((char*)org_x + offset));
+ ray.org.y = vfloat<K>::loadu(valid, (float* __restrict__)((char*)org_y + offset));
+ ray.org.z = vfloat<K>::loadu(valid, (float* __restrict__)((char*)org_z + offset));
+ ray.dir.x = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_x + offset));
+ ray.dir.y = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_y + offset));
+ ray.dir.z = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_z + offset));
+ ray.tfar = vfloat<K>::loadu(valid, (float* __restrict__)((char*)tfar + offset));
+ ray.tnear() = tnear ? vfloat<K>::loadu(valid, (float* __restrict__)((char*)tnear + offset)) : 0.0f;
+ ray.time() = time ? vfloat<K>::loadu(valid, (float* __restrict__)((char*)time + offset)) : 0.0f;
+ ray.mask = mask ? vint<K>::loadu(valid, (const void* __restrict__)((char*)mask + offset)) : -1;
+ ray.id = id ? vint<K>::loadu(valid, (const void* __restrict__)((char*)id + offset)) : -1;
+ ray.flags = flags ? vint<K>::loadu(valid, (const void* __restrict__)((char*)flags + offset)) : -1;
+ return ray;
+ }
+
+ template<int K>
+ __forceinline Vec3vf<K> getDirByOffset(const vbool<K>& valid, size_t offset)
+ {
+ Vec3vf<K> dir;
+ dir.x = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_x + offset));
+ dir.y = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_y + offset));
+ dir.z = vfloat<K>::loadu(valid, (float* __restrict__)((char*)dir_z + offset));
+ return dir;
+ }
+
+ __forceinline void setHitByOffset(size_t offset, const RayHit& ray)
+ {
+ if (ray.geomID != RTC_INVALID_GEOMETRY_ID)
+ {
+ *(float* __restrict__)((char*)tfar + offset) = ray.tfar;
+
+ if (likely(Ng_x)) *(float* __restrict__)((char*)Ng_x + offset) = ray.Ng.x;
+ if (likely(Ng_y)) *(float* __restrict__)((char*)Ng_y + offset) = ray.Ng.y;
+ if (likely(Ng_z)) *(float* __restrict__)((char*)Ng_z + offset) = ray.Ng.z;
+ *(float* __restrict__)((char*)u + offset) = ray.u;
+ *(float* __restrict__)((char*)v + offset) = ray.v;
+ *(unsigned int* __restrict__)((char*)geomID + offset) = ray.geomID;
+ *(unsigned int* __restrict__)((char*)primID + offset) = ray.primID;
+
+ if (likely(instID[0])) {
+ *(unsigned int* __restrict__)((char*)instID[0] + offset) = ray.instID[0];
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID; ++l)
+ *(unsigned int* __restrict__)((char*)instID[l] + offset) = ray.instID[l];
+#endif
+ }
+ }
+ }
+
+ __forceinline void setHitByOffset(size_t offset, const Ray& ray)
+ {
+ *(float* __restrict__)((char*)tfar + offset) = ray.tfar;
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, size_t offset, const RayHitK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+ vfloat<K>::storeu(valid, (float* __restrict__)((char*)tfar + offset), ray.tfar);
+
+ if (likely(Ng_x)) vfloat<K>::storeu(valid, (float* __restrict__)((char*)Ng_x + offset), ray.Ng.x);
+ if (likely(Ng_y)) vfloat<K>::storeu(valid, (float* __restrict__)((char*)Ng_y + offset), ray.Ng.y);
+ if (likely(Ng_z)) vfloat<K>::storeu(valid, (float* __restrict__)((char*)Ng_z + offset), ray.Ng.z);
+ vfloat<K>::storeu(valid, (float* __restrict__)((char*)u + offset), ray.u);
+ vfloat<K>::storeu(valid, (float* __restrict__)((char*)v + offset), ray.v);
+ vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)primID + offset), ray.primID);
+ vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)geomID + offset), ray.geomID);
+
+ if (likely(instID[0])) {
+ vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)instID[0] + offset), ray.instID[0]);
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l)
+ vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)instID[l] + offset), ray.instID[l]);
+#endif
+ }
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, size_t offset, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ vfloat<K>::storeu(valid, (float* __restrict__)((char*)tfar + offset), ray.tfar);
+ }
+
+ __forceinline size_t getOctantByOffset(size_t offset)
+ {
+ const float dx = *(float* __restrict__)((char*)dir_x + offset);
+ const float dy = *(float* __restrict__)((char*)dir_y + offset);
+ const float dz = *(float* __restrict__)((char*)dir_z + offset);
+ const size_t octantID = (dx < 0.0f ? 1 : 0) + (dy < 0.0f ? 2 : 0) + (dz < 0.0f ? 4 : 0);
+ return octantID;
+ }
+
+ __forceinline bool isValidByOffset(size_t offset)
+ {
+ const float nnear = tnear ? *(float* __restrict__)((char*)tnear + offset) : 0.0f;
+ const float ffar = *(float* __restrict__)((char*)tfar + offset);
+ return nnear <= ffar;
+ }
+
+ template<int K>
+ __forceinline vbool<K> isValidByOffset(const vbool<K>& valid, size_t offset)
+ {
+ const vfloat<K> nnear = tnear ? vfloat<K>::loadu(valid, (float* __restrict__)((char*)tnear + offset)) : 0.0f;
+ const vfloat<K> ffar = vfloat<K>::loadu(valid, (float* __restrict__)((char*)tfar + offset));
+ return nnear <= ffar;
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vbool<K>& valid, const vint<K>& offset)
+ {
+ RayK<K> ray;
+
+#if defined(__AVX2__)
+ ray.org.x = vfloat<K>::template gather<1>(valid, org_x, offset);
+ ray.org.y = vfloat<K>::template gather<1>(valid, org_y, offset);
+ ray.org.z = vfloat<K>::template gather<1>(valid, org_z, offset);
+ ray.dir.x = vfloat<K>::template gather<1>(valid, dir_x, offset);
+ ray.dir.y = vfloat<K>::template gather<1>(valid, dir_y, offset);
+ ray.dir.z = vfloat<K>::template gather<1>(valid, dir_z, offset);
+ ray.tfar = vfloat<K>::template gather<1>(valid, tfar, offset);
+ ray.tnear() = tnear ? vfloat<K>::template gather<1>(valid, tnear, offset) : vfloat<K>(zero);
+ ray.time() = time ? vfloat<K>::template gather<1>(valid, time, offset) : vfloat<K>(zero);
+ ray.mask = mask ? vint<K>::template gather<1>(valid, (int*)mask, offset) : vint<K>(-1);
+ ray.id = id ? vint<K>::template gather<1>(valid, (int*)id, offset) : vint<K>(-1);
+ ray.flags = flags ? vint<K>::template gather<1>(valid, (int*)flags, offset) : vint<K>(-1);
+#else
+ ray.org = zero;
+ ray.tnear() = zero;
+ ray.dir = zero;
+ ray.tfar = zero;
+ ray.time() = zero;
+ ray.mask = zero;
+ ray.id = zero;
+ ray.flags = zero;
+
+ for (size_t k = 0; k < K; k++)
+ {
+ if (likely(valid[k]))
+ {
+ const size_t ofs = offset[k];
+
+ ray.org.x[k] = *(float* __restrict__)((char*)org_x + ofs);
+ ray.org.y[k] = *(float* __restrict__)((char*)org_y + ofs);
+ ray.org.z[k] = *(float* __restrict__)((char*)org_z + ofs);
+ ray.dir.x[k] = *(float* __restrict__)((char*)dir_x + ofs);
+ ray.dir.y[k] = *(float* __restrict__)((char*)dir_y + ofs);
+ ray.dir.z[k] = *(float* __restrict__)((char*)dir_z + ofs);
+ ray.tfar[k] = *(float* __restrict__)((char*)tfar + ofs);
+ ray.tnear()[k] = tnear ? *(float* __restrict__)((char*)tnear + ofs) : 0.0f;
+ ray.time()[k] = time ? *(float* __restrict__)((char*)time + ofs) : 0.0f;
+ ray.mask[k] = mask ? *(int* __restrict__)((char*)mask + ofs) : -1;
+ ray.id[k] = id ? *(int* __restrict__)((char*)id + ofs) : -1;
+ ray.flags[k] = flags ? *(int* __restrict__)((char*)flags + ofs) : -1;
+ }
+ }
+#endif
+
+ return ray;
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayHitK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, tfar, offset, ray.tfar);
+
+ if (likely(Ng_x)) vfloat<K>::template scatter<1>(valid, Ng_x, offset, ray.Ng.x);
+ if (likely(Ng_y)) vfloat<K>::template scatter<1>(valid, Ng_y, offset, ray.Ng.y);
+ if (likely(Ng_z)) vfloat<K>::template scatter<1>(valid, Ng_z, offset, ray.Ng.z);
+ vfloat<K>::template scatter<1>(valid, u, offset, ray.u);
+ vfloat<K>::template scatter<1>(valid, v, offset, ray.v);
+ vuint<K>::template scatter<1>(valid, (unsigned int*)geomID, offset, ray.geomID);
+ vuint<K>::template scatter<1>(valid, (unsigned int*)primID, offset, ray.primID);
+
+ if (likely(instID[0])) {
+ vuint<K>::template scatter<1>(valid, (unsigned int*)instID[0], offset, ray.instID[0]);
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l)
+ vuint<K>::template scatter<1>(valid, (unsigned int*)instID[l], offset, ray.instID[l]);
+#endif
+ }
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ const size_t ofs = offset[k];
+
+ *(float* __restrict__)((char*)tfar + ofs) = ray.tfar[k];
+
+ if (likely(Ng_x)) *(float* __restrict__)((char*)Ng_x + ofs) = ray.Ng.x[k];
+ if (likely(Ng_y)) *(float* __restrict__)((char*)Ng_y + ofs) = ray.Ng.y[k];
+ if (likely(Ng_z)) *(float* __restrict__)((char*)Ng_z + ofs) = ray.Ng.z[k];
+ *(float* __restrict__)((char*)u + ofs) = ray.u[k];
+ *(float* __restrict__)((char*)v + ofs) = ray.v[k];
+ *(unsigned int* __restrict__)((char*)primID + ofs) = ray.primID[k];
+ *(unsigned int* __restrict__)((char*)geomID + ofs) = ray.geomID[k];
+
+ if (likely(instID[0])) {
+ *(unsigned int* __restrict__)((char*)instID[0] + ofs) = ray.instID[0][k];
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l)
+ *(unsigned int* __restrict__)((char*)instID[l] + ofs) = ray.instID[l][k];
+#endif
+ }
+ }
+#endif
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, tfar, offset, ray.tfar);
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ const size_t ofs = offset[k];
+
+ *(float* __restrict__)((char*)tfar + ofs) = ray.tfar[k];
+ }
+#endif
+ }
+ }
+
+ /* ray data */
+ float* __restrict__ org_x; // x coordinate of ray origin
+ float* __restrict__ org_y; // y coordinate of ray origin
+ float* __restrict__ org_z; // z coordinate of ray origin
+ float* __restrict__ tnear; // start of ray segment (optional)
+
+ float* __restrict__ dir_x; // x coordinate of ray direction
+ float* __restrict__ dir_y; // y coordinate of ray direction
+ float* __restrict__ dir_z; // z coordinate of ray direction
+ float* __restrict__ time; // time of this ray for motion blur (optional)
+
+ float* __restrict__ tfar; // end of ray segment (set to hit distance)
+ unsigned int* __restrict__ mask; // used to mask out objects during traversal (optional)
+ unsigned int* __restrict__ id; // ray ID
+ unsigned int* __restrict__ flags; // ray flags
+
+ /* hit data */
+ float* __restrict__ Ng_x; // x coordinate of geometry normal (optional)
+ float* __restrict__ Ng_y; // y coordinate of geometry normal (optional)
+ float* __restrict__ Ng_z; // z coordinate of geometry normal (optional)
+
+ float* __restrict__ u; // barycentric u coordinate of hit
+ float* __restrict__ v; // barycentric v coordinate of hit
+
+ unsigned int* __restrict__ primID; // primitive ID
+ unsigned int* __restrict__ geomID; // geometry ID
+ unsigned int* __restrict__ instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID (optional)
+ };
+
+
+ struct RayStreamAOS
+ {
+ __forceinline RayStreamAOS(void* rays)
+ : ptr((Ray*)rays) {}
+
+ __forceinline Ray& getRayByOffset(size_t offset)
+ {
+ return *(Ray*)((char*)ptr + offset);
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vint<K>& offset);
+
+ template<int K>
+ __forceinline RayK<K> getRayByOffset(const vbool<K>& valid, const vint<K>& offset)
+ {
+ const vint<K> valid_offset = select(valid, offset, vintx(zero));
+ return getRayByOffset<K>(valid_offset);
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayHitK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, &ptr->tfar, offset, ray.tfar);
+ vfloat<K>::template scatter<1>(valid, &((RayHit*)ptr)->Ng.x, offset, ray.Ng.x);
+ vfloat<K>::template scatter<1>(valid, &((RayHit*)ptr)->Ng.y, offset, ray.Ng.y);
+ vfloat<K>::template scatter<1>(valid, &((RayHit*)ptr)->Ng.z, offset, ray.Ng.z);
+ vfloat<K>::template scatter<1>(valid, &((RayHit*)ptr)->u, offset, ray.u);
+ vfloat<K>::template scatter<1>(valid, &((RayHit*)ptr)->v, offset, ray.v);
+ vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->primID, offset, ray.primID);
+ vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->geomID, offset, ray.geomID);
+
+ vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->instID[0], offset, ray.instID[0]);
+#if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1)
+ for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l)
+ vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->instID[l], offset, ray.instID[l]);
+#endif
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ RayHit* __restrict__ ray_k = (RayHit*)((char*)ptr + offset[k]);
+ ray_k->tfar = ray.tfar[k];
+ ray_k->Ng.x = ray.Ng.x[k];
+ ray_k->Ng.y = ray.Ng.y[k];
+ ray_k->Ng.z = ray.Ng.z[k];
+ ray_k->u = ray.u[k];
+ ray_k->v = ray.v[k];
+ ray_k->primID = ray.primID[k];
+ ray_k->geomID = ray.geomID[k];
+
+ instance_id_stack::copy_VU<K>(ray.instID, ray_k->instID, k);
+ }
+#endif
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByOffset(const vbool<K>& valid_i, const vint<K>& offset, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ {
+#if defined(__AVX512F__)
+ vfloat<K>::template scatter<1>(valid, &ptr->tfar, offset, ray.tfar);
+#else
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ Ray* __restrict__ ray_k = (Ray*)((char*)ptr + offset[k]);
+ ray_k->tfar = ray.tfar[k];
+ }
+#endif
+ }
+ }
+
+ Ray* __restrict__ ptr;
+ };
+
+ template<>
+ __forceinline Ray4 RayStreamAOS::getRayByOffset<4>(const vint4& offset)
+ {
+ Ray4 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear */
+ const vfloat4 a0 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[0]))->org);
+ const vfloat4 a1 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[1]))->org);
+ const vfloat4 a2 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[2]))->org);
+ const vfloat4 a3 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[3]))->org);
+
+ transpose(a0,a1,a2,a3, ray.org.x, ray.org.y, ray.org.z, ray.tnear());
+
+ /* load and transpose: dir.x, dir.y, dir.z, time */
+ const vfloat4 b0 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[0]))->dir);
+ const vfloat4 b1 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[1]))->dir);
+ const vfloat4 b2 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[2]))->dir);
+ const vfloat4 b3 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[3]))->dir);
+
+ transpose(b0,b1,b2,b3, ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[0]))->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[1]))->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[2]))->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[3]))->tfar);
+
+ vfloat4 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3, ray.tfar, maskf, idf, flagsf);
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+
+#if defined(__AVX__)
+ template<>
+ __forceinline Ray8 RayStreamAOS::getRayByOffset<8>(const vint8& offset)
+ {
+ Ray8 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear, dir.x, dir.y, dir.z, time */
+ const vfloat8 ab0 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[0]))->org);
+ const vfloat8 ab1 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[1]))->org);
+ const vfloat8 ab2 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[2]))->org);
+ const vfloat8 ab3 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[3]))->org);
+ const vfloat8 ab4 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[4]))->org);
+ const vfloat8 ab5 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[5]))->org);
+ const vfloat8 ab6 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[6]))->org);
+ const vfloat8 ab7 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[7]))->org);
+
+ transpose(ab0,ab1,ab2,ab3,ab4,ab5,ab6,ab7, ray.org.x, ray.org.y, ray.org.z, ray.tnear(), ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[0]))->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[1]))->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[2]))->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[3]))->tfar);
+ const vfloat4 c4 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[4]))->tfar);
+ const vfloat4 c5 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[5]))->tfar);
+ const vfloat4 c6 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[6]))->tfar);
+ const vfloat4 c7 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[7]))->tfar);
+
+ vfloat8 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3,c4,c5,c6,c7, ray.tfar, maskf, idf, flagsf);
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+#endif
+
+#if defined(__AVX512F__)
+ template<>
+ __forceinline Ray16 RayStreamAOS::getRayByOffset<16>(const vint16& offset)
+ {
+ Ray16 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear, dir.x, dir.y, dir.z, time */
+ const vfloat8 ab0 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 0]))->org);
+ const vfloat8 ab1 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 1]))->org);
+ const vfloat8 ab2 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 2]))->org);
+ const vfloat8 ab3 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 3]))->org);
+ const vfloat8 ab4 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 4]))->org);
+ const vfloat8 ab5 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 5]))->org);
+ const vfloat8 ab6 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 6]))->org);
+ const vfloat8 ab7 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 7]))->org);
+ const vfloat8 ab8 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 8]))->org);
+ const vfloat8 ab9 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[ 9]))->org);
+ const vfloat8 ab10 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[10]))->org);
+ const vfloat8 ab11 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[11]))->org);
+ const vfloat8 ab12 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[12]))->org);
+ const vfloat8 ab13 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[13]))->org);
+ const vfloat8 ab14 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[14]))->org);
+ const vfloat8 ab15 = vfloat8::loadu(&((Ray*)((char*)ptr + offset[15]))->org);
+
+ transpose(ab0,ab1,ab2,ab3,ab4,ab5,ab6,ab7,ab8,ab9,ab10,ab11,ab12,ab13,ab14,ab15,
+ ray.org.x, ray.org.y, ray.org.z, ray.tnear(), ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 0]))->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 1]))->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 2]))->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 3]))->tfar);
+ const vfloat4 c4 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 4]))->tfar);
+ const vfloat4 c5 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 5]))->tfar);
+ const vfloat4 c6 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 6]))->tfar);
+ const vfloat4 c7 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 7]))->tfar);
+ const vfloat4 c8 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 8]))->tfar);
+ const vfloat4 c9 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[ 9]))->tfar);
+ const vfloat4 c10 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[10]))->tfar);
+ const vfloat4 c11 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[11]))->tfar);
+ const vfloat4 c12 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[12]))->tfar);
+ const vfloat4 c13 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[13]))->tfar);
+ const vfloat4 c14 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[14]))->tfar);
+ const vfloat4 c15 = vfloat4::loadu(&((Ray*)((char*)ptr + offset[15]))->tfar);
+
+ vfloat16 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,
+ ray.tfar, maskf, idf, flagsf);
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+#endif
+
+
+ struct RayStreamAOP
+ {
+ __forceinline RayStreamAOP(void* rays)
+ : ptr((Ray**)rays) {}
+
+ __forceinline Ray& getRayByIndex(size_t index)
+ {
+ return *ptr[index];
+ }
+
+ template<int K>
+ __forceinline RayK<K> getRayByIndex(const vint<K>& index);
+
+ template<int K>
+ __forceinline RayK<K> getRayByIndex(const vbool<K>& valid, const vint<K>& index)
+ {
+ const vint<K> valid_index = select(valid, index, vintx(zero));
+ return getRayByIndex<K>(valid_index);
+ }
+
+ template<int K>
+ __forceinline void setHitByIndex(const vbool<K>& valid_i, const vint<K>& index, const RayHitK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.geomID != RTC_INVALID_GEOMETRY_ID);
+
+ if (likely(any(valid)))
+ {
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ RayHit* __restrict__ ray_k = (RayHit*)ptr[index[k]];
+
+ ray_k->tfar = ray.tfar[k];
+ ray_k->Ng.x = ray.Ng.x[k];
+ ray_k->Ng.y = ray.Ng.y[k];
+ ray_k->Ng.z = ray.Ng.z[k];
+ ray_k->u = ray.u[k];
+ ray_k->v = ray.v[k];
+ ray_k->primID = ray.primID[k];
+ ray_k->geomID = ray.geomID[k];
+ instance_id_stack::copy_VU<K>(ray.instID, ray_k->instID, k);
+ }
+ }
+ }
+
+ template<int K>
+ __forceinline void setHitByIndex(const vbool<K>& valid_i, const vint<K>& index, const RayK<K>& ray)
+ {
+ vbool<K> valid = valid_i;
+ valid &= (ray.tfar < 0.0f);
+
+ if (likely(any(valid)))
+ {
+ size_t valid_bits = movemask(valid);
+ while (valid_bits != 0)
+ {
+ const size_t k = bscf(valid_bits);
+ Ray* __restrict__ ray_k = ptr[index[k]];
+
+ ray_k->tfar = ray.tfar[k];
+ }
+ }
+ }
+
+ Ray** __restrict__ ptr;
+ };
+
+ template<>
+ __forceinline Ray4 RayStreamAOP::getRayByIndex<4>(const vint4& index)
+ {
+ Ray4 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear */
+ const vfloat4 a0 = vfloat4::loadu(&ptr[index[0]]->org);
+ const vfloat4 a1 = vfloat4::loadu(&ptr[index[1]]->org);
+ const vfloat4 a2 = vfloat4::loadu(&ptr[index[2]]->org);
+ const vfloat4 a3 = vfloat4::loadu(&ptr[index[3]]->org);
+
+ transpose(a0,a1,a2,a3, ray.org.x, ray.org.y, ray.org.z, ray.tnear());
+
+ /* load and transpose: dir.x, dir.y, dir.z, time */
+ const vfloat4 b0 = vfloat4::loadu(&ptr[index[0]]->dir);
+ const vfloat4 b1 = vfloat4::loadu(&ptr[index[1]]->dir);
+ const vfloat4 b2 = vfloat4::loadu(&ptr[index[2]]->dir);
+ const vfloat4 b3 = vfloat4::loadu(&ptr[index[3]]->dir);
+
+ transpose(b0,b1,b2,b3, ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&ptr[index[0]]->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&ptr[index[1]]->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&ptr[index[2]]->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&ptr[index[3]]->tfar);
+
+ vfloat4 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3, ray.tfar, maskf, idf, flagsf);
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+
+#if defined(__AVX__)
+ template<>
+ __forceinline Ray8 RayStreamAOP::getRayByIndex<8>(const vint8& index)
+ {
+ Ray8 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear, dir.x, dir.y, dir.z, time */
+ const vfloat8 ab0 = vfloat8::loadu(&ptr[index[0]]->org);
+ const vfloat8 ab1 = vfloat8::loadu(&ptr[index[1]]->org);
+ const vfloat8 ab2 = vfloat8::loadu(&ptr[index[2]]->org);
+ const vfloat8 ab3 = vfloat8::loadu(&ptr[index[3]]->org);
+ const vfloat8 ab4 = vfloat8::loadu(&ptr[index[4]]->org);
+ const vfloat8 ab5 = vfloat8::loadu(&ptr[index[5]]->org);
+ const vfloat8 ab6 = vfloat8::loadu(&ptr[index[6]]->org);
+ const vfloat8 ab7 = vfloat8::loadu(&ptr[index[7]]->org);
+
+ transpose(ab0,ab1,ab2,ab3,ab4,ab5,ab6,ab7, ray.org.x, ray.org.y, ray.org.z, ray.tnear(), ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&ptr[index[0]]->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&ptr[index[1]]->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&ptr[index[2]]->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&ptr[index[3]]->tfar);
+ const vfloat4 c4 = vfloat4::loadu(&ptr[index[4]]->tfar);
+ const vfloat4 c5 = vfloat4::loadu(&ptr[index[5]]->tfar);
+ const vfloat4 c6 = vfloat4::loadu(&ptr[index[6]]->tfar);
+ const vfloat4 c7 = vfloat4::loadu(&ptr[index[7]]->tfar);
+
+ vfloat8 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3,c4,c5,c6,c7, ray.tfar, maskf, idf, flagsf);
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+#endif
+
+#if defined(__AVX512F__)
+ template<>
+ __forceinline Ray16 RayStreamAOP::getRayByIndex<16>(const vint16& index)
+ {
+ Ray16 ray;
+
+ /* load and transpose: org.x, org.y, org.z, tnear, dir.x, dir.y, dir.z, time */
+ const vfloat8 ab0 = vfloat8::loadu(&ptr[index[0]]->org);
+ const vfloat8 ab1 = vfloat8::loadu(&ptr[index[1]]->org);
+ const vfloat8 ab2 = vfloat8::loadu(&ptr[index[2]]->org);
+ const vfloat8 ab3 = vfloat8::loadu(&ptr[index[3]]->org);
+ const vfloat8 ab4 = vfloat8::loadu(&ptr[index[4]]->org);
+ const vfloat8 ab5 = vfloat8::loadu(&ptr[index[5]]->org);
+ const vfloat8 ab6 = vfloat8::loadu(&ptr[index[6]]->org);
+ const vfloat8 ab7 = vfloat8::loadu(&ptr[index[7]]->org);
+ const vfloat8 ab8 = vfloat8::loadu(&ptr[index[8]]->org);
+ const vfloat8 ab9 = vfloat8::loadu(&ptr[index[9]]->org);
+ const vfloat8 ab10 = vfloat8::loadu(&ptr[index[10]]->org);
+ const vfloat8 ab11 = vfloat8::loadu(&ptr[index[11]]->org);
+ const vfloat8 ab12 = vfloat8::loadu(&ptr[index[12]]->org);
+ const vfloat8 ab13 = vfloat8::loadu(&ptr[index[13]]->org);
+ const vfloat8 ab14 = vfloat8::loadu(&ptr[index[14]]->org);
+ const vfloat8 ab15 = vfloat8::loadu(&ptr[index[15]]->org);
+
+ transpose(ab0,ab1,ab2,ab3,ab4,ab5,ab6,ab7,ab8,ab9,ab10,ab11,ab12,ab13,ab14,ab15,
+ ray.org.x, ray.org.y, ray.org.z, ray.tnear(), ray.dir.x, ray.dir.y, ray.dir.z, ray.time());
+
+ /* load and transpose: tfar, mask, id, flags */
+ const vfloat4 c0 = vfloat4::loadu(&ptr[index[0]]->tfar);
+ const vfloat4 c1 = vfloat4::loadu(&ptr[index[1]]->tfar);
+ const vfloat4 c2 = vfloat4::loadu(&ptr[index[2]]->tfar);
+ const vfloat4 c3 = vfloat4::loadu(&ptr[index[3]]->tfar);
+ const vfloat4 c4 = vfloat4::loadu(&ptr[index[4]]->tfar);
+ const vfloat4 c5 = vfloat4::loadu(&ptr[index[5]]->tfar);
+ const vfloat4 c6 = vfloat4::loadu(&ptr[index[6]]->tfar);
+ const vfloat4 c7 = vfloat4::loadu(&ptr[index[7]]->tfar);
+ const vfloat4 c8 = vfloat4::loadu(&ptr[index[8]]->tfar);
+ const vfloat4 c9 = vfloat4::loadu(&ptr[index[9]]->tfar);
+ const vfloat4 c10 = vfloat4::loadu(&ptr[index[10]]->tfar);
+ const vfloat4 c11 = vfloat4::loadu(&ptr[index[11]]->tfar);
+ const vfloat4 c12 = vfloat4::loadu(&ptr[index[12]]->tfar);
+ const vfloat4 c13 = vfloat4::loadu(&ptr[index[13]]->tfar);
+ const vfloat4 c14 = vfloat4::loadu(&ptr[index[14]]->tfar);
+ const vfloat4 c15 = vfloat4::loadu(&ptr[index[15]]->tfar);
+
+ vfloat16 maskf, idf, flagsf;
+ transpose(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,
+ ray.tfar, maskf, idf, flagsf);
+
+ ray.mask = asInt(maskf);
+ ray.id = asInt(idf);
+ ray.flags = asInt(flagsf);
+
+ return ray;
+ }
+#endif
+}
diff --git a/thirdparty/embree/kernels/common/rtcore.cpp b/thirdparty/embree/kernels/common/rtcore.cpp
new file mode 100644
index 0000000000..94b3819e42
--- /dev/null
+++ b/thirdparty/embree/kernels/common/rtcore.cpp
@@ -0,0 +1,1766 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#define RTC_EXPORT_API
+
+#include "default.h"
+#include "device.h"
+#include "scene.h"
+#include "context.h"
+#include "../../include/embree3/rtcore_ray.h"
+using namespace embree;
+
+RTC_NAMESPACE_BEGIN;
+
+ /* mutex to make API thread safe */
+ static MutexSys g_mutex;
+
+ RTC_API RTCDevice rtcNewDevice(const char* config)
+ {
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewDevice);
+ Lock<MutexSys> lock(g_mutex);
+ Device* device = new Device(config);
+ return (RTCDevice) device->refInc();
+ RTC_CATCH_END(nullptr);
+ return (RTCDevice) nullptr;
+ }
+
+ RTC_API void rtcRetainDevice(RTCDevice hdevice)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcRetainDevice);
+ RTC_VERIFY_HANDLE(hdevice);
+ Lock<MutexSys> lock(g_mutex);
+ device->refInc();
+ RTC_CATCH_END(nullptr);
+ }
+
+ RTC_API void rtcReleaseDevice(RTCDevice hdevice)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcReleaseDevice);
+ RTC_VERIFY_HANDLE(hdevice);
+ Lock<MutexSys> lock(g_mutex);
+ device->refDec();
+ RTC_CATCH_END(nullptr);
+ }
+
+ RTC_API ssize_t rtcGetDeviceProperty(RTCDevice hdevice, RTCDeviceProperty prop)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetDeviceProperty);
+ RTC_VERIFY_HANDLE(hdevice);
+ Lock<MutexSys> lock(g_mutex);
+ return device->getProperty(prop);
+ RTC_CATCH_END(device);
+ return 0;
+ }
+
+ RTC_API void rtcSetDeviceProperty(RTCDevice hdevice, const RTCDeviceProperty prop, ssize_t val)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetDeviceProperty);
+ const bool internal_prop = (size_t)prop >= 1000000 && (size_t)prop < 1000004;
+ if (!internal_prop) RTC_VERIFY_HANDLE(hdevice); // allow NULL device for special internal settings
+ Lock<MutexSys> lock(g_mutex);
+ device->setProperty(prop,val);
+ RTC_CATCH_END(device);
+ }
+
+ RTC_API RTCError rtcGetDeviceError(RTCDevice hdevice)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetDeviceError);
+ if (device == nullptr) return Device::getThreadErrorCode();
+ else return device->getDeviceErrorCode();
+ RTC_CATCH_END(device);
+ return RTC_ERROR_UNKNOWN;
+ }
+
+ RTC_API void rtcSetDeviceErrorFunction(RTCDevice hdevice, RTCErrorFunction error, void* userPtr)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetDeviceErrorFunction);
+ RTC_VERIFY_HANDLE(hdevice);
+ device->setErrorFunction(error, userPtr);
+ RTC_CATCH_END(device);
+ }
+
+ RTC_API void rtcSetDeviceMemoryMonitorFunction(RTCDevice hdevice, RTCMemoryMonitorFunction memoryMonitor, void* userPtr)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetDeviceMemoryMonitorFunction);
+ device->setMemoryMonitorFunction(memoryMonitor, userPtr);
+ RTC_CATCH_END(device);
+ }
+
+ RTC_API RTCBuffer rtcNewBuffer(RTCDevice hdevice, size_t byteSize)
+ {
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewBuffer);
+ RTC_VERIFY_HANDLE(hdevice);
+ Buffer* buffer = new Buffer((Device*)hdevice, byteSize);
+ return (RTCBuffer)buffer->refInc();
+ RTC_CATCH_END((Device*)hdevice);
+ return nullptr;
+ }
+
+ RTC_API RTCBuffer rtcNewSharedBuffer(RTCDevice hdevice, void* ptr, size_t byteSize)
+ {
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewSharedBuffer);
+ RTC_VERIFY_HANDLE(hdevice);
+ Buffer* buffer = new Buffer((Device*)hdevice, byteSize, ptr);
+ return (RTCBuffer)buffer->refInc();
+ RTC_CATCH_END((Device*)hdevice);
+ return nullptr;
+ }
+
+ RTC_API void* rtcGetBufferData(RTCBuffer hbuffer)
+ {
+ Buffer* buffer = (Buffer*)hbuffer;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetBufferData);
+ RTC_VERIFY_HANDLE(hbuffer);
+ return buffer->data();
+ RTC_CATCH_END2(buffer);
+ return nullptr;
+ }
+
+ RTC_API void rtcRetainBuffer(RTCBuffer hbuffer)
+ {
+ Buffer* buffer = (Buffer*)hbuffer;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcRetainBuffer);
+ RTC_VERIFY_HANDLE(hbuffer);
+ buffer->refInc();
+ RTC_CATCH_END2(buffer);
+ }
+
+ RTC_API void rtcReleaseBuffer(RTCBuffer hbuffer)
+ {
+ Buffer* buffer = (Buffer*)hbuffer;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcReleaseBuffer);
+ RTC_VERIFY_HANDLE(hbuffer);
+ buffer->refDec();
+ RTC_CATCH_END2(buffer);
+ }
+
+ RTC_API RTCScene rtcNewScene (RTCDevice hdevice)
+ {
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewScene);
+ RTC_VERIFY_HANDLE(hdevice);
+ Scene* scene = new Scene((Device*)hdevice);
+ return (RTCScene) scene->refInc();
+ RTC_CATCH_END((Device*)hdevice);
+ return nullptr;
+ }
+
+ RTC_API RTCDevice rtcGetSceneDevice(RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetSceneDevice);
+ RTC_VERIFY_HANDLE(hscene);
+ return (RTCDevice)scene->device->refInc(); // user will own one additional device reference
+ RTC_CATCH_END2(scene);
+ return (RTCDevice)nullptr;
+ }
+
+ RTC_API void rtcSetSceneProgressMonitorFunction(RTCScene hscene, RTCProgressMonitorFunction progress, void* ptr)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetSceneProgressMonitorFunction);
+ RTC_VERIFY_HANDLE(hscene);
+ Lock<MutexSys> lock(g_mutex);
+ scene->setProgressMonitorFunction(progress,ptr);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcSetSceneBuildQuality (RTCScene hscene, RTCBuildQuality quality)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetSceneBuildQuality);
+ RTC_VERIFY_HANDLE(hscene);
+ if (quality != RTC_BUILD_QUALITY_LOW &&
+ quality != RTC_BUILD_QUALITY_MEDIUM &&
+ quality != RTC_BUILD_QUALITY_HIGH)
+ // -- GODOT start --
+ // throw std::runtime_error("invalid build quality");
+ abort();
+ // -- GODOT end --
+ scene->setBuildQuality(quality);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcSetSceneFlags (RTCScene hscene, RTCSceneFlags flags)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetSceneFlags);
+ RTC_VERIFY_HANDLE(hscene);
+ scene->setSceneFlags(flags);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API RTCSceneFlags rtcGetSceneFlags(RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetSceneFlags);
+ RTC_VERIFY_HANDLE(hscene);
+ return scene->getSceneFlags();
+ RTC_CATCH_END2(scene);
+ return RTC_SCENE_FLAG_NONE;
+ }
+
+ RTC_API void rtcCommitScene (RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcCommitScene);
+ RTC_VERIFY_HANDLE(hscene);
+ scene->commit(false);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcJoinCommitScene (RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcJoinCommitScene);
+ RTC_VERIFY_HANDLE(hscene);
+ scene->commit(true);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcGetSceneBounds(RTCScene hscene, RTCBounds* bounds_o)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetSceneBounds);
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ BBox3fa bounds = scene->bounds.bounds();
+ bounds_o->lower_x = bounds.lower.x;
+ bounds_o->lower_y = bounds.lower.y;
+ bounds_o->lower_z = bounds.lower.z;
+ bounds_o->align0 = 0;
+ bounds_o->upper_x = bounds.upper.x;
+ bounds_o->upper_y = bounds.upper.y;
+ bounds_o->upper_z = bounds.upper.z;
+ bounds_o->align1 = 0;
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcGetSceneLinearBounds(RTCScene hscene, RTCLinearBounds* bounds_o)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetSceneBounds);
+ RTC_VERIFY_HANDLE(hscene);
+ if (bounds_o == nullptr)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid destination pointer");
+ if (scene->isModified())
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+
+ bounds_o->bounds0.lower_x = scene->bounds.bounds0.lower.x;
+ bounds_o->bounds0.lower_y = scene->bounds.bounds0.lower.y;
+ bounds_o->bounds0.lower_z = scene->bounds.bounds0.lower.z;
+ bounds_o->bounds0.align0 = 0;
+ bounds_o->bounds0.upper_x = scene->bounds.bounds0.upper.x;
+ bounds_o->bounds0.upper_y = scene->bounds.bounds0.upper.y;
+ bounds_o->bounds0.upper_z = scene->bounds.bounds0.upper.z;
+ bounds_o->bounds0.align1 = 0;
+ bounds_o->bounds1.lower_x = scene->bounds.bounds1.lower.x;
+ bounds_o->bounds1.lower_y = scene->bounds.bounds1.lower.y;
+ bounds_o->bounds1.lower_z = scene->bounds.bounds1.lower.z;
+ bounds_o->bounds1.align0 = 0;
+ bounds_o->bounds1.upper_x = scene->bounds.bounds1.upper.x;
+ bounds_o->bounds1.upper_y = scene->bounds.bounds1.upper.y;
+ bounds_o->bounds1.upper_z = scene->bounds.bounds1.upper.z;
+ bounds_o->bounds1.align1 = 0;
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcCollide (RTCScene hscene0, RTCScene hscene1, RTCCollideFunc callback, void* userPtr)
+ {
+ Scene* scene0 = (Scene*) hscene0;
+ Scene* scene1 = (Scene*) hscene1;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcCollide);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene0);
+ RTC_VERIFY_HANDLE(hscene1);
+ if (scene0->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (scene1->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (scene0->device != scene1->device) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scenes are from different devices");
+ auto nUserPrims0 = scene0->getNumPrimitives (Geometry::MTY_USER_GEOMETRY, false);
+ auto nUserPrims1 = scene1->getNumPrimitives (Geometry::MTY_USER_GEOMETRY, false);
+ if (scene0->numPrimitives() != nUserPrims0 && scene1->numPrimitives() != nUserPrims1) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scenes must only contain user geometries with a single timestep");
+#endif
+ scene0->intersectors.collide(scene0,scene1,callback,userPtr);
+ RTC_CATCH_END(scene0->device);
+ }
+
+ inline bool pointQuery(Scene* scene, RTCPointQuery* query, RTCPointQueryContext* userContext, RTCPointQueryFunction queryFunc, void* userPtr)
+ {
+ bool changed = false;
+ if (userContext->instStackSize > 0)
+ {
+ const AffineSpace3fa transform = AffineSpace3fa_load_unaligned((AffineSpace3fa*)userContext->world2inst[userContext->instStackSize-1]);
+
+ float similarityScale = 0.f;
+ const bool similtude = similarityTransform(transform, &similarityScale);
+ assert((similtude && similarityScale > 0) || (!similtude && similarityScale == 0.f));
+
+ PointQuery query_inst;
+ query_inst.p = xfmPoint(transform, Vec3fa(query->x, query->y, query->z));
+ query_inst.radius = query->radius * similarityScale;
+ query_inst.time = query->time;
+
+ PointQueryContext context_inst(scene, (PointQuery*)query,
+ similtude ? POINT_QUERY_TYPE_SPHERE : POINT_QUERY_TYPE_AABB,
+ queryFunc, userContext, similarityScale, userPtr);
+ changed = scene->intersectors.pointQuery((PointQuery*)&query_inst, &context_inst);
+ }
+ else
+ {
+ PointQueryContext context(scene, (PointQuery*)query,
+ POINT_QUERY_TYPE_SPHERE, queryFunc, userContext, 1.f, userPtr);
+ changed = scene->intersectors.pointQuery((PointQuery*)query, &context);
+ }
+ return changed;
+ }
+
+ RTC_API bool rtcPointQuery(RTCScene hscene, RTCPointQuery* query, RTCPointQueryContext* userContext, RTCPointQueryFunction queryFunc, void* userPtr)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcPointQuery);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ RTC_VERIFY_HANDLE(userContext);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (((size_t)query) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "query not aligned to 16 bytes");
+ if (((size_t)userContext) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "context not aligned to 16 bytes");
+#endif
+
+ return pointQuery(scene, query, userContext, queryFunc, userPtr);
+ RTC_CATCH_END2_FALSE(scene);
+ }
+
+ RTC_API bool rtcPointQuery4 (const int* valid, RTCScene hscene, RTCPointQuery4* query, struct RTCPointQueryContext* userContext, RTCPointQueryFunction queryFunc, void** userPtrN)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcPointQuery4);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (((size_t)valid) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 16 bytes");
+ if (((size_t)query) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "query not aligned to 16 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(point_query.travs,cnt,cnt,cnt);
+
+ bool changed = false;
+ PointQuery4* query4 = (PointQuery4*)query;
+ PointQuery query1;
+ for (size_t i=0; i<4; i++) {
+ if (!valid[i]) continue;
+ query4->get(i,query1);
+ changed |= pointQuery(scene, (RTCPointQuery*)&query1, userContext, queryFunc, userPtrN?userPtrN[i]:NULL);
+ query4->set(i,query1);
+ }
+ return changed;
+ RTC_CATCH_END2_FALSE(scene);
+ }
+
+ RTC_API bool rtcPointQuery8 (const int* valid, RTCScene hscene, RTCPointQuery8* query, struct RTCPointQueryContext* userContext, RTCPointQueryFunction queryFunc, void** userPtrN)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcPointQuery8);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (((size_t)valid) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 16 bytes");
+ if (((size_t)query) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "query not aligned to 16 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(point_query.travs,cnt,cnt,cnt);
+
+ bool changed = false;
+ PointQuery8* query8 = (PointQuery8*)query;
+ PointQuery query1;
+ for (size_t i=0; i<8; i++) {
+ if (!valid[i]) continue;
+ query8->get(i,query1);
+ changed |= pointQuery(scene, (RTCPointQuery*)&query1, userContext, queryFunc, userPtrN?userPtrN[i]:NULL);
+ query8->set(i,query1);
+ }
+ return changed;
+ RTC_CATCH_END2_FALSE(scene);
+ }
+
+ RTC_API bool rtcPointQuery16 (const int* valid, RTCScene hscene, RTCPointQuery16* query, struct RTCPointQueryContext* userContext, RTCPointQueryFunction queryFunc, void** userPtrN)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcPointQuery16);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene got not committed");
+ if (((size_t)valid) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 16 bytes");
+ if (((size_t)query) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "query not aligned to 16 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(point_query.travs,cnt,cnt,cnt);
+
+ bool changed = false;
+ PointQuery16* query16 = (PointQuery16*)query;
+ PointQuery query1;
+ for (size_t i=0; i<16; i++) {
+ if (!valid[i]) continue;
+ PointQuery query1; query16->get(i,query1);
+ changed |= pointQuery(scene, (RTCPointQuery*)&query1, userContext, queryFunc, userPtrN?userPtrN[i]:NULL);
+ query16->set(i,query1);
+ }
+ return changed;
+ RTC_CATCH_END2_FALSE(scene);
+ }
+
+ RTC_API void rtcIntersect1 (RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit* rayhit)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect1);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)rayhit) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes");
+#endif
+ STAT3(normal.travs,1,1,1);
+ IntersectContext context(scene,user_context);
+ scene->intersectors.intersect(*rayhit,&context);
+#if defined(DEBUG)
+ ((RayHit*)rayhit)->verifyHit();
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersect4 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit4* rayhit)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect4);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 16 bytes");
+ if (((size_t)rayhit) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit not aligned to 16 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(normal.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ Ray4* ray4 = (Ray4*) rayhit;
+ for (size_t i=0; i<4; i++) {
+ if (!valid[i]) continue;
+ RayHit ray1; ray4->get(i,ray1);
+ scene->intersectors.intersect((RTCRayHit&)ray1,&context);
+ ray4->set(i,ray1);
+ }
+#else
+ scene->intersectors.intersect4(valid,*rayhit,&context);
+#endif
+
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersect8 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit8* rayhit)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect8);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x1F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 32 bytes");
+ if (((size_t)rayhit) & 0x1F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit not aligned to 32 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<8; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(normal.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ Ray8* ray8 = (Ray8*) rayhit;
+ for (size_t i=0; i<8; i++) {
+ if (!valid[i]) continue;
+ RayHit ray1; ray8->get(i,ray1);
+ scene->intersectors.intersect((RTCRayHit&)ray1,&context);
+ ray8->set(i,ray1);
+ }
+#else
+ if (likely(scene->intersectors.intersector8))
+ scene->intersectors.intersect8(valid,*rayhit,&context);
+ else
+ scene->device->rayStreamFilters.intersectSOA(scene,(char*)rayhit,8,1,sizeof(RTCRayHit8),&context);
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersect16 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit16* rayhit)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect16);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x3F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 64 bytes");
+ if (((size_t)rayhit) & 0x3F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit not aligned to 64 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<16; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(normal.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ Ray16* ray16 = (Ray16*) rayhit;
+ for (size_t i=0; i<16; i++) {
+ if (!valid[i]) continue;
+ RayHit ray1; ray16->get(i,ray1);
+ scene->intersectors.intersect((RTCRayHit&)ray1,&context);
+ ray16->set(i,ray1);
+ }
+#else
+ if (likely(scene->intersectors.intersector16))
+ scene->intersectors.intersect16(valid,*rayhit,&context);
+ else
+ scene->device->rayStreamFilters.intersectSOA(scene,(char*)rayhit,16,1,sizeof(RTCRayHit16),&context);
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersect1M (RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit* rayhit, unsigned int M, size_t byteStride)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect1M);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)rayhit ) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(normal.travs,M,M,M);
+ IntersectContext context(scene,user_context);
+
+ /* fast codepath for single rays */
+ if (likely(M == 1)) {
+ if (likely(rayhit->ray.tnear <= rayhit->ray.tfar))
+ scene->intersectors.intersect(*rayhit,&context);
+ }
+
+ /* codepath for streams */
+ else {
+ scene->device->rayStreamFilters.intersectAOS(scene,rayhit,M,byteStride,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect1M not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersect1Mp (RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit** rn, unsigned int M)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersect1Mp);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)rn) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(normal.travs,M,M,M);
+ IntersectContext context(scene,user_context);
+
+ /* fast codepath for single rays */
+ if (likely(M == 1)) {
+ if (likely(rn[0]->ray.tnear <= rn[0]->ray.tfar))
+ scene->intersectors.intersect(*rn[0],&context);
+ }
+
+ /* codepath for streams */
+ else {
+ scene->device->rayStreamFilters.intersectAOP(scene,rn,M,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect1Mp not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersectNM (RTCScene hscene, RTCIntersectContext* user_context, struct RTCRayHitN* rayhit, unsigned int N, unsigned int M, size_t byteStride)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersectNM);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)rayhit) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(normal.travs,N*M,N*M,N*M);
+ IntersectContext context(scene,user_context);
+
+ /* code path for single ray streams */
+ if (likely(N == 1))
+ {
+ /* fast code path for streams of size 1 */
+ if (likely(M == 1)) {
+ if (likely(((RTCRayHit*)rayhit)->ray.tnear <= ((RTCRayHit*)rayhit)->ray.tfar))
+ scene->intersectors.intersect(*(RTCRayHit*)rayhit,&context);
+ }
+ /* normal codepath for single ray streams */
+ else {
+ scene->device->rayStreamFilters.intersectAOS(scene,(RTCRayHit*)rayhit,M,byteStride,&context);
+ }
+ }
+ /* code path for ray packet streams */
+ else {
+ scene->device->rayStreamFilters.intersectSOA(scene,(char*)rayhit,N,M,byteStride,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersectNM not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcIntersectNp (RTCScene hscene, RTCIntersectContext* user_context, const RTCRayHitNp* rayhit, unsigned int N)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcIntersectNp);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)rayhit->ray.org_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.org_x not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.org_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.org_y not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.org_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.org_z not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.dir_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_x not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.dir_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_y not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.dir_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_z not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.tnear ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_x not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.tfar ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.tnear not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.time ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.time not aligned to 4 bytes");
+ if (((size_t)rayhit->ray.mask ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.mask not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.Ng_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.Ng_x not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.Ng_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.Ng_y not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.Ng_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.Ng_z not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.u ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.u not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.v ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.v not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.geomID) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.geomID not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.primID) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.primID not aligned to 4 bytes");
+ if (((size_t)rayhit->hit.instID) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.instID not aligned to 4 bytes");
+#endif
+ STAT3(normal.travs,N,N,N);
+ IntersectContext context(scene,user_context);
+ scene->device->rayStreamFilters.intersectSOP(scene,rayhit,N,&context);
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersectNp not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded1 (RTCScene hscene, RTCIntersectContext* user_context, RTCRay* ray)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded1);
+ STAT3(shadow.travs,1,1,1);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)ray) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes");
+#endif
+ IntersectContext context(scene,user_context);
+ scene->intersectors.occluded(*ray,&context);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded4 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRay4* ray)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded4);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 16 bytes");
+ if (((size_t)ray) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(shadow.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ RayHit4* ray4 = (RayHit4*) ray;
+ for (size_t i=0; i<4; i++) {
+ if (!valid[i]) continue;
+ RayHit ray1; ray4->get(i,ray1);
+ scene->intersectors.occluded((RTCRay&)ray1,&context);
+ ray4->geomID[i] = ray1.geomID;
+ }
+#else
+ scene->intersectors.occluded4(valid,*ray,&context);
+#endif
+
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded8 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRay8* ray)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded8);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x1F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 32 bytes");
+ if (((size_t)ray) & 0x1F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 32 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<8; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(shadow.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ RayHit8* ray8 = (RayHit8*) ray;
+ for (size_t i=0; i<8; i++) {
+ if (!valid[i]) continue;
+ RayHit ray1; ray8->get(i,ray1);
+ scene->intersectors.occluded((RTCRay&)ray1,&context);
+ ray8->set(i,ray1);
+ }
+#else
+ if (likely(scene->intersectors.intersector8))
+ scene->intersectors.occluded8(valid,*ray,&context);
+ else
+ scene->device->rayStreamFilters.occludedSOA(scene,(char*)ray,8,1,sizeof(RTCRay8),&context);
+#endif
+
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded16 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRay16* ray)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded16);
+
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)valid) & 0x3F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 64 bytes");
+ if (((size_t)ray) & 0x3F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 64 bytes");
+#endif
+ STAT(size_t cnt=0; for (size_t i=0; i<16; i++) cnt += ((int*)valid)[i] == -1;);
+ STAT3(shadow.travs,cnt,cnt,cnt);
+
+ IntersectContext context(scene,user_context);
+#if !defined(EMBREE_RAY_PACKETS)
+ RayHit16* ray16 = (RayHit16*) ray;
+ for (size_t i=0; i<16; i++) {
+ if (!valid[i]) continue;
+ RayHit ray1; ray16->get(i,ray1);
+ scene->intersectors.occluded((RTCRay&)ray1,&context);
+ ray16->set(i,ray1);
+ }
+#else
+ if (likely(scene->intersectors.intersector16))
+ scene->intersectors.occluded16(valid,*ray,&context);
+ else
+ scene->device->rayStreamFilters.occludedSOA(scene,(char*)ray,16,1,sizeof(RTCRay16),&context);
+#endif
+
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded1M(RTCScene hscene, RTCIntersectContext* user_context, RTCRay* ray, unsigned int M, size_t byteStride)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded1M);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)ray) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(shadow.travs,M,M,M);
+ IntersectContext context(scene,user_context);
+ /* fast codepath for streams of size 1 */
+ if (likely(M == 1)) {
+ if (likely(ray->tnear <= ray->tfar))
+ scene->intersectors.occluded (*ray,&context);
+ }
+ /* codepath for normal streams */
+ else {
+ scene->device->rayStreamFilters.occludedAOS(scene,ray,M,byteStride,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccluded1M not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccluded1Mp(RTCScene hscene, RTCIntersectContext* user_context, RTCRay** ray, unsigned int M)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccluded1Mp);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)ray) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(shadow.travs,M,M,M);
+ IntersectContext context(scene,user_context);
+
+ /* fast codepath for streams of size 1 */
+ if (likely(M == 1)) {
+ if (likely(ray[0]->tnear <= ray[0]->tfar))
+ scene->intersectors.occluded (*ray[0],&context);
+ }
+ /* codepath for normal streams */
+ else {
+ scene->device->rayStreamFilters.occludedAOP(scene,ray,M,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccluded1Mp not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccludedNM(RTCScene hscene, RTCIntersectContext* user_context, RTCRayN* ray, unsigned int N, unsigned int M, size_t byteStride)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccludedNM);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (byteStride < sizeof(RTCRayHit)) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"byteStride too small");
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)ray) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes");
+#endif
+ STAT3(shadow.travs,N*M,N*N,N*N);
+ IntersectContext context(scene,user_context);
+
+ /* codepath for single rays */
+ if (likely(N == 1))
+ {
+ /* fast path for streams of size 1 */
+ if (likely(M == 1)) {
+ if (likely(((RTCRay*)ray)->tnear <= ((RTCRay*)ray)->tfar))
+ scene->intersectors.occluded (*(RTCRay*)ray,&context);
+ }
+ /* codepath for normal ray streams */
+ else {
+ scene->device->rayStreamFilters.occludedAOS(scene,(RTCRay*)ray,M,byteStride,&context);
+ }
+ }
+ /* code path for ray packet streams */
+ else {
+ scene->device->rayStreamFilters.occludedSOA(scene,(char*)ray,N,M,byteStride,&context);
+ }
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccludedNM not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcOccludedNp(RTCScene hscene, RTCIntersectContext* user_context, const RTCRayNp* ray, unsigned int N)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcOccludedNp);
+
+#if defined (EMBREE_RAY_PACKETS)
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed");
+ if (((size_t)ray->org_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "org_x not aligned to 4 bytes");
+ if (((size_t)ray->org_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "org_y not aligned to 4 bytes");
+ if (((size_t)ray->org_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "org_z not aligned to 4 bytes");
+ if (((size_t)ray->dir_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_x not aligned to 4 bytes");
+ if (((size_t)ray->dir_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_y not aligned to 4 bytes");
+ if (((size_t)ray->dir_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_z not aligned to 4 bytes");
+ if (((size_t)ray->tnear ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_x not aligned to 4 bytes");
+ if (((size_t)ray->tfar ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "tnear not aligned to 4 bytes");
+ if (((size_t)ray->time ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "time not aligned to 4 bytes");
+ if (((size_t)ray->mask ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 4 bytes");
+#endif
+ STAT3(shadow.travs,N,N,N);
+ IntersectContext context(scene,user_context);
+ scene->device->rayStreamFilters.occludedSOP(scene,ray,N,&context);
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccludedNp not supported");
+#endif
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcRetainScene (RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcRetainScene);
+ RTC_VERIFY_HANDLE(hscene);
+ scene->refInc();
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcReleaseScene (RTCScene hscene)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcReleaseScene);
+ RTC_VERIFY_HANDLE(hscene);
+ scene->refDec();
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcSetGeometryInstancedScene(RTCGeometry hgeometry, RTCScene hscene)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ Ref<Scene> scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryInstancedScene);
+ RTC_VERIFY_HANDLE(hgeometry);
+ RTC_VERIFY_HANDLE(hscene);
+ geometry->setInstancedScene(scene);
+ RTC_CATCH_END2(geometry);
+ }
+
+ AffineSpace3fa loadTransform(RTCFormat format, const float* xfm)
+ {
+ AffineSpace3fa space = one;
+ switch (format)
+ {
+ case RTC_FORMAT_FLOAT3X4_ROW_MAJOR:
+ space = AffineSpace3fa(Vec3fa(xfm[ 0], xfm[ 4], xfm[ 8]),
+ Vec3fa(xfm[ 1], xfm[ 5], xfm[ 9]),
+ Vec3fa(xfm[ 2], xfm[ 6], xfm[10]),
+ Vec3fa(xfm[ 3], xfm[ 7], xfm[11]));
+ break;
+
+ case RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR:
+ space = AffineSpace3fa(Vec3fa(xfm[ 0], xfm[ 1], xfm[ 2]),
+ Vec3fa(xfm[ 3], xfm[ 4], xfm[ 5]),
+ Vec3fa(xfm[ 6], xfm[ 7], xfm[ 8]),
+ Vec3fa(xfm[ 9], xfm[10], xfm[11]));
+ break;
+
+ case RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR:
+ space = AffineSpace3fa(Vec3fa(xfm[ 0], xfm[ 1], xfm[ 2]),
+ Vec3fa(xfm[ 4], xfm[ 5], xfm[ 6]),
+ Vec3fa(xfm[ 8], xfm[ 9], xfm[10]),
+ Vec3fa(xfm[12], xfm[13], xfm[14]));
+ break;
+
+ default:
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid matrix format");
+ break;
+ }
+ return space;
+ }
+
+ void storeTransform(const AffineSpace3fa& space, RTCFormat format, float* xfm)
+ {
+ switch (format)
+ {
+ case RTC_FORMAT_FLOAT3X4_ROW_MAJOR:
+ xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vy.x; xfm[ 2] = space.l.vz.x; xfm[ 3] = space.p.x;
+ xfm[ 4] = space.l.vx.y; xfm[ 5] = space.l.vy.y; xfm[ 6] = space.l.vz.y; xfm[ 7] = space.p.y;
+ xfm[ 8] = space.l.vx.z; xfm[ 9] = space.l.vy.z; xfm[10] = space.l.vz.z; xfm[11] = space.p.z;
+ break;
+
+ case RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR:
+ xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vx.y; xfm[ 2] = space.l.vx.z;
+ xfm[ 3] = space.l.vy.x; xfm[ 4] = space.l.vy.y; xfm[ 5] = space.l.vy.z;
+ xfm[ 6] = space.l.vz.x; xfm[ 7] = space.l.vz.y; xfm[ 8] = space.l.vz.z;
+ xfm[ 9] = space.p.x; xfm[10] = space.p.y; xfm[11] = space.p.z;
+ break;
+
+ case RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR:
+ xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vx.y; xfm[ 2] = space.l.vx.z; xfm[ 3] = 0.f;
+ xfm[ 4] = space.l.vy.x; xfm[ 5] = space.l.vy.y; xfm[ 6] = space.l.vy.z; xfm[ 7] = 0.f;
+ xfm[ 8] = space.l.vz.x; xfm[ 9] = space.l.vz.y; xfm[10] = space.l.vz.z; xfm[11] = 0.f;
+ xfm[12] = space.p.x; xfm[13] = space.p.y; xfm[14] = space.p.z; xfm[15] = 1.f;
+ break;
+
+ default:
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid matrix format");
+ break;
+ }
+ }
+
+ RTC_API void rtcSetGeometryTransform(RTCGeometry hgeometry, unsigned int timeStep, RTCFormat format, const void* xfm)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTransform);
+ RTC_VERIFY_HANDLE(hgeometry);
+ RTC_VERIFY_HANDLE(xfm);
+ const AffineSpace3fa transform = loadTransform(format, (const float*)xfm);
+ geometry->setTransform(transform, timeStep);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryTransformQuaternion(RTCGeometry hgeometry, unsigned int timeStep, const RTCQuaternionDecomposition* qd)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTransformQuaternion);
+ RTC_VERIFY_HANDLE(hgeometry);
+ RTC_VERIFY_HANDLE(qd);
+
+ AffineSpace3fx transform;
+ transform.l.vx.x = qd->scale_x;
+ transform.l.vy.y = qd->scale_y;
+ transform.l.vz.z = qd->scale_z;
+ transform.l.vy.x = qd->skew_xy;
+ transform.l.vz.x = qd->skew_xz;
+ transform.l.vz.y = qd->skew_yz;
+ transform.l.vx.y = qd->translation_x;
+ transform.l.vx.z = qd->translation_y;
+ transform.l.vy.z = qd->translation_z;
+ transform.p.x = qd->shift_x;
+ transform.p.y = qd->shift_y;
+ transform.p.z = qd->shift_z;
+
+ // normalize quaternion
+ Quaternion3f q(qd->quaternion_r, qd->quaternion_i, qd->quaternion_j, qd->quaternion_k);
+ q = normalize(q);
+ transform.l.vx.w = q.i;
+ transform.l.vy.w = q.j;
+ transform.l.vz.w = q.k;
+ transform.p.w = q.r;
+
+ geometry->setQuaternionDecomposition(transform, timeStep);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcGetGeometryTransform(RTCGeometry hgeometry, float time, RTCFormat format, void* xfm)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryTransform);
+ const AffineSpace3fa transform = geometry->getTransform(time);
+ storeTransform(transform, format, (float*)xfm);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcFilterIntersection(const struct RTCIntersectFunctionNArguments* const args_i, const struct RTCFilterFunctionNArguments* filter_args)
+ {
+ IntersectFunctionNArguments* args = (IntersectFunctionNArguments*) args_i;
+ args->report(args,filter_args);
+ }
+
+ RTC_API void rtcFilterOcclusion(const struct RTCOccludedFunctionNArguments* const args_i, const struct RTCFilterFunctionNArguments* filter_args)
+ {
+ OccludedFunctionNArguments* args = (OccludedFunctionNArguments*) args_i;
+ args->report(args,filter_args);
+ }
+
+ RTC_API RTCGeometry rtcNewGeometry (RTCDevice hdevice, RTCGeometryType type)
+ {
+ Device* device = (Device*) hdevice;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewGeometry);
+ RTC_VERIFY_HANDLE(hdevice);
+
+ switch (type)
+ {
+ case RTC_GEOMETRY_TYPE_TRIANGLE:
+ {
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ createTriangleMeshTy createTriangleMesh = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(device->enabled_cpu_features,createTriangleMesh);
+ Geometry* geom = createTriangleMesh(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_TRIANGLE is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_QUAD:
+ {
+#if defined(EMBREE_GEOMETRY_QUAD)
+ createQuadMeshTy createQuadMesh = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(device->enabled_cpu_features,createQuadMesh);
+ Geometry* geom = createQuadMesh(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_QUAD is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_SPHERE_POINT:
+ case RTC_GEOMETRY_TYPE_DISC_POINT:
+ case RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT:
+ {
+#if defined(EMBREE_GEOMETRY_POINT)
+ createPointsTy createPoints = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(device->enabled_builder_cpu_features, createPoints);
+
+ Geometry *geom;
+ switch(type) {
+ case RTC_GEOMETRY_TYPE_SPHERE_POINT:
+ geom = createPoints(device, Geometry::GTY_SPHERE_POINT);
+ break;
+ case RTC_GEOMETRY_TYPE_DISC_POINT:
+ geom = createPoints(device, Geometry::GTY_DISC_POINT);
+ break;
+ case RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT:
+ geom = createPoints(device, Geometry::GTY_ORIENTED_DISC_POINT);
+ break;
+ default:
+ geom = nullptr;
+ break;
+ }
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_POINT is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_CONE_LINEAR_CURVE:
+ case RTC_GEOMETRY_TYPE_ROUND_LINEAR_CURVE:
+ case RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE:
+
+ case RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE:
+ case RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE:
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BEZIER_CURVE:
+
+ case RTC_GEOMETRY_TYPE_ROUND_BSPLINE_CURVE:
+ case RTC_GEOMETRY_TYPE_FLAT_BSPLINE_CURVE:
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BSPLINE_CURVE:
+
+ case RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE:
+ case RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE:
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_HERMITE_CURVE:
+
+ case RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE:
+ case RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE:
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_CATMULL_ROM_CURVE:
+ {
+#if defined(EMBREE_GEOMETRY_CURVE)
+ createLineSegmentsTy createLineSegments = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(device->enabled_cpu_features,createLineSegments);
+ createCurvesTy createCurves = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(device->enabled_cpu_features,createCurves);
+
+ Geometry* geom;
+ switch (type) {
+ case RTC_GEOMETRY_TYPE_CONE_LINEAR_CURVE : geom = createLineSegments (device,Geometry::GTY_CONE_LINEAR_CURVE); break;
+ case RTC_GEOMETRY_TYPE_ROUND_LINEAR_CURVE : geom = createLineSegments (device,Geometry::GTY_ROUND_LINEAR_CURVE); break;
+ case RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE : geom = createLineSegments (device,Geometry::GTY_FLAT_LINEAR_CURVE); break;
+ //case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_LINEAR_CURVE : geom = createLineSegments (device,Geometry::GTY_ORIENTED_LINEAR_CURVE); break;
+
+ case RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE : geom = createCurves(device,Geometry::GTY_ROUND_BEZIER_CURVE); break;
+ case RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE : geom = createCurves(device,Geometry::GTY_FLAT_BEZIER_CURVE); break;
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BEZIER_CURVE : geom = createCurves(device,Geometry::GTY_ORIENTED_BEZIER_CURVE); break;
+
+ case RTC_GEOMETRY_TYPE_ROUND_BSPLINE_CURVE : geom = createCurves(device,Geometry::GTY_ROUND_BSPLINE_CURVE); break;
+ case RTC_GEOMETRY_TYPE_FLAT_BSPLINE_CURVE : geom = createCurves(device,Geometry::GTY_FLAT_BSPLINE_CURVE); break;
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BSPLINE_CURVE : geom = createCurves(device,Geometry::GTY_ORIENTED_BSPLINE_CURVE); break;
+
+ case RTC_GEOMETRY_TYPE_ROUND_HERMITE_CURVE : geom = createCurves(device,Geometry::GTY_ROUND_HERMITE_CURVE); break;
+ case RTC_GEOMETRY_TYPE_FLAT_HERMITE_CURVE : geom = createCurves(device,Geometry::GTY_FLAT_HERMITE_CURVE); break;
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_HERMITE_CURVE : geom = createCurves(device,Geometry::GTY_ORIENTED_HERMITE_CURVE); break;
+
+ case RTC_GEOMETRY_TYPE_ROUND_CATMULL_ROM_CURVE : geom = createCurves(device,Geometry::GTY_ROUND_CATMULL_ROM_CURVE); break;
+ case RTC_GEOMETRY_TYPE_FLAT_CATMULL_ROM_CURVE : geom = createCurves(device,Geometry::GTY_FLAT_CATMULL_ROM_CURVE); break;
+ case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_CATMULL_ROM_CURVE : geom = createCurves(device,Geometry::GTY_ORIENTED_CATMULL_ROM_CURVE); break;
+ default: geom = nullptr; break;
+ }
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_CURVE is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_SUBDIVISION:
+ {
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ createSubdivMeshTy createSubdivMesh = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX(device->enabled_cpu_features,createSubdivMesh);
+ //SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(device->enabled_cpu_features,createSubdivMesh); // FIXME: this does not work for some reason?
+ Geometry* geom = createSubdivMesh(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_SUBDIVISION is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_USER:
+ {
+#if defined(EMBREE_GEOMETRY_USER)
+ createUserGeometryTy createUserGeometry = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(device->enabled_cpu_features,createUserGeometry);
+ Geometry* geom = createUserGeometry(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_USER is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_INSTANCE:
+ {
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ createInstanceTy createInstance = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(device->enabled_cpu_features,createInstance);
+ Geometry* geom = createInstance(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_INSTANCE is not supported");
+#endif
+ }
+
+ case RTC_GEOMETRY_TYPE_GRID:
+ {
+#if defined(EMBREE_GEOMETRY_GRID)
+ createGridMeshTy createGridMesh = nullptr;
+ SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(device->enabled_cpu_features,createGridMesh);
+ Geometry* geom = createGridMesh(device);
+ return (RTCGeometry) geom->refInc();
+#else
+ throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_GRID is not supported");
+#endif
+ }
+
+ default:
+ throw_RTCError(RTC_ERROR_UNKNOWN,"invalid geometry type");
+ }
+
+ RTC_CATCH_END(device);
+ return nullptr;
+ }
+
+ RTC_API void rtcSetGeometryUserPrimitiveCount(RTCGeometry hgeometry, unsigned int userPrimitiveCount)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryUserPrimitiveCount);
+ RTC_VERIFY_HANDLE(hgeometry);
+
+ if (unlikely(geometry->getType() != Geometry::GTY_USER_GEOMETRY))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation only allowed for user geometries");
+
+ geometry->setNumPrimitives(userPrimitiveCount);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryTimeStepCount(RTCGeometry hgeometry, unsigned int timeStepCount)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTimeStepCount);
+ RTC_VERIFY_HANDLE(hgeometry);
+
+ if (timeStepCount > RTC_MAX_TIME_STEP_COUNT)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"number of time steps is out of range");
+
+ geometry->setNumTimeSteps(timeStepCount);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryTimeRange(RTCGeometry hgeometry, float startTime, float endTime)
+ {
+ Ref<Geometry> geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTimeRange);
+ RTC_VERIFY_HANDLE(hgeometry);
+
+ if (startTime > endTime)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"startTime has to be smaller or equal to the endTime");
+
+ geometry->setTimeRange(BBox1f(startTime,endTime));
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryVertexAttributeCount(RTCGeometry hgeometry, unsigned int N)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryVertexAttributeCount);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setVertexAttributeCount(N);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryTopologyCount(RTCGeometry hgeometry, unsigned int N)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTopologyCount);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setTopologyCount(N);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryBuildQuality (RTCGeometry hgeometry, RTCBuildQuality quality)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryBuildQuality);
+ RTC_VERIFY_HANDLE(hgeometry);
+ if (quality != RTC_BUILD_QUALITY_LOW &&
+ quality != RTC_BUILD_QUALITY_MEDIUM &&
+ quality != RTC_BUILD_QUALITY_HIGH &&
+ quality != RTC_BUILD_QUALITY_REFIT)
+ // -- GODOT start --
+ // throw std::runtime_error("invalid build quality");
+ abort();
+ // -- GODOT end --
+ geometry->setBuildQuality(quality);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryMaxRadiusScale(RTCGeometry hgeometry, float maxRadiusScale)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryMaxRadiusScale);
+ RTC_VERIFY_HANDLE(hgeometry);
+#if RTC_MIN_WIDTH
+ if (maxRadiusScale < 1.0f) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"maximal radius scale has to be larger or equal to 1");
+ geometry->setMaxRadiusScale(maxRadiusScale);
+#else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"min-width feature is not enabled");
+#endif
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryMask (RTCGeometry hgeometry, unsigned int mask)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryMask);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setMask(mask);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometrySubdivisionMode (RTCGeometry hgeometry, unsigned topologyID, RTCSubdivisionMode mode)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometrySubdivisionMode);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setSubdivisionMode(topologyID,mode);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryVertexAttributeTopology(RTCGeometry hgeometry, unsigned int vertexAttributeID, unsigned int topologyID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryVertexAttributeTopology);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setVertexAttributeTopology(vertexAttributeID, topologyID);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryBuffer(RTCGeometry hgeometry, RTCBufferType type, unsigned int slot, RTCFormat format, RTCBuffer hbuffer, size_t byteOffset, size_t byteStride, size_t itemCount)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ Ref<Buffer> buffer = (Buffer*)hbuffer;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryBuffer);
+ RTC_VERIFY_HANDLE(hgeometry);
+ RTC_VERIFY_HANDLE(hbuffer);
+
+ if (geometry->device != buffer->device)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"inputs are from different devices");
+
+ if (itemCount > 0xFFFFFFFFu)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"buffer too large");
+
+ geometry->setBuffer(type, slot, format, buffer, byteOffset, byteStride, (unsigned int)itemCount);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetSharedGeometryBuffer(RTCGeometry hgeometry, RTCBufferType type, unsigned int slot, RTCFormat format, const void* ptr, size_t byteOffset, size_t byteStride, size_t itemCount)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetSharedGeometryBuffer);
+ RTC_VERIFY_HANDLE(hgeometry);
+
+ if (itemCount > 0xFFFFFFFFu)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"buffer too large");
+
+ Ref<Buffer> buffer = new Buffer(geometry->device, itemCount*byteStride, (char*)ptr + byteOffset);
+ geometry->setBuffer(type, slot, format, buffer, 0, byteStride, (unsigned int)itemCount);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void* rtcSetNewGeometryBuffer(RTCGeometry hgeometry, RTCBufferType type, unsigned int slot, RTCFormat format, size_t byteStride, size_t itemCount)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetNewGeometryBuffer);
+ RTC_VERIFY_HANDLE(hgeometry);
+
+ if (itemCount > 0xFFFFFFFFu)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"buffer too large");
+
+ /* vertex buffers need to get overallocated slightly as elements are accessed using SSE loads */
+ size_t bytes = itemCount*byteStride;
+ if (type == RTC_BUFFER_TYPE_VERTEX || type == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE)
+ bytes += (16 - (byteStride%16))%16;
+
+ Ref<Buffer> buffer = new Buffer(geometry->device, bytes);
+ geometry->setBuffer(type, slot, format, buffer, 0, byteStride, (unsigned int)itemCount);
+ return buffer->data();
+ RTC_CATCH_END2(geometry);
+ return nullptr;
+ }
+
+ RTC_API void* rtcGetGeometryBufferData(RTCGeometry hgeometry, RTCBufferType type, unsigned int slot)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryBufferData);
+ RTC_VERIFY_HANDLE(hgeometry);
+ return geometry->getBuffer(type, slot);
+ RTC_CATCH_END2(geometry);
+ return nullptr;
+ }
+
+ RTC_API void rtcEnableGeometry (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcEnableGeometry);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->enable();
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcUpdateGeometryBuffer (RTCGeometry hgeometry, RTCBufferType type, unsigned int slot)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcUpdateGeometryBuffer);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->updateBuffer(type, slot);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcDisableGeometry (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcDisableGeometry);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->disable();
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryTessellationRate (RTCGeometry hgeometry, float tessellationRate)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryTessellationRate);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setTessellationRate(tessellationRate);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryUserData (RTCGeometry hgeometry, void* ptr)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryUserData);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setUserData(ptr);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void* rtcGetGeometryUserData (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry; // no ref counting here!
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryUserData);
+ RTC_VERIFY_HANDLE(hgeometry);
+ return geometry->getUserData();
+ RTC_CATCH_END2(geometry);
+ return nullptr;
+ }
+
+ RTC_API void rtcSetGeometryBoundsFunction (RTCGeometry hgeometry, RTCBoundsFunction bounds, void* userPtr)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryBoundsFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setBoundsFunction(bounds,userPtr);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryDisplacementFunction (RTCGeometry hgeometry, RTCDisplacementFunctionN displacement)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryDisplacementFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setDisplacementFunction(displacement);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryIntersectFunction (RTCGeometry hgeometry, RTCIntersectFunctionN intersect)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryIntersectFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setIntersectFunctionN(intersect);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryPointQueryFunction(RTCGeometry hgeometry, RTCPointQueryFunction pointQuery)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryPointQueryFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setPointQueryFunction(pointQuery);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API unsigned int rtcGetGeometryFirstHalfEdge(RTCGeometry hgeometry, unsigned int faceID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryFirstHalfEdge);
+ return geometry->getFirstHalfEdge(faceID);
+ RTC_CATCH_END2(geometry);
+ return -1;
+ }
+
+ RTC_API unsigned int rtcGetGeometryFace(RTCGeometry hgeometry, unsigned int edgeID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryFace);
+ return geometry->getFace(edgeID);
+ RTC_CATCH_END2(geometry);
+ return -1;
+ }
+
+ RTC_API unsigned int rtcGetGeometryNextHalfEdge(RTCGeometry hgeometry, unsigned int edgeID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryNextHalfEdge);
+ return geometry->getNextHalfEdge(edgeID);
+ RTC_CATCH_END2(geometry);
+ return -1;
+ }
+
+ RTC_API unsigned int rtcGetGeometryPreviousHalfEdge(RTCGeometry hgeometry, unsigned int edgeID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryPreviousHalfEdge);
+ return geometry->getPreviousHalfEdge(edgeID);
+ RTC_CATCH_END2(geometry);
+ return -1;
+ }
+
+ RTC_API unsigned int rtcGetGeometryOppositeHalfEdge(RTCGeometry hgeometry, unsigned int topologyID, unsigned int edgeID)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometryOppositeHalfEdge);
+ return geometry->getOppositeHalfEdge(topologyID,edgeID);
+ RTC_CATCH_END2(geometry);
+ return -1;
+ }
+
+ RTC_API void rtcSetGeometryOccludedFunction (RTCGeometry hgeometry, RTCOccludedFunctionN occluded)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetOccludedFunctionN);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setOccludedFunctionN(occluded);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryIntersectFilterFunction (RTCGeometry hgeometry, RTCFilterFunctionN filter)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryIntersectFilterFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setIntersectionFilterFunctionN(filter);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcSetGeometryOccludedFilterFunction (RTCGeometry hgeometry, RTCFilterFunctionN filter)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcSetGeometryOccludedFilterFunction);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->setOcclusionFilterFunctionN(filter);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcInterpolate(const RTCInterpolateArguments* const args)
+ {
+ Geometry* geometry = (Geometry*) args->geometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcInterpolate);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(args->geometry);
+#endif
+ geometry->interpolate(args);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcInterpolateN(const RTCInterpolateNArguments* const args)
+ {
+ Geometry* geometry = (Geometry*) args->geometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcInterpolateN);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(args->geometry);
+#endif
+ geometry->interpolateN(args);
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcCommitGeometry (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcCommitGeometry);
+ RTC_VERIFY_HANDLE(hgeometry);
+ return geometry->commit();
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API unsigned int rtcAttachGeometry (RTCScene hscene, RTCGeometry hgeometry)
+ {
+ Scene* scene = (Scene*) hscene;
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcAttachGeometry);
+ RTC_VERIFY_HANDLE(hscene);
+ RTC_VERIFY_HANDLE(hgeometry);
+ if (scene->device != geometry->device)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"inputs are from different devices");
+ return scene->bind(RTC_INVALID_GEOMETRY_ID,geometry);
+ RTC_CATCH_END2(scene);
+ return -1;
+ }
+
+ RTC_API void rtcAttachGeometryByID (RTCScene hscene, RTCGeometry hgeometry, unsigned int geomID)
+ {
+ Scene* scene = (Scene*) hscene;
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcAttachGeometryByID);
+ RTC_VERIFY_HANDLE(hscene);
+ RTC_VERIFY_HANDLE(hgeometry);
+ RTC_VERIFY_GEOMID(geomID);
+ if (scene->device != geometry->device)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"inputs are from different devices");
+ scene->bind(geomID,geometry);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcDetachGeometry (RTCScene hscene, unsigned int geomID)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcDetachGeometry);
+ RTC_VERIFY_HANDLE(hscene);
+ RTC_VERIFY_GEOMID(geomID);
+ scene->detachGeometry(geomID);
+ RTC_CATCH_END2(scene);
+ }
+
+ RTC_API void rtcRetainGeometry (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcRetainGeometry);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->refInc();
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API void rtcReleaseGeometry (RTCGeometry hgeometry)
+ {
+ Geometry* geometry = (Geometry*) hgeometry;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcReleaseGeometry);
+ RTC_VERIFY_HANDLE(hgeometry);
+ geometry->refDec();
+ RTC_CATCH_END2(geometry);
+ }
+
+ RTC_API RTCGeometry rtcGetGeometry (RTCScene hscene, unsigned int geomID)
+ {
+ Scene* scene = (Scene*) hscene;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcGetGeometry);
+#if defined(DEBUG)
+ RTC_VERIFY_HANDLE(hscene);
+ RTC_VERIFY_GEOMID(geomID);
+#endif
+ return (RTCGeometry) scene->get(geomID);
+ RTC_CATCH_END2(scene);
+ return nullptr;
+ }
+
+RTC_NAMESPACE_END
diff --git a/thirdparty/embree/kernels/common/rtcore.h b/thirdparty/embree/kernels/common/rtcore.h
new file mode 100644
index 0000000000..373e49a689
--- /dev/null
+++ b/thirdparty/embree/kernels/common/rtcore.h
@@ -0,0 +1,142 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../../include/embree3/rtcore.h"
+RTC_NAMESPACE_USE
+
+namespace embree
+{
+ /*! decoding of intersection flags */
+ __forceinline bool isCoherent (RTCIntersectContextFlags flags) { return (flags & RTC_INTERSECT_CONTEXT_FLAG_COHERENT) == RTC_INTERSECT_CONTEXT_FLAG_COHERENT; }
+ __forceinline bool isIncoherent(RTCIntersectContextFlags flags) { return (flags & RTC_INTERSECT_CONTEXT_FLAG_COHERENT) == RTC_INTERSECT_CONTEXT_FLAG_INCOHERENT; }
+
+#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR >= 8)
+# define USE_TASK_ARENA 1
+#else
+# define USE_TASK_ARENA 0
+#endif
+
+#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION >= 11009) // TBB 2019 Update 9
+# define TASKING_TBB_USE_TASK_ISOLATION 1
+#else
+# define TASKING_TBB_USE_TASK_ISOLATION 0
+#endif
+
+/*! Macros used in the rtcore API implementation */
+// -- GODOT start --
+// #define RTC_CATCH_BEGIN try {
+#define RTC_CATCH_BEGIN
+
+// #define RTC_CATCH_END(device) \
+// } catch (std::bad_alloc&) { \
+// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+// } catch (rtcore_error& e) { \
+// Device::process_error(device,e.error,e.what()); \
+// } catch (std::exception& e) { \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+// } catch (...) { \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+// }
+#define RTC_CATCH_END(device)
+
+// #define RTC_CATCH_END2(scene) \
+// } catch (std::bad_alloc&) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+// } catch (rtcore_error& e) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,e.error,e.what()); \
+// } catch (std::exception& e) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+// } catch (...) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+// }
+#define RTC_CATCH_END2(scene)
+
+// #define RTC_CATCH_END2_FALSE(scene) \
+// } catch (std::bad_alloc&) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+// return false; \
+// } catch (rtcore_error& e) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,e.error,e.what()); \
+// return false; \
+// } catch (std::exception& e) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+// return false; \
+// } catch (...) { \
+// Device* device = scene ? scene->device : nullptr; \
+// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+// return false; \
+// }
+#define RTC_CATCH_END2_FALSE(scene) return false;
+// -- GODOT end --
+
+#define RTC_VERIFY_HANDLE(handle) \
+ if (handle == nullptr) { \
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"invalid argument"); \
+ }
+
+#define RTC_VERIFY_GEOMID(id) \
+ if (id == RTC_INVALID_GEOMETRY_ID) { \
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"invalid argument"); \
+ }
+
+#define RTC_VERIFY_UPPER(id,upper) \
+ if (id > upper) { \
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"invalid argument"); \
+ }
+
+#define RTC_VERIFY_RANGE(id,lower,upper) \
+ if (id < lower || id > upper) \
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"argument out of bounds");
+
+#if 0 // enable to debug print all API calls
+#define RTC_TRACE(x) std::cout << #x << std::endl;
+#else
+#define RTC_TRACE(x)
+#endif
+
+// -- GODOT begin --
+// /*! used to throw embree API errors */
+// struct rtcore_error : public std::exception
+// {
+// __forceinline rtcore_error(RTCError error, const std::string& str)
+// : error(error), str(str) {}
+//
+// ~rtcore_error() throw() {}
+//
+// const char* what () const throw () {
+// return str.c_str();
+// }
+//
+// RTCError error;
+// std::string str;
+// };
+// -- GODOT end --
+
+#if defined(DEBUG) // only report file and line in debug mode
+ // -- GODOT begin --
+ // #define throw_RTCError(error,str) \
+ // throw rtcore_error(error,std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
+ #define throw_RTCError(error,str) \
+ printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
+ // -- GODOT end --
+#else
+ // -- GODOT begin --
+ // #define throw_RTCError(error,str) \
+ // throw rtcore_error(error,str);
+ #define throw_RTCError(error,str) \
+ abort();
+ // -- GODOT end --
+#endif
+
+#define RTC_BUILD_ARGUMENTS_HAS(settings,member) \
+ (settings.byteSize > (offsetof(RTCBuildArguments,member)+sizeof(settings.member)))
+}
diff --git a/thirdparty/embree/kernels/common/rtcore_builder.cpp b/thirdparty/embree/kernels/common/rtcore_builder.cpp
new file mode 100644
index 0000000000..1f1b6f6ddf
--- /dev/null
+++ b/thirdparty/embree/kernels/common/rtcore_builder.cpp
@@ -0,0 +1,442 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#define RTC_EXPORT_API
+
+#include "default.h"
+#include "device.h"
+#include "scene.h"
+#include "context.h"
+#include "alloc.h"
+
+#include "../builders/bvh_builder_sah.h"
+#include "../builders/bvh_builder_morton.h"
+
+namespace embree
+{
+ namespace isa // FIXME: support more ISAs for builders
+ {
+ struct BVH : public RefCount
+ {
+ BVH (Device* device)
+ : device(device), allocator(device,true), morton_src(device,0), morton_tmp(device,0)
+ {
+ device->refInc();
+ }
+
+ ~BVH() {
+ device->refDec();
+ }
+
+ public:
+ Device* device;
+ FastAllocator allocator;
+ mvector<BVHBuilderMorton::BuildPrim> morton_src;
+ mvector<BVHBuilderMorton::BuildPrim> morton_tmp;
+ };
+
+ void* rtcBuildBVHMorton(const RTCBuildArguments* arguments)
+ {
+ BVH* bvh = (BVH*) arguments->bvh;
+ RTCBuildPrimitive* prims_i = arguments->primitives;
+ size_t primitiveCount = arguments->primitiveCount;
+ RTCCreateNodeFunction createNode = arguments->createNode;
+ RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;
+ RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;
+ RTCCreateLeafFunction createLeaf = arguments->createLeaf;
+ RTCProgressMonitorFunction buildProgress = arguments->buildProgress;
+ void* userPtr = arguments->userPtr;
+
+ std::atomic<size_t> progress(0);
+
+ /* initialize temporary arrays for morton builder */
+ PrimRef* prims = (PrimRef*) prims_i;
+ mvector<BVHBuilderMorton::BuildPrim>& morton_src = bvh->morton_src;
+ mvector<BVHBuilderMorton::BuildPrim>& morton_tmp = bvh->morton_tmp;
+ morton_src.resize(primitiveCount);
+ morton_tmp.resize(primitiveCount);
+
+ /* compute centroid bounds */
+ const BBox3fa centBounds = parallel_reduce ( size_t(0), primitiveCount, BBox3fa(empty), [&](const range<size_t>& r) -> BBox3fa {
+
+ BBox3fa bounds(empty);
+ for (size_t i=r.begin(); i<r.end(); i++)
+ bounds.extend(prims[i].bounds().center2());
+ return bounds;
+ }, BBox3fa::merge);
+
+ /* compute morton codes */
+ BVHBuilderMorton::MortonCodeMapping mapping(centBounds);
+ parallel_for ( size_t(0), primitiveCount, [&](const range<size_t>& r) {
+ BVHBuilderMorton::MortonCodeGenerator generator(mapping,&morton_src[r.begin()]);
+ for (size_t i=r.begin(); i<r.end(); i++) {
+ generator(prims[i].bounds(),(unsigned) i);
+ }
+ });
+
+ /* start morton build */
+ std::pair<void*,BBox3fa> root = BVHBuilderMorton::build<std::pair<void*,BBox3fa>>(
+
+ /* thread local allocator for fast allocations */
+ [&] () -> FastAllocator::CachedAllocator {
+ return bvh->allocator.getCachedAllocator();
+ },
+
+ /* lambda function that allocates BVH nodes */
+ [&] ( const FastAllocator::CachedAllocator& alloc, size_t N ) -> void* {
+ return createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);
+ },
+
+ /* lambda function that sets bounds */
+ [&] (void* node, const std::pair<void*,BBox3fa>* children, size_t N) -> std::pair<void*,BBox3fa>
+ {
+ BBox3fa bounds = empty;
+ void* childptrs[BVHBuilderMorton::MAX_BRANCHING_FACTOR];
+ const RTCBounds* cbounds[BVHBuilderMorton::MAX_BRANCHING_FACTOR];
+ for (size_t i=0; i<N; i++) {
+ bounds.extend(children[i].second);
+ childptrs[i] = children[i].first;
+ cbounds[i] = (const RTCBounds*)&children[i].second;
+ }
+ setNodeBounds(node,cbounds,(unsigned int)N,userPtr);
+ setNodeChildren(node,childptrs, (unsigned int)N,userPtr);
+ return std::make_pair(node,bounds);
+ },
+
+ /* lambda function that creates BVH leaves */
+ [&]( const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc) -> std::pair<void*,BBox3fa>
+ {
+ RTCBuildPrimitive localBuildPrims[RTC_BUILD_MAX_PRIMITIVES_PER_LEAF];
+ BBox3fa bounds = empty;
+ for (size_t i=0;i<current.size();i++)
+ {
+ const size_t id = morton_src[current.begin()+i].index;
+ bounds.extend(prims[id].bounds());
+ localBuildPrims[i] = prims_i[id];
+ }
+ void* node = createLeaf((RTCThreadLocalAllocator)&alloc,localBuildPrims,current.size(),userPtr);
+ return std::make_pair(node,bounds);
+ },
+
+ /* lambda that calculates the bounds for some primitive */
+ [&] (const BVHBuilderMorton::BuildPrim& morton) -> BBox3fa {
+ return prims[morton.index].bounds();
+ },
+
+ /* progress monitor function */
+ [&] (size_t dn) {
+ if (!buildProgress) return true;
+ const size_t n = progress.fetch_add(dn)+dn;
+ const double f = std::min(1.0,double(n)/double(primitiveCount));
+ return buildProgress(userPtr,f);
+ },
+
+ morton_src.data(),morton_tmp.data(),primitiveCount,
+ *arguments);
+
+ bvh->allocator.cleanup();
+ return root.first;
+ }
+
+ void* rtcBuildBVHBinnedSAH(const RTCBuildArguments* arguments)
+ {
+ BVH* bvh = (BVH*) arguments->bvh;
+ RTCBuildPrimitive* prims = arguments->primitives;
+ size_t primitiveCount = arguments->primitiveCount;
+ RTCCreateNodeFunction createNode = arguments->createNode;
+ RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;
+ RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;
+ RTCCreateLeafFunction createLeaf = arguments->createLeaf;
+ RTCProgressMonitorFunction buildProgress = arguments->buildProgress;
+ void* userPtr = arguments->userPtr;
+
+ std::atomic<size_t> progress(0);
+
+ /* calculate priminfo */
+ auto computeBounds = [&](const range<size_t>& r) -> CentGeomBBox3fa
+ {
+ CentGeomBBox3fa bounds(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ bounds.extend((BBox3fa&)prims[j]);
+ return bounds;
+ };
+ const CentGeomBBox3fa bounds =
+ parallel_reduce(size_t(0),primitiveCount,size_t(1024),size_t(1024),CentGeomBBox3fa(empty), computeBounds, CentGeomBBox3fa::merge2);
+
+ const PrimInfo pinfo(0,primitiveCount,bounds);
+
+ /* build BVH */
+ void* root = BVHBuilderBinnedSAH::build<void*>(
+
+ /* thread local allocator for fast allocations */
+ [&] () -> FastAllocator::CachedAllocator {
+ return bvh->allocator.getCachedAllocator();
+ },
+
+ /* lambda function that creates BVH nodes */
+ [&](BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, const FastAllocator::CachedAllocator& alloc) -> void*
+ {
+ void* node = createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);
+ const RTCBounds* cbounds[GeneralBVHBuilder::MAX_BRANCHING_FACTOR];
+ for (size_t i=0; i<N; i++) cbounds[i] = (const RTCBounds*) &children[i].prims.geomBounds;
+ setNodeBounds(node,cbounds, (unsigned int)N,userPtr);
+ return node;
+ },
+
+ /* lambda function that updates BVH nodes */
+ [&](const BVHBuilderBinnedSAH::BuildRecord& precord, const BVHBuilderBinnedSAH::BuildRecord* crecords, void* node, void** children, const size_t N) -> void* {
+ setNodeChildren(node,children, (unsigned int)N,userPtr);
+ return node;
+ },
+
+ /* lambda function that creates BVH leaves */
+ [&](const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> void* {
+ return createLeaf((RTCThreadLocalAllocator)&alloc,(RTCBuildPrimitive*)(prims+range.begin()),range.size(),userPtr);
+ },
+
+ /* progress monitor function */
+ [&] (size_t dn) {
+ if (!buildProgress) return true;
+ const size_t n = progress.fetch_add(dn)+dn;
+ const double f = std::min(1.0,double(n)/double(primitiveCount));
+ return buildProgress(userPtr,f);
+ },
+
+ (PrimRef*)prims,pinfo,*arguments);
+
+ bvh->allocator.cleanup();
+ return root;
+ }
+
+ static __forceinline const std::pair<CentGeomBBox3fa,unsigned int> mergePair(const std::pair<CentGeomBBox3fa,unsigned int>& a, const std::pair<CentGeomBBox3fa,unsigned int>& b) {
+ CentGeomBBox3fa centBounds = CentGeomBBox3fa::merge2(a.first,b.first);
+ unsigned int maxGeomID = max(a.second,b.second);
+ return std::pair<CentGeomBBox3fa,unsigned int>(centBounds,maxGeomID);
+ }
+
+ void* rtcBuildBVHSpatialSAH(const RTCBuildArguments* arguments)
+ {
+ BVH* bvh = (BVH*) arguments->bvh;
+ RTCBuildPrimitive* prims = arguments->primitives;
+ size_t primitiveCount = arguments->primitiveCount;
+ RTCCreateNodeFunction createNode = arguments->createNode;
+ RTCSetNodeChildrenFunction setNodeChildren = arguments->setNodeChildren;
+ RTCSetNodeBoundsFunction setNodeBounds = arguments->setNodeBounds;
+ RTCCreateLeafFunction createLeaf = arguments->createLeaf;
+ RTCSplitPrimitiveFunction splitPrimitive = arguments->splitPrimitive;
+ RTCProgressMonitorFunction buildProgress = arguments->buildProgress;
+ void* userPtr = arguments->userPtr;
+
+ std::atomic<size_t> progress(0);
+
+ /* calculate priminfo */
+
+ auto computeBounds = [&](const range<size_t>& r) -> std::pair<CentGeomBBox3fa,unsigned int>
+ {
+ CentGeomBBox3fa bounds(empty);
+ unsigned maxGeomID = 0;
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ bounds.extend((BBox3fa&)prims[j]);
+ maxGeomID = max(maxGeomID,prims[j].geomID);
+ }
+ return std::pair<CentGeomBBox3fa,unsigned int>(bounds,maxGeomID);
+ };
+
+
+ const std::pair<CentGeomBBox3fa,unsigned int> pair =
+ parallel_reduce(size_t(0),primitiveCount,size_t(1024),size_t(1024),std::pair<CentGeomBBox3fa,unsigned int>(CentGeomBBox3fa(empty),0), computeBounds, mergePair);
+
+ CentGeomBBox3fa bounds = pair.first;
+ const unsigned int maxGeomID = pair.second;
+
+ if (unlikely(maxGeomID >= ((unsigned int)1 << (32-RESERVED_NUM_SPATIAL_SPLITS_GEOMID_BITS))))
+ {
+ /* fallback code for max geomID larger than threshold */
+ return rtcBuildBVHBinnedSAH(arguments);
+ }
+
+ const PrimInfo pinfo(0,primitiveCount,bounds);
+
+ /* function that splits a build primitive */
+ struct Splitter
+ {
+ Splitter (RTCSplitPrimitiveFunction splitPrimitive, unsigned geomID, unsigned primID, void* userPtr)
+ : splitPrimitive(splitPrimitive), geomID(geomID), primID(primID), userPtr(userPtr) {}
+
+ __forceinline void operator() (PrimRef& prim, const size_t dim, const float pos, PrimRef& left_o, PrimRef& right_o) const
+ {
+ prim.geomIDref() &= BVHBuilderBinnedFastSpatialSAH::GEOMID_MASK;
+ splitPrimitive((RTCBuildPrimitive*)&prim,(unsigned)dim,pos,(RTCBounds*)&left_o,(RTCBounds*)&right_o,userPtr);
+ left_o.geomIDref() = geomID; left_o.primIDref() = primID;
+ right_o.geomIDref() = geomID; right_o.primIDref() = primID;
+ }
+
+ __forceinline void operator() (const BBox3fa& box, const size_t dim, const float pos, BBox3fa& left_o, BBox3fa& right_o) const
+ {
+ PrimRef prim(box,geomID & BVHBuilderBinnedFastSpatialSAH::GEOMID_MASK,primID);
+ splitPrimitive((RTCBuildPrimitive*)&prim,(unsigned)dim,pos,(RTCBounds*)&left_o,(RTCBounds*)&right_o,userPtr);
+ }
+
+ RTCSplitPrimitiveFunction splitPrimitive;
+ unsigned geomID;
+ unsigned primID;
+ void* userPtr;
+ };
+
+ /* build BVH */
+ void* root = BVHBuilderBinnedFastSpatialSAH::build<void*>(
+
+ /* thread local allocator for fast allocations */
+ [&] () -> FastAllocator::CachedAllocator {
+ return bvh->allocator.getCachedAllocator();
+ },
+
+ /* lambda function that creates BVH nodes */
+ [&] (BVHBuilderBinnedFastSpatialSAH::BuildRecord* children, const size_t N, const FastAllocator::CachedAllocator& alloc) -> void*
+ {
+ void* node = createNode((RTCThreadLocalAllocator)&alloc, (unsigned int)N,userPtr);
+ const RTCBounds* cbounds[GeneralBVHBuilder::MAX_BRANCHING_FACTOR];
+ for (size_t i=0; i<N; i++) cbounds[i] = (const RTCBounds*) &children[i].prims.geomBounds;
+ setNodeBounds(node,cbounds, (unsigned int)N,userPtr);
+ return node;
+ },
+
+ /* lambda function that updates BVH nodes */
+ [&] (const BVHBuilderBinnedFastSpatialSAH::BuildRecord& precord, const BVHBuilderBinnedFastSpatialSAH::BuildRecord* crecords, void* node, void** children, const size_t N) -> void* {
+ setNodeChildren(node,children, (unsigned int)N,userPtr);
+ return node;
+ },
+
+ /* lambda function that creates BVH leaves */
+ [&] (const PrimRef* prims, const range<size_t>& range, const FastAllocator::CachedAllocator& alloc) -> void* {
+ return createLeaf((RTCThreadLocalAllocator)&alloc,(RTCBuildPrimitive*)(prims+range.begin()),range.size(),userPtr);
+ },
+
+ /* returns the splitter */
+ [&] ( const PrimRef& prim ) -> Splitter {
+ return Splitter(splitPrimitive,prim.geomID(),prim.primID(),userPtr);
+ },
+
+ /* progress monitor function */
+ [&] (size_t dn) {
+ if (!buildProgress) return true;
+ const size_t n = progress.fetch_add(dn)+dn;
+ const double f = std::min(1.0,double(n)/double(primitiveCount));
+ return buildProgress(userPtr,f);
+ },
+
+ (PrimRef*)prims,
+ arguments->primitiveArrayCapacity,
+ pinfo,*arguments);
+
+ bvh->allocator.cleanup();
+ return root;
+ }
+ }
+}
+
+using namespace embree;
+using namespace embree::isa;
+
+RTC_NAMESPACE_BEGIN
+
+ RTC_API RTCBVH rtcNewBVH(RTCDevice device)
+ {
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcNewAllocator);
+ RTC_VERIFY_HANDLE(device);
+ BVH* bvh = new BVH((Device*)device);
+ return (RTCBVH) bvh->refInc();
+ RTC_CATCH_END((Device*)device);
+ return nullptr;
+ }
+
+ RTC_API void* rtcBuildBVH(const RTCBuildArguments* arguments)
+ {
+ BVH* bvh = (BVH*) arguments->bvh;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcBuildBVH);
+ RTC_VERIFY_HANDLE(bvh);
+ RTC_VERIFY_HANDLE(arguments);
+ RTC_VERIFY_HANDLE(arguments->createNode);
+ RTC_VERIFY_HANDLE(arguments->setNodeChildren);
+ RTC_VERIFY_HANDLE(arguments->setNodeBounds);
+ RTC_VERIFY_HANDLE(arguments->createLeaf);
+
+ if (arguments->primitiveArrayCapacity < arguments->primitiveCount)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"primitiveArrayCapacity must be greater or equal to primitiveCount")
+
+ /* initialize the allocator */
+ bvh->allocator.init_estimate(arguments->primitiveCount*sizeof(BBox3fa));
+ bvh->allocator.reset();
+
+ /* switch between differnet builders based on quality level */
+ if (arguments->buildQuality == RTC_BUILD_QUALITY_LOW)
+ return rtcBuildBVHMorton(arguments);
+ else if (arguments->buildQuality == RTC_BUILD_QUALITY_MEDIUM)
+ return rtcBuildBVHBinnedSAH(arguments);
+ else if (arguments->buildQuality == RTC_BUILD_QUALITY_HIGH) {
+ if (arguments->splitPrimitive == nullptr || arguments->primitiveArrayCapacity <= arguments->primitiveCount)
+ return rtcBuildBVHBinnedSAH(arguments);
+ else
+ return rtcBuildBVHSpatialSAH(arguments);
+ }
+ else
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid build quality");
+
+ /* if we are in dynamic mode, then do not clear temporary data */
+ if (!(arguments->buildFlags & RTC_BUILD_FLAG_DYNAMIC))
+ {
+ bvh->morton_src.clear();
+ bvh->morton_tmp.clear();
+ }
+
+ RTC_CATCH_END(bvh->device);
+ return nullptr;
+ }
+
+ RTC_API void* rtcThreadLocalAlloc(RTCThreadLocalAllocator localAllocator, size_t bytes, size_t align)
+ {
+ FastAllocator::CachedAllocator* alloc = (FastAllocator::CachedAllocator*) localAllocator;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcThreadLocalAlloc);
+ return alloc->malloc0(bytes,align);
+ RTC_CATCH_END(alloc->alloc->getDevice());
+ return nullptr;
+ }
+
+ RTC_API void rtcMakeStaticBVH(RTCBVH hbvh)
+ {
+ BVH* bvh = (BVH*) hbvh;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcStaticBVH);
+ RTC_VERIFY_HANDLE(hbvh);
+ bvh->morton_src.clear();
+ bvh->morton_tmp.clear();
+ RTC_CATCH_END(bvh->device);
+ }
+
+ RTC_API void rtcRetainBVH(RTCBVH hbvh)
+ {
+ BVH* bvh = (BVH*) hbvh;
+ Device* device = bvh ? bvh->device : nullptr;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcRetainBVH);
+ RTC_VERIFY_HANDLE(hbvh);
+ bvh->refInc();
+ RTC_CATCH_END(device);
+ }
+
+ RTC_API void rtcReleaseBVH(RTCBVH hbvh)
+ {
+ BVH* bvh = (BVH*) hbvh;
+ Device* device = bvh ? bvh->device : nullptr;
+ RTC_CATCH_BEGIN;
+ RTC_TRACE(rtcReleaseBVH);
+ RTC_VERIFY_HANDLE(hbvh);
+ bvh->refDec();
+ RTC_CATCH_END(device);
+ }
+
+RTC_NAMESPACE_END
diff --git a/thirdparty/embree/kernels/common/scene.cpp b/thirdparty/embree/kernels/common/scene.cpp
new file mode 100644
index 0000000000..408d7eae6f
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene.cpp
@@ -0,0 +1,955 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "scene.h"
+
+#include "../bvh/bvh4_factory.h"
+#include "../bvh/bvh8_factory.h"
+#include "../../common/algorithms/parallel_reduce.h"
+
+namespace embree
+{
+ /* error raising rtcIntersect and rtcOccluded functions */
+ void missing_rtcCommit() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); }
+ void invalid_rtcIntersect1() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect and rtcOccluded not enabled"); }
+ void invalid_rtcIntersect4() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect4 and rtcOccluded4 not enabled"); }
+ void invalid_rtcIntersect8() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect8 and rtcOccluded8 not enabled"); }
+ void invalid_rtcIntersect16() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect16 and rtcOccluded16 not enabled"); }
+ void invalid_rtcIntersectN() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersectN and rtcOccludedN not enabled"); }
+
+ Scene::Scene (Device* device)
+ : device(device),
+ flags_modified(true), enabled_geometry_types(0),
+ scene_flags(RTC_SCENE_FLAG_NONE),
+ quality_flags(RTC_BUILD_QUALITY_MEDIUM),
+ is_build(false), modified(true),
+ progressInterface(this), progress_monitor_function(nullptr), progress_monitor_ptr(nullptr), progress_monitor_counter(0)
+ {
+ device->refInc();
+
+ intersectors = Accel::Intersectors(missing_rtcCommit);
+
+ /* one can overwrite flags through device for debugging */
+ if (device->quality_flags != -1)
+ quality_flags = (RTCBuildQuality) device->quality_flags;
+ if (device->scene_flags != -1)
+ scene_flags = (RTCSceneFlags) device->scene_flags;
+ }
+
+ Scene::~Scene() noexcept
+ {
+ device->refDec();
+ }
+
+ void Scene::printStatistics()
+ {
+ /* calculate maximum number of time segments */
+ unsigned max_time_steps = 0;
+ for (size_t i=0; i<size(); i++) {
+ if (!get(i)) continue;
+ max_time_steps = max(max_time_steps,get(i)->numTimeSteps);
+ }
+
+ /* initialize vectors*/
+ std::vector<size_t> statistics[Geometry::GTY_END];
+ for (size_t i=0; i<Geometry::GTY_END; i++)
+ statistics[i].resize(max_time_steps);
+
+ /* gather statistics */
+ for (size_t i=0; i<size(); i++)
+ {
+ if (!get(i)) continue;
+ int ty = get(i)->getType();
+ assert(ty<Geometry::GTY_END);
+ int timesegments = get(i)->numTimeSegments();
+ assert((unsigned int)timesegments < max_time_steps);
+ statistics[ty][timesegments] += get(i)->size();
+ }
+
+ /* print statistics */
+ std::cout << std::setw(23) << "segments" << ": ";
+ for (size_t t=0; t<max_time_steps; t++)
+ std::cout << std::setw(10) << t;
+ std::cout << std::endl;
+
+ std::cout << "-------------------------";
+ for (size_t t=0; t<max_time_steps; t++)
+ std::cout << "----------";
+ std::cout << std::endl;
+
+ for (size_t p=0; p<Geometry::GTY_END; p++)
+ {
+ if (std::string(Geometry::gtype_names[p]) == "") continue;
+ std::cout << std::setw(23) << Geometry::gtype_names[p] << ": ";
+ for (size_t t=0; t<max_time_steps; t++)
+ std::cout << std::setw(10) << statistics[p][t];
+ std::cout << std::endl;
+ }
+ }
+
+ void Scene::createTriangleAccel()
+ {
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ if (device->tri_accel == "default")
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW)
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ {
+ if (quality_flags == RTC_BUILD_QUALITY_HIGH)
+ accels_add(device->bvh8_factory->BVH8Triangle4(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
+ else
+ accels_add(device->bvh8_factory->BVH8Triangle4(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ }
+ else
+#endif
+ {
+ if (quality_flags == RTC_BUILD_QUALITY_HIGH)
+ accels_add(device->bvh4_factory->BVH4Triangle4(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
+ else
+ accels_add(device->bvh4_factory->BVH4Triangle4(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ }
+ break;
+
+ case /*0b01*/ 1:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ accels_add(device->bvh8_factory->BVH8Triangle4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4Triangle4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+
+ break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else /* dynamic */
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8Triangle4 (this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8Triangle4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else
+#endif
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4Triangle4 (this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4Triangle4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4i(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ }
+ }
+ else if (device->tri_accel == "bvh4.triangle4") accels_add(device->bvh4_factory->BVH4Triangle4 (this));
+ else if (device->tri_accel == "bvh4.triangle4v") accels_add(device->bvh4_factory->BVH4Triangle4v(this));
+ else if (device->tri_accel == "bvh4.triangle4i") accels_add(device->bvh4_factory->BVH4Triangle4i(this));
+ else if (device->tri_accel == "qbvh4.triangle4i") accels_add(device->bvh4_factory->BVH4QuantizedTriangle4i(this));
+
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->tri_accel == "bvh8.triangle4") accels_add(device->bvh8_factory->BVH8Triangle4 (this));
+ else if (device->tri_accel == "bvh8.triangle4v") accels_add(device->bvh8_factory->BVH8Triangle4v(this));
+ else if (device->tri_accel == "bvh8.triangle4i") accels_add(device->bvh8_factory->BVH8Triangle4i(this));
+ else if (device->tri_accel == "qbvh8.triangle4i") accels_add(device->bvh8_factory->BVH8QuantizedTriangle4i(this));
+ else if (device->tri_accel == "qbvh8.triangle4") accels_add(device->bvh8_factory->BVH8QuantizedTriangle4(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown triangle acceleration structure "+device->tri_accel);
+#endif
+ }
+
+ void Scene::createTriangleMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ if (device->tri_accel_mb == "default")
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX2()) // BVH8 reduces performance on AVX only-machines
+ {
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else
+#endif
+ {
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Triangle4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ }
+ else if (device->tri_accel_mb == "bvh4.triangle4imb") accels_add(device->bvh4_factory->BVH4Triangle4iMB(this));
+ else if (device->tri_accel_mb == "bvh4.triangle4vmb") accels_add(device->bvh4_factory->BVH4Triangle4vMB(this));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->tri_accel_mb == "bvh8.triangle4imb") accels_add(device->bvh8_factory->BVH8Triangle4iMB(this));
+ else if (device->tri_accel_mb == "bvh8.triangle4vmb") accels_add(device->bvh8_factory->BVH8Triangle4vMB(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown motion blur triangle acceleration structure "+device->tri_accel_mb);
+#endif
+ }
+
+ void Scene::createQuadAccel()
+ {
+#if defined(EMBREE_GEOMETRY_QUAD)
+ if (device->quad_accel == "default")
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW)
+ {
+ /* static */
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ {
+ if (quality_flags == RTC_BUILD_QUALITY_HIGH)
+ accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
+ else
+ accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ }
+ else
+#endif
+ {
+ if (quality_flags == RTC_BUILD_QUALITY_HIGH)
+ accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::HIGH_QUALITY,BVHFactory::IntersectVariant::FAST));
+ else
+ accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ }
+ break;
+
+ case /*0b01*/ 1:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+ break;
+
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4i(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else /* dynamic */
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else
+#endif
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4v(this,BVHFactory::BuildVariant::DYNAMIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ }
+ }
+ else if (device->quad_accel == "bvh4.quad4v") accels_add(device->bvh4_factory->BVH4Quad4v(this));
+ else if (device->quad_accel == "bvh4.quad4i") accels_add(device->bvh4_factory->BVH4Quad4i(this));
+ else if (device->quad_accel == "qbvh4.quad4i") accels_add(device->bvh4_factory->BVH4QuantizedQuad4i(this));
+
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->quad_accel == "bvh8.quad4v") accels_add(device->bvh8_factory->BVH8Quad4v(this));
+ else if (device->quad_accel == "bvh8.quad4i") accels_add(device->bvh8_factory->BVH8Quad4i(this));
+ else if (device->quad_accel == "qbvh8.quad4i") accels_add(device->bvh8_factory->BVH8QuantizedQuad4i(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown quad acceleration structure "+device->quad_accel);
+#endif
+ }
+
+ void Scene::createQuadMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_QUAD)
+ if (device->quad_accel_mb == "default")
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+ switch (mode) {
+ case /*0b00*/ 0:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ accels_add(device->bvh8_factory->BVH8Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST));
+ break;
+
+ case /*0b01*/ 1:
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX())
+ accels_add(device->bvh8_factory->BVH8Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST));
+ break;
+
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::FAST )); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4Quad4iMB(this,BVHFactory::BuildVariant::STATIC,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else if (device->quad_accel_mb == "bvh4.quad4imb") accels_add(device->bvh4_factory->BVH4Quad4iMB(this));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->quad_accel_mb == "bvh8.quad4imb") accels_add(device->bvh8_factory->BVH8Quad4iMB(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown quad motion blur acceleration structure "+device->quad_accel_mb);
+#endif
+ }
+
+ void Scene::createHairAccel()
+ {
+#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT)
+ if (device->hair_accel == "default")
+ {
+ int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel();
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX2()) // only enable on HSW machines, for SNB this codepath is slower
+ {
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8v(this,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b01*/ 1: accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8v(this,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8i(this,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8i(this,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ else
+#endif
+ {
+ switch (mode) {
+ case /*0b00*/ 0: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4v(this,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b01*/ 1: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4v(this,BVHFactory::IntersectVariant::ROBUST)); break;
+ case /*0b10*/ 2: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4i(this,BVHFactory::IntersectVariant::FAST)); break;
+ case /*0b11*/ 3: accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4i(this,BVHFactory::IntersectVariant::ROBUST)); break;
+ }
+ }
+ }
+ else if (device->hair_accel == "bvh4obb.virtualcurve4v" ) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4v(this,BVHFactory::IntersectVariant::FAST));
+ else if (device->hair_accel == "bvh4obb.virtualcurve4i" ) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4i(this,BVHFactory::IntersectVariant::FAST));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->hair_accel == "bvh8obb.virtualcurve8v" ) accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8v(this,BVHFactory::IntersectVariant::FAST));
+ else if (device->hair_accel == "bvh4obb.virtualcurve8i" ) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8i(this,BVHFactory::IntersectVariant::FAST));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown hair acceleration structure "+device->hair_accel);
+#endif
+ }
+
+ void Scene::createHairMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT)
+ if (device->hair_accel_mb == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX2()) // only enable on HSW machines, on SNB this codepath is slower
+ {
+ if (isRobustAccel()) accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::ROBUST));
+ else accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::FAST));
+ }
+ else
+#endif
+ {
+ if (isRobustAccel()) accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4iMB(this,BVHFactory::IntersectVariant::ROBUST));
+ else accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4iMB(this,BVHFactory::IntersectVariant::FAST));
+ }
+ }
+ else if (device->hair_accel_mb == "bvh4.virtualcurve4imb") accels_add(device->bvh4_factory->BVH4OBBVirtualCurve4iMB(this,BVHFactory::IntersectVariant::FAST));
+
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->hair_accel_mb == "bvh4.virtualcurve8imb") accels_add(device->bvh4_factory->BVH4OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::FAST));
+ else if (device->hair_accel_mb == "bvh8.virtualcurve8imb") accels_add(device->bvh8_factory->BVH8OBBVirtualCurve8iMB(this,BVHFactory::IntersectVariant::FAST));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown motion blur hair acceleration structure "+device->hair_accel_mb);
+#endif
+ }
+
+ void Scene::createSubdivAccel()
+ {
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ if (device->subdiv_accel == "default") {
+ accels_add(device->bvh4_factory->BVH4SubdivPatch1(this));
+ }
+ else if (device->subdiv_accel == "bvh4.grid.eager" ) accels_add(device->bvh4_factory->BVH4SubdivPatch1(this));
+ else if (device->subdiv_accel == "bvh4.subdivpatch1eager" ) accels_add(device->bvh4_factory->BVH4SubdivPatch1(this));
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown subdiv accel "+device->subdiv_accel);
+#endif
+ }
+
+ void Scene::createSubdivMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ if (device->subdiv_accel_mb == "default") {
+ accels_add(device->bvh4_factory->BVH4SubdivPatch1MB(this));
+ }
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown subdiv mblur accel "+device->subdiv_accel_mb);
+#endif
+ }
+
+ void Scene::createUserGeometryAccel()
+ {
+#if defined(EMBREE_GEOMETRY_USER)
+ if (device->object_accel == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel())
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh8_factory->BVH8UserGeometry(this,BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh8_factory->BVH8UserGeometry(this,BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ else
+#endif
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh4_factory->BVH4UserGeometry(this,BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh4_factory->BVH4UserGeometry(this,BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ }
+ else if (device->object_accel == "bvh4.object") accels_add(device->bvh4_factory->BVH4UserGeometry(this));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->object_accel == "bvh8.object") accels_add(device->bvh8_factory->BVH8UserGeometry(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown user geometry accel "+device->object_accel);
+#endif
+ }
+
+ void Scene::createUserGeometryMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_USER)
+ if (device->object_accel_mb == "default" ) {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel())
+ accels_add(device->bvh8_factory->BVH8UserGeometryMB(this));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4UserGeometryMB(this));
+ }
+ else if (device->object_accel_mb == "bvh4.object") accels_add(device->bvh4_factory->BVH4UserGeometryMB(this));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->object_accel_mb == "bvh8.object") accels_add(device->bvh8_factory->BVH8UserGeometryMB(this));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown user geometry mblur accel "+device->object_accel_mb);
+#endif
+ }
+
+ void Scene::createInstanceAccel()
+ {
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ // if (device->object_accel == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel()) {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh8_factory->BVH8Instance(this, false, BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh8_factory->BVH8Instance(this, false, BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ else
+#endif
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh4_factory->BVH4Instance(this, false, BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh4_factory->BVH4Instance(this, false, BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ }
+ // else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance accel "+device->instance_accel);
+#endif
+ }
+
+ void Scene::createInstanceMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ //if (device->instance_accel_mb == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel())
+ accels_add(device->bvh8_factory->BVH8InstanceMB(this, false));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4InstanceMB(this, false));
+ }
+ //else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance mblur accel "+device->instance_accel_mb);
+#endif
+ }
+
+ void Scene::createInstanceExpensiveAccel()
+ {
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ // if (device->object_accel == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel()) {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh8_factory->BVH8Instance(this, true, BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh8_factory->BVH8Instance(this, true, BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ else
+#endif
+ {
+ if (quality_flags != RTC_BUILD_QUALITY_LOW) {
+ accels_add(device->bvh4_factory->BVH4Instance(this, true, BVHFactory::BuildVariant::STATIC));
+ } else {
+ accels_add(device->bvh4_factory->BVH4Instance(this, true, BVHFactory::BuildVariant::DYNAMIC));
+ }
+ }
+ }
+ // else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance accel "+device->instance_accel);
+#endif
+ }
+
+ void Scene::createInstanceExpensiveMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ //if (device->instance_accel_mb == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel())
+ accels_add(device->bvh8_factory->BVH8InstanceMB(this, true));
+ else
+#endif
+ accels_add(device->bvh4_factory->BVH4InstanceMB(this, true));
+ }
+ //else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance mblur accel "+device->instance_accel_mb);
+#endif
+ }
+
+ void Scene::createGridAccel()
+ {
+ BVHFactory::IntersectVariant ivariant = isRobustAccel() ? BVHFactory::IntersectVariant::ROBUST : BVHFactory::IntersectVariant::FAST;
+#if defined(EMBREE_GEOMETRY_GRID)
+ if (device->grid_accel == "default")
+ {
+#if defined (EMBREE_TARGET_SIMD8)
+ if (device->canUseAVX() && !isCompactAccel())
+ {
+ accels_add(device->bvh8_factory->BVH8Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
+ }
+ else
+#endif
+ {
+ accels_add(device->bvh4_factory->BVH4Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
+ }
+ }
+ else if (device->grid_accel == "bvh4.grid") accels_add(device->bvh4_factory->BVH4Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
+#if defined (EMBREE_TARGET_SIMD8)
+ else if (device->grid_accel == "bvh8.grid") accels_add(device->bvh8_factory->BVH8Grid(this,BVHFactory::BuildVariant::STATIC,ivariant));
+#endif
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown grid accel "+device->grid_accel);
+#endif
+
+ }
+
+ void Scene::createGridMBAccel()
+ {
+#if defined(EMBREE_GEOMETRY_GRID)
+ if (device->grid_accel_mb == "default")
+ {
+ accels_add(device->bvh4_factory->BVH4GridMB(this,BVHFactory::BuildVariant::STATIC));
+ }
+ else if (device->grid_accel_mb == "bvh4mb.grid") accels_add(device->bvh4_factory->BVH4GridMB(this));
+ else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown grid mb accel "+device->grid_accel);
+#endif
+
+ }
+
+ void Scene::clear() {
+ }
+
+ unsigned Scene::bind(unsigned geomID, Ref<Geometry> geometry)
+ {
+ Lock<SpinLock> lock(geometriesMutex);
+ if (geomID == RTC_INVALID_GEOMETRY_ID) {
+ geomID = id_pool.allocate();
+ if (geomID == RTC_INVALID_GEOMETRY_ID)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"too many geometries inside scene");
+ }
+ else
+ {
+ if (!id_pool.add(geomID))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid geometry ID provided");
+ }
+ if (geomID >= geometries.size()) {
+ geometries.resize(geomID+1);
+ vertices.resize(geomID+1);
+ geometryModCounters_.resize(geomID+1);
+ }
+ geometries[geomID] = geometry;
+ geometryModCounters_[geomID] = 0;
+ if (geometry->isEnabled()) {
+ setModified ();
+ }
+ return geomID;
+ }
+
+ void Scene::detachGeometry(size_t geomID)
+ {
+ Lock<SpinLock> lock(geometriesMutex);
+
+ if (geomID >= geometries.size())
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid geometry ID");
+
+ Ref<Geometry>& geometry = geometries[geomID];
+ if (geometry == null)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid geometry");
+
+ if (geometry->isEnabled()) {
+ setModified ();
+ }
+ accels_deleteGeometry(unsigned(geomID));
+ id_pool.deallocate((unsigned)geomID);
+ geometries[geomID] = null;
+ vertices[geomID] = nullptr;
+ geometryModCounters_[geomID] = 0;
+ }
+
+ void Scene::updateInterface()
+ {
+ is_build = true;
+ }
+
+ void Scene::commit_task ()
+ {
+ checkIfModifiedAndSet ();
+ if (!isModified()) {
+ return;
+ }
+
+ /* print scene statistics */
+ if (device->verbosity(2))
+ printStatistics();
+
+ progress_monitor_counter = 0;
+
+ /* gather scene stats and call preCommit function of each geometry */
+ this->world = parallel_reduce (size_t(0), geometries.size(), GeometryCounts (),
+ [this](const range<size_t>& r)->GeometryCounts
+ {
+ GeometryCounts c;
+ for (auto i=r.begin(); i<r.end(); ++i)
+ {
+ if (geometries[i] && geometries[i]->isEnabled())
+ {
+ geometries[i]->preCommit();
+ geometries[i]->addElementsToCount (c);
+ c.numFilterFunctions += (int) geometries[i]->hasFilterFunctions();
+ }
+ }
+ return c;
+ },
+ std::plus<GeometryCounts>()
+ );
+
+ /* select acceleration structures to build */
+ unsigned int new_enabled_geometry_types = world.enabledGeometryTypesMask();
+ if (flags_modified || new_enabled_geometry_types != enabled_geometry_types)
+ {
+ accels_init();
+
+ /* we need to make all geometries modified, otherwise two level builder will
+ not rebuild currently not modified geometries */
+ parallel_for(geometryModCounters_.size(), [&] ( const size_t i ) {
+ geometryModCounters_[i] = 0;
+ });
+
+ if (getNumPrimitives(TriangleMesh::geom_type,false)) createTriangleAccel();
+ if (getNumPrimitives(TriangleMesh::geom_type,true)) createTriangleMBAccel();
+ if (getNumPrimitives(QuadMesh::geom_type,false)) createQuadAccel();
+ if (getNumPrimitives(QuadMesh::geom_type,true)) createQuadMBAccel();
+ if (getNumPrimitives(GridMesh::geom_type,false)) createGridAccel();
+ if (getNumPrimitives(GridMesh::geom_type,true)) createGridMBAccel();
+ if (getNumPrimitives(SubdivMesh::geom_type,false)) createSubdivAccel();
+ if (getNumPrimitives(SubdivMesh::geom_type,true)) createSubdivMBAccel();
+ if (getNumPrimitives(Geometry::MTY_CURVES,false)) createHairAccel();
+ if (getNumPrimitives(Geometry::MTY_CURVES,true)) createHairMBAccel();
+ if (getNumPrimitives(UserGeometry::geom_type,false)) createUserGeometryAccel();
+ if (getNumPrimitives(UserGeometry::geom_type,true)) createUserGeometryMBAccel();
+ if (getNumPrimitives(Geometry::MTY_INSTANCE_CHEAP,false)) createInstanceAccel();
+ if (getNumPrimitives(Geometry::MTY_INSTANCE_CHEAP,true)) createInstanceMBAccel();
+ if (getNumPrimitives(Geometry::MTY_INSTANCE_EXPENSIVE,false)) createInstanceExpensiveAccel();
+ if (getNumPrimitives(Geometry::MTY_INSTANCE_EXPENSIVE,true)) createInstanceExpensiveMBAccel();
+
+ flags_modified = false;
+ enabled_geometry_types = new_enabled_geometry_types;
+ }
+
+ /* select fast code path if no filter function is present */
+ accels_select(hasFilterFunction());
+
+ /* build all hierarchies of this scene */
+ accels_build();
+
+ /* make static geometry immutable */
+ if (!isDynamicAccel()) {
+ accels_immutable();
+ flags_modified = true; // in non-dynamic mode we have to re-create accels
+ }
+
+ /* call postCommit function of each geometry */
+ parallel_for(geometries.size(), [&] ( const size_t i ) {
+ if (geometries[i] && geometries[i]->isEnabled()) {
+ geometries[i]->postCommit();
+ vertices[i] = geometries[i]->getCompactVertexArray();
+ geometryModCounters_[i] = geometries[i]->getModCounter();
+ }
+ });
+
+ updateInterface();
+
+ if (device->verbosity(2)) {
+ std::cout << "created scene intersector" << std::endl;
+ accels_print(2);
+ std::cout << "selected scene intersector" << std::endl;
+ intersectors.print(2);
+ }
+
+ setModified(false);
+ }
+
+ void Scene::setBuildQuality(RTCBuildQuality quality_flags_i)
+ {
+ if (quality_flags == quality_flags_i) return;
+ quality_flags = quality_flags_i;
+ flags_modified = true;
+ }
+
+ RTCBuildQuality Scene::getBuildQuality() const {
+ return quality_flags;
+ }
+
+ void Scene::setSceneFlags(RTCSceneFlags scene_flags_i)
+ {
+ if (scene_flags == scene_flags_i) return;
+ scene_flags = scene_flags_i;
+ flags_modified = true;
+ }
+
+ RTCSceneFlags Scene::getSceneFlags() const {
+ return scene_flags;
+ }
+
+#if defined(TASKING_INTERNAL)
+
+ void Scene::commit (bool join)
+ {
+ Lock<MutexSys> buildLock(buildMutex,false);
+
+ /* allocates own taskscheduler for each build */
+ Ref<TaskScheduler> scheduler = nullptr;
+ {
+ Lock<MutexSys> lock(schedulerMutex);
+ scheduler = this->scheduler;
+ if (scheduler == null) {
+ buildLock.lock();
+ this->scheduler = scheduler = new TaskScheduler;
+ }
+ }
+
+ /* worker threads join build */
+ if (!buildLock.isLocked())
+ {
+ if (!join)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"use rtcJoinCommitScene to join a build operation");
+
+ scheduler->join();
+ return;
+ }
+
+ /* initiate build */
+ // -- GODOT start --
+ // try {
+ scheduler->spawn_root([&]() { commit_task(); Lock<MutexSys> lock(schedulerMutex); this->scheduler = nullptr; }, 1, !join);
+ // }
+ // catch (...) {
+ // accels_clear();
+ // updateInterface();
+ // Lock<MutexSys> lock(schedulerMutex);
+ // this->scheduler = nullptr;
+ // throw;
+ // }
+ // -- GODOT end --
+ }
+
+#endif
+
+#if defined(TASKING_TBB)
+
+ void Scene::commit (bool join)
+ {
+#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR < 8)
+ if (join)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcJoinCommitScene not supported with this TBB version");
+#endif
+
+ /* try to obtain build lock */
+ Lock<MutexSys> lock(buildMutex,buildMutex.try_lock());
+
+ /* join hierarchy build */
+ if (!lock.isLocked())
+ {
+#if !TASKING_TBB_USE_TASK_ISOLATION
+ if (!join)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invoking rtcCommitScene from multiple threads is not supported with this TBB version");
+#endif
+
+ do {
+
+#if USE_TASK_ARENA
+ if (join) {
+ device->arena->execute([&]{ group.wait(); });
+ }
+ else
+#endif
+ {
+ group.wait();
+ }
+
+ pause_cpu();
+ yield();
+ } while (!buildMutex.try_lock());
+
+ buildMutex.unlock();
+ return;
+ }
+
+ /* for best performance set FTZ and DAZ flags in the MXCSR control and status register */
+ const unsigned int mxcsr = _mm_getcsr();
+ _mm_setcsr(mxcsr | /* FTZ */ (1<<15) | /* DAZ */ (1<<6));
+
+ try {
+#if TBB_INTERFACE_VERSION_MAJOR < 8
+ tbb::task_group_context ctx( tbb::task_group_context::isolated, tbb::task_group_context::default_traits);
+#else
+ tbb::task_group_context ctx( tbb::task_group_context::isolated, tbb::task_group_context::default_traits | tbb::task_group_context::fp_settings );
+#endif
+ //ctx.set_priority(tbb::priority_high);
+
+#if USE_TASK_ARENA
+ if (join)
+ {
+ device->arena->execute([&]{
+ group.run([&]{
+ tbb::parallel_for (size_t(0), size_t(1), size_t(1), [&] (size_t) { commit_task(); }, ctx);
+ });
+ group.wait();
+ });
+ }
+ else
+#endif
+ {
+ group.run([&]{
+ tbb::parallel_for (size_t(0), size_t(1), size_t(1), [&] (size_t) { commit_task(); }, ctx);
+ });
+ group.wait();
+ }
+
+ /* reset MXCSR register again */
+ _mm_setcsr(mxcsr);
+ }
+ catch (...)
+ {
+ /* reset MXCSR register again */
+ _mm_setcsr(mxcsr);
+
+ accels_clear();
+ updateInterface();
+ throw;
+ }
+ }
+#endif
+
+#if defined(TASKING_PPL)
+
+ void Scene::commit (bool join)
+ {
+#if defined(TASKING_PPL)
+ if (join)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcJoinCommitScene not supported with PPL");
+#endif
+
+ /* try to obtain build lock */
+ Lock<MutexSys> lock(buildMutex);
+
+ checkIfModifiedAndSet ();
+ if (!isModified()) {
+ return;
+ }
+
+ /* for best performance set FTZ and DAZ flags in the MXCSR control and status register */
+ const unsigned int mxcsr = _mm_getcsr();
+ _mm_setcsr(mxcsr | /* FTZ */ (1<<15) | /* DAZ */ (1<<6));
+
+ try {
+
+ group.run([&]{
+ concurrency::parallel_for(size_t(0), size_t(1), size_t(1), [&](size_t) { commit_task(); });
+ });
+ group.wait();
+
+ /* reset MXCSR register again */
+ _mm_setcsr(mxcsr);
+ }
+ catch (...)
+ {
+ /* reset MXCSR register again */
+ _mm_setcsr(mxcsr);
+
+ accels_clear();
+ updateInterface();
+ throw;
+ }
+ }
+#endif
+
+ void Scene::setProgressMonitorFunction(RTCProgressMonitorFunction func, void* ptr)
+ {
+ progress_monitor_function = func;
+ progress_monitor_ptr = ptr;
+ }
+
+ void Scene::progressMonitor(double dn)
+ {
+ if (progress_monitor_function) {
+ size_t n = size_t(dn) + progress_monitor_counter.fetch_add(size_t(dn));
+ if (!progress_monitor_function(progress_monitor_ptr, n / (double(numPrimitives())))) {
+ throw_RTCError(RTC_ERROR_CANCELLED,"progress monitor forced termination");
+ }
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/common/scene.h b/thirdparty/embree/kernels/common/scene.h
new file mode 100644
index 0000000000..5ed80a63f6
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene.h
@@ -0,0 +1,390 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "device.h"
+#include "builder.h"
+#include "../../common/algorithms/parallel_any_of.h"
+#include "scene_triangle_mesh.h"
+#include "scene_quad_mesh.h"
+#include "scene_user_geometry.h"
+#include "scene_instance.h"
+#include "scene_curves.h"
+#include "scene_line_segments.h"
+#include "scene_subdiv_mesh.h"
+#include "scene_grid_mesh.h"
+#include "scene_points.h"
+#include "../subdiv/tessellation_cache.h"
+
+#include "acceln.h"
+#include "geometry.h"
+
+namespace embree
+{
+ /*! Base class all scenes are derived from */
+ class Scene : public AccelN
+ {
+ ALIGNED_CLASS_(std::alignment_of<Scene>::value);
+
+ public:
+ template<typename Ty, bool mblur = false>
+ class Iterator
+ {
+ public:
+ Iterator () {}
+
+ Iterator (Scene* scene, bool all = false)
+ : scene(scene), all(all) {}
+
+ __forceinline Ty* at(const size_t i)
+ {
+ Geometry* geom = scene->geometries[i].ptr;
+ if (geom == nullptr) return nullptr;
+ if (!all && !geom->isEnabled()) return nullptr;
+ const size_t mask = geom->getTypeMask() & Ty::geom_type;
+ if (!(mask)) return nullptr;
+ if ((geom->numTimeSteps != 1) != mblur) return nullptr;
+ return (Ty*) geom;
+ }
+
+ __forceinline Ty* operator[] (const size_t i) {
+ return at(i);
+ }
+
+ __forceinline size_t size() const {
+ return scene->size();
+ }
+
+ __forceinline size_t numPrimitives() const {
+ return scene->getNumPrimitives(Ty::geom_type,mblur);
+ }
+
+ __forceinline size_t maxPrimitivesPerGeometry()
+ {
+ size_t ret = 0;
+ for (size_t i=0; i<scene->size(); i++) {
+ Ty* mesh = at(i);
+ if (mesh == nullptr) continue;
+ ret = max(ret,mesh->size());
+ }
+ return ret;
+ }
+
+ __forceinline unsigned int maxGeomID()
+ {
+ unsigned int ret = 0;
+ for (size_t i=0; i<scene->size(); i++) {
+ Ty* mesh = at(i);
+ if (mesh == nullptr) continue;
+ ret = max(ret,(unsigned int)i);
+ }
+ return ret;
+ }
+
+ __forceinline unsigned maxTimeStepsPerGeometry()
+ {
+ unsigned ret = 0;
+ for (size_t i=0; i<scene->size(); i++) {
+ Ty* mesh = at(i);
+ if (mesh == nullptr) continue;
+ ret = max(ret,mesh->numTimeSteps);
+ }
+ return ret;
+ }
+
+ private:
+ Scene* scene;
+ bool all;
+ };
+
+ class Iterator2
+ {
+ public:
+ Iterator2 () {}
+
+ Iterator2 (Scene* scene, Geometry::GTypeMask typemask, bool mblur)
+ : scene(scene), typemask(typemask), mblur(mblur) {}
+
+ __forceinline Geometry* at(const size_t i)
+ {
+ Geometry* geom = scene->geometries[i].ptr;
+ if (geom == nullptr) return nullptr;
+ if (!geom->isEnabled()) return nullptr;
+ if (!(geom->getTypeMask() & typemask)) return nullptr;
+ if ((geom->numTimeSteps != 1) != mblur) return nullptr;
+ return geom;
+ }
+
+ __forceinline Geometry* operator[] (const size_t i) {
+ return at(i);
+ }
+
+ __forceinline size_t size() const {
+ return scene->size();
+ }
+
+ private:
+ Scene* scene;
+ Geometry::GTypeMask typemask;
+ bool mblur;
+ };
+
+ public:
+
+ /*! Scene construction */
+ Scene (Device* device);
+
+ /*! Scene destruction */
+ ~Scene () noexcept;
+
+ private:
+ /*! class is non-copyable */
+ Scene (const Scene& other) DELETED; // do not implement
+ Scene& operator= (const Scene& other) DELETED; // do not implement
+
+ public:
+ void createTriangleAccel();
+ void createTriangleMBAccel();
+ void createQuadAccel();
+ void createQuadMBAccel();
+ void createHairAccel();
+ void createHairMBAccel();
+ void createSubdivAccel();
+ void createSubdivMBAccel();
+ void createUserGeometryAccel();
+ void createUserGeometryMBAccel();
+ void createInstanceAccel();
+ void createInstanceMBAccel();
+ void createInstanceExpensiveAccel();
+ void createInstanceExpensiveMBAccel();
+ void createGridAccel();
+ void createGridMBAccel();
+
+ /*! prints statistics about the scene */
+ void printStatistics();
+
+ /*! clears the scene */
+ void clear();
+
+ /*! detaches some geometry */
+ void detachGeometry(size_t geomID);
+
+ void setBuildQuality(RTCBuildQuality quality_flags);
+ RTCBuildQuality getBuildQuality() const;
+
+ void setSceneFlags(RTCSceneFlags scene_flags);
+ RTCSceneFlags getSceneFlags() const;
+
+ void commit (bool join);
+ void commit_task ();
+ void build () {}
+
+ void updateInterface();
+
+ /* return number of geometries */
+ __forceinline size_t size() const { return geometries.size(); }
+
+ /* bind geometry to the scene */
+ unsigned int bind (unsigned geomID, Ref<Geometry> geometry);
+
+ /* determines if scene is modified */
+ __forceinline bool isModified() const { return modified; }
+
+ /* sets modified flag */
+ __forceinline void setModified(bool f = true) {
+ modified = f;
+ }
+
+ __forceinline bool isGeometryModified(size_t geomID)
+ {
+ Ref<Geometry>& g = geometries[geomID];
+ if (!g) return false;
+ return g->getModCounter() > geometryModCounters_[geomID];
+ }
+
+ protected:
+
+ __forceinline void checkIfModifiedAndSet ()
+ {
+ if (isModified ()) return;
+
+ auto geometryIsModified = [this](size_t geomID)->bool {
+ return isGeometryModified(geomID);
+ };
+
+ if (parallel_any_of (size_t(0), geometries.size (), geometryIsModified)) {
+ setModified ();
+ }
+ }
+
+ public:
+
+ /* get mesh by ID */
+ __forceinline Geometry* get(size_t i) { assert(i < geometries.size()); return geometries[i].ptr; }
+ __forceinline const Geometry* get(size_t i) const { assert(i < geometries.size()); return geometries[i].ptr; }
+
+ template<typename Mesh>
+ __forceinline Mesh* get(size_t i) {
+ assert(i < geometries.size());
+ assert(geometries[i]->getTypeMask() & Mesh::geom_type);
+ return (Mesh*)geometries[i].ptr;
+ }
+ template<typename Mesh>
+ __forceinline const Mesh* get(size_t i) const {
+ assert(i < geometries.size());
+ assert(geometries[i]->getTypeMask() & Mesh::geom_type);
+ return (Mesh*)geometries[i].ptr;
+ }
+
+ template<typename Mesh>
+ __forceinline Mesh* getSafe(size_t i) {
+ assert(i < geometries.size());
+ if (geometries[i] == null) return nullptr;
+ if (!(geometries[i]->getTypeMask() & Mesh::geom_type)) return nullptr;
+ else return (Mesh*) geometries[i].ptr;
+ }
+
+ __forceinline Ref<Geometry> get_locked(size_t i) {
+ Lock<SpinLock> lock(geometriesMutex);
+ assert(i < geometries.size());
+ return geometries[i];
+ }
+
+ /* flag decoding */
+ __forceinline bool isFastAccel() const { return !isCompactAccel() && !isRobustAccel(); }
+ __forceinline bool isCompactAccel() const { return scene_flags & RTC_SCENE_FLAG_COMPACT; }
+ __forceinline bool isRobustAccel() const { return scene_flags & RTC_SCENE_FLAG_ROBUST; }
+ __forceinline bool isStaticAccel() const { return !(scene_flags & RTC_SCENE_FLAG_DYNAMIC); }
+ __forceinline bool isDynamicAccel() const { return scene_flags & RTC_SCENE_FLAG_DYNAMIC; }
+
+ __forceinline bool hasContextFilterFunction() const {
+ return scene_flags & RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION;
+ }
+
+ __forceinline bool hasGeometryFilterFunction() {
+ return world.numFilterFunctions != 0;
+ }
+
+ __forceinline bool hasFilterFunction() {
+ return hasContextFilterFunction() || hasGeometryFilterFunction();
+ }
+
+ /* test if scene got already build */
+ __forceinline bool isBuild() const { return is_build; }
+
+ public:
+ IDPool<unsigned,0xFFFFFFFE> id_pool;
+ vector<Ref<Geometry>> geometries; //!< list of all user geometries
+ vector<unsigned int> geometryModCounters_;
+ vector<float*> vertices;
+
+ public:
+ Device* device;
+
+ /* these are to detect if we need to recreate the acceleration structures */
+ bool flags_modified;
+ unsigned int enabled_geometry_types;
+
+ RTCSceneFlags scene_flags;
+ RTCBuildQuality quality_flags;
+ MutexSys buildMutex;
+ SpinLock geometriesMutex;
+ bool is_build;
+ private:
+ bool modified; //!< true if scene got modified
+
+ public:
+
+ /*! global lock step task scheduler */
+#if defined(TASKING_INTERNAL)
+ MutexSys schedulerMutex;
+ Ref<TaskScheduler> scheduler;
+#elif defined(TASKING_TBB) && TASKING_TBB_USE_TASK_ISOLATION
+ tbb::isolated_task_group group;
+#elif defined(TASKING_TBB)
+ tbb::task_group group;
+#elif defined(TASKING_PPL)
+ concurrency::task_group group;
+#endif
+
+ public:
+ struct BuildProgressMonitorInterface : public BuildProgressMonitor {
+ BuildProgressMonitorInterface(Scene* scene)
+ : scene(scene) {}
+ void operator() (size_t dn) const { scene->progressMonitor(double(dn)); }
+ private:
+ Scene* scene;
+ };
+ BuildProgressMonitorInterface progressInterface;
+ RTCProgressMonitorFunction progress_monitor_function;
+ void* progress_monitor_ptr;
+ std::atomic<size_t> progress_monitor_counter;
+ void progressMonitor(double nprims);
+ void setProgressMonitorFunction(RTCProgressMonitorFunction func, void* ptr);
+
+ private:
+ GeometryCounts world; //!< counts for geometry
+
+ public:
+
+ __forceinline size_t numPrimitives() const {
+ return world.size();
+ }
+
+ __forceinline size_t getNumPrimitives(Geometry::GTypeMask mask, bool mblur) const
+ {
+ size_t count = 0;
+
+ if (mask & Geometry::MTY_TRIANGLE_MESH)
+ count += mblur ? world.numMBTriangles : world.numTriangles;
+
+ if (mask & Geometry::MTY_QUAD_MESH)
+ count += mblur ? world.numMBQuads : world.numQuads;
+
+ if (mask & Geometry::MTY_CURVE2)
+ count += mblur ? world.numMBLineSegments : world.numLineSegments;
+
+ if (mask & Geometry::MTY_CURVE4)
+ count += mblur ? world.numMBBezierCurves : world.numBezierCurves;
+
+ if (mask & Geometry::MTY_POINTS)
+ count += mblur ? world.numMBPoints : world.numPoints;
+
+ if (mask & Geometry::MTY_SUBDIV_MESH)
+ count += mblur ? world.numMBSubdivPatches : world.numSubdivPatches;
+
+ if (mask & Geometry::MTY_USER_GEOMETRY)
+ count += mblur ? world.numMBUserGeometries : world.numUserGeometries;
+
+ if (mask & Geometry::MTY_INSTANCE_CHEAP)
+ count += mblur ? world.numMBInstancesCheap : world.numInstancesCheap;
+
+ if (mask & Geometry::MTY_INSTANCE_EXPENSIVE)
+ count += mblur ? world.numMBInstancesExpensive : world.numInstancesExpensive;
+
+ if (mask & Geometry::MTY_GRID_MESH)
+ count += mblur ? world.numMBGrids : world.numGrids;
+
+ return count;
+ }
+
+ template<typename Mesh, bool mblur>
+ __forceinline unsigned getNumTimeSteps()
+ {
+ if (!mblur)
+ return 1;
+
+ Scene::Iterator<Mesh,mblur> iter(this);
+ return iter.maxTimeStepsPerGeometry();
+ }
+
+ template<typename Mesh, bool mblur>
+ __forceinline unsigned int getMaxGeomID()
+ {
+ Scene::Iterator<Mesh,mblur> iter(this);
+ return iter.maxGeomID();
+ }
+ };
+}
diff --git a/thirdparty/embree/kernels/common/scene_curves.h b/thirdparty/embree/kernels/common/scene_curves.h
new file mode 100644
index 0000000000..a5a39e42d4
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene_curves.h
@@ -0,0 +1,688 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "geometry.h"
+#include "buffer.h"
+
+#include "../subdiv/bezier_curve.h"
+#include "../subdiv/hermite_curve.h"
+#include "../subdiv/bspline_curve.h"
+#include "../subdiv/catmullrom_curve.h"
+#include "../subdiv/linear_bezier_patch.h"
+
+namespace embree
+{
+ /*! represents an array of bicubic bezier curves */
+ struct CurveGeometry : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_CURVE4;
+
+ public:
+
+ /*! bezier curve construction */
+ CurveGeometry (Device* device, Geometry::GType gtype);
+
+ public:
+ void setMask(unsigned mask);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify();
+ void setTessellationRate(float N);
+ void setMaxRadiusScale(float s);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ public:
+
+ /*! returns the number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns the i'th curve */
+ __forceinline const unsigned int& curve(size_t i) const {
+ return curves[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline Vec3ff vertex(size_t i) const {
+ return vertices0[i];
+ }
+
+ /*! returns i'th normal of the first time step */
+ __forceinline Vec3fa normal(size_t i) const {
+ return normals0[i];
+ }
+
+ /*! returns i'th tangent of the first time step */
+ __forceinline Vec3ff tangent(size_t i) const {
+ return tangents0[i];
+ }
+
+ /*! returns i'th normal derivative of the first time step */
+ __forceinline Vec3fa dnormal(size_t i) const {
+ return dnormals0[i];
+ }
+
+ /*! returns i'th radius of the first time step */
+ __forceinline float radius(size_t i) const {
+ return vertices0[i].w;
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline Vec3ff vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th normal of itime'th timestep */
+ __forceinline Vec3fa normal(size_t i, size_t itime) const {
+ return normals[itime][i];
+ }
+
+ /*! returns i'th tangent of itime'th timestep */
+ __forceinline Vec3ff tangent(size_t i, size_t itime) const {
+ return tangents[itime][i];
+ }
+
+ /*! returns i'th normal derivative of itime'th timestep */
+ __forceinline Vec3fa dnormal(size_t i, size_t itime) const {
+ return dnormals[itime][i];
+ }
+
+ /*! returns i'th radius of itime'th timestep */
+ __forceinline float radius(size_t i, size_t itime) const {
+ return vertices[itime][i].w;
+ }
+
+ /*! gathers the curve starting with i'th vertex */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, size_t i) const
+ {
+ p0 = vertex(i+0);
+ p1 = vertex(i+1);
+ p2 = vertex(i+2);
+ p3 = vertex(i+3);
+ }
+
+ /*! gathers the curve starting with i'th vertex of itime'th timestep */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, size_t i, size_t itime) const
+ {
+ p0 = vertex(i+0,itime);
+ p1 = vertex(i+1,itime);
+ p2 = vertex(i+2,itime);
+ p3 = vertex(i+3,itime);
+ }
+
+ /*! gathers the curve starting with i'th vertex */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i) const
+ {
+ p0 = vertex(i+0);
+ p1 = vertex(i+1);
+ p2 = vertex(i+2);
+ p3 = vertex(i+3);
+ n0 = normal(i+0);
+ n1 = normal(i+1);
+ n2 = normal(i+2);
+ n3 = normal(i+3);
+ }
+
+ /*! gathers the curve starting with i'th vertex of itime'th timestep */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i, size_t itime) const
+ {
+ p0 = vertex(i+0,itime);
+ p1 = vertex(i+1,itime);
+ p2 = vertex(i+2,itime);
+ p3 = vertex(i+3,itime);
+ n0 = normal(i+0,itime);
+ n1 = normal(i+1,itime);
+ n2 = normal(i+2,itime);
+ n3 = normal(i+3,itime);
+ }
+
+ /*! prefetches the curve starting with i'th vertex of itime'th timestep */
+ __forceinline void prefetchL1_vertices(size_t i) const
+ {
+ prefetchL1(vertices0.getPtr(i)+0);
+ prefetchL1(vertices0.getPtr(i)+64);
+ }
+
+ /*! prefetches the curve starting with i'th vertex of itime'th timestep */
+ __forceinline void prefetchL2_vertices(size_t i) const
+ {
+ prefetchL2(vertices0.getPtr(i)+0);
+ prefetchL2(vertices0.getPtr(i)+64);
+ }
+
+ /*! loads curve vertices for specified time */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, size_t i, float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+
+ const float t0 = 1.0f - ftime;
+ const float t1 = ftime;
+ Vec3ff a0,a1,a2,a3;
+ gather(a0,a1,a2,a3,i,itime);
+ Vec3ff b0,b1,b2,b3;
+ gather(b0,b1,b2,b3,i,itime+1);
+ p0 = madd(Vec3ff(t0),a0,t1*b0);
+ p1 = madd(Vec3ff(t0),a1,t1*b1);
+ p2 = madd(Vec3ff(t0),a2,t1*b2);
+ p3 = madd(Vec3ff(t0),a3,t1*b3);
+ }
+
+ /*! loads curve vertices for specified time */
+ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i, float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+
+ const float t0 = 1.0f - ftime;
+ const float t1 = ftime;
+ Vec3ff a0,a1,a2,a3; Vec3fa an0,an1,an2,an3;
+ gather(a0,a1,a2,a3,an0,an1,an2,an3,i,itime);
+ Vec3ff b0,b1,b2,b3; Vec3fa bn0,bn1,bn2,bn3;
+ gather(b0,b1,b2,b3,bn0,bn1,bn2,bn3,i,itime+1);
+ p0 = madd(Vec3ff(t0),a0,t1*b0);
+ p1 = madd(Vec3ff(t0),a1,t1*b1);
+ p2 = madd(Vec3ff(t0),a2,t1*b2);
+ p3 = madd(Vec3ff(t0),a3,t1*b3);
+ n0 = madd(Vec3ff(t0),an0,t1*bn0);
+ n1 = madd(Vec3ff(t0),an1,t1*bn1);
+ n2 = madd(Vec3ff(t0),an2,t1*bn2);
+ n3 = madd(Vec3ff(t0),an3,t1*bn3);
+ }
+
+ template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
+ __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const size_t itime) const
+ {
+ Vec3ff v0,v1,v2,v3; Vec3fa n0,n1,n2,n3;
+ unsigned int vertexID = curve(primID);
+ gather(v0,v1,v2,v3,n0,n1,n2,n3,vertexID,itime);
+ SourceCurve3ff ccurve(v0,v1,v2,v3);
+ SourceCurve3fa ncurve(n0,n1,n2,n3);
+ ccurve = enlargeRadiusToMinWidth(context,this,ray_org,ccurve);
+ return TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve);
+ }
+
+ template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
+ __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+ const TensorLinearCubicBezierSurface3fa curve0 = getNormalOrientedCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context,ray_org,primID,itime+0);
+ const TensorLinearCubicBezierSurface3fa curve1 = getNormalOrientedCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context,ray_org,primID,itime+1);
+ return clerp(curve0,curve1,ftime);
+ }
+
+ /*! gathers the hermite curve starting with i'th vertex */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i) const
+ {
+ p0 = vertex (i+0);
+ p1 = vertex (i+1);
+ t0 = tangent(i+0);
+ t1 = tangent(i+1);
+ }
+
+ /*! gathers the hermite curve starting with i'th vertex of itime'th timestep */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i, size_t itime) const
+ {
+ p0 = vertex (i+0,itime);
+ p1 = vertex (i+1,itime);
+ t0 = tangent(i+0,itime);
+ t1 = tangent(i+1,itime);
+ }
+
+ /*! loads curve vertices for specified time */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i, float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+ const float f0 = 1.0f - ftime, f1 = ftime;
+ Vec3ff ap0,at0,ap1,at1;
+ gather_hermite(ap0,at0,ap1,at1,i,itime);
+ Vec3ff bp0,bt0,bp1,bt1;
+ gather_hermite(bp0,bt0,bp1,bt1,i,itime+1);
+ p0 = madd(Vec3ff(f0),ap0,f1*bp0);
+ t0 = madd(Vec3ff(f0),at0,f1*bt0);
+ p1 = madd(Vec3ff(f0),ap1,f1*bp1);
+ t1 = madd(Vec3ff(f0),at1,f1*bt1);
+ }
+
+ /*! gathers the hermite curve starting with i'th vertex */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3ff& t1, Vec3fa& n1, Vec3fa& dn1, size_t i) const
+ {
+ p0 = vertex (i+0);
+ p1 = vertex (i+1);
+ t0 = tangent(i+0);
+ t1 = tangent(i+1);
+ n0 = normal(i+0);
+ n1 = normal(i+1);
+ dn0 = dnormal(i+0);
+ dn1 = dnormal(i+1);
+ }
+
+ /*! gathers the hermite curve starting with i'th vertex of itime'th timestep */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3ff& t1, Vec3fa& n1, Vec3fa& dn1, size_t i, size_t itime) const
+ {
+ p0 = vertex (i+0,itime);
+ p1 = vertex (i+1,itime);
+ t0 = tangent(i+0,itime);
+ t1 = tangent(i+1,itime);
+ n0 = normal(i+0,itime);
+ n1 = normal(i+1,itime);
+ dn0 = dnormal(i+0,itime);
+ dn1 = dnormal(i+1,itime);
+ }
+
+ /*! loads curve vertices for specified time */
+ __forceinline void gather_hermite(Vec3ff& p0, Vec3fa& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3fa& t1, Vec3fa& n1, Vec3fa& dn1, size_t i, float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+ const float f0 = 1.0f - ftime, f1 = ftime;
+ Vec3ff ap0,at0,ap1,at1; Vec3fa an0,adn0,an1,adn1;
+ gather_hermite(ap0,at0,an0,adn0,ap1,at1,an1,adn1,i,itime);
+ Vec3ff bp0,bt0,bp1,bt1; Vec3fa bn0,bdn0,bn1,bdn1;
+ gather_hermite(bp0,bt0,bn0,bdn0,bp1,bt1,bn1,bdn1,i,itime+1);
+ p0 = madd(Vec3ff(f0),ap0,f1*bp0);
+ t0 = madd(Vec3ff(f0),at0,f1*bt0);
+ n0 = madd(Vec3ff(f0),an0,f1*bn0);
+ dn0= madd(Vec3ff(f0),adn0,f1*bdn0);
+ p1 = madd(Vec3ff(f0),ap1,f1*bp1);
+ t1 = madd(Vec3ff(f0),at1,f1*bt1);
+ n1 = madd(Vec3ff(f0),an1,f1*bn1);
+ dn1= madd(Vec3ff(f0),adn1,f1*bdn1);
+ }
+
+ template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
+ __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const size_t itime) const
+ {
+ Vec3ff v0,t0,v1,t1; Vec3fa n0,dn0,n1,dn1;
+ unsigned int vertexID = curve(primID);
+ gather_hermite(v0,t0,n0,dn0,v1,t1,n1,dn1,vertexID,itime);
+
+ SourceCurve3ff ccurve(v0,t0,v1,t1);
+ SourceCurve3fa ncurve(n0,dn0,n1,dn1);
+ ccurve = enlargeRadiusToMinWidth(context,this,ray_org,ccurve);
+ return TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve);
+ }
+
+ template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa>
+ __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const
+ {
+ float ftime;
+ const size_t itime = timeSegment(time, ftime);
+ const TensorLinearCubicBezierSurface3fa curve0 = getNormalOrientedHermiteCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,itime+0);
+ const TensorLinearCubicBezierSurface3fa curve1 = getNormalOrientedHermiteCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,itime+1);
+ return clerp(curve0,curve1,ftime);
+ }
+
+ private:
+ void resizeBuffers(unsigned int numSteps);
+
+ public:
+ BufferView<unsigned int> curves; //!< array of curve indices
+ BufferView<Vec3ff> vertices0; //!< fast access to first vertex buffer
+ BufferView<Vec3fa> normals0; //!< fast access to first normal buffer
+ BufferView<Vec3ff> tangents0; //!< fast access to first tangent buffer
+ BufferView<Vec3fa> dnormals0; //!< fast access to first normal derivative buffer
+ vector<BufferView<Vec3ff>> vertices; //!< vertex array for each timestep
+ vector<BufferView<Vec3fa>> normals; //!< normal array for each timestep
+ vector<BufferView<Vec3ff>> tangents; //!< tangent array for each timestep
+ vector<BufferView<Vec3fa>> dnormals; //!< normal derivative array for each timestep
+ BufferView<char> flags; //!< start, end flag per segment
+ vector<BufferView<char>> vertexAttribs; //!< user buffers
+ int tessellationRate; //!< tessellation rate for flat curve
+ float maxRadiusScale = 1.0; //!< maximal min-width scaling of curve radii
+ };
+
+ namespace isa
+ {
+
+ template<template<typename Ty> class Curve>
+ struct CurveGeometryInterface : public CurveGeometry
+ {
+ typedef Curve<Vec3ff> Curve3ff;
+ typedef Curve<Vec3fa> Curve3fa;
+
+ CurveGeometryInterface (Device* device, Geometry::GType gtype)
+ : CurveGeometry(device,gtype) {}
+
+ __forceinline const Curve3ff getCurveScaledRadius(size_t i, size_t itime = 0) const
+ {
+ const unsigned int index = curve(i);
+ Vec3ff v0 = vertex(index+0,itime);
+ Vec3ff v1 = vertex(index+1,itime);
+ Vec3ff v2 = vertex(index+2,itime);
+ Vec3ff v3 = vertex(index+3,itime);
+ v0.w *= maxRadiusScale;
+ v1.w *= maxRadiusScale;
+ v2.w *= maxRadiusScale;
+ v3.w *= maxRadiusScale;
+ return Curve3ff (v0,v1,v2,v3);
+ }
+
+ __forceinline const Curve3ff getCurveScaledRadius(const LinearSpace3fa& space, size_t i, size_t itime = 0) const
+ {
+ const unsigned int index = curve(i);
+ const Vec3ff v0 = vertex(index+0,itime);
+ const Vec3ff v1 = vertex(index+1,itime);
+ const Vec3ff v2 = vertex(index+2,itime);
+ const Vec3ff v3 = vertex(index+3,itime);
+ const Vec3ff w0(xfmPoint(space,(Vec3fa)v0), maxRadiusScale*v0.w);
+ const Vec3ff w1(xfmPoint(space,(Vec3fa)v1), maxRadiusScale*v1.w);
+ const Vec3ff w2(xfmPoint(space,(Vec3fa)v2), maxRadiusScale*v2.w);
+ const Vec3ff w3(xfmPoint(space,(Vec3fa)v3), maxRadiusScale*v3.w);
+ return Curve3ff(w0,w1,w2,w3);
+ }
+
+ __forceinline const Curve3ff getCurveScaledRadius(const Vec3fa& ofs, const float scale, const float r_scale0, const LinearSpace3fa& space, size_t i, size_t itime = 0) const
+ {
+ const float r_scale = r_scale0*scale;
+ const unsigned int index = curve(i);
+ const Vec3ff v0 = vertex(index+0,itime);
+ const Vec3ff v1 = vertex(index+1,itime);
+ const Vec3ff v2 = vertex(index+2,itime);
+ const Vec3ff v3 = vertex(index+3,itime);
+ const Vec3ff w0(xfmPoint(space,((Vec3fa)v0-ofs)*Vec3fa(scale)), maxRadiusScale*v0.w*r_scale);
+ const Vec3ff w1(xfmPoint(space,((Vec3fa)v1-ofs)*Vec3fa(scale)), maxRadiusScale*v1.w*r_scale);
+ const Vec3ff w2(xfmPoint(space,((Vec3fa)v2-ofs)*Vec3fa(scale)), maxRadiusScale*v2.w*r_scale);
+ const Vec3ff w3(xfmPoint(space,((Vec3fa)v3-ofs)*Vec3fa(scale)), maxRadiusScale*v3.w*r_scale);
+ return Curve3ff(w0,w1,w2,w3);
+ }
+
+ __forceinline const Curve3fa getNormalCurve(size_t i, size_t itime = 0) const
+ {
+ const unsigned int index = curve(i);
+ const Vec3fa n0 = normal(index+0,itime);
+ const Vec3fa n1 = normal(index+1,itime);
+ const Vec3fa n2 = normal(index+2,itime);
+ const Vec3fa n3 = normal(index+3,itime);
+ return Curve3fa (n0,n1,n2,n3);
+ }
+
+ __forceinline const TensorLinearCubicBezierSurface3fa getOrientedCurveScaledRadius(size_t i, size_t itime = 0) const
+ {
+ const Curve3ff center = getCurveScaledRadius(i,itime);
+ const Curve3fa normal = getNormalCurve(i,itime);
+ const TensorLinearCubicBezierSurface3fa ocurve = TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(center,normal);
+ return ocurve;
+ }
+
+ __forceinline const TensorLinearCubicBezierSurface3fa getOrientedCurveScaledRadius(const LinearSpace3fa& space, size_t i, size_t itime = 0) const {
+ return getOrientedCurveScaledRadius(i,itime).xfm(space);
+ }
+
+ __forceinline const TensorLinearCubicBezierSurface3fa getOrientedCurveScaledRadius(const Vec3fa& ofs, const float scale, const LinearSpace3fa& space, size_t i, size_t itime = 0) const {
+ return getOrientedCurveScaledRadius(i,itime).xfm(space,ofs,scale);
+ }
+
+ /*! check if the i'th primitive is valid at the itime'th time step */
+ __forceinline bool valid(Geometry::GType ctype, size_t i, const range<size_t>& itime_range) const
+ {
+ const unsigned int index = curve(i);
+ if (index+3 >= numVertices()) return false;
+
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ {
+ const float r0 = radius(index+0,itime);
+ const float r1 = radius(index+1,itime);
+ const float r2 = radius(index+2,itime);
+ const float r3 = radius(index+3,itime);
+ if (!isvalid(r0) || !isvalid(r1) || !isvalid(r2) || !isvalid(r3))
+ return false;
+
+ const Vec3fa v0 = vertex(index+0,itime);
+ const Vec3fa v1 = vertex(index+1,itime);
+ const Vec3fa v2 = vertex(index+2,itime);
+ const Vec3fa v3 = vertex(index+3,itime);
+ if (!isvalid(v0) || !isvalid(v1) || !isvalid(v2) || !isvalid(v3))
+ return false;
+
+ if (ctype == Geometry::GTY_SUBTYPE_ORIENTED_CURVE)
+ {
+ const Vec3fa n0 = normal(index+0,itime);
+ const Vec3fa n1 = normal(index+1,itime);
+ if (!isvalid(n0) || !isvalid(n1))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ template<int N>
+ void interpolate_impl(const RTCInterpolateArguments* const args)
+ {
+ unsigned int primID = args->primID;
+ float u = args->u;
+ RTCBufferType bufferType = args->bufferType;
+ unsigned int bufferSlot = args->bufferSlot;
+ float* P = args->P;
+ float* dPdu = args->dPdu;
+ float* ddPdudu = args->ddPdudu;
+ unsigned int valueCount = args->valueCount;
+
+ /* calculate base pointer and stride */
+ assert((bufferType == RTC_BUFFER_TYPE_VERTEX && bufferSlot < numTimeSteps) ||
+ (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE && bufferSlot <= vertexAttribs.size()));
+ const char* src = nullptr;
+ size_t stride = 0;
+ if (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE) {
+ src = vertexAttribs[bufferSlot].getPtr();
+ stride = vertexAttribs[bufferSlot].getStride();
+ } else {
+ src = vertices[bufferSlot].getPtr();
+ stride = vertices[bufferSlot].getStride();
+ }
+
+ for (unsigned int i=0; i<valueCount; i+=N)
+ {
+ size_t ofs = i*sizeof(float);
+ const size_t index = curves[primID];
+ const vbool<N> valid = vint<N>((int)i)+vint<N>(step) < vint<N>((int)valueCount);
+ const vfloat<N> p0 = mem<vfloat<N>>::loadu(valid,(float*)&src[(index+0)*stride+ofs]);
+ const vfloat<N> p1 = mem<vfloat<N>>::loadu(valid,(float*)&src[(index+1)*stride+ofs]);
+ const vfloat<N> p2 = mem<vfloat<N>>::loadu(valid,(float*)&src[(index+2)*stride+ofs]);
+ const vfloat<N> p3 = mem<vfloat<N>>::loadu(valid,(float*)&src[(index+3)*stride+ofs]);
+
+ const Curve<vfloat<N>> curve(p0,p1,p2,p3);
+ if (P ) mem<vfloat<N>>::storeu(valid,P+i, curve.eval(u));
+ if (dPdu ) mem<vfloat<N>>::storeu(valid,dPdu+i, curve.eval_du(u));
+ if (ddPdudu) mem<vfloat<N>>::storeu(valid,ddPdudu+i,curve.eval_dudu(u));
+ }
+ }
+
+ void interpolate(const RTCInterpolateArguments* const args) {
+ interpolate_impl<4>(args);
+ }
+ };
+
+ template<template<typename Ty> class Curve>
+ struct HermiteCurveGeometryInterface : public CurveGeometry
+ {
+ typedef Curve<Vec3ff> HermiteCurve3ff;
+ typedef Curve<Vec3fa> HermiteCurve3fa;
+
+ HermiteCurveGeometryInterface (Device* device, Geometry::GType gtype)
+ : CurveGeometry(device,gtype) {}
+
+ __forceinline const HermiteCurve3ff getCurveScaledRadius(size_t i, size_t itime = 0) const
+ {
+ const unsigned int index = curve(i);
+ Vec3ff v0 = vertex(index+0,itime);
+ Vec3ff v1 = vertex(index+1,itime);
+ Vec3ff t0 = tangent(index+0,itime);
+ Vec3ff t1 = tangent(index+1,itime);
+ v0.w *= maxRadiusScale;
+ v1.w *= maxRadiusScale;
+ t0.w *= maxRadiusScale;
+ t1.w *= maxRadiusScale;
+ return HermiteCurve3ff (v0,t0,v1,t1);
+ }
+
+ __forceinline const HermiteCurve3ff getCurveScaledRadius(const LinearSpace3fa& space, size_t i, size_t itime = 0) const
+ {
+ const unsigned int index = curve(i);
+ const Vec3ff v0 = vertex(index+0,itime);
+ const Vec3ff v1 = vertex(index+1,itime);
+ const Vec3ff t0 = tangent(index+0,itime);
+ const Vec3ff t1 = tangent(index+1,itime);
+ const Vec3ff V0(xfmPoint(space,(Vec3fa)v0),maxRadiusScale*v0.w);
+ const Vec3ff V1(xfmPoint(space,(Vec3fa)v1),maxRadiusScale*v1.w);
+ const Vec3ff T0(xfmVector(space,(Vec3fa)t0),maxRadiusScale*t0.w);
+ const Vec3ff T1(xfmVector(space,(Vec3fa)t1),maxRadiusScale*t1.w);
+ return HermiteCurve3ff(V0,T0,V1,T1);
+ }
+
+ __forceinline const HermiteCurve3ff getCurveScaledRadius(const Vec3fa& ofs, const float scale, const float r_scale0, const LinearSpace3fa& space, size_t i, size_t itime = 0) const
+ {
+ const float r_scale = r_scale0*scale;
+ const unsigned int index = curve(i);
+ const Vec3ff v0 = vertex(index+0,itime);
+ const Vec3ff v1 = vertex(index+1,itime);
+ const Vec3ff t0 = tangent(index+0,itime);
+ const Vec3ff t1 = tangent(index+1,itime);
+ const Vec3ff V0(xfmPoint(space,(v0-ofs)*Vec3fa(scale)), maxRadiusScale*v0.w*r_scale);
+ const Vec3ff V1(xfmPoint(space,(v1-ofs)*Vec3fa(scale)), maxRadiusScale*v1.w*r_scale);
+ const Vec3ff T0(xfmVector(space,t0*Vec3fa(scale)), maxRadiusScale*t0.w*r_scale);
+ const Vec3ff T1(xfmVector(space,t1*Vec3fa(scale)), maxRadiusScale*t1.w*r_scale);
+ return HermiteCurve3ff(V0,T0,V1,T1);
+ }
+
+ __forceinline const HermiteCurve3fa getNormalCurve(size_t i, size_t itime = 0) const
+ {
+ const unsigned int index = curve(i);
+ const Vec3fa n0 = normal(index+0,itime);
+ const Vec3fa n1 = normal(index+1,itime);
+ const Vec3fa dn0 = dnormal(index+0,itime);
+ const Vec3fa dn1 = dnormal(index+1,itime);
+ return HermiteCurve3fa (n0,dn0,n1,dn1);
+ }
+
+ __forceinline const TensorLinearCubicBezierSurface3fa getOrientedCurveScaledRadius(size_t i, size_t itime = 0) const
+ {
+ const HermiteCurve3ff center = getCurveScaledRadius(i,itime);
+ const HermiteCurve3fa normal = getNormalCurve(i,itime);
+ const TensorLinearCubicBezierSurface3fa ocurve = TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(center,normal);
+ return ocurve;
+ }
+
+ __forceinline const TensorLinearCubicBezierSurface3fa getOrientedCurveScaledRadius(const LinearSpace3fa& space, size_t i, size_t itime = 0) const {
+ return getOrientedCurveScaledRadius(i,itime).xfm(space);
+ }
+
+ __forceinline const TensorLinearCubicBezierSurface3fa getOrientedCurveScaledRadius(const Vec3fa& ofs, const float scale, const LinearSpace3fa& space, size_t i, size_t itime = 0) const {
+ return getOrientedCurveScaledRadius(i,itime).xfm(space,ofs,scale);
+ }
+
+ /*! check if the i'th primitive is valid at the itime'th time step */
+ __forceinline bool valid(Geometry::GType ctype, size_t i, const range<size_t>& itime_range) const
+ {
+ const unsigned int index = curve(i);
+ if (index+1 >= numVertices()) return false;
+
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ {
+ const Vec3ff v0 = vertex(index+0,itime);
+ const Vec3ff v1 = vertex(index+1,itime);
+ if (!isvalid4(v0) || !isvalid4(v1))
+ return false;
+
+ const Vec3ff t0 = tangent(index+0,itime);
+ const Vec3ff t1 = tangent(index+1,itime);
+ if (!isvalid4(t0) || !isvalid4(t1))
+ return false;
+
+ if (ctype == Geometry::GTY_SUBTYPE_ORIENTED_CURVE)
+ {
+ const Vec3fa n0 = normal(index+0,itime);
+ const Vec3fa n1 = normal(index+1,itime);
+ if (!isvalid(n0) || !isvalid(n1))
+ return false;
+
+ const Vec3fa dn0 = dnormal(index+0,itime);
+ const Vec3fa dn1 = dnormal(index+1,itime);
+ if (!isvalid(dn0) || !isvalid(dn1))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ template<int N>
+ void interpolate_impl(const RTCInterpolateArguments* const args)
+ {
+ unsigned int primID = args->primID;
+ float u = args->u;
+ RTCBufferType bufferType = args->bufferType;
+ unsigned int bufferSlot = args->bufferSlot;
+ float* P = args->P;
+ float* dPdu = args->dPdu;
+ float* ddPdudu = args->ddPdudu;
+ unsigned int valueCount = args->valueCount;
+
+ /* we interpolate vertex attributes linearly for hermite basis */
+ if (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE)
+ {
+ assert(bufferSlot <= vertexAttribs.size());
+ const char* vsrc = vertexAttribs[bufferSlot].getPtr();
+ const size_t vstride = vertexAttribs[bufferSlot].getStride();
+
+ for (unsigned int i=0; i<valueCount; i+=N)
+ {
+ const size_t ofs = i*sizeof(float);
+ const size_t index = curves[primID];
+ const vbool<N> valid = vint<N>((int)i)+vint<N>(step) < vint<N>((int)valueCount);
+ const vfloat<N> p0 = mem<vfloat<N>>::loadu(valid,(float*)&vsrc[(index+0)*vstride+ofs]);
+ const vfloat<N> p1 = mem<vfloat<N>>::loadu(valid,(float*)&vsrc[(index+1)*vstride+ofs]);
+
+ if (P ) mem<vfloat<N>>::storeu(valid,P+i, madd(1.0f-u,p0,u*p1));
+ if (dPdu ) mem<vfloat<N>>::storeu(valid,dPdu+i, p1-p0);
+ if (ddPdudu) mem<vfloat<N>>::storeu(valid,ddPdudu+i,vfloat<N>(zero));
+ }
+ }
+
+ /* interpolation for vertex buffers */
+ else
+ {
+ assert(bufferSlot < numTimeSteps);
+ const char* vsrc = vertices[bufferSlot].getPtr();
+ const char* tsrc = tangents[bufferSlot].getPtr();
+ const size_t vstride = vertices[bufferSlot].getStride();
+ const size_t tstride = vertices[bufferSlot].getStride();
+
+ for (unsigned int i=0; i<valueCount; i+=N)
+ {
+ const size_t ofs = i*sizeof(float);
+ const size_t index = curves[primID];
+ const vbool<N> valid = vint<N>((int)i)+vint<N>(step) < vint<N>((int)valueCount);
+ const vfloat<N> p0 = mem<vfloat<N>>::loadu(valid,(float*)&vsrc[(index+0)*vstride+ofs]);
+ const vfloat<N> p1 = mem<vfloat<N>>::loadu(valid,(float*)&vsrc[(index+1)*vstride+ofs]);
+ const vfloat<N> t0 = mem<vfloat<N>>::loadu(valid,(float*)&tsrc[(index+0)*tstride+ofs]);
+ const vfloat<N> t1 = mem<vfloat<N>>::loadu(valid,(float*)&tsrc[(index+1)*tstride+ofs]);
+
+ const HermiteCurveT<vfloat<N>> curve(p0,t0,p1,t1);
+ if (P ) mem<vfloat<N>>::storeu(valid,P+i, curve.eval(u));
+ if (dPdu ) mem<vfloat<N>>::storeu(valid,dPdu+i, curve.eval_du(u));
+ if (ddPdudu) mem<vfloat<N>>::storeu(valid,ddPdudu+i,curve.eval_dudu(u));
+ }
+ }
+ }
+
+ void interpolate(const RTCInterpolateArguments* const args) {
+ interpolate_impl<4>(args);
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(CurveGeometry*, createCurves, Device* COMMA Geometry::GType);
+}
diff --git a/thirdparty/embree/kernels/common/scene_grid_mesh.h b/thirdparty/embree/kernels/common/scene_grid_mesh.h
new file mode 100644
index 0000000000..fb6fed445b
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene_grid_mesh.h
@@ -0,0 +1,294 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "geometry.h"
+#include "buffer.h"
+
+namespace embree
+{
+ /*! Grid Mesh */
+ struct GridMesh : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_GRID_MESH;
+
+ /*! grid */
+ struct Grid
+ {
+ unsigned int startVtxID;
+ unsigned int lineVtxOffset;
+ unsigned short resX,resY;
+
+ /* border flags due to 3x3 vertex pattern */
+ __forceinline unsigned int get3x3FlagsX(const unsigned int x) const
+ {
+ return (x + 2 >= (unsigned int)resX) ? (1<<15) : 0;
+ }
+
+ /* border flags due to 3x3 vertex pattern */
+ __forceinline unsigned int get3x3FlagsY(const unsigned int y) const
+ {
+ return (y + 2 >= (unsigned int)resY) ? (1<<15) : 0;
+ }
+
+ /*! outputs grid structure */
+ __forceinline friend embree_ostream operator<<(embree_ostream cout, const Grid& t) {
+ return cout << "Grid { startVtxID " << t.startVtxID << ", lineVtxOffset " << t.lineVtxOffset << ", resX " << t.resX << ", resY " << t.resY << " }";
+ }
+ };
+
+ public:
+
+ /*! grid mesh construction */
+ GridMesh (Device* device);
+
+ /* geometry interface */
+ public:
+ void setMask(unsigned mask);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify();
+ void interpolate(const RTCInterpolateArguments* const args);
+
+ template<int N>
+ void interpolate_impl(const RTCInterpolateArguments* const args)
+ {
+ unsigned int primID = args->primID;
+ float U = args->u;
+ float V = args->v;
+
+ /* clamp input u,v to [0;1] range */
+ U = max(min(U,1.0f),0.0f);
+ V = max(min(V,1.0f),0.0f);
+
+ RTCBufferType bufferType = args->bufferType;
+ unsigned int bufferSlot = args->bufferSlot;
+ float* P = args->P;
+ float* dPdu = args->dPdu;
+ float* dPdv = args->dPdv;
+ float* ddPdudu = args->ddPdudu;
+ float* ddPdvdv = args->ddPdvdv;
+ float* ddPdudv = args->ddPdudv;
+ unsigned int valueCount = args->valueCount;
+
+ /* calculate base pointer and stride */
+ assert((bufferType == RTC_BUFFER_TYPE_VERTEX && bufferSlot < numTimeSteps) ||
+ (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE && bufferSlot <= vertexAttribs.size()));
+ const char* src = nullptr;
+ size_t stride = 0;
+ if (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE) {
+ src = vertexAttribs[bufferSlot].getPtr();
+ stride = vertexAttribs[bufferSlot].getStride();
+ } else {
+ src = vertices[bufferSlot].getPtr();
+ stride = vertices[bufferSlot].getStride();
+ }
+
+ const Grid& grid = grids[primID];
+ const int grid_width = grid.resX-1;
+ const int grid_height = grid.resY-1;
+ const float rcp_grid_width = rcp(float(grid_width));
+ const float rcp_grid_height = rcp(float(grid_height));
+ const int iu = min((int)floor(U*grid_width ),grid_width);
+ const int iv = min((int)floor(V*grid_height),grid_height);
+ const float u = U*grid_width-float(iu);
+ const float v = V*grid_height-float(iv);
+
+ for (unsigned int i=0; i<valueCount; i+=N)
+ {
+ const size_t ofs = i*sizeof(float);
+ const unsigned int idx0 = grid.startVtxID + (iv+0)*grid.lineVtxOffset + iu;
+ const unsigned int idx1 = grid.startVtxID + (iv+1)*grid.lineVtxOffset + iu;
+
+ const vbool<N> valid = vint<N>((int)i)+vint<N>(step) < vint<N>(int(valueCount));
+ const vfloat<N> p0 = mem<vfloat<N>>::loadu(valid,(float*)&src[(idx0+0)*stride+ofs]);
+ const vfloat<N> p1 = mem<vfloat<N>>::loadu(valid,(float*)&src[(idx0+1)*stride+ofs]);
+ const vfloat<N> p2 = mem<vfloat<N>>::loadu(valid,(float*)&src[(idx1+1)*stride+ofs]);
+ const vfloat<N> p3 = mem<vfloat<N>>::loadu(valid,(float*)&src[(idx1+0)*stride+ofs]);
+ const vbool<N> left = u+v <= 1.0f;
+ const vfloat<N> Q0 = select(left,p0,p2);
+ const vfloat<N> Q1 = select(left,p1,p3);
+ const vfloat<N> Q2 = select(left,p3,p1);
+ const vfloat<N> U = select(left,u,vfloat<N>(1.0f)-u);
+ const vfloat<N> V = select(left,v,vfloat<N>(1.0f)-v);
+ const vfloat<N> W = 1.0f-U-V;
+
+ if (P) {
+ mem<vfloat<N>>::storeu(valid,P+i,madd(W,Q0,madd(U,Q1,V*Q2)));
+ }
+ if (dPdu) {
+ assert(dPdu); mem<vfloat<N>>::storeu(valid,dPdu+i,select(left,Q1-Q0,Q0-Q1)*rcp_grid_width);
+ assert(dPdv); mem<vfloat<N>>::storeu(valid,dPdv+i,select(left,Q2-Q0,Q0-Q2)*rcp_grid_height);
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); mem<vfloat<N>>::storeu(valid,ddPdudu+i,vfloat<N>(zero));
+ assert(ddPdvdv); mem<vfloat<N>>::storeu(valid,ddPdvdv+i,vfloat<N>(zero));
+ assert(ddPdudv); mem<vfloat<N>>::storeu(valid,ddPdudv+i,vfloat<N>(zero));
+ }
+ }
+ }
+
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ __forceinline unsigned int getNumSubGrids(const size_t gridID)
+ {
+ const Grid &g = grid(gridID);
+ return max((unsigned int)1,((unsigned int)g.resX >> 1) * ((unsigned int)g.resY >> 1));
+ }
+
+ /*! get fast access to first vertex buffer */
+ __forceinline float * getCompactVertexArray () const {
+ return (float*) vertices0.getPtr();
+ }
+
+ public:
+
+ /*! returns number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns i'th grid*/
+ __forceinline const Grid& grid(size_t i) const {
+ return grids[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const Vec3fa vertex(size_t i) const { // FIXME: check if this does a unaligned load
+ return vertices0[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const char* vertexPtr(size_t i) const {
+ return vertices0.getPtr(i);
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const Vec3fa vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i, size_t itime) const {
+ return vertices[itime].getPtr(i);
+ }
+
+ /*! returns i'th vertex of the first timestep */
+ __forceinline size_t grid_vertex_index(const Grid& g, size_t x, size_t y) const {
+ assert(x < (size_t)g.resX);
+ assert(y < (size_t)g.resY);
+ return g.startVtxID + x + y * g.lineVtxOffset;
+ }
+
+ /*! returns i'th vertex of the first timestep */
+ __forceinline const Vec3fa grid_vertex(const Grid& g, size_t x, size_t y) const {
+ const size_t index = grid_vertex_index(g,x,y);
+ return vertex(index);
+ }
+
+ /*! returns i'th vertex of the itime'th timestep */
+ __forceinline const Vec3fa grid_vertex(const Grid& g, size_t x, size_t y, size_t itime) const {
+ const size_t index = grid_vertex_index(g,x,y);
+ return vertex(index,itime);
+ }
+
+ /*! calculates the build bounds of the i'th primitive, if it's valid */
+ __forceinline bool buildBounds(const Grid& g, size_t sx, size_t sy, BBox3fa& bbox) const
+ {
+ BBox3fa b(empty);
+ for (size_t t=0; t<numTimeSteps; t++)
+ {
+ for (size_t y=sy;y<min(sy+3,(size_t)g.resY);y++)
+ for (size_t x=sx;x<min(sx+3,(size_t)g.resX);x++)
+ {
+ const Vec3fa v = grid_vertex(g,x,y,t);
+ if (unlikely(!isvalid(v))) return false;
+ b.extend(v);
+ }
+ }
+
+ bbox = b;
+ return true;
+ }
+
+ /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(const Grid& g, size_t sx, size_t sy, size_t itime, BBox3fa& bbox) const
+ {
+ assert(itime < numTimeSteps);
+ BBox3fa b0(empty);
+ for (size_t y=sy;y<min(sy+3,(size_t)g.resY);y++)
+ for (size_t x=sx;x<min(sx+3,(size_t)g.resX);x++)
+ {
+ const Vec3fa v = grid_vertex(g,x,y,itime);
+ if (unlikely(!isvalid(v))) return false;
+ b0.extend(v);
+ }
+
+ /* use bounds of first time step in builder */
+ bbox = b0;
+ return true;
+ }
+
+ __forceinline bool valid(size_t gridID, size_t itime=0) const {
+ return valid(gridID, make_range(itime, itime));
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t gridID, const range<size_t>& itime_range) const
+ {
+ if (unlikely(gridID >= grids.size())) return false;
+ const Grid &g = grid(gridID);
+ if (unlikely(g.startVtxID + 0 >= vertices0.size())) return false;
+ if (unlikely(g.startVtxID + (g.resY-1)*g.lineVtxOffset + g.resX-1 >= vertices0.size())) return false;
+
+ for (size_t y=0;y<g.resY;y++)
+ for (size_t x=0;x<g.resX;x++)
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ if (!isvalid(grid_vertex(g,x,y,itime))) return false;
+ return true;
+ }
+
+
+ __forceinline BBox3fa bounds(const Grid& g, size_t sx, size_t sy, size_t itime) const
+ {
+ BBox3fa box(empty);
+ buildBounds(g,sx,sy,itime,box);
+ return box;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Grid& g, size_t sx, size_t sy, size_t itime) const {
+ BBox3fa bounds0, bounds1;
+ buildBounds(g,sx,sy,itime+0,bounds0);
+ buildBounds(g,sx,sy,itime+1,bounds1);
+ return LBBox3fa(bounds0,bounds1);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(const Grid& g, size_t sx, size_t sy, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(g,sx,sy,itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ public:
+ BufferView<Grid> grids; //!< array of triangles
+ BufferView<Vec3fa> vertices0; //!< fast access to first vertex buffer
+ vector<BufferView<Vec3fa>> vertices; //!< vertex array for each timestep
+ vector<RawBufferView> vertexAttribs; //!< vertex attributes
+ };
+
+ namespace isa
+ {
+ struct GridMeshISA : public GridMesh
+ {
+ GridMeshISA (Device* device)
+ : GridMesh(device) {}
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(GridMesh*, createGridMesh, Device*);
+}
diff --git a/thirdparty/embree/kernels/common/scene_instance.h b/thirdparty/embree/kernels/common/scene_instance.h
new file mode 100644
index 0000000000..773f2b6fec
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene_instance.h
@@ -0,0 +1,272 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "geometry.h"
+#include "accel.h"
+
+namespace embree
+{
+ struct MotionDerivativeCoefficients;
+
+ /*! Instanced acceleration structure */
+ struct Instance : public Geometry
+ {
+ ALIGNED_STRUCT_(16);
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_INSTANCE;
+
+ public:
+ Instance (Device* device, Accel* object = nullptr, unsigned int numTimeSteps = 1);
+ ~Instance();
+
+ private:
+ Instance (const Instance& other) DELETED; // do not implement
+ Instance& operator= (const Instance& other) DELETED; // do not implement
+
+ private:
+ LBBox3fa nonlinearBounds(const BBox1f& time_range_in,
+ const BBox1f& geom_time_range,
+ float geom_time_segments) const;
+
+ BBox3fa boundSegment(size_t itime,
+ BBox3fa const& obbox0, BBox3fa const& obbox1,
+ BBox3fa const& bbox0, BBox3fa const& bbox1,
+ float t_min, float t_max) const;
+
+ /* calculates the (correct) interpolated bounds */
+ __forceinline BBox3fa bounds(size_t itime0, size_t itime1, float f) const
+ {
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return xfmBounds(slerp(local2world[itime0], local2world[itime1], f),
+ lerp(getObjectBounds(itime0), getObjectBounds(itime1), f));
+ return xfmBounds(lerp(local2world[itime0], local2world[itime1], f),
+ lerp(getObjectBounds(itime0), getObjectBounds(itime1), f));
+ }
+
+ public:
+ virtual void setNumTimeSteps (unsigned int numTimeSteps) override;
+ virtual void setInstancedScene(const Ref<Scene>& scene) override;
+ virtual void setTransform(const AffineSpace3fa& local2world, unsigned int timeStep) override;
+ virtual void setQuaternionDecomposition(const AffineSpace3ff& qd, unsigned int timeStep) override;
+ virtual AffineSpace3fa getTransform(float time) override;
+ virtual void setMask (unsigned mask) override;
+ virtual void build() {}
+ virtual void addElementsToCount (GeometryCounts & counts) const override;
+ virtual void commit() override;
+
+ public:
+
+ /*! calculates the bounds of instance */
+ __forceinline BBox3fa bounds(size_t i) const {
+ assert(i == 0);
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return xfmBounds(quaternionDecompositionToAffineSpace(local2world[0]),object->bounds.bounds());
+ return xfmBounds(local2world[0],object->bounds.bounds());
+ }
+
+ /*! gets the bounds of the instanced scene */
+ __forceinline BBox3fa getObjectBounds(size_t itime) const {
+ return object->getBounds(timeStep(itime));
+ }
+
+ /*! calculates the bounds of instance */
+ __forceinline BBox3fa bounds(size_t i, size_t itime) const {
+ assert(i == 0);
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return xfmBounds(quaternionDecompositionToAffineSpace(local2world[itime]),getObjectBounds(itime));
+ return xfmBounds(local2world[itime],getObjectBounds(itime));
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t i, const BBox1f& dt) const {
+ assert(i == 0);
+ LBBox3fa lbbox = nonlinearBounds(dt, time_range, fnumTimeSegments);
+ return lbbox;
+ }
+
+ /*! calculates the build bounds of the i'th item, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
+ {
+ assert(i==0);
+ const BBox3fa b = bounds(i);
+ if (bbox) *bbox = b;
+ return isvalid(b);
+ }
+
+ /*! calculates the build bounds of the i'th item at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ assert(i==0);
+ const LBBox3fa bounds = linearBounds(i,itime);
+ bbox = bounds.bounds ();
+ return isvalid(bounds);
+ }
+
+ /* gets version info of topology */
+ unsigned int getTopologyVersion() const {
+ return numPrimitives;
+ }
+
+ /* returns true if topology changed */
+ bool topologyChanged(unsigned int otherVersion) const {
+ return numPrimitives != otherVersion;
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ assert(i == 0);
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ if (!isvalid(bounds(i,itime))) return false;
+
+ return true;
+ }
+
+ __forceinline AffineSpace3fa getLocal2World() const
+ {
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return quaternionDecompositionToAffineSpace(local2world[0]);
+ return local2world[0];
+ }
+
+ __forceinline AffineSpace3fa getLocal2World(float t) const
+ {
+ float ftime; const unsigned int itime = timeSegment(t, ftime);
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return slerp(local2world[itime+0],local2world[itime+1],ftime);
+ return lerp(local2world[itime+0],local2world[itime+1],ftime);
+ }
+
+ __forceinline AffineSpace3fa getWorld2Local() const {
+ return world2local0;
+ }
+
+ __forceinline AffineSpace3fa getWorld2Local(float t) const {
+ return rcp(getLocal2World(t));
+ }
+
+ template<int K>
+ __forceinline AffineSpace3vf<K> getWorld2Local(const vbool<K>& valid, const vfloat<K>& t) const
+ {
+ if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION))
+ return getWorld2LocalSlerp<K>(valid, t);
+ return getWorld2LocalLerp<K>(valid, t);
+ }
+
+ private:
+
+ template<int K>
+ __forceinline AffineSpace3vf<K> getWorld2LocalSlerp(const vbool<K>& valid, const vfloat<K>& t) const
+ {
+ vfloat<K> ftime;
+ const vint<K> itime_k = timeSegment<K>(t, ftime);
+ assert(any(valid));
+ const size_t index = bsf(movemask(valid));
+ const int itime = itime_k[index];
+ if (likely(all(valid, itime_k == vint<K>(itime)))) {
+ return rcp(slerp(AffineSpace3vff<K>(local2world[itime+0]),
+ AffineSpace3vff<K>(local2world[itime+1]),
+ ftime));
+ }
+ else {
+ AffineSpace3vff<K> space0,space1;
+ vbool<K> valid1 = valid;
+ while (any(valid1)) {
+ vbool<K> valid2;
+ const int itime = next_unique(valid1, itime_k, valid2);
+ space0 = select(valid2, AffineSpace3vff<K>(local2world[itime+0]), space0);
+ space1 = select(valid2, AffineSpace3vff<K>(local2world[itime+1]), space1);
+ }
+ return rcp(slerp(space0, space1, ftime));
+ }
+ }
+
+ template<int K>
+ __forceinline AffineSpace3vf<K> getWorld2LocalLerp(const vbool<K>& valid, const vfloat<K>& t) const
+ {
+ vfloat<K> ftime;
+ const vint<K> itime_k = timeSegment<K>(t, ftime);
+ assert(any(valid));
+ const size_t index = bsf(movemask(valid));
+ const int itime = itime_k[index];
+ if (likely(all(valid, itime_k == vint<K>(itime)))) {
+ return rcp(lerp(AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+0]),
+ AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+1]),
+ ftime));
+ } else {
+ AffineSpace3vf<K> space0,space1;
+ vbool<K> valid1 = valid;
+ while (any(valid1)) {
+ vbool<K> valid2;
+ const int itime = next_unique(valid1, itime_k, valid2);
+ space0 = select(valid2, AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+0]), space0);
+ space1 = select(valid2, AffineSpace3vf<K>((AffineSpace3fa)local2world[itime+1]), space1);
+ }
+ return rcp(lerp(space0, space1, ftime));
+ }
+ }
+
+ public:
+ Accel* object; //!< pointer to instanced acceleration structure
+ AffineSpace3ff* local2world; //!< transformation from local space to world space for each timestep (either normal matrix or quaternion decomposition)
+ AffineSpace3fa world2local0; //!< transformation from world space to local space for timestep 0
+ };
+
+ namespace isa
+ {
+ struct InstanceISA : public Instance
+ {
+ InstanceISA (Device* device)
+ : Instance(device) {}
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ assert(r.begin() == 0);
+ assert(r.end() == 1);
+
+ PrimInfo pinfo(empty);
+ BBox3fa b = empty;
+ if (!buildBounds(0,&b)) return pinfo;
+ // const BBox3fa b = bounds(0);
+ // if (!isvalid(b)) return pinfo;
+
+ const PrimRef prim(b,geomID,unsigned(0));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ assert(r.begin() == 0);
+ assert(r.end() == 1);
+
+ PrimInfo pinfo(empty);
+ BBox3fa b = empty;
+ if (!buildBounds(0,&b)) return pinfo;
+ // if (!valid(0,range<size_t>(itime))) return pinfo;
+ // const PrimRef prim(linearBounds(0,itime).bounds(),geomID,unsigned(0));
+ const PrimRef prim(b,geomID,unsigned(0));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ assert(r.begin() == 0);
+ assert(r.end() == 1);
+
+ PrimInfoMB pinfo(empty);
+ if (!valid(0, timeSegmentRange(t0t1))) return pinfo;
+ const PrimRefMB prim(linearBounds(0,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(0));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ return pinfo;
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(Instance*, createInstance, Device*);
+}
diff --git a/thirdparty/embree/kernels/common/scene_line_segments.h b/thirdparty/embree/kernels/common/scene_line_segments.h
new file mode 100644
index 0000000000..3c9fdb39db
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene_line_segments.h
@@ -0,0 +1,345 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+#include "geometry.h"
+#include "buffer.h"
+
+namespace embree
+{
+ /*! represents an array of line segments */
+ struct LineSegments : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_CURVE2;
+
+ public:
+
+ /*! line segments construction */
+ LineSegments (Device* device, Geometry::GType gtype);
+
+ public:
+ void setMask (unsigned mask);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify ();
+ void interpolate(const RTCInterpolateArguments* const args);
+ void setTessellationRate(float N);
+ void setMaxRadiusScale(float s);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ template<int N>
+ void interpolate_impl(const RTCInterpolateArguments* const args)
+ {
+ unsigned int primID = args->primID;
+ float u = args->u;
+ RTCBufferType bufferType = args->bufferType;
+ unsigned int bufferSlot = args->bufferSlot;
+ float* P = args->P;
+ float* dPdu = args->dPdu;
+ float* ddPdudu = args->ddPdudu;
+ unsigned int valueCount = args->valueCount;
+
+ /* calculate base pointer and stride */
+ assert((bufferType == RTC_BUFFER_TYPE_VERTEX && bufferSlot < numTimeSteps) ||
+ (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE && bufferSlot <= vertexAttribs.size()));
+ const char* src = nullptr;
+ size_t stride = 0;
+ if (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE) {
+ src = vertexAttribs[bufferSlot].getPtr();
+ stride = vertexAttribs[bufferSlot].getStride();
+ } else {
+ src = vertices[bufferSlot].getPtr();
+ stride = vertices[bufferSlot].getStride();
+ }
+
+ for (unsigned int i=0; i<valueCount; i+=N)
+ {
+ const size_t ofs = i*sizeof(float);
+ const size_t segment = segments[primID];
+ const vbool<N> valid = vint<N>((int)i)+vint<N>(step) < vint<N>(int(valueCount));
+ const vfloat<N> p0 = mem<vfloat<N>>::loadu(valid,(float*)&src[(segment+0)*stride+ofs]);
+ const vfloat<N> p1 = mem<vfloat<N>>::loadu(valid,(float*)&src[(segment+1)*stride+ofs]);
+ if (P ) mem<vfloat<N>>::storeu(valid,P+i,lerp(p0,p1,u));
+ if (dPdu ) mem<vfloat<N>>::storeu(valid,dPdu+i,p1-p0);
+ if (ddPdudu) mem<vfloat<N>>::storeu(valid,dPdu+i,vfloat<N>(zero));
+ }
+ }
+
+ public:
+
+ /*! returns the number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns the i'th segment */
+ __forceinline const unsigned int& segment(size_t i) const {
+ return segments[i];
+ }
+
+ /*! returns the segment to the left of the i'th segment */
+ __forceinline bool segmentLeftExists(size_t i) const {
+ assert (flags);
+ return (flags[i] & RTC_CURVE_FLAG_NEIGHBOR_LEFT) != 0;
+ }
+
+ /*! returns the segment to the right of the i'th segment */
+ __forceinline bool segmentRightExists(size_t i) const {
+ assert (flags);
+ return (flags[i] & RTC_CURVE_FLAG_NEIGHBOR_RIGHT) != 0;
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline Vec3ff vertex(size_t i) const {
+ return vertices0[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const char* vertexPtr(size_t i) const {
+ return vertices0.getPtr(i);
+ }
+
+ /*! returns i'th normal of the first time step */
+ __forceinline Vec3fa normal(size_t i) const {
+ return normals0[i];
+ }
+
+ /*! returns i'th radius of the first time step */
+ __forceinline float radius(size_t i) const {
+ return vertices0[i].w;
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline Vec3ff vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i, size_t itime) const {
+ return vertices[itime].getPtr(i);
+ }
+
+ /*! returns i'th normal of itime'th timestep */
+ __forceinline Vec3fa normal(size_t i, size_t itime) const {
+ return normals[itime][i];
+ }
+
+ /*! returns i'th radius of itime'th timestep */
+ __forceinline float radius(size_t i, size_t itime) const {
+ return vertices[itime][i].w;
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(const Vec3ff& v0, const Vec3ff& v1) const
+ {
+ const BBox3ff b = merge(BBox3ff(v0),BBox3ff(v1));
+ return enlarge((BBox3fa)b,maxRadiusScale*Vec3fa(max(v0.w,v1.w)));
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ const unsigned int index = segment(i);
+ const Vec3ff v0 = vertex(index+0);
+ const Vec3ff v1 = vertex(index+1);
+ return bounds(v0,v1);
+ }
+
+ /*! calculates bounding box of i'th line segment for the itime'th time step */
+ __forceinline BBox3fa bounds(size_t i, size_t itime) const
+ {
+ const unsigned int index = segment(i);
+ const Vec3ff v0 = vertex(index+0,itime);
+ const Vec3ff v1 = vertex(index+1,itime);
+ return bounds(v0,v1);
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(const LinearSpace3fa& space, size_t i) const
+ {
+ const unsigned int index = segment(i);
+ const Vec3ff v0 = vertex(index+0);
+ const Vec3ff v1 = vertex(index+1);
+ const Vec3ff w0(xfmVector(space,(Vec3fa)v0),v0.w);
+ const Vec3ff w1(xfmVector(space,(Vec3fa)v1),v1.w);
+ return bounds(w0,w1);
+ }
+
+ /*! calculates bounding box of i'th line segment for the itime'th time step */
+ __forceinline BBox3fa bounds(const LinearSpace3fa& space, size_t i, size_t itime) const
+ {
+ const unsigned int index = segment(i);
+ const Vec3ff v0 = vertex(index+0,itime);
+ const Vec3ff v1 = vertex(index+1,itime);
+ const Vec3ff w0(xfmVector(space,(Vec3fa)v0),v0.w);
+ const Vec3ff w1(xfmVector(space,(Vec3fa)v1),v1.w);
+ return bounds(w0,w1);
+ }
+
+ /*! check if the i'th primitive is valid at the itime'th timestep */
+ __forceinline bool valid(size_t i, size_t itime) const {
+ return valid(i, make_range(itime, itime));
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ const unsigned int index = segment(i);
+ if (index+1 >= numVertices()) return false;
+
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ {
+ const Vec3ff v0 = vertex(index+0,itime); if (unlikely(!isvalid4(v0))) return false;
+ const Vec3ff v1 = vertex(index+1,itime); if (unlikely(!isvalid4(v1))) return false;
+ if (min(v0.w,v1.w) < 0.0f) return false;
+ }
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive at the itimeGlobal'th time segment */
+ __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const {
+ return LBBox3fa(bounds(i,itime+0),bounds(i,itime+1));
+ }
+
+ /*! calculates the build bounds of the i'th primitive, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox) const
+ {
+ if (!valid(i,0)) return false;
+ *bbox = bounds(i);
+ return true;
+ }
+
+ /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ if (!valid(i,itime+0) || !valid(i,itime+1)) return false;
+ bbox = bounds(i,itime); // use bounds of first time step in builder
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(space, primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline bool linearBounds(size_t i, const BBox1f& time_range, LBBox3fa& bbox) const
+ {
+ if (!valid(i, timeSegmentRange(time_range))) return false;
+ bbox = linearBounds(i, time_range);
+ return true;
+ }
+
+ /*! get fast access to first vertex buffer */
+ __forceinline float * getCompactVertexArray () const {
+ return (float*) vertices0.getPtr();
+ }
+
+ public:
+ BufferView<unsigned int> segments; //!< array of line segment indices
+ BufferView<Vec3ff> vertices0; //!< fast access to first vertex buffer
+ BufferView<Vec3fa> normals0; //!< fast access to first normal buffer
+ BufferView<char> flags; //!< start, end flag per segment
+ vector<BufferView<Vec3ff>> vertices; //!< vertex array for each timestep
+ vector<BufferView<Vec3fa>> normals; //!< normal array for each timestep
+ vector<BufferView<char>> vertexAttribs; //!< user buffers
+ int tessellationRate; //!< tessellation rate for bezier curve
+ float maxRadiusScale = 1.0; //!< maximal min-width scaling of curve radii
+ };
+
+ namespace isa
+ {
+ struct LineSegmentsISA : public LineSegments
+ {
+ LineSegmentsISA (Device* device, Geometry::GType gtype)
+ : LineSegments(device,gtype) {}
+
+ Vec3fa computeDirection(unsigned int primID) const
+ {
+ const unsigned vtxID = segment(primID);
+ const Vec3fa v0 = vertex(vtxID+0);
+ const Vec3fa v1 = vertex(vtxID+1);
+ return v1-v0;
+ }
+
+ Vec3fa computeDirection(unsigned int primID, size_t time) const
+ {
+ const unsigned vtxID = segment(primID);
+ const Vec3fa v0 = vertex(vtxID+0,time);
+ const Vec3fa v1 = vertex(vtxID+1,time);
+ return v1-v0;
+ }
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,&bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,itime,bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!valid(j, timeSegmentRange(t0t1))) continue;
+ const PrimRefMB prim(linearBounds(j,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(j));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ BBox3fa vbounds(size_t i) const {
+ return bounds(i);
+ }
+
+ BBox3fa vbounds(const LinearSpace3fa& space, size_t i) const {
+ return bounds(space,i);
+ }
+
+ LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const {
+ return linearBounds(primID,time_range);
+ }
+
+ LBBox3fa vlinearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const {
+ return linearBounds(space,primID,time_range);
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(LineSegments*, createLineSegments, Device* COMMA Geometry::GType);
+}
diff --git a/thirdparty/embree/kernels/common/scene_points.h b/thirdparty/embree/kernels/common/scene_points.h
new file mode 100644
index 0000000000..017e098a51
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene_points.h
@@ -0,0 +1,282 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "buffer.h"
+#include "default.h"
+#include "geometry.h"
+
+namespace embree
+{
+ /*! represents an array of points */
+ struct Points : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_POINTS;
+
+ public:
+ /*! line segments construction */
+ Points(Device* device, Geometry::GType gtype);
+
+ public:
+ void setMask(unsigned mask);
+ void setNumTimeSteps(unsigned int numTimeSteps);
+ void setVertexAttributeCount(unsigned int N);
+ void setBuffer(RTCBufferType type,
+ unsigned int slot,
+ RTCFormat format,
+ const Ref<Buffer>& buffer,
+ size_t offset,
+ size_t stride,
+ unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify();
+ void setMaxRadiusScale(float s);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ public:
+ /*! returns the number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline Vec3ff vertex(size_t i) const {
+ return vertices0[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const char* vertexPtr(size_t i) const {
+ return vertices0.getPtr(i);
+ }
+
+ /*! returns i'th normal of the first time step */
+ __forceinline Vec3fa normal(size_t i) const {
+ return normals0[i];
+ }
+
+ /*! returns i'th radius of the first time step */
+ __forceinline float radius(size_t i) const {
+ return vertices0[i].w;
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline Vec3ff vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i, size_t itime) const {
+ return vertices[itime].getPtr(i);
+ }
+
+ /*! returns i'th normal of itime'th timestep */
+ __forceinline Vec3fa normal(size_t i, size_t itime) const {
+ return normals[itime][i];
+ }
+
+ /*! returns i'th radius of itime'th timestep */
+ __forceinline float radius(size_t i, size_t itime) const {
+ return vertices[itime][i].w;
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(const Vec3ff& v0) const {
+ return enlarge(BBox3fa(v0), maxRadiusScale*Vec3fa(v0.w));
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ const Vec3ff v0 = vertex(i);
+ return bounds(v0);
+ }
+
+ /*! calculates bounding box of i'th line segment for the itime'th time step */
+ __forceinline BBox3fa bounds(size_t i, size_t itime) const
+ {
+ const Vec3ff v0 = vertex(i, itime);
+ return bounds(v0);
+ }
+
+ /*! calculates bounding box of i'th line segment */
+ __forceinline BBox3fa bounds(const LinearSpace3fa& space, size_t i) const
+ {
+ const Vec3ff v0 = vertex(i);
+ const Vec3ff w0(xfmVector(space, (Vec3fa)v0), v0.w);
+ return bounds(w0);
+ }
+
+ /*! calculates bounding box of i'th line segment for the itime'th time step */
+ __forceinline BBox3fa bounds(const LinearSpace3fa& space, size_t i, size_t itime) const
+ {
+ const Vec3ff v0 = vertex(i, itime);
+ const Vec3ff w0(xfmVector(space, (Vec3fa)v0), v0.w);
+ return bounds(w0);
+ }
+
+ /*! check if the i'th primitive is valid at the itime'th timestep */
+ __forceinline bool valid(size_t i, size_t itime) const {
+ return valid(i, make_range(itime, itime));
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ const unsigned int index = (unsigned int)i;
+ if (index >= numVertices())
+ return false;
+
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++) {
+ const Vec3ff v0 = vertex(index + 0, itime);
+ if (unlikely(!isvalid4(v0)))
+ return false;
+ if (v0.w < 0.0f)
+ return false;
+ }
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive at the itimeGlobal'th time segment */
+ __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const {
+ return LBBox3fa(bounds(i, itime + 0), bounds(i, itime + 1));
+ }
+
+ /*! calculates the build bounds of the i'th primitive, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox) const
+ {
+ if (!valid(i, 0))
+ return false;
+ *bbox = bounds(i);
+ return true;
+ }
+
+ /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ if (!valid(i, itime + 0) || !valid(i, itime + 1))
+ return false;
+ bbox = bounds(i, itime); // use bounds of first time step in builder
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&](size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&](size_t itime) { return bounds(space, primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline bool linearBounds(size_t i, const BBox1f& time_range, LBBox3fa& bbox) const
+ {
+ if (!valid(i, timeSegmentRange(time_range))) return false;
+ bbox = linearBounds(i, time_range);
+ return true;
+ }
+
+ /*! get fast access to first vertex buffer */
+ __forceinline float * getCompactVertexArray () const {
+ return (float*) vertices0.getPtr();
+ }
+
+ public:
+ BufferView<Vec3ff> vertices0; //!< fast access to first vertex buffer
+ BufferView<Vec3fa> normals0; //!< fast access to first normal buffer
+ vector<BufferView<Vec3ff>> vertices; //!< vertex array for each timestep
+ vector<BufferView<Vec3fa>> normals; //!< normal array for each timestep
+ vector<BufferView<char>> vertexAttribs; //!< user buffers
+ float maxRadiusScale = 1.0; //!< maximal min-width scaling of curve radii
+ };
+
+ namespace isa
+ {
+ struct PointsISA : public Points
+ {
+ PointsISA(Device* device, Geometry::GType gtype) : Points(device, gtype) {}
+
+ Vec3fa computeDirection(unsigned int primID) const
+ {
+ return Vec3fa(1, 0, 0);
+ }
+
+ Vec3fa computeDirection(unsigned int primID, size_t time) const
+ {
+ return Vec3fa(1, 0, 0);
+ }
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j = r.begin(); j < r.end(); j++) {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j, &bounds))
+ continue;
+ const PrimRef prim(bounds, geomID, unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j = r.begin(); j < r.end(); j++) {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j, itime, bounds))
+ continue;
+ const PrimRef prim(bounds, geomID, unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims,
+ const BBox1f& t0t1,
+ const range<size_t>& r,
+ size_t k,
+ unsigned int geomID) const
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j = r.begin(); j < r.end(); j++) {
+ if (!valid(j, timeSegmentRange(t0t1)))
+ continue;
+ const PrimRefMB prim(linearBounds(j, t0t1), this->numTimeSegments(), this->time_range, this->numTimeSegments(), geomID, unsigned(j));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ BBox3fa vbounds(size_t i) const
+ {
+ return bounds(i);
+ }
+
+ BBox3fa vbounds(const LinearSpace3fa& space, size_t i) const
+ {
+ return bounds(space, i);
+ }
+
+ LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const
+ {
+ return linearBounds(primID, time_range);
+ }
+
+ LBBox3fa vlinearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const
+ {
+ return linearBounds(space, primID, time_range);
+ }
+ };
+ } // namespace isa
+
+ DECLARE_ISA_FUNCTION(Points*, createPoints, Device* COMMA Geometry::GType);
+} // namespace embree
diff --git a/thirdparty/embree/kernels/common/scene_quad_mesh.h b/thirdparty/embree/kernels/common/scene_quad_mesh.h
new file mode 100644
index 0000000000..bd8eeaaeb7
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene_quad_mesh.h
@@ -0,0 +1,337 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "geometry.h"
+#include "buffer.h"
+
+namespace embree
+{
+ /*! Quad Mesh */
+ struct QuadMesh : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_QUAD_MESH;
+
+ /*! triangle indices */
+ struct Quad
+ {
+ uint32_t v[4];
+
+ /*! outputs triangle indices */
+ __forceinline friend embree_ostream operator<<(embree_ostream cout, const Quad& q) {
+ return cout << "Quad {" << q.v[0] << ", " << q.v[1] << ", " << q.v[2] << ", " << q.v[3] << " }";
+ }
+ };
+
+ public:
+
+ /*! quad mesh construction */
+ QuadMesh (Device* device);
+
+ /* geometry interface */
+ public:
+ void setMask(unsigned mask);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify();
+ void interpolate(const RTCInterpolateArguments* const args);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ template<int N>
+ void interpolate_impl(const RTCInterpolateArguments* const args)
+ {
+ unsigned int primID = args->primID;
+ float u = args->u;
+ float v = args->v;
+ RTCBufferType bufferType = args->bufferType;
+ unsigned int bufferSlot = args->bufferSlot;
+ float* P = args->P;
+ float* dPdu = args->dPdu;
+ float* dPdv = args->dPdv;
+ float* ddPdudu = args->ddPdudu;
+ float* ddPdvdv = args->ddPdvdv;
+ float* ddPdudv = args->ddPdudv;
+ unsigned int valueCount = args->valueCount;
+
+ /* calculate base pointer and stride */
+ assert((bufferType == RTC_BUFFER_TYPE_VERTEX && bufferSlot < numTimeSteps) ||
+ (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE && bufferSlot <= vertexAttribs.size()));
+ const char* src = nullptr;
+ size_t stride = 0;
+ if (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE) {
+ src = vertexAttribs[bufferSlot].getPtr();
+ stride = vertexAttribs[bufferSlot].getStride();
+ } else {
+ src = vertices[bufferSlot].getPtr();
+ stride = vertices[bufferSlot].getStride();
+ }
+
+ for (unsigned int i=0; i<valueCount; i+=N)
+ {
+ const vbool<N> valid = vint<N>((int)i)+vint<N>(step) < vint<N>(int(valueCount));
+ const size_t ofs = i*sizeof(float);
+ const Quad& tri = quad(primID);
+ const vfloat<N> p0 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[0]*stride+ofs]);
+ const vfloat<N> p1 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[1]*stride+ofs]);
+ const vfloat<N> p2 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[2]*stride+ofs]);
+ const vfloat<N> p3 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[3]*stride+ofs]);
+ const vbool<N> left = u+v <= 1.0f;
+ const vfloat<N> Q0 = select(left,p0,p2);
+ const vfloat<N> Q1 = select(left,p1,p3);
+ const vfloat<N> Q2 = select(left,p3,p1);
+ const vfloat<N> U = select(left,u,vfloat<N>(1.0f)-u);
+ const vfloat<N> V = select(left,v,vfloat<N>(1.0f)-v);
+ const vfloat<N> W = 1.0f-U-V;
+ if (P) {
+ mem<vfloat<N>>::storeu(valid,P+i,madd(W,Q0,madd(U,Q1,V*Q2)));
+ }
+ if (dPdu) {
+ assert(dPdu); mem<vfloat<N>>::storeu(valid,dPdu+i,select(left,Q1-Q0,Q0-Q1));
+ assert(dPdv); mem<vfloat<N>>::storeu(valid,dPdv+i,select(left,Q2-Q0,Q0-Q2));
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); mem<vfloat<N>>::storeu(valid,ddPdudu+i,vfloat<N>(zero));
+ assert(ddPdvdv); mem<vfloat<N>>::storeu(valid,ddPdvdv+i,vfloat<N>(zero));
+ assert(ddPdudv); mem<vfloat<N>>::storeu(valid,ddPdudv+i,vfloat<N>(zero));
+ }
+ }
+ }
+
+ public:
+
+ /*! returns number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns i'th quad */
+ __forceinline const Quad& quad(size_t i) const {
+ return quads[i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const Vec3fa vertex(size_t i) const {
+ return vertices0[i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i) const {
+ return vertices0.getPtr(i);
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const Vec3fa vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i, size_t itime) const {
+ return vertices[itime].getPtr(i);
+ }
+
+ /*! calculates the bounds of the i'th quad */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ const Quad& q = quad(i);
+ const Vec3fa v0 = vertex(q.v[0]);
+ const Vec3fa v1 = vertex(q.v[1]);
+ const Vec3fa v2 = vertex(q.v[2]);
+ const Vec3fa v3 = vertex(q.v[3]);
+ return BBox3fa(min(v0,v1,v2,v3),max(v0,v1,v2,v3));
+ }
+
+ /*! calculates the bounds of the i'th quad at the itime'th timestep */
+ __forceinline BBox3fa bounds(size_t i, size_t itime) const
+ {
+ const Quad& q = quad(i);
+ const Vec3fa v0 = vertex(q.v[0],itime);
+ const Vec3fa v1 = vertex(q.v[1],itime);
+ const Vec3fa v2 = vertex(q.v[2],itime);
+ const Vec3fa v3 = vertex(q.v[3],itime);
+ return BBox3fa(min(v0,v1,v2,v3),max(v0,v1,v2,v3));
+ }
+
+ /*! check if the i'th primitive is valid at the itime'th timestep */
+ __forceinline bool valid(size_t i, size_t itime) const {
+ return valid(i, make_range(itime, itime));
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ const Quad& q = quad(i);
+ if (unlikely(q.v[0] >= numVertices())) return false;
+ if (unlikely(q.v[1] >= numVertices())) return false;
+ if (unlikely(q.v[2] >= numVertices())) return false;
+ if (unlikely(q.v[3] >= numVertices())) return false;
+
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ {
+ if (!isvalid(vertex(q.v[0],itime))) return false;
+ if (!isvalid(vertex(q.v[1],itime))) return false;
+ if (!isvalid(vertex(q.v[2],itime))) return false;
+ if (!isvalid(vertex(q.v[3],itime))) return false;
+ }
+
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th quad at the itimeGlobal'th time segment */
+ __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const {
+ return LBBox3fa(bounds(i,itime+0),bounds(i,itime+1));
+ }
+
+ /*! calculates the build bounds of the i'th primitive, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
+ {
+ const Quad& q = quad(i);
+ if (q.v[0] >= numVertices()) return false;
+ if (q.v[1] >= numVertices()) return false;
+ if (q.v[2] >= numVertices()) return false;
+ if (q.v[3] >= numVertices()) return false;
+
+ for (unsigned int t=0; t<numTimeSteps; t++)
+ {
+ const Vec3fa v0 = vertex(q.v[0],t);
+ const Vec3fa v1 = vertex(q.v[1],t);
+ const Vec3fa v2 = vertex(q.v[2],t);
+ const Vec3fa v3 = vertex(q.v[3],t);
+
+ if (unlikely(!isvalid(v0) || !isvalid(v1) || !isvalid(v2) || !isvalid(v3)))
+ return false;
+ }
+
+ if (bbox)
+ *bbox = bounds(i);
+
+ return true;
+ }
+
+ /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ const Quad& q = quad(i);
+ if (unlikely(q.v[0] >= numVertices())) return false;
+ if (unlikely(q.v[1] >= numVertices())) return false;
+ if (unlikely(q.v[2] >= numVertices())) return false;
+ if (unlikely(q.v[3] >= numVertices())) return false;
+
+ assert(itime+1 < numTimeSteps);
+ const Vec3fa a0 = vertex(q.v[0],itime+0); if (unlikely(!isvalid(a0))) return false;
+ const Vec3fa a1 = vertex(q.v[1],itime+0); if (unlikely(!isvalid(a1))) return false;
+ const Vec3fa a2 = vertex(q.v[2],itime+0); if (unlikely(!isvalid(a2))) return false;
+ const Vec3fa a3 = vertex(q.v[3],itime+0); if (unlikely(!isvalid(a3))) return false;
+ const Vec3fa b0 = vertex(q.v[0],itime+1); if (unlikely(!isvalid(b0))) return false;
+ const Vec3fa b1 = vertex(q.v[1],itime+1); if (unlikely(!isvalid(b1))) return false;
+ const Vec3fa b2 = vertex(q.v[2],itime+1); if (unlikely(!isvalid(b2))) return false;
+ const Vec3fa b3 = vertex(q.v[3],itime+1); if (unlikely(!isvalid(b3))) return false;
+
+ /* use bounds of first time step in builder */
+ bbox = BBox3fa(min(a0,a1,a2,a3),max(a0,a1,a2,a3));
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline bool linearBounds(size_t i, const BBox1f& dt, LBBox3fa& bbox) const
+ {
+ if (!valid(i, timeSegmentRange(dt))) return false;
+ bbox = linearBounds(i, dt);
+ return true;
+ }
+
+ /*! get fast access to first vertex buffer */
+ __forceinline float * getCompactVertexArray () const {
+ return (float*) vertices0.getPtr();
+ }
+
+ /* gets version info of topology */
+ unsigned int getTopologyVersion() const {
+ return quads.modCounter;
+ }
+
+ /* returns true if topology changed */
+ bool topologyChanged(unsigned int otherVersion) const {
+ return quads.isModified(otherVersion); // || numPrimitivesChanged;
+ }
+
+ /* returns the projected area */
+ __forceinline float projectedPrimitiveArea(const size_t i) const {
+ const Quad& q = quad(i);
+ const Vec3fa v0 = vertex(q.v[0]);
+ const Vec3fa v1 = vertex(q.v[1]);
+ const Vec3fa v2 = vertex(q.v[2]);
+ const Vec3fa v3 = vertex(q.v[3]);
+ return areaProjectedTriangle(v0,v1,v3) +
+ areaProjectedTriangle(v1,v2,v3);
+ }
+
+ public:
+ BufferView<Quad> quads; //!< array of quads
+ BufferView<Vec3fa> vertices0; //!< fast access to first vertex buffer
+ vector<BufferView<Vec3fa>> vertices; //!< vertex array for each timestep
+ vector<BufferView<char>> vertexAttribs; //!< vertex attribute buffers
+ };
+
+ namespace isa
+ {
+ struct QuadMeshISA : public QuadMesh
+ {
+ QuadMeshISA (Device* device)
+ : QuadMesh(device) {}
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,&bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,itime,bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!valid(j, timeSegmentRange(t0t1))) continue;
+ const PrimRefMB prim(linearBounds(j,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(j));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(QuadMesh*, createQuadMesh, Device*);
+}
diff --git a/thirdparty/embree/kernels/common/scene_subdiv_mesh.h b/thirdparty/embree/kernels/common/scene_subdiv_mesh.h
new file mode 100644
index 0000000000..1db170196d
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene_subdiv_mesh.h
@@ -0,0 +1,326 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "geometry.h"
+#include "buffer.h"
+#include "../subdiv/half_edge.h"
+#include "../subdiv/tessellation_cache.h"
+#include "../subdiv/catmullclark_coefficients.h"
+#include "../subdiv/patch.h"
+#include "../../common/algorithms/parallel_map.h"
+#include "../../common/algorithms/parallel_set.h"
+
+namespace embree
+{
+ class SubdivMesh : public Geometry
+ {
+ ALIGNED_CLASS_(16);
+ public:
+
+ typedef HalfEdge::Edge Edge;
+
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_SUBDIV_MESH;
+
+ /*! structure used to sort half edges using radix sort by their key */
+ struct KeyHalfEdge
+ {
+ KeyHalfEdge() {}
+
+ KeyHalfEdge (uint64_t key, HalfEdge* edge)
+ : key(key), edge(edge) {}
+
+ __forceinline operator uint64_t() const {
+ return key;
+ }
+
+ friend __forceinline bool operator<(const KeyHalfEdge& e0, const KeyHalfEdge& e1) {
+ return e0.key < e1.key;
+ }
+
+ public:
+ uint64_t key;
+ HalfEdge* edge;
+ };
+
+ public:
+
+ /*! subdiv mesh construction */
+ SubdivMesh(Device* device);
+
+ public:
+ void setMask (unsigned mask);
+ void setSubdivisionMode (unsigned int topologyID, RTCSubdivisionMode mode);
+ void setVertexAttributeTopology(unsigned int vertexAttribID, unsigned int topologyID);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setTopologyCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void setTessellationRate(float N);
+ bool verify();
+ void commit();
+ void addElementsToCount (GeometryCounts & counts) const;
+ void setDisplacementFunction (RTCDisplacementFunctionN func);
+ unsigned int getFirstHalfEdge(unsigned int faceID);
+ unsigned int getFace(unsigned int edgeID);
+ unsigned int getNextHalfEdge(unsigned int edgeID);
+ unsigned int getPreviousHalfEdge(unsigned int edgeID);
+ unsigned int getOppositeHalfEdge(unsigned int topologyID, unsigned int edgeID);
+
+ public:
+
+ /*! return the number of faces */
+ size_t numFaces() const {
+ return faceVertices.size();
+ }
+
+ /*! return the number of edges */
+ size_t numEdges() const {
+ return topology[0].vertexIndices.size();
+ }
+
+ /*! return the number of vertices */
+ size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! calculates the bounds of the i'th subdivision patch at the j'th timestep */
+ __forceinline BBox3fa bounds(size_t i, size_t j = 0) const {
+ return topology[0].getHalfEdge(i)->bounds(vertices[j]);
+ }
+
+ /*! check if the i'th primitive is valid */
+ __forceinline bool valid(size_t i) const {
+ return topology[0].valid(i) && !invalidFace(i);
+ }
+
+ /*! check if the i'th primitive is valid for the j'th time range */
+ __forceinline bool valid(size_t i, size_t j) const {
+ return topology[0].valid(i) && !invalidFace(i,j);
+ }
+
+ /*! prints some statistics */
+ void printStatistics();
+
+ /*! initializes the half edge data structure */
+ void initializeHalfEdgeStructures ();
+
+ public:
+
+ /*! returns the vertex buffer for some time step */
+ __forceinline const BufferView<Vec3fa>& getVertexBuffer( const size_t t = 0 ) const {
+ return vertices[t];
+ }
+
+ /* returns tessellation level of edge */
+ __forceinline float getEdgeLevel(const size_t i) const
+ {
+ if (levels) return clamp(levels[i],1.0f,4096.0f); // FIXME: do we want to limit edge level?
+ else return clamp(tessellationRate,1.0f,4096.0f); // FIXME: do we want to limit edge level?
+ }
+
+ public:
+ RTCDisplacementFunctionN displFunc; //!< displacement function
+
+ /*! all buffers in this section are provided by the application */
+ public:
+
+ /*! the topology contains all data that may differ when
+ * interpolating different user data buffers */
+ struct Topology
+ {
+ public:
+
+ /*! Default topology construction */
+ Topology () : halfEdges(nullptr,0) {}
+
+ /*! Topology initialization */
+ Topology (SubdivMesh* mesh);
+
+ /*! make the class movable */
+ public:
+ Topology (Topology&& other) // FIXME: this is only required to workaround compilation issues under Windows
+ : mesh(std::move(other.mesh)),
+ vertexIndices(std::move(other.vertexIndices)),
+ subdiv_mode(std::move(other.subdiv_mode)),
+ halfEdges(std::move(other.halfEdges)),
+ halfEdges0(std::move(other.halfEdges0)),
+ halfEdges1(std::move(other.halfEdges1)) {}
+
+ Topology& operator= (Topology&& other) // FIXME: this is only required to workaround compilation issues under Windows
+ {
+ mesh = std::move(other.mesh);
+ vertexIndices = std::move(other.vertexIndices);
+ subdiv_mode = std::move(other.subdiv_mode);
+ halfEdges = std::move(other.halfEdges);
+ halfEdges0 = std::move(other.halfEdges0);
+ halfEdges1 = std::move(other.halfEdges1);
+ return *this;
+ }
+
+ public:
+ /*! check if the i'th primitive is valid in this topology */
+ __forceinline bool valid(size_t i) const
+ {
+ if (unlikely(subdiv_mode == RTC_SUBDIVISION_MODE_NO_BOUNDARY)) {
+ if (getHalfEdge(i)->faceHasBorder()) return false;
+ }
+ return true;
+ }
+
+ /*! updates the interpolation mode for the topology */
+ void setSubdivisionMode (RTCSubdivisionMode mode);
+
+ /*! marks all buffers as modified */
+ void update ();
+
+ /*! verifies index array */
+ bool verify (size_t numVertices);
+
+ /*! initializes the half edge data structure */
+ void initializeHalfEdgeStructures ();
+
+ private:
+
+ /*! recalculates the half edges */
+ void calculateHalfEdges();
+
+ /*! updates half edges when recalculation is not necessary */
+ void updateHalfEdges();
+
+ /*! user input data */
+ public:
+
+ SubdivMesh* mesh;
+
+ /*! indices of the vertices composing each face */
+ BufferView<unsigned int> vertexIndices;
+
+ /*! subdiv interpolation mode */
+ RTCSubdivisionMode subdiv_mode;
+
+ /*! generated data */
+ public:
+
+ /*! returns the start half edge for face f */
+ __forceinline const HalfEdge* getHalfEdge ( const size_t f ) const {
+ return &halfEdges[mesh->faceStartEdge[f]];
+ }
+
+ /*! Half edge structure, generated by initHalfEdgeStructures */
+ mvector<HalfEdge> halfEdges;
+
+ /*! the following data is only required during construction of the
+ * half edge structure and can be cleared for static scenes */
+ private:
+
+ /*! two arrays used to sort the half edges */
+ std::vector<KeyHalfEdge> halfEdges0;
+ std::vector<KeyHalfEdge> halfEdges1;
+ };
+
+ /*! returns the start half edge for topology t and face f */
+ __forceinline const HalfEdge* getHalfEdge ( const size_t t , const size_t f ) const {
+ return topology[t].getHalfEdge(f);
+ }
+
+ /*! buffer containing the number of vertices for each face */
+ BufferView<unsigned int> faceVertices;
+
+ /*! array of topologies */
+ vector<Topology> topology;
+
+ /*! vertex buffer (one buffer for each time step) */
+ vector<BufferView<Vec3fa>> vertices;
+
+ /*! user data buffers */
+ vector<RawBufferView> vertexAttribs;
+
+ /*! edge crease buffer containing edges (pairs of vertices) that carry edge crease weights */
+ BufferView<Edge> edge_creases;
+
+ /*! edge crease weights for each edge of the edge_creases buffer */
+ BufferView<float> edge_crease_weights;
+
+ /*! vertex crease buffer containing all vertices that carry vertex crease weights */
+ BufferView<unsigned int> vertex_creases;
+
+ /*! vertex crease weights for each vertex of the vertex_creases buffer */
+ BufferView<float> vertex_crease_weights;
+
+ /*! subdivision level for each half edge of the vertexIndices buffer */
+ BufferView<float> levels;
+ float tessellationRate; // constant rate that is used when levels is not set
+
+ /*! buffer that marks specific faces as holes */
+ BufferView<unsigned> holes;
+
+ /*! all data in this section is generated by initializeHalfEdgeStructures function */
+ private:
+
+ /*! number of half edges used by faces */
+ size_t numHalfEdges;
+
+ /*! fast lookup table to find the first half edge for some face */
+ mvector<uint32_t> faceStartEdge;
+
+ /*! fast lookup table to find the face for some half edge */
+ mvector<uint32_t> halfEdgeFace;
+
+ /*! set with all holes */
+ parallel_set<uint32_t> holeSet;
+
+ /*! fast lookup table to detect invalid faces */
+ mvector<char> invalid_face;
+
+ /*! test if face i is invalid in timestep j */
+ __forceinline char& invalidFace(size_t i, size_t j = 0) { return invalid_face[i*numTimeSteps+j]; }
+ __forceinline const char& invalidFace(size_t i, size_t j = 0) const { return invalid_face[i*numTimeSteps+j]; }
+
+ /*! interpolation cache */
+ public:
+ static __forceinline size_t numInterpolationSlots4(size_t stride) { return (stride+15)/16; }
+ static __forceinline size_t numInterpolationSlots8(size_t stride) { return (stride+31)/32; }
+ static __forceinline size_t interpolationSlot(size_t prim, size_t slot, size_t stride) {
+ const size_t slots = numInterpolationSlots4(stride);
+ assert(slot < slots);
+ return slots*prim+slot;
+ }
+ std::vector<std::vector<SharedLazyTessellationCache::CacheEntry>> vertex_buffer_tags;
+ std::vector<std::vector<SharedLazyTessellationCache::CacheEntry>> vertex_attrib_buffer_tags;
+ std::vector<Patch3fa::Ref> patch_eval_trees;
+
+ /*! the following data is only required during construction of the
+ * half edge structure and can be cleared for static scenes */
+ private:
+
+ /*! map with all vertex creases */
+ parallel_map<uint32_t,float> vertexCreaseMap;
+
+ /*! map with all edge creases */
+ parallel_map<uint64_t,float> edgeCreaseMap;
+
+ protected:
+
+ /*! counts number of geometry commits */
+ size_t commitCounter;
+ };
+
+ namespace isa
+ {
+ struct SubdivMeshISA : public SubdivMesh
+ {
+ SubdivMeshISA (Device* device)
+ : SubdivMesh(device) {}
+
+ void interpolate(const RTCInterpolateArguments* const args);
+ void interpolateN(const RTCInterpolateNArguments* const args);
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(SubdivMesh*, createSubdivMesh, Device*);
+};
diff --git a/thirdparty/embree/kernels/common/scene_triangle_mesh.cpp b/thirdparty/embree/kernels/common/scene_triangle_mesh.cpp
new file mode 100644
index 0000000000..3bbd7e51ae
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene_triangle_mesh.cpp
@@ -0,0 +1,194 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "scene_triangle_mesh.h"
+#include "scene.h"
+
+namespace embree
+{
+#if defined(EMBREE_LOWEST_ISA)
+
+ TriangleMesh::TriangleMesh (Device* device)
+ : Geometry(device,GTY_TRIANGLE_MESH,0,1)
+ {
+ vertices.resize(numTimeSteps);
+ }
+
+ void TriangleMesh::setMask (unsigned mask)
+ {
+ this->mask = mask;
+ Geometry::update();
+ }
+
+ void TriangleMesh::setNumTimeSteps (unsigned int numTimeSteps)
+ {
+ vertices.resize(numTimeSteps);
+ Geometry::setNumTimeSteps(numTimeSteps);
+ }
+
+ void TriangleMesh::setVertexAttributeCount (unsigned int N)
+ {
+ vertexAttribs.resize(N);
+ Geometry::update();
+ }
+
+ void TriangleMesh::setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num)
+ {
+ /* verify that all accesses are 4 bytes aligned */
+ if (((size_t(buffer->getPtr()) + offset) & 0x3) || (stride & 0x3))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "data must be 4 bytes aligned");
+
+ if (type == RTC_BUFFER_TYPE_VERTEX)
+ {
+ if (format != RTC_FORMAT_FLOAT3)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid vertex buffer format");
+
+ /* if buffer is larger than 16GB the premultiplied index optimization does not work */
+ if (stride*num > 16ll*1024ll*1024ll*1024ll)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "vertex buffer can be at most 16GB large");
+
+ if (slot >= vertices.size())
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid vertex buffer slot");
+
+ vertices[slot].set(buffer, offset, stride, num, format);
+ vertices[slot].checkPadding16();
+ vertices0 = vertices[0];
+ }
+ else if (type == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE)
+ {
+ if (format < RTC_FORMAT_FLOAT || format > RTC_FORMAT_FLOAT16)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid vertex attribute buffer format");
+
+ if (slot >= vertexAttribs.size())
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid vertex attribute buffer slot");
+
+ vertexAttribs[slot].set(buffer, offset, stride, num, format);
+ vertexAttribs[slot].checkPadding16();
+ }
+ else if (type == RTC_BUFFER_TYPE_INDEX)
+ {
+ if (slot != 0)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ if (format != RTC_FORMAT_UINT3)
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid index buffer format");
+
+ triangles.set(buffer, offset, stride, num, format);
+ setNumPrimitives(num);
+ }
+ else
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown buffer type");
+ }
+
+ void* TriangleMesh::getBuffer(RTCBufferType type, unsigned int slot)
+ {
+ if (type == RTC_BUFFER_TYPE_INDEX)
+ {
+ if (slot != 0)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ return triangles.getPtr();
+ }
+ else if (type == RTC_BUFFER_TYPE_VERTEX)
+ {
+ if (slot >= vertices.size())
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ return vertices[slot].getPtr();
+ }
+ else if (type == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE)
+ {
+ if (slot >= vertexAttribs.size())
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ return vertexAttribs[slot].getPtr();
+ }
+ else
+ {
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown buffer type");
+ return nullptr;
+ }
+ }
+
+ void TriangleMesh::updateBuffer(RTCBufferType type, unsigned int slot)
+ {
+ if (type == RTC_BUFFER_TYPE_INDEX)
+ {
+ if (slot != 0)
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ triangles.setModified();
+ }
+ else if (type == RTC_BUFFER_TYPE_VERTEX)
+ {
+ if (slot >= vertices.size())
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ vertices[slot].setModified();
+ }
+ else if (type == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE)
+ {
+ if (slot >= vertexAttribs.size())
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "invalid buffer slot");
+ vertexAttribs[slot].setModified();
+ }
+ else
+ {
+ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown buffer type");
+ }
+
+ Geometry::update();
+ }
+
+ void TriangleMesh::commit()
+ {
+ /* verify that stride of all time steps are identical */
+ for (unsigned int t=0; t<numTimeSteps; t++)
+ if (vertices[t].getStride() != vertices[0].getStride())
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"stride of vertex buffers have to be identical for each time step");
+
+ Geometry::commit();
+ }
+
+ void TriangleMesh::addElementsToCount (GeometryCounts & counts) const
+ {
+ if (numTimeSteps == 1) counts.numTriangles += numPrimitives;
+ else counts.numMBTriangles += numPrimitives;
+ }
+
+ bool TriangleMesh::verify()
+ {
+ /*! verify size of vertex arrays */
+ if (vertices.size() == 0) return false;
+ for (const auto& buffer : vertices)
+ if (buffer.size() != numVertices())
+ return false;
+
+ /*! verify size of user vertex arrays */
+ for (const auto& buffer : vertexAttribs)
+ if (buffer.size() != numVertices())
+ return false;
+
+ /*! verify triangle indices */
+ for (size_t i=0; i<size(); i++) {
+ if (triangles[i].v[0] >= numVertices()) return false;
+ if (triangles[i].v[1] >= numVertices()) return false;
+ if (triangles[i].v[2] >= numVertices()) return false;
+ }
+
+ /*! verify vertices */
+ for (const auto& buffer : vertices)
+ for (size_t i=0; i<buffer.size(); i++)
+ if (!isvalid(buffer[i]))
+ return false;
+
+ return true;
+ }
+
+ void TriangleMesh::interpolate(const RTCInterpolateArguments* const args) {
+ interpolate_impl<4>(args);
+ }
+
+#endif
+
+ namespace isa
+ {
+ TriangleMesh* createTriangleMesh(Device* device) {
+ return new TriangleMeshISA(device);
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/common/scene_triangle_mesh.h b/thirdparty/embree/kernels/common/scene_triangle_mesh.h
new file mode 100644
index 0000000000..ad3f602fde
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene_triangle_mesh.h
@@ -0,0 +1,318 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "geometry.h"
+#include "buffer.h"
+
+namespace embree
+{
+ /*! Triangle Mesh */
+ struct TriangleMesh : public Geometry
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_TRIANGLE_MESH;
+
+ /*! triangle indices */
+ struct Triangle
+ {
+ uint32_t v[3];
+
+ /*! outputs triangle indices */
+ __forceinline friend embree_ostream operator<<(embree_ostream cout, const Triangle& t) {
+ return cout << "Triangle { " << t.v[0] << ", " << t.v[1] << ", " << t.v[2] << " }";
+ }
+ };
+
+ public:
+
+ /*! triangle mesh construction */
+ TriangleMesh (Device* device);
+
+ /* geometry interface */
+ public:
+ void setMask(unsigned mask);
+ void setNumTimeSteps (unsigned int numTimeSteps);
+ void setVertexAttributeCount (unsigned int N);
+ void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
+ void* getBuffer(RTCBufferType type, unsigned int slot);
+ void updateBuffer(RTCBufferType type, unsigned int slot);
+ void commit();
+ bool verify();
+ void interpolate(const RTCInterpolateArguments* const args);
+ void addElementsToCount (GeometryCounts & counts) const;
+
+ template<int N>
+ void interpolate_impl(const RTCInterpolateArguments* const args)
+ {
+ unsigned int primID = args->primID;
+ float u = args->u;
+ float v = args->v;
+ RTCBufferType bufferType = args->bufferType;
+ unsigned int bufferSlot = args->bufferSlot;
+ float* P = args->P;
+ float* dPdu = args->dPdu;
+ float* dPdv = args->dPdv;
+ float* ddPdudu = args->ddPdudu;
+ float* ddPdvdv = args->ddPdvdv;
+ float* ddPdudv = args->ddPdudv;
+ unsigned int valueCount = args->valueCount;
+
+ /* calculate base pointer and stride */
+ assert((bufferType == RTC_BUFFER_TYPE_VERTEX && bufferSlot < numTimeSteps) ||
+ (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE && bufferSlot <= vertexAttribs.size()));
+ const char* src = nullptr;
+ size_t stride = 0;
+ if (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE) {
+ src = vertexAttribs[bufferSlot].getPtr();
+ stride = vertexAttribs[bufferSlot].getStride();
+ } else {
+ src = vertices[bufferSlot].getPtr();
+ stride = vertices[bufferSlot].getStride();
+ }
+
+ for (unsigned int i=0; i<valueCount; i+=N)
+ {
+ size_t ofs = i*sizeof(float);
+ const float w = 1.0f-u-v;
+ const Triangle& tri = triangle(primID);
+ const vbool<N> valid = vint<N>((int)i)+vint<N>(step) < vint<N>(int(valueCount));
+ const vfloat<N> p0 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[0]*stride+ofs]);
+ const vfloat<N> p1 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[1]*stride+ofs]);
+ const vfloat<N> p2 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[2]*stride+ofs]);
+
+ if (P) {
+ mem<vfloat<N>>::storeu(valid,P+i,madd(w,p0,madd(u,p1,v*p2)));
+ }
+ if (dPdu) {
+ assert(dPdu); mem<vfloat<N>>::storeu(valid,dPdu+i,p1-p0);
+ assert(dPdv); mem<vfloat<N>>::storeu(valid,dPdv+i,p2-p0);
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); mem<vfloat<N>>::storeu(valid,ddPdudu+i,vfloat<N>(zero));
+ assert(ddPdvdv); mem<vfloat<N>>::storeu(valid,ddPdvdv+i,vfloat<N>(zero));
+ assert(ddPdudv); mem<vfloat<N>>::storeu(valid,ddPdudv+i,vfloat<N>(zero));
+ }
+ }
+ }
+
+ public:
+
+ /*! returns number of vertices */
+ __forceinline size_t numVertices() const {
+ return vertices[0].size();
+ }
+
+ /*! returns i'th triangle*/
+ __forceinline const Triangle& triangle(size_t i) const {
+ return triangles[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const Vec3fa vertex(size_t i) const {
+ return vertices0[i];
+ }
+
+ /*! returns i'th vertex of the first time step */
+ __forceinline const char* vertexPtr(size_t i) const {
+ return vertices0.getPtr(i);
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const Vec3fa vertex(size_t i, size_t itime) const {
+ return vertices[itime][i];
+ }
+
+ /*! returns i'th vertex of itime'th timestep */
+ __forceinline const char* vertexPtr(size_t i, size_t itime) const {
+ return vertices[itime].getPtr(i);
+ }
+
+ /*! calculates the bounds of the i'th triangle */
+ __forceinline BBox3fa bounds(size_t i) const
+ {
+ const Triangle& tri = triangle(i);
+ const Vec3fa v0 = vertex(tri.v[0]);
+ const Vec3fa v1 = vertex(tri.v[1]);
+ const Vec3fa v2 = vertex(tri.v[2]);
+ return BBox3fa(min(v0,v1,v2),max(v0,v1,v2));
+ }
+
+ /*! calculates the bounds of the i'th triangle at the itime'th timestep */
+ __forceinline BBox3fa bounds(size_t i, size_t itime) const
+ {
+ const Triangle& tri = triangle(i);
+ const Vec3fa v0 = vertex(tri.v[0],itime);
+ const Vec3fa v1 = vertex(tri.v[1],itime);
+ const Vec3fa v2 = vertex(tri.v[2],itime);
+ return BBox3fa(min(v0,v1,v2),max(v0,v1,v2));
+ }
+
+ /*! check if the i'th primitive is valid at the itime'th timestep */
+ __forceinline bool valid(size_t i, size_t itime) const {
+ return valid(i, make_range(itime, itime));
+ }
+
+ /*! check if the i'th primitive is valid between the specified time range */
+ __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
+ {
+ const Triangle& tri = triangle(i);
+ if (unlikely(tri.v[0] >= numVertices())) return false;
+ if (unlikely(tri.v[1] >= numVertices())) return false;
+ if (unlikely(tri.v[2] >= numVertices())) return false;
+
+ for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
+ {
+ if (!isvalid(vertex(tri.v[0],itime))) return false;
+ if (!isvalid(vertex(tri.v[1],itime))) return false;
+ if (!isvalid(vertex(tri.v[2],itime))) return false;
+ }
+
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive at the itimeGlobal'th time segment */
+ __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const {
+ return LBBox3fa(bounds(i,itime+0),bounds(i,itime+1));
+ }
+
+ /*! calculates the build bounds of the i'th primitive, if it's valid */
+ __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
+ {
+ const Triangle& tri = triangle(i);
+ if (unlikely(tri.v[0] >= numVertices())) return false;
+ if (unlikely(tri.v[1] >= numVertices())) return false;
+ if (unlikely(tri.v[2] >= numVertices())) return false;
+
+ for (size_t t=0; t<numTimeSteps; t++)
+ {
+ const Vec3fa v0 = vertex(tri.v[0],t);
+ const Vec3fa v1 = vertex(tri.v[1],t);
+ const Vec3fa v2 = vertex(tri.v[2],t);
+ if (unlikely(!isvalid(v0) || !isvalid(v1) || !isvalid(v2)))
+ return false;
+ }
+
+ if (likely(bbox))
+ *bbox = bounds(i);
+
+ return true;
+ }
+
+ /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
+ __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
+ {
+ const Triangle& tri = triangle(i);
+ if (unlikely(tri.v[0] >= numVertices())) return false;
+ if (unlikely(tri.v[1] >= numVertices())) return false;
+ if (unlikely(tri.v[2] >= numVertices())) return false;
+
+ assert(itime+1 < numTimeSteps);
+ const Vec3fa a0 = vertex(tri.v[0],itime+0); if (unlikely(!isvalid(a0))) return false;
+ const Vec3fa a1 = vertex(tri.v[1],itime+0); if (unlikely(!isvalid(a1))) return false;
+ const Vec3fa a2 = vertex(tri.v[2],itime+0); if (unlikely(!isvalid(a2))) return false;
+ const Vec3fa b0 = vertex(tri.v[0],itime+1); if (unlikely(!isvalid(b0))) return false;
+ const Vec3fa b1 = vertex(tri.v[1],itime+1); if (unlikely(!isvalid(b1))) return false;
+ const Vec3fa b2 = vertex(tri.v[2],itime+1); if (unlikely(!isvalid(b2))) return false;
+
+ /* use bounds of first time step in builder */
+ bbox = BBox3fa(min(a0,a1,a2),max(a0,a1,a2));
+ return true;
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
+ return LBBox3fa([&] (size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
+ }
+
+ /*! calculates the linear bounds of the i'th primitive for the specified time range */
+ __forceinline bool linearBounds(size_t i, const BBox1f& dt, LBBox3fa& bbox) const {
+ if (!valid(i, timeSegmentRange(dt))) return false;
+ bbox = linearBounds(i, dt);
+ return true;
+ }
+
+ /*! get fast access to first vertex buffer */
+ __forceinline float * getCompactVertexArray () const {
+ return (float*) vertices0.getPtr();
+ }
+
+ /* gets version info of topology */
+ unsigned int getTopologyVersion() const {
+ return triangles.modCounter;
+ }
+
+ /* returns true if topology changed */
+ bool topologyChanged(unsigned int otherVersion) const {
+ return triangles.isModified(otherVersion); // || numPrimitivesChanged;
+ }
+
+ /* returns the projected area */
+ __forceinline float projectedPrimitiveArea(const size_t i) const {
+ const Triangle& tri = triangle(i);
+ const Vec3fa v0 = vertex(tri.v[0]);
+ const Vec3fa v1 = vertex(tri.v[1]);
+ const Vec3fa v2 = vertex(tri.v[2]);
+ return areaProjectedTriangle(v0,v1,v2);
+ }
+
+ public:
+ BufferView<Triangle> triangles; //!< array of triangles
+ BufferView<Vec3fa> vertices0; //!< fast access to first vertex buffer
+ vector<BufferView<Vec3fa>> vertices; //!< vertex array for each timestep
+ vector<RawBufferView> vertexAttribs; //!< vertex attributes
+ };
+
+ namespace isa
+ {
+ struct TriangleMeshISA : public TriangleMesh
+ {
+ TriangleMeshISA (Device* device)
+ : TriangleMesh(device) {}
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,&bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,itime,bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!valid(j, timeSegmentRange(t0t1))) continue;
+ const PrimRefMB prim(linearBounds(j,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(j));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(TriangleMesh*, createTriangleMesh, Device*);
+}
diff --git a/thirdparty/embree/kernels/common/scene_user_geometry.h b/thirdparty/embree/kernels/common/scene_user_geometry.h
new file mode 100644
index 0000000000..2867b18b79
--- /dev/null
+++ b/thirdparty/embree/kernels/common/scene_user_geometry.h
@@ -0,0 +1,77 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "accelset.h"
+
+namespace embree
+{
+ /*! User geometry with user defined intersection functions */
+ struct UserGeometry : public AccelSet
+ {
+ /*! type of this geometry */
+ static const Geometry::GTypeMask geom_type = Geometry::MTY_USER_GEOMETRY;
+
+ public:
+ UserGeometry (Device* device, unsigned int items = 0, unsigned int numTimeSteps = 1);
+ virtual void setMask (unsigned mask);
+ virtual void setBoundsFunction (RTCBoundsFunction bounds, void* userPtr);
+ virtual void setIntersectFunctionN (RTCIntersectFunctionN intersect);
+ virtual void setOccludedFunctionN (RTCOccludedFunctionN occluded);
+ virtual void build() {}
+ virtual void addElementsToCount (GeometryCounts & counts) const;
+ };
+
+ namespace isa
+ {
+ struct UserGeometryISA : public UserGeometry
+ {
+ UserGeometryISA (Device* device)
+ : UserGeometry(device) {}
+
+ PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,&bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfo pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ BBox3fa bounds = empty;
+ if (!buildBounds(j,itime,bounds)) continue;
+ const PrimRef prim(bounds,geomID,unsigned(j));
+ pinfo.add_center2(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+
+ PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
+ {
+ PrimInfoMB pinfo(empty);
+ for (size_t j=r.begin(); j<r.end(); j++)
+ {
+ if (!valid(j, timeSegmentRange(t0t1))) continue;
+ const PrimRefMB prim(linearBounds(j,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(j));
+ pinfo.add_primref(prim);
+ prims[k++] = prim;
+ }
+ return pinfo;
+ }
+ };
+ }
+
+ DECLARE_ISA_FUNCTION(UserGeometry*, createUserGeometry, Device*);
+}
diff --git a/thirdparty/embree/kernels/common/stack_item.h b/thirdparty/embree/kernels/common/stack_item.h
new file mode 100644
index 0000000000..c31c64e862
--- /dev/null
+++ b/thirdparty/embree/kernels/common/stack_item.h
@@ -0,0 +1,125 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+namespace embree
+{
+ /*! An item on the stack holds the node ID and distance of that node. */
+ template<typename T>
+ struct __aligned(16) StackItemT
+ {
+ /*! assert that the xchg function works */
+ static_assert(sizeof(T) <= 12, "sizeof(T) <= 12 failed");
+
+ __forceinline StackItemT() {}
+
+ __forceinline StackItemT(T &ptr, unsigned &dist) : ptr(ptr), dist(dist) {}
+
+ /*! use SSE instructions to swap stack items */
+ __forceinline static void xchg(StackItemT& a, StackItemT& b)
+ {
+ const vfloat4 sse_a = vfloat4::load((float*)&a);
+ const vfloat4 sse_b = vfloat4::load((float*)&b);
+ vfloat4::store(&a,sse_b);
+ vfloat4::store(&b,sse_a);
+ }
+
+ /*! Sort 2 stack items. */
+ __forceinline friend void sort(StackItemT& s1, StackItemT& s2) {
+ if (s2.dist < s1.dist) xchg(s2,s1);
+ }
+
+ /*! Sort 3 stack items. */
+ __forceinline friend void sort(StackItemT& s1, StackItemT& s2, StackItemT& s3)
+ {
+ if (s2.dist < s1.dist) xchg(s2,s1);
+ if (s3.dist < s2.dist) xchg(s3,s2);
+ if (s2.dist < s1.dist) xchg(s2,s1);
+ }
+
+ /*! Sort 4 stack items. */
+ __forceinline friend void sort(StackItemT& s1, StackItemT& s2, StackItemT& s3, StackItemT& s4)
+ {
+ if (s2.dist < s1.dist) xchg(s2,s1);
+ if (s4.dist < s3.dist) xchg(s4,s3);
+ if (s3.dist < s1.dist) xchg(s3,s1);
+ if (s4.dist < s2.dist) xchg(s4,s2);
+ if (s3.dist < s2.dist) xchg(s3,s2);
+ }
+
+ /*! use SSE instructions to swap stack items */
+ __forceinline static void cmp_xchg(vint4& a, vint4& b)
+ {
+#if defined(__AVX512VL__)
+ const vboolf4 mask(shuffle<2,2,2,2>(b) < shuffle<2,2,2,2>(a));
+#else
+ const vboolf4 mask0(b < a);
+ const vboolf4 mask(shuffle<2,2,2,2>(mask0));
+#endif
+ const vint4 c = select(mask,b,a);
+ const vint4 d = select(mask,a,b);
+ a = c;
+ b = d;
+ }
+
+ /*! Sort 3 stack items. */
+ __forceinline static void sort3(vint4& s1, vint4& s2, vint4& s3)
+ {
+ cmp_xchg(s2,s1);
+ cmp_xchg(s3,s2);
+ cmp_xchg(s2,s1);
+ }
+
+ /*! Sort 4 stack items. */
+ __forceinline static void sort4(vint4& s1, vint4& s2, vint4& s3, vint4& s4)
+ {
+ cmp_xchg(s2,s1);
+ cmp_xchg(s4,s3);
+ cmp_xchg(s3,s1);
+ cmp_xchg(s4,s2);
+ cmp_xchg(s3,s2);
+ }
+
+
+ /*! Sort N stack items. */
+ __forceinline friend void sort(StackItemT* begin, StackItemT* end)
+ {
+ for (StackItemT* i = begin+1; i != end; ++i)
+ {
+ const vfloat4 item = vfloat4::load((float*)i);
+ const unsigned dist = i->dist;
+ StackItemT* j = i;
+
+ while ((j != begin) && ((j-1)->dist < dist))
+ {
+ vfloat4::store(j, vfloat4::load((float*)(j-1)));
+ --j;
+ }
+
+ vfloat4::store(j, item);
+ }
+ }
+
+ public:
+ T ptr;
+ unsigned dist;
+ };
+
+ /*! An item on the stack holds the node ID and active ray mask. */
+ template<typename T>
+ struct __aligned(8) StackItemMaskT
+ {
+ T ptr;
+ size_t mask;
+ };
+
+ struct __aligned(8) StackItemMaskCoherent
+ {
+ size_t mask;
+ size_t parent;
+ size_t child;
+ };
+}
diff --git a/thirdparty/embree/kernels/common/stat.cpp b/thirdparty/embree/kernels/common/stat.cpp
new file mode 100644
index 0000000000..ebb77cd534
--- /dev/null
+++ b/thirdparty/embree/kernels/common/stat.cpp
@@ -0,0 +1,128 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "stat.h"
+
+namespace embree
+{
+ Stat Stat::instance;
+
+ Stat::Stat () {
+ }
+
+ Stat::~Stat ()
+ {
+#ifdef EMBREE_STAT_COUNTERS
+ Stat::print(std::cout);
+#endif
+ }
+
+ void Stat::print(std::ostream& cout)
+ {
+ Counters& cntrs = instance.cntrs;
+ Counters::Data& data = instance.cntrs.code;
+ //Counters::Data& data = instance.cntrs.active;
+
+ /* print absolute numbers */
+ cout << "--------- ABSOLUTE ---------" << std::endl;
+ cout << " #normal_travs = " << float(data.normal.travs )*1E-6 << "M" << std::endl;
+ cout << " #nodes = " << float(data.normal.trav_nodes )*1E-6 << "M" << std::endl;
+ cout << " #nodes_xfm = " << float(data.normal.trav_xfm_nodes )*1E-6 << "M" << std::endl;
+ cout << " #leaves = " << float(data.normal.trav_leaves )*1E-6 << "M" << std::endl;
+ cout << " #prims = " << float(data.normal.trav_prims )*1E-6 << "M" << std::endl;
+ cout << " #prim_hits = " << float(data.normal.trav_prim_hits )*1E-6 << "M" << std::endl;
+
+ cout << " #stack nodes = " << float(data.normal.trav_stack_nodes )*1E-6 << "M" << std::endl;
+ cout << " #stack pop = " << float(data.normal.trav_stack_pop )*1E-6 << "M" << std::endl;
+
+ size_t normal_box_hits = 0;
+ size_t weighted_box_hits = 0;
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++) {
+ normal_box_hits += data.normal.trav_hit_boxes[i];
+ weighted_box_hits += data.normal.trav_hit_boxes[i]*i;
+ }
+ cout << " #hit_boxes = " << normal_box_hits << " (total) distribution: ";
+ float average = 0.0f;
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++)
+ {
+ float value = 100.0f * data.normal.trav_hit_boxes[i] / normal_box_hits;
+ cout << "[" << i << "] " << value << " ";
+ average += (float)i*data.normal.trav_hit_boxes[i] / normal_box_hits;
+ }
+ cout << " average = " << average << std::endl;
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++) cout << "[" << i << "] " << 100.0f * data.normal.trav_hit_boxes[i]*i / weighted_box_hits << " ";
+ cout << std::endl;
+
+ if (data.shadow.travs) {
+ cout << " #shadow_travs = " << float(data.shadow.travs )*1E-6 << "M" << std::endl;
+ cout << " #nodes = " << float(data.shadow.trav_nodes )*1E-6 << "M" << std::endl;
+ cout << " #nodes_xfm = " << float(data.shadow.trav_xfm_nodes)*1E-6 << "M" << std::endl;
+ cout << " #leaves = " << float(data.shadow.trav_leaves )*1E-6 << "M" << std::endl;
+ cout << " #prims = " << float(data.shadow.trav_prims )*1E-6 << "M" << std::endl;
+ cout << " #prim_hits = " << float(data.shadow.trav_prim_hits)*1E-6 << "M" << std::endl;
+
+ cout << " #stack nodes = " << float(data.shadow.trav_stack_nodes )*1E-6 << "M" << std::endl;
+ cout << " #stack pop = " << float(data.shadow.trav_stack_pop )*1E-6 << "M" << std::endl;
+
+ size_t shadow_box_hits = 0;
+ size_t weighted_shadow_box_hits = 0;
+
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++) {
+ shadow_box_hits += data.shadow.trav_hit_boxes[i];
+ weighted_shadow_box_hits += data.shadow.trav_hit_boxes[i]*i;
+ }
+ cout << " #hit_boxes = ";
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++) cout << "[" << i << "] " << 100.0f * data.shadow.trav_hit_boxes[i] / shadow_box_hits << " ";
+ cout << std::endl;
+ for (size_t i=0;i<SIZE_HISTOGRAM;i++) cout << "[" << i << "] " << 100.0f * data.shadow.trav_hit_boxes[i]*i / weighted_shadow_box_hits << " ";
+ cout << std::endl;
+ }
+ cout << std::endl;
+
+ /* print per traversal numbers */
+ cout << "--------- PER TRAVERSAL ---------" << std::endl;
+ float active_normal_travs = float(cntrs.active.normal.travs )/float(cntrs.all.normal.travs );
+ float active_normal_trav_nodes = float(cntrs.active.normal.trav_nodes )/float(cntrs.all.normal.trav_nodes );
+ float active_normal_trav_xfm_nodes = float(cntrs.active.normal.trav_xfm_nodes )/float(cntrs.all.normal.trav_xfm_nodes );
+ float active_normal_trav_leaves = float(cntrs.active.normal.trav_leaves)/float(cntrs.all.normal.trav_leaves);
+ float active_normal_trav_prims = float(cntrs.active.normal.trav_prims )/float(cntrs.all.normal.trav_prims );
+ float active_normal_trav_prim_hits = float(cntrs.active.normal.trav_prim_hits )/float(cntrs.all.normal.trav_prim_hits );
+ float active_normal_trav_stack_pop = float(cntrs.active.normal.trav_stack_pop )/float(cntrs.all.normal.trav_stack_pop );
+
+ cout << " #normal_travs = " << float(cntrs.code.normal.travs )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_travs << "% active" << std::endl;
+ cout << " #nodes = " << float(cntrs.code.normal.trav_nodes )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_nodes << "% active" << std::endl;
+ cout << " #node_xfm = " << float(cntrs.code.normal.trav_xfm_nodes )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_xfm_nodes << "% active" << std::endl;
+ cout << " #leaves = " << float(cntrs.code.normal.trav_leaves)/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_leaves << "% active" << std::endl;
+ cout << " #prims = " << float(cntrs.code.normal.trav_prims )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_prims << "% active" << std::endl;
+ cout << " #prim_hits = " << float(cntrs.code.normal.trav_prim_hits )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_prim_hits << "% active" << std::endl;
+ cout << " #stack_pop = " << float(cntrs.code.normal.trav_stack_pop )/float(cntrs.code.normal.travs) << ", " << 100.0f*active_normal_trav_stack_pop << "% active" << std::endl;
+
+ if (cntrs.all.shadow.travs) {
+ float active_shadow_travs = float(cntrs.active.shadow.travs )/float(cntrs.all.shadow.travs );
+ float active_shadow_trav_nodes = float(cntrs.active.shadow.trav_nodes )/float(cntrs.all.shadow.trav_nodes );
+ float active_shadow_trav_xfm_nodes = float(cntrs.active.shadow.trav_xfm_nodes )/float(cntrs.all.shadow.trav_xfm_nodes );
+ float active_shadow_trav_leaves = float(cntrs.active.shadow.trav_leaves)/float(cntrs.all.shadow.trav_leaves);
+ float active_shadow_trav_prims = float(cntrs.active.shadow.trav_prims )/float(cntrs.all.shadow.trav_prims );
+ float active_shadow_trav_prim_hits = float(cntrs.active.shadow.trav_prim_hits )/float(cntrs.all.shadow.trav_prim_hits );
+
+ cout << " #shadow_travs = " << float(cntrs.code.shadow.travs )/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_travs << "% active" << std::endl;
+ cout << " #nodes = " << float(cntrs.code.shadow.trav_nodes )/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_trav_nodes << "% active" << std::endl;
+ cout << " #nodes_xfm = " << float(cntrs.code.shadow.trav_xfm_nodes )/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_trav_xfm_nodes << "% active" << std::endl;
+ cout << " #leaves = " << float(cntrs.code.shadow.trav_leaves)/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_trav_leaves << "% active" << std::endl;
+ cout << " #prims = " << float(cntrs.code.shadow.trav_prims )/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_trav_prims << "% active" << std::endl;
+ cout << " #prim_hits = " << float(cntrs.code.shadow.trav_prim_hits )/float(cntrs.code.shadow.travs) << ", " << 100.0f*active_shadow_trav_prim_hits << "% active" << std::endl;
+
+ }
+ cout << std::endl;
+
+ /* print user counters for performance tuning */
+ cout << "--------- USER ---------" << std::endl;
+ for (size_t i=0; i<10; i++)
+ cout << "#user" << i << " = " << float(cntrs.user[i])/float(cntrs.all.normal.travs+cntrs.all.shadow.travs) << " per traversal" << std::endl;
+
+ cout << "#user5/user3 " << 100.0f*float(cntrs.user[5])/float(cntrs.user[3]) << "%" << std::endl;
+ cout << "#user6/user3 " << 100.0f*float(cntrs.user[6])/float(cntrs.user[3]) << "%" << std::endl;
+ cout << "#user7/user3 " << 100.0f*float(cntrs.user[7])/float(cntrs.user[3]) << "%" << std::endl;
+ cout << std::endl;
+ }
+}
diff --git a/thirdparty/embree/kernels/common/stat.h b/thirdparty/embree/kernels/common/stat.h
new file mode 100644
index 0000000000..02fc07e67f
--- /dev/null
+++ b/thirdparty/embree/kernels/common/stat.h
@@ -0,0 +1,116 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+/* Macros to gather statistics */
+#ifdef EMBREE_STAT_COUNTERS
+# define STAT(x) x
+# define STAT3(s,x,y,z) \
+ STAT(Stat::get().code .s+=x); \
+ STAT(Stat::get().active.s+=y); \
+ STAT(Stat::get().all .s+=z);
+# define STAT_USER(i,x) Stat::get().user[i]+=x;
+#else
+# define STAT(x)
+# define STAT3(s,x,y,z)
+# define STAT_USER(i,x)
+#endif
+
+namespace embree
+{
+ /*! Gathers ray tracing statistics. We count 1) how often a code
+ * location is reached, 2) how many SIMD lanes are active, 3) how
+ * many SIMD lanes reach the code location */
+ class Stat
+ {
+ public:
+
+ static const size_t SIZE_HISTOGRAM = 64+1;
+
+ /*! constructs stat counter class */
+ Stat ();
+
+ /*! destructs stat counter class */
+ ~Stat ();
+
+ class Counters
+ {
+ public:
+ Counters () {
+ clear();
+ }
+
+ void clear()
+ {
+ all.clear();
+ active.clear();
+ code.clear();
+ for (auto& u : user) u.store(0);
+ }
+
+ public:
+
+ /* per packet and per ray stastics */
+ struct Data
+ {
+ void clear () {
+ normal.clear();
+ shadow.clear();
+ point_query.clear();
+ }
+
+ /* normal and shadow ray statistics */
+ struct
+ {
+ void clear()
+ {
+ travs.store(0);
+ trav_nodes.store(0);
+ trav_leaves.store(0);
+ trav_prims.store(0);
+ trav_prim_hits.store(0);
+ for (auto& v : trav_hit_boxes) v.store(0);
+ trav_stack_pop.store(0);
+ trav_stack_nodes.store(0);
+ trav_xfm_nodes.store(0);
+ }
+
+ public:
+ std::atomic<size_t> travs;
+ std::atomic<size_t> trav_nodes;
+ std::atomic<size_t> trav_leaves;
+ std::atomic<size_t> trav_prims;
+ std::atomic<size_t> trav_prim_hits;
+ std::atomic<size_t> trav_hit_boxes[SIZE_HISTOGRAM+1];
+ std::atomic<size_t> trav_stack_pop;
+ std::atomic<size_t> trav_stack_nodes;
+ std::atomic<size_t> trav_xfm_nodes;
+
+ } normal, shadow, point_query;
+ } all, active, code;
+
+ std::atomic<size_t> user[10];
+ };
+
+ public:
+
+ static __forceinline Counters& get() {
+ return instance.cntrs;
+ }
+
+ static void clear() {
+ instance.cntrs.clear();
+ }
+
+ static void print(embree_ostream cout);
+
+ private:
+ Counters cntrs;
+
+ private:
+ static Stat instance;
+ };
+}
diff --git a/thirdparty/embree/kernels/common/state.cpp b/thirdparty/embree/kernels/common/state.cpp
new file mode 100644
index 0000000000..01c862da0c
--- /dev/null
+++ b/thirdparty/embree/kernels/common/state.cpp
@@ -0,0 +1,519 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "state.h"
+#include "../../common/lexers/streamfilters.h"
+
+namespace embree
+{
+ MutexSys g_printMutex;
+
+ State::ErrorHandler State::g_errorHandler;
+
+ State::ErrorHandler::ErrorHandler()
+ : thread_error(createTls()) {}
+
+ State::ErrorHandler::~ErrorHandler()
+ {
+ Lock<MutexSys> lock(errors_mutex);
+ for (size_t i=0; i<thread_errors.size(); i++)
+ delete thread_errors[i];
+ destroyTls(thread_error);
+ thread_errors.clear();
+ }
+
+ RTCError* State::ErrorHandler::error()
+ {
+ RTCError* stored_error = (RTCError*) getTls(thread_error);
+ if (stored_error) return stored_error;
+
+ Lock<MutexSys> lock(errors_mutex);
+ stored_error = new RTCError(RTC_ERROR_NONE);
+ thread_errors.push_back(stored_error);
+ setTls(thread_error,stored_error);
+ return stored_error;
+ }
+
+ State::State ()
+ : enabled_cpu_features(getCPUFeatures()),
+ enabled_builder_cpu_features(enabled_cpu_features),
+ frequency_level(FREQUENCY_SIMD256)
+ {
+ tri_accel = "default";
+ tri_builder = "default";
+ tri_traverser = "default";
+
+ tri_accel_mb = "default";
+ tri_builder_mb = "default";
+ tri_traverser_mb = "default";
+
+ quad_accel = "default";
+ quad_builder = "default";
+ quad_traverser = "default";
+
+ quad_accel_mb = "default";
+ quad_builder_mb = "default";
+ quad_traverser_mb = "default";
+
+ line_accel = "default";
+ line_builder = "default";
+ line_traverser = "default";
+
+ line_accel_mb = "default";
+ line_builder_mb = "default";
+ line_traverser_mb = "default";
+
+ hair_accel = "default";
+ hair_builder = "default";
+ hair_traverser = "default";
+
+ hair_accel_mb = "default";
+ hair_builder_mb = "default";
+ hair_traverser_mb = "default";
+
+ object_accel = "default";
+ object_builder = "default";
+ object_accel_min_leaf_size = 1;
+ object_accel_max_leaf_size = 1;
+
+ object_accel_mb = "default";
+ object_builder_mb = "default";
+ object_accel_mb_min_leaf_size = 1;
+ object_accel_mb_max_leaf_size = 1;
+
+ max_spatial_split_replications = 1.2f;
+ useSpatialPreSplits = false;
+
+ tessellation_cache_size = 128*1024*1024;
+
+ subdiv_accel = "default";
+ subdiv_accel_mb = "default";
+
+ grid_accel = "default";
+ grid_builder = "default";
+ grid_accel_mb = "default";
+ grid_builder_mb = "default";
+
+ instancing_open_min = 0;
+ instancing_block_size = 0;
+ instancing_open_factor = 8.0f;
+ instancing_open_max_depth = 32;
+ instancing_open_max = 50000000;
+
+ float_exceptions = false;
+ quality_flags = -1;
+ scene_flags = -1;
+ verbose = 0;
+ benchmark = 0;
+
+ numThreads = 0;
+ numUserThreads = 0;
+
+#if TASKING_INTERNAL
+ set_affinity = true;
+#else
+ set_affinity = false;
+#endif
+
+ start_threads = false;
+ enable_selockmemoryprivilege = false;
+#if defined(__LINUX__)
+ hugepages = true;
+#else
+ hugepages = false;
+#endif
+ hugepages_success = true;
+
+ alloc_main_block_size = 0;
+ alloc_num_main_slots = 0;
+ alloc_thread_block_size = 0;
+ alloc_single_thread_alloc = -1;
+
+ error_function = nullptr;
+ error_function_userptr = nullptr;
+
+ memory_monitor_function = nullptr;
+ memory_monitor_userptr = nullptr;
+ }
+
+ State::~State() {
+ }
+
+ bool State::hasISA(const int isa) {
+ return (enabled_cpu_features & isa) == isa;
+ }
+
+ bool State::checkISASupport() {
+ return (getCPUFeatures() & enabled_cpu_features) == enabled_cpu_features;
+ }
+
+ void State::verify()
+ {
+ /* verify that calculations stay in range */
+ assert(rcp(min_rcp_input)*FLT_LARGE+FLT_LARGE < 0.01f*FLT_MAX);
+
+ /* here we verify that CPP files compiled for a specific ISA only
+ * call that same or lower ISA version of non-inlined class member
+ * functions */
+#if defined(DEBUG)
+#if defined(EMBREE_TARGET_SSE2)
+ assert(sse2::getISA() <= SSE2);
+#endif
+#if defined(EMBREE_TARGET_SSE42)
+ assert(sse42::getISA() <= SSE42);
+#endif
+#if defined(EMBREE_TARGET_AVX)
+ assert(avx::getISA() <= AVX);
+#endif
+#if defined(EMBREE_TARGET_AVX2)
+ assert(avx2::getISA() <= AVX2);
+#endif
+#if defined (EMBREE_TARGET_AVX512)
+ assert(avx512::getISA() <= AVX512);
+#endif
+#endif
+ }
+
+ const char* symbols[3] = { "=", ",", "|" };
+
+ bool State::parseFile(const FileName& fileName)
+ {
+ FILE* f = fopen(fileName.c_str(),"r");
+ if (!f) return false;
+ Ref<Stream<int> > file = new FileStream(f,fileName);
+
+ std::vector<std::string> syms;
+ for (size_t i=0; i<sizeof(symbols)/sizeof(void*); i++)
+ syms.push_back(symbols[i]);
+
+ Ref<TokenStream> cin = new TokenStream(new LineCommentFilter(file,"#"),
+ TokenStream::alpha+TokenStream::ALPHA+TokenStream::numbers+"_.",
+ TokenStream::separators,syms);
+ parse(cin);
+ return true;
+ }
+
+ void State::parseString(const char* cfg)
+ {
+ if (cfg == nullptr) return;
+
+ std::vector<std::string> syms;
+ for (size_t i=0; i<sizeof(symbols)/sizeof(void*); i++)
+ syms.push_back(symbols[i]);
+
+ Ref<TokenStream> cin = new TokenStream(new StrStream(cfg),
+ TokenStream::alpha+TokenStream::ALPHA+TokenStream::numbers+"_.",
+ TokenStream::separators,syms);
+ parse(cin);
+ }
+
+ int string_to_cpufeatures(const std::string& isa)
+ {
+ if (isa == "sse" ) return SSE;
+ else if (isa == "sse2") return SSE2;
+ else if (isa == "sse3") return SSE3;
+ else if (isa == "ssse3") return SSSE3;
+ else if (isa == "sse41") return SSE41;
+ else if (isa == "sse4.1") return SSE41;
+ else if (isa == "sse42") return SSE42;
+ else if (isa == "sse4.2") return SSE42;
+ else if (isa == "avx") return AVX;
+ else if (isa == "avxi") return AVXI;
+ else if (isa == "avx2") return AVX2;
+ else if (isa == "avx512") return AVX512;
+ else return SSE2;
+ }
+
+ void State::parse(Ref<TokenStream> cin)
+ {
+ /* parse until end of stream */
+ while (cin->peek() != Token::Eof())
+ {
+ const Token tok = cin->get();
+
+ if (tok == Token::Id("threads") && cin->trySymbol("="))
+ numThreads = cin->get().Int();
+
+ else if (tok == Token::Id("user_threads")&& cin->trySymbol("="))
+ numUserThreads = cin->get().Int();
+
+ else if (tok == Token::Id("set_affinity")&& cin->trySymbol("="))
+ set_affinity = cin->get().Int();
+
+ else if (tok == Token::Id("affinity")&& cin->trySymbol("="))
+ set_affinity = cin->get().Int();
+
+ else if (tok == Token::Id("start_threads")&& cin->trySymbol("="))
+ start_threads = cin->get().Int();
+
+ else if (tok == Token::Id("isa") && cin->trySymbol("=")) {
+ std::string isa_str = toLowerCase(cin->get().Identifier());
+ enabled_cpu_features = string_to_cpufeatures(isa_str);
+ enabled_builder_cpu_features = enabled_cpu_features;
+ }
+
+ else if (tok == Token::Id("max_isa") && cin->trySymbol("=")) {
+ std::string isa_str = toLowerCase(cin->get().Identifier());
+ enabled_cpu_features &= string_to_cpufeatures(isa_str);
+ enabled_builder_cpu_features &= enabled_cpu_features;
+ }
+
+ else if (tok == Token::Id("max_builder_isa") && cin->trySymbol("=")) {
+ std::string isa_str = toLowerCase(cin->get().Identifier());
+ enabled_builder_cpu_features &= string_to_cpufeatures(isa_str);
+ }
+
+ else if (tok == Token::Id("frequency_level") && cin->trySymbol("=")) {
+ std::string freq = cin->get().Identifier();
+ if (freq == "simd128") frequency_level = FREQUENCY_SIMD128;
+ else if (freq == "simd256") frequency_level = FREQUENCY_SIMD256;
+ else if (freq == "simd512") frequency_level = FREQUENCY_SIMD512;
+ }
+
+ else if (tok == Token::Id("enable_selockmemoryprivilege") && cin->trySymbol("=")) {
+ enable_selockmemoryprivilege = cin->get().Int();
+ }
+ else if (tok == Token::Id("hugepages") && cin->trySymbol("=")) {
+ hugepages = cin->get().Int();
+ }
+
+ else if (tok == Token::Id("float_exceptions") && cin->trySymbol("="))
+ float_exceptions = cin->get().Int();
+
+ else if ((tok == Token::Id("tri_accel") || tok == Token::Id("accel")) && cin->trySymbol("="))
+ tri_accel = cin->get().Identifier();
+ else if ((tok == Token::Id("tri_builder") || tok == Token::Id("builder")) && cin->trySymbol("="))
+ tri_builder = cin->get().Identifier();
+ else if ((tok == Token::Id("tri_traverser") || tok == Token::Id("traverser")) && cin->trySymbol("="))
+ tri_traverser = cin->get().Identifier();
+
+ else if ((tok == Token::Id("tri_accel_mb") || tok == Token::Id("accel_mb")) && cin->trySymbol("="))
+ tri_accel_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("tri_builder_mb") || tok == Token::Id("builder_mb")) && cin->trySymbol("="))
+ tri_builder_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("tri_traverser_mb") || tok == Token::Id("traverser_mb")) && cin->trySymbol("="))
+ tri_traverser_mb = cin->get().Identifier();
+
+ else if ((tok == Token::Id("quad_accel")) && cin->trySymbol("="))
+ quad_accel = cin->get().Identifier();
+ else if ((tok == Token::Id("quad_builder")) && cin->trySymbol("="))
+ quad_builder = cin->get().Identifier();
+ else if ((tok == Token::Id("quad_traverser")) && cin->trySymbol("="))
+ quad_traverser = cin->get().Identifier();
+
+ else if ((tok == Token::Id("quad_accel_mb")) && cin->trySymbol("="))
+ quad_accel_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("quad_builder_mb")) && cin->trySymbol("="))
+ quad_builder_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("quad_traverser_mb")) && cin->trySymbol("="))
+ quad_traverser_mb = cin->get().Identifier();
+
+ else if ((tok == Token::Id("line_accel")) && cin->trySymbol("="))
+ line_accel = cin->get().Identifier();
+ else if ((tok == Token::Id("line_builder")) && cin->trySymbol("="))
+ line_builder = cin->get().Identifier();
+ else if ((tok == Token::Id("line_traverser")) && cin->trySymbol("="))
+ line_traverser = cin->get().Identifier();
+
+ else if ((tok == Token::Id("line_accel_mb")) && cin->trySymbol("="))
+ line_accel_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("line_builder_mb")) && cin->trySymbol("="))
+ line_builder_mb = cin->get().Identifier();
+ else if ((tok == Token::Id("line_traverser_mb")) && cin->trySymbol("="))
+ line_traverser_mb = cin->get().Identifier();
+
+ else if (tok == Token::Id("hair_accel") && cin->trySymbol("="))
+ hair_accel = cin->get().Identifier();
+ else if (tok == Token::Id("hair_builder") && cin->trySymbol("="))
+ hair_builder = cin->get().Identifier();
+ else if (tok == Token::Id("hair_traverser") && cin->trySymbol("="))
+ hair_traverser = cin->get().Identifier();
+
+ else if (tok == Token::Id("hair_accel_mb") && cin->trySymbol("="))
+ hair_accel_mb = cin->get().Identifier();
+ else if (tok == Token::Id("hair_builder_mb") && cin->trySymbol("="))
+ hair_builder_mb = cin->get().Identifier();
+ else if (tok == Token::Id("hair_traverser_mb") && cin->trySymbol("="))
+ hair_traverser_mb = cin->get().Identifier();
+
+ else if (tok == Token::Id("object_accel") && cin->trySymbol("="))
+ object_accel = cin->get().Identifier();
+ else if (tok == Token::Id("object_builder") && cin->trySymbol("="))
+ object_builder = cin->get().Identifier();
+ else if (tok == Token::Id("object_accel_min_leaf_size") && cin->trySymbol("="))
+ object_accel_min_leaf_size = cin->get().Int();
+ else if (tok == Token::Id("object_accel_max_leaf_size") && cin->trySymbol("="))
+ object_accel_max_leaf_size = cin->get().Int();
+
+ else if (tok == Token::Id("object_accel_mb") && cin->trySymbol("="))
+ object_accel_mb = cin->get().Identifier();
+ else if (tok == Token::Id("object_builder_mb") && cin->trySymbol("="))
+ object_builder_mb = cin->get().Identifier();
+ else if (tok == Token::Id("object_accel_mb_min_leaf_size") && cin->trySymbol("="))
+ object_accel_mb_min_leaf_size = cin->get().Int();
+ else if (tok == Token::Id("object_accel_mb_max_leaf_size") && cin->trySymbol("="))
+ object_accel_mb_max_leaf_size = cin->get().Int();
+
+ else if (tok == Token::Id("instancing_open_min") && cin->trySymbol("="))
+ instancing_open_min = cin->get().Int();
+ else if (tok == Token::Id("instancing_block_size") && cin->trySymbol("=")) {
+ instancing_block_size = cin->get().Int();
+ instancing_open_factor = 0.0f;
+ }
+ else if (tok == Token::Id("instancing_open_max_depth") && cin->trySymbol("="))
+ instancing_open_max_depth = cin->get().Int();
+ else if (tok == Token::Id("instancing_open_factor") && cin->trySymbol("=")) {
+ instancing_block_size = 0;
+ instancing_open_factor = cin->get().Float();
+ }
+ else if (tok == Token::Id("instancing_open_max") && cin->trySymbol("="))
+ instancing_open_max = cin->get().Int();
+
+ else if (tok == Token::Id("subdiv_accel") && cin->trySymbol("="))
+ subdiv_accel = cin->get().Identifier();
+ else if (tok == Token::Id("subdiv_accel_mb") && cin->trySymbol("="))
+ subdiv_accel_mb = cin->get().Identifier();
+
+ else if (tok == Token::Id("grid_accel") && cin->trySymbol("="))
+ grid_accel = cin->get().Identifier();
+ else if (tok == Token::Id("grid_accel_mb") && cin->trySymbol("="))
+ grid_accel_mb = cin->get().Identifier();
+
+ else if (tok == Token::Id("verbose") && cin->trySymbol("="))
+ verbose = cin->get().Int();
+ else if (tok == Token::Id("benchmark") && cin->trySymbol("="))
+ benchmark = cin->get().Int();
+
+ else if (tok == Token::Id("quality")) {
+ if (cin->trySymbol("=")) {
+ Token flag = cin->get();
+ if (flag == Token::Id("low")) quality_flags = RTC_BUILD_QUALITY_LOW;
+ else if (flag == Token::Id("medium")) quality_flags = RTC_BUILD_QUALITY_MEDIUM;
+ else if (flag == Token::Id("high")) quality_flags = RTC_BUILD_QUALITY_HIGH;
+ }
+ }
+
+ else if (tok == Token::Id("scene_flags")) {
+ scene_flags = 0;
+ if (cin->trySymbol("=")) {
+ do {
+ Token flag = cin->get();
+ if (flag == Token::Id("dynamic") ) scene_flags |= RTC_SCENE_FLAG_DYNAMIC;
+ else if (flag == Token::Id("compact")) scene_flags |= RTC_SCENE_FLAG_COMPACT;
+ else if (flag == Token::Id("robust")) scene_flags |= RTC_SCENE_FLAG_ROBUST;
+ } while (cin->trySymbol("|"));
+ }
+ }
+
+ else if (tok == Token::Id("max_spatial_split_replications") && cin->trySymbol("="))
+ max_spatial_split_replications = cin->get().Float();
+
+ else if (tok == Token::Id("presplits") && cin->trySymbol("="))
+ useSpatialPreSplits = cin->get().Int() != 0 ? true : false;
+
+ else if (tok == Token::Id("tessellation_cache_size") && cin->trySymbol("="))
+ tessellation_cache_size = size_t(cin->get().Float()*1024.0f*1024.0f);
+ else if (tok == Token::Id("cache_size") && cin->trySymbol("="))
+ tessellation_cache_size = size_t(cin->get().Float()*1024.0f*1024.0f);
+
+ else if (tok == Token::Id("alloc_main_block_size") && cin->trySymbol("="))
+ alloc_main_block_size = cin->get().Int();
+ else if (tok == Token::Id("alloc_num_main_slots") && cin->trySymbol("="))
+ alloc_num_main_slots = cin->get().Int();
+ else if (tok == Token::Id("alloc_thread_block_size") && cin->trySymbol("="))
+ alloc_thread_block_size = cin->get().Int();
+ else if (tok == Token::Id("alloc_single_thread_alloc") && cin->trySymbol("="))
+ alloc_single_thread_alloc = cin->get().Int();
+
+ cin->trySymbol(","); // optional , separator
+ }
+ }
+
+ bool State::verbosity(size_t N) {
+ return N <= verbose;
+ }
+
+ void State::print()
+ {
+ std::cout << "general:" << std::endl;
+ std::cout << " build threads = " << numThreads << std::endl;
+ std::cout << " build user threads = " << numUserThreads << std::endl;
+ std::cout << " start_threads = " << start_threads << std::endl;
+ std::cout << " affinity = " << set_affinity << std::endl;
+ std::cout << " frequency_level = ";
+ switch (frequency_level) {
+ case FREQUENCY_SIMD128: std::cout << "simd128" << std::endl; break;
+ case FREQUENCY_SIMD256: std::cout << "simd256" << std::endl; break;
+ case FREQUENCY_SIMD512: std::cout << "simd512" << std::endl; break;
+ default: std::cout << "error" << std::endl; break;
+ }
+
+ std::cout << " hugepages = ";
+ if (!hugepages) std::cout << "disabled" << std::endl;
+ else if (hugepages_success) std::cout << "enabled" << std::endl;
+ else std::cout << "failed" << std::endl;
+
+ std::cout << " verbosity = " << verbose << std::endl;
+ std::cout << " cache_size = " << float(tessellation_cache_size)*1E-6 << " MB" << std::endl;
+ std::cout << " max_spatial_split_replications = " << max_spatial_split_replications << std::endl;
+
+ std::cout << "triangles:" << std::endl;
+ std::cout << " accel = " << tri_accel << std::endl;
+ std::cout << " builder = " << tri_builder << std::endl;
+ std::cout << " traverser = " << tri_traverser << std::endl;
+
+ std::cout << "motion blur triangles:" << std::endl;
+ std::cout << " accel = " << tri_accel_mb << std::endl;
+ std::cout << " builder = " << tri_builder_mb << std::endl;
+ std::cout << " traverser = " << tri_traverser_mb << std::endl;
+
+ std::cout << "quads:" << std::endl;
+ std::cout << " accel = " << quad_accel << std::endl;
+ std::cout << " builder = " << quad_builder << std::endl;
+ std::cout << " traverser = " << quad_traverser << std::endl;
+
+ std::cout << "motion blur quads:" << std::endl;
+ std::cout << " accel = " << quad_accel_mb << std::endl;
+ std::cout << " builder = " << quad_builder_mb << std::endl;
+ std::cout << " traverser = " << quad_traverser_mb << std::endl;
+
+ std::cout << "line segments:" << std::endl;
+ std::cout << " accel = " << line_accel << std::endl;
+ std::cout << " builder = " << line_builder << std::endl;
+ std::cout << " traverser = " << line_traverser << std::endl;
+
+ std::cout << "motion blur line segments:" << std::endl;
+ std::cout << " accel = " << line_accel_mb << std::endl;
+ std::cout << " builder = " << line_builder_mb << std::endl;
+ std::cout << " traverser = " << line_traverser_mb << std::endl;
+
+ std::cout << "hair:" << std::endl;
+ std::cout << " accel = " << hair_accel << std::endl;
+ std::cout << " builder = " << hair_builder << std::endl;
+ std::cout << " traverser = " << hair_traverser << std::endl;
+
+ std::cout << "motion blur hair:" << std::endl;
+ std::cout << " accel = " << hair_accel_mb << std::endl;
+ std::cout << " builder = " << hair_builder_mb << std::endl;
+ std::cout << " traverser = " << hair_traverser_mb << std::endl;
+
+ std::cout << "subdivision surfaces:" << std::endl;
+ std::cout << " accel = " << subdiv_accel << std::endl;
+
+ std::cout << "grids:" << std::endl;
+ std::cout << " accel = " << grid_accel << std::endl;
+ std::cout << " builder = " << grid_builder << std::endl;
+
+ std::cout << "motion blur grids:" << std::endl;
+ std::cout << " accel = " << grid_accel_mb << std::endl;
+ std::cout << " builder = " << grid_builder_mb << std::endl;
+
+ std::cout << "object_accel:" << std::endl;
+ std::cout << " min_leaf_size = " << object_accel_min_leaf_size << std::endl;
+ std::cout << " max_leaf_size = " << object_accel_max_leaf_size << std::endl;
+
+ std::cout << "object_accel_mb:" << std::endl;
+ std::cout << " min_leaf_size = " << object_accel_mb_min_leaf_size << std::endl;
+ std::cout << " max_leaf_size = " << object_accel_mb_max_leaf_size << std::endl;
+ }
+}
diff --git a/thirdparty/embree/kernels/common/state.h b/thirdparty/embree/kernels/common/state.h
new file mode 100644
index 0000000000..33bcc843b2
--- /dev/null
+++ b/thirdparty/embree/kernels/common/state.h
@@ -0,0 +1,196 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "default.h"
+
+namespace embree
+{
+ /* mutex to make printing to cout thread safe */
+ extern MutexSys g_printMutex;
+
+ struct State : public RefCount
+ {
+ public:
+ /*! state construction */
+ State ();
+
+ /*! state destruction */
+ ~State();
+
+ /*! verifies that state is correct */
+ void verify();
+
+ /*! parses state from a configuration file */
+ bool parseFile(const FileName& fileName);
+
+ /*! parses the state from a string */
+ void parseString(const char* cfg);
+
+ /*! parses the state from a stream */
+ void parse(Ref<TokenStream> cin);
+
+ /*! prints the state */
+ void print();
+
+ /*! checks if verbosity level is at least N */
+ bool verbosity(size_t N);
+
+ /*! checks if some particular ISA is enabled */
+ bool hasISA(const int isa);
+
+ /*! check whether selected ISA is supported by the HW */
+ bool checkISASupport();
+
+ public:
+ std::string tri_accel; //!< acceleration structure to use for triangles
+ std::string tri_builder; //!< builder to use for triangles
+ std::string tri_traverser; //!< traverser to use for triangles
+
+ public:
+ std::string tri_accel_mb; //!< acceleration structure to use for motion blur triangles
+ std::string tri_builder_mb; //!< builder to use for motion blur triangles
+ std::string tri_traverser_mb; //!< traverser to use for triangles
+
+ public:
+ std::string quad_accel; //!< acceleration structure to use for quads
+ std::string quad_builder; //!< builder to use for quads
+ std::string quad_traverser; //!< traverser to use for quads
+
+ public:
+ std::string quad_accel_mb; //!< acceleration structure to use for motion blur quads
+ std::string quad_builder_mb; //!< builder to use for motion blur quads
+ std::string quad_traverser_mb; //!< traverser to use for motion blur quads
+
+ public:
+ std::string line_accel; //!< acceleration structure to use for line segments
+ std::string line_builder; //!< builder to use for line segments
+ std::string line_traverser; //!< traverser to use for line segments
+
+ public:
+ std::string line_accel_mb; //!< acceleration structure to use for motion blur line segments
+ std::string line_builder_mb; //!< builder to use for motion blur line segments
+ std::string line_traverser_mb; //!< traverser to use for motion blur line segments
+
+ public:
+ std::string hair_accel; //!< hair acceleration structure to use
+ std::string hair_builder; //!< builder to use for hair
+ std::string hair_traverser; //!< traverser to use for hair
+
+ public:
+ std::string hair_accel_mb; //!< acceleration structure to use for motion blur hair
+ std::string hair_builder_mb; //!< builder to use for motion blur hair
+ std::string hair_traverser_mb; //!< traverser to use for motion blur hair
+
+ public:
+ std::string object_accel; //!< acceleration structure for user geometries
+ std::string object_builder; //!< builder for user geometries
+ int object_accel_min_leaf_size; //!< minimum leaf size for object acceleration structure
+ int object_accel_max_leaf_size; //!< maximum leaf size for object acceleration structure
+
+ public:
+ std::string object_accel_mb; //!< acceleration structure for user geometries
+ std::string object_builder_mb; //!< builder for user geometries
+ int object_accel_mb_min_leaf_size; //!< minimum leaf size for mblur object acceleration structure
+ int object_accel_mb_max_leaf_size; //!< maximum leaf size for mblur object acceleration structure
+
+ public:
+ std::string subdiv_accel; //!< acceleration structure to use for subdivision surfaces
+ std::string subdiv_accel_mb; //!< acceleration structure to use for subdivision surfaces
+
+ public:
+ std::string grid_accel; //!< acceleration structure to use for grids
+ std::string grid_builder; //!< builder for grids
+ std::string grid_accel_mb; //!< acceleration structure to use for motion blur grids
+ std::string grid_builder_mb; //!< builder for motion blur grids
+
+ public:
+ float max_spatial_split_replications; //!< maximally replications*N many primitives in accel for spatial splits
+ bool useSpatialPreSplits; //!< use spatial pre-splits instead of the full spatial split builder
+ size_t tessellation_cache_size; //!< size of the shared tessellation cache
+
+ public:
+ size_t instancing_open_min; //!< instancing opens tree to minimally that number of subtrees
+ size_t instancing_block_size; //!< instancing opens tree up to average block size of primitives
+ float instancing_open_factor; //!< instancing opens tree up to x times the number of instances
+ size_t instancing_open_max_depth; //!< maximum open depth for geometries
+ size_t instancing_open_max; //!< instancing opens tree to maximally that number of subtrees
+
+ public:
+ bool float_exceptions; //!< enable floating point exceptions
+ int quality_flags;
+ int scene_flags;
+ size_t verbose; //!< verbosity of output
+ size_t benchmark; //!< true
+
+ public:
+ size_t numThreads; //!< number of threads to use in builders
+ size_t numUserThreads; //!< number of user provided threads to use in builders
+ bool set_affinity; //!< sets affinity for worker threads
+ bool start_threads; //!< true when threads should be started at device creation time
+ int enabled_cpu_features; //!< CPU ISA features to use
+ int enabled_builder_cpu_features; //!< CPU ISA features to use for builders only
+ enum FREQUENCY_LEVEL {
+ FREQUENCY_SIMD128,
+ FREQUENCY_SIMD256,
+ FREQUENCY_SIMD512
+ } frequency_level; //!< frequency level the app wants to run on (default is SIMD256)
+ bool enable_selockmemoryprivilege; //!< configures the SeLockMemoryPrivilege under Windows to enable huge pages
+ bool hugepages; //!< true if huge pages should get used
+ bool hugepages_success; //!< status for enabling huge pages
+
+ public:
+ size_t alloc_main_block_size; //!< main allocation block size (shared between threads)
+ int alloc_num_main_slots; //!< number of such shared blocks to be used to allocate
+ size_t alloc_thread_block_size; //!< size of thread local allocator block size
+ int alloc_single_thread_alloc; //!< in single mode nodes and leaves use same thread local allocator
+
+ public:
+
+ /*! checks if we can use AVX */
+ bool canUseAVX() {
+ return hasISA(AVX) && frequency_level != FREQUENCY_SIMD128;
+ }
+
+ /*! checks if we can use AVX2 */
+ bool canUseAVX2() {
+ return hasISA(AVX2) && frequency_level != FREQUENCY_SIMD128;
+ }
+
+ struct ErrorHandler
+ {
+ public:
+ ErrorHandler();
+ ~ErrorHandler();
+ RTCError* error();
+
+ public:
+ tls_t thread_error;
+ std::vector<RTCError*> thread_errors;
+ MutexSys errors_mutex;
+ };
+ ErrorHandler errorHandler;
+ static ErrorHandler g_errorHandler;
+
+ public:
+ void setErrorFunction(RTCErrorFunction fptr, void* uptr)
+ {
+ error_function = fptr;
+ error_function_userptr = uptr;
+ }
+
+ RTCErrorFunction error_function;
+ void* error_function_userptr;
+
+ public:
+ void setMemoryMonitorFunction(RTCMemoryMonitorFunction fptr, void* uptr)
+ {
+ memory_monitor_function = fptr;
+ memory_monitor_userptr = uptr;
+ }
+
+ RTCMemoryMonitorFunction memory_monitor_function;
+ void* memory_monitor_userptr;
+ };
+}
diff --git a/thirdparty/embree/kernels/common/vector.h b/thirdparty/embree/kernels/common/vector.h
new file mode 100644
index 0000000000..4b08275f3b
--- /dev/null
+++ b/thirdparty/embree/kernels/common/vector.h
@@ -0,0 +1,76 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "default.h"
+
+namespace embree
+{
+ /*! invokes the memory monitor callback */
+ struct MemoryMonitorInterface {
+ virtual void memoryMonitor(ssize_t bytes, bool post) = 0;
+ };
+
+ /*! allocator that performs aligned monitored allocations */
+ template<typename T, size_t alignment = 64>
+ struct aligned_monitored_allocator
+ {
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ __forceinline aligned_monitored_allocator(MemoryMonitorInterface* device)
+ : device(device), hugepages(false) {}
+
+ __forceinline pointer allocate( size_type n )
+ {
+ if (n) {
+ assert(device);
+ device->memoryMonitor(n*sizeof(T),false);
+ }
+ if (n*sizeof(value_type) >= 14 * PAGE_SIZE_2M)
+ {
+ pointer p = (pointer) os_malloc(n*sizeof(value_type),hugepages);
+ assert(p);
+ return p;
+ }
+ return (pointer) alignedMalloc(n*sizeof(value_type),alignment);
+ }
+
+ __forceinline void deallocate( pointer p, size_type n )
+ {
+ if (p)
+ {
+ if (n*sizeof(value_type) >= 14 * PAGE_SIZE_2M)
+ os_free(p,n*sizeof(value_type),hugepages);
+ else
+ alignedFree(p);
+ }
+ else assert(n == 0);
+
+ if (n) {
+ assert(device);
+ device->memoryMonitor(-ssize_t(n)*sizeof(T),true);
+ }
+ }
+
+ __forceinline void construct( pointer p, const_reference val ) {
+ new (p) T(val);
+ }
+
+ __forceinline void destroy( pointer p ) {
+ p->~T();
+ }
+
+ private:
+ MemoryMonitorInterface* device;
+ bool hugepages;
+ };
+
+ /*! monitored vector */
+ template<typename T>
+ using mvector = vector_t<T,aligned_monitored_allocator<T,std::alignment_of<T>::value> >;
+}
diff --git a/thirdparty/embree/kernels/config.h b/thirdparty/embree/kernels/config.h
new file mode 100644
index 0000000000..80a8ab2a56
--- /dev/null
+++ b/thirdparty/embree/kernels/config.h
@@ -0,0 +1,76 @@
+
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+/* #undef EMBREE_RAY_MASK */
+/* #undef EMBREE_STAT_COUNTERS */
+/* #undef EMBREE_BACKFACE_CULLING */
+/* #undef EMBREE_BACKFACE_CULLING_CURVES */
+#define EMBREE_FILTER_FUNCTION
+/* #undef EMBREE_IGNORE_INVALID_RAYS */
+#define EMBREE_GEOMETRY_TRIANGLE
+/* #undef EMBREE_GEOMETRY_QUAD */
+/* #undef EMBREE_GEOMETRY_CURVE */
+/* #undef EMBREE_GEOMETRY_SUBDIVISION */
+/* #undef EMBREE_GEOMETRY_USER */
+/* #undef EMBREE_GEOMETRY_INSTANCE */
+/* #undef EMBREE_GEOMETRY_GRID */
+/* #undef EMBREE_GEOMETRY_POINT */
+/* #undef EMBREE_RAY_PACKETS */
+/* #undef EMBREE_COMPACT_POLYS */
+
+#define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR 2.0
+
+#if defined(EMBREE_GEOMETRY_TRIANGLE)
+ #define IF_ENABLED_TRIS(x) x
+#else
+ #define IF_ENABLED_TRIS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_QUAD)
+ #define IF_ENABLED_QUADS(x) x
+#else
+ #define IF_ENABLED_QUADS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT)
+ #define IF_ENABLED_CURVES_OR_POINTS(x) x
+#else
+ #define IF_ENABLED_CURVES_OR_POINTS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_CURVE)
+ #define IF_ENABLED_CURVES(x) x
+#else
+ #define IF_ENABLED_CURVES(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_POINT)
+ #define IF_ENABLED_POINTS(x) x
+#else
+ #define IF_ENABLED_POINTS(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_SUBDIVISION)
+ #define IF_ENABLED_SUBDIV(x) x
+#else
+ #define IF_ENABLED_SUBDIV(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_USER)
+ #define IF_ENABLED_USER(x) x
+#else
+ #define IF_ENABLED_USER(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_INSTANCE)
+ #define IF_ENABLED_INSTANCE(x) x
+#else
+ #define IF_ENABLED_INSTANCE(x)
+#endif
+
+#if defined(EMBREE_GEOMETRY_GRID)
+ #define IF_ENABLED_GRIDS(x) x
+#else
+ #define IF_ENABLED_GRIDS(x)
+#endif
diff --git a/thirdparty/embree/kernels/geometry/cone.h b/thirdparty/embree/kernels/geometry/cone.h
new file mode 100644
index 0000000000..17429bab32
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/cone.h
@@ -0,0 +1,321 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct Cone
+ {
+ const Vec3fa p0; //!< start position of cone
+ const Vec3fa p1; //!< end position of cone
+ const float r0; //!< start radius of cone
+ const float r1; //!< end radius of cone
+
+ __forceinline Cone(const Vec3fa& p0, const float r0, const Vec3fa& p1, const float r1)
+ : p0(p0), p1(p1), r0(r0), r1(r1) {}
+
+ __forceinline bool intersect(const Vec3fa& org, const Vec3fa& dir,
+ BBox1f& t_o,
+ float& u0_o, Vec3fa& Ng0_o,
+ float& u1_o, Vec3fa& Ng1_o) const
+ {
+ /* calculate quadratic equation to solve */
+ const Vec3fa v0 = p0-org;
+ const Vec3fa v1 = p1-org;
+
+ const float rl = rcp_length(v1-v0);
+ const Vec3fa P0 = v0, dP = (v1-v0)*rl;
+ const float dr = (r1-r0)*rl;
+ const Vec3fa O = -P0, dO = dir;
+
+ const float dOdO = dot(dO,dO);
+ const float OdO = dot(dO,O);
+ const float OO = dot(O,O);
+ const float dOz = dot(dP,dO);
+ const float Oz = dot(dP,O);
+
+ const float R = r0 + Oz*dr;
+ const float A = dOdO - sqr(dOz) * (1.0f+sqr(dr));
+ const float B = 2.0f * (OdO - dOz*(Oz + R*dr));
+ const float C = OO - (sqr(Oz) + sqr(R));
+
+ /* we miss the cone if determinant is smaller than zero */
+ const float D = B*B - 4.0f*A*C;
+ if (D < 0.0f) return false;
+
+ /* special case for rays that are "parallel" to the cone */
+ const float eps = float(1<<8)*float(ulp)*max(abs(dOdO),abs(sqr(dOz)));
+ if (unlikely(abs(A) < eps))
+ {
+ /* cylinder case */
+ if (abs(dr) < 16.0f*float(ulp)) {
+ if (C <= 0.0f) { t_o = BBox1f(neg_inf,pos_inf); return true; }
+ else { t_o = BBox1f(pos_inf,neg_inf); return false; }
+ }
+
+ /* cone case */
+ else
+ {
+ /* if we hit the negative cone there cannot be a hit */
+ const float t = -C/B;
+ const float z0 = Oz+t*dOz;
+ const float z0r = r0+z0*dr;
+ if (z0r < 0.0f) return false;
+
+ /* test if we start inside or outside the cone */
+ if (dOz*dr > 0.0f) t_o = BBox1f(t,pos_inf);
+ else t_o = BBox1f(neg_inf,t);
+ }
+ }
+
+ /* standard case for "non-parallel" rays */
+ else
+ {
+ const float Q = sqrt(D);
+ const float rcp_2A = rcp(2.0f*A);
+ t_o.lower = (-B-Q)*rcp_2A;
+ t_o.upper = (-B+Q)*rcp_2A;
+
+ /* standard case where both hits are on same cone */
+ if (likely(A > 0.0f)) {
+ const float z0 = Oz+t_o.lower*dOz;
+ const float z0r = r0+z0*dr;
+ if (z0r < 0.0f) return false;
+ }
+
+ /* special case where the hits are on the positive and negative cone */
+ else
+ {
+ /* depending on the ray direction and the open direction
+ * of the cone we have a hit from inside or outside the
+ * cone */
+ if (dOz*dr > 0) t_o.upper = pos_inf;
+ else t_o.lower = neg_inf;
+ }
+ }
+
+ /* calculates u and Ng for near hit */
+ {
+ u0_o = (Oz+t_o.lower*dOz)*rl;
+ const Vec3fa Pr = t_o.lower*dir;
+ const Vec3fa Pl = v0 + u0_o*(v1-v0);
+ const Vec3fa R = normalize(Pr-Pl);
+ const Vec3fa U = (p1-p0)+(r1-r0)*R;
+ const Vec3fa V = cross(p1-p0,R);
+ Ng0_o = cross(V,U);
+ }
+
+ /* calculates u and Ng for far hit */
+ {
+ u1_o = (Oz+t_o.upper*dOz)*rl;
+ const Vec3fa Pr = t_o.upper*dir;
+ const Vec3fa Pl = v0 + u1_o*(v1-v0);
+ const Vec3fa R = normalize(Pr-Pl);
+ const Vec3fa U = (p1-p0)+(r1-r0)*R;
+ const Vec3fa V = cross(p1-p0,R);
+ Ng1_o = cross(V,U);
+ }
+ return true;
+ }
+
+ __forceinline bool intersect(const Vec3fa& org, const Vec3fa& dir, BBox1f& t_o) const
+ {
+ float u0_o; Vec3fa Ng0_o; float u1_o; Vec3fa Ng1_o;
+ return intersect(org,dir,t_o,u0_o,Ng0_o,u1_o,Ng1_o);
+ }
+
+ static bool verify(const size_t id, const Cone& cone, const Ray& ray, bool shouldhit, const float t0, const float t1)
+ {
+ float eps = 0.001f;
+ BBox1f t; bool hit;
+ hit = cone.intersect(ray.org,ray.dir,t);
+
+ bool failed = hit != shouldhit;
+ if (shouldhit) failed |= std::isinf(t0) ? t0 != t.lower : (t0 == -1E6) ? t.lower > -1E6f : abs(t0-t.lower) > eps;
+ if (shouldhit) failed |= std::isinf(t1) ? t1 != t.upper : (t1 == +1E6) ? t.upper < +1E6f : abs(t1-t.upper) > eps;
+ if (!failed) return true;
+ embree_cout << "Cone test " << id << " failed: cone = " << cone << ", ray = " << ray << ", hit = " << hit << ", t = " << t << embree_endl;
+ return false;
+ }
+
+ /* verify cone class */
+ static bool verify()
+ {
+ bool passed = true;
+ const Cone cone0(Vec3fa(0.0f,0.0f,0.0f),0.0f,Vec3fa(1.0f,0.0f,0.0f),1.0f);
+ passed &= verify(0,cone0,Ray(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa(+1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,3.0f,pos_inf);
+ passed &= verify(1,cone0,Ray(Vec3fa(+2.0f,1.0f,0.0f),Vec3fa(-1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,1.0f);
+ passed &= verify(2,cone0,Ray(Vec3fa(-1.0f,0.0f,2.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),false,0.0f,0.0f);
+ passed &= verify(3,cone0,Ray(Vec3fa(+1.0f,0.0f,2.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),true,1.0f,3.0f);
+ passed &= verify(4,cone0,Ray(Vec3fa(-1.0f,0.0f,0.0f),Vec3fa(+1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,1.0f,pos_inf);
+ passed &= verify(5,cone0,Ray(Vec3fa(+1.0f,0.0f,0.0f),Vec3fa(-1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,1.0f);
+ passed &= verify(6,cone0,Ray(Vec3fa(+0.0f,0.0f,1.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),true,1.0f,1.0f);
+ passed &= verify(7,cone0,Ray(Vec3fa(+0.0f,1.0f,0.0f),Vec3fa(-1.0f,-1.0f,+0.0f),0.0f,float(inf)),false,0.0f,0.0f);
+ passed &= verify(8,cone0,Ray(Vec3fa(+0.0f,1.0f,0.0f),Vec3fa(+1.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.5f,+1E6);
+ passed &= verify(9,cone0,Ray(Vec3fa(+0.0f,1.0f,0.0f),Vec3fa(-1.0f,+1.0f,+0.0f),0.0f,float(inf)),true,-1E6,-0.5f);
+ const Cone cone1(Vec3fa(0.0f,0.0f,0.0f),1.0f,Vec3fa(1.0f,0.0f,0.0f),0.0f);
+ passed &= verify(10,cone1,Ray(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa(+1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,2.0f);
+ passed &= verify(11,cone1,Ray(Vec3fa(-1.0f,0.0f,2.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),true,0.0f,4.0f);
+ const Cone cylinder(Vec3fa(0.0f,0.0f,0.0f),1.0f,Vec3fa(1.0f,0.0f,0.0f),1.0f);
+ passed &= verify(12,cylinder,Ray(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.0f,2.0f);
+ passed &= verify(13,cylinder,Ray(Vec3fa(+2.0f,1.0f,0.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.0f,2.0f);
+ passed &= verify(14,cylinder,Ray(Vec3fa(+2.0f,1.0f,2.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),false,0.0f,0.0f);
+ passed &= verify(15,cylinder,Ray(Vec3fa(+0.0f,0.0f,0.0f),Vec3fa( 1.0f, 0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,pos_inf);
+ passed &= verify(16,cylinder,Ray(Vec3fa(+0.0f,0.0f,0.0f),Vec3fa(-1.0f, 0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,pos_inf);
+ passed &= verify(17,cylinder,Ray(Vec3fa(+0.0f,2.0f,0.0f),Vec3fa( 1.0f, 0.0f,+0.0f),0.0f,float(inf)),false,pos_inf,neg_inf);
+ passed &= verify(18,cylinder,Ray(Vec3fa(+0.0f,2.0f,0.0f),Vec3fa(-1.0f, 0.0f,+0.0f),0.0f,float(inf)),false,pos_inf,neg_inf);
+ return passed;
+ }
+
+ /*! output operator */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const Cone& c) {
+ return cout << "Cone { p0 = " << c.p0 << ", r0 = " << c.r0 << ", p1 = " << c.p1 << ", r1 = " << c.r1 << "}";
+ }
+ };
+
+ template<int N>
+ struct ConeN
+ {
+ typedef Vec3<vfloat<N>> Vec3vfN;
+
+ const Vec3vfN p0; //!< start position of cone
+ const Vec3vfN p1; //!< end position of cone
+ const vfloat<N> r0; //!< start radius of cone
+ const vfloat<N> r1; //!< end radius of cone
+
+ __forceinline ConeN(const Vec3vfN& p0, const vfloat<N>& r0, const Vec3vfN& p1, const vfloat<N>& r1)
+ : p0(p0), p1(p1), r0(r0), r1(r1) {}
+
+ __forceinline Cone operator[] (const size_t i) const
+ {
+ assert(i<N);
+ return Cone(Vec3fa(p0.x[i],p0.y[i],p0.z[i]),r0[i],Vec3fa(p1.x[i],p1.y[i],p1.z[i]),r1[i]);
+ }
+
+ __forceinline vbool<N> intersect(const Vec3fa& org, const Vec3fa& dir,
+ BBox<vfloat<N>>& t_o,
+ vfloat<N>& u0_o, Vec3vfN& Ng0_o,
+ vfloat<N>& u1_o, Vec3vfN& Ng1_o) const
+ {
+ /* calculate quadratic equation to solve */
+ const Vec3vfN v0 = p0-Vec3vfN(org);
+ const Vec3vfN v1 = p1-Vec3vfN(org);
+
+ const vfloat<N> rl = rcp_length(v1-v0);
+ const Vec3vfN P0 = v0, dP = (v1-v0)*rl;
+ const vfloat<N> dr = (r1-r0)*rl;
+ const Vec3vfN O = -P0, dO = dir;
+
+ const vfloat<N> dOdO = dot(dO,dO);
+ const vfloat<N> OdO = dot(dO,O);
+ const vfloat<N> OO = dot(O,O);
+ const vfloat<N> dOz = dot(dP,dO);
+ const vfloat<N> Oz = dot(dP,O);
+
+ const vfloat<N> R = r0 + Oz*dr;
+ const vfloat<N> A = dOdO - sqr(dOz) * (vfloat<N>(1.0f)+sqr(dr));
+ const vfloat<N> B = 2.0f * (OdO - dOz*(Oz + R*dr));
+ const vfloat<N> C = OO - (sqr(Oz) + sqr(R));
+
+ /* we miss the cone if determinant is smaller than zero */
+ const vfloat<N> D = B*B - 4.0f*A*C;
+ vbool<N> valid = D >= 0.0f;
+ if (none(valid)) return valid;
+
+ /* special case for rays that are "parallel" to the cone */
+ const vfloat<N> eps = float(1<<8)*float(ulp)*max(abs(dOdO),abs(sqr(dOz)));
+ const vbool<N> validt = valid & (abs(A) < eps);
+ const vbool<N> validf = valid & !(abs(A) < eps);
+ if (unlikely(any(validt)))
+ {
+ const vboolx validtt = validt & (abs(dr) < 16.0f*float(ulp));
+ const vboolx validtf = validt & (abs(dr) >= 16.0f*float(ulp));
+
+ /* cylinder case */
+ if (unlikely(any(validtt)))
+ {
+ t_o.lower = select(validtt, select(C <= 0.0f, vfloat<N>(neg_inf), vfloat<N>(pos_inf)), t_o.lower);
+ t_o.upper = select(validtt, select(C <= 0.0f, vfloat<N>(pos_inf), vfloat<N>(neg_inf)), t_o.upper);
+ valid &= !validtt | C <= 0.0f;
+ }
+
+ /* cone case */
+ if (any(validtf))
+ {
+ /* if we hit the negative cone there cannot be a hit */
+ const vfloat<N> t = -C/B;
+ const vfloat<N> z0 = Oz+t*dOz;
+ const vfloat<N> z0r = r0+z0*dr;
+ valid &= !validtf | z0r >= 0.0f;
+
+ /* test if we start inside or outside the cone */
+ t_o.lower = select(validtf, select(dOz*dr > 0.0f, t, vfloat<N>(neg_inf)), t_o.lower);
+ t_o.upper = select(validtf, select(dOz*dr > 0.0f, vfloat<N>(pos_inf), t), t_o.upper);
+ }
+ }
+
+ /* standard case for "non-parallel" rays */
+ if (likely(any(validf)))
+ {
+ const vfloat<N> Q = sqrt(D);
+ const vfloat<N> rcp_2A = 0.5f*rcp(A);
+ t_o.lower = select(validf, (-B-Q)*rcp_2A, t_o.lower);
+ t_o.upper = select(validf, (-B+Q)*rcp_2A, t_o.upper);
+
+ /* standard case where both hits are on same cone */
+ const vbool<N> validft = validf & A>0.0f;
+ const vbool<N> validff = validf & !(A>0.0f);
+ if (any(validft)) {
+ const vfloat<N> z0 = Oz+t_o.lower*dOz;
+ const vfloat<N> z0r = r0+z0*dr;
+ valid &= !validft | z0r >= 0.0f;
+ }
+
+ /* special case where the hits are on the positive and negative cone */
+ if (any(validff)) {
+ /* depending on the ray direction and the open direction
+ * of the cone we have a hit from inside or outside the
+ * cone */
+ t_o.lower = select(validff, select(dOz*dr > 0.0f, t_o.lower, float(neg_inf)), t_o.lower);
+ t_o.upper = select(validff, select(dOz*dr > 0.0f, float(pos_inf), t_o.upper), t_o.upper);
+ }
+ }
+
+ /* calculates u and Ng for near hit */
+ {
+ u0_o = (Oz+t_o.lower*dOz)*rl;
+ const Vec3vfN Pr = t_o.lower*Vec3vfN(dir);
+ const Vec3vfN Pl = v0 + u0_o*(v1-v0);
+ const Vec3vfN R = normalize(Pr-Pl);
+ const Vec3vfN U = (p1-p0)+(r1-r0)*R;
+ const Vec3vfN V = cross(p1-p0,R);
+ Ng0_o = cross(V,U);
+ }
+
+ /* calculates u and Ng for far hit */
+ {
+ u1_o = (Oz+t_o.upper*dOz)*rl;
+ const Vec3vfN Pr = t_o.lower*Vec3vfN(dir);
+ const Vec3vfN Pl = v0 + u1_o*(v1-v0);
+ const Vec3vfN R = normalize(Pr-Pl);
+ const Vec3vfN U = (p1-p0)+(r1-r0)*R;
+ const Vec3vfN V = cross(p1-p0,R);
+ Ng1_o = cross(V,U);
+ }
+ return valid;
+ }
+
+ __forceinline vbool<N> intersect(const Vec3fa& org, const Vec3fa& dir, BBox<vfloat<N>>& t_o) const
+ {
+ vfloat<N> u0_o; Vec3vfN Ng0_o; vfloat<N> u1_o; Vec3vfN Ng1_o;
+ return intersect(org,dir,t_o,u0_o,Ng0_o,u1_o,Ng1_o);
+ }
+ };
+ }
+}
+
diff --git a/thirdparty/embree/kernels/geometry/coneline_intersector.h b/thirdparty/embree/kernels/geometry/coneline_intersector.h
new file mode 100644
index 0000000000..90f3792eff
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/coneline_intersector.h
@@ -0,0 +1,209 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ namespace __coneline_internal
+ {
+ template<int M, typename Epilog, typename ray_tfar_func>
+ static __forceinline bool intersectCone(const vbool<M>& valid_i,
+ const Vec3vf<M>& ray_org_in, const Vec3vf<M>& ray_dir,
+ const vfloat<M>& ray_tnear, const ray_tfar_func& ray_tfar,
+ const Vec4vf<M>& v0, const Vec4vf<M>& v1,
+ const vbool<M>& cL, const vbool<M>& cR,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ /* move ray origin closer to make calculations numerically stable */
+ const vfloat<M> dOdO = sqr(ray_dir);
+ const vfloat<M> rcp_dOdO = rcp(dOdO);
+ const Vec3vf<M> center = vfloat<M>(0.5f)*(v0.xyz()+v1.xyz());
+ const vfloat<M> dt = dot(center-ray_org_in,ray_dir)*rcp_dOdO;
+ const Vec3vf<M> ray_org = ray_org_in + dt*ray_dir;
+
+ const Vec3vf<M> dP = v1.xyz() - v0.xyz();
+ const Vec3vf<M> p0 = ray_org - v0.xyz();
+ const Vec3vf<M> p1 = ray_org - v1.xyz();
+
+ const vfloat<M> dPdP = sqr(dP);
+ const vfloat<M> dP0 = dot(p0,dP);
+ const vfloat<M> dP1 = dot(p1,dP);
+ const vfloat<M> dOdP = dot(ray_dir,dP);
+
+ // intersect cone body
+ const vfloat<M> dr = v0.w - v1.w;
+ const vfloat<M> hy = dPdP + sqr(dr);
+ const vfloat<M> dO0 = dot(ray_dir,p0);
+ const vfloat<M> OO = sqr(p0);
+ const vfloat<M> dPdP2 = sqr(dPdP);
+ const vfloat<M> dPdPr0 = dPdP*v0.w;
+
+ const vfloat<M> A = dPdP2 - sqr(dOdP)*hy;
+ const vfloat<M> B = dPdP2*dO0 - dP0*dOdP*hy + dPdPr0*(dr*dOdP);
+ const vfloat<M> C = dPdP2*OO - sqr(dP0)*hy + dPdPr0*(2.0f*dr*dP0 - dPdPr0);
+
+ const vfloat<M> D = B*B - A*C;
+ valid &= D >= 0.0f;
+ if (unlikely(none(valid))) {
+ return false;
+ }
+
+ /* standard case for "non-parallel" rays */
+ const vfloat<M> Q = sqrt(D);
+ const vfloat<M> rcp_A = rcp(A);
+ /* special case for rays that are "parallel" to the cone - assume miss */
+ const vbool<M> isParallel = abs(A) <= min_rcp_input;
+
+ vfloat<M> t_cone_lower = select (isParallel, neg_inf, (-B-Q)*rcp_A);
+ vfloat<M> t_cone_upper = select (isParallel, pos_inf, (-B+Q)*rcp_A);
+ const vfloat<M> y_lower = dP0 + t_cone_lower*dOdP;
+ const vfloat<M> y_upper = dP0 + t_cone_upper*dOdP;
+ t_cone_lower = select(valid & y_lower > 0.0f & y_lower < dPdP, t_cone_lower, pos_inf);
+ t_cone_upper = select(valid & y_upper > 0.0f & y_upper < dPdP, t_cone_upper, neg_inf);
+
+ const vbool<M> hitDisk0 = valid & cL;
+ const vbool<M> hitDisk1 = valid & cR;
+ const vfloat<M> rcp_dOdP = rcp(dOdP);
+ const vfloat<M> t_disk0 = select (hitDisk0, select (sqr(p0*dOdP-ray_dir*dP0)<(sqr(v0.w)*sqr(dOdP)), -dP0*rcp_dOdP, pos_inf), pos_inf);
+ const vfloat<M> t_disk1 = select (hitDisk1, select (sqr(p1*dOdP-ray_dir*dP1)<(sqr(v1.w)*sqr(dOdP)), -dP1*rcp_dOdP, pos_inf), pos_inf);
+ const vfloat<M> t_disk_lower = min(t_disk0, t_disk1);
+ const vfloat<M> t_disk_upper = max(t_disk0, t_disk1);
+
+ const vfloat<M> t_lower = min(t_cone_lower, t_disk_lower);
+ const vfloat<M> t_upper = max(t_cone_upper, select(t_lower==t_disk_lower,
+ select(t_disk_upper==vfloat<M>(pos_inf),neg_inf,t_disk_upper),
+ select(t_disk_lower==vfloat<M>(pos_inf),neg_inf,t_disk_lower)));
+
+ const vbool<M> valid_lower = valid & ray_tnear <= dt+t_lower & dt+t_lower <= ray_tfar() & t_lower != vfloat<M>(pos_inf);
+ const vbool<M> valid_upper = valid & ray_tnear <= dt+t_upper & dt+t_upper <= ray_tfar() & t_upper != vfloat<M>(neg_inf);
+
+ const vbool<M> valid_first = valid_lower | valid_upper;
+ if (unlikely(none(valid_first)))
+ return false;
+
+ const vfloat<M> t_first = select(valid_lower, t_lower, t_upper);
+ const vfloat<M> y_first = select(valid_lower, y_lower, y_upper);
+
+ const vfloat<M> rcp_dPdP = rcp(dPdP);
+ const Vec3vf<M> dP2drr0dP = dPdP*dr*v0.w*dP;
+ const Vec3vf<M> dPhy = dP*hy;
+ const vbool<M> cone_hit_first = valid & (t_first == t_cone_lower | t_first == t_cone_upper);
+ const vbool<M> disk0_hit_first = valid & (t_first == t_disk0);
+ const Vec3vf<M> Ng_first = select(cone_hit_first, dPdP2*(p0+t_first*ray_dir)+dP2drr0dP-dPhy*y_first, select(disk0_hit_first, -dP, dP));
+ const vfloat<M> u_first = select(cone_hit_first, y_first*rcp_dPdP, select(disk0_hit_first, vfloat<M>(zero), vfloat<M>(one)));
+
+ /* invoke intersection filter for first hit */
+ RoundLineIntersectorHitM<M> hit(u_first,zero,dt+t_first,Ng_first);
+ const bool is_hit_first = epilog(valid_first, hit);
+
+ /* check for possible second hits before potentially accepted hit */
+ const vfloat<M> t_second = t_upper;
+ const vfloat<M> y_second = y_upper;
+ const vbool<M> valid_second = valid_lower & valid_upper & (dt+t_upper <= ray_tfar());
+ if (unlikely(none(valid_second)))
+ return is_hit_first;
+
+ /* invoke intersection filter for second hit */
+ const vbool<M> cone_hit_second = t_second == t_cone_lower | t_second == t_cone_upper;
+ const vbool<M> disk0_hit_second = t_second == t_disk0;
+ const Vec3vf<M> Ng_second = select(cone_hit_second, dPdP2*(p0+t_second*ray_dir)+dP2drr0dP-dPhy*y_second, select(disk0_hit_second, -dP, dP));
+ const vfloat<M> u_second = select(cone_hit_second, y_second*rcp_dPdP, select(disk0_hit_first, vfloat<M>(zero), vfloat<M>(one)));
+
+ hit = RoundLineIntersectorHitM<M>(u_second,zero,dt+t_second,Ng_second);
+ const bool is_hit_second = epilog(valid_second, hit);
+
+ return is_hit_first | is_hit_second;
+ }
+ }
+
+ template<int M>
+ struct ConeLineIntersectorHitM
+ {
+ __forceinline ConeLineIntersectorHitM() {}
+
+ __forceinline ConeLineIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)
+ : vu(u), vv(v), vt(t), vNg(Ng) {}
+
+ __forceinline void finalize() {}
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ public:
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct ConeCurveIntersector1
+ {
+ typedef CurvePrecalculations1 Precalculations;
+
+ struct ray_tfar {
+ Ray& ray;
+ __forceinline ray_tfar(Ray& ray) : ray(ray) {}
+ __forceinline vfloat<M> operator() () const { return ray.tfar; };
+ };
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ Ray& ray,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const vbool<M>& cL, const vbool<M>& cR,
+ const Epilog& epilog)
+ {
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+ const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);
+ const vfloat<M> ray_tnear(ray.tnear());
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v1i);
+ return __coneline_internal::intersectCone<M>(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar(ray),v0,v1,cL,cR,epilog);
+ }
+ };
+
+ template<int M, int K>
+ struct ConeCurveIntersectorK
+ {
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ struct ray_tfar {
+ RayK<K>& ray;
+ size_t k;
+ __forceinline ray_tfar(RayK<K>& ray, size_t k) : ray(ray), k(k) {}
+ __forceinline vfloat<M> operator() () const { return ray.tfar[k]; };
+ };
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const vbool<M>& cL, const vbool<M>& cR,
+ const Epilog& epilog)
+ {
+ const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
+ const vfloat<M> ray_tnear = ray.tnear()[k];
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v1i);
+ return __coneline_internal::intersectCone<M>(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar(ray,k),v0,v1,cL,cR,epilog);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/conelinei_intersector.h b/thirdparty/embree/kernels/geometry/conelinei_intersector.h
new file mode 100644
index 0000000000..6a985ebcad
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/conelinei_intersector.h
@@ -0,0 +1,141 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "coneline_intersector.h"
+#include "intersector_epilog.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, bool filter>
+ struct ConeCurveMiIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom);
+ const vbool<M> valid = line.valid();
+ ConeCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,cL,cR,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom);
+ const vbool<M> valid = line.valid();
+ return ConeCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,cL,cR,Occluded1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ return false;
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, bool filter>
+ struct ConeCurveMiMBIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom,ray.time());
+ const vbool<M> valid = line.valid();
+ ConeCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,cL,cR,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom,ray.time());
+ const vbool<M> valid = line.valid();
+ return ConeCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,cL,cR,Occluded1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ return false;
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct ConeCurveMiIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom);
+ const vbool<M> valid = line.valid();
+ ConeCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,cL,cR,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom);
+ const vbool<M> valid = line.valid();
+ return ConeCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,cL,cR,Occluded1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct ConeCurveMiMBIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom,ray.time()[k]);
+ const vbool<M> valid = line.valid();
+ ConeCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,cL,cR,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1;
+ vbool<M> cL,cR;
+ line.gather(v0,v1,cL,cR,geom,ray.time()[k]);
+ const vbool<M> valid = line.valid();
+ return ConeCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,cL,cR,Occluded1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/curveNi.h b/thirdparty/embree/kernels/geometry/curveNi.h
new file mode 100644
index 0000000000..6366a6fb9c
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curveNi.h
@@ -0,0 +1,222 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ template<int M>
+ struct CurveNi
+ {
+ struct Type : public PrimitiveType {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored primitives */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+M-1)/M; }
+
+ static __forceinline size_t bytes(size_t N)
+ {
+ const size_t f = N/M, r = N%M;
+ static_assert(sizeof(CurveNi) == 22+25*M, "internal data layout issue");
+ return f*sizeof(CurveNi) + (r!=0)*(22 + 25*r);
+ }
+
+ public:
+
+ /*! Default constructor. */
+ __forceinline CurveNi () {}
+
+ /*! fill curve from curve list */
+ __forceinline void fill(const PrimRef* prims, size_t& begin, size_t _end, Scene* scene)
+ {
+ size_t end = min(begin+M,_end);
+ N = (unsigned char)(end-begin);
+ const unsigned int geomID0 = prims[begin].geomID();
+ this->geomID(N) = geomID0;
+ ty = (unsigned char) scene->get(geomID0)->getType();
+
+ /* encode all primitives */
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<N; i++)
+ {
+ const PrimRef& prim = prims[begin+i];
+ const unsigned int geomID = prim.geomID(); assert(geomID == geomID0);
+ const unsigned int primID = prim.primID();
+ bounds.extend(scene->get(geomID)->vbounds(primID));
+ }
+
+ /* calculate offset and scale */
+ Vec3fa loffset = bounds.lower;
+ float lscale = reduce_min(256.0f/(bounds.size()*sqrt(3.0f)));
+ if (bounds.size() == Vec3fa(zero)) lscale = 0.0f;
+ *this->offset(N) = loffset;
+ *this->scale(N) = lscale;
+
+ /* encode all primitives */
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRef& prim = prims[begin];
+ const unsigned int geomID = prim.geomID();
+ const unsigned int primID = prim.primID();
+ const LinearSpace3fa space2 = scene->get(geomID)->computeAlignedSpace(primID);
+
+ const LinearSpace3fa space3(trunc(126.0f*space2.vx),trunc(126.0f*space2.vy),trunc(126.0f*space2.vz));
+ const BBox3fa bounds = scene->get(geomID)->vbounds(loffset,lscale,max(length(space3.vx),length(space3.vy),length(space3.vz)),space3.transposed(),primID);
+
+ bounds_vx_x(N)[i] = (char) space3.vx.x;
+ bounds_vx_y(N)[i] = (char) space3.vx.y;
+ bounds_vx_z(N)[i] = (char) space3.vx.z;
+ bounds_vx_lower(N)[i] = (short) clamp(floor(bounds.lower.x),-32767.0f,32767.0f);
+ bounds_vx_upper(N)[i] = (short) clamp(ceil (bounds.upper.x),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.lower.x) && floor(bounds.lower.x) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.upper.x) && ceil (bounds.upper.x) <= 32767.0f);
+
+ bounds_vy_x(N)[i] = (char) space3.vy.x;
+ bounds_vy_y(N)[i] = (char) space3.vy.y;
+ bounds_vy_z(N)[i] = (char) space3.vy.z;
+ bounds_vy_lower(N)[i] = (short) clamp(floor(bounds.lower.y),-32767.0f,32767.0f);
+ bounds_vy_upper(N)[i] = (short) clamp(ceil (bounds.upper.y),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.lower.y) && floor(bounds.lower.y) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.upper.y) && ceil (bounds.upper.y) <= 32767.0f);
+
+ bounds_vz_x(N)[i] = (char) space3.vz.x;
+ bounds_vz_y(N)[i] = (char) space3.vz.y;
+ bounds_vz_z(N)[i] = (char) space3.vz.z;
+ bounds_vz_lower(N)[i] = (short) clamp(floor(bounds.lower.z),-32767.0f,32767.0f);
+ bounds_vz_upper(N)[i] = (short) clamp(ceil (bounds.upper.z),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.lower.z) && floor(bounds.lower.z) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.upper.z) && ceil (bounds.upper.z) <= 32767.0f);
+
+ this->primID(N)[i] = primID;
+ }
+ }
+
+ template<typename BVH, typename Allocator>
+ __forceinline static typename BVH::NodeRef createLeaf (BVH* bvh, const PrimRef* prims, const range<size_t>& set, const Allocator& alloc)
+ {
+ size_t start = set.begin();
+ size_t items = CurveNi::blocks(set.size());
+ size_t numbytes = CurveNi::bytes(set.size());
+ CurveNi* accel = (CurveNi*) alloc.malloc1(numbytes,BVH::byteAlignment);
+ for (size_t i=0; i<items; i++) {
+ accel[i].fill(prims,start,set.end(),bvh->scene);
+ }
+ return bvh->encodeLeaf((char*)accel,items);
+ };
+
+ public:
+
+ // 27.6 - 46 bytes per primitive
+ unsigned char ty;
+ unsigned char N;
+ unsigned char data[4+25*M+16];
+
+ /*
+ struct Layout
+ {
+ unsigned int geomID;
+ unsigned int primID[N];
+
+ char bounds_vx_x[N];
+ char bounds_vx_y[N];
+ char bounds_vx_z[N];
+ short bounds_vx_lower[N];
+ short bounds_vx_upper[N];
+
+ char bounds_vy_x[N];
+ char bounds_vy_y[N];
+ char bounds_vy_z[N];
+ short bounds_vy_lower[N];
+ short bounds_vy_upper[N];
+
+ char bounds_vz_x[N];
+ char bounds_vz_y[N];
+ char bounds_vz_z[N];
+ short bounds_vz_lower[N];
+ short bounds_vz_upper[N];
+
+ Vec3f offset;
+ float scale;
+ };
+ */
+
+ __forceinline unsigned int& geomID(size_t N) { return *(unsigned int*)((char*)this+2); }
+ __forceinline const unsigned int& geomID(size_t N) const { return *(unsigned int*)((char*)this+2); }
+
+ __forceinline unsigned int* primID(size_t N) { return (unsigned int*)((char*)this+6); }
+ __forceinline const unsigned int* primID(size_t N) const { return (unsigned int*)((char*)this+6); }
+
+ __forceinline char* bounds_vx_x(size_t N) { return (char*)((char*)this+6+4*N); }
+ __forceinline const char* bounds_vx_x(size_t N) const { return (char*)((char*)this+6+4*N); }
+
+ __forceinline char* bounds_vx_y(size_t N) { return (char*)((char*)this+6+5*N); }
+ __forceinline const char* bounds_vx_y(size_t N) const { return (char*)((char*)this+6+5*N); }
+
+ __forceinline char* bounds_vx_z(size_t N) { return (char*)((char*)this+6+6*N); }
+ __forceinline const char* bounds_vx_z(size_t N) const { return (char*)((char*)this+6+6*N); }
+
+ __forceinline short* bounds_vx_lower(size_t N) { return (short*)((char*)this+6+7*N); }
+ __forceinline const short* bounds_vx_lower(size_t N) const { return (short*)((char*)this+6+7*N); }
+
+ __forceinline short* bounds_vx_upper(size_t N) { return (short*)((char*)this+6+9*N); }
+ __forceinline const short* bounds_vx_upper(size_t N) const { return (short*)((char*)this+6+9*N); }
+
+ __forceinline char* bounds_vy_x(size_t N) { return (char*)((char*)this+6+11*N); }
+ __forceinline const char* bounds_vy_x(size_t N) const { return (char*)((char*)this+6+11*N); }
+
+ __forceinline char* bounds_vy_y(size_t N) { return (char*)((char*)this+6+12*N); }
+ __forceinline const char* bounds_vy_y(size_t N) const { return (char*)((char*)this+6+12*N); }
+
+ __forceinline char* bounds_vy_z(size_t N) { return (char*)((char*)this+6+13*N); }
+ __forceinline const char* bounds_vy_z(size_t N) const { return (char*)((char*)this+6+13*N); }
+
+ __forceinline short* bounds_vy_lower(size_t N) { return (short*)((char*)this+6+14*N); }
+ __forceinline const short* bounds_vy_lower(size_t N) const { return (short*)((char*)this+6+14*N); }
+
+ __forceinline short* bounds_vy_upper(size_t N) { return (short*)((char*)this+6+16*N); }
+ __forceinline const short* bounds_vy_upper(size_t N) const { return (short*)((char*)this+6+16*N); }
+
+ __forceinline char* bounds_vz_x(size_t N) { return (char*)((char*)this+6+18*N); }
+ __forceinline const char* bounds_vz_x(size_t N) const { return (char*)((char*)this+6+18*N); }
+
+ __forceinline char* bounds_vz_y(size_t N) { return (char*)((char*)this+6+19*N); }
+ __forceinline const char* bounds_vz_y(size_t N) const { return (char*)((char*)this+6+19*N); }
+
+ __forceinline char* bounds_vz_z(size_t N) { return (char*)((char*)this+6+20*N); }
+ __forceinline const char* bounds_vz_z(size_t N) const { return (char*)((char*)this+6+20*N); }
+
+ __forceinline short* bounds_vz_lower(size_t N) { return (short*)((char*)this+6+21*N); }
+ __forceinline const short* bounds_vz_lower(size_t N) const { return (short*)((char*)this+6+21*N); }
+
+ __forceinline short* bounds_vz_upper(size_t N) { return (short*)((char*)this+6+23*N); }
+ __forceinline const short* bounds_vz_upper(size_t N) const { return (short*)((char*)this+6+23*N); }
+
+ __forceinline Vec3f* offset(size_t N) { return (Vec3f*)((char*)this+6+25*N); }
+ __forceinline const Vec3f* offset(size_t N) const { return (Vec3f*)((char*)this+6+25*N); }
+
+ __forceinline float* scale(size_t N) { return (float*)((char*)this+6+25*N+12); }
+ __forceinline const float* scale(size_t N) const { return (float*)((char*)this+6+25*N+12); }
+
+ __forceinline char* end(size_t N) { return (char*)this+6+25*N+16; }
+ __forceinline const char* end(size_t N) const { return (char*)this+6+25*N+16; }
+ };
+
+ template<int M>
+ typename CurveNi<M>::Type CurveNi<M>::type;
+
+ typedef CurveNi<4> Curve4i;
+ typedef CurveNi<8> Curve8i;
+}
diff --git a/thirdparty/embree/kernels/geometry/curveNi_intersector.h b/thirdparty/embree/kernels/geometry/curveNi_intersector.h
new file mode 100644
index 0000000000..c0b66515c1
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curveNi_intersector.h
@@ -0,0 +1,569 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curveNi.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct CurveNiIntersector1
+ {
+ typedef CurveNi<M> Primitive;
+ typedef Vec3vf<M> Vec3vfM;
+ typedef LinearSpace3<Vec3vfM>LinearSpace3vfM;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline vbool<M> intersect(Ray& ray, const Primitive& prim, vfloat<M>& tNear_o)
+ {
+ const size_t N = prim.N;
+ const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N));
+ const Vec3fa offset = Vec3fa(offset_scale);
+ const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale));
+ const Vec3fa org1 = (ray.org-offset)*scale;
+ const Vec3fa dir1 = ray.dir*scale;
+
+ const LinearSpace3vfM space(vfloat<M>::load(prim.bounds_vx_x(N)), vfloat<M>::load(prim.bounds_vx_y(N)), vfloat<M>::load(prim.bounds_vx_z(N)),
+ vfloat<M>::load(prim.bounds_vy_x(N)), vfloat<M>::load(prim.bounds_vy_y(N)), vfloat<M>::load(prim.bounds_vy_z(N)),
+ vfloat<M>::load(prim.bounds_vz_x(N)), vfloat<M>::load(prim.bounds_vz_y(N)), vfloat<M>::load(prim.bounds_vz_z(N)));
+
+ const Vec3vfM dir2 = xfmVector(space,Vec3vfM(dir1));
+ const Vec3vfM org2 = xfmPoint (space,Vec3vfM(org1));
+ const Vec3vfM rcp_dir2 = rcp_safe(dir2);
+
+ const vfloat<M> t_lower_x = (vfloat<M>::load(prim.bounds_vx_lower(N))-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_upper_x = (vfloat<M>::load(prim.bounds_vx_upper(N))-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_lower_y = (vfloat<M>::load(prim.bounds_vy_lower(N))-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_upper_y = (vfloat<M>::load(prim.bounds_vy_upper(N))-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_lower_z = (vfloat<M>::load(prim.bounds_vz_lower(N))-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+ const vfloat<M> t_upper_z = (vfloat<M>::load(prim.bounds_vz_upper(N))-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+
+ const vfloat<M> round_up (1.0f+3.0f*float(ulp));
+ const vfloat<M> round_down(1.0f-3.0f*float(ulp));
+ const vfloat<M> tNear = round_down*max(mini(t_lower_x,t_upper_x),mini(t_lower_y,t_upper_y),mini(t_lower_z,t_upper_z),vfloat<M>(ray.tnear()));
+ const vfloat<M> tFar = round_up *min(maxi(t_lower_x,t_upper_x),maxi(t_lower_y,t_upper_y),maxi(t_lower_z,t_upper_z),vfloat<M>(ray.tfar));
+ tNear_o = tNear;
+ return (vint<M>(step) < vint<M>(prim.N)) & (tNear <= tFar);
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID));
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID));
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_n(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+
+ unsigned int vertexID = geom->curve(primID);
+ Vec3ff a0,a1,a2,a3; Vec3fa n0,n1,n2,n3; geom->gather(a0,a1,a2,a3,n0,n1,n2,n3,vertexID);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,n0,n1,n2,n3,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_n(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+
+ unsigned int vertexID = geom->curve(primID);
+ Vec3ff a0,a1,a2,a3; Vec3fa n0,n1,n2,n3; geom->gather(a0,a1,a2,a3,n0,n1,n2,n3,vertexID);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,n0,n1,n2,n3,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_h(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID));
+ Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_h(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID));
+ if (Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_hn(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; Vec3fa n0,dn0,n1,dn1; geom->gather_hermite(p0,t0,n0,dn0,p1,t1,n1,dn1,geom->curve(primID));
+ Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,n0,dn0,n1,dn1,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_hn(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; Vec3fa n0,dn0,n1,dn1; geom->gather_hermite(p0,t0,n0,dn0,p1,t1,n1,dn1,geom->curve(primID));
+ if (Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,n0,dn0,n1,dn1,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+ };
+
+ template<int M, int K>
+ struct CurveNiIntersectorK
+ {
+ typedef CurveNi<M> Primitive;
+ typedef Vec3vf<M> Vec3vfM;
+ typedef LinearSpace3<Vec3vfM>LinearSpace3vfM;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline vbool<M> intersect(RayK<K>& ray, const size_t k, const Primitive& prim, vfloat<M>& tNear_o)
+ {
+ const size_t N = prim.N;
+ const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N));
+ const Vec3fa offset = Vec3fa(offset_scale);
+ const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale));
+
+ const Vec3fa ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]);
+ const Vec3fa ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
+ const Vec3fa org1 = (ray_org-offset)*scale;
+ const Vec3fa dir1 = ray_dir*scale;
+
+ const LinearSpace3vfM space(vfloat<M>::load(prim.bounds_vx_x(N)), vfloat<M>::load(prim.bounds_vx_y(N)), vfloat<M>::load(prim.bounds_vx_z(N)),
+ vfloat<M>::load(prim.bounds_vy_x(N)), vfloat<M>::load(prim.bounds_vy_y(N)), vfloat<M>::load(prim.bounds_vy_z(N)),
+ vfloat<M>::load(prim.bounds_vz_x(N)), vfloat<M>::load(prim.bounds_vz_y(N)), vfloat<M>::load(prim.bounds_vz_z(N)));
+
+ const Vec3vfM dir2 = xfmVector(space,Vec3vfM(dir1));
+ const Vec3vfM org2 = xfmPoint (space,Vec3vfM(org1));
+ const Vec3vfM rcp_dir2 = rcp_safe(dir2);
+
+ const vfloat<M> t_lower_x = (vfloat<M>::load(prim.bounds_vx_lower(N))-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_upper_x = (vfloat<M>::load(prim.bounds_vx_upper(N))-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_lower_y = (vfloat<M>::load(prim.bounds_vy_lower(N))-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_upper_y = (vfloat<M>::load(prim.bounds_vy_upper(N))-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_lower_z = (vfloat<M>::load(prim.bounds_vz_lower(N))-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+ const vfloat<M> t_upper_z = (vfloat<M>::load(prim.bounds_vz_upper(N))-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+
+ const vfloat<M> round_up (1.0f+3.0f*float(ulp));
+ const vfloat<M> round_down(1.0f-3.0f*float(ulp));
+ const vfloat<M> tNear = round_down*max(mini(t_lower_x,t_upper_x),mini(t_lower_y,t_upper_y),mini(t_lower_z,t_upper_z),vfloat<M>(ray.tnear()[k]));
+ const vfloat<M> tFar = round_up *min(maxi(t_lower_x,t_upper_x),maxi(t_lower_y,t_upper_y),maxi(t_lower_z,t_upper_z),vfloat<M>(ray.tfar[k]));
+ tNear_o = tNear;
+ return (vint<M>(step) < vint<M>(prim.N)) & (tNear <= tFar);
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID));
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID));
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_n(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+
+ unsigned int vertexID = geom->curve(primID);
+ Vec3ff a0,a1,a2,a3; Vec3fa n0,n1,n2,n3; geom->gather(a0,a1,a2,a3,n0,n1,n2,n3,vertexID);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,n0,n1,n2,n3,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_n(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+
+ unsigned int vertexID = geom->curve(primID);
+ Vec3ff a0,a1,a2,a3; Vec3fa n0,n1,n2,n3; geom->gather(a0,a1,a2,a3,n0,n1,n2,n3,vertexID);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ const unsigned int primID1 = prim.primID(N)[i1];
+ geom->prefetchL1_vertices(geom->curve(primID1));
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ const unsigned int primID2 = prim.primID(N)[i2];
+ geom->prefetchL2_vertices(geom->curve(primID2));
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,n0,n1,n2,n3,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_h(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID));
+ Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_h(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID));
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_hn(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; Vec3fa n0,dn0,n1,dn1; geom->gather_hermite(p0,t0,n0,dn0,p1,t1,n1,dn1,geom->curve(primID));
+ Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,n0,dn0,n1,dn1,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_hn(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; Vec3fa n0,dn0,n1,dn1; geom->gather_hermite(p0,t0,n0,dn0,p1,t1,n1,dn1,geom->curve(primID));
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,n0,dn0,n1,dn1,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/curveNi_mb.h b/thirdparty/embree/kernels/geometry/curveNi_mb.h
new file mode 100644
index 0000000000..5d972b43a0
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curveNi_mb.h
@@ -0,0 +1,278 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ template<int M>
+ struct CurveNiMB
+ {
+ struct Type : public PrimitiveType {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored primitives */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+M-1)/M; }
+
+ static __forceinline size_t bytes(size_t N)
+ {
+ const size_t f = N/M, r = N%M;
+ static_assert(sizeof(CurveNiMB) == 6+37*M+24, "internal data layout issue");
+ return f*sizeof(CurveNiMB) + (r!=0)*(6+37*r+24);
+ }
+
+ public:
+
+ /*! Default constructor. */
+ __forceinline CurveNiMB () {}
+
+ /*! fill curve from curve list */
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& begin, size_t _end, Scene* scene, const BBox1f time_range)
+ {
+ size_t end = min(begin+M,_end);
+ N = (unsigned char)(end-begin);
+ const unsigned int geomID0 = prims[begin].geomID();
+ this->geomID(N) = geomID0;
+ ty = (unsigned char) scene->get(geomID0)->getType();
+
+ /* encode all primitives */
+ LBBox3fa lbounds = empty;
+ for (size_t i=0; i<N; i++)
+ {
+ const PrimRefMB& prim = prims[begin+i];
+ const unsigned int geomID = prim.geomID(); assert(geomID == geomID0);
+ const unsigned int primID = prim.primID();
+ lbounds.extend(scene->get(geomID)->vlinearBounds(primID,time_range));
+ }
+ BBox3fa bounds = lbounds.bounds();
+
+ /* calculate offset and scale */
+ Vec3fa loffset = bounds.lower;
+ float lscale = reduce_min(256.0f/(bounds.size()*sqrt(3.0f)));
+ if (bounds.size() == Vec3fa(zero)) lscale = 0.0f;
+ *this->offset(N) = loffset;
+ *this->scale(N) = lscale;
+ this->time_offset(N) = time_range.lower;
+ this->time_scale(N) = 1.0f/time_range.size();
+
+ /* encode all primitives */
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRefMB& prim = prims[begin];
+ const unsigned int geomID = prim.geomID();
+ const unsigned int primID = prim.primID();
+ const LinearSpace3fa space2 = scene->get(geomID)->computeAlignedSpaceMB(primID,time_range);
+
+ const LinearSpace3fa space3(trunc(126.0f*space2.vx),trunc(126.0f*space2.vy),trunc(126.0f*space2.vz));
+ const LBBox3fa bounds = scene->get(geomID)->vlinearBounds(loffset,lscale,max(length(space3.vx),length(space3.vy),length(space3.vz)),space3.transposed(),primID,time_range);
+
+ // NOTE: this weird (char) (short) cast works around VS2015 Win32 compiler bug
+ bounds_vx_x(N)[i] = (char) (short) space3.vx.x;
+ bounds_vx_y(N)[i] = (char) (short) space3.vx.y;
+ bounds_vx_z(N)[i] = (char) (short) space3.vx.z;
+ bounds_vx_lower0(N)[i] = (short) clamp(floor(bounds.bounds0.lower.x),-32767.0f,32767.0f);
+ bounds_vx_upper0(N)[i] = (short) clamp(ceil (bounds.bounds0.upper.x),-32767.0f,32767.0f);
+ bounds_vx_lower1(N)[i] = (short) clamp(floor(bounds.bounds1.lower.x),-32767.0f,32767.0f);
+ bounds_vx_upper1(N)[i] = (short) clamp(ceil (bounds.bounds1.upper.x),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds0.lower.x) && floor(bounds.bounds0.lower.x) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds0.upper.x) && ceil (bounds.bounds0.upper.x) <= 32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds1.lower.x) && floor(bounds.bounds1.lower.x) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds1.upper.x) && ceil (bounds.bounds1.upper.x) <= 32767.0f);
+
+ bounds_vy_x(N)[i] = (char) (short) space3.vy.x;
+ bounds_vy_y(N)[i] = (char) (short) space3.vy.y;
+ bounds_vy_z(N)[i] = (char) (short) space3.vy.z;
+ bounds_vy_lower0(N)[i] = (short) clamp(floor(bounds.bounds0.lower.y),-32767.0f,32767.0f);
+ bounds_vy_upper0(N)[i] = (short) clamp(ceil (bounds.bounds0.upper.y),-32767.0f,32767.0f);
+ bounds_vy_lower1(N)[i] = (short) clamp(floor(bounds.bounds1.lower.y),-32767.0f,32767.0f);
+ bounds_vy_upper1(N)[i] = (short) clamp(ceil (bounds.bounds1.upper.y),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds0.lower.y) && floor(bounds.bounds0.lower.y) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds0.upper.y) && ceil (bounds.bounds0.upper.y) <= 32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds1.lower.y) && floor(bounds.bounds1.lower.y) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds1.upper.y) && ceil (bounds.bounds1.upper.y) <= 32767.0f);
+
+ bounds_vz_x(N)[i] = (char) (short) space3.vz.x;
+ bounds_vz_y(N)[i] = (char) (short) space3.vz.y;
+ bounds_vz_z(N)[i] = (char) (short) space3.vz.z;
+ bounds_vz_lower0(N)[i] = (short) clamp(floor(bounds.bounds0.lower.z),-32767.0f,32767.0f);
+ bounds_vz_upper0(N)[i] = (short) clamp(ceil (bounds.bounds0.upper.z),-32767.0f,32767.0f);
+ bounds_vz_lower1(N)[i] = (short) clamp(floor(bounds.bounds1.lower.z),-32767.0f,32767.0f);
+ bounds_vz_upper1(N)[i] = (short) clamp(ceil (bounds.bounds1.upper.z),-32767.0f,32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds0.lower.z) && floor(bounds.bounds0.lower.z) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds0.upper.z) && ceil (bounds.bounds0.upper.z) <= 32767.0f);
+ assert(-32767.0f <= floor(bounds.bounds1.lower.z) && floor(bounds.bounds1.lower.z) <= 32767.0f);
+ assert(-32767.0f <= ceil (bounds.bounds1.upper.z) && ceil (bounds.bounds1.upper.z) <= 32767.0f);
+
+ this->primID(N)[i] = primID;
+ }
+
+ return lbounds;
+ }
+
+ template<typename BVH, typename SetMB, typename Allocator>
+ __forceinline static typename BVH::NodeRecordMB4D createLeafMB(BVH* bvh, const SetMB& prims, const Allocator& alloc)
+ {
+ size_t start = prims.begin();
+ size_t end = prims.end();
+ size_t items = CurveNiMB::blocks(prims.size());
+ size_t numbytes = CurveNiMB::bytes(prims.size());
+ CurveNiMB* accel = (CurveNiMB*) alloc.malloc1(numbytes,BVH::byteAlignment);
+ const typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel,items);
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<items; i++)
+ bounds.extend(accel[i].fillMB(prims.prims->data(),start,end,bvh->scene,prims.time_range));
+
+ return typename BVH::NodeRecordMB4D(node,bounds,prims.time_range);
+ };
+
+
+ public:
+
+ // 27.6 - 46 bytes per primitive
+ unsigned char ty;
+ unsigned char N;
+ unsigned char data[4+37*M+24];
+
+ /*
+ struct Layout
+ {
+ unsigned int geomID;
+ unsigned int primID[N];
+
+ char bounds_vx_x[N];
+ char bounds_vx_y[N];
+ char bounds_vx_z[N];
+ short bounds_vx_lower0[N];
+ short bounds_vx_upper0[N];
+ short bounds_vx_lower1[N];
+ short bounds_vx_upper1[N];
+
+ char bounds_vy_x[N];
+ char bounds_vy_y[N];
+ char bounds_vy_z[N];
+ short bounds_vy_lower0[N];
+ short bounds_vy_upper0[N];
+ short bounds_vy_lower1[N];
+ short bounds_vy_upper1[N];
+
+ char bounds_vz_x[N];
+ char bounds_vz_y[N];
+ char bounds_vz_z[N];
+ short bounds_vz_lower0[N];
+ short bounds_vz_upper0[N];
+ short bounds_vz_lower1[N];
+ short bounds_vz_upper1[N];
+
+ Vec3f offset;
+ float scale;
+
+ float time_offset;
+ float time_scale;
+ };
+ */
+
+ __forceinline unsigned int& geomID(size_t N) { return *(unsigned int*)((char*)this+2); }
+ __forceinline const unsigned int& geomID(size_t N) const { return *(unsigned int*)((char*)this+2); }
+
+ __forceinline unsigned int* primID(size_t N) { return (unsigned int*)((char*)this+6); }
+ __forceinline const unsigned int* primID(size_t N) const { return (unsigned int*)((char*)this+6); }
+
+ __forceinline char* bounds_vx_x(size_t N) { return (char*)((char*)this+6+4*N); }
+ __forceinline const char* bounds_vx_x(size_t N) const { return (char*)((char*)this+6+4*N); }
+
+ __forceinline char* bounds_vx_y(size_t N) { return (char*)((char*)this+6+5*N); }
+ __forceinline const char* bounds_vx_y(size_t N) const { return (char*)((char*)this+6+5*N); }
+
+ __forceinline char* bounds_vx_z(size_t N) { return (char*)((char*)this+6+6*N); }
+ __forceinline const char* bounds_vx_z(size_t N) const { return (char*)((char*)this+6+6*N); }
+
+ __forceinline short* bounds_vx_lower0(size_t N) { return (short*)((char*)this+6+7*N); }
+ __forceinline const short* bounds_vx_lower0(size_t N) const { return (short*)((char*)this+6+7*N); }
+
+ __forceinline short* bounds_vx_upper0(size_t N) { return (short*)((char*)this+6+9*N); }
+ __forceinline const short* bounds_vx_upper0(size_t N) const { return (short*)((char*)this+6+9*N); }
+
+ __forceinline short* bounds_vx_lower1(size_t N) { return (short*)((char*)this+6+11*N); }
+ __forceinline const short* bounds_vx_lower1(size_t N) const { return (short*)((char*)this+6+11*N); }
+
+ __forceinline short* bounds_vx_upper1(size_t N) { return (short*)((char*)this+6+13*N); }
+ __forceinline const short* bounds_vx_upper1(size_t N) const { return (short*)((char*)this+6+13*N); }
+
+ __forceinline char* bounds_vy_x(size_t N) { return (char*)((char*)this+6+15*N); }
+ __forceinline const char* bounds_vy_x(size_t N) const { return (char*)((char*)this+6+15*N); }
+
+ __forceinline char* bounds_vy_y(size_t N) { return (char*)((char*)this+6+16*N); }
+ __forceinline const char* bounds_vy_y(size_t N) const { return (char*)((char*)this+6+16*N); }
+
+ __forceinline char* bounds_vy_z(size_t N) { return (char*)((char*)this+6+17*N); }
+ __forceinline const char* bounds_vy_z(size_t N) const { return (char*)((char*)this+6+17*N); }
+
+ __forceinline short* bounds_vy_lower0(size_t N) { return (short*)((char*)this+6+18*N); }
+ __forceinline const short* bounds_vy_lower0(size_t N) const { return (short*)((char*)this+6+18*N); }
+
+ __forceinline short* bounds_vy_upper0(size_t N) { return (short*)((char*)this+6+20*N); }
+ __forceinline const short* bounds_vy_upper0(size_t N) const { return (short*)((char*)this+6+20*N); }
+
+ __forceinline short* bounds_vy_lower1(size_t N) { return (short*)((char*)this+6+22*N); }
+ __forceinline const short* bounds_vy_lower1(size_t N) const { return (short*)((char*)this+6+22*N); }
+
+ __forceinline short* bounds_vy_upper1(size_t N) { return (short*)((char*)this+6+24*N); }
+ __forceinline const short* bounds_vy_upper1(size_t N) const { return (short*)((char*)this+6+24*N); }
+
+ __forceinline char* bounds_vz_x(size_t N) { return (char*)((char*)this+6+26*N); }
+ __forceinline const char* bounds_vz_x(size_t N) const { return (char*)((char*)this+6+26*N); }
+
+ __forceinline char* bounds_vz_y(size_t N) { return (char*)((char*)this+6+27*N); }
+ __forceinline const char* bounds_vz_y(size_t N) const { return (char*)((char*)this+6+27*N); }
+
+ __forceinline char* bounds_vz_z(size_t N) { return (char*)((char*)this+6+28*N); }
+ __forceinline const char* bounds_vz_z(size_t N) const { return (char*)((char*)this+6+28*N); }
+
+ __forceinline short* bounds_vz_lower0(size_t N) { return (short*)((char*)this+6+29*N); }
+ __forceinline const short* bounds_vz_lower0(size_t N) const { return (short*)((char*)this+6+29*N); }
+
+ __forceinline short* bounds_vz_upper0(size_t N) { return (short*)((char*)this+6+31*N); }
+ __forceinline const short* bounds_vz_upper0(size_t N) const { return (short*)((char*)this+6+31*N); }
+
+ __forceinline short* bounds_vz_lower1(size_t N) { return (short*)((char*)this+6+33*N); }
+ __forceinline const short* bounds_vz_lower1(size_t N) const { return (short*)((char*)this+6+33*N); }
+
+ __forceinline short* bounds_vz_upper1(size_t N) { return (short*)((char*)this+6+35*N); }
+ __forceinline const short* bounds_vz_upper1(size_t N) const { return (short*)((char*)this+6+35*N); }
+
+ __forceinline Vec3f* offset(size_t N) { return (Vec3f*)((char*)this+6+37*N); }
+ __forceinline const Vec3f* offset(size_t N) const { return (Vec3f*)((char*)this+6+37*N); }
+
+ __forceinline float* scale(size_t N) { return (float*)((char*)this+6+37*N+12); }
+ __forceinline const float* scale(size_t N) const { return (float*)((char*)this+6+37*N+12); }
+
+ __forceinline float& time_offset(size_t N) { return *(float*)((char*)this+6+37*N+16); }
+ __forceinline const float& time_offset(size_t N) const { return *(float*)((char*)this+6+37*N+16); }
+
+ __forceinline float& time_scale(size_t N) { return *(float*)((char*)this+6+37*N+20); }
+ __forceinline const float& time_scale(size_t N) const { return *(float*)((char*)this+6+37*N+20); }
+
+ __forceinline char* end(size_t N) { return (char*)this+6+37*N+24; }
+ __forceinline const char* end(size_t N) const { return (char*)this+6+37*N+24; }
+ };
+
+ template<int M>
+ typename CurveNiMB<M>::Type CurveNiMB<M>::type;
+
+ typedef CurveNiMB<4> Curve4iMB;
+ typedef CurveNiMB<8> Curve8iMB;
+}
diff --git a/thirdparty/embree/kernels/geometry/curveNi_mb_intersector.h b/thirdparty/embree/kernels/geometry/curveNi_mb_intersector.h
new file mode 100644
index 0000000000..bab796b33b
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curveNi_mb_intersector.h
@@ -0,0 +1,516 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curveNi_mb.h"
+#include "../subdiv/linear_bezier_patch.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct CurveNiMBIntersector1
+ {
+ typedef CurveNiMB<M> Primitive;
+ typedef Vec3vf<M> Vec3vfM;
+ typedef LinearSpace3<Vec3vfM>LinearSpace3vfM;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline vbool<M> intersect(Ray& ray, const Primitive& prim, vfloat<M>& tNear_o)
+ {
+ const size_t N = prim.N;
+ const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N));
+ const Vec3fa offset = Vec3fa(offset_scale);
+ const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale));
+ const Vec3fa org1 = (ray.org-offset)*scale;
+ const Vec3fa dir1 = ray.dir*scale;
+
+ const LinearSpace3vfM space(vfloat<M>::load(prim.bounds_vx_x(N)), vfloat<M>::load(prim.bounds_vx_y(N)), vfloat<M>::load(prim.bounds_vx_z(N)),
+ vfloat<M>::load(prim.bounds_vy_x(N)), vfloat<M>::load(prim.bounds_vy_y(N)), vfloat<M>::load(prim.bounds_vy_z(N)),
+ vfloat<M>::load(prim.bounds_vz_x(N)), vfloat<M>::load(prim.bounds_vz_y(N)), vfloat<M>::load(prim.bounds_vz_z(N)));
+
+ const Vec3vfM dir2 = xfmVector(space,Vec3vfM(dir1));
+ const Vec3vfM org2 = xfmPoint (space,Vec3vfM(org1));
+ const Vec3vfM rcp_dir2 = rcp_safe(dir2);
+
+ const vfloat<M> ltime = (ray.time()-prim.time_offset(N))*prim.time_scale(N);
+ const vfloat<M> vx_lower0 = vfloat<M>::load(prim.bounds_vx_lower0(N));
+ const vfloat<M> vx_lower1 = vfloat<M>::load(prim.bounds_vx_lower1(N));
+ const vfloat<M> vx_lower = madd(ltime,vx_lower1-vx_lower0,vx_lower0);
+ const vfloat<M> vx_upper0 = vfloat<M>::load(prim.bounds_vx_upper0(N));
+ const vfloat<M> vx_upper1 = vfloat<M>::load(prim.bounds_vx_upper1(N));
+ const vfloat<M> vx_upper = madd(ltime,vx_upper1-vx_upper0,vx_upper0);
+
+ const vfloat<M> vy_lower0 = vfloat<M>::load(prim.bounds_vy_lower0(N));
+ const vfloat<M> vy_lower1 = vfloat<M>::load(prim.bounds_vy_lower1(N));
+ const vfloat<M> vy_lower = madd(ltime,vy_lower1-vy_lower0,vy_lower0);
+ const vfloat<M> vy_upper0 = vfloat<M>::load(prim.bounds_vy_upper0(N));
+ const vfloat<M> vy_upper1 = vfloat<M>::load(prim.bounds_vy_upper1(N));
+ const vfloat<M> vy_upper = madd(ltime,vy_upper1-vy_upper0,vy_upper0);
+
+ const vfloat<M> vz_lower0 = vfloat<M>::load(prim.bounds_vz_lower0(N));
+ const vfloat<M> vz_lower1 = vfloat<M>::load(prim.bounds_vz_lower1(N));
+ const vfloat<M> vz_lower = madd(ltime,vz_lower1-vz_lower0,vz_lower0);
+ const vfloat<M> vz_upper0 = vfloat<M>::load(prim.bounds_vz_upper0(N));
+ const vfloat<M> vz_upper1 = vfloat<M>::load(prim.bounds_vz_upper1(N));
+ const vfloat<M> vz_upper = madd(ltime,vz_upper1-vz_upper0,vz_upper0);
+
+ const vfloat<M> t_lower_x = (vx_lower-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_upper_x = (vx_upper-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_lower_y = (vy_lower-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_upper_y = (vy_upper-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_lower_z = (vz_lower-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+ const vfloat<M> t_upper_z = (vz_upper-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+
+ const vfloat<M> round_up (1.0f+3.0f*float(ulp));
+ const vfloat<M> round_down(1.0f-3.0f*float(ulp));
+ const vfloat<M> tNear = round_down*max(mini(t_lower_x,t_upper_x),mini(t_lower_y,t_upper_y),mini(t_lower_z,t_upper_z),vfloat<M>(ray.tnear()));
+ const vfloat<M> tFar = round_up *min(maxi(t_lower_x,t_upper_x),maxi(t_lower_y,t_upper_y),maxi(t_lower_z,t_upper_z),vfloat<M>(ray.tfar));
+ tNear_o = tNear;
+ return (vint<M>(step) < vint<M>(prim.N)) & (tNear <= tFar);
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID),ray.time());
+
+ Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID),ray.time());
+
+ if (Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_n(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray.org, primID,ray.time());
+ Intersector().intersect(pre,ray,context,geom,primID,curve,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_n(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray.org, primID,ray.time());
+
+ if (Intersector().intersect(pre,ray,context,geom,primID,curve,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_h(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID),ray.time());
+ Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_h(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID),ray.time());
+ if (Intersector().intersect(pre,ray,context,geom,primID,p0,t0,p1,t1,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_hn(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedHermiteCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray.org, primID,ray.time());
+ Intersector().intersect(pre,ray,context,geom,primID,curve,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_hn(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedHermiteCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray.org, primID,ray.time());
+ if (Intersector().intersect(pre,ray,context,geom,primID,curve,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+ };
+
+ template<int M, int K>
+ struct CurveNiMBIntersectorK
+ {
+ typedef CurveNiMB<M> Primitive;
+ typedef Vec3vf<M> Vec3vfM;
+ typedef LinearSpace3<Vec3vfM>LinearSpace3vfM;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline vbool<M> intersect(RayK<K>& ray, const size_t k, const Primitive& prim, vfloat<M>& tNear_o)
+ {
+ const size_t N = prim.N;
+ const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N));
+ const Vec3fa offset = Vec3fa(offset_scale);
+ const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale));
+
+ const Vec3fa ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]);
+ const Vec3fa ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
+ const Vec3fa org1 = (ray_org-offset)*scale;
+ const Vec3fa dir1 = ray_dir*scale;
+
+ const LinearSpace3vfM space(vfloat<M>::load(prim.bounds_vx_x(N)), vfloat<M>::load(prim.bounds_vx_y(N)), vfloat<M>::load(prim.bounds_vx_z(N)),
+ vfloat<M>::load(prim.bounds_vy_x(N)), vfloat<M>::load(prim.bounds_vy_y(N)), vfloat<M>::load(prim.bounds_vy_z(N)),
+ vfloat<M>::load(prim.bounds_vz_x(N)), vfloat<M>::load(prim.bounds_vz_y(N)), vfloat<M>::load(prim.bounds_vz_z(N)));
+
+ const Vec3vfM dir2 = xfmVector(space,Vec3vfM(dir1));
+ const Vec3vfM org2 = xfmPoint (space,Vec3vfM(org1));
+ const Vec3vfM rcp_dir2 = rcp_safe(dir2);
+
+ const vfloat<M> ltime = (ray.time()[k]-prim.time_offset(N))*prim.time_scale(N);
+ const vfloat<M> vx_lower0 = vfloat<M>::load(prim.bounds_vx_lower0(N));
+ const vfloat<M> vx_lower1 = vfloat<M>::load(prim.bounds_vx_lower1(N));
+ const vfloat<M> vx_lower = madd(ltime,vx_lower1-vx_lower0,vx_lower0);
+ const vfloat<M> vx_upper0 = vfloat<M>::load(prim.bounds_vx_upper0(N));
+ const vfloat<M> vx_upper1 = vfloat<M>::load(prim.bounds_vx_upper1(N));
+ const vfloat<M> vx_upper = madd(ltime,vx_upper1-vx_upper0,vx_upper0);
+
+ const vfloat<M> vy_lower0 = vfloat<M>::load(prim.bounds_vy_lower0(N));
+ const vfloat<M> vy_lower1 = vfloat<M>::load(prim.bounds_vy_lower1(N));
+ const vfloat<M> vy_lower = madd(ltime,vy_lower1-vy_lower0,vy_lower0);
+ const vfloat<M> vy_upper0 = vfloat<M>::load(prim.bounds_vy_upper0(N));
+ const vfloat<M> vy_upper1 = vfloat<M>::load(prim.bounds_vy_upper1(N));
+ const vfloat<M> vy_upper = madd(ltime,vy_upper1-vy_upper0,vy_upper0);
+
+ const vfloat<M> vz_lower0 = vfloat<M>::load(prim.bounds_vz_lower0(N));
+ const vfloat<M> vz_lower1 = vfloat<M>::load(prim.bounds_vz_lower1(N));
+ const vfloat<M> vz_lower = madd(ltime,vz_lower1-vz_lower0,vz_lower0);
+ const vfloat<M> vz_upper0 = vfloat<M>::load(prim.bounds_vz_upper0(N));
+ const vfloat<M> vz_upper1 = vfloat<M>::load(prim.bounds_vz_upper1(N));
+ const vfloat<M> vz_upper = madd(ltime,vz_upper1-vz_upper0,vz_upper0);
+
+ const vfloat<M> t_lower_x = (vx_lower-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_upper_x = (vx_upper-vfloat<M>(org2.x))*vfloat<M>(rcp_dir2.x);
+ const vfloat<M> t_lower_y = (vy_lower-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_upper_y = (vy_upper-vfloat<M>(org2.y))*vfloat<M>(rcp_dir2.y);
+ const vfloat<M> t_lower_z = (vz_lower-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+ const vfloat<M> t_upper_z = (vz_upper-vfloat<M>(org2.z))*vfloat<M>(rcp_dir2.z);
+
+ const vfloat<M> round_up (1.0f+3.0f*float(ulp));
+ const vfloat<M> round_down(1.0f-3.0f*float(ulp));
+ const vfloat<M> tNear = round_down*max(mini(t_lower_x,t_upper_x),mini(t_lower_y,t_upper_y),mini(t_lower_z,t_upper_z),vfloat<M>(ray.tnear()[k]));
+ const vfloat<M> tFar = round_up *min(maxi(t_lower_x,t_upper_x),maxi(t_lower_y,t_upper_y),maxi(t_lower_z,t_upper_z),vfloat<M>(ray.tfar[k]));
+ tNear_o = tNear;
+ return (vint<M>(step) < vint<M>(prim.N)) & (tNear <= tFar);
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID),ray.time()[k]);
+
+ Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff a0,a1,a2,a3; geom->gather(a0,a1,a2,a3,geom->curve(primID),ray.time()[k]);
+
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_n(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const Vec3fa ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,ray.time()[k]);
+ Intersector().intersect(pre,ray,k,context,geom,primID,curve,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_n(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const Vec3fa ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,ray.time()[k]);
+
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,curve,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_h(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID),ray.time()[k]);
+ Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_h(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ Vec3ff p0,t0,p1,t1; geom->gather_hermite(p0,t0,p1,t1,geom->curve(primID),ray.time()[k]);
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,p0,t0,p1,t1,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_hn(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const Vec3fa ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedHermiteCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,ray.time()[k]);
+ Intersector().intersect(pre,ray,k,context,geom,primID,curve,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_hn(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = context->scene->get<CurveGeometry>(geomID);
+ const Vec3fa ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const TensorLinearCubicBezierSurface3fa curve = geom->getNormalOrientedHermiteCurve<typename Intersector::SourceCurve3ff, typename Intersector::SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,ray.time()[k]);
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,curve,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/curveNv.h b/thirdparty/embree/kernels/geometry/curveNv.h
new file mode 100644
index 0000000000..e41a381706
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curveNv.h
@@ -0,0 +1,101 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curveNi.h"
+
+namespace embree
+{
+ template<int M>
+ struct CurveNv : public CurveNi<M>
+ {
+ using CurveNi<M>::N;
+
+ struct Type : public PrimitiveType {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored primitives */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+M-1)/M; }
+
+ static __forceinline size_t bytes(size_t N)
+ {
+ const size_t f = N/M, r = N%M;
+ static_assert(sizeof(CurveNv) == 22+25*M+4*16*M, "internal data layout issue");
+ return f*sizeof(CurveNv) + (r!=0)*(22 + 25*r + 4*16*r);
+ }
+
+ public:
+
+ /*! Default constructor. */
+ __forceinline CurveNv () {}
+
+ /*! fill curve from curve list */
+ __forceinline void fill(const PrimRef* prims, size_t& begin, size_t _end, Scene* scene)
+ {
+ size_t end = min(begin+M,_end);
+ size_t N = end-begin;
+
+ /* encode all primitives */
+ for (size_t i=0; i<N; i++)
+ {
+ const PrimRef& prim = prims[begin+i];
+ const unsigned int geomID = prim.geomID();
+ const unsigned int primID = prim.primID();
+ CurveGeometry* mesh = (CurveGeometry*) scene->get(geomID);
+ const unsigned vtxID = mesh->curve(primID);
+ Vec3fa::storeu(&this->vertices(i,N)[0],mesh->vertex(vtxID+0));
+ Vec3fa::storeu(&this->vertices(i,N)[1],mesh->vertex(vtxID+1));
+ Vec3fa::storeu(&this->vertices(i,N)[2],mesh->vertex(vtxID+2));
+ Vec3fa::storeu(&this->vertices(i,N)[3],mesh->vertex(vtxID+3));
+ }
+ }
+
+ template<typename BVH, typename Allocator>
+ __forceinline static typename BVH::NodeRef createLeaf (BVH* bvh, const PrimRef* prims, const range<size_t>& set, const Allocator& alloc)
+ {
+ if (set.size() == 0)
+ return BVH::emptyNode;
+
+ /* fall back to CurveNi for oriented curves */
+ unsigned int geomID = prims[set.begin()].geomID();
+ if (bvh->scene->get(geomID)->getCurveType() == Geometry::GTY_SUBTYPE_ORIENTED_CURVE) {
+ return CurveNi<M>::createLeaf(bvh,prims,set,alloc);
+ }
+ if (bvh->scene->get(geomID)->getCurveBasis() == Geometry::GTY_BASIS_HERMITE) {
+ return CurveNi<M>::createLeaf(bvh,prims,set,alloc);
+ }
+
+ size_t start = set.begin();
+ size_t items = CurveNv::blocks(set.size());
+ size_t numbytes = CurveNv::bytes(set.size());
+ CurveNv* accel = (CurveNv*) alloc.malloc1(numbytes,BVH::byteAlignment);
+ for (size_t i=0; i<items; i++) {
+ accel[i].CurveNv<M>::fill(prims,start,set.end(),bvh->scene);
+ accel[i].CurveNi<M>::fill(prims,start,set.end(),bvh->scene);
+ }
+ return bvh->encodeLeaf((char*)accel,items);
+ };
+
+ public:
+ unsigned char data[4*16*M];
+ __forceinline Vec3fa* vertices(size_t i, size_t N) { return (Vec3fa*)CurveNi<M>::end(N)+4*i; }
+ __forceinline const Vec3fa* vertices(size_t i, size_t N) const { return (Vec3fa*)CurveNi<M>::end(N)+4*i; }
+ };
+
+ template<int M>
+ typename CurveNv<M>::Type CurveNv<M>::type;
+
+ typedef CurveNv<4> Curve4v;
+ typedef CurveNv<8> Curve8v;
+}
diff --git a/thirdparty/embree/kernels/geometry/curveNv_intersector.h b/thirdparty/embree/kernels/geometry/curveNv_intersector.h
new file mode 100644
index 0000000000..2742725aec
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curveNv_intersector.h
@@ -0,0 +1,181 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "curveNv.h"
+#include "curveNi_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct CurveNvIntersector1 : public CurveNiIntersector1<M>
+ {
+ typedef CurveNv<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = CurveNiIntersector1<M>::intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = (CurveGeometry*) context->scene->get(geomID);
+ const Vec3ff a0 = Vec3ff::loadu(&prim.vertices(i,N)[0]);
+ const Vec3ff a1 = Vec3ff::loadu(&prim.vertices(i,N)[1]);
+ const Vec3ff a2 = Vec3ff::loadu(&prim.vertices(i,N)[2]);
+ const Vec3ff a3 = Vec3ff::loadu(&prim.vertices(i,N)[3]);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ prefetchL1(&prim.vertices(i1,N)[0]);
+ prefetchL1(&prim.vertices(i1,N)[4]);
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ prefetchL2(&prim.vertices(i2,N)[0]);
+ prefetchL2(&prim.vertices(i2,N)[4]);
+ }
+ }
+
+ Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = CurveNiIntersector1<M>::intersect(ray,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = (CurveGeometry*) context->scene->get(geomID);
+ const Vec3ff a0 = Vec3ff::loadu(&prim.vertices(i,N)[0]);
+ const Vec3ff a1 = Vec3ff::loadu(&prim.vertices(i,N)[1]);
+ const Vec3ff a2 = Vec3ff::loadu(&prim.vertices(i,N)[2]);
+ const Vec3ff a3 = Vec3ff::loadu(&prim.vertices(i,N)[3]);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ prefetchL1(&prim.vertices(i1,N)[0]);
+ prefetchL1(&prim.vertices(i1,N)[4]);
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ prefetchL2(&prim.vertices(i2,N)[0]);
+ prefetchL2(&prim.vertices(i2,N)[4]);
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,context,geom,primID,a0,a1,a2,a3,Epilog(ray,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar));
+ }
+ return false;
+ }
+ };
+
+ template<int M, int K>
+ struct CurveNvIntersectorK : public CurveNiIntersectorK<M,K>
+ {
+ typedef CurveNv<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = CurveNiIntersectorK<M,K>::intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(normal.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = (CurveGeometry*) context->scene->get(geomID);
+ const Vec3ff a0 = Vec3ff::loadu(&prim.vertices(i,N)[0]);
+ const Vec3ff a1 = Vec3ff::loadu(&prim.vertices(i,N)[1]);
+ const Vec3ff a2 = Vec3ff::loadu(&prim.vertices(i,N)[2]);
+ const Vec3ff a3 = Vec3ff::loadu(&prim.vertices(i,N)[3]);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ prefetchL1(&prim.vertices(i1,N)[0]);
+ prefetchL1(&prim.vertices(i1,N)[4]);
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ prefetchL2(&prim.vertices(i2,N)[0]);
+ prefetchL2(&prim.vertices(i2,N)[4]);
+ }
+ }
+
+ Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID));
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ }
+
+ template<typename Intersector, typename Epilog>
+ static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim)
+ {
+ vfloat<M> tNear;
+ vbool<M> valid = CurveNiIntersectorK<M,K>::intersect(ray,k,prim,tNear);
+
+ const size_t N = prim.N;
+ size_t mask = movemask(valid);
+ while (mask)
+ {
+ const size_t i = bscf(mask);
+ STAT3(shadow.trav_prims,1,1,1);
+ const unsigned int geomID = prim.geomID(N);
+ const unsigned int primID = prim.primID(N)[i];
+ const CurveGeometry* geom = (CurveGeometry*) context->scene->get(geomID);
+ const Vec3ff a0 = Vec3ff::loadu(&prim.vertices(i,N)[0]);
+ const Vec3ff a1 = Vec3ff::loadu(&prim.vertices(i,N)[1]);
+ const Vec3ff a2 = Vec3ff::loadu(&prim.vertices(i,N)[2]);
+ const Vec3ff a3 = Vec3ff::loadu(&prim.vertices(i,N)[3]);
+
+ size_t mask1 = mask;
+ const size_t i1 = bscf(mask1);
+ if (mask) {
+ prefetchL1(&prim.vertices(i1,N)[0]);
+ prefetchL1(&prim.vertices(i1,N)[4]);
+ if (mask1) {
+ const size_t i2 = bsf(mask1);
+ prefetchL2(&prim.vertices(i2,N)[0]);
+ prefetchL2(&prim.vertices(i2,N)[4]);
+ }
+ }
+
+ if (Intersector().intersect(pre,ray,k,context,geom,primID,a0,a1,a2,a3,Epilog(ray,k,context,geomID,primID)))
+ return true;
+
+ mask &= movemask(tNear <= vfloat<M>(ray.tfar[k]));
+ }
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/curve_intersector.h b/thirdparty/embree/kernels/geometry/curve_intersector.h
new file mode 100644
index 0000000000..1e8ac26125
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curve_intersector.h
@@ -0,0 +1,98 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "../subdiv/bezier_curve.h"
+#include "../common/primref.h"
+#include "bezier_hair_intersector.h"
+#include "bezier_ribbon_intersector.h"
+#include "bezier_curve_intersector.h"
+#include "oriented_curve_intersector.h"
+#include "../bvh/node_intersector1.h"
+
+// FIXME: this file seems replicate of curve_intersector_virtual.h
+
+namespace embree
+{
+ namespace isa
+ {
+ struct VirtualCurveIntersector1
+ {
+ typedef unsigned char Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ leafIntersector.intersect<1>(&pre,&ray,context,prim);
+ }
+
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ return leafIntersector.occluded<1>(&pre,&ray,context,prim);
+ }
+ };
+
+ template<int K>
+ struct VirtualCurveIntersectorK
+ {
+ typedef unsigned char Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ size_t mask = movemask(valid_i);
+ while (mask) leafIntersector.intersect<K>(&pre,&ray,bscf(mask),context,prim);
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ vbool<K> valid_o = false;
+ size_t mask = movemask(valid_i);
+ while (mask) {
+ size_t k = bscf(mask);
+ if (leafIntersector.occluded<K>(&pre,&ray,k,context,prim))
+ set(valid_o, k);
+ }
+ return valid_o;
+ }
+
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ leafIntersector.intersect<K>(&pre,&ray,k,context,prim);
+ }
+
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurvePrimitive::Intersectors& leafIntersector = ((VirtualCurvePrimitive*) This->leafIntersector)->vtbl[ty];
+ return leafIntersector.occluded<K>(&pre,&ray,k,context,prim);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_distance.h b/thirdparty/embree/kernels/geometry/curve_intersector_distance.h
new file mode 100644
index 0000000000..748a9511a5
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curve_intersector_distance.h
@@ -0,0 +1,129 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename NativeCurve3fa, int M>
+ struct DistanceCurveHit
+ {
+ __forceinline DistanceCurveHit() {}
+
+ __forceinline DistanceCurveHit(const vbool<M>& valid, const vfloat<M>& U, const vfloat<M>& V, const vfloat<M>& T, const int i, const int N,
+ const NativeCurve3fa& curve3D)
+ : U(U), V(V), T(T), i(i), N(N), curve3D(curve3D), valid(valid) {}
+
+ __forceinline void finalize()
+ {
+ vu = (vfloat<M>(step)+U+vfloat<M>(float(i)))*(1.0f/float(N));
+ vv = V;
+ vt = T;
+ }
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const {
+ return curve3D.eval_du(vu[i]);
+ }
+
+ public:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> T;
+ int i, N;
+ NativeCurve3fa curve3D;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ };
+
+ template<typename NativeCurve3fa>
+ struct DistanceCurve1Intersector1
+ {
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculations1& pre,Ray& ray,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& v3,
+ const Epilog& epilog)
+ {
+ const int N = geom->tessellationRate;
+
+ /* transform control points into ray space */
+ const NativeCurve3fa curve3Di(v0,v1,v2,v3);
+ const NativeCurve3fa curve3D = enlargeRadiusToMinWidth(context,geom,ray.org,curve3Di);
+ const NativeCurve3fa curve2D = curve3D.xfm_pr(pre.ray_space,ray.org);
+
+ /* evaluate the bezier curve */
+ vboolx valid = vfloatx(step) < vfloatx(float(N));
+ const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(0,N);
+ const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(0,N);
+
+ /* approximative intersection with cone */
+ const Vec4vfx v = p1-p0;
+ const Vec4vfx w = -p0;
+ const vfloatx d0 = madd(w.x,v.x,w.y*v.y);
+ const vfloatx d1 = madd(v.x,v.x,v.y*v.y);
+ const vfloatx u = clamp(d0*rcp(d1),vfloatx(zero),vfloatx(one));
+ const Vec4vfx p = madd(u,v,p0);
+ const vfloatx t = p.z*pre.depth_scale;
+ const vfloatx d2 = madd(p.x,p.x,p.y*p.y);
+ const vfloatx r = p.w;
+ const vfloatx r2 = r*r;
+ valid &= (d2 <= r2) & (vfloatx(ray.tnear()) <= t) & (t <= vfloatx(ray.tfar));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= t > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*pre.depth_scale; // ignore self intersections
+
+ /* update hit information */
+ bool ishit = false;
+ if (unlikely(any(valid))) {
+ DistanceCurveHit<NativeCurve3fa,VSIZEX> hit(valid,u,0.0f,t,0,N,curve3D);
+ ishit = ishit | epilog(valid,hit);
+ }
+
+ if (unlikely(VSIZEX < N))
+ {
+ /* process SIMD-size many segments per iteration */
+ for (int i=VSIZEX; i<N; i+=VSIZEX)
+ {
+ /* evaluate the bezier curve */
+ vboolx valid = vintx(i)+vintx(step) < vintx(N);
+ const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(i,N);
+ const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(i,N);
+
+ /* approximative intersection with cone */
+ const Vec4vfx v = p1-p0;
+ const Vec4vfx w = -p0;
+ const vfloatx d0 = madd(w.x,v.x,w.y*v.y);
+ const vfloatx d1 = madd(v.x,v.x,v.y*v.y);
+ const vfloatx u = clamp(d0*rcp(d1),vfloatx(zero),vfloatx(one));
+ const Vec4vfx p = madd(u,v,p0);
+ const vfloatx t = p.z*pre.depth_scale;
+ const vfloatx d2 = madd(p.x,p.x,p.y*p.y);
+ const vfloatx r = p.w;
+ const vfloatx r2 = r*r;
+ valid &= (d2 <= r2) & (vfloatx(ray.tnear()) <= t) & (t <= vfloatx(ray.tfar));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= t > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*pre.depth_scale; // ignore self intersections
+
+ /* update hit information */
+ if (unlikely(any(valid))) {
+ DistanceCurveHit<NativeCurve3fa,VSIZEX> hit(valid,u,0.0f,t,i,N,curve3D);
+ ishit = ishit | epilog(valid,hit);
+ }
+ }
+ }
+ return ishit;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_oriented.h b/thirdparty/embree/kernels/geometry/curve_intersector_oriented.h
new file mode 100644
index 0000000000..3d8900c2aa
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curve_intersector_oriented.h
@@ -0,0 +1,417 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "curve_intersector_precalculations.h"
+#include "curve_intersector_sweep.h"
+#include "../subdiv/linear_bezier_patch.h"
+
+#define DBG(x)
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename Ray, typename Epilog>
+ struct TensorLinearCubicBezierSurfaceIntersector
+ {
+ const LinearSpace3fa& ray_space;
+ Ray& ray;
+ TensorLinearCubicBezierSurface3fa curve3d;
+ TensorLinearCubicBezierSurface2fa curve2d;
+ float eps;
+ const Epilog& epilog;
+ bool isHit;
+
+ __forceinline TensorLinearCubicBezierSurfaceIntersector (const LinearSpace3fa& ray_space, Ray& ray, const TensorLinearCubicBezierSurface3fa& curve3d, const Epilog& epilog)
+ : ray_space(ray_space), ray(ray), curve3d(curve3d), epilog(epilog), isHit(false)
+ {
+ const TensorLinearCubicBezierSurface3fa curve3dray = curve3d.xfm(ray_space,ray.org);
+ curve2d = TensorLinearCubicBezierSurface2fa(CubicBezierCurve2fa(curve3dray.L),CubicBezierCurve2fa(curve3dray.R));
+ const BBox2fa b2 = curve2d.bounds();
+ eps = 8.0f*float(ulp)*reduce_max(max(abs(b2.lower),abs(b2.upper)));
+ }
+
+ __forceinline Interval1f solve_linear(const float u0, const float u1, const float& p0, const float& p1)
+ {
+ if (p1 == p0) {
+ if (p0 == 0.0f) return Interval1f(u0,u1);
+ else return Interval1f(empty);
+ }
+ const float t = -p0/(p1-p0);
+ const float tt = lerp(u0,u1,t);
+ return Interval1f(tt);
+ }
+
+ __forceinline void solve_linear(const float u0, const float u1, const Interval1f& p0, const Interval1f& p1, Interval1f& u)
+ {
+ if (sign(p0.lower) != sign(p0.upper)) u.extend(u0);
+ if (sign(p0.lower) != sign(p1.lower)) u.extend(solve_linear(u0,u1,p0.lower,p1.lower));
+ if (sign(p0.upper) != sign(p1.upper)) u.extend(solve_linear(u0,u1,p0.upper,p1.upper));
+ if (sign(p1.lower) != sign(p1.upper)) u.extend(u1);
+ }
+
+ __forceinline Interval1f bezier_clipping(const CubicBezierCurve<Interval1f>& curve)
+ {
+ Interval1f u = empty;
+ solve_linear(0.0f/3.0f,1.0f/3.0f,curve.v0,curve.v1,u);
+ solve_linear(0.0f/3.0f,2.0f/3.0f,curve.v0,curve.v2,u);
+ solve_linear(0.0f/3.0f,3.0f/3.0f,curve.v0,curve.v3,u);
+ solve_linear(1.0f/3.0f,2.0f/3.0f,curve.v1,curve.v2,u);
+ solve_linear(1.0f/3.0f,3.0f/3.0f,curve.v1,curve.v3,u);
+ solve_linear(2.0f/3.0f,3.0f/3.0f,curve.v2,curve.v3,u);
+ return intersect(u,Interval1f(0.0f,1.0f));
+ }
+
+ __forceinline Interval1f bezier_clipping(const LinearBezierCurve<Interval1f>& curve)
+ {
+ Interval1f v = empty;
+ solve_linear(0.0f,1.0f,curve.v0,curve.v1,v);
+ return intersect(v,Interval1f(0.0f,1.0f));
+ }
+
+ __forceinline void solve_bezier_clipping(BBox1f cu, BBox1f cv, const TensorLinearCubicBezierSurface2fa& curve2)
+ {
+ BBox2fa bounds = curve2.bounds();
+ if (bounds.upper.x < 0.0f) return;
+ if (bounds.upper.y < 0.0f) return;
+ if (bounds.lower.x > 0.0f) return;
+ if (bounds.lower.y > 0.0f) return;
+
+ if (max(cu.size(),cv.size()) < 1E-4f)
+ {
+ const float u = cu.center();
+ const float v = cv.center();
+ TensorLinearCubicBezierSurface1f curve_z = curve3d.xfm(ray_space.row2(),ray.org);
+ const float t = curve_z.eval(u,v);
+ if (ray.tnear() <= t && t <= ray.tfar) {
+ const Vec3fa Ng = cross(curve3d.eval_du(u,v),curve3d.eval_dv(u,v));
+ BezierCurveHit hit(t,u,v,Ng);
+ isHit |= epilog(hit);
+ }
+ return;
+ }
+
+ const Vec2fa dv = curve2.axis_v();
+ const TensorLinearCubicBezierSurface1f curve1v = curve2.xfm(dv);
+ LinearBezierCurve<Interval1f> curve0v = curve1v.reduce_u();
+ if (!curve0v.hasRoot()) return;
+
+ const Interval1f v = bezier_clipping(curve0v);
+ if (isEmpty(v)) return;
+ TensorLinearCubicBezierSurface2fa curve2a = curve2.clip_v(v);
+ cv = BBox1f(lerp(cv.lower,cv.upper,v.lower),lerp(cv.lower,cv.upper,v.upper));
+
+ const Vec2fa du = curve2.axis_u();
+ const TensorLinearCubicBezierSurface1f curve1u = curve2a.xfm(du);
+ CubicBezierCurve<Interval1f> curve0u = curve1u.reduce_v();
+ int roots = curve0u.maxRoots();
+ if (roots == 0) return;
+
+ if (roots == 1)
+ {
+ const Interval1f u = bezier_clipping(curve0u);
+ if (isEmpty(u)) return;
+ TensorLinearCubicBezierSurface2fa curve2b = curve2a.clip_u(u);
+ cu = BBox1f(lerp(cu.lower,cu.upper,u.lower),lerp(cu.lower,cu.upper,u.upper));
+ solve_bezier_clipping(cu,cv,curve2b);
+ return;
+ }
+
+ TensorLinearCubicBezierSurface2fa curve2l, curve2r;
+ curve2a.split_u(curve2l,curve2r);
+ solve_bezier_clipping(BBox1f(cu.lower,cu.center()),cv,curve2l);
+ solve_bezier_clipping(BBox1f(cu.center(),cu.upper),cv,curve2r);
+ }
+
+ __forceinline bool solve_bezier_clipping()
+ {
+ solve_bezier_clipping(BBox1f(0.0f,1.0f),BBox1f(0.0f,1.0f),curve2d);
+ return isHit;
+ }
+
+ __forceinline void solve_newton_raphson(BBox1f cu, BBox1f cv)
+ {
+ Vec2fa uv(cu.center(),cv.center());
+ const Vec2fa dfdu = curve2d.eval_du(uv.x,uv.y);
+ const Vec2fa dfdv = curve2d.eval_dv(uv.x,uv.y);
+ const LinearSpace2fa rcp_J = rcp(LinearSpace2fa(dfdu,dfdv));
+ solve_newton_raphson_loop(cu,cv,uv,dfdu,dfdv,rcp_J);
+ }
+
+ __forceinline void solve_newton_raphson_loop(BBox1f cu, BBox1f cv, const Vec2fa& uv_in, const Vec2fa& dfdu, const Vec2fa& dfdv, const LinearSpace2fa& rcp_J)
+ {
+ Vec2fa uv = uv_in;
+
+ for (size_t i=0; i<200; i++)
+ {
+ const Vec2fa f = curve2d.eval(uv.x,uv.y);
+ const Vec2fa duv = rcp_J*f;
+ uv -= duv;
+
+ if (max(abs(f.x),abs(f.y)) < eps)
+ {
+ const float u = uv.x;
+ const float v = uv.y;
+ if (!(u >= 0.0f && u <= 1.0f)) return; // rejects NaNs
+ if (!(v >= 0.0f && v <= 1.0f)) return; // rejects NaNs
+ const TensorLinearCubicBezierSurface1f curve_z = curve3d.xfm(ray_space.row2(),ray.org);
+ const float t = curve_z.eval(u,v);
+ if (!(ray.tnear() <= t && t <= ray.tfar)) return; // rejects NaNs
+ const Vec3fa Ng = cross(curve3d.eval_du(u,v),curve3d.eval_dv(u,v));
+ BezierCurveHit hit(t,u,v,Ng);
+ isHit |= epilog(hit);
+ return;
+ }
+ }
+ }
+
+ __forceinline bool clip_v(BBox1f& cu, BBox1f& cv)
+ {
+ const Vec2fa dv = curve2d.eval_dv(cu.lower,cv.lower);
+ const TensorLinearCubicBezierSurface1f curve1v = curve2d.xfm(dv).clip(cu,cv);
+ LinearBezierCurve<Interval1f> curve0v = curve1v.reduce_u();
+ if (!curve0v.hasRoot()) return false;
+ Interval1f v = bezier_clipping(curve0v);
+ if (isEmpty(v)) return false;
+ v = intersect(v + Interval1f(-0.1f,+0.1f),Interval1f(0.0f,1.0f));
+ cv = BBox1f(lerp(cv.lower,cv.upper,v.lower),lerp(cv.lower,cv.upper,v.upper));
+ return true;
+ }
+
+ __forceinline bool solve_krawczyk(bool very_small, BBox1f& cu, BBox1f& cv)
+ {
+ /* perform bezier clipping in v-direction to get tight v-bounds */
+ TensorLinearCubicBezierSurface2fa curve2 = curve2d.clip(cu,cv);
+ const Vec2fa dv = curve2.axis_v();
+ const TensorLinearCubicBezierSurface1f curve1v = curve2.xfm(dv);
+ LinearBezierCurve<Interval1f> curve0v = curve1v.reduce_u();
+ if (unlikely(!curve0v.hasRoot())) return true;
+ Interval1f v = bezier_clipping(curve0v);
+ if (unlikely(isEmpty(v))) return true;
+ v = intersect(v + Interval1f(-0.1f,+0.1f),Interval1f(0.0f,1.0f));
+ curve2 = curve2.clip_v(v);
+ cv = BBox1f(lerp(cv.lower,cv.upper,v.lower),lerp(cv.lower,cv.upper,v.upper));
+
+ /* perform one newton raphson iteration */
+ Vec2fa c(cu.center(),cv.center());
+ Vec2fa f,dfdu,dfdv; curve2d.eval(c.x,c.y,f,dfdu,dfdv);
+ const LinearSpace2fa rcp_J = rcp(LinearSpace2fa(dfdu,dfdv));
+ const Vec2fa c1 = c - rcp_J*f;
+
+ /* calculate bounds of derivatives */
+ const BBox2fa bounds_du = (1.0f/cu.size())*curve2.derivative_u().bounds();
+ const BBox2fa bounds_dv = (1.0f/cv.size())*curve2.derivative_v().bounds();
+
+ /* calculate krawczyk test */
+ LinearSpace2<Vec2<Interval1f>> I(Interval1f(1.0f), Interval1f(0.0f),
+ Interval1f(0.0f), Interval1f(1.0f));
+
+ LinearSpace2<Vec2<Interval1f>> G(Interval1f(bounds_du.lower.x,bounds_du.upper.x), Interval1f(bounds_dv.lower.x,bounds_dv.upper.x),
+ Interval1f(bounds_du.lower.y,bounds_du.upper.y), Interval1f(bounds_dv.lower.y,bounds_dv.upper.y));
+
+ const LinearSpace2<Vec2f> rcp_J2(rcp_J);
+ const LinearSpace2<Vec2<Interval1f>> rcp_Ji(rcp_J2);
+
+ const Vec2<Interval1f> x(cu,cv);
+ const Vec2<Interval1f> K = Vec2<Interval1f>(Vec2f(c1)) + (I - rcp_Ji*G)*(x-Vec2<Interval1f>(Vec2f(c)));
+
+ /* test if there is no solution */
+ const Vec2<Interval1f> KK = intersect(K,x);
+ if (unlikely(isEmpty(KK.x) || isEmpty(KK.y))) return true;
+
+ /* exit if convergence cannot get proven, but terminate if we are very small */
+ if (unlikely(!subset(K,x) && !very_small)) return false;
+
+ /* solve using newton raphson iteration of convergence is guarenteed */
+ solve_newton_raphson_loop(cu,cv,c1,dfdu,dfdv,rcp_J);
+ return true;
+ }
+
+ __forceinline void solve_newton_raphson_no_recursion(BBox1f cu, BBox1f cv)
+ {
+ if (!clip_v(cu,cv)) return;
+ return solve_newton_raphson(cu,cv);
+ }
+
+ __forceinline void solve_newton_raphson_recursion(BBox1f cu, BBox1f cv)
+ {
+ unsigned int sptr = 0;
+ const unsigned int stack_size = 4;
+ unsigned int mask_stack[stack_size];
+ BBox1f cu_stack[stack_size];
+ BBox1f cv_stack[stack_size];
+ goto entry;
+
+ /* terminate if stack is empty */
+ while (sptr)
+ {
+ /* pop from stack */
+ {
+ sptr--;
+ size_t mask = mask_stack[sptr];
+ cu = cu_stack[sptr];
+ cv = cv_stack[sptr];
+ const size_t i = bscf(mask);
+ mask_stack[sptr] = mask;
+ if (mask) sptr++; // there are still items on the stack
+
+ /* process next element recurse into each hit curve segment */
+ const float u0 = float(i+0)*(1.0f/(VSIZEX-1));
+ const float u1 = float(i+1)*(1.0f/(VSIZEX-1));
+ const BBox1f cui(lerp(cu.lower,cu.upper,u0),lerp(cu.lower,cu.upper,u1));
+ cu = cui;
+ }
+
+#if 0
+ solve_newton_raphson_no_recursion(cu,cv);
+ continue;
+
+#else
+ /* we assume convergence for small u ranges and verify using krawczyk */
+ if (cu.size() < 1.0f/6.0f) {
+ const bool very_small = cu.size() < 0.001f || sptr >= stack_size;
+ if (solve_krawczyk(very_small,cu,cv)) {
+ continue;
+ }
+ }
+#endif
+
+ entry:
+
+ /* split the curve into VSIZEX-1 segments in u-direction */
+ vboolx valid = true;
+ TensorLinearCubicBezierSurface<Vec2vfx> subcurves = curve2d.clip_v(cv).vsplit_u(valid,cu);
+
+ /* slabs test in u-direction */
+ Vec2vfx ndv = cross(subcurves.axis_v());
+ BBox<vfloatx> boundsv = subcurves.vxfm(ndv).bounds();
+ valid &= boundsv.lower <= eps;
+ valid &= boundsv.upper >= -eps;
+ if (none(valid)) continue;
+
+ /* slabs test in v-direction */
+ Vec2vfx ndu = cross(subcurves.axis_u());
+ BBox<vfloatx> boundsu = subcurves.vxfm(ndu).bounds();
+ valid &= boundsu.lower <= eps;
+ valid &= boundsu.upper >= -eps;
+ if (none(valid)) continue;
+
+ /* push valid segments to stack */
+ assert(sptr < stack_size);
+ mask_stack [sptr] = movemask(valid);
+ cu_stack [sptr] = cu;
+ cv_stack [sptr] = cv;
+ sptr++;
+ }
+ }
+
+ __forceinline bool solve_newton_raphson_main()
+ {
+ BBox1f vu(0.0f,1.0f);
+ BBox1f vv(0.0f,1.0f);
+ solve_newton_raphson_recursion(vu,vv);
+ return isHit;
+ }
+ };
+
+
+ template<template<typename Ty> class SourceCurve>
+ struct OrientedCurve1Intersector1
+ {
+ //template<typename Ty> using Curve = SourceCurve<Ty>;
+ typedef SourceCurve<Vec3ff> SourceCurve3ff;
+ typedef SourceCurve<Vec3fa> SourceCurve3fa;
+
+ __forceinline OrientedCurve1Intersector1() {}
+
+ __forceinline OrientedCurve1Intersector1(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __noinline bool intersect(const CurvePrecalculations1& pre, Ray& ray,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0i, const Vec3ff& v1i, const Vec3ff& v2i, const Vec3ff& v3i,
+ const Vec3fa& n0i, const Vec3fa& n1i, const Vec3fa& n2i, const Vec3fa& n3i,
+ const Epilog& epilog) const
+ {
+ STAT3(normal.trav_prims,1,1,1);
+
+ SourceCurve3ff ccurve(v0i,v1i,v2i,v3i);
+ SourceCurve3fa ncurve(n0i,n1i,n2i,n3i);
+ ccurve = enlargeRadiusToMinWidth(context,geom,ray.org,ccurve);
+ TensorLinearCubicBezierSurface3fa curve = TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve);
+ //return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_bezier_clipping();
+ return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_newton_raphson_main();
+ }
+
+ template<typename Epilog>
+ __noinline bool intersect(const CurvePrecalculations1& pre, Ray& ray,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const TensorLinearCubicBezierSurface3fa& curve, const Epilog& epilog) const
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ //return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_bezier_clipping();
+ return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_newton_raphson_main();
+ }
+ };
+
+ template<template<typename Ty> class SourceCurve, int K>
+ struct OrientedCurve1IntersectorK
+ {
+ //template<typename Ty> using Curve = SourceCurve<Ty>;
+ typedef SourceCurve<Vec3ff> SourceCurve3ff;
+ typedef SourceCurve<Vec3fa> SourceCurve3fa;
+
+ struct Ray1
+ {
+ __forceinline Ray1(RayK<K>& ray, size_t k)
+ : org(ray.org.x[k],ray.org.y[k],ray.org.z[k]), dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]), _tnear(ray.tnear()[k]), tfar(ray.tfar[k]) {}
+
+ Vec3fa org;
+ Vec3fa dir;
+ float _tnear;
+ float& tfar;
+
+ __forceinline float& tnear() { return _tnear; }
+ //__forceinline float& tfar() { return _tfar; }
+ __forceinline const float& tnear() const { return _tnear; }
+ //__forceinline const float& tfar() const { return _tfar; }
+ };
+
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& vray, size_t k,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0i, const Vec3ff& v1i, const Vec3ff& v2i, const Vec3ff& v3i,
+ const Vec3fa& n0i, const Vec3fa& n1i, const Vec3fa& n2i, const Vec3fa& n3i,
+ const Epilog& epilog)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Ray1 ray(vray,k);
+ SourceCurve3ff ccurve(v0i,v1i,v2i,v3i);
+ SourceCurve3fa ncurve(n0i,n1i,n2i,n3i);
+ ccurve = enlargeRadiusToMinWidth(context,geom,ray.org,ccurve);
+ TensorLinearCubicBezierSurface3fa curve = TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve);
+ //return TensorLinearCubicBezierSurfaceIntersector<Ray1,Epilog>(pre.ray_space[k],ray,curve,epilog).solve_bezier_clipping();
+ return TensorLinearCubicBezierSurfaceIntersector<Ray1,Epilog>(pre.ray_space[k],ray,curve,epilog).solve_newton_raphson_main();
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& vray, size_t k,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const TensorLinearCubicBezierSurface3fa& curve,
+ const Epilog& epilog)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Ray1 ray(vray,k);
+ //return TensorLinearCubicBezierSurfaceIntersector<Ray1,Epilog>(pre.ray_space[k],ray,curve,epilog).solve_bezier_clipping();
+ return TensorLinearCubicBezierSurfaceIntersector<Ray1,Epilog>(pre.ray_space[k],ray,curve,epilog).solve_newton_raphson_main();
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_precalculations.h b/thirdparty/embree/kernels/geometry/curve_intersector_precalculations.h
new file mode 100644
index 0000000000..de6b70be1b
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curve_intersector_precalculations.h
@@ -0,0 +1,49 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/geometry.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct CurvePrecalculations1
+ {
+ float depth_scale;
+ LinearSpace3fa ray_space;
+
+ __forceinline CurvePrecalculations1() {}
+
+ __forceinline CurvePrecalculations1(const Ray& ray, const void* ptr)
+ {
+ depth_scale = rsqrt(dot(ray.dir,ray.dir));
+ LinearSpace3fa space = frame(depth_scale*ray.dir);
+ space.vz *= depth_scale;
+ ray_space = space.transposed();
+ }
+ };
+
+ template<int K>
+ struct CurvePrecalculationsK
+ {
+ vfloat<K> depth_scale;
+ LinearSpace3fa ray_space[K];
+
+ __forceinline CurvePrecalculationsK(const vbool<K>& valid, const RayK<K>& ray)
+ {
+ size_t mask = movemask(valid);
+ depth_scale = rsqrt(dot(ray.dir,ray.dir));
+ while (mask) {
+ size_t k = bscf(mask);
+ Vec3fa ray_dir_k = Vec3fa(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
+ LinearSpace3fa ray_space_k = frame(depth_scale[k]*ray_dir_k);
+ ray_space_k.vz *= depth_scale[k];
+ ray_space[k] = ray_space_k.transposed();
+ }
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_ribbon.h b/thirdparty/embree/kernels/geometry/curve_intersector_ribbon.h
new file mode 100644
index 0000000000..c3272e99fd
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curve_intersector_ribbon.h
@@ -0,0 +1,216 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "quad_intersector.h"
+#include "curve_intersector_precalculations.h"
+
+#define Bezier1Intersector1 RibbonCurve1Intersector1
+#define Bezier1IntersectorK RibbonCurve1IntersectorK
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename NativeCurve3ff, int M>
+ struct RibbonHit
+ {
+ __forceinline RibbonHit() {}
+
+ __forceinline RibbonHit(const vbool<M>& valid, const vfloat<M>& U, const vfloat<M>& V, const vfloat<M>& T, const int i, const int N,
+ const NativeCurve3ff& curve3D)
+ : U(U), V(V), T(T), i(i), N(N), curve3D(curve3D), valid(valid) {}
+
+ __forceinline void finalize()
+ {
+ vu = (vfloat<M>(step)+U+vfloat<M>(float(i)))*(1.0f/float(N));
+ vv = V;
+ vt = T;
+ }
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return curve3D.eval_du(vu[i]); }
+
+ __forceinline Vec2vf<M> uv() const { return Vec2vf<M>(vu,vv); }
+ __forceinline vfloat<M> t () const { return vt; }
+ __forceinline Vec3vf<M> Ng() const { return (Vec3vf<M>) curve3D.template veval_du<M>(vu); }
+
+ public:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> T;
+ int i, N;
+ NativeCurve3ff curve3D;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ };
+
+ /* calculate squared distance of point p0 to line p1->p2 */
+ __forceinline std::pair<vfloatx,vfloatx> sqr_point_line_distance(const Vec2vfx& p0, const Vec2vfx& p1, const Vec2vfx& p2)
+ {
+ const vfloatx num = det(p2-p1,p1-p0);
+ const vfloatx den2 = dot(p2-p1,p2-p1);
+ return std::make_pair(num*num,den2);
+ }
+
+ /* performs culling against a cylinder */
+ __forceinline vboolx cylinder_culling_test(const Vec2vfx& p0, const Vec2vfx& p1, const Vec2vfx& p2, const vfloatx& r)
+ {
+ const std::pair<vfloatx,vfloatx> d = sqr_point_line_distance(p0,p1,p2);
+ return d.first <= r*r*d.second;
+ }
+
+ template<typename NativeCurve3ff, typename Epilog>
+ __forceinline bool intersect_ribbon(const Vec3fa& ray_org, const Vec3fa& ray_dir, const float ray_tnear, const float& ray_tfar,
+ const LinearSpace3fa& ray_space, const float& depth_scale,
+ const NativeCurve3ff& curve3D, const int N,
+ const Epilog& epilog)
+ {
+ /* transform control points into ray space */
+ const NativeCurve3ff curve2D = curve3D.xfm_pr(ray_space,ray_org);
+ float eps = 4.0f*float(ulp)*reduce_max(max(abs(curve2D.v0),abs(curve2D.v1),abs(curve2D.v2),abs(curve2D.v3)));
+
+ /* evaluate the bezier curve */
+ bool ishit = false;
+ vboolx valid = vfloatx(step) < vfloatx(float(N));
+ const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(0,N);
+ const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(0,N);
+ valid &= cylinder_culling_test(zero,Vec2vfx(p0.x,p0.y),Vec2vfx(p1.x,p1.y),max(p0.w,p1.w));
+
+ if (any(valid))
+ {
+ Vec3vfx dp0dt = curve2D.template derivative0<VSIZEX>(0,N);
+ Vec3vfx dp1dt = curve2D.template derivative1<VSIZEX>(0,N);
+ dp0dt = select(reduce_max(abs(dp0dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp0dt);
+ dp1dt = select(reduce_max(abs(dp1dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp1dt);
+ const Vec3vfx n0(dp0dt.y,-dp0dt.x,0.0f);
+ const Vec3vfx n1(dp1dt.y,-dp1dt.x,0.0f);
+ const Vec3vfx nn0 = normalize(n0);
+ const Vec3vfx nn1 = normalize(n1);
+ const Vec3vfx lp0 = madd(p0.w,nn0,Vec3vfx(p0));
+ const Vec3vfx lp1 = madd(p1.w,nn1,Vec3vfx(p1));
+ const Vec3vfx up0 = nmadd(p0.w,nn0,Vec3vfx(p0));
+ const Vec3vfx up1 = nmadd(p1.w,nn1,Vec3vfx(p1));
+
+ vfloatx vu,vv,vt;
+ vboolx valid0 = intersect_quad_backface_culling<VSIZEX>(valid,zero,Vec3fa(0,0,1),ray_tnear,ray_tfar,lp0,lp1,up1,up0,vu,vv,vt);
+
+ if (any(valid0))
+ {
+ /* ignore self intersections */
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f) {
+ vfloatx r = lerp(p0.w, p1.w, vu);
+ valid0 &= vt > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale;
+ }
+
+ if (any(valid0))
+ {
+ vv = madd(2.0f,vv,vfloatx(-1.0f));
+ RibbonHit<NativeCurve3ff,VSIZEX> bhit(valid0,vu,vv,vt,0,N,curve3D);
+ ishit |= epilog(bhit.valid,bhit);
+ }
+ }
+ }
+
+ if (unlikely(VSIZEX < N))
+ {
+ /* process SIMD-size many segments per iteration */
+ for (int i=VSIZEX; i<N; i+=VSIZEX)
+ {
+ /* evaluate the bezier curve */
+ vboolx valid = vintx(i)+vintx(step) < vintx(N);
+ const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(i,N);
+ const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(i,N);
+ valid &= cylinder_culling_test(zero,Vec2vfx(p0.x,p0.y),Vec2vfx(p1.x,p1.y),max(p0.w,p1.w));
+ if (none(valid)) continue;
+
+ Vec3vfx dp0dt = curve2D.template derivative0<VSIZEX>(i,N);
+ Vec3vfx dp1dt = curve2D.template derivative1<VSIZEX>(i,N);
+ dp0dt = select(reduce_max(abs(dp0dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp0dt);
+ dp1dt = select(reduce_max(abs(dp1dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp1dt);
+ const Vec3vfx n0(dp0dt.y,-dp0dt.x,0.0f);
+ const Vec3vfx n1(dp1dt.y,-dp1dt.x,0.0f);
+ const Vec3vfx nn0 = normalize(n0);
+ const Vec3vfx nn1 = normalize(n1);
+ const Vec3vfx lp0 = madd(p0.w,nn0,Vec3vfx(p0));
+ const Vec3vfx lp1 = madd(p1.w,nn1,Vec3vfx(p1));
+ const Vec3vfx up0 = nmadd(p0.w,nn0,Vec3vfx(p0));
+ const Vec3vfx up1 = nmadd(p1.w,nn1,Vec3vfx(p1));
+
+ vfloatx vu,vv,vt;
+ vboolx valid0 = intersect_quad_backface_culling<VSIZEX>(valid,zero,Vec3fa(0,0,1),ray_tnear,ray_tfar,lp0,lp1,up1,up0,vu,vv,vt);
+
+ if (any(valid0))
+ {
+ /* ignore self intersections */
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f) {
+ vfloatx r = lerp(p0.w, p1.w, vu);
+ valid0 &= vt > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale;
+ }
+
+ if (any(valid0))
+ {
+ vv = madd(2.0f,vv,vfloatx(-1.0f));
+ RibbonHit<NativeCurve3ff,VSIZEX> bhit(valid0,vu,vv,vt,i,N,curve3D);
+ ishit |= epilog(bhit.valid,bhit);
+ }
+ }
+ }
+ }
+ return ishit;
+ }
+
+ template<template<typename Ty> class NativeCurve>
+ struct RibbonCurve1Intersector1
+ {
+ typedef NativeCurve<Vec3ff> NativeCurve3ff;
+
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculations1& pre, Ray& ray,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
+ const Epilog& epilog)
+ {
+ const int N = geom->tessellationRate;
+ NativeCurve3ff curve(v0,v1,v2,v3);
+ curve = enlargeRadiusToMinWidth(context,geom,ray.org,curve);
+ return intersect_ribbon<NativeCurve3ff>(ray.org,ray.dir,ray.tnear(),ray.tfar,
+ pre.ray_space,pre.depth_scale,
+ curve,N,
+ epilog);
+ }
+ };
+
+ template<template<typename Ty> class NativeCurve, int K>
+ struct RibbonCurve1IntersectorK
+ {
+ typedef NativeCurve<Vec3ff> NativeCurve3ff;
+
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
+ const Epilog& epilog)
+ {
+ const int N = geom->tessellationRate;
+ const Vec3fa ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]);
+ const Vec3fa ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
+ NativeCurve3ff curve(v0,v1,v2,v3);
+ curve = enlargeRadiusToMinWidth(context,geom,ray_org,curve);
+ return intersect_ribbon<NativeCurve3ff>(ray_org,ray_dir,ray.tnear()[k],ray.tfar[k],
+ pre.ray_space[k],pre.depth_scale[k],
+ curve,N,
+ epilog);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_sweep.h b/thirdparty/embree/kernels/geometry/curve_intersector_sweep.h
new file mode 100644
index 0000000000..2d4abd73ac
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curve_intersector_sweep.h
@@ -0,0 +1,364 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "cylinder.h"
+#include "plane.h"
+#include "line_intersector.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ static const size_t numJacobianIterations = 5;
+#if defined(__AVX__)
+ static const size_t numBezierSubdivisions = 2;
+#else
+ static const size_t numBezierSubdivisions = 3;
+#endif
+
+ struct BezierCurveHit
+ {
+ __forceinline BezierCurveHit() {}
+
+ __forceinline BezierCurveHit(const float t, const float u, const Vec3fa& Ng)
+ : t(t), u(u), v(0.0f), Ng(Ng) {}
+
+ __forceinline BezierCurveHit(const float t, const float u, const float v, const Vec3fa& Ng)
+ : t(t), u(u), v(v), Ng(Ng) {}
+
+ __forceinline void finalize() {}
+
+ public:
+ float t;
+ float u;
+ float v;
+ Vec3fa Ng;
+ };
+
+ template<typename NativeCurve3ff, typename Ray, typename Epilog>
+ __forceinline bool intersect_bezier_iterative_debug(const Ray& ray, const float dt, const NativeCurve3ff& curve, size_t i,
+ const vfloatx& u, const BBox<vfloatx>& tp, const BBox<vfloatx>& h0, const BBox<vfloatx>& h1,
+ const Vec3vfx& Ng, const Vec4vfx& dP0du, const Vec4vfx& dP3du,
+ const Epilog& epilog)
+ {
+ if (tp.lower[i]+dt > ray.tfar) return false;
+ Vec3fa Ng_o = Vec3fa(Ng.x[i],Ng.y[i],Ng.z[i]);
+ if (h0.lower[i] == tp.lower[i]) Ng_o = -Vec3fa(dP0du.x[i],dP0du.y[i],dP0du.z[i]);
+ if (h1.lower[i] == tp.lower[i]) Ng_o = +Vec3fa(dP3du.x[i],dP3du.y[i],dP3du.z[i]);
+ BezierCurveHit hit(tp.lower[i]+dt,u[i],Ng_o);
+ return epilog(hit);
+ }
+
+ template<typename NativeCurve3ff, typename Ray, typename Epilog>
+ __forceinline bool intersect_bezier_iterative_jacobian(const Ray& ray, const float dt, const NativeCurve3ff& curve, float u, float t, const Epilog& epilog)
+ {
+ const Vec3fa org = zero;
+ const Vec3fa dir = ray.dir;
+ const float length_ray_dir = length(dir);
+
+ /* error of curve evaluations is propertional to largest coordinate */
+ const BBox3ff box = curve.bounds();
+ const float P_err = 16.0f*float(ulp)*reduce_max(max(abs(box.lower),abs(box.upper)));
+
+ for (size_t i=0; i<numJacobianIterations; i++)
+ {
+ const Vec3fa Q = madd(Vec3fa(t),dir,org);
+ //const Vec3fa dQdu = zero;
+ const Vec3fa dQdt = dir;
+ const float Q_err = 16.0f*float(ulp)*length_ray_dir*t; // works as org=zero here
+
+ Vec3ff P,dPdu,ddPdu; curve.eval(u,P,dPdu,ddPdu);
+ //const Vec3fa dPdt = zero;
+
+ const Vec3fa R = Q-P;
+ const float len_R = length(R); //reduce_max(abs(R));
+ const float R_err = max(Q_err,P_err);
+ const Vec3fa dRdu = /*dQdu*/-dPdu;
+ const Vec3fa dRdt = dQdt;//-dPdt;
+
+ const Vec3fa T = normalize(dPdu);
+ const Vec3fa dTdu = dnormalize(dPdu,ddPdu);
+ //const Vec3fa dTdt = zero;
+ const float cos_err = P_err/length(dPdu);
+
+ /* Error estimate for dot(R,T):
+
+ dot(R,T) = cos(R,T) |R| |T|
+ = (cos(R,T) +- cos_error) * (|R| +- |R|_err) * (|T| +- |T|_err)
+ = cos(R,T)*|R|*|T|
+ +- cos(R,T)*(|R|*|T|_err + |T|*|R|_err)
+ +- cos_error*(|R| + |T|)
+ +- lower order terms
+ with cos(R,T) being in [0,1] and |T| = 1 we get:
+ dot(R,T)_err = |R|*|T|_err + |R|_err = cos_error*(|R|+1)
+ */
+
+ const float f = dot(R,T);
+ const float f_err = len_R*P_err + R_err + cos_err*(1.0f+len_R);
+ const float dfdu = dot(dRdu,T) + dot(R,dTdu);
+ const float dfdt = dot(dRdt,T);// + dot(R,dTdt);
+
+ const float K = dot(R,R)-sqr(f);
+ const float dKdu = /*2.0f*/(dot(R,dRdu)-f*dfdu);
+ const float dKdt = /*2.0f*/(dot(R,dRdt)-f*dfdt);
+ const float rsqrt_K = rsqrt(K);
+
+ const float g = sqrt(K)-P.w;
+ const float g_err = R_err + f_err + 16.0f*float(ulp)*box.upper.w;
+ const float dgdu = /*0.5f*/dKdu*rsqrt_K-dPdu.w;
+ const float dgdt = /*0.5f*/dKdt*rsqrt_K;//-dPdt.w;
+
+ const LinearSpace2f J = LinearSpace2f(dfdu,dfdt,dgdu,dgdt);
+ const Vec2f dut = rcp(J)*Vec2f(f,g);
+ const Vec2f ut = Vec2f(u,t) - dut;
+ u = ut.x; t = ut.y;
+
+ if (abs(f) < f_err && abs(g) < g_err)
+ {
+ t+=dt;
+ if (!(ray.tnear() <= t && t <= ray.tfar)) return false; // rejects NaNs
+ if (!(u >= 0.0f && u <= 1.0f)) return false; // rejects NaNs
+ const Vec3fa R = normalize(Q-P);
+ const Vec3fa U = madd(Vec3fa(dPdu.w),R,dPdu);
+ const Vec3fa V = cross(dPdu,R);
+ BezierCurveHit hit(t,u,cross(V,U));
+ return epilog(hit);
+ }
+ }
+ return false;
+ }
+
+ template<typename NativeCurve3ff, typename Ray, typename Epilog>
+ bool intersect_bezier_recursive_jacobian(const Ray& ray, const float dt, const NativeCurve3ff& curve,
+ float u0, float u1, unsigned int depth, const Epilog& epilog)
+ {
+#if defined(__AVX__)
+ enum { VSIZEX_ = 8 };
+ typedef vbool8 vboolx; // maximally 8-wide to work around KNL issues
+ typedef vint8 vintx;
+ typedef vfloat8 vfloatx;
+#else
+ enum { VSIZEX_ = 4 };
+ typedef vbool4 vboolx;
+ typedef vint4 vintx;
+ typedef vfloat4 vfloatx;
+#endif
+ typedef Vec3<vfloatx> Vec3vfx;
+ typedef Vec4<vfloatx> Vec4vfx;
+
+ unsigned int maxDepth = numBezierSubdivisions;
+ bool found = false;
+ const Vec3fa org = zero;
+ const Vec3fa dir = ray.dir;
+
+ unsigned int sptr = 0;
+ const unsigned int stack_size = numBezierSubdivisions+1; // +1 because of unstable workaround below
+ struct StackEntry {
+ vboolx valid;
+ vfloatx tlower;
+ float u0;
+ float u1;
+ unsigned int depth;
+ };
+ StackEntry stack[stack_size];
+ goto entry;
+
+ /* terminate if stack is empty */
+ while (sptr)
+ {
+ /* pop from stack */
+ {
+ sptr--;
+ vboolx valid = stack[sptr].valid;
+ const vfloatx tlower = stack[sptr].tlower;
+ valid &= tlower+dt <= ray.tfar;
+ if (none(valid)) continue;
+ u0 = stack[sptr].u0;
+ u1 = stack[sptr].u1;
+ depth = stack[sptr].depth;
+ const size_t i = select_min(valid,tlower); clear(valid,i);
+ stack[sptr].valid = valid;
+ if (any(valid)) sptr++; // there are still items on the stack
+
+ /* process next segment */
+ const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(vfloatx::size-1)));
+ u0 = vu0[i+0];
+ u1 = vu0[i+1];
+ }
+ entry:
+
+ /* subdivide curve */
+ const float dscale = (u1-u0)*(1.0f/(3.0f*(vfloatx::size-1)));
+ const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(vfloatx::size-1)));
+ Vec4vfx P0, dP0du; curve.template veval<VSIZEX_>(vu0,P0,dP0du); dP0du = dP0du * Vec4vfx(dscale);
+ const Vec4vfx P3 = shift_right_1(P0);
+ const Vec4vfx dP3du = shift_right_1(dP0du);
+ const Vec4vfx P1 = P0 + dP0du;
+ const Vec4vfx P2 = P3 - dP3du;
+
+ /* calculate bounding cylinders */
+ const vfloatx rr1 = sqr_point_to_line_distance(Vec3vfx(dP0du),Vec3vfx(P3-P0));
+ const vfloatx rr2 = sqr_point_to_line_distance(Vec3vfx(dP3du),Vec3vfx(P3-P0));
+ const vfloatx maxr12 = sqrt(max(rr1,rr2));
+ const vfloatx one_plus_ulp = 1.0f+2.0f*float(ulp);
+ const vfloatx one_minus_ulp = 1.0f-2.0f*float(ulp);
+ vfloatx r_outer = max(P0.w,P1.w,P2.w,P3.w)+maxr12;
+ vfloatx r_inner = min(P0.w,P1.w,P2.w,P3.w)-maxr12;
+ r_outer = one_plus_ulp*r_outer;
+ r_inner = max(0.0f,one_minus_ulp*r_inner);
+ const CylinderN<vfloatx::size> cylinder_outer(Vec3vfx(P0),Vec3vfx(P3),r_outer);
+ const CylinderN<vfloatx::size> cylinder_inner(Vec3vfx(P0),Vec3vfx(P3),r_inner);
+ vboolx valid = true; clear(valid,vfloatx::size-1);
+
+ /* intersect with outer cylinder */
+ BBox<vfloatx> tc_outer; vfloatx u_outer0; Vec3vfx Ng_outer0; vfloatx u_outer1; Vec3vfx Ng_outer1;
+ valid &= cylinder_outer.intersect(org,dir,tc_outer,u_outer0,Ng_outer0,u_outer1,Ng_outer1);
+ if (none(valid)) continue;
+
+ /* intersect with cap-planes */
+ BBox<vfloatx> tp(ray.tnear()-dt,ray.tfar-dt);
+ tp = embree::intersect(tp,tc_outer);
+ BBox<vfloatx> h0 = HalfPlaneN<vfloatx::size>(Vec3vfx(P0),+Vec3vfx(dP0du)).intersect(org,dir);
+ tp = embree::intersect(tp,h0);
+ BBox<vfloatx> h1 = HalfPlaneN<vfloatx::size>(Vec3vfx(P3),-Vec3vfx(dP3du)).intersect(org,dir);
+ tp = embree::intersect(tp,h1);
+ valid &= tp.lower <= tp.upper;
+ if (none(valid)) continue;
+
+ /* clamp and correct u parameter */
+ u_outer0 = clamp(u_outer0,vfloatx(0.0f),vfloatx(1.0f));
+ u_outer1 = clamp(u_outer1,vfloatx(0.0f),vfloatx(1.0f));
+ u_outer0 = lerp(u0,u1,(vfloatx(step)+u_outer0)*(1.0f/float(vfloatx::size)));
+ u_outer1 = lerp(u0,u1,(vfloatx(step)+u_outer1)*(1.0f/float(vfloatx::size)));
+
+ /* intersect with inner cylinder */
+ BBox<vfloatx> tc_inner;
+ vfloatx u_inner0 = zero; Vec3vfx Ng_inner0 = zero; vfloatx u_inner1 = zero; Vec3vfx Ng_inner1 = zero;
+ const vboolx valid_inner = cylinder_inner.intersect(org,dir,tc_inner,u_inner0,Ng_inner0,u_inner1,Ng_inner1);
+
+ /* at the unstable area we subdivide deeper */
+ const vboolx unstable0 = (!valid_inner) | (abs(dot(Vec3vfx(Vec3fa(ray.dir)),Ng_inner0)) < 0.3f);
+ const vboolx unstable1 = (!valid_inner) | (abs(dot(Vec3vfx(Vec3fa(ray.dir)),Ng_inner1)) < 0.3f);
+
+ /* subtract the inner interval from the current hit interval */
+ BBox<vfloatx> tp0, tp1;
+ subtract(tp,tc_inner,tp0,tp1);
+ vboolx valid0 = valid & (tp0.lower <= tp0.upper);
+ vboolx valid1 = valid & (tp1.lower <= tp1.upper);
+ if (none(valid0 | valid1)) continue;
+
+ /* iterate over all first hits front to back */
+ const vintx termDepth0 = select(unstable0,vintx(maxDepth+1),vintx(maxDepth));
+ vboolx recursion_valid0 = valid0 & (depth < termDepth0);
+ valid0 &= depth >= termDepth0;
+
+ while (any(valid0))
+ {
+ const size_t i = select_min(valid0,tp0.lower); clear(valid0,i);
+ found = found | intersect_bezier_iterative_jacobian(ray,dt,curve,u_outer0[i],tp0.lower[i],epilog);
+ //found = found | intersect_bezier_iterative_debug (ray,dt,curve,i,u_outer0,tp0,h0,h1,Ng_outer0,dP0du,dP3du,epilog);
+ valid0 &= tp0.lower+dt <= ray.tfar;
+ }
+ valid1 &= tp1.lower+dt <= ray.tfar;
+
+ /* iterate over all second hits front to back */
+ const vintx termDepth1 = select(unstable1,vintx(maxDepth+1),vintx(maxDepth));
+ vboolx recursion_valid1 = valid1 & (depth < termDepth1);
+ valid1 &= depth >= termDepth1;
+ while (any(valid1))
+ {
+ const size_t i = select_min(valid1,tp1.lower); clear(valid1,i);
+ found = found | intersect_bezier_iterative_jacobian(ray,dt,curve,u_outer1[i],tp1.upper[i],epilog);
+ //found = found | intersect_bezier_iterative_debug (ray,dt,curve,i,u_outer1,tp1,h0,h1,Ng_outer1,dP0du,dP3du,epilog);
+ valid1 &= tp1.lower+dt <= ray.tfar;
+ }
+
+ /* push valid segments to stack */
+ recursion_valid0 &= tp0.lower+dt <= ray.tfar;
+ recursion_valid1 &= tp1.lower+dt <= ray.tfar;
+ const vboolx recursion_valid = recursion_valid0 | recursion_valid1;
+ if (any(recursion_valid))
+ {
+ assert(sptr < stack_size);
+ stack[sptr].valid = recursion_valid;
+ stack[sptr].tlower = select(recursion_valid0,tp0.lower,tp1.lower);
+ stack[sptr].u0 = u0;
+ stack[sptr].u1 = u1;
+ stack[sptr].depth = depth+1;
+ sptr++;
+ }
+ }
+ return found;
+ }
+
+ template<template<typename Ty> class NativeCurve>
+ struct SweepCurve1Intersector1
+ {
+ typedef NativeCurve<Vec3ff> NativeCurve3ff;
+
+ template<typename Epilog>
+ __noinline bool intersect(const CurvePrecalculations1& pre, Ray& ray,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
+ const Epilog& epilog)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+
+ /* move ray closer to make intersection stable */
+ NativeCurve3ff curve0(v0,v1,v2,v3);
+ curve0 = enlargeRadiusToMinWidth(context,geom,ray.org,curve0);
+ const float dt = dot(curve0.center()-ray.org,ray.dir)*rcp(dot(ray.dir,ray.dir));
+ const Vec3ff ref(madd(Vec3fa(dt),ray.dir,ray.org),0.0f);
+ const NativeCurve3ff curve1 = curve0-ref;
+ return intersect_bezier_recursive_jacobian(ray,dt,curve1,0.0f,1.0f,1,epilog);
+ }
+ };
+
+ template<template<typename Ty> class NativeCurve, int K>
+ struct SweepCurve1IntersectorK
+ {
+ typedef NativeCurve<Vec3ff> NativeCurve3ff;
+
+ struct Ray1
+ {
+ __forceinline Ray1(RayK<K>& ray, size_t k)
+ : org(ray.org.x[k],ray.org.y[k],ray.org.z[k]), dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]), _tnear(ray.tnear()[k]), tfar(ray.tfar[k]) {}
+
+ Vec3fa org;
+ Vec3fa dir;
+ float _tnear;
+ float& tfar;
+
+ __forceinline float& tnear() { return _tnear; }
+ //__forceinline float& tfar() { return _tfar; }
+ __forceinline const float& tnear() const { return _tnear; }
+ //__forceinline const float& tfar() const { return _tfar; }
+
+ };
+
+ template<typename Epilog>
+ __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& vray, size_t k,
+ IntersectContext* context,
+ const CurveGeometry* geom, const unsigned int primID,
+ const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
+ const Epilog& epilog)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Ray1 ray(vray,k);
+
+ /* move ray closer to make intersection stable */
+ NativeCurve3ff curve0(v0,v1,v2,v3);
+ curve0 = enlargeRadiusToMinWidth(context,geom,ray.org,curve0);
+ const float dt = dot(curve0.center()-ray.org,ray.dir)*rcp(dot(ray.dir,ray.dir));
+ const Vec3ff ref(madd(Vec3fa(dt),ray.dir,ray.org),0.0f);
+ const NativeCurve3ff curve1 = curve0-ref;
+ return intersect_bezier_recursive_jacobian(ray,dt,curve1,0.0f,1.0f,1,epilog);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_virtual.h b/thirdparty/embree/kernels/geometry/curve_intersector_virtual.h
new file mode 100644
index 0000000000..cffa8e46ad
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/curve_intersector_virtual.h
@@ -0,0 +1,671 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "../subdiv/bezier_curve.h"
+#include "../common/primref.h"
+#include "curve_intersector_precalculations.h"
+#include "../bvh/node_intersector1.h"
+#include "../bvh/node_intersector_packet.h"
+
+#include "intersector_epilog.h"
+
+#include "../subdiv/bezier_curve.h"
+#include "../subdiv/bspline_curve.h"
+#include "../subdiv/hermite_curve.h"
+#include "../subdiv/catmullrom_curve.h"
+
+#include "spherei_intersector.h"
+#include "disci_intersector.h"
+
+#include "linei_intersector.h"
+#include "roundlinei_intersector.h"
+#include "conelinei_intersector.h"
+
+#include "curveNi_intersector.h"
+#include "curveNv_intersector.h"
+#include "curveNi_mb_intersector.h"
+
+#include "curve_intersector_distance.h"
+#include "curve_intersector_ribbon.h"
+#include "curve_intersector_oriented.h"
+#include "curve_intersector_sweep.h"
+
+namespace embree
+{
+ struct VirtualCurveIntersector
+ {
+ typedef void (*Intersect1Ty)(void* pre, void* ray, IntersectContext* context, const void* primitive);
+ typedef bool (*Occluded1Ty )(void* pre, void* ray, IntersectContext* context, const void* primitive);
+
+ typedef void (*Intersect4Ty)(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+ typedef bool (*Occluded4Ty) (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+
+ typedef void (*Intersect8Ty)(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+ typedef bool (*Occluded8Ty) (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+
+ typedef void (*Intersect16Ty)(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+ typedef bool (*Occluded16Ty) (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+
+ public:
+ struct Intersectors
+ {
+ Intersectors() {} // WARNING: Do not zero initialize this, as we otherwise get problems with thread unsafe local static variable initialization (e.g. on VS2013) in curve_intersector_virtual.cpp.
+
+ template<int K> void intersect(void* pre, void* ray, IntersectContext* context, const void* primitive);
+ template<int K> bool occluded (void* pre, void* ray, IntersectContext* context, const void* primitive);
+
+ template<int K> void intersect(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+ template<int K> bool occluded (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive);
+
+ public:
+ Intersect1Ty intersect1;
+ Occluded1Ty occluded1;
+ Intersect4Ty intersect4;
+ Occluded4Ty occluded4;
+ Intersect8Ty intersect8;
+ Occluded8Ty occluded8;
+ Intersect16Ty intersect16;
+ Occluded16Ty occluded16;
+ };
+
+ Intersectors vtbl[Geometry::GTY_END];
+ };
+
+ template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<1> (void* pre, void* ray, IntersectContext* context, const void* primitive) { assert(intersect1); intersect1(pre,ray,context,primitive); }
+ template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<1> (void* pre, void* ray, IntersectContext* context, const void* primitive) { assert(occluded1); return occluded1(pre,ray,context,primitive); }
+
+ template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<4>(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(intersect4); intersect4(pre,ray,k,context,primitive); }
+ template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<4> (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(occluded4); return occluded4(pre,ray,k,context,primitive); }
+
+#if defined(__AVX__)
+ template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<8>(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(intersect8); intersect8(pre,ray,k,context,primitive); }
+ template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<8> (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(occluded8); return occluded8(pre,ray,k,context,primitive); }
+#endif
+
+#if defined(__AVX512F__)
+ template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<16>(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(intersect16); intersect16(pre,ray,k,context,primitive); }
+ template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<16> (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(occluded16); return occluded16(pre,ray,k,context,primitive); }
+#endif
+
+ namespace isa
+ {
+ struct VirtualCurveIntersector1
+ {
+ typedef unsigned char Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ leafIntersector.intersect<1>(&pre,&ray,context,prim);
+ }
+
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ return leafIntersector.occluded<1>(&pre,&ray,context,prim);
+ }
+ };
+
+ template<int K>
+ struct VirtualCurveIntersectorK
+ {
+ typedef unsigned char Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ size_t mask = movemask(valid_i);
+ while (mask) leafIntersector.intersect<K>(&pre,&ray,bscf(mask),context,prim);
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ vbool<K> valid_o = false;
+ size_t mask = movemask(valid_i);
+ while (mask) {
+ size_t k = bscf(mask);
+ if (leafIntersector.occluded<K>(&pre,&ray,k,context,prim))
+ set(valid_o, k);
+ }
+ return valid_o;
+ }
+
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ leafIntersector.intersect<K>(&pre,&ray,k,context,prim);
+ }
+
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ assert(num == 1);
+ RTCGeometryType ty = (RTCGeometryType)(*prim);
+ assert(This->leafIntersector);
+ VirtualCurveIntersector::Intersectors& leafIntersector = ((VirtualCurveIntersector*) This->leafIntersector)->vtbl[ty];
+ return leafIntersector.occluded<K>(&pre,&ray,k,context,prim);
+ }
+ };
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearRoundConeNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &RoundLinearCurveMiIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &RoundLinearCurveMiIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &RoundLinearCurveMiIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &RoundLinearCurveMiIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&RoundLinearCurveMiIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &RoundLinearCurveMiIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&RoundLinearCurveMiIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &RoundLinearCurveMiIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearConeNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &ConeCurveMiIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &ConeCurveMiIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &ConeCurveMiIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &ConeCurveMiIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&ConeCurveMiIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &ConeCurveMiIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&ConeCurveMiIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &ConeCurveMiIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearRoundConeNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &RoundLinearCurveMiMBIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &RoundLinearCurveMiMBIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &RoundLinearCurveMiMBIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &RoundLinearCurveMiMBIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&RoundLinearCurveMiMBIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &RoundLinearCurveMiMBIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&RoundLinearCurveMiMBIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &RoundLinearCurveMiMBIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearConeNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &ConeCurveMiMBIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &ConeCurveMiMBIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &ConeCurveMiMBIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &ConeCurveMiMBIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&ConeCurveMiMBIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &ConeCurveMiMBIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&ConeCurveMiMBIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &ConeCurveMiMBIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearRibbonNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &FlatLinearCurveMiIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &FlatLinearCurveMiIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &FlatLinearCurveMiIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &FlatLinearCurveMiIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&FlatLinearCurveMiIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &FlatLinearCurveMiIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&FlatLinearCurveMiIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &FlatLinearCurveMiIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors LinearRibbonNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &FlatLinearCurveMiMBIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &FlatLinearCurveMiMBIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &FlatLinearCurveMiMBIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &FlatLinearCurveMiMBIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&FlatLinearCurveMiMBIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &FlatLinearCurveMiMBIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&FlatLinearCurveMiMBIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &FlatLinearCurveMiMBIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors SphereNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &SphereMiIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &SphereMiIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &SphereMiIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &SphereMiIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&SphereMiIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &SphereMiIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&SphereMiIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &SphereMiIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors SphereNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &SphereMiMBIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &SphereMiMBIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &SphereMiMBIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &SphereMiMBIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&SphereMiMBIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &SphereMiMBIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&SphereMiMBIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &SphereMiMBIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors DiscNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &DiscMiIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &DiscMiIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &DiscMiIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &DiscMiIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&DiscMiIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &DiscMiIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&DiscMiIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &DiscMiIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors DiscNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &DiscMiMBIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &DiscMiMBIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &DiscMiMBIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &DiscMiMBIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&DiscMiMBIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &DiscMiMBIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&DiscMiMBIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &DiscMiMBIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors OrientedDiscNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &OrientedDiscMiIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &OrientedDiscMiIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &OrientedDiscMiIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &OrientedDiscMiIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&OrientedDiscMiIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &OrientedDiscMiIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&OrientedDiscMiIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &OrientedDiscMiIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<int N>
+ static VirtualCurveIntersector::Intersectors OrientedDiscNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &OrientedDiscMiMBIntersector1<N,true>::intersect;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &OrientedDiscMiMBIntersector1<N,true>::occluded;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &OrientedDiscMiMBIntersectorK<N,4,true>::intersect;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &OrientedDiscMiMBIntersectorK<N,4,true>::occluded;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&OrientedDiscMiMBIntersectorK<N,8,true>::intersect;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &OrientedDiscMiMBIntersectorK<N,8,true>::occluded;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&OrientedDiscMiMBIntersectorK<N,16,true>::intersect;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &OrientedDiscMiMBIntersectorK<N,16,true>::occluded;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors RibbonNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_t<RibbonCurve1Intersector1<Curve>, Intersect1EpilogMU<VSIZEX,true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_t <RibbonCurve1Intersector1<Curve>, Occluded1EpilogMU<VSIZEX,true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &CurveNiIntersectorK<N,4>::template intersect_t<RibbonCurve1IntersectorK<Curve,4>, Intersect1KEpilogMU<VSIZEX,4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_t <RibbonCurve1IntersectorK<Curve,4>, Occluded1KEpilogMU<VSIZEX,4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_t<RibbonCurve1IntersectorK<Curve,8>, Intersect1KEpilogMU<VSIZEX,8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_t <RibbonCurve1IntersectorK<Curve,8>, Occluded1KEpilogMU<VSIZEX,8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_t<RibbonCurve1IntersectorK<Curve,16>, Intersect1KEpilogMU<VSIZEX,16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_t <RibbonCurve1IntersectorK<Curve,16>, Occluded1KEpilogMU<VSIZEX,16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors RibbonNvIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNvIntersector1<N>::template intersect_t<RibbonCurve1Intersector1<Curve>, Intersect1EpilogMU<VSIZEX,true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNvIntersector1<N>::template occluded_t <RibbonCurve1Intersector1<Curve>, Occluded1EpilogMU<VSIZEX,true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &CurveNvIntersectorK<N,4>::template intersect_t<RibbonCurve1IntersectorK<Curve,4>, Intersect1KEpilogMU<VSIZEX,4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNvIntersectorK<N,4>::template occluded_t <RibbonCurve1IntersectorK<Curve,4>, Occluded1KEpilogMU<VSIZEX,4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNvIntersectorK<N,8>::template intersect_t<RibbonCurve1IntersectorK<Curve,8>, Intersect1KEpilogMU<VSIZEX,8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNvIntersectorK<N,8>::template occluded_t <RibbonCurve1IntersectorK<Curve,8>, Occluded1KEpilogMU<VSIZEX,8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNvIntersectorK<N,16>::template intersect_t<RibbonCurve1IntersectorK<Curve,16>, Intersect1KEpilogMU<VSIZEX,16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNvIntersectorK<N,16>::template occluded_t <RibbonCurve1IntersectorK<Curve,16>, Occluded1KEpilogMU<VSIZEX,16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors RibbonNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_t<RibbonCurve1Intersector1<Curve>, Intersect1EpilogMU<VSIZEX,true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_t <RibbonCurve1Intersector1<Curve>, Occluded1EpilogMU<VSIZEX,true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty) &CurveNiMBIntersectorK<N,4>::template intersect_t<RibbonCurve1IntersectorK<Curve,4>, Intersect1KEpilogMU<VSIZEX,4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_t <RibbonCurve1IntersectorK<Curve,4>, Occluded1KEpilogMU<VSIZEX,4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_t<RibbonCurve1IntersectorK<Curve,8>, Intersect1KEpilogMU<VSIZEX,8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_t <RibbonCurve1IntersectorK<Curve,8>, Occluded1KEpilogMU<VSIZEX,8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_t<RibbonCurve1IntersectorK<Curve,16>, Intersect1KEpilogMU<VSIZEX,16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_t <RibbonCurve1IntersectorK<Curve,16>, Occluded1KEpilogMU<VSIZEX,16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors CurveNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_t<SweepCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_t <SweepCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiIntersectorK<N,4>::template intersect_t<SweepCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_t <SweepCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_t<SweepCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_t <SweepCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_t<SweepCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_t <SweepCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors CurveNvIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNvIntersector1<N>::template intersect_t<SweepCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNvIntersector1<N>::template occluded_t <SweepCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNvIntersectorK<N,4>::template intersect_t<SweepCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNvIntersectorK<N,4>::template occluded_t <SweepCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNvIntersectorK<N,8>::template intersect_t<SweepCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNvIntersectorK<N,8>::template occluded_t <SweepCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNvIntersectorK<N,16>::template intersect_t<SweepCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNvIntersectorK<N,16>::template occluded_t <SweepCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors CurveNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_t<SweepCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_t <SweepCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiMBIntersectorK<N,4>::template intersect_t<SweepCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_t <SweepCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_t<SweepCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_t <SweepCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_t<SweepCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_t <SweepCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors OrientedCurveNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_n<OrientedCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_n <OrientedCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiIntersectorK<N,4>::template intersect_n<OrientedCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_n <OrientedCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_n<OrientedCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_n <OrientedCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_n<OrientedCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_n <OrientedCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors OrientedCurveNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_n<OrientedCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_n <OrientedCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiMBIntersectorK<N,4>::template intersect_n<OrientedCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_n <OrientedCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_n<OrientedCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_n <OrientedCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_n<OrientedCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_n <OrientedCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteRibbonNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_h<RibbonCurve1Intersector1<Curve>, Intersect1EpilogMU<VSIZEX,true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_h <RibbonCurve1Intersector1<Curve>, Occluded1EpilogMU<VSIZEX,true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiIntersectorK<N,4>::template intersect_h<RibbonCurve1IntersectorK<Curve,4>, Intersect1KEpilogMU<VSIZEX,4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_h <RibbonCurve1IntersectorK<Curve,4>, Occluded1KEpilogMU<VSIZEX,4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_h<RibbonCurve1IntersectorK<Curve,8>, Intersect1KEpilogMU<VSIZEX,8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_h <RibbonCurve1IntersectorK<Curve,8>, Occluded1KEpilogMU<VSIZEX,8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_h<RibbonCurve1IntersectorK<Curve,16>, Intersect1KEpilogMU<VSIZEX,16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_h <RibbonCurve1IntersectorK<Curve,16>, Occluded1KEpilogMU<VSIZEX,16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteRibbonNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_h<RibbonCurve1Intersector1<Curve>, Intersect1EpilogMU<VSIZEX,true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_h <RibbonCurve1Intersector1<Curve>, Occluded1EpilogMU<VSIZEX,true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiMBIntersectorK<N,4>::template intersect_h<RibbonCurve1IntersectorK<Curve,4>, Intersect1KEpilogMU<VSIZEX,4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_h <RibbonCurve1IntersectorK<Curve,4>, Occluded1KEpilogMU<VSIZEX,4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_h<RibbonCurve1IntersectorK<Curve,8>, Intersect1KEpilogMU<VSIZEX,8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_h <RibbonCurve1IntersectorK<Curve,8>, Occluded1KEpilogMU<VSIZEX,8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_h<RibbonCurve1IntersectorK<Curve,16>, Intersect1KEpilogMU<VSIZEX,16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_h <RibbonCurve1IntersectorK<Curve,16>, Occluded1KEpilogMU<VSIZEX,16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteCurveNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_h<SweepCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_h <SweepCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiIntersectorK<N,4>::template intersect_h<SweepCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_h <SweepCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_h<SweepCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_h <SweepCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_h<SweepCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_h <SweepCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteCurveNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_h<SweepCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_h <SweepCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiMBIntersectorK<N,4>::template intersect_h<SweepCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_h <SweepCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_h<SweepCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_h <SweepCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_h<SweepCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_h <SweepCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteOrientedCurveNiIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiIntersector1<N>::template intersect_hn<OrientedCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiIntersector1<N>::template occluded_hn <OrientedCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiIntersectorK<N,4>::template intersect_hn<OrientedCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiIntersectorK<N,4>::template occluded_hn <OrientedCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiIntersectorK<N,8>::template intersect_hn<OrientedCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiIntersectorK<N,8>::template occluded_hn <OrientedCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiIntersectorK<N,16>::template intersect_hn<OrientedCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiIntersectorK<N,16>::template occluded_hn <OrientedCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+
+ template<template<typename Ty> class Curve, int N>
+ static VirtualCurveIntersector::Intersectors HermiteOrientedCurveNiMBIntersectors()
+ {
+ VirtualCurveIntersector::Intersectors intersectors;
+ intersectors.intersect1 = (VirtualCurveIntersector::Intersect1Ty) &CurveNiMBIntersector1<N>::template intersect_hn<OrientedCurve1Intersector1<Curve>, Intersect1Epilog1<true> >;
+ intersectors.occluded1 = (VirtualCurveIntersector::Occluded1Ty) &CurveNiMBIntersector1<N>::template occluded_hn <OrientedCurve1Intersector1<Curve>, Occluded1Epilog1<true> >;
+ intersectors.intersect4 = (VirtualCurveIntersector::Intersect4Ty)&CurveNiMBIntersectorK<N,4>::template intersect_hn<OrientedCurve1IntersectorK<Curve,4>, Intersect1KEpilog1<4,true> >;
+ intersectors.occluded4 = (VirtualCurveIntersector::Occluded4Ty) &CurveNiMBIntersectorK<N,4>::template occluded_hn <OrientedCurve1IntersectorK<Curve,4>, Occluded1KEpilog1<4,true> >;
+#if defined(__AVX__)
+ intersectors.intersect8 = (VirtualCurveIntersector::Intersect8Ty)&CurveNiMBIntersectorK<N,8>::template intersect_hn<OrientedCurve1IntersectorK<Curve,8>, Intersect1KEpilog1<8,true> >;
+ intersectors.occluded8 = (VirtualCurveIntersector::Occluded8Ty) &CurveNiMBIntersectorK<N,8>::template occluded_hn <OrientedCurve1IntersectorK<Curve,8>, Occluded1KEpilog1<8,true> >;
+#endif
+#if defined(__AVX512F__)
+ intersectors.intersect16 = (VirtualCurveIntersector::Intersect16Ty)&CurveNiMBIntersectorK<N,16>::template intersect_hn<OrientedCurve1IntersectorK<Curve,16>, Intersect1KEpilog1<16,true> >;
+ intersectors.occluded16 = (VirtualCurveIntersector::Occluded16Ty) &CurveNiMBIntersectorK<N,16>::template occluded_hn <OrientedCurve1IntersectorK<Curve,16>, Occluded1KEpilog1<16,true> >;
+#endif
+ return intersectors;
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/cylinder.h b/thirdparty/embree/kernels/geometry/cylinder.h
new file mode 100644
index 0000000000..dab02989ce
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/cylinder.h
@@ -0,0 +1,223 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct Cylinder
+ {
+ const Vec3fa p0; //!< start location
+ const Vec3fa p1; //!< end position
+ const float rr; //!< squared radius of cylinder
+
+ __forceinline Cylinder(const Vec3fa& p0, const Vec3fa& p1, const float r)
+ : p0(p0), p1(p1), rr(sqr(r)) {}
+
+ __forceinline Cylinder(const Vec3fa& p0, const Vec3fa& p1, const float rr, bool)
+ : p0(p0), p1(p1), rr(rr) {}
+
+ __forceinline bool intersect(const Vec3fa& org,
+ const Vec3fa& dir,
+ BBox1f& t_o,
+ float& u0_o, Vec3fa& Ng0_o,
+ float& u1_o, Vec3fa& Ng1_o) const
+ {
+ /* calculate quadratic equation to solve */
+ const float rl = rcp_length(p1-p0);
+ const Vec3fa P0 = p0, dP = (p1-p0)*rl;
+ const Vec3fa O = org-P0, dO = dir;
+
+ const float dOdO = dot(dO,dO);
+ const float OdO = dot(dO,O);
+ const float OO = dot(O,O);
+ const float dOz = dot(dP,dO);
+ const float Oz = dot(dP,O);
+
+ const float A = dOdO - sqr(dOz);
+ const float B = 2.0f * (OdO - dOz*Oz);
+ const float C = OO - sqr(Oz) - rr;
+
+ /* we miss the cylinder if determinant is smaller than zero */
+ const float D = B*B - 4.0f*A*C;
+ if (D < 0.0f) {
+ t_o = BBox1f(pos_inf,neg_inf);
+ return false;
+ }
+
+ /* special case for rays that are parallel to the cylinder */
+ const float eps = 16.0f*float(ulp)*max(abs(dOdO),abs(sqr(dOz)));
+ if (abs(A) < eps)
+ {
+ if (C <= 0.0f) {
+ t_o = BBox1f(neg_inf,pos_inf);
+ return true;
+ } else {
+ t_o = BBox1f(pos_inf,neg_inf);
+ return false;
+ }
+ }
+
+ /* standard case for rays that are not parallel to the cylinder */
+ const float Q = sqrt(D);
+ const float rcp_2A = rcp(2.0f*A);
+ const float t0 = (-B-Q)*rcp_2A;
+ const float t1 = (-B+Q)*rcp_2A;
+
+ /* calculates u and Ng for near hit */
+ {
+ u0_o = madd(t0,dOz,Oz)*rl;
+ const Vec3fa Pr = t0*dir;
+ const Vec3fa Pl = madd(u0_o,p1-p0,p0);
+ Ng0_o = Pr-Pl;
+ }
+
+ /* calculates u and Ng for far hit */
+ {
+ u1_o = madd(t1,dOz,Oz)*rl;
+ const Vec3fa Pr = t1*dir;
+ const Vec3fa Pl = madd(u1_o,p1-p0,p0);
+ Ng1_o = Pr-Pl;
+ }
+
+ t_o.lower = t0;
+ t_o.upper = t1;
+ return true;
+ }
+
+ __forceinline bool intersect(const Vec3fa& org_i, const Vec3fa& dir, BBox1f& t_o) const
+ {
+ float u0_o; Vec3fa Ng0_o;
+ float u1_o; Vec3fa Ng1_o;
+ return intersect(org_i,dir,t_o,u0_o,Ng0_o,u1_o,Ng1_o);
+ }
+
+ static bool verify(const size_t id, const Cylinder& cylinder, const RayHit& ray, bool shouldhit, const float t0, const float t1)
+ {
+ float eps = 0.001f;
+ BBox1f t; bool hit;
+ hit = cylinder.intersect(ray.org,ray.dir,t);
+
+ bool failed = hit != shouldhit;
+ if (shouldhit) failed |= std::isinf(t0) ? t0 != t.lower : abs(t0-t.lower) > eps;
+ if (shouldhit) failed |= std::isinf(t1) ? t1 != t.upper : abs(t1-t.upper) > eps;
+ if (!failed) return true;
+ embree_cout << "Cylinder test " << id << " failed: cylinder = " << cylinder << ", ray = " << ray << ", hit = " << hit << ", t = " << t << embree_endl;
+ return false;
+ }
+
+ /* verify cylinder class */
+ static bool verify()
+ {
+ bool passed = true;
+ const Cylinder cylinder(Vec3fa(0.0f,0.0f,0.0f),Vec3fa(1.0f,0.0f,0.0f),1.0f);
+ passed &= verify(0,cylinder,RayHit(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.0f,2.0f);
+ passed &= verify(1,cylinder,RayHit(Vec3fa(+2.0f,1.0f,0.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.0f,2.0f);
+ passed &= verify(2,cylinder,RayHit(Vec3fa(+2.0f,1.0f,2.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),false,0.0f,0.0f);
+ passed &= verify(3,cylinder,RayHit(Vec3fa(+0.0f,0.0f,0.0f),Vec3fa( 1.0f, 0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,pos_inf);
+ passed &= verify(4,cylinder,RayHit(Vec3fa(+0.0f,0.0f,0.0f),Vec3fa(-1.0f, 0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,pos_inf);
+ passed &= verify(5,cylinder,RayHit(Vec3fa(+0.0f,2.0f,0.0f),Vec3fa( 1.0f, 0.0f,+0.0f),0.0f,float(inf)),false,pos_inf,neg_inf);
+ passed &= verify(6,cylinder,RayHit(Vec3fa(+0.0f,2.0f,0.0f),Vec3fa(-1.0f, 0.0f,+0.0f),0.0f,float(inf)),false,pos_inf,neg_inf);
+ return passed;
+ }
+
+ /*! output operator */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const Cylinder& c) {
+ return cout << "Cylinder { p0 = " << c.p0 << ", p1 = " << c.p1 << ", r = " << sqrtf(c.rr) << "}";
+ }
+ };
+
+ template<int N>
+ struct CylinderN
+ {
+ const Vec3vf<N> p0; //!< start location
+ const Vec3vf<N> p1; //!< end position
+ const vfloat<N> rr; //!< squared radius of cylinder
+
+ __forceinline CylinderN(const Vec3vf<N>& p0, const Vec3vf<N>& p1, const vfloat<N>& r)
+ : p0(p0), p1(p1), rr(sqr(r)) {}
+
+ __forceinline CylinderN(const Vec3vf<N>& p0, const Vec3vf<N>& p1, const vfloat<N>& rr, bool)
+ : p0(p0), p1(p1), rr(rr) {}
+
+
+ __forceinline vbool<N> intersect(const Vec3fa& org, const Vec3fa& dir,
+ BBox<vfloat<N>>& t_o,
+ vfloat<N>& u0_o, Vec3vf<N>& Ng0_o,
+ vfloat<N>& u1_o, Vec3vf<N>& Ng1_o) const
+ {
+ /* calculate quadratic equation to solve */
+ const vfloat<N> rl = rcp_length(p1-p0);
+ const Vec3vf<N> P0 = p0, dP = (p1-p0)*rl;
+ const Vec3vf<N> O = Vec3vf<N>(org)-P0, dO = dir;
+
+ const vfloat<N> dOdO = dot(dO,dO);
+ const vfloat<N> OdO = dot(dO,O);
+ const vfloat<N> OO = dot(O,O);
+ const vfloat<N> dOz = dot(dP,dO);
+ const vfloat<N> Oz = dot(dP,O);
+
+ const vfloat<N> A = dOdO - sqr(dOz);
+ const vfloat<N> B = 2.0f * (OdO - dOz*Oz);
+ const vfloat<N> C = OO - sqr(Oz) - rr;
+
+ /* we miss the cylinder if determinant is smaller than zero */
+ const vfloat<N> D = B*B - 4.0f*A*C;
+ vbool<N> valid = D >= 0.0f;
+ if (none(valid)) {
+ t_o = BBox<vfloat<N>>(empty);
+ return valid;
+ }
+
+ /* standard case for rays that are not parallel to the cylinder */
+ const vfloat<N> Q = sqrt(D);
+ const vfloat<N> rcp_2A = rcp(2.0f*A);
+ const vfloat<N> t0 = (-B-Q)*rcp_2A;
+ const vfloat<N> t1 = (-B+Q)*rcp_2A;
+
+ /* calculates u and Ng for near hit */
+ {
+ u0_o = madd(t0,dOz,Oz)*rl;
+ const Vec3vf<N> Pr = t0*Vec3vf<N>(dir);
+ const Vec3vf<N> Pl = madd(u0_o,p1-p0,p0);
+ Ng0_o = Pr-Pl;
+ }
+
+ /* calculates u and Ng for far hit */
+ {
+ u1_o = madd(t1,dOz,Oz)*rl;
+ const Vec3vf<N> Pr = t1*Vec3vf<N>(dir);
+ const Vec3vf<N> Pl = madd(u1_o,p1-p0,p0);
+ Ng1_o = Pr-Pl;
+ }
+
+ t_o.lower = select(valid, t0, vfloat<N>(pos_inf));
+ t_o.upper = select(valid, t1, vfloat<N>(neg_inf));
+
+ /* special case for rays that are parallel to the cylinder */
+ const vfloat<N> eps = 16.0f*float(ulp)*max(abs(dOdO),abs(sqr(dOz)));
+ vbool<N> validt = valid & (abs(A) < eps);
+ if (unlikely(any(validt)))
+ {
+ vbool<N> inside = C <= 0.0f;
+ t_o.lower = select(validt,select(inside,vfloat<N>(neg_inf),vfloat<N>(pos_inf)),t_o.lower);
+ t_o.upper = select(validt,select(inside,vfloat<N>(pos_inf),vfloat<N>(neg_inf)),t_o.upper);
+ valid &= !validt | inside;
+ }
+ return valid;
+ }
+
+ __forceinline vbool<N> intersect(const Vec3fa& org_i, const Vec3fa& dir, BBox<vfloat<N>>& t_o) const
+ {
+ vfloat<N> u0_o; Vec3vf<N> Ng0_o;
+ vfloat<N> u1_o; Vec3vf<N> Ng1_o;
+ return intersect(org_i,dir,t_o,u0_o,Ng0_o,u1_o,Ng1_o);
+ }
+ };
+ }
+}
+
diff --git a/thirdparty/embree/kernels/geometry/disc_intersector.h b/thirdparty/embree/kernels/geometry/disc_intersector.h
new file mode 100644
index 0000000000..816c066899
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/disc_intersector.h
@@ -0,0 +1,216 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/scene_points.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct DiscIntersectorHitM
+ {
+ __forceinline DiscIntersectorHitM() {}
+
+ __forceinline DiscIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)
+ : vu(u), vv(v), vt(t), vNg(Ng)
+ {
+ }
+
+ __forceinline void finalize() {}
+
+ __forceinline Vec2f uv(const size_t i) const
+ {
+ return Vec2f(vu[i], vv[i]);
+ }
+ __forceinline float t(const size_t i) const
+ {
+ return vt[i];
+ }
+ __forceinline Vec3fa Ng(const size_t i) const
+ {
+ return Vec3fa(vNg.x[i], vNg.y[i], vNg.z[i]);
+ }
+
+ public:
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct DiscIntersector1
+ {
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(
+ const vbool<M>& valid_i,
+ Ray& ray,
+ IntersectContext* context,
+ const Points* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+ const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);
+ const vfloat<M> rd2 = rcp(dot(ray_dir, ray_dir));
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ const Vec3vf<M> c0 = center - ray_org;
+ const vfloat<M> projC0 = dot(c0, ray_dir) * rd2;
+
+ valid &= (vfloat<M>(ray.tnear()) <= projC0) & (projC0 <= vfloat<M>(ray.tfar));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= projC0 > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR) * radius * pre.depth_scale; // ignore self intersections
+ if (unlikely(none(valid)))
+ return false;
+
+ const Vec3vf<M> perp = c0 - projC0 * ray_dir;
+ const vfloat<M> l2 = dot(perp, perp);
+ const vfloat<M> r2 = radius * radius;
+ valid &= (l2 <= r2);
+ if (unlikely(none(valid)))
+ return false;
+
+ DiscIntersectorHitM<M> hit(zero, zero, projC0, -ray_dir);
+ return epilog(valid, hit);
+ }
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ Ray& ray,
+ IntersectContext* context,
+ const Points* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i,
+ const Vec3vf<M>& normal,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ vfloat<M> divisor = dot(Vec3vf<M>((Vec3fa)ray.dir), normal);
+ const vbool<M> parallel = divisor == vfloat<M>(0.f);
+ valid &= !parallel;
+ divisor = select(parallel, 1.f, divisor); // prevent divide by zero
+
+ vfloat<M> t = dot(center - Vec3vf<M>((Vec3fa)ray.org), Vec3vf<M>(normal)) / divisor;
+
+ valid &= (vfloat<M>(ray.tnear()) <= t) & (t <= vfloat<M>(ray.tfar));
+ if (unlikely(none(valid)))
+ return false;
+
+ Vec3vf<M> intersection = Vec3vf<M>((Vec3fa)ray.org) + Vec3vf<M>((Vec3fa)ray.dir) * t;
+ vfloat<M> dist2 = dot(intersection - center, intersection - center);
+ valid &= dist2 < radius * radius;
+ if (unlikely(none(valid)))
+ return false;
+
+ DiscIntersectorHitM<M> hit(zero, zero, t, normal);
+ return epilog(valid, hit);
+ }
+ };
+
+ template<int M, int K>
+ struct DiscIntersectorK
+ {
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray,
+ size_t k,
+ IntersectContext* context,
+ const Points* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
+ const vfloat<M> rd2 = rcp(dot(ray_dir, ray_dir));
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ const Vec3vf<M> c0 = center - ray_org;
+ const vfloat<M> projC0 = dot(c0, ray_dir) * rd2;
+
+ valid &= (vfloat<M>(ray.tnear()[k]) <= projC0) & (projC0 <= vfloat<M>(ray.tfar[k]));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= projC0 > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR) * radius * pre.depth_scale[k]; // ignore self intersections
+ if (unlikely(none(valid)))
+ return false;
+
+ const Vec3vf<M> perp = c0 - projC0 * ray_dir;
+ const vfloat<M> l2 = dot(perp, perp);
+ const vfloat<M> r2 = radius * radius;
+ valid &= (l2 <= r2);
+ if (unlikely(none(valid)))
+ return false;
+
+ DiscIntersectorHitM<M> hit(zero, zero, projC0, -ray_dir);
+ return epilog(valid, hit);
+ }
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray,
+ size_t k,
+ IntersectContext* context,
+ const Points* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i,
+ const Vec3vf<M>& normal,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+ const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ vfloat<M> divisor = dot(Vec3vf<M>(ray_dir), normal);
+ const vbool<M> parallel = divisor == vfloat<M>(0.f);
+ valid &= !parallel;
+ divisor = select(parallel, 1.f, divisor); // prevent divide by zero
+
+ vfloat<M> t = dot(center - Vec3vf<M>(ray_org), Vec3vf<M>(normal)) / divisor;
+
+ valid &= (vfloat<M>(ray.tnear()[k]) <= t) & (t <= vfloat<M>(ray.tfar[k]));
+ if (unlikely(none(valid)))
+ return false;
+
+ Vec3vf<M> intersection = Vec3vf<M>(ray_org) + Vec3vf<M>(ray_dir) * t;
+ vfloat<M> dist2 = dot(intersection - center, intersection - center);
+ valid &= dist2 < radius * radius;
+ if (unlikely(none(valid)))
+ return false;
+
+ DiscIntersectorHitM<M> hit(zero, zero, t, normal);
+ return epilog(valid, hit);
+ }
+ };
+ } // namespace isa
+} // namespace embree
diff --git a/thirdparty/embree/kernels/geometry/disci_intersector.h b/thirdparty/embree/kernels/geometry/disci_intersector.h
new file mode 100644
index 0000000000..bb9d396f6e
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/disci_intersector.h
@@ -0,0 +1,277 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "disc_intersector.h"
+#include "intersector_epilog.h"
+#include "pointi.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, bool filter>
+ struct DiscMiIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom);
+ const vbool<M> valid = Disc.valid();
+ DiscIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, Intersect1EpilogM<M, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom);
+ const vbool<M> valid = Disc.valid();
+ return DiscIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, Occluded1EpilogM<M, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, bool filter>
+ struct DiscMiMBIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom, ray.time());
+ const vbool<M> valid = Disc.valid();
+ DiscIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, Intersect1EpilogM<M, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom, ray.time());
+ const vbool<M> valid = Disc.valid();
+ return DiscIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, Occluded1EpilogM<M, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct DiscMiIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom);
+ const vbool<M> valid = Disc.valid();
+ DiscIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Intersect1KEpilogM<M, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom);
+ const vbool<M> valid = Disc.valid();
+ return DiscIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Occluded1KEpilogM<M, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct DiscMiMBIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom, ray.time()[k]);
+ const vbool<M> valid = Disc.valid();
+ DiscIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Intersect1KEpilogM<M, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Disc.gather(v0, geom, ray.time()[k]);
+ const vbool<M> valid = Disc.valid();
+ return DiscIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0, Occluded1KEpilogM<M, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, bool filter>
+ struct OrientedDiscMiIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom);
+ const vbool<M> valid = Disc.valid();
+ DiscIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, n0, Intersect1EpilogM<M, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom);
+ const vbool<M> valid = Disc.valid();
+ return DiscIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, n0, Occluded1EpilogM<M, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, bool filter>
+ struct OrientedDiscMiMBIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom, ray.time());
+ const vbool<M> valid = Disc.valid();
+ DiscIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, n0, Intersect1EpilogM<M, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom, ray.time());
+ const vbool<M> valid = Disc.valid();
+ return DiscIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, n0, Occluded1EpilogM<M, filter>(ray, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct OrientedDiscMiIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom);
+ const vbool<M> valid = Disc.valid();
+ DiscIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0, n0,
+ Intersect1KEpilogM<M, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom);
+ const vbool<M> valid = Disc.valid();
+ return DiscIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0, n0,
+ Occluded1KEpilogM<M, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct OrientedDiscMiMBIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom, ray.time()[k]);
+ const vbool<M> valid = Disc.valid();
+ DiscIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0, n0,
+ Intersect1KEpilogM<M, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(Disc.geomID());
+ Vec4vf<M> v0; Vec3vf<M> n0;
+ Disc.gather(v0, n0, geom, ray.time()[k]);
+ const vbool<M> valid = Disc.valid();
+ return DiscIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0, n0,
+ Occluded1KEpilogM<M, K, filter>(ray, k, context, Disc.geomID(), Disc.primID()));
+ }
+ };
+ } // namespace isa
+} // namespace embree
diff --git a/thirdparty/embree/kernels/geometry/filter.h b/thirdparty/embree/kernels/geometry/filter.h
new file mode 100644
index 0000000000..3b4d924ea7
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/filter.h
@@ -0,0 +1,204 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/geometry.h"
+#include "../common/ray.h"
+#include "../common/hit.h"
+#include "../common/context.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ __forceinline bool runIntersectionFilter1Helper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context)
+ {
+ if (geometry->intersectionFilterN)
+ {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->intersectionFilterN(args);
+
+ if (args->valid[0] == 0)
+ return false;
+ }
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(args);
+
+ if (args->valid[0] == 0)
+ return false;
+ }
+
+ copyHitToRay(*(RayHit*)args->ray,*(Hit*)args->hit);
+ return true;
+ }
+
+ __forceinline bool runIntersectionFilter1(const Geometry* const geometry, RayHit& ray, IntersectContext* context, Hit& hit)
+ {
+ RTCFilterFunctionNArguments args;
+ int mask = -1;
+ args.valid = &mask;
+ args.geometryUserPtr = geometry->userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.hit = (RTCHitN*)&hit;
+ args.N = 1;
+ return runIntersectionFilter1Helper(&args,geometry,context);
+ }
+
+ __forceinline void reportIntersection1(IntersectFunctionNArguments* args, const RTCFilterFunctionNArguments* filter_args)
+ {
+#if defined(EMBREE_FILTER_FUNCTION)
+ IntersectContext* MAYBE_UNUSED context = args->internal_context;
+ const Geometry* const geometry = args->geometry;
+ if (geometry->intersectionFilterN) {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->intersectionFilterN(filter_args);
+ }
+
+ //if (args->valid[0] == 0)
+ // return;
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(filter_args);
+ }
+#endif
+ }
+
+ __forceinline bool runOcclusionFilter1Helper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context)
+ {
+ if (geometry->occlusionFilterN)
+ {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->occlusionFilterN(args);
+
+ if (args->valid[0] == 0)
+ return false;
+ }
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(args);
+
+ if (args->valid[0] == 0)
+ return false;
+ }
+ return true;
+ }
+
+ __forceinline bool runOcclusionFilter1(const Geometry* const geometry, Ray& ray, IntersectContext* context, Hit& hit)
+ {
+ RTCFilterFunctionNArguments args;
+ int mask = -1;
+ args.valid = &mask;
+ args.geometryUserPtr = geometry->userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.hit = (RTCHitN*)&hit;
+ args.N = 1;
+ return runOcclusionFilter1Helper(&args,geometry,context);
+ }
+
+ __forceinline void reportOcclusion1(OccludedFunctionNArguments* args, const RTCFilterFunctionNArguments* filter_args)
+ {
+#if defined(EMBREE_FILTER_FUNCTION)
+ IntersectContext* MAYBE_UNUSED context = args->internal_context;
+ const Geometry* const geometry = args->geometry;
+ if (geometry->occlusionFilterN) {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->occlusionFilterN(filter_args);
+ }
+
+ //if (args->valid[0] == 0)
+ // return false;
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(filter_args);
+ }
+#endif
+ }
+
+ template<int K>
+ __forceinline vbool<K> runIntersectionFilterHelper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context)
+ {
+ vint<K>* mask = (vint<K>*) args->valid;
+ if (geometry->intersectionFilterN)
+ {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->intersectionFilterN(args);
+ }
+
+ vbool<K> valid_o = *mask != vint<K>(zero);
+ if (none(valid_o)) return valid_o;
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(args);
+ }
+
+ valid_o = *mask != vint<K>(zero);
+ if (none(valid_o)) return valid_o;
+
+ copyHitToRay(valid_o,*(RayHitK<K>*)args->ray,*(HitK<K>*)args->hit);
+ return valid_o;
+ }
+
+ template<int K>
+ __forceinline vbool<K> runIntersectionFilter(const vbool<K>& valid, const Geometry* const geometry, RayHitK<K>& ray, IntersectContext* context, HitK<K>& hit)
+ {
+ RTCFilterFunctionNArguments args;
+ vint<K> mask = valid.mask32();
+ args.valid = (int*)&mask;
+ args.geometryUserPtr = geometry->userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.hit = (RTCHitN*)&hit;
+ args.N = K;
+ return runIntersectionFilterHelper<K>(&args,geometry,context);
+ }
+
+ template<int K>
+ __forceinline vbool<K> runOcclusionFilterHelper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context)
+ {
+ vint<K>* mask = (vint<K>*) args->valid;
+ if (geometry->occlusionFilterN)
+ {
+ assert(context->scene->hasGeometryFilterFunction());
+ geometry->occlusionFilterN(args);
+ }
+
+ vbool<K> valid_o = *mask != vint<K>(zero);
+
+ if (none(valid_o)) return valid_o;
+
+ if (context->user->filter) {
+ assert(context->scene->hasContextFilterFunction());
+ context->user->filter(args);
+ }
+
+ valid_o = *mask != vint<K>(zero);
+
+ RayK<K>* ray = (RayK<K>*) args->ray;
+ ray->tfar = select(valid_o, vfloat<K>(neg_inf), ray->tfar);
+ return valid_o;
+ }
+
+ template<int K>
+ __forceinline vbool<K> runOcclusionFilter(const vbool<K>& valid, const Geometry* const geometry, RayK<K>& ray, IntersectContext* context, HitK<K>& hit)
+ {
+ RTCFilterFunctionNArguments args;
+ vint<K> mask = valid.mask32();
+ args.valid = (int*)&mask;
+ args.geometryUserPtr = geometry->userPtr;
+ args.context = context->user;
+ args.ray = (RTCRayN*)&ray;
+ args.hit = (RTCHitN*)&hit;
+ args.N = K;
+ return runOcclusionFilterHelper<K>(&args,geometry,context);
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/grid_intersector.h b/thirdparty/embree/kernels/geometry/grid_intersector.h
new file mode 100644
index 0000000000..9c59cef119
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/grid_intersector.h
@@ -0,0 +1,99 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "grid_soa.h"
+#include "grid_soa_intersector1.h"
+#include "grid_soa_intersector_packet.h"
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename T>
+ class SubdivPatch1Precalculations : public T
+ {
+ public:
+ __forceinline SubdivPatch1Precalculations (const Ray& ray, const void* ptr)
+ : T(ray,ptr) {}
+ };
+
+ template<int K, typename T>
+ class SubdivPatch1PrecalculationsK : public T
+ {
+ public:
+ __forceinline SubdivPatch1PrecalculationsK (const vbool<K>& valid, RayK<K>& ray)
+ : T(valid,ray) {}
+ };
+
+ class Grid1Intersector1
+ {
+ public:
+ typedef GridSOA Primitive;
+ typedef Grid1Precalculations<GridSOAIntersector1::Precalculations> Precalculations;
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersector1::intersect(pre,ray,context,prim,lazy_node);
+ }
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, size_t& lazy_node) {
+ intersect(pre,ray,context,prim,ty,lazy_node);
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersector1::occluded(pre,ray,context,prim,lazy_node);
+ }
+ static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, size_t& lazy_node) {
+ return occluded(pre,ray,context,prim,ty,lazy_node);
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) {
+ assert(false && "not implemented");
+ return false;
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, size_t& lazy_node) {
+ assert(false && "not implemented");
+ return false;
+ }
+ };
+
+ template <int K>
+ struct GridIntersectorK
+ {
+ typedef GridSOA Primitive;
+ typedef SubdivPatch1PrecalculationsK<K,typename GridSOAIntersectorK<K>::Precalculations> Precalculations;
+
+
+ static __forceinline void intersect(const vbool<K>& valid, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersectorK<K>::intersect(valid,pre,ray,context,prim,lazy_node);
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersectorK<K>::occluded(valid,pre,ray,context,prim,lazy_node);
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersectorK<K>::intersect(pre,ray,k,context,prim,lazy_node);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node)
+ {
+ GridSOAIntersectorK<K>::occluded(pre,ray,k,context,prim,lazy_node);
+ }
+ };
+
+ typedef Grid1IntersectorK<4> SubdivPatch1Intersector4;
+ typedef Grid1IntersectorK<8> SubdivPatch1Intersector8;
+ typedef Grid1IntersectorK<16> SubdivPatch1Intersector16;
+
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/grid_soa.h b/thirdparty/embree/kernels/geometry/grid_soa.h
new file mode 100644
index 0000000000..cea90aedf6
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/grid_soa.h
@@ -0,0 +1,275 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/scene_subdiv_mesh.h"
+#include "../bvh/bvh.h"
+#include "../subdiv/tessellation.h"
+#include "../subdiv/tessellation_cache.h"
+#include "subdivpatch1.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ class GridSOA
+ {
+ public:
+
+ /*! GridSOA constructor */
+ GridSOA(const SubdivPatch1Base* patches, const unsigned time_steps,
+ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
+ const SubdivMesh* const geom, const size_t totalBvhBytes, const size_t gridBytes, BBox3fa* bounds_o = nullptr);
+
+ /*! Subgrid creation */
+ template<typename Allocator>
+ static GridSOA* create(const SubdivPatch1Base* patches, const unsigned time_steps,
+ unsigned x0, unsigned x1, unsigned y0, unsigned y1,
+ const Scene* scene, Allocator& alloc, BBox3fa* bounds_o = nullptr)
+ {
+ const unsigned width = x1-x0+1;
+ const unsigned height = y1-y0+1;
+ const GridRange range(0,width-1,0,height-1);
+ size_t bvhBytes = 0;
+ if (time_steps == 1)
+ bvhBytes = getBVHBytes(range,sizeof(BVH4::AABBNode),0);
+ else {
+ bvhBytes = (time_steps-1)*getBVHBytes(range,sizeof(BVH4::AABBNodeMB),0);
+ bvhBytes += getTemporalBVHBytes(make_range(0,int(time_steps-1)),sizeof(BVH4::AABBNodeMB4D));
+ }
+ const size_t gridBytes = 4*size_t(width)*size_t(height)*sizeof(float);
+ size_t rootBytes = time_steps*sizeof(BVH4::NodeRef);
+#if !defined(__64BIT__)
+ rootBytes += 4; // We read 2 elements behind the grid. As we store at least 8 root bytes after the grid we are fine in 64 bit mode. But in 32 bit mode we have to do additional padding.
+#endif
+ void* data = alloc(offsetof(GridSOA,data)+bvhBytes+time_steps*gridBytes+rootBytes);
+ assert(data);
+ return new (data) GridSOA(patches,time_steps,x0,x1,y0,y1,patches->grid_u_res,patches->grid_v_res,scene->get<SubdivMesh>(patches->geomID()),bvhBytes,gridBytes,bounds_o);
+ }
+
+ /*! Grid creation */
+ template<typename Allocator>
+ static GridSOA* create(const SubdivPatch1Base* const patches, const unsigned time_steps,
+ const Scene* scene, const Allocator& alloc, BBox3fa* bounds_o = nullptr)
+ {
+ return create(patches,time_steps,0,patches->grid_u_res-1,0,patches->grid_v_res-1,scene,alloc,bounds_o);
+ }
+
+ /*! returns reference to root */
+ __forceinline BVH4::NodeRef& root(size_t t = 0) { return (BVH4::NodeRef&)data[rootOffset + t*sizeof(BVH4::NodeRef)]; }
+ __forceinline const BVH4::NodeRef& root(size_t t = 0) const { return (BVH4::NodeRef&)data[rootOffset + t*sizeof(BVH4::NodeRef)]; }
+
+ /*! returns pointer to BVH array */
+ __forceinline char* bvhData() { return &data[0]; }
+ __forceinline const char* bvhData() const { return &data[0]; }
+
+ /*! returns pointer to Grid array */
+ __forceinline float* gridData(size_t t = 0) { return (float*) &data[gridOffset + t*gridBytes]; }
+ __forceinline const float* gridData(size_t t = 0) const { return (float*) &data[gridOffset + t*gridBytes]; }
+
+ __forceinline void* encodeLeaf(size_t u, size_t v) {
+ return (void*) (16*(v * width + u + 1)); // +1 to not create empty leaf
+ }
+ __forceinline float* decodeLeaf(size_t t, const void* ptr) {
+ return gridData(t) + (((size_t) (ptr) >> 4) - 1);
+ }
+
+ /*! returns the size of the BVH over the grid in bytes */
+ static size_t getBVHBytes(const GridRange& range, const size_t nodeBytes, const size_t leafBytes);
+
+ /*! returns the size of the temporal BVH over the time range BVHs */
+ static size_t getTemporalBVHBytes(const range<int> time_range, const size_t nodeBytes);
+
+ /*! calculates bounding box of grid range */
+ __forceinline BBox3fa calculateBounds(size_t time, const GridRange& range) const
+ {
+ const float* const grid_array = gridData(time);
+ const float* const grid_x_array = grid_array + 0 * dim_offset;
+ const float* const grid_y_array = grid_array + 1 * dim_offset;
+ const float* const grid_z_array = grid_array + 2 * dim_offset;
+
+ /* compute the bounds just for the range! */
+ BBox3fa bounds( empty );
+ for (unsigned v = range.v_start; v<=range.v_end; v++)
+ {
+ for (unsigned u = range.u_start; u<=range.u_end; u++)
+ {
+ const float x = grid_x_array[ v * width + u];
+ const float y = grid_y_array[ v * width + u];
+ const float z = grid_z_array[ v * width + u];
+ bounds.extend( Vec3fa(x,y,z) );
+ }
+ }
+ assert(is_finite(bounds));
+ return bounds;
+ }
+
+ /*! Evaluates grid over patch and builds BVH4 tree over the grid. */
+ std::pair<BVH4::NodeRef,BBox3fa> buildBVH(BBox3fa* bounds_o);
+
+ /*! Create BVH4 tree over grid. */
+ std::pair<BVH4::NodeRef,BBox3fa> buildBVH(const GridRange& range, size_t& allocator);
+
+ /*! Evaluates grid over patch and builds MSMBlur BVH4 tree over the grid. */
+ std::pair<BVH4::NodeRef,LBBox3fa> buildMSMBlurBVH(const range<int> time_range, BBox3fa* bounds_o);
+
+ /*! Create MBlur BVH4 tree over grid. */
+ std::pair<BVH4::NodeRef,LBBox3fa> buildMBlurBVH(size_t time, const GridRange& range, size_t& allocator);
+
+ /*! Create MSMBlur BVH4 tree over grid. */
+ std::pair<BVH4::NodeRef,LBBox3fa> buildMSMBlurBVH(const range<int> time_range, size_t& allocator, BBox3fa* bounds_o);
+
+ template<typename Loader>
+ struct MapUV
+ {
+ typedef typename Loader::vfloat vfloat;
+ const float* const grid_uv;
+ size_t line_offset;
+ size_t lines;
+
+ __forceinline MapUV(const float* const grid_uv, size_t line_offset, const size_t lines)
+ : grid_uv(grid_uv), line_offset(line_offset), lines(lines) {}
+
+ __forceinline void operator() (vfloat& u, vfloat& v, Vec3<vfloat>& Ng) const {
+ const Vec3<vfloat> tri_v012_uv = Loader::gather(grid_uv,line_offset,lines);
+ const Vec2<vfloat> uv0 = GridSOA::decodeUV(tri_v012_uv[0]);
+ const Vec2<vfloat> uv1 = GridSOA::decodeUV(tri_v012_uv[1]);
+ const Vec2<vfloat> uv2 = GridSOA::decodeUV(tri_v012_uv[2]);
+ const Vec2<vfloat> uv = u * uv1 + v * uv2 + (1.0f-u-v) * uv0;
+ u = uv[0];v = uv[1];
+ }
+ };
+
+ struct Gather2x3
+ {
+ enum { M = 4 };
+ typedef vbool4 vbool;
+ typedef vint4 vint;
+ typedef vfloat4 vfloat;
+
+ static __forceinline const Vec3vf4 gather(const float* const grid, const size_t line_offset, const size_t lines)
+ {
+ vfloat4 r0 = vfloat4::loadu(grid + 0*line_offset);
+ vfloat4 r1 = vfloat4::loadu(grid + 1*line_offset); // this accesses 2 elements too much in case of 2x2 grid, but this is ok as we ensure enough padding after the grid
+ if (unlikely(line_offset == 2))
+ {
+ r0 = shuffle<0,1,1,1>(r0);
+ r1 = shuffle<0,1,1,1>(r1);
+ }
+ return Vec3vf4(unpacklo(r0,r1), // r00, r10, r01, r11
+ shuffle<1,1,2,2>(r0), // r01, r01, r02, r02
+ shuffle<0,1,1,2>(r1)); // r10, r11, r11, r12
+ }
+
+ static __forceinline void gather(const float* const grid_x,
+ const float* const grid_y,
+ const float* const grid_z,
+ const size_t line_offset,
+ const size_t lines,
+ Vec3vf4& v0_o,
+ Vec3vf4& v1_o,
+ Vec3vf4& v2_o)
+ {
+ const Vec3vf4 tri_v012_x = gather(grid_x,line_offset,lines);
+ const Vec3vf4 tri_v012_y = gather(grid_y,line_offset,lines);
+ const Vec3vf4 tri_v012_z = gather(grid_z,line_offset,lines);
+ v0_o = Vec3vf4(tri_v012_x[0],tri_v012_y[0],tri_v012_z[0]);
+ v1_o = Vec3vf4(tri_v012_x[1],tri_v012_y[1],tri_v012_z[1]);
+ v2_o = Vec3vf4(tri_v012_x[2],tri_v012_y[2],tri_v012_z[2]);
+ }
+ };
+
+#if defined (__AVX__)
+ struct Gather3x3
+ {
+ enum { M = 8 };
+ typedef vbool8 vbool;
+ typedef vint8 vint;
+ typedef vfloat8 vfloat;
+
+ static __forceinline const Vec3vf8 gather(const float* const grid, const size_t line_offset, const size_t lines)
+ {
+ vfloat4 ra = vfloat4::loadu(grid + 0*line_offset);
+ vfloat4 rb = vfloat4::loadu(grid + 1*line_offset); // this accesses 2 elements too much in case of 2x2 grid, but this is ok as we ensure enough padding after the grid
+ vfloat4 rc;
+ if (likely(lines > 2))
+ rc = vfloat4::loadu(grid + 2*line_offset);
+ else
+ rc = rb;
+
+ if (unlikely(line_offset == 2))
+ {
+ ra = shuffle<0,1,1,1>(ra);
+ rb = shuffle<0,1,1,1>(rb);
+ rc = shuffle<0,1,1,1>(rc);
+ }
+
+ const vfloat8 r0 = vfloat8(ra,rb);
+ const vfloat8 r1 = vfloat8(rb,rc);
+ return Vec3vf8(unpacklo(r0,r1), // r00, r10, r01, r11, r10, r20, r11, r21
+ shuffle<1,1,2,2>(r0), // r01, r01, r02, r02, r11, r11, r12, r12
+ shuffle<0,1,1,2>(r1)); // r10, r11, r11, r12, r20, r21, r21, r22
+ }
+
+ static __forceinline void gather(const float* const grid_x,
+ const float* const grid_y,
+ const float* const grid_z,
+ const size_t line_offset,
+ const size_t lines,
+ Vec3vf8& v0_o,
+ Vec3vf8& v1_o,
+ Vec3vf8& v2_o)
+ {
+ const Vec3vf8 tri_v012_x = gather(grid_x,line_offset,lines);
+ const Vec3vf8 tri_v012_y = gather(grid_y,line_offset,lines);
+ const Vec3vf8 tri_v012_z = gather(grid_z,line_offset,lines);
+ v0_o = Vec3vf8(tri_v012_x[0],tri_v012_y[0],tri_v012_z[0]);
+ v1_o = Vec3vf8(tri_v012_x[1],tri_v012_y[1],tri_v012_z[1]);
+ v2_o = Vec3vf8(tri_v012_x[2],tri_v012_y[2],tri_v012_z[2]);
+ }
+ };
+#endif
+
+ template<typename vfloat>
+ static __forceinline Vec2<vfloat> decodeUV(const vfloat& uv)
+ {
+ typedef typename vfloat::Int vint;
+ const vint iu = asInt(uv) & 0xffff;
+ const vint iv = srl(asInt(uv),16);
+ const vfloat u = (vfloat)iu * vfloat(8.0f/0x10000);
+ const vfloat v = (vfloat)iv * vfloat(8.0f/0x10000);
+ return Vec2<vfloat>(u,v);
+ }
+
+ __forceinline unsigned int geomID() const {
+ return _geomID;
+ }
+
+ __forceinline unsigned int primID() const {
+ return _primID;
+ }
+
+ public:
+ BVH4::NodeRef troot;
+#if !defined(__64BIT__)
+ unsigned align1;
+#endif
+ unsigned time_steps;
+ unsigned width;
+
+ unsigned height;
+ unsigned dim_offset;
+ unsigned _geomID;
+ unsigned _primID;
+
+ unsigned align2;
+ unsigned gridOffset;
+ unsigned gridBytes;
+ unsigned rootOffset;
+
+ char data[1]; //!< after the struct we first store the BVH, then the grid, and finally the roots
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/grid_soa_intersector1.h b/thirdparty/embree/kernels/geometry/grid_soa_intersector1.h
new file mode 100644
index 0000000000..8fbf0d4bdf
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/grid_soa_intersector1.h
@@ -0,0 +1,207 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "grid_soa.h"
+#include "../common/ray.h"
+#include "triangle_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ class GridSOAIntersector1
+ {
+ public:
+ typedef void Primitive;
+
+ class Precalculations
+ {
+ public:
+ __forceinline Precalculations (const Ray& ray, const void* ptr)
+ : grid(nullptr) {}
+
+ public:
+ GridSOA* grid;
+ int itime;
+ float ftime;
+ };
+
+ template<typename Loader>
+ static __forceinline void intersect(RayHit& ray,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+ Vec3<vfloat> v0, v1, v2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,v0,v1,v2);
+ GridSOA::MapUV<Loader> mapUV(grid_uv,line_offset,lines);
+ PlueckerIntersector1<Loader::M> intersector(ray,nullptr);
+ intersector.intersect(ray,v0,v1,v2,mapUV,Intersect1EpilogMU<Loader::M,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ };
+
+ template<typename Loader>
+ static __forceinline bool occluded(Ray& ray,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ Vec3<vfloat> v0, v1, v2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,v0,v1,v2);
+
+ GridSOA::MapUV<Loader> mapUV(grid_uv,line_offset,lines);
+ PlueckerIntersector1<Loader::M> intersector(ray,nullptr);
+ return intersector.intersect(ray,v0,v1,v2,mapUV,Occluded1EpilogMU<Loader::M,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+
+#if defined(__AVX__)
+ intersect<GridSOA::Gather3x3>( ray, context, grid_x, line_offset, lines, pre);
+#else
+ intersect<GridSOA::Gather2x3>(ray, context, grid_x , line_offset, lines, pre);
+ if (likely(lines > 2))
+ intersect<GridSOA::Gather2x3>(ray, context, grid_x+line_offset, line_offset, lines, pre);
+#endif
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+
+#if defined(__AVX__)
+ return occluded<GridSOA::Gather3x3>( ray, context, grid_x, line_offset, lines, pre);
+#else
+ if (occluded<GridSOA::Gather2x3>(ray, context, grid_x , line_offset, lines, pre)) return true;
+ if (likely(lines > 2))
+ if (occluded<GridSOA::Gather2x3>(ray, context, grid_x+line_offset, line_offset, lines, pre)) return true;
+#endif
+ return false;
+ }
+ };
+
+ class GridSOAMBIntersector1
+ {
+ public:
+ typedef void Primitive;
+ typedef GridSOAIntersector1::Precalculations Precalculations;
+
+ template<typename Loader>
+ static __forceinline void intersect(RayHit& ray, const float ftime,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ Vec3<vfloat> a0, a1, a2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,a0,a1,a2);
+
+ Vec3<vfloat> b0, b1, b2;
+ Loader::gather(grid_x+grid_offset,grid_y+grid_offset,grid_z+grid_offset,line_offset,lines,b0,b1,b2);
+
+ Vec3<vfloat> v0 = lerp(a0,b0,vfloat(ftime));
+ Vec3<vfloat> v1 = lerp(a1,b1,vfloat(ftime));
+ Vec3<vfloat> v2 = lerp(a2,b2,vfloat(ftime));
+
+ GridSOA::MapUV<Loader> mapUV(grid_uv,line_offset,lines);
+ PlueckerIntersector1<Loader::M> intersector(ray,nullptr);
+ intersector.intersect(ray,v0,v1,v2,mapUV,Intersect1EpilogMU<Loader::M,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ };
+
+ template<typename Loader>
+ static __forceinline bool occluded(Ray& ray, const float ftime,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ Vec3<vfloat> a0, a1, a2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,a0,a1,a2);
+
+ Vec3<vfloat> b0, b1, b2;
+ Loader::gather(grid_x+grid_offset,grid_y+grid_offset,grid_z+grid_offset,line_offset,lines,b0,b1,b2);
+
+ Vec3<vfloat> v0 = lerp(a0,b0,vfloat(ftime));
+ Vec3<vfloat> v1 = lerp(a1,b1,vfloat(ftime));
+ Vec3<vfloat> v2 = lerp(a2,b2,vfloat(ftime));
+
+ GridSOA::MapUV<Loader> mapUV(grid_uv,line_offset,lines);
+ PlueckerIntersector1<Loader::M> intersector(ray,nullptr);
+ return intersector.intersect(ray,v0,v1,v2,mapUV,Occluded1EpilogMU<Loader::M,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(pre.itime,prim);
+
+#if defined(__AVX__)
+ intersect<GridSOA::Gather3x3>( ray, pre.ftime, context, grid_x, line_offset, lines, pre);
+#else
+ intersect<GridSOA::Gather2x3>(ray, pre.ftime, context, grid_x, line_offset, lines, pre);
+ if (likely(lines > 2))
+ intersect<GridSOA::Gather2x3>(ray, pre.ftime, context, grid_x+line_offset, line_offset, lines, pre);
+#endif
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(pre.itime,prim);
+
+#if defined(__AVX__)
+ return occluded<GridSOA::Gather3x3>( ray, pre.ftime, context, grid_x, line_offset, lines, pre);
+#else
+ if (occluded<GridSOA::Gather2x3>(ray, pre.ftime, context, grid_x , line_offset, lines, pre)) return true;
+ if (likely(lines > 2))
+ if (occluded<GridSOA::Gather2x3>(ray, pre.ftime, context, grid_x+line_offset, line_offset, lines, pre)) return true;
+#endif
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/grid_soa_intersector_packet.h b/thirdparty/embree/kernels/geometry/grid_soa_intersector_packet.h
new file mode 100644
index 0000000000..14cacab5fe
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/grid_soa_intersector_packet.h
@@ -0,0 +1,445 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "grid_soa.h"
+#include "../common/ray.h"
+#include "triangle_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int K>
+ struct MapUV0
+ {
+ const float* const grid_uv;
+ size_t ofs00, ofs01, ofs10, ofs11;
+
+ __forceinline MapUV0(const float* const grid_uv, size_t ofs00, size_t ofs01, size_t ofs10, size_t ofs11)
+ : grid_uv(grid_uv), ofs00(ofs00), ofs01(ofs01), ofs10(ofs10), ofs11(ofs11) {}
+
+ __forceinline void operator() (vfloat<K>& u, vfloat<K>& v, Vec3vf<K>& Ng) const {
+ const vfloat<K> uv00(grid_uv[ofs00]);
+ const vfloat<K> uv01(grid_uv[ofs01]);
+ const vfloat<K> uv10(grid_uv[ofs10]);
+ const vfloat<K> uv11(grid_uv[ofs11]);
+ const Vec2vf<K> uv0 = GridSOA::decodeUV(uv00);
+ const Vec2vf<K> uv1 = GridSOA::decodeUV(uv01);
+ const Vec2vf<K> uv2 = GridSOA::decodeUV(uv10);
+ const Vec2vf<K> uv = madd(u,uv1,madd(v,uv2,(1.0f-u-v)*uv0));
+ u = uv[0]; v = uv[1];
+ }
+ };
+
+ template<int K>
+ struct MapUV1
+ {
+ const float* const grid_uv;
+ size_t ofs00, ofs01, ofs10, ofs11;
+
+ __forceinline MapUV1(const float* const grid_uv, size_t ofs00, size_t ofs01, size_t ofs10, size_t ofs11)
+ : grid_uv(grid_uv), ofs00(ofs00), ofs01(ofs01), ofs10(ofs10), ofs11(ofs11) {}
+
+ __forceinline void operator() (vfloat<K>& u, vfloat<K>& v, Vec3vf<K>& Ng) const {
+ const vfloat<K> uv00(grid_uv[ofs00]);
+ const vfloat<K> uv01(grid_uv[ofs01]);
+ const vfloat<K> uv10(grid_uv[ofs10]);
+ const vfloat<K> uv11(grid_uv[ofs11]);
+ const Vec2vf<K> uv0 = GridSOA::decodeUV(uv10);
+ const Vec2vf<K> uv1 = GridSOA::decodeUV(uv01);
+ const Vec2vf<K> uv2 = GridSOA::decodeUV(uv11);
+ const Vec2vf<K> uv = madd(u,uv1,madd(v,uv2,(1.0f-u-v)*uv0));
+ u = uv[0]; v = uv[1];
+ }
+ };
+
+ template<int K>
+ class GridSOAIntersectorK
+ {
+ public:
+ typedef void Primitive;
+
+ class Precalculations
+ {
+#if defined(__AVX__)
+ static const int M = 8;
+#else
+ static const int M = 4;
+#endif
+
+ public:
+ __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray)
+ : grid(nullptr), intersector(valid,ray) {}
+
+ public:
+ GridSOA* grid;
+ PlueckerIntersectorK<M,K> intersector; // FIXME: use quad intersector
+ };
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t line_offset = pre.grid->width;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ const size_t max_x = pre.grid->width == 2 ? 1 : 2;
+ const size_t max_y = pre.grid->height == 2 ? 1 : 2;
+ for (size_t y=0; y<max_y; y++)
+ {
+ for (size_t x=0; x<max_x; x++)
+ {
+ const size_t ofs00 = (y+0)*line_offset+(x+0);
+ const size_t ofs01 = (y+0)*line_offset+(x+1);
+ const size_t ofs10 = (y+1)*line_offset+(x+0);
+ const size_t ofs11 = (y+1)*line_offset+(x+1);
+ const Vec3vf<K> p00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> p01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> p10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> p11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+
+ pre.intersector.intersectK(valid_i,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ pre.intersector.intersectK(valid_i,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+ }
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t line_offset = pre.grid->width;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ vbool<K> valid = valid_i;
+ const size_t max_x = pre.grid->width == 2 ? 1 : 2;
+ const size_t max_y = pre.grid->height == 2 ? 1 : 2;
+ for (size_t y=0; y<max_y; y++)
+ {
+ for (size_t x=0; x<max_x; x++)
+ {
+ const size_t ofs00 = (y+0)*line_offset+(x+0);
+ const size_t ofs01 = (y+0)*line_offset+(x+1);
+ const size_t ofs10 = (y+1)*line_offset+(x+0);
+ const size_t ofs11 = (y+1)*line_offset+(x+1);
+ const Vec3vf<K> p00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> p01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> p10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> p11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+
+ pre.intersector.intersectK(valid,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
+ if (none(valid)) break;
+ pre.intersector.intersectK(valid,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
+ if (none(valid)) break;
+ }
+ }
+ return !valid;
+ }
+
+ template<typename Loader>
+ static __forceinline void intersect(RayHitK<K>& ray, size_t k,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+ Vec3<vfloat> v0, v1, v2; Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,v0,v1,v2);
+ pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Intersect1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
+ };
+
+ template<typename Loader>
+ static __forceinline bool occluded(RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+ Vec3<vfloat> v0, v1, v2; Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,v0,v1,v2);
+ return pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Occluded1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+#if defined(__AVX__)
+ intersect<GridSOA::Gather3x3>( ray, k, context, grid_x, line_offset, lines, pre);
+#else
+ intersect<GridSOA::Gather2x3>(ray, k, context, grid_x , line_offset, lines, pre);
+ if (likely(lines > 2))
+ intersect<GridSOA::Gather2x3>(ray, k, context, grid_x+line_offset, line_offset, lines, pre);
+#endif
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(0,prim);
+
+#if defined(__AVX__)
+ return occluded<GridSOA::Gather3x3>( ray, k, context, grid_x, line_offset, lines, pre);
+#else
+ if (occluded<GridSOA::Gather2x3>(ray, k, context, grid_x , line_offset, lines, pre)) return true;
+ if (likely(lines > 2))
+ if (occluded<GridSOA::Gather2x3>(ray, k, context, grid_x+line_offset, line_offset, lines, pre)) return true;
+#endif
+ return false;
+ }
+ };
+
+ template<int K>
+ class GridSOAMBIntersectorK
+ {
+ public:
+ typedef void Primitive;
+ typedef typename GridSOAIntersectorK<K>::Precalculations Precalculations;
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ vfloat<K> vftime;
+ vint<K> vitime = getTimeSegment<K>(ray.time(), vfloat<K>((float)(pre.grid->time_steps-1)), vftime);
+
+ vbool<K> valid1 = valid_i;
+ while (any(valid1)) {
+ const size_t j = bsf(movemask(valid1));
+ const int itime = vitime[j];
+ const vbool<K> valid2 = valid1 & (itime == vitime);
+ valid1 = valid1 & !valid2;
+ intersect(valid2,pre,ray,vftime,itime,context,prim,lazy_node);
+ }
+ }
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, const vfloat<K>& ftime, int itime, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t line_offset = pre.grid->width;
+ const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ const size_t max_x = pre.grid->width == 2 ? 1 : 2;
+ const size_t max_y = pre.grid->height == 2 ? 1 : 2;
+ for (size_t y=0; y<max_y; y++)
+ {
+ for (size_t x=0; x<max_x; x++)
+ {
+ size_t ofs00 = (y+0)*line_offset+(x+0);
+ size_t ofs01 = (y+0)*line_offset+(x+1);
+ size_t ofs10 = (y+1)*line_offset+(x+0);
+ size_t ofs11 = (y+1)*line_offset+(x+1);
+ const Vec3vf<K> a00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> a01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> a10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> a11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+ ofs00 += grid_offset;
+ ofs01 += grid_offset;
+ ofs10 += grid_offset;
+ ofs11 += grid_offset;
+ const Vec3vf<K> b00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> b01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> b10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> b11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+ const Vec3vf<K> p00 = lerp(a00,b00,ftime);
+ const Vec3vf<K> p01 = lerp(a01,b01,ftime);
+ const Vec3vf<K> p10 = lerp(a10,b10,ftime);
+ const Vec3vf<K> p11 = lerp(a11,b11,ftime);
+
+ pre.intersector.intersectK(valid_i,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ pre.intersector.intersectK(valid_i,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),IntersectKEpilogMU<1,K,true>(ray,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+ }
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ vfloat<K> vftime;
+ vint<K> vitime = getTimeSegment<K>(ray.time(), vfloat<K>((float)(pre.grid->time_steps-1)), vftime);
+
+ vbool<K> valid_o = valid_i;
+ vbool<K> valid1 = valid_i;
+ while (any(valid1)) {
+ const int j = int(bsf(movemask(valid1)));
+ const int itime = vitime[j];
+ const vbool<K> valid2 = valid1 & (itime == vitime);
+ valid1 = valid1 & !valid2;
+ valid_o &= !valid2 | occluded(valid2,pre,ray,vftime,itime,context,prim,lazy_node);
+ }
+ return !valid_o;
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, const vfloat<K>& ftime, int itime, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const size_t line_offset = pre.grid->width;
+ const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ vbool<K> valid = valid_i;
+ const size_t max_x = pre.grid->width == 2 ? 1 : 2;
+ const size_t max_y = pre.grid->height == 2 ? 1 : 2;
+ for (size_t y=0; y<max_y; y++)
+ {
+ for (size_t x=0; x<max_x; x++)
+ {
+ size_t ofs00 = (y+0)*line_offset+(x+0);
+ size_t ofs01 = (y+0)*line_offset+(x+1);
+ size_t ofs10 = (y+1)*line_offset+(x+0);
+ size_t ofs11 = (y+1)*line_offset+(x+1);
+ const Vec3vf<K> a00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> a01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> a10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> a11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+ ofs00 += grid_offset;
+ ofs01 += grid_offset;
+ ofs10 += grid_offset;
+ ofs11 += grid_offset;
+ const Vec3vf<K> b00(grid_x[ofs00],grid_y[ofs00],grid_z[ofs00]);
+ const Vec3vf<K> b01(grid_x[ofs01],grid_y[ofs01],grid_z[ofs01]);
+ const Vec3vf<K> b10(grid_x[ofs10],grid_y[ofs10],grid_z[ofs10]);
+ const Vec3vf<K> b11(grid_x[ofs11],grid_y[ofs11],grid_z[ofs11]);
+ const Vec3vf<K> p00 = lerp(a00,b00,ftime);
+ const Vec3vf<K> p01 = lerp(a01,b01,ftime);
+ const Vec3vf<K> p10 = lerp(a10,b10,ftime);
+ const Vec3vf<K> p11 = lerp(a11,b11,ftime);
+
+ pre.intersector.intersectK(valid,ray,p00,p01,p10,MapUV0<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
+ if (none(valid)) break;
+ pre.intersector.intersectK(valid,ray,p10,p01,p11,MapUV1<K>(grid_uv,ofs00,ofs01,ofs10,ofs11),OccludedKEpilogMU<1,K,true>(valid,ray,context,pre.grid->geomID(),pre.grid->primID()));
+ if (none(valid)) break;
+ }
+ }
+ return valid;
+ }
+
+ template<typename Loader>
+ static __forceinline void intersect(RayHitK<K>& ray, size_t k,
+ const float ftime,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ Vec3<vfloat> a0, a1, a2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,a0,a1,a2);
+
+ Vec3<vfloat> b0, b1, b2;
+ Loader::gather(grid_x+grid_offset,grid_y+grid_offset,grid_z+grid_offset,line_offset,lines,b0,b1,b2);
+
+ Vec3<vfloat> v0 = lerp(a0,b0,vfloat(ftime));
+ Vec3<vfloat> v1 = lerp(a1,b1,vfloat(ftime));
+ Vec3<vfloat> v2 = lerp(a2,b2,vfloat(ftime));
+
+ pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Intersect1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
+ };
+
+ template<typename Loader>
+ static __forceinline bool occluded(RayK<K>& ray, size_t k,
+ const float ftime,
+ IntersectContext* context,
+ const float* const grid_x,
+ const size_t line_offset,
+ const size_t lines,
+ Precalculations& pre)
+ {
+ typedef typename Loader::vfloat vfloat;
+ const size_t grid_offset = pre.grid->gridBytes >> 2;
+ const size_t dim_offset = pre.grid->dim_offset;
+ const float* const grid_y = grid_x + 1 * dim_offset;
+ const float* const grid_z = grid_x + 2 * dim_offset;
+ const float* const grid_uv = grid_x + 3 * dim_offset;
+
+ Vec3<vfloat> a0, a1, a2;
+ Loader::gather(grid_x,grid_y,grid_z,line_offset,lines,a0,a1,a2);
+
+ Vec3<vfloat> b0, b1, b2;
+ Loader::gather(grid_x+grid_offset,grid_y+grid_offset,grid_z+grid_offset,line_offset,lines,b0,b1,b2);
+
+ Vec3<vfloat> v0 = lerp(a0,b0,vfloat(ftime));
+ Vec3<vfloat> v1 = lerp(a1,b1,vfloat(ftime));
+ Vec3<vfloat> v2 = lerp(a2,b2,vfloat(ftime));
+
+ return pre.intersector.intersect(ray,k,v0,v1,v2,GridSOA::MapUV<Loader>(grid_uv,line_offset,lines),Occluded1KEpilogMU<Loader::M,K,true>(ray,k,context,pre.grid->geomID(),pre.grid->primID()));
+ }
+
+ /*! Intersect a ray with the primitive. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ float ftime;
+ int itime = getTimeSegment(ray.time()[k], float(pre.grid->time_steps-1), ftime);
+
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
+
+#if defined(__AVX__)
+ intersect<GridSOA::Gather3x3>( ray, k, ftime, context, grid_x, line_offset, lines, pre);
+#else
+ intersect<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x, line_offset, lines, pre);
+ if (likely(lines > 2))
+ intersect<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x+line_offset, line_offset, lines, pre);
+#endif
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ float ftime;
+ int itime = getTimeSegment(ray.time()[k], float(pre.grid->time_steps-1), ftime);
+
+ const size_t line_offset = pre.grid->width;
+ const size_t lines = pre.grid->height;
+ const float* const grid_x = pre.grid->decodeLeaf(itime,prim);
+
+#if defined(__AVX__)
+ return occluded<GridSOA::Gather3x3>( ray, k, ftime, context, grid_x, line_offset, lines, pre);
+#else
+ if (occluded<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x, line_offset, lines, pre)) return true;
+ if (likely(lines > 2))
+ if (occluded<GridSOA::Gather2x3>(ray, k, ftime, context, grid_x+line_offset, line_offset, lines, pre)) return true;
+#endif
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/instance.h b/thirdparty/embree/kernels/geometry/instance.h
new file mode 100644
index 0000000000..7c0e7e0f49
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/instance.h
@@ -0,0 +1,78 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "../common/scene_instance.h"
+
+namespace embree
+{
+ struct InstancePrimitive
+ {
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored primitives */
+ static __forceinline size_t max_size() { return 1; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return N; }
+
+ public:
+
+ InstancePrimitive (const Instance* instance, unsigned int instID)
+ : instance(instance)
+ , instID_(instID)
+ {}
+
+ __forceinline void fill(const PrimRef* prims, size_t& i, size_t end, Scene* scene)
+ {
+ assert(end-i == 1);
+ const PrimRef& prim = prims[i]; i++;
+ const unsigned int geomID = prim.geomID();
+ const Instance* instance = scene->get<Instance>(geomID);
+ new (this) InstancePrimitive(instance, geomID);
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& i, size_t end, Scene* scene, size_t itime)
+ {
+ assert(end-i == 1);
+ const PrimRef& prim = prims[i]; i++;
+ const unsigned int geomID = prim.geomID();
+ const Instance* instance = scene->get<Instance>(geomID);
+ new (this) InstancePrimitive(instance,geomID);
+ return instance->linearBounds(0,itime);
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& i, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ assert(end-i == 1);
+ const PrimRefMB& prim = prims[i]; i++;
+ const unsigned int geomID = prim.geomID();
+ const Instance* instance = scene->get<Instance>(geomID);
+ new (this) InstancePrimitive(instance,geomID);
+ return instance->linearBounds(0,time_range);
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(Instance* instance) {
+ return instance->bounds(0);
+ }
+
+ public:
+ const Instance* instance;
+ const unsigned int instID_ = std::numeric_limits<unsigned int>::max ();
+ };
+}
diff --git a/thirdparty/embree/kernels/geometry/instance_intersector.h b/thirdparty/embree/kernels/geometry/instance_intersector.h
new file mode 100644
index 0000000000..28a7b728e5
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/instance_intersector.h
@@ -0,0 +1,84 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instance.h"
+#include "../common/ray.h"
+#include "../common/point_query.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct InstanceIntersector1
+ {
+ typedef InstancePrimitive Primitive;
+
+ struct Precalculations {
+ __forceinline Precalculations (const Ray& ray, const void *ptr) {}
+ };
+
+ static void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim);
+ static bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim);
+ static bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim);
+ };
+
+ struct InstanceIntersector1MB
+ {
+ typedef InstancePrimitive Primitive;
+
+ struct Precalculations {
+ __forceinline Precalculations (const Ray& ray, const void *ptr) {}
+ };
+
+ static void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim);
+ static bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim);
+ static bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim);
+ };
+
+ template<int K>
+ struct InstanceIntersectorK
+ {
+ typedef InstancePrimitive Primitive;
+
+ struct Precalculations {
+ __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {}
+ };
+
+ static void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& prim);
+ static vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& prim);
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ intersect(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ occluded(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ return ray.tfar[k] < 0.0f;
+ }
+ };
+
+ template<int K>
+ struct InstanceIntersectorKMB
+ {
+ typedef InstancePrimitive Primitive;
+
+ struct Precalculations {
+ __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {}
+ };
+
+ static void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& prim);
+ static vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& prim);
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ intersect(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ occluded(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ return ray.tfar[k] < 0.0f;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/intersector_epilog.h b/thirdparty/embree/kernels/geometry/intersector_epilog.h
new file mode 100644
index 0000000000..7bf134cc54
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/intersector_epilog.h
@@ -0,0 +1,979 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/context.h"
+#include "filter.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct UVIdentity {
+ __forceinline void operator() (vfloat<M>& u, vfloat<M>& v, Vec3vf<M>& Ng) const {}
+ };
+
+
+ template<bool filter>
+ struct Intersect1Epilog1
+ {
+ RayHit& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Intersect1Epilog1(RayHit& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask) == 0) return false;
+#endif
+ hit.finalize();
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ HitK<1> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t;
+ bool found = runIntersectionFilter1(geometry,ray,context,h);
+ if (!found) ray.tfar = old_t;
+ return found;
+ }
+ }
+#endif
+
+ /* update hit information */
+ ray.tfar = hit.t;
+ ray.Ng = hit.Ng;
+ ray.u = hit.u;
+ ray.v = hit.v;
+ ray.primID = primID;
+ ray.geomID = geomID;
+ instance_id_stack::copy_UU(context->user->instID, ray.instID);
+ return true;
+ }
+ };
+
+ template<bool filter>
+ struct Occluded1Epilog1
+ {
+ Ray& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Occluded1Epilog1(Ray& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask) == 0) return false;
+#endif
+ hit.finalize();
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) {
+ HitK<1> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t;
+ const bool found = runOcclusionFilter1(geometry,ray,context,h);
+ if (!found) ray.tfar = old_t;
+ return found;
+ }
+ }
+#endif
+ return true;
+ }
+ };
+
+ template<int K, bool filter>
+ struct Intersect1KEpilog1
+ {
+ RayHitK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Intersect1KEpilog1(RayHitK<K>& ray, size_t k,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask[k]) == 0)
+ return false;
+#endif
+ hit.finalize();
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ HitK<K> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t;
+ const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h));
+ if (!found) ray.tfar[k] = old_t;
+ return found;
+ }
+ }
+#endif
+
+ /* update hit information */
+ ray.tfar[k] = hit.t;
+ ray.Ng.x[k] = hit.Ng.x;
+ ray.Ng.y[k] = hit.Ng.y;
+ ray.Ng.z[k] = hit.Ng.z;
+ ray.u[k] = hit.u;
+ ray.v[k] = hit.v;
+ ray.primID[k] = primID;
+ ray.geomID[k] = geomID;
+ instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k);
+ return true;
+ }
+ };
+
+ template<int K, bool filter>
+ struct Occluded1KEpilog1
+ {
+ RayK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Occluded1KEpilog1(RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask[k]) == 0)
+ return false;
+#endif
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) {
+ hit.finalize();
+ HitK<K> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t;
+ const bool found = any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h));
+ if (!found) ray.tfar[k] = old_t;
+ return found;
+ }
+ }
+#endif
+ return true;
+ }
+ };
+
+ template<int M, bool filter>
+ struct Intersect1EpilogM
+ {
+ RayHit& ray;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+
+ __forceinline Intersect1EpilogM(RayHit& ray,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+ : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+ vbool<M> valid = valid_i;
+ hit.finalize();
+ size_t i = select_min(valid,hit.vt);
+ unsigned int geomID = geomIDs[i];
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
+ bool foundhit = false;
+ goto entry;
+ while (true)
+ {
+ if (unlikely(none(valid))) return foundhit;
+ i = select_min(valid,hit.vt);
+
+ geomID = geomIDs[i];
+ entry:
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ /* goto next hit if mask test fails */
+ if ((geometry->mask & ray.mask) == 0) {
+ clear(valid,i);
+ continue;
+ }
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ /* call intersection filter function */
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ const Vec2f uv = hit.uv(i);
+ HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t(i);
+ const bool found = runIntersectionFilter1(geometry,ray,context,h);
+ if (!found) ray.tfar = old_t;
+ foundhit |= found;
+ clear(valid,i);
+ valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value
+ continue;
+ }
+ }
+#endif
+ break;
+ }
+#endif
+
+ /* update hit information */
+ const Vec2f uv = hit.uv(i);
+ ray.tfar = hit.vt[i];
+ ray.Ng.x = hit.vNg.x[i];
+ ray.Ng.y = hit.vNg.y[i];
+ ray.Ng.z = hit.vNg.z[i];
+ ray.u = uv.x;
+ ray.v = uv.y;
+ ray.primID = primIDs[i];
+ ray.geomID = geomID;
+ instance_id_stack::copy_UU(context->user->instID, ray.instID);
+ return true;
+
+ }
+ };
+
+ template<int M, bool filter>
+ struct Occluded1EpilogM
+ {
+ Ray& ray;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+
+ __forceinline Occluded1EpilogM(Ray& ray,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+ : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
+ if (unlikely(filter))
+ hit.finalize(); /* called only once */
+
+ vbool<M> valid = valid_i;
+ size_t m=movemask(valid);
+ goto entry;
+ while (true)
+ {
+ if (unlikely(m == 0)) return false;
+ entry:
+ size_t i=bsf(m);
+
+ const unsigned int geomID = geomIDs[i];
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ /* goto next hit if mask test fails */
+ if ((geometry->mask & ray.mask) == 0) {
+ m=btc(m,i);
+ continue;
+ }
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ /* if we have no filter then the test passed */
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ const Vec2f uv = hit.uv(i);
+ HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t(i);
+ if (runOcclusionFilter1(geometry,ray,context,h)) return true;
+ ray.tfar = old_t;
+ m=btc(m,i);
+ continue;
+ }
+ }
+#endif
+ break;
+ }
+#endif
+
+ return true;
+ }
+ };
+
+ template<int M, bool filter>
+ struct Intersect1EpilogMU
+ {
+ RayHit& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Intersect1EpilogMU(RayHit& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask) == 0) return false;
+#endif
+
+ vbool<M> valid = valid_i;
+ hit.finalize();
+
+ size_t i = select_min(valid,hit.vt);
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter()))
+ {
+ bool foundhit = false;
+ while (true)
+ {
+ /* call intersection filter function */
+ Vec2f uv = hit.uv(i);
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t(i);
+ HitK<1> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
+ const bool found = runIntersectionFilter1(geometry,ray,context,h);
+ if (!found) ray.tfar = old_t;
+ foundhit |= found;
+ clear(valid,i);
+ valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value
+ if (unlikely(none(valid))) break;
+ i = select_min(valid,hit.vt);
+ }
+ return foundhit;
+ }
+#endif
+
+ /* update hit information */
+ const Vec2f uv = hit.uv(i);
+ const Vec3fa Ng = hit.Ng(i);
+ ray.tfar = hit.t(i);
+ ray.Ng.x = Ng.x;
+ ray.Ng.y = Ng.y;
+ ray.Ng.z = Ng.z;
+ ray.u = uv.x;
+ ray.v = uv.y;
+ ray.primID = primID;
+ ray.geomID = geomID;
+ instance_id_stack::copy_UU(context->user->instID, ray.instID);
+ return true;
+ }
+ };
+
+ template<int M, bool filter>
+ struct Occluded1EpilogMU
+ {
+ Ray& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Occluded1EpilogMU(Ray& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid, Hit& hit) const
+ {
+ /* ray mask test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ if ((geometry->mask & ray.mask) == 0) return false;
+#endif
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ hit.finalize();
+ for (size_t m=movemask(valid), i=bsf(m); m!=0; m=btc(m,i), i=bsf(m))
+ {
+ const Vec2f uv = hit.uv(i);
+ const float old_t = ray.tfar;
+ ray.tfar = hit.t(i);
+ HitK<1> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
+ if (runOcclusionFilter1(geometry,ray,context,h)) return true;
+ ray.tfar = old_t;
+ }
+ return false;
+ }
+#endif
+ return true;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct IntersectKEpilogM
+ {
+ RayHitK<K>& ray;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+ const size_t i;
+
+ __forceinline IntersectKEpilogM(RayHitK<K>& ray,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs,
+ size_t i)
+ : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {}
+
+ template<typename Hit>
+ __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+
+ vfloat<K> u, v, t;
+ Vec3vf<K> Ng;
+ vbool<K> valid = valid_i;
+
+ std::tie(u,v,t,Ng) = hit();
+
+ const unsigned int geomID = geomIDs[i];
+ const unsigned int primID = primIDs[i];
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+ /* ray masking test */
+#if defined(EMBREE_RAY_MASK)
+ valid &= (geometry->mask & ray.mask) != 0;
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* occlusion filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ HitK<K> h(context->user,geomID,primID,u,v,Ng);
+ const vfloat<K> old_t = ray.tfar;
+ ray.tfar = select(valid,t,ray.tfar);
+ const vbool<K> m_accept = runIntersectionFilter(valid,geometry,ray,context,h);
+ ray.tfar = select(m_accept,ray.tfar,old_t);
+ return m_accept;
+ }
+ }
+#endif
+
+ /* update hit information */
+ vfloat<K>::store(valid,&ray.tfar,t);
+ vfloat<K>::store(valid,&ray.Ng.x,Ng.x);
+ vfloat<K>::store(valid,&ray.Ng.y,Ng.y);
+ vfloat<K>::store(valid,&ray.Ng.z,Ng.z);
+ vfloat<K>::store(valid,&ray.u,u);
+ vfloat<K>::store(valid,&ray.v,v);
+ vuint<K>::store(valid,&ray.primID,primID);
+ vuint<K>::store(valid,&ray.geomID,geomID);
+ instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, valid);
+ return valid;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct OccludedKEpilogM
+ {
+ vbool<K>& valid0;
+ RayK<K>& ray;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+ const size_t i;
+
+ __forceinline OccludedKEpilogM(vbool<K>& valid0,
+ RayK<K>& ray,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs,
+ size_t i)
+ : valid0(valid0), ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {}
+
+ template<typename Hit>
+ __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
+ {
+ vbool<K> valid = valid_i;
+
+ /* ray masking test */
+ Scene* scene MAYBE_UNUSED = context->scene;
+ const unsigned int geomID MAYBE_UNUSED = geomIDs[i];
+ const unsigned int primID MAYBE_UNUSED = primIDs[i];
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ valid &= (geometry->mask & ray.mask) != 0;
+ if (unlikely(none(valid))) return valid;
+#endif
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ vfloat<K> u, v, t;
+ Vec3vf<K> Ng;
+ std::tie(u,v,t,Ng) = hit();
+ HitK<K> h(context->user,geomID,primID,u,v,Ng);
+ const vfloat<K> old_t = ray.tfar;
+ ray.tfar = select(valid,t,ray.tfar);
+ valid = runOcclusionFilter(valid,geometry,ray,context,h);
+ ray.tfar = select(valid,ray.tfar,old_t);
+ }
+ }
+#endif
+
+ /* update occlusion */
+ valid0 = valid0 & !valid;
+ return valid;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct IntersectKEpilogMU
+ {
+ RayHitK<K>& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline IntersectKEpilogMU(RayHitK<K>& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline vbool<K> operator() (const vbool<K>& valid_org, const Hit& hit) const
+ {
+ vbool<K> valid = valid_org;
+ vfloat<K> u, v, t;
+ Vec3vf<K> Ng;
+ std::tie(u,v,t,Ng) = hit();
+
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+ /* ray masking test */
+#if defined(EMBREE_RAY_MASK)
+ valid &= (geometry->mask & ray.mask) != 0;
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ HitK<K> h(context->user,geomID,primID,u,v,Ng);
+ const vfloat<K> old_t = ray.tfar;
+ ray.tfar = select(valid,t,ray.tfar);
+ const vbool<K> m_accept = runIntersectionFilter(valid,geometry,ray,context,h);
+ ray.tfar = select(m_accept,ray.tfar,old_t);
+ return m_accept;
+ }
+ }
+#endif
+
+ /* update hit information */
+ vfloat<K>::store(valid,&ray.tfar,t);
+ vfloat<K>::store(valid,&ray.Ng.x,Ng.x);
+ vfloat<K>::store(valid,&ray.Ng.y,Ng.y);
+ vfloat<K>::store(valid,&ray.Ng.z,Ng.z);
+ vfloat<K>::store(valid,&ray.u,u);
+ vfloat<K>::store(valid,&ray.v,v);
+ vuint<K>::store(valid,&ray.primID,primID);
+ vuint<K>::store(valid,&ray.geomID,geomID);
+ instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, valid);
+ return valid;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct OccludedKEpilogMU
+ {
+ vbool<K>& valid0;
+ RayK<K>& ray;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline OccludedKEpilogMU(vbool<K>& valid0,
+ RayK<K>& ray,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : valid0(valid0), ray(ray), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
+ {
+ vbool<K> valid = valid_i;
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ valid &= (geometry->mask & ray.mask) != 0;
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* occlusion filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ vfloat<K> u, v, t;
+ Vec3vf<K> Ng;
+ std::tie(u,v,t,Ng) = hit();
+ HitK<K> h(context->user,geomID,primID,u,v,Ng);
+ const vfloat<K> old_t = ray.tfar;
+ ray.tfar = select(valid,t,ray.tfar);
+ valid = runOcclusionFilter(valid,geometry,ray,context,h);
+ ray.tfar = select(valid,ray.tfar,old_t);
+ }
+ }
+#endif
+
+ /* update occlusion */
+ valid0 = valid0 & !valid;
+ return valid;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct Intersect1KEpilogM
+ {
+ RayHitK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+
+ __forceinline Intersect1KEpilogM(RayHitK<K>& ray, size_t k,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+ : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+ vbool<M> valid = valid_i;
+ hit.finalize();
+ size_t i = select_min(valid,hit.vt);
+ assert(i<M);
+ unsigned int geomID = geomIDs[i];
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
+ bool foundhit = false;
+ goto entry;
+ while (true)
+ {
+ if (unlikely(none(valid))) return foundhit;
+ i = select_min(valid,hit.vt);
+ assert(i<M);
+ geomID = geomIDs[i];
+ entry:
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ /* goto next hit if mask test fails */
+ if ((geometry->mask & ray.mask[k]) == 0) {
+ clear(valid,i);
+ continue;
+ }
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ /* call intersection filter function */
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
+ assert(i<M);
+ const Vec2f uv = hit.uv(i);
+ HitK<K> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t(i);
+ const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h));
+ if (!found) ray.tfar[k] = old_t;
+ foundhit = foundhit | found;
+ clear(valid,i);
+ valid &= hit.vt <= ray.tfar[k]; // intersection filters may modify tfar value
+ continue;
+ }
+ }
+#endif
+ break;
+ }
+#endif
+ assert(i<M);
+ /* update hit information */
+ const Vec2f uv = hit.uv(i);
+ ray.tfar[k] = hit.t(i);
+ ray.Ng.x[k] = hit.vNg.x[i];
+ ray.Ng.y[k] = hit.vNg.y[i];
+ ray.Ng.z[k] = hit.vNg.z[i];
+ ray.u[k] = uv.x;
+ ray.v[k] = uv.y;
+ ray.primID[k] = primIDs[i];
+ ray.geomID[k] = geomID;
+ instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k);
+ return true;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct Occluded1KEpilogM
+ {
+ RayK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const vuint<M>& geomIDs;
+ const vuint<M>& primIDs;
+
+ __forceinline Occluded1KEpilogM(RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+ : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
+ if (unlikely(filter))
+ hit.finalize(); /* called only once */
+
+ vbool<M> valid = valid_i;
+ size_t m=movemask(valid);
+ goto entry;
+ while (true)
+ {
+ if (unlikely(m == 0)) return false;
+ entry:
+ size_t i=bsf(m);
+
+ const unsigned int geomID = geomIDs[i];
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+
+#if defined(EMBREE_RAY_MASK)
+ /* goto next hit if mask test fails */
+ if ((geometry->mask & ray.mask[k]) == 0) {
+ m=btc(m,i);
+ continue;
+ }
+#endif
+
+#if defined(EMBREE_FILTER_FUNCTION)
+ /* execute occlusion filer */
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ const Vec2f uv = hit.uv(i);
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t(i);
+ HitK<K> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
+ if (any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h))) return true;
+ ray.tfar[k] = old_t;
+ m=btc(m,i);
+ continue;
+ }
+ }
+#endif
+ break;
+ }
+#endif
+ return true;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct Intersect1KEpilogMU
+ {
+ RayHitK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Intersect1KEpilogMU(RayHitK<K>& ray, size_t k,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ /* ray mask test */
+ if ((geometry->mask & ray.mask[k]) == 0)
+ return false;
+#endif
+
+ /* finalize hit calculation */
+ vbool<M> valid = valid_i;
+ hit.finalize();
+ size_t i = select_min(valid,hit.vt);
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter()))
+ {
+ bool foundhit = false;
+ while (true)
+ {
+ const Vec2f uv = hit.uv(i);
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t(i);
+ HitK<K> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
+ const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h));
+ if (!found) ray.tfar[k] = old_t;
+ foundhit = foundhit | found;
+ clear(valid,i);
+ valid &= hit.vt <= ray.tfar[k]; // intersection filters may modify tfar value
+ if (unlikely(none(valid))) break;
+ i = select_min(valid,hit.vt);
+ }
+ return foundhit;
+ }
+ }
+#endif
+
+ /* update hit information */
+ const Vec2f uv = hit.uv(i);
+ const Vec3fa Ng = hit.Ng(i);
+ ray.tfar[k] = hit.t(i);
+ ray.Ng.x[k] = Ng.x;
+ ray.Ng.y[k] = Ng.y;
+ ray.Ng.z[k] = Ng.z;
+ ray.u[k] = uv.x;
+ ray.v[k] = uv.y;
+ ray.primID[k] = primID;
+ ray.geomID[k] = geomID;
+ instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k);
+ return true;
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct Occluded1KEpilogMU
+ {
+ RayK<K>& ray;
+ size_t k;
+ IntersectContext* context;
+ const unsigned int geomID;
+ const unsigned int primID;
+
+ __forceinline Occluded1KEpilogMU(RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
+
+ template<typename Hit>
+ __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
+ {
+ Scene* scene MAYBE_UNUSED = context->scene;
+ Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
+#if defined(EMBREE_RAY_MASK)
+ /* ray mask test */
+ if ((geometry->mask & ray.mask[k]) == 0)
+ return false;
+#endif
+
+ /* intersection filter test */
+#if defined(EMBREE_FILTER_FUNCTION)
+ if (filter) {
+ if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
+ {
+ hit.finalize();
+ for (size_t m=movemask(valid_i), i=bsf(m); m!=0; m=btc(m,i), i=bsf(m))
+ {
+ const Vec2f uv = hit.uv(i);
+ const float old_t = ray.tfar[k];
+ ray.tfar[k] = hit.t(i);
+ HitK<K> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
+ if (any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h))) return true;
+ ray.tfar[k] = old_t;
+ }
+ return false;
+ }
+ }
+#endif
+ return true;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/intersector_iterators.h b/thirdparty/embree/kernels/geometry/intersector_iterators.h
new file mode 100644
index 0000000000..9cac1cd25c
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/intersector_iterators.h
@@ -0,0 +1,172 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/scene.h"
+#include "../common/ray.h"
+#include "../common/point_query.h"
+#include "../bvh/node_intersector1.h"
+#include "../bvh/node_intersector_packet.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename Intersector>
+ struct ArrayIntersector1
+ {
+ typedef typename Intersector::Primitive Primitive;
+ typedef typename Intersector::Precalculations Precalculations;
+
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ for (size_t i=0; i<num; i++)
+ Intersector::intersect(pre,ray,context,prim[i]);
+ }
+
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ for (size_t i=0; i<num; i++) {
+ if (Intersector::occluded(pre,ray,context,prim[i]))
+ return true;
+ }
+ return false;
+ }
+
+ template<int N>
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ bool changed = false;
+ for (size_t i=0; i<num; i++)
+ changed |= Intersector::pointQuery(query, context, prim[i]);
+ return changed;
+ }
+
+ template<int K>
+ static __forceinline void intersectK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ }
+
+ template<int K>
+ static __forceinline vbool<K> occludedK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ return valid;
+ }
+ };
+
+ template<int K, typename Intersector>
+ struct ArrayIntersectorK_1
+ {
+ typedef typename Intersector::Primitive Primitive;
+ typedef typename Intersector::Precalculations Precalculations;
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ for (size_t i=0; i<num; i++) {
+ Intersector::intersect(valid,pre,ray,context,prim[i]);
+ }
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ vbool<K> valid0 = valid;
+ for (size_t i=0; i<num; i++) {
+ valid0 &= !Intersector::occluded(valid0,pre,ray,context,prim[i]);
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ for (size_t i=0; i<num; i++) {
+ Intersector::intersect(pre,ray,k,context,prim[i]);
+ }
+ }
+
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ for (size_t i=0; i<num; i++) {
+ if (Intersector::occluded(pre,ray,k,context,prim[i]))
+ return true;
+ }
+ return false;
+ }
+ };
+
+ // =============================================================================================
+
+ template<int K, typename IntersectorK>
+ struct ArrayIntersectorKStream
+ {
+ typedef typename IntersectorK::Primitive PrimitiveK;
+ typedef typename IntersectorK::Precalculations PrecalculationsK;
+
+ static __forceinline void intersectK(const vbool<K>& valid, const Accel::Intersectors* This, /* PrecalculationsK& pre, */ RayHitK<K>& ray, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node)
+ {
+ PrecalculationsK pre(valid,ray); // FIXME: might cause trouble
+
+ for (size_t i=0; i<num; i++) {
+ IntersectorK::intersect(valid,pre,ray,context,prim[i]);
+ }
+ }
+
+ static __forceinline vbool<K> occludedK(const vbool<K>& valid, const Accel::Intersectors* This, /* PrecalculationsK& pre, */ RayK<K>& ray, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node)
+ {
+ PrecalculationsK pre(valid,ray); // FIXME: might cause trouble
+ vbool<K> valid0 = valid;
+ for (size_t i=0; i<num; i++) {
+ valid0 &= !IntersectorK::occluded(valid0,pre,ray,context,prim[i]);
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(const Accel::Intersectors* This, RayHitK<K>& ray, size_t k, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node)
+ {
+ PrecalculationsK pre(ray.tnear() <= ray.tfar,ray); // FIXME: might cause trouble
+ for (size_t i=0; i<num; i++) {
+ IntersectorK::intersect(pre,ray,k,context,prim[i]);
+ }
+ }
+
+ static __forceinline bool occluded(const Accel::Intersectors* This, RayK<K>& ray, size_t k, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node)
+ {
+ PrecalculationsK pre(ray.tnear() <= ray.tfar,ray); // FIXME: might cause trouble
+ for (size_t i=0; i<num; i++) {
+ if (IntersectorK::occluded(pre,ray,k,context,prim[i]))
+ return true;
+ }
+ return false;
+ }
+
+ static __forceinline size_t occluded(const Accel::Intersectors* This, size_t cur_mask, RayK<K>** __restrict__ inputPackets, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node)
+ {
+ size_t m_occluded = 0;
+ for (size_t i=0; i<num; i++) {
+ size_t bits = cur_mask & (~m_occluded);
+ for (; bits!=0; )
+ {
+ const size_t rayID = bscf(bits);
+ RayHitK<K> &ray = *inputPackets[rayID / K];
+ const size_t k = rayID % K;
+ PrecalculationsK pre(ray.tnear() <= ray.tfar,ray); // FIXME: might cause trouble
+ if (IntersectorK::occluded(pre,ray,k,context,prim[i]))
+ {
+ m_occluded |= (size_t)1 << rayID;
+ ray.tfar[k] = neg_inf;
+ }
+ }
+ }
+ return m_occluded;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/line_intersector.h b/thirdparty/embree/kernels/geometry/line_intersector.h
new file mode 100644
index 0000000000..41096d8794
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/line_intersector.h
@@ -0,0 +1,145 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct LineIntersectorHitM
+ {
+ __forceinline LineIntersectorHitM() {}
+
+ __forceinline LineIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)
+ : vu(u), vv(v), vt(t), vNg(Ng) {}
+
+ __forceinline void finalize() {}
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ __forceinline Vec2vf<M> uv() const { return Vec2vf<M>(vu,vv); }
+ __forceinline vfloat<M> t () const { return vt; }
+ __forceinline Vec3vf<M> Ng() const { return vNg; }
+
+ public:
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct FlatLinearCurveIntersector1
+ {
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<typename Ray, typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ Ray& ray,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const Epilog& epilog)
+ {
+ /* transform end points into ray space */
+ vbool<M> valid = valid_i;
+ vfloat<M> depth_scale = pre.depth_scale;
+ LinearSpace3<Vec3vf<M>> ray_space = pre.ray_space;
+
+ const Vec3vf<M> ray_org ((Vec3fa)ray.org);
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v1i);
+
+ Vec4vf<M> p0(xfmVector(ray_space,v0.xyz()-ray_org), v0.w);
+ Vec4vf<M> p1(xfmVector(ray_space,v1.xyz()-ray_org), v1.w);
+
+ /* approximative intersection with cone */
+ const Vec4vf<M> v = p1-p0;
+ const Vec4vf<M> w = -p0;
+ const vfloat<M> d0 = madd(w.x,v.x,w.y*v.y);
+ const vfloat<M> d1 = madd(v.x,v.x,v.y*v.y);
+ const vfloat<M> u = clamp(d0*rcp(d1),vfloat<M>(zero),vfloat<M>(one));
+ const Vec4vf<M> p = madd(u,v,p0);
+ const vfloat<M> t = p.z;
+ const vfloat<M> d2 = madd(p.x,p.x,p.y*p.y);
+ const vfloat<M> r = p.w;
+ const vfloat<M> r2 = r*r;
+ valid &= (d2 <= r2) & (vfloat<M>(ray.tnear()) <= t) & (t <= vfloat<M>(ray.tfar));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= t > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale; // ignore self intersections
+ if (unlikely(none(valid))) return false;
+
+ /* ignore denormalized segments */
+ const Vec3vf<M> T = v1.xyz()-v0.xyz();
+ valid &= (T.x != vfloat<M>(zero)) | (T.y != vfloat<M>(zero)) | (T.z != vfloat<M>(zero));
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ LineIntersectorHitM<M> hit(u,zero,t,T);
+ return epilog(valid,hit);
+ }
+ };
+
+ template<int M, int K>
+ struct FlatLinearCurveIntersectorK
+ {
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const Epilog& epilog)
+ {
+ /* transform end points into ray space */
+ vbool<M> valid = valid_i;
+ vfloat<M> depth_scale = pre.depth_scale[k];
+ LinearSpace3<Vec3vf<M>> ray_space = pre.ray_space[k];
+ const Vec3vf<M> ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v1i);
+
+ Vec4vf<M> p0(xfmVector(ray_space,v0.xyz()-ray_org), v0.w);
+ Vec4vf<M> p1(xfmVector(ray_space,v1.xyz()-ray_org), v1.w);
+
+ /* approximative intersection with cone */
+ const Vec4vf<M> v = p1-p0;
+ const Vec4vf<M> w = -p0;
+ const vfloat<M> d0 = madd(w.x,v.x,w.y*v.y);
+ const vfloat<M> d1 = madd(v.x,v.x,v.y*v.y);
+ const vfloat<M> u = clamp(d0*rcp(d1),vfloat<M>(zero),vfloat<M>(one));
+ const Vec4vf<M> p = madd(u,v,p0);
+ const vfloat<M> t = p.z;
+ const vfloat<M> d2 = madd(p.x,p.x,p.y*p.y);
+ const vfloat<M> r = p.w;
+ const vfloat<M> r2 = r*r;
+ valid &= (d2 <= r2) & (vfloat<M>(ray.tnear()[k]) <= t) & (t <= vfloat<M>(ray.tfar[k]));
+ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f)
+ valid &= t > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale; // ignore self intersections
+ if (unlikely(none(valid))) return false;
+
+ /* ignore denormalized segments */
+ const Vec3vf<M> T = v1.xyz()-v0.xyz();
+ valid &= (T.x != vfloat<M>(zero)) | (T.y != vfloat<M>(zero)) | (T.z != vfloat<M>(zero));
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ LineIntersectorHitM<M> hit(u,zero,t,T);
+ return epilog(valid,hit);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/linei.h b/thirdparty/embree/kernels/geometry/linei.h
new file mode 100644
index 0000000000..3ee70ac012
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/linei.h
@@ -0,0 +1,705 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ template<int M>
+ struct LineMi
+ {
+ /* Virtual interface to query information about the line segment type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored line segments */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N line segments */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ /* Returns required number of bytes for N line segments */
+ static __forceinline size_t bytes(size_t N) { return blocks(N)*sizeof(LineMi); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline LineMi() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline LineMi(const vuint<M>& v0, unsigned short leftExists, unsigned short rightExists, const vuint<M>& geomIDs, const vuint<M>& primIDs, Geometry::GType gtype)
+ : gtype((unsigned char)gtype), m((unsigned char)popcnt(vuint<M>(primIDs) != vuint<M>(-1))), sharedGeomID(geomIDs[0]), leftExists (leftExists), rightExists(rightExists), v0(v0), primIDs(primIDs)
+ {
+ assert(all(vuint<M>(geomID()) == geomIDs));
+ }
+
+ /* Returns a mask that tells which line segments are valid */
+ __forceinline vbool<M> valid() const { return primIDs != vuint<M>(-1); }
+
+ /* Returns if the specified line segment is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return primIDs[i] != -1; }
+
+ /* Returns the number of stored line segments */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ //template<class T>
+ //static __forceinline T unmask(T &index) { return index & 0x3fffffff; }
+
+ __forceinline unsigned int geomID(unsigned int i = 0) const { return sharedGeomID; }
+ //__forceinline vuint<M> geomID() { return unmask(geomIDs); }
+ //__forceinline const vuint<M> geomID() const { return unmask(geomIDs); }
+ //__forceinline unsigned int geomID(const size_t i) const { assert(i<M); return unmask(geomIDs[i]); }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M>& primID() { return primIDs; }
+ __forceinline const vuint<M>& primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* gather the line segments */
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ const LineSegments* geom) const;
+
+ __forceinline void gatheri(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ const LineSegments* geom,
+ const int itime) const;
+
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ const LineSegments* geom,
+ float time) const;
+
+ /* gather the line segments with lateral info */
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ Vec4vf<M>& pL,
+ Vec4vf<M>& pR,
+ const LineSegments* geom) const;
+
+ __forceinline void gatheri(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ Vec4vf<M>& pL,
+ Vec4vf<M>& pR,
+ const LineSegments* geom,
+ const int itime) const;
+
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ Vec4vf<M>& pL,
+ Vec4vf<M>& pR,
+ const LineSegments* geom,
+ float time) const;
+
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ vbool<M>& cL,
+ vbool<M>& cR,
+ const LineSegments* geom) const;
+
+ __forceinline void gatheri(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ vbool<M>& cL,
+ vbool<M>& cR,
+ const LineSegments* geom,
+ const int itime) const;
+
+ __forceinline void gather(Vec4vf<M>& p0,
+ Vec4vf<M>& p1,
+ vbool<M>& cL,
+ vbool<M>& cR,
+ const LineSegments* geom,
+ float time) const;
+
+ /* Calculate the bounds of the line segments */
+ __forceinline const BBox3fa bounds(const Scene* scene, size_t itime = 0) const
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const LineSegments* geom = scene->get<LineSegments>(geomID(i));
+ const Vec3ff& p0 = geom->vertex(v0[i]+0,itime);
+ const Vec3ff& p1 = geom->vertex(v0[i]+1,itime);
+ BBox3fa b = merge(BBox3fa(p0),BBox3fa(p1));
+ b = enlarge(b,Vec3fa(max(p0.w,p1.w)));
+ bounds.extend(b);
+ }
+ return bounds;
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds(const Scene* scene, size_t itime) {
+ return LBBox3fa(bounds(scene,itime+0), bounds(scene,itime+1));
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime, size_t numTimeSteps) {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const LineSegments* geom = scene->get<LineSegments>(geomID(i));
+ allBounds.extend(geom->linearBounds(primID(i), itime, numTimeSteps));
+ }
+ return allBounds;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, const BBox1f time_range)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const LineSegments* geom = scene->get<LineSegments>(geomID((unsigned int)i));
+ allBounds.extend(geom->linearBounds(primID(i), time_range));
+ }
+ return allBounds;
+ }
+
+ /* Fill line segment from line segment list */
+ template<typename PrimRefT>
+ __forceinline void fill(const PrimRefT* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ Geometry::GType gty = scene->get(prims[begin].geomID())->getType();
+ vuint<M> geomID, primID;
+ vuint<M> v0;
+ unsigned short leftExists = 0;
+ unsigned short rightExists = 0;
+ const PrimRefT* prim = &prims[begin];
+
+ for (size_t i=0; i<M; i++)
+ {
+ const LineSegments* geom = scene->get<LineSegments>(prim->geomID());
+ if (begin<end) {
+ geomID[i] = prim->geomID();
+ primID[i] = prim->primID();
+ v0[i] = geom->segment(prim->primID());
+ leftExists |= geom->segmentLeftExists(primID[i]) << i;
+ rightExists |= geom->segmentRightExists(primID[i]) << i;
+ begin++;
+ } else {
+ assert(i);
+ if (i>0) {
+ geomID[i] = geomID[i-1];
+ primID[i] = -1;
+ v0[i] = v0[i-1];
+ }
+ }
+ if (begin<end) prim = &prims[begin]; // FIXME: remove this line
+ }
+ new (this) LineMi(v0,leftExists,rightExists,geomID,primID,gty); // FIXME: use non temporal store
+ }
+
+ template<typename BVH, typename Allocator>
+ __forceinline static typename BVH::NodeRef createLeaf (BVH* bvh, const PrimRef* prims, const range<size_t>& set, const Allocator& alloc)
+ {
+ size_t start = set.begin();
+ size_t items = LineMi::blocks(set.size());
+ size_t numbytes = LineMi::bytes(set.size());
+ LineMi* accel = (LineMi*) alloc.malloc1(numbytes,M*sizeof(float));
+ for (size_t i=0; i<items; i++) {
+ accel[i].fill(prims,start,set.end(),bvh->scene);
+ }
+ return bvh->encodeLeaf((char*)accel,items);
+ };
+
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
+ {
+ fill(prims,begin,end,scene);
+ return linearBounds(scene,itime);
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ fill(prims,begin,end,scene);
+ return linearBounds(scene,time_range);
+ }
+
+ template<typename BVH, typename SetMB, typename Allocator>
+ __forceinline static typename BVH::NodeRecordMB4D createLeafMB(BVH* bvh, const SetMB& prims, const Allocator& alloc)
+ {
+ size_t start = prims.begin();
+ size_t end = prims.end();
+ size_t items = LineMi::blocks(prims.size());
+ size_t numbytes = LineMi::bytes(prims.size());
+ LineMi* accel = (LineMi*) alloc.malloc1(numbytes,M*sizeof(float));
+ const typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel,items);
+
+ LBBox3fa bounds = empty;
+ for (size_t i=0; i<items; i++)
+ bounds.extend(accel[i].fillMB(prims.prims->data(),start,end,bvh->scene,prims.time_range));
+
+ return typename BVH::NodeRecordMB4D(node,bounds,prims.time_range);
+ };
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(LineSegments* geom)
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const Vec3ff& p0 = geom->vertex(v0[i]+0);
+ const Vec3ff& p1 = geom->vertex(v0[i]+1);
+ BBox3fa b = merge(BBox3fa(p0),BBox3fa(p1));
+ b = enlarge(b,Vec3fa(max(p0.w,p1.w)));
+ bounds.extend(b);
+ }
+ return bounds;
+ }
+
+ /*! output operator */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const LineMi& line) {
+ return cout << "Line" << M << "i {" << line.v0 << ", " << line.geomID() << ", " << line.primID() << "}";
+ }
+
+ public:
+ unsigned char gtype;
+ unsigned char m;
+ unsigned int sharedGeomID;
+ unsigned short leftExists, rightExists;
+ vuint<M> v0; // index of start vertex
+ private:
+ vuint<M> primIDs; // primitive ID
+ };
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ const LineSegments* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0]));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1]));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2]));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3]));
+ transpose(a0,a1,a2,a3,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1));
+ transpose(b0,b1,b2,b3,p1.x,p1.y,p1.z,p1.w);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gatheri(Vec4vf4& p0,
+ Vec4vf4& p1,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0],itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1],itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2],itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3],itime));
+ transpose(a0,a1,a2,a3,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1,itime));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1,itime));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1,itime));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1,itime));
+ transpose(b0,b1,b2,b3,p1.x,p1.y,p1.z,p1.w);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf4 a0,a1;
+ gatheri(a0,a1,geom,itime);
+ Vec4vf4 b0,b1;
+ gatheri(b0,b1,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat4(ftime));
+ p1 = lerp(a1,b1,vfloat4(ftime));
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ vbool4& cL,
+ vbool4& cR,
+ const LineSegments* geom) const
+ {
+ gather(p0,p1,geom);
+ cL = !vbool4(leftExists);
+ cR = !vbool4(rightExists);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gatheri(Vec4vf4& p0,
+ Vec4vf4& p1,
+ vbool4& cL,
+ vbool4& cR,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ gatheri(p0,p1,geom,itime);
+ cL = !vbool4(leftExists);
+ cR = !vbool4(rightExists);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ vbool4& cL,
+ vbool4& cR,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf4 a0,a1;
+ gatheri(a0,a1,geom,itime);
+ Vec4vf4 b0,b1;
+ gatheri(b0,b1,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat4(ftime));
+ p1 = lerp(a1,b1,vfloat4(ftime));
+ cL = !vbool4(leftExists);
+ cR = !vbool4(rightExists);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ Vec4vf4& pL,
+ Vec4vf4& pR,
+ const LineSegments* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0]));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1]));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2]));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3]));
+ transpose(a0,a1,a2,a3,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1));
+ transpose(b0,b1,b2,b3,p1.x,p1.y,p1.z,p1.w);
+
+ const vfloat4 l0 = (leftExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]-1)) : vfloat4(inf);
+ const vfloat4 l1 = (leftExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]-1)) : vfloat4(inf);
+ const vfloat4 l2 = (leftExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]-1)) : vfloat4(inf);
+ const vfloat4 l3 = (leftExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]-1)) : vfloat4(inf);
+ transpose(l0,l1,l2,l3,pL.x,pL.y,pL.z,pL.w);
+
+ const vfloat4 r0 = (rightExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]+2)) : vfloat4(inf);
+ const vfloat4 r1 = (rightExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]+2)) : vfloat4(inf);
+ const vfloat4 r2 = (rightExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]+2)) : vfloat4(inf);
+ const vfloat4 r3 = (rightExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]+2)) : vfloat4(inf);
+ transpose(r0,r1,r2,r3,pR.x,pR.y,pR.z,pR.w);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gatheri(Vec4vf4& p0,
+ Vec4vf4& p1,
+ Vec4vf4& pL,
+ Vec4vf4& pR,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0],itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1],itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2],itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3],itime));
+ transpose(a0,a1,a2,a3,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1,itime));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1,itime));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1,itime));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1,itime));
+ transpose(b0,b1,b2,b3,p1.x,p1.y,p1.z,p1.w);
+
+ const vfloat4 l0 = (leftExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]-1,itime)) : vfloat4(inf);
+ const vfloat4 l1 = (leftExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]-1,itime)) : vfloat4(inf);
+ const vfloat4 l2 = (leftExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]-1,itime)) : vfloat4(inf);
+ const vfloat4 l3 = (leftExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]-1,itime)) : vfloat4(inf);
+ transpose(l0,l1,l2,l3,pL.x,pL.y,pL.z,pL.w);
+
+ const vfloat4 r0 = (rightExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]+2,itime)) : vfloat4(inf);
+ const vfloat4 r1 = (rightExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]+2,itime)) : vfloat4(inf);
+ const vfloat4 r2 = (rightExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]+2,itime)) : vfloat4(inf);
+ const vfloat4 r3 = (rightExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]+2,itime)) : vfloat4(inf);
+ transpose(r0,r1,r2,r3,pR.x,pR.y,pR.z,pR.w);
+ }
+
+ template<>
+ __forceinline void LineMi<4>::gather(Vec4vf4& p0,
+ Vec4vf4& p1,
+ Vec4vf4& pL,
+ Vec4vf4& pR,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf4 a0,a1,aL,aR;
+ gatheri(a0,a1,aL,aR,geom,itime);
+ Vec4vf4 b0,b1,bL,bR;
+ gatheri(b0,b1,bL,bR,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat4(ftime));
+ p1 = lerp(a1,b1,vfloat4(ftime));
+ pL = lerp(aL,bL,vfloat4(ftime));
+ pR = lerp(aR,bR,vfloat4(ftime));
+ }
+
+#if defined(__AVX__)
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ const LineSegments* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0]));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1]));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2]));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3]));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(v0[4]));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(v0[5]));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(v0[6]));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(v0[7]));
+ transpose(a0,a1,a2,a3,a4,a5,a6,a7,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1));
+ const vfloat4 b4 = vfloat4::loadu(geom->vertexPtr(v0[4]+1));
+ const vfloat4 b5 = vfloat4::loadu(geom->vertexPtr(v0[5]+1));
+ const vfloat4 b6 = vfloat4::loadu(geom->vertexPtr(v0[6]+1));
+ const vfloat4 b7 = vfloat4::loadu(geom->vertexPtr(v0[7]+1));
+ transpose(b0,b1,b2,b3,b4,b5,b6,b7,p1.x,p1.y,p1.z,p1.w);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gatheri(Vec4vf8& p0,
+ Vec4vf8& p1,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0],itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1],itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2],itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3],itime));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(v0[4],itime));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(v0[5],itime));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(v0[6],itime));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(v0[7],itime));
+ transpose(a0,a1,a2,a3,a4,a5,a6,a7,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1,itime));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1,itime));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1,itime));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1,itime));
+ const vfloat4 b4 = vfloat4::loadu(geom->vertexPtr(v0[4]+1,itime));
+ const vfloat4 b5 = vfloat4::loadu(geom->vertexPtr(v0[5]+1,itime));
+ const vfloat4 b6 = vfloat4::loadu(geom->vertexPtr(v0[6]+1,itime));
+ const vfloat4 b7 = vfloat4::loadu(geom->vertexPtr(v0[7]+1,itime));
+ transpose(b0,b1,b2,b3,b4,b5,b6,b7,p1.x,p1.y,p1.z,p1.w);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf8 a0,a1;
+ gatheri(a0,a1,geom,itime);
+ Vec4vf8 b0,b1;
+ gatheri(b0,b1,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat8(ftime));
+ p1 = lerp(a1,b1,vfloat8(ftime));
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ Vec4vf8& pL,
+ Vec4vf8& pR,
+ const LineSegments* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0]));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1]));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2]));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3]));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(v0[4]));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(v0[5]));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(v0[6]));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(v0[7]));
+ transpose(a0,a1,a2,a3,a4,a5,a6,a7,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1));
+ const vfloat4 b4 = vfloat4::loadu(geom->vertexPtr(v0[4]+1));
+ const vfloat4 b5 = vfloat4::loadu(geom->vertexPtr(v0[5]+1));
+ const vfloat4 b6 = vfloat4::loadu(geom->vertexPtr(v0[6]+1));
+ const vfloat4 b7 = vfloat4::loadu(geom->vertexPtr(v0[7]+1));
+ transpose(b0,b1,b2,b3,b4,b5,b6,b7,p1.x,p1.y,p1.z,p1.w);
+
+ const vfloat4 l0 = (leftExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]-1)) : vfloat4(inf);
+ const vfloat4 l1 = (leftExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]-1)) : vfloat4(inf);
+ const vfloat4 l2 = (leftExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]-1)) : vfloat4(inf);
+ const vfloat4 l3 = (leftExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]-1)) : vfloat4(inf);
+ const vfloat4 l4 = (leftExists & (1<<4)) ? vfloat4::loadu(geom->vertexPtr(v0[4]-1)) : vfloat4(inf);
+ const vfloat4 l5 = (leftExists & (1<<5)) ? vfloat4::loadu(geom->vertexPtr(v0[5]-1)) : vfloat4(inf);
+ const vfloat4 l6 = (leftExists & (1<<6)) ? vfloat4::loadu(geom->vertexPtr(v0[6]-1)) : vfloat4(inf);
+ const vfloat4 l7 = (leftExists & (1<<7)) ? vfloat4::loadu(geom->vertexPtr(v0[7]-1)) : vfloat4(inf);
+ transpose(l0,l1,l2,l3,l4,l5,l6,l7,pL.x,pL.y,pL.z,pL.w);
+
+ const vfloat4 r0 = (rightExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]+2)) : vfloat4(inf);
+ const vfloat4 r1 = (rightExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]+2)) : vfloat4(inf);
+ const vfloat4 r2 = (rightExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]+2)) : vfloat4(inf);
+ const vfloat4 r3 = (rightExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]+2)) : vfloat4(inf);
+ const vfloat4 r4 = (rightExists & (1<<4)) ? vfloat4::loadu(geom->vertexPtr(v0[4]+2)) : vfloat4(inf);
+ const vfloat4 r5 = (rightExists & (1<<5)) ? vfloat4::loadu(geom->vertexPtr(v0[5]+2)) : vfloat4(inf);
+ const vfloat4 r6 = (rightExists & (1<<6)) ? vfloat4::loadu(geom->vertexPtr(v0[6]+2)) : vfloat4(inf);
+ const vfloat4 r7 = (rightExists & (1<<7)) ? vfloat4::loadu(geom->vertexPtr(v0[7]+2)) : vfloat4(inf);
+ transpose(r0,r1,r2,r3,r4,r5,r6,r7,pR.x,pR.y,pR.z,pR.w);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gatheri(Vec4vf8& p0,
+ Vec4vf8& p1,
+ Vec4vf8& pL,
+ Vec4vf8& pR,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(v0[0],itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(v0[1],itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(v0[2],itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(v0[3],itime));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(v0[4],itime));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(v0[5],itime));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(v0[6],itime));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(v0[7],itime));
+ transpose(a0,a1,a2,a3,a4,a5,a6,a7,p0.x,p0.y,p0.z,p0.w);
+
+ const vfloat4 b0 = vfloat4::loadu(geom->vertexPtr(v0[0]+1,itime));
+ const vfloat4 b1 = vfloat4::loadu(geom->vertexPtr(v0[1]+1,itime));
+ const vfloat4 b2 = vfloat4::loadu(geom->vertexPtr(v0[2]+1,itime));
+ const vfloat4 b3 = vfloat4::loadu(geom->vertexPtr(v0[3]+1,itime));
+ const vfloat4 b4 = vfloat4::loadu(geom->vertexPtr(v0[4]+1,itime));
+ const vfloat4 b5 = vfloat4::loadu(geom->vertexPtr(v0[5]+1,itime));
+ const vfloat4 b6 = vfloat4::loadu(geom->vertexPtr(v0[6]+1,itime));
+ const vfloat4 b7 = vfloat4::loadu(geom->vertexPtr(v0[7]+1,itime));
+ transpose(b0,b1,b2,b3,b4,b5,b6,b7,p1.x,p1.y,p1.z,p1.w);
+
+ const vfloat4 l0 = (leftExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]-1,itime)) : vfloat4(inf);
+ const vfloat4 l1 = (leftExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]-1,itime)) : vfloat4(inf);
+ const vfloat4 l2 = (leftExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]-1,itime)) : vfloat4(inf);
+ const vfloat4 l3 = (leftExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]-1,itime)) : vfloat4(inf);
+ const vfloat4 l4 = (leftExists & (1<<4)) ? vfloat4::loadu(geom->vertexPtr(v0[4]-1,itime)) : vfloat4(inf);
+ const vfloat4 l5 = (leftExists & (1<<5)) ? vfloat4::loadu(geom->vertexPtr(v0[5]-1,itime)) : vfloat4(inf);
+ const vfloat4 l6 = (leftExists & (1<<6)) ? vfloat4::loadu(geom->vertexPtr(v0[6]-1,itime)) : vfloat4(inf);
+ const vfloat4 l7 = (leftExists & (1<<7)) ? vfloat4::loadu(geom->vertexPtr(v0[7]-1,itime)) : vfloat4(inf);
+ transpose(l0,l1,l2,l3,l4,l5,l6,l7,pL.x,pL.y,pL.z,pL.w);
+
+ const vfloat4 r0 = (rightExists & (1<<0)) ? vfloat4::loadu(geom->vertexPtr(v0[0]+2,itime)) : vfloat4(inf);
+ const vfloat4 r1 = (rightExists & (1<<1)) ? vfloat4::loadu(geom->vertexPtr(v0[1]+2,itime)) : vfloat4(inf);
+ const vfloat4 r2 = (rightExists & (1<<2)) ? vfloat4::loadu(geom->vertexPtr(v0[2]+2,itime)) : vfloat4(inf);
+ const vfloat4 r3 = (rightExists & (1<<3)) ? vfloat4::loadu(geom->vertexPtr(v0[3]+2,itime)) : vfloat4(inf);
+ const vfloat4 r4 = (rightExists & (1<<4)) ? vfloat4::loadu(geom->vertexPtr(v0[4]+2,itime)) : vfloat4(inf);
+ const vfloat4 r5 = (rightExists & (1<<5)) ? vfloat4::loadu(geom->vertexPtr(v0[5]+2,itime)) : vfloat4(inf);
+ const vfloat4 r6 = (rightExists & (1<<6)) ? vfloat4::loadu(geom->vertexPtr(v0[6]+2,itime)) : vfloat4(inf);
+ const vfloat4 r7 = (rightExists & (1<<7)) ? vfloat4::loadu(geom->vertexPtr(v0[7]+2,itime)) : vfloat4(inf);
+ transpose(r0,r1,r2,r3,r4,r5,r6,r7,pR.x,pR.y,pR.z,pR.w);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ Vec4vf8& pL,
+ Vec4vf8& pR,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf8 a0,a1,aL,aR;
+ gatheri(a0,a1,aL,aR,geom,itime);
+ Vec4vf8 b0,b1,bL,bR;
+ gatheri(b0,b1,bL,bR,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat8(ftime));
+ p1 = lerp(a1,b1,vfloat8(ftime));
+ pL = lerp(aL,bL,vfloat8(ftime));
+ pR = lerp(aR,bR,vfloat8(ftime));
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ vbool8& cL,
+ vbool8& cR,
+ const LineSegments* geom) const
+ {
+ gather(p0,p1,geom);
+ cL = !vbool8(leftExists);
+ cR = !vbool8(rightExists);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gatheri(Vec4vf8& p0,
+ Vec4vf8& p1,
+ vbool8& cL,
+ vbool8& cR,
+ const LineSegments* geom,
+ const int itime) const
+ {
+ gatheri(p0,p1,geom,itime);
+ cL = !vbool8(leftExists);
+ cR = !vbool8(rightExists);
+ }
+
+ template<>
+ __forceinline void LineMi<8>::gather(Vec4vf8& p0,
+ Vec4vf8& p1,
+ vbool8& cL,
+ vbool8& cR,
+ const LineSegments* geom,
+ float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf8 a0,a1;
+ gatheri(a0,a1,geom,itime);
+ Vec4vf8 b0,b1;
+ gatheri(b0,b1,geom,itime+1);
+ p0 = lerp(a0,b0,vfloat8(ftime));
+ p1 = lerp(a1,b1,vfloat8(ftime));
+ cL = !vbool8(leftExists);
+ cR = !vbool8(rightExists);
+ }
+
+#endif
+
+ template<int M>
+ typename LineMi<M>::Type LineMi<M>::type;
+
+ typedef LineMi<4> Line4i;
+ typedef LineMi<8> Line8i;
+}
diff --git a/thirdparty/embree/kernels/geometry/linei_intersector.h b/thirdparty/embree/kernels/geometry/linei_intersector.h
new file mode 100644
index 0000000000..5992827f5b
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/linei_intersector.h
@@ -0,0 +1,124 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "linei.h"
+#include "line_intersector.h"
+#include "intersector_epilog.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, bool filter>
+ struct FlatLinearCurveMiIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom);
+ const vbool<M> valid = line.valid();
+ FlatLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom);
+ const vbool<M> valid = line.valid();
+ return FlatLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,Occluded1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, bool filter>
+ struct FlatLinearCurveMiMBIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom,ray.time());
+ const vbool<M> valid = line.valid();
+ FlatLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom,ray.time());
+ const vbool<M> valid = line.valid();
+ return FlatLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,Occluded1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct FlatLinearCurveMiIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom);
+ const vbool<M> valid = line.valid();
+ FlatLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom);
+ const vbool<M> valid = line.valid();
+ return FlatLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,Occluded1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct FlatLinearCurveMiMBIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom,ray.time()[k]);
+ const vbool<M> valid = line.valid();
+ FlatLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1; line.gather(v0,v1,geom,ray.time()[k]);
+ const vbool<M> valid = line.valid();
+ return FlatLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,Occluded1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/object.h b/thirdparty/embree/kernels/geometry/object.h
new file mode 100644
index 0000000000..2a61829ffd
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/object.h
@@ -0,0 +1,84 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ struct Object
+ {
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored primitives */
+ static __forceinline size_t max_size() { return 1; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return N; }
+
+ public:
+
+ /*! constructs a virtual object */
+ Object (unsigned geomID, unsigned primID)
+ : _geomID(geomID), _primID(primID) {}
+
+ __forceinline unsigned geomID() const {
+ return _geomID;
+ }
+
+ __forceinline unsigned primID() const {
+ return _primID;
+ }
+
+ /*! fill triangle from triangle list */
+ __forceinline void fill(const PrimRef* prims, size_t& i, size_t end, Scene* scene)
+ {
+ const PrimRef& prim = prims[i]; i++;
+ new (this) Object(prim.geomID(), prim.primID());
+ }
+
+ /*! fill triangle from triangle list */
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& i, size_t end, Scene* scene, size_t itime)
+ {
+ const PrimRef& prim = prims[i]; i++;
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ new (this) Object(geomID, primID);
+ AccelSet* accel = (AccelSet*) scene->get(geomID);
+ return accel->linearBounds(primID,itime);
+ }
+
+ /*! fill triangle from triangle list */
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& i, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ const PrimRefMB& prim = prims[i]; i++;
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ new (this) Object(geomID, primID);
+ AccelSet* accel = (AccelSet*) scene->get(geomID);
+ return accel->linearBounds(primID,time_range);
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(AccelSet* mesh) {
+ return mesh->bounds(primID());
+ }
+
+ private:
+ unsigned int _geomID; //!< geometry ID
+ unsigned int _primID; //!< primitive ID
+ };
+}
diff --git a/thirdparty/embree/kernels/geometry/object_intersector.h b/thirdparty/embree/kernels/geometry/object_intersector.h
new file mode 100644
index 0000000000..11ceb2f7fe
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/object_intersector.h
@@ -0,0 +1,127 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "object.h"
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<bool mblur>
+ struct ObjectIntersector1
+ {
+ typedef Object Primitive;
+
+ static const bool validIntersectorK = false;
+
+ struct Precalculations {
+ __forceinline Precalculations() {}
+ __forceinline Precalculations (const Ray& ray, const void *ptr) {}
+ };
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim)
+ {
+ AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID());
+
+ /* perform ray mask test */
+#if defined(EMBREE_RAY_MASK)
+ if ((ray.mask & accel->mask) == 0)
+ return;
+#endif
+
+ accel->intersect(ray,prim.geomID(),prim.primID(),context,reportIntersection1);
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim)
+ {
+ AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID());
+ /* perform ray mask test */
+#if defined(EMBREE_RAY_MASK)
+ if ((ray.mask & accel->mask) == 0)
+ return false;
+#endif
+
+ accel->occluded(ray,prim.geomID(),prim.primID(),context,&reportOcclusion1);
+ return ray.tfar < 0.0f;
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim)
+ {
+ AccelSet* accel = (AccelSet*)context->scene->get(prim.geomID());
+ context->geomID = prim.geomID();
+ context->primID = prim.primID();
+ return accel->pointQuery(query, context);
+ }
+
+ template<int K>
+ static __forceinline void intersectK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(false);
+ }
+
+ template<int K>
+ static __forceinline vbool<K> occludedK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node)
+ {
+ assert(false);
+ return valid;
+ }
+ };
+
+ template<int K, bool mblur>
+ struct ObjectIntersectorK
+ {
+ typedef Object Primitive;
+
+ struct Precalculations {
+ __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {}
+ };
+
+ static __forceinline void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vbool<K> valid = valid_i;
+ AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID());
+
+ /* perform ray mask test */
+#if defined(EMBREE_RAY_MASK)
+ valid &= (ray.mask & accel->mask) != 0;
+ if (none(valid)) return;
+#endif
+ accel->intersect(valid,ray,prim.geomID(),prim.primID(),context,&reportIntersection1);
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& prim)
+ {
+ vbool<K> valid = valid_i;
+ AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID());
+
+ /* perform ray mask test */
+#if defined(EMBREE_RAY_MASK)
+ valid &= (ray.mask & accel->mask) != 0;
+ if (none(valid)) return false;
+#endif
+ accel->occluded(valid,ray,prim.geomID(),prim.primID(),context,&reportOcclusion1);
+ return ray.tfar < 0.0f;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ intersect(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) {
+ occluded(vbool<K>(1<<int(k)),pre,ray,context,prim);
+ return ray.tfar[k] < 0.0f;
+ }
+ };
+
+ typedef ObjectIntersectorK<4,false> ObjectIntersector4;
+ typedef ObjectIntersectorK<8,false> ObjectIntersector8;
+ typedef ObjectIntersectorK<16,false> ObjectIntersector16;
+
+ typedef ObjectIntersectorK<4,true> ObjectIntersector4MB;
+ typedef ObjectIntersectorK<8,true> ObjectIntersector8MB;
+ typedef ObjectIntersectorK<16,true> ObjectIntersector16MB;
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/plane.h b/thirdparty/embree/kernels/geometry/plane.h
new file mode 100644
index 0000000000..e447122eab
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/plane.h
@@ -0,0 +1,57 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct HalfPlane
+ {
+ const Vec3fa P; //!< plane origin
+ const Vec3fa N; //!< plane normal
+
+ __forceinline HalfPlane(const Vec3fa& P, const Vec3fa& N)
+ : P(P), N(N) {}
+
+ __forceinline BBox1f intersect(const Vec3fa& ray_org, const Vec3fa& ray_dir) const
+ {
+ Vec3fa O = Vec3fa(ray_org) - P;
+ Vec3fa D = Vec3fa(ray_dir);
+ float ON = dot(O,N);
+ float DN = dot(D,N);
+ bool eps = abs(DN) < min_rcp_input;
+ float t = -ON*rcp(DN);
+ float lower = select(eps || DN < 0.0f, float(neg_inf), t);
+ float upper = select(eps || DN > 0.0f, float(pos_inf), t);
+ return BBox1f(lower,upper);
+ }
+ };
+
+ template<int M>
+ struct HalfPlaneN
+ {
+ const Vec3vf<M> P; //!< plane origin
+ const Vec3vf<M> N; //!< plane normal
+
+ __forceinline HalfPlaneN(const Vec3vf<M>& P, const Vec3vf<M>& N)
+ : P(P), N(N) {}
+
+ __forceinline BBox<vfloat<M>> intersect(const Vec3fa& ray_org, const Vec3fa& ray_dir) const
+ {
+ Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray_org) - P;
+ Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray_dir);
+ vfloat<M> ON = dot(O,N);
+ vfloat<M> DN = dot(D,N);
+ vbool<M> eps = abs(DN) < min_rcp_input;
+ vfloat<M> t = -ON*rcp(DN);
+ vfloat<M> lower = select(eps | DN < 0.0f, vfloat<M>(neg_inf), t);
+ vfloat<M> upper = select(eps | DN > 0.0f, vfloat<M>(pos_inf), t);
+ return BBox<vfloat<M>>(lower,upper);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/pointi.h b/thirdparty/embree/kernels/geometry/pointi.h
new file mode 100644
index 0000000000..bed04116b0
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/pointi.h
@@ -0,0 +1,412 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ template<int M>
+ struct PointMi
+ {
+ /* Virtual interface to query information about the line segment type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored line segments */
+ static __forceinline size_t max_size()
+ {
+ return M;
+ }
+
+ /* Returns required number of primitive blocks for N line segments */
+ static __forceinline size_t blocks(size_t N)
+ {
+ return (N + max_size() - 1) / max_size();
+ }
+
+ /* Returns required number of bytes for N line segments */
+ static __forceinline size_t bytes(size_t N)
+ {
+ return blocks(N) * sizeof(PointMi);
+ }
+
+ public:
+ /* Default constructor */
+ __forceinline PointMi() {}
+
+ /* Construction from vertices and IDs */
+ __forceinline PointMi(const vuint<M>& geomIDs, const vuint<M>& primIDs, Geometry::GType gtype, uint32_t numPrimitives)
+ : gtype((unsigned char)gtype),
+ numPrimitives(numPrimitives),
+ sharedGeomID(geomIDs[0]),
+ primIDs(primIDs)
+ {
+ assert(all(vuint<M>(geomID()) == geomIDs));
+ }
+
+ /* Returns a mask that tells which line segments are valid */
+ __forceinline vbool<M> valid() const {
+ return vint<M>(step) < vint<M>(numPrimitives);
+ }
+
+ /* Returns if the specified line segment is valid */
+ __forceinline bool valid(const size_t i) const
+ {
+ assert(i < M);
+ return i < numPrimitives;
+ }
+
+ /* Returns the number of stored line segments */
+ __forceinline size_t size() const {
+ return numPrimitives;
+ }
+
+ __forceinline unsigned int geomID(unsigned int i = 0) const {
+ return sharedGeomID;
+ }
+
+ __forceinline vuint<M>& primID() {
+ return primIDs;
+ }
+ __forceinline const vuint<M>& primID() const {
+ return primIDs;
+ }
+ __forceinline unsigned int primID(const size_t i) const {
+ assert(i < M);
+ return primIDs[i];
+ }
+
+ /* gather the line segments */
+ __forceinline void gather(Vec4vf<M>& p0, const Points* geom) const;
+ __forceinline void gather(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom) const;
+
+ __forceinline void gatheri(Vec4vf<M>& p0, const Points* geom, const int itime) const;
+ __forceinline void gatheri(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom, const int itime) const;
+
+ __forceinline void gather(Vec4vf<M>& p0, const Points* geom, float time) const;
+ __forceinline void gather(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom, float time) const;
+
+ /* Calculate the bounds of the line segments */
+ __forceinline const BBox3fa bounds(const Scene* scene, size_t itime = 0) const
+ {
+ BBox3fa bounds = empty;
+ for (size_t i = 0; i < M && valid(i); i++) {
+ const Points* geom = scene->get<Points>(geomID(i));
+ bounds.extend(geom->bounds(primID(i),itime));
+ }
+ return bounds;
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds(const Scene* scene, size_t itime) {
+ return LBBox3fa(bounds(scene, itime + 0), bounds(scene, itime + 1));
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene* const scene, size_t itime, size_t numTimeSteps)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i = 0; i < M && valid(i); i++) {
+ const Points* geom = scene->get<Points>(geomID(i));
+ allBounds.extend(geom->linearBounds(primID(i), itime, numTimeSteps));
+ }
+ return allBounds;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene* const scene, const BBox1f time_range)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i = 0; i < M && valid(i); i++) {
+ const Points* geom = scene->get<Points>(geomID((unsigned int)i));
+ allBounds.extend(geom->linearBounds(primID(i), time_range));
+ }
+ return allBounds;
+ }
+
+ /* Fill line segment from line segment list */
+ template<typename PrimRefT>
+ __forceinline void fill(const PrimRefT* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ Geometry::GType gty = scene->get(prims[begin].geomID())->getType();
+ vuint<M> geomID, primID;
+ vuint<M> v0;
+ const PrimRefT* prim = &prims[begin];
+
+ int numPrimitives = 0;
+ for (size_t i = 0; i < M; i++) {
+ if (begin < end) {
+ geomID[i] = prim->geomID();
+ primID[i] = prim->primID();
+ begin++;
+ numPrimitives++;
+ } else {
+ assert(i);
+ if (i > 0) {
+ geomID[i] = geomID[i - 1];
+ primID[i] = primID[i - 1];
+ }
+ }
+ if (begin < end)
+ prim = &prims[begin]; // FIXME: remove this line
+ }
+ new (this) PointMi(geomID, primID, gty, numPrimitives); // FIXME: use non temporal store
+ }
+
+ template<typename BVH, typename Allocator>
+ __forceinline static typename BVH::NodeRef createLeaf(BVH* bvh,
+ const PrimRef* prims,
+ const range<size_t>& set,
+ const Allocator& alloc)
+ {
+ size_t start = set.begin();
+ size_t items = PointMi::blocks(set.size());
+ size_t numbytes = PointMi::bytes(set.size());
+ PointMi* accel = (PointMi*)alloc.malloc1(numbytes, M * sizeof(float));
+ for (size_t i = 0; i < items; i++) {
+ accel[i].fill(prims, start, set.end(), bvh->scene);
+ }
+ return bvh->encodeLeaf((char*)accel, items);
+ };
+
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, itime);
+ }
+
+ __forceinline LBBox3fa fillMB(
+ const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, time_range);
+ }
+
+ template<typename BVH, typename SetMB, typename Allocator>
+ __forceinline static typename BVH::NodeRecordMB4D createLeafMB(BVH* bvh, const SetMB& prims, const Allocator& alloc)
+ {
+ size_t start = prims.object_range.begin();
+ size_t end = prims.object_range.end();
+ size_t items = PointMi::blocks(prims.object_range.size());
+ size_t numbytes = PointMi::bytes(prims.object_range.size());
+ PointMi* accel = (PointMi*)alloc.malloc1(numbytes, M * sizeof(float));
+ const typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel, items);
+
+ LBBox3fa bounds = empty;
+ for (size_t i = 0; i < items; i++)
+ bounds.extend(accel[i].fillMB(prims.prims->data(), start, end, bvh->scene, prims.time_range));
+
+ return typename BVH::NodeRecordMB4D(node, bounds, prims.time_range);
+ };
+
+ /*! output operator */
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const PointMi& line)
+ {
+ return cout << "Line" << M << "i {" << line.v0 << ", " << line.geomID() << ", " << line.primID() << "}";
+ }
+
+ public:
+ unsigned char gtype;
+ unsigned char numPrimitives;
+ unsigned int sharedGeomID;
+
+ private:
+ vuint<M> primIDs; // primitive ID
+ };
+
+ template<>
+ __forceinline void PointMi<4>::gather(Vec4vf4& p0, const Points* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
+ transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
+ }
+
+ template<>
+ __forceinline void PointMi<4>::gather(Vec4vf4& p0, Vec3vf4& n0, const Points* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
+ transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
+ const vfloat4 b0 = vfloat4(geom->normal(primID(0)));
+ const vfloat4 b1 = vfloat4(geom->normal(primID(1)));
+ const vfloat4 b2 = vfloat4(geom->normal(primID(2)));
+ const vfloat4 b3 = vfloat4(geom->normal(primID(3)));
+ transpose(b0, b1, b2, b3, n0.x, n0.y, n0.z);
+ }
+
+ template<>
+ __forceinline void PointMi<4>::gatheri(Vec4vf4& p0, const Points* geom, const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
+ transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
+ }
+
+ template<>
+ __forceinline void PointMi<4>::gatheri(Vec4vf4& p0, Vec3vf4& n0, const Points* geom, const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
+ transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
+ const vfloat4 b0 = vfloat4(geom->normal(primID(0), itime));
+ const vfloat4 b1 = vfloat4(geom->normal(primID(1), itime));
+ const vfloat4 b2 = vfloat4(geom->normal(primID(2), itime));
+ const vfloat4 b3 = vfloat4(geom->normal(primID(3), itime));
+ transpose(b0, b1, b2, b3, n0.x, n0.y, n0.z);
+ }
+
+ template<>
+ __forceinline void PointMi<4>::gather(Vec4vf4& p0, const Points* geom, float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf4 a0; gatheri(a0, geom, itime);
+ Vec4vf4 b0; gatheri(b0, geom, itime + 1);
+ p0 = lerp(a0, b0, vfloat4(ftime));
+ }
+
+ template<>
+ __forceinline void PointMi<4>::gather(Vec4vf4& p0, Vec3vf4& n0, const Points* geom, float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf4 a0, b0;
+ Vec3vf4 norm0, norm1;
+ gatheri(a0, norm0, geom, itime);
+ gatheri(b0, norm1, geom, itime + 1);
+ p0 = lerp(a0, b0, vfloat4(ftime));
+ n0 = lerp(norm0, norm1, vfloat4(ftime));
+ }
+
+#if defined(__AVX__)
+
+ template<>
+ __forceinline void PointMi<8>::gather(Vec4vf8& p0, const Points* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4)));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5)));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6)));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7)));
+ transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
+ }
+
+ template<>
+ __forceinline void PointMi<8>::gather(Vec4vf8& p0, Vec3vf8& n0, const Points* geom) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4)));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5)));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6)));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7)));
+ transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
+ const vfloat4 b0 = vfloat4(geom->normal(primID(0)));
+ const vfloat4 b1 = vfloat4(geom->normal(primID(1)));
+ const vfloat4 b2 = vfloat4(geom->normal(primID(2)));
+ const vfloat4 b3 = vfloat4(geom->normal(primID(3)));
+ const vfloat4 b4 = vfloat4(geom->normal(primID(4)));
+ const vfloat4 b5 = vfloat4(geom->normal(primID(5)));
+ const vfloat4 b6 = vfloat4(geom->normal(primID(6)));
+ const vfloat4 b7 = vfloat4(geom->normal(primID(7)));
+ transpose(b0, b1, b2, b3, b4, b5, b6, b7, n0.x, n0.y, n0.z);
+ }
+
+ template<>
+ __forceinline void PointMi<8>::gatheri(Vec4vf8& p0, const Points* geom, const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4), itime));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5), itime));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6), itime));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7), itime));
+ transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
+ }
+
+ template<>
+ __forceinline void PointMi<8>::gatheri(Vec4vf8& p0, Vec3vf8& n0, const Points* geom, const int itime) const
+ {
+ const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
+ const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
+ const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
+ const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
+ const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4), itime));
+ const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5), itime));
+ const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6), itime));
+ const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7), itime));
+ transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
+ const vfloat4 b0 = vfloat4(geom->normal(primID(0), itime));
+ const vfloat4 b1 = vfloat4(geom->normal(primID(1), itime));
+ const vfloat4 b2 = vfloat4(geom->normal(primID(2), itime));
+ const vfloat4 b3 = vfloat4(geom->normal(primID(3), itime));
+ const vfloat4 b4 = vfloat4(geom->normal(primID(4), itime));
+ const vfloat4 b5 = vfloat4(geom->normal(primID(5), itime));
+ const vfloat4 b6 = vfloat4(geom->normal(primID(6), itime));
+ const vfloat4 b7 = vfloat4(geom->normal(primID(7), itime));
+ transpose(b0, b1, b2, b3, b4, b5, b6, b7, n0.x, n0.y, n0.z);
+ }
+
+ template<>
+ __forceinline void PointMi<8>::gather(Vec4vf8& p0, const Points* geom, float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf8 a0;
+ gatheri(a0, geom, itime);
+ Vec4vf8 b0;
+ gatheri(b0, geom, itime + 1);
+ p0 = lerp(a0, b0, vfloat8(ftime));
+ }
+
+ template<>
+ __forceinline void PointMi<8>::gather(Vec4vf8& p0, Vec3vf8& n0, const Points* geom, float time) const
+ {
+ float ftime;
+ const int itime = geom->timeSegment(time, ftime);
+
+ Vec4vf8 a0, b0;
+ Vec3vf8 norm0, norm1;
+ gatheri(a0, norm0, geom, itime);
+ gatheri(b0, norm1, geom, itime + 1);
+ p0 = lerp(a0, b0, vfloat8(ftime));
+ n0 = lerp(norm0, norm1, vfloat8(ftime));
+ }
+#endif
+
+ template<int M>
+ typename PointMi<M>::Type PointMi<M>::type;
+
+ typedef PointMi<4> Point4i;
+ typedef PointMi<8> Point8i;
+
+} // namespace embree
diff --git a/thirdparty/embree/kernels/geometry/primitive.h b/thirdparty/embree/kernels/geometry/primitive.h
new file mode 100644
index 0000000000..608d981dd7
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/primitive.h
@@ -0,0 +1,49 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/scene.h"
+#include "../../common/simd/simd.h"
+#include "../common/primref.h"
+#include "../common/primref_mb.h"
+
+namespace embree
+{
+ struct PrimitiveType
+ {
+ /*! returns name of this primitive type */
+ virtual const char* name() const = 0;
+
+ /*! Returns the number of stored active primitives in a block. */
+ virtual size_t sizeActive(const char* This) const = 0;
+
+ /*! Returns the number of stored active and inactive primitives in a block. */
+ virtual size_t sizeTotal(const char* This) const = 0;
+
+ /*! Returns the number of bytes of block. */
+ virtual size_t getBytes(const char* This) const = 0;
+ };
+
+ template<typename Primitive>
+ struct PrimitivePointQuery1
+ {
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim)
+ {
+ bool changed = false;
+ for (size_t i = 0; i < Primitive::max_size(); i++)
+ {
+ if (!prim.valid(i)) break;
+ STAT3(point_query.trav_prims,1,1,1);
+ AccelSet* accel = (AccelSet*)context->scene->get(prim.geomID(i));
+ context->geomID = prim.geomID(i);
+ context->primID = prim.primID(i);
+ changed |= accel->pointQuery(query, context);
+ }
+ return changed;
+ }
+
+ static __forceinline void pointQueryNoop(PointQuery* query, PointQueryContext* context, const Primitive& prim) { }
+ };
+}
diff --git a/thirdparty/embree/kernels/geometry/primitive4.cpp b/thirdparty/embree/kernels/geometry/primitive4.cpp
new file mode 100644
index 0000000000..9c953c5d35
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/primitive4.cpp
@@ -0,0 +1,379 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "primitive.h"
+#include "curveNv.h"
+#include "curveNi.h"
+#include "curveNi_mb.h"
+#include "linei.h"
+#include "triangle.h"
+#include "trianglev.h"
+#include "trianglev_mb.h"
+#include "trianglei.h"
+#include "quadv.h"
+#include "quadi.h"
+#include "subdivpatch1.h"
+#include "object.h"
+#include "instance.h"
+#include "subgrid.h"
+
+namespace embree
+{
+ /********************** Curve4v **************************/
+
+ template<>
+ const char* Curve4v::Type::name () const {
+ return "curve4v";
+ }
+
+ template<>
+ size_t Curve4v::Type::sizeActive(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return ((Line4i*)This)->size();
+ else
+ return ((Curve4v*)This)->N;
+ }
+
+ template<>
+ size_t Curve4v::Type::sizeTotal(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return 4;
+ else
+ return ((Curve4v*)This)->N;
+ }
+
+ template<>
+ size_t Curve4v::Type::getBytes(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return Line4i::bytes(sizeActive(This));
+ else
+ return Curve4v::bytes(sizeActive(This));
+ }
+
+ /********************** Curve4i **************************/
+
+ template<>
+ const char* Curve4i::Type::name () const {
+ return "curve4i";
+ }
+
+ template<>
+ size_t Curve4i::Type::sizeActive(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return ((Line4i*)This)->size();
+ else
+ return ((Curve4i*)This)->N;
+ }
+
+ template<>
+ size_t Curve4i::Type::sizeTotal(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return 4;
+ else
+ return ((Curve4i*)This)->N;
+ }
+
+ template<>
+ size_t Curve4i::Type::getBytes(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return Line4i::bytes(sizeActive(This));
+ else
+ return Curve4i::bytes(sizeActive(This));
+ }
+
+ /********************** Curve4iMB **************************/
+
+ template<>
+ const char* Curve4iMB::Type::name () const {
+ return "curve4imb";
+ }
+
+ template<>
+ size_t Curve4iMB::Type::sizeActive(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return ((Line4i*)This)->size();
+ else
+ return ((Curve4iMB*)This)->N;
+ }
+
+ template<>
+ size_t Curve4iMB::Type::sizeTotal(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return 4;
+ else
+ return ((Curve4iMB*)This)->N;
+ }
+
+ template<>
+ size_t Curve4iMB::Type::getBytes(const char* This) const
+ {
+ if ((*This & Geometry::GType::GTY_BASIS_MASK) == Geometry::GType::GTY_BASIS_LINEAR)
+ return Line4i::bytes(sizeActive(This));
+ else
+ return Curve4iMB::bytes(sizeActive(This));
+ }
+
+ /********************** Line4i **************************/
+
+ template<>
+ const char* Line4i::Type::name () const {
+ return "line4i";
+ }
+
+ template<>
+ size_t Line4i::Type::sizeActive(const char* This) const {
+ return ((Line4i*)This)->size();
+ }
+
+ template<>
+ size_t Line4i::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Line4i::Type::getBytes(const char* This) const {
+ return sizeof(Line4i);
+ }
+
+ /********************** Triangle4 **************************/
+
+ template<>
+ const char* Triangle4::Type::name () const {
+ return "triangle4";
+ }
+
+ template<>
+ size_t Triangle4::Type::sizeActive(const char* This) const {
+ return ((Triangle4*)This)->size();
+ }
+
+ template<>
+ size_t Triangle4::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Triangle4::Type::getBytes(const char* This) const {
+ return sizeof(Triangle4);
+ }
+
+ /********************** Triangle4v **************************/
+
+ template<>
+ const char* Triangle4v::Type::name () const {
+ return "triangle4v";
+ }
+
+ template<>
+ size_t Triangle4v::Type::sizeActive(const char* This) const {
+ return ((Triangle4v*)This)->size();
+ }
+
+ template<>
+ size_t Triangle4v::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Triangle4v::Type::getBytes(const char* This) const {
+ return sizeof(Triangle4v);
+ }
+
+ /********************** Triangle4i **************************/
+
+ template<>
+ const char* Triangle4i::Type::name () const {
+ return "triangle4i";
+ }
+
+ template<>
+ size_t Triangle4i::Type::sizeActive(const char* This) const {
+ return ((Triangle4i*)This)->size();
+ }
+
+ template<>
+ size_t Triangle4i::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Triangle4i::Type::getBytes(const char* This) const {
+ return sizeof(Triangle4i);
+ }
+
+ /********************** Triangle4vMB **************************/
+
+ template<>
+ const char* Triangle4vMB::Type::name () const {
+ return "triangle4vmb";
+ }
+
+ template<>
+ size_t Triangle4vMB::Type::sizeActive(const char* This) const {
+ return ((Triangle4vMB*)This)->size();
+ }
+
+ template<>
+ size_t Triangle4vMB::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Triangle4vMB::Type::getBytes(const char* This) const {
+ return sizeof(Triangle4vMB);
+ }
+
+ /********************** Quad4v **************************/
+
+ template<>
+ const char* Quad4v::Type::name () const {
+ return "quad4v";
+ }
+
+ template<>
+ size_t Quad4v::Type::sizeActive(const char* This) const {
+ return ((Quad4v*)This)->size();
+ }
+
+ template<>
+ size_t Quad4v::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Quad4v::Type::getBytes(const char* This) const {
+ return sizeof(Quad4v);
+ }
+
+ /********************** Quad4i **************************/
+
+ template<>
+ const char* Quad4i::Type::name () const {
+ return "quad4i";
+ }
+
+ template<>
+ size_t Quad4i::Type::sizeActive(const char* This) const {
+ return ((Quad4i*)This)->size();
+ }
+
+ template<>
+ size_t Quad4i::Type::sizeTotal(const char* This) const {
+ return 4;
+ }
+
+ template<>
+ size_t Quad4i::Type::getBytes(const char* This) const {
+ return sizeof(Quad4i);
+ }
+
+ /********************** SubdivPatch1 **************************/
+
+ const char* SubdivPatch1::Type::name () const {
+ return "subdivpatch1";
+ }
+
+ size_t SubdivPatch1::Type::sizeActive(const char* This) const {
+ return 1;
+ }
+
+ size_t SubdivPatch1::Type::sizeTotal(const char* This) const {
+ return 1;
+ }
+
+ size_t SubdivPatch1::Type::getBytes(const char* This) const {
+ return sizeof(SubdivPatch1);
+ }
+
+ SubdivPatch1::Type SubdivPatch1::type;
+
+ /********************** Virtual Object **************************/
+
+ const char* Object::Type::name () const {
+ return "object";
+ }
+
+ size_t Object::Type::sizeActive(const char* This) const {
+ return 1;
+ }
+
+ size_t Object::Type::sizeTotal(const char* This) const {
+ return 1;
+ }
+
+ size_t Object::Type::getBytes(const char* This) const {
+ return sizeof(Object);
+ }
+
+ Object::Type Object::type;
+
+ /********************** Instance **************************/
+
+ const char* InstancePrimitive::Type::name () const {
+ return "instance";
+ }
+
+ size_t InstancePrimitive::Type::sizeActive(const char* This) const {
+ return 1;
+ }
+
+ size_t InstancePrimitive::Type::sizeTotal(const char* This) const {
+ return 1;
+ }
+
+ size_t InstancePrimitive::Type::getBytes(const char* This) const {
+ return sizeof(InstancePrimitive);
+ }
+
+ InstancePrimitive::Type InstancePrimitive::type;
+
+ /********************** SubGrid **************************/
+
+ const char* SubGrid::Type::name () const {
+ return "subgrid";
+ }
+
+ size_t SubGrid::Type::sizeActive(const char* This) const {
+ return 1;
+ }
+
+ size_t SubGrid::Type::sizeTotal(const char* This) const {
+ return 1;
+ }
+
+ size_t SubGrid::Type::getBytes(const char* This) const {
+ return sizeof(SubGrid);
+ }
+
+ SubGrid::Type SubGrid::type;
+
+ /********************** SubGridQBVH4 **************************/
+
+ template<>
+ const char* SubGridQBVH4::Type::name () const {
+ return "SubGridQBVH4";
+ }
+
+ template<>
+ size_t SubGridQBVH4::Type::sizeActive(const char* This) const {
+ return 1;
+ }
+
+ template<>
+ size_t SubGridQBVH4::Type::sizeTotal(const char* This) const {
+ return 1;
+ }
+
+ template<>
+ size_t SubGridQBVH4::Type::getBytes(const char* This) const {
+ return sizeof(SubGridQBVH4);
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/quad_intersector.h b/thirdparty/embree/kernels/geometry/quad_intersector.h
new file mode 100644
index 0000000000..93c9526912
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/quad_intersector.h
@@ -0,0 +1,76 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects a ray with a quad with backface culling
+ * enabled. The quad v0,v1,v2,v3 is split into two triangles
+ * v0,v1,v3 and v2,v3,v1. The edge v1,v2 decides which of the two
+ * triangles gets intersected. */
+ template<int N>
+ __forceinline vbool<N> intersect_quad_backface_culling(const vbool<N>& valid0,
+ const Vec3fa& ray_org,
+ const Vec3fa& ray_dir,
+ const float ray_tnear,
+ const float ray_tfar,
+ const Vec3vf<N>& quad_v0,
+ const Vec3vf<N>& quad_v1,
+ const Vec3vf<N>& quad_v2,
+ const Vec3vf<N>& quad_v3,
+ vfloat<N>& u_o,
+ vfloat<N>& v_o,
+ vfloat<N>& t_o)
+ {
+ /* calculate vertices relative to ray origin */
+ vbool<N> valid = valid0;
+ const Vec3vf<N> O = Vec3vf<N>(ray_org);
+ const Vec3vf<N> D = Vec3vf<N>(ray_dir);
+ const Vec3vf<N> va = quad_v0-O;
+ const Vec3vf<N> vb = quad_v1-O;
+ const Vec3vf<N> vc = quad_v2-O;
+ const Vec3vf<N> vd = quad_v3-O;
+
+ const Vec3vf<N> edb = vb-vd;
+ const vfloat<N> WW = dot(cross(vd,edb),D);
+ const Vec3vf<N> v0 = select(WW <= 0.0f,va,vc);
+ const Vec3vf<N> v1 = select(WW <= 0.0f,vb,vd);
+ const Vec3vf<N> v2 = select(WW <= 0.0f,vd,vb);
+
+ /* calculate edges */
+ const Vec3vf<N> e0 = v2-v0;
+ const Vec3vf<N> e1 = v0-v1;
+
+ /* perform edge tests */
+ const vfloat<N> U = dot(cross(v0,e0),D);
+ const vfloat<N> V = dot(cross(v1,e1),D);
+ valid &= max(U,V) <= 0.0f;
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<N> Ng = cross(e1,e0);
+ const vfloat<N> den = dot(Ng,D);
+ const vfloat<N> rcpDen = rcp(den);
+
+ /* perform depth test */
+ const vfloat<N> t = rcpDen*dot(v0,Ng);
+ valid &= vfloat<N>(ray_tnear) <= t & t <= vfloat<N>(ray_tfar);
+ if (unlikely(none(valid))) return false;
+
+ /* avoid division by 0 */
+ valid &= den != vfloat<N>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ t_o = t;
+ u_o = U * rcpDen;
+ v_o = V * rcpDen;
+ u_o = select(WW <= 0.0f,u_o,1.0f-u_o);
+ v_o = select(WW <= 0.0f,v_o,1.0f-v_o);
+ return valid;
+ }
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/quad_intersector_moeller.h b/thirdparty/embree/kernels/geometry/quad_intersector_moeller.h
new file mode 100644
index 0000000000..3abc9d6f70
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/quad_intersector_moeller.h
@@ -0,0 +1,460 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "quadv.h"
+#include "triangle_intersector_moeller.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct QuadHitM
+ {
+ __forceinline QuadHitM() {}
+
+ __forceinline QuadHitM(const vbool<M>& valid,
+ const vfloat<M>& U,
+ const vfloat<M>& V,
+ const vfloat<M>& T,
+ const vfloat<M>& absDen,
+ const Vec3vf<M>& Ng,
+ const vbool<M>& flags)
+ : U(U), V(V), T(T), absDen(absDen), tri_Ng(Ng), valid(valid), flags(flags) {}
+
+ __forceinline void finalize()
+ {
+ const vfloat<M> rcpAbsDen = rcp(absDen);
+ vt = T * rcpAbsDen;
+ const vfloat<M> u = min(U * rcpAbsDen,1.0f);
+ const vfloat<M> v = min(V * rcpAbsDen,1.0f);
+ const vfloat<M> u1 = vfloat<M>(1.0f) - u;
+ const vfloat<M> v1 = vfloat<M>(1.0f) - v;
+#if !defined(__AVX__) || defined(EMBREE_BACKFACE_CULLING)
+ vu = select(flags,u1,u);
+ vv = select(flags,v1,v);
+ vNg = Vec3vf<M>(tri_Ng.x,tri_Ng.y,tri_Ng.z);
+#else
+ const vfloat<M> flip = select(flags,vfloat<M>(-1.0f),vfloat<M>(1.0f));
+ vv = select(flags,u1,v);
+ vu = select(flags,v1,u);
+ vNg = Vec3vf<M>(flip*tri_Ng.x,flip*tri_Ng.y,flip*tri_Ng.z);
+#endif
+ }
+
+ __forceinline Vec2f uv(const size_t i)
+ {
+ const float u = vu[i];
+ const float v = vv[i];
+ return Vec2f(u,v);
+ }
+
+ __forceinline float t(const size_t i) { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ private:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> T;
+ vfloat<M> absDen;
+ Vec3vf<M> tri_Ng;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+
+ public:
+ const vbool<M> flags;
+ };
+
+ template<int K>
+ struct QuadHitK
+ {
+ __forceinline QuadHitK(const vfloat<K>& U,
+ const vfloat<K>& V,
+ const vfloat<K>& T,
+ const vfloat<K>& absDen,
+ const Vec3vf<K>& Ng,
+ const vbool<K>& flags)
+ : U(U), V(V), T(T), absDen(absDen), flags(flags), tri_Ng(Ng) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vfloat<K> rcpAbsDen = rcp(absDen);
+ const vfloat<K> t = T * rcpAbsDen;
+ const vfloat<K> u0 = min(U * rcpAbsDen,1.0f);
+ const vfloat<K> v0 = min(V * rcpAbsDen,1.0f);
+ const vfloat<K> u1 = vfloat<K>(1.0f) - u0;
+ const vfloat<K> v1 = vfloat<K>(1.0f) - v0;
+ const vfloat<K> u = select(flags,u1,u0);
+ const vfloat<K> v = select(flags,v1,v0);
+ const Vec3vf<K> Ng(tri_Ng.x,tri_Ng.y,tri_Ng.z);
+ return std::make_tuple(u,v,t,Ng);
+ }
+
+ private:
+ const vfloat<K> U;
+ const vfloat<K> V;
+ const vfloat<K> T;
+ const vfloat<K> absDen;
+ const vbool<K> flags;
+ const Vec3vf<K> tri_Ng;
+ };
+
+ /* ----------------------------- */
+ /* -- single ray intersectors -- */
+ /* ----------------------------- */
+
+
+ template<int M, bool filter>
+ struct QuadMIntersector1MoellerTrumbore;
+
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMIntersector1MoellerTrumbore
+ {
+ __forceinline QuadMIntersector1MoellerTrumbore() {}
+
+ __forceinline QuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
+
+ __forceinline void intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ UVIdentity<M> mapUV;
+ MoellerTrumboreHitM<M,UVIdentity<M>> hit(mapUV);
+ MoellerTrumboreIntersector1<M> intersector(ray,nullptr);
+ Intersect1EpilogM<M,filter> epilog(ray,context,geomID,primID);
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,v0,v1,v3,mapUV,hit))
+ epilog(hit.valid,hit);
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,v2,v3,v1,mapUV,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ epilog(hit.valid,hit);
+ }
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ UVIdentity<M> mapUV;
+ MoellerTrumboreHitM<M,UVIdentity<M>> hit(mapUV);
+ MoellerTrumboreIntersector1<M> intersector(ray,nullptr);
+ Occluded1EpilogM<M,filter> epilog(ray,context,geomID,primID);
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,v0,v1,v3,mapUV,hit))
+ {
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,v2,v3,v1,mapUV,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+ return false;
+ }
+ };
+
+#if defined(__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<bool filter>
+ struct QuadMIntersector1MoellerTrumbore<4,filter>
+ {
+ __forceinline QuadMIntersector1MoellerTrumbore() {}
+
+ __forceinline QuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ UVIdentity<8> mapUV;
+ MoellerTrumboreHitM<8,UVIdentity<8>> hit(mapUV);
+ MoellerTrumboreIntersector1<8> intersector(ray,nullptr);
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ if (unlikely(intersector.intersect(ray,vtx0,vtx1,vtx2,mapUV,hit)))
+ {
+ vfloat8 U = hit.U, V = hit.V, absDen = hit.absDen;
+
+#if !defined(EMBREE_BACKFACE_CULLING)
+ hit.U = select(flags,absDen-V,U);
+ hit.V = select(flags,absDen-U,V);
+ hit.vNg *= select(flags,vfloat8(-1.0f),vfloat8(1.0f)); // FIXME: use XOR
+#else
+ hit.U = select(flags,absDen-U,U);
+ hit.V = select(flags,absDen-V,V);
+#endif
+ if (unlikely(epilog(hit.valid,hit)))
+ return true;
+ }
+ return false;
+ }
+
+ __forceinline bool intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Intersect1EpilogM<8,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Occluded1EpilogM<8,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#endif
+
+ /* ----------------------------- */
+ /* -- ray packet intersectors -- */
+ /* ----------------------------- */
+
+
+ struct MoellerTrumboreIntersector1KTriangleM
+ {
+ /*! Intersect k'th ray from ray packet of size K with M triangles. */
+ template<int M, int K, typename Epilog>
+ static __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Vec3vf<M>& tri_Ng,
+ const vbool<M>& flags,
+ const Epilog& epilog)
+ {
+ /* calculate denominator */
+ const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vf<M> C = Vec3vf<M>(tri_v0) - O;
+ const Vec3vf<M> R = cross(C,D);
+ const vfloat<M> den = dot(Vec3vf<M>(tri_Ng),D);
+ const vfloat<M> absDen = abs(den);
+ const vfloat<M> sgnDen = signmsk(den);
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(R,Vec3vf<M>(tri_e2)) ^ sgnDen;
+ const vfloat<M> V = dot(R,Vec3vf<M>(tri_e1)) ^ sgnDen;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = (den < vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#else
+ vbool<M> valid = (den != vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#endif
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen;
+ valid &= (absDen*vfloat<M>(ray.tnear()[k]) < T) & (T <= absDen*vfloat<M>(ray.tfar[k]));
+ if (likely(none(valid))) return false;
+
+ /* calculate hit information */
+ QuadHitM<M> hit(valid,U,V,T,absDen,tri_Ng,flags);
+ return epilog(valid,hit);
+ }
+
+ template<int M, int K, typename Epilog>
+ static __forceinline bool intersect1(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const vbool<M>& flags,
+ const Epilog& epilog)
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ const Vec3vf<M> Ng = cross(e2,e1);
+ return intersect<M,K>(ray,k,v0,e1,e2,Ng,flags,epilog);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct QuadMIntersectorKMoellerTrumboreBase
+ {
+ __forceinline QuadMIntersectorKMoellerTrumboreBase(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const Vec3vf<K>& tri_Ng,
+ const vbool<K>& flags,
+ const Epilog& epilog) const
+ {
+ /* calculate denominator */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> C = tri_v0 - ray.org;
+ const Vec3vf<K> R = cross(C,ray.dir);
+ const vfloat<K> den = dot(tri_Ng,ray.dir);
+ const vfloat<K> absDen = abs(den);
+ const vfloat<K> sgnDen = signmsk(den);
+
+ /* test against edge p2 p0 */
+ const vfloat<K> U = dot(R,tri_e2) ^ sgnDen;
+ valid &= U >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p0 p1 */
+ const vfloat<K> V = dot(R,tri_e1) ^ sgnDen;
+ valid &= V >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p1 p2 */
+ const vfloat<K> W = absDen-U-V;
+ valid &= W >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<K> T = dot(tri_Ng,C) ^ sgnDen;
+ valid &= (absDen*ray.tnear() < T) & (T <= absDen*ray.tfar);
+ if (unlikely(none(valid))) return false;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= den < vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#else
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* calculate hit information */
+ QuadHitK<K> hit(U,V,T,absDen,tri_Ng,flags);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersects K rays with one of M quads. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const vbool<K>& flags,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<K> e1 = tri_v0-tri_v1;
+ const Vec3vf<K> e2 = tri_v2-tri_v0;
+ const Vec3vf<K> Ng = cross(e2,e1);
+ return intersectK(valid0,ray,tri_v0,e1,e2,Ng,flags,epilog);
+ }
+
+ /*! Intersects K rays with one of M quads. */
+ template<typename Epilog>
+ __forceinline bool intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const Vec3vf<K>& v3,
+ const Epilog& epilog) const
+ {
+ intersectK(valid0,ray,v0,v1,v3,vbool<K>(false),epilog);
+ if (none(valid0)) return true;
+ intersectK(valid0,ray,v2,v3,v1,vbool<K>(true ),epilog);
+ return none(valid0);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct QuadMIntersectorKMoellerTrumbore : public QuadMIntersectorKMoellerTrumboreBase<M,K,filter>
+ {
+ __forceinline QuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
+ : QuadMIntersectorKMoellerTrumboreBase<M,K,filter>(valid,ray) {}
+
+ __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Intersect1KEpilogM<M,K,filter> epilog(ray,k,context,geomID,primID);
+ MoellerTrumboreIntersector1KTriangleM::intersect1<M,K>(ray,k,v0,v1,v3,vbool<M>(false),epilog);
+ MoellerTrumboreIntersector1KTriangleM::intersect1<M,K>(ray,k,v2,v3,v1,vbool<M>(true ),epilog);
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Occluded1KEpilogM<M,K,filter> epilog(ray,k,context,geomID,primID);
+ if (MoellerTrumboreIntersector1KTriangleM::intersect1<M,K>(ray,k,v0,v1,v3,vbool<M>(false),epilog)) return true;
+ if (MoellerTrumboreIntersector1KTriangleM::intersect1<M,K>(ray,k,v2,v3,v1,vbool<M>(true ),epilog)) return true;
+ return false;
+ }
+ };
+
+
+#if defined(__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<int K, bool filter>
+ struct QuadMIntersectorKMoellerTrumbore<4,K,filter> : public QuadMIntersectorKMoellerTrumboreBase<4,K,filter>
+ {
+ __forceinline QuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
+ : QuadMIntersectorKMoellerTrumboreBase<4,K,filter>(valid,ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect1(RayK<K>& ray, size_t k,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ return MoellerTrumboreIntersector1KTriangleM::intersect1<8,K>(ray,k,vtx0,vtx1,vtx2,flags,epilog);
+ }
+
+ __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Intersect1KEpilogM<8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Occluded1KEpilogM<8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#endif
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/quad_intersector_pluecker.h b/thirdparty/embree/kernels/geometry/quad_intersector_pluecker.h
new file mode 100644
index 0000000000..9873ff76ac
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/quad_intersector_pluecker.h
@@ -0,0 +1,438 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "quad_intersector_moeller.h"
+
+/*! Modified Pluecker ray/triangle intersector. The test first shifts
+ * the ray origin into the origin of the coordinate system and then
+ * uses Pluecker coordinates for the intersection. Due to the shift,
+ * the Pluecker coordinate calculation simplifies and the tests get
+ * numerically stable. The edge equations are watertight along the
+ * edge for neighboring triangles. */
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct QuadHitPlueckerM
+ {
+ __forceinline QuadHitPlueckerM() {}
+
+ __forceinline QuadHitPlueckerM(const vbool<M>& valid,
+ const vfloat<M>& U,
+ const vfloat<M>& V,
+ const vfloat<M>& UVW,
+ const vfloat<M>& t,
+ const Vec3vf<M>& Ng,
+ const vbool<M>& flags)
+ : U(U), V(V), UVW(UVW), tri_Ng(Ng), valid(valid), vt(t), flags(flags) {}
+
+ __forceinline void finalize()
+ {
+ const vbool<M> invalid = abs(UVW) < min_rcp_input;
+ const vfloat<M> rcpUVW = select(invalid,vfloat<M>(0.0f),rcp(UVW));
+ const vfloat<M> u = min(U * rcpUVW,1.0f);
+ const vfloat<M> v = min(V * rcpUVW,1.0f);
+ const vfloat<M> u1 = vfloat<M>(1.0f) - u;
+ const vfloat<M> v1 = vfloat<M>(1.0f) - v;
+#if !defined(__AVX__) || defined(EMBREE_BACKFACE_CULLING)
+ vu = select(flags,u1,u);
+ vv = select(flags,v1,v);
+ vNg = Vec3vf<M>(tri_Ng.x,tri_Ng.y,tri_Ng.z);
+#else
+ const vfloat<M> flip = select(flags,vfloat<M>(-1.0f),vfloat<M>(1.0f));
+ vv = select(flags,u1,v);
+ vu = select(flags,v1,u);
+ vNg = Vec3vf<M>(flip*tri_Ng.x,flip*tri_Ng.y,flip*tri_Ng.z);
+#endif
+ }
+
+ __forceinline Vec2f uv(const size_t i)
+ {
+ const float u = vu[i];
+ const float v = vv[i];
+ return Vec2f(u,v);
+ }
+
+ __forceinline float t(const size_t i) { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ private:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> UVW;
+ Vec3vf<M> tri_Ng;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+
+ public:
+ const vbool<M> flags;
+ };
+
+ template<int K>
+ struct QuadHitPlueckerK
+ {
+ __forceinline QuadHitPlueckerK(const vfloat<K>& U,
+ const vfloat<K>& V,
+ const vfloat<K>& UVW,
+ const vfloat<K>& t,
+ const Vec3vf<K>& Ng,
+ const vbool<K>& flags)
+ : U(U), V(V), UVW(UVW), t(t), flags(flags), tri_Ng(Ng) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vbool<K> invalid = abs(UVW) < min_rcp_input;
+ const vfloat<K> rcpUVW = select(invalid,vfloat<K>(0.0f),rcp(UVW));
+ const vfloat<K> u0 = min(U * rcpUVW,1.0f);
+ const vfloat<K> v0 = min(V * rcpUVW,1.0f);
+ const vfloat<K> u1 = vfloat<K>(1.0f) - u0;
+ const vfloat<K> v1 = vfloat<K>(1.0f) - v0;
+ const vfloat<K> u = select(flags,u1,u0);
+ const vfloat<K> v = select(flags,v1,v0);
+ const Vec3vf<K> Ng(tri_Ng.x,tri_Ng.y,tri_Ng.z);
+ return std::make_tuple(u,v,t,Ng);
+ }
+
+ private:
+ const vfloat<K> U;
+ const vfloat<K> V;
+ const vfloat<K> UVW;
+ const vfloat<K> t;
+ const vbool<K> flags;
+ const Vec3vf<K> tri_Ng;
+ };
+
+ struct PlueckerIntersectorTriangle1
+ {
+ template<int M, typename Epilog>
+ static __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const vbool<M>& flags,
+ const Epilog& epilog)
+ {
+ /* calculate vertices relative to ray origin */
+ const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org);
+ const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir);
+ const Vec3vf<M> v0 = tri_v0-O;
+ const Vec3vf<M> v1 = tri_v1-O;
+ const Vec3vf<M> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<M> e0 = v2-v0;
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(cross(e0,v2+v0),D);
+ const vfloat<M> V = dot(cross(e1,v0+v1),D);
+ const vfloat<M> W = dot(cross(e2,v1+v2),D);
+ const vfloat<M> UVW = U+V+W;
+ const vfloat<M> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = max(U,V,W) <= eps;
+#else
+ vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<M> den = twice(dot(Ng,D));
+
+ /* perform depth test */
+ const vfloat<M> T = twice(dot(v0,Ng));
+ const vfloat<M> t = rcp(den)*T;
+ valid &= vfloat<M>(ray.tnear()) <= t & t <= vfloat<M>(ray.tfar);
+ valid &= den != vfloat<M>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ QuadHitPlueckerM<M> hit(valid,U,V,UVW,t,Ng,flags);
+ return epilog(valid,hit);
+ }
+ };
+
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMIntersector1Pluecker
+ {
+ __forceinline QuadMIntersector1Pluecker() {}
+
+ __forceinline QuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
+
+ __forceinline void intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Intersect1EpilogM<M,filter> epilog(ray,context,geomID,primID);
+ PlueckerIntersectorTriangle1::intersect<M>(ray,v0,v1,v3,vbool<M>(false),epilog);
+ PlueckerIntersectorTriangle1::intersect<M>(ray,v2,v3,v1,vbool<M>(true),epilog);
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Occluded1EpilogM<M,filter> epilog(ray,context,geomID,primID);
+ if (PlueckerIntersectorTriangle1::intersect<M>(ray,v0,v1,v3,vbool<M>(false),epilog)) return true;
+ if (PlueckerIntersectorTriangle1::intersect<M>(ray,v2,v3,v1,vbool<M>(true ),epilog)) return true;
+ return false;
+ }
+ };
+
+#if defined(__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<bool filter>
+ struct QuadMIntersector1Pluecker<4,filter>
+ {
+ __forceinline QuadMIntersector1Pluecker() {}
+
+ __forceinline QuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ return PlueckerIntersectorTriangle1::intersect<8>(ray,vtx0,vtx1,vtx2,flags,epilog);
+ }
+
+ __forceinline bool intersect(RayHit& ray, IntersectContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Intersect1EpilogM<8,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect(ray,v0,v1,v2,v3,Occluded1EpilogM<8,filter>(ray,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#endif
+
+
+ /* ----------------------------- */
+ /* -- ray packet intersectors -- */
+ /* ----------------------------- */
+
+ struct PlueckerIntersector1KTriangleM
+ {
+ /*! Intersect k'th ray from ray packet of size K with M triangles. */
+ template<int M, int K, typename Epilog>
+ static __forceinline bool intersect1(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const vbool<M>& flags,
+ const Epilog& epilog)
+ {
+ /* calculate vertices relative to ray origin */
+ const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vf<M> v0 = tri_v0-O;
+ const Vec3vf<M> v1 = tri_v1-O;
+ const Vec3vf<M> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<M> e0 = v2-v0;
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(cross(e0,v2+v0),D);
+ const vfloat<M> V = dot(cross(e1,v0+v1),D);
+ const vfloat<M> W = dot(cross(e2,v1+v2),D);
+
+ const vfloat<M> UVW = U+V+W;
+ const vfloat<M> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = max(U,V,W) <= eps;
+#else
+ vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<M> den = twice(dot(Ng,D));
+
+ /* perform depth test */
+ const vfloat<M> T = twice(dot(v0,Ng));
+ const vfloat<M> t = rcp(den)*T;
+ valid &= vfloat<M>(ray.tnear()[k]) <= t & t <= vfloat<M>(ray.tfar[k]);
+ if (unlikely(none(valid))) return false;
+
+ /* avoid division by 0 */
+ valid &= den != vfloat<M>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ QuadHitPlueckerM<M> hit(valid,U,V,UVW,t,Ng,flags);
+ return epilog(valid,hit);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct QuadMIntersectorKPlueckerBase
+ {
+ __forceinline QuadMIntersectorKPlueckerBase(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const vbool<K>& flags,
+ const Epilog& epilog) const
+ {
+ /* calculate vertices relative to ray origin */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> O = ray.org;
+ const Vec3vf<K> D = ray.dir;
+ const Vec3vf<K> v0 = tri_v0-O;
+ const Vec3vf<K> v1 = tri_v1-O;
+ const Vec3vf<K> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<K> e0 = v2-v0;
+ const Vec3vf<K> e1 = v0-v1;
+ const Vec3vf<K> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<K> U = dot(Vec3vf<K>(cross(e0,v2+v0)),D);
+ const vfloat<K> V = dot(Vec3vf<K>(cross(e1,v0+v1)),D);
+ const vfloat<K> W = dot(Vec3vf<K>(cross(e2,v1+v2)),D);
+ const vfloat<K> UVW = U+V+W;
+ const vfloat<K> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= max(U,V,W) <= eps;
+#else
+ valid &= (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<K> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<K> den = twice(dot(Vec3vf<K>(Ng),D));
+
+ /* perform depth test */
+ const vfloat<K> T = twice(dot(v0,Vec3vf<K>(Ng)));
+ const vfloat<K> t = rcp(den)*T;
+ valid &= ray.tnear() <= t & t <= ray.tfar;
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* calculate hit information */
+ QuadHitPlueckerK<K> hit(U,V,UVW,t,Ng,flags);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersects K rays with one of M quads. */
+ template<typename Epilog>
+ __forceinline bool intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const Vec3vf<K>& v3,
+ const Epilog& epilog) const
+ {
+ intersectK(valid0,ray,v0,v1,v3,vbool<K>(false),epilog);
+ if (none(valid0)) return true;
+ intersectK(valid0,ray,v2,v3,v1,vbool<K>(true ),epilog);
+ return none(valid0);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct QuadMIntersectorKPluecker : public QuadMIntersectorKPlueckerBase<M,K,filter>
+ {
+ __forceinline QuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
+ : QuadMIntersectorKPlueckerBase<M,K,filter>(valid,ray) {}
+
+ __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Intersect1KEpilogM<M,K,filter> epilog(ray,k,context,geomID,primID);
+ PlueckerIntersector1KTriangleM::intersect1<M,K>(ray,k,v0,v1,v3,vbool<M>(false),epilog);
+ PlueckerIntersector1KTriangleM::intersect1<M,K>(ray,k,v2,v3,v1,vbool<M>(true ),epilog);
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const vuint<M>& geomID, const vuint<M>& primID) const
+ {
+ Occluded1KEpilogM<M,K,filter> epilog(ray,k,context,geomID,primID);
+ if (PlueckerIntersector1KTriangleM::intersect1<M,K>(ray,k,v0,v1,v3,vbool<M>(false),epilog)) return true;
+ if (PlueckerIntersector1KTriangleM::intersect1<M,K>(ray,k,v2,v3,v1,vbool<M>(true ),epilog)) return true;
+ return false;
+ }
+ };
+
+#if defined(__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<int K, bool filter>
+ struct QuadMIntersectorKPluecker<4,K,filter> : public QuadMIntersectorKPlueckerBase<4,K,filter>
+ {
+ __forceinline QuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
+ : QuadMIntersectorKPlueckerBase<4,K,filter>(valid,ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect1(RayK<K>& ray, size_t k, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ return PlueckerIntersector1KTriangleM::intersect1<8,K>(ray,k,vtx0,vtx1,vtx2,flags,epilog);
+ }
+
+ __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Intersect1KEpilogM<8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const vuint4& geomID, const vuint4& primID) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,Occluded1KEpilogM<8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
+ }
+ };
+
+#endif
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/quadi.h b/thirdparty/embree/kernels/geometry/quadi.h
new file mode 100644
index 0000000000..70a7bdf158
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/quadi.h
@@ -0,0 +1,483 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "../common/scene.h"
+
+namespace embree
+{
+ /* Stores M quads from an indexed face set */
+ template <int M>
+ struct QuadMi
+ {
+ /* Virtual interface to query information about the quad type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored quads */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline QuadMi() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline QuadMi(const vuint<M>& v0,
+ const vuint<M>& v1,
+ const vuint<M>& v2,
+ const vuint<M>& v3,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+#if defined(EMBREE_COMPACT_POLYS)
+ : geomIDs(geomIDs), primIDs(primIDs) {}
+#else
+ : v0_(v0),v1_(v1), v2_(v2), v3_(v3), geomIDs(geomIDs), primIDs(primIDs) {}
+#endif
+
+ /* Returns a mask that tells which quads are valid */
+ __forceinline vbool<M> valid() const { return primIDs != vuint<M>(-1); }
+
+ /* Returns if the specified quad is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return primIDs[i] != -1; }
+
+ /* Returns the number of stored quads */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M>& geomID() { return geomIDs; }
+ __forceinline const vuint<M>& geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); assert(geomIDs[i] != -1); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M>& primID() { return primIDs; }
+ __forceinline const vuint<M>& primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the quads */
+ __forceinline const BBox3fa bounds(const Scene *const scene, const size_t itime=0) const
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M && valid(i); i++) {
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(i));
+ bounds.extend(mesh->bounds(primID(i),itime));
+ }
+ return bounds;
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds(const Scene* const scene, const size_t itime) {
+ return LBBox3fa(bounds(scene,itime+0),bounds(scene,itime+1));
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime, size_t numTimeSteps)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(i));
+ allBounds.extend(mesh->linearBounds(primID(i), itime, numTimeSteps));
+ }
+ return allBounds;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, const BBox1f time_range)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(i));
+ allBounds.extend(mesh->linearBounds(primID(i), time_range));
+ }
+ return allBounds;
+ }
+
+ /* Fill quad from quad list */
+ template<typename PrimRefT>
+ __forceinline void fill(const PrimRefT* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ vuint<M> geomID = -1, primID = -1;
+ const PrimRefT* prim = &prims[begin];
+ vuint<M> v0 = zero, v1 = zero, v2 = zero, v3 = zero;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (begin<end) {
+ geomID[i] = prim->geomID();
+ primID[i] = prim->primID();
+#if !defined(EMBREE_COMPACT_POLYS)
+ const QuadMesh* mesh = scene->get<QuadMesh>(prim->geomID());
+ const QuadMesh::Quad& q = mesh->quad(prim->primID());
+ unsigned int_stride = mesh->vertices0.getStride()/4;
+ v0[i] = q.v[0] * int_stride;
+ v1[i] = q.v[1] * int_stride;
+ v2[i] = q.v[2] * int_stride;
+ v3[i] = q.v[3] * int_stride;
+#endif
+ begin++;
+ } else {
+ assert(i);
+ if (likely(i > 0)) {
+ geomID[i] = geomID[0]; // always valid geomIDs
+ primID[i] = -1; // indicates invalid data
+ v0[i] = v0[0];
+ v1[i] = v0[0];
+ v2[i] = v0[0];
+ v3[i] = v0[0];
+ }
+ }
+ if (begin<end) prim = &prims[begin];
+ }
+ new (this) QuadMi(v0,v1,v2,v3,geomID,primID); // FIXME: use non temporal store
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, itime);
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, time_range);
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const QuadMi& quad) {
+ return cout << "QuadMi<" << M << ">( "
+#if !defined(EMBREE_COMPACT_POLYS)
+ << "v0 = " << quad.v0_ << ", v1 = " << quad.v1_ << ", v2 = " << quad.v2_ << ", v3 = " << quad.v3_ << ", "
+#endif
+ << "geomID = " << quad.geomIDs << ", primID = " << quad.primIDs << " )";
+ }
+
+ protected:
+#if !defined(EMBREE_COMPACT_POLYS)
+ vuint<M> v0_; // 4 byte offset of 1st vertex
+ vuint<M> v1_; // 4 byte offset of 2nd vertex
+ vuint<M> v2_; // 4 byte offset of 3rd vertex
+ vuint<M> v3_; // 4 byte offset of 4th vertex
+#endif
+ vuint<M> geomIDs; // geometry ID of mesh
+ vuint<M> primIDs; // primitive ID of primitive inside mesh
+ };
+
+ namespace isa
+ {
+
+ template<int M>
+ struct QuadMi : public embree::QuadMi<M>
+ {
+#if !defined(EMBREE_COMPACT_POLYS)
+ using embree::QuadMi<M>::v0_;
+ using embree::QuadMi<M>::v1_;
+ using embree::QuadMi<M>::v2_;
+ using embree::QuadMi<M>::v3_;
+#endif
+ using embree::QuadMi<M>::geomIDs;
+ using embree::QuadMi<M>::primIDs;
+ using embree::QuadMi<M>::geomID;
+ using embree::QuadMi<M>::primID;
+ using embree::QuadMi<M>::valid;
+
+ template<int vid>
+ __forceinline Vec3f getVertex(const size_t index, const Scene *const scene) const
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(index));
+ const QuadMesh::Quad& quad = mesh->quad(primID(index));
+ return (Vec3f) mesh->vertices[0][quad.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const float* vertices = scene->vertices[geomID(index)];
+ return (Vec3f&) vertices[v[index]];
+#endif
+ }
+
+ template<int vid, typename T>
+ __forceinline Vec3<T> getVertex(const size_t index, const Scene *const scene, const size_t itime, const T& ftime) const
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(index));
+ const QuadMesh::Quad& quad = mesh->quad(primID(index));
+ const Vec3fa v0 = mesh->vertices[itime+0][quad.v[vid]];
+ const Vec3fa v1 = mesh->vertices[itime+1][quad.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(index));
+ const float* vertices0 = (const float*) mesh->vertexPtr(0,itime+0);
+ const float* vertices1 = (const float*) mesh->vertexPtr(0,itime+1);
+ const Vec3fa v0 = Vec3fa::loadu(vertices0+v[index]);
+ const Vec3fa v1 = Vec3fa::loadu(vertices1+v[index]);
+#endif
+ const Vec3<T> p0(v0.x,v0.y,v0.z);
+ const Vec3<T> p1(v1.x,v1.y,v1.z);
+ return lerp(p0,p1,ftime);
+ }
+
+ template<int vid, int K, typename T>
+ __forceinline Vec3<T> getVertex(const vbool<K>& valid, const size_t index, const Scene *const scene, const vint<K>& itime, const T& ftime) const
+ {
+ Vec3<T> p0, p1;
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(index));
+
+ for (size_t mask=movemask(valid), i=bsf(mask); mask; mask=btc(mask,i), i=bsf(mask))
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const QuadMesh::Quad& quad = mesh->quad(primID(index));
+ const Vec3fa v0 = mesh->vertices[itime[i]+0][quad.v[vid]];
+ const Vec3fa v1 = mesh->vertices[itime[i]+1][quad.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const float* vertices0 = (const float*) mesh->vertexPtr(0,itime[i]+0);
+ const float* vertices1 = (const float*) mesh->vertexPtr(0,itime[i]+1);
+ const Vec3fa v0 = Vec3fa::loadu(vertices0+v[index]);
+ const Vec3fa v1 = Vec3fa::loadu(vertices1+v[index]);
+#endif
+ p0.x[i] = v0.x; p0.y[i] = v0.y; p0.z[i] = v0.z;
+ p1.x[i] = v1.x; p1.y[i] = v1.y; p1.z[i] = v1.z;
+ }
+ return (T(one)-ftime)*p0 + ftime*p1;
+ }
+
+ struct Quad {
+ vfloat4 v0,v1,v2,v3;
+ };
+
+#if defined(EMBREE_COMPACT_POLYS)
+
+ __forceinline Quad loadQuad(const int i, const Scene* const scene) const
+ {
+ const unsigned int geomID = geomIDs[i];
+ const unsigned int primID = primIDs[i];
+ if (unlikely(primID == -1)) return { zero, zero, zero, zero };
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID);
+ const QuadMesh::Quad& quad = mesh->quad(primID);
+ const vfloat4 v0 = (vfloat4) mesh->vertices0[quad.v[0]];
+ const vfloat4 v1 = (vfloat4) mesh->vertices0[quad.v[1]];
+ const vfloat4 v2 = (vfloat4) mesh->vertices0[quad.v[2]];
+ const vfloat4 v3 = (vfloat4) mesh->vertices0[quad.v[3]];
+ return { v0, v1, v2, v3 };
+ }
+
+ __forceinline Quad loadQuad(const int i, const int itime, const Scene* const scene) const
+ {
+ const unsigned int geomID = geomIDs[i];
+ const unsigned int primID = primIDs[i];
+ if (unlikely(primID == -1)) return { zero, zero, zero, zero };
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID);
+ const QuadMesh::Quad& quad = mesh->quad(primID);
+ const vfloat4 v0 = (vfloat4) mesh->vertices[itime][quad.v[0]];
+ const vfloat4 v1 = (vfloat4) mesh->vertices[itime][quad.v[1]];
+ const vfloat4 v2 = (vfloat4) mesh->vertices[itime][quad.v[2]];
+ const vfloat4 v3 = (vfloat4) mesh->vertices[itime][quad.v[3]];
+ return { v0, v1, v2, v3 };
+ }
+
+#else
+
+ __forceinline Quad loadQuad(const int i, const Scene* const scene) const
+ {
+ const float* vertices = scene->vertices[geomID(i)];
+ const vfloat4 v0 = vfloat4::loadu(vertices + v0_[i]);
+ const vfloat4 v1 = vfloat4::loadu(vertices + v1_[i]);
+ const vfloat4 v2 = vfloat4::loadu(vertices + v2_[i]);
+ const vfloat4 v3 = vfloat4::loadu(vertices + v3_[i]);
+ return { v0, v1, v2, v3 };
+ }
+
+ __forceinline Quad loadQuad(const int i, const int itime, const Scene* const scene) const
+ {
+ const unsigned int geomID = geomIDs[i];
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID);
+ const float* vertices = (const float*) mesh->vertexPtr(0,itime);
+ const vfloat4 v0 = vfloat4::loadu(vertices + v0_[i]);
+ const vfloat4 v1 = vfloat4::loadu(vertices + v1_[i]);
+ const vfloat4 v2 = vfloat4::loadu(vertices + v2_[i]);
+ const vfloat4 v3 = vfloat4::loadu(vertices + v3_[i]);
+ return { v0, v1, v2, v3 };
+ }
+
+#endif
+
+ /* Gather the quads */
+ __forceinline void gather(Vec3vf<M>& p0,
+ Vec3vf<M>& p1,
+ Vec3vf<M>& p2,
+ Vec3vf<M>& p3,
+ const Scene *const scene) const;
+
+#if defined(__AVX512F__)
+ __forceinline void gather(Vec3vf16& p0,
+ Vec3vf16& p1,
+ Vec3vf16& p2,
+ Vec3vf16& p3,
+ const Scene *const scene) const;
+#endif
+
+ template<int K>
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER < 2000) // workaround for compiler bug in ICC 2019
+ __noinline
+#else
+ __forceinline
+#endif
+ void gather(const vbool<K>& valid,
+ Vec3vf<K>& p0,
+ Vec3vf<K>& p1,
+ Vec3vf<K>& p2,
+ Vec3vf<K>& p3,
+ const size_t index,
+ const Scene* const scene,
+ const vfloat<K>& time) const
+ {
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(index));
+
+ vfloat<K> ftime;
+ const vint<K> itime = mesh->timeSegment<K>(time, ftime);
+
+ const size_t first = bsf(movemask(valid));
+ if (likely(all(valid,itime[first] == itime)))
+ {
+ p0 = getVertex<0>(index, scene, itime[first], ftime);
+ p1 = getVertex<1>(index, scene, itime[first], ftime);
+ p2 = getVertex<2>(index, scene, itime[first], ftime);
+ p3 = getVertex<3>(index, scene, itime[first], ftime);
+ }
+ else
+ {
+ p0 = getVertex<0,K>(valid, index, scene, itime, ftime);
+ p1 = getVertex<1,K>(valid, index, scene, itime, ftime);
+ p2 = getVertex<2,K>(valid, index, scene, itime, ftime);
+ p3 = getVertex<3,K>(valid, index, scene, itime, ftime);
+ }
+ }
+
+ __forceinline void gather(Vec3vf<M>& p0,
+ Vec3vf<M>& p1,
+ Vec3vf<M>& p2,
+ Vec3vf<M>& p3,
+ const QuadMesh* mesh,
+ const Scene *const scene,
+ const int itime) const;
+
+ __forceinline void gather(Vec3vf<M>& p0,
+ Vec3vf<M>& p1,
+ Vec3vf<M>& p2,
+ Vec3vf<M>& p3,
+ const Scene *const scene,
+ const float time) const;
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(QuadMesh* mesh)
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M; i++)
+ {
+ if (!valid(i)) break;
+ const unsigned primId = primID(i);
+ const QuadMesh::Quad& q = mesh->quad(primId);
+ const Vec3fa p0 = mesh->vertex(q.v[0]);
+ const Vec3fa p1 = mesh->vertex(q.v[1]);
+ const Vec3fa p2 = mesh->vertex(q.v[2]);
+ const Vec3fa p3 = mesh->vertex(q.v[3]);
+ bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2),BBox3fa(p3)));
+ }
+ return bounds;
+ }
+
+ private:
+#if !defined(EMBREE_COMPACT_POLYS)
+ template<int N> const vuint<M>& getVertexOffset() const;
+#endif
+ };
+
+#if !defined(EMBREE_COMPACT_POLYS)
+ template<> template<> __forceinline const vuint<4>& QuadMi<4>::getVertexOffset<0>() const { return v0_; }
+ template<> template<> __forceinline const vuint<4>& QuadMi<4>::getVertexOffset<1>() const { return v1_; }
+ template<> template<> __forceinline const vuint<4>& QuadMi<4>::getVertexOffset<2>() const { return v2_; }
+ template<> template<> __forceinline const vuint<4>& QuadMi<4>::getVertexOffset<3>() const { return v3_; }
+#endif
+
+ template<>
+ __forceinline void QuadMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const Scene *const scene) const
+ {
+ prefetchL1(((char*)this)+0*64);
+ prefetchL1(((char*)this)+1*64);
+ const Quad tri0 = loadQuad(0,scene);
+ const Quad tri1 = loadQuad(1,scene);
+ const Quad tri2 = loadQuad(2,scene);
+ const Quad tri3 = loadQuad(3,scene);
+ transpose(tri0.v0,tri1.v0,tri2.v0,tri3.v0,p0.x,p0.y,p0.z);
+ transpose(tri0.v1,tri1.v1,tri2.v1,tri3.v1,p1.x,p1.y,p1.z);
+ transpose(tri0.v2,tri1.v2,tri2.v2,tri3.v2,p2.x,p2.y,p2.z);
+ transpose(tri0.v3,tri1.v3,tri2.v3,tri3.v3,p3.x,p3.y,p3.z);
+ }
+
+ template<>
+ __forceinline void QuadMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const QuadMesh* mesh,
+ const Scene *const scene,
+ const int itime) const
+ {
+ // FIXME: for trianglei there all geometries are identical, is this the case here too?
+
+ const Quad tri0 = loadQuad(0,itime,scene);
+ const Quad tri1 = loadQuad(1,itime,scene);
+ const Quad tri2 = loadQuad(2,itime,scene);
+ const Quad tri3 = loadQuad(3,itime,scene);
+ transpose(tri0.v0,tri1.v0,tri2.v0,tri3.v0,p0.x,p0.y,p0.z);
+ transpose(tri0.v1,tri1.v1,tri2.v1,tri3.v1,p1.x,p1.y,p1.z);
+ transpose(tri0.v2,tri1.v2,tri2.v2,tri3.v2,p2.x,p2.y,p2.z);
+ transpose(tri0.v3,tri1.v3,tri2.v3,tri3.v3,p3.x,p3.y,p3.z);
+ }
+
+ template<>
+ __forceinline void QuadMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const Scene *const scene,
+ const float time) const
+ {
+ const QuadMesh* mesh = scene->get<QuadMesh>(geomID(0)); // in mblur mode all geometries are identical
+
+ float ftime;
+ const int itime = mesh->timeSegment(time, ftime);
+
+ Vec3vf4 a0,a1,a2,a3; gather(a0,a1,a2,a3,mesh,scene,itime);
+ Vec3vf4 b0,b1,b2,b3; gather(b0,b1,b2,b3,mesh,scene,itime+1);
+ p0 = lerp(a0,b0,vfloat4(ftime));
+ p1 = lerp(a1,b1,vfloat4(ftime));
+ p2 = lerp(a2,b2,vfloat4(ftime));
+ p3 = lerp(a3,b3,vfloat4(ftime));
+ }
+ }
+
+ template<int M>
+ typename QuadMi<M>::Type QuadMi<M>::type;
+
+ typedef QuadMi<4> Quad4i;
+}
diff --git a/thirdparty/embree/kernels/geometry/quadi_intersector.h b/thirdparty/embree/kernels/geometry/quadi_intersector.h
new file mode 100644
index 0000000000..20a98c3406
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/quadi_intersector.h
@@ -0,0 +1,350 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "quadi.h"
+#include "quad_intersector_moeller.h"
+#include "quad_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMiIntersector1Moeller
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersector1MoellerTrumbore<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMiIntersectorKMoeller
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersectorKMoellerTrumbore<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ Scene* scene = context->scene;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> p0 = quad.template getVertex<0>(i,scene);
+ const Vec3vf<K> p1 = quad.template getVertex<1>(i,scene);
+ const Vec3vf<K> p2 = quad.template getVertex<2>(i,scene);
+ const Vec3vf<K> p3 = quad.template getVertex<3>(i,scene);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ Scene* scene = context->scene;
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> p0 = quad.template getVertex<0>(i,scene);
+ const Vec3vf<K> p1 = quad.template getVertex<1>(i,scene);
+ const Vec3vf<K> p2 = quad.template getVertex<2>(i,scene);
+ const Vec3vf<K> p3 = quad.template getVertex<3>(i,scene);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+ };
+
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMiIntersector1Pluecker
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersector1Pluecker<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMiIntersectorKPluecker
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersectorKPluecker<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ Scene* scene = context->scene;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> p0 = quad.template getVertex<0>(i,scene);
+ const Vec3vf<K> p1 = quad.template getVertex<1>(i,scene);
+ const Vec3vf<K> p2 = quad.template getVertex<2>(i,scene);
+ const Vec3vf<K> p3 = quad.template getVertex<3>(i,scene);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ Scene* scene = context->scene;
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> p0 = quad.template getVertex<0>(i,scene);
+ const Vec3vf<K> p1 = quad.template getVertex<1>(i,scene);
+ const Vec3vf<K> p2 = quad.template getVertex<2>(i,scene);
+ const Vec3vf<K> p3 = quad.template getVertex<3>(i,scene);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+ };
+
+ /*! Intersects M motion blur quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMiMBIntersector1Moeller
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersector1MoellerTrumbore<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time());
+ pre.intersect(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time());
+ return pre.occluded(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M motion blur quads with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMiMBIntersectorKMoeller
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersectorKMoellerTrumbore<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M quads. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ Vec3vf<K> v0,v1,v2,v3; quad.template gather<K>(valid_i,v0,v1,v2,v3,i,context->scene,ray.time());
+ pre.intersectK(valid_i,ray,v0,v1,v2,v3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M quads. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ Vec3vf<K> v0,v1,v2,v3; quad.template gather<K>(valid_i,v0,v1,v2,v3,i,context->scene,ray.time());
+ if (pre.intersectK(valid0,ray,v0,v1,v2,v3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M quads and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M quads. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+ };
+
+ /*! Intersects M motion blur quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMiMBIntersector1Pluecker
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersector1Pluecker<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time());
+ pre.intersect(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time());
+ return pre.occluded(ray,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M motion blur quads with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMiMBIntersectorKPluecker
+ {
+ typedef QuadMi<M> Primitive;
+ typedef QuadMIntersectorKPluecker<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M quads. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ Vec3vf<K> v0,v1,v2,v3; quad.template gather<K>(valid_i,v0,v1,v2,v3,i,context->scene,ray.time());
+ pre.intersectK(valid_i,ray,v0,v1,v2,v3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M quads. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<QuadMi<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ Vec3vf<K> v0,v1,v2,v3; quad.template gather<K>(valid_i,v0,v1,v2,v3,i,context->scene,ray.time());
+ if (pre.intersectK(valid0,ray,v0,v1,v2,v3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M quads and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M quads. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,quad.geomID(),quad.primID());
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/quadv.h b/thirdparty/embree/kernels/geometry/quadv.h
new file mode 100644
index 0000000000..2137356ff2
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/quadv.h
@@ -0,0 +1,165 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ /* Stores the vertices of M quads in struct of array layout */
+ template <int M>
+ struct QuadMv
+ {
+ public:
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored quads */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline QuadMv() {}
+
+ /* Construction from vertices and IDs */
+ __forceinline QuadMv(const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const vuint<M>& geomIDs, const vuint<M>& primIDs)
+ : v0(v0), v1(v1), v2(v2), v3(v3), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ /* Returns a mask that tells which quads are valid */
+ __forceinline vbool<M> valid() const { return geomIDs != vuint<M>(-1); }
+
+ /* Returns true if the specified quad is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return geomIDs[i] != -1; }
+
+ /* Returns the number of stored quads */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M>& geomID() { return geomIDs; }
+ __forceinline const vuint<M>& geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M> primID() { return primIDs; }
+ __forceinline const vuint<M> primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the quads */
+ __forceinline BBox3fa bounds() const
+ {
+ Vec3vf<M> lower = min(v0,v1,v2,v3);
+ Vec3vf<M> upper = max(v0,v1,v2,v3);
+ vbool<M> mask = valid();
+ lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
+ lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
+ lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
+ upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
+ upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
+ upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
+ return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
+ Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
+ }
+
+ /* Non temporal store */
+ __forceinline static void store_nt(QuadMv* dst, const QuadMv& src)
+ {
+ vfloat<M>::store_nt(&dst->v0.x,src.v0.x);
+ vfloat<M>::store_nt(&dst->v0.y,src.v0.y);
+ vfloat<M>::store_nt(&dst->v0.z,src.v0.z);
+ vfloat<M>::store_nt(&dst->v1.x,src.v1.x);
+ vfloat<M>::store_nt(&dst->v1.y,src.v1.y);
+ vfloat<M>::store_nt(&dst->v1.z,src.v1.z);
+ vfloat<M>::store_nt(&dst->v2.x,src.v2.x);
+ vfloat<M>::store_nt(&dst->v2.y,src.v2.y);
+ vfloat<M>::store_nt(&dst->v2.z,src.v2.z);
+ vfloat<M>::store_nt(&dst->v3.x,src.v3.x);
+ vfloat<M>::store_nt(&dst->v3.y,src.v3.y);
+ vfloat<M>::store_nt(&dst->v3.z,src.v3.z);
+ vuint<M>::store_nt(&dst->geomIDs,src.geomIDs);
+ vuint<M>::store_nt(&dst->primIDs,src.primIDs);
+ }
+
+ /* Fill quad from quad list */
+ __forceinline void fill(const PrimRef* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero, v3 = zero;
+
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRef& prim = prims[begin];
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const QuadMesh* __restrict__ const mesh = scene->get<QuadMesh>(geomID);
+ const QuadMesh::Quad& quad = mesh->quad(primID);
+ const Vec3fa& p0 = mesh->vertex(quad.v[0]);
+ const Vec3fa& p1 = mesh->vertex(quad.v[1]);
+ const Vec3fa& p2 = mesh->vertex(quad.v[2]);
+ const Vec3fa& p3 = mesh->vertex(quad.v[3]);
+ vgeomID [i] = geomID;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ v3.x[i] = p3.x; v3.y[i] = p3.y; v3.z[i] = p3.z;
+ }
+ QuadMv::store_nt(this,QuadMv(v0,v1,v2,v3,vgeomID,vprimID));
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(QuadMesh* mesh)
+ {
+ BBox3fa bounds = empty;
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (primID(i) == -1) break;
+ const unsigned geomId = geomID(i);
+ const unsigned primId = primID(i);
+ const QuadMesh::Quad& quad = mesh->quad(primId);
+ const Vec3fa p0 = mesh->vertex(quad.v[0]);
+ const Vec3fa p1 = mesh->vertex(quad.v[1]);
+ const Vec3fa p2 = mesh->vertex(quad.v[2]);
+ const Vec3fa p3 = mesh->vertex(quad.v[3]);
+ bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2),BBox3fa(p3)));
+ vgeomID [i] = geomId;
+ vprimID [i] = primId;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ v3.x[i] = p3.x; v3.y[i] = p3.y; v3.z[i] = p3.z;
+ }
+ new (this) QuadMv(v0,v1,v2,v3,vgeomID,vprimID);
+ return bounds;
+ }
+
+ public:
+ Vec3vf<M> v0; // 1st vertex of the quads
+ Vec3vf<M> v1; // 2nd vertex of the quads
+ Vec3vf<M> v2; // 3rd vertex of the quads
+ Vec3vf<M> v3; // 4rd vertex of the quads
+ private:
+ vuint<M> geomIDs; // geometry ID
+ vuint<M> primIDs; // primitive ID
+ };
+
+ template<int M>
+ typename QuadMv<M>::Type QuadMv<M>::type;
+
+ typedef QuadMv<4> Quad4v;
+}
diff --git a/thirdparty/embree/kernels/geometry/quadv_intersector.h b/thirdparty/embree/kernels/geometry/quadv_intersector.h
new file mode 100644
index 0000000000..9b28e05614
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/quadv_intersector.h
@@ -0,0 +1,181 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "quadv.h"
+#include "quad_intersector_moeller.h"
+#include "quad_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMvIntersector1Moeller
+ {
+ typedef QuadMv<M> Primitive;
+ typedef QuadMIntersector1MoellerTrumbore<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.occluded(ray,context, quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMvIntersectorKMoeller
+ {
+ typedef QuadMv<M> Primitive;
+ typedef QuadMIntersectorKMoellerTrumbore<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ for (size_t i=0; i<QuadMv<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(quad.v0,i);
+ const Vec3vf<K> p1 = broadcast<vfloat<K>>(quad.v1,i);
+ const Vec3vf<K> p2 = broadcast<vfloat<K>>(quad.v2,i);
+ const Vec3vf<K> p3 = broadcast<vfloat<K>>(quad.v3,i);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<QuadMv<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(quad.v0,i);
+ const Vec3vf<K> p1 = broadcast<vfloat<K>>(quad.v1,i);
+ const Vec3vf<K> p2 = broadcast<vfloat<K>>(quad.v2,i);
+ const Vec3vf<K> p3 = broadcast<vfloat<K>>(quad.v3,i);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.occluded1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+ };
+
+ /*! Intersects M quads with 1 ray */
+ template<int M, bool filter>
+ struct QuadMvIntersector1Pluecker
+ {
+ typedef QuadMv<M> Primitive;
+ typedef QuadMIntersector1Pluecker<M,filter> Precalculations;
+
+ /*! Intersect a ray with the M quads and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of M quads. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.occluded(ray,context, quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& quad)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, quad);
+ }
+ };
+
+ /*! Intersects M triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct QuadMvIntersectorKPluecker
+ {
+ typedef QuadMv<M> Primitive;
+ typedef QuadMIntersectorKPluecker<M,K,filter> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ for (size_t i=0; i<QuadMv<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(quad.v0,i);
+ const Vec3vf<K> p1 = broadcast<vfloat<K>>(quad.v1,i);
+ const Vec3vf<K> p2 = broadcast<vfloat<K>>(quad.v2,i);
+ const Vec3vf<K> p3 = broadcast<vfloat<K>>(quad.v3,i);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,IntersectKEpilogM<M,K,filter>(ray,context,quad.geomID(),quad.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<QuadMv<M>::max_size(); i++)
+ {
+ if (!quad.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(quad.v0,i);
+ const Vec3vf<K> p1 = broadcast<vfloat<K>>(quad.v1,i);
+ const Vec3vf<K> p2 = broadcast<vfloat<K>>(quad.v2,i);
+ const Vec3vf<K> p3 = broadcast<vfloat<K>>(quad.v3,i);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,OccludedKEpilogM<M,K,filter>(valid0,ray,context,quad.geomID(),quad.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.occluded1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID());
+ }
+ };
+ }
+}
+
diff --git a/thirdparty/embree/kernels/geometry/roundline_intersector.h b/thirdparty/embree/kernels/geometry/roundline_intersector.h
new file mode 100644
index 0000000000..0e9393442b
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/roundline_intersector.h
@@ -0,0 +1,715 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "curve_intersector_precalculations.h"
+
+
+/*
+
+ This file implements the intersection of a ray with a round linear
+ curve segment. We define the geometry of such a round linear curve
+ segment from point p0 with radius r0 to point p1 with radius r1
+ using the cone that touches spheres p0/r0 and p1/r1 tangentially
+ plus the sphere p1/r1. We denote the tangentially touching cone from
+ p0/r0 to p1/r1 with cone(p0,r0,p1,r1) and the cone plus the ending
+ sphere with cone_sphere(p0,r0,p1,r1).
+
+ For multiple connected round linear curve segments this construction
+ yield a proper shape when viewed from the outside. Using the
+ following CSG we can also handle the interiour in most common cases:
+
+ round_linear_curve(pl,rl,p0,r0,p1,r1,pr,rr) =
+ cone_sphere(p0,r0,p1,r1) - cone(pl,rl,p0,r0) - cone(p1,r1,pr,rr)
+
+ Thus by subtracting the neighboring cone geometries, we cut away
+ parts of the center cone_sphere surface which lie inside the
+ combined curve. This approach works as long as geometry of the
+ current cone_sphere penetrates into direct neighbor segments only,
+ and not into segments further away.
+
+ To construct a cone that touches two spheres at p0 and p1 with r0
+ and r1, one has to increase the cone radius at r0 and r1 to obtain
+ larger radii w0 and w1, such that the infinite cone properly touches
+ the spheres. From the paper "Ray Tracing Generalized Tube
+ Primitives: Method and Applications"
+ (https://www.researchgate.net/publication/334378683_Ray_Tracing_Generalized_Tube_Primitives_Method_and_Applications)
+ one can derive the following equations for these increased
+ radii:
+
+ sr = 1.0f / sqrt(1-sqr(dr)/sqr(p1-p0))
+ w0 = sr*r0
+ w1 = sr*r1
+
+ Further, we want the cone to start where it touches the sphere at p0
+ and to end where it touches sphere at p1. Therefore, we need to
+ construct clipping locations y0 and y1 for the start and end of the
+ cone. These start and end clipping location of the cone can get
+ calculated as:
+
+ Y0 = - r0 * (r1-r0) / length(p1-p0)
+ Y1 = length(p1-p0) - r1 * (r1-r0) / length(p1-p0)
+
+ Where the cone starts a distance Y0 and ends a distance Y1 away of
+ point p0 along the cone center. The distance between Y1-Y0 can get
+ calculated as:
+
+ dY = length(p1-p0) - (r1-r0)^2 / length(p1-p0)
+
+ In the code below, Y will always be scaled by length(p1-p0) to
+ obtain y and you will find the terms r0*(r1-r0) and
+ (p1-p0)^2-(r1-r0)^2.
+
+ */
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct RoundLineIntersectorHitM
+ {
+ __forceinline RoundLineIntersectorHitM() {}
+
+ __forceinline RoundLineIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)
+ : vu(u), vv(v), vt(t), vNg(Ng) {}
+
+ __forceinline void finalize() {}
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ __forceinline Vec2vf<M> uv() const { return Vec2vf<M>(vu,vv); }
+ __forceinline vfloat<M> t () const { return vt; }
+ __forceinline Vec3vf<M> Ng() const { return vNg; }
+
+ public:
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ namespace __roundline_internal
+ {
+ template<int M>
+ struct ConeGeometry
+ {
+ ConeGeometry (const Vec4vf<M>& a, const Vec4vf<M>& b)
+ : p0(a.xyz()), p1(b.xyz()), dP(p1-p0), dPdP(dot(dP,dP)), r0(a.w), sqr_r0(sqr(r0)), r1(b.w), dr(r1-r0), drdr(dr*dr), r0dr (r0*dr), g(dPdP - drdr) {}
+
+ /*
+
+ This function tests if a point is accepted by first cone
+ clipping plane.
+
+ First, we need to project the point onto the line p0->p1:
+
+ Y = (p-p0)*(p1-p0)/length(p1-p0)
+
+ This value y is the distance to the projection point from
+ p0. The clip distances are calculated as:
+
+ Y0 = - r0 * (r1-r0) / length(p1-p0)
+ Y1 = length(p1-p0) - r1 * (r1-r0) / length(p1-p0)
+
+ Thus to test if the point p is accepted by the first
+ clipping plane we need to test Y > Y0 and to test if it
+ is accepted by the second clipping plane we need to test
+ Y < Y1.
+
+ By multiplying the calculations with length(p1-p0) these
+ calculation can get simplied to:
+
+ y = (p-p0)*(p1-p0)
+ y0 = - r0 * (r1-r0)
+ y1 = (p1-p0)^2 - r1 * (r1-r0)
+
+ and the test y > y0 and y < y1.
+
+ */
+
+ __forceinline vbool<M> isClippedByPlane (const vbool<M>& valid_i, const Vec3vf<M>& p) const
+ {
+ const Vec3vf<M> p0p = p - p0;
+ const vfloat<M> y = dot(p0p,dP);
+ const vfloat<M> cap0 = -r0dr;
+ const vbool<M> inside_cone = y > cap0;
+ return valid_i & (p0.x != vfloat<M>(inf)) & (p1.x != vfloat<M>(inf)) & inside_cone;
+ }
+
+ /*
+
+ This function tests whether a point lies inside the capped cone
+ tangential to its ending spheres.
+
+ Therefore one has to check if the point is inside the
+ region defined by the cone clipping planes, which is
+ performed similar as in the previous function.
+
+ To perform the inside cone test we need to project the
+ point onto the line p0->p1:
+
+ dP = p1-p0
+ Y = (p-p0)*dP/length(dP)
+
+ This value Y is the distance to the projection point from
+ p0. To obtain a parameter value u going from 0 to 1 along
+ the line p0->p1 we calculate:
+
+ U = Y/length(dP)
+
+ The radii to use at points p0 and p1 are:
+
+ w0 = sr * r0
+ w1 = sr * r1
+ dw = w1-w0
+
+ Using these radii and u one can directly test if the point
+ lies inside the cone using the formula dP*dP < wy*wy with:
+
+ wy = w0 + u*dw
+ py = p0 + u*dP - p
+
+ By multiplying the calculations with length(p1-p0) and
+ inserting the definition of w can obtain simpler equations:
+
+ y = (p-p0)*dP
+ ry = r0 + y/dP^2 * dr
+ wy = sr*ry
+ py = p0 + y/dP^2*dP - p
+ y0 = - r0 * dr
+ y1 = dP^2 - r1 * dr
+
+ Thus for the in-cone test we get:
+
+ py^2 < wy^2
+ <=> py^2 < sr^2 * ry^2
+ <=> py^2 * ( dP^2 - dr^2 ) < dP^2 * ry^2
+
+ This can further get simplified to:
+
+ (p0-p)^2 * (dP^2 - dr^2) - y^2 < dP^2 * r0^2 + 2.0f*r0*dr*y;
+
+ */
+
+ __forceinline vbool<M> isInsideCappedCone (const vbool<M>& valid_i, const Vec3vf<M>& p) const
+ {
+ const Vec3vf<M> p0p = p - p0;
+ const vfloat<M> y = dot(p0p,dP);
+ const vfloat<M> cap0 = -r0dr+vfloat<M>(ulp);
+ const vfloat<M> cap1 = -r1*dr + dPdP;
+
+ vbool<M> inside_cone = valid_i & (p0.x != vfloat<M>(inf)) & (p1.x != vfloat<M>(inf));
+ inside_cone &= y > cap0; // start clipping plane
+ inside_cone &= y < cap1; // end clipping plane
+ inside_cone &= sqr(p0p)*g - sqr(y) < dPdP * sqr_r0 + 2.0f*r0dr*y; // in cone test
+ return inside_cone;
+ }
+
+ protected:
+ Vec3vf<M> p0;
+ Vec3vf<M> p1;
+ Vec3vf<M> dP;
+ vfloat<M> dPdP;
+ vfloat<M> r0;
+ vfloat<M> sqr_r0;
+ vfloat<M> r1;
+ vfloat<M> dr;
+ vfloat<M> drdr;
+ vfloat<M> r0dr;
+ vfloat<M> g;
+ };
+
+ template<int M>
+ struct ConeGeometryIntersector : public ConeGeometry<M>
+ {
+ using ConeGeometry<M>::p0;
+ using ConeGeometry<M>::p1;
+ using ConeGeometry<M>::dP;
+ using ConeGeometry<M>::dPdP;
+ using ConeGeometry<M>::r0;
+ using ConeGeometry<M>::sqr_r0;
+ using ConeGeometry<M>::r1;
+ using ConeGeometry<M>::dr;
+ using ConeGeometry<M>::r0dr;
+ using ConeGeometry<M>::g;
+
+ ConeGeometryIntersector (const Vec3vf<M>& ray_org, const Vec3vf<M>& ray_dir, const vfloat<M>& dOdO, const vfloat<M>& rcp_dOdO, const Vec4vf<M>& a, const Vec4vf<M>& b)
+ : ConeGeometry<M>(a,b), org(ray_org), O(ray_org-p0), dO(ray_dir), dOdO(dOdO), rcp_dOdO(rcp_dOdO), OdP(dot(dP,O)), dOdP(dot(dP,dO)), yp(OdP + r0dr) {}
+
+ /*
+
+ This function intersects a ray with a cone that touches a
+ start sphere p0/r0 and end sphere p1/r1.
+
+ To find this ray/cone intersections one could just
+ calculate radii w0 and w1 as described above and use a
+ standard ray/cone intersection routine with these
+ radii. However, it turns out that calculations can get
+ simplified when deriving a specialized ray/cone
+ intersection for this special case. We perform
+ calculations relative to the cone origin p0 and define:
+
+ O = ray_org - p0
+ dO = ray_dir
+ dP = p1-p0
+ dr = r1-r0
+ dw = w1-w0
+
+ For some t we can compute the potential hit point h = O + t*dO and
+ project it onto the cone vector dP to obtain u = (h*dP)/(dP*dP). In
+ case of an intersection, the squared distance from the hit point
+ projected onto the cone center line to the hit point should be equal
+ to the squared cone radius at u:
+
+ (u*dP - h)^2 = (w0 + u*dw)^2
+
+ Inserting the definition of h, u, w0, and dw into this formula, then
+ factoring out all terms, and sorting by t^2, t^1, and t^0 terms
+ yields a quadratic equation to solve.
+
+ Inserting u:
+ ( (h*dP)*dP/dP^2 - h )^2 = ( w0 + (h*dP)*dw/dP^2 )^2
+
+ Multiplying by dP^4:
+ ( (h*dP)*dP - h*dP^2 )^2 = ( w0*dP^2 + (h*dP)*dw )^2
+
+ Inserting w0 and dw:
+ ( (h*dP)*dP - h*dP^2 )^2 = ( r0*dP^2 + (h*dP)*dr )^2 / (1-dr^2/dP^2)
+ ( (h*dP)*dP - h*dP^2 )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + (h*dP)*dr )^2
+
+ Now one can insert the definition of h, factor out, and presort by t:
+ ( ((O + t*dO)*dP)*dP - (O + t*dO)*dP^2 )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + ((O + t*dO)*dP)*dr )^2
+ ( (O*dP)*dP-O*dP^2 + t*( (dO*dP)*dP - dO*dP^2 ) )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + (O*dP)*dr + t*(dO*dP)*dr )^2
+
+ Factoring out further and sorting by t^2, t^1 and t^0 yields:
+
+ 0 = t^2 * [ ((dO*dP)*dP - dO-dP^2)^2 * (dP^2 - dr^2) - dP^2*(dO*dP)^2*dr^2 ]
+ + 2*t^1 * [ ((O*dP)*dP - O*dP^2) * ((dO*dP)*dP - dO*dP^2) * (dP^2 - dr^2) - dP^2*(r0*dP^2 + (O*dP)*dr)*(dO*dP)*dr ]
+ + t^0 * [ ( (O*dP)*dP - O*dP^2)^2 * (dP^2-dr^2) - dP^2*(r0*dP^2 + (O*dP)*dr)^2 ]
+
+ This can be simplified to:
+
+ 0 = t^2 * [ (dP^2 - dr^2)*dO^2 - (dO*dP)^2 ]
+ + 2*t^1 * [ (dP^2 - dr^2)*(O*dO) - (dO*dP)*(O*dP + r0*dr) ]
+ + t^0 * [ (dP^2 - dr^2)*O^2 - (O*dP)^2 - r0^2*dP^2 - 2.0f*r0*dr*(O*dP) ]
+
+ Solving this quadratic equation yields the values for t at which the
+ ray intersects the cone.
+
+ */
+
+ __forceinline bool intersectCone(vbool<M>& valid, vfloat<M>& lower, vfloat<M>& upper)
+ {
+ /* return no hit by default */
+ lower = pos_inf;
+ upper = neg_inf;
+
+ /* compute quadratic equation A*t^2 + B*t + C = 0 */
+ const vfloat<M> OO = dot(O,O);
+ const vfloat<M> OdO = dot(dO,O);
+ const vfloat<M> A = g * dOdO - sqr(dOdP);
+ const vfloat<M> B = 2.0f * (g*OdO - dOdP*yp);
+ const vfloat<M> C = g*OO - sqr(OdP) - sqr_r0*dPdP - 2.0f*r0dr*OdP;
+
+ /* we miss the cone if determinant is smaller than zero */
+ const vfloat<M> D = B*B - 4.0f*A*C;
+ valid &= (D >= 0.0f & g > 0.0f); // if g <= 0 then the cone is inside a sphere end
+
+ /* When rays are parallel to the cone surface, then the
+ * ray may be inside or outside the cone. We just assume a
+ * miss in that case, which is fine as rays inside the
+ * cone would anyway hit the ending spheres in that
+ * case. */
+ valid &= abs(A) > min_rcp_input;
+ if (unlikely(none(valid))) {
+ return false;
+ }
+
+ /* compute distance to front and back hit */
+ const vfloat<M> Q = sqrt(D);
+ const vfloat<M> rcp_2A = rcp(2.0f*A);
+ t_cone_front = (-B-Q)*rcp_2A;
+ y_cone_front = yp + t_cone_front*dOdP;
+ lower = select( (y_cone_front > -(float)ulp) & (y_cone_front <= g) & (g > 0.0f), t_cone_front, vfloat<M>(pos_inf));
+#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
+ t_cone_back = (-B+Q)*rcp_2A;
+ y_cone_back = yp + t_cone_back *dOdP;
+ upper = select( (y_cone_back > -(float)ulp) & (y_cone_back <= g) & (g > 0.0f), t_cone_back , vfloat<M>(neg_inf));
+#endif
+ return true;
+ }
+
+ /*
+ This function intersects the ray with the end sphere at
+ p1. We already clip away hits that are inside the
+ neighboring cone segment.
+
+ */
+
+ __forceinline void intersectEndSphere(vbool<M>& valid,
+ const ConeGeometry<M>& coneR,
+ vfloat<M>& lower, vfloat<M>& upper)
+ {
+ /* calculate front and back hit with end sphere */
+ const Vec3vf<M> O1 = org - p1;
+ const vfloat<M> O1dO = dot(O1,dO);
+ const vfloat<M> h2 = sqr(O1dO) - dOdO*(sqr(O1) - sqr(r1));
+ const vfloat<M> rhs1 = select( h2 >= 0.0f, sqrt(h2), vfloat<M>(neg_inf) );
+
+ /* clip away front hit if it is inside next cone segment */
+ t_sph1_front = (-O1dO - rhs1)*rcp_dOdO;
+ const Vec3vf<M> hit_front = org + t_sph1_front*dO;
+ vbool<M> valid_sph1_front = h2 >= 0.0f & yp + t_sph1_front*dOdP > g & !coneR.isClippedByPlane (valid, hit_front);
+ lower = select(valid_sph1_front, t_sph1_front, vfloat<M>(pos_inf));
+
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ /* clip away back hit if it is inside next cone segment */
+ t_sph1_back = (-O1dO + rhs1)*rcp_dOdO;
+ const Vec3vf<M> hit_back = org + t_sph1_back*dO;
+ vbool<M> valid_sph1_back = h2 >= 0.0f & yp + t_sph1_back*dOdP > g & !coneR.isClippedByPlane (valid, hit_back);
+ upper = select(valid_sph1_back, t_sph1_back, vfloat<M>(neg_inf));
+#else
+ upper = vfloat<M>(neg_inf);
+#endif
+ }
+
+ __forceinline void intersectBeginSphere(const vbool<M>& valid,
+ vfloat<M>& lower, vfloat<M>& upper)
+ {
+ /* calculate front and back hit with end sphere */
+ const Vec3vf<M> O1 = org - p0;
+ const vfloat<M> O1dO = dot(O1,dO);
+ const vfloat<M> h2 = sqr(O1dO) - dOdO*(sqr(O1) - sqr(r0));
+ const vfloat<M> rhs1 = select( h2 >= 0.0f, sqrt(h2), vfloat<M>(neg_inf) );
+
+ /* clip away front hit if it is inside next cone segment */
+ t_sph0_front = (-O1dO - rhs1)*rcp_dOdO;
+ vbool<M> valid_sph1_front = valid & h2 >= 0.0f & yp + t_sph0_front*dOdP < 0;
+ lower = select(valid_sph1_front, t_sph0_front, vfloat<M>(pos_inf));
+
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ /* clip away back hit if it is inside next cone segment */
+ t_sph0_back = (-O1dO + rhs1)*rcp_dOdO;
+ vbool<M> valid_sph1_back = valid & h2 >= 0.0f & yp + t_sph0_back*dOdP < 0;
+ upper = select(valid_sph1_back, t_sph0_back, vfloat<M>(neg_inf));
+#else
+ upper = vfloat<M>(neg_inf);
+#endif
+ }
+
+ /*
+
+ This function calculates the geometry normal of some cone hit.
+
+ For a given hit point h (relative to p0) with a cone
+ starting at p0 with radius w0 and ending at p1 with
+ radius w1 one normally calculates the geometry normal by
+ first calculating the parmetric u hit location along the
+ cone:
+
+ u = dot(h,dP)/dP^2
+
+ Using this value one can now directly calculate the
+ geometry normal by bending the connection vector (h-u*dP)
+ from hit to projected hit with some cone dependent value
+ dw/sqrt(dP^2) * normalize(dP):
+
+ Ng = normalize(h-u*dP) - dw/length(dP) * normalize(dP)
+
+ The length of the vector (h-u*dP) can also get calculated
+ by interpolating the radii as w0+u*dw which yields:
+
+ Ng = (h-u*dP)/(w0+u*dw) - dw/dP^2 * dP
+
+ Multiplying with (w0+u*dw) yield a scaled Ng':
+
+ Ng' = (h-u*dP) - (w0+u*dw)*dw/dP^2*dP
+
+ Inserting the definition of w0 and dw and refactoring
+ yield a furhter scaled Ng'':
+
+ Ng'' = (dP^2 - dr^2) (h-q) - (r0+u*dr)*dr*dP
+
+ Now inserting the definition of u gives and multiplying
+ with the denominator yields:
+
+ Ng''' = (dP^2-dr^2)*(dP^2*h-dot(h,dP)*dP) - (dP^2*r0+dot(h,dP)*dr)*dr*dP
+
+ Factoring out, cancelling terms, dividing by dP^2, and
+ factoring again yields finally:
+
+ Ng'''' = (dP^2-dr^2)*h - dP*(dot(h,dP) + r0*dr)
+
+ */
+
+ __forceinline Vec3vf<M> Ng_cone(const vbool<M>& front_hit) const
+ {
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ const vfloat<M> y = select(front_hit, y_cone_front, y_cone_back);
+ const vfloat<M> t = select(front_hit, t_cone_front, t_cone_back);
+ const Vec3vf<M> h = O + t*dO;
+ return g*h-dP*y;
+#else
+ const Vec3vf<M> h = O + t_cone_front*dO;
+ return g*h-dP*y_cone_front;
+#endif
+ }
+
+ /* compute geometry normal of sphere hit as the difference
+ * vector from hit point to sphere center */
+
+ __forceinline Vec3vf<M> Ng_sphere1(const vbool<M>& front_hit) const
+ {
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ const vfloat<M> t_sph1 = select(front_hit, t_sph1_front, t_sph1_back);
+ return org+t_sph1*dO-p1;
+#else
+ return org+t_sph1_front*dO-p1;
+#endif
+ }
+
+ __forceinline Vec3vf<M> Ng_sphere0(const vbool<M>& front_hit) const
+ {
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ const vfloat<M> t_sph0 = select(front_hit, t_sph0_front, t_sph0_back);
+ return org+t_sph0*dO-p0;
+#else
+ return org+t_sph0_front*dO-p0;
+#endif
+ }
+
+ /*
+ This function calculates the u coordinate of a
+ hit. Therefore we use the hit distance y (which is zero
+ at the first cone clipping plane) and divide by distance
+ g between the clipping planes.
+
+ */
+
+ __forceinline vfloat<M> u_cone(const vbool<M>& front_hit) const
+ {
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ const vfloat<M> y = select(front_hit, y_cone_front, y_cone_back);
+ return clamp(y*rcp(g));
+#else
+ return clamp(y_cone_front*rcp(g));
+#endif
+ }
+
+ private:
+ Vec3vf<M> org;
+ Vec3vf<M> O;
+ Vec3vf<M> dO;
+ vfloat<M> dOdO;
+ vfloat<M> rcp_dOdO;
+ vfloat<M> OdP;
+ vfloat<M> dOdP;
+
+ /* for ray/cone intersection */
+ private:
+ vfloat<M> yp;
+ vfloat<M> y_cone_front;
+ vfloat<M> t_cone_front;
+#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
+ vfloat<M> y_cone_back;
+ vfloat<M> t_cone_back;
+#endif
+
+ /* for ray/sphere intersection */
+ private:
+ vfloat<M> t_sph1_front;
+ vfloat<M> t_sph0_front;
+#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
+ vfloat<M> t_sph1_back;
+ vfloat<M> t_sph0_back;
+#endif
+ };
+
+
+ template<int M, typename Epilog, typename ray_tfar_func>
+ static __forceinline bool intersectConeSphere(const vbool<M>& valid_i,
+ const Vec3vf<M>& ray_org_in, const Vec3vf<M>& ray_dir,
+ const vfloat<M>& ray_tnear, const ray_tfar_func& ray_tfar,
+ const Vec4vf<M>& v0, const Vec4vf<M>& v1,
+ const Vec4vf<M>& vL, const Vec4vf<M>& vR,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ /* move ray origin closer to make calculations numerically stable */
+ const vfloat<M> dOdO = sqr(ray_dir);
+ const vfloat<M> rcp_dOdO = rcp(dOdO);
+ const Vec3vf<M> center = vfloat<M>(0.5f)*(v0.xyz()+v1.xyz());
+ const vfloat<M> dt = dot(center-ray_org_in,ray_dir)*rcp_dOdO;
+ const Vec3vf<M> ray_org = ray_org_in + dt*ray_dir;
+
+ /* intersect with cone from v0 to v1 */
+ vfloat<M> t_cone_lower, t_cone_upper;
+ ConeGeometryIntersector<M> cone (ray_org, ray_dir, dOdO, rcp_dOdO, v0, v1);
+ vbool<M> validCone = valid;
+ cone.intersectCone(validCone, t_cone_lower, t_cone_upper);
+
+ valid &= (validCone | (cone.g <= 0.0f)); // if cone is entirely in sphere end - check sphere
+ if (unlikely(none(valid)))
+ return false;
+
+ /* cone hits inside the neighboring capped cones are inside the geometry and thus ignored */
+ const ConeGeometry<M> coneL (v0, vL);
+ const ConeGeometry<M> coneR (v1, vR);
+#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
+ const Vec3vf<M> hit_lower = ray_org + t_cone_lower*ray_dir;
+ const Vec3vf<M> hit_upper = ray_org + t_cone_upper*ray_dir;
+ t_cone_lower = select (!coneL.isInsideCappedCone (validCone, hit_lower) & !coneR.isInsideCappedCone (validCone, hit_lower), t_cone_lower, vfloat<M>(pos_inf));
+ t_cone_upper = select (!coneL.isInsideCappedCone (validCone, hit_upper) & !coneR.isInsideCappedCone (validCone, hit_upper), t_cone_upper, vfloat<M>(neg_inf));
+#endif
+
+ /* intersect ending sphere */
+ vfloat<M> t_sph1_lower, t_sph1_upper;
+ vfloat<M> t_sph0_lower = vfloat<M>(pos_inf);
+ vfloat<M> t_sph0_upper = vfloat<M>(neg_inf);
+ cone.intersectEndSphere(valid, coneR, t_sph1_lower, t_sph1_upper);
+
+ const vbool<M> isBeginPoint = valid & (vL[0] == vfloat<M>(pos_inf));
+ if (unlikely(any(isBeginPoint))) {
+ cone.intersectBeginSphere (isBeginPoint, t_sph0_lower, t_sph0_upper);
+ }
+
+ /* CSG union of cone and end sphere */
+ vfloat<M> t_sph_lower = min(t_sph0_lower, t_sph1_lower);
+ vfloat<M> t_cone_sphere_lower = min(t_cone_lower, t_sph_lower);
+#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
+ vfloat<M> t_sph_upper = max(t_sph0_upper, t_sph1_upper);
+ vfloat<M> t_cone_sphere_upper = max(t_cone_upper, t_sph_upper);
+
+ /* filter out hits that are not in tnear/tfar range */
+ const vbool<M> valid_lower = valid & ray_tnear <= dt+t_cone_sphere_lower & dt+t_cone_sphere_lower <= ray_tfar() & t_cone_sphere_lower != vfloat<M>(pos_inf);
+ const vbool<M> valid_upper = valid & ray_tnear <= dt+t_cone_sphere_upper & dt+t_cone_sphere_upper <= ray_tfar() & t_cone_sphere_upper != vfloat<M>(neg_inf);
+
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_lower | valid_upper;
+ if (unlikely(none(valid_first)))
+ return false;
+
+ /* construct first hit */
+ const vfloat<M> t_first = select(valid_lower, t_cone_sphere_lower, t_cone_sphere_upper);
+ const vbool<M> cone_hit_first = t_first == t_cone_lower | t_first == t_cone_upper;
+ const vbool<M> sph0_hit_first = t_first == t_sph0_lower | t_first == t_sph0_upper;
+ const Vec3vf<M> Ng_first = select(cone_hit_first, cone.Ng_cone(valid_lower), select (sph0_hit_first, cone.Ng_sphere0(valid_lower), cone.Ng_sphere1(valid_lower)));
+ const vfloat<M> u_first = select(cone_hit_first, cone.u_cone(valid_lower), select (sph0_hit_first, vfloat<M>(zero), vfloat<M>(one)));
+
+ /* invoke intersection filter for first hit */
+ RoundLineIntersectorHitM<M> hit(u_first,zero,dt+t_first,Ng_first);
+ const bool is_hit_first = epilog(valid_first, hit);
+
+ /* check for possible second hits before potentially accepted hit */
+ const vfloat<M> t_second = t_cone_sphere_upper;
+ const vbool<M> valid_second = valid_lower & valid_upper & (dt+t_cone_sphere_upper <= ray_tfar());
+ if (unlikely(none(valid_second)))
+ return is_hit_first;
+
+ /* invoke intersection filter for second hit */
+ const vbool<M> cone_hit_second = t_second == t_cone_lower | t_second == t_cone_upper;
+ const vbool<M> sph0_hit_second = t_second == t_sph0_lower | t_second == t_sph0_upper;
+ const Vec3vf<M> Ng_second = select(cone_hit_second, cone.Ng_cone(false), select (sph0_hit_second, cone.Ng_sphere0(false), cone.Ng_sphere1(false)));
+ const vfloat<M> u_second = select(cone_hit_second, cone.u_cone(false), select (sph0_hit_second, vfloat<M>(zero), vfloat<M>(one)));
+
+ hit = RoundLineIntersectorHitM<M>(u_second,zero,dt+t_second,Ng_second);
+ const bool is_hit_second = epilog(valid_second, hit);
+
+ return is_hit_first | is_hit_second;
+#else
+ /* filter out hits that are not in tnear/tfar range */
+ const vbool<M> valid_lower = valid & ray_tnear <= dt+t_cone_sphere_lower & dt+t_cone_sphere_lower <= ray_tfar() & t_cone_sphere_lower != vfloat<M>(pos_inf);
+
+ /* check if there is a valid hit */
+ if (unlikely(none(valid_lower)))
+ return false;
+
+ /* construct first hit */
+ const vbool<M> cone_hit_first = t_cone_sphere_lower == t_cone_lower | t_cone_sphere_lower == t_cone_upper;
+ const vbool<M> sph0_hit_first = t_cone_sphere_lower == t_sph0_lower | t_cone_sphere_lower == t_sph0_upper;
+ const Vec3vf<M> Ng_first = select(cone_hit_first, cone.Ng_cone(valid_lower), select (sph0_hit_first, cone.Ng_sphere0(valid_lower), cone.Ng_sphere1(valid_lower)));
+ const vfloat<M> u_first = select(cone_hit_first, cone.u_cone(valid_lower), select (sph0_hit_first, vfloat<M>(zero), vfloat<M>(one)));
+
+ /* invoke intersection filter for first hit */
+ RoundLineIntersectorHitM<M> hit(u_first,zero,dt+t_cone_sphere_lower,Ng_first);
+ const bool is_hit_first = epilog(valid_lower, hit);
+
+ return is_hit_first;
+#endif
+ }
+
+ } // end namespace __roundline_internal
+
+ template<int M>
+ struct RoundLinearCurveIntersector1
+ {
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<typename Ray>
+ struct ray_tfar {
+ Ray& ray;
+ __forceinline ray_tfar(Ray& ray) : ray(ray) {}
+ __forceinline vfloat<M> operator() () const { return ray.tfar; };
+ };
+
+ template<typename Ray, typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ Ray& ray,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const Vec4vf<M>& vLi, const Vec4vf<M>& vRi,
+ const Epilog& epilog)
+ {
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+ const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);
+ const vfloat<M> ray_tnear(ray.tnear());
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v1i);
+ const Vec4vf<M> vL = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vLi);
+ const Vec4vf<M> vR = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vRi);
+ return __roundline_internal::intersectConeSphere<M>(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar<Ray>(ray),v0,v1,vL,vR,epilog);
+ }
+ };
+
+ template<int M, int K>
+ struct RoundLinearCurveIntersectorK
+ {
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ struct ray_tfar {
+ RayK<K>& ray;
+ size_t k;
+ __forceinline ray_tfar(RayK<K>& ray, size_t k) : ray(ray), k(k) {}
+ __forceinline vfloat<M> operator() () const { return ray.tfar[k]; };
+ };
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const LineSegments* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
+ const Vec4vf<M>& vLi, const Vec4vf<M>& vRi,
+ const Epilog& epilog)
+ {
+ const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
+ const vfloat<M> ray_tnear = ray.tnear()[k];
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec4vf<M> v1 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v1i);
+ const Vec4vf<M> vL = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vLi);
+ const Vec4vf<M> vR = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vRi);
+ return __roundline_internal::intersectConeSphere<M>(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar(ray,k),v0,v1,vL,vR,epilog);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/roundlinei_intersector.h b/thirdparty/embree/kernels/geometry/roundlinei_intersector.h
new file mode 100644
index 0000000000..29061d6475
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/roundlinei_intersector.h
@@ -0,0 +1,123 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "roundline_intersector.h"
+#include "intersector_epilog.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, bool filter>
+ struct RoundLinearCurveMiIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom);
+ const vbool<M> valid = line.valid();
+ RoundLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,vL,vR,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom);
+ const vbool<M> valid = line.valid();
+ return RoundLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,vL,vR,Occluded1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, bool filter>
+ struct RoundLinearCurveMiMBIntersector1
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom,ray.time());
+ const vbool<M> valid = line.valid();
+ RoundLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,vL,vR,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom,ray.time());
+ const vbool<M> valid = line.valid();
+ return RoundLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,vL,vR,Occluded1EpilogM<M,filter>(ray,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& line)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, line);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct RoundLinearCurveMiIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom);
+ const vbool<M> valid = line.valid();
+ RoundLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,vL,vR,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom);
+ const vbool<M> valid = line.valid();
+ return RoundLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,vL,vR,Occluded1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct RoundLinearCurveMiMBIntersectorK
+ {
+ typedef LineMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom,ray.time()[k]);
+ const vbool<M> valid = line.valid();
+ RoundLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,vL,vR,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const LineSegments* geom = context->scene->get<LineSegments>(line.geomID());
+ Vec4vf<M> v0,v1,vL,vR; line.gather(v0,v1,vL,vR,geom,ray.time()[k]);
+ const vbool<M> valid = line.valid();
+ return RoundLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,vL,vR,Occluded1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/sphere_intersector.h b/thirdparty/embree/kernels/geometry/sphere_intersector.h
new file mode 100644
index 0000000000..2670f9762d
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/sphere_intersector.h
@@ -0,0 +1,183 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/scene_points.h"
+#include "curve_intersector_precalculations.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct SphereIntersectorHitM
+ {
+ __forceinline SphereIntersectorHitM() {}
+
+ __forceinline SphereIntersectorHitM(const vfloat<M>& t, const Vec3vf<M>& Ng)
+ : vt(t), vNg(Ng) {}
+
+ __forceinline void finalize() {}
+
+ __forceinline Vec2f uv(const size_t i) const {
+ return Vec2f(0.0f, 0.0f);
+ }
+ __forceinline float t(const size_t i) const {
+ return vt[i];
+ }
+ __forceinline Vec3fa Ng(const size_t i) const {
+ return Vec3fa(vNg.x[i], vNg.y[i], vNg.z[i]);
+ }
+
+ public:
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct SphereIntersector1
+ {
+ typedef CurvePrecalculations1 Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(
+ const vbool<M>& valid_i, Ray& ray,
+ const Precalculations& pre, const Vec4vf<M>& v0, const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ const vfloat<M> rd2 = rcp(dot(ray.dir, ray.dir));
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+ const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ const Vec3vf<M> c0 = center - ray_org;
+ const vfloat<M> projC0 = dot(c0, ray_dir) * rd2;
+ const Vec3vf<M> perp = c0 - projC0 * ray_dir;
+ const vfloat<M> l2 = dot(perp, perp);
+ const vfloat<M> r2 = radius * radius;
+ valid &= (l2 <= r2);
+ if (unlikely(none(valid)))
+ return false;
+
+ const vfloat<M> td = sqrt((r2 - l2) * rd2);
+ const vfloat<M> t_front = projC0 - td;
+ const vfloat<M> t_back = projC0 + td;
+
+ const vbool<M> valid_front = valid & (ray.tnear() <= t_front) & (t_front <= ray.tfar);
+ const vbool<M> valid_back = valid & (ray.tnear() <= t_back ) & (t_back <= ray.tfar);
+
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_front | valid_back;
+ if (unlikely(none(valid_first)))
+ return false;
+
+ /* construct first hit */
+ const vfloat<M> td_front = -td;
+ const vfloat<M> td_back = +td;
+ const vfloat<M> t_first = select(valid_front, t_front, t_back);
+ const Vec3vf<M> Ng_first = select(valid_front, td_front, td_back) * ray_dir - perp;
+ SphereIntersectorHitM<M> hit(t_first, Ng_first);
+
+ /* invoke intersection filter for first hit */
+ const bool is_hit_first = epilog(valid_first, hit);
+
+ /* check for possible second hits before potentially accepted hit */
+ const vfloat<M> t_second = t_back;
+ const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar);
+ if (unlikely(none(valid_second)))
+ return is_hit_first;
+
+ /* invoke intersection filter for second hit */
+ const Vec3vf<M> Ng_second = td_back * ray_dir - perp;
+ hit = SphereIntersectorHitM<M> (t_second, Ng_second);
+ const bool is_hit_second = epilog(valid_second, hit);
+
+ return is_hit_first | is_hit_second;
+ }
+
+ template<typename Epilog>
+ static __forceinline bool intersect(
+ const vbool<M>& valid_i, Ray& ray, IntersectContext* context, const Points* geom,
+ const Precalculations& pre, const Vec4vf<M>& v0i, const Epilog& epilog)
+ {
+ const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ return intersect(valid_i,ray,pre,v0,epilog);
+ }
+ };
+
+ template<int M, int K>
+ struct SphereIntersectorK
+ {
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid_i,
+ RayK<K>& ray, size_t k,
+ IntersectContext* context,
+ const Points* geom,
+ const Precalculations& pre,
+ const Vec4vf<M>& v0i,
+ const Epilog& epilog)
+ {
+ vbool<M> valid = valid_i;
+
+ const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
+ const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
+ const vfloat<M> rd2 = rcp(dot(ray_dir, ray_dir));
+
+ const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
+ const Vec3vf<M> center = v0.xyz();
+ const vfloat<M> radius = v0.w;
+
+ const Vec3vf<M> c0 = center - ray_org;
+ const vfloat<M> projC0 = dot(c0, ray_dir) * rd2;
+ const Vec3vf<M> perp = c0 - projC0 * ray_dir;
+ const vfloat<M> l2 = dot(perp, perp);
+ const vfloat<M> r2 = radius * radius;
+ valid &= (l2 <= r2);
+ if (unlikely(none(valid)))
+ return false;
+
+ const vfloat<M> td = sqrt((r2 - l2) * rd2);
+ const vfloat<M> t_front = projC0 - td;
+ const vfloat<M> t_back = projC0 + td;
+
+ const vbool<M> valid_front = valid & (ray.tnear()[k] <= t_front) & (t_front <= ray.tfar[k]);
+ const vbool<M> valid_back = valid & (ray.tnear()[k] <= t_back ) & (t_back <= ray.tfar[k]);
+
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_front | valid_back;
+ if (unlikely(none(valid_first)))
+ return false;
+
+ /* construct first hit */
+ const vfloat<M> td_front = -td;
+ const vfloat<M> td_back = +td;
+ const vfloat<M> t_first = select(valid_front, t_front, t_back);
+ const Vec3vf<M> Ng_first = select(valid_front, td_front, td_back) * ray_dir - perp;
+ SphereIntersectorHitM<M> hit(t_first, Ng_first);
+
+ /* invoke intersection filter for first hit */
+ const bool is_hit_first = epilog(valid_first, hit);
+
+ /* check for possible second hits before potentially accepted hit */
+ const vfloat<M> t_second = t_back;
+ const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar[k]);
+ if (unlikely(none(valid_second)))
+ return is_hit_first;
+
+ /* invoke intersection filter for second hit */
+ const Vec3vf<M> Ng_second = td_back * ray_dir - perp;
+ hit = SphereIntersectorHitM<M> (t_second, Ng_second);
+ const bool is_hit_second = epilog(valid_second, hit);
+
+ return is_hit_first | is_hit_second;
+ }
+ };
+ } // namespace isa
+} // namespace embree
diff --git a/thirdparty/embree/kernels/geometry/spherei_intersector.h b/thirdparty/embree/kernels/geometry/spherei_intersector.h
new file mode 100644
index 0000000000..7a0b428117
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/spherei_intersector.h
@@ -0,0 +1,156 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "intersector_epilog.h"
+#include "pointi.h"
+#include "sphere_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, bool filter>
+ struct SphereMiIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& sphere)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom);
+ const vbool<M> valid = sphere.valid();
+ SphereIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, Intersect1EpilogM<M, filter>(ray, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& sphere)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom);
+ const vbool<M> valid = sphere.valid();
+ return SphereIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, Occluded1EpilogM<M, filter>(ray, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query,
+ PointQueryContext* context,
+ const Primitive& sphere)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, sphere);
+ }
+ };
+
+ template<int M, bool filter>
+ struct SphereMiMBIntersector1
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculations1 Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre,
+ RayHit& ray,
+ IntersectContext* context,
+ const Primitive& sphere)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom, ray.time());
+ const vbool<M> valid = sphere.valid();
+ SphereIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, Intersect1EpilogM<M, filter>(ray, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre,
+ Ray& ray,
+ IntersectContext* context,
+ const Primitive& sphere)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom, ray.time());
+ const vbool<M> valid = sphere.valid();
+ return SphereIntersector1<M>::intersect(
+ valid, ray, context, geom, pre, v0, Occluded1EpilogM<M, filter>(ray, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query,
+ PointQueryContext* context,
+ const Primitive& sphere)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, sphere);
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct SphereMiIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom);
+ const vbool<M> valid = sphere.valid();
+ SphereIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Intersect1KEpilogM<M, K, filter>(ray, k, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom);
+ const vbool<M> valid = sphere.valid();
+ return SphereIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Occluded1KEpilogM<M, K, filter>(ray, k, context, sphere.geomID(), sphere.primID()));
+ }
+ };
+
+ template<int M, int K, bool filter>
+ struct SphereMiMBIntersectorK
+ {
+ typedef PointMi<M> Primitive;
+ typedef CurvePrecalculationsK<K> Precalculations;
+
+ static __forceinline void intersect(
+ const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere)
+ {
+ STAT3(normal.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom, ray.time()[k]);
+ const vbool<M> valid = sphere.valid();
+ SphereIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Intersect1KEpilogM<M, K, filter>(ray, k, context, sphere.geomID(), sphere.primID()));
+ }
+
+ static __forceinline bool occluded(
+ const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere)
+ {
+ STAT3(shadow.trav_prims, 1, 1, 1);
+ const Points* geom = context->scene->get<Points>(sphere.geomID());
+ Vec4vf<M> v0; sphere.gather(v0, geom, ray.time()[k]);
+ const vbool<M> valid = sphere.valid();
+ return SphereIntersectorK<M, K>::intersect(
+ valid, ray, k, context, geom, pre, v0,
+ Occluded1KEpilogM<M, K, filter>(ray, k, context, sphere.geomID(), sphere.primID()));
+ }
+ };
+ } // namespace isa
+} // namespace embree
diff --git a/thirdparty/embree/kernels/geometry/subdivpatch1.h b/thirdparty/embree/kernels/geometry/subdivpatch1.h
new file mode 100644
index 0000000000..ae0d4e2616
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/subdivpatch1.h
@@ -0,0 +1,38 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../geometry/primitive.h"
+#include "../subdiv/subdivpatch1base.h"
+
+namespace embree
+{
+
+ struct __aligned(64) SubdivPatch1 : public SubdivPatch1Base
+ {
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+
+ static Type type;
+
+ public:
+
+ /*! constructor for cached subdiv patch */
+ SubdivPatch1 (const unsigned int gID,
+ const unsigned int pID,
+ const unsigned int subPatch,
+ const SubdivMesh *const mesh,
+ const size_t time,
+ const Vec2f uv[4],
+ const float edge_level[4],
+ const int subdiv[4],
+ const int simd_width)
+ : SubdivPatch1Base(gID,pID,subPatch,mesh,time,uv,edge_level,subdiv,simd_width) {}
+ };
+}
diff --git a/thirdparty/embree/kernels/geometry/subdivpatch1_intersector.h b/thirdparty/embree/kernels/geometry/subdivpatch1_intersector.h
new file mode 100644
index 0000000000..b4b15a1210
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/subdivpatch1_intersector.h
@@ -0,0 +1,237 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "subdivpatch1.h"
+#include "grid_soa.h"
+#include "grid_soa_intersector1.h"
+#include "grid_soa_intersector_packet.h"
+#include "../common/ray.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename T>
+ class SubdivPatch1Precalculations : public T
+ {
+ public:
+ __forceinline SubdivPatch1Precalculations (const Ray& ray, const void* ptr)
+ : T(ray,ptr) {}
+ };
+
+ template<int K, typename T>
+ class SubdivPatch1PrecalculationsK : public T
+ {
+ public:
+ __forceinline SubdivPatch1PrecalculationsK (const vbool<K>& valid, RayK<K>& ray)
+ : T(valid,ray) {}
+ };
+
+ class SubdivPatch1Intersector1
+ {
+ public:
+ typedef GridSOA Primitive;
+ typedef SubdivPatch1Precalculations<GridSOAIntersector1::Precalculations> Precalculations;
+
+ static __forceinline bool processLazyNode(Precalculations& pre, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ lazy_node = prim->root(0);
+ pre.grid = (Primitive*)prim;
+ return false;
+ }
+
+ /*! Intersect a ray with the primitive. */
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAIntersector1::intersect(pre,ray,context,prim,lazy_node);
+ else processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) {
+ intersect(This,pre,ray,context,prim,ty,tray,lazy_node);
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAIntersector1::occluded(pre,ray,context,prim,lazy_node);
+ else return processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) {
+ return occluded(This,pre,ray,context,prim,ty,tray,lazy_node);
+ }
+
+ template<int N>
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t ty, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ // TODO: PointQuery implement
+ assert(false && "not implemented");
+ return false;
+ }
+
+ template<int N>
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravPointQuery<N> &tquery, size_t& lazy_node) {
+ return pointQuery(This,query,context,prim,ty,tquery,lazy_node);
+ }
+ };
+
+ class SubdivPatch1MBIntersector1
+ {
+ public:
+ typedef SubdivPatch1 Primitive;
+ typedef GridSOAMBIntersector1::Precalculations Precalculations;
+
+ static __forceinline bool processLazyNode(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim_i, size_t& lazy_node)
+ {
+ Primitive* prim = (Primitive*) prim_i;
+ GridSOA* grid = nullptr;
+ grid = (GridSOA*) prim->root_ref.get();
+ pre.itime = getTimeSegment(ray.time(), float(grid->time_steps-1), pre.ftime);
+ lazy_node = grid->root(pre.itime);
+ pre.grid = grid;
+ return false;
+ }
+
+ /*! Intersect a ray with the primitive. */
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAMBIntersector1::intersect(pre,ray,context,prim,lazy_node);
+ else processLazyNode(pre,ray,context,prim,lazy_node);
+ }
+
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) {
+ intersect(This,pre,ray,context,prim,ty,tray,lazy_node);
+ }
+
+ /*! Test if the ray is occluded by the primitive */
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAMBIntersector1::occluded(pre,ray,context,prim,lazy_node);
+ else return processLazyNode(pre,ray,context,prim,lazy_node);
+ }
+
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) {
+ return occluded(This,pre,ray,context,prim,ty,tray,lazy_node);
+ }
+
+ template<int N>
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t ty, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ // TODO: PointQuery implement
+ assert(false && "not implemented");
+ return false;
+ }
+
+ template<int N, bool robust>
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravPointQuery<N> &tquery, size_t& lazy_node) {
+ return pointQuery(This,query,context,prim,ty,tquery,lazy_node);
+ }
+ };
+
+ template <int K>
+ struct SubdivPatch1IntersectorK
+ {
+ typedef GridSOA Primitive;
+ typedef SubdivPatch1PrecalculationsK<K,typename GridSOAIntersectorK<K>::Precalculations> Precalculations;
+
+ static __forceinline bool processLazyNode(Precalculations& pre, IntersectContext* context, const Primitive* prim, size_t& lazy_node)
+ {
+ lazy_node = prim->root(0);
+ pre.grid = (Primitive*)prim;
+ return false;
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAIntersectorK<K>::intersect(valid,pre,ray,context,prim,lazy_node);
+ else processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAIntersectorK<K>::occluded(valid,pre,ray,context,prim,lazy_node);
+ else return processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAIntersectorK<K>::intersect(pre,ray,k,context,prim,lazy_node);
+ else processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAIntersectorK<K>::occluded(pre,ray,k,context,prim,lazy_node);
+ else return processLazyNode(pre,context,prim,lazy_node);
+ }
+ };
+
+ typedef SubdivPatch1IntersectorK<4> SubdivPatch1Intersector4;
+ typedef SubdivPatch1IntersectorK<8> SubdivPatch1Intersector8;
+ typedef SubdivPatch1IntersectorK<16> SubdivPatch1Intersector16;
+
+ template <int K>
+ struct SubdivPatch1MBIntersectorK
+ {
+ typedef SubdivPatch1 Primitive;
+ //typedef GridSOAMBIntersectorK<K>::Precalculations Precalculations;
+ typedef SubdivPatch1PrecalculationsK<K,typename GridSOAMBIntersectorK<K>::Precalculations> Precalculations;
+
+ static __forceinline bool processLazyNode(Precalculations& pre, IntersectContext* context, const Primitive* prim_i, size_t& lazy_node)
+ {
+ Primitive* prim = (Primitive*) prim_i;
+ GridSOA* grid = (GridSOA*) prim->root_ref.get();
+ lazy_node = grid->troot;
+ pre.grid = grid;
+ return false;
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAMBIntersectorK<K>::intersect(valid,pre,ray,context,prim,lazy_node);
+ else processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAMBIntersectorK<K>::occluded(valid,pre,ray,context,prim,lazy_node);
+ else return processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) GridSOAMBIntersectorK<K>::intersect(pre,ray,k,context,prim,lazy_node);
+ else processLazyNode(pre,context,prim,lazy_node);
+ }
+
+ template<int N, bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ if (likely(ty == 0)) return GridSOAMBIntersectorK<K>::occluded(pre,ray,k,context,prim,lazy_node);
+ else return processLazyNode(pre,context,prim,lazy_node);
+ }
+ };
+
+ typedef SubdivPatch1MBIntersectorK<4> SubdivPatch1MBIntersector4;
+ typedef SubdivPatch1MBIntersectorK<8> SubdivPatch1MBIntersector8;
+ typedef SubdivPatch1MBIntersectorK<16> SubdivPatch1MBIntersector16;
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/subgrid.h b/thirdparty/embree/kernels/geometry/subgrid.h
new file mode 100644
index 0000000000..ce54421cab
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/subgrid.h
@@ -0,0 +1,517 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/ray.h"
+#include "../common/scene_grid_mesh.h"
+#include "../bvh/bvh.h"
+
+namespace embree
+{
+ /* Stores M quads from an indexed face set */
+ struct SubGrid
+ {
+ /* Virtual interface to query information about the quad type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored quads */
+ static __forceinline size_t max_size() { return 1; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline SubGrid() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline SubGrid(const unsigned int x,
+ const unsigned int y,
+ const unsigned int geomID,
+ const unsigned int primID)
+ : _x(x), _y(y), _geomID(geomID), _primID(primID)
+ {
+ }
+
+ __forceinline bool invalid3x3X() const { return (unsigned int)_x & (1<<15); }
+ __forceinline bool invalid3x3Y() const { return (unsigned int)_y & (1<<15); }
+
+ /* Gather the quads */
+ __forceinline void gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const GridMesh* const mesh,
+ const GridMesh::Grid &g) const
+ {
+ /* first quad always valid */
+ const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
+ const size_t vtxID01 = vtxID00 + 1;
+ const vfloat4 vtx00 = vfloat4::loadu(mesh->vertexPtr(vtxID00));
+ const vfloat4 vtx01 = vfloat4::loadu(mesh->vertexPtr(vtxID01));
+ const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
+ const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
+ const vfloat4 vtx10 = vfloat4::loadu(mesh->vertexPtr(vtxID10));
+ const vfloat4 vtx11 = vfloat4::loadu(mesh->vertexPtr(vtxID11));
+
+ /* deltaX => vtx02, vtx12 */
+ const size_t deltaX = invalid3x3X() ? 0 : 1;
+ const size_t vtxID02 = vtxID01 + deltaX;
+ const vfloat4 vtx02 = vfloat4::loadu(mesh->vertexPtr(vtxID02));
+ const size_t vtxID12 = vtxID11 + deltaX;
+ const vfloat4 vtx12 = vfloat4::loadu(mesh->vertexPtr(vtxID12));
+
+ /* deltaY => vtx20, vtx21 */
+ const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
+ const size_t vtxID20 = vtxID10 + deltaY;
+ const size_t vtxID21 = vtxID11 + deltaY;
+ const vfloat4 vtx20 = vfloat4::loadu(mesh->vertexPtr(vtxID20));
+ const vfloat4 vtx21 = vfloat4::loadu(mesh->vertexPtr(vtxID21));
+
+ /* deltaX/deltaY => vtx22 */
+ const size_t vtxID22 = vtxID11 + deltaX + deltaY;
+ const vfloat4 vtx22 = vfloat4::loadu(mesh->vertexPtr(vtxID22));
+
+ transpose(vtx00,vtx01,vtx11,vtx10,p0.x,p0.y,p0.z);
+ transpose(vtx01,vtx02,vtx12,vtx11,p1.x,p1.y,p1.z);
+ transpose(vtx11,vtx12,vtx22,vtx21,p2.x,p2.y,p2.z);
+ transpose(vtx10,vtx11,vtx21,vtx20,p3.x,p3.y,p3.z);
+ }
+
+ template<typename T>
+ __forceinline vfloat4 getVertexMB(const GridMesh* const mesh, const size_t offset, const size_t itime, const float ftime) const
+ {
+ const T v0 = T::loadu(mesh->vertexPtr(offset,itime+0));
+ const T v1 = T::loadu(mesh->vertexPtr(offset,itime+1));
+ return lerp(v0,v1,ftime);
+ }
+
+ /* Gather the quads */
+ __forceinline void gatherMB(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const GridMesh* const mesh,
+ const GridMesh::Grid &g,
+ const size_t itime,
+ const float ftime) const
+ {
+ /* first quad always valid */
+ const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
+ const size_t vtxID01 = vtxID00 + 1;
+ const vfloat4 vtx00 = getVertexMB<vfloat4>(mesh,vtxID00,itime,ftime);
+ const vfloat4 vtx01 = getVertexMB<vfloat4>(mesh,vtxID01,itime,ftime);
+ const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
+ const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
+ const vfloat4 vtx10 = getVertexMB<vfloat4>(mesh,vtxID10,itime,ftime);
+ const vfloat4 vtx11 = getVertexMB<vfloat4>(mesh,vtxID11,itime,ftime);
+
+ /* deltaX => vtx02, vtx12 */
+ const size_t deltaX = invalid3x3X() ? 0 : 1;
+ const size_t vtxID02 = vtxID01 + deltaX;
+ const vfloat4 vtx02 = getVertexMB<vfloat4>(mesh,vtxID02,itime,ftime);
+ const size_t vtxID12 = vtxID11 + deltaX;
+ const vfloat4 vtx12 = getVertexMB<vfloat4>(mesh,vtxID12,itime,ftime);
+
+ /* deltaY => vtx20, vtx21 */
+ const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
+ const size_t vtxID20 = vtxID10 + deltaY;
+ const size_t vtxID21 = vtxID11 + deltaY;
+ const vfloat4 vtx20 = getVertexMB<vfloat4>(mesh,vtxID20,itime,ftime);
+ const vfloat4 vtx21 = getVertexMB<vfloat4>(mesh,vtxID21,itime,ftime);
+
+ /* deltaX/deltaY => vtx22 */
+ const size_t vtxID22 = vtxID11 + deltaX + deltaY;
+ const vfloat4 vtx22 = getVertexMB<vfloat4>(mesh,vtxID22,itime,ftime);
+
+ transpose(vtx00,vtx01,vtx11,vtx10,p0.x,p0.y,p0.z);
+ transpose(vtx01,vtx02,vtx12,vtx11,p1.x,p1.y,p1.z);
+ transpose(vtx11,vtx12,vtx22,vtx21,p2.x,p2.y,p2.z);
+ transpose(vtx10,vtx11,vtx21,vtx20,p3.x,p3.y,p3.z);
+ }
+
+
+
+ /* Gather the quads */
+ __forceinline void gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const Scene *const scene) const
+ {
+ const GridMesh* const mesh = scene->get<GridMesh>(geomID());
+ const GridMesh::Grid &g = mesh->grid(primID());
+ gather(p0,p1,p2,p3,mesh,g);
+ }
+
+ /* Gather the quads in the motion blur case */
+ __forceinline void gatherMB(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ Vec3vf4& p3,
+ const Scene *const scene,
+ const size_t itime,
+ const float ftime) const
+ {
+ const GridMesh* const mesh = scene->get<GridMesh>(geomID());
+ const GridMesh::Grid &g = mesh->grid(primID());
+ gatherMB(p0,p1,p2,p3,mesh,g,itime,ftime);
+ }
+
+ /* Gather the quads */
+ __forceinline void gather(Vec3fa vtx[16], const Scene *const scene) const
+ {
+ const GridMesh* mesh = scene->get<GridMesh>(geomID());
+ const GridMesh::Grid &g = mesh->grid(primID());
+
+ /* first quad always valid */
+ const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
+ const size_t vtxID01 = vtxID00 + 1;
+ const Vec3fa vtx00 = Vec3fa::loadu(mesh->vertexPtr(vtxID00));
+ const Vec3fa vtx01 = Vec3fa::loadu(mesh->vertexPtr(vtxID01));
+ const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
+ const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
+ const Vec3fa vtx10 = Vec3fa::loadu(mesh->vertexPtr(vtxID10));
+ const Vec3fa vtx11 = Vec3fa::loadu(mesh->vertexPtr(vtxID11));
+
+ /* deltaX => vtx02, vtx12 */
+ const size_t deltaX = invalid3x3X() ? 0 : 1;
+ const size_t vtxID02 = vtxID01 + deltaX;
+ const Vec3fa vtx02 = Vec3fa::loadu(mesh->vertexPtr(vtxID02));
+ const size_t vtxID12 = vtxID11 + deltaX;
+ const Vec3fa vtx12 = Vec3fa::loadu(mesh->vertexPtr(vtxID12));
+
+ /* deltaY => vtx20, vtx21 */
+ const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
+ const size_t vtxID20 = vtxID10 + deltaY;
+ const size_t vtxID21 = vtxID11 + deltaY;
+ const Vec3fa vtx20 = Vec3fa::loadu(mesh->vertexPtr(vtxID20));
+ const Vec3fa vtx21 = Vec3fa::loadu(mesh->vertexPtr(vtxID21));
+
+ /* deltaX/deltaY => vtx22 */
+ const size_t vtxID22 = vtxID11 + deltaX + deltaY;
+ const Vec3fa vtx22 = Vec3fa::loadu(mesh->vertexPtr(vtxID22));
+
+ vtx[ 0] = vtx00; vtx[ 1] = vtx01; vtx[ 2] = vtx11; vtx[ 3] = vtx10;
+ vtx[ 4] = vtx01; vtx[ 5] = vtx02; vtx[ 6] = vtx12; vtx[ 7] = vtx11;
+ vtx[ 8] = vtx10; vtx[ 9] = vtx11; vtx[10] = vtx21; vtx[11] = vtx20;
+ vtx[12] = vtx11; vtx[13] = vtx12; vtx[14] = vtx22; vtx[15] = vtx21;
+ }
+
+ /* Gather the quads */
+ __forceinline void gatherMB(vfloat4 vtx[16], const Scene *const scene, const size_t itime, const float ftime) const
+ {
+ const GridMesh* mesh = scene->get<GridMesh>(geomID());
+ const GridMesh::Grid &g = mesh->grid(primID());
+
+ /* first quad always valid */
+ const size_t vtxID00 = g.startVtxID + x() + y() * g.lineVtxOffset;
+ const size_t vtxID01 = vtxID00 + 1;
+ const vfloat4 vtx00 = getVertexMB<vfloat4>(mesh,vtxID00,itime,ftime);
+ const vfloat4 vtx01 = getVertexMB<vfloat4>(mesh,vtxID01,itime,ftime);
+ const size_t vtxID10 = vtxID00 + g.lineVtxOffset;
+ const size_t vtxID11 = vtxID01 + g.lineVtxOffset;
+ const vfloat4 vtx10 = getVertexMB<vfloat4>(mesh,vtxID10,itime,ftime);
+ const vfloat4 vtx11 = getVertexMB<vfloat4>(mesh,vtxID11,itime,ftime);
+
+ /* deltaX => vtx02, vtx12 */
+ const size_t deltaX = invalid3x3X() ? 0 : 1;
+ const size_t vtxID02 = vtxID01 + deltaX;
+ const vfloat4 vtx02 = getVertexMB<vfloat4>(mesh,vtxID02,itime,ftime);
+ const size_t vtxID12 = vtxID11 + deltaX;
+ const vfloat4 vtx12 = getVertexMB<vfloat4>(mesh,vtxID12,itime,ftime);
+
+ /* deltaY => vtx20, vtx21 */
+ const size_t deltaY = invalid3x3Y() ? 0 : g.lineVtxOffset;
+ const size_t vtxID20 = vtxID10 + deltaY;
+ const size_t vtxID21 = vtxID11 + deltaY;
+ const vfloat4 vtx20 = getVertexMB<vfloat4>(mesh,vtxID20,itime,ftime);
+ const vfloat4 vtx21 = getVertexMB<vfloat4>(mesh,vtxID21,itime,ftime);
+
+ /* deltaX/deltaY => vtx22 */
+ const size_t vtxID22 = vtxID11 + deltaX + deltaY;
+ const vfloat4 vtx22 = getVertexMB<vfloat4>(mesh,vtxID22,itime,ftime);
+
+ vtx[ 0] = vtx00; vtx[ 1] = vtx01; vtx[ 2] = vtx11; vtx[ 3] = vtx10;
+ vtx[ 4] = vtx01; vtx[ 5] = vtx02; vtx[ 6] = vtx12; vtx[ 7] = vtx11;
+ vtx[ 8] = vtx10; vtx[ 9] = vtx11; vtx[10] = vtx21; vtx[11] = vtx20;
+ vtx[12] = vtx11; vtx[13] = vtx12; vtx[14] = vtx22; vtx[15] = vtx21;
+ }
+
+
+ /* Calculate the bounds of the subgrid */
+ __forceinline const BBox3fa bounds(const Scene *const scene, const size_t itime=0) const
+ {
+ BBox3fa bounds = empty;
+ FATAL("not implemented yet");
+ return bounds;
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds(const Scene* const scene, const size_t itime)
+ {
+ return LBBox3fa(bounds(scene,itime+0),bounds(scene,itime+1));
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime, size_t numTimeSteps)
+ {
+ LBBox3fa allBounds = empty;
+ FATAL("not implemented yet");
+ return allBounds;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, const BBox1f time_range)
+ {
+ LBBox3fa allBounds = empty;
+ FATAL("not implemented yet");
+ return allBounds;
+ }
+
+
+ friend embree_ostream operator<<(embree_ostream cout, const SubGrid& sg) {
+ return cout << "SubGrid " << " ( x " << sg.x() << ", y = " << sg.y() << ", geomID = " << sg.geomID() << ", primID = " << sg.primID() << " )";
+ }
+
+ __forceinline unsigned int geomID() const { return _geomID; }
+ __forceinline unsigned int primID() const { return _primID; }
+ __forceinline unsigned int x() const { return (unsigned int)_x & 0x7fff; }
+ __forceinline unsigned int y() const { return (unsigned int)_y & 0x7fff; }
+
+ private:
+ unsigned short _x;
+ unsigned short _y;
+ unsigned int _geomID; // geometry ID of mesh
+ unsigned int _primID; // primitive ID of primitive inside mesh
+ };
+
+ struct SubGridID {
+ unsigned short x;
+ unsigned short y;
+ unsigned int primID;
+
+ __forceinline SubGridID() {}
+ __forceinline SubGridID(const unsigned int x, const unsigned int y, const unsigned int primID) :
+ x(x), y(y), primID(primID) {}
+ };
+
+ /* QuantizedBaseNode as large subgrid leaf */
+ template<int N>
+ struct SubGridQBVHN
+ {
+ /* Virtual interface to query information about the quad type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ __forceinline size_t size() const
+ {
+ for (size_t i=0;i<N;i++)
+ if (primID(i) == -1) return i;
+ return N;
+ }
+
+ __forceinline void clear() {
+ for (size_t i=0;i<N;i++)
+ subgridIDs[i] = SubGridID(0,0,(unsigned int)-1);
+ qnode.clear();
+ }
+
+ /* Default constructor */
+ __forceinline SubGridQBVHN() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline SubGridQBVHN(const unsigned int x[N],
+ const unsigned int y[N],
+ const unsigned int primID[N],
+ const BBox3fa * const subGridBounds,
+ const unsigned int geomID,
+ const unsigned int items)
+ {
+ clear();
+ _geomID = geomID;
+
+ __aligned(64) typename BVHN<N>::AABBNode node;
+ node.clear();
+ for (size_t i=0;i<items;i++)
+ {
+ subgridIDs[i] = SubGridID(x[i],y[i],primID[i]);
+ node.setBounds(i,subGridBounds[i]);
+ }
+ qnode.init_dim(node);
+ }
+
+ __forceinline unsigned int geomID() const { return _geomID; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i < N); return subgridIDs[i].primID; }
+ __forceinline unsigned int x(const size_t i) const { assert(i < N); return subgridIDs[i].x; }
+ __forceinline unsigned int y(const size_t i) const { assert(i < N); return subgridIDs[i].y; }
+
+ __forceinline SubGrid subgrid(const size_t i) const {
+ assert(i < N);
+ assert(primID(i) != -1);
+ return SubGrid(x(i),y(i),geomID(),primID(i));
+ }
+
+ public:
+ SubGridID subgridIDs[N];
+
+ typename BVHN<N>::QuantizedBaseNode qnode;
+
+ unsigned int _geomID; // geometry ID of mesh
+
+
+ friend embree_ostream operator<<(embree_ostream cout, const SubGridQBVHN& sg) {
+ cout << "SubGridQBVHN " << embree_endl;
+ for (size_t i=0;i<N;i++)
+ cout << i << " ( x = " << sg.subgridIDs[i].x << ", y = " << sg.subgridIDs[i].y << ", primID = " << sg.subgridIDs[i].primID << " )" << embree_endl;
+ cout << "geomID " << sg._geomID << embree_endl;
+ cout << "lowerX " << sg.qnode.dequantizeLowerX() << embree_endl;
+ cout << "upperX " << sg.qnode.dequantizeUpperX() << embree_endl;
+ cout << "lowerY " << sg.qnode.dequantizeLowerY() << embree_endl;
+ cout << "upperY " << sg.qnode.dequantizeUpperY() << embree_endl;
+ cout << "lowerZ " << sg.qnode.dequantizeLowerZ() << embree_endl;
+ cout << "upperZ " << sg.qnode.dequantizeUpperZ() << embree_endl;
+ return cout;
+ }
+
+ };
+
+ template<int N>
+ typename SubGridQBVHN<N>::Type SubGridQBVHN<N>::type;
+
+ typedef SubGridQBVHN<4> SubGridQBVH4;
+ typedef SubGridQBVHN<8> SubGridQBVH8;
+
+
+ /* QuantizedBaseNode as large subgrid leaf */
+ template<int N>
+ struct SubGridMBQBVHN
+ {
+ /* Virtual interface to query information about the quad type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ __forceinline size_t size() const
+ {
+ for (size_t i=0;i<N;i++)
+ if (primID(i) == -1) return i;
+ return N;
+ }
+
+ __forceinline void clear() {
+ for (size_t i=0;i<N;i++)
+ subgridIDs[i] = SubGridID(0,0,(unsigned int)-1);
+ qnode.clear();
+ }
+
+ /* Default constructor */
+ __forceinline SubGridMBQBVHN() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline SubGridMBQBVHN(const unsigned int x[N],
+ const unsigned int y[N],
+ const unsigned int primID[N],
+ const BBox3fa * const subGridBounds0,
+ const BBox3fa * const subGridBounds1,
+ const unsigned int geomID,
+ const float toffset,
+ const float tscale,
+ const unsigned int items)
+ {
+ clear();
+ _geomID = geomID;
+ time_offset = toffset;
+ time_scale = tscale;
+
+ __aligned(64) typename BVHN<N>::AABBNode node0,node1;
+ node0.clear();
+ node1.clear();
+ for (size_t i=0;i<items;i++)
+ {
+ subgridIDs[i] = SubGridID(x[i],y[i],primID[i]);
+ node0.setBounds(i,subGridBounds0[i]);
+ node1.setBounds(i,subGridBounds1[i]);
+ }
+ qnode.node0.init_dim(node0);
+ qnode.node1.init_dim(node1);
+ }
+
+ __forceinline unsigned int geomID() const { return _geomID; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i < N); return subgridIDs[i].primID; }
+ __forceinline unsigned int x(const size_t i) const { assert(i < N); return subgridIDs[i].x; }
+ __forceinline unsigned int y(const size_t i) const { assert(i < N); return subgridIDs[i].y; }
+
+ __forceinline SubGrid subgrid(const size_t i) const {
+ assert(i < N);
+ assert(primID(i) != -1);
+ return SubGrid(x(i),y(i),geomID(),primID(i));
+ }
+
+ __forceinline float adjustTime(const float t) const { return time_scale * (t-time_offset); }
+
+ template<int K>
+ __forceinline vfloat<K> adjustTime(const vfloat<K> &t) const { return time_scale * (t-time_offset); }
+
+ public:
+ SubGridID subgridIDs[N];
+
+ typename BVHN<N>::QuantizedBaseNodeMB qnode;
+
+ float time_offset;
+ float time_scale;
+ unsigned int _geomID; // geometry ID of mesh
+
+
+ friend embree_ostream operator<<(embree_ostream cout, const SubGridMBQBVHN& sg) {
+ cout << "SubGridMBQBVHN " << embree_endl;
+ for (size_t i=0;i<N;i++)
+ cout << i << " ( x = " << sg.subgridIDs[i].x << ", y = " << sg.subgridIDs[i].y << ", primID = " << sg.subgridIDs[i].primID << " )" << embree_endl;
+ cout << "geomID " << sg._geomID << embree_endl;
+ cout << "time_offset " << sg.time_offset << embree_endl;
+ cout << "time_scale " << sg.time_scale << embree_endl;
+ cout << "lowerX " << sg.qnode.node0.dequantizeLowerX() << embree_endl;
+ cout << "upperX " << sg.qnode.node0.dequantizeUpperX() << embree_endl;
+ cout << "lowerY " << sg.qnode.node0.dequantizeLowerY() << embree_endl;
+ cout << "upperY " << sg.qnode.node0.dequantizeUpperY() << embree_endl;
+ cout << "lowerZ " << sg.qnode.node0.dequantizeLowerZ() << embree_endl;
+ cout << "upperZ " << sg.qnode.node0.dequantizeUpperZ() << embree_endl;
+ cout << "lowerX " << sg.qnode.node1.dequantizeLowerX() << embree_endl;
+ cout << "upperX " << sg.qnode.node1.dequantizeUpperX() << embree_endl;
+ cout << "lowerY " << sg.qnode.node1.dequantizeLowerY() << embree_endl;
+ cout << "upperY " << sg.qnode.node1.dequantizeUpperY() << embree_endl;
+ cout << "lowerZ " << sg.qnode.node1.dequantizeLowerZ() << embree_endl;
+ cout << "upperZ " << sg.qnode.node1.dequantizeUpperZ() << embree_endl;
+ return cout;
+ }
+
+ };
+
+}
diff --git a/thirdparty/embree/kernels/geometry/subgrid_intersector.h b/thirdparty/embree/kernels/geometry/subgrid_intersector.h
new file mode 100644
index 0000000000..ad5fee2e4e
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/subgrid_intersector.h
@@ -0,0 +1,517 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "subgrid.h"
+#include "subgrid_intersector_moeller.h"
+#include "subgrid_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+
+ // =======================================================================================
+ // =================================== SubGridIntersectors ===============================
+ // =======================================================================================
+
+
+ template<int N, bool filter>
+ struct SubGridIntersector1Moeller
+ {
+ typedef SubGridQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersector1MoellerTrumbore<4,filter> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const SubGrid& subgrid)
+ {
+ STAT3(point_query.trav_prims,1,1,1);
+ AccelSet* accel = (AccelSet*)context->scene->get(subgrid.geomID());
+ assert(accel);
+ context->geomID = subgrid.geomID();
+ context->primID = subgrid.primID();
+ return accel->pointQuery(query, context);
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+#if defined(__AVX__)
+ STAT3(normal.trav_hit_boxes[popcnt(mask)],1,1,1);
+#endif
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (unlikely(dist[ID] > ray.tfar)) continue;
+ intersect(pre,ray,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+ template<bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (occluded(pre,ray,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ bool changed = false;
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask;
+ if (likely(context->query_type == POINT_QUERY_TYPE_SPHERE)) {
+ mask = BVHNQuantizedBaseNodePointQuerySphere1<N>::pointQuery(&prim[i].qnode,tquery,dist);
+ } else {
+ mask = BVHNQuantizedBaseNodePointQueryAABB1<N>::pointQuery(&prim[i].qnode,tquery,dist);
+ }
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+ changed |= pointQuery(query, context, prim[i].subgrid(ID));
+ }
+ }
+ return changed;
+ }
+ };
+
+ template<int N, bool filter>
+ struct SubGridIntersector1Pluecker
+ {
+ typedef SubGridQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersector1Pluecker<4,filter> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const SubGrid& subgrid)
+ {
+ STAT3(point_query.trav_prims,1,1,1);
+ AccelSet* accel = (AccelSet*)context->scene->get(subgrid.geomID());
+ context->geomID = subgrid.geomID();
+ context->primID = subgrid.primID();
+ return accel->pointQuery(query, context);
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+#if defined(__AVX__)
+ STAT3(normal.trav_hit_boxes[popcnt(mask)],1,1,1);
+#endif
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (unlikely(dist[ID] > ray.tfar)) continue;
+ intersect(pre,ray,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (occluded(pre,ray,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ bool changed = false;
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask;
+ if (likely(context->query_type == POINT_QUERY_TYPE_SPHERE)) {
+ mask = BVHNQuantizedBaseNodePointQuerySphere1<N>::pointQuery(&prim[i].qnode,tquery,dist);
+ } else {
+ mask = BVHNQuantizedBaseNodePointQueryAABB1<N>::pointQuery(&prim[i].qnode,tquery,dist);
+ }
+#if defined(__AVX__)
+ STAT3(point_query.trav_hit_boxes[popcnt(mask)],1,1,1);
+#endif
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+ changed |= pointQuery(query, context, prim[i].subgrid(ID));
+ }
+ }
+ return changed;
+ }
+ };
+
+ template<int N, int K, bool filter>
+ struct SubGridIntersectorKMoeller
+ {
+ typedef SubGridQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersectorKMoellerTrumbore<4,K,filter> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ Vec3fa vtx[16];
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ subgrid.gather(vtx,context->scene);
+ for (unsigned int i=0; i<4; i++)
+ {
+ const Vec3vf<K> p0 = vtx[i*4+0];
+ const Vec3vf<K> p1 = vtx[i*4+1];
+ const Vec3vf<K> p2 = vtx[i*4+2];
+ const Vec3vf<K> p3 = vtx[i*4+3];
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,g,subgrid,i,IntersectKEpilogM<4,K,filter>(ray,context,subgrid.geomID(),subgrid.primID(),i));
+ }
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ vbool<K> valid0 = valid_i;
+ Vec3fa vtx[16];
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ subgrid.gather(vtx,context->scene);
+ for (unsigned int i=0; i<4; i++)
+ {
+ const Vec3vf<K> p0 = vtx[i*4+0];
+ const Vec3vf<K> p1 = vtx[i*4+1];
+ const Vec3vf<K> p2 = vtx[i*4+2];
+ const Vec3vf<K> p3 = vtx[i*4+3];
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ if (pre.intersectK(valid0,ray,p0,p1,p2,p3,g,subgrid,i,OccludedKEpilogM<4,K,filter>(valid0,ray,context,subgrid.geomID(),subgrid.primID(),i)))
+ break;
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
+ intersect(valid,pre,ray,context,prim[j].subgrid(i));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+ vbool<K> valid0 = valid;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid0 & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
+ valid0 &= !occluded(valid0,pre,ray,context,prim[j].subgrid(i));
+ if (none(valid0)) break;
+ }
+ }
+ return !valid0;
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (unlikely(dist[ID] > ray.tfar[k])) continue;
+ intersect(pre,ray,k,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (occluded(pre,ray,k,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+
+ template<int N, int K, bool filter>
+ struct SubGridIntersectorKPluecker
+ {
+ typedef SubGridQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersectorKPluecker<4,K,filter> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ Vec3fa vtx[16];
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ subgrid.gather(vtx,context->scene);
+ for (unsigned int i=0; i<4; i++)
+ {
+ const Vec3vf<K> p0 = vtx[i*4+0];
+ const Vec3vf<K> p1 = vtx[i*4+1];
+ const Vec3vf<K> p2 = vtx[i*4+2];
+ const Vec3vf<K> p3 = vtx[i*4+3];
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ pre.intersectK(valid_i,ray,p0,p1,p2,p3,g,subgrid,i,IntersectKEpilogM<4,K,filter>(ray,context,subgrid.geomID(),subgrid.primID(),i));
+ }
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ vbool<K> valid0 = valid_i;
+ Vec3fa vtx[16];
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ subgrid.gather(vtx,context->scene);
+ for (unsigned int i=0; i<4; i++)
+ {
+ const Vec3vf<K> p0 = vtx[i*4+0];
+ const Vec3vf<K> p1 = vtx[i*4+1];
+ const Vec3vf<K> p2 = vtx[i*4+2];
+ const Vec3vf<K> p3 = vtx[i*4+3];
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ //if (pre.intersectK(valid0,ray,p0,p1,p2,p3,g,subgrid,i,OccludedKEpilogM<4,K,filter>(valid0,ray,context,subgrid.geomID(),subgrid.primID(),i)))
+ if (pre.occludedK(valid0,ray,p0,p1,p2,p3,g,subgrid,i,OccludedKEpilogM<4,K,filter>(valid0,ray,context,subgrid.geomID(),subgrid.primID(),i)))
+
+ break;
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+ Vec3vf4 v0,v1,v2,v3; subgrid.gather(v0,v1,v2,v3,context->scene);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
+ intersect(valid,pre,ray,context,prim[j].subgrid(i));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+ vbool<K> valid0 = valid;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid0 & isecK.intersectK(&prim[j].qnode,i,tray,dist))) continue;
+ valid0 &= !occluded(valid0,pre,ray,context,prim[j].subgrid(i));
+ if (none(valid0)) break;
+ }
+ }
+ return !valid0;
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (unlikely(dist[ID] > ray.tfar[k])) continue;
+ intersect(pre,ray,k,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ assert(((size_t)1 << ID) & movemask(prim[i].qnode.validMask()));
+
+ if (occluded(pre,ray,k,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/subgrid_intersector_moeller.h b/thirdparty/embree/kernels/geometry/subgrid_intersector_moeller.h
new file mode 100644
index 0000000000..64937d34fe
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/subgrid_intersector_moeller.h
@@ -0,0 +1,382 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "subgrid.h"
+#include "quad_intersector_moeller.h"
+
+namespace embree
+{
+ namespace isa
+ {
+
+ /* ----------------------------- */
+ /* -- single ray intersectors -- */
+ /* ----------------------------- */
+
+ template<int M>
+ __forceinline void interpolateUV(MoellerTrumboreHitM<M,UVIdentity<M>> &hit,const GridMesh::Grid &g, const SubGrid& subgrid, const vint<M> &stepX, const vint<M> &stepY)
+ {
+ /* correct U,V interpolation across the entire grid */
+ const vint<M> sx((int)subgrid.x());
+ const vint<M> sy((int)subgrid.y());
+ const vint<M> sxM(sx + stepX);
+ const vint<M> syM(sy + stepY);
+ const float inv_resX = rcp((float)((int)g.resX-1));
+ const float inv_resY = rcp((float)((int)g.resY-1));
+ hit.U = (hit.U + (vfloat<M>)sxM * hit.absDen) * inv_resX;
+ hit.V = (hit.V + (vfloat<M>)syM * hit.absDen) * inv_resY;
+ }
+
+ template<int M, bool filter>
+ struct SubGridQuadMIntersector1MoellerTrumbore;
+
+ template<int M, bool filter>
+ struct SubGridQuadMIntersector1MoellerTrumbore
+ {
+ __forceinline SubGridQuadMIntersector1MoellerTrumbore() {}
+
+ __forceinline SubGridQuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
+
+ __forceinline void intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ UVIdentity<M> mapUV;
+ MoellerTrumboreHitM<M,UVIdentity<M>> hit(mapUV);
+ MoellerTrumboreIntersector1<M> intersector(ray,nullptr);
+ Intersect1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,v0,v1,v3,mapUV,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,v2,v3,v1,mapUV,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ UVIdentity<M> mapUV;
+ MoellerTrumboreHitM<M,UVIdentity<M>> hit(mapUV);
+ MoellerTrumboreIntersector1<M> intersector(ray,nullptr);
+ Occluded1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,v0,v1,v3,mapUV,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,v2,v3,v1,mapUV,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+ return false;
+ }
+ };
+
+#if defined (__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<bool filter>
+ struct SubGridQuadMIntersector1MoellerTrumbore<4,filter>
+ {
+ __forceinline SubGridQuadMIntersector1MoellerTrumbore() {}
+
+ __forceinline SubGridQuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid& subgrid, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ UVIdentity<8> mapUV;
+ MoellerTrumboreHitM<8,UVIdentity<8>> hit(mapUV);
+ MoellerTrumboreIntersector1<8> intersector(ray,nullptr);
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ if (unlikely(intersector.intersect(ray,vtx0,vtx1,vtx2,mapUV,hit)))
+ {
+ /* correct U,V interpolation across the entire grid */
+ const vfloat8 U = select(flags,hit.absDen - hit.V,hit.U);
+ const vfloat8 V = select(flags,hit.absDen - hit.U,hit.V);
+ hit.U = U;
+ hit.V = V;
+ hit.vNg *= select(flags,vfloat8(-1.0f),vfloat8(1.0f));
+ interpolateUV<8>(hit,g,subgrid,vint<8>(0,1,1,0,0,1,1,0),vint<8>(0,0,1,1,0,0,1,1));
+ if (unlikely(epilog(hit.valid,hit)))
+ return true;
+ }
+ return false;
+ }
+
+ __forceinline bool intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ return intersect(ray,v0,v1,v2,v3,g,subgrid,Intersect1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ return intersect(ray,v0,v1,v2,v3,g,subgrid,Occluded1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
+ }
+ };
+
+#endif
+
+ // ============================================================================================================================
+ // ============================================================================================================================
+ // ============================================================================================================================
+
+
+ /* ----------------------------- */
+ /* -- ray packet intersectors -- */
+ /* ----------------------------- */
+
+ template<int K>
+ __forceinline void interpolateUV(const vbool<K>& valid, MoellerTrumboreHitK<K,UVIdentity<K>> &hit,const GridMesh::Grid &g, const SubGrid& subgrid, const unsigned int i)
+ {
+ /* correct U,V interpolation across the entire grid */
+ const unsigned int sx = subgrid.x() + (unsigned int)(i % 2);
+ const unsigned int sy = subgrid.y() + (unsigned int)(i >>1);
+ const float inv_resX = rcp((float)(int)(g.resX-1));
+ const float inv_resY = rcp((float)(int)(g.resY-1));
+ hit.U = select(valid,(hit.U + vfloat<K>((float)sx) * hit.absDen) * inv_resX,hit.U);
+ hit.V = select(valid,(hit.V + vfloat<K>((float)sy) * hit.absDen) * inv_resY,hit.V);
+ }
+
+ template<int M, int K, bool filter>
+ struct SubGridQuadMIntersectorKMoellerTrumboreBase
+ {
+ __forceinline SubGridQuadMIntersectorKMoellerTrumboreBase(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersectK(const vbool<K>& valid,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const Vec3vf<K>& v3,
+ const GridMesh::Grid &g,
+ const SubGrid &subgrid,
+ const unsigned int i,
+ const Epilog& epilog) const
+ {
+ UVIdentity<K> mapUV;
+ MoellerTrumboreHitK<K,UVIdentity<K>> hit(mapUV);
+ MoellerTrumboreIntersectorK<M,K> intersector;
+
+ const vbool<K> valid0 = intersector.intersectK(valid,ray,v0,v1,v3,mapUV,hit);
+ if (any(valid0))
+ {
+ interpolateUV(valid0,hit,g,subgrid,i);
+ epilog(valid0,hit);
+ }
+ const vbool<K> valid1 = intersector.intersectK(valid,ray,v2,v3,v1,mapUV,hit);
+ if (any(valid1))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ interpolateUV(valid1,hit,g,subgrid,i);
+ epilog(valid1,hit);
+ }
+ return any(valid0|valid1);
+ }
+
+ template<typename Epilog>
+ __forceinline bool occludedK(const vbool<K>& valid,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const Vec3vf<K>& v3,
+ const GridMesh::Grid &g,
+ const SubGrid &subgrid,
+ const unsigned int i,
+ const Epilog& epilog) const
+ {
+ UVIdentity<K> mapUV;
+ MoellerTrumboreHitK<K,UVIdentity<K>> hit(mapUV);
+ MoellerTrumboreIntersectorK<M,K> intersector;
+
+ vbool<K> valid_final = valid;
+ const vbool<K> valid0 = intersector.intersectK(valid,ray,v0,v1,v3,mapUV,hit);
+ if (any(valid0))
+ {
+ interpolateUV(valid0,hit,g,subgrid,i);
+ epilog(valid0,hit);
+ valid_final &= !valid0;
+ }
+ if (none(valid_final)) return true;
+ const vbool<K> valid1 = intersector.intersectK(valid,ray,v2,v3,v1,mapUV,hit);
+ if (any(valid1))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ interpolateUV(valid1,hit,g,subgrid,i);
+ epilog(valid1,hit);
+ valid_final &= !valid1;
+ }
+ return none(valid_final);
+ }
+
+ static __forceinline bool intersect1(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ MoellerTrumboreHitM<M,UVIdentity<M>> &hit)
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ MoellerTrumboreIntersectorK<8,K> intersector;
+ UVIdentity<M> mapUV;
+ return intersector.intersectEdge(ray,k,v0,e1,e2,mapUV,hit);
+ }
+
+ };
+
+ template<int M, int K, bool filter>
+ struct SubGridQuadMIntersectorKMoellerTrumbore : public SubGridQuadMIntersectorKMoellerTrumboreBase<M,K,filter>
+ {
+ __forceinline SubGridQuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
+ : SubGridQuadMIntersectorKMoellerTrumboreBase<M,K,filter>(valid,ray) {}
+
+ __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ UVIdentity<M> mapUV;
+ MoellerTrumboreHitM<M,UVIdentity<M>> hit(mapUV);
+ Intersect1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
+ MoellerTrumboreIntersectorK<M,K> intersector;
+ /* intersect first triangle */
+ if (intersector.intersect(ray,k,v0,v1,v3,mapUV,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,k,v2,v3,v1,mapUV,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ UVIdentity<M> mapUV;
+ MoellerTrumboreHitM<M,UVIdentity<M>> hit(mapUV);
+ Occluded1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
+ MoellerTrumboreIntersectorK<M,K> intersector;
+ /* intersect first triangle */
+ if (intersector.intersect(ray,k,v0,v1,v3,mapUV,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit)) return true;
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,k,v2,v3,v1,mapUV,hit))
+ {
+ hit.U = hit.absDen - hit.U;
+ hit.V = hit.absDen - hit.V;
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit)) return true;
+ }
+ return false;
+ }
+ };
+
+
+#if defined (__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<int K, bool filter>
+ struct SubGridQuadMIntersectorKMoellerTrumbore<4,K,filter> : public SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>
+ {
+ __forceinline SubGridQuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray)
+ : SubGridQuadMIntersectorKMoellerTrumboreBase<4,K,filter>(valid,ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect1(RayK<K>& ray, size_t k,const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid &subgrid, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+
+ UVIdentity<8> mapUV;
+ MoellerTrumboreHitM<8,UVIdentity<8>> hit(mapUV);
+ if (SubGridQuadMIntersectorKMoellerTrumboreBase<8,K,filter>::intersect1(ray,k,vtx0,vtx1,vtx2,hit))
+ {
+ const vfloat8 U = select(flags,hit.absDen - hit.V,hit.U);
+ const vfloat8 V = select(flags,hit.absDen - hit.U,hit.V);
+ hit.U = U;
+ hit.V = V;
+ hit.vNg *= select(flags,vfloat8(-1.0f),vfloat8(1.0f));
+ interpolateUV<8>(hit,g,subgrid,vint<8>(0,1,1,0,0,1,1,0),vint<8>(0,0,1,1,0,0,1,1));
+ if (unlikely(epilog(hit.valid,hit)))
+ return true;
+
+ }
+ return false;
+ }
+
+ __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Intersect1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID()));
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Occluded1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID()));
+ }
+ };
+
+#endif
+
+
+
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/subgrid_intersector_pluecker.h b/thirdparty/embree/kernels/geometry/subgrid_intersector_pluecker.h
new file mode 100644
index 0000000000..5ded56e1f7
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/subgrid_intersector_pluecker.h
@@ -0,0 +1,367 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "subgrid.h"
+#include "quad_intersector_moeller.h"
+#include "quad_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+
+ template<int M>
+ __forceinline void interpolateUV(PlueckerHitM<M,UVIdentity<M>> &hit,const GridMesh::Grid &g, const SubGrid& subgrid, const vint<M> &stepX, const vint<M> &stepY)
+ {
+ /* correct U,V interpolation across the entire grid */
+ const vint<M> sx((int)subgrid.x());
+ const vint<M> sy((int)subgrid.y());
+ const vint<M> sxM(sx + stepX);
+ const vint<M> syM(sy + stepY);
+ const float inv_resX = rcp((float)((int)g.resX-1));
+ const float inv_resY = rcp((float)((int)g.resY-1));
+ hit.U = (hit.U + vfloat<M>(sxM) * hit.UVW) * inv_resX;
+ hit.V = (hit.V + vfloat<M>(syM) * hit.UVW) * inv_resY;
+ }
+
+ template<int M, bool filter>
+ struct SubGridQuadMIntersector1Pluecker;
+
+ template<int M, bool filter>
+ struct SubGridQuadMIntersector1Pluecker
+ {
+ __forceinline SubGridQuadMIntersector1Pluecker() {}
+
+ __forceinline SubGridQuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
+
+ __forceinline void intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ UVIdentity<M> mapUV;
+ PlueckerHitM<M,UVIdentity<M>> hit(mapUV);
+ PlueckerIntersector1<M> intersector(ray,nullptr);
+
+ Intersect1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,v0,v1,v3,mapUV,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,v2,v3,v1,mapUV,hit))
+ {
+ hit.U = hit.UVW - hit.U;
+ hit.V = hit.UVW - hit.V;
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ UVIdentity<M> mapUV;
+ PlueckerHitM<M,UVIdentity<M>> hit(mapUV);
+ PlueckerIntersector1<M> intersector(ray,nullptr);
+ Occluded1EpilogMU<M,filter> epilog(ray,context,subgrid.geomID(),subgrid.primID());
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,v0,v1,v3,mapUV,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,v2,v3,v1,mapUV,hit))
+ {
+ hit.U = hit.UVW - hit.U;
+ hit.V = hit.UVW - hit.V;
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit))
+ return true;
+ }
+ return false;
+ }
+ };
+
+#if defined (__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<bool filter>
+ struct SubGridQuadMIntersector1Pluecker<4,filter>
+ {
+ __forceinline SubGridQuadMIntersector1Pluecker() {}
+
+ __forceinline SubGridQuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid& subgrid, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+
+ UVIdentity<8> mapUV;
+ PlueckerHitM<8,UVIdentity<8>> hit(mapUV);
+ PlueckerIntersector1<8> intersector(ray,nullptr);
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ if (unlikely(intersector.intersect(ray,vtx0,vtx1,vtx2,mapUV,hit)))
+ {
+ /* correct U,V interpolation across the entire grid */
+ const vfloat8 U = select(flags,hit.UVW - hit.V,hit.U);
+ const vfloat8 V = select(flags,hit.UVW - hit.U,hit.V);
+ hit.U = U;
+ hit.V = V;
+ hit.vNg *= select(flags,vfloat8(-1.0f),vfloat8(1.0f));
+ interpolateUV<8>(hit,g,subgrid,vint<8>(0,1,1,0,0,1,1,0),vint<8>(0,0,1,1,0,0,1,1));
+ if (unlikely(epilog(hit.valid,hit)))
+ return true;
+ }
+ return false;
+ }
+
+ __forceinline bool intersect(RayHit& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ return intersect(ray,v0,v1,v2,v3,g,subgrid,Intersect1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
+ }
+
+ __forceinline bool occluded(Ray& ray, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid& subgrid) const
+ {
+ return intersect(ray,v0,v1,v2,v3,g,subgrid,Occluded1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID()));
+ }
+ };
+
+#endif
+
+
+ /* ----------------------------- */
+ /* -- ray packet intersectors -- */
+ /* ----------------------------- */
+
+ template<int K>
+ __forceinline void interpolateUV(const vbool<K>& valid, PlueckerHitK<K,UVIdentity<K>> &hit,const GridMesh::Grid &g, const SubGrid& subgrid, const unsigned int i)
+ {
+ /* correct U,V interpolation across the entire grid */
+ const unsigned int sx = subgrid.x() + (unsigned int)(i % 2);
+ const unsigned int sy = subgrid.y() + (unsigned int)(i >>1);
+ const float inv_resX = rcp((float)(int)(g.resX-1));
+ const float inv_resY = rcp((float)(int)(g.resY-1));
+ hit.U = select(valid,(hit.U + vfloat<K>((float)sx) * hit.UVW) * inv_resX,hit.U);
+ hit.V = select(valid,(hit.V + vfloat<K>((float)sy) * hit.UVW) * inv_resY,hit.V);
+ }
+
+ template<int M, int K, bool filter>
+ struct SubGridQuadMIntersectorKPlueckerBase
+ {
+ __forceinline SubGridQuadMIntersectorKPlueckerBase(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersectK(const vbool<K>& valid,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const Vec3vf<K>& v3,
+ const GridMesh::Grid &g,
+ const SubGrid &subgrid,
+ const unsigned int i,
+ const Epilog& epilog) const
+ {
+ UVIdentity<K> mapUV;
+ PlueckerHitK<K,UVIdentity<K>> hit(mapUV);
+ PlueckerIntersectorK<M,K> intersector;
+
+ const vbool<K> valid0 = intersector.intersectK(valid,ray,v0,v1,v3,mapUV,hit);
+ if (any(valid0))
+ {
+ interpolateUV(valid0,hit,g,subgrid,i);
+ epilog(valid0,hit);
+ }
+ const vbool<K> valid1 = intersector.intersectK(valid,ray,v2,v3,v1,mapUV,hit);
+ if (any(valid1))
+ {
+ hit.U = hit.UVW - hit.U;
+ hit.V = hit.UVW - hit.V;
+ interpolateUV(valid1,hit,g,subgrid,i);
+ epilog(valid1,hit);
+ }
+ return any(valid0|valid1);
+ }
+
+ template<typename Epilog>
+ __forceinline bool occludedK(const vbool<K>& valid,
+ RayK<K>& ray,
+ const Vec3vf<K>& v0,
+ const Vec3vf<K>& v1,
+ const Vec3vf<K>& v2,
+ const Vec3vf<K>& v3,
+ const GridMesh::Grid &g,
+ const SubGrid &subgrid,
+ const unsigned int i,
+ const Epilog& epilog) const
+ {
+ UVIdentity<K> mapUV;
+ PlueckerHitK<K,UVIdentity<K>> hit(mapUV);
+ PlueckerIntersectorK<M,K> intersector;
+
+ vbool<K> valid_final = valid;
+ const vbool<K> valid0 = intersector.intersectK(valid,ray,v0,v1,v3,mapUV,hit);
+ if (any(valid0))
+ {
+ interpolateUV(valid0,hit,g,subgrid,i);
+ epilog(valid0,hit);
+ valid_final &= !valid0;
+ }
+ if (none(valid_final)) return true;
+ const vbool<K> valid1 = intersector.intersectK(valid,ray,v2,v3,v1,mapUV,hit);
+ if (any(valid1))
+ {
+ hit.U = hit.UVW - hit.U;
+ hit.V = hit.UVW - hit.V;
+ interpolateUV(valid1,hit,g,subgrid,i);
+ epilog(valid1,hit);
+ valid_final &= !valid1;
+ }
+ return none(valid_final);
+ }
+
+
+ };
+
+
+
+
+ template<int M, int K, bool filter>
+ struct SubGridQuadMIntersectorKPluecker : public SubGridQuadMIntersectorKPlueckerBase<M,K,filter>
+ {
+ __forceinline SubGridQuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
+ : SubGridQuadMIntersectorKPlueckerBase<M,K,filter>(valid,ray) {}
+
+ __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ UVIdentity<M> mapUV;
+ PlueckerHitM<M,UVIdentity<M>> hit(mapUV);
+ Intersect1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
+ PlueckerIntersectorK<M,K> intersector;
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,k,v0,v1,v3,mapUV,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,k,v2,v3,v1,mapUV,hit))
+ {
+ hit.U = hit.UVW - hit.U;
+ hit.V = hit.UVW - hit.V;
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ epilog(hit.valid,hit);
+ }
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ UVIdentity<M> mapUV;
+ PlueckerHitM<M,UVIdentity<M>> hit(mapUV);
+ Occluded1KEpilogMU<M,K,filter> epilog(ray,k,context,subgrid.geomID(),subgrid.primID());
+ PlueckerIntersectorK<M,K> intersector;
+
+ /* intersect first triangle */
+ if (intersector.intersect(ray,k,v0,v1,v3,mapUV,hit))
+ {
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit)) return true;
+ }
+
+ /* intersect second triangle */
+ if (intersector.intersect(ray,k,v2,v3,v1,mapUV,hit))
+ {
+ hit.U = hit.UVW - hit.U;
+ hit.V = hit.UVW - hit.V;
+ interpolateUV<M>(hit,g,subgrid,vint<M>(0,1,1,0),vint<M>(0,0,1,1));
+ if (epilog(hit.valid,hit)) return true;
+ }
+ return false;
+ }
+ };
+
+
+#if defined (__AVX__)
+
+ /*! Intersects 4 quads with 1 ray using AVX */
+ template<int K, bool filter>
+ struct SubGridQuadMIntersectorKPluecker<4,K,filter> : public SubGridQuadMIntersectorKPlueckerBase<4,K,filter>
+ {
+ __forceinline SubGridQuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
+ : SubGridQuadMIntersectorKPlueckerBase<4,K,filter>(valid,ray) {}
+
+ template<typename Epilog>
+ __forceinline bool intersect1(RayK<K>& ray, size_t k,const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
+ const GridMesh::Grid &g, const SubGrid &subgrid, const Epilog& epilog) const
+ {
+ const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
+#if !defined(EMBREE_BACKFACE_CULLING)
+ const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
+#else
+ const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
+ const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
+#endif
+ UVIdentity<8> mapUV;
+ PlueckerHitM<8,UVIdentity<8>> hit(mapUV);
+ PlueckerIntersectorK<8,K> intersector;
+ const vbool8 flags(0,0,0,0,1,1,1,1);
+ if (unlikely(intersector.intersect(ray,k,vtx0,vtx1,vtx2,mapUV,hit)))
+ {
+ /* correct U,V interpolation across the entire grid */
+ const vfloat8 U = select(flags,hit.UVW - hit.V,hit.U);
+ const vfloat8 V = select(flags,hit.UVW - hit.U,hit.V);
+ hit.U = U;
+ hit.V = V;
+ hit.vNg *= select(flags,vfloat8(-1.0f),vfloat8(1.0f));
+ interpolateUV<8>(hit,g,subgrid,vint<8>(0,1,1,0,0,1,1,0),vint<8>(0,0,1,1,0,0,1,1));
+ if (unlikely(epilog(hit.valid,hit)))
+ return true;
+ }
+ return false;
+ }
+
+ __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Intersect1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID()));
+ }
+
+ __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context,
+ const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const
+ {
+ return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Occluded1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID()));
+ }
+ };
+#endif
+
+
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/subgrid_mb_intersector.h b/thirdparty/embree/kernels/geometry/subgrid_mb_intersector.h
new file mode 100644
index 0000000000..473d656e24
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/subgrid_mb_intersector.h
@@ -0,0 +1,236 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "subgrid_intersector.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int N, bool filter>
+ struct SubGridMBIntersector1Pluecker
+ {
+ typedef SubGridMBQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersector1Pluecker<4,filter> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ float ftime;
+ const int itime = mesh->timeSegment(ray.time(), ftime);
+ Vec3vf4 v0,v1,v2,v3; subgrid.gatherMB(v0,v1,v2,v3,context->scene,itime,ftime);
+ pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ float ftime;
+ const int itime = mesh->timeSegment(ray.time(), ftime);
+
+ Vec3vf4 v0,v1,v2,v3; subgrid.gatherMB(v0,v1,v2,v3,context->scene,itime,ftime);
+ return pre.occluded(ray,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const SubGrid& subgrid)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, subgrid);
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ const float time = prim[i].adjustTime(ray.time());
+
+ assert(time <= 1.0f);
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,time,dist);
+#if defined(__AVX__)
+ STAT3(normal.trav_hit_boxes[popcnt(mask)],1,1,1);
+#endif
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ if (unlikely(dist[ID] > ray.tfar)) continue;
+ intersect(pre,ray,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+ for (size_t i=0;i<num;i++)
+ {
+ const float time = prim[i].adjustTime(ray.time());
+ assert(time <= 1.0f);
+ vfloat<N> dist;
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,time,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ if (occluded(pre,ray,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node)
+ {
+ assert(false && "not implemented");
+ return false;
+ }
+ };
+
+
+ template<int N, int K, bool filter>
+ struct SubGridMBIntersectorKPluecker
+ {
+ typedef SubGridMBQBVHN<N> Primitive;
+ typedef SubGridQuadMIntersectorKPluecker<4,K,filter> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ size_t m_valid = movemask(valid_i);
+ while(m_valid)
+ {
+ size_t ID = bscf(m_valid);
+ intersect(pre,ray,ID,context,subgrid);
+ }
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid)
+ {
+ vbool<K> valid0 = valid_i;
+ size_t m_valid = movemask(valid_i);
+ while(m_valid)
+ {
+ size_t ID = bscf(m_valid);
+ if (occluded(pre,ray,ID,context,subgrid))
+ clear(valid0,ID);
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ vfloat<K> ftime;
+ const vint<K> itime = mesh->timeSegment<K>(ray.time(), ftime);
+ Vec3vf4 v0,v1,v2,v3; subgrid.gatherMB(v0,v1,v2,v3,context->scene,itime[k],ftime[k]);
+ pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID());
+ const GridMesh::Grid &g = mesh->grid(subgrid.primID());
+
+ vfloat<K> ftime;
+ const vint<K> itime = mesh->timeSegment<K>(ray.time(), ftime);
+ Vec3vf4 v0,v1,v2,v3; subgrid.gatherMB(v0,v1,v2,v3,context->scene,itime[k],ftime[k]);
+ return pre.occluded1(ray,k,context,v0,v1,v2,v3,g,subgrid);
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ const vfloat<K> time = prim[j].template adjustTime<K>(ray.time());
+
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid & isecK.intersectK(&prim[j].qnode,i,tray,time,dist))) continue;
+ intersect(valid,pre,ray,context,prim[j].subgrid(i));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK;
+
+ vbool<K> valid0 = valid;
+ for (size_t j=0;j<num;j++)
+ {
+ size_t m_valid = movemask(prim[j].qnode.validMask());
+ const vfloat<K> time = prim[j].template adjustTime<K>(ray.time());
+ vfloat<K> dist;
+ while(m_valid)
+ {
+ const size_t i = bscf(m_valid);
+ if (none(valid0 & isecK.intersectK(&prim[j].qnode,i,tray,time,dist))) continue;
+ valid0 &= !occluded(valid0,pre,ray,context,prim[j].subgrid(i));
+ if (none(valid0)) break;
+ }
+ }
+ return !valid0;
+ }
+
+ template<bool robust>
+ static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ const float time = prim[i].adjustTime(ray.time()[k]);
+ assert(time <= 1.0f);
+
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,time,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ if (unlikely(dist[ID] > ray.tfar[k])) continue;
+ intersect(pre,ray,k,context,prim[i].subgrid(ID));
+ }
+ }
+ }
+
+ template<bool robust>
+ static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node)
+ {
+ BVHNQuantizedBaseNodeIntersector1<N,robust> isec1;
+
+ for (size_t i=0;i<num;i++)
+ {
+ vfloat<N> dist;
+ const float time = prim[i].adjustTime(ray.time()[k]);
+ assert(time <= 1.0f);
+
+ size_t mask = isec1.intersect(&prim[i].qnode,tray,time,dist);
+ while(mask != 0)
+ {
+ const size_t ID = bscf(mask);
+ if (occluded(pre,ray,k,context,prim[i].subgrid(ID)))
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/triangle.h b/thirdparty/embree/kernels/geometry/triangle.h
new file mode 100644
index 0000000000..24b758ae48
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/triangle.h
@@ -0,0 +1,162 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ /* Precalculated representation for M triangles. Stores for each
+ triangle a base vertex, two edges, and the geometry normal to
+ speed up intersection calculations */
+ template<int M>
+ struct TriangleM
+ {
+ public:
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored triangles */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline TriangleM() {}
+
+ /* Construction from vertices and IDs */
+ __forceinline TriangleM(const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const vuint<M>& geomIDs, const vuint<M>& primIDs)
+ : v0(v0), e1(v0-v1), e2(v2-v0), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ /* Returns a mask that tells which triangles are valid */
+ __forceinline vbool<M> valid() const { return geomIDs != vuint<M>(-1); }
+
+ /* Returns true if the specified triangle is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return geomIDs[i] != -1; }
+
+ /* Returns the number of stored triangles */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M>& geomID() { return geomIDs; }
+ __forceinline const vuint<M>& geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M>& primID() { return primIDs; }
+ __forceinline const vuint<M>& primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the triangle */
+ __forceinline BBox3fa bounds() const
+ {
+ Vec3vf<M> p0 = v0;
+ Vec3vf<M> p1 = v0-e1;
+ Vec3vf<M> p2 = v0+e2;
+ Vec3vf<M> lower = min(p0,p1,p2);
+ Vec3vf<M> upper = max(p0,p1,p2);
+ vbool<M> mask = valid();
+ lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
+ lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
+ lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
+ upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
+ upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
+ upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
+ return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
+ Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
+ }
+
+ /* Non temporal store */
+ __forceinline static void store_nt(TriangleM* dst, const TriangleM& src)
+ {
+ vfloat<M>::store_nt(&dst->v0.x,src.v0.x);
+ vfloat<M>::store_nt(&dst->v0.y,src.v0.y);
+ vfloat<M>::store_nt(&dst->v0.z,src.v0.z);
+ vfloat<M>::store_nt(&dst->e1.x,src.e1.x);
+ vfloat<M>::store_nt(&dst->e1.y,src.e1.y);
+ vfloat<M>::store_nt(&dst->e1.z,src.e1.z);
+ vfloat<M>::store_nt(&dst->e2.x,src.e2.x);
+ vfloat<M>::store_nt(&dst->e2.y,src.e2.y);
+ vfloat<M>::store_nt(&dst->e2.z,src.e2.z);
+ vuint<M>::store_nt(&dst->geomIDs,src.geomIDs);
+ vuint<M>::store_nt(&dst->primIDs,src.primIDs);
+ }
+
+ /* Fill triangle from triangle list */
+ __forceinline void fill(const PrimRef* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
+
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRef& prim = prims[begin];
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const TriangleMesh* __restrict__ const mesh = scene->get<TriangleMesh>(geomID);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ vgeomID [i] = geomID;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+ TriangleM::store_nt(this,TriangleM(v0,v1,v2,vgeomID,vprimID));
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(TriangleMesh* mesh)
+ {
+ BBox3fa bounds = empty;
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (unlikely(geomID(i) == -1)) break;
+ const unsigned geomId = geomID(i);
+ const unsigned primId = primID(i);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primId);
+ const Vec3fa p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa p2 = mesh->vertex(tri.v[2]);
+ bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2)));
+ vgeomID [i] = geomId;
+ vprimID [i] = primId;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+ TriangleM::store_nt(this,TriangleM(v0,v1,v2,vgeomID,vprimID));
+ return bounds;
+ }
+
+ public:
+ Vec3vf<M> v0; // base vertex of the triangles
+ Vec3vf<M> e1; // 1st edge of the triangles (v0-v1)
+ Vec3vf<M> e2; // 2nd edge of the triangles (v2-v0)
+ private:
+ vuint<M> geomIDs; // geometry IDs
+ vuint<M> primIDs; // primitive IDs
+ };
+
+ template<int M>
+ typename TriangleM<M>::Type TriangleM<M>::type;
+
+ typedef TriangleM<4> Triangle4;
+}
diff --git a/thirdparty/embree/kernels/geometry/triangle_intersector.h b/thirdparty/embree/kernels/geometry/triangle_intersector.h
new file mode 100644
index 0000000000..2cdff78ec8
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/triangle_intersector.h
@@ -0,0 +1,96 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "triangle_intersector_moeller.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M triangles with 1 ray */
+ template<int M, bool filter>
+ struct TriangleMIntersector1Moeller
+ {
+ typedef TriangleM<M> Primitive;
+ typedef MoellerTrumboreIntersector1<M> Precalculations;
+
+ /*! Intersect a ray with the M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersectEdge(ray,tri.v0,tri.e1,tri.e2,UVIdentity<M>(),Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersectEdge(ray,tri.v0,tri.e1,tri.e2,UVIdentity<M>(),Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+
+ };
+
+ /*! Intersects M triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct TriangleMIntersectorKMoeller
+ {
+ typedef TriangleM<M> Primitive;
+ typedef MoellerTrumboreIntersectorK<M,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ STAT_USER(0,TriangleM<M>::max_size());
+ for (size_t i=0; i<TriangleM<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> e1 = broadcast<vfloat<K>>(tri.e1,i);
+ const Vec3vf<K> e2 = broadcast<vfloat<K>>(tri.e2,i);
+ pre.intersectEdgeK(valid_i,ray,p0,e1,e2,UVIdentity<K>(),IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<TriangleM<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> p0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> e1 = broadcast<vfloat<K>>(tri.e1,i);
+ const Vec3vf<K> e2 = broadcast<vfloat<K>>(tri.e2,i);
+ pre.intersectEdgeK(valid0,ray,p0,e1,e2,UVIdentity<K>(),OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersectEdge(ray,k,tri.v0,tri.e1,tri.e2,UVIdentity<M>(),Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleM<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersectEdge(ray,k,tri.v0,tri.e1,tri.e2,UVIdentity<M>(),Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/triangle_intersector_moeller.h b/thirdparty/embree/kernels/geometry/triangle_intersector_moeller.h
new file mode 100644
index 0000000000..0a42d8f08b
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/triangle_intersector_moeller.h
@@ -0,0 +1,525 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "intersector_epilog.h"
+
+/*! This intersector implements a modified version of the Moeller
+ * Trumbore intersector from the paper "Fast, Minimum Storage
+ * Ray-Triangle Intersection". In contrast to the paper we
+ * precalculate some factors and factor the calculations differently
+ * to allow precalculating the cross product e1 x e2. The resulting
+ * algorithm is similar to the fastest one of the paper "Optimizing
+ * Ray-Triangle Intersection via Automated Search". */
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, typename UVMapper>
+ struct MoellerTrumboreHitM
+ {
+ __forceinline MoellerTrumboreHitM(const UVMapper& mapUV) : mapUV(mapUV) {}
+
+ __forceinline MoellerTrumboreHitM(const vbool<M>& valid, const vfloat<M>& U, const vfloat<M>& V, const vfloat<M>& T, const vfloat<M>& absDen, const Vec3vf<M>& Ng, const UVMapper& mapUV)
+ : U(U), V(V), T(T), absDen(absDen), mapUV(mapUV), valid(valid), vNg(Ng) {}
+
+ __forceinline void finalize()
+ {
+ const vfloat<M> rcpAbsDen = rcp(absDen);
+ vt = T * rcpAbsDen;
+ vu = U * rcpAbsDen;
+ vv = V * rcpAbsDen;
+ mapUV(vu,vv,vNg);
+ }
+
+ __forceinline Vec2vf<M> uv() const { return Vec2vf<M>(vu,vv); }
+ __forceinline vfloat<M> t () const { return vt; }
+ __forceinline Vec3vf<M> Ng() const { return vNg; }
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ public:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> T;
+ vfloat<M> absDen;
+ UVMapper mapUV;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M, bool early_out = true>
+ struct MoellerTrumboreIntersector1
+ {
+ __forceinline MoellerTrumboreIntersector1() {}
+
+ __forceinline MoellerTrumboreIntersector1(const Ray& ray, const void* ptr) {}
+
+ template<typename UVMapper>
+ __forceinline bool intersect(const vbool<M>& valid0,
+ Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Vec3vf<M>& tri_Ng,
+ const UVMapper& mapUV,
+ MoellerTrumboreHitM<M,UVMapper>& hit) const
+ {
+ /* calculate denominator */
+ vbool<M> valid = valid0;
+ const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org);
+ const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir);
+ const Vec3vf<M> C = Vec3vf<M>(tri_v0) - O;
+ const Vec3vf<M> R = cross(C,D);
+ const vfloat<M> den = dot(Vec3vf<M>(tri_Ng),D);
+
+ const vfloat<M> absDen = abs(den);
+ const vfloat<M> sgnDen = signmsk(den);
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(R,Vec3vf<M>(tri_e2)) ^ sgnDen;
+ const vfloat<M> V = dot(R,Vec3vf<M>(tri_e1)) ^ sgnDen;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= (den < vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#else
+ valid &= (den != vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#endif
+ if (likely(early_out && none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen;
+ valid &= (absDen*vfloat<M>(ray.tnear()) < T) & (T <= absDen*vfloat<M>(ray.tfar));
+ if (likely(early_out && none(valid))) return false;
+
+ /* update hit information */
+ new (&hit) MoellerTrumboreHitM<M,UVMapper>(valid,U,V,T,absDen,tri_Ng,mapUV);
+
+ return true;
+ }
+
+ template<typename UVMapper>
+ __forceinline bool intersectEdge(const vbool<M>& valid,
+ Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const UVMapper& mapUV,
+ MoellerTrumboreHitM<M,UVMapper>& hit) const
+ {
+ const Vec3<vfloat<M>> tri_Ng = cross(tri_e2,tri_e1);
+ return intersect(valid,ray,tri_v0,tri_e1,tri_e2,tri_Ng,mapUV,hit);
+ }
+
+ template<typename UVMapper>
+ __forceinline bool intersectEdge(Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const UVMapper& mapUV,
+ MoellerTrumboreHitM<M,UVMapper>& hit) const
+ {
+ vbool<M> valid = true;
+ const Vec3<vfloat<M>> tri_Ng = cross(tri_e2,tri_e1);
+ return intersect(valid,ray,tri_v0,tri_e1,tri_e2,tri_Ng,mapUV,hit);
+ }
+
+ template<typename UVMapper>
+ __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const UVMapper& mapUV,
+ MoellerTrumboreHitM<M,UVMapper>& hit) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,v0,e1,e2,mapUV,hit);
+ }
+
+ template<typename UVMapper>
+ __forceinline bool intersect(const vbool<M>& valid,
+ Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const UVMapper& mapUV,
+ MoellerTrumboreHitM<M,UVMapper>& hit) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(valid,ray,v0,e1,e2,mapUV,hit);
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersectEdge(Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& e1,
+ const Vec3vf<M>& e2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitM<M,UVMapper> hit(mapUV);
+ if (likely(intersectEdge(ray,v0,e1,e2,mapUV,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitM<M,UVMapper> hit(mapUV);
+ if (likely(intersect(ray,v0,v1,v2,mapUV,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ auto mapUV = UVIdentity<M>();
+ MoellerTrumboreHitM<M,UVIdentity<M>> hit(mapUV);
+ if (likely(intersect(ray,v0,v1,v2,mapUV,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersect(const vbool<M>& valid,
+ Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitM<M,UVMapper> hit(mapUV);
+ if (likely(intersect(valid,ray,v0,v1,v2,mapUV,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+ };
+
+ template<int K, typename UVMapper>
+ struct MoellerTrumboreHitK
+ {
+ __forceinline MoellerTrumboreHitK(const UVMapper& mapUV) : mapUV(mapUV) {}
+ __forceinline MoellerTrumboreHitK(const vfloat<K>& U, const vfloat<K>& V, const vfloat<K>& T, const vfloat<K>& absDen, const Vec3vf<K>& Ng, const UVMapper& mapUV)
+ : U(U), V(V), T(T), absDen(absDen), Ng(Ng), mapUV(mapUV) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vfloat<K> rcpAbsDen = rcp(absDen);
+ const vfloat<K> t = T * rcpAbsDen;
+ vfloat<K> u = U * rcpAbsDen;
+ vfloat<K> v = V * rcpAbsDen;
+ Vec3vf<K> vNg = Ng;
+ mapUV(u,v,vNg);
+ return std::make_tuple(u,v,t,vNg);
+ }
+
+ vfloat<K> U;
+ vfloat<K> V;
+ const vfloat<K> T;
+ const vfloat<K> absDen;
+ const Vec3vf<K> Ng;
+ const UVMapper& mapUV;
+ };
+
+ template<int M, int K>
+ struct MoellerTrumboreIntersectorK
+ {
+ __forceinline MoellerTrumboreIntersectorK() {}
+ __forceinline MoellerTrumboreIntersectorK(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename UVMapper>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ //RayK<K>& ray,
+ const Vec3vf<K>& ray_org,
+ const Vec3vf<K>& ray_dir,
+ const vfloat<K>& ray_tnear,
+ const vfloat<K>& ray_tfar,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const Vec3vf<K>& tri_Ng,
+ const UVMapper& mapUV,
+ MoellerTrumboreHitK<K,UVMapper> &hit) const
+ {
+ /* calculate denominator */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> C = tri_v0 - ray_org;
+ const Vec3vf<K> R = cross(C,ray_dir);
+ const vfloat<K> den = dot(tri_Ng,ray_dir);
+ const vfloat<K> absDen = abs(den);
+ const vfloat<K> sgnDen = signmsk(den);
+
+ /* test against edge p2 p0 */
+ const vfloat<K> U = dot(tri_e2,R) ^ sgnDen;
+ valid &= U >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p0 p1 */
+ const vfloat<K> V = dot(tri_e1,R) ^ sgnDen;
+ valid &= V >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p1 p2 */
+ const vfloat<K> W = absDen-U-V;
+ valid &= W >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<K> T = dot(tri_Ng,C) ^ sgnDen;
+ valid &= (absDen*ray_tnear < T) & (T <= absDen*ray_tfar);
+ if (unlikely(none(valid))) return false;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= den < vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#else
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* calculate hit information */
+ new (&hit) MoellerTrumboreHitK<K,UVMapper>(U,V,T,absDen,tri_Ng,mapUV);
+ return valid;
+ }
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename UVMapper>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const UVMapper& mapUV,
+ MoellerTrumboreHitK<K,UVMapper> &hit) const
+ {
+ const Vec3vf<K> e1 = tri_v0-tri_v1;
+ const Vec3vf<K> e2 = tri_v2-tri_v0;
+ const Vec3vf<K> Ng = cross(e2,e1);
+ return intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,e1,e2,Ng,mapUV,hit);
+ }
+
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename UVMapper, typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitK<K,UVIdentity<K>> hit(mapUV);
+ const Vec3vf<K> e1 = tri_v0-tri_v1;
+ const Vec3vf<K> e2 = tri_v2-tri_v0;
+ const Vec3vf<K> Ng = cross(e2,e1);
+ const vbool<K> valid = intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,e1,e2,Ng,mapUV,hit);
+ return epilog(valid,hit);
+ }
+
+
+
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const Epilog& epilog) const
+ {
+ UVIdentity<K> mapUV;
+ MoellerTrumboreHitK<K,UVIdentity<K>> hit(mapUV);
+ const Vec3vf<K> e1 = tri_v0-tri_v1;
+ const Vec3vf<K> e2 = tri_v2-tri_v0;
+ const Vec3vf<K> Ng = cross(e2,e1);
+ const vbool<K> valid = intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,e1,e2,Ng,mapUV,hit);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename UVMapper, typename Epilog>
+ __forceinline vbool<K> intersectEdgeK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitK<K,UVIdentity<K>> hit(mapUV);
+ const Vec3vf<K> tri_Ng = cross(tri_e2,tri_e1);
+ const vbool<K> valid = intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,tri_e1,tri_e2,tri_Ng,mapUV,hit);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersect k'th ray from ray packet of size K with M triangles. */
+ template<typename UVMapper>
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const UVMapper& mapUV,
+ MoellerTrumboreHitM<M,UVMapper>& hit) const
+ {
+ /* calculate denominator */
+ typedef Vec3vf<M> Vec3vfM;
+ const Vec3vf<M> tri_Ng = cross(tri_e2,tri_e1);
+
+ const Vec3vfM O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vfM D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vfM C = Vec3vfM(tri_v0) - O;
+ const Vec3vfM R = cross(C,D);
+ const vfloat<M> den = dot(Vec3vfM(tri_Ng),D);
+ const vfloat<M> absDen = abs(den);
+ const vfloat<M> sgnDen = signmsk(den);
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(Vec3vf<M>(tri_e2),R) ^ sgnDen;
+ const vfloat<M> V = dot(Vec3vf<M>(tri_e1),R) ^ sgnDen;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = (den < vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#else
+ vbool<M> valid = (den != vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#endif
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen;
+ valid &= (absDen*vfloat<M>(ray.tnear()[k]) < T) & (T <= absDen*vfloat<M>(ray.tfar[k]));
+ if (likely(none(valid))) return false;
+
+ /* calculate hit information */
+ new (&hit) MoellerTrumboreHitM<M,UVMapper>(valid,U,V,T,absDen,tri_Ng,mapUV);
+ return true;
+ }
+
+ template<typename UVMapper>
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const UVMapper& mapUV,
+ MoellerTrumboreHitM<M,UVMapper>& hit) const
+ {
+ if (likely(intersect(ray,k,tri_v0,tri_e1,tri_e2,mapUV,hit)))
+ {
+ hit.valid &= time_range.lower <= vfloat<M>(ray.time[k]);
+ hit.valid &= vfloat<M>(ray.time[k]) < time_range.upper;
+ return any(hit.valid);
+ }
+ return false;
+ }
+
+ template<typename UVMapper>
+ __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const UVMapper& mapUV,
+ MoellerTrumboreHitM<M,UVMapper>& hit) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,k,v0,e1,e2,mapUV,hit);
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitM<M,UVMapper> hit(mapUV);
+ if (likely(intersectEdge(ray,k,tri_v0,tri_e1,tri_e2,mapUV,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ MoellerTrumboreHitM<M,UVMapper> hit(mapUV);
+ if (likely(intersectEdge(ray,k,time_range,tri_v0,tri_e1,tri_e2,mapUV,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,k,v0,e1,e2,mapUV,epilog);
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ return intersect(ray,k,v0,v1,v2,UVIdentity<M>(),epilog);
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,k,time_range,v0,e1,e2,mapUV,epilog);
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/triangle_intersector_pluecker.h b/thirdparty/embree/kernels/geometry/triangle_intersector_pluecker.h
new file mode 100644
index 0000000000..8fbefcea88
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/triangle_intersector_pluecker.h
@@ -0,0 +1,407 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "trianglev.h"
+#include "trianglev_mb.h"
+#include "intersector_epilog.h"
+
+/*! Modified Pluecker ray/triangle intersector. The test first shifts
+ * the ray origin into the origin of the coordinate system and then
+ * uses Pluecker coordinates for the intersection. Due to the shift,
+ * the Pluecker coordinate calculation simplifies and the tests get
+ * numerically stable. The edge equations are watertight along the
+ * edge for neighboring triangles. */
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M, typename UVMapper>
+ struct PlueckerHitM
+ {
+ __forceinline PlueckerHitM(const UVMapper& mapUV) : mapUV(mapUV) {}
+
+ __forceinline PlueckerHitM(const vbool<M>& valid, const vfloat<M>& U, const vfloat<M>& V, const vfloat<M>& UVW, const vfloat<M>& t, const Vec3vf<M>& Ng, const UVMapper& mapUV)
+ : U(U), V(V), UVW(UVW), mapUV(mapUV), valid(valid), vt(t), vNg(Ng) {}
+
+ __forceinline void finalize()
+ {
+ const vbool<M> invalid = abs(UVW) < min_rcp_input;
+ const vfloat<M> rcpUVW = select(invalid,vfloat<M>(0.0f),rcp(UVW));
+ vu = min(U * rcpUVW,1.0f);
+ vv = min(V * rcpUVW,1.0f);
+ mapUV(vu,vv,vNg);
+ }
+
+ __forceinline Vec2vf<M> uv() const { return Vec2vf<M>(vu,vv); }
+ __forceinline vfloat<M> t () const { return vt; }
+ __forceinline Vec3vf<M> Ng() const { return vNg; }
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ public:
+ vfloat<M> U;
+ vfloat<M> V;
+ vfloat<M> UVW;
+ const UVMapper& mapUV;
+
+ public:
+ vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M, bool early_out = true>
+ struct PlueckerIntersector1
+ {
+ __forceinline PlueckerIntersector1() {}
+
+ __forceinline PlueckerIntersector1(const Ray& ray, const void* ptr) {}
+
+ template<typename UVMapper>
+ __forceinline bool intersect(const vbool<M>& valid0,
+ Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const UVMapper& mapUV,
+ PlueckerHitM<M,UVMapper>& hit) const
+ {
+ vbool<M> valid = valid0;
+
+ /* calculate vertices relative to ray origin */
+ const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org);
+ const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir);
+ const Vec3vf<M> v0 = tri_v0-O;
+ const Vec3vf<M> v1 = tri_v1-O;
+ const Vec3vf<M> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<M> e0 = v2-v0;
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(cross(e0,v2+v0),D);
+ const vfloat<M> V = dot(cross(e1,v0+v1),D);
+ const vfloat<M> W = dot(cross(e2,v1+v2),D);
+ const vfloat<M> UVW = U+V+W;
+ const vfloat<M> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= max(U,V,W) <= eps;
+#else
+ valid &= (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(early_out && none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<M> den = twice(dot(Ng,D));
+
+ /* perform depth test */
+ const vfloat<M> T = twice(dot(v0,Ng));
+ const vfloat<M> t = rcp(den)*T;
+ valid &= vfloat<M>(ray.tnear()) <= t & t <= vfloat<M>(ray.tfar);
+ valid &= den != vfloat<M>(zero);
+ if (unlikely(early_out && none(valid))) return false;
+
+ /* update hit information */
+ new (&hit) PlueckerHitM<M,UVMapper>(valid,U,V,UVW,t,Ng,mapUV);
+ return true;
+ }
+
+ template<typename UVMapper>
+ __forceinline bool intersectEdge(const vbool<M>& valid,
+ Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const UVMapper& mapUV,
+ PlueckerHitM<M,UVMapper>& hit) const
+ {
+ return intersect(valid,ray,tri_v0,tri_v1,tri_v2,mapUV,hit);
+ }
+
+ template<typename UVMapper>
+ __forceinline bool intersectEdge(Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const UVMapper& mapUV,
+ PlueckerHitM<M,UVMapper>& hit) const
+ {
+ vbool<M> valid = true;
+ return intersect(valid,ray,tri_v0,tri_v1,tri_v2,mapUV,hit);
+ }
+
+ template<typename UVMapper>
+ __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const UVMapper& mapUV,
+ PlueckerHitM<M,UVMapper>& hit) const
+ {
+ return intersectEdge(ray,tri_v0,tri_v1,tri_v2,mapUV,hit);
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersectEdge(Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& e1,
+ const Vec3vf<M>& e2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ PlueckerHitM<M,UVMapper> hit(mapUV);
+ if (likely(intersectEdge(ray,v0,e1,e2,mapUV,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ PlueckerHitM<M,UVMapper> hit(mapUV);
+ if (likely(intersect(ray,v0,v1,v2,mapUV,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ auto mapUV = UVIdentity<M>();
+ PlueckerHitM<M,UVIdentity<M>> hit(mapUV);
+ if (likely(intersect(ray,v0,v1,v2,mapUV,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersect(const vbool<M>& valid,
+ Ray& ray,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ PlueckerHitM<M,UVMapper> hit(mapUV);
+ if (likely(intersect(valid,ray,v0,v1,v2,mapUV,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ };
+
+ template<int K, typename UVMapper>
+ struct PlueckerHitK
+ {
+ __forceinline PlueckerHitK(const UVMapper& mapUV) : mapUV(mapUV) {}
+
+ __forceinline PlueckerHitK(const vfloat<K>& U, const vfloat<K>& V, const vfloat<K>& UVW, const vfloat<K>& t, const Vec3vf<K>& Ng, const UVMapper& mapUV)
+ : U(U), V(V), UVW(UVW), t(t), Ng(Ng), mapUV(mapUV) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vbool<K> invalid = abs(UVW) < min_rcp_input;
+ const vfloat<K> rcpUVW = select(invalid,vfloat<K>(0.0f),rcp(UVW));
+ vfloat<K> u = min(U * rcpUVW,1.0f);
+ vfloat<K> v = min(V * rcpUVW,1.0f);
+ Vec3vf<K> vNg = Ng;
+ mapUV(u,v,vNg);
+ return std::make_tuple(u,v,t,vNg);
+ }
+ vfloat<K> U;
+ vfloat<K> V;
+ const vfloat<K> UVW;
+ const vfloat<K> t;
+ const Vec3vf<K> Ng;
+ const UVMapper& mapUV;
+ };
+
+ template<int M, int K>
+ struct PlueckerIntersectorK
+ {
+ __forceinline PlueckerIntersectorK() {}
+ __forceinline PlueckerIntersectorK(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename UVMapper>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const UVMapper& mapUV,
+ PlueckerHitK<K,UVMapper> &hit) const
+ {
+ /* calculate vertices relative to ray origin */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> O = ray.org;
+ const Vec3vf<K> D = ray.dir;
+ const Vec3vf<K> v0 = tri_v0-O;
+ const Vec3vf<K> v1 = tri_v1-O;
+ const Vec3vf<K> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<K> e0 = v2-v0;
+ const Vec3vf<K> e1 = v0-v1;
+ const Vec3vf<K> e2 = v1-v2;
+
+ /* perform edge tests */
+ const vfloat<K> U = dot(Vec3vf<K>(cross(e0,v2+v0)),D);
+ const vfloat<K> V = dot(Vec3vf<K>(cross(e1,v0+v1)),D);
+ const vfloat<K> W = dot(Vec3vf<K>(cross(e2,v1+v2)),D);
+ const vfloat<K> UVW = U+V+W;
+ const vfloat<K> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= max(U,V,W) <= eps;
+#else
+ valid &= (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return valid;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<K> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<K> den = twice(dot(Vec3vf<K>(Ng),D));
+
+ /* perform depth test */
+ const vfloat<K> T = twice(dot(v0,Vec3vf<K>(Ng)));
+ const vfloat<K> t = rcp(den)*T;
+ valid &= ray.tnear() <= t & t <= ray.tfar;
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return valid;
+
+ /* calculate hit information */
+ new (&hit) PlueckerHitK<K,UVMapper>(U,V,UVW,t,Ng,mapUV);
+ return valid;
+ }
+
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const Epilog& epilog) const
+ {
+ UVIdentity<K> mapUV;
+ PlueckerHitK<K,UVIdentity<K>> hit(mapUV);
+ const vbool<K> valid = intersectK(valid0,ray,tri_v0,tri_v1,tri_v2,mapUV,hit);
+ return epilog(valid,hit);
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ PlueckerHitK<K,UVMapper> hit(mapUV);
+ const vbool<K> valid = intersectK(valid0,ray,tri_v0,tri_v1,tri_v2,mapUV,hit);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersect k'th ray from ray packet of size K with M triangles. */
+ template<typename UVMapper>
+ __forceinline bool intersect(RayK<K>& ray, size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const UVMapper& mapUV,
+ PlueckerHitM<M,UVMapper> &hit) const
+ {
+ /* calculate vertices relative to ray origin */
+ const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vf<M> v0 = tri_v0-O;
+ const Vec3vf<M> v1 = tri_v1-O;
+ const Vec3vf<M> v2 = tri_v2-O;
+
+ /* calculate triangle edges */
+ const Vec3vf<M> e0 = v2-v0;
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v1-v2;
+
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(cross(e0,v2+v0),D);
+ const vfloat<M> V = dot(cross(e1,v0+v1),D);
+ const vfloat<M> W = dot(cross(e2,v1+v2),D);
+
+ const vfloat<M> UVW = U+V+W;
+ const vfloat<M> eps = float(ulp)*abs(UVW);
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = max(U,V,W) <= eps;
+#else
+ vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
+#endif
+ if (unlikely(none(valid))) return false;
+
+ /* calculate geometry normal and denominator */
+ const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
+ const vfloat<M> den = twice(dot(Ng,D));
+
+ /* perform depth test */
+ const vfloat<M> T = twice(dot(v0,Ng));
+ const vfloat<M> t = rcp(den)*T;
+ valid &= vfloat<M>(ray.tnear()[k]) <= t & t <= vfloat<M>(ray.tfar[k]);
+ if (unlikely(none(valid))) return false;
+
+ /* avoid division by 0 */
+ valid &= den != vfloat<M>(zero);
+ if (unlikely(none(valid))) return false;
+
+ /* update hit information */
+ new (&hit) PlueckerHitM<M,UVMapper>(valid,U,V,UVW,t,Ng,mapUV);
+ return true;
+ }
+
+ template<typename UVMapper, typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray, size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const UVMapper& mapUV,
+ const Epilog& epilog) const
+ {
+ PlueckerHitM<M,UVMapper> hit(mapUV);
+ if (intersect(ray,k,tri_v0,tri_v1,tri_v2,mapUV,hit))
+ return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray, size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ const Epilog& epilog) const
+ {
+ UVIdentity<M> mapUV;
+ PlueckerHitM<M,UVIdentity<M>> hit(mapUV);
+ if (intersect(ray,k,tri_v0,tri_v1,tri_v2,mapUV,hit))
+ return epilog(hit.valid,hit);
+ return false;
+ }
+
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/triangle_intersector_woop.h b/thirdparty/embree/kernels/geometry/triangle_intersector_woop.h
new file mode 100644
index 0000000000..f05dcc4537
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/triangle_intersector_woop.h
@@ -0,0 +1,418 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "intersector_epilog.h"
+
+/*! This intersector implements a modified version of the Woop's ray-triangle intersection test */
+
+namespace embree
+{
+ namespace isa
+ {
+ template<int M>
+ struct WoopHitM
+ {
+ __forceinline WoopHitM() {}
+
+ __forceinline WoopHitM(const vbool<M>& valid,
+ const vfloat<M>& U,
+ const vfloat<M>& V,
+ const vfloat<M>& T,
+ const vfloat<M>& inv_det,
+ const Vec3vf<M>& Ng)
+ : U(U), V(V), T(T), inv_det(inv_det), valid(valid), vNg(Ng) {}
+
+ __forceinline void finalize()
+ {
+ vt = T;
+ vu = U*inv_det;
+ vv = V*inv_det;
+ }
+
+ __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
+ __forceinline float t (const size_t i) const { return vt[i]; }
+ __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
+
+ private:
+ const vfloat<M> U;
+ const vfloat<M> V;
+ const vfloat<M> T;
+ const vfloat<M> inv_det;
+
+ public:
+ const vbool<M> valid;
+ vfloat<M> vu;
+ vfloat<M> vv;
+ vfloat<M> vt;
+ Vec3vf<M> vNg;
+ };
+
+ template<int M>
+ struct WoopPrecalculations1
+ {
+ unsigned int kx,ky,kz;
+ Vec3vf<M> org;
+ Vec3fa S;
+ __forceinline WoopPrecalculations1() {}
+
+ __forceinline WoopPrecalculations1(const Ray& ray, const void* ptr)
+ {
+ kz = maxDim(abs(ray.dir));
+ kx = (kz+1) % 3;
+ ky = (kx+1) % 3;
+ const float inv_dir_kz = rcp(ray.dir[kz]);
+ if (ray.dir[kz]) std::swap(kx,ky);
+ S.x = ray.dir[kx] * inv_dir_kz;
+ S.y = ray.dir[ky] * inv_dir_kz;
+ S.z = inv_dir_kz;
+ org = Vec3vf<M>(ray.org[kx],ray.org[ky],ray.org[kz]);
+ }
+ };
+
+
+ template<int M>
+ struct WoopIntersector1
+ {
+
+ typedef WoopPrecalculations1<M> Precalculations;
+
+ __forceinline WoopIntersector1() {}
+
+ __forceinline WoopIntersector1(const Ray& ray, const void* ptr) {}
+
+ static __forceinline bool intersect(const vbool<M>& valid0,
+ Ray& ray,
+ const Precalculations& pre,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_v1,
+ const Vec3vf<M>& tri_v2,
+ WoopHitM<M>& hit)
+ {
+ vbool<M> valid = valid0;
+
+ /* vertices relative to ray origin */
+ const Vec3vf<M> org = Vec3vf<M>(pre.org.x,pre.org.y,pre.org.z);
+ const Vec3vf<M> A = Vec3vf<M>(tri_v0[pre.kx],tri_v0[pre.ky],tri_v0[pre.kz]) - org;
+ const Vec3vf<M> B = Vec3vf<M>(tri_v1[pre.kx],tri_v1[pre.ky],tri_v1[pre.kz]) - org;
+ const Vec3vf<M> C = Vec3vf<M>(tri_v2[pre.kx],tri_v2[pre.ky],tri_v2[pre.kz]) - org;
+
+ /* shear and scale vertices */
+ const vfloat<M> Ax = nmadd(A.z,pre.S.x,A.x);
+ const vfloat<M> Ay = nmadd(A.z,pre.S.y,A.y);
+ const vfloat<M> Bx = nmadd(B.z,pre.S.x,B.x);
+ const vfloat<M> By = nmadd(B.z,pre.S.y,B.y);
+ const vfloat<M> Cx = nmadd(C.z,pre.S.x,C.x);
+ const vfloat<M> Cy = nmadd(C.z,pre.S.y,C.y);
+
+ /* scaled barycentric */
+ const vfloat<M> U0 = Cx*By;
+ const vfloat<M> U1 = Cy*Bx;
+ const vfloat<M> V0 = Ax*Cy;
+ const vfloat<M> V1 = Ay*Cx;
+ const vfloat<M> W0 = Bx*Ay;
+ const vfloat<M> W1 = By*Ax;
+#if !defined(__AVX512F__)
+ valid &= (U0 >= U1) & (V0 >= V1) & (W0 >= W1) |
+ (U0 <= U1) & (V0 <= V1) & (W0 <= W1);
+#else
+ valid &= ge(ge(U0 >= U1,V0,V1),W0,W1) | le(le(U0 <= U1,V0,V1),W0,W1);
+#endif
+
+ if (likely(none(valid))) return false;
+ const vfloat<M> U = U0-U1;
+ const vfloat<M> V = V0-V1;
+ const vfloat<M> W = W0-W1;
+
+ const vfloat<M> det = U+V+W;
+
+ valid &= det != 0.0f;
+ const vfloat<M> inv_det = rcp(det);
+
+ const vfloat<M> Az = pre.S.z * A.z;
+ const vfloat<M> Bz = pre.S.z * B.z;
+ const vfloat<M> Cz = pre.S.z * C.z;
+ const vfloat<M> T = madd(U,Az,madd(V,Bz,W*Cz));
+ const vfloat<M> t = T * inv_det;
+ /* perform depth test */
+ valid &= (vfloat<M>(ray.tnear()) < t) & (t <= vfloat<M>(ray.tfar));
+ if (likely(none(valid))) return false;
+
+ const Vec3vf<M> tri_Ng = cross(tri_v2-tri_v0,tri_v0-tri_v1);
+
+ /* update hit information */
+ new (&hit) WoopHitM<M>(valid,U,V,t,inv_det,tri_Ng);
+ return true;
+ }
+
+ static __forceinline bool intersect(Ray& ray,
+ const Precalculations& pre,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ WoopHitM<M>& hit)
+ {
+ vbool<M> valid = true;
+ return intersect(valid,ray,pre,v0,v1,v2,hit);
+ }
+
+
+ template<typename Epilog>
+ static __forceinline bool intersect(Ray& ray,
+ const Precalculations& pre,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog)
+ {
+ WoopHitM<M> hit;
+ if (likely(intersect(ray,pre,v0,v1,v2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ static __forceinline bool intersect(const vbool<M>& valid,
+ Ray& ray,
+ const Precalculations& pre,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog)
+ {
+ WoopHitM<M> hit;
+ if (likely(intersect(valid,ray,pre,v0,v1,v2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+ };
+
+#if 0
+ template<int K>
+ struct WoopHitK
+ {
+ __forceinline WoopHitK(const vfloat<K>& U, const vfloat<K>& V, const vfloat<K>& T, const vfloat<K>& absDen, const Vec3vf<K>& Ng)
+ : U(U), V(V), T(T), absDen(absDen), Ng(Ng) {}
+
+ __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
+ {
+ const vfloat<K> rcpAbsDen = rcp(absDen);
+ const vfloat<K> t = T * rcpAbsDen;
+ const vfloat<K> u = U * rcpAbsDen;
+ const vfloat<K> v = V * rcpAbsDen;
+ return std::make_tuple(u,v,t,Ng);
+ }
+
+ private:
+ const vfloat<K> U;
+ const vfloat<K> V;
+ const vfloat<K> T;
+ const vfloat<K> absDen;
+ const Vec3vf<K> Ng;
+ };
+
+ template<int M, int K>
+ struct WoopIntersectorK
+ {
+ __forceinline WoopIntersectorK(const vbool<K>& valid, const RayK<K>& ray) {}
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ //RayK<K>& ray,
+ const Vec3vf<K>& ray_org,
+ const Vec3vf<K>& ray_dir,
+ const vfloat<K>& ray_tnear,
+ const vfloat<K>& ray_tfar,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const Vec3vf<K>& tri_Ng,
+ const Epilog& epilog) const
+ {
+ /* calculate denominator */
+ vbool<K> valid = valid0;
+ const Vec3vf<K> C = tri_v0 - ray_org;
+ const Vec3vf<K> R = cross(C,ray_dir);
+ const vfloat<K> den = dot(tri_Ng,ray_dir);
+ const vfloat<K> absDen = abs(den);
+ const vfloat<K> sgnDen = signmsk(den);
+
+ /* test against edge p2 p0 */
+ const vfloat<K> U = dot(tri_e2,R) ^ sgnDen;
+ valid &= U >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p0 p1 */
+ const vfloat<K> V = dot(tri_e1,R) ^ sgnDen;
+ valid &= V >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* test against edge p1 p2 */
+ const vfloat<K> W = absDen-U-V;
+ valid &= W >= 0.0f;
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<K> T = dot(tri_Ng,C) ^ sgnDen;
+ valid &= (absDen*ray_tnear < T) & (T <= absDen*ray_tfar);
+ if (unlikely(none(valid))) return false;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ valid &= den < vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#else
+ valid &= den != vfloat<K>(zero);
+ if (unlikely(none(valid))) return false;
+#endif
+
+ /* calculate hit information */
+ WoopHitK<K> hit(U,V,T,absDen,tri_Ng);
+ return epilog(valid,hit);
+ }
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_v1,
+ const Vec3vf<K>& tri_v2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<K> e1 = tri_v0-tri_v1;
+ const Vec3vf<K> e2 = tri_v2-tri_v0;
+ const Vec3vf<K> Ng = cross(e2,e1);
+ return intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,e1,e2,Ng,epilog);
+ }
+
+ /*! Intersects K rays with one of M triangles. */
+ template<typename Epilog>
+ __forceinline vbool<K> intersectEdgeK(const vbool<K>& valid0,
+ RayK<K>& ray,
+ const Vec3vf<K>& tri_v0,
+ const Vec3vf<K>& tri_e1,
+ const Vec3vf<K>& tri_e2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<K> tri_Ng = cross(tri_e2,tri_e1);
+ return intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,tri_e1,tri_e2,tri_Ng,epilog);
+ }
+
+ /*! Intersect k'th ray from ray packet of size K with M triangles. */
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ WoopHitM<M>& hit) const
+ {
+ /* calculate denominator */
+ typedef Vec3vf<M> Vec3vfM;
+ const Vec3vf<M> tri_Ng = cross(tri_e2,tri_e1);
+
+ const Vec3vfM O = broadcast<vfloat<M>>(ray.org,k);
+ const Vec3vfM D = broadcast<vfloat<M>>(ray.dir,k);
+ const Vec3vfM C = Vec3vfM(tri_v0) - O;
+ const Vec3vfM R = cross(C,D);
+ const vfloat<M> den = dot(Vec3vfM(tri_Ng),D);
+ const vfloat<M> absDen = abs(den);
+ const vfloat<M> sgnDen = signmsk(den);
+
+ /* perform edge tests */
+ const vfloat<M> U = dot(Vec3vf<M>(tri_e2),R) ^ sgnDen;
+ const vfloat<M> V = dot(Vec3vf<M>(tri_e1),R) ^ sgnDen;
+
+ /* perform backface culling */
+#if defined(EMBREE_BACKFACE_CULLING)
+ vbool<M> valid = (den < vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#else
+ vbool<M> valid = (den != vfloat<M>(zero)) & (U >= 0.0f) & (V >= 0.0f) & (U+V<=absDen);
+#endif
+ if (likely(none(valid))) return false;
+
+ /* perform depth test */
+ const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen;
+ valid &= (absDen*vfloat<M>(ray.tnear()[k]) < T) & (T <= absDen*vfloat<M>(ray.tfar[k]));
+ if (likely(none(valid))) return false;
+
+ /* calculate hit information */
+ new (&hit) WoopHitM<M>(valid,U,V,T,absDen,tri_Ng);
+ return true;
+ }
+
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ WoopHitM<M>& hit) const
+ {
+ if (likely(intersect(ray,k,tri_v0,tri_e1,tri_e2,hit)))
+ {
+ hit.valid &= time_range.lower <= vfloat<M>(ray.time[k]);
+ hit.valid &= vfloat<M>(ray.time[k]) < time_range.upper;
+ return any(hit.valid);
+ }
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Epilog& epilog) const
+ {
+ WoopHitM<M> hit;
+ if (likely(intersectEdge(ray,k,tri_v0,tri_e1,tri_e2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersectEdge(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& tri_v0,
+ const Vec3vf<M>& tri_e1,
+ const Vec3vf<M>& tri_e2,
+ const Epilog& epilog) const
+ {
+ WoopHitM<M> hit;
+ if (likely(intersectEdge(ray,k,time_range,tri_v0,tri_e1,tri_e2,hit))) return epilog(hit.valid,hit);
+ return false;
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,k,v0,e1,e2,epilog);
+ }
+
+ template<typename Epilog>
+ __forceinline bool intersect(RayK<K>& ray,
+ size_t k,
+ const BBox<vfloat<M>>& time_range,
+ const Vec3vf<M>& v0,
+ const Vec3vf<M>& v1,
+ const Vec3vf<M>& v2,
+ const Epilog& epilog) const
+ {
+ const Vec3vf<M> e1 = v0-v1;
+ const Vec3vf<M> e2 = v2-v0;
+ return intersectEdge(ray,k,time_range,v0,e1,e2,epilog);
+ }
+ };
+#endif
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/triangle_triangle_intersector.h b/thirdparty/embree/kernels/geometry/triangle_triangle_intersector.h
new file mode 100644
index 0000000000..50106bcc16
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/triangle_triangle_intersector.h
@@ -0,0 +1,132 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#include "primitive.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct TriangleTriangleIntersector
+ {
+ __forceinline static float T(float pa0, float pa1, float da0, float da1) {
+ return pa0 + (pa1-pa0)*da0/(da0-da1);
+ }
+
+ __forceinline static bool point_line_side(const Vec2f& p, const Vec2f& a0, const Vec2f& a1) {
+ return det(p-a0,a0-a1) >= 0.0f;
+ }
+
+ __forceinline static bool point_inside_triangle(const Vec2f& p, const Vec2f& a, const Vec2f& b, const Vec2f& c)
+ {
+ const bool pab = point_line_side(p,a,b);
+ const bool pbc = point_line_side(p,b,c);
+ const bool pca = point_line_side(p,c,a);
+ return pab == pbc && pab == pca;
+ }
+
+ __forceinline static bool intersect_line_line(const Vec2f& a0, const Vec2f& a1, const Vec2f& b0, const Vec2f& b1)
+ {
+ const bool different_sides0 = point_line_side(b0,a0,a1) != point_line_side(b1,a0,a1);
+ const bool different_sides1 = point_line_side(a0,b0,b1) != point_line_side(a1,b0,b1);
+ return different_sides0 && different_sides1;
+ }
+
+ __forceinline static bool intersect_triangle_triangle (const Vec2f& a0, const Vec2f& a1, const Vec2f& a2,
+ const Vec2f& b0, const Vec2f& b1, const Vec2f& b2)
+ {
+ const bool a01_b01 = intersect_line_line(a0,a1,b0,b1);
+ if (a01_b01) return true;
+ const bool a01_b12 = intersect_line_line(a0,a1,b1,b2);
+ if (a01_b12) return true;
+ const bool a01_b20 = intersect_line_line(a0,a1,b2,b0);
+ if (a01_b20) return true;
+ const bool a12_b01 = intersect_line_line(a1,a2,b0,b1);
+ if (a12_b01) return true;
+ const bool a12_b12 = intersect_line_line(a1,a2,b1,b2);
+ if (a12_b12) return true;
+ const bool a12_b20 = intersect_line_line(a1,a2,b2,b0);
+ if (a12_b20) return true;
+ const bool a20_b01 = intersect_line_line(a2,a0,b0,b1);
+ if (a20_b01) return true;
+ const bool a20_b12 = intersect_line_line(a2,a0,b1,b2);
+ if (a20_b12) return true;
+ const bool a20_b20 = intersect_line_line(a2,a0,b2,b0);
+ if (a20_b20) return true;
+
+ bool a_in_b = point_inside_triangle(a0,b0,b1,b2) && point_inside_triangle(a1,b0,b1,b2) && point_inside_triangle(a2,b0,b1,b2);
+ if (a_in_b) return true;
+
+ bool b_in_a = point_inside_triangle(b0,a0,a1,a2) && point_inside_triangle(b1,a0,a1,a2) && point_inside_triangle(b2,a0,a1,a2);
+ if (b_in_a) return true;
+
+ return false;
+ }
+
+ static bool intersect_triangle_triangle (const Vec3fa& a0, const Vec3fa& a1, const Vec3fa& a2,
+ const Vec3fa& b0, const Vec3fa& b1, const Vec3fa& b2)
+ {
+ const float eps = 1E-5f;
+
+ /* calculate triangle planes */
+ const Vec3fa Na = cross(a1-a0,a2-a0);
+ const float Ca = dot(Na,a0);
+ const Vec3fa Nb = cross(b1-b0,b2-b0);
+ const float Cb = dot(Nb,b0);
+
+ /* project triangle A onto plane B */
+ const float da0 = dot(Nb,a0)-Cb;
+ const float da1 = dot(Nb,a1)-Cb;
+ const float da2 = dot(Nb,a2)-Cb;
+ if (max(da0,da1,da2) < -eps) return false;
+ if (min(da0,da1,da2) > +eps) return false;
+ //CSTAT(bvh_collide_prim_intersections4++);
+
+ /* project triangle B onto plane A */
+ const float db0 = dot(Na,b0)-Ca;
+ const float db1 = dot(Na,b1)-Ca;
+ const float db2 = dot(Na,b2)-Ca;
+ if (max(db0,db1,db2) < -eps) return false;
+ if (min(db0,db1,db2) > +eps) return false;
+ //CSTAT(bvh_collide_prim_intersections5++);
+
+ if (unlikely((std::fabs(da0) < eps && std::fabs(da1) < eps && std::fabs(da2) < eps) ||
+ (std::fabs(db0) < eps && std::fabs(db1) < eps && std::fabs(db2) < eps)))
+ {
+ const size_t dz = maxDim(Na);
+ const size_t dx = (dz+1)%3;
+ const size_t dy = (dx+1)%3;
+ const Vec2f A0(a0[dx],a0[dy]);
+ const Vec2f A1(a1[dx],a1[dy]);
+ const Vec2f A2(a2[dx],a2[dy]);
+ const Vec2f B0(b0[dx],b0[dy]);
+ const Vec2f B1(b1[dx],b1[dy]);
+ const Vec2f B2(b2[dx],b2[dy]);
+ return intersect_triangle_triangle(A0,A1,A2,B0,B1,B2);
+ }
+
+ const Vec3fa D = cross(Na,Nb);
+ const float pa0 = dot(D,a0);
+ const float pa1 = dot(D,a1);
+ const float pa2 = dot(D,a2);
+ const float pb0 = dot(D,b0);
+ const float pb1 = dot(D,b1);
+ const float pb2 = dot(D,b2);
+
+ BBox1f ba = empty;
+ if (min(da0,da1) <= 0.0f && max(da0,da1) >= 0.0f && abs(da0-da1) > 0.0f) ba.extend(T(pa0,pa1,da0,da1));
+ if (min(da1,da2) <= 0.0f && max(da1,da2) >= 0.0f && abs(da1-da2) > 0.0f) ba.extend(T(pa1,pa2,da1,da2));
+ if (min(da2,da0) <= 0.0f && max(da2,da0) >= 0.0f && abs(da2-da0) > 0.0f) ba.extend(T(pa2,pa0,da2,da0));
+
+ BBox1f bb = empty;
+ if (min(db0,db1) <= 0.0f && max(db0,db1) >= 0.0f && abs(db0-db1) > 0.0f) bb.extend(T(pb0,pb1,db0,db1));
+ if (min(db1,db2) <= 0.0f && max(db1,db2) >= 0.0f && abs(db1-db2) > 0.0f) bb.extend(T(pb1,pb2,db1,db2));
+ if (min(db2,db0) <= 0.0f && max(db2,db0) >= 0.0f && abs(db2-db0) > 0.0f) bb.extend(T(pb2,pb0,db2,db0));
+
+ return conjoint(ba,bb);
+ }
+ };
+ }
+}
+
+
diff --git a/thirdparty/embree/kernels/geometry/trianglei.h b/thirdparty/embree/kernels/geometry/trianglei.h
new file mode 100644
index 0000000000..6aad48a5ef
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/trianglei.h
@@ -0,0 +1,442 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+#include "../common/scene.h"
+
+namespace embree
+{
+ /* Stores M triangles from an indexed face set */
+ template <int M>
+ struct TriangleMi
+ {
+ /* Virtual interface to query information about the triangle type */
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* primitive supports multiple time segments */
+ static const bool singleTimeSegment = false;
+
+ /* Returns maximum number of stored triangles */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline TriangleMi() { }
+
+ /* Construction from vertices and IDs */
+ __forceinline TriangleMi(const vuint<M>& v0,
+ const vuint<M>& v1,
+ const vuint<M>& v2,
+ const vuint<M>& geomIDs,
+ const vuint<M>& primIDs)
+#if defined(EMBREE_COMPACT_POLYS)
+ : geomIDs(geomIDs), primIDs(primIDs) {}
+#else
+ : v0_(v0), v1_(v1), v2_(v2), geomIDs(geomIDs), primIDs(primIDs) {}
+#endif
+
+ /* Returns a mask that tells which triangles are valid */
+ __forceinline vbool<M> valid() const { return primIDs != vuint<M>(-1); }
+
+ /* Returns if the specified triangle is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return primIDs[i] != -1; }
+
+ /* Returns the number of stored triangles */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M> geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M> primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the triangles */
+ __forceinline const BBox3fa bounds(const Scene *const scene, const size_t itime=0) const
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M && valid(i); i++) {
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(i));
+ bounds.extend(mesh->bounds(primID(i),itime));
+ }
+ return bounds;
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime) {
+ return LBBox3fa(bounds(scene,itime+0),bounds(scene,itime+1));
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, size_t itime, size_t numTimeSteps)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(i));
+ allBounds.extend(mesh->linearBounds(primID(i), itime, numTimeSteps));
+ }
+ return allBounds;
+ }
+
+ __forceinline LBBox3fa linearBounds(const Scene *const scene, const BBox1f time_range)
+ {
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && valid(i); i++)
+ {
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(i));
+ allBounds.extend(mesh->linearBounds(primID(i), time_range));
+ }
+ return allBounds;
+ }
+
+ /* Non-temporal store */
+ __forceinline static void store_nt(TriangleMi* dst, const TriangleMi& src)
+ {
+#if !defined(EMBREE_COMPACT_POLYS)
+ vuint<M>::store_nt(&dst->v0_,src.v0_);
+ vuint<M>::store_nt(&dst->v1_,src.v1_);
+ vuint<M>::store_nt(&dst->v2_,src.v2_);
+#endif
+ vuint<M>::store_nt(&dst->geomIDs,src.geomIDs);
+ vuint<M>::store_nt(&dst->primIDs,src.primIDs);
+ }
+
+ /* Fill triangle from triangle list */
+ template<typename PrimRefT>
+ __forceinline void fill(const PrimRefT* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ vuint<M> v0 = zero, v1 = zero, v2 = zero;
+ vuint<M> geomID = -1, primID = -1;
+ const PrimRefT* prim = &prims[begin];
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (begin<end) {
+ geomID[i] = prim->geomID();
+ primID[i] = prim->primID();
+#if !defined(EMBREE_COMPACT_POLYS)
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(prim->geomID());
+ const TriangleMesh::Triangle& tri = mesh->triangle(prim->primID());
+ unsigned int int_stride = mesh->vertices0.getStride()/4;
+ v0[i] = tri.v[0] * int_stride;
+ v1[i] = tri.v[1] * int_stride;
+ v2[i] = tri.v[2] * int_stride;
+#endif
+ begin++;
+ } else {
+ assert(i);
+ if (likely(i > 0)) {
+ geomID[i] = geomID[0];
+ primID[i] = -1;
+ v0[i] = v0[0];
+ v1[i] = v0[0];
+ v2[i] = v0[0];
+ }
+ }
+ if (begin<end) prim = &prims[begin];
+ }
+ new (this) TriangleMi(v0,v1,v2,geomID,primID); // FIXME: use non temporal store
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, itime);
+ }
+
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ fill(prims, begin, end, scene);
+ return linearBounds(scene, time_range);
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(TriangleMesh* mesh)
+ {
+ BBox3fa bounds = empty;
+ for (size_t i=0; i<M; i++)
+ {
+ if (primID(i) == -1) break;
+ const unsigned int primId = primID(i);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primId);
+ const Vec3fa p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa p2 = mesh->vertex(tri.v[2]);
+ bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2)));
+ }
+ return bounds;
+ }
+
+ protected:
+#if !defined(EMBREE_COMPACT_POLYS)
+ vuint<M> v0_; // 4 byte offset of 1st vertex
+ vuint<M> v1_; // 4 byte offset of 2nd vertex
+ vuint<M> v2_; // 4 byte offset of 3rd vertex
+#endif
+ vuint<M> geomIDs; // geometry ID of mesh
+ vuint<M> primIDs; // primitive ID of primitive inside mesh
+ };
+
+ namespace isa
+ {
+
+ template<int M>
+ struct TriangleMi : public embree::TriangleMi<M>
+ {
+#if !defined(EMBREE_COMPACT_POLYS)
+ using embree::TriangleMi<M>::v0_;
+ using embree::TriangleMi<M>::v1_;
+ using embree::TriangleMi<M>::v2_;
+#endif
+ using embree::TriangleMi<M>::geomIDs;
+ using embree::TriangleMi<M>::primIDs;
+ using embree::TriangleMi<M>::geomID;
+ using embree::TriangleMi<M>::primID;
+ using embree::TriangleMi<M>::valid;
+
+ /* loads a single vertex */
+ template<int vid>
+ __forceinline Vec3f getVertex(const size_t index, const Scene *const scene) const
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(index));
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID(index));
+ return (Vec3f) mesh->vertices[0][tri.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const float* vertices = scene->vertices[geomID(index)];
+ return (Vec3f&) vertices[v[index]];
+#endif
+ }
+
+ template<int vid, typename T>
+ __forceinline Vec3<T> getVertex(const size_t index, const Scene *const scene, const size_t itime, const T& ftime) const
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(index));
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID(index));
+ const Vec3fa v0 = mesh->vertices[itime+0][tri.v[vid]];
+ const Vec3fa v1 = mesh->vertices[itime+1][tri.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(index));
+ const float* vertices0 = (const float*) mesh->vertexPtr(0,itime+0);
+ const float* vertices1 = (const float*) mesh->vertexPtr(0,itime+1);
+ const Vec3fa v0 = Vec3fa::loadu(vertices0+v[index]);
+ const Vec3fa v1 = Vec3fa::loadu(vertices1+v[index]);
+#endif
+ const Vec3<T> p0(v0.x,v0.y,v0.z);
+ const Vec3<T> p1(v1.x,v1.y,v1.z);
+ return lerp(p0,p1,ftime);
+ }
+
+ template<int vid, int K, typename T>
+ __forceinline Vec3<T> getVertex(const vbool<K>& valid, const size_t index, const Scene *const scene, const vint<K>& itime, const T& ftime) const
+ {
+ Vec3<T> p0, p1;
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(index));
+
+ for (size_t mask=movemask(valid), i=bsf(mask); mask; mask=btc(mask,i), i=bsf(mask))
+ {
+#if defined(EMBREE_COMPACT_POLYS)
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID(index));
+ const Vec3fa v0 = mesh->vertices[itime[i]+0][tri.v[vid]];
+ const Vec3fa v1 = mesh->vertices[itime[i]+1][tri.v[vid]];
+#else
+ const vuint<M>& v = getVertexOffset<vid>();
+ const float* vertices0 = (const float*) mesh->vertexPtr(0,itime[i]+0);
+ const float* vertices1 = (const float*) mesh->vertexPtr(0,itime[i]+1);
+ const Vec3fa v0 = Vec3fa::loadu(vertices0+v[index]);
+ const Vec3fa v1 = Vec3fa::loadu(vertices1+v[index]);
+#endif
+ p0.x[i] = v0.x; p0.y[i] = v0.y; p0.z[i] = v0.z;
+ p1.x[i] = v1.x; p1.y[i] = v1.y; p1.z[i] = v1.z;
+ }
+ return (T(one)-ftime)*p0 + ftime*p1;
+ }
+
+ struct Triangle {
+ vfloat4 v0,v1,v2;
+ };
+
+#if defined(EMBREE_COMPACT_POLYS)
+
+ __forceinline Triangle loadTriangle(const int i, const Scene* const scene) const
+ {
+ const unsigned int geomID = geomIDs[i];
+ const unsigned int primID = primIDs[i];
+ if (unlikely(primID == -1)) return { zero, zero, zero };
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const vfloat4 v0 = (vfloat4) mesh->vertices0[tri.v[0]];
+ const vfloat4 v1 = (vfloat4) mesh->vertices0[tri.v[1]];
+ const vfloat4 v2 = (vfloat4) mesh->vertices0[tri.v[2]];
+ return { v0, v1, v2 };
+ }
+
+ __forceinline Triangle loadTriangle(const int i, const int itime, const TriangleMesh* const mesh) const
+ {
+ const unsigned int primID = primIDs[i];
+ if (unlikely(primID == -1)) return { zero, zero, zero };
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const vfloat4 v0 = (vfloat4) mesh->vertices[itime][tri.v[0]];
+ const vfloat4 v1 = (vfloat4) mesh->vertices[itime][tri.v[1]];
+ const vfloat4 v2 = (vfloat4) mesh->vertices[itime][tri.v[2]];
+ return { v0, v1, v2 };
+ }
+
+#else
+
+ __forceinline Triangle loadTriangle(const int i, const Scene* const scene) const
+ {
+ const float* vertices = scene->vertices[geomID(i)];
+ const vfloat4 v0 = vfloat4::loadu(vertices + v0_[i]);
+ const vfloat4 v1 = vfloat4::loadu(vertices + v1_[i]);
+ const vfloat4 v2 = vfloat4::loadu(vertices + v2_[i]);
+ return { v0, v1, v2 };
+ }
+
+ __forceinline Triangle loadTriangle(const int i, const int itime, const TriangleMesh* const mesh) const
+ {
+ const float* vertices = (const float*) mesh->vertexPtr(0,itime);
+ const vfloat4 v0 = vfloat4::loadu(vertices + v0_[i]);
+ const vfloat4 v1 = vfloat4::loadu(vertices + v1_[i]);
+ const vfloat4 v2 = vfloat4::loadu(vertices + v2_[i]);
+ return { v0, v1, v2 };
+ }
+
+#endif
+
+ /* Gather the triangles */
+ __forceinline void gather(Vec3vf<M>& p0, Vec3vf<M>& p1, Vec3vf<M>& p2, const Scene* const scene) const;
+
+ template<int K>
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER < 2000) // workaround for compiler bug in ICC 2019
+ __noinline
+#else
+ __forceinline
+#endif
+ void gather(const vbool<K>& valid,
+ Vec3vf<K>& p0,
+ Vec3vf<K>& p1,
+ Vec3vf<K>& p2,
+ const size_t index,
+ const Scene* const scene,
+ const vfloat<K>& time) const
+ {
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(index));
+
+ vfloat<K> ftime;
+ const vint<K> itime = mesh->timeSegment<K>(time, ftime);
+
+ const size_t first = bsf(movemask(valid));
+ if (likely(all(valid,itime[first] == itime)))
+ {
+ p0 = getVertex<0>(index, scene, itime[first], ftime);
+ p1 = getVertex<1>(index, scene, itime[first], ftime);
+ p2 = getVertex<2>(index, scene, itime[first], ftime);
+ } else {
+ p0 = getVertex<0,K>(valid, index, scene, itime, ftime);
+ p1 = getVertex<1,K>(valid, index, scene, itime, ftime);
+ p2 = getVertex<2,K>(valid, index, scene, itime, ftime);
+ }
+ }
+
+ __forceinline void gather(Vec3vf<M>& p0,
+ Vec3vf<M>& p1,
+ Vec3vf<M>& p2,
+ const TriangleMesh* mesh,
+ const Scene *const scene,
+ const int itime) const;
+
+ __forceinline void gather(Vec3vf<M>& p0,
+ Vec3vf<M>& p1,
+ Vec3vf<M>& p2,
+ const Scene *const scene,
+ const float time) const;
+
+
+#if !defined(EMBREE_COMPACT_POLYS)
+ template<int N> const vuint<M>& getVertexOffset() const;
+#endif
+ };
+
+#if !defined(EMBREE_COMPACT_POLYS)
+ template<> template<> __forceinline const vuint<4>& TriangleMi<4>::getVertexOffset<0>() const { return v0_; }
+ template<> template<> __forceinline const vuint<4>& TriangleMi<4>::getVertexOffset<1>() const { return v1_; }
+ template<> template<> __forceinline const vuint<4>& TriangleMi<4>::getVertexOffset<2>() const { return v2_; }
+#endif
+
+ template<>
+ __forceinline void TriangleMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ const Scene* const scene) const
+ {
+ const Triangle tri0 = loadTriangle(0,scene);
+ const Triangle tri1 = loadTriangle(1,scene);
+ const Triangle tri2 = loadTriangle(2,scene);
+ const Triangle tri3 = loadTriangle(3,scene);
+ transpose(tri0.v0,tri1.v0,tri2.v0,tri3.v0,p0.x,p0.y,p0.z);
+ transpose(tri0.v1,tri1.v1,tri2.v1,tri3.v1,p1.x,p1.y,p1.z);
+ transpose(tri0.v2,tri1.v2,tri2.v2,tri3.v2,p2.x,p2.y,p2.z);
+ }
+
+ template<>
+ __forceinline void TriangleMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ const TriangleMesh* mesh,
+ const Scene *const scene,
+ const int itime) const
+ {
+ const Triangle tri0 = loadTriangle(0,itime,mesh);
+ const Triangle tri1 = loadTriangle(1,itime,mesh);
+ const Triangle tri2 = loadTriangle(2,itime,mesh);
+ const Triangle tri3 = loadTriangle(3,itime,mesh);
+ transpose(tri0.v0,tri1.v0,tri2.v0,tri3.v0,p0.x,p0.y,p0.z);
+ transpose(tri0.v1,tri1.v1,tri2.v1,tri3.v1,p1.x,p1.y,p1.z);
+ transpose(tri0.v2,tri1.v2,tri2.v2,tri3.v2,p2.x,p2.y,p2.z);
+ }
+
+ template<>
+ __forceinline void TriangleMi<4>::gather(Vec3vf4& p0,
+ Vec3vf4& p1,
+ Vec3vf4& p2,
+ const Scene *const scene,
+ const float time) const
+ {
+ const TriangleMesh* mesh = scene->get<TriangleMesh>(geomID(0)); // in mblur mode all geometries are identical
+
+ float ftime;
+ const int itime = mesh->timeSegment(time, ftime);
+
+ Vec3vf4 a0,a1,a2; gather(a0,a1,a2,mesh,scene,itime);
+ Vec3vf4 b0,b1,b2; gather(b0,b1,b2,mesh,scene,itime+1);
+ p0 = lerp(a0,b0,vfloat4(ftime));
+ p1 = lerp(a1,b1,vfloat4(ftime));
+ p2 = lerp(a2,b2,vfloat4(ftime));
+ }
+ }
+
+ template<int M>
+ typename TriangleMi<M>::Type TriangleMi<M>::type;
+
+ typedef TriangleMi<4> Triangle4i;
+}
diff --git a/thirdparty/embree/kernels/geometry/trianglei_intersector.h b/thirdparty/embree/kernels/geometry/trianglei_intersector.h
new file mode 100644
index 0000000000..f7deb9e72d
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/trianglei_intersector.h
@@ -0,0 +1,336 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "trianglei.h"
+#include "triangle_intersector_moeller.h"
+#include "triangle_intersector_pluecker.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M triangles with 1 ray */
+ template<int M, bool filter>
+ struct TriangleMiIntersector1Moeller
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef MoellerTrumboreIntersector1<M> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ pre.intersect(ray,v0,v1,v2,Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ return pre.intersect(ray,v0,v1,v2,Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M triangles with K rays */
+ template<int M, int K, bool filter>
+ struct TriangleMiIntersectorKMoeller
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef MoellerTrumboreIntersectorK<M,K> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ const Scene* scene = context->scene;
+ for (size_t i=0; i<Primitive::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),RayHitK<K>::size());
+ const Vec3vf<K> v0 = tri.template getVertex<0>(i,scene);
+ const Vec3vf<K> v1 = tri.template getVertex<1>(i,scene);
+ const Vec3vf<K> v2 = tri.template getVertex<2>(i,scene);
+ pre.intersectK(valid_i,ray,v0,v1,v2,IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ vbool<K> valid0 = valid_i;
+ const Scene* scene = context->scene;
+
+ for (size_t i=0; i<Primitive::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid_i),RayHitK<K>::size());
+ const Vec3vf<K> v0 = tri.template getVertex<0>(i,scene);
+ const Vec3vf<K> v1 = tri.template getVertex<1>(i,scene);
+ const Vec3vf<K> v2 = tri.template getVertex<2>(i,scene);
+ pre.intersectK(valid0,ray,v0,v1,v2,OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ pre.intersect(ray,k,v0,v1,v2,Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ return pre.intersect(ray,k,v0,v1,v2,Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+
+ /*! Intersects M triangles with 1 ray */
+ template<int M, bool filter>
+ struct TriangleMiIntersector1Pluecker
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef PlueckerIntersector1<M> Precalculations;
+
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ pre.intersect(ray,v0,v1,v2,Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ return pre.intersect(ray,v0,v1,v2,Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M triangles with K rays */
+ template<int M, int K, bool filter>
+ struct TriangleMiIntersectorKPluecker
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef PlueckerIntersectorK<M,K> Precalculations;
+
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ const Scene* scene = context->scene;
+ for (size_t i=0; i<Primitive::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),RayHitK<K>::size());
+ const Vec3vf<K> v0 = tri.template getVertex<0>(i,scene);
+ const Vec3vf<K> v1 = tri.template getVertex<1>(i,scene);
+ const Vec3vf<K> v2 = tri.template getVertex<2>(i,scene);
+ pre.intersectK(valid_i,ray,v0,v1,v2,IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ vbool<K> valid0 = valid_i;
+ const Scene* scene = context->scene;
+
+ for (size_t i=0; i<Primitive::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid_i),RayHitK<K>::size());
+ const Vec3vf<K> v0 = tri.template getVertex<0>(i,scene);
+ const Vec3vf<K> v1 = tri.template getVertex<1>(i,scene);
+ const Vec3vf<K> v2 = tri.template getVertex<2>(i,scene);
+ pre.intersectK(valid0,ray,v0,v1,v2,OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ pre.intersect(ray,k,v0,v1,v2,Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene);
+ return pre.intersect(ray,k,v0,v1,v2,Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+
+ /*! Intersects M motion blur triangles with 1 ray */
+ template<int M, bool filter>
+ struct TriangleMiMBIntersector1Moeller
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef MoellerTrumboreIntersector1<M> Precalculations;
+
+ /*! Intersect a ray with the M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time());
+ pre.intersect(ray,v0,v1,v2,Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time());
+ return pre.intersect(ray,v0,v1,v2,Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M motion blur triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct TriangleMiMBIntersectorKMoeller
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef MoellerTrumboreIntersectorK<M,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ for (size_t i=0; i<TriangleMi<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ Vec3vf<K> v0,v1,v2; tri.template gather<K>(valid_i,v0,v1,v2,i,context->scene,ray.time());
+ pre.intersectK(valid_i,ray,v0,v1,v2,IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<TriangleMi<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ Vec3vf<K> v0,v1,v2; tri.template gather<K>(valid_i,v0,v1,v2,i,context->scene,ray.time());
+ pre.intersectK(valid0,ray,v0,v1,v2,OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]);
+ pre.intersect(ray,k,v0,v1,v2,Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]);
+ return pre.intersect(ray,k,v0,v1,v2,Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+
+ /*! Intersects M motion blur triangles with 1 ray */
+ template<int M, bool filter>
+ struct TriangleMiMBIntersector1Pluecker
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef PlueckerIntersector1<M> Precalculations;
+
+ /*! Intersect a ray with the M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time());
+ pre.intersect(ray,v0,v1,v2,Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time());
+ return pre.intersect(ray,v0,v1,v2,Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M motion blur triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct TriangleMiMBIntersectorKPluecker
+ {
+ typedef TriangleMi<M> Primitive;
+ typedef PlueckerIntersectorK<M,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ for (size_t i=0; i<TriangleMi<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ Vec3vf<K> v0,v1,v2; tri.template gather<K>(valid_i,v0,v1,v2,i,context->scene,ray.time());
+ pre.intersectK(valid_i,ray,v0,v1,v2,IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ vbool<K> valid0 = valid_i;
+ for (size_t i=0; i<TriangleMi<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ Vec3vf<K> v0,v1,v2; tri.template gather<K>(valid_i,v0,v1,v2,i,context->scene,ray.time());
+ pre.intersectK(valid0,ray,v0,v1,v2,OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]);
+ pre.intersect(ray,k,v0,v1,v2,Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]);
+ return pre.intersect(ray,k,v0,v1,v2,Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/trianglev.h b/thirdparty/embree/kernels/geometry/trianglev.h
new file mode 100644
index 0000000000..cd94756b9e
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/trianglev.h
@@ -0,0 +1,157 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ /* Stores the vertices of M triangles in struct of array layout */
+ template <int M>
+ struct TriangleMv
+ {
+ public:
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+ static Type type;
+
+ public:
+
+ /* Returns maximum number of stored triangles */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline TriangleMv() {}
+
+ /* Construction from vertices and IDs */
+ __forceinline TriangleMv(const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const vuint<M>& geomIDs, const vuint<M>& primIDs)
+ : v0(v0), v1(v1), v2(v2), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ /* Returns a mask that tells which triangles are valid */
+ __forceinline vbool<M> valid() const { return geomIDs != vuint<M>(-1); }
+
+ /* Returns true if the specified triangle is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return geomIDs[i] != -1; }
+
+ /* Returns the number of stored triangles */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M>& geomID() { return geomIDs; }
+ __forceinline const vuint<M>& geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M>& primID() { return primIDs; }
+ __forceinline const vuint<M>& primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the triangles */
+ __forceinline BBox3fa bounds() const
+ {
+ Vec3vf<M> lower = min(v0,v1,v2);
+ Vec3vf<M> upper = max(v0,v1,v2);
+ vbool<M> mask = valid();
+ lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
+ lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
+ lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
+ upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
+ upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
+ upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
+ return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
+ Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
+ }
+
+ /* Non temporal store */
+ __forceinline static void store_nt(TriangleMv* dst, const TriangleMv& src)
+ {
+ vfloat<M>::store_nt(&dst->v0.x,src.v0.x);
+ vfloat<M>::store_nt(&dst->v0.y,src.v0.y);
+ vfloat<M>::store_nt(&dst->v0.z,src.v0.z);
+ vfloat<M>::store_nt(&dst->v1.x,src.v1.x);
+ vfloat<M>::store_nt(&dst->v1.y,src.v1.y);
+ vfloat<M>::store_nt(&dst->v1.z,src.v1.z);
+ vfloat<M>::store_nt(&dst->v2.x,src.v2.x);
+ vfloat<M>::store_nt(&dst->v2.y,src.v2.y);
+ vfloat<M>::store_nt(&dst->v2.z,src.v2.z);
+ vuint<M>::store_nt(&dst->geomIDs,src.geomIDs);
+ vuint<M>::store_nt(&dst->primIDs,src.primIDs);
+ }
+
+ /* Fill triangle from triangle list */
+ __forceinline void fill(const PrimRef* prims, size_t& begin, size_t end, Scene* scene)
+ {
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
+
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRef& prim = prims[begin];
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const TriangleMesh* __restrict__ const mesh = scene->get<TriangleMesh>(geomID);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa& p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa& p2 = mesh->vertex(tri.v[2]);
+ vgeomID [i] = geomID;
+ vprimID [i] = primID;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+ TriangleMv::store_nt(this,TriangleMv(v0,v1,v2,vgeomID,vprimID));
+ }
+
+ /* Updates the primitive */
+ __forceinline BBox3fa update(TriangleMesh* mesh)
+ {
+ BBox3fa bounds = empty;
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (primID(i) == -1) break;
+ const unsigned geomId = geomID(i);
+ const unsigned primId = primID(i);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primId);
+ const Vec3fa p0 = mesh->vertex(tri.v[0]);
+ const Vec3fa p1 = mesh->vertex(tri.v[1]);
+ const Vec3fa p2 = mesh->vertex(tri.v[2]);
+ bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2)));
+ vgeomID [i] = geomId;
+ vprimID [i] = primId;
+ v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
+ v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
+ v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
+ }
+ new (this) TriangleMv(v0,v1,v2,vgeomID,vprimID);
+ return bounds;
+ }
+
+ public:
+ Vec3vf<M> v0; // 1st vertex of the triangles
+ Vec3vf<M> v1; // 2nd vertex of the triangles
+ Vec3vf<M> v2; // 3rd vertex of the triangles
+ private:
+ vuint<M> geomIDs; // geometry ID
+ vuint<M> primIDs; // primitive ID
+ };
+
+ template<int M>
+ typename TriangleMv<M>::Type TriangleMv<M>::type;
+
+ typedef TriangleMv<4> Triangle4v;
+}
diff --git a/thirdparty/embree/kernels/geometry/trianglev_intersector.h b/thirdparty/embree/kernels/geometry/trianglev_intersector.h
new file mode 100644
index 0000000000..3abb7f8e32
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/trianglev_intersector.h
@@ -0,0 +1,206 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "triangle_intersector_pluecker.h"
+#include "triangle_intersector_moeller.h"
+#include "triangle_intersector_woop.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M triangles with 1 ray */
+ template<int M, bool filter>
+ struct TriangleMvIntersector1Moeller
+ {
+ typedef TriangleMv<M> Primitive;
+ typedef MoellerTrumboreIntersector1<M> Precalculations;
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,tri.v0,tri.v1,tri.v2,/*UVIdentity<M>(),*/Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersect(ray,tri.v0,tri.v1,tri.v2,/*UVIdentity<M>(),*/Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+
+ template<int M, bool filter>
+ struct TriangleMvIntersector1Woop
+ {
+ typedef TriangleMv<M> Primitive;
+ typedef WoopIntersector1<M> intersec;
+ typedef WoopPrecalculations1<M> Precalculations;
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ intersec::intersect(ray,pre,tri.v0,tri.v1,tri.v2,Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return intersec::intersect(ray,pre,tri.v0,tri.v1,tri.v2,Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+
+ /*! Intersects M triangles with K rays */
+ template<int M, int K, bool filter>
+ struct TriangleMvIntersectorKMoeller
+ {
+ typedef TriangleMv<M> Primitive;
+ typedef MoellerTrumboreIntersectorK<M,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ for (size_t i=0; i<M; i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> v0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> v1 = broadcast<vfloat<K>>(tri.v1,i);
+ const Vec3vf<K> v2 = broadcast<vfloat<K>>(tri.v2,i);
+ pre.intersectK(valid_i,ray,v0,v1,v2,/*UVIdentity<K>(),*/IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> v0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> v1 = broadcast<vfloat<K>>(tri.v1,i);
+ const Vec3vf<K> v2 = broadcast<vfloat<K>>(tri.v2,i);
+ pre.intersectK(valid0,ray,v0,v1,v2,/*UVIdentity<K>(),*/OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,/*UVIdentity<M>(),*/Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID())); //FIXME: M
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,/*UVIdentity<M>(),*/Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID())); //FIXME: M
+ }
+ };
+
+ /*! Intersects M triangles with 1 ray */
+ template<int M, bool filter>
+ struct TriangleMvIntersector1Pluecker
+ {
+ typedef TriangleMv<M> Primitive;
+ typedef PlueckerIntersector1<M> Precalculations;
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,tri.v0,tri.v1,tri.v2,UVIdentity<M>(),Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersect(ray,tri.v0,tri.v1,tri.v2,UVIdentity<M>(),Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M triangles with K rays */
+ template<int M, int K, bool filter>
+ struct TriangleMvIntersectorKPluecker
+ {
+ typedef TriangleMv<M> Primitive;
+ typedef PlueckerIntersectorK<M,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ for (size_t i=0; i<M; i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> v0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> v1 = broadcast<vfloat<K>>(tri.v1,i);
+ const Vec3vf<K> v2 = broadcast<vfloat<K>>(tri.v2,i);
+ pre.intersectK(valid_i,ray,v0,v1,v2,UVIdentity<K>(),IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<M; i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> v0 = broadcast<vfloat<K>>(tri.v0,i);
+ const Vec3vf<K> v1 = broadcast<vfloat<K>>(tri.v1,i);
+ const Vec3vf<K> v2 = broadcast<vfloat<K>>(tri.v2,i);
+ pre.intersectK(valid0,ray,v0,v1,v2,UVIdentity<K>(),OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,UVIdentity<M>(),Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ return pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,UVIdentity<M>(),Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/geometry/trianglev_mb.h b/thirdparty/embree/kernels/geometry/trianglev_mb.h
new file mode 100644
index 0000000000..b550a29fd5
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/trianglev_mb.h
@@ -0,0 +1,201 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "primitive.h"
+
+namespace embree
+{
+ /* Stores the vertices of M triangles in struct of array layout */
+ template<int M>
+ struct TriangleMvMB
+ {
+ public:
+ struct Type : public PrimitiveType
+ {
+ const char* name() const;
+ size_t sizeActive(const char* This) const;
+ size_t sizeTotal(const char* This) const;
+ size_t getBytes(const char* This) const;
+ };
+
+ static Type type;
+
+ public:
+
+ /* primitive supports single time segments */
+ static const bool singleTimeSegment = true;
+
+ /* Returns maximum number of stored triangles */
+ static __forceinline size_t max_size() { return M; }
+
+ /* Returns required number of primitive blocks for N primitives */
+ static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
+
+ public:
+
+ /* Default constructor */
+ __forceinline TriangleMvMB() {}
+
+ /* Construction from vertices and IDs */
+ __forceinline TriangleMvMB(const Vec3vf<M>& a0, const Vec3vf<M>& a1,
+ const Vec3vf<M>& b0, const Vec3vf<M>& b1,
+ const Vec3vf<M>& c0, const Vec3vf<M>& c1,
+ const vuint<M>& geomIDs, const vuint<M>& primIDs)
+ : v0(a0), v1(b0), v2(c0), dv0(a1-a0), dv1(b1-b0), dv2(c1-c0), geomIDs(geomIDs), primIDs(primIDs) {}
+
+ /* Returns a mask that tells which triangles are valid */
+ __forceinline vbool<M> valid() const { return geomIDs != vuint<M>(-1); }
+
+ /* Returns if the specified triangle is valid */
+ __forceinline bool valid(const size_t i) const { assert(i<M); return geomIDs[i] != -1; }
+
+ /* Returns the number of stored triangles */
+ __forceinline size_t size() const { return bsf(~movemask(valid())); }
+
+ /* Returns the geometry IDs */
+ __forceinline vuint<M>& geomID() { return geomIDs; }
+ __forceinline const vuint<M>& geomID() const { return geomIDs; }
+ __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
+
+ /* Returns the primitive IDs */
+ __forceinline vuint<M>& primID() { return primIDs; }
+ __forceinline const vuint<M>& primID() const { return primIDs; }
+ __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
+
+ /* Calculate the bounds of the triangles at t0 */
+ __forceinline BBox3fa bounds0() const
+ {
+ Vec3vf<M> lower = min(v0,v1,v2);
+ Vec3vf<M> upper = max(v0,v1,v2);
+ const vbool<M> mask = valid();
+ lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
+ lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
+ lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
+ upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
+ upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
+ upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
+ return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
+ Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
+ }
+
+ /* Calculate the bounds of the triangles at t1 */
+ __forceinline BBox3fa bounds1() const
+ {
+ const Vec3vf<M> p0 = v0+dv0;
+ const Vec3vf<M> p1 = v1+dv1;
+ const Vec3vf<M> p2 = v2+dv2;
+ Vec3vf<M> lower = min(p0,p1,p2);
+ Vec3vf<M> upper = max(p0,p1,p2);
+ const vbool<M> mask = valid();
+ lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
+ lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
+ lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
+ upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
+ upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
+ upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
+ return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
+ Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
+ }
+
+ /* Calculate the linear bounds of the primitive */
+ __forceinline LBBox3fa linearBounds() const {
+ return LBBox3fa(bounds0(),bounds1());
+ }
+
+ /* Fill triangle from triangle list */
+ __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
+ {
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> va0 = zero, vb0 = zero, vc0 = zero;
+ Vec3vf<M> va1 = zero, vb1 = zero, vc1 = zero;
+
+ BBox3fa bounds0 = empty;
+ BBox3fa bounds1 = empty;
+
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRef& prim = prims[begin];
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const TriangleMesh* __restrict__ const mesh = scene->get<TriangleMesh>(geomID);
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ const Vec3fa& a0 = mesh->vertex(tri.v[0],itime+0); bounds0.extend(a0);
+ const Vec3fa& a1 = mesh->vertex(tri.v[0],itime+1); bounds1.extend(a1);
+ const Vec3fa& b0 = mesh->vertex(tri.v[1],itime+0); bounds0.extend(b0);
+ const Vec3fa& b1 = mesh->vertex(tri.v[1],itime+1); bounds1.extend(b1);
+ const Vec3fa& c0 = mesh->vertex(tri.v[2],itime+0); bounds0.extend(c0);
+ const Vec3fa& c1 = mesh->vertex(tri.v[2],itime+1); bounds1.extend(c1);
+ vgeomID [i] = geomID;
+ vprimID [i] = primID;
+ va0.x[i] = a0.x; va0.y[i] = a0.y; va0.z[i] = a0.z;
+ va1.x[i] = a1.x; va1.y[i] = a1.y; va1.z[i] = a1.z;
+ vb0.x[i] = b0.x; vb0.y[i] = b0.y; vb0.z[i] = b0.z;
+ vb1.x[i] = b1.x; vb1.y[i] = b1.y; vb1.z[i] = b1.z;
+ vc0.x[i] = c0.x; vc0.y[i] = c0.y; vc0.z[i] = c0.z;
+ vc1.x[i] = c1.x; vc1.y[i] = c1.y; vc1.z[i] = c1.z;
+ }
+ new (this) TriangleMvMB(va0,va1,vb0,vb1,vc0,vc1,vgeomID,vprimID);
+ return LBBox3fa(bounds0,bounds1);
+ }
+
+ /* Fill triangle from triangle list */
+ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
+ {
+ vuint<M> vgeomID = -1, vprimID = -1;
+ Vec3vf<M> va0 = zero, vb0 = zero, vc0 = zero;
+ Vec3vf<M> va1 = zero, vb1 = zero, vc1 = zero;
+
+ LBBox3fa allBounds = empty;
+ for (size_t i=0; i<M && begin<end; i++, begin++)
+ {
+ const PrimRefMB& prim = prims[begin];
+ const unsigned geomID = prim.geomID();
+ const unsigned primID = prim.primID();
+ const TriangleMesh* const mesh = scene->get<TriangleMesh>(geomID);
+ const range<int> itime_range = mesh->timeSegmentRange(time_range);
+ assert(itime_range.size() == 1);
+ const int ilower = itime_range.begin();
+ const TriangleMesh::Triangle& tri = mesh->triangle(primID);
+ allBounds.extend(mesh->linearBounds(primID, time_range));
+ const Vec3fa& a0 = mesh->vertex(tri.v[0],ilower+0);
+ const Vec3fa& a1 = mesh->vertex(tri.v[0],ilower+1);
+ const Vec3fa& b0 = mesh->vertex(tri.v[1],ilower+0);
+ const Vec3fa& b1 = mesh->vertex(tri.v[1],ilower+1);
+ const Vec3fa& c0 = mesh->vertex(tri.v[2],ilower+0);
+ const Vec3fa& c1 = mesh->vertex(tri.v[2],ilower+1);
+ const BBox1f time_range_v(mesh->timeStep(ilower+0),mesh->timeStep(ilower+1));
+ auto a01 = globalLinear(std::make_pair(a0,a1),time_range_v);
+ auto b01 = globalLinear(std::make_pair(b0,b1),time_range_v);
+ auto c01 = globalLinear(std::make_pair(c0,c1),time_range_v);
+ vgeomID [i] = geomID;
+ vprimID [i] = primID;
+ va0.x[i] = a01.first .x; va0.y[i] = a01.first .y; va0.z[i] = a01.first .z;
+ va1.x[i] = a01.second.x; va1.y[i] = a01.second.y; va1.z[i] = a01.second.z;
+ vb0.x[i] = b01.first .x; vb0.y[i] = b01.first .y; vb0.z[i] = b01.first .z;
+ vb1.x[i] = b01.second.x; vb1.y[i] = b01.second.y; vb1.z[i] = b01.second.z;
+ vc0.x[i] = c01.first .x; vc0.y[i] = c01.first .y; vc0.z[i] = c01.first .z;
+ vc1.x[i] = c01.second.x; vc1.y[i] = c01.second.y; vc1.z[i] = c01.second.z;
+ }
+ new (this) TriangleMvMB(va0,va1,vb0,vb1,vc0,vc1,vgeomID,vprimID);
+ return allBounds;
+ }
+
+ public:
+ Vec3vf<M> v0; // 1st vertex of the triangles
+ Vec3vf<M> v1; // 2nd vertex of the triangles
+ Vec3vf<M> v2; // 3rd vertex of the triangles
+ Vec3vf<M> dv0; // difference vector between time steps t0 and t1 for first vertex
+ Vec3vf<M> dv1; // difference vector between time steps t0 and t1 for second vertex
+ Vec3vf<M> dv2; // difference vector between time steps t0 and t1 for third vertex
+ private:
+ vuint<M> geomIDs; // geometry ID
+ vuint<M> primIDs; // primitive ID
+ };
+
+ template<int M>
+ typename TriangleMvMB<M>::Type TriangleMvMB<M>::type;
+
+ typedef TriangleMvMB<4> Triangle4vMB;
+}
diff --git a/thirdparty/embree/kernels/geometry/trianglev_mb_intersector.h b/thirdparty/embree/kernels/geometry/trianglev_mb_intersector.h
new file mode 100644
index 0000000000..38cd52e85d
--- /dev/null
+++ b/thirdparty/embree/kernels/geometry/trianglev_mb_intersector.h
@@ -0,0 +1,211 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "triangle.h"
+#include "intersector_epilog.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ /*! Intersects M motion blur triangles with 1 ray */
+ template<int M, bool filter>
+ struct TriangleMvMBIntersector1Moeller
+ {
+ typedef TriangleMvMB<M> Primitive;
+ typedef MoellerTrumboreIntersector1<M> Precalculations;
+
+ /*! Intersect a ray with the M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const Vec3vf<M> time(ray.time());
+ const Vec3vf<M> v0 = madd(time,Vec3vf<M>(tri.dv0),Vec3vf<M>(tri.v0));
+ const Vec3vf<M> v1 = madd(time,Vec3vf<M>(tri.dv1),Vec3vf<M>(tri.v1));
+ const Vec3vf<M> v2 = madd(time,Vec3vf<M>(tri.dv2),Vec3vf<M>(tri.v2));
+ pre.intersect(ray,v0,v1,v2,Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const Vec3vf<M> time(ray.time());
+ const Vec3vf<M> v0 = madd(time,Vec3vf<M>(tri.dv0),Vec3vf<M>(tri.v0));
+ const Vec3vf<M> v1 = madd(time,Vec3vf<M>(tri.dv1),Vec3vf<M>(tri.v1));
+ const Vec3vf<M> v2 = madd(time,Vec3vf<M>(tri.dv2),Vec3vf<M>(tri.v2));
+ return pre.intersect(ray,v0,v1,v2,Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M motion blur triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct TriangleMvMBIntersectorKMoeller
+ {
+ typedef TriangleMvMB<M> Primitive;
+ typedef MoellerTrumboreIntersectorK<M,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ for (size_t i=0; i<TriangleMvMB<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> time(ray.time());
+ const Vec3vf<K> v0 = madd(time,broadcast<vfloat<K>>(tri.dv0,i),broadcast<vfloat<K>>(tri.v0,i));
+ const Vec3vf<K> v1 = madd(time,broadcast<vfloat<K>>(tri.dv1,i),broadcast<vfloat<K>>(tri.v1,i));
+ const Vec3vf<K> v2 = madd(time,broadcast<vfloat<K>>(tri.dv2,i),broadcast<vfloat<K>>(tri.v2,i));
+ pre.intersectK(valid_i,ray,v0,v1,v2,IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<TriangleMvMB<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> time(ray.time());
+ const Vec3vf<K> v0 = madd(time,broadcast<vfloat<K>>(tri.dv0,i),broadcast<vfloat<K>>(tri.v0,i));
+ const Vec3vf<K> v1 = madd(time,broadcast<vfloat<K>>(tri.dv1,i),broadcast<vfloat<K>>(tri.v1,i));
+ const Vec3vf<K> v2 = madd(time,broadcast<vfloat<K>>(tri.dv2,i),broadcast<vfloat<K>>(tri.v2,i));
+ pre.intersectK(valid0,ray,v0,v1,v2,OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const Vec3vf<M> time(ray.time()[k]);
+ const Vec3vf<M> v0 = madd(time,Vec3vf<M>(tri.dv0),Vec3vf<M>(tri.v0));
+ const Vec3vf<M> v1 = madd(time,Vec3vf<M>(tri.dv1),Vec3vf<M>(tri.v1));
+ const Vec3vf<M> v2 = madd(time,Vec3vf<M>(tri.dv2),Vec3vf<M>(tri.v2));
+ pre.intersect(ray,k,v0,v1,v2,Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const Vec3vf<M> time(ray.time()[k]);
+ const Vec3vf<M> v0 = madd(time,Vec3vf<M>(tri.dv0),Vec3vf<M>(tri.v0));
+ const Vec3vf<M> v1 = madd(time,Vec3vf<M>(tri.dv1),Vec3vf<M>(tri.v1));
+ const Vec3vf<M> v2 = madd(time,Vec3vf<M>(tri.dv2),Vec3vf<M>(tri.v2));
+ return pre.intersect(ray,k,v0,v1,v2,Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+
+ /*! Intersects M motion blur triangles with 1 ray */
+ template<int M, bool filter>
+ struct TriangleMvMBIntersector1Pluecker
+ {
+ typedef TriangleMvMB<M> Primitive;
+ typedef PlueckerIntersector1<M> Precalculations;
+
+ /*! Intersect a ray with the M triangles and updates the hit. */
+ static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const Vec3vf<M> time(ray.time());
+ const Vec3vf<M> v0 = madd(time,Vec3vf<M>(tri.dv0),Vec3vf<M>(tri.v0));
+ const Vec3vf<M> v1 = madd(time,Vec3vf<M>(tri.dv1),Vec3vf<M>(tri.v1));
+ const Vec3vf<M> v2 = madd(time,Vec3vf<M>(tri.dv2),Vec3vf<M>(tri.v2));
+ pre.intersect(ray,v0,v1,v2,UVIdentity<M>(),Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of M triangles. */
+ static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const Vec3vf<M> time(ray.time());
+ const Vec3vf<M> v0 = madd(time,Vec3vf<M>(tri.dv0),Vec3vf<M>(tri.v0));
+ const Vec3vf<M> v1 = madd(time,Vec3vf<M>(tri.dv1),Vec3vf<M>(tri.v1));
+ const Vec3vf<M> v2 = madd(time,Vec3vf<M>(tri.dv2),Vec3vf<M>(tri.v2));
+ return pre.intersect(ray,v0,v1,v2,UVIdentity<M>(),Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID()));
+ }
+
+ static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& tri)
+ {
+ return PrimitivePointQuery1<Primitive>::pointQuery(query, context, tri);
+ }
+ };
+
+ /*! Intersects M motion blur triangles with K rays. */
+ template<int M, int K, bool filter>
+ struct TriangleMvMBIntersectorKPluecker
+ {
+ typedef TriangleMvMB<M> Primitive;
+ typedef PlueckerIntersectorK<M,K> Precalculations;
+
+ /*! Intersects K rays with M triangles. */
+ static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ for (size_t i=0; i<TriangleMvMB<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(normal.trav_prims,1,popcnt(valid_i),K);
+ const Vec3vf<K> time(ray.time());
+ const Vec3vf<K> v0 = madd(time,broadcast<vfloat<K>>(tri.dv0,i),broadcast<vfloat<K>>(tri.v0,i));
+ const Vec3vf<K> v1 = madd(time,broadcast<vfloat<K>>(tri.dv1,i),broadcast<vfloat<K>>(tri.v1,i));
+ const Vec3vf<K> v2 = madd(time,broadcast<vfloat<K>>(tri.dv2,i),broadcast<vfloat<K>>(tri.v2,i));
+ pre.intersectK(valid_i,ray,v0,v1,v2,UVIdentity<K>(),IntersectKEpilogM<M,K,filter>(ray,context,tri.geomID(),tri.primID(),i));
+ }
+ }
+
+ /*! Test for K rays if they are occluded by any of the M triangles. */
+ static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ vbool<K> valid0 = valid_i;
+
+ for (size_t i=0; i<TriangleMvMB<M>::max_size(); i++)
+ {
+ if (!tri.valid(i)) break;
+ STAT3(shadow.trav_prims,1,popcnt(valid0),K);
+ const Vec3vf<K> time(ray.time());
+ const Vec3vf<K> v0 = madd(time,broadcast<vfloat<K>>(tri.dv0,i),broadcast<vfloat<K>>(tri.v0,i));
+ const Vec3vf<K> v1 = madd(time,broadcast<vfloat<K>>(tri.dv1,i),broadcast<vfloat<K>>(tri.v1,i));
+ const Vec3vf<K> v2 = madd(time,broadcast<vfloat<K>>(tri.dv2,i),broadcast<vfloat<K>>(tri.v2,i));
+ pre.intersectK(valid0,ray,v0,v1,v2,UVIdentity<K>(),OccludedKEpilogM<M,K,filter>(valid0,ray,context,tri.geomID(),tri.primID(),i));
+ if (none(valid0)) break;
+ }
+ return !valid0;
+ }
+
+ /*! Intersect a ray with M triangles and updates the hit. */
+ static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(normal.trav_prims,1,1,1);
+ const Vec3vf<M> time(ray.time()[k]);
+ const Vec3vf<M> v0 = madd(time,Vec3vf<M>(tri.dv0),Vec3vf<M>(tri.v0));
+ const Vec3vf<M> v1 = madd(time,Vec3vf<M>(tri.dv1),Vec3vf<M>(tri.v1));
+ const Vec3vf<M> v2 = madd(time,Vec3vf<M>(tri.dv2),Vec3vf<M>(tri.v2));
+ pre.intersect(ray,k,v0,v1,v2,UVIdentity<M>(),Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+
+ /*! Test if the ray is occluded by one of the M triangles. */
+ static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri)
+ {
+ STAT3(shadow.trav_prims,1,1,1);
+ const Vec3vf<M> time(ray.time()[k]);
+ const Vec3vf<M> v0 = madd(time,Vec3vf<M>(tri.dv0),Vec3vf<M>(tri.v0));
+ const Vec3vf<M> v1 = madd(time,Vec3vf<M>(tri.dv1),Vec3vf<M>(tri.v1));
+ const Vec3vf<M> v2 = madd(time,Vec3vf<M>(tri.dv2),Vec3vf<M>(tri.v2));
+ return pre.intersect(ray,k,v0,v1,v2,UVIdentity<M>(),Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID()));
+ }
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/hash.h b/thirdparty/embree/kernels/hash.h
new file mode 100644
index 0000000000..10f315cee7
--- /dev/null
+++ b/thirdparty/embree/kernels/hash.h
@@ -0,0 +1,5 @@
+
+// Copyright 2009-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#define RTC_HASH "7c53133eb21424f7f0ae1e25bf357e358feaf6ab"
diff --git a/thirdparty/embree/kernels/subdiv/bezier_curve.h b/thirdparty/embree/kernels/subdiv/bezier_curve.h
new file mode 100644
index 0000000000..a5adad5cc9
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/bezier_curve.h
@@ -0,0 +1,671 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+//#include "../common/scene_curves.h"
+#include "../common/context.h"
+
+namespace embree
+{
+ class BezierBasis
+ {
+ public:
+
+ template<typename T>
+ static __forceinline Vec4<T> eval(const T& u)
+ {
+ const T t1 = u;
+ const T t0 = 1.0f-t1;
+ const T B0 = t0 * t0 * t0;
+ const T B1 = 3.0f * t1 * (t0 * t0);
+ const T B2 = 3.0f * (t1 * t1) * t0;
+ const T B3 = t1 * t1 * t1;
+ return Vec4<T>(B0,B1,B2,B3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative(const T& u)
+ {
+ const T t1 = u;
+ const T t0 = 1.0f-t1;
+ const T B0 = -(t0*t0);
+ const T B1 = madd(-2.0f,t0*t1,t0*t0);
+ const T B2 = msub(+2.0f,t0*t1,t1*t1);
+ const T B3 = +(t1*t1);
+ return T(3.0f)*Vec4<T>(B0,B1,B2,B3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative2(const T& u)
+ {
+ const T t1 = u;
+ const T t0 = 1.0f-t1;
+ const T B0 = t0;
+ const T B1 = madd(-2.0f,t0,t1);
+ const T B2 = madd(-2.0f,t1,t0);
+ const T B3 = t1;
+ return T(6.0f)*Vec4<T>(B0,B1,B2,B3);
+ }
+ };
+
+ struct PrecomputedBezierBasis
+ {
+ enum { N = 16 };
+ public:
+ PrecomputedBezierBasis() {}
+ PrecomputedBezierBasis(int shift);
+
+ /* basis for bezier evaluation */
+ public:
+ float c0[N+1][N+1];
+ float c1[N+1][N+1];
+ float c2[N+1][N+1];
+ float c3[N+1][N+1];
+
+ /* basis for bezier derivative evaluation */
+ public:
+ float d0[N+1][N+1];
+ float d1[N+1][N+1];
+ float d2[N+1][N+1];
+ float d3[N+1][N+1];
+ };
+ extern PrecomputedBezierBasis bezier_basis0;
+ extern PrecomputedBezierBasis bezier_basis1;
+
+
+ template<typename V>
+ struct LinearBezierCurve
+ {
+ V v0,v1;
+
+ __forceinline LinearBezierCurve () {}
+
+ __forceinline LinearBezierCurve (const LinearBezierCurve& other)
+ : v0(other.v0), v1(other.v1) {}
+
+ __forceinline LinearBezierCurve& operator= (const LinearBezierCurve& other) {
+ v0 = other.v0; v1 = other.v1; return *this;
+ }
+
+ __forceinline LinearBezierCurve (const V& v0, const V& v1)
+ : v0(v0), v1(v1) {}
+
+ __forceinline V begin() const { return v0; }
+ __forceinline V end () const { return v1; }
+
+ bool hasRoot() const;
+
+ friend embree_ostream operator<<(embree_ostream cout, const LinearBezierCurve& a) {
+ return cout << "LinearBezierCurve (" << a.v0 << ", " << a.v1 << ")";
+ }
+ };
+
+ template<> __forceinline bool LinearBezierCurve<Interval1f>::hasRoot() const {
+ return numRoots(v0,v1);
+ }
+
+ template<typename V>
+ struct QuadraticBezierCurve
+ {
+ V v0,v1,v2;
+
+ __forceinline QuadraticBezierCurve () {}
+
+ __forceinline QuadraticBezierCurve (const QuadraticBezierCurve& other)
+ : v0(other.v0), v1(other.v1), v2(other.v2) {}
+
+ __forceinline QuadraticBezierCurve& operator= (const QuadraticBezierCurve& other) {
+ v0 = other.v0; v1 = other.v1; v2 = other.v2; return *this;
+ }
+
+ __forceinline QuadraticBezierCurve (const V& v0, const V& v1, const V& v2)
+ : v0(v0), v1(v1), v2(v2) {}
+
+ __forceinline V begin() const { return v0; }
+ __forceinline V end () const { return v2; }
+
+ __forceinline V interval() const {
+ return merge(v0,v1,v2);
+ }
+
+ __forceinline BBox<V> bounds() const {
+ return merge(BBox<V>(v0),BBox<V>(v1),BBox<V>(v2));
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const QuadraticBezierCurve& a) {
+ return cout << "QuadraticBezierCurve ( (" << a.u.lower << ", " << a.u.upper << "), " << a.v0 << ", " << a.v1 << ", " << a.v2 << ")";
+ }
+ };
+
+
+ typedef QuadraticBezierCurve<float> QuadraticBezierCurve1f;
+ typedef QuadraticBezierCurve<Vec2fa> QuadraticBezierCurve2fa;
+ typedef QuadraticBezierCurve<Vec3fa> QuadraticBezierCurve3fa;
+
+ template<typename Vertex>
+ struct CubicBezierCurve
+ {
+ Vertex v0,v1,v2,v3;
+
+ __forceinline CubicBezierCurve() {}
+
+ template<typename T1>
+ __forceinline CubicBezierCurve (const CubicBezierCurve<T1>& other)
+ : v0(other.v0), v1(other.v1), v2(other.v2), v3(other.v3) {}
+
+ __forceinline CubicBezierCurve& operator= (const CubicBezierCurve& other) {
+ v0 = other.v0; v1 = other.v1; v2 = other.v2; v3 = other.v3; return *this;
+ }
+
+ __forceinline CubicBezierCurve(const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3)
+ : v0(v0), v1(v1), v2(v2), v3(v3) {}
+
+ __forceinline Vertex begin() const {
+ return v0;
+ }
+
+ __forceinline Vertex end() const {
+ return v3;
+ }
+
+ __forceinline Vertex center() const {
+ return 0.25f*(v0+v1+v2+v3);
+ }
+
+ __forceinline Vertex begin_direction() const {
+ return v1-v0;
+ }
+
+ __forceinline Vertex end_direction() const {
+ return v3-v2;
+ }
+
+ __forceinline CubicBezierCurve<float> xfm(const Vertex& dx) const {
+ return CubicBezierCurve<float>(dot(v0,dx),dot(v1,dx),dot(v2,dx),dot(v3,dx));
+ }
+
+ __forceinline CubicBezierCurve<vfloatx> vxfm(const Vertex& dx) const {
+ return CubicBezierCurve<vfloatx>(dot(v0,dx),dot(v1,dx),dot(v2,dx),dot(v3,dx));
+ }
+
+ __forceinline CubicBezierCurve<float> xfm(const Vertex& dx, const Vertex& p) const {
+ return CubicBezierCurve<float>(dot(v0-p,dx),dot(v1-p,dx),dot(v2-p,dx),dot(v3-p,dx));
+ }
+
+ __forceinline CubicBezierCurve<Vec3fa> xfm(const LinearSpace3fa& space) const
+ {
+ const Vec3fa q0 = xfmVector(space,v0);
+ const Vec3fa q1 = xfmVector(space,v1);
+ const Vec3fa q2 = xfmVector(space,v2);
+ const Vec3fa q3 = xfmVector(space,v3);
+ return CubicBezierCurve<Vec3fa>(q0,q1,q2,q3);
+ }
+
+ __forceinline CubicBezierCurve<Vec3fa> xfm(const LinearSpace3fa& space, const Vec3fa& p) const
+ {
+ const Vec3fa q0 = xfmVector(space,v0-p);
+ const Vec3fa q1 = xfmVector(space,v1-p);
+ const Vec3fa q2 = xfmVector(space,v2-p);
+ const Vec3fa q3 = xfmVector(space,v3-p);
+ return CubicBezierCurve<Vec3fa>(q0,q1,q2,q3);
+ }
+
+ __forceinline CubicBezierCurve<Vec3ff> xfm_pr(const LinearSpace3fa& space, const Vec3fa& p) const
+ {
+ const Vec3ff q0(xfmVector(space,(Vec3fa)v0-p), v0.w);
+ const Vec3ff q1(xfmVector(space,(Vec3fa)v1-p), v1.w);
+ const Vec3ff q2(xfmVector(space,(Vec3fa)v2-p), v2.w);
+ const Vec3ff q3(xfmVector(space,(Vec3fa)v3-p), v3.w);
+ return CubicBezierCurve<Vec3ff>(q0,q1,q2,q3);
+ }
+
+ __forceinline CubicBezierCurve<Vec3fa> xfm(const LinearSpace3fa& space, const Vec3fa& p, const float s) const
+ {
+ const Vec3fa q0 = xfmVector(space,s*(v0-p));
+ const Vec3fa q1 = xfmVector(space,s*(v1-p));
+ const Vec3fa q2 = xfmVector(space,s*(v2-p));
+ const Vec3fa q3 = xfmVector(space,s*(v3-p));
+ return CubicBezierCurve<Vec3fa>(q0,q1,q2,q3);
+ }
+
+ __forceinline int maxRoots() const;
+
+ __forceinline BBox<Vertex> bounds() const {
+ return merge(BBox<Vertex>(v0),BBox<Vertex>(v1),BBox<Vertex>(v2),BBox<Vertex>(v3));
+ }
+
+ __forceinline friend CubicBezierCurve operator +( const CubicBezierCurve& a, const CubicBezierCurve& b ) {
+ return CubicBezierCurve(a.v0+b.v0,a.v1+b.v1,a.v2+b.v2,a.v3+b.v3);
+ }
+
+ __forceinline friend CubicBezierCurve operator -( const CubicBezierCurve& a, const CubicBezierCurve& b ) {
+ return CubicBezierCurve(a.v0-b.v0,a.v1-b.v1,a.v2-b.v2,a.v3-b.v3);
+ }
+
+ __forceinline friend CubicBezierCurve operator -( const CubicBezierCurve& a, const Vertex& b ) {
+ return CubicBezierCurve(a.v0-b,a.v1-b,a.v2-b,a.v3-b);
+ }
+
+ __forceinline friend CubicBezierCurve operator *( const Vertex& a, const CubicBezierCurve& b ) {
+ return CubicBezierCurve(a*b.v0,a*b.v1,a*b.v2,a*b.v3);
+ }
+
+ __forceinline friend CubicBezierCurve cmadd( const Vertex& a, const CubicBezierCurve& b, const CubicBezierCurve& c) {
+ return CubicBezierCurve(madd(a,b.v0,c.v0),madd(a,b.v1,c.v1),madd(a,b.v2,c.v2),madd(a,b.v3,c.v3));
+ }
+
+ __forceinline friend CubicBezierCurve clerp ( const CubicBezierCurve& a, const CubicBezierCurve& b, const Vertex& t ) {
+ return cmadd((Vertex(1.0f)-t),a,t*b);
+ }
+
+ __forceinline friend CubicBezierCurve merge ( const CubicBezierCurve& a, const CubicBezierCurve& b ) {
+ return CubicBezierCurve(merge(a.v0,b.v0),merge(a.v1,b.v1),merge(a.v2,b.v2),merge(a.v3,b.v3));
+ }
+
+ __forceinline void split(CubicBezierCurve& left, CubicBezierCurve& right, const float t = 0.5f) const
+ {
+ const Vertex p00 = v0;
+ const Vertex p01 = v1;
+ const Vertex p02 = v2;
+ const Vertex p03 = v3;
+
+ const Vertex p10 = lerp(p00,p01,t);
+ const Vertex p11 = lerp(p01,p02,t);
+ const Vertex p12 = lerp(p02,p03,t);
+ const Vertex p20 = lerp(p10,p11,t);
+ const Vertex p21 = lerp(p11,p12,t);
+ const Vertex p30 = lerp(p20,p21,t);
+
+ new (&left ) CubicBezierCurve(p00,p10,p20,p30);
+ new (&right) CubicBezierCurve(p30,p21,p12,p03);
+ }
+
+ __forceinline CubicBezierCurve<Vec2vfx> split() const
+ {
+ const float u0 = 0.0f, u1 = 1.0f;
+ const float dscale = (u1-u0)*(1.0f/(3.0f*(VSIZEX-1)));
+ const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(VSIZEX-1)));
+ Vec2vfx P0, dP0du; evalN(vu0,P0,dP0du); dP0du = dP0du * Vec2vfx(dscale);
+ const Vec2vfx P3 = shift_right_1(P0);
+ const Vec2vfx dP3du = shift_right_1(dP0du);
+ const Vec2vfx P1 = P0 + dP0du;
+ const Vec2vfx P2 = P3 - dP3du;
+ return CubicBezierCurve<Vec2vfx>(P0,P1,P2,P3);
+ }
+
+ __forceinline CubicBezierCurve<Vec2vfx> split(const BBox1f& u) const
+ {
+ const float u0 = u.lower, u1 = u.upper;
+ const float dscale = (u1-u0)*(1.0f/(3.0f*(VSIZEX-1)));
+ const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(VSIZEX-1)));
+ Vec2vfx P0, dP0du; evalN(vu0,P0,dP0du); dP0du = dP0du * Vec2vfx(dscale);
+ const Vec2vfx P3 = shift_right_1(P0);
+ const Vec2vfx dP3du = shift_right_1(dP0du);
+ const Vec2vfx P1 = P0 + dP0du;
+ const Vec2vfx P2 = P3 - dP3du;
+ return CubicBezierCurve<Vec2vfx>(P0,P1,P2,P3);
+ }
+
+ __forceinline void eval(float t, Vertex& p, Vertex& dp) const
+ {
+ const Vertex p00 = v0;
+ const Vertex p01 = v1;
+ const Vertex p02 = v2;
+ const Vertex p03 = v3;
+
+ const Vertex p10 = lerp(p00,p01,t);
+ const Vertex p11 = lerp(p01,p02,t);
+ const Vertex p12 = lerp(p02,p03,t);
+ const Vertex p20 = lerp(p10,p11,t);
+ const Vertex p21 = lerp(p11,p12,t);
+ const Vertex p30 = lerp(p20,p21,t);
+
+ p = p30;
+ dp = Vertex(3.0f)*(p21-p20);
+ }
+
+#if 0
+ __forceinline Vertex eval(float t) const
+ {
+ const Vertex p00 = v0;
+ const Vertex p01 = v1;
+ const Vertex p02 = v2;
+ const Vertex p03 = v3;
+
+ const Vertex p10 = lerp(p00,p01,t);
+ const Vertex p11 = lerp(p01,p02,t);
+ const Vertex p12 = lerp(p02,p03,t);
+ const Vertex p20 = lerp(p10,p11,t);
+ const Vertex p21 = lerp(p11,p12,t);
+ const Vertex p30 = lerp(p20,p21,t);
+
+ return p30;
+ }
+#else
+ __forceinline Vertex eval(const float t) const
+ {
+ const Vec4<float> b = BezierBasis::eval(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+#endif
+
+ __forceinline Vertex eval_dt(float t) const
+ {
+ const Vertex p00 = v1-v0;
+ const Vertex p01 = v2-v1;
+ const Vertex p02 = v3-v2;
+ const Vertex p10 = lerp(p00,p01,t);
+ const Vertex p11 = lerp(p01,p02,t);
+ const Vertex p20 = lerp(p10,p11,t);
+ return Vertex(3.0f)*p20;
+ }
+
+ __forceinline Vertex eval_du(const float t) const
+ {
+ const Vec4<float> b = BezierBasis::derivative(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline Vertex eval_dudu(const float t) const
+ {
+ const Vec4<float> b = BezierBasis::derivative2(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline void evalN(const vfloatx& t, Vec2vfx& p, Vec2vfx& dp) const
+ {
+ const Vec2vfx p00 = v0;
+ const Vec2vfx p01 = v1;
+ const Vec2vfx p02 = v2;
+ const Vec2vfx p03 = v3;
+
+ const Vec2vfx p10 = lerp(p00,p01,t);
+ const Vec2vfx p11 = lerp(p01,p02,t);
+ const Vec2vfx p12 = lerp(p02,p03,t);
+
+ const Vec2vfx p20 = lerp(p10,p11,t);
+ const Vec2vfx p21 = lerp(p11,p12,t);
+
+ const Vec2vfx p30 = lerp(p20,p21,t);
+
+ p = p30;
+ dp = vfloatx(3.0f)*(p21-p20);
+ }
+
+ __forceinline void eval(const float t, Vertex& p, Vertex& dp, Vertex& ddp) const
+ {
+ const Vertex p00 = v0;
+ const Vertex p01 = v1;
+ const Vertex p02 = v2;
+ const Vertex p03 = v3;
+ const Vertex p10 = lerp(p00,p01,t);
+ const Vertex p11 = lerp(p01,p02,t);
+ const Vertex p12 = lerp(p02,p03,t);
+ const Vertex p20 = lerp(p10,p11,t);
+ const Vertex p21 = lerp(p11,p12,t);
+ const Vertex p30 = lerp(p20,p21,t);
+ p = p30;
+ dp = 3.0f*(p21-p20);
+ ddp = eval_dudu(t);
+ }
+
+ __forceinline CubicBezierCurve clip(const Interval1f& u1) const
+ {
+ Vertex f0,df0; eval(u1.lower,f0,df0);
+ Vertex f1,df1; eval(u1.upper,f1,df1);
+ float s = u1.upper-u1.lower;
+ return CubicBezierCurve(f0,f0+s*(1.0f/3.0f)*df0,f1-s*(1.0f/3.0f)*df1,f1);
+ }
+
+ __forceinline QuadraticBezierCurve<Vertex> derivative() const
+ {
+ const Vertex q0 = 3.0f*(v1-v0);
+ const Vertex q1 = 3.0f*(v2-v1);
+ const Vertex q2 = 3.0f*(v3-v2);
+ return QuadraticBezierCurve<Vertex>(q0,q1,q2);
+ }
+
+ __forceinline BBox<Vertex> derivative_bounds(const Interval1f& u1) const
+ {
+ Vertex f0,df0; eval(u1.lower,f0,df0);
+ Vertex f3,df3; eval(u1.upper,f3,df3);
+ const float s = u1.upper-u1.lower;
+ const Vertex f1 = f0+s*(1.0f/3.0f)*df0;
+ const Vertex f2 = f3-s*(1.0f/3.0f)*df3;
+ const Vertex q0 = s*df0;
+ const Vertex q1 = 3.0f*(f2-f1);
+ const Vertex q2 = s*df3;
+ return merge(BBox<Vertex>(q0),BBox<Vertex>(q1),BBox<Vertex>(q2));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BezierBasis::eval(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_du(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BezierBasis::derivative(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_dudu(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BezierBasis::derivative2(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline void veval(const vfloat<M>& t, Vec4vf<M>& p, Vec4vf<M>& dp) const
+ {
+ const Vec4vf<M> p00 = v0;
+ const Vec4vf<M> p01 = v1;
+ const Vec4vf<M> p02 = v2;
+ const Vec4vf<M> p03 = v3;
+
+ const Vec4vf<M> p10 = lerp(p00,p01,t);
+ const Vec4vf<M> p11 = lerp(p01,p02,t);
+ const Vec4vf<M> p12 = lerp(p02,p03,t);
+ const Vec4vf<M> p20 = lerp(p10,p11,t);
+ const Vec4vf<M> p21 = lerp(p11,p12,t);
+ const Vec4vf<M> p30 = lerp(p20,p21,t);
+
+ p = p30;
+ dp = vfloat<M>(3.0f)*(p21-p20);
+ }
+
+ template<int M, typename Vec = Vec4vf<M>>
+ __forceinline Vec eval0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBezierBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bezier_basis0.c0[size][ofs]), Vec(v0),
+ madd(vfloat<M>::loadu(&bezier_basis0.c1[size][ofs]), Vec(v1),
+ madd(vfloat<M>::loadu(&bezier_basis0.c2[size][ofs]), Vec(v2),
+ vfloat<M>::loadu(&bezier_basis0.c3[size][ofs]) * Vec(v3))));
+ }
+
+ template<int M, typename Vec = Vec4vf<M>>
+ __forceinline Vec eval1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBezierBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bezier_basis1.c0[size][ofs]), Vec(v0),
+ madd(vfloat<M>::loadu(&bezier_basis1.c1[size][ofs]), Vec(v1),
+ madd(vfloat<M>::loadu(&bezier_basis1.c2[size][ofs]), Vec(v2),
+ vfloat<M>::loadu(&bezier_basis1.c3[size][ofs]) * Vec(v3))));
+ }
+
+ template<int M, typename Vec = Vec4vf<M>>
+ __forceinline Vec derivative0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBezierBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bezier_basis0.d0[size][ofs]), Vec(v0),
+ madd(vfloat<M>::loadu(&bezier_basis0.d1[size][ofs]), Vec(v1),
+ madd(vfloat<M>::loadu(&bezier_basis0.d2[size][ofs]), Vec(v2),
+ vfloat<M>::loadu(&bezier_basis0.d3[size][ofs]) * Vec(v3))));
+ }
+
+ template<int M, typename Vec = Vec4vf<M>>
+ __forceinline Vec derivative1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBezierBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bezier_basis1.d0[size][ofs]), Vec(v0),
+ madd(vfloat<M>::loadu(&bezier_basis1.d1[size][ofs]), Vec(v1),
+ madd(vfloat<M>::loadu(&bezier_basis1.d2[size][ofs]), Vec(v2),
+ vfloat<M>::loadu(&bezier_basis1.d3[size][ofs]) * Vec(v3))));
+ }
+
+ /* calculates bounds of bezier curve geometry */
+ __forceinline BBox3fa accurateBounds() const
+ {
+ const int N = 7;
+ const float scale = 1.0f/(3.0f*(N-1));
+ Vec3vfx pl(pos_inf), pu(neg_inf);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vintx vi = vintx(i)+vintx(step);
+ vboolx valid = vi <= vintx(N);
+ const Vec3vfx p = eval0<VSIZEX,Vec3vf<VSIZEX>>(i,N);
+ const Vec3vfx dp = derivative0<VSIZEX,Vec3vf<VSIZEX>>(i,N);
+ const Vec3vfx pm = p-Vec3vfx(scale)*select(vi!=vintx(0),dp,Vec3vfx(zero));
+ const Vec3vfx pp = p+Vec3vfx(scale)*select(vi!=vintx(N),dp,Vec3vfx(zero));
+ pl = select(valid,min(pl,p,pm,pp),pl); // FIXME: use masked min
+ pu = select(valid,max(pu,p,pm,pp),pu); // FIXME: use masked min
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ return BBox3fa(lower,upper);
+ }
+
+ /* calculates bounds of bezier curve geometry */
+ __forceinline BBox3fa accurateRoundBounds() const
+ {
+ const int N = 7;
+ const float scale = 1.0f/(3.0f*(N-1));
+ Vec4vfx pl(pos_inf), pu(neg_inf);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vintx vi = vintx(i)+vintx(step);
+ vboolx valid = vi <= vintx(N);
+ const Vec4vfx p = eval0<VSIZEX>(i,N);
+ const Vec4vfx dp = derivative0<VSIZEX>(i,N);
+ const Vec4vfx pm = p-Vec4vfx(scale)*select(vi!=vintx(0),dp,Vec4vfx(zero));
+ const Vec4vfx pp = p+Vec4vfx(scale)*select(vi!=vintx(N),dp,Vec4vfx(zero));
+ pl = select(valid,min(pl,p,pm,pp),pl); // FIXME: use masked min
+ pu = select(valid,max(pu,p,pm,pp),pu); // FIXME: use masked min
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const float r_min = reduce_min(pl.w);
+ const float r_max = reduce_max(pu.w);
+ const Vec3fa upper_r = Vec3fa(max(abs(r_min),abs(r_max)));
+ return enlarge(BBox3fa(lower,upper),upper_r);
+ }
+
+ /* calculates bounds when tessellated into N line segments */
+ __forceinline BBox3fa accurateFlatBounds(int N) const
+ {
+ if (likely(N == 4))
+ {
+ const Vec4vf4 pi = eval0<4>(0,4);
+ const Vec3fa lower(reduce_min(pi.x),reduce_min(pi.y),reduce_min(pi.z));
+ const Vec3fa upper(reduce_max(pi.x),reduce_max(pi.y),reduce_max(pi.z));
+ const Vec3fa upper_r = Vec3fa(reduce_max(abs(pi.w)));
+ return enlarge(BBox3fa(min(lower,v3),max(upper,v3)),max(upper_r,Vec3fa(abs(v3.w))));
+ }
+ else
+ {
+ Vec3vfx pl(pos_inf), pu(neg_inf); vfloatx ru(0.0f);
+ for (int i=0; i<N; i+=VSIZEX)
+ {
+ vboolx valid = vintx(i)+vintx(step) < vintx(N);
+ const Vec4vfx pi = eval0<VSIZEX>(i,N);
+
+ pl.x = select(valid,min(pl.x,pi.x),pl.x); // FIXME: use masked min
+ pl.y = select(valid,min(pl.y,pi.y),pl.y);
+ pl.z = select(valid,min(pl.z,pi.z),pl.z);
+
+ pu.x = select(valid,max(pu.x,pi.x),pu.x); // FIXME: use masked min
+ pu.y = select(valid,max(pu.y,pi.y),pu.y);
+ pu.z = select(valid,max(pu.z,pi.z),pu.z);
+
+ ru = select(valid,max(ru,abs(pi.w)),ru);
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const Vec3fa upper_r(reduce_max(ru));
+ return enlarge(BBox3fa(min(lower,v3),max(upper,v3)),max(upper_r,Vec3fa(abs(v3.w))));
+ }
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const CubicBezierCurve& curve) {
+ return cout << "CubicBezierCurve { v0 = " << curve.v0 << ", v1 = " << curve.v1 << ", v2 = " << curve.v2 << ", v3 = " << curve.v3 << " }";
+ }
+ };
+
+#if defined(__AVX__)
+ template<>
+ __forceinline CubicBezierCurve<vfloat4> CubicBezierCurve<vfloat4>::clip(const Interval1f& u1) const
+ {
+ const vfloat8 p00 = vfloat8(v0);
+ const vfloat8 p01 = vfloat8(v1);
+ const vfloat8 p02 = vfloat8(v2);
+ const vfloat8 p03 = vfloat8(v3);
+
+ const vfloat8 t(vfloat4(u1.lower),vfloat4(u1.upper));
+ const vfloat8 p10 = lerp(p00,p01,t);
+ const vfloat8 p11 = lerp(p01,p02,t);
+ const vfloat8 p12 = lerp(p02,p03,t);
+ const vfloat8 p20 = lerp(p10,p11,t);
+ const vfloat8 p21 = lerp(p11,p12,t);
+ const vfloat8 p30 = lerp(p20,p21,t);
+
+ const vfloat8 f01 = p30;
+ const vfloat8 df01 = vfloat8(3.0f)*(p21-p20);
+
+ const vfloat4 f0 = extract4<0>(f01), f1 = extract4<1>(f01);
+ const vfloat4 df0 = extract4<0>(df01), df1 = extract4<1>(df01);
+ const float s = u1.upper-u1.lower;
+ return CubicBezierCurve(f0,f0+s*(1.0f/3.0f)*df0,f1-s*(1.0f/3.0f)*df1,f1);
+ }
+#endif
+
+ template<typename Vertex> using BezierCurveT = CubicBezierCurve<Vertex>;
+
+ typedef CubicBezierCurve<float> CubicBezierCurve1f;
+ typedef CubicBezierCurve<Vec2fa> CubicBezierCurve2fa;
+ typedef CubicBezierCurve<Vec3fa> CubicBezierCurve3fa;
+ typedef CubicBezierCurve<Vec3fa> BezierCurve3fa;
+
+ template<> __forceinline int CubicBezierCurve<float>::maxRoots() const
+ {
+ float eps = 1E-4f;
+ bool neg0 = v0 <= 0.0f; bool zero0 = fabs(v0) < eps;
+ bool neg1 = v1 <= 0.0f; bool zero1 = fabs(v1) < eps;
+ bool neg2 = v2 <= 0.0f; bool zero2 = fabs(v2) < eps;
+ bool neg3 = v3 <= 0.0f; bool zero3 = fabs(v3) < eps;
+ return (neg0 != neg1 || zero0) + (neg1 != neg2 || zero1) + (neg2 != neg3 || zero2 || zero3);
+ }
+
+ template<> __forceinline int CubicBezierCurve<Interval1f>::maxRoots() const {
+ return numRoots(v0,v1) + numRoots(v1,v2) + numRoots(v2,v3);
+ }
+
+ template<typename CurveGeometry>
+ __forceinline CubicBezierCurve<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const CubicBezierCurve<Vec3ff>& curve)
+ {
+ return CubicBezierCurve<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,curve.v0),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v1),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v2),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v3));
+ }
+}
diff --git a/thirdparty/embree/kernels/subdiv/bezier_patch.h b/thirdparty/embree/kernels/subdiv/bezier_patch.h
new file mode 100644
index 0000000000..2ff03902a7
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/bezier_patch.h
@@ -0,0 +1,372 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_patch.h"
+#include "bezier_curve.h"
+
+namespace embree
+{
+ template<class T, class S>
+ static __forceinline T deCasteljau(const S& uu, const T& v0, const T& v1, const T& v2, const T& v3)
+ {
+ const T v0_1 = lerp(v0,v1,uu);
+ const T v1_1 = lerp(v1,v2,uu);
+ const T v2_1 = lerp(v2,v3,uu);
+ const T v0_2 = lerp(v0_1,v1_1,uu);
+ const T v1_2 = lerp(v1_1,v2_1,uu);
+ const T v0_3 = lerp(v0_2,v1_2,uu);
+ return v0_3;
+ }
+
+ template<class T, class S>
+ static __forceinline T deCasteljau_tangent(const S& uu, const T& v0, const T& v1, const T& v2, const T& v3)
+ {
+ const T v0_1 = lerp(v0,v1,uu);
+ const T v1_1 = lerp(v1,v2,uu);
+ const T v2_1 = lerp(v2,v3,uu);
+ const T v0_2 = lerp(v0_1,v1_1,uu);
+ const T v1_2 = lerp(v1_1,v2_1,uu);
+ return S(3.0f)*(v1_2-v0_2);
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeInnerBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) {
+ return 1.0f / 36.0f * (16.0f * v[y][x] + 4.0f * (v[y-1][x] + v[y+1][x] + v[y][x-1] + v[y][x+1]) + (v[y-1][x-1] + v[y+1][x+1] + v[y-1][x+1] + v[y+1][x-1]));
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeTopEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) {
+ return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y-1][x] + 2.0f * (v[y][x-1] + v[y][x+1]) + (v[y-1][x-1] + v[y-1][x+1]));
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeBottomEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) {
+ return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y+1][x] + 2.0f * (v[y][x-1] + v[y][x+1]) + v[y+1][x-1] + v[y+1][x+1]);
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeLeftEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) {
+ return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y][x-1] + 2.0f * (v[y-1][x] + v[y+1][x]) + v[y-1][x-1] + v[y+1][x-1]);
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeRightEdgeBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x) {
+ return 1.0f / 18.0f * (8.0f * v[y][x] + 4.0f * v[y][x+1] + 2.0f * (v[y-1][x] + v[y+1][x]) + v[y-1][x+1] + v[y+1][x+1]);
+ }
+
+ template<typename Vertex>
+ __forceinline Vertex computeCornerBezierControlPoint(const Vertex v[4][4], const size_t y, const size_t x, const ssize_t delta_y, const ssize_t delta_x)
+ {
+ return 1.0f / 9.0f * (4.0f * v[y][x] + 2.0f * (v[y+delta_y][x] + v[y][x+delta_x]) + v[y+delta_y][x+delta_x]);
+ }
+
+ template<typename Vertex, typename Vertex_t>
+ class __aligned(64) BezierPatchT
+ {
+ public:
+ Vertex matrix[4][4];
+
+ public:
+
+ __forceinline BezierPatchT() {}
+
+ __forceinline BezierPatchT (const HalfEdge* edge, const char* vertices, size_t stride);
+
+ __forceinline BezierPatchT(const CatmullClarkPatchT<Vertex,Vertex_t>& patch);
+
+ __forceinline BezierPatchT(const CatmullClarkPatchT<Vertex,Vertex_t>& patch,
+ const BezierCurveT<Vertex>* border0,
+ const BezierCurveT<Vertex>* border1,
+ const BezierCurveT<Vertex>* border2,
+ const BezierCurveT<Vertex>* border3);
+
+ __forceinline BezierPatchT(const BSplinePatchT<Vertex,Vertex_t>& source)
+ {
+ /* compute inner bezier control points */
+ matrix[0][0] = computeInnerBezierControlPoint(source.v,1,1);
+ matrix[0][3] = computeInnerBezierControlPoint(source.v,1,2);
+ matrix[3][3] = computeInnerBezierControlPoint(source.v,2,2);
+ matrix[3][0] = computeInnerBezierControlPoint(source.v,2,1);
+
+ /* compute top edge control points */
+ matrix[0][1] = computeRightEdgeBezierControlPoint(source.v,1,1);
+ matrix[0][2] = computeLeftEdgeBezierControlPoint(source.v,1,2);
+
+ /* compute buttom edge control points */
+ matrix[3][1] = computeRightEdgeBezierControlPoint(source.v,2,1);
+ matrix[3][2] = computeLeftEdgeBezierControlPoint(source.v,2,2);
+
+ /* compute left edge control points */
+ matrix[1][0] = computeBottomEdgeBezierControlPoint(source.v,1,1);
+ matrix[2][0] = computeTopEdgeBezierControlPoint(source.v,2,1);
+
+ /* compute right edge control points */
+ matrix[1][3] = computeBottomEdgeBezierControlPoint(source.v,1,2);
+ matrix[2][3] = computeTopEdgeBezierControlPoint(source.v,2,2);
+
+ /* compute corner control points */
+ matrix[1][1] = computeCornerBezierControlPoint(source.v,1,1, 1, 1);
+ matrix[1][2] = computeCornerBezierControlPoint(source.v,1,2, 1,-1);
+ matrix[2][2] = computeCornerBezierControlPoint(source.v,2,2,-1,-1);
+ matrix[2][1] = computeCornerBezierControlPoint(source.v,2,1,-1, 1);
+ }
+
+ static __forceinline Vertex_t bilinear(const Vec4f Bu, const Vertex matrix[4][4], const Vec4f Bv)
+ {
+ const Vertex_t M0 = madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3])));
+ const Vertex_t M1 = madd(Bu.x,matrix[1][0],madd(Bu.y,matrix[1][1],madd(Bu.z,matrix[1][2],Bu.w * matrix[1][3])));
+ const Vertex_t M2 = madd(Bu.x,matrix[2][0],madd(Bu.y,matrix[2][1],madd(Bu.z,matrix[2][2],Bu.w * matrix[2][3])));
+ const Vertex_t M3 = madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3])));
+ return madd(Bv.x,M0,madd(Bv.y,M1,madd(Bv.z,M2,Bv.w*M3)));
+ }
+
+ static __forceinline Vertex_t eval(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::eval(uu);
+ const Vec4f Bv = BezierBasis::eval(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t eval_du(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::derivative(uu);
+ const Vec4f Bv = BezierBasis::eval(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t eval_dv(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::eval(uu);
+ const Vec4f Bv = BezierBasis::derivative(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t eval_dudu(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::derivative2(uu);
+ const Vec4f Bv = BezierBasis::eval(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t eval_dvdv(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::eval(uu);
+ const Vec4f Bv = BezierBasis::derivative2(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t eval_dudv(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vec4f Bu = BezierBasis::derivative(uu);
+ const Vec4f Bv = BezierBasis::derivative(vv);
+ return bilinear(Bu,matrix,Bv);
+ }
+
+ static __forceinline Vertex_t normal(const Vertex matrix[4][4], const float uu, const float vv)
+ {
+ const Vertex_t dPdu = eval_du(matrix,uu,vv);
+ const Vertex_t dPdv = eval_dv(matrix,uu,vv);
+ return cross(dPdu,dPdv);
+ }
+
+ __forceinline Vertex_t normal(const float uu, const float vv)
+ {
+ const Vertex_t dPdu = eval_du(matrix,uu,vv);
+ const Vertex_t dPdv = eval_dv(matrix,uu,vv);
+ return cross(dPdu,dPdv);
+ }
+
+ __forceinline Vertex_t eval(const float uu, const float vv) const {
+ return eval(matrix,uu,vv);
+ }
+
+ __forceinline Vertex_t eval_du(const float uu, const float vv) const {
+ return eval_du(matrix,uu,vv);
+ }
+
+ __forceinline Vertex_t eval_dv(const float uu, const float vv) const {
+ return eval_dv(matrix,uu,vv);
+ }
+
+ __forceinline Vertex_t eval_dudu(const float uu, const float vv) const {
+ return eval_dudu(matrix,uu,vv);
+ }
+
+ __forceinline Vertex_t eval_dvdv(const float uu, const float vv) const {
+ return eval_dvdv(matrix,uu,vv);
+ }
+
+ __forceinline Vertex_t eval_dudv(const float uu, const float vv) const {
+ return eval_dudv(matrix,uu,vv);
+ }
+
+ __forceinline void eval(const float u, const float v, Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv, const float dscale = 1.0f) const
+ {
+ if (P) {
+ *P = eval(u,v);
+ }
+ if (dPdu) {
+ assert(dPdu); *dPdu = eval_du(u,v)*dscale;
+ assert(dPdv); *dPdv = eval_dv(u,v)*dscale;
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(dscale);
+ assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(dscale);
+ assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(dscale);
+ }
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval(const size_t i, const vfloat& uu, const vfloat& vv, const Vec4<vfloat>& u_n, const Vec4<vfloat>& v_n) const
+ {
+ const vfloat curve0_x = v_n[0] * vfloat(matrix[0][0][i]) + v_n[1] * vfloat(matrix[1][0][i]) + v_n[2] * vfloat(matrix[2][0][i]) + v_n[3] * vfloat(matrix[3][0][i]);
+ const vfloat curve1_x = v_n[0] * vfloat(matrix[0][1][i]) + v_n[1] * vfloat(matrix[1][1][i]) + v_n[2] * vfloat(matrix[2][1][i]) + v_n[3] * vfloat(matrix[3][1][i]);
+ const vfloat curve2_x = v_n[0] * vfloat(matrix[0][2][i]) + v_n[1] * vfloat(matrix[1][2][i]) + v_n[2] * vfloat(matrix[2][2][i]) + v_n[3] * vfloat(matrix[3][2][i]);
+ const vfloat curve3_x = v_n[0] * vfloat(matrix[0][3][i]) + v_n[1] * vfloat(matrix[1][3][i]) + v_n[2] * vfloat(matrix[2][3][i]) + v_n[3] * vfloat(matrix[3][3][i]);
+ return u_n[0] * curve0_x + u_n[1] * curve1_x + u_n[2] * curve2_x + u_n[3] * curve3_x;
+ }
+
+ template<typename vbool, typename vfloat>
+ __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
+ const float dscale, const size_t dstride, const size_t N) const
+ {
+ if (P) {
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,P+i*dstride,eval(i,uu,vv,u_n,v_n));
+ }
+ if (dPdu)
+ {
+ {
+ assert(dPdu);
+ const Vec4<vfloat> u_n = BezierBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,dPdu+i*dstride,eval(i,uu,vv,u_n,v_n)*dscale);
+ }
+ {
+ assert(dPdv);
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,dPdv+i*dstride,eval(i,uu,vv,u_n,v_n)*dscale);
+ }
+ }
+ if (ddPdudu)
+ {
+ {
+ assert(ddPdudu);
+ const Vec4<vfloat> u_n = BezierBasis::derivative2(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdudu+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ {
+ assert(ddPdvdv);
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative2(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdvdv+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ {
+ assert(ddPdudv);
+ const Vec4<vfloat> u_n = BezierBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdudv+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ }
+ }
+
+ template<typename T>
+ static __forceinline Vec3<T> eval(const Vertex matrix[4][4], const T& uu, const T& vv)
+ {
+ const T one_minus_uu = 1.0f - uu;
+ const T one_minus_vv = 1.0f - vv;
+
+ const T B0_u = one_minus_uu * one_minus_uu * one_minus_uu;
+ const T B0_v = one_minus_vv * one_minus_vv * one_minus_vv;
+ const T B1_u = 3.0f * (one_minus_uu * uu * one_minus_uu);
+ const T B1_v = 3.0f * (one_minus_vv * vv * one_minus_vv);
+ const T B2_u = 3.0f * (uu * one_minus_uu * uu);
+ const T B2_v = 3.0f * (vv * one_minus_vv * vv);
+ const T B3_u = uu * uu * uu;
+ const T B3_v = vv * vv * vv;
+
+ const T x =
+ madd(B0_v,madd(B0_u,matrix[0][0].x,madd(B1_u,matrix[0][1].x,madd(B2_u,matrix[0][2].x,B3_u*matrix[0][3].x))),
+ madd(B1_v,madd(B0_u,matrix[1][0].x,madd(B1_u,matrix[1][1].x,madd(B2_u,matrix[1][2].x,B3_u*matrix[1][3].x))),
+ madd(B2_v,madd(B0_u,matrix[2][0].x,madd(B1_u,matrix[2][1].x,madd(B2_u,matrix[2][2].x,B3_u*matrix[2][3].x))),
+ B3_v*madd(B0_u,matrix[3][0].x,madd(B1_u,matrix[3][1].x,madd(B2_u,matrix[3][2].x,B3_u*matrix[3][3].x))))));
+
+ const T y =
+ madd(B0_v,madd(B0_u,matrix[0][0].y,madd(B1_u,matrix[0][1].y,madd(B2_u,matrix[0][2].y,B3_u*matrix[0][3].y))),
+ madd(B1_v,madd(B0_u,matrix[1][0].y,madd(B1_u,matrix[1][1].y,madd(B2_u,matrix[1][2].y,B3_u*matrix[1][3].y))),
+ madd(B2_v,madd(B0_u,matrix[2][0].y,madd(B1_u,matrix[2][1].y,madd(B2_u,matrix[2][2].y,B3_u*matrix[2][3].y))),
+ B3_v*madd(B0_u,matrix[3][0].y,madd(B1_u,matrix[3][1].y,madd(B2_u,matrix[3][2].y,B3_u*matrix[3][3].y))))));
+
+ const T z =
+ madd(B0_v,madd(B0_u,matrix[0][0].z,madd(B1_u,matrix[0][1].z,madd(B2_u,matrix[0][2].z,B3_u*matrix[0][3].z))),
+ madd(B1_v,madd(B0_u,matrix[1][0].z,madd(B1_u,matrix[1][1].z,madd(B2_u,matrix[1][2].z,B3_u*matrix[1][3].z))),
+ madd(B2_v,madd(B0_u,matrix[2][0].z,madd(B1_u,matrix[2][1].z,madd(B2_u,matrix[2][2].z,B3_u*matrix[2][3].z))),
+ B3_v*madd(B0_u,matrix[3][0].z,madd(B1_u,matrix[3][1].z,madd(B2_u,matrix[3][2].z,B3_u*matrix[3][3].z))))));
+
+ return Vec3<T>(x,y,z);
+ }
+
+ template<typename vfloat>
+ __forceinline Vec3<vfloat> eval(const vfloat& uu, const vfloat& vv) const {
+ return eval(matrix,uu,vv);
+ }
+
+ template<class T>
+ static __forceinline Vec3<T> normal(const Vertex matrix[4][4], const T& uu, const T& vv)
+ {
+
+ const Vec3<T> matrix_00 = Vec3<T>(matrix[0][0].x,matrix[0][0].y,matrix[0][0].z);
+ const Vec3<T> matrix_01 = Vec3<T>(matrix[0][1].x,matrix[0][1].y,matrix[0][1].z);
+ const Vec3<T> matrix_02 = Vec3<T>(matrix[0][2].x,matrix[0][2].y,matrix[0][2].z);
+ const Vec3<T> matrix_03 = Vec3<T>(matrix[0][3].x,matrix[0][3].y,matrix[0][3].z);
+
+ const Vec3<T> matrix_10 = Vec3<T>(matrix[1][0].x,matrix[1][0].y,matrix[1][0].z);
+ const Vec3<T> matrix_11 = Vec3<T>(matrix[1][1].x,matrix[1][1].y,matrix[1][1].z);
+ const Vec3<T> matrix_12 = Vec3<T>(matrix[1][2].x,matrix[1][2].y,matrix[1][2].z);
+ const Vec3<T> matrix_13 = Vec3<T>(matrix[1][3].x,matrix[1][3].y,matrix[1][3].z);
+
+ const Vec3<T> matrix_20 = Vec3<T>(matrix[2][0].x,matrix[2][0].y,matrix[2][0].z);
+ const Vec3<T> matrix_21 = Vec3<T>(matrix[2][1].x,matrix[2][1].y,matrix[2][1].z);
+ const Vec3<T> matrix_22 = Vec3<T>(matrix[2][2].x,matrix[2][2].y,matrix[2][2].z);
+ const Vec3<T> matrix_23 = Vec3<T>(matrix[2][3].x,matrix[2][3].y,matrix[2][3].z);
+
+ const Vec3<T> matrix_30 = Vec3<T>(matrix[3][0].x,matrix[3][0].y,matrix[3][0].z);
+ const Vec3<T> matrix_31 = Vec3<T>(matrix[3][1].x,matrix[3][1].y,matrix[3][1].z);
+ const Vec3<T> matrix_32 = Vec3<T>(matrix[3][2].x,matrix[3][2].y,matrix[3][2].z);
+ const Vec3<T> matrix_33 = Vec3<T>(matrix[3][3].x,matrix[3][3].y,matrix[3][3].z);
+
+ /* tangentU */
+ const Vec3<T> col0 = deCasteljau(vv, matrix_00, matrix_10, matrix_20, matrix_30);
+ const Vec3<T> col1 = deCasteljau(vv, matrix_01, matrix_11, matrix_21, matrix_31);
+ const Vec3<T> col2 = deCasteljau(vv, matrix_02, matrix_12, matrix_22, matrix_32);
+ const Vec3<T> col3 = deCasteljau(vv, matrix_03, matrix_13, matrix_23, matrix_33);
+
+ const Vec3<T> tangentU = deCasteljau_tangent(uu, col0, col1, col2, col3);
+
+ /* tangentV */
+ const Vec3<T> row0 = deCasteljau(uu, matrix_00, matrix_01, matrix_02, matrix_03);
+ const Vec3<T> row1 = deCasteljau(uu, matrix_10, matrix_11, matrix_12, matrix_13);
+ const Vec3<T> row2 = deCasteljau(uu, matrix_20, matrix_21, matrix_22, matrix_23);
+ const Vec3<T> row3 = deCasteljau(uu, matrix_30, matrix_31, matrix_32, matrix_33);
+
+ const Vec3<T> tangentV = deCasteljau_tangent(vv, row0, row1, row2, row3);
+
+ /* normal = tangentU x tangentV */
+ const Vec3<T> n = cross(tangentU,tangentV);
+ return n;
+ }
+
+ template<typename vfloat>
+ __forceinline Vec3<vfloat> normal(const vfloat& uu, const vfloat& vv) const {
+ return normal(matrix,uu,vv);
+ }
+ };
+
+ typedef BezierPatchT<Vec3fa,Vec3fa_t> BezierPatch3fa;
+}
diff --git a/thirdparty/embree/kernels/subdiv/bilinear_patch.h b/thirdparty/embree/kernels/subdiv/bilinear_patch.h
new file mode 100644
index 0000000000..cade104a6c
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/bilinear_patch.h
@@ -0,0 +1,191 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_patch.h"
+#include "bezier_curve.h"
+
+namespace embree
+{
+ template<typename Vertex, typename Vertex_t = Vertex>
+ class __aligned(64) BilinearPatchT
+ {
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+
+ public:
+ Vertex v[4];
+
+ public:
+
+ __forceinline BilinearPatchT () {}
+
+ __forceinline BilinearPatchT (const HalfEdge* edge, const BufferView<Vertex>& vertices) {
+ init(edge,vertices.getPtr(),vertices.getStride());
+ }
+
+ __forceinline BilinearPatchT (const HalfEdge* edge, const char* vertices, size_t stride) {
+ init(edge,vertices,stride);
+ }
+
+ __forceinline void init (const HalfEdge* edge, const char* vertices, size_t stride)
+ {
+ v[0] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
+ v[1] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
+ v[2] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
+ v[3] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
+ }
+
+ __forceinline BilinearPatchT (const CatmullClarkPatch& patch)
+ {
+ v[0] = patch.ring[0].getLimitVertex();
+ v[1] = patch.ring[1].getLimitVertex();
+ v[2] = patch.ring[2].getLimitVertex();
+ v[3] = patch.ring[3].getLimitVertex();
+ }
+
+ __forceinline BBox<Vertex> bounds() const
+ {
+
+ BBox<Vertex> bounds (v[0]);
+ bounds.extend(v[1]);
+ bounds.extend(v[2]);
+ bounds.extend(v[3]);
+ return bounds;
+ }
+
+ __forceinline Vertex eval(const float uu, const float vv) const {
+ return lerp(lerp(v[0],v[1],uu),lerp(v[3],v[2],uu),vv);
+ }
+
+ __forceinline Vertex eval_du(const float uu, const float vv) const {
+ return lerp(v[1]-v[0],v[2]-v[3],vv);
+ }
+
+ __forceinline Vertex eval_dv(const float uu, const float vv) const {
+ return lerp(v[3]-v[0],v[2]-v[1],uu);
+ }
+
+ __forceinline Vertex eval_dudu(const float uu, const float vv) const {
+ return Vertex(zero);
+ }
+
+ __forceinline Vertex eval_dvdv(const float uu, const float vv) const {
+ return Vertex(zero);
+ }
+
+ __forceinline Vertex eval_dudv(const float uu, const float vv) const {
+ return (v[2]-v[3]) - (v[1]-v[0]);
+ }
+
+ __forceinline Vertex normal(const float uu, const float vv) const {
+ return cross(eval_du(uu,vv),eval_dv(uu,vv));
+ }
+
+ __forceinline void eval(const float u, const float v,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv,
+ const float dscale = 1.0f) const
+ {
+ if (P) {
+ *P = eval(u,v);
+ }
+ if (dPdu) {
+ assert(dPdu); *dPdu = eval_du(u,v)*dscale;
+ assert(dPdv); *dPdv = eval_dv(u,v)*dscale;
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(dscale);
+ assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(dscale);
+ assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(dscale);
+ }
+ }
+
+ template<class vfloat>
+ __forceinline Vec3<vfloat> eval(const vfloat& uu, const vfloat& vv) const
+ {
+ const vfloat x = lerp(lerp(v[0].x,v[1].x,uu),lerp(v[3].x,v[2].x,uu),vv);
+ const vfloat y = lerp(lerp(v[0].y,v[1].y,uu),lerp(v[3].y,v[2].y,uu),vv);
+ const vfloat z = lerp(lerp(v[0].z,v[1].z,uu),lerp(v[3].z,v[2].z,uu),vv);
+ return Vec3<vfloat>(x,y,z);
+ }
+
+ template<class vfloat>
+ __forceinline Vec3<vfloat> eval_du(const vfloat& uu, const vfloat& vv) const
+ {
+ const vfloat x = lerp(v[1].x-v[0].x,v[2].x-v[3].x,vv);
+ const vfloat y = lerp(v[1].y-v[0].y,v[2].y-v[3].y,vv);
+ const vfloat z = lerp(v[1].z-v[0].z,v[2].z-v[3].z,vv);
+ return Vec3<vfloat>(x,y,z);
+ }
+
+ template<class vfloat>
+ __forceinline Vec3<vfloat> eval_dv(const vfloat& uu, const vfloat& vv) const
+ {
+ const vfloat x = lerp(v[3].x-v[0].x,v[2].x-v[1].x,uu);
+ const vfloat y = lerp(v[3].y-v[0].y,v[2].y-v[1].y,uu);
+ const vfloat z = lerp(v[3].z-v[0].z,v[2].z-v[1].z,uu);
+ return Vec3<vfloat>(x,y,z);
+ }
+
+ template<typename vfloat>
+ __forceinline Vec3<vfloat> normal(const vfloat& uu, const vfloat& vv) const {
+ return cross(eval_du(uu,vv),eval_dv(uu,vv));
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return lerp(lerp(v[0][i],v[1][i],uu),lerp(v[3][i],v[2][i],uu),vv);
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval_du(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return lerp(v[1][i]-v[0][i],v[2][i]-v[3][i],vv);
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval_dv(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return lerp(v[3][i]-v[0][i],v[2][i]-v[1][i],uu);
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval_dudu(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return vfloat(zero);
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval_dvdv(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return vfloat(zero);
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval_dudv(const size_t i, const vfloat& uu, const vfloat& vv) const {
+ return (v[2][i]-v[3][i]) - (v[1][i]-v[0][i]);
+ }
+
+ template<typename vbool, typename vfloat>
+ __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
+ const float dscale, const size_t dstride, const size_t N) const
+ {
+ if (P) {
+ for (size_t i=0; i<N; i++) vfloat::store(valid,P+i*dstride,eval(i,uu,vv));
+ }
+ if (dPdu) {
+ for (size_t i=0; i<N; i++) {
+ assert(dPdu); vfloat::store(valid,dPdu+i*dstride,eval_du(i,uu,vv)*dscale);
+ assert(dPdv); vfloat::store(valid,dPdv+i*dstride,eval_dv(i,uu,vv)*dscale);
+ }
+ }
+ if (ddPdudu) {
+ for (size_t i=0; i<N; i++) {
+ assert(ddPdudu); vfloat::store(valid,ddPdudu+i*dstride,eval_dudu(i,uu,vv)*sqr(dscale));
+ assert(ddPdvdv); vfloat::store(valid,ddPdvdv+i*dstride,eval_dvdv(i,uu,vv)*sqr(dscale));
+ assert(ddPdudv); vfloat::store(valid,ddPdudv+i*dstride,eval_dudv(i,uu,vv)*sqr(dscale));
+ }
+ }
+ }
+ };
+
+ typedef BilinearPatchT<Vec3fa,Vec3fa_t> BilinearPatch3fa;
+}
diff --git a/thirdparty/embree/kernels/subdiv/bspline_curve.h b/thirdparty/embree/kernels/subdiv/bspline_curve.h
new file mode 100644
index 0000000000..51489ef37c
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/bspline_curve.h
@@ -0,0 +1,320 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "bezier_curve.h"
+
+namespace embree
+{
+ class BSplineBasis
+ {
+ public:
+
+ template<typename T>
+ static __forceinline Vec4<T> eval(const T& u)
+ {
+ const T t = u;
+ const T s = T(1.0f) - u;
+ const T n0 = s*s*s;
+ const T n1 = (4.0f*(s*s*s)+(t*t*t)) + (12.0f*((s*t)*s) + 6.0f*((t*s)*t));
+ const T n2 = (4.0f*(t*t*t)+(s*s*s)) + (12.0f*((t*s)*t) + 6.0f*((s*t)*s));
+ const T n3 = t*t*t;
+ return T(1.0f/6.0f)*Vec4<T>(n0,n1,n2,n3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative(const T& u)
+ {
+ const T t = u;
+ const T s = 1.0f - u;
+ const T n0 = -s*s;
+ const T n1 = -t*t - 4.0f*(t*s);
+ const T n2 = s*s + 4.0f*(s*t);
+ const T n3 = t*t;
+ return T(0.5f)*Vec4<T>(n0,n1,n2,n3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative2(const T& u)
+ {
+ const T t = u;
+ const T s = 1.0f - u;
+ const T n0 = s;
+ const T n1 = t - 2.0f*s;
+ const T n2 = s - 2.0f*t;
+ const T n3 = t;
+ return Vec4<T>(n0,n1,n2,n3);
+ }
+ };
+
+ struct PrecomputedBSplineBasis
+ {
+ enum { N = 16 };
+ public:
+ PrecomputedBSplineBasis() {}
+ PrecomputedBSplineBasis(int shift);
+
+ /* basis for bspline evaluation */
+ public:
+ float c0[N+1][N+1];
+ float c1[N+1][N+1];
+ float c2[N+1][N+1];
+ float c3[N+1][N+1];
+
+ /* basis for bspline derivative evaluation */
+ public:
+ float d0[N+1][N+1];
+ float d1[N+1][N+1];
+ float d2[N+1][N+1];
+ float d3[N+1][N+1];
+ };
+ extern PrecomputedBSplineBasis bspline_basis0;
+ extern PrecomputedBSplineBasis bspline_basis1;
+
+ template<typename Vertex>
+ struct BSplineCurveT
+ {
+ Vertex v0,v1,v2,v3;
+
+ __forceinline BSplineCurveT() {}
+
+ __forceinline BSplineCurveT(const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3)
+ : v0(v0), v1(v1), v2(v2), v3(v3) {}
+
+ __forceinline Vertex begin() const {
+ return madd(1.0f/6.0f,v0,madd(2.0f/3.0f,v1,1.0f/6.0f*v2));
+ }
+
+ __forceinline Vertex end() const {
+ return madd(1.0f/6.0f,v1,madd(2.0f/3.0f,v2,1.0f/6.0f*v3));
+ }
+
+ __forceinline Vertex center() const {
+ return 0.25f*(v0+v1+v2+v3);
+ }
+
+ __forceinline BBox<Vertex> bounds() const {
+ return merge(BBox<Vertex>(v0),BBox<Vertex>(v1),BBox<Vertex>(v2),BBox<Vertex>(v3));
+ }
+
+ __forceinline friend BSplineCurveT operator -( const BSplineCurveT& a, const Vertex& b ) {
+ return BSplineCurveT(a.v0-b,a.v1-b,a.v2-b,a.v3-b);
+ }
+
+ __forceinline BSplineCurveT<Vec3ff> xfm_pr(const LinearSpace3fa& space, const Vec3fa& p) const
+ {
+ const Vec3ff q0(xfmVector(space,(Vec3fa)v0-p), v0.w);
+ const Vec3ff q1(xfmVector(space,(Vec3fa)v1-p), v1.w);
+ const Vec3ff q2(xfmVector(space,(Vec3fa)v2-p), v2.w);
+ const Vec3ff q3(xfmVector(space,(Vec3fa)v3-p), v3.w);
+ return BSplineCurveT<Vec3ff>(q0,q1,q2,q3);
+ }
+
+ __forceinline Vertex eval(const float t) const
+ {
+ const Vec4<float> b = BSplineBasis::eval(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline Vertex eval_du(const float t) const
+ {
+ const Vec4<float> b = BSplineBasis::derivative(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline Vertex eval_dudu(const float t) const
+ {
+ const Vec4<float> b = BSplineBasis::derivative2(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline void eval(const float t, Vertex& p, Vertex& dp, Vertex& ddp) const
+ {
+ p = eval(t);
+ dp = eval_du(t);
+ ddp = eval_dudu(t);
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BSplineBasis::eval(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_du(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BSplineBasis::derivative(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_dudu(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = BSplineBasis::derivative2(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline void veval(const vfloat<M>& t, Vec4vf<M>& p, Vec4vf<M>& dp) const
+ {
+ p = veval<M>(t);
+ dp = veval_du<M>(t);
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> eval0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBSplineBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bspline_basis0.c0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&bspline_basis0.c1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&bspline_basis0.c2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&bspline_basis0.c3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> eval1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBSplineBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bspline_basis1.c0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&bspline_basis1.c1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&bspline_basis1.c2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&bspline_basis1.c3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> derivative0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBSplineBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bspline_basis0.d0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&bspline_basis0.d1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&bspline_basis0.d2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&bspline_basis0.d3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> derivative1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedBSplineBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&bspline_basis1.d0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&bspline_basis1.d1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&bspline_basis1.d2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&bspline_basis1.d3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ /* calculates bounds of bspline curve geometry */
+ __forceinline BBox3fa accurateRoundBounds() const
+ {
+ const int N = 7;
+ const float scale = 1.0f/(3.0f*(N-1));
+ Vec4vfx pl(pos_inf), pu(neg_inf);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vintx vi = vintx(i)+vintx(step);
+ vboolx valid = vi <= vintx(N);
+ const Vec4vfx p = eval0<VSIZEX>(i,N);
+ const Vec4vfx dp = derivative0<VSIZEX>(i,N);
+ const Vec4vfx pm = p-Vec4vfx(scale)*select(vi!=vintx(0),dp,Vec4vfx(zero));
+ const Vec4vfx pp = p+Vec4vfx(scale)*select(vi!=vintx(N),dp,Vec4vfx(zero));
+ pl = select(valid,min(pl,p,pm,pp),pl); // FIXME: use masked min
+ pu = select(valid,max(pu,p,pm,pp),pu); // FIXME: use masked min
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const float r_min = reduce_min(pl.w);
+ const float r_max = reduce_max(pu.w);
+ const Vec3fa upper_r = Vec3fa(max(abs(r_min),abs(r_max)));
+ return enlarge(BBox3fa(lower,upper),upper_r);
+ }
+
+ /* calculates bounds when tessellated into N line segments */
+ __forceinline BBox3fa accurateFlatBounds(int N) const
+ {
+ if (likely(N == 4))
+ {
+ const Vec4vf4 pi = eval0<4>(0,4);
+ const Vec3fa lower(reduce_min(pi.x),reduce_min(pi.y),reduce_min(pi.z));
+ const Vec3fa upper(reduce_max(pi.x),reduce_max(pi.y),reduce_max(pi.z));
+ const Vec3fa upper_r = Vec3fa(reduce_max(abs(pi.w)));
+ const Vec3ff pe = end();
+ return enlarge(BBox3fa(min(lower,pe),max(upper,pe)),max(upper_r,Vec3fa(abs(pe.w))));
+ }
+ else
+ {
+ Vec3vfx pl(pos_inf), pu(neg_inf); vfloatx ru(0.0f);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vboolx valid = vintx(i)+vintx(step) <= vintx(N);
+ const Vec4vfx pi = eval0<VSIZEX>(i,N);
+
+ pl.x = select(valid,min(pl.x,pi.x),pl.x); // FIXME: use masked min
+ pl.y = select(valid,min(pl.y,pi.y),pl.y);
+ pl.z = select(valid,min(pl.z,pi.z),pl.z);
+
+ pu.x = select(valid,max(pu.x,pi.x),pu.x); // FIXME: use masked min
+ pu.y = select(valid,max(pu.y,pi.y),pu.y);
+ pu.z = select(valid,max(pu.z,pi.z),pu.z);
+
+ ru = select(valid,max(ru,abs(pi.w)),ru);
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const Vec3fa upper_r(reduce_max(ru));
+ return enlarge(BBox3fa(lower,upper),upper_r);
+ }
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const BSplineCurveT& curve) {
+ return cout << "BSplineCurve { v0 = " << curve.v0 << ", v1 = " << curve.v1 << ", v2 = " << curve.v2 << ", v3 = " << curve.v3 << " }";
+ }
+ };
+
+ template<typename Vertex>
+ __forceinline void convert(const BezierCurveT<Vertex>& icurve, BezierCurveT<Vertex>& ocurve) {
+ ocurve = icurve;
+ }
+
+ template<typename Vertex>
+ __forceinline void convert(const BSplineCurveT<Vertex>& icurve, BSplineCurveT<Vertex>& ocurve) {
+ ocurve = icurve;
+ }
+
+ template<typename Vertex>
+ __forceinline void convert(const BezierCurveT<Vertex>& icurve, BSplineCurveT<Vertex>& ocurve)
+ {
+ const Vertex v0 = madd(6.0f,icurve.v0,madd(-7.0f,icurve.v1,2.0f*icurve.v2));
+ const Vertex v1 = msub(2.0f,icurve.v1,icurve.v2);
+ const Vertex v2 = msub(2.0f,icurve.v2,icurve.v1);
+ const Vertex v3 = madd(2.0f,icurve.v1,madd(-7.0f,icurve.v2,6.0f*icurve.v3));
+ ocurve = BSplineCurveT<Vertex>(v0,v1,v2,v3);
+ }
+
+ template<typename Vertex>
+ __forceinline void convert(const BSplineCurveT<Vertex>& icurve, BezierCurveT<Vertex>& ocurve)
+ {
+ const Vertex v0 = madd(1.0f/6.0f,icurve.v0,madd(2.0f/3.0f,icurve.v1,1.0f/6.0f*icurve.v2));
+ const Vertex v1 = madd(2.0f/3.0f,icurve.v1,1.0f/3.0f*icurve.v2);
+ const Vertex v2 = madd(1.0f/3.0f,icurve.v1,2.0f/3.0f*icurve.v2);
+ const Vertex v3 = madd(1.0f/6.0f,icurve.v1,madd(2.0f/3.0f,icurve.v2,1.0f/6.0f*icurve.v3));
+ ocurve = BezierCurveT<Vertex>(v0,v1,v2,v3);
+ }
+
+ template<typename CurveGeometry>
+ __forceinline BSplineCurveT<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const BSplineCurveT<Vec3ff>& curve)
+ {
+ return BSplineCurveT<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,curve.v0),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v1),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v2),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v3));
+ }
+
+ typedef BSplineCurveT<Vec3fa> BSplineCurve3fa;
+}
+
diff --git a/thirdparty/embree/kernels/subdiv/bspline_patch.h b/thirdparty/embree/kernels/subdiv/bspline_patch.h
new file mode 100644
index 0000000000..ff47f01c7a
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/bspline_patch.h
@@ -0,0 +1,449 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_patch.h"
+#include "bspline_curve.h"
+
+namespace embree
+{
+ template<typename Vertex, typename Vertex_t = Vertex>
+ class __aligned(64) BSplinePatchT
+ {
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+
+ public:
+
+ __forceinline BSplinePatchT () {}
+
+ __forceinline BSplinePatchT (const CatmullClarkPatch& patch) {
+ init(patch);
+ }
+
+ __forceinline BSplinePatchT(const CatmullClarkPatch& patch,
+ const BezierCurveT<Vertex>* border0,
+ const BezierCurveT<Vertex>* border1,
+ const BezierCurveT<Vertex>* border2,
+ const BezierCurveT<Vertex>* border3)
+ {
+ init(patch);
+ }
+
+ __forceinline BSplinePatchT (const HalfEdge* edge, const char* vertices, size_t stride) {
+ init(edge,vertices,stride);
+ }
+
+ __forceinline Vertex hard_corner(const Vertex& v01, const Vertex& v02,
+ const Vertex& v10, const Vertex& v11, const Vertex& v12,
+ const Vertex& v20, const Vertex& v21, const Vertex& v22)
+ {
+ return 4.0f*v11 - 2.0f*(v12+v21) + v22;
+ }
+
+ __forceinline Vertex soft_convex_corner( const Vertex& v01, const Vertex& v02,
+ const Vertex& v10, const Vertex& v11, const Vertex& v12,
+ const Vertex& v20, const Vertex& v21, const Vertex& v22)
+ {
+ return -8.0f*v11 + 4.0f*(v12+v21) + v22;
+ }
+
+ __forceinline Vertex convex_corner(const float vertex_crease_weight,
+ const Vertex& v01, const Vertex& v02,
+ const Vertex& v10, const Vertex& v11, const Vertex& v12,
+ const Vertex& v20, const Vertex& v21, const Vertex& v22)
+ {
+ if (std::isinf(vertex_crease_weight)) return hard_corner(v01,v02,v10,v11,v12,v20,v21,v22);
+ else return soft_convex_corner(v01,v02,v10,v11,v12,v20,v21,v22);
+ }
+
+ __forceinline Vertex load(const HalfEdge* edge, const char* vertices, size_t stride) {
+ return Vertex_t::loadu(vertices+edge->getStartVertexIndex()*stride);
+ }
+
+ __forceinline void init_border(const CatmullClarkRing& edge0,
+ Vertex& v01, Vertex& v02,
+ const Vertex& v11, const Vertex& v12,
+ const Vertex& v21, const Vertex& v22)
+ {
+ if (likely(edge0.has_opposite_back(0)))
+ {
+ v01 = edge0.back(2);
+ v02 = edge0.back(1);
+ } else {
+ v01 = 2.0f*v11-v21;
+ v02 = 2.0f*v12-v22;
+ }
+ }
+
+ __forceinline void init_corner(const CatmullClarkRing& edge0,
+ Vertex& v00, const Vertex& v01, const Vertex& v02,
+ const Vertex& v10, const Vertex& v11, const Vertex& v12,
+ const Vertex& v20, const Vertex& v21, const Vertex& v22)
+ {
+ const bool MAYBE_UNUSED has_back1 = edge0.has_opposite_back(1);
+ const bool has_back0 = edge0.has_opposite_back(0);
+ const bool has_front1 = edge0.has_opposite_front(1);
+ const bool MAYBE_UNUSED has_front2 = edge0.has_opposite_front(2);
+
+ if (likely(has_back0)) {
+ if (likely(has_front1)) { assert(has_back1 && has_front2); v00 = edge0.back(3); }
+ else { assert(!has_back1); v00 = 2.0f*v01-v02; }
+ }
+ else {
+ if (likely(has_front1)) { assert(!has_front2); v00 = 2.0f*v10-v20; }
+ else v00 = convex_corner(edge0.vertex_crease_weight,v01,v02,v10,v11,v12,v20,v21,v22);
+ }
+ }
+
+ void init(const CatmullClarkPatch& patch)
+ {
+ /* fill inner vertices */
+ const Vertex v11 = v[1][1] = patch.ring[0].vtx;
+ const Vertex v12 = v[1][2] = patch.ring[1].vtx;
+ const Vertex v22 = v[2][2] = patch.ring[2].vtx;
+ const Vertex v21 = v[2][1] = patch.ring[3].vtx;
+
+ /* fill border vertices */
+ init_border(patch.ring[0],v[0][1],v[0][2],v11,v12,v21,v22);
+ init_border(patch.ring[1],v[1][3],v[2][3],v12,v22,v11,v21);
+ init_border(patch.ring[2],v[3][2],v[3][1],v22,v21,v12,v11);
+ init_border(patch.ring[3],v[2][0],v[1][0],v21,v11,v22,v12);
+
+ /* fill corner vertices */
+ init_corner(patch.ring[0],v[0][0],v[0][1],v[0][2],v[1][0],v11,v12,v[2][0],v21,v22);
+ init_corner(patch.ring[1],v[0][3],v[1][3],v[2][3],v[0][2],v12,v22,v[0][1],v11,v21);
+ init_corner(patch.ring[2],v[3][3],v[3][2],v[3][1],v[2][3],v22,v21,v[1][3],v12,v11);
+ init_corner(patch.ring[3],v[3][0],v[2][0],v[1][0],v[3][1],v21,v11,v[3][2],v22,v12);
+ }
+
+ void init_border(const HalfEdge* edge0, const char* vertices, size_t stride,
+ Vertex& v01, Vertex& v02,
+ const Vertex& v11, const Vertex& v12,
+ const Vertex& v21, const Vertex& v22)
+ {
+ if (likely(edge0->hasOpposite()))
+ {
+ const HalfEdge* e = edge0->opposite()->next()->next();
+ v01 = load(e,vertices,stride);
+ v02 = load(e->next(),vertices,stride);
+ } else {
+ v01 = 2.0f*v11-v21;
+ v02 = 2.0f*v12-v22;
+ }
+ }
+
+ void init_corner(const HalfEdge* edge0, const char* vertices, size_t stride,
+ Vertex& v00, const Vertex& v01, const Vertex& v02,
+ const Vertex& v10, const Vertex& v11, const Vertex& v12,
+ const Vertex& v20, const Vertex& v21, const Vertex& v22)
+ {
+ const bool has_back0 = edge0->hasOpposite();
+ const bool has_front1 = edge0->prev()->hasOpposite();
+
+ if (likely(has_back0))
+ {
+ const HalfEdge* e = edge0->opposite()->next();
+ if (likely(has_front1))
+ {
+ assert(e->hasOpposite());
+ assert(edge0->prev()->opposite()->prev()->hasOpposite());
+ v00 = load(e->opposite()->prev(),vertices,stride);
+ }
+ else {
+ assert(!e->hasOpposite());
+ v00 = 2.0f*v01-v02;
+ }
+ }
+ else
+ {
+ if (likely(has_front1)) {
+ assert(!edge0->prev()->opposite()->prev()->hasOpposite());
+ v00 = 2.0f*v10-v20;
+ }
+ else {
+ assert(edge0->vertex_crease_weight == 0.0f || std::isinf(edge0->vertex_crease_weight));
+ v00 = convex_corner(edge0->vertex_crease_weight,v01,v02,v10,v11,v12,v20,v21,v22);
+ }
+ }
+ }
+
+ void init(const HalfEdge* edge0, const char* vertices, size_t stride)
+ {
+ assert( edge0->isRegularFace() );
+
+ /* fill inner vertices */
+ const Vertex v11 = v[1][1] = load(edge0,vertices,stride); const HalfEdge* edge1 = edge0->next();
+ const Vertex v12 = v[1][2] = load(edge1,vertices,stride); const HalfEdge* edge2 = edge1->next();
+ const Vertex v22 = v[2][2] = load(edge2,vertices,stride); const HalfEdge* edge3 = edge2->next();
+ const Vertex v21 = v[2][1] = load(edge3,vertices,stride); assert(edge0 == edge3->next());
+
+ /* fill border vertices */
+ init_border(edge0,vertices,stride,v[0][1],v[0][2],v11,v12,v21,v22);
+ init_border(edge1,vertices,stride,v[1][3],v[2][3],v12,v22,v11,v21);
+ init_border(edge2,vertices,stride,v[3][2],v[3][1],v22,v21,v12,v11);
+ init_border(edge3,vertices,stride,v[2][0],v[1][0],v21,v11,v22,v12);
+
+ /* fill corner vertices */
+ init_corner(edge0,vertices,stride,v[0][0],v[0][1],v[0][2],v[1][0],v11,v12,v[2][0],v21,v22);
+ init_corner(edge1,vertices,stride,v[0][3],v[1][3],v[2][3],v[0][2],v12,v22,v[0][1],v11,v21);
+ init_corner(edge2,vertices,stride,v[3][3],v[3][2],v[3][1],v[2][3],v22,v21,v[1][3],v12,v11);
+ init_corner(edge3,vertices,stride,v[3][0],v[2][0],v[1][0],v[3][1],v21,v11,v[3][2],v22,v12);
+ }
+
+ __forceinline BBox<Vertex> bounds() const
+ {
+ const Vertex* const cv = &v[0][0];
+ BBox<Vertex> bounds (cv[0]);
+ for (size_t i=1; i<16 ; i++)
+ bounds.extend( cv[i] );
+ return bounds;
+ }
+
+ __forceinline Vertex eval(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::eval(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::eval(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex eval_du(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::eval(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::derivative(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex eval_dv(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::derivative(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::eval(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex eval_dudu(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::eval(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::derivative2(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex eval_dvdv(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::derivative2(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::eval(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex eval_dudv(const float uu, const float vv) const
+ {
+ const Vec4f v_n = BSplineBasis::derivative(vv);
+ const Vertex_t curve0 = madd(v_n[0],v[0][0],madd(v_n[1],v[1][0],madd(v_n[2],v[2][0],v_n[3] * v[3][0])));
+ const Vertex_t curve1 = madd(v_n[0],v[0][1],madd(v_n[1],v[1][1],madd(v_n[2],v[2][1],v_n[3] * v[3][1])));
+ const Vertex_t curve2 = madd(v_n[0],v[0][2],madd(v_n[1],v[1][2],madd(v_n[2],v[2][2],v_n[3] * v[3][2])));
+ const Vertex_t curve3 = madd(v_n[0],v[0][3],madd(v_n[1],v[1][3],madd(v_n[2],v[2][3],v_n[3] * v[3][3])));
+
+ const Vec4f u_n = BSplineBasis::derivative(uu);
+ return madd(u_n[0],curve0,madd(u_n[1],curve1,madd(u_n[2],curve2,u_n[3] * curve3)));
+ }
+
+ __forceinline Vertex normal(const float uu, const float vv) const
+ {
+ const Vertex tu = eval_du(uu,vv);
+ const Vertex tv = eval_dv(uu,vv);
+ return cross(tu,tv);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval(const T& uu, const T& vv, const Vec4<T>& u_n, const Vec4<T>& v_n) const
+ {
+ const T curve0_x = madd(v_n[0],T(v[0][0].x),madd(v_n[1],T(v[1][0].x),madd(v_n[2],T(v[2][0].x),v_n[3] * T(v[3][0].x))));
+ const T curve1_x = madd(v_n[0],T(v[0][1].x),madd(v_n[1],T(v[1][1].x),madd(v_n[2],T(v[2][1].x),v_n[3] * T(v[3][1].x))));
+ const T curve2_x = madd(v_n[0],T(v[0][2].x),madd(v_n[1],T(v[1][2].x),madd(v_n[2],T(v[2][2].x),v_n[3] * T(v[3][2].x))));
+ const T curve3_x = madd(v_n[0],T(v[0][3].x),madd(v_n[1],T(v[1][3].x),madd(v_n[2],T(v[2][3].x),v_n[3] * T(v[3][3].x))));
+ const T x = madd(u_n[0],curve0_x,madd(u_n[1],curve1_x,madd(u_n[2],curve2_x,u_n[3] * curve3_x)));
+
+ const T curve0_y = madd(v_n[0],T(v[0][0].y),madd(v_n[1],T(v[1][0].y),madd(v_n[2],T(v[2][0].y),v_n[3] * T(v[3][0].y))));
+ const T curve1_y = madd(v_n[0],T(v[0][1].y),madd(v_n[1],T(v[1][1].y),madd(v_n[2],T(v[2][1].y),v_n[3] * T(v[3][1].y))));
+ const T curve2_y = madd(v_n[0],T(v[0][2].y),madd(v_n[1],T(v[1][2].y),madd(v_n[2],T(v[2][2].y),v_n[3] * T(v[3][2].y))));
+ const T curve3_y = madd(v_n[0],T(v[0][3].y),madd(v_n[1],T(v[1][3].y),madd(v_n[2],T(v[2][3].y),v_n[3] * T(v[3][3].y))));
+ const T y = madd(u_n[0],curve0_y,madd(u_n[1],curve1_y,madd(u_n[2],curve2_y,u_n[3] * curve3_y)));
+
+ const T curve0_z = madd(v_n[0],T(v[0][0].z),madd(v_n[1],T(v[1][0].z),madd(v_n[2],T(v[2][0].z),v_n[3] * T(v[3][0].z))));
+ const T curve1_z = madd(v_n[0],T(v[0][1].z),madd(v_n[1],T(v[1][1].z),madd(v_n[2],T(v[2][1].z),v_n[3] * T(v[3][1].z))));
+ const T curve2_z = madd(v_n[0],T(v[0][2].z),madd(v_n[1],T(v[1][2].z),madd(v_n[2],T(v[2][2].z),v_n[3] * T(v[3][2].z))));
+ const T curve3_z = madd(v_n[0],T(v[0][3].z),madd(v_n[1],T(v[1][3].z),madd(v_n[2],T(v[2][3].z),v_n[3] * T(v[3][3].z))));
+ const T z = madd(u_n[0],curve0_z,madd(u_n[1],curve1_z,madd(u_n[2],curve2_z,u_n[3] * curve3_z)));
+
+ return Vec3<T>(x,y,z);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::eval(uu);
+ const Vec4<T> v_n = BSplineBasis::eval(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval_du(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::derivative(uu);
+ const Vec4<T> v_n = BSplineBasis::eval(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval_dv(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::eval(uu);
+ const Vec4<T> v_n = BSplineBasis::derivative(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval_dudu(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::derivative2(uu);
+ const Vec4<T> v_n = BSplineBasis::eval(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval_dvdv(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::eval(uu);
+ const Vec4<T> v_n = BSplineBasis::derivative2(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> eval_dudv(const T& uu, const T& vv) const
+ {
+ const Vec4<T> u_n = BSplineBasis::derivative(uu);
+ const Vec4<T> v_n = BSplineBasis::derivative(vv);
+ return eval(uu,vv,u_n,v_n);
+ }
+
+ template<typename T>
+ __forceinline Vec3<T> normal(const T& uu, const T& vv) const {
+ return cross(eval_du(uu,vv),eval_dv(uu,vv));
+ }
+
+ void eval(const float u, const float v,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv,
+ const float dscale = 1.0f) const
+ {
+ if (P) {
+ *P = eval(u,v);
+ }
+ if (dPdu) {
+ assert(dPdu); *dPdu = eval_du(u,v)*dscale;
+ assert(dPdv); *dPdv = eval_dv(u,v)*dscale;
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(dscale);
+ assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(dscale);
+ assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(dscale);
+ }
+ }
+
+ template<class vfloat>
+ __forceinline vfloat eval(const size_t i, const vfloat& uu, const vfloat& vv, const Vec4<vfloat>& u_n, const Vec4<vfloat>& v_n) const
+ {
+ const vfloat curve0_x = madd(v_n[0],vfloat(v[0][0][i]),madd(v_n[1],vfloat(v[1][0][i]),madd(v_n[2],vfloat(v[2][0][i]),v_n[3] * vfloat(v[3][0][i]))));
+ const vfloat curve1_x = madd(v_n[0],vfloat(v[0][1][i]),madd(v_n[1],vfloat(v[1][1][i]),madd(v_n[2],vfloat(v[2][1][i]),v_n[3] * vfloat(v[3][1][i]))));
+ const vfloat curve2_x = madd(v_n[0],vfloat(v[0][2][i]),madd(v_n[1],vfloat(v[1][2][i]),madd(v_n[2],vfloat(v[2][2][i]),v_n[3] * vfloat(v[3][2][i]))));
+ const vfloat curve3_x = madd(v_n[0],vfloat(v[0][3][i]),madd(v_n[1],vfloat(v[1][3][i]),madd(v_n[2],vfloat(v[2][3][i]),v_n[3] * vfloat(v[3][3][i]))));
+ return madd(u_n[0],curve0_x,madd(u_n[1],curve1_x,madd(u_n[2],curve2_x,u_n[3] * curve3_x)));
+ }
+
+ template<typename vbool, typename vfloat>
+ void eval(const vbool& valid, const vfloat& uu, const vfloat& vv,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
+ const float dscale, const size_t dstride, const size_t N) const
+ {
+ if (P) {
+ const Vec4<vfloat> u_n = BSplineBasis::eval(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,P+i*dstride,eval(i,uu,vv,u_n,v_n));
+ }
+ if (dPdu)
+ {
+ {
+ assert(dPdu);
+ const Vec4<vfloat> u_n = BSplineBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,dPdu+i*dstride,eval(i,uu,vv,u_n,v_n)*dscale);
+ }
+ {
+ assert(dPdv);
+ const Vec4<vfloat> u_n = BSplineBasis::eval(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,dPdv+i*dstride,eval(i,uu,vv,u_n,v_n)*dscale);
+ }
+ }
+ if (ddPdudu)
+ {
+ {
+ assert(ddPdudu);
+ const Vec4<vfloat> u_n = BSplineBasis::derivative2(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::eval(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdudu+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ {
+ assert(ddPdvdv);
+ const Vec4<vfloat> u_n = BSplineBasis::eval(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::derivative2(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdvdv+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ {
+ assert(ddPdudv);
+ const Vec4<vfloat> u_n = BSplineBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BSplineBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) vfloat::store(valid,ddPdudv+i*dstride,eval(i,uu,vv,u_n,v_n)*sqr(dscale));
+ }
+ }
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream o, const BSplinePatchT& p)
+ {
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ o << "[" << y << "][" << x << "] " << p.v[y][x] << embree_endl;
+ return o;
+ }
+
+ public:
+ Vertex v[4][4];
+ };
+
+ typedef BSplinePatchT<Vec3fa,Vec3fa_t> BSplinePatch3fa;
+}
diff --git a/thirdparty/embree/kernels/subdiv/catmullclark_coefficients.h b/thirdparty/embree/kernels/subdiv/catmullclark_coefficients.h
new file mode 100644
index 0000000000..46959797bf
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/catmullclark_coefficients.h
@@ -0,0 +1,85 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/geometry.h"
+
+namespace embree
+{
+ static const size_t MAX_PATCH_VALENCE = 16; //!< maximum number of vertices of a patch
+ static const size_t MAX_RING_FACE_VALENCE = 64; //!< maximum number of faces per ring
+ static const size_t MAX_RING_EDGE_VALENCE = 2*64; //!< maximum number of edges per ring
+
+ class CatmullClarkPrecomputedCoefficients
+ {
+ private:
+
+ float table_cos_2PI_div_n[MAX_RING_FACE_VALENCE+1];
+
+ float* table_limittangent_a[MAX_RING_FACE_VALENCE+1];
+ float* table_limittangent_b[MAX_RING_FACE_VALENCE+1];
+ float table_limittangent_c[MAX_RING_FACE_VALENCE+1];
+
+ __forceinline float set_cos_2PI_div_n(const size_t n) {
+ if (unlikely(n == 0)) return 1.0f;
+ return cosf(2.0f*float(pi)/(float)n);
+ }
+
+ __forceinline float set_limittangent_a(const size_t i, const size_t n)
+ {
+ if (unlikely(n == 0)) return 1.0f;
+ const float c0 = 1.0f/(float)n * 1.0f / sqrtf(4.0f + cosf(float(pi)/(float)n)*cosf(float(pi)/(float)n));
+ const float c1 = (1.0f/(float)n + cosf(float(pi)/(float)n) * c0);
+ return cosf(2.0f*float(pi)*(float)i/(float)n) * c1;
+ }
+
+ __forceinline float set_limittangent_b(const size_t i, const size_t n)
+ {
+ if (unlikely(n == 0)) return 1.0f;
+ const float c0 = 1.0f/(float)n * 1.0f / sqrtf(4.0f + cosf(float(pi)/(float)n)*cosf(float(pi)/(float)n));
+ return cosf((2.0f*float(pi)*i+float(pi))/(float)n) * c0;
+ }
+
+ __forceinline float set_limittangent_c(const size_t n)
+ {
+ if (unlikely(n == 0)) return 1.0f;
+ return 2.0f/16.0f * (5.0f + cosf(2.0f*float(pi)/(float)n) + cosf(float(pi)/(float)n) * sqrtf(18.0f+2.0f*cosf(2.0f*float(pi)/(float)n)));
+ }
+
+ public:
+
+ __forceinline float cos_2PI_div_n(const size_t n)
+ {
+ if (likely(n <= MAX_RING_FACE_VALENCE))
+ return table_cos_2PI_div_n[n];
+ else
+ return set_cos_2PI_div_n(n);
+ }
+
+ __forceinline float limittangent_a(const size_t i, const size_t n)
+ {
+ assert(n <= MAX_RING_FACE_VALENCE);
+ assert(i < n);
+ return table_limittangent_a[n][i];
+ }
+
+ __forceinline float limittangent_b(const size_t i, const size_t n)
+ {
+ assert(n <= MAX_RING_FACE_VALENCE);
+ assert(i < n);
+ return table_limittangent_b[n][i];
+ }
+
+ __forceinline float limittangent_c(const size_t n)
+ {
+ assert(n <= MAX_RING_FACE_VALENCE);
+ return table_limittangent_c[n];
+ }
+
+ static CatmullClarkPrecomputedCoefficients table;
+
+ CatmullClarkPrecomputedCoefficients();
+ ~CatmullClarkPrecomputedCoefficients();
+ };
+}
diff --git a/thirdparty/embree/kernels/subdiv/catmullclark_patch.h b/thirdparty/embree/kernels/subdiv/catmullclark_patch.h
new file mode 100644
index 0000000000..91772d94ed
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/catmullclark_patch.h
@@ -0,0 +1,562 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_ring.h"
+#include "bezier_curve.h"
+
+namespace embree
+{
+ template<typename Vertex, typename Vertex_t = Vertex>
+ class __aligned(64) CatmullClarkPatchT
+ {
+ public:
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;
+ typedef typename CatmullClark1Ring::Type Type;
+
+ array_t<CatmullClark1RingT<Vertex,Vertex_t>,4> ring;
+
+ public:
+ __forceinline CatmullClarkPatchT () {}
+
+ __forceinline CatmullClarkPatchT (const HalfEdge* first_half_edge, const char* vertices, size_t stride) {
+ init(first_half_edge,vertices,stride);
+ }
+
+ __forceinline CatmullClarkPatchT (const HalfEdge* first_half_edge, const BufferView<Vec3fa>& vertices) {
+ init(first_half_edge,vertices.getPtr(),vertices.getStride());
+ }
+
+ __forceinline void init (const HalfEdge* first_half_edge, const char* vertices, size_t stride)
+ {
+ for (unsigned i=0; i<4; i++)
+ ring[i].init(first_half_edge+i,vertices,stride);
+
+ assert(verify());
+ }
+
+ __forceinline size_t bytes() const {
+ return ring[0].bytes()+ring[1].bytes()+ring[2].bytes()+ring[3].bytes();
+ }
+
+ __forceinline void serialize(void* ptr, size_t& ofs) const
+ {
+ for (size_t i=0; i<4; i++)
+ ring[i].serialize((char*)ptr,ofs);
+ }
+
+ __forceinline void deserialize(void* ptr)
+ {
+ size_t ofs = 0;
+ for (size_t i=0; i<4; i++)
+ ring[i].deserialize((char*)ptr,ofs);
+ }
+
+ __forceinline BBox3fa bounds() const
+ {
+ BBox3fa bounds (ring[0].bounds());
+ for (size_t i=1; i<4; i++)
+ bounds.extend(ring[i].bounds());
+ return bounds;
+ }
+
+ __forceinline Type type() const
+ {
+ const int ty0 = ring[0].type() ^ CatmullClark1Ring::TYPE_CREASES;
+ const int ty1 = ring[1].type() ^ CatmullClark1Ring::TYPE_CREASES;
+ const int ty2 = ring[2].type() ^ CatmullClark1Ring::TYPE_CREASES;
+ const int ty3 = ring[3].type() ^ CatmullClark1Ring::TYPE_CREASES;
+ return (Type) ((ty0 & ty1 & ty2 & ty3) ^ CatmullClark1Ring::TYPE_CREASES);
+ }
+
+ __forceinline bool isFinalResolution(float res) const {
+ return ring[0].isFinalResolution(res) && ring[1].isFinalResolution(res) && ring[2].isFinalResolution(res) && ring[3].isFinalResolution(res);
+ }
+
+ static __forceinline void init_regular(const CatmullClark1RingT<Vertex,Vertex_t>& p0,
+ const CatmullClark1RingT<Vertex,Vertex_t>& p1,
+ CatmullClark1RingT<Vertex,Vertex_t>& dest0,
+ CatmullClark1RingT<Vertex,Vertex_t>& dest1)
+ {
+ assert(p1.face_valence > 2);
+ dest1.vertex_level = dest0.vertex_level = p0.edge_level;
+ dest1.face_valence = dest0.face_valence = 4;
+ dest1.edge_valence = dest0.edge_valence = 8;
+ dest1.border_index = dest0.border_index = -1;
+ dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];
+ dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;
+
+ dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];
+ dest1.ring[1] = dest0.ring[7] = (Vertex_t)p1.ring[0];
+ dest1.ring[0] = dest0.ring[6] = (Vertex_t)p1.vtx;
+ dest1.ring[7] = dest0.ring[5] = (Vertex_t)p1.ring[4];
+ dest1.ring[6] = dest0.ring[4] = (Vertex_t)p0.ring[p0.edge_valence-1];
+ dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.edge_valence-2];
+ dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;
+ dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];
+
+ dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;
+ dest1.crease_weight[0] = dest0.crease_weight[3] = p1.crease_weight[1];
+ dest1.crease_weight[3] = dest0.crease_weight[2] = 0.0f;
+ dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];
+
+ if (p0.eval_unique_identifier <= p1.eval_unique_identifier)
+ {
+ dest0.eval_start_index = 3;
+ dest1.eval_start_index = 0;
+ dest0.eval_unique_identifier = p0.eval_unique_identifier;
+ dest1.eval_unique_identifier = p0.eval_unique_identifier;
+ }
+ else
+ {
+ dest0.eval_start_index = 1;
+ dest1.eval_start_index = 2;
+ dest0.eval_unique_identifier = p1.eval_unique_identifier;
+ dest1.eval_unique_identifier = p1.eval_unique_identifier;
+ }
+ }
+
+ static __forceinline void init_border(const CatmullClark1RingT<Vertex,Vertex_t> &p0,
+ const CatmullClark1RingT<Vertex,Vertex_t> &p1,
+ CatmullClark1RingT<Vertex,Vertex_t> &dest0,
+ CatmullClark1RingT<Vertex,Vertex_t> &dest1)
+ {
+ dest1.vertex_level = dest0.vertex_level = p0.edge_level;
+ dest1.face_valence = dest0.face_valence = 3;
+ dest1.edge_valence = dest0.edge_valence = 6;
+ dest0.border_index = 2;
+ dest1.border_index = 4;
+ dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];
+ dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;
+
+ dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];
+ dest1.ring[1] = dest0.ring[5] = (Vertex_t)p1.ring[0];
+ dest1.ring[0] = dest0.ring[4] = (Vertex_t)p1.vtx;
+ dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.border_index+1]; // dummy
+ dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;
+ dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];
+
+ dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;
+ dest1.crease_weight[0] = dest0.crease_weight[2] = p1.crease_weight[1];
+ dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];
+
+ if (p0.eval_unique_identifier <= p1.eval_unique_identifier)
+ {
+ dest0.eval_start_index = 1;
+ dest1.eval_start_index = 2;
+ dest0.eval_unique_identifier = p0.eval_unique_identifier;
+ dest1.eval_unique_identifier = p0.eval_unique_identifier;
+ }
+ else
+ {
+ dest0.eval_start_index = 2;
+ dest1.eval_start_index = 0;
+ dest0.eval_unique_identifier = p1.eval_unique_identifier;
+ dest1.eval_unique_identifier = p1.eval_unique_identifier;
+ }
+ }
+
+ static __forceinline void init_regular(const Vertex_t &center, const Vertex_t center_ring[8], const unsigned int offset, CatmullClark1RingT<Vertex,Vertex_t> &dest)
+ {
+ dest.vertex_level = 0.0f;
+ dest.face_valence = 4;
+ dest.edge_valence = 8;
+ dest.border_index = -1;
+ dest.vtx = (Vertex_t)center;
+ dest.vertex_crease_weight = 0.0f;
+ for (size_t i=0; i<8; i++)
+ dest.ring[i] = (Vertex_t)center_ring[(offset+i)%8];
+ for (size_t i=0; i<4; i++)
+ dest.crease_weight[i] = 0.0f;
+
+ dest.eval_start_index = (8-offset)>>1;
+ if (dest.eval_start_index >= dest.face_valence) dest.eval_start_index -= dest.face_valence;
+ assert( dest.eval_start_index < dest.face_valence );
+ dest.eval_unique_identifier = 0;
+ }
+
+ __noinline void subdivide(array_t<CatmullClarkPatchT,4>& patch) const
+ {
+ ring[0].subdivide(patch[0].ring[0]);
+ ring[1].subdivide(patch[1].ring[1]);
+ ring[2].subdivide(patch[2].ring[2]);
+ ring[3].subdivide(patch[3].ring[3]);
+
+ patch[0].ring[0].edge_level = 0.5f*ring[0].edge_level;
+ patch[0].ring[1].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);
+ patch[0].ring[2].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);
+ patch[0].ring[3].edge_level = 0.5f*ring[3].edge_level;
+
+ patch[1].ring[0].edge_level = 0.5f*ring[0].edge_level;
+ patch[1].ring[1].edge_level = 0.5f*ring[1].edge_level;
+ patch[1].ring[2].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);
+ patch[1].ring[3].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);
+
+ patch[2].ring[0].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);
+ patch[2].ring[1].edge_level = 0.5f*ring[1].edge_level;
+ patch[2].ring[2].edge_level = 0.5f*ring[2].edge_level;
+ patch[2].ring[3].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);
+
+ patch[3].ring[0].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);
+ patch[3].ring[1].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);
+ patch[3].ring[2].edge_level = 0.5f*ring[2].edge_level;
+ patch[3].ring[3].edge_level = 0.5f*ring[3].edge_level;
+
+ const bool regular0 = ring[0].has_last_face() && ring[1].face_valence > 2;
+ if (likely(regular0))
+ init_regular(patch[0].ring[0],patch[1].ring[1],patch[0].ring[1],patch[1].ring[0]);
+ else
+ init_border(patch[0].ring[0],patch[1].ring[1],patch[0].ring[1],patch[1].ring[0]);
+
+ const bool regular1 = ring[1].has_last_face() && ring[2].face_valence > 2;
+ if (likely(regular1))
+ init_regular(patch[1].ring[1],patch[2].ring[2],patch[1].ring[2],patch[2].ring[1]);
+ else
+ init_border(patch[1].ring[1],patch[2].ring[2],patch[1].ring[2],patch[2].ring[1]);
+
+ const bool regular2 = ring[2].has_last_face() && ring[3].face_valence > 2;
+ if (likely(regular2))
+ init_regular(patch[2].ring[2],patch[3].ring[3],patch[2].ring[3],patch[3].ring[2]);
+ else
+ init_border(patch[2].ring[2],patch[3].ring[3],patch[2].ring[3],patch[3].ring[2]);
+
+ const bool regular3 = ring[3].has_last_face() && ring[0].face_valence > 2;
+ if (likely(regular3))
+ init_regular(patch[3].ring[3],patch[0].ring[0],patch[3].ring[0],patch[0].ring[3]);
+ else
+ init_border(patch[3].ring[3],patch[0].ring[0],patch[3].ring[0],patch[0].ring[3]);
+
+ Vertex_t center = (ring[0].vtx + ring[1].vtx + ring[2].vtx + ring[3].vtx) * 0.25f;
+
+ Vertex_t center_ring[8];
+ center_ring[0] = (Vertex_t)patch[3].ring[3].ring[0];
+ center_ring[7] = (Vertex_t)patch[3].ring[3].vtx;
+ center_ring[6] = (Vertex_t)patch[2].ring[2].ring[0];
+ center_ring[5] = (Vertex_t)patch[2].ring[2].vtx;
+ center_ring[4] = (Vertex_t)patch[1].ring[1].ring[0];
+ center_ring[3] = (Vertex_t)patch[1].ring[1].vtx;
+ center_ring[2] = (Vertex_t)patch[0].ring[0].ring[0];
+ center_ring[1] = (Vertex_t)patch[0].ring[0].vtx;
+
+ init_regular(center,center_ring,0,patch[0].ring[2]);
+ init_regular(center,center_ring,2,patch[1].ring[3]);
+ init_regular(center,center_ring,4,patch[2].ring[0]);
+ init_regular(center,center_ring,6,patch[3].ring[1]);
+
+ assert(patch[0].verify());
+ assert(patch[1].verify());
+ assert(patch[2].verify());
+ assert(patch[3].verify());
+ }
+
+ bool verify() const {
+ return ring[0].hasValidPositions() && ring[1].hasValidPositions() && ring[2].hasValidPositions() && ring[3].hasValidPositions();
+ }
+
+ __forceinline void init( FinalQuad& quad ) const
+ {
+ quad.vtx[0] = (Vertex_t)ring[0].vtx;
+ quad.vtx[1] = (Vertex_t)ring[1].vtx;
+ quad.vtx[2] = (Vertex_t)ring[2].vtx;
+ quad.vtx[3] = (Vertex_t)ring[3].vtx;
+ };
+
+ friend __forceinline embree_ostream operator<<(embree_ostream o, const CatmullClarkPatchT &p)
+ {
+ o << "CatmullClarkPatch { " << embree_endl;
+ for (size_t i=0; i<4; i++)
+ o << "ring" << i << ": " << p.ring[i] << embree_endl;
+ o << "}" << embree_endl;
+ return o;
+ }
+ };
+
+ typedef CatmullClarkPatchT<Vec3fa,Vec3fa_t> CatmullClarkPatch3fa;
+
+ template<typename Vertex, typename Vertex_t = Vertex>
+ class __aligned(64) GeneralCatmullClarkPatchT
+ {
+ public:
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;
+ typedef BezierCurveT<Vertex> BezierCurve;
+
+ static const unsigned SIZE = MAX_PATCH_VALENCE;
+ DynamicStackArray<GeneralCatmullClark1RingT<Vertex,Vertex_t>,8,SIZE> ring;
+ unsigned N;
+
+ __forceinline GeneralCatmullClarkPatchT ()
+ : N(0) {}
+
+ GeneralCatmullClarkPatchT (const HalfEdge* h, const char* vertices, size_t stride) {
+ init(h,vertices,stride);
+ }
+
+ __forceinline GeneralCatmullClarkPatchT (const HalfEdge* first_half_edge, const BufferView<Vec3fa>& vertices) {
+ init(first_half_edge,vertices.getPtr(),vertices.getStride());
+ }
+
+ __forceinline void init (const HalfEdge* h, const char* vertices, size_t stride)
+ {
+ unsigned int i = 0;
+ const HalfEdge* edge = h;
+ do {
+ ring[i].init(edge,vertices,stride);
+ edge = edge->next();
+ i++;
+ } while ((edge != h) && (i < SIZE));
+ N = i;
+ }
+
+ __forceinline unsigned size() const {
+ return N;
+ }
+
+ __forceinline bool isQuadPatch() const {
+ return (N == 4) && ring[0].only_quads && ring[1].only_quads && ring[2].only_quads && ring[3].only_quads;
+ }
+
+ static __forceinline void init_regular(const CatmullClark1RingT<Vertex,Vertex_t>& p0,
+ const CatmullClark1RingT<Vertex,Vertex_t>& p1,
+ CatmullClark1RingT<Vertex,Vertex_t>& dest0,
+ CatmullClark1RingT<Vertex,Vertex_t>& dest1)
+ {
+ assert(p1.face_valence > 2);
+ dest1.vertex_level = dest0.vertex_level = p0.edge_level;
+ dest1.face_valence = dest0.face_valence = 4;
+ dest1.edge_valence = dest0.edge_valence = 8;
+ dest1.border_index = dest0.border_index = -1;
+ dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];
+ dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;
+
+ dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];
+ dest1.ring[1] = dest0.ring[7] = (Vertex_t)p1.ring[0];
+ dest1.ring[0] = dest0.ring[6] = (Vertex_t)p1.vtx;
+ dest1.ring[7] = dest0.ring[5] = (Vertex_t)p1.ring[4];
+ dest1.ring[6] = dest0.ring[4] = (Vertex_t)p0.ring[p0.edge_valence-1];
+ dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.edge_valence-2];
+ dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;
+ dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];
+
+ dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;
+ dest1.crease_weight[0] = dest0.crease_weight[3] = p1.crease_weight[1];
+ dest1.crease_weight[3] = dest0.crease_weight[2] = 0.0f;
+ dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];
+
+ if (p0.eval_unique_identifier <= p1.eval_unique_identifier)
+ {
+ dest0.eval_start_index = 3;
+ dest1.eval_start_index = 0;
+ dest0.eval_unique_identifier = p0.eval_unique_identifier;
+ dest1.eval_unique_identifier = p0.eval_unique_identifier;
+ }
+ else
+ {
+ dest0.eval_start_index = 1;
+ dest1.eval_start_index = 2;
+ dest0.eval_unique_identifier = p1.eval_unique_identifier;
+ dest1.eval_unique_identifier = p1.eval_unique_identifier;
+ }
+ }
+
+
+ static __forceinline void init_border(const CatmullClark1RingT<Vertex,Vertex_t> &p0,
+ const CatmullClark1RingT<Vertex,Vertex_t> &p1,
+ CatmullClark1RingT<Vertex,Vertex_t> &dest0,
+ CatmullClark1RingT<Vertex,Vertex_t> &dest1)
+ {
+ dest1.vertex_level = dest0.vertex_level = p0.edge_level;
+ dest1.face_valence = dest0.face_valence = 3;
+ dest1.edge_valence = dest0.edge_valence = 6;
+ dest0.border_index = 2;
+ dest1.border_index = 4;
+ dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];
+ dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;
+
+ dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];
+ dest1.ring[1] = dest0.ring[5] = (Vertex_t)p1.ring[0];
+ dest1.ring[0] = dest0.ring[4] = (Vertex_t)p1.vtx;
+ dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.border_index+1]; // dummy
+ dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;
+ dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];
+
+ dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;
+ dest1.crease_weight[0] = dest0.crease_weight[2] = p1.crease_weight[1];
+ dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];
+
+ if (p0.eval_unique_identifier <= p1.eval_unique_identifier)
+ {
+ dest0.eval_start_index = 1;
+ dest1.eval_start_index = 2;
+ dest0.eval_unique_identifier = p0.eval_unique_identifier;
+ dest1.eval_unique_identifier = p0.eval_unique_identifier;
+ }
+ else
+ {
+ dest0.eval_start_index = 2;
+ dest1.eval_start_index = 0;
+ dest0.eval_unique_identifier = p1.eval_unique_identifier;
+ dest1.eval_unique_identifier = p1.eval_unique_identifier;
+ }
+ }
+
+ static __forceinline void init_regular(const Vertex_t &center, const array_t<Vertex_t,2*SIZE>& center_ring, const float vertex_level, const unsigned int N, const unsigned int offset, CatmullClark1RingT<Vertex,Vertex_t> &dest)
+ {
+ assert(N<(MAX_RING_FACE_VALENCE));
+ assert(2*N<(MAX_RING_EDGE_VALENCE));
+ dest.vertex_level = vertex_level;
+ dest.face_valence = N;
+ dest.edge_valence = 2*N;
+ dest.border_index = -1;
+ dest.vtx = (Vertex_t)center;
+ dest.vertex_crease_weight = 0.0f;
+ for (unsigned i=0; i<2*N; i++) {
+ dest.ring[i] = (Vertex_t)center_ring[(2*N+offset+i-1)%(2*N)];
+ assert(isvalid(dest.ring[i]));
+ }
+ for (unsigned i=0; i<N; i++)
+ dest.crease_weight[i] = 0.0f;
+
+ assert(offset <= 2*N);
+ dest.eval_start_index = (2*N-offset)>>1;
+ if (dest.eval_start_index >= dest.face_valence) dest.eval_start_index -= dest.face_valence;
+
+ assert( dest.eval_start_index < dest.face_valence );
+ dest.eval_unique_identifier = 0;
+ }
+
+ __noinline void subdivide(array_t<CatmullClarkPatch,SIZE>& patch, unsigned& N_o) const
+ {
+ N_o = N;
+ assert( N );
+ for (unsigned i=0; i<N; i++) {
+ unsigned ip1 = (i+1)%N; // FIXME: %
+ ring[i].subdivide(patch[i].ring[0]);
+ patch[i] .ring[0].edge_level = 0.5f*ring[i].edge_level;
+ patch[ip1].ring[3].edge_level = 0.5f*ring[i].edge_level;
+
+ assert( patch[i].ring[0].hasValidPositions() );
+
+ }
+ assert(N < 2*SIZE);
+ Vertex_t center = Vertex_t(0.0f);
+ array_t<Vertex_t,2*SIZE> center_ring;
+ float center_vertex_level = 2.0f; // guarantees that irregular vertices get always isolated also for non-quads
+
+ for (unsigned i=0; i<N; i++)
+ {
+ unsigned ip1 = (i+1)%N; // FIXME: %
+ unsigned im1 = (i+N-1)%N; // FIXME: %
+ bool regular = ring[i].has_last_face() && ring[ip1].face_valence > 2;
+ if (likely(regular)) init_regular(patch[i].ring[0],patch[ip1].ring[0],patch[i].ring[1],patch[ip1].ring[3]);
+ else init_border (patch[i].ring[0],patch[ip1].ring[0],patch[i].ring[1],patch[ip1].ring[3]);
+
+ assert( patch[i].ring[1].hasValidPositions() );
+ assert( patch[ip1].ring[3].hasValidPositions() );
+
+ float level = 0.25f*(ring[im1].edge_level+ring[ip1].edge_level);
+ patch[i].ring[1].edge_level = patch[ip1].ring[2].edge_level = level;
+ center_vertex_level = max(center_vertex_level,level);
+
+ center += ring[i].vtx;
+ center_ring[2*i+0] = (Vertex_t)patch[i].ring[0].vtx;
+ center_ring[2*i+1] = (Vertex_t)patch[i].ring[0].ring[0];
+ }
+ center /= float(N);
+
+ for (unsigned int i=0; i<N; i++) {
+ init_regular(center,center_ring,center_vertex_level,N,2*i,patch[i].ring[2]);
+
+ assert( patch[i].ring[2].hasValidPositions() );
+ }
+ }
+
+ void init(CatmullClarkPatch& patch) const
+ {
+ assert(size() == 4);
+ ring[0].convert(patch.ring[0]);
+ ring[1].convert(patch.ring[1]);
+ ring[2].convert(patch.ring[2]);
+ ring[3].convert(patch.ring[3]);
+ }
+
+ static void fix_quad_ring_order (array_t<CatmullClarkPatch,GeneralCatmullClarkPatchT::SIZE>& patches)
+ {
+ CatmullClark1Ring patches1ring1 = patches[1].ring[1];
+ patches[1].ring[1] = patches[1].ring[0]; // FIXME: optimize these assignments
+ patches[1].ring[0] = patches[1].ring[3];
+ patches[1].ring[3] = patches[1].ring[2];
+ patches[1].ring[2] = patches1ring1;
+
+ CatmullClark1Ring patches2ring2 = patches[2].ring[2];
+ patches[2].ring[2] = patches[2].ring[0];
+ patches[2].ring[0] = patches2ring2;
+ CatmullClark1Ring patches2ring3 = patches[2].ring[3];
+ patches[2].ring[3] = patches[2].ring[1];
+ patches[2].ring[1] = patches2ring3;
+
+ CatmullClark1Ring patches3ring3 = patches[3].ring[3];
+ patches[3].ring[3] = patches[3].ring[0];
+ patches[3].ring[0] = patches[3].ring[1];
+ patches[3].ring[1] = patches[3].ring[2];
+ patches[3].ring[2] = patches3ring3;
+ }
+
+ __forceinline void getLimitBorder(BezierCurve curves[GeneralCatmullClarkPatchT::SIZE]) const
+ {
+ Vertex P0 = ring[0].getLimitVertex();
+ for (unsigned i=0; i<N; i++)
+ {
+ const unsigned i0 = i, i1 = i+1==N ? 0 : i+1;
+ const Vertex P1 = madd(1.0f/3.0f,ring[i0].getLimitTangent(),P0);
+ const Vertex P3 = ring[i1].getLimitVertex();
+ const Vertex P2 = madd(1.0f/3.0f,ring[i1].getSecondLimitTangent(),P3);
+ new (&curves[i]) BezierCurve(P0,P1,P2,P3);
+ P0 = P3;
+ }
+ }
+
+ __forceinline void getLimitBorder(BezierCurve curves[2], const unsigned subPatch) const
+ {
+ const unsigned i0 = subPatch;
+ const Vertex t0_p = ring[i0].getLimitTangent();
+ const Vertex t0_m = ring[i0].getSecondLimitTangent();
+
+ const unsigned i1 = subPatch+1 == N ? 0 : subPatch+1;
+ const Vertex t1_p = ring[i1].getLimitTangent();
+ const Vertex t1_m = ring[i1].getSecondLimitTangent();
+
+ const unsigned i2 = subPatch == 0 ? N-1 : subPatch-1;
+ const Vertex t2_p = ring[i2].getLimitTangent();
+ const Vertex t2_m = ring[i2].getSecondLimitTangent();
+
+ const Vertex b00 = ring[i0].getLimitVertex();
+ const Vertex b03 = ring[i1].getLimitVertex();
+ const Vertex b33 = ring[i2].getLimitVertex();
+
+ const Vertex b01 = madd(1.0/3.0f,t0_p,b00);
+ const Vertex b11 = madd(1.0/3.0f,t0_m,b00);
+
+ //const Vertex b13 = madd(1.0/3.0f,t1_p,b03);
+ const Vertex b02 = madd(1.0/3.0f,t1_m,b03);
+
+ const Vertex b22 = madd(1.0/3.0f,t2_p,b33);
+ const Vertex b23 = madd(1.0/3.0f,t2_m,b33);
+
+ new (&curves[0]) BezierCurve(b00,b01,b02,b03);
+ new (&curves[1]) BezierCurve(b33,b22,b11,b00);
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream o, const GeneralCatmullClarkPatchT &p)
+ {
+ o << "GeneralCatmullClarkPatch { " << embree_endl;
+ for (unsigned i=0; i<p.N; i++)
+ o << "ring" << i << ": " << p.ring[i] << embree_endl;
+ o << "}" << embree_endl;
+ return o;
+ }
+ };
+
+ typedef GeneralCatmullClarkPatchT<Vec3fa,Vec3fa_t> GeneralCatmullClarkPatch3fa;
+}
diff --git a/thirdparty/embree/kernels/subdiv/catmullclark_ring.h b/thirdparty/embree/kernels/subdiv/catmullclark_ring.h
new file mode 100644
index 0000000000..e5ad5dadfe
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/catmullclark_ring.h
@@ -0,0 +1,826 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/geometry.h"
+#include "../common/buffer.h"
+#include "half_edge.h"
+#include "catmullclark_coefficients.h"
+
+namespace embree
+{
+ struct __aligned(64) FinalQuad {
+ Vec3fa vtx[4];
+ };
+
+ template<typename Vertex, typename Vertex_t = Vertex>
+ struct __aligned(64) CatmullClark1RingT
+ {
+ ALIGNED_STRUCT_(64);
+
+ int border_index; //!< edge index where border starts
+ unsigned int face_valence; //!< number of adjacent quad faces
+ unsigned int edge_valence; //!< number of adjacent edges (2*face_valence)
+ float vertex_crease_weight; //!< weight of vertex crease (0 if no vertex crease)
+ DynamicStackArray<float,16,MAX_RING_FACE_VALENCE> crease_weight; //!< edge crease weights for each adjacent edge
+ float vertex_level; //!< maximum level of all adjacent edges
+ float edge_level; //!< level of first edge
+ unsigned int eval_start_index; //!< topology dependent index to start evaluation
+ unsigned int eval_unique_identifier; //!< topology dependent unique identifier for this ring
+ Vertex vtx; //!< center vertex
+ DynamicStackArray<Vertex,32,MAX_RING_EDGE_VALENCE> ring; //!< ring of neighboring vertices
+
+ public:
+ CatmullClark1RingT ()
+ : eval_start_index(0), eval_unique_identifier(0) {} // FIXME: default constructor should be empty
+
+ /*! calculates number of bytes required to serialize this structure */
+ __forceinline size_t bytes() const
+ {
+ size_t ofs = 0;
+ ofs += sizeof(border_index);
+ ofs += sizeof(face_valence);
+ assert(2*face_valence == edge_valence);
+ ofs += sizeof(vertex_crease_weight);
+ ofs += face_valence*sizeof(float);
+ ofs += sizeof(vertex_level);
+ ofs += sizeof(edge_level);
+ ofs += sizeof(eval_start_index);
+ ofs += sizeof(eval_unique_identifier);
+ ofs += sizeof(vtx);
+ ofs += edge_valence*sizeof(Vertex);
+ return ofs;
+ }
+
+ template<typename Ty>
+ static __forceinline void store(char* ptr, size_t& ofs, const Ty& v) {
+ *(Ty*)&ptr[ofs] = v; ofs += sizeof(Ty);
+ }
+
+ template<typename Ty>
+ static __forceinline void load(char* ptr, size_t& ofs, Ty& v) {
+ v = *(Ty*)&ptr[ofs]; ofs += sizeof(Ty);
+ }
+
+ /*! serializes the ring to some memory location */
+ __forceinline void serialize(char* ptr, size_t& ofs) const
+ {
+ store(ptr,ofs,border_index);
+ store(ptr,ofs,face_valence);
+ store(ptr,ofs,vertex_crease_weight);
+ for (size_t i=0; i<face_valence; i++)
+ store(ptr,ofs,crease_weight[i]);
+ store(ptr,ofs,vertex_level);
+ store(ptr,ofs,edge_level);
+ store(ptr,ofs,eval_start_index);
+ store(ptr,ofs,eval_unique_identifier);
+ Vertex_t::storeu(&ptr[ofs],vtx); ofs += sizeof(Vertex);
+ for (size_t i=0; i<edge_valence; i++) {
+ Vertex_t::storeu(&ptr[ofs],ring[i]); ofs += sizeof(Vertex);
+ }
+ }
+
+ /*! deserializes the ring from some memory location */
+ __forceinline void deserialize(char* ptr, size_t& ofs)
+ {
+ load(ptr,ofs,border_index);
+ load(ptr,ofs,face_valence);
+ edge_valence = 2*face_valence;
+ load(ptr,ofs,vertex_crease_weight);
+ for (size_t i=0; i<face_valence; i++)
+ load(ptr,ofs,crease_weight[i]);
+ load(ptr,ofs,vertex_level);
+ load(ptr,ofs,edge_level);
+ load(ptr,ofs,eval_start_index);
+ load(ptr,ofs,eval_unique_identifier);
+ vtx = Vertex_t::loadu(&ptr[ofs]); ofs += sizeof(Vertex);
+ for (size_t i=0; i<edge_valence; i++) {
+ ring[i] = Vertex_t::loadu(&ptr[ofs]); ofs += sizeof(Vertex);
+ }
+ }
+
+ __forceinline bool hasBorder() const {
+ return border_index != -1;
+ }
+
+ __forceinline const Vertex& front(size_t i) const {
+ assert(edge_valence>i);
+ return ring[i];
+ }
+
+ __forceinline const Vertex& back(size_t i) const {
+ assert(edge_valence>=i);
+ return ring[edge_valence-i];
+ }
+
+ __forceinline bool has_last_face() const {
+ return (size_t)border_index != (size_t)edge_valence-2;
+ }
+
+ __forceinline bool has_opposite_front(size_t i) const {
+ return (size_t)border_index != 2*i;
+ }
+
+ __forceinline bool has_opposite_back(size_t i) const {
+ return (size_t)border_index != ((size_t)edge_valence-2-2*i);
+ }
+
+ __forceinline BBox3fa bounds() const
+ {
+ BBox3fa bounds ( vtx );
+ for (size_t i = 0; i<edge_valence ; i++)
+ bounds.extend( ring[i] );
+ return bounds;
+ }
+
+ /*! initializes the ring from the half edge structure */
+ __forceinline void init(const HalfEdge* const h, const char* vertices, size_t stride)
+ {
+ border_index = -1;
+ vtx = Vertex_t::loadu(vertices+h->getStartVertexIndex()*stride);
+ vertex_crease_weight = h->vertex_crease_weight;
+
+ HalfEdge* p = (HalfEdge*) h;
+
+ unsigned i=0;
+ unsigned min_vertex_index = (unsigned)-1;
+ unsigned min_vertex_index_face = (unsigned)-1;
+ edge_level = p->edge_level;
+ vertex_level = 0.0f;
+
+ do
+ {
+ vertex_level = max(vertex_level,p->edge_level);
+ crease_weight[i/2] = p->edge_crease_weight;
+ assert(p->hasOpposite() || p->edge_crease_weight == float(inf));
+
+ /* store first two vertices of face */
+ p = p->next();
+ const unsigned index0 = p->getStartVertexIndex();
+ ring[i++] = Vertex_t::loadu(vertices+index0*stride);
+ if (index0 < min_vertex_index) { min_vertex_index = index0; min_vertex_index_face = i>>1; }
+ p = p->next();
+
+ const unsigned index1 = p->getStartVertexIndex();
+ ring[i++] = Vertex_t::loadu(vertices+index1*stride);
+ p = p->next();
+
+ /* continue with next face */
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else
+ {
+ /* find minimum start vertex */
+ const unsigned index0 = p->getStartVertexIndex();
+ if (index0 < min_vertex_index) { min_vertex_index = index0; min_vertex_index_face = i>>1; }
+
+ /*! mark first border edge and store dummy vertex for face between the two border edges */
+ border_index = i;
+ crease_weight[i/2] = inf;
+ ring[i++] = Vertex_t::loadu(vertices+index0*stride);
+ ring[i++] = vtx; // dummy vertex
+
+ /*! goto other side of border */
+ p = (HalfEdge*) h;
+ while (p->hasOpposite())
+ p = p->opposite()->next();
+ }
+
+ } while (p != h);
+
+ edge_valence = i;
+ face_valence = i >> 1;
+ eval_unique_identifier = min_vertex_index;
+ eval_start_index = min_vertex_index_face;
+
+ assert( hasValidPositions() );
+ }
+
+ __forceinline void subdivide(CatmullClark1RingT& dest) const
+ {
+ dest.edge_level = 0.5f*edge_level;
+ dest.vertex_level = 0.5f*vertex_level;
+ dest.face_valence = face_valence;
+ dest.edge_valence = edge_valence;
+ dest.border_index = border_index;
+ dest.vertex_crease_weight = max(0.0f,vertex_crease_weight-1.0f);
+ dest.eval_start_index = eval_start_index;
+ dest.eval_unique_identifier = eval_unique_identifier;
+
+ /* calculate face points */
+ Vertex_t S = Vertex_t(0.0f);
+ for (size_t i=0; i<face_valence; i++)
+ {
+ size_t face_index = i + eval_start_index; if (face_index >= face_valence) face_index -= face_valence; assert(face_index < face_valence);
+ size_t index0 = 2*face_index+0; if (index0 >= edge_valence) index0 -= edge_valence; assert(index0 < edge_valence);
+ size_t index1 = 2*face_index+1; if (index1 >= edge_valence) index1 -= edge_valence; assert(index1 < edge_valence);
+ size_t index2 = 2*face_index+2; if (index2 >= edge_valence) index2 -= edge_valence; assert(index2 < edge_valence);
+ S += dest.ring[index1] = ((vtx + ring[index1]) + (ring[index0] + ring[index2])) * 0.25f;
+ }
+
+ /* calculate new edge points */
+ size_t num_creases = 0;
+ array_t<size_t,MAX_RING_FACE_VALENCE> crease_id;
+
+ for (size_t i=0; i<face_valence; i++)
+ {
+ size_t face_index = i + eval_start_index;
+ if (face_index >= face_valence) face_index -= face_valence;
+ const float edge_crease = crease_weight[face_index];
+ dest.crease_weight[face_index] = max(edge_crease-1.0f,0.0f);
+
+ size_t index = 2*face_index;
+ size_t prev_index = face_index == 0 ? edge_valence-1 : 2*face_index-1;
+ size_t next_index = 2*face_index+1;
+
+ const Vertex_t v = vtx + ring[index];
+ const Vertex_t f = dest.ring[prev_index] + dest.ring[next_index];
+ S += ring[index];
+
+ /* fast path for regular edge points */
+ if (likely(edge_crease <= 0.0f)) {
+ dest.ring[index] = (v+f) * 0.25f;
+ }
+
+ /* slower path for hard edge rule */
+ else {
+ crease_id[num_creases++] = face_index;
+ dest.ring[index] = v*0.5f;
+
+ /* even slower path for blended edge rule */
+ if (unlikely(edge_crease < 1.0f)) {
+ dest.ring[index] = lerp((v+f)*0.25f,v*0.5f,edge_crease);
+ }
+ }
+ }
+
+ /* compute new vertex using smooth rule */
+ const float inv_face_valence = 1.0f / (float)face_valence;
+ const Vertex_t v_smooth = (Vertex_t) madd(inv_face_valence,S,(float(face_valence)-2.0f)*vtx)*inv_face_valence;
+ dest.vtx = v_smooth;
+
+ /* compute new vertex using vertex_crease_weight rule */
+ if (unlikely(vertex_crease_weight > 0.0f))
+ {
+ if (vertex_crease_weight >= 1.0f) {
+ dest.vtx = vtx;
+ } else {
+ dest.vtx = lerp(v_smooth,vtx,vertex_crease_weight);
+ }
+ return;
+ }
+
+ /* no edge crease rule and dart rule */
+ if (likely(num_creases <= 1))
+ return;
+
+ /* compute new vertex using crease rule */
+ if (likely(num_creases == 2))
+ {
+ /* update vertex using crease rule */
+ const size_t crease0 = crease_id[0], crease1 = crease_id[1];
+ const Vertex_t v_sharp = (Vertex_t)(ring[2*crease0] + 6.0f*vtx + ring[2*crease1]) * (1.0f / 8.0f);
+ dest.vtx = v_sharp;
+
+ /* update crease_weights using chaikin rule */
+ const float crease_weight0 = crease_weight[crease0], crease_weight1 = crease_weight[crease1];
+ dest.crease_weight[crease0] = max(0.25f*(3.0f*crease_weight0 + crease_weight1)-1.0f,0.0f);
+ dest.crease_weight[crease1] = max(0.25f*(3.0f*crease_weight1 + crease_weight0)-1.0f,0.0f);
+
+ /* interpolate between sharp and smooth rule */
+ const float v_blend = 0.5f*(crease_weight0+crease_weight1);
+ if (unlikely(v_blend < 1.0f)) {
+ dest.vtx = lerp(v_smooth,v_sharp,v_blend);
+ }
+ }
+
+ /* compute new vertex using corner rule */
+ else {
+ dest.vtx = vtx;
+ }
+ }
+
+ __forceinline bool isRegular1() const
+ {
+ if (border_index == -1) {
+ if (face_valence == 4) return true;
+ } else {
+ if (face_valence < 4) return true;
+ }
+ return false;
+ }
+
+ __forceinline size_t numEdgeCreases() const
+ {
+ ssize_t numCreases = 0;
+ for (size_t i=0; i<face_valence; i++) {
+ numCreases += crease_weight[i] > 0.0f;
+ }
+ return numCreases;
+ }
+
+ enum Type {
+ TYPE_NONE = 0, //!< invalid type
+ TYPE_REGULAR = 1, //!< regular patch when ignoring creases
+ TYPE_REGULAR_CREASES = 2, //!< regular patch when considering creases
+ TYPE_GREGORY = 4, //!< gregory patch when ignoring creases
+ TYPE_GREGORY_CREASES = 8, //!< gregory patch when considering creases
+ TYPE_CREASES = 16 //!< patch has crease features
+ };
+
+ __forceinline Type type() const
+ {
+ /* check if there is an edge crease anywhere */
+ const size_t numCreases = numEdgeCreases();
+ const bool noInnerCreases = hasBorder() ? numCreases == 2 : numCreases == 0;
+
+ Type crease_mask = (Type) (TYPE_REGULAR | TYPE_GREGORY);
+ if (noInnerCreases ) crease_mask = (Type) (crease_mask | TYPE_REGULAR_CREASES | TYPE_GREGORY_CREASES);
+ if (numCreases != 0) crease_mask = (Type) (crease_mask | TYPE_CREASES);
+
+ /* calculate if this vertex is regular */
+ bool hasBorder = border_index != -1;
+ if (face_valence == 2 && hasBorder) {
+ if (vertex_crease_weight == 0.0f ) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
+ else if (vertex_crease_weight == float(inf)) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
+ else return TYPE_CREASES;
+ }
+ else if (vertex_crease_weight != 0.0f) return TYPE_CREASES;
+ else if (face_valence == 3 && hasBorder) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
+ else if (face_valence == 4 && !hasBorder) return (Type) (crease_mask & (TYPE_REGULAR | TYPE_REGULAR_CREASES | TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
+ else return (Type) (crease_mask & (TYPE_GREGORY | TYPE_GREGORY_CREASES | TYPE_CREASES));
+ }
+
+ __forceinline bool isFinalResolution(float res) const {
+ return vertex_level <= res;
+ }
+
+ /* computes the limit vertex */
+ __forceinline Vertex getLimitVertex() const
+ {
+ /* return hard corner */
+ if (unlikely(std::isinf(vertex_crease_weight)))
+ return vtx;
+
+ /* border vertex rule */
+ if (unlikely(border_index != -1))
+ {
+ const unsigned int second_border_index = border_index+2 >= int(edge_valence) ? 0 : border_index+2;
+ return (4.0f * vtx + (ring[border_index] + ring[second_border_index])) * 1.0f/6.0f;
+ }
+
+ Vertex_t F( 0.0f );
+ Vertex_t E( 0.0f );
+
+ assert(eval_start_index < face_valence);
+
+ for (size_t i=0; i<face_valence; i++) {
+ size_t index = i+eval_start_index;
+ if (index >= face_valence) index -= face_valence;
+ F += ring[2*index+1];
+ E += ring[2*index];
+ }
+
+ const float n = (float)face_valence;
+ return (Vertex_t)(n*n*vtx+4.0f*E+F) / ((n+5.0f)*n);
+ }
+
+ /* gets limit tangent in the direction of egde vtx -> ring[0] */
+ __forceinline Vertex getLimitTangent() const
+ {
+ if (unlikely(std::isinf(vertex_crease_weight)))
+ return ring[0] - vtx;
+
+ /* border vertex rule */
+ if (unlikely(border_index != -1))
+ {
+ if (border_index != (int)edge_valence-2 ) {
+ return ring[0] - vtx;
+ }
+ else
+ {
+ const unsigned int second_border_index = border_index+2 >= int(edge_valence) ? 0 : border_index+2;
+ return (ring[second_border_index] - ring[border_index]) * 0.5f;
+ }
+ }
+
+ Vertex_t alpha( 0.0f );
+ Vertex_t beta ( 0.0f );
+
+ const size_t n = face_valence;
+
+ assert(eval_start_index < face_valence);
+
+ Vertex_t q( 0.0f );
+ for (size_t i=0; i<face_valence; i++)
+ {
+ size_t index = i+eval_start_index;
+ if (index >= face_valence) index -= face_valence;
+ const float a = CatmullClarkPrecomputedCoefficients::table.limittangent_a(index,n);
+ const float b = CatmullClarkPrecomputedCoefficients::table.limittangent_b(index,n);
+ alpha += a * ring[2*index];
+ beta += b * ring[2*index+1];
+ }
+
+ const float sigma = CatmullClarkPrecomputedCoefficients::table.limittangent_c(n);
+ return sigma * (alpha + beta);
+ }
+
+ /* gets limit tangent in the direction of egde vtx -> ring[edge_valence-2] */
+ __forceinline Vertex getSecondLimitTangent() const
+ {
+ if (unlikely(std::isinf(vertex_crease_weight)))
+ return ring[2] - vtx;
+
+ /* border vertex rule */
+ if (unlikely(border_index != -1))
+ {
+ if (border_index != 2) {
+ return ring[2] - vtx;
+ }
+ else {
+ const unsigned int second_border_index = border_index+2 >= int(edge_valence) ? 0 : border_index+2;
+ return (ring[border_index] - ring[second_border_index]) * 0.5f;
+ }
+ }
+
+ Vertex_t alpha( 0.0f );
+ Vertex_t beta ( 0.0f );
+
+ const size_t n = face_valence;
+
+ assert(eval_start_index < face_valence);
+
+ for (size_t i=0; i<face_valence; i++)
+ {
+ size_t index = i+eval_start_index;
+ if (index >= face_valence) index -= face_valence;
+
+ size_t prev_index = index == 0 ? face_valence-1 : index-1; // need to be bit-wise exact in cosf eval
+ const float a = CatmullClarkPrecomputedCoefficients::table.limittangent_a(prev_index,n);
+ const float b = CatmullClarkPrecomputedCoefficients::table.limittangent_b(prev_index,n);
+ alpha += a * ring[2*index];
+ beta += b * ring[2*index+1];
+ }
+
+ const float sigma = CatmullClarkPrecomputedCoefficients::table.limittangent_c(n);
+ return sigma* (alpha + beta);
+ }
+
+ /* gets surface normal */
+ const Vertex getNormal() const {
+ return cross(getLimitTangent(),getSecondLimitTangent());
+ }
+
+ /* returns center of the n-th quad in the 1-ring */
+ __forceinline Vertex getQuadCenter(const size_t index) const
+ {
+ const Vertex_t &p0 = vtx;
+ const Vertex_t &p1 = ring[2*index+0];
+ const Vertex_t &p2 = ring[2*index+1];
+ const Vertex_t &p3 = index == face_valence-1 ? ring[0] : ring[2*index+2];
+ const Vertex p = (p0+p1+p2+p3) * 0.25f;
+ return p;
+ }
+
+ /* returns center of the n-th edge in the 1-ring */
+ __forceinline Vertex getEdgeCenter(const size_t index) const {
+ return (vtx + ring[index*2]) * 0.5f;
+ }
+
+ bool hasValidPositions() const
+ {
+ for (size_t i=0; i<edge_valence; i++) {
+ if (!isvalid(ring[i]))
+ return false;
+ }
+ return true;
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream o, const CatmullClark1RingT &c)
+ {
+ o << "vtx " << c.vtx << " size = " << c.edge_valence << ", " <<
+ "hard_edge = " << c.border_index << ", face_valence " << c.face_valence <<
+ ", edge_level = " << c.edge_level << ", vertex_level = " << c.vertex_level << ", eval_start_index: " << c.eval_start_index << ", ring: " << embree_endl;
+
+ for (unsigned int i=0; i<min(c.edge_valence,(unsigned int)MAX_RING_FACE_VALENCE); i++) {
+ o << i << " -> " << c.ring[i];
+ if (i % 2 == 0) o << " crease = " << c.crease_weight[i/2];
+ o << embree_endl;
+ }
+ return o;
+ }
+ };
+
+ typedef CatmullClark1RingT<Vec3fa,Vec3fa_t> CatmullClark1Ring3fa;
+
+ template<typename Vertex, typename Vertex_t = Vertex>
+ struct __aligned(64) GeneralCatmullClark1RingT
+ {
+ ALIGNED_STRUCT_(64);
+
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;
+
+ struct Face
+ {
+ __forceinline Face() {}
+ __forceinline Face (int size, float crease_weight)
+ : size(size), crease_weight(crease_weight) {}
+
+ // FIXME: add member that returns total number of vertices
+
+ int size; // number of vertices-2 of nth face in ring
+ float crease_weight;
+ };
+
+ Vertex vtx;
+ DynamicStackArray<Vertex,32,MAX_RING_EDGE_VALENCE> ring;
+ DynamicStackArray<Face,16,MAX_RING_FACE_VALENCE> faces;
+ unsigned int face_valence;
+ unsigned int edge_valence;
+ int border_face;
+ float vertex_crease_weight;
+ float vertex_level; //!< maximum level of adjacent edges
+ float edge_level; // level of first edge
+ bool only_quads; // true if all faces are quads
+ unsigned int eval_start_face_index;
+ unsigned int eval_start_vertex_index;
+ unsigned int eval_unique_identifier;
+
+ public:
+ GeneralCatmullClark1RingT()
+ : eval_start_face_index(0), eval_start_vertex_index(0), eval_unique_identifier(0) {}
+
+ __forceinline bool isRegular() const
+ {
+ if (border_face == -1 && face_valence == 4) return true;
+ return false;
+ }
+
+ __forceinline bool has_last_face() const {
+ return border_face != (int)face_valence-1;
+ }
+
+ __forceinline bool has_second_face() const {
+ return (border_face == -1) || (border_face >= 2);
+ }
+
+ bool hasValidPositions() const
+ {
+ for (size_t i=0; i<edge_valence; i++) {
+ if (!isvalid(ring[i]))
+ return false;
+ }
+ return true;
+ }
+
+ __forceinline void init(const HalfEdge* const h, const char* vertices, size_t stride)
+ {
+ only_quads = true;
+ border_face = -1;
+ vtx = Vertex_t::loadu(vertices+h->getStartVertexIndex()*stride);
+ vertex_crease_weight = h->vertex_crease_weight;
+ HalfEdge* p = (HalfEdge*) h;
+
+ unsigned int e=0, f=0;
+ unsigned min_vertex_index = (unsigned)-1;
+ unsigned min_vertex_index_face = (unsigned)-1;
+ unsigned min_vertex_index_vertex = (unsigned)-1;
+ edge_level = p->edge_level;
+ vertex_level = 0.0f;
+ do
+ {
+ HalfEdge* p_prev = p->prev();
+ HalfEdge* p_next = p->next();
+ const float crease_weight = p->edge_crease_weight;
+ assert(p->hasOpposite() || p->edge_crease_weight == float(inf));
+ vertex_level = max(vertex_level,p->edge_level);
+
+ /* find minimum start vertex */
+ unsigned vertex_index = p_next->getStartVertexIndex();
+ if (vertex_index < min_vertex_index) { min_vertex_index = vertex_index; min_vertex_index_face = f; min_vertex_index_vertex = e; }
+
+ /* store first N-2 vertices of face */
+ unsigned int vn = 0;
+ for (p = p_next; p!=p_prev; p=p->next()) {
+ ring[e++] = Vertex_t::loadu(vertices+p->getStartVertexIndex()*stride);
+ vn++;
+ }
+ faces[f++] = Face(vn,crease_weight);
+ only_quads &= (vn == 2);
+
+ /* continue with next face */
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else
+ {
+ /* find minimum start vertex */
+ unsigned vertex_index = p->getStartVertexIndex();
+ if (vertex_index < min_vertex_index) { min_vertex_index = vertex_index; min_vertex_index_face = f; min_vertex_index_vertex = e; }
+
+ /*! mark first border edge and store dummy vertex for face between the two border edges */
+ border_face = f;
+ faces[f++] = Face(2,inf);
+ ring[e++] = Vertex_t::loadu(vertices+p->getStartVertexIndex()*stride);
+ ring[e++] = vtx; // dummy vertex
+
+ /*! goto other side of border */
+ p = (HalfEdge*) h;
+ while (p->hasOpposite())
+ p = p->opposite()->next();
+ }
+
+ } while (p != h);
+
+ edge_valence = e;
+ face_valence = f;
+ eval_unique_identifier = min_vertex_index;
+ eval_start_face_index = min_vertex_index_face;
+ eval_start_vertex_index = min_vertex_index_vertex;
+
+ assert( hasValidPositions() );
+ }
+
+ __forceinline void subdivide(CatmullClark1Ring& dest) const
+ {
+ dest.edge_level = 0.5f*edge_level;
+ dest.vertex_level = 0.5f*vertex_level;
+ dest.face_valence = face_valence;
+ dest.edge_valence = 2*face_valence;
+ dest.border_index = border_face == -1 ? -1 : 2*border_face; // FIXME:
+ dest.vertex_crease_weight = max(0.0f,vertex_crease_weight-1.0f);
+ dest.eval_start_index = eval_start_face_index;
+ dest.eval_unique_identifier = eval_unique_identifier;
+ assert(dest.face_valence <= MAX_RING_FACE_VALENCE);
+
+ /* calculate face points */
+ Vertex_t S = Vertex_t(0.0f);
+ for (size_t face=0, v=eval_start_vertex_index; face<face_valence; face++) {
+ size_t f = (face + eval_start_face_index)%face_valence;
+
+ Vertex_t F = vtx;
+ for (size_t k=v; k<=v+faces[f].size; k++) F += ring[k%edge_valence]; // FIXME: optimize
+ S += dest.ring[2*f+1] = F/float(faces[f].size+2);
+ v+=faces[f].size;
+ v%=edge_valence;
+ }
+
+ /* calculate new edge points */
+ size_t num_creases = 0;
+ array_t<size_t,MAX_RING_FACE_VALENCE> crease_id;
+ Vertex_t C = Vertex_t(0.0f);
+ for (size_t face=0, j=eval_start_vertex_index; face<face_valence; face++)
+ {
+ size_t i = (face + eval_start_face_index)%face_valence;
+
+ const Vertex_t v = vtx + ring[j];
+ Vertex_t f = dest.ring[2*i+1];
+ if (i == 0) f += dest.ring[dest.edge_valence-1];
+ else f += dest.ring[2*i-1];
+ S += ring[j];
+ dest.crease_weight[i] = max(faces[i].crease_weight-1.0f,0.0f);
+
+ /* fast path for regular edge points */
+ if (likely(faces[i].crease_weight <= 0.0f)) {
+ dest.ring[2*i] = (v+f) * 0.25f;
+ }
+
+ /* slower path for hard edge rule */
+ else {
+ C += ring[j]; crease_id[num_creases++] = i;
+ dest.ring[2*i] = v*0.5f;
+
+ /* even slower path for blended edge rule */
+ if (unlikely(faces[i].crease_weight < 1.0f)) {
+ dest.ring[2*i] = lerp((v+f)*0.25f,v*0.5f,faces[i].crease_weight);
+ }
+ }
+ j+=faces[i].size;
+ j%=edge_valence;
+ }
+
+ /* compute new vertex using smooth rule */
+ const float inv_face_valence = 1.0f / (float)face_valence;
+ const Vertex_t v_smooth = (Vertex_t) madd(inv_face_valence,S,(float(face_valence)-2.0f)*vtx)*inv_face_valence;
+ dest.vtx = v_smooth;
+
+ /* compute new vertex using vertex_crease_weight rule */
+ if (unlikely(vertex_crease_weight > 0.0f))
+ {
+ if (vertex_crease_weight >= 1.0f) {
+ dest.vtx = vtx;
+ } else {
+ dest.vtx = lerp(vtx,v_smooth,vertex_crease_weight);
+ }
+ return;
+ }
+
+ if (likely(num_creases <= 1))
+ return;
+
+ /* compute new vertex using crease rule */
+ if (likely(num_creases == 2)) {
+ const Vertex_t v_sharp = (Vertex_t)(C + 6.0f * vtx) * (1.0f / 8.0f);
+ const float crease_weight0 = faces[crease_id[0]].crease_weight;
+ const float crease_weight1 = faces[crease_id[1]].crease_weight;
+ dest.vtx = v_sharp;
+ dest.crease_weight[crease_id[0]] = max(0.25f*(3.0f*crease_weight0 + crease_weight1)-1.0f,0.0f);
+ dest.crease_weight[crease_id[1]] = max(0.25f*(3.0f*crease_weight1 + crease_weight0)-1.0f,0.0f);
+ const float v_blend = 0.5f*(crease_weight0+crease_weight1);
+ if (unlikely(v_blend < 1.0f)) {
+ dest.vtx = lerp(v_sharp,v_smooth,v_blend);
+ }
+ }
+
+ /* compute new vertex using corner rule */
+ else {
+ dest.vtx = vtx;
+ }
+ }
+
+ void convert(CatmullClark1Ring& dst) const
+ {
+ dst.edge_level = edge_level;
+ dst.vertex_level = vertex_level;
+ dst.vtx = vtx;
+ dst.face_valence = face_valence;
+ dst.edge_valence = 2*face_valence;
+ dst.border_index = border_face == -1 ? -1 : 2*border_face;
+ for (size_t i=0; i<face_valence; i++)
+ dst.crease_weight[i] = faces[i].crease_weight;
+ dst.vertex_crease_weight = vertex_crease_weight;
+ for (size_t i=0; i<edge_valence; i++) dst.ring[i] = ring[i];
+
+ dst.eval_start_index = eval_start_face_index;
+ dst.eval_unique_identifier = eval_unique_identifier;
+
+ assert( dst.hasValidPositions() );
+ }
+
+
+ /* gets limit tangent in the direction of egde vtx -> ring[0] */
+ __forceinline Vertex getLimitTangent() const
+ {
+ CatmullClark1Ring cc_vtx;
+
+ /* fast path for quad only rings */
+ if (only_quads)
+ {
+ convert(cc_vtx);
+ return cc_vtx.getLimitTangent();
+ }
+
+ subdivide(cc_vtx);
+ return 2.0f * cc_vtx.getLimitTangent();
+ }
+
+ /* gets limit tangent in the direction of egde vtx -> ring[edge_valence-2] */
+ __forceinline Vertex getSecondLimitTangent() const
+ {
+ CatmullClark1Ring cc_vtx;
+
+ /* fast path for quad only rings */
+ if (only_quads)
+ {
+ convert(cc_vtx);
+ return cc_vtx.getSecondLimitTangent();
+ }
+
+ subdivide(cc_vtx);
+ return 2.0f * cc_vtx.getSecondLimitTangent();
+ }
+
+
+ /* gets limit vertex */
+ __forceinline Vertex getLimitVertex() const
+ {
+ CatmullClark1Ring cc_vtx;
+
+ /* fast path for quad only rings */
+ if (only_quads)
+ convert(cc_vtx);
+ else
+ subdivide(cc_vtx);
+ return cc_vtx.getLimitVertex();
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream o, const GeneralCatmullClark1RingT &c)
+ {
+ o << "vtx " << c.vtx << " size = " << c.edge_valence << ", border_face = " << c.border_face << ", " << " face_valence = " << c.face_valence <<
+ ", edge_level = " << c.edge_level << ", vertex_level = " << c.vertex_level << ", ring: " << embree_endl;
+ for (size_t v=0, f=0; f<c.face_valence; v+=c.faces[f++].size) {
+ for (size_t i=v; i<v+c.faces[f].size; i++) {
+ o << i << " -> " << c.ring[i];
+ if (i == v) o << " crease = " << c.faces[f].crease_weight;
+ o << embree_endl;
+ }
+ }
+ return o;
+ }
+ };
+}
diff --git a/thirdparty/embree/kernels/subdiv/catmullrom_curve.h b/thirdparty/embree/kernels/subdiv/catmullrom_curve.h
new file mode 100644
index 0000000000..74fc4c1230
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/catmullrom_curve.h
@@ -0,0 +1,297 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "../common/scene_curves.h"
+
+/*
+
+ Implements Catmul Rom curves with control points p0, p1, p2, p3. At
+ t=0 the curve goes through p1, with tangent (p2-p0)/3, and for t=1
+ the curve goes through p2 with tangent (p3-p2)/2.
+
+ */
+
+namespace embree
+{
+ class CatmullRomBasis
+ {
+ public:
+
+ template<typename T>
+ static __forceinline Vec4<T> eval(const T& u)
+ {
+ const T t = u;
+ const T s = T(1.0f) - u;
+ const T n0 = - t * s * s;
+ const T n1 = 2.0f + t * t * (3.0f * t - 5.0f);
+ const T n2 = 2.0f + s * s * (3.0f * s - 5.0f);
+ const T n3 = - s * t * t;
+ return T(0.5f) * Vec4<T>(n0, n1, n2, n3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative(const T& u)
+ {
+ const T t = u;
+ const T s = 1.0f - u;
+ const T n0 = - s * s + 2.0f * s * t;
+ const T n1 = 2.0f * t * (3.0f * t - 5.0f) + 3.0f * t * t;
+ const T n2 = 2.0f * s * (3.0f * t + 2.0f) - 3.0f * s * s;
+ const T n3 = -2.0f * s * t + t * t;
+ return T(0.5f) * Vec4<T>(n0, n1, n2, n3);
+ }
+
+ template<typename T>
+ static __forceinline Vec4<T> derivative2(const T& u)
+ {
+ const T t = u;
+ const T n0 = -3.0f * t + 2.0f;
+ const T n1 = 9.0f * t - 5.0f;
+ const T n2 = -9.0f * t + 4.0f;
+ const T n3 = 3.0f * t - 1.0f;
+ return Vec4<T>(n0, n1, n2, n3);
+ }
+ };
+
+ struct PrecomputedCatmullRomBasis
+ {
+ enum { N = 16 };
+ public:
+ PrecomputedCatmullRomBasis() {}
+ PrecomputedCatmullRomBasis(int shift);
+
+ /* basis for bspline evaluation */
+ public:
+ float c0[N+1][N+1];
+ float c1[N+1][N+1];
+ float c2[N+1][N+1];
+ float c3[N+1][N+1];
+
+ /* basis for bspline derivative evaluation */
+ public:
+ float d0[N+1][N+1];
+ float d1[N+1][N+1];
+ float d2[N+1][N+1];
+ float d3[N+1][N+1];
+ };
+ extern PrecomputedCatmullRomBasis catmullrom_basis0;
+ extern PrecomputedCatmullRomBasis catmullrom_basis1;
+
+ template<typename Vertex>
+ struct CatmullRomCurveT
+ {
+ Vertex v0,v1,v2,v3;
+
+ __forceinline CatmullRomCurveT() {}
+
+ __forceinline CatmullRomCurveT(const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3)
+ : v0(v0), v1(v1), v2(v2), v3(v3) {}
+
+ __forceinline Vertex begin() const {
+ return madd(1.0f/6.0f,v0,madd(2.0f/3.0f,v1,1.0f/6.0f*v2));
+ }
+
+ __forceinline Vertex end() const {
+ return madd(1.0f/6.0f,v1,madd(2.0f/3.0f,v2,1.0f/6.0f*v3));
+ }
+
+ __forceinline Vertex center() const {
+ return 0.25f*(v0+v1+v2+v3);
+ }
+
+ __forceinline BBox<Vertex> bounds() const {
+ return merge(BBox<Vertex>(v0),BBox<Vertex>(v1),BBox<Vertex>(v2),BBox<Vertex>(v3));
+ }
+
+ __forceinline friend CatmullRomCurveT operator -( const CatmullRomCurveT& a, const Vertex& b ) {
+ return CatmullRomCurveT(a.v0-b,a.v1-b,a.v2-b,a.v3-b);
+ }
+
+ __forceinline CatmullRomCurveT<Vec3ff> xfm_pr(const LinearSpace3fa& space, const Vec3fa& p) const
+ {
+ const Vec3ff q0(xfmVector(space,v0-p), v0.w);
+ const Vec3ff q1(xfmVector(space,v1-p), v1.w);
+ const Vec3ff q2(xfmVector(space,v2-p), v2.w);
+ const Vec3ff q3(xfmVector(space,v3-p), v3.w);
+ return CatmullRomCurveT<Vec3ff>(q0,q1,q2,q3);
+ }
+
+ __forceinline Vertex eval(const float t) const
+ {
+ const Vec4<float> b = CatmullRomBasis::eval(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline Vertex eval_du(const float t) const
+ {
+ const Vec4<float> b = CatmullRomBasis::derivative(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline Vertex eval_dudu(const float t) const
+ {
+ const Vec4<float> b = CatmullRomBasis::derivative2(t);
+ return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3)));
+ }
+
+ __forceinline void eval(const float t, Vertex& p, Vertex& dp, Vertex& ddp) const
+ {
+ p = eval(t);
+ dp = eval_du(t);
+ ddp = eval_dudu(t);
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = CatmullRomBasis::eval(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_du(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = CatmullRomBasis::derivative(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> veval_dudu(const vfloat<M>& t) const
+ {
+ const Vec4vf<M> b = CatmullRomBasis::derivative2(t);
+ return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline void veval(const vfloat<M>& t, Vec4vf<M>& p, Vec4vf<M>& dp) const
+ {
+ p = veval<M>(t);
+ dp = veval_du<M>(t);
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> eval0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedCatmullRomBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&catmullrom_basis0.c0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&catmullrom_basis0.c1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&catmullrom_basis0.c2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&catmullrom_basis0.c3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> eval1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedCatmullRomBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&catmullrom_basis1.c0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&catmullrom_basis1.c1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&catmullrom_basis1.c2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&catmullrom_basis1.c3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> derivative0(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedCatmullRomBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&catmullrom_basis0.d0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&catmullrom_basis0.d1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&catmullrom_basis0.d2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&catmullrom_basis0.d3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ template<int M>
+ __forceinline Vec4vf<M> derivative1(const int ofs, const int size) const
+ {
+ assert(size <= PrecomputedCatmullRomBasis::N);
+ assert(ofs <= size);
+ return madd(vfloat<M>::loadu(&catmullrom_basis1.d0[size][ofs]), Vec4vf<M>(v0),
+ madd(vfloat<M>::loadu(&catmullrom_basis1.d1[size][ofs]), Vec4vf<M>(v1),
+ madd(vfloat<M>::loadu(&catmullrom_basis1.d2[size][ofs]), Vec4vf<M>(v2),
+ vfloat<M>::loadu(&catmullrom_basis1.d3[size][ofs]) * Vec4vf<M>(v3))));
+ }
+
+ /* calculates bounds of catmull-rom curve geometry */
+ __forceinline BBox3fa accurateRoundBounds() const
+ {
+ const int N = 7;
+ const float scale = 1.0f/(3.0f*(N-1));
+ Vec4vfx pl(pos_inf), pu(neg_inf);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vintx vi = vintx(i)+vintx(step);
+ vboolx valid = vi <= vintx(N);
+ const Vec4vfx p = eval0<VSIZEX>(i,N);
+ const Vec4vfx dp = derivative0<VSIZEX>(i,N);
+ const Vec4vfx pm = p-Vec4vfx(scale)*select(vi!=vintx(0),dp,Vec4vfx(zero));
+ const Vec4vfx pp = p+Vec4vfx(scale)*select(vi!=vintx(N),dp,Vec4vfx(zero));
+ pl = select(valid,min(pl,p,pm,pp),pl); // FIXME: use masked min
+ pu = select(valid,max(pu,p,pm,pp),pu); // FIXME: use masked min
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const float r_min = reduce_min(pl.w);
+ const float r_max = reduce_max(pu.w);
+ const Vec3fa upper_r = Vec3fa(max(abs(r_min),abs(r_max)));
+ return enlarge(BBox3fa(lower,upper),upper_r);
+ }
+
+ /* calculates bounds when tessellated into N line segments */
+ __forceinline BBox3fa accurateFlatBounds(int N) const
+ {
+ if (likely(N == 4))
+ {
+ const Vec4vf4 pi = eval0<4>(0,4);
+ const Vec3fa lower(reduce_min(pi.x),reduce_min(pi.y),reduce_min(pi.z));
+ const Vec3fa upper(reduce_max(pi.x),reduce_max(pi.y),reduce_max(pi.z));
+ const Vec3fa upper_r = Vec3fa(reduce_max(abs(pi.w)));
+ const Vec3ff pe = end();
+ return enlarge(BBox3fa(min(lower,pe),max(upper,pe)),max(upper_r,Vec3fa(abs(pe.w))));
+ }
+ else
+ {
+ Vec3vfx pl(pos_inf), pu(neg_inf); vfloatx ru(0.0f);
+ for (int i=0; i<=N; i+=VSIZEX)
+ {
+ vboolx valid = vintx(i)+vintx(step) <= vintx(N);
+ const Vec4vfx pi = eval0<VSIZEX>(i,N);
+
+ pl.x = select(valid,min(pl.x,pi.x),pl.x); // FIXME: use masked min
+ pl.y = select(valid,min(pl.y,pi.y),pl.y);
+ pl.z = select(valid,min(pl.z,pi.z),pl.z);
+
+ pu.x = select(valid,max(pu.x,pi.x),pu.x); // FIXME: use masked min
+ pu.y = select(valid,max(pu.y,pi.y),pu.y);
+ pu.z = select(valid,max(pu.z,pi.z),pu.z);
+
+ ru = select(valid,max(ru,abs(pi.w)),ru);
+ }
+ const Vec3fa lower(reduce_min(pl.x),reduce_min(pl.y),reduce_min(pl.z));
+ const Vec3fa upper(reduce_max(pu.x),reduce_max(pu.y),reduce_max(pu.z));
+ const Vec3fa upper_r(reduce_max(ru));
+ return enlarge(BBox3fa(lower,upper),upper_r);
+ }
+ }
+
+ friend __forceinline embree_ostream operator<<(embree_ostream cout, const CatmullRomCurveT& curve) {
+ return cout << "CatmullRomCurve { v0 = " << curve.v0 << ", v1 = " << curve.v1 << ", v2 = " << curve.v2 << ", v3 = " << curve.v3 << " }";
+ }
+ };
+
+ template<typename CurveGeometry>
+ __forceinline CatmullRomCurveT<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const CatmullRomCurveT<Vec3ff>& curve)
+ {
+ return CatmullRomCurveT<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,curve.v0),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v1),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v2),
+ enlargeRadiusToMinWidth(context,geom,ray_org,curve.v3));
+ }
+
+ typedef CatmullRomCurveT<Vec3fa> CatmullRomCurve3fa;
+}
+
diff --git a/thirdparty/embree/kernels/subdiv/feature_adaptive_eval.h b/thirdparty/embree/kernels/subdiv/feature_adaptive_eval.h
new file mode 100644
index 0000000000..58c0b63e62
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/feature_adaptive_eval.h
@@ -0,0 +1,226 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename Vertex, typename Vertex_t = Vertex>
+ struct FeatureAdaptiveEval
+ {
+ public:
+
+ typedef PatchT<Vertex,Vertex_t> Patch;
+ typedef typename Patch::Ref Ref;
+ typedef GeneralCatmullClarkPatchT<Vertex,Vertex_t> GeneralCatmullClarkPatch;
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+ typedef BSplinePatchT<Vertex,Vertex_t> BSplinePatch;
+ typedef BezierPatchT<Vertex,Vertex_t> BezierPatch;
+ typedef GregoryPatchT<Vertex,Vertex_t> GregoryPatch;
+ typedef BilinearPatchT<Vertex,Vertex_t> BilinearPatch;
+ typedef BezierCurveT<Vertex> BezierCurve;
+
+ public:
+
+ FeatureAdaptiveEval (const HalfEdge* edge, const char* vertices, size_t stride, const float u, const float v,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv)
+ {
+ switch (edge->patch_type) {
+ case HalfEdge::BILINEAR_PATCH: BilinearPatch(edge,vertices,stride).eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f); break;
+ case HalfEdge::REGULAR_QUAD_PATCH: RegularPatchT(edge,vertices,stride).eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f); break;
+#if PATCH_USE_GREGORY == 2
+ case HalfEdge::IRREGULAR_QUAD_PATCH: GregoryPatch(edge,vertices,stride).eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f); break;
+#endif
+ default: {
+ GeneralCatmullClarkPatch patch(edge,vertices,stride);
+ eval(patch,Vec2f(u,v),0);
+ break;
+ }
+ }
+ }
+
+ FeatureAdaptiveEval (CatmullClarkPatch& patch, const float u, const float v, float dscale, size_t depth,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv)
+ {
+ eval(patch,Vec2f(u,v),dscale,depth);
+ }
+
+ void eval_general_quad(const GeneralCatmullClarkPatch& patch, array_t<CatmullClarkPatch,GeneralCatmullClarkPatch::SIZE>& patches, const Vec2f& uv, size_t depth)
+ {
+ float u = uv.x, v = uv.y;
+ if (v < 0.5f) {
+ if (u < 0.5f) {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,0);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[0],Vec2f(2.0f*u,2.0f*v),2.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[0],Vec2f(2.0f*u,2.0f*v),2.0f,depth+1);
+#endif
+ if (dPdu && dPdv) {
+ const Vertex dpdx = *dPdu, dpdy = *dPdv;
+ *dPdu = dpdx; *dPdv = dpdy;
+ }
+ }
+ else {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,1);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[1],Vec2f(2.0f*v,2.0f-2.0f*u),2.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[1],Vec2f(2.0f*v,2.0f-2.0f*u),2.0f,depth+1);
+#endif
+ if (dPdu && dPdv) {
+ const Vertex dpdx = *dPdu, dpdy = *dPdv;
+ *dPdu = -dpdy; *dPdv = dpdx;
+ }
+ }
+ } else {
+ if (u > 0.5f) {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,2);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[2],Vec2f(2.0f-2.0f*u,2.0f-2.0f*v),2.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[2],Vec2f(2.0f-2.0f*u,2.0f-2.0f*v),2.0f,depth+1);
+#endif
+ if (dPdu && dPdv) {
+ const Vertex dpdx = *dPdu, dpdy = *dPdv;
+ *dPdu = -dpdx; *dPdv = -dpdy;
+ }
+ }
+ else {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,3);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[3],Vec2f(2.0f-2.0f*v,2.0f*u),2.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[3],Vec2f(2.0f-2.0f*v,2.0f*u),2.0f,depth+1);
+#endif
+ if (dPdu && dPdv) {
+ const Vertex dpdx = *dPdu, dpdy = *dPdv;
+ *dPdu = dpdy; *dPdv = -dpdx;
+ }
+ }
+ }
+ }
+
+ __forceinline bool final(const CatmullClarkPatch& patch, const typename CatmullClarkRing::Type type, size_t depth)
+ {
+ const int max_eval_depth = (type & CatmullClarkRing::TYPE_CREASES) ? PATCH_MAX_EVAL_DEPTH_CREASE : PATCH_MAX_EVAL_DEPTH_IRREGULAR;
+//#if PATCH_MIN_RESOLUTION
+// return patch.isFinalResolution(PATCH_MIN_RESOLUTION) || depth>=(size_t)max_eval_depth;
+//#else
+ return depth>=(size_t)max_eval_depth;
+//#endif
+ }
+
+ void eval(CatmullClarkPatch& patch, Vec2f uv, float dscale, size_t depth,
+ BezierCurve* border0 = nullptr, BezierCurve* border1 = nullptr, BezierCurve* border2 = nullptr, BezierCurve* border3 = nullptr)
+ {
+ while (true)
+ {
+ typename CatmullClarkPatch::Type ty = patch.type();
+
+ if (unlikely(final(patch,ty,depth)))
+ {
+ if (ty & CatmullClarkRing::TYPE_REGULAR) {
+ RegularPatch(patch,border0,border1,border2,border3).eval(uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(234423,c,c,-1);
+ return;
+ } else {
+ IrregularFillPatch(patch,border0,border1,border2,border3).eval(uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(34534,c,-1,c);
+ return;
+ }
+ }
+ else if (ty & CatmullClarkRing::TYPE_REGULAR_CREASES) {
+ assert(depth > 0);
+ RegularPatch(patch,border0,border1,border2,border3).eval(uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(43524,c,c,-1);
+ return;
+ }
+#if PATCH_USE_GREGORY == 2
+ else if (ty & CatmullClarkRing::TYPE_GREGORY_CREASES) {
+ assert(depth > 0);
+ GregoryPatch(patch,border0,border1,border2,border3).eval(uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(23498,c,-1,c);
+ return;
+ }
+#endif
+ else
+ {
+ array_t<CatmullClarkPatch,4> patches;
+ patch.subdivide(patches); // FIXME: only have to generate one of the patches
+
+ const float u = uv.x, v = uv.y;
+ if (v < 0.5f) {
+ if (u < 0.5f) { patch = patches[0]; uv = Vec2f(2.0f*u,2.0f*v); dscale *= 2.0f; }
+ else { patch = patches[1]; uv = Vec2f(2.0f*u-1.0f,2.0f*v); dscale *= 2.0f; }
+ } else {
+ if (u > 0.5f) { patch = patches[2]; uv = Vec2f(2.0f*u-1.0f,2.0f*v-1.0f); dscale *= 2.0f; }
+ else { patch = patches[3]; uv = Vec2f(2.0f*u,2.0f*v-1.0f); dscale *= 2.0f; }
+ }
+ depth++;
+ }
+ }
+ }
+
+ void eval(const GeneralCatmullClarkPatch& patch, const Vec2f& uv, const size_t depth)
+ {
+ /* convert into standard quad patch if possible */
+ if (likely(patch.isQuadPatch()))
+ {
+ CatmullClarkPatch qpatch; patch.init(qpatch);
+ return eval(qpatch,uv,1.0f,depth);
+ }
+
+ /* subdivide patch */
+ unsigned N;
+ array_t<CatmullClarkPatch,GeneralCatmullClarkPatch::SIZE> patches;
+ patch.subdivide(patches,N); // FIXME: only have to generate one of the patches
+
+ /* parametrization for quads */
+ if (N == 4)
+ eval_general_quad(patch,patches,uv,depth);
+
+ /* parametrization for arbitrary polygons */
+ else
+ {
+ const unsigned l = (unsigned) floor(0.5f*uv.x); const float u = 2.0f*frac(0.5f*uv.x)-0.5f;
+ const unsigned h = (unsigned) floor(0.5f*uv.y); const float v = 2.0f*frac(0.5f*uv.y)-0.5f;
+ const unsigned i = 4*h+l; assert(i<N);
+ if (i >= N) return;
+
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,i);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[i],Vec2f(u,v),1.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[i],Vec2f(u,v),1.0f,depth+1);
+#endif
+ }
+ }
+
+ private:
+ Vertex* const P;
+ Vertex* const dPdu;
+ Vertex* const dPdv;
+ Vertex* const ddPdudu;
+ Vertex* const ddPdvdv;
+ Vertex* const ddPdudv;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/subdiv/feature_adaptive_eval_grid.h b/thirdparty/embree/kernels/subdiv/feature_adaptive_eval_grid.h
new file mode 100644
index 0000000000..4755aba28d
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/feature_adaptive_eval_grid.h
@@ -0,0 +1,359 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+#include "catmullclark_patch.h"
+#include "bspline_patch.h"
+#include "gregory_patch.h"
+#include "tessellation.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct FeatureAdaptiveEvalGrid
+ {
+ typedef CatmullClark1Ring3fa CatmullClarkRing;
+ typedef CatmullClarkPatch3fa CatmullClarkPatch;
+ typedef BilinearPatch3fa BilinearPatch;
+ typedef BSplinePatch3fa BSplinePatch;
+ typedef BezierPatch3fa BezierPatch;
+ typedef GregoryPatch3fa GregoryPatch;
+
+ private:
+ const unsigned x0,x1;
+ const unsigned y0,y1;
+ const unsigned swidth,sheight;
+ const float rcp_swidth, rcp_sheight;
+ float* const Px;
+ float* const Py;
+ float* const Pz;
+ float* const U;
+ float* const V;
+ float* const Nx;
+ float* const Ny;
+ float* const Nz;
+ const unsigned dwidth;
+ //const unsigned dheight;
+ unsigned count;
+
+
+ public:
+ FeatureAdaptiveEvalGrid (const GeneralCatmullClarkPatch3fa& patch, unsigned subPatch,
+ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
+ float* Px, float* Py, float* Pz, float* U, float* V,
+ float* Nx, float* Ny, float* Nz,
+ const unsigned dwidth, const unsigned dheight)
+ : x0(x0), x1(x1), y0(y0), y1(y1), swidth(swidth), sheight(sheight), rcp_swidth(1.0f/(swidth-1.0f)), rcp_sheight(1.0f/(sheight-1.0f)),
+ Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), /*dheight(dheight),*/ count(0)
+ {
+ assert(swidth < (2<<20) && sheight < (2<<20));
+ const BBox2f srange(Vec2f(0.0f,0.0f),Vec2f(float(swidth-1),float(sheight-1)));
+ const BBox2f erange(Vec2f((float)x0,(float)y0),Vec2f((float)x1,(float)y1));
+
+ /* convert into standard quad patch if possible */
+ if (likely(patch.isQuadPatch()))
+ {
+ CatmullClarkPatch3fa qpatch; patch.init(qpatch);
+ eval(qpatch, srange, erange, 0);
+ assert(count == (x1-x0+1)*(y1-y0+1));
+ return;
+ }
+
+ /* subdivide patch */
+ unsigned N;
+ array_t<CatmullClarkPatch3fa,GeneralCatmullClarkPatch3fa::SIZE> patches;
+ patch.subdivide(patches,N);
+
+ if (N == 4)
+ {
+ const Vec2f c = srange.center();
+ const BBox2f srange0(srange.lower,c);
+ const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));
+ const BBox2f srange2(c,srange.upper);
+ const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));
+
+#if PATCH_USE_GREGORY == 2
+ BezierCurve3fa borders[GeneralCatmullClarkPatch3fa::SIZE]; patch.getLimitBorder(borders);
+ BezierCurve3fa border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve3fa border1l,border1r; borders[1].subdivide(border1l,border1r);
+ BezierCurve3fa border2l,border2r; borders[2].subdivide(border2l,border2r);
+ BezierCurve3fa border3l,border3r; borders[3].subdivide(border3l,border3r);
+ GeneralCatmullClarkPatch3fa::fix_quad_ring_order(patches);
+ eval(patches[0],srange0,intersect(srange0,erange),1,&border0l,nullptr,nullptr,&border3r);
+ eval(patches[1],srange1,intersect(srange1,erange),1,&border0r,&border1l,nullptr,nullptr);
+ eval(patches[2],srange2,intersect(srange2,erange),1,nullptr,&border1r,&border2l,nullptr);
+ eval(patches[3],srange3,intersect(srange3,erange),1,nullptr,nullptr,&border2r,&border3l);
+#else
+ GeneralCatmullClarkPatch3fa::fix_quad_ring_order(patches);
+ eval(patches[0],srange0,intersect(srange0,erange),1);
+ eval(patches[1],srange1,intersect(srange1,erange),1);
+ eval(patches[2],srange2,intersect(srange2,erange),1);
+ eval(patches[3],srange3,intersect(srange3,erange),1);
+#endif
+ }
+ else
+ {
+ assert(subPatch < N);
+
+#if PATCH_USE_GREGORY == 2
+ BezierCurve3fa borders[2]; patch.getLimitBorder(borders,subPatch);
+ BezierCurve3fa border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve3fa border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval(patches[subPatch], srange, erange, 1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval(patches[subPatch], srange, erange, 1);
+#endif
+
+ }
+ assert(count == (x1-x0+1)*(y1-y0+1));
+ }
+
+ FeatureAdaptiveEvalGrid (const CatmullClarkPatch3fa& patch,
+ const BBox2f& srange, const BBox2f& erange, const unsigned depth,
+ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
+ float* Px, float* Py, float* Pz, float* U, float* V,
+ float* Nx, float* Ny, float* Nz,
+ const unsigned dwidth, const unsigned dheight)
+ : x0(x0), x1(x1), y0(y0), y1(y1), swidth(swidth), sheight(sheight), rcp_swidth(1.0f/(swidth-1.0f)), rcp_sheight(1.0f/(sheight-1.0f)),
+ Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), /*dheight(dheight),*/ count(0)
+ {
+ eval(patch,srange,erange,depth);
+ }
+
+ template<typename Patch>
+ void evalLocalGrid(const Patch& patch, const BBox2f& srange, const int lx0, const int lx1, const int ly0, const int ly1)
+ {
+ const float scale_x = rcp(srange.upper.x-srange.lower.x);
+ const float scale_y = rcp(srange.upper.y-srange.lower.y);
+ count += (lx1-lx0)*(ly1-ly0);
+
+#if 0
+ for (unsigned iy=ly0; iy<ly1; iy++) {
+ for (unsigned ix=lx0; ix<lx1; ix++) {
+ const float lu = select(ix == swidth -1, float(1.0f), (float(ix)-srange.lower.x)*scale_x);
+ const float lv = select(iy == sheight-1, float(1.0f), (float(iy)-srange.lower.y)*scale_y);
+ const Vec3fa p = patch.eval(lu,lv);
+ const float u = float(ix)*rcp_swidth;
+ const float v = float(iy)*rcp_sheight;
+ const int ofs = (iy-y0)*dwidth+(ix-x0);
+ Px[ofs] = p.x;
+ Py[ofs] = p.y;
+ Pz[ofs] = p.z;
+ U[ofs] = u;
+ V[ofs] = v;
+ }
+ }
+#else
+ foreach2(lx0,lx1,ly0,ly1,[&](const vboolx& valid, const vintx& ix, const vintx& iy) {
+ const vfloatx lu = select(ix == swidth -1, vfloatx(1.0f), (vfloatx(ix)-srange.lower.x)*scale_x);
+ const vfloatx lv = select(iy == sheight-1, vfloatx(1.0f), (vfloatx(iy)-srange.lower.y)*scale_y);
+ const Vec3vfx p = patch.eval(lu,lv);
+ Vec3vfx n = zero;
+ if (unlikely(Nx != nullptr)) n = normalize_safe(patch.normal(lu,lv));
+ const vfloatx u = vfloatx(ix)*rcp_swidth;
+ const vfloatx v = vfloatx(iy)*rcp_sheight;
+ const vintx ofs = (iy-y0)*dwidth+(ix-x0);
+ if (likely(all(valid)) && all(iy==iy[0])) {
+ const unsigned ofs2 = ofs[0];
+ vfloatx::storeu(Px+ofs2,p.x);
+ vfloatx::storeu(Py+ofs2,p.y);
+ vfloatx::storeu(Pz+ofs2,p.z);
+ vfloatx::storeu(U+ofs2,u);
+ vfloatx::storeu(V+ofs2,v);
+ if (unlikely(Nx != nullptr)) {
+ vfloatx::storeu(Nx+ofs2,n.x);
+ vfloatx::storeu(Ny+ofs2,n.y);
+ vfloatx::storeu(Nz+ofs2,n.z);
+ }
+ } else {
+ foreach_unique_index(valid,iy,[&](const vboolx& valid, const int iy0, const int j) {
+ const unsigned ofs2 = ofs[j]-j;
+ vfloatx::storeu(valid,Px+ofs2,p.x);
+ vfloatx::storeu(valid,Py+ofs2,p.y);
+ vfloatx::storeu(valid,Pz+ofs2,p.z);
+ vfloatx::storeu(valid,U+ofs2,u);
+ vfloatx::storeu(valid,V+ofs2,v);
+ if (unlikely(Nx != nullptr)) {
+ vfloatx::storeu(valid,Nx+ofs2,n.x);
+ vfloatx::storeu(valid,Ny+ofs2,n.y);
+ vfloatx::storeu(valid,Nz+ofs2,n.z);
+ }
+ });
+ }
+ });
+#endif
+ }
+
+ __forceinline bool final(const CatmullClarkPatch3fa& patch, const CatmullClarkRing::Type type, unsigned depth)
+ {
+ const unsigned max_eval_depth = (type & CatmullClarkRing::TYPE_CREASES) ? PATCH_MAX_EVAL_DEPTH_CREASE : PATCH_MAX_EVAL_DEPTH_IRREGULAR;
+//#if PATCH_MIN_RESOLUTION
+// return patch.isFinalResolution(PATCH_MIN_RESOLUTION) || depth>=max_eval_depth;
+//#else
+ return depth>=max_eval_depth;
+//#endif
+ }
+
+ void eval(const CatmullClarkPatch3fa& patch, const BBox2f& srange, const BBox2f& erange, const unsigned depth,
+ const BezierCurve3fa* border0 = nullptr, const BezierCurve3fa* border1 = nullptr, const BezierCurve3fa* border2 = nullptr, const BezierCurve3fa* border3 = nullptr)
+ {
+ if (erange.empty())
+ return;
+
+ int lx0 = (int) ceilf(erange.lower.x);
+ int lx1 = (int) ceilf(erange.upper.x) + (erange.upper.x == x1 && (srange.lower.x < erange.upper.x || erange.upper.x == 0));
+ int ly0 = (int) ceilf(erange.lower.y);
+ int ly1 = (int) ceilf(erange.upper.y) + (erange.upper.y == y1 && (srange.lower.y < erange.upper.y || erange.upper.y == 0));
+ if (lx0 >= lx1 || ly0 >= ly1) return;
+
+ CatmullClarkPatch::Type ty = patch.type();
+
+ if (unlikely(final(patch,ty,depth)))
+ {
+ if (ty & CatmullClarkRing::TYPE_REGULAR) {
+ RegularPatch rpatch(patch,border0,border1,border2,border3);
+ evalLocalGrid(rpatch,srange,lx0,lx1,ly0,ly1);
+ return;
+ } else {
+ IrregularFillPatch ipatch(patch,border0,border1,border2,border3);
+ evalLocalGrid(ipatch,srange,lx0,lx1,ly0,ly1);
+ return;
+ }
+ }
+ else if (ty & CatmullClarkRing::TYPE_REGULAR_CREASES) {
+ assert(depth > 0);
+ RegularPatch rpatch(patch,border0,border1,border2,border3);
+ evalLocalGrid(rpatch,srange,lx0,lx1,ly0,ly1);
+ return;
+ }
+#if PATCH_USE_GREGORY == 2
+ else if (ty & CatmullClarkRing::TYPE_GREGORY_CREASES) {
+ assert(depth > 0);
+ GregoryPatch gpatch(patch,border0,border1,border2,border3);
+ evalLocalGrid(gpatch,srange,lx0,lx1,ly0,ly1);
+ }
+#endif
+ else
+ {
+ array_t<CatmullClarkPatch3fa,4> patches;
+ patch.subdivide(patches);
+
+ const Vec2f c = srange.center();
+ const BBox2f srange0(srange.lower,c);
+ const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));
+ const BBox2f srange2(c,srange.upper);
+ const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));
+
+ eval(patches[0],srange0,intersect(srange0,erange),depth+1);
+ eval(patches[1],srange1,intersect(srange1,erange),depth+1);
+ eval(patches[2],srange2,intersect(srange2,erange),depth+1);
+ eval(patches[3],srange3,intersect(srange3,erange),depth+1);
+ }
+ }
+ };
+
+ template<typename Eval, typename Patch>
+ bool stitch_col(const Patch& patch, int subPatch,
+ const bool right, const unsigned y0, const unsigned y1, const int fine_y, const int coarse_y,
+ float* Px, float* Py, float* Pz, float* U, float* V, float* Nx, float* Ny, float* Nz, const unsigned dx0, const unsigned dwidth, const unsigned dheight)
+ {
+ assert(coarse_y <= fine_y);
+ if (likely(fine_y == coarse_y))
+ return false;
+
+ const unsigned y0s = stitch(y0,fine_y,coarse_y);
+ const unsigned y1s = stitch(y1,fine_y,coarse_y);
+ const unsigned M = y1s-y0s+1 + VSIZEX;
+
+ dynamic_large_stack_array(float,px,M,64*sizeof(float));
+ dynamic_large_stack_array(float,py,M,64*sizeof(float));
+ dynamic_large_stack_array(float,pz,M,64*sizeof(float));
+ dynamic_large_stack_array(float,u,M,64*sizeof(float));
+ dynamic_large_stack_array(float,v,M,64*sizeof(float));
+ dynamic_large_stack_array(float,nx,M,64*sizeof(float));
+ dynamic_large_stack_array(float,ny,M,64*sizeof(float));
+ dynamic_large_stack_array(float,nz,M,64*sizeof(float));
+ const bool has_Nxyz = Nx; assert(!Nx || (Ny && Nz));
+ Eval(patch,subPatch, right,right, y0s,y1s, 2,coarse_y+1, px,py,pz,u,v,
+ has_Nxyz ? (float*)nx : nullptr,has_Nxyz ? (float*)ny : nullptr ,has_Nxyz ? (float*)nz : nullptr, 1,4097);
+
+ for (unsigned y=y0; y<=y1; y++)
+ {
+ const unsigned ys = stitch(y,fine_y,coarse_y)-y0s;
+ Px[(y-y0)*dwidth+dx0] = px[ys];
+ Py[(y-y0)*dwidth+dx0] = py[ys];
+ Pz[(y-y0)*dwidth+dx0] = pz[ys];
+ U [(y-y0)*dwidth+dx0] = u[ys];
+ V [(y-y0)*dwidth+dx0] = v[ys];
+ if (unlikely(has_Nxyz)) {
+ Nx[(y-y0)*dwidth+dx0] = nx[ys];
+ Ny[(y-y0)*dwidth+dx0] = ny[ys];
+ Nz[(y-y0)*dwidth+dx0] = nz[ys];
+ }
+ }
+ return true;
+ }
+
+ template<typename Eval, typename Patch>
+ bool stitch_row(const Patch& patch, int subPatch,
+ const bool bottom, const unsigned x0, const unsigned x1, const int fine_x, const int coarse_x,
+ float* Px, float* Py, float* Pz, float* U, float* V, float* Nx, float* Ny, float* Nz, const unsigned dy0, const unsigned dwidth, const unsigned dheight)
+ {
+ assert(coarse_x <= fine_x);
+ if (likely(fine_x == coarse_x))
+ return false;
+
+ const unsigned x0s = stitch(x0,fine_x,coarse_x);
+ const unsigned x1s = stitch(x1,fine_x,coarse_x);
+ const unsigned M = x1s-x0s+1 + VSIZEX;
+
+ dynamic_large_stack_array(float,px,M,32*sizeof(float));
+ dynamic_large_stack_array(float,py,M,32*sizeof(float));
+ dynamic_large_stack_array(float,pz,M,32*sizeof(float));
+ dynamic_large_stack_array(float,u,M,32*sizeof(float));
+ dynamic_large_stack_array(float,v,M,32*sizeof(float));
+ dynamic_large_stack_array(float,nx,M,32*sizeof(float));
+ dynamic_large_stack_array(float,ny,M,32*sizeof(float));
+ dynamic_large_stack_array(float,nz,M,32*sizeof(float));
+ const bool has_Nxyz = Nx; assert(!Nx || (Ny && Nz));
+ Eval(patch,subPatch, x0s,x1s, bottom,bottom, coarse_x+1,2, px,py,pz,u,v,
+ has_Nxyz ? (float*)nx :nullptr, has_Nxyz ? (float*)ny : nullptr , has_Nxyz ? (float*)nz : nullptr, 4097,1);
+
+ for (unsigned x=x0; x<=x1; x++)
+ {
+ const unsigned xs = stitch(x,fine_x,coarse_x)-x0s;
+ Px[dy0*dwidth+x-x0] = px[xs];
+ Py[dy0*dwidth+x-x0] = py[xs];
+ Pz[dy0*dwidth+x-x0] = pz[xs];
+ U [dy0*dwidth+x-x0] = u[xs];
+ V [dy0*dwidth+x-x0] = v[xs];
+ if (unlikely(has_Nxyz)) {
+ Nx[dy0*dwidth+x-x0] = nx[xs];
+ Ny[dy0*dwidth+x-x0] = ny[xs];
+ Nz[dy0*dwidth+x-x0] = nz[xs];
+ }
+ }
+ return true;
+ }
+
+ template<typename Eval, typename Patch>
+ void feature_adaptive_eval_grid (const Patch& patch, unsigned subPatch, const float levels[4],
+ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
+ float* Px, float* Py, float* Pz, float* U, float* V, float* Nx, float* Ny, float* Nz, const unsigned dwidth, const unsigned dheight)
+ {
+ bool sl = false, sr = false, st = false, sb = false;
+ if (levels) {
+ sl = x0 == 0 && stitch_col<Eval,Patch>(patch,subPatch,0,y0,y1,sheight-1,int(levels[3]), Px,Py,Pz,U,V,Nx,Ny,Nz, 0 ,dwidth,dheight);
+ sr = x1 == swidth-1 && stitch_col<Eval,Patch>(patch,subPatch,1,y0,y1,sheight-1,int(levels[1]), Px,Py,Pz,U,V,Nx,Ny,Nz, x1-x0,dwidth,dheight);
+ st = y0 == 0 && stitch_row<Eval,Patch>(patch,subPatch,0,x0,x1,swidth-1,int(levels[0]), Px,Py,Pz,U,V,Nx,Ny,Nz, 0 ,dwidth,dheight);
+ sb = y1 == sheight-1 && stitch_row<Eval,Patch>(patch,subPatch,1,x0,x1,swidth-1,int(levels[2]), Px,Py,Pz,U,V,Nx,Ny,Nz, y1-y0,dwidth,dheight);
+ }
+ const unsigned ofs = st*dwidth+sl;
+ Eval(patch,subPatch,x0+sl,x1-sr,y0+st,y1-sb, swidth,sheight, Px+ofs,Py+ofs,Pz+ofs,U+ofs,V+ofs,Nx?Nx+ofs:nullptr,Ny?Ny+ofs:nullptr,Nz?Nz+ofs:nullptr, dwidth,dheight);
+ }
+ }
+}
+
diff --git a/thirdparty/embree/kernels/subdiv/feature_adaptive_eval_simd.h b/thirdparty/embree/kernels/subdiv/feature_adaptive_eval_simd.h
new file mode 100644
index 0000000000..edab0db12f
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/feature_adaptive_eval_simd.h
@@ -0,0 +1,186 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename vbool, typename vint, typename vfloat, typename Vertex, typename Vertex_t = Vertex>
+ struct FeatureAdaptiveEvalSimd
+ {
+ public:
+
+ typedef PatchT<Vertex,Vertex_t> Patch;
+ typedef typename Patch::Ref Ref;
+ typedef GeneralCatmullClarkPatchT<Vertex,Vertex_t> GeneralCatmullClarkPatch;
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+ typedef BSplinePatchT<Vertex,Vertex_t> BSplinePatch;
+ typedef BezierPatchT<Vertex,Vertex_t> BezierPatch;
+ typedef GregoryPatchT<Vertex,Vertex_t> GregoryPatch;
+ typedef BilinearPatchT<Vertex,Vertex_t> BilinearPatch;
+ typedef BezierCurveT<Vertex> BezierCurve;
+
+ FeatureAdaptiveEvalSimd (const HalfEdge* edge, const char* vertices, size_t stride, const vbool& valid, const vfloat& u, const vfloat& v,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, const size_t dstride, const size_t N)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv), dstride(dstride), N(N)
+ {
+ switch (edge->patch_type) {
+ case HalfEdge::BILINEAR_PATCH: BilinearPatch(edge,vertices,stride).eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f,dstride,N); break;
+ case HalfEdge::REGULAR_QUAD_PATCH: RegularPatchT(edge,vertices,stride).eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f,dstride,N); break;
+#if PATCH_USE_GREGORY == 2
+ case HalfEdge::IRREGULAR_QUAD_PATCH: GregoryPatchT<Vertex,Vertex_t>(edge,vertices,stride).eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,1.0f,dstride,N); break;
+#endif
+ default: {
+ GeneralCatmullClarkPatch patch(edge,vertices,stride);
+ eval_direct(valid,patch,Vec2<vfloat>(u,v),0);
+ break;
+ }
+ }
+ }
+
+ FeatureAdaptiveEvalSimd (const CatmullClarkPatch& patch, const vbool& valid, const vfloat& u, const vfloat& v, float dscale, size_t depth,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, const size_t dstride, const size_t N)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv), dstride(dstride), N(N)
+ {
+ eval_direct(valid,patch,Vec2<vfloat>(u,v),dscale,depth);
+ }
+
+ template<size_t N>
+ __forceinline void eval_quad_direct(const vbool& valid, array_t<CatmullClarkPatch,N>& patches, const Vec2<vfloat>& uv, float dscale, size_t depth)
+ {
+ const vfloat u = uv.x, v = uv.y;
+ const vbool u0_mask = u < 0.5f, u1_mask = u >= 0.5f;
+ const vbool v0_mask = v < 0.5f, v1_mask = v >= 0.5f;
+ const vbool u0v0_mask = valid & u0_mask & v0_mask;
+ const vbool u0v1_mask = valid & u0_mask & v1_mask;
+ const vbool u1v0_mask = valid & u1_mask & v0_mask;
+ const vbool u1v1_mask = valid & u1_mask & v1_mask;
+ if (any(u0v0_mask)) eval_direct(u0v0_mask,patches[0],Vec2<vfloat>(2.0f*u,2.0f*v),2.0f*dscale,depth+1);
+ if (any(u1v0_mask)) eval_direct(u1v0_mask,patches[1],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v),2.0f*dscale,depth+1);
+ if (any(u1v1_mask)) eval_direct(u1v1_mask,patches[2],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v-1.0f),2.0f*dscale,depth+1);
+ if (any(u0v1_mask)) eval_direct(u0v1_mask,patches[3],Vec2<vfloat>(2.0f*u,2.0f*v-1.0f),2.0f*dscale,depth+1);
+ }
+
+ template<size_t N>
+ __forceinline void eval_general_quad_direct(const vbool& valid, const GeneralCatmullClarkPatch& patch, array_t<CatmullClarkPatch,N>& patches, const Vec2<vfloat>& uv, float dscale, size_t depth)
+ {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[GeneralCatmullClarkPatch::SIZE]; patch.getLimitBorder(borders);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border1l,border1r; borders[1].subdivide(border1l,border1r);
+ BezierCurve border2l,border2r; borders[2].subdivide(border2l,border2r);
+ BezierCurve border3l,border3r; borders[3].subdivide(border3l,border3r);
+#endif
+ GeneralCatmullClarkPatch::fix_quad_ring_order(patches);
+ const vfloat u = uv.x, v = uv.y;
+ const vbool u0_mask = u < 0.5f, u1_mask = u >= 0.5f;
+ const vbool v0_mask = v < 0.5f, v1_mask = v >= 0.5f;
+ const vbool u0v0_mask = valid & u0_mask & v0_mask;
+ const vbool u0v1_mask = valid & u0_mask & v1_mask;
+ const vbool u1v0_mask = valid & u1_mask & v0_mask;
+ const vbool u1v1_mask = valid & u1_mask & v1_mask;
+#if PATCH_USE_GREGORY == 2
+ if (any(u0v0_mask)) eval_direct(u0v0_mask,patches[0],Vec2<vfloat>(2.0f*u,2.0f*v),2.0f*dscale,depth+1,&border0l,nullptr,nullptr,&border3r);
+ if (any(u1v0_mask)) eval_direct(u1v0_mask,patches[1],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v),2.0f*dscale,depth+1,&border0r,&border1l,nullptr,nullptr);
+ if (any(u1v1_mask)) eval_direct(u1v1_mask,patches[2],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v-1.0f),2.0f*dscale,depth+1,nullptr,&border1r,&border2l,nullptr);
+ if (any(u0v1_mask)) eval_direct(u0v1_mask,patches[3],Vec2<vfloat>(2.0f*u,2.0f*v-1.0f),2.0f*dscale,depth+1,nullptr,nullptr,&border2r,&border3l);
+#else
+ if (any(u0v0_mask)) eval_direct(u0v0_mask,patches[0],Vec2<vfloat>(2.0f*u,2.0f*v),2.0f*dscale,depth+1);
+ if (any(u1v0_mask)) eval_direct(u1v0_mask,patches[1],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v),2.0f*dscale,depth+1);
+ if (any(u1v1_mask)) eval_direct(u1v1_mask,patches[2],Vec2<vfloat>(2.0f*u-1.0f,2.0f*v-1.0f),2.0f*dscale,depth+1);
+ if (any(u0v1_mask)) eval_direct(u0v1_mask,patches[3],Vec2<vfloat>(2.0f*u,2.0f*v-1.0f),2.0f*dscale,depth+1);
+#endif
+ }
+
+ __forceinline bool final(const CatmullClarkPatch& patch, const typename CatmullClarkRing::Type type, size_t depth)
+ {
+ const size_t max_eval_depth = (type & CatmullClarkRing::TYPE_CREASES) ? PATCH_MAX_EVAL_DEPTH_CREASE : PATCH_MAX_EVAL_DEPTH_IRREGULAR;
+//#if PATCH_MIN_RESOLUTION
+// return patch.isFinalResolution(PATCH_MIN_RESOLUTION) || depth>=max_eval_depth;
+//#else
+ return depth>=max_eval_depth;
+//#endif
+ }
+
+ void eval_direct(const vbool& valid, const CatmullClarkPatch& patch, const Vec2<vfloat>& uv, float dscale, size_t depth,
+ BezierCurve* border0 = nullptr, BezierCurve* border1 = nullptr, BezierCurve* border2 = nullptr, BezierCurve* border3 = nullptr)
+ {
+ typename CatmullClarkPatch::Type ty = patch.type();
+
+ if (unlikely(final(patch,ty,depth)))
+ {
+ if (ty & CatmullClarkRing::TYPE_REGULAR) {
+ RegularPatch(patch,border0,border1,border2,border3).eval(valid,uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ } else {
+ IrregularFillPatch(patch,border0,border1,border2,border3).eval(valid,uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ }
+ }
+ else if (ty & CatmullClarkRing::TYPE_REGULAR_CREASES) {
+ assert(depth > 0); RegularPatch(patch,border0,border1,border2,border3).eval(valid,uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ }
+#if PATCH_USE_GREGORY == 2
+ else if (ty & CatmullClarkRing::TYPE_GREGORY_CREASES) {
+ assert(depth > 0); GregoryPatch(patch,border0,border1,border2,border3).eval(valid,uv.x,uv.y,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ }
+#endif
+ else
+ {
+ array_t<CatmullClarkPatch,4> patches;
+ patch.subdivide(patches); // FIXME: only have to generate one of the patches
+ eval_quad_direct(valid,patches,uv,dscale,depth);
+ }
+ }
+
+ void eval_direct(const vbool& valid, const GeneralCatmullClarkPatch& patch, const Vec2<vfloat>& uv, const size_t depth)
+ {
+ /* convert into standard quad patch if possible */
+ if (likely(patch.isQuadPatch())) {
+ CatmullClarkPatch qpatch; patch.init(qpatch);
+ return eval_direct(valid,qpatch,uv,1.0f,depth);
+ }
+
+ /* subdivide patch */
+ unsigned Nc;
+ array_t<CatmullClarkPatch,GeneralCatmullClarkPatch::SIZE> patches;
+ patch.subdivide(patches,Nc); // FIXME: only have to generate one of the patches
+
+ /* parametrization for quads */
+ if (Nc == 4)
+ eval_general_quad_direct(valid,patch,patches,uv,1.0f,depth);
+
+ /* parametrization for arbitrary polygons */
+ else
+ {
+ const vint l = (vint)floor(0.5f*uv.x); const vfloat u = 2.0f*frac(0.5f*uv.x)-0.5f;
+ const vint h = (vint)floor(0.5f*uv.y); const vfloat v = 2.0f*frac(0.5f*uv.y)-0.5f;
+ const vint i = (h<<2)+l; assert(all(valid,i<Nc));
+ foreach_unique(valid,i,[&](const vbool& valid, const int i) {
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[2]; patch.getLimitBorder(borders,i);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[1].subdivide(border2l,border2r);
+ eval_direct(valid,patches[i],Vec2<vfloat>(u,v),1.0f,depth+1, &border0l, nullptr, nullptr, &border2r);
+#else
+ eval_direct(valid,patches[i],Vec2<vfloat>(u,v),1.0f,depth+1);
+#endif
+ });
+ }
+ }
+
+ private:
+ float* const P;
+ float* const dPdu;
+ float* const dPdv;
+ float* const ddPdudu;
+ float* const ddPdvdv;
+ float* const ddPdudv;
+ const size_t dstride;
+ const size_t N;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/subdiv/gregory_patch.h b/thirdparty/embree/kernels/subdiv/gregory_patch.h
new file mode 100644
index 0000000000..9026d5c407
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/gregory_patch.h
@@ -0,0 +1,893 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_patch.h"
+#include "bezier_patch.h"
+#include "bezier_curve.h"
+#include "catmullclark_coefficients.h"
+
+namespace embree
+{
+ template<typename Vertex, typename Vertex_t = Vertex>
+ class __aligned(64) GregoryPatchT
+ {
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+ typedef GeneralCatmullClarkPatchT<Vertex,Vertex_t> GeneralCatmullClarkPatch;
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;
+ typedef BezierCurveT<Vertex> BezierCurve;
+
+ public:
+ Vertex v[4][4];
+ Vertex f[2][2];
+
+ __forceinline GregoryPatchT() {}
+
+ __forceinline GregoryPatchT(const CatmullClarkPatch& patch) {
+ init(patch);
+ }
+
+ __forceinline GregoryPatchT(const CatmullClarkPatch& patch,
+ const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
+ {
+ init_crackfix(patch,border0,border1,border2,border3);
+ }
+
+ __forceinline GregoryPatchT (const HalfEdge* edge, const char* vertices, size_t stride) {
+ init(CatmullClarkPatch(edge,vertices,stride));
+ }
+
+ __forceinline Vertex& p0() { return v[0][0]; }
+ __forceinline Vertex& p1() { return v[0][3]; }
+ __forceinline Vertex& p2() { return v[3][3]; }
+ __forceinline Vertex& p3() { return v[3][0]; }
+
+ __forceinline Vertex& e0_p() { return v[0][1]; }
+ __forceinline Vertex& e0_m() { return v[1][0]; }
+ __forceinline Vertex& e1_p() { return v[1][3]; }
+ __forceinline Vertex& e1_m() { return v[0][2]; }
+ __forceinline Vertex& e2_p() { return v[3][2]; }
+ __forceinline Vertex& e2_m() { return v[2][3]; }
+ __forceinline Vertex& e3_p() { return v[2][0]; }
+ __forceinline Vertex& e3_m() { return v[3][1]; }
+
+ __forceinline Vertex& f0_p() { return v[1][1]; }
+ __forceinline Vertex& f1_p() { return v[1][2]; }
+ __forceinline Vertex& f2_p() { return v[2][2]; }
+ __forceinline Vertex& f3_p() { return v[2][1]; }
+ __forceinline Vertex& f0_m() { return f[0][0]; }
+ __forceinline Vertex& f1_m() { return f[0][1]; }
+ __forceinline Vertex& f2_m() { return f[1][1]; }
+ __forceinline Vertex& f3_m() { return f[1][0]; }
+
+ __forceinline const Vertex& p0() const { return v[0][0]; }
+ __forceinline const Vertex& p1() const { return v[0][3]; }
+ __forceinline const Vertex& p2() const { return v[3][3]; }
+ __forceinline const Vertex& p3() const { return v[3][0]; }
+
+ __forceinline const Vertex& e0_p() const { return v[0][1]; }
+ __forceinline const Vertex& e0_m() const { return v[1][0]; }
+ __forceinline const Vertex& e1_p() const { return v[1][3]; }
+ __forceinline const Vertex& e1_m() const { return v[0][2]; }
+ __forceinline const Vertex& e2_p() const { return v[3][2]; }
+ __forceinline const Vertex& e2_m() const { return v[2][3]; }
+ __forceinline const Vertex& e3_p() const { return v[2][0]; }
+ __forceinline const Vertex& e3_m() const { return v[3][1]; }
+
+ __forceinline const Vertex& f0_p() const { return v[1][1]; }
+ __forceinline const Vertex& f1_p() const { return v[1][2]; }
+ __forceinline const Vertex& f2_p() const { return v[2][2]; }
+ __forceinline const Vertex& f3_p() const { return v[2][1]; }
+ __forceinline const Vertex& f0_m() const { return f[0][0]; }
+ __forceinline const Vertex& f1_m() const { return f[0][1]; }
+ __forceinline const Vertex& f2_m() const { return f[1][1]; }
+ __forceinline const Vertex& f3_m() const { return f[1][0]; }
+
+ __forceinline Vertex initCornerVertex(const CatmullClarkPatch& irreg_patch, const size_t index) {
+ return irreg_patch.ring[index].getLimitVertex();
+ }
+
+ __forceinline Vertex initPositiveEdgeVertex(const CatmullClarkPatch& irreg_patch, const size_t index, const Vertex& p_vtx) {
+ return madd(1.0f/3.0f,irreg_patch.ring[index].getLimitTangent(),p_vtx);
+ }
+
+ __forceinline Vertex initNegativeEdgeVertex(const CatmullClarkPatch& irreg_patch, const size_t index, const Vertex& p_vtx) {
+ return madd(1.0f/3.0f,irreg_patch.ring[index].getSecondLimitTangent(),p_vtx);
+ }
+
+ __forceinline Vertex initPositiveEdgeVertex2(const CatmullClarkPatch& irreg_patch, const size_t index, const Vertex& p_vtx)
+ {
+ CatmullClark1Ring3fa r0,r1,r2;
+ irreg_patch.ring[index].subdivide(r0);
+ r0.subdivide(r1);
+ r1.subdivide(r2);
+ return madd(8.0f/3.0f,r2.getLimitTangent(),p_vtx);
+ }
+
+ __forceinline Vertex initNegativeEdgeVertex2(const CatmullClarkPatch& irreg_patch, const size_t index, const Vertex& p_vtx)
+ {
+ CatmullClark1Ring3fa r0,r1,r2;
+ irreg_patch.ring[index].subdivide(r0);
+ r0.subdivide(r1);
+ r1.subdivide(r2);
+ return madd(8.0f/3.0f,r2.getSecondLimitTangent(),p_vtx);
+ }
+
+ void initFaceVertex(const CatmullClarkPatch& irreg_patch,
+ const size_t index,
+ const Vertex& p_vtx,
+ const Vertex& e0_p_vtx,
+ const Vertex& e1_m_vtx,
+ const unsigned int face_valence_p1,
+ const Vertex& e0_m_vtx,
+ const Vertex& e3_p_vtx,
+ const unsigned int face_valence_p3,
+ Vertex& f_p_vtx,
+ Vertex& f_m_vtx)
+ {
+ const unsigned int face_valence = irreg_patch.ring[index].face_valence;
+ const unsigned int edge_valence = irreg_patch.ring[index].edge_valence;
+ const unsigned int border_index = irreg_patch.ring[index].border_index;
+
+ const Vertex& vtx = irreg_patch.ring[index].vtx;
+ const Vertex e_i = irreg_patch.ring[index].getEdgeCenter(0);
+ const Vertex c_i_m_1 = irreg_patch.ring[index].getQuadCenter(0);
+ const Vertex e_i_m_1 = irreg_patch.ring[index].getEdgeCenter(1);
+
+ Vertex c_i, e_i_p_1;
+ const bool hasHardEdge0 =
+ std::isinf(irreg_patch.ring[index].vertex_crease_weight) &&
+ std::isinf(irreg_patch.ring[index].crease_weight[0]);
+
+ if (unlikely((border_index == edge_valence-2) || hasHardEdge0))
+ {
+ /* mirror quad center and edge mid-point */
+ c_i = madd(2.0f, e_i - c_i_m_1, c_i_m_1);
+ e_i_p_1 = madd(2.0f, vtx - e_i_m_1, e_i_m_1);
+ }
+ else
+ {
+ c_i = irreg_patch.ring[index].getQuadCenter( face_valence-1 );
+ e_i_p_1 = irreg_patch.ring[index].getEdgeCenter( face_valence-1 );
+ }
+
+ Vertex c_i_m_2, e_i_m_2;
+ const bool hasHardEdge1 =
+ std::isinf(irreg_patch.ring[index].vertex_crease_weight) &&
+ std::isinf(irreg_patch.ring[index].crease_weight[1]);
+
+ if (unlikely(border_index == 2 || hasHardEdge1))
+ {
+ /* mirror quad center and edge mid-point */
+ c_i_m_2 = madd(2.0f, e_i_m_1 - c_i_m_1, c_i_m_1);
+ e_i_m_2 = madd(2.0f, vtx - e_i, + e_i);
+ }
+ else
+ {
+ c_i_m_2 = irreg_patch.ring[index].getQuadCenter( 1 );
+ e_i_m_2 = irreg_patch.ring[index].getEdgeCenter( 2 );
+ }
+
+ const float d = 3.0f;
+ //const float c = cosf(2.0f*M_PI/(float)face_valence);
+ //const float c_e_p = cosf(2.0f*M_PI/(float)face_valence_p1);
+ //const float c_e_m = cosf(2.0f*M_PI/(float)face_valence_p3);
+
+ const float c = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence);
+ const float c_e_p = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence_p1);
+ const float c_e_m = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence_p3);
+
+ const Vertex r_e_p = 1.0f/3.0f * (e_i_m_1 - e_i_p_1) + 2.0f/3.0f * (c_i_m_1 - c_i);
+ const Vertex r_e_m = 1.0f/3.0f * (e_i - e_i_m_2) + 2.0f/3.0f * (c_i_m_1 - c_i_m_2);
+
+ f_p_vtx = 1.0f / d * (c_e_p * p_vtx + (d - 2.0f*c - c_e_p) * e0_p_vtx + 2.0f*c* e1_m_vtx + r_e_p);
+ f_m_vtx = 1.0f / d * (c_e_m * p_vtx + (d - 2.0f*c - c_e_m) * e0_m_vtx + 2.0f*c* e3_p_vtx + r_e_m);
+ }
+
+ __noinline void init(const CatmullClarkPatch& patch)
+ {
+ assert( patch.ring[0].hasValidPositions() );
+ assert( patch.ring[1].hasValidPositions() );
+ assert( patch.ring[2].hasValidPositions() );
+ assert( patch.ring[3].hasValidPositions() );
+
+ p0() = initCornerVertex(patch,0);
+ p1() = initCornerVertex(patch,1);
+ p2() = initCornerVertex(patch,2);
+ p3() = initCornerVertex(patch,3);
+
+ e0_p() = initPositiveEdgeVertex(patch,0, p0());
+ e1_p() = initPositiveEdgeVertex(patch,1, p1());
+ e2_p() = initPositiveEdgeVertex(patch,2, p2());
+ e3_p() = initPositiveEdgeVertex(patch,3, p3());
+
+ e0_m() = initNegativeEdgeVertex(patch,0, p0());
+ e1_m() = initNegativeEdgeVertex(patch,1, p1());
+ e2_m() = initNegativeEdgeVertex(patch,2, p2());
+ e3_m() = initNegativeEdgeVertex(patch,3, p3());
+
+ const unsigned int face_valence_p0 = patch.ring[0].face_valence;
+ const unsigned int face_valence_p1 = patch.ring[1].face_valence;
+ const unsigned int face_valence_p2 = patch.ring[2].face_valence;
+ const unsigned int face_valence_p3 = patch.ring[3].face_valence;
+
+ initFaceVertex(patch,0,p0(),e0_p(),e1_m(),face_valence_p1,e0_m(),e3_p(),face_valence_p3,f0_p(),f0_m() );
+ initFaceVertex(patch,1,p1(),e1_p(),e2_m(),face_valence_p2,e1_m(),e0_p(),face_valence_p0,f1_p(),f1_m() );
+ initFaceVertex(patch,2,p2(),e2_p(),e3_m(),face_valence_p3,e2_m(),e1_p(),face_valence_p1,f2_p(),f2_m() );
+ initFaceVertex(patch,3,p3(),e3_p(),e0_m(),face_valence_p0,e3_m(),e2_p(),face_valence_p3,f3_p(),f3_m() );
+
+ }
+
+ __noinline void init_crackfix(const CatmullClarkPatch& patch,
+ const BezierCurve* border0,
+ const BezierCurve* border1,
+ const BezierCurve* border2,
+ const BezierCurve* border3)
+ {
+ assert( patch.ring[0].hasValidPositions() );
+ assert( patch.ring[1].hasValidPositions() );
+ assert( patch.ring[2].hasValidPositions() );
+ assert( patch.ring[3].hasValidPositions() );
+
+ p0() = initCornerVertex(patch,0);
+ p1() = initCornerVertex(patch,1);
+ p2() = initCornerVertex(patch,2);
+ p3() = initCornerVertex(patch,3);
+
+ e0_p() = initPositiveEdgeVertex(patch,0, p0());
+ e1_p() = initPositiveEdgeVertex(patch,1, p1());
+ e2_p() = initPositiveEdgeVertex(patch,2, p2());
+ e3_p() = initPositiveEdgeVertex(patch,3, p3());
+
+ e0_m() = initNegativeEdgeVertex(patch,0, p0());
+ e1_m() = initNegativeEdgeVertex(patch,1, p1());
+ e2_m() = initNegativeEdgeVertex(patch,2, p2());
+ e3_m() = initNegativeEdgeVertex(patch,3, p3());
+
+ if (unlikely(border0 != nullptr))
+ {
+ p0() = border0->v0;
+ e0_p() = border0->v1;
+ e1_m() = border0->v2;
+ p1() = border0->v3;
+ }
+
+ if (unlikely(border1 != nullptr))
+ {
+ p1() = border1->v0;
+ e1_p() = border1->v1;
+ e2_m() = border1->v2;
+ p2() = border1->v3;
+ }
+
+ if (unlikely(border2 != nullptr))
+ {
+ p2() = border2->v0;
+ e2_p() = border2->v1;
+ e3_m() = border2->v2;
+ p3() = border2->v3;
+ }
+
+ if (unlikely(border3 != nullptr))
+ {
+ p3() = border3->v0;
+ e3_p() = border3->v1;
+ e0_m() = border3->v2;
+ p0() = border3->v3;
+ }
+
+ const unsigned int face_valence_p0 = patch.ring[0].face_valence;
+ const unsigned int face_valence_p1 = patch.ring[1].face_valence;
+ const unsigned int face_valence_p2 = patch.ring[2].face_valence;
+ const unsigned int face_valence_p3 = patch.ring[3].face_valence;
+
+ initFaceVertex(patch,0,p0(),e0_p(),e1_m(),face_valence_p1,e0_m(),e3_p(),face_valence_p3,f0_p(),f0_m() );
+ initFaceVertex(patch,1,p1(),e1_p(),e2_m(),face_valence_p2,e1_m(),e0_p(),face_valence_p0,f1_p(),f1_m() );
+ initFaceVertex(patch,2,p2(),e2_p(),e3_m(),face_valence_p3,e2_m(),e1_p(),face_valence_p1,f2_p(),f2_m() );
+ initFaceVertex(patch,3,p3(),e3_p(),e0_m(),face_valence_p0,e3_m(),e2_p(),face_valence_p3,f3_p(),f3_m() );
+ }
+
+
+ void computeGregoryPatchFacePoints(const unsigned int face_valence,
+ const Vertex& r_e_p,
+ const Vertex& r_e_m,
+ const Vertex& p_vtx,
+ const Vertex& e0_p_vtx,
+ const Vertex& e1_m_vtx,
+ const unsigned int face_valence_p1,
+ const Vertex& e0_m_vtx,
+ const Vertex& e3_p_vtx,
+ const unsigned int face_valence_p3,
+ Vertex& f_p_vtx,
+ Vertex& f_m_vtx,
+ const float d = 3.0f)
+ {
+ //const float c = cosf(2.0*M_PI/(float)face_valence);
+ //const float c_e_p = cosf(2.0*M_PI/(float)face_valence_p1);
+ //const float c_e_m = cosf(2.0*M_PI/(float)face_valence_p3);
+
+ const float c = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence);
+ const float c_e_p = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence_p1);
+ const float c_e_m = CatmullClarkPrecomputedCoefficients::table.cos_2PI_div_n(face_valence_p3);
+
+
+ f_p_vtx = 1.0f / d * (c_e_p * p_vtx + (d - 2.0f*c - c_e_p) * e0_p_vtx + 2.0f*c* e1_m_vtx + r_e_p);
+ f_m_vtx = 1.0f / d * (c_e_m * p_vtx + (d - 2.0f*c - c_e_m) * e0_m_vtx + 2.0f*c* e3_p_vtx + r_e_m);
+ f_p_vtx = 1.0f / d * (c_e_p * p_vtx + (d - 2.0f*c - c_e_p) * e0_p_vtx + 2.0f*c* e1_m_vtx + r_e_p);
+ f_m_vtx = 1.0f / d * (c_e_m * p_vtx + (d - 2.0f*c - c_e_m) * e0_m_vtx + 2.0f*c* e3_p_vtx + r_e_m);
+ }
+
+ __noinline void init(const GeneralCatmullClarkPatch& patch)
+ {
+ assert(patch.size() == 4);
+#if 0
+ CatmullClarkPatch qpatch; patch.init(qpatch);
+ init(qpatch);
+#else
+ const float face_valence_p0 = patch.ring[0].face_valence;
+ const float face_valence_p1 = patch.ring[1].face_valence;
+ const float face_valence_p2 = patch.ring[2].face_valence;
+ const float face_valence_p3 = patch.ring[3].face_valence;
+
+ Vertex p0_r_p, p0_r_m;
+ patch.ring[0].computeGregoryPatchEdgePoints( p0(), e0_p(), e0_m(), p0_r_p, p0_r_m );
+
+ Vertex p1_r_p, p1_r_m;
+ patch.ring[1].computeGregoryPatchEdgePoints( p1(), e1_p(), e1_m(), p1_r_p, p1_r_m );
+
+ Vertex p2_r_p, p2_r_m;
+ patch.ring[2].computeGregoryPatchEdgePoints( p2(), e2_p(), e2_m(), p2_r_p, p2_r_m );
+
+ Vertex p3_r_p, p3_r_m;
+ patch.ring[3].computeGregoryPatchEdgePoints( p3(), e3_p(), e3_m(), p3_r_p, p3_r_m );
+
+ computeGregoryPatchFacePoints(face_valence_p0, p0_r_p, p0_r_m, p0(), e0_p(), e1_m(), face_valence_p1, e0_m(), e3_p(), face_valence_p3, f0_p(), f0_m() );
+ computeGregoryPatchFacePoints(face_valence_p1, p1_r_p, p1_r_m, p1(), e1_p(), e2_m(), face_valence_p2, e1_m(), e0_p(), face_valence_p0, f1_p(), f1_m() );
+ computeGregoryPatchFacePoints(face_valence_p2, p2_r_p, p2_r_m, p2(), e2_p(), e3_m(), face_valence_p3, e2_m(), e1_p(), face_valence_p1, f2_p(), f2_m() );
+ computeGregoryPatchFacePoints(face_valence_p3, p3_r_p, p3_r_m, p3(), e3_p(), e0_m(), face_valence_p0, e3_m(), e2_p(), face_valence_p3, f3_p(), f3_m() );
+
+#endif
+ }
+
+
+ __forceinline void convert_to_bezier()
+ {
+ f0_p() = (f0_p() + f0_m()) * 0.5f;
+ f1_p() = (f1_p() + f1_m()) * 0.5f;
+ f2_p() = (f2_p() + f2_m()) * 0.5f;
+ f3_p() = (f3_p() + f3_m()) * 0.5f;
+ f0_m() = Vertex( zero );
+ f1_m() = Vertex( zero );
+ f2_m() = Vertex( zero );
+ f3_m() = Vertex( zero );
+ }
+
+ static __forceinline void computeInnerVertices(const Vertex matrix[4][4], const Vertex f_m[2][2], const float uu, const float vv,
+ Vertex_t& matrix_11, Vertex_t& matrix_12, Vertex_t& matrix_22, Vertex_t& matrix_21)
+ {
+ if (unlikely(uu == 0.0f || uu == 1.0f || vv == 0.0f || vv == 1.0f))
+ {
+ matrix_11 = matrix[1][1];
+ matrix_12 = matrix[1][2];
+ matrix_22 = matrix[2][2];
+ matrix_21 = matrix[2][1];
+ }
+ else
+ {
+ const Vertex_t f0_p = matrix[1][1];
+ const Vertex_t f1_p = matrix[1][2];
+ const Vertex_t f2_p = matrix[2][2];
+ const Vertex_t f3_p = matrix[2][1];
+
+ const Vertex_t f0_m = f_m[0][0];
+ const Vertex_t f1_m = f_m[0][1];
+ const Vertex_t f2_m = f_m[1][1];
+ const Vertex_t f3_m = f_m[1][0];
+
+ matrix_11 = ( uu * f0_p + vv * f0_m)*rcp(uu+vv);
+ matrix_12 = ((1.0f-uu) * f1_m + vv * f1_p)*rcp(1.0f-uu+vv);
+ matrix_22 = ((1.0f-uu) * f2_p + (1.0f-vv) * f2_m)*rcp(2.0f-uu-vv);
+ matrix_21 = ( uu * f3_m + (1.0f-vv) * f3_p)*rcp(1.0f+uu-vv);
+ }
+ }
+
+ template<typename vfloat>
+ static __forceinline void computeInnerVertices(const Vertex v[4][4], const Vertex f[2][2],
+ size_t i, const vfloat& uu, const vfloat& vv, vfloat& matrix_11, vfloat& matrix_12, vfloat& matrix_22, vfloat& matrix_21)
+ {
+ const auto m_border = (uu == 0.0f) | (uu == 1.0f) | (vv == 0.0f) | (vv == 1.0f);
+
+ const vfloat f0_p = v[1][1][i];
+ const vfloat f1_p = v[1][2][i];
+ const vfloat f2_p = v[2][2][i];
+ const vfloat f3_p = v[2][1][i];
+
+ const vfloat f0_m = f[0][0][i];
+ const vfloat f1_m = f[0][1][i];
+ const vfloat f2_m = f[1][1][i];
+ const vfloat f3_m = f[1][0][i];
+
+ const vfloat one_minus_uu = vfloat(1.0f) - uu;
+ const vfloat one_minus_vv = vfloat(1.0f) - vv;
+
+ const vfloat f0_i = ( uu * f0_p + vv * f0_m) * rcp(uu+vv);
+ const vfloat f1_i = (one_minus_uu * f1_m + vv * f1_p) * rcp(one_minus_uu+vv);
+ const vfloat f2_i = (one_minus_uu * f2_p + one_minus_vv * f2_m) * rcp(one_minus_uu+one_minus_vv);
+ const vfloat f3_i = ( uu * f3_m + one_minus_vv * f3_p) * rcp(uu+one_minus_vv);
+
+ matrix_11 = select(m_border,f0_p,f0_i);
+ matrix_12 = select(m_border,f1_p,f1_i);
+ matrix_22 = select(m_border,f2_p,f2_i);
+ matrix_21 = select(m_border,f3_p,f3_i);
+ }
+
+ static __forceinline Vertex eval(const Vertex matrix[4][4], const Vertex f[2][2], const float& uu, const float& vv)
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::eval(uu);
+ const Vec4<float> Bv = BezierBasis::eval(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ static __forceinline Vertex eval_du(const Vertex matrix[4][4], const Vertex f[2][2], const float uu, const float vv) // approximative derivative
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::derivative(uu);
+ const Vec4<float> Bv = BezierBasis::eval(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ static __forceinline Vertex eval_dv(const Vertex matrix[4][4], const Vertex f[2][2], const float uu, const float vv) // approximative derivative
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::eval(uu);
+ const Vec4<float> Bv = BezierBasis::derivative(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ static __forceinline Vertex eval_dudu(const Vertex matrix[4][4], const Vertex f[2][2], const float uu, const float vv) // approximative derivative
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::derivative2(uu);
+ const Vec4<float> Bv = BezierBasis::eval(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ static __forceinline Vertex eval_dvdv(const Vertex matrix[4][4], const Vertex f[2][2], const float uu, const float vv) // approximative derivative
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::eval(uu);
+ const Vec4<float> Bv = BezierBasis::derivative2(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ static __forceinline Vertex eval_dudv(const Vertex matrix[4][4], const Vertex f[2][2], const float uu, const float vv) // approximative derivative
+ {
+ Vertex_t v_11, v_12, v_22, v_21;
+ computeInnerVertices(matrix,f,uu,vv,v_11, v_12, v_22, v_21);
+
+ const Vec4<float> Bu = BezierBasis::derivative(uu);
+ const Vec4<float> Bv = BezierBasis::derivative(vv);
+
+ return madd(Bv.x,madd(Bu.x,matrix[0][0],madd(Bu.y,matrix[0][1],madd(Bu.z,matrix[0][2],Bu.w * matrix[0][3]))),
+ madd(Bv.y,madd(Bu.x,matrix[1][0],madd(Bu.y,v_11 ,madd(Bu.z,v_12 ,Bu.w * matrix[1][3]))),
+ madd(Bv.z,madd(Bu.x,matrix[2][0],madd(Bu.y,v_21 ,madd(Bu.z,v_22 ,Bu.w * matrix[2][3]))),
+ Bv.w*madd(Bu.x,matrix[3][0],madd(Bu.y,matrix[3][1],madd(Bu.z,matrix[3][2],Bu.w * matrix[3][3]))))));
+ }
+
+ __forceinline Vertex eval(const float uu, const float vv) const {
+ return eval(v,f,uu,vv);
+ }
+
+ __forceinline Vertex eval_du( const float uu, const float vv) const {
+ return eval_du(v,f,uu,vv);
+ }
+
+ __forceinline Vertex eval_dv( const float uu, const float vv) const {
+ return eval_dv(v,f,uu,vv);
+ }
+
+ __forceinline Vertex eval_dudu( const float uu, const float vv) const {
+ return eval_dudu(v,f,uu,vv);
+ }
+
+ __forceinline Vertex eval_dvdv( const float uu, const float vv) const {
+ return eval_dvdv(v,f,uu,vv);
+ }
+
+ __forceinline Vertex eval_dudv( const float uu, const float vv) const {
+ return eval_dudv(v,f,uu,vv);
+ }
+
+ static __forceinline Vertex normal(const Vertex matrix[4][4], const Vertex f_m[2][2], const float uu, const float vv) // FIXME: why not using basis functions
+ {
+ /* interpolate inner vertices */
+ Vertex_t matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(matrix,f_m,uu,vv,matrix_11, matrix_12, matrix_22, matrix_21);
+
+ /* tangentU */
+ const Vertex_t col0 = deCasteljau(vv, (Vertex_t)matrix[0][0], (Vertex_t)matrix[1][0], (Vertex_t)matrix[2][0], (Vertex_t)matrix[3][0]);
+ const Vertex_t col1 = deCasteljau(vv, (Vertex_t)matrix[0][1], (Vertex_t)matrix_11 , (Vertex_t)matrix_21 , (Vertex_t)matrix[3][1]);
+ const Vertex_t col2 = deCasteljau(vv, (Vertex_t)matrix[0][2], (Vertex_t)matrix_12 , (Vertex_t)matrix_22 , (Vertex_t)matrix[3][2]);
+ const Vertex_t col3 = deCasteljau(vv, (Vertex_t)matrix[0][3], (Vertex_t)matrix[1][3], (Vertex_t)matrix[2][3], (Vertex_t)matrix[3][3]);
+
+ const Vertex_t tangentU = deCasteljau_tangent(uu, col0, col1, col2, col3);
+
+ /* tangentV */
+ const Vertex_t row0 = deCasteljau(uu, (Vertex_t)matrix[0][0], (Vertex_t)matrix[0][1], (Vertex_t)matrix[0][2], (Vertex_t)matrix[0][3]);
+ const Vertex_t row1 = deCasteljau(uu, (Vertex_t)matrix[1][0], (Vertex_t)matrix_11 , (Vertex_t)matrix_12 , (Vertex_t)matrix[1][3]);
+ const Vertex_t row2 = deCasteljau(uu, (Vertex_t)matrix[2][0], (Vertex_t)matrix_21 , (Vertex_t)matrix_22 , (Vertex_t)matrix[2][3]);
+ const Vertex_t row3 = deCasteljau(uu, (Vertex_t)matrix[3][0], (Vertex_t)matrix[3][1], (Vertex_t)matrix[3][2], (Vertex_t)matrix[3][3]);
+
+ const Vertex_t tangentV = deCasteljau_tangent(vv, row0, row1, row2, row3);
+
+ /* normal = tangentU x tangentV */
+ const Vertex_t n = cross(tangentU,tangentV);
+
+ return n;
+ }
+
+ __forceinline Vertex normal( const float uu, const float vv) const {
+ return normal(v,f,uu,vv);
+ }
+
+ __forceinline void eval(const float u, const float v,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv,
+ Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv,
+ const float dscale = 1.0f) const
+ {
+ if (P) {
+ *P = eval(u,v);
+ }
+ if (dPdu) {
+ assert(dPdu); *dPdu = eval_du(u,v)*dscale;
+ assert(dPdv); *dPdv = eval_dv(u,v)*dscale;
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(dscale);
+ assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(dscale);
+ assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(dscale);
+ }
+ }
+
+ template<class vfloat>
+ static __forceinline vfloat eval(const Vertex v[4][4], const Vertex f[2][2],
+ const size_t i, const vfloat& uu, const vfloat& vv, const Vec4<vfloat>& u_n, const Vec4<vfloat>& v_n,
+ vfloat& matrix_11, vfloat& matrix_12, vfloat& matrix_22, vfloat& matrix_21)
+ {
+ const vfloat curve0_x = madd(v_n[0],vfloat(v[0][0][i]),madd(v_n[1],vfloat(v[1][0][i]),madd(v_n[2],vfloat(v[2][0][i]),v_n[3] * vfloat(v[3][0][i]))));
+ const vfloat curve1_x = madd(v_n[0],vfloat(v[0][1][i]),madd(v_n[1],vfloat(matrix_11 ),madd(v_n[2],vfloat(matrix_21 ),v_n[3] * vfloat(v[3][1][i]))));
+ const vfloat curve2_x = madd(v_n[0],vfloat(v[0][2][i]),madd(v_n[1],vfloat(matrix_12 ),madd(v_n[2],vfloat(matrix_22 ),v_n[3] * vfloat(v[3][2][i]))));
+ const vfloat curve3_x = madd(v_n[0],vfloat(v[0][3][i]),madd(v_n[1],vfloat(v[1][3][i]),madd(v_n[2],vfloat(v[2][3][i]),v_n[3] * vfloat(v[3][3][i]))));
+ return madd(u_n[0],curve0_x,madd(u_n[1],curve1_x,madd(u_n[2],curve2_x,u_n[3] * curve3_x)));
+ }
+
+ template<typename vbool, typename vfloat>
+ static __forceinline void eval(const Vertex v[4][4], const Vertex f[2][2],
+ const vbool& valid, const vfloat& uu, const vfloat& vv,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
+ const float dscale, const size_t dstride, const size_t N)
+ {
+ if (P) {
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,P+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21));
+ }
+ }
+ if (dPdu)
+ {
+ {
+ assert(dPdu);
+ const Vec4<vfloat> u_n = BezierBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,dPdu+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21)*dscale);
+ }
+ }
+ {
+ assert(dPdv);
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,dPdv+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21)*dscale);
+ }
+ }
+ }
+ if (ddPdudu)
+ {
+ {
+ assert(ddPdudu);
+ const Vec4<vfloat> u_n = BezierBasis::derivative2(uu);
+ const Vec4<vfloat> v_n = BezierBasis::eval(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,ddPdudu+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21)*sqr(dscale));
+ }
+ }
+ {
+ assert(ddPdvdv);
+ const Vec4<vfloat> u_n = BezierBasis::eval(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative2(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,ddPdvdv+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21)*sqr(dscale));
+ }
+ }
+ {
+ assert(ddPdudv);
+ const Vec4<vfloat> u_n = BezierBasis::derivative(uu);
+ const Vec4<vfloat> v_n = BezierBasis::derivative(vv);
+ for (size_t i=0; i<N; i++) {
+ vfloat matrix_11, matrix_12, matrix_22, matrix_21;
+ computeInnerVertices(v,f,i,uu,vv,matrix_11,matrix_12,matrix_22,matrix_21); // FIXME: calculated multiple times
+ vfloat::store(valid,ddPdudv+i*dstride,eval(v,f,i,uu,vv,u_n,v_n,matrix_11,matrix_12,matrix_22,matrix_21)*sqr(dscale));
+ }
+ }
+ }
+ }
+
+ template<typename vbool, typename vfloat>
+ __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
+ const float dscale, const size_t dstride, const size_t N) const {
+ eval(v,f,valid,uu,vv,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ }
+
+ template<class T>
+ static __forceinline Vec3<T> eval_t(const Vertex matrix[4][4], const Vec3<T> f[2][2], const T& uu, const T& vv)
+ {
+ typedef typename T::Bool M;
+ const M m_border = (uu == 0.0f) | (uu == 1.0f) | (vv == 0.0f) | (vv == 1.0f);
+
+ const Vec3<T> f0_p = Vec3<T>(matrix[1][1].x,matrix[1][1].y,matrix[1][1].z);
+ const Vec3<T> f1_p = Vec3<T>(matrix[1][2].x,matrix[1][2].y,matrix[1][2].z);
+ const Vec3<T> f2_p = Vec3<T>(matrix[2][2].x,matrix[2][2].y,matrix[2][2].z);
+ const Vec3<T> f3_p = Vec3<T>(matrix[2][1].x,matrix[2][1].y,matrix[2][1].z);
+
+ const Vec3<T> f0_m = f[0][0];
+ const Vec3<T> f1_m = f[0][1];
+ const Vec3<T> f2_m = f[1][1];
+ const Vec3<T> f3_m = f[1][0];
+
+ const T one_minus_uu = T(1.0f) - uu;
+ const T one_minus_vv = T(1.0f) - vv;
+
+ const Vec3<T> f0_i = ( uu * f0_p + vv * f0_m) * rcp(uu+vv);
+ const Vec3<T> f1_i = (one_minus_uu * f1_m + vv * f1_p) * rcp(one_minus_uu+vv);
+ const Vec3<T> f2_i = (one_minus_uu * f2_p + one_minus_vv * f2_m) * rcp(one_minus_uu+one_minus_vv);
+ const Vec3<T> f3_i = ( uu * f3_m + one_minus_vv * f3_p) * rcp(uu+one_minus_vv);
+
+ const Vec3<T> F0( select(m_border,f0_p.x,f0_i.x), select(m_border,f0_p.y,f0_i.y), select(m_border,f0_p.z,f0_i.z) );
+ const Vec3<T> F1( select(m_border,f1_p.x,f1_i.x), select(m_border,f1_p.y,f1_i.y), select(m_border,f1_p.z,f1_i.z) );
+ const Vec3<T> F2( select(m_border,f2_p.x,f2_i.x), select(m_border,f2_p.y,f2_i.y), select(m_border,f2_p.z,f2_i.z) );
+ const Vec3<T> F3( select(m_border,f3_p.x,f3_i.x), select(m_border,f3_p.y,f3_i.y), select(m_border,f3_p.z,f3_i.z) );
+
+ const T B0_u = one_minus_uu * one_minus_uu * one_minus_uu;
+ const T B0_v = one_minus_vv * one_minus_vv * one_minus_vv;
+ const T B1_u = 3.0f * (one_minus_uu * uu * one_minus_uu);
+ const T B1_v = 3.0f * (one_minus_vv * vv * one_minus_vv);
+ const T B2_u = 3.0f * (uu * one_minus_uu * uu);
+ const T B2_v = 3.0f * (vv * one_minus_vv * vv);
+ const T B3_u = uu * uu * uu;
+ const T B3_v = vv * vv * vv;
+
+ const T x = madd(B0_v,madd(B0_u,matrix[0][0].x,madd(B1_u,matrix[0][1].x,madd(B2_u,matrix[0][2].x,B3_u * matrix[0][3].x))),
+ madd(B1_v,madd(B0_u,matrix[1][0].x,madd(B1_u,F0.x ,madd(B2_u,F1.x ,B3_u * matrix[1][3].x))),
+ madd(B2_v,madd(B0_u,matrix[2][0].x,madd(B1_u,F3.x ,madd(B2_u,F2.x ,B3_u * matrix[2][3].x))),
+ B3_v*madd(B0_u,matrix[3][0].x,madd(B1_u,matrix[3][1].x,madd(B2_u,matrix[3][2].x,B3_u * matrix[3][3].x))))));
+
+ const T y = madd(B0_v,madd(B0_u,matrix[0][0].y,madd(B1_u,matrix[0][1].y,madd(B2_u,matrix[0][2].y,B3_u * matrix[0][3].y))),
+ madd(B1_v,madd(B0_u,matrix[1][0].y,madd(B1_u,F0.y ,madd(B2_u,F1.y ,B3_u * matrix[1][3].y))),
+ madd(B2_v,madd(B0_u,matrix[2][0].y,madd(B1_u,F3.y ,madd(B2_u,F2.y ,B3_u * matrix[2][3].y))),
+ B3_v*madd(B0_u,matrix[3][0].y,madd(B1_u,matrix[3][1].y,madd(B2_u,matrix[3][2].y,B3_u * matrix[3][3].y))))));
+
+ const T z = madd(B0_v,madd(B0_u,matrix[0][0].z,madd(B1_u,matrix[0][1].z,madd(B2_u,matrix[0][2].z,B3_u * matrix[0][3].z))),
+ madd(B1_v,madd(B0_u,matrix[1][0].z,madd(B1_u,F0.z ,madd(B2_u,F1.z ,B3_u * matrix[1][3].z))),
+ madd(B2_v,madd(B0_u,matrix[2][0].z,madd(B1_u,F3.z ,madd(B2_u,F2.z ,B3_u * matrix[2][3].z))),
+ B3_v*madd(B0_u,matrix[3][0].z,madd(B1_u,matrix[3][1].z,madd(B2_u,matrix[3][2].z,B3_u * matrix[3][3].z))))));
+
+ return Vec3<T>(x,y,z);
+ }
+
+ template<class T>
+ __forceinline Vec3<T> eval(const T& uu, const T& vv) const
+ {
+ Vec3<T> ff[2][2];
+ ff[0][0] = Vec3<T>(f[0][0]);
+ ff[0][1] = Vec3<T>(f[0][1]);
+ ff[1][1] = Vec3<T>(f[1][1]);
+ ff[1][0] = Vec3<T>(f[1][0]);
+ return eval_t(v,ff,uu,vv);
+ }
+
+ template<class T>
+ static __forceinline Vec3<T> normal_t(const Vertex matrix[4][4], const Vec3<T> f[2][2], const T& uu, const T& vv)
+ {
+ typedef typename T::Bool M;
+
+ const Vec3<T> f0_p = Vec3<T>(matrix[1][1].x,matrix[1][1].y,matrix[1][1].z);
+ const Vec3<T> f1_p = Vec3<T>(matrix[1][2].x,matrix[1][2].y,matrix[1][2].z);
+ const Vec3<T> f2_p = Vec3<T>(matrix[2][2].x,matrix[2][2].y,matrix[2][2].z);
+ const Vec3<T> f3_p = Vec3<T>(matrix[2][1].x,matrix[2][1].y,matrix[2][1].z);
+
+ const Vec3<T> f0_m = f[0][0];
+ const Vec3<T> f1_m = f[0][1];
+ const Vec3<T> f2_m = f[1][1];
+ const Vec3<T> f3_m = f[1][0];
+
+ const T one_minus_uu = T(1.0f) - uu;
+ const T one_minus_vv = T(1.0f) - vv;
+
+ const Vec3<T> f0_i = ( uu * f0_p + vv * f0_m) * rcp(uu+vv);
+ const Vec3<T> f1_i = (one_minus_uu * f1_m + vv * f1_p) * rcp(one_minus_uu+vv);
+ const Vec3<T> f2_i = (one_minus_uu * f2_p + one_minus_vv * f2_m) * rcp(one_minus_uu+one_minus_vv);
+ const Vec3<T> f3_i = ( uu * f3_m + one_minus_vv * f3_p) * rcp(uu+one_minus_vv);
+
+#if 1
+ const M m_corner0 = (uu == 0.0f) & (vv == 0.0f);
+ const M m_corner1 = (uu == 1.0f) & (vv == 0.0f);
+ const M m_corner2 = (uu == 1.0f) & (vv == 1.0f);
+ const M m_corner3 = (uu == 0.0f) & (vv == 1.0f);
+ const Vec3<T> matrix_11( select(m_corner0,f0_p.x,f0_i.x), select(m_corner0,f0_p.y,f0_i.y), select(m_corner0,f0_p.z,f0_i.z) );
+ const Vec3<T> matrix_12( select(m_corner1,f1_p.x,f1_i.x), select(m_corner1,f1_p.y,f1_i.y), select(m_corner1,f1_p.z,f1_i.z) );
+ const Vec3<T> matrix_22( select(m_corner2,f2_p.x,f2_i.x), select(m_corner2,f2_p.y,f2_i.y), select(m_corner2,f2_p.z,f2_i.z) );
+ const Vec3<T> matrix_21( select(m_corner3,f3_p.x,f3_i.x), select(m_corner3,f3_p.y,f3_i.y), select(m_corner3,f3_p.z,f3_i.z) );
+#else
+ const M m_border = (uu == 0.0f) | (uu == 1.0f) | (vv == 0.0f) | (vv == 1.0f);
+ const Vec3<T> matrix_11( select(m_border,f0_p.x,f0_i.x), select(m_border,f0_p.y,f0_i.y), select(m_border,f0_p.z,f0_i.z) );
+ const Vec3<T> matrix_12( select(m_border,f1_p.x,f1_i.x), select(m_border,f1_p.y,f1_i.y), select(m_border,f1_p.z,f1_i.z) );
+ const Vec3<T> matrix_22( select(m_border,f2_p.x,f2_i.x), select(m_border,f2_p.y,f2_i.y), select(m_border,f2_p.z,f2_i.z) );
+ const Vec3<T> matrix_21( select(m_border,f3_p.x,f3_i.x), select(m_border,f3_p.y,f3_i.y), select(m_border,f3_p.z,f3_i.z) );
+#endif
+
+ const Vec3<T> matrix_00 = Vec3<T>(matrix[0][0].x,matrix[0][0].y,matrix[0][0].z);
+ const Vec3<T> matrix_10 = Vec3<T>(matrix[1][0].x,matrix[1][0].y,matrix[1][0].z);
+ const Vec3<T> matrix_20 = Vec3<T>(matrix[2][0].x,matrix[2][0].y,matrix[2][0].z);
+ const Vec3<T> matrix_30 = Vec3<T>(matrix[3][0].x,matrix[3][0].y,matrix[3][0].z);
+
+ const Vec3<T> matrix_01 = Vec3<T>(matrix[0][1].x,matrix[0][1].y,matrix[0][1].z);
+ const Vec3<T> matrix_02 = Vec3<T>(matrix[0][2].x,matrix[0][2].y,matrix[0][2].z);
+ const Vec3<T> matrix_03 = Vec3<T>(matrix[0][3].x,matrix[0][3].y,matrix[0][3].z);
+
+ const Vec3<T> matrix_31 = Vec3<T>(matrix[3][1].x,matrix[3][1].y,matrix[3][1].z);
+ const Vec3<T> matrix_32 = Vec3<T>(matrix[3][2].x,matrix[3][2].y,matrix[3][2].z);
+ const Vec3<T> matrix_33 = Vec3<T>(matrix[3][3].x,matrix[3][3].y,matrix[3][3].z);
+
+ const Vec3<T> matrix_13 = Vec3<T>(matrix[1][3].x,matrix[1][3].y,matrix[1][3].z);
+ const Vec3<T> matrix_23 = Vec3<T>(matrix[2][3].x,matrix[2][3].y,matrix[2][3].z);
+
+ /* tangentU */
+ const Vec3<T> col0 = deCasteljau(vv, matrix_00, matrix_10, matrix_20, matrix_30);
+ const Vec3<T> col1 = deCasteljau(vv, matrix_01, matrix_11, matrix_21, matrix_31);
+ const Vec3<T> col2 = deCasteljau(vv, matrix_02, matrix_12, matrix_22, matrix_32);
+ const Vec3<T> col3 = deCasteljau(vv, matrix_03, matrix_13, matrix_23, matrix_33);
+
+ const Vec3<T> tangentU = deCasteljau_tangent(uu, col0, col1, col2, col3);
+
+ /* tangentV */
+ const Vec3<T> row0 = deCasteljau(uu, matrix_00, matrix_01, matrix_02, matrix_03);
+ const Vec3<T> row1 = deCasteljau(uu, matrix_10, matrix_11, matrix_12, matrix_13);
+ const Vec3<T> row2 = deCasteljau(uu, matrix_20, matrix_21, matrix_22, matrix_23);
+ const Vec3<T> row3 = deCasteljau(uu, matrix_30, matrix_31, matrix_32, matrix_33);
+
+ const Vec3<T> tangentV = deCasteljau_tangent(vv, row0, row1, row2, row3);
+
+ /* normal = tangentU x tangentV */
+ const Vec3<T> n = cross(tangentU,tangentV);
+ return n;
+ }
+
+ template<class T>
+ __forceinline Vec3<T> normal(const T& uu, const T& vv) const
+ {
+ Vec3<T> ff[2][2];
+ ff[0][0] = Vec3<T>(f[0][0]);
+ ff[0][1] = Vec3<T>(f[0][1]);
+ ff[1][1] = Vec3<T>(f[1][1]);
+ ff[1][0] = Vec3<T>(f[1][0]);
+ return normal_t(v,ff,uu,vv);
+ }
+
+ __forceinline BBox<Vertex> bounds() const
+ {
+ const Vertex *const cv = &v[0][0];
+ BBox<Vertex> bounds (cv[0]);
+ for (size_t i=1; i<16; i++)
+ bounds.extend( cv[i] );
+ bounds.extend(f[0][0]);
+ bounds.extend(f[1][0]);
+ bounds.extend(f[1][1]);
+ bounds.extend(f[1][1]);
+ return bounds;
+ }
+
+ friend embree_ostream operator<<(embree_ostream o, const GregoryPatchT& p)
+ {
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ o << "v[" << y << "][" << x << "] " << p.v[y][x] << embree_endl;
+
+ for (size_t y=0; y<2; y++)
+ for (size_t x=0; x<2; x++)
+ o << "f[" << y << "][" << x << "] " << p.f[y][x] << embree_endl;
+ return o;
+ }
+ };
+
+ typedef GregoryPatchT<Vec3fa,Vec3fa_t> GregoryPatch3fa;
+
+ template<typename Vertex, typename Vertex_t>
+ __forceinline BezierPatchT<Vertex,Vertex_t>::BezierPatchT (const HalfEdge* edge, const char* vertices, size_t stride)
+ {
+ CatmullClarkPatchT<Vertex,Vertex_t> patch(edge,vertices,stride);
+ GregoryPatchT<Vertex,Vertex_t> gpatch(patch);
+ gpatch.convert_to_bezier();
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ matrix[y][x] = (Vertex_t)gpatch.v[y][x];
+ }
+
+ template<typename Vertex, typename Vertex_t>
+ __forceinline BezierPatchT<Vertex,Vertex_t>::BezierPatchT(const CatmullClarkPatchT<Vertex,Vertex_t>& patch)
+ {
+ GregoryPatchT<Vertex,Vertex_t> gpatch(patch);
+ gpatch.convert_to_bezier();
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ matrix[y][x] = (Vertex_t)gpatch.v[y][x];
+ }
+
+ template<typename Vertex, typename Vertex_t>
+ __forceinline BezierPatchT<Vertex,Vertex_t>::BezierPatchT(const CatmullClarkPatchT<Vertex,Vertex_t>& patch,
+ const BezierCurveT<Vertex>* border0,
+ const BezierCurveT<Vertex>* border1,
+ const BezierCurveT<Vertex>* border2,
+ const BezierCurveT<Vertex>* border3)
+ {
+ GregoryPatchT<Vertex,Vertex_t> gpatch(patch,border0,border1,border2,border3);
+ gpatch.convert_to_bezier();
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ matrix[y][x] = (Vertex_t)gpatch.v[y][x];
+ }
+}
diff --git a/thirdparty/embree/kernels/subdiv/gregory_patch_dense.h b/thirdparty/embree/kernels/subdiv/gregory_patch_dense.h
new file mode 100644
index 0000000000..4cf9a7e98f
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/gregory_patch_dense.h
@@ -0,0 +1,113 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "gregory_patch.h"
+
+namespace embree
+{
+ class __aligned(64) DenseGregoryPatch3fa
+ {
+ typedef Vec3fa Vec3fa_4x4[4][4];
+ public:
+
+ __forceinline DenseGregoryPatch3fa (const GregoryPatch3fa& patch)
+ {
+ for (size_t y=0; y<4; y++)
+ for (size_t x=0; x<4; x++)
+ matrix[y][x] = Vec3ff(patch.v[y][x], 0.0f);
+
+ matrix[0][0].w = patch.f[0][0].x;
+ matrix[0][1].w = patch.f[0][0].y;
+ matrix[0][2].w = patch.f[0][0].z;
+ matrix[0][3].w = 0.0f;
+
+ matrix[1][0].w = patch.f[0][1].x;
+ matrix[1][1].w = patch.f[0][1].y;
+ matrix[1][2].w = patch.f[0][1].z;
+ matrix[1][3].w = 0.0f;
+
+ matrix[2][0].w = patch.f[1][1].x;
+ matrix[2][1].w = patch.f[1][1].y;
+ matrix[2][2].w = patch.f[1][1].z;
+ matrix[2][3].w = 0.0f;
+
+ matrix[3][0].w = patch.f[1][0].x;
+ matrix[3][1].w = patch.f[1][0].y;
+ matrix[3][2].w = patch.f[1][0].z;
+ matrix[3][3].w = 0.0f;
+ }
+
+ __forceinline void extract_f_m(Vec3fa f_m[2][2]) const
+ {
+ f_m[0][0] = Vec3fa( matrix[0][0].w, matrix[0][1].w, matrix[0][2].w );
+ f_m[0][1] = Vec3fa( matrix[1][0].w, matrix[1][1].w, matrix[1][2].w );
+ f_m[1][1] = Vec3fa( matrix[2][0].w, matrix[2][1].w, matrix[2][2].w );
+ f_m[1][0] = Vec3fa( matrix[3][0].w, matrix[3][1].w, matrix[3][2].w );
+ }
+
+ __forceinline Vec3fa eval(const float uu, const float vv) const
+ {
+ __aligned(64) Vec3fa f_m[2][2]; extract_f_m(f_m);
+ return GregoryPatch3fa::eval(*(Vec3fa_4x4*)&matrix,f_m,uu,vv);
+ }
+
+ __forceinline Vec3fa normal(const float uu, const float vv) const
+ {
+ __aligned(64) Vec3fa f_m[2][2]; extract_f_m(f_m);
+ return GregoryPatch3fa::normal(*(Vec3fa_4x4*)&matrix,f_m,uu,vv);
+ }
+
+ template<class T>
+ __forceinline Vec3<T> eval(const T &uu, const T &vv) const
+ {
+ Vec3<T> f_m[2][2];
+ f_m[0][0] = Vec3<T>( matrix[0][0].w, matrix[0][1].w, matrix[0][2].w );
+ f_m[0][1] = Vec3<T>( matrix[1][0].w, matrix[1][1].w, matrix[1][2].w );
+ f_m[1][1] = Vec3<T>( matrix[2][0].w, matrix[2][1].w, matrix[2][2].w );
+ f_m[1][0] = Vec3<T>( matrix[3][0].w, matrix[3][1].w, matrix[3][2].w );
+ return GregoryPatch3fa::eval_t(*(Vec3fa_4x4*)&matrix,f_m,uu,vv);
+ }
+
+ template<class T>
+ __forceinline Vec3<T> normal(const T &uu, const T &vv) const
+ {
+ Vec3<T> f_m[2][2];
+ f_m[0][0] = Vec3<T>( matrix[0][0].w, matrix[0][1].w, matrix[0][2].w );
+ f_m[0][1] = Vec3<T>( matrix[1][0].w, matrix[1][1].w, matrix[1][2].w );
+ f_m[1][1] = Vec3<T>( matrix[2][0].w, matrix[2][1].w, matrix[2][2].w );
+ f_m[1][0] = Vec3<T>( matrix[3][0].w, matrix[3][1].w, matrix[3][2].w );
+ return GregoryPatch3fa::normal_t(*(Vec3fa_4x4*)&matrix,f_m,uu,vv);
+ }
+
+ __forceinline void eval(const float u, const float v,
+ Vec3fa* P, Vec3fa* dPdu, Vec3fa* dPdv, Vec3fa* ddPdudu, Vec3fa* ddPdvdv, Vec3fa* ddPdudv,
+ const float dscale = 1.0f) const
+ {
+ __aligned(64) Vec3fa f_m[2][2]; extract_f_m(f_m);
+ if (P) {
+ *P = GregoryPatch3fa::eval(*(Vec3fa_4x4*)&matrix,f_m,u,v);
+ }
+ if (dPdu) {
+ assert(dPdu); *dPdu = GregoryPatch3fa::eval_du(*(Vec3fa_4x4*)&matrix,f_m,u,v)*dscale;
+ assert(dPdv); *dPdv = GregoryPatch3fa::eval_dv(*(Vec3fa_4x4*)&matrix,f_m,u,v)*dscale;
+ }
+ if (ddPdudu) {
+ assert(ddPdudu); *ddPdudu = GregoryPatch3fa::eval_dudu(*(Vec3fa_4x4*)&matrix,f_m,u,v)*sqr(dscale);
+ assert(ddPdvdv); *ddPdvdv = GregoryPatch3fa::eval_dvdv(*(Vec3fa_4x4*)&matrix,f_m,u,v)*sqr(dscale);
+ assert(ddPdudv); *ddPdudv = GregoryPatch3fa::eval_dudv(*(Vec3fa_4x4*)&matrix,f_m,u,v)*sqr(dscale);
+ }
+ }
+
+ template<typename vbool, typename vfloat>
+ __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv, float* P, float* dPdu, float* dPdv, const float dscale, const size_t dstride, const size_t N) const
+ {
+ __aligned(64) Vec3fa f_m[2][2]; extract_f_m(f_m);
+ GregoryPatch3fa::eval(matrix,f_m,valid,uu,vv,P,dPdu,dPdv,dscale,dstride,N);
+ }
+
+ private:
+ Vec3ff matrix[4][4]; // f_p/m points are stored in 4th component
+ };
+}
diff --git a/thirdparty/embree/kernels/subdiv/gridrange.h b/thirdparty/embree/kernels/subdiv/gridrange.h
new file mode 100644
index 0000000000..4f2b90d7bd
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/gridrange.h
@@ -0,0 +1,96 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+
+namespace embree
+{
+ struct __aligned(16) GridRange
+ {
+ unsigned int u_start;
+ unsigned int u_end;
+ unsigned int v_start;
+ unsigned int v_end;
+
+ __forceinline GridRange() {}
+
+ __forceinline GridRange(unsigned int u_start, unsigned int u_end, unsigned int v_start, unsigned int v_end)
+ : u_start(u_start), u_end(u_end), v_start(v_start), v_end(v_end) {}
+
+ __forceinline unsigned int width() const {
+ return u_end-u_start+1;
+ }
+
+ __forceinline unsigned int height() const {
+ return v_end-v_start+1;
+ }
+
+ __forceinline bool hasLeafSize() const
+ {
+ const unsigned int u_size = u_end-u_start+1;
+ const unsigned int v_size = v_end-v_start+1;
+ assert(u_size >= 1);
+ assert(v_size >= 1);
+ return u_size <= 3 && v_size <= 3;
+ }
+
+ static __forceinline unsigned int split(unsigned int start,unsigned int end)
+ {
+ const unsigned int center = (start+end)/2;
+ assert (center > start);
+ assert (center < end);
+ return center;
+ }
+
+ __forceinline void split(GridRange& r0, GridRange& r1) const
+ {
+ assert( hasLeafSize() == false );
+ const unsigned int u_size = u_end-u_start+1;
+ const unsigned int v_size = v_end-v_start+1;
+ r0 = *this;
+ r1 = *this;
+
+ if (u_size >= v_size)
+ {
+ const unsigned int u_mid = split(u_start,u_end);
+ r0.u_end = u_mid;
+ r1.u_start = u_mid;
+ }
+ else
+ {
+ const unsigned int v_mid = split(v_start,v_end);
+ r0.v_end = v_mid;
+ r1.v_start = v_mid;
+ }
+ }
+
+ __forceinline unsigned int splitIntoSubRanges(GridRange r[4]) const
+ {
+ assert( !hasLeafSize() );
+ unsigned int children = 0;
+ GridRange first,second;
+ split(first,second);
+
+ if (first.hasLeafSize()) {
+ r[0] = first;
+ children++;
+ }
+ else {
+ first.split(r[0],r[1]);
+ children += 2;
+ }
+
+ if (second.hasLeafSize()) {
+ r[children] = second;
+ children++;
+ }
+ else {
+ second.split(r[children+0],r[children+1]);
+ children += 2;
+ }
+ return children;
+ }
+ };
+}
diff --git a/thirdparty/embree/kernels/subdiv/half_edge.h b/thirdparty/embree/kernels/subdiv/half_edge.h
new file mode 100644
index 0000000000..baf019cd79
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/half_edge.h
@@ -0,0 +1,371 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_coefficients.h"
+
+namespace embree
+{
+ class __aligned(32) HalfEdge
+ {
+ friend class SubdivMesh;
+ public:
+
+ enum PatchType : char {
+ BILINEAR_PATCH = 0, //!< a bilinear patch
+ REGULAR_QUAD_PATCH = 1, //!< a regular quad patch can be represented as a B-Spline
+ IRREGULAR_QUAD_PATCH = 2, //!< an irregular quad patch can be represented as a Gregory patch
+ COMPLEX_PATCH = 3 //!< these patches need subdivision and cannot be processed by the above fast code paths
+ };
+
+ enum VertexType : char {
+ REGULAR_VERTEX = 0, //!< regular vertex
+ NON_MANIFOLD_EDGE_VERTEX = 1, //!< vertex of a non-manifold edge
+ };
+
+ __forceinline friend PatchType max( const PatchType& ty0, const PatchType& ty1) {
+ return (PatchType) max((int)ty0,(int)ty1);
+ }
+
+ struct Edge
+ {
+ /*! edge constructor */
+ __forceinline Edge(const uint32_t v0, const uint32_t v1)
+ : v0(v0), v1(v1) {}
+
+ /*! create an 64 bit identifier that is unique for the not oriented edge */
+ __forceinline operator uint64_t() const
+ {
+ uint32_t p0 = v0, p1 = v1;
+ if (p0<p1) std::swap(p0,p1);
+ return (((uint64_t)p0) << 32) | (uint64_t)p1;
+ }
+
+ public:
+ uint32_t v0,v1; //!< start and end vertex of the edge
+ };
+
+ HalfEdge ()
+ : vtx_index(-1), next_half_edge_ofs(0), prev_half_edge_ofs(0), opposite_half_edge_ofs(0), edge_crease_weight(0),
+ vertex_crease_weight(0), edge_level(0), patch_type(COMPLEX_PATCH), vertex_type(REGULAR_VERTEX)
+ {
+ static_assert(sizeof(HalfEdge) == 32, "invalid half edge size");
+ }
+
+ __forceinline bool hasOpposite() const { return opposite_half_edge_ofs != 0; }
+ __forceinline void setOpposite(HalfEdge* opposite) { opposite_half_edge_ofs = int(opposite-this); }
+
+ __forceinline HalfEdge* next() { assert( next_half_edge_ofs != 0 ); return &this[next_half_edge_ofs]; }
+ __forceinline const HalfEdge* next() const { assert( next_half_edge_ofs != 0 ); return &this[next_half_edge_ofs]; }
+
+ __forceinline HalfEdge* prev() { assert( prev_half_edge_ofs != 0 ); return &this[prev_half_edge_ofs]; }
+ __forceinline const HalfEdge* prev() const { assert( prev_half_edge_ofs != 0 ); return &this[prev_half_edge_ofs]; }
+
+ __forceinline HalfEdge* opposite() { assert( opposite_half_edge_ofs != 0 ); return &this[opposite_half_edge_ofs]; }
+ __forceinline const HalfEdge* opposite() const { assert( opposite_half_edge_ofs != 0 ); return &this[opposite_half_edge_ofs]; }
+
+ __forceinline HalfEdge* rotate() { return opposite()->next(); }
+ __forceinline const HalfEdge* rotate() const { return opposite()->next(); }
+
+ __forceinline unsigned int getStartVertexIndex() const { return vtx_index; }
+ __forceinline unsigned int getEndVertexIndex () const { return next()->vtx_index; }
+ __forceinline Edge getEdge () const { return Edge(getStartVertexIndex(),getEndVertexIndex()); }
+
+
+ /*! tests if the start vertex of the edge is regular */
+ __forceinline PatchType vertexType() const
+ {
+ const HalfEdge* p = this;
+ size_t face_valence = 0;
+ bool hasBorder = false;
+
+ do
+ {
+ /* we need subdivision to handle edge creases */
+ if (p->hasOpposite() && p->edge_crease_weight > 0.0f)
+ return COMPLEX_PATCH;
+
+ face_valence++;
+
+ /* test for quad */
+ const HalfEdge* pp = p;
+ pp = pp->next(); if (pp == p) return COMPLEX_PATCH;
+ pp = pp->next(); if (pp == p) return COMPLEX_PATCH;
+ pp = pp->next(); if (pp == p) return COMPLEX_PATCH;
+ pp = pp->next(); if (pp != p) return COMPLEX_PATCH;
+
+ /* continue with next face */
+ p = p->prev();
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else
+ {
+ face_valence++;
+ hasBorder = true;
+ p = this;
+ while (p->hasOpposite())
+ p = p->rotate();
+ }
+ } while (p != this);
+
+ /* calculate vertex type */
+ if (face_valence == 2 && hasBorder) {
+ if (vertex_crease_weight == 0.0f ) return REGULAR_QUAD_PATCH;
+ else if (vertex_crease_weight == float(inf)) return REGULAR_QUAD_PATCH;
+ else return COMPLEX_PATCH;
+ }
+ else if (vertex_crease_weight != 0.0f) return COMPLEX_PATCH;
+ else if (face_valence == 3 && hasBorder) return REGULAR_QUAD_PATCH;
+ else if (face_valence == 4 && !hasBorder) return REGULAR_QUAD_PATCH;
+ else return IRREGULAR_QUAD_PATCH;
+ }
+
+ /*! tests if this edge is part of a bilinear patch */
+ __forceinline bool bilinearVertex() const {
+ return vertex_crease_weight == float(inf) && edge_crease_weight == float(inf);
+ }
+
+ /*! calculates the type of the patch */
+ __forceinline PatchType patchType() const
+ {
+ const HalfEdge* p = this;
+ PatchType ret = REGULAR_QUAD_PATCH;
+ bool bilinear = true;
+
+ ret = max(ret,p->vertexType());
+ bilinear &= p->bilinearVertex();
+ if ((p = p->next()) == this) return COMPLEX_PATCH;
+
+ ret = max(ret,p->vertexType());
+ bilinear &= p->bilinearVertex();
+ if ((p = p->next()) == this) return COMPLEX_PATCH;
+
+ ret = max(ret,p->vertexType());
+ bilinear &= p->bilinearVertex();
+ if ((p = p->next()) == this) return COMPLEX_PATCH;
+
+ ret = max(ret,p->vertexType());
+ bilinear &= p->bilinearVertex();
+ if ((p = p->next()) != this) return COMPLEX_PATCH;
+
+ if (bilinear) return BILINEAR_PATCH;
+ return ret;
+ }
+
+ /*! tests if the face is a regular b-spline face */
+ __forceinline bool isRegularFace() const {
+ return patch_type == REGULAR_QUAD_PATCH;
+ }
+
+ /*! tests if the face can be diced (using bspline or gregory patch) */
+ __forceinline bool isGregoryFace() const {
+ return patch_type == IRREGULAR_QUAD_PATCH || patch_type == REGULAR_QUAD_PATCH;
+ }
+
+ /*! tests if the base vertex of this half edge is a corner vertex */
+ __forceinline bool isCorner() const {
+ return !hasOpposite() && !prev()->hasOpposite();
+ }
+
+ /*! tests if the vertex is attached to any border */
+ __forceinline bool vertexHasBorder() const
+ {
+ const HalfEdge* p = this;
+ do {
+ if (!p->hasOpposite()) return true;
+ p = p->rotate();
+ } while (p != this);
+ return false;
+ }
+
+ /*! tests if the face this half edge belongs to has some border */
+ __forceinline bool faceHasBorder() const
+ {
+ const HalfEdge* p = this;
+ do {
+ if (p->vertexHasBorder() && (p->vertex_type != HalfEdge::NON_MANIFOLD_EDGE_VERTEX)) return true;
+ p = p->next();
+ } while (p != this);
+ return false;
+ }
+
+ /*! calculates conservative bounds of a catmull clark subdivision face */
+ __forceinline BBox3fa bounds(const BufferView<Vec3fa>& vertices) const
+ {
+ BBox3fa bounds = this->get1RingBounds(vertices);
+ for (const HalfEdge* p=this->next(); p!=this; p=p->next())
+ bounds.extend(p->get1RingBounds(vertices));
+ return bounds;
+ }
+
+ /*! tests if this is a valid patch */
+ __forceinline bool valid(const BufferView<Vec3fa>& vertices) const
+ {
+ size_t N = 1;
+ if (!this->validRing(vertices)) return false;
+ for (const HalfEdge* p=this->next(); p!=this; p=p->next(), N++) {
+ if (!p->validRing(vertices)) return false;
+ }
+ return N >= 3 && N <= MAX_PATCH_VALENCE;
+ }
+
+ /*! counts number of polygon edges */
+ __forceinline unsigned int numEdges() const
+ {
+ unsigned int N = 1;
+ for (const HalfEdge* p=this->next(); p!=this; p=p->next(), N++);
+ return N;
+ }
+
+ /*! calculates face and edge valence */
+ __forceinline void calculateFaceValenceAndEdgeValence(size_t& faceValence, size_t& edgeValence) const
+ {
+ faceValence = 0;
+ edgeValence = 0;
+
+ const HalfEdge* p = this;
+ do
+ {
+ /* calculate bounds of current face */
+ unsigned int numEdges = p->numEdges();
+ assert(numEdges >= 3);
+ edgeValence += numEdges-2;
+
+ faceValence++;
+ p = p->prev();
+
+ /* continue with next face */
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else {
+ faceValence++;
+ edgeValence++;
+ p = this;
+ while (p->hasOpposite())
+ p = p->opposite()->next();
+ }
+
+ } while (p != this);
+ }
+
+ /*! stream output */
+ friend __forceinline std::ostream &operator<<(std::ostream &o, const HalfEdge &h)
+ {
+ return o << "{ " <<
+ "vertex = " << h.vtx_index << ", " << //" -> " << h.next()->vtx_index << ", " <<
+ "prev = " << h.prev_half_edge_ofs << ", " <<
+ "next = " << h.next_half_edge_ofs << ", " <<
+ "opposite = " << h.opposite_half_edge_ofs << ", " <<
+ "edge_crease = " << h.edge_crease_weight << ", " <<
+ "vertex_crease = " << h.vertex_crease_weight << ", " <<
+ //"edge_level = " << h.edge_level <<
+ " }";
+ }
+
+ private:
+
+ /*! calculates the bounds of the face associated with the half-edge */
+ __forceinline BBox3fa getFaceBounds(const BufferView<Vec3fa>& vertices) const
+ {
+ BBox3fa b = vertices[getStartVertexIndex()];
+ for (const HalfEdge* p = next(); p!=this; p=p->next()) {
+ b.extend(vertices[p->getStartVertexIndex()]);
+ }
+ return b;
+ }
+
+ /*! calculates the bounds of the 1-ring associated with the vertex of the half-edge */
+ __forceinline BBox3fa get1RingBounds(const BufferView<Vec3fa>& vertices) const
+ {
+ BBox3fa bounds = empty;
+ const HalfEdge* p = this;
+ do
+ {
+ /* calculate bounds of current face */
+ bounds.extend(p->getFaceBounds(vertices));
+ p = p->prev();
+
+ /* continue with next face */
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else {
+ p = this;
+ while (p->hasOpposite())
+ p = p->opposite()->next();
+ }
+
+ } while (p != this);
+
+ return bounds;
+ }
+
+ /*! tests if this is a valid face */
+ __forceinline bool validFace(const BufferView<Vec3fa>& vertices, size_t& N) const
+ {
+ const Vec3fa v = vertices[getStartVertexIndex()];
+ if (!isvalid(v)) return false;
+ size_t n = 1;
+ for (const HalfEdge* p = next(); p!=this; p=p->next(), n++) {
+ const Vec3fa v = vertices[p->getStartVertexIndex()];
+ if (!isvalid(v)) return false;
+ }
+ N += n-2;
+ return n >= 3 && n <= MAX_PATCH_VALENCE;
+ }
+
+ /*! tests if this is a valid ring */
+ __forceinline bool validRing(const BufferView<Vec3fa>& vertices) const
+ {
+ size_t faceValence = 0;
+ size_t edgeValence = 0;
+
+ const HalfEdge* p = this;
+ do
+ {
+ /* calculate bounds of current face */
+ if (!p->validFace(vertices,edgeValence))
+ return false;
+
+ faceValence++;
+ p = p->prev();
+
+ /* continue with next face */
+ if (likely(p->hasOpposite()))
+ p = p->opposite();
+
+ /* if there is no opposite go the long way to the other side of the border */
+ else {
+ faceValence++;
+ edgeValence++;
+ p = this;
+ while (p->hasOpposite())
+ p = p->opposite()->next();
+ }
+
+ } while (p != this);
+
+ return faceValence <= MAX_RING_FACE_VALENCE && edgeValence <= MAX_RING_EDGE_VALENCE;
+ }
+
+ private:
+ unsigned int vtx_index; //!< index of edge start vertex
+ int next_half_edge_ofs; //!< relative offset to next half edge of face
+ int prev_half_edge_ofs; //!< relative offset to previous half edge of face
+ int opposite_half_edge_ofs; //!< relative offset to opposite half edge
+
+ public:
+ float edge_crease_weight; //!< crease weight attached to edge
+ float vertex_crease_weight; //!< crease weight attached to start vertex
+ float edge_level; //!< subdivision factor for edge
+ PatchType patch_type; //!< stores type of subdiv patch
+ VertexType vertex_type; //!< stores type of the start vertex
+ char align[2];
+ };
+}
diff --git a/thirdparty/embree/kernels/subdiv/hermite_curve.h b/thirdparty/embree/kernels/subdiv/hermite_curve.h
new file mode 100644
index 0000000000..ffef5a4315
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/hermite_curve.h
@@ -0,0 +1,39 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+#include "bezier_curve.h"
+
+namespace embree
+{
+ template<typename Vertex>
+ struct HermiteCurveT : BezierCurveT<Vertex>
+ {
+ __forceinline HermiteCurveT() {}
+
+ __forceinline HermiteCurveT(const BezierCurveT<Vertex>& curve)
+ : BezierCurveT<Vertex>(curve) {}
+
+ __forceinline HermiteCurveT(const Vertex& v0, const Vertex& t0, const Vertex& v1, const Vertex& t1)
+ : BezierCurveT<Vertex>(v0,madd(1.0f/3.0f,t0,v0),nmadd(1.0f/3.0f,t1,v1),v1) {}
+
+ __forceinline HermiteCurveT<Vec3ff> xfm_pr(const LinearSpace3fa& space, const Vec3fa& p) const
+ {
+ const Vec3ff q0(xfmVector(space,this->v0-p), this->v0.w);
+ const Vec3ff q1(xfmVector(space,this->v1-p), this->v1.w);
+ const Vec3ff q2(xfmVector(space,this->v2-p), this->v2.w);
+ const Vec3ff q3(xfmVector(space,this->v3-p), this->v3.w);
+ return BezierCurveT<Vec3ff>(q0,q1,q2,q3);
+ }
+ };
+
+ template<typename CurveGeometry>
+ __forceinline HermiteCurveT<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const HermiteCurveT<Vec3ff>& curve) {
+ return HermiteCurveT<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,BezierCurveT<Vec3ff>(curve)));
+ }
+
+ typedef HermiteCurveT<Vec3fa> HermiteCurve3fa;
+}
+
diff --git a/thirdparty/embree/kernels/subdiv/linear_bezier_patch.h b/thirdparty/embree/kernels/subdiv/linear_bezier_patch.h
new file mode 100644
index 0000000000..f8e8a25f35
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/linear_bezier_patch.h
@@ -0,0 +1,403 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "bezier_curve.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename V>
+ struct TensorLinearQuadraticBezierSurface
+ {
+ QuadraticBezierCurve<V> L;
+ QuadraticBezierCurve<V> R;
+
+ __forceinline TensorLinearQuadraticBezierSurface() {}
+
+ __forceinline TensorLinearQuadraticBezierSurface(const TensorLinearQuadraticBezierSurface<V>& curve)
+ : L(curve.L), R(curve.R) {}
+
+ __forceinline TensorLinearQuadraticBezierSurface& operator= (const TensorLinearQuadraticBezierSurface& other) {
+ L = other.L; R = other.R; return *this;
+ }
+
+ __forceinline TensorLinearQuadraticBezierSurface(const QuadraticBezierCurve<V>& L, const QuadraticBezierCurve<V>& R)
+ : L(L), R(R) {}
+
+ __forceinline BBox<V> bounds() const {
+ return merge(L.bounds(),R.bounds());
+ }
+ };
+
+ template<>
+ struct TensorLinearQuadraticBezierSurface<Vec2fa>
+ {
+ QuadraticBezierCurve<vfloat4> LR;
+
+ __forceinline TensorLinearQuadraticBezierSurface() {}
+
+ __forceinline TensorLinearQuadraticBezierSurface(const TensorLinearQuadraticBezierSurface<Vec2fa>& curve)
+ : LR(curve.LR) {}
+
+ __forceinline TensorLinearQuadraticBezierSurface& operator= (const TensorLinearQuadraticBezierSurface& other) {
+ LR = other.LR; return *this;
+ }
+
+ __forceinline TensorLinearQuadraticBezierSurface(const QuadraticBezierCurve<vfloat4>& LR)
+ : LR(LR) {}
+
+ __forceinline BBox<Vec2fa> bounds() const
+ {
+ const BBox<vfloat4> b = LR.bounds();
+ const BBox<Vec2fa> bl(Vec2fa(b.lower),Vec2fa(b.upper));
+ const BBox<Vec2fa> br(Vec2fa(shuffle<2,3,2,3>(b.lower)),Vec2fa(shuffle<2,3,2,3>(b.upper)));
+ return merge(bl,br);
+ }
+ };
+
+ template<typename V>
+ struct TensorLinearCubicBezierSurface
+ {
+ CubicBezierCurve<V> L;
+ CubicBezierCurve<V> R;
+
+ __forceinline TensorLinearCubicBezierSurface() {}
+
+ __forceinline TensorLinearCubicBezierSurface(const TensorLinearCubicBezierSurface& curve)
+ : L(curve.L), R(curve.R) {}
+
+ __forceinline TensorLinearCubicBezierSurface& operator= (const TensorLinearCubicBezierSurface& other) {
+ L = other.L; R = other.R; return *this;
+ }
+
+ __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve<V>& L, const CubicBezierCurve<V>& R)
+ : L(L), R(R) {}
+
+ template<template<typename T> class SourceCurve>
+ __forceinline static TensorLinearCubicBezierSurface fromCenterAndNormalCurve(const SourceCurve<Vec3ff>& center, const SourceCurve<Vec3fa>& normal)
+ {
+ SourceCurve<Vec3ff> vcurve = center;
+ SourceCurve<Vec3fa> ncurve = normal;
+
+ /* here we construct a patch which follows the curve l(t) =
+ * p(t) +/- r(t)*normalize(cross(n(t),dp(t))) */
+
+ const Vec3ff p0 = vcurve.eval(0.0f);
+ const Vec3ff dp0 = vcurve.eval_du(0.0f);
+ const Vec3ff ddp0 = vcurve.eval_dudu(0.0f);
+
+ const Vec3fa n0 = ncurve.eval(0.0f);
+ const Vec3fa dn0 = ncurve.eval_du(0.0f);
+
+ const Vec3ff p1 = vcurve.eval(1.0f);
+ const Vec3ff dp1 = vcurve.eval_du(1.0f);
+ const Vec3ff ddp1 = vcurve.eval_dudu(1.0f);
+
+ const Vec3fa n1 = ncurve.eval(1.0f);
+ const Vec3fa dn1 = ncurve.eval_du(1.0f);
+
+ const Vec3fa bt0 = cross(n0,dp0);
+ const Vec3fa dbt0 = cross(dn0,dp0) + cross(n0,ddp0);
+
+ const Vec3fa bt1 = cross(n1,dp1);
+ const Vec3fa dbt1 = cross(dn1,dp1) + cross(n1,ddp1);
+
+ const Vec3fa k0 = normalize(bt0);
+ const Vec3fa dk0 = dnormalize(bt0,dbt0);
+
+ const Vec3fa k1 = normalize(bt1);
+ const Vec3fa dk1 = dnormalize(bt1,dbt1);
+
+ const Vec3fa l0 = p0 - p0.w*k0;
+ const Vec3fa dl0 = dp0 - (dp0.w*k0 + p0.w*dk0);
+
+ const Vec3fa r0 = p0 + p0.w*k0;
+ const Vec3fa dr0 = dp0 + (dp0.w*k0 + p0.w*dk0);
+
+ const Vec3fa l1 = p1 - p1.w*k1;
+ const Vec3fa dl1 = dp1 - (dp1.w*k1 + p1.w*dk1);
+
+ const Vec3fa r1 = p1 + p1.w*k1;
+ const Vec3fa dr1 = dp1 + (dp1.w*k1 + p1.w*dk1);
+
+ const float scale = 1.0f/3.0f;
+ CubicBezierCurve<V> L(l0,l0+scale*dl0,l1-scale*dl1,l1);
+ CubicBezierCurve<V> R(r0,r0+scale*dr0,r1-scale*dr1,r1);
+ return TensorLinearCubicBezierSurface(L,R);
+ }
+
+ __forceinline BBox<V> bounds() const {
+ return merge(L.bounds(),R.bounds());
+ }
+
+ __forceinline BBox3fa accurateBounds() const {
+ return merge(L.accurateBounds(),R.accurateBounds());
+ }
+
+ __forceinline CubicBezierCurve<Interval1f> reduce_v() const {
+ return merge(CubicBezierCurve<Interval<V>>(L),CubicBezierCurve<Interval<V>>(R));
+ }
+
+ __forceinline LinearBezierCurve<Interval1f> reduce_u() const {
+ return LinearBezierCurve<Interval1f>(L.bounds(),R.bounds());
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<float> xfm(const V& dx) const {
+ return TensorLinearCubicBezierSurface<float>(L.xfm(dx),R.xfm(dx));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<vfloatx> vxfm(const V& dx) const {
+ return TensorLinearCubicBezierSurface<vfloatx>(L.vxfm(dx),R.vxfm(dx));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<float> xfm(const V& dx, const V& p) const {
+ return TensorLinearCubicBezierSurface<float>(L.xfm(dx,p),R.xfm(dx,p));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<Vec3fa> xfm(const LinearSpace3fa& space) const {
+ return TensorLinearCubicBezierSurface(L.xfm(space),R.xfm(space));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<Vec3fa> xfm(const LinearSpace3fa& space, const Vec3fa& p) const {
+ return TensorLinearCubicBezierSurface(L.xfm(space,p),R.xfm(space,p));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<Vec3fa> xfm(const LinearSpace3fa& space, const Vec3fa& p, const float s) const {
+ return TensorLinearCubicBezierSurface(L.xfm(space,p,s),R.xfm(space,p,s));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip_u(const Interval1f& u) const {
+ return TensorLinearCubicBezierSurface(L.clip(u),R.clip(u));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip_v(const Interval1f& v) const {
+ return TensorLinearCubicBezierSurface(clerp(L,R,V(v.lower)),clerp(L,R,V(v.upper)));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip(const Interval1f& u, const Interval1f& v) const {
+ return clip_v(v).clip_u(u);
+ }
+
+ __forceinline void split_u(TensorLinearCubicBezierSurface& left, TensorLinearCubicBezierSurface& right, const float u = 0.5f) const
+ {
+ CubicBezierCurve<V> L0,L1; L.split(L0,L1,u);
+ CubicBezierCurve<V> R0,R1; R.split(R0,R1,u);
+ new (&left ) TensorLinearCubicBezierSurface(L0,R0);
+ new (&right) TensorLinearCubicBezierSurface(L1,R1);
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<Vec2vfx> vsplit_u(vboolx& valid, const BBox1f& u) const {
+ valid = true; clear(valid,VSIZEX-1);
+ return TensorLinearCubicBezierSurface<Vec2vfx>(L.split(u),R.split(u));
+ }
+
+ __forceinline V eval(const float u, const float v) const {
+ return clerp(L,R,V(v)).eval(u);
+ }
+
+ __forceinline V eval_du(const float u, const float v) const {
+ return clerp(L,R,V(v)).eval_dt(u);
+ }
+
+ __forceinline V eval_dv(const float u, const float v) const {
+ return (R-L).eval(u);
+ }
+
+ __forceinline void eval(const float u, const float v, V& p, V& dpdu, V& dpdv) const
+ {
+ V p0, dp0du; L.eval(u,p0,dp0du);
+ V p1, dp1du; R.eval(u,p1,dp1du);
+ p = lerp(p0,p1,v);
+ dpdu = lerp(dp0du,dp1du,v);
+ dpdv = p1-p0;
+ }
+
+ __forceinline TensorLinearQuadraticBezierSurface<V> derivative_u() const {
+ return TensorLinearQuadraticBezierSurface<V>(L.derivative(),R.derivative());
+ }
+
+ __forceinline CubicBezierCurve<V> derivative_v() const {
+ return R-L;
+ }
+
+ __forceinline V axis_u() const {
+ return (L.end()-L.begin())+(R.end()-R.begin());
+ }
+
+ __forceinline V axis_v() const {
+ return (R.begin()-L.begin())+(R.end()-L.end());
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const TensorLinearCubicBezierSurface& a)
+ {
+ return cout << "TensorLinearCubicBezierSurface" << embree_endl
+ << "{" << embree_endl
+ << " L = " << a.L << ", " << embree_endl
+ << " R = " << a.R << embree_endl
+ << "}";
+ }
+
+ friend __forceinline TensorLinearCubicBezierSurface clerp(const TensorLinearCubicBezierSurface& a, const TensorLinearCubicBezierSurface& b, const float t) {
+ return TensorLinearCubicBezierSurface(clerp(a.L,b.L,V(t)), clerp(a.R,b.R,V(t)));
+ }
+ };
+
+ template<>
+ struct TensorLinearCubicBezierSurface<Vec2fa>
+ {
+ CubicBezierCurve<vfloat4> LR;
+
+ __forceinline TensorLinearCubicBezierSurface() {}
+
+ __forceinline TensorLinearCubicBezierSurface(const TensorLinearCubicBezierSurface& curve)
+ : LR(curve.LR) {}
+
+ __forceinline TensorLinearCubicBezierSurface& operator= (const TensorLinearCubicBezierSurface& other) {
+ LR = other.LR; return *this;
+ }
+
+ __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve<vfloat4>& LR)
+ : LR(LR) {}
+
+ __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve<Vec2fa>& L, const CubicBezierCurve<Vec2fa>& R)
+ : LR(shuffle<0,1,0,1>(vfloat4(L.v0),vfloat4(R.v0)),shuffle<0,1,0,1>(vfloat4(L.v1),vfloat4(R.v1)),shuffle<0,1,0,1>(vfloat4(L.v2),vfloat4(R.v2)),shuffle<0,1,0,1>(vfloat4(L.v3),vfloat4(R.v3))) {}
+
+ __forceinline CubicBezierCurve<Vec2fa> getL() const {
+ return CubicBezierCurve<Vec2fa>(Vec2fa(LR.v0),Vec2fa(LR.v1),Vec2fa(LR.v2),Vec2fa(LR.v3));
+ }
+
+ __forceinline CubicBezierCurve<Vec2fa> getR() const {
+ return CubicBezierCurve<Vec2fa>(Vec2fa(shuffle<2,3,2,3>(LR.v0)),Vec2fa(shuffle<2,3,2,3>(LR.v1)),Vec2fa(shuffle<2,3,2,3>(LR.v2)),Vec2fa(shuffle<2,3,2,3>(LR.v3)));
+ }
+
+ __forceinline BBox<Vec2fa> bounds() const
+ {
+ const BBox<vfloat4> b = LR.bounds();
+ const BBox<Vec2fa> bl(Vec2fa(b.lower),Vec2fa(b.upper));
+ const BBox<Vec2fa> br(Vec2fa(shuffle<2,3,2,3>(b.lower)),Vec2fa(shuffle<2,3,2,3>(b.upper)));
+ return merge(bl,br);
+ }
+
+ __forceinline BBox1f bounds(const Vec2fa& axis) const
+ {
+ const CubicBezierCurve<vfloat4> LRx = LR;
+ const CubicBezierCurve<vfloat4> LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3));
+ const CubicBezierCurve<vfloat4> LRa = cmadd(shuffle<0>(vfloat4(axis)),LRx,shuffle<1>(vfloat4(axis))*LRy);
+ const BBox<vfloat4> Lb = LRa.bounds();
+ const BBox<vfloat4> Rb(shuffle<3>(Lb.lower),shuffle<3>(Lb.upper));
+ const BBox<vfloat4> b = merge(Lb,Rb);
+ return BBox1f(b.lower[0],b.upper[0]);
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<float> xfm(const Vec2fa& dx) const
+ {
+ const CubicBezierCurve<vfloat4> LRx = LR;
+ const CubicBezierCurve<vfloat4> LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3));
+ const CubicBezierCurve<vfloat4> LRa = cmadd(shuffle<0>(vfloat4(dx)),LRx,shuffle<1>(vfloat4(dx))*LRy);
+ return TensorLinearCubicBezierSurface<float>(CubicBezierCurve<float>(LRa.v0[0],LRa.v1[0],LRa.v2[0],LRa.v3[0]),
+ CubicBezierCurve<float>(LRa.v0[2],LRa.v1[2],LRa.v2[2],LRa.v3[2]));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<float> xfm(const Vec2fa& dx, const Vec2fa& p) const
+ {
+ const vfloat4 pxyxy = shuffle<0,1,0,1>(vfloat4(p));
+ const CubicBezierCurve<vfloat4> LRx = LR-pxyxy;
+ const CubicBezierCurve<vfloat4> LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3));
+ const CubicBezierCurve<vfloat4> LRa = cmadd(shuffle<0>(vfloat4(dx)),LRx,shuffle<1>(vfloat4(dx))*LRy);
+ return TensorLinearCubicBezierSurface<float>(CubicBezierCurve<float>(LRa.v0[0],LRa.v1[0],LRa.v2[0],LRa.v3[0]),
+ CubicBezierCurve<float>(LRa.v0[2],LRa.v1[2],LRa.v2[2],LRa.v3[2]));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip_u(const Interval1f& u) const {
+ return TensorLinearCubicBezierSurface(LR.clip(u));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip_v(const Interval1f& v) const
+ {
+ const CubicBezierCurve<vfloat4> LL(shuffle<0,1,0,1>(LR.v0),shuffle<0,1,0,1>(LR.v1),shuffle<0,1,0,1>(LR.v2),shuffle<0,1,0,1>(LR.v3));
+ const CubicBezierCurve<vfloat4> RR(shuffle<2,3,2,3>(LR.v0),shuffle<2,3,2,3>(LR.v1),shuffle<2,3,2,3>(LR.v2),shuffle<2,3,2,3>(LR.v3));
+ return TensorLinearCubicBezierSurface(clerp(LL,RR,vfloat4(v.lower,v.lower,v.upper,v.upper)));
+ }
+
+ __forceinline TensorLinearCubicBezierSurface clip(const Interval1f& u, const Interval1f& v) const {
+ return clip_v(v).clip_u(u);
+ }
+
+ __forceinline void split_u(TensorLinearCubicBezierSurface& left, TensorLinearCubicBezierSurface& right, const float u = 0.5f) const
+ {
+ CubicBezierCurve<vfloat4> LR0,LR1; LR.split(LR0,LR1,u);
+ new (&left ) TensorLinearCubicBezierSurface(LR0);
+ new (&right) TensorLinearCubicBezierSurface(LR1);
+ }
+
+ __forceinline TensorLinearCubicBezierSurface<Vec2vfx> vsplit_u(vboolx& valid, const BBox1f& u) const {
+ valid = true; clear(valid,VSIZEX-1);
+ return TensorLinearCubicBezierSurface<Vec2vfx>(getL().split(u),getR().split(u));
+ }
+
+ __forceinline Vec2fa eval(const float u, const float v) const
+ {
+ const vfloat4 p = LR.eval(u);
+ return Vec2fa(lerp(shuffle<0,1,0,1>(p),shuffle<2,3,2,3>(p),v));
+ }
+
+ __forceinline Vec2fa eval_du(const float u, const float v) const
+ {
+ const vfloat4 dpdu = LR.eval_dt(u);
+ return Vec2fa(lerp(shuffle<0,1,0,1>(dpdu),shuffle<2,3,2,3>(dpdu),v));
+ }
+
+ __forceinline Vec2fa eval_dv(const float u, const float v) const
+ {
+ const vfloat4 p = LR.eval(u);
+ return Vec2fa(shuffle<2,3,2,3>(p)-shuffle<0,1,0,1>(p));
+ }
+
+ __forceinline void eval(const float u, const float v, Vec2fa& p, Vec2fa& dpdu, Vec2fa& dpdv) const
+ {
+ vfloat4 p0, dp0du; LR.eval(u,p0,dp0du);
+ p = Vec2fa(lerp(shuffle<0,1,0,1>(p0),shuffle<2,3,2,3>(p0),v));
+ dpdu = Vec2fa(lerp(shuffle<0,1,0,1>(dp0du),shuffle<2,3,2,3>(dp0du),v));
+ dpdv = Vec2fa(shuffle<2,3,2,3>(p0)-shuffle<0,1,0,1>(p0));
+ }
+
+ __forceinline TensorLinearQuadraticBezierSurface<Vec2fa> derivative_u() const {
+ return TensorLinearQuadraticBezierSurface<Vec2fa>(LR.derivative());
+ }
+
+ __forceinline CubicBezierCurve<Vec2fa> derivative_v() const {
+ return getR()-getL();
+ }
+
+ __forceinline Vec2fa axis_u() const
+ {
+ const CubicBezierCurve<Vec2fa> L = getL();
+ const CubicBezierCurve<Vec2fa> R = getR();
+ return (L.end()-L.begin())+(R.end()-R.begin());
+ }
+
+ __forceinline Vec2fa axis_v() const
+ {
+ const CubicBezierCurve<Vec2fa> L = getL();
+ const CubicBezierCurve<Vec2fa> R = getR();
+ return (R.begin()-L.begin())+(R.end()-L.end());
+ }
+
+ friend embree_ostream operator<<(embree_ostream cout, const TensorLinearCubicBezierSurface& a)
+ {
+ return cout << "TensorLinearCubicBezierSurface" << embree_endl
+ << "{" << embree_endl
+ << " L = " << a.getL() << ", " << embree_endl
+ << " R = " << a.getR() << embree_endl
+ << "}";
+ }
+ };
+
+ typedef TensorLinearCubicBezierSurface<float> TensorLinearCubicBezierSurface1f;
+ typedef TensorLinearCubicBezierSurface<Vec2fa> TensorLinearCubicBezierSurface2fa;
+ typedef TensorLinearCubicBezierSurface<Vec3fa> TensorLinearCubicBezierSurface3fa;
+ }
+}
diff --git a/thirdparty/embree/kernels/subdiv/patch.h b/thirdparty/embree/kernels/subdiv/patch.h
new file mode 100644
index 0000000000..c4340ea9b6
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/patch.h
@@ -0,0 +1,371 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "catmullclark_patch.h"
+#include "bilinear_patch.h"
+#include "bspline_patch.h"
+#include "bezier_patch.h"
+#include "gregory_patch.h"
+#include "tessellation_cache.h"
+
+#if 1
+#define PATCH_DEBUG_SUBDIVISION(ptr,x,y,z)
+#else
+#define PATCH_DEBUG_SUBDIVISION(ptr,x,y,z) \
+ { \
+ size_t hex = (size_t)ptr; \
+ for (size_t i=0; i<4; i++) hex = hex ^ (hex >> 8); \
+ const float c = (float)(((hex >> 0) ^ (hex >> 4) ^ (hex >> 8) ^ (hex >> 12) ^ (hex >> 16))&0xf)/15.0f; \
+ if (P) *P = Vertex(0.5f+0.5f*x,0.5f+0.5f*y,0.5f+0.5f*z,0.0f); \
+ }
+#endif
+
+#define PATCH_MAX_CACHE_DEPTH 2
+//#define PATCH_MIN_RESOLUTION 1 // FIXME: not yet completely implemented
+#define PATCH_MAX_EVAL_DEPTH_IRREGULAR 10 // maximum evaluation depth at irregular vertices (has to be larger or equal than PATCH_MAX_CACHE_DEPTH)
+#define PATCH_MAX_EVAL_DEPTH_CREASE 10 // maximum evaluation depth at crease features (has to be larger or equal than PATCH_MAX_CACHE_DEPTH)
+#define PATCH_USE_GREGORY 1 // 0 = no gregory, 1 = fill, 2 = as early as possible
+
+#if PATCH_USE_GREGORY==2
+#define PATCH_USE_BEZIER_PATCH 1 // enable use of bezier instead of b-spline patches
+#else
+#define PATCH_USE_BEZIER_PATCH 0 // enable use of bezier instead of b-spline patches
+#endif
+
+#if PATCH_USE_BEZIER_PATCH
+# define RegularPatch BezierPatch
+# define RegularPatchT BezierPatchT<Vertex,Vertex_t>
+#else
+# define RegularPatch BSplinePatch
+# define RegularPatchT BSplinePatchT<Vertex,Vertex_t>
+#endif
+
+#if PATCH_USE_GREGORY
+#define IrregularFillPatch GregoryPatch
+#define IrregularFillPatchT GregoryPatchT<Vertex,Vertex_t>
+#else
+#define IrregularFillPatch BilinearPatch
+#define IrregularFillPatchT BilinearPatchT<Vertex,Vertex_t>
+#endif
+
+namespace embree
+{
+ template<typename Vertex, typename Vertex_t = Vertex>
+ struct __aligned(64) PatchT
+ {
+ public:
+
+ typedef GeneralCatmullClarkPatchT<Vertex,Vertex_t> GeneralCatmullClarkPatch;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+ typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
+ typedef BezierCurveT<Vertex> BezierCurve;
+
+ enum Type {
+ INVALID_PATCH = 0,
+ BILINEAR_PATCH = 1,
+ BSPLINE_PATCH = 2,
+ BEZIER_PATCH = 3,
+ GREGORY_PATCH = 4,
+ SUBDIVIDED_GENERAL_PATCH = 7,
+ SUBDIVIDED_QUAD_PATCH = 8,
+ EVAL_PATCH = 9,
+ };
+
+ struct Ref
+ {
+ __forceinline Ref(void* p = nullptr)
+ : ptr((size_t)p) {}
+
+ __forceinline operator bool() const { return ptr != 0; }
+ __forceinline operator size_t() const { return ptr; }
+
+ __forceinline Ref (Type ty, void* in)
+ : ptr(((size_t)in)+ty) { assert((((size_t)in) & 0xF) == 0); }
+
+ __forceinline Type type () const { return (Type)(ptr & 0xF); }
+ __forceinline void* object() const { return (void*) (ptr & ~0xF); }
+
+ size_t ptr;
+ };
+
+ struct EvalPatch
+ {
+ /* creates EvalPatch from a CatmullClarkPatch */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch)
+ {
+ size_t ofs = 0, bytes = patch.bytes();
+ void* ptr = alloc(bytes);
+ patch.serialize(ptr,ofs);
+ assert(ofs == bytes);
+ return Ref(EVAL_PATCH, ptr);
+ }
+ };
+
+ struct BilinearPatch
+ {
+ /* creates BilinearPatch from a CatmullClarkPatch */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
+ const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
+ return Ref(BILINEAR_PATCH, new (alloc(sizeof(BilinearPatch))) BilinearPatch(patch));
+ }
+
+ __forceinline BilinearPatch (const CatmullClarkPatch& patch)
+ : patch(patch) {}
+
+ /* creates BilinearPatch from 4 vertices */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
+ return Ref(BILINEAR_PATCH, new (alloc(sizeof(BilinearPatch))) BilinearPatch(edge,vertices,stride));
+ }
+
+ __forceinline BilinearPatch (const HalfEdge* edge, const char* vertices, size_t stride)
+ : patch(edge,vertices,stride) {}
+
+ public:
+ BilinearPatchT<Vertex,Vertex_t> patch;
+ };
+
+ struct BSplinePatch
+ {
+ /* creates BSplinePatch from a half edge */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
+ return Ref(BSPLINE_PATCH, new (alloc(sizeof(BSplinePatch))) BSplinePatch(edge,vertices,stride));
+ }
+
+ __forceinline BSplinePatch (const HalfEdge* edge, const char* vertices, size_t stride)
+ : patch(edge,vertices,stride) {}
+
+ /* creates BSplinePatch from a CatmullClarkPatch */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
+ const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
+ return Ref(BSPLINE_PATCH, new (alloc(sizeof(BSplinePatch))) BSplinePatch(patch,border0,border1,border2,border3));
+ }
+
+ __forceinline BSplinePatch (const CatmullClarkPatch& patch, const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
+ : patch(patch,border0,border1,border2,border3) {}
+
+ public:
+ BSplinePatchT<Vertex,Vertex_t> patch;
+ };
+
+ struct BezierPatch
+ {
+ /* creates BezierPatch from a half edge */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
+ return Ref(BEZIER_PATCH, new (alloc(sizeof(BezierPatch))) BezierPatch(edge,vertices,stride));
+ }
+
+ __forceinline BezierPatch (const HalfEdge* edge, const char* vertices, size_t stride)
+ : patch(edge,vertices,stride) {}
+
+ /* creates Bezier from a CatmullClarkPatch */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
+ const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
+ return Ref(BEZIER_PATCH, new (alloc(sizeof(BezierPatch))) BezierPatch(patch,border0,border1,border2,border3));
+ }
+
+ __forceinline BezierPatch (const CatmullClarkPatch& patch, const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
+ : patch(patch,border0,border1,border2,border3) {}
+
+ public:
+ BezierPatchT<Vertex,Vertex_t> patch;
+ };
+
+ struct GregoryPatch
+ {
+ /* creates GregoryPatch from half edge */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
+ return Ref(GREGORY_PATCH, new (alloc(sizeof(GregoryPatch))) GregoryPatch(edge,vertices,stride));
+ }
+
+ __forceinline GregoryPatch (const HalfEdge* edge, const char* vertices, size_t stride)
+ : patch(CatmullClarkPatch(edge,vertices,stride)) {}
+
+ /* creates GregoryPatch from CatmullClarkPatch */
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
+ const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
+ return Ref(GREGORY_PATCH, new (alloc(sizeof(GregoryPatch))) GregoryPatch(patch,border0,border1,border2,border3));
+ }
+
+ __forceinline GregoryPatch (const CatmullClarkPatch& patch, const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
+ : patch(patch,border0,border1,border2,border3) {}
+
+ public:
+ GregoryPatchT<Vertex,Vertex_t> patch;
+ };
+
+ struct SubdividedQuadPatch
+ {
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, Ref children[4]) {
+ return Ref(SUBDIVIDED_QUAD_PATCH, new (alloc(sizeof(SubdividedQuadPatch))) SubdividedQuadPatch(children));
+ }
+
+ __forceinline SubdividedQuadPatch(Ref children[4]) {
+ for (size_t i=0; i<4; i++) child[i] = children[i];
+ }
+
+ public:
+ Ref child[4];
+ };
+
+ struct SubdividedGeneralPatch
+ {
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, Ref* children, const unsigned N) {
+ return Ref(SUBDIVIDED_GENERAL_PATCH, new (alloc(sizeof(SubdividedGeneralPatch))) SubdividedGeneralPatch(children,N));
+ }
+
+ __forceinline SubdividedGeneralPatch(Ref* children, const unsigned N) : N(N) {
+ for (unsigned i=0; i<N; i++) child[i] = children[i];
+ }
+
+ unsigned N;
+ Ref child[MAX_PATCH_VALENCE];
+ };
+
+ /*! Default constructor. */
+ __forceinline PatchT () {}
+
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride)
+ {
+ if (PATCH_MAX_CACHE_DEPTH == 0)
+ return nullptr;
+
+ Ref child(0);
+ switch (edge->patch_type) {
+ case HalfEdge::BILINEAR_PATCH: child = BilinearPatch::create(alloc,edge,vertices,stride); break;
+ case HalfEdge::REGULAR_QUAD_PATCH: child = RegularPatch::create(alloc,edge,vertices,stride); break;
+#if PATCH_USE_GREGORY == 2
+ case HalfEdge::IRREGULAR_QUAD_PATCH: child = GregoryPatch::create(alloc,edge,vertices,stride); break;
+#endif
+ default: {
+ GeneralCatmullClarkPatch patch(edge,vertices,stride);
+ child = PatchT::create(alloc,patch,edge,vertices,stride,0);
+ }
+ }
+ return child;
+ }
+
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, GeneralCatmullClarkPatch& patch, const HalfEdge* edge, const char* vertices, size_t stride, size_t depth)
+ {
+ /* convert into standard quad patch if possible */
+ if (likely(patch.isQuadPatch()))
+ {
+ CatmullClarkPatch qpatch; patch.init(qpatch);
+ return PatchT::create(alloc,qpatch,edge,vertices,stride,depth);
+ }
+
+ /* do only cache up to some depth */
+ if (depth >= PATCH_MAX_CACHE_DEPTH)
+ return nullptr;
+
+ /* subdivide patch */
+ unsigned N;
+ array_t<CatmullClarkPatch,GeneralCatmullClarkPatch::SIZE> patches;
+ patch.subdivide(patches,N);
+
+ if (N == 4)
+ {
+ Ref child[4];
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[GeneralCatmullClarkPatch::SIZE]; patch.getLimitBorder(borders);
+ BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
+ BezierCurve border1l,border1r; borders[1].subdivide(border1l,border1r);
+ BezierCurve border2l,border2r; borders[2].subdivide(border2l,border2r);
+ BezierCurve border3l,border3r; borders[3].subdivide(border3l,border3r);
+ GeneralCatmullClarkPatch::fix_quad_ring_order(patches);
+ child[0] = PatchT::create(alloc,patches[0],edge,vertices,stride,depth+1,&border0l,nullptr,nullptr,&border3r);
+ child[1] = PatchT::create(alloc,patches[1],edge,vertices,stride,depth+1,&border0r,&border1l,nullptr,nullptr);
+ child[2] = PatchT::create(alloc,patches[2],edge,vertices,stride,depth+1,nullptr,&border1r,&border2l,nullptr);
+ child[3] = PatchT::create(alloc,patches[3],edge,vertices,stride,depth+1,nullptr,nullptr,&border2r,&border3l);
+#else
+ GeneralCatmullClarkPatch::fix_quad_ring_order(patches);
+ for (size_t i=0; i<4; i++)
+ child[i] = PatchT::create(alloc,patches[i],edge,vertices,stride,depth+1);
+#endif
+ return SubdividedQuadPatch::create(alloc,child);
+ }
+ else
+ {
+ assert(N<MAX_PATCH_VALENCE);
+ Ref child[MAX_PATCH_VALENCE];
+
+#if PATCH_USE_GREGORY == 2
+ BezierCurve borders[GeneralCatmullClarkPatch::SIZE];
+ patch.getLimitBorder(borders);
+
+ for (size_t i0=0; i0<N; i0++) {
+ const size_t i2 = i0==0 ? N-1 : i0-1;
+ BezierCurve border0l,border0r; borders[i0].subdivide(border0l,border0r);
+ BezierCurve border2l,border2r; borders[i2].subdivide(border2l,border2r);
+ child[i0] = PatchT::create(alloc,patches[i0],edge,vertices,stride,depth+1, &border0l, nullptr, nullptr, &border2r);
+ }
+#else
+ for (size_t i=0; i<N; i++)
+ child[i] = PatchT::create(alloc,patches[i],edge,vertices,stride,depth+1);
+#endif
+ return SubdividedGeneralPatch::create(alloc,child,N);
+ }
+
+ return nullptr;
+ }
+
+ static __forceinline bool final(const CatmullClarkPatch& patch, const typename CatmullClarkRing::Type type, size_t depth)
+ {
+ const size_t max_eval_depth = (type & CatmullClarkRing::TYPE_CREASES) ? PATCH_MAX_EVAL_DEPTH_CREASE : PATCH_MAX_EVAL_DEPTH_IRREGULAR;
+//#if PATCH_MIN_RESOLUTION
+// return patch.isFinalResolution(PATCH_MIN_RESOLUTION) || depth>=max_eval_depth;
+//#else
+ return depth>=max_eval_depth;
+//#endif
+ }
+
+ template<typename Allocator>
+ __noinline static Ref create(const Allocator& alloc, CatmullClarkPatch& patch, const HalfEdge* edge, const char* vertices, size_t stride, size_t depth,
+ const BezierCurve* border0 = nullptr, const BezierCurve* border1 = nullptr, const BezierCurve* border2 = nullptr, const BezierCurve* border3 = nullptr)
+ {
+ const typename CatmullClarkPatch::Type ty = patch.type();
+ if (unlikely(final(patch,ty,depth))) {
+ if (ty & CatmullClarkRing::TYPE_REGULAR) return RegularPatch::create(alloc,patch,border0,border1,border2,border3);
+ else return IrregularFillPatch::create(alloc,patch,border0,border1,border2,border3);
+ }
+ else if (ty & CatmullClarkRing::TYPE_REGULAR_CREASES) {
+ assert(depth > 0); return RegularPatch::create(alloc,patch,border0,border1,border2,border3);
+ }
+#if PATCH_USE_GREGORY == 2
+ else if (ty & CatmullClarkRing::TYPE_GREGORY_CREASES) {
+ assert(depth > 0); return GregoryPatch::create(alloc,patch,border0,border1,border2,border3);
+ }
+#endif
+ else if (depth >= PATCH_MAX_CACHE_DEPTH) {
+ return EvalPatch::create(alloc,patch);
+ }
+
+ else
+ {
+ Ref child[4];
+ array_t<CatmullClarkPatch,4> patches;
+ patch.subdivide(patches);
+
+ for (size_t i=0; i<4; i++)
+ child[i] = PatchT::create(alloc,patches[i],edge,vertices,stride,depth+1);
+ return SubdividedQuadPatch::create(alloc,child);
+ }
+ }
+ };
+
+ typedef PatchT<Vec3fa,Vec3fa_t> Patch3fa;
+}
diff --git a/thirdparty/embree/kernels/subdiv/patch_eval.h b/thirdparty/embree/kernels/subdiv/patch_eval.h
new file mode 100644
index 0000000000..a3fafa72f4
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/patch_eval.h
@@ -0,0 +1,129 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+#include "feature_adaptive_eval.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename Vertex, typename Vertex_t = Vertex>
+ struct PatchEval
+ {
+ public:
+
+ typedef PatchT<Vertex,Vertex_t> Patch;
+ typedef typename Patch::Ref Ref;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+
+ PatchEval (SharedLazyTessellationCache::CacheEntry& entry, size_t commitCounter,
+ const HalfEdge* edge, const char* vertices, size_t stride, const float u, const float v,
+ Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv)
+ {
+ /* conservative time for the very first allocation */
+ auto time = SharedLazyTessellationCache::sharedLazyTessellationCache.getTime(commitCounter);
+
+ Ref patch = SharedLazyTessellationCache::lookup(entry,commitCounter,[&] () {
+ auto alloc = [&](size_t bytes) { return SharedLazyTessellationCache::malloc(bytes); };
+ return Patch::create(alloc,edge,vertices,stride);
+ },true);
+
+ auto curTime = SharedLazyTessellationCache::sharedLazyTessellationCache.getTime(commitCounter);
+ const bool allAllocationsValid = SharedLazyTessellationCache::validTime(time,curTime);
+
+ if (patch && allAllocationsValid && eval(patch,u,v,1.0f,0)) {
+ SharedLazyTessellationCache::unlock();
+ return;
+ }
+ SharedLazyTessellationCache::unlock();
+ FeatureAdaptiveEval<Vertex,Vertex_t>(edge,vertices,stride,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv);
+ PATCH_DEBUG_SUBDIVISION(edge,c,-1,-1);
+ }
+
+ __forceinline bool eval_quad(const typename Patch::SubdividedQuadPatch* This, const float u, const float v, const float dscale, const size_t depth)
+ {
+ if (v < 0.5f) {
+ if (u < 0.5f) return eval(This->child[0],2.0f*u,2.0f*v,2.0f*dscale,depth+1);
+ else return eval(This->child[1],2.0f*u-1.0f,2.0f*v,2.0f*dscale,depth+1);
+ } else {
+ if (u > 0.5f) return eval(This->child[2],2.0f*u-1.0f,2.0f*v-1.0f,2.0f*dscale,depth+1);
+ else return eval(This->child[3],2.0f*u,2.0f*v-1.0f,2.0f*dscale,depth+1);
+ }
+ }
+
+ bool eval_general(const typename Patch::SubdividedGeneralPatch* This, const float U, const float V, const size_t depth)
+ {
+ const unsigned l = (unsigned) floor(0.5f*U); const float u = 2.0f*frac(0.5f*U)-0.5f;
+ const unsigned h = (unsigned) floor(0.5f*V); const float v = 2.0f*frac(0.5f*V)-0.5f;
+ const unsigned i = 4*h+l; assert(i<This->N);
+ return eval(This->child[i],u,v,1.0f,depth+1);
+ }
+
+ bool eval(Ref This, const float& u, const float& v, const float dscale, const size_t depth)
+ {
+ if (!This) return false;
+ //PRINT(depth);
+ //PRINT2(u,v);
+
+ switch (This.type())
+ {
+ case Patch::BILINEAR_PATCH: {
+ //PRINT("bilinear");
+ ((typename Patch::BilinearPatch*)This.object())->patch.eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(This,-1,c,c);
+ return true;
+ }
+ case Patch::BSPLINE_PATCH: {
+ //PRINT("bspline");
+ ((typename Patch::BSplinePatch*)This.object())->patch.eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(This,-1,c,-1);
+ return true;
+ }
+ case Patch::BEZIER_PATCH: {
+ //PRINT("bezier");
+ ((typename Patch::BezierPatch*)This.object())->patch.eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(This,-1,c,-1);
+ return true;
+ }
+ case Patch::GREGORY_PATCH: {
+ //PRINT("gregory");
+ ((typename Patch::GregoryPatch*)This.object())->patch.eval(u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale);
+ PATCH_DEBUG_SUBDIVISION(This,-1,-1,c);
+ return true;
+ }
+ case Patch::SUBDIVIDED_QUAD_PATCH: {
+ //PRINT("subdivided quad");
+ return eval_quad(((typename Patch::SubdividedQuadPatch*)This.object()),u,v,dscale,depth);
+ }
+ case Patch::SUBDIVIDED_GENERAL_PATCH: {
+ //PRINT("general_patch");
+ assert(dscale == 1.0f);
+ return eval_general(((typename Patch::SubdividedGeneralPatch*)This.object()),u,v,depth);
+ }
+ case Patch::EVAL_PATCH: {
+ //PRINT("eval_patch");
+ CatmullClarkPatch patch; patch.deserialize(This.object());
+ FeatureAdaptiveEval<Vertex,Vertex_t>(patch,u,v,dscale,depth,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv);
+ return true;
+ }
+ default:
+ assert(false);
+ return false;
+ }
+ }
+
+ private:
+ Vertex* const P;
+ Vertex* const dPdu;
+ Vertex* const dPdv;
+ Vertex* const ddPdudu;
+ Vertex* const ddPdvdv;
+ Vertex* const ddPdudv;
+ };
+ }
+}
+
diff --git a/thirdparty/embree/kernels/subdiv/patch_eval_grid.h b/thirdparty/embree/kernels/subdiv/patch_eval_grid.h
new file mode 100644
index 0000000000..167e1ebe1c
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/patch_eval_grid.h
@@ -0,0 +1,245 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+#include "feature_adaptive_eval_grid.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ struct PatchEvalGrid
+ {
+ typedef Patch3fa Patch;
+ typedef Patch::Ref Ref;
+ typedef GeneralCatmullClarkPatch3fa GeneralCatmullClarkPatch;
+ typedef CatmullClarkPatch3fa CatmullClarkPatch;
+ typedef BSplinePatch3fa BSplinePatch;
+ typedef BezierPatch3fa BezierPatch;
+ typedef GregoryPatch3fa GregoryPatch;
+ typedef BilinearPatch3fa BilinearPatch;
+
+ private:
+ const unsigned x0,x1;
+ const unsigned y0,y1;
+ const unsigned swidth,sheight;
+ const float rcp_swidth, rcp_sheight;
+ float* const Px;
+ float* const Py;
+ float* const Pz;
+ float* const U;
+ float* const V;
+ float* const Nx;
+ float* const Ny;
+ float* const Nz;
+ const unsigned dwidth,dheight;
+ unsigned count;
+
+ public:
+
+ PatchEvalGrid (Ref patch, unsigned subPatch,
+ const unsigned x0, const unsigned x1, const unsigned y0, const unsigned y1, const unsigned swidth, const unsigned sheight,
+ float* Px, float* Py, float* Pz, float* U, float* V,
+ float* Nx, float* Ny, float* Nz,
+ const unsigned dwidth, const unsigned dheight)
+ : x0(x0), x1(x1), y0(y0), y1(y1), swidth(swidth), sheight(sheight), rcp_swidth(1.0f/(swidth-1.0f)), rcp_sheight(1.0f/(sheight-1.0f)),
+ Px(Px), Py(Py), Pz(Pz), U(U), V(V), Nx(Nx), Ny(Ny), Nz(Nz), dwidth(dwidth), dheight(dheight), count(0)
+ {
+ assert(swidth < (2<<20) && sheight < (2<<20));
+ const BBox2f srange(Vec2f(0.0f,0.0f),Vec2f(float(swidth-1),float(sheight-1)));
+ const BBox2f erange(Vec2f(float(x0),float(y0)),Vec2f((float)x1,(float)y1));
+ bool done MAYBE_UNUSED = eval(patch,subPatch,srange,erange);
+ assert(done);
+ assert(count == (x1-x0+1)*(y1-y0+1));
+ }
+
+ template<typename Patch>
+ __forceinline void evalLocalGrid(const Patch* patch, const BBox2f& srange, const int lx0, const int lx1, const int ly0, const int ly1)
+ {
+ const float scale_x = rcp(srange.upper.x-srange.lower.x);
+ const float scale_y = rcp(srange.upper.y-srange.lower.y);
+ count += (lx1-lx0)*(ly1-ly0);
+
+#if 0
+ for (unsigned iy=ly0; iy<ly1; iy++) {
+ for (unsigned ix=lx0; ix<lx1; ix++) {
+ const float lu = select(ix == swidth -1, float(1.0f), (float(ix)-srange.lower.x)*scale_x);
+ const float lv = select(iy == sheight-1, float(1.0f), (float(iy)-srange.lower.y)*scale_y);
+ const Vec3fa p = patch->patch.eval(lu,lv);
+ const float u = float(ix)*rcp_swidth;
+ const float v = float(iy)*rcp_sheight;
+ const int ofs = (iy-y0)*dwidth+(ix-x0);
+ Px[ofs] = p.x;
+ Py[ofs] = p.y;
+ Pz[ofs] = p.z;
+ U[ofs] = u;
+ V[ofs] = v;
+ }
+ }
+#else
+ foreach2(lx0,lx1,ly0,ly1,[&](const vboolx& valid, const vintx& ix, const vintx& iy) {
+ const vfloatx lu = select(ix == swidth -1, vfloatx(1.0f), (vfloatx(ix)-srange.lower.x)*scale_x);
+ const vfloatx lv = select(iy == sheight-1, vfloatx(1.0f), (vfloatx(iy)-srange.lower.y)*scale_y);
+ const Vec3vfx p = patch->patch.eval(lu,lv);
+ Vec3vfx n = zero;
+ if (unlikely(Nx != nullptr)) n = normalize_safe(patch->patch.normal(lu,lv));
+ const vfloatx u = vfloatx(ix)*rcp_swidth;
+ const vfloatx v = vfloatx(iy)*rcp_sheight;
+ const vintx ofs = (iy-y0)*dwidth+(ix-x0);
+ if (likely(all(valid)) && all(iy==iy[0])) {
+ const unsigned ofs2 = ofs[0];
+ vfloatx::storeu(Px+ofs2,p.x);
+ vfloatx::storeu(Py+ofs2,p.y);
+ vfloatx::storeu(Pz+ofs2,p.z);
+ vfloatx::storeu(U+ofs2,u);
+ vfloatx::storeu(V+ofs2,v);
+ if (unlikely(Nx != nullptr)) {
+ vfloatx::storeu(Nx+ofs2,n.x);
+ vfloatx::storeu(Ny+ofs2,n.y);
+ vfloatx::storeu(Nz+ofs2,n.z);
+ }
+ } else {
+ foreach_unique_index(valid,iy,[&](const vboolx& valid, const int iy0, const int j) {
+ const unsigned ofs2 = ofs[j]-j;
+ vfloatx::storeu(valid,Px+ofs2,p.x);
+ vfloatx::storeu(valid,Py+ofs2,p.y);
+ vfloatx::storeu(valid,Pz+ofs2,p.z);
+ vfloatx::storeu(valid,U+ofs2,u);
+ vfloatx::storeu(valid,V+ofs2,v);
+ if (unlikely(Nx != nullptr)) {
+ vfloatx::storeu(valid,Nx+ofs2,n.x);
+ vfloatx::storeu(valid,Ny+ofs2,n.y);
+ vfloatx::storeu(valid,Nz+ofs2,n.z);
+ }
+ });
+ }
+ });
+#endif
+ }
+
+ bool eval(Ref This, const BBox2f& srange, const BBox2f& erange, const unsigned depth)
+ {
+ if (erange.empty())
+ return true;
+
+ const int lx0 = (int) ceilf(erange.lower.x);
+ const int lx1 = (int) ceilf(erange.upper.x) + (erange.upper.x == x1 && (srange.lower.x < erange.upper.x || erange.upper.x == 0));
+ const int ly0 = (int) ceilf(erange.lower.y);
+ const int ly1 = (int) ceilf(erange.upper.y) + (erange.upper.y == y1 && (srange.lower.y < erange.upper.y || erange.upper.y == 0));
+ if (lx0 >= lx1 || ly0 >= ly1)
+ return true;
+
+ if (!This)
+ return false;
+
+ switch (This.type())
+ {
+ case Patch::BILINEAR_PATCH: {
+ evalLocalGrid((Patch::BilinearPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
+ return true;
+ }
+ case Patch::BSPLINE_PATCH: {
+ evalLocalGrid((Patch::BSplinePatch*)This.object(),srange,lx0,lx1,ly0,ly1);
+ return true;
+ }
+ case Patch::BEZIER_PATCH: {
+ evalLocalGrid((Patch::BezierPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
+ return true;
+ }
+ case Patch::GREGORY_PATCH: {
+ evalLocalGrid((Patch::GregoryPatch*)This.object(),srange,lx0,lx1,ly0,ly1);
+ return true;
+ }
+ case Patch::SUBDIVIDED_QUAD_PATCH:
+ {
+ const Vec2f c = srange.center();
+ const BBox2f srange0(srange.lower,c);
+ const BBox2f srange1(Vec2f(c.x,srange.lower.y),Vec2f(srange.upper.x,c.y));
+ const BBox2f srange2(c,srange.upper);
+ const BBox2f srange3(Vec2f(srange.lower.x,c.y),Vec2f(c.x,srange.upper.y));
+
+ Patch::SubdividedQuadPatch* patch = (Patch::SubdividedQuadPatch*)This.object();
+ eval(patch->child[0],srange0,intersect(srange0,erange),depth+1);
+ eval(patch->child[1],srange1,intersect(srange1,erange),depth+1);
+ eval(patch->child[2],srange2,intersect(srange2,erange),depth+1);
+ eval(patch->child[3],srange3,intersect(srange3,erange),depth+1);
+ return true;
+ }
+ case Patch::EVAL_PATCH: {
+ CatmullClarkPatch patch; patch.deserialize(This.object());
+ FeatureAdaptiveEvalGrid(patch,srange,erange,depth,x0,x1,y0,y1,swidth,sheight,Px,Py,Pz,U,V,Nx,Ny,Nz,dwidth,dheight);
+ count += (lx1-lx0)*(ly1-ly0);
+ return true;
+ }
+ default:
+ assert(false);
+ return false;
+ }
+ }
+
+ bool eval(Ref This, unsigned subPatch, const BBox2f& srange, const BBox2f& erange)
+ {
+ if (!This)
+ return false;
+
+ switch (This.type())
+ {
+ case Patch::SUBDIVIDED_GENERAL_PATCH: {
+ Patch::SubdividedGeneralPatch* patch = (Patch::SubdividedGeneralPatch*)This.object();
+ assert(subPatch < patch->N);
+ return eval(patch->child[subPatch],srange,erange,1);
+ }
+ default:
+ assert(subPatch == 0);
+ return eval(This,srange,erange,0);
+ }
+ }
+ };
+
+ __forceinline unsigned patch_eval_subdivision_count (const HalfEdge* h)
+ {
+ const unsigned N = h->numEdges();
+ if (N == 4) return 1;
+ else return N;
+ }
+
+ template<typename Tessellator>
+ inline void patch_eval_subdivision (const HalfEdge* h, Tessellator tessellator)
+ {
+ const unsigned N = h->numEdges();
+ int neighborSubdiv[GeneralCatmullClarkPatch3fa::SIZE]; // FIXME: use array_t
+ float levels[GeneralCatmullClarkPatch3fa::SIZE];
+ for (unsigned i=0; i<N; i++) {
+ assert(i<GeneralCatmullClarkPatch3fa::SIZE);
+ neighborSubdiv[i] = h->hasOpposite() ? h->opposite()->numEdges() != 4 : 0;
+ levels[i] = h->edge_level;
+ h = h->next();
+ }
+ if (N == 4)
+ {
+ const Vec2f uv[4] = { Vec2f(0.0f,0.0f), Vec2f(1.0f,0.0f), Vec2f(1.0f,1.0f), Vec2f(0.0f,1.0f) };
+ tessellator(uv,neighborSubdiv,levels,0);
+ }
+ else
+ {
+ for (unsigned i=0; i<N; i++)
+ {
+ assert(i<MAX_PATCH_VALENCE);
+ static_assert(MAX_PATCH_VALENCE <= 16, "MAX_PATCH_VALENCE > 16");
+ const int h = (i >> 2) & 3, l = i & 3;
+ const Vec2f subPatchID((float)l,(float)h);
+ const Vec2f uv[4] = { 2.0f*subPatchID + (0.5f+Vec2f(0.0f,0.0f)),
+ 2.0f*subPatchID + (0.5f+Vec2f(1.0f,0.0f)),
+ 2.0f*subPatchID + (0.5f+Vec2f(1.0f,1.0f)),
+ 2.0f*subPatchID + (0.5f+Vec2f(0.0f,1.0f)) };
+ const int neighborSubdiv1[4] = { 0,0,0,0 };
+ const float levels1[4] = { 0.5f*levels[(i+0)%N], 0.5f*levels[(i+0)%N], 0.5f*levels[(i+N-1)%N], 0.5f*levels[(i+N-1)%N] };
+ tessellator(uv,neighborSubdiv1,levels1,i);
+ }
+ }
+ }
+ }
+}
+
diff --git a/thirdparty/embree/kernels/subdiv/patch_eval_simd.h b/thirdparty/embree/kernels/subdiv/patch_eval_simd.h
new file mode 100644
index 0000000000..fef88a4492
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/patch_eval_simd.h
@@ -0,0 +1,127 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "patch.h"
+#include "feature_adaptive_eval_simd.h"
+
+namespace embree
+{
+ namespace isa
+ {
+ template<typename vbool, typename vint, typename vfloat, typename Vertex, typename Vertex_t = Vertex>
+ struct PatchEvalSimd
+ {
+ public:
+
+ typedef PatchT<Vertex,Vertex_t> Patch;
+ typedef typename Patch::Ref Ref;
+ typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
+
+ PatchEvalSimd (SharedLazyTessellationCache::CacheEntry& entry, size_t commitCounter,
+ const HalfEdge* edge, const char* vertices, size_t stride, const vbool& valid0, const vfloat& u, const vfloat& v,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, const size_t dstride, const size_t N)
+ : P(P), dPdu(dPdu), dPdv(dPdv), ddPdudu(ddPdudu), ddPdvdv(ddPdvdv), ddPdudv(ddPdudv), dstride(dstride), N(N)
+ {
+ /* conservative time for the very first allocation */
+ auto time = SharedLazyTessellationCache::sharedLazyTessellationCache.getTime(commitCounter);
+
+ Ref patch = SharedLazyTessellationCache::lookup(entry,commitCounter,[&] () {
+ auto alloc = [](size_t bytes) { return SharedLazyTessellationCache::malloc(bytes); };
+ return Patch::create(alloc,edge,vertices,stride);
+ }, true);
+
+ auto curTime = SharedLazyTessellationCache::sharedLazyTessellationCache.getTime(commitCounter);
+ const bool allAllocationsValid = SharedLazyTessellationCache::validTime(time,curTime);
+
+ patch = allAllocationsValid ? patch : nullptr;
+
+ /* use cached data structure for calculations */
+ const vbool valid1 = patch ? eval(valid0,patch,u,v,1.0f,0) : vbool(false);
+ SharedLazyTessellationCache::unlock();
+ const vbool valid2 = valid0 & !valid1;
+ if (any(valid2)) {
+ FeatureAdaptiveEvalSimd<vbool,vint,vfloat,Vertex,Vertex_t>(edge,vertices,stride,valid2,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dstride,N);
+ }
+ }
+
+ vbool eval_quad(const vbool& valid, const typename Patch::SubdividedQuadPatch* This, const vfloat& u, const vfloat& v, const float dscale, const size_t depth)
+ {
+ vbool ret = false;
+ const vbool u0_mask = u < 0.5f, u1_mask = u >= 0.5f;
+ const vbool v0_mask = v < 0.5f, v1_mask = v >= 0.5f;
+ const vbool u0v0_mask = valid & u0_mask & v0_mask;
+ const vbool u0v1_mask = valid & u0_mask & v1_mask;
+ const vbool u1v0_mask = valid & u1_mask & v0_mask;
+ const vbool u1v1_mask = valid & u1_mask & v1_mask;
+ if (any(u0v0_mask)) ret |= eval(u0v0_mask,This->child[0],2.0f*u,2.0f*v,2.0f*dscale,depth+1);
+ if (any(u1v0_mask)) ret |= eval(u1v0_mask,This->child[1],2.0f*u-1.0f,2.0f*v,2.0f*dscale,depth+1);
+ if (any(u1v1_mask)) ret |= eval(u1v1_mask,This->child[2],2.0f*u-1.0f,2.0f*v-1.0f,2.0f*dscale,depth+1);
+ if (any(u0v1_mask)) ret |= eval(u0v1_mask,This->child[3],2.0f*u,2.0f*v-1.0f,2.0f*dscale,depth+1);
+ return ret;
+ }
+
+ vbool eval_general(const vbool& valid, const typename Patch::SubdividedGeneralPatch* patch, const vfloat& U, const vfloat& V, const size_t depth)
+ {
+ vbool ret = false;
+ const vint l = (vint)floor(0.5f*U); const vfloat u = 2.0f*frac(0.5f*U)-0.5f;
+ const vint h = (vint)floor(0.5f*V); const vfloat v = 2.0f*frac(0.5f*V)-0.5f;
+ const vint i = (h<<2)+l; assert(all(valid,i<patch->N));
+ foreach_unique(valid,i,[&](const vbool& valid, const int i) {
+ ret |= eval(valid,patch->child[i],u,v,1.0f,depth+1);
+ });
+ return ret;
+ }
+
+ vbool eval(const vbool& valid, Ref This, const vfloat& u, const vfloat& v, const float dscale, const size_t depth)
+ {
+ if (!This) return false;
+ switch (This.type())
+ {
+ case Patch::BILINEAR_PATCH: {
+ ((typename Patch::BilinearPatch*)This.object())->patch.eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ return valid;
+ }
+ case Patch::BSPLINE_PATCH: {
+ ((typename Patch::BSplinePatch*)This.object())->patch.eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ return valid;
+ }
+ case Patch::BEZIER_PATCH: {
+ ((typename Patch::BezierPatch*)This.object())->patch.eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ return valid;
+ }
+ case Patch::GREGORY_PATCH: {
+ ((typename Patch::GregoryPatch*)This.object())->patch.eval(valid,u,v,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dscale,dstride,N);
+ return valid;
+ }
+ case Patch::SUBDIVIDED_QUAD_PATCH: {
+ return eval_quad(valid,((typename Patch::SubdividedQuadPatch*)This.object()),u,v,dscale,depth);
+ }
+ case Patch::SUBDIVIDED_GENERAL_PATCH: {
+ assert(dscale == 1.0f);
+ return eval_general(valid,((typename Patch::SubdividedGeneralPatch*)This.object()),u,v,depth);
+ }
+ case Patch::EVAL_PATCH: {
+ CatmullClarkPatch patch; patch.deserialize(This.object());
+ FeatureAdaptiveEvalSimd<vbool,vint,vfloat,Vertex,Vertex_t>(patch,valid,u,v,dscale,depth,P,dPdu,dPdv,ddPdudu,ddPdvdv,ddPdudv,dstride,N);
+ return valid;
+ }
+ default:
+ assert(false);
+ return false;
+ }
+ }
+
+ private:
+ float* const P;
+ float* const dPdu;
+ float* const dPdv;
+ float* const ddPdudu;
+ float* const ddPdvdv;
+ float* const ddPdudv;
+ const size_t dstride;
+ const size_t N;
+ };
+ }
+}
diff --git a/thirdparty/embree/kernels/subdiv/subdivpatch1base.h b/thirdparty/embree/kernels/subdiv/subdivpatch1base.h
new file mode 100644
index 0000000000..c3069dadee
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/subdivpatch1base.h
@@ -0,0 +1,156 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../geometry/primitive.h"
+#include "bspline_patch.h"
+#include "bezier_patch.h"
+#include "gregory_patch.h"
+#include "gregory_patch_dense.h"
+#include "tessellation.h"
+#include "tessellation_cache.h"
+#include "gridrange.h"
+#include "patch_eval_grid.h"
+#include "feature_adaptive_eval_grid.h"
+#include "../common/scene_subdiv_mesh.h"
+
+namespace embree
+{
+ struct __aligned(64) SubdivPatch1Base
+ {
+ public:
+
+ enum Type {
+ INVALID_PATCH = 0,
+ BSPLINE_PATCH = 1,
+ BEZIER_PATCH = 2,
+ GREGORY_PATCH = 3,
+ EVAL_PATCH = 5,
+ BILINEAR_PATCH = 6,
+ };
+
+ enum Flags {
+ TRANSITION_PATCH = 16,
+ };
+
+ /*! Default constructor. */
+ __forceinline SubdivPatch1Base () {}
+
+ SubdivPatch1Base (const unsigned int gID,
+ const unsigned int pID,
+ const unsigned int subPatch,
+ const SubdivMesh *const mesh,
+ const size_t time,
+ const Vec2f uv[4],
+ const float edge_level[4],
+ const int subdiv[4],
+ const int simd_width);
+
+ __forceinline bool needsStitching() const {
+ return flags & TRANSITION_PATCH;
+ }
+
+ __forceinline Vec2f getUV(const size_t i) const {
+ return Vec2f((float)u[i],(float)v[i]) * (8.0f/0x10000);
+ }
+
+ static void computeEdgeLevels(const float edge_level[4], const int subdiv[4], float level[4]);
+ static Vec2i computeGridSize(const float level[4]);
+ bool updateEdgeLevels(const float edge_level[4], const int subdiv[4], const SubdivMesh *const mesh, const int simd_width);
+
+ public:
+
+ __forceinline size_t getGridBytes() const {
+ const size_t grid_size_xyzuv = (grid_size_simd_blocks * VSIZEX) * 4;
+ return 64*((grid_size_xyzuv+15) / 16);
+ }
+
+ __forceinline void write_lock() { mtx.lock(); }
+ __forceinline void write_unlock() { mtx.unlock(); }
+ __forceinline bool try_write_lock() { return mtx.try_lock(); }
+ //__forceinline bool try_read_lock() { return mtx.try_read_lock(); }
+
+ __forceinline void resetRootRef() {
+ //assert( mtx.hasInitialState() );
+ root_ref = SharedLazyTessellationCache::Tag();
+ }
+
+ __forceinline SharedLazyTessellationCache::CacheEntry& entry() {
+ return (SharedLazyTessellationCache::CacheEntry&) root_ref;
+ }
+
+ public:
+ __forceinline unsigned int geomID() const {
+ return geom;
+ }
+
+ __forceinline unsigned int primID() const {
+ return prim;
+ }
+
+ public:
+ SharedLazyTessellationCache::Tag root_ref;
+ SpinLock mtx;
+
+ unsigned short u[4]; //!< 16bit discretized u,v coordinates
+ unsigned short v[4];
+ float level[4];
+
+ unsigned char flags;
+ unsigned char type;
+ unsigned short grid_u_res;
+ unsigned int geom; //!< geometry ID of the subdivision mesh this patch belongs to
+ unsigned int prim; //!< primitive ID of this subdivision patch
+ unsigned short grid_v_res;
+
+ unsigned short grid_size_simd_blocks;
+ unsigned int time_;
+
+ struct PatchHalfEdge {
+ const HalfEdge* edge;
+ unsigned subPatch;
+ };
+
+ Vec3fa patch_v[4][4];
+
+ const HalfEdge *edge() const { return ((PatchHalfEdge*)patch_v)->edge; }
+ unsigned time() const { return time_; }
+ unsigned subPatch() const { return ((PatchHalfEdge*)patch_v)->subPatch; }
+
+ void set_edge(const HalfEdge *h) const { ((PatchHalfEdge*)patch_v)->edge = h; }
+ void set_subPatch(const unsigned s) const { ((PatchHalfEdge*)patch_v)->subPatch = s; }
+ };
+
+ namespace isa
+ {
+ Vec3fa patchEval(const SubdivPatch1Base& patch, const float uu, const float vv);
+ Vec3fa patchNormal(const SubdivPatch1Base& patch, const float uu, const float vv);
+
+ template<typename simdf>
+ Vec3<simdf> patchEval(const SubdivPatch1Base& patch, const simdf& uu, const simdf& vv);
+
+ template<typename simdf>
+ Vec3<simdf> patchNormal(const SubdivPatch1Base& patch, const simdf& uu, const simdf& vv);
+
+
+ /* eval grid over patch and stich edges when required */
+ void evalGrid(const SubdivPatch1Base& patch,
+ const unsigned x0, const unsigned x1,
+ const unsigned y0, const unsigned y1,
+ const unsigned swidth, const unsigned sheight,
+ float *__restrict__ const grid_x,
+ float *__restrict__ const grid_y,
+ float *__restrict__ const grid_z,
+ float *__restrict__ const grid_u,
+ float *__restrict__ const grid_v,
+ const SubdivMesh* const geom);
+
+ /* eval grid over patch and stich edges when required */
+ BBox3fa evalGridBounds(const SubdivPatch1Base& patch,
+ const unsigned x0, const unsigned x1,
+ const unsigned y0, const unsigned y1,
+ const unsigned swidth, const unsigned sheight,
+ const SubdivMesh* const geom);
+ }
+}
diff --git a/thirdparty/embree/kernels/subdiv/tessellation.h b/thirdparty/embree/kernels/subdiv/tessellation.h
new file mode 100644
index 0000000000..abde4f2bde
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/tessellation.h
@@ -0,0 +1,161 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace embree
+{
+ /* adjust discret tessellation level for feature-adaptive pre-subdivision */
+ __forceinline float adjustTessellationLevel(float l, const size_t sublevel)
+ {
+ for (size_t i=0; i<sublevel; i++) l *= 0.5f;
+ float r = ceilf(l);
+ for (size_t i=0; i<sublevel; i++) r *= 2.0f;
+ return r;
+ }
+
+ __forceinline int stitch(const int x, const int fine, const int coarse) {
+ return (2*x+1)*coarse/(2*fine);
+ }
+
+ __forceinline void stitchGridEdges(const unsigned int low_rate,
+ const unsigned int high_rate,
+ const unsigned int x0,
+ const unsigned int x1,
+ float * __restrict__ const uv_array,
+ const unsigned int uv_array_step)
+ {
+#if 1
+ const float inv_low_rate = rcp((float)(low_rate-1));
+ for (unsigned x=x0; x<=x1; x++) {
+ uv_array[(x-x0)*uv_array_step] = float(stitch(x,high_rate-1,low_rate-1))*inv_low_rate;
+ }
+ if (unlikely(x1 == high_rate-1))
+ uv_array[(x1-x0)*uv_array_step] = 1.0f;
+#else
+ assert(low_rate < high_rate);
+ assert(high_rate >= 2);
+
+ const float inv_low_rate = rcp((float)(low_rate-1));
+ const unsigned int dy = low_rate - 1;
+ const unsigned int dx = high_rate - 1;
+
+ int p = 2*dy-dx;
+
+ unsigned int offset = 0;
+ unsigned int y = 0;
+ float value = 0.0f;
+ for(unsigned int x=0;x<high_rate-1; x++) // '<=' would be correct but we will leave the 1.0f at the end
+ {
+ uv_array[offset] = value;
+
+ offset += uv_array_step;
+ if (unlikely(p > 0))
+ {
+ y++;
+ value = (float)y * inv_low_rate;
+ p -= 2*dx;
+ }
+ p += 2*dy;
+ }
+#endif
+ }
+
+ __forceinline void stitchUVGrid(const float edge_levels[4],
+ const unsigned int swidth,
+ const unsigned int sheight,
+ const unsigned int x0,
+ const unsigned int y0,
+ const unsigned int grid_u_res,
+ const unsigned int grid_v_res,
+ float * __restrict__ const u_array,
+ float * __restrict__ const v_array)
+ {
+ const unsigned int x1 = x0+grid_u_res-1;
+ const unsigned int y1 = y0+grid_v_res-1;
+ const unsigned int int_edge_points0 = (unsigned int)edge_levels[0] + 1;
+ const unsigned int int_edge_points1 = (unsigned int)edge_levels[1] + 1;
+ const unsigned int int_edge_points2 = (unsigned int)edge_levels[2] + 1;
+ const unsigned int int_edge_points3 = (unsigned int)edge_levels[3] + 1;
+
+ if (unlikely(y0 == 0 && int_edge_points0 < swidth))
+ stitchGridEdges(int_edge_points0,swidth,x0,x1,u_array,1);
+
+ if (unlikely(y1 == sheight-1 && int_edge_points2 < swidth))
+ stitchGridEdges(int_edge_points2,swidth,x0,x1,&u_array[(grid_v_res-1)*grid_u_res],1);
+
+ if (unlikely(x0 == 0 && int_edge_points1 < sheight))
+ stitchGridEdges(int_edge_points1,sheight,y0,y1,&v_array[grid_u_res-1],grid_u_res);
+
+ if (unlikely(x1 == swidth-1 && int_edge_points3 < sheight))
+ stitchGridEdges(int_edge_points3,sheight,y0,y1,v_array,grid_u_res);
+ }
+
+ __forceinline void gridUVTessellator(const float edge_levels[4],
+ const unsigned int swidth,
+ const unsigned int sheight,
+ const unsigned int x0,
+ const unsigned int y0,
+ const unsigned int grid_u_res,
+ const unsigned int grid_v_res,
+ float * __restrict__ const u_array,
+ float * __restrict__ const v_array)
+ {
+ assert( grid_u_res >= 1);
+ assert( grid_v_res >= 1);
+ assert( edge_levels[0] >= 1.0f );
+ assert( edge_levels[1] >= 1.0f );
+ assert( edge_levels[2] >= 1.0f );
+ assert( edge_levels[3] >= 1.0f );
+
+#if defined(__AVX__)
+ const vint8 grid_u_segments = vint8(swidth)-1;
+ const vint8 grid_v_segments = vint8(sheight)-1;
+
+ const vfloat8 inv_grid_u_segments = rcp(vfloat8(grid_u_segments));
+ const vfloat8 inv_grid_v_segments = rcp(vfloat8(grid_v_segments));
+
+ unsigned int index = 0;
+ vint8 v_i( zero );
+ for (unsigned int y=0;y<grid_v_res;y++,index+=grid_u_res,v_i += 1)
+ {
+ vint8 u_i ( step );
+
+ const vbool8 m_v = v_i < grid_v_segments;
+
+ for (unsigned int x=0;x<grid_u_res;x+=8, u_i += 8)
+ {
+ const vbool8 m_u = u_i < grid_u_segments;
+ const vfloat8 u = select(m_u, vfloat8(x0+u_i) * inv_grid_u_segments, 1.0f);
+ const vfloat8 v = select(m_v, vfloat8(y0+v_i) * inv_grid_v_segments, 1.0f);
+ vfloat8::storeu(&u_array[index + x],u);
+ vfloat8::storeu(&v_array[index + x],v);
+ }
+ }
+ #else
+ const vint4 grid_u_segments = vint4(swidth)-1;
+ const vint4 grid_v_segments = vint4(sheight)-1;
+
+ const vfloat4 inv_grid_u_segments = rcp(vfloat4(grid_u_segments));
+ const vfloat4 inv_grid_v_segments = rcp(vfloat4(grid_v_segments));
+
+ unsigned int index = 0;
+ vint4 v_i( zero );
+ for (unsigned int y=0;y<grid_v_res;y++,index+=grid_u_res,v_i += 1)
+ {
+ vint4 u_i ( step );
+
+ const vbool4 m_v = v_i < grid_v_segments;
+
+ for (unsigned int x=0;x<grid_u_res;x+=4, u_i += 4)
+ {
+ const vbool4 m_u = u_i < grid_u_segments;
+ const vfloat4 u = select(m_u, vfloat4(x0+u_i) * inv_grid_u_segments, 1.0f);
+ const vfloat4 v = select(m_v, vfloat4(y0+v_i) * inv_grid_v_segments, 1.0f);
+ vfloat4::storeu(&u_array[index + x],u);
+ vfloat4::storeu(&v_array[index + x],v);
+ }
+ }
+#endif
+ }
+}
diff --git a/thirdparty/embree/kernels/subdiv/tessellation_cache.h b/thirdparty/embree/kernels/subdiv/tessellation_cache.h
new file mode 100644
index 0000000000..99edf49be4
--- /dev/null
+++ b/thirdparty/embree/kernels/subdiv/tessellation_cache.h
@@ -0,0 +1,325 @@
+// Copyright 2009-2021 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "../common/default.h"
+
+/* force a complete cache invalidation when running out of allocation space */
+#define FORCE_SIMPLE_FLUSH 0
+
+#define THREAD_BLOCK_ATOMIC_ADD 4
+
+#if defined(DEBUG)
+#define CACHE_STATS(x)
+#else
+#define CACHE_STATS(x)
+#endif
+
+namespace embree
+{
+ class SharedTessellationCacheStats
+ {
+ public:
+ /* stats */
+ static std::atomic<size_t> cache_accesses;
+ static std::atomic<size_t> cache_hits;
+ static std::atomic<size_t> cache_misses;
+ static std::atomic<size_t> cache_flushes;
+ static size_t cache_num_patches;
+ __aligned(64) static SpinLock mtx;
+
+ /* print stats for debugging */
+ static void printStats();
+ static void clearStats();
+ };
+
+ void resizeTessellationCache(size_t new_size);
+ void resetTessellationCache();
+
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct __aligned(64) ThreadWorkState
+ {
+ ALIGNED_STRUCT_(64);
+
+ std::atomic<size_t> counter;
+ ThreadWorkState* next;
+ bool allocated;
+
+ __forceinline ThreadWorkState(bool allocated = false)
+ : counter(0), next(nullptr), allocated(allocated)
+ {
+ assert( ((size_t)this % 64) == 0 );
+ }
+ };
+
+ class __aligned(64) SharedLazyTessellationCache
+ {
+ public:
+
+ static const size_t NUM_CACHE_SEGMENTS = 8;
+ static const size_t NUM_PREALLOC_THREAD_WORK_STATES = 512;
+ static const size_t COMMIT_INDEX_SHIFT = 32+8;
+#if defined(__64BIT__)
+ static const size_t REF_TAG_MASK = 0xffffffffff;
+#else
+ static const size_t REF_TAG_MASK = 0x7FFFFFFF;
+#endif
+ static const size_t MAX_TESSELLATION_CACHE_SIZE = REF_TAG_MASK+1;
+ static const size_t BLOCK_SIZE = 64;
+
+
+ /*! Per thread tessellation ref cache */
+ static __thread ThreadWorkState* init_t_state;
+ static ThreadWorkState* current_t_state;
+
+ static __forceinline ThreadWorkState *threadState()
+ {
+ if (unlikely(!init_t_state))
+ /* sets init_t_state, can't return pointer due to macosx icc bug*/
+ SharedLazyTessellationCache::sharedLazyTessellationCache.getNextRenderThreadWorkState();
+ return init_t_state;
+ }
+
+ struct Tag
+ {
+ __forceinline Tag() : data(0) {}
+
+ __forceinline Tag(void* ptr, size_t combinedTime) {
+ init(ptr,combinedTime);
+ }
+
+ __forceinline Tag(size_t ptr, size_t combinedTime) {
+ init((void*)ptr,combinedTime);
+ }
+
+ __forceinline void init(void* ptr, size_t combinedTime)
+ {
+ if (ptr == nullptr) {
+ data = 0;
+ return;
+ }
+ int64_t new_root_ref = (int64_t) ptr;
+ new_root_ref -= (int64_t)SharedLazyTessellationCache::sharedLazyTessellationCache.getDataPtr();
+ assert( new_root_ref <= (int64_t)REF_TAG_MASK );
+ new_root_ref |= (int64_t)combinedTime << COMMIT_INDEX_SHIFT;
+ data = new_root_ref;
+ }
+
+ __forceinline int64_t get() const { return data.load(); }
+ __forceinline void set( int64_t v ) { data.store(v); }
+ __forceinline void reset() { data.store(0); }
+
+ private:
+ atomic<int64_t> data;
+ };
+
+ static __forceinline size_t extractCommitIndex(const int64_t v) { return v >> SharedLazyTessellationCache::COMMIT_INDEX_SHIFT; }
+
+ struct CacheEntry
+ {
+ Tag tag;
+ SpinLock mutex;
+ };
+
+ private:
+
+ float *data;
+ bool hugepages;
+ size_t size;
+ size_t maxBlocks;
+ ThreadWorkState *threadWorkState;
+
+ __aligned(64) std::atomic<size_t> localTime;
+ __aligned(64) std::atomic<size_t> next_block;
+ __aligned(64) SpinLock reset_state;
+ __aligned(64) SpinLock linkedlist_mtx;
+ __aligned(64) std::atomic<size_t> switch_block_threshold;
+ __aligned(64) std::atomic<size_t> numRenderThreads;
+
+
+ public:
+
+
+ SharedLazyTessellationCache();
+ ~SharedLazyTessellationCache();
+
+ void getNextRenderThreadWorkState();
+
+ __forceinline size_t maxAllocSize() const {
+ return switch_block_threshold;
+ }
+
+ __forceinline size_t getCurrentIndex() { return localTime.load(); }
+ __forceinline void addCurrentIndex(const size_t i=1) { localTime.fetch_add(i); }
+
+ __forceinline size_t getTime(const size_t globalTime) {
+ return localTime.load()+NUM_CACHE_SEGMENTS*globalTime;
+ }
+
+
+ __forceinline size_t lockThread (ThreadWorkState *const t_state, const ssize_t plus=1) { return t_state->counter.fetch_add(plus); }
+ __forceinline size_t unlockThread(ThreadWorkState *const t_state, const ssize_t plus=-1) { assert(isLocked(t_state)); return t_state->counter.fetch_add(plus); }
+
+ __forceinline bool isLocked(ThreadWorkState *const t_state) { return t_state->counter.load() != 0; }
+
+ static __forceinline void lock () { sharedLazyTessellationCache.lockThread(threadState()); }
+ static __forceinline void unlock() { sharedLazyTessellationCache.unlockThread(threadState()); }
+ static __forceinline bool isLocked() { return sharedLazyTessellationCache.isLocked(threadState()); }
+ static __forceinline size_t getState() { return threadState()->counter.load(); }
+ static __forceinline void lockThreadLoop() { sharedLazyTessellationCache.lockThreadLoop(threadState()); }
+
+ static __forceinline size_t getTCacheTime(const size_t globalTime) {
+ return sharedLazyTessellationCache.getTime(globalTime);
+ }
+
+ /* per thread lock */
+ __forceinline void lockThreadLoop (ThreadWorkState *const t_state)
+ {
+ while(1)
+ {
+ size_t lock = SharedLazyTessellationCache::sharedLazyTessellationCache.lockThread(t_state,1);
+ if (unlikely(lock >= THREAD_BLOCK_ATOMIC_ADD))
+ {
+ /* lock failed wait until sync phase is over */
+ sharedLazyTessellationCache.unlockThread(t_state,-1);
+ sharedLazyTessellationCache.waitForUsersLessEqual(t_state,0);
+ }
+ else
+ break;
+ }
+ }
+
+ static __forceinline void* lookup(CacheEntry& entry, size_t globalTime)
+ {
+ const int64_t subdiv_patch_root_ref = entry.tag.get();
+ CACHE_STATS(SharedTessellationCacheStats::cache_accesses++);
+
+ if (likely(subdiv_patch_root_ref != 0))
+ {
+ const size_t subdiv_patch_root = (subdiv_patch_root_ref & REF_TAG_MASK) + (size_t)sharedLazyTessellationCache.getDataPtr();
+ const size_t subdiv_patch_cache_index = extractCommitIndex(subdiv_patch_root_ref);
+
+ if (likely( sharedLazyTessellationCache.validCacheIndex(subdiv_patch_cache_index,globalTime) ))
+ {
+ CACHE_STATS(SharedTessellationCacheStats::cache_hits++);
+ return (void*) subdiv_patch_root;
+ }
+ }
+ CACHE_STATS(SharedTessellationCacheStats::cache_misses++);
+ return nullptr;
+ }
+
+ template<typename Constructor>
+ static __forceinline auto lookup (CacheEntry& entry, size_t globalTime, const Constructor constructor, const bool before=false) -> decltype(constructor())
+ {
+ ThreadWorkState *t_state = SharedLazyTessellationCache::threadState();
+
+ while (true)
+ {
+ sharedLazyTessellationCache.lockThreadLoop(t_state);
+ void* patch = SharedLazyTessellationCache::lookup(entry,globalTime);
+ if (patch) return (decltype(constructor())) patch;
+
+ if (entry.mutex.try_lock())
+ {
+ if (!validTag(entry.tag,globalTime))
+ {
+ auto timeBefore = sharedLazyTessellationCache.getTime(globalTime);
+ auto ret = constructor(); // thread is locked here!
+ assert(ret);
+ /* this should never return nullptr */
+ auto timeAfter = sharedLazyTessellationCache.getTime(globalTime);
+ auto time = before ? timeBefore : timeAfter;
+ __memory_barrier();
+ entry.tag = SharedLazyTessellationCache::Tag(ret,time);
+ __memory_barrier();
+ entry.mutex.unlock();
+ return ret;
+ }
+ entry.mutex.unlock();
+ }
+ SharedLazyTessellationCache::sharedLazyTessellationCache.unlockThread(t_state);
+ }
+ }
+
+ __forceinline bool validCacheIndex(const size_t i, const size_t globalTime)
+ {
+#if FORCE_SIMPLE_FLUSH == 1
+ return i == getTime(globalTime);
+#else
+ return i+(NUM_CACHE_SEGMENTS-1) >= getTime(globalTime);
+#endif
+ }
+
+ static __forceinline bool validTime(const size_t oldtime, const size_t newTime)
+ {
+ return oldtime+(NUM_CACHE_SEGMENTS-1) >= newTime;
+ }
+
+
+ static __forceinline bool validTag(const Tag& tag, size_t globalTime)
+ {
+ const int64_t subdiv_patch_root_ref = tag.get();
+ if (subdiv_patch_root_ref == 0) return false;
+ const size_t subdiv_patch_cache_index = extractCommitIndex(subdiv_patch_root_ref);
+ return sharedLazyTessellationCache.validCacheIndex(subdiv_patch_cache_index,globalTime);
+ }
+
+ void waitForUsersLessEqual(ThreadWorkState *const t_state,
+ const unsigned int users);
+
+ __forceinline size_t alloc(const size_t blocks)
+ {
+ if (unlikely(blocks >= switch_block_threshold))
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION,"allocation exceeds size of tessellation cache segment");
+
+ assert(blocks < switch_block_threshold);
+ size_t index = next_block.fetch_add(blocks);
+ if (unlikely(index + blocks >= switch_block_threshold)) return (size_t)-1;
+ return index;
+ }
+
+ static __forceinline void* malloc(const size_t bytes)
+ {
+ size_t block_index = -1;
+ ThreadWorkState *const t_state = threadState();
+ while (true)
+ {
+ block_index = sharedLazyTessellationCache.alloc((bytes+BLOCK_SIZE-1)/BLOCK_SIZE);
+ if (block_index == (size_t)-1)
+ {
+ sharedLazyTessellationCache.unlockThread(t_state);
+ sharedLazyTessellationCache.allocNextSegment();
+ sharedLazyTessellationCache.lockThread(t_state);
+ continue;
+ }
+ break;
+ }
+ return sharedLazyTessellationCache.getBlockPtr(block_index);
+ }
+
+ __forceinline void *getBlockPtr(const size_t block_index)
+ {
+ assert(block_index < maxBlocks);
+ assert(data);
+ assert(block_index*16 <= size);
+ return (void*)&data[block_index*16];
+ }
+
+ __forceinline void* getDataPtr() { return data; }
+ __forceinline size_t getNumUsedBytes() { return next_block * BLOCK_SIZE; }
+ __forceinline size_t getMaxBlocks() { return maxBlocks; }
+ __forceinline size_t getSize() { return size; }
+
+ void allocNextSegment();
+ void realloc(const size_t newSize);
+
+ void reset();
+
+ static SharedLazyTessellationCache sharedLazyTessellationCache;
+ };
+}
diff --git a/thirdparty/embree/patches/godot-changes-android.patch b/thirdparty/embree/patches/godot-changes-android.patch
new file mode 100644
index 0000000000..a27f924bde
--- /dev/null
+++ b/thirdparty/embree/patches/godot-changes-android.patch
@@ -0,0 +1,103 @@
+diff --git a/thirdparty/embree/common/sys/sysinfo.cpp b/thirdparty/embree/common/sys/sysinfo.cpp
+index ba97dc227b..1679599608 100644
+--- a/thirdparty/embree/common/sys/sysinfo.cpp
++++ b/thirdparty/embree/common/sys/sysinfo.cpp
+@@ -618,7 +618,10 @@ namespace embree
+ static int nThreads = -1;
+ if (nThreads != -1) return nThreads;
+
+-#if defined(__MACOSX__)
++// -- GODOT start --
++// #if defined(__MACOSX__)
++#if defined(__MACOSX__) || defined(__ANDROID__)
++// -- GODOT end --
+ nThreads = sysconf(_SC_NPROCESSORS_ONLN); // does not work in Linux LXC container
+ assert(nThreads);
+ #else
+diff --git a/thirdparty/embree/common/sys/thread.cpp b/thirdparty/embree/common/sys/thread.cpp
+index a7827e18f7..f4014be89b 100644
+--- a/thirdparty/embree/common/sys/thread.cpp
++++ b/thirdparty/embree/common/sys/thread.cpp
+@@ -158,7 +158,9 @@ namespace embree
+ /// Linux Platform
+ ////////////////////////////////////////////////////////////////////////////////
+
+-#if defined(__LINUX__)
++// -- GODOT start --
++#if defined(__LINUX__) && !defined(__ANDROID__)
++// -- GODOT end --
+
+ #include <fstream>
+ #include <sstream>
+@@ -247,6 +249,28 @@ namespace embree
+ }
+ #endif
+
++// -- GODOT start --
++////////////////////////////////////////////////////////////////////////////////
++/// Android Platform
++////////////////////////////////////////////////////////////////////////////////
++
++#if defined(__ANDROID__)
++
++namespace embree
++{
++ /*! set affinity of the calling thread */
++ void setAffinity(ssize_t affinity)
++ {
++ cpu_set_t cset;
++ CPU_ZERO(&cset);
++ CPU_SET(affinity, &cset);
++
++ sched_setaffinity(0, sizeof(cset), &cset);
++ }
++}
++#endif
++// -- GODOT end --
++
+ ////////////////////////////////////////////////////////////////////////////////
+ /// FreeBSD Platform
+ ////////////////////////////////////////////////////////////////////////////////
+@@ -355,7 +379,9 @@ namespace embree
+ pthread_attr_destroy(&attr);
+
+ /* set affinity */
+-#if defined(__LINUX__)
++// -- GODOT start --
++#if defined(__LINUX__) && !defined(__ANDROID__)
++// -- GODOT end --
+ if (threadID >= 0) {
+ cpu_set_t cset;
+ CPU_ZERO(&cset);
+@@ -370,7 +396,16 @@ namespace embree
+ CPU_SET(threadID, &cset);
+ pthread_setaffinity_np(*tid, sizeof(cset), &cset);
+ }
++// -- GODOT start --
++#elif defined(__ANDROID__)
++ if (threadID >= 0) {
++ cpu_set_t cset;
++ CPU_ZERO(&cset);
++ CPU_SET(threadID, &cset);
++ sched_setaffinity(pthread_gettid_np(*tid), sizeof(cset), &cset);
++ }
+ #endif
++// -- GODOT end --
+
+ return thread_t(tid);
+ }
+@@ -389,8 +424,14 @@ namespace embree
+
+ /*! destroy a hardware thread by its handle */
+ void destroyThread(thread_t tid) {
++// -- GODOT start --
++#if defined(__ANDROID__)
++ FATAL("Can't destroy threads on Android.");
++#else
+ pthread_cancel(*(pthread_t*)tid);
+ delete (pthread_t*)tid;
++#endif
++// -- GODOT end --
+ }
+
+ /*! creates thread local storage */
diff --git a/thirdparty/embree/patches/godot-changes-misc.patch b/thirdparty/embree/patches/godot-changes-misc.patch
new file mode 100644
index 0000000000..8bf0d9fa97
--- /dev/null
+++ b/thirdparty/embree/patches/godot-changes-misc.patch
@@ -0,0 +1,105 @@
+diff --git a/thirdparty/embree/common/sys/intrinsics.h b/thirdparty/embree/common/sys/intrinsics.h
+index 79729c87ab..ed8dd7d40a 100644
+--- a/thirdparty/embree/common/sys/intrinsics.h
++++ b/thirdparty/embree/common/sys/intrinsics.h
+@@ -34,8 +34,14 @@
+ #endif
+
+ #if defined(__WIN32__)
+-# define NOMINMAX
+-# include <windows.h>
++// -- GODOT start --
++#if !defined(NOMINMAX)
++// -- GODOT end --
++#define NOMINMAX
++// -- GODOT start --
++#endif
++#include "windows.h"
++// -- GODOT end --
+ #endif
+
+ /* normally defined in pmmintrin.h, but we always need this */
+diff --git a/thirdparty/embree/common/sys/platform.h b/thirdparty/embree/common/sys/platform.h
+index 3fc5e99b8d..697e07bb86 100644
+--- a/thirdparty/embree/common/sys/platform.h
++++ b/thirdparty/embree/common/sys/platform.h
+@@ -99,7 +99,9 @@
+ #define dll_import
+ #endif
+
+-#ifdef __WIN32__
++// -- GODOT start --
++#if defined(__WIN32__) && !defined(__MINGW32__)
++// -- GODOT end --
+ #if !defined(__noinline)
+ #define __noinline __declspec(noinline)
+ #endif
+@@ -149,6 +151,9 @@
+ #define DELETED = delete
+ #endif
+
++// -- GODOT start --
++#if !defined(likely)
++// -- GODOT end --
+ #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+ #define likely(expr) (expr)
+ #define unlikely(expr) (expr)
+@@ -156,6 +161,9 @@
+ #define likely(expr) __builtin_expect((bool)(expr),true )
+ #define unlikely(expr) __builtin_expect((bool)(expr),false)
+ #endif
++// -- GODOT start --
++#endif
++// -- GODOT end --
+
+ ////////////////////////////////////////////////////////////////////////////////
+ /// Error handling and debugging
+diff --git a/thirdparty/embree/common/sys/sysinfo.cpp b/thirdparty/embree/common/sys/sysinfo.cpp
+index ba97dc227b..f1a59e511e 100644
+--- a/thirdparty/embree/common/sys/sysinfo.cpp
++++ b/thirdparty/embree/common/sys/sysinfo.cpp
+@@ -248,7 +248,9 @@ namespace embree
+ #if defined(__X86_ASM__)
+ __noinline int64_t get_xcr0()
+ {
+-#if defined (__WIN32__)
++// -- GODOT start --
++#if defined (__WIN32__) && !defined (__MINGW32__)
++// -- GODOT end --
+ int64_t xcr0 = 0; // int64_t is workaround for compiler bug under VS2013, Win32
+ xcr0 = _xgetbv(0);
+ return xcr0;
+diff --git a/thirdparty/embree/include/embree3/rtcore_common.h b/thirdparty/embree/include/embree3/rtcore_common.h
+index 9c14b28745..4857e1e05e 100644
+--- a/thirdparty/embree/include/embree3/rtcore_common.h
++++ b/thirdparty/embree/include/embree3/rtcore_common.h
+@@ -19,7 +19,9 @@ typedef int ssize_t;
+ #endif
+ #endif
+
+-#ifdef _WIN32
++// -- GODOT start --
++#if defined(_WIN32) && defined(_MSC_VER)
++// -- GODOT end --
+ # define RTC_ALIGN(...) __declspec(align(__VA_ARGS__))
+ #else
+ # define RTC_ALIGN(...) __attribute__((aligned(__VA_ARGS__)))
+diff --git a/thirdparty/embree/common/tasking/taskschedulertbb.h b/thirdparty/embree/common/tasking/taskschedulertbb.h
+index 3fd15816e9..35bd49849f 100644
+--- a/thirdparty/embree/common/tasking/taskschedulertbb.h
++++ b/thirdparty/embree/common/tasking/taskschedulertbb.h
+@@ -12,7 +12,13 @@
+ #include "../sys/ref.h"
+
+ #if defined(__WIN32__)
++// -- GODOT start --
++#if !defined(NOMINMAX)
++// -- GODOT end --
+ # define NOMINMAX
++// -- GODOT start --
++#endif
++// -- GODOT end --
+ #endif
+
+ // We need to define these to avoid implicit linkage against
+ \ No newline at end of file
diff --git a/thirdparty/embree/patches/godot-changes-noexcept.patch b/thirdparty/embree/patches/godot-changes-noexcept.patch
new file mode 100644
index 0000000000..c587a0e2be
--- /dev/null
+++ b/thirdparty/embree/patches/godot-changes-noexcept.patch
@@ -0,0 +1,630 @@
+diff --git a/thirdparty/embree/common/algorithms/parallel_for.h b/thirdparty/embree/common/algorithms/parallel_for.h
+index f052d8b468..645681ac63 100644
+--- a/thirdparty/embree/common/algorithms/parallel_for.h
++++ b/thirdparty/embree/common/algorithms/parallel_for.h
+@@ -21,7 +21,10 @@ namespace embree
+ func(r.begin());
+ });
+ if (!TaskScheduler::wait())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ }
+
+ #elif defined(TASKING_TBB)
+@@ -31,13 +34,19 @@ namespace embree
+ func(i);
+ },context);
+ if (context.is_group_execution_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ });
+ if (tbb::task::self().is_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #endif
+
+ #elif defined(TASKING_PPL)
+@@ -57,7 +66,10 @@ namespace embree
+ #if defined(TASKING_INTERNAL)
+ TaskScheduler::spawn(first,last,minStepSize,func);
+ if (!TaskScheduler::wait())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+
+ #elif defined(TASKING_TBB)
+ #if TBB_INTERFACE_VERSION >= 12002
+@@ -66,13 +78,19 @@ namespace embree
+ func(range<Index>(r.begin(),r.end()));
+ },context);
+ if (context.is_group_execution_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #else
+ tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
+ func(range<Index>(r.begin(),r.end()));
+ });
+ if (tbb::task::self().is_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #endif
+
+ #elif defined(TASKING_PPL)
+@@ -104,13 +122,19 @@ namespace embree
+ func(i);
+ },tbb::simple_partitioner(),context);
+ if (context.is_group_execution_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },tbb::simple_partitioner());
+ if (tbb::task::self().is_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #endif
+ }
+
+@@ -125,13 +149,19 @@ namespace embree
+ func(i);
+ },ap,context);
+ if (context.is_group_execution_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #else
+ tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
+ func(i);
+ },ap);
+ if (tbb::task::self().is_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // throw std::runtime_error("task cancelled");
++ abort();
++ // -- GODOT end --
+ #endif
+ }
+
+diff --git a/thirdparty/embree/common/algorithms/parallel_reduce.h b/thirdparty/embree/common/algorithms/parallel_reduce.h
+index f42ae2ec50..8271372ea4 100644
+--- a/thirdparty/embree/common/algorithms/parallel_reduce.h
++++ b/thirdparty/embree/common/algorithms/parallel_reduce.h
+@@ -58,15 +58,19 @@ namespace embree
+ const Value v = tbb::parallel_reduce(tbb::blocked_range<Index>(first,last,minStepSize),identity,
+ [&](const tbb::blocked_range<Index>& r, const Value& start) { return reduction(start,func(range<Index>(r.begin(),r.end()))); },
+ reduction,context);
+- if (context.is_group_execution_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // if (context.is_group_execution_cancelled())
++ // throw std::runtime_error("task cancelled");
++ // -- GODOT end --
+ return v;
+ #else
+ const Value v = tbb::parallel_reduce(tbb::blocked_range<Index>(first,last,minStepSize),identity,
+ [&](const tbb::blocked_range<Index>& r, const Value& start) { return reduction(start,func(range<Index>(r.begin(),r.end()))); },
+ reduction);
+- if (tbb::task::self().is_cancelled())
+- throw std::runtime_error("task cancelled");
++ // -- GODOT start --
++ // if (tbb::task::self().is_cancelled())
++ // throw std::runtime_error("task cancelled");
++ // -- GODOT end --
+ return v;
+ #endif
+ #else // TASKING_PPL
+diff --git a/thirdparty/embree/common/lexers/stringstream.cpp b/thirdparty/embree/common/lexers/stringstream.cpp
+index 42ffb10176..a037869506 100644
+--- a/thirdparty/embree/common/lexers/stringstream.cpp
++++ b/thirdparty/embree/common/lexers/stringstream.cpp
+@@ -39,7 +39,10 @@ namespace embree
+ std::vector<char> str; str.reserve(64);
+ while (cin->peek() != EOF && !isSeparator(cin->peek())) {
+ int c = cin->get();
+- if (!isValidChar(c)) throw std::runtime_error("invalid character "+std::string(1,c)+" in input");
++ // -- GODOT start --
++ // if (!isValidChar(c)) throw std::runtime_error("invalid character "+std::string(1,c)+" in input");
++ if (!isValidChar(c)) abort();
++ // -- GODOT end --
+ str.push_back((char)c);
+ }
+ str.push_back(0);
+diff --git a/thirdparty/embree/common/sys/alloc.cpp b/thirdparty/embree/common/sys/alloc.cpp
+index 1bc30fe9a5..abdd269069 100644
+--- a/thirdparty/embree/common/sys/alloc.cpp
++++ b/thirdparty/embree/common/sys/alloc.cpp
+@@ -21,7 +21,10 @@ namespace embree
+ void* ptr = _mm_malloc(size,align);
+
+ if (size != 0 && ptr == nullptr)
+- throw std::bad_alloc();
++ // -- GODOT start --
++ // throw std::bad_alloc();
++ abort();
++ // -- GODOT end --
+
+ return ptr;
+ }
+@@ -128,7 +131,10 @@ namespace embree
+ /* fall back to 4k pages */
+ int flags = MEM_COMMIT | MEM_RESERVE;
+ char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE);
+- if (ptr == nullptr) throw std::bad_alloc();
++ // -- GODOT start --
++ // if (ptr == nullptr) throw std::bad_alloc();
++ if (ptr == nullptr) abort();
++ // -- GODOT end --
+ hugepages = false;
+ return ptr;
+ }
+@@ -145,7 +151,10 @@ namespace embree
+ return bytesOld;
+
+ if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT))
+- throw std::bad_alloc();
++ // -- GODOT start --
++ // throw std::bad_alloc();
++ abort();
++ // -- GODOT end --
+
+ return bytesNew;
+ }
+@@ -156,7 +165,10 @@ namespace embree
+ return;
+
+ if (!VirtualFree(ptr,0,MEM_RELEASE))
+- throw std::bad_alloc();
++ // -- GODOT start --
++ // throw std::bad_alloc();
++ abort();
++ // -- GODOT end --
+ }
+
+ void os_advise(void *ptr, size_t bytes)
+@@ -260,7 +272,10 @@ namespace embree
+
+ /* fallback to 4k pages */
+ void* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+- if (ptr == MAP_FAILED) throw std::bad_alloc();
++ // -- GODOT start --
++ // if (ptr == MAP_FAILED) throw std::bad_alloc();
++ if (ptr == MAP_FAILED) abort();
++ // -- GODOT end --
+ hugepages = false;
+
+ /* advise huge page hint for THP */
+@@ -277,7 +292,10 @@ namespace embree
+ return bytesOld;
+
+ if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1)
+- throw std::bad_alloc();
++ // -- GODOT start --
++ // throw std::bad_alloc();
++ abort();
++ // -- GODOT end --
+
+ return bytesNew;
+ }
+@@ -291,7 +309,10 @@ namespace embree
+ const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K;
+ bytes = (bytes+pageSize-1) & ~(pageSize-1);
+ if (munmap(ptr,bytes) == -1)
+- throw std::bad_alloc();
++ // -- GODOT start --
++ // throw std::bad_alloc();
++ abort();
++ // -- GODOT end --
+ }
+
+ /* hint for transparent huge pages (THP) */
+diff --git a/thirdparty/embree/common/sys/platform.h b/thirdparty/embree/common/sys/platform.h
+index 8a6d9fa0a9..697e07bb86 100644
+--- a/thirdparty/embree/common/sys/platform.h
++++ b/thirdparty/embree/common/sys/platform.h
+@@ -179,11 +179,19 @@
+ #define PRINT4(x,y,z,w) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << ", " << STRING(w) << " = " << (w) << embree_endl
+
+ #if defined(DEBUG) // only report file and line in debug mode
++ // -- GODOT start --
++ // #define THROW_RUNTIME_ERROR(str)
++ // throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
+ #define THROW_RUNTIME_ERROR(str) \
+- throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
++ printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
++ // -- GODOT end --
+ #else
++ // -- GODOT start --
++ // #define THROW_RUNTIME_ERROR(str)
++ // throw std::runtime_error(str);
+ #define THROW_RUNTIME_ERROR(str) \
+- throw std::runtime_error(str);
++ abort();
++ // -- GODOT end --
+ #endif
+
+ #define FATAL(x) THROW_RUNTIME_ERROR(x)
+diff --git a/thirdparty/embree/common/tasking/taskschedulerinternal.cpp b/thirdparty/embree/common/tasking/taskschedulerinternal.cpp
+index dca835a716..ad438588a3 100644
+--- a/thirdparty/embree/common/tasking/taskschedulerinternal.cpp
++++ b/thirdparty/embree/common/tasking/taskschedulerinternal.cpp
+@@ -48,13 +48,15 @@ namespace embree
+ {
+ Task* prevTask = thread.task;
+ thread.task = this;
+- try {
+- if (thread.scheduler->cancellingException == nullptr)
++ // -- GODOT start --
++ // try {
++ // if (thread.scheduler->cancellingException == nullptr)
+ closure->execute();
+- } catch (...) {
+- if (thread.scheduler->cancellingException == nullptr)
+- thread.scheduler->cancellingException = std::current_exception();
+- }
++ // } catch (...) {
++ // if (thread.scheduler->cancellingException == nullptr)
++ // thread.scheduler->cancellingException = std::current_exception();
++ // }
++ // -- GODOT end --
+ thread.task = prevTask;
+ add_dependencies(-1);
+ }
+@@ -291,8 +293,11 @@ namespace embree
+ size_t threadIndex = allocThreadIndex();
+ condition.wait(mutex, [&] () { return hasRootTask.load(); });
+ mutex.unlock();
+- std::exception_ptr except = thread_loop(threadIndex);
+- if (except != nullptr) std::rethrow_exception(except);
++ // -- GODOT start --
++ // std::exception_ptr except = thread_loop(threadIndex);
++ // if (except != nullptr) std::rethrow_exception(except);
++ thread_loop(threadIndex);
++ // -- GODOT end --
+ }
+
+ void TaskScheduler::reset() {
+@@ -324,7 +329,10 @@ namespace embree
+ return thread->scheduler->cancellingException == nullptr;
+ }
+
+- std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex)
++// -- GODOT start --
++// std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex)
++ void TaskScheduler::thread_loop(size_t threadIndex)
++// -- GODOT end --
+ {
+ /* allocate thread structure */
+ std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation
+@@ -347,9 +355,10 @@ namespace embree
+ swapThread(oldThread);
+
+ /* remember exception to throw */
+- std::exception_ptr except = nullptr;
+- if (cancellingException != nullptr) except = cancellingException;
+-
++ // -- GODOT start --
++ // std::exception_ptr except = nullptr;
++ // if (cancellingException != nullptr) except = cancellingException;
++ // -- GODOT end --
+ /* wait for all threads to terminate */
+ threadCounter--;
+ #if defined(__WIN32__)
+@@ -367,7 +376,10 @@ namespace embree
+ yield();
+ #endif
+ }
+- return except;
++ // -- GODOT start --
++ // return except;
++ return;
++ // -- GODOT end --
+ }
+
+ bool TaskScheduler::steal_from_other_threads(Thread& thread)
+diff --git a/thirdparty/embree/common/tasking/taskschedulerinternal.h b/thirdparty/embree/common/tasking/taskschedulerinternal.h
+index c766a0bb6a..8fa6bb12fa 100644
+--- a/thirdparty/embree/common/tasking/taskschedulerinternal.h
++++ b/thirdparty/embree/common/tasking/taskschedulerinternal.h
+@@ -123,7 +123,10 @@ namespace embree
+ {
+ size_t ofs = bytes + ((align - stackPtr) & (align-1));
+ if (stackPtr + ofs > CLOSURE_STACK_SIZE)
+- throw std::runtime_error("closure stack overflow");
++ // -- GODOT start --
++ // throw std::runtime_error("closure stack overflow");
++ abort();
++ // -- GODOT end --
+ stackPtr += ofs;
+ return &stack[stackPtr-bytes];
+ }
+@@ -132,7 +135,10 @@ namespace embree
+ __forceinline void push_right(Thread& thread, const size_t size, const Closure& closure)
+ {
+ if (right >= TASK_STACK_SIZE)
+- throw std::runtime_error("task stack overflow");
++ // -- GODOT start --
++ // throw std::runtime_error("task stack overflow");
++ abort();
++ // -- GODOT end --
+
+ /* allocate new task on right side of stack */
+ size_t oldStackPtr = stackPtr;
+@@ -238,7 +244,10 @@ namespace embree
+ void wait_for_threads(size_t threadCount);
+
+ /*! thread loop for all worker threads */
+- std::exception_ptr thread_loop(size_t threadIndex);
++ // -- GODOT start --
++ // std::exception_ptr thread_loop(size_t threadIndex);
++ void thread_loop(size_t threadIndex);
++ // -- GODOT end --
+
+ /*! steals a task from a different thread */
+ bool steal_from_other_threads(Thread& thread);
+diff --git a/thirdparty/embree/kernels/bvh/bvh_statistics.cpp b/thirdparty/embree/kernels/bvh/bvh_statistics.cpp
+index d8da78eed7..d857ff7d95 100644
+--- a/thirdparty/embree/kernels/bvh/bvh_statistics.cpp
++++ b/thirdparty/embree/kernels/bvh/bvh_statistics.cpp
+@@ -150,7 +150,10 @@ namespace embree
+ }
+ }
+ else {
+- throw std::runtime_error("not supported node type in bvh_statistics");
++ // -- GODOT start --
++ // throw std::runtime_error("not supported node type in bvh_statistics");
++ abort();
++ // -- GODOT end --
+ }
+ return s;
+ }
+diff --git a/thirdparty/embree/kernels/common/rtcore.cpp b/thirdparty/embree/kernels/common/rtcore.cpp
+index 74e9fb335c..94b3819e42 100644
+--- a/thirdparty/embree/kernels/common/rtcore.cpp
++++ b/thirdparty/embree/kernels/common/rtcore.cpp
+@@ -197,7 +197,10 @@ RTC_NAMESPACE_BEGIN;
+ if (quality != RTC_BUILD_QUALITY_LOW &&
+ quality != RTC_BUILD_QUALITY_MEDIUM &&
+ quality != RTC_BUILD_QUALITY_HIGH)
+- throw std::runtime_error("invalid build quality");
++ // -- GODOT start --
++ // throw std::runtime_error("invalid build quality");
++ abort();
++ // -- GODOT end --
+ scene->setBuildQuality(quality);
+ RTC_CATCH_END2(scene);
+ }
+@@ -1350,7 +1353,10 @@ RTC_NAMESPACE_BEGIN;
+ quality != RTC_BUILD_QUALITY_MEDIUM &&
+ quality != RTC_BUILD_QUALITY_HIGH &&
+ quality != RTC_BUILD_QUALITY_REFIT)
+- throw std::runtime_error("invalid build quality");
++ // -- GODOT start --
++ // throw std::runtime_error("invalid build quality");
++ abort();
++ // -- GODOT end --
+ geometry->setBuildQuality(quality);
+ RTC_CATCH_END2(geometry);
+ }
+diff --git a/thirdparty/embree/kernels/common/rtcore.h b/thirdparty/embree/kernels/common/rtcore.h
+index 4e4b24e9c2..373e49a689 100644
+--- a/thirdparty/embree/kernels/common/rtcore.h
++++ b/thirdparty/embree/kernels/common/rtcore.h
+@@ -25,52 +25,58 @@ namespace embree
+ #endif
+
+ /*! Macros used in the rtcore API implementation */
+-#define RTC_CATCH_BEGIN try {
++// -- GODOT start --
++// #define RTC_CATCH_BEGIN try {
++#define RTC_CATCH_BEGIN
+
+-#define RTC_CATCH_END(device) \
+- } catch (std::bad_alloc&) { \
+- Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+- } catch (rtcore_error& e) { \
+- Device::process_error(device,e.error,e.what()); \
+- } catch (std::exception& e) { \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+- } catch (...) { \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+- }
++// #define RTC_CATCH_END(device) \
++// } catch (std::bad_alloc&) { \
++// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
++// } catch (rtcore_error& e) { \
++// Device::process_error(device,e.error,e.what()); \
++// } catch (std::exception& e) { \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
++// } catch (...) { \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
++// }
++#define RTC_CATCH_END(device)
+
+-#define RTC_CATCH_END2(scene) \
+- } catch (std::bad_alloc&) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+- } catch (rtcore_error& e) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,e.error,e.what()); \
+- } catch (std::exception& e) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+- } catch (...) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+- }
++// #define RTC_CATCH_END2(scene) \
++// } catch (std::bad_alloc&) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
++// } catch (rtcore_error& e) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,e.error,e.what()); \
++// } catch (std::exception& e) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
++// } catch (...) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
++// }
++#define RTC_CATCH_END2(scene)
+
+-#define RTC_CATCH_END2_FALSE(scene) \
+- } catch (std::bad_alloc&) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
+- return false; \
+- } catch (rtcore_error& e) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,e.error,e.what()); \
+- return false; \
+- } catch (std::exception& e) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
+- return false; \
+- } catch (...) { \
+- Device* device = scene ? scene->device : nullptr; \
+- Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
+- return false; \
+- }
++// #define RTC_CATCH_END2_FALSE(scene) \
++// } catch (std::bad_alloc&) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \
++// return false; \
++// } catch (rtcore_error& e) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,e.error,e.what()); \
++// return false; \
++// } catch (std::exception& e) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,e.what()); \
++// return false; \
++// } catch (...) { \
++// Device* device = scene ? scene->device : nullptr; \
++// Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \
++// return false; \
++// }
++#define RTC_CATCH_END2_FALSE(scene) return false;
++// -- GODOT end --
+
+ #define RTC_VERIFY_HANDLE(handle) \
+ if (handle == nullptr) { \
+@@ -97,28 +103,38 @@ namespace embree
+ #define RTC_TRACE(x)
+ #endif
+
+- /*! used to throw embree API errors */
+- struct rtcore_error : public std::exception
+- {
+- __forceinline rtcore_error(RTCError error, const std::string& str)
+- : error(error), str(str) {}
+-
+- ~rtcore_error() throw() {}
+-
+- const char* what () const throw () {
+- return str.c_str();
+- }
+-
+- RTCError error;
+- std::string str;
+- };
++// -- GODOT begin --
++// /*! used to throw embree API errors */
++// struct rtcore_error : public std::exception
++// {
++// __forceinline rtcore_error(RTCError error, const std::string& str)
++// : error(error), str(str) {}
++//
++// ~rtcore_error() throw() {}
++//
++// const char* what () const throw () {
++// return str.c_str();
++// }
++//
++// RTCError error;
++// std::string str;
++// };
++// -- GODOT end --
+
+ #if defined(DEBUG) // only report file and line in debug mode
++ // -- GODOT begin --
++ // #define throw_RTCError(error,str) \
++ // throw rtcore_error(error,std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
+ #define throw_RTCError(error,str) \
+- throw rtcore_error(error,std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
++ printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
++ // -- GODOT end --
+ #else
++ // -- GODOT begin --
++ // #define throw_RTCError(error,str) \
++ // throw rtcore_error(error,str);
+ #define throw_RTCError(error,str) \
+- throw rtcore_error(error,str);
++ abort();
++ // -- GODOT end --
+ #endif
+
+ #define RTC_BUILD_ARGUMENTS_HAS(settings,member) \
+diff --git a/thirdparty/embree/kernels/common/scene.cpp b/thirdparty/embree/kernels/common/scene.cpp
+index 0149055f2c..408d7eae6f 100644
+--- a/thirdparty/embree/kernels/common/scene.cpp
++++ b/thirdparty/embree/kernels/common/scene.cpp
+@@ -792,16 +792,18 @@ namespace embree
+ }
+
+ /* initiate build */
+- try {
++ // -- GODOT start --
++ // try {
+ scheduler->spawn_root([&]() { commit_task(); Lock<MutexSys> lock(schedulerMutex); this->scheduler = nullptr; }, 1, !join);
+- }
+- catch (...) {
+- accels_clear();
+- updateInterface();
+- Lock<MutexSys> lock(schedulerMutex);
+- this->scheduler = nullptr;
+- throw;
+- }
++ // }
++ // catch (...) {
++ // accels_clear();
++ // updateInterface();
++ // Lock<MutexSys> lock(schedulerMutex);
++ // this->scheduler = nullptr;
++ // throw;
++ // }
++ // -- GODOT end --
+ }
+
+ #endif
diff --git a/thirdparty/embree/patches/godot-changes-ubsan.patch b/thirdparty/embree/patches/godot-changes-ubsan.patch
new file mode 100644
index 0000000000..1336246f0d
--- /dev/null
+++ b/thirdparty/embree/patches/godot-changes-ubsan.patch
@@ -0,0 +1,24 @@
+diff --git a/thirdparty/embree/kernels/builders/primrefgen.cpp b/thirdparty/embree/kernels/builders/primrefgen.cpp
+index bb4fc81dfe..d279dc4993 100644
+--- a/thirdparty/embree/kernels/builders/primrefgen.cpp
++++ b/thirdparty/embree/kernels/builders/primrefgen.cpp
+@@ -184,6 +184,9 @@ namespace embree
+
+ // special variants for grid meshes
+
++// -- GODOT start --
++#if defined(EMBREE_GEOMETRY_GRID)
++// -- GODOT end --
+ PrimInfo createPrimRefArrayGrids(Scene* scene, mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids)
+ {
+ PrimInfo pinfo(empty);
+@@ -293,6 +296,9 @@ namespace embree
+
+ return pinfo;
+ }
++// -- GODOT start --
++#endif
++// -- GODOT end --
+
+ // ====================================================================================================
+ // ====================================================================================================
diff --git a/thirdparty/enet/godot.cpp b/thirdparty/enet/godot.cpp
index 73fa3c62a2..fd7968204b 100644
--- a/thirdparty/enet/godot.cpp
+++ b/thirdparty/enet/godot.cpp
@@ -45,9 +45,10 @@
/// Abstract ENet interface for UDP/DTLS.
class ENetGodotSocket {
public:
- virtual Error bind(IP_Address p_ip, uint16_t p_port) = 0;
- virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) = 0;
- virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) = 0;
+ virtual Error bind(IPAddress p_ip, uint16_t p_port) = 0;
+ virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) = 0;
+ virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) = 0;
+ virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port) = 0;
virtual int set_option(ENetSocketOption p_option, int p_value) = 0;
virtual void close() = 0;
virtual void set_refuse_new_connections(bool p_enable) {} /* Only used by dtls server */
@@ -64,8 +65,7 @@ class ENetUDP : public ENetGodotSocket {
private:
Ref<NetSocket> sock;
- IP_Address address;
- uint16_t port = 0;
+ IPAddress local_address;
bool bound = false;
public:
@@ -79,18 +79,21 @@ public:
sock->close();
}
- Error bind(IP_Address p_ip, uint16_t p_port) {
- address = p_ip;
- port = p_port;
+ Error bind(IPAddress p_ip, uint16_t p_port) {
+ local_address = p_ip;
bound = true;
- return sock->bind(address, port);
+ return sock->bind(p_ip, p_port);
}
- Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
+ Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) {
+ return sock->get_socket_address(r_ip, r_port);
+ }
+
+ Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
return sock->sendto(p_buffer, p_len, r_sent, p_ip, p_port);
}
- Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) {
+ Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port) {
Error err = sock->poll(NetSocket::POLL_TYPE_IN, 0);
if (err != OK) {
return err;
@@ -142,6 +145,7 @@ public:
void close() {
sock->close();
+ local_address.clear();
}
};
@@ -153,6 +157,7 @@ class ENetDTLSClient : public ENetGodotSocket {
bool verify = false;
String for_hostname;
Ref<X509Certificate> cert;
+ IPAddress local_address;
public:
ENetDTLSClient(ENetUDP *p_base, Ref<X509Certificate> p_cert, bool p_verify, String p_for_hostname) {
@@ -161,9 +166,11 @@ public:
cert = p_cert;
udp.instance();
dtls = Ref<PacketPeerDTLS>(PacketPeerDTLS::create());
- p_base->close();
if (p_base->bound) {
- bind(p_base->address, p_base->port);
+ uint16_t port;
+ p_base->get_socket_address(&local_address, &port);
+ p_base->close();
+ bind(local_address, port);
}
}
@@ -171,11 +178,21 @@ public:
close();
}
- Error bind(IP_Address p_ip, uint16_t p_port) {
- return udp->listen(p_port, p_ip);
+ Error bind(IPAddress p_ip, uint16_t p_port) {
+ local_address = p_ip;
+ return udp->bind(p_port, p_ip);
+ }
+
+ Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) {
+ if (!udp->is_bound()) {
+ return ERR_UNCONFIGURED;
+ }
+ *r_ip = local_address;
+ *r_port = udp->get_local_port();
+ return OK;
}
- Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
+ Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
if (!connected) {
udp->connect_to_host(p_ip, p_port);
dtls->connect_to_peer(udp, verify, for_hostname, cert);
@@ -191,7 +208,7 @@ public:
return dtls->put_packet(p_buffer, p_len);
}
- Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) {
+ Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port) {
dtls->poll();
if (dtls->get_status() == PacketPeerDTLS::STATUS_HANDSHAKING) {
return ERR_BUSY;
@@ -211,7 +228,7 @@ public:
ERR_FAIL_COND_V(err != OK, err);
ERR_FAIL_COND_V(p_len < r_read, ERR_OUT_OF_MEMORY);
- copymem(p_buffer, buffer, r_read);
+ memcpy(p_buffer, buffer, r_read);
r_ip = udp->get_packet_address();
r_port = udp->get_packet_port();
return err;
@@ -233,13 +250,16 @@ class ENetDTLSServer : public ENetGodotSocket {
Ref<UDPServer> udp_server;
Map<String, Ref<PacketPeerDTLS>> peers;
int last_service = 0;
+ IPAddress local_address;
public:
ENetDTLSServer(ENetUDP *p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert) {
udp_server.instance();
- p_base->close();
if (p_base->bound) {
- bind(p_base->address, p_base->port);
+ uint16_t port;
+ p_base->get_socket_address(&local_address, &port);
+ p_base->close();
+ bind(local_address, port);
}
server = Ref<DTLSServer>(DTLSServer::create());
server->setup(p_key, p_cert);
@@ -253,11 +273,21 @@ public:
udp_server->set_max_pending_connections(p_refuse ? 0 : 16);
}
- Error bind(IP_Address p_ip, uint16_t p_port) {
+ Error bind(IPAddress p_ip, uint16_t p_port) {
+ local_address = p_ip;
return udp_server->listen(p_port, p_ip);
}
- Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
+ Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) {
+ if (!udp_server->is_listening()) {
+ return ERR_UNCONFIGURED;
+ }
+ *r_ip = local_address;
+ *r_port = udp_server->get_local_port();
+ return OK;
+ }
+
+ Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
String key = String(p_ip) + ":" + itos(p_port);
ERR_FAIL_COND_V(!peers.has(key), ERR_UNAVAILABLE);
Ref<PacketPeerDTLS> peer = peers[key];
@@ -272,12 +302,12 @@ public:
return err;
}
- Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) {
+ Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port) {
udp_server->poll();
// TODO limits? Maybe we can better enforce allowed connections!
if (udp_server->is_connection_available()) {
Ref<PacketPeerUDP> udp = udp_server->take_connection();
- IP_Address peer_ip = udp->get_packet_address();
+ IPAddress peer_ip = udp->get_packet_address();
int peer_port = udp->get_packet_port();
Ref<PacketPeerDTLS> peer = server->take_connection(udp);
PacketPeerDTLS::Status status = peer->get_status();
@@ -315,7 +345,7 @@ public:
Vector<String> s = E->key().rsplit(":", false, 1);
ERR_CONTINUE(s.size() != 2); // BUG!
- copymem(p_buffer, buffer, r_read);
+ memcpy(p_buffer, buffer, r_read);
r_ip = s[0];
r_port = s[1].to_int();
break; // err = OK
@@ -341,6 +371,7 @@ public:
peers.clear();
udp_server->stop();
server->stop();
+ local_address.clear();
}
};
@@ -366,7 +397,7 @@ void enet_time_set(enet_uint32 newTimeBase) {
}
int enet_address_set_host(ENetAddress *address, const char *name) {
- IP_Address ip = IP::get_singleton()->resolve_hostname(name);
+ IPAddress ip = IP::get_singleton()->resolve_hostname(name);
ERR_FAIL_COND_V(!ip.is_valid(), -1);
enet_address_set_ip(address, ip.get_ipv6(), 16);
@@ -411,9 +442,9 @@ void enet_host_refuse_new_connections(ENetHost *host, int p_refuse) {
}
int enet_socket_bind(ENetSocket socket, const ENetAddress *address) {
- IP_Address ip;
+ IPAddress ip;
if (address->wildcard) {
- ip = IP_Address("*");
+ ip = IPAddress("*");
} else {
ip.set_ipv6(address->host);
}
@@ -435,7 +466,7 @@ int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBu
ERR_FAIL_COND_V(address == nullptr, -1);
ENetGodotSocket *sock = (ENetGodotSocket *)socket;
- IP_Address dest;
+ IPAddress dest;
Error err;
size_t i = 0;
@@ -477,7 +508,7 @@ int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buf
ENetGodotSocket *sock = (ENetGodotSocket *)socket;
int read;
- IP_Address ip;
+ IPAddress ip;
Error err = sock->recvfrom((uint8_t *)buffers[0].data, buffers[0].dataLength, read, ip, address->port);
if (err == ERR_BUSY) {
@@ -493,15 +524,26 @@ int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buf
return read;
}
+int enet_socket_get_address (ENetSocket socket, ENetAddress * address) {
+ IPAddress ip;
+ uint16_t port;
+ ENetGodotSocket *sock = (ENetGodotSocket *)socket;
+
+ if (sock->get_socket_address(&ip, &port) != OK) {
+ return -1;
+ }
+
+ enet_address_set_ip(address, ip.get_ipv6(), 16);
+ address->port = port;
+
+ return 0;
+}
+
// Not implemented
int enet_socket_wait(ENetSocket socket, enet_uint32 *condition, enet_uint32 timeout) {
return 0; // do we need this function?
}
-int enet_socket_get_address(ENetSocket socket, ENetAddress *address) {
- return -1; // do we need this function?
-}
-
int enet_socketset_select(ENetSocket maxSocket, ENetSocketSet *readSet, ENetSocketSet *writeSet, enet_uint32 timeout) {
return -1;
}
diff --git a/thirdparty/fonts/OpenSans_SemiBold.ttf b/thirdparty/fonts/OpenSans_SemiBold.ttf
new file mode 100644
index 0000000000..54e7059cf3
--- /dev/null
+++ b/thirdparty/fonts/OpenSans_SemiBold.ttf
Binary files differ
diff --git a/thirdparty/icu4c/APIChangeReport.md b/thirdparty/icu4c/APIChangeReport.md
deleted file mode 100644
index 5385904fd1..0000000000
--- a/thirdparty/icu4c/APIChangeReport.md
+++ /dev/null
@@ -1,396 +0,0 @@
-
-
-<!--
- Copyright © 2019 and later: Unicode, Inc. and others.
- License & terms of use: http://www.unicode.org/copyright.html
--->
-
-# ICU4C API Comparison: ICU 67 with ICU 68
-
-> _Note_ Markdown format of this document is new for ICU 65.
-
-- [Removed from ICU 67](#removed)
-- [Deprecated or Obsoleted in ICU 68](#deprecated)
-- [Changed in ICU 68](#changed)
-- [Promoted to stable in ICU 68](#promoted)
-- [Added in ICU 68](#added)
-- [Other existing drafts in ICU 68](#other)
-- [Signature Simplifications](#simplifications)
-
-## Removed
-
-Removed from ICU 67
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| fmtable.h | const UFormattable* icu::Formattable::toUFormattable() | StableICU 52 | (missing)
-| measunit.h | LocalArray&lt;MeasureUnit&gt; icu::MeasureUnit::splitToSingleUnits(int32_t&amp;, UErrorCode&amp;) const | InternalICU 67 | (missing)
-| measunit.h | int32_t icu::MeasureUnit::getIndex() const | Internal | (missing)
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::resolveUnitPerUnit(const MeasureUnit&amp;, const MeasureUnit&amp;, bool*) | Internal | (missing)
-| measunit.h | <tt>static</tt> int32_t icu::MeasureUnit::getIndexCount() | Internal | (missing)
-| measunit.h | <tt>static</tt> int32_t icu::MeasureUnit::internalGetIndexForTypeAndSubtype(const char*, const char*) | Internal | (missing)
-| nounit.h | UClassID icu::NoUnit::getDynamicClassID() const | DraftICU 60 | (missing)
-| nounit.h | icu::NoUnit::NoUnit(const NoUnit&amp;) | DraftICU 60 | (missing)
-| nounit.h | icu::NoUnit::~NoUnit() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::base() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::percent() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::permille() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> UClassID icu::NoUnit::getStaticClassID() | DraftICU 60 | (missing)
-| nounit.h | void* icu::NoUnit::clone() const | DraftICU 60 | (missing)
-| uniset.h | const USet* icu::UnicodeSet::toUSet() | StableICU 4.2 | (missing)
-
-## Deprecated
-
-Deprecated or Obsoleted in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getFirstDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getSecondDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| umachine.h | <tt>#define</tt> FALSE | StableICU 2.0 | DeprecatedICU 68
-| umachine.h | <tt>#define</tt> TRUE | StableICU 2.0 | DeprecatedICU 68
-
-## Changed
-
-Changed in ICU 68 (old, new)
-
-
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| bytestrie.h | BytesTrie&amp; icu::BytesTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| bytestrie.h | uint64_t icu::BytesTrie::getState64() const | Draft→StableICU 65
-| listformatter.h | <tt>static</tt> ListFormatter* icu::ListFormatter::createInstance(const Locale&amp;, UListFormatterType, UListFormatterWidth, UErrorCode&amp;) | Draft→StableICU 67
-| localebuilder.h | UBool icu::LocaleBuilder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::addSupportedLocale(const Locale&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::operator=(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDefaultLocale(const Locale*) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDemotionPerDesiredLocale(ULocMatchDemotion) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setFavorSubtag(ULocMatchFavorSubtag) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Iter, Iter) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Locale::Iterator&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesFromListString(StringPiece) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesViaConverter(Iter, Iter, Conv) | Draft→StableICU 65
-| localematcher.h | Locale icu::LocaleMatcher::Result::makeResolvedLocale(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher icu::LocaleMatcher::Builder::build(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher&amp; icu::LocaleMatcher::operator=(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result&amp; icu::LocaleMatcher::Result::operator=(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | UBool icu::LocaleMatcher::Builder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getDesiredLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getSupportedLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatchForListString(StringPiece, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_NONE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_REGION | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_LANGUAGE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_SCRIPT | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::~Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::LocaleMatcher(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::Result(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::~Result() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::~LocaleMatcher() | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getDesiredIndex() const | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getSupportedIndex() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | UBool icu::Locale::Iterator::hasNext() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::RangeIterator&lt; Iter &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::next() override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::Iterator::next() | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::RangeIterator&lt; Iter &gt;::next() override | Draft→StableICU 65
-| locid.h | icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::ConvertingIterator(Iter, Iter, Conv) | Draft→StableICU 65
-| locid.h | icu::Locale::Iterator::~Iterator() | Draft→StableICU 65
-| locid.h | icu::Locale::RangeIterator&lt; Iter &gt;::RangeIterator(Iter, Iter) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getBar() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDecade() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEm() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getMegapixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPascal() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getThermUs() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createBar(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDecade(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEm(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createMegapixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPascal(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createThermUs(UErrorCode&amp;) | Draft→StableICU 65
-| numberformatter.h | StringClass icu::number::FormattedNumber::toDecimalNumber(UErrorCode&amp;) const | Draft→StableICU 65
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getFirstDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getSecondDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_HOUR | Draft→StableICU 65
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_MINUTE | Draft→StableICU 65
-| stringpiece.h | icu::StringPiece::StringPiece(T) | Draft→StableICU 65
-| ucal.h | int32_t ucal_getHostTimeZone(UChar*, int32_t, UErrorCode*) | Draft→StableICU 65
-| ucharstrie.h | UCharsTrie&amp; icu::UCharsTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| ucharstrie.h | uint64_t icu::UCharsTrie::getState64() const | Draft→StableICU 65
-| ulistformatter.h | UListFormatter* ulistfmt_openForType(const char*, UListFormatterType, UListFormatterWidth, UErrorCode*) | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_AND | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_OR | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_UNITS | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_NARROW | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_SHORT | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_WIDE | Draft→StableICU 67
-| uloc.h | UEnumeration* uloc_openAvailableByType(ULocAvailableType, UErrorCode*) | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_DEFAULT | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_ONLY_LEGACY_ALIASES | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_WITH_LEGACY_ALIASES | Draft→StableICU 65
-| umachine.h | <tt>#define</tt> FALSE | StableICU 2.0 | DeprecatedICU 68
-| umachine.h | <tt>#define</tt> TRUE | StableICU 2.0 | DeprecatedICU 68
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_BUNDLE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_DATA_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_RES_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_START | Draft→StableICU 65
-
-## Promoted
-
-Promoted to stable in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| bytestrie.h | BytesTrie&amp; icu::BytesTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| bytestrie.h | uint64_t icu::BytesTrie::getState64() const | Draft→StableICU 65
-| fmtable.h | UFormattable* icu::Formattable::toUFormattable() | (missing) | StableICU 52
-| listformatter.h | <tt>static</tt> ListFormatter* icu::ListFormatter::createInstance(const Locale&amp;, UListFormatterType, UListFormatterWidth, UErrorCode&amp;) | Draft→StableICU 67
-| localebuilder.h | UBool icu::LocaleBuilder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::addSupportedLocale(const Locale&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::operator=(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDefaultLocale(const Locale*) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDemotionPerDesiredLocale(ULocMatchDemotion) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setFavorSubtag(ULocMatchFavorSubtag) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Iter, Iter) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Locale::Iterator&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesFromListString(StringPiece) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesViaConverter(Iter, Iter, Conv) | Draft→StableICU 65
-| localematcher.h | Locale icu::LocaleMatcher::Result::makeResolvedLocale(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher icu::LocaleMatcher::Builder::build(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher&amp; icu::LocaleMatcher::operator=(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result&amp; icu::LocaleMatcher::Result::operator=(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | UBool icu::LocaleMatcher::Builder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getDesiredLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getSupportedLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatchForListString(StringPiece, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_NONE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_REGION | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_LANGUAGE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_SCRIPT | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::~Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::LocaleMatcher(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::Result(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::~Result() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::~LocaleMatcher() | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getDesiredIndex() const | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getSupportedIndex() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | UBool icu::Locale::Iterator::hasNext() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::RangeIterator&lt; Iter &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::next() override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::Iterator::next() | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::RangeIterator&lt; Iter &gt;::next() override | Draft→StableICU 65
-| locid.h | icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::ConvertingIterator(Iter, Iter, Conv) | Draft→StableICU 65
-| locid.h | icu::Locale::Iterator::~Iterator() | Draft→StableICU 65
-| locid.h | icu::Locale::RangeIterator&lt; Iter &gt;::RangeIterator(Iter, Iter) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getBar() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDecade() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEm() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getMegapixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPascal() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getThermUs() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createBar(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDecade(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEm(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createMegapixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPascal(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createThermUs(UErrorCode&amp;) | Draft→StableICU 65
-| numberformatter.h | StringClass icu::number::FormattedNumber::toDecimalNumber(UErrorCode&amp;) const | Draft→StableICU 65
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_HOUR | Draft→StableICU 65
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_MINUTE | Draft→StableICU 65
-| stringpiece.h | icu::StringPiece::StringPiece(T) | Draft→StableICU 65
-| ucal.h | int32_t ucal_getHostTimeZone(UChar*, int32_t, UErrorCode*) | Draft→StableICU 65
-| ucharstrie.h | UCharsTrie&amp; icu::UCharsTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| ucharstrie.h | uint64_t icu::UCharsTrie::getState64() const | Draft→StableICU 65
-| ulistformatter.h | UListFormatter* ulistfmt_openForType(const char*, UListFormatterType, UListFormatterWidth, UErrorCode*) | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_AND | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_OR | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_UNITS | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_NARROW | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_SHORT | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_WIDE | Draft→StableICU 67
-| uloc.h | UEnumeration* uloc_openAvailableByType(ULocAvailableType, UErrorCode*) | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_DEFAULT | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_ONLY_LEGACY_ALIASES | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_WITH_LEGACY_ALIASES | Draft→StableICU 65
-| uniset.h | USet* icu::UnicodeSet::toUSet() | (missing) | StableICU 4.2
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_BUNDLE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_DATA_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_RES_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_START | Draft→StableICU 65
-
-## Added
-
-Added in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| dtitvfmt.h | UDisplayContext icu::DateIntervalFormat::getContext(UDisplayContextType, UErrorCode&amp;) const | (missing) | DraftICU 68
-| dtitvfmt.h | void icu::DateIntervalFormat::setContext(UDisplayContext, UErrorCode&amp;) | (missing) | DraftICU 68
-| dtptngen.h | <tt>static</tt> DateTimePatternGenerator* icu::DateTimePatternGenerator::createInstanceNoStdPat(const Locale&amp;, UErrorCode&amp;) | (missing) | Internal
-| fmtable.h | UFormattable* icu::Formattable::toUFormattable() | (missing) | StableICU 52
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setMaxDistance(const Locale&amp;, const Locale&amp;) | (missing) | DraftICU 68
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setNoDefaultLocale() | (missing) | DraftICU 68
-| localematcher.h | UBool icu::LocaleMatcher::isMatch(const Locale&amp;, const Locale&amp;, UErrorCode&amp;) const | (missing) | DraftICU 68
-| measunit.h | int32_t icu::MeasureUnit::getOffset() const | (missing) | Internal
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getCandela() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDessertSpoon() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDessertSpoonImperial() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDot() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDram() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDrop() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEarthRadius() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getGrain() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getJigger() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getLumen() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPinch() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getQuartImperial() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createCandela(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDessertSpoon(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDessertSpoonImperial(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDot(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDram(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDrop(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEarthRadius(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createGrain(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createJigger(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createLumen(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPinch(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createQuartImperial(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | std::pair&lt; LocalArray&lt; MeasureUnit &gt;, int32_t &gt; icu::MeasureUnit::splitToSingleUnits(UErrorCode&amp;) const | (missing) | DraftICU 68
-| numberformatter.h | Derived icu::number::NumberFormatterSettings&lt; Derived &gt;::usage(StringPiece) const&amp; | (missing) | DraftICU 68
-| numberformatter.h | Derived icu::number::NumberFormatterSettings&lt; Derived &gt;::usage(StringPiece)&amp;&amp; | (missing) | DraftICU 68
-| numberformatter.h | MeasureUnit icu::number::FormattedNumber::getOutputUnit(UErrorCode&amp;) const | (missing) | DraftICU 68
-| numberformatter.h | Usage&amp; icu::number::impl::Usage::operator=(Usage&amp;&amp;) | (missing) | Internal
-| numberformatter.h | Usage&amp; icu::number::impl::Usage::operator=(const Usage&amp;) | (missing) | Internal
-| numberformatter.h | bool icu::number::impl::Usage::isSet() const | (missing) | Internal
-| numberformatter.h | icu::number::impl::Usage::Usage(Usage&amp;&amp;) | (missing) | Internal
-| numberformatter.h | icu::number::impl::Usage::Usage(const Usage&amp;) | (missing) | Internal
-| numberformatter.h | icu::number::impl::Usage::~Usage() | (missing) | Internal
-| numberformatter.h | int16_t icu::number::impl::Usage::length() const | (missing) | Internal
-| numberformatter.h | void icu::number::impl::Usage::set(StringPiece) | (missing) | Internal
-| numberrangeformatter.h | std::pair&lt; StringClass, StringClass &gt; icu::number::FormattedNumberRange::getDecimalNumbers(UErrorCode&amp;) const | (missing) | DraftICU 68
-| plurrule.h | UnicodeString icu::PluralRules::select(const number::FormattedNumberRange&amp;, UErrorCode&amp;) const | (missing) | DraftICU 68
-| plurrule.h | UnicodeString icu::PluralRules::select(const number::impl::UFormattedNumberRangeData*, UErrorCode&amp;) const | (missing) | Internal
-| plurrule.h | int32_t icu::PluralRules::getSamples(const UnicodeString&amp;, FixedDecimal*, int32_t, UErrorCode&amp;) | (missing) | Internal
-| timezone.h | <tt>static</tt> TimeZone* icu::TimeZone::forLocaleOrDefault(const Locale&amp;) | (missing) | Internal
-| ucurr.h | <tt>enum</tt> UCurrNameStyle::UCURR_FORMAL_SYMBOL_NAME | (missing) | DraftICU 68
-| ucurr.h | <tt>enum</tt> UCurrNameStyle::UCURR_VARIANT_SYMBOL_NAME | (missing) | DraftICU 68
-| udateintervalformat.h | UDisplayContext udtitvfmt_getContext(const UDateIntervalFormat*, UDisplayContextType, UErrorCode*) | (missing) | DraftICU 68
-| udateintervalformat.h | void udtitvfmt_setContext(UDateIntervalFormat*, UDisplayContext, UErrorCode*) | (missing) | DraftICU 68
-| umachine.h | <tt>#define</tt> U_DEFINE_FALSE_AND_TRUE | (missing) | InternalICU 68
-| uniset.h | USet* icu::UnicodeSet::toUSet() | (missing) | StableICU 4.2
-| unum.h | <tt>enum</tt> UNumberFormatMinimumGroupingDigits::UNUM_MINIMUM_GROUPING_DIGITS_AUTO | (missing) | DraftICU 68
-| unum.h | <tt>enum</tt> UNumberFormatMinimumGroupingDigits::UNUM_MINIMUM_GROUPING_DIGITS_MIN2 | (missing) | DraftICU 68
-| unumberformatter.h | <tt>enum</tt> UNumberUnitWidth::UNUM_UNIT_WIDTH_FORMAL | (missing) | DraftICU 68
-| unumberformatter.h | <tt>enum</tt> UNumberUnitWidth::UNUM_UNIT_WIDTH_VARIANT | (missing) | DraftICU 68
-| unumberformatter.h | int32_t unumf_resultToDecimalNumber(const UFormattedNumber*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | UFormattedNumberRange* unumrf_openResult(UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | UNumberRangeFormatter* unumrf_openForSkeletonWithCollapseAndIdentityFallback(const UChar*, int32_t, UNumberRangeCollapse, UNumberRangeIdentityFallback, const char*, UParseError*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | UNumberRangeIdentityResult unumrf_resultGetIdentityResult(const UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | const UFormattedValue* unumrf_resultAsValue(const UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | int32_t unumrf_resultGetFirstDecimalNumber(const UFormattedNumberRange*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | int32_t unumrf_resultGetSecondDecimalNumber(const UFormattedNumberRange*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_close(UNumberRangeFormatter*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_closeResult(UFormattedNumberRange*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_formatDecimalRange(const UNumberRangeFormatter*, const char*, int32_t, const char*, int32_t, UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_formatDoubleRange(const UNumberRangeFormatter*, double, double, UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| upluralrules.h | int32_t uplrules_selectForRange(const UPluralRules*, const struct UFormattedNumberRange*, UChar*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-
-## Other
-
-Other existing drafts in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| bytestream.h | void icu::ByteSink::AppendU8(const char*, int32_t) | DraftICU 67 |
-| bytestream.h | void icu::ByteSink::AppendU8(const char8_t*, int32_t) | DraftICU 67 |
-| dtptngen.h | UDateFormatHourCycle icu::DateTimePatternGenerator::getDefaultHourCycle(UErrorCode&amp;) const | DraftICU 67 |
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDirection(ULocMatchDirection) | DraftICU 67 |
-| localematcher.h | <tt>enum</tt> ULocMatchDirection::ULOCMATCH_DIRECTION_ONLY_TWO_WAY | DraftICU 67 |
-| localematcher.h | <tt>enum</tt> ULocMatchDirection::ULOCMATCH_DIRECTION_WITH_ONE_WAY | DraftICU 67 |
-| locid.h | void icu::Locale::canonicalize(UErrorCode&amp;) | DraftICU 67 |
-| measfmt.h | void icu::MeasureFormat::parseObject(const UnicodeString&amp;, Formattable&amp;, ParsePosition&amp;) const | DraftICU 53 |
-| measunit.h | MeasureUnit icu::MeasureUnit::product(const MeasureUnit&amp;, UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit icu::MeasureUnit::reciprocal(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit icu::MeasureUnit::withDimensionality(int32_t, UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit icu::MeasureUnit::withSIPrefix(UMeasureSIPrefix, UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit&amp; icu::MeasureUnit::operator=(MeasureUnit&amp;&amp;) noexcept | DraftICU 67 |
-| measunit.h | UMeasureSIPrefix icu::MeasureUnit::getSIPrefix(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | UMeasureUnitComplexity icu::MeasureUnit::getComplexity(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | const char* icu::MeasureUnit::getIdentifier() const | DraftICU 67 |
-| measunit.h | icu::MeasureUnit::MeasureUnit(MeasureUnit&amp;&amp;) noexcept | DraftICU 67 |
-| measunit.h | int32_t icu::MeasureUnit::getDimensionality(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::forIdentifier(StringPiece, UErrorCode&amp;) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(const char8_t*) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(const char8_t*, int32_t) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(const std::u8string&amp;) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(std::nullptr_t) | DraftICU 67 |
-| stringpiece.h | int32_t icu::StringPiece::compare(StringPiece) | DraftICU 67 |
-| stringpiece.h | int32_t icu::StringPiece::find(StringPiece, int32_t) | DraftICU 67 |
-| stringpiece.h | void icu::StringPiece::set(const char8_t*) | DraftICU 67 |
-| stringpiece.h | void icu::StringPiece::set(const char8_t*, int32_t) | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_11 | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_12 | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_23 | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_24 | DraftICU 67 |
-| udateintervalformat.h | void udtitvfmt_formatCalendarToResult(const UDateIntervalFormat*, UCalendar*, UCalendar*, UFormattedDateInterval*, UErrorCode*) | DraftICU 67 |
-| udateintervalformat.h | void udtitvfmt_formatToResult(const UDateIntervalFormat*, UDate, UDate, UFormattedDateInterval*, UErrorCode*) | DraftICU 67 |
-| udatpg.h | UDateFormatHourCycle udatpg_getDefaultHourCycle(const UDateTimePatternGenerator*, UErrorCode*) | DraftICU 67 |
-| uregex.h | <tt>enum</tt> URegexpFlag::UREGEX_CANON_EQ | DraftICU 2.4 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_BREAK_ENGINE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_CHARACTER | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_LINE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_SENTENCE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_TITLE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_WORD | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_START | DraftICU 67 |
-
-## Simplifications
-
-This section shows cases where the signature was "simplified" for the sake of comparison. The simplified form is in bold, followed by
- all possible variations in "original" form.
-
-
-## Colophon
-
-Contents generated by StableAPI tool on Fri Oct 23 11:32:42 PDT 2020
-
-Copyright © 2019 and later: Unicode, Inc. and others.
-License & terms of use: http://www.unicode.org/copyright.html
- \ No newline at end of file
diff --git a/thirdparty/icu4c/common/bytestriebuilder.cpp b/thirdparty/icu4c/common/bytestriebuilder.cpp
index ec1ab7d8f5..28256f272a 100644
--- a/thirdparty/icu4c/common/bytestriebuilder.cpp
+++ b/thirdparty/icu4c/common/bytestriebuilder.cpp
@@ -474,31 +474,39 @@ BytesTrieBuilder::writeDeltaTo(int32_t jumpTarget) {
U_ASSERT(i>=0);
if(i<=BytesTrie::kMaxOneByteDelta) {
return write(i);
+ } else {
+ char intBytes[5];
+ return write(intBytes, internalEncodeDelta(i, intBytes));
}
- char intBytes[5];
- int32_t length;
+}
+
+int32_t
+BytesTrieBuilder::internalEncodeDelta(int32_t i, char intBytes[]) {
+ U_ASSERT(i>=0);
+ if(i<=BytesTrie::kMaxOneByteDelta) {
+ intBytes[0]=(char)i;
+ return 1;
+ }
+ int32_t length=1;
if(i<=BytesTrie::kMaxTwoByteDelta) {
intBytes[0]=(char)(BytesTrie::kMinTwoByteDeltaLead+(i>>8));
- length=1;
} else {
if(i<=BytesTrie::kMaxThreeByteDelta) {
intBytes[0]=(char)(BytesTrie::kMinThreeByteDeltaLead+(i>>16));
- length=2;
} else {
if(i<=0xffffff) {
intBytes[0]=(char)BytesTrie::kFourByteDeltaLead;
- length=3;
} else {
intBytes[0]=(char)BytesTrie::kFiveByteDeltaLead;
intBytes[1]=(char)(i>>24);
- length=4;
+ length=2;
}
- intBytes[1]=(char)(i>>16);
+ intBytes[length++]=(char)(i>>16);
}
- intBytes[1]=(char)(i>>8);
+ intBytes[length++]=(char)(i>>8);
}
intBytes[length++]=(char)i;
- return write(intBytes, length);
+ return length;
}
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/charstr.cpp b/thirdparty/icu4c/common/charstr.cpp
index 318a185b3f..c35622882c 100644
--- a/thirdparty/icu4c/common/charstr.cpp
+++ b/thirdparty/icu4c/common/charstr.cpp
@@ -14,6 +14,8 @@
* created by: Markus W. Scherer
*/
+#include <cstdlib>
+
#include "unicode/utypes.h"
#include "unicode/putil.h"
#include "charstr.h"
@@ -141,6 +143,38 @@ CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &error
return *this;
}
+CharString &CharString::appendNumber(int32_t number, UErrorCode &status) {
+ if (number < 0) {
+ this->append('-', status);
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ }
+
+ if (number == 0) {
+ this->append('0', status);
+ return *this;
+ }
+
+ int32_t numLen = 0;
+ while (number != 0) {
+ int32_t residue = number % 10;
+ number /= 10;
+ this->append(std::abs(residue) + '0', status);
+ numLen++;
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ }
+
+ int32_t start = this->length() - numLen, end = this->length() - 1;
+ while(start < end) {
+ std::swap(this->data()[start++], this->data()[end--]);
+ }
+
+ return *this;
+}
+
char *CharString::getAppendBuffer(int32_t minCapacity,
int32_t desiredCapacityHint,
int32_t &resultCapacity,
diff --git a/thirdparty/icu4c/common/charstr.h b/thirdparty/icu4c/common/charstr.h
index 6619faac61..175acd1c0a 100644
--- a/thirdparty/icu4c/common/charstr.h
+++ b/thirdparty/icu4c/common/charstr.h
@@ -127,6 +127,9 @@ public:
return append(s.data(), s.length(), errorCode);
}
CharString &append(const char *s, int32_t sLength, UErrorCode &status);
+
+ CharString &appendNumber(int32_t number, UErrorCode &status);
+
/**
* Returns a writable buffer for appending and writes the buffer's capacity to
* resultCapacity. Guarantees resultCapacity>=minCapacity if U_SUCCESS().
diff --git a/thirdparty/icu4c/common/cmemory.h b/thirdparty/icu4c/common/cmemory.h
index a9d9424b4e..f03b7dcce6 100644
--- a/thirdparty/icu4c/common/cmemory.h
+++ b/thirdparty/icu4c/common/cmemory.h
@@ -31,14 +31,63 @@
#include <stddef.h>
#include <string.h>
#include "unicode/localpointer.h"
+#include "uassert.h"
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
#include <stdio.h>
#endif
-
-#define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size)
-#define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size)
+// uprv_memcpy and uprv_memmove
+#if defined(__clang__)
+#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("clang diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("clang diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#elif defined(__GNUC__)
+#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("GCC diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("GCC diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#else
+#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#endif
/**
* \def UPRV_LENGTHOF
diff --git a/thirdparty/icu4c/common/dictbe.cpp b/thirdparty/icu4c/common/dictbe.cpp
index b42cdf03fa..44285755f3 100644
--- a/thirdparty/icu4c/common/dictbe.cpp
+++ b/thirdparty/icu4c/common/dictbe.cpp
@@ -265,13 +265,9 @@ ThaiBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % THAI_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound%THAI_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound%THAI_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
@@ -503,13 +499,9 @@ LaoBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % LAO_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound%LAO_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound%LAO_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
@@ -699,13 +691,9 @@ BurmeseBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % BURMESE_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound%BURMESE_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound%BURMESE_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
@@ -908,13 +896,9 @@ KhmerBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % KHMER_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound % KHMER_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound % KHMER_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
diff --git a/thirdparty/icu4c/common/edits.cpp b/thirdparty/icu4c/common/edits.cpp
index 95f0c19a72..92ca36fb5d 100644
--- a/thirdparty/icu4c/common/edits.cpp
+++ b/thirdparty/icu4c/common/edits.cpp
@@ -86,6 +86,7 @@ Edits &Edits::moveArray(Edits &src) U_NOEXCEPT {
}
Edits &Edits::operator=(const Edits &other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
length = other.length;
delta = other.delta;
numChanges = other.numChanges;
diff --git a/thirdparty/icu4c/common/filteredbrk.cpp b/thirdparty/icu4c/common/filteredbrk.cpp
index c07128cbce..25080f9d33 100644
--- a/thirdparty/icu4c/common/filteredbrk.cpp
+++ b/thirdparty/icu4c/common/filteredbrk.cpp
@@ -20,6 +20,7 @@
#include "ubrkimpl.h" // U_ICUDATA_BRKITR
#include "uvector.h"
#include "cmemory.h"
+#include "umutex.h"
U_NAMESPACE_BEGIN
@@ -139,13 +140,30 @@ class SimpleFilteredSentenceBreakData : public UMemory {
public:
SimpleFilteredSentenceBreakData(UCharsTrie *forwards, UCharsTrie *backwards )
: fForwardsPartialTrie(forwards), fBackwardsTrie(backwards), refcount(1) { }
- SimpleFilteredSentenceBreakData *incr() { refcount++; return this; }
- SimpleFilteredSentenceBreakData *decr() { if((--refcount) <= 0) delete this; return 0; }
- virtual ~SimpleFilteredSentenceBreakData();
+ SimpleFilteredSentenceBreakData *incr() {
+ umtx_atomic_inc(&refcount);
+ return this;
+ }
+ SimpleFilteredSentenceBreakData *decr() {
+ if(umtx_atomic_dec(&refcount) <= 0) {
+ delete this;
+ }
+ return 0;
+ }
+ virtual ~SimpleFilteredSentenceBreakData();
+
+ bool hasForwardsPartialTrie() const { return fForwardsPartialTrie.isValid(); }
+ bool hasBackwardsTrie() const { return fBackwardsTrie.isValid(); }
- LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M."
- LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs.
- int32_t refcount;
+ const UCharsTrie &getForwardsPartialTrie() const { return *fForwardsPartialTrie; }
+ const UCharsTrie &getBackwardsTrie() const { return *fBackwardsTrie; }
+
+private:
+ // These tries own their data arrays.
+ // They are shared and must therefore not be modified.
+ LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M."
+ LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs.
+ u_atomic_int32_t refcount;
};
SimpleFilteredSentenceBreakData::~SimpleFilteredSentenceBreakData() {}
@@ -244,7 +262,13 @@ SimpleFilteredSentenceBreakIterator::SimpleFilteredSentenceBreakIterator(BreakIt
fData(new SimpleFilteredSentenceBreakData(forwards, backwards)),
fDelegate(adopt)
{
- // all set..
+ if (fData == nullptr) {
+ delete forwards;
+ delete backwards;
+ if (U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
}
SimpleFilteredSentenceBreakIterator::~SimpleFilteredSentenceBreakIterator() {
@@ -261,59 +285,62 @@ SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) {
int32_t bestValue = -1;
// loops while 'n' points to an exception.
utext_setNativeIndex(fText.getAlias(), n); // from n..
- fData->fBackwardsTrie->reset();
- UChar32 uch;
//if(debug2) u_printf(" n@ %d\n", n);
// Assume a space is following the '.' (so we handle the case: "Mr. /Brown")
- if((uch=utext_previous32(fText.getAlias()))==(UChar32)0x0020) { // TODO: skip a class of chars here??
+ if(utext_previous32(fText.getAlias())==u' ') { // TODO: skip a class of chars here??
// TODO only do this the 1st time?
//if(debug2) u_printf("skipping prev: |%C| \n", (UChar)uch);
} else {
//if(debug2) u_printf("not skipping prev: |%C| \n", (UChar)uch);
- uch = utext_next32(fText.getAlias());
+ utext_next32(fText.getAlias());
//if(debug2) u_printf(" -> : |%C| \n", (UChar)uch);
}
- UStringTrieResult r = USTRINGTRIE_INTERMEDIATE_VALUE;
-
- while((uch=utext_previous32(fText.getAlias()))!=U_SENTINEL && // more to consume backwards and..
- USTRINGTRIE_HAS_NEXT(r=fData->fBackwardsTrie->nextForCodePoint(uch))) {// more in the trie
- if(USTRINGTRIE_HAS_VALUE(r)) { // remember the best match so far
- bestPosn = utext_getNativeIndex(fText.getAlias());
- bestValue = fData->fBackwardsTrie->getValue();
- }
- //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias()));
+ {
+ // Do not modify the shared trie!
+ UCharsTrie iter(fData->getBackwardsTrie());
+ UChar32 uch;
+ while((uch=utext_previous32(fText.getAlias()))!=U_SENTINEL) { // more to consume backwards
+ UStringTrieResult r = iter.nextForCodePoint(uch);
+ if(USTRINGTRIE_HAS_VALUE(r)) { // remember the best match so far
+ bestPosn = utext_getNativeIndex(fText.getAlias());
+ bestValue = iter.getValue();
+ }
+ if(!USTRINGTRIE_HAS_NEXT(r)) {
+ break;
+ }
+ //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias()));
+ }
}
- if(USTRINGTRIE_MATCHES(r)) { // exact match?
- //if(debug2) u_printf("rev<?/%C/?end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
- bestValue = fData->fBackwardsTrie->getValue();
- bestPosn = utext_getNativeIndex(fText.getAlias());
- //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
- }
+ //if(bestValue >= 0) {
+ //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
+ //}
if(bestPosn>=0) {
//if(debug2) u_printf("rev< /%C/ end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
//if(USTRINGTRIE_MATCHES(r)) { // matched - so, now what?
- //int32_t bestValue = fBackwardsTrie->getValue();
+ //int32_t bestValue = iter.getValue();
////if(debug2) u_printf("rev< /%C/ matched, skip..%d bestValue=%d\n", (UChar)uch, r, bestValue);
if(bestValue == kMATCH) { // exact match!
//if(debug2) u_printf(" exact backward match\n");
return kExceptionHere; // See if the next is another exception.
} else if(bestValue == kPARTIAL
- && fData->fForwardsPartialTrie.isValid()) { // make sure there's a forward trie
+ && fData->hasForwardsPartialTrie()) { // make sure there's a forward trie
//if(debug2) u_printf(" partial backward match\n");
// We matched the "Ph." in "Ph.D." - now we need to run everything through the forwards trie
// to see if it matches something going forward.
- fData->fForwardsPartialTrie->reset();
UStringTrieResult rfwd = USTRINGTRIE_INTERMEDIATE_VALUE;
utext_setNativeIndex(fText.getAlias(), bestPosn); // hope that's close ..
//if(debug2) u_printf("Retrying at %d\n", bestPosn);
+ // Do not modify the shared trie!
+ UCharsTrie iter(fData->getForwardsPartialTrie());
+ UChar32 uch;
while((uch=utext_next32(fText.getAlias()))!=U_SENTINEL &&
- USTRINGTRIE_HAS_NEXT(rfwd=fData->fForwardsPartialTrie->nextForCodePoint(uch))) {
+ USTRINGTRIE_HAS_NEXT(rfwd=iter.nextForCodePoint(uch))) {
//if(debug2) u_printf("fwd> /%C/ cont?%d @%d\n", (UChar)uch, rfwd, utext_getNativeIndex(fText.getAlias()));
}
if(USTRINGTRIE_MATCHES(rfwd)) {
@@ -339,7 +366,7 @@ SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) {
int32_t
SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) {
if(n == UBRK_DONE || // at end or
- fData->fBackwardsTrie.isNull()) { // .. no backwards table loaded == no exceptions
+ !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions
return n;
}
// OK, do we need to break here?
@@ -369,7 +396,7 @@ SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) {
int32_t
SimpleFilteredSentenceBreakIterator::internalPrev(int32_t n) {
if(n == 0 || n == UBRK_DONE || // at end or
- fData->fBackwardsTrie.isNull()) { // .. no backwards table loaded == no exceptions
+ !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions
return n;
}
// OK, do we need to break here?
@@ -420,7 +447,7 @@ SimpleFilteredSentenceBreakIterator::previous(void) {
UBool SimpleFilteredSentenceBreakIterator::isBoundary(int32_t offset) {
if (!fDelegate->isBoundary(offset)) return false; // no break to suppress
- if (fData->fBackwardsTrie.isNull()) return true; // no data = no suppressions
+ if (!fData->hasBackwardsTrie()) return true; // no data = no suppressions
UErrorCode status = U_ZERO_ERROR;
resetState(status);
diff --git a/thirdparty/icu4c/common/hash.h b/thirdparty/icu4c/common/hash.h
index f02cb7087a..b927ddb3c3 100644
--- a/thirdparty/icu4c/common/hash.h
+++ b/thirdparty/icu4c/common/hash.h
@@ -85,16 +85,22 @@ public:
inline int32_t puti(const UnicodeString& key, int32_t value, UErrorCode& status);
+ inline int32_t putiAllowZero(const UnicodeString& key, int32_t value, UErrorCode& status);
+
inline void* get(const UnicodeString& key) const;
inline int32_t geti(const UnicodeString& key) const;
+ inline int32_t getiAndFound(const UnicodeString& key, UBool &found) const;
+
inline void* remove(const UnicodeString& key);
inline int32_t removei(const UnicodeString& key);
inline void removeAll(void);
+ inline UBool containsKey(const UnicodeString& key) const;
+
inline const UHashElement* find(const UnicodeString& key) const;
/**
@@ -203,6 +209,11 @@ inline int32_t Hashtable::puti(const UnicodeString& key, int32_t value, UErrorCo
return uhash_puti(hash, new UnicodeString(key), value, &status);
}
+inline int32_t Hashtable::putiAllowZero(const UnicodeString& key, int32_t value,
+ UErrorCode& status) {
+ return uhash_putiAllowZero(hash, new UnicodeString(key), value, &status);
+}
+
inline void* Hashtable::get(const UnicodeString& key) const {
return uhash_get(hash, &key);
}
@@ -211,6 +222,10 @@ inline int32_t Hashtable::geti(const UnicodeString& key) const {
return uhash_geti(hash, &key);
}
+inline int32_t Hashtable::getiAndFound(const UnicodeString& key, UBool &found) const {
+ return uhash_getiAndFound(hash, &key, &found);
+}
+
inline void* Hashtable::remove(const UnicodeString& key) {
return uhash_remove(hash, &key);
}
@@ -219,6 +234,10 @@ inline int32_t Hashtable::removei(const UnicodeString& key) {
return uhash_removei(hash, &key);
}
+inline UBool Hashtable::containsKey(const UnicodeString& key) const {
+ return uhash_containsKey(hash, &key);
+}
+
inline const UHashElement* Hashtable::find(const UnicodeString& key) const {
return uhash_find(hash, &key);
}
diff --git a/thirdparty/icu4c/common/localematcher.cpp b/thirdparty/icu4c/common/localematcher.cpp
index 5795cbf87e..132aee290e 100644
--- a/thirdparty/icu4c/common/localematcher.cpp
+++ b/thirdparty/icu4c/common/localematcher.cpp
@@ -345,9 +345,8 @@ UBool compareLSRs(const UHashTok t1, const UHashTok t2) {
int32_t LocaleMatcher::putIfAbsent(const LSR &lsr, int32_t i, int32_t suppLength,
UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return suppLength; }
- int32_t index = uhash_geti(supportedLsrToIndex, &lsr);
- if (index == 0) {
- uhash_puti(supportedLsrToIndex, const_cast<LSR *>(&lsr), i + 1, &errorCode);
+ if (!uhash_containsKey(supportedLsrToIndex, &lsr)) {
+ uhash_putiAllowZero(supportedLsrToIndex, const_cast<LSR *>(&lsr), i, &errorCode);
if (U_SUCCESS(errorCode)) {
supportedLSRs[suppLength] = &lsr;
supportedIndexes[suppLength++] = i;
@@ -685,12 +684,11 @@ int32_t LocaleMatcher::getBestSuppIndex(LSR desiredLSR, LocaleLsrIterator *remai
int32_t bestSupportedLsrIndex = -1;
for (int32_t bestShiftedDistance = LocaleDistance::shiftDistance(thresholdDistance);;) {
// Quick check for exact maximized LSR.
- // Returns suppIndex+1 where 0 means not found.
if (supportedLsrToIndex != nullptr) {
desiredLSR.setHashCode();
- int32_t index = uhash_geti(supportedLsrToIndex, &desiredLSR);
- if (index != 0) {
- int32_t suppIndex = index - 1;
+ UBool found = false;
+ int32_t suppIndex = uhash_getiAndFound(supportedLsrToIndex, &desiredLSR, &found);
+ if (found) {
if (remainingIter != nullptr) {
remainingIter->rememberCurrent(desiredIndex, errorCode);
}
diff --git a/thirdparty/icu4c/common/localeprioritylist.cpp b/thirdparty/icu4c/common/localeprioritylist.cpp
index 8916b121be..4455eedb75 100644
--- a/thirdparty/icu4c/common/localeprioritylist.cpp
+++ b/thirdparty/icu4c/common/localeprioritylist.cpp
@@ -187,17 +187,18 @@ bool LocalePriorityList::add(const Locale &locale, int32_t weight, UErrorCode &e
if (U_FAILURE(errorCode)) { return false; }
}
LocalPointer<Locale> clone;
- int32_t index = uhash_geti(map, &locale);
- if (index != 0) {
+ UBool found = false;
+ int32_t index = uhash_getiAndFound(map, &locale, &found);
+ if (found) {
// Duplicate: Remove the old item and append it anew.
- LocaleAndWeight &lw = list->array[index - 1];
+ LocaleAndWeight &lw = list->array[index];
clone.adoptInstead(lw.locale);
lw.locale = nullptr;
lw.weight = 0;
++numRemoved;
}
if (weight <= 0) { // do not add q=0
- if (index != 0) {
+ if (found) {
// Not strictly necessary but cleaner.
uhash_removei(map, &locale);
}
@@ -217,7 +218,7 @@ bool LocalePriorityList::add(const Locale &locale, int32_t weight, UErrorCode &e
return false;
}
}
- uhash_puti(map, clone.getAlias(), listLength + 1, &errorCode);
+ uhash_putiAllowZero(map, clone.getAlias(), listLength, &errorCode);
if (U_FAILURE(errorCode)) { return false; }
LocaleAndWeight &lw = list->array[listLength];
lw.locale = clone.orphan();
diff --git a/thirdparty/icu4c/common/locdispnames.cpp b/thirdparty/icu4c/common/locdispnames.cpp
index 47c0667417..96af3f9aa8 100644
--- a/thirdparty/icu4c/common/locdispnames.cpp
+++ b/thirdparty/icu4c/common/locdispnames.cpp
@@ -698,7 +698,7 @@ uloc_getDisplayName(const char *locale,
} /* end switch */
if (len>0) {
- /* we addeed a component, so add separator and write it if there's room. */
+ /* we added a component, so add separator and write it if there's room. */
if(len+sepLen<=cap) {
const UChar * plimit = p + len;
for (; p < plimit; p++) {
diff --git a/thirdparty/icu4c/common/locid.cpp b/thirdparty/icu4c/common/locid.cpp
index 874e4a7055..0d506293a9 100644
--- a/thirdparty/icu4c/common/locid.cpp
+++ b/thirdparty/icu4c/common/locid.cpp
@@ -254,7 +254,7 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
Locale::~Locale()
{
- if (baseName != fullName) {
+ if ((baseName != fullName) && (baseName != fullNameBuffer)) {
uprv_free(baseName);
}
baseName = NULL;
@@ -466,7 +466,7 @@ Locale& Locale::operator=(const Locale& other) {
}
Locale& Locale::operator=(Locale&& other) U_NOEXCEPT {
- if (baseName != fullName) uprv_free(baseName);
+ if ((baseName != fullName) && (baseName != fullNameBuffer)) uprv_free(baseName);
if (fullName != fullNameBuffer) uprv_free(fullName);
if (other.fullName == other.fullNameBuffer) {
@@ -524,7 +524,7 @@ static const char* const KNOWN_CANONICALIZED[] = {
"km", "km_KH", "kn", "kn_IN", "ko", "ko_KR", "ky", "ky_KG", "lo", "lo_LA",
"lt", "lt_LT", "lv", "lv_LV", "mk", "mk_MK", "ml", "ml_IN", "mn", "mn_MN",
"mr", "mr_IN", "ms", "ms_MY", "my", "my_MM", "nb", "nb_NO", "ne", "ne_NP",
- "nl", "nl_NL", "or", "or_IN", "pa", "pa_IN", "pl", "pl_PL", "ps", "ps_AF",
+ "nl", "nl_NL", "no", "or", "or_IN", "pa", "pa_IN", "pl", "pl_PL", "ps", "ps_AF",
"pt", "pt_BR", "pt_PT", "ro", "ro_RO", "ru", "ru_RU", "sd", "sd_IN", "si",
"si_LK", "sk", "sk_SK", "sl", "sl_SI", "so", "so_SO", "sq", "sq_AL", "sr",
"sr_Cyrl_RS", "sr_Latn", "sr_RS", "sv", "sv_SE", "sw", "sw_TZ", "ta",
@@ -627,6 +627,17 @@ private:
LocalMemory<const char*>& types,
LocalMemory<int32_t>& replacementIndexes,
int32_t &length, UErrorCode &status);
+
+ // Read the subdivisionAlias data from alias to
+ // strings+types+replacementIndexes
+ // Allocate length items for types, to store the type field.
+ // Allocate length items for replacementIndexes,
+ // to store the index in the strings for the replacement variant.
+ void readSubdivisionAlias(UResourceBundle* alias,
+ UniqueCharStrings* strings,
+ LocalMemory<const char*>& types,
+ LocalMemory<int32_t>& replacementIndexes,
+ int32_t &length, UErrorCode &status);
};
/**
@@ -647,6 +658,7 @@ public:
const CharStringMap& scriptMap() const { return script; }
const CharStringMap& territoryMap() const { return territory; }
const CharStringMap& variantMap() const { return variant; }
+ const CharStringMap& subdivisionMap() const { return subdivision; }
static void U_CALLCONV loadData(UErrorCode &status);
static UBool U_CALLCONV cleanup();
@@ -658,11 +670,13 @@ private:
CharStringMap scriptMap,
CharStringMap territoryMap,
CharStringMap variantMap,
+ CharStringMap subdivisionMap,
CharString* strings)
: language(std::move(languageMap)),
script(std::move(scriptMap)),
territory(std::move(territoryMap)),
variant(std::move(variantMap)),
+ subdivision(std::move(subdivisionMap)),
strings(strings) {
}
@@ -676,6 +690,7 @@ private:
CharStringMap script;
CharStringMap territory;
CharStringMap variant;
+ CharStringMap subdivision;
CharString* strings;
friend class AliasDataBuilder;
@@ -867,6 +882,34 @@ AliasDataBuilder::readVariantAlias(
}
/**
+ * Read the subdivisionAlias data from alias to strings+types+replacementIndexes.
+ * Allocate length items for types, to store the type field. Allocate length
+ * items for replacementIndexes, to store the index in the strings for the
+ * replacement regions.
+ */
+void
+AliasDataBuilder::readSubdivisionAlias(
+ UResourceBundle* alias,
+ UniqueCharStrings* strings,
+ LocalMemory<const char*>& types,
+ LocalMemory<int32_t>& replacementIndexes,
+ int32_t &length,
+ UErrorCode &status)
+{
+ return readAlias(
+ alias, strings, types, replacementIndexes, length,
+#if U_DEBUG
+ [](const char* type) {
+ U_ASSERT(uprv_strlen(type) >= 3 && uprv_strlen(type) <= 8);
+ },
+#else
+ [](const char*) {},
+#endif
+ [](const UnicodeString&) { },
+ status);
+}
+
+/**
* Initializes the alias data from the ICU resource bundles. The alias data
* contains alias of language, country, script and variants.
*
@@ -905,12 +948,14 @@ AliasDataBuilder::build(UErrorCode &status) {
ures_getByKey(metadataAlias.getAlias(), "territory", nullptr, &status));
LocalUResourceBundlePointer variantAlias(
ures_getByKey(metadataAlias.getAlias(), "variant", nullptr, &status));
+ LocalUResourceBundlePointer subdivisionAlias(
+ ures_getByKey(metadataAlias.getAlias(), "subdivision", nullptr, &status));
if (U_FAILURE(status)) {
return nullptr;
}
int32_t languagesLength = 0, scriptLength = 0, territoryLength = 0,
- variantLength = 0;
+ variantLength = 0, subdivisionLength = 0;
// Read the languageAlias into languageTypes, languageReplacementIndexes
// and strings
@@ -955,6 +1000,16 @@ AliasDataBuilder::build(UErrorCode &status) {
variantReplacementIndexes,
variantLength, status);
+ // Read the subdivisionAlias into subdivisionTypes, subdivisionReplacementIndexes
+ // and strings
+ LocalMemory<const char*> subdivisionTypes;
+ LocalMemory<int32_t> subdivisionReplacementIndexes;
+ readSubdivisionAlias(subdivisionAlias.getAlias(),
+ &strings,
+ subdivisionTypes,
+ subdivisionReplacementIndexes,
+ subdivisionLength, status);
+
if (U_FAILURE(status)) {
return nullptr;
}
@@ -994,6 +1049,14 @@ AliasDataBuilder::build(UErrorCode &status) {
status);
}
+ // Build the subdivisionMap from subdivisionTypes & subdivisionReplacementIndexes.
+ CharStringMap subdivisionMap(2, status);
+ for (int32_t i = 0; U_SUCCESS(status) && i < subdivisionLength; i++) {
+ subdivisionMap.put(subdivisionTypes[i],
+ strings.get(subdivisionReplacementIndexes[i]),
+ status);
+ }
+
if (U_FAILURE(status)) {
return nullptr;
}
@@ -1004,6 +1067,7 @@ AliasDataBuilder::build(UErrorCode &status) {
std::move(scriptMap),
std::move(territoryMap),
std::move(variantMap),
+ std::move(subdivisionMap),
strings.orphanCharStrings());
if (data == nullptr) {
@@ -1105,6 +1169,14 @@ private:
// Replace by using variantAlias.
bool replaceVariant(UErrorCode& status);
+
+ // Replace by using subdivisionAlias.
+ bool replaceSubdivision(StringPiece subdivision,
+ CharString& output, UErrorCode& status);
+
+ // Replace transformed extensions.
+ bool replaceTransformedExtensions(
+ CharString& transformedExtensions, CharString& output, UErrorCode& status);
};
CharString&
@@ -1294,7 +1366,6 @@ AliasReplacer::replaceLanguage(
}
}
if (replacedExtensions != nullptr) {
- // TODO(ICU-21292)
// DO NOTHING
// UTS35 does not specifiy what should we do if we have extensions in the
// replacement. Currently we know only the following 4 "BCP47 LegacyRules" have
@@ -1435,6 +1506,106 @@ AliasReplacer::replaceVariant(UErrorCode& status)
return false;
}
+bool
+AliasReplacer::replaceSubdivision(
+ StringPiece subdivision, CharString& output, UErrorCode& status)
+{
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ const char *replacement = data->subdivisionMap().get(subdivision.data());
+ if (replacement != nullptr) {
+ const char* firstSpace = uprv_strchr(replacement, ' ');
+ // Found replacement data for this subdivision.
+ size_t len = (firstSpace != nullptr) ?
+ (firstSpace - replacement) : uprv_strlen(replacement);
+ if (2 <= len && len <= 8) {
+ output.append(replacement, (int32_t)len, status);
+ if (2 == len) {
+ // Add 'zzzz' based on changes to UTS #35 for CLDR-14312.
+ output.append("zzzz", 4, status);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+AliasReplacer::replaceTransformedExtensions(
+ CharString& transformedExtensions, CharString& output, UErrorCode& status)
+{
+ // The content of the transformedExtensions will be modified in this
+ // function to NULL-terminating (tkey-tvalue) pairs.
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ int32_t len = transformedExtensions.length();
+ const char* str = transformedExtensions.data();
+ const char* tkey = ultag_getTKeyStart(str);
+ int32_t tlangLen = (tkey == str) ? 0 :
+ ((tkey == nullptr) ? len : static_cast<int32_t>((tkey - str - 1)));
+ CharStringByteSink sink(&output);
+ if (tlangLen > 0) {
+ Locale tlang = LocaleBuilder()
+ .setLanguageTag(StringPiece(str, tlangLen))
+ .build(status);
+ tlang.canonicalize(status);
+ tlang.toLanguageTag(sink, status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ T_CString_toLowerCase(output.data());
+ }
+ if (tkey != nullptr) {
+ // We need to sort the tfields by tkey
+ UVector tfields(status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ do {
+ const char* tvalue = uprv_strchr(tkey, '-');
+ if (tvalue == nullptr) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ const char* nextTKey = ultag_getTKeyStart(tvalue);
+ if (nextTKey != nullptr) {
+ *((char*)(nextTKey-1)) = '\0'; // NULL terminate tvalue
+ }
+ tfields.insertElementAt((void*)tkey, tfields.size(), status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ tkey = nextTKey;
+ } while (tkey != nullptr);
+ tfields.sort([](UElement e1, UElement e2) -> int8_t {
+ // uprv_strcmp return int and in some platform, such as arm64-v8a,
+ // it may return positive values > 127 which cause the casted value
+ // of int8_t negative.
+ int res = uprv_strcmp(
+ (const char*)e1.pointer, (const char*)e2.pointer);
+ return (res == 0) ? 0 : ((res > 0) ? 1 : -1);
+ }, status);
+ for (int32_t i = 0; i < tfields.size(); i++) {
+ if (output.length() > 0) {
+ output.append('-', status);
+ }
+ const char* tfield = (const char*) tfields.elementAt(i);
+ const char* tvalue = uprv_strchr(tfield, '-');
+ // Split the "tkey-tvalue" pair string so that we can canonicalize the tvalue.
+ U_ASSERT(tvalue != nullptr);
+ *((char*)tvalue++) = '\0'; // NULL terminate tkey
+ output.append(tfield, status).append('-', status);
+ const char* bcpTValue = ulocimp_toBcpType(tfield, tvalue, nullptr, nullptr);
+ output.append((bcpTValue == nullptr) ? tvalue : bcpTValue, status);
+ }
+ }
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ return true;
+}
+
CharString&
AliasReplacer::outputToString(
CharString& out, UErrorCode status)
@@ -1453,8 +1624,12 @@ AliasReplacer::outputToString(
out.append(SEP_CHAR, status);
}
variants.sort([](UElement e1, UElement e2) -> int8_t {
- return uprv_strcmp(
+ // uprv_strcmp return int and in some platform, such as arm64-v8a,
+ // it may return positive values > 127 which cause the casted value
+ // of int8_t negative.
+ int res = uprv_strcmp(
(const char*)e1.pointer, (const char*)e2.pointer);
+ return (res == 0) ? 0 : ((res > 0) ? 1 : -1);
}, status);
int32_t variantsStart = out.length();
for (int32_t i = 0; i < variants.size(); i++) {
@@ -1497,7 +1672,6 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
region = nullptr;
}
const char* variantsStr = locale.getVariant();
- const char* extensionsStr = locale_getKeywordsStart(locale.getName());
CharString variantsBuff(variantsStr, -1, status);
if (!variantsBuff.isEmpty()) {
if (U_FAILURE(status)) { return false; }
@@ -1516,8 +1690,12 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
// Sort the variants
variants.sort([](UElement e1, UElement e2) -> int8_t {
- return uprv_strcmp(
+ // uprv_strcmp return int and in some platform, such as arm64-v8a,
+ // it may return positive values > 127 which cause the casted value
+ // of int8_t negative.
+ int res = uprv_strcmp(
(const char*)e1.pointer, (const char*)e2.pointer);
+ return (res == 0) ? 0 : ((res > 0) ? 1 : -1);
}, status);
// A changed count to assert when loop too many times.
@@ -1561,11 +1739,52 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
if (U_FAILURE(status)) { return false; }
// Nothing changed and we know the order of the vaiants are not change
// because we have no variant or only one.
- if (changed == 0 && variants.size() <= 1) {
+ const char* extensionsStr = locale_getKeywordsStart(locale.getName());
+ if (changed == 0 && variants.size() <= 1 && extensionsStr == nullptr) {
return false;
}
outputToString(out, status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
if (extensionsStr != nullptr) {
+ changed = 0;
+ Locale temp(locale);
+ LocalPointer<icu::StringEnumeration> iter(locale.createKeywords(status));
+ if (U_SUCCESS(status) && !iter.isNull()) {
+ const char* key;
+ while ((key = iter->next(nullptr, status)) != nullptr) {
+ if (uprv_strcmp("sd", key) == 0 || uprv_strcmp("rg", key) == 0 ||
+ uprv_strcmp("t", key) == 0) {
+ CharString value;
+ CharStringByteSink valueSink(&value);
+ locale.getKeywordValue(key, valueSink, status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ CharString replacement;
+ if (uprv_strlen(key) == 2) {
+ if (replaceSubdivision(value.toStringPiece(), replacement, status)) {
+ changed++;
+ temp.setKeywordValue(key, replacement.data(), status);
+ }
+ } else {
+ U_ASSERT(uprv_strcmp(key, "t") == 0);
+ if (replaceTransformedExtensions(value, replacement, status)) {
+ changed++;
+ temp.setKeywordValue(key, replacement.data(), status);
+ }
+ }
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ }
+ }
+ }
+ if (changed != 0) {
+ extensionsStr = locale_getKeywordsStart(temp.getName());
+ }
out.append(extensionsStr, status);
}
if (U_FAILURE(status)) {
@@ -1573,8 +1792,6 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
}
// If the tag is not changed, return.
if (uprv_strcmp(out.data(), locale.getName()) == 0) {
- U_ASSERT(changed == 0);
- U_ASSERT(variants.size() > 1);
out.clear();
return false;
}
@@ -1636,7 +1853,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize)
{
fIsBogus = FALSE;
/* Free our current storage */
- if (baseName != fullName) {
+ if ((baseName != fullName) && (baseName != fullNameBuffer)) {
uprv_free(baseName);
}
baseName = NULL;
@@ -1672,6 +1889,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize)
uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) {
+ U_ASSERT(baseName == nullptr);
/*Go to heap for the fullName if necessary*/
fullName = (char *)uprv_malloc(sizeof(char)*(length + 1));
if(fullName == 0) {
@@ -1825,7 +2043,7 @@ Locale::hashCode() const
void
Locale::setToBogus() {
/* Free our current storage */
- if(baseName != fullName) {
+ if((baseName != fullName) && (baseName != fullNameBuffer)) {
uprv_free(baseName);
}
baseName = NULL;
diff --git a/thirdparty/icu4c/common/loclikelysubtags.cpp b/thirdparty/icu4c/common/loclikelysubtags.cpp
index a031bfa587..aa592e6ea8 100644
--- a/thirdparty/icu4c/common/loclikelysubtags.cpp
+++ b/thirdparty/icu4c/common/loclikelysubtags.cpp
@@ -320,7 +320,8 @@ XLikelySubtags::~XLikelySubtags() {
LSR XLikelySubtags::makeMaximizedLsrFrom(const Locale &locale, UErrorCode &errorCode) const {
const char *name = locale.getName();
if (uprv_isAtSign(name[0]) && name[1] == 'x' && name[2] == '=') { // name.startsWith("@x=")
- // Private use language tag x-subtag-subtag...
+ // Private use language tag x-subtag-subtag... which CLDR changes to
+ // und-x-subtag-subtag...
return LSR(name, "", "", LSR::EXPLICIT_LSR);
}
return makeMaximizedLsr(locale.getLanguage(), locale.getScript(), locale.getCountry(),
diff --git a/thirdparty/icu4c/common/norm2allmodes.h b/thirdparty/icu4c/common/norm2allmodes.h
index e8bd52c6ae..584835da57 100644
--- a/thirdparty/icu4c/common/norm2allmodes.h
+++ b/thirdparty/icu4c/common/norm2allmodes.h
@@ -38,7 +38,7 @@ public:
virtual UnicodeString &
normalize(const UnicodeString &src,
UnicodeString &dest,
- UErrorCode &errorCode) const {
+ UErrorCode &errorCode) const U_OVERRIDE {
if(U_FAILURE(errorCode)) {
dest.setToBogus();
return dest;
@@ -64,13 +64,13 @@ public:
virtual UnicodeString &
normalizeSecondAndAppend(UnicodeString &first,
const UnicodeString &second,
- UErrorCode &errorCode) const {
+ UErrorCode &errorCode) const U_OVERRIDE {
return normalizeSecondAndAppend(first, second, true, errorCode);
}
virtual UnicodeString &
append(UnicodeString &first,
const UnicodeString &second,
- UErrorCode &errorCode) const {
+ UErrorCode &errorCode) const U_OVERRIDE {
return normalizeSecondAndAppend(first, second, false, errorCode);
}
UnicodeString &
@@ -107,7 +107,7 @@ public:
UnicodeString &safeMiddle,
ReorderingBuffer &buffer, UErrorCode &errorCode) const = 0;
virtual UBool
- getDecomposition(UChar32 c, UnicodeString &decomposition) const {
+ getDecomposition(UChar32 c, UnicodeString &decomposition) const U_OVERRIDE {
UChar buffer[4];
int32_t length;
const UChar *d=impl.getDecomposition(c, buffer, length);
@@ -122,7 +122,7 @@ public:
return true;
}
virtual UBool
- getRawDecomposition(UChar32 c, UnicodeString &decomposition) const {
+ getRawDecomposition(UChar32 c, UnicodeString &decomposition) const U_OVERRIDE {
UChar buffer[30];
int32_t length;
const UChar *d=impl.getRawDecomposition(c, buffer, length);
@@ -137,18 +137,18 @@ public:
return true;
}
virtual UChar32
- composePair(UChar32 a, UChar32 b) const {
+ composePair(UChar32 a, UChar32 b) const U_OVERRIDE {
return impl.composePair(a, b);
}
virtual uint8_t
- getCombiningClass(UChar32 c) const {
+ getCombiningClass(UChar32 c) const U_OVERRIDE {
return impl.getCC(impl.getNorm16(c));
}
// quick checks
virtual UBool
- isNormalized(const UnicodeString &s, UErrorCode &errorCode) const {
+ isNormalized(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE {
if(U_FAILURE(errorCode)) {
return false;
}
@@ -161,11 +161,11 @@ public:
return sLimit==spanQuickCheckYes(sArray, sLimit, errorCode);
}
virtual UNormalizationCheckResult
- quickCheck(const UnicodeString &s, UErrorCode &errorCode) const {
+ quickCheck(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE {
return Normalizer2WithImpl::isNormalized(s, errorCode) ? UNORM_YES : UNORM_NO;
}
virtual int32_t
- spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const {
+ spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE {
if(U_FAILURE(errorCode)) {
return 0;
}
@@ -194,27 +194,57 @@ public:
private:
virtual void
normalize(const UChar *src, const UChar *limit,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.decompose(src, limit, &buffer, errorCode);
}
using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function.
virtual void
normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize,
UnicodeString &safeMiddle,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.decomposeAndAppend(src, limit, doNormalize, safeMiddle, buffer, errorCode);
}
+
+ void
+ normalizeUTF8(uint32_t options, StringPiece src, ByteSink &sink,
+ Edits *edits, UErrorCode &errorCode) const U_OVERRIDE {
+ if (U_FAILURE(errorCode)) {
+ return;
+ }
+ if (edits != nullptr && (options & U_EDITS_NO_RESET) == 0) {
+ edits->reset();
+ }
+ const uint8_t *s = reinterpret_cast<const uint8_t *>(src.data());
+ impl.decomposeUTF8(options, s, s + src.length(), &sink, edits, errorCode);
+ sink.Flush();
+ }
+ virtual UBool
+ isNormalizedUTF8(StringPiece sp, UErrorCode &errorCode) const U_OVERRIDE {
+ if(U_FAILURE(errorCode)) {
+ return false;
+ }
+ const uint8_t *s = reinterpret_cast<const uint8_t *>(sp.data());
+ const uint8_t *sLimit = s + sp.length();
+ return sLimit == impl.decomposeUTF8(0, s, sLimit, nullptr, nullptr, errorCode);
+ }
+
virtual const UChar *
- spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const {
+ spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const U_OVERRIDE {
return impl.decompose(src, limit, NULL, errorCode);
}
using Normalizer2WithImpl::spanQuickCheckYes; // Avoid warning about hiding base class function.
- virtual UNormalizationCheckResult getQuickCheck(UChar32 c) const {
+ virtual UNormalizationCheckResult getQuickCheck(UChar32 c) const U_OVERRIDE {
return impl.isDecompYes(impl.getNorm16(c)) ? UNORM_YES : UNORM_NO;
}
- virtual UBool hasBoundaryBefore(UChar32 c) const { return impl.hasDecompBoundaryBefore(c); }
- virtual UBool hasBoundaryAfter(UChar32 c) const { return impl.hasDecompBoundaryAfter(c); }
- virtual UBool isInert(UChar32 c) const { return impl.isDecompInert(c); }
+ virtual UBool hasBoundaryBefore(UChar32 c) const U_OVERRIDE {
+ return impl.hasDecompBoundaryBefore(c);
+ }
+ virtual UBool hasBoundaryAfter(UChar32 c) const U_OVERRIDE {
+ return impl.hasDecompBoundaryAfter(c);
+ }
+ virtual UBool isInert(UChar32 c) const U_OVERRIDE {
+ return impl.isDecompInert(c);
+ }
};
class ComposeNormalizer2 : public Normalizer2WithImpl {
@@ -321,24 +351,30 @@ public:
private:
virtual void
normalize(const UChar *src, const UChar *limit,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.makeFCD(src, limit, &buffer, errorCode);
}
using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function.
virtual void
normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize,
UnicodeString &safeMiddle,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.makeFCDAndAppend(src, limit, doNormalize, safeMiddle, buffer, errorCode);
}
virtual const UChar *
- spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const {
+ spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const U_OVERRIDE {
return impl.makeFCD(src, limit, NULL, errorCode);
}
using Normalizer2WithImpl::spanQuickCheckYes; // Avoid warning about hiding base class function.
- virtual UBool hasBoundaryBefore(UChar32 c) const { return impl.hasFCDBoundaryBefore(c); }
- virtual UBool hasBoundaryAfter(UChar32 c) const { return impl.hasFCDBoundaryAfter(c); }
- virtual UBool isInert(UChar32 c) const { return impl.isFCDInert(c); }
+ virtual UBool hasBoundaryBefore(UChar32 c) const U_OVERRIDE {
+ return impl.hasFCDBoundaryBefore(c);
+ }
+ virtual UBool hasBoundaryAfter(UChar32 c) const U_OVERRIDE {
+ return impl.hasFCDBoundaryAfter(c);
+ }
+ virtual UBool isInert(UChar32 c) const U_OVERRIDE {
+ return impl.isFCDInert(c);
+ }
};
struct Norm2AllModes : public UMemory {
diff --git a/thirdparty/icu4c/common/normalizer2impl.cpp b/thirdparty/icu4c/common/normalizer2impl.cpp
index cbf6b4d980..c0ad5c69f3 100644
--- a/thirdparty/icu4c/common/normalizer2impl.cpp
+++ b/thirdparty/icu4c/common/normalizer2impl.cpp
@@ -731,9 +731,131 @@ UBool Normalizer2Impl::decompose(UChar32 c, uint16_t norm16,
return buffer.append((const UChar *)mapping+1, length, TRUE, leadCC, trailCC, errorCode);
}
+// Dual functionality:
+// sink != nullptr: normalize
+// sink == nullptr: isNormalized/spanQuickCheckYes
+const uint8_t *
+Normalizer2Impl::decomposeUTF8(uint32_t options,
+ const uint8_t *src, const uint8_t *limit,
+ ByteSink *sink, Edits *edits, UErrorCode &errorCode) const {
+ U_ASSERT(limit != nullptr);
+ UnicodeString s16;
+ uint8_t minNoLead = leadByteForCP(minDecompNoCP);
+
+ const uint8_t *prevBoundary = src;
+ // only for quick check
+ uint8_t prevCC = 0;
+
+ for (;;) {
+ // Fast path: Scan over a sequence of characters below the minimum "no" code point,
+ // or with (decompYes && ccc==0) properties.
+ const uint8_t *fastStart = src;
+ const uint8_t *prevSrc;
+ uint16_t norm16 = 0;
+
+ for (;;) {
+ if (src == limit) {
+ if (prevBoundary != limit && sink != nullptr) {
+ ByteSinkUtil::appendUnchanged(prevBoundary, limit,
+ *sink, options, edits, errorCode);
+ }
+ return src;
+ }
+ if (*src < minNoLead) {
+ ++src;
+ } else {
+ prevSrc = src;
+ UCPTRIE_FAST_U8_NEXT(normTrie, UCPTRIE_16, src, limit, norm16);
+ if (!isMostDecompYesAndZeroCC(norm16)) {
+ break;
+ }
+ }
+ }
+ // isMostDecompYesAndZeroCC(norm16) is false, that is, norm16>=minYesNo,
+ // and the current character at [prevSrc..src[ is not a common case with cc=0
+ // (MIN_NORMAL_MAYBE_YES or JAMO_VT).
+ // It could still be a maybeYes with cc=0.
+ if (prevSrc != fastStart) {
+ // The fast path looped over yes/0 characters before the current one.
+ if (sink != nullptr &&
+ !ByteSinkUtil::appendUnchanged(prevBoundary, prevSrc,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ prevBoundary = prevSrc;
+ prevCC = 0;
+ }
+
+ // Medium-fast path: Quick check.
+ if (isMaybeOrNonZeroCC(norm16)) {
+ // Does not decompose.
+ uint8_t cc = getCCFromYesOrMaybe(norm16);
+ if (prevCC <= cc || cc == 0) {
+ prevCC = cc;
+ if (cc <= 1) {
+ if (sink != nullptr &&
+ !ByteSinkUtil::appendUnchanged(prevBoundary, src,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ prevBoundary = src;
+ }
+ continue;
+ }
+ }
+ if (sink == nullptr) {
+ return prevBoundary; // quick check: "no" or cc out of order
+ }
+
+ // Slow path
+ // Decompose up to and including the current character.
+ if (prevBoundary != prevSrc && norm16HasDecompBoundaryBefore(norm16)) {
+ if (!ByteSinkUtil::appendUnchanged(prevBoundary, prevSrc,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ prevBoundary = prevSrc;
+ }
+ ReorderingBuffer buffer(*this, s16, errorCode);
+ if (U_FAILURE(errorCode)) {
+ break;
+ }
+ decomposeShort(prevBoundary, src, STOP_AT_LIMIT, FALSE /* onlyContiguous */,
+ buffer, errorCode);
+ // Decompose until the next boundary.
+ if (buffer.getLastCC() > 1) {
+ src = decomposeShort(src, limit, STOP_AT_DECOMP_BOUNDARY, FALSE /* onlyContiguous */,
+ buffer, errorCode);
+ }
+ if (U_FAILURE(errorCode)) {
+ break;
+ }
+ if ((src - prevSrc) > INT32_MAX) { // guard before buffer.equals()
+ errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
+ break;
+ }
+ // We already know there was a change if the original character decomposed;
+ // otherwise compare.
+ if (isMaybeOrNonZeroCC(norm16) && buffer.equals(prevBoundary, src)) {
+ if (!ByteSinkUtil::appendUnchanged(prevBoundary, src,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ } else {
+ if (!ByteSinkUtil::appendChange(prevBoundary, src, buffer.getStart(), buffer.length(),
+ *sink, edits, errorCode)) {
+ break;
+ }
+ }
+ prevBoundary = src;
+ prevCC = 0;
+ }
+ return src;
+}
+
const uint8_t *
Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
- UBool stopAtCompBoundary, UBool onlyContiguous,
+ StopAt stopAt, UBool onlyContiguous,
ReorderingBuffer &buffer, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) {
return nullptr;
@@ -746,21 +868,28 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
UChar32 c = U_SENTINEL;
if (norm16 >= limitNoNo) {
if (isMaybeOrNonZeroCC(norm16)) {
- // No boundaries around this character.
+ // No comp boundaries around this character.
+ uint8_t cc = getCCFromYesOrMaybe(norm16);
+ if (cc == 0 && stopAt == STOP_AT_DECOMP_BOUNDARY) {
+ return prevSrc;
+ }
c = codePointFromValidUTF8(prevSrc, src);
- if (!buffer.append(c, getCCFromYesOrMaybe(norm16), errorCode)) {
+ if (!buffer.append(c, cc, errorCode)) {
return nullptr;
}
+ if (stopAt == STOP_AT_DECOMP_BOUNDARY && buffer.getLastCC() <= 1) {
+ return src;
+ }
continue;
}
// Maps to an isCompYesAndZeroCC.
- if (stopAtCompBoundary) {
+ if (stopAt != STOP_AT_LIMIT) {
return prevSrc;
}
c = codePointFromValidUTF8(prevSrc, src);
c = mapAlgorithmic(c, norm16);
norm16 = getRawNorm16(c);
- } else if (stopAtCompBoundary && norm16 < minNoNoCompNoMaybeCC) {
+ } else if (stopAt != STOP_AT_LIMIT && norm16 < minNoNoCompNoMaybeCC) {
return prevSrc;
}
// norm16!=INERT guarantees that [prevSrc, src[ is valid UTF-8.
@@ -768,7 +897,8 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
// its norm16==INERT is normalization-inert,
// so it gets copied unchanged in the fast path,
// and we stop the slow path where invalid UTF-8 begins.
- U_ASSERT(norm16 != INERT);
+ // c >= 0 is the result of an algorithmic mapping.
+ U_ASSERT(c >= 0 || norm16 != INERT);
if (norm16 < minYesNo) {
if (c < 0) {
c = codePointFromValidUTF8(prevSrc, src);
@@ -798,11 +928,15 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
} else {
leadCC = 0;
}
+ if (leadCC == 0 && stopAt == STOP_AT_DECOMP_BOUNDARY) {
+ return prevSrc;
+ }
if (!buffer.append((const char16_t *)mapping+1, length, TRUE, leadCC, trailCC, errorCode)) {
return nullptr;
}
}
- if (stopAtCompBoundary && norm16HasCompBoundaryAfter(norm16, onlyContiguous)) {
+ if ((stopAt == STOP_AT_COMP_BOUNDARY && norm16HasCompBoundaryAfter(norm16, onlyContiguous)) ||
+ (stopAt == STOP_AT_DECOMP_BOUNDARY && buffer.getLastCC() <= 1)) {
return src;
}
}
@@ -1954,10 +2088,10 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
break;
}
// We know there is not a boundary here.
- decomposeShort(prevSrc, src, FALSE /* !stopAtCompBoundary */, onlyContiguous,
+ decomposeShort(prevSrc, src, STOP_AT_LIMIT, onlyContiguous,
buffer, errorCode);
// Decompose until the next boundary.
- src = decomposeShort(src, limit, TRUE /* stopAtCompBoundary */, onlyContiguous,
+ src = decomposeShort(src, limit, STOP_AT_COMP_BOUNDARY, onlyContiguous,
buffer, errorCode);
if (U_FAILURE(errorCode)) {
break;
diff --git a/thirdparty/icu4c/common/normalizer2impl.h b/thirdparty/icu4c/common/normalizer2impl.h
index 4218a30a34..bdb6767a92 100644
--- a/thirdparty/icu4c/common/normalizer2impl.h
+++ b/thirdparty/icu4c/common/normalizer2impl.h
@@ -491,6 +491,12 @@ public:
UnicodeString &safeMiddle,
ReorderingBuffer &buffer,
UErrorCode &errorCode) const;
+
+ /** sink==nullptr: isNormalized()/spanQuickCheckYes() */
+ const uint8_t *decomposeUTF8(uint32_t options,
+ const uint8_t *src, const uint8_t *limit,
+ ByteSink *sink, Edits *edits, UErrorCode &errorCode) const;
+
UBool compose(const UChar *src, const UChar *limit,
UBool onlyContiguous,
UBool doCompose,
@@ -649,6 +655,9 @@ private:
UChar32 minNeedDataCP,
ReorderingBuffer *buffer,
UErrorCode &errorCode) const;
+
+ enum StopAt { STOP_AT_LIMIT, STOP_AT_DECOMP_BOUNDARY, STOP_AT_COMP_BOUNDARY };
+
const UChar *decomposeShort(const UChar *src, const UChar *limit,
UBool stopAtCompBoundary, UBool onlyContiguous,
ReorderingBuffer &buffer, UErrorCode &errorCode) const;
@@ -656,7 +665,7 @@ private:
ReorderingBuffer &buffer, UErrorCode &errorCode) const;
const uint8_t *decomposeShort(const uint8_t *src, const uint8_t *limit,
- UBool stopAtCompBoundary, UBool onlyContiguous,
+ StopAt stopAt, UBool onlyContiguous,
ReorderingBuffer &buffer, UErrorCode &errorCode) const;
static int32_t combine(const uint16_t *list, UChar32 trail);
diff --git a/thirdparty/icu4c/common/pluralmap.h b/thirdparty/icu4c/common/pluralmap.h
index d898ac4671..2a14a07af1 100644
--- a/thirdparty/icu4c/common/pluralmap.h
+++ b/thirdparty/icu4c/common/pluralmap.h
@@ -24,7 +24,7 @@ class U_COMMON_API PluralMapBase : public UMemory {
public:
/**
* The names of all the plural categories. NONE is not an actual plural
- * category, but rather represents the absense of a plural category.
+ * category, but rather represents the absence of a plural category.
*/
enum Category {
NONE = -1,
diff --git a/thirdparty/icu4c/common/putil.cpp b/thirdparty/icu4c/common/putil.cpp
index 3ed6a05d22..ffcbbcce59 100644
--- a/thirdparty/icu4c/common/putil.cpp
+++ b/thirdparty/icu4c/common/putil.cpp
@@ -1139,7 +1139,7 @@ uprv_tzname(int n)
#endif
if (tzid != NULL && isValidOlsonID(tzid)
#if U_PLATFORM == U_PF_SOLARIS
- /* When TZ equals localtime on Solaris, check the /etc/localtime file. */
+ /* Don't misinterpret TZ "localtime" on Solaris as a time zone name. */
&& uprv_strcmp(tzid, TZ_ENV_CHECK) != 0
#endif
) {
@@ -1361,7 +1361,7 @@ uprv_pathIsAbsolute(const char *path)
/* Backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
(needed for some Darwin ICU build environments) */
-#if U_PLATFORM_IS_DARWIN_BASED && TARGET_OS_SIMULATOR
+#if U_PLATFORM_IS_DARWIN_BASED && defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
# if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
# define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT"
# endif
diff --git a/thirdparty/icu4c/common/putilimp.h b/thirdparty/icu4c/common/putilimp.h
index a325c6c359..5b95a68418 100644
--- a/thirdparty/icu4c/common/putilimp.h
+++ b/thirdparty/icu4c/common/putilimp.h
@@ -527,7 +527,7 @@ U_CAPI void * U_EXPORT2 uprv_maximumPtr(void *base);
* on the destination pointer and capacity cannot overflow.
*
* The pinned capacity must fulfill the following conditions (for positive capacities):
- * - dest + capacity is a valid pointer according to the machine arcitecture (AS/400, 64-bit, etc.)
+ * - dest + capacity is a valid pointer according to the machine architecture (AS/400, 64-bit, etc.)
* - (dest + capacity) >= dest
* - The size (in bytes) of T[capacity] does not exceed 0x7fffffff
*
diff --git a/thirdparty/icu4c/common/rbbi.cpp b/thirdparty/icu4c/common/rbbi.cpp
index 9b7e70c3cf..b821ca4463 100644
--- a/thirdparty/icu4c/common/rbbi.cpp
+++ b/thirdparty/icu4c/common/rbbi.cpp
@@ -812,7 +812,7 @@ int32_t RuleBasedBreakIterator::handleNext() {
}
#endif
- // handleNext alway sets the break tag value.
+ // handleNext always sets the break tag value.
// Set the default for it.
fRuleStatusIndex = 0;
diff --git a/thirdparty/icu4c/common/rbbi_cache.cpp b/thirdparty/icu4c/common/rbbi_cache.cpp
index 63ff3001c7..44f19d8697 100644
--- a/thirdparty/icu4c/common/rbbi_cache.cpp
+++ b/thirdparty/icu4c/common/rbbi_cache.cpp
@@ -258,7 +258,7 @@ void RuleBasedBreakIterator::BreakCache::preceding(int32_t startPos, UErrorCode
previous(status);
} else {
// seek() leaves the BreakCache positioned at the preceding boundary
- // if the requested position is between two bounaries.
+ // if the requested position is between two boundaries.
// current() pushes the BreakCache position out to the BreakIterator itself.
U_ASSERT(startPos > fTextIdx);
current();
diff --git a/thirdparty/icu4c/common/rbbiscan.cpp b/thirdparty/icu4c/common/rbbiscan.cpp
index 9c406af671..45911b1cfe 100644
--- a/thirdparty/icu4c/common/rbbiscan.cpp
+++ b/thirdparty/icu4c/common/rbbiscan.cpp
@@ -284,7 +284,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
case doEndAssign:
{
- // We have reached the end of an assignement statement.
+ // We have reached the end of an assignment statement.
// Current scan char is the ';' that terminates the assignment.
// Terminate expression, leaves expression parse tree rooted in TOS node.
@@ -856,6 +856,10 @@ UChar32 RBBIRuleScanner::nextCharLL() {
return (UChar32)-1;
}
ch = fRB->fRules.char32At(fNextIndex);
+ if (U_IS_SURROGATE(ch)) {
+ error(U_ILLEGAL_CHAR_FOUND);
+ return U_SENTINEL;
+ }
fNextIndex = fRB->fRules.moveIndex32(fNextIndex, 1);
if (ch == chCR ||
diff --git a/thirdparty/icu4c/common/rbbitblb.cpp b/thirdparty/icu4c/common/rbbitblb.cpp
index 70e260fc08..dd76337bc6 100644
--- a/thirdparty/icu4c/common/rbbitblb.cpp
+++ b/thirdparty/icu4c/common/rbbitblb.cpp
@@ -151,7 +151,7 @@ void RBBITableBuilder::buildForwardTable() {
//
// calculate the functions nullable, firstpos, lastpos and followpos on
// nodes in the parse tree.
- // See the alogrithm description in Aho.
+ // See the algorithm description in Aho.
// Understanding how this works by looking at the code alone will be
// nearly impossible.
//
diff --git a/thirdparty/icu4c/common/resource.h b/thirdparty/icu4c/common/resource.h
index 3795694412..48f5b9fa6e 100644
--- a/thirdparty/icu4c/common/resource.h
+++ b/thirdparty/icu4c/common/resource.h
@@ -274,8 +274,10 @@ public:
*
* @param key The key string of the enumeration-start resource.
* Empty if the enumeration starts at the top level of the bundle.
- * @param value Call getArray() or getTable() as appropriate.
- * Then reuse for output values from Array and Table getters.
+ * @param value Call getArray() or getTable() as appropriate. Then reuse for
+ * output values from Array and Table getters. Note: ResourceTable and
+ * ResourceArray instances must outlive the ResourceValue instance for
+ * ResourceTracer to be happy.
* @param noFallback true if the bundle has no parent;
* that is, its top-level table has the nofallback attribute,
* or it is the root bundle of a locale tree.
diff --git a/thirdparty/icu4c/common/restrace.cpp b/thirdparty/icu4c/common/restrace.cpp
index 5c6498850e..1f83372d68 100644
--- a/thirdparty/icu4c/common/restrace.cpp
+++ b/thirdparty/icu4c/common/restrace.cpp
@@ -54,6 +54,9 @@ void ResourceTracer::traceOpen() const {
CharString& ResourceTracer::getFilePath(CharString& output, UErrorCode& status) const {
if (fResB) {
+ // Note: if you get a segfault around here, check that ResourceTable and
+ // ResourceArray instances outlive ResourceValue instances referring to
+ // their contents:
output.append(fResB->fData->fPath, status);
output.append('/', status);
output.append(fResB->fData->fName, status);
diff --git a/thirdparty/icu4c/common/servnotf.h b/thirdparty/icu4c/common/servnotf.h
index 305570c1e6..73ce38c772 100644
--- a/thirdparty/icu4c/common/servnotf.h
+++ b/thirdparty/icu4c/common/servnotf.h
@@ -82,7 +82,7 @@ public:
/**
* Add a listener to be notified when notifyChanged is called.
* The listener must not be null. AcceptsListener must return
- * true for the listener. Attempts to concurrently
+ * true for the listener. Attempts to concurrently
* register the identical listener more than once will be
* silently ignored.
*/
@@ -90,7 +90,7 @@ public:
/**
* Stop notifying this listener. The listener must
- * not be null. Attemps to remove a listener that is
+ * not be null. Attempts to remove a listener that is
* not registered will be silently ignored.
*/
virtual void removeListener(const EventListener* l, UErrorCode& status);
diff --git a/thirdparty/icu4c/common/ubrk.cpp b/thirdparty/icu4c/common/ubrk.cpp
index f8bdf5a6b6..bb5bdd1b50 100644
--- a/thirdparty/icu4c/common/ubrk.cpp
+++ b/thirdparty/icu4c/common/ubrk.cpp
@@ -174,6 +174,18 @@ ubrk_safeClone(
return (UBreakIterator *)newBI;
}
+U_CAPI UBreakIterator * U_EXPORT2
+ubrk_clone(const UBreakIterator *bi, UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return nullptr;
+ }
+ BreakIterator *newBI = ((BreakIterator *)bi)->clone();
+ if (newBI == nullptr) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ return (UBreakIterator *)newBI;
+}
U_CAPI void U_EXPORT2
diff --git a/thirdparty/icu4c/common/ucase.cpp b/thirdparty/icu4c/common/ucase.cpp
index 2b142f5bc2..4f4c274d60 100644
--- a/thirdparty/icu4c/common/ucase.cpp
+++ b/thirdparty/icu4c/common/ucase.cpp
@@ -681,7 +681,7 @@ ucase_isCaseSensitive(UChar32 c) {
* - In [CoreProps], C has one of the properties Uppercase, or Lowercase
* - Given D = NFD(C), then it is not the case that:
* D = UCD_lower(D) = UCD_upper(D) = UCD_title(D)
- * (This third criterium does not add any characters to the list
+ * (This third criterion does not add any characters to the list
* for Unicode 3.2. Ignored.)
*
* D2. A character C is defined to be case-ignorable
diff --git a/thirdparty/icu4c/common/uchar.cpp b/thirdparty/icu4c/common/uchar.cpp
index eb14e4c75d..61e9c3d900 100644
--- a/thirdparty/icu4c/common/uchar.cpp
+++ b/thirdparty/icu4c/common/uchar.cpp
@@ -194,7 +194,7 @@ u_isISOControl(UChar32 c) {
/* Some control characters that are used as space. */
#define IS_THAT_CONTROL_SPACE(c) \
- (c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==NL))
+ (c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==0x85))
/* Java has decided that U+0085 New Line is not whitespace any more. */
#define IS_THAT_ASCII_CONTROL_SPACE(c) \
@@ -677,14 +677,14 @@ uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
sa->add(sa->set, CR+1); /* range TAB..CR */
sa->add(sa->set, 0x1c);
sa->add(sa->set, 0x1f+1);
- USET_ADD_CP_AND_NEXT(sa, NL);
+ USET_ADD_CP_AND_NEXT(sa, 0x85); // NEXT LINE (NEL)
/* add for u_isIDIgnorable() what was not added above */
- sa->add(sa->set, DEL); /* range DEL..NBSP-1, NBSP added below */
+ sa->add(sa->set, 0x7f); /* range DEL..NBSP-1, NBSP added below */
sa->add(sa->set, HAIRSP);
sa->add(sa->set, RLM+1);
- sa->add(sa->set, INHSWAP);
- sa->add(sa->set, NOMDIG+1);
+ sa->add(sa->set, 0x206a); // INHIBIT SYMMETRIC SWAPPING
+ sa->add(sa->set, 0x206f+1); // NOMINAL DIGIT SHAPES
USET_ADD_CP_AND_NEXT(sa, ZWNBSP);
/* add no-break spaces for u_isWhitespace() what was not added above */
@@ -693,23 +693,25 @@ uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
USET_ADD_CP_AND_NEXT(sa, NNBSP);
/* add for u_digit() */
- sa->add(sa->set, U_a);
- sa->add(sa->set, U_z+1);
- sa->add(sa->set, U_A);
- sa->add(sa->set, U_Z+1);
- sa->add(sa->set, U_FW_a);
- sa->add(sa->set, U_FW_z+1);
- sa->add(sa->set, U_FW_A);
- sa->add(sa->set, U_FW_Z+1);
+ sa->add(sa->set, u'a');
+ sa->add(sa->set, u'z'+1);
+ sa->add(sa->set, u'A');
+ sa->add(sa->set, u'Z'+1);
+ // fullwidth
+ sa->add(sa->set, u'ï½');
+ sa->add(sa->set, u'z'+1);
+ sa->add(sa->set, u'A');
+ sa->add(sa->set, u'Z'+1);
/* add for u_isxdigit() */
- sa->add(sa->set, U_f+1);
- sa->add(sa->set, U_F+1);
- sa->add(sa->set, U_FW_f+1);
- sa->add(sa->set, U_FW_F+1);
+ sa->add(sa->set, u'f'+1);
+ sa->add(sa->set, u'F'+1);
+ // fullwidth
+ sa->add(sa->set, u'f'+1);
+ sa->add(sa->set, u'F'+1);
/* add for UCHAR_DEFAULT_IGNORABLE_CODE_POINT what was not added above */
- sa->add(sa->set, WJ); /* range WJ..NOMDIG */
+ sa->add(sa->set, 0x2060); /* range 2060..206f */
sa->add(sa->set, 0xfff0);
sa->add(sa->set, 0xfffb+1);
sa->add(sa->set, 0xe0000);
diff --git a/thirdparty/icu4c/common/ucnv2022.cpp b/thirdparty/icu4c/common/ucnv2022.cpp
index 169ad4c526..1726440b94 100644
--- a/thirdparty/icu4c/common/ucnv2022.cpp
+++ b/thirdparty/icu4c/common/ucnv2022.cpp
@@ -820,7 +820,7 @@ getKey_2022(char c,int32_t* key,int32_t* offset){
return INVALID_2022;
}
-/*runs through a state machine to determine the escape sequence - codepage correspondance
+/*runs through a state machine to determine the escape sequence - codepage correspondence
*/
static void
changeState_2022(UConverter* _this,
@@ -1424,7 +1424,7 @@ toUnicodeCallback(UConverter *cnv,
* KSC5601 : alias to ibm-949 mapping table
* GB2312 : alias to ibm-1386 mapping table
* ISO-8859-1 : Algorithmic implemented as LATIN1 case
-* ISO-8859-7 : alisas to ibm-9409 mapping table
+* ISO-8859-7 : alias to ibm-9409 mapping table
*/
/* preference order of JP charsets */
@@ -2324,7 +2324,7 @@ endloop:
/***************************************************************
* Rules for ISO-2022-KR encoding
* i) The KSC5601 designator sequence should appear only once in a file,
-* at the begining of a line before any KSC5601 characters. This usually
+* at the beginning of a line before any KSC5601 characters. This usually
* means that it appears by itself on the first line of the file
* ii) There are only 2 shifting sequences SO to shift into double byte mode
* and SI to shift into single byte mode
diff --git a/thirdparty/icu4c/common/ucnv_bld.cpp b/thirdparty/icu4c/common/ucnv_bld.cpp
index 0e198892f1..d08eec7369 100644
--- a/thirdparty/icu4c/common/ucnv_bld.cpp
+++ b/thirdparty/icu4c/common/ucnv_bld.cpp
@@ -427,7 +427,7 @@ getAlgorithmicTypeFromName(const char *realName)
#define UCNV_CACHE_LOAD_FACTOR 2
/* Puts the shared data in the static hashtable SHARED_DATA_HASHTABLE */
-/* Will always be called with the cnvCacheMutex alrady being held */
+/* Will always be called with the cnvCacheMutex already being held */
/* by the calling function. */
/* Stores the shared data in the SHARED_DATA_HASHTABLE
* @param data The shared data
diff --git a/thirdparty/icu4c/common/ucnv_err.cpp b/thirdparty/icu4c/common/ucnv_err.cpp
index 6b738face5..e1f2b934aa 100644
--- a/thirdparty/icu4c/common/ucnv_err.cpp
+++ b/thirdparty/icu4c/common/ucnv_err.cpp
@@ -321,7 +321,7 @@ UCNV_FROM_U_CALLBACK_ESCAPE (
case UCNV_PRV_ESCAPE_CSS2:
valueString[valueStringLength++] = (UChar) UNICODE_RS_CODEPOINT; /* adding \ */
valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, codePoint, 16, 0);
- /* Always add space character, becase the next character might be whitespace,
+ /* Always add space character, because the next character might be whitespace,
which would erroneously be considered the termination of the escape sequence. */
valueString[valueStringLength++] = (UChar) UNICODE_SPACE_CODEPOINT;
break;
diff --git a/thirdparty/icu4c/common/ucnv_lmb.cpp b/thirdparty/icu4c/common/ucnv_lmb.cpp
index 168392837b..41317d1cc0 100644
--- a/thirdparty/icu4c/common/ucnv_lmb.cpp
+++ b/thirdparty/icu4c/common/ucnv_lmb.cpp
@@ -81,7 +81,7 @@
[G] D1 [D2]
That is, a sometimes-optional 'group' byte, followed by 1 and sometimes 2
- data bytes. The maximum size of a LMBCS chjaracter is 3 bytes:
+ data bytes. The maximum size of a LMBCS character is 3 bytes:
*/
#define ULMBCS_CHARSIZE_MAX 3
/*
@@ -164,7 +164,7 @@ beginning of internal 'system' range names: */
/* Then we needed a place to put all the other ansi control characters
that must be moved to different values because LMBCS reserves those
values for other purposes. To represent the control characters, we start
-with a first byte of 0xF & add the control chaarcter value as the
+with a first byte of 0xF & add the control character value as the
second byte */
#define ULMBCS_GRP_CTRL 0x0F
diff --git a/thirdparty/icu4c/common/ucnv_u7.cpp b/thirdparty/icu4c/common/ucnv_u7.cpp
index 87ba8cf37e..de9f3f42ec 100644
--- a/thirdparty/icu4c/common/ucnv_u7.cpp
+++ b/thirdparty/icu4c/common/ucnv_u7.cpp
@@ -814,7 +814,7 @@ const UConverterSharedData _UTF7Data=
* the use of "~" in some servers as a home directory indicator.
*
* 5) UTF-7 permits multiple alternate forms to represent the same
- * string; in particular, printable US-ASCII chararacters can be
+ * string; in particular, printable US-ASCII characters can be
* represented in encoded form.
*
* In modified UTF-7, printable US-ASCII characters except for "&"
diff --git a/thirdparty/icu4c/common/ucnvisci.cpp b/thirdparty/icu4c/common/ucnvisci.cpp
index 44a7c05a3c..ffb8c7ac3e 100644
--- a/thirdparty/icu4c/common/ucnvisci.cpp
+++ b/thirdparty/icu4c/common/ucnvisci.cpp
@@ -992,7 +992,7 @@ UConverter_fromUnicode_ISCII_OFFSETS_LOGIC(
if (converterData->currentDeltaFromUnicode == PNJ_DELTA) {
if (sourceChar == PNJ_TIPPI) {
- /* Make sure Tippi is converterd to Bindi. */
+ /* Make sure Tippi is converted to Bindi. */
sourceChar = PNJ_BINDI;
} else if (sourceChar == PNJ_ADHAK) {
/* This is for consonant cluster handling. */
@@ -1147,7 +1147,7 @@ static const uint16_t lookupTable[][2]={
/* is the code point valid in current script? */ \
if(sourceChar> ASCII_END && \
(validityTable[(targetUniChar & 0x7F)] & data->currentMaskToUnicode)==0){ \
- /* Vocallic RR is assigne in ISCII Telugu and Unicode */ \
+ /* Vocallic RR is assigned in ISCII Telugu and Unicode */ \
if(data->currentDeltaToUnicode!=(TELUGU_DELTA) || \
targetUniChar!=VOCALLIC_RR){ \
targetUniChar=missingCharMarker; \
@@ -1272,7 +1272,7 @@ UConverter_toUnicode_ISCII_OFFSETS_LOGIC(UConverterToUnicodeArgs *args, UErrorCo
goto CALLBACK;
} else if (*contextCharToUnicode==ISCII_INV) {
if (sourceChar==ISCII_HALANT) {
- targetUniChar = 0x0020; /* replace with space accoding to Indic FAQ */
+ targetUniChar = 0x0020; /* replace with space according to Indic FAQ */
} else {
targetUniChar = ZWJ;
}
diff --git a/thirdparty/icu4c/common/ucurr.cpp b/thirdparty/icu4c/common/ucurr.cpp
index 0e14cddcff..20bbd51488 100644
--- a/thirdparty/icu4c/common/ucurr.cpp
+++ b/thirdparty/icu4c/common/ucurr.cpp
@@ -844,7 +844,7 @@ typedef struct {
#endif
-// Comparason function used in quick sort.
+// Comparison function used in quick sort.
static int U_CALLCONV currencyNameComparator(const void* a, const void* b) {
const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b;
@@ -1530,7 +1530,7 @@ uprv_parseCurrency(const char* locale,
int32_t max = 0;
int32_t matchIndex = -1;
- // case in-sensitive comparision against currency names
+ // case in-sensitive comparison against currency names
searchCurrencyName(currencyNames, total_currency_name_count,
upperText, textLen, partialMatchLen, &max, &matchIndex);
diff --git a/thirdparty/icu4c/common/uhash.cpp b/thirdparty/icu4c/common/uhash.cpp
index 86311ceb0b..67c7c36354 100644
--- a/thirdparty/icu4c/common/uhash.cpp
+++ b/thirdparty/icu4c/common/uhash.cpp
@@ -133,8 +133,10 @@ static const float RESIZE_POLICY_RATIO_TABLE[6] = {
* or a pointer. If a hint bit is zero, then the associated
* token is assumed to be an integer.
*/
+#define HINT_BOTH_INTEGERS (0)
#define HINT_KEY_POINTER (1)
#define HINT_VALUE_POINTER (2)
+#define HINT_ALLOW_ZERO (4)
/********************************************************************
* PRIVATE Implementation
@@ -479,8 +481,9 @@ _uhash_put(UHashtable *hash,
goto err;
}
U_ASSERT(hash != NULL);
- /* Cannot always check pointer here or iSeries sees NULL every time. */
- if ((hint & HINT_VALUE_POINTER) && value.pointer == NULL) {
+ if ((hint & HINT_VALUE_POINTER) ?
+ value.pointer == NULL :
+ value.integer == 0 && (hint & HINT_ALLOW_ZERO) == 0) {
/* Disallow storage of NULL values, since NULL is returned by
* get() to indicate an absent key. Storing NULL == removing.
*/
@@ -687,6 +690,28 @@ uhash_igeti(const UHashtable *hash,
return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.integer;
}
+U_CAPI int32_t U_EXPORT2
+uhash_getiAndFound(const UHashtable *hash,
+ const void *key,
+ UBool *found) {
+ UHashTok keyholder;
+ keyholder.pointer = (void *)key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ *found = !IS_EMPTY_OR_DELETED(e->hashcode);
+ return e->value.integer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_igetiAndFound(const UHashtable *hash,
+ int32_t key,
+ UBool *found) {
+ UHashTok keyholder;
+ keyholder.integer = key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ *found = !IS_EMPTY_OR_DELETED(e->hashcode);
+ return e->value.integer;
+}
+
U_CAPI void* U_EXPORT2
uhash_put(UHashtable *hash,
void* key,
@@ -736,7 +761,34 @@ uhash_iputi(UHashtable *hash,
keyholder.integer = key;
valueholder.integer = value;
return _uhash_put(hash, keyholder, valueholder,
- 0, /* neither is a ptr */
+ HINT_BOTH_INTEGERS,
+ status).integer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_putiAllowZero(UHashtable *hash,
+ void *key,
+ int32_t value,
+ UErrorCode *status) {
+ UHashTok keyholder, valueholder;
+ keyholder.pointer = key;
+ valueholder.integer = value;
+ return _uhash_put(hash, keyholder, valueholder,
+ HINT_KEY_POINTER | HINT_ALLOW_ZERO,
+ status).integer;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uhash_iputiAllowZero(UHashtable *hash,
+ int32_t key,
+ int32_t value,
+ UErrorCode *status) {
+ UHashTok keyholder, valueholder;
+ keyholder.integer = key;
+ valueholder.integer = value;
+ return _uhash_put(hash, keyholder, valueholder,
+ HINT_BOTH_INTEGERS | HINT_ALLOW_ZERO,
status).integer;
}
@@ -785,6 +837,29 @@ uhash_removeAll(UHashtable *hash) {
U_ASSERT(hash->count == 0);
}
+U_CAPI UBool U_EXPORT2
+uhash_containsKey(const UHashtable *hash, const void *key) {
+ UHashTok keyholder;
+ keyholder.pointer = (void *)key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ return !IS_EMPTY_OR_DELETED(e->hashcode);
+}
+
+/**
+ * Returns true if the UHashtable contains an item with this integer key.
+ *
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @return true if the key is found.
+ */
+U_CAPI UBool U_EXPORT2
+uhash_icontainsKey(const UHashtable *hash, int32_t key) {
+ UHashTok keyholder;
+ keyholder.integer = key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ return !IS_EMPTY_OR_DELETED(e->hashcode);
+}
+
U_CAPI const UHashElement* U_EXPORT2
uhash_find(const UHashtable *hash, const void* key) {
UHashTok keyholder;
diff --git a/thirdparty/icu4c/common/uhash.h b/thirdparty/icu4c/common/uhash.h
index b59d2711bb..af75999860 100644
--- a/thirdparty/icu4c/common/uhash.h
+++ b/thirdparty/icu4c/common/uhash.h
@@ -23,7 +23,7 @@
/**
* UHashtable stores key-value pairs and does moderately fast lookup
* based on keys. It provides a good tradeoff between access time and
- * storage space. As elements are added to it, it grows to accomodate
+ * storage space. As elements are added to it, it grows to accommodate
* them. By default, the table never shrinks, even if all elements
* are removed from it.
*
@@ -54,6 +54,13 @@
* uhash_remove() on that key. This keeps uhash_get(), uhash_count(),
* and uhash_nextElement() consistent with one another.
*
+ * Keys and values can be integers.
+ * Functions that work with an integer key have an "i" prefix.
+ * Functions that work with an integer value have an "i" suffix.
+ * As with putting a NULL value pointer, putting a zero value integer removes the item.
+ * Except, there are pairs of functions that allow setting zero values
+ * and fetching (value, found) pairs.
+ *
* To see everything in a hashtable, use uhash_nextElement() to
* iterate through its contents. Each call to this function returns a
* UHashElement pointer. A hash element contains a key, value, and
@@ -406,6 +413,44 @@ uhash_iputi(UHashtable *hash,
UErrorCode *status);
/**
+ * Put a (key=pointer, value=integer) item in a UHashtable. If the
+ * keyDeleter is non-NULL, then the hashtable owns 'key' after this
+ * call. valueDeleter must be NULL.
+ * Storing a 0 value is possible; call uhash_igetiAndFound() to retrieve values including zero.
+ *
+ * @param hash The target UHashtable.
+ * @param key The key to store.
+ * @param value The integer value to store.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The previous value, or 0 if none.
+ * @see uhash_getiAndFound
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_putiAllowZero(UHashtable *hash,
+ void *key,
+ int32_t value,
+ UErrorCode *status);
+
+/**
+ * Put a (key=integer, value=integer) item in a UHashtable. If the
+ * keyDeleter is non-NULL, then the hashtable owns 'key' after this
+ * call. valueDeleter must be NULL.
+ * Storing a 0 value is possible; call uhash_igetiAndFound() to retrieve values including zero.
+ *
+ * @param hash The target UHashtable.
+ * @param key The key to store.
+ * @param value The integer value to store.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The previous value, or 0 if none.
+ * @see uhash_igetiAndFound
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_iputiAllowZero(UHashtable *hash,
+ int32_t key,
+ int32_t value,
+ UErrorCode *status);
+
+/**
* Retrieve a pointer value from a UHashtable using a pointer key,
* as previously stored by uhash_put().
* @param hash The target UHashtable.
@@ -449,6 +494,34 @@ uhash_igeti(const UHashtable *hash,
int32_t key);
/**
+ * Retrieves an integer value from a UHashtable using a pointer key,
+ * as previously stored by uhash_putiAllowZero() or uhash_puti().
+ *
+ * @param hash The target UHashtable.
+ * @param key A pointer key stored in a hashtable
+ * @param found A pointer to a boolean which will be set for whether the key was found.
+ * @return The requested item, or 0 if not found.
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_getiAndFound(const UHashtable *hash,
+ const void *key,
+ UBool *found);
+
+/**
+ * Retrieves an integer value from a UHashtable using an integer key,
+ * as previously stored by uhash_iputiAllowZero() or uhash_iputi().
+ *
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @param found A pointer to a boolean which will be set for whether the key was found.
+ * @return The requested item, or 0 if not found.
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_igetiAndFound(const UHashtable *hash,
+ int32_t key,
+ UBool *found);
+
+/**
* Remove an item from a UHashtable stored by uhash_put().
* @param hash The target UHashtable.
* @param key A key stored in a hashtable
@@ -496,6 +569,26 @@ U_CAPI void U_EXPORT2
uhash_removeAll(UHashtable *hash);
/**
+ * Returns true if the UHashtable contains an item with this pointer key.
+ *
+ * @param hash The target UHashtable.
+ * @param key A pointer key stored in a hashtable
+ * @return true if the key is found.
+ */
+U_CAPI UBool U_EXPORT2
+uhash_containsKey(const UHashtable *hash, const void *key);
+
+/**
+ * Returns true if the UHashtable contains an item with this integer key.
+ *
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @return true if the key is found.
+ */
+U_CAPI UBool U_EXPORT2
+uhash_icontainsKey(const UHashtable *hash, int32_t key);
+
+/**
* Locate an element of a UHashtable. The caller must not modify the
* returned object. The primary use of this function is to obtain the
* stored key when it may not be identical to the search key. For
diff --git a/thirdparty/icu4c/common/uloc.cpp b/thirdparty/icu4c/common/uloc.cpp
index ebfbb50650..d96e79b8fd 100644
--- a/thirdparty/icu4c/common/uloc.cpp
+++ b/thirdparty/icu4c/common/uloc.cpp
@@ -143,7 +143,7 @@ static const char * const LANGUAGES[] = {
"mad", "maf", "mag", "mai", "mak", "man", "mas", "mde",
"mdf", "mdh", "mdr", "men", "mer", "mfe", "mg", "mga",
"mgh", "mgo", "mh", "mi", "mic", "min", "mis", "mk",
- "ml", "mn", "mnc", "mni", "mo",
+ "ml", "mn", "mnc", "mni",
"moh", "mos", "mr", "mrj",
"ms", "mt", "mua", "mul", "mus", "mwl", "mwr", "mwv",
"my", "mye", "myv", "mzn",
@@ -166,9 +166,9 @@ static const char * const LANGUAGES[] = {
"sl", "sli", "sly", "sm", "sma", "smj", "smn", "sms",
"sn", "snk", "so", "sog", "sq", "sr", "srn", "srr",
"ss", "ssy", "st", "stq", "su", "suk", "sus", "sux",
- "sv", "sw", "swb", "swc", "syc", "syr", "szl",
+ "sv", "sw", "swb", "syc", "syr", "szl",
"ta", "tcy", "te", "tem", "teo", "ter", "tet", "tg",
- "th", "ti", "tig", "tiv", "tk", "tkl", "tkr", "tl",
+ "th", "ti", "tig", "tiv", "tk", "tkl", "tkr",
"tlh", "tli", "tly", "tmh", "tn", "to", "tog", "tpi",
"tr", "tru", "trv", "ts", "tsd", "tsi", "tt", "ttt",
"tum", "tvl", "tw", "twq", "ty", "tyv", "tzm",
@@ -181,7 +181,7 @@ static const char * const LANGUAGES[] = {
"za", "zap", "zbl", "zea", "zen", "zgh", "zh", "zu",
"zun", "zxx", "zza",
NULL,
- "in", "iw", "ji", "jw", "sh", /* obsolete language codes */
+ "in", "iw", "ji", "jw", "mo", "sh", "swc", "tl", /* obsolete language codes */
NULL
};
@@ -260,7 +260,7 @@ static const char * const LANGUAGES_3[] = {
"mad", "maf", "mag", "mai", "mak", "man", "mas", "mde",
"mdf", "mdh", "mdr", "men", "mer", "mfe", "mlg", "mga",
"mgh", "mgo", "mah", "mri", "mic", "min", "mis", "mkd",
- "mal", "mon", "mnc", "mni", "mol",
+ "mal", "mon", "mnc", "mni",
"moh", "mos", "mar", "mrj",
"msa", "mlt", "mua", "mul", "mus", "mwl", "mwr", "mwv",
"mya", "mye", "myv", "mzn",
@@ -283,9 +283,9 @@ static const char * const LANGUAGES_3[] = {
"slv", "sli", "sly", "smo", "sma", "smj", "smn", "sms",
"sna", "snk", "som", "sog", "sqi", "srp", "srn", "srr",
"ssw", "ssy", "sot", "stq", "sun", "suk", "sus", "sux",
- "swe", "swa", "swb", "swc", "syc", "syr", "szl",
+ "swe", "swa", "swb", "syc", "syr", "szl",
"tam", "tcy", "tel", "tem", "teo", "ter", "tet", "tgk",
- "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr", "tgl",
+ "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr",
"tlh", "tli", "tly", "tmh", "tsn", "ton", "tog", "tpi",
"tur", "tru", "trv", "tso", "tsd", "tsi", "tat", "ttt",
"tum", "tvl", "twi", "twq", "tah", "tyv", "tzm",
@@ -298,8 +298,8 @@ static const char * const LANGUAGES_3[] = {
"zha", "zap", "zbl", "zea", "zen", "zgh", "zho", "zul",
"zun", "zxx", "zza",
NULL,
-/* "in", "iw", "ji", "jw", "sh", */
- "ind", "heb", "yid", "jaw", "srp",
+/* "in", "iw", "ji", "jw", "mo", "sh", "swc", "tl", */
+ "ind", "heb", "yid", "jaw", "mol", "srp", "swc", "tgl",
NULL
};
@@ -334,13 +334,13 @@ static const char * const COUNTRIES[] = {
"BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV",
"BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG",
"CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR",
- "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK",
- "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER",
+ "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DG", "DJ", "DK",
+ "DM", "DO", "DZ", "EA", "EC", "EE", "EG", "EH", "ER",
"ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR",
"GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL",
"GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU",
"GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU",
- "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS",
+ "IC", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS",
"IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI",
"KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA",
"LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU",
@@ -357,7 +357,7 @@ static const char * const COUNTRIES[] = {
"TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV",
"TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ",
"VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF",
- "WS", "YE", "YT", "ZA", "ZM", "ZW",
+ "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW",
NULL,
"AN", "BU", "CS", "FX", "RO", "SU", "TP", "YD", "YU", "ZR", /* obsolete country codes */
NULL
@@ -397,10 +397,10 @@ static const char * const COUNTRIES_3[] = {
"BWA", "BLR", "BLZ", "CAN", "CCK", "COD", "CAF", "COG",
/* "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", */
"CHE", "CIV", "COK", "CHL", "CMR", "CHN", "COL", "CRI",
-/* "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", */
- "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DJI", "DNK",
-/* "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", */
- "DMA", "DOM", "DZA", "ECU", "EST", "EGY", "ESH", "ERI",
+/* "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DG", "DJ", "DK", */
+ "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DGA", "DJI", "DNK",
+/* "DM", "DO", "DZ", "EA", "EC", "EE", "EG", "EH", "ER", */
+ "DMA", "DOM", "DZA", "XEA", "ECU", "EST", "EGY", "ESH", "ERI",
/* "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", */
"ESP", "ETH", "FIN", "FJI", "FLK", "FSM", "FRO", "FRA",
/* "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", */
@@ -409,8 +409,8 @@ static const char * const COUNTRIES_3[] = {
"GMB", "GIN", "GLP", "GNQ", "GRC", "SGS", "GTM", "GUM",
/* "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", */
"GNB", "GUY", "HKG", "HMD", "HND", "HRV", "HTI", "HUN",
-/* "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS" */
- "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL",
+/* "IC", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS" */
+ "XIC", "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL",
/* "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", */
"ITA", "JEY", "JAM", "JOR", "JPN", "KEN", "KGZ", "KHM", "KIR",
/* "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", */
@@ -443,8 +443,8 @@ static const char * const COUNTRIES_3[] = {
"TWN", "TZA", "UKR", "UGA", "UMI", "USA", "URY", "UZB",
/* "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", */
"VAT", "VCT", "VEN", "VGB", "VIR", "VNM", "VUT", "WLF",
-/* "WS", "YE", "YT", "ZA", "ZM", "ZW", */
- "WSM", "YEM", "MYT", "ZAF", "ZMB", "ZWE",
+/* "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW", */
+ "WSM", "XXK", "YEM", "MYT", "ZAF", "ZMB", "ZWE",
NULL,
/* "AN", "BU", "CS", "FX", "RO", "SU", "TP", "YD", "YU", "ZR" */
"ANT", "BUR", "SCG", "FXX", "ROM", "SUN", "TMP", "YMD", "YUG", "ZAR",
diff --git a/thirdparty/icu4c/common/uloc_keytype.cpp b/thirdparty/icu4c/common/uloc_keytype.cpp
index 019da058cf..c289ebe76f 100644
--- a/thirdparty/icu4c/common/uloc_keytype.cpp
+++ b/thirdparty/icu4c/common/uloc_keytype.cpp
@@ -271,7 +271,7 @@ initFromResourceBundle(UErrorCode& sts) {
if (U_FAILURE(sts)) {
break;
}
- // check if this is an alias of canoncal legacy type
+ // check if this is an alias of canonical legacy type
if (uprv_compareInvWithUChar(NULL, legacyTypeId, -1, to, toLen) == 0) {
const char* from = ures_getKey(typeAliasDataEntry.getAlias());
if (isTZ) {
diff --git a/thirdparty/icu4c/common/uloc_tag.cpp b/thirdparty/icu4c/common/uloc_tag.cpp
index 7f7fd9119e..1235081bf3 100644
--- a/thirdparty/icu4c/common/uloc_tag.cpp
+++ b/thirdparty/icu4c/common/uloc_tag.cpp
@@ -129,7 +129,6 @@ static const char* const LEGACY[] = {
// Legacy tags with no preferred value in the IANA
// registry. Kept for now for the backward compatibility
// because ICU has mapped them this way.
- "cel-gaulish", "xtg-x-cel-gaulish",
"i-default", "en-x-i-default",
"i-enochian", "und-x-i-enochian",
"i-mingo", "see-x-i-mingo",
@@ -647,6 +646,22 @@ _isTKey(const char* s, int32_t len)
return FALSE;
}
+U_CAPI const char * U_EXPORT2
+ultag_getTKeyStart(const char *localeID) {
+ const char *result = localeID;
+ const char *sep;
+ while((sep = uprv_strchr(result, SEP)) != nullptr) {
+ if (_isTKey(result, static_cast<int32_t>(sep - result))) {
+ return result;
+ }
+ result = ++sep;
+ }
+ if (_isTKey(result, -1)) {
+ return result;
+ }
+ return nullptr;
+}
+
static UBool
_isTValue(const char* s, int32_t len)
{
@@ -671,9 +686,13 @@ _isTransformedExtensionSubtag(int32_t& state, const char* s, int32_t len)
const int32_t kGotTKey = -1; // Got tkey, wait for tvalue. ERROR if stop here.
const int32_t kGotTValue = 6; // Got tvalue, wait for tkey, tvalue or end
+
+ if (len < 0) {
+ len = (int32_t)uprv_strlen(s);
+ }
switch (state) {
case kStart:
- if (ultag_isLanguageSubtag(s, len)) {
+ if (ultag_isLanguageSubtag(s, len) && len != 4) {
state = kGotLanguage;
return TRUE;
}
@@ -1775,11 +1794,6 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
return;
}
- /* Determine if variants already exists */
- if (ultag_getVariantsSize(langtag)) {
- posixVariant = TRUE;
- }
-
n = ultag_getExtensionsSize(langtag);
/* resolve locale keywords and reordering keys */
@@ -1787,6 +1801,11 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
key = ultag_getExtensionKey(langtag, i);
type = ultag_getExtensionValue(langtag, i);
if (*key == LDMLEXT) {
+ /* Determine if variants already exists */
+ if (ultag_getVariantsSize(langtag)) {
+ posixVariant = TRUE;
+ }
+
_appendLDMLExtensionAsKeywords(type, &kwdFirst, extPool, kwdBuf, &posixVariant, status);
if (U_FAILURE(*status)) {
break;
@@ -2028,7 +2047,10 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
- uprv_memcpy(tagBuf, tag, tagLen);
+
+ if (tagLen > 0) {
+ uprv_memcpy(tagBuf, tag, tagLen);
+ }
*(tagBuf + tagLen) = 0;
/* create a ULanguageTag */
@@ -2692,8 +2714,7 @@ ulocimp_toLanguageTag(const char* localeID,
if (U_SUCCESS(tmpStatus)) {
if (ultag_isPrivateuseValueSubtags(buf.data(), buf.length())) {
/* return private use only tag */
- static const char PREFIX[] = { PRIVATEUSE, SEP };
- sink.Append(PREFIX, sizeof(PREFIX));
+ sink.Append("und-x-", 6);
sink.Append(buf.data(), buf.length());
done = TRUE;
} else if (strict) {
diff --git a/thirdparty/icu4c/common/ulocimp.h b/thirdparty/icu4c/common/ulocimp.h
index 5691fe9a77..1f796aa213 100644
--- a/thirdparty/icu4c/common/ulocimp.h
+++ b/thirdparty/icu4c/common/ulocimp.h
@@ -286,6 +286,9 @@ ultag_isUnicodeLocaleType(const char* s, int32_t len);
U_CFUNC UBool
ultag_isVariantSubtags(const char* s, int32_t len);
+U_CAPI const char * U_EXPORT2
+ultag_getTKeyStart(const char *localeID);
+
U_CFUNC const char*
ulocimp_toBcpKey(const char* key);
diff --git a/thirdparty/icu4c/common/unicode/bytestream.h b/thirdparty/icu4c/common/unicode/bytestream.h
index 044f7a77e7..9735ee0bf8 100644
--- a/thirdparty/icu4c/common/unicode/bytestream.h
+++ b/thirdparty/icu4c/common/unicode/bytestream.h
@@ -71,7 +71,6 @@ public:
*/
virtual void Append(const char* bytes, int32_t n) = 0;
-#ifndef U_HIDE_DRAFT_API
/**
* Appends n bytes to this. Same as Append().
* Call AppendU8() with u8"string literals" which are const char * in C++11
@@ -81,7 +80,7 @@ public:
*
* @param bytes the pointer to the bytes
* @param n the number of bytes; must be non-negative
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void AppendU8(const char* bytes, int32_t n) {
Append(bytes, n);
@@ -97,13 +96,12 @@ public:
*
* @param bytes the pointer to the bytes
* @param n the number of bytes; must be non-negative
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void AppendU8(const char8_t* bytes, int32_t n) {
Append(reinterpret_cast<const char*>(bytes), n);
}
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Returns a writable buffer for appending and writes the buffer's capacity to
diff --git a/thirdparty/icu4c/common/unicode/bytestrie.h b/thirdparty/icu4c/common/unicode/bytestrie.h
index 85f802df42..271a81d1b4 100644
--- a/thirdparty/icu4c/common/unicode/bytestrie.h
+++ b/thirdparty/icu4c/common/unicode/bytestrie.h
@@ -30,6 +30,8 @@
#include "unicode/uobject.h"
#include "unicode/ustringtrie.h"
+class BytesTrieTest;
+
U_NAMESPACE_BEGIN
class ByteSink;
@@ -378,6 +380,7 @@ public:
private:
friend class BytesTrieBuilder;
+ friend class ::BytesTrieTest;
/**
* Constructs a BytesTrie reader instance.
diff --git a/thirdparty/icu4c/common/unicode/bytestriebuilder.h b/thirdparty/icu4c/common/unicode/bytestriebuilder.h
index cae16e48b4..3cff89e443 100644
--- a/thirdparty/icu4c/common/unicode/bytestriebuilder.h
+++ b/thirdparty/icu4c/common/unicode/bytestriebuilder.h
@@ -30,6 +30,8 @@
#include "unicode/stringpiece.h"
#include "unicode/stringtriebuilder.h"
+class BytesTrieTest;
+
U_NAMESPACE_BEGIN
class BytesTrieElement;
@@ -125,6 +127,8 @@ public:
BytesTrieBuilder &clear();
private:
+ friend class ::BytesTrieTest;
+
BytesTrieBuilder(const BytesTrieBuilder &other); // no copy constructor
BytesTrieBuilder &operator=(const BytesTrieBuilder &other); // no assignment operator
@@ -168,6 +172,7 @@ private:
virtual int32_t writeValueAndFinal(int32_t i, UBool isFinal);
virtual int32_t writeValueAndType(UBool hasValue, int32_t value, int32_t node);
virtual int32_t writeDeltaTo(int32_t jumpTarget);
+ static int32_t internalEncodeDelta(int32_t i, char intBytes[]);
CharString *strings; // Pointer not object so we need not #include internal charstr.h.
BytesTrieElement *elements;
diff --git a/thirdparty/icu4c/common/unicode/docmain.h b/thirdparty/icu4c/common/unicode/docmain.h
index edcb5d4e83..e82678c95f 100644
--- a/thirdparty/icu4c/common/unicode/docmain.h
+++ b/thirdparty/icu4c/common/unicode/docmain.h
@@ -15,7 +15,7 @@
* \file
* \brief (Non API- contains Doxygen definitions)
*
- * This file contains documentation for Doxygen and doesnot have
+ * This file contains documentation for Doxygen and does not have
* any significance with respect to C or C++ API
*/
@@ -74,7 +74,7 @@
* </tr>
* <tr>
* <td>Strings and Character Iteration</td>
- * <td>ustring.h, utf8.h, utf16.h, UText, UCharIterator</td>
+ * <td>ustring.h, utf8.h, utf16.h, icu::StringPiece, UText, UCharIterator, icu::ByteSink</td>
* <td>icu::UnicodeString, icu::CharacterIterator, icu::Appendable, icu::StringPiece,icu::ByteSink</td>
* </tr>
* <tr>
@@ -128,9 +128,9 @@
* <td>icu::Normalizer2</td>
* </tr>
* <tr>
- * <td>Calendars</td>
+ * <td>Calendars and Time Zones</td>
* <td>ucal.h</td>
- * <td>icu::Calendar</td>
+ * <td>icu::Calendar, icu::TimeZone</td>
* </tr>
* <tr>
* <td>Date and Time Formatting</td>
diff --git a/thirdparty/icu4c/common/unicode/icuplug.h b/thirdparty/icu4c/common/unicode/icuplug.h
index 52f810da57..205af360d4 100644
--- a/thirdparty/icu4c/common/unicode/icuplug.h
+++ b/thirdparty/icu4c/common/unicode/icuplug.h
@@ -117,14 +117,13 @@
/* === Basic types === */
#ifndef U_HIDE_INTERNAL_API
+struct UPlugData;
/**
* @{
- * Opaque structure passed to/from a plugin.
- * use the APIs to access it.
+ * Typedef for opaque structure passed to/from a plugin.
+ * Use the APIs to access it.
* @internal ICU 4.4 Technology Preview
*/
-
-struct UPlugData;
typedef struct UPlugData UPlugData;
/** @} */
diff --git a/thirdparty/icu4c/common/unicode/localematcher.h b/thirdparty/icu4c/common/unicode/localematcher.h
index 63a68b0b7f..0cd068ef32 100644
--- a/thirdparty/icu4c/common/unicode/localematcher.h
+++ b/thirdparty/icu4c/common/unicode/localematcher.h
@@ -91,8 +91,6 @@ enum ULocMatchDemotion {
typedef enum ULocMatchDemotion ULocMatchDemotion;
#endif
-#ifndef U_FORCE_HIDE_DRAFT_API
-
/**
* Builder option for whether to include or ignore one-way (fallback) match data.
* The LocaleMatcher uses CLDR languageMatch data which includes fallback (oneway=true) entries.
@@ -108,20 +106,20 @@ typedef enum ULocMatchDemotion ULocMatchDemotion;
* but not if it is merely a fallback.
*
* @see LocaleMatcher::Builder#setDirection(ULocMatchDirection)
- * @draft ICU 67
+ * @stable ICU 67
*/
enum ULocMatchDirection {
/**
* Locale matching includes one-way matches such as Breton→French. (default)
*
- * @draft ICU 67
+ * @stable ICU 67
*/
ULOCMATCH_DIRECTION_WITH_ONE_WAY,
/**
* Locale matching limited to two-way matches including e.g. Danish↔Norwegian
* but ignoring one-way matches.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
ULOCMATCH_DIRECTION_ONLY_TWO_WAY
};
@@ -129,8 +127,6 @@ enum ULocMatchDirection {
typedef enum ULocMatchDirection ULocMatchDirection;
#endif
-#endif // U_FORCE_HIDE_DRAFT_API
-
struct UHashtable;
U_NAMESPACE_BEGIN
@@ -463,14 +459,13 @@ public:
*/
Builder &setDemotionPerDesiredLocale(ULocMatchDemotion demotion);
-#ifndef U_HIDE_DRAFT_API
/**
* Option for whether to include or ignore one-way (fallback) match data.
* By default, they are included.
*
* @param direction the match direction to set.
* @return this Builder object
- * @draft ICU 67
+ * @stable ICU 67
*/
Builder &setDirection(ULocMatchDirection direction) {
if (U_SUCCESS(errorCode_)) {
@@ -478,7 +473,6 @@ public:
}
return *this;
}
-#endif // U_HIDE_DRAFT_API
#ifndef U_HIDE_DRAFT_API
/**
@@ -704,7 +698,7 @@ private:
LSR *lsrs;
int32_t supportedLocalesLength;
// These are in preference order: 1. Default locale 2. paradigm locales 3. others.
- UHashtable *supportedLsrToIndex; // Map<LSR, Integer> stores index+1 because 0 is "not found"
+ UHashtable *supportedLsrToIndex; // Map<LSR, Integer>
// Array versions of the supportedLsrToIndex keys and values.
// The distance lookup loops over the supportedLSRs and returns the index of the best match.
const LSR **supportedLSRs;
diff --git a/thirdparty/icu4c/common/unicode/locid.h b/thirdparty/icu4c/common/unicode/locid.h
index ba858d702a..81f4685d65 100644
--- a/thirdparty/icu4c/common/unicode/locid.h
+++ b/thirdparty/icu4c/common/unicode/locid.h
@@ -571,15 +571,13 @@ public:
*/
void minimizeSubtags(UErrorCode& status);
-#ifndef U_HIDE_DRAFT_API
/**
* Canonicalize the locale ID of this object according to CLDR.
* @param status the status code
- * @draft ICU 67
+ * @stable ICU 67
* @see createCanonical
*/
void canonicalize(UErrorCode& status);
-#endif // U_HIDE_DRAFT_API
/**
* Gets the list of keywords for the specified locale.
diff --git a/thirdparty/icu4c/common/unicode/normalizer2.h b/thirdparty/icu4c/common/unicode/normalizer2.h
index 5eb1d95caf..2d355250c2 100644
--- a/thirdparty/icu4c/common/unicode/normalizer2.h
+++ b/thirdparty/icu4c/common/unicode/normalizer2.h
@@ -225,10 +225,8 @@ public:
* Normalizes a UTF-8 string and optionally records how source substrings
* relate to changed and unchanged result substrings.
*
- * Currently implemented completely only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * Otherwise currently converts to & from UTF-16 and does not support edits.
+ * Implemented completely for all built-in modes except for FCD.
+ * The base class implementation converts to & from UTF-16 and does not support edits.
*
* @param options Options bit set, usually 0. See U_OMIT_UNCHANGED_TEXT and U_EDITS_NO_RESET.
* @param src Source UTF-8 string.
@@ -381,11 +379,9 @@ public:
* resolves to "yes" or "no" to provide a definitive result,
* at the cost of doing more work in those cases.
*
- * This works for all normalization modes,
- * but it is currently optimized for UTF-8 only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * For other modes it currently converts to UTF-16 and calls isNormalized().
+ * This works for all normalization modes.
+ * It is optimized for UTF-8 for all built-in modes except for FCD.
+ * The base class implementation converts to UTF-16 and calls isNormalized().
*
* @param s UTF-8 input string
* @param errorCode Standard ICU error code. Its input value must
@@ -543,10 +539,8 @@ public:
* Normalizes a UTF-8 string and optionally records how source substrings
* relate to changed and unchanged result substrings.
*
- * Currently implemented completely only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * Otherwise currently converts to & from UTF-16 and does not support edits.
+ * Implemented completely for most built-in modes except for FCD.
+ * The base class implementation converts to & from UTF-16 and does not support edits.
*
* @param options Options bit set, usually 0. See U_OMIT_UNCHANGED_TEXT and U_EDITS_NO_RESET.
* @param src Source UTF-8 string.
@@ -676,11 +670,9 @@ public:
* resolves to "yes" or "no" to provide a definitive result,
* at the cost of doing more work in those cases.
*
- * This works for all normalization modes,
- * but it is currently optimized for UTF-8 only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * For other modes it currently converts to UTF-16 and calls isNormalized().
+ * This works for all normalization modes.
+ * It is optimized for UTF-8 for all built-in modes except for FCD.
+ * The base class implementation converts to UTF-16 and calls isNormalized().
*
* @param s UTF-8 input string
* @param errorCode Standard ICU error code. Its input value must
diff --git a/thirdparty/icu4c/common/unicode/platform.h b/thirdparty/icu4c/common/unicode/platform.h
index 2bb2f8b318..cb3a833fef 100644
--- a/thirdparty/icu4c/common/unicode/platform.h
+++ b/thirdparty/icu4c/common/unicode/platform.h
@@ -880,6 +880,6 @@ namespace std {
#else
# define U_CALLCONV_FPTR
#endif
-/* @} */
+/** @} */
#endif // _PLATFORM_H
diff --git a/thirdparty/icu4c/common/unicode/stringpiece.h b/thirdparty/icu4c/common/unicode/stringpiece.h
index 7d7d871e1f..8c96789e73 100644
--- a/thirdparty/icu4c/common/unicode/stringpiece.h
+++ b/thirdparty/icu4c/common/unicode/stringpiece.h
@@ -75,12 +75,11 @@ class U_COMMON_API StringPiece : public UMemory {
* @stable ICU 4.2
*/
StringPiece(const char* str);
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN)
/**
* Constructs from a NUL-terminated const char8_t * pointer.
* @param str a NUL-terminated const char8_t * pointer
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(const char8_t* str) : StringPiece(reinterpret_cast<const char*>(str)) {}
#endif
@@ -88,10 +87,9 @@ class U_COMMON_API StringPiece : public UMemory {
* Constructs an empty StringPiece.
* Needed for type disambiguation from multiple other overloads.
* @param p nullptr
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(std::nullptr_t p) : ptr_(p), length_(0) {}
-#endif // U_HIDE_DRAFT_API
/**
* Constructs from a std::string.
@@ -99,17 +97,15 @@ class U_COMMON_API StringPiece : public UMemory {
*/
StringPiece(const std::string& str)
: ptr_(str.data()), length_(static_cast<int32_t>(str.size())) { }
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_lib_char8_t) || defined(U_IN_DOXYGEN)
/**
* Constructs from a std::u8string.
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(const std::u8string& str)
: ptr_(reinterpret_cast<const char*>(str.data())),
length_(static_cast<int32_t>(str.size())) { }
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Constructs from some other implementation of a string piece class, from any
@@ -152,18 +148,16 @@ class U_COMMON_API StringPiece : public UMemory {
* @stable ICU 4.2
*/
StringPiece(const char* offset, int32_t len) : ptr_(offset), length_(len) { }
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN)
/**
* Constructs from a const char8_t * pointer and a specified length.
* @param str a const char8_t * pointer (need not be terminated)
* @param len the length of the string; must be non-negative
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(const char8_t* str, int32_t len) :
StringPiece(reinterpret_cast<const char*>(str), len) {}
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Substring of another StringPiece.
@@ -233,13 +227,12 @@ class U_COMMON_API StringPiece : public UMemory {
*/
void set(const char* str);
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN)
/**
* Resets the stringpiece to refer to new data.
* @param xdata pointer the new string data. Need not be NUL-terminated.
* @param len the length of the new data
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void set(const char8_t* xdata, int32_t len) {
set(reinterpret_cast<const char*>(xdata), len);
@@ -248,13 +241,12 @@ class U_COMMON_API StringPiece : public UMemory {
/**
* Resets the stringpiece to refer to new data.
* @param str a pointer to a NUL-terminated string.
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void set(const char8_t* str) {
set(reinterpret_cast<const char*>(str));
}
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Removes the first n string units.
@@ -286,13 +278,12 @@ class U_COMMON_API StringPiece : public UMemory {
}
}
-#ifndef U_HIDE_DRAFT_API
/**
* Searches the StringPiece for the given search string (needle);
* @param needle The string for which to search.
* @param offset Where to start searching within this string (haystack).
* @return The offset of needle in haystack, or -1 if not found.
- * @draft ICU 67
+ * @stable ICU 67
*/
int32_t find(StringPiece needle, int32_t offset);
@@ -301,10 +292,9 @@ class U_COMMON_API StringPiece : public UMemory {
* similar to std::string::compare().
* @param other The string to compare to.
* @return below zero if this < other; above zero if this > other; 0 if this == other.
- * @draft ICU 67
+ * @stable ICU 67
*/
int32_t compare(StringPiece other);
-#endif // U_HIDE_DRAFT_API
/**
* Maximum integer, used as a default value for substring methods.
diff --git a/thirdparty/icu4c/common/unicode/ubrk.h b/thirdparty/icu4c/common/unicode/ubrk.h
index 37189a8598..1249b0b160 100644
--- a/thirdparty/icu4c/common/unicode/ubrk.h
+++ b/thirdparty/icu4c/common/unicode/ubrk.h
@@ -296,6 +296,8 @@ ubrk_openBinaryRules(const uint8_t *binaryRules, int32_t rulesLength,
const UChar * text, int32_t textLength,
UErrorCode * status);
+#ifndef U_HIDE_DEPRECATED_API
+
/**
* Thread safe cloning operation
* @param bi iterator to be cloned
@@ -312,7 +314,7 @@ ubrk_openBinaryRules(const uint8_t *binaryRules, int32_t rulesLength,
* @param status to indicate whether the operation went on smoothly or there were errors
* An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used if any allocations were necessary.
* @return pointer to the new clone
- * @stable ICU 2.0
+ * @deprecated ICU 69 Use ubrk_clone() instead.
*/
U_CAPI UBreakIterator * U_EXPORT2
ubrk_safeClone(
@@ -321,6 +323,23 @@ ubrk_safeClone(
int32_t *pBufferSize,
UErrorCode *status);
+#endif /* U_HIDE_DEPRECATED_API */
+
+#ifndef U_HIDE_DRAFT_API
+
+/**
+ * Thread safe cloning operation.
+ * @param bi iterator to be cloned
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * @return pointer to the new clone
+ * @draft ICU 69
+ */
+U_CAPI UBreakIterator * U_EXPORT2
+ubrk_clone(const UBreakIterator *bi,
+ UErrorCode *status);
+
+#endif // U_HIDE_DRAFT_API
+
#ifndef U_HIDE_DEPRECATED_API
/**
diff --git a/thirdparty/icu4c/common/unicode/ucnv.h b/thirdparty/icu4c/common/unicode/ucnv.h
index 58f271cfb5..5d784990f2 100644
--- a/thirdparty/icu4c/common/unicode/ucnv.h
+++ b/thirdparty/icu4c/common/unicode/ucnv.h
@@ -1699,10 +1699,10 @@ ucnv_countAvailable(void);
/**
* Gets the canonical converter name of the specified converter from a list of
- * all available converters contaied in the alias file. All converters
+ * all available converters contained in the alias file. All converters
* in this list can be opened.
*
- * @param n the index to a converter available on the system (in the range <TT>[0..ucnv_countAvaiable()]</TT>)
+ * @param n the index to a converter available on the system (in the range <TT>[0..ucnv_countAvailable()]</TT>)
* @return a pointer a string (library owned), or <TT>NULL</TT> if the index is out of bounds.
* @see ucnv_countAvailable
* @stable ICU 2.0
diff --git a/thirdparty/icu4c/common/unicode/ucnvsel.h b/thirdparty/icu4c/common/unicode/ucnvsel.h
index 5e0a71cf35..3d7d3327f7 100644
--- a/thirdparty/icu4c/common/unicode/ucnvsel.h
+++ b/thirdparty/icu4c/common/unicode/ucnvsel.h
@@ -45,11 +45,11 @@
* from the serialized form.
*/
+struct UConverterSelector;
/**
* @{
- * The selector data structure
+ * Typedef for selector data structure.
*/
-struct UConverterSelector;
typedef struct UConverterSelector UConverterSelector;
/** @} */
diff --git a/thirdparty/icu4c/common/unicode/unifilt.h b/thirdparty/icu4c/common/unicode/unifilt.h
index 420e1a1905..7870b55939 100644
--- a/thirdparty/icu4c/common/unicode/unifilt.h
+++ b/thirdparty/icu4c/common/unicode/unifilt.h
@@ -40,8 +40,8 @@ U_NAMESPACE_BEGIN
*
* <code>UnicodeFilter</code> defines a protocol for selecting a
* subset of the full range (U+0000 to U+10FFFF) of Unicode characters.
- * Currently, filters are used in conjunction with classes like {@link
- * Transliterator} to only process selected characters through a
+ * Currently, filters are used in conjunction with classes like
+ * {@link Transliterator} to only process selected characters through a
* transformation.
*
* <p>Note: UnicodeFilter currently stubs out two pure virtual methods
diff --git a/thirdparty/icu4c/common/unicode/uniset.h b/thirdparty/icu4c/common/unicode/uniset.h
index 50b6360f3a..8403c4026c 100644
--- a/thirdparty/icu4c/common/unicode/uniset.h
+++ b/thirdparty/icu4c/common/unicode/uniset.h
@@ -178,8 +178,6 @@ class RuleCharacterIterator;
* Unicode property
* </table>
*
- * <p><b>Warning</b>: you cannot add an empty string ("") to a UnicodeSet.</p>
- *
* <p><b>Formal syntax</b></p>
*
* \htmlonly<blockquote>\endhtmlonly
@@ -601,7 +599,7 @@ public:
/**
* Make this object represent the range `start - end`.
- * If `end > start` then this object is set to an empty range.
+ * If `start > end` then this object is set to an empty range.
* A frozen set will not be modified.
*
* @param start first character in the set, inclusive
@@ -1077,7 +1075,7 @@ public:
/**
* Adds the specified range to this set if it is not already
* present. If this set already contains the specified range,
- * the call leaves this set unchanged. If <code>end > start</code>
+ * the call leaves this set unchanged. If <code>start > end</code>
* then an empty range is added, leaving the set unchanged.
* This is equivalent to a boolean logic OR, or a set UNION.
* A frozen set will not be modified.
@@ -1095,6 +1093,9 @@ public:
* present. If this set already contains the specified character,
* the call leaves this set unchanged.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& add(UChar32 c);
@@ -1104,8 +1105,8 @@ public:
* present. If this set already contains the multicharacter,
* the call leaves this set unchanged.
* Thus "ch" => {"ch"}
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
* A frozen set will not be modified.
+ *
* @param s the source string
* @return this object, for chaining
* @stable ICU 2.4
@@ -1124,8 +1125,8 @@ public:
public:
/**
- * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
+ * Adds each of the characters in this string to the set. Note: "ch" => {"c", "h"}
+ * If this set already contains any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1135,7 +1136,6 @@ public:
/**
* Retains EACH of the characters in this string. Note: "ch" == {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1145,7 +1145,6 @@ public:
/**
* Complement EACH of the characters in this string. Note: "ch" == {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1155,7 +1154,6 @@ public:
/**
* Remove EACH of the characters in this string. Note: "ch" == {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1165,7 +1163,7 @@ public:
/**
* Makes a set from a multicharacter string. Thus "ch" => {"ch"}
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ *
* @param s the source string
* @return a newly created set containing the given string.
* The caller owns the return object and is responsible for deleting it.
@@ -1185,15 +1183,13 @@ public:
/**
* Retain only the elements in this set that are contained in the
- * specified range. If <code>end > start</code> then an empty range is
+ * specified range. If <code>start > end</code> then an empty range is
* retained, leaving the set empty. This is equivalent to
* a boolean logic AND, or a set INTERSECTION.
* A frozen set will not be modified.
*
- * @param start first character, inclusive, of range to be retained
- * to this set.
- * @param end last character, inclusive, of range to be retained
- * to this set.
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
* @stable ICU 2.0
*/
virtual UnicodeSet& retain(UChar32 start, UChar32 end);
@@ -1202,14 +1198,31 @@ public:
/**
* Retain the specified character from this set if it is present.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& retain(UChar32 c);
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Retains only the specified string from this set if it is present.
+ * Upon return this set will be empty if it did not contain s, or
+ * will only contain s if it did contain s.
+ * A frozen set will not be modified.
+ *
+ * @param s the source string
+ * @return this object, for chaining
+ * @draft ICU 69
+ */
+ UnicodeSet& retain(const UnicodeString &s);
+#endif // U_HIDE_DRAFT_API
+
/**
* Removes the specified range from this set if it is present.
* The set will not contain the specified range once the call
- * returns. If <code>end > start</code> then an empty range is
+ * returns. If <code>start > end</code> then an empty range is
* removed, leaving the set unchanged.
* A frozen set will not be modified.
*
@@ -1226,6 +1239,9 @@ public:
* The set will not contain the specified range once the call
* returns.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& remove(UChar32 c);
@@ -1253,15 +1269,13 @@ public:
/**
* Complements the specified range in this set. Any character in
* the range will be removed if it is in this set, or will be
- * added if it is not in this set. If <code>end > start</code>
+ * added if it is not in this set. If <code>start > end</code>
* then an empty range is complemented, leaving the set unchanged.
* This is equivalent to a boolean logic XOR.
* A frozen set will not be modified.
*
- * @param start first character, inclusive, of range to be removed
- * from this set.
- * @param end last character, inclusive, of range to be removed
- * from this set.
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
* @stable ICU 2.0
*/
virtual UnicodeSet& complement(UChar32 start, UChar32 end);
@@ -1271,16 +1285,18 @@ public:
* will be removed if it is in this set, or will be added if it is
* not in this set.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& complement(UChar32 c);
/**
* Complement the specified string in this set.
- * The set will not contain the specified string once the call
- * returns.
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ * The string will be removed if it is in this set, or will be added if it is not in this set.
* A frozen set will not be modified.
+ *
* @param s the string to complement
* @return this object, for chaining
* @stable ICU 2.4
diff --git a/thirdparty/icu4c/common/unicode/unistr.h b/thirdparty/icu4c/common/unicode/unistr.h
index 456389f265..85bd964951 100644
--- a/thirdparty/icu4c/common/unicode/unistr.h
+++ b/thirdparty/icu4c/common/unicode/unistr.h
@@ -44,9 +44,10 @@ struct UConverter; // unicode/ucnv.h
#ifndef USTRING_H
/**
* \ingroup ustring_ustrlen
+ * @param s Pointer to sequence of UChars.
+ * @return Length of sequence.
*/
-U_CAPI int32_t U_EXPORT2
-u_strlen(const UChar *s);
+U_CAPI int32_t U_EXPORT2 u_strlen(const UChar *s);
#endif
U_NAMESPACE_BEGIN
@@ -2766,7 +2767,6 @@ public:
* @param options Options bit set, usually 0. See U_TITLECASE_NO_LOWERCASE,
* U_TITLECASE_NO_BREAK_ADJUSTMENT, U_TITLECASE_ADJUST_TO_CASED,
* U_TITLECASE_WHOLE_STRING, U_TITLECASE_SENTENCES.
- * @param options Options bit set, see ucasemap_open().
* @return A reference to this.
* @stable ICU 3.8
*/
@@ -3614,7 +3614,7 @@ private:
// turn a bogus string into an empty one
void unBogus();
- // implements assigment operator, copy constructor, and fastCopyFrom()
+ // implements assignment operator, copy constructor, and fastCopyFrom()
UnicodeString &copyFrom(const UnicodeString &src, UBool fastCopy=false);
// Copies just the fields without memory management.
diff --git a/thirdparty/icu4c/common/unicode/urename.h b/thirdparty/icu4c/common/unicode/urename.h
index fe59fdd893..737f4b308e 100644
--- a/thirdparty/icu4c/common/unicode/urename.h
+++ b/thirdparty/icu4c/common/unicode/urename.h
@@ -482,6 +482,7 @@
#define ubiditransform_open U_ICU_ENTRY_POINT_RENAME(ubiditransform_open)
#define ubiditransform_transform U_ICU_ENTRY_POINT_RENAME(ubiditransform_transform)
#define ublock_getCode U_ICU_ENTRY_POINT_RENAME(ublock_getCode)
+#define ubrk_clone U_ICU_ENTRY_POINT_RENAME(ubrk_clone)
#define ubrk_close U_ICU_ENTRY_POINT_RENAME(ubrk_close)
#define ubrk_countAvailable U_ICU_ENTRY_POINT_RENAME(ubrk_countAvailable)
#define ubrk_current U_ICU_ENTRY_POINT_RENAME(ubrk_current)
@@ -534,6 +535,7 @@
#define ucal_getTimeZoneDisplayName U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneDisplayName)
#define ucal_getTimeZoneID U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneID)
#define ucal_getTimeZoneIDForWindowsID U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneIDForWindowsID)
+#define ucal_getTimeZoneOffsetFromLocal U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneOffsetFromLocal)
#define ucal_getTimeZoneTransitionDate U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneTransitionDate)
#define ucal_getType U_ICU_ENTRY_POINT_RENAME(ucal_getType)
#define ucal_getWeekendTransition U_ICU_ENTRY_POINT_RENAME(ucal_getWeekendTransition)
@@ -962,6 +964,7 @@
#define uhash_compareScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_compareScriptSet)
#define uhash_compareUChars U_ICU_ENTRY_POINT_RENAME(uhash_compareUChars)
#define uhash_compareUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_compareUnicodeString)
+#define uhash_containsKey U_ICU_ENTRY_POINT_RENAME(uhash_containsKey)
#define uhash_count U_ICU_ENTRY_POINT_RENAME(uhash_count)
#define uhash_deleteHashtable U_ICU_ENTRY_POINT_RENAME(uhash_deleteHashtable)
#define uhash_deleteScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_deleteScriptSet)
@@ -970,6 +973,7 @@
#define uhash_find U_ICU_ENTRY_POINT_RENAME(uhash_find)
#define uhash_get U_ICU_ENTRY_POINT_RENAME(uhash_get)
#define uhash_geti U_ICU_ENTRY_POINT_RENAME(uhash_geti)
+#define uhash_getiAndFound U_ICU_ENTRY_POINT_RENAME(uhash_getiAndFound)
#define uhash_hashCaselessUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_hashCaselessUnicodeString)
#define uhash_hashChars U_ICU_ENTRY_POINT_RENAME(uhash_hashChars)
#define uhash_hashIChars U_ICU_ENTRY_POINT_RENAME(uhash_hashIChars)
@@ -977,12 +981,15 @@
#define uhash_hashScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_hashScriptSet)
#define uhash_hashUChars U_ICU_ENTRY_POINT_RENAME(uhash_hashUChars)
#define uhash_hashUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_hashUnicodeString)
+#define uhash_icontainsKey U_ICU_ENTRY_POINT_RENAME(uhash_icontainsKey)
#define uhash_iget U_ICU_ENTRY_POINT_RENAME(uhash_iget)
#define uhash_igeti U_ICU_ENTRY_POINT_RENAME(uhash_igeti)
+#define uhash_igetiAndFound U_ICU_ENTRY_POINT_RENAME(uhash_igetiAndFound)
#define uhash_init U_ICU_ENTRY_POINT_RENAME(uhash_init)
#define uhash_initSize U_ICU_ENTRY_POINT_RENAME(uhash_initSize)
#define uhash_iput U_ICU_ENTRY_POINT_RENAME(uhash_iput)
#define uhash_iputi U_ICU_ENTRY_POINT_RENAME(uhash_iputi)
+#define uhash_iputiAllowZero U_ICU_ENTRY_POINT_RENAME(uhash_iputiAllowZero)
#define uhash_iremove U_ICU_ENTRY_POINT_RENAME(uhash_iremove)
#define uhash_iremovei U_ICU_ENTRY_POINT_RENAME(uhash_iremovei)
#define uhash_nextElement U_ICU_ENTRY_POINT_RENAME(uhash_nextElement)
@@ -990,6 +997,7 @@
#define uhash_openSize U_ICU_ENTRY_POINT_RENAME(uhash_openSize)
#define uhash_put U_ICU_ENTRY_POINT_RENAME(uhash_put)
#define uhash_puti U_ICU_ENTRY_POINT_RENAME(uhash_puti)
+#define uhash_putiAllowZero U_ICU_ENTRY_POINT_RENAME(uhash_putiAllowZero)
#define uhash_remove U_ICU_ENTRY_POINT_RENAME(uhash_remove)
#define uhash_removeAll U_ICU_ENTRY_POINT_RENAME(uhash_removeAll)
#define uhash_removeElement U_ICU_ENTRY_POINT_RENAME(uhash_removeElement)
@@ -1150,6 +1158,8 @@
#define ultag_isUnicodeLocaleKey U_ICU_ENTRY_POINT_RENAME(ultag_isUnicodeLocaleKey)
#define ultag_isUnicodeLocaleType U_ICU_ENTRY_POINT_RENAME(ultag_isUnicodeLocaleType)
#define ultag_isVariantSubtags U_ICU_ENTRY_POINT_RENAME(ultag_isVariantSubtags)
+#define umeas_getPrefixBase U_ICU_ENTRY_POINT_RENAME(umeas_getPrefixBase)
+#define umeas_getPrefixPower U_ICU_ENTRY_POINT_RENAME(umeas_getPrefixPower)
#define umsg_applyPattern U_ICU_ENTRY_POINT_RENAME(umsg_applyPattern)
#define umsg_autoQuoteApostrophe U_ICU_ENTRY_POINT_RENAME(umsg_autoQuoteApostrophe)
#define umsg_clone U_ICU_ENTRY_POINT_RENAME(umsg_clone)
@@ -1672,6 +1682,9 @@
#define uset_compact U_ICU_ENTRY_POINT_RENAME(uset_compact)
#define uset_complement U_ICU_ENTRY_POINT_RENAME(uset_complement)
#define uset_complementAll U_ICU_ENTRY_POINT_RENAME(uset_complementAll)
+#define uset_complementAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_complementAllCodePoints)
+#define uset_complementRange U_ICU_ENTRY_POINT_RENAME(uset_complementRange)
+#define uset_complementString U_ICU_ENTRY_POINT_RENAME(uset_complementString)
#define uset_contains U_ICU_ENTRY_POINT_RENAME(uset_contains)
#define uset_containsAll U_ICU_ENTRY_POINT_RENAME(uset_containsAll)
#define uset_containsAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_containsAllCodePoints)
@@ -1695,12 +1708,15 @@
#define uset_openPatternOptions U_ICU_ENTRY_POINT_RENAME(uset_openPatternOptions)
#define uset_remove U_ICU_ENTRY_POINT_RENAME(uset_remove)
#define uset_removeAll U_ICU_ENTRY_POINT_RENAME(uset_removeAll)
+#define uset_removeAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_removeAllCodePoints)
#define uset_removeAllStrings U_ICU_ENTRY_POINT_RENAME(uset_removeAllStrings)
#define uset_removeRange U_ICU_ENTRY_POINT_RENAME(uset_removeRange)
#define uset_removeString U_ICU_ENTRY_POINT_RENAME(uset_removeString)
#define uset_resemblesPattern U_ICU_ENTRY_POINT_RENAME(uset_resemblesPattern)
#define uset_retain U_ICU_ENTRY_POINT_RENAME(uset_retain)
#define uset_retainAll U_ICU_ENTRY_POINT_RENAME(uset_retainAll)
+#define uset_retainAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_retainAllCodePoints)
+#define uset_retainString U_ICU_ENTRY_POINT_RENAME(uset_retainString)
#define uset_serialize U_ICU_ENTRY_POINT_RENAME(uset_serialize)
#define uset_serializedContains U_ICU_ENTRY_POINT_RENAME(uset_serializedContains)
#define uset_set U_ICU_ENTRY_POINT_RENAME(uset_set)
diff --git a/thirdparty/icu4c/common/unicode/uset.h b/thirdparty/icu4c/common/unicode/uset.h
index 502ea8dc14..1d0daf9d09 100644
--- a/thirdparty/icu4c/common/unicode/uset.h
+++ b/thirdparty/icu4c/common/unicode/uset.h
@@ -582,8 +582,8 @@ U_CAPI void U_EXPORT2
uset_addString(USet* set, const UChar* str, int32_t strLen);
/**
- * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
+ * Adds each of the characters in this string to the set. Note: "ch" => {"c", "h"}
+ * If this set already contains any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param set the object to which to add the character
* @param str the source string
@@ -628,6 +628,20 @@ uset_removeRange(USet* set, UChar32 start, UChar32 end);
U_CAPI void U_EXPORT2
uset_removeString(USet* set, const UChar* str, int32_t strLen);
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Removes EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_removeAllCodePoints(USet *set, const UChar *str, int32_t length);
+#endif // U_HIDE_DRAFT_API
+
/**
* Removes from this set all of its elements that are contained in the
* specified set. This operation effectively modifies this
@@ -650,15 +664,41 @@ uset_removeAll(USet* set, const USet* removeSet);
* A frozen set will not be modified.
*
* @param set the object for which to retain only the specified range
- * @param start first character, inclusive, of range to be retained
- * to this set.
- * @param end last character, inclusive, of range to be retained
- * to this set.
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
* @stable ICU 3.2
*/
U_CAPI void U_EXPORT2
uset_retain(USet* set, UChar32 start, UChar32 end);
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Retains only the specified string from this set if it is present.
+ * Upon return this set will be empty if it did not contain s, or
+ * will only contain s if it did contain s.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_retainString(USet *set, const UChar *str, int32_t length);
+
+/**
+ * Retains EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_retainAllCodePoints(USet *set, const UChar *str, int32_t length);
+#endif // U_HIDE_DRAFT_API
+
/**
* Retains only the elements in this set that are contained in the
* specified set. In other words, removes from this set all of
@@ -696,6 +736,49 @@ uset_compact(USet* set);
U_CAPI void U_EXPORT2
uset_complement(USet* set);
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Complements the specified range in this set. Any character in
+ * the range will be removed if it is in this set, or will be
+ * added if it is not in this set. If <code>start > end</code>
+ * then an empty range is complemented, leaving the set unchanged.
+ * This is equivalent to a boolean logic XOR.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_complementRange(USet *set, UChar32 start, UChar32 end);
+
+/**
+ * Complements the specified string in this set.
+ * The string will be removed if it is in this set, or will be added if it is not in this set.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_complementString(USet *set, const UChar *str, int32_t length);
+
+/**
+ * Complements EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_complementAllCodePoints(USet *set, const UChar *str, int32_t length);
+#endif // U_HIDE_DRAFT_API
+
/**
* Complements in this set all elements contained in the specified
* set. Any character in the other set will be removed if it is
diff --git a/thirdparty/icu4c/common/unicode/ushape.h b/thirdparty/icu4c/common/unicode/ushape.h
index fed4869abd..14371edc8f 100644
--- a/thirdparty/icu4c/common/unicode/ushape.h
+++ b/thirdparty/icu4c/common/unicode/ushape.h
@@ -323,7 +323,7 @@ u_shapeArabic(const UChar *source, int32_t sourceLength,
#define U_SHAPE_PRESERVE_PRESENTATION 0x8000
/** Presentation form option:
* Replace Arabic Presentation Forms-A and Arabic Presentationo Forms-B with
- * their unshaped correspondants in range 0+06xx, before shaping.
+ * their unshaped correspondents in range 0+06xx, before shaping.
* @stable ICU 3.6
*/
#define U_SHAPE_PRESERVE_PRESENTATION_NOOP 0
diff --git a/thirdparty/icu4c/common/unicode/utrace.h b/thirdparty/icu4c/common/unicode/utrace.h
index 28c313c582..677486f473 100644
--- a/thirdparty/icu4c/common/unicode/utrace.h
+++ b/thirdparty/icu4c/common/unicode/utrace.h
@@ -173,24 +173,23 @@ typedef enum UTraceFunctionNumber {
UTRACE_RES_DATA_LIMIT,
#endif // U_HIDE_INTERNAL_API
-#ifndef U_HIDE_DRAFT_API
/**
* The lowest break iterator location.
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_START=0x4000,
/**
* Indicates that a character instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_CHARACTER = UTRACE_UBRK_START,
/**
* Indicates that a word instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_WORD,
@@ -200,21 +199,21 @@ typedef enum UTraceFunctionNumber {
* Provides one C-style string to UTraceData: the lb value ("",
* "loose", "strict", or "normal").
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_LINE,
/**
* Indicates that a sentence instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_SENTENCE,
/**
* Indicates that a title instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_TITLE,
@@ -224,12 +223,10 @@ typedef enum UTraceFunctionNumber {
* Provides one C-style string to UTraceData: the script code of what
* the break engine cover ("Hani", "Khmr", "Laoo", "Mymr", or "Thai").
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_BREAK_ENGINE,
-#endif // U_HIDE_DRAFT_API
-
#ifndef U_HIDE_INTERNAL_API
/**
* One more than the highest normal break iterator trace location.
diff --git a/thirdparty/icu4c/common/unicode/uvernum.h b/thirdparty/icu4c/common/unicode/uvernum.h
index a46481a3fe..b09d4943c1 100644
--- a/thirdparty/icu4c/common/unicode/uvernum.h
+++ b/thirdparty/icu4c/common/unicode/uvernum.h
@@ -60,13 +60,13 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION_MAJOR_NUM 68
+#define U_ICU_VERSION_MAJOR_NUM 69
/** The current ICU minor version as an integer.
* This value will change in the subsequent releases of ICU
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_MINOR_NUM 2
+#define U_ICU_VERSION_MINOR_NUM 1
/** The current ICU patchlevel version as an integer.
* This value will change in the subsequent releases of ICU
@@ -86,7 +86,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_SUFFIX _68
+#define U_ICU_VERSION_SUFFIX _69
/**
* \def U_DEF2_ICU_ENTRY_POINT_RENAME
@@ -139,7 +139,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION "68.2"
+#define U_ICU_VERSION "69.1"
/**
* The current ICU library major version number as a string, for library name suffixes.
@@ -152,13 +152,13 @@
*
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_SHORT "68"
+#define U_ICU_VERSION_SHORT "69"
#ifndef U_HIDE_INTERNAL_API
/** Data version in ICU4C.
* @internal ICU 4.4 Internal Use Only
**/
-#define U_ICU_DATA_VERSION "68.2"
+#define U_ICU_DATA_VERSION "69.1"
#endif /* U_HIDE_INTERNAL_API */
/*===========================================================================
diff --git a/thirdparty/icu4c/common/uniset.cpp b/thirdparty/icu4c/common/uniset.cpp
index b73d612f24..461e5a7197 100644
--- a/thirdparty/icu4c/common/uniset.cpp
+++ b/thirdparty/icu4c/common/uniset.cpp
@@ -30,24 +30,6 @@
#include "bmpset.h"
#include "unisetspan.h"
-// Define UChar constants using hex for EBCDIC compatibility
-// Used #define to reduce private static exports and memory access time.
-#define SET_OPEN ((UChar)0x005B) /*[*/
-#define SET_CLOSE ((UChar)0x005D) /*]*/
-#define HYPHEN ((UChar)0x002D) /*-*/
-#define COMPLEMENT ((UChar)0x005E) /*^*/
-#define COLON ((UChar)0x003A) /*:*/
-#define BACKSLASH ((UChar)0x005C) /*\*/
-#define INTERSECTION ((UChar)0x0026) /*&*/
-#define UPPER_U ((UChar)0x0055) /*U*/
-#define LOWER_U ((UChar)0x0075) /*u*/
-#define OPEN_BRACE ((UChar)123) /*{*/
-#define CLOSE_BRACE ((UChar)125) /*}*/
-#define UPPER_P ((UChar)0x0050) /*P*/
-#define LOWER_P ((UChar)0x0070) /*p*/
-#define UPPER_N ((UChar)78) /*N*/
-#define EQUALS ((UChar)0x003D) /*=*/
-
// HIGH_VALUE > all valid values. 110000 for codepoints
#define UNICODESET_HIGH 0x0110000
@@ -444,7 +426,6 @@ UBool UnicodeSet::contains(UChar32 start, UChar32 end) const {
* @return <tt>true</tt> if this set contains the specified string
*/
UBool UnicodeSet::contains(const UnicodeString& s) const {
- if (s.length() == 0) return FALSE;
int32_t cp = getSingleCP(s);
if (cp < 0) {
return stringsContains(s);
@@ -559,11 +540,9 @@ UBool UnicodeSet::matchesIndexValue(uint8_t v) const {
if (hasStrings()) {
for (i=0; i<strings->size(); ++i) {
const UnicodeString& s = *(const UnicodeString*)strings->elementAt(i);
- //if (s.length() == 0) {
- // // Empty strings match everything
- // return TRUE;
- //}
- // assert(s.length() != 0); // We enforce this elsewhere
+ if (s.isEmpty()) {
+ continue; // skip the empty string
+ }
UChar32 c = s.char32At(0);
if ((c & 0xFF) == v) {
return TRUE;
@@ -582,9 +561,6 @@ UMatchDegree UnicodeSet::matches(const Replaceable& text,
int32_t limit,
UBool incremental) {
if (offset == limit) {
- // Strings, if any, have length != 0, so we don't worry
- // about them here. If we ever allow zero-length strings
- // we much check for them here.
if (contains(U_ETHER)) {
return incremental ? U_PARTIAL_MATCH : U_MATCH;
} else {
@@ -614,11 +590,9 @@ UMatchDegree UnicodeSet::matches(const Replaceable& text,
for (i=0; i<strings->size(); ++i) {
const UnicodeString& trial = *(const UnicodeString*)strings->elementAt(i);
-
- //if (trial.length() == 0) {
- // return U_MATCH; // null-string always matches
- //}
- // assert(trial.length() != 0); // We ensure this elsewhere
+ if (trial.isEmpty()) {
+ continue; // skip the empty string
+ }
UChar c = trial.charAt(forward ? 0 : trial.length() - 1);
@@ -971,12 +945,12 @@ UnicodeSet& UnicodeSet::add(UChar32 c) {
* present. If this set already contains the multicharacter,
* the call leaves this set unchanged.
* Thus "ch" => {"ch"}
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ *
* @param s the source string
* @return the modified set, for chaining
*/
UnicodeSet& UnicodeSet::add(const UnicodeString& s) {
- if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+ if (isFrozen() || isBogus()) return *this;
int32_t cp = getSingleCP(s);
if (cp < 0) {
if (!stringsContains(s)) {
@@ -991,8 +965,7 @@ UnicodeSet& UnicodeSet::add(const UnicodeString& s) {
/**
* Adds the given string, in order, to 'strings'. The given string
- * must have been checked by the caller to not be empty and to not
- * already be in 'strings'.
+ * must have been checked by the caller to not already be in 'strings'.
*/
void UnicodeSet::_add(const UnicodeString& s) {
if (isFrozen() || isBogus()) {
@@ -1021,16 +994,13 @@ void UnicodeSet::_add(const UnicodeString& s) {
* @param string to test
*/
int32_t UnicodeSet::getSingleCP(const UnicodeString& s) {
- //if (s.length() < 1) {
- // throw new IllegalArgumentException("Can't use zero-length strings in UnicodeSet");
- //}
- if (s.length() > 2) return -1;
- if (s.length() == 1) return s.charAt(0);
-
- // at this point, len = 2
- UChar32 cp = s.char32At(0);
- if (cp > 0xFFFF) { // is surrogate pair
- return cp;
+ int32_t sLength = s.length();
+ if (sLength == 1) return s.charAt(0);
+ if (sLength == 2) {
+ UChar32 cp = s.char32At(0);
+ if (cp > 0xFFFF) { // is surrogate pair
+ return cp;
+ }
}
return -1;
}
@@ -1150,6 +1120,26 @@ UnicodeSet& UnicodeSet::retain(UChar32 c) {
return retain(c, c);
}
+UnicodeSet& UnicodeSet::retain(const UnicodeString &s) {
+ if (isFrozen() || isBogus()) { return *this; }
+ UChar32 cp = getSingleCP(s);
+ if (cp < 0) {
+ bool isIn = stringsContains(s);
+ // Check for getRangeCount() first to avoid somewhat-expensive size()
+ // when there are single code points.
+ if (isIn && getRangeCount() == 0 && size() == 1) {
+ return *this;
+ }
+ clear();
+ if (isIn) {
+ _add(s);
+ }
+ } else {
+ retain(cp, cp);
+ }
+ return *this;
+}
+
/**
* Removes the specified range from this set if it is present.
* The set will not contain the specified range once the call
@@ -1186,7 +1176,7 @@ UnicodeSet& UnicodeSet::remove(UChar32 c) {
* @return the modified set, for chaining
*/
UnicodeSet& UnicodeSet::remove(const UnicodeString& s) {
- if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+ if (isFrozen() || isBogus()) return *this;
int32_t cp = getSingleCP(s);
if (cp < 0) {
if (strings != nullptr && strings->removeElement((void*) &s)) {
@@ -1252,12 +1242,12 @@ UnicodeSet& UnicodeSet::complement(void) {
* Complement the specified string in this set.
* The set will not contain the specified string once the call
* returns.
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ *
* @param s the string to complement
* @return this object, for chaining
*/
UnicodeSet& UnicodeSet::complement(const UnicodeString& s) {
- if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+ if (isFrozen() || isBogus()) return *this;
int32_t cp = getSingleCP(s);
if (cp < 0) {
if (stringsContains(s)) {
@@ -2001,22 +1991,22 @@ escapeUnprintable) {
}
// Okay to let ':' pass through
switch (c) {
- case SET_OPEN:
- case SET_CLOSE:
- case HYPHEN:
- case COMPLEMENT:
- case INTERSECTION:
- case BACKSLASH:
- case OPEN_BRACE:
- case CLOSE_BRACE:
- case COLON:
+ case u'[':
+ case u']':
+ case u'-':
+ case u'^':
+ case u'&':
+ case u'\\':
+ case u'{':
+ case u'}':
+ case u':':
case SymbolTable::SYMBOL_REF:
- buf.append(BACKSLASH);
+ buf.append(u'\\');
break;
default:
// Escape whitespace
if (PatternProps::isWhiteSpace(c)) {
- buf.append(BACKSLASH);
+ buf.append(u'\\');
}
break;
}
@@ -2049,7 +2039,7 @@ UnicodeString& UnicodeSet::_toPattern(UnicodeString& result,
backslashCount = 0;
} else {
result.append(c);
- if (c == BACKSLASH) {
+ if (c == u'\\') {
++backslashCount;
} else {
backslashCount = 0;
@@ -2082,13 +2072,13 @@ UnicodeString& UnicodeSet::toPattern(UnicodeString& result,
UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
UBool escapeUnprintable) const
{
- result.append(SET_OPEN);
+ result.append(u'[');
// // Check against the predefined categories. We implicitly build
// // up ALL category sets the first time toPattern() is called.
// for (int8_t cat=0; cat<Unicode::GENERAL_TYPES_COUNT; ++cat) {
// if (*this == getCategorySet(cat)) {
-// result.append(COLON);
+// result.append(u':');
// result.append(CATEGORY_NAMES, cat*2, 2);
// return result.append(CATEGORY_CLOSE);
// }
@@ -2104,7 +2094,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
getRangeEnd(count-1) == MAX_VALUE) {
// Emit the inverse
- result.append(COMPLEMENT);
+ result.append(u'^');
for (int32_t i = 1; i < count; ++i) {
UChar32 start = getRangeEnd(i-1)+1;
@@ -2112,7 +2102,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
_appendToPat(result, start, escapeUnprintable);
if (start != end) {
if ((start+1) != end) {
- result.append(HYPHEN);
+ result.append(u'-');
}
_appendToPat(result, end, escapeUnprintable);
}
@@ -2127,7 +2117,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
_appendToPat(result, start, escapeUnprintable);
if (start != end) {
if ((start+1) != end) {
- result.append(HYPHEN);
+ result.append(u'-');
}
_appendToPat(result, end, escapeUnprintable);
}
@@ -2136,14 +2126,14 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
if (strings != nullptr) {
for (int32_t i = 0; i<strings->size(); ++i) {
- result.append(OPEN_BRACE);
+ result.append(u'{');
_appendToPat(result,
*(const UnicodeString*) strings->elementAt(i),
escapeUnprintable);
- result.append(CLOSE_BRACE);
+ result.append(u'}');
}
}
- return result.append(SET_CLOSE);
+ return result.append(u']');
}
/**
diff --git a/thirdparty/icu4c/common/uniset_props.cpp b/thirdparty/icu4c/common/uniset_props.cpp
index 37277fcb75..8fde5abcdd 100644
--- a/thirdparty/icu4c/common/uniset_props.cpp
+++ b/thirdparty/icu4c/common/uniset_props.cpp
@@ -47,31 +47,6 @@
U_NAMESPACE_USE
-// Define UChar constants using hex for EBCDIC compatibility
-// Used #define to reduce private static exports and memory access time.
-#define SET_OPEN ((UChar)0x005B) /*[*/
-#define SET_CLOSE ((UChar)0x005D) /*]*/
-#define HYPHEN ((UChar)0x002D) /*-*/
-#define COMPLEMENT ((UChar)0x005E) /*^*/
-#define COLON ((UChar)0x003A) /*:*/
-#define BACKSLASH ((UChar)0x005C) /*\*/
-#define INTERSECTION ((UChar)0x0026) /*&*/
-#define UPPER_U ((UChar)0x0055) /*U*/
-#define LOWER_U ((UChar)0x0075) /*u*/
-#define OPEN_BRACE ((UChar)123) /*{*/
-#define CLOSE_BRACE ((UChar)125) /*}*/
-#define UPPER_P ((UChar)0x0050) /*P*/
-#define LOWER_P ((UChar)0x0070) /*p*/
-#define UPPER_N ((UChar)78) /*N*/
-#define EQUALS ((UChar)0x003D) /*=*/
-
-//static const UChar POSIX_OPEN[] = { SET_OPEN,COLON,0 }; // "[:"
-static const UChar POSIX_CLOSE[] = { COLON,SET_CLOSE,0 }; // ":]"
-//static const UChar PERL_OPEN[] = { BACKSLASH,LOWER_P,0 }; // "\\p"
-//static const UChar PERL_CLOSE[] = { CLOSE_BRACE,0 }; // "}"
-//static const UChar NAME_OPEN[] = { BACKSLASH,UPPER_N,0 }; // "\\N"
-static const UChar HYPHEN_RIGHT_BRACE[] = {HYPHEN,SET_CLOSE,0}; /*-]*/
-
// Special property set IDs
static const char ANY[] = "ANY"; // [\u0000-\U0010FFFF]
static const char ASCII[] = "ASCII"; // [\u0000-\u007F]
@@ -81,12 +56,6 @@ static const char ASSIGNED[] = "Assigned"; // [:^Cn:]
#define NAME_PROP "na"
#define NAME_PROP_LENGTH 2
-/**
- * Delimiter string used in patterns to close a category reference:
- * ":]". Example: "[:Lu:]".
- */
-//static const UChar CATEGORY_CLOSE[] = {COLON, SET_CLOSE, 0x0000}; /* ":]" */
-
// Cached sets ------------------------------------------------------------- ***
U_CDECL_BEGIN
@@ -140,27 +109,27 @@ uniset_getUnicode32Instance(UErrorCode &errorCode) {
static inline UBool
isPerlOpen(const UnicodeString &pattern, int32_t pos) {
UChar c;
- return pattern.charAt(pos)==BACKSLASH && ((c=pattern.charAt(pos+1))==LOWER_P || c==UPPER_P);
+ return pattern.charAt(pos)==u'\\' && ((c=pattern.charAt(pos+1))==u'p' || c==u'P');
}
/*static inline UBool
isPerlClose(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==CLOSE_BRACE;
+ return pattern.charAt(pos)==u'}';
}*/
static inline UBool
isNameOpen(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==BACKSLASH && pattern.charAt(pos+1)==UPPER_N;
+ return pattern.charAt(pos)==u'\\' && pattern.charAt(pos+1)==u'N';
}
static inline UBool
isPOSIXOpen(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==SET_OPEN && pattern.charAt(pos+1)==COLON;
+ return pattern.charAt(pos)==u'[' && pattern.charAt(pos+1)==u':';
}
/*static inline UBool
isPOSIXClose(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==COLON && pattern.charAt(pos+1)==SET_CLOSE;
+ return pattern.charAt(pos)==u':' && pattern.charAt(pos+1)==u']';
}*/
// TODO memory debugging provided inside uniset.cpp
@@ -326,9 +295,8 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
while (mode != 2 && !chars.atEnd()) {
U_ASSERT((lastItem == 0 && op == 0) ||
- (lastItem == 1 && (op == 0 || op == HYPHEN /*'-'*/)) ||
- (lastItem == 2 && (op == 0 || op == HYPHEN /*'-'*/ ||
- op == INTERSECTION /*'&'*/)));
+ (lastItem == 1 && (op == 0 || op == u'-')) ||
+ (lastItem == 2 && (op == 0 || op == u'-' || op == u'&')));
UChar32 c = 0;
UBool literal = FALSE;
@@ -356,27 +324,27 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x5B /*'['*/ && !literal) {
+ if (c == u'[' && !literal) {
if (mode == 1) {
chars.setPos(backup); // backup
setMode = 1;
} else {
// Handle opening '[' delimiter
mode = 1;
- patLocal.append((UChar) 0x5B /*'['*/);
+ patLocal.append(u'[');
chars.getPos(backup); // prepare to backup
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x5E /*'^'*/ && !literal) {
+ if (c == u'^' && !literal) {
invert = TRUE;
- patLocal.append((UChar) 0x5E /*'^'*/);
+ patLocal.append(u'^');
chars.getPos(backup); // prepare to backup
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
}
// Fall through to handle special leading '-';
// otherwise restart loop for nested [], \p{}, etc.
- if (c == HYPHEN /*'-'*/) {
+ if (c == u'-') {
literal = TRUE;
// Fall through to handle literal '-' below
} else {
@@ -418,7 +386,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
op = 0;
}
- if (op == HYPHEN /*'-'*/ || op == INTERSECTION /*'&'*/) {
+ if (op == u'-' || op == u'&') {
patLocal.append(op);
}
@@ -454,10 +422,10 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
}
switch (op) {
- case HYPHEN: /*'-'*/
+ case u'-':
removeAll(*nested);
break;
- case INTERSECTION: /*'&'*/
+ case u'&':
retainAll(*nested);
break;
case 0:
@@ -483,24 +451,24 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
if (!literal) {
switch (c) {
- case 0x5D /*']'*/:
+ case u']':
if (lastItem == 1) {
add(lastChar, lastChar);
_appendToPat(patLocal, lastChar, FALSE);
}
// Treat final trailing '-' as a literal
- if (op == HYPHEN /*'-'*/) {
+ if (op == u'-') {
add(op, op);
patLocal.append(op);
- } else if (op == INTERSECTION /*'&'*/) {
+ } else if (op == u'&') {
// syntaxError(chars, "Trailing '&'");
ec = U_MALFORMED_SET;
return;
}
- patLocal.append((UChar) 0x5D /*']'*/);
+ patLocal.append(u']');
mode = 2;
continue;
- case HYPHEN /*'-'*/:
+ case u'-':
if (op == 0) {
if (lastItem != 0) {
op = (UChar) c;
@@ -510,8 +478,8 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
add(c, c);
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x5D /*']'*/ && !literal) {
- patLocal.append(HYPHEN_RIGHT_BRACE, 2);
+ if (c == u']' && !literal) {
+ patLocal.append(u"-]", 2);
mode = 2;
continue;
}
@@ -520,7 +488,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// syntaxError(chars, "'-' not after char or set");
ec = U_MALFORMED_SET;
return;
- case INTERSECTION /*'&'*/:
+ case u'&':
if (lastItem == 2 && op == 0) {
op = (UChar) c;
continue;
@@ -528,11 +496,11 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// syntaxError(chars, "'&' not after set");
ec = U_MALFORMED_SET;
return;
- case 0x5E /*'^'*/:
+ case u'^':
// syntaxError(chars, "'^' not after '['");
ec = U_MALFORMED_SET;
return;
- case 0x7B /*'{'*/:
+ case u'{':
if (op != 0) {
// syntaxError(chars, "Missing operand after operator");
ec = U_MALFORMED_SET;
@@ -549,13 +517,13 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
while (!chars.atEnd()) {
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x7D /*'}'*/ && !literal) {
+ if (c == u'}' && !literal) {
ok = TRUE;
break;
}
buf.append(c);
}
- if (buf.length() < 1 || !ok) {
+ if (!ok) {
// syntaxError(chars, "Invalid multicharacter string");
ec = U_MALFORMED_SET;
return;
@@ -565,9 +533,9 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// we don't need to drop through to the further
// processing
add(buf);
- patLocal.append((UChar) 0x7B /*'{'*/);
+ patLocal.append(u'{');
_appendToPat(patLocal, buf, FALSE);
- patLocal.append((UChar) 0x7D /*'}'*/);
+ patLocal.append(u'}');
continue;
case SymbolTable::SYMBOL_REF:
// symbols nosymbols
@@ -580,7 +548,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
chars.getPos(backup);
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- UBool anchor = (c == 0x5D /*']'*/ && !literal);
+ UBool anchor = (c == u']' && !literal);
if (symbols == 0 && !anchor) {
c = SymbolTable::SYMBOL_REF;
chars.setPos(backup);
@@ -594,7 +562,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
add(U_ETHER);
usePat = TRUE;
patLocal.append((UChar) SymbolTable::SYMBOL_REF);
- patLocal.append((UChar) 0x5D /*']'*/);
+ patLocal.append(u']');
mode = 2;
continue;
}
@@ -617,7 +585,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
lastChar = c;
break;
case 1:
- if (op == HYPHEN /*'-'*/) {
+ if (op == u'-') {
if (lastChar >= c) {
// Don't allow redundant (a-a) or empty (b-a) ranges;
// these are most likely typos.
@@ -1036,11 +1004,11 @@ UBool UnicodeSet::resemblesPropertyPattern(RuleCharacterIterator& chars,
RuleCharacterIterator::Pos pos;
chars.getPos(pos);
UChar32 c = chars.next(iterOpts, literal, ec);
- if (c == 0x5B /*'['*/ || c == 0x5C /*'\\'*/) {
+ if (c == u'[' || c == u'\\') {
UChar32 d = chars.next(iterOpts & ~RuleCharacterIterator::SKIP_WHITESPACE,
literal, ec);
- result = (c == 0x5B /*'['*/) ? (d == 0x3A /*':'*/) :
- (d == 0x4E /*'N'*/ || d == 0x70 /*'p'*/ || d == 0x50 /*'P'*/);
+ result = (c == u'[') ? (d == u':') :
+ (d == u'N' || d == u'p' || d == u'P');
}
chars.setPos(pos);
return result && U_SUCCESS(ec);
@@ -1071,17 +1039,17 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
posix = TRUE;
pos += 2;
pos = ICU_Utility::skipWhitespace(pattern, pos);
- if (pos < pattern.length() && pattern.charAt(pos) == COMPLEMENT) {
+ if (pos < pattern.length() && pattern.charAt(pos) == u'^') {
++pos;
invert = TRUE;
}
} else if (isPerlOpen(pattern, pos) || isNameOpen(pattern, pos)) {
UChar c = pattern.charAt(pos+1);
- invert = (c == UPPER_P);
- isName = (c == UPPER_N);
+ invert = (c == u'P');
+ isName = (c == u'N');
pos += 2;
pos = ICU_Utility::skipWhitespace(pattern, pos);
- if (pos == pattern.length() || pattern.charAt(pos++) != OPEN_BRACE) {
+ if (pos == pattern.length() || pattern.charAt(pos++) != u'{') {
// Syntax error; "\p" or "\P" not followed by "{"
FAIL(ec);
}
@@ -1093,9 +1061,9 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
// Look for the matching close delimiter, either :] or }
int32_t close;
if (posix) {
- close = pattern.indexOf(POSIX_CLOSE, 2, pos);
+ close = pattern.indexOf(u":]", 2, pos);
} else {
- close = pattern.indexOf(CLOSE_BRACE, pos);
+ close = pattern.indexOf(u'}', pos);
}
if (close < 0) {
// Syntax error; close delimiter missing
@@ -1105,7 +1073,7 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
// Look for an '=' sign. If this is present, we will parse a
// medium \p{gc=Cf} or long \p{GeneralCategory=Format}
// pattern.
- int32_t equals = pattern.indexOf(EQUALS, pos);
+ int32_t equals = pattern.indexOf(u'=', pos);
UnicodeString propName, valueName;
if (equals >= 0 && equals < close && !isName) {
// Equals seen; parse medium/long pattern
diff --git a/thirdparty/icu4c/common/unisetspan.cpp b/thirdparty/icu4c/common/unisetspan.cpp
index 68e44d91ee..fe0d74f5b2 100644
--- a/thirdparty/icu4c/common/unisetspan.cpp
+++ b/thirdparty/icu4c/common/unisetspan.cpp
@@ -231,6 +231,9 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ if (length16==0) {
+ continue; // skip the empty string
+ }
UBool thisRelevant;
spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED);
if(spanLength<length16) { // Relevant string.
@@ -312,7 +315,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED);
- if(spanLength<length16) { // Relevant string.
+ if(spanLength<length16 && length16>0) { // Relevant string.
if(which&UTF16) {
if(which&CONTAINED) {
if(which&FWD) {
@@ -362,7 +365,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
addToSpanNotSet(c);
}
}
- } else { // Irrelevant string.
+ } else { // Irrelevant string. (Also the empty string.)
if(which&UTF8) {
if(which&CONTAINED) { // Only necessary for LONGEST_MATCH.
uint8_t *s8=utf8+utf8Count;
@@ -653,11 +656,12 @@ int32_t UnicodeSetStringSpan::span(const UChar *s, int32_t length, USetSpanCondi
for(i=0; i<stringsLength; ++i) {
int32_t overlap=spanLengths[i];
if(overlap==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
// Try to match this string at pos-overlap..pos.
if(overlap>=LONG_SPAN) {
@@ -697,6 +701,9 @@ int32_t UnicodeSetStringSpan::span(const UChar *s, int32_t length, USetSpanCondi
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ if (length16==0) {
+ continue; // skip the empty string
+ }
// Try to match this string at pos-overlap..pos.
if(overlap>=LONG_SPAN) {
@@ -817,11 +824,12 @@ int32_t UnicodeSetStringSpan::spanBack(const UChar *s, int32_t length, USetSpanC
for(i=0; i<stringsLength; ++i) {
int32_t overlap=spanBackLengths[i];
if(overlap==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
// Try to match this string at pos-(length16-overlap)..pos-length16.
if(overlap>=LONG_SPAN) {
@@ -863,6 +871,9 @@ int32_t UnicodeSetStringSpan::spanBack(const UChar *s, int32_t length, USetSpanC
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ if (length16==0) {
+ continue; // skip the empty string
+ }
// Try to match this string at pos-(length16-overlap)..pos-length16.
if(overlap>=LONG_SPAN) {
@@ -1358,11 +1369,12 @@ int32_t UnicodeSetStringSpan::spanNot(const UChar *s, int32_t length) const {
// Try to match the strings at pos.
for(i=0; i<stringsLength; ++i) {
if(spanLengths[i]==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
if(length16<=rest && matches16CPB(s, pos, length, s16, length16)) {
return pos; // There is a set element at pos.
}
@@ -1401,11 +1413,12 @@ int32_t UnicodeSetStringSpan::spanNotBack(const UChar *s, int32_t length) const
// it is easier and we only need to know whether the string is irrelevant
// which is the same in either array.
if(spanLengths[i]==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
if(length16<=pos && matches16CPB(s, pos-length16, length, s16, length16)) {
return pos; // There is a set element at pos.
}
diff --git a/thirdparty/icu4c/common/uprops.h b/thirdparty/icu4c/common/uprops.h
index 8bf929919f..09830bdeb9 100644
--- a/thirdparty/icu4c/common/uprops.h
+++ b/thirdparty/icu4c/common/uprops.h
@@ -310,55 +310,12 @@ u_isgraphPOSIX(UChar32 c);
U_CFUNC UBool
u_isprintPOSIX(UChar32 c);
-/** Turn a bit index into a bit flag. @internal */
-#define FLAG(n) ((uint32_t)1<<(n))
-
-/** Flags for general categories in the order of UCharCategory. @internal */
-#define _Cn FLAG(U_GENERAL_OTHER_TYPES)
-#define _Lu FLAG(U_UPPERCASE_LETTER)
-#define _Ll FLAG(U_LOWERCASE_LETTER)
-#define _Lt FLAG(U_TITLECASE_LETTER)
-#define _Lm FLAG(U_MODIFIER_LETTER)
-/* #define _Lo FLAG(U_OTHER_LETTER) -- conflicts with MS Visual Studio 9.0 xiosbase */
-#define _Mn FLAG(U_NON_SPACING_MARK)
-#define _Me FLAG(U_ENCLOSING_MARK)
-#define _Mc FLAG(U_COMBINING_SPACING_MARK)
-#define _Nd FLAG(U_DECIMAL_DIGIT_NUMBER)
-#define _Nl FLAG(U_LETTER_NUMBER)
-#define _No FLAG(U_OTHER_NUMBER)
-#define _Zs FLAG(U_SPACE_SEPARATOR)
-#define _Zl FLAG(U_LINE_SEPARATOR)
-#define _Zp FLAG(U_PARAGRAPH_SEPARATOR)
-#define _Cc FLAG(U_CONTROL_CHAR)
-#define _Cf FLAG(U_FORMAT_CHAR)
-#define _Co FLAG(U_PRIVATE_USE_CHAR)
-#define _Cs FLAG(U_SURROGATE)
-#define _Pd FLAG(U_DASH_PUNCTUATION)
-#define _Ps FLAG(U_START_PUNCTUATION)
-/* #define _Pe FLAG(U_END_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 xlocnum */
-/* #define _Pc FLAG(U_CONNECTOR_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 streambuf */
-#define _Po FLAG(U_OTHER_PUNCTUATION)
-#define _Sm FLAG(U_MATH_SYMBOL)
-#define _Sc FLAG(U_CURRENCY_SYMBOL)
-#define _Sk FLAG(U_MODIFIER_SYMBOL)
-#define _So FLAG(U_OTHER_SYMBOL)
-#define _Pi FLAG(U_INITIAL_PUNCTUATION)
-/* #define _Pf FLAG(U_FINAL_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 streambuf */
-
/** Some code points. @internal */
enum {
TAB =0x0009,
LF =0x000a,
FF =0x000c,
CR =0x000d,
- U_A =0x0041,
- U_F =0x0046,
- U_Z =0x005a,
- U_a =0x0061,
- U_f =0x0066,
- U_z =0x007a,
- DEL =0x007f,
- NL =0x0085,
NBSP =0x00a0,
CGJ =0x034f,
FIGURESP=0x2007,
@@ -367,15 +324,6 @@ enum {
ZWJ =0x200d,
RLM =0x200f,
NNBSP =0x202f,
- WJ =0x2060,
- INHSWAP =0x206a,
- NOMDIG =0x206f,
- U_FW_A =0xff21,
- U_FW_F =0xff26,
- U_FW_Z =0xff3a,
- U_FW_a =0xff41,
- U_FW_f =0xff46,
- U_FW_z =0xff5a,
ZWNBSP =0xfeff
};
diff --git a/thirdparty/icu4c/common/uresbund.cpp b/thirdparty/icu4c/common/uresbund.cpp
index 2ece87897d..5ea4187100 100644
--- a/thirdparty/icu4c/common/uresbund.cpp
+++ b/thirdparty/icu4c/common/uresbund.cpp
@@ -92,6 +92,15 @@ static UBool chopLocale(char *name) {
}
/**
+ * Called to check whether a name without '_' needs to be checked for a parent.
+ * Some code had assumed that locale IDs with '_' could not have a non-root parent.
+ * We may want a better way of doing this.
+ */
+static UBool mayHaveParent(char *name) {
+ return (name[0] != 0 && uprv_strstr("nb nn",name) != nullptr);
+}
+
+/**
* Internal function
*/
static void entryIncrease(UResourceDataEntry *entry) {
@@ -529,8 +538,8 @@ loadParentsExceptRoot(UResourceDataEntry *&t1,
char name[], int32_t nameCapacity,
UBool usingUSRData, char usrDataPath[], UErrorCode *status) {
if (U_FAILURE(*status)) { return FALSE; }
- UBool hasChopped = TRUE;
- while (hasChopped && t1->fParent == NULL && !t1->fData.noFallback &&
+ UBool checkParent = TRUE;
+ while (checkParent && t1->fParent == NULL && !t1->fData.noFallback &&
res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
Resource parentRes = res_getResource(&t1->fData, "%%Parent");
if (parentRes != RES_BOGUS) { // An explicit parent was found.
@@ -573,7 +582,7 @@ loadParentsExceptRoot(UResourceDataEntry *&t1,
}
}
t1 = t2;
- hasChopped = chopLocale(name);
+ checkParent = chopLocale(name) || mayHaveParent(name);
}
return TRUE;
}
@@ -692,7 +701,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
}
}
}
- if (hasChopped && !isRoot) {
+ if ((hasChopped || mayHaveParent(name)) && !isRoot) {
if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
goto finish;
}
@@ -716,7 +725,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
hasRealData = TRUE;
isDefault = TRUE;
// TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path?
- if (hasChopped && !isRoot) {
+ if ((hasChopped || mayHaveParent(name)) && !isRoot) {
if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
goto finish;
}
@@ -1908,6 +1917,8 @@ ures_getByKeyWithFallback(const UResourceBundle *resB,
} else {
break;
}
+ } else if (res == RES_BOGUS) {
+ break;
}
} while(*myPath); /* Continue until the whole path is consumed */
}
@@ -3019,7 +3030,7 @@ ures_getKeywordValues(const char *path, const char *keyword, UErrorCode *status)
U_CAPI UBool U_EXPORT2
ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){
if(res1==NULL || res2==NULL){
- return res1==res2; /* pointer comparision */
+ return res1==res2; /* pointer comparison */
}
if(res1->fKey==NULL|| res2->fKey==NULL){
return (res1->fKey==res2->fKey);
diff --git a/thirdparty/icu4c/common/uresdata.cpp b/thirdparty/icu4c/common/uresdata.cpp
index ae731e4544..9af081be40 100644
--- a/thirdparty/icu4c/common/uresdata.cpp
+++ b/thirdparty/icu4c/common/uresdata.cpp
@@ -960,14 +960,6 @@ res_findResource(const ResourceData *pResData, Resource r, char** path, const ch
if(URES_IS_TABLE(type)) {
*key = pathP;
t2 = res_getTableItemByKey(pResData, t1, &indexR, key);
- if(t2 == RES_BOGUS) {
- /* if we fail to get the resource by key, maybe we got an index */
- indexR = uprv_strtol(pathP, &closeIndex, 10);
- if(indexR >= 0 && *closeIndex == 0 && (*pathP != '0' || closeIndex - pathP == 1)) {
- /* if we indeed have an index, try to get the item by index */
- t2 = res_getTableItemByIndex(pResData, t1, indexR, key);
- } // else t2 is already RES_BOGUS
- }
} else if(URES_IS_ARRAY(type)) {
indexR = uprv_strtol(pathP, &closeIndex, 10);
if(indexR >= 0 && *closeIndex == 0) {
diff --git a/thirdparty/icu4c/common/uresimp.h b/thirdparty/icu4c/common/uresimp.h
index 69d82566fe..f038dedace 100644
--- a/thirdparty/icu4c/common/uresimp.h
+++ b/thirdparty/icu4c/common/uresimp.h
@@ -270,11 +270,13 @@ ures_getByKeyWithFallback(const UResourceBundle *resB,
* function can perform fallback on the sub-resources of the table.
* @param resB a resource
* @param inKey a key associated with the requested resource
+ * @param len if not NULL, used to return the length of the string
* @param status: fills in the outgoing error code
* could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
* could be a non-failing error
* e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
- * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it
+ * @return returns a pointer to a zero-terminated UChar array which lives in a
+ * memory mapped/DLL file.
*/
U_CAPI const UChar* U_EXPORT2
ures_getStringByKeyWithFallback(const UResourceBundle *resB,
diff --git a/thirdparty/icu4c/common/uset.cpp b/thirdparty/icu4c/common/uset.cpp
index eae7981d52..a7e3046dbf 100644
--- a/thirdparty/icu4c/common/uset.cpp
+++ b/thirdparty/icu4c/common/uset.cpp
@@ -117,6 +117,12 @@ uset_removeString(USet* set, const UChar* str, int32_t strLen) {
}
U_CAPI void U_EXPORT2
+uset_removeAllCodePoints(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::removeAll(s);
+}
+
+U_CAPI void U_EXPORT2
uset_removeAll(USet* set, const USet* remove) {
((UnicodeSet*) set)->UnicodeSet::removeAll(*(const UnicodeSet*)remove);
}
@@ -127,6 +133,18 @@ uset_retain(USet* set, UChar32 start, UChar32 end) {
}
U_CAPI void U_EXPORT2
+uset_retainString(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::retain(s);
+}
+
+U_CAPI void U_EXPORT2
+uset_retainAllCodePoints(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::retainAll(s);
+}
+
+U_CAPI void U_EXPORT2
uset_retainAll(USet* set, const USet* retain) {
((UnicodeSet*) set)->UnicodeSet::retainAll(*(const UnicodeSet*)retain);
}
@@ -142,6 +160,23 @@ uset_complement(USet* set) {
}
U_CAPI void U_EXPORT2
+uset_complementRange(USet *set, UChar32 start, UChar32 end) {
+ ((UnicodeSet*) set)->UnicodeSet::complement(start, end);
+}
+
+U_CAPI void U_EXPORT2
+uset_complementString(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::complement(s);
+}
+
+U_CAPI void U_EXPORT2
+uset_complementAllCodePoints(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::complementAll(s);
+}
+
+U_CAPI void U_EXPORT2
uset_complementAll(USet* set, const USet* complement) {
((UnicodeSet*) set)->UnicodeSet::complementAll(*(const UnicodeSet*)complement);
}
diff --git a/thirdparty/icu4c/common/usprep.cpp b/thirdparty/icu4c/common/usprep.cpp
index 8351a77370..874ffc63a8 100644
--- a/thirdparty/icu4c/common/usprep.cpp
+++ b/thirdparty/icu4c/common/usprep.cpp
@@ -575,7 +575,7 @@ usprep_map( const UStringPrepProfile* profile,
}
}else if(type==USPREP_DELETE){
- // just consume the codepoint and contine
+ // just consume the codepoint and continue
continue;
}
//copy the code point into destination
diff --git a/thirdparty/icu4c/common/ustr_wcs.cpp b/thirdparty/icu4c/common/ustr_wcs.cpp
index e9f278e969..89d0762480 100644
--- a/thirdparty/icu4c/common/ustr_wcs.cpp
+++ b/thirdparty/icu4c/common/ustr_wcs.cpp
@@ -364,7 +364,7 @@ _strFromWCS( UChar *dest,
}
/* we have found a null so convert the
- * chunk from begining of non-null char to null
+ * chunk from beginning of non-null char to null
*/
retVal = uprv_wcstombs(pCSrc,pSrc,remaining);
@@ -387,7 +387,7 @@ _strFromWCS( UChar *dest,
* null terminate it and convert wchar_ts to chars
*/
if(nulLen >= _STACK_BUFFER_CAPACITY){
- /* Should rarely occcur */
+ /* Should rarely occur */
/* allocate new buffer buffer */
pWStack =(wchar_t*) uprv_malloc(sizeof(wchar_t) * (nulLen + 1));
if(pWStack==NULL){
diff --git a/thirdparty/icu4c/common/utext.cpp b/thirdparty/icu4c/common/utext.cpp
index 763b6684fb..d79f8141bb 100644
--- a/thirdparty/icu4c/common/utext.cpp
+++ b/thirdparty/icu4c/common/utext.cpp
@@ -382,7 +382,7 @@ utext_previous32From(UText *ut, int64_t index) {
//
UChar32 cPrev; // The character preceding cCurr, which is what we will return.
- // Address the chunk containg the position preceding the incoming index
+ // Address the chunk containing the position preceding the incoming index
// A tricky edge case:
// We try to test the requested native index against the chunkNativeStart to determine
// whether the character preceding the one at the index is in the current chunk.
@@ -894,7 +894,7 @@ struct UTF8Buf {
// one for a supplementary starting in the last normal position,
// and one for an entry for the buffer limit position.
uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*3+6]; // Map native offset from bufNativeStart to
- // correspoding offset in filled part of buf.
+ // corresponding offset in filled part of buf.
int32_t align;
};
@@ -1545,7 +1545,7 @@ utf8TextMapOffsetToNative(const UText *ut) {
}
//
-// Map a native index to the corrsponding chunk offset
+// Map a native index to the corresponding chunk offset
//
static int32_t U_CALLCONV
utf8TextMapIndexToUTF16(const UText *ut, int64_t index64) {
diff --git a/thirdparty/icu4c/common/util.h b/thirdparty/icu4c/common/util.h
index 9c3b76d9ed..b5fac383a2 100644
--- a/thirdparty/icu4c/common/util.h
+++ b/thirdparty/icu4c/common/util.h
@@ -13,10 +13,10 @@
#ifndef ICU_UTIL_H
#define ICU_UTIL_H
-#include "unicode/utypes.h"
-#include "unicode/uobject.h"
+#include "charstr.h"
#include "unicode/unistr.h"
-
+#include "unicode/uobject.h"
+#include "unicode/utypes.h"
//--------------------------------------------------------------------
// class ICU_Utility
// i18n utility functions, scoped into the class ICU_Utility.
diff --git a/thirdparty/icu4c/common/utracimp.h b/thirdparty/icu4c/common/utracimp.h
index f32fe1db39..945540d25a 100644
--- a/thirdparty/icu4c/common/utracimp.h
+++ b/thirdparty/icu4c/common/utracimp.h
@@ -193,7 +193,7 @@ UPRV_BLOCK_MACRO_BEGIN { \
* Trace statement for each exit point of a function that has a UTRACE_ENTRY()
* statement, and that returns a value.
*
- * @param val The function's return value, int32_t or comatible type.
+ * @param val The function's return value, int32_t or compatible type.
*
* @internal
*/
diff --git a/thirdparty/icu4c/common/uvector.cpp b/thirdparty/icu4c/common/uvector.cpp
index cf19edf646..9c7e74c6d5 100644
--- a/thirdparty/icu4c/common/uvector.cpp
+++ b/thirdparty/icu4c/common/uvector.cpp
@@ -312,7 +312,7 @@ int32_t UVector::indexOf(UElement key, int32_t startIndex, int8_t hint) const {
} else {
for (i=startIndex; i<count; ++i) {
/* Pointers are not always the same size as ints so to perform
- * a valid comparision we need to know whether we are being
+ * a valid comparison we need to know whether we are being
* provided an int or a pointer. */
if (hint & HINT_KEY_POINTER) {
if (key.pointer == elements[i].pointer) {
@@ -518,7 +518,7 @@ sortiComparator(const void * /*context */, const void *left, const void *right)
}
/**
- * Sort the vector, assuming it constains ints.
+ * Sort the vector, assuming it contains ints.
* (A more general sort would take a comparison function, but it's
* not clear whether UVector's UElementComparator or
* UComparator from uprv_sortAray would be more appropriate.)
diff --git a/thirdparty/icu4c/common/wintz.cpp b/thirdparty/icu4c/common/wintz.cpp
index 580cedadb6..ebf31650c2 100644
--- a/thirdparty/icu4c/common/wintz.cpp
+++ b/thirdparty/icu4c/common/wintz.cpp
@@ -124,10 +124,26 @@ uprv_detectWindowsTimeZone()
// No way to support when DST is turned off and the offset in minutes is not a multiple of 60.
if (utcOffsetMins % 60 == 0) {
char gmtOffsetTz[11] = {}; // "Etc/GMT+dd" is 11-char long with a terminal null.
- // Note '-' before 'utcOffsetMin'. The timezone ID's sign convention
- // is that a timezone ahead of UTC is Etc/GMT-<offset> and a timezone
- // behind UTC is Etc/GMT+<offset>.
- int ret = snprintf(gmtOffsetTz, UPRV_LENGTHOF(gmtOffsetTz), "Etc/GMT%+ld", -utcOffsetMins / 60);
+ // Important note on the sign convention for zones:
+ //
+ // From https://en.wikipedia.org/wiki/Tz_database#Area
+ // "In order to conform with the POSIX style, those zone names beginning with "Etc/GMT" have their sign reversed
+ // from the standard ISO 8601 convention. In the "Etc" area, zones west of GMT have a positive sign and those
+ // east have a negative sign in their name (e.g "Etc/GMT-14" is 14 hours ahead of GMT)."
+ //
+ // Regarding the POSIX style, from https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
+ // "The offset specifies the time value you must add to the local time to get a Coordinated Universal Time value."
+ //
+ // However, the Bias value in DYNAMIC_TIME_ZONE_INFORMATION *already* follows the POSIX convention.
+ //
+ // From https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-dynamic_time_zone_information
+ // "The bias is the difference, in minutes, between Coordinated Universal Time (UTC) and
+ // local time. All translations between UTC and local time are based on the following formula:
+ // UTC = local time + bias"
+ //
+ // For example, a time zone that is 3 hours ahead of UTC (UTC+03:00) would have a Bias value of -180, and the
+ // corresponding time zone ID would be "Etc/GMT-3". (So there is no need to negate utcOffsetMins below.)
+ int ret = snprintf(gmtOffsetTz, UPRV_LENGTHOF(gmtOffsetTz), "Etc/GMT%+ld", utcOffsetMins / 60);
if (ret > 0 && ret < UPRV_LENGTHOF(gmtOffsetTz)) {
return uprv_strdup(gmtOffsetTz);
}
diff --git a/thirdparty/icu4c/icudt68l.dat b/thirdparty/icu4c/icudt69l.dat
index 9ecea5d548..3101a49695 100644
--- a/thirdparty/icu4c/icudt68l.dat
+++ b/thirdparty/icu4c/icudt69l.dat
Binary files differ
diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
index fe8d349731..e44b99ce52 100644
--- a/thirdparty/meshoptimizer/meshoptimizer.h
+++ b/thirdparty/meshoptimizer/meshoptimizer.h
@@ -299,6 +299,11 @@ MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t ver
MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* result_error);
/**
+ * Experimental: Mesh simplifier with attribute metric; attributes follow xyz position data atm (vertex data must contain 3 + attribute_count floats per vertex)
+ */
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float* result_error, const float* attributes, const float* attribute_weights, size_t attribute_count);
+
+/**
* Experimental: Mesh simplifier (sloppy)
* Reduces the number of triangles in the mesh, sacrificing mesh apperance for simplification performance
* The algorithm doesn't preserve mesh topology but can stop short of the target goal based on target error.
diff --git a/thirdparty/meshoptimizer/patches/attribute-aware-simplify.patch b/thirdparty/meshoptimizer/patches/attribute-aware-simplify.patch
new file mode 100644
index 0000000000..cf648b0da3
--- /dev/null
+++ b/thirdparty/meshoptimizer/patches/attribute-aware-simplify.patch
@@ -0,0 +1,262 @@
+diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
+index fe8d349731..e44b99ce52 100644
+--- a/thirdparty/meshoptimizer/meshoptimizer.h
++++ b/thirdparty/meshoptimizer/meshoptimizer.h
+@@ -298,6 +298,11 @@ MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t ver
+ */
+ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* result_error);
+
++/**
++ * Experimental: Mesh simplifier with attribute metric; attributes follow xyz position data atm (vertex data must contain 3 + attribute_count floats per vertex)
++ */
++MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float* result_error, const float* attributes, const float* attribute_weights, size_t attribute_count);
++
+ /**
+ * Experimental: Mesh simplifier (sloppy)
+ * Reduces the number of triangles in the mesh, sacrificing mesh apperance for simplification performance
+diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
+index b2cb589462..059cabb055 100644
+--- a/thirdparty/meshoptimizer/simplifier.cpp
++++ b/thirdparty/meshoptimizer/simplifier.cpp
+@@ -20,6 +20,8 @@
+ #define TRACESTATS(i) (void)0
+ #endif
+
++#define ATTRIBUTES 8
++
+ // This work is based on:
+ // Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
+ // Michael Garland. Quadric-based polygonal surface simplification. 1999
+@@ -358,6 +360,10 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned
+ struct Vector3
+ {
+ float x, y, z;
++
++#if ATTRIBUTES
++ float a[ATTRIBUTES];
++#endif
+ };
+
+ static float rescalePositions(Vector3* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride)
+@@ -414,6 +420,13 @@ struct Quadric
+ float a10, a20, a21;
+ float b0, b1, b2, c;
+ float w;
++
++#if ATTRIBUTES
++ float gx[ATTRIBUTES];
++ float gy[ATTRIBUTES];
++ float gz[ATTRIBUTES];
++ float gw[ATTRIBUTES];
++#endif
+ };
+
+ struct Collapse
+@@ -456,6 +469,16 @@ static void quadricAdd(Quadric& Q, const Quadric& R)
+ Q.b2 += R.b2;
+ Q.c += R.c;
+ Q.w += R.w;
++
++#if ATTRIBUTES
++ for (int k = 0; k < ATTRIBUTES; ++k)
++ {
++ Q.gx[k] += R.gx[k];
++ Q.gy[k] += R.gy[k];
++ Q.gz[k] += R.gz[k];
++ Q.gw[k] += R.gw[k];
++ }
++#endif
+ }
+
+ static float quadricError(const Quadric& Q, const Vector3& v)
+@@ -481,6 +504,17 @@ static float quadricError(const Quadric& Q, const Vector3& v)
+ r += ry * v.y;
+ r += rz * v.z;
+
++#if ATTRIBUTES
++ // see quadricUpdateAttributes for general derivation; here we need to add the parts of (eval(pos) - attr)^2 that depend on attr
++ for (int k = 0; k < ATTRIBUTES; ++k)
++ {
++ float a = v.a[k];
++
++ r += a * a * Q.w;
++ r -= 2 * a * (v.x * Q.gx[k] + v.y * Q.gy[k] + v.z * Q.gz[k] + Q.gw[k]);
++ }
++#endif
++
+ float s = Q.w == 0.f ? 0.f : 1.f / Q.w;
+
+ return fabsf(r) * s;
+@@ -504,6 +538,13 @@ static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, flo
+ Q.b2 = c * dw;
+ Q.c = d * dw;
+ Q.w = w;
++
++#if ATTRIBUTES
++ memset(Q.gx, 0, sizeof(Q.gx));
++ memset(Q.gy, 0, sizeof(Q.gy));
++ memset(Q.gz, 0, sizeof(Q.gz));
++ memset(Q.gw, 0, sizeof(Q.gw));
++#endif
+ }
+
+ static void quadricFromPoint(Quadric& Q, float x, float y, float z, float w)
+@@ -556,6 +597,84 @@ static void quadricFromTriangleEdge(Quadric& Q, const Vector3& p0, const Vector3
+ quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, length * weight);
+ }
+
++#if ATTRIBUTES
++static void quadricUpdateAttributes(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float w)
++{
++ // for each attribute we want to encode the following function into the quadric:
++ // (eval(pos) - attr)^2
++ // where eval(pos) interpolates attribute across the triangle like so:
++ // eval(pos) = pos.x * gx + pos.y * gy + pos.z * gz + gw
++ // where gx/gy/gz/gw are gradients
++ Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
++ Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
++
++ // we compute gradients using barycentric coordinates; barycentric coordinates can be computed as follows:
++ // v = (d11 * d20 - d01 * d21) / denom
++ // w = (d00 * d21 - d01 * d20) / denom
++ // u = 1 - v - w
++ // here v0, v1 are triangle edge vectors, v2 is a vector from point to triangle corner, and dij = dot(vi, vj)
++ const Vector3& v0 = p10;
++ const Vector3& v1 = p20;
++ float d00 = v0.x * v0.x + v0.y * v0.y + v0.z * v0.z;
++ float d01 = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;
++ float d11 = v1.x * v1.x + v1.y * v1.y + v1.z * v1.z;
++ float denom = d00 * d11 - d01 * d01;
++ float denomr = denom == 0 ? 0.f : 1.f / denom;
++
++ // precompute gradient factors
++ // these are derived by directly computing derivative of eval(pos) = a0 * u + a1 * v + a2 * w and factoring out common factors that are shared between attributes
++ float gx1 = (d11 * v0.x - d01 * v1.x) * denomr;
++ float gx2 = (d00 * v1.x - d01 * v0.x) * denomr;
++ float gy1 = (d11 * v0.y - d01 * v1.y) * denomr;
++ float gy2 = (d00 * v1.y - d01 * v0.y) * denomr;
++ float gz1 = (d11 * v0.z - d01 * v1.z) * denomr;
++ float gz2 = (d00 * v1.z - d01 * v0.z) * denomr;
++
++ for (int k = 0; k < ATTRIBUTES; ++k)
++ {
++ float a0 = p0.a[k], a1 = p1.a[k], a2 = p2.a[k];
++
++ // compute gradient of eval(pos) for x/y/z/w
++ // the formulas below are obtained by directly computing derivative of eval(pos) = a0 * u + a1 * v + a2 * w
++ float gx = gx1 * (a1 - a0) + gx2 * (a2 - a0);
++ float gy = gy1 * (a1 - a0) + gy2 * (a2 - a0);
++ float gz = gz1 * (a1 - a0) + gz2 * (a2 - a0);
++ float gw = a0 - p0.x * gx - p0.y * gy - p0.z * gz;
++
++ // quadric encodes (eval(pos)-attr)^2; this means that the resulting expansion needs to compute, for example, pos.x * pos.y * K
++ // since quadrics already encode factors for pos.x * pos.y, we can accumulate almost everything in basic quadric fields
++ Q.a00 += w * (gx * gx);
++ Q.a11 += w * (gy * gy);
++ Q.a22 += w * (gz * gz);
++
++ Q.a10 += w * (gy * gx);
++ Q.a20 += w * (gz * gx);
++ Q.a21 += w * (gz * gy);
++
++ Q.b0 += w * (gx * gw);
++ Q.b1 += w * (gy * gw);
++ Q.b2 += w * (gz * gw);
++
++ Q.c += w * (gw * gw);
++
++ // the only remaining sum components are ones that depend on attr; these will be addded during error evaluation, see quadricError
++ Q.gx[k] = w * gx;
++ Q.gy[k] = w * gy;
++ Q.gz[k] = w * gz;
++ Q.gw[k] = w * gw;
++
++#if TRACE > 2
++ printf("attr%d: %e %e %e\n",
++ k,
++ (gx * p0.x + gy * p0.y + gz * p0.z + gw - a0),
++ (gx * p1.x + gy * p1.y + gz * p1.z + gw - a1),
++ (gx * p2.x + gy * p2.y + gz * p2.z + gw - a2)
++ );
++#endif
++ }
++}
++#endif
++
+ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap)
+ {
+ for (size_t i = 0; i < index_count; i += 3)
+@@ -567,6 +686,9 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
+ Quadric Q;
+ quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
+
++#if ATTRIBUTES
++ quadricUpdateAttributes(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], Q.w);
++#endif
+ quadricAdd(vertex_quadrics[remap[i0]], Q);
+ quadricAdd(vertex_quadrics[remap[i1]], Q);
+ quadricAdd(vertex_quadrics[remap[i2]], Q);
+@@ -1259,13 +1381,19 @@ unsigned int* meshopt_simplifyDebugLoopBack = 0;
+ #endif
+
+ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* out_result_error)
++{
++ return meshopt_simplifyWithAttributes(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, target_index_count, target_error, out_result_error, 0, 0, 0);
++}
++
++size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float* out_result_error, const float* attributes, const float* attribute_weights, size_t attribute_count)
+ {
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+- assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+- assert(vertex_positions_stride % sizeof(float) == 0);
++ assert(vertex_stride > 0 && vertex_stride <= 256);
++ assert(vertex_stride % sizeof(float) == 0);
+ assert(target_index_count <= index_count);
++ assert(attribute_count <= ATTRIBUTES);
+
+ meshopt_Allocator allocator;
+
+@@ -1279,7 +1407,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
+ // build position remap that maps each vertex to the one with identical position
+ unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
+ unsigned int* wedge = allocator.allocate<unsigned int>(vertex_count);
+- buildPositionRemap(remap, wedge, vertex_positions_data, vertex_count, vertex_positions_stride, allocator);
++ buildPositionRemap(remap, wedge, vertex_data, vertex_count, vertex_stride, allocator);
+
+ // classify vertices; vertex kind determines collapse rules, see kCanCollapse
+ unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
+@@ -1303,7 +1431,21 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
+ #endif
+
+ Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
+- rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride);
++ rescalePositions(vertex_positions, vertex_data, vertex_count, vertex_stride);
++
++#if ATTRIBUTES
++ for (size_t i = 0; i < vertex_count; ++i)
++ {
++ memset(vertex_positions[i].a, 0, sizeof(vertex_positions[i].a));
++
++ for (size_t k = 0; k < attribute_count; ++k)
++ {
++ float a = attributes[i * attribute_count + k];
++
++ vertex_positions[i].a[k] = a * attribute_weights[k];
++ }
++ }
++#endif
+
+ Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
+ memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
+@@ -1395,7 +1537,9 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
+
+ // result_error is quadratic; we need to remap it back to linear
+ if (out_result_error)
++ {
+ *out_result_error = sqrtf(result_error);
++ }
+
+ return result_count;
+ }
diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
index b2cb589462..0f10ebef4b 100644
--- a/thirdparty/meshoptimizer/simplifier.cpp
+++ b/thirdparty/meshoptimizer/simplifier.cpp
@@ -20,6 +20,8 @@
#define TRACESTATS(i) (void)0
#endif
+#define ATTRIBUTES 8
+
// This work is based on:
// Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
// Michael Garland. Quadric-based polygonal surface simplification. 1999
@@ -118,8 +120,13 @@ struct PositionHasher
{
const unsigned int* key = reinterpret_cast<const unsigned int*>(vertex_positions + index * vertex_stride_float);
+ // scramble bits to make sure that integer coordinates have entropy in lower bits
+ unsigned int x = key[0] ^ (key[0] >> 17);
+ unsigned int y = key[1] ^ (key[1] >> 17);
+ unsigned int z = key[2] ^ (key[2] >> 17);
+
// Optimized Spatial Hashing for Collision Detection of Deformable Objects
- return (key[0] * 73856093) ^ (key[1] * 19349663) ^ (key[2] * 83492791);
+ return (x * 73856093) ^ (y * 19349663) ^ (z * 83492791);
}
bool equal(unsigned int lhs, unsigned int rhs) const
@@ -358,6 +365,10 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned
struct Vector3
{
float x, y, z;
+
+#if ATTRIBUTES
+ float a[ATTRIBUTES];
+#endif
};
static float rescalePositions(Vector3* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride)
@@ -414,6 +425,13 @@ struct Quadric
float a10, a20, a21;
float b0, b1, b2, c;
float w;
+
+#if ATTRIBUTES
+ float gx[ATTRIBUTES];
+ float gy[ATTRIBUTES];
+ float gz[ATTRIBUTES];
+ float gw[ATTRIBUTES];
+#endif
};
struct Collapse
@@ -456,6 +474,16 @@ static void quadricAdd(Quadric& Q, const Quadric& R)
Q.b2 += R.b2;
Q.c += R.c;
Q.w += R.w;
+
+#if ATTRIBUTES
+ for (int k = 0; k < ATTRIBUTES; ++k)
+ {
+ Q.gx[k] += R.gx[k];
+ Q.gy[k] += R.gy[k];
+ Q.gz[k] += R.gz[k];
+ Q.gw[k] += R.gw[k];
+ }
+#endif
}
static float quadricError(const Quadric& Q, const Vector3& v)
@@ -481,6 +509,17 @@ static float quadricError(const Quadric& Q, const Vector3& v)
r += ry * v.y;
r += rz * v.z;
+#if ATTRIBUTES
+ // see quadricUpdateAttributes for general derivation; here we need to add the parts of (eval(pos) - attr)^2 that depend on attr
+ for (int k = 0; k < ATTRIBUTES; ++k)
+ {
+ float a = v.a[k];
+
+ r += a * a * Q.w;
+ r -= 2 * a * (v.x * Q.gx[k] + v.y * Q.gy[k] + v.z * Q.gz[k] + Q.gw[k]);
+ }
+#endif
+
float s = Q.w == 0.f ? 0.f : 1.f / Q.w;
return fabsf(r) * s;
@@ -504,6 +543,13 @@ static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, flo
Q.b2 = c * dw;
Q.c = d * dw;
Q.w = w;
+
+#if ATTRIBUTES
+ memset(Q.gx, 0, sizeof(Q.gx));
+ memset(Q.gy, 0, sizeof(Q.gy));
+ memset(Q.gz, 0, sizeof(Q.gz));
+ memset(Q.gw, 0, sizeof(Q.gw));
+#endif
}
static void quadricFromPoint(Quadric& Q, float x, float y, float z, float w)
@@ -556,6 +602,84 @@ static void quadricFromTriangleEdge(Quadric& Q, const Vector3& p0, const Vector3
quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, length * weight);
}
+#if ATTRIBUTES
+static void quadricUpdateAttributes(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float w)
+{
+ // for each attribute we want to encode the following function into the quadric:
+ // (eval(pos) - attr)^2
+ // where eval(pos) interpolates attribute across the triangle like so:
+ // eval(pos) = pos.x * gx + pos.y * gy + pos.z * gz + gw
+ // where gx/gy/gz/gw are gradients
+ Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
+ Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
+
+ // we compute gradients using barycentric coordinates; barycentric coordinates can be computed as follows:
+ // v = (d11 * d20 - d01 * d21) / denom
+ // w = (d00 * d21 - d01 * d20) / denom
+ // u = 1 - v - w
+ // here v0, v1 are triangle edge vectors, v2 is a vector from point to triangle corner, and dij = dot(vi, vj)
+ const Vector3& v0 = p10;
+ const Vector3& v1 = p20;
+ float d00 = v0.x * v0.x + v0.y * v0.y + v0.z * v0.z;
+ float d01 = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;
+ float d11 = v1.x * v1.x + v1.y * v1.y + v1.z * v1.z;
+ float denom = d00 * d11 - d01 * d01;
+ float denomr = denom == 0 ? 0.f : 1.f / denom;
+
+ // precompute gradient factors
+ // these are derived by directly computing derivative of eval(pos) = a0 * u + a1 * v + a2 * w and factoring out common factors that are shared between attributes
+ float gx1 = (d11 * v0.x - d01 * v1.x) * denomr;
+ float gx2 = (d00 * v1.x - d01 * v0.x) * denomr;
+ float gy1 = (d11 * v0.y - d01 * v1.y) * denomr;
+ float gy2 = (d00 * v1.y - d01 * v0.y) * denomr;
+ float gz1 = (d11 * v0.z - d01 * v1.z) * denomr;
+ float gz2 = (d00 * v1.z - d01 * v0.z) * denomr;
+
+ for (int k = 0; k < ATTRIBUTES; ++k)
+ {
+ float a0 = p0.a[k], a1 = p1.a[k], a2 = p2.a[k];
+
+ // compute gradient of eval(pos) for x/y/z/w
+ // the formulas below are obtained by directly computing derivative of eval(pos) = a0 * u + a1 * v + a2 * w
+ float gx = gx1 * (a1 - a0) + gx2 * (a2 - a0);
+ float gy = gy1 * (a1 - a0) + gy2 * (a2 - a0);
+ float gz = gz1 * (a1 - a0) + gz2 * (a2 - a0);
+ float gw = a0 - p0.x * gx - p0.y * gy - p0.z * gz;
+
+ // quadric encodes (eval(pos)-attr)^2; this means that the resulting expansion needs to compute, for example, pos.x * pos.y * K
+ // since quadrics already encode factors for pos.x * pos.y, we can accumulate almost everything in basic quadric fields
+ Q.a00 += w * (gx * gx);
+ Q.a11 += w * (gy * gy);
+ Q.a22 += w * (gz * gz);
+
+ Q.a10 += w * (gy * gx);
+ Q.a20 += w * (gz * gx);
+ Q.a21 += w * (gz * gy);
+
+ Q.b0 += w * (gx * gw);
+ Q.b1 += w * (gy * gw);
+ Q.b2 += w * (gz * gw);
+
+ Q.c += w * (gw * gw);
+
+ // the only remaining sum components are ones that depend on attr; these will be addded during error evaluation, see quadricError
+ Q.gx[k] = w * gx;
+ Q.gy[k] = w * gy;
+ Q.gz[k] = w * gz;
+ Q.gw[k] = w * gw;
+
+#if TRACE > 2
+ printf("attr%d: %e %e %e\n",
+ k,
+ (gx * p0.x + gy * p0.y + gz * p0.z + gw - a0),
+ (gx * p1.x + gy * p1.y + gz * p1.z + gw - a1),
+ (gx * p2.x + gy * p2.y + gz * p2.z + gw - a2)
+ );
+#endif
+ }
+}
+#endif
+
static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap)
{
for (size_t i = 0; i < index_count; i += 3)
@@ -567,6 +691,9 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
Quadric Q;
quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
+#if ATTRIBUTES
+ quadricUpdateAttributes(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], Q.w);
+#endif
quadricAdd(vertex_quadrics[remap[i0]], Q);
quadricAdd(vertex_quadrics[remap[i1]], Q);
quadricAdd(vertex_quadrics[remap[i2]], Q);
@@ -1038,7 +1165,7 @@ struct IdHasher
struct TriangleHasher
{
- unsigned int* indices;
+ const unsigned int* indices;
size_t hash(unsigned int i) const
{
@@ -1253,19 +1380,26 @@ static float interpolate(float y, float x0, float y0, float x1, float y1, float
} // namespace meshopt
#ifndef NDEBUG
-unsigned char* meshopt_simplifyDebugKind = 0;
-unsigned int* meshopt_simplifyDebugLoop = 0;
-unsigned int* meshopt_simplifyDebugLoopBack = 0;
+// Note: this is only exposed for debug visualization purposes; do *not* use these in debug builds
+MESHOPTIMIZER_API unsigned char* meshopt_simplifyDebugKind = 0;
+MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoop = 0;
+MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoopBack = 0;
#endif
size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float* out_result_error)
{
+ return meshopt_simplifyWithAttributes(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, target_index_count, target_error, out_result_error, 0, 0, 0);
+}
+
+size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float* out_result_error, const float* attributes, const float* attribute_weights, size_t attribute_count)
+{
using namespace meshopt;
assert(index_count % 3 == 0);
- assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
- assert(vertex_positions_stride % sizeof(float) == 0);
+ assert(vertex_stride > 0 && vertex_stride <= 256);
+ assert(vertex_stride % sizeof(float) == 0);
assert(target_index_count <= index_count);
+ assert(attribute_count <= ATTRIBUTES);
meshopt_Allocator allocator;
@@ -1279,7 +1413,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
// build position remap that maps each vertex to the one with identical position
unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
unsigned int* wedge = allocator.allocate<unsigned int>(vertex_count);
- buildPositionRemap(remap, wedge, vertex_positions_data, vertex_count, vertex_positions_stride, allocator);
+ buildPositionRemap(remap, wedge, vertex_data, vertex_count, vertex_stride, allocator);
// classify vertices; vertex kind determines collapse rules, see kCanCollapse
unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
@@ -1303,7 +1437,21 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
#endif
Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
- rescalePositions(vertex_positions, vertex_positions_data, vertex_count, vertex_positions_stride);
+ rescalePositions(vertex_positions, vertex_data, vertex_count, vertex_stride);
+
+#if ATTRIBUTES
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ memset(vertex_positions[i].a, 0, sizeof(vertex_positions[i].a));
+
+ for (size_t k = 0; k < attribute_count; ++k)
+ {
+ float a = attributes[i * attribute_count + k];
+
+ vertex_positions[i].a[k] = a * attribute_weights[k];
+ }
+ }
+#endif
Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
@@ -1395,7 +1543,9 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
// result_error is quadratic; we need to remap it back to linear
if (out_result_error)
+ {
*out_result_error = sqrtf(result_error);
+ }
return result_count;
}
diff --git a/thirdparty/misc/patches/polypartition-godot-types.patch b/thirdparty/misc/patches/polypartition-godot-types.patch
index 59fdb2707c..782f02e8dc 100644
--- a/thirdparty/misc/patches/polypartition-godot-types.patch
+++ b/thirdparty/misc/patches/polypartition-godot-types.patch
@@ -1,5 +1,5 @@
diff --git a/thirdparty/misc/polypartition.cpp b/thirdparty/misc/polypartition.cpp
-index 3a8a6efa8319..4f1b6dcb21d8 100644
+index 3a8a6efa83..5e94793b79 100644
--- a/thirdparty/misc/polypartition.cpp
+++ b/thirdparty/misc/polypartition.cpp
@@ -23,10 +23,7 @@
@@ -510,7 +510,7 @@ index 3a8a6efa8319..4f1b6dcb21d8 100644
- return 0;
- }
- numvertices += iter->GetNumPoints();
-+ for (iter = inpolys->front(); iter; iter++) {
++ for (iter = inpolys->front(); iter; iter = iter->next()) {
+ numvertices += iter->get().GetNumPoints();
}
@@ -521,7 +521,7 @@ index 3a8a6efa8319..4f1b6dcb21d8 100644
polystartindex = 0;
- for (iter = inpolys->begin(); iter != inpolys->end(); iter++) {
- poly = &(*iter);
-+ for (iter = inpolys->front(); iter; iter++) {
++ for (iter = inpolys->front(); iter; iter = iter->next()) {
+ poly = &(iter->get());
polyendindex = polystartindex + poly->GetNumPoints() - 1;
for (i = 0; i < poly->GetNumPoints(); i++) {
@@ -569,7 +569,7 @@ index 3a8a6efa8319..4f1b6dcb21d8 100644
newedge.p2 = v->p;
edgeIter = edgeTree.lower_bound(newedge);
- if (edgeIter == edgeTree.begin()) {
-+ if (edgeIter == edgeTree.front()) {
++ if (edgeIter == nullptr || edgeIter == edgeTree.front()) {
error = true;
break;
}
@@ -606,7 +606,7 @@ index 3a8a6efa8319..4f1b6dcb21d8 100644
newedge.p2 = v->p;
edgeIter = edgeTree.lower_bound(newedge);
- if (edgeIter == edgeTree.begin()) {
-+ if (edgeIter == edgeTree.front()) {
++ if (edgeIter == nullptr || edgeIter == edgeTree.front()) {
error = true;
break;
}
@@ -648,7 +648,7 @@ index 3a8a6efa8319..4f1b6dcb21d8 100644
newedge.p2 = v->p;
edgeIter = edgeTree.lower_bound(newedge);
- if (edgeIter == edgeTree.begin()) {
-+ if (edgeIter == edgeTree.front()) {
++ if (edgeIter == nullptr || edgeIter == edgeTree.front()) {
error = true;
break;
}
@@ -716,7 +716,7 @@ index 3a8a6efa8319..4f1b6dcb21d8 100644
}
}
diff --git a/thirdparty/misc/polypartition.h b/thirdparty/misc/polypartition.h
-index f163f5d2173f..b2d905a3ef76 100644
+index f163f5d217..b2d905a3ef 100644
--- a/thirdparty/misc/polypartition.h
+++ b/thirdparty/misc/polypartition.h
@@ -24,8 +24,9 @@
diff --git a/thirdparty/misc/polypartition.cpp b/thirdparty/misc/polypartition.cpp
index 4f1b6dcb21..5e94793b79 100644
--- a/thirdparty/misc/polypartition.cpp
+++ b/thirdparty/misc/polypartition.cpp
@@ -1289,7 +1289,7 @@ int TPPLPartition::MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monoto
bool error = false;
numvertices = 0;
- for (iter = inpolys->front(); iter; iter++) {
+ for (iter = inpolys->front(); iter; iter = iter->next()) {
numvertices += iter->get().GetNumPoints();
}
@@ -1298,7 +1298,7 @@ int TPPLPartition::MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monoto
newnumvertices = numvertices;
polystartindex = 0;
- for (iter = inpolys->front(); iter; iter++) {
+ for (iter = inpolys->front(); iter; iter = iter->next()) {
poly = &(iter->get());
polyendindex = polystartindex + poly->GetNumPoints() - 1;
for (i = 0; i < poly->GetNumPoints(); i++) {
@@ -1408,7 +1408,7 @@ int TPPLPartition::MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monoto
newedge.p1 = v->p;
newedge.p2 = v->p;
edgeIter = edgeTree.lower_bound(newedge);
- if (edgeIter == edgeTree.front()) {
+ if (edgeIter == nullptr || edgeIter == edgeTree.front()) {
error = true;
break;
}
@@ -1449,7 +1449,7 @@ int TPPLPartition::MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monoto
newedge.p1 = v->p;
newedge.p2 = v->p;
edgeIter = edgeTree.lower_bound(newedge);
- if (edgeIter == edgeTree.front()) {
+ if (edgeIter == nullptr || edgeIter == edgeTree.front()) {
error = true;
break;
}
@@ -1494,7 +1494,7 @@ int TPPLPartition::MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monoto
newedge.p1 = v->p;
newedge.p2 = v->p;
edgeIter = edgeTree.lower_bound(newedge);
- if (edgeIter == edgeTree.front()) {
+ if (edgeIter == nullptr || edgeIter == edgeTree.front()) {
error = true;
break;
}
diff --git a/thirdparty/misc/smolv.cpp b/thirdparty/misc/smolv.cpp
new file mode 100644
index 0000000000..26ed7294f9
--- /dev/null
+++ b/thirdparty/misc/smolv.cpp
@@ -0,0 +1,2108 @@
+// smol-v - public domain - https://github.com/aras-p/smol-v
+// authored 2016-2020 by Aras Pranckevicius
+// no warranty implied; use at your own risk
+// See end of file for license information.
+
+#include "smolv.h"
+#include <stdint.h>
+#include <vector>
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+
+#if !defined(_MSC_VER) && __cplusplus < 201103L
+#define static_assert(x,y)
+#endif
+
+#define _SMOLV_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
+// --------------------------------------------------------------------------------------------
+// Metadata about known SPIR-V operations
+
+enum SpvOp
+{
+ SpvOpNop = 0,
+ SpvOpUndef = 1,
+ SpvOpSourceContinued = 2,
+ SpvOpSource = 3,
+ SpvOpSourceExtension = 4,
+ SpvOpName = 5,
+ SpvOpMemberName = 6,
+ SpvOpString = 7,
+ SpvOpLine = 8,
+ SpvOpExtension = 10,
+ SpvOpExtInstImport = 11,
+ SpvOpExtInst = 12,
+ SpvOpVectorShuffleCompact = 13, // not in SPIR-V, added for SMOL-V!
+ SpvOpMemoryModel = 14,
+ SpvOpEntryPoint = 15,
+ SpvOpExecutionMode = 16,
+ SpvOpCapability = 17,
+ SpvOpTypeVoid = 19,
+ SpvOpTypeBool = 20,
+ SpvOpTypeInt = 21,
+ SpvOpTypeFloat = 22,
+ SpvOpTypeVector = 23,
+ SpvOpTypeMatrix = 24,
+ SpvOpTypeImage = 25,
+ SpvOpTypeSampler = 26,
+ SpvOpTypeSampledImage = 27,
+ SpvOpTypeArray = 28,
+ SpvOpTypeRuntimeArray = 29,
+ SpvOpTypeStruct = 30,
+ SpvOpTypeOpaque = 31,
+ SpvOpTypePointer = 32,
+ SpvOpTypeFunction = 33,
+ SpvOpTypeEvent = 34,
+ SpvOpTypeDeviceEvent = 35,
+ SpvOpTypeReserveId = 36,
+ SpvOpTypeQueue = 37,
+ SpvOpTypePipe = 38,
+ SpvOpTypeForwardPointer = 39,
+ SpvOpConstantTrue = 41,
+ SpvOpConstantFalse = 42,
+ SpvOpConstant = 43,
+ SpvOpConstantComposite = 44,
+ SpvOpConstantSampler = 45,
+ SpvOpConstantNull = 46,
+ SpvOpSpecConstantTrue = 48,
+ SpvOpSpecConstantFalse = 49,
+ SpvOpSpecConstant = 50,
+ SpvOpSpecConstantComposite = 51,
+ SpvOpSpecConstantOp = 52,
+ SpvOpFunction = 54,
+ SpvOpFunctionParameter = 55,
+ SpvOpFunctionEnd = 56,
+ SpvOpFunctionCall = 57,
+ SpvOpVariable = 59,
+ SpvOpImageTexelPointer = 60,
+ SpvOpLoad = 61,
+ SpvOpStore = 62,
+ SpvOpCopyMemory = 63,
+ SpvOpCopyMemorySized = 64,
+ SpvOpAccessChain = 65,
+ SpvOpInBoundsAccessChain = 66,
+ SpvOpPtrAccessChain = 67,
+ SpvOpArrayLength = 68,
+ SpvOpGenericPtrMemSemantics = 69,
+ SpvOpInBoundsPtrAccessChain = 70,
+ SpvOpDecorate = 71,
+ SpvOpMemberDecorate = 72,
+ SpvOpDecorationGroup = 73,
+ SpvOpGroupDecorate = 74,
+ SpvOpGroupMemberDecorate = 75,
+ SpvOpVectorExtractDynamic = 77,
+ SpvOpVectorInsertDynamic = 78,
+ SpvOpVectorShuffle = 79,
+ SpvOpCompositeConstruct = 80,
+ SpvOpCompositeExtract = 81,
+ SpvOpCompositeInsert = 82,
+ SpvOpCopyObject = 83,
+ SpvOpTranspose = 84,
+ SpvOpSampledImage = 86,
+ SpvOpImageSampleImplicitLod = 87,
+ SpvOpImageSampleExplicitLod = 88,
+ SpvOpImageSampleDrefImplicitLod = 89,
+ SpvOpImageSampleDrefExplicitLod = 90,
+ SpvOpImageSampleProjImplicitLod = 91,
+ SpvOpImageSampleProjExplicitLod = 92,
+ SpvOpImageSampleProjDrefImplicitLod = 93,
+ SpvOpImageSampleProjDrefExplicitLod = 94,
+ SpvOpImageFetch = 95,
+ SpvOpImageGather = 96,
+ SpvOpImageDrefGather = 97,
+ SpvOpImageRead = 98,
+ SpvOpImageWrite = 99,
+ SpvOpImage = 100,
+ SpvOpImageQueryFormat = 101,
+ SpvOpImageQueryOrder = 102,
+ SpvOpImageQuerySizeLod = 103,
+ SpvOpImageQuerySize = 104,
+ SpvOpImageQueryLod = 105,
+ SpvOpImageQueryLevels = 106,
+ SpvOpImageQuerySamples = 107,
+ SpvOpConvertFToU = 109,
+ SpvOpConvertFToS = 110,
+ SpvOpConvertSToF = 111,
+ SpvOpConvertUToF = 112,
+ SpvOpUConvert = 113,
+ SpvOpSConvert = 114,
+ SpvOpFConvert = 115,
+ SpvOpQuantizeToF16 = 116,
+ SpvOpConvertPtrToU = 117,
+ SpvOpSatConvertSToU = 118,
+ SpvOpSatConvertUToS = 119,
+ SpvOpConvertUToPtr = 120,
+ SpvOpPtrCastToGeneric = 121,
+ SpvOpGenericCastToPtr = 122,
+ SpvOpGenericCastToPtrExplicit = 123,
+ SpvOpBitcast = 124,
+ SpvOpSNegate = 126,
+ SpvOpFNegate = 127,
+ SpvOpIAdd = 128,
+ SpvOpFAdd = 129,
+ SpvOpISub = 130,
+ SpvOpFSub = 131,
+ SpvOpIMul = 132,
+ SpvOpFMul = 133,
+ SpvOpUDiv = 134,
+ SpvOpSDiv = 135,
+ SpvOpFDiv = 136,
+ SpvOpUMod = 137,
+ SpvOpSRem = 138,
+ SpvOpSMod = 139,
+ SpvOpFRem = 140,
+ SpvOpFMod = 141,
+ SpvOpVectorTimesScalar = 142,
+ SpvOpMatrixTimesScalar = 143,
+ SpvOpVectorTimesMatrix = 144,
+ SpvOpMatrixTimesVector = 145,
+ SpvOpMatrixTimesMatrix = 146,
+ SpvOpOuterProduct = 147,
+ SpvOpDot = 148,
+ SpvOpIAddCarry = 149,
+ SpvOpISubBorrow = 150,
+ SpvOpUMulExtended = 151,
+ SpvOpSMulExtended = 152,
+ SpvOpAny = 154,
+ SpvOpAll = 155,
+ SpvOpIsNan = 156,
+ SpvOpIsInf = 157,
+ SpvOpIsFinite = 158,
+ SpvOpIsNormal = 159,
+ SpvOpSignBitSet = 160,
+ SpvOpLessOrGreater = 161,
+ SpvOpOrdered = 162,
+ SpvOpUnordered = 163,
+ SpvOpLogicalEqual = 164,
+ SpvOpLogicalNotEqual = 165,
+ SpvOpLogicalOr = 166,
+ SpvOpLogicalAnd = 167,
+ SpvOpLogicalNot = 168,
+ SpvOpSelect = 169,
+ SpvOpIEqual = 170,
+ SpvOpINotEqual = 171,
+ SpvOpUGreaterThan = 172,
+ SpvOpSGreaterThan = 173,
+ SpvOpUGreaterThanEqual = 174,
+ SpvOpSGreaterThanEqual = 175,
+ SpvOpULessThan = 176,
+ SpvOpSLessThan = 177,
+ SpvOpULessThanEqual = 178,
+ SpvOpSLessThanEqual = 179,
+ SpvOpFOrdEqual = 180,
+ SpvOpFUnordEqual = 181,
+ SpvOpFOrdNotEqual = 182,
+ SpvOpFUnordNotEqual = 183,
+ SpvOpFOrdLessThan = 184,
+ SpvOpFUnordLessThan = 185,
+ SpvOpFOrdGreaterThan = 186,
+ SpvOpFUnordGreaterThan = 187,
+ SpvOpFOrdLessThanEqual = 188,
+ SpvOpFUnordLessThanEqual = 189,
+ SpvOpFOrdGreaterThanEqual = 190,
+ SpvOpFUnordGreaterThanEqual = 191,
+ SpvOpShiftRightLogical = 194,
+ SpvOpShiftRightArithmetic = 195,
+ SpvOpShiftLeftLogical = 196,
+ SpvOpBitwiseOr = 197,
+ SpvOpBitwiseXor = 198,
+ SpvOpBitwiseAnd = 199,
+ SpvOpNot = 200,
+ SpvOpBitFieldInsert = 201,
+ SpvOpBitFieldSExtract = 202,
+ SpvOpBitFieldUExtract = 203,
+ SpvOpBitReverse = 204,
+ SpvOpBitCount = 205,
+ SpvOpDPdx = 207,
+ SpvOpDPdy = 208,
+ SpvOpFwidth = 209,
+ SpvOpDPdxFine = 210,
+ SpvOpDPdyFine = 211,
+ SpvOpFwidthFine = 212,
+ SpvOpDPdxCoarse = 213,
+ SpvOpDPdyCoarse = 214,
+ SpvOpFwidthCoarse = 215,
+ SpvOpEmitVertex = 218,
+ SpvOpEndPrimitive = 219,
+ SpvOpEmitStreamVertex = 220,
+ SpvOpEndStreamPrimitive = 221,
+ SpvOpControlBarrier = 224,
+ SpvOpMemoryBarrier = 225,
+ SpvOpAtomicLoad = 227,
+ SpvOpAtomicStore = 228,
+ SpvOpAtomicExchange = 229,
+ SpvOpAtomicCompareExchange = 230,
+ SpvOpAtomicCompareExchangeWeak = 231,
+ SpvOpAtomicIIncrement = 232,
+ SpvOpAtomicIDecrement = 233,
+ SpvOpAtomicIAdd = 234,
+ SpvOpAtomicISub = 235,
+ SpvOpAtomicSMin = 236,
+ SpvOpAtomicUMin = 237,
+ SpvOpAtomicSMax = 238,
+ SpvOpAtomicUMax = 239,
+ SpvOpAtomicAnd = 240,
+ SpvOpAtomicOr = 241,
+ SpvOpAtomicXor = 242,
+ SpvOpPhi = 245,
+ SpvOpLoopMerge = 246,
+ SpvOpSelectionMerge = 247,
+ SpvOpLabel = 248,
+ SpvOpBranch = 249,
+ SpvOpBranchConditional = 250,
+ SpvOpSwitch = 251,
+ SpvOpKill = 252,
+ SpvOpReturn = 253,
+ SpvOpReturnValue = 254,
+ SpvOpUnreachable = 255,
+ SpvOpLifetimeStart = 256,
+ SpvOpLifetimeStop = 257,
+ SpvOpGroupAsyncCopy = 259,
+ SpvOpGroupWaitEvents = 260,
+ SpvOpGroupAll = 261,
+ SpvOpGroupAny = 262,
+ SpvOpGroupBroadcast = 263,
+ SpvOpGroupIAdd = 264,
+ SpvOpGroupFAdd = 265,
+ SpvOpGroupFMin = 266,
+ SpvOpGroupUMin = 267,
+ SpvOpGroupSMin = 268,
+ SpvOpGroupFMax = 269,
+ SpvOpGroupUMax = 270,
+ SpvOpGroupSMax = 271,
+ SpvOpReadPipe = 274,
+ SpvOpWritePipe = 275,
+ SpvOpReservedReadPipe = 276,
+ SpvOpReservedWritePipe = 277,
+ SpvOpReserveReadPipePackets = 278,
+ SpvOpReserveWritePipePackets = 279,
+ SpvOpCommitReadPipe = 280,
+ SpvOpCommitWritePipe = 281,
+ SpvOpIsValidReserveId = 282,
+ SpvOpGetNumPipePackets = 283,
+ SpvOpGetMaxPipePackets = 284,
+ SpvOpGroupReserveReadPipePackets = 285,
+ SpvOpGroupReserveWritePipePackets = 286,
+ SpvOpGroupCommitReadPipe = 287,
+ SpvOpGroupCommitWritePipe = 288,
+ SpvOpEnqueueMarker = 291,
+ SpvOpEnqueueKernel = 292,
+ SpvOpGetKernelNDrangeSubGroupCount = 293,
+ SpvOpGetKernelNDrangeMaxSubGroupSize = 294,
+ SpvOpGetKernelWorkGroupSize = 295,
+ SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296,
+ SpvOpRetainEvent = 297,
+ SpvOpReleaseEvent = 298,
+ SpvOpCreateUserEvent = 299,
+ SpvOpIsValidEvent = 300,
+ SpvOpSetUserEventStatus = 301,
+ SpvOpCaptureEventProfilingInfo = 302,
+ SpvOpGetDefaultQueue = 303,
+ SpvOpBuildNDRange = 304,
+ SpvOpImageSparseSampleImplicitLod = 305,
+ SpvOpImageSparseSampleExplicitLod = 306,
+ SpvOpImageSparseSampleDrefImplicitLod = 307,
+ SpvOpImageSparseSampleDrefExplicitLod = 308,
+ SpvOpImageSparseSampleProjImplicitLod = 309,
+ SpvOpImageSparseSampleProjExplicitLod = 310,
+ SpvOpImageSparseSampleProjDrefImplicitLod = 311,
+ SpvOpImageSparseSampleProjDrefExplicitLod = 312,
+ SpvOpImageSparseFetch = 313,
+ SpvOpImageSparseGather = 314,
+ SpvOpImageSparseDrefGather = 315,
+ SpvOpImageSparseTexelsResident = 316,
+ SpvOpNoLine = 317,
+ SpvOpAtomicFlagTestAndSet = 318,
+ SpvOpAtomicFlagClear = 319,
+ SpvOpImageSparseRead = 320,
+ SpvOpSizeOf = 321,
+ SpvOpTypePipeStorage = 322,
+ SpvOpConstantPipeStorage = 323,
+ SpvOpCreatePipeFromPipeStorage = 324,
+ SpvOpGetKernelLocalSizeForSubgroupCount = 325,
+ SpvOpGetKernelMaxNumSubgroups = 326,
+ SpvOpTypeNamedBarrier = 327,
+ SpvOpNamedBarrierInitialize = 328,
+ SpvOpMemoryNamedBarrier = 329,
+ SpvOpModuleProcessed = 330,
+ SpvOpExecutionModeId = 331,
+ SpvOpDecorateId = 332,
+ SpvOpGroupNonUniformElect = 333,
+ SpvOpGroupNonUniformAll = 334,
+ SpvOpGroupNonUniformAny = 335,
+ SpvOpGroupNonUniformAllEqual = 336,
+ SpvOpGroupNonUniformBroadcast = 337,
+ SpvOpGroupNonUniformBroadcastFirst = 338,
+ SpvOpGroupNonUniformBallot = 339,
+ SpvOpGroupNonUniformInverseBallot = 340,
+ SpvOpGroupNonUniformBallotBitExtract = 341,
+ SpvOpGroupNonUniformBallotBitCount = 342,
+ SpvOpGroupNonUniformBallotFindLSB = 343,
+ SpvOpGroupNonUniformBallotFindMSB = 344,
+ SpvOpGroupNonUniformShuffle = 345,
+ SpvOpGroupNonUniformShuffleXor = 346,
+ SpvOpGroupNonUniformShuffleUp = 347,
+ SpvOpGroupNonUniformShuffleDown = 348,
+ SpvOpGroupNonUniformIAdd = 349,
+ SpvOpGroupNonUniformFAdd = 350,
+ SpvOpGroupNonUniformIMul = 351,
+ SpvOpGroupNonUniformFMul = 352,
+ SpvOpGroupNonUniformSMin = 353,
+ SpvOpGroupNonUniformUMin = 354,
+ SpvOpGroupNonUniformFMin = 355,
+ SpvOpGroupNonUniformSMax = 356,
+ SpvOpGroupNonUniformUMax = 357,
+ SpvOpGroupNonUniformFMax = 358,
+ SpvOpGroupNonUniformBitwiseAnd = 359,
+ SpvOpGroupNonUniformBitwiseOr = 360,
+ SpvOpGroupNonUniformBitwiseXor = 361,
+ SpvOpGroupNonUniformLogicalAnd = 362,
+ SpvOpGroupNonUniformLogicalOr = 363,
+ SpvOpGroupNonUniformLogicalXor = 364,
+ SpvOpGroupNonUniformQuadBroadcast = 365,
+ SpvOpGroupNonUniformQuadSwap = 366,
+};
+static const int kKnownOpsCount = SpvOpGroupNonUniformQuadSwap+1;
+
+
+static const char* kSpirvOpNames[] =
+{
+ "Nop",
+ "Undef",
+ "SourceContinued",
+ "Source",
+ "SourceExtension",
+ "Name",
+ "MemberName",
+ "String",
+ "Line",
+ "#9",
+ "Extension",
+ "ExtInstImport",
+ "ExtInst",
+ "VectorShuffleCompact",
+ "MemoryModel",
+ "EntryPoint",
+ "ExecutionMode",
+ "Capability",
+ "#18",
+ "TypeVoid",
+ "TypeBool",
+ "TypeInt",
+ "TypeFloat",
+ "TypeVector",
+ "TypeMatrix",
+ "TypeImage",
+ "TypeSampler",
+ "TypeSampledImage",
+ "TypeArray",
+ "TypeRuntimeArray",
+ "TypeStruct",
+ "TypeOpaque",
+ "TypePointer",
+ "TypeFunction",
+ "TypeEvent",
+ "TypeDeviceEvent",
+ "TypeReserveId",
+ "TypeQueue",
+ "TypePipe",
+ "TypeForwardPointer",
+ "#40",
+ "ConstantTrue",
+ "ConstantFalse",
+ "Constant",
+ "ConstantComposite",
+ "ConstantSampler",
+ "ConstantNull",
+ "#47",
+ "SpecConstantTrue",
+ "SpecConstantFalse",
+ "SpecConstant",
+ "SpecConstantComposite",
+ "SpecConstantOp",
+ "#53",
+ "Function",
+ "FunctionParameter",
+ "FunctionEnd",
+ "FunctionCall",
+ "#58",
+ "Variable",
+ "ImageTexelPointer",
+ "Load",
+ "Store",
+ "CopyMemory",
+ "CopyMemorySized",
+ "AccessChain",
+ "InBoundsAccessChain",
+ "PtrAccessChain",
+ "ArrayLength",
+ "GenericPtrMemSemantics",
+ "InBoundsPtrAccessChain",
+ "Decorate",
+ "MemberDecorate",
+ "DecorationGroup",
+ "GroupDecorate",
+ "GroupMemberDecorate",
+ "#76",
+ "VectorExtractDynamic",
+ "VectorInsertDynamic",
+ "VectorShuffle",
+ "CompositeConstruct",
+ "CompositeExtract",
+ "CompositeInsert",
+ "CopyObject",
+ "Transpose",
+ "#85",
+ "SampledImage",
+ "ImageSampleImplicitLod",
+ "ImageSampleExplicitLod",
+ "ImageSampleDrefImplicitLod",
+ "ImageSampleDrefExplicitLod",
+ "ImageSampleProjImplicitLod",
+ "ImageSampleProjExplicitLod",
+ "ImageSampleProjDrefImplicitLod",
+ "ImageSampleProjDrefExplicitLod",
+ "ImageFetch",
+ "ImageGather",
+ "ImageDrefGather",
+ "ImageRead",
+ "ImageWrite",
+ "Image",
+ "ImageQueryFormat",
+ "ImageQueryOrder",
+ "ImageQuerySizeLod",
+ "ImageQuerySize",
+ "ImageQueryLod",
+ "ImageQueryLevels",
+ "ImageQuerySamples",
+ "#108",
+ "ConvertFToU",
+ "ConvertFToS",
+ "ConvertSToF",
+ "ConvertUToF",
+ "UConvert",
+ "SConvert",
+ "FConvert",
+ "QuantizeToF16",
+ "ConvertPtrToU",
+ "SatConvertSToU",
+ "SatConvertUToS",
+ "ConvertUToPtr",
+ "PtrCastToGeneric",
+ "GenericCastToPtr",
+ "GenericCastToPtrExplicit",
+ "Bitcast",
+ "#125",
+ "SNegate",
+ "FNegate",
+ "IAdd",
+ "FAdd",
+ "ISub",
+ "FSub",
+ "IMul",
+ "FMul",
+ "UDiv",
+ "SDiv",
+ "FDiv",
+ "UMod",
+ "SRem",
+ "SMod",
+ "FRem",
+ "FMod",
+ "VectorTimesScalar",
+ "MatrixTimesScalar",
+ "VectorTimesMatrix",
+ "MatrixTimesVector",
+ "MatrixTimesMatrix",
+ "OuterProduct",
+ "Dot",
+ "IAddCarry",
+ "ISubBorrow",
+ "UMulExtended",
+ "SMulExtended",
+ "#153",
+ "Any",
+ "All",
+ "IsNan",
+ "IsInf",
+ "IsFinite",
+ "IsNormal",
+ "SignBitSet",
+ "LessOrGreater",
+ "Ordered",
+ "Unordered",
+ "LogicalEqual",
+ "LogicalNotEqual",
+ "LogicalOr",
+ "LogicalAnd",
+ "LogicalNot",
+ "Select",
+ "IEqual",
+ "INotEqual",
+ "UGreaterThan",
+ "SGreaterThan",
+ "UGreaterThanEqual",
+ "SGreaterThanEqual",
+ "ULessThan",
+ "SLessThan",
+ "ULessThanEqual",
+ "SLessThanEqual",
+ "FOrdEqual",
+ "FUnordEqual",
+ "FOrdNotEqual",
+ "FUnordNotEqual",
+ "FOrdLessThan",
+ "FUnordLessThan",
+ "FOrdGreaterThan",
+ "FUnordGreaterThan",
+ "FOrdLessThanEqual",
+ "FUnordLessThanEqual",
+ "FOrdGreaterThanEqual",
+ "FUnordGreaterThanEqual",
+ "#192",
+ "#193",
+ "ShiftRightLogical",
+ "ShiftRightArithmetic",
+ "ShiftLeftLogical",
+ "BitwiseOr",
+ "BitwiseXor",
+ "BitwiseAnd",
+ "Not",
+ "BitFieldInsert",
+ "BitFieldSExtract",
+ "BitFieldUExtract",
+ "BitReverse",
+ "BitCount",
+ "#206",
+ "DPdx",
+ "DPdy",
+ "Fwidth",
+ "DPdxFine",
+ "DPdyFine",
+ "FwidthFine",
+ "DPdxCoarse",
+ "DPdyCoarse",
+ "FwidthCoarse",
+ "#216",
+ "#217",
+ "EmitVertex",
+ "EndPrimitive",
+ "EmitStreamVertex",
+ "EndStreamPrimitive",
+ "#222",
+ "#223",
+ "ControlBarrier",
+ "MemoryBarrier",
+ "#226",
+ "AtomicLoad",
+ "AtomicStore",
+ "AtomicExchange",
+ "AtomicCompareExchange",
+ "AtomicCompareExchangeWeak",
+ "AtomicIIncrement",
+ "AtomicIDecrement",
+ "AtomicIAdd",
+ "AtomicISub",
+ "AtomicSMin",
+ "AtomicUMin",
+ "AtomicSMax",
+ "AtomicUMax",
+ "AtomicAnd",
+ "AtomicOr",
+ "AtomicXor",
+ "#243",
+ "#244",
+ "Phi",
+ "LoopMerge",
+ "SelectionMerge",
+ "Label",
+ "Branch",
+ "BranchConditional",
+ "Switch",
+ "Kill",
+ "Return",
+ "ReturnValue",
+ "Unreachable",
+ "LifetimeStart",
+ "LifetimeStop",
+ "#258",
+ "GroupAsyncCopy",
+ "GroupWaitEvents",
+ "GroupAll",
+ "GroupAny",
+ "GroupBroadcast",
+ "GroupIAdd",
+ "GroupFAdd",
+ "GroupFMin",
+ "GroupUMin",
+ "GroupSMin",
+ "GroupFMax",
+ "GroupUMax",
+ "GroupSMax",
+ "#272",
+ "#273",
+ "ReadPipe",
+ "WritePipe",
+ "ReservedReadPipe",
+ "ReservedWritePipe",
+ "ReserveReadPipePackets",
+ "ReserveWritePipePackets",
+ "CommitReadPipe",
+ "CommitWritePipe",
+ "IsValidReserveId",
+ "GetNumPipePackets",
+ "GetMaxPipePackets",
+ "GroupReserveReadPipePackets",
+ "GroupReserveWritePipePackets",
+ "GroupCommitReadPipe",
+ "GroupCommitWritePipe",
+ "#289",
+ "#290",
+ "EnqueueMarker",
+ "EnqueueKernel",
+ "GetKernelNDrangeSubGroupCount",
+ "GetKernelNDrangeMaxSubGroupSize",
+ "GetKernelWorkGroupSize",
+ "GetKernelPreferredWorkGroupSizeMultiple",
+ "RetainEvent",
+ "ReleaseEvent",
+ "CreateUserEvent",
+ "IsValidEvent",
+ "SetUserEventStatus",
+ "CaptureEventProfilingInfo",
+ "GetDefaultQueue",
+ "BuildNDRange",
+ "ImageSparseSampleImplicitLod",
+ "ImageSparseSampleExplicitLod",
+ "ImageSparseSampleDrefImplicitLod",
+ "ImageSparseSampleDrefExplicitLod",
+ "ImageSparseSampleProjImplicitLod",
+ "ImageSparseSampleProjExplicitLod",
+ "ImageSparseSampleProjDrefImplicitLod",
+ "ImageSparseSampleProjDrefExplicitLod",
+ "ImageSparseFetch",
+ "ImageSparseGather",
+ "ImageSparseDrefGather",
+ "ImageSparseTexelsResident",
+ "NoLine",
+ "AtomicFlagTestAndSet",
+ "AtomicFlagClear",
+ "ImageSparseRead",
+ "SizeOf",
+ "TypePipeStorage",
+ "ConstantPipeStorage",
+ "CreatePipeFromPipeStorage",
+ "GetKernelLocalSizeForSubgroupCount",
+ "GetKernelMaxNumSubgroups",
+ "TypeNamedBarrier",
+ "NamedBarrierInitialize",
+ "MemoryNamedBarrier",
+ "ModuleProcessed",
+ "ExecutionModeId",
+ "DecorateId",
+ "GroupNonUniformElect",
+ "GroupNonUniformAll",
+ "GroupNonUniformAny",
+ "GroupNonUniformAllEqual",
+ "GroupNonUniformBroadcast",
+ "GroupNonUniformBroadcastFirst",
+ "GroupNonUniformBallot",
+ "GroupNonUniformInverseBallot",
+ "GroupNonUniformBallotBitExtract",
+ "GroupNonUniformBallotBitCount",
+ "GroupNonUniformBallotFindLSB",
+ "GroupNonUniformBallotFindMSB",
+ "GroupNonUniformShuffle",
+ "GroupNonUniformShuffleXor",
+ "GroupNonUniformShuffleUp",
+ "GroupNonUniformShuffleDown",
+ "GroupNonUniformIAdd",
+ "GroupNonUniformFAdd",
+ "GroupNonUniformIMul",
+ "GroupNonUniformFMul",
+ "GroupNonUniformSMin",
+ "GroupNonUniformUMin",
+ "GroupNonUniformFMin",
+ "GroupNonUniformSMax",
+ "GroupNonUniformUMax",
+ "GroupNonUniformFMax",
+ "GroupNonUniformBitwiseAnd",
+ "GroupNonUniformBitwiseOr",
+ "GroupNonUniformBitwiseXor",
+ "GroupNonUniformLogicalAnd",
+ "GroupNonUniformLogicalOr",
+ "GroupNonUniformLogicalXor",
+ "GroupNonUniformQuadBroadcast",
+ "GroupNonUniformQuadSwap",
+};
+static_assert(_SMOLV_ARRAY_SIZE(kSpirvOpNames) == kKnownOpsCount, "kSpirvOpNames table mismatch with known SpvOps");
+
+
+struct OpData
+{
+ uint8_t hasResult; // does it have result ID?
+ uint8_t hasType; // does it have type ID?
+ uint8_t deltaFromResult; // How many words after (optional) type+result to write out as deltas from result?
+ uint8_t varrest; // should the rest of words be written in varint encoding?
+};
+static const OpData kSpirvOpData[] =
+{
+ {0, 0, 0, 0}, // Nop
+ {1, 1, 0, 0}, // Undef
+ {0, 0, 0, 0}, // SourceContinued
+ {0, 0, 0, 1}, // Source
+ {0, 0, 0, 0}, // SourceExtension
+ {0, 0, 0, 0}, // Name
+ {0, 0, 0, 0}, // MemberName
+ {0, 0, 0, 0}, // String
+ {0, 0, 0, 1}, // Line
+ {1, 1, 0, 0}, // #9
+ {0, 0, 0, 0}, // Extension
+ {1, 0, 0, 0}, // ExtInstImport
+ {1, 1, 0, 1}, // ExtInst
+ {1, 1, 2, 1}, // VectorShuffleCompact - new in SMOLV
+ {0, 0, 0, 1}, // MemoryModel
+ {0, 0, 0, 1}, // EntryPoint
+ {0, 0, 0, 1}, // ExecutionMode
+ {0, 0, 0, 1}, // Capability
+ {1, 1, 0, 0}, // #18
+ {1, 0, 0, 1}, // TypeVoid
+ {1, 0, 0, 1}, // TypeBool
+ {1, 0, 0, 1}, // TypeInt
+ {1, 0, 0, 1}, // TypeFloat
+ {1, 0, 0, 1}, // TypeVector
+ {1, 0, 0, 1}, // TypeMatrix
+ {1, 0, 0, 1}, // TypeImage
+ {1, 0, 0, 1}, // TypeSampler
+ {1, 0, 0, 1}, // TypeSampledImage
+ {1, 0, 0, 1}, // TypeArray
+ {1, 0, 0, 1}, // TypeRuntimeArray
+ {1, 0, 0, 1}, // TypeStruct
+ {1, 0, 0, 1}, // TypeOpaque
+ {1, 0, 0, 1}, // TypePointer
+ {1, 0, 0, 1}, // TypeFunction
+ {1, 0, 0, 1}, // TypeEvent
+ {1, 0, 0, 1}, // TypeDeviceEvent
+ {1, 0, 0, 1}, // TypeReserveId
+ {1, 0, 0, 1}, // TypeQueue
+ {1, 0, 0, 1}, // TypePipe
+ {0, 0, 0, 1}, // TypeForwardPointer
+ {1, 1, 0, 0}, // #40
+ {1, 1, 0, 0}, // ConstantTrue
+ {1, 1, 0, 0}, // ConstantFalse
+ {1, 1, 0, 0}, // Constant
+ {1, 1, 9, 0}, // ConstantComposite
+ {1, 1, 0, 1}, // ConstantSampler
+ {1, 1, 0, 0}, // ConstantNull
+ {1, 1, 0, 0}, // #47
+ {1, 1, 0, 0}, // SpecConstantTrue
+ {1, 1, 0, 0}, // SpecConstantFalse
+ {1, 1, 0, 0}, // SpecConstant
+ {1, 1, 9, 0}, // SpecConstantComposite
+ {1, 1, 0, 0}, // SpecConstantOp
+ {1, 1, 0, 0}, // #53
+ {1, 1, 0, 1}, // Function
+ {1, 1, 0, 0}, // FunctionParameter
+ {0, 0, 0, 0}, // FunctionEnd
+ {1, 1, 9, 0}, // FunctionCall
+ {1, 1, 0, 0}, // #58
+ {1, 1, 0, 1}, // Variable
+ {1, 1, 0, 0}, // ImageTexelPointer
+ {1, 1, 1, 1}, // Load
+ {0, 0, 2, 1}, // Store
+ {0, 0, 0, 0}, // CopyMemory
+ {0, 0, 0, 0}, // CopyMemorySized
+ {1, 1, 0, 1}, // AccessChain
+ {1, 1, 0, 0}, // InBoundsAccessChain
+ {1, 1, 0, 0}, // PtrAccessChain
+ {1, 1, 0, 0}, // ArrayLength
+ {1, 1, 0, 0}, // GenericPtrMemSemantics
+ {1, 1, 0, 0}, // InBoundsPtrAccessChain
+ {0, 0, 0, 1}, // Decorate
+ {0, 0, 0, 1}, // MemberDecorate
+ {1, 0, 0, 0}, // DecorationGroup
+ {0, 0, 0, 0}, // GroupDecorate
+ {0, 0, 0, 0}, // GroupMemberDecorate
+ {1, 1, 0, 0}, // #76
+ {1, 1, 1, 1}, // VectorExtractDynamic
+ {1, 1, 2, 1}, // VectorInsertDynamic
+ {1, 1, 2, 1}, // VectorShuffle
+ {1, 1, 9, 0}, // CompositeConstruct
+ {1, 1, 1, 1}, // CompositeExtract
+ {1, 1, 2, 1}, // CompositeInsert
+ {1, 1, 1, 0}, // CopyObject
+ {1, 1, 0, 0}, // Transpose
+ {1, 1, 0, 0}, // #85
+ {1, 1, 0, 0}, // SampledImage
+ {1, 1, 2, 1}, // ImageSampleImplicitLod
+ {1, 1, 2, 1}, // ImageSampleExplicitLod
+ {1, 1, 3, 1}, // ImageSampleDrefImplicitLod
+ {1, 1, 3, 1}, // ImageSampleDrefExplicitLod
+ {1, 1, 2, 1}, // ImageSampleProjImplicitLod
+ {1, 1, 2, 1}, // ImageSampleProjExplicitLod
+ {1, 1, 3, 1}, // ImageSampleProjDrefImplicitLod
+ {1, 1, 3, 1}, // ImageSampleProjDrefExplicitLod
+ {1, 1, 2, 1}, // ImageFetch
+ {1, 1, 3, 1}, // ImageGather
+ {1, 1, 3, 1}, // ImageDrefGather
+ {1, 1, 2, 1}, // ImageRead
+ {0, 0, 3, 1}, // ImageWrite
+ {1, 1, 1, 0}, // Image
+ {1, 1, 1, 0}, // ImageQueryFormat
+ {1, 1, 1, 0}, // ImageQueryOrder
+ {1, 1, 2, 0}, // ImageQuerySizeLod
+ {1, 1, 1, 0}, // ImageQuerySize
+ {1, 1, 2, 0}, // ImageQueryLod
+ {1, 1, 1, 0}, // ImageQueryLevels
+ {1, 1, 1, 0}, // ImageQuerySamples
+ {1, 1, 0, 0}, // #108
+ {1, 1, 1, 0}, // ConvertFToU
+ {1, 1, 1, 0}, // ConvertFToS
+ {1, 1, 1, 0}, // ConvertSToF
+ {1, 1, 1, 0}, // ConvertUToF
+ {1, 1, 1, 0}, // UConvert
+ {1, 1, 1, 0}, // SConvert
+ {1, 1, 1, 0}, // FConvert
+ {1, 1, 1, 0}, // QuantizeToF16
+ {1, 1, 1, 0}, // ConvertPtrToU
+ {1, 1, 1, 0}, // SatConvertSToU
+ {1, 1, 1, 0}, // SatConvertUToS
+ {1, 1, 1, 0}, // ConvertUToPtr
+ {1, 1, 1, 0}, // PtrCastToGeneric
+ {1, 1, 1, 0}, // GenericCastToPtr
+ {1, 1, 1, 1}, // GenericCastToPtrExplicit
+ {1, 1, 1, 0}, // Bitcast
+ {1, 1, 0, 0}, // #125
+ {1, 1, 1, 0}, // SNegate
+ {1, 1, 1, 0}, // FNegate
+ {1, 1, 2, 0}, // IAdd
+ {1, 1, 2, 0}, // FAdd
+ {1, 1, 2, 0}, // ISub
+ {1, 1, 2, 0}, // FSub
+ {1, 1, 2, 0}, // IMul
+ {1, 1, 2, 0}, // FMul
+ {1, 1, 2, 0}, // UDiv
+ {1, 1, 2, 0}, // SDiv
+ {1, 1, 2, 0}, // FDiv
+ {1, 1, 2, 0}, // UMod
+ {1, 1, 2, 0}, // SRem
+ {1, 1, 2, 0}, // SMod
+ {1, 1, 2, 0}, // FRem
+ {1, 1, 2, 0}, // FMod
+ {1, 1, 2, 0}, // VectorTimesScalar
+ {1, 1, 2, 0}, // MatrixTimesScalar
+ {1, 1, 2, 0}, // VectorTimesMatrix
+ {1, 1, 2, 0}, // MatrixTimesVector
+ {1, 1, 2, 0}, // MatrixTimesMatrix
+ {1, 1, 2, 0}, // OuterProduct
+ {1, 1, 2, 0}, // Dot
+ {1, 1, 2, 0}, // IAddCarry
+ {1, 1, 2, 0}, // ISubBorrow
+ {1, 1, 2, 0}, // UMulExtended
+ {1, 1, 2, 0}, // SMulExtended
+ {1, 1, 0, 0}, // #153
+ {1, 1, 1, 0}, // Any
+ {1, 1, 1, 0}, // All
+ {1, 1, 1, 0}, // IsNan
+ {1, 1, 1, 0}, // IsInf
+ {1, 1, 1, 0}, // IsFinite
+ {1, 1, 1, 0}, // IsNormal
+ {1, 1, 1, 0}, // SignBitSet
+ {1, 1, 2, 0}, // LessOrGreater
+ {1, 1, 2, 0}, // Ordered
+ {1, 1, 2, 0}, // Unordered
+ {1, 1, 2, 0}, // LogicalEqual
+ {1, 1, 2, 0}, // LogicalNotEqual
+ {1, 1, 2, 0}, // LogicalOr
+ {1, 1, 2, 0}, // LogicalAnd
+ {1, 1, 1, 0}, // LogicalNot
+ {1, 1, 3, 0}, // Select
+ {1, 1, 2, 0}, // IEqual
+ {1, 1, 2, 0}, // INotEqual
+ {1, 1, 2, 0}, // UGreaterThan
+ {1, 1, 2, 0}, // SGreaterThan
+ {1, 1, 2, 0}, // UGreaterThanEqual
+ {1, 1, 2, 0}, // SGreaterThanEqual
+ {1, 1, 2, 0}, // ULessThan
+ {1, 1, 2, 0}, // SLessThan
+ {1, 1, 2, 0}, // ULessThanEqual
+ {1, 1, 2, 0}, // SLessThanEqual
+ {1, 1, 2, 0}, // FOrdEqual
+ {1, 1, 2, 0}, // FUnordEqual
+ {1, 1, 2, 0}, // FOrdNotEqual
+ {1, 1, 2, 0}, // FUnordNotEqual
+ {1, 1, 2, 0}, // FOrdLessThan
+ {1, 1, 2, 0}, // FUnordLessThan
+ {1, 1, 2, 0}, // FOrdGreaterThan
+ {1, 1, 2, 0}, // FUnordGreaterThan
+ {1, 1, 2, 0}, // FOrdLessThanEqual
+ {1, 1, 2, 0}, // FUnordLessThanEqual
+ {1, 1, 2, 0}, // FOrdGreaterThanEqual
+ {1, 1, 2, 0}, // FUnordGreaterThanEqual
+ {1, 1, 0, 0}, // #192
+ {1, 1, 0, 0}, // #193
+ {1, 1, 2, 0}, // ShiftRightLogical
+ {1, 1, 2, 0}, // ShiftRightArithmetic
+ {1, 1, 2, 0}, // ShiftLeftLogical
+ {1, 1, 2, 0}, // BitwiseOr
+ {1, 1, 2, 0}, // BitwiseXor
+ {1, 1, 2, 0}, // BitwiseAnd
+ {1, 1, 1, 0}, // Not
+ {1, 1, 4, 0}, // BitFieldInsert
+ {1, 1, 3, 0}, // BitFieldSExtract
+ {1, 1, 3, 0}, // BitFieldUExtract
+ {1, 1, 1, 0}, // BitReverse
+ {1, 1, 1, 0}, // BitCount
+ {1, 1, 0, 0}, // #206
+ {1, 1, 0, 0}, // DPdx
+ {1, 1, 0, 0}, // DPdy
+ {1, 1, 0, 0}, // Fwidth
+ {1, 1, 0, 0}, // DPdxFine
+ {1, 1, 0, 0}, // DPdyFine
+ {1, 1, 0, 0}, // FwidthFine
+ {1, 1, 0, 0}, // DPdxCoarse
+ {1, 1, 0, 0}, // DPdyCoarse
+ {1, 1, 0, 0}, // FwidthCoarse
+ {1, 1, 0, 0}, // #216
+ {1, 1, 0, 0}, // #217
+ {0, 0, 0, 0}, // EmitVertex
+ {0, 0, 0, 0}, // EndPrimitive
+ {0, 0, 0, 0}, // EmitStreamVertex
+ {0, 0, 0, 0}, // EndStreamPrimitive
+ {1, 1, 0, 0}, // #222
+ {1, 1, 0, 0}, // #223
+ {0, 0, 3, 0}, // ControlBarrier
+ {0, 0, 2, 0}, // MemoryBarrier
+ {1, 1, 0, 0}, // #226
+ {1, 1, 0, 0}, // AtomicLoad
+ {0, 0, 0, 0}, // AtomicStore
+ {1, 1, 0, 0}, // AtomicExchange
+ {1, 1, 0, 0}, // AtomicCompareExchange
+ {1, 1, 0, 0}, // AtomicCompareExchangeWeak
+ {1, 1, 0, 0}, // AtomicIIncrement
+ {1, 1, 0, 0}, // AtomicIDecrement
+ {1, 1, 0, 0}, // AtomicIAdd
+ {1, 1, 0, 0}, // AtomicISub
+ {1, 1, 0, 0}, // AtomicSMin
+ {1, 1, 0, 0}, // AtomicUMin
+ {1, 1, 0, 0}, // AtomicSMax
+ {1, 1, 0, 0}, // AtomicUMax
+ {1, 1, 0, 0}, // AtomicAnd
+ {1, 1, 0, 0}, // AtomicOr
+ {1, 1, 0, 0}, // AtomicXor
+ {1, 1, 0, 0}, // #243
+ {1, 1, 0, 0}, // #244
+ {1, 1, 0, 0}, // Phi
+ {0, 0, 2, 1}, // LoopMerge
+ {0, 0, 1, 1}, // SelectionMerge
+ {1, 0, 0, 0}, // Label
+ {0, 0, 1, 0}, // Branch
+ {0, 0, 3, 1}, // BranchConditional
+ {0, 0, 0, 0}, // Switch
+ {0, 0, 0, 0}, // Kill
+ {0, 0, 0, 0}, // Return
+ {0, 0, 0, 0}, // ReturnValue
+ {0, 0, 0, 0}, // Unreachable
+ {0, 0, 0, 0}, // LifetimeStart
+ {0, 0, 0, 0}, // LifetimeStop
+ {1, 1, 0, 0}, // #258
+ {1, 1, 0, 0}, // GroupAsyncCopy
+ {0, 0, 0, 0}, // GroupWaitEvents
+ {1, 1, 0, 0}, // GroupAll
+ {1, 1, 0, 0}, // GroupAny
+ {1, 1, 0, 0}, // GroupBroadcast
+ {1, 1, 0, 0}, // GroupIAdd
+ {1, 1, 0, 0}, // GroupFAdd
+ {1, 1, 0, 0}, // GroupFMin
+ {1, 1, 0, 0}, // GroupUMin
+ {1, 1, 0, 0}, // GroupSMin
+ {1, 1, 0, 0}, // GroupFMax
+ {1, 1, 0, 0}, // GroupUMax
+ {1, 1, 0, 0}, // GroupSMax
+ {1, 1, 0, 0}, // #272
+ {1, 1, 0, 0}, // #273
+ {1, 1, 0, 0}, // ReadPipe
+ {1, 1, 0, 0}, // WritePipe
+ {1, 1, 0, 0}, // ReservedReadPipe
+ {1, 1, 0, 0}, // ReservedWritePipe
+ {1, 1, 0, 0}, // ReserveReadPipePackets
+ {1, 1, 0, 0}, // ReserveWritePipePackets
+ {0, 0, 0, 0}, // CommitReadPipe
+ {0, 0, 0, 0}, // CommitWritePipe
+ {1, 1, 0, 0}, // IsValidReserveId
+ {1, 1, 0, 0}, // GetNumPipePackets
+ {1, 1, 0, 0}, // GetMaxPipePackets
+ {1, 1, 0, 0}, // GroupReserveReadPipePackets
+ {1, 1, 0, 0}, // GroupReserveWritePipePackets
+ {0, 0, 0, 0}, // GroupCommitReadPipe
+ {0, 0, 0, 0}, // GroupCommitWritePipe
+ {1, 1, 0, 0}, // #289
+ {1, 1, 0, 0}, // #290
+ {1, 1, 0, 0}, // EnqueueMarker
+ {1, 1, 0, 0}, // EnqueueKernel
+ {1, 1, 0, 0}, // GetKernelNDrangeSubGroupCount
+ {1, 1, 0, 0}, // GetKernelNDrangeMaxSubGroupSize
+ {1, 1, 0, 0}, // GetKernelWorkGroupSize
+ {1, 1, 0, 0}, // GetKernelPreferredWorkGroupSizeMultiple
+ {0, 0, 0, 0}, // RetainEvent
+ {0, 0, 0, 0}, // ReleaseEvent
+ {1, 1, 0, 0}, // CreateUserEvent
+ {1, 1, 0, 0}, // IsValidEvent
+ {0, 0, 0, 0}, // SetUserEventStatus
+ {0, 0, 0, 0}, // CaptureEventProfilingInfo
+ {1, 1, 0, 0}, // GetDefaultQueue
+ {1, 1, 0, 0}, // BuildNDRange
+ {1, 1, 2, 1}, // ImageSparseSampleImplicitLod
+ {1, 1, 2, 1}, // ImageSparseSampleExplicitLod
+ {1, 1, 3, 1}, // ImageSparseSampleDrefImplicitLod
+ {1, 1, 3, 1}, // ImageSparseSampleDrefExplicitLod
+ {1, 1, 2, 1}, // ImageSparseSampleProjImplicitLod
+ {1, 1, 2, 1}, // ImageSparseSampleProjExplicitLod
+ {1, 1, 3, 1}, // ImageSparseSampleProjDrefImplicitLod
+ {1, 1, 3, 1}, // ImageSparseSampleProjDrefExplicitLod
+ {1, 1, 2, 1}, // ImageSparseFetch
+ {1, 1, 3, 1}, // ImageSparseGather
+ {1, 1, 3, 1}, // ImageSparseDrefGather
+ {1, 1, 1, 0}, // ImageSparseTexelsResident
+ {0, 0, 0, 0}, // NoLine
+ {1, 1, 0, 0}, // AtomicFlagTestAndSet
+ {0, 0, 0, 0}, // AtomicFlagClear
+ {1, 1, 0, 0}, // ImageSparseRead
+ {1, 1, 0, 0}, // SizeOf
+ {1, 1, 0, 0}, // TypePipeStorage
+ {1, 1, 0, 0}, // ConstantPipeStorage
+ {1, 1, 0, 0}, // CreatePipeFromPipeStorage
+ {1, 1, 0, 0}, // GetKernelLocalSizeForSubgroupCount
+ {1, 1, 0, 0}, // GetKernelMaxNumSubgroups
+ {1, 1, 0, 0}, // TypeNamedBarrier
+ {1, 1, 0, 1}, // NamedBarrierInitialize
+ {0, 0, 2, 1}, // MemoryNamedBarrier
+ {1, 1, 0, 0}, // ModuleProcessed
+ {0, 0, 0, 1}, // ExecutionModeId
+ {0, 0, 0, 1}, // DecorateId
+ {1, 1, 1, 1}, // GroupNonUniformElect
+ {1, 1, 1, 1}, // GroupNonUniformAll
+ {1, 1, 1, 1}, // GroupNonUniformAny
+ {1, 1, 1, 1}, // GroupNonUniformAllEqual
+ {1, 1, 1, 1}, // GroupNonUniformBroadcast
+ {1, 1, 1, 1}, // GroupNonUniformBroadcastFirst
+ {1, 1, 1, 1}, // GroupNonUniformBallot
+ {1, 1, 1, 1}, // GroupNonUniformInverseBallot
+ {1, 1, 1, 1}, // GroupNonUniformBallotBitExtract
+ {1, 1, 1, 1}, // GroupNonUniformBallotBitCount
+ {1, 1, 1, 1}, // GroupNonUniformBallotFindLSB
+ {1, 1, 1, 1}, // GroupNonUniformBallotFindMSB
+ {1, 1, 1, 1}, // GroupNonUniformShuffle
+ {1, 1, 1, 1}, // GroupNonUniformShuffleXor
+ {1, 1, 1, 1}, // GroupNonUniformShuffleUp
+ {1, 1, 1, 1}, // GroupNonUniformShuffleDown
+ {1, 1, 1, 1}, // GroupNonUniformIAdd
+ {1, 1, 1, 1}, // GroupNonUniformFAdd
+ {1, 1, 1, 1}, // GroupNonUniformIMul
+ {1, 1, 1, 1}, // GroupNonUniformFMul
+ {1, 1, 1, 1}, // GroupNonUniformSMin
+ {1, 1, 1, 1}, // GroupNonUniformUMin
+ {1, 1, 1, 1}, // GroupNonUniformFMin
+ {1, 1, 1, 1}, // GroupNonUniformSMax
+ {1, 1, 1, 1}, // GroupNonUniformUMax
+ {1, 1, 1, 1}, // GroupNonUniformFMax
+ {1, 1, 1, 1}, // GroupNonUniformBitwiseAnd
+ {1, 1, 1, 1}, // GroupNonUniformBitwiseOr
+ {1, 1, 1, 1}, // GroupNonUniformBitwiseXor
+ {1, 1, 1, 1}, // GroupNonUniformLogicalAnd
+ {1, 1, 1, 1}, // GroupNonUniformLogicalOr
+ {1, 1, 1, 1}, // GroupNonUniformLogicalXor
+ {1, 1, 1, 1}, // GroupNonUniformQuadBroadcast
+ {1, 1, 1, 1}, // GroupNonUniformQuadSwap
+};
+static_assert(_SMOLV_ARRAY_SIZE(kSpirvOpData) == kKnownOpsCount, "kSpirvOpData table mismatch with known SpvOps");
+
+// Instruction encoding depends on the table that describes the various SPIR-V opcodes.
+// Whenever we change or expand the table, we need to bump up the SMOL-V version, and make
+// sure that we can still decode files encoded by an older version.
+static int smolv_GetKnownOpsCount(int version)
+{
+ if (version == 0)
+ return SpvOpModuleProcessed+1;
+ if (version == 1) // 2020 February, version 1 added ExecutionModeId..GroupNonUniformQuadSwap
+ return SpvOpGroupNonUniformQuadSwap+1;
+ return 0;
+}
+
+static bool smolv_OpHasResult(SpvOp op, int opsCount)
+{
+ if (op < 0 || op >= opsCount)
+ return false;
+ return kSpirvOpData[op].hasResult != 0;
+}
+
+static bool smolv_OpHasType(SpvOp op, int opsCount)
+{
+ if (op < 0 || op >= opsCount)
+ return false;
+ return kSpirvOpData[op].hasType != 0;
+}
+
+static int smolv_OpDeltaFromResult(SpvOp op, int opsCount)
+{
+ if (op < 0 || op >= opsCount)
+ return 0;
+ return kSpirvOpData[op].deltaFromResult;
+}
+
+static bool smolv_OpVarRest(SpvOp op, int opsCount)
+{
+ if (op < 0 || op >= opsCount)
+ return false;
+ return kSpirvOpData[op].varrest != 0;
+}
+
+static bool smolv_OpDebugInfo(SpvOp op, int opsCount)
+{
+ return
+ op == SpvOpSourceContinued ||
+ op == SpvOpSource ||
+ op == SpvOpSourceExtension ||
+ op == SpvOpName ||
+ op == SpvOpMemberName ||
+ op == SpvOpString ||
+ op == SpvOpLine ||
+ op == SpvOpNoLine ||
+ op == SpvOpModuleProcessed;
+}
+
+
+static int smolv_DecorationExtraOps(int dec)
+{
+ if (dec == 0 || (dec >= 2 && dec <= 5)) // RelaxedPrecision, Block..ColMajor
+ return 0;
+ if (dec >= 29 && dec <= 37) // Stream..XfbStride
+ return 1;
+ return -1; // unknown, encode length
+}
+
+
+// --------------------------------------------------------------------------------------------
+
+
+static bool smolv_CheckGenericHeader(const uint32_t* words, size_t wordCount, uint32_t expectedMagic, uint32_t versionMask)
+{
+ if (!words)
+ return false;
+ if (wordCount < 5)
+ return false;
+
+ uint32_t headerMagic = words[0];
+ if (headerMagic != expectedMagic)
+ return false;
+ uint32_t headerVersion = words[1] & versionMask;
+ if (headerVersion < 0x00010000 || headerVersion > 0x00010500)
+ return false; // only support 1.0 through 1.5
+
+ return true;
+}
+
+static const int kSpirVHeaderMagic = 0x07230203;
+static const int kSmolHeaderMagic = 0x534D4F4C; // "SMOL"
+
+static const int kSmolCurrEncodingVersion = 1;
+
+static bool smolv_CheckSpirVHeader(const uint32_t* words, size_t wordCount)
+{
+ //@TODO: if SPIR-V header magic was reversed, that means the file got written
+ // in a "big endian" order. Need to byteswap all words then.
+ return smolv_CheckGenericHeader(words, wordCount, kSpirVHeaderMagic, 0xFFFFFFFF);
+}
+static bool smolv_CheckSmolHeader(const uint8_t* bytes, size_t byteCount)
+{
+ if (!smolv_CheckGenericHeader((const uint32_t*)bytes, byteCount/4, kSmolHeaderMagic, 0x00FFFFFF))
+ return false;
+ if (byteCount < 24) // one more word past header to store decoded length
+ return false;
+ // SMOL-V version
+ int smolVersion = ((const uint32_t*)bytes)[1] >> 24;
+ if (smolVersion < 0 || smolVersion > kSmolCurrEncodingVersion)
+ return false;
+ return true;
+}
+
+
+static void smolv_Write4(smolv::ByteArray& arr, uint32_t v)
+{
+ arr.push_back(v & 0xFF);
+ arr.push_back((v >> 8) & 0xFF);
+ arr.push_back((v >> 16) & 0xFF);
+ arr.push_back(v >> 24);
+}
+
+static void smolv_Write4(uint8_t*& buf, uint32_t v)
+{
+ memcpy(buf, &v, 4);
+ buf += 4;
+}
+
+
+static bool smolv_Read4(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outv)
+{
+ if (data + 4 > dataEnd)
+ return false;
+ outv = (data[0]) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+ data += 4;
+ return true;
+}
+
+
+// --------------------------------------------------------------------------------------------
+
+// Variable-length integer encoding for unsigned integers. In each byte:
+// - highest bit set if more bytes follow, cleared if this is last byte.
+// - other 7 bits are the actual value payload.
+// Takes 1-5 bytes to encode an integer (values between 0 and 127 take one byte, etc.).
+
+static void smolv_WriteVarint(smolv::ByteArray& arr, uint32_t v)
+{
+ while (v > 127)
+ {
+ arr.push_back((v & 127) | 128);
+ v >>= 7;
+ }
+ arr.push_back(v & 127);
+}
+
+static bool smolv_ReadVarint(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outVal)
+{
+ uint32_t v = 0;
+ uint32_t shift = 0;
+ while (data < dataEnd)
+ {
+ uint8_t b = *data;
+ v |= (b & 127) << shift;
+ shift += 7;
+ data++;
+ if (!(b & 128))
+ break;
+ }
+ outVal = v;
+ return true; //@TODO: report failures
+}
+
+static uint32_t smolv_ZigEncode(int32_t i)
+{
+ return (uint32_t(i) << 1) ^ (i >> 31);
+}
+
+static int32_t smolv_ZigDecode(uint32_t u)
+{
+ return (u & 1) ? ((u >> 1) ^ ~0) : (u >> 1);
+}
+
+
+// Remap most common Op codes (Load, Store, Decorate, VectorShuffle etc.) to be in < 16 range, for
+// more compact varint encoding. This basically swaps rarely used op values that are < 16 with the
+// ones that are common.
+
+static SpvOp smolv_RemapOp(SpvOp op)
+{
+# define _SMOLV_SWAP_OP(op1,op2) if (op==op1) return op2; if (op==op2) return op1
+ _SMOLV_SWAP_OP(SpvOpDecorate,SpvOpNop); // 0: 24%
+ _SMOLV_SWAP_OP(SpvOpLoad,SpvOpUndef); // 1: 17%
+ _SMOLV_SWAP_OP(SpvOpStore,SpvOpSourceContinued); // 2: 9%
+ _SMOLV_SWAP_OP(SpvOpAccessChain,SpvOpSource); // 3: 7.2%
+ _SMOLV_SWAP_OP(SpvOpVectorShuffle,SpvOpSourceExtension); // 4: 5.0%
+ // Name - already small enum value - 5: 4.4%
+ // MemberName - already small enum value - 6: 2.9%
+ _SMOLV_SWAP_OP(SpvOpMemberDecorate,SpvOpString); // 7: 4.0%
+ _SMOLV_SWAP_OP(SpvOpLabel,SpvOpLine); // 8: 0.9%
+ _SMOLV_SWAP_OP(SpvOpVariable,(SpvOp)9); // 9: 3.9%
+ _SMOLV_SWAP_OP(SpvOpFMul,SpvOpExtension); // 10: 3.9%
+ _SMOLV_SWAP_OP(SpvOpFAdd,SpvOpExtInstImport); // 11: 2.5%
+ // ExtInst - already small enum value - 12: 1.2%
+ // VectorShuffleCompact - already small enum value - used for compact shuffle encoding
+ _SMOLV_SWAP_OP(SpvOpTypePointer,SpvOpMemoryModel); // 14: 2.2%
+ _SMOLV_SWAP_OP(SpvOpFNegate,SpvOpEntryPoint); // 15: 1.1%
+# undef _SMOLV_SWAP_OP
+ return op;
+}
+
+
+// For most compact varint encoding of common instructions, the instruction length should come out
+// into 3 bits (be <8). SPIR-V instruction lengths are always at least 1, and for some other
+// instructions they are guaranteed to be some other minimum length. Adjust the length before encoding,
+// and after decoding accordingly.
+
+static uint32_t smolv_EncodeLen(SpvOp op, uint32_t len)
+{
+ len--;
+ if (op == SpvOpVectorShuffle) len -= 4;
+ if (op == SpvOpVectorShuffleCompact) len -= 4;
+ if (op == SpvOpDecorate) len -= 2;
+ if (op == SpvOpLoad) len -= 3;
+ if (op == SpvOpAccessChain) len -= 3;
+ return len;
+}
+
+static uint32_t smolv_DecodeLen(SpvOp op, uint32_t len)
+{
+ len++;
+ if (op == SpvOpVectorShuffle) len += 4;
+ if (op == SpvOpVectorShuffleCompact) len += 4;
+ if (op == SpvOpDecorate) len += 2;
+ if (op == SpvOpLoad) len += 3;
+ if (op == SpvOpAccessChain) len += 3;
+ return len;
+}
+
+
+// Shuffling bits of length + opcode to be more compact in varint encoding in typical cases:
+// 0x LLLL OOOO is how SPIR-V encodes it (L=length, O=op), we shuffle into:
+// 0x LLLO OOLO, so that common case (op<16, len<8) is encoded into one byte.
+
+static bool smolv_WriteLengthOp(smolv::ByteArray& arr, uint32_t len, SpvOp op)
+{
+ len = smolv_EncodeLen(op, len);
+ // SPIR-V length field is 16 bits; if we get a larger value that means something
+ // was wrong, e.g. a vector shuffle instruction with less than 4 words (and our
+ // adjustment to common lengths in smolv_EncodeLen wrapped around)
+ if (len > 0xFFFF)
+ return false;
+ op = smolv_RemapOp(op);
+ uint32_t oplen = ((len >> 4) << 20) | ((op >> 4) << 8) | ((len & 0xF) << 4) | (op & 0xF);
+ smolv_WriteVarint(arr, oplen);
+ return true;
+}
+
+static bool smolv_ReadLengthOp(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outLen, SpvOp& outOp)
+{
+ uint32_t val;
+ if (!smolv_ReadVarint(data, dataEnd, val))
+ return false;
+ outLen = ((val >> 20) << 4) | ((val >> 4) & 0xF);
+ outOp = (SpvOp)(((val >> 4) & 0xFFF0) | (val & 0xF));
+
+ outOp = smolv_RemapOp(outOp);
+ outLen = smolv_DecodeLen(outOp, outLen);
+ return true;
+}
+
+
+
+#define _SMOLV_READ_OP(len, words, op) \
+ uint32_t len = words[0] >> 16; \
+ if (len < 1) return false; /* malformed instruction, length needs to be at least 1 */ \
+ if (words + len > wordsEnd) return false; /* malformed instruction, goes past end of data */ \
+ SpvOp op = (SpvOp)(words[0] & 0xFFFF)
+
+
+bool smolv::Encode(const void* spirvData, size_t spirvSize, ByteArray& outSmolv, uint32_t flags, StripOpNameFilterFunc stripFilter)
+{
+ const size_t wordCount = spirvSize / 4;
+ if (wordCount * 4 != spirvSize)
+ return false;
+ const uint32_t* words = (const uint32_t*)spirvData;
+ const uint32_t* wordsEnd = words + wordCount;
+ if (!smolv_CheckSpirVHeader(words, wordCount))
+ return false;
+
+ // reserve space in output (typical compression is to about 30%; reserve half of input space)
+ outSmolv.reserve(outSmolv.size() + spirvSize/2);
+
+ // header (matches SPIR-V one, except different magic)
+ smolv_Write4(outSmolv, kSmolHeaderMagic);
+ smolv_Write4(outSmolv, (words[1] & 0x00FFFFFF) + (kSmolCurrEncodingVersion<<24)); // SPIR-V version (_XXX) + SMOL-V version (X___)
+ smolv_Write4(outSmolv, words[2]); // generator
+ smolv_Write4(outSmolv, words[3]); // bound
+ smolv_Write4(outSmolv, words[4]); // schema
+
+ const size_t headerSpirvSizeOffset = outSmolv.size(); // size field may get updated later if stripping is enabled
+ smolv_Write4(outSmolv, (uint32_t)spirvSize); // space needed to decode (i.e. original SPIR-V size)
+
+ size_t strippedSpirvWordCount = wordCount;
+ uint32_t prevResult = 0;
+ uint32_t prevDecorate = 0;
+
+ const int knownOpsCount = smolv_GetKnownOpsCount(kSmolCurrEncodingVersion);
+
+ words += 5;
+ while (words < wordsEnd)
+ {
+ _SMOLV_READ_OP(instrLen, words, op);
+
+ if ((flags & kEncodeFlagStripDebugInfo) && smolv_OpDebugInfo(op, knownOpsCount))
+ {
+ if (!stripFilter || op != SpvOpName || !stripFilter(reinterpret_cast<const char*>(&words[2])))
+ {
+ strippedSpirvWordCount -= instrLen;
+ words += instrLen;
+ continue;
+ }
+ }
+
+ // A usual case of vector shuffle, with less than 4 components, each with a value
+ // in [0..3] range: encode it in a more compact form, with the swizzle pattern in one byte.
+ // Turn this into a VectorShuffleCompact instruction, that takes up unused slot in Ops.
+ uint32_t swizzle = 0;
+ if (op == SpvOpVectorShuffle && instrLen <= 9)
+ {
+ uint32_t swz0 = instrLen > 5 ? words[5] : 0;
+ uint32_t swz1 = instrLen > 6 ? words[6] : 0;
+ uint32_t swz2 = instrLen > 7 ? words[7] : 0;
+ uint32_t swz3 = instrLen > 8 ? words[8] : 0;
+ if (swz0 < 4 && swz1 < 4 && swz2 < 4 && swz3 < 4)
+ {
+ op = SpvOpVectorShuffleCompact;
+ swizzle = (swz0 << 6) | (swz1 << 4) | (swz2 << 2) | (swz3);
+ }
+ }
+
+ // length + opcode
+ if (!smolv_WriteLengthOp(outSmolv, instrLen, op))
+ return false;
+
+ size_t ioffs = 1;
+ // write type as varint, if we have it
+ if (smolv_OpHasType(op, knownOpsCount))
+ {
+ if (ioffs >= instrLen)
+ return false;
+ smolv_WriteVarint(outSmolv, words[ioffs]);
+ ioffs++;
+ }
+ // write result as delta+zig+varint, if we have it
+ if (smolv_OpHasResult(op, knownOpsCount))
+ {
+ if (ioffs >= instrLen)
+ return false;
+ uint32_t v = words[ioffs];
+ smolv_WriteVarint(outSmolv, smolv_ZigEncode(v - prevResult)); // some deltas are negative, use zig
+ prevResult = v;
+ ioffs++;
+ }
+
+ // Decorate & MemberDecorate: IDs relative to previous decorate
+ if (op == SpvOpDecorate || op == SpvOpMemberDecorate)
+ {
+ if (ioffs >= instrLen)
+ return false;
+ uint32_t v = words[ioffs];
+ smolv_WriteVarint(outSmolv, smolv_ZigEncode(v - prevDecorate)); // spirv-remapped deltas often negative, use zig
+ prevDecorate = v;
+ ioffs++;
+ }
+
+ // MemberDecorate special encoding: whole row of MemberDecorate instructions is often referring
+ // to the same type and linearly increasing member indices. Scan ahead to see how many we have,
+ // and encode whole bunch as one.
+ if (op == SpvOpMemberDecorate)
+ {
+ // scan ahead until we reach end, non-member-decoration or different type
+ const uint32_t decorationType = words[ioffs-1];
+ const uint32_t* memberWords = words;
+ uint32_t prevIndex = 0;
+ uint32_t prevOffset = 0;
+ // write a byte on how many we have encoded as a bunch
+ size_t countLocation = outSmolv.size();
+ outSmolv.push_back(0);
+ int count = 0;
+ while (memberWords < wordsEnd && count < 255)
+ {
+ _SMOLV_READ_OP(memberLen, memberWords, memberOp);
+ if (memberOp != SpvOpMemberDecorate)
+ break;
+ if (memberLen < 4)
+ return false; // invalid input
+ if (memberWords[1] != decorationType)
+ break;
+
+ // write member index as delta from previous
+ uint32_t memberIndex = memberWords[2];
+ smolv_WriteVarint(outSmolv, memberIndex - prevIndex);
+ prevIndex = memberIndex;
+
+ // decoration (and length if not common/known)
+ uint32_t memberDec = memberWords[3];
+ smolv_WriteVarint(outSmolv, memberDec);
+ const int knownExtraOps = smolv_DecorationExtraOps(memberDec);
+ if (knownExtraOps == -1)
+ smolv_WriteVarint(outSmolv, memberLen-4);
+ else if (unsigned(knownExtraOps) + 4 != memberLen)
+ return false; // invalid input
+
+ // Offset decorations are most often linearly increasing, so encode as deltas
+ if (memberDec == 35) // Offset
+ {
+ if (memberLen != 5)
+ return false;
+ smolv_WriteVarint(outSmolv, memberWords[4]-prevOffset);
+ prevOffset = memberWords[4];
+ }
+ else
+ {
+ // write rest of decorations as varint
+ for (uint32_t i = 4; i < memberLen; ++i)
+ smolv_WriteVarint(outSmolv, memberWords[i]);
+ }
+
+ memberWords += memberLen;
+ ++count;
+ }
+ outSmolv[countLocation] = uint8_t(count);
+ words = memberWords;
+ continue;
+ }
+
+ // Write out this many IDs, encoding them relative+zigzag to result ID
+ int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount);
+ for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
+ {
+ if (ioffs >= instrLen)
+ return false;
+ uint32_t delta = prevResult - words[ioffs];
+ // some deltas are negative (often on branches, or if program was processed by spirv-remap),
+ // so use zig encoding
+ smolv_WriteVarint(outSmolv, smolv_ZigEncode(delta));
+ }
+
+ if (op == SpvOpVectorShuffleCompact)
+ {
+ // compact vector shuffle, just write out single swizzle byte
+ outSmolv.push_back(uint8_t(swizzle));
+ ioffs = instrLen;
+ }
+ else if (smolv_OpVarRest(op, knownOpsCount))
+ {
+ // write out rest of words with variable encoding (expected to be small integers)
+ for (; ioffs < instrLen; ++ioffs)
+ smolv_WriteVarint(outSmolv, words[ioffs]);
+ }
+ else
+ {
+ // write out rest of words without any encoding
+ for (; ioffs < instrLen; ++ioffs)
+ smolv_Write4(outSmolv, words[ioffs]);
+ }
+
+ words += instrLen;
+ }
+
+ if (strippedSpirvWordCount != wordCount)
+ {
+ uint8_t* headerSpirvSize = &outSmolv[headerSpirvSizeOffset];
+ smolv_Write4(headerSpirvSize, (uint32_t)strippedSpirvWordCount * 4);
+ }
+
+ return true;
+}
+
+
+size_t smolv::GetDecodedBufferSize(const void* smolvData, size_t smolvSize)
+{
+ if (!smolv_CheckSmolHeader((const uint8_t*)smolvData, smolvSize))
+ return 0;
+ const uint32_t* words = (const uint32_t*)smolvData;
+ return words[5];
+}
+
+
+bool smolv::Decode(const void* smolvData, size_t smolvSize, void* spirvOutputBuffer, size_t spirvOutputBufferSize, uint32_t flags)
+{
+ // check header, and whether we have enough output buffer space
+ const size_t neededBufferSize = GetDecodedBufferSize(smolvData, smolvSize);
+ if (neededBufferSize == 0)
+ return false; // invalid SMOL-V
+ if (spirvOutputBufferSize < neededBufferSize)
+ return false; // not enough space in output buffer
+ if (spirvOutputBuffer == NULL)
+ return false; // output buffer is null
+
+ const uint8_t* bytes = (const uint8_t*)smolvData;
+ const uint8_t* bytesEnd = bytes + smolvSize;
+
+ uint8_t* outSpirv = (uint8_t*)spirvOutputBuffer;
+
+ uint32_t val;
+ int smolVersion = 0;
+
+ // header
+ smolv_Write4(outSpirv, kSpirVHeaderMagic); bytes += 4;
+ smolv_Read4(bytes, bytesEnd, val); smolVersion = val >> 24; val &= 0x00FFFFFF; smolv_Write4(outSpirv, val); // version
+ smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // generator
+ smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // bound
+ smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // schema
+ bytes += 4; // decode buffer size
+
+ // there are two SMOL-V encoding versions, both not indicating anything in their header version field:
+ // one that is called "before zero" here (2016-08-31 code). Support decoding that one only by presence
+ // of this special flag.
+ const bool beforeZeroVersion = smolVersion == 0 && (flags & kDecodeFlagUse20160831AsZeroVersion) != 0;
+
+ const int knownOpsCount = smolv_GetKnownOpsCount(smolVersion);
+
+ uint32_t prevResult = 0;
+ uint32_t prevDecorate = 0;
+
+ while (bytes < bytesEnd)
+ {
+ // read length + opcode
+ uint32_t instrLen;
+ SpvOp op;
+ if (!smolv_ReadLengthOp(bytes, bytesEnd, instrLen, op))
+ return false;
+ const bool wasSwizzle = (op == SpvOpVectorShuffleCompact);
+ if (wasSwizzle)
+ op = SpvOpVectorShuffle;
+ smolv_Write4(outSpirv, (instrLen << 16) | op);
+
+ size_t ioffs = 1;
+
+ // read type as varint, if we have it
+ if (smolv_OpHasType(op, knownOpsCount))
+ {
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ smolv_Write4(outSpirv, val);
+ ioffs++;
+ }
+ // read result as delta+varint, if we have it
+ if (smolv_OpHasResult(op, knownOpsCount))
+ {
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ val = prevResult + smolv_ZigDecode(val);
+ smolv_Write4(outSpirv, val);
+ prevResult = val;
+ ioffs++;
+ }
+
+ // Decorate: IDs relative to previous decorate
+ if (op == SpvOpDecorate || op == SpvOpMemberDecorate)
+ {
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ // "before zero" version did not use zig encoding for the value
+ val = prevDecorate + (beforeZeroVersion ? val : smolv_ZigDecode(val));
+ smolv_Write4(outSpirv, val);
+ prevDecorate = val;
+ ioffs++;
+ }
+
+ // MemberDecorate special decoding
+ if (op == SpvOpMemberDecorate && !beforeZeroVersion)
+ {
+ if (bytes >= bytesEnd)
+ return false; // broken input
+ int count = *bytes++;
+ int prevIndex = 0;
+ int prevOffset = 0;
+ for (int m = 0; m < count; ++m)
+ {
+ // read member index
+ uint32_t memberIndex;
+ if (!smolv_ReadVarint(bytes, bytesEnd, memberIndex)) return false;
+ memberIndex += prevIndex;
+ prevIndex = memberIndex;
+
+ // decoration (and length if not common/known)
+ uint32_t memberDec;
+ if (!smolv_ReadVarint(bytes, bytesEnd, memberDec)) return false;
+ const int knownExtraOps = smolv_DecorationExtraOps(memberDec);
+ uint32_t memberLen;
+ if (knownExtraOps == -1)
+ {
+ if (!smolv_ReadVarint(bytes, bytesEnd, memberLen)) return false;
+ memberLen += 4;
+ }
+ else
+ memberLen = 4 + knownExtraOps;
+
+ // write SPIR-V op+length (unless it's first member decoration, in which case it was written before)
+ if (m != 0)
+ {
+ smolv_Write4(outSpirv, (memberLen << 16) | op);
+ smolv_Write4(outSpirv, prevDecorate);
+ }
+ smolv_Write4(outSpirv, memberIndex);
+ smolv_Write4(outSpirv, memberDec);
+ // Special case for Offset decorations
+ if (memberDec == 35) // Offset
+ {
+ if (memberLen != 5)
+ return false;
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ val += prevOffset;
+ smolv_Write4(outSpirv, val);
+ prevOffset = val;
+ }
+ else
+ {
+ for (uint32_t i = 4; i < memberLen; ++i)
+ {
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ smolv_Write4(outSpirv, val);
+ }
+ }
+ }
+ continue;
+ }
+
+ // Read this many IDs, that are relative to result ID
+ int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount);
+ // "before zero" version only used zig encoding for IDs of several ops; after
+ // that ops got zig encoding for their IDs
+ bool zigDecodeVals = true;
+ if (beforeZeroVersion)
+ {
+ if (op != SpvOpControlBarrier && op != SpvOpMemoryBarrier && op != SpvOpLoopMerge && op != SpvOpSelectionMerge && op != SpvOpBranch && op != SpvOpBranchConditional && op != SpvOpMemoryNamedBarrier)
+ zigDecodeVals = false;
+ }
+ for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
+ {
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ if (zigDecodeVals)
+ val = smolv_ZigDecode(val);
+ smolv_Write4(outSpirv, prevResult - val);
+ }
+
+ if (wasSwizzle && instrLen <= 9)
+ {
+ uint32_t swizzle = *bytes++;
+ if (instrLen > 5) smolv_Write4(outSpirv, (swizzle >> 6) & 3);
+ if (instrLen > 6) smolv_Write4(outSpirv, (swizzle >> 4) & 3);
+ if (instrLen > 7) smolv_Write4(outSpirv, (swizzle >> 2) & 3);
+ if (instrLen > 8) smolv_Write4(outSpirv, swizzle & 3);
+ }
+ else if (smolv_OpVarRest(op, knownOpsCount))
+ {
+ // read rest of words with variable encoding
+ for (; ioffs < instrLen; ++ioffs)
+ {
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ smolv_Write4(outSpirv, val);
+ }
+ }
+ else
+ {
+ // read rest of words without any encoding
+ for (; ioffs < instrLen; ++ioffs)
+ {
+ if (!smolv_Read4(bytes, bytesEnd, val)) return false;
+ smolv_Write4(outSpirv, val);
+ }
+ }
+ }
+
+ if ((uint8_t*)spirvOutputBuffer + neededBufferSize != outSpirv)
+ return false; // something went wrong during decoding? we should have decoded to exact output size
+
+ return true;
+}
+
+
+
+// --------------------------------------------------------------------------------------------
+// Calculating instruction count / space stats on SPIR-V and SMOL-V
+
+
+struct smolv::Stats
+{
+ Stats() { memset(this, 0, sizeof(*this)); }
+ size_t opCounts[kKnownOpsCount];
+ size_t opSizes[kKnownOpsCount];
+ size_t smolOpSizes[kKnownOpsCount];
+ size_t varintCountsOp[6];
+ size_t varintCountsType[6];
+ size_t varintCountsRes[6];
+ size_t varintCountsOther[6];
+ size_t totalOps;
+ size_t totalSize;
+ size_t totalSizeSmol;
+ size_t inputCount;
+};
+
+
+smolv::Stats* smolv::StatsCreate()
+{
+ return new Stats();
+}
+
+void smolv::StatsDelete(smolv::Stats *s)
+{
+ delete s;
+}
+
+
+bool smolv::StatsCalculate(smolv::Stats* stats, const void* spirvData, size_t spirvSize)
+{
+ if (!stats)
+ return false;
+
+ const size_t wordCount = spirvSize / 4;
+ if (wordCount * 4 != spirvSize)
+ return false;
+ const uint32_t* words = (const uint32_t*)spirvData;
+ const uint32_t* wordsEnd = words + wordCount;
+ if (!smolv_CheckSpirVHeader(words, wordCount))
+ return false;
+ words += 5;
+
+ stats->inputCount++;
+ stats->totalSize += wordCount;
+
+ while (words < wordsEnd)
+ {
+ _SMOLV_READ_OP(instrLen, words, op);
+
+ if (op < kKnownOpsCount)
+ {
+ stats->opCounts[op]++;
+ stats->opSizes[op] += instrLen;
+ }
+ words += instrLen;
+ stats->totalOps++;
+ }
+
+ return true;
+}
+
+
+bool smolv::StatsCalculateSmol(smolv::Stats* stats, const void* smolvData, size_t smolvSize)
+{
+ if (!stats)
+ return false;
+
+ // debugging helper to dump all encoded bytes to stdout, keep at "if 0"
+# if 0
+# define _SMOLV_DEBUG_PRINT_ENCODED_BYTES() { \
+ printf("Op %-22s ", op < kKnownOpsCount ? kSpirvOpNames[op] : "???"); \
+ for (const uint8_t* b = instrBegin; b < bytes; ++b) \
+ printf("%02x ", *b); \
+ printf("\n"); \
+ }
+# else
+# define _SMOLV_DEBUG_PRINT_ENCODED_BYTES() {}
+# endif
+
+ const uint8_t* bytes = (const uint8_t*)smolvData;
+ const uint8_t* bytesEnd = bytes + smolvSize;
+ if (!smolv_CheckSmolHeader(bytes, smolvSize))
+ return false;
+
+ uint32_t val;
+ int smolVersion;
+ bytes += 4;
+ smolv_Read4(bytes, bytesEnd, val); smolVersion = val >> 24;
+ const int knownOpsCount = smolv_GetKnownOpsCount(smolVersion);
+ bytes += 16;
+
+ stats->totalSizeSmol += smolvSize;
+
+ while (bytes < bytesEnd)
+ {
+ const uint8_t* instrBegin = bytes;
+ const uint8_t* varBegin;
+
+ // read length + opcode
+ uint32_t instrLen;
+ SpvOp op;
+ varBegin = bytes;
+ if (!smolv_ReadLengthOp(bytes, bytesEnd, instrLen, op))
+ return false;
+ const bool wasSwizzle = (op == SpvOpVectorShuffleCompact);
+ if (wasSwizzle)
+ op = SpvOpVectorShuffle;
+ stats->varintCountsOp[bytes-varBegin]++;
+
+ size_t ioffs = 1;
+ if (smolv_OpHasType(op, knownOpsCount))
+ {
+ varBegin = bytes;
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ stats->varintCountsType[bytes-varBegin]++;
+ ioffs++;
+ }
+ if (smolv_OpHasResult(op, knownOpsCount))
+ {
+ varBegin = bytes;
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ stats->varintCountsRes[bytes-varBegin]++;
+ ioffs++;
+ }
+
+ if (op == SpvOpDecorate || op == SpvOpMemberDecorate)
+ {
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ ioffs++;
+ }
+ // MemberDecorate special decoding
+ if (op == SpvOpMemberDecorate)
+ {
+ if (bytes >= bytesEnd)
+ return false; // broken input
+ int count = *bytes++;
+ for (int m = 0; m < count; ++m)
+ {
+ uint32_t memberIndex;
+ if (!smolv_ReadVarint(bytes, bytesEnd, memberIndex)) return false;
+ uint32_t memberDec;
+ if (!smolv_ReadVarint(bytes, bytesEnd, memberDec)) return false;
+ const int knownExtraOps = smolv_DecorationExtraOps(memberDec);
+ uint32_t memberLen;
+ if (knownExtraOps == -1)
+ {
+ if (!smolv_ReadVarint(bytes, bytesEnd, memberLen)) return false;
+ memberLen += 4;
+ }
+ else
+ memberLen = 4 + knownExtraOps;
+ for (uint32_t i = 4; i < memberLen; ++i)
+ {
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ }
+ }
+ stats->smolOpSizes[op] += bytes - instrBegin;
+ _SMOLV_DEBUG_PRINT_ENCODED_BYTES();
+ continue;
+ }
+
+ int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount);
+ for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
+ {
+ varBegin = bytes;
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ stats->varintCountsRes[bytes-varBegin]++;
+ }
+
+ if (wasSwizzle && instrLen <= 9)
+ {
+ bytes++;
+ }
+ else if (smolv_OpVarRest(op, knownOpsCount))
+ {
+ for (; ioffs < instrLen; ++ioffs)
+ {
+ varBegin = bytes;
+ if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
+ stats->varintCountsOther[bytes-varBegin]++;
+ }
+ }
+ else
+ {
+ for (; ioffs < instrLen; ++ioffs)
+ {
+ if (!smolv_Read4(bytes, bytesEnd, val)) return false;
+ }
+ }
+
+ if (op < kKnownOpsCount)
+ {
+ stats->smolOpSizes[op] += bytes - instrBegin;
+ }
+ _SMOLV_DEBUG_PRINT_ENCODED_BYTES();
+ }
+
+ return true;
+}
+
+static bool CompareOpCounters (std::pair<SpvOp,size_t> a, std::pair<SpvOp,size_t> b)
+{
+ return a.second > b.second;
+}
+
+void smolv::StatsPrint(const Stats* stats)
+{
+ if (!stats)
+ return;
+
+ typedef std::pair<SpvOp,size_t> OpCounter;
+ OpCounter counts[kKnownOpsCount];
+ OpCounter sizes[kKnownOpsCount];
+ OpCounter sizesSmol[kKnownOpsCount];
+ for (int i = 0; i < kKnownOpsCount; ++i)
+ {
+ counts[i].first = (SpvOp)i;
+ counts[i].second = stats->opCounts[i];
+ sizes[i].first = (SpvOp)i;
+ sizes[i].second = stats->opSizes[i];
+ sizesSmol[i].first = (SpvOp)i;
+ sizesSmol[i].second = stats->smolOpSizes[i];
+ }
+ std::sort(counts, counts + kKnownOpsCount, CompareOpCounters);
+ std::sort(sizes, sizes + kKnownOpsCount, CompareOpCounters);
+ std::sort(sizesSmol, sizesSmol + kKnownOpsCount, CompareOpCounters);
+
+ printf("Stats for %i SPIR-V inputs, total size %i words (%.1fKB):\n", (int)stats->inputCount, (int)stats->totalSize, stats->totalSize * 4.0f / 1024.0f);
+ printf("Most occuring ops:\n");
+ for (int i = 0; i < 30; ++i)
+ {
+ SpvOp op = counts[i].first;
+ printf(" #%2i: %4i %-20s %4i (%4.1f%%)\n", i, op, kSpirvOpNames[op], (int)counts[i].second, (float)counts[i].second / (float)stats->totalOps * 100.0f);
+ }
+ printf("Largest total size of ops:\n");
+ for (int i = 0; i < 30; ++i)
+ {
+ SpvOp op = sizes[i].first;
+ printf(" #%2i: %-22s %6i (%4.1f%%) avg len %.1f\n",
+ i,
+ kSpirvOpNames[op],
+ (int)sizes[i].second*4,
+ (float)sizes[i].second / (float)stats->totalSize * 100.0f,
+ (float)sizes[i].second*4 / (float)stats->opCounts[op]
+ );
+ }
+ printf("SMOL varint encoding counts per byte length:\n");
+ printf(" B: %6s %6s %6s %6s\n", "Op", "Type", "Result", "Other");
+ for (int i = 1; i < 6; ++i)
+ {
+ printf(" %i: %6i %6i %6i %6i\n", i, (int)stats->varintCountsOp[i], (int)stats->varintCountsType[i], (int)stats->varintCountsRes[i], (int)stats->varintCountsOther[i]);
+ }
+ printf("Largest total size of ops in SMOL:\n");
+ for (int i = 0; i < 30; ++i)
+ {
+ SpvOp op = sizesSmol[i].first;
+ printf(" #%2i: %-22s %6i (%4.1f%%) avg len %.1f\n",
+ i,
+ kSpirvOpNames[op],
+ (int)sizesSmol[i].second,
+ (float)sizesSmol[i].second / (float)stats->totalSizeSmol * 100.0f,
+ (float)sizesSmol[i].second / (float)stats->opCounts[op]
+ );
+ }
+}
+
+
+// ------------------------------------------------------------------------------
+// This software is available under 2 licenses -- choose whichever you prefer.
+// ------------------------------------------------------------------------------
+// ALTERNATIVE A - MIT License
+// Copyright (c) 2016-2020 Aras Pranckevicius
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+// ------------------------------------------------------------------------------
+// ALTERNATIVE B - Public Domain (www.unlicense.org)
+// This is free and unencumbered software released into the public domain.
+// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+// software, either in source code form or as a compiled binary, for any purpose,
+// commercial or non-commercial, and by any means.
+// In jurisdictions that recognize copyright laws, the author or authors of this
+// software dedicate any and all copyright interest in the software to the public
+// domain. We make this dedication for the benefit of the public at large and to
+// the detriment of our heirs and successors. We intend this dedication to be an
+// overt act of relinquishment in perpetuity of all present and future rights to
+// this software under copyright law.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// ------------------------------------------------------------------------------
diff --git a/thirdparty/misc/smolv.h b/thirdparty/misc/smolv.h
new file mode 100644
index 0000000000..798ee4126f
--- /dev/null
+++ b/thirdparty/misc/smolv.h
@@ -0,0 +1,169 @@
+// smol-v - public domain - https://github.com/aras-p/smol-v
+// authored 2016-2020 by Aras Pranckevicius
+// no warranty implied; use at your own risk
+// See end of file for license information.
+//
+//
+// ### OVERVIEW:
+//
+// SMOL-V encodes Vulkan/Khronos SPIR-V format programs into a form that is smaller, and is more
+// compressible. Normally no changes to the programs are done; they decode
+// into exactly same program as what was encoded. Optionally, debug information
+// can be removed too.
+//
+// SPIR-V is a very verbose format, several times larger than same programs expressed in other
+// shader formats (e.g. DX11 bytecode, GLSL, DX9 bytecode etc.). The SSA-form with ever increasing
+// IDs is not very appreciated by regular data compressors either. SMOL-V does several things
+// to improve this:
+// - Many words, especially ones that most often have small values, are encoded using
+// "varint" scheme (1-5 bytes per word, with just one byte for values in 0..127 range).
+// See https://developers.google.com/protocol-buffers/docs/encoding
+// - Some IDs used in the program are delta-encoded, relative to previously seen IDs (e.g. Result
+// IDs). Often instructions reference things that were computed just before, so this results in
+// small deltas. These values are also encoded using "varint" scheme.
+// - Reordering instruction opcodes so that the most common ones are the smallest values, for smaller
+// varint encoding.
+// - Encoding several instructions in a more compact form, e.g. the "typical <=4 component swizzle"
+// shape of a VectorShuffle instruction, or sequences of MemberDecorate instructions.
+//
+// A somewhat similar utility is spirv-remap from glslang, see
+// https://github.com/KhronosGroup/glslang/blob/master/README-spirv-remap.txt
+//
+//
+// ### USAGE:
+//
+// Add source/smolv.h and source/smolv.cpp to your C++ project build.
+// Currently it might require C++11 or somesuch; I only tested with Visual Studio 2017/2019, Mac Xcode 11 and Gcc 5.4.
+//
+// smolv::Encode and smolv::Decode is the basic functionality.
+//
+// Other functions are for development/statistics purposes, to figure out frequencies and
+// distributions of the instructions.
+//
+// There's a test + compression benchmarking suite in testing/testmain.cpp; using that needs adding
+// other files under testing/external to the build too (3rd party code: glslang remapper, Zstd, LZ4).
+//
+//
+// ### LIMITATIONS / TODO:
+//
+// - SPIR-V where the words got stored in big-endian layout is not supported yet.
+// - The whole thing might not work on Big-Endian CPUs. It might, but I'm not 100% sure.
+// - Not much prevention is done against malformed/corrupted inputs, TODO.
+// - Out of memory cases are not handled. The code will either throw exception
+// or crash, depending on your compilation flags.
+
+#pragma once
+
+#include <stdint.h>
+#include <vector>
+#include <cstddef>
+
+namespace smolv
+{
+ typedef std::vector<uint8_t> ByteArray;
+
+ enum EncodeFlags
+ {
+ kEncodeFlagNone = 0,
+ kEncodeFlagStripDebugInfo = (1<<0), // Strip all optional SPIR-V instructions (debug names etc.)
+ };
+ enum DecodeFlags
+ {
+ kDecodeFlagNone = 0,
+ kDecodeFlagUse20160831AsZeroVersion = (1 << 0), // For "version zero" of SMOL-V encoding, use 2016 08 31 code path (this is what happens to be used by Unity 2017-2020)
+ };
+
+ // Preserve *some* OpName debug names.
+ // Return true to preserve, false to strip.
+ // This is really only used to implement a workaround for problems with some Vulkan drivers.
+ typedef bool(*StripOpNameFilterFunc)(const char* name);
+
+ // -------------------------------------------------------------------
+ // Encoding / Decoding
+
+ // Encode SPIR-V into SMOL-V.
+ //
+ // Resulting data is appended to outSmolv array (the array is not cleared).
+ //
+ // flags is bitset of EncodeFlags values.
+ //
+ // Returns false on malformed SPIR-V input; if that happens the output array might get
+ // partial/broken SMOL-V program.
+ bool Encode(const void* spirvData, size_t spirvSize, ByteArray& outSmolv, uint32_t flags = kEncodeFlagNone, StripOpNameFilterFunc stripFilter = 0);
+
+
+ // Decode SMOL-V into SPIR-V.
+ //
+ // Resulting data is written into the passed buffer. Get required buffer space with
+ // GetDecodeBufferSize; this is the size of decoded SPIR-V program.
+ //
+ // flags is bitset of DecodeFlags values.
+
+ // Decoding does no memory allocations.
+ //
+ // Returns false on malformed input; if that happens the output buffer might be only partially
+ // written to.
+ bool Decode(const void* smolvData, size_t smolvSize, void* spirvOutputBuffer, size_t spirvOutputBufferSize, uint32_t flags = kDecodeFlagNone);
+
+
+ // Given a SMOL-V program, get size of the decoded SPIR-V program.
+ // This is the buffer size that Decode expects.
+ //
+ // Returns zero on malformed input (just checks the header, not the full input).
+ size_t GetDecodedBufferSize(const void* smolvData, size_t smolvSize);
+
+
+ // -------------------------------------------------------------------
+ // Computing instruction statistics on SPIR-V/SMOL-V programs
+
+ struct Stats;
+
+ Stats* StatsCreate();
+ void StatsDelete(Stats* s);
+
+ bool StatsCalculate(Stats* stats, const void* spirvData, size_t spirvSize);
+ bool StatsCalculateSmol(Stats* stats, const void* smolvData, size_t smolvSize);
+ void StatsPrint(const Stats* stats);
+
+} // namespace smolv
+
+
+// ------------------------------------------------------------------------------
+// This software is available under 2 licenses -- choose whichever you prefer.
+// ------------------------------------------------------------------------------
+// ALTERNATIVE A - MIT License
+// Copyright (c) 2016-2020 Aras Pranckevicius
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+// ------------------------------------------------------------------------------
+// ALTERNATIVE B - Public Domain (www.unlicense.org)
+// This is free and unencumbered software released into the public domain.
+// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+// software, either in source code form or as a compiled binary, for any purpose,
+// commercial or non-commercial, and by any means.
+// In jurisdictions that recognize copyright laws, the author or authors of this
+// software dedicate any and all copyright interest in the software to the public
+// domain. We make this dedication for the benefit of the public at large and to
+// the detriment of our heirs and successors. We intend this dedication to be an
+// overt act of relinquishment in perpetuity of all present and future rights to
+// this software under copyright law.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// ------------------------------------------------------------------------------
diff --git a/thirdparty/oidn/core/transfer_function.cpp b/thirdparty/oidn/core/transfer_function.cpp
index 487f0a9f75..ce5deca56b 100644
--- a/thirdparty/oidn/core/transfer_function.cpp
+++ b/thirdparty/oidn/core/transfer_function.cpp
@@ -24,10 +24,6 @@ namespace oidn {
float AutoexposureNode::autoexposure(const Image& color)
{
assert(color.format == Format::Float3);
-// -- GODOT start --
-// We don't want to mess with TTB and we don't use autoexposure, so we disable this code
-#if 0
-// -- GODOT end --
constexpr float key = 0.18f;
constexpr float eps = 1e-8f;
@@ -42,61 +38,66 @@ namespace oidn {
// Compute the average log luminance of the downsampled image
using Sum = std::pair<float, int>;
- Sum sum =
- tbb::parallel_reduce(
- tbb::blocked_range2d<int>(0, HK, 0, WK),
- Sum(0.f, 0),
- [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
+ // -- GODOT start --
+ // Sum sum =
+ // tbb::parallel_reduce(
+ // tbb::blocked_range2d<int>(0, HK, 0, WK),
+ // Sum(0.f, 0),
+ // [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
+ // {
+ // // Iterate over blocks
+ // for (int i = r.rows().begin(); i != r.rows().end(); ++i)
+ // {
+ // for (int j = r.cols().begin(); j != r.cols().end(); ++j)
+ // {
+
+ Sum sum = Sum(0.0f, 0);
+
+ for (int i = 0; i != HK; ++i)
+ {
+ for (int j = 0; j != WK; ++j)
+ {
+ // Compute the average luminance in the current block
+ const int beginH = int(ptrdiff_t(i) * H / HK);
+ const int beginW = int(ptrdiff_t(j) * W / WK);
+ const int endH = int(ptrdiff_t(i+1) * H / HK);
+ const int endW = int(ptrdiff_t(j+1) * W / WK);
+
+ float L = 0.f;
+
+ for (int h = beginH; h < endH; ++h)
{
- // Iterate over blocks
- for (int i = r.rows().begin(); i != r.rows().end(); ++i)
+ for (int w = beginW; w < endW; ++w)
{
- for (int j = r.cols().begin(); j != r.cols().end(); ++j)
- {
- // Compute the average luminance in the current block
- const int beginH = int(ptrdiff_t(i) * H / HK);
- const int beginW = int(ptrdiff_t(j) * W / WK);
- const int endH = int(ptrdiff_t(i+1) * H / HK);
- const int endW = int(ptrdiff_t(j+1) * W / WK);
-
- float L = 0.f;
-
- for (int h = beginH; h < endH; ++h)
- {
- for (int w = beginW; w < endW; ++w)
- {
- const float* rgb = (const float*)color.get(h, w);
-
- const float r = maxSafe(rgb[0], 0.f);
- const float g = maxSafe(rgb[1], 0.f);
- const float b = maxSafe(rgb[2], 0.f);
-
- L += luminance(r, g, b);
- }
- }
-
- L /= (endH - beginH) * (endW - beginW);
-
- // Accumulate the log luminance
- if (L > eps)
- {
- sum.first += log2(L);
- sum.second++;
- }
- }
+ const float* rgb = (const float*)color.get(h, w);
+
+ const float r = maxSafe(rgb[0], 0.f);
+ const float g = maxSafe(rgb[1], 0.f);
+ const float b = maxSafe(rgb[2], 0.f);
+
+ L += luminance(r, g, b);
}
+ }
- return sum;
- },
- [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
- tbb::static_partitioner()
- );
+ L /= (endH - beginH) * (endW - beginW);
+
+ // Accumulate the log luminance
+ if (L > eps)
+ {
+ sum.first += log2(L);
+ sum.second++;
+ }
+ }
+ }
+
+ // return sum;
+ // },
+ // [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
+ // tbb::static_partitioner()
+ // );
+ // -- GODOT end --
return (sum.second > 0) ? (key / exp2(sum.first / float(sum.second))) : 1.f;
-// -- GODOT start --
-#endif
- return 1.0;
-// -- GODOT end --
}
} // namespace oidn
diff --git a/thirdparty/oidn/patches/godot-changes-c58c5216.patch b/thirdparty/oidn/patches/godot-changes-c58c5216.patch
index 6a54703064..c01f00187b 100644
--- a/thirdparty/oidn/patches/godot-changes-c58c5216.patch
+++ b/thirdparty/oidn/patches/godot-changes-c58c5216.patch
@@ -280,28 +280,58 @@ index 8c2de09..ed8328c 100644
namespace oidn {
diff --git a/core/transfer_function.cpp b/core/transfer_function.cpp
-index 601f814..487f0a9 100644
+index 601f814..ce5deca 100644
--- a/core/transfer_function.cpp
+++ b/core/transfer_function.cpp
-@@ -24,6 +24,10 @@ namespace oidn {
- float AutoexposureNode::autoexposure(const Image& color)
- {
- assert(color.format == Format::Float3);
-+// -- GODOT start --
-+// We don't want to mess with TTB and we don't use autoexposure, so we disable this code
-+#if 0
-+// -- GODOT end --
+@@ -38,16 +38,24 @@ namespace oidn {
+ // Compute the average log luminance of the downsampled image
+ using Sum = std::pair<float, int>;
+
+- Sum sum =
+- tbb::parallel_reduce(
+- tbb::blocked_range2d<int>(0, HK, 0, WK),
+- Sum(0.f, 0),
+- [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
++ // -- GODOT start --
++ // Sum sum =
++ // tbb::parallel_reduce(
++ // tbb::blocked_range2d<int>(0, HK, 0, WK),
++ // Sum(0.f, 0),
++ // [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
++ // {
++ // // Iterate over blocks
++ // for (int i = r.rows().begin(); i != r.rows().end(); ++i)
++ // {
++ // for (int j = r.cols().begin(); j != r.cols().end(); ++j)
++ // {
++
++ Sum sum = Sum(0.0f, 0);
++
++ for (int i = 0; i != HK; ++i)
+ {
+- // Iterate over blocks
+- for (int i = r.rows().begin(); i != r.rows().end(); ++i)
+- {
+- for (int j = r.cols().begin(); j != r.cols().end(); ++j)
++ for (int j = 0; j != WK; ++j)
+ {
+ // Compute the average luminance in the current block
+ const int beginH = int(ptrdiff_t(i) * H / HK);
+@@ -82,11 +90,12 @@ namespace oidn {
+ }
+ }
- constexpr float key = 0.18f;
- constexpr float eps = 1e-8f;
-@@ -89,6 +93,10 @@ namespace oidn {
- );
+- return sum;
+- },
+- [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
+- tbb::static_partitioner()
+- );
++ // return sum;
++ // },
++ // [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
++ // tbb::static_partitioner()
++ // );
++ // -- GODOT end --
return (sum.second > 0) ? (key / exp2(sum.first / float(sum.second))) : 1.f;
-+// -- GODOT start --
-+#endif
-+ return 1.0;
-+// -- GODOT end --
}
-
- } // namespace oidn